From c38dead3ea7e177728d90cd815cf4eead0c9f534 Mon Sep 17 00:00:00 2001 From: marha Date: Sat, 15 May 2010 16:28:11 +0000 Subject: xserver git update 15/5/2010 --- xorg-server/Xext/bigreq.c | 160 +- xorg-server/Xext/dpms.c | 758 +- xorg-server/Xext/geext.c | 534 +- xorg-server/Xext/panoramiX.c | 2568 ++-- xorg-server/Xext/panoramiXprocs.c | 4893 ++++--- xorg-server/Xext/saver.c | 3078 ++--- xorg-server/Xext/security.c | 2305 ++-- xorg-server/Xext/shape.c | 2586 ++-- xorg-server/Xext/shm.c | 2658 ++-- xorg-server/Xext/sleepuntil.c | 450 +- xorg-server/Xext/sync.c | 4798 +++---- xorg-server/Xext/xace.c | 700 +- xorg-server/Xext/xcalibrate.c | 598 +- xorg-server/Xext/xcmisc.c | 434 +- xorg-server/Xext/xf86bigfont.c | 30 +- xorg-server/Xext/xres.c | 766 +- xorg-server/Xext/xselinux_ext.c | 1468 +- xorg-server/Xext/xselinux_hooks.c | 1919 ++- xorg-server/Xext/xselinux_label.c | 748 +- xorg-server/Xext/xselinuxint.h | 1114 +- xorg-server/Xext/xtest.c | 1426 +- xorg-server/Xext/xvdisp.c | 3924 +++--- xorg-server/Xext/xvmain.c | 2378 ++-- xorg-server/Xext/xvmc.c | 1574 +-- xorg-server/Xi/exevents.c | 4356 +++--- xorg-server/Xi/extinit.c | 2 +- xorg-server/Xi/getdctl.c | 628 +- xorg-server/Xi/getfctl.c | 732 +- xorg-server/Xi/getkmap.c | 316 +- xorg-server/Xi/getmmap.c | 274 +- xorg-server/Xi/getprop.c | 374 +- xorg-server/Xi/getselev.c | 356 +- xorg-server/Xi/gtmotion.c | 356 +- xorg-server/Xi/listdev.c | 868 +- xorg-server/Xi/queryst.c | 382 +- xorg-server/Xi/xichangehierarchy.c | 908 +- xorg-server/Xi/xipassivegrab.c | 626 +- xorg-server/Xi/xiproperty.c | 28 +- xorg-server/Xi/xiquerydevice.c | 1006 +- xorg-server/Xi/xiquerypointer.c | 456 +- xorg-server/Xi/xiselectev.c | 598 +- xorg-server/composite/compalloc.c | 1295 +- xorg-server/composite/compext.c | 1174 +- xorg-server/composite/compinit.c | 788 +- xorg-server/composite/compoverlay.c | 320 +- xorg-server/config/config.c | 278 +- xorg-server/config/dbus.c | 884 +- xorg-server/config/hal.c | 1294 +- xorg-server/config/udev.c | 534 +- xorg-server/configure.ac | 4494 +++---- xorg-server/damageext/damageext.c | 16 +- xorg-server/dbe/dbe.c | 3364 +++-- xorg-server/dbe/midbe.c | 1618 +-- xorg-server/dix/atom.c | 430 +- xorg-server/dix/colormap.c | 5516 ++++---- xorg-server/dix/cursor.c | 1024 +- xorg-server/dix/devices.c | 5036 +++---- xorg-server/dix/dispatch.c | 448 +- xorg-server/dix/dixfonts.c | 4207 +++--- xorg-server/dix/dixutils.c | 36 +- xorg-server/dix/eventconvert.c | 1438 +- xorg-server/dix/events.c | 11824 ++++++++-------- xorg-server/dix/extension.c | 716 +- xorg-server/dix/gc.c | 2392 ++-- xorg-server/dix/getevents.c | 2416 ++-- xorg-server/dix/glyphcurs.c | 383 +- xorg-server/dix/grabs.c | 1120 +- xorg-server/dix/inpututils.c | 668 +- xorg-server/dix/main.c | 690 +- xorg-server/dix/pixmap.c | 244 +- xorg-server/dix/privates.c | 604 +- xorg-server/dix/property.c | 1294 +- xorg-server/dix/ptrveloc.c | 2354 ++-- xorg-server/dix/registry.c | 672 +- xorg-server/dix/resource.c | 30 +- xorg-server/dix/selection.c | 626 +- xorg-server/dix/swaprep.c | 2616 ++-- xorg-server/dix/window.c | 7775 ++++++----- xorg-server/exa/exa.c | 2258 ++-- xorg-server/exa/exa_accel.c | 2608 ++-- xorg-server/exa/exa_glyphs.c | 1734 +-- xorg-server/exa/exa_offscreen.c | 1392 +- xorg-server/fb/fballpriv.c | 152 +- xorg-server/fb/fbcmap.c | 1172 +- xorg-server/fb/fbcopy.c | 748 +- xorg-server/fb/fboverlay.c | 874 +- xorg-server/fb/fbpixmap.c | 784 +- xorg-server/fb/fbscreen.c | 582 +- xorg-server/fb/fbseg.c | 1470 +- xorg-server/glx/glxcmds.c | 26 +- xorg-server/glx/glxdri.c | 38 +- xorg-server/glx/glxdri2.c | 45 +- xorg-server/glx/glxdricommon.c | 412 +- xorg-server/glx/glxdriswrast.c | 32 +- xorg-server/glx/glxext.c | 1220 +- xorg-server/glx/glxscreens.c | 8 +- xorg-server/glx/indirect_util.c | 620 +- xorg-server/glx/single2.c | 782 +- xorg-server/glx/single2swap.c | 532 +- xorg-server/glx/unpack.h | 468 +- xorg-server/glx/xfont.c | 6 +- xorg-server/hw/dmx/dmx.c | 2254 ++-- xorg-server/hw/dmx/dmx_glxvisuals.c | 1202 +- xorg-server/hw/dmx/dmxcmap.c | 424 +- xorg-server/hw/dmx/dmxcursor.c | 1970 +-- xorg-server/hw/dmx/dmxfont.c | 1110 +- xorg-server/hw/dmx/dmxgc.c | 842 +- xorg-server/hw/dmx/dmxinit.c | 2074 +-- xorg-server/hw/dmx/dmxpict.c | 26 +- xorg-server/hw/dmx/dmxpixmap.c | 506 +- xorg-server/hw/dmx/dmxprop.c | 694 +- xorg-server/hw/dmx/dmxscrinit.c | 1048 +- xorg-server/hw/dmx/dmxsync.c | 386 +- xorg-server/hw/dmx/dmxwindow.c | 2030 +-- xorg-server/hw/dmx/doc/dmx.sgml | 5555 ++++---- xorg-server/hw/dmx/glxProxy/glxcmds.c | 7220 +++++----- xorg-server/hw/dmx/glxProxy/glxext.c | 1064 +- xorg-server/hw/dmx/glxProxy/glxscreens.c | 754 +- xorg-server/hw/dmx/glxProxy/glxsingle.c | 2024 +-- xorg-server/hw/dmx/glxProxy/glxswap.c | 1076 +- xorg-server/hw/dmx/glxProxy/glxutil.c | 222 +- xorg-server/hw/dmx/glxProxy/glxvendor.c | 1164 +- xorg-server/hw/dmx/glxProxy/glxvisuals.c | 1078 +- xorg-server/hw/dmx/glxProxy/unpack.h | 456 +- xorg-server/hw/dmx/input/dmxinputinit.c | 2622 ++-- xorg-server/hw/dmx/input/dmxmotion.c | 284 +- xorg-server/hw/dmx/input/lnx-keyboard.c | 1980 +-- xorg-server/hw/dmx/input/usb-keyboard.c | 888 +- xorg-server/hw/kdrive/ephyr/ephyr.c | 2358 ++-- xorg-server/hw/kdrive/ephyr/ephyr_draw.c | 1047 +- xorg-server/hw/kdrive/ephyr/ephyrdriext.c | 2858 ++-- xorg-server/hw/kdrive/ephyr/ephyrglxext.c | 1446 +- xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c | 2024 +-- xorg-server/hw/kdrive/ephyr/ephyrvideo.c | 2546 ++-- xorg-server/hw/kdrive/fake/fake.c | 952 +- xorg-server/hw/kdrive/fbdev/fbdev.c | 1652 +-- xorg-server/hw/kdrive/linux/evdev.c | 1078 +- xorg-server/hw/kdrive/linux/keyboard.c | 1530 +-- xorg-server/hw/kdrive/linux/mouse.c | 2060 +-- xorg-server/hw/kdrive/linux/tslib.c | 380 +- xorg-server/hw/kdrive/src/kcmap.c | 492 +- xorg-server/hw/kdrive/src/kdrive.c | 2566 ++-- xorg-server/hw/kdrive/src/kinfo.c | 326 +- xorg-server/hw/kdrive/src/kinput.c | 4720 +++---- xorg-server/hw/kdrive/src/kshadow.c | 162 +- xorg-server/hw/kdrive/src/kxv.c | 3814 +++--- xorg-server/hw/vfb/InitOutput.c | 1946 +-- xorg-server/hw/xfree86/common/xf86.h | 708 +- xorg-server/hw/xfree86/common/xf86AutoConfig.c | 1276 +- xorg-server/hw/xfree86/common/xf86Bus.c | 1366 +- xorg-server/hw/xfree86/common/xf86Config.c | 5172 +++---- xorg-server/hw/xfree86/common/xf86Configure.c | 1784 +-- xorg-server/hw/xfree86/common/xf86Cursor.c | 1724 +-- xorg-server/hw/xfree86/common/xf86DGA.c | 2454 ++-- xorg-server/hw/xfree86/common/xf86DPMS.c | 400 +- xorg-server/hw/xfree86/common/xf86Events.c | 4 +- xorg-server/hw/xfree86/common/xf86Helper.c | 5176 +++---- xorg-server/hw/xfree86/common/xf86Init.c | 3644 ++--- xorg-server/hw/xfree86/common/xf86Mode.c | 4134 +++--- xorg-server/hw/xfree86/common/xf86Option.c | 1724 +-- xorg-server/hw/xfree86/common/xf86Privstr.h | 343 +- xorg-server/hw/xfree86/common/xf86RandR.c | 918 +- xorg-server/hw/xfree86/common/xf86ShowOpts.c | 256 +- xorg-server/hw/xfree86/common/xf86VGAarbiter.c | 2202 +-- xorg-server/hw/xfree86/common/xf86VidMode.c | 1334 +- xorg-server/hw/xfree86/common/xf86Xinput.c | 2568 ++-- xorg-server/hw/xfree86/common/xf86cmap.c | 2332 ++-- xorg-server/hw/xfree86/common/xf86fbman.c | 2876 ++-- xorg-server/hw/xfree86/common/xf86pciBus.c | 846 +- xorg-server/hw/xfree86/common/xf86sbusBus.c | 1376 +- xorg-server/hw/xfree86/common/xf86xv.c | 4203 +++--- xorg-server/hw/xfree86/common/xf86xvmc.c | 458 +- xorg-server/hw/xfree86/common/xisb.c | 348 +- xorg-server/hw/xfree86/ddc/ddc.c | 1014 +- xorg-server/hw/xfree86/ddc/ddcProperty.c | 250 +- xorg-server/hw/xfree86/ddc/interpret_edid.c | 1370 +- xorg-server/hw/xfree86/dixmods/extmod/modinit.c | 374 +- xorg-server/hw/xfree86/dixmods/extmod/xf86dga2.c | 2120 ++- xorg-server/hw/xfree86/dixmods/extmod/xf86vmode.c | 4340 +++--- xorg-server/hw/xfree86/dri/dri.c | 5008 +++---- xorg-server/hw/xfree86/dri/xf86dri.c | 1358 +- xorg-server/hw/xfree86/dri2/dri2.c | 165 +- xorg-server/hw/xfree86/dri2/dri2.h | 9 +- xorg-server/hw/xfree86/dri2/dri2ext.c | 64 +- xorg-server/hw/xfree86/exa/examodule.c | 396 +- xorg-server/hw/xfree86/fbdevhw/fbdevhw.c | 2018 +-- xorg-server/hw/xfree86/i2c/bt829.c | 1490 +- xorg-server/hw/xfree86/i2c/fi1236.c | 1210 +- xorg-server/hw/xfree86/i2c/msp3430.c | 1452 +- xorg-server/hw/xfree86/i2c/tda8425.c | 156 +- xorg-server/hw/xfree86/i2c/tda9850.c | 224 +- xorg-server/hw/xfree86/i2c/tda9885.c | 208 +- xorg-server/hw/xfree86/i2c/uda1380.c | 366 +- xorg-server/hw/xfree86/i2c/xf86i2c.c | 1732 +-- xorg-server/hw/xfree86/int10/generic.c | 988 +- xorg-server/hw/xfree86/int10/helper_exec.c | 1454 +- xorg-server/hw/xfree86/int10/helper_mem.c | 660 +- xorg-server/hw/xfree86/loader/loadext.c | 884 +- xorg-server/hw/xfree86/loader/loadmod.c | 2536 ++-- xorg-server/hw/xfree86/modes/xf86Crtc.c | 6402 ++++----- xorg-server/hw/xfree86/modes/xf86Cursors.c | 4 +- xorg-server/hw/xfree86/modes/xf86DiDGA.c | 436 +- xorg-server/hw/xfree86/modes/xf86DisplayIDModes.c | 874 +- xorg-server/hw/xfree86/modes/xf86EdidModes.c | 2430 ++-- xorg-server/hw/xfree86/modes/xf86Modes.c | 1454 +- xorg-server/hw/xfree86/modes/xf86RandR12.c | 3620 ++--- xorg-server/hw/xfree86/modes/xf86Rotate.c | 1054 +- xorg-server/hw/xfree86/os-support/bsd/i386_video.c | 1816 +-- xorg-server/hw/xfree86/os-support/bus/Sbus.c | 1380 +- .../hw/xfree86/os-support/linux/int10/linux.c | 1088 +- xorg-server/hw/xfree86/os-support/linux/lnx_agp.c | 748 +- .../hw/xfree86/os-support/linux/lnx_video.c | 1756 +-- .../hw/xfree86/os-support/shared/posix_tty.c | 1310 +- xorg-server/hw/xfree86/os-support/shared/vidmem.c | 592 +- .../hw/xfree86/os-support/solaris/sun_agp.c | 654 +- xorg-server/hw/xfree86/ramdac/xf86Cursor.c | 958 +- xorg-server/hw/xfree86/ramdac/xf86HWCurs.c | 1054 +- xorg-server/hw/xfree86/ramdac/xf86RamDac.c | 308 +- xorg-server/hw/xfree86/shadowfb/shadow.c | 3458 ++--- xorg-server/hw/xfree86/vbe/vbe.c | 2290 ++-- xorg-server/hw/xfree86/vbe/vbe.h | 682 +- xorg-server/hw/xfree86/vbe/vbeModes.c | 902 +- xorg-server/hw/xfree86/vgahw/vgaCmap.c | 602 +- xorg-server/hw/xfree86/vgahw/vgaHW.c | 3990 +++--- xorg-server/hw/xfree86/xaa/xaaBitBlt.c | 442 +- xorg-server/hw/xfree86/xaa/xaaCpyArea.c | 774 +- xorg-server/hw/xfree86/xaa/xaaCpyPlane.c | 416 +- xorg-server/hw/xfree86/xaa/xaaCpyWin.c | 164 +- xorg-server/hw/xfree86/xaa/xaaGC.c | 1312 +- xorg-server/hw/xfree86/xaa/xaaImage.c | 1042 +- xorg-server/hw/xfree86/xaa/xaaInit.c | 1248 +- xorg-server/hw/xfree86/xaa/xaaInitAccel.c | 2996 ++--- xorg-server/hw/xfree86/xaa/xaaLineMisc.c | 302 +- xorg-server/hw/xfree86/xaa/xaaNonTEText.c | 1182 +- xorg-server/hw/xfree86/xaa/xaaOffscreen.c | 324 +- xorg-server/hw/xfree86/xaa/xaaOverlay.c | 258 +- xorg-server/hw/xfree86/xaa/xaaOverlayDF.c | 2100 +-- xorg-server/hw/xfree86/xaa/xaaPCache.c | 4760 +++---- xorg-server/hw/xfree86/xaa/xaaPict.c | 1310 +- xorg-server/hw/xfree86/xaa/xaaStateChange.c | 3252 ++--- xorg-server/hw/xfree86/xaa/xaaTEGlyph.c | 2154 +-- xorg-server/hw/xfree86/xaa/xaaTEText.c | 624 +- xorg-server/hw/xfree86/xaa/xaaWrapper.c | 948 +- xorg-server/hw/xfree86/xaa/xaalocal.h | 3510 ++--- xorg-server/hw/xnest/Color.c | 990 +- xorg-server/hw/xnest/Cursor.c | 366 +- xorg-server/hw/xnest/Display.c | 386 +- xorg-server/hw/xnest/Font.c | 172 +- xorg-server/hw/xnest/GC.c | 678 +- xorg-server/hw/xnest/Keyboard.c | 514 +- xorg-server/hw/xnest/Pixmap.c | 282 +- xorg-server/hw/xnest/Screen.c | 841 +- xorg-server/hw/xquartz/GL/glcontextmodes.c | 1100 +- xorg-server/hw/xquartz/GL/indirect.c | 18 +- xorg-server/hw/xquartz/GL/visualConfigs.c | 570 +- xorg-server/hw/xquartz/applewm.c | 1492 +- xorg-server/hw/xquartz/darwin.c | 1816 +-- xorg-server/hw/xquartz/pseudoramiX.c | 942 +- xorg-server/hw/xquartz/quartz.c | 897 +- xorg-server/hw/xquartz/xpr/appledri.c | 858 +- xorg-server/hw/xquartz/xpr/dri.c | 1906 +-- xorg-server/hw/xquartz/xpr/driWrap.c | 1094 +- xorg-server/hw/xquartz/xpr/x-hook.c | 240 +- xorg-server/hw/xquartz/xpr/xprCursor.c | 836 +- xorg-server/hw/xquartz/xpr/xprScreen.c | 4 +- xorg-server/hw/xwin/glx/indirect.c | 4632 +++---- xorg-server/hw/xwin/win.h | 2928 ++-- xorg-server/hw/xwin/winauth.c | 4 +- xorg-server/hw/xwin/winconfig.c | 4 +- xorg-server/hw/xwin/windialogs.c | 1574 +-- xorg-server/hw/xwin/winerror.c | 304 +- xorg-server/hw/xwin/winvideo.c | 420 +- xorg-server/hw/xwin/winwindow.c | 1274 +- xorg-server/hw/xwin/winwindowswm.c | 26 +- xorg-server/include/colormap.h | 376 +- xorg-server/include/dixfont.h | 375 +- xorg-server/include/gc.h | 340 +- xorg-server/include/gcstruct.h | 648 +- xorg-server/include/misc.h | 590 +- xorg-server/include/os.h | 80 +- xorg-server/include/privates.h | 298 +- xorg-server/include/regionstr.h | 586 +- xorg-server/include/resource.h | 558 +- xorg-server/include/scrnintstr.h | 1242 +- xorg-server/mi/miarc.c | 102 +- xorg-server/mi/mibitblt.c | 1661 ++- xorg-server/mi/micmap.c | 1332 +- xorg-server/mi/micopy.c | 708 +- xorg-server/mi/midispcur.c | 1748 +-- xorg-server/mi/mieq.c | 4 +- xorg-server/mi/miexpose.c | 1399 +- xorg-server/mi/mifillarc.c | 1596 +-- xorg-server/mi/mifillrct.c | 286 +- xorg-server/mi/mifpolycon.c | 560 +- xorg-server/mi/migc.c | 510 +- xorg-server/mi/miglblt.c | 516 +- xorg-server/mi/mioverlay.c | 3896 +++--- xorg-server/mi/mipointer.c | 1172 +- xorg-server/mi/mipolycon.c | 494 +- xorg-server/mi/mipolygen.c | 460 +- xorg-server/mi/mipolypnt.c | 250 +- xorg-server/mi/mipolyrect.c | 374 +- xorg-server/mi/mipolyutil.c | 770 +- xorg-server/mi/mipushpxl.c | 542 +- xorg-server/mi/miregion.c | 3690 ++--- xorg-server/mi/miscrinit.c | 625 +- xorg-server/mi/mispans.c | 1058 +- xorg-server/mi/misprite.c | 2230 +-- xorg-server/mi/miwideline.c | 4453 +++--- xorg-server/mi/miwideline.h | 236 +- xorg-server/mi/miwindow.c | 1672 +-- xorg-server/mi/mizerarc.c | 1692 +-- xorg-server/mi/mizerline.c | 758 +- xorg-server/miext/cw/cw.c | 1044 +- xorg-server/miext/cw/cw_render.c | 938 +- xorg-server/miext/damage/damage.c | 4332 +++--- xorg-server/miext/rootless/rootlessScreen.c | 1510 +-- xorg-server/miext/rootless/rootlessWindow.c | 3312 ++--- xorg-server/miext/shadow/shadow.c | 498 +- xorg-server/miext/shadow/shalloc.c | 100 +- xorg-server/os/WaitFor.c | 1362 +- xorg-server/os/access.c | 37 +- xorg-server/os/connection.c | 2600 ++-- xorg-server/os/io.c | 2214 +-- xorg-server/os/log.c | 1221 +- xorg-server/os/mitauth.c | 14 +- xorg-server/os/osinit.c | 653 +- xorg-server/os/rpcauth.c | 6 +- xorg-server/os/utils.c | 3867 +++--- xorg-server/os/xdmauth.c | 44 +- xorg-server/os/xdmcp.c | 14 +- xorg-server/os/xprintf.c | 208 +- xorg-server/os/xsha1.c | 336 +- xorg-server/randr/randr.c | 992 +- xorg-server/randr/rrcrtc.c | 2774 ++-- xorg-server/randr/rrdispatch.c | 456 +- xorg-server/randr/rrinfo.c | 682 +- xorg-server/randr/rrmode.c | 738 +- xorg-server/randr/rroutput.c | 1242 +- xorg-server/randr/rrproperty.c | 56 +- xorg-server/randr/rrscreen.c | 2008 +-- xorg-server/randr/rrtransform.c | 570 +- xorg-server/randr/rrxinerama.c | 952 +- xorg-server/record/record.c | 5834 ++++---- xorg-server/record/set.c | 862 +- xorg-server/render/animcur.c | 860 +- xorg-server/render/filter.c | 718 +- xorg-server/render/glyph.c | 1508 +-- xorg-server/render/miindex.c | 716 +- xorg-server/render/mipict.c | 1286 +- xorg-server/render/mirect.c | 371 +- xorg-server/render/mitri.c | 382 +- xorg-server/render/picture.c | 56 +- xorg-server/render/render.c | 164 +- xorg-server/test/xi2/protocol-common.c | 337 +- xorg-server/test/xi2/protocol-eventconvert.c | 1814 +-- xorg-server/xfixes/cursor.c | 2208 +-- xorg-server/xfixes/region.c | 65 +- xorg-server/xfixes/saveset.c | 148 +- xorg-server/xfixes/select.c | 584 +- xorg-server/xfixes/xfixes.c | 526 +- xorg-server/xkb/XKBAlloc.c | 674 +- xorg-server/xkb/XKBGAlloc.c | 1994 +-- xorg-server/xkb/XKBMAlloc.c | 1800 +-- xorg-server/xkb/XKBMisc.c | 1678 +-- xorg-server/xkb/ddxList.c | 586 +- xorg-server/xkb/ddxLoad.c | 916 +- xorg-server/xkb/maprules.c | 2038 +-- xorg-server/xkb/xkb.c | 13442 +++++++++---------- xorg-server/xkb/xkbActions.c | 2778 ++-- xorg-server/xkb/xkbEvents.c | 2224 +-- xorg-server/xkb/xkbInit.c | 1558 +-- xorg-server/xkb/xkbLEDs.c | 1954 +-- xorg-server/xkb/xkbUtils.c | 4384 +++--- xorg-server/xkb/xkmread.c | 2476 ++-- xorg-server/xkbdata.src/symbols/fi | 438 +- xorg-server/xkbdata.src/symbols/hu | 859 +- 377 files changed, 263887 insertions(+), 264262 deletions(-) (limited to 'xorg-server') diff --git a/xorg-server/Xext/bigreq.c b/xorg-server/Xext/bigreq.c index f9f15edc5..4ebc0d6b9 100644 --- a/xorg-server/Xext/bigreq.c +++ b/xorg-server/Xext/bigreq.c @@ -1,80 +1,80 @@ -/* - -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 "modinit.h" - -static DISPATCH_PROC(ProcBigReqDispatch); - -void BigReqExtensionInit(INITARGS); - -void -BigReqExtensionInit(INITARGS) -{ - AddExtension(XBigReqExtensionName, 0, 0, - ProcBigReqDispatch, ProcBigReqDispatch, - NULL, StandardMinorOpcode); -} - -static int -ProcBigReqDispatch (ClientPtr client) -{ - REQUEST(xBigReqEnableReq); - xBigReqEnableReply rep; - int n; - - if (client->swapped) { - swaps(&stuff->length, n); - } - if (stuff->brReqType != X_BigReqEnable) - return BadRequest; - REQUEST_SIZE_MATCH(xBigReqEnableReq); - client->big_requests = TRUE; - memset(&rep, 0, sizeof(xBigReqEnableReply)); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.max_request_size = maxBigRequestSize; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.max_request_size, n); - } - WriteToClient(client, sizeof(xBigReqEnableReply), (char *)&rep); - return(client->noClientException); -} +/* + +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 "modinit.h" + +static DISPATCH_PROC(ProcBigReqDispatch); + +void BigReqExtensionInit(INITARGS); + +void +BigReqExtensionInit(INITARGS) +{ + AddExtension(XBigReqExtensionName, 0, 0, + ProcBigReqDispatch, ProcBigReqDispatch, + NULL, StandardMinorOpcode); +} + +static int +ProcBigReqDispatch (ClientPtr client) +{ + REQUEST(xBigReqEnableReq); + xBigReqEnableReply rep; + int n; + + if (client->swapped) { + swaps(&stuff->length, n); + } + if (stuff->brReqType != X_BigReqEnable) + return BadRequest; + REQUEST_SIZE_MATCH(xBigReqEnableReq); + client->big_requests = TRUE; + memset(&rep, 0, sizeof(xBigReqEnableReply)); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.max_request_size = maxBigRequestSize; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.max_request_size, n); + } + WriteToClient(client, sizeof(xBigReqEnableReply), (char *)&rep); + return Success; +} diff --git a/xorg-server/Xext/dpms.c b/xorg-server/Xext/dpms.c index df63a8bf1..13854f704 100644 --- a/xorg-server/Xext/dpms.c +++ b/xorg-server/Xext/dpms.c @@ -1,379 +1,379 @@ -/***************************************************************** - -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. - -******************************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include "misc.h" -#include "os.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "opaque.h" -#include -#include "dpmsproc.h" -#include "modinit.h" - -static int -ProcDPMSGetVersion(ClientPtr client) -{ - /* REQUEST(xDPMSGetVersionReq); */ - xDPMSGetVersionReply rep; - int n; - - 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, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xDPMSGetVersionReply), (char *)&rep); - return(client->noClientException); -} - -static int -ProcDPMSCapable(ClientPtr client) -{ - /* REQUEST(xDPMSCapableReq); */ - xDPMSCapableReply rep; - int n; - - REQUEST_SIZE_MATCH(xDPMSCapableReq); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.capable = DPMSCapableFlag; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - } - WriteToClient(client, sizeof(xDPMSCapableReply), (char *)&rep); - return(client->noClientException); -} - -static int -ProcDPMSGetTimeouts(ClientPtr client) -{ - /* REQUEST(xDPMSGetTimeoutsReq); */ - xDPMSGetTimeoutsReply rep; - int n; - - 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, n); - swaps(&rep.standby, n); - swaps(&rep.suspend, n); - swaps(&rep.off, n); - } - WriteToClient(client, sizeof(xDPMSGetTimeoutsReply), (char *)&rep); - return(client->noClientException); -} - -static int -ProcDPMSSetTimeouts(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(ClientPtr client) -{ - Bool was_enabled = DPMSEnabled; - - REQUEST_SIZE_MATCH(xDPMSEnableReq); - - if (DPMSCapableFlag) { - DPMSEnabled = TRUE; - if (!was_enabled) - SetScreenSaverTimer(); - } - - return(client->noClientException); -} - -static int -ProcDPMSDisable(ClientPtr client) -{ - /* REQUEST(xDPMSDisableReq); */ - - REQUEST_SIZE_MATCH(xDPMSDisableReq); - - DPMSSet(client, DPMSModeOn); - - DPMSEnabled = FALSE; - - return(client->noClientException); -} - -static int -ProcDPMSForceLevel(ClientPtr client) -{ - REQUEST(xDPMSForceLevelReq); - - REQUEST_SIZE_MATCH(xDPMSForceLevelReq); - - if (!DPMSEnabled) - return BadMatch; - - if (stuff->level != DPMSModeOn && - stuff->level != DPMSModeStandby && - stuff->level != DPMSModeSuspend && - stuff->level != DPMSModeOff) { - client->errorValue = stuff->level; - return BadValue; - } - - DPMSSet(client, stuff->level); - - return(client->noClientException); -} - -static int -ProcDPMSInfo(ClientPtr client) -{ - /* REQUEST(xDPMSInfoReq); */ - xDPMSInfoReply rep; - int n; - - 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, n); - swaps(&rep.power_level, n); - } - WriteToClient(client, sizeof(xDPMSInfoReply), (char *)&rep); - return(client->noClientException); -} - -static int -ProcDPMSDispatch (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(ClientPtr client) -{ - int n; - REQUEST(xDPMSGetVersionReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDPMSGetVersionReq); - swaps(&stuff->majorVersion, n); - swaps(&stuff->minorVersion, n); - return ProcDPMSGetVersion(client); -} - -static int -SProcDPMSCapable(ClientPtr client) -{ - REQUEST(xDPMSCapableReq); - int n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDPMSCapableReq); - - return ProcDPMSCapable(client); -} - -static int -SProcDPMSGetTimeouts(ClientPtr client) -{ - REQUEST(xDPMSGetTimeoutsReq); - int n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDPMSGetTimeoutsReq); - - return ProcDPMSGetTimeouts(client); -} - -static int -SProcDPMSSetTimeouts(ClientPtr client) -{ - REQUEST(xDPMSSetTimeoutsReq); - int n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDPMSSetTimeoutsReq); - - swaps(&stuff->standby, n); - swaps(&stuff->suspend, n); - swaps(&stuff->off, n); - return ProcDPMSSetTimeouts(client); -} - -static int -SProcDPMSEnable(ClientPtr client) -{ - REQUEST(xDPMSEnableReq); - int n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDPMSEnableReq); - - return ProcDPMSEnable(client); -} - -static int -SProcDPMSDisable(ClientPtr client) -{ - REQUEST(xDPMSDisableReq); - int n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDPMSDisableReq); - - return ProcDPMSDisable(client); -} - -static int -SProcDPMSForceLevel(ClientPtr client) -{ - REQUEST(xDPMSForceLevelReq); - int n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDPMSForceLevelReq); - - swaps(&stuff->level, n); - - return ProcDPMSForceLevel(client); -} - -static int -SProcDPMSInfo(ClientPtr client) -{ - REQUEST(xDPMSInfoReq); - int n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDPMSInfoReq); - - return ProcDPMSInfo(client); -} - -static int -SProcDPMSDispatch (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; - } -} - -void -DPMSExtensionInit(INITARGS) -{ - AddExtension(DPMSExtensionName, 0, 0, - ProcDPMSDispatch, SProcDPMSDispatch, - NULL, StandardMinorOpcode); -} +/***************************************************************** + +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. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "opaque.h" +#include +#include "dpmsproc.h" +#include "modinit.h" + +static int +ProcDPMSGetVersion(ClientPtr client) +{ + /* REQUEST(xDPMSGetVersionReq); */ + xDPMSGetVersionReply rep; + int n; + + 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, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xDPMSGetVersionReply), (char *)&rep); + return Success; +} + +static int +ProcDPMSCapable(ClientPtr client) +{ + /* REQUEST(xDPMSCapableReq); */ + xDPMSCapableReply rep; + int n; + + REQUEST_SIZE_MATCH(xDPMSCapableReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.capable = DPMSCapableFlag; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + } + WriteToClient(client, sizeof(xDPMSCapableReply), (char *)&rep); + return Success; +} + +static int +ProcDPMSGetTimeouts(ClientPtr client) +{ + /* REQUEST(xDPMSGetTimeoutsReq); */ + xDPMSGetTimeoutsReply rep; + int n; + + 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, n); + swaps(&rep.standby, n); + swaps(&rep.suspend, n); + swaps(&rep.off, n); + } + WriteToClient(client, sizeof(xDPMSGetTimeoutsReply), (char *)&rep); + return Success; +} + +static int +ProcDPMSSetTimeouts(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 Success; +} + +static int +ProcDPMSEnable(ClientPtr client) +{ + Bool was_enabled = DPMSEnabled; + + REQUEST_SIZE_MATCH(xDPMSEnableReq); + + if (DPMSCapableFlag) { + DPMSEnabled = TRUE; + if (!was_enabled) + SetScreenSaverTimer(); + } + + return Success; +} + +static int +ProcDPMSDisable(ClientPtr client) +{ + /* REQUEST(xDPMSDisableReq); */ + + REQUEST_SIZE_MATCH(xDPMSDisableReq); + + DPMSSet(client, DPMSModeOn); + + DPMSEnabled = FALSE; + + return Success; +} + +static int +ProcDPMSForceLevel(ClientPtr client) +{ + REQUEST(xDPMSForceLevelReq); + + REQUEST_SIZE_MATCH(xDPMSForceLevelReq); + + if (!DPMSEnabled) + return BadMatch; + + if (stuff->level != DPMSModeOn && + stuff->level != DPMSModeStandby && + stuff->level != DPMSModeSuspend && + stuff->level != DPMSModeOff) { + client->errorValue = stuff->level; + return BadValue; + } + + DPMSSet(client, stuff->level); + + return Success; +} + +static int +ProcDPMSInfo(ClientPtr client) +{ + /* REQUEST(xDPMSInfoReq); */ + xDPMSInfoReply rep; + int n; + + 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, n); + swaps(&rep.power_level, n); + } + WriteToClient(client, sizeof(xDPMSInfoReply), (char *)&rep); + return Success; +} + +static int +ProcDPMSDispatch (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(ClientPtr client) +{ + int n; + REQUEST(xDPMSGetVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDPMSGetVersionReq); + swaps(&stuff->majorVersion, n); + swaps(&stuff->minorVersion, n); + return ProcDPMSGetVersion(client); +} + +static int +SProcDPMSCapable(ClientPtr client) +{ + REQUEST(xDPMSCapableReq); + int n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDPMSCapableReq); + + return ProcDPMSCapable(client); +} + +static int +SProcDPMSGetTimeouts(ClientPtr client) +{ + REQUEST(xDPMSGetTimeoutsReq); + int n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDPMSGetTimeoutsReq); + + return ProcDPMSGetTimeouts(client); +} + +static int +SProcDPMSSetTimeouts(ClientPtr client) +{ + REQUEST(xDPMSSetTimeoutsReq); + int n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDPMSSetTimeoutsReq); + + swaps(&stuff->standby, n); + swaps(&stuff->suspend, n); + swaps(&stuff->off, n); + return ProcDPMSSetTimeouts(client); +} + +static int +SProcDPMSEnable(ClientPtr client) +{ + REQUEST(xDPMSEnableReq); + int n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDPMSEnableReq); + + return ProcDPMSEnable(client); +} + +static int +SProcDPMSDisable(ClientPtr client) +{ + REQUEST(xDPMSDisableReq); + int n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDPMSDisableReq); + + return ProcDPMSDisable(client); +} + +static int +SProcDPMSForceLevel(ClientPtr client) +{ + REQUEST(xDPMSForceLevelReq); + int n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDPMSForceLevelReq); + + swaps(&stuff->level, n); + + return ProcDPMSForceLevel(client); +} + +static int +SProcDPMSInfo(ClientPtr client) +{ + REQUEST(xDPMSInfoReq); + int n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDPMSInfoReq); + + return ProcDPMSInfo(client); +} + +static int +SProcDPMSDispatch (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; + } +} + +void +DPMSExtensionInit(INITARGS) +{ + AddExtension(DPMSExtensionName, 0, 0, + ProcDPMSDispatch, SProcDPMSDispatch, + NULL, StandardMinorOpcode); +} diff --git a/xorg-server/Xext/geext.c b/xorg-server/Xext/geext.c index f0a3d8778..253c87bc9 100644 --- a/xorg-server/Xext/geext.c +++ b/xorg-server/Xext/geext.c @@ -1,267 +1,267 @@ -/* - * Copyright 2007-2008 Peter Hutterer - * - * 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. - * - * Author: Peter Hutterer, University of South Australia, NICTA - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif -#include "windowstr.h" -#include -#include "registry.h" - -#include "geint.h" -#include "geext.h" -#include "protocol-versions.h" - -#define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) - -static int GEClientPrivateKeyIndex; -DevPrivateKey GEClientPrivateKey = &GEClientPrivateKeyIndex; - -int RT_GECLIENT = 0; - - -GEExtension GEExtensions[MAXEXTENSIONS]; - -/* Major available requests */ -static const int version_requests[] = { - X_GEQueryVersion, /* before client sends QueryVersion */ - X_GEQueryVersion, /* must be set to last request in version 1 */ -}; - -/* Forward declarations */ -static void SGEGenericEvent(xEvent* from, xEvent* to); - -#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) - -/************************************************************/ -/* request handlers */ -/************************************************************/ - -static int -ProcGEQueryVersion(ClientPtr client) -{ - int n; - GEClientInfoPtr pGEClient = GEGetClient(client); - xGEQueryVersionReply rep; - REQUEST(xGEQueryVersionReq); - - REQUEST_SIZE_MATCH(xGEQueryVersionReq); - - rep.repType = X_Reply; - rep.RepType = X_GEQueryVersion; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - /* return the supported version by the server */ - rep.majorVersion = SERVER_GE_MAJOR_VERSION; - rep.minorVersion = SERVER_GE_MINOR_VERSION; - - /* Remember version the client requested */ - pGEClient->major_version = stuff->majorVersion; - pGEClient->minor_version = stuff->minorVersion; - - if (client->swapped) - { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - - WriteToClient(client, sizeof(xGEQueryVersionReply), (char*)&rep); - return(client->noClientException); -} - -int (*ProcGEVector[GENumberRequests])(ClientPtr) = { - /* Version 1.0 */ - ProcGEQueryVersion -}; - -/************************************************************/ -/* swapped request handlers */ -/************************************************************/ -static int -SProcGEQueryVersion(ClientPtr client) -{ - int n; - REQUEST(xGEQueryVersionReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xGEQueryVersionReq); - swaps(&stuff->majorVersion, n); - swaps(&stuff->minorVersion, n); - return(*ProcGEVector[stuff->ReqType])(client); -} - -int (*SProcGEVector[GENumberRequests])(ClientPtr) = { - /* Version 1.0 */ - SProcGEQueryVersion -}; - - -/************************************************************/ -/* callbacks */ -/************************************************************/ - -/* dispatch requests */ -static int -ProcGEDispatch(ClientPtr client) -{ - GEClientInfoPtr pGEClient = GEGetClient(client); - REQUEST(xGEReq); - - if (pGEClient->major_version >= NUM_VERSION_REQUESTS) - return BadRequest; - if (stuff->ReqType > version_requests[pGEClient->major_version]) - return BadRequest; - - return (ProcGEVector[stuff->ReqType])(client); -} - -/* dispatch swapped requests */ -static int -SProcGEDispatch(ClientPtr client) -{ - REQUEST(xGEReq); - if (stuff->ReqType >= GENumberRequests) - return BadRequest; - return (*SProcGEVector[stuff->ReqType])(client); -} - -/** - * Called when a new client inits a connection to the X server. - * - * We alloc a simple struct to store the client's major/minor version. Can be - * used in the furture for versioning support. - */ -static void -GEClientCallback(CallbackListPtr *list, - pointer closure, - pointer data) -{ - NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; - ClientPtr pClient = clientinfo->client; - GEClientInfoPtr pGEClient = GEGetClient(pClient); - - pGEClient->major_version = 0; - pGEClient->minor_version = 0; -} - -/* Reset extension. Called on server shutdown. */ -static void -GEResetProc(ExtensionEntry *extEntry) -{ - DeleteCallback(&ClientStateCallback, GEClientCallback, 0); - EventSwapVector[GenericEvent] = NotImplemented; -} - -/* Calls the registered event swap function for the extension. - * - * Each extension can register a swap function to handle GenericEvents being - * swapped properly. The server calls SGEGenericEvent() before the event is - * written on the wire, this one calls the registered swap function to do the - * work. - */ -static void -SGEGenericEvent(xEvent* from, xEvent* to) -{ - xGenericEvent* gefrom = (xGenericEvent*)from; - xGenericEvent* geto = (xGenericEvent*)to; - - if (gefrom->extension > MAXEXTENSIONS) - { - ErrorF("GE: Invalid extension offset for event.\n"); - return; - } - - if (GEExtensions[gefrom->extension & 0x7F].evswap) - GEExtensions[gefrom->extension & 0x7F].evswap(gefrom, geto); -} - -/* Init extension, register at server. - * Since other extensions may rely on XGE (XInput does already), it is a good - * idea to init XGE first, before any other extension. - */ -void -GEExtensionInit(void) -{ - ExtensionEntry *extEntry; - - if (!dixRequestPrivate(GEClientPrivateKey, sizeof(GEClientInfoRec))) - FatalError("GEExtensionInit: GE private request failed.\n"); - - if(!AddCallback(&ClientStateCallback, GEClientCallback, 0)) - { - FatalError("GEExtensionInit: register client callback failed.\n"); - } - - if((extEntry = AddExtension(GE_NAME, - 0, GENumberErrors, - ProcGEDispatch, SProcGEDispatch, - GEResetProc, StandardMinorOpcode)) != 0) - { - memset(GEExtensions, 0, sizeof(GEExtensions)); - - EventSwapVector[GenericEvent] = (EventSwapPtr) SGEGenericEvent; - } else { - FatalError("GEInit: AddExtensions failed.\n"); - } - -} - -/************************************************************/ -/* interface for extensions */ -/************************************************************/ - -/* Register an extension with GE. The given swap function will be called each - * time an event is sent to a client with different byte order. - * @param extension The extensions major opcode - * @param ev_swap The event swap function. - * @param ev_fill Called for an event before delivery. The extension now has - * the chance to fill in necessary fields for the event. - */ -void -GERegisterExtension(int extension, - void (*ev_swap)(xGenericEvent* from, xGenericEvent* to)) -{ - if ((extension & 0x7F) >= MAXEXTENSIONS) - FatalError("GE: extension > MAXEXTENSIONS. This should not happen.\n"); - - /* extension opcodes are > 128, might as well save some space here */ - GEExtensions[extension & 0x7f].evswap = ev_swap; -} - - -/* Sets type and extension field for a generic event. This is just an - * auxiliary function, extensions could do it manually too. - */ -void -GEInitEvent(xGenericEvent* ev, int extension) -{ - ev->type = GenericEvent; - ev->extension = extension; - ev->length = 0; -} - +/* + * Copyright 2007-2008 Peter Hutterer + * + * 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. + * + * Author: Peter Hutterer, University of South Australia, NICTA + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif +#include "windowstr.h" +#include +#include "registry.h" + +#include "geint.h" +#include "geext.h" +#include "protocol-versions.h" + +#define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) + +static int GEClientPrivateKeyIndex; +DevPrivateKey GEClientPrivateKey = &GEClientPrivateKeyIndex; + +int RT_GECLIENT = 0; + + +GEExtension GEExtensions[MAXEXTENSIONS]; + +/* Major available requests */ +static const int version_requests[] = { + X_GEQueryVersion, /* before client sends QueryVersion */ + X_GEQueryVersion, /* must be set to last request in version 1 */ +}; + +/* Forward declarations */ +static void SGEGenericEvent(xEvent* from, xEvent* to); + +#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) + +/************************************************************/ +/* request handlers */ +/************************************************************/ + +static int +ProcGEQueryVersion(ClientPtr client) +{ + int n; + GEClientInfoPtr pGEClient = GEGetClient(client); + xGEQueryVersionReply rep; + REQUEST(xGEQueryVersionReq); + + REQUEST_SIZE_MATCH(xGEQueryVersionReq); + + rep.repType = X_Reply; + rep.RepType = X_GEQueryVersion; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + /* return the supported version by the server */ + rep.majorVersion = SERVER_GE_MAJOR_VERSION; + rep.minorVersion = SERVER_GE_MINOR_VERSION; + + /* Remember version the client requested */ + pGEClient->major_version = stuff->majorVersion; + pGEClient->minor_version = stuff->minorVersion; + + if (client->swapped) + { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + + WriteToClient(client, sizeof(xGEQueryVersionReply), (char*)&rep); + return Success; +} + +int (*ProcGEVector[GENumberRequests])(ClientPtr) = { + /* Version 1.0 */ + ProcGEQueryVersion +}; + +/************************************************************/ +/* swapped request handlers */ +/************************************************************/ +static int +SProcGEQueryVersion(ClientPtr client) +{ + int n; + REQUEST(xGEQueryVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xGEQueryVersionReq); + swaps(&stuff->majorVersion, n); + swaps(&stuff->minorVersion, n); + return(*ProcGEVector[stuff->ReqType])(client); +} + +int (*SProcGEVector[GENumberRequests])(ClientPtr) = { + /* Version 1.0 */ + SProcGEQueryVersion +}; + + +/************************************************************/ +/* callbacks */ +/************************************************************/ + +/* dispatch requests */ +static int +ProcGEDispatch(ClientPtr client) +{ + GEClientInfoPtr pGEClient = GEGetClient(client); + REQUEST(xGEReq); + + if (pGEClient->major_version >= NUM_VERSION_REQUESTS) + return BadRequest; + if (stuff->ReqType > version_requests[pGEClient->major_version]) + return BadRequest; + + return (ProcGEVector[stuff->ReqType])(client); +} + +/* dispatch swapped requests */ +static int +SProcGEDispatch(ClientPtr client) +{ + REQUEST(xGEReq); + if (stuff->ReqType >= GENumberRequests) + return BadRequest; + return (*SProcGEVector[stuff->ReqType])(client); +} + +/** + * Called when a new client inits a connection to the X server. + * + * We alloc a simple struct to store the client's major/minor version. Can be + * used in the furture for versioning support. + */ +static void +GEClientCallback(CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + GEClientInfoPtr pGEClient = GEGetClient(pClient); + + pGEClient->major_version = 0; + pGEClient->minor_version = 0; +} + +/* Reset extension. Called on server shutdown. */ +static void +GEResetProc(ExtensionEntry *extEntry) +{ + DeleteCallback(&ClientStateCallback, GEClientCallback, 0); + EventSwapVector[GenericEvent] = NotImplemented; +} + +/* Calls the registered event swap function for the extension. + * + * Each extension can register a swap function to handle GenericEvents being + * swapped properly. The server calls SGEGenericEvent() before the event is + * written on the wire, this one calls the registered swap function to do the + * work. + */ +static void +SGEGenericEvent(xEvent* from, xEvent* to) +{ + xGenericEvent* gefrom = (xGenericEvent*)from; + xGenericEvent* geto = (xGenericEvent*)to; + + if (gefrom->extension > MAXEXTENSIONS) + { + ErrorF("GE: Invalid extension offset for event.\n"); + return; + } + + if (GEExtensions[gefrom->extension & 0x7F].evswap) + GEExtensions[gefrom->extension & 0x7F].evswap(gefrom, geto); +} + +/* Init extension, register at server. + * Since other extensions may rely on XGE (XInput does already), it is a good + * idea to init XGE first, before any other extension. + */ +void +GEExtensionInit(void) +{ + ExtensionEntry *extEntry; + + if (!dixRequestPrivate(GEClientPrivateKey, sizeof(GEClientInfoRec))) + FatalError("GEExtensionInit: GE private request failed.\n"); + + if(!AddCallback(&ClientStateCallback, GEClientCallback, 0)) + { + FatalError("GEExtensionInit: register client callback failed.\n"); + } + + if((extEntry = AddExtension(GE_NAME, + 0, GENumberErrors, + ProcGEDispatch, SProcGEDispatch, + GEResetProc, StandardMinorOpcode)) != 0) + { + memset(GEExtensions, 0, sizeof(GEExtensions)); + + EventSwapVector[GenericEvent] = (EventSwapPtr) SGEGenericEvent; + } else { + FatalError("GEInit: AddExtensions failed.\n"); + } + +} + +/************************************************************/ +/* interface for extensions */ +/************************************************************/ + +/* Register an extension with GE. The given swap function will be called each + * time an event is sent to a client with different byte order. + * @param extension The extensions major opcode + * @param ev_swap The event swap function. + * @param ev_fill Called for an event before delivery. The extension now has + * the chance to fill in necessary fields for the event. + */ +void +GERegisterExtension(int extension, + void (*ev_swap)(xGenericEvent* from, xGenericEvent* to)) +{ + if ((extension & 0x7F) >= MAXEXTENSIONS) + FatalError("GE: extension > MAXEXTENSIONS. This should not happen.\n"); + + /* extension opcodes are > 128, might as well save some space here */ + GEExtensions[extension & 0x7f].evswap = ev_swap; +} + + +/* Sets type and extension field for a generic event. This is just an + * auxiliary function, extensions could do it manually too. + */ +void +GEInitEvent(xGenericEvent* ev, int extension) +{ + ev->type = GenericEvent; + ev->extension = extension; + ev->length = 0; +} + diff --git a/xorg-server/Xext/panoramiX.c b/xorg-server/Xext/panoramiX.c index d5965c2d0..e26aadc95 100644 --- a/xorg-server/Xext/panoramiX.c +++ b/xorg-server/Xext/panoramiX.c @@ -1,1284 +1,1284 @@ -/***************************************************************** -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 - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include "misc.h" -#include "cursor.h" -#include "cursorstr.h" -#include "extnsionst.h" -#include "dixstruct.h" -#include "gc.h" -#include "gcstruct.h" -#include "scrnintstr.h" -#include "window.h" -#include "windowstr.h" -#include "pixmapstr.h" -#include "panoramiX.h" -#include -#include "panoramiXsrv.h" -#include "globals.h" -#include "servermd.h" -#include "resource.h" -#include "picturestr.h" -#include "modinit.h" -#include "protocol-versions.h" - -#ifdef GLXPROXY -extern VisualPtr glxMatchVisual(ScreenPtr pScreen, - VisualPtr pVisual, - ScreenPtr pMatchScreen); -#endif - -/* - * PanoramiX data declarations - */ - -int PanoramiXPixWidth = 0; -int PanoramiXPixHeight = 0; -int PanoramiXNumScreens = 0; - -PanoramiXData *panoramiXdataPtr = NULL; -static RegionRec PanoramiXScreenRegion = {{0, 0, 0, 0}, NULL}; - -static int PanoramiXNumDepths; -static DepthPtr PanoramiXDepths; -static int PanoramiXNumVisuals; -static VisualPtr PanoramiXVisuals; - -unsigned long XRC_DRAWABLE; -unsigned long XRT_WINDOW; -unsigned long XRT_PIXMAP; -unsigned long XRT_GC; -unsigned long XRT_COLORMAP; - -static Bool VisualsEqual(VisualPtr, ScreenPtr, VisualPtr); -XineramaVisualsEqualProcPtr XineramaVisualsEqualPtr = &VisualsEqual; - -/* - * Function prototypes - */ - -static int panoramiXGeneration; -static int ProcPanoramiXDispatch(ClientPtr client); - -static void PanoramiXResetProc(ExtensionEntry*); - -/* - * External references for functions and data variables - */ - -#include "panoramiXh.h" - -int (* SavedProcVector[256]) (ClientPtr client) = { NULL, }; - -static int PanoramiXGCKeyIndex; -static DevPrivateKey PanoramiXGCKey = &PanoramiXGCKeyIndex; -static int PanoramiXScreenKeyIndex; -static DevPrivateKey PanoramiXScreenKey = &PanoramiXScreenKeyIndex; - -typedef struct { - DDXPointRec clipOrg; - DDXPointRec patOrg; - GCFuncs *wrapFuncs; -} PanoramiXGCRec, *PanoramiXGCPtr; - -typedef struct { - CreateGCProcPtr CreateGC; - CloseScreenProcPtr CloseScreen; -} PanoramiXScreenRec, *PanoramiXScreenPtr; - -RegionRec XineramaScreenRegions[MAXSCREENS]; - -static void XineramaValidateGC(GCPtr, unsigned long, DrawablePtr); -static void XineramaChangeGC(GCPtr, unsigned long); -static void XineramaCopyGC(GCPtr, unsigned long, GCPtr); -static void XineramaDestroyGC(GCPtr); -static void XineramaChangeClip(GCPtr, int, pointer, int); -static void XineramaDestroyClip(GCPtr); -static void XineramaCopyClip(GCPtr, GCPtr); - -static GCFuncs XineramaGCFuncs = { - XineramaValidateGC, XineramaChangeGC, XineramaCopyGC, XineramaDestroyGC, - XineramaChangeClip, XineramaDestroyClip, XineramaCopyClip -}; - -#define Xinerama_GC_FUNC_PROLOGUE(pGC)\ - PanoramiXGCPtr pGCPriv = (PanoramiXGCPtr) \ - dixLookupPrivate(&(pGC)->devPrivates, PanoramiXGCKey); \ - (pGC)->funcs = pGCPriv->wrapFuncs; - -#define Xinerama_GC_FUNC_EPILOGUE(pGC)\ - pGCPriv->wrapFuncs = (pGC)->funcs;\ - (pGC)->funcs = &XineramaGCFuncs; - - -static Bool -XineramaCloseScreen (int i, ScreenPtr pScreen) -{ - PanoramiXScreenPtr pScreenPriv = (PanoramiXScreenPtr) - dixLookupPrivate(&pScreen->devPrivates, PanoramiXScreenKey); - - pScreen->CloseScreen = pScreenPriv->CloseScreen; - pScreen->CreateGC = pScreenPriv->CreateGC; - - REGION_UNINIT(pScreen, &XineramaScreenRegions[pScreen->myNum]); - if (pScreen->myNum == 0) - REGION_UNINIT(pScreen, &PanoramiXScreenRegion); - - xfree ((pointer) pScreenPriv); - - return (*pScreen->CloseScreen) (i, pScreen); -} - -static Bool -XineramaCreateGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - PanoramiXScreenPtr pScreenPriv = (PanoramiXScreenPtr) - dixLookupPrivate(&pScreen->devPrivates, PanoramiXScreenKey); - Bool ret; - - pScreen->CreateGC = pScreenPriv->CreateGC; - if((ret = (*pScreen->CreateGC)(pGC))) { - PanoramiXGCPtr pGCPriv = (PanoramiXGCPtr) - dixLookupPrivate(&pGC->devPrivates, PanoramiXGCKey); - - pGCPriv->wrapFuncs = pGC->funcs; - pGC->funcs = &XineramaGCFuncs; - - pGCPriv->clipOrg.x = pGC->clipOrg.x; - pGCPriv->clipOrg.y = pGC->clipOrg.y; - pGCPriv->patOrg.x = pGC->patOrg.x; - pGCPriv->patOrg.y = pGC->patOrg.y; - } - pScreen->CreateGC = XineramaCreateGC; - - return ret; -} - -static void -XineramaValidateGC( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -){ - Xinerama_GC_FUNC_PROLOGUE (pGC); - - if((pDraw->type == DRAWABLE_WINDOW) && !(((WindowPtr)pDraw)->parent)) { - /* the root window */ - int x_off = panoramiXdataPtr[pGC->pScreen->myNum].x; - int y_off = panoramiXdataPtr[pGC->pScreen->myNum].y; - int new_val; - - new_val = pGCPriv->clipOrg.x - x_off; - if(pGC->clipOrg.x != new_val) { - pGC->clipOrg.x = new_val; - changes |= GCClipXOrigin; - } - new_val = pGCPriv->clipOrg.y - y_off; - if(pGC->clipOrg.y != new_val) { - pGC->clipOrg.y = new_val; - changes |= GCClipYOrigin; - } - new_val = pGCPriv->patOrg.x - x_off; - if(pGC->patOrg.x != new_val) { - pGC->patOrg.x = new_val; - changes |= GCTileStipXOrigin; - } - new_val = pGCPriv->patOrg.y - y_off; - if(pGC->patOrg.y != new_val) { - pGC->patOrg.y = new_val; - changes |= GCTileStipYOrigin; - } - } else { - if(pGC->clipOrg.x != pGCPriv->clipOrg.x) { - pGC->clipOrg.x = pGCPriv->clipOrg.x; - changes |= GCClipXOrigin; - } - if(pGC->clipOrg.y != pGCPriv->clipOrg.y) { - pGC->clipOrg.y = pGCPriv->clipOrg.y; - changes |= GCClipYOrigin; - } - if(pGC->patOrg.x != pGCPriv->patOrg.x) { - pGC->patOrg.x = pGCPriv->patOrg.x; - changes |= GCTileStipXOrigin; - } - if(pGC->patOrg.y != pGCPriv->patOrg.y) { - pGC->patOrg.y = pGCPriv->patOrg.y; - changes |= GCTileStipYOrigin; - } - } - - (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); - Xinerama_GC_FUNC_EPILOGUE (pGC); -} - -static void -XineramaDestroyGC(GCPtr pGC) -{ - Xinerama_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->DestroyGC)(pGC); - Xinerama_GC_FUNC_EPILOGUE (pGC); -} - -static void -XineramaChangeGC ( - GCPtr pGC, - unsigned long mask -){ - Xinerama_GC_FUNC_PROLOGUE (pGC); - - if(mask & GCTileStipXOrigin) - pGCPriv->patOrg.x = pGC->patOrg.x; - if(mask & GCTileStipYOrigin) - pGCPriv->patOrg.y = pGC->patOrg.y; - if(mask & GCClipXOrigin) - pGCPriv->clipOrg.x = pGC->clipOrg.x; - if(mask & GCClipYOrigin) - pGCPriv->clipOrg.y = pGC->clipOrg.y; - - (*pGC->funcs->ChangeGC) (pGC, mask); - Xinerama_GC_FUNC_EPILOGUE (pGC); -} - -static void -XineramaCopyGC ( - GCPtr pGCSrc, - unsigned long mask, - GCPtr pGCDst -){ - PanoramiXGCPtr pSrcPriv = (PanoramiXGCPtr) - dixLookupPrivate(&pGCSrc->devPrivates, PanoramiXGCKey); - Xinerama_GC_FUNC_PROLOGUE (pGCDst); - - if(mask & GCTileStipXOrigin) - pGCPriv->patOrg.x = pSrcPriv->patOrg.x; - if(mask & GCTileStipYOrigin) - pGCPriv->patOrg.y = pSrcPriv->patOrg.y; - if(mask & GCClipXOrigin) - pGCPriv->clipOrg.x = pSrcPriv->clipOrg.x; - if(mask & GCClipYOrigin) - pGCPriv->clipOrg.y = pSrcPriv->clipOrg.y; - - (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); - Xinerama_GC_FUNC_EPILOGUE (pGCDst); -} - -static void -XineramaChangeClip ( - GCPtr pGC, - int type, - pointer pvalue, - int nrects -){ - Xinerama_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); - Xinerama_GC_FUNC_EPILOGUE (pGC); -} - -static void -XineramaCopyClip(GCPtr pgcDst, GCPtr pgcSrc) -{ - Xinerama_GC_FUNC_PROLOGUE (pgcDst); - (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); - Xinerama_GC_FUNC_EPILOGUE (pgcDst); -} - -static void -XineramaDestroyClip(GCPtr pGC) -{ - Xinerama_GC_FUNC_PROLOGUE (pGC); - (* pGC->funcs->DestroyClip)(pGC); - Xinerama_GC_FUNC_EPILOGUE (pGC); -} - -int -XineramaDeleteResource(pointer data, XID id) -{ - xfree(data); - return 1; -} - -typedef struct { - int screen; - int id; -} PanoramiXSearchData; - -static Bool -XineramaFindIDByScrnum(pointer resource, XID id, pointer privdata) -{ - PanoramiXRes *res = (PanoramiXRes*)resource; - PanoramiXSearchData *data = (PanoramiXSearchData*)privdata; - - return (res->info[data->screen].id == data->id); -} - -PanoramiXRes * -PanoramiXFindIDByScrnum(RESTYPE type, XID id, int screen) -{ - PanoramiXSearchData data; - pointer val; - - if(!screen) { - dixLookupResourceByType(&val, id, type, serverClient, DixReadAccess); - return val; - } - - data.screen = screen; - data.id = id; - - return LookupClientResourceComplex(clients[CLIENT_ID(id)], type, - XineramaFindIDByScrnum, &data); -} - -typedef struct _connect_callback_list { - void (*func)(void); - struct _connect_callback_list *next; -} XineramaConnectionCallbackList; - -static XineramaConnectionCallbackList *ConnectionCallbackList = NULL; - -Bool -XineramaRegisterConnectionBlockCallback(void (*func)(void)) -{ - XineramaConnectionCallbackList *newlist; - - if(!(newlist = xalloc(sizeof(XineramaConnectionCallbackList)))) - return FALSE; - - newlist->next = ConnectionCallbackList; - newlist->func = func; - ConnectionCallbackList = newlist; - - return TRUE; -} - -static void XineramaInitData(ScreenPtr pScreen) -{ - int i, w, h; - - REGION_NULL(pScreen, &PanoramiXScreenRegion) - for (i = 0; i < PanoramiXNumScreens; i++) { - BoxRec TheBox; - - pScreen = screenInfo.screens[i]; - - panoramiXdataPtr[i].x = dixScreenOrigins[i].x; - panoramiXdataPtr[i].y = dixScreenOrigins[i].y; - panoramiXdataPtr[i].width = pScreen->width; - panoramiXdataPtr[i].height = pScreen->height; - - TheBox.x1 = panoramiXdataPtr[i].x; - TheBox.x2 = TheBox.x1 + panoramiXdataPtr[i].width; - TheBox.y1 = panoramiXdataPtr[i].y; - TheBox.y2 = TheBox.y1 + panoramiXdataPtr[i].height; - - REGION_INIT(pScreen, &XineramaScreenRegions[i], &TheBox, 1); - REGION_UNION(pScreen, &PanoramiXScreenRegion, &PanoramiXScreenRegion, - &XineramaScreenRegions[i]); - } - - PanoramiXPixWidth = panoramiXdataPtr[0].x + panoramiXdataPtr[0].width; - PanoramiXPixHeight = panoramiXdataPtr[0].y + panoramiXdataPtr[0].height; - - for (i = 1; i < PanoramiXNumScreens; i++) { - w = panoramiXdataPtr[i].x + panoramiXdataPtr[i].width; - h = panoramiXdataPtr[i].y + panoramiXdataPtr[i].height; - - if (PanoramiXPixWidth < w) - PanoramiXPixWidth = w; - if (PanoramiXPixHeight < h) - PanoramiXPixHeight = h; - } -} - -void XineramaReinitData(ScreenPtr pScreen) -{ - int i; - - REGION_UNINIT(pScreen, &PanoramiXScreenRegion); - for (i = 0; i < PanoramiXNumScreens; i++) - REGION_UNINIT(pScreen, &XineramaScreenRegions[i]); - - XineramaInitData(pScreen); -} - -/* - * PanoramiXExtensionInit(): - * Called from InitExtensions in main(). - * Register PanoramiXeen Extension - * Initialize global variables. - */ - -void PanoramiXExtensionInit(int argc, char *argv[]) -{ - int i; - Bool success = FALSE; - ExtensionEntry *extEntry; - ScreenPtr pScreen = screenInfo.screens[0]; - PanoramiXScreenPtr pScreenPriv; - - if (noPanoramiXExtension) - return; - - PanoramiXNumScreens = screenInfo.numScreens; - if (PanoramiXNumScreens == 1) { /* Only 1 screen */ - noPanoramiXExtension = TRUE; - return; - } - - while (panoramiXGeneration != serverGeneration) { - extEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, - ProcPanoramiXDispatch, - SProcPanoramiXDispatch, PanoramiXResetProc, - StandardMinorOpcode); - if (!extEntry) - break; - - /* - * First make sure all the basic allocations succeed. If not, - * run in non-PanoramiXeen mode. - */ - - panoramiXdataPtr = (PanoramiXData *) - xcalloc(PanoramiXNumScreens, sizeof(PanoramiXData)); - - if (!panoramiXdataPtr) - break; - - if (!dixRequestPrivate(PanoramiXGCKey, sizeof(PanoramiXGCRec))) { - noPanoramiXExtension = TRUE; - return; - } - - for (i = 0; i < PanoramiXNumScreens; i++) { - pScreen = screenInfo.screens[i]; - pScreenPriv = xalloc(sizeof(PanoramiXScreenRec)); - dixSetPrivate(&pScreen->devPrivates, PanoramiXScreenKey, - pScreenPriv); - if(!pScreenPriv) { - noPanoramiXExtension = TRUE; - return; - } - - pScreenPriv->CreateGC = pScreen->CreateGC; - pScreenPriv->CloseScreen = pScreen->CloseScreen; - - pScreen->CreateGC = XineramaCreateGC; - pScreen->CloseScreen = XineramaCloseScreen; - } - - XRC_DRAWABLE = CreateNewResourceClass(); - XRT_WINDOW = CreateNewResourceType(XineramaDeleteResource, - "XineramaWindow"); - if (XRT_WINDOW) - XRT_WINDOW |= XRC_DRAWABLE; - XRT_PIXMAP = CreateNewResourceType(XineramaDeleteResource, - "XineramaPixmap"); - if (XRT_PIXMAP) - XRT_PIXMAP |= XRC_DRAWABLE; - XRT_GC = CreateNewResourceType(XineramaDeleteResource, - "XineramaGC"); - XRT_COLORMAP = CreateNewResourceType(XineramaDeleteResource, - "XineramaColormap"); - - if (XRT_WINDOW && XRT_PIXMAP && XRT_GC && XRT_COLORMAP) { - panoramiXGeneration = serverGeneration; - success = TRUE; - } - } - - if (!success) { - noPanoramiXExtension = TRUE; - ErrorF(PANORAMIX_PROTOCOL_NAME " extension failed to initialize\n"); - return; - } - - XineramaInitData(pScreen); - - /* - * Put our processes into the ProcVector - */ - - for (i = 256; i--; ) - SavedProcVector[i] = ProcVector[i]; - - ProcVector[X_CreateWindow] = PanoramiXCreateWindow; - ProcVector[X_ChangeWindowAttributes] = PanoramiXChangeWindowAttributes; - ProcVector[X_DestroyWindow] = PanoramiXDestroyWindow; - ProcVector[X_DestroySubwindows] = PanoramiXDestroySubwindows; - ProcVector[X_ChangeSaveSet] = PanoramiXChangeSaveSet; - ProcVector[X_ReparentWindow] = PanoramiXReparentWindow; - ProcVector[X_MapWindow] = PanoramiXMapWindow; - ProcVector[X_MapSubwindows] = PanoramiXMapSubwindows; - ProcVector[X_UnmapWindow] = PanoramiXUnmapWindow; - ProcVector[X_UnmapSubwindows] = PanoramiXUnmapSubwindows; - ProcVector[X_ConfigureWindow] = PanoramiXConfigureWindow; - ProcVector[X_CirculateWindow] = PanoramiXCirculateWindow; - ProcVector[X_GetGeometry] = PanoramiXGetGeometry; - ProcVector[X_TranslateCoords] = PanoramiXTranslateCoords; - ProcVector[X_CreatePixmap] = PanoramiXCreatePixmap; - ProcVector[X_FreePixmap] = PanoramiXFreePixmap; - ProcVector[X_CreateGC] = PanoramiXCreateGC; - ProcVector[X_ChangeGC] = PanoramiXChangeGC; - ProcVector[X_CopyGC] = PanoramiXCopyGC; - ProcVector[X_SetDashes] = PanoramiXSetDashes; - ProcVector[X_SetClipRectangles] = PanoramiXSetClipRectangles; - ProcVector[X_FreeGC] = PanoramiXFreeGC; - ProcVector[X_ClearArea] = PanoramiXClearToBackground; - ProcVector[X_CopyArea] = PanoramiXCopyArea; - ProcVector[X_CopyPlane] = PanoramiXCopyPlane; - ProcVector[X_PolyPoint] = PanoramiXPolyPoint; - ProcVector[X_PolyLine] = PanoramiXPolyLine; - ProcVector[X_PolySegment] = PanoramiXPolySegment; - ProcVector[X_PolyRectangle] = PanoramiXPolyRectangle; - ProcVector[X_PolyArc] = PanoramiXPolyArc; - ProcVector[X_FillPoly] = PanoramiXFillPoly; - ProcVector[X_PolyFillRectangle] = PanoramiXPolyFillRectangle; - ProcVector[X_PolyFillArc] = PanoramiXPolyFillArc; - ProcVector[X_PutImage] = PanoramiXPutImage; - ProcVector[X_GetImage] = PanoramiXGetImage; - ProcVector[X_PolyText8] = PanoramiXPolyText8; - ProcVector[X_PolyText16] = PanoramiXPolyText16; - ProcVector[X_ImageText8] = PanoramiXImageText8; - ProcVector[X_ImageText16] = PanoramiXImageText16; - ProcVector[X_CreateColormap] = PanoramiXCreateColormap; - ProcVector[X_FreeColormap] = PanoramiXFreeColormap; - ProcVector[X_CopyColormapAndFree] = PanoramiXCopyColormapAndFree; - ProcVector[X_InstallColormap] = PanoramiXInstallColormap; - ProcVector[X_UninstallColormap] = PanoramiXUninstallColormap; - ProcVector[X_AllocColor] = PanoramiXAllocColor; - ProcVector[X_AllocNamedColor] = PanoramiXAllocNamedColor; - ProcVector[X_AllocColorCells] = PanoramiXAllocColorCells; - ProcVector[X_AllocColorPlanes] = PanoramiXAllocColorPlanes; - ProcVector[X_FreeColors] = PanoramiXFreeColors; - ProcVector[X_StoreColors] = PanoramiXStoreColors; - ProcVector[X_StoreNamedColor] = PanoramiXStoreNamedColor; - - PanoramiXRenderInit (); -} - -extern Bool CreateConnectionBlock(void); - -Bool PanoramiXCreateConnectionBlock(void) -{ - int i, j, length; - Bool disableBackingStore = FALSE; - int old_width, old_height; - float width_mult, height_mult; - xWindowRoot *root; - xVisualType *visual; - xDepth *depth; - VisualPtr pVisual; - ScreenPtr pScreen; - - /* - * Do normal CreateConnectionBlock but faking it for only one screen - */ - - if(!PanoramiXNumDepths) { - ErrorF("Xinerama error: No common visuals\n"); - return FALSE; - } - - for(i = 1; i < screenInfo.numScreens; i++) { - pScreen = screenInfo.screens[i]; - if(pScreen->rootDepth != screenInfo.screens[0]->rootDepth) { - ErrorF("Xinerama error: Root window depths differ\n"); - return FALSE; - } - if(pScreen->backingStoreSupport != screenInfo.screens[0]->backingStoreSupport) - disableBackingStore = TRUE; - } - - if (disableBackingStore) { - for (i = 0; i < screenInfo.numScreens; i++) { - pScreen = screenInfo.screens[i]; - pScreen->backingStoreSupport = NotUseful; - } - } - - i = screenInfo.numScreens; - screenInfo.numScreens = 1; - if (!CreateConnectionBlock()) { - screenInfo.numScreens = i; - return FALSE; - } - - screenInfo.numScreens = i; - - root = (xWindowRoot *) (ConnectionInfo + connBlockScreenStart); - length = connBlockScreenStart + sizeof(xWindowRoot); - - /* overwrite the connection block */ - root->nDepths = PanoramiXNumDepths; - - for (i = 0; i < PanoramiXNumDepths; i++) { - depth = (xDepth *) (ConnectionInfo + length); - depth->depth = PanoramiXDepths[i].depth; - depth->nVisuals = PanoramiXDepths[i].numVids; - length += sizeof(xDepth); - visual = (xVisualType *)(ConnectionInfo + length); - - for (j = 0; j < depth->nVisuals; j++, visual++) { - visual->visualID = PanoramiXDepths[i].vids[j]; - - for (pVisual = PanoramiXVisuals; - pVisual->vid != visual->visualID; - pVisual++) - ; - - visual->class = pVisual->class; - visual->bitsPerRGB = pVisual->bitsPerRGBValue; - visual->colormapEntries = pVisual->ColormapEntries; - visual->redMask = pVisual->redMask; - visual->greenMask = pVisual->greenMask; - visual->blueMask = pVisual->blueMask; - } - - length += (depth->nVisuals * sizeof(xVisualType)); - } - - connSetupPrefix.length = bytes_to_int32(length); - - for (i = 0; i < PanoramiXNumDepths; i++) - xfree(PanoramiXDepths[i].vids); - xfree(PanoramiXDepths); - PanoramiXDepths = NULL; - - /* - * OK, change some dimensions so it looks as if it were one big screen - */ - - old_width = root->pixWidth; - old_height = root->pixHeight; - - root->pixWidth = PanoramiXPixWidth; - root->pixHeight = PanoramiXPixHeight; - width_mult = (1.0 * root->pixWidth) / old_width; - height_mult = (1.0 * root->pixHeight) / old_height; - root->mmWidth *= width_mult; - root->mmHeight *= height_mult; - - while(ConnectionCallbackList) { - pointer tmp; - - tmp = (pointer)ConnectionCallbackList; - (*ConnectionCallbackList->func)(); - ConnectionCallbackList = ConnectionCallbackList->next; - xfree(tmp); - } - - return TRUE; -} - -/* - * This isn't just memcmp(), bitsPerRGBValue is skipped. markv made that - * change way back before xf86 4.0, but the comment for _why_ is a bit - * opaque, so I'm not going to question it for now. - * - * This is probably better done as a screen hook so DBE/EVI/GLX can add - * their own tests, and adding privates to VisualRec so they don't have to - * do their own back-mapping. - */ -static Bool -VisualsEqual(VisualPtr a, ScreenPtr pScreenB, VisualPtr b) -{ - return ((a->class == b->class) && - (a->ColormapEntries == b->ColormapEntries) && - (a->nplanes == b->nplanes) && - (a->redMask == b->redMask) && - (a->greenMask == b->greenMask) && - (a->blueMask == b->blueMask) && - (a->offsetRed == b->offsetRed) && - (a->offsetGreen == b->offsetGreen) && - (a->offsetBlue == b->offsetBlue)); -} - -static void -PanoramiXMaybeAddDepth(DepthPtr pDepth) -{ - ScreenPtr pScreen; - int j, k; - Bool found = FALSE; - - for (j = 1; j < PanoramiXNumScreens; j++) { - pScreen = screenInfo.screens[j]; - for (k = 0; k < pScreen->numDepths; k++) { - if (pScreen->allowedDepths[k].depth == pDepth->depth) { - found = TRUE; - break; - } - } - } - - if (!found) - return; - - j = PanoramiXNumDepths; - PanoramiXNumDepths++; - PanoramiXDepths = xrealloc(PanoramiXDepths, - PanoramiXNumDepths * sizeof(DepthRec)); - PanoramiXDepths[j].depth = pDepth->depth; - PanoramiXDepths[j].numVids = 0; - /* XXX suboptimal, should grow these dynamically */ - if(pDepth->numVids) - PanoramiXDepths[j].vids = xalloc(sizeof(VisualID) * pDepth->numVids); - else - PanoramiXDepths[j].vids = NULL; -} - -static void -PanoramiXMaybeAddVisual(VisualPtr pVisual) -{ - ScreenPtr pScreen; - int j, k; - Bool found = FALSE; - - for (j = 1; j < PanoramiXNumScreens; j++) { - pScreen = screenInfo.screens[j]; - found = FALSE; - - for (k = 0; k < pScreen->numVisuals; k++) { - VisualPtr candidate = &pScreen->visuals[k]; - - if ((*XineramaVisualsEqualPtr)(pVisual, pScreen, candidate) -#ifdef GLXPROXY - && glxMatchVisual(screenInfo.screens[0], pVisual, pScreen) -#endif - ) { - found = TRUE; - break; - } - } - - if (!found) - return; - } - - /* found a matching visual on all screens, add it to the subset list */ - j = PanoramiXNumVisuals; - PanoramiXNumVisuals++; - PanoramiXVisuals = xrealloc(PanoramiXVisuals, - PanoramiXNumVisuals * sizeof(VisualRec)); - - memcpy(&PanoramiXVisuals[j], pVisual, sizeof(VisualRec)); - - for (k = 0; k < PanoramiXNumDepths; k++) { - if (PanoramiXDepths[k].depth == pVisual->nplanes) { - PanoramiXDepths[k].vids[PanoramiXDepths[k].numVids] = pVisual->vid; - PanoramiXDepths[k].numVids++; - break; - } - } -} - -extern void -PanoramiXConsolidate(void) -{ - int i; - PanoramiXRes *root, *defmap, *saver; - ScreenPtr pScreen = screenInfo.screens[0]; - DepthPtr pDepth = pScreen->allowedDepths; - VisualPtr pVisual = pScreen->visuals; - - PanoramiXNumDepths = 0; - PanoramiXNumVisuals = 0; - - for (i = 0; i < pScreen->numDepths; i++) - PanoramiXMaybeAddDepth(pDepth++); - - for (i = 0; i < pScreen->numVisuals; i++) - PanoramiXMaybeAddVisual(pVisual++); - - root = xalloc(sizeof(PanoramiXRes)); - root->type = XRT_WINDOW; - defmap = xalloc(sizeof(PanoramiXRes)); - defmap->type = XRT_COLORMAP; - saver = xalloc(sizeof(PanoramiXRes)); - saver->type = XRT_WINDOW; - - for (i = 0; i < PanoramiXNumScreens; i++) { - root->info[i].id = WindowTable[i]->drawable.id; - root->u.win.class = InputOutput; - root->u.win.root = TRUE; - saver->info[i].id = savedScreenInfo[i].wid; - saver->u.win.class = InputOutput; - saver->u.win.root = TRUE; - defmap->info[i].id = (screenInfo.screens[i])->defColormap; - } - - AddResource(root->info[0].id, XRT_WINDOW, root); - AddResource(saver->info[0].id, XRT_WINDOW, saver); - AddResource(defmap->info[0].id, XRT_COLORMAP, defmap); -} - -VisualID -PanoramiXTranslateVisualID(int screen, VisualID orig) -{ - ScreenPtr pOtherScreen = screenInfo.screens[screen]; - VisualPtr pVisual = NULL; - int i; - - for (i = 0; i < PanoramiXNumVisuals; i++) { - if (orig == PanoramiXVisuals[i].vid) { - pVisual = &PanoramiXVisuals[i]; - break; - } - } - - if (!pVisual) - return 0; - - /* if screen is 0, orig is already the correct visual ID */ - if (screen == 0) - return orig; - - /* found the original, now translate it relative to the backend screen */ - for (i = 0; i < pOtherScreen->numVisuals; i++) { - VisualPtr pOtherVisual = &pOtherScreen->visuals[i]; - - if ((*XineramaVisualsEqualPtr)(pVisual, pOtherScreen, pOtherVisual)) - return pOtherVisual->vid; - } - - return 0; -} - - -/* - * PanoramiXResetProc() - * Exit, deallocating as needed. - */ - -static void PanoramiXResetProc(ExtensionEntry* extEntry) -{ - int i; - - PanoramiXRenderReset (); - screenInfo.numScreens = PanoramiXNumScreens; - for (i = 256; i--; ) - ProcVector[i] = SavedProcVector[i]; - - Xfree(panoramiXdataPtr); -} - - -int -ProcPanoramiXQueryVersion (ClientPtr client) -{ - /* REQUEST(xPanoramiXQueryVersionReq); */ - xPanoramiXQueryVersionReply rep; - register int n; - - REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_PANORAMIX_MAJOR_VERSION; - rep.minorVersion = SERVER_PANORAMIX_MINOR_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof (xPanoramiXQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -int -ProcPanoramiXGetState(ClientPtr client) -{ - REQUEST(xPanoramiXGetStateReq); - WindowPtr pWin; - xPanoramiXGetStateReply rep; - int n, rc; - - REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.state = !noPanoramiXExtension; - rep.window = stuff->window; - if (client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.window, n); - } - WriteToClient (client, sizeof (xPanoramiXGetStateReply), (char *) &rep); - return client->noClientException; - -} - -int -ProcPanoramiXGetScreenCount(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenCountReq); - WindowPtr pWin; - xPanoramiXGetScreenCountReply rep; - int n, rc; - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.ScreenCount = PanoramiXNumScreens; - rep.window = stuff->window; - if (client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.window, n); - } - WriteToClient (client, sizeof (xPanoramiXGetScreenCountReply), (char *) &rep); - return client->noClientException; -} - -int -ProcPanoramiXGetScreenSize(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenSizeReq); - WindowPtr pWin; - xPanoramiXGetScreenSizeReply rep; - int n, rc; - - if (stuff->screen >= PanoramiXNumScreens) - return BadMatch; - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - /* screen dimensions */ - rep.width = panoramiXdataPtr[stuff->screen].width; - rep.height = panoramiXdataPtr[stuff->screen].height; - rep.window = stuff->window; - rep.screen = stuff->screen; - if (client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.width, n); - swapl (&rep.height, n); - swapl (&rep.window, n); - swapl (&rep.screen, n); - } - WriteToClient (client, sizeof (xPanoramiXGetScreenSizeReply), (char *) &rep); - return client->noClientException; -} - - -int -ProcXineramaIsActive(ClientPtr client) -{ - /* REQUEST(xXineramaIsActiveReq); */ - xXineramaIsActiveReply rep; - - REQUEST_SIZE_MATCH(xXineramaIsActiveReq); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; -#if 1 - { - /* The following hack fools clients into thinking that Xinerama - * is disabled even though it is not. */ - rep.state = !noPanoramiXExtension && !PanoramiXExtensionDisabledHack; - } -#else - rep.state = !noPanoramiXExtension; -#endif - if (client->swapped) { - int n; - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.state, n); - } - WriteToClient (client, sizeof (xXineramaIsActiveReply), (char *) &rep); - return client->noClientException; -} - - -int -ProcXineramaQueryScreens(ClientPtr client) -{ - /* REQUEST(xXineramaQueryScreensReq); */ - xXineramaQueryScreensReply rep; - - REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.number = (noPanoramiXExtension) ? 0 : PanoramiXNumScreens; - rep.length = bytes_to_int32(rep.number * sz_XineramaScreenInfo); - if (client->swapped) { - int n; - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.number, n); - } - WriteToClient (client, sizeof (xXineramaQueryScreensReply), (char *) &rep); - - if(!noPanoramiXExtension) { - xXineramaScreenInfo scratch; - int i; - - for(i = 0; i < PanoramiXNumScreens; i++) { - scratch.x_org = panoramiXdataPtr[i].x; - scratch.y_org = panoramiXdataPtr[i].y; - scratch.width = panoramiXdataPtr[i].width; - scratch.height = panoramiXdataPtr[i].height; - - if(client->swapped) { - int n; - swaps (&scratch.x_org, n); - swaps (&scratch.y_org, n); - swaps (&scratch.width, n); - swaps (&scratch.height, n); - } - WriteToClient (client, sz_XineramaScreenInfo, (char *) &scratch); - } - } - - return client->noClientException; -} - - -static int -ProcPanoramiXDispatch (ClientPtr client) -{ REQUEST(xReq); - switch (stuff->data) - { - case X_PanoramiXQueryVersion: - return ProcPanoramiXQueryVersion(client); - case X_PanoramiXGetState: - return ProcPanoramiXGetState(client); - case X_PanoramiXGetScreenCount: - return ProcPanoramiXGetScreenCount(client); - case X_PanoramiXGetScreenSize: - return ProcPanoramiXGetScreenSize(client); - case X_XineramaIsActive: - return ProcXineramaIsActive(client); - case X_XineramaQueryScreens: - return ProcXineramaQueryScreens(client); - } - return BadRequest; -} - - -#if X_BYTE_ORDER == X_LITTLE_ENDIAN -#define SHIFT_L(v,s) (v) << (s) -#define SHIFT_R(v,s) (v) >> (s) -#else -#define SHIFT_L(v,s) (v) >> (s) -#define SHIFT_R(v,s) (v) << (s) -#endif - -static void -CopyBits(char *dst, int shiftL, char *src, int bytes) -{ - /* Just get it to work. Worry about speed later */ - int shiftR = 8 - shiftL; - - while(bytes--) { - *dst |= SHIFT_L(*src, shiftL); - *(dst + 1) |= SHIFT_R(*src, shiftR); - dst++; src++; - } -} - - -/* Caution. This doesn't support 2 and 4 bpp formats. We expect - 1 bpp and planar data to be already cleared when presented - to this function */ - -void -XineramaGetImageData( - DrawablePtr *pDrawables, - int left, - int top, - int width, - int height, - unsigned int format, - unsigned long planemask, - char *data, - int pitch, - Bool isRoot -){ - RegionRec SrcRegion, GrabRegion; - BoxRec SrcBox, *pbox; - int x, y, w, h, i, j, nbox, size, sizeNeeded, ScratchPitch, inOut, depth; - DrawablePtr pDraw = pDrawables[0]; - char *ScratchMem = NULL; - - size = 0; - - /* find box in logical screen space */ - SrcBox.x1 = left; - SrcBox.y1 = top; - if(!isRoot) { - SrcBox.x1 += pDraw->x + panoramiXdataPtr[0].x; - SrcBox.y1 += pDraw->y + panoramiXdataPtr[0].y; - } - SrcBox.x2 = SrcBox.x1 + width; - SrcBox.y2 = SrcBox.y1 + height; - - REGION_INIT(pScreen, &SrcRegion, &SrcBox, 1); - REGION_NULL(pScreen, &GrabRegion); - - depth = (format == XYPixmap) ? 1 : pDraw->depth; - - for(i = 0; i < PanoramiXNumScreens; i++) { - pDraw = pDrawables[i]; - - inOut = RECT_IN_REGION(pScreen,&XineramaScreenRegions[i],&SrcBox); - - if(inOut == rgnIN) { - (*pDraw->pScreen->GetImage)(pDraw, - SrcBox.x1 - pDraw->x - panoramiXdataPtr[i].x, - SrcBox.y1 - pDraw->y - panoramiXdataPtr[i].y, - width, height, format, planemask, data); - break; - } else if (inOut == rgnOUT) - continue; - - REGION_INTERSECT(pScreen, &GrabRegion, &SrcRegion, - &XineramaScreenRegions[i]); - - nbox = REGION_NUM_RECTS(&GrabRegion); - - if(nbox) { - pbox = REGION_RECTS(&GrabRegion); - - while(nbox--) { - w = pbox->x2 - pbox->x1; - h = pbox->y2 - pbox->y1; - ScratchPitch = PixmapBytePad(w, depth); - sizeNeeded = ScratchPitch * h; - - if(sizeNeeded > size) { - char *tmpdata = ScratchMem; - ScratchMem = xrealloc(ScratchMem, sizeNeeded); - if(ScratchMem) - size = sizeNeeded; - else { - ScratchMem = tmpdata; - break; - } - } - - x = pbox->x1 - pDraw->x - panoramiXdataPtr[i].x; - y = pbox->y1 - pDraw->y - panoramiXdataPtr[i].y; - - (*pDraw->pScreen->GetImage)(pDraw, x, y, w, h, - format, planemask, ScratchMem); - - /* copy the memory over */ - - if(depth == 1) { - int k, shift, leftover, index, index2; - - x = pbox->x1 - SrcBox.x1; - y = pbox->y1 - SrcBox.y1; - shift = x & 7; - x >>= 3; - leftover = w & 7; - w >>= 3; - - /* clean up the edge */ - if(leftover) { - int mask = (1 << leftover) - 1; - for(j = h, k = w; j--; k += ScratchPitch) - ScratchMem[k] &= mask; - } - - for(j = 0, index = (pitch * y) + x, index2 = 0; j < h; - j++, index += pitch, index2 += ScratchPitch) - { - if(w) { - if(!shift) - memcpy(data + index, ScratchMem + index2, w); - else - CopyBits(data + index, shift, - ScratchMem + index2, w); - } - - if(leftover) { - data[index + w] |= - SHIFT_L(ScratchMem[index2 + w], shift); - if((shift + leftover) > 8) - data[index + w + 1] |= - SHIFT_R(ScratchMem[index2 + w],(8 - shift)); - } - } - } else { - j = BitsPerPixel(depth) >> 3; - x = (pbox->x1 - SrcBox.x1) * j; - y = pbox->y1 - SrcBox.y1; - w *= j; - - for(j = 0; j < h; j++) { - memcpy(data + (pitch * (y + j)) + x, - ScratchMem + (ScratchPitch * j), w); - } - } - pbox++; - } - - REGION_SUBTRACT(pScreen, &SrcRegion, &SrcRegion, &GrabRegion); - if(!REGION_NOTEMPTY(pScreen, &SrcRegion)) - break; - } - - } - - if(ScratchMem) - xfree(ScratchMem); - - REGION_UNINIT(pScreen, &SrcRegion); - REGION_UNINIT(pScreen, &GrabRegion); -} +/***************************************************************** +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 + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "misc.h" +#include "cursor.h" +#include "cursorstr.h" +#include "extnsionst.h" +#include "dixstruct.h" +#include "gc.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "window.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "panoramiX.h" +#include +#include "panoramiXsrv.h" +#include "globals.h" +#include "servermd.h" +#include "resource.h" +#include "picturestr.h" +#include "modinit.h" +#include "protocol-versions.h" + +#ifdef GLXPROXY +extern VisualPtr glxMatchVisual(ScreenPtr pScreen, + VisualPtr pVisual, + ScreenPtr pMatchScreen); +#endif + +/* + * PanoramiX data declarations + */ + +int PanoramiXPixWidth = 0; +int PanoramiXPixHeight = 0; +int PanoramiXNumScreens = 0; + +PanoramiXData *panoramiXdataPtr = NULL; +static RegionRec PanoramiXScreenRegion = {{0, 0, 0, 0}, NULL}; + +static int PanoramiXNumDepths; +static DepthPtr PanoramiXDepths; +static int PanoramiXNumVisuals; +static VisualPtr PanoramiXVisuals; + +unsigned long XRC_DRAWABLE; +unsigned long XRT_WINDOW; +unsigned long XRT_PIXMAP; +unsigned long XRT_GC; +unsigned long XRT_COLORMAP; + +static Bool VisualsEqual(VisualPtr, ScreenPtr, VisualPtr); +XineramaVisualsEqualProcPtr XineramaVisualsEqualPtr = &VisualsEqual; + +/* + * Function prototypes + */ + +static int panoramiXGeneration; +static int ProcPanoramiXDispatch(ClientPtr client); + +static void PanoramiXResetProc(ExtensionEntry*); + +/* + * External references for functions and data variables + */ + +#include "panoramiXh.h" + +int (* SavedProcVector[256]) (ClientPtr client) = { NULL, }; + +static int PanoramiXGCKeyIndex; +static DevPrivateKey PanoramiXGCKey = &PanoramiXGCKeyIndex; +static int PanoramiXScreenKeyIndex; +static DevPrivateKey PanoramiXScreenKey = &PanoramiXScreenKeyIndex; + +typedef struct { + DDXPointRec clipOrg; + DDXPointRec patOrg; + GCFuncs *wrapFuncs; +} PanoramiXGCRec, *PanoramiXGCPtr; + +typedef struct { + CreateGCProcPtr CreateGC; + CloseScreenProcPtr CloseScreen; +} PanoramiXScreenRec, *PanoramiXScreenPtr; + +RegionRec XineramaScreenRegions[MAXSCREENS]; + +static void XineramaValidateGC(GCPtr, unsigned long, DrawablePtr); +static void XineramaChangeGC(GCPtr, unsigned long); +static void XineramaCopyGC(GCPtr, unsigned long, GCPtr); +static void XineramaDestroyGC(GCPtr); +static void XineramaChangeClip(GCPtr, int, pointer, int); +static void XineramaDestroyClip(GCPtr); +static void XineramaCopyClip(GCPtr, GCPtr); + +static GCFuncs XineramaGCFuncs = { + XineramaValidateGC, XineramaChangeGC, XineramaCopyGC, XineramaDestroyGC, + XineramaChangeClip, XineramaDestroyClip, XineramaCopyClip +}; + +#define Xinerama_GC_FUNC_PROLOGUE(pGC)\ + PanoramiXGCPtr pGCPriv = (PanoramiXGCPtr) \ + dixLookupPrivate(&(pGC)->devPrivates, PanoramiXGCKey); \ + (pGC)->funcs = pGCPriv->wrapFuncs; + +#define Xinerama_GC_FUNC_EPILOGUE(pGC)\ + pGCPriv->wrapFuncs = (pGC)->funcs;\ + (pGC)->funcs = &XineramaGCFuncs; + + +static Bool +XineramaCloseScreen (int i, ScreenPtr pScreen) +{ + PanoramiXScreenPtr pScreenPriv = (PanoramiXScreenPtr) + dixLookupPrivate(&pScreen->devPrivates, PanoramiXScreenKey); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->CreateGC = pScreenPriv->CreateGC; + + REGION_UNINIT(pScreen, &XineramaScreenRegions[pScreen->myNum]); + if (pScreen->myNum == 0) + REGION_UNINIT(pScreen, &PanoramiXScreenRegion); + + free((pointer) pScreenPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static Bool +XineramaCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + PanoramiXScreenPtr pScreenPriv = (PanoramiXScreenPtr) + dixLookupPrivate(&pScreen->devPrivates, PanoramiXScreenKey); + Bool ret; + + pScreen->CreateGC = pScreenPriv->CreateGC; + if((ret = (*pScreen->CreateGC)(pGC))) { + PanoramiXGCPtr pGCPriv = (PanoramiXGCPtr) + dixLookupPrivate(&pGC->devPrivates, PanoramiXGCKey); + + pGCPriv->wrapFuncs = pGC->funcs; + pGC->funcs = &XineramaGCFuncs; + + pGCPriv->clipOrg.x = pGC->clipOrg.x; + pGCPriv->clipOrg.y = pGC->clipOrg.y; + pGCPriv->patOrg.x = pGC->patOrg.x; + pGCPriv->patOrg.y = pGC->patOrg.y; + } + pScreen->CreateGC = XineramaCreateGC; + + return ret; +} + +static void +XineramaValidateGC( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +){ + Xinerama_GC_FUNC_PROLOGUE (pGC); + + if((pDraw->type == DRAWABLE_WINDOW) && !(((WindowPtr)pDraw)->parent)) { + /* the root window */ + int x_off = panoramiXdataPtr[pGC->pScreen->myNum].x; + int y_off = panoramiXdataPtr[pGC->pScreen->myNum].y; + int new_val; + + new_val = pGCPriv->clipOrg.x - x_off; + if(pGC->clipOrg.x != new_val) { + pGC->clipOrg.x = new_val; + changes |= GCClipXOrigin; + } + new_val = pGCPriv->clipOrg.y - y_off; + if(pGC->clipOrg.y != new_val) { + pGC->clipOrg.y = new_val; + changes |= GCClipYOrigin; + } + new_val = pGCPriv->patOrg.x - x_off; + if(pGC->patOrg.x != new_val) { + pGC->patOrg.x = new_val; + changes |= GCTileStipXOrigin; + } + new_val = pGCPriv->patOrg.y - y_off; + if(pGC->patOrg.y != new_val) { + pGC->patOrg.y = new_val; + changes |= GCTileStipYOrigin; + } + } else { + if(pGC->clipOrg.x != pGCPriv->clipOrg.x) { + pGC->clipOrg.x = pGCPriv->clipOrg.x; + changes |= GCClipXOrigin; + } + if(pGC->clipOrg.y != pGCPriv->clipOrg.y) { + pGC->clipOrg.y = pGCPriv->clipOrg.y; + changes |= GCClipYOrigin; + } + if(pGC->patOrg.x != pGCPriv->patOrg.x) { + pGC->patOrg.x = pGCPriv->patOrg.x; + changes |= GCTileStipXOrigin; + } + if(pGC->patOrg.y != pGCPriv->patOrg.y) { + pGC->patOrg.y = pGCPriv->patOrg.y; + changes |= GCTileStipYOrigin; + } + } + + (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); + Xinerama_GC_FUNC_EPILOGUE (pGC); +} + +static void +XineramaDestroyGC(GCPtr pGC) +{ + Xinerama_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->DestroyGC)(pGC); + Xinerama_GC_FUNC_EPILOGUE (pGC); +} + +static void +XineramaChangeGC ( + GCPtr pGC, + unsigned long mask +){ + Xinerama_GC_FUNC_PROLOGUE (pGC); + + if(mask & GCTileStipXOrigin) + pGCPriv->patOrg.x = pGC->patOrg.x; + if(mask & GCTileStipYOrigin) + pGCPriv->patOrg.y = pGC->patOrg.y; + if(mask & GCClipXOrigin) + pGCPriv->clipOrg.x = pGC->clipOrg.x; + if(mask & GCClipYOrigin) + pGCPriv->clipOrg.y = pGC->clipOrg.y; + + (*pGC->funcs->ChangeGC) (pGC, mask); + Xinerama_GC_FUNC_EPILOGUE (pGC); +} + +static void +XineramaCopyGC ( + GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst +){ + PanoramiXGCPtr pSrcPriv = (PanoramiXGCPtr) + dixLookupPrivate(&pGCSrc->devPrivates, PanoramiXGCKey); + Xinerama_GC_FUNC_PROLOGUE (pGCDst); + + if(mask & GCTileStipXOrigin) + pGCPriv->patOrg.x = pSrcPriv->patOrg.x; + if(mask & GCTileStipYOrigin) + pGCPriv->patOrg.y = pSrcPriv->patOrg.y; + if(mask & GCClipXOrigin) + pGCPriv->clipOrg.x = pSrcPriv->clipOrg.x; + if(mask & GCClipYOrigin) + pGCPriv->clipOrg.y = pSrcPriv->clipOrg.y; + + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + Xinerama_GC_FUNC_EPILOGUE (pGCDst); +} + +static void +XineramaChangeClip ( + GCPtr pGC, + int type, + pointer pvalue, + int nrects +){ + Xinerama_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + Xinerama_GC_FUNC_EPILOGUE (pGC); +} + +static void +XineramaCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + Xinerama_GC_FUNC_PROLOGUE (pgcDst); + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + Xinerama_GC_FUNC_EPILOGUE (pgcDst); +} + +static void +XineramaDestroyClip(GCPtr pGC) +{ + Xinerama_GC_FUNC_PROLOGUE (pGC); + (* pGC->funcs->DestroyClip)(pGC); + Xinerama_GC_FUNC_EPILOGUE (pGC); +} + +int +XineramaDeleteResource(pointer data, XID id) +{ + free(data); + return 1; +} + +typedef struct { + int screen; + int id; +} PanoramiXSearchData; + +static Bool +XineramaFindIDByScrnum(pointer resource, XID id, pointer privdata) +{ + PanoramiXRes *res = (PanoramiXRes*)resource; + PanoramiXSearchData *data = (PanoramiXSearchData*)privdata; + + return (res->info[data->screen].id == data->id); +} + +PanoramiXRes * +PanoramiXFindIDByScrnum(RESTYPE type, XID id, int screen) +{ + PanoramiXSearchData data; + pointer val; + + if(!screen) { + dixLookupResourceByType(&val, id, type, serverClient, DixReadAccess); + return val; + } + + data.screen = screen; + data.id = id; + + return LookupClientResourceComplex(clients[CLIENT_ID(id)], type, + XineramaFindIDByScrnum, &data); +} + +typedef struct _connect_callback_list { + void (*func)(void); + struct _connect_callback_list *next; +} XineramaConnectionCallbackList; + +static XineramaConnectionCallbackList *ConnectionCallbackList = NULL; + +Bool +XineramaRegisterConnectionBlockCallback(void (*func)(void)) +{ + XineramaConnectionCallbackList *newlist; + + if(!(newlist = malloc(sizeof(XineramaConnectionCallbackList)))) + return FALSE; + + newlist->next = ConnectionCallbackList; + newlist->func = func; + ConnectionCallbackList = newlist; + + return TRUE; +} + +static void XineramaInitData(ScreenPtr pScreen) +{ + int i, w, h; + + REGION_NULL(pScreen, &PanoramiXScreenRegion) + for (i = 0; i < PanoramiXNumScreens; i++) { + BoxRec TheBox; + + pScreen = screenInfo.screens[i]; + + panoramiXdataPtr[i].x = dixScreenOrigins[i].x; + panoramiXdataPtr[i].y = dixScreenOrigins[i].y; + panoramiXdataPtr[i].width = pScreen->width; + panoramiXdataPtr[i].height = pScreen->height; + + TheBox.x1 = panoramiXdataPtr[i].x; + TheBox.x2 = TheBox.x1 + panoramiXdataPtr[i].width; + TheBox.y1 = panoramiXdataPtr[i].y; + TheBox.y2 = TheBox.y1 + panoramiXdataPtr[i].height; + + REGION_INIT(pScreen, &XineramaScreenRegions[i], &TheBox, 1); + REGION_UNION(pScreen, &PanoramiXScreenRegion, &PanoramiXScreenRegion, + &XineramaScreenRegions[i]); + } + + PanoramiXPixWidth = panoramiXdataPtr[0].x + panoramiXdataPtr[0].width; + PanoramiXPixHeight = panoramiXdataPtr[0].y + panoramiXdataPtr[0].height; + + for (i = 1; i < PanoramiXNumScreens; i++) { + w = panoramiXdataPtr[i].x + panoramiXdataPtr[i].width; + h = panoramiXdataPtr[i].y + panoramiXdataPtr[i].height; + + if (PanoramiXPixWidth < w) + PanoramiXPixWidth = w; + if (PanoramiXPixHeight < h) + PanoramiXPixHeight = h; + } +} + +void XineramaReinitData(ScreenPtr pScreen) +{ + int i; + + REGION_UNINIT(pScreen, &PanoramiXScreenRegion); + for (i = 0; i < PanoramiXNumScreens; i++) + REGION_UNINIT(pScreen, &XineramaScreenRegions[i]); + + XineramaInitData(pScreen); +} + +/* + * PanoramiXExtensionInit(): + * Called from InitExtensions in main(). + * Register PanoramiXeen Extension + * Initialize global variables. + */ + +void PanoramiXExtensionInit(int argc, char *argv[]) +{ + int i; + Bool success = FALSE; + ExtensionEntry *extEntry; + ScreenPtr pScreen = screenInfo.screens[0]; + PanoramiXScreenPtr pScreenPriv; + + if (noPanoramiXExtension) + return; + + PanoramiXNumScreens = screenInfo.numScreens; + if (PanoramiXNumScreens == 1) { /* Only 1 screen */ + noPanoramiXExtension = TRUE; + return; + } + + while (panoramiXGeneration != serverGeneration) { + extEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, + ProcPanoramiXDispatch, + SProcPanoramiXDispatch, PanoramiXResetProc, + StandardMinorOpcode); + if (!extEntry) + break; + + /* + * First make sure all the basic allocations succeed. If not, + * run in non-PanoramiXeen mode. + */ + + panoramiXdataPtr = (PanoramiXData *) + calloc(PanoramiXNumScreens, sizeof(PanoramiXData)); + + if (!panoramiXdataPtr) + break; + + if (!dixRequestPrivate(PanoramiXGCKey, sizeof(PanoramiXGCRec))) { + noPanoramiXExtension = TRUE; + return; + } + + for (i = 0; i < PanoramiXNumScreens; i++) { + pScreen = screenInfo.screens[i]; + pScreenPriv = malloc(sizeof(PanoramiXScreenRec)); + dixSetPrivate(&pScreen->devPrivates, PanoramiXScreenKey, + pScreenPriv); + if(!pScreenPriv) { + noPanoramiXExtension = TRUE; + return; + } + + pScreenPriv->CreateGC = pScreen->CreateGC; + pScreenPriv->CloseScreen = pScreen->CloseScreen; + + pScreen->CreateGC = XineramaCreateGC; + pScreen->CloseScreen = XineramaCloseScreen; + } + + XRC_DRAWABLE = CreateNewResourceClass(); + XRT_WINDOW = CreateNewResourceType(XineramaDeleteResource, + "XineramaWindow"); + if (XRT_WINDOW) + XRT_WINDOW |= XRC_DRAWABLE; + XRT_PIXMAP = CreateNewResourceType(XineramaDeleteResource, + "XineramaPixmap"); + if (XRT_PIXMAP) + XRT_PIXMAP |= XRC_DRAWABLE; + XRT_GC = CreateNewResourceType(XineramaDeleteResource, + "XineramaGC"); + XRT_COLORMAP = CreateNewResourceType(XineramaDeleteResource, + "XineramaColormap"); + + if (XRT_WINDOW && XRT_PIXMAP && XRT_GC && XRT_COLORMAP) { + panoramiXGeneration = serverGeneration; + success = TRUE; + } + } + + if (!success) { + noPanoramiXExtension = TRUE; + ErrorF(PANORAMIX_PROTOCOL_NAME " extension failed to initialize\n"); + return; + } + + XineramaInitData(pScreen); + + /* + * Put our processes into the ProcVector + */ + + for (i = 256; i--; ) + SavedProcVector[i] = ProcVector[i]; + + ProcVector[X_CreateWindow] = PanoramiXCreateWindow; + ProcVector[X_ChangeWindowAttributes] = PanoramiXChangeWindowAttributes; + ProcVector[X_DestroyWindow] = PanoramiXDestroyWindow; + ProcVector[X_DestroySubwindows] = PanoramiXDestroySubwindows; + ProcVector[X_ChangeSaveSet] = PanoramiXChangeSaveSet; + ProcVector[X_ReparentWindow] = PanoramiXReparentWindow; + ProcVector[X_MapWindow] = PanoramiXMapWindow; + ProcVector[X_MapSubwindows] = PanoramiXMapSubwindows; + ProcVector[X_UnmapWindow] = PanoramiXUnmapWindow; + ProcVector[X_UnmapSubwindows] = PanoramiXUnmapSubwindows; + ProcVector[X_ConfigureWindow] = PanoramiXConfigureWindow; + ProcVector[X_CirculateWindow] = PanoramiXCirculateWindow; + ProcVector[X_GetGeometry] = PanoramiXGetGeometry; + ProcVector[X_TranslateCoords] = PanoramiXTranslateCoords; + ProcVector[X_CreatePixmap] = PanoramiXCreatePixmap; + ProcVector[X_FreePixmap] = PanoramiXFreePixmap; + ProcVector[X_CreateGC] = PanoramiXCreateGC; + ProcVector[X_ChangeGC] = PanoramiXChangeGC; + ProcVector[X_CopyGC] = PanoramiXCopyGC; + ProcVector[X_SetDashes] = PanoramiXSetDashes; + ProcVector[X_SetClipRectangles] = PanoramiXSetClipRectangles; + ProcVector[X_FreeGC] = PanoramiXFreeGC; + ProcVector[X_ClearArea] = PanoramiXClearToBackground; + ProcVector[X_CopyArea] = PanoramiXCopyArea; + ProcVector[X_CopyPlane] = PanoramiXCopyPlane; + ProcVector[X_PolyPoint] = PanoramiXPolyPoint; + ProcVector[X_PolyLine] = PanoramiXPolyLine; + ProcVector[X_PolySegment] = PanoramiXPolySegment; + ProcVector[X_PolyRectangle] = PanoramiXPolyRectangle; + ProcVector[X_PolyArc] = PanoramiXPolyArc; + ProcVector[X_FillPoly] = PanoramiXFillPoly; + ProcVector[X_PolyFillRectangle] = PanoramiXPolyFillRectangle; + ProcVector[X_PolyFillArc] = PanoramiXPolyFillArc; + ProcVector[X_PutImage] = PanoramiXPutImage; + ProcVector[X_GetImage] = PanoramiXGetImage; + ProcVector[X_PolyText8] = PanoramiXPolyText8; + ProcVector[X_PolyText16] = PanoramiXPolyText16; + ProcVector[X_ImageText8] = PanoramiXImageText8; + ProcVector[X_ImageText16] = PanoramiXImageText16; + ProcVector[X_CreateColormap] = PanoramiXCreateColormap; + ProcVector[X_FreeColormap] = PanoramiXFreeColormap; + ProcVector[X_CopyColormapAndFree] = PanoramiXCopyColormapAndFree; + ProcVector[X_InstallColormap] = PanoramiXInstallColormap; + ProcVector[X_UninstallColormap] = PanoramiXUninstallColormap; + ProcVector[X_AllocColor] = PanoramiXAllocColor; + ProcVector[X_AllocNamedColor] = PanoramiXAllocNamedColor; + ProcVector[X_AllocColorCells] = PanoramiXAllocColorCells; + ProcVector[X_AllocColorPlanes] = PanoramiXAllocColorPlanes; + ProcVector[X_FreeColors] = PanoramiXFreeColors; + ProcVector[X_StoreColors] = PanoramiXStoreColors; + ProcVector[X_StoreNamedColor] = PanoramiXStoreNamedColor; + + PanoramiXRenderInit (); +} + +extern Bool CreateConnectionBlock(void); + +Bool PanoramiXCreateConnectionBlock(void) +{ + int i, j, length; + Bool disableBackingStore = FALSE; + int old_width, old_height; + float width_mult, height_mult; + xWindowRoot *root; + xVisualType *visual; + xDepth *depth; + VisualPtr pVisual; + ScreenPtr pScreen; + + /* + * Do normal CreateConnectionBlock but faking it for only one screen + */ + + if(!PanoramiXNumDepths) { + ErrorF("Xinerama error: No common visuals\n"); + return FALSE; + } + + for(i = 1; i < screenInfo.numScreens; i++) { + pScreen = screenInfo.screens[i]; + if(pScreen->rootDepth != screenInfo.screens[0]->rootDepth) { + ErrorF("Xinerama error: Root window depths differ\n"); + return FALSE; + } + if(pScreen->backingStoreSupport != screenInfo.screens[0]->backingStoreSupport) + disableBackingStore = TRUE; + } + + if (disableBackingStore) { + for (i = 0; i < screenInfo.numScreens; i++) { + pScreen = screenInfo.screens[i]; + pScreen->backingStoreSupport = NotUseful; + } + } + + i = screenInfo.numScreens; + screenInfo.numScreens = 1; + if (!CreateConnectionBlock()) { + screenInfo.numScreens = i; + return FALSE; + } + + screenInfo.numScreens = i; + + root = (xWindowRoot *) (ConnectionInfo + connBlockScreenStart); + length = connBlockScreenStart + sizeof(xWindowRoot); + + /* overwrite the connection block */ + root->nDepths = PanoramiXNumDepths; + + for (i = 0; i < PanoramiXNumDepths; i++) { + depth = (xDepth *) (ConnectionInfo + length); + depth->depth = PanoramiXDepths[i].depth; + depth->nVisuals = PanoramiXDepths[i].numVids; + length += sizeof(xDepth); + visual = (xVisualType *)(ConnectionInfo + length); + + for (j = 0; j < depth->nVisuals; j++, visual++) { + visual->visualID = PanoramiXDepths[i].vids[j]; + + for (pVisual = PanoramiXVisuals; + pVisual->vid != visual->visualID; + pVisual++) + ; + + visual->class = pVisual->class; + visual->bitsPerRGB = pVisual->bitsPerRGBValue; + visual->colormapEntries = pVisual->ColormapEntries; + visual->redMask = pVisual->redMask; + visual->greenMask = pVisual->greenMask; + visual->blueMask = pVisual->blueMask; + } + + length += (depth->nVisuals * sizeof(xVisualType)); + } + + connSetupPrefix.length = bytes_to_int32(length); + + for (i = 0; i < PanoramiXNumDepths; i++) + free(PanoramiXDepths[i].vids); + free(PanoramiXDepths); + PanoramiXDepths = NULL; + + /* + * OK, change some dimensions so it looks as if it were one big screen + */ + + old_width = root->pixWidth; + old_height = root->pixHeight; + + root->pixWidth = PanoramiXPixWidth; + root->pixHeight = PanoramiXPixHeight; + width_mult = (1.0 * root->pixWidth) / old_width; + height_mult = (1.0 * root->pixHeight) / old_height; + root->mmWidth *= width_mult; + root->mmHeight *= height_mult; + + while(ConnectionCallbackList) { + pointer tmp; + + tmp = (pointer)ConnectionCallbackList; + (*ConnectionCallbackList->func)(); + ConnectionCallbackList = ConnectionCallbackList->next; + free(tmp); + } + + return TRUE; +} + +/* + * This isn't just memcmp(), bitsPerRGBValue is skipped. markv made that + * change way back before xf86 4.0, but the comment for _why_ is a bit + * opaque, so I'm not going to question it for now. + * + * This is probably better done as a screen hook so DBE/EVI/GLX can add + * their own tests, and adding privates to VisualRec so they don't have to + * do their own back-mapping. + */ +static Bool +VisualsEqual(VisualPtr a, ScreenPtr pScreenB, VisualPtr b) +{ + return ((a->class == b->class) && + (a->ColormapEntries == b->ColormapEntries) && + (a->nplanes == b->nplanes) && + (a->redMask == b->redMask) && + (a->greenMask == b->greenMask) && + (a->blueMask == b->blueMask) && + (a->offsetRed == b->offsetRed) && + (a->offsetGreen == b->offsetGreen) && + (a->offsetBlue == b->offsetBlue)); +} + +static void +PanoramiXMaybeAddDepth(DepthPtr pDepth) +{ + ScreenPtr pScreen; + int j, k; + Bool found = FALSE; + + for (j = 1; j < PanoramiXNumScreens; j++) { + pScreen = screenInfo.screens[j]; + for (k = 0; k < pScreen->numDepths; k++) { + if (pScreen->allowedDepths[k].depth == pDepth->depth) { + found = TRUE; + break; + } + } + } + + if (!found) + return; + + j = PanoramiXNumDepths; + PanoramiXNumDepths++; + PanoramiXDepths = realloc(PanoramiXDepths, + PanoramiXNumDepths * sizeof(DepthRec)); + PanoramiXDepths[j].depth = pDepth->depth; + PanoramiXDepths[j].numVids = 0; + /* XXX suboptimal, should grow these dynamically */ + if(pDepth->numVids) + PanoramiXDepths[j].vids = malloc(sizeof(VisualID) * pDepth->numVids); + else + PanoramiXDepths[j].vids = NULL; +} + +static void +PanoramiXMaybeAddVisual(VisualPtr pVisual) +{ + ScreenPtr pScreen; + int j, k; + Bool found = FALSE; + + for (j = 1; j < PanoramiXNumScreens; j++) { + pScreen = screenInfo.screens[j]; + found = FALSE; + + for (k = 0; k < pScreen->numVisuals; k++) { + VisualPtr candidate = &pScreen->visuals[k]; + + if ((*XineramaVisualsEqualPtr)(pVisual, pScreen, candidate) +#ifdef GLXPROXY + && glxMatchVisual(screenInfo.screens[0], pVisual, pScreen) +#endif + ) { + found = TRUE; + break; + } + } + + if (!found) + return; + } + + /* found a matching visual on all screens, add it to the subset list */ + j = PanoramiXNumVisuals; + PanoramiXNumVisuals++; + PanoramiXVisuals = realloc(PanoramiXVisuals, + PanoramiXNumVisuals * sizeof(VisualRec)); + + memcpy(&PanoramiXVisuals[j], pVisual, sizeof(VisualRec)); + + for (k = 0; k < PanoramiXNumDepths; k++) { + if (PanoramiXDepths[k].depth == pVisual->nplanes) { + PanoramiXDepths[k].vids[PanoramiXDepths[k].numVids] = pVisual->vid; + PanoramiXDepths[k].numVids++; + break; + } + } +} + +extern void +PanoramiXConsolidate(void) +{ + int i; + PanoramiXRes *root, *defmap, *saver; + ScreenPtr pScreen = screenInfo.screens[0]; + DepthPtr pDepth = pScreen->allowedDepths; + VisualPtr pVisual = pScreen->visuals; + + PanoramiXNumDepths = 0; + PanoramiXNumVisuals = 0; + + for (i = 0; i < pScreen->numDepths; i++) + PanoramiXMaybeAddDepth(pDepth++); + + for (i = 0; i < pScreen->numVisuals; i++) + PanoramiXMaybeAddVisual(pVisual++); + + root = malloc(sizeof(PanoramiXRes)); + root->type = XRT_WINDOW; + defmap = malloc(sizeof(PanoramiXRes)); + defmap->type = XRT_COLORMAP; + saver = malloc(sizeof(PanoramiXRes)); + saver->type = XRT_WINDOW; + + for (i = 0; i < PanoramiXNumScreens; i++) { + root->info[i].id = WindowTable[i]->drawable.id; + root->u.win.class = InputOutput; + root->u.win.root = TRUE; + saver->info[i].id = savedScreenInfo[i].wid; + saver->u.win.class = InputOutput; + saver->u.win.root = TRUE; + defmap->info[i].id = (screenInfo.screens[i])->defColormap; + } + + AddResource(root->info[0].id, XRT_WINDOW, root); + AddResource(saver->info[0].id, XRT_WINDOW, saver); + AddResource(defmap->info[0].id, XRT_COLORMAP, defmap); +} + +VisualID +PanoramiXTranslateVisualID(int screen, VisualID orig) +{ + ScreenPtr pOtherScreen = screenInfo.screens[screen]; + VisualPtr pVisual = NULL; + int i; + + for (i = 0; i < PanoramiXNumVisuals; i++) { + if (orig == PanoramiXVisuals[i].vid) { + pVisual = &PanoramiXVisuals[i]; + break; + } + } + + if (!pVisual) + return 0; + + /* if screen is 0, orig is already the correct visual ID */ + if (screen == 0) + return orig; + + /* found the original, now translate it relative to the backend screen */ + for (i = 0; i < pOtherScreen->numVisuals; i++) { + VisualPtr pOtherVisual = &pOtherScreen->visuals[i]; + + if ((*XineramaVisualsEqualPtr)(pVisual, pOtherScreen, pOtherVisual)) + return pOtherVisual->vid; + } + + return 0; +} + + +/* + * PanoramiXResetProc() + * Exit, deallocating as needed. + */ + +static void PanoramiXResetProc(ExtensionEntry* extEntry) +{ + int i; + + PanoramiXRenderReset (); + screenInfo.numScreens = PanoramiXNumScreens; + for (i = 256; i--; ) + ProcVector[i] = SavedProcVector[i]; + + free(panoramiXdataPtr); +} + + +int +ProcPanoramiXQueryVersion (ClientPtr client) +{ + /* REQUEST(xPanoramiXQueryVersionReq); */ + xPanoramiXQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_PANORAMIX_MAJOR_VERSION; + rep.minorVersion = SERVER_PANORAMIX_MINOR_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof (xPanoramiXQueryVersionReply), (char *)&rep); + return Success; +} + +int +ProcPanoramiXGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + WindowPtr pWin; + xPanoramiXGetStateReply rep; + int n, rc; + + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = !noPanoramiXExtension; + rep.window = stuff->window; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.window, n); + } + WriteToClient (client, sizeof (xPanoramiXGetStateReply), (char *) &rep); + return Success; + +} + +int +ProcPanoramiXGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + WindowPtr pWin; + xPanoramiXGetScreenCountReply rep; + int n, rc; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.ScreenCount = PanoramiXNumScreens; + rep.window = stuff->window; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.window, n); + } + WriteToClient (client, sizeof (xPanoramiXGetScreenCountReply), (char *) &rep); + return Success; +} + +int +ProcPanoramiXGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + WindowPtr pWin; + xPanoramiXGetScreenSizeReply rep; + int n, rc; + + if (stuff->screen >= PanoramiXNumScreens) + return BadMatch; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + /* screen dimensions */ + rep.width = panoramiXdataPtr[stuff->screen].width; + rep.height = panoramiXdataPtr[stuff->screen].height; + rep.window = stuff->window; + rep.screen = stuff->screen; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.width, n); + swapl (&rep.height, n); + swapl (&rep.window, n); + swapl (&rep.screen, n); + } + WriteToClient (client, sizeof (xPanoramiXGetScreenSizeReply), (char *) &rep); + return Success; +} + + +int +ProcXineramaIsActive(ClientPtr client) +{ + /* REQUEST(xXineramaIsActiveReq); */ + xXineramaIsActiveReply rep; + + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; +#if 1 + { + /* The following hack fools clients into thinking that Xinerama + * is disabled even though it is not. */ + rep.state = !noPanoramiXExtension && !PanoramiXExtensionDisabledHack; + } +#else + rep.state = !noPanoramiXExtension; +#endif + if (client->swapped) { + int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.state, n); + } + WriteToClient (client, sizeof (xXineramaIsActiveReply), (char *) &rep); + return Success; +} + + +int +ProcXineramaQueryScreens(ClientPtr client) +{ + /* REQUEST(xXineramaQueryScreensReq); */ + xXineramaQueryScreensReply rep; + + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.number = (noPanoramiXExtension) ? 0 : PanoramiXNumScreens; + rep.length = bytes_to_int32(rep.number * sz_XineramaScreenInfo); + if (client->swapped) { + int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.number, n); + } + WriteToClient (client, sizeof (xXineramaQueryScreensReply), (char *) &rep); + + if(!noPanoramiXExtension) { + xXineramaScreenInfo scratch; + int i; + + for(i = 0; i < PanoramiXNumScreens; i++) { + scratch.x_org = panoramiXdataPtr[i].x; + scratch.y_org = panoramiXdataPtr[i].y; + scratch.width = panoramiXdataPtr[i].width; + scratch.height = panoramiXdataPtr[i].height; + + if(client->swapped) { + int n; + swaps (&scratch.x_org, n); + swaps (&scratch.y_org, n); + swaps (&scratch.width, n); + swaps (&scratch.height, n); + } + WriteToClient (client, sz_XineramaScreenInfo, (char *) &scratch); + } + } + + return Success; +} + + +static int +ProcPanoramiXDispatch (ClientPtr client) +{ REQUEST(xReq); + switch (stuff->data) + { + case X_PanoramiXQueryVersion: + return ProcPanoramiXQueryVersion(client); + case X_PanoramiXGetState: + return ProcPanoramiXGetState(client); + case X_PanoramiXGetScreenCount: + return ProcPanoramiXGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return ProcPanoramiXGetScreenSize(client); + case X_XineramaIsActive: + return ProcXineramaIsActive(client); + case X_XineramaQueryScreens: + return ProcXineramaQueryScreens(client); + } + return BadRequest; +} + + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN +#define SHIFT_L(v,s) (v) << (s) +#define SHIFT_R(v,s) (v) >> (s) +#else +#define SHIFT_L(v,s) (v) >> (s) +#define SHIFT_R(v,s) (v) << (s) +#endif + +static void +CopyBits(char *dst, int shiftL, char *src, int bytes) +{ + /* Just get it to work. Worry about speed later */ + int shiftR = 8 - shiftL; + + while(bytes--) { + *dst |= SHIFT_L(*src, shiftL); + *(dst + 1) |= SHIFT_R(*src, shiftR); + dst++; src++; + } +} + + +/* Caution. This doesn't support 2 and 4 bpp formats. We expect + 1 bpp and planar data to be already cleared when presented + to this function */ + +void +XineramaGetImageData( + DrawablePtr *pDrawables, + int left, + int top, + int width, + int height, + unsigned int format, + unsigned long planemask, + char *data, + int pitch, + Bool isRoot +){ + RegionRec SrcRegion, GrabRegion; + BoxRec SrcBox, *pbox; + int x, y, w, h, i, j, nbox, size, sizeNeeded, ScratchPitch, inOut, depth; + DrawablePtr pDraw = pDrawables[0]; + char *ScratchMem = NULL; + + size = 0; + + /* find box in logical screen space */ + SrcBox.x1 = left; + SrcBox.y1 = top; + if(!isRoot) { + SrcBox.x1 += pDraw->x + panoramiXdataPtr[0].x; + SrcBox.y1 += pDraw->y + panoramiXdataPtr[0].y; + } + SrcBox.x2 = SrcBox.x1 + width; + SrcBox.y2 = SrcBox.y1 + height; + + REGION_INIT(pScreen, &SrcRegion, &SrcBox, 1); + REGION_NULL(pScreen, &GrabRegion); + + depth = (format == XYPixmap) ? 1 : pDraw->depth; + + for(i = 0; i < PanoramiXNumScreens; i++) { + pDraw = pDrawables[i]; + + inOut = RECT_IN_REGION(pScreen,&XineramaScreenRegions[i],&SrcBox); + + if(inOut == rgnIN) { + (*pDraw->pScreen->GetImage)(pDraw, + SrcBox.x1 - pDraw->x - panoramiXdataPtr[i].x, + SrcBox.y1 - pDraw->y - panoramiXdataPtr[i].y, + width, height, format, planemask, data); + break; + } else if (inOut == rgnOUT) + continue; + + REGION_INTERSECT(pScreen, &GrabRegion, &SrcRegion, + &XineramaScreenRegions[i]); + + nbox = REGION_NUM_RECTS(&GrabRegion); + + if(nbox) { + pbox = REGION_RECTS(&GrabRegion); + + while(nbox--) { + w = pbox->x2 - pbox->x1; + h = pbox->y2 - pbox->y1; + ScratchPitch = PixmapBytePad(w, depth); + sizeNeeded = ScratchPitch * h; + + if(sizeNeeded > size) { + char *tmpdata = ScratchMem; + ScratchMem = realloc(ScratchMem, sizeNeeded); + if(ScratchMem) + size = sizeNeeded; + else { + ScratchMem = tmpdata; + break; + } + } + + x = pbox->x1 - pDraw->x - panoramiXdataPtr[i].x; + y = pbox->y1 - pDraw->y - panoramiXdataPtr[i].y; + + (*pDraw->pScreen->GetImage)(pDraw, x, y, w, h, + format, planemask, ScratchMem); + + /* copy the memory over */ + + if(depth == 1) { + int k, shift, leftover, index, index2; + + x = pbox->x1 - SrcBox.x1; + y = pbox->y1 - SrcBox.y1; + shift = x & 7; + x >>= 3; + leftover = w & 7; + w >>= 3; + + /* clean up the edge */ + if(leftover) { + int mask = (1 << leftover) - 1; + for(j = h, k = w; j--; k += ScratchPitch) + ScratchMem[k] &= mask; + } + + for(j = 0, index = (pitch * y) + x, index2 = 0; j < h; + j++, index += pitch, index2 += ScratchPitch) + { + if(w) { + if(!shift) + memcpy(data + index, ScratchMem + index2, w); + else + CopyBits(data + index, shift, + ScratchMem + index2, w); + } + + if(leftover) { + data[index + w] |= + SHIFT_L(ScratchMem[index2 + w], shift); + if((shift + leftover) > 8) + data[index + w + 1] |= + SHIFT_R(ScratchMem[index2 + w],(8 - shift)); + } + } + } else { + j = BitsPerPixel(depth) >> 3; + x = (pbox->x1 - SrcBox.x1) * j; + y = pbox->y1 - SrcBox.y1; + w *= j; + + for(j = 0; j < h; j++) { + memcpy(data + (pitch * (y + j)) + x, + ScratchMem + (ScratchPitch * j), w); + } + } + pbox++; + } + + REGION_SUBTRACT(pScreen, &SrcRegion, &SrcRegion, &GrabRegion); + if(!REGION_NOTEMPTY(pScreen, &SrcRegion)) + break; + } + + } + + if(ScratchMem) + free(ScratchMem); + + REGION_UNINIT(pScreen, &SrcRegion); + REGION_UNINIT(pScreen, &GrabRegion); +} diff --git a/xorg-server/Xext/panoramiXprocs.c b/xorg-server/Xext/panoramiXprocs.c index 6635db905..369744c8c 100644 --- a/xorg-server/Xext/panoramiXprocs.c +++ b/xorg-server/Xext/panoramiXprocs.c @@ -1,2452 +1,2441 @@ -/***************************************************************** -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. -******************************************************************/ - -/* Massively rewritten by Mark Vojkovich */ - - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include -#include "windowstr.h" -#include "dixfontstr.h" -#include "gcstruct.h" -#include "colormapst.h" -#include "scrnintstr.h" -#include "opaque.h" -#include "inputstr.h" -#include "migc.h" -#include "misc.h" -#include "dixstruct.h" -#include "panoramiX.h" -#include "panoramiXsrv.h" -#include "resource.h" -#include "panoramiXh.h" - -#define XINERAMA_IMAGE_BUFSIZE (256*1024) -#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \ - CWDontPropagate | CWOverrideRedirect | CWCursor ) - -/* 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. - */ -extern XID clientErrorValue; /* XXX this is a kludge */ - -int PanoramiXCreateWindow(ClientPtr client) -{ - PanoramiXRes *parent, *newWin; - PanoramiXRes *backPix = NULL; - PanoramiXRes *bordPix = NULL; - PanoramiXRes *cmap = NULL; - REQUEST(xCreateWindowReq); - int pback_offset = 0, pbord_offset = 0, cmap_offset = 0; - int result, len, j; - int orig_x, orig_y; - XID orig_visual, tmp; - Bool parentIsRoot; - - REQUEST_AT_LEAST_SIZE(xCreateWindowReq); - - len = client->req_len - bytes_to_int32(sizeof(xCreateWindowReq)); - if (Ones(stuff->mask) != len) - return BadLength; - - result = dixLookupResourceByType((pointer *)&parent, stuff->parent, - XRT_WINDOW, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - if(stuff->class == CopyFromParent) - stuff->class = parent->u.win.class; - - if((stuff->class == InputOnly) && (stuff->mask & (~INPUTONLY_LEGAL_MASK))) - return BadMatch; - - if ((Mask)stuff->mask & CWBackPixmap) { - pback_offset = Ones((Mask)stuff->mask & (CWBackPixmap - 1)); - tmp = *((CARD32 *) &stuff[1] + pback_offset); - if ((tmp != None) && (tmp != ParentRelative)) { - result = dixLookupResourceByType((pointer *)&backPix, tmp, - XRT_PIXMAP, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - if ((Mask)stuff->mask & CWBorderPixmap) { - pbord_offset = Ones((Mask)stuff->mask & (CWBorderPixmap - 1)); - tmp = *((CARD32 *) &stuff[1] + pbord_offset); - if (tmp != CopyFromParent) { - result = dixLookupResourceByType((pointer *)&bordPix, tmp, - XRT_PIXMAP, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - if ((Mask)stuff->mask & CWColormap) { - cmap_offset = Ones((Mask)stuff->mask & (CWColormap - 1)); - tmp = *((CARD32 *) &stuff[1] + cmap_offset); - if ((tmp != CopyFromParent) && (tmp != None)) { - result = dixLookupResourceByType((pointer *)&cmap, tmp, - XRT_COLORMAP, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - } - } - - if(!(newWin = xalloc(sizeof(PanoramiXRes)))) - return BadAlloc; - - newWin->type = XRT_WINDOW; - newWin->u.win.visibility = VisibilityNotViewable; - newWin->u.win.class = stuff->class; - newWin->u.win.root = FALSE; - newWin->info[0].id = stuff->wid; - for(j = 1; j < PanoramiXNumScreens; j++) - newWin->info[j].id = FakeClientID(client->index); - - if (stuff->class == InputOnly) - stuff->visual = CopyFromParent; - orig_visual = stuff->visual; - orig_x = stuff->x; - orig_y = stuff->y; - parentIsRoot = (stuff->parent == WindowTable[0]->drawable.id) || - (stuff->parent == savedScreenInfo[0].wid); - FOR_NSCREENS_BACKWARD(j) { - stuff->wid = newWin->info[j].id; - stuff->parent = parent->info[j].id; - if (parentIsRoot) { - stuff->x = orig_x - panoramiXdataPtr[j].x; - stuff->y = orig_y - panoramiXdataPtr[j].y; - } - if (backPix) - *((CARD32 *) &stuff[1] + pback_offset) = backPix->info[j].id; - if (bordPix) - *((CARD32 *) &stuff[1] + pbord_offset) = bordPix->info[j].id; - if (cmap) - *((CARD32 *) &stuff[1] + cmap_offset) = cmap->info[j].id; - if ( orig_visual != CopyFromParent ) - stuff->visual = PanoramiXTranslateVisualID(j, orig_visual); - result = (*SavedProcVector[X_CreateWindow])(client); - if(result != Success) break; - } - - if (result == Success) - AddResource(newWin->info[0].id, XRT_WINDOW, newWin); - else - xfree(newWin); - - return (result); -} - - -int PanoramiXChangeWindowAttributes(ClientPtr client) -{ - PanoramiXRes *win; - PanoramiXRes *backPix = NULL; - PanoramiXRes *bordPix = NULL; - PanoramiXRes *cmap = NULL; - REQUEST(xChangeWindowAttributesReq); - int pback_offset = 0, pbord_offset = 0, cmap_offset = 0; - int result, len, j; - XID tmp; - - REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq); - - len = client->req_len - bytes_to_int32(sizeof(xChangeWindowAttributesReq)); - if (Ones(stuff->valueMask) != len) - return BadLength; - - result = dixLookupResourceByType((pointer *)&win, stuff->window, - XRT_WINDOW, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - if((win->u.win.class == InputOnly) && - (stuff->valueMask & (~INPUTONLY_LEGAL_MASK))) - return BadMatch; - - if ((Mask)stuff->valueMask & CWBackPixmap) { - pback_offset = Ones((Mask)stuff->valueMask & (CWBackPixmap - 1)); - tmp = *((CARD32 *) &stuff[1] + pback_offset); - if ((tmp != None) && (tmp != ParentRelative)) { - result = dixLookupResourceByType((pointer *)&backPix, tmp, - XRT_PIXMAP, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - if ((Mask)stuff->valueMask & CWBorderPixmap) { - pbord_offset = Ones((Mask)stuff->valueMask & (CWBorderPixmap - 1)); - tmp = *((CARD32 *) &stuff[1] + pbord_offset); - if (tmp != CopyFromParent) { - result = dixLookupResourceByType((pointer *)&bordPix, tmp, - XRT_PIXMAP, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - if ((Mask)stuff->valueMask & CWColormap) { - cmap_offset = Ones((Mask)stuff->valueMask & (CWColormap - 1)); - tmp = *((CARD32 *) &stuff[1] + cmap_offset); - if ((tmp != CopyFromParent) && (tmp != None)) { - result = dixLookupResourceByType((pointer *)&cmap, tmp, - XRT_COLORMAP, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - } - } - - FOR_NSCREENS_BACKWARD(j) { - stuff->window = win->info[j].id; - if (backPix) - *((CARD32 *) &stuff[1] + pback_offset) = backPix->info[j].id; - if (bordPix) - *((CARD32 *) &stuff[1] + pbord_offset) = bordPix->info[j].id; - if (cmap) - *((CARD32 *) &stuff[1] + cmap_offset) = cmap->info[j].id; - result = (*SavedProcVector[X_ChangeWindowAttributes])(client); - } - - return (result); -} - - -int PanoramiXDestroyWindow(ClientPtr client) -{ - PanoramiXRes *win; - int result, j; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->id, XRT_WINDOW, - client, DixDestroyAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->id = win->info[j].id; - result = (*SavedProcVector[X_DestroyWindow])(client); - if(result != Success) break; - } - - /* Since ProcDestroyWindow is using FreeResource, it will free - our resource for us on the last pass through the loop above */ - - return (result); -} - - -int PanoramiXDestroySubwindows(ClientPtr client) -{ - PanoramiXRes *win; - int result, j; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->id, XRT_WINDOW, - client, DixDestroyAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->id = win->info[j].id; - result = (*SavedProcVector[X_DestroySubwindows])(client); - if(result != Success) break; - } - - /* DestroySubwindows is using FreeResource which will free - our resources for us on the last pass through the loop above */ - - return (result); -} - - -int PanoramiXChangeSaveSet(ClientPtr client) -{ - PanoramiXRes *win; - int result, j; - REQUEST(xChangeSaveSetReq); - - REQUEST_SIZE_MATCH(xChangeSaveSetReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->window, - XRT_WINDOW, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->window = win->info[j].id; - result = (*SavedProcVector[X_ChangeSaveSet])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXReparentWindow(ClientPtr client) -{ - PanoramiXRes *win, *parent; - int result, j; - int x, y; - Bool parentIsRoot; - REQUEST(xReparentWindowReq); - - REQUEST_SIZE_MATCH(xReparentWindowReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->window, - XRT_WINDOW, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - result = dixLookupResourceByType((pointer *)&parent, stuff->parent, - XRT_WINDOW, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - x = stuff->x; - y = stuff->y; - parentIsRoot = (stuff->parent == WindowTable[0]->drawable.id) || - (stuff->parent == savedScreenInfo[0].wid); - FOR_NSCREENS_BACKWARD(j) { - stuff->window = win->info[j].id; - stuff->parent = parent->info[j].id; - if(parentIsRoot) { - stuff->x = x - panoramiXdataPtr[j].x; - stuff->y = y - panoramiXdataPtr[j].y; - } - result = (*SavedProcVector[X_ReparentWindow])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXMapWindow(ClientPtr client) -{ - PanoramiXRes *win; - int result, j; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->id, - XRT_WINDOW, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS_FORWARD(j) { - stuff->id = win->info[j].id; - result = (*SavedProcVector[X_MapWindow])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXMapSubwindows(ClientPtr client) -{ - PanoramiXRes *win; - int result, j; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->id, - XRT_WINDOW, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS_FORWARD(j) { - stuff->id = win->info[j].id; - result = (*SavedProcVector[X_MapSubwindows])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXUnmapWindow(ClientPtr client) -{ - PanoramiXRes *win; - int result, j; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->id, - XRT_WINDOW, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS_FORWARD(j) { - stuff->id = win->info[j].id; - result = (*SavedProcVector[X_UnmapWindow])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXUnmapSubwindows(ClientPtr client) -{ - PanoramiXRes *win; - int result, j; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->id, - XRT_WINDOW, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS_FORWARD(j) { - stuff->id = win->info[j].id; - result = (*SavedProcVector[X_UnmapSubwindows])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXConfigureWindow(ClientPtr client) -{ - PanoramiXRes *win; - PanoramiXRes *sib = NULL; - WindowPtr pWin; - int result, j, len, sib_offset = 0, x = 0, y = 0; - int x_offset = -1; - int y_offset = -1; - REQUEST(xConfigureWindowReq); - - REQUEST_AT_LEAST_SIZE(xConfigureWindowReq); - - len = client->req_len - bytes_to_int32(sizeof(xConfigureWindowReq)); - if (Ones(stuff->mask) != len) - return BadLength; - - /* because we need the parent */ - result = dixLookupResourceByType((pointer *)&pWin, stuff->window, - RT_WINDOW, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - result = dixLookupResourceByType((pointer *)&win, stuff->window, - XRT_WINDOW, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - if ((Mask)stuff->mask & CWSibling) { - XID tmp; - sib_offset = Ones((Mask)stuff->mask & (CWSibling - 1)); - if ((tmp = *((CARD32 *) &stuff[1] + sib_offset))) { - result = dixLookupResourceByType((pointer *)&sib, tmp, XRT_WINDOW, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - } - } - - if(pWin->parent && ((pWin->parent == WindowTable[0]) || - (pWin->parent->drawable.id == savedScreenInfo[0].wid))) - { - if ((Mask)stuff->mask & CWX) { - x_offset = 0; - x = *((CARD32 *)&stuff[1]); - } - if ((Mask)stuff->mask & CWY) { - y_offset = (x_offset == -1) ? 0 : 1; - y = *((CARD32 *) &stuff[1] + y_offset); - } - } - - /* have to go forward or you get expose events before - ConfigureNotify events */ - FOR_NSCREENS_FORWARD(j) { - stuff->window = win->info[j].id; - if(sib) - *((CARD32 *) &stuff[1] + sib_offset) = sib->info[j].id; - if(x_offset >= 0) - *((CARD32 *) &stuff[1] + x_offset) = x - panoramiXdataPtr[j].x; - if(y_offset >= 0) - *((CARD32 *) &stuff[1] + y_offset) = y - panoramiXdataPtr[j].y; - result = (*SavedProcVector[X_ConfigureWindow])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXCirculateWindow(ClientPtr client) -{ - PanoramiXRes *win; - int result, j; - REQUEST(xCirculateWindowReq); - - REQUEST_SIZE_MATCH(xCirculateWindowReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->window, - XRT_WINDOW, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS_FORWARD(j) { - stuff->window = win->info[j].id; - result = (*SavedProcVector[X_CirculateWindow])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXGetGeometry(ClientPtr client) -{ - xGetGeometryReply rep; - DrawablePtr pDraw; - int rc; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupDrawable(&pDraw, stuff->id, client, M_ANY, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.root = WindowTable[0]->drawable.id; - rep.depth = pDraw->depth; - rep.width = pDraw->width; - rep.height = pDraw->height; - rep.x = rep.y = rep.borderWidth = 0; - - if (stuff->id == rep.root) { - xWindowRoot *root = (xWindowRoot *) - (ConnectionInfo + connBlockScreenStart); - - rep.width = root->pixWidth; - rep.height = root->pixHeight; - } else - if ((pDraw->type == UNDRAWABLE_WINDOW) || (pDraw->type == DRAWABLE_WINDOW)) - { - WindowPtr pWin = (WindowPtr)pDraw; - rep.x = pWin->origin.x - wBorderWidth (pWin); - rep.y = pWin->origin.y - wBorderWidth (pWin); - if((pWin->parent == WindowTable[0]) || - (pWin->parent->drawable.id == savedScreenInfo[0].wid)) - { - rep.x += panoramiXdataPtr[0].x; - rep.y += panoramiXdataPtr[0].y; - } - rep.borderWidth = pWin->borderWidth; - } - - WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep); - return (client->noClientException); -} - -int PanoramiXTranslateCoords(ClientPtr client) -{ - INT16 x, y; - REQUEST(xTranslateCoordsReq); - int rc; - WindowPtr pWin, pDst; - xTranslateCoordsReply rep; - - REQUEST_SIZE_MATCH(xTranslateCoordsReq); - rc = dixLookupWindow(&pWin, stuff->srcWid, client, DixReadAccess); - if (rc != Success) - return rc; - rc = dixLookupWindow(&pDst, stuff->dstWid, client, DixReadAccess); - if (rc != Success) - return rc; - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.sameScreen = xTrue; - rep.child = None; - - if((pWin == WindowTable[0]) || - (pWin->drawable.id == savedScreenInfo[0].wid)) - { - x = stuff->srcX - panoramiXdataPtr[0].x; - y = stuff->srcY - panoramiXdataPtr[0].y; - } else { - 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->drawable.pScreen, - wBoundingShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box)) - ) - { - rep.child = pWin->drawable.id; - pWin = (WindowPtr) NULL; - } - else - pWin = pWin->nextSib; - } - rep.dstX = x - pDst->drawable.x; - rep.dstY = y - pDst->drawable.y; - if((pDst == WindowTable[0]) || - (pDst->drawable.id == savedScreenInfo[0].wid)) - { - rep.dstX += panoramiXdataPtr[0].x; - rep.dstY += panoramiXdataPtr[0].y; - } - - WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep); - return(client->noClientException); -} - -int PanoramiXCreatePixmap(ClientPtr client) -{ - PanoramiXRes *refDraw, *newPix; - int result, j; - REQUEST(xCreatePixmapReq); - - REQUEST_SIZE_MATCH(xCreatePixmapReq); - client->errorValue = stuff->pid; - - result = dixLookupResourceByClass((pointer *)&refDraw, stuff->drawable, - XRC_DRAWABLE, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(!(newPix = xalloc(sizeof(PanoramiXRes)))) - return BadAlloc; - - newPix->type = XRT_PIXMAP; - newPix->u.pix.shared = FALSE; - newPix->info[0].id = stuff->pid; - for(j = 1; j < PanoramiXNumScreens; j++) - newPix->info[j].id = FakeClientID(client->index); - - FOR_NSCREENS_BACKWARD(j) { - stuff->pid = newPix->info[j].id; - stuff->drawable = refDraw->info[j].id; - result = (*SavedProcVector[X_CreatePixmap])(client); - if(result != Success) break; - } - - if (result == Success) - AddResource(newPix->info[0].id, XRT_PIXMAP, newPix); - else - xfree(newPix); - - return (result); -} - - -int PanoramiXFreePixmap(ClientPtr client) -{ - PanoramiXRes *pix; - int result, j; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - - client->errorValue = stuff->id; - - result = dixLookupResourceByType((pointer *)&pix, stuff->id, XRT_PIXMAP, - client, DixDestroyAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->id = pix->info[j].id; - result = (*SavedProcVector[X_FreePixmap])(client); - if(result != Success) break; - } - - /* Since ProcFreePixmap is using FreeResource, it will free - our resource for us on the last pass through the loop above */ - - return (result); -} - - -int PanoramiXCreateGC(ClientPtr client) -{ - PanoramiXRes *refDraw; - PanoramiXRes *newGC; - PanoramiXRes *stip = NULL; - PanoramiXRes *tile = NULL; - PanoramiXRes *clip = NULL; - REQUEST(xCreateGCReq); - int tile_offset = 0, stip_offset = 0, clip_offset = 0; - int result, len, j; - XID tmp; - - REQUEST_AT_LEAST_SIZE(xCreateGCReq); - - client->errorValue = stuff->gc; - len = client->req_len - bytes_to_int32(sizeof(xCreateGCReq)); - if (Ones(stuff->mask) != len) - return BadLength; - - result = dixLookupResourceByClass((pointer *)&refDraw, stuff->drawable, - XRC_DRAWABLE, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if ((Mask)stuff->mask & GCTile) { - tile_offset = Ones((Mask)stuff->mask & (GCTile - 1)); - if ((tmp = *((CARD32 *) &stuff[1] + tile_offset))) { - result = dixLookupResourceByType((pointer *)&tile, tmp, XRT_PIXMAP, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - if ((Mask)stuff->mask & GCStipple) { - stip_offset = Ones((Mask)stuff->mask & (GCStipple - 1)); - if ((tmp = *((CARD32 *) &stuff[1] + stip_offset))) { - result = dixLookupResourceByType((pointer *)&stip, tmp, XRT_PIXMAP, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - if ((Mask)stuff->mask & GCClipMask) { - clip_offset = Ones((Mask)stuff->mask & (GCClipMask - 1)); - if ((tmp = *((CARD32 *) &stuff[1] + clip_offset))) { - result = dixLookupResourceByType((pointer *)&clip, tmp, XRT_PIXMAP, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - - if(!(newGC = xalloc(sizeof(PanoramiXRes)))) - return BadAlloc; - - newGC->type = XRT_GC; - newGC->info[0].id = stuff->gc; - for(j = 1; j < PanoramiXNumScreens; j++) - newGC->info[j].id = FakeClientID(client->index); - - FOR_NSCREENS_BACKWARD(j) { - stuff->gc = newGC->info[j].id; - stuff->drawable = refDraw->info[j].id; - if (tile) - *((CARD32 *) &stuff[1] + tile_offset) = tile->info[j].id; - if (stip) - *((CARD32 *) &stuff[1] + stip_offset) = stip->info[j].id; - if (clip) - *((CARD32 *) &stuff[1] + clip_offset) = clip->info[j].id; - result = (*SavedProcVector[X_CreateGC])(client); - if(result != Success) break; - } - - if (result == Success) - AddResource(newGC->info[0].id, XRT_GC, newGC); - else - xfree(newGC); - - return (result); -} - -int PanoramiXChangeGC(ClientPtr client) -{ - PanoramiXRes *gc; - PanoramiXRes *stip = NULL; - PanoramiXRes *tile = NULL; - PanoramiXRes *clip = NULL; - REQUEST(xChangeGCReq); - int tile_offset = 0, stip_offset = 0, clip_offset = 0; - int result, len, j; - XID tmp; - - REQUEST_AT_LEAST_SIZE(xChangeGCReq); - - len = client->req_len - bytes_to_int32(sizeof(xChangeGCReq)); - if (Ones(stuff->mask) != len) - return BadLength; - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - if ((Mask)stuff->mask & GCTile) { - tile_offset = Ones((Mask)stuff->mask & (GCTile - 1)); - if ((tmp = *((CARD32 *) &stuff[1] + tile_offset))) { - result = dixLookupResourceByType((pointer *)&tile, tmp, XRT_PIXMAP, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - if ((Mask)stuff->mask & GCStipple) { - stip_offset = Ones((Mask)stuff->mask & (GCStipple - 1)); - if ((tmp = *((CARD32 *) &stuff[1] + stip_offset))) { - result = dixLookupResourceByType((pointer *)&stip, tmp, XRT_PIXMAP, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - if ((Mask)stuff->mask & GCClipMask) { - clip_offset = Ones((Mask)stuff->mask & (GCClipMask - 1)); - if ((tmp = *((CARD32 *) &stuff[1] + clip_offset))) { - result = dixLookupResourceByType((pointer *)&clip, tmp, XRT_PIXMAP, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } - } - - - FOR_NSCREENS_BACKWARD(j) { - stuff->gc = gc->info[j].id; - if (tile) - *((CARD32 *) &stuff[1] + tile_offset) = tile->info[j].id; - if (stip) - *((CARD32 *) &stuff[1] + stip_offset) = stip->info[j].id; - if (clip) - *((CARD32 *) &stuff[1] + clip_offset) = clip->info[j].id; - result = (*SavedProcVector[X_ChangeGC])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXCopyGC(ClientPtr client) -{ - PanoramiXRes *srcGC, *dstGC; - int result, j; - REQUEST(xCopyGCReq); - - REQUEST_SIZE_MATCH(xCopyGCReq); - - result = dixLookupResourceByType((pointer *)&srcGC, stuff->srcGC, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - result = dixLookupResourceByType((pointer *)&dstGC, stuff->dstGC, XRT_GC, - client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - FOR_NSCREENS(j) { - stuff->srcGC = srcGC->info[j].id; - stuff->dstGC = dstGC->info[j].id; - result = (*SavedProcVector[X_CopyGC])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXSetDashes(ClientPtr client) -{ - PanoramiXRes *gc; - int result, j; - REQUEST(xSetDashesReq); - - REQUEST_FIXED_SIZE(xSetDashesReq, stuff->nDashes); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->gc = gc->info[j].id; - result = (*SavedProcVector[X_SetDashes])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXSetClipRectangles(ClientPtr client) -{ - PanoramiXRes *gc; - int result, j; - REQUEST(xSetClipRectanglesReq); - - REQUEST_AT_LEAST_SIZE(xSetClipRectanglesReq); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->gc = gc->info[j].id; - result = (*SavedProcVector[X_SetClipRectangles])(client); - if(result != Success) break; - } - - return (result); -} - - -int PanoramiXFreeGC(ClientPtr client) -{ - PanoramiXRes *gc; - int result, j; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - - result = dixLookupResourceByType((pointer *)&gc, stuff->id, XRT_GC, - client, DixDestroyAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->id = gc->info[j].id; - result = (*SavedProcVector[X_FreeGC])(client); - if(result != Success) break; - } - - /* Since ProcFreeGC is using FreeResource, it will free - our resource for us on the last pass through the loop above */ - - return (result); -} - - -int PanoramiXClearToBackground(ClientPtr client) -{ - PanoramiXRes *win; - int result, j, x, y; - Bool isRoot; - REQUEST(xClearAreaReq); - - REQUEST_SIZE_MATCH(xClearAreaReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->window, - XRT_WINDOW, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - x = stuff->x; - y = stuff->y; - isRoot = win->u.win.root; - FOR_NSCREENS_BACKWARD(j) { - stuff->window = win->info[j].id; - if(isRoot) { - stuff->x = x - panoramiXdataPtr[j].x; - stuff->y = y - panoramiXdataPtr[j].y; - } - result = (*SavedProcVector[X_ClearArea])(client); - if(result != Success) break; - } - - return (result); -} - - -/* - For Window to Pixmap copies you're screwed since each screen's - pixmap will look like what it sees on its screen. Unless the - screens overlap and the window lies on each, the two copies - will be out of sync. To remedy this we do a GetImage and PutImage - in place of the copy. Doing this as a single Image isn't quite - correct since it will include the obscured areas but we will - have to fix this later. (MArk). -*/ - -int PanoramiXCopyArea(ClientPtr client) -{ - int j, result, srcx, srcy, dstx, dsty; - PanoramiXRes *gc, *src, *dst; - Bool srcIsRoot = FALSE; - Bool dstIsRoot = FALSE; - Bool srcShared, dstShared; - REQUEST(xCopyAreaReq); - - REQUEST_SIZE_MATCH(xCopyAreaReq); - - result = dixLookupResourceByClass((pointer *)&src, stuff->srcDrawable, - XRC_DRAWABLE, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - srcShared = IS_SHARED_PIXMAP(src); - - result = dixLookupResourceByClass((pointer *)&dst, stuff->dstDrawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - dstShared = IS_SHARED_PIXMAP(dst); - - if(dstShared && srcShared) - return (* SavedProcVector[X_CopyArea])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - if((dst->type == XRT_WINDOW) && dst->u.win.root) - dstIsRoot = TRUE; - if((src->type == XRT_WINDOW) && src->u.win.root) - srcIsRoot = TRUE; - - srcx = stuff->srcX; srcy = stuff->srcY; - dstx = stuff->dstX; dsty = stuff->dstY; - if((dst->type == XRT_PIXMAP) && (src->type == XRT_WINDOW)) { - DrawablePtr drawables[MAXSCREENS]; - DrawablePtr pDst; - GCPtr pGC; - char *data; - int pitch, rc; - - FOR_NSCREENS(j) { - rc = dixLookupDrawable(drawables+j, src->info[j].id, client, 0, - DixGetAttrAccess); - if (rc != Success) - return rc; - } - - pitch = PixmapBytePad(stuff->width, drawables[0]->depth); - if(!(data = xcalloc(1, stuff->height * pitch))) - return BadAlloc; - - XineramaGetImageData(drawables, srcx, srcy, - stuff->width, stuff->height, ZPixmap, ~0, data, pitch, - srcIsRoot); - - FOR_NSCREENS_BACKWARD(j) { - stuff->gc = gc->info[j].id; - VALIDATE_DRAWABLE_AND_GC(dst->info[j].id, pDst, DixWriteAccess); - if(drawables[0]->depth != pDst->depth) { - client->errorValue = stuff->dstDrawable; - xfree(data); - return (BadMatch); - } - - (*pGC->ops->PutImage) (pDst, pGC, pDst->depth, dstx, dsty, - stuff->width, stuff->height, - 0, ZPixmap, data); - - if(dstShared) break; - } - - xfree(data); - - result = Success; - } else { - DrawablePtr pDst = NULL, pSrc = NULL; - GCPtr pGC = NULL; - RegionPtr pRgn[MAXSCREENS]; - int rc; - - FOR_NSCREENS_BACKWARD(j) { - stuff->dstDrawable = dst->info[j].id; - stuff->srcDrawable = src->info[j].id; - stuff->gc = gc->info[j].id; - if (srcIsRoot) { - stuff->srcX = srcx - panoramiXdataPtr[j].x; - stuff->srcY = srcy - panoramiXdataPtr[j].y; - } - if (dstIsRoot) { - stuff->dstX = dstx - panoramiXdataPtr[j].x; - stuff->dstY = dsty - panoramiXdataPtr[j].y; - } - - VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, DixWriteAccess); - - if (stuff->dstDrawable != stuff->srcDrawable) { - rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - if ((pDst->pScreen != pSrc->pScreen) || - (pDst->depth != pSrc->depth)) { - client->errorValue = stuff->dstDrawable; - return (BadMatch); - } - } else - pSrc = pDst; - - pRgn[j] = (*pGC->ops->CopyArea)(pSrc, pDst, pGC, - stuff->srcX, stuff->srcY, - stuff->width, stuff->height, - stuff->dstX, stuff->dstY); - - if(dstShared) { - while(j--) pRgn[j] = NULL; - break; - } - } - - if(pGC->graphicsExposures) { - ScreenPtr pScreen = pDst->pScreen; - RegionRec totalReg; - Bool overlap; - - REGION_NULL(pScreen, &totalReg); - FOR_NSCREENS_BACKWARD(j) { - if(pRgn[j]) { - if(srcIsRoot) { - REGION_TRANSLATE(pScreen, pRgn[j], - panoramiXdataPtr[j].x, panoramiXdataPtr[j].y); - } - REGION_APPEND(pScreen, &totalReg, pRgn[j]); - REGION_DESTROY(pScreen, pRgn[j]); - } - } - REGION_VALIDATE(pScreen, &totalReg, &overlap); - (*pScreen->SendGraphicsExpose)( - client, &totalReg, stuff->dstDrawable, X_CopyArea, 0); - REGION_UNINIT(pScreen, &totalReg); - } - - result = client->noClientException; - } - - return (result); -} - - -int PanoramiXCopyPlane(ClientPtr client) -{ - int j, srcx, srcy, dstx, dsty, rc; - PanoramiXRes *gc, *src, *dst; - Bool srcIsRoot = FALSE; - Bool dstIsRoot = FALSE; - Bool srcShared, dstShared; - DrawablePtr psrcDraw, pdstDraw = NULL; - GCPtr pGC = NULL; - RegionPtr pRgn[MAXSCREENS]; - REQUEST(xCopyPlaneReq); - - REQUEST_SIZE_MATCH(xCopyPlaneReq); - - rc = dixLookupResourceByClass((pointer *)&src, stuff->srcDrawable, - XRC_DRAWABLE, client, DixReadAccess); - if (rc != Success) - return (rc == BadValue) ? BadDrawable : rc; - - srcShared = IS_SHARED_PIXMAP(src); - - rc = dixLookupResourceByClass((pointer *)&dst, stuff->dstDrawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (rc != Success) - return (rc == BadValue) ? BadDrawable : rc; - - dstShared = IS_SHARED_PIXMAP(dst); - - if(dstShared && srcShared) - return (* SavedProcVector[X_CopyPlane])(client); - - rc = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (rc != Success) - return (rc == BadValue) ? BadGC : rc; - - if((dst->type == XRT_WINDOW) && dst->u.win.root) - dstIsRoot = TRUE; - if((src->type == XRT_WINDOW) && src->u.win.root) - srcIsRoot = TRUE; - - srcx = stuff->srcX; srcy = stuff->srcY; - dstx = stuff->dstX; dsty = stuff->dstY; - - FOR_NSCREENS_BACKWARD(j) { - stuff->dstDrawable = dst->info[j].id; - stuff->srcDrawable = src->info[j].id; - stuff->gc = gc->info[j].id; - if (srcIsRoot) { - stuff->srcX = srcx - panoramiXdataPtr[j].x; - stuff->srcY = srcy - panoramiXdataPtr[j].y; - } - if (dstIsRoot) { - stuff->dstX = dstx - panoramiXdataPtr[j].x; - stuff->dstY = dsty - panoramiXdataPtr[j].y; - } - - VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pdstDraw, DixWriteAccess); - if (stuff->dstDrawable != stuff->srcDrawable) { - rc = dixLookupDrawable(&psrcDraw, stuff->srcDrawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - if (pdstDraw->pScreen != psrcDraw->pScreen) { - client->errorValue = stuff->dstDrawable; - return (BadMatch); - } - } else - psrcDraw = pdstDraw; - - if(stuff->bitPlane == 0 || (stuff->bitPlane & (stuff->bitPlane - 1)) || - (stuff->bitPlane > (1L << (psrcDraw->depth - 1)))) { - client->errorValue = stuff->bitPlane; - return(BadValue); - } - - pRgn[j] = (*pGC->ops->CopyPlane)(psrcDraw, pdstDraw, pGC, - stuff->srcX, stuff->srcY, - stuff->width, stuff->height, - stuff->dstX, stuff->dstY, stuff->bitPlane); - - if(dstShared) { - while(j--) pRgn[j] = NULL; - break; - } - } - - if(pGC->graphicsExposures) { - ScreenPtr pScreen = pdstDraw->pScreen; - RegionRec totalReg; - Bool overlap; - - REGION_NULL(pScreen, &totalReg); - FOR_NSCREENS_BACKWARD(j) { - if(pRgn[j]) { - REGION_APPEND(pScreen, &totalReg, pRgn[j]); - REGION_DESTROY(pScreen, pRgn[j]); - } - } - REGION_VALIDATE(pScreen, &totalReg, &overlap); - (*pScreen->SendGraphicsExpose)( - client, &totalReg, stuff->dstDrawable, X_CopyPlane, 0); - REGION_UNINIT(pScreen, &totalReg); - } - - return (client->noClientException); -} - - -int PanoramiXPolyPoint(ClientPtr client) -{ - PanoramiXRes *gc, *draw; - int result, npoint, j; - xPoint *origPts; - Bool isRoot; - REQUEST(xPolyPointReq); - - REQUEST_AT_LEAST_SIZE(xPolyPointReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PolyPoint])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyPointReq)); - if (npoint > 0) { - origPts = xalloc(npoint * sizeof(xPoint)); - memcpy((char *) origPts, (char *) &stuff[1], npoint * sizeof(xPoint)); - FOR_NSCREENS_FORWARD(j){ - - if(j) memcpy(&stuff[1], origPts, npoint * sizeof(xPoint)); - - if (isRoot) { - int x_off = panoramiXdataPtr[j].x; - int y_off = panoramiXdataPtr[j].y; - - if(x_off || y_off) { - xPoint *pnts = (xPoint*)&stuff[1]; - int i = (stuff->coordMode==CoordModePrevious) ? 1 : npoint; - - while(i--) { - pnts->x -= x_off; - pnts->y -= y_off; - pnts++; - } - } - } - - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - result = (* SavedProcVector[X_PolyPoint])(client); - if(result != Success) break; - } - xfree(origPts); - return (result); - } else - return (client->noClientException); -} - - -int PanoramiXPolyLine(ClientPtr client) -{ - PanoramiXRes *gc, *draw; - int result, npoint, j; - xPoint *origPts; - Bool isRoot; - REQUEST(xPolyLineReq); - - REQUEST_AT_LEAST_SIZE(xPolyLineReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PolyLine])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyLineReq)); - if (npoint > 0){ - origPts = xalloc(npoint * sizeof(xPoint)); - memcpy((char *) origPts, (char *) &stuff[1], npoint * sizeof(xPoint)); - FOR_NSCREENS_FORWARD(j){ - - if(j) memcpy(&stuff[1], origPts, npoint * sizeof(xPoint)); - - if (isRoot) { - int x_off = panoramiXdataPtr[j].x; - int y_off = panoramiXdataPtr[j].y; - - if(x_off || y_off) { - xPoint *pnts = (xPoint*)&stuff[1]; - int i = (stuff->coordMode==CoordModePrevious) ? 1 : npoint; - - while(i--) { - pnts->x -= x_off; - pnts->y -= y_off; - pnts++; - } - } - } - - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - result = (* SavedProcVector[X_PolyLine])(client); - if(result != Success) break; - } - xfree(origPts); - return (result); - } else - return (client->noClientException); -} - - -int PanoramiXPolySegment(ClientPtr client) -{ - int result, nsegs, i, j; - PanoramiXRes *gc, *draw; - xSegment *origSegs; - Bool isRoot; - REQUEST(xPolySegmentReq); - - REQUEST_AT_LEAST_SIZE(xPolySegmentReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PolySegment])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - nsegs = (client->req_len << 2) - sizeof(xPolySegmentReq); - if(nsegs & 4) return BadLength; - nsegs >>= 3; - if (nsegs > 0) { - origSegs = xalloc(nsegs * sizeof(xSegment)); - memcpy((char *) origSegs, (char *) &stuff[1], nsegs * sizeof(xSegment)); - FOR_NSCREENS_FORWARD(j){ - - if(j) memcpy(&stuff[1], origSegs, nsegs * sizeof(xSegment)); - - if (isRoot) { - int x_off = panoramiXdataPtr[j].x; - int y_off = panoramiXdataPtr[j].y; - - if(x_off || y_off) { - xSegment *segs = (xSegment*)&stuff[1]; - - for (i = nsegs; i--; segs++) { - segs->x1 -= x_off; - segs->x2 -= x_off; - segs->y1 -= y_off; - segs->y2 -= y_off; - } - } - } - - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - result = (* SavedProcVector[X_PolySegment])(client); - if(result != Success) break; - } - xfree(origSegs); - return (result); - } else - return (client->noClientException); -} - - -int PanoramiXPolyRectangle(ClientPtr client) -{ - int result, nrects, i, j; - PanoramiXRes *gc, *draw; - Bool isRoot; - xRectangle *origRecs; - REQUEST(xPolyRectangleReq); - - REQUEST_AT_LEAST_SIZE(xPolyRectangleReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PolyRectangle])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - nrects = (client->req_len << 2) - sizeof(xPolyRectangleReq); - if(nrects & 4) return BadLength; - nrects >>= 3; - if (nrects > 0){ - origRecs = xalloc(nrects * sizeof(xRectangle)); - memcpy((char *)origRecs,(char *)&stuff[1],nrects * sizeof(xRectangle)); - FOR_NSCREENS_FORWARD(j){ - - if(j) memcpy(&stuff[1], origRecs, nrects * sizeof(xRectangle)); - - if (isRoot) { - int x_off = panoramiXdataPtr[j].x; - int y_off = panoramiXdataPtr[j].y; - - - if(x_off || y_off) { - xRectangle *rects = (xRectangle *) &stuff[1]; - - for (i = nrects; i--; rects++) { - rects->x -= x_off; - rects->y -= y_off; - } - } - } - - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - result = (* SavedProcVector[X_PolyRectangle])(client); - if(result != Success) break; - } - xfree(origRecs); - return (result); - } else - return (client->noClientException); -} - - -int PanoramiXPolyArc(ClientPtr client) -{ - int result, narcs, i, j; - PanoramiXRes *gc, *draw; - Bool isRoot; - xArc *origArcs; - REQUEST(xPolyArcReq); - - REQUEST_AT_LEAST_SIZE(xPolyArcReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PolyArc])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - narcs = (client->req_len << 2) - sizeof(xPolyArcReq); - if(narcs % sizeof(xArc)) return BadLength; - narcs /= sizeof(xArc); - if (narcs > 0){ - origArcs = xalloc(narcs * sizeof(xArc)); - memcpy((char *) origArcs, (char *) &stuff[1], narcs * sizeof(xArc)); - FOR_NSCREENS_FORWARD(j){ - - if(j) memcpy(&stuff[1], origArcs, narcs * sizeof(xArc)); - - if (isRoot) { - int x_off = panoramiXdataPtr[j].x; - int y_off = panoramiXdataPtr[j].y; - - if(x_off || y_off) { - xArc *arcs = (xArc *) &stuff[1]; - - for (i = narcs; i--; arcs++) { - arcs->x -= x_off; - arcs->y -= y_off; - } - } - } - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - result = (* SavedProcVector[X_PolyArc])(client); - if(result != Success) break; - } - xfree(origArcs); - return (result); - } else - return (client->noClientException); -} - - -int PanoramiXFillPoly(ClientPtr client) -{ - int result, count, j; - PanoramiXRes *gc, *draw; - Bool isRoot; - DDXPointPtr locPts; - REQUEST(xFillPolyReq); - - REQUEST_AT_LEAST_SIZE(xFillPolyReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_FillPoly])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - count = bytes_to_int32((client->req_len << 2) - sizeof(xFillPolyReq)); - if (count > 0){ - locPts = xalloc(count * sizeof(DDXPointRec)); - memcpy((char *)locPts, (char *)&stuff[1], count * sizeof(DDXPointRec)); - FOR_NSCREENS_FORWARD(j){ - - if(j) memcpy(&stuff[1], locPts, count * sizeof(DDXPointRec)); - - if (isRoot) { - int x_off = panoramiXdataPtr[j].x; - int y_off = panoramiXdataPtr[j].y; - - if(x_off || y_off) { - DDXPointPtr pnts = (DDXPointPtr)&stuff[1]; - int i = (stuff->coordMode==CoordModePrevious) ? 1 : count; - - while(i--) { - pnts->x -= x_off; - pnts->y -= y_off; - pnts++; - } - } - } - - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - result = (* SavedProcVector[X_FillPoly])(client); - if(result != Success) break; - } - xfree(locPts); - return (result); - } else - return (client->noClientException); -} - - -int PanoramiXPolyFillRectangle(ClientPtr client) -{ - int result, things, i, j; - PanoramiXRes *gc, *draw; - Bool isRoot; - xRectangle *origRects; - REQUEST(xPolyFillRectangleReq); - - REQUEST_AT_LEAST_SIZE(xPolyFillRectangleReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PolyFillRectangle])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - things = (client->req_len << 2) - sizeof(xPolyFillRectangleReq); - if(things & 4) return BadLength; - things >>= 3; - if (things > 0){ - origRects = xalloc(things * sizeof(xRectangle)); - memcpy((char*)origRects,(char*)&stuff[1], things * sizeof(xRectangle)); - FOR_NSCREENS_FORWARD(j){ - - if(j) memcpy(&stuff[1], origRects, things * sizeof(xRectangle)); - - if (isRoot) { - int x_off = panoramiXdataPtr[j].x; - int y_off = panoramiXdataPtr[j].y; - - if(x_off || y_off) { - xRectangle *rects = (xRectangle *) &stuff[1]; - - for (i = things; i--; rects++) { - rects->x -= x_off; - rects->y -= y_off; - } - } - } - - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - result = (* SavedProcVector[X_PolyFillRectangle])(client); - if(result != Success) break; - } - xfree(origRects); - return (result); - } else - return (client->noClientException); -} - - -int PanoramiXPolyFillArc(ClientPtr client) -{ - PanoramiXRes *gc, *draw; - Bool isRoot; - int result, narcs, i, j; - xArc *origArcs; - REQUEST(xPolyFillArcReq); - - REQUEST_AT_LEAST_SIZE(xPolyFillArcReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PolyFillArc])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - narcs = (client->req_len << 2) - sizeof(xPolyFillArcReq); - if (narcs % sizeof(xArc)) return BadLength; - narcs /= sizeof(xArc); - if (narcs > 0) { - origArcs = xalloc(narcs * sizeof(xArc)); - memcpy((char *) origArcs, (char *)&stuff[1], narcs * sizeof(xArc)); - FOR_NSCREENS_FORWARD(j){ - - if(j) memcpy(&stuff[1], origArcs, narcs * sizeof(xArc)); - - if (isRoot) { - int x_off = panoramiXdataPtr[j].x; - int y_off = panoramiXdataPtr[j].y; - - if(x_off || y_off) { - xArc *arcs = (xArc *) &stuff[1]; - - for (i = narcs; i--; arcs++) { - arcs->x -= x_off; - arcs->y -= y_off; - } - } - } - - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - result = (* SavedProcVector[X_PolyFillArc])(client); - if(result != Success) break; - } - xfree(origArcs); - return (result); - } else - return (client->noClientException); -} - - -int PanoramiXPutImage(ClientPtr client) -{ - PanoramiXRes *gc, *draw; - Bool isRoot; - int j, result, orig_x, orig_y; - REQUEST(xPutImageReq); - - REQUEST_AT_LEAST_SIZE(xPutImageReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PutImage])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - orig_x = stuff->dstX; - orig_y = stuff->dstY; - FOR_NSCREENS_BACKWARD(j){ - if (isRoot) { - stuff->dstX = orig_x - panoramiXdataPtr[j].x; - stuff->dstY = orig_y - panoramiXdataPtr[j].y; - } - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - result = (* SavedProcVector[X_PutImage])(client); - if(result != Success) break; - } - return (result); -} - - -int PanoramiXGetImage(ClientPtr client) -{ - DrawablePtr drawables[MAXSCREENS]; - DrawablePtr pDraw; - PanoramiXRes *draw; - xGetImageReply xgi; - Bool isRoot; - char *pBuf; - int i, x, y, w, h, format, rc; - Mask plane = 0, planemask; - int linesDone, nlines, linesPerBuf; - long widthBytesLine, length; - - REQUEST(xGetImageReq); - - REQUEST_SIZE_MATCH(xGetImageReq); - - if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) { - client->errorValue = stuff->format; - return(BadValue); - } - - rc = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (rc != Success) - return (rc == BadValue) ? BadDrawable : rc; - - if(draw->type == XRT_PIXMAP) - return (*SavedProcVector[X_GetImage])(client); - - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - if(!((WindowPtr)pDraw)->realized) - return(BadMatch); - - x = stuff->x; - y = stuff->y; - w = stuff->width; - h = stuff->height; - format = stuff->format; - planemask = stuff->planeMask; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - if(isRoot) { - if( /* check for being onscreen */ - x < 0 || x + w > PanoramiXPixWidth || - y < 0 || y + h > PanoramiXPixHeight ) - return(BadMatch); - } else { - if( /* check for being onscreen */ - panoramiXdataPtr[0].x + pDraw->x + x < 0 || - panoramiXdataPtr[0].x + pDraw->x + x + w > PanoramiXPixWidth || - panoramiXdataPtr[0].y + pDraw->y + y < 0 || - panoramiXdataPtr[0].y + pDraw->y + y + h > PanoramiXPixHeight || - /* check for being inside of border */ - x < - wBorderWidth((WindowPtr)pDraw) || - x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || - y < -wBorderWidth((WindowPtr)pDraw) || - y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height) - return(BadMatch); - } - - drawables[0] = pDraw; - for(i = 1; i < PanoramiXNumScreens; i++) { - rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0, - DixGetAttrAccess); - if (rc != Success) - return rc; - } - - xgi.visual = wVisual (((WindowPtr) pDraw)); - xgi.type = X_Reply; - xgi.sequenceNumber = client->sequence; - xgi.depth = pDraw->depth; - if(format == ZPixmap) { - widthBytesLine = PixmapBytePad(w, pDraw->depth); - length = widthBytesLine * h; - - - } else { - widthBytesLine = BitmapBytePad(w); - plane = ((Mask)1) << (pDraw->depth - 1); - /* only planes asked for */ - length = widthBytesLine * h * - Ones(planemask & (plane | (plane - 1))); - - } - - xgi.length = bytes_to_int32(length); - - if (widthBytesLine == 0 || h == 0) - linesPerBuf = 0; - else if (widthBytesLine >= XINERAMA_IMAGE_BUFSIZE) - linesPerBuf = 1; - else { - linesPerBuf = XINERAMA_IMAGE_BUFSIZE / widthBytesLine; - if (linesPerBuf > h) - linesPerBuf = h; - } - length = linesPerBuf * widthBytesLine; - if(!(pBuf = xalloc(length))) - return (BadAlloc); - - WriteReplyToClient(client, sizeof (xGetImageReply), &xgi); - - if (linesPerBuf == 0) { - /* nothing to do */ - } - else if (format == ZPixmap) { - linesDone = 0; - while (h - linesDone > 0) { - nlines = min(linesPerBuf, h - linesDone); - - if(pDraw->depth == 1) - bzero(pBuf, nlines * widthBytesLine); - - XineramaGetImageData(drawables, x, y + linesDone, w, nlines, - format, planemask, pBuf, widthBytesLine, isRoot); - - (void)WriteToClient(client, - (int)(nlines * widthBytesLine), - pBuf); - linesDone += nlines; - } - } else { /* XYPixmap */ - for (; plane; plane >>= 1) { - if (planemask & plane) { - linesDone = 0; - while (h - linesDone > 0) { - nlines = min(linesPerBuf, h - linesDone); - - bzero(pBuf, nlines * widthBytesLine); - - XineramaGetImageData(drawables, x, y + linesDone, w, - nlines, format, plane, pBuf, - widthBytesLine, isRoot); - - (void)WriteToClient(client, - (int)(nlines * widthBytesLine), - pBuf); - - linesDone += nlines; - } - } - } - } - xfree(pBuf); - return (client->noClientException); -} - - -/* The text stuff should be rewritten so that duplication happens - at the GlyphBlt level. That is, loading the font and getting - the glyphs should only happen once */ - -int -PanoramiXPolyText8(ClientPtr client) -{ - PanoramiXRes *gc, *draw; - Bool isRoot; - int result, j; - int orig_x, orig_y; - REQUEST(xPolyTextReq); - - REQUEST_AT_LEAST_SIZE(xPolyTextReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PolyText8])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - orig_x = stuff->x; - orig_y = stuff->y; - FOR_NSCREENS_BACKWARD(j){ - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - if (isRoot) { - stuff->x = orig_x - panoramiXdataPtr[j].x; - stuff->y = orig_y - panoramiXdataPtr[j].y; - } - result = (*SavedProcVector[X_PolyText8])(client); - if(result != Success) break; - } - return (result); -} - -int -PanoramiXPolyText16(ClientPtr client) -{ - PanoramiXRes *gc, *draw; - Bool isRoot; - int result, j; - int orig_x, orig_y; - REQUEST(xPolyTextReq); - - REQUEST_AT_LEAST_SIZE(xPolyTextReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_PolyText16])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - orig_x = stuff->x; - orig_y = stuff->y; - FOR_NSCREENS_BACKWARD(j){ - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - if (isRoot) { - stuff->x = orig_x - panoramiXdataPtr[j].x; - stuff->y = orig_y - panoramiXdataPtr[j].y; - } - result = (*SavedProcVector[X_PolyText16])(client); - if(result != Success) break; - } - return (result); -} - - -int PanoramiXImageText8(ClientPtr client) -{ - int result, j; - PanoramiXRes *gc, *draw; - Bool isRoot; - int orig_x, orig_y; - REQUEST(xImageTextReq); - - REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_ImageText8])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - orig_x = stuff->x; - orig_y = stuff->y; - FOR_NSCREENS_BACKWARD(j){ - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - if (isRoot) { - stuff->x = orig_x - panoramiXdataPtr[j].x; - stuff->y = orig_y - panoramiXdataPtr[j].y; - } - result = (*SavedProcVector[X_ImageText8])(client); - if(result != Success) break; - } - return (result); -} - - -int PanoramiXImageText16(ClientPtr client) -{ - int result, j; - PanoramiXRes *gc, *draw; - Bool isRoot; - int orig_x, orig_y; - REQUEST(xImageTextReq); - - REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars << 1); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - if(IS_SHARED_PIXMAP(draw)) - return (*SavedProcVector[X_ImageText16])(client); - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - orig_x = stuff->x; - orig_y = stuff->y; - FOR_NSCREENS_BACKWARD(j){ - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - if (isRoot) { - stuff->x = orig_x - panoramiXdataPtr[j].x; - stuff->y = orig_y - panoramiXdataPtr[j].y; - } - result = (*SavedProcVector[X_ImageText16])(client); - if(result != Success) break; - } - return (result); -} - - - -int PanoramiXCreateColormap(ClientPtr client) -{ - PanoramiXRes *win, *newCmap; - int result, j, orig_visual; - REQUEST(xCreateColormapReq); - - REQUEST_SIZE_MATCH(xCreateColormapReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->window, - XRT_WINDOW, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - if(!(newCmap = xalloc(sizeof(PanoramiXRes)))) - return BadAlloc; - - newCmap->type = XRT_COLORMAP; - newCmap->info[0].id = stuff->mid; - for(j = 1; j < PanoramiXNumScreens; j++) - newCmap->info[j].id = FakeClientID(client->index); - - orig_visual = stuff->visual; - FOR_NSCREENS_BACKWARD(j){ - stuff->mid = newCmap->info[j].id; - stuff->window = win->info[j].id; - stuff->visual = PanoramiXTranslateVisualID(j, orig_visual); - result = (* SavedProcVector[X_CreateColormap])(client); - if(result != Success) break; - } - - if (result == Success) - AddResource(newCmap->info[0].id, XRT_COLORMAP, newCmap); - else - xfree(newCmap); - - return (result); -} - - -int PanoramiXFreeColormap(ClientPtr client) -{ - PanoramiXRes *cmap; - int result, j; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - - client->errorValue = stuff->id; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->id, XRT_COLORMAP, - client, DixDestroyAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->id = cmap->info[j].id; - result = (* SavedProcVector[X_FreeColormap])(client); - if(result != Success) break; - } - - /* Since ProcFreeColormap is using FreeResource, it will free - our resource for us on the last pass through the loop above */ - - return (result); -} - - -int -PanoramiXCopyColormapAndFree(ClientPtr client) -{ - PanoramiXRes *cmap, *newCmap; - int result, j; - REQUEST(xCopyColormapAndFreeReq); - - REQUEST_SIZE_MATCH(xCopyColormapAndFreeReq); - - client->errorValue = stuff->srcCmap; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->srcCmap, - XRT_COLORMAP, client, - DixReadAccess | DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - if(!(newCmap = xalloc(sizeof(PanoramiXRes)))) - return BadAlloc; - - newCmap->type = XRT_COLORMAP; - newCmap->info[0].id = stuff->mid; - for(j = 1; j < PanoramiXNumScreens; j++) - newCmap->info[j].id = FakeClientID(client->index); - - FOR_NSCREENS_BACKWARD(j){ - stuff->srcCmap = cmap->info[j].id; - stuff->mid = newCmap->info[j].id; - result = (* SavedProcVector[X_CopyColormapAndFree])(client); - if(result != Success) break; - } - - if (result == Success) - AddResource(newCmap->info[0].id, XRT_COLORMAP, newCmap); - else - xfree(newCmap); - - return (result); -} - - -int PanoramiXInstallColormap(ClientPtr client) -{ - REQUEST(xResourceReq); - int result, j; - PanoramiXRes *cmap; - - REQUEST_SIZE_MATCH(xResourceReq); - - client->errorValue = stuff->id; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->id, XRT_COLORMAP, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j){ - stuff->id = cmap->info[j].id; - result = (* SavedProcVector[X_InstallColormap])(client); - if(result != Success) break; - } - return (result); -} - - -int PanoramiXUninstallColormap(ClientPtr client) -{ - REQUEST(xResourceReq); - int result, j; - PanoramiXRes *cmap; - - REQUEST_SIZE_MATCH(xResourceReq); - - client->errorValue = stuff->id; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->id, XRT_COLORMAP, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->id = cmap->info[j].id; - result = (* SavedProcVector[X_UninstallColormap])(client); - if(result != Success) break; - } - return (result); -} - - -int PanoramiXAllocColor(ClientPtr client) -{ - int result, j; - PanoramiXRes *cmap; - REQUEST(xAllocColorReq); - - REQUEST_SIZE_MATCH(xAllocColorReq); - - client->errorValue = stuff->cmap; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, - XRT_COLORMAP, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j){ - stuff->cmap = cmap->info[j].id; - result = (* SavedProcVector[X_AllocColor])(client); - if(result != Success) break; - } - return (result); -} - - -int PanoramiXAllocNamedColor(ClientPtr client) -{ - int result, j; - PanoramiXRes *cmap; - REQUEST(xAllocNamedColorReq); - - REQUEST_FIXED_SIZE(xAllocNamedColorReq, stuff->nbytes); - - client->errorValue = stuff->cmap; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, - XRT_COLORMAP, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j){ - stuff->cmap = cmap->info[j].id; - result = (* SavedProcVector[X_AllocNamedColor])(client); - if(result != Success) break; - } - return (result); -} - - -int PanoramiXAllocColorCells(ClientPtr client) -{ - int result, j; - PanoramiXRes *cmap; - REQUEST(xAllocColorCellsReq); - - REQUEST_SIZE_MATCH(xAllocColorCellsReq); - - client->errorValue = stuff->cmap; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, - XRT_COLORMAP, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j){ - stuff->cmap = cmap->info[j].id; - result = (* SavedProcVector[X_AllocColorCells])(client); - if(result != Success) break; - } - return (result); -} - - -int PanoramiXAllocColorPlanes(ClientPtr client) -{ - int result, j; - PanoramiXRes *cmap; - REQUEST(xAllocColorPlanesReq); - - REQUEST_SIZE_MATCH(xAllocColorPlanesReq); - - client->errorValue = stuff->cmap; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, - XRT_COLORMAP, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j){ - stuff->cmap = cmap->info[j].id; - result = (* SavedProcVector[X_AllocColorPlanes])(client); - if(result != Success) break; - } - return (result); -} - - - -int PanoramiXFreeColors(ClientPtr client) -{ - int result, j; - PanoramiXRes *cmap; - REQUEST(xFreeColorsReq); - - REQUEST_AT_LEAST_SIZE(xFreeColorsReq); - - client->errorValue = stuff->cmap; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, - XRT_COLORMAP, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j) { - stuff->cmap = cmap->info[j].id; - result = (* SavedProcVector[X_FreeColors])(client); - } - return (result); -} - - -int PanoramiXStoreColors(ClientPtr client) -{ - int result, j; - PanoramiXRes *cmap; - REQUEST(xStoreColorsReq); - - REQUEST_AT_LEAST_SIZE(xStoreColorsReq); - - client->errorValue = stuff->cmap; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, - XRT_COLORMAP, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j){ - stuff->cmap = cmap->info[j].id; - result = (* SavedProcVector[X_StoreColors])(client); - if(result != Success) break; - } - return (result); -} - - -int PanoramiXStoreNamedColor(ClientPtr client) -{ - int result, j; - PanoramiXRes *cmap; - REQUEST(xStoreNamedColorReq); - - REQUEST_FIXED_SIZE(xStoreNamedColorReq, stuff->nbytes); - - client->errorValue = stuff->cmap; - - result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, - XRT_COLORMAP, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadColor : result; - - FOR_NSCREENS_BACKWARD(j){ - stuff->cmap = cmap->info[j].id; - result = (* SavedProcVector[X_StoreNamedColor])(client); - if(result != Success) break; - } - return (result); -} +/***************************************************************** +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. +******************************************************************/ + +/* Massively rewritten by Mark Vojkovich */ + + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include "windowstr.h" +#include "dixfontstr.h" +#include "gcstruct.h" +#include "colormapst.h" +#include "scrnintstr.h" +#include "opaque.h" +#include "inputstr.h" +#include "migc.h" +#include "misc.h" +#include "dixstruct.h" +#include "panoramiX.h" +#include "panoramiXsrv.h" +#include "resource.h" +#include "panoramiXh.h" + +#define XINERAMA_IMAGE_BUFSIZE (256*1024) +#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \ + CWDontPropagate | CWOverrideRedirect | CWCursor ) + +int PanoramiXCreateWindow(ClientPtr client) +{ + PanoramiXRes *parent, *newWin; + PanoramiXRes *backPix = NULL; + PanoramiXRes *bordPix = NULL; + PanoramiXRes *cmap = NULL; + REQUEST(xCreateWindowReq); + int pback_offset = 0, pbord_offset = 0, cmap_offset = 0; + int result, len, j; + int orig_x, orig_y; + XID orig_visual, tmp; + Bool parentIsRoot; + + REQUEST_AT_LEAST_SIZE(xCreateWindowReq); + + len = client->req_len - bytes_to_int32(sizeof(xCreateWindowReq)); + if (Ones(stuff->mask) != len) + return BadLength; + + result = dixLookupResourceByType((pointer *)&parent, stuff->parent, + XRT_WINDOW, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + if(stuff->class == CopyFromParent) + stuff->class = parent->u.win.class; + + if((stuff->class == InputOnly) && (stuff->mask & (~INPUTONLY_LEGAL_MASK))) + return BadMatch; + + if ((Mask)stuff->mask & CWBackPixmap) { + pback_offset = Ones((Mask)stuff->mask & (CWBackPixmap - 1)); + tmp = *((CARD32 *) &stuff[1] + pback_offset); + if ((tmp != None) && (tmp != ParentRelative)) { + result = dixLookupResourceByType((pointer *)&backPix, tmp, + XRT_PIXMAP, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + if ((Mask)stuff->mask & CWBorderPixmap) { + pbord_offset = Ones((Mask)stuff->mask & (CWBorderPixmap - 1)); + tmp = *((CARD32 *) &stuff[1] + pbord_offset); + if (tmp != CopyFromParent) { + result = dixLookupResourceByType((pointer *)&bordPix, tmp, + XRT_PIXMAP, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + if ((Mask)stuff->mask & CWColormap) { + cmap_offset = Ones((Mask)stuff->mask & (CWColormap - 1)); + tmp = *((CARD32 *) &stuff[1] + cmap_offset); + if ((tmp != CopyFromParent) && (tmp != None)) { + result = dixLookupResourceByType((pointer *)&cmap, tmp, + XRT_COLORMAP, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + } + } + + if(!(newWin = malloc(sizeof(PanoramiXRes)))) + return BadAlloc; + + newWin->type = XRT_WINDOW; + newWin->u.win.visibility = VisibilityNotViewable; + newWin->u.win.class = stuff->class; + newWin->u.win.root = FALSE; + newWin->info[0].id = stuff->wid; + for(j = 1; j < PanoramiXNumScreens; j++) + newWin->info[j].id = FakeClientID(client->index); + + if (stuff->class == InputOnly) + stuff->visual = CopyFromParent; + orig_visual = stuff->visual; + orig_x = stuff->x; + orig_y = stuff->y; + parentIsRoot = (stuff->parent == WindowTable[0]->drawable.id) || + (stuff->parent == savedScreenInfo[0].wid); + FOR_NSCREENS_BACKWARD(j) { + stuff->wid = newWin->info[j].id; + stuff->parent = parent->info[j].id; + if (parentIsRoot) { + stuff->x = orig_x - panoramiXdataPtr[j].x; + stuff->y = orig_y - panoramiXdataPtr[j].y; + } + if (backPix) + *((CARD32 *) &stuff[1] + pback_offset) = backPix->info[j].id; + if (bordPix) + *((CARD32 *) &stuff[1] + pbord_offset) = bordPix->info[j].id; + if (cmap) + *((CARD32 *) &stuff[1] + cmap_offset) = cmap->info[j].id; + if ( orig_visual != CopyFromParent ) + stuff->visual = PanoramiXTranslateVisualID(j, orig_visual); + result = (*SavedProcVector[X_CreateWindow])(client); + if(result != Success) break; + } + + if (result == Success) + AddResource(newWin->info[0].id, XRT_WINDOW, newWin); + else + free(newWin); + + return (result); +} + + +int PanoramiXChangeWindowAttributes(ClientPtr client) +{ + PanoramiXRes *win; + PanoramiXRes *backPix = NULL; + PanoramiXRes *bordPix = NULL; + PanoramiXRes *cmap = NULL; + REQUEST(xChangeWindowAttributesReq); + int pback_offset = 0, pbord_offset = 0, cmap_offset = 0; + int result, len, j; + XID tmp; + + REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq); + + len = client->req_len - bytes_to_int32(sizeof(xChangeWindowAttributesReq)); + if (Ones(stuff->valueMask) != len) + return BadLength; + + result = dixLookupResourceByType((pointer *)&win, stuff->window, + XRT_WINDOW, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + if((win->u.win.class == InputOnly) && + (stuff->valueMask & (~INPUTONLY_LEGAL_MASK))) + return BadMatch; + + if ((Mask)stuff->valueMask & CWBackPixmap) { + pback_offset = Ones((Mask)stuff->valueMask & (CWBackPixmap - 1)); + tmp = *((CARD32 *) &stuff[1] + pback_offset); + if ((tmp != None) && (tmp != ParentRelative)) { + result = dixLookupResourceByType((pointer *)&backPix, tmp, + XRT_PIXMAP, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + if ((Mask)stuff->valueMask & CWBorderPixmap) { + pbord_offset = Ones((Mask)stuff->valueMask & (CWBorderPixmap - 1)); + tmp = *((CARD32 *) &stuff[1] + pbord_offset); + if (tmp != CopyFromParent) { + result = dixLookupResourceByType((pointer *)&bordPix, tmp, + XRT_PIXMAP, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + if ((Mask)stuff->valueMask & CWColormap) { + cmap_offset = Ones((Mask)stuff->valueMask & (CWColormap - 1)); + tmp = *((CARD32 *) &stuff[1] + cmap_offset); + if ((tmp != CopyFromParent) && (tmp != None)) { + result = dixLookupResourceByType((pointer *)&cmap, tmp, + XRT_COLORMAP, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + } + } + + FOR_NSCREENS_BACKWARD(j) { + stuff->window = win->info[j].id; + if (backPix) + *((CARD32 *) &stuff[1] + pback_offset) = backPix->info[j].id; + if (bordPix) + *((CARD32 *) &stuff[1] + pbord_offset) = bordPix->info[j].id; + if (cmap) + *((CARD32 *) &stuff[1] + cmap_offset) = cmap->info[j].id; + result = (*SavedProcVector[X_ChangeWindowAttributes])(client); + } + + return (result); +} + + +int PanoramiXDestroyWindow(ClientPtr client) +{ + PanoramiXRes *win; + int result, j; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->id, XRT_WINDOW, + client, DixDestroyAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->id = win->info[j].id; + result = (*SavedProcVector[X_DestroyWindow])(client); + if(result != Success) break; + } + + /* Since ProcDestroyWindow is using FreeResource, it will free + our resource for us on the last pass through the loop above */ + + return (result); +} + + +int PanoramiXDestroySubwindows(ClientPtr client) +{ + PanoramiXRes *win; + int result, j; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->id, XRT_WINDOW, + client, DixDestroyAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->id = win->info[j].id; + result = (*SavedProcVector[X_DestroySubwindows])(client); + if(result != Success) break; + } + + /* DestroySubwindows is using FreeResource which will free + our resources for us on the last pass through the loop above */ + + return (result); +} + + +int PanoramiXChangeSaveSet(ClientPtr client) +{ + PanoramiXRes *win; + int result, j; + REQUEST(xChangeSaveSetReq); + + REQUEST_SIZE_MATCH(xChangeSaveSetReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->window, + XRT_WINDOW, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->window = win->info[j].id; + result = (*SavedProcVector[X_ChangeSaveSet])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXReparentWindow(ClientPtr client) +{ + PanoramiXRes *win, *parent; + int result, j; + int x, y; + Bool parentIsRoot; + REQUEST(xReparentWindowReq); + + REQUEST_SIZE_MATCH(xReparentWindowReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->window, + XRT_WINDOW, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + result = dixLookupResourceByType((pointer *)&parent, stuff->parent, + XRT_WINDOW, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + x = stuff->x; + y = stuff->y; + parentIsRoot = (stuff->parent == WindowTable[0]->drawable.id) || + (stuff->parent == savedScreenInfo[0].wid); + FOR_NSCREENS_BACKWARD(j) { + stuff->window = win->info[j].id; + stuff->parent = parent->info[j].id; + if(parentIsRoot) { + stuff->x = x - panoramiXdataPtr[j].x; + stuff->y = y - panoramiXdataPtr[j].y; + } + result = (*SavedProcVector[X_ReparentWindow])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXMapWindow(ClientPtr client) +{ + PanoramiXRes *win; + int result, j; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->id, + XRT_WINDOW, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS_FORWARD(j) { + stuff->id = win->info[j].id; + result = (*SavedProcVector[X_MapWindow])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXMapSubwindows(ClientPtr client) +{ + PanoramiXRes *win; + int result, j; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->id, + XRT_WINDOW, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS_FORWARD(j) { + stuff->id = win->info[j].id; + result = (*SavedProcVector[X_MapSubwindows])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXUnmapWindow(ClientPtr client) +{ + PanoramiXRes *win; + int result, j; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->id, + XRT_WINDOW, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS_FORWARD(j) { + stuff->id = win->info[j].id; + result = (*SavedProcVector[X_UnmapWindow])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXUnmapSubwindows(ClientPtr client) +{ + PanoramiXRes *win; + int result, j; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->id, + XRT_WINDOW, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS_FORWARD(j) { + stuff->id = win->info[j].id; + result = (*SavedProcVector[X_UnmapSubwindows])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXConfigureWindow(ClientPtr client) +{ + PanoramiXRes *win; + PanoramiXRes *sib = NULL; + WindowPtr pWin; + int result, j, len, sib_offset = 0, x = 0, y = 0; + int x_offset = -1; + int y_offset = -1; + REQUEST(xConfigureWindowReq); + + REQUEST_AT_LEAST_SIZE(xConfigureWindowReq); + + len = client->req_len - bytes_to_int32(sizeof(xConfigureWindowReq)); + if (Ones(stuff->mask) != len) + return BadLength; + + /* because we need the parent */ + result = dixLookupResourceByType((pointer *)&pWin, stuff->window, + RT_WINDOW, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + result = dixLookupResourceByType((pointer *)&win, stuff->window, + XRT_WINDOW, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + if ((Mask)stuff->mask & CWSibling) { + XID tmp; + sib_offset = Ones((Mask)stuff->mask & (CWSibling - 1)); + if ((tmp = *((CARD32 *) &stuff[1] + sib_offset))) { + result = dixLookupResourceByType((pointer *)&sib, tmp, XRT_WINDOW, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + } + } + + if(pWin->parent && ((pWin->parent == WindowTable[0]) || + (pWin->parent->drawable.id == savedScreenInfo[0].wid))) + { + if ((Mask)stuff->mask & CWX) { + x_offset = 0; + x = *((CARD32 *)&stuff[1]); + } + if ((Mask)stuff->mask & CWY) { + y_offset = (x_offset == -1) ? 0 : 1; + y = *((CARD32 *) &stuff[1] + y_offset); + } + } + + /* have to go forward or you get expose events before + ConfigureNotify events */ + FOR_NSCREENS_FORWARD(j) { + stuff->window = win->info[j].id; + if(sib) + *((CARD32 *) &stuff[1] + sib_offset) = sib->info[j].id; + if(x_offset >= 0) + *((CARD32 *) &stuff[1] + x_offset) = x - panoramiXdataPtr[j].x; + if(y_offset >= 0) + *((CARD32 *) &stuff[1] + y_offset) = y - panoramiXdataPtr[j].y; + result = (*SavedProcVector[X_ConfigureWindow])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXCirculateWindow(ClientPtr client) +{ + PanoramiXRes *win; + int result, j; + REQUEST(xCirculateWindowReq); + + REQUEST_SIZE_MATCH(xCirculateWindowReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->window, + XRT_WINDOW, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS_FORWARD(j) { + stuff->window = win->info[j].id; + result = (*SavedProcVector[X_CirculateWindow])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXGetGeometry(ClientPtr client) +{ + xGetGeometryReply rep; + DrawablePtr pDraw; + int rc; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupDrawable(&pDraw, stuff->id, client, M_ANY, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.root = WindowTable[0]->drawable.id; + rep.depth = pDraw->depth; + rep.width = pDraw->width; + rep.height = pDraw->height; + rep.x = rep.y = rep.borderWidth = 0; + + if (stuff->id == rep.root) { + xWindowRoot *root = (xWindowRoot *) + (ConnectionInfo + connBlockScreenStart); + + rep.width = root->pixWidth; + rep.height = root->pixHeight; + } else + if ((pDraw->type == UNDRAWABLE_WINDOW) || (pDraw->type == DRAWABLE_WINDOW)) + { + WindowPtr pWin = (WindowPtr)pDraw; + rep.x = pWin->origin.x - wBorderWidth (pWin); + rep.y = pWin->origin.y - wBorderWidth (pWin); + if((pWin->parent == WindowTable[0]) || + (pWin->parent->drawable.id == savedScreenInfo[0].wid)) + { + rep.x += panoramiXdataPtr[0].x; + rep.y += panoramiXdataPtr[0].y; + } + rep.borderWidth = pWin->borderWidth; + } + + WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep); + return Success; +} + +int PanoramiXTranslateCoords(ClientPtr client) +{ + INT16 x, y; + REQUEST(xTranslateCoordsReq); + int rc; + WindowPtr pWin, pDst; + xTranslateCoordsReply rep; + + REQUEST_SIZE_MATCH(xTranslateCoordsReq); + rc = dixLookupWindow(&pWin, stuff->srcWid, client, DixReadAccess); + if (rc != Success) + return rc; + rc = dixLookupWindow(&pDst, stuff->dstWid, client, DixReadAccess); + if (rc != Success) + return rc; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.sameScreen = xTrue; + rep.child = None; + + if((pWin == WindowTable[0]) || + (pWin->drawable.id == savedScreenInfo[0].wid)) + { + x = stuff->srcX - panoramiXdataPtr[0].x; + y = stuff->srcY - panoramiXdataPtr[0].y; + } else { + 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->drawable.pScreen, + wBoundingShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box)) + ) + { + rep.child = pWin->drawable.id; + pWin = (WindowPtr) NULL; + } + else + pWin = pWin->nextSib; + } + rep.dstX = x - pDst->drawable.x; + rep.dstY = y - pDst->drawable.y; + if((pDst == WindowTable[0]) || + (pDst->drawable.id == savedScreenInfo[0].wid)) + { + rep.dstX += panoramiXdataPtr[0].x; + rep.dstY += panoramiXdataPtr[0].y; + } + + WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep); + return Success; +} + +int PanoramiXCreatePixmap(ClientPtr client) +{ + PanoramiXRes *refDraw, *newPix; + int result, j; + REQUEST(xCreatePixmapReq); + + REQUEST_SIZE_MATCH(xCreatePixmapReq); + client->errorValue = stuff->pid; + + result = dixLookupResourceByClass((pointer *)&refDraw, stuff->drawable, + XRC_DRAWABLE, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(!(newPix = malloc(sizeof(PanoramiXRes)))) + return BadAlloc; + + newPix->type = XRT_PIXMAP; + newPix->u.pix.shared = FALSE; + newPix->info[0].id = stuff->pid; + for(j = 1; j < PanoramiXNumScreens; j++) + newPix->info[j].id = FakeClientID(client->index); + + FOR_NSCREENS_BACKWARD(j) { + stuff->pid = newPix->info[j].id; + stuff->drawable = refDraw->info[j].id; + result = (*SavedProcVector[X_CreatePixmap])(client); + if(result != Success) break; + } + + if (result == Success) + AddResource(newPix->info[0].id, XRT_PIXMAP, newPix); + else + free(newPix); + + return (result); +} + + +int PanoramiXFreePixmap(ClientPtr client) +{ + PanoramiXRes *pix; + int result, j; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + + client->errorValue = stuff->id; + + result = dixLookupResourceByType((pointer *)&pix, stuff->id, XRT_PIXMAP, + client, DixDestroyAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->id = pix->info[j].id; + result = (*SavedProcVector[X_FreePixmap])(client); + if(result != Success) break; + } + + /* Since ProcFreePixmap is using FreeResource, it will free + our resource for us on the last pass through the loop above */ + + return (result); +} + + +int PanoramiXCreateGC(ClientPtr client) +{ + PanoramiXRes *refDraw; + PanoramiXRes *newGC; + PanoramiXRes *stip = NULL; + PanoramiXRes *tile = NULL; + PanoramiXRes *clip = NULL; + REQUEST(xCreateGCReq); + int tile_offset = 0, stip_offset = 0, clip_offset = 0; + int result, len, j; + XID tmp; + + REQUEST_AT_LEAST_SIZE(xCreateGCReq); + + client->errorValue = stuff->gc; + len = client->req_len - bytes_to_int32(sizeof(xCreateGCReq)); + if (Ones(stuff->mask) != len) + return BadLength; + + result = dixLookupResourceByClass((pointer *)&refDraw, stuff->drawable, + XRC_DRAWABLE, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if ((Mask)stuff->mask & GCTile) { + tile_offset = Ones((Mask)stuff->mask & (GCTile - 1)); + if ((tmp = *((CARD32 *) &stuff[1] + tile_offset))) { + result = dixLookupResourceByType((pointer *)&tile, tmp, XRT_PIXMAP, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + if ((Mask)stuff->mask & GCStipple) { + stip_offset = Ones((Mask)stuff->mask & (GCStipple - 1)); + if ((tmp = *((CARD32 *) &stuff[1] + stip_offset))) { + result = dixLookupResourceByType((pointer *)&stip, tmp, XRT_PIXMAP, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + if ((Mask)stuff->mask & GCClipMask) { + clip_offset = Ones((Mask)stuff->mask & (GCClipMask - 1)); + if ((tmp = *((CARD32 *) &stuff[1] + clip_offset))) { + result = dixLookupResourceByType((pointer *)&clip, tmp, XRT_PIXMAP, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + + if(!(newGC = malloc(sizeof(PanoramiXRes)))) + return BadAlloc; + + newGC->type = XRT_GC; + newGC->info[0].id = stuff->gc; + for(j = 1; j < PanoramiXNumScreens; j++) + newGC->info[j].id = FakeClientID(client->index); + + FOR_NSCREENS_BACKWARD(j) { + stuff->gc = newGC->info[j].id; + stuff->drawable = refDraw->info[j].id; + if (tile) + *((CARD32 *) &stuff[1] + tile_offset) = tile->info[j].id; + if (stip) + *((CARD32 *) &stuff[1] + stip_offset) = stip->info[j].id; + if (clip) + *((CARD32 *) &stuff[1] + clip_offset) = clip->info[j].id; + result = (*SavedProcVector[X_CreateGC])(client); + if(result != Success) break; + } + + if (result == Success) + AddResource(newGC->info[0].id, XRT_GC, newGC); + else + free(newGC); + + return (result); +} + +int PanoramiXChangeGC(ClientPtr client) +{ + PanoramiXRes *gc; + PanoramiXRes *stip = NULL; + PanoramiXRes *tile = NULL; + PanoramiXRes *clip = NULL; + REQUEST(xChangeGCReq); + int tile_offset = 0, stip_offset = 0, clip_offset = 0; + int result, len, j; + XID tmp; + + REQUEST_AT_LEAST_SIZE(xChangeGCReq); + + len = client->req_len - bytes_to_int32(sizeof(xChangeGCReq)); + if (Ones(stuff->mask) != len) + return BadLength; + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + if ((Mask)stuff->mask & GCTile) { + tile_offset = Ones((Mask)stuff->mask & (GCTile - 1)); + if ((tmp = *((CARD32 *) &stuff[1] + tile_offset))) { + result = dixLookupResourceByType((pointer *)&tile, tmp, XRT_PIXMAP, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + if ((Mask)stuff->mask & GCStipple) { + stip_offset = Ones((Mask)stuff->mask & (GCStipple - 1)); + if ((tmp = *((CARD32 *) &stuff[1] + stip_offset))) { + result = dixLookupResourceByType((pointer *)&stip, tmp, XRT_PIXMAP, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + if ((Mask)stuff->mask & GCClipMask) { + clip_offset = Ones((Mask)stuff->mask & (GCClipMask - 1)); + if ((tmp = *((CARD32 *) &stuff[1] + clip_offset))) { + result = dixLookupResourceByType((pointer *)&clip, tmp, XRT_PIXMAP, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } + } + + + FOR_NSCREENS_BACKWARD(j) { + stuff->gc = gc->info[j].id; + if (tile) + *((CARD32 *) &stuff[1] + tile_offset) = tile->info[j].id; + if (stip) + *((CARD32 *) &stuff[1] + stip_offset) = stip->info[j].id; + if (clip) + *((CARD32 *) &stuff[1] + clip_offset) = clip->info[j].id; + result = (*SavedProcVector[X_ChangeGC])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXCopyGC(ClientPtr client) +{ + PanoramiXRes *srcGC, *dstGC; + int result, j; + REQUEST(xCopyGCReq); + + REQUEST_SIZE_MATCH(xCopyGCReq); + + result = dixLookupResourceByType((pointer *)&srcGC, stuff->srcGC, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + result = dixLookupResourceByType((pointer *)&dstGC, stuff->dstGC, XRT_GC, + client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + FOR_NSCREENS(j) { + stuff->srcGC = srcGC->info[j].id; + stuff->dstGC = dstGC->info[j].id; + result = (*SavedProcVector[X_CopyGC])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXSetDashes(ClientPtr client) +{ + PanoramiXRes *gc; + int result, j; + REQUEST(xSetDashesReq); + + REQUEST_FIXED_SIZE(xSetDashesReq, stuff->nDashes); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->gc = gc->info[j].id; + result = (*SavedProcVector[X_SetDashes])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXSetClipRectangles(ClientPtr client) +{ + PanoramiXRes *gc; + int result, j; + REQUEST(xSetClipRectanglesReq); + + REQUEST_AT_LEAST_SIZE(xSetClipRectanglesReq); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->gc = gc->info[j].id; + result = (*SavedProcVector[X_SetClipRectangles])(client); + if(result != Success) break; + } + + return (result); +} + + +int PanoramiXFreeGC(ClientPtr client) +{ + PanoramiXRes *gc; + int result, j; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + + result = dixLookupResourceByType((pointer *)&gc, stuff->id, XRT_GC, + client, DixDestroyAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->id = gc->info[j].id; + result = (*SavedProcVector[X_FreeGC])(client); + if(result != Success) break; + } + + /* Since ProcFreeGC is using FreeResource, it will free + our resource for us on the last pass through the loop above */ + + return (result); +} + + +int PanoramiXClearToBackground(ClientPtr client) +{ + PanoramiXRes *win; + int result, j, x, y; + Bool isRoot; + REQUEST(xClearAreaReq); + + REQUEST_SIZE_MATCH(xClearAreaReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->window, + XRT_WINDOW, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + x = stuff->x; + y = stuff->y; + isRoot = win->u.win.root; + FOR_NSCREENS_BACKWARD(j) { + stuff->window = win->info[j].id; + if(isRoot) { + stuff->x = x - panoramiXdataPtr[j].x; + stuff->y = y - panoramiXdataPtr[j].y; + } + result = (*SavedProcVector[X_ClearArea])(client); + if(result != Success) break; + } + + return (result); +} + + +/* + For Window to Pixmap copies you're screwed since each screen's + pixmap will look like what it sees on its screen. Unless the + screens overlap and the window lies on each, the two copies + will be out of sync. To remedy this we do a GetImage and PutImage + in place of the copy. Doing this as a single Image isn't quite + correct since it will include the obscured areas but we will + have to fix this later. (MArk). +*/ + +int PanoramiXCopyArea(ClientPtr client) +{ + int j, result, srcx, srcy, dstx, dsty; + PanoramiXRes *gc, *src, *dst; + Bool srcIsRoot = FALSE; + Bool dstIsRoot = FALSE; + Bool srcShared, dstShared; + REQUEST(xCopyAreaReq); + + REQUEST_SIZE_MATCH(xCopyAreaReq); + + result = dixLookupResourceByClass((pointer *)&src, stuff->srcDrawable, + XRC_DRAWABLE, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + srcShared = IS_SHARED_PIXMAP(src); + + result = dixLookupResourceByClass((pointer *)&dst, stuff->dstDrawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + dstShared = IS_SHARED_PIXMAP(dst); + + if(dstShared && srcShared) + return (* SavedProcVector[X_CopyArea])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + if((dst->type == XRT_WINDOW) && dst->u.win.root) + dstIsRoot = TRUE; + if((src->type == XRT_WINDOW) && src->u.win.root) + srcIsRoot = TRUE; + + srcx = stuff->srcX; srcy = stuff->srcY; + dstx = stuff->dstX; dsty = stuff->dstY; + if((dst->type == XRT_PIXMAP) && (src->type == XRT_WINDOW)) { + DrawablePtr drawables[MAXSCREENS]; + DrawablePtr pDst; + GCPtr pGC; + char *data; + int pitch, rc; + + FOR_NSCREENS(j) { + rc = dixLookupDrawable(drawables+j, src->info[j].id, client, 0, + DixGetAttrAccess); + if (rc != Success) + return rc; + } + + pitch = PixmapBytePad(stuff->width, drawables[0]->depth); + if(!(data = calloc(1, stuff->height * pitch))) + return BadAlloc; + + XineramaGetImageData(drawables, srcx, srcy, + stuff->width, stuff->height, ZPixmap, ~0, data, pitch, + srcIsRoot); + + FOR_NSCREENS_BACKWARD(j) { + stuff->gc = gc->info[j].id; + VALIDATE_DRAWABLE_AND_GC(dst->info[j].id, pDst, DixWriteAccess); + if(drawables[0]->depth != pDst->depth) { + client->errorValue = stuff->dstDrawable; + free(data); + return (BadMatch); + } + + (*pGC->ops->PutImage) (pDst, pGC, pDst->depth, dstx, dsty, + stuff->width, stuff->height, + 0, ZPixmap, data); + + if(dstShared) break; + } + + free(data); + } else { + DrawablePtr pDst = NULL, pSrc = NULL; + GCPtr pGC = NULL; + RegionPtr pRgn[MAXSCREENS]; + int rc; + + FOR_NSCREENS_BACKWARD(j) { + stuff->dstDrawable = dst->info[j].id; + stuff->srcDrawable = src->info[j].id; + stuff->gc = gc->info[j].id; + if (srcIsRoot) { + stuff->srcX = srcx - panoramiXdataPtr[j].x; + stuff->srcY = srcy - panoramiXdataPtr[j].y; + } + if (dstIsRoot) { + stuff->dstX = dstx - panoramiXdataPtr[j].x; + stuff->dstY = dsty - panoramiXdataPtr[j].y; + } + + VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, DixWriteAccess); + + if (stuff->dstDrawable != stuff->srcDrawable) { + rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + if ((pDst->pScreen != pSrc->pScreen) || + (pDst->depth != pSrc->depth)) { + client->errorValue = stuff->dstDrawable; + return (BadMatch); + } + } else + pSrc = pDst; + + pRgn[j] = (*pGC->ops->CopyArea)(pSrc, pDst, pGC, + stuff->srcX, stuff->srcY, + stuff->width, stuff->height, + stuff->dstX, stuff->dstY); + + if(dstShared) { + while(j--) pRgn[j] = NULL; + break; + } + } + + if(pGC->graphicsExposures) { + ScreenPtr pScreen = pDst->pScreen; + RegionRec totalReg; + Bool overlap; + + REGION_NULL(pScreen, &totalReg); + FOR_NSCREENS_BACKWARD(j) { + if(pRgn[j]) { + if(srcIsRoot) { + REGION_TRANSLATE(pScreen, pRgn[j], + panoramiXdataPtr[j].x, panoramiXdataPtr[j].y); + } + REGION_APPEND(pScreen, &totalReg, pRgn[j]); + REGION_DESTROY(pScreen, pRgn[j]); + } + } + REGION_VALIDATE(pScreen, &totalReg, &overlap); + (*pScreen->SendGraphicsExpose)( + client, &totalReg, stuff->dstDrawable, X_CopyArea, 0); + REGION_UNINIT(pScreen, &totalReg); + } + } + + return Success; +} + + +int PanoramiXCopyPlane(ClientPtr client) +{ + int j, srcx, srcy, dstx, dsty, rc; + PanoramiXRes *gc, *src, *dst; + Bool srcIsRoot = FALSE; + Bool dstIsRoot = FALSE; + Bool srcShared, dstShared; + DrawablePtr psrcDraw, pdstDraw = NULL; + GCPtr pGC = NULL; + RegionPtr pRgn[MAXSCREENS]; + REQUEST(xCopyPlaneReq); + + REQUEST_SIZE_MATCH(xCopyPlaneReq); + + rc = dixLookupResourceByClass((pointer *)&src, stuff->srcDrawable, + XRC_DRAWABLE, client, DixReadAccess); + if (rc != Success) + return (rc == BadValue) ? BadDrawable : rc; + + srcShared = IS_SHARED_PIXMAP(src); + + rc = dixLookupResourceByClass((pointer *)&dst, stuff->dstDrawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (rc != Success) + return (rc == BadValue) ? BadDrawable : rc; + + dstShared = IS_SHARED_PIXMAP(dst); + + if(dstShared && srcShared) + return (* SavedProcVector[X_CopyPlane])(client); + + rc = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (rc != Success) + return (rc == BadValue) ? BadGC : rc; + + if((dst->type == XRT_WINDOW) && dst->u.win.root) + dstIsRoot = TRUE; + if((src->type == XRT_WINDOW) && src->u.win.root) + srcIsRoot = TRUE; + + srcx = stuff->srcX; srcy = stuff->srcY; + dstx = stuff->dstX; dsty = stuff->dstY; + + FOR_NSCREENS_BACKWARD(j) { + stuff->dstDrawable = dst->info[j].id; + stuff->srcDrawable = src->info[j].id; + stuff->gc = gc->info[j].id; + if (srcIsRoot) { + stuff->srcX = srcx - panoramiXdataPtr[j].x; + stuff->srcY = srcy - panoramiXdataPtr[j].y; + } + if (dstIsRoot) { + stuff->dstX = dstx - panoramiXdataPtr[j].x; + stuff->dstY = dsty - panoramiXdataPtr[j].y; + } + + VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pdstDraw, DixWriteAccess); + if (stuff->dstDrawable != stuff->srcDrawable) { + rc = dixLookupDrawable(&psrcDraw, stuff->srcDrawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + if (pdstDraw->pScreen != psrcDraw->pScreen) { + client->errorValue = stuff->dstDrawable; + return (BadMatch); + } + } else + psrcDraw = pdstDraw; + + if(stuff->bitPlane == 0 || (stuff->bitPlane & (stuff->bitPlane - 1)) || + (stuff->bitPlane > (1L << (psrcDraw->depth - 1)))) { + client->errorValue = stuff->bitPlane; + return(BadValue); + } + + pRgn[j] = (*pGC->ops->CopyPlane)(psrcDraw, pdstDraw, pGC, + stuff->srcX, stuff->srcY, + stuff->width, stuff->height, + stuff->dstX, stuff->dstY, stuff->bitPlane); + + if(dstShared) { + while(j--) pRgn[j] = NULL; + break; + } + } + + if(pGC->graphicsExposures) { + ScreenPtr pScreen = pdstDraw->pScreen; + RegionRec totalReg; + Bool overlap; + + REGION_NULL(pScreen, &totalReg); + FOR_NSCREENS_BACKWARD(j) { + if(pRgn[j]) { + REGION_APPEND(pScreen, &totalReg, pRgn[j]); + REGION_DESTROY(pScreen, pRgn[j]); + } + } + REGION_VALIDATE(pScreen, &totalReg, &overlap); + (*pScreen->SendGraphicsExpose)( + client, &totalReg, stuff->dstDrawable, X_CopyPlane, 0); + REGION_UNINIT(pScreen, &totalReg); + } + + return Success; +} + + +int PanoramiXPolyPoint(ClientPtr client) +{ + PanoramiXRes *gc, *draw; + int result, npoint, j; + xPoint *origPts; + Bool isRoot; + REQUEST(xPolyPointReq); + + REQUEST_AT_LEAST_SIZE(xPolyPointReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PolyPoint])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyPointReq)); + if (npoint > 0) { + origPts = malloc(npoint * sizeof(xPoint)); + memcpy((char *) origPts, (char *) &stuff[1], npoint * sizeof(xPoint)); + FOR_NSCREENS_FORWARD(j){ + + if(j) memcpy(&stuff[1], origPts, npoint * sizeof(xPoint)); + + if (isRoot) { + int x_off = panoramiXdataPtr[j].x; + int y_off = panoramiXdataPtr[j].y; + + if(x_off || y_off) { + xPoint *pnts = (xPoint*)&stuff[1]; + int i = (stuff->coordMode==CoordModePrevious) ? 1 : npoint; + + while(i--) { + pnts->x -= x_off; + pnts->y -= y_off; + pnts++; + } + } + } + + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + result = (* SavedProcVector[X_PolyPoint])(client); + if(result != Success) break; + } + free(origPts); + return (result); + } else + return Success; +} + + +int PanoramiXPolyLine(ClientPtr client) +{ + PanoramiXRes *gc, *draw; + int result, npoint, j; + xPoint *origPts; + Bool isRoot; + REQUEST(xPolyLineReq); + + REQUEST_AT_LEAST_SIZE(xPolyLineReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PolyLine])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyLineReq)); + if (npoint > 0){ + origPts = malloc(npoint * sizeof(xPoint)); + memcpy((char *) origPts, (char *) &stuff[1], npoint * sizeof(xPoint)); + FOR_NSCREENS_FORWARD(j){ + + if(j) memcpy(&stuff[1], origPts, npoint * sizeof(xPoint)); + + if (isRoot) { + int x_off = panoramiXdataPtr[j].x; + int y_off = panoramiXdataPtr[j].y; + + if(x_off || y_off) { + xPoint *pnts = (xPoint*)&stuff[1]; + int i = (stuff->coordMode==CoordModePrevious) ? 1 : npoint; + + while(i--) { + pnts->x -= x_off; + pnts->y -= y_off; + pnts++; + } + } + } + + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + result = (* SavedProcVector[X_PolyLine])(client); + if(result != Success) break; + } + free(origPts); + return (result); + } else + return Success; +} + + +int PanoramiXPolySegment(ClientPtr client) +{ + int result, nsegs, i, j; + PanoramiXRes *gc, *draw; + xSegment *origSegs; + Bool isRoot; + REQUEST(xPolySegmentReq); + + REQUEST_AT_LEAST_SIZE(xPolySegmentReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PolySegment])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + nsegs = (client->req_len << 2) - sizeof(xPolySegmentReq); + if(nsegs & 4) return BadLength; + nsegs >>= 3; + if (nsegs > 0) { + origSegs = malloc(nsegs * sizeof(xSegment)); + memcpy((char *) origSegs, (char *) &stuff[1], nsegs * sizeof(xSegment)); + FOR_NSCREENS_FORWARD(j){ + + if(j) memcpy(&stuff[1], origSegs, nsegs * sizeof(xSegment)); + + if (isRoot) { + int x_off = panoramiXdataPtr[j].x; + int y_off = panoramiXdataPtr[j].y; + + if(x_off || y_off) { + xSegment *segs = (xSegment*)&stuff[1]; + + for (i = nsegs; i--; segs++) { + segs->x1 -= x_off; + segs->x2 -= x_off; + segs->y1 -= y_off; + segs->y2 -= y_off; + } + } + } + + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + result = (* SavedProcVector[X_PolySegment])(client); + if(result != Success) break; + } + free(origSegs); + return (result); + } else + return Success; +} + + +int PanoramiXPolyRectangle(ClientPtr client) +{ + int result, nrects, i, j; + PanoramiXRes *gc, *draw; + Bool isRoot; + xRectangle *origRecs; + REQUEST(xPolyRectangleReq); + + REQUEST_AT_LEAST_SIZE(xPolyRectangleReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PolyRectangle])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + nrects = (client->req_len << 2) - sizeof(xPolyRectangleReq); + if(nrects & 4) return BadLength; + nrects >>= 3; + if (nrects > 0){ + origRecs = malloc(nrects * sizeof(xRectangle)); + memcpy((char *)origRecs,(char *)&stuff[1],nrects * sizeof(xRectangle)); + FOR_NSCREENS_FORWARD(j){ + + if(j) memcpy(&stuff[1], origRecs, nrects * sizeof(xRectangle)); + + if (isRoot) { + int x_off = panoramiXdataPtr[j].x; + int y_off = panoramiXdataPtr[j].y; + + + if(x_off || y_off) { + xRectangle *rects = (xRectangle *) &stuff[1]; + + for (i = nrects; i--; rects++) { + rects->x -= x_off; + rects->y -= y_off; + } + } + } + + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + result = (* SavedProcVector[X_PolyRectangle])(client); + if(result != Success) break; + } + free(origRecs); + return (result); + } else + return Success; +} + + +int PanoramiXPolyArc(ClientPtr client) +{ + int result, narcs, i, j; + PanoramiXRes *gc, *draw; + Bool isRoot; + xArc *origArcs; + REQUEST(xPolyArcReq); + + REQUEST_AT_LEAST_SIZE(xPolyArcReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PolyArc])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + narcs = (client->req_len << 2) - sizeof(xPolyArcReq); + if(narcs % sizeof(xArc)) return BadLength; + narcs /= sizeof(xArc); + if (narcs > 0){ + origArcs = malloc(narcs * sizeof(xArc)); + memcpy((char *) origArcs, (char *) &stuff[1], narcs * sizeof(xArc)); + FOR_NSCREENS_FORWARD(j){ + + if(j) memcpy(&stuff[1], origArcs, narcs * sizeof(xArc)); + + if (isRoot) { + int x_off = panoramiXdataPtr[j].x; + int y_off = panoramiXdataPtr[j].y; + + if(x_off || y_off) { + xArc *arcs = (xArc *) &stuff[1]; + + for (i = narcs; i--; arcs++) { + arcs->x -= x_off; + arcs->y -= y_off; + } + } + } + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + result = (* SavedProcVector[X_PolyArc])(client); + if(result != Success) break; + } + free(origArcs); + return (result); + } else + return Success; +} + + +int PanoramiXFillPoly(ClientPtr client) +{ + int result, count, j; + PanoramiXRes *gc, *draw; + Bool isRoot; + DDXPointPtr locPts; + REQUEST(xFillPolyReq); + + REQUEST_AT_LEAST_SIZE(xFillPolyReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_FillPoly])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + count = bytes_to_int32((client->req_len << 2) - sizeof(xFillPolyReq)); + if (count > 0){ + locPts = malloc(count * sizeof(DDXPointRec)); + memcpy((char *)locPts, (char *)&stuff[1], count * sizeof(DDXPointRec)); + FOR_NSCREENS_FORWARD(j){ + + if(j) memcpy(&stuff[1], locPts, count * sizeof(DDXPointRec)); + + if (isRoot) { + int x_off = panoramiXdataPtr[j].x; + int y_off = panoramiXdataPtr[j].y; + + if(x_off || y_off) { + DDXPointPtr pnts = (DDXPointPtr)&stuff[1]; + int i = (stuff->coordMode==CoordModePrevious) ? 1 : count; + + while(i--) { + pnts->x -= x_off; + pnts->y -= y_off; + pnts++; + } + } + } + + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + result = (* SavedProcVector[X_FillPoly])(client); + if(result != Success) break; + } + free(locPts); + return (result); + } else + return Success; +} + + +int PanoramiXPolyFillRectangle(ClientPtr client) +{ + int result, things, i, j; + PanoramiXRes *gc, *draw; + Bool isRoot; + xRectangle *origRects; + REQUEST(xPolyFillRectangleReq); + + REQUEST_AT_LEAST_SIZE(xPolyFillRectangleReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PolyFillRectangle])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + things = (client->req_len << 2) - sizeof(xPolyFillRectangleReq); + if(things & 4) return BadLength; + things >>= 3; + if (things > 0){ + origRects = malloc(things * sizeof(xRectangle)); + memcpy((char*)origRects,(char*)&stuff[1], things * sizeof(xRectangle)); + FOR_NSCREENS_FORWARD(j){ + + if(j) memcpy(&stuff[1], origRects, things * sizeof(xRectangle)); + + if (isRoot) { + int x_off = panoramiXdataPtr[j].x; + int y_off = panoramiXdataPtr[j].y; + + if(x_off || y_off) { + xRectangle *rects = (xRectangle *) &stuff[1]; + + for (i = things; i--; rects++) { + rects->x -= x_off; + rects->y -= y_off; + } + } + } + + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + result = (* SavedProcVector[X_PolyFillRectangle])(client); + if(result != Success) break; + } + free(origRects); + return (result); + } else + return Success; +} + + +int PanoramiXPolyFillArc(ClientPtr client) +{ + PanoramiXRes *gc, *draw; + Bool isRoot; + int result, narcs, i, j; + xArc *origArcs; + REQUEST(xPolyFillArcReq); + + REQUEST_AT_LEAST_SIZE(xPolyFillArcReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PolyFillArc])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + narcs = (client->req_len << 2) - sizeof(xPolyFillArcReq); + if (narcs % sizeof(xArc)) return BadLength; + narcs /= sizeof(xArc); + if (narcs > 0) { + origArcs = malloc(narcs * sizeof(xArc)); + memcpy((char *) origArcs, (char *)&stuff[1], narcs * sizeof(xArc)); + FOR_NSCREENS_FORWARD(j){ + + if(j) memcpy(&stuff[1], origArcs, narcs * sizeof(xArc)); + + if (isRoot) { + int x_off = panoramiXdataPtr[j].x; + int y_off = panoramiXdataPtr[j].y; + + if(x_off || y_off) { + xArc *arcs = (xArc *) &stuff[1]; + + for (i = narcs; i--; arcs++) { + arcs->x -= x_off; + arcs->y -= y_off; + } + } + } + + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + result = (* SavedProcVector[X_PolyFillArc])(client); + if(result != Success) break; + } + free(origArcs); + return (result); + } else + return Success; +} + + +int PanoramiXPutImage(ClientPtr client) +{ + PanoramiXRes *gc, *draw; + Bool isRoot; + int j, result, orig_x, orig_y; + REQUEST(xPutImageReq); + + REQUEST_AT_LEAST_SIZE(xPutImageReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PutImage])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + orig_x = stuff->dstX; + orig_y = stuff->dstY; + FOR_NSCREENS_BACKWARD(j){ + if (isRoot) { + stuff->dstX = orig_x - panoramiXdataPtr[j].x; + stuff->dstY = orig_y - panoramiXdataPtr[j].y; + } + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + result = (* SavedProcVector[X_PutImage])(client); + if(result != Success) break; + } + return (result); +} + + +int PanoramiXGetImage(ClientPtr client) +{ + DrawablePtr drawables[MAXSCREENS]; + DrawablePtr pDraw; + PanoramiXRes *draw; + xGetImageReply xgi; + Bool isRoot; + char *pBuf; + int i, x, y, w, h, format, rc; + Mask plane = 0, planemask; + int linesDone, nlines, linesPerBuf; + long widthBytesLine, length; + + REQUEST(xGetImageReq); + + REQUEST_SIZE_MATCH(xGetImageReq); + + if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) { + client->errorValue = stuff->format; + return(BadValue); + } + + rc = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (rc != Success) + return (rc == BadValue) ? BadDrawable : rc; + + if(draw->type == XRT_PIXMAP) + return (*SavedProcVector[X_GetImage])(client); + + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + if(!((WindowPtr)pDraw)->realized) + return(BadMatch); + + x = stuff->x; + y = stuff->y; + w = stuff->width; + h = stuff->height; + format = stuff->format; + planemask = stuff->planeMask; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + if(isRoot) { + if( /* check for being onscreen */ + x < 0 || x + w > PanoramiXPixWidth || + y < 0 || y + h > PanoramiXPixHeight ) + return(BadMatch); + } else { + if( /* check for being onscreen */ + panoramiXdataPtr[0].x + pDraw->x + x < 0 || + panoramiXdataPtr[0].x + pDraw->x + x + w > PanoramiXPixWidth || + panoramiXdataPtr[0].y + pDraw->y + y < 0 || + panoramiXdataPtr[0].y + pDraw->y + y + h > PanoramiXPixHeight || + /* check for being inside of border */ + x < - wBorderWidth((WindowPtr)pDraw) || + x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || + y < -wBorderWidth((WindowPtr)pDraw) || + y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height) + return(BadMatch); + } + + drawables[0] = pDraw; + for(i = 1; i < PanoramiXNumScreens; i++) { + rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0, + DixGetAttrAccess); + if (rc != Success) + return rc; + } + + xgi.visual = wVisual (((WindowPtr) pDraw)); + xgi.type = X_Reply; + xgi.sequenceNumber = client->sequence; + xgi.depth = pDraw->depth; + if(format == ZPixmap) { + widthBytesLine = PixmapBytePad(w, pDraw->depth); + length = widthBytesLine * h; + + + } else { + widthBytesLine = BitmapBytePad(w); + plane = ((Mask)1) << (pDraw->depth - 1); + /* only planes asked for */ + length = widthBytesLine * h * + Ones(planemask & (plane | (plane - 1))); + + } + + xgi.length = bytes_to_int32(length); + + if (widthBytesLine == 0 || h == 0) + linesPerBuf = 0; + else if (widthBytesLine >= XINERAMA_IMAGE_BUFSIZE) + linesPerBuf = 1; + else { + linesPerBuf = XINERAMA_IMAGE_BUFSIZE / widthBytesLine; + if (linesPerBuf > h) + linesPerBuf = h; + } + length = linesPerBuf * widthBytesLine; + if(!(pBuf = malloc(length))) + return (BadAlloc); + + WriteReplyToClient(client, sizeof (xGetImageReply), &xgi); + + if (linesPerBuf == 0) { + /* nothing to do */ + } + else if (format == ZPixmap) { + linesDone = 0; + while (h - linesDone > 0) { + nlines = min(linesPerBuf, h - linesDone); + + if(pDraw->depth == 1) + bzero(pBuf, nlines * widthBytesLine); + + XineramaGetImageData(drawables, x, y + linesDone, w, nlines, + format, planemask, pBuf, widthBytesLine, isRoot); + + (void)WriteToClient(client, + (int)(nlines * widthBytesLine), + pBuf); + linesDone += nlines; + } + } else { /* XYPixmap */ + for (; plane; plane >>= 1) { + if (planemask & plane) { + linesDone = 0; + while (h - linesDone > 0) { + nlines = min(linesPerBuf, h - linesDone); + + bzero(pBuf, nlines * widthBytesLine); + + XineramaGetImageData(drawables, x, y + linesDone, w, + nlines, format, plane, pBuf, + widthBytesLine, isRoot); + + (void)WriteToClient(client, + (int)(nlines * widthBytesLine), + pBuf); + + linesDone += nlines; + } + } + } + } + free(pBuf); + return Success; +} + + +/* The text stuff should be rewritten so that duplication happens + at the GlyphBlt level. That is, loading the font and getting + the glyphs should only happen once */ + +int +PanoramiXPolyText8(ClientPtr client) +{ + PanoramiXRes *gc, *draw; + Bool isRoot; + int result, j; + int orig_x, orig_y; + REQUEST(xPolyTextReq); + + REQUEST_AT_LEAST_SIZE(xPolyTextReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PolyText8])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + orig_x = stuff->x; + orig_y = stuff->y; + FOR_NSCREENS_BACKWARD(j){ + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + if (isRoot) { + stuff->x = orig_x - panoramiXdataPtr[j].x; + stuff->y = orig_y - panoramiXdataPtr[j].y; + } + result = (*SavedProcVector[X_PolyText8])(client); + if(result != Success) break; + } + return (result); +} + +int +PanoramiXPolyText16(ClientPtr client) +{ + PanoramiXRes *gc, *draw; + Bool isRoot; + int result, j; + int orig_x, orig_y; + REQUEST(xPolyTextReq); + + REQUEST_AT_LEAST_SIZE(xPolyTextReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_PolyText16])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + orig_x = stuff->x; + orig_y = stuff->y; + FOR_NSCREENS_BACKWARD(j){ + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + if (isRoot) { + stuff->x = orig_x - panoramiXdataPtr[j].x; + stuff->y = orig_y - panoramiXdataPtr[j].y; + } + result = (*SavedProcVector[X_PolyText16])(client); + if(result != Success) break; + } + return (result); +} + + +int PanoramiXImageText8(ClientPtr client) +{ + int result, j; + PanoramiXRes *gc, *draw; + Bool isRoot; + int orig_x, orig_y; + REQUEST(xImageTextReq); + + REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_ImageText8])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + orig_x = stuff->x; + orig_y = stuff->y; + FOR_NSCREENS_BACKWARD(j){ + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + if (isRoot) { + stuff->x = orig_x - panoramiXdataPtr[j].x; + stuff->y = orig_y - panoramiXdataPtr[j].y; + } + result = (*SavedProcVector[X_ImageText8])(client); + if(result != Success) break; + } + return (result); +} + + +int PanoramiXImageText16(ClientPtr client) +{ + int result, j; + PanoramiXRes *gc, *draw; + Bool isRoot; + int orig_x, orig_y; + REQUEST(xImageTextReq); + + REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars << 1); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + if(IS_SHARED_PIXMAP(draw)) + return (*SavedProcVector[X_ImageText16])(client); + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, XRT_GC, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + orig_x = stuff->x; + orig_y = stuff->y; + FOR_NSCREENS_BACKWARD(j){ + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + if (isRoot) { + stuff->x = orig_x - panoramiXdataPtr[j].x; + stuff->y = orig_y - panoramiXdataPtr[j].y; + } + result = (*SavedProcVector[X_ImageText16])(client); + if(result != Success) break; + } + return (result); +} + + + +int PanoramiXCreateColormap(ClientPtr client) +{ + PanoramiXRes *win, *newCmap; + int result, j, orig_visual; + REQUEST(xCreateColormapReq); + + REQUEST_SIZE_MATCH(xCreateColormapReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->window, + XRT_WINDOW, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + if(!(newCmap = malloc(sizeof(PanoramiXRes)))) + return BadAlloc; + + newCmap->type = XRT_COLORMAP; + newCmap->info[0].id = stuff->mid; + for(j = 1; j < PanoramiXNumScreens; j++) + newCmap->info[j].id = FakeClientID(client->index); + + orig_visual = stuff->visual; + FOR_NSCREENS_BACKWARD(j){ + stuff->mid = newCmap->info[j].id; + stuff->window = win->info[j].id; + stuff->visual = PanoramiXTranslateVisualID(j, orig_visual); + result = (* SavedProcVector[X_CreateColormap])(client); + if(result != Success) break; + } + + if (result == Success) + AddResource(newCmap->info[0].id, XRT_COLORMAP, newCmap); + else + free(newCmap); + + return (result); +} + + +int PanoramiXFreeColormap(ClientPtr client) +{ + PanoramiXRes *cmap; + int result, j; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + + client->errorValue = stuff->id; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->id, XRT_COLORMAP, + client, DixDestroyAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->id = cmap->info[j].id; + result = (* SavedProcVector[X_FreeColormap])(client); + if(result != Success) break; + } + + /* Since ProcFreeColormap is using FreeResource, it will free + our resource for us on the last pass through the loop above */ + + return (result); +} + + +int +PanoramiXCopyColormapAndFree(ClientPtr client) +{ + PanoramiXRes *cmap, *newCmap; + int result, j; + REQUEST(xCopyColormapAndFreeReq); + + REQUEST_SIZE_MATCH(xCopyColormapAndFreeReq); + + client->errorValue = stuff->srcCmap; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->srcCmap, + XRT_COLORMAP, client, + DixReadAccess | DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + if(!(newCmap = malloc(sizeof(PanoramiXRes)))) + return BadAlloc; + + newCmap->type = XRT_COLORMAP; + newCmap->info[0].id = stuff->mid; + for(j = 1; j < PanoramiXNumScreens; j++) + newCmap->info[j].id = FakeClientID(client->index); + + FOR_NSCREENS_BACKWARD(j){ + stuff->srcCmap = cmap->info[j].id; + stuff->mid = newCmap->info[j].id; + result = (* SavedProcVector[X_CopyColormapAndFree])(client); + if(result != Success) break; + } + + if (result == Success) + AddResource(newCmap->info[0].id, XRT_COLORMAP, newCmap); + else + free(newCmap); + + return (result); +} + + +int PanoramiXInstallColormap(ClientPtr client) +{ + REQUEST(xResourceReq); + int result, j; + PanoramiXRes *cmap; + + REQUEST_SIZE_MATCH(xResourceReq); + + client->errorValue = stuff->id; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->id, XRT_COLORMAP, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j){ + stuff->id = cmap->info[j].id; + result = (* SavedProcVector[X_InstallColormap])(client); + if(result != Success) break; + } + return (result); +} + + +int PanoramiXUninstallColormap(ClientPtr client) +{ + REQUEST(xResourceReq); + int result, j; + PanoramiXRes *cmap; + + REQUEST_SIZE_MATCH(xResourceReq); + + client->errorValue = stuff->id; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->id, XRT_COLORMAP, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->id = cmap->info[j].id; + result = (* SavedProcVector[X_UninstallColormap])(client); + if(result != Success) break; + } + return (result); +} + + +int PanoramiXAllocColor(ClientPtr client) +{ + int result, j; + PanoramiXRes *cmap; + REQUEST(xAllocColorReq); + + REQUEST_SIZE_MATCH(xAllocColorReq); + + client->errorValue = stuff->cmap; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, + XRT_COLORMAP, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j){ + stuff->cmap = cmap->info[j].id; + result = (* SavedProcVector[X_AllocColor])(client); + if(result != Success) break; + } + return (result); +} + + +int PanoramiXAllocNamedColor(ClientPtr client) +{ + int result, j; + PanoramiXRes *cmap; + REQUEST(xAllocNamedColorReq); + + REQUEST_FIXED_SIZE(xAllocNamedColorReq, stuff->nbytes); + + client->errorValue = stuff->cmap; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, + XRT_COLORMAP, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j){ + stuff->cmap = cmap->info[j].id; + result = (* SavedProcVector[X_AllocNamedColor])(client); + if(result != Success) break; + } + return (result); +} + + +int PanoramiXAllocColorCells(ClientPtr client) +{ + int result, j; + PanoramiXRes *cmap; + REQUEST(xAllocColorCellsReq); + + REQUEST_SIZE_MATCH(xAllocColorCellsReq); + + client->errorValue = stuff->cmap; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, + XRT_COLORMAP, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j){ + stuff->cmap = cmap->info[j].id; + result = (* SavedProcVector[X_AllocColorCells])(client); + if(result != Success) break; + } + return (result); +} + + +int PanoramiXAllocColorPlanes(ClientPtr client) +{ + int result, j; + PanoramiXRes *cmap; + REQUEST(xAllocColorPlanesReq); + + REQUEST_SIZE_MATCH(xAllocColorPlanesReq); + + client->errorValue = stuff->cmap; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, + XRT_COLORMAP, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j){ + stuff->cmap = cmap->info[j].id; + result = (* SavedProcVector[X_AllocColorPlanes])(client); + if(result != Success) break; + } + return (result); +} + + + +int PanoramiXFreeColors(ClientPtr client) +{ + int result, j; + PanoramiXRes *cmap; + REQUEST(xFreeColorsReq); + + REQUEST_AT_LEAST_SIZE(xFreeColorsReq); + + client->errorValue = stuff->cmap; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, + XRT_COLORMAP, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j) { + stuff->cmap = cmap->info[j].id; + result = (* SavedProcVector[X_FreeColors])(client); + } + return (result); +} + + +int PanoramiXStoreColors(ClientPtr client) +{ + int result, j; + PanoramiXRes *cmap; + REQUEST(xStoreColorsReq); + + REQUEST_AT_LEAST_SIZE(xStoreColorsReq); + + client->errorValue = stuff->cmap; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, + XRT_COLORMAP, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j){ + stuff->cmap = cmap->info[j].id; + result = (* SavedProcVector[X_StoreColors])(client); + if(result != Success) break; + } + return (result); +} + + +int PanoramiXStoreNamedColor(ClientPtr client) +{ + int result, j; + PanoramiXRes *cmap; + REQUEST(xStoreNamedColorReq); + + REQUEST_FIXED_SIZE(xStoreNamedColorReq, stuff->nbytes); + + client->errorValue = stuff->cmap; + + result = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, + XRT_COLORMAP, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadColor : result; + + FOR_NSCREENS_BACKWARD(j){ + stuff->cmap = cmap->info[j].id; + result = (* SavedProcVector[X_StoreNamedColor])(client); + if(result != Success) break; + } + return (result); +} diff --git a/xorg-server/Xext/saver.c b/xorg-server/Xext/saver.c index aa2e61428..f82b4b51b 100644 --- a/xorg-server/Xext/saver.c +++ b/xorg-server/Xext/saver.c @@ -1,1539 +1,1539 @@ -/* - * -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" -#include "xace.h" -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#ifdef DPMSExtension -#include -#endif -#include "protocol-versions.h" - -#include - -#include "modinit.h" - -static int ScreenSaverEventBase = 0; - -static 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 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 SaverEventType; /* 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 ScreenPrivateKeyIndex; -static DevPrivateKey ScreenPrivateKey = &ScreenPrivateKeyIndex; - -#define GetScreenPrivate(s) ((ScreenSaverScreenPrivatePtr) \ - dixLookupPrivate(&(s)->devPrivates, ScreenPrivateKey)) -#define SetScreenPrivate(s,v) \ - dixSetPrivate(&(s)->devPrivates, ScreenPrivateKey, v); -#define SetupScreen(s) ScreenSaverScreenPrivatePtr pPriv = (s ? GetScreenPrivate(s) : NULL) - -#define New(t) (xalloc (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, "SaverAttr"); - SaverEventType = CreateNewResourceType(ScreenSaverFreeEvents, - "SaverEvent"); - SuspendType = CreateNewResourceType(ScreenSaverFreeSuspend, - "SaverSuspend"); - - for (i = 0; i < screenInfo.numScreens; i++) - { - pScreen = screenInfo.screens[i]; - SetScreenPrivate (pScreen, NULL); - } - if (AttrType && SaverEventType && SuspendType && - (extEntry = AddExtension(ScreenSaverName, ScreenSaverNumberEvents, 0, - ProcScreenSaverDispatch, SProcScreenSaverDispatch, - NULL, StandardMinorOpcode))) - { - ScreenSaverEventBase = extEntry->eventBase; - EventSwapVector[ScreenSaverEventBase] = (EventSwapPtr) SScreenSaverNotifyEvent; - } -} - -static void -CheckScreenPrivate (ScreenPtr pScreen) -{ - SetupScreen (pScreen); - - if (!pPriv) - return; - if (!pPriv->attr && !pPriv->events && - !pPriv->hasWindow && pPriv->installedMap == None) - { - xfree (pPriv); - SetScreenPrivate (pScreen, NULL); - savedScreenInfo[pScreen->myNum].ExternalScreenSaver = NULL; - } -} - -static ScreenSaverScreenPrivatePtr -MakeScreenPrivate (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 (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 (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, SaverEventType); - *pPrev = pEv->next; - xfree (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, SaverEventType, (pointer) pEv)) - return FALSE; - } - pEv->mask = mask; - } - return TRUE; -} - -static void -FreeAttrs (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 (ScreenSaverAttrPtr pAttr) -{ - FreeAttrs (pAttr); - xfree (pAttr->values); - xfree (pAttr); -} - -static int -ScreenSaverFreeEvents (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; - xfree (pEv); - CheckScreenPrivate (pScreen); - return TRUE; -} - -static int -ScreenSaverFreeAttr (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) - { - dixSaveScreens (serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); - dixSaveScreens (serverClient, 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; - xfree (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 (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 (xScreenSaverNotifyEvent *from, - xScreenSaverNotifyEvent *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 (ScreenPtr pScreen) -{ - SetupScreen(pScreen); - ColormapPtr pCmap; - int rc; - - if (pPriv && pPriv->installedMap != None) - { - rc = dixLookupResourceByType((pointer *)&pCmap, pPriv->installedMap, - RT_COLORMAP, serverClient, - DixUninstallAccess); - if (rc == Success) - (*pCmap->pScreen->UninstallColormap) (pCmap); - pPriv->installedMap = None; - CheckScreenPrivate (pScreen); - } -} - -static Bool -CreateSaverWindow (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; - } - pAttr->pCursor->refcnt++; - if (pWin->optional->cursor) - FreeCursor (pWin->optional->cursor, (Cursor)0); - pWin->optional->cursor = pAttr->pCursor; - 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 = xalloc (pScreen->maxInstalledCmaps * sizeof (Colormap)); - numInstalled = (*pWin->drawable.pScreen->ListInstalledColormaps) - (pScreen, installedMaps); - for (i = 0; i < numInstalled; i++) - if (installedMaps[i] == wantMap) - break; - - xfree ((char *) installedMaps); - - if (i < numInstalled) - return TRUE; - - result = dixLookupResourceByType((pointer *)&pCmap, wantMap, RT_COLORMAP, - serverClient, DixInstallAccess); - if (result != Success) - return TRUE; - - pPriv->installedMap = wantMap; - - (*pCmap->pScreen->InstallColormap) (pCmap); - - return TRUE; -} - -static Bool -DestroySaverWindow (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 (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; - - } -#ifdef PANORAMIX - if(noPanoramiXExtension || !pScreen->myNum) -#endif - SendScreenSaverNotify (pScreen, state, force); - return ret; -} - -static int -ProcScreenSaverQueryVersion (ClientPtr client) -{ - xScreenSaverQueryVersionReply rep; - int n; - - REQUEST_SIZE_MATCH (xScreenSaverQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_SAVER_MAJOR_VERSION; - rep.minorVersion = SERVER_SAVER_MINOR_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - } - WriteToClient(client, sizeof (xScreenSaverQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcScreenSaverQueryInfo (ClientPtr client) -{ - REQUEST(xScreenSaverQueryInfoReq); - xScreenSaverQueryInfoReply rep; - int n, rc; - ScreenSaverStuffPtr pSaver; - DrawablePtr pDraw; - CARD32 lastInput; - ScreenSaverScreenPrivatePtr pPriv; - - REQUEST_SIZE_MATCH (xScreenSaverQueryInfoReq); - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, - DixGetAttrAccess); - if (rc != Success) - return rc; - rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, pDraw->pScreen, - DixGetAttrAccess); - if (rc != Success) - return rc; - - 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, n); - swapl (&rep.length, n); - swapl (&rep.window, n); - swapl (&rep.tilOrSince, n); - swapl (&rep.idle, n); - swapl (&rep.eventMask, n); - } - WriteToClient(client, sizeof (xScreenSaverQueryInfoReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcScreenSaverSelectInput (ClientPtr client) -{ - REQUEST(xScreenSaverSelectInputReq); - DrawablePtr pDraw; - int rc; - - REQUEST_SIZE_MATCH (xScreenSaverSelectInputReq); - rc = dixLookupDrawable (&pDraw, stuff->drawable, client, 0, - DixGetAttrAccess); - if (rc != Success) - return rc; - - rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, pDraw->pScreen, - DixSetAttrAccess); - if (rc != Success) - return rc; - - 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, len, 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); - ret = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, - DixGetAttrAccess); - if (ret != Success) - return ret; - pScreen = pDraw->pScreen; - pParent = WindowTable[pScreen->myNum]; - - ret = XaceHook(XACE_SCREENSAVER_ACCESS, client, pScreen, DixSetAttrAccess); - if (ret != Success) - return ret; - - len = stuff->length - bytes_to_int32(sizeof(xScreenSaverSetAttributesReq)); - 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 = xalloc ((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 - { - ret = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, - client, DixReadAccess); - if (ret == Success) - { - if ((pPixmap->drawable.depth != depth) || - (pPixmap->drawable.pScreen != pScreen)) - { - ret = BadMatch; - goto PatchUp; - } - pAttr->pBackgroundPixmap = pPixmap; - pPixmap->refcnt++; - pAttr->mask &= ~CWBackPixmap; - } - else - { - ret = (ret == BadValue) ? BadPixmap : ret; - 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 - { - ret = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, - client, DixReadAccess); - if (ret == Success) - { - if ((pPixmap->drawable.depth != depth) || - (pPixmap->drawable.pScreen != pScreen)) - { - ret = BadMatch; - goto PatchUp; - } - pAttr->pBorderPixmap = pPixmap; - pPixmap->refcnt++; - pAttr->mask &= ~CWBorderPixmap; - } - else - { - ret = (ret == BadValue) ? BadPixmap : ret; - 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; - ret = dixLookupResourceByType((pointer *)&pCmap, cmap, RT_COLORMAP, - client, DixUseAccess); - if (ret != Success) - { - ret = (ret == BadValue) ? BadColor : ret; - 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 - { - ret = dixLookupResourceByType((pointer *)&pCursor, cursorID, - RT_CURSOR, client, DixUseAccess); - if (ret != Success) - { - ret = (ret == BadValue) ? BadCursor : ret; - 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) xfree (pAttr->values); - xfree (pAttr); - return ret; -} - -static int -ScreenSaverUnsetAttributes (ClientPtr client) -{ - REQUEST(xScreenSaverSetAttributesReq); - DrawablePtr pDraw; - ScreenSaverScreenPrivatePtr pPriv; - int rc; - - REQUEST_SIZE_MATCH (xScreenSaverUnsetAttributesReq); - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, - DixGetAttrAccess); - if (rc != Success) - return rc; - 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) -{ -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - REQUEST(xScreenSaverSetAttributesReq); - PanoramiXRes *draw; - PanoramiXRes *backPix = NULL; - PanoramiXRes *bordPix = NULL; - PanoramiXRes *cmap = NULL; - int i, status, len; - int pback_offset = 0, pbord_offset = 0, cmap_offset = 0; - XID orig_visual, tmp; - - REQUEST_AT_LEAST_SIZE (xScreenSaverSetAttributesReq); - - status = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (status != Success) - return (status == BadValue) ? BadDrawable : status; - - len = stuff->length - bytes_to_int32(sizeof(xScreenSaverSetAttributesReq)); - if (Ones(stuff->mask) != len) - return BadLength; - - if((Mask)stuff->mask & CWBackPixmap) { - pback_offset = Ones((Mask)stuff->mask & (CWBackPixmap - 1)); - tmp = *((CARD32 *) &stuff[1] + pback_offset); - if ((tmp != None) && (tmp != ParentRelative)) { - status = dixLookupResourceByType((pointer *)&backPix, tmp, - XRT_PIXMAP, client, - DixReadAccess); - if (status != Success) - return (status == BadValue) ? BadPixmap : status; - } - } - - if ((Mask)stuff->mask & CWBorderPixmap) { - pbord_offset = Ones((Mask)stuff->mask & (CWBorderPixmap - 1)); - tmp = *((CARD32 *) &stuff[1] + pbord_offset); - if (tmp != CopyFromParent) { - status = dixLookupResourceByType((pointer *)&bordPix, tmp, - XRT_PIXMAP, client, - DixReadAccess); - if (status != Success) - return (status == BadValue) ? BadPixmap : status; - } - } - - if ((Mask)stuff->mask & CWColormap) { - cmap_offset = Ones((Mask)stuff->mask & (CWColormap - 1)); - tmp = *((CARD32 *) &stuff[1] + cmap_offset); - if ((tmp != CopyFromParent) && (tmp != None)) { - status = dixLookupResourceByType((pointer *)&cmap, tmp, - XRT_COLORMAP, client, - DixReadAccess); - if (status != Success) - return (status == BadValue) ? BadColor : status; - } - } - - orig_visual = stuff->visualID; - - FOR_NSCREENS_BACKWARD(i) { - stuff->drawable = draw->info[i].id; - if (backPix) - *((CARD32 *) &stuff[1] + pback_offset) = backPix->info[i].id; - if (bordPix) - *((CARD32 *) &stuff[1] + pbord_offset) = bordPix->info[i].id; - if (cmap) - *((CARD32 *) &stuff[1] + cmap_offset) = cmap->info[i].id; - - if (orig_visual != CopyFromParent) - stuff->visualID = PanoramiXTranslateVisualID(i, orig_visual); - - status = ScreenSaverSetAttributes(client); - } - - return status; - } -#endif - - return ScreenSaverSetAttributes(client); -} - -static int -ProcScreenSaverUnsetAttributes (ClientPtr client) -{ -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - REQUEST(xScreenSaverUnsetAttributesReq); - PanoramiXRes *draw; - int rc, i; - - rc = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (rc != Success) - return (rc == BadValue) ? BadDrawable : rc; - - for(i = PanoramiXNumScreens - 1; i > 0; i--) { - stuff->drawable = draw->info[i].id; - ScreenSaverUnsetAttributes(client); - } - - stuff->drawable = draw->info[0].id; - } -#endif - - 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 = xalloc (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)) - { - xfree (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 (ClientPtr client) -{ - REQUEST(xReq); - - if (stuff->data < NUM_REQUESTS) - return (*NormalVector[stuff->data])(client); - return BadRequest; -} - -static int -SProcScreenSaverQueryVersion (ClientPtr client) -{ - REQUEST(xScreenSaverQueryVersionReq); - int n; - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xScreenSaverQueryVersionReq); - return ProcScreenSaverQueryVersion (client); -} - -static int -SProcScreenSaverQueryInfo (ClientPtr client) -{ - REQUEST(xScreenSaverQueryInfoReq); - int n; - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xScreenSaverQueryInfoReq); - swapl (&stuff->drawable, n); - return ProcScreenSaverQueryInfo (client); -} - -static int -SProcScreenSaverSelectInput (ClientPtr client) -{ - REQUEST(xScreenSaverSelectInputReq); - int n; - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xScreenSaverSelectInputReq); - swapl (&stuff->drawable, n); - swapl (&stuff->eventMask, n); - return ProcScreenSaverSelectInput (client); -} - -static int -SProcScreenSaverSetAttributes (ClientPtr client) -{ - REQUEST(xScreenSaverSetAttributesReq); - int n; - - swaps (&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xScreenSaverSetAttributesReq); - swapl (&stuff->drawable, n); - swaps (&stuff->x, n); - swaps (&stuff->y, n); - swaps (&stuff->width, n); - swaps (&stuff->height, n); - swaps (&stuff->borderWidth, n); - swapl (&stuff->visualID, n); - swapl (&stuff->mask, n); - SwapRestL(stuff); - return ProcScreenSaverSetAttributes (client); -} - -static int -SProcScreenSaverUnsetAttributes (ClientPtr client) -{ - REQUEST(xScreenSaverUnsetAttributesReq); - int n; - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xScreenSaverUnsetAttributesReq); - swapl (&stuff->drawable, n); - return ProcScreenSaverUnsetAttributes (client); -} - -static int -SProcScreenSaverSuspend (ClientPtr client) -{ - int n; - REQUEST(xScreenSaverSuspendReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xScreenSaverSuspendReq); - swapl(&stuff->suspend, n); - return ProcScreenSaverSuspend (client); -} - -static DISPATCH_PROC((*SwappedVector[])) = { - SProcScreenSaverQueryVersion, - SProcScreenSaverQueryInfo, - SProcScreenSaverSelectInput, - SProcScreenSaverSetAttributes, - SProcScreenSaverUnsetAttributes, - SProcScreenSaverSuspend, -}; - -static int -SProcScreenSaverDispatch (ClientPtr client) -{ - REQUEST(xReq); - - if (stuff->data < NUM_REQUESTS) - return (*SwappedVector[stuff->data])(client); - return BadRequest; -} +/* + * +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" +#include "xace.h" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif +#ifdef DPMSExtension +#include +#endif +#include "protocol-versions.h" + +#include + +#include "modinit.h" + +static int ScreenSaverEventBase = 0; + +static 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 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 SaverEventType; /* 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 ScreenPrivateKeyIndex; +static DevPrivateKey ScreenPrivateKey = &ScreenPrivateKeyIndex; + +#define GetScreenPrivate(s) ((ScreenSaverScreenPrivatePtr) \ + dixLookupPrivate(&(s)->devPrivates, ScreenPrivateKey)) +#define SetScreenPrivate(s,v) \ + dixSetPrivate(&(s)->devPrivates, ScreenPrivateKey, 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, "SaverAttr"); + SaverEventType = CreateNewResourceType(ScreenSaverFreeEvents, + "SaverEvent"); + SuspendType = CreateNewResourceType(ScreenSaverFreeSuspend, + "SaverSuspend"); + + for (i = 0; i < screenInfo.numScreens; i++) + { + pScreen = screenInfo.screens[i]; + SetScreenPrivate (pScreen, NULL); + } + if (AttrType && SaverEventType && SuspendType && + (extEntry = AddExtension(ScreenSaverName, ScreenSaverNumberEvents, 0, + ProcScreenSaverDispatch, SProcScreenSaverDispatch, + NULL, StandardMinorOpcode))) + { + ScreenSaverEventBase = extEntry->eventBase; + EventSwapVector[ScreenSaverEventBase] = (EventSwapPtr) SScreenSaverNotifyEvent; + } +} + +static void +CheckScreenPrivate (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 (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 (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 (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, SaverEventType); + *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, SaverEventType, (pointer) pEv)) + return FALSE; + } + pEv->mask = mask; + } + return TRUE; +} + +static void +FreeAttrs (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 (ScreenSaverAttrPtr pAttr) +{ + FreeAttrs (pAttr); + free(pAttr->values); + free(pAttr); +} + +static int +ScreenSaverFreeEvents (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 (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) + { + dixSaveScreens (serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); + dixSaveScreens (serverClient, 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 (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 (xScreenSaverNotifyEvent *from, + xScreenSaverNotifyEvent *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 (ScreenPtr pScreen) +{ + SetupScreen(pScreen); + ColormapPtr pCmap; + int rc; + + if (pPriv && pPriv->installedMap != None) + { + rc = dixLookupResourceByType((pointer *)&pCmap, pPriv->installedMap, + RT_COLORMAP, serverClient, + DixUninstallAccess); + if (rc == Success) + (*pCmap->pScreen->UninstallColormap) (pCmap); + pPriv->installedMap = None; + CheckScreenPrivate (pScreen); + } +} + +static Bool +CreateSaverWindow (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; + } + pAttr->pCursor->refcnt++; + if (pWin->optional->cursor) + FreeCursor (pWin->optional->cursor, (Cursor)0); + pWin->optional->cursor = pAttr->pCursor; + 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 = malloc(pScreen->maxInstalledCmaps * sizeof (Colormap)); + numInstalled = (*pWin->drawable.pScreen->ListInstalledColormaps) + (pScreen, installedMaps); + for (i = 0; i < numInstalled; i++) + if (installedMaps[i] == wantMap) + break; + + free((char *) installedMaps); + + if (i < numInstalled) + return TRUE; + + result = dixLookupResourceByType((pointer *)&pCmap, wantMap, RT_COLORMAP, + serverClient, DixInstallAccess); + if (result != Success) + return TRUE; + + pPriv->installedMap = wantMap; + + (*pCmap->pScreen->InstallColormap) (pCmap); + + return TRUE; +} + +static Bool +DestroySaverWindow (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 (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; + + } +#ifdef PANORAMIX + if(noPanoramiXExtension || !pScreen->myNum) +#endif + SendScreenSaverNotify (pScreen, state, force); + return ret; +} + +static int +ProcScreenSaverQueryVersion (ClientPtr client) +{ + xScreenSaverQueryVersionReply rep; + int n; + + REQUEST_SIZE_MATCH (xScreenSaverQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_SAVER_MAJOR_VERSION; + rep.minorVersion = SERVER_SAVER_MINOR_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + WriteToClient(client, sizeof (xScreenSaverQueryVersionReply), (char *)&rep); + return Success; +} + +static int +ProcScreenSaverQueryInfo (ClientPtr client) +{ + REQUEST(xScreenSaverQueryInfoReq); + xScreenSaverQueryInfoReply rep; + int n, rc; + ScreenSaverStuffPtr pSaver; + DrawablePtr pDraw; + CARD32 lastInput; + ScreenSaverScreenPrivatePtr pPriv; + + REQUEST_SIZE_MATCH (xScreenSaverQueryInfoReq); + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, + DixGetAttrAccess); + if (rc != Success) + return rc; + rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, pDraw->pScreen, + DixGetAttrAccess); + if (rc != Success) + return rc; + + 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, n); + swapl (&rep.length, n); + swapl (&rep.window, n); + swapl (&rep.tilOrSince, n); + swapl (&rep.idle, n); + swapl (&rep.eventMask, n); + } + WriteToClient(client, sizeof (xScreenSaverQueryInfoReply), (char *)&rep); + return Success; +} + +static int +ProcScreenSaverSelectInput (ClientPtr client) +{ + REQUEST(xScreenSaverSelectInputReq); + DrawablePtr pDraw; + int rc; + + REQUEST_SIZE_MATCH (xScreenSaverSelectInputReq); + rc = dixLookupDrawable (&pDraw, stuff->drawable, client, 0, + DixGetAttrAccess); + if (rc != Success) + return rc; + + rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, pDraw->pScreen, + DixSetAttrAccess); + if (rc != Success) + return rc; + + 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, len, 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); + ret = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, + DixGetAttrAccess); + if (ret != Success) + return ret; + pScreen = pDraw->pScreen; + pParent = WindowTable[pScreen->myNum]; + + ret = XaceHook(XACE_SCREENSAVER_ACCESS, client, pScreen, DixSetAttrAccess); + if (ret != Success) + return ret; + + len = stuff->length - bytes_to_int32(sizeof(xScreenSaverSetAttributesReq)); + 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 + { + ret = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, + client, DixReadAccess); + if (ret == Success) + { + if ((pPixmap->drawable.depth != depth) || + (pPixmap->drawable.pScreen != pScreen)) + { + ret = BadMatch; + goto PatchUp; + } + pAttr->pBackgroundPixmap = pPixmap; + pPixmap->refcnt++; + pAttr->mask &= ~CWBackPixmap; + } + else + { + ret = (ret == BadValue) ? BadPixmap : ret; + 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 + { + ret = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, + client, DixReadAccess); + if (ret == Success) + { + if ((pPixmap->drawable.depth != depth) || + (pPixmap->drawable.pScreen != pScreen)) + { + ret = BadMatch; + goto PatchUp; + } + pAttr->pBorderPixmap = pPixmap; + pPixmap->refcnt++; + pAttr->mask &= ~CWBorderPixmap; + } + else + { + ret = (ret == BadValue) ? BadPixmap : ret; + 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; + ret = dixLookupResourceByType((pointer *)&pCmap, cmap, RT_COLORMAP, + client, DixUseAccess); + if (ret != Success) + { + ret = (ret == BadValue) ? BadColor : ret; + 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 + { + ret = dixLookupResourceByType((pointer *)&pCursor, cursorID, + RT_CURSOR, client, DixUseAccess); + if (ret != Success) + { + ret = (ret == BadValue) ? BadCursor : ret; + 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; + int rc; + + REQUEST_SIZE_MATCH (xScreenSaverUnsetAttributesReq); + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, + DixGetAttrAccess); + if (rc != Success) + return rc; + 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) +{ +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + REQUEST(xScreenSaverSetAttributesReq); + PanoramiXRes *draw; + PanoramiXRes *backPix = NULL; + PanoramiXRes *bordPix = NULL; + PanoramiXRes *cmap = NULL; + int i, status, len; + int pback_offset = 0, pbord_offset = 0, cmap_offset = 0; + XID orig_visual, tmp; + + REQUEST_AT_LEAST_SIZE (xScreenSaverSetAttributesReq); + + status = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (status != Success) + return (status == BadValue) ? BadDrawable : status; + + len = stuff->length - bytes_to_int32(sizeof(xScreenSaverSetAttributesReq)); + if (Ones(stuff->mask) != len) + return BadLength; + + if((Mask)stuff->mask & CWBackPixmap) { + pback_offset = Ones((Mask)stuff->mask & (CWBackPixmap - 1)); + tmp = *((CARD32 *) &stuff[1] + pback_offset); + if ((tmp != None) && (tmp != ParentRelative)) { + status = dixLookupResourceByType((pointer *)&backPix, tmp, + XRT_PIXMAP, client, + DixReadAccess); + if (status != Success) + return (status == BadValue) ? BadPixmap : status; + } + } + + if ((Mask)stuff->mask & CWBorderPixmap) { + pbord_offset = Ones((Mask)stuff->mask & (CWBorderPixmap - 1)); + tmp = *((CARD32 *) &stuff[1] + pbord_offset); + if (tmp != CopyFromParent) { + status = dixLookupResourceByType((pointer *)&bordPix, tmp, + XRT_PIXMAP, client, + DixReadAccess); + if (status != Success) + return (status == BadValue) ? BadPixmap : status; + } + } + + if ((Mask)stuff->mask & CWColormap) { + cmap_offset = Ones((Mask)stuff->mask & (CWColormap - 1)); + tmp = *((CARD32 *) &stuff[1] + cmap_offset); + if ((tmp != CopyFromParent) && (tmp != None)) { + status = dixLookupResourceByType((pointer *)&cmap, tmp, + XRT_COLORMAP, client, + DixReadAccess); + if (status != Success) + return (status == BadValue) ? BadColor : status; + } + } + + orig_visual = stuff->visualID; + + FOR_NSCREENS_BACKWARD(i) { + stuff->drawable = draw->info[i].id; + if (backPix) + *((CARD32 *) &stuff[1] + pback_offset) = backPix->info[i].id; + if (bordPix) + *((CARD32 *) &stuff[1] + pbord_offset) = bordPix->info[i].id; + if (cmap) + *((CARD32 *) &stuff[1] + cmap_offset) = cmap->info[i].id; + + if (orig_visual != CopyFromParent) + stuff->visualID = PanoramiXTranslateVisualID(i, orig_visual); + + status = ScreenSaverSetAttributes(client); + } + + return status; + } +#endif + + return ScreenSaverSetAttributes(client); +} + +static int +ProcScreenSaverUnsetAttributes (ClientPtr client) +{ +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + REQUEST(xScreenSaverUnsetAttributesReq); + PanoramiXRes *draw; + int rc, i; + + rc = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (rc != Success) + return (rc == BadValue) ? BadDrawable : rc; + + for(i = PanoramiXNumScreens - 1; i > 0; i--) { + stuff->drawable = draw->info[i].id; + ScreenSaverUnsetAttributes(client); + } + + stuff->drawable = draw->info[0].id; + } +#endif + + 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 Success; +} + +static DISPATCH_PROC((*NormalVector[])) = { + ProcScreenSaverQueryVersion, + ProcScreenSaverQueryInfo, + ProcScreenSaverSelectInput, + ProcScreenSaverSetAttributes, + ProcScreenSaverUnsetAttributes, + ProcScreenSaverSuspend, +}; + +#define NUM_REQUESTS ((sizeof NormalVector) / (sizeof NormalVector[0])) + +static int +ProcScreenSaverDispatch (ClientPtr client) +{ + REQUEST(xReq); + + if (stuff->data < NUM_REQUESTS) + return (*NormalVector[stuff->data])(client); + return BadRequest; +} + +static int +SProcScreenSaverQueryVersion (ClientPtr client) +{ + REQUEST(xScreenSaverQueryVersionReq); + int n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xScreenSaverQueryVersionReq); + return ProcScreenSaverQueryVersion (client); +} + +static int +SProcScreenSaverQueryInfo (ClientPtr client) +{ + REQUEST(xScreenSaverQueryInfoReq); + int n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xScreenSaverQueryInfoReq); + swapl (&stuff->drawable, n); + return ProcScreenSaverQueryInfo (client); +} + +static int +SProcScreenSaverSelectInput (ClientPtr client) +{ + REQUEST(xScreenSaverSelectInputReq); + int n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xScreenSaverSelectInputReq); + swapl (&stuff->drawable, n); + swapl (&stuff->eventMask, n); + return ProcScreenSaverSelectInput (client); +} + +static int +SProcScreenSaverSetAttributes (ClientPtr client) +{ + REQUEST(xScreenSaverSetAttributesReq); + int n; + + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xScreenSaverSetAttributesReq); + swapl (&stuff->drawable, n); + swaps (&stuff->x, n); + swaps (&stuff->y, n); + swaps (&stuff->width, n); + swaps (&stuff->height, n); + swaps (&stuff->borderWidth, n); + swapl (&stuff->visualID, n); + swapl (&stuff->mask, n); + SwapRestL(stuff); + return ProcScreenSaverSetAttributes (client); +} + +static int +SProcScreenSaverUnsetAttributes (ClientPtr client) +{ + REQUEST(xScreenSaverUnsetAttributesReq); + int n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xScreenSaverUnsetAttributesReq); + swapl (&stuff->drawable, n); + return ProcScreenSaverUnsetAttributes (client); +} + +static int +SProcScreenSaverSuspend (ClientPtr client) +{ + int n; + REQUEST(xScreenSaverSuspendReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xScreenSaverSuspendReq); + swapl(&stuff->suspend, n); + return ProcScreenSaverSuspend (client); +} + +static DISPATCH_PROC((*SwappedVector[])) = { + SProcScreenSaverQueryVersion, + SProcScreenSaverQueryInfo, + SProcScreenSaverSelectInput, + SProcScreenSaverSetAttributes, + SProcScreenSaverUnsetAttributes, + SProcScreenSaverSuspend, +}; + +static int +SProcScreenSaverDispatch (ClientPtr client) +{ + REQUEST(xReq); + + if (stuff->data < NUM_REQUESTS) + return (*SwappedVector[stuff->data])(client); + return BadRequest; +} diff --git a/xorg-server/Xext/security.c b/xorg-server/Xext/security.c index af8d2052f..289f9597d 100644 --- a/xorg-server/Xext/security.c +++ b/xorg-server/Xext/security.c @@ -1,1154 +1,1151 @@ -/* - -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 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 "scrnintstr.h" -#include "inputstr.h" -#include "windowstr.h" -#include "propertyst.h" -#include "colormapst.h" -#include "privates.h" -#include "registry.h" -#include "xacestr.h" -#include "securitysrv.h" -#include -#include "modinit.h" -#include "protocol-versions.h" - -/* Extension stuff */ -static int SecurityErrorBase; /* first Security error number */ -static int SecurityEventBase; /* first Security event number */ - -RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */ -static RESTYPE RTEventClient; - -static CallbackListPtr SecurityValidateGroupCallback = NULL; - -/* Private state record */ -static int stateKeyIndex; -static DevPrivateKey stateKey = &stateKeyIndex; - -/* This is what we store as client security state */ -typedef struct { - int haveState; - unsigned int trustLevel; - XID authId; -} SecurityStateRec; - -/* Extensions that untrusted clients shouldn't have access to */ -static char *SecurityTrustedExtensions[] = { - "XC-MISC", - "BIG-REQUESTS", - "XpExtension", - NULL -}; - -/* - * Access modes that untrusted clients are allowed on trusted objects. - */ -static const Mask SecurityResourceMask = - DixGetAttrAccess | DixReceiveAccess | DixListPropAccess | - DixGetPropAccess | DixListAccess; -static const Mask SecurityWindowExtraMask = DixRemoveAccess; -static const Mask SecurityRootWindowExtraMask = - DixReceiveAccess | DixSendAccess | DixAddAccess | DixRemoveAccess; -static const Mask SecurityDeviceMask = - DixGetAttrAccess | DixReceiveAccess | DixGetFocusAccess | - DixGrabAccess | DixSetAttrAccess | DixUseAccess; -static const Mask SecurityServerMask = DixGetAttrAccess | DixGrabAccess; -static const Mask SecurityClientMask = DixGetAttrAccess; - - -/* SecurityAudit - * - * Arguments: - * format is the formatting string to be used to interpret the - * remaining arguments. - * - * Returns: nothing. - * - * Side Effects: - * Writes the message to the log file if security logging is on. - */ - -static void -SecurityAudit(char *format, ...) -{ - va_list args; - - if (auditTrailLevel < SECURITY_AUDIT_LEVEL) - return; - va_start(args, format); - VAuditF(format, args); - va_end(args); -} /* SecurityAudit */ - -/* - * Performs a Security permission check. - */ -static int -SecurityDoCheck(SecurityStateRec *subj, SecurityStateRec *obj, - Mask requested, Mask allowed) -{ - if (!subj->haveState || !obj->haveState) - return Success; - if (subj->trustLevel == XSecurityClientTrusted) - return Success; - if (obj->trustLevel != XSecurityClientTrusted) - return Success; - if ((requested | allowed) == allowed) - return Success; - - return BadAccess; -} - -/* - * Labels initial server objects. - */ -static void -SecurityLabelInitial(void) -{ - SecurityStateRec *state; - - /* Do the serverClient */ - state = dixLookupPrivate(&serverClient->devPrivates, stateKey); - state->trustLevel = XSecurityClientTrusted; - state->haveState = TRUE; -} - -/* - * Looks up a request name - */ -static _X_INLINE const char * -SecurityLookupRequestName(ClientPtr client) -{ - int major = ((xReq *)client->requestBuffer)->reqType; - int minor = MinorOpcodeOfRequest(client); - return LookupRequestName(major, minor); -} - - -#define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) - -/* SecurityDeleteAuthorization - * - * Arguments: - * value is the authorization to delete. - * id is its resource ID. - * - * Returns: Success. - * - * Side Effects: - * Frees everything associated with the authorization. - */ - -static int -SecurityDeleteAuthorization( - pointer value, - XID id) -{ - SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value; - unsigned short name_len, data_len; - char *name, *data; - int status; - int i; - OtherClientsPtr pEventClient; - - /* Remove the auth using the os layer auth manager */ - - status = AuthorizationFromID(pAuth->id, &name_len, &name, - &data_len, &data); - assert(status); - status = RemoveAuthorization(name_len, name, data_len, data); - assert(status); - (void)status; - - /* free the auth timer if there is one */ - - if (pAuth->timer) TimerFree(pAuth->timer); - - /* send revoke events */ - - while ((pEventClient = pAuth->eventClients)) - { - /* send revocation event event */ - ClientPtr client = rClient(pEventClient); - - if (!client->clientGone) - { - xSecurityAuthorizationRevokedEvent are; - are.type = SecurityEventBase + XSecurityAuthorizationRevoked; - are.sequenceNumber = client->sequence; - are.authId = pAuth->id; - WriteEventsToClient(client, 1, (xEvent *)&are); - } - FreeResource(pEventClient->resource, RT_NONE); - } - - /* kill all clients using this auth */ - - for (i = 1; idevPrivates, stateKey); - if (state->haveState && state->authId == pAuth->id) - CloseDownClient(clients[i]); - } - - SecurityAudit("revoked authorization ID %d\n", pAuth->id); - xfree(pAuth); - return Success; - -} /* SecurityDeleteAuthorization */ - - -/* resource delete function for RTEventClient */ -static int -SecurityDeleteAuthorizationEventClient( - pointer value, - XID id) -{ - OtherClientsPtr pEventClient, prev = NULL; - SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value; - - for (pEventClient = pAuth->eventClients; - pEventClient; - pEventClient = pEventClient->next) - { - if (pEventClient->resource == id) - { - if (prev) - prev->next = pEventClient->next; - else - pAuth->eventClients = pEventClient->next; - xfree(pEventClient); - return(Success); - } - prev = pEventClient; - } - /*NOTREACHED*/ - return -1; /* make compiler happy */ -} /* SecurityDeleteAuthorizationEventClient */ - - -/* SecurityComputeAuthorizationTimeout - * - * Arguments: - * pAuth is the authorization for which we are computing the timeout - * seconds is the number of seconds we want to wait - * - * Returns: - * the number of milliseconds that the auth timer should be set to - * - * Side Effects: - * Sets pAuth->secondsRemaining to any "overflow" amount of time - * that didn't fit in 32 bits worth of milliseconds - */ - -static CARD32 -SecurityComputeAuthorizationTimeout( - SecurityAuthorizationPtr pAuth, - unsigned int seconds) -{ - /* maxSecs is the number of full seconds that can be expressed in - * 32 bits worth of milliseconds - */ - CARD32 maxSecs = (CARD32)(~0) / (CARD32)MILLI_PER_SECOND; - - if (seconds > maxSecs) - { /* only come here if we want to wait more than 49 days */ - pAuth->secondsRemaining = seconds - maxSecs; - return maxSecs * MILLI_PER_SECOND; - } - else - { /* by far the common case */ - pAuth->secondsRemaining = 0; - return seconds * MILLI_PER_SECOND; - } -} /* SecurityStartAuthorizationTimer */ - -/* SecurityAuthorizationExpired - * - * This function is passed as an argument to TimerSet and gets called from - * the timer manager in the os layer when its time is up. - * - * Arguments: - * timer is the timer for this authorization. - * time is the current time. - * pval is the authorization whose time is up. - * - * Returns: - * A new time delay in milliseconds if the timer should wait some - * more, else zero. - * - * Side Effects: - * Frees the authorization resource if the timeout period is really - * over, otherwise recomputes pAuth->secondsRemaining. - */ - -static CARD32 -SecurityAuthorizationExpired( - OsTimerPtr timer, - CARD32 time, - pointer pval) -{ - SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)pval; - - assert(pAuth->timer == timer); - - if (pAuth->secondsRemaining) - { - return SecurityComputeAuthorizationTimeout(pAuth, - pAuth->secondsRemaining); - } - else - { - FreeResource(pAuth->id, RT_NONE); - return 0; - } -} /* SecurityAuthorizationExpired */ - -/* SecurityStartAuthorizationTimer - * - * Arguments: - * pAuth is the authorization whose timer should be started. - * - * Returns: nothing. - * - * Side Effects: - * A timer is started, set to expire after the timeout period for - * this authorization. When it expires, the function - * SecurityAuthorizationExpired will be called. - */ - -static void -SecurityStartAuthorizationTimer( - SecurityAuthorizationPtr pAuth) -{ - pAuth->timer = TimerSet(pAuth->timer, 0, - SecurityComputeAuthorizationTimeout(pAuth, pAuth->timeout), - SecurityAuthorizationExpired, pAuth); -} /* SecurityStartAuthorizationTimer */ - - -/* Proc functions all take a client argument, execute the request in - * client->requestBuffer, and return a protocol error status. - */ - -static int -ProcSecurityQueryVersion( - ClientPtr client) -{ - /* REQUEST(xSecurityQueryVersionReq); */ - xSecurityQueryVersionReply rep; - - REQUEST_SIZE_MATCH(xSecurityQueryVersionReq); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.majorVersion = SERVER_SECURITY_MAJOR_VERSION; - rep.minorVersion = SERVER_SECURITY_MINOR_VERSION; - if(client->swapped) - { - char n; - swaps(&rep.sequenceNumber, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - (void)WriteToClient(client, SIZEOF(xSecurityQueryVersionReply), - (char *)&rep); - return (client->noClientException); -} /* ProcSecurityQueryVersion */ - - -static int -SecurityEventSelectForAuthorization( - SecurityAuthorizationPtr pAuth, - ClientPtr client, - Mask mask) -{ - OtherClients *pEventClient; - - for (pEventClient = pAuth->eventClients; - pEventClient; - pEventClient = pEventClient->next) - { - if (SameClient(pEventClient, client)) - { - if (mask == 0) - FreeResource(pEventClient->resource, RT_NONE); - else - pEventClient->mask = mask; - return Success; - } - } - - pEventClient = xalloc(sizeof(OtherClients)); - if (!pEventClient) - return BadAlloc; - pEventClient->mask = mask; - pEventClient->resource = FakeClientID(client->index); - pEventClient->next = pAuth->eventClients; - if (!AddResource(pEventClient->resource, RTEventClient, - (pointer)pAuth)) - { - xfree(pEventClient); - return BadAlloc; - } - pAuth->eventClients = pEventClient; - - return Success; -} /* SecurityEventSelectForAuthorization */ - - -static int -ProcSecurityGenerateAuthorization( - ClientPtr client) -{ - REQUEST(xSecurityGenerateAuthorizationReq); - int len; /* request length in CARD32s*/ - Bool removeAuth = FALSE; /* if bailout, call RemoveAuthorization? */ - SecurityAuthorizationPtr pAuth = NULL; /* auth we are creating */ - int err; /* error to return from this function */ - XID authId; /* authorization ID assigned by os layer */ - xSecurityGenerateAuthorizationReply rep; /* reply struct */ - unsigned int trustLevel; /* trust level of new auth */ - XID group; /* group of new auth */ - CARD32 timeout; /* timeout of new auth */ - CARD32 *values; /* list of supplied attributes */ - char *protoname; /* auth proto name sent in request */ - char *protodata; /* auth proto data sent in request */ - unsigned int authdata_len; /* # bytes of generated auth data */ - char *pAuthdata; /* generated auth data */ - Mask eventMask; /* what events on this auth does client want */ - - /* check request length */ - - REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq); - len = bytes_to_int32(SIZEOF(xSecurityGenerateAuthorizationReq)); - len += bytes_to_int32(stuff->nbytesAuthProto); - len += bytes_to_int32(stuff->nbytesAuthData); - values = ((CARD32 *)stuff) + len; - len += Ones(stuff->valueMask); - if (client->req_len != len) - return BadLength; - - /* check valuemask */ - if (stuff->valueMask & ~XSecurityAllAuthorizationAttributes) - { - client->errorValue = stuff->valueMask; - return BadValue; - } - - /* check timeout */ - timeout = 60; - if (stuff->valueMask & XSecurityTimeout) - { - timeout = *values++; - } - - /* check trustLevel */ - trustLevel = XSecurityClientUntrusted; - if (stuff->valueMask & XSecurityTrustLevel) - { - trustLevel = *values++; - if (trustLevel != XSecurityClientTrusted && - trustLevel != XSecurityClientUntrusted) - { - client->errorValue = trustLevel; - return BadValue; - } - } - - /* check group */ - group = None; - if (stuff->valueMask & XSecurityGroup) - { - group = *values++; - if (SecurityValidateGroupCallback) - { - SecurityValidateGroupInfoRec vgi; - vgi.group = group; - vgi.valid = FALSE; - CallCallbacks(&SecurityValidateGroupCallback, (pointer)&vgi); - - /* if nobody said they recognized it, it's an error */ - - if (!vgi.valid) - { - client->errorValue = group; - return BadValue; - } - } - } - - /* check event mask */ - eventMask = 0; - if (stuff->valueMask & XSecurityEventMask) - { - eventMask = *values++; - if (eventMask & ~XSecurityAllEventMasks) - { - client->errorValue = eventMask; - return BadValue; - } - } - - protoname = (char *)&stuff[1]; - protodata = protoname + bytes_to_int32(stuff->nbytesAuthProto); - - /* call os layer to generate the authorization */ - - authId = GenerateAuthorization(stuff->nbytesAuthProto, protoname, - stuff->nbytesAuthData, protodata, - &authdata_len, &pAuthdata); - if ((XID) ~0L == authId) - { - err = SecurityErrorBase + XSecurityBadAuthorizationProtocol; - goto bailout; - } - - /* now that we've added the auth, remember to remove it if we have to - * abort the request for some reason (like allocation failure) - */ - removeAuth = TRUE; - - /* associate additional information with this auth ID */ - - pAuth = xalloc(sizeof(SecurityAuthorizationRec)); - if (!pAuth) - { - err = BadAlloc; - goto bailout; - } - - /* fill in the auth fields */ - - pAuth->id = authId; - pAuth->timeout = timeout; - pAuth->group = group; - pAuth->trustLevel = trustLevel; - pAuth->refcnt = 0; /* the auth was just created; nobody's using it yet */ - pAuth->secondsRemaining = 0; - pAuth->timer = NULL; - pAuth->eventClients = NULL; - - /* handle event selection */ - if (eventMask) - { - err = SecurityEventSelectForAuthorization(pAuth, client, eventMask); - if (err != Success) - goto bailout; - } - - if (!AddResource(authId, SecurityAuthorizationResType, pAuth)) - { - err = BadAlloc; - goto bailout; - } - - /* start the timer ticking */ - - if (pAuth->timeout != 0) - SecurityStartAuthorizationTimer(pAuth); - - /* tell client the auth id and data */ - - rep.type = X_Reply; - rep.length = bytes_to_int32(authdata_len); - rep.sequenceNumber = client->sequence; - rep.authId = authId; - rep.dataLength = authdata_len; - - if (client->swapped) - { - char n; - swapl(&rep.length, n); - swaps(&rep.sequenceNumber, n); - swapl(&rep.authId, n); - swaps(&rep.dataLength, n); - } - - WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply), - (char *)&rep); - WriteToClient(client, authdata_len, pAuthdata); - - SecurityAudit("client %d generated authorization %d trust %d timeout %d group %d events %d\n", - client->index, pAuth->id, pAuth->trustLevel, pAuth->timeout, - pAuth->group, eventMask); - - /* the request succeeded; don't call RemoveAuthorization or free pAuth */ - - removeAuth = FALSE; - pAuth = NULL; - err = client->noClientException; - -bailout: - if (removeAuth) - RemoveAuthorization(stuff->nbytesAuthProto, protoname, - authdata_len, pAuthdata); - if (pAuth) xfree(pAuth); - return err; - -} /* ProcSecurityGenerateAuthorization */ - -static int -ProcSecurityRevokeAuthorization( - ClientPtr client) -{ - REQUEST(xSecurityRevokeAuthorizationReq); - SecurityAuthorizationPtr pAuth; - int rc; - - REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq); - - rc = dixLookupResourceByType((pointer *)&pAuth, stuff->authId, - SecurityAuthorizationResType, client, - DixDestroyAccess); - if (rc != Success) - return (rc == BadValue) ? - SecurityErrorBase + XSecurityBadAuthorization : rc; - - FreeResource(stuff->authId, RT_NONE); - return Success; -} /* ProcSecurityRevokeAuthorization */ - - -static int -ProcSecurityDispatch( - ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) - { - case X_SecurityQueryVersion: - return ProcSecurityQueryVersion(client); - case X_SecurityGenerateAuthorization: - return ProcSecurityGenerateAuthorization(client); - case X_SecurityRevokeAuthorization: - return ProcSecurityRevokeAuthorization(client); - default: - return BadRequest; - } -} /* ProcSecurityDispatch */ - -static int -SProcSecurityQueryVersion( - ClientPtr client) -{ - REQUEST(xSecurityQueryVersionReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xSecurityQueryVersionReq); - swaps(&stuff->majorVersion, n); - swaps(&stuff->minorVersion,n); - return ProcSecurityQueryVersion(client); -} /* SProcSecurityQueryVersion */ - - -static int -SProcSecurityGenerateAuthorization( - ClientPtr client) -{ - REQUEST(xSecurityGenerateAuthorizationReq); - char n; - CARD32 *values; - unsigned long nvalues; - int values_offset; - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq); - swaps(&stuff->nbytesAuthProto, n); - swaps(&stuff->nbytesAuthData, n); - swapl(&stuff->valueMask, n); - values_offset = bytes_to_int32(stuff->nbytesAuthProto) + - bytes_to_int32(stuff->nbytesAuthData); - if (values_offset > - stuff->length - bytes_to_int32(sz_xSecurityGenerateAuthorizationReq)) - return BadLength; - values = (CARD32 *)(&stuff[1]) + values_offset; - nvalues = (((CARD32 *)stuff) + stuff->length) - values; - SwapLongs(values, nvalues); - return ProcSecurityGenerateAuthorization(client); -} /* SProcSecurityGenerateAuthorization */ - - -static int -SProcSecurityRevokeAuthorization( - ClientPtr client) -{ - REQUEST(xSecurityRevokeAuthorizationReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq); - swapl(&stuff->authId, n); - return ProcSecurityRevokeAuthorization(client); -} /* SProcSecurityRevokeAuthorization */ - - -static int -SProcSecurityDispatch( - ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) - { - case X_SecurityQueryVersion: - return SProcSecurityQueryVersion(client); - case X_SecurityGenerateAuthorization: - return SProcSecurityGenerateAuthorization(client); - case X_SecurityRevokeAuthorization: - return SProcSecurityRevokeAuthorization(client); - default: - return BadRequest; - } -} /* SProcSecurityDispatch */ - -static void -SwapSecurityAuthorizationRevokedEvent( - xSecurityAuthorizationRevokedEvent *from, - xSecurityAuthorizationRevokedEvent *to) -{ - to->type = from->type; - to->detail = from->detail; - cpswaps(from->sequenceNumber, to->sequenceNumber); - cpswapl(from->authId, to->authId); -} - -/* SecurityCheckDeviceAccess - * - * Arguments: - * client is the client attempting to access a device. - * dev is the device being accessed. - * fromRequest is TRUE if the device access is a direct result of - * the client executing some request and FALSE if it is a - * result of the server trying to send an event (e.g. KeymapNotify) - * to the client. - * Returns: - * TRUE if the device access should be allowed, else FALSE. - * - * Side Effects: - * An audit message is generated if access is denied. - */ - -static void -SecurityDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceDeviceAccessRec *rec = calldata; - SecurityStateRec *subj, *obj; - Mask requested = rec->access_mode; - Mask allowed = SecurityDeviceMask; - - subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); - obj = dixLookupPrivate(&serverClient->devPrivates, stateKey); - - if (rec->dev != inputInfo.keyboard) - /* this extension only supports the core keyboard */ - allowed = requested; - - if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { - SecurityAudit("Security denied client %d keyboard access on request " - "%s\n", rec->client->index, - SecurityLookupRequestName(rec->client)); - rec->status = BadAccess; - } -} - -/* SecurityResource - * - * This function gets plugged into client->CheckAccess and is called from - * SecurityLookupIDByType/Class to determine if the client can access the - * resource. - * - * Arguments: - * client is the client doing the resource access. - * id is the resource id. - * rtype is its type or class. - * access_mode represents the intended use of the resource; see - * resource.h. - * res is a pointer to the resource structure for this resource. - * - * Returns: - * If access is granted, the value of rval that was passed in, else FALSE. - * - * Side Effects: - * Disallowed resource accesses are audited. - */ - -static void -SecurityResource(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceResourceAccessRec *rec = calldata; - SecurityStateRec *subj, *obj; - int cid = CLIENT_ID(rec->id); - Mask requested = rec->access_mode; - Mask allowed = SecurityResourceMask; - - subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); - obj = dixLookupPrivate(&clients[cid]->devPrivates, stateKey); - - /* disable background None for untrusted windows */ - if ((requested & DixCreateAccess) && (rec->rtype == RT_WINDOW)) - if (subj->haveState && subj->trustLevel != XSecurityClientTrusted) - ((WindowPtr)rec->res)->forcedBG = TRUE; - - /* additional permissions for specific resource types */ - if (rec->rtype == RT_WINDOW) - allowed |= SecurityWindowExtraMask; - - /* special checks for server-owned resources */ - if (cid == 0) { - if (rec->rtype & RC_DRAWABLE) - /* additional operations allowed on root windows */ - allowed |= SecurityRootWindowExtraMask; - - else if (rec->rtype == RT_COLORMAP) - /* allow access to default colormaps */ - allowed = requested; - - else - /* allow read access to other server-owned resources */ - allowed |= DixReadAccess; - } - - if (SecurityDoCheck(subj, obj, requested, allowed) == Success) - return; - - SecurityAudit("Security: denied client %d access %x to resource 0x%x " - "of client %d on request %s\n", rec->client->index, - requested, rec->id, cid, - SecurityLookupRequestName(rec->client)); - rec->status = BadAccess; /* deny access */ -} - - -static void -SecurityExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceExtAccessRec *rec = calldata; - SecurityStateRec *subj; - int i = 0; - - subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); - - if (subj->haveState && subj->trustLevel == XSecurityClientTrusted) - return; - - while (SecurityTrustedExtensions[i]) - if (!strcmp(SecurityTrustedExtensions[i++], rec->ext->name)) - return; - - SecurityAudit("Security: denied client %d access to extension " - "%s on request %s\n", - rec->client->index, rec->ext->name, - SecurityLookupRequestName(rec->client)); - rec->status = BadAccess; -} - -static void -SecurityServer(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceServerAccessRec *rec = calldata; - SecurityStateRec *subj, *obj; - Mask requested = rec->access_mode; - Mask allowed = SecurityServerMask; - - subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); - obj = dixLookupPrivate(&serverClient->devPrivates, stateKey); - - if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { - SecurityAudit("Security: denied client %d access to server " - "configuration request %s\n", rec->client->index, - SecurityLookupRequestName(rec->client)); - rec->status = BadAccess; - } -} - -static void -SecurityClient(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceClientAccessRec *rec = calldata; - SecurityStateRec *subj, *obj; - Mask requested = rec->access_mode; - Mask allowed = SecurityClientMask; - - subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); - obj = dixLookupPrivate(&rec->target->devPrivates, stateKey); - - if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { - SecurityAudit("Security: denied client %d access to client %d on " - "request %s\n", rec->client->index, rec->target->index, - SecurityLookupRequestName(rec->client)); - rec->status = BadAccess; - } -} - -static void -SecurityProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XacePropertyAccessRec *rec = calldata; - SecurityStateRec *subj, *obj; - ATOM name = (*rec->ppProp)->propertyName; - Mask requested = rec->access_mode; - Mask allowed = SecurityResourceMask | DixReadAccess; - - subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); - obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); - - if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { - SecurityAudit("Security: denied client %d access to property %s " - "(atom 0x%x) window 0x%x of client %d on request %s\n", - rec->client->index, NameForAtom(name), name, - rec->pWin->drawable.id, wClient(rec->pWin)->index, - SecurityLookupRequestName(rec->client)); - rec->status = BadAccess; - } -} - -static void -SecuritySend(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceSendAccessRec *rec = calldata; - SecurityStateRec *subj, *obj; - - if (rec->client) { - int i; - - subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); - obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); - - if (SecurityDoCheck(subj, obj, DixSendAccess, 0) == Success) - return; - - for (i = 0; i < rec->count; i++) - if (rec->events[i].u.u.type != UnmapNotify && - rec->events[i].u.u.type != ConfigureRequest && - rec->events[i].u.u.type != ClientMessage) { - - SecurityAudit("Security: denied client %d from sending event " - "of type %s to window 0x%x of client %d\n", - rec->client->index, - LookupEventName(rec->events[i].u.u.type), - rec->pWin->drawable.id, - wClient(rec->pWin)->index); - rec->status = BadAccess; - return; - } - } -} - -static void -SecurityReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceReceiveAccessRec *rec = calldata; - SecurityStateRec *subj, *obj; - - subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); - obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); - - if (SecurityDoCheck(subj, obj, DixReceiveAccess, 0) == Success) - return; - - SecurityAudit("Security: denied client %d from receiving an event " - "sent to window 0x%x of client %d\n", - rec->client->index, rec->pWin->drawable.id, - wClient(rec->pWin)->index); - rec->status = BadAccess; -} - -/* SecurityClientStateCallback - * - * Arguments: - * pcbl is &ClientStateCallback. - * nullata is NULL. - * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h) - * which contains information about client state changes. - * - * Returns: nothing. - * - * Side Effects: - * - * If a new client is connecting, its authorization ID is copied to - * client->authID. If this is a generated authorization, its reference - * count is bumped, its timer is cancelled if it was running, and its - * trustlevel is copied to TRUSTLEVEL(client). - * - * If a client is disconnecting and the client was using a generated - * authorization, the authorization's reference count is decremented, and - * if it is now zero, the timer for this authorization is started. - */ - -static void -SecurityClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - NewClientInfoRec *pci = calldata; - SecurityStateRec *state; - SecurityAuthorizationPtr pAuth; - int rc; - - state = dixLookupPrivate(&pci->client->devPrivates, stateKey); - - switch (pci->client->clientState) { - case ClientStateInitial: - state->trustLevel = XSecurityClientTrusted; - state->authId = None; - state->haveState = TRUE; - break; - - case ClientStateRunning: - state->authId = AuthorizationIDOfClient(pci->client); - rc = dixLookupResourceByType((pointer *)&pAuth, state->authId, - SecurityAuthorizationResType, serverClient, - DixGetAttrAccess); - if (rc == Success) { - /* it is a generated authorization */ - pAuth->refcnt++; - if (pAuth->refcnt == 1 && pAuth->timer) - TimerCancel(pAuth->timer); - - state->trustLevel = pAuth->trustLevel; - } - break; - - case ClientStateGone: - case ClientStateRetained: - rc = dixLookupResourceByType((pointer *)&pAuth, state->authId, - SecurityAuthorizationResType, serverClient, - DixGetAttrAccess); - if (rc == Success) { - /* it is a generated authorization */ - pAuth->refcnt--; - if (pAuth->refcnt == 0) - SecurityStartAuthorizationTimer(pAuth); - } - break; - - default: - break; - } -} - -/* SecurityResetProc - * - * Arguments: - * extEntry is the extension information for the security extension. - * - * Returns: nothing. - * - * Side Effects: - * Performs any cleanup needed by Security at server shutdown time. - */ - -static void -SecurityResetProc( - ExtensionEntry *extEntry) -{ - /* Unregister callbacks */ - DeleteCallback(&ClientStateCallback, SecurityClientState, NULL); - - XaceDeleteCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL); - XaceDeleteCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL); - XaceDeleteCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL); - XaceDeleteCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL); - XaceDeleteCallback(XACE_SEND_ACCESS, SecuritySend, NULL); - XaceDeleteCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL); - XaceDeleteCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL); - XaceDeleteCallback(XACE_EXT_ACCESS, SecurityExtension, NULL); - XaceDeleteCallback(XACE_SERVER_ACCESS, SecurityServer, NULL); -} - - -/* SecurityExtensionInit - * - * Arguments: none. - * - * Returns: nothing. - * - * Side Effects: - * Enables the Security extension if possible. - */ - -void -SecurityExtensionInit(INITARGS) -{ - ExtensionEntry *extEntry; - int ret = TRUE; - - SecurityAuthorizationResType = - CreateNewResourceType(SecurityDeleteAuthorization, - "SecurityAuthorization"); - - RTEventClient = - CreateNewResourceType(SecurityDeleteAuthorizationEventClient, - "SecurityEventClient"); - - if (!SecurityAuthorizationResType || !RTEventClient) - return; - - RTEventClient |= RC_NEVERRETAIN; - - /* Allocate the private storage */ - if (!dixRequestPrivate(stateKey, sizeof(SecurityStateRec))) - FatalError("SecurityExtensionSetup: Can't allocate client private.\n"); - - /* Register callbacks */ - ret &= AddCallback(&ClientStateCallback, SecurityClientState, NULL); - - ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL); - ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL); - ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL); - ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL); - ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SecuritySend, NULL); - ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL); - ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL); - ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SecurityExtension, NULL); - ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SecurityServer, NULL); - - if (!ret) - FatalError("SecurityExtensionSetup: Failed to register callbacks\n"); - - /* Add extension to server */ - extEntry = AddExtension(SECURITY_EXTENSION_NAME, - XSecurityNumberEvents, XSecurityNumberErrors, - ProcSecurityDispatch, SProcSecurityDispatch, - SecurityResetProc, StandardMinorOpcode); - - SecurityErrorBase = extEntry->errorBase; - SecurityEventBase = extEntry->eventBase; - - EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] = - (EventSwapPtr)SwapSecurityAuthorizationRevokedEvent; - - /* Label objects that were created before we could register ourself */ - SecurityLabelInitial(); -} +/* + +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 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 "scrnintstr.h" +#include "inputstr.h" +#include "windowstr.h" +#include "propertyst.h" +#include "colormapst.h" +#include "privates.h" +#include "registry.h" +#include "xacestr.h" +#include "securitysrv.h" +#include +#include "modinit.h" +#include "protocol-versions.h" + +/* Extension stuff */ +static int SecurityErrorBase; /* first Security error number */ +static int SecurityEventBase; /* first Security event number */ + +RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */ +static RESTYPE RTEventClient; + +static CallbackListPtr SecurityValidateGroupCallback = NULL; + +/* Private state record */ +static int stateKeyIndex; +static DevPrivateKey stateKey = &stateKeyIndex; + +/* This is what we store as client security state */ +typedef struct { + int haveState; + unsigned int trustLevel; + XID authId; +} SecurityStateRec; + +/* Extensions that untrusted clients shouldn't have access to */ +static char *SecurityTrustedExtensions[] = { + "XC-MISC", + "BIG-REQUESTS", + "XpExtension", + NULL +}; + +/* + * Access modes that untrusted clients are allowed on trusted objects. + */ +static const Mask SecurityResourceMask = + DixGetAttrAccess | DixReceiveAccess | DixListPropAccess | + DixGetPropAccess | DixListAccess; +static const Mask SecurityWindowExtraMask = DixRemoveAccess; +static const Mask SecurityRootWindowExtraMask = + DixReceiveAccess | DixSendAccess | DixAddAccess | DixRemoveAccess; +static const Mask SecurityDeviceMask = + DixGetAttrAccess | DixReceiveAccess | DixGetFocusAccess | + DixGrabAccess | DixSetAttrAccess | DixUseAccess; +static const Mask SecurityServerMask = DixGetAttrAccess | DixGrabAccess; +static const Mask SecurityClientMask = DixGetAttrAccess; + + +/* SecurityAudit + * + * Arguments: + * format is the formatting string to be used to interpret the + * remaining arguments. + * + * Returns: nothing. + * + * Side Effects: + * Writes the message to the log file if security logging is on. + */ + +static void +SecurityAudit(char *format, ...) +{ + va_list args; + + if (auditTrailLevel < SECURITY_AUDIT_LEVEL) + return; + va_start(args, format); + VAuditF(format, args); + va_end(args); +} /* SecurityAudit */ + +/* + * Performs a Security permission check. + */ +static int +SecurityDoCheck(SecurityStateRec *subj, SecurityStateRec *obj, + Mask requested, Mask allowed) +{ + if (!subj->haveState || !obj->haveState) + return Success; + if (subj->trustLevel == XSecurityClientTrusted) + return Success; + if (obj->trustLevel != XSecurityClientTrusted) + return Success; + if ((requested | allowed) == allowed) + return Success; + + return BadAccess; +} + +/* + * Labels initial server objects. + */ +static void +SecurityLabelInitial(void) +{ + SecurityStateRec *state; + + /* Do the serverClient */ + state = dixLookupPrivate(&serverClient->devPrivates, stateKey); + state->trustLevel = XSecurityClientTrusted; + state->haveState = TRUE; +} + +/* + * Looks up a request name + */ +static _X_INLINE const char * +SecurityLookupRequestName(ClientPtr client) +{ + int major = ((xReq *)client->requestBuffer)->reqType; + int minor = MinorOpcodeOfRequest(client); + return LookupRequestName(major, minor); +} + + +#define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) + +/* SecurityDeleteAuthorization + * + * Arguments: + * value is the authorization to delete. + * id is its resource ID. + * + * Returns: Success. + * + * Side Effects: + * Frees everything associated with the authorization. + */ + +static int +SecurityDeleteAuthorization( + pointer value, + XID id) +{ + SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value; + unsigned short name_len, data_len; + char *name, *data; + int status; + int i; + OtherClientsPtr pEventClient; + + /* Remove the auth using the os layer auth manager */ + + status = AuthorizationFromID(pAuth->id, &name_len, &name, + &data_len, &data); + assert(status); + status = RemoveAuthorization(name_len, name, data_len, data); + assert(status); + (void)status; + + /* free the auth timer if there is one */ + + if (pAuth->timer) TimerFree(pAuth->timer); + + /* send revoke events */ + + while ((pEventClient = pAuth->eventClients)) + { + /* send revocation event event */ + ClientPtr client = rClient(pEventClient); + + if (!client->clientGone) + { + xSecurityAuthorizationRevokedEvent are; + are.type = SecurityEventBase + XSecurityAuthorizationRevoked; + are.sequenceNumber = client->sequence; + are.authId = pAuth->id; + WriteEventsToClient(client, 1, (xEvent *)&are); + } + FreeResource(pEventClient->resource, RT_NONE); + } + + /* kill all clients using this auth */ + + for (i = 1; idevPrivates, stateKey); + if (state->haveState && state->authId == pAuth->id) + CloseDownClient(clients[i]); + } + + SecurityAudit("revoked authorization ID %d\n", pAuth->id); + free(pAuth); + return Success; + +} /* SecurityDeleteAuthorization */ + + +/* resource delete function for RTEventClient */ +static int +SecurityDeleteAuthorizationEventClient( + pointer value, + XID id) +{ + OtherClientsPtr pEventClient, prev = NULL; + SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value; + + for (pEventClient = pAuth->eventClients; + pEventClient; + pEventClient = pEventClient->next) + { + if (pEventClient->resource == id) + { + if (prev) + prev->next = pEventClient->next; + else + pAuth->eventClients = pEventClient->next; + free(pEventClient); + return(Success); + } + prev = pEventClient; + } + /*NOTREACHED*/ + return -1; /* make compiler happy */ +} /* SecurityDeleteAuthorizationEventClient */ + + +/* SecurityComputeAuthorizationTimeout + * + * Arguments: + * pAuth is the authorization for which we are computing the timeout + * seconds is the number of seconds we want to wait + * + * Returns: + * the number of milliseconds that the auth timer should be set to + * + * Side Effects: + * Sets pAuth->secondsRemaining to any "overflow" amount of time + * that didn't fit in 32 bits worth of milliseconds + */ + +static CARD32 +SecurityComputeAuthorizationTimeout( + SecurityAuthorizationPtr pAuth, + unsigned int seconds) +{ + /* maxSecs is the number of full seconds that can be expressed in + * 32 bits worth of milliseconds + */ + CARD32 maxSecs = (CARD32)(~0) / (CARD32)MILLI_PER_SECOND; + + if (seconds > maxSecs) + { /* only come here if we want to wait more than 49 days */ + pAuth->secondsRemaining = seconds - maxSecs; + return maxSecs * MILLI_PER_SECOND; + } + else + { /* by far the common case */ + pAuth->secondsRemaining = 0; + return seconds * MILLI_PER_SECOND; + } +} /* SecurityStartAuthorizationTimer */ + +/* SecurityAuthorizationExpired + * + * This function is passed as an argument to TimerSet and gets called from + * the timer manager in the os layer when its time is up. + * + * Arguments: + * timer is the timer for this authorization. + * time is the current time. + * pval is the authorization whose time is up. + * + * Returns: + * A new time delay in milliseconds if the timer should wait some + * more, else zero. + * + * Side Effects: + * Frees the authorization resource if the timeout period is really + * over, otherwise recomputes pAuth->secondsRemaining. + */ + +static CARD32 +SecurityAuthorizationExpired( + OsTimerPtr timer, + CARD32 time, + pointer pval) +{ + SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)pval; + + assert(pAuth->timer == timer); + + if (pAuth->secondsRemaining) + { + return SecurityComputeAuthorizationTimeout(pAuth, + pAuth->secondsRemaining); + } + else + { + FreeResource(pAuth->id, RT_NONE); + return 0; + } +} /* SecurityAuthorizationExpired */ + +/* SecurityStartAuthorizationTimer + * + * Arguments: + * pAuth is the authorization whose timer should be started. + * + * Returns: nothing. + * + * Side Effects: + * A timer is started, set to expire after the timeout period for + * this authorization. When it expires, the function + * SecurityAuthorizationExpired will be called. + */ + +static void +SecurityStartAuthorizationTimer( + SecurityAuthorizationPtr pAuth) +{ + pAuth->timer = TimerSet(pAuth->timer, 0, + SecurityComputeAuthorizationTimeout(pAuth, pAuth->timeout), + SecurityAuthorizationExpired, pAuth); +} /* SecurityStartAuthorizationTimer */ + + +/* Proc functions all take a client argument, execute the request in + * client->requestBuffer, and return a protocol error status. + */ + +static int +ProcSecurityQueryVersion( + ClientPtr client) +{ + /* REQUEST(xSecurityQueryVersionReq); */ + xSecurityQueryVersionReply rep; + + REQUEST_SIZE_MATCH(xSecurityQueryVersionReq); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.majorVersion = SERVER_SECURITY_MAJOR_VERSION; + rep.minorVersion = SERVER_SECURITY_MINOR_VERSION; + if(client->swapped) + { + char n; + swaps(&rep.sequenceNumber, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + (void)WriteToClient(client, SIZEOF(xSecurityQueryVersionReply), + (char *)&rep); + return Success; +} /* ProcSecurityQueryVersion */ + + +static int +SecurityEventSelectForAuthorization( + SecurityAuthorizationPtr pAuth, + ClientPtr client, + Mask mask) +{ + OtherClients *pEventClient; + + for (pEventClient = pAuth->eventClients; + pEventClient; + pEventClient = pEventClient->next) + { + if (SameClient(pEventClient, client)) + { + if (mask == 0) + FreeResource(pEventClient->resource, RT_NONE); + else + pEventClient->mask = mask; + return Success; + } + } + + pEventClient = malloc(sizeof(OtherClients)); + if (!pEventClient) + return BadAlloc; + pEventClient->mask = mask; + pEventClient->resource = FakeClientID(client->index); + pEventClient->next = pAuth->eventClients; + if (!AddResource(pEventClient->resource, RTEventClient, + (pointer)pAuth)) + { + free(pEventClient); + return BadAlloc; + } + pAuth->eventClients = pEventClient; + + return Success; +} /* SecurityEventSelectForAuthorization */ + + +static int +ProcSecurityGenerateAuthorization( + ClientPtr client) +{ + REQUEST(xSecurityGenerateAuthorizationReq); + int len; /* request length in CARD32s*/ + Bool removeAuth = FALSE; /* if bailout, call RemoveAuthorization? */ + SecurityAuthorizationPtr pAuth = NULL; /* auth we are creating */ + int err; /* error to return from this function */ + XID authId; /* authorization ID assigned by os layer */ + xSecurityGenerateAuthorizationReply rep; /* reply struct */ + unsigned int trustLevel; /* trust level of new auth */ + XID group; /* group of new auth */ + CARD32 timeout; /* timeout of new auth */ + CARD32 *values; /* list of supplied attributes */ + char *protoname; /* auth proto name sent in request */ + char *protodata; /* auth proto data sent in request */ + unsigned int authdata_len; /* # bytes of generated auth data */ + char *pAuthdata; /* generated auth data */ + Mask eventMask; /* what events on this auth does client want */ + + /* check request length */ + + REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq); + len = bytes_to_int32(SIZEOF(xSecurityGenerateAuthorizationReq)); + len += bytes_to_int32(stuff->nbytesAuthProto); + len += bytes_to_int32(stuff->nbytesAuthData); + values = ((CARD32 *)stuff) + len; + len += Ones(stuff->valueMask); + if (client->req_len != len) + return BadLength; + + /* check valuemask */ + if (stuff->valueMask & ~XSecurityAllAuthorizationAttributes) + { + client->errorValue = stuff->valueMask; + return BadValue; + } + + /* check timeout */ + timeout = 60; + if (stuff->valueMask & XSecurityTimeout) + { + timeout = *values++; + } + + /* check trustLevel */ + trustLevel = XSecurityClientUntrusted; + if (stuff->valueMask & XSecurityTrustLevel) + { + trustLevel = *values++; + if (trustLevel != XSecurityClientTrusted && + trustLevel != XSecurityClientUntrusted) + { + client->errorValue = trustLevel; + return BadValue; + } + } + + /* check group */ + group = None; + if (stuff->valueMask & XSecurityGroup) + { + group = *values++; + if (SecurityValidateGroupCallback) + { + SecurityValidateGroupInfoRec vgi; + vgi.group = group; + vgi.valid = FALSE; + CallCallbacks(&SecurityValidateGroupCallback, (pointer)&vgi); + + /* if nobody said they recognized it, it's an error */ + + if (!vgi.valid) + { + client->errorValue = group; + return BadValue; + } + } + } + + /* check event mask */ + eventMask = 0; + if (stuff->valueMask & XSecurityEventMask) + { + eventMask = *values++; + if (eventMask & ~XSecurityAllEventMasks) + { + client->errorValue = eventMask; + return BadValue; + } + } + + protoname = (char *)&stuff[1]; + protodata = protoname + bytes_to_int32(stuff->nbytesAuthProto); + + /* call os layer to generate the authorization */ + + authId = GenerateAuthorization(stuff->nbytesAuthProto, protoname, + stuff->nbytesAuthData, protodata, + &authdata_len, &pAuthdata); + if ((XID) ~0L == authId) + { + err = SecurityErrorBase + XSecurityBadAuthorizationProtocol; + goto bailout; + } + + /* now that we've added the auth, remember to remove it if we have to + * abort the request for some reason (like allocation failure) + */ + removeAuth = TRUE; + + /* associate additional information with this auth ID */ + + pAuth = malloc(sizeof(SecurityAuthorizationRec)); + if (!pAuth) + { + err = BadAlloc; + goto bailout; + } + + /* fill in the auth fields */ + + pAuth->id = authId; + pAuth->timeout = timeout; + pAuth->group = group; + pAuth->trustLevel = trustLevel; + pAuth->refcnt = 0; /* the auth was just created; nobody's using it yet */ + pAuth->secondsRemaining = 0; + pAuth->timer = NULL; + pAuth->eventClients = NULL; + + /* handle event selection */ + if (eventMask) + { + err = SecurityEventSelectForAuthorization(pAuth, client, eventMask); + if (err != Success) + goto bailout; + } + + if (!AddResource(authId, SecurityAuthorizationResType, pAuth)) + { + err = BadAlloc; + goto bailout; + } + + /* start the timer ticking */ + + if (pAuth->timeout != 0) + SecurityStartAuthorizationTimer(pAuth); + + /* tell client the auth id and data */ + + rep.type = X_Reply; + rep.length = bytes_to_int32(authdata_len); + rep.sequenceNumber = client->sequence; + rep.authId = authId; + rep.dataLength = authdata_len; + + if (client->swapped) + { + char n; + swapl(&rep.length, n); + swaps(&rep.sequenceNumber, n); + swapl(&rep.authId, n); + swaps(&rep.dataLength, n); + } + + WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply), + (char *)&rep); + WriteToClient(client, authdata_len, pAuthdata); + + SecurityAudit("client %d generated authorization %d trust %d timeout %d group %d events %d\n", + client->index, pAuth->id, pAuth->trustLevel, pAuth->timeout, + pAuth->group, eventMask); + + /* the request succeeded; don't call RemoveAuthorization or free pAuth */ + return Success; + +bailout: + if (removeAuth) + RemoveAuthorization(stuff->nbytesAuthProto, protoname, + authdata_len, pAuthdata); + if (pAuth) free(pAuth); + return err; + +} /* ProcSecurityGenerateAuthorization */ + +static int +ProcSecurityRevokeAuthorization( + ClientPtr client) +{ + REQUEST(xSecurityRevokeAuthorizationReq); + SecurityAuthorizationPtr pAuth; + int rc; + + REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq); + + rc = dixLookupResourceByType((pointer *)&pAuth, stuff->authId, + SecurityAuthorizationResType, client, + DixDestroyAccess); + if (rc != Success) + return (rc == BadValue) ? + SecurityErrorBase + XSecurityBadAuthorization : rc; + + FreeResource(stuff->authId, RT_NONE); + return Success; +} /* ProcSecurityRevokeAuthorization */ + + +static int +ProcSecurityDispatch( + ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_SecurityQueryVersion: + return ProcSecurityQueryVersion(client); + case X_SecurityGenerateAuthorization: + return ProcSecurityGenerateAuthorization(client); + case X_SecurityRevokeAuthorization: + return ProcSecurityRevokeAuthorization(client); + default: + return BadRequest; + } +} /* ProcSecurityDispatch */ + +static int +SProcSecurityQueryVersion( + ClientPtr client) +{ + REQUEST(xSecurityQueryVersionReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xSecurityQueryVersionReq); + swaps(&stuff->majorVersion, n); + swaps(&stuff->minorVersion,n); + return ProcSecurityQueryVersion(client); +} /* SProcSecurityQueryVersion */ + + +static int +SProcSecurityGenerateAuthorization( + ClientPtr client) +{ + REQUEST(xSecurityGenerateAuthorizationReq); + char n; + CARD32 *values; + unsigned long nvalues; + int values_offset; + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq); + swaps(&stuff->nbytesAuthProto, n); + swaps(&stuff->nbytesAuthData, n); + swapl(&stuff->valueMask, n); + values_offset = bytes_to_int32(stuff->nbytesAuthProto) + + bytes_to_int32(stuff->nbytesAuthData); + if (values_offset > + stuff->length - bytes_to_int32(sz_xSecurityGenerateAuthorizationReq)) + return BadLength; + values = (CARD32 *)(&stuff[1]) + values_offset; + nvalues = (((CARD32 *)stuff) + stuff->length) - values; + SwapLongs(values, nvalues); + return ProcSecurityGenerateAuthorization(client); +} /* SProcSecurityGenerateAuthorization */ + + +static int +SProcSecurityRevokeAuthorization( + ClientPtr client) +{ + REQUEST(xSecurityRevokeAuthorizationReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq); + swapl(&stuff->authId, n); + return ProcSecurityRevokeAuthorization(client); +} /* SProcSecurityRevokeAuthorization */ + + +static int +SProcSecurityDispatch( + ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_SecurityQueryVersion: + return SProcSecurityQueryVersion(client); + case X_SecurityGenerateAuthorization: + return SProcSecurityGenerateAuthorization(client); + case X_SecurityRevokeAuthorization: + return SProcSecurityRevokeAuthorization(client); + default: + return BadRequest; + } +} /* SProcSecurityDispatch */ + +static void +SwapSecurityAuthorizationRevokedEvent( + xSecurityAuthorizationRevokedEvent *from, + xSecurityAuthorizationRevokedEvent *to) +{ + to->type = from->type; + to->detail = from->detail; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->authId, to->authId); +} + +/* SecurityCheckDeviceAccess + * + * Arguments: + * client is the client attempting to access a device. + * dev is the device being accessed. + * fromRequest is TRUE if the device access is a direct result of + * the client executing some request and FALSE if it is a + * result of the server trying to send an event (e.g. KeymapNotify) + * to the client. + * Returns: + * TRUE if the device access should be allowed, else FALSE. + * + * Side Effects: + * An audit message is generated if access is denied. + */ + +static void +SecurityDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceDeviceAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + Mask requested = rec->access_mode; + Mask allowed = SecurityDeviceMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&serverClient->devPrivates, stateKey); + + if (rec->dev != inputInfo.keyboard) + /* this extension only supports the core keyboard */ + allowed = requested; + + if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { + SecurityAudit("Security denied client %d keyboard access on request " + "%s\n", rec->client->index, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; + } +} + +/* SecurityResource + * + * This function gets plugged into client->CheckAccess and is called from + * SecurityLookupIDByType/Class to determine if the client can access the + * resource. + * + * Arguments: + * client is the client doing the resource access. + * id is the resource id. + * rtype is its type or class. + * access_mode represents the intended use of the resource; see + * resource.h. + * res is a pointer to the resource structure for this resource. + * + * Returns: + * If access is granted, the value of rval that was passed in, else FALSE. + * + * Side Effects: + * Disallowed resource accesses are audited. + */ + +static void +SecurityResource(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceResourceAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + int cid = CLIENT_ID(rec->id); + Mask requested = rec->access_mode; + Mask allowed = SecurityResourceMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&clients[cid]->devPrivates, stateKey); + + /* disable background None for untrusted windows */ + if ((requested & DixCreateAccess) && (rec->rtype == RT_WINDOW)) + if (subj->haveState && subj->trustLevel != XSecurityClientTrusted) + ((WindowPtr)rec->res)->forcedBG = TRUE; + + /* additional permissions for specific resource types */ + if (rec->rtype == RT_WINDOW) + allowed |= SecurityWindowExtraMask; + + /* special checks for server-owned resources */ + if (cid == 0) { + if (rec->rtype & RC_DRAWABLE) + /* additional operations allowed on root windows */ + allowed |= SecurityRootWindowExtraMask; + + else if (rec->rtype == RT_COLORMAP) + /* allow access to default colormaps */ + allowed = requested; + + else + /* allow read access to other server-owned resources */ + allowed |= DixReadAccess; + } + + if (SecurityDoCheck(subj, obj, requested, allowed) == Success) + return; + + SecurityAudit("Security: denied client %d access %x to resource 0x%x " + "of client %d on request %s\n", rec->client->index, + requested, rec->id, cid, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; /* deny access */ +} + + +static void +SecurityExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceExtAccessRec *rec = calldata; + SecurityStateRec *subj; + int i = 0; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + + if (subj->haveState && subj->trustLevel == XSecurityClientTrusted) + return; + + while (SecurityTrustedExtensions[i]) + if (!strcmp(SecurityTrustedExtensions[i++], rec->ext->name)) + return; + + SecurityAudit("Security: denied client %d access to extension " + "%s on request %s\n", + rec->client->index, rec->ext->name, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; +} + +static void +SecurityServer(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceServerAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + Mask requested = rec->access_mode; + Mask allowed = SecurityServerMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&serverClient->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { + SecurityAudit("Security: denied client %d access to server " + "configuration request %s\n", rec->client->index, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; + } +} + +static void +SecurityClient(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceClientAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + Mask requested = rec->access_mode; + Mask allowed = SecurityClientMask; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&rec->target->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { + SecurityAudit("Security: denied client %d access to client %d on " + "request %s\n", rec->client->index, rec->target->index, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; + } +} + +static void +SecurityProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XacePropertyAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + ATOM name = (*rec->ppProp)->propertyName; + Mask requested = rec->access_mode; + Mask allowed = SecurityResourceMask | DixReadAccess; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, requested, allowed) != Success) { + SecurityAudit("Security: denied client %d access to property %s " + "(atom 0x%x) window 0x%x of client %d on request %s\n", + rec->client->index, NameForAtom(name), name, + rec->pWin->drawable.id, wClient(rec->pWin)->index, + SecurityLookupRequestName(rec->client)); + rec->status = BadAccess; + } +} + +static void +SecuritySend(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceSendAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + + if (rec->client) { + int i; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, DixSendAccess, 0) == Success) + return; + + for (i = 0; i < rec->count; i++) + if (rec->events[i].u.u.type != UnmapNotify && + rec->events[i].u.u.type != ConfigureRequest && + rec->events[i].u.u.type != ClientMessage) { + + SecurityAudit("Security: denied client %d from sending event " + "of type %s to window 0x%x of client %d\n", + rec->client->index, + LookupEventName(rec->events[i].u.u.type), + rec->pWin->drawable.id, + wClient(rec->pWin)->index); + rec->status = BadAccess; + return; + } + } +} + +static void +SecurityReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceReceiveAccessRec *rec = calldata; + SecurityStateRec *subj, *obj; + + subj = dixLookupPrivate(&rec->client->devPrivates, stateKey); + obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey); + + if (SecurityDoCheck(subj, obj, DixReceiveAccess, 0) == Success) + return; + + SecurityAudit("Security: denied client %d from receiving an event " + "sent to window 0x%x of client %d\n", + rec->client->index, rec->pWin->drawable.id, + wClient(rec->pWin)->index); + rec->status = BadAccess; +} + +/* SecurityClientStateCallback + * + * Arguments: + * pcbl is &ClientStateCallback. + * nullata is NULL. + * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h) + * which contains information about client state changes. + * + * Returns: nothing. + * + * Side Effects: + * + * If a new client is connecting, its authorization ID is copied to + * client->authID. If this is a generated authorization, its reference + * count is bumped, its timer is cancelled if it was running, and its + * trustlevel is copied to TRUSTLEVEL(client). + * + * If a client is disconnecting and the client was using a generated + * authorization, the authorization's reference count is decremented, and + * if it is now zero, the timer for this authorization is started. + */ + +static void +SecurityClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + NewClientInfoRec *pci = calldata; + SecurityStateRec *state; + SecurityAuthorizationPtr pAuth; + int rc; + + state = dixLookupPrivate(&pci->client->devPrivates, stateKey); + + switch (pci->client->clientState) { + case ClientStateInitial: + state->trustLevel = XSecurityClientTrusted; + state->authId = None; + state->haveState = TRUE; + break; + + case ClientStateRunning: + state->authId = AuthorizationIDOfClient(pci->client); + rc = dixLookupResourceByType((pointer *)&pAuth, state->authId, + SecurityAuthorizationResType, serverClient, + DixGetAttrAccess); + if (rc == Success) { + /* it is a generated authorization */ + pAuth->refcnt++; + if (pAuth->refcnt == 1 && pAuth->timer) + TimerCancel(pAuth->timer); + + state->trustLevel = pAuth->trustLevel; + } + break; + + case ClientStateGone: + case ClientStateRetained: + rc = dixLookupResourceByType((pointer *)&pAuth, state->authId, + SecurityAuthorizationResType, serverClient, + DixGetAttrAccess); + if (rc == Success) { + /* it is a generated authorization */ + pAuth->refcnt--; + if (pAuth->refcnt == 0) + SecurityStartAuthorizationTimer(pAuth); + } + break; + + default: + break; + } +} + +/* SecurityResetProc + * + * Arguments: + * extEntry is the extension information for the security extension. + * + * Returns: nothing. + * + * Side Effects: + * Performs any cleanup needed by Security at server shutdown time. + */ + +static void +SecurityResetProc( + ExtensionEntry *extEntry) +{ + /* Unregister callbacks */ + DeleteCallback(&ClientStateCallback, SecurityClientState, NULL); + + XaceDeleteCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL); + XaceDeleteCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL); + XaceDeleteCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL); + XaceDeleteCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL); + XaceDeleteCallback(XACE_SEND_ACCESS, SecuritySend, NULL); + XaceDeleteCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL); + XaceDeleteCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL); + XaceDeleteCallback(XACE_EXT_ACCESS, SecurityExtension, NULL); + XaceDeleteCallback(XACE_SERVER_ACCESS, SecurityServer, NULL); +} + + +/* SecurityExtensionInit + * + * Arguments: none. + * + * Returns: nothing. + * + * Side Effects: + * Enables the Security extension if possible. + */ + +void +SecurityExtensionInit(INITARGS) +{ + ExtensionEntry *extEntry; + int ret = TRUE; + + SecurityAuthorizationResType = + CreateNewResourceType(SecurityDeleteAuthorization, + "SecurityAuthorization"); + + RTEventClient = + CreateNewResourceType(SecurityDeleteAuthorizationEventClient, + "SecurityEventClient"); + + if (!SecurityAuthorizationResType || !RTEventClient) + return; + + RTEventClient |= RC_NEVERRETAIN; + + /* Allocate the private storage */ + if (!dixRequestPrivate(stateKey, sizeof(SecurityStateRec))) + FatalError("SecurityExtensionSetup: Can't allocate client private.\n"); + + /* Register callbacks */ + ret &= AddCallback(&ClientStateCallback, SecurityClientState, NULL); + + ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SecurityExtension, NULL); + ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SecurityResource, NULL); + ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SecurityDevice, NULL); + ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SecurityProperty, NULL); + ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SecuritySend, NULL); + ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SecurityReceive, NULL); + ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SecurityClient, NULL); + ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SecurityExtension, NULL); + ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SecurityServer, NULL); + + if (!ret) + FatalError("SecurityExtensionSetup: Failed to register callbacks\n"); + + /* Add extension to server */ + extEntry = AddExtension(SECURITY_EXTENSION_NAME, + XSecurityNumberEvents, XSecurityNumberErrors, + ProcSecurityDispatch, SProcSecurityDispatch, + SecurityResetProc, StandardMinorOpcode); + + SecurityErrorBase = extEntry->errorBase; + SecurityEventBase = extEntry->eventBase; + + EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] = + (EventSwapPtr)SwapSecurityAuthorizationRevokedEvent; + + /* Label objects that were created before we could register ourself */ + SecurityLabelInitial(); +} diff --git a/xorg-server/Xext/shape.c b/xorg-server/Xext/shape.c index 58b5c23c0..edecc51ed 100644 --- a/xorg-server/Xext/shape.c +++ b/xorg-server/Xext/shape.c @@ -1,1293 +1,1293 @@ -/************************************************************ - -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" -#include -#include "regionstr.h" -#include "gcstruct.h" -#include "modinit.h" -#include "protocol-versions.h" - -typedef RegionPtr (*CreateDftPtr)( - WindowPtr /* pWin */ - ); - -static int ShapeFreeClient( - pointer /* data */, - XID /* id */ - ); -static int ShapeFreeEvents( - pointer /* data */, - XID /* id */ - ); -static void SShapeNotifyEvent( - xShapeNotifyEvent * /* from */, - xShapeNotifyEvent * /* to */ - ); - -/* 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); - -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif - -static int ShapeEventBase = 0; -static RESTYPE ClientType, ShapeEventType; /* 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, "ShapeClient"); - ShapeEventType = CreateNewResourceType(ShapeFreeEvents, "ShapeEvent"); - if (ClientType && ShapeEventType && - (extEntry = AddExtension(SHAPENAME, ShapeNumberEvents, 0, - ProcShapeDispatch, SProcShapeDispatch, - NULL, StandardMinorOpcode))) - { - ShapeEventBase = extEntry->eventBase; - EventSwapVector[ShapeEventBase] = (EventSwapPtr) SShapeNotifyEvent; - } -} - -static int -RegionOperate ( - ClientPtr client, - WindowPtr pWin, - int kind, - RegionPtr *destRgnp, - RegionPtr srcRgn, - int op, - int xoff, int yoff, - CreateDftPtr create) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - if (srcRgn && (xoff || yoff)) - REGION_TRANSLATE(pScreen, srcRgn, xoff, yoff); - if (!pWin->parent) - { - if (srcRgn) - REGION_DESTROY(pScreen, 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 (pScreen, *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(pScreen, *destRgnp); - *destRgnp = srcRgn; - srcRgn = 0; - break; - case ShapeUnion: - if (*destRgnp) - REGION_UNION(pScreen, *destRgnp, *destRgnp, srcRgn); - break; - case ShapeIntersect: - if (*destRgnp) - REGION_INTERSECT(pScreen, *destRgnp, *destRgnp, srcRgn); - else { - *destRgnp = srcRgn; - srcRgn = 0; - } - break; - case ShapeSubtract: - if (!*destRgnp) - *destRgnp = (*create)(pWin); - REGION_SUBTRACT(pScreen, *destRgnp, *destRgnp, srcRgn); - break; - case ShapeInvert: - if (!*destRgnp) - *destRgnp = REGION_CREATE(pScreen, (BoxPtr) 0, 0); - else - REGION_SUBTRACT(pScreen, *destRgnp, srcRgn, *destRgnp); - break; - default: - client->errorValue = op; - return BadValue; - } - if (srcRgn) - REGION_DESTROY(pScreen, srcRgn); - (*pScreen->SetShape) (pWin); - SendShapeNotify (pWin, kind); - return Success; -} - -RegionPtr -CreateBoundingShape (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(pWin->drawable.pScreen, &extents, 1); -} - -RegionPtr -CreateClipShape (WindowPtr pWin) -{ - BoxRec extents; - - extents.x1 = 0; - extents.y1 = 0; - extents.x2 = pWin->drawable.width; - extents.y2 = pWin->drawable.height; - return REGION_CREATE(pWin->drawable.pScreen, &extents, 1); -} - -static int -ProcShapeQueryVersion (ClientPtr client) -{ - xShapeQueryVersionReply rep; - int n; - - REQUEST_SIZE_MATCH (xShapeQueryVersionReq); - memset(&rep, 0, sizeof(xShapeQueryVersionReply)); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_SHAPE_MAJOR_VERSION; - rep.minorVersion = SERVER_SHAPE_MINOR_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof (xShapeQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -/***************** - * ProcShapeRectangles - * - *****************/ - -static int -ProcShapeRectangles (ClientPtr client) -{ - WindowPtr pWin; - ScreenPtr pScreen; - REQUEST(xShapeRectanglesReq); - xRectangle *prects; - int nrects, ctype, rc; - RegionPtr srcRgn; - RegionPtr *destRgn; - CreateDftPtr createDefault; - - REQUEST_AT_LEAST_SIZE (xShapeRectanglesReq); - UpdateCurrentTime(); - rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess); - if (rc != Success) - return rc; - 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; - } - pScreen = pWin->drawable.pScreen; - 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(pScreen, 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); -} - -#ifdef PANORAMIX -static int -ProcPanoramiXShapeRectangles( - ClientPtr client) -{ - REQUEST(xShapeRectanglesReq); - PanoramiXRes *win; - int j, result; - - REQUEST_AT_LEAST_SIZE (xShapeRectanglesReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->dest, XRT_WINDOW, - client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS(j) { - stuff->dest = win->info[j].id; - result = ProcShapeRectangles (client); - if (result != Success) break; - } - return (result); -} -#endif - - -/************** - * ProcShapeMask - **************/ - - -static int -ProcShapeMask (ClientPtr client) -{ - WindowPtr pWin; - ScreenPtr pScreen; - REQUEST(xShapeMaskReq); - RegionPtr srcRgn; - RegionPtr *destRgn; - PixmapPtr pPixmap; - CreateDftPtr createDefault; - int rc; - - REQUEST_SIZE_MATCH (xShapeMaskReq); - UpdateCurrentTime(); - rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess); - if (rc != Success) - return rc; - 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 { - rc = dixLookupResourceByType((pointer *)&pPixmap, stuff->src, RT_PIXMAP, - client, DixReadAccess); - if (rc != Success) - return (rc == BadValue) ? BadPixmap : rc; - 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); -} - -#ifdef PANORAMIX -static int -ProcPanoramiXShapeMask( - ClientPtr client) -{ - REQUEST(xShapeMaskReq); - PanoramiXRes *win, *pmap; - int j, result; - - REQUEST_SIZE_MATCH (xShapeMaskReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->dest, XRT_WINDOW, - client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - if(stuff->src != None) { - result = dixLookupResourceByType((pointer *)&pmap, stuff->src, - XRT_PIXMAP, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadPixmap : result; - } else - pmap = NULL; - - FOR_NSCREENS(j) { - stuff->dest = win->info[j].id; - if(pmap) - stuff->src = pmap->info[j].id; - result = ProcShapeMask (client); - if (result != Success) break; - } - return (result); -} -#endif - - -/************ - * ProcShapeCombine - ************/ - -static int -ProcShapeCombine (ClientPtr client) -{ - WindowPtr pSrcWin, pDestWin; - ScreenPtr pScreen; - REQUEST(xShapeCombineReq); - RegionPtr srcRgn; - RegionPtr *destRgn; - CreateDftPtr createDefault; - CreateDftPtr createSrc; - RegionPtr tmp; - int rc; - - REQUEST_SIZE_MATCH (xShapeCombineReq); - UpdateCurrentTime(); - rc = dixLookupWindow(&pDestWin, stuff->dest, client, DixSetAttrAccess); - if (rc != Success) - return rc; - 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; - - rc = dixLookupWindow(&pSrcWin, stuff->src, client, DixGetAttrAccess); - if (rc != Success) - return rc; - 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(pScreen, (BoxPtr) 0, 0); - REGION_COPY(pScreen, 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); -} - - -#ifdef PANORAMIX -static int -ProcPanoramiXShapeCombine( - ClientPtr client) -{ - REQUEST(xShapeCombineReq); - PanoramiXRes *win, *win2; - int j, result; - - REQUEST_AT_LEAST_SIZE (xShapeCombineReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->dest, XRT_WINDOW, - client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - result = dixLookupResourceByType((pointer *)&win2, stuff->src, XRT_WINDOW, - client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS(j) { - stuff->dest = win->info[j].id; - stuff->src = win2->info[j].id; - result = ProcShapeCombine (client); - if (result != Success) break; - } - return (result); -} -#endif - -/************* - * ProcShapeOffset - *************/ - -static int -ProcShapeOffset (ClientPtr client) -{ - WindowPtr pWin; - ScreenPtr pScreen; - REQUEST(xShapeOffsetReq); - RegionPtr srcRgn; - int rc; - - REQUEST_SIZE_MATCH (xShapeOffsetReq); - UpdateCurrentTime(); - rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess); - if (rc != Success) - return rc; - 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(pScreen, srcRgn, stuff->xOff, stuff->yOff); - (*pScreen->SetShape) (pWin); - } - SendShapeNotify (pWin, (int)stuff->destKind); - return Success; -} - - -#ifdef PANORAMIX -static int -ProcPanoramiXShapeOffset( - ClientPtr client) -{ - REQUEST(xShapeOffsetReq); - PanoramiXRes *win; - int j, result; - - REQUEST_AT_LEAST_SIZE (xShapeOffsetReq); - - result = dixLookupResourceByType((pointer *)&win, stuff->dest, XRT_WINDOW, - client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadWindow : result; - - FOR_NSCREENS(j) { - stuff->dest = win->info[j].id; - result = ProcShapeOffset (client); - if(result != Success) break; - } - return (result); -} -#endif - - -static int -ProcShapeQueryExtents (ClientPtr client) -{ - REQUEST(xShapeQueryExtentsReq); - WindowPtr pWin; - xShapeQueryExtentsReply rep; - BoxRec extents, *pExtents; - int n, rc; - RegionPtr region; - - REQUEST_SIZE_MATCH (xShapeQueryExtentsReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - memset(&rep, 0, sizeof(xShapeQueryExtentsReply)); - 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(pWin->drawable.pScreen, 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(pWin->drawable.pScreen, 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, n); - swapl(&rep.length, n); - swaps(&rep.xBoundingShape, n); - swaps(&rep.yBoundingShape, n); - swaps(&rep.widthBoundingShape, n); - swaps(&rep.heightBoundingShape, n); - swaps(&rep.xClipShape, n); - swaps(&rep.yClipShape, n); - swaps(&rep.widthClipShape, n); - swaps(&rep.heightClipShape, n); - } - WriteToClient(client, sizeof (xShapeQueryExtentsReply), (char *)&rep); - return (client->noClientException); -} - -/*ARGSUSED*/ -static int -ShapeFreeClient (pointer data, XID id) -{ - ShapeEventPtr pShapeEvent; - WindowPtr pWin; - ShapeEventPtr *pHead, pCur, pPrev; - int rc; - - pShapeEvent = (ShapeEventPtr) data; - pWin = pShapeEvent->window; - rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, - ShapeEventType, serverClient, DixReadAccess); - if (rc == Success) { - 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; - } - } - xfree ((pointer) pShapeEvent); - return 1; -} - -/*ARGSUSED*/ -static int -ShapeFreeEvents (pointer data, XID id) -{ - ShapeEventPtr *pHead, pCur, pNext; - - pHead = (ShapeEventPtr *) data; - for (pCur = *pHead; pCur; pCur = pNext) { - pNext = pCur->next; - FreeResource (pCur->clientResource, ClientType); - xfree ((pointer) pCur); - } - xfree ((pointer) pHead); - return 1; -} - -static int -ProcShapeSelectInput (ClientPtr client) -{ - REQUEST(xShapeSelectInputReq); - WindowPtr pWin; - ShapeEventPtr pShapeEvent, pNewShapeEvent, *pHead; - XID clientResource; - int rc; - - REQUEST_SIZE_MATCH (xShapeSelectInputReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixReceiveAccess); - if (rc != Success) - return rc; - rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, - ShapeEventType, client, DixWriteAccess); - if (rc != Success && rc != BadValue) - return rc; - - 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 = xalloc (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 = xalloc (sizeof (ShapeEventPtr)); - if (!pHead || - !AddResource (pWin->drawable.id, ShapeEventType, (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; - xfree (pShapeEvent); - } - } - break; - default: - client->errorValue = stuff->enable; - return BadValue; - } - return Success; -} - -/* - * deliver the event - */ - -void -SendShapeNotify (WindowPtr pWin, int which) -{ - ShapeEventPtr *pHead, pShapeEvent; - ClientPtr client; - xShapeNotifyEvent se; - BoxRec extents; - RegionPtr region; - BYTE shaped; - int rc; - - rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, - ShapeEventType, serverClient, DixReadAccess); - if (rc != Success) - return; - switch (which) { - case ShapeBounding: - region = wBoundingShape(pWin); - if (region) { - extents = *REGION_EXTENTS(pWin->drawable.pScreen, 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(pWin->drawable.pScreen, 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(pWin->drawable.pScreen, 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 (ClientPtr client) -{ - REQUEST(xShapeInputSelectedReq); - WindowPtr pWin; - ShapeEventPtr pShapeEvent, *pHead; - int enabled, rc; - xShapeInputSelectedReply rep; - int n; - - REQUEST_SIZE_MATCH (xShapeInputSelectedReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, - ShapeEventType, client, DixReadAccess); - if (rc != Success && rc != BadValue) - return rc; - 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, n); - swapl (&rep.length, n); - } - WriteToClient (client, sizeof (xShapeInputSelectedReply), (char *) &rep); - return (client->noClientException); -} - -static int -ProcShapeGetRectangles (ClientPtr client) -{ - REQUEST(xShapeGetRectanglesReq); - WindowPtr pWin; - xShapeGetRectanglesReply rep; - xRectangle *rects; - int nrects, i, rc; - RegionPtr region; - int n; - - REQUEST_SIZE_MATCH(xShapeGetRectanglesReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - 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 = xalloc (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 = xalloc (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 = bytes_to_int32(nrects * sizeof (xRectangle)); - rep.ordering = YXBanded; - rep.nrects = nrects; - if (client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.nrects, n); - SwapShorts ((short *)rects, (unsigned long)nrects * 4); - } - WriteToClient (client, sizeof (rep), (char *) &rep); - WriteToClient (client, nrects * sizeof (xRectangle), (char *) rects); - xfree (rects); - return client->noClientException; -} - -static int -ProcShapeDispatch (ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_ShapeQueryVersion: - return ProcShapeQueryVersion (client); - case X_ShapeRectangles: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShapeRectangles (client); - else -#endif - return ProcShapeRectangles (client); - case X_ShapeMask: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShapeMask (client); - else -#endif - return ProcShapeMask (client); - case X_ShapeCombine: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShapeCombine (client); - else -#endif - return ProcShapeCombine (client); - case X_ShapeOffset: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShapeOffset (client); - else -#endif - 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(xShapeNotifyEvent *from, xShapeNotifyEvent *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 (ClientPtr client) -{ - int n; - REQUEST (xShapeQueryVersionReq); - - swaps (&stuff->length, n); - return ProcShapeQueryVersion (client); -} - -static int -SProcShapeRectangles (ClientPtr client) -{ - char n; - REQUEST (xShapeRectanglesReq); - - swaps (&stuff->length, n); - REQUEST_AT_LEAST_SIZE (xShapeRectanglesReq); - swapl (&stuff->dest, n); - swaps (&stuff->xOff, n); - swaps (&stuff->yOff, n); - SwapRestS(stuff); - return ProcShapeRectangles (client); -} - -static int -SProcShapeMask (ClientPtr client) -{ - char n; - REQUEST (xShapeMaskReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH (xShapeMaskReq); - swapl (&stuff->dest, n); - swaps (&stuff->xOff, n); - swaps (&stuff->yOff, n); - swapl (&stuff->src, n); - return ProcShapeMask (client); -} - -static int -SProcShapeCombine (ClientPtr client) -{ - char n; - REQUEST (xShapeCombineReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH (xShapeCombineReq); - swapl (&stuff->dest, n); - swaps (&stuff->xOff, n); - swaps (&stuff->yOff, n); - swapl (&stuff->src, n); - return ProcShapeCombine (client); -} - -static int -SProcShapeOffset (ClientPtr client) -{ - char n; - REQUEST (xShapeOffsetReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH (xShapeOffsetReq); - swapl (&stuff->dest, n); - swaps (&stuff->xOff, n); - swaps (&stuff->yOff, n); - return ProcShapeOffset (client); -} - -static int -SProcShapeQueryExtents (ClientPtr client) -{ - char n; - REQUEST (xShapeQueryExtentsReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH (xShapeQueryExtentsReq); - swapl (&stuff->window, n); - return ProcShapeQueryExtents (client); -} - -static int -SProcShapeSelectInput (ClientPtr client) -{ - char n; - REQUEST (xShapeSelectInputReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH (xShapeSelectInputReq); - swapl (&stuff->window, n); - return ProcShapeSelectInput (client); -} - -static int -SProcShapeInputSelected (ClientPtr client) -{ - int n; - REQUEST (xShapeInputSelectedReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH (xShapeInputSelectedReq); - swapl (&stuff->window, n); - return ProcShapeInputSelected (client); -} - -static int -SProcShapeGetRectangles (ClientPtr client) -{ - REQUEST(xShapeGetRectanglesReq); - char n; - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xShapeGetRectanglesReq); - swapl (&stuff->window, n); - return ProcShapeGetRectangles (client); -} - -static int -SProcShapeDispatch (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; - } -} +/************************************************************ + +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" +#include +#include "regionstr.h" +#include "gcstruct.h" +#include "modinit.h" +#include "protocol-versions.h" + +typedef RegionPtr (*CreateDftPtr)( + WindowPtr /* pWin */ + ); + +static int ShapeFreeClient( + pointer /* data */, + XID /* id */ + ); +static int ShapeFreeEvents( + pointer /* data */, + XID /* id */ + ); +static void SShapeNotifyEvent( + xShapeNotifyEvent * /* from */, + xShapeNotifyEvent * /* to */ + ); + +/* 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); + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +static int ShapeEventBase = 0; +static RESTYPE ClientType, ShapeEventType; /* 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, "ShapeClient"); + ShapeEventType = CreateNewResourceType(ShapeFreeEvents, "ShapeEvent"); + if (ClientType && ShapeEventType && + (extEntry = AddExtension(SHAPENAME, ShapeNumberEvents, 0, + ProcShapeDispatch, SProcShapeDispatch, + NULL, StandardMinorOpcode))) + { + ShapeEventBase = extEntry->eventBase; + EventSwapVector[ShapeEventBase] = (EventSwapPtr) SShapeNotifyEvent; + } +} + +static int +RegionOperate ( + ClientPtr client, + WindowPtr pWin, + int kind, + RegionPtr *destRgnp, + RegionPtr srcRgn, + int op, + int xoff, int yoff, + CreateDftPtr create) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (srcRgn && (xoff || yoff)) + REGION_TRANSLATE(pScreen, srcRgn, xoff, yoff); + if (!pWin->parent) + { + if (srcRgn) + REGION_DESTROY(pScreen, 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 (pScreen, *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(pScreen, *destRgnp); + *destRgnp = srcRgn; + srcRgn = 0; + break; + case ShapeUnion: + if (*destRgnp) + REGION_UNION(pScreen, *destRgnp, *destRgnp, srcRgn); + break; + case ShapeIntersect: + if (*destRgnp) + REGION_INTERSECT(pScreen, *destRgnp, *destRgnp, srcRgn); + else { + *destRgnp = srcRgn; + srcRgn = 0; + } + break; + case ShapeSubtract: + if (!*destRgnp) + *destRgnp = (*create)(pWin); + REGION_SUBTRACT(pScreen, *destRgnp, *destRgnp, srcRgn); + break; + case ShapeInvert: + if (!*destRgnp) + *destRgnp = REGION_CREATE(pScreen, (BoxPtr) 0, 0); + else + REGION_SUBTRACT(pScreen, *destRgnp, srcRgn, *destRgnp); + break; + default: + client->errorValue = op; + return BadValue; + } + if (srcRgn) + REGION_DESTROY(pScreen, srcRgn); + (*pScreen->SetShape) (pWin); + SendShapeNotify (pWin, kind); + return Success; +} + +RegionPtr +CreateBoundingShape (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(pWin->drawable.pScreen, &extents, 1); +} + +RegionPtr +CreateClipShape (WindowPtr pWin) +{ + BoxRec extents; + + extents.x1 = 0; + extents.y1 = 0; + extents.x2 = pWin->drawable.width; + extents.y2 = pWin->drawable.height; + return REGION_CREATE(pWin->drawable.pScreen, &extents, 1); +} + +static int +ProcShapeQueryVersion (ClientPtr client) +{ + xShapeQueryVersionReply rep; + int n; + + REQUEST_SIZE_MATCH (xShapeQueryVersionReq); + memset(&rep, 0, sizeof(xShapeQueryVersionReply)); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_SHAPE_MAJOR_VERSION; + rep.minorVersion = SERVER_SHAPE_MINOR_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof (xShapeQueryVersionReply), (char *)&rep); + return Success; +} + +/***************** + * ProcShapeRectangles + * + *****************/ + +static int +ProcShapeRectangles (ClientPtr client) +{ + WindowPtr pWin; + ScreenPtr pScreen; + REQUEST(xShapeRectanglesReq); + xRectangle *prects; + int nrects, ctype, rc; + RegionPtr srcRgn; + RegionPtr *destRgn; + CreateDftPtr createDefault; + + REQUEST_AT_LEAST_SIZE (xShapeRectanglesReq); + UpdateCurrentTime(); + rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess); + if (rc != Success) + return rc; + 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; + } + pScreen = pWin->drawable.pScreen; + 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(pScreen, 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); +} + +#ifdef PANORAMIX +static int +ProcPanoramiXShapeRectangles( + ClientPtr client) +{ + REQUEST(xShapeRectanglesReq); + PanoramiXRes *win; + int j, result; + + REQUEST_AT_LEAST_SIZE (xShapeRectanglesReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->dest, XRT_WINDOW, + client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS(j) { + stuff->dest = win->info[j].id; + result = ProcShapeRectangles (client); + if (result != Success) break; + } + return (result); +} +#endif + + +/************** + * ProcShapeMask + **************/ + + +static int +ProcShapeMask (ClientPtr client) +{ + WindowPtr pWin; + ScreenPtr pScreen; + REQUEST(xShapeMaskReq); + RegionPtr srcRgn; + RegionPtr *destRgn; + PixmapPtr pPixmap; + CreateDftPtr createDefault; + int rc; + + REQUEST_SIZE_MATCH (xShapeMaskReq); + UpdateCurrentTime(); + rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess); + if (rc != Success) + return rc; + 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 { + rc = dixLookupResourceByType((pointer *)&pPixmap, stuff->src, RT_PIXMAP, + client, DixReadAccess); + if (rc != Success) + return (rc == BadValue) ? BadPixmap : rc; + 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); +} + +#ifdef PANORAMIX +static int +ProcPanoramiXShapeMask( + ClientPtr client) +{ + REQUEST(xShapeMaskReq); + PanoramiXRes *win, *pmap; + int j, result; + + REQUEST_SIZE_MATCH (xShapeMaskReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->dest, XRT_WINDOW, + client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + if(stuff->src != None) { + result = dixLookupResourceByType((pointer *)&pmap, stuff->src, + XRT_PIXMAP, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadPixmap : result; + } else + pmap = NULL; + + FOR_NSCREENS(j) { + stuff->dest = win->info[j].id; + if(pmap) + stuff->src = pmap->info[j].id; + result = ProcShapeMask (client); + if (result != Success) break; + } + return (result); +} +#endif + + +/************ + * ProcShapeCombine + ************/ + +static int +ProcShapeCombine (ClientPtr client) +{ + WindowPtr pSrcWin, pDestWin; + ScreenPtr pScreen; + REQUEST(xShapeCombineReq); + RegionPtr srcRgn; + RegionPtr *destRgn; + CreateDftPtr createDefault; + CreateDftPtr createSrc; + RegionPtr tmp; + int rc; + + REQUEST_SIZE_MATCH (xShapeCombineReq); + UpdateCurrentTime(); + rc = dixLookupWindow(&pDestWin, stuff->dest, client, DixSetAttrAccess); + if (rc != Success) + return rc; + 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; + + rc = dixLookupWindow(&pSrcWin, stuff->src, client, DixGetAttrAccess); + if (rc != Success) + return rc; + 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(pScreen, (BoxPtr) 0, 0); + REGION_COPY(pScreen, 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); +} + + +#ifdef PANORAMIX +static int +ProcPanoramiXShapeCombine( + ClientPtr client) +{ + REQUEST(xShapeCombineReq); + PanoramiXRes *win, *win2; + int j, result; + + REQUEST_AT_LEAST_SIZE (xShapeCombineReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->dest, XRT_WINDOW, + client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + result = dixLookupResourceByType((pointer *)&win2, stuff->src, XRT_WINDOW, + client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS(j) { + stuff->dest = win->info[j].id; + stuff->src = win2->info[j].id; + result = ProcShapeCombine (client); + if (result != Success) break; + } + return (result); +} +#endif + +/************* + * ProcShapeOffset + *************/ + +static int +ProcShapeOffset (ClientPtr client) +{ + WindowPtr pWin; + ScreenPtr pScreen; + REQUEST(xShapeOffsetReq); + RegionPtr srcRgn; + int rc; + + REQUEST_SIZE_MATCH (xShapeOffsetReq); + UpdateCurrentTime(); + rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess); + if (rc != Success) + return rc; + 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(pScreen, srcRgn, stuff->xOff, stuff->yOff); + (*pScreen->SetShape) (pWin); + } + SendShapeNotify (pWin, (int)stuff->destKind); + return Success; +} + + +#ifdef PANORAMIX +static int +ProcPanoramiXShapeOffset( + ClientPtr client) +{ + REQUEST(xShapeOffsetReq); + PanoramiXRes *win; + int j, result; + + REQUEST_AT_LEAST_SIZE (xShapeOffsetReq); + + result = dixLookupResourceByType((pointer *)&win, stuff->dest, XRT_WINDOW, + client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadWindow : result; + + FOR_NSCREENS(j) { + stuff->dest = win->info[j].id; + result = ProcShapeOffset (client); + if(result != Success) break; + } + return (result); +} +#endif + + +static int +ProcShapeQueryExtents (ClientPtr client) +{ + REQUEST(xShapeQueryExtentsReq); + WindowPtr pWin; + xShapeQueryExtentsReply rep; + BoxRec extents, *pExtents; + int n, rc; + RegionPtr region; + + REQUEST_SIZE_MATCH (xShapeQueryExtentsReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + memset(&rep, 0, sizeof(xShapeQueryExtentsReply)); + 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(pWin->drawable.pScreen, 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(pWin->drawable.pScreen, 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, n); + swapl(&rep.length, n); + swaps(&rep.xBoundingShape, n); + swaps(&rep.yBoundingShape, n); + swaps(&rep.widthBoundingShape, n); + swaps(&rep.heightBoundingShape, n); + swaps(&rep.xClipShape, n); + swaps(&rep.yClipShape, n); + swaps(&rep.widthClipShape, n); + swaps(&rep.heightClipShape, n); + } + WriteToClient(client, sizeof (xShapeQueryExtentsReply), (char *)&rep); + return Success; +} + +/*ARGSUSED*/ +static int +ShapeFreeClient (pointer data, XID id) +{ + ShapeEventPtr pShapeEvent; + WindowPtr pWin; + ShapeEventPtr *pHead, pCur, pPrev; + int rc; + + pShapeEvent = (ShapeEventPtr) data; + pWin = pShapeEvent->window; + rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, + ShapeEventType, serverClient, DixReadAccess); + if (rc == Success) { + 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 (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 (ClientPtr client) +{ + REQUEST(xShapeSelectInputReq); + WindowPtr pWin; + ShapeEventPtr pShapeEvent, pNewShapeEvent, *pHead; + XID clientResource; + int rc; + + REQUEST_SIZE_MATCH (xShapeSelectInputReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixReceiveAccess); + if (rc != Success) + return rc; + rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, + ShapeEventType, client, DixWriteAccess); + if (rc != Success && rc != BadValue) + return rc; + + 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 = 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, ShapeEventType, (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 (WindowPtr pWin, int which) +{ + ShapeEventPtr *pHead, pShapeEvent; + ClientPtr client; + xShapeNotifyEvent se; + BoxRec extents; + RegionPtr region; + BYTE shaped; + int rc; + + rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, + ShapeEventType, serverClient, DixReadAccess); + if (rc != Success) + return; + switch (which) { + case ShapeBounding: + region = wBoundingShape(pWin); + if (region) { + extents = *REGION_EXTENTS(pWin->drawable.pScreen, 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(pWin->drawable.pScreen, 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(pWin->drawable.pScreen, 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 (ClientPtr client) +{ + REQUEST(xShapeInputSelectedReq); + WindowPtr pWin; + ShapeEventPtr pShapeEvent, *pHead; + int enabled, rc; + xShapeInputSelectedReply rep; + int n; + + REQUEST_SIZE_MATCH (xShapeInputSelectedReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, + ShapeEventType, client, DixReadAccess); + if (rc != Success && rc != BadValue) + return rc; + 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, n); + swapl (&rep.length, n); + } + WriteToClient (client, sizeof (xShapeInputSelectedReply), (char *) &rep); + return Success; +} + +static int +ProcShapeGetRectangles (ClientPtr client) +{ + REQUEST(xShapeGetRectanglesReq); + WindowPtr pWin; + xShapeGetRectanglesReply rep; + xRectangle *rects; + int nrects, i, rc; + RegionPtr region; + int n; + + REQUEST_SIZE_MATCH(xShapeGetRectanglesReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + 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 = malloc(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 = malloc(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 = bytes_to_int32(nrects * sizeof (xRectangle)); + rep.ordering = YXBanded; + rep.nrects = nrects; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.nrects, n); + SwapShorts ((short *)rects, (unsigned long)nrects * 4); + } + WriteToClient (client, sizeof (rep), (char *) &rep); + WriteToClient (client, nrects * sizeof (xRectangle), (char *) rects); + free(rects); + return Success; +} + +static int +ProcShapeDispatch (ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_ShapeQueryVersion: + return ProcShapeQueryVersion (client); + case X_ShapeRectangles: +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + return ProcPanoramiXShapeRectangles (client); + else +#endif + return ProcShapeRectangles (client); + case X_ShapeMask: +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + return ProcPanoramiXShapeMask (client); + else +#endif + return ProcShapeMask (client); + case X_ShapeCombine: +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + return ProcPanoramiXShapeCombine (client); + else +#endif + return ProcShapeCombine (client); + case X_ShapeOffset: +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + return ProcPanoramiXShapeOffset (client); + else +#endif + 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(xShapeNotifyEvent *from, xShapeNotifyEvent *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 (ClientPtr client) +{ + int n; + REQUEST (xShapeQueryVersionReq); + + swaps (&stuff->length, n); + return ProcShapeQueryVersion (client); +} + +static int +SProcShapeRectangles (ClientPtr client) +{ + char n; + REQUEST (xShapeRectanglesReq); + + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE (xShapeRectanglesReq); + swapl (&stuff->dest, n); + swaps (&stuff->xOff, n); + swaps (&stuff->yOff, n); + SwapRestS(stuff); + return ProcShapeRectangles (client); +} + +static int +SProcShapeMask (ClientPtr client) +{ + char n; + REQUEST (xShapeMaskReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xShapeMaskReq); + swapl (&stuff->dest, n); + swaps (&stuff->xOff, n); + swaps (&stuff->yOff, n); + swapl (&stuff->src, n); + return ProcShapeMask (client); +} + +static int +SProcShapeCombine (ClientPtr client) +{ + char n; + REQUEST (xShapeCombineReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xShapeCombineReq); + swapl (&stuff->dest, n); + swaps (&stuff->xOff, n); + swaps (&stuff->yOff, n); + swapl (&stuff->src, n); + return ProcShapeCombine (client); +} + +static int +SProcShapeOffset (ClientPtr client) +{ + char n; + REQUEST (xShapeOffsetReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xShapeOffsetReq); + swapl (&stuff->dest, n); + swaps (&stuff->xOff, n); + swaps (&stuff->yOff, n); + return ProcShapeOffset (client); +} + +static int +SProcShapeQueryExtents (ClientPtr client) +{ + char n; + REQUEST (xShapeQueryExtentsReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xShapeQueryExtentsReq); + swapl (&stuff->window, n); + return ProcShapeQueryExtents (client); +} + +static int +SProcShapeSelectInput (ClientPtr client) +{ + char n; + REQUEST (xShapeSelectInputReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xShapeSelectInputReq); + swapl (&stuff->window, n); + return ProcShapeSelectInput (client); +} + +static int +SProcShapeInputSelected (ClientPtr client) +{ + int n; + REQUEST (xShapeInputSelectedReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xShapeInputSelectedReq); + swapl (&stuff->window, n); + return ProcShapeInputSelected (client); +} + +static int +SProcShapeGetRectangles (ClientPtr client) +{ + REQUEST(xShapeGetRectanglesReq); + char n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xShapeGetRectanglesReq); + swapl (&stuff->window, n); + return ProcShapeGetRectangles (client); +} + +static int +SProcShapeDispatch (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/xorg-server/Xext/shm.c b/xorg-server/Xext/shm.c index ab58c2750..0d78fbc06 100644 --- a/xorg-server/Xext/shm.c +++ b/xorg-server/Xext/shm.c @@ -1,1329 +1,1329 @@ -/************************************************************ - -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" -#include "shmint.h" -#include "xace.h" -#include -#include -#include "protocol-versions.h" - -/* Needed for Solaris cross-zone shared memory extension */ -#ifdef HAVE_SHMCTL64 -#include -#define SHMSTAT(id, buf) shmctl64(id, IPC_STAT64, buf) -#define SHMSTAT_TYPE struct shmid_ds64 -#define SHMPERM_TYPE struct ipc_perm64 -#define SHM_PERM(buf) buf.shmx_perm -#define SHM_SEGSZ(buf) buf.shmx_segsz -#define SHMPERM_UID(p) p->ipcx_uid -#define SHMPERM_CUID(p) p->ipcx_cuid -#define SHMPERM_GID(p) p->ipcx_gid -#define SHMPERM_CGID(p) p->ipcx_cgid -#define SHMPERM_MODE(p) p->ipcx_mode -#define SHMPERM_ZONEID(p) p->ipcx_zoneid -#else -#define SHMSTAT(id, buf) shmctl(id, IPC_STAT, buf) -#define SHMSTAT_TYPE struct shmid_ds -#define SHMPERM_TYPE struct ipc_perm -#define SHM_PERM(buf) buf.shm_perm -#define SHM_SEGSZ(buf) buf.shm_segsz -#define SHMPERM_UID(p) p->uid -#define SHMPERM_CUID(p) p->cuid -#define SHMPERM_GID(p) p->gid -#define SHMPERM_CGID(p) p->cgid -#define SHMPERM_MODE(p) p->mode -#endif - -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif - -#include "modinit.h" - -typedef struct _ShmDesc { - struct _ShmDesc *next; - int shmid; - int refcnt; - char *addr; - Bool writable; - unsigned long size; -} ShmDescRec, *ShmDescPtr; - -typedef struct _ShmScrPrivateRec { - CloseScreenProcPtr CloseScreen; - ShmFuncsPtr shmFuncs; - DestroyPixmapProcPtr destroyPixmap; -} ShmScrPrivateRec; - -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; -int ShmCompletionCode; -int BadShmSegCode; -RESTYPE ShmSegType; -static ShmDescPtr Shmsegs; -static Bool sharedPixmaps; -static int shmScrPrivateKeyIndex; -static DevPrivateKey shmScrPrivateKey = &shmScrPrivateKeyIndex; -static int shmPixmapPrivateIndex; -static DevPrivateKey shmPixmapPrivate = &shmPixmapPrivateIndex; -static ShmFuncs miFuncs = {NULL, NULL}; -static ShmFuncs fbFuncs = {fbShmCreatePixmap, NULL}; - -#define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey)) - -#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ -{ \ - int rc; \ - rc = dixLookupResourceByType((pointer *)&(shmdesc), shmseg, ShmSegType, \ - client, DixReadAccess); \ - if (rc != Success) \ - return (rc == BadValue) ? BadShmSegCode : rc; \ -} - -#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__) || defined(__DragonFly__) -#include - -static Bool badSysCall = FALSE; - -static void -SigSysHandler(int signo) -{ - badSysCall = TRUE; -} - -static Bool CheckForShmSyscall(void) -{ - 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, NULL); - } - else - { - /* Allocation failed */ - badSysCall = TRUE; - } - signal(SIGSYS, oldHandler); - return(!badSysCall); -} - -#define MUST_CHECK_FOR_SHM_SYSCALL - -#endif - -static Bool -ShmCloseScreen(int i, ScreenPtr pScreen) -{ - ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); - pScreen->CloseScreen = screen_priv->CloseScreen; - dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL); - xfree (screen_priv); - return (*pScreen->CloseScreen) (i, pScreen); -} - -static ShmScrPrivateRec * -ShmInitScreenPriv(ScreenPtr pScreen) -{ - ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); - if (!screen_priv) - { - screen_priv = xcalloc (1, sizeof (ShmScrPrivateRec)); - screen_priv->CloseScreen = pScreen->CloseScreen; - dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv); - pScreen->CloseScreen = ShmCloseScreen; - } - return screen_priv; -} - -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; - { - sharedPixmaps = xTrue; - for (i = 0; i < screenInfo.numScreens; i++) - { - ShmScrPrivateRec *screen_priv = ShmInitScreenPriv(screenInfo.screens[i]); - if (!screen_priv->shmFuncs) - screen_priv->shmFuncs = &miFuncs; - if (!screen_priv->shmFuncs->CreatePixmap) - sharedPixmaps = xFalse; - } - if (sharedPixmaps) - for (i = 0; i < screenInfo.numScreens; i++) - { - ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(screenInfo.screens[i]); - screen_priv->destroyPixmap = screenInfo.screens[i]->DestroyPixmap; - screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap; - } - } - ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg"); - 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(ExtensionEntry *extEntry) -{ - int i; - for (i = 0; i < screenInfo.numScreens; i++) - ShmRegisterFuncs(screenInfo.screens[i], NULL); -} - -void -ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs) -{ - ShmInitScreenPriv(pScreen)->shmFuncs = funcs; -} - -static Bool -ShmDestroyPixmap (PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); - Bool ret; - if (pPixmap->refcnt == 1) - { - ShmDescPtr shmdesc; - shmdesc = (ShmDescPtr)dixLookupPrivate(&pPixmap->devPrivates, - shmPixmapPrivate); - if (shmdesc) - ShmDetachSegment ((pointer) shmdesc, pPixmap->drawable.id); - } - - pScreen->DestroyPixmap = screen_priv->destroyPixmap; - ret = (*pScreen->DestroyPixmap) (pPixmap); - screen_priv->destroyPixmap = pScreen->DestroyPixmap; - pScreen->DestroyPixmap = ShmDestroyPixmap; - return ret; -} - -void -ShmRegisterFbFuncs(ScreenPtr pScreen) -{ - ShmRegisterFuncs(pScreen, &fbFuncs); -} - -static int -ProcShmQueryVersion(ClientPtr client) -{ - xShmQueryVersionReply rep; - int n; - - REQUEST_SIZE_MATCH(xShmQueryVersionReq); - memset(&rep, 0, sizeof(xShmQueryVersionReply)); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.sharedPixmaps = sharedPixmaps; - rep.pixmapFormat = sharedPixmaps ? ZPixmap : 0; - rep.majorVersion = SERVER_SHM_MAJOR_VERSION; - rep.minorVersion = SERVER_SHM_MINOR_VERSION; - rep.uid = geteuid(); - rep.gid = getegid(); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - swaps(&rep.uid, n); - swaps(&rep.gid, n); - } - 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, SHMPERM_TYPE *perm, int readonly) -{ - int uid, gid; - mode_t mask; - int uidset = 0, gidset = 0; - LocalClientCredRec *lcc; - - if (GetLocalClientCreds(client, &lcc) != -1) { - - if (lcc->fieldsSet & LCC_UID_SET) { - uid = lcc->euid; - uidset = 1; - } - if (lcc->fieldsSet & LCC_GID_SET) { - gid = lcc->egid; - gidset = 1; - } - -#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID) - if ( ((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1) - || (lcc->zoneid != SHMPERM_ZONEID(perm))) { - uidset = 0; - gidset = 0; - } -#endif - FreeLocalClientCreds(lcc); - - if (uidset) { - /* User id 0 always gets access */ - if (uid == 0) { - return 0; - } - /* Check the owner */ - if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) { - mask = S_IRUSR; - if (!readonly) { - mask |= S_IWUSR; - } - return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; - } - } - - if (gidset) { - /* Check the group */ - if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) { - mask = S_IRGRP; - if (!readonly) { - mask |= S_IWGRP; - } - return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; - } - } - } - /* Otherwise, check everyone else */ - mask = S_IROTH; - if (!readonly) { - mask |= S_IWOTH; - } - return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; -} - -static int -ProcShmAttach(ClientPtr client) -{ - SHMSTAT_TYPE 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 = xalloc(sizeof(ShmDescRec)); - if (!shmdesc) - return BadAlloc; - shmdesc->addr = shmat(stuff->shmid, 0, - stuff->readOnly ? SHM_RDONLY : 0); - if ((shmdesc->addr == ((char *)-1)) || - SHMSTAT(stuff->shmid, &buf)) - { - xfree(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, &(SHM_PERM(buf)), stuff->readOnly) == -1) { - shmdt(shmdesc->addr); - xfree(shmdesc); - return BadAccess; - } - - shmdesc->shmid = stuff->shmid; - shmdesc->refcnt = 1; - shmdesc->writable = !stuff->readOnly; - shmdesc->size = SHM_SEGSZ(buf); - shmdesc->next = Shmsegs; - Shmsegs = shmdesc; - } - if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc)) - return BadAlloc; - return(client->noClientException); -} - -/*ARGSUSED*/ -static int -ShmDetachSegment(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; - xfree(shmdesc); - return Success; -} - -static int -ProcShmDetach(ClientPtr client) -{ - ShmDescPtr shmdesc; - REQUEST(xShmDetachReq); - - REQUEST_SIZE_MATCH(xShmDetachReq); - VERIFY_SHMSEG(stuff->shmseg, shmdesc, client); - FreeResource(stuff->shmseg, RT_NONE); - return(client->noClientException); -} - -/* - * If the given request doesn't exactly match PutImage's constraints, - * wrap the image in a scratch pixmap header and let CopyArea sort it out. - */ -static void -doShmPutImage(DrawablePtr dst, GCPtr pGC, - int depth, unsigned int format, - int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, - char *data) -{ - PixmapPtr pPixmap; - - if (format == ZPixmap || depth == 1) { - pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth, - BitsPerPixel(depth), - PixmapBytePad(w, depth), - data); - if (!pPixmap) - return; - pGC->ops->CopyArea((DrawablePtr)pPixmap, dst, pGC, sx, sy, sw, sh, dx, dy); - FreeScratchPixmapHeader(pPixmap); - } else { - GCPtr putGC = GetScratchGC(depth, dst->pScreen); - - if (!putGC) - return; - - pPixmap = (*dst->pScreen->CreatePixmap)(dst->pScreen, sw, sh, depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pPixmap) { - FreeScratchGC(putGC); - return; - } - ValidateGC(&pPixmap->drawable, putGC); - (*putGC->ops->PutImage)(&pPixmap->drawable, putGC, depth, -sx, -sy, w, h, 0, - (format == XYPixmap) ? XYPixmap : ZPixmap, data); - FreeScratchGC(putGC); - if (format == XYBitmap) - (void)(*pGC->ops->CopyPlane)(&pPixmap->drawable, dst, pGC, 0, 0, sw, sh, - dx, dy, 1L); - else - (void)(*pGC->ops->CopyArea)(&pPixmap->drawable, dst, pGC, 0, 0, sw, sh, - dx, dy); - (*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap); - } -} - -#ifdef PANORAMIX -static int -ProcPanoramiXShmPutImage(ClientPtr client) -{ - int j, result, orig_x, orig_y; - PanoramiXRes *draw, *gc; - Bool sendEvent, isRoot; - - REQUEST(xShmPutImageReq); - REQUEST_SIZE_MATCH(xShmPutImageReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, - XRT_GC, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - orig_x = stuff->dstX; - orig_y = stuff->dstY; - sendEvent = stuff->sendEvent; - stuff->sendEvent = 0; - FOR_NSCREENS(j) { - if(!j) stuff->sendEvent = sendEvent; - stuff->drawable = draw->info[j].id; - stuff->gc = gc->info[j].id; - if (isRoot) { - stuff->dstX = orig_x - panoramiXdataPtr[j].x; - stuff->dstY = orig_y - panoramiXdataPtr[j].y; - } - result = ProcShmPutImage(client); - if(result != client->noClientException) break; - } - return(result); -} - -static int -ProcPanoramiXShmGetImage(ClientPtr client) -{ - PanoramiXRes *draw; - DrawablePtr *drawables; - DrawablePtr pDraw; - xShmGetImageReply xgi; - ShmDescPtr shmdesc; - int i, x, y, w, h, format, rc; - Mask plane = 0, planemask; - long lenPer = 0, length, widthBytesLine; - Bool isRoot; - - REQUEST(xShmGetImageReq); - - REQUEST_SIZE_MATCH(xShmGetImageReq); - - if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) { - client->errorValue = stuff->format; - return(BadValue); - } - - rc = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (rc != Success) - return (rc == BadValue) ? BadDrawable : rc; - - if (draw->type == XRT_PIXMAP) - return ProcShmGetImage(client); - - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); - - x = stuff->x; - y = stuff->y; - w = stuff->width; - h = stuff->height; - format = stuff->format; - planemask = stuff->planeMask; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - if(isRoot) { - if( /* check for being onscreen */ - x < 0 || x + w > PanoramiXPixWidth || - y < 0 || y + h > PanoramiXPixHeight ) - return(BadMatch); - } else { - if( /* check for being onscreen */ - panoramiXdataPtr[0].x + pDraw->x + x < 0 || - panoramiXdataPtr[0].x + pDraw->x + x + w > PanoramiXPixWidth || - panoramiXdataPtr[0].y + pDraw->y + y < 0 || - panoramiXdataPtr[0].y + pDraw->y + y + h > PanoramiXPixHeight || - /* check for being inside of border */ - x < - wBorderWidth((WindowPtr)pDraw) || - x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || - y < -wBorderWidth((WindowPtr)pDraw) || - y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height) - return(BadMatch); - } - - drawables = xcalloc(PanoramiXNumScreens, sizeof(DrawablePtr)); - if(!drawables) - return(BadAlloc); - - drawables[0] = pDraw; - for(i = 1; i < PanoramiXNumScreens; i++) { - rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0, - DixReadAccess); - if (rc != Success) - { - xfree(drawables); - return rc; - } - } - - xgi.visual = wVisual(((WindowPtr)pDraw)); - xgi.type = X_Reply; - xgi.length = 0; - xgi.sequenceNumber = client->sequence; - xgi.depth = pDraw->depth; - - if(format == ZPixmap) { - widthBytesLine = PixmapBytePad(w, pDraw->depth); - length = widthBytesLine * h; - } else { - widthBytesLine = PixmapBytePad(w, 1); - lenPer = widthBytesLine * h; - plane = ((Mask)1) << (pDraw->depth - 1); - length = lenPer * Ones(planemask & (plane | (plane - 1))); - } - - VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); - xgi.size = length; - - if (length == 0) {/* nothing to do */ } - else if (format == ZPixmap) { - XineramaGetImageData(drawables, x, y, w, h, format, planemask, - shmdesc->addr + stuff->offset, - widthBytesLine, isRoot); - } else { - - length = stuff->offset; - for (; plane; plane >>= 1) { - if (planemask & plane) { - XineramaGetImageData(drawables, x, y, w, h, - format, plane, shmdesc->addr + length, - widthBytesLine, isRoot); - length += lenPer; - } - } - } - xfree(drawables); - - if (client->swapped) { - int n; - swaps(&xgi.sequenceNumber, n); - swapl(&xgi.length, n); - swapl(&xgi.visual, n); - swapl(&xgi.size, n); - } - WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); - - return(client->noClientException); -} - -static int -ProcPanoramiXShmCreatePixmap(ClientPtr client) -{ - ScreenPtr pScreen = NULL; - PixmapPtr pMap = NULL; - DrawablePtr pDraw; - DepthPtr pDepth; - int i, j, result, rc; - ShmDescPtr shmdesc; - REQUEST(xShmCreatePixmapReq); - unsigned int width, height, depth; - unsigned long size; - PanoramiXRes *newPix; - - REQUEST_SIZE_MATCH(xShmCreatePixmapReq); - client->errorValue = stuff->pid; - if (!sharedPixmaps) - return BadImplementation; - LEGAL_NEW_RESOURCE(stuff->pid, client); - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, - DixGetAttrAccess); - if (rc != Success) - return rc; - - VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); - - width = stuff->width; - height = stuff->height; - depth = stuff->depth; - if (!width || !height || !depth) - { - client->errorValue = 0; - return BadValue; - } - if (width > 32767 || height > 32767) - return BadAlloc; - - if (stuff->depth != 1) - { - pDepth = pDraw->pScreen->allowedDepths; - for (i=0; ipScreen->numDepths; i++, pDepth++) - if (pDepth->depth == stuff->depth) - goto CreatePmap; - client->errorValue = stuff->depth; - return BadValue; - } - -CreatePmap: - size = PixmapBytePad(width, depth) * height; - if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { - if (size < width * height) - return BadAlloc; - } - /* thankfully, offset is unsigned */ - if (stuff->offset + size < size) - return BadAlloc; - - VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); - - if(!(newPix = xalloc(sizeof(PanoramiXRes)))) - return BadAlloc; - - newPix->type = XRT_PIXMAP; - newPix->u.pix.shared = TRUE; - newPix->info[0].id = stuff->pid; - for(j = 1; j < PanoramiXNumScreens; j++) - newPix->info[j].id = FakeClientID(client->index); - - result = (client->noClientException); - - FOR_NSCREENS(j) { - ShmScrPrivateRec *screen_priv; - pScreen = screenInfo.screens[j]; - - screen_priv = ShmGetScreenPriv(pScreen); - pMap = (*screen_priv->shmFuncs->CreatePixmap)(pScreen, - stuff->width, stuff->height, stuff->depth, - shmdesc->addr + stuff->offset); - - if (pMap) { - dixSetPrivate(&pMap->devPrivates, shmPixmapPrivate, shmdesc); - shmdesc->refcnt++; - pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - pMap->drawable.id = newPix->info[j].id; - if (!AddResource(newPix->info[j].id, RT_PIXMAP, (pointer)pMap)) { - (*pScreen->DestroyPixmap)(pMap); - result = BadAlloc; - break; - } - } else { - result = BadAlloc; - break; - } - } - - if(result == BadAlloc) { - while(j--) { - (*pScreen->DestroyPixmap)(pMap); - FreeResource(newPix->info[j].id, RT_NONE); - } - xfree(newPix); - } else - AddResource(stuff->pid, XRT_PIXMAP, newPix); - - return result; -} - -#endif - -static int -ProcShmPutImage(ClientPtr client) -{ - GCPtr pGC; - DrawablePtr pDraw; - long length; - ShmDescPtr shmdesc; - REQUEST(xShmPutImageReq); - - REQUEST_SIZE_MATCH(xShmPutImageReq); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - 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; - } - - /* - * There's a potential integer overflow in this check: - * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, - * client); - * the version below ought to avoid it - */ - if (stuff->totalHeight != 0 && - length > (shmdesc->size - stuff->offset)/stuff->totalHeight) { - client->errorValue = stuff->totalWidth; - return BadValue; - } - 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 - doShmPutImage(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(ClientPtr client) -{ - DrawablePtr pDraw; - long lenPer = 0, length; - Mask plane = 0; - xShmGetImageReply xgi; - ShmDescPtr shmdesc; - int n, rc; - - REQUEST(xShmGetImageReq); - - REQUEST_SIZE_MATCH(xShmGetImageReq); - if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) - { - client->errorValue = stuff->format; - return(BadValue); - } - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - 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, n); - swapl(&xgi.length, n); - swapl(&xgi.visual, n); - swapl(&xgi.size, n); - } - WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); - - return(client->noClientException); -} - -static PixmapPtr -fbShmCreatePixmap (ScreenPtr pScreen, - int width, int height, int depth, char *addr) -{ - PixmapPtr pPixmap; - - pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0); - 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(ClientPtr client) -{ - PixmapPtr pMap; - DrawablePtr pDraw; - DepthPtr pDepth; - int i, rc; - ShmDescPtr shmdesc; - ShmScrPrivateRec *screen_priv; - REQUEST(xShmCreatePixmapReq); - unsigned int width, height, depth; - unsigned long size; - - REQUEST_SIZE_MATCH(xShmCreatePixmapReq); - client->errorValue = stuff->pid; - if (!sharedPixmaps) - return BadImplementation; - LEGAL_NEW_RESOURCE(stuff->pid, client); - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, - DixGetAttrAccess); - if (rc != Success) - return rc; - - VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); - - width = stuff->width; - height = stuff->height; - depth = stuff->depth; - if (!width || !height || !depth) - { - client->errorValue = 0; - return BadValue; - } - if (width > 32767 || height > 32767) - return BadAlloc; - - if (stuff->depth != 1) - { - pDepth = pDraw->pScreen->allowedDepths; - for (i=0; ipScreen->numDepths; i++, pDepth++) - if (pDepth->depth == stuff->depth) - goto CreatePmap; - client->errorValue = stuff->depth; - return BadValue; - } - -CreatePmap: - size = PixmapBytePad(width, depth) * height; - if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { - if (size < width * height) - return BadAlloc; - } - /* thankfully, offset is unsigned */ - if (stuff->offset + size < size) - return BadAlloc; - - VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); - screen_priv = ShmGetScreenPriv(pDraw->pScreen); - pMap = (*screen_priv->shmFuncs->CreatePixmap)( - pDraw->pScreen, stuff->width, - stuff->height, stuff->depth, - shmdesc->addr + stuff->offset); - if (pMap) - { - rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP, - pMap, RT_NONE, NULL, DixCreateAccess); - if (rc != Success) { - pDraw->pScreen->DestroyPixmap(pMap); - return rc; - } - dixSetPrivate(&pMap->devPrivates, shmPixmapPrivate, 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); - } - pDraw->pScreen->DestroyPixmap(pMap); - } - return (BadAlloc); -} - -static int -ProcShmDispatch (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: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShmPutImage(client); -#endif - return ProcShmPutImage(client); - case X_ShmGetImage: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShmGetImage(client); -#endif - return ProcShmGetImage(client); - case X_ShmCreatePixmap: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShmCreatePixmap(client); -#endif - return ProcShmCreatePixmap(client); - default: - return BadRequest; - } -} - -static void -SShmCompletionEvent(xShmCompletionEvent *from, xShmCompletionEvent *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(ClientPtr client) -{ - int n; - REQUEST(xShmQueryVersionReq); - - swaps(&stuff->length, n); - return ProcShmQueryVersion(client); -} - -static int -SProcShmAttach(ClientPtr client) -{ - int n; - REQUEST(xShmAttachReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xShmAttachReq); - swapl(&stuff->shmseg, n); - swapl(&stuff->shmid, n); - return ProcShmAttach(client); -} - -static int -SProcShmDetach(ClientPtr client) -{ - int n; - REQUEST(xShmDetachReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xShmDetachReq); - swapl(&stuff->shmseg, n); - return ProcShmDetach(client); -} - -static int -SProcShmPutImage(ClientPtr client) -{ - int n; - REQUEST(xShmPutImageReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xShmPutImageReq); - swapl(&stuff->drawable, n); - swapl(&stuff->gc, n); - swaps(&stuff->totalWidth, n); - swaps(&stuff->totalHeight, n); - swaps(&stuff->srcX, n); - swaps(&stuff->srcY, n); - swaps(&stuff->srcWidth, n); - swaps(&stuff->srcHeight, n); - swaps(&stuff->dstX, n); - swaps(&stuff->dstY, n); - swapl(&stuff->shmseg, n); - swapl(&stuff->offset, n); - return ProcShmPutImage(client); -} - -static int -SProcShmGetImage(ClientPtr client) -{ - int n; - REQUEST(xShmGetImageReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xShmGetImageReq); - swapl(&stuff->drawable, n); - swaps(&stuff->x, n); - swaps(&stuff->y, n); - swaps(&stuff->width, n); - swaps(&stuff->height, n); - swapl(&stuff->planeMask, n); - swapl(&stuff->shmseg, n); - swapl(&stuff->offset, n); - return ProcShmGetImage(client); -} - -static int -SProcShmCreatePixmap(ClientPtr client) -{ - int n; - REQUEST(xShmCreatePixmapReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xShmCreatePixmapReq); - swapl(&stuff->pid, n); - swapl(&stuff->drawable, n); - swaps(&stuff->width, n); - swaps(&stuff->height, n); - swapl(&stuff->shmseg, n); - swapl(&stuff->offset, n); - return ProcShmCreatePixmap(client); -} - -static int -SProcShmDispatch (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; - } -} +/************************************************************ + +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" +#include "shmint.h" +#include "xace.h" +#include +#include +#include "protocol-versions.h" + +/* Needed for Solaris cross-zone shared memory extension */ +#ifdef HAVE_SHMCTL64 +#include +#define SHMSTAT(id, buf) shmctl64(id, IPC_STAT64, buf) +#define SHMSTAT_TYPE struct shmid_ds64 +#define SHMPERM_TYPE struct ipc_perm64 +#define SHM_PERM(buf) buf.shmx_perm +#define SHM_SEGSZ(buf) buf.shmx_segsz +#define SHMPERM_UID(p) p->ipcx_uid +#define SHMPERM_CUID(p) p->ipcx_cuid +#define SHMPERM_GID(p) p->ipcx_gid +#define SHMPERM_CGID(p) p->ipcx_cgid +#define SHMPERM_MODE(p) p->ipcx_mode +#define SHMPERM_ZONEID(p) p->ipcx_zoneid +#else +#define SHMSTAT(id, buf) shmctl(id, IPC_STAT, buf) +#define SHMSTAT_TYPE struct shmid_ds +#define SHMPERM_TYPE struct ipc_perm +#define SHM_PERM(buf) buf.shm_perm +#define SHM_SEGSZ(buf) buf.shm_segsz +#define SHMPERM_UID(p) p->uid +#define SHMPERM_CUID(p) p->cuid +#define SHMPERM_GID(p) p->gid +#define SHMPERM_CGID(p) p->cgid +#define SHMPERM_MODE(p) p->mode +#endif + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +#include "modinit.h" + +typedef struct _ShmDesc { + struct _ShmDesc *next; + int shmid; + int refcnt; + char *addr; + Bool writable; + unsigned long size; +} ShmDescRec, *ShmDescPtr; + +typedef struct _ShmScrPrivateRec { + CloseScreenProcPtr CloseScreen; + ShmFuncsPtr shmFuncs; + DestroyPixmapProcPtr destroyPixmap; +} ShmScrPrivateRec; + +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; +int ShmCompletionCode; +int BadShmSegCode; +RESTYPE ShmSegType; +static ShmDescPtr Shmsegs; +static Bool sharedPixmaps; +static int shmScrPrivateKeyIndex; +static DevPrivateKey shmScrPrivateKey = &shmScrPrivateKeyIndex; +static int shmPixmapPrivateIndex; +static DevPrivateKey shmPixmapPrivate = &shmPixmapPrivateIndex; +static ShmFuncs miFuncs = {NULL, NULL}; +static ShmFuncs fbFuncs = {fbShmCreatePixmap, NULL}; + +#define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey)) + +#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ +{ \ + int rc; \ + rc = dixLookupResourceByType((pointer *)&(shmdesc), shmseg, ShmSegType, \ + client, DixReadAccess); \ + if (rc != Success) \ + return (rc == BadValue) ? BadShmSegCode : rc; \ +} + +#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__) || defined(__DragonFly__) +#include + +static Bool badSysCall = FALSE; + +static void +SigSysHandler(int signo) +{ + badSysCall = TRUE; +} + +static Bool CheckForShmSyscall(void) +{ + 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, NULL); + } + else + { + /* Allocation failed */ + badSysCall = TRUE; + } + signal(SIGSYS, oldHandler); + return(!badSysCall); +} + +#define MUST_CHECK_FOR_SHM_SYSCALL + +#endif + +static Bool +ShmCloseScreen(int i, ScreenPtr pScreen) +{ + ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); + pScreen->CloseScreen = screen_priv->CloseScreen; + dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL); + free(screen_priv); + return (*pScreen->CloseScreen) (i, pScreen); +} + +static ShmScrPrivateRec * +ShmInitScreenPriv(ScreenPtr pScreen) +{ + ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); + if (!screen_priv) + { + screen_priv = calloc(1, sizeof (ShmScrPrivateRec)); + screen_priv->CloseScreen = pScreen->CloseScreen; + dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv); + pScreen->CloseScreen = ShmCloseScreen; + } + return screen_priv; +} + +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; + { + sharedPixmaps = xTrue; + for (i = 0; i < screenInfo.numScreens; i++) + { + ShmScrPrivateRec *screen_priv = ShmInitScreenPriv(screenInfo.screens[i]); + if (!screen_priv->shmFuncs) + screen_priv->shmFuncs = &miFuncs; + if (!screen_priv->shmFuncs->CreatePixmap) + sharedPixmaps = xFalse; + } + if (sharedPixmaps) + for (i = 0; i < screenInfo.numScreens; i++) + { + ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(screenInfo.screens[i]); + screen_priv->destroyPixmap = screenInfo.screens[i]->DestroyPixmap; + screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap; + } + } + ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg"); + 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(ExtensionEntry *extEntry) +{ + int i; + for (i = 0; i < screenInfo.numScreens; i++) + ShmRegisterFuncs(screenInfo.screens[i], NULL); +} + +void +ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs) +{ + ShmInitScreenPriv(pScreen)->shmFuncs = funcs; +} + +static Bool +ShmDestroyPixmap (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); + Bool ret; + if (pPixmap->refcnt == 1) + { + ShmDescPtr shmdesc; + shmdesc = (ShmDescPtr)dixLookupPrivate(&pPixmap->devPrivates, + shmPixmapPrivate); + if (shmdesc) + ShmDetachSegment ((pointer) shmdesc, pPixmap->drawable.id); + } + + pScreen->DestroyPixmap = screen_priv->destroyPixmap; + ret = (*pScreen->DestroyPixmap) (pPixmap); + screen_priv->destroyPixmap = pScreen->DestroyPixmap; + pScreen->DestroyPixmap = ShmDestroyPixmap; + return ret; +} + +void +ShmRegisterFbFuncs(ScreenPtr pScreen) +{ + ShmRegisterFuncs(pScreen, &fbFuncs); +} + +static int +ProcShmQueryVersion(ClientPtr client) +{ + xShmQueryVersionReply rep; + int n; + + REQUEST_SIZE_MATCH(xShmQueryVersionReq); + memset(&rep, 0, sizeof(xShmQueryVersionReply)); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.sharedPixmaps = sharedPixmaps; + rep.pixmapFormat = sharedPixmaps ? ZPixmap : 0; + rep.majorVersion = SERVER_SHM_MAJOR_VERSION; + rep.minorVersion = SERVER_SHM_MINOR_VERSION; + rep.uid = geteuid(); + rep.gid = getegid(); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + swaps(&rep.uid, n); + swaps(&rep.gid, n); + } + WriteToClient(client, sizeof(xShmQueryVersionReply), (char *)&rep); + return Success; +} + +/* + * Simulate the access() system call for a shared memory segement, + * using the credentials from the client if available + */ +static int +shm_access(ClientPtr client, SHMPERM_TYPE *perm, int readonly) +{ + int uid, gid; + mode_t mask; + int uidset = 0, gidset = 0; + LocalClientCredRec *lcc; + + if (GetLocalClientCreds(client, &lcc) != -1) { + + if (lcc->fieldsSet & LCC_UID_SET) { + uid = lcc->euid; + uidset = 1; + } + if (lcc->fieldsSet & LCC_GID_SET) { + gid = lcc->egid; + gidset = 1; + } + +#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID) + if ( ((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1) + || (lcc->zoneid != SHMPERM_ZONEID(perm))) { + uidset = 0; + gidset = 0; + } +#endif + FreeLocalClientCreds(lcc); + + if (uidset) { + /* User id 0 always gets access */ + if (uid == 0) { + return 0; + } + /* Check the owner */ + if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) { + mask = S_IRUSR; + if (!readonly) { + mask |= S_IWUSR; + } + return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; + } + } + + if (gidset) { + /* Check the group */ + if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) { + mask = S_IRGRP; + if (!readonly) { + mask |= S_IWGRP; + } + return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; + } + } + } + /* Otherwise, check everyone else */ + mask = S_IROTH; + if (!readonly) { + mask |= S_IWOTH; + } + return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; +} + +static int +ProcShmAttach(ClientPtr client) +{ + SHMSTAT_TYPE 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)) || + SHMSTAT(stuff->shmid, &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, &(SHM_PERM(buf)), stuff->readOnly) == -1) { + shmdt(shmdesc->addr); + free(shmdesc); + return BadAccess; + } + + shmdesc->shmid = stuff->shmid; + shmdesc->refcnt = 1; + shmdesc->writable = !stuff->readOnly; + shmdesc->size = SHM_SEGSZ(buf); + shmdesc->next = Shmsegs; + Shmsegs = shmdesc; + } + if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc)) + return BadAlloc; + return Success; +} + +/*ARGSUSED*/ +static int +ShmDetachSegment(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(ClientPtr client) +{ + ShmDescPtr shmdesc; + REQUEST(xShmDetachReq); + + REQUEST_SIZE_MATCH(xShmDetachReq); + VERIFY_SHMSEG(stuff->shmseg, shmdesc, client); + FreeResource(stuff->shmseg, RT_NONE); + return Success; +} + +/* + * If the given request doesn't exactly match PutImage's constraints, + * wrap the image in a scratch pixmap header and let CopyArea sort it out. + */ +static void +doShmPutImage(DrawablePtr dst, GCPtr pGC, + int depth, unsigned int format, + int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, + char *data) +{ + PixmapPtr pPixmap; + + if (format == ZPixmap || depth == 1) { + pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth, + BitsPerPixel(depth), + PixmapBytePad(w, depth), + data); + if (!pPixmap) + return; + pGC->ops->CopyArea((DrawablePtr)pPixmap, dst, pGC, sx, sy, sw, sh, dx, dy); + FreeScratchPixmapHeader(pPixmap); + } else { + GCPtr putGC = GetScratchGC(depth, dst->pScreen); + + if (!putGC) + return; + + pPixmap = (*dst->pScreen->CreatePixmap)(dst->pScreen, sw, sh, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pPixmap) { + FreeScratchGC(putGC); + return; + } + ValidateGC(&pPixmap->drawable, putGC); + (*putGC->ops->PutImage)(&pPixmap->drawable, putGC, depth, -sx, -sy, w, h, 0, + (format == XYPixmap) ? XYPixmap : ZPixmap, data); + FreeScratchGC(putGC); + if (format == XYBitmap) + (void)(*pGC->ops->CopyPlane)(&pPixmap->drawable, dst, pGC, 0, 0, sw, sh, + dx, dy, 1L); + else + (void)(*pGC->ops->CopyArea)(&pPixmap->drawable, dst, pGC, 0, 0, sw, sh, + dx, dy); + (*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap); + } +} + +#ifdef PANORAMIX +static int +ProcPanoramiXShmPutImage(ClientPtr client) +{ + int j, result, orig_x, orig_y; + PanoramiXRes *draw, *gc; + Bool sendEvent, isRoot; + + REQUEST(xShmPutImageReq); + REQUEST_SIZE_MATCH(xShmPutImageReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, + XRT_GC, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + orig_x = stuff->dstX; + orig_y = stuff->dstY; + sendEvent = stuff->sendEvent; + stuff->sendEvent = 0; + FOR_NSCREENS(j) { + if(!j) stuff->sendEvent = sendEvent; + stuff->drawable = draw->info[j].id; + stuff->gc = gc->info[j].id; + if (isRoot) { + stuff->dstX = orig_x - panoramiXdataPtr[j].x; + stuff->dstY = orig_y - panoramiXdataPtr[j].y; + } + result = ProcShmPutImage(client); + if(result != Success) break; + } + return(result); +} + +static int +ProcPanoramiXShmGetImage(ClientPtr client) +{ + PanoramiXRes *draw; + DrawablePtr *drawables; + DrawablePtr pDraw; + xShmGetImageReply xgi; + ShmDescPtr shmdesc; + int i, x, y, w, h, format, rc; + Mask plane = 0, planemask; + long lenPer = 0, length, widthBytesLine; + Bool isRoot; + + REQUEST(xShmGetImageReq); + + REQUEST_SIZE_MATCH(xShmGetImageReq); + + if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) { + client->errorValue = stuff->format; + return(BadValue); + } + + rc = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (rc != Success) + return (rc == BadValue) ? BadDrawable : rc; + + if (draw->type == XRT_PIXMAP) + return ProcShmGetImage(client); + + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); + + x = stuff->x; + y = stuff->y; + w = stuff->width; + h = stuff->height; + format = stuff->format; + planemask = stuff->planeMask; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + if(isRoot) { + if( /* check for being onscreen */ + x < 0 || x + w > PanoramiXPixWidth || + y < 0 || y + h > PanoramiXPixHeight ) + return(BadMatch); + } else { + if( /* check for being onscreen */ + panoramiXdataPtr[0].x + pDraw->x + x < 0 || + panoramiXdataPtr[0].x + pDraw->x + x + w > PanoramiXPixWidth || + panoramiXdataPtr[0].y + pDraw->y + y < 0 || + panoramiXdataPtr[0].y + pDraw->y + y + h > PanoramiXPixHeight || + /* check for being inside of border */ + x < - wBorderWidth((WindowPtr)pDraw) || + x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || + y < -wBorderWidth((WindowPtr)pDraw) || + y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height) + return(BadMatch); + } + + drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr)); + if(!drawables) + return(BadAlloc); + + drawables[0] = pDraw; + for(i = 1; i < PanoramiXNumScreens; i++) { + rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0, + DixReadAccess); + if (rc != Success) + { + free(drawables); + return rc; + } + } + + xgi.visual = wVisual(((WindowPtr)pDraw)); + xgi.type = X_Reply; + xgi.length = 0; + xgi.sequenceNumber = client->sequence; + xgi.depth = pDraw->depth; + + if(format == ZPixmap) { + widthBytesLine = PixmapBytePad(w, pDraw->depth); + length = widthBytesLine * h; + } else { + widthBytesLine = PixmapBytePad(w, 1); + lenPer = widthBytesLine * h; + plane = ((Mask)1) << (pDraw->depth - 1); + length = lenPer * Ones(planemask & (plane | (plane - 1))); + } + + VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); + xgi.size = length; + + if (length == 0) {/* nothing to do */ } + else if (format == ZPixmap) { + XineramaGetImageData(drawables, x, y, w, h, format, planemask, + shmdesc->addr + stuff->offset, + widthBytesLine, isRoot); + } else { + + length = stuff->offset; + for (; plane; plane >>= 1) { + if (planemask & plane) { + XineramaGetImageData(drawables, x, y, w, h, + format, plane, shmdesc->addr + length, + widthBytesLine, isRoot); + length += lenPer; + } + } + } + free(drawables); + + if (client->swapped) { + int n; + swaps(&xgi.sequenceNumber, n); + swapl(&xgi.length, n); + swapl(&xgi.visual, n); + swapl(&xgi.size, n); + } + WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); + + return Success; +} + +static int +ProcPanoramiXShmCreatePixmap(ClientPtr client) +{ + ScreenPtr pScreen = NULL; + PixmapPtr pMap = NULL; + DrawablePtr pDraw; + DepthPtr pDepth; + int i, j, result, rc; + ShmDescPtr shmdesc; + REQUEST(xShmCreatePixmapReq); + unsigned int width, height, depth; + unsigned long size; + PanoramiXRes *newPix; + + REQUEST_SIZE_MATCH(xShmCreatePixmapReq); + client->errorValue = stuff->pid; + if (!sharedPixmaps) + return BadImplementation; + LEGAL_NEW_RESOURCE(stuff->pid, client); + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, + DixGetAttrAccess); + if (rc != Success) + return rc; + + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); + + width = stuff->width; + height = stuff->height; + depth = stuff->depth; + if (!width || !height || !depth) + { + client->errorValue = 0; + return BadValue; + } + if (width > 32767 || height > 32767) + return BadAlloc; + + if (stuff->depth != 1) + { + pDepth = pDraw->pScreen->allowedDepths; + for (i=0; ipScreen->numDepths; i++, pDepth++) + if (pDepth->depth == stuff->depth) + goto CreatePmap; + client->errorValue = stuff->depth; + return BadValue; + } + +CreatePmap: + size = PixmapBytePad(width, depth) * height; + if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { + if (size < width * height) + return BadAlloc; + } + /* thankfully, offset is unsigned */ + if (stuff->offset + size < size) + return BadAlloc; + + VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); + + if(!(newPix = malloc(sizeof(PanoramiXRes)))) + return BadAlloc; + + newPix->type = XRT_PIXMAP; + newPix->u.pix.shared = TRUE; + newPix->info[0].id = stuff->pid; + for(j = 1; j < PanoramiXNumScreens; j++) + newPix->info[j].id = FakeClientID(client->index); + + result = Success; + + FOR_NSCREENS(j) { + ShmScrPrivateRec *screen_priv; + pScreen = screenInfo.screens[j]; + + screen_priv = ShmGetScreenPriv(pScreen); + pMap = (*screen_priv->shmFuncs->CreatePixmap)(pScreen, + stuff->width, stuff->height, stuff->depth, + shmdesc->addr + stuff->offset); + + if (pMap) { + dixSetPrivate(&pMap->devPrivates, shmPixmapPrivate, shmdesc); + shmdesc->refcnt++; + pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pMap->drawable.id = newPix->info[j].id; + if (!AddResource(newPix->info[j].id, RT_PIXMAP, (pointer)pMap)) { + (*pScreen->DestroyPixmap)(pMap); + result = BadAlloc; + break; + } + } else { + result = BadAlloc; + break; + } + } + + if(result == BadAlloc) { + while(j--) { + (*pScreen->DestroyPixmap)(pMap); + FreeResource(newPix->info[j].id, RT_NONE); + } + free(newPix); + } else + AddResource(stuff->pid, XRT_PIXMAP, newPix); + + return result; +} + +#endif + +static int +ProcShmPutImage(ClientPtr client) +{ + GCPtr pGC; + DrawablePtr pDraw; + long length; + ShmDescPtr shmdesc; + REQUEST(xShmPutImageReq); + + REQUEST_SIZE_MATCH(xShmPutImageReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + 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; + } + + /* + * There's a potential integer overflow in this check: + * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, + * client); + * the version below ought to avoid it + */ + if (stuff->totalHeight != 0 && + length > (shmdesc->size - stuff->offset)/stuff->totalHeight) { + client->errorValue = stuff->totalWidth; + return BadValue; + } + 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 + doShmPutImage(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 Success; +} + + + +static int +ProcShmGetImage(ClientPtr client) +{ + DrawablePtr pDraw; + long lenPer = 0, length; + Mask plane = 0; + xShmGetImageReply xgi; + ShmDescPtr shmdesc; + int n, rc; + + REQUEST(xShmGetImageReq); + + REQUEST_SIZE_MATCH(xShmGetImageReq); + if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) + { + client->errorValue = stuff->format; + return(BadValue); + } + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + 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, n); + swapl(&xgi.length, n); + swapl(&xgi.visual, n); + swapl(&xgi.size, n); + } + WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); + + return Success; +} + +static PixmapPtr +fbShmCreatePixmap (ScreenPtr pScreen, + int width, int height, int depth, char *addr) +{ + PixmapPtr pPixmap; + + pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0); + 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(ClientPtr client) +{ + PixmapPtr pMap; + DrawablePtr pDraw; + DepthPtr pDepth; + int i, rc; + ShmDescPtr shmdesc; + ShmScrPrivateRec *screen_priv; + REQUEST(xShmCreatePixmapReq); + unsigned int width, height, depth; + unsigned long size; + + REQUEST_SIZE_MATCH(xShmCreatePixmapReq); + client->errorValue = stuff->pid; + if (!sharedPixmaps) + return BadImplementation; + LEGAL_NEW_RESOURCE(stuff->pid, client); + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, + DixGetAttrAccess); + if (rc != Success) + return rc; + + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); + + width = stuff->width; + height = stuff->height; + depth = stuff->depth; + if (!width || !height || !depth) + { + client->errorValue = 0; + return BadValue; + } + if (width > 32767 || height > 32767) + return BadAlloc; + + if (stuff->depth != 1) + { + pDepth = pDraw->pScreen->allowedDepths; + for (i=0; ipScreen->numDepths; i++, pDepth++) + if (pDepth->depth == stuff->depth) + goto CreatePmap; + client->errorValue = stuff->depth; + return BadValue; + } + +CreatePmap: + size = PixmapBytePad(width, depth) * height; + if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { + if (size < width * height) + return BadAlloc; + } + /* thankfully, offset is unsigned */ + if (stuff->offset + size < size) + return BadAlloc; + + VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); + screen_priv = ShmGetScreenPriv(pDraw->pScreen); + pMap = (*screen_priv->shmFuncs->CreatePixmap)( + pDraw->pScreen, stuff->width, + stuff->height, stuff->depth, + shmdesc->addr + stuff->offset); + if (pMap) + { + rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP, + pMap, RT_NONE, NULL, DixCreateAccess); + if (rc != Success) { + pDraw->pScreen->DestroyPixmap(pMap); + return rc; + } + dixSetPrivate(&pMap->devPrivates, shmPixmapPrivate, shmdesc); + shmdesc->refcnt++; + pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pMap->drawable.id = stuff->pid; + if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap)) + { + return Success; + } + pDraw->pScreen->DestroyPixmap(pMap); + } + return (BadAlloc); +} + +static int +ProcShmDispatch (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: +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + return ProcPanoramiXShmPutImage(client); +#endif + return ProcShmPutImage(client); + case X_ShmGetImage: +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + return ProcPanoramiXShmGetImage(client); +#endif + return ProcShmGetImage(client); + case X_ShmCreatePixmap: +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + return ProcPanoramiXShmCreatePixmap(client); +#endif + return ProcShmCreatePixmap(client); + default: + return BadRequest; + } +} + +static void +SShmCompletionEvent(xShmCompletionEvent *from, xShmCompletionEvent *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(ClientPtr client) +{ + int n; + REQUEST(xShmQueryVersionReq); + + swaps(&stuff->length, n); + return ProcShmQueryVersion(client); +} + +static int +SProcShmAttach(ClientPtr client) +{ + int n; + REQUEST(xShmAttachReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmAttachReq); + swapl(&stuff->shmseg, n); + swapl(&stuff->shmid, n); + return ProcShmAttach(client); +} + +static int +SProcShmDetach(ClientPtr client) +{ + int n; + REQUEST(xShmDetachReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmDetachReq); + swapl(&stuff->shmseg, n); + return ProcShmDetach(client); +} + +static int +SProcShmPutImage(ClientPtr client) +{ + int n; + REQUEST(xShmPutImageReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmPutImageReq); + swapl(&stuff->drawable, n); + swapl(&stuff->gc, n); + swaps(&stuff->totalWidth, n); + swaps(&stuff->totalHeight, n); + swaps(&stuff->srcX, n); + swaps(&stuff->srcY, n); + swaps(&stuff->srcWidth, n); + swaps(&stuff->srcHeight, n); + swaps(&stuff->dstX, n); + swaps(&stuff->dstY, n); + swapl(&stuff->shmseg, n); + swapl(&stuff->offset, n); + return ProcShmPutImage(client); +} + +static int +SProcShmGetImage(ClientPtr client) +{ + int n; + REQUEST(xShmGetImageReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmGetImageReq); + swapl(&stuff->drawable, n); + swaps(&stuff->x, n); + swaps(&stuff->y, n); + swaps(&stuff->width, n); + swaps(&stuff->height, n); + swapl(&stuff->planeMask, n); + swapl(&stuff->shmseg, n); + swapl(&stuff->offset, n); + return ProcShmGetImage(client); +} + +static int +SProcShmCreatePixmap(ClientPtr client) +{ + int n; + REQUEST(xShmCreatePixmapReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmCreatePixmapReq); + swapl(&stuff->pid, n); + swapl(&stuff->drawable, n); + swaps(&stuff->width, n); + swaps(&stuff->height, n); + swapl(&stuff->shmseg, n); + swapl(&stuff->offset, n); + return ProcShmCreatePixmap(client); +} + +static int +SProcShmDispatch (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/xorg-server/Xext/sleepuntil.c b/xorg-server/Xext/sleepuntil.c index 075f428d4..69945585d 100644 --- a/xorg-server/Xext/sleepuntil.c +++ b/xorg-server/Xext/sleepuntil.c @@ -1,225 +1,225 @@ -/* - * -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 */ -); - -int -ClientSleepUntil (ClientPtr client, - TimeStamp *revive, - void (*notifyFunc)(ClientPtr, pointer), - pointer closure) -{ - SertafiedPtr pRequest, pReq, pPrev; - - if (SertafiedGeneration != serverGeneration) - { - SertafiedResType = CreateNewResourceType (SertafiedDelete, - "ClientSleep"); - if (!SertafiedResType) - return FALSE; - SertafiedGeneration = serverGeneration; - BlockHandlerRegistered = FALSE; - } - pRequest = xalloc (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)) - { - xfree (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 (ClientPtr client, pointer closure) -{ - if (!client->clientGone) - AttendClient (client); -} - - -static int -SertafiedDelete (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); - xfree (pRequest); - return TRUE; -} - -static void -SertafiedBlockHandler (pointer data, OSTimePtr wt, 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 (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; - } -} +/* + * +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 */ +); + +int +ClientSleepUntil (ClientPtr client, + TimeStamp *revive, + void (*notifyFunc)(ClientPtr, pointer), + pointer closure) +{ + SertafiedPtr pRequest, pReq, pPrev; + + if (SertafiedGeneration != serverGeneration) + { + SertafiedResType = CreateNewResourceType (SertafiedDelete, + "ClientSleep"); + 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 (ClientPtr client, pointer closure) +{ + if (!client->clientGone) + AttendClient (client); +} + + +static int +SertafiedDelete (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 (pointer data, OSTimePtr wt, 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 (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/xorg-server/Xext/sync.c b/xorg-server/Xext/sync.c index e865e527a..8faab0d1d 100644 --- a/xorg-server/Xext/sync.c +++ b/xorg-server/Xext/sync.c @@ -1,2399 +1,2399 @@ -/* - -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" -#include -#include "syncsrv.h" - -#include -#if !defined(WIN32) -#include -#endif - -#include "modinit.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 void SyncComputeBracketValues(SyncCounter *); - -static void SyncInitServerTime(void); - -static void SyncInitIdleTime(void); - -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(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; - - xfree(pCur); - break; - } - - pPrev = pCur; - pCur = pCur->next; - } - - if (IsSystemCounter(pTrigger->pCounter)) - SyncComputeBracketValues(pTrigger->pCounter); -} - - -static int -SyncAddTriggerToCounter(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 = xalloc(sizeof(SyncTriggerList)))) - return BadAlloc; - - pCur->pTrigger = pTrigger; - pCur->next = pTrigger->pCounter->pTriglist; - pTrigger->pCounter->pTriglist = pCur; - - if (IsSystemCounter(pTrigger->pCounter)) - SyncComputeBracketValues(pTrigger->pCounter); - - 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(SyncTrigger *pTrigger, CARD64 oldval) -{ - return (pTrigger->pCounter == NULL || - XSyncValueGreaterOrEqual(pTrigger->pCounter->value, - pTrigger->test_value)); -} - -static Bool -SyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger, CARD64 oldval) -{ - return (pTrigger->pCounter == NULL || - XSyncValueLessOrEqual(pTrigger->pCounter->value, - pTrigger->test_value)); -} - -static Bool -SyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval) -{ - return (pTrigger->pCounter == NULL || - (XSyncValueLessThan(oldval, pTrigger->test_value) && - XSyncValueGreaterOrEqual(pTrigger->pCounter->value, - pTrigger->test_value))); -} - -static Bool -SyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval) -{ - return (pTrigger->pCounter == NULL || - (XSyncValueGreaterThan(oldval, pTrigger->test_value) && - XSyncValueLessOrEqual(pTrigger->pCounter->value, - pTrigger->test_value))); -} - -static int -SyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XSyncCounter counter, - Mask changes) -{ - SyncCounter *pCounter = pTrigger->pCounter; - int rc; - Bool newcounter = FALSE; - - if (changes & XSyncCACounter) - { - if (counter == None) - pCounter = NULL; - else if (Success != (rc = dixLookupResourceByType ((pointer *)&pCounter, - counter, RTCounter, client, DixReadAccess))) - { - client->errorValue = counter; - return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; - } - 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 ((rc = SyncAddTriggerToCounter(pTrigger)) != Success) - return rc; - } - else if (IsSystemCounter(pCounter)) - { - SyncComputeBracketValues(pCounter); - } - - 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(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(ClientPtr client, SyncAwait **ppAwait, - int num_events) -{ - xSyncCounterNotifyEvent *pEvents, *pev; - int i; - - if (client->clientGone) - return; - pev = pEvents = xalloc(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); - xfree(pEvents); -} - - -/* This function is called when an alarm's counter is destroyed. - * It is plugged into pTrigger->CounterDestroyed (for alarm triggers). - */ -static void -SyncAlarmCounterDestroyed(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(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(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 = xalloc(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); - xfree(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(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); - } -} - - -/* loosely based on dix/events.c/EventSelectForWindow */ -static Bool -SyncEventSelectForAlarm(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 = xalloc(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)) - { - xfree(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(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(ClientPtr client, XSyncCounter id, CARD64 initialvalue) -{ - SyncCounter *pCounter; - - if (!(pCounter = xalloc(sizeof(SyncCounter)))) - return NULL; - - if (!AddResource(id, RTCounter, (pointer) pCounter)) - { - xfree(pCounter); - return NULL; - } - - pCounter->client = client; - pCounter->id = id; - pCounter->value = initialvalue; - pCounter->pTriglist = NULL; - pCounter->beingDestroyed = FALSE; - pCounter->pSysCounterInfo = NULL; - return pCounter; -} - -static int FreeCounter(void *, XID); - -/* - * ***** System Counter utilities - */ - -pointer -SyncCreateSystemCounter( - 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 = xrealloc(SysCounterList, - (SyncNumSystemCounters+1)*sizeof(SyncCounter *)); - if (!SysCounterList) - return 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, "SyncCounter"); - if (RTCounter == 0) - { - return NULL; - } - } - - pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial); - - if (pCounter) - { - SysCounterInfo *psci; - - psci = xalloc(sizeof(SysCounterInfo)); - if (!psci) - { - FreeResource(pCounter->id, RT_NONE); - return 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 pCounter; -} - -void -SyncDestroySystemCounter(pointer pSysCounter) -{ - SyncCounter *pCounter = (SyncCounter *)pSysCounter; - FreeResource(pCounter->id, RT_NONE); -} - -static void -SyncComputeBracketValues(SyncCounter *pCounter) -{ - 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; - - 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 == XSyncNegativeTransition && - ct != XSyncCounterNeverIncreases) - { - 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 != XSyncCounterNeverDecreases) - { - if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) && - XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) - { - psci->bracket_greater = pTrigger->test_value; - pnewgtval = &psci->bracket_greater; - } - } - } /* end for each trigger */ - - if (pnewgtval || pnewltval) - { - (*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval); - } -} - -/* - * ***** Resource delete functions - */ - -/* ARGSUSED */ -static int -FreeAlarm(void *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); - - xfree(pAlarm); - return Success; -} - - -/* - * ** Cleanup after the destruction of a Counter - */ -/* ARGSUSED */ -static int -FreeCounter(void *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; - xfree(ptl); /* destroy the trigger list as we go */ - } - if (IsSystemCounter(pCounter)) - { - int i, found = 0; - - xfree(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--; - } - xfree(pCounter); - return Success; -} - -/* - * ** Cleanup after Await - */ -/* ARGSUSED */ -static int -FreeAwait(void *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); - } - xfree(pAwaitUnion); - return Success; -} - -/* loosely based on dix/events.c/OtherClientGone */ -static int -FreeAlarmClient(void *value, 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; - xfree(pCur); - return Success; - } - } - FatalError("alarm client not on event list"); - /*NOTREACHED*/ -} - - -/* - * ***** Proc functions - */ - - -/* - * ** Initialize the extension - */ -static int -ProcSyncInitialize(ClientPtr client) -{ - xSyncInitializeReply rep; - int n; - - REQUEST_SIZE_MATCH(xSyncInitializeReq); - - memset(&rep, 0, sizeof(xSyncInitializeReply)); - 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, n); - } - WriteToClient(client, sizeof(rep), (char *) &rep); - return client->noClientException; -} - -/* - * ** Get list of system counters available through the extension - */ -static int -ProcSyncListSystemCounters(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 += pad_to_int32(sz_xSyncSystemCounter + strlen(name)); - } - - if (len) - { - walklist = list = xalloc(len); - if (!list) - return BadAlloc; - } - - rep.length = bytes_to_int32(len); - - if (client->swapped) - { - char n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.nCounters, n); - } - - 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) - { - char n; - swapl(&walklist->counter, n); - swapl(&walklist->resolution_hi, n); - swapl(&walklist->resolution_lo, n); - swaps(&walklist->name_length, n); - } - - pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter; - strncpy(pname_in_reply, psci->name, namelen); - walklist = (xSyncSystemCounter *) (((char *)walklist) + - pad_to_int32(sz_xSyncSystemCounter + namelen)); - } - - WriteToClient(client, sizeof(rep), (char *) &rep); - if (len) - { - WriteToClient(client, len, (char *) list); - xfree(list); - } - - return client->noClientException; -} - -/* - * ** Set client Priority - */ -static int -ProcSyncSetPriority(ClientPtr client) -{ - REQUEST(xSyncSetPriorityReq); - ClientPtr priorityclient; - int rc; - - REQUEST_SIZE_MATCH(xSyncSetPriorityReq); - - if (stuff->id == None) - priorityclient = client; - else { - rc = dixLookupClient(&priorityclient, stuff->id, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - - 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(ClientPtr client) -{ - REQUEST(xSyncGetPriorityReq); - xSyncGetPriorityReply rep; - ClientPtr priorityclient; - int rc; - - REQUEST_SIZE_MATCH(xSyncGetPriorityReq); - - if (stuff->id == None) - priorityclient = client; - else { - rc = dixLookupClient(&priorityclient, stuff->id, client, - DixGetAttrAccess); - if (rc != Success) - return rc; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.priority = priorityclient->priority; - - if (client->swapped) - { - char n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.priority, n); - } - - WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep); - - return client->noClientException; -} - -/* - * ** Create a new counter - */ -static int -ProcSyncCreateCounter(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(ClientPtr client) -{ - REQUEST(xSyncSetCounterReq); - SyncCounter *pCounter; - CARD64 newvalue; - int rc; - - REQUEST_SIZE_MATCH(xSyncSetCounterReq); - - rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter, - client, DixWriteAccess); - if (rc != Success) - return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; - - 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(ClientPtr client) -{ - REQUEST(xSyncChangeCounterReq); - SyncCounter *pCounter; - CARD64 newvalue; - Bool overflow; - int rc; - - REQUEST_SIZE_MATCH(xSyncChangeCounterReq); - - rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter, - client, DixWriteAccess); - if (rc != Success) - return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; - - 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(ClientPtr client) -{ - REQUEST(xSyncDestroyCounterReq); - SyncCounter *pCounter; - int rc; - - REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); - - rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, RTCounter, - client, DixDestroyAccess); - if (rc != Success) - return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; - - if (IsSystemCounter(pCounter)) - { - client->errorValue = stuff->counter; - return BadAccess; - } - FreeResource(pCounter->id, RT_NONE); - return Success; -} - - -/* - * ** Await - */ -static int -ProcSyncAwait(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 = xalloc((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)) - { - xfree(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(ClientPtr client) -{ - REQUEST(xSyncQueryCounterReq); - xSyncQueryCounterReply rep; - SyncCounter *pCounter; - int rc; - - REQUEST_SIZE_MATCH(xSyncQueryCounterReq); - - rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, - RTCounter, client, DixReadAccess); - if (rc != Success) - return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; - - 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) - { - char n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.value_hi, n); - swapl(&rep.value_lo, n); - } - WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep); - return client->noClientException; -} - - -/* - * ** Create Alarm - */ -static int -ProcSyncCreateAlarm(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 - bytes_to_int32(sizeof(xSyncCreateAlarmReq)); - /* 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 = xalloc(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) - { - xfree(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) - { - xfree(pAlarm); - return status; - } - - if (!AddResource(stuff->id, RTAlarm, pAlarm)) - { - xfree(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(ClientPtr client) -{ - REQUEST(xSyncChangeAlarmReq); - SyncAlarm *pAlarm; - long vmask; - int len, status; - - REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); - - status = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm, - client, DixWriteAccess); - if (status != Success) - return (status == BadValue) ? SyncErrorBase + XSyncBadAlarm : status; - - vmask = stuff->valueMask; - len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq)); - /* 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(ClientPtr client) -{ - REQUEST(xSyncQueryAlarmReq); - SyncAlarm *pAlarm; - xSyncQueryAlarmReply rep; - SyncTrigger *pTrigger; - int rc; - - REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); - - rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm, - client, DixReadAccess); - if (rc != Success) - return (rc == BadValue) ? SyncErrorBase + XSyncBadAlarm : rc; - - rep.type = X_Reply; - rep.length = bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)); - 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) - { - char n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.counter, n); - swapl(&rep.wait_value_hi, n); - swapl(&rep.wait_value_lo, n); - swapl(&rep.test_type, n); - swapl(&rep.delta_hi, n); - swapl(&rep.delta_lo, n); - } - - WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep); - return client->noClientException; -} - -static int -ProcSyncDestroyAlarm(ClientPtr client) -{ - SyncAlarm *pAlarm; - int rc; - REQUEST(xSyncDestroyAlarmReq); - - REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); - - rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm, - client, DixDestroyAccess); - if (rc != Success) - return (rc == BadValue) ? SyncErrorBase + XSyncBadAlarm : rc; - - FreeResource(stuff->alarm, RT_NONE); - return client->noClientException; -} - -/* - * ** Given an extension request, call the appropriate request procedure - */ -static int -ProcSyncDispatch(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(ClientPtr client) -{ - REQUEST(xSyncInitializeReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncInitializeReq); - - return ProcSyncInitialize(client); -} - -static int -SProcSyncListSystemCounters(ClientPtr client) -{ - REQUEST(xSyncListSystemCountersReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncListSystemCountersReq); - - return ProcSyncListSystemCounters(client); -} - -static int -SProcSyncCreateCounter(ClientPtr client) -{ - REQUEST(xSyncCreateCounterReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncCreateCounterReq); - swapl(&stuff->cid, n); - swapl(&stuff->initial_value_lo, n); - swapl(&stuff->initial_value_hi, n); - - return ProcSyncCreateCounter(client); -} - -static int -SProcSyncSetCounter(ClientPtr client) -{ - REQUEST(xSyncSetCounterReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncSetCounterReq); - swapl(&stuff->cid, n); - swapl(&stuff->value_lo, n); - swapl(&stuff->value_hi, n); - - return ProcSyncSetCounter(client); -} - -static int -SProcSyncChangeCounter(ClientPtr client) -{ - REQUEST(xSyncChangeCounterReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncChangeCounterReq); - swapl(&stuff->cid, n); - swapl(&stuff->value_lo, n); - swapl(&stuff->value_hi, n); - - return ProcSyncChangeCounter(client); -} - -static int -SProcSyncQueryCounter(ClientPtr client) -{ - REQUEST(xSyncQueryCounterReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncQueryCounterReq); - swapl(&stuff->counter, n); - - return ProcSyncQueryCounter(client); -} - -static int -SProcSyncDestroyCounter(ClientPtr client) -{ - REQUEST(xSyncDestroyCounterReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncDestroyCounterReq); - swapl(&stuff->counter, n); - - return ProcSyncDestroyCounter(client); -} - -static int -SProcSyncAwait(ClientPtr client) -{ - REQUEST(xSyncAwaitReq); - char n; - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); - SwapRestL(stuff); - - return ProcSyncAwait(client); -} - -static int -SProcSyncCreateAlarm(ClientPtr client) -{ - REQUEST(xSyncCreateAlarmReq); - char n; - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); - swapl(&stuff->id, n); - swapl(&stuff->valueMask, n); - SwapRestL(stuff); - - return ProcSyncCreateAlarm(client); -} - -static int -SProcSyncChangeAlarm(ClientPtr client) -{ - REQUEST(xSyncChangeAlarmReq); - char n; - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); - swapl(&stuff->alarm, n); - swapl(&stuff->valueMask, n); - SwapRestL(stuff); - return ProcSyncChangeAlarm(client); -} - -static int -SProcSyncQueryAlarm(ClientPtr client) -{ - REQUEST(xSyncQueryAlarmReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncQueryAlarmReq); - swapl(&stuff->alarm, n); - - return ProcSyncQueryAlarm(client); -} - -static int -SProcSyncDestroyAlarm(ClientPtr client) -{ - REQUEST(xSyncDestroyAlarmReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq); - swapl(&stuff->alarm, n); - - return ProcSyncDestroyAlarm(client); -} - -static int -SProcSyncSetPriority(ClientPtr client) -{ - REQUEST(xSyncSetPriorityReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncSetPriorityReq); - swapl(&stuff->id, n); - swapl(&stuff->priority, n); - - return ProcSyncSetPriority(client); -} - -static int -SProcSyncGetPriority(ClientPtr client) -{ - REQUEST(xSyncGetPriorityReq); - char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH (xSyncGetPriorityReq); - swapl(&stuff->id, n); - - return ProcSyncGetPriority(client); -} - - -static int -SProcSyncDispatch(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(xSyncCounterNotifyEvent *from, xSyncCounterNotifyEvent *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(xSyncAlarmNotifyEvent *from, xSyncAlarmNotifyEvent *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(ExtensionEntry *extEntry) -{ - xfree(SysCounterList); - SysCounterList = NULL; - RTCounter = 0; -} - - -/* - * ** Initialise the extension. - */ -void -SyncExtensionInit(void) -{ - ExtensionEntry *extEntry; - - if (RTCounter == 0) - { - RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter"); - } - RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm"); - RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait"); - if (RTAwait) - RTAwait |= RC_NEVERRETAIN; - RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient"); - if (RTAlarmClient) - RTAlarmClient |= 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(); - SyncInitIdleTime(); - -#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 (now deprecated) - */ -/*ARGSUSED*/ -static void -ServertimeBlockHandler(void *env, struct timeval **wt, void *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(void *env, int rc, void *LastSelectMask) -{ - if (pnext_time) - { - GetTime(); - - if (XSyncValueGreaterOrEqual(Now, *pnext_time)) - { - SyncChangeCounter(ServertimeCounter, Now); - } - } -} - -static void -ServertimeQueryValue(void *pCounter, CARD64 *pValue_return) -{ - GetTime(); - *pValue_return = Now; -} - -static void -ServertimeBracketValues(void *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(void) -{ - CARD64 resolution; - - XSyncIntsToValue(&Now, GetTimeInMillis(), 0); - XSyncIntToValue(&resolution, 4); - ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution, - XSyncCounterNeverDecreases, - ServertimeQueryValue, ServertimeBracketValues); - pnext_time = NULL; -} - - - -/* - * IDLETIME implementation - */ - -static SyncCounter *IdleTimeCounter; -static XSyncValue *pIdleTimeValueLess; -static XSyncValue *pIdleTimeValueGreater; - -static void -IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return) -{ - CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds; - XSyncIntsToValue (pValue_return, idle, 0); -} - -static void -IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask) -{ - XSyncValue idle, old_idle; - SyncTriggerList *list = IdleTimeCounter->pTriglist; - SyncTrigger *trig; - - if (!pIdleTimeValueLess && !pIdleTimeValueGreater) - return; - - old_idle = IdleTimeCounter->value; - IdleTimeQueryValue (NULL, &idle); - IdleTimeCounter->value = idle; /* push, so CheckTrigger works */ - - if (pIdleTimeValueLess && - XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)) - { - /* - * We've been idle for less than the threshold value, and someone - * wants to know about that, but now we need to know whether they - * want level or edge trigger. Check the trigger list against the - * current idle time, and if any succeed, bomb out of select() - * immediately so we can reschedule. - */ - - for (list = IdleTimeCounter->pTriglist; list; list = list->next) { - trig = list->pTrigger; - if (trig->CheckTrigger(trig, old_idle)) { - AdjustWaitForDelay(wt, 0); - break; - } - } - } - else if (pIdleTimeValueGreater) - { - /* - * There's a threshold in the positive direction. If we've been - * idle less than it, schedule a wakeup for sometime in the future. - * If we've been idle more than it, and someone wants to know about - * that level-triggered, schedule an immediate wakeup. - */ - unsigned long timeout = -1; - - if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) { - XSyncValue value; - Bool overflow; - - XSyncValueSubtract (&value, *pIdleTimeValueGreater, - idle, &overflow); - timeout = min(timeout, XSyncValueLow32 (value)); - } else { - for (list = IdleTimeCounter->pTriglist; list; list = list->next) { - trig = list->pTrigger; - if (trig->CheckTrigger(trig, old_idle)) { - timeout = min(timeout, 0); - break; - } - } - } - - AdjustWaitForDelay (wt, timeout); - } - - IdleTimeCounter->value = old_idle; /* pop */ -} - -static void -IdleTimeWakeupHandler (pointer env, int rc, pointer LastSelectMask) -{ - XSyncValue idle; - - if (!pIdleTimeValueLess && !pIdleTimeValueGreater) - return; - - IdleTimeQueryValue (NULL, &idle); - - if ((pIdleTimeValueGreater && - XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) || - (pIdleTimeValueLess && - XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))) - { - SyncChangeCounter (IdleTimeCounter, idle); - } -} - -static void -IdleTimeBracketValues (pointer pCounter, CARD64 *pbracket_less, - CARD64 *pbracket_greater) -{ - Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater); - - if (registered && !pbracket_less && !pbracket_greater) - { - RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler, - IdleTimeWakeupHandler, - NULL); - } - else if (!registered && (pbracket_less || pbracket_greater)) - { - RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler, - IdleTimeWakeupHandler, - NULL); - } - - pIdleTimeValueGreater = pbracket_greater; - pIdleTimeValueLess = pbracket_less; -} - -static void -SyncInitIdleTime (void) -{ - CARD64 resolution; - XSyncValue idle; - - IdleTimeQueryValue (NULL, &idle); - XSyncIntToValue (&resolution, 4); - - IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution, - XSyncCounterUnrestricted, - IdleTimeQueryValue, - IdleTimeBracketValues); - - pIdleTimeValueLess = pIdleTimeValueGreater = NULL; -} +/* + +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" +#include +#include "syncsrv.h" + +#include +#if !defined(WIN32) +#include +#endif + +#include "modinit.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 void SyncComputeBracketValues(SyncCounter *); + +static void SyncInitServerTime(void); + +static void SyncInitIdleTime(void); + +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(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); +} + + +static int +SyncAddTriggerToCounter(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); + + 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(SyncTrigger *pTrigger, CARD64 oldval) +{ + return (pTrigger->pCounter == NULL || + XSyncValueGreaterOrEqual(pTrigger->pCounter->value, + pTrigger->test_value)); +} + +static Bool +SyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger, CARD64 oldval) +{ + return (pTrigger->pCounter == NULL || + XSyncValueLessOrEqual(pTrigger->pCounter->value, + pTrigger->test_value)); +} + +static Bool +SyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval) +{ + return (pTrigger->pCounter == NULL || + (XSyncValueLessThan(oldval, pTrigger->test_value) && + XSyncValueGreaterOrEqual(pTrigger->pCounter->value, + pTrigger->test_value))); +} + +static Bool +SyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval) +{ + return (pTrigger->pCounter == NULL || + (XSyncValueGreaterThan(oldval, pTrigger->test_value) && + XSyncValueLessOrEqual(pTrigger->pCounter->value, + pTrigger->test_value))); +} + +static int +SyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XSyncCounter counter, + Mask changes) +{ + SyncCounter *pCounter = pTrigger->pCounter; + int rc; + Bool newcounter = FALSE; + + if (changes & XSyncCACounter) + { + if (counter == None) + pCounter = NULL; + else if (Success != (rc = dixLookupResourceByType ((pointer *)&pCounter, + counter, RTCounter, client, DixReadAccess))) + { + client->errorValue = counter; + return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; + } + 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 ((rc = SyncAddTriggerToCounter(pTrigger)) != Success) + return rc; + } + else if (IsSystemCounter(pCounter)) + { + SyncComputeBracketValues(pCounter); + } + + 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(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(ClientPtr client, SyncAwait **ppAwait, + int num_events) +{ + xSyncCounterNotifyEvent *pEvents, *pev; + int i; + + if (client->clientGone) + return; + pev = pEvents = malloc(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); + free(pEvents); +} + + +/* This function is called when an alarm's counter is destroyed. + * It is plugged into pTrigger->CounterDestroyed (for alarm triggers). + */ +static void +SyncAlarmCounterDestroyed(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(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(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 = malloc(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); + free(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(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); + } +} + + +/* loosely based on dix/events.c/EventSelectForWindow */ +static Bool +SyncEventSelectForAlarm(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(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(ClientPtr client, XSyncCounter id, CARD64 initialvalue) +{ + SyncCounter *pCounter; + + if (!(pCounter = malloc(sizeof(SyncCounter)))) + return NULL; + + if (!AddResource(id, RTCounter, (pointer) pCounter)) + { + free(pCounter); + return NULL; + } + + pCounter->client = client; + pCounter->id = id; + pCounter->value = initialvalue; + pCounter->pTriglist = NULL; + pCounter->beingDestroyed = FALSE; + pCounter->pSysCounterInfo = NULL; + return pCounter; +} + +static int FreeCounter(void *, XID); + +/* + * ***** System Counter utilities + */ + +pointer +SyncCreateSystemCounter( + 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 = realloc(SysCounterList, + (SyncNumSystemCounters+1)*sizeof(SyncCounter *)); + if (!SysCounterList) + return 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, "SyncCounter"); + if (RTCounter == 0) + { + return NULL; + } + } + + pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial); + + if (pCounter) + { + SysCounterInfo *psci; + + psci = malloc(sizeof(SysCounterInfo)); + if (!psci) + { + FreeResource(pCounter->id, RT_NONE); + return 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 pCounter; +} + +void +SyncDestroySystemCounter(pointer pSysCounter) +{ + SyncCounter *pCounter = (SyncCounter *)pSysCounter; + FreeResource(pCounter->id, RT_NONE); +} + +static void +SyncComputeBracketValues(SyncCounter *pCounter) +{ + 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; + + 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 == XSyncNegativeTransition && + ct != XSyncCounterNeverIncreases) + { + 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 != XSyncCounterNeverDecreases) + { + if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) && + XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) + { + psci->bracket_greater = pTrigger->test_value; + pnewgtval = &psci->bracket_greater; + } + } + } /* end for each trigger */ + + if (pnewgtval || pnewltval) + { + (*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval); + } +} + +/* + * ***** Resource delete functions + */ + +/* ARGSUSED */ +static int +FreeAlarm(void *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(void *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(void *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(void *value, 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(ClientPtr client) +{ + xSyncInitializeReply rep; + int n; + + REQUEST_SIZE_MATCH(xSyncInitializeReq); + + memset(&rep, 0, sizeof(xSyncInitializeReply)); + 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, n); + } + WriteToClient(client, sizeof(rep), (char *) &rep); + return Success; +} + +/* + * ** Get list of system counters available through the extension + */ +static int +ProcSyncListSystemCounters(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 += pad_to_int32(sz_xSyncSystemCounter + strlen(name)); + } + + if (len) + { + walklist = list = malloc(len); + if (!list) + return BadAlloc; + } + + rep.length = bytes_to_int32(len); + + if (client->swapped) + { + char n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.nCounters, n); + } + + 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) + { + char n; + swapl(&walklist->counter, n); + swapl(&walklist->resolution_hi, n); + swapl(&walklist->resolution_lo, n); + swaps(&walklist->name_length, n); + } + + pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter; + strncpy(pname_in_reply, psci->name, namelen); + walklist = (xSyncSystemCounter *) (((char *)walklist) + + pad_to_int32(sz_xSyncSystemCounter + namelen)); + } + + WriteToClient(client, sizeof(rep), (char *) &rep); + if (len) + { + WriteToClient(client, len, (char *) list); + free(list); + } + + return Success; +} + +/* + * ** Set client Priority + */ +static int +ProcSyncSetPriority(ClientPtr client) +{ + REQUEST(xSyncSetPriorityReq); + ClientPtr priorityclient; + int rc; + + REQUEST_SIZE_MATCH(xSyncSetPriorityReq); + + if (stuff->id == None) + priorityclient = client; + else { + rc = dixLookupClient(&priorityclient, stuff->id, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + + 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(ClientPtr client) +{ + REQUEST(xSyncGetPriorityReq); + xSyncGetPriorityReply rep; + ClientPtr priorityclient; + int rc; + + REQUEST_SIZE_MATCH(xSyncGetPriorityReq); + + if (stuff->id == None) + priorityclient = client; + else { + rc = dixLookupClient(&priorityclient, stuff->id, client, + DixGetAttrAccess); + if (rc != Success) + return rc; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.priority = priorityclient->priority; + + if (client->swapped) + { + char n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.priority, n); + } + + WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep); + + return Success; +} + +/* + * ** Create a new counter + */ +static int +ProcSyncCreateCounter(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 Success; +} + +/* + * ** Set Counter value + */ +static int +ProcSyncSetCounter(ClientPtr client) +{ + REQUEST(xSyncSetCounterReq); + SyncCounter *pCounter; + CARD64 newvalue; + int rc; + + REQUEST_SIZE_MATCH(xSyncSetCounterReq); + + rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter, + client, DixWriteAccess); + if (rc != Success) + return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; + + 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(ClientPtr client) +{ + REQUEST(xSyncChangeCounterReq); + SyncCounter *pCounter; + CARD64 newvalue; + Bool overflow; + int rc; + + REQUEST_SIZE_MATCH(xSyncChangeCounterReq); + + rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter, + client, DixWriteAccess); + if (rc != Success) + return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; + + 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(ClientPtr client) +{ + REQUEST(xSyncDestroyCounterReq); + SyncCounter *pCounter; + int rc; + + REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); + + rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, RTCounter, + client, DixDestroyAccess); + if (rc != Success) + return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; + + if (IsSystemCounter(pCounter)) + { + client->errorValue = stuff->counter; + return BadAccess; + } + FreeResource(pCounter->id, RT_NONE); + return Success; +} + + +/* + * ** Await + */ +static int +ProcSyncAwait(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(ClientPtr client) +{ + REQUEST(xSyncQueryCounterReq); + xSyncQueryCounterReply rep; + SyncCounter *pCounter; + int rc; + + REQUEST_SIZE_MATCH(xSyncQueryCounterReq); + + rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, + RTCounter, client, DixReadAccess); + if (rc != Success) + return (rc == BadValue) ? SyncErrorBase + XSyncBadCounter : rc; + + 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) + { + char n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.value_hi, n); + swapl(&rep.value_lo, n); + } + WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep); + return Success; +} + + +/* + * ** Create Alarm + */ +static int +ProcSyncCreateAlarm(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 - bytes_to_int32(sizeof(xSyncCreateAlarmReq)); + /* 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(ClientPtr client) +{ + REQUEST(xSyncChangeAlarmReq); + SyncAlarm *pAlarm; + long vmask; + int len, status; + + REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); + + status = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm, + client, DixWriteAccess); + if (status != Success) + return (status == BadValue) ? SyncErrorBase + XSyncBadAlarm : status; + + vmask = stuff->valueMask; + len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq)); + /* 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(ClientPtr client) +{ + REQUEST(xSyncQueryAlarmReq); + SyncAlarm *pAlarm; + xSyncQueryAlarmReply rep; + SyncTrigger *pTrigger; + int rc; + + REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); + + rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm, + client, DixReadAccess); + if (rc != Success) + return (rc == BadValue) ? SyncErrorBase + XSyncBadAlarm : rc; + + rep.type = X_Reply; + rep.length = bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)); + 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) + { + char n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.counter, n); + swapl(&rep.wait_value_hi, n); + swapl(&rep.wait_value_lo, n); + swapl(&rep.test_type, n); + swapl(&rep.delta_hi, n); + swapl(&rep.delta_lo, n); + } + + WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep); + return Success; +} + +static int +ProcSyncDestroyAlarm(ClientPtr client) +{ + SyncAlarm *pAlarm; + int rc; + REQUEST(xSyncDestroyAlarmReq); + + REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); + + rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm, + client, DixDestroyAccess); + if (rc != Success) + return (rc == BadValue) ? SyncErrorBase + XSyncBadAlarm : rc; + + FreeResource(stuff->alarm, RT_NONE); + return Success; +} + +/* + * ** Given an extension request, call the appropriate request procedure + */ +static int +ProcSyncDispatch(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(ClientPtr client) +{ + REQUEST(xSyncInitializeReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncInitializeReq); + + return ProcSyncInitialize(client); +} + +static int +SProcSyncListSystemCounters(ClientPtr client) +{ + REQUEST(xSyncListSystemCountersReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncListSystemCountersReq); + + return ProcSyncListSystemCounters(client); +} + +static int +SProcSyncCreateCounter(ClientPtr client) +{ + REQUEST(xSyncCreateCounterReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncCreateCounterReq); + swapl(&stuff->cid, n); + swapl(&stuff->initial_value_lo, n); + swapl(&stuff->initial_value_hi, n); + + return ProcSyncCreateCounter(client); +} + +static int +SProcSyncSetCounter(ClientPtr client) +{ + REQUEST(xSyncSetCounterReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncSetCounterReq); + swapl(&stuff->cid, n); + swapl(&stuff->value_lo, n); + swapl(&stuff->value_hi, n); + + return ProcSyncSetCounter(client); +} + +static int +SProcSyncChangeCounter(ClientPtr client) +{ + REQUEST(xSyncChangeCounterReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncChangeCounterReq); + swapl(&stuff->cid, n); + swapl(&stuff->value_lo, n); + swapl(&stuff->value_hi, n); + + return ProcSyncChangeCounter(client); +} + +static int +SProcSyncQueryCounter(ClientPtr client) +{ + REQUEST(xSyncQueryCounterReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncQueryCounterReq); + swapl(&stuff->counter, n); + + return ProcSyncQueryCounter(client); +} + +static int +SProcSyncDestroyCounter(ClientPtr client) +{ + REQUEST(xSyncDestroyCounterReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncDestroyCounterReq); + swapl(&stuff->counter, n); + + return ProcSyncDestroyCounter(client); +} + +static int +SProcSyncAwait(ClientPtr client) +{ + REQUEST(xSyncAwaitReq); + char n; + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); + SwapRestL(stuff); + + return ProcSyncAwait(client); +} + +static int +SProcSyncCreateAlarm(ClientPtr client) +{ + REQUEST(xSyncCreateAlarmReq); + char n; + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); + swapl(&stuff->id, n); + swapl(&stuff->valueMask, n); + SwapRestL(stuff); + + return ProcSyncCreateAlarm(client); +} + +static int +SProcSyncChangeAlarm(ClientPtr client) +{ + REQUEST(xSyncChangeAlarmReq); + char n; + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); + swapl(&stuff->alarm, n); + swapl(&stuff->valueMask, n); + SwapRestL(stuff); + return ProcSyncChangeAlarm(client); +} + +static int +SProcSyncQueryAlarm(ClientPtr client) +{ + REQUEST(xSyncQueryAlarmReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncQueryAlarmReq); + swapl(&stuff->alarm, n); + + return ProcSyncQueryAlarm(client); +} + +static int +SProcSyncDestroyAlarm(ClientPtr client) +{ + REQUEST(xSyncDestroyAlarmReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq); + swapl(&stuff->alarm, n); + + return ProcSyncDestroyAlarm(client); +} + +static int +SProcSyncSetPriority(ClientPtr client) +{ + REQUEST(xSyncSetPriorityReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncSetPriorityReq); + swapl(&stuff->id, n); + swapl(&stuff->priority, n); + + return ProcSyncSetPriority(client); +} + +static int +SProcSyncGetPriority(ClientPtr client) +{ + REQUEST(xSyncGetPriorityReq); + char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xSyncGetPriorityReq); + swapl(&stuff->id, n); + + return ProcSyncGetPriority(client); +} + + +static int +SProcSyncDispatch(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(xSyncCounterNotifyEvent *from, xSyncCounterNotifyEvent *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(xSyncAlarmNotifyEvent *from, xSyncAlarmNotifyEvent *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(ExtensionEntry *extEntry) +{ + free(SysCounterList); + SysCounterList = NULL; + RTCounter = 0; +} + + +/* + * ** Initialise the extension. + */ +void +SyncExtensionInit(void) +{ + ExtensionEntry *extEntry; + + if (RTCounter == 0) + { + RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter"); + } + RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm"); + RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait"); + if (RTAwait) + RTAwait |= RC_NEVERRETAIN; + RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient"); + if (RTAlarmClient) + RTAlarmClient |= 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(); + SyncInitIdleTime(); + +#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 (now deprecated) + */ +/*ARGSUSED*/ +static void +ServertimeBlockHandler(void *env, struct timeval **wt, void *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(void *env, int rc, void *LastSelectMask) +{ + if (pnext_time) + { + GetTime(); + + if (XSyncValueGreaterOrEqual(Now, *pnext_time)) + { + SyncChangeCounter(ServertimeCounter, Now); + } + } +} + +static void +ServertimeQueryValue(void *pCounter, CARD64 *pValue_return) +{ + GetTime(); + *pValue_return = Now; +} + +static void +ServertimeBracketValues(void *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(void) +{ + CARD64 resolution; + + XSyncIntsToValue(&Now, GetTimeInMillis(), 0); + XSyncIntToValue(&resolution, 4); + ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution, + XSyncCounterNeverDecreases, + ServertimeQueryValue, ServertimeBracketValues); + pnext_time = NULL; +} + + + +/* + * IDLETIME implementation + */ + +static SyncCounter *IdleTimeCounter; +static XSyncValue *pIdleTimeValueLess; +static XSyncValue *pIdleTimeValueGreater; + +static void +IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return) +{ + CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds; + XSyncIntsToValue (pValue_return, idle, 0); +} + +static void +IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask) +{ + XSyncValue idle, old_idle; + SyncTriggerList *list = IdleTimeCounter->pTriglist; + SyncTrigger *trig; + + if (!pIdleTimeValueLess && !pIdleTimeValueGreater) + return; + + old_idle = IdleTimeCounter->value; + IdleTimeQueryValue (NULL, &idle); + IdleTimeCounter->value = idle; /* push, so CheckTrigger works */ + + if (pIdleTimeValueLess && + XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)) + { + /* + * We've been idle for less than the threshold value, and someone + * wants to know about that, but now we need to know whether they + * want level or edge trigger. Check the trigger list against the + * current idle time, and if any succeed, bomb out of select() + * immediately so we can reschedule. + */ + + for (list = IdleTimeCounter->pTriglist; list; list = list->next) { + trig = list->pTrigger; + if (trig->CheckTrigger(trig, old_idle)) { + AdjustWaitForDelay(wt, 0); + break; + } + } + } + else if (pIdleTimeValueGreater) + { + /* + * There's a threshold in the positive direction. If we've been + * idle less than it, schedule a wakeup for sometime in the future. + * If we've been idle more than it, and someone wants to know about + * that level-triggered, schedule an immediate wakeup. + */ + unsigned long timeout = -1; + + if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) { + XSyncValue value; + Bool overflow; + + XSyncValueSubtract (&value, *pIdleTimeValueGreater, + idle, &overflow); + timeout = min(timeout, XSyncValueLow32 (value)); + } else { + for (list = IdleTimeCounter->pTriglist; list; list = list->next) { + trig = list->pTrigger; + if (trig->CheckTrigger(trig, old_idle)) { + timeout = min(timeout, 0); + break; + } + } + } + + AdjustWaitForDelay (wt, timeout); + } + + IdleTimeCounter->value = old_idle; /* pop */ +} + +static void +IdleTimeWakeupHandler (pointer env, int rc, pointer LastSelectMask) +{ + XSyncValue idle; + + if (!pIdleTimeValueLess && !pIdleTimeValueGreater) + return; + + IdleTimeQueryValue (NULL, &idle); + + if ((pIdleTimeValueGreater && + XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) || + (pIdleTimeValueLess && + XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))) + { + SyncChangeCounter (IdleTimeCounter, idle); + } +} + +static void +IdleTimeBracketValues (pointer pCounter, CARD64 *pbracket_less, + CARD64 *pbracket_greater) +{ + Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater); + + if (registered && !pbracket_less && !pbracket_greater) + { + RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler, + IdleTimeWakeupHandler, + NULL); + } + else if (!registered && (pbracket_less || pbracket_greater)) + { + RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler, + IdleTimeWakeupHandler, + NULL); + } + + pIdleTimeValueGreater = pbracket_greater; + pIdleTimeValueLess = pbracket_less; +} + +static void +SyncInitIdleTime (void) +{ + CARD64 resolution; + XSyncValue idle; + + IdleTimeQueryValue (NULL, &idle); + XSyncIntToValue (&resolution, 4); + + IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution, + XSyncCounterUnrestricted, + IdleTimeQueryValue, + IdleTimeBracketValues); + + pIdleTimeValueLess = pIdleTimeValueGreater = NULL; +} diff --git a/xorg-server/Xext/xace.c b/xorg-server/Xext/xace.c index bf0e98fb0..648de53fe 100644 --- a/xorg-server/Xext/xace.c +++ b/xorg-server/Xext/xace.c @@ -1,350 +1,350 @@ -/************************************************************ - -Author: Eamon Walsh - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -this permission notice appear in supporting documentation. 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 -AUTHOR 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. - -********************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include "scrnintstr.h" -#include "extnsionst.h" -#include "pixmapstr.h" -#include "regionstr.h" -#include "gcstruct.h" -#include "xacestr.h" - -#define XSERV_t -#define TRANS_SERVER -#include -#include "../os/osdep.h" - -_X_EXPORT CallbackListPtr XaceHooks[XACE_NUM_HOOKS] = {0}; - -/* Special-cased hook functions. Called by Xserver. - */ -int XaceHookDispatch(ClientPtr client, int major) -{ - /* Call the audit begin callback, there is no return value. */ - XaceAuditRec rec = { client, 0 }; - CallCallbacks(&XaceHooks[XACE_AUDIT_BEGIN], &rec); - - if (major < 128) { - /* Call the core dispatch hook */ - XaceCoreDispatchRec rec = { client, Success /* default allow */ }; - CallCallbacks(&XaceHooks[XACE_CORE_DISPATCH], &rec); - return rec.status; - } else { - /* Call the extension dispatch hook */ - ExtensionEntry *ext = GetExtensionEntry(major); - XaceExtAccessRec rec = { client, ext, DixUseAccess, Success }; - if (ext) - CallCallbacks(&XaceHooks[XACE_EXT_DISPATCH], &rec); - /* On error, pretend extension doesn't exist */ - return (rec.status == Success) ? Success : BadRequest; - } -} - -int XaceHookPropertyAccess(ClientPtr client, WindowPtr pWin, - PropertyPtr *ppProp, Mask access_mode) -{ - XacePropertyAccessRec rec = { client, pWin, ppProp, access_mode, Success }; - CallCallbacks(&XaceHooks[XACE_PROPERTY_ACCESS], &rec); - return rec.status; -} - -int XaceHookSelectionAccess(ClientPtr client, - Selection **ppSel, Mask access_mode) -{ - XaceSelectionAccessRec rec = { client, ppSel, access_mode, Success }; - CallCallbacks(&XaceHooks[XACE_SELECTION_ACCESS], &rec); - return rec.status; -} - -void XaceHookAuditEnd(ClientPtr ptr, int result) -{ - XaceAuditRec rec = { ptr, result }; - /* call callbacks, there is no return value. */ - CallCallbacks(&XaceHooks[XACE_AUDIT_END], &rec); -} - -/* Entry point for hook functions. Called by Xserver. - */ -int XaceHook(int hook, ...) -{ - pointer calldata; /* data passed to callback */ - int *prv = NULL; /* points to return value from callback */ - va_list ap; /* argument list */ - va_start(ap, hook); - - /* Marshal arguments for passing to callback. - * Each callback has its own case, which sets up a structure to hold - * the arguments and integer return parameter, or in some cases just - * sets calldata directly to a single argument (with no return result) - */ - switch (hook) - { - case XACE_RESOURCE_ACCESS: { - XaceResourceAccessRec rec; - rec.client = va_arg(ap, ClientPtr); - rec.id = va_arg(ap, XID); - rec.rtype = va_arg(ap, RESTYPE); - rec.res = va_arg(ap, pointer); - rec.ptype = va_arg(ap, RESTYPE); - rec.parent = va_arg(ap, pointer); - rec.access_mode = va_arg(ap, Mask); - rec.status = Success; /* default allow */ - calldata = &rec; - prv = &rec.status; - break; - } - case XACE_DEVICE_ACCESS: { - XaceDeviceAccessRec rec; - rec.client = va_arg(ap, ClientPtr); - rec.dev = va_arg(ap, DeviceIntPtr); - rec.access_mode = va_arg(ap, Mask); - rec.status = Success; /* default allow */ - calldata = &rec; - prv = &rec.status; - break; - } - case XACE_SEND_ACCESS: { - XaceSendAccessRec rec; - rec.client = va_arg(ap, ClientPtr); - rec.dev = va_arg(ap, DeviceIntPtr); - rec.pWin = va_arg(ap, WindowPtr); - rec.events = va_arg(ap, xEventPtr); - rec.count = va_arg(ap, int); - rec.status = Success; /* default allow */ - calldata = &rec; - prv = &rec.status; - break; - } - case XACE_RECEIVE_ACCESS: { - XaceReceiveAccessRec rec; - rec.client = va_arg(ap, ClientPtr); - rec.pWin = va_arg(ap, WindowPtr); - rec.events = va_arg(ap, xEventPtr); - rec.count = va_arg(ap, int); - rec.status = Success; /* default allow */ - calldata = &rec; - prv = &rec.status; - break; - } - case XACE_CLIENT_ACCESS: { - XaceClientAccessRec rec; - rec.client = va_arg(ap, ClientPtr); - rec.target = va_arg(ap, ClientPtr); - rec.access_mode = va_arg(ap, Mask); - rec.status = Success; /* default allow */ - calldata = &rec; - prv = &rec.status; - break; - } - case XACE_EXT_ACCESS: { - XaceExtAccessRec rec; - rec.client = va_arg(ap, ClientPtr); - rec.ext = va_arg(ap, ExtensionEntry*); - rec.access_mode = DixGetAttrAccess; - rec.status = Success; /* default allow */ - calldata = &rec; - prv = &rec.status; - break; - } - case XACE_SERVER_ACCESS: { - XaceServerAccessRec rec; - rec.client = va_arg(ap, ClientPtr); - rec.access_mode = va_arg(ap, Mask); - rec.status = Success; /* default allow */ - calldata = &rec; - prv = &rec.status; - break; - } - case XACE_SCREEN_ACCESS: - case XACE_SCREENSAVER_ACCESS: { - XaceScreenAccessRec rec; - rec.client = va_arg(ap, ClientPtr); - rec.screen = va_arg(ap, ScreenPtr); - rec.access_mode = va_arg(ap, Mask); - rec.status = Success; /* default allow */ - calldata = &rec; - prv = &rec.status; - break; - } - case XACE_AUTH_AVAIL: { - XaceAuthAvailRec rec; - rec.client = va_arg(ap, ClientPtr); - rec.authId = va_arg(ap, XID); - calldata = &rec; - break; - } - case XACE_KEY_AVAIL: { - XaceKeyAvailRec rec; - rec.event = va_arg(ap, xEventPtr); - rec.keybd = va_arg(ap, DeviceIntPtr); - rec.count = va_arg(ap, int); - calldata = &rec; - break; - } - default: { - va_end(ap); - return 0; /* unimplemented hook number */ - } - } - va_end(ap); - - /* call callbacks and return result, if any. */ - CallCallbacks(&XaceHooks[hook], calldata); - return prv ? *prv : Success; -} - -/* XaceCensorImage - * - * Called after pScreen->GetImage to prevent pieces or trusted windows from - * being returned in image data from an untrusted window. - * - * Arguments: - * client is the client doing the GetImage. - * pVisibleRegion is the visible region of the window. - * widthBytesLine is the width in bytes of one horizontal line in pBuf. - * pDraw is the source window. - * x, y, w, h is the rectangle of image data from pDraw in pBuf. - * format is the format of the image data in pBuf: ZPixmap or XYPixmap. - * pBuf is the image data. - * - * Returns: nothing. - * - * Side Effects: - * Any part of the rectangle (x, y, w, h) that is outside the visible - * region of the window will be destroyed (overwritten) in pBuf. - */ -void -XaceCensorImage( - ClientPtr client, - RegionPtr pVisibleRegion, - long widthBytesLine, - DrawablePtr pDraw, - int x, int y, int w, int h, - unsigned int format, - char *pBuf) -{ - ScreenPtr pScreen; - RegionRec imageRegion; /* region representing x,y,w,h */ - RegionRec censorRegion; /* region to obliterate */ - BoxRec imageBox; - int nRects; - - pScreen = pDraw->pScreen; - - imageBox.x1 = x; - imageBox.y1 = y; - imageBox.x2 = x + w; - imageBox.y2 = y + h; - REGION_INIT(pScreen, &imageRegion, &imageBox, 1); - REGION_NULL(pScreen, &censorRegion); - - /* censorRegion = imageRegion - visibleRegion */ - REGION_SUBTRACT(pScreen, &censorRegion, &imageRegion, pVisibleRegion); - nRects = REGION_NUM_RECTS(&censorRegion); - if (nRects > 0) - { /* we have something to censor */ - GCPtr pScratchGC = NULL; - PixmapPtr pPix = NULL; - xRectangle *pRects = NULL; - Bool failed = FALSE; - int depth = 1; - int bitsPerPixel = 1; - int i; - BoxPtr pBox; - - /* convert region to list-of-rectangles for PolyFillRect */ - - pRects = xalloc(nRects * sizeof(xRectangle)); - if (!pRects) - { - failed = TRUE; - goto failSafe; - } - for (pBox = REGION_RECTS(&censorRegion), i = 0; - i < nRects; - i++, pBox++) - { - pRects[i].x = pBox->x1; - pRects[i].y = pBox->y1 - imageBox.y1; - pRects[i].width = pBox->x2 - pBox->x1; - pRects[i].height = pBox->y2 - pBox->y1; - } - - /* use pBuf as a fake pixmap */ - - if (format == ZPixmap) - { - depth = pDraw->depth; - bitsPerPixel = pDraw->bitsPerPixel; - } - - pPix = GetScratchPixmapHeader(pDraw->pScreen, w, h, - depth, bitsPerPixel, - widthBytesLine, (pointer)pBuf); - if (!pPix) - { - failed = TRUE; - goto failSafe; - } - - pScratchGC = GetScratchGC(depth, pPix->drawable.pScreen); - if (!pScratchGC) - { - failed = TRUE; - goto failSafe; - } - - ValidateGC(&pPix->drawable, pScratchGC); - (* pScratchGC->ops->PolyFillRect)(&pPix->drawable, - pScratchGC, nRects, pRects); - - failSafe: - if (failed) - { - /* Censoring was not completed above. To be safe, wipe out - * all the image data so that nothing trusted gets out. - */ - bzero(pBuf, (int)(widthBytesLine * h)); - } - if (pRects) xfree(pRects); - if (pScratchGC) FreeScratchGC(pScratchGC); - if (pPix) FreeScratchPixmapHeader(pPix); - } - REGION_UNINIT(pScreen, &imageRegion); - REGION_UNINIT(pScreen, &censorRegion); -} /* XaceCensorImage */ - -/* - * Xtrans wrappers for use by modules - */ -int XaceGetConnectionNumber(ClientPtr client) -{ - XtransConnInfo ci = ((OsCommPtr)client->osPrivate)->trans_conn; - return _XSERVTransGetConnectionNumber(ci); -} - -int XaceIsLocal(ClientPtr client) -{ - XtransConnInfo ci = ((OsCommPtr)client->osPrivate)->trans_conn; - return _XSERVTransIsLocal(ci); -} +/************************************************************ + +Author: Eamon Walsh + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +this permission notice appear in supporting documentation. 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 +AUTHOR 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. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "scrnintstr.h" +#include "extnsionst.h" +#include "pixmapstr.h" +#include "regionstr.h" +#include "gcstruct.h" +#include "xacestr.h" + +#define XSERV_t +#define TRANS_SERVER +#include +#include "../os/osdep.h" + +_X_EXPORT CallbackListPtr XaceHooks[XACE_NUM_HOOKS] = {0}; + +/* Special-cased hook functions. Called by Xserver. + */ +int XaceHookDispatch(ClientPtr client, int major) +{ + /* Call the audit begin callback, there is no return value. */ + XaceAuditRec rec = { client, 0 }; + CallCallbacks(&XaceHooks[XACE_AUDIT_BEGIN], &rec); + + if (major < 128) { + /* Call the core dispatch hook */ + XaceCoreDispatchRec rec = { client, Success /* default allow */ }; + CallCallbacks(&XaceHooks[XACE_CORE_DISPATCH], &rec); + return rec.status; + } else { + /* Call the extension dispatch hook */ + ExtensionEntry *ext = GetExtensionEntry(major); + XaceExtAccessRec rec = { client, ext, DixUseAccess, Success }; + if (ext) + CallCallbacks(&XaceHooks[XACE_EXT_DISPATCH], &rec); + /* On error, pretend extension doesn't exist */ + return (rec.status == Success) ? Success : BadRequest; + } +} + +int XaceHookPropertyAccess(ClientPtr client, WindowPtr pWin, + PropertyPtr *ppProp, Mask access_mode) +{ + XacePropertyAccessRec rec = { client, pWin, ppProp, access_mode, Success }; + CallCallbacks(&XaceHooks[XACE_PROPERTY_ACCESS], &rec); + return rec.status; +} + +int XaceHookSelectionAccess(ClientPtr client, + Selection **ppSel, Mask access_mode) +{ + XaceSelectionAccessRec rec = { client, ppSel, access_mode, Success }; + CallCallbacks(&XaceHooks[XACE_SELECTION_ACCESS], &rec); + return rec.status; +} + +void XaceHookAuditEnd(ClientPtr ptr, int result) +{ + XaceAuditRec rec = { ptr, result }; + /* call callbacks, there is no return value. */ + CallCallbacks(&XaceHooks[XACE_AUDIT_END], &rec); +} + +/* Entry point for hook functions. Called by Xserver. + */ +int XaceHook(int hook, ...) +{ + pointer calldata; /* data passed to callback */ + int *prv = NULL; /* points to return value from callback */ + va_list ap; /* argument list */ + va_start(ap, hook); + + /* Marshal arguments for passing to callback. + * Each callback has its own case, which sets up a structure to hold + * the arguments and integer return parameter, or in some cases just + * sets calldata directly to a single argument (with no return result) + */ + switch (hook) + { + case XACE_RESOURCE_ACCESS: { + XaceResourceAccessRec rec; + rec.client = va_arg(ap, ClientPtr); + rec.id = va_arg(ap, XID); + rec.rtype = va_arg(ap, RESTYPE); + rec.res = va_arg(ap, pointer); + rec.ptype = va_arg(ap, RESTYPE); + rec.parent = va_arg(ap, pointer); + rec.access_mode = va_arg(ap, Mask); + rec.status = Success; /* default allow */ + calldata = &rec; + prv = &rec.status; + break; + } + case XACE_DEVICE_ACCESS: { + XaceDeviceAccessRec rec; + rec.client = va_arg(ap, ClientPtr); + rec.dev = va_arg(ap, DeviceIntPtr); + rec.access_mode = va_arg(ap, Mask); + rec.status = Success; /* default allow */ + calldata = &rec; + prv = &rec.status; + break; + } + case XACE_SEND_ACCESS: { + XaceSendAccessRec rec; + rec.client = va_arg(ap, ClientPtr); + rec.dev = va_arg(ap, DeviceIntPtr); + rec.pWin = va_arg(ap, WindowPtr); + rec.events = va_arg(ap, xEventPtr); + rec.count = va_arg(ap, int); + rec.status = Success; /* default allow */ + calldata = &rec; + prv = &rec.status; + break; + } + case XACE_RECEIVE_ACCESS: { + XaceReceiveAccessRec rec; + rec.client = va_arg(ap, ClientPtr); + rec.pWin = va_arg(ap, WindowPtr); + rec.events = va_arg(ap, xEventPtr); + rec.count = va_arg(ap, int); + rec.status = Success; /* default allow */ + calldata = &rec; + prv = &rec.status; + break; + } + case XACE_CLIENT_ACCESS: { + XaceClientAccessRec rec; + rec.client = va_arg(ap, ClientPtr); + rec.target = va_arg(ap, ClientPtr); + rec.access_mode = va_arg(ap, Mask); + rec.status = Success; /* default allow */ + calldata = &rec; + prv = &rec.status; + break; + } + case XACE_EXT_ACCESS: { + XaceExtAccessRec rec; + rec.client = va_arg(ap, ClientPtr); + rec.ext = va_arg(ap, ExtensionEntry*); + rec.access_mode = DixGetAttrAccess; + rec.status = Success; /* default allow */ + calldata = &rec; + prv = &rec.status; + break; + } + case XACE_SERVER_ACCESS: { + XaceServerAccessRec rec; + rec.client = va_arg(ap, ClientPtr); + rec.access_mode = va_arg(ap, Mask); + rec.status = Success; /* default allow */ + calldata = &rec; + prv = &rec.status; + break; + } + case XACE_SCREEN_ACCESS: + case XACE_SCREENSAVER_ACCESS: { + XaceScreenAccessRec rec; + rec.client = va_arg(ap, ClientPtr); + rec.screen = va_arg(ap, ScreenPtr); + rec.access_mode = va_arg(ap, Mask); + rec.status = Success; /* default allow */ + calldata = &rec; + prv = &rec.status; + break; + } + case XACE_AUTH_AVAIL: { + XaceAuthAvailRec rec; + rec.client = va_arg(ap, ClientPtr); + rec.authId = va_arg(ap, XID); + calldata = &rec; + break; + } + case XACE_KEY_AVAIL: { + XaceKeyAvailRec rec; + rec.event = va_arg(ap, xEventPtr); + rec.keybd = va_arg(ap, DeviceIntPtr); + rec.count = va_arg(ap, int); + calldata = &rec; + break; + } + default: { + va_end(ap); + return 0; /* unimplemented hook number */ + } + } + va_end(ap); + + /* call callbacks and return result, if any. */ + CallCallbacks(&XaceHooks[hook], calldata); + return prv ? *prv : Success; +} + +/* XaceCensorImage + * + * Called after pScreen->GetImage to prevent pieces or trusted windows from + * being returned in image data from an untrusted window. + * + * Arguments: + * client is the client doing the GetImage. + * pVisibleRegion is the visible region of the window. + * widthBytesLine is the width in bytes of one horizontal line in pBuf. + * pDraw is the source window. + * x, y, w, h is the rectangle of image data from pDraw in pBuf. + * format is the format of the image data in pBuf: ZPixmap or XYPixmap. + * pBuf is the image data. + * + * Returns: nothing. + * + * Side Effects: + * Any part of the rectangle (x, y, w, h) that is outside the visible + * region of the window will be destroyed (overwritten) in pBuf. + */ +void +XaceCensorImage( + ClientPtr client, + RegionPtr pVisibleRegion, + long widthBytesLine, + DrawablePtr pDraw, + int x, int y, int w, int h, + unsigned int format, + char *pBuf) +{ + ScreenPtr pScreen; + RegionRec imageRegion; /* region representing x,y,w,h */ + RegionRec censorRegion; /* region to obliterate */ + BoxRec imageBox; + int nRects; + + pScreen = pDraw->pScreen; + + imageBox.x1 = x; + imageBox.y1 = y; + imageBox.x2 = x + w; + imageBox.y2 = y + h; + REGION_INIT(pScreen, &imageRegion, &imageBox, 1); + REGION_NULL(pScreen, &censorRegion); + + /* censorRegion = imageRegion - visibleRegion */ + REGION_SUBTRACT(pScreen, &censorRegion, &imageRegion, pVisibleRegion); + nRects = REGION_NUM_RECTS(&censorRegion); + if (nRects > 0) + { /* we have something to censor */ + GCPtr pScratchGC = NULL; + PixmapPtr pPix = NULL; + xRectangle *pRects = NULL; + Bool failed = FALSE; + int depth = 1; + int bitsPerPixel = 1; + int i; + BoxPtr pBox; + + /* convert region to list-of-rectangles for PolyFillRect */ + + pRects = malloc(nRects * sizeof(xRectangle)); + if (!pRects) + { + failed = TRUE; + goto failSafe; + } + for (pBox = REGION_RECTS(&censorRegion), i = 0; + i < nRects; + i++, pBox++) + { + pRects[i].x = pBox->x1; + pRects[i].y = pBox->y1 - imageBox.y1; + pRects[i].width = pBox->x2 - pBox->x1; + pRects[i].height = pBox->y2 - pBox->y1; + } + + /* use pBuf as a fake pixmap */ + + if (format == ZPixmap) + { + depth = pDraw->depth; + bitsPerPixel = pDraw->bitsPerPixel; + } + + pPix = GetScratchPixmapHeader(pDraw->pScreen, w, h, + depth, bitsPerPixel, + widthBytesLine, (pointer)pBuf); + if (!pPix) + { + failed = TRUE; + goto failSafe; + } + + pScratchGC = GetScratchGC(depth, pPix->drawable.pScreen); + if (!pScratchGC) + { + failed = TRUE; + goto failSafe; + } + + ValidateGC(&pPix->drawable, pScratchGC); + (* pScratchGC->ops->PolyFillRect)(&pPix->drawable, + pScratchGC, nRects, pRects); + + failSafe: + if (failed) + { + /* Censoring was not completed above. To be safe, wipe out + * all the image data so that nothing trusted gets out. + */ + bzero(pBuf, (int)(widthBytesLine * h)); + } + if (pRects) free(pRects); + if (pScratchGC) FreeScratchGC(pScratchGC); + if (pPix) FreeScratchPixmapHeader(pPix); + } + REGION_UNINIT(pScreen, &imageRegion); + REGION_UNINIT(pScreen, &censorRegion); +} /* XaceCensorImage */ + +/* + * Xtrans wrappers for use by modules + */ +int XaceGetConnectionNumber(ClientPtr client) +{ + XtransConnInfo ci = ((OsCommPtr)client->osPrivate)->trans_conn; + return _XSERVTransGetConnectionNumber(ci); +} + +int XaceIsLocal(ClientPtr client) +{ + XtransConnInfo ci = ((OsCommPtr)client->osPrivate)->trans_conn; + return _XSERVTransIsLocal(ci); +} diff --git a/xorg-server/Xext/xcalibrate.c b/xorg-server/Xext/xcalibrate.c index 6e6461a5f..029154fa0 100644 --- a/xorg-server/Xext/xcalibrate.c +++ b/xorg-server/Xext/xcalibrate.c @@ -1,299 +1,299 @@ -/* - * Copyright © 2003 Philip Blundell - * - * 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 Philip Blundell not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Philip Blundell makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * PHILIP BLUNDELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL PHILIP BLUNDELL 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_KDRIVE_CONFIG_H -#include -#endif - - -#include -#include -#include "misc.h" -#include "os.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "swaprep.h" -#include "protocol-versions.h" - -#include -#include - -extern void (*tslib_raw_event_hook)(int x, int y, int pressure, void *closure); -extern void *tslib_raw_event_closure; - -static CARD8 XCalibrateReqCode; -int XCalibrateEventBase; -int XCalibrateReqBase; -int XCalibrateErrorBase; - -static ClientPtr xcalibrate_client; - -static void -xcalibrate_event_hook (int x, int y, int pressure, void *closure) -{ - ClientPtr pClient = (ClientPtr) closure; - xXCalibrateRawTouchscreenEvent ev; - - ev.type = XCalibrateEventBase + X_XCalibrateRawTouchscreen; - ev.sequenceNumber = pClient->sequence; - ev.x = x; - ev.y = y; - ev.pressure = pressure; - - if (!pClient->clientGone) - WriteEventsToClient (pClient, 1, (xEvent *) &ev); -} - -static int -ProcXCalibrateQueryVersion (ClientPtr client) -{ - REQUEST(xXCalibrateQueryVersionReq); - xXCalibrateQueryVersionReply rep; - CARD16 client_major, client_minor; /* not used */ - - REQUEST_SIZE_MATCH (xXCalibrateQueryVersionReq); - - client_major = stuff->majorVersion; - client_minor = stuff->minorVersion; - - fprintf(stderr, "%s(): called\n", __func__); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_XCALIBRATE_MAJOR_VERSION; - rep.minorVersion = SERVER_XCALIBRATE_MINOR_VERSION; - if (client->swapped) { - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof (xXCalibrateQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -static int -SProcXCalibrateQueryVersion (ClientPtr client) -{ - REQUEST(xXCalibrateQueryVersionReq); - int n; - - REQUEST_SIZE_MATCH (xXCalibrateQueryVersionReq); - swaps(&stuff->majorVersion,n); - swaps(&stuff->minorVersion,n); - return ProcXCalibrateQueryVersion(client); -} - -static int -ProcXCalibrateSetRawMode (ClientPtr client) -{ - REQUEST(xXCalibrateRawModeReq); - xXCalibrateRawModeReply rep; - - REQUEST_SIZE_MATCH (xXCalibrateRawModeReq); - - memset (&rep, 0, sizeof (rep)); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - - if (stuff->on) - { - if (xcalibrate_client == NULL) - { - /* Start calibrating. */ - xcalibrate_client = client; - tslib_raw_event_hook = xcalibrate_event_hook; - tslib_raw_event_closure = client; - rep.status = GrabSuccess; - } - else - { - rep.status = AlreadyGrabbed; - } - } - else - { - if (xcalibrate_client == client) - { - /* Stop calibrating. */ - xcalibrate_client = NULL; - tslib_raw_event_hook = NULL; - tslib_raw_event_closure = NULL; - rep.status = GrabSuccess; - - /* Cycle input off and on to reload configuration. */ - KdDisableInput (); - KdEnableInput (); - } - else - { - rep.status = AlreadyGrabbed; - } - } - - if (client->swapped) - { - int n; - - swaps (&rep.sequenceNumber, n); - swaps (&rep.status, n); - } - WriteToClient(client, sizeof (rep), (char *) &rep); - return (client->noClientException); -} - -static int -SProcXCalibrateSetRawMode (ClientPtr client) -{ - REQUEST(xXCalibrateRawModeReq); - int n; - - REQUEST_SIZE_MATCH (xXCalibrateRawModeReq); - - swaps(&stuff->on, n); - - return ProcXCalibrateSetRawMode(client); -} - -static int -ProcXCalibrateScreenToCoord (ClientPtr client) -{ - REQUEST(xXCalibrateScreenToCoordReq); - xXCalibrateScreenToCoordReply rep; - - REQUEST_SIZE_MATCH (xXCalibrateScreenToCoordReq); - - memset (&rep, 0, sizeof (rep)); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.x = stuff->x; - rep.y = stuff->y; - - KdScreenToPointerCoords(&rep.x, &rep.y); - - if (client->swapped) - { - int n; - - swaps (&rep.x, n); - swaps (&rep.y, n); - } - WriteToClient(client, sizeof (rep), (char *) &rep); - return (client->noClientException); -} - -static int -SProcXCalibrateScreenToCoord (ClientPtr client) -{ - REQUEST(xXCalibrateScreenToCoordReq); - int n; - - REQUEST_SIZE_MATCH (xXCalibrateScreenToCoordReq); - - swaps(&stuff->x, n); - swaps(&stuff->y, n); - - return ProcXCalibrateScreenToCoord(client); -} - -static int -ProcXCalibrateDispatch (ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_XCalibrateQueryVersion: - return ProcXCalibrateQueryVersion(client); - case X_XCalibrateRawMode: - return ProcXCalibrateSetRawMode(client); - case X_XCalibrateScreenToCoord: - return ProcXCalibrateScreenToCoord(client); - - default: break; - } - - return BadRequest; -} - -static int -SProcXCalibrateDispatch (ClientPtr client) -{ - REQUEST(xReq); - int n; - - swaps(&stuff->length,n); - - switch (stuff->data) { - case X_XCalibrateQueryVersion: - return SProcXCalibrateQueryVersion(client); - case X_XCalibrateRawMode: - return SProcXCalibrateSetRawMode(client); - case X_XCalibrateScreenToCoord: - return SProcXCalibrateScreenToCoord(client); - - default: break; - } - - return BadRequest; -} - -static void -XCalibrateClientCallback (CallbackListPtr *list, - pointer closure, - pointer data) -{ - NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; - ClientPtr pClient = clientinfo->client; - - if (clientinfo->setup == NULL - && xcalibrate_client != NULL - && xcalibrate_client == pClient) - { - /* Stop calibrating. */ - xcalibrate_client = NULL; - tslib_raw_event_hook = NULL; - tslib_raw_event_closure = NULL; - } -} - -void -XCalibrateExtensionInit(void) -{ - ExtensionEntry *extEntry; - - if (!AddCallback (&ClientStateCallback, XCalibrateClientCallback, 0)) - return; - - extEntry = AddExtension(XCALIBRATE_NAME, XCalibrateNumberEvents, XCalibrateNumberErrors, - ProcXCalibrateDispatch, SProcXCalibrateDispatch, - NULL, StandardMinorOpcode); - - if (!extEntry) - return; - - XCalibrateReqCode = (unsigned char)extEntry->base; - XCalibrateEventBase = extEntry->eventBase; - XCalibrateErrorBase = extEntry->errorBase; - - xcalibrate_client = 0; -} +/* + * Copyright © 2003 Philip Blundell + * + * 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 Philip Blundell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Philip Blundell makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * PHILIP BLUNDELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL PHILIP BLUNDELL 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_KDRIVE_CONFIG_H +#include +#endif + + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "swaprep.h" +#include "protocol-versions.h" + +#include +#include + +extern void (*tslib_raw_event_hook)(int x, int y, int pressure, void *closure); +extern void *tslib_raw_event_closure; + +static CARD8 XCalibrateReqCode; +int XCalibrateEventBase; +int XCalibrateReqBase; +int XCalibrateErrorBase; + +static ClientPtr xcalibrate_client; + +static void +xcalibrate_event_hook (int x, int y, int pressure, void *closure) +{ + ClientPtr pClient = (ClientPtr) closure; + xXCalibrateRawTouchscreenEvent ev; + + ev.type = XCalibrateEventBase + X_XCalibrateRawTouchscreen; + ev.sequenceNumber = pClient->sequence; + ev.x = x; + ev.y = y; + ev.pressure = pressure; + + if (!pClient->clientGone) + WriteEventsToClient (pClient, 1, (xEvent *) &ev); +} + +static int +ProcXCalibrateQueryVersion (ClientPtr client) +{ + REQUEST(xXCalibrateQueryVersionReq); + xXCalibrateQueryVersionReply rep; + CARD16 client_major, client_minor; /* not used */ + + REQUEST_SIZE_MATCH (xXCalibrateQueryVersionReq); + + client_major = stuff->majorVersion; + client_minor = stuff->minorVersion; + + fprintf(stderr, "%s(): called\n", __func__); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_XCALIBRATE_MAJOR_VERSION; + rep.minorVersion = SERVER_XCALIBRATE_MINOR_VERSION; + if (client->swapped) { + int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof (xXCalibrateQueryVersionReply), (char *)&rep); + return Success; +} + +static int +SProcXCalibrateQueryVersion (ClientPtr client) +{ + REQUEST(xXCalibrateQueryVersionReq); + int n; + + REQUEST_SIZE_MATCH (xXCalibrateQueryVersionReq); + swaps(&stuff->majorVersion,n); + swaps(&stuff->minorVersion,n); + return ProcXCalibrateQueryVersion(client); +} + +static int +ProcXCalibrateSetRawMode (ClientPtr client) +{ + REQUEST(xXCalibrateRawModeReq); + xXCalibrateRawModeReply rep; + + REQUEST_SIZE_MATCH (xXCalibrateRawModeReq); + + memset (&rep, 0, sizeof (rep)); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + + if (stuff->on) + { + if (xcalibrate_client == NULL) + { + /* Start calibrating. */ + xcalibrate_client = client; + tslib_raw_event_hook = xcalibrate_event_hook; + tslib_raw_event_closure = client; + rep.status = GrabSuccess; + } + else + { + rep.status = AlreadyGrabbed; + } + } + else + { + if (xcalibrate_client == client) + { + /* Stop calibrating. */ + xcalibrate_client = NULL; + tslib_raw_event_hook = NULL; + tslib_raw_event_closure = NULL; + rep.status = GrabSuccess; + + /* Cycle input off and on to reload configuration. */ + KdDisableInput (); + KdEnableInput (); + } + else + { + rep.status = AlreadyGrabbed; + } + } + + if (client->swapped) + { + int n; + + swaps (&rep.sequenceNumber, n); + swaps (&rep.status, n); + } + WriteToClient(client, sizeof (rep), (char *) &rep); + return Success; +} + +static int +SProcXCalibrateSetRawMode (ClientPtr client) +{ + REQUEST(xXCalibrateRawModeReq); + int n; + + REQUEST_SIZE_MATCH (xXCalibrateRawModeReq); + + swaps(&stuff->on, n); + + return ProcXCalibrateSetRawMode(client); +} + +static int +ProcXCalibrateScreenToCoord (ClientPtr client) +{ + REQUEST(xXCalibrateScreenToCoordReq); + xXCalibrateScreenToCoordReply rep; + + REQUEST_SIZE_MATCH (xXCalibrateScreenToCoordReq); + + memset (&rep, 0, sizeof (rep)); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.x = stuff->x; + rep.y = stuff->y; + + KdScreenToPointerCoords(&rep.x, &rep.y); + + if (client->swapped) + { + int n; + + swaps (&rep.x, n); + swaps (&rep.y, n); + } + WriteToClient(client, sizeof (rep), (char *) &rep); + return Success; +} + +static int +SProcXCalibrateScreenToCoord (ClientPtr client) +{ + REQUEST(xXCalibrateScreenToCoordReq); + int n; + + REQUEST_SIZE_MATCH (xXCalibrateScreenToCoordReq); + + swaps(&stuff->x, n); + swaps(&stuff->y, n); + + return ProcXCalibrateScreenToCoord(client); +} + +static int +ProcXCalibrateDispatch (ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_XCalibrateQueryVersion: + return ProcXCalibrateQueryVersion(client); + case X_XCalibrateRawMode: + return ProcXCalibrateSetRawMode(client); + case X_XCalibrateScreenToCoord: + return ProcXCalibrateScreenToCoord(client); + + default: break; + } + + return BadRequest; +} + +static int +SProcXCalibrateDispatch (ClientPtr client) +{ + REQUEST(xReq); + int n; + + swaps(&stuff->length,n); + + switch (stuff->data) { + case X_XCalibrateQueryVersion: + return SProcXCalibrateQueryVersion(client); + case X_XCalibrateRawMode: + return SProcXCalibrateSetRawMode(client); + case X_XCalibrateScreenToCoord: + return SProcXCalibrateScreenToCoord(client); + + default: break; + } + + return BadRequest; +} + +static void +XCalibrateClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + + if (clientinfo->setup == NULL + && xcalibrate_client != NULL + && xcalibrate_client == pClient) + { + /* Stop calibrating. */ + xcalibrate_client = NULL; + tslib_raw_event_hook = NULL; + tslib_raw_event_closure = NULL; + } +} + +void +XCalibrateExtensionInit(void) +{ + ExtensionEntry *extEntry; + + if (!AddCallback (&ClientStateCallback, XCalibrateClientCallback, 0)) + return; + + extEntry = AddExtension(XCALIBRATE_NAME, XCalibrateNumberEvents, XCalibrateNumberErrors, + ProcXCalibrateDispatch, SProcXCalibrateDispatch, + NULL, StandardMinorOpcode); + + if (!extEntry) + return; + + XCalibrateReqCode = (unsigned char)extEntry->base; + XCalibrateEventBase = extEntry->eventBase; + XCalibrateErrorBase = extEntry->errorBase; + + xcalibrate_client = 0; +} diff --git a/xorg-server/Xext/xcmisc.c b/xorg-server/Xext/xcmisc.c index 39079a294..625351f51 100644 --- a/xorg-server/Xext/xcmisc.c +++ b/xorg-server/Xext/xcmisc.c @@ -1,217 +1,217 @@ -/* - -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 "modinit.h" - -#if HAVE_STDINT_H -#include -#elif !defined(UINT32_MAX) -#define UINT32_MAX 0xffffffffU -#endif - -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); - -void -XCMiscExtensionInit(INITARGS) -{ - AddExtension(XCMiscExtensionName, 0, 0, - ProcXCMiscDispatch, SProcXCMiscDispatch, - NULL, StandardMinorOpcode); -} - -static int -ProcXCMiscGetVersion(ClientPtr client) -{ - xXCMiscGetVersionReply rep; - int n; - - 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, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xXCMiscGetVersionReply), (char *)&rep); - return(client->noClientException); -} - -static int -ProcXCMiscGetXIDRange(ClientPtr client) -{ - xXCMiscGetXIDRangeReply rep; - int n; - 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, n); - swapl(&rep.start_id, n); - swapl(&rep.count, n); - } - WriteToClient(client, sizeof(xXCMiscGetXIDRangeReply), (char *)&rep); - return(client->noClientException); -} - -static int -ProcXCMiscGetXIDList(ClientPtr client) -{ - REQUEST(xXCMiscGetXIDListReq); - xXCMiscGetXIDListReply rep; - int n; - XID *pids; - unsigned int count; - - REQUEST_SIZE_MATCH(xXCMiscGetXIDListReq); - - if (stuff->count > UINT32_MAX / sizeof(XID)) - return BadAlloc; - - pids = (XID *)Xalloc(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, n); - swapl(&rep.length, n); - swapl(&rep.count, n); - } - WriteToClient(client, sizeof(xXCMiscGetXIDListReply), (char *)&rep); - if (count) - { - client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; - WriteSwappedDataToClient(client, count * sizeof(XID), pids); - } - Xfree(pids); - return(client->noClientException); -} - -static int -ProcXCMiscDispatch (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(ClientPtr client) -{ - int n; - REQUEST(xXCMiscGetVersionReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXCMiscGetVersionReq); - swaps(&stuff->majorVersion, n); - swaps(&stuff->minorVersion, n); - return ProcXCMiscGetVersion(client); -} - -static int -SProcXCMiscGetXIDRange(ClientPtr client) -{ - int n; - REQUEST(xReq); - - swaps(&stuff->length, n); - return ProcXCMiscGetXIDRange(client); -} - -static int -SProcXCMiscGetXIDList(ClientPtr client) -{ - int n; - REQUEST(xXCMiscGetXIDListReq); - - swaps(&stuff->length, n); - swapl(&stuff->count, n); - return ProcXCMiscGetXIDList(client); -} - -static int -SProcXCMiscDispatch (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; - } -} +/* + +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 "modinit.h" + +#if HAVE_STDINT_H +#include +#elif !defined(UINT32_MAX) +#define UINT32_MAX 0xffffffffU +#endif + +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); + +void +XCMiscExtensionInit(INITARGS) +{ + AddExtension(XCMiscExtensionName, 0, 0, + ProcXCMiscDispatch, SProcXCMiscDispatch, + NULL, StandardMinorOpcode); +} + +static int +ProcXCMiscGetVersion(ClientPtr client) +{ + xXCMiscGetVersionReply rep; + int n; + + 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, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xXCMiscGetVersionReply), (char *)&rep); + return Success; +} + +static int +ProcXCMiscGetXIDRange(ClientPtr client) +{ + xXCMiscGetXIDRangeReply rep; + int n; + 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, n); + swapl(&rep.start_id, n); + swapl(&rep.count, n); + } + WriteToClient(client, sizeof(xXCMiscGetXIDRangeReply), (char *)&rep); + return Success; +} + +static int +ProcXCMiscGetXIDList(ClientPtr client) +{ + REQUEST(xXCMiscGetXIDListReq); + xXCMiscGetXIDListReply rep; + int n; + XID *pids; + unsigned int count; + + REQUEST_SIZE_MATCH(xXCMiscGetXIDListReq); + + if (stuff->count > UINT32_MAX / sizeof(XID)) + return BadAlloc; + + pids = (XID *)malloc(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, n); + swapl(&rep.length, n); + swapl(&rep.count, n); + } + WriteToClient(client, sizeof(xXCMiscGetXIDListReply), (char *)&rep); + if (count) + { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, count * sizeof(XID), pids); + } + free(pids); + return Success; +} + +static int +ProcXCMiscDispatch (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(ClientPtr client) +{ + int n; + REQUEST(xXCMiscGetVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXCMiscGetVersionReq); + swaps(&stuff->majorVersion, n); + swaps(&stuff->minorVersion, n); + return ProcXCMiscGetVersion(client); +} + +static int +SProcXCMiscGetXIDRange(ClientPtr client) +{ + int n; + REQUEST(xReq); + + swaps(&stuff->length, n); + return ProcXCMiscGetXIDRange(client); +} + +static int +SProcXCMiscGetXIDList(ClientPtr client) +{ + int n; + REQUEST(xXCMiscGetXIDListReq); + + swaps(&stuff->length, n); + swapl(&stuff->count, n); + return ProcXCMiscGetXIDList(client); +} + +static int +SProcXCMiscDispatch (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/xorg-server/Xext/xf86bigfont.c b/xorg-server/Xext/xf86bigfont.c index 8e8d460e5..8d7071507 100644 --- a/xorg-server/Xext/xf86bigfont.c +++ b/xorg-server/Xext/xf86bigfont.c @@ -230,7 +230,7 @@ shmalloc( if (size < 3500) return (ShmDescPtr) NULL; - pDesc = xalloc(sizeof(ShmDescRec)); + pDesc = malloc(sizeof(ShmDescRec)); if (!pDesc) return (ShmDescPtr) NULL; @@ -239,7 +239,7 @@ shmalloc( if (shmid == -1) { ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n", size, strerror(errno)); - xfree(pDesc); + free(pDesc); return (ShmDescPtr) NULL; } @@ -247,7 +247,7 @@ shmalloc( ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n", size, strerror(errno)); shmctl(shmid, IPC_RMID, (void *) 0); - xfree(pDesc); + free(pDesc); return (ShmDescPtr) NULL; } @@ -276,7 +276,7 @@ shmdealloc( if (pDesc->next) pDesc->next->prev = pDesc->prev; *pDesc->prev = pDesc->next; - xfree(pDesc); + free(pDesc); } #endif @@ -368,7 +368,7 @@ ProcXF86BigfontQueryVersion( } WriteToClient(client, sizeof(xXF86BigfontQueryVersionReply), (char *)&reply); - return client->noClientException; + return Success; } static void @@ -464,7 +464,7 @@ ProcXF86BigfontQueryFont( shmid = pDesc->shmid; } else { #endif - pCI = xalloc(nCharInfos * sizeof(xCharInfo)); + pCI = malloc(nCharInfos * sizeof(xCharInfo)); if (!pCI) return BadAlloc; #ifdef HAS_SHM @@ -526,9 +526,9 @@ ProcXF86BigfontQueryFont( if (hashModulus > nCharInfos+1) hashModulus = nCharInfos+1; - tmp = xalloc((4*nCharInfos+1) * sizeof(CARD16)); + tmp = malloc((4*nCharInfos+1) * sizeof(CARD16)); if (!tmp) { - if (!pDesc) xfree(pCI); + if (!pDesc) free(pCI); return BadAlloc; } pIndex2UniqIndex = tmp; @@ -610,12 +610,12 @@ ProcXF86BigfontQueryFont( ? nUniqCharInfos * sizeof(xCharInfo) + (nCharInfos+1)/2 * 2 * sizeof(CARD16) : 0); - xXF86BigfontQueryFontReply* reply = xalloc(rlength); + xXF86BigfontQueryFontReply* reply = malloc(rlength); char* p; if (!reply) { if (nCharInfos > 0) { - if (shmid == -1) xfree(pIndex2UniqIndex); - if (!pDesc) xfree(pCI); + if (shmid == -1) free(pIndex2UniqIndex); + if (!pDesc) free(pCI); } return BadAlloc; } @@ -693,12 +693,12 @@ ProcXF86BigfontQueryFont( } } WriteToClient(client, rlength, (char *)reply); - xfree(reply); + free(reply); if (nCharInfos > 0) { - if (shmid == -1) xfree(pIndex2UniqIndex); - if (!pDesc) xfree(pCI); + if (shmid == -1) free(pIndex2UniqIndex); + if (!pDesc) free(pCI); } - return (client->noClientException); + return Success; } } diff --git a/xorg-server/Xext/xres.c b/xorg-server/Xext/xres.c index 109aa639a..4a5bffa81 100644 --- a/xorg-server/Xext/xres.c +++ b/xorg-server/Xext/xres.c @@ -1,383 +1,383 @@ -/* - 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 "registry.h" -#include -#include "pixmapstr.h" -#include "windowstr.h" -#include "gcstruct.h" -#include "modinit.h" -#include "protocol-versions.h" - -static int -ProcXResQueryVersion (ClientPtr client) -{ - REQUEST(xXResQueryVersionReq); - xXResQueryVersionReply rep; - CARD16 client_major, client_minor; /* not used */ - - REQUEST_SIZE_MATCH (xXResQueryVersionReq); - - client_major = stuff->client_major; - client_minor = stuff->client_minor; - (void) client_major; - (void) client_minor; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.server_major = SERVER_XRES_MAJOR_VERSION; - rep.server_minor = SERVER_XRES_MINOR_VERSION; - if (client->swapped) { - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.server_major, n); - swaps(&rep.server_minor, n); - } - 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 = xalloc(currentMaxClients * sizeof(int)); - - num_clients = 0; - for(i = 0; 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 = bytes_to_int32(rep.num_clients * sz_xXResClient); - if (client->swapped) { - int n; - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.num_clients, n); - } - 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) { - int n; - swapl (&scratch.resource_base, n); - swapl (&scratch.resource_mask, n); - } - WriteToClient (client, sz_xXResClient, (char *) &scratch); - } - } - - xfree(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); - - if((clientID >= currentMaxClients) || !clients[clientID]) { - client->errorValue = stuff->xid; - return BadValue; - } - - counts = xcalloc(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 = bytes_to_int32(rep.num_types * sz_xXResType); - if (client->swapped) { - int n; - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.num_types, n); - } - - WriteToClient (client,sizeof(xXResQueryClientResourcesReply),(char*)&rep); - - if(num_types) { - xXResType scratch; - char *name; - - for(i = 0; i < lastResourceType; i++) { - if(!counts[i]) continue; - - name = (char *)LookupResourceName(i + 1); - if (strcmp(name, XREGISTRY_UNKNOWN)) - scratch.resource_type = MakeAtom(name, strlen(name), TRUE); - else { - char buf[40]; - snprintf(buf, sizeof(buf), "Unregistered resource %i", i + 1); - scratch.resource_type = MakeAtom(buf, strlen(buf), TRUE); - } - - scratch.count = counts[i]; - - if(client->swapped) { - int n; - swapl (&scratch.resource_type, n); - swapl (&scratch.count, n); - } - WriteToClient (client, sz_xXResType, (char *) &scratch); - } - } - - xfree(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); - - if((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)); - -#ifdef COMPOSITE - /* FIXME: include composite pixmaps too */ -#endif - - 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) { - int n; - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.bytes, n); - swapl (&rep.bytes_overflow, n); - } - WriteToClient (client,sizeof(xXResQueryClientPixmapBytesReply),(char*)&rep); - - return (client->noClientException); -} - -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(xXResQueryVersionReq); - int n; - - REQUEST_SIZE_MATCH (xXResQueryVersionReq); - swaps(&stuff->client_major,n); - swaps(&stuff->client_minor,n); - return ProcXResQueryVersion(client); -} - -static int -SProcXResQueryClientResources (ClientPtr client) -{ - REQUEST(xXResQueryClientResourcesReq); - int n; - - REQUEST_SIZE_MATCH (xXResQueryClientResourcesReq); - swaps(&stuff->xid,n); - return ProcXResQueryClientResources(client); -} - -static int -SProcXResQueryClientPixmapBytes (ClientPtr client) -{ - REQUEST(xXResQueryClientPixmapBytesReq); - int n; - - REQUEST_SIZE_MATCH (xXResQueryClientPixmapBytesReq); - swaps(&stuff->xid,n); - return ProcXResQueryClientPixmapBytes(client); -} - -static int -SProcResDispatch (ClientPtr client) -{ - REQUEST(xReq); - int n; - - swaps(&stuff->length,n); - - 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, - NULL, StandardMinorOpcode); -} +/* + 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 "registry.h" +#include +#include "pixmapstr.h" +#include "windowstr.h" +#include "gcstruct.h" +#include "modinit.h" +#include "protocol-versions.h" + +static int +ProcXResQueryVersion (ClientPtr client) +{ + REQUEST(xXResQueryVersionReq); + xXResQueryVersionReply rep; + CARD16 client_major, client_minor; /* not used */ + + REQUEST_SIZE_MATCH (xXResQueryVersionReq); + + client_major = stuff->client_major; + client_minor = stuff->client_minor; + (void) client_major; + (void) client_minor; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.server_major = SERVER_XRES_MAJOR_VERSION; + rep.server_minor = SERVER_XRES_MINOR_VERSION; + if (client->swapped) { + int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.server_major, n); + swaps(&rep.server_minor, n); + } + WriteToClient(client, sizeof (xXResQueryVersionReply), (char *)&rep); + return Success; +} + +static int +ProcXResQueryClients (ClientPtr client) +{ + /* REQUEST(xXResQueryClientsReq); */ + xXResQueryClientsReply rep; + int *current_clients; + int i, num_clients; + + REQUEST_SIZE_MATCH(xXResQueryClientsReq); + + current_clients = malloc(currentMaxClients * sizeof(int)); + + num_clients = 0; + for(i = 0; 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 = bytes_to_int32(rep.num_clients * sz_xXResClient); + if (client->swapped) { + int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.num_clients, n); + } + 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) { + int n; + swapl (&scratch.resource_base, n); + swapl (&scratch.resource_mask, n); + } + WriteToClient (client, sz_xXResClient, (char *) &scratch); + } + } + + free(current_clients); + + return Success; +} + + +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); + + if((clientID >= currentMaxClients) || !clients[clientID]) { + client->errorValue = stuff->xid; + return BadValue; + } + + counts = calloc(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 = bytes_to_int32(rep.num_types * sz_xXResType); + if (client->swapped) { + int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.num_types, n); + } + + WriteToClient (client,sizeof(xXResQueryClientResourcesReply),(char*)&rep); + + if(num_types) { + xXResType scratch; + char *name; + + for(i = 0; i < lastResourceType; i++) { + if(!counts[i]) continue; + + name = (char *)LookupResourceName(i + 1); + if (strcmp(name, XREGISTRY_UNKNOWN)) + scratch.resource_type = MakeAtom(name, strlen(name), TRUE); + else { + char buf[40]; + snprintf(buf, sizeof(buf), "Unregistered resource %i", i + 1); + scratch.resource_type = MakeAtom(buf, strlen(buf), TRUE); + } + + scratch.count = counts[i]; + + if(client->swapped) { + int n; + swapl (&scratch.resource_type, n); + swapl (&scratch.count, n); + } + WriteToClient (client, sz_xXResType, (char *) &scratch); + } + } + + free(counts); + + return Success; +} + +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); + + if((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)); + +#ifdef COMPOSITE + /* FIXME: include composite pixmaps too */ +#endif + + 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) { + int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.bytes, n); + swapl (&rep.bytes_overflow, n); + } + WriteToClient (client,sizeof(xXResQueryClientPixmapBytesReply),(char*)&rep); + + return Success; +} + +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(xXResQueryVersionReq); + int n; + + REQUEST_SIZE_MATCH (xXResQueryVersionReq); + swaps(&stuff->client_major,n); + swaps(&stuff->client_minor,n); + return ProcXResQueryVersion(client); +} + +static int +SProcXResQueryClientResources (ClientPtr client) +{ + REQUEST(xXResQueryClientResourcesReq); + int n; + + REQUEST_SIZE_MATCH (xXResQueryClientResourcesReq); + swaps(&stuff->xid,n); + return ProcXResQueryClientResources(client); +} + +static int +SProcXResQueryClientPixmapBytes (ClientPtr client) +{ + REQUEST(xXResQueryClientPixmapBytesReq); + int n; + + REQUEST_SIZE_MATCH (xXResQueryClientPixmapBytesReq); + swaps(&stuff->xid,n); + return ProcXResQueryClientPixmapBytes(client); +} + +static int +SProcResDispatch (ClientPtr client) +{ + REQUEST(xReq); + int n; + + swaps(&stuff->length,n); + + 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, + NULL, StandardMinorOpcode); +} diff --git a/xorg-server/Xext/xselinux_ext.c b/xorg-server/Xext/xselinux_ext.c index aa5573455..0076cedb4 100644 --- a/xorg-server/Xext/xselinux_ext.c +++ b/xorg-server/Xext/xselinux_ext.c @@ -1,734 +1,734 @@ -/************************************************************ - -Author: Eamon Walsh - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -this permission notice appear in supporting documentation. 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 -AUTHOR 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. - -********************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "selection.h" -#include "inputstr.h" -#include "windowstr.h" -#include "propertyst.h" -#include "extnsionst.h" -#include "modinit.h" -#include "xselinuxint.h" - -#define CTX_DEV offsetof(SELinuxSubjectRec, dev_create_sid) -#define CTX_WIN offsetof(SELinuxSubjectRec, win_create_sid) -#define CTX_PRP offsetof(SELinuxSubjectRec, prp_create_sid) -#define CTX_SEL offsetof(SELinuxSubjectRec, sel_create_sid) -#define USE_PRP offsetof(SELinuxSubjectRec, prp_use_sid) -#define USE_SEL offsetof(SELinuxSubjectRec, sel_use_sid) - -typedef struct { - security_context_t octx; - security_context_t dctx; - CARD32 octx_len; - CARD32 dctx_len; - CARD32 id; -} SELinuxListItemRec; - - -/* - * Extension Dispatch - */ - -static security_context_t -SELinuxCopyContext(char *ptr, unsigned len) -{ - security_context_t copy = xalloc(len + 1); - if (!copy) - return NULL; - strncpy(copy, ptr, len); - copy[len] = '\0'; - return copy; -} - -static int -ProcSELinuxQueryVersion(ClientPtr client) -{ - SELinuxQueryVersionReply rep; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.server_major = SELINUX_MAJOR_VERSION; - rep.server_minor = SELINUX_MINOR_VERSION; - if (client->swapped) { - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.server_major, n); - swaps(&rep.server_minor, n); - } - WriteToClient(client, sizeof(rep), (char *)&rep); - return (client->noClientException); -} - -static int -SELinuxSendContextReply(ClientPtr client, security_id_t sid) -{ - SELinuxGetContextReply rep; - security_context_t ctx = NULL; - int len = 0; - - if (sid) { - if (avc_sid_to_context_raw(sid, &ctx) < 0) - return BadValue; - len = strlen(ctx) + 1; - } - - rep.type = X_Reply; - rep.length = bytes_to_int32(len); - rep.sequenceNumber = client->sequence; - rep.context_len = len; - - if (client->swapped) { - int n; - swapl(&rep.length, n); - swaps(&rep.sequenceNumber, n); - swapl(&rep.context_len, n); - } - - WriteToClient(client, sizeof(SELinuxGetContextReply), (char *)&rep); - WriteToClient(client, len, ctx); - freecon(ctx); - return client->noClientException; -} - -static int -ProcSELinuxSetCreateContext(ClientPtr client, unsigned offset) -{ - PrivateRec **privPtr = &client->devPrivates; - security_id_t *pSid; - security_context_t ctx = NULL; - char *ptr; - int rc; - - REQUEST(SELinuxSetCreateContextReq); - REQUEST_FIXED_SIZE(SELinuxSetCreateContextReq, stuff->context_len); - - if (stuff->context_len > 0) { - ctx = SELinuxCopyContext((char *)(stuff + 1), stuff->context_len); - if (!ctx) - return BadAlloc; - } - - ptr = dixLookupPrivate(privPtr, subjectKey); - pSid = (security_id_t *)(ptr + offset); - *pSid = NULL; - - rc = Success; - if (stuff->context_len > 0) { - if (security_check_context_raw(ctx) < 0 || - avc_context_to_sid_raw(ctx, pSid) < 0) - rc = BadValue; - } - - xfree(ctx); - return rc; -} - -static int -ProcSELinuxGetCreateContext(ClientPtr client, unsigned offset) -{ - security_id_t *pSid; - char *ptr; - - REQUEST_SIZE_MATCH(SELinuxGetCreateContextReq); - - if (offset == CTX_DEV) - ptr = dixLookupPrivate(&serverClient->devPrivates, subjectKey); - else - ptr = dixLookupPrivate(&client->devPrivates, subjectKey); - - pSid = (security_id_t *)(ptr + offset); - return SELinuxSendContextReply(client, *pSid); -} - -static int -ProcSELinuxSetDeviceContext(ClientPtr client) -{ - security_context_t ctx; - security_id_t sid; - DeviceIntPtr dev; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj; - int rc; - - REQUEST(SELinuxSetContextReq); - REQUEST_FIXED_SIZE(SELinuxSetContextReq, stuff->context_len); - - if (stuff->context_len < 1) - return BadLength; - ctx = SELinuxCopyContext((char *)(stuff + 1), stuff->context_len); - if (!ctx) - return BadAlloc; - - rc = dixLookupDevice(&dev, stuff->id, client, DixManageAccess); - if (rc != Success) - goto out; - - if (security_check_context_raw(ctx) < 0 || - avc_context_to_sid_raw(ctx, &sid) < 0) { - rc = BadValue; - goto out; - } - - subj = dixLookupPrivate(&dev->devPrivates, subjectKey); - subj->sid = sid; - obj = dixLookupPrivate(&dev->devPrivates, objectKey); - obj->sid = sid; - - rc = Success; -out: - xfree(ctx); - return rc; -} - -static int -ProcSELinuxGetDeviceContext(ClientPtr client) -{ - DeviceIntPtr dev; - SELinuxSubjectRec *subj; - int rc; - - REQUEST(SELinuxGetContextReq); - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - - rc = dixLookupDevice(&dev, stuff->id, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - subj = dixLookupPrivate(&dev->devPrivates, subjectKey); - return SELinuxSendContextReply(client, subj->sid); -} - -static int -ProcSELinuxGetDrawableContext(ClientPtr client) -{ - DrawablePtr pDraw; - PrivateRec **privatePtr; - SELinuxObjectRec *obj; - int rc; - - REQUEST(SELinuxGetContextReq); - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - - rc = dixLookupDrawable(&pDraw, stuff->id, client, - M_WINDOW | M_DRAWABLE_PIXMAP, - DixGetAttrAccess); - if (rc != Success) - return rc; - - if (pDraw->type == M_DRAWABLE_PIXMAP) - privatePtr = &((PixmapPtr)pDraw)->devPrivates; - else - privatePtr = &((WindowPtr)pDraw)->devPrivates; - - obj = dixLookupPrivate(privatePtr, objectKey); - return SELinuxSendContextReply(client, obj->sid); -} - -static int -ProcSELinuxGetPropertyContext(ClientPtr client, pointer privKey) -{ - WindowPtr pWin; - PropertyPtr pProp; - SELinuxObjectRec *obj; - int rc; - - REQUEST(SELinuxGetPropertyContextReq); - REQUEST_SIZE_MATCH(SELinuxGetPropertyContextReq); - - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetPropAccess); - if (rc != Success) - return rc; - - rc = dixLookupProperty(&pProp, pWin, stuff->property, client, - DixGetAttrAccess); - if (rc != Success) - return rc; - - obj = dixLookupPrivate(&pProp->devPrivates, privKey); - return SELinuxSendContextReply(client, obj->sid); -} - -static int -ProcSELinuxGetSelectionContext(ClientPtr client, pointer privKey) -{ - Selection *pSel; - SELinuxObjectRec *obj; - int rc; - - REQUEST(SELinuxGetContextReq); - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - - rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - obj = dixLookupPrivate(&pSel->devPrivates, privKey); - return SELinuxSendContextReply(client, obj->sid); -} - -static int -ProcSELinuxGetClientContext(ClientPtr client) -{ - ClientPtr target; - SELinuxSubjectRec *subj; - int rc; - - REQUEST(SELinuxGetContextReq); - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - - rc = dixLookupClient(&target, stuff->id, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - subj = dixLookupPrivate(&target->devPrivates, subjectKey); - return SELinuxSendContextReply(client, subj->sid); -} - -static int -SELinuxPopulateItem(SELinuxListItemRec *i, PrivateRec **privPtr, CARD32 id, - int *size) -{ - SELinuxObjectRec *obj = dixLookupPrivate(privPtr, objectKey); - SELinuxObjectRec *data = dixLookupPrivate(privPtr, dataKey); - - if (avc_sid_to_context_raw(obj->sid, &i->octx) < 0) - return BadValue; - if (avc_sid_to_context_raw(data->sid, &i->dctx) < 0) - return BadValue; - - i->id = id; - i->octx_len = bytes_to_int32(strlen(i->octx) + 1); - i->dctx_len = bytes_to_int32(strlen(i->dctx) + 1); - - *size += i->octx_len + i->dctx_len + 3; - return Success; -} - -static void -SELinuxFreeItems(SELinuxListItemRec *items, int count) -{ - int k; - for (k = 0; k < count; k++) { - freecon(items[k].octx); - freecon(items[k].dctx); - } - xfree(items); -} - -static int -SELinuxSendItemsToClient(ClientPtr client, SELinuxListItemRec *items, - int size, int count) -{ - int rc, k, n, pos = 0; - SELinuxListItemsReply rep; - CARD32 *buf; - - buf = xcalloc(size, sizeof(CARD32)); - if (size && !buf) { - rc = BadAlloc; - goto out; - } - - /* Fill in the buffer */ - for (k = 0; k < count; k++) { - buf[pos] = items[k].id; - if (client->swapped) - swapl(buf + pos, n); - pos++; - - buf[pos] = items[k].octx_len * 4; - if (client->swapped) - swapl(buf + pos, n); - pos++; - - buf[pos] = items[k].dctx_len * 4; - if (client->swapped) - swapl(buf + pos, n); - pos++; - - memcpy((char *)(buf + pos), items[k].octx, strlen(items[k].octx) + 1); - pos += items[k].octx_len; - memcpy((char *)(buf + pos), items[k].dctx, strlen(items[k].dctx) + 1); - pos += items[k].dctx_len; - } - - /* Send reply to client */ - rep.type = X_Reply; - rep.length = size; - rep.sequenceNumber = client->sequence; - rep.count = count; - - if (client->swapped) { - swapl(&rep.length, n); - swaps(&rep.sequenceNumber, n); - swapl(&rep.count, n); - } - - WriteToClient(client, sizeof(SELinuxListItemsReply), (char *)&rep); - WriteToClient(client, size * 4, (char *)buf); - - /* Free stuff and return */ - rc = client->noClientException; - xfree(buf); -out: - SELinuxFreeItems(items, count); - return rc; -} - -static int -ProcSELinuxListProperties(ClientPtr client) -{ - WindowPtr pWin; - PropertyPtr pProp; - SELinuxListItemRec *items; - int rc, count, size, i; - CARD32 id; - - REQUEST(SELinuxGetContextReq); - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - - rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess); - if (rc != Success) - return rc; - - /* Count the number of properties and allocate items */ - count = 0; - for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) - count++; - items = xcalloc(count, sizeof(SELinuxListItemRec)); - if (count && !items) - return BadAlloc; - - /* Fill in the items and calculate size */ - i = 0; - size = 0; - for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) { - id = pProp->propertyName; - rc = SELinuxPopulateItem(items + i, &pProp->devPrivates, id, &size); - if (rc != Success) { - SELinuxFreeItems(items, count); - return rc; - } - i++; - } - - return SELinuxSendItemsToClient(client, items, size, count); -} - -static int -ProcSELinuxListSelections(ClientPtr client) -{ - Selection *pSel; - SELinuxListItemRec *items; - int rc, count, size, i; - CARD32 id; - - REQUEST_SIZE_MATCH(SELinuxGetCreateContextReq); - - /* Count the number of selections and allocate items */ - count = 0; - for (pSel = CurrentSelections; pSel; pSel = pSel->next) - count++; - items = xcalloc(count, sizeof(SELinuxListItemRec)); - if (count && !items) - return BadAlloc; - - /* Fill in the items and calculate size */ - i = 0; - size = 0; - for (pSel = CurrentSelections; pSel; pSel = pSel->next) { - id = pSel->selection; - rc = SELinuxPopulateItem(items + i, &pSel->devPrivates, id, &size); - if (rc != Success) { - SELinuxFreeItems(items, count); - return rc; - } - i++; - } - - return SELinuxSendItemsToClient(client, items, size, count); -} - -static int -ProcSELinuxDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_SELinuxQueryVersion: - return ProcSELinuxQueryVersion(client); - case X_SELinuxSetDeviceCreateContext: - return ProcSELinuxSetCreateContext(client, CTX_DEV); - case X_SELinuxGetDeviceCreateContext: - return ProcSELinuxGetCreateContext(client, CTX_DEV); - case X_SELinuxSetDeviceContext: - return ProcSELinuxSetDeviceContext(client); - case X_SELinuxGetDeviceContext: - return ProcSELinuxGetDeviceContext(client); - case X_SELinuxSetDrawableCreateContext: - return ProcSELinuxSetCreateContext(client, CTX_WIN); - case X_SELinuxGetDrawableCreateContext: - return ProcSELinuxGetCreateContext(client, CTX_WIN); - case X_SELinuxGetDrawableContext: - return ProcSELinuxGetDrawableContext(client); - case X_SELinuxSetPropertyCreateContext: - return ProcSELinuxSetCreateContext(client, CTX_PRP); - case X_SELinuxGetPropertyCreateContext: - return ProcSELinuxGetCreateContext(client, CTX_PRP); - case X_SELinuxSetPropertyUseContext: - return ProcSELinuxSetCreateContext(client, USE_PRP); - case X_SELinuxGetPropertyUseContext: - return ProcSELinuxGetCreateContext(client, USE_PRP); - case X_SELinuxGetPropertyContext: - return ProcSELinuxGetPropertyContext(client, objectKey); - case X_SELinuxGetPropertyDataContext: - return ProcSELinuxGetPropertyContext(client, dataKey); - case X_SELinuxListProperties: - return ProcSELinuxListProperties(client); - case X_SELinuxSetSelectionCreateContext: - return ProcSELinuxSetCreateContext(client, CTX_SEL); - case X_SELinuxGetSelectionCreateContext: - return ProcSELinuxGetCreateContext(client, CTX_SEL); - case X_SELinuxSetSelectionUseContext: - return ProcSELinuxSetCreateContext(client, USE_SEL); - case X_SELinuxGetSelectionUseContext: - return ProcSELinuxGetCreateContext(client, USE_SEL); - case X_SELinuxGetSelectionContext: - return ProcSELinuxGetSelectionContext(client, objectKey); - case X_SELinuxGetSelectionDataContext: - return ProcSELinuxGetSelectionContext(client, dataKey); - case X_SELinuxListSelections: - return ProcSELinuxListSelections(client); - case X_SELinuxGetClientContext: - return ProcSELinuxGetClientContext(client); - default: - return BadRequest; - } -} - -static int -SProcSELinuxQueryVersion(ClientPtr client) -{ - REQUEST(SELinuxQueryVersionReq); - int n; - - REQUEST_SIZE_MATCH(SELinuxQueryVersionReq); - swaps(&stuff->client_major, n); - swaps(&stuff->client_minor, n); - return ProcSELinuxQueryVersion(client); -} - -static int -SProcSELinuxSetCreateContext(ClientPtr client, unsigned offset) -{ - REQUEST(SELinuxSetCreateContextReq); - int n; - - REQUEST_AT_LEAST_SIZE(SELinuxSetCreateContextReq); - swapl(&stuff->context_len, n); - return ProcSELinuxSetCreateContext(client, offset); -} - -static int -SProcSELinuxSetDeviceContext(ClientPtr client) -{ - REQUEST(SELinuxSetContextReq); - int n; - - REQUEST_AT_LEAST_SIZE(SELinuxSetContextReq); - swapl(&stuff->id, n); - swapl(&stuff->context_len, n); - return ProcSELinuxSetDeviceContext(client); -} - -static int -SProcSELinuxGetDeviceContext(ClientPtr client) -{ - REQUEST(SELinuxGetContextReq); - int n; - - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - swapl(&stuff->id, n); - return ProcSELinuxGetDeviceContext(client); -} - -static int -SProcSELinuxGetDrawableContext(ClientPtr client) -{ - REQUEST(SELinuxGetContextReq); - int n; - - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - swapl(&stuff->id, n); - return ProcSELinuxGetDrawableContext(client); -} - -static int -SProcSELinuxGetPropertyContext(ClientPtr client, pointer privKey) -{ - REQUEST(SELinuxGetPropertyContextReq); - int n; - - REQUEST_SIZE_MATCH(SELinuxGetPropertyContextReq); - swapl(&stuff->window, n); - swapl(&stuff->property, n); - return ProcSELinuxGetPropertyContext(client, privKey); -} - -static int -SProcSELinuxGetSelectionContext(ClientPtr client, pointer privKey) -{ - REQUEST(SELinuxGetContextReq); - int n; - - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - swapl(&stuff->id, n); - return ProcSELinuxGetSelectionContext(client, privKey); -} - -static int -SProcSELinuxListProperties(ClientPtr client) -{ - REQUEST(SELinuxGetContextReq); - int n; - - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - swapl(&stuff->id, n); - return ProcSELinuxListProperties(client); -} - -static int -SProcSELinuxGetClientContext(ClientPtr client) -{ - REQUEST(SELinuxGetContextReq); - int n; - - REQUEST_SIZE_MATCH(SELinuxGetContextReq); - swapl(&stuff->id, n); - return ProcSELinuxGetClientContext(client); -} - -static int -SProcSELinuxDispatch(ClientPtr client) -{ - REQUEST(xReq); - int n; - - swaps(&stuff->length, n); - - switch (stuff->data) { - case X_SELinuxQueryVersion: - return SProcSELinuxQueryVersion(client); - case X_SELinuxSetDeviceCreateContext: - return SProcSELinuxSetCreateContext(client, CTX_DEV); - case X_SELinuxGetDeviceCreateContext: - return ProcSELinuxGetCreateContext(client, CTX_DEV); - case X_SELinuxSetDeviceContext: - return SProcSELinuxSetDeviceContext(client); - case X_SELinuxGetDeviceContext: - return SProcSELinuxGetDeviceContext(client); - case X_SELinuxSetDrawableCreateContext: - return SProcSELinuxSetCreateContext(client, CTX_WIN); - case X_SELinuxGetDrawableCreateContext: - return ProcSELinuxGetCreateContext(client, CTX_WIN); - case X_SELinuxGetDrawableContext: - return SProcSELinuxGetDrawableContext(client); - case X_SELinuxSetPropertyCreateContext: - return SProcSELinuxSetCreateContext(client, CTX_PRP); - case X_SELinuxGetPropertyCreateContext: - return ProcSELinuxGetCreateContext(client, CTX_PRP); - case X_SELinuxSetPropertyUseContext: - return SProcSELinuxSetCreateContext(client, USE_PRP); - case X_SELinuxGetPropertyUseContext: - return ProcSELinuxGetCreateContext(client, USE_PRP); - case X_SELinuxGetPropertyContext: - return SProcSELinuxGetPropertyContext(client, objectKey); - case X_SELinuxGetPropertyDataContext: - return SProcSELinuxGetPropertyContext(client, dataKey); - case X_SELinuxListProperties: - return SProcSELinuxListProperties(client); - case X_SELinuxSetSelectionCreateContext: - return SProcSELinuxSetCreateContext(client, CTX_SEL); - case X_SELinuxGetSelectionCreateContext: - return ProcSELinuxGetCreateContext(client, CTX_SEL); - case X_SELinuxSetSelectionUseContext: - return SProcSELinuxSetCreateContext(client, USE_SEL); - case X_SELinuxGetSelectionUseContext: - return ProcSELinuxGetCreateContext(client, USE_SEL); - case X_SELinuxGetSelectionContext: - return SProcSELinuxGetSelectionContext(client, objectKey); - case X_SELinuxGetSelectionDataContext: - return SProcSELinuxGetSelectionContext(client, dataKey); - case X_SELinuxListSelections: - return ProcSELinuxListSelections(client); - case X_SELinuxGetClientContext: - return SProcSELinuxGetClientContext(client); - default: - return BadRequest; - } -} - - -/* - * Extension Setup / Teardown - */ - -static void -SELinuxResetProc(ExtensionEntry *extEntry) -{ - SELinuxFlaskReset(); - SELinuxLabelReset(); -} - -void -SELinuxExtensionInit(INITARGS) -{ - ExtensionEntry *extEntry; - - /* Check SELinux mode on system, configuration file, and boolean */ - if (!is_selinux_enabled()) { - LogMessage(X_INFO, "SELinux: Disabled on system\n"); - return; - } - if (selinuxEnforcingState == SELINUX_MODE_DISABLED) { - LogMessage(X_INFO, "SELinux: Disabled in configuration file\n"); - return; - } - if (!security_get_boolean_active("xserver_object_manager")) { - LogMessage(X_INFO, "SELinux: Disabled by boolean\n"); - return; - } - - /* Set up XACE hooks */ - SELinuxLabelInit(); - SELinuxFlaskInit(); - - /* Add extension to server */ - extEntry = AddExtension(SELINUX_EXTENSION_NAME, - SELinuxNumberEvents, SELinuxNumberErrors, - ProcSELinuxDispatch, SProcSELinuxDispatch, - SELinuxResetProc, StandardMinorOpcode); - - AddExtensionAlias("Flask", extEntry); -} +/************************************************************ + +Author: Eamon Walsh + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +this permission notice appear in supporting documentation. 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 +AUTHOR 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. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "selection.h" +#include "inputstr.h" +#include "windowstr.h" +#include "propertyst.h" +#include "extnsionst.h" +#include "modinit.h" +#include "xselinuxint.h" + +#define CTX_DEV offsetof(SELinuxSubjectRec, dev_create_sid) +#define CTX_WIN offsetof(SELinuxSubjectRec, win_create_sid) +#define CTX_PRP offsetof(SELinuxSubjectRec, prp_create_sid) +#define CTX_SEL offsetof(SELinuxSubjectRec, sel_create_sid) +#define USE_PRP offsetof(SELinuxSubjectRec, prp_use_sid) +#define USE_SEL offsetof(SELinuxSubjectRec, sel_use_sid) + +typedef struct { + security_context_t octx; + security_context_t dctx; + CARD32 octx_len; + CARD32 dctx_len; + CARD32 id; +} SELinuxListItemRec; + + +/* + * Extension Dispatch + */ + +static security_context_t +SELinuxCopyContext(char *ptr, unsigned len) +{ + security_context_t copy = malloc(len + 1); + if (!copy) + return NULL; + strncpy(copy, ptr, len); + copy[len] = '\0'; + return copy; +} + +static int +ProcSELinuxQueryVersion(ClientPtr client) +{ + SELinuxQueryVersionReply rep; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.server_major = SELINUX_MAJOR_VERSION; + rep.server_minor = SELINUX_MINOR_VERSION; + if (client->swapped) { + int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.server_major, n); + swaps(&rep.server_minor, n); + } + WriteToClient(client, sizeof(rep), (char *)&rep); + return Success; +} + +static int +SELinuxSendContextReply(ClientPtr client, security_id_t sid) +{ + SELinuxGetContextReply rep; + security_context_t ctx = NULL; + int len = 0; + + if (sid) { + if (avc_sid_to_context_raw(sid, &ctx) < 0) + return BadValue; + len = strlen(ctx) + 1; + } + + rep.type = X_Reply; + rep.length = bytes_to_int32(len); + rep.sequenceNumber = client->sequence; + rep.context_len = len; + + if (client->swapped) { + int n; + swapl(&rep.length, n); + swaps(&rep.sequenceNumber, n); + swapl(&rep.context_len, n); + } + + WriteToClient(client, sizeof(SELinuxGetContextReply), (char *)&rep); + WriteToClient(client, len, ctx); + freecon(ctx); + return Success; +} + +static int +ProcSELinuxSetCreateContext(ClientPtr client, unsigned offset) +{ + PrivateRec **privPtr = &client->devPrivates; + security_id_t *pSid; + security_context_t ctx = NULL; + char *ptr; + int rc; + + REQUEST(SELinuxSetCreateContextReq); + REQUEST_FIXED_SIZE(SELinuxSetCreateContextReq, stuff->context_len); + + if (stuff->context_len > 0) { + ctx = SELinuxCopyContext((char *)(stuff + 1), stuff->context_len); + if (!ctx) + return BadAlloc; + } + + ptr = dixLookupPrivate(privPtr, subjectKey); + pSid = (security_id_t *)(ptr + offset); + *pSid = NULL; + + rc = Success; + if (stuff->context_len > 0) { + if (security_check_context_raw(ctx) < 0 || + avc_context_to_sid_raw(ctx, pSid) < 0) + rc = BadValue; + } + + free(ctx); + return rc; +} + +static int +ProcSELinuxGetCreateContext(ClientPtr client, unsigned offset) +{ + security_id_t *pSid; + char *ptr; + + REQUEST_SIZE_MATCH(SELinuxGetCreateContextReq); + + if (offset == CTX_DEV) + ptr = dixLookupPrivate(&serverClient->devPrivates, subjectKey); + else + ptr = dixLookupPrivate(&client->devPrivates, subjectKey); + + pSid = (security_id_t *)(ptr + offset); + return SELinuxSendContextReply(client, *pSid); +} + +static int +ProcSELinuxSetDeviceContext(ClientPtr client) +{ + security_context_t ctx; + security_id_t sid; + DeviceIntPtr dev; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj; + int rc; + + REQUEST(SELinuxSetContextReq); + REQUEST_FIXED_SIZE(SELinuxSetContextReq, stuff->context_len); + + if (stuff->context_len < 1) + return BadLength; + ctx = SELinuxCopyContext((char *)(stuff + 1), stuff->context_len); + if (!ctx) + return BadAlloc; + + rc = dixLookupDevice(&dev, stuff->id, client, DixManageAccess); + if (rc != Success) + goto out; + + if (security_check_context_raw(ctx) < 0 || + avc_context_to_sid_raw(ctx, &sid) < 0) { + rc = BadValue; + goto out; + } + + subj = dixLookupPrivate(&dev->devPrivates, subjectKey); + subj->sid = sid; + obj = dixLookupPrivate(&dev->devPrivates, objectKey); + obj->sid = sid; + + rc = Success; +out: + free(ctx); + return rc; +} + +static int +ProcSELinuxGetDeviceContext(ClientPtr client) +{ + DeviceIntPtr dev; + SELinuxSubjectRec *subj; + int rc; + + REQUEST(SELinuxGetContextReq); + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + + rc = dixLookupDevice(&dev, stuff->id, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + subj = dixLookupPrivate(&dev->devPrivates, subjectKey); + return SELinuxSendContextReply(client, subj->sid); +} + +static int +ProcSELinuxGetDrawableContext(ClientPtr client) +{ + DrawablePtr pDraw; + PrivateRec **privatePtr; + SELinuxObjectRec *obj; + int rc; + + REQUEST(SELinuxGetContextReq); + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + + rc = dixLookupDrawable(&pDraw, stuff->id, client, + M_WINDOW | M_DRAWABLE_PIXMAP, + DixGetAttrAccess); + if (rc != Success) + return rc; + + if (pDraw->type == M_DRAWABLE_PIXMAP) + privatePtr = &((PixmapPtr)pDraw)->devPrivates; + else + privatePtr = &((WindowPtr)pDraw)->devPrivates; + + obj = dixLookupPrivate(privatePtr, objectKey); + return SELinuxSendContextReply(client, obj->sid); +} + +static int +ProcSELinuxGetPropertyContext(ClientPtr client, pointer privKey) +{ + WindowPtr pWin; + PropertyPtr pProp; + SELinuxObjectRec *obj; + int rc; + + REQUEST(SELinuxGetPropertyContextReq); + REQUEST_SIZE_MATCH(SELinuxGetPropertyContextReq); + + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetPropAccess); + if (rc != Success) + return rc; + + rc = dixLookupProperty(&pProp, pWin, stuff->property, client, + DixGetAttrAccess); + if (rc != Success) + return rc; + + obj = dixLookupPrivate(&pProp->devPrivates, privKey); + return SELinuxSendContextReply(client, obj->sid); +} + +static int +ProcSELinuxGetSelectionContext(ClientPtr client, pointer privKey) +{ + Selection *pSel; + SELinuxObjectRec *obj; + int rc; + + REQUEST(SELinuxGetContextReq); + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + + rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + obj = dixLookupPrivate(&pSel->devPrivates, privKey); + return SELinuxSendContextReply(client, obj->sid); +} + +static int +ProcSELinuxGetClientContext(ClientPtr client) +{ + ClientPtr target; + SELinuxSubjectRec *subj; + int rc; + + REQUEST(SELinuxGetContextReq); + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + + rc = dixLookupClient(&target, stuff->id, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + subj = dixLookupPrivate(&target->devPrivates, subjectKey); + return SELinuxSendContextReply(client, subj->sid); +} + +static int +SELinuxPopulateItem(SELinuxListItemRec *i, PrivateRec **privPtr, CARD32 id, + int *size) +{ + SELinuxObjectRec *obj = dixLookupPrivate(privPtr, objectKey); + SELinuxObjectRec *data = dixLookupPrivate(privPtr, dataKey); + + if (avc_sid_to_context_raw(obj->sid, &i->octx) < 0) + return BadValue; + if (avc_sid_to_context_raw(data->sid, &i->dctx) < 0) + return BadValue; + + i->id = id; + i->octx_len = bytes_to_int32(strlen(i->octx) + 1); + i->dctx_len = bytes_to_int32(strlen(i->dctx) + 1); + + *size += i->octx_len + i->dctx_len + 3; + return Success; +} + +static void +SELinuxFreeItems(SELinuxListItemRec *items, int count) +{ + int k; + for (k = 0; k < count; k++) { + freecon(items[k].octx); + freecon(items[k].dctx); + } + free(items); +} + +static int +SELinuxSendItemsToClient(ClientPtr client, SELinuxListItemRec *items, + int size, int count) +{ + int rc, k, n, pos = 0; + SELinuxListItemsReply rep; + CARD32 *buf; + + buf = calloc(size, sizeof(CARD32)); + if (size && !buf) { + rc = BadAlloc; + goto out; + } + + /* Fill in the buffer */ + for (k = 0; k < count; k++) { + buf[pos] = items[k].id; + if (client->swapped) + swapl(buf + pos, n); + pos++; + + buf[pos] = items[k].octx_len * 4; + if (client->swapped) + swapl(buf + pos, n); + pos++; + + buf[pos] = items[k].dctx_len * 4; + if (client->swapped) + swapl(buf + pos, n); + pos++; + + memcpy((char *)(buf + pos), items[k].octx, strlen(items[k].octx) + 1); + pos += items[k].octx_len; + memcpy((char *)(buf + pos), items[k].dctx, strlen(items[k].dctx) + 1); + pos += items[k].dctx_len; + } + + /* Send reply to client */ + rep.type = X_Reply; + rep.length = size; + rep.sequenceNumber = client->sequence; + rep.count = count; + + if (client->swapped) { + swapl(&rep.length, n); + swaps(&rep.sequenceNumber, n); + swapl(&rep.count, n); + } + + WriteToClient(client, sizeof(SELinuxListItemsReply), (char *)&rep); + WriteToClient(client, size * 4, (char *)buf); + + /* Free stuff and return */ + rc = Success; + free(buf); +out: + SELinuxFreeItems(items, count); + return rc; +} + +static int +ProcSELinuxListProperties(ClientPtr client) +{ + WindowPtr pWin; + PropertyPtr pProp; + SELinuxListItemRec *items; + int rc, count, size, i; + CARD32 id; + + REQUEST(SELinuxGetContextReq); + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + + rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess); + if (rc != Success) + return rc; + + /* Count the number of properties and allocate items */ + count = 0; + for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) + count++; + items = calloc(count, sizeof(SELinuxListItemRec)); + if (count && !items) + return BadAlloc; + + /* Fill in the items and calculate size */ + i = 0; + size = 0; + for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) { + id = pProp->propertyName; + rc = SELinuxPopulateItem(items + i, &pProp->devPrivates, id, &size); + if (rc != Success) { + SELinuxFreeItems(items, count); + return rc; + } + i++; + } + + return SELinuxSendItemsToClient(client, items, size, count); +} + +static int +ProcSELinuxListSelections(ClientPtr client) +{ + Selection *pSel; + SELinuxListItemRec *items; + int rc, count, size, i; + CARD32 id; + + REQUEST_SIZE_MATCH(SELinuxGetCreateContextReq); + + /* Count the number of selections and allocate items */ + count = 0; + for (pSel = CurrentSelections; pSel; pSel = pSel->next) + count++; + items = calloc(count, sizeof(SELinuxListItemRec)); + if (count && !items) + return BadAlloc; + + /* Fill in the items and calculate size */ + i = 0; + size = 0; + for (pSel = CurrentSelections; pSel; pSel = pSel->next) { + id = pSel->selection; + rc = SELinuxPopulateItem(items + i, &pSel->devPrivates, id, &size); + if (rc != Success) { + SELinuxFreeItems(items, count); + return rc; + } + i++; + } + + return SELinuxSendItemsToClient(client, items, size, count); +} + +static int +ProcSELinuxDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_SELinuxQueryVersion: + return ProcSELinuxQueryVersion(client); + case X_SELinuxSetDeviceCreateContext: + return ProcSELinuxSetCreateContext(client, CTX_DEV); + case X_SELinuxGetDeviceCreateContext: + return ProcSELinuxGetCreateContext(client, CTX_DEV); + case X_SELinuxSetDeviceContext: + return ProcSELinuxSetDeviceContext(client); + case X_SELinuxGetDeviceContext: + return ProcSELinuxGetDeviceContext(client); + case X_SELinuxSetDrawableCreateContext: + return ProcSELinuxSetCreateContext(client, CTX_WIN); + case X_SELinuxGetDrawableCreateContext: + return ProcSELinuxGetCreateContext(client, CTX_WIN); + case X_SELinuxGetDrawableContext: + return ProcSELinuxGetDrawableContext(client); + case X_SELinuxSetPropertyCreateContext: + return ProcSELinuxSetCreateContext(client, CTX_PRP); + case X_SELinuxGetPropertyCreateContext: + return ProcSELinuxGetCreateContext(client, CTX_PRP); + case X_SELinuxSetPropertyUseContext: + return ProcSELinuxSetCreateContext(client, USE_PRP); + case X_SELinuxGetPropertyUseContext: + return ProcSELinuxGetCreateContext(client, USE_PRP); + case X_SELinuxGetPropertyContext: + return ProcSELinuxGetPropertyContext(client, objectKey); + case X_SELinuxGetPropertyDataContext: + return ProcSELinuxGetPropertyContext(client, dataKey); + case X_SELinuxListProperties: + return ProcSELinuxListProperties(client); + case X_SELinuxSetSelectionCreateContext: + return ProcSELinuxSetCreateContext(client, CTX_SEL); + case X_SELinuxGetSelectionCreateContext: + return ProcSELinuxGetCreateContext(client, CTX_SEL); + case X_SELinuxSetSelectionUseContext: + return ProcSELinuxSetCreateContext(client, USE_SEL); + case X_SELinuxGetSelectionUseContext: + return ProcSELinuxGetCreateContext(client, USE_SEL); + case X_SELinuxGetSelectionContext: + return ProcSELinuxGetSelectionContext(client, objectKey); + case X_SELinuxGetSelectionDataContext: + return ProcSELinuxGetSelectionContext(client, dataKey); + case X_SELinuxListSelections: + return ProcSELinuxListSelections(client); + case X_SELinuxGetClientContext: + return ProcSELinuxGetClientContext(client); + default: + return BadRequest; + } +} + +static int +SProcSELinuxQueryVersion(ClientPtr client) +{ + REQUEST(SELinuxQueryVersionReq); + int n; + + REQUEST_SIZE_MATCH(SELinuxQueryVersionReq); + swaps(&stuff->client_major, n); + swaps(&stuff->client_minor, n); + return ProcSELinuxQueryVersion(client); +} + +static int +SProcSELinuxSetCreateContext(ClientPtr client, unsigned offset) +{ + REQUEST(SELinuxSetCreateContextReq); + int n; + + REQUEST_AT_LEAST_SIZE(SELinuxSetCreateContextReq); + swapl(&stuff->context_len, n); + return ProcSELinuxSetCreateContext(client, offset); +} + +static int +SProcSELinuxSetDeviceContext(ClientPtr client) +{ + REQUEST(SELinuxSetContextReq); + int n; + + REQUEST_AT_LEAST_SIZE(SELinuxSetContextReq); + swapl(&stuff->id, n); + swapl(&stuff->context_len, n); + return ProcSELinuxSetDeviceContext(client); +} + +static int +SProcSELinuxGetDeviceContext(ClientPtr client) +{ + REQUEST(SELinuxGetContextReq); + int n; + + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + swapl(&stuff->id, n); + return ProcSELinuxGetDeviceContext(client); +} + +static int +SProcSELinuxGetDrawableContext(ClientPtr client) +{ + REQUEST(SELinuxGetContextReq); + int n; + + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + swapl(&stuff->id, n); + return ProcSELinuxGetDrawableContext(client); +} + +static int +SProcSELinuxGetPropertyContext(ClientPtr client, pointer privKey) +{ + REQUEST(SELinuxGetPropertyContextReq); + int n; + + REQUEST_SIZE_MATCH(SELinuxGetPropertyContextReq); + swapl(&stuff->window, n); + swapl(&stuff->property, n); + return ProcSELinuxGetPropertyContext(client, privKey); +} + +static int +SProcSELinuxGetSelectionContext(ClientPtr client, pointer privKey) +{ + REQUEST(SELinuxGetContextReq); + int n; + + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + swapl(&stuff->id, n); + return ProcSELinuxGetSelectionContext(client, privKey); +} + +static int +SProcSELinuxListProperties(ClientPtr client) +{ + REQUEST(SELinuxGetContextReq); + int n; + + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + swapl(&stuff->id, n); + return ProcSELinuxListProperties(client); +} + +static int +SProcSELinuxGetClientContext(ClientPtr client) +{ + REQUEST(SELinuxGetContextReq); + int n; + + REQUEST_SIZE_MATCH(SELinuxGetContextReq); + swapl(&stuff->id, n); + return ProcSELinuxGetClientContext(client); +} + +static int +SProcSELinuxDispatch(ClientPtr client) +{ + REQUEST(xReq); + int n; + + swaps(&stuff->length, n); + + switch (stuff->data) { + case X_SELinuxQueryVersion: + return SProcSELinuxQueryVersion(client); + case X_SELinuxSetDeviceCreateContext: + return SProcSELinuxSetCreateContext(client, CTX_DEV); + case X_SELinuxGetDeviceCreateContext: + return ProcSELinuxGetCreateContext(client, CTX_DEV); + case X_SELinuxSetDeviceContext: + return SProcSELinuxSetDeviceContext(client); + case X_SELinuxGetDeviceContext: + return SProcSELinuxGetDeviceContext(client); + case X_SELinuxSetDrawableCreateContext: + return SProcSELinuxSetCreateContext(client, CTX_WIN); + case X_SELinuxGetDrawableCreateContext: + return ProcSELinuxGetCreateContext(client, CTX_WIN); + case X_SELinuxGetDrawableContext: + return SProcSELinuxGetDrawableContext(client); + case X_SELinuxSetPropertyCreateContext: + return SProcSELinuxSetCreateContext(client, CTX_PRP); + case X_SELinuxGetPropertyCreateContext: + return ProcSELinuxGetCreateContext(client, CTX_PRP); + case X_SELinuxSetPropertyUseContext: + return SProcSELinuxSetCreateContext(client, USE_PRP); + case X_SELinuxGetPropertyUseContext: + return ProcSELinuxGetCreateContext(client, USE_PRP); + case X_SELinuxGetPropertyContext: + return SProcSELinuxGetPropertyContext(client, objectKey); + case X_SELinuxGetPropertyDataContext: + return SProcSELinuxGetPropertyContext(client, dataKey); + case X_SELinuxListProperties: + return SProcSELinuxListProperties(client); + case X_SELinuxSetSelectionCreateContext: + return SProcSELinuxSetCreateContext(client, CTX_SEL); + case X_SELinuxGetSelectionCreateContext: + return ProcSELinuxGetCreateContext(client, CTX_SEL); + case X_SELinuxSetSelectionUseContext: + return SProcSELinuxSetCreateContext(client, USE_SEL); + case X_SELinuxGetSelectionUseContext: + return ProcSELinuxGetCreateContext(client, USE_SEL); + case X_SELinuxGetSelectionContext: + return SProcSELinuxGetSelectionContext(client, objectKey); + case X_SELinuxGetSelectionDataContext: + return SProcSELinuxGetSelectionContext(client, dataKey); + case X_SELinuxListSelections: + return ProcSELinuxListSelections(client); + case X_SELinuxGetClientContext: + return SProcSELinuxGetClientContext(client); + default: + return BadRequest; + } +} + + +/* + * Extension Setup / Teardown + */ + +static void +SELinuxResetProc(ExtensionEntry *extEntry) +{ + SELinuxFlaskReset(); + SELinuxLabelReset(); +} + +void +SELinuxExtensionInit(INITARGS) +{ + ExtensionEntry *extEntry; + + /* Check SELinux mode on system, configuration file, and boolean */ + if (!is_selinux_enabled()) { + LogMessage(X_INFO, "SELinux: Disabled on system\n"); + return; + } + if (selinuxEnforcingState == SELINUX_MODE_DISABLED) { + LogMessage(X_INFO, "SELinux: Disabled in configuration file\n"); + return; + } + if (!security_get_boolean_active("xserver_object_manager")) { + LogMessage(X_INFO, "SELinux: Disabled by boolean\n"); + return; + } + + /* Set up XACE hooks */ + SELinuxLabelInit(); + SELinuxFlaskInit(); + + /* Add extension to server */ + extEntry = AddExtension(SELINUX_EXTENSION_NAME, + SELinuxNumberEvents, SELinuxNumberErrors, + ProcSELinuxDispatch, SProcSELinuxDispatch, + SELinuxResetProc, StandardMinorOpcode); + + AddExtensionAlias("Flask", extEntry); +} diff --git a/xorg-server/Xext/xselinux_hooks.c b/xorg-server/Xext/xselinux_hooks.c index 6c8c8cdbe..6075a34e8 100644 --- a/xorg-server/Xext/xselinux_hooks.c +++ b/xorg-server/Xext/xselinux_hooks.c @@ -1,981 +1,938 @@ -/************************************************************ - -Author: Eamon Walsh - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -this permission notice appear in supporting documentation. 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 -AUTHOR 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. - -********************************************************/ - -/* - * Portions of this code copyright (c) 2005 by Trusted Computer Solutions, Inc. - * All rights reserved. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include -#include "selection.h" -#include "inputstr.h" -#include "scrnintstr.h" -#include "windowstr.h" -#include "propertyst.h" -#include "extnsionst.h" -#include "xacestr.h" -#include "../os/osdep.h" -#define _XSELINUX_NEED_FLASK_MAP -#include "xselinuxint.h" - - -/* structure passed to auditing callback */ -typedef struct { - ClientPtr client; /* client */ - DeviceIntPtr dev; /* device */ - char *command; /* client's executable path */ - unsigned id; /* resource id, if any */ - int restype; /* resource type, if any */ - int event; /* event type, if any */ - Atom property; /* property name, if any */ - Atom selection; /* selection name, if any */ - char *extension; /* extension name, if any */ -} SELinuxAuditRec; - -/* private state keys */ -static int subjectKeyIndex; -DevPrivateKey subjectKey = &subjectKeyIndex; -static int objectKeyIndex; -DevPrivateKey objectKey = &objectKeyIndex; -static int dataKeyIndex; -DevPrivateKey dataKey = &dataKeyIndex; - -/* audit file descriptor */ -static int audit_fd; - -/* atoms for window label properties */ -static Atom atom_ctx; -static Atom atom_client_ctx; - -/* The unlabeled SID */ -static security_id_t unlabeled_sid; - -/* forward declarations */ -static void SELinuxScreen(CallbackListPtr *, pointer, pointer); - -/* "true" pointer value for use as callback data */ -static pointer truep = (pointer)1; - - -/* - * Performs an SELinux permission check. - */ -static int -SELinuxDoCheck(SELinuxSubjectRec *subj, SELinuxObjectRec *obj, - security_class_t class, Mask mode, SELinuxAuditRec *auditdata) -{ - /* serverClient requests OK */ - if (subj->privileged) - return Success; - - auditdata->command = subj->command; - errno = 0; - - if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref, - auditdata) < 0) { - if (mode == DixUnknownAccess) - return Success; /* DixUnknownAccess requests OK ... for now */ - if (errno == EACCES) - return BadAccess; - ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno); - return BadValue; - } - - return Success; -} - -/* - * Labels a newly connected client. - */ -static void -SELinuxLabelClient(ClientPtr client) -{ - int fd = XaceGetConnectionNumber(client); - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj; - security_context_t ctx; - - subj = dixLookupPrivate(&client->devPrivates, subjectKey); - obj = dixLookupPrivate(&client->devPrivates, objectKey); - - /* Try to get a context from the socket */ - if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) { - /* Otherwise, fall back to a default context */ - ctx = SELinuxDefaultClientLabel(); - } - - /* For local clients, try and determine the executable name */ - if (XaceIsLocal(client)) { - struct ucred creds; - socklen_t len = sizeof(creds); - char path[PATH_MAX + 1]; - size_t bytes; - - memset(&creds, 0, sizeof(creds)); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0) - goto finish; - - snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid); - fd = open(path, O_RDONLY); - if (fd < 0) - goto finish; - - bytes = read(fd, path, PATH_MAX + 1); - close(fd); - if (bytes <= 0) - goto finish; - - subj->command = xalloc(bytes); - if (!subj->command) - goto finish; - - memcpy(subj->command, path, bytes); - subj->command[bytes - 1] = 0; - } - -finish: - /* Get a SID from the context */ - if (avc_context_to_sid_raw(ctx, &subj->sid) < 0) - FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n", - client->index, ctx); - - obj->sid = subj->sid; - freecon(ctx); -} - -/* - * Labels initial server objects. - */ -static void -SELinuxLabelInitial(void) -{ - int i; - XaceScreenAccessRec srec; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj; - security_context_t ctx; - pointer unused; - - /* Do the serverClient */ - subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey); - obj = dixLookupPrivate(&serverClient->devPrivates, objectKey); - subj->privileged = 1; - - /* Use the context of the X server process for the serverClient */ - if (getcon_raw(&ctx) < 0) - FatalError("SELinux: couldn't get context of X server process\n"); - - /* Get a SID from the context */ - if (avc_context_to_sid_raw(ctx, &subj->sid) < 0) - FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx); - - obj->sid = subj->sid; - freecon(ctx); - - srec.client = serverClient; - srec.access_mode = DixCreateAccess; - srec.status = Success; - - for (i = 0; i < screenInfo.numScreens; i++) { - /* Do the screen object */ - srec.screen = screenInfo.screens[i]; - SELinuxScreen(NULL, NULL, &srec); - - /* Do the default colormap */ - dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap, - RT_COLORMAP, serverClient, DixCreateAccess); - } -} - -/* - * Labels new resource objects. - */ -static int -SELinuxLabelResource(XaceResourceAccessRec *rec, SELinuxSubjectRec *subj, - SELinuxObjectRec *obj, security_class_t class) -{ - int offset; - security_id_t tsid; - - /* Check for a create context */ - if (rec->rtype & RC_DRAWABLE && subj->win_create_sid) { - obj->sid = subj->win_create_sid; - return Success; - } - - if (rec->parent) - offset = dixLookupPrivateOffset(rec->ptype); - - if (rec->parent && offset >= 0) { - /* Use the SID of the parent object in the labeling operation */ - PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset); - SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey); - tsid = pobj->sid; - } else { - /* Use the SID of the subject */ - tsid = subj->sid; - } - - /* Perform a transition to obtain the final SID */ - if (avc_compute_create(subj->sid, tsid, class, &obj->sid) < 0) { - ErrorF("SELinux: a compute_create call failed!\n"); - return BadValue; - } - - return Success; -} - - -/* - * Libselinux Callbacks - */ - -static int -SELinuxAudit(void *auditdata, - security_class_t class, - char *msgbuf, - size_t msgbufsize) -{ - SELinuxAuditRec *audit = auditdata; - ClientPtr client = audit->client; - char idNum[16]; - const char *propertyName, *selectionName; - int major = -1, minor = -1; - - if (client) { - REQUEST(xReq); - if (stuff) { - major = stuff->reqType; - minor = MinorOpcodeOfRequest(client); - } - } - if (audit->id) - snprintf(idNum, 16, "%x", audit->id); - - propertyName = audit->property ? NameForAtom(audit->property) : NULL; - selectionName = audit->selection ? NameForAtom(audit->selection) : NULL; - - return snprintf(msgbuf, msgbufsize, - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - (major >= 0) ? "request=" : "", - (major >= 0) ? LookupRequestName(major, minor) : "", - audit->command ? " comm=" : "", - audit->command ? audit->command : "", - audit->dev ? " xdevice=\"" : "", - audit->dev ? audit->dev->name : "", - audit->dev ? "\"" : "", - audit->id ? " resid=" : "", - audit->id ? idNum : "", - audit->restype ? " restype=" : "", - audit->restype ? LookupResourceName(audit->restype) : "", - audit->event ? " event=" : "", - audit->event ? LookupEventName(audit->event & 127) : "", - audit->property ? " property=" : "", - audit->property ? propertyName : "", - audit->selection ? " selection=" : "", - audit->selection ? selectionName : "", - audit->extension ? " extension=" : "", - audit->extension ? audit->extension : ""); -} - -static int -SELinuxLog(int type, const char *fmt, ...) -{ - va_list ap; - char buf[MAX_AUDIT_MESSAGE_LENGTH]; - int rc, aut; - - switch (type) { - case SELINUX_INFO: - aut = AUDIT_USER_MAC_POLICY_LOAD; - break; - case SELINUX_AVC: - aut = AUDIT_USER_AVC; - break; - default: - aut = AUDIT_USER_SELINUX_ERR; - break; - } - - va_start(ap, fmt); - vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap); - rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0); - va_end(ap); - LogMessageVerb(X_WARNING, 0, "%s", buf); - return 0; -} - -/* - * XACE Callbacks - */ - -static void -SELinuxDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceDeviceAccessRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj; - SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev }; - security_class_t cls; - int rc; - - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey); - - /* If this is a new object that needs labeling, do it now */ - if (rec->access_mode & DixCreateAccess) { - SELinuxSubjectRec *dsubj; - dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey); - - if (subj->dev_create_sid) { - /* Label the device with the create context */ - obj->sid = subj->dev_create_sid; - dsubj->sid = subj->dev_create_sid; - } else { - /* Label the device directly with the process SID */ - obj->sid = subj->sid; - dsubj->sid = subj->sid; - } - } - - cls = IsPointerDevice(rec->dev) ? SECCLASS_X_POINTER : SECCLASS_X_KEYBOARD; - rc = SELinuxDoCheck(subj, obj, cls, rec->access_mode, &auditdata); - if (rc != Success) - rec->status = rc; -} - -static void -SELinuxSend(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceSendAccessRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj, ev_sid; - SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev }; - security_class_t class; - int rc, i, type; - - if (rec->dev) - subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey); - else - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - - obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey); - - /* Check send permission on window */ - rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess, - &auditdata); - if (rc != Success) - goto err; - - /* Check send permission on specific event types */ - for (i = 0; i < rec->count; i++) { - type = rec->events[i].u.u.type; - class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT; - - rc = SELinuxEventToSID(type, obj->sid, &ev_sid); - if (rc != Success) - goto err; - - auditdata.event = type; - rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata); - if (rc != Success) - goto err; - } - return; -err: - rec->status = rc; -} - -static void -SELinuxReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceReceiveAccessRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj, ev_sid; - SELinuxAuditRec auditdata = { .client = NULL }; - security_class_t class; - int rc, i, type; - - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey); - - /* Check receive permission on window */ - rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess, - &auditdata); - if (rc != Success) - goto err; - - /* Check receive permission on specific event types */ - for (i = 0; i < rec->count; i++) { - type = rec->events[i].u.u.type; - class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT; - - rc = SELinuxEventToSID(type, obj->sid, &ev_sid); - if (rc != Success) - goto err; - - auditdata.event = type; - rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata); - if (rc != Success) - goto err; - } - return; -err: - rec->status = rc; -} - -static void -SELinuxExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceExtAccessRec *rec = calldata; - SELinuxSubjectRec *subj, *serv; - SELinuxObjectRec *obj; - SELinuxAuditRec auditdata = { .client = rec->client }; - int rc; - - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey); - - /* If this is a new object that needs labeling, do it now */ - /* XXX there should be a separate callback for this */ - if (obj->sid == unlabeled_sid) { - security_id_t sid; - - serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey); - rc = SELinuxExtensionToSID(rec->ext->name, &sid); - if (rc != Success) { - rec->status = rc; - return; - } - - /* Perform a transition to obtain the final SID */ - if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION, - &obj->sid) < 0) { - ErrorF("SELinux: a SID transition call failed!\n"); - rec->status = BadValue; - return; - } - } - - /* Perform the security check */ - auditdata.extension = rec->ext->name; - rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode, - &auditdata); - if (rc != Success) - rec->status = rc; -} - -static void -SELinuxSelection(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceSelectionAccessRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj, *data; - Selection *pSel = *rec->ppSel; - Atom name = pSel->selection; - Mask access_mode = rec->access_mode; - SELinuxAuditRec auditdata = { .client = rec->client, .selection = name }; - security_id_t tsid; - int rc; - - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - obj = dixLookupPrivate(&pSel->devPrivates, objectKey); - - /* If this is a new object that needs labeling, do it now */ - if (access_mode & DixCreateAccess) { - rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly); - if (rc != Success) - obj->sid = unlabeled_sid; - access_mode = DixSetAttrAccess; - } - /* If this is a polyinstantiated object, find the right instance */ - else if (obj->poly) { - rc = SELinuxSelectionToSID(name, subj, &tsid, NULL); - if (rc != Success) { - rec->status = rc; - return; - } - while (pSel->selection != name || obj->sid != tsid) { - if ((pSel = pSel->next) == NULL) - break; - obj = dixLookupPrivate(&pSel->devPrivates, objectKey); - } - - if (pSel) - *rec->ppSel = pSel; - else { - rec->status = BadMatch; - return; - } - } - - /* Perform the security check */ - rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode, - &auditdata); - if (rc != Success) - rec->status = rc; - - /* Label the content (advisory only) */ - if (access_mode & DixSetAttrAccess) { - data = dixLookupPrivate(&pSel->devPrivates, dataKey); - if (subj->sel_create_sid) - data->sid = subj->sel_create_sid; - else - data->sid = obj->sid; - } -} - -static void -SELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XacePropertyAccessRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj, *data; - PropertyPtr pProp = *rec->ppProp; - Atom name = pProp->propertyName; - SELinuxAuditRec auditdata = { .client = rec->client, .property = name }; - security_id_t tsid; - int rc; - - /* Don't care about the new content check */ - if (rec->access_mode & DixPostAccess) - return; - - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - obj = dixLookupPrivate(&pProp->devPrivates, objectKey); - - /* If this is a new object that needs labeling, do it now */ - if (rec->access_mode & DixCreateAccess) { - rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly); - if (rc != Success) { - rec->status = rc; - return; - } - } - /* If this is a polyinstantiated object, find the right instance */ - else if (obj->poly) { - rc = SELinuxPropertyToSID(name, subj, &tsid, NULL); - if (rc != Success) { - rec->status = rc; - return; - } - while (pProp->propertyName != name || obj->sid != tsid) { - if ((pProp = pProp->next) == NULL) - break; - obj = dixLookupPrivate(&pProp->devPrivates, objectKey); - } - - if (pProp) - *rec->ppProp = pProp; - else { - rec->status = BadMatch; - return; - } - } - - /* Perform the security check */ - rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode, - &auditdata); - if (rc != Success) - rec->status = rc; - - /* Label the content (advisory only) */ - if (rec->access_mode & DixWriteAccess) { - data = dixLookupPrivate(&pProp->devPrivates, dataKey); - if (subj->prp_create_sid) - data->sid = subj->prp_create_sid; - else - data->sid = obj->sid; - } -} - -static void -SELinuxResource(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceResourceAccessRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj; - SELinuxAuditRec auditdata = { .client = rec->client }; - Mask access_mode = rec->access_mode; - PrivateRec **privatePtr; - security_class_t class; - int rc, offset; - - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - - /* Determine if the resource object has a devPrivates field */ - offset = dixLookupPrivateOffset(rec->rtype); - if (offset < 0) { - /* No: use the SID of the owning client */ - class = SECCLASS_X_RESOURCE; - privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates; - obj = dixLookupPrivate(privatePtr, objectKey); - } else { - /* Yes: use the SID from the resource object itself */ - class = SELinuxTypeToClass(rec->rtype); - privatePtr = DEVPRIV_AT(rec->res, offset); - obj = dixLookupPrivate(privatePtr, objectKey); - } - - /* If this is a new object that needs labeling, do it now */ - if (access_mode & DixCreateAccess && offset >= 0) { - rc = SELinuxLabelResource(rec, subj, obj, class); - if (rc != Success) { - rec->status = rc; - return; - } - } - - /* Collapse generic resource permissions down to read/write */ - if (class == SECCLASS_X_RESOURCE) { - access_mode = !!(rec->access_mode & SELinuxReadMask); /* rd */ - access_mode |= !!(rec->access_mode & ~SELinuxReadMask) << 1; /* wr */ - } - - /* Perform the security check */ - auditdata.restype = rec->rtype; - auditdata.id = rec->id; - rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata); - if (rc != Success) - rec->status = rc; - - /* Perform the background none check on windows */ - if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) { - rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata); - if (rc != Success) - ((WindowPtr)rec->res)->forcedBG = TRUE; - } -} - -static void -SELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata) -{ - XaceScreenAccessRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj; - SELinuxAuditRec auditdata = { .client = rec->client }; - Mask access_mode = rec->access_mode; - int rc; - - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey); - - /* If this is a new object that needs labeling, do it now */ - if (access_mode & DixCreateAccess) { - /* Perform a transition to obtain the final SID */ - if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN, - &obj->sid) < 0) { - ErrorF("SELinux: a compute_create call failed!\n"); - rec->status = BadValue; - return; - } - } - - if (is_saver) - access_mode <<= 2; - - rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata); - if (rc != Success) - rec->status = rc; -} - -static void -SELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceClientAccessRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj; - SELinuxAuditRec auditdata = { .client = rec->client }; - int rc; - - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - obj = dixLookupPrivate(&rec->target->devPrivates, objectKey); - - rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode, - &auditdata); - if (rc != Success) - rec->status = rc; -} - -static void -SELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - XaceServerAccessRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj; - SELinuxAuditRec auditdata = { .client = rec->client }; - int rc; - - subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); - obj = dixLookupPrivate(&serverClient->devPrivates, objectKey); - - rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode, - &auditdata); - if (rc != Success) - rec->status = rc; -} - - -/* - * DIX Callbacks - */ - -static void -SELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - NewClientInfoRec *pci = calldata; - - switch (pci->client->clientState) { - case ClientStateInitial: - SELinuxLabelClient(pci->client); - break; - - default: - break; - } -} - -static void -SELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - ResourceStateInfoRec *rec = calldata; - SELinuxSubjectRec *subj; - SELinuxObjectRec *obj; - WindowPtr pWin; - - if (rec->type != RT_WINDOW) - return; - if (rec->state != ResourceStateAdding) - return; - - pWin = (WindowPtr)rec->value; - subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey); - - if (subj->sid) { - security_context_t ctx; - int rc = avc_sid_to_context_raw(subj->sid, &ctx); - if (rc < 0) - FatalError("SELinux: Failed to get security context!\n"); - rc = dixChangeWindowProperty(serverClient, - pWin, atom_client_ctx, XA_STRING, 8, - PropModeReplace, strlen(ctx), ctx, FALSE); - if (rc != Success) - FatalError("SELinux: Failed to set label property on window!\n"); - freecon(ctx); - } else - FatalError("SELinux: Unexpected unlabeled client found\n"); - - obj = dixLookupPrivate(&pWin->devPrivates, objectKey); - - if (obj->sid) { - security_context_t ctx; - int rc = avc_sid_to_context_raw(obj->sid, &ctx); - if (rc < 0) - FatalError("SELinux: Failed to get security context!\n"); - rc = dixChangeWindowProperty(serverClient, - pWin, atom_ctx, XA_STRING, 8, - PropModeReplace, strlen(ctx), ctx, FALSE); - if (rc != Success) - FatalError("SELinux: Failed to set label property on window!\n"); - freecon(ctx); - } else - FatalError("SELinux: Unexpected unlabeled window found\n"); -} - - -/* - * DevPrivates Callbacks - */ - -static void -SELinuxSubjectInit(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - PrivateCallbackRec *rec = calldata; - SELinuxSubjectRec *subj = *rec->value; - - subj->sid = unlabeled_sid; - - avc_entry_ref_init(&subj->aeref); -} - -static void -SELinuxSubjectFree(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - PrivateCallbackRec *rec = calldata; - SELinuxSubjectRec *subj = *rec->value; - - xfree(subj->command); -} - -static void -SELinuxObjectInit(CallbackListPtr *pcbl, pointer unused, pointer calldata) -{ - PrivateCallbackRec *rec = calldata; - SELinuxObjectRec *obj = *rec->value; - - obj->sid = unlabeled_sid; -} - -static int netlink_fd; - -static void -SELinuxBlockHandler(void *data, struct timeval **tv, void *read_mask) -{ -} - -static void -SELinuxWakeupHandler(void *data, int err, void *read_mask) -{ - if (FD_ISSET(netlink_fd, (fd_set *)read_mask)) - avc_netlink_check_nb(); -} - -void -SELinuxFlaskReset(void) -{ - /* Unregister callbacks */ - DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL); - DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL); - - XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL); - XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL); - XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL); - XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL); - XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL); - XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL); - XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL); - XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL); - XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL); - XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL); - XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL); - XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep); - - /* Tear down SELinux stuff */ - audit_close(audit_fd); - avc_netlink_release_fd(); - RemoveBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler, - NULL); - RemoveGeneralSocket(netlink_fd); - - avc_destroy(); -} - -void -SELinuxFlaskInit(void) -{ - struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *)0 }; - security_context_t ctx; - int ret = TRUE; - - switch(selinuxEnforcingState) { - case SELINUX_MODE_ENFORCING: - LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n"); - avc_option.value = (char *)1; - break; - case SELINUX_MODE_PERMISSIVE: - LogMessage(X_INFO, "SELinux: Configured in permissive mode\n"); - avc_option.value = (char *)0; - break; - default: - avc_option.type = AVC_OPT_UNUSED; - break; - } - - /* Set up SELinux stuff */ - selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback)SELinuxLog); - selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback)SELinuxAudit); - - if (selinux_set_mapping(map) < 0) { - if (errno == EINVAL) { - ErrorF("SELinux: Invalid object class mapping, disabling SELinux support.\n"); - return; - } - FatalError("SELinux: Failed to set up security class mapping\n"); - } - - if (avc_open(&avc_option, 1) < 0) - FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n"); - - if (security_get_initial_context_raw("unlabeled", &ctx) < 0) - FatalError("SELinux: Failed to look up unlabeled context\n"); - if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0) - FatalError("SELinux: a context_to_SID call failed!\n"); - freecon(ctx); - - /* Prepare for auditing */ - audit_fd = audit_open(); - if (audit_fd < 0) - FatalError("SELinux: Failed to open the system audit log\n"); - - /* Allocate private storage */ - if (!dixRequestPrivate(subjectKey, sizeof(SELinuxSubjectRec)) || - !dixRequestPrivate(objectKey, sizeof(SELinuxObjectRec)) || - !dixRequestPrivate(dataKey, sizeof(SELinuxObjectRec))) - FatalError("SELinux: Failed to allocate private storage.\n"); - - /* Create atoms for doing window labeling */ - atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE); - if (atom_ctx == BAD_RESOURCE) - FatalError("SELinux: Failed to create atom\n"); - atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE); - if (atom_client_ctx == BAD_RESOURCE) - FatalError("SELinux: Failed to create atom\n"); - - netlink_fd = avc_netlink_acquire_fd(); - AddGeneralSocket(netlink_fd); - RegisterBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler, - NULL); - - /* Register callbacks */ - ret &= dixRegisterPrivateInitFunc(subjectKey, SELinuxSubjectInit, NULL); - ret &= dixRegisterPrivateDeleteFunc(subjectKey, SELinuxSubjectFree, NULL); - ret &= dixRegisterPrivateInitFunc(objectKey, SELinuxObjectInit, NULL); - ret &= dixRegisterPrivateInitFunc(dataKey, SELinuxObjectInit, NULL); - - ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL); - ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL); - - ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL); - ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL); - ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL); - ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL); - ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL); - ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL); - ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL); - ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL); - ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL); - ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL); - ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL); - ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep); - if (!ret) - FatalError("SELinux: Failed to register one or more callbacks\n"); - - /* Label objects that were created before we could register ourself */ - SELinuxLabelInitial(); -} +/************************************************************ + +Author: Eamon Walsh + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +this permission notice appear in supporting documentation. 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 +AUTHOR 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. + +********************************************************/ + +/* + * Portions of this code copyright (c) 2005 by Trusted Computer Solutions, Inc. + * All rights reserved. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include "selection.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "propertyst.h" +#include "extnsionst.h" +#include "xacestr.h" +#include "../os/osdep.h" +#define _XSELINUX_NEED_FLASK_MAP +#include "xselinuxint.h" + + +/* structure passed to auditing callback */ +typedef struct { + ClientPtr client; /* client */ + DeviceIntPtr dev; /* device */ + char *command; /* client's executable path */ + unsigned id; /* resource id, if any */ + int restype; /* resource type, if any */ + int event; /* event type, if any */ + Atom property; /* property name, if any */ + Atom selection; /* selection name, if any */ + char *extension; /* extension name, if any */ +} SELinuxAuditRec; + +/* private state keys */ +static int subjectKeyIndex; +DevPrivateKey subjectKey = &subjectKeyIndex; +static int objectKeyIndex; +DevPrivateKey objectKey = &objectKeyIndex; +static int dataKeyIndex; +DevPrivateKey dataKey = &dataKeyIndex; + +/* audit file descriptor */ +static int audit_fd; + +/* atoms for window label properties */ +static Atom atom_ctx; +static Atom atom_client_ctx; + +/* The unlabeled SID */ +static security_id_t unlabeled_sid; + +/* forward declarations */ +static void SELinuxScreen(CallbackListPtr *, pointer, pointer); + +/* "true" pointer value for use as callback data */ +static pointer truep = (pointer)1; + + +/* + * Performs an SELinux permission check. + */ +static int +SELinuxDoCheck(SELinuxSubjectRec *subj, SELinuxObjectRec *obj, + security_class_t class, Mask mode, SELinuxAuditRec *auditdata) +{ + /* serverClient requests OK */ + if (subj->privileged) + return Success; + + auditdata->command = subj->command; + errno = 0; + + if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref, + auditdata) < 0) { + if (mode == DixUnknownAccess) + return Success; /* DixUnknownAccess requests OK ... for now */ + if (errno == EACCES) + return BadAccess; + ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno); + return BadValue; + } + + return Success; +} + +/* + * Labels a newly connected client. + */ +static void +SELinuxLabelClient(ClientPtr client) +{ + int fd = XaceGetConnectionNumber(client); + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj; + security_context_t ctx; + + subj = dixLookupPrivate(&client->devPrivates, subjectKey); + obj = dixLookupPrivate(&client->devPrivates, objectKey); + + /* Try to get a context from the socket */ + if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) { + /* Otherwise, fall back to a default context */ + ctx = SELinuxDefaultClientLabel(); + } + + /* For local clients, try and determine the executable name */ + if (XaceIsLocal(client)) { + struct ucred creds; + socklen_t len = sizeof(creds); + char path[PATH_MAX + 1]; + size_t bytes; + + memset(&creds, 0, sizeof(creds)); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0) + goto finish; + + snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid); + fd = open(path, O_RDONLY); + if (fd < 0) + goto finish; + + bytes = read(fd, path, PATH_MAX + 1); + close(fd); + if (bytes <= 0) + goto finish; + + strncpy(subj->command, path, COMMAND_LEN - 1); + } + +finish: + /* Get a SID from the context */ + if (avc_context_to_sid_raw(ctx, &subj->sid) < 0) + FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n", + client->index, ctx); + + obj->sid = subj->sid; + freecon(ctx); +} + +/* + * Labels initial server objects. + */ +static void +SELinuxLabelInitial(void) +{ + int i; + XaceScreenAccessRec srec; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj; + security_context_t ctx; + pointer unused; + + /* Do the serverClient */ + subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey); + obj = dixLookupPrivate(&serverClient->devPrivates, objectKey); + subj->privileged = 1; + + /* Use the context of the X server process for the serverClient */ + if (getcon_raw(&ctx) < 0) + FatalError("SELinux: couldn't get context of X server process\n"); + + /* Get a SID from the context */ + if (avc_context_to_sid_raw(ctx, &subj->sid) < 0) + FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx); + + obj->sid = subj->sid; + freecon(ctx); + + srec.client = serverClient; + srec.access_mode = DixCreateAccess; + srec.status = Success; + + for (i = 0; i < screenInfo.numScreens; i++) { + /* Do the screen object */ + srec.screen = screenInfo.screens[i]; + SELinuxScreen(NULL, NULL, &srec); + + /* Do the default colormap */ + dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap, + RT_COLORMAP, serverClient, DixCreateAccess); + } +} + +/* + * Labels new resource objects. + */ +static int +SELinuxLabelResource(XaceResourceAccessRec *rec, SELinuxSubjectRec *subj, + SELinuxObjectRec *obj, security_class_t class) +{ + int offset; + security_id_t tsid; + + /* Check for a create context */ + if (rec->rtype & RC_DRAWABLE && subj->win_create_sid) { + obj->sid = subj->win_create_sid; + return Success; + } + + if (rec->parent) + offset = dixLookupPrivateOffset(rec->ptype); + + if (rec->parent && offset >= 0) { + /* Use the SID of the parent object in the labeling operation */ + PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset); + SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey); + tsid = pobj->sid; + } else { + /* Use the SID of the subject */ + tsid = subj->sid; + } + + /* Perform a transition to obtain the final SID */ + if (avc_compute_create(subj->sid, tsid, class, &obj->sid) < 0) { + ErrorF("SELinux: a compute_create call failed!\n"); + return BadValue; + } + + return Success; +} + + +/* + * Libselinux Callbacks + */ + +static int +SELinuxAudit(void *auditdata, + security_class_t class, + char *msgbuf, + size_t msgbufsize) +{ + SELinuxAuditRec *audit = auditdata; + ClientPtr client = audit->client; + char idNum[16]; + const char *propertyName, *selectionName; + int major = -1, minor = -1; + + if (client) { + REQUEST(xReq); + if (stuff) { + major = stuff->reqType; + minor = MinorOpcodeOfRequest(client); + } + } + if (audit->id) + snprintf(idNum, 16, "%x", audit->id); + + propertyName = audit->property ? NameForAtom(audit->property) : NULL; + selectionName = audit->selection ? NameForAtom(audit->selection) : NULL; + + return snprintf(msgbuf, msgbufsize, + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + (major >= 0) ? "request=" : "", + (major >= 0) ? LookupRequestName(major, minor) : "", + audit->command ? " comm=" : "", + audit->command ? audit->command : "", + audit->dev ? " xdevice=\"" : "", + audit->dev ? audit->dev->name : "", + audit->dev ? "\"" : "", + audit->id ? " resid=" : "", + audit->id ? idNum : "", + audit->restype ? " restype=" : "", + audit->restype ? LookupResourceName(audit->restype) : "", + audit->event ? " event=" : "", + audit->event ? LookupEventName(audit->event & 127) : "", + audit->property ? " property=" : "", + audit->property ? propertyName : "", + audit->selection ? " selection=" : "", + audit->selection ? selectionName : "", + audit->extension ? " extension=" : "", + audit->extension ? audit->extension : ""); +} + +static int +SELinuxLog(int type, const char *fmt, ...) +{ + va_list ap; + char buf[MAX_AUDIT_MESSAGE_LENGTH]; + int rc, aut; + + switch (type) { + case SELINUX_INFO: + aut = AUDIT_USER_MAC_POLICY_LOAD; + break; + case SELINUX_AVC: + aut = AUDIT_USER_AVC; + break; + default: + aut = AUDIT_USER_SELINUX_ERR; + break; + } + + va_start(ap, fmt); + vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap); + rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0); + va_end(ap); + LogMessageVerb(X_WARNING, 0, "%s", buf); + return 0; +} + +/* + * XACE Callbacks + */ + +static void +SELinuxDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceDeviceAccessRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj; + SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev }; + security_class_t cls; + int rc; + + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey); + + /* If this is a new object that needs labeling, do it now */ + if (rec->access_mode & DixCreateAccess) { + SELinuxSubjectRec *dsubj; + dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey); + + if (subj->dev_create_sid) { + /* Label the device with the create context */ + obj->sid = subj->dev_create_sid; + dsubj->sid = subj->dev_create_sid; + } else { + /* Label the device directly with the process SID */ + obj->sid = subj->sid; + dsubj->sid = subj->sid; + } + } + + cls = IsPointerDevice(rec->dev) ? SECCLASS_X_POINTER : SECCLASS_X_KEYBOARD; + rc = SELinuxDoCheck(subj, obj, cls, rec->access_mode, &auditdata); + if (rc != Success) + rec->status = rc; +} + +static void +SELinuxSend(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceSendAccessRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj, ev_sid; + SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev }; + security_class_t class; + int rc, i, type; + + if (rec->dev) + subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey); + else + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + + obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey); + + /* Check send permission on window */ + rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess, + &auditdata); + if (rc != Success) + goto err; + + /* Check send permission on specific event types */ + for (i = 0; i < rec->count; i++) { + type = rec->events[i].u.u.type; + class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT; + + rc = SELinuxEventToSID(type, obj->sid, &ev_sid); + if (rc != Success) + goto err; + + auditdata.event = type; + rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata); + if (rc != Success) + goto err; + } + return; +err: + rec->status = rc; +} + +static void +SELinuxReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceReceiveAccessRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj, ev_sid; + SELinuxAuditRec auditdata = { .client = NULL }; + security_class_t class; + int rc, i, type; + + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey); + + /* Check receive permission on window */ + rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess, + &auditdata); + if (rc != Success) + goto err; + + /* Check receive permission on specific event types */ + for (i = 0; i < rec->count; i++) { + type = rec->events[i].u.u.type; + class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT; + + rc = SELinuxEventToSID(type, obj->sid, &ev_sid); + if (rc != Success) + goto err; + + auditdata.event = type; + rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata); + if (rc != Success) + goto err; + } + return; +err: + rec->status = rc; +} + +static void +SELinuxExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceExtAccessRec *rec = calldata; + SELinuxSubjectRec *subj, *serv; + SELinuxObjectRec *obj; + SELinuxAuditRec auditdata = { .client = rec->client }; + int rc; + + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey); + + /* If this is a new object that needs labeling, do it now */ + /* XXX there should be a separate callback for this */ + if (obj->sid == NULL) { + security_id_t sid; + + serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey); + rc = SELinuxExtensionToSID(rec->ext->name, &sid); + if (rc != Success) { + rec->status = rc; + return; + } + + /* Perform a transition to obtain the final SID */ + if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION, + &obj->sid) < 0) { + ErrorF("SELinux: a SID transition call failed!\n"); + rec->status = BadValue; + return; + } + } + + /* Perform the security check */ + auditdata.extension = rec->ext->name; + rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode, + &auditdata); + if (rc != Success) + rec->status = rc; +} + +static void +SELinuxSelection(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceSelectionAccessRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj, *data; + Selection *pSel = *rec->ppSel; + Atom name = pSel->selection; + Mask access_mode = rec->access_mode; + SELinuxAuditRec auditdata = { .client = rec->client, .selection = name }; + security_id_t tsid; + int rc; + + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + obj = dixLookupPrivate(&pSel->devPrivates, objectKey); + + /* If this is a new object that needs labeling, do it now */ + if (access_mode & DixCreateAccess) { + rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly); + if (rc != Success) + obj->sid = unlabeled_sid; + access_mode = DixSetAttrAccess; + } + /* If this is a polyinstantiated object, find the right instance */ + else if (obj->poly) { + rc = SELinuxSelectionToSID(name, subj, &tsid, NULL); + if (rc != Success) { + rec->status = rc; + return; + } + while (pSel->selection != name || obj->sid != tsid) { + if ((pSel = pSel->next) == NULL) + break; + obj = dixLookupPrivate(&pSel->devPrivates, objectKey); + } + + if (pSel) + *rec->ppSel = pSel; + else { + rec->status = BadMatch; + return; + } + } + + /* Perform the security check */ + rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode, + &auditdata); + if (rc != Success) + rec->status = rc; + + /* Label the content (advisory only) */ + if (access_mode & DixSetAttrAccess) { + data = dixLookupPrivate(&pSel->devPrivates, dataKey); + if (subj->sel_create_sid) + data->sid = subj->sel_create_sid; + else + data->sid = obj->sid; + } +} + +static void +SELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XacePropertyAccessRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj, *data; + PropertyPtr pProp = *rec->ppProp; + Atom name = pProp->propertyName; + SELinuxAuditRec auditdata = { .client = rec->client, .property = name }; + security_id_t tsid; + int rc; + + /* Don't care about the new content check */ + if (rec->access_mode & DixPostAccess) + return; + + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + obj = dixLookupPrivate(&pProp->devPrivates, objectKey); + + /* If this is a new object that needs labeling, do it now */ + if (rec->access_mode & DixCreateAccess) { + rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly); + if (rc != Success) { + rec->status = rc; + return; + } + } + /* If this is a polyinstantiated object, find the right instance */ + else if (obj->poly) { + rc = SELinuxPropertyToSID(name, subj, &tsid, NULL); + if (rc != Success) { + rec->status = rc; + return; + } + while (pProp->propertyName != name || obj->sid != tsid) { + if ((pProp = pProp->next) == NULL) + break; + obj = dixLookupPrivate(&pProp->devPrivates, objectKey); + } + + if (pProp) + *rec->ppProp = pProp; + else { + rec->status = BadMatch; + return; + } + } + + /* Perform the security check */ + rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode, + &auditdata); + if (rc != Success) + rec->status = rc; + + /* Label the content (advisory only) */ + if (rec->access_mode & DixWriteAccess) { + data = dixLookupPrivate(&pProp->devPrivates, dataKey); + if (subj->prp_create_sid) + data->sid = subj->prp_create_sid; + else + data->sid = obj->sid; + } +} + +static void +SELinuxResource(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceResourceAccessRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj; + SELinuxAuditRec auditdata = { .client = rec->client }; + Mask access_mode = rec->access_mode; + PrivateRec **privatePtr; + security_class_t class; + int rc, offset; + + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + + /* Determine if the resource object has a devPrivates field */ + offset = dixLookupPrivateOffset(rec->rtype); + if (offset < 0) { + /* No: use the SID of the owning client */ + class = SECCLASS_X_RESOURCE; + privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates; + obj = dixLookupPrivate(privatePtr, objectKey); + } else { + /* Yes: use the SID from the resource object itself */ + class = SELinuxTypeToClass(rec->rtype); + privatePtr = DEVPRIV_AT(rec->res, offset); + obj = dixLookupPrivate(privatePtr, objectKey); + } + + /* If this is a new object that needs labeling, do it now */ + if (access_mode & DixCreateAccess && offset >= 0) { + rc = SELinuxLabelResource(rec, subj, obj, class); + if (rc != Success) { + rec->status = rc; + return; + } + } + + /* Collapse generic resource permissions down to read/write */ + if (class == SECCLASS_X_RESOURCE) { + access_mode = !!(rec->access_mode & SELinuxReadMask); /* rd */ + access_mode |= !!(rec->access_mode & ~SELinuxReadMask) << 1; /* wr */ + } + + /* Perform the security check */ + auditdata.restype = rec->rtype; + auditdata.id = rec->id; + rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata); + if (rc != Success) + rec->status = rc; + + /* Perform the background none check on windows */ + if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) { + rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata); + if (rc != Success) + ((WindowPtr)rec->res)->forcedBG = TRUE; + } +} + +static void +SELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata) +{ + XaceScreenAccessRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj; + SELinuxAuditRec auditdata = { .client = rec->client }; + Mask access_mode = rec->access_mode; + int rc; + + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey); + + /* If this is a new object that needs labeling, do it now */ + if (access_mode & DixCreateAccess) { + /* Perform a transition to obtain the final SID */ + if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN, + &obj->sid) < 0) { + ErrorF("SELinux: a compute_create call failed!\n"); + rec->status = BadValue; + return; + } + } + + if (is_saver) + access_mode <<= 2; + + rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata); + if (rc != Success) + rec->status = rc; +} + +static void +SELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceClientAccessRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj; + SELinuxAuditRec auditdata = { .client = rec->client }; + int rc; + + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + obj = dixLookupPrivate(&rec->target->devPrivates, objectKey); + + rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode, + &auditdata); + if (rc != Success) + rec->status = rc; +} + +static void +SELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + XaceServerAccessRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj; + SELinuxAuditRec auditdata = { .client = rec->client }; + int rc; + + subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); + obj = dixLookupPrivate(&serverClient->devPrivates, objectKey); + + rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode, + &auditdata); + if (rc != Success) + rec->status = rc; +} + + +/* + * DIX Callbacks + */ + +static void +SELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + NewClientInfoRec *pci = calldata; + + switch (pci->client->clientState) { + case ClientStateInitial: + SELinuxLabelClient(pci->client); + break; + + default: + break; + } +} + +static void +SELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata) +{ + ResourceStateInfoRec *rec = calldata; + SELinuxSubjectRec *subj; + SELinuxObjectRec *obj; + WindowPtr pWin; + + if (rec->type != RT_WINDOW) + return; + if (rec->state != ResourceStateAdding) + return; + + pWin = (WindowPtr)rec->value; + subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey); + + if (subj->sid) { + security_context_t ctx; + int rc = avc_sid_to_context_raw(subj->sid, &ctx); + if (rc < 0) + FatalError("SELinux: Failed to get security context!\n"); + rc = dixChangeWindowProperty(serverClient, + pWin, atom_client_ctx, XA_STRING, 8, + PropModeReplace, strlen(ctx), ctx, FALSE); + if (rc != Success) + FatalError("SELinux: Failed to set label property on window!\n"); + freecon(ctx); + } else + FatalError("SELinux: Unexpected unlabeled client found\n"); + + obj = dixLookupPrivate(&pWin->devPrivates, objectKey); + + if (obj->sid) { + security_context_t ctx; + int rc = avc_sid_to_context_raw(obj->sid, &ctx); + if (rc < 0) + FatalError("SELinux: Failed to get security context!\n"); + rc = dixChangeWindowProperty(serverClient, + pWin, atom_ctx, XA_STRING, 8, + PropModeReplace, strlen(ctx), ctx, FALSE); + if (rc != Success) + FatalError("SELinux: Failed to set label property on window!\n"); + freecon(ctx); + } else + FatalError("SELinux: Unexpected unlabeled window found\n"); +} + + +static int netlink_fd; + +static void +SELinuxBlockHandler(void *data, struct timeval **tv, void *read_mask) +{ +} + +static void +SELinuxWakeupHandler(void *data, int err, void *read_mask) +{ + if (FD_ISSET(netlink_fd, (fd_set *)read_mask)) + avc_netlink_check_nb(); +} + +void +SELinuxFlaskReset(void) +{ + /* Unregister callbacks */ + DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL); + DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL); + + XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL); + XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL); + XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL); + XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL); + XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL); + XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL); + XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL); + XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL); + XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL); + XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL); + XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL); + XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep); + + /* Tear down SELinux stuff */ + audit_close(audit_fd); + avc_netlink_release_fd(); + RemoveBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler, + NULL); + RemoveGeneralSocket(netlink_fd); + + avc_destroy(); +} + +void +SELinuxFlaskInit(void) +{ + struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *)0 }; + security_context_t ctx; + int ret = TRUE; + + switch(selinuxEnforcingState) { + case SELINUX_MODE_ENFORCING: + LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n"); + avc_option.value = (char *)1; + break; + case SELINUX_MODE_PERMISSIVE: + LogMessage(X_INFO, "SELinux: Configured in permissive mode\n"); + avc_option.value = (char *)0; + break; + default: + avc_option.type = AVC_OPT_UNUSED; + break; + } + + /* Set up SELinux stuff */ + selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback)SELinuxLog); + selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback)SELinuxAudit); + + if (selinux_set_mapping(map) < 0) { + if (errno == EINVAL) { + ErrorF("SELinux: Invalid object class mapping, disabling SELinux support.\n"); + return; + } + FatalError("SELinux: Failed to set up security class mapping\n"); + } + + if (avc_open(&avc_option, 1) < 0) + FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n"); + + if (security_get_initial_context_raw("unlabeled", &ctx) < 0) + FatalError("SELinux: Failed to look up unlabeled context\n"); + if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0) + FatalError("SELinux: a context_to_SID call failed!\n"); + freecon(ctx); + + /* Prepare for auditing */ + audit_fd = audit_open(); + if (audit_fd < 0) + FatalError("SELinux: Failed to open the system audit log\n"); + + /* Allocate private storage */ + if (!dixRequestPrivate(subjectKey, sizeof(SELinuxSubjectRec)) || + !dixRequestPrivate(objectKey, sizeof(SELinuxObjectRec)) || + !dixRequestPrivate(dataKey, sizeof(SELinuxObjectRec))) + FatalError("SELinux: Failed to allocate private storage.\n"); + + /* Create atoms for doing window labeling */ + atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE); + if (atom_ctx == BAD_RESOURCE) + FatalError("SELinux: Failed to create atom\n"); + atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE); + if (atom_client_ctx == BAD_RESOURCE) + FatalError("SELinux: Failed to create atom\n"); + + netlink_fd = avc_netlink_acquire_fd(); + AddGeneralSocket(netlink_fd); + RegisterBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler, + NULL); + + /* Register callbacks */ + ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL); + ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL); + + ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL); + ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL); + ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL); + ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL); + ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL); + ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL); + ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL); + ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL); + ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL); + ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL); + ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL); + ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep); + if (!ret) + FatalError("SELinux: Failed to register one or more callbacks\n"); + + /* Label objects that were created before we could register ourself */ + SELinuxLabelInitial(); +} diff --git a/xorg-server/Xext/xselinux_label.c b/xorg-server/Xext/xselinux_label.c index 9b5023a53..76e537abe 100644 --- a/xorg-server/Xext/xselinux_label.c +++ b/xorg-server/Xext/xselinux_label.c @@ -1,374 +1,374 @@ -/************************************************************ - -Author: Eamon Walsh - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -this permission notice appear in supporting documentation. 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 -AUTHOR 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. - -********************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "registry.h" -#include "xselinuxint.h" - -/* selection and property atom cache */ -typedef struct { - SELinuxObjectRec prp; - SELinuxObjectRec sel; -} SELinuxAtomRec; - -/* dynamic array */ -typedef struct { - unsigned size; - void **array; -} SELinuxArrayRec; - -/* labeling handle */ -static struct selabel_handle *label_hnd; - -/* Array of object classes indexed by resource type */ -SELinuxArrayRec arr_types; -/* Array of event SIDs indexed by event type */ -SELinuxArrayRec arr_events; -/* Array of property and selection SID structures */ -SELinuxArrayRec arr_atoms; - -/* - * Dynamic array helpers - */ -static void * -SELinuxArrayGet(SELinuxArrayRec *rec, unsigned key) -{ - return (rec->size > key) ? rec->array[key] : 0; -} - -static int -SELinuxArraySet(SELinuxArrayRec *rec, unsigned key, void *val) -{ - if (key >= rec->size) { - /* Need to increase size of array */ - rec->array = xrealloc(rec->array, (key + 1) * sizeof(val)); - if (!rec->array) - return FALSE; - memset(rec->array + rec->size, 0, (key - rec->size + 1) * sizeof(val)); - rec->size = key + 1; - } - - rec->array[key] = val; - return TRUE; -} - -static void -SELinuxArrayFree(SELinuxArrayRec *rec, int free_elements) -{ - if (free_elements) { - unsigned i = rec->size; - while (i) - xfree(rec->array[--i]); - } - - xfree(rec->array); - rec->size = 0; - rec->array = NULL; -} - -/* - * Looks up a name in the selection or property mappings - */ -static int -SELinuxAtomToSIDLookup(Atom atom, SELinuxObjectRec *obj, int map, int polymap) -{ - const char *name = NameForAtom(atom); - security_context_t ctx; - int rc = Success; - - obj->poly = 1; - - /* Look in the mappings of names to contexts */ - if (selabel_lookup_raw(label_hnd, &ctx, name, map) == 0) { - obj->poly = 0; - } else if (errno != ENOENT) { - ErrorF("SELinux: a property label lookup failed!\n"); - return BadValue; - } else if (selabel_lookup_raw(label_hnd, &ctx, name, polymap) < 0) { - ErrorF("SELinux: a property label lookup failed!\n"); - return BadValue; - } - - /* Get a SID for context */ - if (avc_context_to_sid_raw(ctx, &obj->sid) < 0) { - ErrorF("SELinux: a context_to_SID_raw call failed!\n"); - rc = BadAlloc; - } - - freecon(ctx); - return rc; -} - -/* - * Looks up the SID corresponding to the given property or selection atom - */ -int -SELinuxAtomToSID(Atom atom, int prop, SELinuxObjectRec **obj_rtn) -{ - SELinuxAtomRec *rec; - SELinuxObjectRec *obj; - int rc, map, polymap; - - rec = SELinuxArrayGet(&arr_atoms, atom); - if (!rec) { - rec = xcalloc(1, sizeof(SELinuxAtomRec)); - if (!rec || !SELinuxArraySet(&arr_atoms, atom, rec)) - return BadAlloc; - } - - if (prop) { - obj = &rec->prp; - map = SELABEL_X_PROP; - polymap = SELABEL_X_POLYPROP; - } else { - obj = &rec->sel; - map = SELABEL_X_SELN; - polymap = SELABEL_X_POLYSELN; - } - - if (!obj->sid) { - rc = SELinuxAtomToSIDLookup(atom, obj, map, polymap); - if (rc != Success) - goto out; - } - - *obj_rtn = obj; - rc = Success; -out: - return rc; -} - -/* - * Looks up a SID for a selection/subject pair - */ -int -SELinuxSelectionToSID(Atom selection, SELinuxSubjectRec *subj, - security_id_t *sid_rtn, int *poly_rtn) -{ - int rc; - SELinuxObjectRec *obj; - security_id_t tsid; - - /* Get the default context and polyinstantiation bit */ - rc = SELinuxAtomToSID(selection, 0, &obj); - if (rc != Success) - return rc; - - /* Check for an override context next */ - if (subj->sel_use_sid) { - tsid = subj->sel_use_sid; - goto out; - } - - tsid = obj->sid; - - /* Polyinstantiate if necessary to obtain the final SID */ - if (obj->poly && avc_compute_member(subj->sid, obj->sid, - SECCLASS_X_SELECTION, &tsid) < 0) { - ErrorF("SELinux: a compute_member call failed!\n"); - return BadValue; - } -out: - *sid_rtn = tsid; - if (poly_rtn) - *poly_rtn = obj->poly; - return Success; -} - -/* - * Looks up a SID for a property/subject pair - */ -int -SELinuxPropertyToSID(Atom property, SELinuxSubjectRec *subj, - security_id_t *sid_rtn, int *poly_rtn) -{ - int rc; - SELinuxObjectRec *obj; - security_id_t tsid, tsid2; - - /* Get the default context and polyinstantiation bit */ - rc = SELinuxAtomToSID(property, 1, &obj); - if (rc != Success) - return rc; - - /* Check for an override context next */ - if (subj->prp_use_sid) { - tsid = subj->prp_use_sid; - goto out; - } - - /* Perform a transition */ - if (avc_compute_create(subj->sid, obj->sid, - SECCLASS_X_PROPERTY, &tsid) < 0) { - ErrorF("SELinux: a compute_create call failed!\n"); - return BadValue; - } - - /* Polyinstantiate if necessary to obtain the final SID */ - if (obj->poly) { - tsid2 = tsid; - if (avc_compute_member(subj->sid, tsid2, - SECCLASS_X_PROPERTY, &tsid) < 0) { - ErrorF("SELinux: a compute_member call failed!\n"); - return BadValue; - } - } -out: - *sid_rtn = tsid; - if (poly_rtn) - *poly_rtn = obj->poly; - return Success; -} - -/* - * Looks up the SID corresponding to the given event type - */ -int -SELinuxEventToSID(unsigned type, security_id_t sid_of_window, - SELinuxObjectRec *sid_return) -{ - const char *name = LookupEventName(type); - security_id_t sid; - security_context_t ctx; - type &= 127; - - sid = SELinuxArrayGet(&arr_events, type); - if (!sid) { - /* Look in the mappings of event names to contexts */ - if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EVENT) < 0) { - ErrorF("SELinux: an event label lookup failed!\n"); - return BadValue; - } - /* Get a SID for context */ - if (avc_context_to_sid_raw(ctx, &sid) < 0) { - ErrorF("SELinux: a context_to_SID_raw call failed!\n"); - freecon(ctx); - return BadAlloc; - } - freecon(ctx); - /* Cache the SID value */ - if (!SELinuxArraySet(&arr_events, type, sid)) - return BadAlloc; - } - - /* Perform a transition to obtain the final SID */ - if (avc_compute_create(sid_of_window, sid, SECCLASS_X_EVENT, - &sid_return->sid) < 0) { - ErrorF("SELinux: a compute_create call failed!\n"); - return BadValue; - } - - return Success; -} - -int -SELinuxExtensionToSID(const char *name, security_id_t *sid_rtn) -{ - security_context_t ctx; - - /* Look in the mappings of extension names to contexts */ - if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EXT) < 0) { - ErrorF("SELinux: a property label lookup failed!\n"); - return BadValue; - } - /* Get a SID for context */ - if (avc_context_to_sid_raw(ctx, sid_rtn) < 0) { - ErrorF("SELinux: a context_to_SID_raw call failed!\n"); - freecon(ctx); - return BadAlloc; - } - freecon(ctx); - return Success; -} - -/* - * Returns the object class corresponding to the given resource type. - */ -security_class_t -SELinuxTypeToClass(RESTYPE type) -{ - void *tmp; - - tmp = SELinuxArrayGet(&arr_types, type & TypeMask); - if (!tmp) { - unsigned long class = SECCLASS_X_RESOURCE; - - if (type & RC_DRAWABLE) - class = SECCLASS_X_DRAWABLE; - else if (type == RT_GC) - class = SECCLASS_X_GC; - else if (type == RT_FONT) - class = SECCLASS_X_FONT; - else if (type == RT_CURSOR) - class = SECCLASS_X_CURSOR; - else if (type == RT_COLORMAP) - class = SECCLASS_X_COLORMAP; - else { - /* Need to do a string lookup */ - const char *str = LookupResourceName(type); - if (!strcmp(str, "PICTURE")) - class = SECCLASS_X_DRAWABLE; - else if (!strcmp(str, "GLYPHSET")) - class = SECCLASS_X_FONT; - } - - tmp = (void *)class; - SELinuxArraySet(&arr_types, type & TypeMask, tmp); - } - - return (security_class_t)(unsigned long)tmp; -} - -security_context_t -SELinuxDefaultClientLabel(void) -{ - security_context_t ctx; - - if (selabel_lookup_raw(label_hnd, &ctx, "remote", SELABEL_X_CLIENT) < 0) - FatalError("SELinux: failed to look up remote-client context\n"); - - return ctx; -} - -void -SELinuxLabelInit(void) -{ - struct selinux_opt selabel_option = { SELABEL_OPT_VALIDATE, (char *)1 }; - - label_hnd = selabel_open(SELABEL_CTX_X, &selabel_option, 1); - if (!label_hnd) - FatalError("SELinux: Failed to open x_contexts mapping in policy\n"); -} - -void -SELinuxLabelReset(void) -{ - selabel_close(label_hnd); - label_hnd = NULL; - - /* Free local state */ - SELinuxArrayFree(&arr_types, 0); - SELinuxArrayFree(&arr_events, 0); - SELinuxArrayFree(&arr_atoms, 1); -} +/************************************************************ + +Author: Eamon Walsh + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +this permission notice appear in supporting documentation. 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 +AUTHOR 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. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "registry.h" +#include "xselinuxint.h" + +/* selection and property atom cache */ +typedef struct { + SELinuxObjectRec prp; + SELinuxObjectRec sel; +} SELinuxAtomRec; + +/* dynamic array */ +typedef struct { + unsigned size; + void **array; +} SELinuxArrayRec; + +/* labeling handle */ +static struct selabel_handle *label_hnd; + +/* Array of object classes indexed by resource type */ +SELinuxArrayRec arr_types; +/* Array of event SIDs indexed by event type */ +SELinuxArrayRec arr_events; +/* Array of property and selection SID structures */ +SELinuxArrayRec arr_atoms; + +/* + * Dynamic array helpers + */ +static void * +SELinuxArrayGet(SELinuxArrayRec *rec, unsigned key) +{ + return (rec->size > key) ? rec->array[key] : 0; +} + +static int +SELinuxArraySet(SELinuxArrayRec *rec, unsigned key, void *val) +{ + if (key >= rec->size) { + /* Need to increase size of array */ + rec->array = realloc(rec->array, (key + 1) * sizeof(val)); + if (!rec->array) + return FALSE; + memset(rec->array + rec->size, 0, (key - rec->size + 1) * sizeof(val)); + rec->size = key + 1; + } + + rec->array[key] = val; + return TRUE; +} + +static void +SELinuxArrayFree(SELinuxArrayRec *rec, int free_elements) +{ + if (free_elements) { + unsigned i = rec->size; + while (i) + free(rec->array[--i]); + } + + free(rec->array); + rec->size = 0; + rec->array = NULL; +} + +/* + * Looks up a name in the selection or property mappings + */ +static int +SELinuxAtomToSIDLookup(Atom atom, SELinuxObjectRec *obj, int map, int polymap) +{ + const char *name = NameForAtom(atom); + security_context_t ctx; + int rc = Success; + + obj->poly = 1; + + /* Look in the mappings of names to contexts */ + if (selabel_lookup_raw(label_hnd, &ctx, name, map) == 0) { + obj->poly = 0; + } else if (errno != ENOENT) { + ErrorF("SELinux: a property label lookup failed!\n"); + return BadValue; + } else if (selabel_lookup_raw(label_hnd, &ctx, name, polymap) < 0) { + ErrorF("SELinux: a property label lookup failed!\n"); + return BadValue; + } + + /* Get a SID for context */ + if (avc_context_to_sid_raw(ctx, &obj->sid) < 0) { + ErrorF("SELinux: a context_to_SID_raw call failed!\n"); + rc = BadAlloc; + } + + freecon(ctx); + return rc; +} + +/* + * Looks up the SID corresponding to the given property or selection atom + */ +int +SELinuxAtomToSID(Atom atom, int prop, SELinuxObjectRec **obj_rtn) +{ + SELinuxAtomRec *rec; + SELinuxObjectRec *obj; + int rc, map, polymap; + + rec = SELinuxArrayGet(&arr_atoms, atom); + if (!rec) { + rec = calloc(1, sizeof(SELinuxAtomRec)); + if (!rec || !SELinuxArraySet(&arr_atoms, atom, rec)) + return BadAlloc; + } + + if (prop) { + obj = &rec->prp; + map = SELABEL_X_PROP; + polymap = SELABEL_X_POLYPROP; + } else { + obj = &rec->sel; + map = SELABEL_X_SELN; + polymap = SELABEL_X_POLYSELN; + } + + if (!obj->sid) { + rc = SELinuxAtomToSIDLookup(atom, obj, map, polymap); + if (rc != Success) + goto out; + } + + *obj_rtn = obj; + rc = Success; +out: + return rc; +} + +/* + * Looks up a SID for a selection/subject pair + */ +int +SELinuxSelectionToSID(Atom selection, SELinuxSubjectRec *subj, + security_id_t *sid_rtn, int *poly_rtn) +{ + int rc; + SELinuxObjectRec *obj; + security_id_t tsid; + + /* Get the default context and polyinstantiation bit */ + rc = SELinuxAtomToSID(selection, 0, &obj); + if (rc != Success) + return rc; + + /* Check for an override context next */ + if (subj->sel_use_sid) { + tsid = subj->sel_use_sid; + goto out; + } + + tsid = obj->sid; + + /* Polyinstantiate if necessary to obtain the final SID */ + if (obj->poly && avc_compute_member(subj->sid, obj->sid, + SECCLASS_X_SELECTION, &tsid) < 0) { + ErrorF("SELinux: a compute_member call failed!\n"); + return BadValue; + } +out: + *sid_rtn = tsid; + if (poly_rtn) + *poly_rtn = obj->poly; + return Success; +} + +/* + * Looks up a SID for a property/subject pair + */ +int +SELinuxPropertyToSID(Atom property, SELinuxSubjectRec *subj, + security_id_t *sid_rtn, int *poly_rtn) +{ + int rc; + SELinuxObjectRec *obj; + security_id_t tsid, tsid2; + + /* Get the default context and polyinstantiation bit */ + rc = SELinuxAtomToSID(property, 1, &obj); + if (rc != Success) + return rc; + + /* Check for an override context next */ + if (subj->prp_use_sid) { + tsid = subj->prp_use_sid; + goto out; + } + + /* Perform a transition */ + if (avc_compute_create(subj->sid, obj->sid, + SECCLASS_X_PROPERTY, &tsid) < 0) { + ErrorF("SELinux: a compute_create call failed!\n"); + return BadValue; + } + + /* Polyinstantiate if necessary to obtain the final SID */ + if (obj->poly) { + tsid2 = tsid; + if (avc_compute_member(subj->sid, tsid2, + SECCLASS_X_PROPERTY, &tsid) < 0) { + ErrorF("SELinux: a compute_member call failed!\n"); + return BadValue; + } + } +out: + *sid_rtn = tsid; + if (poly_rtn) + *poly_rtn = obj->poly; + return Success; +} + +/* + * Looks up the SID corresponding to the given event type + */ +int +SELinuxEventToSID(unsigned type, security_id_t sid_of_window, + SELinuxObjectRec *sid_return) +{ + const char *name = LookupEventName(type); + security_id_t sid; + security_context_t ctx; + type &= 127; + + sid = SELinuxArrayGet(&arr_events, type); + if (!sid) { + /* Look in the mappings of event names to contexts */ + if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EVENT) < 0) { + ErrorF("SELinux: an event label lookup failed!\n"); + return BadValue; + } + /* Get a SID for context */ + if (avc_context_to_sid_raw(ctx, &sid) < 0) { + ErrorF("SELinux: a context_to_SID_raw call failed!\n"); + freecon(ctx); + return BadAlloc; + } + freecon(ctx); + /* Cache the SID value */ + if (!SELinuxArraySet(&arr_events, type, sid)) + return BadAlloc; + } + + /* Perform a transition to obtain the final SID */ + if (avc_compute_create(sid_of_window, sid, SECCLASS_X_EVENT, + &sid_return->sid) < 0) { + ErrorF("SELinux: a compute_create call failed!\n"); + return BadValue; + } + + return Success; +} + +int +SELinuxExtensionToSID(const char *name, security_id_t *sid_rtn) +{ + security_context_t ctx; + + /* Look in the mappings of extension names to contexts */ + if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EXT) < 0) { + ErrorF("SELinux: a property label lookup failed!\n"); + return BadValue; + } + /* Get a SID for context */ + if (avc_context_to_sid_raw(ctx, sid_rtn) < 0) { + ErrorF("SELinux: a context_to_SID_raw call failed!\n"); + freecon(ctx); + return BadAlloc; + } + freecon(ctx); + return Success; +} + +/* + * Returns the object class corresponding to the given resource type. + */ +security_class_t +SELinuxTypeToClass(RESTYPE type) +{ + void *tmp; + + tmp = SELinuxArrayGet(&arr_types, type & TypeMask); + if (!tmp) { + unsigned long class = SECCLASS_X_RESOURCE; + + if (type & RC_DRAWABLE) + class = SECCLASS_X_DRAWABLE; + else if (type == RT_GC) + class = SECCLASS_X_GC; + else if (type == RT_FONT) + class = SECCLASS_X_FONT; + else if (type == RT_CURSOR) + class = SECCLASS_X_CURSOR; + else if (type == RT_COLORMAP) + class = SECCLASS_X_COLORMAP; + else { + /* Need to do a string lookup */ + const char *str = LookupResourceName(type); + if (!strcmp(str, "PICTURE")) + class = SECCLASS_X_DRAWABLE; + else if (!strcmp(str, "GLYPHSET")) + class = SECCLASS_X_FONT; + } + + tmp = (void *)class; + SELinuxArraySet(&arr_types, type & TypeMask, tmp); + } + + return (security_class_t)(unsigned long)tmp; +} + +security_context_t +SELinuxDefaultClientLabel(void) +{ + security_context_t ctx; + + if (selabel_lookup_raw(label_hnd, &ctx, "remote", SELABEL_X_CLIENT) < 0) + FatalError("SELinux: failed to look up remote-client context\n"); + + return ctx; +} + +void +SELinuxLabelInit(void) +{ + struct selinux_opt selabel_option = { SELABEL_OPT_VALIDATE, (char *)1 }; + + label_hnd = selabel_open(SELABEL_CTX_X, &selabel_option, 1); + if (!label_hnd) + FatalError("SELinux: Failed to open x_contexts mapping in policy\n"); +} + +void +SELinuxLabelReset(void) +{ + selabel_close(label_hnd); + label_hnd = NULL; + + /* Free local state */ + SELinuxArrayFree(&arr_types, 0); + SELinuxArrayFree(&arr_events, 0); + SELinuxArrayFree(&arr_atoms, 1); +} diff --git a/xorg-server/Xext/xselinuxint.h b/xorg-server/Xext/xselinuxint.h index 854a57dd7..f084b94b2 100644 --- a/xorg-server/Xext/xselinuxint.h +++ b/xorg-server/Xext/xselinuxint.h @@ -1,556 +1,558 @@ -/************************************************************ - -Author: Eamon Walsh - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -this permission notice appear in supporting documentation. 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 -AUTHOR 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 _XSELINUXINT_H -#define _XSELINUXINT_H - -#include -#include - -#include "globals.h" -#include "dixaccess.h" -#include "dixstruct.h" -#include "privates.h" -#include "resource.h" -#include "registry.h" -#include "inputstr.h" -#include "xselinux.h" - -/* - * Types - */ - -/* subject state (clients and devices only) */ -typedef struct { - security_id_t sid; - security_id_t dev_create_sid; - security_id_t win_create_sid; - security_id_t sel_create_sid; - security_id_t prp_create_sid; - security_id_t sel_use_sid; - security_id_t prp_use_sid; - struct avc_entry_ref aeref; - char *command; - int privileged; -} SELinuxSubjectRec; - -/* object state */ -typedef struct { - security_id_t sid; - int poly; -} SELinuxObjectRec; - -/* - * Globals - */ - -extern DevPrivateKey subjectKey; -extern DevPrivateKey objectKey; -extern DevPrivateKey dataKey; - -/* - * Label functions - */ - -int -SELinuxAtomToSID(Atom atom, int prop, SELinuxObjectRec **obj_rtn); - -int -SELinuxSelectionToSID(Atom selection, SELinuxSubjectRec *subj, - security_id_t *sid_rtn, int *poly_rtn); - -int -SELinuxPropertyToSID(Atom property, SELinuxSubjectRec *subj, - security_id_t *sid_rtn, int *poly_rtn); - -int -SELinuxEventToSID(unsigned type, security_id_t sid_of_window, - SELinuxObjectRec *sid_return); - -int -SELinuxExtensionToSID(const char *name, security_id_t *sid_rtn); - -security_class_t -SELinuxTypeToClass(RESTYPE type); - -security_context_t -SELinuxDefaultClientLabel(void); - -void -SELinuxLabelInit(void); - -void -SELinuxLabelReset(void); - -/* - * Security module functions - */ - -void -SELinuxFlaskInit(void); - -void -SELinuxFlaskReset(void); - - -/* - * Private Flask definitions - */ - -/* Security class constants */ -#define SECCLASS_X_DRAWABLE 1 -#define SECCLASS_X_SCREEN 2 -#define SECCLASS_X_GC 3 -#define SECCLASS_X_FONT 4 -#define SECCLASS_X_COLORMAP 5 -#define SECCLASS_X_PROPERTY 6 -#define SECCLASS_X_SELECTION 7 -#define SECCLASS_X_CURSOR 8 -#define SECCLASS_X_CLIENT 9 -#define SECCLASS_X_POINTER 10 -#define SECCLASS_X_KEYBOARD 11 -#define SECCLASS_X_SERVER 12 -#define SECCLASS_X_EXTENSION 13 -#define SECCLASS_X_EVENT 14 -#define SECCLASS_X_FAKEEVENT 15 -#define SECCLASS_X_RESOURCE 16 - -#ifdef _XSELINUX_NEED_FLASK_MAP -/* Mapping from DixAccess bits to Flask permissions */ -static struct security_class_mapping map[] = { - { "x_drawable", - { "read", /* DixReadAccess */ - "write", /* DixWriteAccess */ - "destroy", /* DixDestroyAccess */ - "create", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - "list_property", /* DixListPropAccess */ - "get_property", /* DixGetPropAccess */ - "set_property", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "list_child", /* DixListAccess */ - "add_child", /* DixAddAccess */ - "remove_child", /* DixRemoveAccess */ - "hide", /* DixHideAccess */ - "show", /* DixShowAccess */ - "blend", /* DixBlendAccess */ - "override", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "send", /* DixSendAccess */ - "receive", /* DixReceiveAccess */ - "", /* DixUseAccess */ - "manage", /* DixManageAccess */ - NULL }}, - { "x_screen", - { "", /* DixReadAccess */ - "", /* DixWriteAccess */ - "", /* DixDestroyAccess */ - "", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - "saver_getattr", /* DixListPropAccess */ - "saver_setattr", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "", /* DixAddAccess */ - "", /* DixRemoveAccess */ - "hide_cursor", /* DixHideAccess */ - "show_cursor", /* DixShowAccess */ - "saver_hide", /* DixBlendAccess */ - "saver_show", /* DixGrabAccess */ - NULL }}, - { "x_gc", - { "", /* DixReadAccess */ - "", /* DixWriteAccess */ - "destroy", /* DixDestroyAccess */ - "create", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "", /* DixAddAccess */ - "", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "", /* DixSendAccess */ - "", /* DixReceiveAccess */ - "use", /* DixUseAccess */ - NULL }}, - { "x_font", - { "", /* DixReadAccess */ - "", /* DixWriteAccess */ - "destroy", /* DixDestroyAccess */ - "create", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "add_glyph", /* DixAddAccess */ - "remove_glyph", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "", /* DixSendAccess */ - "", /* DixReceiveAccess */ - "use", /* DixUseAccess */ - NULL }}, - { "x_colormap", - { "read", /* DixReadAccess */ - "write", /* DixWriteAccess */ - "destroy", /* DixDestroyAccess */ - "create", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "add_color", /* DixAddAccess */ - "remove_color", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "install", /* DixInstallAccess */ - "uninstall", /* DixUninstallAccess */ - "", /* DixSendAccess */ - "", /* DixReceiveAccess */ - "use", /* DixUseAccess */ - NULL }}, - { "x_property", - { "read", /* DixReadAccess */ - "write", /* DixWriteAccess */ - "destroy", /* DixDestroyAccess */ - "create", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "", /* DixAddAccess */ - "", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "write", /* DixBlendAccess */ - NULL }}, - { "x_selection", - { "read", /* DixReadAccess */ - "", /* DixWriteAccess */ - "", /* DixDestroyAccess */ - "setattr", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - NULL }}, - { "x_cursor", - { "read", /* DixReadAccess */ - "write", /* DixWriteAccess */ - "destroy", /* DixDestroyAccess */ - "create", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "", /* DixAddAccess */ - "", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "", /* DixSendAccess */ - "", /* DixReceiveAccess */ - "use", /* DixUseAccess */ - NULL }}, - { "x_client", - { "", /* DixReadAccess */ - "", /* DixWriteAccess */ - "destroy", /* DixDestroyAccess */ - "", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "", /* DixAddAccess */ - "", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "", /* DixSendAccess */ - "", /* DixReceiveAccess */ - "", /* DixUseAccess */ - "manage", /* DixManageAccess */ - NULL }}, - { "x_pointer", - { "read", /* DixReadAccess */ - "write", /* DixWriteAccess */ - "destroy", /* DixDestroyAccess */ - "create", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - "list_property", /* DixListPropAccess */ - "get_property", /* DixGetPropAccess */ - "set_property", /* DixSetPropAccess */ - "getfocus", /* DixGetFocusAccess */ - "setfocus", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "add", /* DixAddAccess */ - "remove", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "grab", /* DixGrabAccess */ - "freeze", /* DixFreezeAccess */ - "force_cursor", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "", /* DixSendAccess */ - "", /* DixReceiveAccess */ - "use", /* DixUseAccess */ - "manage", /* DixManageAccess */ - "", /* DixDebugAccess */ - "bell", /* DixBellAccess */ - NULL }}, - { "x_keyboard", - { "read", /* DixReadAccess */ - "write", /* DixWriteAccess */ - "destroy", /* DixDestroyAccess */ - "create", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - "list_property", /* DixListPropAccess */ - "get_property", /* DixGetPropAccess */ - "set_property", /* DixSetPropAccess */ - "getfocus", /* DixGetFocusAccess */ - "setfocus", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "add", /* DixAddAccess */ - "remove", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "grab", /* DixGrabAccess */ - "freeze", /* DixFreezeAccess */ - "force_cursor", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "", /* DixSendAccess */ - "", /* DixReceiveAccess */ - "use", /* DixUseAccess */ - "manage", /* DixManageAccess */ - "", /* DixDebugAccess */ - "bell", /* DixBellAccess */ - NULL }}, - { "x_server", - { "record", /* DixReadAccess */ - "", /* DixWriteAccess */ - "", /* DixDestroyAccess */ - "", /* DixCreateAccess */ - "getattr", /* DixGetAttrAccess */ - "setattr", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "", /* DixAddAccess */ - "", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "grab", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "", /* DixSendAccess */ - "", /* DixReceiveAccess */ - "", /* DixUseAccess */ - "manage", /* DixManageAccess */ - "debug", /* DixDebugAccess */ - NULL }}, - { "x_extension", - { "", /* DixReadAccess */ - "", /* DixWriteAccess */ - "", /* DixDestroyAccess */ - "", /* DixCreateAccess */ - "query", /* DixGetAttrAccess */ - "", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "", /* DixAddAccess */ - "", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "", /* DixSendAccess */ - "", /* DixReceiveAccess */ - "use", /* DixUseAccess */ - NULL }}, - { "x_event", - { "", /* DixReadAccess */ - "", /* DixWriteAccess */ - "", /* DixDestroyAccess */ - "", /* DixCreateAccess */ - "", /* DixGetAttrAccess */ - "", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "", /* DixAddAccess */ - "", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "send", /* DixSendAccess */ - "receive", /* DixReceiveAccess */ - NULL }}, - { "x_synthetic_event", - { "", /* DixReadAccess */ - "", /* DixWriteAccess */ - "", /* DixDestroyAccess */ - "", /* DixCreateAccess */ - "", /* DixGetAttrAccess */ - "", /* DixSetAttrAccess */ - "", /* DixListPropAccess */ - "", /* DixGetPropAccess */ - "", /* DixSetPropAccess */ - "", /* DixGetFocusAccess */ - "", /* DixSetFocusAccess */ - "", /* DixListAccess */ - "", /* DixAddAccess */ - "", /* DixRemoveAccess */ - "", /* DixHideAccess */ - "", /* DixShowAccess */ - "", /* DixBlendAccess */ - "", /* DixGrabAccess */ - "", /* DixFreezeAccess */ - "", /* DixForceAccess */ - "", /* DixInstallAccess */ - "", /* DixUninstallAccess */ - "send", /* DixSendAccess */ - "receive", /* DixReceiveAccess */ - NULL }}, - { "x_resource", - { "read", /* DixReadAccess */ - "write", /* DixWriteAccess */ - "write", /* DixDestroyAccess */ - "write", /* DixCreateAccess */ - "read", /* DixGetAttrAccess */ - "write", /* DixSetAttrAccess */ - "read", /* DixListPropAccess */ - "read", /* DixGetPropAccess */ - "write", /* DixSetPropAccess */ - "read", /* DixGetFocusAccess */ - "write", /* DixSetFocusAccess */ - "read", /* DixListAccess */ - "write", /* DixAddAccess */ - "write", /* DixRemoveAccess */ - "write", /* DixHideAccess */ - "read", /* DixShowAccess */ - "read", /* DixBlendAccess */ - "write", /* DixGrabAccess */ - "write", /* DixFreezeAccess */ - "write", /* DixForceAccess */ - "write", /* DixInstallAccess */ - "write", /* DixUninstallAccess */ - "write", /* DixSendAccess */ - "read", /* DixReceiveAccess */ - "read", /* DixUseAccess */ - "write", /* DixManageAccess */ - "read", /* DixDebugAccess */ - "write", /* DixBellAccess */ - NULL }}, - { NULL } -}; - -/* x_resource "read" bits from the list above */ -#define SELinuxReadMask (DixReadAccess|DixGetAttrAccess|DixListPropAccess| \ - DixGetPropAccess|DixGetFocusAccess|DixListAccess| \ - DixShowAccess|DixBlendAccess|DixReceiveAccess| \ - DixUseAccess|DixDebugAccess) - -#endif /* _XSELINUX_NEED_FLASK_MAP */ -#endif /* _XSELINUXINT_H */ +/************************************************************ + +Author: Eamon Walsh + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +this permission notice appear in supporting documentation. 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 +AUTHOR 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 _XSELINUXINT_H +#define _XSELINUXINT_H + +#include +#include + +#include "globals.h" +#include "dixaccess.h" +#include "dixstruct.h" +#include "privates.h" +#include "resource.h" +#include "registry.h" +#include "inputstr.h" +#include "xselinux.h" + +/* + * Types + */ + +#define COMMAND_LEN 64 + +/* subject state (clients and devices only) */ +typedef struct { + security_id_t sid; + security_id_t dev_create_sid; + security_id_t win_create_sid; + security_id_t sel_create_sid; + security_id_t prp_create_sid; + security_id_t sel_use_sid; + security_id_t prp_use_sid; + struct avc_entry_ref aeref; + char command[COMMAND_LEN]; + int privileged; +} SELinuxSubjectRec; + +/* object state */ +typedef struct { + security_id_t sid; + int poly; +} SELinuxObjectRec; + +/* + * Globals + */ + +extern DevPrivateKey subjectKey; +extern DevPrivateKey objectKey; +extern DevPrivateKey dataKey; + +/* + * Label functions + */ + +int +SELinuxAtomToSID(Atom atom, int prop, SELinuxObjectRec **obj_rtn); + +int +SELinuxSelectionToSID(Atom selection, SELinuxSubjectRec *subj, + security_id_t *sid_rtn, int *poly_rtn); + +int +SELinuxPropertyToSID(Atom property, SELinuxSubjectRec *subj, + security_id_t *sid_rtn, int *poly_rtn); + +int +SELinuxEventToSID(unsigned type, security_id_t sid_of_window, + SELinuxObjectRec *sid_return); + +int +SELinuxExtensionToSID(const char *name, security_id_t *sid_rtn); + +security_class_t +SELinuxTypeToClass(RESTYPE type); + +security_context_t +SELinuxDefaultClientLabel(void); + +void +SELinuxLabelInit(void); + +void +SELinuxLabelReset(void); + +/* + * Security module functions + */ + +void +SELinuxFlaskInit(void); + +void +SELinuxFlaskReset(void); + + +/* + * Private Flask definitions + */ + +/* Security class constants */ +#define SECCLASS_X_DRAWABLE 1 +#define SECCLASS_X_SCREEN 2 +#define SECCLASS_X_GC 3 +#define SECCLASS_X_FONT 4 +#define SECCLASS_X_COLORMAP 5 +#define SECCLASS_X_PROPERTY 6 +#define SECCLASS_X_SELECTION 7 +#define SECCLASS_X_CURSOR 8 +#define SECCLASS_X_CLIENT 9 +#define SECCLASS_X_POINTER 10 +#define SECCLASS_X_KEYBOARD 11 +#define SECCLASS_X_SERVER 12 +#define SECCLASS_X_EXTENSION 13 +#define SECCLASS_X_EVENT 14 +#define SECCLASS_X_FAKEEVENT 15 +#define SECCLASS_X_RESOURCE 16 + +#ifdef _XSELINUX_NEED_FLASK_MAP +/* Mapping from DixAccess bits to Flask permissions */ +static struct security_class_mapping map[] = { + { "x_drawable", + { "read", /* DixReadAccess */ + "write", /* DixWriteAccess */ + "destroy", /* DixDestroyAccess */ + "create", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + "list_property", /* DixListPropAccess */ + "get_property", /* DixGetPropAccess */ + "set_property", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "list_child", /* DixListAccess */ + "add_child", /* DixAddAccess */ + "remove_child", /* DixRemoveAccess */ + "hide", /* DixHideAccess */ + "show", /* DixShowAccess */ + "blend", /* DixBlendAccess */ + "override", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "send", /* DixSendAccess */ + "receive", /* DixReceiveAccess */ + "", /* DixUseAccess */ + "manage", /* DixManageAccess */ + NULL }}, + { "x_screen", + { "", /* DixReadAccess */ + "", /* DixWriteAccess */ + "", /* DixDestroyAccess */ + "", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + "saver_getattr", /* DixListPropAccess */ + "saver_setattr", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "", /* DixAddAccess */ + "", /* DixRemoveAccess */ + "hide_cursor", /* DixHideAccess */ + "show_cursor", /* DixShowAccess */ + "saver_hide", /* DixBlendAccess */ + "saver_show", /* DixGrabAccess */ + NULL }}, + { "x_gc", + { "", /* DixReadAccess */ + "", /* DixWriteAccess */ + "destroy", /* DixDestroyAccess */ + "create", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "", /* DixAddAccess */ + "", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "", /* DixSendAccess */ + "", /* DixReceiveAccess */ + "use", /* DixUseAccess */ + NULL }}, + { "x_font", + { "", /* DixReadAccess */ + "", /* DixWriteAccess */ + "destroy", /* DixDestroyAccess */ + "create", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "add_glyph", /* DixAddAccess */ + "remove_glyph", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "", /* DixSendAccess */ + "", /* DixReceiveAccess */ + "use", /* DixUseAccess */ + NULL }}, + { "x_colormap", + { "read", /* DixReadAccess */ + "write", /* DixWriteAccess */ + "destroy", /* DixDestroyAccess */ + "create", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "add_color", /* DixAddAccess */ + "remove_color", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "install", /* DixInstallAccess */ + "uninstall", /* DixUninstallAccess */ + "", /* DixSendAccess */ + "", /* DixReceiveAccess */ + "use", /* DixUseAccess */ + NULL }}, + { "x_property", + { "read", /* DixReadAccess */ + "write", /* DixWriteAccess */ + "destroy", /* DixDestroyAccess */ + "create", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "", /* DixAddAccess */ + "", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "write", /* DixBlendAccess */ + NULL }}, + { "x_selection", + { "read", /* DixReadAccess */ + "", /* DixWriteAccess */ + "", /* DixDestroyAccess */ + "setattr", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + NULL }}, + { "x_cursor", + { "read", /* DixReadAccess */ + "write", /* DixWriteAccess */ + "destroy", /* DixDestroyAccess */ + "create", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "", /* DixAddAccess */ + "", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "", /* DixSendAccess */ + "", /* DixReceiveAccess */ + "use", /* DixUseAccess */ + NULL }}, + { "x_client", + { "", /* DixReadAccess */ + "", /* DixWriteAccess */ + "destroy", /* DixDestroyAccess */ + "", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "", /* DixAddAccess */ + "", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "", /* DixSendAccess */ + "", /* DixReceiveAccess */ + "", /* DixUseAccess */ + "manage", /* DixManageAccess */ + NULL }}, + { "x_pointer", + { "read", /* DixReadAccess */ + "write", /* DixWriteAccess */ + "destroy", /* DixDestroyAccess */ + "create", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + "list_property", /* DixListPropAccess */ + "get_property", /* DixGetPropAccess */ + "set_property", /* DixSetPropAccess */ + "getfocus", /* DixGetFocusAccess */ + "setfocus", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "add", /* DixAddAccess */ + "remove", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "grab", /* DixGrabAccess */ + "freeze", /* DixFreezeAccess */ + "force_cursor", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "", /* DixSendAccess */ + "", /* DixReceiveAccess */ + "use", /* DixUseAccess */ + "manage", /* DixManageAccess */ + "", /* DixDebugAccess */ + "bell", /* DixBellAccess */ + NULL }}, + { "x_keyboard", + { "read", /* DixReadAccess */ + "write", /* DixWriteAccess */ + "destroy", /* DixDestroyAccess */ + "create", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + "list_property", /* DixListPropAccess */ + "get_property", /* DixGetPropAccess */ + "set_property", /* DixSetPropAccess */ + "getfocus", /* DixGetFocusAccess */ + "setfocus", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "add", /* DixAddAccess */ + "remove", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "grab", /* DixGrabAccess */ + "freeze", /* DixFreezeAccess */ + "force_cursor", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "", /* DixSendAccess */ + "", /* DixReceiveAccess */ + "use", /* DixUseAccess */ + "manage", /* DixManageAccess */ + "", /* DixDebugAccess */ + "bell", /* DixBellAccess */ + NULL }}, + { "x_server", + { "record", /* DixReadAccess */ + "", /* DixWriteAccess */ + "", /* DixDestroyAccess */ + "", /* DixCreateAccess */ + "getattr", /* DixGetAttrAccess */ + "setattr", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "", /* DixAddAccess */ + "", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "grab", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "", /* DixSendAccess */ + "", /* DixReceiveAccess */ + "", /* DixUseAccess */ + "manage", /* DixManageAccess */ + "debug", /* DixDebugAccess */ + NULL }}, + { "x_extension", + { "", /* DixReadAccess */ + "", /* DixWriteAccess */ + "", /* DixDestroyAccess */ + "", /* DixCreateAccess */ + "query", /* DixGetAttrAccess */ + "", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "", /* DixAddAccess */ + "", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "", /* DixSendAccess */ + "", /* DixReceiveAccess */ + "use", /* DixUseAccess */ + NULL }}, + { "x_event", + { "", /* DixReadAccess */ + "", /* DixWriteAccess */ + "", /* DixDestroyAccess */ + "", /* DixCreateAccess */ + "", /* DixGetAttrAccess */ + "", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "", /* DixAddAccess */ + "", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "send", /* DixSendAccess */ + "receive", /* DixReceiveAccess */ + NULL }}, + { "x_synthetic_event", + { "", /* DixReadAccess */ + "", /* DixWriteAccess */ + "", /* DixDestroyAccess */ + "", /* DixCreateAccess */ + "", /* DixGetAttrAccess */ + "", /* DixSetAttrAccess */ + "", /* DixListPropAccess */ + "", /* DixGetPropAccess */ + "", /* DixSetPropAccess */ + "", /* DixGetFocusAccess */ + "", /* DixSetFocusAccess */ + "", /* DixListAccess */ + "", /* DixAddAccess */ + "", /* DixRemoveAccess */ + "", /* DixHideAccess */ + "", /* DixShowAccess */ + "", /* DixBlendAccess */ + "", /* DixGrabAccess */ + "", /* DixFreezeAccess */ + "", /* DixForceAccess */ + "", /* DixInstallAccess */ + "", /* DixUninstallAccess */ + "send", /* DixSendAccess */ + "receive", /* DixReceiveAccess */ + NULL }}, + { "x_resource", + { "read", /* DixReadAccess */ + "write", /* DixWriteAccess */ + "write", /* DixDestroyAccess */ + "write", /* DixCreateAccess */ + "read", /* DixGetAttrAccess */ + "write", /* DixSetAttrAccess */ + "read", /* DixListPropAccess */ + "read", /* DixGetPropAccess */ + "write", /* DixSetPropAccess */ + "read", /* DixGetFocusAccess */ + "write", /* DixSetFocusAccess */ + "read", /* DixListAccess */ + "write", /* DixAddAccess */ + "write", /* DixRemoveAccess */ + "write", /* DixHideAccess */ + "read", /* DixShowAccess */ + "read", /* DixBlendAccess */ + "write", /* DixGrabAccess */ + "write", /* DixFreezeAccess */ + "write", /* DixForceAccess */ + "write", /* DixInstallAccess */ + "write", /* DixUninstallAccess */ + "write", /* DixSendAccess */ + "read", /* DixReceiveAccess */ + "read", /* DixUseAccess */ + "write", /* DixManageAccess */ + "read", /* DixDebugAccess */ + "write", /* DixBellAccess */ + NULL }}, + { NULL } +}; + +/* x_resource "read" bits from the list above */ +#define SELinuxReadMask (DixReadAccess|DixGetAttrAccess|DixListPropAccess| \ + DixGetPropAccess|DixGetFocusAccess|DixListAccess| \ + DixShowAccess|DixBlendAccess|DixReceiveAccess| \ + DixUseAccess|DixDebugAccess) + +#endif /* _XSELINUX_NEED_FLASK_MAP */ +#endif /* _XSELINUXINT_H */ diff --git a/xorg-server/Xext/xtest.c b/xorg-server/Xext/xtest.c index 99b6711f2..05395a7c1 100644 --- a/xorg-server/Xext/xtest.c +++ b/xorg-server/Xext/xtest.c @@ -1,713 +1,713 @@ -/* - - 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 -#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" -#include "mi.h" -#include "xkbsrv.h" -#include "xkbstr.h" -#include -#include -#include -#include "exglobals.h" -#include "mipointer.h" -#include "xserver-properties.h" -#include "exevents.h" - -#include "modinit.h" - -extern int DeviceValuator; - -/* XTest events are sent during request processing and may be interruped by - * a SIGIO. We need a separate event list to avoid events overwriting each - * other's memory */ -static EventListPtr xtest_evlist; - -/* Used to store if a device is an XTest Virtual device */ -static int XTestDevicePrivateKeyIndex; -DevPrivateKey XTestDevicePrivateKey = &XTestDevicePrivateKeyIndex; - -/** - * xtestpointer - * is the virtual pointer for XTest. It is the first slave - * device of the VCP. - * xtestkeyboard - * is the virtual keyboard for XTest. It is the first slave - * device of the VCK - * - * Neither of these devices can be deleted. - */ -DeviceIntPtr xtestpointer, xtestkeyboard; - -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif - -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) -{ - AddExtension(XTestExtensionName, 0, 0, - ProcXTestDispatch, SProcXTestDispatch, - NULL, StandardMinorOpcode); - - xtest_evlist = InitEventList(GetMaximumEventsNum()); -} - -static int -ProcXTestGetVersion(ClientPtr client) -{ - xXTestGetVersionReply rep; - int n; - - 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, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xXTestGetVersionReply), (char *)&rep); - return(client->noClientException); -} - -static int -ProcXTestCompareCursor(ClientPtr client) -{ - REQUEST(xXTestCompareCursorReq); - xXTestCompareCursorReply rep; - WindowPtr pWin; - CursorPtr pCursor; - int n, rc; - DeviceIntPtr ptr = PickPointer(client); - - REQUEST_SIZE_MATCH(xXTestCompareCursorReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - if (stuff->cursor == None) - pCursor = NullCursor; - else if (stuff->cursor == XTestCurrentCursor) - pCursor = GetSpriteCursor(ptr); - else { - rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR, - client, DixReadAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return (rc == BadValue) ? BadCursor : rc; - } - } - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.same = (wCursor(pWin) == pCursor); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - } - WriteToClient(client, sizeof(xXTestCompareCursorReply), (char *)&rep); - return(client->noClientException); -} - -static int -ProcXTestFakeInput(ClientPtr client) -{ - REQUEST(xXTestFakeInputReq); - int nev, n, type, rc; - xEvent *ev; - DeviceIntPtr dev = NULL; - WindowPtr root; - Bool extension = FALSE; - deviceValuator *dv = NULL; - int valuators[MAX_VALUATORS] = {0}; - int numValuators = 0; - int firstValuator = 0; - int nevents = 0; - int i; - int base = 0; - int flags = 0; - int need_ptr_update = 1; - - 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 (type >= EXTENSION_EVENT_BASE) - { - extension = TRUE; - - /* check device */ - rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client, - DixWriteAccess); - if (rc != Success) - { - client->errorValue = stuff->deviceid & 0177; - return rc; - } - - /* check type */ - type -= DeviceValuator; - switch (type) { - case XI_DeviceKeyPress: - case XI_DeviceKeyRelease: - if (!dev->key) - { - client->errorValue = ev->u.u.type; - return BadValue; - } - break; - case XI_DeviceButtonPress: - case XI_DeviceButtonRelease: - if (!dev->button) - { - client->errorValue = ev->u.u.type; - return BadValue; - } - break; - case XI_DeviceMotionNotify: - if (!dev->valuator) - { - client->errorValue = ev->u.u.type; - return BadValue; - } - break; - case XI_ProximityIn: - case XI_ProximityOut: - if (!dev->proximity) - { - client->errorValue = ev->u.u.type; - return BadValue; - } - break; - default: - client->errorValue = ev->u.u.type; - return BadValue; - } - - /* check validity */ - if (nev == 1 && type == XI_DeviceMotionNotify) - return BadLength; /* DevMotion must be followed by DevValuator */ - - if (type == XI_DeviceMotionNotify) - { - firstValuator = ((deviceValuator *)(ev+1))->first_valuator; - if (firstValuator > dev->valuator->numAxes) - { - client->errorValue = ev->u.u.type; - return BadValue; - } - - if (ev->u.u.detail == xFalse) - flags |= POINTER_ABSOLUTE; - } else - { - firstValuator = 0; - flags |= POINTER_ABSOLUTE; - } - - if (nev > 1 && !dev->valuator) - { - client->errorValue = dv->first_valuator; - return BadValue; - } - - - /* check validity of valuator events */ - base = firstValuator; - for (n = 1; n < nev; n++) - { - dv = (deviceValuator *)(ev + n); - if (dv->type != DeviceValuator) - { - client->errorValue = dv->type; - return BadValue; - } - if (dv->first_valuator != base) - { - client->errorValue = dv->first_valuator; - return BadValue; - } - switch(dv->num_valuators) - { - case 6: valuators[base + 5] = dv->valuator5; - case 5: valuators[base + 4] = dv->valuator4; - case 4: valuators[base + 3] = dv->valuator3; - case 3: valuators[base + 2] = dv->valuator2; - case 2: valuators[base + 1] = dv->valuator1; - case 1: valuators[base] = dv->valuator0; - break; - default: - client->errorValue = dv->num_valuators; - return BadValue; - } - - base += dv->num_valuators; - numValuators += dv->num_valuators; - - if (firstValuator + numValuators > dev->valuator->numAxes) - { - client->errorValue = dv->num_valuators; - return BadValue; - } - } - type = type - XI_DeviceKeyPress + KeyPress; - - } else - { - if (nev != 1) - return BadLength; - switch (type) - { - case KeyPress: - case KeyRelease: - dev = PickKeyboard(client); - break; - case ButtonPress: - case ButtonRelease: - dev = PickPointer(client); - break; - case MotionNotify: - dev = PickPointer(client); - valuators[0] = ev->u.keyButtonPointer.rootX; - valuators[1] = ev->u.keyButtonPointer.rootY; - numValuators = 2; - firstValuator = 0; - if (ev->u.u.detail == xFalse) - flags = POINTER_ABSOLUTE | POINTER_SCREEN; - break; - default: - client->errorValue = ev->u.u.type; - return BadValue; - } - - dev = GetXTestDevice(dev); - } - - /* If the event has a time set, wait for it to pass */ - 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 (from the deprecated Multibuffer - * extension) 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, n); - } - ResetCurrentRequest (client); - client->sequence--; - return Success; - } - - switch (type) - { - case KeyPress: - case KeyRelease: - if (!dev->key) - return BadDevice; - - if (ev->u.u.detail < dev->key->xkbInfo->desc->min_key_code || - ev->u.u.detail > dev->key->xkbInfo->desc->max_key_code) - { - client->errorValue = ev->u.u.detail; - return BadValue; - } - - need_ptr_update = 0; - break; - case MotionNotify: - if (!dev->valuator) - return BadDevice; - - /* broken lib, XI events have root uninitialized */ - if (extension || ev->u.keyButtonPointer.root == None) - root = GetCurrentRootWindow(dev); - else - { - rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root, - client, DixGetAttrAccess); - if (rc != Success) - return rc; - if (root->parent) - { - client->errorValue = ev->u.keyButtonPointer.root; - return BadValue; - } - } - if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) - { - client->errorValue = ev->u.u.detail; - return BadValue; - } - - /* FIXME: Xinerama! */ - - break; - case ButtonPress: - case ButtonRelease: - if (!dev->button) - return BadDevice; - - 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) - dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); - - switch(type) { - case MotionNotify: - nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, - firstValuator, numValuators, valuators); - break; - case ButtonPress: - case ButtonRelease: - nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail, - flags, firstValuator, - numValuators, valuators); - break; - case KeyPress: - case KeyRelease: - nevents = GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail); - break; - } - - for (i = 0; i < nevents; i++) - mieqProcessDeviceEvent(dev, (InternalEvent*)(xtest_evlist+i)->event, NULL); - - if (need_ptr_update) - miPointerUpdateSprite(dev); - return client->noClientException; -} - -static int -ProcXTestGrabControl(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 (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(ClientPtr client) -{ - int n; - REQUEST(xXTestGetVersionReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXTestGetVersionReq); - swaps(&stuff->minorVersion, n); - return ProcXTestGetVersion(client); -} - -static int -SProcXTestCompareCursor(ClientPtr client) -{ - int n; - REQUEST(xXTestCompareCursorReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXTestCompareCursorReq); - swapl(&stuff->window, n); - swapl(&stuff->cursor, n); - return ProcXTestCompareCursor(client); -} - -static int -XTestSwapFakeInput(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(ClientPtr client) -{ - int n; - REQUEST(xReq); - - swaps(&stuff->length, n); - n = XTestSwapFakeInput(client, stuff); - if (n != Success) - return n; - return ProcXTestFakeInput(client); -} - -static int -SProcXTestGrabControl(ClientPtr client) -{ - int n; - REQUEST(xXTestGrabControlReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXTestGrabControlReq); - return ProcXTestGrabControl(client); -} - -static int -SProcXTestDispatch (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; - } -} - -/** - * Allocate an virtual slave device for xtest events, this - * is a slave device to inputInfo master devices - */ -void InitXTestDevices(void) -{ - if(AllocXTestDevice(serverClient, "Virtual core", - &xtestpointer, &xtestkeyboard, - inputInfo.pointer, inputInfo.keyboard) != Success) - FatalError("Failed to allocate XTest devices"); - - if (ActivateDevice(xtestpointer, TRUE) != Success || - ActivateDevice(xtestkeyboard, TRUE) != Success) - FatalError("Failed to activate XTest core devices."); - if (!EnableDevice(xtestpointer, TRUE) || - !EnableDevice(xtestkeyboard, TRUE)) - FatalError("Failed to enable XTest core devices."); - - AttachDevice(NULL, xtestpointer, inputInfo.pointer); - AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard); -} - -/** - * Don't allow changing the XTest property. - */ -static int -DeviceSetXTestProperty(DeviceIntPtr dev, Atom property, - XIPropertyValuePtr prop, BOOL checkonly) -{ - if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE)) - return BadAccess; - - return Success; -} - -/** - * Allocate a device pair that is initialised as a slave - * device with properties that identify the devices as belonging - * to XTest subsystem. - * This only creates the pair, Activate/Enable Device - * still need to be called. - */ -int AllocXTestDevice (ClientPtr client, char* name, - DeviceIntPtr* ptr, DeviceIntPtr* keybd, - DeviceIntPtr master_ptr, DeviceIntPtr master_keybd) -{ - int retval; - int len = strlen(name); - char *xtestname = xcalloc(len + 7, 1 ); - char dummy = 1; - - strncpy( xtestname, name, len); - strncat( xtestname, " XTEST", 6 ); - - retval = AllocDevicePair( client, xtestname, ptr, keybd, CorePointerProc, CoreKeyboardProc, FALSE); - if ( retval == Success ){ - dixSetPrivate(&((*ptr)->devPrivates), XTestDevicePrivateKey, (void *)(intptr_t)master_ptr->id); - dixSetPrivate(&((*keybd)->devPrivates), XTestDevicePrivateKey, (void *)(intptr_t)master_keybd->id); - - XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), - XA_INTEGER, 8, PropModeReplace, 1, &dummy, - FALSE); - XISetDevicePropertyDeletable(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), FALSE); - XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL); - XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), - XA_INTEGER, 8, PropModeReplace, 1, &dummy, - FALSE); - XISetDevicePropertyDeletable(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), FALSE); - XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL); - } - - xfree( xtestname ); - - return retval; -} - -/** - * If master is NULL, return TRUE if the given device is an xtest device or - * FALSE otherwise. - * If master is not NULL, return TRUE if the given device is this master's - * xtest device. - */ -BOOL -IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master) -{ - int is_XTest = FALSE; - int mid; - void *tmp; /* shut up, gcc! */ - - if (IsMaster(dev)) - return is_XTest; - - tmp = dixLookupPrivate(&dev->devPrivates, XTestDevicePrivateKey); - mid = (intptr_t)tmp; - - /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest - * device */ - if ((!master && mid) || - (master && mid == master->id)) - is_XTest = TRUE; - - return is_XTest; -} - -/** - * @return The X Test virtual device for the given master. - */ -DeviceIntPtr -GetXTestDevice(DeviceIntPtr master) -{ - DeviceIntPtr it; - - for (it = inputInfo.devices; it; it = it->next) - { - if (IsXTestDevice(it, master)) - return it; - } - - /* This only happens if master is a slave device. don't do that */ - return NULL; -} - +/* + + 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 +#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" +#include "mi.h" +#include "xkbsrv.h" +#include "xkbstr.h" +#include +#include +#include +#include "exglobals.h" +#include "mipointer.h" +#include "xserver-properties.h" +#include "exevents.h" + +#include "modinit.h" + +extern int DeviceValuator; + +/* XTest events are sent during request processing and may be interruped by + * a SIGIO. We need a separate event list to avoid events overwriting each + * other's memory */ +static EventListPtr xtest_evlist; + +/* Used to store if a device is an XTest Virtual device */ +static int XTestDevicePrivateKeyIndex; +DevPrivateKey XTestDevicePrivateKey = &XTestDevicePrivateKeyIndex; + +/** + * xtestpointer + * is the virtual pointer for XTest. It is the first slave + * device of the VCP. + * xtestkeyboard + * is the virtual keyboard for XTest. It is the first slave + * device of the VCK + * + * Neither of these devices can be deleted. + */ +DeviceIntPtr xtestpointer, xtestkeyboard; + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +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) +{ + AddExtension(XTestExtensionName, 0, 0, + ProcXTestDispatch, SProcXTestDispatch, + NULL, StandardMinorOpcode); + + xtest_evlist = InitEventList(GetMaximumEventsNum()); +} + +static int +ProcXTestGetVersion(ClientPtr client) +{ + xXTestGetVersionReply rep; + int n; + + 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, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xXTestGetVersionReply), (char *)&rep); + return Success; +} + +static int +ProcXTestCompareCursor(ClientPtr client) +{ + REQUEST(xXTestCompareCursorReq); + xXTestCompareCursorReply rep; + WindowPtr pWin; + CursorPtr pCursor; + int n, rc; + DeviceIntPtr ptr = PickPointer(client); + + REQUEST_SIZE_MATCH(xXTestCompareCursorReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + if (stuff->cursor == None) + pCursor = NullCursor; + else if (stuff->cursor == XTestCurrentCursor) + pCursor = GetSpriteCursor(ptr); + else { + rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR, + client, DixReadAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return (rc == BadValue) ? BadCursor : rc; + } + } + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.same = (wCursor(pWin) == pCursor); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + } + WriteToClient(client, sizeof(xXTestCompareCursorReply), (char *)&rep); + return Success; +} + +static int +ProcXTestFakeInput(ClientPtr client) +{ + REQUEST(xXTestFakeInputReq); + int nev, n, type, rc; + xEvent *ev; + DeviceIntPtr dev = NULL; + WindowPtr root; + Bool extension = FALSE; + deviceValuator *dv = NULL; + int valuators[MAX_VALUATORS] = {0}; + int numValuators = 0; + int firstValuator = 0; + int nevents = 0; + int i; + int base = 0; + int flags = 0; + int need_ptr_update = 1; + + 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 (type >= EXTENSION_EVENT_BASE) + { + extension = TRUE; + + /* check device */ + rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client, + DixWriteAccess); + if (rc != Success) + { + client->errorValue = stuff->deviceid & 0177; + return rc; + } + + /* check type */ + type -= DeviceValuator; + switch (type) { + case XI_DeviceKeyPress: + case XI_DeviceKeyRelease: + if (!dev->key) + { + client->errorValue = ev->u.u.type; + return BadValue; + } + break; + case XI_DeviceButtonPress: + case XI_DeviceButtonRelease: + if (!dev->button) + { + client->errorValue = ev->u.u.type; + return BadValue; + } + break; + case XI_DeviceMotionNotify: + if (!dev->valuator) + { + client->errorValue = ev->u.u.type; + return BadValue; + } + break; + case XI_ProximityIn: + case XI_ProximityOut: + if (!dev->proximity) + { + client->errorValue = ev->u.u.type; + return BadValue; + } + break; + default: + client->errorValue = ev->u.u.type; + return BadValue; + } + + /* check validity */ + if (nev == 1 && type == XI_DeviceMotionNotify) + return BadLength; /* DevMotion must be followed by DevValuator */ + + if (type == XI_DeviceMotionNotify) + { + firstValuator = ((deviceValuator *)(ev+1))->first_valuator; + if (firstValuator > dev->valuator->numAxes) + { + client->errorValue = ev->u.u.type; + return BadValue; + } + + if (ev->u.u.detail == xFalse) + flags |= POINTER_ABSOLUTE; + } else + { + firstValuator = 0; + flags |= POINTER_ABSOLUTE; + } + + if (nev > 1 && !dev->valuator) + { + client->errorValue = dv->first_valuator; + return BadValue; + } + + + /* check validity of valuator events */ + base = firstValuator; + for (n = 1; n < nev; n++) + { + dv = (deviceValuator *)(ev + n); + if (dv->type != DeviceValuator) + { + client->errorValue = dv->type; + return BadValue; + } + if (dv->first_valuator != base) + { + client->errorValue = dv->first_valuator; + return BadValue; + } + switch(dv->num_valuators) + { + case 6: valuators[base + 5] = dv->valuator5; + case 5: valuators[base + 4] = dv->valuator4; + case 4: valuators[base + 3] = dv->valuator3; + case 3: valuators[base + 2] = dv->valuator2; + case 2: valuators[base + 1] = dv->valuator1; + case 1: valuators[base] = dv->valuator0; + break; + default: + client->errorValue = dv->num_valuators; + return BadValue; + } + + base += dv->num_valuators; + numValuators += dv->num_valuators; + + if (firstValuator + numValuators > dev->valuator->numAxes) + { + client->errorValue = dv->num_valuators; + return BadValue; + } + } + type = type - XI_DeviceKeyPress + KeyPress; + + } else + { + if (nev != 1) + return BadLength; + switch (type) + { + case KeyPress: + case KeyRelease: + dev = PickKeyboard(client); + break; + case ButtonPress: + case ButtonRelease: + dev = PickPointer(client); + break; + case MotionNotify: + dev = PickPointer(client); + valuators[0] = ev->u.keyButtonPointer.rootX; + valuators[1] = ev->u.keyButtonPointer.rootY; + numValuators = 2; + firstValuator = 0; + if (ev->u.u.detail == xFalse) + flags = POINTER_ABSOLUTE | POINTER_SCREEN; + break; + default: + client->errorValue = ev->u.u.type; + return BadValue; + } + + dev = GetXTestDevice(dev); + } + + /* If the event has a time set, wait for it to pass */ + 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 (from the deprecated Multibuffer + * extension) 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, n); + } + ResetCurrentRequest (client); + client->sequence--; + return Success; + } + + switch (type) + { + case KeyPress: + case KeyRelease: + if (!dev->key) + return BadDevice; + + if (ev->u.u.detail < dev->key->xkbInfo->desc->min_key_code || + ev->u.u.detail > dev->key->xkbInfo->desc->max_key_code) + { + client->errorValue = ev->u.u.detail; + return BadValue; + } + + need_ptr_update = 0; + break; + case MotionNotify: + if (!dev->valuator) + return BadDevice; + + /* broken lib, XI events have root uninitialized */ + if (extension || ev->u.keyButtonPointer.root == None) + root = GetCurrentRootWindow(dev); + else + { + rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root, + client, DixGetAttrAccess); + if (rc != Success) + return rc; + if (root->parent) + { + client->errorValue = ev->u.keyButtonPointer.root; + return BadValue; + } + } + if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) + { + client->errorValue = ev->u.u.detail; + return BadValue; + } + + /* FIXME: Xinerama! */ + + break; + case ButtonPress: + case ButtonRelease: + if (!dev->button) + return BadDevice; + + 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) + dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); + + switch(type) { + case MotionNotify: + nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, + firstValuator, numValuators, valuators); + break; + case ButtonPress: + case ButtonRelease: + nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail, + flags, firstValuator, + numValuators, valuators); + break; + case KeyPress: + case KeyRelease: + nevents = GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail); + break; + } + + for (i = 0; i < nevents; i++) + mieqProcessDeviceEvent(dev, (InternalEvent*)(xtest_evlist+i)->event, NULL); + + if (need_ptr_update) + miPointerUpdateSprite(dev); + return Success; +} + +static int +ProcXTestGrabControl(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 Success; +} + +static int +ProcXTestDispatch (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(ClientPtr client) +{ + int n; + REQUEST(xXTestGetVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXTestGetVersionReq); + swaps(&stuff->minorVersion, n); + return ProcXTestGetVersion(client); +} + +static int +SProcXTestCompareCursor(ClientPtr client) +{ + int n; + REQUEST(xXTestCompareCursorReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXTestCompareCursorReq); + swapl(&stuff->window, n); + swapl(&stuff->cursor, n); + return ProcXTestCompareCursor(client); +} + +static int +XTestSwapFakeInput(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(ClientPtr client) +{ + int n; + REQUEST(xReq); + + swaps(&stuff->length, n); + n = XTestSwapFakeInput(client, stuff); + if (n != Success) + return n; + return ProcXTestFakeInput(client); +} + +static int +SProcXTestGrabControl(ClientPtr client) +{ + int n; + REQUEST(xXTestGrabControlReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXTestGrabControlReq); + return ProcXTestGrabControl(client); +} + +static int +SProcXTestDispatch (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; + } +} + +/** + * Allocate an virtual slave device for xtest events, this + * is a slave device to inputInfo master devices + */ +void InitXTestDevices(void) +{ + if(AllocXTestDevice(serverClient, "Virtual core", + &xtestpointer, &xtestkeyboard, + inputInfo.pointer, inputInfo.keyboard) != Success) + FatalError("Failed to allocate XTest devices"); + + if (ActivateDevice(xtestpointer, TRUE) != Success || + ActivateDevice(xtestkeyboard, TRUE) != Success) + FatalError("Failed to activate XTest core devices."); + if (!EnableDevice(xtestpointer, TRUE) || + !EnableDevice(xtestkeyboard, TRUE)) + FatalError("Failed to enable XTest core devices."); + + AttachDevice(NULL, xtestpointer, inputInfo.pointer); + AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard); +} + +/** + * Don't allow changing the XTest property. + */ +static int +DeviceSetXTestProperty(DeviceIntPtr dev, Atom property, + XIPropertyValuePtr prop, BOOL checkonly) +{ + if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE)) + return BadAccess; + + return Success; +} + +/** + * Allocate a device pair that is initialised as a slave + * device with properties that identify the devices as belonging + * to XTest subsystem. + * This only creates the pair, Activate/Enable Device + * still need to be called. + */ +int AllocXTestDevice (ClientPtr client, char* name, + DeviceIntPtr* ptr, DeviceIntPtr* keybd, + DeviceIntPtr master_ptr, DeviceIntPtr master_keybd) +{ + int retval; + int len = strlen(name); + char *xtestname = calloc(len + 7, 1 ); + char dummy = 1; + + strncpy( xtestname, name, len); + strncat( xtestname, " XTEST", 6 ); + + retval = AllocDevicePair( client, xtestname, ptr, keybd, CorePointerProc, CoreKeyboardProc, FALSE); + if ( retval == Success ){ + dixSetPrivate(&((*ptr)->devPrivates), XTestDevicePrivateKey, (void *)(intptr_t)master_ptr->id); + dixSetPrivate(&((*keybd)->devPrivates), XTestDevicePrivateKey, (void *)(intptr_t)master_keybd->id); + + XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), + XA_INTEGER, 8, PropModeReplace, 1, &dummy, + FALSE); + XISetDevicePropertyDeletable(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), FALSE); + XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL); + XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), + XA_INTEGER, 8, PropModeReplace, 1, &dummy, + FALSE); + XISetDevicePropertyDeletable(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), FALSE); + XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL); + } + + free( xtestname ); + + return retval; +} + +/** + * If master is NULL, return TRUE if the given device is an xtest device or + * FALSE otherwise. + * If master is not NULL, return TRUE if the given device is this master's + * xtest device. + */ +BOOL +IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master) +{ + int is_XTest = FALSE; + int mid; + void *tmp; /* shut up, gcc! */ + + if (IsMaster(dev)) + return is_XTest; + + tmp = dixLookupPrivate(&dev->devPrivates, XTestDevicePrivateKey); + mid = (intptr_t)tmp; + + /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest + * device */ + if ((!master && mid) || + (master && mid == master->id)) + is_XTest = TRUE; + + return is_XTest; +} + +/** + * @return The X Test virtual device for the given master. + */ +DeviceIntPtr +GetXTestDevice(DeviceIntPtr master) +{ + DeviceIntPtr it; + + for (it = inputInfo.devices; it; it = it->next) + { + if (IsXTestDevice(it, master)) + return it; + } + + /* This only happens if master is a slave device. don't do that */ + return NULL; +} + diff --git a/xorg-server/Xext/xvdisp.c b/xorg-server/Xext/xvdisp.c index 4345672ab..34ea61ad3 100644 --- a/xorg-server/Xext/xvdisp.c +++ b/xorg-server/Xext/xvdisp.c @@ -1,1962 +1,1962 @@ -/*********************************************************** -Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts, -and the Massachusetts Institute of Technology, Cambridge, 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 names of Digital or MIT 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 "scrnintstr.h" -#include "windowstr.h" -#include "pixmapstr.h" -#include "gcstruct.h" -#include "dixstruct.h" -#include "resource.h" -#include "opaque.h" - -#include -#include -#include "xvdix.h" -#ifdef MITSHM -#include -#endif - -#include "xvdisp.h" - -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" - -unsigned long XvXRTPort; -#endif - -static int -SWriteQueryExtensionReply( - ClientPtr client, - xvQueryExtensionReply *rep -){ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->version, n); - swaps(&rep->revision, n); - - (void)WriteToClient(client, sz_xvQueryExtensionReply, (char *)rep); - - return Success; -} - -static int -SWriteQueryAdaptorsReply( - ClientPtr client, - xvQueryAdaptorsReply *rep -){ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->num_adaptors, n); - - (void)WriteToClient(client, sz_xvQueryAdaptorsReply, (char *)rep); - - return Success; -} - -static int -SWriteQueryEncodingsReply( - ClientPtr client, - xvQueryEncodingsReply *rep -){ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->num_encodings, n); - - (void)WriteToClient(client, sz_xvQueryEncodingsReply, (char *)rep); - - return Success; -} - -static int -SWriteAdaptorInfo( - ClientPtr client, - xvAdaptorInfo *pAdaptor -){ - char n; - - swapl(&pAdaptor->base_id, n); - swaps(&pAdaptor->name_size, n); - swaps(&pAdaptor->num_ports, n); - swaps(&pAdaptor->num_formats, n); - - (void)WriteToClient(client, sz_xvAdaptorInfo, (char *)pAdaptor); - - return Success; -} - -static int -SWriteEncodingInfo( - ClientPtr client, - xvEncodingInfo *pEncoding -){ - char n; - - swapl(&pEncoding->encoding, n); - swaps(&pEncoding->name_size, n); - swaps(&pEncoding->width, n); - swaps(&pEncoding->height, n); - swapl(&pEncoding->rate.numerator, n); - swapl(&pEncoding->rate.denominator, n); - (void)WriteToClient(client, sz_xvEncodingInfo, (char *)pEncoding); - - return Success; -} - -static int -SWriteFormat( - ClientPtr client, - xvFormat *pFormat -){ - char n; - - swapl(&pFormat->visual, n); - (void)WriteToClient(client, sz_xvFormat, (char *)pFormat); - - return Success; -} - -static int -SWriteAttributeInfo( - ClientPtr client, - xvAttributeInfo *pAtt -){ - char n; - - swapl(&pAtt->flags, n); - swapl(&pAtt->size, n); - swapl(&pAtt->min, n); - swapl(&pAtt->max, n); - (void)WriteToClient(client, sz_xvAttributeInfo, (char *)pAtt); - - return Success; -} - -static int -SWriteImageFormatInfo( - ClientPtr client, - xvImageFormatInfo *pImage -){ - char n; - - swapl(&pImage->id, n); - swapl(&pImage->red_mask, n); - swapl(&pImage->green_mask, n); - swapl(&pImage->blue_mask, n); - swapl(&pImage->y_sample_bits, n); - swapl(&pImage->u_sample_bits, n); - swapl(&pImage->v_sample_bits, n); - swapl(&pImage->horz_y_period, n); - swapl(&pImage->horz_u_period, n); - swapl(&pImage->horz_v_period, n); - swapl(&pImage->vert_y_period, n); - swapl(&pImage->vert_u_period, n); - swapl(&pImage->vert_v_period, n); - - (void)WriteToClient(client, sz_xvImageFormatInfo, (char *)pImage); - - return Success; -} - -static int -SWriteGrabPortReply( - ClientPtr client, - xvGrabPortReply *rep -){ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - - (void)WriteToClient(client, sz_xvGrabPortReply, (char *)rep); - - return Success; -} - -static int -SWriteGetPortAttributeReply( - ClientPtr client, - xvGetPortAttributeReply *rep -){ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swapl(&rep->value, n); - - (void)WriteToClient(client, sz_xvGetPortAttributeReply, (char *)rep); - - return Success; -} - -static int -SWriteQueryBestSizeReply( - ClientPtr client, - xvQueryBestSizeReply *rep -){ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->actual_width, n); - swaps(&rep->actual_height, n); - - (void)WriteToClient(client, sz_xvQueryBestSizeReply, (char *)rep); - - return Success; -} - -static int -SWriteQueryPortAttributesReply( - ClientPtr client, - xvQueryPortAttributesReply *rep -){ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swapl(&rep->num_attributes, n); - swapl(&rep->text_size, n); - - (void)WriteToClient(client, sz_xvQueryPortAttributesReply, (char *)rep); - - return Success; -} - -static int -SWriteQueryImageAttributesReply( - ClientPtr client, - xvQueryImageAttributesReply *rep -){ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swapl(&rep->num_planes, n); - swapl(&rep->data_size, n); - swaps(&rep->width, n); - swaps(&rep->height, n); - - (void)WriteToClient(client, sz_xvQueryImageAttributesReply, (char *)rep); - - return Success; -} - -static int -SWriteListImageFormatsReply( - ClientPtr client, - xvListImageFormatsReply *rep -){ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swapl(&rep->num_formats, n); - - (void)WriteToClient(client, sz_xvListImageFormatsReply, (char *)rep); - - return Success; -} - -#define _WriteQueryAdaptorsReply(_c,_d) \ - if ((_c)->swapped) SWriteQueryAdaptorsReply(_c, _d); \ - else WriteToClient(_c, sz_xvQueryAdaptorsReply, (char*)_d) - -#define _WriteQueryExtensionReply(_c,_d) \ - if ((_c)->swapped) SWriteQueryExtensionReply(_c, _d); \ - else WriteToClient(_c, sz_xvQueryExtensionReply, (char*)_d) - -#define _WriteQueryEncodingsReply(_c,_d) \ - if ((_c)->swapped) SWriteQueryEncodingsReply(_c, _d); \ - else WriteToClient(_c, sz_xvQueryEncodingsReply, (char*)_d) - -#define _WriteAdaptorInfo(_c,_d) \ - if ((_c)->swapped) SWriteAdaptorInfo(_c, _d); \ - else WriteToClient(_c, sz_xvAdaptorInfo, (char*)_d) - -#define _WriteAttributeInfo(_c,_d) \ - if ((_c)->swapped) SWriteAttributeInfo(_c, _d); \ - else WriteToClient(_c, sz_xvAttributeInfo, (char*)_d) - -#define _WriteEncodingInfo(_c,_d) \ - if ((_c)->swapped) SWriteEncodingInfo(_c, _d); \ - else WriteToClient(_c, sz_xvEncodingInfo, (char*)_d) - -#define _WriteFormat(_c,_d) \ - if ((_c)->swapped) SWriteFormat(_c, _d); \ - else WriteToClient(_c, sz_xvFormat, (char*)_d) - -#define _WriteGrabPortReply(_c,_d) \ - if ((_c)->swapped) SWriteGrabPortReply(_c, _d); \ - else WriteToClient(_c, sz_xvGrabPortReply, (char*)_d) - -#define _WriteGetPortAttributeReply(_c,_d) \ - if ((_c)->swapped) SWriteGetPortAttributeReply(_c, _d); \ - else WriteToClient(_c, sz_xvGetPortAttributeReply, (char*)_d) - -#define _WriteQueryBestSizeReply(_c,_d) \ - if ((_c)->swapped) SWriteQueryBestSizeReply(_c, _d); \ - else WriteToClient(_c, sz_xvQueryBestSizeReply,(char*) _d) - -#define _WriteQueryPortAttributesReply(_c,_d) \ - if ((_c)->swapped) SWriteQueryPortAttributesReply(_c, _d); \ - else WriteToClient(_c, sz_xvQueryPortAttributesReply,(char*) _d) - -#define _WriteQueryImageAttributesReply(_c,_d) \ - if ((_c)->swapped) SWriteQueryImageAttributesReply(_c, _d); \ - else WriteToClient(_c, sz_xvQueryImageAttributesReply,(char*) _d) - -#define _WriteListImageFormatsReply(_c,_d) \ - if ((_c)->swapped) SWriteListImageFormatsReply(_c, _d); \ - else WriteToClient(_c, sz_xvListImageFormatsReply,(char*) _d) - -#define _WriteImageFormatInfo(_c,_d) \ - if ((_c)->swapped) SWriteImageFormatInfo(_c, _d); \ - else WriteToClient(_c, sz_xvImageFormatInfo, (char*)_d) - -#define _AllocatePort(_i,_p) \ - ((_p)->id != _i) ? (* (_p)->pAdaptor->ddAllocatePort)(_i,_p,&_p) : Success - -static int -ProcXvQueryExtension(ClientPtr client) -{ - xvQueryExtensionReply rep; - /* REQUEST(xvQueryExtensionReq); */ - REQUEST_SIZE_MATCH(xvQueryExtensionReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.version = XvVersion; - rep.revision = XvRevision; - - _WriteQueryExtensionReply(client, &rep); - - return Success; -} - -static int -ProcXvQueryAdaptors(ClientPtr client) -{ - xvFormat format; - xvAdaptorInfo ainfo; - xvQueryAdaptorsReply rep; - int totalSize, na, nf, rc; - int nameSize; - XvAdaptorPtr pa; - XvFormatPtr pf; - WindowPtr pWin; - ScreenPtr pScreen; - XvScreenPtr pxvs; - - REQUEST(xvQueryAdaptorsReq); - REQUEST_SIZE_MATCH(xvQueryAdaptorsReq); - - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - pScreen = pWin->drawable.pScreen; - pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - XvGetScreenKey()); - if (!pxvs) - { - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.num_adaptors = 0; - rep.length = 0; - - _WriteQueryAdaptorsReply(client, &rep); - - return Success; - } - - (* pxvs->ddQueryAdaptors)(pScreen, &pxvs->pAdaptors, &pxvs->nAdaptors); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.num_adaptors = pxvs->nAdaptors; - - /* CALCULATE THE TOTAL SIZE OF THE REPLY IN BYTES */ - - totalSize = pxvs->nAdaptors * sz_xvAdaptorInfo; - - /* FOR EACH ADPATOR ADD UP THE BYTES FOR ENCODINGS AND FORMATS */ - - na = pxvs->nAdaptors; - pa = pxvs->pAdaptors; - while (na--) - { - totalSize += pad_to_int32(strlen(pa->name)); - totalSize += pa->nFormats * sz_xvFormat; - pa++; - } - - rep.length = bytes_to_int32(totalSize); - - _WriteQueryAdaptorsReply(client, &rep); - - na = pxvs->nAdaptors; - pa = pxvs->pAdaptors; - while (na--) - { - - ainfo.base_id = pa->base_id; - ainfo.num_ports = pa->nPorts; - ainfo.type = pa->type; - ainfo.name_size = nameSize = strlen(pa->name); - ainfo.num_formats = pa->nFormats; - - _WriteAdaptorInfo(client, &ainfo); - - WriteToClient(client, nameSize, pa->name); - - nf = pa->nFormats; - pf = pa->pFormats; - while (nf--) - { - format.depth = pf->depth; - format.visual = pf->visual; - _WriteFormat(client, &format); - pf++; - } - - pa++; - - } - - return (client->noClientException); -} - -static int -ProcXvQueryEncodings(ClientPtr client) -{ - xvEncodingInfo einfo; - xvQueryEncodingsReply rep; - int totalSize; - int nameSize; - XvPortPtr pPort; - int ne; - XvEncodingPtr pe; - int status; - - REQUEST(xvQueryEncodingsReq); - REQUEST_SIZE_MATCH(xvQueryEncodingsReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.num_encodings = pPort->pAdaptor->nEncodings; - - /* FOR EACH ENCODING ADD UP THE BYTES FOR ENCODING NAMES */ - - ne = pPort->pAdaptor->nEncodings; - pe = pPort->pAdaptor->pEncodings; - totalSize = ne * sz_xvEncodingInfo; - while (ne--) - { - totalSize += pad_to_int32(strlen(pe->name)); - pe++; - } - - rep.length = bytes_to_int32(totalSize); - - _WriteQueryEncodingsReply(client, &rep); - - ne = pPort->pAdaptor->nEncodings; - pe = pPort->pAdaptor->pEncodings; - while (ne--) - { - einfo.encoding = pe->id; - einfo.name_size = nameSize = strlen(pe->name); - einfo.width = pe->width; - einfo.height = pe->height; - einfo.rate.numerator = pe->rate.numerator; - einfo.rate.denominator = pe->rate.denominator; - _WriteEncodingInfo(client, &einfo); - WriteToClient(client, nameSize, pe->name); - pe++; - } - - return (client->noClientException); -} - -static int -ProcXvPutVideo(ClientPtr client) -{ - DrawablePtr pDraw; - XvPortPtr pPort; - GCPtr pGC; - int status; - - REQUEST(xvPutVideoReq); - REQUEST_SIZE_MATCH(xvPutVideoReq); - - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - if (!(pPort->pAdaptor->type & XvInputMask) || - !(pPort->pAdaptor->type & XvVideoMask)) - { - client->errorValue = stuff->port; - return (BadMatch); - } - - status = XvdiMatchPort(pPort, pDraw); - if (status != Success) - { - return status; - } - - return XvdiPutVideo(client, pDraw, pPort, pGC, stuff->vid_x, stuff->vid_y, - stuff->vid_w, stuff->vid_h, stuff->drw_x, stuff->drw_y, - stuff->drw_w, stuff->drw_h); -} - -static int -ProcXvPutStill(ClientPtr client) -{ - DrawablePtr pDraw; - XvPortPtr pPort; - GCPtr pGC; - int status; - - REQUEST(xvPutStillReq); - REQUEST_SIZE_MATCH(xvPutStillReq); - - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - if (!(pPort->pAdaptor->type & XvInputMask) || - !(pPort->pAdaptor->type & XvStillMask)) - { - client->errorValue = stuff->port; - return (BadMatch); - } - - status = XvdiMatchPort(pPort, pDraw); - if (status != Success) - { - return status; - } - - return XvdiPutStill(client, pDraw, pPort, pGC, stuff->vid_x, stuff->vid_y, - stuff->vid_w, stuff->vid_h, stuff->drw_x, stuff->drw_y, - stuff->drw_w, stuff->drw_h); -} - -static int -ProcXvGetVideo(ClientPtr client) -{ - DrawablePtr pDraw; - XvPortPtr pPort; - GCPtr pGC; - int status; - - REQUEST(xvGetVideoReq); - REQUEST_SIZE_MATCH(xvGetVideoReq); - - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixReadAccess); - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - if (!(pPort->pAdaptor->type & XvOutputMask) || - !(pPort->pAdaptor->type & XvVideoMask)) - { - client->errorValue = stuff->port; - return (BadMatch); - } - - status = XvdiMatchPort(pPort, pDraw); - if (status != Success) - { - return status; - } - - return XvdiGetVideo(client, pDraw, pPort, pGC, stuff->vid_x, stuff->vid_y, - stuff->vid_w, stuff->vid_h, stuff->drw_x, stuff->drw_y, - stuff->drw_w, stuff->drw_h); -} - -static int -ProcXvGetStill(ClientPtr client) -{ - DrawablePtr pDraw; - XvPortPtr pPort; - GCPtr pGC; - int status; - - REQUEST(xvGetStillReq); - REQUEST_SIZE_MATCH(xvGetStillReq); - - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixReadAccess); - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - if (!(pPort->pAdaptor->type & XvOutputMask) || - !(pPort->pAdaptor->type & XvStillMask)) - { - client->errorValue = stuff->port; - return (BadMatch); - } - - status = XvdiMatchPort(pPort, pDraw); - if (status != Success) - { - return status; - } - - return XvdiGetStill(client, pDraw, pPort, pGC, stuff->vid_x, stuff->vid_y, - stuff->vid_w, stuff->vid_h, stuff->drw_x, stuff->drw_y, - stuff->drw_w, stuff->drw_h); -} - -static int -ProcXvSelectVideoNotify(ClientPtr client) -{ - DrawablePtr pDraw; - int rc; - REQUEST(xvSelectVideoNotifyReq); - REQUEST_SIZE_MATCH(xvSelectVideoNotifyReq); - - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReceiveAccess); - if (rc != Success) - return rc; - - return XvdiSelectVideoNotify(client, pDraw, stuff->onoff); -} - -static int -ProcXvSelectPortNotify(ClientPtr client) -{ - int status; - XvPortPtr pPort; - REQUEST(xvSelectPortNotifyReq); - REQUEST_SIZE_MATCH(xvSelectPortNotifyReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - return XvdiSelectPortNotify(client, pPort, stuff->onoff); -} - -static int -ProcXvGrabPort(ClientPtr client) -{ - int result, status; - XvPortPtr pPort; - xvGrabPortReply rep; - REQUEST(xvGrabPortReq); - REQUEST_SIZE_MATCH(xvGrabPortReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - status = XvdiGrabPort(client, pPort, stuff->time, &result); - - if (status != Success) - { - return status; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.result = result; - - _WriteGrabPortReply(client, &rep); - - return Success; -} - -static int -ProcXvUngrabPort(ClientPtr client) -{ - int status; - XvPortPtr pPort; - REQUEST(xvGrabPortReq); - REQUEST_SIZE_MATCH(xvGrabPortReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - return XvdiUngrabPort(client, pPort, stuff->time); -} - -static int -ProcXvStopVideo(ClientPtr client) -{ - int status, rc; - DrawablePtr pDraw; - XvPortPtr pPort; - REQUEST(xvStopVideoReq); - REQUEST_SIZE_MATCH(xvStopVideoReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess); - if (rc != Success) - return rc; - - return XvdiStopVideo(client, pPort, pDraw); -} - -static int -ProcXvSetPortAttribute(ClientPtr client) -{ - int status; - XvPortPtr pPort; - REQUEST(xvSetPortAttributeReq); - REQUEST_SIZE_MATCH(xvSetPortAttributeReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixSetAttrAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - if (!ValidAtom(stuff->attribute)) - { - client->errorValue = stuff->attribute; - return(BadAtom); - } - - status = XvdiSetPortAttribute(client, pPort, stuff->attribute, stuff->value); - - if (status == BadMatch) - client->errorValue = stuff->attribute; - else - client->errorValue = stuff->value; - - return status; -} - -static int -ProcXvGetPortAttribute(ClientPtr client) -{ - INT32 value; - int status; - XvPortPtr pPort; - xvGetPortAttributeReply rep; - REQUEST(xvGetPortAttributeReq); - REQUEST_SIZE_MATCH(xvGetPortAttributeReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixGetAttrAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - if (!ValidAtom(stuff->attribute)) - { - client->errorValue = stuff->attribute; - return(BadAtom); - } - - status = XvdiGetPortAttribute(client, pPort, stuff->attribute, &value); - if (status != Success) - { - client->errorValue = stuff->attribute; - return status; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.value = value; - - _WriteGetPortAttributeReply(client, &rep); - - return Success; -} - -static int -ProcXvQueryBestSize(ClientPtr client) -{ - int status; - unsigned int actual_width, actual_height; - XvPortPtr pPort; - xvQueryBestSizeReply rep; - REQUEST(xvQueryBestSizeReq); - REQUEST_SIZE_MATCH(xvQueryBestSizeReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - - (* pPort->pAdaptor->ddQueryBestSize)(client, pPort, stuff->motion, - stuff->vid_w, stuff->vid_h, - stuff->drw_w, stuff->drw_h, - &actual_width, &actual_height); - - rep.actual_width = actual_width; - rep.actual_height = actual_height; - - _WriteQueryBestSizeReply(client, &rep); - - return Success; -} - - -static int -ProcXvQueryPortAttributes(ClientPtr client) -{ - int status, size, i; - XvPortPtr pPort; - XvAttributePtr pAtt; - xvQueryPortAttributesReply rep; - xvAttributeInfo Info; - REQUEST(xvQueryPortAttributesReq); - REQUEST_SIZE_MATCH(xvQueryPortAttributesReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixGetAttrAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.num_attributes = pPort->pAdaptor->nAttributes; - rep.text_size = 0; - - for(i = 0, pAtt = pPort->pAdaptor->pAttributes; - i < pPort->pAdaptor->nAttributes; i++, pAtt++) - { - rep.text_size += pad_to_int32(strlen(pAtt->name) + 1); - } - - rep.length = (pPort->pAdaptor->nAttributes * sz_xvAttributeInfo) - + rep.text_size; - rep.length >>= 2; - - _WriteQueryPortAttributesReply(client, &rep); - - for(i = 0, pAtt = pPort->pAdaptor->pAttributes; - i < pPort->pAdaptor->nAttributes; i++, pAtt++) - { - size = strlen(pAtt->name) + 1; /* pass the NULL */ - Info.flags = pAtt->flags; - Info.min = pAtt->min_value; - Info.max = pAtt->max_value; - Info.size = pad_to_int32(size); - - _WriteAttributeInfo(client, &Info); - - WriteToClient(client, size, pAtt->name); - } - - return Success; -} - -static int -ProcXvPutImage(ClientPtr client) -{ - DrawablePtr pDraw; - XvPortPtr pPort; - XvImagePtr pImage = NULL; - GCPtr pGC; - int status, i, size; - CARD16 width, height; - - REQUEST(xvPutImageReq); - REQUEST_AT_LEAST_SIZE(xvPutImageReq); - - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - if (!(pPort->pAdaptor->type & XvImageMask) || - !(pPort->pAdaptor->type & XvInputMask)) - { - client->errorValue = stuff->port; - return (BadMatch); - } - - status = XvdiMatchPort(pPort, pDraw); - if (status != Success) - { - return status; - } - - for(i = 0; i < pPort->pAdaptor->nImages; i++) { - if(pPort->pAdaptor->pImages[i].id == stuff->id) { - pImage = &(pPort->pAdaptor->pImages[i]); - break; - } - } - - if(!pImage) - return BadMatch; - - width = stuff->width; - height = stuff->height; - size = (*pPort->pAdaptor->ddQueryImageAttributes)(client, - pPort, pImage, &width, &height, NULL, NULL); - size += sizeof(xvPutImageReq); - size = bytes_to_int32(size); - - if((width < stuff->width) || (height < stuff->height)) - return BadValue; - - if(client->req_len < size) - return BadLength; - - return XvdiPutImage(client, pDraw, pPort, pGC, stuff->src_x, stuff->src_y, - stuff->src_w, stuff->src_h, stuff->drw_x, stuff->drw_y, - stuff->drw_w, stuff->drw_h, pImage, - (unsigned char*)(&stuff[1]), FALSE, - stuff->width, stuff->height); -} - -#ifdef MITSHM -/* redefined here since it's not in any header file */ -typedef struct _ShmDesc { - struct _ShmDesc *next; - int shmid; - int refcnt; - char *addr; - Bool writable; - unsigned long size; -} ShmDescRec, *ShmDescPtr; - -extern RESTYPE ShmSegType; -extern int BadShmSegCode; -extern int ShmCompletionCode; - -static int -ProcXvShmPutImage(ClientPtr client) -{ - ShmDescPtr shmdesc; - DrawablePtr pDraw; - XvPortPtr pPort; - XvImagePtr pImage = NULL; - GCPtr pGC; - int status, size_needed, i; - CARD16 width, height; - - REQUEST(xvShmPutImageReq); - REQUEST_SIZE_MATCH(xvShmPutImageReq); - - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if ((status = _AllocatePort(stuff->port, pPort)) != Success) - { - client->errorValue = stuff->port; - return (status); - } - - if (!(pPort->pAdaptor->type & XvImageMask) || - !(pPort->pAdaptor->type & XvInputMask)) - { - client->errorValue = stuff->port; - return (BadMatch); - } - - status = XvdiMatchPort(pPort, pDraw); - if (status != Success) - { - return status; - } - - for(i = 0; i < pPort->pAdaptor->nImages; i++) { - if(pPort->pAdaptor->pImages[i].id == stuff->id) { - pImage = &(pPort->pAdaptor->pImages[i]); - break; - } - } - - if(!pImage) - return BadMatch; - - status = dixLookupResourceByType((pointer *)&shmdesc, stuff->shmseg, - ShmSegType, serverClient, DixReadAccess); - if (status != Success) - return (status == BadValue) ? BadShmSegCode : status; - - width = stuff->width; - height = stuff->height; - size_needed = (*pPort->pAdaptor->ddQueryImageAttributes)(client, - pPort, pImage, &width, &height, NULL, NULL); - if((size_needed + stuff->offset) > shmdesc->size) - return BadAccess; - - if((width < stuff->width) || (height < stuff->height)) - return BadValue; - - status = XvdiPutImage(client, pDraw, pPort, pGC, stuff->src_x, stuff->src_y, - stuff->src_w, stuff->src_h, stuff->drw_x, stuff->drw_y, - stuff->drw_w, stuff->drw_h, pImage, - (unsigned char *)shmdesc->addr + stuff->offset, - stuff->send_event, stuff->width, stuff->height); - - if((status == Success) && stuff->send_event) { - xShmCompletionEvent ev; - - ev.type = ShmCompletionCode; - ev.drawable = stuff->drawable; - ev.sequenceNumber = client->sequence; - ev.minorEvent = xv_ShmPutImage; - ev.majorEvent = XvReqCode; - ev.shmseg = stuff->shmseg; - ev.offset = stuff->offset; - WriteEventsToClient(client, 1, (xEvent *) &ev); - } - - return status; -} -#else /* !MITSHM */ -static int -ProcXvShmPutImage(ClientPtr client) -{ - SendErrorToClient(client, XvReqCode, xv_ShmPutImage, 0, BadImplementation); - return(BadImplementation); -} -#endif - -#ifdef XvMCExtension -#include "xvmcext.h" -#endif - -static int -ProcXvQueryImageAttributes(ClientPtr client) -{ - xvQueryImageAttributesReply rep; - int size, num_planes, i; - CARD16 width, height; - XvImagePtr pImage = NULL; - XvPortPtr pPort; - int *offsets; - int *pitches; - int planeLength; - REQUEST(xvQueryImageAttributesReq); - - REQUEST_SIZE_MATCH(xvQueryImageAttributesReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - for(i = 0; i < pPort->pAdaptor->nImages; i++) { - if(pPort->pAdaptor->pImages[i].id == stuff->id) { - pImage = &(pPort->pAdaptor->pImages[i]); - break; - } - } - -#ifdef XvMCExtension - if(!pImage) - pImage = XvMCFindXvImage(pPort, stuff->id); -#endif - - if(!pImage) - return BadMatch; - - num_planes = pImage->num_planes; - - if(!(offsets = xalloc(num_planes << 3))) - return BadAlloc; - pitches = offsets + num_planes; - - width = stuff->width; - height = stuff->height; - - size = (*pPort->pAdaptor->ddQueryImageAttributes)(client, pPort, pImage, - &width, &height, offsets, pitches); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = planeLength = num_planes << 1; - rep.num_planes = num_planes; - rep.width = width; - rep.height = height; - rep.data_size = size; - - _WriteQueryImageAttributesReply(client, &rep); - if(client->swapped) - SwapLongs((CARD32*)offsets, planeLength); - WriteToClient(client, planeLength << 2, (char*)offsets); - - xfree(offsets); - - return Success; -} - -static int -ProcXvListImageFormats(ClientPtr client) -{ - XvPortPtr pPort; - XvImagePtr pImage; - int i; - xvListImageFormatsReply rep; - xvImageFormatInfo info; - REQUEST(xvListImageFormatsReq); - - REQUEST_SIZE_MATCH(xvListImageFormatsReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.num_formats = pPort->pAdaptor->nImages; - rep.length = bytes_to_int32(pPort->pAdaptor->nImages * sz_xvImageFormatInfo); - - _WriteListImageFormatsReply(client, &rep); - - pImage = pPort->pAdaptor->pImages; - - for(i = 0; i < pPort->pAdaptor->nImages; i++, pImage++) { - info.id = pImage->id; - info.type = pImage->type; - info.byte_order = pImage->byte_order; - memcpy(&info.guid, pImage->guid, 16); - info.bpp = pImage->bits_per_pixel; - info.num_planes = pImage->num_planes; - info.depth = pImage->depth; - info.red_mask = pImage->red_mask; - info.green_mask = pImage->green_mask; - info.blue_mask = pImage->blue_mask; - info.format = pImage->format; - info.y_sample_bits = pImage->y_sample_bits; - info.u_sample_bits = pImage->u_sample_bits; - info.v_sample_bits = pImage->v_sample_bits; - info.horz_y_period = pImage->horz_y_period; - info.horz_u_period = pImage->horz_u_period; - info.horz_v_period = pImage->horz_v_period; - info.vert_y_period = pImage->vert_y_period; - info.vert_u_period = pImage->vert_u_period; - info.vert_v_period = pImage->vert_v_period; - memcpy(&info.comp_order, pImage->component_order, 32); - info.scanline_order = pImage->scanline_order; - _WriteImageFormatInfo(client, &info); - } - - return Success; -} - -static int (*XvProcVector[xvNumRequests])(ClientPtr) = { - ProcXvQueryExtension, - ProcXvQueryAdaptors, - ProcXvQueryEncodings, - ProcXvGrabPort, - ProcXvUngrabPort, - ProcXvPutVideo, - ProcXvPutStill, - ProcXvGetVideo, - ProcXvGetStill, - ProcXvStopVideo, - ProcXvSelectVideoNotify, - ProcXvSelectPortNotify, - ProcXvQueryBestSize, - ProcXvSetPortAttribute, - ProcXvGetPortAttribute, - ProcXvQueryPortAttributes, - ProcXvListImageFormats, - ProcXvQueryImageAttributes, - ProcXvPutImage, - ProcXvShmPutImage, -}; - -int -ProcXvDispatch(ClientPtr client) -{ - REQUEST(xReq); - - UpdateCurrentTime(); - - if (stuff->data > xvNumRequests) { - SendErrorToClient(client, XvReqCode, stuff->data, 0, BadRequest); - return(BadRequest); - } - - return XvProcVector[stuff->data](client); -} - -/* Swapped Procs */ - -static int -SProcXvQueryExtension(ClientPtr client) -{ - char n; - REQUEST(xvQueryExtensionReq); - swaps(&stuff->length, n); - return XvProcVector[xv_QueryExtension](client); -} - -static int -SProcXvQueryAdaptors(ClientPtr client) -{ - char n; - REQUEST(xvQueryAdaptorsReq); - swaps(&stuff->length, n); - swapl(&stuff->window, n); - return XvProcVector[xv_QueryAdaptors](client); -} - -static int -SProcXvQueryEncodings(ClientPtr client) -{ - char n; - REQUEST(xvQueryEncodingsReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - return XvProcVector[xv_QueryEncodings](client); -} - -static int -SProcXvGrabPort(ClientPtr client) -{ - char n; - REQUEST(xvGrabPortReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->time, n); - return XvProcVector[xv_GrabPort](client); -} - -static int -SProcXvUngrabPort(ClientPtr client) -{ - char n; - REQUEST(xvUngrabPortReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->time, n); - return XvProcVector[xv_UngrabPort](client); -} - -static int -SProcXvPutVideo(ClientPtr client) -{ - char n; - REQUEST(xvPutVideoReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->drawable, n); - swapl(&stuff->gc, n); - swaps(&stuff->vid_x, n); - swaps(&stuff->vid_y, n); - swaps(&stuff->vid_w, n); - swaps(&stuff->vid_h, n); - swaps(&stuff->drw_x, n); - swaps(&stuff->drw_y, n); - swaps(&stuff->drw_w, n); - swaps(&stuff->drw_h, n); - return XvProcVector[xv_PutVideo](client); -} - -static int -SProcXvPutStill(ClientPtr client) -{ - char n; - REQUEST(xvPutStillReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->drawable, n); - swapl(&stuff->gc, n); - swaps(&stuff->vid_x, n); - swaps(&stuff->vid_y, n); - swaps(&stuff->vid_w, n); - swaps(&stuff->vid_h, n); - swaps(&stuff->drw_x, n); - swaps(&stuff->drw_y, n); - swaps(&stuff->drw_w, n); - swaps(&stuff->drw_h, n); - return XvProcVector[xv_PutStill](client); -} - -static int -SProcXvGetVideo(ClientPtr client) -{ - char n; - REQUEST(xvGetVideoReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->drawable, n); - swapl(&stuff->gc, n); - swaps(&stuff->vid_x, n); - swaps(&stuff->vid_y, n); - swaps(&stuff->vid_w, n); - swaps(&stuff->vid_h, n); - swaps(&stuff->drw_x, n); - swaps(&stuff->drw_y, n); - swaps(&stuff->drw_w, n); - swaps(&stuff->drw_h, n); - return XvProcVector[xv_GetVideo](client); -} - -static int -SProcXvGetStill(ClientPtr client) -{ - char n; - REQUEST(xvGetStillReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->drawable, n); - swapl(&stuff->gc, n); - swaps(&stuff->vid_x, n); - swaps(&stuff->vid_y, n); - swaps(&stuff->vid_w, n); - swaps(&stuff->vid_h, n); - swaps(&stuff->drw_x, n); - swaps(&stuff->drw_y, n); - swaps(&stuff->drw_w, n); - swaps(&stuff->drw_h, n); - return XvProcVector[xv_GetStill](client); -} - -static int -SProcXvPutImage(ClientPtr client) -{ - char n; - REQUEST(xvPutImageReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->drawable, n); - swapl(&stuff->gc, n); - swapl(&stuff->id, n); - swaps(&stuff->src_x, n); - swaps(&stuff->src_y, n); - swaps(&stuff->src_w, n); - swaps(&stuff->src_h, n); - swaps(&stuff->drw_x, n); - swaps(&stuff->drw_y, n); - swaps(&stuff->drw_w, n); - swaps(&stuff->drw_h, n); - swaps(&stuff->width, n); - swaps(&stuff->height, n); - return XvProcVector[xv_PutImage](client); -} - -#ifdef MITSHM -static int -SProcXvShmPutImage(ClientPtr client) -{ - char n; - REQUEST(xvShmPutImageReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->drawable, n); - swapl(&stuff->gc, n); - swapl(&stuff->shmseg, n); - swapl(&stuff->id, n); - swapl(&stuff->offset, n); - swaps(&stuff->src_x, n); - swaps(&stuff->src_y, n); - swaps(&stuff->src_w, n); - swaps(&stuff->src_h, n); - swaps(&stuff->drw_x, n); - swaps(&stuff->drw_y, n); - swaps(&stuff->drw_w, n); - swaps(&stuff->drw_h, n); - swaps(&stuff->width, n); - swaps(&stuff->height, n); - return XvProcVector[xv_ShmPutImage](client); -} -#else /* MITSHM */ -#define SProcXvShmPutImage ProcXvShmPutImage -#endif - -static int -SProcXvSelectVideoNotify(ClientPtr client) -{ - char n; - REQUEST(xvSelectVideoNotifyReq); - swaps(&stuff->length, n); - swapl(&stuff->drawable, n); - return XvProcVector[xv_SelectVideoNotify](client); -} - -static int -SProcXvSelectPortNotify(ClientPtr client) -{ - char n; - REQUEST(xvSelectPortNotifyReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - return XvProcVector[xv_SelectPortNotify](client); -} - -static int -SProcXvStopVideo(ClientPtr client) -{ - char n; - REQUEST(xvStopVideoReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->drawable, n); - return XvProcVector[xv_StopVideo](client); -} - -static int -SProcXvSetPortAttribute(ClientPtr client) -{ - char n; - REQUEST(xvSetPortAttributeReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->attribute, n); - swapl(&stuff->value, n); - return XvProcVector[xv_SetPortAttribute](client); -} - -static int -SProcXvGetPortAttribute(ClientPtr client) -{ - char n; - REQUEST(xvGetPortAttributeReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->attribute, n); - return XvProcVector[xv_GetPortAttribute](client); -} - -static int -SProcXvQueryBestSize(ClientPtr client) -{ - char n; - REQUEST(xvQueryBestSizeReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swaps(&stuff->vid_w, n); - swaps(&stuff->vid_h, n); - swaps(&stuff->drw_w, n); - swaps(&stuff->drw_h, n); - return XvProcVector[xv_QueryBestSize](client); -} - -static int -SProcXvQueryPortAttributes(ClientPtr client) -{ - char n; - REQUEST(xvQueryPortAttributesReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - return XvProcVector[xv_QueryPortAttributes](client); -} - -static int -SProcXvQueryImageAttributes(ClientPtr client) -{ - char n; - REQUEST(xvQueryImageAttributesReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - swapl(&stuff->id, n); - swaps(&stuff->width, n); - swaps(&stuff->height, n); - return XvProcVector[xv_QueryImageAttributes](client); -} - -static int -SProcXvListImageFormats(ClientPtr client) -{ - char n; - REQUEST(xvListImageFormatsReq); - swaps(&stuff->length, n); - swapl(&stuff->port, n); - return XvProcVector[xv_ListImageFormats](client); -} - -static int (*SXvProcVector[xvNumRequests])(ClientPtr) = { - SProcXvQueryExtension, - SProcXvQueryAdaptors, - SProcXvQueryEncodings, - SProcXvGrabPort, - SProcXvUngrabPort, - SProcXvPutVideo, - SProcXvPutStill, - SProcXvGetVideo, - SProcXvGetStill, - SProcXvStopVideo, - SProcXvSelectVideoNotify, - SProcXvSelectPortNotify, - SProcXvQueryBestSize, - SProcXvSetPortAttribute, - SProcXvGetPortAttribute, - SProcXvQueryPortAttributes, - SProcXvListImageFormats, - SProcXvQueryImageAttributes, - SProcXvPutImage, - SProcXvShmPutImage, -}; - -int -SProcXvDispatch(ClientPtr client) -{ - REQUEST(xReq); - - UpdateCurrentTime(); - - if (stuff->data > xvNumRequests) { - SendErrorToClient(client, XvReqCode, stuff->data, 0, BadRequest); - return(BadRequest); - } - - return SXvProcVector[stuff->data](client); -} - -#ifdef PANORAMIX -static int -XineramaXvStopVideo(ClientPtr client) -{ - int result, i; - PanoramiXRes *draw, *port; - REQUEST(xvStopVideoReq); - REQUEST_SIZE_MATCH(xvStopVideoReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - result = dixLookupResourceByType((pointer *)&port, stuff->port, - XvXRTPort, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? _XvBadPort : result; - - FOR_NSCREENS_BACKWARD(i) { - if(port->info[i].id) { - stuff->drawable = draw->info[i].id; - stuff->port = port->info[i].id; - result = ProcXvStopVideo(client); - } - } - - return result; -} - -static int -XineramaXvSetPortAttribute(ClientPtr client) -{ - REQUEST(xvSetPortAttributeReq); - PanoramiXRes *port; - int result, i; - - REQUEST_SIZE_MATCH(xvSetPortAttributeReq); - - result = dixLookupResourceByType((pointer *)&port, stuff->port, - XvXRTPort, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? _XvBadPort : result; - - FOR_NSCREENS_BACKWARD(i) { - if(port->info[i].id) { - stuff->port = port->info[i].id; - result = ProcXvSetPortAttribute(client); - } - } - return result; -} - -#ifdef MITSHM -static int -XineramaXvShmPutImage(ClientPtr client) -{ - REQUEST(xvShmPutImageReq); - PanoramiXRes *draw, *gc, *port; - Bool send_event = stuff->send_event; - Bool isRoot; - int result, i, x, y; - - REQUEST_SIZE_MATCH(xvShmPutImageReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, - XRT_GC, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - result = dixLookupResourceByType((pointer *)&port, stuff->port, - XvXRTPort, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? _XvBadPort : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - x = stuff->drw_x; - y = stuff->drw_y; - - FOR_NSCREENS_BACKWARD(i) { - if(port->info[i].id) { - stuff->drawable = draw->info[i].id; - stuff->port = port->info[i].id; - stuff->gc = gc->info[i].id; - stuff->drw_x = x; - stuff->drw_y = y; - if(isRoot) { - stuff->drw_x -= panoramiXdataPtr[i].x; - stuff->drw_y -= panoramiXdataPtr[i].y; - } - stuff->send_event = (send_event && !i) ? 1 : 0; - - result = ProcXvShmPutImage(client); - } - } - return result; -} -#else -#define XineramaXvShmPutImage ProcXvShmPutImage -#endif - -static int -XineramaXvPutImage(ClientPtr client) -{ - REQUEST(xvPutImageReq); - PanoramiXRes *draw, *gc, *port; - Bool isRoot; - int result, i, x, y; - - REQUEST_AT_LEAST_SIZE(xvPutImageReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, - XRT_GC, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - result = dixLookupResourceByType((pointer *)&port, stuff->port, - XvXRTPort, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? _XvBadPort : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - x = stuff->drw_x; - y = stuff->drw_y; - - FOR_NSCREENS_BACKWARD(i) { - if(port->info[i].id) { - stuff->drawable = draw->info[i].id; - stuff->port = port->info[i].id; - stuff->gc = gc->info[i].id; - stuff->drw_x = x; - stuff->drw_y = y; - if(isRoot) { - stuff->drw_x -= panoramiXdataPtr[i].x; - stuff->drw_y -= panoramiXdataPtr[i].y; - } - - result = ProcXvPutImage(client); - } - } - return result; -} - -static int -XineramaXvPutVideo(ClientPtr client) -{ - REQUEST(xvPutImageReq); - PanoramiXRes *draw, *gc, *port; - Bool isRoot; - int result, i, x, y; - - REQUEST_AT_LEAST_SIZE(xvPutVideoReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, - XRT_GC, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - result = dixLookupResourceByType((pointer *)&port, stuff->port, - XvXRTPort, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? _XvBadPort : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - x = stuff->drw_x; - y = stuff->drw_y; - - FOR_NSCREENS_BACKWARD(i) { - if(port->info[i].id) { - stuff->drawable = draw->info[i].id; - stuff->port = port->info[i].id; - stuff->gc = gc->info[i].id; - stuff->drw_x = x; - stuff->drw_y = y; - if(isRoot) { - stuff->drw_x -= panoramiXdataPtr[i].x; - stuff->drw_y -= panoramiXdataPtr[i].y; - } - - result = ProcXvPutVideo(client); - } - } - return result; -} - -static int -XineramaXvPutStill(ClientPtr client) -{ - REQUEST(xvPutImageReq); - PanoramiXRes *draw, *gc, *port; - Bool isRoot; - int result, i, x, y; - - REQUEST_AT_LEAST_SIZE(xvPutImageReq); - - result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, - XRC_DRAWABLE, client, DixWriteAccess); - if (result != Success) - return (result == BadValue) ? BadDrawable : result; - - result = dixLookupResourceByType((pointer *)&gc, stuff->gc, - XRT_GC, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? BadGC : result; - - result = dixLookupResourceByType((pointer *)&port, stuff->port, - XvXRTPort, client, DixReadAccess); - if (result != Success) - return (result == BadValue) ? _XvBadPort : result; - - isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; - - x = stuff->drw_x; - y = stuff->drw_y; - - FOR_NSCREENS_BACKWARD(i) { - if(port->info[i].id) { - stuff->drawable = draw->info[i].id; - stuff->port = port->info[i].id; - stuff->gc = gc->info[i].id; - stuff->drw_x = x; - stuff->drw_y = y; - if(isRoot) { - stuff->drw_x -= panoramiXdataPtr[i].x; - stuff->drw_y -= panoramiXdataPtr[i].y; - } - - result = ProcXvPutStill(client); - } - } - return result; -} - -static Bool -isImageAdaptor(XvAdaptorPtr pAdapt) -{ - return (pAdapt->type & XvImageMask) && (pAdapt->nImages > 0); -} - -static Bool -hasOverlay(XvAdaptorPtr pAdapt) -{ - int i; - for(i = 0; i < pAdapt->nAttributes; i++) - if(!strcmp(pAdapt->pAttributes[i].name, "XV_COLORKEY")) - return TRUE; - return FALSE; -} - -static XvAdaptorPtr -matchAdaptor(ScreenPtr pScreen, XvAdaptorPtr refAdapt, Bool isOverlay) -{ - int i; - XvScreenPtr xvsp = dixLookupPrivate(&pScreen->devPrivates, XvGetScreenKey()); - /* Do not try to go on if xv is not supported on this screen */ - if(xvsp == NULL) - return NULL; - - /* if the adaptor has the same name it's a perfect match */ - for(i = 0; i < xvsp->nAdaptors; i++) { - XvAdaptorPtr pAdapt = xvsp->pAdaptors + i; - if(!strcmp(refAdapt->name, pAdapt->name)) - return pAdapt; - } - - /* otherwise we only look for XvImage adaptors */ - if(!isImageAdaptor(refAdapt)) - return NULL; - - /* prefer overlay/overlay non-overlay/non-overlay pairing */ - for(i = 0; i < xvsp->nAdaptors; i++) { - XvAdaptorPtr pAdapt = xvsp->pAdaptors + i; - if(isImageAdaptor(pAdapt) && isOverlay == hasOverlay(pAdapt)) - return pAdapt; - } - - /* but we'll take any XvImage pairing if we can get it */ - for(i = 0; i < xvsp->nAdaptors; i++) { - XvAdaptorPtr pAdapt = xvsp->pAdaptors + i; - if(isImageAdaptor(pAdapt)) - return pAdapt; - } - return NULL; -} - -void XineramifyXv(void) -{ - XvScreenPtr xvsp0 = dixLookupPrivate(&screenInfo.screens[0]->devPrivates, XvGetScreenKey()); - XvAdaptorPtr MatchingAdaptors[MAXSCREENS]; - int i, j, k; - - XvXRTPort = CreateNewResourceType(XineramaDeleteResource, "XvXRTPort"); - - if (!xvsp0 || !XvXRTPort) return; - - for(i = 0; i < xvsp0->nAdaptors; i++) { - Bool isOverlay; - XvAdaptorPtr refAdapt = xvsp0->pAdaptors + i; - if(!(refAdapt->type & XvInputMask)) continue; - - MatchingAdaptors[0] = refAdapt; - isOverlay = hasOverlay(refAdapt); - for(j = 1; j < PanoramiXNumScreens; j++) - MatchingAdaptors[j] = matchAdaptor(screenInfo.screens[j], refAdapt, isOverlay); - - /* now create a resource for each port */ - for(j = 0; j < refAdapt->nPorts; j++) { - PanoramiXRes *port = xalloc(sizeof(PanoramiXRes)); - if(!port) - break; - - for(k = 0; k < PanoramiXNumScreens; k++) { - if(MatchingAdaptors[k] && (MatchingAdaptors[k]->nPorts > j)) - port->info[k].id = MatchingAdaptors[k]->base_id + j; - else - port->info[k].id = 0; - } - AddResource(port->info[0].id, XvXRTPort, port); - } - } - - /* munge the dispatch vector */ - XvProcVector[xv_PutVideo] = XineramaXvPutVideo; - XvProcVector[xv_PutStill] = XineramaXvPutStill; - XvProcVector[xv_StopVideo] = XineramaXvStopVideo; - XvProcVector[xv_SetPortAttribute] = XineramaXvSetPortAttribute; - XvProcVector[xv_PutImage] = XineramaXvPutImage; - XvProcVector[xv_ShmPutImage] = XineramaXvShmPutImage; -} -#endif /* PANORAMIX */ - -void -XvResetProcVector(void) -{ -#ifdef PANORAMIX - XvProcVector[xv_PutVideo] = ProcXvPutVideo; - XvProcVector[xv_PutStill] = ProcXvPutStill; - XvProcVector[xv_StopVideo] = ProcXvStopVideo; - XvProcVector[xv_SetPortAttribute] = ProcXvSetPortAttribute; - XvProcVector[xv_PutImage] = ProcXvPutImage; - XvProcVector[xv_ShmPutImage] = ProcXvShmPutImage; -#endif -} +/*********************************************************** +Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts, +and the Massachusetts Institute of Technology, Cambridge, 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 names of Digital or MIT 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 "scrnintstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "gcstruct.h" +#include "dixstruct.h" +#include "resource.h" +#include "opaque.h" + +#include +#include +#include "xvdix.h" +#ifdef MITSHM +#include +#endif + +#include "xvdisp.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" + +unsigned long XvXRTPort; +#endif + +static int +SWriteQueryExtensionReply( + ClientPtr client, + xvQueryExtensionReply *rep +){ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->version, n); + swaps(&rep->revision, n); + + (void)WriteToClient(client, sz_xvQueryExtensionReply, (char *)rep); + + return Success; +} + +static int +SWriteQueryAdaptorsReply( + ClientPtr client, + xvQueryAdaptorsReply *rep +){ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->num_adaptors, n); + + (void)WriteToClient(client, sz_xvQueryAdaptorsReply, (char *)rep); + + return Success; +} + +static int +SWriteQueryEncodingsReply( + ClientPtr client, + xvQueryEncodingsReply *rep +){ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->num_encodings, n); + + (void)WriteToClient(client, sz_xvQueryEncodingsReply, (char *)rep); + + return Success; +} + +static int +SWriteAdaptorInfo( + ClientPtr client, + xvAdaptorInfo *pAdaptor +){ + char n; + + swapl(&pAdaptor->base_id, n); + swaps(&pAdaptor->name_size, n); + swaps(&pAdaptor->num_ports, n); + swaps(&pAdaptor->num_formats, n); + + (void)WriteToClient(client, sz_xvAdaptorInfo, (char *)pAdaptor); + + return Success; +} + +static int +SWriteEncodingInfo( + ClientPtr client, + xvEncodingInfo *pEncoding +){ + char n; + + swapl(&pEncoding->encoding, n); + swaps(&pEncoding->name_size, n); + swaps(&pEncoding->width, n); + swaps(&pEncoding->height, n); + swapl(&pEncoding->rate.numerator, n); + swapl(&pEncoding->rate.denominator, n); + (void)WriteToClient(client, sz_xvEncodingInfo, (char *)pEncoding); + + return Success; +} + +static int +SWriteFormat( + ClientPtr client, + xvFormat *pFormat +){ + char n; + + swapl(&pFormat->visual, n); + (void)WriteToClient(client, sz_xvFormat, (char *)pFormat); + + return Success; +} + +static int +SWriteAttributeInfo( + ClientPtr client, + xvAttributeInfo *pAtt +){ + char n; + + swapl(&pAtt->flags, n); + swapl(&pAtt->size, n); + swapl(&pAtt->min, n); + swapl(&pAtt->max, n); + (void)WriteToClient(client, sz_xvAttributeInfo, (char *)pAtt); + + return Success; +} + +static int +SWriteImageFormatInfo( + ClientPtr client, + xvImageFormatInfo *pImage +){ + char n; + + swapl(&pImage->id, n); + swapl(&pImage->red_mask, n); + swapl(&pImage->green_mask, n); + swapl(&pImage->blue_mask, n); + swapl(&pImage->y_sample_bits, n); + swapl(&pImage->u_sample_bits, n); + swapl(&pImage->v_sample_bits, n); + swapl(&pImage->horz_y_period, n); + swapl(&pImage->horz_u_period, n); + swapl(&pImage->horz_v_period, n); + swapl(&pImage->vert_y_period, n); + swapl(&pImage->vert_u_period, n); + swapl(&pImage->vert_v_period, n); + + (void)WriteToClient(client, sz_xvImageFormatInfo, (char *)pImage); + + return Success; +} + +static int +SWriteGrabPortReply( + ClientPtr client, + xvGrabPortReply *rep +){ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + + (void)WriteToClient(client, sz_xvGrabPortReply, (char *)rep); + + return Success; +} + +static int +SWriteGetPortAttributeReply( + ClientPtr client, + xvGetPortAttributeReply *rep +){ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swapl(&rep->value, n); + + (void)WriteToClient(client, sz_xvGetPortAttributeReply, (char *)rep); + + return Success; +} + +static int +SWriteQueryBestSizeReply( + ClientPtr client, + xvQueryBestSizeReply *rep +){ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->actual_width, n); + swaps(&rep->actual_height, n); + + (void)WriteToClient(client, sz_xvQueryBestSizeReply, (char *)rep); + + return Success; +} + +static int +SWriteQueryPortAttributesReply( + ClientPtr client, + xvQueryPortAttributesReply *rep +){ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swapl(&rep->num_attributes, n); + swapl(&rep->text_size, n); + + (void)WriteToClient(client, sz_xvQueryPortAttributesReply, (char *)rep); + + return Success; +} + +static int +SWriteQueryImageAttributesReply( + ClientPtr client, + xvQueryImageAttributesReply *rep +){ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swapl(&rep->num_planes, n); + swapl(&rep->data_size, n); + swaps(&rep->width, n); + swaps(&rep->height, n); + + (void)WriteToClient(client, sz_xvQueryImageAttributesReply, (char *)rep); + + return Success; +} + +static int +SWriteListImageFormatsReply( + ClientPtr client, + xvListImageFormatsReply *rep +){ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swapl(&rep->num_formats, n); + + (void)WriteToClient(client, sz_xvListImageFormatsReply, (char *)rep); + + return Success; +} + +#define _WriteQueryAdaptorsReply(_c,_d) \ + if ((_c)->swapped) SWriteQueryAdaptorsReply(_c, _d); \ + else WriteToClient(_c, sz_xvQueryAdaptorsReply, (char*)_d) + +#define _WriteQueryExtensionReply(_c,_d) \ + if ((_c)->swapped) SWriteQueryExtensionReply(_c, _d); \ + else WriteToClient(_c, sz_xvQueryExtensionReply, (char*)_d) + +#define _WriteQueryEncodingsReply(_c,_d) \ + if ((_c)->swapped) SWriteQueryEncodingsReply(_c, _d); \ + else WriteToClient(_c, sz_xvQueryEncodingsReply, (char*)_d) + +#define _WriteAdaptorInfo(_c,_d) \ + if ((_c)->swapped) SWriteAdaptorInfo(_c, _d); \ + else WriteToClient(_c, sz_xvAdaptorInfo, (char*)_d) + +#define _WriteAttributeInfo(_c,_d) \ + if ((_c)->swapped) SWriteAttributeInfo(_c, _d); \ + else WriteToClient(_c, sz_xvAttributeInfo, (char*)_d) + +#define _WriteEncodingInfo(_c,_d) \ + if ((_c)->swapped) SWriteEncodingInfo(_c, _d); \ + else WriteToClient(_c, sz_xvEncodingInfo, (char*)_d) + +#define _WriteFormat(_c,_d) \ + if ((_c)->swapped) SWriteFormat(_c, _d); \ + else WriteToClient(_c, sz_xvFormat, (char*)_d) + +#define _WriteGrabPortReply(_c,_d) \ + if ((_c)->swapped) SWriteGrabPortReply(_c, _d); \ + else WriteToClient(_c, sz_xvGrabPortReply, (char*)_d) + +#define _WriteGetPortAttributeReply(_c,_d) \ + if ((_c)->swapped) SWriteGetPortAttributeReply(_c, _d); \ + else WriteToClient(_c, sz_xvGetPortAttributeReply, (char*)_d) + +#define _WriteQueryBestSizeReply(_c,_d) \ + if ((_c)->swapped) SWriteQueryBestSizeReply(_c, _d); \ + else WriteToClient(_c, sz_xvQueryBestSizeReply,(char*) _d) + +#define _WriteQueryPortAttributesReply(_c,_d) \ + if ((_c)->swapped) SWriteQueryPortAttributesReply(_c, _d); \ + else WriteToClient(_c, sz_xvQueryPortAttributesReply,(char*) _d) + +#define _WriteQueryImageAttributesReply(_c,_d) \ + if ((_c)->swapped) SWriteQueryImageAttributesReply(_c, _d); \ + else WriteToClient(_c, sz_xvQueryImageAttributesReply,(char*) _d) + +#define _WriteListImageFormatsReply(_c,_d) \ + if ((_c)->swapped) SWriteListImageFormatsReply(_c, _d); \ + else WriteToClient(_c, sz_xvListImageFormatsReply,(char*) _d) + +#define _WriteImageFormatInfo(_c,_d) \ + if ((_c)->swapped) SWriteImageFormatInfo(_c, _d); \ + else WriteToClient(_c, sz_xvImageFormatInfo, (char*)_d) + +#define _AllocatePort(_i,_p) \ + ((_p)->id != _i) ? (* (_p)->pAdaptor->ddAllocatePort)(_i,_p,&_p) : Success + +static int +ProcXvQueryExtension(ClientPtr client) +{ + xvQueryExtensionReply rep; + /* REQUEST(xvQueryExtensionReq); */ + REQUEST_SIZE_MATCH(xvQueryExtensionReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.version = XvVersion; + rep.revision = XvRevision; + + _WriteQueryExtensionReply(client, &rep); + + return Success; +} + +static int +ProcXvQueryAdaptors(ClientPtr client) +{ + xvFormat format; + xvAdaptorInfo ainfo; + xvQueryAdaptorsReply rep; + int totalSize, na, nf, rc; + int nameSize; + XvAdaptorPtr pa; + XvFormatPtr pf; + WindowPtr pWin; + ScreenPtr pScreen; + XvScreenPtr pxvs; + + REQUEST(xvQueryAdaptorsReq); + REQUEST_SIZE_MATCH(xvQueryAdaptorsReq); + + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + XvGetScreenKey()); + if (!pxvs) + { + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.num_adaptors = 0; + rep.length = 0; + + _WriteQueryAdaptorsReply(client, &rep); + + return Success; + } + + (* pxvs->ddQueryAdaptors)(pScreen, &pxvs->pAdaptors, &pxvs->nAdaptors); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.num_adaptors = pxvs->nAdaptors; + + /* CALCULATE THE TOTAL SIZE OF THE REPLY IN BYTES */ + + totalSize = pxvs->nAdaptors * sz_xvAdaptorInfo; + + /* FOR EACH ADPATOR ADD UP THE BYTES FOR ENCODINGS AND FORMATS */ + + na = pxvs->nAdaptors; + pa = pxvs->pAdaptors; + while (na--) + { + totalSize += pad_to_int32(strlen(pa->name)); + totalSize += pa->nFormats * sz_xvFormat; + pa++; + } + + rep.length = bytes_to_int32(totalSize); + + _WriteQueryAdaptorsReply(client, &rep); + + na = pxvs->nAdaptors; + pa = pxvs->pAdaptors; + while (na--) + { + + ainfo.base_id = pa->base_id; + ainfo.num_ports = pa->nPorts; + ainfo.type = pa->type; + ainfo.name_size = nameSize = strlen(pa->name); + ainfo.num_formats = pa->nFormats; + + _WriteAdaptorInfo(client, &ainfo); + + WriteToClient(client, nameSize, pa->name); + + nf = pa->nFormats; + pf = pa->pFormats; + while (nf--) + { + format.depth = pf->depth; + format.visual = pf->visual; + _WriteFormat(client, &format); + pf++; + } + + pa++; + + } + + return Success; +} + +static int +ProcXvQueryEncodings(ClientPtr client) +{ + xvEncodingInfo einfo; + xvQueryEncodingsReply rep; + int totalSize; + int nameSize; + XvPortPtr pPort; + int ne; + XvEncodingPtr pe; + int status; + + REQUEST(xvQueryEncodingsReq); + REQUEST_SIZE_MATCH(xvQueryEncodingsReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.num_encodings = pPort->pAdaptor->nEncodings; + + /* FOR EACH ENCODING ADD UP THE BYTES FOR ENCODING NAMES */ + + ne = pPort->pAdaptor->nEncodings; + pe = pPort->pAdaptor->pEncodings; + totalSize = ne * sz_xvEncodingInfo; + while (ne--) + { + totalSize += pad_to_int32(strlen(pe->name)); + pe++; + } + + rep.length = bytes_to_int32(totalSize); + + _WriteQueryEncodingsReply(client, &rep); + + ne = pPort->pAdaptor->nEncodings; + pe = pPort->pAdaptor->pEncodings; + while (ne--) + { + einfo.encoding = pe->id; + einfo.name_size = nameSize = strlen(pe->name); + einfo.width = pe->width; + einfo.height = pe->height; + einfo.rate.numerator = pe->rate.numerator; + einfo.rate.denominator = pe->rate.denominator; + _WriteEncodingInfo(client, &einfo); + WriteToClient(client, nameSize, pe->name); + pe++; + } + + return Success; +} + +static int +ProcXvPutVideo(ClientPtr client) +{ + DrawablePtr pDraw; + XvPortPtr pPort; + GCPtr pGC; + int status; + + REQUEST(xvPutVideoReq); + REQUEST_SIZE_MATCH(xvPutVideoReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + if (!(pPort->pAdaptor->type & XvInputMask) || + !(pPort->pAdaptor->type & XvVideoMask)) + { + client->errorValue = stuff->port; + return (BadMatch); + } + + status = XvdiMatchPort(pPort, pDraw); + if (status != Success) + { + return status; + } + + return XvdiPutVideo(client, pDraw, pPort, pGC, stuff->vid_x, stuff->vid_y, + stuff->vid_w, stuff->vid_h, stuff->drw_x, stuff->drw_y, + stuff->drw_w, stuff->drw_h); +} + +static int +ProcXvPutStill(ClientPtr client) +{ + DrawablePtr pDraw; + XvPortPtr pPort; + GCPtr pGC; + int status; + + REQUEST(xvPutStillReq); + REQUEST_SIZE_MATCH(xvPutStillReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + if (!(pPort->pAdaptor->type & XvInputMask) || + !(pPort->pAdaptor->type & XvStillMask)) + { + client->errorValue = stuff->port; + return (BadMatch); + } + + status = XvdiMatchPort(pPort, pDraw); + if (status != Success) + { + return status; + } + + return XvdiPutStill(client, pDraw, pPort, pGC, stuff->vid_x, stuff->vid_y, + stuff->vid_w, stuff->vid_h, stuff->drw_x, stuff->drw_y, + stuff->drw_w, stuff->drw_h); +} + +static int +ProcXvGetVideo(ClientPtr client) +{ + DrawablePtr pDraw; + XvPortPtr pPort; + GCPtr pGC; + int status; + + REQUEST(xvGetVideoReq); + REQUEST_SIZE_MATCH(xvGetVideoReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixReadAccess); + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + if (!(pPort->pAdaptor->type & XvOutputMask) || + !(pPort->pAdaptor->type & XvVideoMask)) + { + client->errorValue = stuff->port; + return (BadMatch); + } + + status = XvdiMatchPort(pPort, pDraw); + if (status != Success) + { + return status; + } + + return XvdiGetVideo(client, pDraw, pPort, pGC, stuff->vid_x, stuff->vid_y, + stuff->vid_w, stuff->vid_h, stuff->drw_x, stuff->drw_y, + stuff->drw_w, stuff->drw_h); +} + +static int +ProcXvGetStill(ClientPtr client) +{ + DrawablePtr pDraw; + XvPortPtr pPort; + GCPtr pGC; + int status; + + REQUEST(xvGetStillReq); + REQUEST_SIZE_MATCH(xvGetStillReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixReadAccess); + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + if (!(pPort->pAdaptor->type & XvOutputMask) || + !(pPort->pAdaptor->type & XvStillMask)) + { + client->errorValue = stuff->port; + return (BadMatch); + } + + status = XvdiMatchPort(pPort, pDraw); + if (status != Success) + { + return status; + } + + return XvdiGetStill(client, pDraw, pPort, pGC, stuff->vid_x, stuff->vid_y, + stuff->vid_w, stuff->vid_h, stuff->drw_x, stuff->drw_y, + stuff->drw_w, stuff->drw_h); +} + +static int +ProcXvSelectVideoNotify(ClientPtr client) +{ + DrawablePtr pDraw; + int rc; + REQUEST(xvSelectVideoNotifyReq); + REQUEST_SIZE_MATCH(xvSelectVideoNotifyReq); + + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReceiveAccess); + if (rc != Success) + return rc; + + return XvdiSelectVideoNotify(client, pDraw, stuff->onoff); +} + +static int +ProcXvSelectPortNotify(ClientPtr client) +{ + int status; + XvPortPtr pPort; + REQUEST(xvSelectPortNotifyReq); + REQUEST_SIZE_MATCH(xvSelectPortNotifyReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + return XvdiSelectPortNotify(client, pPort, stuff->onoff); +} + +static int +ProcXvGrabPort(ClientPtr client) +{ + int result, status; + XvPortPtr pPort; + xvGrabPortReply rep; + REQUEST(xvGrabPortReq); + REQUEST_SIZE_MATCH(xvGrabPortReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + status = XvdiGrabPort(client, pPort, stuff->time, &result); + + if (status != Success) + { + return status; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.result = result; + + _WriteGrabPortReply(client, &rep); + + return Success; +} + +static int +ProcXvUngrabPort(ClientPtr client) +{ + int status; + XvPortPtr pPort; + REQUEST(xvGrabPortReq); + REQUEST_SIZE_MATCH(xvGrabPortReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + return XvdiUngrabPort(client, pPort, stuff->time); +} + +static int +ProcXvStopVideo(ClientPtr client) +{ + int status, rc; + DrawablePtr pDraw; + XvPortPtr pPort; + REQUEST(xvStopVideoReq); + REQUEST_SIZE_MATCH(xvStopVideoReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess); + if (rc != Success) + return rc; + + return XvdiStopVideo(client, pPort, pDraw); +} + +static int +ProcXvSetPortAttribute(ClientPtr client) +{ + int status; + XvPortPtr pPort; + REQUEST(xvSetPortAttributeReq); + REQUEST_SIZE_MATCH(xvSetPortAttributeReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixSetAttrAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + if (!ValidAtom(stuff->attribute)) + { + client->errorValue = stuff->attribute; + return(BadAtom); + } + + status = XvdiSetPortAttribute(client, pPort, stuff->attribute, stuff->value); + + if (status == BadMatch) + client->errorValue = stuff->attribute; + else + client->errorValue = stuff->value; + + return status; +} + +static int +ProcXvGetPortAttribute(ClientPtr client) +{ + INT32 value; + int status; + XvPortPtr pPort; + xvGetPortAttributeReply rep; + REQUEST(xvGetPortAttributeReq); + REQUEST_SIZE_MATCH(xvGetPortAttributeReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixGetAttrAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + if (!ValidAtom(stuff->attribute)) + { + client->errorValue = stuff->attribute; + return(BadAtom); + } + + status = XvdiGetPortAttribute(client, pPort, stuff->attribute, &value); + if (status != Success) + { + client->errorValue = stuff->attribute; + return status; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.value = value; + + _WriteGetPortAttributeReply(client, &rep); + + return Success; +} + +static int +ProcXvQueryBestSize(ClientPtr client) +{ + int status; + unsigned int actual_width, actual_height; + XvPortPtr pPort; + xvQueryBestSizeReply rep; + REQUEST(xvQueryBestSizeReq); + REQUEST_SIZE_MATCH(xvQueryBestSizeReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + + (* pPort->pAdaptor->ddQueryBestSize)(client, pPort, stuff->motion, + stuff->vid_w, stuff->vid_h, + stuff->drw_w, stuff->drw_h, + &actual_width, &actual_height); + + rep.actual_width = actual_width; + rep.actual_height = actual_height; + + _WriteQueryBestSizeReply(client, &rep); + + return Success; +} + + +static int +ProcXvQueryPortAttributes(ClientPtr client) +{ + int status, size, i; + XvPortPtr pPort; + XvAttributePtr pAtt; + xvQueryPortAttributesReply rep; + xvAttributeInfo Info; + REQUEST(xvQueryPortAttributesReq); + REQUEST_SIZE_MATCH(xvQueryPortAttributesReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixGetAttrAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.num_attributes = pPort->pAdaptor->nAttributes; + rep.text_size = 0; + + for(i = 0, pAtt = pPort->pAdaptor->pAttributes; + i < pPort->pAdaptor->nAttributes; i++, pAtt++) + { + rep.text_size += pad_to_int32(strlen(pAtt->name) + 1); + } + + rep.length = (pPort->pAdaptor->nAttributes * sz_xvAttributeInfo) + + rep.text_size; + rep.length >>= 2; + + _WriteQueryPortAttributesReply(client, &rep); + + for(i = 0, pAtt = pPort->pAdaptor->pAttributes; + i < pPort->pAdaptor->nAttributes; i++, pAtt++) + { + size = strlen(pAtt->name) + 1; /* pass the NULL */ + Info.flags = pAtt->flags; + Info.min = pAtt->min_value; + Info.max = pAtt->max_value; + Info.size = pad_to_int32(size); + + _WriteAttributeInfo(client, &Info); + + WriteToClient(client, size, pAtt->name); + } + + return Success; +} + +static int +ProcXvPutImage(ClientPtr client) +{ + DrawablePtr pDraw; + XvPortPtr pPort; + XvImagePtr pImage = NULL; + GCPtr pGC; + int status, i, size; + CARD16 width, height; + + REQUEST(xvPutImageReq); + REQUEST_AT_LEAST_SIZE(xvPutImageReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + if (!(pPort->pAdaptor->type & XvImageMask) || + !(pPort->pAdaptor->type & XvInputMask)) + { + client->errorValue = stuff->port; + return (BadMatch); + } + + status = XvdiMatchPort(pPort, pDraw); + if (status != Success) + { + return status; + } + + for(i = 0; i < pPort->pAdaptor->nImages; i++) { + if(pPort->pAdaptor->pImages[i].id == stuff->id) { + pImage = &(pPort->pAdaptor->pImages[i]); + break; + } + } + + if(!pImage) + return BadMatch; + + width = stuff->width; + height = stuff->height; + size = (*pPort->pAdaptor->ddQueryImageAttributes)(client, + pPort, pImage, &width, &height, NULL, NULL); + size += sizeof(xvPutImageReq); + size = bytes_to_int32(size); + + if((width < stuff->width) || (height < stuff->height)) + return BadValue; + + if(client->req_len < size) + return BadLength; + + return XvdiPutImage(client, pDraw, pPort, pGC, stuff->src_x, stuff->src_y, + stuff->src_w, stuff->src_h, stuff->drw_x, stuff->drw_y, + stuff->drw_w, stuff->drw_h, pImage, + (unsigned char*)(&stuff[1]), FALSE, + stuff->width, stuff->height); +} + +#ifdef MITSHM +/* redefined here since it's not in any header file */ +typedef struct _ShmDesc { + struct _ShmDesc *next; + int shmid; + int refcnt; + char *addr; + Bool writable; + unsigned long size; +} ShmDescRec, *ShmDescPtr; + +extern RESTYPE ShmSegType; +extern int BadShmSegCode; +extern int ShmCompletionCode; + +static int +ProcXvShmPutImage(ClientPtr client) +{ + ShmDescPtr shmdesc; + DrawablePtr pDraw; + XvPortPtr pPort; + XvImagePtr pImage = NULL; + GCPtr pGC; + int status, size_needed, i; + CARD16 width, height; + + REQUEST(xvShmPutImageReq); + REQUEST_SIZE_MATCH(xvShmPutImageReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if ((status = _AllocatePort(stuff->port, pPort)) != Success) + { + client->errorValue = stuff->port; + return (status); + } + + if (!(pPort->pAdaptor->type & XvImageMask) || + !(pPort->pAdaptor->type & XvInputMask)) + { + client->errorValue = stuff->port; + return (BadMatch); + } + + status = XvdiMatchPort(pPort, pDraw); + if (status != Success) + { + return status; + } + + for(i = 0; i < pPort->pAdaptor->nImages; i++) { + if(pPort->pAdaptor->pImages[i].id == stuff->id) { + pImage = &(pPort->pAdaptor->pImages[i]); + break; + } + } + + if(!pImage) + return BadMatch; + + status = dixLookupResourceByType((pointer *)&shmdesc, stuff->shmseg, + ShmSegType, serverClient, DixReadAccess); + if (status != Success) + return (status == BadValue) ? BadShmSegCode : status; + + width = stuff->width; + height = stuff->height; + size_needed = (*pPort->pAdaptor->ddQueryImageAttributes)(client, + pPort, pImage, &width, &height, NULL, NULL); + if((size_needed + stuff->offset) > shmdesc->size) + return BadAccess; + + if((width < stuff->width) || (height < stuff->height)) + return BadValue; + + status = XvdiPutImage(client, pDraw, pPort, pGC, stuff->src_x, stuff->src_y, + stuff->src_w, stuff->src_h, stuff->drw_x, stuff->drw_y, + stuff->drw_w, stuff->drw_h, pImage, + (unsigned char *)shmdesc->addr + stuff->offset, + stuff->send_event, stuff->width, stuff->height); + + if((status == Success) && stuff->send_event) { + xShmCompletionEvent ev; + + ev.type = ShmCompletionCode; + ev.drawable = stuff->drawable; + ev.sequenceNumber = client->sequence; + ev.minorEvent = xv_ShmPutImage; + ev.majorEvent = XvReqCode; + ev.shmseg = stuff->shmseg; + ev.offset = stuff->offset; + WriteEventsToClient(client, 1, (xEvent *) &ev); + } + + return status; +} +#else /* !MITSHM */ +static int +ProcXvShmPutImage(ClientPtr client) +{ + SendErrorToClient(client, XvReqCode, xv_ShmPutImage, 0, BadImplementation); + return(BadImplementation); +} +#endif + +#ifdef XvMCExtension +#include "xvmcext.h" +#endif + +static int +ProcXvQueryImageAttributes(ClientPtr client) +{ + xvQueryImageAttributesReply rep; + int size, num_planes, i; + CARD16 width, height; + XvImagePtr pImage = NULL; + XvPortPtr pPort; + int *offsets; + int *pitches; + int planeLength; + REQUEST(xvQueryImageAttributesReq); + + REQUEST_SIZE_MATCH(xvQueryImageAttributesReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + for(i = 0; i < pPort->pAdaptor->nImages; i++) { + if(pPort->pAdaptor->pImages[i].id == stuff->id) { + pImage = &(pPort->pAdaptor->pImages[i]); + break; + } + } + +#ifdef XvMCExtension + if(!pImage) + pImage = XvMCFindXvImage(pPort, stuff->id); +#endif + + if(!pImage) + return BadMatch; + + num_planes = pImage->num_planes; + + if(!(offsets = malloc(num_planes << 3))) + return BadAlloc; + pitches = offsets + num_planes; + + width = stuff->width; + height = stuff->height; + + size = (*pPort->pAdaptor->ddQueryImageAttributes)(client, pPort, pImage, + &width, &height, offsets, pitches); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = planeLength = num_planes << 1; + rep.num_planes = num_planes; + rep.width = width; + rep.height = height; + rep.data_size = size; + + _WriteQueryImageAttributesReply(client, &rep); + if(client->swapped) + SwapLongs((CARD32*)offsets, planeLength); + WriteToClient(client, planeLength << 2, (char*)offsets); + + free(offsets); + + return Success; +} + +static int +ProcXvListImageFormats(ClientPtr client) +{ + XvPortPtr pPort; + XvImagePtr pImage; + int i; + xvListImageFormatsReply rep; + xvImageFormatInfo info; + REQUEST(xvListImageFormatsReq); + + REQUEST_SIZE_MATCH(xvListImageFormatsReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.num_formats = pPort->pAdaptor->nImages; + rep.length = bytes_to_int32(pPort->pAdaptor->nImages * sz_xvImageFormatInfo); + + _WriteListImageFormatsReply(client, &rep); + + pImage = pPort->pAdaptor->pImages; + + for(i = 0; i < pPort->pAdaptor->nImages; i++, pImage++) { + info.id = pImage->id; + info.type = pImage->type; + info.byte_order = pImage->byte_order; + memcpy(&info.guid, pImage->guid, 16); + info.bpp = pImage->bits_per_pixel; + info.num_planes = pImage->num_planes; + info.depth = pImage->depth; + info.red_mask = pImage->red_mask; + info.green_mask = pImage->green_mask; + info.blue_mask = pImage->blue_mask; + info.format = pImage->format; + info.y_sample_bits = pImage->y_sample_bits; + info.u_sample_bits = pImage->u_sample_bits; + info.v_sample_bits = pImage->v_sample_bits; + info.horz_y_period = pImage->horz_y_period; + info.horz_u_period = pImage->horz_u_period; + info.horz_v_period = pImage->horz_v_period; + info.vert_y_period = pImage->vert_y_period; + info.vert_u_period = pImage->vert_u_period; + info.vert_v_period = pImage->vert_v_period; + memcpy(&info.comp_order, pImage->component_order, 32); + info.scanline_order = pImage->scanline_order; + _WriteImageFormatInfo(client, &info); + } + + return Success; +} + +static int (*XvProcVector[xvNumRequests])(ClientPtr) = { + ProcXvQueryExtension, + ProcXvQueryAdaptors, + ProcXvQueryEncodings, + ProcXvGrabPort, + ProcXvUngrabPort, + ProcXvPutVideo, + ProcXvPutStill, + ProcXvGetVideo, + ProcXvGetStill, + ProcXvStopVideo, + ProcXvSelectVideoNotify, + ProcXvSelectPortNotify, + ProcXvQueryBestSize, + ProcXvSetPortAttribute, + ProcXvGetPortAttribute, + ProcXvQueryPortAttributes, + ProcXvListImageFormats, + ProcXvQueryImageAttributes, + ProcXvPutImage, + ProcXvShmPutImage, +}; + +int +ProcXvDispatch(ClientPtr client) +{ + REQUEST(xReq); + + UpdateCurrentTime(); + + if (stuff->data > xvNumRequests) { + SendErrorToClient(client, XvReqCode, stuff->data, 0, BadRequest); + return(BadRequest); + } + + return XvProcVector[stuff->data](client); +} + +/* Swapped Procs */ + +static int +SProcXvQueryExtension(ClientPtr client) +{ + char n; + REQUEST(xvQueryExtensionReq); + swaps(&stuff->length, n); + return XvProcVector[xv_QueryExtension](client); +} + +static int +SProcXvQueryAdaptors(ClientPtr client) +{ + char n; + REQUEST(xvQueryAdaptorsReq); + swaps(&stuff->length, n); + swapl(&stuff->window, n); + return XvProcVector[xv_QueryAdaptors](client); +} + +static int +SProcXvQueryEncodings(ClientPtr client) +{ + char n; + REQUEST(xvQueryEncodingsReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + return XvProcVector[xv_QueryEncodings](client); +} + +static int +SProcXvGrabPort(ClientPtr client) +{ + char n; + REQUEST(xvGrabPortReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->time, n); + return XvProcVector[xv_GrabPort](client); +} + +static int +SProcXvUngrabPort(ClientPtr client) +{ + char n; + REQUEST(xvUngrabPortReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->time, n); + return XvProcVector[xv_UngrabPort](client); +} + +static int +SProcXvPutVideo(ClientPtr client) +{ + char n; + REQUEST(xvPutVideoReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->drawable, n); + swapl(&stuff->gc, n); + swaps(&stuff->vid_x, n); + swaps(&stuff->vid_y, n); + swaps(&stuff->vid_w, n); + swaps(&stuff->vid_h, n); + swaps(&stuff->drw_x, n); + swaps(&stuff->drw_y, n); + swaps(&stuff->drw_w, n); + swaps(&stuff->drw_h, n); + return XvProcVector[xv_PutVideo](client); +} + +static int +SProcXvPutStill(ClientPtr client) +{ + char n; + REQUEST(xvPutStillReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->drawable, n); + swapl(&stuff->gc, n); + swaps(&stuff->vid_x, n); + swaps(&stuff->vid_y, n); + swaps(&stuff->vid_w, n); + swaps(&stuff->vid_h, n); + swaps(&stuff->drw_x, n); + swaps(&stuff->drw_y, n); + swaps(&stuff->drw_w, n); + swaps(&stuff->drw_h, n); + return XvProcVector[xv_PutStill](client); +} + +static int +SProcXvGetVideo(ClientPtr client) +{ + char n; + REQUEST(xvGetVideoReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->drawable, n); + swapl(&stuff->gc, n); + swaps(&stuff->vid_x, n); + swaps(&stuff->vid_y, n); + swaps(&stuff->vid_w, n); + swaps(&stuff->vid_h, n); + swaps(&stuff->drw_x, n); + swaps(&stuff->drw_y, n); + swaps(&stuff->drw_w, n); + swaps(&stuff->drw_h, n); + return XvProcVector[xv_GetVideo](client); +} + +static int +SProcXvGetStill(ClientPtr client) +{ + char n; + REQUEST(xvGetStillReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->drawable, n); + swapl(&stuff->gc, n); + swaps(&stuff->vid_x, n); + swaps(&stuff->vid_y, n); + swaps(&stuff->vid_w, n); + swaps(&stuff->vid_h, n); + swaps(&stuff->drw_x, n); + swaps(&stuff->drw_y, n); + swaps(&stuff->drw_w, n); + swaps(&stuff->drw_h, n); + return XvProcVector[xv_GetStill](client); +} + +static int +SProcXvPutImage(ClientPtr client) +{ + char n; + REQUEST(xvPutImageReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->drawable, n); + swapl(&stuff->gc, n); + swapl(&stuff->id, n); + swaps(&stuff->src_x, n); + swaps(&stuff->src_y, n); + swaps(&stuff->src_w, n); + swaps(&stuff->src_h, n); + swaps(&stuff->drw_x, n); + swaps(&stuff->drw_y, n); + swaps(&stuff->drw_w, n); + swaps(&stuff->drw_h, n); + swaps(&stuff->width, n); + swaps(&stuff->height, n); + return XvProcVector[xv_PutImage](client); +} + +#ifdef MITSHM +static int +SProcXvShmPutImage(ClientPtr client) +{ + char n; + REQUEST(xvShmPutImageReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->drawable, n); + swapl(&stuff->gc, n); + swapl(&stuff->shmseg, n); + swapl(&stuff->id, n); + swapl(&stuff->offset, n); + swaps(&stuff->src_x, n); + swaps(&stuff->src_y, n); + swaps(&stuff->src_w, n); + swaps(&stuff->src_h, n); + swaps(&stuff->drw_x, n); + swaps(&stuff->drw_y, n); + swaps(&stuff->drw_w, n); + swaps(&stuff->drw_h, n); + swaps(&stuff->width, n); + swaps(&stuff->height, n); + return XvProcVector[xv_ShmPutImage](client); +} +#else /* MITSHM */ +#define SProcXvShmPutImage ProcXvShmPutImage +#endif + +static int +SProcXvSelectVideoNotify(ClientPtr client) +{ + char n; + REQUEST(xvSelectVideoNotifyReq); + swaps(&stuff->length, n); + swapl(&stuff->drawable, n); + return XvProcVector[xv_SelectVideoNotify](client); +} + +static int +SProcXvSelectPortNotify(ClientPtr client) +{ + char n; + REQUEST(xvSelectPortNotifyReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + return XvProcVector[xv_SelectPortNotify](client); +} + +static int +SProcXvStopVideo(ClientPtr client) +{ + char n; + REQUEST(xvStopVideoReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->drawable, n); + return XvProcVector[xv_StopVideo](client); +} + +static int +SProcXvSetPortAttribute(ClientPtr client) +{ + char n; + REQUEST(xvSetPortAttributeReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->attribute, n); + swapl(&stuff->value, n); + return XvProcVector[xv_SetPortAttribute](client); +} + +static int +SProcXvGetPortAttribute(ClientPtr client) +{ + char n; + REQUEST(xvGetPortAttributeReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->attribute, n); + return XvProcVector[xv_GetPortAttribute](client); +} + +static int +SProcXvQueryBestSize(ClientPtr client) +{ + char n; + REQUEST(xvQueryBestSizeReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swaps(&stuff->vid_w, n); + swaps(&stuff->vid_h, n); + swaps(&stuff->drw_w, n); + swaps(&stuff->drw_h, n); + return XvProcVector[xv_QueryBestSize](client); +} + +static int +SProcXvQueryPortAttributes(ClientPtr client) +{ + char n; + REQUEST(xvQueryPortAttributesReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + return XvProcVector[xv_QueryPortAttributes](client); +} + +static int +SProcXvQueryImageAttributes(ClientPtr client) +{ + char n; + REQUEST(xvQueryImageAttributesReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + swapl(&stuff->id, n); + swaps(&stuff->width, n); + swaps(&stuff->height, n); + return XvProcVector[xv_QueryImageAttributes](client); +} + +static int +SProcXvListImageFormats(ClientPtr client) +{ + char n; + REQUEST(xvListImageFormatsReq); + swaps(&stuff->length, n); + swapl(&stuff->port, n); + return XvProcVector[xv_ListImageFormats](client); +} + +static int (*SXvProcVector[xvNumRequests])(ClientPtr) = { + SProcXvQueryExtension, + SProcXvQueryAdaptors, + SProcXvQueryEncodings, + SProcXvGrabPort, + SProcXvUngrabPort, + SProcXvPutVideo, + SProcXvPutStill, + SProcXvGetVideo, + SProcXvGetStill, + SProcXvStopVideo, + SProcXvSelectVideoNotify, + SProcXvSelectPortNotify, + SProcXvQueryBestSize, + SProcXvSetPortAttribute, + SProcXvGetPortAttribute, + SProcXvQueryPortAttributes, + SProcXvListImageFormats, + SProcXvQueryImageAttributes, + SProcXvPutImage, + SProcXvShmPutImage, +}; + +int +SProcXvDispatch(ClientPtr client) +{ + REQUEST(xReq); + + UpdateCurrentTime(); + + if (stuff->data > xvNumRequests) { + SendErrorToClient(client, XvReqCode, stuff->data, 0, BadRequest); + return(BadRequest); + } + + return SXvProcVector[stuff->data](client); +} + +#ifdef PANORAMIX +static int +XineramaXvStopVideo(ClientPtr client) +{ + int result, i; + PanoramiXRes *draw, *port; + REQUEST(xvStopVideoReq); + REQUEST_SIZE_MATCH(xvStopVideoReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + result = dixLookupResourceByType((pointer *)&port, stuff->port, + XvXRTPort, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? _XvBadPort : result; + + FOR_NSCREENS_BACKWARD(i) { + if(port->info[i].id) { + stuff->drawable = draw->info[i].id; + stuff->port = port->info[i].id; + result = ProcXvStopVideo(client); + } + } + + return result; +} + +static int +XineramaXvSetPortAttribute(ClientPtr client) +{ + REQUEST(xvSetPortAttributeReq); + PanoramiXRes *port; + int result, i; + + REQUEST_SIZE_MATCH(xvSetPortAttributeReq); + + result = dixLookupResourceByType((pointer *)&port, stuff->port, + XvXRTPort, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? _XvBadPort : result; + + FOR_NSCREENS_BACKWARD(i) { + if(port->info[i].id) { + stuff->port = port->info[i].id; + result = ProcXvSetPortAttribute(client); + } + } + return result; +} + +#ifdef MITSHM +static int +XineramaXvShmPutImage(ClientPtr client) +{ + REQUEST(xvShmPutImageReq); + PanoramiXRes *draw, *gc, *port; + Bool send_event = stuff->send_event; + Bool isRoot; + int result, i, x, y; + + REQUEST_SIZE_MATCH(xvShmPutImageReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, + XRT_GC, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + result = dixLookupResourceByType((pointer *)&port, stuff->port, + XvXRTPort, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? _XvBadPort : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + x = stuff->drw_x; + y = stuff->drw_y; + + FOR_NSCREENS_BACKWARD(i) { + if(port->info[i].id) { + stuff->drawable = draw->info[i].id; + stuff->port = port->info[i].id; + stuff->gc = gc->info[i].id; + stuff->drw_x = x; + stuff->drw_y = y; + if(isRoot) { + stuff->drw_x -= panoramiXdataPtr[i].x; + stuff->drw_y -= panoramiXdataPtr[i].y; + } + stuff->send_event = (send_event && !i) ? 1 : 0; + + result = ProcXvShmPutImage(client); + } + } + return result; +} +#else +#define XineramaXvShmPutImage ProcXvShmPutImage +#endif + +static int +XineramaXvPutImage(ClientPtr client) +{ + REQUEST(xvPutImageReq); + PanoramiXRes *draw, *gc, *port; + Bool isRoot; + int result, i, x, y; + + REQUEST_AT_LEAST_SIZE(xvPutImageReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, + XRT_GC, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + result = dixLookupResourceByType((pointer *)&port, stuff->port, + XvXRTPort, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? _XvBadPort : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + x = stuff->drw_x; + y = stuff->drw_y; + + FOR_NSCREENS_BACKWARD(i) { + if(port->info[i].id) { + stuff->drawable = draw->info[i].id; + stuff->port = port->info[i].id; + stuff->gc = gc->info[i].id; + stuff->drw_x = x; + stuff->drw_y = y; + if(isRoot) { + stuff->drw_x -= panoramiXdataPtr[i].x; + stuff->drw_y -= panoramiXdataPtr[i].y; + } + + result = ProcXvPutImage(client); + } + } + return result; +} + +static int +XineramaXvPutVideo(ClientPtr client) +{ + REQUEST(xvPutImageReq); + PanoramiXRes *draw, *gc, *port; + Bool isRoot; + int result, i, x, y; + + REQUEST_AT_LEAST_SIZE(xvPutVideoReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, + XRT_GC, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + result = dixLookupResourceByType((pointer *)&port, stuff->port, + XvXRTPort, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? _XvBadPort : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + x = stuff->drw_x; + y = stuff->drw_y; + + FOR_NSCREENS_BACKWARD(i) { + if(port->info[i].id) { + stuff->drawable = draw->info[i].id; + stuff->port = port->info[i].id; + stuff->gc = gc->info[i].id; + stuff->drw_x = x; + stuff->drw_y = y; + if(isRoot) { + stuff->drw_x -= panoramiXdataPtr[i].x; + stuff->drw_y -= panoramiXdataPtr[i].y; + } + + result = ProcXvPutVideo(client); + } + } + return result; +} + +static int +XineramaXvPutStill(ClientPtr client) +{ + REQUEST(xvPutImageReq); + PanoramiXRes *draw, *gc, *port; + Bool isRoot; + int result, i, x, y; + + REQUEST_AT_LEAST_SIZE(xvPutImageReq); + + result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, + XRC_DRAWABLE, client, DixWriteAccess); + if (result != Success) + return (result == BadValue) ? BadDrawable : result; + + result = dixLookupResourceByType((pointer *)&gc, stuff->gc, + XRT_GC, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? BadGC : result; + + result = dixLookupResourceByType((pointer *)&port, stuff->port, + XvXRTPort, client, DixReadAccess); + if (result != Success) + return (result == BadValue) ? _XvBadPort : result; + + isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; + + x = stuff->drw_x; + y = stuff->drw_y; + + FOR_NSCREENS_BACKWARD(i) { + if(port->info[i].id) { + stuff->drawable = draw->info[i].id; + stuff->port = port->info[i].id; + stuff->gc = gc->info[i].id; + stuff->drw_x = x; + stuff->drw_y = y; + if(isRoot) { + stuff->drw_x -= panoramiXdataPtr[i].x; + stuff->drw_y -= panoramiXdataPtr[i].y; + } + + result = ProcXvPutStill(client); + } + } + return result; +} + +static Bool +isImageAdaptor(XvAdaptorPtr pAdapt) +{ + return (pAdapt->type & XvImageMask) && (pAdapt->nImages > 0); +} + +static Bool +hasOverlay(XvAdaptorPtr pAdapt) +{ + int i; + for(i = 0; i < pAdapt->nAttributes; i++) + if(!strcmp(pAdapt->pAttributes[i].name, "XV_COLORKEY")) + return TRUE; + return FALSE; +} + +static XvAdaptorPtr +matchAdaptor(ScreenPtr pScreen, XvAdaptorPtr refAdapt, Bool isOverlay) +{ + int i; + XvScreenPtr xvsp = dixLookupPrivate(&pScreen->devPrivates, XvGetScreenKey()); + /* Do not try to go on if xv is not supported on this screen */ + if(xvsp == NULL) + return NULL; + + /* if the adaptor has the same name it's a perfect match */ + for(i = 0; i < xvsp->nAdaptors; i++) { + XvAdaptorPtr pAdapt = xvsp->pAdaptors + i; + if(!strcmp(refAdapt->name, pAdapt->name)) + return pAdapt; + } + + /* otherwise we only look for XvImage adaptors */ + if(!isImageAdaptor(refAdapt)) + return NULL; + + /* prefer overlay/overlay non-overlay/non-overlay pairing */ + for(i = 0; i < xvsp->nAdaptors; i++) { + XvAdaptorPtr pAdapt = xvsp->pAdaptors + i; + if(isImageAdaptor(pAdapt) && isOverlay == hasOverlay(pAdapt)) + return pAdapt; + } + + /* but we'll take any XvImage pairing if we can get it */ + for(i = 0; i < xvsp->nAdaptors; i++) { + XvAdaptorPtr pAdapt = xvsp->pAdaptors + i; + if(isImageAdaptor(pAdapt)) + return pAdapt; + } + return NULL; +} + +void XineramifyXv(void) +{ + XvScreenPtr xvsp0 = dixLookupPrivate(&screenInfo.screens[0]->devPrivates, XvGetScreenKey()); + XvAdaptorPtr MatchingAdaptors[MAXSCREENS]; + int i, j, k; + + XvXRTPort = CreateNewResourceType(XineramaDeleteResource, "XvXRTPort"); + + if (!xvsp0 || !XvXRTPort) return; + + for(i = 0; i < xvsp0->nAdaptors; i++) { + Bool isOverlay; + XvAdaptorPtr refAdapt = xvsp0->pAdaptors + i; + if(!(refAdapt->type & XvInputMask)) continue; + + MatchingAdaptors[0] = refAdapt; + isOverlay = hasOverlay(refAdapt); + for(j = 1; j < PanoramiXNumScreens; j++) + MatchingAdaptors[j] = matchAdaptor(screenInfo.screens[j], refAdapt, isOverlay); + + /* now create a resource for each port */ + for(j = 0; j < refAdapt->nPorts; j++) { + PanoramiXRes *port = malloc(sizeof(PanoramiXRes)); + if(!port) + break; + + for(k = 0; k < PanoramiXNumScreens; k++) { + if(MatchingAdaptors[k] && (MatchingAdaptors[k]->nPorts > j)) + port->info[k].id = MatchingAdaptors[k]->base_id + j; + else + port->info[k].id = 0; + } + AddResource(port->info[0].id, XvXRTPort, port); + } + } + + /* munge the dispatch vector */ + XvProcVector[xv_PutVideo] = XineramaXvPutVideo; + XvProcVector[xv_PutStill] = XineramaXvPutStill; + XvProcVector[xv_StopVideo] = XineramaXvStopVideo; + XvProcVector[xv_SetPortAttribute] = XineramaXvSetPortAttribute; + XvProcVector[xv_PutImage] = XineramaXvPutImage; + XvProcVector[xv_ShmPutImage] = XineramaXvShmPutImage; +} +#endif /* PANORAMIX */ + +void +XvResetProcVector(void) +{ +#ifdef PANORAMIX + XvProcVector[xv_PutVideo] = ProcXvPutVideo; + XvProcVector[xv_PutStill] = ProcXvPutStill; + XvProcVector[xv_StopVideo] = ProcXvStopVideo; + XvProcVector[xv_SetPortAttribute] = ProcXvSetPortAttribute; + XvProcVector[xv_PutImage] = ProcXvPutImage; + XvProcVector[xv_ShmPutImage] = ProcXvShmPutImage; +#endif +} diff --git a/xorg-server/Xext/xvmain.c b/xorg-server/Xext/xvmain.c index 05a68907a..413b94015 100644 --- a/xorg-server/Xext/xvmain.c +++ b/xorg-server/Xext/xvmain.c @@ -1,1190 +1,1188 @@ -/*********************************************************** -Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts, -and the Massachusetts Institute of Technology, Cambridge, 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 names of Digital or MIT 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. - -******************************************************************/ - -/* -** File: -** -** xvmain.c --- Xv server extension main device independent module. -** -** Author: -** -** David Carver (Digital Workstation Engineering/Project Athena) -** -** Revisions: -** -** 04.09.91 Carver -** - change: stop video always generates an event even when video -** wasn't active -** -** 29.08.91 Carver -** - change: unrealizing windows no longer preempts video -** -** 11.06.91 Carver -** - changed SetPortControl to SetPortAttribute -** - changed GetPortControl to GetPortAttribute -** - changed QueryBestSize -** -** 28.05.91 Carver -** - fixed Put and Get requests to not preempt operations to same drawable -** -** 15.05.91 Carver -** - version 2.0 upgrade -** -** 19.03.91 Carver -** - fixed Put and Get requests to honor grabbed ports. -** - fixed Video requests to update di structure with new drawable, and -** client after calling ddx. -** -** 24.01.91 Carver -** - version 1.4 upgrade -** -** Notes: -** -** Port structures reference client structures in a two different -** ways: when grabs, or video is active. Each reference is encoded -** as fake client resources and thus when the client is goes away so -** does the reference (it is zeroed). No other action is taken, so -** video doesn't necessarily stop. It probably will as a result of -** other resources going away, but if a client starts video using -** none of its own resources, then the video will continue to play -** after the client disappears. -** -** -*/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include -#include -#include "misc.h" -#include "os.h" -#include "scrnintstr.h" -#include "windowstr.h" -#include "pixmapstr.h" -#include "gc.h" -#include "extnsionst.h" -#include "dixstruct.h" -#include "resource.h" -#include "opaque.h" -#include "input.h" - -#define GLOBAL - -#include -#include -#include "xvdix.h" - -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#include "xvdisp.h" - -static int XvScreenKeyIndex; -static DevPrivateKey XvScreenKey = &XvScreenKeyIndex; -unsigned long XvExtensionGeneration = 0; -unsigned long XvScreenGeneration = 0; -unsigned long XvResourceGeneration = 0; - -int XvReqCode; -int XvEventBase; -int XvErrorBase; - -unsigned long XvRTPort; -unsigned long XvRTEncoding; -unsigned long XvRTGrab; -unsigned long XvRTVideoNotify; -unsigned long XvRTVideoNotifyList; -unsigned long XvRTPortNotify; - - - -/* EXTERNAL */ - -extern XID clientErrorValue; - -static void WriteSwappedVideoNotifyEvent(xvEvent *, xvEvent *); -static void WriteSwappedPortNotifyEvent(xvEvent *, xvEvent *); -static Bool CreateResourceTypes(void); - -static Bool XvCloseScreen(int, ScreenPtr); -static Bool XvDestroyPixmap(PixmapPtr); -static Bool XvDestroyWindow(WindowPtr); -static void XvResetProc(ExtensionEntry*); -static int XvdiDestroyGrab(pointer, XID); -static int XvdiDestroyEncoding(pointer, XID); -static int XvdiDestroyVideoNotify(pointer, XID); -static int XvdiDestroyPortNotify(pointer, XID); -static int XvdiDestroyVideoNotifyList(pointer, XID); -static int XvdiDestroyPort(pointer, XID); -static int XvdiSendVideoNotify(XvPortPtr, DrawablePtr, int); - - - - -/* -** XvExtensionInit -** -** -*/ - -void -XvExtensionInit(void) -{ - ExtensionEntry *extEntry; - - /* LOOK TO SEE IF ANY SCREENS WERE INITIALIZED; IF NOT THEN - INIT GLOBAL VARIABLES SO THE EXTENSION CAN FUNCTION */ - if (XvScreenGeneration != serverGeneration) - { - if (!CreateResourceTypes()) - { - ErrorF("XvExtensionInit: Unable to allocate resource types\n"); - return; - } -#ifdef PANORAMIX - XineramaRegisterConnectionBlockCallback(XineramifyXv); -#endif - XvScreenGeneration = serverGeneration; - } - - if (XvExtensionGeneration != serverGeneration) - { - XvExtensionGeneration = serverGeneration; - - extEntry = AddExtension(XvName, XvNumEvents, XvNumErrors, - ProcXvDispatch, SProcXvDispatch, - XvResetProc, StandardMinorOpcode); - if (!extEntry) - { - FatalError("XvExtensionInit: AddExtensions failed\n"); - } - - XvReqCode = extEntry->base; - XvEventBase = extEntry->eventBase; - XvErrorBase = extEntry->errorBase; - - EventSwapVector[XvEventBase+XvVideoNotify] = - (EventSwapPtr)WriteSwappedVideoNotifyEvent; - EventSwapVector[XvEventBase+XvPortNotify] = - (EventSwapPtr)WriteSwappedPortNotifyEvent; - - (void)MakeAtom(XvName, strlen(XvName), xTrue); - - } -} - -static Bool -CreateResourceTypes(void) - -{ - - if (XvResourceGeneration == serverGeneration) return TRUE; - - XvResourceGeneration = serverGeneration; - - if (!(XvRTPort = CreateNewResourceType(XvdiDestroyPort, "XvRTPort"))) - { - ErrorF("CreateResourceTypes: failed to allocate port resource.\n"); - return FALSE; - } - - if (!(XvRTGrab = CreateNewResourceType(XvdiDestroyGrab, "XvRTGrab"))) - { - ErrorF("CreateResourceTypes: failed to allocate grab resource.\n"); - return FALSE; - } - - if (!(XvRTEncoding = CreateNewResourceType(XvdiDestroyEncoding, - "XvRTEncoding"))) - { - ErrorF("CreateResourceTypes: failed to allocate encoding resource.\n"); - return FALSE; - } - - if (!(XvRTVideoNotify = CreateNewResourceType(XvdiDestroyVideoNotify, - "XvRTVideoNotify"))) - { - ErrorF("CreateResourceTypes: failed to allocate video notify resource.\n"); - return FALSE; - } - - if (!(XvRTVideoNotifyList = CreateNewResourceType(XvdiDestroyVideoNotifyList, - "XvRTVideoNotifyList"))) - { - ErrorF("CreateResourceTypes: failed to allocate video notify list resource.\n"); - return FALSE; - } - - if (!(XvRTPortNotify = CreateNewResourceType(XvdiDestroyPortNotify, - "XvRTPortNotify"))) - { - ErrorF("CreateResourceTypes: failed to allocate port notify resource.\n"); - return FALSE; - } - - return TRUE; - -} - -int -XvScreenInit(ScreenPtr pScreen) -{ - XvScreenPtr pxvs; - - if (XvScreenGeneration != serverGeneration) - { - if (!CreateResourceTypes()) - { - ErrorF("XvScreenInit: Unable to allocate resource types\n"); - return BadAlloc; - } -#ifdef PANORAMIX - XineramaRegisterConnectionBlockCallback(XineramifyXv); -#endif - XvScreenGeneration = serverGeneration; - } - - if (dixLookupPrivate(&pScreen->devPrivates, XvScreenKey)) - { - ErrorF("XvScreenInit: screen devPrivates ptr non-NULL before init\n"); - } - - /* ALLOCATE SCREEN PRIVATE RECORD */ - - pxvs = xalloc (sizeof (XvScreenRec)); - if (!pxvs) - { - ErrorF("XvScreenInit: Unable to allocate screen private structure\n"); - return BadAlloc; - } - - dixSetPrivate(&pScreen->devPrivates, XvScreenKey, pxvs); - - - pxvs->DestroyPixmap = pScreen->DestroyPixmap; - pxvs->DestroyWindow = pScreen->DestroyWindow; - pxvs->CloseScreen = pScreen->CloseScreen; - - pScreen->DestroyPixmap = XvDestroyPixmap; - pScreen->DestroyWindow = XvDestroyWindow; - pScreen->CloseScreen = XvCloseScreen; - - return Success; -} - -static Bool -XvCloseScreen( - int ii, - ScreenPtr pScreen -){ - - XvScreenPtr pxvs; - - pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XvScreenKey); - - pScreen->DestroyPixmap = pxvs->DestroyPixmap; - pScreen->DestroyWindow = pxvs->DestroyWindow; - pScreen->CloseScreen = pxvs->CloseScreen; - - (* pxvs->ddCloseScreen)(ii, pScreen); - - xfree(pxvs); - - dixSetPrivate(&pScreen->devPrivates, XvScreenKey, NULL); - - return (*pScreen->CloseScreen)(ii, pScreen); -} - -static void -XvResetProc(ExtensionEntry* extEntry) -{ - XvResetProcVector(); -} - -DevPrivateKey -XvGetScreenKey(void) -{ - return XvScreenKey; -} - -unsigned long -XvGetRTPort(void) -{ - return XvRTPort; -} - -static Bool -XvDestroyPixmap(PixmapPtr pPix) -{ - Bool status; - ScreenPtr pScreen; - XvScreenPtr pxvs; - XvAdaptorPtr pa; - int na; - XvPortPtr pp; - int np; - - pScreen = pPix->drawable.pScreen; - - SCREEN_PROLOGUE(pScreen, DestroyPixmap); - - pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XvScreenKey); - - /* CHECK TO SEE IF THIS PORT IS IN USE */ - - pa = pxvs->pAdaptors; - na = pxvs->nAdaptors; - while (na--) - { - np = pa->nPorts; - pp = pa->pPorts; - - while (np--) - { - if (pp->pDraw == (DrawablePtr)pPix) - { - XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted); - - (void)(* pp->pAdaptor->ddStopVideo)(NULL, pp, pp->pDraw); - - pp->pDraw = NULL; - pp->client = NULL; - pp->time = currentTime; - } - pp++; - } - pa++; - } - - status = (* pScreen->DestroyPixmap)(pPix); - - SCREEN_EPILOGUE(pScreen, DestroyPixmap, XvDestroyPixmap); - - return status; - -} - -static Bool -XvDestroyWindow(WindowPtr pWin) -{ - Bool status; - ScreenPtr pScreen; - XvScreenPtr pxvs; - XvAdaptorPtr pa; - int na; - XvPortPtr pp; - int np; - - pScreen = pWin->drawable.pScreen; - - SCREEN_PROLOGUE(pScreen, DestroyWindow); - - pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XvScreenKey); - - /* CHECK TO SEE IF THIS PORT IS IN USE */ - - pa = pxvs->pAdaptors; - na = pxvs->nAdaptors; - while (na--) - { - np = pa->nPorts; - pp = pa->pPorts; - - while (np--) - { - if (pp->pDraw == (DrawablePtr)pWin) - { - XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted); - - (void)(* pp->pAdaptor->ddStopVideo)(NULL, pp, pp->pDraw); - - pp->pDraw = NULL; - pp->client = NULL; - pp->time = currentTime; - } - pp++; - } - pa++; - } - - - status = (* pScreen->DestroyWindow)(pWin); - - SCREEN_EPILOGUE(pScreen, DestroyWindow, XvDestroyWindow); - - return status; - -} - -/* The XvdiVideoStopped procedure is a hook for the device dependent layer. - It provides a way for the dd layer to inform the di layer that video has - stopped in a port for reasons that the di layer had no control over; note - that it doesn't call back into the dd layer */ - -int -XvdiVideoStopped(XvPortPtr pPort, int reason) -{ - - /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */ - - if (!pPort->pDraw) return Success; - - XvdiSendVideoNotify(pPort, pPort->pDraw, reason); - - pPort->pDraw = NULL; - pPort->client = NULL; - pPort->time = currentTime; - - return Success; - -} - -static int -XvdiDestroyPort(pointer pPort, XID id) -{ - return (* ((XvPortPtr)pPort)->pAdaptor->ddFreePort)(pPort); -} - -static int -XvdiDestroyGrab(pointer pGrab, XID id) -{ - ((XvGrabPtr)pGrab)->client = NULL; - return Success; -} - -static int -XvdiDestroyVideoNotify(pointer pn, XID id) -{ - /* JUST CLEAR OUT THE client POINTER FIELD */ - - ((XvVideoNotifyPtr)pn)->client = NULL; - return Success; -} - -static int -XvdiDestroyPortNotify(pointer pn, XID id) -{ - /* JUST CLEAR OUT THE client POINTER FIELD */ - - ((XvPortNotifyPtr)pn)->client = NULL; - return Success; -} - -static int -XvdiDestroyVideoNotifyList(pointer pn, XID id) -{ - XvVideoNotifyPtr npn,cpn; - - /* ACTUALLY DESTROY THE NOTITY LIST */ - - cpn = (XvVideoNotifyPtr)pn; - - while (cpn) - { - npn = cpn->next; - if (cpn->client) FreeResource(cpn->id, XvRTVideoNotify); - xfree(cpn); - cpn = npn; - } - return Success; -} - -static int -XvdiDestroyEncoding(pointer value, XID id) -{ - return Success; -} - -static int -XvdiSendVideoNotify(XvPortPtr pPort, DrawablePtr pDraw, int reason) -{ - xvEvent event; - XvVideoNotifyPtr pn; - - dixLookupResourceByType((pointer *)&pn, pDraw->id, XvRTVideoNotifyList, - serverClient, DixReadAccess); - - while (pn) - { - if (pn->client) - { - event.u.u.type = XvEventBase + XvVideoNotify; - event.u.u.sequenceNumber = pn->client->sequence; - event.u.videoNotify.time = currentTime.milliseconds; - event.u.videoNotify.drawable = pDraw->id; - event.u.videoNotify.port = pPort->id; - event.u.videoNotify.reason = reason; - TryClientEvents(pn->client, NULL, (xEventPtr)&event, 1, - NoEventMask, NoEventMask, NullGrab); - } - pn = pn->next; - } - - return Success; - -} - - -int -XvdiSendPortNotify( - XvPortPtr pPort, - Atom attribute, - INT32 value -){ - xvEvent event; - XvPortNotifyPtr pn; - - pn = pPort->pNotify; - - while (pn) - { - if (pn->client) - { - event.u.u.type = XvEventBase + XvPortNotify; - event.u.u.sequenceNumber = pn->client->sequence; - event.u.portNotify.time = currentTime.milliseconds; - event.u.portNotify.port = pPort->id; - event.u.portNotify.attribute = attribute; - event.u.portNotify.value = value; - TryClientEvents(pn->client, NULL, (xEventPtr)&event, 1, - NoEventMask, NoEventMask, NullGrab); - } - pn = pn->next; - } - - return Success; - -} - - -#define CHECK_SIZE(dw, dh, sw, sh) { \ - if(!dw || !dh || !sw || !sh) return Success; \ - /* The region code will break these if they are too large */ \ - if((dw > 32767) || (dh > 32767) || (sw > 32767) || (sh > 32767)) \ - return BadValue; \ -} - - -int -XvdiPutVideo( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - DrawablePtr pOldDraw; - - CHECK_SIZE(drw_w, drw_h, vid_w, vid_h); - - /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ - - UpdateCurrentTime(); - - /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN - INFORM CLIENT OF ITS FAILURE */ - - if (pPort->grab.client && (pPort->grab.client != client)) - { - XvdiSendVideoNotify(pPort, pDraw, XvBusy); - return Success; - } - - /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED - EVENTS TO ANY CLIENTS WHO WANT THEM */ - - pOldDraw = pPort->pDraw; - if ((pOldDraw) && (pOldDraw != pDraw)) - { - XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted); - } - - (void) (* pPort->pAdaptor->ddPutVideo)(client, pDraw, pPort, pGC, - vid_x, vid_y, vid_w, vid_h, - drw_x, drw_y, drw_w, drw_h); - - if ((pPort->pDraw) && (pOldDraw != pDraw)) - { - pPort->client = client; - XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted); - } - - pPort->time = currentTime; - - return (Success); - -} - -int -XvdiPutStill( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - int status; - - CHECK_SIZE(drw_w, drw_h, vid_w, vid_h); - - /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ - - UpdateCurrentTime(); - - /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN - INFORM CLIENT OF ITS FAILURE */ - - if (pPort->grab.client && (pPort->grab.client != client)) - { - XvdiSendVideoNotify(pPort, pDraw, XvBusy); - return Success; - } - - pPort->time = currentTime; - - status = (* pPort->pAdaptor->ddPutStill)(client, pDraw, pPort, pGC, - vid_x, vid_y, vid_w, vid_h, - drw_x, drw_y, drw_w, drw_h); - - return status; - -} - -int -XvdiPutImage( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 src_x, INT16 src_y, - CARD16 src_w, CARD16 src_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h, - XvImagePtr image, - unsigned char* data, - Bool sync, - CARD16 width, CARD16 height -){ - CHECK_SIZE(drw_w, drw_h, src_w, src_h); - - /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ - - UpdateCurrentTime(); - - /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN - INFORM CLIENT OF ITS FAILURE */ - - if (pPort->grab.client && (pPort->grab.client != client)) - { - XvdiSendVideoNotify(pPort, pDraw, XvBusy); - return Success; - } - - pPort->time = currentTime; - - return (* pPort->pAdaptor->ddPutImage)(client, pDraw, pPort, pGC, - src_x, src_y, src_w, src_h, - drw_x, drw_y, drw_w, drw_h, - image, data, sync, width, height); -} - - -int -XvdiGetVideo( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - DrawablePtr pOldDraw; - - CHECK_SIZE(drw_w, drw_h, vid_w, vid_h); - - /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ - - UpdateCurrentTime(); - - /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN - INFORM CLIENT OF ITS FAILURE */ - - if (pPort->grab.client && (pPort->grab.client != client)) - { - XvdiSendVideoNotify(pPort, pDraw, XvBusy); - return Success; - } - - /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED - EVENTS TO ANY CLIENTS WHO WANT THEM */ - - pOldDraw = pPort->pDraw; - if ((pOldDraw) && (pOldDraw != pDraw)) - { - XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted); - } - - (void) (* pPort->pAdaptor->ddGetVideo)(client, pDraw, pPort, pGC, - vid_x, vid_y, vid_w, vid_h, - drw_x, drw_y, drw_w, drw_h); - - if ((pPort->pDraw) && (pOldDraw != pDraw)) - { - pPort->client = client; - XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted); - } - - pPort->time = currentTime; - - return (Success); - -} - -int -XvdiGetStill( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - int status; - - CHECK_SIZE(drw_w, drw_h, vid_w, vid_h); - - /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ - - UpdateCurrentTime(); - - /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN - INFORM CLIENT OF ITS FAILURE */ - - if (pPort->grab.client && (pPort->grab.client != client)) - { - XvdiSendVideoNotify(pPort, pDraw, XvBusy); - return Success; - } - - status = (* pPort->pAdaptor->ddGetStill)(client, pDraw, pPort, pGC, - vid_x, vid_y, vid_w, vid_h, - drw_x, drw_y, drw_w, drw_h); - - pPort->time = currentTime; - - return status; - -} - -int -XvdiGrabPort( - ClientPtr client, - XvPortPtr pPort, - Time ctime, - int *p_result -){ - unsigned long id; - TimeStamp time; - - UpdateCurrentTime(); - time = ClientTimeToServerTime(ctime); - - if (pPort->grab.client && (client != pPort->grab.client)) - { - *p_result = XvAlreadyGrabbed; - return Success; - } - - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, pPort->time) == EARLIER)) - { - *p_result = XvInvalidTime; - return Success; - } - - if (client == pPort->grab.client) - { - *p_result = Success; - return Success; - } - - id = FakeClientID(client->index); - - if (!AddResource(id, XvRTGrab, &pPort->grab)) - { - return BadAlloc; - } - - /* IF THERE IS ACTIVE VIDEO THEN STOP IT */ - - if ((pPort->pDraw) && (client != pPort->client)) - { - XvdiStopVideo(NULL, pPort, pPort->pDraw); - } - - pPort->grab.client = client; - pPort->grab.id = id; - - pPort->time = currentTime; - - *p_result = Success; - - return Success; - -} - -int -XvdiUngrabPort( - ClientPtr client, - XvPortPtr pPort, - Time ctime -){ - TimeStamp time; - - UpdateCurrentTime(); - time = ClientTimeToServerTime(ctime); - - if ((!pPort->grab.client) || (client != pPort->grab.client)) - { - return Success; - } - - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, pPort->time) == EARLIER)) - { - return Success; - } - - /* FREE THE GRAB RESOURCE; AND SET THE GRAB CLIENT TO NULL */ - - FreeResource(pPort->grab.id, XvRTGrab); - pPort->grab.client = NULL; - - pPort->time = currentTime; - - return Success; - -} - - -int -XvdiSelectVideoNotify( - ClientPtr client, - DrawablePtr pDraw, - BOOL onoff -){ - XvVideoNotifyPtr pn,tpn,fpn; - int rc; - - /* FIND VideoNotify LIST */ - - rc = dixLookupResourceByType((pointer *)&pn, pDraw->id, XvRTVideoNotifyList, - client, DixWriteAccess); - if (rc != Success && rc != BadValue) - return rc; - - /* IF ONE DONES'T EXIST AND NO MASK, THEN JUST RETURN */ - - if (!onoff && !pn) return Success; - - /* IF ONE DOESN'T EXIST CREATE IT AND ADD A RESOURCE SO THAT THE LIST - WILL BE DELETED WHEN THE DRAWABLE IS DESTROYED */ - - if (!pn) - { - if (!(tpn = xalloc(sizeof(XvVideoNotifyRec)))) - return BadAlloc; - tpn->next = NULL; - if (!AddResource(pDraw->id, XvRTVideoNotifyList, tpn)) - { - xfree(tpn); - return BadAlloc; - } - } - else - { - /* LOOK TO SEE IF ENTRY ALREADY EXISTS */ - - fpn = NULL; - tpn = pn; - while (tpn) - { - if (tpn->client == client) - { - if (!onoff) tpn->client = NULL; - return Success; - } - if (!tpn->client) fpn = tpn; /* TAKE NOTE OF FREE ENTRY */ - tpn = tpn->next; - } - - /* IF TUNNING OFF, THEN JUST RETURN */ - - if (!onoff) return Success; - - /* IF ONE ISN'T FOUND THEN ALLOCATE ONE AND LINK IT INTO THE LIST */ - - if (fpn) - { - tpn = fpn; - } - else - { - if (!(tpn = xalloc(sizeof(XvVideoNotifyRec)))) - return BadAlloc; - tpn->next = pn->next; - pn->next = tpn; - } - } - - /* INIT CLIENT PTR IN CASE WE CAN'T ADD RESOURCE */ - /* ADD RESOURCE SO THAT IF CLIENT EXITS THE CLIENT PTR WILL BE CLEARED */ - - tpn->client = NULL; - tpn->id = FakeClientID(client->index); - AddResource(tpn->id, XvRTVideoNotify, tpn); - - tpn->client = client; - return Success; - -} - -int -XvdiSelectPortNotify( - ClientPtr client, - XvPortPtr pPort, - BOOL onoff -){ - XvPortNotifyPtr pn,tpn; - - /* SEE IF CLIENT IS ALREADY IN LIST */ - - tpn = NULL; - pn = pPort->pNotify; - while (pn) - { - if (!pn->client) tpn = pn; /* TAKE NOTE OF FREE ENTRY */ - if (pn->client == client) break; - pn = pn->next; - } - - /* IS THE CLIENT ALREADY ON THE LIST? */ - - if (pn) - { - /* REMOVE IT? */ - - if (!onoff) - { - pn->client = NULL; - FreeResource(pn->id, XvRTPortNotify); - } - - return Success; - } - - /* DIDN'T FIND IT; SO REUSE LIST ELEMENT IF ONE IS FREE OTHERWISE - CREATE A NEW ONE AND ADD IT TO THE BEGINNING OF THE LIST */ - - if (!tpn) - { - if (!(tpn = xalloc(sizeof(XvPortNotifyRec)))) - return BadAlloc; - tpn->next = pPort->pNotify; - pPort->pNotify = tpn; - } - - tpn->client = client; - tpn->id = FakeClientID(client->index); - AddResource(tpn->id, XvRTPortNotify, tpn); - - return Success; - -} - -int -XvdiStopVideo( - ClientPtr client, - XvPortPtr pPort, - DrawablePtr pDraw -){ - int status; - - /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */ - - if (!pPort->pDraw || (pPort->pDraw != pDraw)) - { - XvdiSendVideoNotify(pPort, pDraw, XvStopped); - return Success; - } - - /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN - INFORM CLIENT OF ITS FAILURE */ - - if ((client) && (pPort->grab.client) && (pPort->grab.client != client)) - { - XvdiSendVideoNotify(pPort, pDraw, XvBusy); - return Success; - } - - XvdiSendVideoNotify(pPort, pDraw, XvStopped); - - status = (* pPort->pAdaptor->ddStopVideo)(client, pPort, pDraw); - - pPort->pDraw = NULL; - pPort->client = (ClientPtr)client; - pPort->time = currentTime; - - return status; - -} - -int -XvdiPreemptVideo( - ClientPtr client, - XvPortPtr pPort, - DrawablePtr pDraw -){ - int status; - - /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */ - - if (!pPort->pDraw || (pPort->pDraw != pDraw)) return Success; - - XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted); - - status = (* pPort->pAdaptor->ddStopVideo)(client, pPort, pPort->pDraw); - - pPort->pDraw = NULL; - pPort->client = (ClientPtr)client; - pPort->time = currentTime; - - return status; - -} - -int -XvdiMatchPort( - XvPortPtr pPort, - DrawablePtr pDraw -){ - - XvAdaptorPtr pa; - XvFormatPtr pf; - int nf; - - pa = pPort->pAdaptor; - - if (pa->pScreen != pDraw->pScreen) return BadMatch; - - nf = pa->nFormats; - pf = pa->pFormats; - - while (nf--) - { - if ((pf->depth == pDraw->depth) -#if 0 - && ((pDraw->type == DRAWABLE_PIXMAP) || - (wVisual(((WindowPtr)pDraw)) == pf->visual)) -#endif - ) - return Success; - pf++; - } - - return BadMatch; - -} - -int -XvdiSetPortAttribute( - ClientPtr client, - XvPortPtr pPort, - Atom attribute, - INT32 value -){ - - XvdiSendPortNotify(pPort, attribute, value); - - return - (* pPort->pAdaptor->ddSetPortAttribute)(client, pPort, attribute, value); - -} - -int -XvdiGetPortAttribute( - ClientPtr client, - XvPortPtr pPort, - Atom attribute, - INT32 *p_value -){ - - return - (* pPort->pAdaptor->ddGetPortAttribute)(client, pPort, attribute, p_value); - -} - -static void -WriteSwappedVideoNotifyEvent(xvEvent *from, xvEvent *to) - -{ - - to->u.u.type = from->u.u.type; - to->u.u.detail = from->u.u.detail; - cpswaps(from->u.videoNotify.sequenceNumber, - to->u.videoNotify.sequenceNumber); - cpswapl(from->u.videoNotify.time, to->u.videoNotify.time); - cpswapl(from->u.videoNotify.drawable, to->u.videoNotify.drawable); - cpswapl(from->u.videoNotify.port, to->u.videoNotify.port); - -} - -static void -WriteSwappedPortNotifyEvent(xvEvent *from, xvEvent *to) - -{ - - to->u.u.type = from->u.u.type; - to->u.u.detail = from->u.u.detail; - cpswaps(from->u.portNotify.sequenceNumber, to->u.portNotify.sequenceNumber); - cpswapl(from->u.portNotify.time, to->u.portNotify.time); - cpswapl(from->u.portNotify.port, to->u.portNotify.port); - cpswapl(from->u.portNotify.value, to->u.portNotify.value); - -} +/*********************************************************** +Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts, +and the Massachusetts Institute of Technology, Cambridge, 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 names of Digital or MIT 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. + +******************************************************************/ + +/* +** File: +** +** xvmain.c --- Xv server extension main device independent module. +** +** Author: +** +** David Carver (Digital Workstation Engineering/Project Athena) +** +** Revisions: +** +** 04.09.91 Carver +** - change: stop video always generates an event even when video +** wasn't active +** +** 29.08.91 Carver +** - change: unrealizing windows no longer preempts video +** +** 11.06.91 Carver +** - changed SetPortControl to SetPortAttribute +** - changed GetPortControl to GetPortAttribute +** - changed QueryBestSize +** +** 28.05.91 Carver +** - fixed Put and Get requests to not preempt operations to same drawable +** +** 15.05.91 Carver +** - version 2.0 upgrade +** +** 19.03.91 Carver +** - fixed Put and Get requests to honor grabbed ports. +** - fixed Video requests to update di structure with new drawable, and +** client after calling ddx. +** +** 24.01.91 Carver +** - version 1.4 upgrade +** +** Notes: +** +** Port structures reference client structures in a two different +** ways: when grabs, or video is active. Each reference is encoded +** as fake client resources and thus when the client is goes away so +** does the reference (it is zeroed). No other action is taken, so +** video doesn't necessarily stop. It probably will as a result of +** other resources going away, but if a client starts video using +** none of its own resources, then the video will continue to play +** after the client disappears. +** +** +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include +#include +#include "misc.h" +#include "os.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "gc.h" +#include "extnsionst.h" +#include "dixstruct.h" +#include "resource.h" +#include "opaque.h" +#include "input.h" + +#define GLOBAL + +#include +#include +#include "xvdix.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif +#include "xvdisp.h" + +static int XvScreenKeyIndex; +static DevPrivateKey XvScreenKey = &XvScreenKeyIndex; +unsigned long XvExtensionGeneration = 0; +unsigned long XvScreenGeneration = 0; +unsigned long XvResourceGeneration = 0; + +int XvReqCode; +int XvEventBase; +int XvErrorBase; + +unsigned long XvRTPort; +unsigned long XvRTEncoding; +unsigned long XvRTGrab; +unsigned long XvRTVideoNotify; +unsigned long XvRTVideoNotifyList; +unsigned long XvRTPortNotify; + + + +/* EXTERNAL */ + +static void WriteSwappedVideoNotifyEvent(xvEvent *, xvEvent *); +static void WriteSwappedPortNotifyEvent(xvEvent *, xvEvent *); +static Bool CreateResourceTypes(void); + +static Bool XvCloseScreen(int, ScreenPtr); +static Bool XvDestroyPixmap(PixmapPtr); +static Bool XvDestroyWindow(WindowPtr); +static void XvResetProc(ExtensionEntry*); +static int XvdiDestroyGrab(pointer, XID); +static int XvdiDestroyEncoding(pointer, XID); +static int XvdiDestroyVideoNotify(pointer, XID); +static int XvdiDestroyPortNotify(pointer, XID); +static int XvdiDestroyVideoNotifyList(pointer, XID); +static int XvdiDestroyPort(pointer, XID); +static int XvdiSendVideoNotify(XvPortPtr, DrawablePtr, int); + + + + +/* +** XvExtensionInit +** +** +*/ + +void +XvExtensionInit(void) +{ + ExtensionEntry *extEntry; + + /* LOOK TO SEE IF ANY SCREENS WERE INITIALIZED; IF NOT THEN + INIT GLOBAL VARIABLES SO THE EXTENSION CAN FUNCTION */ + if (XvScreenGeneration != serverGeneration) + { + if (!CreateResourceTypes()) + { + ErrorF("XvExtensionInit: Unable to allocate resource types\n"); + return; + } +#ifdef PANORAMIX + XineramaRegisterConnectionBlockCallback(XineramifyXv); +#endif + XvScreenGeneration = serverGeneration; + } + + if (XvExtensionGeneration != serverGeneration) + { + XvExtensionGeneration = serverGeneration; + + extEntry = AddExtension(XvName, XvNumEvents, XvNumErrors, + ProcXvDispatch, SProcXvDispatch, + XvResetProc, StandardMinorOpcode); + if (!extEntry) + { + FatalError("XvExtensionInit: AddExtensions failed\n"); + } + + XvReqCode = extEntry->base; + XvEventBase = extEntry->eventBase; + XvErrorBase = extEntry->errorBase; + + EventSwapVector[XvEventBase+XvVideoNotify] = + (EventSwapPtr)WriteSwappedVideoNotifyEvent; + EventSwapVector[XvEventBase+XvPortNotify] = + (EventSwapPtr)WriteSwappedPortNotifyEvent; + + (void)MakeAtom(XvName, strlen(XvName), xTrue); + + } +} + +static Bool +CreateResourceTypes(void) + +{ + + if (XvResourceGeneration == serverGeneration) return TRUE; + + XvResourceGeneration = serverGeneration; + + if (!(XvRTPort = CreateNewResourceType(XvdiDestroyPort, "XvRTPort"))) + { + ErrorF("CreateResourceTypes: failed to allocate port resource.\n"); + return FALSE; + } + + if (!(XvRTGrab = CreateNewResourceType(XvdiDestroyGrab, "XvRTGrab"))) + { + ErrorF("CreateResourceTypes: failed to allocate grab resource.\n"); + return FALSE; + } + + if (!(XvRTEncoding = CreateNewResourceType(XvdiDestroyEncoding, + "XvRTEncoding"))) + { + ErrorF("CreateResourceTypes: failed to allocate encoding resource.\n"); + return FALSE; + } + + if (!(XvRTVideoNotify = CreateNewResourceType(XvdiDestroyVideoNotify, + "XvRTVideoNotify"))) + { + ErrorF("CreateResourceTypes: failed to allocate video notify resource.\n"); + return FALSE; + } + + if (!(XvRTVideoNotifyList = CreateNewResourceType(XvdiDestroyVideoNotifyList, + "XvRTVideoNotifyList"))) + { + ErrorF("CreateResourceTypes: failed to allocate video notify list resource.\n"); + return FALSE; + } + + if (!(XvRTPortNotify = CreateNewResourceType(XvdiDestroyPortNotify, + "XvRTPortNotify"))) + { + ErrorF("CreateResourceTypes: failed to allocate port notify resource.\n"); + return FALSE; + } + + return TRUE; + +} + +int +XvScreenInit(ScreenPtr pScreen) +{ + XvScreenPtr pxvs; + + if (XvScreenGeneration != serverGeneration) + { + if (!CreateResourceTypes()) + { + ErrorF("XvScreenInit: Unable to allocate resource types\n"); + return BadAlloc; + } +#ifdef PANORAMIX + XineramaRegisterConnectionBlockCallback(XineramifyXv); +#endif + XvScreenGeneration = serverGeneration; + } + + if (dixLookupPrivate(&pScreen->devPrivates, XvScreenKey)) + { + ErrorF("XvScreenInit: screen devPrivates ptr non-NULL before init\n"); + } + + /* ALLOCATE SCREEN PRIVATE RECORD */ + + pxvs = malloc(sizeof (XvScreenRec)); + if (!pxvs) + { + ErrorF("XvScreenInit: Unable to allocate screen private structure\n"); + return BadAlloc; + } + + dixSetPrivate(&pScreen->devPrivates, XvScreenKey, pxvs); + + + pxvs->DestroyPixmap = pScreen->DestroyPixmap; + pxvs->DestroyWindow = pScreen->DestroyWindow; + pxvs->CloseScreen = pScreen->CloseScreen; + + pScreen->DestroyPixmap = XvDestroyPixmap; + pScreen->DestroyWindow = XvDestroyWindow; + pScreen->CloseScreen = XvCloseScreen; + + return Success; +} + +static Bool +XvCloseScreen( + int ii, + ScreenPtr pScreen +){ + + XvScreenPtr pxvs; + + pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XvScreenKey); + + pScreen->DestroyPixmap = pxvs->DestroyPixmap; + pScreen->DestroyWindow = pxvs->DestroyWindow; + pScreen->CloseScreen = pxvs->CloseScreen; + + (* pxvs->ddCloseScreen)(ii, pScreen); + + free(pxvs); + + dixSetPrivate(&pScreen->devPrivates, XvScreenKey, NULL); + + return (*pScreen->CloseScreen)(ii, pScreen); +} + +static void +XvResetProc(ExtensionEntry* extEntry) +{ + XvResetProcVector(); +} + +DevPrivateKey +XvGetScreenKey(void) +{ + return XvScreenKey; +} + +unsigned long +XvGetRTPort(void) +{ + return XvRTPort; +} + +static Bool +XvDestroyPixmap(PixmapPtr pPix) +{ + Bool status; + ScreenPtr pScreen; + XvScreenPtr pxvs; + XvAdaptorPtr pa; + int na; + XvPortPtr pp; + int np; + + pScreen = pPix->drawable.pScreen; + + SCREEN_PROLOGUE(pScreen, DestroyPixmap); + + pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XvScreenKey); + + /* CHECK TO SEE IF THIS PORT IS IN USE */ + + pa = pxvs->pAdaptors; + na = pxvs->nAdaptors; + while (na--) + { + np = pa->nPorts; + pp = pa->pPorts; + + while (np--) + { + if (pp->pDraw == (DrawablePtr)pPix) + { + XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted); + + (void)(* pp->pAdaptor->ddStopVideo)(NULL, pp, pp->pDraw); + + pp->pDraw = NULL; + pp->client = NULL; + pp->time = currentTime; + } + pp++; + } + pa++; + } + + status = (* pScreen->DestroyPixmap)(pPix); + + SCREEN_EPILOGUE(pScreen, DestroyPixmap, XvDestroyPixmap); + + return status; + +} + +static Bool +XvDestroyWindow(WindowPtr pWin) +{ + Bool status; + ScreenPtr pScreen; + XvScreenPtr pxvs; + XvAdaptorPtr pa; + int na; + XvPortPtr pp; + int np; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE(pScreen, DestroyWindow); + + pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XvScreenKey); + + /* CHECK TO SEE IF THIS PORT IS IN USE */ + + pa = pxvs->pAdaptors; + na = pxvs->nAdaptors; + while (na--) + { + np = pa->nPorts; + pp = pa->pPorts; + + while (np--) + { + if (pp->pDraw == (DrawablePtr)pWin) + { + XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted); + + (void)(* pp->pAdaptor->ddStopVideo)(NULL, pp, pp->pDraw); + + pp->pDraw = NULL; + pp->client = NULL; + pp->time = currentTime; + } + pp++; + } + pa++; + } + + + status = (* pScreen->DestroyWindow)(pWin); + + SCREEN_EPILOGUE(pScreen, DestroyWindow, XvDestroyWindow); + + return status; + +} + +/* The XvdiVideoStopped procedure is a hook for the device dependent layer. + It provides a way for the dd layer to inform the di layer that video has + stopped in a port for reasons that the di layer had no control over; note + that it doesn't call back into the dd layer */ + +int +XvdiVideoStopped(XvPortPtr pPort, int reason) +{ + + /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */ + + if (!pPort->pDraw) return Success; + + XvdiSendVideoNotify(pPort, pPort->pDraw, reason); + + pPort->pDraw = NULL; + pPort->client = NULL; + pPort->time = currentTime; + + return Success; + +} + +static int +XvdiDestroyPort(pointer pPort, XID id) +{ + return (* ((XvPortPtr)pPort)->pAdaptor->ddFreePort)(pPort); +} + +static int +XvdiDestroyGrab(pointer pGrab, XID id) +{ + ((XvGrabPtr)pGrab)->client = NULL; + return Success; +} + +static int +XvdiDestroyVideoNotify(pointer pn, XID id) +{ + /* JUST CLEAR OUT THE client POINTER FIELD */ + + ((XvVideoNotifyPtr)pn)->client = NULL; + return Success; +} + +static int +XvdiDestroyPortNotify(pointer pn, XID id) +{ + /* JUST CLEAR OUT THE client POINTER FIELD */ + + ((XvPortNotifyPtr)pn)->client = NULL; + return Success; +} + +static int +XvdiDestroyVideoNotifyList(pointer pn, XID id) +{ + XvVideoNotifyPtr npn,cpn; + + /* ACTUALLY DESTROY THE NOTITY LIST */ + + cpn = (XvVideoNotifyPtr)pn; + + while (cpn) + { + npn = cpn->next; + if (cpn->client) FreeResource(cpn->id, XvRTVideoNotify); + free(cpn); + cpn = npn; + } + return Success; +} + +static int +XvdiDestroyEncoding(pointer value, XID id) +{ + return Success; +} + +static int +XvdiSendVideoNotify(XvPortPtr pPort, DrawablePtr pDraw, int reason) +{ + xvEvent event; + XvVideoNotifyPtr pn; + + dixLookupResourceByType((pointer *)&pn, pDraw->id, XvRTVideoNotifyList, + serverClient, DixReadAccess); + + while (pn) + { + if (pn->client) + { + event.u.u.type = XvEventBase + XvVideoNotify; + event.u.u.sequenceNumber = pn->client->sequence; + event.u.videoNotify.time = currentTime.milliseconds; + event.u.videoNotify.drawable = pDraw->id; + event.u.videoNotify.port = pPort->id; + event.u.videoNotify.reason = reason; + TryClientEvents(pn->client, NULL, (xEventPtr)&event, 1, + NoEventMask, NoEventMask, NullGrab); + } + pn = pn->next; + } + + return Success; + +} + + +int +XvdiSendPortNotify( + XvPortPtr pPort, + Atom attribute, + INT32 value +){ + xvEvent event; + XvPortNotifyPtr pn; + + pn = pPort->pNotify; + + while (pn) + { + if (pn->client) + { + event.u.u.type = XvEventBase + XvPortNotify; + event.u.u.sequenceNumber = pn->client->sequence; + event.u.portNotify.time = currentTime.milliseconds; + event.u.portNotify.port = pPort->id; + event.u.portNotify.attribute = attribute; + event.u.portNotify.value = value; + TryClientEvents(pn->client, NULL, (xEventPtr)&event, 1, + NoEventMask, NoEventMask, NullGrab); + } + pn = pn->next; + } + + return Success; + +} + + +#define CHECK_SIZE(dw, dh, sw, sh) { \ + if(!dw || !dh || !sw || !sh) return Success; \ + /* The region code will break these if they are too large */ \ + if((dw > 32767) || (dh > 32767) || (sw > 32767) || (sh > 32767)) \ + return BadValue; \ +} + + +int +XvdiPutVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + DrawablePtr pOldDraw; + + CHECK_SIZE(drw_w, drw_h, vid_w, vid_h); + + /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ + + UpdateCurrentTime(); + + /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN + INFORM CLIENT OF ITS FAILURE */ + + if (pPort->grab.client && (pPort->grab.client != client)) + { + XvdiSendVideoNotify(pPort, pDraw, XvBusy); + return Success; + } + + /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED + EVENTS TO ANY CLIENTS WHO WANT THEM */ + + pOldDraw = pPort->pDraw; + if ((pOldDraw) && (pOldDraw != pDraw)) + { + XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted); + } + + (void) (* pPort->pAdaptor->ddPutVideo)(client, pDraw, pPort, pGC, + vid_x, vid_y, vid_w, vid_h, + drw_x, drw_y, drw_w, drw_h); + + if ((pPort->pDraw) && (pOldDraw != pDraw)) + { + pPort->client = client; + XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted); + } + + pPort->time = currentTime; + + return (Success); + +} + +int +XvdiPutStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + int status; + + CHECK_SIZE(drw_w, drw_h, vid_w, vid_h); + + /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ + + UpdateCurrentTime(); + + /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN + INFORM CLIENT OF ITS FAILURE */ + + if (pPort->grab.client && (pPort->grab.client != client)) + { + XvdiSendVideoNotify(pPort, pDraw, XvBusy); + return Success; + } + + pPort->time = currentTime; + + status = (* pPort->pAdaptor->ddPutStill)(client, pDraw, pPort, pGC, + vid_x, vid_y, vid_w, vid_h, + drw_x, drw_y, drw_w, drw_h); + + return status; + +} + +int +XvdiPutImage( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 src_x, INT16 src_y, + CARD16 src_w, CARD16 src_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h, + XvImagePtr image, + unsigned char* data, + Bool sync, + CARD16 width, CARD16 height +){ + CHECK_SIZE(drw_w, drw_h, src_w, src_h); + + /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ + + UpdateCurrentTime(); + + /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN + INFORM CLIENT OF ITS FAILURE */ + + if (pPort->grab.client && (pPort->grab.client != client)) + { + XvdiSendVideoNotify(pPort, pDraw, XvBusy); + return Success; + } + + pPort->time = currentTime; + + return (* pPort->pAdaptor->ddPutImage)(client, pDraw, pPort, pGC, + src_x, src_y, src_w, src_h, + drw_x, drw_y, drw_w, drw_h, + image, data, sync, width, height); +} + + +int +XvdiGetVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + DrawablePtr pOldDraw; + + CHECK_SIZE(drw_w, drw_h, vid_w, vid_h); + + /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ + + UpdateCurrentTime(); + + /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN + INFORM CLIENT OF ITS FAILURE */ + + if (pPort->grab.client && (pPort->grab.client != client)) + { + XvdiSendVideoNotify(pPort, pDraw, XvBusy); + return Success; + } + + /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED + EVENTS TO ANY CLIENTS WHO WANT THEM */ + + pOldDraw = pPort->pDraw; + if ((pOldDraw) && (pOldDraw != pDraw)) + { + XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted); + } + + (void) (* pPort->pAdaptor->ddGetVideo)(client, pDraw, pPort, pGC, + vid_x, vid_y, vid_w, vid_h, + drw_x, drw_y, drw_w, drw_h); + + if ((pPort->pDraw) && (pOldDraw != pDraw)) + { + pPort->client = client; + XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted); + } + + pPort->time = currentTime; + + return (Success); + +} + +int +XvdiGetStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + int status; + + CHECK_SIZE(drw_w, drw_h, vid_w, vid_h); + + /* UPDATE TIME VARIABLES FOR USE IN EVENTS */ + + UpdateCurrentTime(); + + /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN + INFORM CLIENT OF ITS FAILURE */ + + if (pPort->grab.client && (pPort->grab.client != client)) + { + XvdiSendVideoNotify(pPort, pDraw, XvBusy); + return Success; + } + + status = (* pPort->pAdaptor->ddGetStill)(client, pDraw, pPort, pGC, + vid_x, vid_y, vid_w, vid_h, + drw_x, drw_y, drw_w, drw_h); + + pPort->time = currentTime; + + return status; + +} + +int +XvdiGrabPort( + ClientPtr client, + XvPortPtr pPort, + Time ctime, + int *p_result +){ + unsigned long id; + TimeStamp time; + + UpdateCurrentTime(); + time = ClientTimeToServerTime(ctime); + + if (pPort->grab.client && (client != pPort->grab.client)) + { + *p_result = XvAlreadyGrabbed; + return Success; + } + + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, pPort->time) == EARLIER)) + { + *p_result = XvInvalidTime; + return Success; + } + + if (client == pPort->grab.client) + { + *p_result = Success; + return Success; + } + + id = FakeClientID(client->index); + + if (!AddResource(id, XvRTGrab, &pPort->grab)) + { + return BadAlloc; + } + + /* IF THERE IS ACTIVE VIDEO THEN STOP IT */ + + if ((pPort->pDraw) && (client != pPort->client)) + { + XvdiStopVideo(NULL, pPort, pPort->pDraw); + } + + pPort->grab.client = client; + pPort->grab.id = id; + + pPort->time = currentTime; + + *p_result = Success; + + return Success; + +} + +int +XvdiUngrabPort( + ClientPtr client, + XvPortPtr pPort, + Time ctime +){ + TimeStamp time; + + UpdateCurrentTime(); + time = ClientTimeToServerTime(ctime); + + if ((!pPort->grab.client) || (client != pPort->grab.client)) + { + return Success; + } + + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, pPort->time) == EARLIER)) + { + return Success; + } + + /* FREE THE GRAB RESOURCE; AND SET THE GRAB CLIENT TO NULL */ + + FreeResource(pPort->grab.id, XvRTGrab); + pPort->grab.client = NULL; + + pPort->time = currentTime; + + return Success; + +} + + +int +XvdiSelectVideoNotify( + ClientPtr client, + DrawablePtr pDraw, + BOOL onoff +){ + XvVideoNotifyPtr pn,tpn,fpn; + int rc; + + /* FIND VideoNotify LIST */ + + rc = dixLookupResourceByType((pointer *)&pn, pDraw->id, XvRTVideoNotifyList, + client, DixWriteAccess); + if (rc != Success && rc != BadValue) + return rc; + + /* IF ONE DONES'T EXIST AND NO MASK, THEN JUST RETURN */ + + if (!onoff && !pn) return Success; + + /* IF ONE DOESN'T EXIST CREATE IT AND ADD A RESOURCE SO THAT THE LIST + WILL BE DELETED WHEN THE DRAWABLE IS DESTROYED */ + + if (!pn) + { + if (!(tpn = malloc(sizeof(XvVideoNotifyRec)))) + return BadAlloc; + tpn->next = NULL; + if (!AddResource(pDraw->id, XvRTVideoNotifyList, tpn)) + { + free(tpn); + return BadAlloc; + } + } + else + { + /* LOOK TO SEE IF ENTRY ALREADY EXISTS */ + + fpn = NULL; + tpn = pn; + while (tpn) + { + if (tpn->client == client) + { + if (!onoff) tpn->client = NULL; + return Success; + } + if (!tpn->client) fpn = tpn; /* TAKE NOTE OF FREE ENTRY */ + tpn = tpn->next; + } + + /* IF TUNNING OFF, THEN JUST RETURN */ + + if (!onoff) return Success; + + /* IF ONE ISN'T FOUND THEN ALLOCATE ONE AND LINK IT INTO THE LIST */ + + if (fpn) + { + tpn = fpn; + } + else + { + if (!(tpn = malloc(sizeof(XvVideoNotifyRec)))) + return BadAlloc; + tpn->next = pn->next; + pn->next = tpn; + } + } + + /* INIT CLIENT PTR IN CASE WE CAN'T ADD RESOURCE */ + /* ADD RESOURCE SO THAT IF CLIENT EXITS THE CLIENT PTR WILL BE CLEARED */ + + tpn->client = NULL; + tpn->id = FakeClientID(client->index); + AddResource(tpn->id, XvRTVideoNotify, tpn); + + tpn->client = client; + return Success; + +} + +int +XvdiSelectPortNotify( + ClientPtr client, + XvPortPtr pPort, + BOOL onoff +){ + XvPortNotifyPtr pn,tpn; + + /* SEE IF CLIENT IS ALREADY IN LIST */ + + tpn = NULL; + pn = pPort->pNotify; + while (pn) + { + if (!pn->client) tpn = pn; /* TAKE NOTE OF FREE ENTRY */ + if (pn->client == client) break; + pn = pn->next; + } + + /* IS THE CLIENT ALREADY ON THE LIST? */ + + if (pn) + { + /* REMOVE IT? */ + + if (!onoff) + { + pn->client = NULL; + FreeResource(pn->id, XvRTPortNotify); + } + + return Success; + } + + /* DIDN'T FIND IT; SO REUSE LIST ELEMENT IF ONE IS FREE OTHERWISE + CREATE A NEW ONE AND ADD IT TO THE BEGINNING OF THE LIST */ + + if (!tpn) + { + if (!(tpn = malloc(sizeof(XvPortNotifyRec)))) + return BadAlloc; + tpn->next = pPort->pNotify; + pPort->pNotify = tpn; + } + + tpn->client = client; + tpn->id = FakeClientID(client->index); + AddResource(tpn->id, XvRTPortNotify, tpn); + + return Success; + +} + +int +XvdiStopVideo( + ClientPtr client, + XvPortPtr pPort, + DrawablePtr pDraw +){ + int status; + + /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */ + + if (!pPort->pDraw || (pPort->pDraw != pDraw)) + { + XvdiSendVideoNotify(pPort, pDraw, XvStopped); + return Success; + } + + /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN + INFORM CLIENT OF ITS FAILURE */ + + if ((client) && (pPort->grab.client) && (pPort->grab.client != client)) + { + XvdiSendVideoNotify(pPort, pDraw, XvBusy); + return Success; + } + + XvdiSendVideoNotify(pPort, pDraw, XvStopped); + + status = (* pPort->pAdaptor->ddStopVideo)(client, pPort, pDraw); + + pPort->pDraw = NULL; + pPort->client = (ClientPtr)client; + pPort->time = currentTime; + + return status; + +} + +int +XvdiPreemptVideo( + ClientPtr client, + XvPortPtr pPort, + DrawablePtr pDraw +){ + int status; + + /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */ + + if (!pPort->pDraw || (pPort->pDraw != pDraw)) return Success; + + XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted); + + status = (* pPort->pAdaptor->ddStopVideo)(client, pPort, pPort->pDraw); + + pPort->pDraw = NULL; + pPort->client = (ClientPtr)client; + pPort->time = currentTime; + + return status; + +} + +int +XvdiMatchPort( + XvPortPtr pPort, + DrawablePtr pDraw +){ + + XvAdaptorPtr pa; + XvFormatPtr pf; + int nf; + + pa = pPort->pAdaptor; + + if (pa->pScreen != pDraw->pScreen) return BadMatch; + + nf = pa->nFormats; + pf = pa->pFormats; + + while (nf--) + { + if ((pf->depth == pDraw->depth) +#if 0 + && ((pDraw->type == DRAWABLE_PIXMAP) || + (wVisual(((WindowPtr)pDraw)) == pf->visual)) +#endif + ) + return Success; + pf++; + } + + return BadMatch; + +} + +int +XvdiSetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 value +){ + + XvdiSendPortNotify(pPort, attribute, value); + + return + (* pPort->pAdaptor->ddSetPortAttribute)(client, pPort, attribute, value); + +} + +int +XvdiGetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 *p_value +){ + + return + (* pPort->pAdaptor->ddGetPortAttribute)(client, pPort, attribute, p_value); + +} + +static void +WriteSwappedVideoNotifyEvent(xvEvent *from, xvEvent *to) + +{ + + to->u.u.type = from->u.u.type; + to->u.u.detail = from->u.u.detail; + cpswaps(from->u.videoNotify.sequenceNumber, + to->u.videoNotify.sequenceNumber); + cpswapl(from->u.videoNotify.time, to->u.videoNotify.time); + cpswapl(from->u.videoNotify.drawable, to->u.videoNotify.drawable); + cpswapl(from->u.videoNotify.port, to->u.videoNotify.port); + +} + +static void +WriteSwappedPortNotifyEvent(xvEvent *from, xvEvent *to) + +{ + + to->u.u.type = from->u.u.type; + to->u.u.detail = from->u.u.detail; + cpswaps(from->u.portNotify.sequenceNumber, to->u.portNotify.sequenceNumber); + cpswapl(from->u.portNotify.time, to->u.portNotify.time); + cpswapl(from->u.portNotify.port, to->u.portNotify.port); + cpswapl(from->u.portNotify.value, to->u.portNotify.value); + +} diff --git a/xorg-server/Xext/xvmc.c b/xorg-server/Xext/xvmc.c index c85f85eb4..18a81c76b 100644 --- a/xorg-server/Xext/xvmc.c +++ b/xorg-server/Xext/xvmc.c @@ -1,787 +1,787 @@ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include -#include -#include "misc.h" -#include "os.h" -#include "dixstruct.h" -#include "resource.h" -#include "scrnintstr.h" -#include "extnsionst.h" -#include "servermd.h" -#include -#include "xvdix.h" -#include -#include -#include -#include "xvmcext.h" -#include "protocol-versions.h" - -#ifdef HAS_XVMCSHM -#include -#include -#include -#endif /* HAS_XVMCSHM */ - - - -#define DR_CLIENT_DRIVER_NAME_SIZE 48 -#define DR_BUSID_SIZE 48 - -static int XvMCScreenKeyIndex; -static DevPrivateKey XvMCScreenKey; - -unsigned long XvMCGeneration = 0; - -int XvMCReqCode; -int XvMCEventBase; -int XvMCErrorBase; - -unsigned long XvMCRTContext; -unsigned long XvMCRTSurface; -unsigned long XvMCRTSubpicture; - -typedef struct { - int num_adaptors; - XvMCAdaptorPtr adaptors; - CloseScreenProcPtr CloseScreen; - char clientDriverName[DR_CLIENT_DRIVER_NAME_SIZE]; - char busID[DR_BUSID_SIZE]; - int major; - int minor; - int patchLevel; -} XvMCScreenRec, *XvMCScreenPtr; - -#define XVMC_GET_PRIVATE(pScreen) \ - (XvMCScreenPtr)(dixLookupPrivate(&(pScreen)->devPrivates, XvMCScreenKey)) - - -static int -XvMCDestroyContextRes(pointer data, XID id) -{ - XvMCContextPtr pContext = (XvMCContextPtr)data; - - pContext->refcnt--; - - if(!pContext->refcnt) { - XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); - (*pScreenPriv->adaptors[pContext->adapt_num].DestroyContext)(pContext); - xfree(pContext); - } - - return Success; -} - -static int -XvMCDestroySurfaceRes(pointer data, XID id) -{ - XvMCSurfacePtr pSurface = (XvMCSurfacePtr)data; - XvMCContextPtr pContext = pSurface->context; - XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); - - (*pScreenPriv->adaptors[pContext->adapt_num].DestroySurface)(pSurface); - xfree(pSurface); - - XvMCDestroyContextRes((pointer)pContext, pContext->context_id); - - return Success; -} - - -static int -XvMCDestroySubpictureRes(pointer data, XID id) -{ - XvMCSubpicturePtr pSubpict = (XvMCSubpicturePtr)data; - XvMCContextPtr pContext = pSubpict->context; - XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); - - (*pScreenPriv->adaptors[pContext->adapt_num].DestroySubpicture)(pSubpict); - xfree(pSubpict); - - XvMCDestroyContextRes((pointer)pContext, pContext->context_id); - - return Success; -} - -static int -ProcXvMCQueryVersion(ClientPtr client) -{ - xvmcQueryVersionReply rep; - /* REQUEST(xvmcQueryVersionReq); */ - REQUEST_SIZE_MATCH(xvmcQueryVersionReq); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.major = SERVER_XVMC_MAJOR_VERSION; - rep.minor = SERVER_XVMC_MINOR_VERSION; - WriteToClient(client, sizeof(xvmcQueryVersionReply), (char*)&rep); - return Success; -} - - -static int -ProcXvMCListSurfaceTypes(ClientPtr client) -{ - XvPortPtr pPort; - int i; - XvMCScreenPtr pScreenPriv; - xvmcListSurfaceTypesReply rep; - xvmcSurfaceInfo info; - XvMCAdaptorPtr adaptor = NULL; - XvMCSurfaceInfoPtr surface; - REQUEST(xvmcListSurfaceTypesReq); - REQUEST_SIZE_MATCH(xvmcListSurfaceTypesReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - if(XvMCScreenKey) { /* any adaptors at all */ - ScreenPtr pScreen = pPort->pAdaptor->pScreen; - if((pScreenPriv = XVMC_GET_PRIVATE(pScreen))) { /* any this screen */ - for(i = 0; i < pScreenPriv->num_adaptors; i++) { - if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) { - adaptor = &(pScreenPriv->adaptors[i]); - break; - } - } - } - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.num = (adaptor) ? adaptor->num_surfaces : 0; - rep.length = bytes_to_int32(rep.num * sizeof(xvmcSurfaceInfo)); - - WriteToClient(client, sizeof(xvmcListSurfaceTypesReply), (char*)&rep); - - for(i = 0; i < rep.num; i++) { - surface = adaptor->surfaces[i]; - info.surface_type_id = surface->surface_type_id; - info.chroma_format = surface->chroma_format; - info.max_width = surface->max_width; - info.max_height = surface->max_height; - info.subpicture_max_width = surface->subpicture_max_width; - info.subpicture_max_height = surface->subpicture_max_height; - info.mc_type = surface->mc_type; - info.flags = surface->flags; - WriteToClient(client, sizeof(xvmcSurfaceInfo), (char*)&info); - } - - return Success; -} - -static int -ProcXvMCCreateContext(ClientPtr client) -{ - XvPortPtr pPort; - CARD32 *data = NULL; - int dwords = 0; - int i, result, adapt_num = -1; - ScreenPtr pScreen; - XvMCContextPtr pContext; - XvMCScreenPtr pScreenPriv; - XvMCAdaptorPtr adaptor = NULL; - XvMCSurfaceInfoPtr surface = NULL; - xvmcCreateContextReply rep; - REQUEST(xvmcCreateContextReq); - REQUEST_SIZE_MATCH(xvmcCreateContextReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - pScreen = pPort->pAdaptor->pScreen; - - if(XvMCScreenKey == NULL) /* no XvMC adaptors */ - return BadMatch; - - if(!(pScreenPriv = XVMC_GET_PRIVATE(pScreen))) /* none this screen */ - return BadMatch; - - for(i = 0; i < pScreenPriv->num_adaptors; i++) { - if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) { - adaptor = &(pScreenPriv->adaptors[i]); - adapt_num = i; - break; - } - } - - if(adapt_num < 0) /* none this port */ - return BadMatch; - - for(i = 0; i < adaptor->num_surfaces; i++) { - if(adaptor->surfaces[i]->surface_type_id == stuff->surface_type_id) { - surface = adaptor->surfaces[i]; - break; - } - } - - /* adaptor doesn't support this suface_type_id */ - if(!surface) return BadMatch; - - - if((stuff->width > surface->max_width) || - (stuff->height > surface->max_height)) - return BadValue; - - if(!(pContext = xalloc(sizeof(XvMCContextRec)))) { - return BadAlloc; - } - - - pContext->pScreen = pScreen; - pContext->adapt_num = adapt_num; - pContext->context_id = stuff->context_id; - pContext->surface_type_id = stuff->surface_type_id; - pContext->width = stuff->width; - pContext->height = stuff->height; - pContext->flags = stuff->flags; - pContext->refcnt = 1; - - result = (*adaptor->CreateContext)(pPort, pContext, &dwords, &data); - - if(result != Success) { - xfree(pContext); - return result; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.width_actual = pContext->width; - rep.height_actual = pContext->height; - rep.flags_return = pContext->flags; - rep.length = dwords; - - WriteToClient(client, sizeof(xvmcCreateContextReply), (char*)&rep); - if(dwords) - WriteToClient(client, dwords << 2, (char*)data); - AddResource(pContext->context_id, XvMCRTContext, pContext); - - if(data) - xfree(data); - - return Success; -} - -static int -ProcXvMCDestroyContext(ClientPtr client) -{ - pointer val; - int rc; - REQUEST(xvmcDestroyContextReq); - REQUEST_SIZE_MATCH(xvmcDestroyContextReq); - - rc = dixLookupResourceByType(&val, stuff->context_id, XvMCRTContext, - client, DixDestroyAccess); - if (rc != Success) - return (rc == BadValue) ? XvMCBadContext + XvMCErrorBase : rc; - - FreeResource(stuff->context_id, RT_NONE); - - return Success; -} - -static int -ProcXvMCCreateSurface(ClientPtr client) -{ - CARD32 *data = NULL; - int dwords = 0; - int result; - XvMCContextPtr pContext; - XvMCSurfacePtr pSurface; - XvMCScreenPtr pScreenPriv; - xvmcCreateSurfaceReply rep; - REQUEST(xvmcCreateSurfaceReq); - REQUEST_SIZE_MATCH(xvmcCreateSurfaceReq); - - result = dixLookupResourceByType((pointer *)&pContext, stuff->context_id, - XvMCRTContext, client, DixUseAccess); - if (result != Success) - return (result == BadValue) ? XvMCBadContext + XvMCErrorBase : result; - - pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); - - if(!(pSurface = xalloc(sizeof(XvMCSurfaceRec)))) - return BadAlloc; - - pSurface->surface_id = stuff->surface_id; - pSurface->surface_type_id = pContext->surface_type_id; - pSurface->context = pContext; - - result = (*pScreenPriv->adaptors[pContext->adapt_num].CreateSurface)( - pSurface, &dwords, &data); - - if(result != Success) { - xfree(pSurface); - return result; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = dwords; - - WriteToClient(client, sizeof(xvmcCreateSurfaceReply), (char*)&rep); - if(dwords) - WriteToClient(client, dwords << 2, (char*)data); - AddResource(pSurface->surface_id, XvMCRTSurface, pSurface); - - if(data) - xfree(data); - - pContext->refcnt++; - - return Success; -} - -static int -ProcXvMCDestroySurface(ClientPtr client) -{ - pointer val; - int rc; - REQUEST(xvmcDestroySurfaceReq); - REQUEST_SIZE_MATCH(xvmcDestroySurfaceReq); - - rc = dixLookupResourceByType(&val, stuff->surface_id, XvMCRTSurface, - client, DixDestroyAccess); - if (rc != Success) - return (rc == BadValue) ? XvMCBadSurface + XvMCErrorBase : rc; - - FreeResource(stuff->surface_id, RT_NONE); - - return Success; -} - -static int -ProcXvMCCreateSubpicture(ClientPtr client) -{ - Bool image_supported = FALSE; - CARD32 *data = NULL; - int i, result, dwords = 0; - XvMCContextPtr pContext; - XvMCSubpicturePtr pSubpicture; - XvMCScreenPtr pScreenPriv; - xvmcCreateSubpictureReply rep; - XvMCAdaptorPtr adaptor; - XvMCSurfaceInfoPtr surface = NULL; - REQUEST(xvmcCreateSubpictureReq); - REQUEST_SIZE_MATCH(xvmcCreateSubpictureReq); - - result = dixLookupResourceByType((pointer *)&pContext, stuff->context_id, - XvMCRTContext, client, DixUseAccess); - if (result != Success) - return (result == BadValue) ? XvMCBadContext + XvMCErrorBase : result; - - pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); - - adaptor = &(pScreenPriv->adaptors[pContext->adapt_num]); - - /* find which surface this context supports */ - for(i = 0; i < adaptor->num_surfaces; i++) { - if(adaptor->surfaces[i]->surface_type_id == pContext->surface_type_id){ - surface = adaptor->surfaces[i]; - break; - } - } - - if(!surface) return BadMatch; - - /* make sure this surface supports that xvimage format */ - if(!surface->compatible_subpictures) return BadMatch; - - for(i = 0; i < surface->compatible_subpictures->num_xvimages; i++) { - if(surface->compatible_subpictures->xvimage_ids[i] == stuff->xvimage_id) { - image_supported = TRUE; - break; - } - } - - if(!image_supported) return BadMatch; - - /* make sure the size is OK */ - if((stuff->width > surface->subpicture_max_width) || - (stuff->height > surface->subpicture_max_height)) - return BadValue; - - if(!(pSubpicture = xalloc(sizeof(XvMCSubpictureRec)))) - return BadAlloc; - - pSubpicture->subpicture_id = stuff->subpicture_id; - pSubpicture->xvimage_id = stuff->xvimage_id; - pSubpicture->width = stuff->width; - pSubpicture->height = stuff->height; - pSubpicture->num_palette_entries = 0; /* overwritten by DDX */ - pSubpicture->entry_bytes = 0; /* overwritten by DDX */ - pSubpicture->component_order[0] = 0; /* overwritten by DDX */ - pSubpicture->component_order[1] = 0; - pSubpicture->component_order[2] = 0; - pSubpicture->component_order[3] = 0; - pSubpicture->context = pContext; - - result = (*pScreenPriv->adaptors[pContext->adapt_num].CreateSubpicture)( - pSubpicture, &dwords, &data); - - if(result != Success) { - xfree(pSubpicture); - return result; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.width_actual = pSubpicture->width; - rep.height_actual = pSubpicture->height; - rep.num_palette_entries = pSubpicture->num_palette_entries; - rep.entry_bytes = pSubpicture->entry_bytes; - rep.component_order[0] = pSubpicture->component_order[0]; - rep.component_order[1] = pSubpicture->component_order[1]; - rep.component_order[2] = pSubpicture->component_order[2]; - rep.component_order[3] = pSubpicture->component_order[3]; - rep.length = dwords; - - WriteToClient(client, sizeof(xvmcCreateSubpictureReply), (char*)&rep); - if(dwords) - WriteToClient(client, dwords << 2, (char*)data); - AddResource(pSubpicture->subpicture_id, XvMCRTSubpicture, pSubpicture); - - if(data) - xfree(data); - - pContext->refcnt++; - - return Success; -} - -static int -ProcXvMCDestroySubpicture(ClientPtr client) -{ - pointer val; - int rc; - REQUEST(xvmcDestroySubpictureReq); - REQUEST_SIZE_MATCH(xvmcDestroySubpictureReq); - - rc = dixLookupResourceByType(&val, stuff->subpicture_id, XvMCRTSubpicture, - client, DixDestroyAccess); - if (rc != Success) - return (rc == BadValue) ? XvMCBadSubpicture + XvMCErrorBase : rc; - - FreeResource(stuff->subpicture_id, RT_NONE); - - return Success; -} - - -static int -ProcXvMCListSubpictureTypes(ClientPtr client) -{ - XvPortPtr pPort; - xvmcListSubpictureTypesReply rep; - XvMCScreenPtr pScreenPriv; - ScreenPtr pScreen; - XvMCAdaptorPtr adaptor = NULL; - XvMCSurfaceInfoPtr surface = NULL; - xvImageFormatInfo info; - XvImagePtr pImage; - int i, j; - REQUEST(xvmcListSubpictureTypesReq); - REQUEST_SIZE_MATCH(xvmcListSubpictureTypesReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - pScreen = pPort->pAdaptor->pScreen; - - if(XvMCScreenKey == NULL) /* No XvMC adaptors */ - return BadMatch; - - if(!(pScreenPriv = XVMC_GET_PRIVATE(pScreen))) - return BadMatch; /* None this screen */ - - for(i = 0; i < pScreenPriv->num_adaptors; i++) { - if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) { - adaptor = &(pScreenPriv->adaptors[i]); - break; - } - } - - if(!adaptor) return BadMatch; - - for(i = 0; i < adaptor->num_surfaces; i++) { - if(adaptor->surfaces[i]->surface_type_id == stuff->surface_type_id) { - surface = adaptor->surfaces[i]; - break; - } - } - - if(!surface) return BadMatch; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.num = 0; - if(surface->compatible_subpictures) - rep.num = surface->compatible_subpictures->num_xvimages; - - rep.length = bytes_to_int32(rep.num * sizeof(xvImageFormatInfo)); - - WriteToClient(client, sizeof(xvmcListSubpictureTypesReply), (char*)&rep); - - for(i = 0; i < rep.num; i++) { - pImage = NULL; - for(j = 0; j < adaptor->num_subpictures; j++) { - if(surface->compatible_subpictures->xvimage_ids[i] == - adaptor->subpictures[j]->id) - { - pImage = adaptor->subpictures[j]; - break; - } - } - if(!pImage) return BadImplementation; - - info.id = pImage->id; - info.type = pImage->type; - info.byte_order = pImage->byte_order; - memcpy(&info.guid, pImage->guid, 16); - info.bpp = pImage->bits_per_pixel; - info.num_planes = pImage->num_planes; - info.depth = pImage->depth; - info.red_mask = pImage->red_mask; - info.green_mask = pImage->green_mask; - info.blue_mask = pImage->blue_mask; - info.format = pImage->format; - info.y_sample_bits = pImage->y_sample_bits; - info.u_sample_bits = pImage->u_sample_bits; - info.v_sample_bits = pImage->v_sample_bits; - info.horz_y_period = pImage->horz_y_period; - info.horz_u_period = pImage->horz_u_period; - info.horz_v_period = pImage->horz_v_period; - info.vert_y_period = pImage->vert_y_period; - info.vert_u_period = pImage->vert_u_period; - info.vert_v_period = pImage->vert_v_period; - memcpy(&info.comp_order, pImage->component_order, 32); - info.scanline_order = pImage->scanline_order; - WriteToClient(client, sizeof(xvImageFormatInfo), (char*)&info); - } - - return Success; -} - -static int -ProcXvMCGetDRInfo(ClientPtr client) -{ - xvmcGetDRInfoReply rep; - XvPortPtr pPort; - ScreenPtr pScreen; - XvMCScreenPtr pScreenPriv; - -#ifdef HAS_XVMCSHM - volatile CARD32 *patternP; -#endif - - REQUEST(xvmcGetDRInfoReq); - REQUEST_SIZE_MATCH(xvmcGetDRInfoReq); - - VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); - - pScreen = pPort->pAdaptor->pScreen; - pScreenPriv = XVMC_GET_PRIVATE(pScreen); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.major = pScreenPriv->major; - rep.minor = pScreenPriv->minor; - rep.patchLevel = pScreenPriv->patchLevel; - rep.nameLen = bytes_to_int32(strlen(pScreenPriv->clientDriverName) + 1); - rep.busIDLen = bytes_to_int32(strlen(pScreenPriv->busID) + 1); - - rep.length = rep.nameLen + rep.busIDLen; - rep.nameLen <<=2; - rep.busIDLen <<=2; - - /* - * Read back to the client what she has put in the shared memory - * segment she prepared for us. - */ - - rep.isLocal = 1; -#ifdef HAS_XVMCSHM - patternP = (CARD32 *)shmat( stuff->shmKey, NULL, SHM_RDONLY ); - if ( -1 != (long) patternP) { - volatile CARD32 *patternC = patternP; - int i; - CARD32 magic = stuff->magic; - - rep.isLocal = 1; - i = 1024 / sizeof(CARD32); - - while ( i-- ) { - if (*patternC++ != magic) { - rep.isLocal = 0; - break; - } - magic = ~magic; - } - shmdt( (char *)patternP ); - } -#endif /* HAS_XVMCSHM */ - - WriteToClient(client, sizeof(xvmcGetDRInfoReply), - (char*)&rep); - if (rep.length) { - WriteToClient(client, rep.nameLen, - pScreenPriv->clientDriverName); - WriteToClient(client, rep.busIDLen, - pScreenPriv->busID); - } - return Success; -} - - -int (*ProcXvMCVector[xvmcNumRequest])(ClientPtr) = { - ProcXvMCQueryVersion, - ProcXvMCListSurfaceTypes, - ProcXvMCCreateContext, - ProcXvMCDestroyContext, - ProcXvMCCreateSurface, - ProcXvMCDestroySurface, - ProcXvMCCreateSubpicture, - ProcXvMCDestroySubpicture, - ProcXvMCListSubpictureTypes, - ProcXvMCGetDRInfo -}; - -static int -ProcXvMCDispatch (ClientPtr client) -{ - REQUEST(xReq); - - if(stuff->data < xvmcNumRequest) - return (*ProcXvMCVector[stuff->data])(client); - else - return BadRequest; -} - -static int -SProcXvMCDispatch (ClientPtr client) -{ - /* We only support local */ - return BadImplementation; -} - -void -XvMCExtensionInit(void) -{ - ExtensionEntry *extEntry; - - if(XvMCScreenKey == NULL) /* nobody supports it */ - return; - - if(!(XvMCRTContext = CreateNewResourceType(XvMCDestroyContextRes, - "XvMCRTContext"))) - return; - - if(!(XvMCRTSurface = CreateNewResourceType(XvMCDestroySurfaceRes, - "XvMCRTSurface"))) - return; - - if(!(XvMCRTSubpicture = CreateNewResourceType(XvMCDestroySubpictureRes, - "XvMCRTSubpicture"))) - return; - - extEntry = AddExtension(XvMCName, XvMCNumEvents, XvMCNumErrors, - ProcXvMCDispatch, SProcXvMCDispatch, - NULL, StandardMinorOpcode); - - if(!extEntry) return; - - XvMCReqCode = extEntry->base; - XvMCEventBase = extEntry->eventBase; - XvMCErrorBase = extEntry->errorBase; -} - -static Bool -XvMCCloseScreen (int i, ScreenPtr pScreen) -{ - XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pScreen); - - pScreen->CloseScreen = pScreenPriv->CloseScreen; - - xfree(pScreenPriv); - - return (*pScreen->CloseScreen)(i, pScreen); -} - - -int -XvMCScreenInit(ScreenPtr pScreen, int num, XvMCAdaptorPtr pAdapt) -{ - XvMCScreenPtr pScreenPriv; - - XvMCScreenKey = &XvMCScreenKeyIndex; - - if(!(pScreenPriv = xalloc(sizeof(XvMCScreenRec)))) - return BadAlloc; - - dixSetPrivate(&pScreen->devPrivates, XvMCScreenKey, pScreenPriv); - - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = XvMCCloseScreen; - - pScreenPriv->num_adaptors = num; - pScreenPriv->adaptors = pAdapt; - pScreenPriv->clientDriverName[0] = 0; - pScreenPriv->busID[0] = 0; - pScreenPriv->major = 0; - pScreenPriv->minor = 0; - pScreenPriv->patchLevel = 0; - - return Success; -} - -XvImagePtr XvMCFindXvImage(XvPortPtr pPort, CARD32 id) -{ - XvImagePtr pImage = NULL; - ScreenPtr pScreen = pPort->pAdaptor->pScreen; - XvMCScreenPtr pScreenPriv; - XvMCAdaptorPtr adaptor = NULL; - int i; - - if(XvMCScreenKey == NULL) return NULL; - - if(!(pScreenPriv = XVMC_GET_PRIVATE(pScreen))) - return NULL; - - for(i = 0; i < pScreenPriv->num_adaptors; i++) { - if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) { - adaptor = &(pScreenPriv->adaptors[i]); - break; - } - } - - if(!adaptor) return NULL; - - for(i = 0; i < adaptor->num_subpictures; i++) { - if(adaptor->subpictures[i]->id == id) { - pImage = adaptor->subpictures[i]; - break; - } - } - - return pImage; -} - -int -xf86XvMCRegisterDRInfo(ScreenPtr pScreen, char *name, - char *busID, int major, int minor, - int patchLevel) -{ - XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pScreen); - strncpy(pScreenPriv->clientDriverName, name, - DR_CLIENT_DRIVER_NAME_SIZE); - strncpy(pScreenPriv->busID, busID, DR_BUSID_SIZE); - pScreenPriv->major = major; - pScreenPriv->minor = minor; - pScreenPriv->patchLevel = patchLevel; - pScreenPriv->clientDriverName[DR_CLIENT_DRIVER_NAME_SIZE-1] = 0; - pScreenPriv->busID[DR_BUSID_SIZE-1] = 0; - return Success; -} - + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "resource.h" +#include "scrnintstr.h" +#include "extnsionst.h" +#include "servermd.h" +#include +#include "xvdix.h" +#include +#include +#include +#include "xvmcext.h" +#include "protocol-versions.h" + +#ifdef HAS_XVMCSHM +#include +#include +#include +#endif /* HAS_XVMCSHM */ + + + +#define DR_CLIENT_DRIVER_NAME_SIZE 48 +#define DR_BUSID_SIZE 48 + +static int XvMCScreenKeyIndex; +static DevPrivateKey XvMCScreenKey; + +unsigned long XvMCGeneration = 0; + +int XvMCReqCode; +int XvMCEventBase; +int XvMCErrorBase; + +unsigned long XvMCRTContext; +unsigned long XvMCRTSurface; +unsigned long XvMCRTSubpicture; + +typedef struct { + int num_adaptors; + XvMCAdaptorPtr adaptors; + CloseScreenProcPtr CloseScreen; + char clientDriverName[DR_CLIENT_DRIVER_NAME_SIZE]; + char busID[DR_BUSID_SIZE]; + int major; + int minor; + int patchLevel; +} XvMCScreenRec, *XvMCScreenPtr; + +#define XVMC_GET_PRIVATE(pScreen) \ + (XvMCScreenPtr)(dixLookupPrivate(&(pScreen)->devPrivates, XvMCScreenKey)) + + +static int +XvMCDestroyContextRes(pointer data, XID id) +{ + XvMCContextPtr pContext = (XvMCContextPtr)data; + + pContext->refcnt--; + + if(!pContext->refcnt) { + XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); + (*pScreenPriv->adaptors[pContext->adapt_num].DestroyContext)(pContext); + free(pContext); + } + + return Success; +} + +static int +XvMCDestroySurfaceRes(pointer data, XID id) +{ + XvMCSurfacePtr pSurface = (XvMCSurfacePtr)data; + XvMCContextPtr pContext = pSurface->context; + XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); + + (*pScreenPriv->adaptors[pContext->adapt_num].DestroySurface)(pSurface); + free(pSurface); + + XvMCDestroyContextRes((pointer)pContext, pContext->context_id); + + return Success; +} + + +static int +XvMCDestroySubpictureRes(pointer data, XID id) +{ + XvMCSubpicturePtr pSubpict = (XvMCSubpicturePtr)data; + XvMCContextPtr pContext = pSubpict->context; + XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); + + (*pScreenPriv->adaptors[pContext->adapt_num].DestroySubpicture)(pSubpict); + free(pSubpict); + + XvMCDestroyContextRes((pointer)pContext, pContext->context_id); + + return Success; +} + +static int +ProcXvMCQueryVersion(ClientPtr client) +{ + xvmcQueryVersionReply rep; + /* REQUEST(xvmcQueryVersionReq); */ + REQUEST_SIZE_MATCH(xvmcQueryVersionReq); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.major = SERVER_XVMC_MAJOR_VERSION; + rep.minor = SERVER_XVMC_MINOR_VERSION; + WriteToClient(client, sizeof(xvmcQueryVersionReply), (char*)&rep); + return Success; +} + + +static int +ProcXvMCListSurfaceTypes(ClientPtr client) +{ + XvPortPtr pPort; + int i; + XvMCScreenPtr pScreenPriv; + xvmcListSurfaceTypesReply rep; + xvmcSurfaceInfo info; + XvMCAdaptorPtr adaptor = NULL; + XvMCSurfaceInfoPtr surface; + REQUEST(xvmcListSurfaceTypesReq); + REQUEST_SIZE_MATCH(xvmcListSurfaceTypesReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + if(XvMCScreenKey) { /* any adaptors at all */ + ScreenPtr pScreen = pPort->pAdaptor->pScreen; + if((pScreenPriv = XVMC_GET_PRIVATE(pScreen))) { /* any this screen */ + for(i = 0; i < pScreenPriv->num_adaptors; i++) { + if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) { + adaptor = &(pScreenPriv->adaptors[i]); + break; + } + } + } + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.num = (adaptor) ? adaptor->num_surfaces : 0; + rep.length = bytes_to_int32(rep.num * sizeof(xvmcSurfaceInfo)); + + WriteToClient(client, sizeof(xvmcListSurfaceTypesReply), (char*)&rep); + + for(i = 0; i < rep.num; i++) { + surface = adaptor->surfaces[i]; + info.surface_type_id = surface->surface_type_id; + info.chroma_format = surface->chroma_format; + info.max_width = surface->max_width; + info.max_height = surface->max_height; + info.subpicture_max_width = surface->subpicture_max_width; + info.subpicture_max_height = surface->subpicture_max_height; + info.mc_type = surface->mc_type; + info.flags = surface->flags; + WriteToClient(client, sizeof(xvmcSurfaceInfo), (char*)&info); + } + + return Success; +} + +static int +ProcXvMCCreateContext(ClientPtr client) +{ + XvPortPtr pPort; + CARD32 *data = NULL; + int dwords = 0; + int i, result, adapt_num = -1; + ScreenPtr pScreen; + XvMCContextPtr pContext; + XvMCScreenPtr pScreenPriv; + XvMCAdaptorPtr adaptor = NULL; + XvMCSurfaceInfoPtr surface = NULL; + xvmcCreateContextReply rep; + REQUEST(xvmcCreateContextReq); + REQUEST_SIZE_MATCH(xvmcCreateContextReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + pScreen = pPort->pAdaptor->pScreen; + + if(XvMCScreenKey == NULL) /* no XvMC adaptors */ + return BadMatch; + + if(!(pScreenPriv = XVMC_GET_PRIVATE(pScreen))) /* none this screen */ + return BadMatch; + + for(i = 0; i < pScreenPriv->num_adaptors; i++) { + if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) { + adaptor = &(pScreenPriv->adaptors[i]); + adapt_num = i; + break; + } + } + + if(adapt_num < 0) /* none this port */ + return BadMatch; + + for(i = 0; i < adaptor->num_surfaces; i++) { + if(adaptor->surfaces[i]->surface_type_id == stuff->surface_type_id) { + surface = adaptor->surfaces[i]; + break; + } + } + + /* adaptor doesn't support this suface_type_id */ + if(!surface) return BadMatch; + + + if((stuff->width > surface->max_width) || + (stuff->height > surface->max_height)) + return BadValue; + + if(!(pContext = malloc(sizeof(XvMCContextRec)))) { + return BadAlloc; + } + + + pContext->pScreen = pScreen; + pContext->adapt_num = adapt_num; + pContext->context_id = stuff->context_id; + pContext->surface_type_id = stuff->surface_type_id; + pContext->width = stuff->width; + pContext->height = stuff->height; + pContext->flags = stuff->flags; + pContext->refcnt = 1; + + result = (*adaptor->CreateContext)(pPort, pContext, &dwords, &data); + + if(result != Success) { + free(pContext); + return result; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.width_actual = pContext->width; + rep.height_actual = pContext->height; + rep.flags_return = pContext->flags; + rep.length = dwords; + + WriteToClient(client, sizeof(xvmcCreateContextReply), (char*)&rep); + if(dwords) + WriteToClient(client, dwords << 2, (char*)data); + AddResource(pContext->context_id, XvMCRTContext, pContext); + + if(data) + free(data); + + return Success; +} + +static int +ProcXvMCDestroyContext(ClientPtr client) +{ + pointer val; + int rc; + REQUEST(xvmcDestroyContextReq); + REQUEST_SIZE_MATCH(xvmcDestroyContextReq); + + rc = dixLookupResourceByType(&val, stuff->context_id, XvMCRTContext, + client, DixDestroyAccess); + if (rc != Success) + return (rc == BadValue) ? XvMCBadContext + XvMCErrorBase : rc; + + FreeResource(stuff->context_id, RT_NONE); + + return Success; +} + +static int +ProcXvMCCreateSurface(ClientPtr client) +{ + CARD32 *data = NULL; + int dwords = 0; + int result; + XvMCContextPtr pContext; + XvMCSurfacePtr pSurface; + XvMCScreenPtr pScreenPriv; + xvmcCreateSurfaceReply rep; + REQUEST(xvmcCreateSurfaceReq); + REQUEST_SIZE_MATCH(xvmcCreateSurfaceReq); + + result = dixLookupResourceByType((pointer *)&pContext, stuff->context_id, + XvMCRTContext, client, DixUseAccess); + if (result != Success) + return (result == BadValue) ? XvMCBadContext + XvMCErrorBase : result; + + pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); + + if(!(pSurface = malloc(sizeof(XvMCSurfaceRec)))) + return BadAlloc; + + pSurface->surface_id = stuff->surface_id; + pSurface->surface_type_id = pContext->surface_type_id; + pSurface->context = pContext; + + result = (*pScreenPriv->adaptors[pContext->adapt_num].CreateSurface)( + pSurface, &dwords, &data); + + if(result != Success) { + free(pSurface); + return result; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = dwords; + + WriteToClient(client, sizeof(xvmcCreateSurfaceReply), (char*)&rep); + if(dwords) + WriteToClient(client, dwords << 2, (char*)data); + AddResource(pSurface->surface_id, XvMCRTSurface, pSurface); + + if(data) + free(data); + + pContext->refcnt++; + + return Success; +} + +static int +ProcXvMCDestroySurface(ClientPtr client) +{ + pointer val; + int rc; + REQUEST(xvmcDestroySurfaceReq); + REQUEST_SIZE_MATCH(xvmcDestroySurfaceReq); + + rc = dixLookupResourceByType(&val, stuff->surface_id, XvMCRTSurface, + client, DixDestroyAccess); + if (rc != Success) + return (rc == BadValue) ? XvMCBadSurface + XvMCErrorBase : rc; + + FreeResource(stuff->surface_id, RT_NONE); + + return Success; +} + +static int +ProcXvMCCreateSubpicture(ClientPtr client) +{ + Bool image_supported = FALSE; + CARD32 *data = NULL; + int i, result, dwords = 0; + XvMCContextPtr pContext; + XvMCSubpicturePtr pSubpicture; + XvMCScreenPtr pScreenPriv; + xvmcCreateSubpictureReply rep; + XvMCAdaptorPtr adaptor; + XvMCSurfaceInfoPtr surface = NULL; + REQUEST(xvmcCreateSubpictureReq); + REQUEST_SIZE_MATCH(xvmcCreateSubpictureReq); + + result = dixLookupResourceByType((pointer *)&pContext, stuff->context_id, + XvMCRTContext, client, DixUseAccess); + if (result != Success) + return (result == BadValue) ? XvMCBadContext + XvMCErrorBase : result; + + pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen); + + adaptor = &(pScreenPriv->adaptors[pContext->adapt_num]); + + /* find which surface this context supports */ + for(i = 0; i < adaptor->num_surfaces; i++) { + if(adaptor->surfaces[i]->surface_type_id == pContext->surface_type_id){ + surface = adaptor->surfaces[i]; + break; + } + } + + if(!surface) return BadMatch; + + /* make sure this surface supports that xvimage format */ + if(!surface->compatible_subpictures) return BadMatch; + + for(i = 0; i < surface->compatible_subpictures->num_xvimages; i++) { + if(surface->compatible_subpictures->xvimage_ids[i] == stuff->xvimage_id) { + image_supported = TRUE; + break; + } + } + + if(!image_supported) return BadMatch; + + /* make sure the size is OK */ + if((stuff->width > surface->subpicture_max_width) || + (stuff->height > surface->subpicture_max_height)) + return BadValue; + + if(!(pSubpicture = malloc(sizeof(XvMCSubpictureRec)))) + return BadAlloc; + + pSubpicture->subpicture_id = stuff->subpicture_id; + pSubpicture->xvimage_id = stuff->xvimage_id; + pSubpicture->width = stuff->width; + pSubpicture->height = stuff->height; + pSubpicture->num_palette_entries = 0; /* overwritten by DDX */ + pSubpicture->entry_bytes = 0; /* overwritten by DDX */ + pSubpicture->component_order[0] = 0; /* overwritten by DDX */ + pSubpicture->component_order[1] = 0; + pSubpicture->component_order[2] = 0; + pSubpicture->component_order[3] = 0; + pSubpicture->context = pContext; + + result = (*pScreenPriv->adaptors[pContext->adapt_num].CreateSubpicture)( + pSubpicture, &dwords, &data); + + if(result != Success) { + free(pSubpicture); + return result; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.width_actual = pSubpicture->width; + rep.height_actual = pSubpicture->height; + rep.num_palette_entries = pSubpicture->num_palette_entries; + rep.entry_bytes = pSubpicture->entry_bytes; + rep.component_order[0] = pSubpicture->component_order[0]; + rep.component_order[1] = pSubpicture->component_order[1]; + rep.component_order[2] = pSubpicture->component_order[2]; + rep.component_order[3] = pSubpicture->component_order[3]; + rep.length = dwords; + + WriteToClient(client, sizeof(xvmcCreateSubpictureReply), (char*)&rep); + if(dwords) + WriteToClient(client, dwords << 2, (char*)data); + AddResource(pSubpicture->subpicture_id, XvMCRTSubpicture, pSubpicture); + + if(data) + free(data); + + pContext->refcnt++; + + return Success; +} + +static int +ProcXvMCDestroySubpicture(ClientPtr client) +{ + pointer val; + int rc; + REQUEST(xvmcDestroySubpictureReq); + REQUEST_SIZE_MATCH(xvmcDestroySubpictureReq); + + rc = dixLookupResourceByType(&val, stuff->subpicture_id, XvMCRTSubpicture, + client, DixDestroyAccess); + if (rc != Success) + return (rc == BadValue) ? XvMCBadSubpicture + XvMCErrorBase : rc; + + FreeResource(stuff->subpicture_id, RT_NONE); + + return Success; +} + + +static int +ProcXvMCListSubpictureTypes(ClientPtr client) +{ + XvPortPtr pPort; + xvmcListSubpictureTypesReply rep; + XvMCScreenPtr pScreenPriv; + ScreenPtr pScreen; + XvMCAdaptorPtr adaptor = NULL; + XvMCSurfaceInfoPtr surface = NULL; + xvImageFormatInfo info; + XvImagePtr pImage; + int i, j; + REQUEST(xvmcListSubpictureTypesReq); + REQUEST_SIZE_MATCH(xvmcListSubpictureTypesReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + pScreen = pPort->pAdaptor->pScreen; + + if(XvMCScreenKey == NULL) /* No XvMC adaptors */ + return BadMatch; + + if(!(pScreenPriv = XVMC_GET_PRIVATE(pScreen))) + return BadMatch; /* None this screen */ + + for(i = 0; i < pScreenPriv->num_adaptors; i++) { + if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) { + adaptor = &(pScreenPriv->adaptors[i]); + break; + } + } + + if(!adaptor) return BadMatch; + + for(i = 0; i < adaptor->num_surfaces; i++) { + if(adaptor->surfaces[i]->surface_type_id == stuff->surface_type_id) { + surface = adaptor->surfaces[i]; + break; + } + } + + if(!surface) return BadMatch; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.num = 0; + if(surface->compatible_subpictures) + rep.num = surface->compatible_subpictures->num_xvimages; + + rep.length = bytes_to_int32(rep.num * sizeof(xvImageFormatInfo)); + + WriteToClient(client, sizeof(xvmcListSubpictureTypesReply), (char*)&rep); + + for(i = 0; i < rep.num; i++) { + pImage = NULL; + for(j = 0; j < adaptor->num_subpictures; j++) { + if(surface->compatible_subpictures->xvimage_ids[i] == + adaptor->subpictures[j]->id) + { + pImage = adaptor->subpictures[j]; + break; + } + } + if(!pImage) return BadImplementation; + + info.id = pImage->id; + info.type = pImage->type; + info.byte_order = pImage->byte_order; + memcpy(&info.guid, pImage->guid, 16); + info.bpp = pImage->bits_per_pixel; + info.num_planes = pImage->num_planes; + info.depth = pImage->depth; + info.red_mask = pImage->red_mask; + info.green_mask = pImage->green_mask; + info.blue_mask = pImage->blue_mask; + info.format = pImage->format; + info.y_sample_bits = pImage->y_sample_bits; + info.u_sample_bits = pImage->u_sample_bits; + info.v_sample_bits = pImage->v_sample_bits; + info.horz_y_period = pImage->horz_y_period; + info.horz_u_period = pImage->horz_u_period; + info.horz_v_period = pImage->horz_v_period; + info.vert_y_period = pImage->vert_y_period; + info.vert_u_period = pImage->vert_u_period; + info.vert_v_period = pImage->vert_v_period; + memcpy(&info.comp_order, pImage->component_order, 32); + info.scanline_order = pImage->scanline_order; + WriteToClient(client, sizeof(xvImageFormatInfo), (char*)&info); + } + + return Success; +} + +static int +ProcXvMCGetDRInfo(ClientPtr client) +{ + xvmcGetDRInfoReply rep; + XvPortPtr pPort; + ScreenPtr pScreen; + XvMCScreenPtr pScreenPriv; + +#ifdef HAS_XVMCSHM + volatile CARD32 *patternP; +#endif + + REQUEST(xvmcGetDRInfoReq); + REQUEST_SIZE_MATCH(xvmcGetDRInfoReq); + + VALIDATE_XV_PORT(stuff->port, pPort, DixReadAccess); + + pScreen = pPort->pAdaptor->pScreen; + pScreenPriv = XVMC_GET_PRIVATE(pScreen); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.major = pScreenPriv->major; + rep.minor = pScreenPriv->minor; + rep.patchLevel = pScreenPriv->patchLevel; + rep.nameLen = bytes_to_int32(strlen(pScreenPriv->clientDriverName) + 1); + rep.busIDLen = bytes_to_int32(strlen(pScreenPriv->busID) + 1); + + rep.length = rep.nameLen + rep.busIDLen; + rep.nameLen <<=2; + rep.busIDLen <<=2; + + /* + * Read back to the client what she has put in the shared memory + * segment she prepared for us. + */ + + rep.isLocal = 1; +#ifdef HAS_XVMCSHM + patternP = (CARD32 *)shmat( stuff->shmKey, NULL, SHM_RDONLY ); + if ( -1 != (long) patternP) { + volatile CARD32 *patternC = patternP; + int i; + CARD32 magic = stuff->magic; + + rep.isLocal = 1; + i = 1024 / sizeof(CARD32); + + while ( i-- ) { + if (*patternC++ != magic) { + rep.isLocal = 0; + break; + } + magic = ~magic; + } + shmdt( (char *)patternP ); + } +#endif /* HAS_XVMCSHM */ + + WriteToClient(client, sizeof(xvmcGetDRInfoReply), + (char*)&rep); + if (rep.length) { + WriteToClient(client, rep.nameLen, + pScreenPriv->clientDriverName); + WriteToClient(client, rep.busIDLen, + pScreenPriv->busID); + } + return Success; +} + + +int (*ProcXvMCVector[xvmcNumRequest])(ClientPtr) = { + ProcXvMCQueryVersion, + ProcXvMCListSurfaceTypes, + ProcXvMCCreateContext, + ProcXvMCDestroyContext, + ProcXvMCCreateSurface, + ProcXvMCDestroySurface, + ProcXvMCCreateSubpicture, + ProcXvMCDestroySubpicture, + ProcXvMCListSubpictureTypes, + ProcXvMCGetDRInfo +}; + +static int +ProcXvMCDispatch (ClientPtr client) +{ + REQUEST(xReq); + + if(stuff->data < xvmcNumRequest) + return (*ProcXvMCVector[stuff->data])(client); + else + return BadRequest; +} + +static int +SProcXvMCDispatch (ClientPtr client) +{ + /* We only support local */ + return BadImplementation; +} + +void +XvMCExtensionInit(void) +{ + ExtensionEntry *extEntry; + + if(XvMCScreenKey == NULL) /* nobody supports it */ + return; + + if(!(XvMCRTContext = CreateNewResourceType(XvMCDestroyContextRes, + "XvMCRTContext"))) + return; + + if(!(XvMCRTSurface = CreateNewResourceType(XvMCDestroySurfaceRes, + "XvMCRTSurface"))) + return; + + if(!(XvMCRTSubpicture = CreateNewResourceType(XvMCDestroySubpictureRes, + "XvMCRTSubpicture"))) + return; + + extEntry = AddExtension(XvMCName, XvMCNumEvents, XvMCNumErrors, + ProcXvMCDispatch, SProcXvMCDispatch, + NULL, StandardMinorOpcode); + + if(!extEntry) return; + + XvMCReqCode = extEntry->base; + XvMCEventBase = extEntry->eventBase; + XvMCErrorBase = extEntry->errorBase; +} + +static Bool +XvMCCloseScreen (int i, ScreenPtr pScreen) +{ + XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pScreen); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + + free(pScreenPriv); + + return (*pScreen->CloseScreen)(i, pScreen); +} + + +int +XvMCScreenInit(ScreenPtr pScreen, int num, XvMCAdaptorPtr pAdapt) +{ + XvMCScreenPtr pScreenPriv; + + XvMCScreenKey = &XvMCScreenKeyIndex; + + if(!(pScreenPriv = malloc(sizeof(XvMCScreenRec)))) + return BadAlloc; + + dixSetPrivate(&pScreen->devPrivates, XvMCScreenKey, pScreenPriv); + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = XvMCCloseScreen; + + pScreenPriv->num_adaptors = num; + pScreenPriv->adaptors = pAdapt; + pScreenPriv->clientDriverName[0] = 0; + pScreenPriv->busID[0] = 0; + pScreenPriv->major = 0; + pScreenPriv->minor = 0; + pScreenPriv->patchLevel = 0; + + return Success; +} + +XvImagePtr XvMCFindXvImage(XvPortPtr pPort, CARD32 id) +{ + XvImagePtr pImage = NULL; + ScreenPtr pScreen = pPort->pAdaptor->pScreen; + XvMCScreenPtr pScreenPriv; + XvMCAdaptorPtr adaptor = NULL; + int i; + + if(XvMCScreenKey == NULL) return NULL; + + if(!(pScreenPriv = XVMC_GET_PRIVATE(pScreen))) + return NULL; + + for(i = 0; i < pScreenPriv->num_adaptors; i++) { + if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) { + adaptor = &(pScreenPriv->adaptors[i]); + break; + } + } + + if(!adaptor) return NULL; + + for(i = 0; i < adaptor->num_subpictures; i++) { + if(adaptor->subpictures[i]->id == id) { + pImage = adaptor->subpictures[i]; + break; + } + } + + return pImage; +} + +int +xf86XvMCRegisterDRInfo(ScreenPtr pScreen, char *name, + char *busID, int major, int minor, + int patchLevel) +{ + XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pScreen); + strncpy(pScreenPriv->clientDriverName, name, + DR_CLIENT_DRIVER_NAME_SIZE); + strncpy(pScreenPriv->busID, busID, DR_BUSID_SIZE); + pScreenPriv->major = major; + pScreenPriv->minor = minor; + pScreenPriv->patchLevel = patchLevel; + pScreenPriv->clientDriverName[DR_CLIENT_DRIVER_NAME_SIZE-1] = 0; + pScreenPriv->busID[DR_BUSID_SIZE-1] = 0; + return Success; +} + diff --git a/xorg-server/Xi/exevents.c b/xorg-server/Xi/exevents.c index 949efe77f..97ad6fdd2 100644 --- a/xorg-server/Xi/exevents.c +++ b/xorg-server/Xi/exevents.c @@ -1,2178 +1,2178 @@ -/************************************************************ - -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. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - 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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-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. - -********************************************************/ - -/******************************************************************** - * - * Routines to register and initialize extension input devices. - * This also contains ProcessOtherEvent, the routine called from DDX - * to route extension events. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" -#include -#include -#include -#include -#include -#include -#include "windowstr.h" -#include "miscstruct.h" -#include "region.h" -#include "exevents.h" -#include "extnsionst.h" -#include "exglobals.h" -#include "dixevents.h" /* DeliverFocusedEvent */ -#include "dixgrabs.h" /* CreateGrab() */ -#include "scrnintstr.h" -#include "listdev.h" /* for CopySwapXXXClass */ -#include "xace.h" -#include "xiquerydevice.h" /* For List*Info */ -#include "eventconvert.h" -#include "eventstr.h" - -#include -#include "xkbsrv.h" - -#define WID(w) ((w) ? ((w)->drawable.id) : 0) -#define AllModifiersMask ( \ - ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ - Mod3Mask | Mod4Mask | Mod5Mask ) -#define AllButtonsMask ( \ - Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) - -Bool ShouldFreeInputMasks(WindowPtr /* pWin */ , - Bool /* ignoreSelectedEvents */ - ); -static Bool MakeInputMasks(WindowPtr /* pWin */ - ); - -/* - * Only let the given client know of core events which will affect its - * interpretation of input events, if the client's ClientPointer (or the - * paired keyboard) is the current device. - */ -int -XIShouldNotify(ClientPtr client, DeviceIntPtr dev) -{ - DeviceIntPtr current_ptr = PickPointer(client); - DeviceIntPtr current_kbd = GetPairedDevice(current_ptr); - - if (dev == current_kbd || dev == current_ptr) - return 1; - - return 0; -} - -void -RegisterOtherDevice(DeviceIntPtr device) -{ - device->public.processInputProc = ProcessOtherEvent; - device->public.realInputProc = ProcessOtherEvent; -} - -Bool -IsPointerEvent(InternalEvent* event) -{ - switch(event->any.type) - { - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_Motion: - /* XXX: enter/leave ?? */ - return TRUE; - default: - break; - } - return FALSE; -} - -/** - * @return the device matching the deviceid of the device set in the event, or - * NULL if the event is not an XInput event. - */ -DeviceIntPtr -XIGetDevice(xEvent* xE) -{ - DeviceIntPtr pDev = NULL; - - if (xE->u.u.type == DeviceButtonPress || - xE->u.u.type == DeviceButtonRelease || - xE->u.u.type == DeviceMotionNotify || - xE->u.u.type == ProximityIn || - xE->u.u.type == ProximityOut || - xE->u.u.type == DevicePropertyNotify) - { - int rc; - int id; - - id = ((deviceKeyButtonPointer*)xE)->deviceid & ~MORE_EVENTS; - - rc = dixLookupDevice(&pDev, id, serverClient, DixUnknownAccess); - if (rc != Success) - ErrorF("[dix] XIGetDevice failed on XACE restrictions (%d)\n", rc); - } - return pDev; -} - - -/** - * Copy the device->key into master->key and send a mapping notify to the - * clients if appropriate. - * master->key needs to be allocated by the caller. - * - * Device is the slave device. If it is attached to a master device, we may - * need to send a mapping notify to the client because it causes the MD - * to change state. - * - * Mapping notify needs to be sent in the following cases: - * - different slave device on same master - * - different master - * - * XXX: They way how the code is we also send a map notify if the slave device - * stays the same, but the master changes. This isn't really necessary though. - * - * XXX: this gives you funny behaviour with the ClientPointer. When a - * MappingNotify is sent to the client, the client usually responds with a - * GetKeyboardMapping. This will retrieve the ClientPointer's keyboard - * mapping, regardless of which keyboard sent the last mapping notify request. - * So depending on the CP setting, your keyboard may change layout in each - * app... - * - * This code is basically the old SwitchCoreKeyboard. - */ - -void -CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master) -{ - KeyClassPtr mk = master->key; - KeyClassPtr dk = device->key; - int i; - - if (device == master) - return; - - mk->sourceid = device->id; - - for (i = 0; i < 8; i++) - mk->modifierKeyCount[i] = dk->modifierKeyCount[i]; - - if (!XkbCopyDeviceKeymap(master, device)) - FatalError("Couldn't pivot keymap from device to core!\n"); -} - -/** - * Copies the feedback classes from device "from" into device "to". Classes - * are duplicated (not just flipping the pointers). All feedback classes are - * linked lists, the full list is duplicated. - */ -static void -DeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to) -{ - ClassesPtr classes; - - - if (from->intfeed) - { - IntegerFeedbackPtr *i, it; - - if (!to->intfeed) - { - classes = to->unused_classes; - to->intfeed = classes->intfeed; - } - - i = &to->intfeed; - for (it = from->intfeed; it; it = it->next) - { - if (!(*i)) - { - *i = xcalloc(1, sizeof(IntegerFeedbackClassRec)); - if (!(*i)) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*i)->CtrlProc = it->CtrlProc; - (*i)->ctrl = it->ctrl; - - i = &(*i)->next; - } - } else if (to->intfeed && !from->intfeed) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->intfeed = to->intfeed; - to->intfeed = NULL; - } - - if (from->stringfeed) - { - StringFeedbackPtr *s, it; - - if (!to->stringfeed) - { - classes = to->unused_classes; - to->stringfeed = classes->stringfeed; - } - - s = &to->stringfeed; - for (it = from->stringfeed; it; it = it->next) - { - if (!(*s)) - { - *s = xcalloc(1, sizeof(StringFeedbackClassRec)); - if (!(*s)) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*s)->CtrlProc = it->CtrlProc; - (*s)->ctrl = it->ctrl; - - s = &(*s)->next; - } - } else if (to->stringfeed && !from->stringfeed) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->stringfeed = to->stringfeed; - to->stringfeed = NULL; - } - - if (from->bell) - { - BellFeedbackPtr *b, it; - - if (!to->bell) - { - classes = to->unused_classes; - to->bell = classes->bell; - } - - b = &to->bell; - for (it = from->bell; it; it = it->next) - { - if (!(*b)) - { - *b = xcalloc(1, sizeof(BellFeedbackClassRec)); - if (!(*b)) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*b)->BellProc = it->BellProc; - (*b)->CtrlProc = it->CtrlProc; - (*b)->ctrl = it->ctrl; - - b = &(*b)->next; - } - } else if (to->bell && !from->bell) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->bell = to->bell; - to->bell = NULL; - } - - if (from->leds) - { - LedFeedbackPtr *l, it; - - if (!to->leds) - { - classes = to->unused_classes; - to->leds = classes->leds; - } - - l = &to->leds; - for (it = from->leds; it; it = it->next) - { - if (!(*l)) - { - *l = xcalloc(1, sizeof(LedFeedbackClassRec)); - if (!(*l)) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*l)->CtrlProc = it->CtrlProc; - (*l)->ctrl = it->ctrl; - if ((*l)->xkb_sli) - XkbFreeSrvLedInfo((*l)->xkb_sli); - (*l)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, NULL, *l); - - l = &(*l)->next; - } - } else if (to->leds && !from->leds) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->leds = to->leds; - to->leds = NULL; - } -} - -static void -DeepCopyKeyboardClasses(DeviceIntPtr from, DeviceIntPtr to) -{ - ClassesPtr classes; - - /* XkbInitDevice (->XkbInitIndicatorMap->XkbFindSrvLedInfo) relies on the - * kbdfeed to be set up properly, so let's do the feedback classes first. - */ - if (from->kbdfeed) - { - KbdFeedbackPtr *k, it; - - if (!to->kbdfeed) - { - classes = to->unused_classes; - - to->kbdfeed = classes->kbdfeed; - if (!to->kbdfeed) - InitKeyboardDeviceStruct(to, NULL, NULL, NULL); - } - - k = &to->kbdfeed; - for(it = from->kbdfeed; it; it = it->next) - { - if (!(*k)) - { - *k = xcalloc(1, sizeof(KbdFeedbackClassRec)); - if (!*k) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*k)->BellProc = it->BellProc; - (*k)->CtrlProc = it->CtrlProc; - (*k)->ctrl = it->ctrl; - if ((*k)->xkb_sli) - XkbFreeSrvLedInfo((*k)->xkb_sli); - (*k)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, *k, NULL); - - k = &(*k)->next; - } - } else if (to->kbdfeed && !from->kbdfeed) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->kbdfeed = to->kbdfeed; - to->kbdfeed = NULL; - } - - if (from->key) - { - if (!to->key) - { - classes = to->unused_classes; - to->key = classes->key; - if (!to->key) - InitKeyboardDeviceStruct(to, NULL, NULL, NULL); - else - classes->key = NULL; - } - - CopyKeyClass(from, to); - } else if (to->key && !from->key) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->key = to->key; - to->key = NULL; - } - - /* If a SrvLedInfoPtr's flags are XkbSLI_IsDefault, the names and maps - * pointer point into the xkbInfo->desc struct. XkbCopySrvLedInfo - * didn't update the pointers so we need to do it manually here. - */ - if (to->kbdfeed) - { - KbdFeedbackPtr k; - - for (k = to->kbdfeed; k; k = k->next) - { - if (!k->xkb_sli) - continue; - if (k->xkb_sli->flags & XkbSLI_IsDefault) - { - k->xkb_sli->names = to->key->xkbInfo->desc->names->indicators; - k->xkb_sli->maps = to->key->xkbInfo->desc->indicators->maps; - } - } - } - - /* We can't just copy over the focus class. When an app sets the focus, - * it'll do so on the master device. Copying the SDs focus means losing - * the focus. - * So we only copy the focus class if the device didn't have one, - * otherwise we leave it as it is. - */ - if (from->focus) - { - if (!to->focus) - { - WindowPtr *oldTrace; - - classes = to->unused_classes; - to->focus = classes->focus; - if (!to->focus) - { - to->focus = xcalloc(1, sizeof(FocusClassRec)); - if (!to->focus) - FatalError("[Xi] no memory for class shift.\n"); - } else - classes->focus = NULL; - - oldTrace = to->focus->trace; - memcpy(to->focus, from->focus, sizeof(FocusClassRec)); - to->focus->trace = xrealloc(oldTrace, - to->focus->traceSize * sizeof(WindowPtr)); - if (!to->focus->trace && to->focus->traceSize) - FatalError("[Xi] no memory for trace.\n"); - memcpy(to->focus->trace, from->focus->trace, - from->focus->traceSize * sizeof(WindowPtr)); - to->focus->sourceid = from->id; - } - } else if (to->focus) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->focus = to->focus; - to->focus = NULL; - } - -} - -static void -DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) -{ - ClassesPtr classes; - - /* Feedback classes must be copied first */ - if (from->ptrfeed) - { - PtrFeedbackPtr *p, it; - if (!to->ptrfeed) - { - classes = to->unused_classes; - to->ptrfeed = classes->ptrfeed; - } - - p = &to->ptrfeed; - for (it = from->ptrfeed; it; it = it->next) - { - if (!(*p)) - { - *p = xcalloc(1, sizeof(PtrFeedbackClassRec)); - if (!*p) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*p)->CtrlProc = it->CtrlProc; - (*p)->ctrl = it->ctrl; - - p = &(*p)->next; - } - } else if (to->ptrfeed && !from->ptrfeed) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->ptrfeed = to->ptrfeed; - to->ptrfeed = NULL; - } - - if (from->valuator) - { - ValuatorClassPtr v; - if (!to->valuator) - { - classes = to->unused_classes; - to->valuator = classes->valuator; - if (to->valuator) - classes->valuator = NULL; - } - - to->valuator = xrealloc(to->valuator, sizeof(ValuatorClassRec) + - from->valuator->numAxes * sizeof(AxisInfo) + - from->valuator->numAxes * sizeof(double)); - v = to->valuator; - if (!v) - FatalError("[Xi] no memory for class shift.\n"); - - v->numAxes = from->valuator->numAxes; - v->axes = (AxisInfoPtr)&v[1]; - memcpy(v->axes, from->valuator->axes, v->numAxes * sizeof(AxisInfo)); - - v->axisVal = (double*)(v->axes + from->valuator->numAxes); - v->sourceid = from->id; - v->mode = from->valuator->mode; - } else if (to->valuator && !from->valuator) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->valuator = to->valuator; - to->valuator = NULL; - } - - if (from->button) - { - if (!to->button) - { - classes = to->unused_classes; - to->button = classes->button; - if (!to->button) - { - to->button = xcalloc(1, sizeof(ButtonClassRec)); - if (!to->button) - FatalError("[Xi] no memory for class shift.\n"); - } else - classes->button = NULL; - } - - if (from->button->xkb_acts) - { - if (!to->button->xkb_acts) - { - to->button->xkb_acts = xcalloc(1, sizeof(XkbAction)); - if (!to->button->xkb_acts) - FatalError("[Xi] not enough memory for xkb_acts.\n"); - } - memcpy(to->button->xkb_acts, from->button->xkb_acts, - sizeof(XkbAction)); - } else - xfree(to->button->xkb_acts); - - memcpy(to->button->labels, from->button->labels, - from->button->numButtons * sizeof(Atom)); - to->button->sourceid = from->id; - } else if (to->button && !from->button) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->button = to->button; - to->button = NULL; - } - - if (from->proximity) - { - if (!to->proximity) - { - classes = to->unused_classes; - to->proximity = classes->proximity; - if (!to->proximity) - { - to->proximity = xcalloc(1, sizeof(ProximityClassRec)); - if (!to->proximity) - FatalError("[Xi] no memory for class shift.\n"); - } else - classes->proximity = NULL; - } - memcpy(to->proximity, from->proximity, sizeof(ProximityClassRec)); - to->proximity->sourceid = from->id; - } else if (to->proximity) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->proximity = to->proximity; - to->proximity = NULL; - } - - if (from->absolute) - { - if (!to->absolute) - { - classes = to->unused_classes; - to->absolute = classes->absolute; - if (!to->absolute) - { - to->absolute = xcalloc(1, sizeof(AbsoluteClassRec)); - if (!to->absolute) - FatalError("[Xi] no memory for class shift.\n"); - } else - classes->absolute = NULL; - } - memcpy(to->absolute, from->absolute, sizeof(AbsoluteClassRec)); - to->absolute->sourceid = from->id; - } else if (to->absolute) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->absolute = to->absolute; - to->absolute = NULL; - } -} - -/** - * Copies the CONTENT of the classes of device from into the classes in device - * to. From and to are identical after finishing. - * - * If to does not have classes from currenly has, the classes are stored in - * to's devPrivates system. Later, we recover it again from there if needed. - * Saves a few memory allocations. - */ -void -DeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to, DeviceChangedEvent *dce) -{ - /* generic feedback classes, not tied to pointer and/or keyboard */ - DeepCopyFeedbackClasses(from, to); - - if ((dce->flags & DEVCHANGE_KEYBOARD_EVENT)) - DeepCopyKeyboardClasses(from, to); - if ((dce->flags & DEVCHANGE_POINTER_EVENT)) - DeepCopyPointerClasses(from, to); -} - - -/** - * Send an XI2 DeviceChangedEvent to all interested clients. - */ -void -XISendDeviceChangedEvent(DeviceIntPtr device, DeviceIntPtr master, DeviceChangedEvent *dce) -{ - xXIDeviceChangedEvent *dcce; - int rc; - - rc = EventToXI2((InternalEvent*)dce, (xEvent**)&dcce); - if (rc != Success) - { - ErrorF("[Xi] event conversion from DCE failed with code %d\n", rc); - return; - } - - /* we don't actually swap if there's a NullClient, swapping is done - * later when event is delivered. */ - SendEventToAllWindows(master, XI_DeviceChangedMask, (xEvent*)dcce, 1); - xfree(dcce); -} - -static void -ChangeMasterDeviceClasses(DeviceIntPtr device, DeviceChangedEvent *dce) -{ - DeviceIntPtr slave; - int rc; - - /* For now, we don't have devices that change physically. */ - if (!IsMaster(device)) - return; - - rc = dixLookupDevice(&slave, dce->sourceid, serverClient, DixReadAccess); - - if (rc != Success) - return; /* Device has disappeared */ - - if (!slave->u.master) - return; /* set floating since the event */ - - if (slave->u.master->id != dce->masterid) - return; /* not our slave anymore, don't care */ - - /* FIXME: we probably need to send a DCE for the new slave now */ - - device->public.devicePrivate = slave->public.devicePrivate; - - /* FIXME: the classes may have changed since we generated the event. */ - DeepCopyDeviceClasses(slave, device, dce); - XISendDeviceChangedEvent(slave, device, dce); -} - -/** - * Update the device state according to the data in the event. - * - * return values are - * DEFAULT ... process as normal - * DONT_PROCESS ... return immediately from caller - */ -#define DEFAULT 0 -#define DONT_PROCESS 1 -int -UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event) -{ - int i; - int key = 0, - bit = 0, - last_valuator; - - KeyClassPtr k = NULL; - ButtonClassPtr b = NULL; - ValuatorClassPtr v = NULL; - BYTE *kptr = NULL; - - /* This event is always the first we get, before the actual events with - * the data. However, the way how the DDX is set up, "device" will - * actually be the slave device that caused the event. - */ - switch(event->type) - { - case ET_DeviceChanged: - ChangeMasterDeviceClasses(device, (DeviceChangedEvent*)event); - return DONT_PROCESS; /* event has been sent already */ - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - break; - default: - /* other events don't update the device */ - return DEFAULT; - } - - k = device->key; - v = device->valuator; - b = device->button; - - key = event->detail.key; - bit = 1 << (key & 7); - - /* Update device axis */ - /* Check valuators first */ - last_valuator = -1; - for (i = 0; i < MAX_VALUATORS; i++) - { - if (BitIsOn(&event->valuators.mask, i)) - { - if (!v) - { - ErrorF("[Xi] Valuators reported for non-valuator device '%s'. " - "Ignoring event.\n", device->name); - return DONT_PROCESS; - } else if (v->numAxes < i) - { - ErrorF("[Xi] Too many valuators reported for device '%s'. " - "Ignoring event.\n", device->name); - return DONT_PROCESS; - } - last_valuator = i; - } - } - - for (i = 0; i <= last_valuator && i < v->numAxes; i++) - { - if (BitIsOn(&event->valuators.mask, i)) - { - /* XXX: Relative/Absolute mode */ - v->axisVal[i] = event->valuators.data[i]; - v->axisVal[i] += (event->valuators.data_frac[i] * 1.0f / (1 << 16) / (1 << 16)); - } - } - - if (event->type == ET_KeyPress) { - if (!k) - return DONT_PROCESS; - - kptr = &k->down[key >> 3]; - /* don't allow ddx to generate multiple downs, but repeats are okay */ - if ((*kptr & bit) && !event->key_repeat) - return DONT_PROCESS; - if (device->valuator) - device->valuator->motionHintWindow = NullWindow; - *kptr |= bit; - } else if (event->type == ET_KeyRelease) { - if (!k) - return DONT_PROCESS; - - kptr = &k->down[key >> 3]; - if (!(*kptr & bit)) /* guard against duplicates */ - return DONT_PROCESS; - if (device->valuator) - device->valuator->motionHintWindow = NullWindow; - *kptr &= ~bit; - } else if (event->type == ET_ButtonPress) { - Mask mask; - if (!b) - return DONT_PROCESS; - - kptr = &b->down[key >> 3]; - if ((*kptr & bit) != 0) - return DONT_PROCESS; - *kptr |= bit; - if (device->valuator) - device->valuator->motionHintWindow = NullWindow; - if (!b->map[key]) - return DONT_PROCESS; - b->buttonsDown++; - b->motionMask = DeviceButtonMotionMask; - if (b->map[key] <= 5) - b->state |= (Button1Mask >> 1) << b->map[key]; - - /* Add state and motionMask to the filter for this event */ - mask = DevicePointerMotionMask | b->state | b->motionMask; - SetMaskForEvent(device->id, mask, DeviceMotionNotify); - mask = PointerMotionMask | b->state | b->motionMask; - SetMaskForEvent(device->id, mask, MotionNotify); - } else if (event->type == ET_ButtonRelease) { - Mask mask; - if (!b) - return DONT_PROCESS; - - kptr = &b->down[key>>3]; - if (!(*kptr & bit)) - return DONT_PROCESS; - if (IsMaster(device)) { - DeviceIntPtr sd; - - /* - * Leave the button down if any slave has the - * button still down. Note that this depends on the - * event being delivered through the slave first - */ - for (sd = inputInfo.devices; sd; sd = sd->next) { - if (IsMaster(sd) || sd->u.master != device) - continue; - if (!sd->button) - continue; - if ((sd->button->down[key>>3] & bit) != 0) - return DONT_PROCESS; - } - } - *kptr &= ~bit; - if (device->valuator) - device->valuator->motionHintWindow = NullWindow; - if (!b->map[key]) - return DONT_PROCESS; - if (b->buttonsDown >= 1 && !--b->buttonsDown) - b->motionMask = 0; - if (b->map[key] <= 5) - b->state &= ~((Button1Mask >> 1) << b->map[key]); - - /* Add state and motionMask to the filter for this event */ - mask = DevicePointerMotionMask | b->state | b->motionMask; - SetMaskForEvent(device->id, mask, DeviceMotionNotify); - mask = PointerMotionMask | b->state | b->motionMask; - SetMaskForEvent(device->id, mask, MotionNotify); - } else if (event->type == ET_ProximityIn) - device->valuator->mode &= ~OutOfProximity; - else if (event->type == ET_ProximityOut) - device->valuator->mode |= OutOfProximity; - - return DEFAULT; -} - -static void -ProcessRawEvent(RawDeviceEvent *ev, DeviceIntPtr device) -{ - GrabPtr grab = device->deviceGrab.grab; - - if (grab) - DeliverGrabbedEvent((InternalEvent*)ev, device, FALSE); - else { /* deliver to all root windows */ - xEvent *xi; - int i; - - i = EventToXI2((InternalEvent*)ev, (xEvent**)&xi); - if (i != Success) - { - ErrorF("[Xi] %s: XI2 conversion failed in ProcessRawEvent (%d)\n", - device->name, i); - return; - } - - for (i = 0; i < screenInfo.numScreens; i++) - DeliverEventsToWindow(device, WindowTable[i], xi, 1, - GetEventFilter(device, xi), NULL); - xfree(xi); - } -} - -/** - * Main device event processing function. - * Called from when processing the events from the event queue. - * - */ -void -ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device) -{ - GrabPtr grab; - Bool deactivateDeviceGrab = FALSE; - int key = 0, rootX, rootY; - ButtonClassPtr b; - KeyClassPtr k; - ValuatorClassPtr v; - int ret = 0; - int state, i; - DeviceIntPtr mouse = NULL, kbd = NULL; - DeviceEvent *event = &ev->device_event; - - CHECKEVENT(ev); - - if (ev->any.type == ET_RawKeyPress || - ev->any.type == ET_RawKeyRelease || - ev->any.type == ET_RawButtonPress || - ev->any.type == ET_RawButtonRelease || - ev->any.type == ET_RawMotion) - { - ProcessRawEvent(&ev->raw_event, device); - return; - } - - if (IsPointerDevice(device)) - { - kbd = GetPairedDevice(device); - mouse = device; - if (!kbd->key) /* can happen with floating SDs */ - kbd = NULL; - } else - { - mouse = GetPairedDevice(device); - kbd = device; - if (!mouse->valuator || !mouse->button) /* may be float. SDs */ - mouse = NULL; - } - - /* State needs to be assembled BEFORE the device is updated. */ - state = (kbd && kbd->key) ? XkbStateFieldFromRec(&kbd->key->xkbInfo->state) : 0; - state |= (mouse && mouse->button) ? (mouse->button->state) : 0; - - for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) - if (BitIsOn(mouse->button->down, i)) - SetBit(event->buttons, i); - - if (kbd && kbd->key) - { - XkbStatePtr state; - /* we need the state before the event happens */ - if (event->type == ET_KeyPress || event->type == ET_KeyRelease) - state = &kbd->key->xkbInfo->prev_state; - else - state = &kbd->key->xkbInfo->state; - - event->mods.base = state->base_mods; - event->mods.latched = state->latched_mods; - event->mods.locked = state->locked_mods; - event->mods.effective = state->mods; - - event->group.base = state->base_group; - event->group.latched = state->latched_group; - event->group.locked = state->locked_group; - event->group.effective = state->group; - } - - ret = UpdateDeviceState(device, event); - if (ret == DONT_PROCESS) - return; - - v = device->valuator; - b = device->button; - k = device->key; - - if (IsMaster(device) || !device->u.master) - CheckMotion(event, device); - - switch (event->type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - GetSpritePosition(device, &rootX, &rootY); - event->root_x = rootX; - event->root_y = rootY; - NoticeEventTime((InternalEvent*)event); - event->corestate = state; - key = event->detail.key; - break; - default: - break; - } - - if (DeviceEventCallback && !syncEvents.playingEvents) { - DeviceEventInfoRec eventinfo; - SpritePtr pSprite = device->spriteInfo->sprite; - - /* see comment in EnqueueEvents regarding the next three lines */ - if (ev->any.type == ET_Motion) - ev->device_event.root = WindowTable[pSprite->hotPhys.pScreen->myNum]->drawable.id; - - eventinfo.device = device; - eventinfo.event = ev; - CallCallbacks(&DeviceEventCallback, (pointer) & eventinfo); - } - - grab = device->deviceGrab.grab; - - switch(event->type) - { - case ET_KeyPress: - if (!grab && CheckDeviceGrabs(device, event, 0)) { - device->deviceGrab.activatingKey = key; - return; - } - break; - case ET_KeyRelease: - if (grab && device->deviceGrab.fromPassiveGrab && - (key == device->deviceGrab.activatingKey) && - (device->deviceGrab.grab->type == KeyPress || - device->deviceGrab.grab->type == DeviceKeyPress || - device->deviceGrab.grab->type == XI_KeyPress)) - deactivateDeviceGrab = TRUE; - break; - case ET_ButtonPress: - event->detail.button = b->map[key]; - if (!event->detail.button) { /* there's no button 0 */ - event->detail.button = key; - return; - } - if (!grab && CheckDeviceGrabs(device, event, 0)) - { - /* if a passive grab was activated, the event has been sent - * already */ - return; - } - break; - case ET_ButtonRelease: - event->detail.button = b->map[key]; - if (!event->detail.button) { /* there's no button 0 */ - event->detail.button = key; - return; - } - if (grab && !b->buttonsDown && - device->deviceGrab.fromPassiveGrab && - (device->deviceGrab.grab->type == ButtonPress || - device->deviceGrab.grab->type == DeviceButtonPress || - device->deviceGrab.grab->type == XI_ButtonPress)) - deactivateDeviceGrab = TRUE; - default: - break; - } - - - if (grab) - DeliverGrabbedEvent((InternalEvent*)event, device, deactivateDeviceGrab); - else if (device->focus && !IsPointerEvent((InternalEvent*)ev)) - DeliverFocusedEvent(device, (InternalEvent*)event, - GetSpriteWindow(device)); - else - DeliverDeviceEvents(GetSpriteWindow(device), (InternalEvent*)event, - NullGrab, NullWindow, device); - - if (deactivateDeviceGrab == TRUE) - (*device->deviceGrab.DeactivateGrab) (device); - event->detail.key = key; -} - -int -InitProximityClassDeviceStruct(DeviceIntPtr dev) -{ - ProximityClassPtr proxc; - - proxc = (ProximityClassPtr) xalloc(sizeof(ProximityClassRec)); - if (!proxc) - return FALSE; - proxc->sourceid = dev->id; - dev->proximity = proxc; - return TRUE; -} - -/** - * Initialise the device's valuators. The memory must already be allocated, - * this function merely inits the matching axis (specified through axnum) to - * sane values. - * - * It is a condition that (minval < maxval). - * - * @see InitValuatorClassDeviceStruct - */ -void -InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int maxval, - int resolution, int min_res, int max_res) -{ - AxisInfoPtr ax; - - if (!dev || !dev->valuator || minval > maxval) - return; - if (axnum >= dev->valuator->numAxes) - return; - - ax = dev->valuator->axes + axnum; - - ax->min_value = minval; - ax->max_value = maxval; - ax->resolution = resolution; - ax->min_resolution = min_res; - ax->max_resolution = max_res; - ax->label = label; -} - -static void -FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, - ButtonClassPtr b, ValuatorClassPtr v, int first) -{ - ev->type = DeviceStateNotify; - ev->deviceid = dev->id; - ev->time = currentTime.milliseconds; - ev->classes_reported = 0; - ev->num_keys = 0; - ev->num_buttons = 0; - ev->num_valuators = 0; - - if (b) { - ev->classes_reported |= (1 << ButtonClass); - ev->num_buttons = b->numButtons; - memcpy((char*)ev->buttons, (char*)b->down, 4); - } else if (k) { - ev->classes_reported |= (1 << KeyClass); - ev->num_keys = k->xkbInfo->desc->max_key_code - - k->xkbInfo->desc->min_key_code; - memmove((char *)&ev->keys[0], (char *)k->down, 4); - } - if (v) { - int nval = v->numAxes - first; - - ev->classes_reported |= (1 << ValuatorClass); - ev->classes_reported |= (dev->valuator->mode << ModeBitsShift); - ev->num_valuators = nval < 3 ? nval : 3; - switch (ev->num_valuators) { - case 3: - ev->valuator2 = v->axisVal[first + 2]; - case 2: - ev->valuator1 = v->axisVal[first + 1]; - case 1: - ev->valuator0 = v->axisVal[first]; - break; - } - } -} - -static void -FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, - int first) -{ - int nval = v->numAxes - first; - - ev->type = DeviceValuator; - ev->deviceid = dev->id; - ev->num_valuators = nval < 3 ? nval : 3; - ev->first_valuator = first; - switch (ev->num_valuators) { - case 3: - ev->valuator2 = v->axisVal[first + 2]; - case 2: - ev->valuator1 = v->axisVal[first + 1]; - case 1: - ev->valuator0 = v->axisVal[first]; - break; - } - first += ev->num_valuators; -} - -void -DeviceFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, - WindowPtr pWin) -{ - deviceFocus event; - xXIFocusInEvent *xi2event; - DeviceIntPtr mouse; - int btlen, len, i; - - mouse = (IsMaster(dev) || dev->u.master) ? GetMaster(dev, MASTER_POINTER) : dev; - - /* XI 2 event */ - btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; - btlen = bytes_to_int32(btlen); - len = sizeof(xXIFocusInEvent) + btlen * 4; - - xi2event = xcalloc(1, len); - xi2event->type = GenericEvent; - xi2event->extension = IReqCode; - xi2event->evtype = type; - xi2event->length = bytes_to_int32(len - sizeof(xEvent)); - xi2event->buttons_len = btlen; - xi2event->detail = detail; - xi2event->time = currentTime.milliseconds; - xi2event->deviceid = dev->id; - xi2event->sourceid = dev->id; /* a device doesn't change focus by itself */ - xi2event->mode = mode; - xi2event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); - xi2event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); - - for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) - if (BitIsOn(mouse->button->down, i)) - SetBit(&xi2event[1], i); - - if (dev->key) - { - xi2event->mods.base_mods = dev->key->xkbInfo->state.base_mods; - xi2event->mods.latched_mods = dev->key->xkbInfo->state.latched_mods; - xi2event->mods.locked_mods = dev->key->xkbInfo->state.locked_mods; - xi2event->mods.effective_mods = dev->key->xkbInfo->state.mods; - - xi2event->group.base_group = dev->key->xkbInfo->state.base_group; - xi2event->group.latched_group = dev->key->xkbInfo->state.latched_group; - xi2event->group.locked_group = dev->key->xkbInfo->state.locked_group; - xi2event->group.effective_group = dev->key->xkbInfo->state.group; - } - - FixUpEventFromWindow(dev, (xEvent*)xi2event, pWin, None, FALSE); - - DeliverEventsToWindow(dev, pWin, (xEvent*)xi2event, 1, - GetEventFilter(dev, (xEvent*)xi2event), NullGrab); - - xfree(xi2event); - - /* XI 1.x event */ - event.deviceid = dev->id; - event.mode = mode; - event.type = (type == XI_FocusIn) ? DeviceFocusIn : DeviceFocusOut; - event.detail = detail; - event.window = pWin->drawable.id; - event.time = currentTime.milliseconds; - - DeliverEventsToWindow(dev, pWin, (xEvent *) & event, 1, - DeviceFocusChangeMask, NullGrab); - - if ((type == DeviceFocusIn) && - (wOtherInputMasks(pWin)) && - (wOtherInputMasks(pWin)->inputEvents[dev->id] & DeviceStateNotifyMask)) - { - int evcount = 1; - deviceStateNotify *ev, *sev; - deviceKeyStateNotify *kev; - deviceButtonStateNotify *bev; - - KeyClassPtr k; - ButtonClassPtr b; - ValuatorClassPtr v; - int nval = 0, nkeys = 0, nbuttons = 0, first = 0; - - if ((b = dev->button) != NULL) { - nbuttons = b->numButtons; - if (nbuttons > 32) - evcount++; - } - if ((k = dev->key) != NULL) { - nkeys = k->xkbInfo->desc->max_key_code - - k->xkbInfo->desc->min_key_code; - if (nkeys > 32) - evcount++; - if (nbuttons > 0) { - evcount++; - } - } - if ((v = dev->valuator) != NULL) { - nval = v->numAxes; - - if (nval > 3) - evcount++; - if (nval > 6) { - if (!(k && b)) - evcount++; - if (nval > 9) - evcount += ((nval - 7) / 3); - } - } - - sev = ev = (deviceStateNotify *) xalloc(evcount * sizeof(xEvent)); - FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first); - - if (b != NULL) { - FixDeviceStateNotify(dev, ev++, NULL, b, v, first); - first += 3; - nval -= 3; - if (nbuttons > 32) { - (ev - 1)->deviceid |= MORE_EVENTS; - bev = (deviceButtonStateNotify *) ev++; - bev->type = DeviceButtonStateNotify; - bev->deviceid = dev->id; - memcpy((char*)&bev->buttons[4], (char*)&b->down[4], DOWN_LENGTH - 4); - } - if (nval > 0) { - (ev - 1)->deviceid |= MORE_EVENTS; - FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); - first += 3; - nval -= 3; - } - } - - if (k != NULL) { - FixDeviceStateNotify(dev, ev++, k, NULL, v, first); - first += 3; - nval -= 3; - if (nkeys > 32) { - (ev - 1)->deviceid |= MORE_EVENTS; - kev = (deviceKeyStateNotify *) ev++; - kev->type = DeviceKeyStateNotify; - kev->deviceid = dev->id; - memmove((char *)&kev->keys[0], (char *)&k->down[4], 28); - } - if (nval > 0) { - (ev - 1)->deviceid |= MORE_EVENTS; - FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); - first += 3; - nval -= 3; - } - } - - while (nval > 0) { - FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first); - first += 3; - nval -= 3; - if (nval > 0) { - (ev - 1)->deviceid |= MORE_EVENTS; - FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); - first += 3; - nval -= 3; - } - } - - DeliverEventsToWindow(dev, pWin, (xEvent *) sev, evcount, - DeviceStateNotifyMask, NullGrab); - xfree(sev); - } -} - -int -CheckGrabValues(ClientPtr client, GrabParameters* param) -{ - if (param->grabtype != GRABTYPE_CORE && - param->grabtype != GRABTYPE_XI && - param->grabtype != GRABTYPE_XI2) - { - ErrorF("[Xi] grabtype is invalid. This is a bug.\n"); - return BadImplementation; - } - - if ((param->this_device_mode != GrabModeSync) && - (param->this_device_mode != GrabModeAsync)) { - client->errorValue = param->this_device_mode; - return BadValue; - } - if ((param->other_devices_mode != GrabModeSync) && - (param->other_devices_mode != GrabModeAsync)) { - client->errorValue = param->other_devices_mode; - return BadValue; - } - - if (param->grabtype != GRABTYPE_XI2 && (param->modifiers != AnyModifier) && - (param->modifiers & ~AllModifiersMask)) { - client->errorValue = param->modifiers; - return BadValue; - } - - if ((param->ownerEvents != xFalse) && (param->ownerEvents != xTrue)) { - client->errorValue = param->ownerEvents; - return BadValue; - } - return Success; -} - -int -GrabButton(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device, - int button, GrabParameters *param, GrabType grabtype, - GrabMask *mask) -{ - WindowPtr pWin, confineTo; - CursorPtr cursor; - GrabPtr grab; - int rc, type = -1; - Mask access_mode = DixGrabAccess; - - rc = CheckGrabValues(client, param); - if (rc != Success) - return rc; - if (param->confineTo == None) - confineTo = NullWindow; - else { - rc = dixLookupWindow(&confineTo, param->confineTo, client, DixSetAttrAccess); - if (rc != Success) - return rc; - } - if (param->cursor == None) - cursor = NullCursor; - else { - rc = dixLookupResourceByType((pointer *)&cursor, param->cursor, - RT_CURSOR, client, DixUseAccess); - if (rc != Success) - { - client->errorValue = param->cursor; - return (rc == BadValue) ? BadCursor : rc; - } - access_mode |= DixForceAccess; - } - if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc != Success) - return rc; - rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - if (grabtype == GRABTYPE_XI) - type = DeviceButtonPress; - else if (grabtype == GRABTYPE_XI2) - type = XI_ButtonPress; - - grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype, - mask, param, type, button, confineTo, cursor); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - -/** - * Grab the given key. If grabtype is GRABTYPE_XI, the key is a keycode. If - * grabtype is GRABTYPE_XI2, the key is a keysym. - */ -int -GrabKey(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device, - int key, GrabParameters *param, GrabType grabtype, GrabMask *mask) -{ - WindowPtr pWin; - GrabPtr grab; - KeyClassPtr k = dev->key; - Mask access_mode = DixGrabAccess; - int rc, type = -1; - - rc = CheckGrabValues(client, param); - if (rc != Success) - return rc; - if (k == NULL) - return BadMatch; - if (grabtype == GRABTYPE_XI) - { - if ((key > k->xkbInfo->desc->max_key_code || - key < k->xkbInfo->desc->min_key_code) - && (key != AnyKey)) { - client->errorValue = key; - return BadValue; - } - type = DeviceKeyPress; - } else if (grabtype == GRABTYPE_XI2) - type = XI_KeyPress; - - rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc != Success) - return rc; - - grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype, - mask, param, type, key, NULL, NULL); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - -/* Enter/FocusIn grab */ -int -GrabWindow(ClientPtr client, DeviceIntPtr dev, int type, - GrabParameters *param, GrabMask *mask) -{ - WindowPtr pWin; - CursorPtr cursor; - GrabPtr grab; - Mask access_mode = DixGrabAccess; - int rc; - - rc = CheckGrabValues(client, param); - if (rc != Success) - return rc; - - rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - if (param->cursor == None) - cursor = NullCursor; - else { - rc = dixLookupResourceByType((pointer *)&cursor, param->cursor, - RT_CURSOR, client, DixUseAccess); - if (rc != Success) - { - client->errorValue = param->cursor; - return (rc == BadValue) ? BadCursor : rc; - } - access_mode |= DixForceAccess; - } - if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc != Success) - return rc; - - grab = CreateGrab(client->index, dev, dev, pWin, GRABTYPE_XI2, - mask, param, (type == XIGrabtypeEnter) ? XI_Enter : XI_FocusIn, - 0, NULL, cursor); - - if (!grab) - return BadAlloc; - - return AddPassiveGrabToList(client, grab); -} - -int -SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client, - Mask mask, Mask exclusivemasks) -{ - int mskidx = dev->id; - int i, ret; - Mask check; - InputClientsPtr others; - - check = (mask & exclusivemasks); - if (wOtherInputMasks(pWin)) { - if (check & wOtherInputMasks(pWin)->inputEvents[mskidx]) { /* It is illegal for two different - * clients to select on any of the - * events for maskcheck. However, - * it is OK, for some client to - * continue selecting on one of those - * events. */ - for (others = wOtherInputMasks(pWin)->inputClients; others; - others = others->next) { - if (!SameClient(others, client) && (check & - others->mask[mskidx])) - return BadAccess; - } - } - for (others = wOtherInputMasks(pWin)->inputClients; others; - others = others->next) { - if (SameClient(others, client)) { - check = others->mask[mskidx]; - others->mask[mskidx] = mask; - if (mask == 0) { - for (i = 0; i < EMASKSIZE; i++) - if (i != mskidx && others->mask[i] != 0) - break; - if (i == EMASKSIZE) { - RecalculateDeviceDeliverableEvents(pWin); - if (ShouldFreeInputMasks(pWin, FALSE)) - FreeResource(others->resource, RT_NONE); - return Success; - } - } - goto maskSet; - } - } - } - check = 0; - if ((ret = AddExtensionClient(pWin, client, mask, mskidx)) != Success) - return ret; - maskSet: - if (dev->valuator) - if ((dev->valuator->motionHintWindow == pWin) && - (mask & DevicePointerMotionHintMask) && - !(check & DevicePointerMotionHintMask) && !dev->deviceGrab.grab) - dev->valuator->motionHintWindow = NullWindow; - RecalculateDeviceDeliverableEvents(pWin); - return Success; -} - -int -AddExtensionClient(WindowPtr pWin, ClientPtr client, Mask mask, int mskidx) -{ - InputClientsPtr others; - - if (!pWin->optional && !MakeWindowOptional(pWin)) - return BadAlloc; - others = xcalloc(1, sizeof(InputClients)); - if (!others) - return BadAlloc; - if (!pWin->optional->inputMasks && !MakeInputMasks(pWin)) - return BadAlloc; - others->mask[mskidx] = mask; - others->resource = FakeClientID(client->index); - others->next = pWin->optional->inputMasks->inputClients; - pWin->optional->inputMasks->inputClients = others; - if (!AddResource(others->resource, RT_INPUTCLIENT, (pointer) pWin)) - return BadAlloc; - return Success; -} - -static Bool -MakeInputMasks(WindowPtr pWin) -{ - struct _OtherInputMasks *imasks; - - imasks = xcalloc(1, sizeof(struct _OtherInputMasks)); - if (!imasks) - return FALSE; - pWin->optional->inputMasks = imasks; - return TRUE; -} - -void -RecalculateDeviceDeliverableEvents(WindowPtr pWin) -{ - InputClientsPtr others; - struct _OtherInputMasks *inputMasks; /* default: NULL */ - WindowPtr pChild, tmp; - int i, j; - - pChild = pWin; - while (1) { - if ((inputMasks = wOtherInputMasks(pChild)) != 0) { - for (i = 0; i < EMASKSIZE; i++) - memset(inputMasks->xi2mask[i], 0, sizeof(inputMasks->xi2mask[i])); - for (others = inputMasks->inputClients; others; - others = others->next) { - for (i = 0; i < EMASKSIZE; i++) - inputMasks->inputEvents[i] |= others->mask[i]; - for (i = 0; i < EMASKSIZE; i++) - for (j = 0; j < XI2MASKSIZE; j++) - inputMasks->xi2mask[i][j] |= others->xi2mask[i][j]; - } - for (i = 0; i < EMASKSIZE; i++) - inputMasks->deliverableEvents[i] = inputMasks->inputEvents[i]; - for (tmp = pChild->parent; tmp; tmp = tmp->parent) - if (wOtherInputMasks(tmp)) - for (i = 0; i < EMASKSIZE; i++) - inputMasks->deliverableEvents[i] |= - (wOtherInputMasks(tmp)->deliverableEvents[i] - & ~inputMasks-> - dontPropagateMask[i] & PropagateMask[i]); - } - if (pChild->firstChild) { - pChild = pChild->firstChild; - continue; - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } -} - -int -InputClientGone(WindowPtr pWin, XID id) -{ - InputClientsPtr other, prev; - - if (!wOtherInputMasks(pWin)) - return (Success); - prev = 0; - for (other = wOtherInputMasks(pWin)->inputClients; other; - other = other->next) { - if (other->resource == id) { - if (prev) { - prev->next = other->next; - xfree(other); - } else if (!(other->next)) { - if (ShouldFreeInputMasks(pWin, TRUE)) { - wOtherInputMasks(pWin)->inputClients = other->next; - xfree(wOtherInputMasks(pWin)); - pWin->optional->inputMasks = (OtherInputMasks *) NULL; - CheckWindowOptionalNeed(pWin); - xfree(other); - } else { - other->resource = FakeClientID(0); - if (!AddResource(other->resource, RT_INPUTCLIENT, - (pointer) pWin)) - return BadAlloc; - } - } else { - wOtherInputMasks(pWin)->inputClients = other->next; - xfree(other); - } - RecalculateDeviceDeliverableEvents(pWin); - return (Success); - } - prev = other; - } - FatalError("client not on device event list"); -} - -int -SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate, - xEvent * ev, Mask mask, int count) -{ - WindowPtr pWin; - WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ - WindowPtr spriteWin = GetSpriteWindow(d); - - if (dest == PointerWindow) - pWin = spriteWin; - else if (dest == InputFocus) { - WindowPtr inputFocus; - - if (!d->focus) - inputFocus = spriteWin; - else - inputFocus = d->focus->win; - - if (inputFocus == FollowKeyboardWin) - 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 = GetCurrentRootWindow(d); - - if (IsParent(inputFocus, spriteWin)) { - effectiveFocus = inputFocus; - pWin = spriteWin; - } else - effectiveFocus = pWin = inputFocus; - } else - dixLookupWindow(&pWin, dest, client, DixSendAccess); - if (!pWin) - return BadWindow; - if ((propagate != xFalse) && (propagate != xTrue)) { - client->errorValue = propagate; - return BadValue; - } - ev->u.u.type |= 0x80; - if (propagate) { - for (; pWin; pWin = pWin->parent) { - if (DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab)) - return Success; - if (pWin == effectiveFocus) - return Success; - if (wOtherInputMasks(pWin)) - mask &= ~wOtherInputMasks(pWin)->dontPropagateMask[d->id]; - if (!mask) - break; - } - } else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, ev, count)) - DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab); - return Success; -} - -int -SetButtonMapping(ClientPtr client, DeviceIntPtr dev, int nElts, BYTE * map) -{ - int i; - ButtonClassPtr b = dev->button; - - if (b == NULL) - return BadMatch; - - if (nElts != b->numButtons) { - client->errorValue = nElts; - return BadValue; - } - if (BadDeviceMap(&map[0], nElts, 1, 255, &client->errorValue)) - return BadValue; - for (i = 0; i < nElts; i++) - if ((b->map[i + 1] != map[i]) && BitIsOn(b->down, i + 1)) - return MappingBusy; - for (i = 0; i < nElts; i++) - b->map[i + 1] = map[i]; - return Success; -} - -int -ChangeKeyMapping(ClientPtr client, - DeviceIntPtr dev, - unsigned len, - int type, - KeyCode firstKeyCode, - CARD8 keyCodes, CARD8 keySymsPerKeyCode, KeySym * map) -{ - KeySymsRec keysyms; - KeyClassPtr k = dev->key; - - if (k == NULL) - return (BadMatch); - - if (len != (keyCodes * keySymsPerKeyCode)) - return BadLength; - - if ((firstKeyCode < k->xkbInfo->desc->min_key_code) || - (firstKeyCode + keyCodes - 1 > k->xkbInfo->desc->max_key_code)) { - client->errorValue = firstKeyCode; - return BadValue; - } - if (keySymsPerKeyCode == 0) { - client->errorValue = 0; - return BadValue; - } - keysyms.minKeyCode = firstKeyCode; - keysyms.maxKeyCode = firstKeyCode + keyCodes - 1; - keysyms.mapWidth = keySymsPerKeyCode; - keysyms.map = map; - - XkbApplyMappingChange(dev, &keysyms, firstKeyCode, keyCodes, NULL, - serverClient); - - return client->noClientException; -} - -static void -DeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev) -{ - WindowPtr parent; - - /* Deactivate any grabs performed on this window, before making - * any input focus changes. - * Deactivating a device grab should cause focus events. */ - - if (dev->deviceGrab.grab && (dev->deviceGrab.grab->window == pWin)) - (*dev->deviceGrab.DeactivateGrab) (dev); - - /* If the focus window is a root window (ie. has no parent) - * then don't delete the focus from it. */ - - if (dev->focus && (pWin == dev->focus->win) && (pWin->parent != NullWindow)) { - int focusEventMode = NotifyNormal; - - /* If a grab is in progress, then alter the mode of focus events. */ - - if (dev->deviceGrab.grab) - focusEventMode = NotifyWhileGrabbed; - - switch (dev->focus->revert) { - case RevertToNone: - if (!ActivateFocusInGrab(dev, pWin, NoneWin)) - DoFocusEvents(dev, pWin, NoneWin, focusEventMode); - dev->focus->win = NoneWin; - dev->focus->traceGood = 0; - break; - case RevertToParent: - parent = pWin; - do { - parent = parent->parent; - dev->focus->traceGood--; - } - while (!parent->realized); - if (!ActivateFocusInGrab(dev, pWin, parent)) - DoFocusEvents(dev, pWin, parent, focusEventMode); - dev->focus->win = parent; - dev->focus->revert = RevertToNone; - break; - case RevertToPointerRoot: - if (!ActivateFocusInGrab(dev, pWin, PointerRootWin)) - DoFocusEvents(dev, pWin, PointerRootWin, focusEventMode); - dev->focus->win = PointerRootWin; - dev->focus->traceGood = 0; - break; - case RevertToFollowKeyboard: - { - DeviceIntPtr kbd = GetMaster(dev, MASTER_KEYBOARD); - if (!kbd || (kbd == dev && kbd != inputInfo.keyboard)) - kbd = inputInfo.keyboard; - if (kbd->focus->win) { - if (!ActivateFocusInGrab(dev, pWin, kbd->focus->win)) - DoFocusEvents(dev, pWin, kbd->focus->win, focusEventMode); - dev->focus->win = FollowKeyboardWin; - dev->focus->traceGood = 0; - } else { - if (!ActivateFocusInGrab(dev, pWin, NoneWin)) - DoFocusEvents(dev, pWin, NoneWin, focusEventMode); - dev->focus->win = NoneWin; - dev->focus->traceGood = 0; - } - } - break; - } - } - - if (dev->valuator) - if (dev->valuator->motionHintWindow == pWin) - dev->valuator->motionHintWindow = NullWindow; -} - -void -DeleteWindowFromAnyExtEvents(WindowPtr pWin, Bool freeResources) -{ - int i; - DeviceIntPtr dev; - InputClientsPtr ic; - struct _OtherInputMasks *inputMasks; - - for (dev = inputInfo.devices; dev; dev = dev->next) { - DeleteDeviceFromAnyExtEvents(pWin, dev); - } - - for (dev = inputInfo.off_devices; dev; dev = dev->next) - DeleteDeviceFromAnyExtEvents(pWin, dev); - - if (freeResources) - while ((inputMasks = wOtherInputMasks(pWin)) != 0) { - ic = inputMasks->inputClients; - for (i = 0; i < EMASKSIZE; i++) - inputMasks->dontPropagateMask[i] = 0; - FreeResource(ic->resource, RT_NONE); - } -} - -int -MaybeSendDeviceMotionNotifyHint(deviceKeyButtonPointer * pEvents, Mask mask) -{ - DeviceIntPtr dev; - - dixLookupDevice(&dev, pEvents->deviceid & DEVICE_BITS, serverClient, - DixReadAccess); - if (!dev) - return 0; - - if (pEvents->type == DeviceMotionNotify) { - if (mask & DevicePointerMotionHintMask) { - if (WID(dev->valuator->motionHintWindow) == pEvents->event) { - return 1; /* don't send, but pretend we did */ - } - pEvents->detail = NotifyHint; - } else { - pEvents->detail = NotifyNormal; - } - } - return (0); -} - -void -CheckDeviceGrabAndHintWindow(WindowPtr pWin, int type, - deviceKeyButtonPointer * xE, GrabPtr grab, - ClientPtr client, Mask deliveryMask) -{ - DeviceIntPtr dev; - - dixLookupDevice(&dev, xE->deviceid & DEVICE_BITS, serverClient, - DixGrabAccess); - if (!dev) - return; - - if (type == DeviceMotionNotify) - dev->valuator->motionHintWindow = pWin; - else if ((type == DeviceButtonPress) && (!grab) && - (deliveryMask & DeviceButtonGrabMask)) { - GrabRec tempGrab; - - tempGrab.device = dev; - tempGrab.resource = client->clientAsMask; - tempGrab.window = pWin; - tempGrab.ownerEvents = - (deliveryMask & DeviceOwnerGrabButtonMask) ? TRUE : FALSE; - tempGrab.eventMask = deliveryMask; - tempGrab.keyboardMode = GrabModeAsync; - tempGrab.pointerMode = GrabModeAsync; - tempGrab.confineTo = NullWindow; - tempGrab.cursor = NullCursor; - tempGrab.next = NULL; - (*dev->deviceGrab.ActivateGrab) (dev, &tempGrab, currentTime, TRUE); - } -} - -static Mask -DeviceEventMaskForClient(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client) -{ - InputClientsPtr other; - - if (!wOtherInputMasks(pWin)) - return 0; - for (other = wOtherInputMasks(pWin)->inputClients; other; - other = other->next) { - if (SameClient(other, client)) - return other->mask[dev->id]; - } - return 0; -} - -void -MaybeStopDeviceHint(DeviceIntPtr dev, ClientPtr client) -{ - WindowPtr pWin; - GrabPtr grab = dev->deviceGrab.grab; - - pWin = dev->valuator->motionHintWindow; - - if ((grab && SameClient(grab, client) && - ((grab->eventMask & DevicePointerMotionHintMask) || - (grab->ownerEvents && - (DeviceEventMaskForClient(dev, pWin, client) & - DevicePointerMotionHintMask)))) || - (!grab && - (DeviceEventMaskForClient(dev, pWin, client) & - DevicePointerMotionHintMask))) - dev->valuator->motionHintWindow = NullWindow; -} - -int -DeviceEventSuppressForWindow(WindowPtr pWin, ClientPtr client, Mask mask, - int maskndx) -{ - struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - - if (mask & ~PropagateMask[maskndx]) { - client->errorValue = mask; - return BadValue; - } - - if (mask == 0) { - if (inputMasks) - inputMasks->dontPropagateMask[maskndx] = mask; - } else { - if (!inputMasks) - AddExtensionClient(pWin, client, 0, 0); - inputMasks = wOtherInputMasks(pWin); - inputMasks->dontPropagateMask[maskndx] = mask; - } - RecalculateDeviceDeliverableEvents(pWin); - if (ShouldFreeInputMasks(pWin, FALSE)) - FreeResource(inputMasks->inputClients->resource, RT_NONE); - return Success; -} - -Bool -ShouldFreeInputMasks(WindowPtr pWin, Bool ignoreSelectedEvents) -{ - int i; - Mask allInputEventMasks = 0; - struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - - for (i = 0; i < EMASKSIZE; i++) - allInputEventMasks |= inputMasks->dontPropagateMask[i]; - if (!ignoreSelectedEvents) - for (i = 0; i < EMASKSIZE; i++) - allInputEventMasks |= inputMasks->inputEvents[i]; - if (allInputEventMasks == 0) - return TRUE; - else - return FALSE; -} - -/*********************************************************************** - * - * Walk through the window tree, finding all clients that want to know - * about the Event. - * - */ - -static void -FindInterestedChildren(DeviceIntPtr dev, WindowPtr p1, Mask mask, - xEvent * ev, int count) -{ - WindowPtr p2; - - while (p1) { - p2 = p1->firstChild; - DeliverEventsToWindow(dev, p1, ev, count, mask, NullGrab); - FindInterestedChildren(dev, p2, mask, ev, count); - p1 = p1->nextSib; - } -} - -/*********************************************************************** - * - * Send an event to interested clients in all windows on all screens. - * - */ - -void -SendEventToAllWindows(DeviceIntPtr dev, Mask mask, xEvent * ev, int count) -{ - int i; - WindowPtr pWin, p1; - - for (i = 0; i < screenInfo.numScreens; i++) { - pWin = WindowTable[i]; - if (!pWin) - continue; - DeliverEventsToWindow(dev, pWin, ev, count, mask, NullGrab); - p1 = pWin->firstChild; - FindInterestedChildren(dev, p1, mask, ev, count); - } -} - -/** - * Set the XI2 mask for the given client on the given window. - * @param dev The device to set the mask for. - * @param win The window to set the mask on. - * @param client The client setting the mask. - * @param len Number of bytes in mask. - * @param mask Event mask in the form of (1 << eventtype) - */ -int -XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client, - unsigned int len, unsigned char* mask) -{ - OtherInputMasks *masks; - InputClientsPtr others = NULL; - - masks = wOtherInputMasks(win); - if (masks) - { - for (others = wOtherInputMasks(win)->inputClients; others; - others = others->next) { - if (SameClient(others, client)) { - memset(others->xi2mask[dev->id], 0, - sizeof(others->xi2mask[dev->id])); - break; - } - } - } - - len = min(len, sizeof(others->xi2mask[dev->id])); - - if (len && !others) - { - if (AddExtensionClient(win, client, 0, 0) != Success) - return BadAlloc; - others= wOtherInputMasks(win)->inputClients; - } - - if (others) - memset(others->xi2mask[dev->id], 0, sizeof(others->xi2mask[dev->id])); - - if (len) - memcpy(others->xi2mask[dev->id], mask, len); - - RecalculateDeviceDeliverableEvents(win); - - return Success; -} +/************************************************************ + +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. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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. + +********************************************************/ + +/******************************************************************** + * + * Routines to register and initialize extension input devices. + * This also contains ProcessOtherEvent, the routine called from DDX + * to route extension events. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" +#include +#include +#include +#include +#include +#include +#include "windowstr.h" +#include "miscstruct.h" +#include "region.h" +#include "exevents.h" +#include "extnsionst.h" +#include "exglobals.h" +#include "dixevents.h" /* DeliverFocusedEvent */ +#include "dixgrabs.h" /* CreateGrab() */ +#include "scrnintstr.h" +#include "listdev.h" /* for CopySwapXXXClass */ +#include "xace.h" +#include "xiquerydevice.h" /* For List*Info */ +#include "eventconvert.h" +#include "eventstr.h" + +#include +#include "xkbsrv.h" + +#define WID(w) ((w) ? ((w)->drawable.id) : 0) +#define AllModifiersMask ( \ + ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ + Mod3Mask | Mod4Mask | Mod5Mask ) +#define AllButtonsMask ( \ + Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) + +Bool ShouldFreeInputMasks(WindowPtr /* pWin */ , + Bool /* ignoreSelectedEvents */ + ); +static Bool MakeInputMasks(WindowPtr /* pWin */ + ); + +/* + * Only let the given client know of core events which will affect its + * interpretation of input events, if the client's ClientPointer (or the + * paired keyboard) is the current device. + */ +int +XIShouldNotify(ClientPtr client, DeviceIntPtr dev) +{ + DeviceIntPtr current_ptr = PickPointer(client); + DeviceIntPtr current_kbd = GetPairedDevice(current_ptr); + + if (dev == current_kbd || dev == current_ptr) + return 1; + + return 0; +} + +void +RegisterOtherDevice(DeviceIntPtr device) +{ + device->public.processInputProc = ProcessOtherEvent; + device->public.realInputProc = ProcessOtherEvent; +} + +Bool +IsPointerEvent(InternalEvent* event) +{ + switch(event->any.type) + { + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_Motion: + /* XXX: enter/leave ?? */ + return TRUE; + default: + break; + } + return FALSE; +} + +/** + * @return the device matching the deviceid of the device set in the event, or + * NULL if the event is not an XInput event. + */ +DeviceIntPtr +XIGetDevice(xEvent* xE) +{ + DeviceIntPtr pDev = NULL; + + if (xE->u.u.type == DeviceButtonPress || + xE->u.u.type == DeviceButtonRelease || + xE->u.u.type == DeviceMotionNotify || + xE->u.u.type == ProximityIn || + xE->u.u.type == ProximityOut || + xE->u.u.type == DevicePropertyNotify) + { + int rc; + int id; + + id = ((deviceKeyButtonPointer*)xE)->deviceid & ~MORE_EVENTS; + + rc = dixLookupDevice(&pDev, id, serverClient, DixUnknownAccess); + if (rc != Success) + ErrorF("[dix] XIGetDevice failed on XACE restrictions (%d)\n", rc); + } + return pDev; +} + + +/** + * Copy the device->key into master->key and send a mapping notify to the + * clients if appropriate. + * master->key needs to be allocated by the caller. + * + * Device is the slave device. If it is attached to a master device, we may + * need to send a mapping notify to the client because it causes the MD + * to change state. + * + * Mapping notify needs to be sent in the following cases: + * - different slave device on same master + * - different master + * + * XXX: They way how the code is we also send a map notify if the slave device + * stays the same, but the master changes. This isn't really necessary though. + * + * XXX: this gives you funny behaviour with the ClientPointer. When a + * MappingNotify is sent to the client, the client usually responds with a + * GetKeyboardMapping. This will retrieve the ClientPointer's keyboard + * mapping, regardless of which keyboard sent the last mapping notify request. + * So depending on the CP setting, your keyboard may change layout in each + * app... + * + * This code is basically the old SwitchCoreKeyboard. + */ + +void +CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master) +{ + KeyClassPtr mk = master->key; + KeyClassPtr dk = device->key; + int i; + + if (device == master) + return; + + mk->sourceid = device->id; + + for (i = 0; i < 8; i++) + mk->modifierKeyCount[i] = dk->modifierKeyCount[i]; + + if (!XkbCopyDeviceKeymap(master, device)) + FatalError("Couldn't pivot keymap from device to core!\n"); +} + +/** + * Copies the feedback classes from device "from" into device "to". Classes + * are duplicated (not just flipping the pointers). All feedback classes are + * linked lists, the full list is duplicated. + */ +static void +DeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to) +{ + ClassesPtr classes; + + + if (from->intfeed) + { + IntegerFeedbackPtr *i, it; + + if (!to->intfeed) + { + classes = to->unused_classes; + to->intfeed = classes->intfeed; + } + + i = &to->intfeed; + for (it = from->intfeed; it; it = it->next) + { + if (!(*i)) + { + *i = calloc(1, sizeof(IntegerFeedbackClassRec)); + if (!(*i)) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*i)->CtrlProc = it->CtrlProc; + (*i)->ctrl = it->ctrl; + + i = &(*i)->next; + } + } else if (to->intfeed && !from->intfeed) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->intfeed = to->intfeed; + to->intfeed = NULL; + } + + if (from->stringfeed) + { + StringFeedbackPtr *s, it; + + if (!to->stringfeed) + { + classes = to->unused_classes; + to->stringfeed = classes->stringfeed; + } + + s = &to->stringfeed; + for (it = from->stringfeed; it; it = it->next) + { + if (!(*s)) + { + *s = calloc(1, sizeof(StringFeedbackClassRec)); + if (!(*s)) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*s)->CtrlProc = it->CtrlProc; + (*s)->ctrl = it->ctrl; + + s = &(*s)->next; + } + } else if (to->stringfeed && !from->stringfeed) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->stringfeed = to->stringfeed; + to->stringfeed = NULL; + } + + if (from->bell) + { + BellFeedbackPtr *b, it; + + if (!to->bell) + { + classes = to->unused_classes; + to->bell = classes->bell; + } + + b = &to->bell; + for (it = from->bell; it; it = it->next) + { + if (!(*b)) + { + *b = calloc(1, sizeof(BellFeedbackClassRec)); + if (!(*b)) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*b)->BellProc = it->BellProc; + (*b)->CtrlProc = it->CtrlProc; + (*b)->ctrl = it->ctrl; + + b = &(*b)->next; + } + } else if (to->bell && !from->bell) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->bell = to->bell; + to->bell = NULL; + } + + if (from->leds) + { + LedFeedbackPtr *l, it; + + if (!to->leds) + { + classes = to->unused_classes; + to->leds = classes->leds; + } + + l = &to->leds; + for (it = from->leds; it; it = it->next) + { + if (!(*l)) + { + *l = calloc(1, sizeof(LedFeedbackClassRec)); + if (!(*l)) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*l)->CtrlProc = it->CtrlProc; + (*l)->ctrl = it->ctrl; + if ((*l)->xkb_sli) + XkbFreeSrvLedInfo((*l)->xkb_sli); + (*l)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, NULL, *l); + + l = &(*l)->next; + } + } else if (to->leds && !from->leds) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->leds = to->leds; + to->leds = NULL; + } +} + +static void +DeepCopyKeyboardClasses(DeviceIntPtr from, DeviceIntPtr to) +{ + ClassesPtr classes; + + /* XkbInitDevice (->XkbInitIndicatorMap->XkbFindSrvLedInfo) relies on the + * kbdfeed to be set up properly, so let's do the feedback classes first. + */ + if (from->kbdfeed) + { + KbdFeedbackPtr *k, it; + + if (!to->kbdfeed) + { + classes = to->unused_classes; + + to->kbdfeed = classes->kbdfeed; + if (!to->kbdfeed) + InitKeyboardDeviceStruct(to, NULL, NULL, NULL); + } + + k = &to->kbdfeed; + for(it = from->kbdfeed; it; it = it->next) + { + if (!(*k)) + { + *k = calloc(1, sizeof(KbdFeedbackClassRec)); + if (!*k) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*k)->BellProc = it->BellProc; + (*k)->CtrlProc = it->CtrlProc; + (*k)->ctrl = it->ctrl; + if ((*k)->xkb_sli) + XkbFreeSrvLedInfo((*k)->xkb_sli); + (*k)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, *k, NULL); + + k = &(*k)->next; + } + } else if (to->kbdfeed && !from->kbdfeed) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->kbdfeed = to->kbdfeed; + to->kbdfeed = NULL; + } + + if (from->key) + { + if (!to->key) + { + classes = to->unused_classes; + to->key = classes->key; + if (!to->key) + InitKeyboardDeviceStruct(to, NULL, NULL, NULL); + else + classes->key = NULL; + } + + CopyKeyClass(from, to); + } else if (to->key && !from->key) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->key = to->key; + to->key = NULL; + } + + /* If a SrvLedInfoPtr's flags are XkbSLI_IsDefault, the names and maps + * pointer point into the xkbInfo->desc struct. XkbCopySrvLedInfo + * didn't update the pointers so we need to do it manually here. + */ + if (to->kbdfeed) + { + KbdFeedbackPtr k; + + for (k = to->kbdfeed; k; k = k->next) + { + if (!k->xkb_sli) + continue; + if (k->xkb_sli->flags & XkbSLI_IsDefault) + { + k->xkb_sli->names = to->key->xkbInfo->desc->names->indicators; + k->xkb_sli->maps = to->key->xkbInfo->desc->indicators->maps; + } + } + } + + /* We can't just copy over the focus class. When an app sets the focus, + * it'll do so on the master device. Copying the SDs focus means losing + * the focus. + * So we only copy the focus class if the device didn't have one, + * otherwise we leave it as it is. + */ + if (from->focus) + { + if (!to->focus) + { + WindowPtr *oldTrace; + + classes = to->unused_classes; + to->focus = classes->focus; + if (!to->focus) + { + to->focus = calloc(1, sizeof(FocusClassRec)); + if (!to->focus) + FatalError("[Xi] no memory for class shift.\n"); + } else + classes->focus = NULL; + + oldTrace = to->focus->trace; + memcpy(to->focus, from->focus, sizeof(FocusClassRec)); + to->focus->trace = realloc(oldTrace, + to->focus->traceSize * sizeof(WindowPtr)); + if (!to->focus->trace && to->focus->traceSize) + FatalError("[Xi] no memory for trace.\n"); + memcpy(to->focus->trace, from->focus->trace, + from->focus->traceSize * sizeof(WindowPtr)); + to->focus->sourceid = from->id; + } + } else if (to->focus) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->focus = to->focus; + to->focus = NULL; + } + +} + +static void +DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) +{ + ClassesPtr classes; + + /* Feedback classes must be copied first */ + if (from->ptrfeed) + { + PtrFeedbackPtr *p, it; + if (!to->ptrfeed) + { + classes = to->unused_classes; + to->ptrfeed = classes->ptrfeed; + } + + p = &to->ptrfeed; + for (it = from->ptrfeed; it; it = it->next) + { + if (!(*p)) + { + *p = calloc(1, sizeof(PtrFeedbackClassRec)); + if (!*p) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*p)->CtrlProc = it->CtrlProc; + (*p)->ctrl = it->ctrl; + + p = &(*p)->next; + } + } else if (to->ptrfeed && !from->ptrfeed) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->ptrfeed = to->ptrfeed; + to->ptrfeed = NULL; + } + + if (from->valuator) + { + ValuatorClassPtr v; + if (!to->valuator) + { + classes = to->unused_classes; + to->valuator = classes->valuator; + if (to->valuator) + classes->valuator = NULL; + } + + to->valuator = realloc(to->valuator, sizeof(ValuatorClassRec) + + from->valuator->numAxes * sizeof(AxisInfo) + + from->valuator->numAxes * sizeof(double)); + v = to->valuator; + if (!v) + FatalError("[Xi] no memory for class shift.\n"); + + v->numAxes = from->valuator->numAxes; + v->axes = (AxisInfoPtr)&v[1]; + memcpy(v->axes, from->valuator->axes, v->numAxes * sizeof(AxisInfo)); + + v->axisVal = (double*)(v->axes + from->valuator->numAxes); + v->sourceid = from->id; + v->mode = from->valuator->mode; + } else if (to->valuator && !from->valuator) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->valuator = to->valuator; + to->valuator = NULL; + } + + if (from->button) + { + if (!to->button) + { + classes = to->unused_classes; + to->button = classes->button; + if (!to->button) + { + to->button = calloc(1, sizeof(ButtonClassRec)); + if (!to->button) + FatalError("[Xi] no memory for class shift.\n"); + } else + classes->button = NULL; + } + + if (from->button->xkb_acts) + { + if (!to->button->xkb_acts) + { + to->button->xkb_acts = calloc(1, sizeof(XkbAction)); + if (!to->button->xkb_acts) + FatalError("[Xi] not enough memory for xkb_acts.\n"); + } + memcpy(to->button->xkb_acts, from->button->xkb_acts, + sizeof(XkbAction)); + } else + free(to->button->xkb_acts); + + memcpy(to->button->labels, from->button->labels, + from->button->numButtons * sizeof(Atom)); + to->button->sourceid = from->id; + } else if (to->button && !from->button) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->button = to->button; + to->button = NULL; + } + + if (from->proximity) + { + if (!to->proximity) + { + classes = to->unused_classes; + to->proximity = classes->proximity; + if (!to->proximity) + { + to->proximity = calloc(1, sizeof(ProximityClassRec)); + if (!to->proximity) + FatalError("[Xi] no memory for class shift.\n"); + } else + classes->proximity = NULL; + } + memcpy(to->proximity, from->proximity, sizeof(ProximityClassRec)); + to->proximity->sourceid = from->id; + } else if (to->proximity) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->proximity = to->proximity; + to->proximity = NULL; + } + + if (from->absolute) + { + if (!to->absolute) + { + classes = to->unused_classes; + to->absolute = classes->absolute; + if (!to->absolute) + { + to->absolute = calloc(1, sizeof(AbsoluteClassRec)); + if (!to->absolute) + FatalError("[Xi] no memory for class shift.\n"); + } else + classes->absolute = NULL; + } + memcpy(to->absolute, from->absolute, sizeof(AbsoluteClassRec)); + to->absolute->sourceid = from->id; + } else if (to->absolute) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->absolute = to->absolute; + to->absolute = NULL; + } +} + +/** + * Copies the CONTENT of the classes of device from into the classes in device + * to. From and to are identical after finishing. + * + * If to does not have classes from currenly has, the classes are stored in + * to's devPrivates system. Later, we recover it again from there if needed. + * Saves a few memory allocations. + */ +void +DeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to, DeviceChangedEvent *dce) +{ + /* generic feedback classes, not tied to pointer and/or keyboard */ + DeepCopyFeedbackClasses(from, to); + + if ((dce->flags & DEVCHANGE_KEYBOARD_EVENT)) + DeepCopyKeyboardClasses(from, to); + if ((dce->flags & DEVCHANGE_POINTER_EVENT)) + DeepCopyPointerClasses(from, to); +} + + +/** + * Send an XI2 DeviceChangedEvent to all interested clients. + */ +void +XISendDeviceChangedEvent(DeviceIntPtr device, DeviceIntPtr master, DeviceChangedEvent *dce) +{ + xXIDeviceChangedEvent *dcce; + int rc; + + rc = EventToXI2((InternalEvent*)dce, (xEvent**)&dcce); + if (rc != Success) + { + ErrorF("[Xi] event conversion from DCE failed with code %d\n", rc); + return; + } + + /* we don't actually swap if there's a NullClient, swapping is done + * later when event is delivered. */ + SendEventToAllWindows(master, XI_DeviceChangedMask, (xEvent*)dcce, 1); + free(dcce); +} + +static void +ChangeMasterDeviceClasses(DeviceIntPtr device, DeviceChangedEvent *dce) +{ + DeviceIntPtr slave; + int rc; + + /* For now, we don't have devices that change physically. */ + if (!IsMaster(device)) + return; + + rc = dixLookupDevice(&slave, dce->sourceid, serverClient, DixReadAccess); + + if (rc != Success) + return; /* Device has disappeared */ + + if (!slave->u.master) + return; /* set floating since the event */ + + if (slave->u.master->id != dce->masterid) + return; /* not our slave anymore, don't care */ + + /* FIXME: we probably need to send a DCE for the new slave now */ + + device->public.devicePrivate = slave->public.devicePrivate; + + /* FIXME: the classes may have changed since we generated the event. */ + DeepCopyDeviceClasses(slave, device, dce); + XISendDeviceChangedEvent(slave, device, dce); +} + +/** + * Update the device state according to the data in the event. + * + * return values are + * DEFAULT ... process as normal + * DONT_PROCESS ... return immediately from caller + */ +#define DEFAULT 0 +#define DONT_PROCESS 1 +int +UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event) +{ + int i; + int key = 0, + bit = 0, + last_valuator; + + KeyClassPtr k = NULL; + ButtonClassPtr b = NULL; + ValuatorClassPtr v = NULL; + BYTE *kptr = NULL; + + /* This event is always the first we get, before the actual events with + * the data. However, the way how the DDX is set up, "device" will + * actually be the slave device that caused the event. + */ + switch(event->type) + { + case ET_DeviceChanged: + ChangeMasterDeviceClasses(device, (DeviceChangedEvent*)event); + return DONT_PROCESS; /* event has been sent already */ + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + break; + default: + /* other events don't update the device */ + return DEFAULT; + } + + k = device->key; + v = device->valuator; + b = device->button; + + key = event->detail.key; + bit = 1 << (key & 7); + + /* Update device axis */ + /* Check valuators first */ + last_valuator = -1; + for (i = 0; i < MAX_VALUATORS; i++) + { + if (BitIsOn(&event->valuators.mask, i)) + { + if (!v) + { + ErrorF("[Xi] Valuators reported for non-valuator device '%s'. " + "Ignoring event.\n", device->name); + return DONT_PROCESS; + } else if (v->numAxes < i) + { + ErrorF("[Xi] Too many valuators reported for device '%s'. " + "Ignoring event.\n", device->name); + return DONT_PROCESS; + } + last_valuator = i; + } + } + + for (i = 0; i <= last_valuator && i < v->numAxes; i++) + { + if (BitIsOn(&event->valuators.mask, i)) + { + /* XXX: Relative/Absolute mode */ + v->axisVal[i] = event->valuators.data[i]; + v->axisVal[i] += (event->valuators.data_frac[i] * 1.0f / (1 << 16) / (1 << 16)); + } + } + + if (event->type == ET_KeyPress) { + if (!k) + return DONT_PROCESS; + + kptr = &k->down[key >> 3]; + /* don't allow ddx to generate multiple downs, but repeats are okay */ + if ((*kptr & bit) && !event->key_repeat) + return DONT_PROCESS; + if (device->valuator) + device->valuator->motionHintWindow = NullWindow; + *kptr |= bit; + } else if (event->type == ET_KeyRelease) { + if (!k) + return DONT_PROCESS; + + kptr = &k->down[key >> 3]; + if (!(*kptr & bit)) /* guard against duplicates */ + return DONT_PROCESS; + if (device->valuator) + device->valuator->motionHintWindow = NullWindow; + *kptr &= ~bit; + } else if (event->type == ET_ButtonPress) { + Mask mask; + if (!b) + return DONT_PROCESS; + + kptr = &b->down[key >> 3]; + if ((*kptr & bit) != 0) + return DONT_PROCESS; + *kptr |= bit; + if (device->valuator) + device->valuator->motionHintWindow = NullWindow; + if (!b->map[key]) + return DONT_PROCESS; + b->buttonsDown++; + b->motionMask = DeviceButtonMotionMask; + if (b->map[key] <= 5) + b->state |= (Button1Mask >> 1) << b->map[key]; + + /* Add state and motionMask to the filter for this event */ + mask = DevicePointerMotionMask | b->state | b->motionMask; + SetMaskForEvent(device->id, mask, DeviceMotionNotify); + mask = PointerMotionMask | b->state | b->motionMask; + SetMaskForEvent(device->id, mask, MotionNotify); + } else if (event->type == ET_ButtonRelease) { + Mask mask; + if (!b) + return DONT_PROCESS; + + kptr = &b->down[key>>3]; + if (!(*kptr & bit)) + return DONT_PROCESS; + if (IsMaster(device)) { + DeviceIntPtr sd; + + /* + * Leave the button down if any slave has the + * button still down. Note that this depends on the + * event being delivered through the slave first + */ + for (sd = inputInfo.devices; sd; sd = sd->next) { + if (IsMaster(sd) || sd->u.master != device) + continue; + if (!sd->button) + continue; + if ((sd->button->down[key>>3] & bit) != 0) + return DONT_PROCESS; + } + } + *kptr &= ~bit; + if (device->valuator) + device->valuator->motionHintWindow = NullWindow; + if (!b->map[key]) + return DONT_PROCESS; + if (b->buttonsDown >= 1 && !--b->buttonsDown) + b->motionMask = 0; + if (b->map[key] <= 5) + b->state &= ~((Button1Mask >> 1) << b->map[key]); + + /* Add state and motionMask to the filter for this event */ + mask = DevicePointerMotionMask | b->state | b->motionMask; + SetMaskForEvent(device->id, mask, DeviceMotionNotify); + mask = PointerMotionMask | b->state | b->motionMask; + SetMaskForEvent(device->id, mask, MotionNotify); + } else if (event->type == ET_ProximityIn) + device->valuator->mode &= ~OutOfProximity; + else if (event->type == ET_ProximityOut) + device->valuator->mode |= OutOfProximity; + + return DEFAULT; +} + +static void +ProcessRawEvent(RawDeviceEvent *ev, DeviceIntPtr device) +{ + GrabPtr grab = device->deviceGrab.grab; + + if (grab) + DeliverGrabbedEvent((InternalEvent*)ev, device, FALSE); + else { /* deliver to all root windows */ + xEvent *xi; + int i; + + i = EventToXI2((InternalEvent*)ev, (xEvent**)&xi); + if (i != Success) + { + ErrorF("[Xi] %s: XI2 conversion failed in ProcessRawEvent (%d)\n", + device->name, i); + return; + } + + for (i = 0; i < screenInfo.numScreens; i++) + DeliverEventsToWindow(device, WindowTable[i], xi, 1, + GetEventFilter(device, xi), NULL); + free(xi); + } +} + +/** + * Main device event processing function. + * Called from when processing the events from the event queue. + * + */ +void +ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device) +{ + GrabPtr grab; + Bool deactivateDeviceGrab = FALSE; + int key = 0, rootX, rootY; + ButtonClassPtr b; + KeyClassPtr k; + ValuatorClassPtr v; + int ret = 0; + int state, i; + DeviceIntPtr mouse = NULL, kbd = NULL; + DeviceEvent *event = &ev->device_event; + + CHECKEVENT(ev); + + if (ev->any.type == ET_RawKeyPress || + ev->any.type == ET_RawKeyRelease || + ev->any.type == ET_RawButtonPress || + ev->any.type == ET_RawButtonRelease || + ev->any.type == ET_RawMotion) + { + ProcessRawEvent(&ev->raw_event, device); + return; + } + + if (IsPointerDevice(device)) + { + kbd = GetPairedDevice(device); + mouse = device; + if (!kbd->key) /* can happen with floating SDs */ + kbd = NULL; + } else + { + mouse = GetPairedDevice(device); + kbd = device; + if (!mouse->valuator || !mouse->button) /* may be float. SDs */ + mouse = NULL; + } + + /* State needs to be assembled BEFORE the device is updated. */ + state = (kbd && kbd->key) ? XkbStateFieldFromRec(&kbd->key->xkbInfo->state) : 0; + state |= (mouse && mouse->button) ? (mouse->button->state) : 0; + + for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) + if (BitIsOn(mouse->button->down, i)) + SetBit(event->buttons, i); + + if (kbd && kbd->key) + { + XkbStatePtr state; + /* we need the state before the event happens */ + if (event->type == ET_KeyPress || event->type == ET_KeyRelease) + state = &kbd->key->xkbInfo->prev_state; + else + state = &kbd->key->xkbInfo->state; + + event->mods.base = state->base_mods; + event->mods.latched = state->latched_mods; + event->mods.locked = state->locked_mods; + event->mods.effective = state->mods; + + event->group.base = state->base_group; + event->group.latched = state->latched_group; + event->group.locked = state->locked_group; + event->group.effective = state->group; + } + + ret = UpdateDeviceState(device, event); + if (ret == DONT_PROCESS) + return; + + v = device->valuator; + b = device->button; + k = device->key; + + if (IsMaster(device) || !device->u.master) + CheckMotion(event, device); + + switch (event->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + GetSpritePosition(device, &rootX, &rootY); + event->root_x = rootX; + event->root_y = rootY; + NoticeEventTime((InternalEvent*)event); + event->corestate = state; + key = event->detail.key; + break; + default: + break; + } + + if (DeviceEventCallback && !syncEvents.playingEvents) { + DeviceEventInfoRec eventinfo; + SpritePtr pSprite = device->spriteInfo->sprite; + + /* see comment in EnqueueEvents regarding the next three lines */ + if (ev->any.type == ET_Motion) + ev->device_event.root = WindowTable[pSprite->hotPhys.pScreen->myNum]->drawable.id; + + eventinfo.device = device; + eventinfo.event = ev; + CallCallbacks(&DeviceEventCallback, (pointer) & eventinfo); + } + + grab = device->deviceGrab.grab; + + switch(event->type) + { + case ET_KeyPress: + if (!grab && CheckDeviceGrabs(device, event, 0)) { + device->deviceGrab.activatingKey = key; + return; + } + break; + case ET_KeyRelease: + if (grab && device->deviceGrab.fromPassiveGrab && + (key == device->deviceGrab.activatingKey) && + (device->deviceGrab.grab->type == KeyPress || + device->deviceGrab.grab->type == DeviceKeyPress || + device->deviceGrab.grab->type == XI_KeyPress)) + deactivateDeviceGrab = TRUE; + break; + case ET_ButtonPress: + event->detail.button = b->map[key]; + if (!event->detail.button) { /* there's no button 0 */ + event->detail.button = key; + return; + } + if (!grab && CheckDeviceGrabs(device, event, 0)) + { + /* if a passive grab was activated, the event has been sent + * already */ + return; + } + break; + case ET_ButtonRelease: + event->detail.button = b->map[key]; + if (!event->detail.button) { /* there's no button 0 */ + event->detail.button = key; + return; + } + if (grab && !b->buttonsDown && + device->deviceGrab.fromPassiveGrab && + (device->deviceGrab.grab->type == ButtonPress || + device->deviceGrab.grab->type == DeviceButtonPress || + device->deviceGrab.grab->type == XI_ButtonPress)) + deactivateDeviceGrab = TRUE; + default: + break; + } + + + if (grab) + DeliverGrabbedEvent((InternalEvent*)event, device, deactivateDeviceGrab); + else if (device->focus && !IsPointerEvent((InternalEvent*)ev)) + DeliverFocusedEvent(device, (InternalEvent*)event, + GetSpriteWindow(device)); + else + DeliverDeviceEvents(GetSpriteWindow(device), (InternalEvent*)event, + NullGrab, NullWindow, device); + + if (deactivateDeviceGrab == TRUE) + (*device->deviceGrab.DeactivateGrab) (device); + event->detail.key = key; +} + +int +InitProximityClassDeviceStruct(DeviceIntPtr dev) +{ + ProximityClassPtr proxc; + + proxc = (ProximityClassPtr) malloc(sizeof(ProximityClassRec)); + if (!proxc) + return FALSE; + proxc->sourceid = dev->id; + dev->proximity = proxc; + return TRUE; +} + +/** + * Initialise the device's valuators. The memory must already be allocated, + * this function merely inits the matching axis (specified through axnum) to + * sane values. + * + * It is a condition that (minval < maxval). + * + * @see InitValuatorClassDeviceStruct + */ +void +InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int maxval, + int resolution, int min_res, int max_res) +{ + AxisInfoPtr ax; + + if (!dev || !dev->valuator || minval > maxval) + return; + if (axnum >= dev->valuator->numAxes) + return; + + ax = dev->valuator->axes + axnum; + + ax->min_value = minval; + ax->max_value = maxval; + ax->resolution = resolution; + ax->min_resolution = min_res; + ax->max_resolution = max_res; + ax->label = label; +} + +static void +FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, + ButtonClassPtr b, ValuatorClassPtr v, int first) +{ + ev->type = DeviceStateNotify; + ev->deviceid = dev->id; + ev->time = currentTime.milliseconds; + ev->classes_reported = 0; + ev->num_keys = 0; + ev->num_buttons = 0; + ev->num_valuators = 0; + + if (b) { + ev->classes_reported |= (1 << ButtonClass); + ev->num_buttons = b->numButtons; + memcpy((char*)ev->buttons, (char*)b->down, 4); + } else if (k) { + ev->classes_reported |= (1 << KeyClass); + ev->num_keys = k->xkbInfo->desc->max_key_code - + k->xkbInfo->desc->min_key_code; + memmove((char *)&ev->keys[0], (char *)k->down, 4); + } + if (v) { + int nval = v->numAxes - first; + + ev->classes_reported |= (1 << ValuatorClass); + ev->classes_reported |= (dev->valuator->mode << ModeBitsShift); + ev->num_valuators = nval < 3 ? nval : 3; + switch (ev->num_valuators) { + case 3: + ev->valuator2 = v->axisVal[first + 2]; + case 2: + ev->valuator1 = v->axisVal[first + 1]; + case 1: + ev->valuator0 = v->axisVal[first]; + break; + } + } +} + +static void +FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, + int first) +{ + int nval = v->numAxes - first; + + ev->type = DeviceValuator; + ev->deviceid = dev->id; + ev->num_valuators = nval < 3 ? nval : 3; + ev->first_valuator = first; + switch (ev->num_valuators) { + case 3: + ev->valuator2 = v->axisVal[first + 2]; + case 2: + ev->valuator1 = v->axisVal[first + 1]; + case 1: + ev->valuator0 = v->axisVal[first]; + break; + } + first += ev->num_valuators; +} + +void +DeviceFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, + WindowPtr pWin) +{ + deviceFocus event; + xXIFocusInEvent *xi2event; + DeviceIntPtr mouse; + int btlen, len, i; + + mouse = (IsMaster(dev) || dev->u.master) ? GetMaster(dev, MASTER_POINTER) : dev; + + /* XI 2 event */ + btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; + btlen = bytes_to_int32(btlen); + len = sizeof(xXIFocusInEvent) + btlen * 4; + + xi2event = calloc(1, len); + xi2event->type = GenericEvent; + xi2event->extension = IReqCode; + xi2event->evtype = type; + xi2event->length = bytes_to_int32(len - sizeof(xEvent)); + xi2event->buttons_len = btlen; + xi2event->detail = detail; + xi2event->time = currentTime.milliseconds; + xi2event->deviceid = dev->id; + xi2event->sourceid = dev->id; /* a device doesn't change focus by itself */ + xi2event->mode = mode; + xi2event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); + xi2event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); + + for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) + if (BitIsOn(mouse->button->down, i)) + SetBit(&xi2event[1], i); + + if (dev->key) + { + xi2event->mods.base_mods = dev->key->xkbInfo->state.base_mods; + xi2event->mods.latched_mods = dev->key->xkbInfo->state.latched_mods; + xi2event->mods.locked_mods = dev->key->xkbInfo->state.locked_mods; + xi2event->mods.effective_mods = dev->key->xkbInfo->state.mods; + + xi2event->group.base_group = dev->key->xkbInfo->state.base_group; + xi2event->group.latched_group = dev->key->xkbInfo->state.latched_group; + xi2event->group.locked_group = dev->key->xkbInfo->state.locked_group; + xi2event->group.effective_group = dev->key->xkbInfo->state.group; + } + + FixUpEventFromWindow(dev, (xEvent*)xi2event, pWin, None, FALSE); + + DeliverEventsToWindow(dev, pWin, (xEvent*)xi2event, 1, + GetEventFilter(dev, (xEvent*)xi2event), NullGrab); + + free(xi2event); + + /* XI 1.x event */ + event.deviceid = dev->id; + event.mode = mode; + event.type = (type == XI_FocusIn) ? DeviceFocusIn : DeviceFocusOut; + event.detail = detail; + event.window = pWin->drawable.id; + event.time = currentTime.milliseconds; + + DeliverEventsToWindow(dev, pWin, (xEvent *) & event, 1, + DeviceFocusChangeMask, NullGrab); + + if ((type == DeviceFocusIn) && + (wOtherInputMasks(pWin)) && + (wOtherInputMasks(pWin)->inputEvents[dev->id] & DeviceStateNotifyMask)) + { + int evcount = 1; + deviceStateNotify *ev, *sev; + deviceKeyStateNotify *kev; + deviceButtonStateNotify *bev; + + KeyClassPtr k; + ButtonClassPtr b; + ValuatorClassPtr v; + int nval = 0, nkeys = 0, nbuttons = 0, first = 0; + + if ((b = dev->button) != NULL) { + nbuttons = b->numButtons; + if (nbuttons > 32) + evcount++; + } + if ((k = dev->key) != NULL) { + nkeys = k->xkbInfo->desc->max_key_code - + k->xkbInfo->desc->min_key_code; + if (nkeys > 32) + evcount++; + if (nbuttons > 0) { + evcount++; + } + } + if ((v = dev->valuator) != NULL) { + nval = v->numAxes; + + if (nval > 3) + evcount++; + if (nval > 6) { + if (!(k && b)) + evcount++; + if (nval > 9) + evcount += ((nval - 7) / 3); + } + } + + sev = ev = (deviceStateNotify *) malloc(evcount * sizeof(xEvent)); + FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first); + + if (b != NULL) { + FixDeviceStateNotify(dev, ev++, NULL, b, v, first); + first += 3; + nval -= 3; + if (nbuttons > 32) { + (ev - 1)->deviceid |= MORE_EVENTS; + bev = (deviceButtonStateNotify *) ev++; + bev->type = DeviceButtonStateNotify; + bev->deviceid = dev->id; + memcpy((char*)&bev->buttons[4], (char*)&b->down[4], DOWN_LENGTH - 4); + } + if (nval > 0) { + (ev - 1)->deviceid |= MORE_EVENTS; + FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); + first += 3; + nval -= 3; + } + } + + if (k != NULL) { + FixDeviceStateNotify(dev, ev++, k, NULL, v, first); + first += 3; + nval -= 3; + if (nkeys > 32) { + (ev - 1)->deviceid |= MORE_EVENTS; + kev = (deviceKeyStateNotify *) ev++; + kev->type = DeviceKeyStateNotify; + kev->deviceid = dev->id; + memmove((char *)&kev->keys[0], (char *)&k->down[4], 28); + } + if (nval > 0) { + (ev - 1)->deviceid |= MORE_EVENTS; + FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); + first += 3; + nval -= 3; + } + } + + while (nval > 0) { + FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first); + first += 3; + nval -= 3; + if (nval > 0) { + (ev - 1)->deviceid |= MORE_EVENTS; + FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); + first += 3; + nval -= 3; + } + } + + DeliverEventsToWindow(dev, pWin, (xEvent *) sev, evcount, + DeviceStateNotifyMask, NullGrab); + free(sev); + } +} + +int +CheckGrabValues(ClientPtr client, GrabParameters* param) +{ + if (param->grabtype != GRABTYPE_CORE && + param->grabtype != GRABTYPE_XI && + param->grabtype != GRABTYPE_XI2) + { + ErrorF("[Xi] grabtype is invalid. This is a bug.\n"); + return BadImplementation; + } + + if ((param->this_device_mode != GrabModeSync) && + (param->this_device_mode != GrabModeAsync)) { + client->errorValue = param->this_device_mode; + return BadValue; + } + if ((param->other_devices_mode != GrabModeSync) && + (param->other_devices_mode != GrabModeAsync)) { + client->errorValue = param->other_devices_mode; + return BadValue; + } + + if (param->grabtype != GRABTYPE_XI2 && (param->modifiers != AnyModifier) && + (param->modifiers & ~AllModifiersMask)) { + client->errorValue = param->modifiers; + return BadValue; + } + + if ((param->ownerEvents != xFalse) && (param->ownerEvents != xTrue)) { + client->errorValue = param->ownerEvents; + return BadValue; + } + return Success; +} + +int +GrabButton(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device, + int button, GrabParameters *param, GrabType grabtype, + GrabMask *mask) +{ + WindowPtr pWin, confineTo; + CursorPtr cursor; + GrabPtr grab; + int rc, type = -1; + Mask access_mode = DixGrabAccess; + + rc = CheckGrabValues(client, param); + if (rc != Success) + return rc; + if (param->confineTo == None) + confineTo = NullWindow; + else { + rc = dixLookupWindow(&confineTo, param->confineTo, client, DixSetAttrAccess); + if (rc != Success) + return rc; + } + if (param->cursor == None) + cursor = NullCursor; + else { + rc = dixLookupResourceByType((pointer *)&cursor, param->cursor, + RT_CURSOR, client, DixUseAccess); + if (rc != Success) + { + client->errorValue = param->cursor; + return (rc == BadValue) ? BadCursor : rc; + } + access_mode |= DixForceAccess; + } + if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc != Success) + return rc; + rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + if (grabtype == GRABTYPE_XI) + type = DeviceButtonPress; + else if (grabtype == GRABTYPE_XI2) + type = XI_ButtonPress; + + grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype, + mask, param, type, button, confineTo, cursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + +/** + * Grab the given key. If grabtype is GRABTYPE_XI, the key is a keycode. If + * grabtype is GRABTYPE_XI2, the key is a keysym. + */ +int +GrabKey(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device, + int key, GrabParameters *param, GrabType grabtype, GrabMask *mask) +{ + WindowPtr pWin; + GrabPtr grab; + KeyClassPtr k = dev->key; + Mask access_mode = DixGrabAccess; + int rc, type = -1; + + rc = CheckGrabValues(client, param); + if (rc != Success) + return rc; + if (k == NULL) + return BadMatch; + if (grabtype == GRABTYPE_XI) + { + if ((key > k->xkbInfo->desc->max_key_code || + key < k->xkbInfo->desc->min_key_code) + && (key != AnyKey)) { + client->errorValue = key; + return BadValue; + } + type = DeviceKeyPress; + } else if (grabtype == GRABTYPE_XI2) + type = XI_KeyPress; + + rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc != Success) + return rc; + + grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype, + mask, param, type, key, NULL, NULL); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + +/* Enter/FocusIn grab */ +int +GrabWindow(ClientPtr client, DeviceIntPtr dev, int type, + GrabParameters *param, GrabMask *mask) +{ + WindowPtr pWin; + CursorPtr cursor; + GrabPtr grab; + Mask access_mode = DixGrabAccess; + int rc; + + rc = CheckGrabValues(client, param); + if (rc != Success) + return rc; + + rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + if (param->cursor == None) + cursor = NullCursor; + else { + rc = dixLookupResourceByType((pointer *)&cursor, param->cursor, + RT_CURSOR, client, DixUseAccess); + if (rc != Success) + { + client->errorValue = param->cursor; + return (rc == BadValue) ? BadCursor : rc; + } + access_mode |= DixForceAccess; + } + if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc != Success) + return rc; + + grab = CreateGrab(client->index, dev, dev, pWin, GRABTYPE_XI2, + mask, param, (type == XIGrabtypeEnter) ? XI_Enter : XI_FocusIn, + 0, NULL, cursor); + + if (!grab) + return BadAlloc; + + return AddPassiveGrabToList(client, grab); +} + +int +SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client, + Mask mask, Mask exclusivemasks) +{ + int mskidx = dev->id; + int i, ret; + Mask check; + InputClientsPtr others; + + check = (mask & exclusivemasks); + if (wOtherInputMasks(pWin)) { + if (check & wOtherInputMasks(pWin)->inputEvents[mskidx]) { /* It is illegal for two different + * clients to select on any of the + * events for maskcheck. However, + * it is OK, for some client to + * continue selecting on one of those + * events. */ + for (others = wOtherInputMasks(pWin)->inputClients; others; + others = others->next) { + if (!SameClient(others, client) && (check & + others->mask[mskidx])) + return BadAccess; + } + } + for (others = wOtherInputMasks(pWin)->inputClients; others; + others = others->next) { + if (SameClient(others, client)) { + check = others->mask[mskidx]; + others->mask[mskidx] = mask; + if (mask == 0) { + for (i = 0; i < EMASKSIZE; i++) + if (i != mskidx && others->mask[i] != 0) + break; + if (i == EMASKSIZE) { + RecalculateDeviceDeliverableEvents(pWin); + if (ShouldFreeInputMasks(pWin, FALSE)) + FreeResource(others->resource, RT_NONE); + return Success; + } + } + goto maskSet; + } + } + } + check = 0; + if ((ret = AddExtensionClient(pWin, client, mask, mskidx)) != Success) + return ret; + maskSet: + if (dev->valuator) + if ((dev->valuator->motionHintWindow == pWin) && + (mask & DevicePointerMotionHintMask) && + !(check & DevicePointerMotionHintMask) && !dev->deviceGrab.grab) + dev->valuator->motionHintWindow = NullWindow; + RecalculateDeviceDeliverableEvents(pWin); + return Success; +} + +int +AddExtensionClient(WindowPtr pWin, ClientPtr client, Mask mask, int mskidx) +{ + InputClientsPtr others; + + if (!pWin->optional && !MakeWindowOptional(pWin)) + return BadAlloc; + others = calloc(1, sizeof(InputClients)); + if (!others) + return BadAlloc; + if (!pWin->optional->inputMasks && !MakeInputMasks(pWin)) + return BadAlloc; + others->mask[mskidx] = mask; + others->resource = FakeClientID(client->index); + others->next = pWin->optional->inputMasks->inputClients; + pWin->optional->inputMasks->inputClients = others; + if (!AddResource(others->resource, RT_INPUTCLIENT, (pointer) pWin)) + return BadAlloc; + return Success; +} + +static Bool +MakeInputMasks(WindowPtr pWin) +{ + struct _OtherInputMasks *imasks; + + imasks = calloc(1, sizeof(struct _OtherInputMasks)); + if (!imasks) + return FALSE; + pWin->optional->inputMasks = imasks; + return TRUE; +} + +void +RecalculateDeviceDeliverableEvents(WindowPtr pWin) +{ + InputClientsPtr others; + struct _OtherInputMasks *inputMasks; /* default: NULL */ + WindowPtr pChild, tmp; + int i, j; + + pChild = pWin; + while (1) { + if ((inputMasks = wOtherInputMasks(pChild)) != 0) { + for (i = 0; i < EMASKSIZE; i++) + memset(inputMasks->xi2mask[i], 0, sizeof(inputMasks->xi2mask[i])); + for (others = inputMasks->inputClients; others; + others = others->next) { + for (i = 0; i < EMASKSIZE; i++) + inputMasks->inputEvents[i] |= others->mask[i]; + for (i = 0; i < EMASKSIZE; i++) + for (j = 0; j < XI2MASKSIZE; j++) + inputMasks->xi2mask[i][j] |= others->xi2mask[i][j]; + } + for (i = 0; i < EMASKSIZE; i++) + inputMasks->deliverableEvents[i] = inputMasks->inputEvents[i]; + for (tmp = pChild->parent; tmp; tmp = tmp->parent) + if (wOtherInputMasks(tmp)) + for (i = 0; i < EMASKSIZE; i++) + inputMasks->deliverableEvents[i] |= + (wOtherInputMasks(tmp)->deliverableEvents[i] + & ~inputMasks-> + dontPropagateMask[i] & PropagateMask[i]); + } + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + +int +InputClientGone(WindowPtr pWin, XID id) +{ + InputClientsPtr other, prev; + + if (!wOtherInputMasks(pWin)) + return (Success); + prev = 0; + for (other = wOtherInputMasks(pWin)->inputClients; other; + other = other->next) { + if (other->resource == id) { + if (prev) { + prev->next = other->next; + free(other); + } else if (!(other->next)) { + if (ShouldFreeInputMasks(pWin, TRUE)) { + wOtherInputMasks(pWin)->inputClients = other->next; + free(wOtherInputMasks(pWin)); + pWin->optional->inputMasks = (OtherInputMasks *) NULL; + CheckWindowOptionalNeed(pWin); + free(other); + } else { + other->resource = FakeClientID(0); + if (!AddResource(other->resource, RT_INPUTCLIENT, + (pointer) pWin)) + return BadAlloc; + } + } else { + wOtherInputMasks(pWin)->inputClients = other->next; + free(other); + } + RecalculateDeviceDeliverableEvents(pWin); + return (Success); + } + prev = other; + } + FatalError("client not on device event list"); +} + +int +SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate, + xEvent * ev, Mask mask, int count) +{ + WindowPtr pWin; + WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ + WindowPtr spriteWin = GetSpriteWindow(d); + + if (dest == PointerWindow) + pWin = spriteWin; + else if (dest == InputFocus) { + WindowPtr inputFocus; + + if (!d->focus) + inputFocus = spriteWin; + else + inputFocus = d->focus->win; + + if (inputFocus == FollowKeyboardWin) + 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 = GetCurrentRootWindow(d); + + if (IsParent(inputFocus, spriteWin)) { + effectiveFocus = inputFocus; + pWin = spriteWin; + } else + effectiveFocus = pWin = inputFocus; + } else + dixLookupWindow(&pWin, dest, client, DixSendAccess); + if (!pWin) + return BadWindow; + if ((propagate != xFalse) && (propagate != xTrue)) { + client->errorValue = propagate; + return BadValue; + } + ev->u.u.type |= 0x80; + if (propagate) { + for (; pWin; pWin = pWin->parent) { + if (DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab)) + return Success; + if (pWin == effectiveFocus) + return Success; + if (wOtherInputMasks(pWin)) + mask &= ~wOtherInputMasks(pWin)->dontPropagateMask[d->id]; + if (!mask) + break; + } + } else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, ev, count)) + DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab); + return Success; +} + +int +SetButtonMapping(ClientPtr client, DeviceIntPtr dev, int nElts, BYTE * map) +{ + int i; + ButtonClassPtr b = dev->button; + + if (b == NULL) + return BadMatch; + + if (nElts != b->numButtons) { + client->errorValue = nElts; + return BadValue; + } + if (BadDeviceMap(&map[0], nElts, 1, 255, &client->errorValue)) + return BadValue; + for (i = 0; i < nElts; i++) + if ((b->map[i + 1] != map[i]) && BitIsOn(b->down, i + 1)) + return MappingBusy; + for (i = 0; i < nElts; i++) + b->map[i + 1] = map[i]; + return Success; +} + +int +ChangeKeyMapping(ClientPtr client, + DeviceIntPtr dev, + unsigned len, + int type, + KeyCode firstKeyCode, + CARD8 keyCodes, CARD8 keySymsPerKeyCode, KeySym * map) +{ + KeySymsRec keysyms; + KeyClassPtr k = dev->key; + + if (k == NULL) + return (BadMatch); + + if (len != (keyCodes * keySymsPerKeyCode)) + return BadLength; + + if ((firstKeyCode < k->xkbInfo->desc->min_key_code) || + (firstKeyCode + keyCodes - 1 > k->xkbInfo->desc->max_key_code)) { + client->errorValue = firstKeyCode; + return BadValue; + } + if (keySymsPerKeyCode == 0) { + client->errorValue = 0; + return BadValue; + } + keysyms.minKeyCode = firstKeyCode; + keysyms.maxKeyCode = firstKeyCode + keyCodes - 1; + keysyms.mapWidth = keySymsPerKeyCode; + keysyms.map = map; + + XkbApplyMappingChange(dev, &keysyms, firstKeyCode, keyCodes, NULL, + serverClient); + + return Success; +} + +static void +DeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev) +{ + WindowPtr parent; + + /* Deactivate any grabs performed on this window, before making + * any input focus changes. + * Deactivating a device grab should cause focus events. */ + + if (dev->deviceGrab.grab && (dev->deviceGrab.grab->window == pWin)) + (*dev->deviceGrab.DeactivateGrab) (dev); + + /* If the focus window is a root window (ie. has no parent) + * then don't delete the focus from it. */ + + if (dev->focus && (pWin == dev->focus->win) && (pWin->parent != NullWindow)) { + int focusEventMode = NotifyNormal; + + /* If a grab is in progress, then alter the mode of focus events. */ + + if (dev->deviceGrab.grab) + focusEventMode = NotifyWhileGrabbed; + + switch (dev->focus->revert) { + case RevertToNone: + if (!ActivateFocusInGrab(dev, pWin, NoneWin)) + DoFocusEvents(dev, pWin, NoneWin, focusEventMode); + dev->focus->win = NoneWin; + dev->focus->traceGood = 0; + break; + case RevertToParent: + parent = pWin; + do { + parent = parent->parent; + dev->focus->traceGood--; + } + while (!parent->realized); + if (!ActivateFocusInGrab(dev, pWin, parent)) + DoFocusEvents(dev, pWin, parent, focusEventMode); + dev->focus->win = parent; + dev->focus->revert = RevertToNone; + break; + case RevertToPointerRoot: + if (!ActivateFocusInGrab(dev, pWin, PointerRootWin)) + DoFocusEvents(dev, pWin, PointerRootWin, focusEventMode); + dev->focus->win = PointerRootWin; + dev->focus->traceGood = 0; + break; + case RevertToFollowKeyboard: + { + DeviceIntPtr kbd = GetMaster(dev, MASTER_KEYBOARD); + if (!kbd || (kbd == dev && kbd != inputInfo.keyboard)) + kbd = inputInfo.keyboard; + if (kbd->focus->win) { + if (!ActivateFocusInGrab(dev, pWin, kbd->focus->win)) + DoFocusEvents(dev, pWin, kbd->focus->win, focusEventMode); + dev->focus->win = FollowKeyboardWin; + dev->focus->traceGood = 0; + } else { + if (!ActivateFocusInGrab(dev, pWin, NoneWin)) + DoFocusEvents(dev, pWin, NoneWin, focusEventMode); + dev->focus->win = NoneWin; + dev->focus->traceGood = 0; + } + } + break; + } + } + + if (dev->valuator) + if (dev->valuator->motionHintWindow == pWin) + dev->valuator->motionHintWindow = NullWindow; +} + +void +DeleteWindowFromAnyExtEvents(WindowPtr pWin, Bool freeResources) +{ + int i; + DeviceIntPtr dev; + InputClientsPtr ic; + struct _OtherInputMasks *inputMasks; + + for (dev = inputInfo.devices; dev; dev = dev->next) { + DeleteDeviceFromAnyExtEvents(pWin, dev); + } + + for (dev = inputInfo.off_devices; dev; dev = dev->next) + DeleteDeviceFromAnyExtEvents(pWin, dev); + + if (freeResources) + while ((inputMasks = wOtherInputMasks(pWin)) != 0) { + ic = inputMasks->inputClients; + for (i = 0; i < EMASKSIZE; i++) + inputMasks->dontPropagateMask[i] = 0; + FreeResource(ic->resource, RT_NONE); + } +} + +int +MaybeSendDeviceMotionNotifyHint(deviceKeyButtonPointer * pEvents, Mask mask) +{ + DeviceIntPtr dev; + + dixLookupDevice(&dev, pEvents->deviceid & DEVICE_BITS, serverClient, + DixReadAccess); + if (!dev) + return 0; + + if (pEvents->type == DeviceMotionNotify) { + if (mask & DevicePointerMotionHintMask) { + if (WID(dev->valuator->motionHintWindow) == pEvents->event) { + return 1; /* don't send, but pretend we did */ + } + pEvents->detail = NotifyHint; + } else { + pEvents->detail = NotifyNormal; + } + } + return (0); +} + +void +CheckDeviceGrabAndHintWindow(WindowPtr pWin, int type, + deviceKeyButtonPointer * xE, GrabPtr grab, + ClientPtr client, Mask deliveryMask) +{ + DeviceIntPtr dev; + + dixLookupDevice(&dev, xE->deviceid & DEVICE_BITS, serverClient, + DixGrabAccess); + if (!dev) + return; + + if (type == DeviceMotionNotify) + dev->valuator->motionHintWindow = pWin; + else if ((type == DeviceButtonPress) && (!grab) && + (deliveryMask & DeviceButtonGrabMask)) { + GrabRec tempGrab; + + tempGrab.device = dev; + tempGrab.resource = client->clientAsMask; + tempGrab.window = pWin; + tempGrab.ownerEvents = + (deliveryMask & DeviceOwnerGrabButtonMask) ? TRUE : FALSE; + tempGrab.eventMask = deliveryMask; + tempGrab.keyboardMode = GrabModeAsync; + tempGrab.pointerMode = GrabModeAsync; + tempGrab.confineTo = NullWindow; + tempGrab.cursor = NullCursor; + tempGrab.next = NULL; + (*dev->deviceGrab.ActivateGrab) (dev, &tempGrab, currentTime, TRUE); + } +} + +static Mask +DeviceEventMaskForClient(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client) +{ + InputClientsPtr other; + + if (!wOtherInputMasks(pWin)) + return 0; + for (other = wOtherInputMasks(pWin)->inputClients; other; + other = other->next) { + if (SameClient(other, client)) + return other->mask[dev->id]; + } + return 0; +} + +void +MaybeStopDeviceHint(DeviceIntPtr dev, ClientPtr client) +{ + WindowPtr pWin; + GrabPtr grab = dev->deviceGrab.grab; + + pWin = dev->valuator->motionHintWindow; + + if ((grab && SameClient(grab, client) && + ((grab->eventMask & DevicePointerMotionHintMask) || + (grab->ownerEvents && + (DeviceEventMaskForClient(dev, pWin, client) & + DevicePointerMotionHintMask)))) || + (!grab && + (DeviceEventMaskForClient(dev, pWin, client) & + DevicePointerMotionHintMask))) + dev->valuator->motionHintWindow = NullWindow; +} + +int +DeviceEventSuppressForWindow(WindowPtr pWin, ClientPtr client, Mask mask, + int maskndx) +{ + struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + + if (mask & ~PropagateMask[maskndx]) { + client->errorValue = mask; + return BadValue; + } + + if (mask == 0) { + if (inputMasks) + inputMasks->dontPropagateMask[maskndx] = mask; + } else { + if (!inputMasks) + AddExtensionClient(pWin, client, 0, 0); + inputMasks = wOtherInputMasks(pWin); + inputMasks->dontPropagateMask[maskndx] = mask; + } + RecalculateDeviceDeliverableEvents(pWin); + if (ShouldFreeInputMasks(pWin, FALSE)) + FreeResource(inputMasks->inputClients->resource, RT_NONE); + return Success; +} + +Bool +ShouldFreeInputMasks(WindowPtr pWin, Bool ignoreSelectedEvents) +{ + int i; + Mask allInputEventMasks = 0; + struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + + for (i = 0; i < EMASKSIZE; i++) + allInputEventMasks |= inputMasks->dontPropagateMask[i]; + if (!ignoreSelectedEvents) + for (i = 0; i < EMASKSIZE; i++) + allInputEventMasks |= inputMasks->inputEvents[i]; + if (allInputEventMasks == 0) + return TRUE; + else + return FALSE; +} + +/*********************************************************************** + * + * Walk through the window tree, finding all clients that want to know + * about the Event. + * + */ + +static void +FindInterestedChildren(DeviceIntPtr dev, WindowPtr p1, Mask mask, + xEvent * ev, int count) +{ + WindowPtr p2; + + while (p1) { + p2 = p1->firstChild; + DeliverEventsToWindow(dev, p1, ev, count, mask, NullGrab); + FindInterestedChildren(dev, p2, mask, ev, count); + p1 = p1->nextSib; + } +} + +/*********************************************************************** + * + * Send an event to interested clients in all windows on all screens. + * + */ + +void +SendEventToAllWindows(DeviceIntPtr dev, Mask mask, xEvent * ev, int count) +{ + int i; + WindowPtr pWin, p1; + + for (i = 0; i < screenInfo.numScreens; i++) { + pWin = WindowTable[i]; + if (!pWin) + continue; + DeliverEventsToWindow(dev, pWin, ev, count, mask, NullGrab); + p1 = pWin->firstChild; + FindInterestedChildren(dev, p1, mask, ev, count); + } +} + +/** + * Set the XI2 mask for the given client on the given window. + * @param dev The device to set the mask for. + * @param win The window to set the mask on. + * @param client The client setting the mask. + * @param len Number of bytes in mask. + * @param mask Event mask in the form of (1 << eventtype) + */ +int +XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client, + unsigned int len, unsigned char* mask) +{ + OtherInputMasks *masks; + InputClientsPtr others = NULL; + + masks = wOtherInputMasks(win); + if (masks) + { + for (others = wOtherInputMasks(win)->inputClients; others; + others = others->next) { + if (SameClient(others, client)) { + memset(others->xi2mask[dev->id], 0, + sizeof(others->xi2mask[dev->id])); + break; + } + } + } + + len = min(len, sizeof(others->xi2mask[dev->id])); + + if (len && !others) + { + if (AddExtensionClient(win, client, 0, 0) != Success) + return BadAlloc; + others= wOtherInputMasks(win)->inputClients; + } + + if (others) + memset(others->xi2mask[dev->id], 0, sizeof(others->xi2mask[dev->id])); + + if (len) + memcpy(others->xi2mask[dev->id], mask, len); + + RecalculateDeviceDeliverableEvents(win); + + return Success; +} diff --git a/xorg-server/Xi/extinit.c b/xorg-server/Xi/extinit.c index 07057377a..9d6c81a5b 100644 --- a/xorg-server/Xi/extinit.c +++ b/xorg-server/Xi/extinit.c @@ -1156,7 +1156,7 @@ void AssignTypeAndName(DeviceIntPtr dev, Atom type, char *name) { dev->xinput_type = type; - dev->name = (char *)xalloc(strlen(name) + 1); + dev->name = (char *)malloc(strlen(name) + 1); strcpy(dev->name, name); } diff --git a/xorg-server/Xi/getdctl.c b/xorg-server/Xi/getdctl.c index 68181fa61..35ddd3f8e 100644 --- a/xorg-server/Xi/getdctl.c +++ b/xorg-server/Xi/getdctl.c @@ -1,314 +1,314 @@ -/************************************************************ - -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. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - 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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-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. - -********************************************************/ - -/******************************************************************** - * - * Get Device control attributes for an extension device. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" /* DeviceIntPtr */ -#include -#include -#include "exglobals.h" - -#include "getdctl.h" - -/*********************************************************************** - * - * This procedure gets the control attributes for an extension device, - * for clients on machines with a different byte ordering than the server. - * - */ - -int -SProcXGetDeviceControl(ClientPtr client) -{ - char n; - - REQUEST(xGetDeviceControlReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xGetDeviceControlReq); - swaps(&stuff->control, n); - return (ProcXGetDeviceControl(client)); -} - -/*********************************************************************** - * - * This procedure copies DeviceResolution data, swapping if necessary. - * - */ - -static void -CopySwapDeviceResolution(ClientPtr client, ValuatorClassPtr v, char *buf, - int length) -{ - char n; - AxisInfoPtr a; - xDeviceResolutionState *r; - int i, *iptr; - - r = (xDeviceResolutionState *) buf; - r->control = DEVICE_RESOLUTION; - r->length = length; - r->num_valuators = v->numAxes; - buf += sizeof(xDeviceResolutionState); - iptr = (int *)buf; - for (i = 0, a = v->axes; i < v->numAxes; i++, a++) - *iptr++ = a->resolution; - for (i = 0, a = v->axes; i < v->numAxes; i++, a++) - *iptr++ = a->min_resolution; - for (i = 0, a = v->axes; i < v->numAxes; i++, a++) - *iptr++ = a->max_resolution; - if (client->swapped) { - swaps(&r->control, n); - swaps(&r->length, n); - swapl(&r->num_valuators, n); - iptr = (int *)buf; - for (i = 0; i < (3 * v->numAxes); i++, iptr++) { - swapl(iptr, n); - } - } -} - -static void CopySwapDeviceAbsCalib (ClientPtr client, AbsoluteClassPtr dts, - char *buf) -{ - char n; - xDeviceAbsCalibState *calib = (xDeviceAbsCalibState *) buf; - - calib->control = DEVICE_ABS_CALIB; - calib->length = sizeof(xDeviceAbsCalibState); - calib->min_x = dts->min_x; - calib->max_x = dts->max_x; - calib->min_y = dts->min_y; - calib->max_y = dts->max_y; - calib->flip_x = dts->flip_x; - calib->flip_y = dts->flip_y; - calib->rotation = dts->rotation; - calib->button_threshold = dts->button_threshold; - - if (client->swapped) { - swaps(&calib->control, n); - swaps(&calib->length, n); - swapl(&calib->min_x, n); - swapl(&calib->max_x, n); - swapl(&calib->min_y, n); - swapl(&calib->max_y, n); - swapl(&calib->flip_x, n); - swapl(&calib->flip_y, n); - swapl(&calib->rotation, n); - swapl(&calib->button_threshold, n); - } -} - -static void CopySwapDeviceAbsArea (ClientPtr client, AbsoluteClassPtr dts, - char *buf) -{ - char n; - xDeviceAbsAreaState *area = (xDeviceAbsAreaState *) buf; - - area->control = DEVICE_ABS_AREA; - area->length = sizeof(xDeviceAbsAreaState); - area->offset_x = dts->offset_x; - area->offset_y = dts->offset_y; - area->width = dts->width; - area->height = dts->height; - area->screen = dts->screen; - area->following = dts->following; - - if (client->swapped) { - swaps(&area->control, n); - swaps(&area->length, n); - swapl(&area->offset_x, n); - swapl(&area->offset_y, n); - swapl(&area->width, n); - swapl(&area->height, n); - swapl(&area->screen, n); - swapl(&area->following, n); - } -} - -static void CopySwapDeviceCore (ClientPtr client, DeviceIntPtr dev, char *buf) -{ - char n; - xDeviceCoreState *c = (xDeviceCoreState *) buf; - - c->control = DEVICE_CORE; - c->length = sizeof(xDeviceCoreState); - c->status = dev->coreEvents; - c->iscore = (dev == inputInfo.keyboard || dev == inputInfo.pointer); - - if (client->swapped) { - swaps(&c->control, n); - swaps(&c->length, n); - swaps(&c->status, n); - } -} - -static void CopySwapDeviceEnable (ClientPtr client, DeviceIntPtr dev, char *buf) -{ - char n; - xDeviceEnableState *e = (xDeviceEnableState *) buf; - - e->control = DEVICE_ENABLE; - e->length = sizeof(xDeviceEnableState); - e->enable = dev->enabled; - - if (client->swapped) { - swaps(&e->control, n); - swaps(&e->length, n); - swaps(&e->enable, n); - } -} - -/*********************************************************************** - * - * This procedure writes the reply for the xGetDeviceControl function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXGetDeviceControl(ClientPtr client, int size, xGetDeviceControlReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - WriteToClient(client, size, (char *)rep); -} - -/*********************************************************************** - * - * Get the state of the specified device control. - * - */ - -int -ProcXGetDeviceControl(ClientPtr client) -{ - int rc, total_length = 0; - char *buf, *savbuf; - DeviceIntPtr dev; - xGetDeviceControlReply rep; - - REQUEST(xGetDeviceControlReq); - REQUEST_SIZE_MATCH(xGetDeviceControlReq); - - rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.repType = X_Reply; - rep.RepType = X_GetDeviceControl; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - switch (stuff->control) { - case DEVICE_RESOLUTION: - if (!dev->valuator) - return BadMatch; - total_length = sizeof(xDeviceResolutionState) + - (3 * sizeof(int) * dev->valuator->numAxes); - break; - case DEVICE_ABS_CALIB: - if (!dev->absolute) - return BadMatch; - - total_length = sizeof(xDeviceAbsCalibState); - break; - case DEVICE_ABS_AREA: - if (!dev->absolute) - return BadMatch; - - total_length = sizeof(xDeviceAbsAreaState); - break; - case DEVICE_CORE: - total_length = sizeof(xDeviceCoreState); - break; - case DEVICE_ENABLE: - total_length = sizeof(xDeviceEnableState); - break; - default: - return BadValue; - } - - buf = (char *)xalloc(total_length); - if (!buf) - return BadAlloc; - savbuf = buf; - - switch (stuff->control) { - case DEVICE_RESOLUTION: - CopySwapDeviceResolution(client, dev->valuator, buf, total_length); - break; - case DEVICE_ABS_CALIB: - CopySwapDeviceAbsCalib(client, dev->absolute, buf); - break; - case DEVICE_ABS_AREA: - CopySwapDeviceAbsArea(client, dev->absolute, buf); - break; - case DEVICE_CORE: - CopySwapDeviceCore(client, dev, buf); - break; - case DEVICE_ENABLE: - CopySwapDeviceEnable(client, dev, buf); - break; - default: - break; - } - - rep.length = bytes_to_int32(total_length); - WriteReplyToClient(client, sizeof(xGetDeviceControlReply), &rep); - WriteToClient(client, total_length, savbuf); - xfree(savbuf); - return Success; -} +/************************************************************ + +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. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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. + +********************************************************/ + +/******************************************************************** + * + * Get Device control attributes for an extension device. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" /* DeviceIntPtr */ +#include +#include +#include "exglobals.h" + +#include "getdctl.h" + +/*********************************************************************** + * + * This procedure gets the control attributes for an extension device, + * for clients on machines with a different byte ordering than the server. + * + */ + +int +SProcXGetDeviceControl(ClientPtr client) +{ + char n; + + REQUEST(xGetDeviceControlReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xGetDeviceControlReq); + swaps(&stuff->control, n); + return (ProcXGetDeviceControl(client)); +} + +/*********************************************************************** + * + * This procedure copies DeviceResolution data, swapping if necessary. + * + */ + +static void +CopySwapDeviceResolution(ClientPtr client, ValuatorClassPtr v, char *buf, + int length) +{ + char n; + AxisInfoPtr a; + xDeviceResolutionState *r; + int i, *iptr; + + r = (xDeviceResolutionState *) buf; + r->control = DEVICE_RESOLUTION; + r->length = length; + r->num_valuators = v->numAxes; + buf += sizeof(xDeviceResolutionState); + iptr = (int *)buf; + for (i = 0, a = v->axes; i < v->numAxes; i++, a++) + *iptr++ = a->resolution; + for (i = 0, a = v->axes; i < v->numAxes; i++, a++) + *iptr++ = a->min_resolution; + for (i = 0, a = v->axes; i < v->numAxes; i++, a++) + *iptr++ = a->max_resolution; + if (client->swapped) { + swaps(&r->control, n); + swaps(&r->length, n); + swapl(&r->num_valuators, n); + iptr = (int *)buf; + for (i = 0; i < (3 * v->numAxes); i++, iptr++) { + swapl(iptr, n); + } + } +} + +static void CopySwapDeviceAbsCalib (ClientPtr client, AbsoluteClassPtr dts, + char *buf) +{ + char n; + xDeviceAbsCalibState *calib = (xDeviceAbsCalibState *) buf; + + calib->control = DEVICE_ABS_CALIB; + calib->length = sizeof(xDeviceAbsCalibState); + calib->min_x = dts->min_x; + calib->max_x = dts->max_x; + calib->min_y = dts->min_y; + calib->max_y = dts->max_y; + calib->flip_x = dts->flip_x; + calib->flip_y = dts->flip_y; + calib->rotation = dts->rotation; + calib->button_threshold = dts->button_threshold; + + if (client->swapped) { + swaps(&calib->control, n); + swaps(&calib->length, n); + swapl(&calib->min_x, n); + swapl(&calib->max_x, n); + swapl(&calib->min_y, n); + swapl(&calib->max_y, n); + swapl(&calib->flip_x, n); + swapl(&calib->flip_y, n); + swapl(&calib->rotation, n); + swapl(&calib->button_threshold, n); + } +} + +static void CopySwapDeviceAbsArea (ClientPtr client, AbsoluteClassPtr dts, + char *buf) +{ + char n; + xDeviceAbsAreaState *area = (xDeviceAbsAreaState *) buf; + + area->control = DEVICE_ABS_AREA; + area->length = sizeof(xDeviceAbsAreaState); + area->offset_x = dts->offset_x; + area->offset_y = dts->offset_y; + area->width = dts->width; + area->height = dts->height; + area->screen = dts->screen; + area->following = dts->following; + + if (client->swapped) { + swaps(&area->control, n); + swaps(&area->length, n); + swapl(&area->offset_x, n); + swapl(&area->offset_y, n); + swapl(&area->width, n); + swapl(&area->height, n); + swapl(&area->screen, n); + swapl(&area->following, n); + } +} + +static void CopySwapDeviceCore (ClientPtr client, DeviceIntPtr dev, char *buf) +{ + char n; + xDeviceCoreState *c = (xDeviceCoreState *) buf; + + c->control = DEVICE_CORE; + c->length = sizeof(xDeviceCoreState); + c->status = dev->coreEvents; + c->iscore = (dev == inputInfo.keyboard || dev == inputInfo.pointer); + + if (client->swapped) { + swaps(&c->control, n); + swaps(&c->length, n); + swaps(&c->status, n); + } +} + +static void CopySwapDeviceEnable (ClientPtr client, DeviceIntPtr dev, char *buf) +{ + char n; + xDeviceEnableState *e = (xDeviceEnableState *) buf; + + e->control = DEVICE_ENABLE; + e->length = sizeof(xDeviceEnableState); + e->enable = dev->enabled; + + if (client->swapped) { + swaps(&e->control, n); + swaps(&e->length, n); + swaps(&e->enable, n); + } +} + +/*********************************************************************** + * + * This procedure writes the reply for the xGetDeviceControl function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXGetDeviceControl(ClientPtr client, int size, xGetDeviceControlReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + WriteToClient(client, size, (char *)rep); +} + +/*********************************************************************** + * + * Get the state of the specified device control. + * + */ + +int +ProcXGetDeviceControl(ClientPtr client) +{ + int rc, total_length = 0; + char *buf, *savbuf; + DeviceIntPtr dev; + xGetDeviceControlReply rep; + + REQUEST(xGetDeviceControlReq); + REQUEST_SIZE_MATCH(xGetDeviceControlReq); + + rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.repType = X_Reply; + rep.RepType = X_GetDeviceControl; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + switch (stuff->control) { + case DEVICE_RESOLUTION: + if (!dev->valuator) + return BadMatch; + total_length = sizeof(xDeviceResolutionState) + + (3 * sizeof(int) * dev->valuator->numAxes); + break; + case DEVICE_ABS_CALIB: + if (!dev->absolute) + return BadMatch; + + total_length = sizeof(xDeviceAbsCalibState); + break; + case DEVICE_ABS_AREA: + if (!dev->absolute) + return BadMatch; + + total_length = sizeof(xDeviceAbsAreaState); + break; + case DEVICE_CORE: + total_length = sizeof(xDeviceCoreState); + break; + case DEVICE_ENABLE: + total_length = sizeof(xDeviceEnableState); + break; + default: + return BadValue; + } + + buf = (char *)malloc(total_length); + if (!buf) + return BadAlloc; + savbuf = buf; + + switch (stuff->control) { + case DEVICE_RESOLUTION: + CopySwapDeviceResolution(client, dev->valuator, buf, total_length); + break; + case DEVICE_ABS_CALIB: + CopySwapDeviceAbsCalib(client, dev->absolute, buf); + break; + case DEVICE_ABS_AREA: + CopySwapDeviceAbsArea(client, dev->absolute, buf); + break; + case DEVICE_CORE: + CopySwapDeviceCore(client, dev, buf); + break; + case DEVICE_ENABLE: + CopySwapDeviceEnable(client, dev, buf); + break; + default: + break; + } + + rep.length = bytes_to_int32(total_length); + WriteReplyToClient(client, sizeof(xGetDeviceControlReply), &rep); + WriteToClient(client, total_length, savbuf); + free(savbuf); + return Success; +} diff --git a/xorg-server/Xi/getfctl.c b/xorg-server/Xi/getfctl.c index 607765e98..99b94158c 100644 --- a/xorg-server/Xi/getfctl.c +++ b/xorg-server/Xi/getfctl.c @@ -1,366 +1,366 @@ -/************************************************************ - -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. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - 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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-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. - -********************************************************/ - -/******************************************************************** - * - * Get feedback control attributes for an extension device. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" /* DeviceIntPtr */ -#include -#include -#include "exglobals.h" - -#include "getfctl.h" - -/*********************************************************************** - * - * This procedure gets the control attributes for an extension device, - * for clients on machines with a different byte ordering than the server. - * - */ - -int -SProcXGetFeedbackControl(ClientPtr client) -{ - char n; - - REQUEST(xGetFeedbackControlReq); - swaps(&stuff->length, n); - return (ProcXGetFeedbackControl(client)); -} - -/*********************************************************************** - * - * This procedure copies KbdFeedbackClass data, swapping if necessary. - * - */ - -static void -CopySwapKbdFeedback(ClientPtr client, KbdFeedbackPtr k, char **buf) -{ - int i; - char n; - xKbdFeedbackState *k2; - - k2 = (xKbdFeedbackState *) * buf; - k2->class = KbdFeedbackClass; - k2->length = sizeof(xKbdFeedbackState); - k2->id = k->ctrl.id; - k2->click = k->ctrl.click; - k2->percent = k->ctrl.bell; - k2->pitch = k->ctrl.bell_pitch; - k2->duration = k->ctrl.bell_duration; - k2->led_mask = k->ctrl.leds; - k2->global_auto_repeat = k->ctrl.autoRepeat; - for (i = 0; i < 32; i++) - k2->auto_repeats[i] = k->ctrl.autoRepeats[i]; - if (client->swapped) { - swaps(&k2->length, n); - swaps(&k2->pitch, n); - swaps(&k2->duration, n); - swapl(&k2->led_mask, n); - swapl(&k2->led_values, n); - } - *buf += sizeof(xKbdFeedbackState); -} - -/*********************************************************************** - * - * This procedure copies PtrFeedbackClass data, swapping if necessary. - * - */ - -static void -CopySwapPtrFeedback(ClientPtr client, PtrFeedbackPtr p, char **buf) -{ - char n; - xPtrFeedbackState *p2; - - p2 = (xPtrFeedbackState *) * buf; - p2->class = PtrFeedbackClass; - p2->length = sizeof(xPtrFeedbackState); - p2->id = p->ctrl.id; - p2->accelNum = p->ctrl.num; - p2->accelDenom = p->ctrl.den; - p2->threshold = p->ctrl.threshold; - if (client->swapped) { - swaps(&p2->length, n); - swaps(&p2->accelNum, n); - swaps(&p2->accelDenom, n); - swaps(&p2->threshold, n); - } - *buf += sizeof(xPtrFeedbackState); -} - -/*********************************************************************** - * - * This procedure copies IntegerFeedbackClass data, swapping if necessary. - * - */ - -static void -CopySwapIntegerFeedback(ClientPtr client, IntegerFeedbackPtr i, char **buf) -{ - char n; - xIntegerFeedbackState *i2; - - i2 = (xIntegerFeedbackState *) * buf; - i2->class = IntegerFeedbackClass; - i2->length = sizeof(xIntegerFeedbackState); - i2->id = i->ctrl.id; - i2->resolution = i->ctrl.resolution; - i2->min_value = i->ctrl.min_value; - i2->max_value = i->ctrl.max_value; - if (client->swapped) { - swaps(&i2->length, n); - swapl(&i2->resolution, n); - swapl(&i2->min_value, n); - swapl(&i2->max_value, n); - } - *buf += sizeof(xIntegerFeedbackState); -} - -/*********************************************************************** - * - * This procedure copies StringFeedbackClass data, swapping if necessary. - * - */ - -static void -CopySwapStringFeedback(ClientPtr client, StringFeedbackPtr s, char **buf) -{ - int i; - char n; - xStringFeedbackState *s2; - KeySym *kptr; - - s2 = (xStringFeedbackState *) * buf; - s2->class = StringFeedbackClass; - s2->length = sizeof(xStringFeedbackState) + - s->ctrl.num_symbols_supported * sizeof(KeySym); - s2->id = s->ctrl.id; - s2->max_symbols = s->ctrl.max_symbols; - s2->num_syms_supported = s->ctrl.num_symbols_supported; - *buf += sizeof(xStringFeedbackState); - kptr = (KeySym *) (*buf); - for (i = 0; i < s->ctrl.num_symbols_supported; i++) - *kptr++ = *(s->ctrl.symbols_supported + i); - if (client->swapped) { - swaps(&s2->length, n); - swaps(&s2->max_symbols, n); - swaps(&s2->num_syms_supported, n); - kptr = (KeySym *) (*buf); - for (i = 0; i < s->ctrl.num_symbols_supported; i++, kptr++) { - swapl(kptr, n); - } - } - *buf += (s->ctrl.num_symbols_supported * sizeof(KeySym)); -} - -/*********************************************************************** - * - * This procedure copies LedFeedbackClass data, swapping if necessary. - * - */ - -static void -CopySwapLedFeedback(ClientPtr client, LedFeedbackPtr l, char **buf) -{ - char n; - xLedFeedbackState *l2; - - l2 = (xLedFeedbackState *) * buf; - l2->class = LedFeedbackClass; - l2->length = sizeof(xLedFeedbackState); - l2->id = l->ctrl.id; - l2->led_values = l->ctrl.led_values; - l2->led_mask = l->ctrl.led_mask; - if (client->swapped) { - swaps(&l2->length, n); - swapl(&l2->led_values, n); - swapl(&l2->led_mask, n); - } - *buf += sizeof(xLedFeedbackState); -} - -/*********************************************************************** - * - * This procedure copies BellFeedbackClass data, swapping if necessary. - * - */ - -static void -CopySwapBellFeedback(ClientPtr client, BellFeedbackPtr b, char **buf) -{ - char n; - xBellFeedbackState *b2; - - b2 = (xBellFeedbackState *) * buf; - b2->class = BellFeedbackClass; - b2->length = sizeof(xBellFeedbackState); - b2->id = b->ctrl.id; - b2->percent = b->ctrl.percent; - b2->pitch = b->ctrl.pitch; - b2->duration = b->ctrl.duration; - if (client->swapped) { - swaps(&b2->length, n); - swaps(&b2->pitch, n); - swaps(&b2->duration, n); - } - *buf += sizeof(xBellFeedbackState); -} - -/*********************************************************************** - * - * This procedure writes the reply for the xGetFeedbackControl function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXGetFeedbackControl(ClientPtr client, int size, - xGetFeedbackControlReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->num_feedbacks, n); - WriteToClient(client, size, (char *)rep); -} - -/*********************************************************************** - * - * Get the feedback control state. - * - */ - -int -ProcXGetFeedbackControl(ClientPtr client) -{ - int rc, total_length = 0; - char *buf, *savbuf; - DeviceIntPtr dev; - KbdFeedbackPtr k; - PtrFeedbackPtr p; - IntegerFeedbackPtr i; - StringFeedbackPtr s; - BellFeedbackPtr b; - LedFeedbackPtr l; - xGetFeedbackControlReply rep; - - REQUEST(xGetFeedbackControlReq); - REQUEST_SIZE_MATCH(xGetFeedbackControlReq); - - rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.repType = X_Reply; - rep.RepType = X_GetFeedbackControl; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.num_feedbacks = 0; - - for (k = dev->kbdfeed; k; k = k->next) { - rep.num_feedbacks++; - total_length += sizeof(xKbdFeedbackState); - } - for (p = dev->ptrfeed; p; p = p->next) { - rep.num_feedbacks++; - total_length += sizeof(xPtrFeedbackState); - } - for (s = dev->stringfeed; s; s = s->next) { - rep.num_feedbacks++; - total_length += sizeof(xStringFeedbackState) + - (s->ctrl.num_symbols_supported * sizeof(KeySym)); - } - for (i = dev->intfeed; i; i = i->next) { - rep.num_feedbacks++; - total_length += sizeof(xIntegerFeedbackState); - } - for (l = dev->leds; l; l = l->next) { - rep.num_feedbacks++; - total_length += sizeof(xLedFeedbackState); - } - for (b = dev->bell; b; b = b->next) { - rep.num_feedbacks++; - total_length += sizeof(xBellFeedbackState); - } - - if (total_length == 0) - return BadMatch; - - buf = (char *)xalloc(total_length); - if (!buf) - return BadAlloc; - savbuf = buf; - - for (k = dev->kbdfeed; k; k = k->next) - CopySwapKbdFeedback(client, k, &buf); - for (p = dev->ptrfeed; p; p = p->next) - CopySwapPtrFeedback(client, p, &buf); - for (s = dev->stringfeed; s; s = s->next) - CopySwapStringFeedback(client, s, &buf); - for (i = dev->intfeed; i; i = i->next) - CopySwapIntegerFeedback(client, i, &buf); - for (l = dev->leds; l; l = l->next) - CopySwapLedFeedback(client, l, &buf); - for (b = dev->bell; b; b = b->next) - CopySwapBellFeedback(client, b, &buf); - - rep.length = bytes_to_int32(total_length); - WriteReplyToClient(client, sizeof(xGetFeedbackControlReply), &rep); - WriteToClient(client, total_length, savbuf); - xfree(savbuf); - return Success; -} +/************************************************************ + +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. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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. + +********************************************************/ + +/******************************************************************** + * + * Get feedback control attributes for an extension device. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" /* DeviceIntPtr */ +#include +#include +#include "exglobals.h" + +#include "getfctl.h" + +/*********************************************************************** + * + * This procedure gets the control attributes for an extension device, + * for clients on machines with a different byte ordering than the server. + * + */ + +int +SProcXGetFeedbackControl(ClientPtr client) +{ + char n; + + REQUEST(xGetFeedbackControlReq); + swaps(&stuff->length, n); + return (ProcXGetFeedbackControl(client)); +} + +/*********************************************************************** + * + * This procedure copies KbdFeedbackClass data, swapping if necessary. + * + */ + +static void +CopySwapKbdFeedback(ClientPtr client, KbdFeedbackPtr k, char **buf) +{ + int i; + char n; + xKbdFeedbackState *k2; + + k2 = (xKbdFeedbackState *) * buf; + k2->class = KbdFeedbackClass; + k2->length = sizeof(xKbdFeedbackState); + k2->id = k->ctrl.id; + k2->click = k->ctrl.click; + k2->percent = k->ctrl.bell; + k2->pitch = k->ctrl.bell_pitch; + k2->duration = k->ctrl.bell_duration; + k2->led_mask = k->ctrl.leds; + k2->global_auto_repeat = k->ctrl.autoRepeat; + for (i = 0; i < 32; i++) + k2->auto_repeats[i] = k->ctrl.autoRepeats[i]; + if (client->swapped) { + swaps(&k2->length, n); + swaps(&k2->pitch, n); + swaps(&k2->duration, n); + swapl(&k2->led_mask, n); + swapl(&k2->led_values, n); + } + *buf += sizeof(xKbdFeedbackState); +} + +/*********************************************************************** + * + * This procedure copies PtrFeedbackClass data, swapping if necessary. + * + */ + +static void +CopySwapPtrFeedback(ClientPtr client, PtrFeedbackPtr p, char **buf) +{ + char n; + xPtrFeedbackState *p2; + + p2 = (xPtrFeedbackState *) * buf; + p2->class = PtrFeedbackClass; + p2->length = sizeof(xPtrFeedbackState); + p2->id = p->ctrl.id; + p2->accelNum = p->ctrl.num; + p2->accelDenom = p->ctrl.den; + p2->threshold = p->ctrl.threshold; + if (client->swapped) { + swaps(&p2->length, n); + swaps(&p2->accelNum, n); + swaps(&p2->accelDenom, n); + swaps(&p2->threshold, n); + } + *buf += sizeof(xPtrFeedbackState); +} + +/*********************************************************************** + * + * This procedure copies IntegerFeedbackClass data, swapping if necessary. + * + */ + +static void +CopySwapIntegerFeedback(ClientPtr client, IntegerFeedbackPtr i, char **buf) +{ + char n; + xIntegerFeedbackState *i2; + + i2 = (xIntegerFeedbackState *) * buf; + i2->class = IntegerFeedbackClass; + i2->length = sizeof(xIntegerFeedbackState); + i2->id = i->ctrl.id; + i2->resolution = i->ctrl.resolution; + i2->min_value = i->ctrl.min_value; + i2->max_value = i->ctrl.max_value; + if (client->swapped) { + swaps(&i2->length, n); + swapl(&i2->resolution, n); + swapl(&i2->min_value, n); + swapl(&i2->max_value, n); + } + *buf += sizeof(xIntegerFeedbackState); +} + +/*********************************************************************** + * + * This procedure copies StringFeedbackClass data, swapping if necessary. + * + */ + +static void +CopySwapStringFeedback(ClientPtr client, StringFeedbackPtr s, char **buf) +{ + int i; + char n; + xStringFeedbackState *s2; + KeySym *kptr; + + s2 = (xStringFeedbackState *) * buf; + s2->class = StringFeedbackClass; + s2->length = sizeof(xStringFeedbackState) + + s->ctrl.num_symbols_supported * sizeof(KeySym); + s2->id = s->ctrl.id; + s2->max_symbols = s->ctrl.max_symbols; + s2->num_syms_supported = s->ctrl.num_symbols_supported; + *buf += sizeof(xStringFeedbackState); + kptr = (KeySym *) (*buf); + for (i = 0; i < s->ctrl.num_symbols_supported; i++) + *kptr++ = *(s->ctrl.symbols_supported + i); + if (client->swapped) { + swaps(&s2->length, n); + swaps(&s2->max_symbols, n); + swaps(&s2->num_syms_supported, n); + kptr = (KeySym *) (*buf); + for (i = 0; i < s->ctrl.num_symbols_supported; i++, kptr++) { + swapl(kptr, n); + } + } + *buf += (s->ctrl.num_symbols_supported * sizeof(KeySym)); +} + +/*********************************************************************** + * + * This procedure copies LedFeedbackClass data, swapping if necessary. + * + */ + +static void +CopySwapLedFeedback(ClientPtr client, LedFeedbackPtr l, char **buf) +{ + char n; + xLedFeedbackState *l2; + + l2 = (xLedFeedbackState *) * buf; + l2->class = LedFeedbackClass; + l2->length = sizeof(xLedFeedbackState); + l2->id = l->ctrl.id; + l2->led_values = l->ctrl.led_values; + l2->led_mask = l->ctrl.led_mask; + if (client->swapped) { + swaps(&l2->length, n); + swapl(&l2->led_values, n); + swapl(&l2->led_mask, n); + } + *buf += sizeof(xLedFeedbackState); +} + +/*********************************************************************** + * + * This procedure copies BellFeedbackClass data, swapping if necessary. + * + */ + +static void +CopySwapBellFeedback(ClientPtr client, BellFeedbackPtr b, char **buf) +{ + char n; + xBellFeedbackState *b2; + + b2 = (xBellFeedbackState *) * buf; + b2->class = BellFeedbackClass; + b2->length = sizeof(xBellFeedbackState); + b2->id = b->ctrl.id; + b2->percent = b->ctrl.percent; + b2->pitch = b->ctrl.pitch; + b2->duration = b->ctrl.duration; + if (client->swapped) { + swaps(&b2->length, n); + swaps(&b2->pitch, n); + swaps(&b2->duration, n); + } + *buf += sizeof(xBellFeedbackState); +} + +/*********************************************************************** + * + * This procedure writes the reply for the xGetFeedbackControl function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXGetFeedbackControl(ClientPtr client, int size, + xGetFeedbackControlReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->num_feedbacks, n); + WriteToClient(client, size, (char *)rep); +} + +/*********************************************************************** + * + * Get the feedback control state. + * + */ + +int +ProcXGetFeedbackControl(ClientPtr client) +{ + int rc, total_length = 0; + char *buf, *savbuf; + DeviceIntPtr dev; + KbdFeedbackPtr k; + PtrFeedbackPtr p; + IntegerFeedbackPtr i; + StringFeedbackPtr s; + BellFeedbackPtr b; + LedFeedbackPtr l; + xGetFeedbackControlReply rep; + + REQUEST(xGetFeedbackControlReq); + REQUEST_SIZE_MATCH(xGetFeedbackControlReq); + + rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.repType = X_Reply; + rep.RepType = X_GetFeedbackControl; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.num_feedbacks = 0; + + for (k = dev->kbdfeed; k; k = k->next) { + rep.num_feedbacks++; + total_length += sizeof(xKbdFeedbackState); + } + for (p = dev->ptrfeed; p; p = p->next) { + rep.num_feedbacks++; + total_length += sizeof(xPtrFeedbackState); + } + for (s = dev->stringfeed; s; s = s->next) { + rep.num_feedbacks++; + total_length += sizeof(xStringFeedbackState) + + (s->ctrl.num_symbols_supported * sizeof(KeySym)); + } + for (i = dev->intfeed; i; i = i->next) { + rep.num_feedbacks++; + total_length += sizeof(xIntegerFeedbackState); + } + for (l = dev->leds; l; l = l->next) { + rep.num_feedbacks++; + total_length += sizeof(xLedFeedbackState); + } + for (b = dev->bell; b; b = b->next) { + rep.num_feedbacks++; + total_length += sizeof(xBellFeedbackState); + } + + if (total_length == 0) + return BadMatch; + + buf = (char *)malloc(total_length); + if (!buf) + return BadAlloc; + savbuf = buf; + + for (k = dev->kbdfeed; k; k = k->next) + CopySwapKbdFeedback(client, k, &buf); + for (p = dev->ptrfeed; p; p = p->next) + CopySwapPtrFeedback(client, p, &buf); + for (s = dev->stringfeed; s; s = s->next) + CopySwapStringFeedback(client, s, &buf); + for (i = dev->intfeed; i; i = i->next) + CopySwapIntegerFeedback(client, i, &buf); + for (l = dev->leds; l; l = l->next) + CopySwapLedFeedback(client, l, &buf); + for (b = dev->bell; b; b = b->next) + CopySwapBellFeedback(client, b, &buf); + + rep.length = bytes_to_int32(total_length); + WriteReplyToClient(client, sizeof(xGetFeedbackControlReply), &rep); + WriteToClient(client, total_length, savbuf); + free(savbuf); + return Success; +} diff --git a/xorg-server/Xi/getkmap.c b/xorg-server/Xi/getkmap.c index 78449e212..6672ed32c 100644 --- a/xorg-server/Xi/getkmap.c +++ b/xorg-server/Xi/getkmap.c @@ -1,158 +1,158 @@ -/************************************************************ - -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. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - 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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-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. - -********************************************************/ - -/******************************************************************** - * - * Get the key mapping for an extension device. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" /* DeviceIntPtr */ -#include -#include -#include "exglobals.h" -#include "swaprep.h" -#include "xkbsrv.h" -#include "xkbstr.h" - -#include "getkmap.h" - -/*********************************************************************** - * - * This procedure gets the key mapping for an extension device, - * for clients on machines with a different byte ordering than the server. - * - */ - -int -SProcXGetDeviceKeyMapping(ClientPtr client) -{ - char n; - - REQUEST(xGetDeviceKeyMappingReq); - swaps(&stuff->length, n); - return (ProcXGetDeviceKeyMapping(client)); -} - -/*********************************************************************** - * - * Get the device key mapping. - * - */ - -int -ProcXGetDeviceKeyMapping(ClientPtr client) -{ - xGetDeviceKeyMappingReply rep; - DeviceIntPtr dev; - XkbDescPtr xkb; - KeySymsPtr syms; - int rc; - - REQUEST(xGetDeviceKeyMappingReq); - REQUEST_SIZE_MATCH(xGetDeviceKeyMappingReq); - - rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); - if (rc != Success) - return rc; - if (dev->key == NULL) - return BadMatch; - xkb = dev->key->xkbInfo->desc; - - if (stuff->firstKeyCode < xkb->min_key_code || - stuff->firstKeyCode > xkb->max_key_code) { - client->errorValue = stuff->firstKeyCode; - return BadValue; - } - - if (stuff->firstKeyCode + stuff->count > xkb->max_key_code + 1) { - client->errorValue = stuff->count; - return BadValue; - } - - syms = XkbGetCoreMap(dev); - if (!syms) - return BadAlloc; - - rep.repType = X_Reply; - rep.RepType = X_GetDeviceKeyMapping; - rep.sequenceNumber = client->sequence; - rep.keySymsPerKeyCode = syms->mapWidth; - rep.length = (syms->mapWidth * stuff->count); /* KeySyms are 4 bytes */ - WriteReplyToClient(client, sizeof(xGetDeviceKeyMappingReply), &rep); - - client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; - WriteSwappedDataToClient(client, - syms->mapWidth * stuff->count * sizeof(KeySym), - &syms->map[syms->mapWidth * (stuff->firstKeyCode - - syms->minKeyCode)]); - xfree(syms->map); - xfree(syms); - - return Success; -} - -/*********************************************************************** - * - * This procedure writes the reply for the XGetDeviceKeyMapping function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXGetDeviceKeyMapping(ClientPtr client, int size, - xGetDeviceKeyMappingReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - WriteToClient(client, size, (char *)rep); -} +/************************************************************ + +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. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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. + +********************************************************/ + +/******************************************************************** + * + * Get the key mapping for an extension device. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" /* DeviceIntPtr */ +#include +#include +#include "exglobals.h" +#include "swaprep.h" +#include "xkbsrv.h" +#include "xkbstr.h" + +#include "getkmap.h" + +/*********************************************************************** + * + * This procedure gets the key mapping for an extension device, + * for clients on machines with a different byte ordering than the server. + * + */ + +int +SProcXGetDeviceKeyMapping(ClientPtr client) +{ + char n; + + REQUEST(xGetDeviceKeyMappingReq); + swaps(&stuff->length, n); + return (ProcXGetDeviceKeyMapping(client)); +} + +/*********************************************************************** + * + * Get the device key mapping. + * + */ + +int +ProcXGetDeviceKeyMapping(ClientPtr client) +{ + xGetDeviceKeyMappingReply rep; + DeviceIntPtr dev; + XkbDescPtr xkb; + KeySymsPtr syms; + int rc; + + REQUEST(xGetDeviceKeyMappingReq); + REQUEST_SIZE_MATCH(xGetDeviceKeyMappingReq); + + rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); + if (rc != Success) + return rc; + if (dev->key == NULL) + return BadMatch; + xkb = dev->key->xkbInfo->desc; + + if (stuff->firstKeyCode < xkb->min_key_code || + stuff->firstKeyCode > xkb->max_key_code) { + client->errorValue = stuff->firstKeyCode; + return BadValue; + } + + if (stuff->firstKeyCode + stuff->count > xkb->max_key_code + 1) { + client->errorValue = stuff->count; + return BadValue; + } + + syms = XkbGetCoreMap(dev); + if (!syms) + return BadAlloc; + + rep.repType = X_Reply; + rep.RepType = X_GetDeviceKeyMapping; + rep.sequenceNumber = client->sequence; + rep.keySymsPerKeyCode = syms->mapWidth; + rep.length = (syms->mapWidth * stuff->count); /* KeySyms are 4 bytes */ + WriteReplyToClient(client, sizeof(xGetDeviceKeyMappingReply), &rep); + + client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; + WriteSwappedDataToClient(client, + syms->mapWidth * stuff->count * sizeof(KeySym), + &syms->map[syms->mapWidth * (stuff->firstKeyCode - + syms->minKeyCode)]); + free(syms->map); + free(syms); + + return Success; +} + +/*********************************************************************** + * + * This procedure writes the reply for the XGetDeviceKeyMapping function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXGetDeviceKeyMapping(ClientPtr client, int size, + xGetDeviceKeyMappingReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + WriteToClient(client, size, (char *)rep); +} diff --git a/xorg-server/Xi/getmmap.c b/xorg-server/Xi/getmmap.c index ddf27a5f0..96e9643fc 100644 --- a/xorg-server/Xi/getmmap.c +++ b/xorg-server/Xi/getmmap.c @@ -1,137 +1,137 @@ -/************************************************************ - -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. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - 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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-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. - -********************************************************/ - -/******************************************************************** - * - * Get the modifier mapping for an extension device. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" /* DeviceIntPtr */ -#include -#include /* Request macro */ -#include "exglobals.h" - -#include "getmmap.h" - -/*********************************************************************** - * - * This procedure gets the modifier mapping for an extension device, - * for clients on machines with a different byte ordering than the server. - * - */ - -int -SProcXGetDeviceModifierMapping(ClientPtr client) -{ - char n; - - REQUEST(xGetDeviceModifierMappingReq); - swaps(&stuff->length, n); - return (ProcXGetDeviceModifierMapping(client)); -} - -/*********************************************************************** - * - * Get the device Modifier mapping. - * - */ - -int -ProcXGetDeviceModifierMapping(ClientPtr client) -{ - DeviceIntPtr dev; - xGetDeviceModifierMappingReply rep; - KeyCode *modkeymap = NULL; - int ret, max_keys_per_mod; - - REQUEST(xGetDeviceModifierMappingReq); - REQUEST_SIZE_MATCH(xGetDeviceModifierMappingReq); - - ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); - if (ret != Success) - return ret; - - ret = generate_modkeymap(client, dev, &modkeymap, &max_keys_per_mod); - if (ret != Success) - return ret; - - rep.repType = X_Reply; - rep.RepType = X_GetDeviceModifierMapping; - rep.numKeyPerModifier = max_keys_per_mod; - rep.sequenceNumber = client->sequence; - /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */ - rep.length = max_keys_per_mod << 1; - - WriteReplyToClient(client, sizeof(xGetDeviceModifierMappingReply), &rep); - WriteToClient(client, max_keys_per_mod * 8, (char *) modkeymap); - - xfree(modkeymap); - - return Success; -} - -/*********************************************************************** - * - * This procedure writes the reply for the XGetDeviceModifierMapping function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXGetDeviceModifierMapping(ClientPtr client, int size, - xGetDeviceModifierMappingReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - WriteToClient(client, size, (char *)rep); -} +/************************************************************ + +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. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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. + +********************************************************/ + +/******************************************************************** + * + * Get the modifier mapping for an extension device. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" /* DeviceIntPtr */ +#include +#include /* Request macro */ +#include "exglobals.h" + +#include "getmmap.h" + +/*********************************************************************** + * + * This procedure gets the modifier mapping for an extension device, + * for clients on machines with a different byte ordering than the server. + * + */ + +int +SProcXGetDeviceModifierMapping(ClientPtr client) +{ + char n; + + REQUEST(xGetDeviceModifierMappingReq); + swaps(&stuff->length, n); + return (ProcXGetDeviceModifierMapping(client)); +} + +/*********************************************************************** + * + * Get the device Modifier mapping. + * + */ + +int +ProcXGetDeviceModifierMapping(ClientPtr client) +{ + DeviceIntPtr dev; + xGetDeviceModifierMappingReply rep; + KeyCode *modkeymap = NULL; + int ret, max_keys_per_mod; + + REQUEST(xGetDeviceModifierMappingReq); + REQUEST_SIZE_MATCH(xGetDeviceModifierMappingReq); + + ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); + if (ret != Success) + return ret; + + ret = generate_modkeymap(client, dev, &modkeymap, &max_keys_per_mod); + if (ret != Success) + return ret; + + rep.repType = X_Reply; + rep.RepType = X_GetDeviceModifierMapping; + rep.numKeyPerModifier = max_keys_per_mod; + rep.sequenceNumber = client->sequence; + /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */ + rep.length = max_keys_per_mod << 1; + + WriteReplyToClient(client, sizeof(xGetDeviceModifierMappingReply), &rep); + WriteToClient(client, max_keys_per_mod * 8, (char *) modkeymap); + + free(modkeymap); + + return Success; +} + +/*********************************************************************** + * + * This procedure writes the reply for the XGetDeviceModifierMapping function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXGetDeviceModifierMapping(ClientPtr client, int size, + xGetDeviceModifierMappingReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + WriteToClient(client, size, (char *)rep); +} diff --git a/xorg-server/Xi/getprop.c b/xorg-server/Xi/getprop.c index 1f28a8a40..8f2d792be 100644 --- a/xorg-server/Xi/getprop.c +++ b/xorg-server/Xi/getprop.c @@ -1,187 +1,187 @@ -/************************************************************ - -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. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - 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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-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. - -********************************************************/ - -/*********************************************************************** - * - * Function to return the dont-propagate-list for an extension device. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" /* DeviceIntPtr */ -#include "windowstr.h" /* window structs */ -#include -#include -#include "exglobals.h" -#include "swaprep.h" - -#include "getprop.h" - -extern XExtEventInfo EventInfo[]; -extern int ExtEventIndex; - -/*********************************************************************** - * - * Handle a request from a client with a different byte order. - * - */ - -int -SProcXGetDeviceDontPropagateList(ClientPtr client) -{ - char n; - - REQUEST(xGetDeviceDontPropagateListReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xGetDeviceDontPropagateListReq); - swapl(&stuff->window, n); - return (ProcXGetDeviceDontPropagateList(client)); -} - -/*********************************************************************** - * - * This procedure lists the input devices available to the server. - * - */ - -int -ProcXGetDeviceDontPropagateList(ClientPtr client) -{ - CARD16 count = 0; - int i, rc; - XEventClass *buf = NULL, *tbuf; - WindowPtr pWin; - xGetDeviceDontPropagateListReply rep; - OtherInputMasks *others; - - REQUEST(xGetDeviceDontPropagateListReq); - REQUEST_SIZE_MATCH(xGetDeviceDontPropagateListReq); - - rep.repType = X_Reply; - rep.RepType = X_GetDeviceDontPropagateList; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.count = 0; - - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - if ((others = wOtherInputMasks(pWin)) != 0) { - for (i = 0; i < EMASKSIZE; i++) - tbuf = ClassFromMask(NULL, others->dontPropagateMask[i], i, - &count, COUNT); - if (count) { - rep.count = count; - buf = (XEventClass *) xalloc(rep.count * sizeof(XEventClass)); - rep.length = bytes_to_int32(rep.count * sizeof(XEventClass)); - - tbuf = buf; - for (i = 0; i < EMASKSIZE; i++) - tbuf = ClassFromMask(tbuf, others->dontPropagateMask[i], i, - NULL, CREATE); - } - } - - WriteReplyToClient(client, sizeof(xGetDeviceDontPropagateListReply), &rep); - - if (count) { - client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; - WriteSwappedDataToClient(client, count * sizeof(XEventClass), buf); - xfree(buf); - } - return Success; -} - -/*********************************************************************** - * - * This procedure gets a list of event classes from a mask word. - * A single mask may translate to more than one event class. - * - */ - -XEventClass - * ClassFromMask(XEventClass * buf, Mask mask, int maskndx, CARD16 * count, - int mode) -{ - int i, j; - int id = maskndx; - Mask tmask = 0x80000000; - - for (i = 0; i < 32; i++, tmask >>= 1) - if (tmask & mask) { - for (j = 0; j < ExtEventIndex; j++) - if (EventInfo[j].mask == tmask) { - if (mode == COUNT) - (*count)++; - else - *buf++ = (id << 8) | EventInfo[j].type; - } - } - return (buf); -} - -/*********************************************************************** - * - * This procedure writes the reply for the XGetDeviceDontPropagateList function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXGetDeviceDontPropagateList(ClientPtr client, int size, - xGetDeviceDontPropagateListReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->count, n); - WriteToClient(client, size, (char *)rep); -} +/************************************************************ + +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. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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. + +********************************************************/ + +/*********************************************************************** + * + * Function to return the dont-propagate-list for an extension device. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window structs */ +#include +#include +#include "exglobals.h" +#include "swaprep.h" + +#include "getprop.h" + +extern XExtEventInfo EventInfo[]; +extern int ExtEventIndex; + +/*********************************************************************** + * + * Handle a request from a client with a different byte order. + * + */ + +int +SProcXGetDeviceDontPropagateList(ClientPtr client) +{ + char n; + + REQUEST(xGetDeviceDontPropagateListReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xGetDeviceDontPropagateListReq); + swapl(&stuff->window, n); + return (ProcXGetDeviceDontPropagateList(client)); +} + +/*********************************************************************** + * + * This procedure lists the input devices available to the server. + * + */ + +int +ProcXGetDeviceDontPropagateList(ClientPtr client) +{ + CARD16 count = 0; + int i, rc; + XEventClass *buf = NULL, *tbuf; + WindowPtr pWin; + xGetDeviceDontPropagateListReply rep; + OtherInputMasks *others; + + REQUEST(xGetDeviceDontPropagateListReq); + REQUEST_SIZE_MATCH(xGetDeviceDontPropagateListReq); + + rep.repType = X_Reply; + rep.RepType = X_GetDeviceDontPropagateList; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.count = 0; + + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + if ((others = wOtherInputMasks(pWin)) != 0) { + for (i = 0; i < EMASKSIZE; i++) + tbuf = ClassFromMask(NULL, others->dontPropagateMask[i], i, + &count, COUNT); + if (count) { + rep.count = count; + buf = (XEventClass *) malloc(rep.count * sizeof(XEventClass)); + rep.length = bytes_to_int32(rep.count * sizeof(XEventClass)); + + tbuf = buf; + for (i = 0; i < EMASKSIZE; i++) + tbuf = ClassFromMask(tbuf, others->dontPropagateMask[i], i, + NULL, CREATE); + } + } + + WriteReplyToClient(client, sizeof(xGetDeviceDontPropagateListReply), &rep); + + if (count) { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, count * sizeof(XEventClass), buf); + free(buf); + } + return Success; +} + +/*********************************************************************** + * + * This procedure gets a list of event classes from a mask word. + * A single mask may translate to more than one event class. + * + */ + +XEventClass + * ClassFromMask(XEventClass * buf, Mask mask, int maskndx, CARD16 * count, + int mode) +{ + int i, j; + int id = maskndx; + Mask tmask = 0x80000000; + + for (i = 0; i < 32; i++, tmask >>= 1) + if (tmask & mask) { + for (j = 0; j < ExtEventIndex; j++) + if (EventInfo[j].mask == tmask) { + if (mode == COUNT) + (*count)++; + else + *buf++ = (id << 8) | EventInfo[j].type; + } + } + return (buf); +} + +/*********************************************************************** + * + * This procedure writes the reply for the XGetDeviceDontPropagateList function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXGetDeviceDontPropagateList(ClientPtr client, int size, + xGetDeviceDontPropagateListReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->count, n); + WriteToClient(client, size, (char *)rep); +} diff --git a/xorg-server/Xi/getselev.c b/xorg-server/Xi/getselev.c index 90f6284e5..3b556000c 100644 --- a/xorg-server/Xi/getselev.c +++ b/xorg-server/Xi/getselev.c @@ -1,178 +1,178 @@ -/************************************************************ - -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. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - 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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-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. - -********************************************************/ - -/*********************************************************************** - * - * Extension function to get the current selected events for a given window. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include "inputstr.h" /* DeviceIntPtr */ -#include "windowstr.h" /* window struct */ -#include "exglobals.h" -#include "swaprep.h" - -#include "getprop.h" -#include "getselev.h" - -/*********************************************************************** - * - * This procedure gets the current selected extension events. - * - */ - -int -SProcXGetSelectedExtensionEvents(ClientPtr client) -{ - char n; - - REQUEST(xGetSelectedExtensionEventsReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xGetSelectedExtensionEventsReq); - swapl(&stuff->window, n); - return (ProcXGetSelectedExtensionEvents(client)); -} - -/*********************************************************************** - * - * This procedure gets the current device select mask, - * if the client and server have a different byte ordering. - * - */ - -int -ProcXGetSelectedExtensionEvents(ClientPtr client) -{ - int i, rc, total_length = 0; - xGetSelectedExtensionEventsReply rep; - WindowPtr pWin; - XEventClass *buf = NULL; - XEventClass *tclient; - XEventClass *aclient; - OtherInputMasks *pOthers; - InputClientsPtr others; - - REQUEST(xGetSelectedExtensionEventsReq); - REQUEST_SIZE_MATCH(xGetSelectedExtensionEventsReq); - - rep.repType = X_Reply; - rep.RepType = X_GetSelectedExtensionEvents; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.this_client_count = 0; - rep.all_clients_count = 0; - - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - if ((pOthers = wOtherInputMasks(pWin)) != 0) { - for (others = pOthers->inputClients; others; others = others->next) - for (i = 0; i < EMASKSIZE; i++) - tclient = ClassFromMask(NULL, others->mask[i], i, - &rep.all_clients_count, COUNT); - - for (others = pOthers->inputClients; others; others = others->next) - if (SameClient(others, client)) { - for (i = 0; i < EMASKSIZE; i++) - tclient = ClassFromMask(NULL, others->mask[i], i, - &rep.this_client_count, COUNT); - break; - } - - total_length = (rep.all_clients_count + rep.this_client_count) * - sizeof(XEventClass); - rep.length = bytes_to_int32(total_length); - buf = (XEventClass *) xalloc(total_length); - - tclient = buf; - aclient = buf + rep.this_client_count; - if (others) - for (i = 0; i < EMASKSIZE; i++) - tclient = - ClassFromMask(tclient, others->mask[i], i, NULL, CREATE); - - for (others = pOthers->inputClients; others; others = others->next) - for (i = 0; i < EMASKSIZE; i++) - aclient = - ClassFromMask(aclient, others->mask[i], i, NULL, CREATE); - } - - WriteReplyToClient(client, sizeof(xGetSelectedExtensionEventsReply), &rep); - - if (total_length) { - client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; - WriteSwappedDataToClient(client, total_length, buf); - xfree(buf); - } - return Success; -} - -/*********************************************************************** - * - * This procedure writes the reply for the XGetSelectedExtensionEvents function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXGetSelectedExtensionEvents(ClientPtr client, int size, - xGetSelectedExtensionEventsReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->this_client_count, n); - swaps(&rep->all_clients_count, n); - WriteToClient(client, size, (char *)rep); -} +/************************************************************ + +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. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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. + +********************************************************/ + +/*********************************************************************** + * + * Extension function to get the current selected events for a given window. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window struct */ +#include "exglobals.h" +#include "swaprep.h" + +#include "getprop.h" +#include "getselev.h" + +/*********************************************************************** + * + * This procedure gets the current selected extension events. + * + */ + +int +SProcXGetSelectedExtensionEvents(ClientPtr client) +{ + char n; + + REQUEST(xGetSelectedExtensionEventsReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xGetSelectedExtensionEventsReq); + swapl(&stuff->window, n); + return (ProcXGetSelectedExtensionEvents(client)); +} + +/*********************************************************************** + * + * This procedure gets the current device select mask, + * if the client and server have a different byte ordering. + * + */ + +int +ProcXGetSelectedExtensionEvents(ClientPtr client) +{ + int i, rc, total_length = 0; + xGetSelectedExtensionEventsReply rep; + WindowPtr pWin; + XEventClass *buf = NULL; + XEventClass *tclient; + XEventClass *aclient; + OtherInputMasks *pOthers; + InputClientsPtr others; + + REQUEST(xGetSelectedExtensionEventsReq); + REQUEST_SIZE_MATCH(xGetSelectedExtensionEventsReq); + + rep.repType = X_Reply; + rep.RepType = X_GetSelectedExtensionEvents; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.this_client_count = 0; + rep.all_clients_count = 0; + + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + if ((pOthers = wOtherInputMasks(pWin)) != 0) { + for (others = pOthers->inputClients; others; others = others->next) + for (i = 0; i < EMASKSIZE; i++) + tclient = ClassFromMask(NULL, others->mask[i], i, + &rep.all_clients_count, COUNT); + + for (others = pOthers->inputClients; others; others = others->next) + if (SameClient(others, client)) { + for (i = 0; i < EMASKSIZE; i++) + tclient = ClassFromMask(NULL, others->mask[i], i, + &rep.this_client_count, COUNT); + break; + } + + total_length = (rep.all_clients_count + rep.this_client_count) * + sizeof(XEventClass); + rep.length = bytes_to_int32(total_length); + buf = (XEventClass *) malloc(total_length); + + tclient = buf; + aclient = buf + rep.this_client_count; + if (others) + for (i = 0; i < EMASKSIZE; i++) + tclient = + ClassFromMask(tclient, others->mask[i], i, NULL, CREATE); + + for (others = pOthers->inputClients; others; others = others->next) + for (i = 0; i < EMASKSIZE; i++) + aclient = + ClassFromMask(aclient, others->mask[i], i, NULL, CREATE); + } + + WriteReplyToClient(client, sizeof(xGetSelectedExtensionEventsReply), &rep); + + if (total_length) { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, total_length, buf); + free(buf); + } + return Success; +} + +/*********************************************************************** + * + * This procedure writes the reply for the XGetSelectedExtensionEvents function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXGetSelectedExtensionEvents(ClientPtr client, int size, + xGetSelectedExtensionEventsReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->this_client_count, n); + swaps(&rep->all_clients_count, n); + WriteToClient(client, size, (char *)rep); +} diff --git a/xorg-server/Xi/gtmotion.c b/xorg-server/Xi/gtmotion.c index 8e91c5a47..930e08c8c 100644 --- a/xorg-server/Xi/gtmotion.c +++ b/xorg-server/Xi/gtmotion.c @@ -1,178 +1,178 @@ -/************************************************************ - -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. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - 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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-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. - -********************************************************/ - -/*********************************************************************** - * - * Request to get the motion history from an extension device. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" /* DeviceIntPtr */ -#include -#include -#include "exevents.h" -#include "exglobals.h" - -#include "gtmotion.h" - -/*********************************************************************** - * - * Swap the request if server and client have different byte ordering. - * - */ - -int -SProcXGetDeviceMotionEvents(ClientPtr client) -{ - char n; - - REQUEST(xGetDeviceMotionEventsReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xGetDeviceMotionEventsReq); - swapl(&stuff->start, n); - swapl(&stuff->stop, n); - return (ProcXGetDeviceMotionEvents(client)); -} - -/**************************************************************************** - * - * Get the motion history for an extension pointer devices. - * - */ - -int -ProcXGetDeviceMotionEvents(ClientPtr client) -{ - INT32 *coords = NULL, *bufptr; - xGetDeviceMotionEventsReply rep; - unsigned long i; - int rc, num_events, axes, size = 0; - unsigned long nEvents; - DeviceIntPtr dev; - TimeStamp start, stop; - int length = 0; - ValuatorClassPtr v; - - REQUEST(xGetDeviceMotionEventsReq); - - REQUEST_SIZE_MATCH(xGetDeviceMotionEventsReq); - rc = dixLookupDevice(&dev, stuff->deviceid, client, DixReadAccess); - if (rc != Success) - return rc; - v = dev->valuator; - if (v == NULL || v->numAxes == 0) - return BadMatch; - if (dev->valuator->motionHintWindow) - MaybeStopDeviceHint(dev, client); - axes = v->numAxes; - rep.repType = X_Reply; - rep.RepType = X_GetDeviceMotionEvents; - rep.sequenceNumber = client->sequence; - rep.nEvents = 0; - rep.axes = axes; - rep.mode = Absolute; /* XXX we don't do relative at the moment */ - rep.length = 0; - start = ClientTimeToServerTime(stuff->start); - stop = ClientTimeToServerTime(stuff->stop); - if (CompareTimeStamps(start, stop) == LATER || - CompareTimeStamps(start, currentTime) == LATER) { - WriteReplyToClient(client, sizeof(xGetDeviceMotionEventsReply), &rep); - return Success; - } - if (CompareTimeStamps(stop, currentTime) == LATER) - stop = currentTime; - num_events = v->numMotionEvents; - if (num_events) { - size = sizeof(Time) + (axes * sizeof(INT32)); - rep.nEvents = GetMotionHistory(dev, (xTimecoord **) &coords,/* XXX */ - start.milliseconds, stop.milliseconds, - (ScreenPtr) NULL, FALSE); - } - if (rep.nEvents > 0) { - length = bytes_to_int32(rep.nEvents * size); - rep.length = length; - } - nEvents = rep.nEvents; - WriteReplyToClient(client, sizeof(xGetDeviceMotionEventsReply), &rep); - if (nEvents) { - if (client->swapped) { - char n; - - bufptr = coords; - for (i = 0; i < nEvents * (axes + 1); i++) { - swapl(bufptr, n); - bufptr++; - } - } - WriteToClient(client, length * 4, (char *)coords); - } - if (coords) - xfree(coords); - return Success; -} - -/*********************************************************************** - * - * This procedure writes the reply for the XGetDeviceMotionEvents function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXGetDeviceMotionEvents(ClientPtr client, int size, - xGetDeviceMotionEventsReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swapl(&rep->nEvents, n); - WriteToClient(client, size, (char *)rep); -} +/************************************************************ + +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. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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. + +********************************************************/ + +/*********************************************************************** + * + * Request to get the motion history from an extension device. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" /* DeviceIntPtr */ +#include +#include +#include "exevents.h" +#include "exglobals.h" + +#include "gtmotion.h" + +/*********************************************************************** + * + * Swap the request if server and client have different byte ordering. + * + */ + +int +SProcXGetDeviceMotionEvents(ClientPtr client) +{ + char n; + + REQUEST(xGetDeviceMotionEventsReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xGetDeviceMotionEventsReq); + swapl(&stuff->start, n); + swapl(&stuff->stop, n); + return (ProcXGetDeviceMotionEvents(client)); +} + +/**************************************************************************** + * + * Get the motion history for an extension pointer devices. + * + */ + +int +ProcXGetDeviceMotionEvents(ClientPtr client) +{ + INT32 *coords = NULL, *bufptr; + xGetDeviceMotionEventsReply rep; + unsigned long i; + int rc, num_events, axes, size = 0; + unsigned long nEvents; + DeviceIntPtr dev; + TimeStamp start, stop; + int length = 0; + ValuatorClassPtr v; + + REQUEST(xGetDeviceMotionEventsReq); + + REQUEST_SIZE_MATCH(xGetDeviceMotionEventsReq); + rc = dixLookupDevice(&dev, stuff->deviceid, client, DixReadAccess); + if (rc != Success) + return rc; + v = dev->valuator; + if (v == NULL || v->numAxes == 0) + return BadMatch; + if (dev->valuator->motionHintWindow) + MaybeStopDeviceHint(dev, client); + axes = v->numAxes; + rep.repType = X_Reply; + rep.RepType = X_GetDeviceMotionEvents; + rep.sequenceNumber = client->sequence; + rep.nEvents = 0; + rep.axes = axes; + rep.mode = Absolute; /* XXX we don't do relative at the moment */ + rep.length = 0; + start = ClientTimeToServerTime(stuff->start); + stop = ClientTimeToServerTime(stuff->stop); + if (CompareTimeStamps(start, stop) == LATER || + CompareTimeStamps(start, currentTime) == LATER) { + WriteReplyToClient(client, sizeof(xGetDeviceMotionEventsReply), &rep); + return Success; + } + if (CompareTimeStamps(stop, currentTime) == LATER) + stop = currentTime; + num_events = v->numMotionEvents; + if (num_events) { + size = sizeof(Time) + (axes * sizeof(INT32)); + rep.nEvents = GetMotionHistory(dev, (xTimecoord **) &coords,/* XXX */ + start.milliseconds, stop.milliseconds, + (ScreenPtr) NULL, FALSE); + } + if (rep.nEvents > 0) { + length = bytes_to_int32(rep.nEvents * size); + rep.length = length; + } + nEvents = rep.nEvents; + WriteReplyToClient(client, sizeof(xGetDeviceMotionEventsReply), &rep); + if (nEvents) { + if (client->swapped) { + char n; + + bufptr = coords; + for (i = 0; i < nEvents * (axes + 1); i++) { + swapl(bufptr, n); + bufptr++; + } + } + WriteToClient(client, length * 4, (char *)coords); + } + if (coords) + free(coords); + return Success; +} + +/*********************************************************************** + * + * This procedure writes the reply for the XGetDeviceMotionEvents function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXGetDeviceMotionEvents(ClientPtr client, int size, + xGetDeviceMotionEventsReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swapl(&rep->nEvents, n); + WriteToClient(client, size, (char *)rep); +} diff --git a/xorg-server/Xi/listdev.c b/xorg-server/Xi/listdev.c index 98ef7aa43..2015f9cdd 100644 --- a/xorg-server/Xi/listdev.c +++ b/xorg-server/Xi/listdev.c @@ -1,434 +1,434 @@ -/************************************************************ - -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. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - 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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-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. - -********************************************************/ - -/*********************************************************************** - * - * Extension function to list the available input devices. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include /* for inputstr.h */ -#include /* Request macro */ -#include "inputstr.h" /* DeviceIntPtr */ -#include -#include -#include "XIstubs.h" -#include "extnsionst.h" -#include "exevents.h" -#include "xace.h" -#include "xkbsrv.h" -#include "xkbstr.h" - -#include "listdev.h" - - -/*********************************************************************** - * - * This procedure lists the input devices available to the server. - * - */ - -int -SProcXListInputDevices(ClientPtr client) -{ - char n; - - REQUEST(xListInputDevicesReq); - swaps(&stuff->length, n); - return (ProcXListInputDevices(client)); -} - -/*********************************************************************** - * - * This procedure calculates the size of the information to be returned - * for an input device. - * - */ - -static void -SizeDeviceInfo(DeviceIntPtr d, int *namesize, int *size) -{ - int chunks; - - *namesize += 1; - if (d->name) - *namesize += strlen(d->name); - if (d->key != NULL) - *size += sizeof(xKeyInfo); - if (d->button != NULL) - *size += sizeof(xButtonInfo); - if (d->valuator != NULL) { - chunks = ((int)d->valuator->numAxes + 19) / VPC; - *size += (chunks * sizeof(xValuatorInfo) + - d->valuator->numAxes * sizeof(xAxisInfo)); - } -} - -/*********************************************************************** - * - * This procedure copies data to the DeviceInfo struct, swapping if necessary. - * - * We need the extra byte in the allocated buffer, because the trailing null - * hammers one extra byte, which is overwritten by the next name except for - * the last name copied. - * - */ - -static void -CopyDeviceName(char **namebuf, char *name) -{ - char *nameptr = (char *)*namebuf; - - if (name) { - *nameptr++ = strlen(name); - strcpy(nameptr, name); - *namebuf += (strlen(name) + 1); - } else { - *nameptr++ = 0; - *namebuf += 1; - } -} - -/*********************************************************************** - * - * This procedure copies ButtonClass information, swapping if necessary. - * - */ - -static void -CopySwapButtonClass(ClientPtr client, ButtonClassPtr b, char **buf) -{ - char n; - xButtonInfoPtr b2; - - b2 = (xButtonInfoPtr) * buf; - b2->class = ButtonClass; - b2->length = sizeof(xButtonInfo); - b2->num_buttons = b->numButtons; - if (client && client->swapped) { - swaps(&b2->num_buttons, n); /* macro - braces are required */ - } - *buf += sizeof(xButtonInfo); -} - -/*********************************************************************** - * - * This procedure copies data to the DeviceInfo struct, swapping if necessary. - * - */ - -static void -CopySwapDevice(ClientPtr client, DeviceIntPtr d, int num_classes, - char **buf) -{ - char n; - xDeviceInfoPtr dev; - - dev = (xDeviceInfoPtr) * buf; - - dev->id = d->id; - dev->type = d->xinput_type; - dev->num_classes = num_classes; - if (IsMaster(d) && IsKeyboardDevice(d)) - dev->use = IsXKeyboard; - else if (IsMaster(d) && IsPointerDevice(d)) - dev->use = IsXPointer; - else if (d->key && d->kbdfeed) - dev->use = IsXExtensionKeyboard; - else if (d->valuator && d->button) - dev->use = IsXExtensionPointer; - else - dev->use = IsXExtensionDevice; - - if (client->swapped) { - swapl(&dev->type, n); /* macro - braces are required */ - } - *buf += sizeof(xDeviceInfo); -} - -/*********************************************************************** - * - * This procedure copies KeyClass information, swapping if necessary. - * - */ - -static void -CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf) -{ - char n; - xKeyInfoPtr k2; - - k2 = (xKeyInfoPtr) * buf; - k2->class = KeyClass; - k2->length = sizeof(xKeyInfo); - k2->min_keycode = k->xkbInfo->desc->min_key_code; - k2->max_keycode = k->xkbInfo->desc->max_key_code; - k2->num_keys = k2->max_keycode - k2->min_keycode + 1; - if (client && client->swapped) { - swaps(&k2->num_keys, n); - } - *buf += sizeof(xKeyInfo); -} - -/*********************************************************************** - * - * This procedure copies ValuatorClass information, swapping if necessary. - * - * Devices may have up to 255 valuators. The length of a ValuatorClass is - * defined to be sizeof(ValuatorClassInfo) + num_axes * sizeof (xAxisInfo). - * The maximum length is therefore (8 + 255 * 12) = 3068. However, the - * length field is one byte. If a device has more than 20 valuators, we - * must therefore return multiple valuator classes to the client. - * - */ - -static int -CopySwapValuatorClass(ClientPtr client, ValuatorClassPtr v, char **buf) -{ - int i, j, axes, t_axes; - char n; - xValuatorInfoPtr v2; - AxisInfo *a; - xAxisInfoPtr a2; - - for (i = 0, axes = v->numAxes; i < ((v->numAxes + 19) / VPC); - i++, axes -= VPC) { - t_axes = axes < VPC ? axes : VPC; - if (t_axes < 0) - t_axes = v->numAxes % VPC; - v2 = (xValuatorInfoPtr) * buf; - v2->class = ValuatorClass; - v2->length = sizeof(xValuatorInfo) + t_axes * sizeof(xAxisInfo); - v2->num_axes = t_axes; - v2->mode = v->mode & DeviceMode; - v2->motion_buffer_size = v->numMotionEvents; - if (client && client->swapped) { - swapl(&v2->motion_buffer_size, n); - } - *buf += sizeof(xValuatorInfo); - a = v->axes + (VPC * i); - a2 = (xAxisInfoPtr) * buf; - for (j = 0; j < t_axes; j++) { - a2->min_value = a->min_value; - a2->max_value = a->max_value; - a2->resolution = a->resolution; - if (client && client->swapped) { - swapl(&a2->min_value, n); - swapl(&a2->max_value, n); - swapl(&a2->resolution, n); - } - a2++; - a++; - *buf += sizeof(xAxisInfo); - } - } - return (i); -} - -static void -CopySwapClasses(ClientPtr client, DeviceIntPtr dev, CARD8 *num_classes, - char** classbuf) -{ - if (dev->key != NULL) { - CopySwapKeyClass(client, dev->key, classbuf); - (*num_classes)++; - } - if (dev->button != NULL) { - CopySwapButtonClass(client, dev->button, classbuf); - (*num_classes)++; - } - if (dev->valuator != NULL) { - (*num_classes) += - CopySwapValuatorClass(client, dev->valuator, classbuf); - } -} - -/*********************************************************************** - * - * This procedure lists information to be returned for an input device. - * - */ - -static void -ListDeviceInfo(ClientPtr client, DeviceIntPtr d, xDeviceInfoPtr dev, - char **devbuf, char **classbuf, char **namebuf) -{ - CopyDeviceName(namebuf, d->name); - CopySwapDevice(client, d, 0, devbuf); - CopySwapClasses(client, d, &dev->num_classes, classbuf); -} - -/*********************************************************************** - * - * This procedure checks if a device should be left off the list. - * - */ - -static Bool -ShouldSkipDevice(ClientPtr client, DeviceIntPtr d) -{ - /* don't send master devices other than VCP/VCK */ - if (!IsMaster(d) || d == inputInfo.pointer || d == inputInfo.keyboard) - { - int rc = XaceHook(XACE_DEVICE_ACCESS, client, d, DixGetAttrAccess); - if (rc == Success) - return FALSE; - } - return TRUE; -} - - -/*********************************************************************** - * - * This procedure lists the input devices available to the server. - * - * If this request is called by a client that has not issued a - * GetExtensionVersion request with major/minor version set, we don't send the - * complete device list. Instead, we only send the VCP, the VCK and floating - * SDs. This resembles the setup found on XI 1.x machines. - */ - -int -ProcXListInputDevices(ClientPtr client) -{ - xListInputDevicesReply rep; - int numdevs = 0; - int namesize = 1; /* need 1 extra byte for strcpy */ - int i = 0, size = 0; - int total_length; - char *devbuf, *classbuf, *namebuf, *savbuf; - Bool *skip; - xDeviceInfo *dev; - DeviceIntPtr d; - - REQUEST_SIZE_MATCH(xListInputDevicesReq); - - memset(&rep, 0, sizeof(xListInputDevicesReply)); - rep.repType = X_Reply; - rep.RepType = X_ListInputDevices; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - - AddOtherInputDevices(); - - /* allocate space for saving skip value */ - skip = xcalloc(sizeof(Bool), inputInfo.numDevices); - if (!skip) - return BadAlloc; - - /* figure out which devices to skip */ - numdevs = 0; - for (d = inputInfo.devices; d; d = d->next, i++) { - skip[i] = ShouldSkipDevice(client, d); - if (skip[i]) - continue; - - SizeDeviceInfo(d, &namesize, &size); - numdevs++; - } - - for (d = inputInfo.off_devices; d; d = d->next, i++) { - skip[i] = ShouldSkipDevice(client, d); - if (skip[i]) - continue; - - SizeDeviceInfo(d, &namesize, &size); - numdevs++; - } - - /* allocate space for reply */ - total_length = numdevs * sizeof(xDeviceInfo) + size + namesize; - devbuf = (char *)xcalloc(1, total_length); - classbuf = devbuf + (numdevs * sizeof(xDeviceInfo)); - namebuf = classbuf + size; - savbuf = devbuf; - - /* fill in and send reply */ - i = 0; - dev = (xDeviceInfoPtr) devbuf; - for (d = inputInfo.devices; d; d = d->next, i++) { - if (skip[i]) - continue; - - ListDeviceInfo(client, d, dev++, &devbuf, &classbuf, &namebuf); - } - - for (d = inputInfo.off_devices; d; d = d->next, i++) { - if (skip[i]) - continue; - - ListDeviceInfo(client, d, dev++, &devbuf, &classbuf, &namebuf); - } - rep.ndevices = numdevs; - rep.length = bytes_to_int32(total_length); - WriteReplyToClient(client, sizeof(xListInputDevicesReply), &rep); - WriteToClient(client, total_length, savbuf); - xfree(savbuf); - xfree(skip); - return Success; -} - -/*********************************************************************** - * - * This procedure writes the reply for the XListInputDevices function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXListInputDevices(ClientPtr client, int size, xListInputDevicesReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - WriteToClient(client, size, (char *)rep); -} +/************************************************************ + +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. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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. + +********************************************************/ + +/*********************************************************************** + * + * Extension function to list the available input devices. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include /* for inputstr.h */ +#include /* Request macro */ +#include "inputstr.h" /* DeviceIntPtr */ +#include +#include +#include "XIstubs.h" +#include "extnsionst.h" +#include "exevents.h" +#include "xace.h" +#include "xkbsrv.h" +#include "xkbstr.h" + +#include "listdev.h" + + +/*********************************************************************** + * + * This procedure lists the input devices available to the server. + * + */ + +int +SProcXListInputDevices(ClientPtr client) +{ + char n; + + REQUEST(xListInputDevicesReq); + swaps(&stuff->length, n); + return (ProcXListInputDevices(client)); +} + +/*********************************************************************** + * + * This procedure calculates the size of the information to be returned + * for an input device. + * + */ + +static void +SizeDeviceInfo(DeviceIntPtr d, int *namesize, int *size) +{ + int chunks; + + *namesize += 1; + if (d->name) + *namesize += strlen(d->name); + if (d->key != NULL) + *size += sizeof(xKeyInfo); + if (d->button != NULL) + *size += sizeof(xButtonInfo); + if (d->valuator != NULL) { + chunks = ((int)d->valuator->numAxes + 19) / VPC; + *size += (chunks * sizeof(xValuatorInfo) + + d->valuator->numAxes * sizeof(xAxisInfo)); + } +} + +/*********************************************************************** + * + * This procedure copies data to the DeviceInfo struct, swapping if necessary. + * + * We need the extra byte in the allocated buffer, because the trailing null + * hammers one extra byte, which is overwritten by the next name except for + * the last name copied. + * + */ + +static void +CopyDeviceName(char **namebuf, char *name) +{ + char *nameptr = (char *)*namebuf; + + if (name) { + *nameptr++ = strlen(name); + strcpy(nameptr, name); + *namebuf += (strlen(name) + 1); + } else { + *nameptr++ = 0; + *namebuf += 1; + } +} + +/*********************************************************************** + * + * This procedure copies ButtonClass information, swapping if necessary. + * + */ + +static void +CopySwapButtonClass(ClientPtr client, ButtonClassPtr b, char **buf) +{ + char n; + xButtonInfoPtr b2; + + b2 = (xButtonInfoPtr) * buf; + b2->class = ButtonClass; + b2->length = sizeof(xButtonInfo); + b2->num_buttons = b->numButtons; + if (client && client->swapped) { + swaps(&b2->num_buttons, n); /* macro - braces are required */ + } + *buf += sizeof(xButtonInfo); +} + +/*********************************************************************** + * + * This procedure copies data to the DeviceInfo struct, swapping if necessary. + * + */ + +static void +CopySwapDevice(ClientPtr client, DeviceIntPtr d, int num_classes, + char **buf) +{ + char n; + xDeviceInfoPtr dev; + + dev = (xDeviceInfoPtr) * buf; + + dev->id = d->id; + dev->type = d->xinput_type; + dev->num_classes = num_classes; + if (IsMaster(d) && IsKeyboardDevice(d)) + dev->use = IsXKeyboard; + else if (IsMaster(d) && IsPointerDevice(d)) + dev->use = IsXPointer; + else if (d->key && d->kbdfeed) + dev->use = IsXExtensionKeyboard; + else if (d->valuator && d->button) + dev->use = IsXExtensionPointer; + else + dev->use = IsXExtensionDevice; + + if (client->swapped) { + swapl(&dev->type, n); /* macro - braces are required */ + } + *buf += sizeof(xDeviceInfo); +} + +/*********************************************************************** + * + * This procedure copies KeyClass information, swapping if necessary. + * + */ + +static void +CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf) +{ + char n; + xKeyInfoPtr k2; + + k2 = (xKeyInfoPtr) * buf; + k2->class = KeyClass; + k2->length = sizeof(xKeyInfo); + k2->min_keycode = k->xkbInfo->desc->min_key_code; + k2->max_keycode = k->xkbInfo->desc->max_key_code; + k2->num_keys = k2->max_keycode - k2->min_keycode + 1; + if (client && client->swapped) { + swaps(&k2->num_keys, n); + } + *buf += sizeof(xKeyInfo); +} + +/*********************************************************************** + * + * This procedure copies ValuatorClass information, swapping if necessary. + * + * Devices may have up to 255 valuators. The length of a ValuatorClass is + * defined to be sizeof(ValuatorClassInfo) + num_axes * sizeof (xAxisInfo). + * The maximum length is therefore (8 + 255 * 12) = 3068. However, the + * length field is one byte. If a device has more than 20 valuators, we + * must therefore return multiple valuator classes to the client. + * + */ + +static int +CopySwapValuatorClass(ClientPtr client, ValuatorClassPtr v, char **buf) +{ + int i, j, axes, t_axes; + char n; + xValuatorInfoPtr v2; + AxisInfo *a; + xAxisInfoPtr a2; + + for (i = 0, axes = v->numAxes; i < ((v->numAxes + 19) / VPC); + i++, axes -= VPC) { + t_axes = axes < VPC ? axes : VPC; + if (t_axes < 0) + t_axes = v->numAxes % VPC; + v2 = (xValuatorInfoPtr) * buf; + v2->class = ValuatorClass; + v2->length = sizeof(xValuatorInfo) + t_axes * sizeof(xAxisInfo); + v2->num_axes = t_axes; + v2->mode = v->mode & DeviceMode; + v2->motion_buffer_size = v->numMotionEvents; + if (client && client->swapped) { + swapl(&v2->motion_buffer_size, n); + } + *buf += sizeof(xValuatorInfo); + a = v->axes + (VPC * i); + a2 = (xAxisInfoPtr) * buf; + for (j = 0; j < t_axes; j++) { + a2->min_value = a->min_value; + a2->max_value = a->max_value; + a2->resolution = a->resolution; + if (client && client->swapped) { + swapl(&a2->min_value, n); + swapl(&a2->max_value, n); + swapl(&a2->resolution, n); + } + a2++; + a++; + *buf += sizeof(xAxisInfo); + } + } + return (i); +} + +static void +CopySwapClasses(ClientPtr client, DeviceIntPtr dev, CARD8 *num_classes, + char** classbuf) +{ + if (dev->key != NULL) { + CopySwapKeyClass(client, dev->key, classbuf); + (*num_classes)++; + } + if (dev->button != NULL) { + CopySwapButtonClass(client, dev->button, classbuf); + (*num_classes)++; + } + if (dev->valuator != NULL) { + (*num_classes) += + CopySwapValuatorClass(client, dev->valuator, classbuf); + } +} + +/*********************************************************************** + * + * This procedure lists information to be returned for an input device. + * + */ + +static void +ListDeviceInfo(ClientPtr client, DeviceIntPtr d, xDeviceInfoPtr dev, + char **devbuf, char **classbuf, char **namebuf) +{ + CopyDeviceName(namebuf, d->name); + CopySwapDevice(client, d, 0, devbuf); + CopySwapClasses(client, d, &dev->num_classes, classbuf); +} + +/*********************************************************************** + * + * This procedure checks if a device should be left off the list. + * + */ + +static Bool +ShouldSkipDevice(ClientPtr client, DeviceIntPtr d) +{ + /* don't send master devices other than VCP/VCK */ + if (!IsMaster(d) || d == inputInfo.pointer || d == inputInfo.keyboard) + { + int rc = XaceHook(XACE_DEVICE_ACCESS, client, d, DixGetAttrAccess); + if (rc == Success) + return FALSE; + } + return TRUE; +} + + +/*********************************************************************** + * + * This procedure lists the input devices available to the server. + * + * If this request is called by a client that has not issued a + * GetExtensionVersion request with major/minor version set, we don't send the + * complete device list. Instead, we only send the VCP, the VCK and floating + * SDs. This resembles the setup found on XI 1.x machines. + */ + +int +ProcXListInputDevices(ClientPtr client) +{ + xListInputDevicesReply rep; + int numdevs = 0; + int namesize = 1; /* need 1 extra byte for strcpy */ + int i = 0, size = 0; + int total_length; + char *devbuf, *classbuf, *namebuf, *savbuf; + Bool *skip; + xDeviceInfo *dev; + DeviceIntPtr d; + + REQUEST_SIZE_MATCH(xListInputDevicesReq); + + memset(&rep, 0, sizeof(xListInputDevicesReply)); + rep.repType = X_Reply; + rep.RepType = X_ListInputDevices; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + + AddOtherInputDevices(); + + /* allocate space for saving skip value */ + skip = calloc(sizeof(Bool), inputInfo.numDevices); + if (!skip) + return BadAlloc; + + /* figure out which devices to skip */ + numdevs = 0; + for (d = inputInfo.devices; d; d = d->next, i++) { + skip[i] = ShouldSkipDevice(client, d); + if (skip[i]) + continue; + + SizeDeviceInfo(d, &namesize, &size); + numdevs++; + } + + for (d = inputInfo.off_devices; d; d = d->next, i++) { + skip[i] = ShouldSkipDevice(client, d); + if (skip[i]) + continue; + + SizeDeviceInfo(d, &namesize, &size); + numdevs++; + } + + /* allocate space for reply */ + total_length = numdevs * sizeof(xDeviceInfo) + size + namesize; + devbuf = (char *)calloc(1, total_length); + classbuf = devbuf + (numdevs * sizeof(xDeviceInfo)); + namebuf = classbuf + size; + savbuf = devbuf; + + /* fill in and send reply */ + i = 0; + dev = (xDeviceInfoPtr) devbuf; + for (d = inputInfo.devices; d; d = d->next, i++) { + if (skip[i]) + continue; + + ListDeviceInfo(client, d, dev++, &devbuf, &classbuf, &namebuf); + } + + for (d = inputInfo.off_devices; d; d = d->next, i++) { + if (skip[i]) + continue; + + ListDeviceInfo(client, d, dev++, &devbuf, &classbuf, &namebuf); + } + rep.ndevices = numdevs; + rep.length = bytes_to_int32(total_length); + WriteReplyToClient(client, sizeof(xListInputDevicesReply), &rep); + WriteToClient(client, total_length, savbuf); + free(savbuf); + free(skip); + return Success; +} + +/*********************************************************************** + * + * This procedure writes the reply for the XListInputDevices function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXListInputDevices(ClientPtr client, int size, xListInputDevicesReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + WriteToClient(client, size, (char *)rep); +} diff --git a/xorg-server/Xi/queryst.c b/xorg-server/Xi/queryst.c index 78b97a769..15d44592e 100644 --- a/xorg-server/Xi/queryst.c +++ b/xorg-server/Xi/queryst.c @@ -1,191 +1,191 @@ -/* - -Copyright 1998, 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. - -*/ - -/*********************************************************************** - * - * Request to query the state of an extension input device. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" /* DeviceIntPtr */ -#include "windowstr.h" /* window structure */ -#include -#include -#include "exevents.h" -#include "exglobals.h" -#include "xkbsrv.h" -#include "xkbstr.h" - -#include "queryst.h" - -/*********************************************************************** - * - * This procedure allows a client to query the state of a device. - * - */ - -int -SProcXQueryDeviceState(ClientPtr client) -{ - char n; - - REQUEST(xQueryDeviceStateReq); - swaps(&stuff->length, n); - return (ProcXQueryDeviceState(client)); -} - -/*********************************************************************** - * - * This procedure allows frozen events to be routed. - * - */ - -int -ProcXQueryDeviceState(ClientPtr client) -{ - char n; - int rc, i; - int num_classes = 0; - int total_length = 0; - char *buf, *savbuf; - KeyClassPtr k; - xKeyState *tk; - ButtonClassPtr b; - xButtonState *tb; - ValuatorClassPtr v; - xValuatorState *tv; - xQueryDeviceStateReply rep; - DeviceIntPtr dev; - double *values; - - REQUEST(xQueryDeviceStateReq); - REQUEST_SIZE_MATCH(xQueryDeviceStateReq); - - rep.repType = X_Reply; - rep.RepType = X_QueryDeviceState; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = dixLookupDevice(&dev, stuff->deviceid, client, DixReadAccess); - if (rc != Success && rc != BadAccess) - return rc; - - v = dev->valuator; - if (v != NULL && v->motionHintWindow != NULL) - MaybeStopDeviceHint(dev, client); - - k = dev->key; - if (k != NULL) { - total_length += sizeof(xKeyState); - num_classes++; - } - - b = dev->button; - if (b != NULL) { - total_length += sizeof(xButtonState); - num_classes++; - } - - if (v != NULL) { - total_length += (sizeof(xValuatorState) + (v->numAxes * sizeof(int))); - num_classes++; - } - buf = (char *)xcalloc(total_length, 1); - if (!buf) - return BadAlloc; - savbuf = buf; - - if (k != NULL) { - tk = (xKeyState *) buf; - tk->class = KeyClass; - tk->length = sizeof(xKeyState); - tk->num_keys = k->xkbInfo->desc->max_key_code - - k->xkbInfo->desc->min_key_code + 1; - if (rc != BadAccess) - for (i = 0; i < 32; i++) - tk->keys[i] = k->down[i]; - buf += sizeof(xKeyState); - } - - if (b != NULL) { - tb = (xButtonState *) buf; - tb->class = ButtonClass; - tb->length = sizeof(xButtonState); - tb->num_buttons = b->numButtons; - if (rc != BadAccess) - memcpy(tb->buttons, b->down, sizeof(b->down)); - buf += sizeof(xButtonState); - } - - if (v != NULL) { - tv = (xValuatorState *) buf; - tv->class = ValuatorClass; - tv->length = sizeof(xValuatorState) + v->numAxes * 4; - tv->num_valuators = v->numAxes; - tv->mode = v->mode; - buf += sizeof(xValuatorState); - for (i = 0, values = v->axisVal; i < v->numAxes; i++) { - if (rc != BadAccess) - *((int *)buf) = *values; - values++; - if (client->swapped) { - swapl((int *)buf, n); /* macro - braces needed */ - } - buf += sizeof(int); - } - } - - rep.num_classes = num_classes; - rep.length = bytes_to_int32(total_length); - WriteReplyToClient(client, sizeof(xQueryDeviceStateReply), &rep); - if (total_length > 0) - WriteToClient(client, total_length, savbuf); - xfree(savbuf); - return Success; -} - -/*********************************************************************** - * - * This procedure writes the reply for the XQueryDeviceState function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXQueryDeviceState(ClientPtr client, int size, xQueryDeviceStateReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - WriteToClient(client, size, (char *)rep); -} +/* + +Copyright 1998, 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. + +*/ + +/*********************************************************************** + * + * Request to query the state of an extension input device. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window structure */ +#include +#include +#include "exevents.h" +#include "exglobals.h" +#include "xkbsrv.h" +#include "xkbstr.h" + +#include "queryst.h" + +/*********************************************************************** + * + * This procedure allows a client to query the state of a device. + * + */ + +int +SProcXQueryDeviceState(ClientPtr client) +{ + char n; + + REQUEST(xQueryDeviceStateReq); + swaps(&stuff->length, n); + return (ProcXQueryDeviceState(client)); +} + +/*********************************************************************** + * + * This procedure allows frozen events to be routed. + * + */ + +int +ProcXQueryDeviceState(ClientPtr client) +{ + char n; + int rc, i; + int num_classes = 0; + int total_length = 0; + char *buf, *savbuf; + KeyClassPtr k; + xKeyState *tk; + ButtonClassPtr b; + xButtonState *tb; + ValuatorClassPtr v; + xValuatorState *tv; + xQueryDeviceStateReply rep; + DeviceIntPtr dev; + double *values; + + REQUEST(xQueryDeviceStateReq); + REQUEST_SIZE_MATCH(xQueryDeviceStateReq); + + rep.repType = X_Reply; + rep.RepType = X_QueryDeviceState; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = dixLookupDevice(&dev, stuff->deviceid, client, DixReadAccess); + if (rc != Success && rc != BadAccess) + return rc; + + v = dev->valuator; + if (v != NULL && v->motionHintWindow != NULL) + MaybeStopDeviceHint(dev, client); + + k = dev->key; + if (k != NULL) { + total_length += sizeof(xKeyState); + num_classes++; + } + + b = dev->button; + if (b != NULL) { + total_length += sizeof(xButtonState); + num_classes++; + } + + if (v != NULL) { + total_length += (sizeof(xValuatorState) + (v->numAxes * sizeof(int))); + num_classes++; + } + buf = (char *)calloc(total_length, 1); + if (!buf) + return BadAlloc; + savbuf = buf; + + if (k != NULL) { + tk = (xKeyState *) buf; + tk->class = KeyClass; + tk->length = sizeof(xKeyState); + tk->num_keys = k->xkbInfo->desc->max_key_code - + k->xkbInfo->desc->min_key_code + 1; + if (rc != BadAccess) + for (i = 0; i < 32; i++) + tk->keys[i] = k->down[i]; + buf += sizeof(xKeyState); + } + + if (b != NULL) { + tb = (xButtonState *) buf; + tb->class = ButtonClass; + tb->length = sizeof(xButtonState); + tb->num_buttons = b->numButtons; + if (rc != BadAccess) + memcpy(tb->buttons, b->down, sizeof(b->down)); + buf += sizeof(xButtonState); + } + + if (v != NULL) { + tv = (xValuatorState *) buf; + tv->class = ValuatorClass; + tv->length = sizeof(xValuatorState) + v->numAxes * 4; + tv->num_valuators = v->numAxes; + tv->mode = v->mode; + buf += sizeof(xValuatorState); + for (i = 0, values = v->axisVal; i < v->numAxes; i++) { + if (rc != BadAccess) + *((int *)buf) = *values; + values++; + if (client->swapped) { + swapl((int *)buf, n); /* macro - braces needed */ + } + buf += sizeof(int); + } + } + + rep.num_classes = num_classes; + rep.length = bytes_to_int32(total_length); + WriteReplyToClient(client, sizeof(xQueryDeviceStateReply), &rep); + if (total_length > 0) + WriteToClient(client, total_length, savbuf); + free(savbuf); + return Success; +} + +/*********************************************************************** + * + * This procedure writes the reply for the XQueryDeviceState function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXQueryDeviceState(ClientPtr client, int size, xQueryDeviceStateReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + WriteToClient(client, size, (char *)rep); +} diff --git a/xorg-server/Xi/xichangehierarchy.c b/xorg-server/Xi/xichangehierarchy.c index 1a06e4555..5deb52eac 100644 --- a/xorg-server/Xi/xichangehierarchy.c +++ b/xorg-server/Xi/xichangehierarchy.c @@ -1,454 +1,454 @@ -/* - * Copyright 2007-2008 Peter Hutterer - * Copyright 2009 Red Hat, Inc. - * - * 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. - * - * Author: Peter Hutterer, University of South Australia, NICTA - */ - -/*********************************************************************** - * - * Request change in the device hierarchy. - * - */ - - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include /* for inputstr.h */ -#include /* Request macro */ -#include "inputstr.h" /* DeviceIntPtr */ -#include "windowstr.h" /* window structure */ -#include "scrnintstr.h" /* screen structure */ -#include -#include -#include -#include "extnsionst.h" -#include "exevents.h" -#include "exglobals.h" -#include "geext.h" -#include "xace.h" -#include "xiquerydevice.h" /* for GetDeviceUse */ - -#include "xkbsrv.h" - -#include "xichangehierarchy.h" - -/** - * Send the current state of the device hierarchy to all clients. - */ -void XISendDeviceHierarchyEvent(int flags[MAXDEVICES]) -{ - xXIHierarchyEvent *ev; - xXIHierarchyInfo *info; - DeviceIntRec dummyDev; - DeviceIntPtr dev; - int i; - - if (!flags) - return; - - ev = xcalloc(1, sizeof(xXIHierarchyEvent) + - MAXDEVICES * sizeof(xXIHierarchyInfo)); - ev->type = GenericEvent; - ev->extension = IReqCode; - ev->evtype = XI_HierarchyChanged; - ev->time = GetTimeInMillis(); - ev->flags = 0; - ev->num_info = inputInfo.numDevices; - - info = (xXIHierarchyInfo*)&ev[1]; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - info->deviceid = dev->id; - info->enabled = dev->enabled; - info->use = GetDeviceUse(dev, &info->attachment); - info->flags = flags[dev->id]; - ev->flags |= info->flags; - info++; - } - for (dev = inputInfo.off_devices; dev; dev = dev->next) - { - info->deviceid = dev->id; - info->enabled = dev->enabled; - info->use = GetDeviceUse(dev, &info->attachment); - info->flags = flags[dev->id]; - ev->flags |= info->flags; - info++; - } - - - for (i = 0; i < MAXDEVICES; i++) - { - if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) - { - info->deviceid = i; - info->enabled = FALSE; - info->flags = flags[i]; - info->use = 0; - ev->flags |= info->flags; - ev->num_info++; - info++; - } - } - - ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo)); - - dummyDev.id = XIAllDevices; - SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8), (xEvent*)ev, 1); - xfree(ev); -} - - -/*********************************************************************** - * - * This procedure allows a client to change the device hierarchy through - * adding new master devices, removing them, etc. - * - */ - -int SProcXIChangeHierarchy(ClientPtr client) -{ - char n; - - REQUEST(xXIChangeHierarchyReq); - swaps(&stuff->length, n); - return (ProcXIChangeHierarchy(client)); -} - -#define SWAPIF(cmd) if (client->swapped) { cmd; } - -int -ProcXIChangeHierarchy(ClientPtr client) -{ - DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd; - xXIAnyHierarchyChangeInfo *any; - int required_len = sizeof(xXIChangeHierarchyReq); - char n; - int rc = Success; - int flags[MAXDEVICES] = {0}; - - REQUEST(xXIChangeHierarchyReq); - REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq); - - if (!stuff->num_changes) - return rc; - - any = (xXIAnyHierarchyChangeInfo*)&stuff[1]; - while(stuff->num_changes--) - { - SWAPIF(swapl(&any->type, n)); - SWAPIF(swaps(&any->length, n)); - - required_len += any->length; - if ((stuff->length * 4) < required_len) - return BadLength; - - switch(any->type) - { - case XIAddMaster: - { - xXIAddMasterInfo* c = (xXIAddMasterInfo*)any; - char* name; - - SWAPIF(swaps(&c->name_len, n)); - name = xcalloc(c->name_len + 1, sizeof(char)); - strncpy(name, (char*)&c[1], c->name_len); - - - rc = AllocDevicePair(client, name, &ptr, &keybd, - CorePointerProc, CoreKeyboardProc, - TRUE); - if (rc != Success) - { - xfree(name); - goto unwind; - } - - if (!c->send_core) - ptr->coreEvents = keybd->coreEvents = FALSE; - - /* Allocate virtual slave devices for xtest events */ - rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, - ptr, keybd); - if (rc != Success) - { - - xfree(name); - goto unwind; - } - - ActivateDevice(ptr, FALSE); - ActivateDevice(keybd, FALSE); - flags[ptr->id] |= XIMasterAdded; - flags[keybd->id] |= XIMasterAdded; - - ActivateDevice(XTestptr, FALSE); - ActivateDevice(XTestkeybd, FALSE); - flags[XTestptr->id] |= XISlaveAdded; - flags[XTestkeybd->id] |= XISlaveAdded; - - if (c->enable) - { - EnableDevice(ptr, FALSE); - EnableDevice(keybd, FALSE); - flags[ptr->id] |= XIDeviceEnabled; - flags[keybd->id] |= XIDeviceEnabled; - - EnableDevice(XTestptr, FALSE); - EnableDevice(XTestkeybd, FALSE); - flags[XTestptr->id] |= XIDeviceEnabled; - flags[XTestkeybd->id] |= XIDeviceEnabled; - } - - /* Attach the XTest virtual devices to the newly - created master device */ - AttachDevice(NULL, XTestptr, ptr); - AttachDevice(NULL, XTestkeybd, keybd); - flags[XTestptr->id] |= XISlaveAttached; - flags[XTestkeybd->id] |= XISlaveAttached; - - xfree(name); - } - break; - case XIRemoveMaster: - { - xXIRemoveMasterInfo* r = (xXIRemoveMasterInfo*)any; - - if (r->return_mode != XIAttachToMaster && - r->return_mode != XIFloating) - return BadValue; - - rc = dixLookupDevice(&ptr, r->deviceid, client, - DixDestroyAccess); - if (rc != Success) - goto unwind; - - if (!IsMaster(ptr)) - { - client->errorValue = r->deviceid; - rc = BadDevice; - goto unwind; - } - - /* XXX: For now, don't allow removal of VCP, VCK */ - if (ptr == inputInfo.pointer || - ptr == inputInfo.keyboard) - { - rc = BadDevice; - goto unwind; - } - - - ptr = GetMaster(ptr, MASTER_POINTER); - rc = dixLookupDevice(&ptr, - ptr->id, - client, - DixDestroyAccess); - if (rc != Success) - goto unwind; - keybd = GetMaster(ptr, MASTER_KEYBOARD); - rc = dixLookupDevice(&keybd, - keybd->id, - client, - DixDestroyAccess); - if (rc != Success) - goto unwind; - - XTestptr = GetXTestDevice(ptr); - rc = dixLookupDevice(&XTestptr, XTestptr->id, client, - DixDestroyAccess); - if (rc != Success) - goto unwind; - - XTestkeybd = GetXTestDevice(keybd); - rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, - DixDestroyAccess); - if (rc != Success) - goto unwind; - - /* Disabling sends the devices floating, reattach them if - * desired. */ - if (r->return_mode == XIAttachToMaster) - { - DeviceIntPtr attached, - newptr, - newkeybd; - - rc = dixLookupDevice(&newptr, r->return_pointer, - client, DixAddAccess); - if (rc != Success) - goto unwind; - - if (!IsMaster(newptr)) - { - client->errorValue = r->return_pointer; - rc = BadDevice; - goto unwind; - } - - rc = dixLookupDevice(&newkeybd, r->return_keyboard, - client, DixAddAccess); - if (rc != Success) - goto unwind; - - if (!IsMaster(newkeybd)) - { - client->errorValue = r->return_keyboard; - rc = BadDevice; - goto unwind; - } - - for (attached = inputInfo.devices; - attached; - attached = attached->next) - { - if (!IsMaster(attached)) { - if (attached->u.master == ptr) - { - AttachDevice(client, attached, newptr); - flags[attached->id] |= XISlaveAttached; - } - if (attached->u.master == keybd) - { - AttachDevice(client, attached, newkeybd); - flags[attached->id] |= XISlaveAttached; - } - } - } - } - - /* can't disable until we removed pairing */ - keybd->spriteInfo->paired = NULL; - ptr->spriteInfo->paired = NULL; - XTestptr->spriteInfo->paired = NULL; - XTestkeybd->spriteInfo->paired = NULL; - - /* disable the remove the devices, XTest devices must be done first - else the sprites they rely on will be destroyed */ - DisableDevice(XTestptr, FALSE); - DisableDevice(XTestkeybd, FALSE); - DisableDevice(keybd, FALSE); - DisableDevice(ptr, FALSE); - flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached; - flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached; - flags[keybd->id] |= XIDeviceDisabled; - flags[ptr->id] |= XIDeviceDisabled; - - RemoveDevice(XTestptr, FALSE); - RemoveDevice(XTestkeybd, FALSE); - RemoveDevice(keybd, FALSE); - RemoveDevice(ptr, FALSE); - flags[XTestptr->id] |= XISlaveRemoved; - flags[XTestkeybd->id] |= XISlaveRemoved; - flags[keybd->id] |= XIMasterRemoved; - flags[ptr->id] |= XIMasterRemoved; - } - break; - case XIDetachSlave: - { - xXIDetachSlaveInfo* c = (xXIDetachSlaveInfo*)any; - - rc = dixLookupDevice(&ptr, c->deviceid, client, - DixManageAccess); - if (rc != Success) - goto unwind; - - if (IsMaster(ptr)) - { - client->errorValue = c->deviceid; - rc = BadDevice; - goto unwind; - } - - /* Don't allow changes to XTest Devices, these are fixed */ - if (IsXTestDevice(ptr, NULL)) - { - client->errorValue = c->deviceid; - rc = BadDevice; - goto unwind; - } - - AttachDevice(client, ptr, NULL); - flags[ptr->id] |= XISlaveDetached; - } - break; - case XIAttachSlave: - { - xXIAttachSlaveInfo* c = (xXIAttachSlaveInfo*)any; - DeviceIntPtr newmaster; - - rc = dixLookupDevice(&ptr, c->deviceid, client, - DixManageAccess); - if (rc != Success) - goto unwind; - - if (IsMaster(ptr)) - { - client->errorValue = c->deviceid; - rc = BadDevice; - goto unwind; - } - - /* Don't allow changes to XTest Devices, these are fixed */ - if (IsXTestDevice(ptr, NULL)) - { - client->errorValue = c->deviceid; - rc = BadDevice; - goto unwind; - } - - rc = dixLookupDevice(&newmaster, c->new_master, - client, DixAddAccess); - if (rc != Success) - goto unwind; - if (!IsMaster(newmaster)) - { - client->errorValue = c->new_master; - rc = BadDevice; - goto unwind; - } - - if (!((IsPointerDevice(newmaster) && - IsPointerDevice(ptr)) || - (IsKeyboardDevice(newmaster) && - IsKeyboardDevice(ptr)))) - { - rc = BadDevice; - goto unwind; - } - AttachDevice(client, ptr, newmaster); - flags[ptr->id] |= XISlaveAttached; - } - break; - } - - any = (xXIAnyHierarchyChangeInfo*)((char*)any + any->length * 4); - } - -unwind: - - XISendDeviceHierarchyEvent(flags); - return rc; -} - +/* + * Copyright 2007-2008 Peter Hutterer + * Copyright 2009 Red Hat, Inc. + * + * 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. + * + * Author: Peter Hutterer, University of South Australia, NICTA + */ + +/*********************************************************************** + * + * Request change in the device hierarchy. + * + */ + + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include /* for inputstr.h */ +#include /* Request macro */ +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window structure */ +#include "scrnintstr.h" /* screen structure */ +#include +#include +#include +#include "extnsionst.h" +#include "exevents.h" +#include "exglobals.h" +#include "geext.h" +#include "xace.h" +#include "xiquerydevice.h" /* for GetDeviceUse */ + +#include "xkbsrv.h" + +#include "xichangehierarchy.h" + +/** + * Send the current state of the device hierarchy to all clients. + */ +void XISendDeviceHierarchyEvent(int flags[MAXDEVICES]) +{ + xXIHierarchyEvent *ev; + xXIHierarchyInfo *info; + DeviceIntRec dummyDev; + DeviceIntPtr dev; + int i; + + if (!flags) + return; + + ev = calloc(1, sizeof(xXIHierarchyEvent) + + MAXDEVICES * sizeof(xXIHierarchyInfo)); + ev->type = GenericEvent; + ev->extension = IReqCode; + ev->evtype = XI_HierarchyChanged; + ev->time = GetTimeInMillis(); + ev->flags = 0; + ev->num_info = inputInfo.numDevices; + + info = (xXIHierarchyInfo*)&ev[1]; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + info->deviceid = dev->id; + info->enabled = dev->enabled; + info->use = GetDeviceUse(dev, &info->attachment); + info->flags = flags[dev->id]; + ev->flags |= info->flags; + info++; + } + for (dev = inputInfo.off_devices; dev; dev = dev->next) + { + info->deviceid = dev->id; + info->enabled = dev->enabled; + info->use = GetDeviceUse(dev, &info->attachment); + info->flags = flags[dev->id]; + ev->flags |= info->flags; + info++; + } + + + for (i = 0; i < MAXDEVICES; i++) + { + if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) + { + info->deviceid = i; + info->enabled = FALSE; + info->flags = flags[i]; + info->use = 0; + ev->flags |= info->flags; + ev->num_info++; + info++; + } + } + + ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo)); + + dummyDev.id = XIAllDevices; + SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8), (xEvent*)ev, 1); + free(ev); +} + + +/*********************************************************************** + * + * This procedure allows a client to change the device hierarchy through + * adding new master devices, removing them, etc. + * + */ + +int SProcXIChangeHierarchy(ClientPtr client) +{ + char n; + + REQUEST(xXIChangeHierarchyReq); + swaps(&stuff->length, n); + return (ProcXIChangeHierarchy(client)); +} + +#define SWAPIF(cmd) if (client->swapped) { cmd; } + +int +ProcXIChangeHierarchy(ClientPtr client) +{ + DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd; + xXIAnyHierarchyChangeInfo *any; + int required_len = sizeof(xXIChangeHierarchyReq); + char n; + int rc = Success; + int flags[MAXDEVICES] = {0}; + + REQUEST(xXIChangeHierarchyReq); + REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq); + + if (!stuff->num_changes) + return rc; + + any = (xXIAnyHierarchyChangeInfo*)&stuff[1]; + while(stuff->num_changes--) + { + SWAPIF(swapl(&any->type, n)); + SWAPIF(swaps(&any->length, n)); + + required_len += any->length; + if ((stuff->length * 4) < required_len) + return BadLength; + + switch(any->type) + { + case XIAddMaster: + { + xXIAddMasterInfo* c = (xXIAddMasterInfo*)any; + char* name; + + SWAPIF(swaps(&c->name_len, n)); + name = calloc(c->name_len + 1, sizeof(char)); + strncpy(name, (char*)&c[1], c->name_len); + + + rc = AllocDevicePair(client, name, &ptr, &keybd, + CorePointerProc, CoreKeyboardProc, + TRUE); + if (rc != Success) + { + free(name); + goto unwind; + } + + if (!c->send_core) + ptr->coreEvents = keybd->coreEvents = FALSE; + + /* Allocate virtual slave devices for xtest events */ + rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, + ptr, keybd); + if (rc != Success) + { + + free(name); + goto unwind; + } + + ActivateDevice(ptr, FALSE); + ActivateDevice(keybd, FALSE); + flags[ptr->id] |= XIMasterAdded; + flags[keybd->id] |= XIMasterAdded; + + ActivateDevice(XTestptr, FALSE); + ActivateDevice(XTestkeybd, FALSE); + flags[XTestptr->id] |= XISlaveAdded; + flags[XTestkeybd->id] |= XISlaveAdded; + + if (c->enable) + { + EnableDevice(ptr, FALSE); + EnableDevice(keybd, FALSE); + flags[ptr->id] |= XIDeviceEnabled; + flags[keybd->id] |= XIDeviceEnabled; + + EnableDevice(XTestptr, FALSE); + EnableDevice(XTestkeybd, FALSE); + flags[XTestptr->id] |= XIDeviceEnabled; + flags[XTestkeybd->id] |= XIDeviceEnabled; + } + + /* Attach the XTest virtual devices to the newly + created master device */ + AttachDevice(NULL, XTestptr, ptr); + AttachDevice(NULL, XTestkeybd, keybd); + flags[XTestptr->id] |= XISlaveAttached; + flags[XTestkeybd->id] |= XISlaveAttached; + + free(name); + } + break; + case XIRemoveMaster: + { + xXIRemoveMasterInfo* r = (xXIRemoveMasterInfo*)any; + + if (r->return_mode != XIAttachToMaster && + r->return_mode != XIFloating) + return BadValue; + + rc = dixLookupDevice(&ptr, r->deviceid, client, + DixDestroyAccess); + if (rc != Success) + goto unwind; + + if (!IsMaster(ptr)) + { + client->errorValue = r->deviceid; + rc = BadDevice; + goto unwind; + } + + /* XXX: For now, don't allow removal of VCP, VCK */ + if (ptr == inputInfo.pointer || + ptr == inputInfo.keyboard) + { + rc = BadDevice; + goto unwind; + } + + + ptr = GetMaster(ptr, MASTER_POINTER); + rc = dixLookupDevice(&ptr, + ptr->id, + client, + DixDestroyAccess); + if (rc != Success) + goto unwind; + keybd = GetMaster(ptr, MASTER_KEYBOARD); + rc = dixLookupDevice(&keybd, + keybd->id, + client, + DixDestroyAccess); + if (rc != Success) + goto unwind; + + XTestptr = GetXTestDevice(ptr); + rc = dixLookupDevice(&XTestptr, XTestptr->id, client, + DixDestroyAccess); + if (rc != Success) + goto unwind; + + XTestkeybd = GetXTestDevice(keybd); + rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, + DixDestroyAccess); + if (rc != Success) + goto unwind; + + /* Disabling sends the devices floating, reattach them if + * desired. */ + if (r->return_mode == XIAttachToMaster) + { + DeviceIntPtr attached, + newptr, + newkeybd; + + rc = dixLookupDevice(&newptr, r->return_pointer, + client, DixAddAccess); + if (rc != Success) + goto unwind; + + if (!IsMaster(newptr)) + { + client->errorValue = r->return_pointer; + rc = BadDevice; + goto unwind; + } + + rc = dixLookupDevice(&newkeybd, r->return_keyboard, + client, DixAddAccess); + if (rc != Success) + goto unwind; + + if (!IsMaster(newkeybd)) + { + client->errorValue = r->return_keyboard; + rc = BadDevice; + goto unwind; + } + + for (attached = inputInfo.devices; + attached; + attached = attached->next) + { + if (!IsMaster(attached)) { + if (attached->u.master == ptr) + { + AttachDevice(client, attached, newptr); + flags[attached->id] |= XISlaveAttached; + } + if (attached->u.master == keybd) + { + AttachDevice(client, attached, newkeybd); + flags[attached->id] |= XISlaveAttached; + } + } + } + } + + /* can't disable until we removed pairing */ + keybd->spriteInfo->paired = NULL; + ptr->spriteInfo->paired = NULL; + XTestptr->spriteInfo->paired = NULL; + XTestkeybd->spriteInfo->paired = NULL; + + /* disable the remove the devices, XTest devices must be done first + else the sprites they rely on will be destroyed */ + DisableDevice(XTestptr, FALSE); + DisableDevice(XTestkeybd, FALSE); + DisableDevice(keybd, FALSE); + DisableDevice(ptr, FALSE); + flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached; + flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached; + flags[keybd->id] |= XIDeviceDisabled; + flags[ptr->id] |= XIDeviceDisabled; + + RemoveDevice(XTestptr, FALSE); + RemoveDevice(XTestkeybd, FALSE); + RemoveDevice(keybd, FALSE); + RemoveDevice(ptr, FALSE); + flags[XTestptr->id] |= XISlaveRemoved; + flags[XTestkeybd->id] |= XISlaveRemoved; + flags[keybd->id] |= XIMasterRemoved; + flags[ptr->id] |= XIMasterRemoved; + } + break; + case XIDetachSlave: + { + xXIDetachSlaveInfo* c = (xXIDetachSlaveInfo*)any; + + rc = dixLookupDevice(&ptr, c->deviceid, client, + DixManageAccess); + if (rc != Success) + goto unwind; + + if (IsMaster(ptr)) + { + client->errorValue = c->deviceid; + rc = BadDevice; + goto unwind; + } + + /* Don't allow changes to XTest Devices, these are fixed */ + if (IsXTestDevice(ptr, NULL)) + { + client->errorValue = c->deviceid; + rc = BadDevice; + goto unwind; + } + + AttachDevice(client, ptr, NULL); + flags[ptr->id] |= XISlaveDetached; + } + break; + case XIAttachSlave: + { + xXIAttachSlaveInfo* c = (xXIAttachSlaveInfo*)any; + DeviceIntPtr newmaster; + + rc = dixLookupDevice(&ptr, c->deviceid, client, + DixManageAccess); + if (rc != Success) + goto unwind; + + if (IsMaster(ptr)) + { + client->errorValue = c->deviceid; + rc = BadDevice; + goto unwind; + } + + /* Don't allow changes to XTest Devices, these are fixed */ + if (IsXTestDevice(ptr, NULL)) + { + client->errorValue = c->deviceid; + rc = BadDevice; + goto unwind; + } + + rc = dixLookupDevice(&newmaster, c->new_master, + client, DixAddAccess); + if (rc != Success) + goto unwind; + if (!IsMaster(newmaster)) + { + client->errorValue = c->new_master; + rc = BadDevice; + goto unwind; + } + + if (!((IsPointerDevice(newmaster) && + IsPointerDevice(ptr)) || + (IsKeyboardDevice(newmaster) && + IsKeyboardDevice(ptr)))) + { + rc = BadDevice; + goto unwind; + } + AttachDevice(client, ptr, newmaster); + flags[ptr->id] |= XISlaveAttached; + } + break; + } + + any = (xXIAnyHierarchyChangeInfo*)((char*)any + any->length * 4); + } + +unwind: + + XISendDeviceHierarchyEvent(flags); + return rc; +} + diff --git a/xorg-server/Xi/xipassivegrab.c b/xorg-server/Xi/xipassivegrab.c index 41a56b14e..4a79ed497 100644 --- a/xorg-server/Xi/xipassivegrab.c +++ b/xorg-server/Xi/xipassivegrab.c @@ -1,313 +1,313 @@ -/* - * Copyright © 2009 Red Hat, Inc. - * - * 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. - * - * Author: Peter Hutterer - */ - -/*********************************************************************** - * - * Request to grab or ungrab input device. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" /* DeviceIntPtr */ -#include "windowstr.h" /* window structure */ -#include -#include -#include "swaprep.h" - -#include "exglobals.h" /* BadDevice */ -#include "exevents.h" -#include "xipassivegrab.h" -#include "dixgrabs.h" - -int -SProcXIPassiveGrabDevice(ClientPtr client) -{ - int i; - char n; - xXIModifierInfo *mods; - - REQUEST(xXIPassiveGrabDeviceReq); - - swaps(&stuff->length, n); - swaps(&stuff->deviceid, n); - swapl(&stuff->grab_window, n); - swapl(&stuff->cursor, n); - swapl(&stuff->time, n); - swapl(&stuff->detail, n); - swaps(&stuff->mask_len, n); - swaps(&stuff->num_modifiers, n); - - mods = (xXIModifierInfo*)&stuff[1]; - - for (i = 0; i < stuff->num_modifiers; i++, mods++) - { - swapl(&mods->base_mods, n); - swapl(&mods->latched_mods, n); - swapl(&mods->locked_mods, n); - } - - return ProcXIPassiveGrabDevice(client); -} - -int -ProcXIPassiveGrabDevice(ClientPtr client) -{ - DeviceIntPtr dev, mod_dev; - xXIPassiveGrabDeviceReply rep; - int i, ret = Success; - uint8_t status; - uint32_t *modifiers; - xXIGrabModifierInfo *modifiers_failed; - GrabMask mask; - GrabParameters param; - void *tmp; - int mask_len; - - REQUEST(xXIPassiveGrabDeviceReq); - REQUEST_AT_LEAST_SIZE(xXIPassiveGrabDeviceReq); - - if (stuff->deviceid == XIAllDevices) - dev = inputInfo.all_devices; - else if (stuff->deviceid == XIAllMasterDevices) - dev = inputInfo.all_master_devices; - else - { - ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess); - if (ret != Success) - return ret; - } - - if (stuff->grab_type != XIGrabtypeButton && - stuff->grab_type != XIGrabtypeKeycode && - stuff->grab_type != XIGrabtypeEnter && - stuff->grab_type != XIGrabtypeFocusIn) - { - client->errorValue = stuff->grab_type; - return BadValue; - } - - if ((stuff->grab_type == XIGrabtypeEnter || - stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0) - { - client->errorValue = stuff->detail; - return BadValue; - } - - if (XICheckInvalidMaskBits((unsigned char*)&stuff[1], - stuff->mask_len * 4) != Success) - return BadValue; - - mask_len = min(sizeof(mask.xi2mask[stuff->deviceid]), stuff->mask_len * 4); - memset(mask.xi2mask, 0, sizeof(mask.xi2mask)); - memcpy(mask.xi2mask[stuff->deviceid], &stuff[1], mask_len * 4); - - rep.repType = X_Reply; - rep.RepType = X_XIPassiveGrabDevice; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.num_modifiers = 0; - - memset(¶m, 0, sizeof(param)); - param.grabtype = GRABTYPE_XI2; - param.ownerEvents = stuff->owner_events; - param.this_device_mode = stuff->grab_mode; - param.other_devices_mode = stuff->paired_device_mode; - param.grabWindow = stuff->grab_window; - param.cursor = stuff->cursor; - - if (stuff->cursor != None) - { - status = dixLookupResourceByType(&tmp, stuff->cursor, - RT_CURSOR, client, DixUseAccess); - if (status != Success) - { - client->errorValue = stuff->cursor; - return (status == BadValue) ? BadCursor : status; - } - } - - status = dixLookupWindow((WindowPtr*)&tmp, stuff->grab_window, client, DixSetAttrAccess); - if (status != Success) - return status; - - status = CheckGrabValues(client, ¶m); - - modifiers = (uint32_t*)&stuff[1] + stuff->mask_len; - modifiers_failed = xcalloc(stuff->num_modifiers, sizeof(xXIGrabModifierInfo)); - if (!modifiers_failed) - return BadAlloc; - - if (!IsMaster(dev) && dev->u.master) - mod_dev = GetMaster(dev, MASTER_KEYBOARD); - else - mod_dev = dev; - - for (i = 0; i < stuff->num_modifiers; i++, modifiers++) - { - param.modifiers = *modifiers; - switch(stuff->grab_type) - { - case XIGrabtypeButton: - status = GrabButton(client, dev, mod_dev, stuff->detail, - ¶m, GRABTYPE_XI2, &mask); - break; - case XIGrabtypeKeycode: - status = GrabKey(client, dev, mod_dev, stuff->detail, - ¶m, GRABTYPE_XI2, &mask); - break; - case XIGrabtypeEnter: - case XIGrabtypeFocusIn: - status = GrabWindow(client, dev, stuff->grab_type, - ¶m, &mask); - break; - } - - if (status != GrabSuccess) - { - xXIGrabModifierInfo *info = modifiers_failed + rep.num_modifiers; - - info->status = status; - info->modifiers = *modifiers; - rep.num_modifiers++; - rep.length++; - } - } - - WriteReplyToClient(client, sizeof(rep), &rep); - if (rep.num_modifiers) - { - client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; - WriteSwappedDataToClient(client, rep.num_modifiers * 4, (char*)modifiers_failed); - } - xfree(modifiers_failed); - return ret; -} - -void -SRepXIPassiveGrabDevice(ClientPtr client, int size, - xXIPassiveGrabDeviceReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->num_modifiers, n); - - WriteToClient(client, size, (char *)rep); -} - -int -SProcXIPassiveUngrabDevice(ClientPtr client) -{ - char n; - int i; - uint32_t *modifiers; - - REQUEST(xXIPassiveUngrabDeviceReq); - - swaps(&stuff->length, n); - swapl(&stuff->grab_window, n); - swaps(&stuff->deviceid, n); - swapl(&stuff->detail, n); - swaps(&stuff->num_modifiers, n); - - modifiers = (uint32_t*)&stuff[1]; - - for (i = 0; i < stuff->num_modifiers; i++, modifiers++) - swapl(modifiers, n); - - return ProcXIPassiveUngrabDevice(client); -} - -int -ProcXIPassiveUngrabDevice(ClientPtr client) -{ - DeviceIntPtr dev, mod_dev; - WindowPtr win; - GrabRec tempGrab; - uint32_t* modifiers; - int i, rc; - - REQUEST(xXIPassiveUngrabDeviceReq); - REQUEST_AT_LEAST_SIZE(xXIPassiveUngrabDeviceReq); - - rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess); - if (rc != Success) - return rc; - - if (stuff->grab_type != XIGrabtypeButton && - stuff->grab_type != XIGrabtypeKeycode && - stuff->grab_type != XIGrabtypeEnter && - stuff->grab_type != XIGrabtypeFocusIn) - { - client->errorValue = stuff->grab_type; - return BadValue; - } - - if ((stuff->grab_type == XIGrabtypeEnter || - stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0) - { - client->errorValue = stuff->detail; - return BadValue; - } - - rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - if (!IsMaster(dev) && dev->u.master) - mod_dev = GetMaster(dev, MASTER_KEYBOARD); - else - mod_dev = dev; - - tempGrab.resource = client->clientAsMask; - tempGrab.device = dev; - tempGrab.window = win; - switch(stuff->grab_type) - { - case XIGrabtypeButton: tempGrab.type = XI_ButtonPress; break; - case XIGrabtypeKeycode: tempGrab.type = XI_KeyPress; break; - case XIGrabtypeEnter: tempGrab.type = XI_Enter; break; - case XIGrabtypeFocusIn: tempGrab.type = XI_FocusIn; break; - } - tempGrab.grabtype = GRABTYPE_XI2; - tempGrab.modifierDevice = mod_dev; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.detail.exact = stuff->detail; - tempGrab.detail.pMask = NULL; - - modifiers = (uint32_t*)&stuff[1]; - - for (i = 0; i < stuff->num_modifiers; i++, modifiers++) - { - tempGrab.modifiersDetail.exact = *modifiers; - DeletePassiveGrabFromList(&tempGrab); - } - - return Success; -} +/* + * Copyright © 2009 Red Hat, Inc. + * + * 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. + * + * Author: Peter Hutterer + */ + +/*********************************************************************** + * + * Request to grab or ungrab input device. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window structure */ +#include +#include +#include "swaprep.h" + +#include "exglobals.h" /* BadDevice */ +#include "exevents.h" +#include "xipassivegrab.h" +#include "dixgrabs.h" + +int +SProcXIPassiveGrabDevice(ClientPtr client) +{ + int i; + char n; + xXIModifierInfo *mods; + + REQUEST(xXIPassiveGrabDeviceReq); + + swaps(&stuff->length, n); + swaps(&stuff->deviceid, n); + swapl(&stuff->grab_window, n); + swapl(&stuff->cursor, n); + swapl(&stuff->time, n); + swapl(&stuff->detail, n); + swaps(&stuff->mask_len, n); + swaps(&stuff->num_modifiers, n); + + mods = (xXIModifierInfo*)&stuff[1]; + + for (i = 0; i < stuff->num_modifiers; i++, mods++) + { + swapl(&mods->base_mods, n); + swapl(&mods->latched_mods, n); + swapl(&mods->locked_mods, n); + } + + return ProcXIPassiveGrabDevice(client); +} + +int +ProcXIPassiveGrabDevice(ClientPtr client) +{ + DeviceIntPtr dev, mod_dev; + xXIPassiveGrabDeviceReply rep; + int i, ret = Success; + uint8_t status; + uint32_t *modifiers; + xXIGrabModifierInfo *modifiers_failed; + GrabMask mask; + GrabParameters param; + void *tmp; + int mask_len; + + REQUEST(xXIPassiveGrabDeviceReq); + REQUEST_AT_LEAST_SIZE(xXIPassiveGrabDeviceReq); + + if (stuff->deviceid == XIAllDevices) + dev = inputInfo.all_devices; + else if (stuff->deviceid == XIAllMasterDevices) + dev = inputInfo.all_master_devices; + else + { + ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess); + if (ret != Success) + return ret; + } + + if (stuff->grab_type != XIGrabtypeButton && + stuff->grab_type != XIGrabtypeKeycode && + stuff->grab_type != XIGrabtypeEnter && + stuff->grab_type != XIGrabtypeFocusIn) + { + client->errorValue = stuff->grab_type; + return BadValue; + } + + if ((stuff->grab_type == XIGrabtypeEnter || + stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0) + { + client->errorValue = stuff->detail; + return BadValue; + } + + if (XICheckInvalidMaskBits((unsigned char*)&stuff[1], + stuff->mask_len * 4) != Success) + return BadValue; + + mask_len = min(sizeof(mask.xi2mask[stuff->deviceid]), stuff->mask_len * 4); + memset(mask.xi2mask, 0, sizeof(mask.xi2mask)); + memcpy(mask.xi2mask[stuff->deviceid], &stuff[1], mask_len * 4); + + rep.repType = X_Reply; + rep.RepType = X_XIPassiveGrabDevice; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.num_modifiers = 0; + + memset(¶m, 0, sizeof(param)); + param.grabtype = GRABTYPE_XI2; + param.ownerEvents = stuff->owner_events; + param.this_device_mode = stuff->grab_mode; + param.other_devices_mode = stuff->paired_device_mode; + param.grabWindow = stuff->grab_window; + param.cursor = stuff->cursor; + + if (stuff->cursor != None) + { + status = dixLookupResourceByType(&tmp, stuff->cursor, + RT_CURSOR, client, DixUseAccess); + if (status != Success) + { + client->errorValue = stuff->cursor; + return (status == BadValue) ? BadCursor : status; + } + } + + status = dixLookupWindow((WindowPtr*)&tmp, stuff->grab_window, client, DixSetAttrAccess); + if (status != Success) + return status; + + status = CheckGrabValues(client, ¶m); + + modifiers = (uint32_t*)&stuff[1] + stuff->mask_len; + modifiers_failed = calloc(stuff->num_modifiers, sizeof(xXIGrabModifierInfo)); + if (!modifiers_failed) + return BadAlloc; + + if (!IsMaster(dev) && dev->u.master) + mod_dev = GetMaster(dev, MASTER_KEYBOARD); + else + mod_dev = dev; + + for (i = 0; i < stuff->num_modifiers; i++, modifiers++) + { + param.modifiers = *modifiers; + switch(stuff->grab_type) + { + case XIGrabtypeButton: + status = GrabButton(client, dev, mod_dev, stuff->detail, + ¶m, GRABTYPE_XI2, &mask); + break; + case XIGrabtypeKeycode: + status = GrabKey(client, dev, mod_dev, stuff->detail, + ¶m, GRABTYPE_XI2, &mask); + break; + case XIGrabtypeEnter: + case XIGrabtypeFocusIn: + status = GrabWindow(client, dev, stuff->grab_type, + ¶m, &mask); + break; + } + + if (status != GrabSuccess) + { + xXIGrabModifierInfo *info = modifiers_failed + rep.num_modifiers; + + info->status = status; + info->modifiers = *modifiers; + rep.num_modifiers++; + rep.length++; + } + } + + WriteReplyToClient(client, sizeof(rep), &rep); + if (rep.num_modifiers) + { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, rep.num_modifiers * 4, (char*)modifiers_failed); + } + free(modifiers_failed); + return ret; +} + +void +SRepXIPassiveGrabDevice(ClientPtr client, int size, + xXIPassiveGrabDeviceReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->num_modifiers, n); + + WriteToClient(client, size, (char *)rep); +} + +int +SProcXIPassiveUngrabDevice(ClientPtr client) +{ + char n; + int i; + uint32_t *modifiers; + + REQUEST(xXIPassiveUngrabDeviceReq); + + swaps(&stuff->length, n); + swapl(&stuff->grab_window, n); + swaps(&stuff->deviceid, n); + swapl(&stuff->detail, n); + swaps(&stuff->num_modifiers, n); + + modifiers = (uint32_t*)&stuff[1]; + + for (i = 0; i < stuff->num_modifiers; i++, modifiers++) + swapl(modifiers, n); + + return ProcXIPassiveUngrabDevice(client); +} + +int +ProcXIPassiveUngrabDevice(ClientPtr client) +{ + DeviceIntPtr dev, mod_dev; + WindowPtr win; + GrabRec tempGrab; + uint32_t* modifiers; + int i, rc; + + REQUEST(xXIPassiveUngrabDeviceReq); + REQUEST_AT_LEAST_SIZE(xXIPassiveUngrabDeviceReq); + + rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess); + if (rc != Success) + return rc; + + if (stuff->grab_type != XIGrabtypeButton && + stuff->grab_type != XIGrabtypeKeycode && + stuff->grab_type != XIGrabtypeEnter && + stuff->grab_type != XIGrabtypeFocusIn) + { + client->errorValue = stuff->grab_type; + return BadValue; + } + + if ((stuff->grab_type == XIGrabtypeEnter || + stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0) + { + client->errorValue = stuff->detail; + return BadValue; + } + + rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + if (!IsMaster(dev) && dev->u.master) + mod_dev = GetMaster(dev, MASTER_KEYBOARD); + else + mod_dev = dev; + + tempGrab.resource = client->clientAsMask; + tempGrab.device = dev; + tempGrab.window = win; + switch(stuff->grab_type) + { + case XIGrabtypeButton: tempGrab.type = XI_ButtonPress; break; + case XIGrabtypeKeycode: tempGrab.type = XI_KeyPress; break; + case XIGrabtypeEnter: tempGrab.type = XI_Enter; break; + case XIGrabtypeFocusIn: tempGrab.type = XI_FocusIn; break; + } + tempGrab.grabtype = GRABTYPE_XI2; + tempGrab.modifierDevice = mod_dev; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.detail.exact = stuff->detail; + tempGrab.detail.pMask = NULL; + + modifiers = (uint32_t*)&stuff[1]; + + for (i = 0; i < stuff->num_modifiers; i++, modifiers++) + { + tempGrab.modifiersDetail.exact = *modifiers; + DeletePassiveGrabFromList(&tempGrab); + } + + return Success; +} diff --git a/xorg-server/Xi/xiproperty.c b/xorg-server/Xi/xiproperty.c index 6e298b7d1..4f8d2430d 100644 --- a/xorg-server/Xi/xiproperty.c +++ b/xorg-server/Xi/xiproperty.c @@ -225,7 +225,7 @@ static int list_atoms(DeviceIntPtr dev, int *natoms, Atom **atoms_return) { Atom *a; - atoms = xalloc(nprops * sizeof(Atom)); + atoms = malloc(nprops * sizeof(Atom)); if(!atoms) return BadAlloc; a = atoms; @@ -457,7 +457,7 @@ XIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return) if (!buf && !(*nelem_return)) { - buf = xcalloc(val->size, sizeof(int)); + buf = calloc(val->size, sizeof(int)); if (!buf) return BadAlloc; *buf_return = buf; @@ -517,7 +517,7 @@ XIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return) if (!buf && !(*nelem_return)) { - buf = xcalloc(val->size, sizeof(float)); + buf = calloc(val->size, sizeof(float)); if (!buf) return BadAlloc; *buf_return = buf; @@ -549,7 +549,7 @@ XIRegisterPropertyHandler(DeviceIntPtr dev, { XIPropertyHandlerPtr new_handler; - new_handler = xcalloc(1, sizeof(XIPropertyHandler)); + new_handler = calloc(1, sizeof(XIPropertyHandler)); if (!new_handler) return 0; @@ -583,7 +583,7 @@ XIUnregisterPropertyHandler(DeviceIntPtr dev, long id) else prev->next = curr->next; - xfree(curr); + free(curr); } static XIPropertyPtr @@ -591,7 +591,7 @@ XICreateDeviceProperty (Atom property) { XIPropertyPtr prop; - prop = (XIPropertyPtr)xalloc(sizeof(XIPropertyRec)); + prop = (XIPropertyPtr)malloc(sizeof(XIPropertyRec)); if (!prop) return NULL; @@ -621,8 +621,8 @@ static void XIDestroyDeviceProperty (XIPropertyPtr prop) { if (prop->value.data) - xfree(prop->value.data); - xfree(prop); + free(prop->value.data); + free(prop); } /* This function destroys all of the device's property-related stuff, @@ -649,7 +649,7 @@ XIDeleteAllDeviceProperties (DeviceIntPtr device) while(curr_handler) { next_handler = curr_handler->next; - xfree(curr_handler); + free(curr_handler); curr_handler = next_handler; } @@ -745,7 +745,7 @@ XIChangeDeviceProperty (DeviceIntPtr dev, Atom property, Atom type, pointer new_data = NULL, old_data = NULL; total_size = total_len * size_in_bytes; - new_value.data = (pointer)xalloc (total_size); + new_value.data = (pointer)malloc(total_size); if (!new_value.data && total_size) { if (add) @@ -797,7 +797,7 @@ XIChangeDeviceProperty (DeviceIntPtr dev, Atom property, Atom type, if (checkonly && rc != Success) { if (new_value.data) - xfree (new_value.data); + free(new_value.data); return (rc); } } @@ -807,7 +807,7 @@ XIChangeDeviceProperty (DeviceIntPtr dev, Atom property, Atom type, } while (!checkonly); } if (prop_value->data) - xfree (prop_value->data); + free(prop_value->data); *prop_value = new_value; } else if (len == 0) { @@ -905,7 +905,7 @@ ProcXListDeviceProperties (ClientPtr client) { client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); - xfree(atoms); + free(atoms); } return rc; } @@ -1149,7 +1149,7 @@ ProcXIListProperties(ClientPtr client) { client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); - xfree(atoms); + free(atoms); } return rc; } diff --git a/xorg-server/Xi/xiquerydevice.c b/xorg-server/Xi/xiquerydevice.c index 47ab688fd..c24f8a894 100644 --- a/xorg-server/Xi/xiquerydevice.c +++ b/xorg-server/Xi/xiquerydevice.c @@ -1,503 +1,503 @@ -/* - * Copyright © 2009 Red Hat, Inc. - * - * 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. - * - * Authors: Peter Hutterer - * - */ - -/** - * @file Protocol handling for the XIQueryDevice request/reply. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" -#include -#include -#include -#include "xkbstr.h" -#include "xkbsrv.h" -#include "xserver-properties.h" -#include "exevents.h" -#include "xace.h" - -#include "xiquerydevice.h" - -static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d); -static int -ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info); -static int SizeDeviceInfo(DeviceIntPtr dev); -static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info); -int -SProcXIQueryDevice(ClientPtr client) -{ - char n; - - REQUEST(xXIQueryDeviceReq); - - swaps(&stuff->length, n); - swaps(&stuff->deviceid, n); - - return ProcXIQueryDevice(client); -} - -int -ProcXIQueryDevice(ClientPtr client) -{ - xXIQueryDeviceReply rep; - DeviceIntPtr dev = NULL; - int rc = Success; - int i = 0, len = 0; - char *info, *ptr; - Bool *skip = NULL; - - REQUEST(xXIQueryDeviceReq); - REQUEST_SIZE_MATCH(xXIQueryDeviceReq); - - if (stuff->deviceid != XIAllDevices && stuff->deviceid != XIAllMasterDevices) - { - rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); - if (rc != Success) - { - client->errorValue = stuff->deviceid; - return rc; - } - len += SizeDeviceInfo(dev); - } - else - { - skip = xcalloc(sizeof(Bool), inputInfo.numDevices); - if (!skip) - return BadAlloc; - - for (dev = inputInfo.devices; dev; dev = dev->next, i++) - { - skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev); - if (!skip[i]) - len += SizeDeviceInfo(dev); - } - - for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) - { - skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev); - if (!skip[i]) - len += SizeDeviceInfo(dev); - } - } - - info = xcalloc(1, len); - if (!info) - return BadAlloc; - - memset(&rep, 0, sizeof(xXIQueryDeviceReply)); - rep.repType = X_Reply; - rep.RepType = X_XIQueryDevice; - rep.sequenceNumber = client->sequence; - rep.length = len/4; - rep.num_devices = 0; - - ptr = info; - if (dev) - { - len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); - if (client->swapped) - SwapDeviceInfo(dev, (xXIDeviceInfo*)info); - info += len; - rep.num_devices = 1; - } else - { - i = 0; - for (dev = inputInfo.devices; dev; dev = dev->next, i++) - { - if (!skip[i]) - { - len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); - if (client->swapped) - SwapDeviceInfo(dev, (xXIDeviceInfo*)info); - info += len; - rep.num_devices++; - } - } - - for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) - { - if (!skip[i]) - { - len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); - if (client->swapped) - SwapDeviceInfo(dev, (xXIDeviceInfo*)info); - info += len; - rep.num_devices++; - } - } - } - - WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep); - WriteToClient(client, rep.length * 4, ptr); - xfree(ptr); - xfree(skip); - return rc; -} - -void -SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply *rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->num_devices, n); - - /* Device info is already swapped, see ProcXIQueryDevice */ - - WriteToClient(client, size, (char *)rep); -} - - -/** - * @return Whether the device should be included in the returned list. - */ -static Bool -ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr dev) -{ - /* if all devices are not being queried, only master devices are */ - if (deviceid == XIAllDevices || IsMaster(dev)) - { - int rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); - if (rc == Success) - return FALSE; - } - return TRUE; -} - -/** - * @return The number of bytes needed to store this device's xXIDeviceInfo - * (and its classes). - */ -static int -SizeDeviceInfo(DeviceIntPtr dev) -{ - int len = sizeof(xXIDeviceInfo); - - /* 4-padded name */ - len += pad_to_int32(strlen(dev->name)); - - return len + SizeDeviceClasses(dev); - -} - -/* - * @return The number of bytes needed to store this device's classes. - */ -int -SizeDeviceClasses(DeviceIntPtr dev) -{ - int len = 0; - - if (dev->button) - { - len += sizeof(xXIButtonInfo); - len += dev->button->numButtons * sizeof(Atom); - len += pad_to_int32(bits_to_bytes(dev->button->numButtons)); - } - - if (dev->key) - { - XkbDescPtr xkb = dev->key->xkbInfo->desc; - len += sizeof(xXIKeyInfo); - len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t); - } - - if (dev->valuator) - len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; - - return len; -} - - -/** - * Write button information into info. - * @return Number of bytes written into info. - */ -int -ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info, Bool reportState) -{ - unsigned char *bits; - int mask_len; - int i; - - if (!dev || !dev->button) - return 0; - - mask_len = bytes_to_int32(bits_to_bytes(dev->button->numButtons)); - - info->type = ButtonClass; - info->num_buttons = dev->button->numButtons; - info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + - info->num_buttons + mask_len; - info->sourceid = dev->button->sourceid; - - bits = (unsigned char*)&info[1]; - memset(bits, 0, mask_len * 4); - - if (reportState) - for (i = 0; i < dev->button->numButtons; i++) - if (BitIsOn(dev->button->down, i)) - SetBit(bits, i); - - bits += mask_len * 4; - memcpy(bits, dev->button->labels, dev->button->numButtons * sizeof(Atom)); - - return info->length * 4; -} - -static void -SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info) -{ - char n; - Atom *btn; - int i; - swaps(&info->type, n); - swaps(&info->length, n); - swaps(&info->sourceid, n); - - for (i = 0, btn = (Atom*)&info[1]; i < info->num_buttons; i++, btn++) - swaps(btn, n); - - swaps(&info->num_buttons, n); -} - -/** - * Write key information into info. - * @return Number of bytes written into info. - */ -int -ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) -{ - int i; - XkbDescPtr xkb = dev->key->xkbInfo->desc; - uint32_t *kc; - - info->type = KeyClass; - info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1; - info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes; - info->sourceid = dev->key->sourceid; - - kc = (uint32_t*)&info[1]; - for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++) - *kc = i; - - return info->length * 4; -} - -static void -SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) -{ - char n; - uint32_t *key; - int i; - swaps(&info->type, n); - swaps(&info->length, n); - swaps(&info->sourceid, n); - - for (i = 0, key = (uint32_t*)&info[1]; i < info->num_keycodes; i++, key++) - swapl(key, n); - - swaps(&info->num_keycodes, n); -} - -/** - * List axis information for the given axis. - * - * @return The number of bytes written into info. - */ -int -ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, int axisnumber, - Bool reportState) -{ - ValuatorClassPtr v = dev->valuator; - - info->type = ValuatorClass; - info->length = sizeof(xXIValuatorInfo)/4; - info->label = v->axes[axisnumber].label; - info->min.integral = v->axes[axisnumber].min_value; - info->min.frac = 0; - info->max.integral = v->axes[axisnumber].max_value; - info->max.frac = 0; - info->value.integral = (int)v->axisVal[axisnumber]; - info->value.frac = (int)(v->axisVal[axisnumber] * (1 << 16) * (1 << 16)); - info->resolution = v->axes[axisnumber].resolution; - info->number = axisnumber; - info->mode = v->mode; /* Server doesn't have per-axis mode yet */ - info->sourceid = v->sourceid; - - if (!reportState) - info->value = info->min; - - return info->length * 4; -} - -static void -SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info) -{ - char n; - swaps(&info->type, n); - swaps(&info->length, n); - swapl(&info->label, n); - swapl(&info->min.integral, n); - swapl(&info->min.frac, n); - swapl(&info->max.integral, n); - swapl(&info->max.frac, n); - swaps(&info->number, n); - swaps(&info->sourceid, n); -} - -int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment) -{ - DeviceIntPtr master = dev->u.master; - int use; - - if (IsMaster(dev)) - { - DeviceIntPtr paired = GetPairedDevice(dev); - use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard; - *attachment = (paired ? paired->id : 0); - } else if (master) - { - use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard; - *attachment = master->id; - } else - use = XIFloatingSlave; - - return use; -} - -/** - * Write the info for device dev into the buffer pointed to by info. - * - * @return The number of bytes used. - */ -static int -ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info) -{ - char *any = (char*)&info[1]; - int len = 0, total_len = 0; - - info->deviceid = dev->id; - info->use = GetDeviceUse(dev, &info->attachment); - info->num_classes = 0; - info->name_len = strlen(dev->name); - info->enabled = dev->enabled; - total_len = sizeof(xXIDeviceInfo); - - len = pad_to_int32(info->name_len); - memset(any, 0, len); - strncpy(any, dev->name, info->name_len); - any += len; - total_len += len; - - total_len += ListDeviceClasses(client, dev, any, &info->num_classes); - return total_len; -} - -/** - * Write the class info of the device into the memory pointed to by any, set - * nclasses to the number of classes in total and return the number of bytes - * written. - */ -int -ListDeviceClasses(ClientPtr client, DeviceIntPtr dev, - char *any, uint16_t *nclasses) -{ - int total_len = 0; - int len; - int i; - int rc; - - /* Check if the current device state should be suppressed */ - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess); - - if (dev->button) - { - (*nclasses)++; - len = ListButtonInfo(dev, (xXIButtonInfo*)any, rc == Success); - any += len; - total_len += len; - } - - if (dev->key) - { - (*nclasses)++; - len = ListKeyInfo(dev, (xXIKeyInfo*)any); - any += len; - total_len += len; - } - - for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) - { - (*nclasses)++; - len = ListValuatorInfo(dev, (xXIValuatorInfo*)any, i, rc == Success); - any += len; - total_len += len; - } - - return total_len; -} - -static void -SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) -{ - char n; - char *any = (char*)&info[1]; - int i; - - /* Skip over name */ - any += pad_to_int32(info->name_len); - - for (i = 0; i < info->num_classes; i++) - { - int len = ((xXIAnyInfo*)any)->length; - switch(((xXIAnyInfo*)any)->type) - { - case XIButtonClass: - SwapButtonInfo(dev, (xXIButtonInfo*)any); - break; - case XIKeyClass: - SwapKeyInfo(dev, (xXIKeyInfo*)any); - break; - case XIValuatorClass: - SwapValuatorInfo(dev, (xXIValuatorInfo*)any); - break; - } - - any += len * 4; - } - - swaps(&info->deviceid, n); - swaps(&info->use, n); - swaps(&info->attachment, n); - swaps(&info->num_classes, n); - swaps(&info->name_len, n); - -} +/* + * Copyright © 2009 Red Hat, Inc. + * + * 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. + * + * Authors: Peter Hutterer + * + */ + +/** + * @file Protocol handling for the XIQueryDevice request/reply. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" +#include +#include +#include +#include "xkbstr.h" +#include "xkbsrv.h" +#include "xserver-properties.h" +#include "exevents.h" +#include "xace.h" + +#include "xiquerydevice.h" + +static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d); +static int +ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info); +static int SizeDeviceInfo(DeviceIntPtr dev); +static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info); +int +SProcXIQueryDevice(ClientPtr client) +{ + char n; + + REQUEST(xXIQueryDeviceReq); + + swaps(&stuff->length, n); + swaps(&stuff->deviceid, n); + + return ProcXIQueryDevice(client); +} + +int +ProcXIQueryDevice(ClientPtr client) +{ + xXIQueryDeviceReply rep; + DeviceIntPtr dev = NULL; + int rc = Success; + int i = 0, len = 0; + char *info, *ptr; + Bool *skip = NULL; + + REQUEST(xXIQueryDeviceReq); + REQUEST_SIZE_MATCH(xXIQueryDeviceReq); + + if (stuff->deviceid != XIAllDevices && stuff->deviceid != XIAllMasterDevices) + { + rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); + if (rc != Success) + { + client->errorValue = stuff->deviceid; + return rc; + } + len += SizeDeviceInfo(dev); + } + else + { + skip = calloc(sizeof(Bool), inputInfo.numDevices); + if (!skip) + return BadAlloc; + + for (dev = inputInfo.devices; dev; dev = dev->next, i++) + { + skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev); + if (!skip[i]) + len += SizeDeviceInfo(dev); + } + + for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) + { + skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev); + if (!skip[i]) + len += SizeDeviceInfo(dev); + } + } + + info = calloc(1, len); + if (!info) + return BadAlloc; + + memset(&rep, 0, sizeof(xXIQueryDeviceReply)); + rep.repType = X_Reply; + rep.RepType = X_XIQueryDevice; + rep.sequenceNumber = client->sequence; + rep.length = len/4; + rep.num_devices = 0; + + ptr = info; + if (dev) + { + len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); + if (client->swapped) + SwapDeviceInfo(dev, (xXIDeviceInfo*)info); + info += len; + rep.num_devices = 1; + } else + { + i = 0; + for (dev = inputInfo.devices; dev; dev = dev->next, i++) + { + if (!skip[i]) + { + len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); + if (client->swapped) + SwapDeviceInfo(dev, (xXIDeviceInfo*)info); + info += len; + rep.num_devices++; + } + } + + for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) + { + if (!skip[i]) + { + len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); + if (client->swapped) + SwapDeviceInfo(dev, (xXIDeviceInfo*)info); + info += len; + rep.num_devices++; + } + } + } + + WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep); + WriteToClient(client, rep.length * 4, ptr); + free(ptr); + free(skip); + return rc; +} + +void +SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply *rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->num_devices, n); + + /* Device info is already swapped, see ProcXIQueryDevice */ + + WriteToClient(client, size, (char *)rep); +} + + +/** + * @return Whether the device should be included in the returned list. + */ +static Bool +ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr dev) +{ + /* if all devices are not being queried, only master devices are */ + if (deviceid == XIAllDevices || IsMaster(dev)) + { + int rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); + if (rc == Success) + return FALSE; + } + return TRUE; +} + +/** + * @return The number of bytes needed to store this device's xXIDeviceInfo + * (and its classes). + */ +static int +SizeDeviceInfo(DeviceIntPtr dev) +{ + int len = sizeof(xXIDeviceInfo); + + /* 4-padded name */ + len += pad_to_int32(strlen(dev->name)); + + return len + SizeDeviceClasses(dev); + +} + +/* + * @return The number of bytes needed to store this device's classes. + */ +int +SizeDeviceClasses(DeviceIntPtr dev) +{ + int len = 0; + + if (dev->button) + { + len += sizeof(xXIButtonInfo); + len += dev->button->numButtons * sizeof(Atom); + len += pad_to_int32(bits_to_bytes(dev->button->numButtons)); + } + + if (dev->key) + { + XkbDescPtr xkb = dev->key->xkbInfo->desc; + len += sizeof(xXIKeyInfo); + len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t); + } + + if (dev->valuator) + len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; + + return len; +} + + +/** + * Write button information into info. + * @return Number of bytes written into info. + */ +int +ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info, Bool reportState) +{ + unsigned char *bits; + int mask_len; + int i; + + if (!dev || !dev->button) + return 0; + + mask_len = bytes_to_int32(bits_to_bytes(dev->button->numButtons)); + + info->type = ButtonClass; + info->num_buttons = dev->button->numButtons; + info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + + info->num_buttons + mask_len; + info->sourceid = dev->button->sourceid; + + bits = (unsigned char*)&info[1]; + memset(bits, 0, mask_len * 4); + + if (reportState) + for (i = 0; i < dev->button->numButtons; i++) + if (BitIsOn(dev->button->down, i)) + SetBit(bits, i); + + bits += mask_len * 4; + memcpy(bits, dev->button->labels, dev->button->numButtons * sizeof(Atom)); + + return info->length * 4; +} + +static void +SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info) +{ + char n; + Atom *btn; + int i; + swaps(&info->type, n); + swaps(&info->length, n); + swaps(&info->sourceid, n); + + for (i = 0, btn = (Atom*)&info[1]; i < info->num_buttons; i++, btn++) + swaps(btn, n); + + swaps(&info->num_buttons, n); +} + +/** + * Write key information into info. + * @return Number of bytes written into info. + */ +int +ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) +{ + int i; + XkbDescPtr xkb = dev->key->xkbInfo->desc; + uint32_t *kc; + + info->type = KeyClass; + info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1; + info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes; + info->sourceid = dev->key->sourceid; + + kc = (uint32_t*)&info[1]; + for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++) + *kc = i; + + return info->length * 4; +} + +static void +SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) +{ + char n; + uint32_t *key; + int i; + swaps(&info->type, n); + swaps(&info->length, n); + swaps(&info->sourceid, n); + + for (i = 0, key = (uint32_t*)&info[1]; i < info->num_keycodes; i++, key++) + swapl(key, n); + + swaps(&info->num_keycodes, n); +} + +/** + * List axis information for the given axis. + * + * @return The number of bytes written into info. + */ +int +ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, int axisnumber, + Bool reportState) +{ + ValuatorClassPtr v = dev->valuator; + + info->type = ValuatorClass; + info->length = sizeof(xXIValuatorInfo)/4; + info->label = v->axes[axisnumber].label; + info->min.integral = v->axes[axisnumber].min_value; + info->min.frac = 0; + info->max.integral = v->axes[axisnumber].max_value; + info->max.frac = 0; + info->value.integral = (int)v->axisVal[axisnumber]; + info->value.frac = (int)(v->axisVal[axisnumber] * (1 << 16) * (1 << 16)); + info->resolution = v->axes[axisnumber].resolution; + info->number = axisnumber; + info->mode = v->mode; /* Server doesn't have per-axis mode yet */ + info->sourceid = v->sourceid; + + if (!reportState) + info->value = info->min; + + return info->length * 4; +} + +static void +SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info) +{ + char n; + swaps(&info->type, n); + swaps(&info->length, n); + swapl(&info->label, n); + swapl(&info->min.integral, n); + swapl(&info->min.frac, n); + swapl(&info->max.integral, n); + swapl(&info->max.frac, n); + swaps(&info->number, n); + swaps(&info->sourceid, n); +} + +int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment) +{ + DeviceIntPtr master = dev->u.master; + int use; + + if (IsMaster(dev)) + { + DeviceIntPtr paired = GetPairedDevice(dev); + use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard; + *attachment = (paired ? paired->id : 0); + } else if (master) + { + use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard; + *attachment = master->id; + } else + use = XIFloatingSlave; + + return use; +} + +/** + * Write the info for device dev into the buffer pointed to by info. + * + * @return The number of bytes used. + */ +static int +ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info) +{ + char *any = (char*)&info[1]; + int len = 0, total_len = 0; + + info->deviceid = dev->id; + info->use = GetDeviceUse(dev, &info->attachment); + info->num_classes = 0; + info->name_len = strlen(dev->name); + info->enabled = dev->enabled; + total_len = sizeof(xXIDeviceInfo); + + len = pad_to_int32(info->name_len); + memset(any, 0, len); + strncpy(any, dev->name, info->name_len); + any += len; + total_len += len; + + total_len += ListDeviceClasses(client, dev, any, &info->num_classes); + return total_len; +} + +/** + * Write the class info of the device into the memory pointed to by any, set + * nclasses to the number of classes in total and return the number of bytes + * written. + */ +int +ListDeviceClasses(ClientPtr client, DeviceIntPtr dev, + char *any, uint16_t *nclasses) +{ + int total_len = 0; + int len; + int i; + int rc; + + /* Check if the current device state should be suppressed */ + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess); + + if (dev->button) + { + (*nclasses)++; + len = ListButtonInfo(dev, (xXIButtonInfo*)any, rc == Success); + any += len; + total_len += len; + } + + if (dev->key) + { + (*nclasses)++; + len = ListKeyInfo(dev, (xXIKeyInfo*)any); + any += len; + total_len += len; + } + + for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) + { + (*nclasses)++; + len = ListValuatorInfo(dev, (xXIValuatorInfo*)any, i, rc == Success); + any += len; + total_len += len; + } + + return total_len; +} + +static void +SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) +{ + char n; + char *any = (char*)&info[1]; + int i; + + /* Skip over name */ + any += pad_to_int32(info->name_len); + + for (i = 0; i < info->num_classes; i++) + { + int len = ((xXIAnyInfo*)any)->length; + switch(((xXIAnyInfo*)any)->type) + { + case XIButtonClass: + SwapButtonInfo(dev, (xXIButtonInfo*)any); + break; + case XIKeyClass: + SwapKeyInfo(dev, (xXIKeyInfo*)any); + break; + case XIValuatorClass: + SwapValuatorInfo(dev, (xXIValuatorInfo*)any); + break; + } + + any += len * 4; + } + + swaps(&info->deviceid, n); + swaps(&info->use, n); + swaps(&info->attachment, n); + swaps(&info->num_classes, n); + swaps(&info->name_len, n); + +} diff --git a/xorg-server/Xi/xiquerypointer.c b/xorg-server/Xi/xiquerypointer.c index 93ceba4c3..a5855bef3 100644 --- a/xorg-server/Xi/xiquerypointer.c +++ b/xorg-server/Xi/xiquerypointer.c @@ -1,228 +1,228 @@ -/* - * Copyright 2007-2008 Peter Hutterer - * - * 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. - * - * Author: Peter Hutterer, University of South Australia, NICTA - */ - -/*********************************************************************** - * - * Request to query the pointer location of an extension input device. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include /* for inputstr.h */ -#include /* Request macro */ -#include "inputstr.h" /* DeviceIntPtr */ -#include "windowstr.h" /* window structure */ -#include -#include -#include "extnsionst.h" -#include "exevents.h" -#include "exglobals.h" -#include "eventconvert.h" -#include "xkbsrv.h" - -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -#include "xiquerypointer.h" - -/*********************************************************************** - * - * This procedure allows a client to query the pointer of a device. - * - */ - -int -SProcXIQueryPointer(ClientPtr client) -{ - char n; - - REQUEST(xXIQueryPointerReq); - swaps(&stuff->length, n); - swaps(&stuff->deviceid, n); - swapl(&stuff->win, n); - return (ProcXIQueryPointer(client)); -} - -int -ProcXIQueryPointer(ClientPtr client) -{ - int rc; - xXIQueryPointerReply rep; - DeviceIntPtr pDev, kbd; - WindowPtr pWin, t; - SpritePtr pSprite; - XkbStatePtr state; - char *buttons = NULL; - int buttons_size = 0; /* size of buttons array */ - - REQUEST(xXIQueryPointerReq); - REQUEST_SIZE_MATCH(xXIQueryPointerReq); - - rc = dixLookupDevice(&pDev, stuff->deviceid, client, DixReadAccess); - if (rc != Success) - { - client->errorValue = stuff->deviceid; - return rc; - } - - if (pDev->valuator == NULL || IsKeyboardDevice(pDev) || - (!IsMaster(pDev) && pDev->u.master)) /* no attached devices */ - { - client->errorValue = stuff->deviceid; - return BadDevice; - } - - rc = dixLookupWindow(&pWin, stuff->win, client, DixGetAttrAccess); - if (rc != Success) - { - SendErrorToClient(client, IReqCode, X_XIQueryPointer, - stuff->win, rc); - return Success; - } - - if (pDev->valuator->motionHintWindow) - MaybeStopHint(pDev, client); - - if (IsMaster(pDev)) - kbd = GetPairedDevice(pDev); - else - kbd = (pDev->key) ? pDev : NULL; - - pSprite = pDev->spriteInfo->sprite; - - memset(&rep, 0, sizeof(rep)); - rep.repType = X_Reply; - rep.RepType = X_XIQueryPointer; - rep.length = 6; - rep.sequenceNumber = client->sequence; - rep.root = (GetCurrentRootWindow(pDev))->drawable.id; - rep.root_x = FP1616(pSprite->hot.x, 0); - rep.root_y = FP1616(pSprite->hot.y, 0); - rep.child = None; - - if (kbd) - { - state = &kbd->key->xkbInfo->prev_state; - rep.mods.base_mods = state->base_mods; - rep.mods.latched_mods = state->latched_mods; - rep.mods.locked_mods = state->locked_mods; - - rep.group.base_group = state->base_group; - rep.group.latched_group = state->latched_group; - rep.group.locked_group = state->locked_group; - } - - if (pDev->button) - { - int i, down; - rep.buttons_len = bytes_to_int32(bits_to_bytes(pDev->button->numButtons)); - rep.length += rep.buttons_len; - buttons_size = rep.buttons_len * 4; - buttons = xcalloc(1, buttons_size); - if (!buttons) - return BadAlloc; - - down = pDev->button->buttonsDown; - - for (i = 0; i < pDev->button->numButtons && down; i++) - { - if (BitIsOn(pDev->button->down, i)) - { - SetBit(buttons, i); - down--; - } - } - } else - rep.buttons_len = 0; - - if (pSprite->hot.pScreen == pWin->drawable.pScreen) - { - rep.same_screen = xTrue; - rep.win_x = FP1616(pSprite->hot.x - pWin->drawable.x, 0); - rep.win_y = FP1616(pSprite->hot.y - pWin->drawable.y, 0); - for (t = pSprite->win; t; t = t->parent) - if (t->parent == pWin) - { - rep.child = t->drawable.id; - break; - } - } else - { - rep.same_screen = xFalse; - rep.win_x = 0; - rep.win_y = 0; - } - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - rep.root_x += FP1616(panoramiXdataPtr[0].x, 0); - rep.root_y += FP1616(panoramiXdataPtr[0].y, 0); - if (stuff->win == rep.root) - { - rep.win_x += FP1616(panoramiXdataPtr[0].x, 0); - rep.win_y += FP1616(panoramiXdataPtr[0].y, 0); - } - } -#endif - - WriteReplyToClient(client, sizeof(xXIQueryPointerReply), &rep); - if (buttons) - WriteToClient(client, buttons_size, buttons); - - xfree(buttons); - - return Success; -} - -/*********************************************************************** - * - * This procedure writes the reply for the XIQueryPointer function, - * if the client and server have a different byte ordering. - * - */ - -void -SRepXIQueryPointer(ClientPtr client, int size, - xXIQueryPointerReply * rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swapl(&rep->root, n); - swapl(&rep->child, n); - swapl(&rep->root_x, n); - swapl(&rep->root_y, n); - swapl(&rep->win_x, n); - swapl(&rep->win_y, n); - swaps(&rep->buttons_len, n); - - WriteToClient(client, size, (char *)rep); -} - +/* + * Copyright 2007-2008 Peter Hutterer + * + * 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. + * + * Author: Peter Hutterer, University of South Australia, NICTA + */ + +/*********************************************************************** + * + * Request to query the pointer location of an extension input device. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include /* for inputstr.h */ +#include /* Request macro */ +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window structure */ +#include +#include +#include "extnsionst.h" +#include "exevents.h" +#include "exglobals.h" +#include "eventconvert.h" +#include "xkbsrv.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +#include "xiquerypointer.h" + +/*********************************************************************** + * + * This procedure allows a client to query the pointer of a device. + * + */ + +int +SProcXIQueryPointer(ClientPtr client) +{ + char n; + + REQUEST(xXIQueryPointerReq); + swaps(&stuff->length, n); + swaps(&stuff->deviceid, n); + swapl(&stuff->win, n); + return (ProcXIQueryPointer(client)); +} + +int +ProcXIQueryPointer(ClientPtr client) +{ + int rc; + xXIQueryPointerReply rep; + DeviceIntPtr pDev, kbd; + WindowPtr pWin, t; + SpritePtr pSprite; + XkbStatePtr state; + char *buttons = NULL; + int buttons_size = 0; /* size of buttons array */ + + REQUEST(xXIQueryPointerReq); + REQUEST_SIZE_MATCH(xXIQueryPointerReq); + + rc = dixLookupDevice(&pDev, stuff->deviceid, client, DixReadAccess); + if (rc != Success) + { + client->errorValue = stuff->deviceid; + return rc; + } + + if (pDev->valuator == NULL || IsKeyboardDevice(pDev) || + (!IsMaster(pDev) && pDev->u.master)) /* no attached devices */ + { + client->errorValue = stuff->deviceid; + return BadDevice; + } + + rc = dixLookupWindow(&pWin, stuff->win, client, DixGetAttrAccess); + if (rc != Success) + { + SendErrorToClient(client, IReqCode, X_XIQueryPointer, + stuff->win, rc); + return Success; + } + + if (pDev->valuator->motionHintWindow) + MaybeStopHint(pDev, client); + + if (IsMaster(pDev)) + kbd = GetPairedDevice(pDev); + else + kbd = (pDev->key) ? pDev : NULL; + + pSprite = pDev->spriteInfo->sprite; + + memset(&rep, 0, sizeof(rep)); + rep.repType = X_Reply; + rep.RepType = X_XIQueryPointer; + rep.length = 6; + rep.sequenceNumber = client->sequence; + rep.root = (GetCurrentRootWindow(pDev))->drawable.id; + rep.root_x = FP1616(pSprite->hot.x, 0); + rep.root_y = FP1616(pSprite->hot.y, 0); + rep.child = None; + + if (kbd) + { + state = &kbd->key->xkbInfo->prev_state; + rep.mods.base_mods = state->base_mods; + rep.mods.latched_mods = state->latched_mods; + rep.mods.locked_mods = state->locked_mods; + + rep.group.base_group = state->base_group; + rep.group.latched_group = state->latched_group; + rep.group.locked_group = state->locked_group; + } + + if (pDev->button) + { + int i, down; + rep.buttons_len = bytes_to_int32(bits_to_bytes(pDev->button->numButtons)); + rep.length += rep.buttons_len; + buttons_size = rep.buttons_len * 4; + buttons = calloc(1, buttons_size); + if (!buttons) + return BadAlloc; + + down = pDev->button->buttonsDown; + + for (i = 0; i < pDev->button->numButtons && down; i++) + { + if (BitIsOn(pDev->button->down, i)) + { + SetBit(buttons, i); + down--; + } + } + } else + rep.buttons_len = 0; + + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + rep.same_screen = xTrue; + rep.win_x = FP1616(pSprite->hot.x - pWin->drawable.x, 0); + rep.win_y = FP1616(pSprite->hot.y - pWin->drawable.y, 0); + for (t = pSprite->win; t; t = t->parent) + if (t->parent == pWin) + { + rep.child = t->drawable.id; + break; + } + } else + { + rep.same_screen = xFalse; + rep.win_x = 0; + rep.win_y = 0; + } + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + rep.root_x += FP1616(panoramiXdataPtr[0].x, 0); + rep.root_y += FP1616(panoramiXdataPtr[0].y, 0); + if (stuff->win == rep.root) + { + rep.win_x += FP1616(panoramiXdataPtr[0].x, 0); + rep.win_y += FP1616(panoramiXdataPtr[0].y, 0); + } + } +#endif + + WriteReplyToClient(client, sizeof(xXIQueryPointerReply), &rep); + if (buttons) + WriteToClient(client, buttons_size, buttons); + + free(buttons); + + return Success; +} + +/*********************************************************************** + * + * This procedure writes the reply for the XIQueryPointer function, + * if the client and server have a different byte ordering. + * + */ + +void +SRepXIQueryPointer(ClientPtr client, int size, + xXIQueryPointerReply * rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swapl(&rep->root, n); + swapl(&rep->child, n); + swapl(&rep->root_x, n); + swapl(&rep->root_y, n); + swapl(&rep->win_x, n); + swapl(&rep->win_y, n); + swaps(&rep->buttons_len, n); + + WriteToClient(client, size, (char *)rep); +} + diff --git a/xorg-server/Xi/xiselectev.c b/xorg-server/Xi/xiselectev.c index 672edab3b..6a810bce4 100644 --- a/xorg-server/Xi/xiselectev.c +++ b/xorg-server/Xi/xiselectev.c @@ -1,299 +1,299 @@ -/* - * Copyright 2008 Red Hat, Inc. - * - * 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. - * - * Author: Peter Hutterer - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - - -#include "dixstruct.h" -#include "windowstr.h" -#include "exglobals.h" -#include "exevents.h" -#include - -#include "xiselectev.h" - -/** - * Check the given mask (in len bytes) for invalid mask bits. - * Invalid mask bits are any bits above XI2LastEvent. - * - * @return BadValue if at least one invalid bit is set or Success otherwise. - */ -int XICheckInvalidMaskBits(unsigned char *mask, int len) -{ - if (len >= XIMaskLen(XI2LASTEVENT)) - { - int i; - for (i = XI2LASTEVENT + 1; i < len * 8; i++) - if (BitIsOn(mask, i)) - return BadValue; - } - - return Success; -} - -int -SProcXISelectEvents(ClientPtr client) -{ - char n; - int i; - xXIEventMask* evmask; - - REQUEST(xXISelectEventsReq); - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xXISelectEventsReq); - swapl(&stuff->win, n); - swaps(&stuff->num_masks, n); - - evmask = (xXIEventMask*)&stuff[1]; - for (i = 0; i < stuff->num_masks; i++) - { - swaps(&evmask->deviceid, n); - swaps(&evmask->mask_len, n); - evmask = (xXIEventMask*)(((char*)&evmask[1]) + evmask->mask_len * 4); - } - - return (ProcXISelectEvents(client)); -} - -int -ProcXISelectEvents(ClientPtr client) -{ - int rc, num_masks; - WindowPtr win; - DeviceIntPtr dev; - DeviceIntRec dummy; - xXIEventMask *evmask; - int *types = NULL; - int len; - - REQUEST(xXISelectEventsReq); - REQUEST_AT_LEAST_SIZE(xXISelectEventsReq); - - if (stuff->num_masks == 0) - return BadValue; - - rc = dixLookupWindow(&win, stuff->win, client, DixReceiveAccess); - if (rc != Success) - return rc; - - len = sz_xXISelectEventsReq; - - /* check request validity */ - evmask = (xXIEventMask*)&stuff[1]; - num_masks = stuff->num_masks; - while(num_masks--) - { - len += sizeof(xXIEventMask) + evmask->mask_len * 4; - - if (bytes_to_int32(len) > stuff->length) - return BadLength; - - if (evmask->deviceid != XIAllDevices && - evmask->deviceid != XIAllMasterDevices) - rc = dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess); - else { - /* XXX: XACE here? */ - } - if (rc != Success) - return rc; - - /* hierarchy event mask is not allowed on devices */ - if (evmask->deviceid != XIAllDevices && evmask->mask_len >= 1) - { - unsigned char *bits = (unsigned char*)&evmask[1]; - if (BitIsOn(bits, XI_HierarchyChanged)) - return BadValue; - } - - /* Raw events may only be selected on root windows */ - if (win->parent && evmask->mask_len >= 1) - { - unsigned char *bits = (unsigned char*)&evmask[1]; - if (BitIsOn(bits, XI_RawKeyPress) || - BitIsOn(bits, XI_RawKeyRelease) || - BitIsOn(bits, XI_RawButtonPress) || - BitIsOn(bits, XI_RawButtonRelease) || - BitIsOn(bits, XI_RawMotion)) - return BadValue; - } - - if (XICheckInvalidMaskBits((unsigned char*)&evmask[1], - evmask->mask_len * 4) != Success) - return BadValue; - - evmask = (xXIEventMask*)(((unsigned char*)evmask) + evmask->mask_len * 4); - evmask++; - } - - if (bytes_to_int32(len) != stuff->length) - return BadLength; - - /* Set masks on window */ - evmask = (xXIEventMask*)&stuff[1]; - num_masks = stuff->num_masks; - while(num_masks--) - { - if (evmask->deviceid == XIAllDevices || - evmask->deviceid == XIAllMasterDevices) - { - dummy.id = evmask->deviceid; - dev = &dummy; - } else - dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess); - if (XISetEventMask(dev, win, client, evmask->mask_len * 4, - (unsigned char*)&evmask[1]) != Success) - return BadAlloc; - evmask = (xXIEventMask*)(((unsigned char*)evmask) + evmask->mask_len * 4); - evmask++; - } - - RecalculateDeliverableEvents(win); - - xfree(types); - return Success; -} - - -int -SProcXIGetSelectedEvents(ClientPtr client) -{ - char n; - - REQUEST(xXIGetSelectedEventsReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq); - swapl(&stuff->win, n); - - return (ProcXIGetSelectedEvents(client)); -} - -int -ProcXIGetSelectedEvents(ClientPtr client) -{ - int rc, i; - WindowPtr win; - char n; - char *buffer = NULL; - xXIGetSelectedEventsReply reply; - OtherInputMasks *masks; - InputClientsPtr others = NULL; - xXIEventMask *evmask = NULL; - DeviceIntPtr dev; - - REQUEST(xXIGetSelectedEventsReq); - REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq); - - rc = dixLookupWindow(&win, stuff->win, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - reply.repType = X_Reply; - reply.RepType = X_XIGetSelectedEvents; - reply.length = 0; - reply.sequenceNumber = client->sequence; - reply.num_masks = 0; - - masks = wOtherInputMasks(win); - if (masks) - { - for (others = wOtherInputMasks(win)->inputClients; others; - others = others->next) { - if (SameClient(others, client)) { - break; - } - } - } - - if (!others) - { - WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply); - return Success; - } - - buffer = xcalloc(MAXDEVICES, sizeof(xXIEventMask) + pad_to_int32(XI2MASKSIZE)); - if (!buffer) - return BadAlloc; - - evmask = (xXIEventMask*)buffer; - for (i = 0; i < MAXDEVICES; i++) - { - int j; - unsigned char *devmask = others->xi2mask[i]; - - if (i > 2) - { - rc = dixLookupDevice(&dev, i, client, DixGetAttrAccess); - if (rc != Success) - continue; - } - - - for (j = XI2MASKSIZE - 1; j >= 0; j--) - { - if (devmask[j] != 0) - { - int mask_len = (j + 4)/4; /* j is an index, hence + 4, not + 3 */ - evmask->deviceid = i; - evmask->mask_len = mask_len; - reply.num_masks++; - reply.length += sizeof(xXIEventMask)/4 + evmask->mask_len; - - if (client->swapped) - { - swaps(&evmask->deviceid, n); - swaps(&evmask->mask_len, n); - } - - memcpy(&evmask[1], devmask, j + 1); - evmask = (xXIEventMask*)((char*)evmask + - sizeof(xXIEventMask) + mask_len * 4); - break; - } - } - } - - WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply); - - if (reply.num_masks) - WriteToClient(client, reply.length * 4, buffer); - - xfree(buffer); - return Success; -} - -void SRepXIGetSelectedEvents(ClientPtr client, - int len, xXIGetSelectedEventsReply *rep) -{ - char n; - - swaps(&rep->sequenceNumber, n); - swapl(&rep->length, n); - swaps(&rep->num_masks, n); - WriteToClient(client, len, (char *)rep); -} - - +/* + * Copyright 2008 Red Hat, Inc. + * + * 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. + * + * Author: Peter Hutterer + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + + +#include "dixstruct.h" +#include "windowstr.h" +#include "exglobals.h" +#include "exevents.h" +#include + +#include "xiselectev.h" + +/** + * Check the given mask (in len bytes) for invalid mask bits. + * Invalid mask bits are any bits above XI2LastEvent. + * + * @return BadValue if at least one invalid bit is set or Success otherwise. + */ +int XICheckInvalidMaskBits(unsigned char *mask, int len) +{ + if (len >= XIMaskLen(XI2LASTEVENT)) + { + int i; + for (i = XI2LASTEVENT + 1; i < len * 8; i++) + if (BitIsOn(mask, i)) + return BadValue; + } + + return Success; +} + +int +SProcXISelectEvents(ClientPtr client) +{ + char n; + int i; + xXIEventMask* evmask; + + REQUEST(xXISelectEventsReq); + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXISelectEventsReq); + swapl(&stuff->win, n); + swaps(&stuff->num_masks, n); + + evmask = (xXIEventMask*)&stuff[1]; + for (i = 0; i < stuff->num_masks; i++) + { + swaps(&evmask->deviceid, n); + swaps(&evmask->mask_len, n); + evmask = (xXIEventMask*)(((char*)&evmask[1]) + evmask->mask_len * 4); + } + + return (ProcXISelectEvents(client)); +} + +int +ProcXISelectEvents(ClientPtr client) +{ + int rc, num_masks; + WindowPtr win; + DeviceIntPtr dev; + DeviceIntRec dummy; + xXIEventMask *evmask; + int *types = NULL; + int len; + + REQUEST(xXISelectEventsReq); + REQUEST_AT_LEAST_SIZE(xXISelectEventsReq); + + if (stuff->num_masks == 0) + return BadValue; + + rc = dixLookupWindow(&win, stuff->win, client, DixReceiveAccess); + if (rc != Success) + return rc; + + len = sz_xXISelectEventsReq; + + /* check request validity */ + evmask = (xXIEventMask*)&stuff[1]; + num_masks = stuff->num_masks; + while(num_masks--) + { + len += sizeof(xXIEventMask) + evmask->mask_len * 4; + + if (bytes_to_int32(len) > stuff->length) + return BadLength; + + if (evmask->deviceid != XIAllDevices && + evmask->deviceid != XIAllMasterDevices) + rc = dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess); + else { + /* XXX: XACE here? */ + } + if (rc != Success) + return rc; + + /* hierarchy event mask is not allowed on devices */ + if (evmask->deviceid != XIAllDevices && evmask->mask_len >= 1) + { + unsigned char *bits = (unsigned char*)&evmask[1]; + if (BitIsOn(bits, XI_HierarchyChanged)) + return BadValue; + } + + /* Raw events may only be selected on root windows */ + if (win->parent && evmask->mask_len >= 1) + { + unsigned char *bits = (unsigned char*)&evmask[1]; + if (BitIsOn(bits, XI_RawKeyPress) || + BitIsOn(bits, XI_RawKeyRelease) || + BitIsOn(bits, XI_RawButtonPress) || + BitIsOn(bits, XI_RawButtonRelease) || + BitIsOn(bits, XI_RawMotion)) + return BadValue; + } + + if (XICheckInvalidMaskBits((unsigned char*)&evmask[1], + evmask->mask_len * 4) != Success) + return BadValue; + + evmask = (xXIEventMask*)(((unsigned char*)evmask) + evmask->mask_len * 4); + evmask++; + } + + if (bytes_to_int32(len) != stuff->length) + return BadLength; + + /* Set masks on window */ + evmask = (xXIEventMask*)&stuff[1]; + num_masks = stuff->num_masks; + while(num_masks--) + { + if (evmask->deviceid == XIAllDevices || + evmask->deviceid == XIAllMasterDevices) + { + dummy.id = evmask->deviceid; + dev = &dummy; + } else + dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess); + if (XISetEventMask(dev, win, client, evmask->mask_len * 4, + (unsigned char*)&evmask[1]) != Success) + return BadAlloc; + evmask = (xXIEventMask*)(((unsigned char*)evmask) + evmask->mask_len * 4); + evmask++; + } + + RecalculateDeliverableEvents(win); + + free(types); + return Success; +} + + +int +SProcXIGetSelectedEvents(ClientPtr client) +{ + char n; + + REQUEST(xXIGetSelectedEventsReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq); + swapl(&stuff->win, n); + + return (ProcXIGetSelectedEvents(client)); +} + +int +ProcXIGetSelectedEvents(ClientPtr client) +{ + int rc, i; + WindowPtr win; + char n; + char *buffer = NULL; + xXIGetSelectedEventsReply reply; + OtherInputMasks *masks; + InputClientsPtr others = NULL; + xXIEventMask *evmask = NULL; + DeviceIntPtr dev; + + REQUEST(xXIGetSelectedEventsReq); + REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq); + + rc = dixLookupWindow(&win, stuff->win, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + reply.repType = X_Reply; + reply.RepType = X_XIGetSelectedEvents; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.num_masks = 0; + + masks = wOtherInputMasks(win); + if (masks) + { + for (others = wOtherInputMasks(win)->inputClients; others; + others = others->next) { + if (SameClient(others, client)) { + break; + } + } + } + + if (!others) + { + WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply); + return Success; + } + + buffer = calloc(MAXDEVICES, sizeof(xXIEventMask) + pad_to_int32(XI2MASKSIZE)); + if (!buffer) + return BadAlloc; + + evmask = (xXIEventMask*)buffer; + for (i = 0; i < MAXDEVICES; i++) + { + int j; + unsigned char *devmask = others->xi2mask[i]; + + if (i > 2) + { + rc = dixLookupDevice(&dev, i, client, DixGetAttrAccess); + if (rc != Success) + continue; + } + + + for (j = XI2MASKSIZE - 1; j >= 0; j--) + { + if (devmask[j] != 0) + { + int mask_len = (j + 4)/4; /* j is an index, hence + 4, not + 3 */ + evmask->deviceid = i; + evmask->mask_len = mask_len; + reply.num_masks++; + reply.length += sizeof(xXIEventMask)/4 + evmask->mask_len; + + if (client->swapped) + { + swaps(&evmask->deviceid, n); + swaps(&evmask->mask_len, n); + } + + memcpy(&evmask[1], devmask, j + 1); + evmask = (xXIEventMask*)((char*)evmask + + sizeof(xXIEventMask) + mask_len * 4); + break; + } + } + } + + WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply); + + if (reply.num_masks) + WriteToClient(client, reply.length * 4, buffer); + + free(buffer); + return Success; +} + +void SRepXIGetSelectedEvents(ClientPtr client, + int len, xXIGetSelectedEventsReply *rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->num_masks, n); + WriteToClient(client, len, (char *)rep); +} + + diff --git a/xorg-server/composite/compalloc.c b/xorg-server/composite/compalloc.c index 73adc72d0..e56a27e96 100644 --- a/xorg-server/composite/compalloc.c +++ b/xorg-server/composite/compalloc.c @@ -1,647 +1,648 @@ -/* - * Copyright © 2006 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, 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. - * - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "compint.h" - -static void -compReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) -{ - WindowPtr pWin = (WindowPtr) closure; - ScreenPtr pScreen = pWin->drawable.pScreen; - CompScreenPtr cs = GetCompScreen (pScreen); - CompWindowPtr cw = GetCompWindow (pWin); - - cs->damaged = TRUE; - cw->damaged = TRUE; -} - -static void -compDestroyDamage (DamagePtr pDamage, void *closure) -{ - WindowPtr pWin = (WindowPtr) closure; - CompWindowPtr cw = GetCompWindow (pWin); - - cw->damage = 0; -} - -/* - * Redirect one window for one client - */ -int -compRedirectWindow (ClientPtr pClient, WindowPtr pWin, int update) -{ - CompWindowPtr cw = GetCompWindow (pWin); - CompClientWindowPtr ccw; - Bool wasMapped = pWin->mapped; - CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen); - - if (pWin == cs->pOverlayWin) { - return Success; - } - - if (!pWin->parent) - return BadMatch; - - /* - * Only one Manual update is allowed - */ - if (cw && update == CompositeRedirectManual) - for (ccw = cw->clients; ccw; ccw = ccw->next) - if (ccw->update == CompositeRedirectManual) - return BadAccess; - - /* - * Allocate per-client per-window structure - * The client *could* allocate multiple, but while supported, - * it is not expected to be common - */ - ccw = xalloc (sizeof (CompClientWindowRec)); - if (!ccw) - return BadAlloc; - ccw->id = FakeClientID (pClient->index); - ccw->update = update; - /* - * Now make sure there's a per-window structure to hang this from - */ - if (!cw) - { - cw = xalloc (sizeof (CompWindowRec)); - if (!cw) - { - xfree (ccw); - return BadAlloc; - } - cw->damage = DamageCreate (compReportDamage, - compDestroyDamage, - DamageReportNonEmpty, - FALSE, - pWin->drawable.pScreen, - pWin); - if (!cw->damage) - { - xfree (ccw); - xfree (cw); - return BadAlloc; - } - if (wasMapped) - { - DisableMapUnmapEvents (pWin); - UnmapWindow (pWin, FALSE); - EnableMapUnmapEvents (pWin); - } - - REGION_NULL (pScreen, &cw->borderClip); - cw->borderClipX = 0; - cw->borderClipY = 0; - cw->update = CompositeRedirectAutomatic; - cw->clients = 0; - cw->oldx = COMP_ORIGIN_INVALID; - cw->oldy = COMP_ORIGIN_INVALID; - cw->damageRegistered = FALSE; - cw->damaged = FALSE; - dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw); - } - ccw->next = cw->clients; - cw->clients = ccw; - if (!AddResource (ccw->id, CompositeClientWindowType, pWin)) - return BadAlloc; - if (ccw->update == CompositeRedirectManual) - { - /* If the window was CompositeRedirectAutomatic, then - * unmap the window so that the parent clip list will - * be correctly recomputed. - */ - if (pWin->mapped) - { - DisableMapUnmapEvents (pWin); - UnmapWindow (pWin, FALSE); - EnableMapUnmapEvents (pWin); - } - if (cw->damageRegistered) - { - DamageUnregister (&pWin->drawable, cw->damage); - cw->damageRegistered = FALSE; - } - cw->update = CompositeRedirectManual; - } - - if (!compCheckRedirect (pWin)) - { - FreeResource (ccw->id, RT_NONE); - return BadAlloc; - } - if (wasMapped && !pWin->mapped) - { - Bool overrideRedirect = pWin->overrideRedirect; - pWin->overrideRedirect = TRUE; - DisableMapUnmapEvents (pWin); - MapWindow (pWin, pClient); - EnableMapUnmapEvents (pWin); - pWin->overrideRedirect = overrideRedirect; - } - - return Success; -} - -/* - * Free one of the per-client per-window resources, clearing - * redirect and the per-window pointer as appropriate - */ -void -compFreeClientWindow (WindowPtr pWin, XID id) -{ - CompWindowPtr cw = GetCompWindow (pWin); - CompClientWindowPtr ccw, *prev; - Bool wasMapped = pWin->mapped; - - if (!cw) - return; - for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next) - { - if (ccw->id == id) - { - *prev = ccw->next; - if (ccw->update == CompositeRedirectManual) - cw->update = CompositeRedirectAutomatic; - xfree (ccw); - break; - } - } - if (!cw->clients) - { - if (wasMapped) - { - DisableMapUnmapEvents (pWin); - UnmapWindow (pWin, FALSE); - EnableMapUnmapEvents (pWin); - } - - if (pWin->redirectDraw != RedirectDrawNone) - compFreePixmap (pWin); - - if (cw->damage) - DamageDestroy (cw->damage); - - REGION_UNINIT (pScreen, &cw->borderClip); - - dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL); - xfree (cw); - } - else if (cw->update == CompositeRedirectAutomatic && - !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone) - { - DamageRegister (&pWin->drawable, cw->damage); - cw->damageRegistered = TRUE; - pWin->redirectDraw = RedirectDrawAutomatic; - DamageRegionAppend(&pWin->drawable, &pWin->borderSize); - } - if (wasMapped && !pWin->mapped) - { - Bool overrideRedirect = pWin->overrideRedirect; - pWin->overrideRedirect = TRUE; - DisableMapUnmapEvents (pWin); - MapWindow (pWin, clients[CLIENT_ID(id)]); - EnableMapUnmapEvents (pWin); - pWin->overrideRedirect = overrideRedirect; - } -} - -/* - * This is easy, just free the appropriate resource. - */ - -int -compUnredirectWindow (ClientPtr pClient, WindowPtr pWin, int update) -{ - CompWindowPtr cw = GetCompWindow (pWin); - CompClientWindowPtr ccw; - - if (!cw) - return BadValue; - - for (ccw = cw->clients; ccw; ccw = ccw->next) - if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) - { - FreeResource (ccw->id, RT_NONE); - return Success; - } - return BadValue; -} - -/* - * Redirect all subwindows for one client - */ - -int -compRedirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update) -{ - CompSubwindowsPtr csw = GetCompSubwindows (pWin); - CompClientWindowPtr ccw; - WindowPtr pChild; - - /* - * Only one Manual update is allowed - */ - if (csw && update == CompositeRedirectManual) - for (ccw = csw->clients; ccw; ccw = ccw->next) - if (ccw->update == CompositeRedirectManual) - return BadAccess; - /* - * Allocate per-client per-window structure - * The client *could* allocate multiple, but while supported, - * it is not expected to be common - */ - ccw = xalloc (sizeof (CompClientWindowRec)); - if (!ccw) - return BadAlloc; - ccw->id = FakeClientID (pClient->index); - ccw->update = update; - /* - * Now make sure there's a per-window structure to hang this from - */ - if (!csw) - { - csw = xalloc (sizeof (CompSubwindowsRec)); - if (!csw) - { - xfree (ccw); - return BadAlloc; - } - csw->update = CompositeRedirectAutomatic; - csw->clients = 0; - dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw); - } - /* - * Redirect all existing windows - */ - for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) - { - int ret = compRedirectWindow (pClient, pChild, update); - if (ret != Success) - { - for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib) - (void) compUnredirectWindow (pClient, pChild, update); - if (!csw->clients) - { - xfree (csw); - dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0); - } - xfree (ccw); - return ret; - } - } - /* - * Hook into subwindows list - */ - ccw->next = csw->clients; - csw->clients = ccw; - if (!AddResource (ccw->id, CompositeClientSubwindowsType, pWin)) - return BadAlloc; - if (ccw->update == CompositeRedirectManual) - { - csw->update = CompositeRedirectManual; - /* - * tell damage extension that damage events for this client are - * critical output - */ - DamageExtSetCritical (pClient, TRUE); - } - return Success; -} - -/* - * Free one of the per-client per-subwindows resources, - * which frees one redirect per subwindow - */ -void -compFreeClientSubwindows (WindowPtr pWin, XID id) -{ - CompSubwindowsPtr csw = GetCompSubwindows (pWin); - CompClientWindowPtr ccw, *prev; - WindowPtr pChild; - - if (!csw) - return; - for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next) - { - if (ccw->id == id) - { - ClientPtr pClient = clients[CLIENT_ID(id)]; - - *prev = ccw->next; - if (ccw->update == CompositeRedirectManual) - { - /* - * tell damage extension that damage events for this client are - * critical output - */ - DamageExtSetCritical (pClient, FALSE); - csw->update = CompositeRedirectAutomatic; - if (pWin->mapped) - (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, TRUE); - } - - /* - * Unredirect all existing subwindows - */ - for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) - (void) compUnredirectWindow (pClient, pChild, ccw->update); - - xfree (ccw); - break; - } - } - - /* - * Check if all of the per-client records are gone - */ - if (!csw->clients) - { - dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL); - xfree (csw); - } -} - -/* - * This is easy, just free the appropriate resource. - */ - -int -compUnredirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update) -{ - CompSubwindowsPtr csw = GetCompSubwindows (pWin); - CompClientWindowPtr ccw; - - if (!csw) - return BadValue; - for (ccw = csw->clients; ccw; ccw = ccw->next) - if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) - { - FreeResource (ccw->id, RT_NONE); - return Success; - } - return BadValue; -} - -/* - * Add redirection information for one subwindow (during reparent) - */ - -int -compRedirectOneSubwindow (WindowPtr pParent, WindowPtr pWin) -{ - CompSubwindowsPtr csw = GetCompSubwindows (pParent); - CompClientWindowPtr ccw; - - if (!csw) - return Success; - for (ccw = csw->clients; ccw; ccw = ccw->next) - { - int ret = compRedirectWindow (clients[CLIENT_ID(ccw->id)], - pWin, ccw->update); - if (ret != Success) - return ret; - } - return Success; -} - -/* - * Remove redirection information for one subwindow (during reparent) - */ - -int -compUnredirectOneSubwindow (WindowPtr pParent, WindowPtr pWin) -{ - CompSubwindowsPtr csw = GetCompSubwindows (pParent); - CompClientWindowPtr ccw; - - if (!csw) - return Success; - for (ccw = csw->clients; ccw; ccw = ccw->next) - { - int ret = compUnredirectWindow (clients[CLIENT_ID(ccw->id)], - pWin, ccw->update); - if (ret != Success) - return ret; - } - return Success; -} - -static PixmapPtr -compNewPixmap (WindowPtr pWin, int x, int y, int w, int h) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - WindowPtr pParent = pWin->parent; - PixmapPtr pPixmap; - - pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth, - CREATE_PIXMAP_USAGE_BACKING_PIXMAP); - - if (!pPixmap) - return 0; - - pPixmap->screen_x = x; - pPixmap->screen_y = y; - - if (pParent->drawable.depth == pWin->drawable.depth) - { - GCPtr pGC = GetScratchGC (pWin->drawable.depth, pScreen); - - /* - * Copy bits from the parent into the new pixmap so that it will - * have "reasonable" contents in case for background None areas. - */ - if (pGC) - { - XID val = IncludeInferiors; - - ValidateGC(&pPixmap->drawable, pGC); - dixChangeGC (serverClient, pGC, GCSubwindowMode, &val, NULL); - (*pGC->ops->CopyArea) (&pParent->drawable, - &pPixmap->drawable, - pGC, - x - pParent->drawable.x, - y - pParent->drawable.y, - w, h, 0, 0); - FreeScratchGC (pGC); - } - } - else - { - PictFormatPtr pSrcFormat = compWindowFormat (pParent); - PictFormatPtr pDstFormat = compWindowFormat (pWin); - XID inferiors = IncludeInferiors; - int error; - - PicturePtr pSrcPicture = CreatePicture (None, - &pParent->drawable, - pSrcFormat, - CPSubwindowMode, - &inferiors, - serverClient, &error); - - PicturePtr pDstPicture = CreatePicture (None, - &pPixmap->drawable, - pDstFormat, - 0, 0, - serverClient, &error); - - if (pSrcPicture && pDstPicture) - { - CompositePicture (PictOpSrc, - pSrcPicture, - NULL, - pDstPicture, - x - pParent->drawable.x, - y - pParent->drawable.y, - 0, 0, 0, 0, w, h); - } - if (pSrcPicture) - FreePicture (pSrcPicture, 0); - if (pDstPicture) - FreePicture (pDstPicture, 0); - } - return pPixmap; -} - -Bool -compAllocPixmap (WindowPtr pWin) -{ - int bw = (int) pWin->borderWidth; - int x = pWin->drawable.x - bw; - int y = pWin->drawable.y - bw; - int w = pWin->drawable.width + (bw << 1); - int h = pWin->drawable.height + (bw << 1); - PixmapPtr pPixmap = compNewPixmap (pWin, x, y, w, h); - CompWindowPtr cw = GetCompWindow (pWin); - - if (!pPixmap) - return FALSE; - if (cw->update == CompositeRedirectAutomatic) - pWin->redirectDraw = RedirectDrawAutomatic; - else - pWin->redirectDraw = RedirectDrawManual; - - compSetPixmap (pWin, pPixmap); - cw->oldx = COMP_ORIGIN_INVALID; - cw->oldy = COMP_ORIGIN_INVALID; - cw->damageRegistered = FALSE; - if (cw->update == CompositeRedirectAutomatic) - { - DamageRegister (&pWin->drawable, cw->damage); - cw->damageRegistered = TRUE; - } - return TRUE; -} - -void -compFreePixmap (WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - PixmapPtr pRedirectPixmap, pParentPixmap; - CompWindowPtr cw = GetCompWindow (pWin); - - if (cw->damageRegistered) - { - DamageUnregister (&pWin->drawable, cw->damage); - cw->damageRegistered = FALSE; - DamageEmpty (cw->damage); - } - /* - * Move the parent-constrained border clip region back into - * the window so that ValidateTree will handle the unmap - * case correctly. Unmap adds the window borderClip to the - * parent exposed area; regions beyond the parent cause crashes - */ - REGION_COPY (pScreen, &pWin->borderClip, &cw->borderClip); - pRedirectPixmap = (*pScreen->GetWindowPixmap) (pWin); - pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent); - pWin->redirectDraw = RedirectDrawNone; - compSetPixmap (pWin, pParentPixmap); - (*pScreen->DestroyPixmap) (pRedirectPixmap); -} - -/* - * Make sure the pixmap is the right size and offset. Allocate a new - * pixmap to change size, adjust origin to change offset, leaving the - * old pixmap in cw->pOldPixmap so bits can be recovered - */ -Bool -compReallocPixmap (WindowPtr pWin, int draw_x, int draw_y, - unsigned int w, unsigned int h, int bw) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin); - PixmapPtr pNew; - CompWindowPtr cw = GetCompWindow (pWin); - int pix_x, pix_y; - int pix_w, pix_h; - - assert (cw && pWin->redirectDraw != RedirectDrawNone); - cw->oldx = pOld->screen_x; - cw->oldy = pOld->screen_y; - pix_x = draw_x - bw; - pix_y = draw_y - bw; - pix_w = w + (bw << 1); - pix_h = h + (bw << 1); - if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height) - { - pNew = compNewPixmap (pWin, pix_x, pix_y, pix_w, pix_h); - if (!pNew) - return FALSE; - cw->pOldPixmap = pOld; - compSetPixmap (pWin, pNew); - } - else - { - pNew = pOld; - cw->pOldPixmap = 0; - } - pNew->screen_x = pix_x; - pNew->screen_y = pix_y; - return TRUE; -} +/* + * Copyright © 2006 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, 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. + * + * 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "compint.h" + +static void +compReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + WindowPtr pWin = (WindowPtr) closure; + ScreenPtr pScreen = pWin->drawable.pScreen; + CompScreenPtr cs = GetCompScreen (pScreen); + CompWindowPtr cw = GetCompWindow (pWin); + + cs->damaged = TRUE; + cw->damaged = TRUE; +} + +static void +compDestroyDamage (DamagePtr pDamage, void *closure) +{ + WindowPtr pWin = (WindowPtr) closure; + CompWindowPtr cw = GetCompWindow (pWin); + + cw->damage = 0; +} + +/* + * Redirect one window for one client + */ +int +compRedirectWindow (ClientPtr pClient, WindowPtr pWin, int update) +{ + CompWindowPtr cw = GetCompWindow (pWin); + CompClientWindowPtr ccw; + Bool wasMapped = pWin->mapped; + CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen); + + if (pWin == cs->pOverlayWin) { + return Success; + } + + if (!pWin->parent) + return BadMatch; + + /* + * Only one Manual update is allowed + */ + if (cw && update == CompositeRedirectManual) + for (ccw = cw->clients; ccw; ccw = ccw->next) + if (ccw->update == CompositeRedirectManual) + return BadAccess; + + /* + * Allocate per-client per-window structure + * The client *could* allocate multiple, but while supported, + * it is not expected to be common + */ + ccw = malloc(sizeof (CompClientWindowRec)); + if (!ccw) + return BadAlloc; + ccw->id = FakeClientID (pClient->index); + ccw->update = update; + /* + * Now make sure there's a per-window structure to hang this from + */ + if (!cw) + { + cw = malloc(sizeof (CompWindowRec)); + if (!cw) + { + free(ccw); + return BadAlloc; + } + cw->damage = DamageCreate (compReportDamage, + compDestroyDamage, + DamageReportNonEmpty, + FALSE, + pWin->drawable.pScreen, + pWin); + if (!cw->damage) + { + free(ccw); + free(cw); + return BadAlloc; + } + if (wasMapped) + { + DisableMapUnmapEvents (pWin); + UnmapWindow (pWin, FALSE); + EnableMapUnmapEvents (pWin); + } + + REGION_NULL (pScreen, &cw->borderClip); + cw->borderClipX = 0; + cw->borderClipY = 0; + cw->update = CompositeRedirectAutomatic; + cw->clients = 0; + cw->oldx = COMP_ORIGIN_INVALID; + cw->oldy = COMP_ORIGIN_INVALID; + cw->damageRegistered = FALSE; + cw->damaged = FALSE; + dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw); + } + ccw->next = cw->clients; + cw->clients = ccw; + if (!AddResource (ccw->id, CompositeClientWindowType, pWin)) + return BadAlloc; + if (ccw->update == CompositeRedirectManual) + { + /* If the window was CompositeRedirectAutomatic, then + * unmap the window so that the parent clip list will + * be correctly recomputed. + */ + if (pWin->mapped) + { + DisableMapUnmapEvents (pWin); + UnmapWindow (pWin, FALSE); + EnableMapUnmapEvents (pWin); + } + if (cw->damageRegistered) + { + DamageUnregister (&pWin->drawable, cw->damage); + cw->damageRegistered = FALSE; + } + cw->update = CompositeRedirectManual; + } + + if (!compCheckRedirect (pWin)) + { + FreeResource (ccw->id, RT_NONE); + return BadAlloc; + } + if (wasMapped && !pWin->mapped) + { + Bool overrideRedirect = pWin->overrideRedirect; + pWin->overrideRedirect = TRUE; + DisableMapUnmapEvents (pWin); + MapWindow (pWin, pClient); + EnableMapUnmapEvents (pWin); + pWin->overrideRedirect = overrideRedirect; + } + + return Success; +} + +/* + * Free one of the per-client per-window resources, clearing + * redirect and the per-window pointer as appropriate + */ +void +compFreeClientWindow (WindowPtr pWin, XID id) +{ + CompWindowPtr cw = GetCompWindow (pWin); + CompClientWindowPtr ccw, *prev; + Bool wasMapped = pWin->mapped; + + if (!cw) + return; + for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next) + { + if (ccw->id == id) + { + *prev = ccw->next; + if (ccw->update == CompositeRedirectManual) + cw->update = CompositeRedirectAutomatic; + free(ccw); + break; + } + } + if (!cw->clients) + { + if (wasMapped) + { + DisableMapUnmapEvents (pWin); + UnmapWindow (pWin, FALSE); + EnableMapUnmapEvents (pWin); + } + + if (pWin->redirectDraw != RedirectDrawNone) + compFreePixmap (pWin); + + if (cw->damage) + DamageDestroy (cw->damage); + + REGION_UNINIT (pScreen, &cw->borderClip); + + dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL); + free(cw); + } + else if (cw->update == CompositeRedirectAutomatic && + !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone) + { + DamageRegister (&pWin->drawable, cw->damage); + cw->damageRegistered = TRUE; + pWin->redirectDraw = RedirectDrawAutomatic; + DamageRegionAppend(&pWin->drawable, &pWin->borderSize); + } + if (wasMapped && !pWin->mapped) + { + Bool overrideRedirect = pWin->overrideRedirect; + pWin->overrideRedirect = TRUE; + DisableMapUnmapEvents (pWin); + MapWindow (pWin, clients[CLIENT_ID(id)]); + EnableMapUnmapEvents (pWin); + pWin->overrideRedirect = overrideRedirect; + } +} + +/* + * This is easy, just free the appropriate resource. + */ + +int +compUnredirectWindow (ClientPtr pClient, WindowPtr pWin, int update) +{ + CompWindowPtr cw = GetCompWindow (pWin); + CompClientWindowPtr ccw; + + if (!cw) + return BadValue; + + for (ccw = cw->clients; ccw; ccw = ccw->next) + if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) + { + FreeResource (ccw->id, RT_NONE); + return Success; + } + return BadValue; +} + +/* + * Redirect all subwindows for one client + */ + +int +compRedirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pWin); + CompClientWindowPtr ccw; + WindowPtr pChild; + + /* + * Only one Manual update is allowed + */ + if (csw && update == CompositeRedirectManual) + for (ccw = csw->clients; ccw; ccw = ccw->next) + if (ccw->update == CompositeRedirectManual) + return BadAccess; + /* + * Allocate per-client per-window structure + * The client *could* allocate multiple, but while supported, + * it is not expected to be common + */ + ccw = malloc(sizeof (CompClientWindowRec)); + if (!ccw) + return BadAlloc; + ccw->id = FakeClientID (pClient->index); + ccw->update = update; + /* + * Now make sure there's a per-window structure to hang this from + */ + if (!csw) + { + csw = malloc(sizeof (CompSubwindowsRec)); + if (!csw) + { + free(ccw); + return BadAlloc; + } + csw->update = CompositeRedirectAutomatic; + csw->clients = 0; + dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw); + } + /* + * Redirect all existing windows + */ + for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) + { + int ret = compRedirectWindow (pClient, pChild, update); + if (ret != Success) + { + for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib) + (void) compUnredirectWindow (pClient, pChild, update); + if (!csw->clients) + { + free(csw); + dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0); + } + free(ccw); + return ret; + } + } + /* + * Hook into subwindows list + */ + ccw->next = csw->clients; + csw->clients = ccw; + if (!AddResource (ccw->id, CompositeClientSubwindowsType, pWin)) + return BadAlloc; + if (ccw->update == CompositeRedirectManual) + { + csw->update = CompositeRedirectManual; + /* + * tell damage extension that damage events for this client are + * critical output + */ + DamageExtSetCritical (pClient, TRUE); + } + return Success; +} + +/* + * Free one of the per-client per-subwindows resources, + * which frees one redirect per subwindow + */ +void +compFreeClientSubwindows (WindowPtr pWin, XID id) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pWin); + CompClientWindowPtr ccw, *prev; + WindowPtr pChild; + + if (!csw) + return; + for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next) + { + if (ccw->id == id) + { + ClientPtr pClient = clients[CLIENT_ID(id)]; + + *prev = ccw->next; + if (ccw->update == CompositeRedirectManual) + { + /* + * tell damage extension that damage events for this client are + * critical output + */ + DamageExtSetCritical (pClient, FALSE); + csw->update = CompositeRedirectAutomatic; + if (pWin->mapped) + (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, TRUE); + } + + /* + * Unredirect all existing subwindows + */ + for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) + (void) compUnredirectWindow (pClient, pChild, ccw->update); + + free(ccw); + break; + } + } + + /* + * Check if all of the per-client records are gone + */ + if (!csw->clients) + { + dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL); + free(csw); + } +} + +/* + * This is easy, just free the appropriate resource. + */ + +int +compUnredirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pWin); + CompClientWindowPtr ccw; + + if (!csw) + return BadValue; + for (ccw = csw->clients; ccw; ccw = ccw->next) + if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) + { + FreeResource (ccw->id, RT_NONE); + return Success; + } + return BadValue; +} + +/* + * Add redirection information for one subwindow (during reparent) + */ + +int +compRedirectOneSubwindow (WindowPtr pParent, WindowPtr pWin) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pParent); + CompClientWindowPtr ccw; + + if (!csw) + return Success; + for (ccw = csw->clients; ccw; ccw = ccw->next) + { + int ret = compRedirectWindow (clients[CLIENT_ID(ccw->id)], + pWin, ccw->update); + if (ret != Success) + return ret; + } + return Success; +} + +/* + * Remove redirection information for one subwindow (during reparent) + */ + +int +compUnredirectOneSubwindow (WindowPtr pParent, WindowPtr pWin) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pParent); + CompClientWindowPtr ccw; + + if (!csw) + return Success; + for (ccw = csw->clients; ccw; ccw = ccw->next) + { + int ret = compUnredirectWindow (clients[CLIENT_ID(ccw->id)], + pWin, ccw->update); + if (ret != Success) + return ret; + } + return Success; +} + +static PixmapPtr +compNewPixmap (WindowPtr pWin, int x, int y, int w, int h) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pParent = pWin->parent; + PixmapPtr pPixmap; + + pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth, + CREATE_PIXMAP_USAGE_BACKING_PIXMAP); + + if (!pPixmap) + return 0; + + pPixmap->screen_x = x; + pPixmap->screen_y = y; + + if (pParent->drawable.depth == pWin->drawable.depth) + { + GCPtr pGC = GetScratchGC (pWin->drawable.depth, pScreen); + + /* + * Copy bits from the parent into the new pixmap so that it will + * have "reasonable" contents in case for background None areas. + */ + if (pGC) + { + ChangeGCVal val; + val.val = IncludeInferiors; + + ValidateGC(&pPixmap->drawable, pGC); + ChangeGC (serverClient, pGC, GCSubwindowMode, &val); + (*pGC->ops->CopyArea) (&pParent->drawable, + &pPixmap->drawable, + pGC, + x - pParent->drawable.x, + y - pParent->drawable.y, + w, h, 0, 0); + FreeScratchGC (pGC); + } + } + else + { + PictFormatPtr pSrcFormat = compWindowFormat (pParent); + PictFormatPtr pDstFormat = compWindowFormat (pWin); + XID inferiors = IncludeInferiors; + int error; + + PicturePtr pSrcPicture = CreatePicture (None, + &pParent->drawable, + pSrcFormat, + CPSubwindowMode, + &inferiors, + serverClient, &error); + + PicturePtr pDstPicture = CreatePicture (None, + &pPixmap->drawable, + pDstFormat, + 0, 0, + serverClient, &error); + + if (pSrcPicture && pDstPicture) + { + CompositePicture (PictOpSrc, + pSrcPicture, + NULL, + pDstPicture, + x - pParent->drawable.x, + y - pParent->drawable.y, + 0, 0, 0, 0, w, h); + } + if (pSrcPicture) + FreePicture (pSrcPicture, 0); + if (pDstPicture) + FreePicture (pDstPicture, 0); + } + return pPixmap; +} + +Bool +compAllocPixmap (WindowPtr pWin) +{ + int bw = (int) pWin->borderWidth; + int x = pWin->drawable.x - bw; + int y = pWin->drawable.y - bw; + int w = pWin->drawable.width + (bw << 1); + int h = pWin->drawable.height + (bw << 1); + PixmapPtr pPixmap = compNewPixmap (pWin, x, y, w, h); + CompWindowPtr cw = GetCompWindow (pWin); + + if (!pPixmap) + return FALSE; + if (cw->update == CompositeRedirectAutomatic) + pWin->redirectDraw = RedirectDrawAutomatic; + else + pWin->redirectDraw = RedirectDrawManual; + + compSetPixmap (pWin, pPixmap); + cw->oldx = COMP_ORIGIN_INVALID; + cw->oldy = COMP_ORIGIN_INVALID; + cw->damageRegistered = FALSE; + if (cw->update == CompositeRedirectAutomatic) + { + DamageRegister (&pWin->drawable, cw->damage); + cw->damageRegistered = TRUE; + } + return TRUE; +} + +void +compFreePixmap (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + PixmapPtr pRedirectPixmap, pParentPixmap; + CompWindowPtr cw = GetCompWindow (pWin); + + if (cw->damageRegistered) + { + DamageUnregister (&pWin->drawable, cw->damage); + cw->damageRegistered = FALSE; + DamageEmpty (cw->damage); + } + /* + * Move the parent-constrained border clip region back into + * the window so that ValidateTree will handle the unmap + * case correctly. Unmap adds the window borderClip to the + * parent exposed area; regions beyond the parent cause crashes + */ + REGION_COPY (pScreen, &pWin->borderClip, &cw->borderClip); + pRedirectPixmap = (*pScreen->GetWindowPixmap) (pWin); + pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent); + pWin->redirectDraw = RedirectDrawNone; + compSetPixmap (pWin, pParentPixmap); + (*pScreen->DestroyPixmap) (pRedirectPixmap); +} + +/* + * Make sure the pixmap is the right size and offset. Allocate a new + * pixmap to change size, adjust origin to change offset, leaving the + * old pixmap in cw->pOldPixmap so bits can be recovered + */ +Bool +compReallocPixmap (WindowPtr pWin, int draw_x, int draw_y, + unsigned int w, unsigned int h, int bw) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin); + PixmapPtr pNew; + CompWindowPtr cw = GetCompWindow (pWin); + int pix_x, pix_y; + int pix_w, pix_h; + + assert (cw && pWin->redirectDraw != RedirectDrawNone); + cw->oldx = pOld->screen_x; + cw->oldy = pOld->screen_y; + pix_x = draw_x - bw; + pix_y = draw_y - bw; + pix_w = w + (bw << 1); + pix_h = h + (bw << 1); + if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height) + { + pNew = compNewPixmap (pWin, pix_x, pix_y, pix_w, pix_h); + if (!pNew) + return FALSE; + cw->pOldPixmap = pOld; + compSetPixmap (pWin, pNew); + } + else + { + pNew = pOld; + cw->pOldPixmap = 0; + } + pNew->screen_x = pix_x; + pNew->screen_y = pix_y; + return TRUE; +} diff --git a/xorg-server/composite/compext.c b/xorg-server/composite/compext.c index 17c4bae1e..664b0fcc3 100644 --- a/xorg-server/composite/compext.c +++ b/xorg-server/composite/compext.c @@ -1,587 +1,587 @@ -/* - * Copyright © 2006 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, 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. - * - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "compint.h" -#include "xace.h" -#include "protocol-versions.h" - -static CARD8 CompositeReqCode; -static int CompositeClientPrivateKeyIndex; -static DevPrivateKey CompositeClientPrivateKey = &CompositeClientPrivateKeyIndex; -RESTYPE CompositeClientWindowType; -RESTYPE CompositeClientSubwindowsType; -RESTYPE CompositeClientOverlayType; - -typedef struct _CompositeClient { - int major_version; - int minor_version; -} CompositeClientRec, *CompositeClientPtr; - -#define GetCompositeClient(pClient) ((CompositeClientPtr) \ - dixLookupPrivate(&(pClient)->devPrivates, CompositeClientPrivateKey)) - -static void -CompositeClientCallback (CallbackListPtr *list, - pointer closure, - pointer data) -{ - NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; - ClientPtr pClient = clientinfo->client; - CompositeClientPtr pCompositeClient = GetCompositeClient (pClient); - - pCompositeClient->major_version = 0; - pCompositeClient->minor_version = 0; -} - -static int -FreeCompositeClientWindow (pointer value, XID ccwid) -{ - WindowPtr pWin = value; - - compFreeClientWindow (pWin, ccwid); - return Success; -} - -static int -FreeCompositeClientSubwindows (pointer value, XID ccwid) -{ - WindowPtr pWin = value; - - compFreeClientSubwindows (pWin, ccwid); - return Success; -} - -static int -FreeCompositeClientOverlay (pointer value, XID ccwid) -{ - CompOverlayClientPtr pOc = (CompOverlayClientPtr) value; - - compFreeOverlayClient (pOc); - return Success; -} - -static int -ProcCompositeQueryVersion (ClientPtr client) -{ - CompositeClientPtr pCompositeClient = GetCompositeClient (client); - xCompositeQueryVersionReply rep; - register int n; - REQUEST(xCompositeQueryVersionReq); - - REQUEST_SIZE_MATCH(xCompositeQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - if (stuff->majorVersion < SERVER_COMPOSITE_MAJOR_VERSION) { - rep.majorVersion = stuff->majorVersion; - rep.minorVersion = stuff->minorVersion; - } else { - rep.majorVersion = SERVER_COMPOSITE_MAJOR_VERSION; - rep.minorVersion = SERVER_COMPOSITE_MINOR_VERSION; - } - pCompositeClient->major_version = rep.majorVersion; - pCompositeClient->minor_version = rep.minorVersion; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.majorVersion, n); - swapl(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xCompositeQueryVersionReply), (char *)&rep); - return(client->noClientException); -} - -#define VERIFY_WINDOW(pWindow, wid, client, mode) \ - do { \ - int err; \ - err = dixLookupResourceByType((pointer *) &pWindow, wid, \ - RT_WINDOW, client, mode); \ - if (err == BadValue) { \ - client->errorValue = wid; \ - return BadWindow; \ - } else if (err != Success) { \ - client->errorValue = wid; \ - return err; \ - } \ - } while (0) - -static int -ProcCompositeRedirectWindow (ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xCompositeRedirectWindowReq); - - REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq); - VERIFY_WINDOW(pWin, stuff->window, client, - DixSetAttrAccess|DixManageAccess|DixBlendAccess); - - return compRedirectWindow (client, pWin, stuff->update); -} - -static int -ProcCompositeRedirectSubwindows (ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xCompositeRedirectSubwindowsReq); - - REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq); - VERIFY_WINDOW(pWin, stuff->window, client, - DixSetAttrAccess|DixManageAccess|DixBlendAccess); - - return compRedirectSubwindows (client, pWin, stuff->update); -} - -static int -ProcCompositeUnredirectWindow (ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xCompositeUnredirectWindowReq); - - REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq); - VERIFY_WINDOW(pWin, stuff->window, client, - DixSetAttrAccess|DixManageAccess|DixBlendAccess); - - return compUnredirectWindow (client, pWin, stuff->update); -} - -static int -ProcCompositeUnredirectSubwindows (ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xCompositeUnredirectSubwindowsReq); - - REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq); - VERIFY_WINDOW(pWin, stuff->window, client, - DixSetAttrAccess|DixManageAccess|DixBlendAccess); - - return compUnredirectSubwindows (client, pWin, stuff->update); -} - -static int -ProcCompositeCreateRegionFromBorderClip (ClientPtr client) -{ - WindowPtr pWin; - CompWindowPtr cw; - RegionPtr pBorderClip, pRegion; - REQUEST(xCompositeCreateRegionFromBorderClipReq); - - REQUEST_SIZE_MATCH(xCompositeCreateRegionFromBorderClipReq); - VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess); - LEGAL_NEW_RESOURCE (stuff->region, client); - - cw = GetCompWindow (pWin); - if (cw) - pBorderClip = &cw->borderClip; - else - pBorderClip = &pWin->borderClip; - pRegion = XFixesRegionCopy (pBorderClip); - if (!pRegion) - return BadAlloc; - REGION_TRANSLATE (pScreen, pRegion, -pWin->drawable.x, -pWin->drawable.y); - - if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) - return BadAlloc; - - return(client->noClientException); -} - -static int -ProcCompositeNameWindowPixmap (ClientPtr client) -{ - WindowPtr pWin; - CompWindowPtr cw; - PixmapPtr pPixmap; - int rc; - REQUEST(xCompositeNameWindowPixmapReq); - - REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq); - VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess); - - if (!pWin->viewable) - return BadMatch; - - LEGAL_NEW_RESOURCE (stuff->pixmap, client); - - cw = GetCompWindow (pWin); - if (!cw) - return BadMatch; - - pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); - if (!pPixmap) - return BadMatch; - - /* security creation/labeling check */ - rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP, - pPixmap, RT_WINDOW, pWin, DixCreateAccess); - if (rc != Success) - return rc; - - ++pPixmap->refcnt; - - if (!AddResource (stuff->pixmap, RT_PIXMAP, (pointer) pPixmap)) - return BadAlloc; - - return(client->noClientException); -} - - -static int -ProcCompositeGetOverlayWindow (ClientPtr client) -{ - REQUEST(xCompositeGetOverlayWindowReq); - xCompositeGetOverlayWindowReply rep; - WindowPtr pWin; - ScreenPtr pScreen; - CompScreenPtr cs; - CompOverlayClientPtr pOc; - int rc; - - REQUEST_SIZE_MATCH(xCompositeGetOverlayWindowReq); - VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess); - pScreen = pWin->drawable.pScreen; - - /* - * Create an OverlayClient structure to mark this client's - * interest in the overlay window - */ - pOc = compCreateOverlayClient(pScreen, client); - if (pOc == NULL) - return BadAlloc; - - /* - * Make sure the overlay window exists - */ - cs = GetCompScreen(pScreen); - if (cs->pOverlayWin == NULL) - if (!compCreateOverlayWindow(pScreen)) - { - FreeResource (pOc->resource, RT_NONE); - return BadAlloc; - } - - rc = XaceHook(XACE_RESOURCE_ACCESS, client, cs->pOverlayWin->drawable.id, - RT_WINDOW, cs->pOverlayWin, RT_NONE, NULL, DixGetAttrAccess); - if (rc != Success) - { - FreeResource (pOc->resource, RT_NONE); - return rc; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.overlayWin = cs->pOverlayWin->drawable.id; - - if (client->swapped) - { - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.overlayWin, n); - } - (void) WriteToClient(client, sz_xCompositeGetOverlayWindowReply, (char *)&rep); - - return client->noClientException; -} - -static int -ProcCompositeReleaseOverlayWindow (ClientPtr client) -{ - REQUEST(xCompositeReleaseOverlayWindowReq); - WindowPtr pWin; - ScreenPtr pScreen; - CompOverlayClientPtr pOc; - - REQUEST_SIZE_MATCH(xCompositeReleaseOverlayWindowReq); - VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess); - pScreen = pWin->drawable.pScreen; - - /* - * Has client queried a reference to the overlay window - * on this screen? If not, generate an error. - */ - pOc = compFindOverlayClient (pWin->drawable.pScreen, client); - if (pOc == NULL) - return BadMatch; - - /* The delete function will free the client structure */ - FreeResource (pOc->resource, RT_NONE); - - return client->noClientException; -} - -static int (*ProcCompositeVector[CompositeNumberRequests])(ClientPtr) = { - ProcCompositeQueryVersion, - ProcCompositeRedirectWindow, - ProcCompositeRedirectSubwindows, - ProcCompositeUnredirectWindow, - ProcCompositeUnredirectSubwindows, - ProcCompositeCreateRegionFromBorderClip, - ProcCompositeNameWindowPixmap, - ProcCompositeGetOverlayWindow, - ProcCompositeReleaseOverlayWindow, -}; - -static int -ProcCompositeDispatch (ClientPtr client) -{ - REQUEST(xReq); - - if (stuff->data < CompositeNumberRequests) - return (*ProcCompositeVector[stuff->data]) (client); - else - return BadRequest; -} - -static int -SProcCompositeQueryVersion (ClientPtr client) -{ - int n; - REQUEST(xCompositeQueryVersionReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xCompositeQueryVersionReq); - swapl(&stuff->majorVersion, n); - swapl(&stuff->minorVersion, n); - return (*ProcCompositeVector[stuff->compositeReqType]) (client); -} - -static int -SProcCompositeRedirectWindow (ClientPtr client) -{ - int n; - REQUEST(xCompositeRedirectWindowReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq); - swapl (&stuff->window, n); - return (*ProcCompositeVector[stuff->compositeReqType]) (client); -} - -static int -SProcCompositeRedirectSubwindows (ClientPtr client) -{ - int n; - REQUEST(xCompositeRedirectSubwindowsReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq); - swapl (&stuff->window, n); - return (*ProcCompositeVector[stuff->compositeReqType]) (client); -} - -static int -SProcCompositeUnredirectWindow (ClientPtr client) -{ - int n; - REQUEST(xCompositeUnredirectWindowReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq); - swapl (&stuff->window, n); - return (*ProcCompositeVector[stuff->compositeReqType]) (client); -} - -static int -SProcCompositeUnredirectSubwindows (ClientPtr client) -{ - int n; - REQUEST(xCompositeUnredirectSubwindowsReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq); - swapl (&stuff->window, n); - return (*ProcCompositeVector[stuff->compositeReqType]) (client); -} - -static int -SProcCompositeCreateRegionFromBorderClip (ClientPtr client) -{ - int n; - REQUEST(xCompositeCreateRegionFromBorderClipReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xCompositeCreateRegionFromBorderClipReq); - swapl (&stuff->region, n); - swapl (&stuff->window, n); - return (*ProcCompositeVector[stuff->compositeReqType]) (client); -} - -static int -SProcCompositeNameWindowPixmap (ClientPtr client) -{ - int n; - REQUEST(xCompositeNameWindowPixmapReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq); - swapl (&stuff->window, n); - swapl (&stuff->pixmap, n); - return (*ProcCompositeVector[stuff->compositeReqType]) (client); -} - -static int -SProcCompositeGetOverlayWindow (ClientPtr client) -{ - int n; - REQUEST(xCompositeGetOverlayWindowReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xCompositeGetOverlayWindowReq); - swapl(&stuff->window, n); - return (*ProcCompositeVector[stuff->compositeReqType]) (client); -} - -static int -SProcCompositeReleaseOverlayWindow (ClientPtr client) -{ - int n; - REQUEST(xCompositeReleaseOverlayWindowReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xCompositeReleaseOverlayWindowReq); - swapl(&stuff->window, n); - return (*ProcCompositeVector[stuff->compositeReqType]) (client); -} - -static int (*SProcCompositeVector[CompositeNumberRequests])(ClientPtr) = { - SProcCompositeQueryVersion, - SProcCompositeRedirectWindow, - SProcCompositeRedirectSubwindows, - SProcCompositeUnredirectWindow, - SProcCompositeUnredirectSubwindows, - SProcCompositeCreateRegionFromBorderClip, - SProcCompositeNameWindowPixmap, - SProcCompositeGetOverlayWindow, - SProcCompositeReleaseOverlayWindow, -}; - -static int -SProcCompositeDispatch (ClientPtr client) -{ - REQUEST(xReq); - - if (stuff->data < CompositeNumberRequests) - return (*SProcCompositeVector[stuff->data]) (client); - else - return BadRequest; -} - -void -CompositeExtensionInit (void) -{ - ExtensionEntry *extEntry; - int s; - - /* Assume initialization is going to fail */ - noCompositeExtension = TRUE; - - for (s = 0; s < screenInfo.numScreens; s++) { - ScreenPtr pScreen = screenInfo.screens[s]; - VisualPtr vis; - - /* Composite on 8bpp pseudocolor root windows appears to fail, so - * just disable it on anything pseudocolor for safety. - */ - for (vis = pScreen->visuals; vis->vid != pScreen->rootVisual; vis++) - ; - if ((vis->class | DynamicClass) == PseudoColor) - return; - - /* Ensure that Render is initialized, which is required for automatic - * compositing. - */ - if (GetPictureScreenIfSet(pScreen) == NULL) - return; - } -#ifdef PANORAMIX - /* Xinerama's rewriting of window drawing before Composite gets to it - * breaks Composite. - */ - if (!noPanoramiXExtension) - return; -#endif - - CompositeClientWindowType = CreateNewResourceType - (FreeCompositeClientWindow, "CompositeClientWindow"); - if (!CompositeClientWindowType) - return; - - CompositeClientSubwindowsType = CreateNewResourceType - (FreeCompositeClientSubwindows, "CompositeClientSubwindows"); - if (!CompositeClientSubwindowsType) - return; - - CompositeClientOverlayType = CreateNewResourceType - (FreeCompositeClientOverlay, "CompositeClientOverlay"); - if (!CompositeClientOverlayType) - return; - - if (!dixRequestPrivate(CompositeClientPrivateKey, - sizeof(CompositeClientRec))) - return; - - if (!AddCallback (&ClientStateCallback, CompositeClientCallback, 0)) - return; - - for (s = 0; s < screenInfo.numScreens; s++) - if (!compScreenInit (screenInfo.screens[s])) - return; - - extEntry = AddExtension (COMPOSITE_NAME, 0, 0, - ProcCompositeDispatch, SProcCompositeDispatch, - NULL, StandardMinorOpcode); - if (!extEntry) - return; - CompositeReqCode = (CARD8) extEntry->base; - - miRegisterRedirectBorderClipProc (compSetRedirectBorderClip, - compGetRedirectBorderClip); - - /* Initialization succeeded */ - noCompositeExtension = FALSE; -} +/* + * Copyright © 2006 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, 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. + * + * 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "compint.h" +#include "xace.h" +#include "protocol-versions.h" + +static CARD8 CompositeReqCode; +static int CompositeClientPrivateKeyIndex; +static DevPrivateKey CompositeClientPrivateKey = &CompositeClientPrivateKeyIndex; +RESTYPE CompositeClientWindowType; +RESTYPE CompositeClientSubwindowsType; +RESTYPE CompositeClientOverlayType; + +typedef struct _CompositeClient { + int major_version; + int minor_version; +} CompositeClientRec, *CompositeClientPtr; + +#define GetCompositeClient(pClient) ((CompositeClientPtr) \ + dixLookupPrivate(&(pClient)->devPrivates, CompositeClientPrivateKey)) + +static void +CompositeClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + CompositeClientPtr pCompositeClient = GetCompositeClient (pClient); + + pCompositeClient->major_version = 0; + pCompositeClient->minor_version = 0; +} + +static int +FreeCompositeClientWindow (pointer value, XID ccwid) +{ + WindowPtr pWin = value; + + compFreeClientWindow (pWin, ccwid); + return Success; +} + +static int +FreeCompositeClientSubwindows (pointer value, XID ccwid) +{ + WindowPtr pWin = value; + + compFreeClientSubwindows (pWin, ccwid); + return Success; +} + +static int +FreeCompositeClientOverlay (pointer value, XID ccwid) +{ + CompOverlayClientPtr pOc = (CompOverlayClientPtr) value; + + compFreeOverlayClient (pOc); + return Success; +} + +static int +ProcCompositeQueryVersion (ClientPtr client) +{ + CompositeClientPtr pCompositeClient = GetCompositeClient (client); + xCompositeQueryVersionReply rep; + register int n; + REQUEST(xCompositeQueryVersionReq); + + REQUEST_SIZE_MATCH(xCompositeQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (stuff->majorVersion < SERVER_COMPOSITE_MAJOR_VERSION) { + rep.majorVersion = stuff->majorVersion; + rep.minorVersion = stuff->minorVersion; + } else { + rep.majorVersion = SERVER_COMPOSITE_MAJOR_VERSION; + rep.minorVersion = SERVER_COMPOSITE_MINOR_VERSION; + } + pCompositeClient->major_version = rep.majorVersion; + pCompositeClient->minor_version = rep.minorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xCompositeQueryVersionReply), (char *)&rep); + return Success; +} + +#define VERIFY_WINDOW(pWindow, wid, client, mode) \ + do { \ + int err; \ + err = dixLookupResourceByType((pointer *) &pWindow, wid, \ + RT_WINDOW, client, mode); \ + if (err == BadValue) { \ + client->errorValue = wid; \ + return BadWindow; \ + } else if (err != Success) { \ + client->errorValue = wid; \ + return err; \ + } \ + } while (0) + +static int +ProcCompositeRedirectWindow (ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xCompositeRedirectWindowReq); + + REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq); + VERIFY_WINDOW(pWin, stuff->window, client, + DixSetAttrAccess|DixManageAccess|DixBlendAccess); + + return compRedirectWindow (client, pWin, stuff->update); +} + +static int +ProcCompositeRedirectSubwindows (ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xCompositeRedirectSubwindowsReq); + + REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq); + VERIFY_WINDOW(pWin, stuff->window, client, + DixSetAttrAccess|DixManageAccess|DixBlendAccess); + + return compRedirectSubwindows (client, pWin, stuff->update); +} + +static int +ProcCompositeUnredirectWindow (ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xCompositeUnredirectWindowReq); + + REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq); + VERIFY_WINDOW(pWin, stuff->window, client, + DixSetAttrAccess|DixManageAccess|DixBlendAccess); + + return compUnredirectWindow (client, pWin, stuff->update); +} + +static int +ProcCompositeUnredirectSubwindows (ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xCompositeUnredirectSubwindowsReq); + + REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq); + VERIFY_WINDOW(pWin, stuff->window, client, + DixSetAttrAccess|DixManageAccess|DixBlendAccess); + + return compUnredirectSubwindows (client, pWin, stuff->update); +} + +static int +ProcCompositeCreateRegionFromBorderClip (ClientPtr client) +{ + WindowPtr pWin; + CompWindowPtr cw; + RegionPtr pBorderClip, pRegion; + REQUEST(xCompositeCreateRegionFromBorderClipReq); + + REQUEST_SIZE_MATCH(xCompositeCreateRegionFromBorderClipReq); + VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess); + LEGAL_NEW_RESOURCE (stuff->region, client); + + cw = GetCompWindow (pWin); + if (cw) + pBorderClip = &cw->borderClip; + else + pBorderClip = &pWin->borderClip; + pRegion = XFixesRegionCopy (pBorderClip); + if (!pRegion) + return BadAlloc; + REGION_TRANSLATE (pScreen, pRegion, -pWin->drawable.x, -pWin->drawable.y); + + if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) + return BadAlloc; + + return Success; +} + +static int +ProcCompositeNameWindowPixmap (ClientPtr client) +{ + WindowPtr pWin; + CompWindowPtr cw; + PixmapPtr pPixmap; + int rc; + REQUEST(xCompositeNameWindowPixmapReq); + + REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq); + VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess); + + if (!pWin->viewable) + return BadMatch; + + LEGAL_NEW_RESOURCE (stuff->pixmap, client); + + cw = GetCompWindow (pWin); + if (!cw) + return BadMatch; + + pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); + if (!pPixmap) + return BadMatch; + + /* security creation/labeling check */ + rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP, + pPixmap, RT_WINDOW, pWin, DixCreateAccess); + if (rc != Success) + return rc; + + ++pPixmap->refcnt; + + if (!AddResource (stuff->pixmap, RT_PIXMAP, (pointer) pPixmap)) + return BadAlloc; + + return Success; +} + + +static int +ProcCompositeGetOverlayWindow (ClientPtr client) +{ + REQUEST(xCompositeGetOverlayWindowReq); + xCompositeGetOverlayWindowReply rep; + WindowPtr pWin; + ScreenPtr pScreen; + CompScreenPtr cs; + CompOverlayClientPtr pOc; + int rc; + + REQUEST_SIZE_MATCH(xCompositeGetOverlayWindowReq); + VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess); + pScreen = pWin->drawable.pScreen; + + /* + * Create an OverlayClient structure to mark this client's + * interest in the overlay window + */ + pOc = compCreateOverlayClient(pScreen, client); + if (pOc == NULL) + return BadAlloc; + + /* + * Make sure the overlay window exists + */ + cs = GetCompScreen(pScreen); + if (cs->pOverlayWin == NULL) + if (!compCreateOverlayWindow(pScreen)) + { + FreeResource (pOc->resource, RT_NONE); + return BadAlloc; + } + + rc = XaceHook(XACE_RESOURCE_ACCESS, client, cs->pOverlayWin->drawable.id, + RT_WINDOW, cs->pOverlayWin, RT_NONE, NULL, DixGetAttrAccess); + if (rc != Success) + { + FreeResource (pOc->resource, RT_NONE); + return rc; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.overlayWin = cs->pOverlayWin->drawable.id; + + if (client->swapped) + { + int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.overlayWin, n); + } + (void) WriteToClient(client, sz_xCompositeGetOverlayWindowReply, (char *)&rep); + + return Success; +} + +static int +ProcCompositeReleaseOverlayWindow (ClientPtr client) +{ + REQUEST(xCompositeReleaseOverlayWindowReq); + WindowPtr pWin; + ScreenPtr pScreen; + CompOverlayClientPtr pOc; + + REQUEST_SIZE_MATCH(xCompositeReleaseOverlayWindowReq); + VERIFY_WINDOW(pWin, stuff->window, client, DixGetAttrAccess); + pScreen = pWin->drawable.pScreen; + + /* + * Has client queried a reference to the overlay window + * on this screen? If not, generate an error. + */ + pOc = compFindOverlayClient (pWin->drawable.pScreen, client); + if (pOc == NULL) + return BadMatch; + + /* The delete function will free the client structure */ + FreeResource (pOc->resource, RT_NONE); + + return Success; +} + +static int (*ProcCompositeVector[CompositeNumberRequests])(ClientPtr) = { + ProcCompositeQueryVersion, + ProcCompositeRedirectWindow, + ProcCompositeRedirectSubwindows, + ProcCompositeUnredirectWindow, + ProcCompositeUnredirectSubwindows, + ProcCompositeCreateRegionFromBorderClip, + ProcCompositeNameWindowPixmap, + ProcCompositeGetOverlayWindow, + ProcCompositeReleaseOverlayWindow, +}; + +static int +ProcCompositeDispatch (ClientPtr client) +{ + REQUEST(xReq); + + if (stuff->data < CompositeNumberRequests) + return (*ProcCompositeVector[stuff->data]) (client); + else + return BadRequest; +} + +static int +SProcCompositeQueryVersion (ClientPtr client) +{ + int n; + REQUEST(xCompositeQueryVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeQueryVersionReq); + swapl(&stuff->majorVersion, n); + swapl(&stuff->minorVersion, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeRedirectWindow (ClientPtr client) +{ + int n; + REQUEST(xCompositeRedirectWindowReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeRedirectSubwindows (ClientPtr client) +{ + int n; + REQUEST(xCompositeRedirectSubwindowsReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeUnredirectWindow (ClientPtr client) +{ + int n; + REQUEST(xCompositeUnredirectWindowReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeUnredirectSubwindows (ClientPtr client) +{ + int n; + REQUEST(xCompositeUnredirectSubwindowsReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeCreateRegionFromBorderClip (ClientPtr client) +{ + int n; + REQUEST(xCompositeCreateRegionFromBorderClipReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeCreateRegionFromBorderClipReq); + swapl (&stuff->region, n); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeNameWindowPixmap (ClientPtr client) +{ + int n; + REQUEST(xCompositeNameWindowPixmapReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq); + swapl (&stuff->window, n); + swapl (&stuff->pixmap, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeGetOverlayWindow (ClientPtr client) +{ + int n; + REQUEST(xCompositeGetOverlayWindowReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeGetOverlayWindowReq); + swapl(&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeReleaseOverlayWindow (ClientPtr client) +{ + int n; + REQUEST(xCompositeReleaseOverlayWindowReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeReleaseOverlayWindowReq); + swapl(&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int (*SProcCompositeVector[CompositeNumberRequests])(ClientPtr) = { + SProcCompositeQueryVersion, + SProcCompositeRedirectWindow, + SProcCompositeRedirectSubwindows, + SProcCompositeUnredirectWindow, + SProcCompositeUnredirectSubwindows, + SProcCompositeCreateRegionFromBorderClip, + SProcCompositeNameWindowPixmap, + SProcCompositeGetOverlayWindow, + SProcCompositeReleaseOverlayWindow, +}; + +static int +SProcCompositeDispatch (ClientPtr client) +{ + REQUEST(xReq); + + if (stuff->data < CompositeNumberRequests) + return (*SProcCompositeVector[stuff->data]) (client); + else + return BadRequest; +} + +void +CompositeExtensionInit (void) +{ + ExtensionEntry *extEntry; + int s; + + /* Assume initialization is going to fail */ + noCompositeExtension = TRUE; + + for (s = 0; s < screenInfo.numScreens; s++) { + ScreenPtr pScreen = screenInfo.screens[s]; + VisualPtr vis; + + /* Composite on 8bpp pseudocolor root windows appears to fail, so + * just disable it on anything pseudocolor for safety. + */ + for (vis = pScreen->visuals; vis->vid != pScreen->rootVisual; vis++) + ; + if ((vis->class | DynamicClass) == PseudoColor) + return; + + /* Ensure that Render is initialized, which is required for automatic + * compositing. + */ + if (GetPictureScreenIfSet(pScreen) == NULL) + return; + } +#ifdef PANORAMIX + /* Xinerama's rewriting of window drawing before Composite gets to it + * breaks Composite. + */ + if (!noPanoramiXExtension) + return; +#endif + + CompositeClientWindowType = CreateNewResourceType + (FreeCompositeClientWindow, "CompositeClientWindow"); + if (!CompositeClientWindowType) + return; + + CompositeClientSubwindowsType = CreateNewResourceType + (FreeCompositeClientSubwindows, "CompositeClientSubwindows"); + if (!CompositeClientSubwindowsType) + return; + + CompositeClientOverlayType = CreateNewResourceType + (FreeCompositeClientOverlay, "CompositeClientOverlay"); + if (!CompositeClientOverlayType) + return; + + if (!dixRequestPrivate(CompositeClientPrivateKey, + sizeof(CompositeClientRec))) + return; + + if (!AddCallback (&ClientStateCallback, CompositeClientCallback, 0)) + return; + + for (s = 0; s < screenInfo.numScreens; s++) + if (!compScreenInit (screenInfo.screens[s])) + return; + + extEntry = AddExtension (COMPOSITE_NAME, 0, 0, + ProcCompositeDispatch, SProcCompositeDispatch, + NULL, StandardMinorOpcode); + if (!extEntry) + return; + CompositeReqCode = (CARD8) extEntry->base; + + miRegisterRedirectBorderClipProc (compSetRedirectBorderClip, + compGetRedirectBorderClip); + + /* Initialization succeeded */ + noCompositeExtension = FALSE; +} diff --git a/xorg-server/composite/compinit.c b/xorg-server/composite/compinit.c index e8b563de6..9a99ce633 100644 --- a/xorg-server/composite/compinit.c +++ b/xorg-server/composite/compinit.c @@ -1,394 +1,394 @@ -/* - * Copyright © 2006 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, 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. - * - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "compint.h" -#include "compositeext.h" - -static int CompScreenPrivateKeyIndex; -DevPrivateKey CompScreenPrivateKey = &CompScreenPrivateKeyIndex; -static int CompWindowPrivateKeyIndex; -DevPrivateKey CompWindowPrivateKey = &CompWindowPrivateKeyIndex; -static int CompSubwindowsPrivateKeyIndex; -DevPrivateKey CompSubwindowsPrivateKey = &CompSubwindowsPrivateKeyIndex; - - -static Bool -compCloseScreen (int index, ScreenPtr pScreen) -{ - CompScreenPtr cs = GetCompScreen (pScreen); - Bool ret; - - xfree (cs->alternateVisuals); - - pScreen->CloseScreen = cs->CloseScreen; - pScreen->BlockHandler = cs->BlockHandler; - pScreen->InstallColormap = cs->InstallColormap; - pScreen->ChangeWindowAttributes = cs->ChangeWindowAttributes; - pScreen->ReparentWindow = cs->ReparentWindow; - pScreen->MoveWindow = cs->MoveWindow; - pScreen->ResizeWindow = cs->ResizeWindow; - pScreen->ChangeBorderWidth = cs->ChangeBorderWidth; - - pScreen->ClipNotify = cs->ClipNotify; - pScreen->UnrealizeWindow = cs->UnrealizeWindow; - pScreen->RealizeWindow = cs->RealizeWindow; - pScreen->DestroyWindow = cs->DestroyWindow; - pScreen->CreateWindow = cs->CreateWindow; - pScreen->CopyWindow = cs->CopyWindow; - pScreen->PositionWindow = cs->PositionWindow; - - xfree (cs); - dixSetPrivate(&pScreen->devPrivates, CompScreenPrivateKey, NULL); - ret = (*pScreen->CloseScreen) (index, pScreen); - - return ret; -} - -static void -compInstallColormap (ColormapPtr pColormap) -{ - VisualPtr pVisual = pColormap->pVisual; - ScreenPtr pScreen = pColormap->pScreen; - CompScreenPtr cs = GetCompScreen (pScreen); - int a; - - for (a = 0; a < cs->numAlternateVisuals; a++) - if (pVisual->vid == cs->alternateVisuals[a]) - return; - pScreen->InstallColormap = cs->InstallColormap; - (*pScreen->InstallColormap) (pColormap); - cs->InstallColormap = pScreen->InstallColormap; - pScreen->InstallColormap = compInstallColormap; -} - -/* Fake backing store via automatic redirection */ -static Bool -compChangeWindowAttributes(WindowPtr pWin, unsigned long mask) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - CompScreenPtr cs = GetCompScreen (pScreen); - Bool ret; - - pScreen->ChangeWindowAttributes = cs->ChangeWindowAttributes; - ret = pScreen->ChangeWindowAttributes(pWin, mask); - - if (ret && (mask & CWBackingStore) && - pScreen->backingStoreSupport != NotUseful) { - if (pWin->backingStore != NotUseful) { - compRedirectWindow(serverClient, pWin, CompositeRedirectAutomatic); - pWin->backStorage = (pointer) (intptr_t) 1; - } else { - compUnredirectWindow(serverClient, pWin, - CompositeRedirectAutomatic); - pWin->backStorage = NULL; - } - } - - pScreen->ChangeWindowAttributes = compChangeWindowAttributes; - - return ret; -} - -static void -compScreenUpdate (ScreenPtr pScreen) -{ - CompScreenPtr cs = GetCompScreen (pScreen); - - compCheckTree (pScreen); - if (cs->damaged) - { - compWindowUpdate (WindowTable[pScreen->myNum]); - cs->damaged = FALSE; - } -} - -static void -compBlockHandler (int i, - pointer blockData, - pointer pTimeout, - pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[i]; - CompScreenPtr cs = GetCompScreen (pScreen); - - pScreen->BlockHandler = cs->BlockHandler; - compScreenUpdate (pScreen); - (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); - cs->BlockHandler = pScreen->BlockHandler; - pScreen->BlockHandler = compBlockHandler; -} - -/* - * Add alternate visuals -- always expose an ARGB32 and RGB24 visual - */ - -static DepthPtr -compFindVisuallessDepth (ScreenPtr pScreen, int d) -{ - int i; - - for (i = 0; i < pScreen->numDepths; i++) - { - DepthPtr depth = &pScreen->allowedDepths[i]; - if (depth->depth == d) - { - /* - * Make sure it doesn't have visuals already - */ - if (depth->numVids) - return 0; - /* - * looks fine - */ - return depth; - } - } - /* - * If there isn't one, then it's gonna be hard to have - * an associated visual - */ - return 0; -} - -/* - * Add a list of visual IDs to the list of visuals to implicitly redirect. - */ -static Bool -compRegisterAlternateVisuals (CompScreenPtr cs, VisualID *vids, int nVisuals) -{ - VisualID *p; - - p = xrealloc(cs->alternateVisuals, - sizeof(VisualID) * (cs->numAlternateVisuals + nVisuals)); - if(p == NULL) - return FALSE; - - memcpy(&p[cs->numAlternateVisuals], vids, sizeof(VisualID) * nVisuals); - - cs->alternateVisuals = p; - cs->numAlternateVisuals += nVisuals; - - return TRUE; -} - -Bool CompositeRegisterAlternateVisuals (ScreenPtr pScreen, VisualID *vids, - int nVisuals) -{ - CompScreenPtr cs = GetCompScreen (pScreen); - return compRegisterAlternateVisuals(cs, vids, nVisuals); -} - -typedef struct _alternateVisual { - int depth; - CARD32 format; -} CompAlternateVisual; - -static CompAlternateVisual altVisuals[] = { -#if COMP_INCLUDE_RGB24_VISUAL - { 24, PICT_r8g8b8 }, -#endif - { 32, PICT_a8r8g8b8 }, -}; - -static const int NUM_COMP_ALTERNATE_VISUALS = sizeof(altVisuals) / - sizeof(CompAlternateVisual); - -static Bool -compAddAlternateVisual(ScreenPtr pScreen, CompScreenPtr cs, - CompAlternateVisual *alt) -{ - VisualPtr visual; - DepthPtr depth; - PictFormatPtr pPictFormat; - unsigned long alphaMask; - - /* - * The ARGB32 visual is always available. Other alternate depth visuals - * are only provided if their depth is less than the root window depth. - * There's no deep reason for this. - */ - if (alt->depth >= pScreen->rootDepth && alt->depth != 32) - return FALSE; - - depth = compFindVisuallessDepth (pScreen, alt->depth); - if (!depth) - /* alt->depth doesn't exist or already has alternate visuals. */ - return TRUE; - - pPictFormat = PictureMatchFormat (pScreen, alt->depth, alt->format); - if (!pPictFormat) - return FALSE; - - if (ResizeVisualArray(pScreen, 1, depth) == FALSE) { - return FALSE; - } - - visual = pScreen->visuals + (pScreen->numVisuals - 1); /* the new one */ - - /* Initialize the visual */ - visual->bitsPerRGBValue = 8; - if (PICT_FORMAT_TYPE(alt->format) == PICT_TYPE_COLOR) { - visual->class = PseudoColor; - visual->nplanes = PICT_FORMAT_BPP(alt->format); - visual->ColormapEntries = 1 << visual->nplanes; - } else { - DirectFormatRec *direct = &pPictFormat->direct; - visual->class = TrueColor; - visual->redMask = ((unsigned long)direct->redMask) << direct->red; - visual->greenMask = ((unsigned long)direct->greenMask) << direct->green; - visual->blueMask = ((unsigned long)direct->blueMask) << direct->blue; - alphaMask = ((unsigned long)direct->alphaMask) << direct->alpha; - visual->offsetRed = direct->red; - visual->offsetGreen = direct->green; - visual->offsetBlue = direct->blue; - /* - * Include A bits in this (unlike GLX which includes only RGB) - * This lets DIX compute suitable masks for colormap allocations - */ - visual->nplanes = Ones (visual->redMask | - visual->greenMask | - visual->blueMask | - alphaMask); - /* find widest component */ - visual->ColormapEntries = (1 << max (Ones (visual->redMask), - max (Ones (visual->greenMask), - Ones (visual->blueMask)))); - } - - /* remember the visual ID to detect auto-update windows */ - compRegisterAlternateVisuals(cs, &visual->vid, 1); - - return TRUE; -} - -static Bool -compAddAlternateVisuals (ScreenPtr pScreen, CompScreenPtr cs) -{ - int alt, ret = 0; - - for (alt = 0; alt < NUM_COMP_ALTERNATE_VISUALS; alt++) - ret |= compAddAlternateVisual(pScreen, cs, altVisuals + alt); - - return !!ret; -} - -Bool -compScreenInit (ScreenPtr pScreen) -{ - CompScreenPtr cs; - - if (GetCompScreen (pScreen)) - return TRUE; - cs = (CompScreenPtr) xalloc (sizeof (CompScreenRec)); - if (!cs) - return FALSE; - - cs->damaged = FALSE; - cs->overlayWid = FakeClientID(0); - cs->pOverlayWin = NULL; - cs->pOverlayClients = NULL; - - cs->numAlternateVisuals = 0; - cs->alternateVisuals = NULL; - - if (!compAddAlternateVisuals (pScreen, cs)) - { - xfree (cs); - return FALSE; - } - - cs->PositionWindow = pScreen->PositionWindow; - pScreen->PositionWindow = compPositionWindow; - - cs->CopyWindow = pScreen->CopyWindow; - pScreen->CopyWindow = compCopyWindow; - - cs->CreateWindow = pScreen->CreateWindow; - pScreen->CreateWindow = compCreateWindow; - - cs->DestroyWindow = pScreen->DestroyWindow; - pScreen->DestroyWindow = compDestroyWindow; - - cs->RealizeWindow = pScreen->RealizeWindow; - pScreen->RealizeWindow = compRealizeWindow; - - cs->UnrealizeWindow = pScreen->UnrealizeWindow; - pScreen->UnrealizeWindow = compUnrealizeWindow; - - cs->ClipNotify = pScreen->ClipNotify; - pScreen->ClipNotify = compClipNotify; - - cs->MoveWindow = pScreen->MoveWindow; - pScreen->MoveWindow = compMoveWindow; - - cs->ResizeWindow = pScreen->ResizeWindow; - pScreen->ResizeWindow = compResizeWindow; - - cs->ChangeBorderWidth = pScreen->ChangeBorderWidth; - pScreen->ChangeBorderWidth = compChangeBorderWidth; - - cs->ReparentWindow = pScreen->ReparentWindow; - pScreen->ReparentWindow = compReparentWindow; - - cs->InstallColormap = pScreen->InstallColormap; - pScreen->InstallColormap = compInstallColormap; - - cs->ChangeWindowAttributes = pScreen->ChangeWindowAttributes; - pScreen->ChangeWindowAttributes = compChangeWindowAttributes; - - cs->BlockHandler = pScreen->BlockHandler; - pScreen->BlockHandler = compBlockHandler; - - cs->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = compCloseScreen; - - dixSetPrivate(&pScreen->devPrivates, CompScreenPrivateKey, cs); - - RegisterRealChildHeadProc(CompositeRealChildHead); - - return TRUE; -} +/* + * Copyright © 2006 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, 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. + * + * 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "compint.h" +#include "compositeext.h" + +static int CompScreenPrivateKeyIndex; +DevPrivateKey CompScreenPrivateKey = &CompScreenPrivateKeyIndex; +static int CompWindowPrivateKeyIndex; +DevPrivateKey CompWindowPrivateKey = &CompWindowPrivateKeyIndex; +static int CompSubwindowsPrivateKeyIndex; +DevPrivateKey CompSubwindowsPrivateKey = &CompSubwindowsPrivateKeyIndex; + + +static Bool +compCloseScreen (int index, ScreenPtr pScreen) +{ + CompScreenPtr cs = GetCompScreen (pScreen); + Bool ret; + + free(cs->alternateVisuals); + + pScreen->CloseScreen = cs->CloseScreen; + pScreen->BlockHandler = cs->BlockHandler; + pScreen->InstallColormap = cs->InstallColormap; + pScreen->ChangeWindowAttributes = cs->ChangeWindowAttributes; + pScreen->ReparentWindow = cs->ReparentWindow; + pScreen->MoveWindow = cs->MoveWindow; + pScreen->ResizeWindow = cs->ResizeWindow; + pScreen->ChangeBorderWidth = cs->ChangeBorderWidth; + + pScreen->ClipNotify = cs->ClipNotify; + pScreen->UnrealizeWindow = cs->UnrealizeWindow; + pScreen->RealizeWindow = cs->RealizeWindow; + pScreen->DestroyWindow = cs->DestroyWindow; + pScreen->CreateWindow = cs->CreateWindow; + pScreen->CopyWindow = cs->CopyWindow; + pScreen->PositionWindow = cs->PositionWindow; + + free(cs); + dixSetPrivate(&pScreen->devPrivates, CompScreenPrivateKey, NULL); + ret = (*pScreen->CloseScreen) (index, pScreen); + + return ret; +} + +static void +compInstallColormap (ColormapPtr pColormap) +{ + VisualPtr pVisual = pColormap->pVisual; + ScreenPtr pScreen = pColormap->pScreen; + CompScreenPtr cs = GetCompScreen (pScreen); + int a; + + for (a = 0; a < cs->numAlternateVisuals; a++) + if (pVisual->vid == cs->alternateVisuals[a]) + return; + pScreen->InstallColormap = cs->InstallColormap; + (*pScreen->InstallColormap) (pColormap); + cs->InstallColormap = pScreen->InstallColormap; + pScreen->InstallColormap = compInstallColormap; +} + +/* Fake backing store via automatic redirection */ +static Bool +compChangeWindowAttributes(WindowPtr pWin, unsigned long mask) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + CompScreenPtr cs = GetCompScreen (pScreen); + Bool ret; + + pScreen->ChangeWindowAttributes = cs->ChangeWindowAttributes; + ret = pScreen->ChangeWindowAttributes(pWin, mask); + + if (ret && (mask & CWBackingStore) && + pScreen->backingStoreSupport != NotUseful) { + if (pWin->backingStore != NotUseful) { + compRedirectWindow(serverClient, pWin, CompositeRedirectAutomatic); + pWin->backStorage = (pointer) (intptr_t) 1; + } else { + compUnredirectWindow(serverClient, pWin, + CompositeRedirectAutomatic); + pWin->backStorage = NULL; + } + } + + pScreen->ChangeWindowAttributes = compChangeWindowAttributes; + + return ret; +} + +static void +compScreenUpdate (ScreenPtr pScreen) +{ + CompScreenPtr cs = GetCompScreen (pScreen); + + compCheckTree (pScreen); + if (cs->damaged) + { + compWindowUpdate (WindowTable[pScreen->myNum]); + cs->damaged = FALSE; + } +} + +static void +compBlockHandler (int i, + pointer blockData, + pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + CompScreenPtr cs = GetCompScreen (pScreen); + + pScreen->BlockHandler = cs->BlockHandler; + compScreenUpdate (pScreen); + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + cs->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = compBlockHandler; +} + +/* + * Add alternate visuals -- always expose an ARGB32 and RGB24 visual + */ + +static DepthPtr +compFindVisuallessDepth (ScreenPtr pScreen, int d) +{ + int i; + + for (i = 0; i < pScreen->numDepths; i++) + { + DepthPtr depth = &pScreen->allowedDepths[i]; + if (depth->depth == d) + { + /* + * Make sure it doesn't have visuals already + */ + if (depth->numVids) + return 0; + /* + * looks fine + */ + return depth; + } + } + /* + * If there isn't one, then it's gonna be hard to have + * an associated visual + */ + return 0; +} + +/* + * Add a list of visual IDs to the list of visuals to implicitly redirect. + */ +static Bool +compRegisterAlternateVisuals (CompScreenPtr cs, VisualID *vids, int nVisuals) +{ + VisualID *p; + + p = realloc(cs->alternateVisuals, + sizeof(VisualID) * (cs->numAlternateVisuals + nVisuals)); + if(p == NULL) + return FALSE; + + memcpy(&p[cs->numAlternateVisuals], vids, sizeof(VisualID) * nVisuals); + + cs->alternateVisuals = p; + cs->numAlternateVisuals += nVisuals; + + return TRUE; +} + +Bool CompositeRegisterAlternateVisuals (ScreenPtr pScreen, VisualID *vids, + int nVisuals) +{ + CompScreenPtr cs = GetCompScreen (pScreen); + return compRegisterAlternateVisuals(cs, vids, nVisuals); +} + +typedef struct _alternateVisual { + int depth; + CARD32 format; +} CompAlternateVisual; + +static CompAlternateVisual altVisuals[] = { +#if COMP_INCLUDE_RGB24_VISUAL + { 24, PICT_r8g8b8 }, +#endif + { 32, PICT_a8r8g8b8 }, +}; + +static const int NUM_COMP_ALTERNATE_VISUALS = sizeof(altVisuals) / + sizeof(CompAlternateVisual); + +static Bool +compAddAlternateVisual(ScreenPtr pScreen, CompScreenPtr cs, + CompAlternateVisual *alt) +{ + VisualPtr visual; + DepthPtr depth; + PictFormatPtr pPictFormat; + unsigned long alphaMask; + + /* + * The ARGB32 visual is always available. Other alternate depth visuals + * are only provided if their depth is less than the root window depth. + * There's no deep reason for this. + */ + if (alt->depth >= pScreen->rootDepth && alt->depth != 32) + return FALSE; + + depth = compFindVisuallessDepth (pScreen, alt->depth); + if (!depth) + /* alt->depth doesn't exist or already has alternate visuals. */ + return TRUE; + + pPictFormat = PictureMatchFormat (pScreen, alt->depth, alt->format); + if (!pPictFormat) + return FALSE; + + if (ResizeVisualArray(pScreen, 1, depth) == FALSE) { + return FALSE; + } + + visual = pScreen->visuals + (pScreen->numVisuals - 1); /* the new one */ + + /* Initialize the visual */ + visual->bitsPerRGBValue = 8; + if (PICT_FORMAT_TYPE(alt->format) == PICT_TYPE_COLOR) { + visual->class = PseudoColor; + visual->nplanes = PICT_FORMAT_BPP(alt->format); + visual->ColormapEntries = 1 << visual->nplanes; + } else { + DirectFormatRec *direct = &pPictFormat->direct; + visual->class = TrueColor; + visual->redMask = ((unsigned long)direct->redMask) << direct->red; + visual->greenMask = ((unsigned long)direct->greenMask) << direct->green; + visual->blueMask = ((unsigned long)direct->blueMask) << direct->blue; + alphaMask = ((unsigned long)direct->alphaMask) << direct->alpha; + visual->offsetRed = direct->red; + visual->offsetGreen = direct->green; + visual->offsetBlue = direct->blue; + /* + * Include A bits in this (unlike GLX which includes only RGB) + * This lets DIX compute suitable masks for colormap allocations + */ + visual->nplanes = Ones (visual->redMask | + visual->greenMask | + visual->blueMask | + alphaMask); + /* find widest component */ + visual->ColormapEntries = (1 << max (Ones (visual->redMask), + max (Ones (visual->greenMask), + Ones (visual->blueMask)))); + } + + /* remember the visual ID to detect auto-update windows */ + compRegisterAlternateVisuals(cs, &visual->vid, 1); + + return TRUE; +} + +static Bool +compAddAlternateVisuals (ScreenPtr pScreen, CompScreenPtr cs) +{ + int alt, ret = 0; + + for (alt = 0; alt < NUM_COMP_ALTERNATE_VISUALS; alt++) + ret |= compAddAlternateVisual(pScreen, cs, altVisuals + alt); + + return !!ret; +} + +Bool +compScreenInit (ScreenPtr pScreen) +{ + CompScreenPtr cs; + + if (GetCompScreen (pScreen)) + return TRUE; + cs = (CompScreenPtr) malloc(sizeof (CompScreenRec)); + if (!cs) + return FALSE; + + cs->damaged = FALSE; + cs->overlayWid = FakeClientID(0); + cs->pOverlayWin = NULL; + cs->pOverlayClients = NULL; + + cs->numAlternateVisuals = 0; + cs->alternateVisuals = NULL; + + if (!compAddAlternateVisuals (pScreen, cs)) + { + free(cs); + return FALSE; + } + + cs->PositionWindow = pScreen->PositionWindow; + pScreen->PositionWindow = compPositionWindow; + + cs->CopyWindow = pScreen->CopyWindow; + pScreen->CopyWindow = compCopyWindow; + + cs->CreateWindow = pScreen->CreateWindow; + pScreen->CreateWindow = compCreateWindow; + + cs->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = compDestroyWindow; + + cs->RealizeWindow = pScreen->RealizeWindow; + pScreen->RealizeWindow = compRealizeWindow; + + cs->UnrealizeWindow = pScreen->UnrealizeWindow; + pScreen->UnrealizeWindow = compUnrealizeWindow; + + cs->ClipNotify = pScreen->ClipNotify; + pScreen->ClipNotify = compClipNotify; + + cs->MoveWindow = pScreen->MoveWindow; + pScreen->MoveWindow = compMoveWindow; + + cs->ResizeWindow = pScreen->ResizeWindow; + pScreen->ResizeWindow = compResizeWindow; + + cs->ChangeBorderWidth = pScreen->ChangeBorderWidth; + pScreen->ChangeBorderWidth = compChangeBorderWidth; + + cs->ReparentWindow = pScreen->ReparentWindow; + pScreen->ReparentWindow = compReparentWindow; + + cs->InstallColormap = pScreen->InstallColormap; + pScreen->InstallColormap = compInstallColormap; + + cs->ChangeWindowAttributes = pScreen->ChangeWindowAttributes; + pScreen->ChangeWindowAttributes = compChangeWindowAttributes; + + cs->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = compBlockHandler; + + cs->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = compCloseScreen; + + dixSetPrivate(&pScreen->devPrivates, CompScreenPrivateKey, cs); + + RegisterRealChildHeadProc(CompositeRealChildHead); + + return TRUE; +} diff --git a/xorg-server/composite/compoverlay.c b/xorg-server/composite/compoverlay.c index 6d73f003d..453259e92 100644 --- a/xorg-server/composite/compoverlay.c +++ b/xorg-server/composite/compoverlay.c @@ -1,160 +1,160 @@ -/* - * Copyright © 2006 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, 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. - * - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "compint.h" -#include "xace.h" - -/* - * Delete the given overlay client list element from its screen list. - */ -void -compFreeOverlayClient (CompOverlayClientPtr pOcToDel) -{ - ScreenPtr pScreen = pOcToDel->pScreen; - CompScreenPtr cs = GetCompScreen (pScreen); - CompOverlayClientPtr *pPrev, pOc; - - for (pPrev = &cs->pOverlayClients; (pOc = *pPrev); pPrev = &pOc->pNext) - { - if (pOc == pOcToDel) { - *pPrev = pOc->pNext; - xfree (pOc); - break; - } - } - - /* Destroy overlay window when there are no more clients using it */ - if (cs->pOverlayClients == NULL) - compDestroyOverlayWindow (pScreen); -} - -/* - * Return the client's first overlay client rec from the given screen - */ -CompOverlayClientPtr -compFindOverlayClient (ScreenPtr pScreen, ClientPtr pClient) -{ - CompScreenPtr cs = GetCompScreen(pScreen); - CompOverlayClientPtr pOc; - - for (pOc = cs->pOverlayClients; pOc != NULL; pOc = pOc->pNext) - if (pOc->pClient == pClient) - return pOc; - - return NULL; -} - -/* - * Create an overlay client object for the given client - */ -CompOverlayClientPtr -compCreateOverlayClient (ScreenPtr pScreen, ClientPtr pClient) -{ - CompScreenPtr cs = GetCompScreen(pScreen); - CompOverlayClientPtr pOc; - - pOc = (CompOverlayClientPtr) xalloc(sizeof(CompOverlayClientRec)); - if (pOc == NULL) - return NULL; - - pOc->pClient = pClient; - pOc->pScreen = pScreen; - pOc->resource = FakeClientID(pClient->index); - pOc->pNext = cs->pOverlayClients; - cs->pOverlayClients = pOc; - - /* - * Create a resource for this element so it can be deleted - * when the client goes away. - */ - if (!AddResource (pOc->resource, CompositeClientOverlayType, (pointer) pOc)) - return NULL; - - return pOc; -} - -/* - * Create the overlay window and map it - */ -Bool -compCreateOverlayWindow (ScreenPtr pScreen) -{ - CompScreenPtr cs = GetCompScreen(pScreen); - WindowPtr pRoot = WindowTable[pScreen->myNum]; - WindowPtr pWin; - XID attrs[] = { None, TRUE }; /* backPixmap, overrideRedirect */ - int result; - - pWin = cs->pOverlayWin = - CreateWindow (cs->overlayWid, pRoot, - 0, 0, pScreen->width, pScreen->height, 0, - InputOutput, CWBackPixmap | CWOverrideRedirect, &attrs[0], - pRoot->drawable.depth, - serverClient, pScreen->rootVisual, &result); - if (pWin == NULL) - return FALSE; - - if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer)pWin)) - return FALSE; - - MapWindow(pWin, serverClient); - - return TRUE; -} - -/* - * Destroy the overlay window - */ -void -compDestroyOverlayWindow (ScreenPtr pScreen) -{ - CompScreenPtr cs = GetCompScreen(pScreen); - - cs->pOverlayWin = NullWindow; - FreeResource (cs->overlayWid, RT_NONE); -} - +/* + * Copyright © 2006 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, 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. + * + * 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "compint.h" +#include "xace.h" + +/* + * Delete the given overlay client list element from its screen list. + */ +void +compFreeOverlayClient (CompOverlayClientPtr pOcToDel) +{ + ScreenPtr pScreen = pOcToDel->pScreen; + CompScreenPtr cs = GetCompScreen (pScreen); + CompOverlayClientPtr *pPrev, pOc; + + for (pPrev = &cs->pOverlayClients; (pOc = *pPrev); pPrev = &pOc->pNext) + { + if (pOc == pOcToDel) { + *pPrev = pOc->pNext; + free(pOc); + break; + } + } + + /* Destroy overlay window when there are no more clients using it */ + if (cs->pOverlayClients == NULL) + compDestroyOverlayWindow (pScreen); +} + +/* + * Return the client's first overlay client rec from the given screen + */ +CompOverlayClientPtr +compFindOverlayClient (ScreenPtr pScreen, ClientPtr pClient) +{ + CompScreenPtr cs = GetCompScreen(pScreen); + CompOverlayClientPtr pOc; + + for (pOc = cs->pOverlayClients; pOc != NULL; pOc = pOc->pNext) + if (pOc->pClient == pClient) + return pOc; + + return NULL; +} + +/* + * Create an overlay client object for the given client + */ +CompOverlayClientPtr +compCreateOverlayClient (ScreenPtr pScreen, ClientPtr pClient) +{ + CompScreenPtr cs = GetCompScreen(pScreen); + CompOverlayClientPtr pOc; + + pOc = (CompOverlayClientPtr) malloc(sizeof(CompOverlayClientRec)); + if (pOc == NULL) + return NULL; + + pOc->pClient = pClient; + pOc->pScreen = pScreen; + pOc->resource = FakeClientID(pClient->index); + pOc->pNext = cs->pOverlayClients; + cs->pOverlayClients = pOc; + + /* + * Create a resource for this element so it can be deleted + * when the client goes away. + */ + if (!AddResource (pOc->resource, CompositeClientOverlayType, (pointer) pOc)) + return NULL; + + return pOc; +} + +/* + * Create the overlay window and map it + */ +Bool +compCreateOverlayWindow (ScreenPtr pScreen) +{ + CompScreenPtr cs = GetCompScreen(pScreen); + WindowPtr pRoot = WindowTable[pScreen->myNum]; + WindowPtr pWin; + XID attrs[] = { None, TRUE }; /* backPixmap, overrideRedirect */ + int result; + + pWin = cs->pOverlayWin = + CreateWindow (cs->overlayWid, pRoot, + 0, 0, pScreen->width, pScreen->height, 0, + InputOutput, CWBackPixmap | CWOverrideRedirect, &attrs[0], + pRoot->drawable.depth, + serverClient, pScreen->rootVisual, &result); + if (pWin == NULL) + return FALSE; + + if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer)pWin)) + return FALSE; + + MapWindow(pWin, serverClient); + + return TRUE; +} + +/* + * Destroy the overlay window + */ +void +compDestroyOverlayWindow (ScreenPtr pScreen) +{ + CompScreenPtr cs = GetCompScreen(pScreen); + + cs->pOverlayWin = NullWindow; + FreeResource (cs->overlayWid, RT_NONE); +} + diff --git a/xorg-server/config/config.c b/xorg-server/config/config.c index 7bf5e4179..1ffbdcdad 100644 --- a/xorg-server/config/config.c +++ b/xorg-server/config/config.c @@ -1,139 +1,139 @@ -/* - * Copyright © 2006-2007 Daniel Stone - * - * 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. - * - * Author: Daniel Stone - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "os.h" -#include "inputstr.h" -#include "hotplug.h" -#include "config-backends.h" - -void -config_init(void) -{ -#ifdef CONFIG_UDEV - if (!config_udev_init()) - ErrorF("[config] failed to initialise udev\n"); -#elif defined(CONFIG_NEED_DBUS) - if (config_dbus_core_init()) { -# ifdef CONFIG_DBUS_API - if (!config_dbus_init()) - ErrorF("[config] failed to initialise D-Bus API\n"); -# endif -# ifdef CONFIG_HAL - if (!config_hal_init()) - ErrorF("[config] failed to initialise HAL\n"); -# endif - } - else { - ErrorF("[config] failed to initialise D-Bus core\n"); - } -#endif -} - -void -config_fini(void) -{ -#if defined(CONFIG_UDEV) - config_udev_fini(); -#elif defined(CONFIG_NEED_DBUS) -# ifdef CONFIG_HAL - config_hal_fini(); -# endif -# ifdef CONFIG_DBUS_API - config_dbus_fini(); -# endif - config_dbus_core_fini(); -#endif -} - -static void -remove_device(const char *backend, DeviceIntPtr dev) -{ - /* this only gets called for devices that have already been added */ - LogMessage(X_INFO, "config/%s: removing device %s\n", backend, dev->name); - - /* Call PIE here so we don't try to dereference a device that's - * already been removed. */ - OsBlockSignals(); - ProcessInputEvents(); - DeleteInputDeviceRequest(dev); - OsReleaseSignals(); -} - -void -remove_devices(const char *backend, const char *config_info) -{ - DeviceIntPtr dev, next; - - for (dev = inputInfo.devices; dev; dev = next) { - next = dev->next; - if (dev->config_info && strcmp(dev->config_info, config_info) == 0) - remove_device(backend, dev); - } - for (dev = inputInfo.off_devices; dev; dev = next) { - next = dev->next; - if (dev->config_info && strcmp(dev->config_info, config_info) == 0) - remove_device(backend, dev); - } -} - -BOOL -device_is_duplicate(const char *config_info) -{ - DeviceIntPtr dev; - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) - return TRUE; - } - - for (dev = inputInfo.off_devices; dev; dev = dev->next) - { - if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) - return TRUE; - } - - return FALSE; -} - -void -add_option(InputOption **options, const char *key, const char *value) -{ - if (!value || *value == '\0') - return; - - for (; *options; options = &(*options)->next) - ; - *options = xcalloc(sizeof(**options), 1); - if (!*options) /* Yeesh. */ - return; - (*options)->key = xstrdup(key); - (*options)->value = xstrdup(value); - (*options)->next = NULL; -} +/* + * Copyright © 2006-2007 Daniel Stone + * + * 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. + * + * Author: Daniel Stone + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "os.h" +#include "inputstr.h" +#include "hotplug.h" +#include "config-backends.h" + +void +config_init(void) +{ +#ifdef CONFIG_UDEV + if (!config_udev_init()) + ErrorF("[config] failed to initialise udev\n"); +#elif defined(CONFIG_NEED_DBUS) + if (config_dbus_core_init()) { +# ifdef CONFIG_DBUS_API + if (!config_dbus_init()) + ErrorF("[config] failed to initialise D-Bus API\n"); +# endif +# ifdef CONFIG_HAL + if (!config_hal_init()) + ErrorF("[config] failed to initialise HAL\n"); +# endif + } + else { + ErrorF("[config] failed to initialise D-Bus core\n"); + } +#endif +} + +void +config_fini(void) +{ +#if defined(CONFIG_UDEV) + config_udev_fini(); +#elif defined(CONFIG_NEED_DBUS) +# ifdef CONFIG_HAL + config_hal_fini(); +# endif +# ifdef CONFIG_DBUS_API + config_dbus_fini(); +# endif + config_dbus_core_fini(); +#endif +} + +static void +remove_device(const char *backend, DeviceIntPtr dev) +{ + /* this only gets called for devices that have already been added */ + LogMessage(X_INFO, "config/%s: removing device %s\n", backend, dev->name); + + /* Call PIE here so we don't try to dereference a device that's + * already been removed. */ + OsBlockSignals(); + ProcessInputEvents(); + DeleteInputDeviceRequest(dev); + OsReleaseSignals(); +} + +void +remove_devices(const char *backend, const char *config_info) +{ + DeviceIntPtr dev, next; + + for (dev = inputInfo.devices; dev; dev = next) { + next = dev->next; + if (dev->config_info && strcmp(dev->config_info, config_info) == 0) + remove_device(backend, dev); + } + for (dev = inputInfo.off_devices; dev; dev = next) { + next = dev->next; + if (dev->config_info && strcmp(dev->config_info, config_info) == 0) + remove_device(backend, dev); + } +} + +BOOL +device_is_duplicate(const char *config_info) +{ + DeviceIntPtr dev; + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) + return TRUE; + } + + for (dev = inputInfo.off_devices; dev; dev = dev->next) + { + if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) + return TRUE; + } + + return FALSE; +} + +void +add_option(InputOption **options, const char *key, const char *value) +{ + if (!value || *value == '\0') + return; + + for (; *options; options = &(*options)->next) + ; + *options = calloc(sizeof(**options), 1); + if (!*options) /* Yeesh. */ + return; + (*options)->key = xstrdup(key); + (*options)->value = xstrdup(value); + (*options)->next = NULL; +} diff --git a/xorg-server/config/dbus.c b/xorg-server/config/dbus.c index 86d9d287f..d6316623b 100644 --- a/xorg-server/config/dbus.c +++ b/xorg-server/config/dbus.c @@ -1,442 +1,442 @@ -/* - * Copyright © 2006-2007 Daniel Stone - * - * 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. - * - * Author: Daniel Stone - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#define DBUS_API_SUBJECT_TO_CHANGE -#include -#include - -#include - -#include "config-backends.h" -#include "opaque.h" /* for 'display': there should be a better way. */ -#include "input.h" -#include "inputstr.h" - -#define API_VERSION 2 - -#define MATCH_RULE "type='method_call',interface='org.x.config.input'" - -#define MALFORMED_MSG "[config/dbus] malformed message, dropping" -#define MALFORMED_MESSAGE() { DebugF(MALFORMED_MSG "\n"); \ - ret = BadValue; \ - goto unwind; } -#define MALFORMED_MESSAGE_ERROR() { DebugF(MALFORMED_MSG ": %s, %s", \ - error->name, error->message); \ - ret = BadValue; \ - goto unwind; } - -struct connection_info { - char busobject[32]; - char busname[64]; - DBusConnection *connection; -}; - -static void -reset_info(struct connection_info *info) -{ - info->connection = NULL; - info->busname[0] = '\0'; - info->busobject[0] = '\0'; -} - -static int -add_device(DBusMessage *message, DBusMessage *reply, DBusError *error) -{ - DBusMessageIter iter, reply_iter, subiter; - InputOption *tmpo = NULL, *options = NULL; - char *tmp = NULL; - int ret, err; - DeviceIntPtr dev = NULL; - - dbus_message_iter_init_append(reply, &reply_iter); - - if (!dbus_message_iter_init(message, &iter)) { - ErrorF("[config/dbus] couldn't initialise iterator\n"); - MALFORMED_MESSAGE(); - } - - options = xcalloc(sizeof(*options), 1); - if (!options) { - ErrorF("[config/dbus] couldn't allocate option\n"); - return BadAlloc; - } - - options->key = xstrdup("_source"); - options->value = xstrdup("client/dbus"); - if (!options->key || !options->value) { - ErrorF("[config/dbus] couldn't allocate first key/value pair\n"); - ret = BadAlloc; - goto unwind; - } - - /* signature should be [ss][ss]... */ - while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) { - tmpo = xcalloc(sizeof(*tmpo), 1); - if (!tmpo) { - ErrorF("[config/dbus] couldn't allocate option\n"); - ret = BadAlloc; - goto unwind; - } - tmpo->next = options; - options = tmpo; - - dbus_message_iter_recurse(&iter, &subiter); - - if (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_STRING) - MALFORMED_MESSAGE(); - - dbus_message_iter_get_basic(&subiter, &tmp); - if (!tmp) - MALFORMED_MESSAGE(); - /* The _ prefix refers to internal settings, and may not be given by - * the client. */ - if (tmp[0] == '_') { - ErrorF("[config/dbus] attempted subterfuge: option name %s given\n", - tmp); - MALFORMED_MESSAGE(); - } - options->key = xstrdup(tmp); - if (!options->key) { - ErrorF("[config/dbus] couldn't duplicate key!\n"); - ret = BadAlloc; - goto unwind; - } - - if (!dbus_message_iter_has_next(&subiter)) - MALFORMED_MESSAGE(); - dbus_message_iter_next(&subiter); - if (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_STRING) - MALFORMED_MESSAGE(); - - dbus_message_iter_get_basic(&subiter, &tmp); - if (!tmp) - MALFORMED_MESSAGE(); - options->value = xstrdup(tmp); - if (!options->value) { - ErrorF("[config/dbus] couldn't duplicate option!\n"); - ret = BadAlloc; - goto unwind; - } - - dbus_message_iter_next(&iter); - } - - ret = NewInputDeviceRequest(options, NULL, &dev); - if (ret != Success) { - DebugF("[config/dbus] NewInputDeviceRequest failed\n"); - goto unwind; - } - - if (!dev) { - DebugF("[config/dbus] NewInputDeviceRequest provided no device\n"); - ret = BadImplementation; - goto unwind; - } - - /* XXX: If we fail halfway through, we don't seem to have any way to - * empty the iterator, so you'll end up with some device IDs, - * plus an error. This seems to be a shortcoming in the D-Bus - * API. */ - for (; dev; dev = dev->next) { - if (!dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, - &dev->id)) { - ErrorF("[config/dbus] couldn't append to iterator\n"); - ret = BadAlloc; - goto unwind; - } - } - -unwind: - if (ret != Success) { - if (dev) - RemoveDevice(dev, TRUE); - - err = -ret; - dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &err); - } - - while (options) { - tmpo = options; - options = options->next; - if (tmpo->key) - xfree(tmpo->key); - if (tmpo->value) - xfree(tmpo->value); - xfree(tmpo); - } - - return ret; -} - -static int -remove_device(DBusMessage *message, DBusMessage *reply, DBusError *error) -{ - int deviceid, ret, err; - DeviceIntPtr dev; - DBusMessageIter iter, reply_iter; - - dbus_message_iter_init_append(reply, &reply_iter); - - if (!dbus_message_iter_init(message, &iter)) { - ErrorF("[config/dbus] failed to init iterator\n"); - MALFORMED_MESSAGE(); - } - - if (!dbus_message_get_args(message, error, DBUS_TYPE_UINT32, - &deviceid, DBUS_TYPE_INVALID)) { - MALFORMED_MESSAGE_ERROR(); - } - - dixLookupDevice(&dev, deviceid, serverClient, DixDestroyAccess); - if (!dev) { - DebugF("[config/dbus] bogus device id %d given\n", deviceid); - ret = BadMatch; - goto unwind; - } - - DebugF("[config/dbus] removing device %s (id %d)\n", dev->name, deviceid); - - /* Call PIE here so we don't try to dereference a device that's - * already been removed. */ - OsBlockSignals(); - ProcessInputEvents(); - DeleteInputDeviceRequest(dev); - OsReleaseSignals(); - - ret = Success; - -unwind: - err = (ret == Success) ? ret : -ret; - dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &err); - - return ret; -} - -static int -list_devices(DBusMessage *message, DBusMessage *reply, DBusError *error) -{ - DeviceIntPtr dev; - DBusMessageIter iter, subiter; - - dbus_message_iter_init_append(reply, &iter); - - for (dev = inputInfo.devices; dev; dev = dev->next) { - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, - &subiter)) { - ErrorF("[config/dbus] couldn't init container\n"); - return BadAlloc; - } - if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_UINT32, - &dev->id)) { - ErrorF("[config/dbus] couldn't append to iterator\n"); - return BadAlloc; - } - if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING, - &dev->name)) { - ErrorF("[config/dbus] couldn't append to iterator\n"); - return BadAlloc; - } - if (!dbus_message_iter_close_container(&iter, &subiter)) { - ErrorF("[config/dbus] couldn't close container\n"); - return BadAlloc; - } - } - - return Success; -} - -static int -get_version(DBusMessage *message, DBusMessage *reply, DBusError *error) -{ - DBusMessageIter iter; - unsigned int version = API_VERSION; - - dbus_message_iter_init_append(reply, &iter); - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &version)) { - ErrorF("[config/dbus] couldn't append version\n"); - return BadAlloc; - } - - return Success; -} - -static DBusHandlerResult -message_handler(DBusConnection *connection, DBusMessage *message, void *data) -{ - DBusError error; - DBusMessage *reply; - struct connection_info *info = data; - - /* ret is the overall D-Bus handler result, whereas err is the internal - * X error from our individual functions. */ - int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - int err; - - DebugF("[config/dbus] received a message for %s\n", - dbus_message_get_interface(message)); - - dbus_error_init(&error); - - reply = dbus_message_new_method_return(message); - if (!reply) { - ErrorF("[config/dbus] failed to create reply\n"); - ret = DBUS_HANDLER_RESULT_NEED_MEMORY; - goto err_start; - } - - if (strcmp(dbus_message_get_member(message), "add") == 0) - err = add_device(message, reply, &error); - else if (strcmp(dbus_message_get_member(message), "remove") == 0) - err = remove_device(message, reply, &error); - else if (strcmp(dbus_message_get_member(message), "listDevices") == 0) - err = list_devices(message, reply, &error); - else if (strcmp(dbus_message_get_member(message), "version") == 0) - err = get_version(message, reply, &error); - else - goto err_reply; - - /* Failure to allocate is a special case. */ - if (err == BadAlloc) { - ret = DBUS_HANDLER_RESULT_NEED_MEMORY; - goto err_reply; - } - - /* While failure here is always an OOM, we don't return that, - * since that would result in devices being double-added/removed. */ - if (dbus_connection_send(info->connection, reply, NULL)) - dbus_connection_flush(info->connection); - else - ErrorF("[config/dbus] failed to send reply\n"); - - ret = DBUS_HANDLER_RESULT_HANDLED; - -err_reply: - dbus_message_unref(reply); -err_start: - dbus_error_free(&error); - - return ret; -} - -static void -connect_hook(DBusConnection *connection, void *data) -{ - DBusError error; - DBusObjectPathVTable vtable = { .message_function = message_handler, }; - struct connection_info *info = data; - - info->connection = connection; - - dbus_error_init(&error); - - dbus_bus_request_name(info->connection, info->busname, 0, &error); - if (dbus_error_is_set(&error)) { - ErrorF("[config/dbus] couldn't take over org.x.config: %s (%s)\n", - error.name, error.message); - goto err_start; - } - - /* blocks until we get a reply. */ - dbus_bus_add_match(info->connection, MATCH_RULE, &error); - if (dbus_error_is_set(&error)) { - ErrorF("[config/dbus] couldn't add match: %s (%s)\n", error.name, - error.message); - goto err_name; - } - - if (!dbus_connection_register_object_path(info->connection, - info->busobject, &vtable, - info)) { - ErrorF("[config/dbus] couldn't register object path\n"); - goto err_match; - } - - DebugF("[dbus] registered %s, %s\n", info->busname, info->busobject); - - dbus_error_free(&error); - - return; - -err_match: - dbus_bus_remove_match(info->connection, MATCH_RULE, &error); -err_name: - dbus_bus_release_name(info->connection, info->busname, &error); -err_start: - dbus_error_free(&error); - - reset_info(info); -} - -static void -disconnect_hook(void *data) -{ -} - -#if 0 -void -pre_disconnect_hook(void) -{ - DBusError error; - - dbus_error_init(&error); - dbus_connection_unregister_object_path(connection_data->connection, - connection_data->busobject); - dbus_bus_remove_match(connection_data->connection, MATCH_RULE, - &error); - dbus_bus_release_name(connection_data->connection, - connection_data->busname, &error); - dbus_error_free(&error); -} -#endif - -static struct connection_info connection_data; -static struct config_dbus_core_hook core_hook = { - .connect = connect_hook, - .disconnect = disconnect_hook, - .data = &connection_data, -}; - -int -config_dbus_init(void) -{ - snprintf(connection_data.busname, sizeof(connection_data.busname), - "org.x.config.display%d", atoi(display)); - snprintf(connection_data.busobject, sizeof(connection_data.busobject), - "/org/x/config/%d", atoi(display)); - - return config_dbus_core_add_hook(&core_hook); -} - -void -config_dbus_fini(void) -{ - config_dbus_core_remove_hook(&core_hook); - connection_data.busname[0] = '\0'; - connection_data.busobject[0] = '\0'; -} +/* + * Copyright © 2006-2007 Daniel Stone + * + * 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. + * + * Author: Daniel Stone + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include + +#include + +#include "config-backends.h" +#include "opaque.h" /* for 'display': there should be a better way. */ +#include "input.h" +#include "inputstr.h" + +#define API_VERSION 2 + +#define MATCH_RULE "type='method_call',interface='org.x.config.input'" + +#define MALFORMED_MSG "[config/dbus] malformed message, dropping" +#define MALFORMED_MESSAGE() { DebugF(MALFORMED_MSG "\n"); \ + ret = BadValue; \ + goto unwind; } +#define MALFORMED_MESSAGE_ERROR() { DebugF(MALFORMED_MSG ": %s, %s", \ + error->name, error->message); \ + ret = BadValue; \ + goto unwind; } + +struct connection_info { + char busobject[32]; + char busname[64]; + DBusConnection *connection; +}; + +static void +reset_info(struct connection_info *info) +{ + info->connection = NULL; + info->busname[0] = '\0'; + info->busobject[0] = '\0'; +} + +static int +add_device(DBusMessage *message, DBusMessage *reply, DBusError *error) +{ + DBusMessageIter iter, reply_iter, subiter; + InputOption *tmpo = NULL, *options = NULL; + char *tmp = NULL; + int ret, err; + DeviceIntPtr dev = NULL; + + dbus_message_iter_init_append(reply, &reply_iter); + + if (!dbus_message_iter_init(message, &iter)) { + ErrorF("[config/dbus] couldn't initialise iterator\n"); + MALFORMED_MESSAGE(); + } + + options = calloc(sizeof(*options), 1); + if (!options) { + ErrorF("[config/dbus] couldn't allocate option\n"); + return BadAlloc; + } + + options->key = xstrdup("_source"); + options->value = xstrdup("client/dbus"); + if (!options->key || !options->value) { + ErrorF("[config/dbus] couldn't allocate first key/value pair\n"); + ret = BadAlloc; + goto unwind; + } + + /* signature should be [ss][ss]... */ + while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) { + tmpo = calloc(sizeof(*tmpo), 1); + if (!tmpo) { + ErrorF("[config/dbus] couldn't allocate option\n"); + ret = BadAlloc; + goto unwind; + } + tmpo->next = options; + options = tmpo; + + dbus_message_iter_recurse(&iter, &subiter); + + if (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_STRING) + MALFORMED_MESSAGE(); + + dbus_message_iter_get_basic(&subiter, &tmp); + if (!tmp) + MALFORMED_MESSAGE(); + /* The _ prefix refers to internal settings, and may not be given by + * the client. */ + if (tmp[0] == '_') { + ErrorF("[config/dbus] attempted subterfuge: option name %s given\n", + tmp); + MALFORMED_MESSAGE(); + } + options->key = xstrdup(tmp); + if (!options->key) { + ErrorF("[config/dbus] couldn't duplicate key!\n"); + ret = BadAlloc; + goto unwind; + } + + if (!dbus_message_iter_has_next(&subiter)) + MALFORMED_MESSAGE(); + dbus_message_iter_next(&subiter); + if (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_STRING) + MALFORMED_MESSAGE(); + + dbus_message_iter_get_basic(&subiter, &tmp); + if (!tmp) + MALFORMED_MESSAGE(); + options->value = xstrdup(tmp); + if (!options->value) { + ErrorF("[config/dbus] couldn't duplicate option!\n"); + ret = BadAlloc; + goto unwind; + } + + dbus_message_iter_next(&iter); + } + + ret = NewInputDeviceRequest(options, NULL, &dev); + if (ret != Success) { + DebugF("[config/dbus] NewInputDeviceRequest failed\n"); + goto unwind; + } + + if (!dev) { + DebugF("[config/dbus] NewInputDeviceRequest provided no device\n"); + ret = BadImplementation; + goto unwind; + } + + /* XXX: If we fail halfway through, we don't seem to have any way to + * empty the iterator, so you'll end up with some device IDs, + * plus an error. This seems to be a shortcoming in the D-Bus + * API. */ + for (; dev; dev = dev->next) { + if (!dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, + &dev->id)) { + ErrorF("[config/dbus] couldn't append to iterator\n"); + ret = BadAlloc; + goto unwind; + } + } + +unwind: + if (ret != Success) { + if (dev) + RemoveDevice(dev, TRUE); + + err = -ret; + dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &err); + } + + while (options) { + tmpo = options; + options = options->next; + if (tmpo->key) + free(tmpo->key); + if (tmpo->value) + free(tmpo->value); + free(tmpo); + } + + return ret; +} + +static int +remove_device(DBusMessage *message, DBusMessage *reply, DBusError *error) +{ + int deviceid, ret, err; + DeviceIntPtr dev; + DBusMessageIter iter, reply_iter; + + dbus_message_iter_init_append(reply, &reply_iter); + + if (!dbus_message_iter_init(message, &iter)) { + ErrorF("[config/dbus] failed to init iterator\n"); + MALFORMED_MESSAGE(); + } + + if (!dbus_message_get_args(message, error, DBUS_TYPE_UINT32, + &deviceid, DBUS_TYPE_INVALID)) { + MALFORMED_MESSAGE_ERROR(); + } + + dixLookupDevice(&dev, deviceid, serverClient, DixDestroyAccess); + if (!dev) { + DebugF("[config/dbus] bogus device id %d given\n", deviceid); + ret = BadMatch; + goto unwind; + } + + DebugF("[config/dbus] removing device %s (id %d)\n", dev->name, deviceid); + + /* Call PIE here so we don't try to dereference a device that's + * already been removed. */ + OsBlockSignals(); + ProcessInputEvents(); + DeleteInputDeviceRequest(dev); + OsReleaseSignals(); + + ret = Success; + +unwind: + err = (ret == Success) ? ret : -ret; + dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &err); + + return ret; +} + +static int +list_devices(DBusMessage *message, DBusMessage *reply, DBusError *error) +{ + DeviceIntPtr dev; + DBusMessageIter iter, subiter; + + dbus_message_iter_init_append(reply, &iter); + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, + &subiter)) { + ErrorF("[config/dbus] couldn't init container\n"); + return BadAlloc; + } + if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_UINT32, + &dev->id)) { + ErrorF("[config/dbus] couldn't append to iterator\n"); + return BadAlloc; + } + if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING, + &dev->name)) { + ErrorF("[config/dbus] couldn't append to iterator\n"); + return BadAlloc; + } + if (!dbus_message_iter_close_container(&iter, &subiter)) { + ErrorF("[config/dbus] couldn't close container\n"); + return BadAlloc; + } + } + + return Success; +} + +static int +get_version(DBusMessage *message, DBusMessage *reply, DBusError *error) +{ + DBusMessageIter iter; + unsigned int version = API_VERSION; + + dbus_message_iter_init_append(reply, &iter); + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &version)) { + ErrorF("[config/dbus] couldn't append version\n"); + return BadAlloc; + } + + return Success; +} + +static DBusHandlerResult +message_handler(DBusConnection *connection, DBusMessage *message, void *data) +{ + DBusError error; + DBusMessage *reply; + struct connection_info *info = data; + + /* ret is the overall D-Bus handler result, whereas err is the internal + * X error from our individual functions. */ + int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + int err; + + DebugF("[config/dbus] received a message for %s\n", + dbus_message_get_interface(message)); + + dbus_error_init(&error); + + reply = dbus_message_new_method_return(message); + if (!reply) { + ErrorF("[config/dbus] failed to create reply\n"); + ret = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto err_start; + } + + if (strcmp(dbus_message_get_member(message), "add") == 0) + err = add_device(message, reply, &error); + else if (strcmp(dbus_message_get_member(message), "remove") == 0) + err = remove_device(message, reply, &error); + else if (strcmp(dbus_message_get_member(message), "listDevices") == 0) + err = list_devices(message, reply, &error); + else if (strcmp(dbus_message_get_member(message), "version") == 0) + err = get_version(message, reply, &error); + else + goto err_reply; + + /* Failure to allocate is a special case. */ + if (err == BadAlloc) { + ret = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto err_reply; + } + + /* While failure here is always an OOM, we don't return that, + * since that would result in devices being double-added/removed. */ + if (dbus_connection_send(info->connection, reply, NULL)) + dbus_connection_flush(info->connection); + else + ErrorF("[config/dbus] failed to send reply\n"); + + ret = DBUS_HANDLER_RESULT_HANDLED; + +err_reply: + dbus_message_unref(reply); +err_start: + dbus_error_free(&error); + + return ret; +} + +static void +connect_hook(DBusConnection *connection, void *data) +{ + DBusError error; + DBusObjectPathVTable vtable = { .message_function = message_handler, }; + struct connection_info *info = data; + + info->connection = connection; + + dbus_error_init(&error); + + dbus_bus_request_name(info->connection, info->busname, 0, &error); + if (dbus_error_is_set(&error)) { + ErrorF("[config/dbus] couldn't take over org.x.config: %s (%s)\n", + error.name, error.message); + goto err_start; + } + + /* blocks until we get a reply. */ + dbus_bus_add_match(info->connection, MATCH_RULE, &error); + if (dbus_error_is_set(&error)) { + ErrorF("[config/dbus] couldn't add match: %s (%s)\n", error.name, + error.message); + goto err_name; + } + + if (!dbus_connection_register_object_path(info->connection, + info->busobject, &vtable, + info)) { + ErrorF("[config/dbus] couldn't register object path\n"); + goto err_match; + } + + DebugF("[dbus] registered %s, %s\n", info->busname, info->busobject); + + dbus_error_free(&error); + + return; + +err_match: + dbus_bus_remove_match(info->connection, MATCH_RULE, &error); +err_name: + dbus_bus_release_name(info->connection, info->busname, &error); +err_start: + dbus_error_free(&error); + + reset_info(info); +} + +static void +disconnect_hook(void *data) +{ +} + +#if 0 +void +pre_disconnect_hook(void) +{ + DBusError error; + + dbus_error_init(&error); + dbus_connection_unregister_object_path(connection_data->connection, + connection_data->busobject); + dbus_bus_remove_match(connection_data->connection, MATCH_RULE, + &error); + dbus_bus_release_name(connection_data->connection, + connection_data->busname, &error); + dbus_error_free(&error); +} +#endif + +static struct connection_info connection_data; +static struct config_dbus_core_hook core_hook = { + .connect = connect_hook, + .disconnect = disconnect_hook, + .data = &connection_data, +}; + +int +config_dbus_init(void) +{ + snprintf(connection_data.busname, sizeof(connection_data.busname), + "org.x.config.display%d", atoi(display)); + snprintf(connection_data.busobject, sizeof(connection_data.busobject), + "/org/x/config/%d", atoi(display)); + + return config_dbus_core_add_hook(&core_hook); +} + +void +config_dbus_fini(void) +{ + config_dbus_core_remove_hook(&core_hook); + connection_data.busname[0] = '\0'; + connection_data.busobject[0] = '\0'; +} diff --git a/xorg-server/config/hal.c b/xorg-server/config/hal.c index d3daa84cd..738cb3185 100644 --- a/xorg-server/config/hal.c +++ b/xorg-server/config/hal.c @@ -1,647 +1,647 @@ -/* - * Copyright © 2007 Daniel Stone - * Copyright © 2007 Red Hat, Inc. - * - * 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. - * - * Author: Daniel Stone - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "input.h" -#include "inputstr.h" -#include "hotplug.h" -#include "config-backends.h" -#include "os.h" - - -#define LIBHAL_PROP_KEY "input.x11_options." -#define LIBHAL_XKB_PROP_KEY "input.xkb." - - -struct config_hal_info { - DBusConnection *system_bus; - LibHalContext *hal_ctx; -}; - -/* Used for special handling of xkb options. */ -struct xkb_options { - char* layout; - char* model; - char* rules; - char* variant; - char* options; -}; - -static void -device_removed(LibHalContext *ctx, const char *udi) -{ - char *value; - - value = xalloc(strlen(udi) + 5); /* "hal:" + NULL */ - if (!value) - return; - sprintf(value, "hal:%s", udi); - - remove_devices("hal", value); - - xfree(value); -} - -static char * -get_prop_string(LibHalContext *hal_ctx, const char *udi, const char *name) -{ - char *prop, *ret; - - prop = libhal_device_get_property_string(hal_ctx, udi, name, NULL); - LogMessageVerb(X_INFO, 10, "config/hal: getting %s on %s returned %s\n", name, udi, prop ? prop : "(null)"); - if (prop) { - ret = xstrdup(prop); - libhal_free_string(prop); - } - else { - return NULL; - } - - return ret; -} - -static char * -get_prop_string_array(LibHalContext *hal_ctx, const char *udi, const char *prop) -{ - char **props, *ret, *str; - int i, len = 0; - - props = libhal_device_get_property_strlist(hal_ctx, udi, prop, NULL); - if (props) { - for (i = 0; props[i]; i++) - len += strlen(props[i]); - - ret = xcalloc(sizeof(char), len + i); /* i - 1 commas, 1 NULL */ - if (!ret) { - libhal_free_string_array(props); - return NULL; - } - - str = ret; - for (i = 0; props[i]; i++) { - strcpy(str, props[i]); - str += strlen(props[i]); - *str++ = ','; - } - *(str-1) = '\0'; - - libhal_free_string_array(props); - } - else { - return NULL; - } - - return ret; -} - -static void -device_added(LibHalContext *hal_ctx, const char *udi) -{ - char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL; - InputOption *options = NULL, *tmpo = NULL; - InputAttributes attrs = {0}; - DeviceIntPtr dev = NULL; - DBusError error; - struct xkb_options xkb_opts = {0}; - int rc; - - LibHalPropertySet *set = NULL; - LibHalPropertySetIterator set_iter; - char *psi_key = NULL, *tmp_val; - - - dbus_error_init(&error); - - driver = get_prop_string(hal_ctx, udi, "input.x11_driver"); - if (!driver){ - /* verbose, don't tell the user unless they _want_ to see it */ - LogMessageVerb(X_INFO,7,"config/hal: no driver specified for device %s\n", udi); - goto unwind; - } - - path = get_prop_string(hal_ctx, udi, "input.device"); - if (!path) { - LogMessage(X_WARNING,"config/hal: no driver or path specified for %s\n", udi); - goto unwind; - } - attrs.device = xstrdup(path); - - name = get_prop_string(hal_ctx, udi, "info.product"); - if (!name) - name = xstrdup("(unnamed)"); - else - attrs.product = xstrdup(name); - - attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor"); - attrs.tags = xstrtokenize(get_prop_string(hal_ctx, udi, "input.tags"), ","); - - if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL)) - attrs.flags |= ATTR_KEYBOARD; - if (libhal_device_query_capability(hal_ctx, udi, "input.mouse", NULL)) - attrs.flags |= ATTR_POINTER; - if (libhal_device_query_capability(hal_ctx, udi, "input.joystick", NULL)) - attrs.flags |= ATTR_JOYSTICK; - if (libhal_device_query_capability(hal_ctx, udi, "input.tablet", NULL)) - attrs.flags |= ATTR_TABLET; - if (libhal_device_query_capability(hal_ctx, udi, "input.touchpad", NULL)) - attrs.flags |= ATTR_TOUCHPAD; - if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL)) - attrs.flags |= ATTR_TOUCHSCREEN; - - options = xcalloc(sizeof(*options), 1); - if (!options){ - LogMessage(X_ERROR, "config/hal: couldn't allocate space for input options!\n"); - goto unwind; - } - - options->key = xstrdup("_source"); - options->value = xstrdup("server/hal"); - if (!options->key || !options->value) { - LogMessage(X_ERROR, "config/hal: couldn't allocate first key/value pair\n"); - goto unwind; - } - - /* most drivers use device.. not path. evdev uses both however, but the - * path version isn't documented apparently. support both for now. */ - add_option(&options, "path", path); - add_option(&options, "device", path); - - add_option(&options, "driver", driver); - add_option(&options, "name", name); - - config_info = xalloc(strlen(udi) + 5); /* "hal:" and NULL */ - if (!config_info) { - LogMessage(X_ERROR, "config/hal: couldn't allocate name\n"); - goto unwind; - } - sprintf(config_info, "hal:%s", udi); - - /* Check for duplicate devices */ - if (device_is_duplicate(config_info)) - { - LogMessage(X_WARNING, "config/hal: device %s already added. Ignoring.\n", name); - goto unwind; - } - - /* ok, grab options from hal.. iterate through all properties - * and lets see if any of them are options that we can add */ - set = libhal_device_get_all_properties(hal_ctx, udi, &error); - - if (!set) { - LogMessage(X_ERROR, "config/hal: couldn't get property list for %s: %s (%s)\n", - udi, error.name, error.message); - goto unwind; - } - - libhal_psi_init(&set_iter,set); - while (libhal_psi_has_more(&set_iter)) { - /* we are looking for supported keys.. extract and add to options */ - psi_key = libhal_psi_get_key(&set_iter); - - if (psi_key){ - - /* normal options first (input.x11_options.) */ - if (!strncasecmp(psi_key, LIBHAL_PROP_KEY, sizeof(LIBHAL_PROP_KEY)-1)){ - char* tmp; - - /* only support strings for all values */ - tmp_val = get_prop_string(hal_ctx, udi, psi_key); - - if (tmp_val){ - - /* xkb needs special handling. HAL specs include - * input.xkb.xyz options, but the x11-input.fdi specifies - * input.x11_options.Xkbxyz options. By default, we use - * the former, unless the specific X11 ones are specified. - * Since we can't predict the order in which the keys - * arrive, we need to store them. - */ - if ((tmp = strcasestr(psi_key, "xkb")) && strlen(tmp) >= 4) - { - if (!strcasecmp(&tmp[3], "layout")) - { - if (xkb_opts.layout) - xfree(xkb_opts.layout); - xkb_opts.layout = strdup(tmp_val); - } else if (!strcasecmp(&tmp[3], "model")) - { - if (xkb_opts.model) - xfree(xkb_opts.model); - xkb_opts.model = strdup(tmp_val); - } else if (!strcasecmp(&tmp[3], "rules")) - { - if (xkb_opts.rules) - xfree(xkb_opts.rules); - xkb_opts.rules = strdup(tmp_val); - } else if (!strcasecmp(&tmp[3], "variant")) - { - if (xkb_opts.variant) - xfree(xkb_opts.variant); - xkb_opts.variant = strdup(tmp_val); - } else if (!strcasecmp(&tmp[3], "options")) - { - if (xkb_opts.options) - xfree(xkb_opts.options); - xkb_opts.options = strdup(tmp_val); - } - } else - { - /* all others */ - add_option(&options, psi_key + sizeof(LIBHAL_PROP_KEY)-1, tmp_val); - xfree(tmp_val); - } - } else - { - /* server 1.4 had xkb_options as strlist. */ - if ((tmp = strcasestr(psi_key, "xkb")) && - (strlen(tmp) >= 4) && - (!strcasecmp(&tmp[3], "options")) && - (tmp_val = get_prop_string_array(hal_ctx, udi, psi_key))) - { - if (xkb_opts.options) - xfree(xkb_opts.options); - xkb_opts.options = strdup(tmp_val); - } - } - } else if (!strncasecmp(psi_key, LIBHAL_XKB_PROP_KEY, sizeof(LIBHAL_XKB_PROP_KEY)-1)){ - char* tmp; - - /* only support strings for all values */ - tmp_val = get_prop_string(hal_ctx, udi, psi_key); - - if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) { - - tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1]; - - if (!strcasecmp(tmp, "layout")) - { - if (!xkb_opts.layout) - xkb_opts.layout = strdup(tmp_val); - } else if (!strcasecmp(tmp, "rules")) - { - if (!xkb_opts.rules) - xkb_opts.rules = strdup(tmp_val); - } else if (!strcasecmp(tmp, "variant")) - { - if (!xkb_opts.variant) - xkb_opts.variant = strdup(tmp_val); - } else if (!strcasecmp(tmp, "model")) - { - if (!xkb_opts.model) - xkb_opts.model = strdup(tmp_val); - } else if (!strcasecmp(tmp, "options")) - { - if (!xkb_opts.options) - xkb_opts.options = strdup(tmp_val); - } - xfree(tmp_val); - } else - { - /* server 1.4 had xkb options as strlist */ - tmp_val = get_prop_string_array(hal_ctx, udi, psi_key); - if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) - { - tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1]; - if (!strcasecmp(tmp, ".options") && (!xkb_opts.options)) - xkb_opts.options = strdup(tmp_val); - } - } - } - } - - /* psi_key doesn't need to be freed */ - libhal_psi_next(&set_iter); - } - - - /* Now add xkb options */ - if (xkb_opts.layout) - add_option(&options, "xkb_layout", xkb_opts.layout); - if (xkb_opts.rules) - add_option(&options, "xkb_rules", xkb_opts.rules); - if (xkb_opts.variant) - add_option(&options, "xkb_variant", xkb_opts.variant); - if (xkb_opts.model) - add_option(&options, "xkb_model", xkb_opts.model); - if (xkb_opts.options) - add_option(&options, "xkb_options", xkb_opts.options); - - /* this isn't an error, but how else do you output something that the user can see? */ - LogMessage(X_INFO, "config/hal: Adding input device %s\n", name); - if ((rc = NewInputDeviceRequest(options, &attrs, &dev)) != Success) { - LogMessage(X_ERROR, "config/hal: NewInputDeviceRequest failed (%d)\n", rc); - dev = NULL; - goto unwind; - } - - for (; dev; dev = dev->next){ - if (dev->config_info) - xfree(dev->config_info); - dev->config_info = xstrdup(config_info); - } - -unwind: - if (set) - libhal_free_property_set(set); - if (path) - xfree(path); - if (driver) - xfree(driver); - if (name) - xfree(name); - if (config_info) - xfree(config_info); - while (!dev && (tmpo = options)) { - options = tmpo->next; - xfree(tmpo->key); - xfree(tmpo->value); - xfree(tmpo); - } - - xfree(attrs.product); - xfree(attrs.vendor); - xfree(attrs.device); - if (attrs.tags) { - char **tag = attrs.tags; - while (*tag) { - xfree(*tag); - tag++; - } - xfree(attrs.tags); - } - - if (xkb_opts.layout) - xfree(xkb_opts.layout); - if (xkb_opts.rules) - xfree(xkb_opts.rules); - if (xkb_opts.model) - xfree(xkb_opts.model); - if (xkb_opts.variant) - xfree(xkb_opts.variant); - if (xkb_opts.options) - xfree(xkb_opts.options); - - dbus_error_free(&error); - - return; -} - -static void -disconnect_hook(void *data) -{ - DBusError error; - struct config_hal_info *info = data; - - if (info->hal_ctx) { - if (dbus_connection_get_is_connected(info->system_bus)) { - dbus_error_init(&error); - if (!libhal_ctx_shutdown(info->hal_ctx, &error)) - LogMessage(X_WARNING, "config/hal: disconnect_hook couldn't shut down context: %s (%s)\n", - error.name, error.message); - dbus_error_free(&error); - } - libhal_ctx_free(info->hal_ctx); - } - - info->hal_ctx = NULL; - info->system_bus = NULL; -} - -static BOOL -connect_and_register(DBusConnection *connection, struct config_hal_info *info) -{ - DBusError error; - char **devices; - int num_devices, i; - - if (info->hal_ctx) - return TRUE; /* already registered, pretend we did something */ - - info->system_bus = connection; - - dbus_error_init(&error); - - info->hal_ctx = libhal_ctx_new(); - if (!info->hal_ctx) { - LogMessage(X_ERROR, "config/hal: couldn't create HAL context\n"); - goto out_err; - } - - if (!libhal_ctx_set_dbus_connection(info->hal_ctx, info->system_bus)) { - LogMessage(X_ERROR, "config/hal: couldn't associate HAL context with bus\n"); - goto out_err; - } - if (!libhal_ctx_init(info->hal_ctx, &error)) { - LogMessage(X_ERROR, "config/hal: couldn't initialise context: %s (%s)\n", - error.name ? error.name : "unknown error", - error.message ? error.message : "null"); - goto out_err; - } - if (!libhal_device_property_watch_all(info->hal_ctx, &error)) { - LogMessage(X_ERROR, "config/hal: couldn't watch all properties: %s (%s)\n", - error.name ? error.name : "unknown error", - error.message ? error.message : "null"); - goto out_ctx; - } - libhal_ctx_set_device_added(info->hal_ctx, device_added); - libhal_ctx_set_device_removed(info->hal_ctx, device_removed); - - devices = libhal_find_device_by_capability(info->hal_ctx, "input", - &num_devices, &error); - /* FIXME: Get default devices if error is set. */ - if (dbus_error_is_set(&error)) { - LogMessage(X_ERROR, "config/hal: couldn't find input device: %s (%s)\n", - error.name ? error.name : "unknown error", - error.message ? error.message : "null"); - goto out_ctx; - } - for (i = 0; i < num_devices; i++) - device_added(info->hal_ctx, devices[i]); - libhal_free_string_array(devices); - - dbus_error_free(&error); - - return TRUE; - -out_ctx: - dbus_error_free(&error); - - if (!libhal_ctx_shutdown(info->hal_ctx, &error)) { - LogMessage(X_WARNING, "config/hal: couldn't shut down context: %s (%s)\n", - error.name ? error.name : "unknown error", - error.message ? error.message : "null"); - dbus_error_free(&error); - } - -out_err: - dbus_error_free(&error); - - if (info->hal_ctx) { - libhal_ctx_free(info->hal_ctx); - } - - info->hal_ctx = NULL; - info->system_bus = NULL; - - return FALSE; -} - - -/** - * Handle NewOwnerChanged signals to deal with HAL startup at X server runtime. - * - * NewOwnerChanged is send once when HAL shuts down, and once again when it - * comes back up. Message has three arguments, first is the name - * (org.freedesktop.Hal), the second one is the old owner, third one is new - * owner. - */ -static DBusHandlerResult -ownerchanged_handler(DBusConnection *connection, DBusMessage *message, void *data) -{ - int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (dbus_message_is_signal(message, - "org.freedesktop.DBus", - "NameOwnerChanged")) { - DBusError error; - char *name, *old_owner, *new_owner; - - dbus_error_init(&error); - dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &old_owner, - DBUS_TYPE_STRING, &new_owner, - DBUS_TYPE_INVALID); - - if (dbus_error_is_set(&error)) { - ErrorF("[config/hal] failed to get NameOwnerChanged args: %s (%s)\n", - error.name, error.message); - } else if (name && strcmp(name, "org.freedesktop.Hal") == 0) { - - if (!old_owner || !strlen(old_owner)) { - DebugF("[config/hal] HAL startup detected.\n"); - if (connect_and_register(connection, (struct config_hal_info*)data)) - dbus_connection_unregister_object_path(connection, - "/org/freedesktop/DBus"); - else - ErrorF("[config/hal] Failed to connect to HAL bus.\n"); - } - - ret = DBUS_HANDLER_RESULT_HANDLED; - } - dbus_error_free(&error); - } - - return ret; -} - -/** - * Register a handler for the NameOwnerChanged signal. - */ -static BOOL -listen_for_startup(DBusConnection *connection, void *data) -{ - DBusObjectPathVTable vtable = { .message_function = ownerchanged_handler, }; - DBusError error; - const char MATCH_RULE[] = "sender='org.freedesktop.DBus'," - "interface='org.freedesktop.DBus'," - "type='signal'," - "path='/org/freedesktop/DBus'," - "member='NameOwnerChanged'"; - int rc = FALSE; - - dbus_error_init(&error); - dbus_bus_add_match(connection, MATCH_RULE, &error); - if (!dbus_error_is_set(&error)) { - if (dbus_connection_register_object_path(connection, - "/org/freedesktop/DBus", - &vtable, - data)) - rc = TRUE; - else - ErrorF("[config/hal] cannot register object path.\n"); - } else { - ErrorF("[config/hal] couldn't add match rule: %s (%s)\n", error.name, - error.message); - ErrorF("[config/hal] cannot detect a HAL startup.\n"); - } - - dbus_error_free(&error); - - return rc; -} - -static void -connect_hook(DBusConnection *connection, void *data) -{ - struct config_hal_info *info = data; - - if (listen_for_startup(connection, data) && - connect_and_register(connection, info)) - dbus_connection_unregister_object_path(connection, - "/org/freedesktop/DBus"); - - return; -} - -static struct config_hal_info hal_info; -static struct config_dbus_core_hook hook = { - .connect = connect_hook, - .disconnect = disconnect_hook, - .data = &hal_info, -}; - -int -config_hal_init(void) -{ - memset(&hal_info, 0, sizeof(hal_info)); - hal_info.system_bus = NULL; - hal_info.hal_ctx = NULL; - - if (!config_dbus_core_add_hook(&hook)) { - LogMessage(X_ERROR, "config/hal: failed to add D-Bus hook\n"); - return 0; - } - - /* verbose message */ - LogMessageVerb(X_INFO,7,"config/hal: initialized"); - - return 1; -} - -void -config_hal_fini(void) -{ - config_dbus_core_remove_hook(&hook); -} +/* + * Copyright © 2007 Daniel Stone + * Copyright © 2007 Red Hat, Inc. + * + * 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. + * + * Author: Daniel Stone + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "input.h" +#include "inputstr.h" +#include "hotplug.h" +#include "config-backends.h" +#include "os.h" + + +#define LIBHAL_PROP_KEY "input.x11_options." +#define LIBHAL_XKB_PROP_KEY "input.xkb." + + +struct config_hal_info { + DBusConnection *system_bus; + LibHalContext *hal_ctx; +}; + +/* Used for special handling of xkb options. */ +struct xkb_options { + char* layout; + char* model; + char* rules; + char* variant; + char* options; +}; + +static void +device_removed(LibHalContext *ctx, const char *udi) +{ + char *value; + + value = malloc(strlen(udi) + 5); /* "hal:" + NULL */ + if (!value) + return; + sprintf(value, "hal:%s", udi); + + remove_devices("hal", value); + + free(value); +} + +static char * +get_prop_string(LibHalContext *hal_ctx, const char *udi, const char *name) +{ + char *prop, *ret; + + prop = libhal_device_get_property_string(hal_ctx, udi, name, NULL); + LogMessageVerb(X_INFO, 10, "config/hal: getting %s on %s returned %s\n", name, udi, prop ? prop : "(null)"); + if (prop) { + ret = xstrdup(prop); + libhal_free_string(prop); + } + else { + return NULL; + } + + return ret; +} + +static char * +get_prop_string_array(LibHalContext *hal_ctx, const char *udi, const char *prop) +{ + char **props, *ret, *str; + int i, len = 0; + + props = libhal_device_get_property_strlist(hal_ctx, udi, prop, NULL); + if (props) { + for (i = 0; props[i]; i++) + len += strlen(props[i]); + + ret = calloc(sizeof(char), len + i); /* i - 1 commas, 1 NULL */ + if (!ret) { + libhal_free_string_array(props); + return NULL; + } + + str = ret; + for (i = 0; props[i]; i++) { + strcpy(str, props[i]); + str += strlen(props[i]); + *str++ = ','; + } + *(str-1) = '\0'; + + libhal_free_string_array(props); + } + else { + return NULL; + } + + return ret; +} + +static void +device_added(LibHalContext *hal_ctx, const char *udi) +{ + char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL; + InputOption *options = NULL, *tmpo = NULL; + InputAttributes attrs = {0}; + DeviceIntPtr dev = NULL; + DBusError error; + struct xkb_options xkb_opts = {0}; + int rc; + + LibHalPropertySet *set = NULL; + LibHalPropertySetIterator set_iter; + char *psi_key = NULL, *tmp_val; + + + dbus_error_init(&error); + + driver = get_prop_string(hal_ctx, udi, "input.x11_driver"); + if (!driver){ + /* verbose, don't tell the user unless they _want_ to see it */ + LogMessageVerb(X_INFO,7,"config/hal: no driver specified for device %s\n", udi); + goto unwind; + } + + path = get_prop_string(hal_ctx, udi, "input.device"); + if (!path) { + LogMessage(X_WARNING,"config/hal: no driver or path specified for %s\n", udi); + goto unwind; + } + attrs.device = xstrdup(path); + + name = get_prop_string(hal_ctx, udi, "info.product"); + if (!name) + name = xstrdup("(unnamed)"); + else + attrs.product = xstrdup(name); + + attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor"); + attrs.tags = xstrtokenize(get_prop_string(hal_ctx, udi, "input.tags"), ","); + + if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL)) + attrs.flags |= ATTR_KEYBOARD; + if (libhal_device_query_capability(hal_ctx, udi, "input.mouse", NULL)) + attrs.flags |= ATTR_POINTER; + if (libhal_device_query_capability(hal_ctx, udi, "input.joystick", NULL)) + attrs.flags |= ATTR_JOYSTICK; + if (libhal_device_query_capability(hal_ctx, udi, "input.tablet", NULL)) + attrs.flags |= ATTR_TABLET; + if (libhal_device_query_capability(hal_ctx, udi, "input.touchpad", NULL)) + attrs.flags |= ATTR_TOUCHPAD; + if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL)) + attrs.flags |= ATTR_TOUCHSCREEN; + + options = calloc(sizeof(*options), 1); + if (!options){ + LogMessage(X_ERROR, "config/hal: couldn't allocate space for input options!\n"); + goto unwind; + } + + options->key = xstrdup("_source"); + options->value = xstrdup("server/hal"); + if (!options->key || !options->value) { + LogMessage(X_ERROR, "config/hal: couldn't allocate first key/value pair\n"); + goto unwind; + } + + /* most drivers use device.. not path. evdev uses both however, but the + * path version isn't documented apparently. support both for now. */ + add_option(&options, "path", path); + add_option(&options, "device", path); + + add_option(&options, "driver", driver); + add_option(&options, "name", name); + + config_info = malloc(strlen(udi) + 5); /* "hal:" and NULL */ + if (!config_info) { + LogMessage(X_ERROR, "config/hal: couldn't allocate name\n"); + goto unwind; + } + sprintf(config_info, "hal:%s", udi); + + /* Check for duplicate devices */ + if (device_is_duplicate(config_info)) + { + LogMessage(X_WARNING, "config/hal: device %s already added. Ignoring.\n", name); + goto unwind; + } + + /* ok, grab options from hal.. iterate through all properties + * and lets see if any of them are options that we can add */ + set = libhal_device_get_all_properties(hal_ctx, udi, &error); + + if (!set) { + LogMessage(X_ERROR, "config/hal: couldn't get property list for %s: %s (%s)\n", + udi, error.name, error.message); + goto unwind; + } + + libhal_psi_init(&set_iter,set); + while (libhal_psi_has_more(&set_iter)) { + /* we are looking for supported keys.. extract and add to options */ + psi_key = libhal_psi_get_key(&set_iter); + + if (psi_key){ + + /* normal options first (input.x11_options.) */ + if (!strncasecmp(psi_key, LIBHAL_PROP_KEY, sizeof(LIBHAL_PROP_KEY)-1)){ + char* tmp; + + /* only support strings for all values */ + tmp_val = get_prop_string(hal_ctx, udi, psi_key); + + if (tmp_val){ + + /* xkb needs special handling. HAL specs include + * input.xkb.xyz options, but the x11-input.fdi specifies + * input.x11_options.Xkbxyz options. By default, we use + * the former, unless the specific X11 ones are specified. + * Since we can't predict the order in which the keys + * arrive, we need to store them. + */ + if ((tmp = strcasestr(psi_key, "xkb")) && strlen(tmp) >= 4) + { + if (!strcasecmp(&tmp[3], "layout")) + { + if (xkb_opts.layout) + free(xkb_opts.layout); + xkb_opts.layout = strdup(tmp_val); + } else if (!strcasecmp(&tmp[3], "model")) + { + if (xkb_opts.model) + free(xkb_opts.model); + xkb_opts.model = strdup(tmp_val); + } else if (!strcasecmp(&tmp[3], "rules")) + { + if (xkb_opts.rules) + free(xkb_opts.rules); + xkb_opts.rules = strdup(tmp_val); + } else if (!strcasecmp(&tmp[3], "variant")) + { + if (xkb_opts.variant) + free(xkb_opts.variant); + xkb_opts.variant = strdup(tmp_val); + } else if (!strcasecmp(&tmp[3], "options")) + { + if (xkb_opts.options) + free(xkb_opts.options); + xkb_opts.options = strdup(tmp_val); + } + } else + { + /* all others */ + add_option(&options, psi_key + sizeof(LIBHAL_PROP_KEY)-1, tmp_val); + free(tmp_val); + } + } else + { + /* server 1.4 had xkb_options as strlist. */ + if ((tmp = strcasestr(psi_key, "xkb")) && + (strlen(tmp) >= 4) && + (!strcasecmp(&tmp[3], "options")) && + (tmp_val = get_prop_string_array(hal_ctx, udi, psi_key))) + { + if (xkb_opts.options) + free(xkb_opts.options); + xkb_opts.options = strdup(tmp_val); + } + } + } else if (!strncasecmp(psi_key, LIBHAL_XKB_PROP_KEY, sizeof(LIBHAL_XKB_PROP_KEY)-1)){ + char* tmp; + + /* only support strings for all values */ + tmp_val = get_prop_string(hal_ctx, udi, psi_key); + + if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) { + + tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1]; + + if (!strcasecmp(tmp, "layout")) + { + if (!xkb_opts.layout) + xkb_opts.layout = strdup(tmp_val); + } else if (!strcasecmp(tmp, "rules")) + { + if (!xkb_opts.rules) + xkb_opts.rules = strdup(tmp_val); + } else if (!strcasecmp(tmp, "variant")) + { + if (!xkb_opts.variant) + xkb_opts.variant = strdup(tmp_val); + } else if (!strcasecmp(tmp, "model")) + { + if (!xkb_opts.model) + xkb_opts.model = strdup(tmp_val); + } else if (!strcasecmp(tmp, "options")) + { + if (!xkb_opts.options) + xkb_opts.options = strdup(tmp_val); + } + free(tmp_val); + } else + { + /* server 1.4 had xkb options as strlist */ + tmp_val = get_prop_string_array(hal_ctx, udi, psi_key); + if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) + { + tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1]; + if (!strcasecmp(tmp, ".options") && (!xkb_opts.options)) + xkb_opts.options = strdup(tmp_val); + } + } + } + } + + /* psi_key doesn't need to be freed */ + libhal_psi_next(&set_iter); + } + + + /* Now add xkb options */ + if (xkb_opts.layout) + add_option(&options, "xkb_layout", xkb_opts.layout); + if (xkb_opts.rules) + add_option(&options, "xkb_rules", xkb_opts.rules); + if (xkb_opts.variant) + add_option(&options, "xkb_variant", xkb_opts.variant); + if (xkb_opts.model) + add_option(&options, "xkb_model", xkb_opts.model); + if (xkb_opts.options) + add_option(&options, "xkb_options", xkb_opts.options); + + /* this isn't an error, but how else do you output something that the user can see? */ + LogMessage(X_INFO, "config/hal: Adding input device %s\n", name); + if ((rc = NewInputDeviceRequest(options, &attrs, &dev)) != Success) { + LogMessage(X_ERROR, "config/hal: NewInputDeviceRequest failed (%d)\n", rc); + dev = NULL; + goto unwind; + } + + for (; dev; dev = dev->next){ + if (dev->config_info) + free(dev->config_info); + dev->config_info = xstrdup(config_info); + } + +unwind: + if (set) + libhal_free_property_set(set); + if (path) + free(path); + if (driver) + free(driver); + if (name) + free(name); + if (config_info) + free(config_info); + while (!dev && (tmpo = options)) { + options = tmpo->next; + free(tmpo->key); + free(tmpo->value); + free(tmpo); + } + + free(attrs.product); + free(attrs.vendor); + free(attrs.device); + if (attrs.tags) { + char **tag = attrs.tags; + while (*tag) { + free(*tag); + tag++; + } + free(attrs.tags); + } + + if (xkb_opts.layout) + free(xkb_opts.layout); + if (xkb_opts.rules) + free(xkb_opts.rules); + if (xkb_opts.model) + free(xkb_opts.model); + if (xkb_opts.variant) + free(xkb_opts.variant); + if (xkb_opts.options) + free(xkb_opts.options); + + dbus_error_free(&error); + + return; +} + +static void +disconnect_hook(void *data) +{ + DBusError error; + struct config_hal_info *info = data; + + if (info->hal_ctx) { + if (dbus_connection_get_is_connected(info->system_bus)) { + dbus_error_init(&error); + if (!libhal_ctx_shutdown(info->hal_ctx, &error)) + LogMessage(X_WARNING, "config/hal: disconnect_hook couldn't shut down context: %s (%s)\n", + error.name, error.message); + dbus_error_free(&error); + } + libhal_ctx_free(info->hal_ctx); + } + + info->hal_ctx = NULL; + info->system_bus = NULL; +} + +static BOOL +connect_and_register(DBusConnection *connection, struct config_hal_info *info) +{ + DBusError error; + char **devices; + int num_devices, i; + + if (info->hal_ctx) + return TRUE; /* already registered, pretend we did something */ + + info->system_bus = connection; + + dbus_error_init(&error); + + info->hal_ctx = libhal_ctx_new(); + if (!info->hal_ctx) { + LogMessage(X_ERROR, "config/hal: couldn't create HAL context\n"); + goto out_err; + } + + if (!libhal_ctx_set_dbus_connection(info->hal_ctx, info->system_bus)) { + LogMessage(X_ERROR, "config/hal: couldn't associate HAL context with bus\n"); + goto out_err; + } + if (!libhal_ctx_init(info->hal_ctx, &error)) { + LogMessage(X_ERROR, "config/hal: couldn't initialise context: %s (%s)\n", + error.name ? error.name : "unknown error", + error.message ? error.message : "null"); + goto out_err; + } + if (!libhal_device_property_watch_all(info->hal_ctx, &error)) { + LogMessage(X_ERROR, "config/hal: couldn't watch all properties: %s (%s)\n", + error.name ? error.name : "unknown error", + error.message ? error.message : "null"); + goto out_ctx; + } + libhal_ctx_set_device_added(info->hal_ctx, device_added); + libhal_ctx_set_device_removed(info->hal_ctx, device_removed); + + devices = libhal_find_device_by_capability(info->hal_ctx, "input", + &num_devices, &error); + /* FIXME: Get default devices if error is set. */ + if (dbus_error_is_set(&error)) { + LogMessage(X_ERROR, "config/hal: couldn't find input device: %s (%s)\n", + error.name ? error.name : "unknown error", + error.message ? error.message : "null"); + goto out_ctx; + } + for (i = 0; i < num_devices; i++) + device_added(info->hal_ctx, devices[i]); + libhal_free_string_array(devices); + + dbus_error_free(&error); + + return TRUE; + +out_ctx: + dbus_error_free(&error); + + if (!libhal_ctx_shutdown(info->hal_ctx, &error)) { + LogMessage(X_WARNING, "config/hal: couldn't shut down context: %s (%s)\n", + error.name ? error.name : "unknown error", + error.message ? error.message : "null"); + dbus_error_free(&error); + } + +out_err: + dbus_error_free(&error); + + if (info->hal_ctx) { + libhal_ctx_free(info->hal_ctx); + } + + info->hal_ctx = NULL; + info->system_bus = NULL; + + return FALSE; +} + + +/** + * Handle NewOwnerChanged signals to deal with HAL startup at X server runtime. + * + * NewOwnerChanged is send once when HAL shuts down, and once again when it + * comes back up. Message has three arguments, first is the name + * (org.freedesktop.Hal), the second one is the old owner, third one is new + * owner. + */ +static DBusHandlerResult +ownerchanged_handler(DBusConnection *connection, DBusMessage *message, void *data) +{ + int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (dbus_message_is_signal(message, + "org.freedesktop.DBus", + "NameOwnerChanged")) { + DBusError error; + char *name, *old_owner, *new_owner; + + dbus_error_init(&error); + dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&error)) { + ErrorF("[config/hal] failed to get NameOwnerChanged args: %s (%s)\n", + error.name, error.message); + } else if (name && strcmp(name, "org.freedesktop.Hal") == 0) { + + if (!old_owner || !strlen(old_owner)) { + DebugF("[config/hal] HAL startup detected.\n"); + if (connect_and_register(connection, (struct config_hal_info*)data)) + dbus_connection_unregister_object_path(connection, + "/org/freedesktop/DBus"); + else + ErrorF("[config/hal] Failed to connect to HAL bus.\n"); + } + + ret = DBUS_HANDLER_RESULT_HANDLED; + } + dbus_error_free(&error); + } + + return ret; +} + +/** + * Register a handler for the NameOwnerChanged signal. + */ +static BOOL +listen_for_startup(DBusConnection *connection, void *data) +{ + DBusObjectPathVTable vtable = { .message_function = ownerchanged_handler, }; + DBusError error; + const char MATCH_RULE[] = "sender='org.freedesktop.DBus'," + "interface='org.freedesktop.DBus'," + "type='signal'," + "path='/org/freedesktop/DBus'," + "member='NameOwnerChanged'"; + int rc = FALSE; + + dbus_error_init(&error); + dbus_bus_add_match(connection, MATCH_RULE, &error); + if (!dbus_error_is_set(&error)) { + if (dbus_connection_register_object_path(connection, + "/org/freedesktop/DBus", + &vtable, + data)) + rc = TRUE; + else + ErrorF("[config/hal] cannot register object path.\n"); + } else { + ErrorF("[config/hal] couldn't add match rule: %s (%s)\n", error.name, + error.message); + ErrorF("[config/hal] cannot detect a HAL startup.\n"); + } + + dbus_error_free(&error); + + return rc; +} + +static void +connect_hook(DBusConnection *connection, void *data) +{ + struct config_hal_info *info = data; + + if (listen_for_startup(connection, data) && + connect_and_register(connection, info)) + dbus_connection_unregister_object_path(connection, + "/org/freedesktop/DBus"); + + return; +} + +static struct config_hal_info hal_info; +static struct config_dbus_core_hook hook = { + .connect = connect_hook, + .disconnect = disconnect_hook, + .data = &hal_info, +}; + +int +config_hal_init(void) +{ + memset(&hal_info, 0, sizeof(hal_info)); + hal_info.system_bus = NULL; + hal_info.hal_ctx = NULL; + + if (!config_dbus_core_add_hook(&hook)) { + LogMessage(X_ERROR, "config/hal: failed to add D-Bus hook\n"); + return 0; + } + + /* verbose message */ + LogMessageVerb(X_INFO,7,"config/hal: initialized"); + + return 1; +} + +void +config_hal_fini(void) +{ + config_dbus_core_remove_hook(&hook); +} diff --git a/xorg-server/config/udev.c b/xorg-server/config/udev.c index 452fb5a8d..304ee2c93 100644 --- a/xorg-server/config/udev.c +++ b/xorg-server/config/udev.c @@ -1,267 +1,267 @@ -/* - * Copyright © 2009 Julien Cristau - * - * 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. - * - * Author: Julien Cristau - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "input.h" -#include "inputstr.h" -#include "hotplug.h" -#include "config-backends.h" -#include "os.h" - -#define UDEV_XKB_PROP_KEY "xkb" - -static struct udev_monitor *udev_monitor; - -static void -device_added(struct udev_device *udev_device) -{ - const char *path, *name = NULL; - char *config_info = NULL; - const char *syspath; - const char *key, *value, *tmp; - InputOption *options = NULL, *tmpo; - InputAttributes attrs = {}; - DeviceIntPtr dev = NULL; - struct udev_list_entry *set, *entry; - struct udev_device *parent; - int rc; - - path = udev_device_get_devnode(udev_device); - - syspath = udev_device_get_syspath(udev_device); - - if (!path || !syspath) - return; - - if (!udev_device_get_property_value(udev_device, "ID_INPUT")) - return; - - options = xcalloc(sizeof(*options), 1); - if (!options) - return; - - options->key = xstrdup("_source"); - options->value = xstrdup("server/udev"); - if (!options->key || !options->value) - goto unwind; - - parent = udev_device_get_parent(udev_device); - if (parent) { - name = udev_device_get_sysattr_value(parent, "name"); - if (!name) - name = udev_device_get_property_value(parent, "NAME"); - } - if (!name) - name = "(unnamed)"; - else - attrs.product = name; - add_option(&options, "name", name); - - add_option(&options, "path", path); - add_option(&options, "device", path); - attrs.device = path; - attrs.tags = xstrtokenize(udev_device_get_property_value(udev_device, "ID_INPUT.tags"), ","); - - config_info = Xprintf("udev:%s", syspath); - if (!config_info) - goto unwind; - - if (device_is_duplicate(config_info)) { - LogMessage(X_WARNING, "config/udev: device %s already added. " - "Ignoring.\n", name); - goto unwind; - } - - set = udev_device_get_properties_list_entry(udev_device); - udev_list_entry_foreach(entry, set) { - key = udev_list_entry_get_name(entry); - if (!key) - continue; - value = udev_list_entry_get_value(entry); - if (!strncasecmp(key, UDEV_XKB_PROP_KEY, - sizeof(UDEV_XKB_PROP_KEY) - 1)) { - tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1; - if (!strcasecmp(tmp, "rules")) - add_option(&options, "xkb_rules", value); - else if (!strcasecmp(tmp, "layout")) - add_option(&options, "xkb_layout", value); - else if (!strcasecmp(tmp, "variant")) - add_option(&options, "xkb_variant", value); - else if (!strcasecmp(tmp, "model")) - add_option(&options, "xkb_model", value); - else if (!strcasecmp(tmp, "options")) - add_option(&options, "xkb_options", value); - } else if (!strcmp(key, "ID_VENDOR")) { - attrs.vendor = value; - } else if (!strcmp(key, "ID_INPUT_KEY")) { - attrs.flags |= ATTR_KEYBOARD; - } else if (!strcmp(key, "ID_INPUT_MOUSE")) { - attrs.flags |= ATTR_POINTER; - } else if (!strcmp(key, "ID_INPUT_JOYSTICK")) { - attrs.flags |= ATTR_JOYSTICK; - } else if (!strcmp(key, "ID_INPUT_TABLET")) { - attrs.flags |= ATTR_TABLET; - } else if (!strcmp(key, "ID_INPUT_TOUCHPAD")) { - attrs.flags |= ATTR_TOUCHPAD; - } else if (!strcmp(key, "ID_INPUT_TOUCHSCREEN")) { - attrs.flags |= ATTR_TOUCHSCREEN; - } - } - LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n", - name, path); - rc = NewInputDeviceRequest(options, &attrs, &dev); - if (rc != Success) - goto unwind; - - for (; dev; dev = dev->next) { - xfree(dev->config_info); - dev->config_info = xstrdup(config_info); - } - - unwind: - xfree(config_info); - while (!dev && (tmpo = options)) { - options = tmpo->next; - xfree(tmpo->key); - xfree(tmpo->value); - xfree(tmpo); - } - - if (attrs.tags) { - char **tag = attrs.tags; - while (*tag) { - xfree(*tag); - tag++; - } - xfree(attrs.tags); - } - - return; -} - -static void -device_removed(struct udev_device *device) -{ - char *value; - const char *syspath = udev_device_get_syspath(device); - - value = Xprintf("udev:%s", syspath); - if (!value) - return; - - remove_devices("udev", value); - - xfree(value); -} - -static void -wakeup_handler(pointer data, int err, pointer read_mask) -{ - int udev_fd = udev_monitor_get_fd(udev_monitor); - struct udev_device *udev_device; - const char *action; - - if (err < 0) - return; - - if (FD_ISSET(udev_fd, (fd_set *)read_mask)) { - udev_device = udev_monitor_receive_device(udev_monitor); - if (!udev_device) - return; - action = udev_device_get_action(udev_device); - if (action) { - if (!strcmp(action, "add")) - device_added(udev_device); - else if (!strcmp(action, "remove")) - device_removed(udev_device); - } - udev_device_unref(udev_device); - } -} - -static void -block_handler(pointer data, struct timeval **tv, pointer read_mask) -{ -} - -int -config_udev_init(void) -{ - struct udev *udev; - struct udev_enumerate *enumerate; - struct udev_list_entry *devices, *device; - - udev = udev_new(); - if (!udev) - return 0; - udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); - if (!udev_monitor) - return 0; - - if (udev_monitor_enable_receiving(udev_monitor)) { - ErrorF("config/udev: failed to bind the udev monitor\n"); - return 0; - } - - enumerate = udev_enumerate_new(udev); - if (!enumerate) - return 0; - udev_enumerate_scan_devices(enumerate); - devices = udev_enumerate_get_list_entry(enumerate); - udev_list_entry_foreach(device, devices) { - const char *syspath = udev_list_entry_get_name(device); - struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath); - device_added(udev_device); - udev_device_unref(udev_device); - } - udev_enumerate_unref(enumerate); - - RegisterBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); - AddGeneralSocket(udev_monitor_get_fd(udev_monitor)); - - return 1; -} - -void -config_udev_fini(void) -{ - struct udev *udev; - - if (!udev_monitor) - return; - - udev = udev_monitor_get_udev(udev_monitor); - - RemoveGeneralSocket(udev_monitor_get_fd(udev_monitor)); - RemoveBlockAndWakeupHandlers(block_handler, wakeup_handler, udev_monitor); - udev_monitor_unref(udev_monitor); - udev_monitor = NULL; - udev_unref(udev); -} +/* + * Copyright © 2009 Julien Cristau + * + * 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. + * + * Author: Julien Cristau + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "input.h" +#include "inputstr.h" +#include "hotplug.h" +#include "config-backends.h" +#include "os.h" + +#define UDEV_XKB_PROP_KEY "xkb" + +static struct udev_monitor *udev_monitor; + +static void +device_added(struct udev_device *udev_device) +{ + const char *path, *name = NULL; + char *config_info = NULL; + const char *syspath; + const char *key, *value, *tmp; + InputOption *options = NULL, *tmpo; + InputAttributes attrs = {}; + DeviceIntPtr dev = NULL; + struct udev_list_entry *set, *entry; + struct udev_device *parent; + int rc; + + path = udev_device_get_devnode(udev_device); + + syspath = udev_device_get_syspath(udev_device); + + if (!path || !syspath) + return; + + if (!udev_device_get_property_value(udev_device, "ID_INPUT")) + return; + + options = calloc(sizeof(*options), 1); + if (!options) + return; + + options->key = xstrdup("_source"); + options->value = xstrdup("server/udev"); + if (!options->key || !options->value) + goto unwind; + + parent = udev_device_get_parent(udev_device); + if (parent) { + name = udev_device_get_sysattr_value(parent, "name"); + if (!name) + name = udev_device_get_property_value(parent, "NAME"); + } + if (!name) + name = "(unnamed)"; + else + attrs.product = name; + add_option(&options, "name", name); + + add_option(&options, "path", path); + add_option(&options, "device", path); + attrs.device = path; + attrs.tags = xstrtokenize(udev_device_get_property_value(udev_device, "ID_INPUT.tags"), ","); + + config_info = Xprintf("udev:%s", syspath); + if (!config_info) + goto unwind; + + if (device_is_duplicate(config_info)) { + LogMessage(X_WARNING, "config/udev: device %s already added. " + "Ignoring.\n", name); + goto unwind; + } + + set = udev_device_get_properties_list_entry(udev_device); + udev_list_entry_foreach(entry, set) { + key = udev_list_entry_get_name(entry); + if (!key) + continue; + value = udev_list_entry_get_value(entry); + if (!strncasecmp(key, UDEV_XKB_PROP_KEY, + sizeof(UDEV_XKB_PROP_KEY) - 1)) { + tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1; + if (!strcasecmp(tmp, "rules")) + add_option(&options, "xkb_rules", value); + else if (!strcasecmp(tmp, "layout")) + add_option(&options, "xkb_layout", value); + else if (!strcasecmp(tmp, "variant")) + add_option(&options, "xkb_variant", value); + else if (!strcasecmp(tmp, "model")) + add_option(&options, "xkb_model", value); + else if (!strcasecmp(tmp, "options")) + add_option(&options, "xkb_options", value); + } else if (!strcmp(key, "ID_VENDOR")) { + attrs.vendor = value; + } else if (!strcmp(key, "ID_INPUT_KEY")) { + attrs.flags |= ATTR_KEYBOARD; + } else if (!strcmp(key, "ID_INPUT_MOUSE")) { + attrs.flags |= ATTR_POINTER; + } else if (!strcmp(key, "ID_INPUT_JOYSTICK")) { + attrs.flags |= ATTR_JOYSTICK; + } else if (!strcmp(key, "ID_INPUT_TABLET")) { + attrs.flags |= ATTR_TABLET; + } else if (!strcmp(key, "ID_INPUT_TOUCHPAD")) { + attrs.flags |= ATTR_TOUCHPAD; + } else if (!strcmp(key, "ID_INPUT_TOUCHSCREEN")) { + attrs.flags |= ATTR_TOUCHSCREEN; + } + } + LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n", + name, path); + rc = NewInputDeviceRequest(options, &attrs, &dev); + if (rc != Success) + goto unwind; + + for (; dev; dev = dev->next) { + free(dev->config_info); + dev->config_info = xstrdup(config_info); + } + + unwind: + free(config_info); + while (!dev && (tmpo = options)) { + options = tmpo->next; + free(tmpo->key); + free(tmpo->value); + free(tmpo); + } + + if (attrs.tags) { + char **tag = attrs.tags; + while (*tag) { + free(*tag); + tag++; + } + free(attrs.tags); + } + + return; +} + +static void +device_removed(struct udev_device *device) +{ + char *value; + const char *syspath = udev_device_get_syspath(device); + + value = Xprintf("udev:%s", syspath); + if (!value) + return; + + remove_devices("udev", value); + + free(value); +} + +static void +wakeup_handler(pointer data, int err, pointer read_mask) +{ + int udev_fd = udev_monitor_get_fd(udev_monitor); + struct udev_device *udev_device; + const char *action; + + if (err < 0) + return; + + if (FD_ISSET(udev_fd, (fd_set *)read_mask)) { + udev_device = udev_monitor_receive_device(udev_monitor); + if (!udev_device) + return; + action = udev_device_get_action(udev_device); + if (action) { + if (!strcmp(action, "add")) + device_added(udev_device); + else if (!strcmp(action, "remove")) + device_removed(udev_device); + } + udev_device_unref(udev_device); + } +} + +static void +block_handler(pointer data, struct timeval **tv, pointer read_mask) +{ +} + +int +config_udev_init(void) +{ + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *device; + + udev = udev_new(); + if (!udev) + return 0; + udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (!udev_monitor) + return 0; + + if (udev_monitor_enable_receiving(udev_monitor)) { + ErrorF("config/udev: failed to bind the udev monitor\n"); + return 0; + } + + enumerate = udev_enumerate_new(udev); + if (!enumerate) + return 0; + udev_enumerate_scan_devices(enumerate); + devices = udev_enumerate_get_list_entry(enumerate); + udev_list_entry_foreach(device, devices) { + const char *syspath = udev_list_entry_get_name(device); + struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath); + device_added(udev_device); + udev_device_unref(udev_device); + } + udev_enumerate_unref(enumerate); + + RegisterBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); + AddGeneralSocket(udev_monitor_get_fd(udev_monitor)); + + return 1; +} + +void +config_udev_fini(void) +{ + struct udev *udev; + + if (!udev_monitor) + return; + + udev = udev_monitor_get_udev(udev_monitor); + + RemoveGeneralSocket(udev_monitor_get_fd(udev_monitor)); + RemoveBlockAndWakeupHandlers(block_handler, wakeup_handler, udev_monitor); + udev_monitor_unref(udev_monitor); + udev_monitor = NULL; + udev_unref(udev); +} diff --git a/xorg-server/configure.ac b/xorg-server/configure.ac index 6110d8cca..959ed48a8 100644 --- a/xorg-server/configure.ac +++ b/xorg-server/configure.ac @@ -1,2246 +1,2248 @@ -dnl Copyright © 2003-2007 Keith Packard, Daniel Stone -dnl -dnl Permission is hereby granted, free of charge, to any person obtaining a -dnl copy of this software and associated documentation files (the "Software"), -dnl to deal in the Software without restriction, including without limitation -dnl the rights to use, copy, modify, merge, publish, distribute, sublicense, -dnl and/or sell copies of the Software, and to permit persons to whom the -dnl Software is furnished to do so, subject to the following conditions: -dnl -dnl The above copyright notice and this permission notice (including the next -dnl paragraph) shall be included in all copies or substantial portions of the -dnl Software. -dnl -dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -dnl IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -dnl FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -dnl THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -dnl LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -dnl FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -dnl DEALINGS IN THE SOFTWARE. -dnl -dnl Authors: Keith Packard -dnl Daniel Stone -dnl an unwitting cast of miscellaneous others -dnl -dnl Process this file with autoconf to create configure. - -AC_PREREQ(2.57) -AC_INIT([xorg-server], 1.8.99.0, [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], xorg-server) -RELEASE_DATE="unreleased" -AC_CONFIG_SRCDIR([Makefile.am]) -AM_INIT_AUTOMAKE([foreign dist-bzip2]) -AM_MAINTAINER_MODE - -# Require xorg-macros: XORG_DEFAULT_OPTIONS -m4_ifndef([XORG_MACROS_VERSION], - [m4_fatal([must install xorg-macros 1.6 or later before running autoconf/autogen])]) -XORG_MACROS_VERSION(1.6) -XORG_DEFAULT_OPTIONS -XORG_WITH_DOXYGEN(1.6.1) - -m4_ifndef([XORG_FONT_MACROS_VERSION], [m4_fatal([must install fontutil 1.1 or later before running autoconf/autogen])]) -XORG_FONT_MACROS_VERSION(1.1) - -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 xorg-server.h is an external header, designed to be included by loadable -dnl drivers. -AC_CONFIG_HEADERS(include/xorg-server.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 xorg-config.h covers the Xorg DDX. -AC_CONFIG_HEADERS(include/xorg-config.h) -dnl xkb-config.h covers XKB for the Xorg and Xnest DDXs. -AC_CONFIG_HEADERS(include/xkb-config.h) -dnl xwin-config.h covers the XWin DDX. -AC_CONFIG_HEADERS(include/xwin-config.h) -dnl kdrive-config.h covers the kdrive DDX -AC_CONFIG_HEADERS(include/kdrive-config.h) -dnl version-config.h covers the version numbers so they can be bumped without -dnl forcing an entire recompile.x -AC_CONFIG_HEADERS(include/version-config.h) - -AC_PROG_CC -AM_PROG_AS -AC_PROG_INSTALL -AC_PROG_LN_S -AC_LIBTOOL_WIN32_DLL -AC_DISABLE_STATIC -AC_PROG_LIBTOOL -DOLT -AC_PROG_MAKE_SET -PKG_PROG_PKG_CONFIG -AC_PROG_LEX -AC_PROG_YACC -AC_SYS_LARGEFILE -XORG_PROG_RAWCPP -AC_PROG_SED - -# Quoted so that make will expand $(CWARNFLAGS) in makefiles to allow -# easier overrides at build time. -XSERVER_CFLAGS='$(CWARNFLAGS)' - -dnl Check for dtrace program (needed to build Xserver dtrace probes) -dnl Also checks for , since some Linux distros have an -dnl ISDN trace program named dtrace -AC_ARG_WITH(dtrace, AS_HELP_STRING([--with-dtrace=PATH], - [Enable dtrace probes (default: enabled if dtrace found)]), - [WDTRACE=$withval], [WDTRACE=auto]) -if test "x$WDTRACE" = "xyes" -o "x$WDTRACE" = "xauto" ; then - AC_PATH_PROG(DTRACE, [dtrace], [not_found], [$PATH:/usr/sbin]) - if test "x$DTRACE" = "xnot_found" ; then - if test "x$WDTRACE" = "xyes" ; then - AC_MSG_FAILURE([dtrace requested but not found]) - fi - WDTRACE="no" - else - AC_CHECK_HEADER(sys/sdt.h, [HAS_SDT_H="yes"], [HAS_SDT_H="no"]) - if test "x$WDTRACE" = "xauto" -a "x$HAS_SDT_H" = "xno" ; then - WDTRACE="no" - fi - fi -fi -if test "x$WDTRACE" != "xno" ; then - AC_DEFINE(XSERVER_DTRACE, 1, - [Define to 1 if the DTrace Xserver provider probes should be built in.]) - -# Solaris/OpenSolaris require dtrace -G to build dtrace probe information into -# object files, and require linking with those as relocatable objects, not .a -# archives. MacOS X handles all this in the normal compiler toolchain, and on -# some releases (like Tiger), will error out on dtrace -G. For now, other -# platforms with Dtrace ports are assumed to support -G (the FreeBSD and Linux -# ports appear to, based on my web searches, but have not yet been tested). - case $host_os in - darwin*) SPECIAL_DTRACE_OBJECTS=no ;; - *) SPECIAL_DTRACE_OBJECTS=yes ;; - esac -fi -AM_CONDITIONAL(XSERVER_DTRACE, [test "x$WDTRACE" != "xno"]) -AM_CONDITIONAL(SPECIAL_DTRACE_OBJECTS, [test "x$SPECIAL_DTRACE_OBJECTS" = "xyes"]) - -AC_HEADER_DIRENT -AC_HEADER_STDC -AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h dlfcn.h stropts.h fnmatch.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 - -# Checks for headers/macros for byte swapping -# Known variants: -# bswap_16, bswap_32, bswap_64 (glibc) -# __swap16, __swap32, __swap64 (OpenBSD) -# bswap16, bswap32, bswap64 (other BSD's) -# and a fallback to local macros if none of the above are found - -# if is found, assume it's the correct version -AC_CHECK_HEADERS([byteswap.h]) - -# if is found, have to check which version -AC_CHECK_HEADER([sys/endian.h], [HAVE_SYS_ENDIAN_H="yes"], [HAVE_SYS_ENDIAN_H="no"]) - -if test "x$HAVE_SYS_ENDIAN_H" = "xyes" ; then - AC_MSG_CHECKING([for __swap16 variant of byteswapping macros]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([ -#include -#include - ], [ -int a = 1, b; -b = __swap16(a); - ]) -], [SYS_ENDIAN__SWAP='yes'], [SYS_ENDIAN__SWAP='no']) - AC_MSG_RESULT([$SYS_ENDIAN__SWAP]) - - AC_MSG_CHECKING([for bswap16 variant of byteswapping macros]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([ -#include -#include - ], [ -int a = 1, b; -b = bswap16(a); - ]) -], [SYS_ENDIAN_BSWAP='yes'], [SYS_ENDIAN_BSWAP='no']) - AC_MSG_RESULT([$SYS_ENDIAN_BSWAP]) - - if test "$SYS_ENDIAN_BSWAP" = "yes" ; then - USE_SYS_ENDIAN_H=yes - BSWAP=bswap - else - if test "$SYS_ENDIAN__SWAP" = "yes" ; then - USE_SYS_ENDIAN_H=yes - BSWAP=__swap - else - USE_SYS_ENDIAN_H=no - fi - fi - - if test "$USE_SYS_ENDIAN_H" = "yes" ; then - AC_DEFINE([USE_SYS_ENDIAN_H], 1, - [Define to use byteswap macros from ]) - AC_DEFINE_UNQUOTED([bswap_16], ${BSWAP}16, - [Define to 16-bit byteswap macro]) - AC_DEFINE_UNQUOTED([bswap_32], ${BSWAP}32, - [Define to 32-bit byteswap macro]) - AC_DEFINE_UNQUOTED([bswap_64], ${BSWAP}64, - [Define to 64-bit byteswap macro]) - fi -fi - -dnl Check to see if dlopen is in default libraries (like Solaris, which -dnl has it in libc), or if libdl is needed to get it. -AC_CHECK_FUNC([dlopen], [], - AC_CHECK_LIB([dl], [dlopen], DLOPEN_LIBS="-ldl")) -AC_SUBST(DLOPEN_LIBS) - -dnl Checks for library functions. -AC_FUNC_VPRINTF -AC_CHECK_FUNCS([geteuid getuid link memmove memset mkstemp strchr strrchr \ - strtol getopt getopt_long vsnprintf walkcontext backtrace \ - getisax getzoneid shmctl64 strcasestr ffs]) -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]) -AC_CHECK_FUNC([strlcpy], AC_DEFINE(HAS_STRLCPY, 1, [Have the 'strlcpy' function])) - -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) -AC_CHECK_LIB(m, cbrt, AC_DEFINE(HAVE_CBRT, 1, [Have the 'cbrt' function])) - -AC_CHECK_HEADERS([ndbm.h dbm.h rpcsvc/dbm.h]) - -dnl AGPGART headers -AC_CHECK_HEADERS([linux/agpgart.h sys/agpio.h sys/agpgart.h], AGP=yes) -AM_CONDITIONAL(AGP, [test "x$AGP" = xyes]) - -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 -#include -#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 OpenBSD /dev/xf86 aperture driver -if test -c /dev/xf86 ; then - AC_DEFINE(HAS_APERTURE_DRV, 1, [System has /dev/xf86 aperture driver]) -fi - -dnl BSD APM support -AC_CHECK_HEADER([machine/apmvar.h],[ - AC_CHECK_HEADER([sys/event.h], - ac_cv_BSD_KQUEUE_APM=yes, - ac_cv_BSD_APM=yes)]) - -AM_CONDITIONAL(BSD_APM, [test "x$ac_cv_BSD_APM" = xyes]) -AM_CONDITIONAL(BSD_KQUEUE_APM, [test "x$ac_cv_BSD_KQUEUE_APM" = xyes]) - -dnl glibc backtrace support check (hw/xfree86/common/xf86Events.c) -AC_CHECK_HEADER([execinfo.h],[ - AC_CHECK_LIB(c, backtrace, [ - AC_DEFINE(HAVE_BACKTRACE, 1, [Has backtrace support]) - AC_DEFINE(HAVE_EXECINFO_H, 1, [Have execinfo.h]) - ])] -) - -dnl ARM needs additional compiler flags for proper backtraces if GCC is -dnl used. Compile a dummy program with the -mapcs-frame option. If it -dnl succeeds, we know that we are building for ARM with GCC. -old_CFLAGS="$CFLAGS" -CFLAGS="-mapcs-frame" -AC_COMPILE_IFELSE( - AC_LANG_PROGRAM([[ ]]), - ARM_BACKTRACE_CFLAGS="$CFLAGS", - ARM_BACKTRACE_CFLAGS="" -) -CFLAGS="$old_CFLAGS" -AC_SUBST(ARM_BACKTRACE_CFLAGS) - -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 - *freebsd*) SYS_LIBS=-lio ;; - *netbsd*) AC_DEFINE(USE_ALPHA_PIO, 1, [NetBSD PIO alpha IO]) ;; - esac - GLX_ARCH_DEFINES="-D__GLX_ALIGN64 -mieee" - ;; - arm*) - ARM_VIDEO=yes - ;; - i*86) - I386_VIDEO=yes - case $host_os in - *freebsd*) AC_DEFINE(USE_DEV_IO) ;; - *dragonfly*) 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*) - SPARC64_VIDEO=yes - BSD_ARCH_SOURCES="sparc64_video.c ioperm_noop.c" - GLX_ARCH_DEFINES="-D__GLX_ALIGN64" - ;; - x86_64*|amd64*) - I386_VIDEO=yes - case $host_os in - *freebsd*) AC_DEFINE(USE_DEV_IO, 1, [BSD /dev/io]) ;; - *dragonfly*) 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 - GLX_ARCH_DEFINES="-D__GLX_ALIGN64" - ;; - ia64*) - GLX_ARCH_DEFINES="-D__GLX_ALIGN64" - ;; - s390*) - GLX_ARCH_DEFINES="-D__GLX_ALIGN64" - ;; -esac -AC_SUBST(GLX_ARCH_DEFINES) - -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 -USE_SIGIO_BY_DEFAULT="yes" -dnl it would be nice to autodetect these *CONS_SUPPORTs -case $host_os in - *freebsd* | *dragonfly*) - 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]) - DRI=yes - ;; - *netbsd*) - AC_DEFINE(CSRG_BASED, 1, [System is BSD-like]) - AC_DEFINE(PCCONS_SUPPORT, 1, [System has PC console]) - AC_DEFINE(PCVT_SUPPORT, 1, [System has PCVT console]) - AC_DEFINE(WSCONS_SUPPORT, 1, [System has wscons console]) - DRI=yes - ;; - *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]) - ;; - *linux*) - DRI=yes - ;; - *solaris*) - PKG_CHECK_EXISTS(libdrm, DRI=yes, DRI=no) - # Disable use of SIGIO by default until some system bugs are - # fixed - see Sun/OpenSolaris bug id 6879897 - USE_SIGIO_BY_DEFAULT="no" - ;; - darwin*) - AC_DEFINE(CSRG_BASED, 1, [System is BSD-like]) - ;; - cygwin*) - CFLAGS="$CFLAGS -DFD_SETSIZE=256" - ;; -esac - -dnl augment XORG_RELEASE_VERSION for our snapshot number and to expose the -dnl major number -PVMAJOR=`echo $PACKAGE_VERSION | cut -d . -f 1` -PVS=`echo $PACKAGE_VERSION | cut -d . -f 4 | cut -d - -f 1` -if test "x$PVS" = "x"; then - PVS="0" -fi - -VENDOR_RELEASE="((($PVMAJOR) * 10000000) + (($PVM) * 100000) + (($PVP) * 1000) + $PVS)" -VENDOR_MAN_VERSION="Version ${PACKAGE_VERSION}" - -VENDOR_NAME="The X.Org Foundation" -VENDOR_NAME_SHORT="X.Org" -VENDOR_WEB="http://wiki.x.org" - -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], - [Obsolete - use --enable-strict-compilation instead]), - AC_MSG_ERROR([--enable-werror has been replaced by --enable-strict-compilation])) - -AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], - [Enable debugging (default: disabled)]), - [DEBUGGING=$enableval], [DEBUGGING=no]) -AC_ARG_ENABLE(unit-tests, AS_HELP_STRING([--enable-unit-tests], - [Enable unit-tests (default: auto)]), - [UNITTESTS=$enableval], [UNITTESTS=auto]) -AC_ARG_ENABLE(use-sigio-by-default, AS_HELP_STRING([--enable-use-sigio-by-default] - [Enable SIGIO input handlers by default (default: $USE_SIGIO_BY_DEFAULT)]), - [USE_SIGIO_BY_DEFAULT=$enableval], []) -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-name=VENDOR], - [Vendor string reported by the server]), - [ VENDOR_NAME="$withval" ], []) -AC_ARG_WITH(vendor-name-short, AS_HELP_STRING([--with-vendor-name-short=VENDOR], - [Short version of vendor string reported by the server]), - [ VENDOR_NAME_SHORT="$withval" ], []) -AC_ARG_WITH(vendor-web, AS_HELP_STRING([--with-vendor-web=URL], - [Vendor web address reported by the server]), - [ VENDOR_WEB="$withval" ], []) -AC_ARG_WITH(module-dir, AS_HELP_STRING([--with-module-dir=DIR], - [Directory where modules are installed (default: $libdir/xorg/modules)]), - [ moduledir="$withval" ], - [ moduledir="${libdir}/xorg/modules" ]) -AC_ARG_WITH(log-dir, AS_HELP_STRING([--with-log-dir=DIR], - [Directory where log files are kept (default: $localstatedir/log)]), - [ logdir="$withval" ], - [ logdir="$localstatedir/log" ]) -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(os-name, AS_HELP_STRING([--with-os-name=OSNAME], [Name of OS (default: output of "uname -srm")]), - [ OSNAME="$withval" ], - [ OSNAME=`uname -srm` ]) -AC_ARG_WITH(os-vendor, AS_HELP_STRING([--with-os-vendor=OSVENDOR], [Name of OS vendor]), - [ OSVENDOR="$withval" ], - [ OSVENDOR="" ]) -AC_ARG_WITH(builderstring, AS_HELP_STRING([--with-builderstring=BUILDERSTRING], [Additional builder string]), - [ BUILDERSTRING="$withval" ] - [ ]) - -dnl Determine font path -XORG_FONTROOTDIR -XORG_FONTSUBDIR(FONTMISCDIR, fontmiscdir, misc) -XORG_FONTSUBDIR(FONTOTFDIR, fontotfdir, OTF) -XORG_FONTSUBDIR(FONTTTFDIR, fontttfdir, TTF) -XORG_FONTSUBDIR(FONTTYPE1DIR, fonttype1dir, Type1) -XORG_FONTSUBDIR(FONT75DPIDIR, font75dpidir, 75dpi) -XORG_FONTSUBDIR(FONT100DPIDIR, font100dpidir, 100dpi) - -dnl Uses --default-font-path if set, otherwise checks for /etc/X11/fontpath.d, -dnl otherwise uses standard subdirectories of FONTROOTDIR. When cross -dnl compiling, assume default font path uses standard FONTROOTDIR directories. -DEFAULT_FONT_PATH="${FONTMISCDIR}/,${FONTTTFDIR}/,${FONTOTFDIR}/,${FONTTYPE1DIR}/,${FONT100DPIDIR}/,${FONT75DPIDIR}/" -if test "$cross_compiling" != yes; then - AC_CHECK_FILE([${sysconfdir}/X11/fontpath.d], - [DEFAULT_FONT_PATH='catalogue:${sysconfdir}/X11/fontpath.d'], - [case $host_os in - darwin*) DEFAULT_FONT_PATH="${DEFAULT_FONT_PATH},/Library/Fonts,/System/Library/Fonts" ;; - esac]) -fi -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}" ]) - -AC_MSG_CHECKING([for default font path]) -AC_MSG_RESULT([$FONTPATH]) - -AC_ARG_WITH(xkb-path, AS_HELP_STRING([--with-xkb-path=PATH], [Path to XKB base dir (default: ${datadir}/X11/xkb)]), - [ XKBPATH="$withval" ], - [ XKBPATH="${datadir}/X11/xkb" ]) -AC_ARG_WITH(xkb-output, AS_HELP_STRING([--with-xkb-output=PATH], [Path to XKB output dir (default: ${datadir}/X11/xkb/compiled)]), - [ XKBOUTPUT="$withval" ], - [ XKBOUTPUT="compiled" ]) -AC_ARG_WITH(default-xkb-rules, AS_HELP_STRING([--with-default-xkb-rules=RULES], - [Keyboard ruleset (default: base/evdev)]), - [ XKB_DFLT_RULES="$withval" ], - [ XKB_DFLT_RULES="" ]) -AC_ARG_WITH(default-xkb-model, AS_HELP_STRING([--with-default-xkb-model=MODEL], - [Keyboard model (default: pc105)]), - [ XKB_DFLT_MODEL="$withval" ], - [ XKB_DFLT_MODEL="pc105" ]) -AC_ARG_WITH(default-xkb-layout, AS_HELP_STRING([--with-default-xkb-layout=LAYOUT], - [Keyboard layout (default: us)]), - [ XKB_DFLT_LAYOUT="$withval" ], - [ XKB_DFLT_LAYOUT="us" ]) -AC_ARG_WITH(default-xkb-variant, AS_HELP_STRING([--with-default-xkb-variant=VARIANT], - [Keyboard variant (default: (none))]), - [ XKB_DFLT_VARIANT="$withval" ], - [ XKB_DFLT_VARIANT="" ]) -AC_ARG_WITH(default-xkb-options, AS_HELP_STRING([--with-default-xkb-options=OPTIONS], - [Keyboard layout options (default: (none))]), - [ XKB_DFLT_OPTIONS="$withval" ], - [ XKB_DFLT_OPTIONS="" ]) -AC_ARG_WITH(serverconfig-path, AS_HELP_STRING([--with-serverconfig-path=PATH], - [Directory where ancillary server config files are installed (default: ${libdir}/xorg)]), - [ SERVERCONFIG="$withval" ], - [ SERVERCONFIG="${libdir}/xorg" ]) -AC_ARG_WITH(apple-applications-dir,AS_HELP_STRING([--with-apple-applications-dir=PATH], [Path to the Applications directory (default: /Applications/Utilities)]), - [ APPLE_APPLICATIONS_DIR="${withval}" ], - [ APPLE_APPLICATIONS_DIR="/Applications/Utilities" ]) -AC_SUBST([APPLE_APPLICATIONS_DIR]) -AC_ARG_WITH(apple-application-name,AS_HELP_STRING([--with-apple-application-name=NAME], [Name for the .app (default: X11)]), - [ APPLE_APPLICATION_NAME="${withval}" ], - [ APPLE_APPLICATION_NAME="X11" ]) -AC_SUBST([APPLE_APPLICATION_NAME]) -AC_ARG_WITH(launchd-id-prefix, AS_HELP_STRING([--with-launchd-id-prefix=PATH], [Prefix to use for launchd identifiers (default: org.x)]), - [ LAUNCHD_ID_PREFIX="${withval}" ], - [ LAUNCHD_ID_PREFIX="org.x" ]) -AC_SUBST([LAUNCHD_ID_PREFIX]) -AC_DEFINE_UNQUOTED(LAUNCHD_ID_PREFIX, "$LAUNCHD_ID_PREFIX", [Prefix to use for launchd identifiers]) -AC_ARG_ENABLE(sparkle,AS_HELP_STRING([--enable-sparkle], [Enable updating of X11.app using the Sparkle Framework (default: disabled)]), - [ XQUARTZ_SPARKLE="${enableval}" ], - [ XQUARTZ_SPARKLE="no" ]) -AC_SUBST([XQUARTZ_SPARKLE]) -AC_ARG_ENABLE(builddocs, AS_HELP_STRING([--enable-builddocs], [Build docs (default: disabled)]), - [BUILDDOCS=$enableval], - [BUILDDOCS=no]) -AC_ARG_ENABLE(install-libxf86config, - AS_HELP_STRING([--enable-install-libxf86config], - [Install libxf86config (default: disabled)]), - [INSTALL_LIBXF86CONFIG=$enableval], - [INSTALL_LIBXF86CONFIG=no]) -AC_ARG_ENABLE(visibility, AC_HELP_STRING([--enable-visibility], [Enable symbol visibility (default: auto)]), - [SYMBOL_VISIBILITY=$enableval], - [SYMBOL_VISIBILITY=auto]) -AC_ARG_ENABLE(pc98, AC_HELP_STRING([--enable-pc98], [Enable PC98 support in Xorg (default: auto)]), - [SUPPORT_PC98=$enableval], - [SUPPORT_PC98=auto]) - -dnl GLX build options -AC_ARG_WITH(dri-driver-path, AS_HELP_STRING([--with-dri-driver-path=PATH], [Path to DRI drivers (default: ${libdir}/dri)]), - [ DRI_DRIVER_PATH="$withval" ], - [ DRI_DRIVER_PATH="${libdir}/dri" ]) -AC_ARG_ENABLE(aiglx, AS_HELP_STRING([--enable-aiglx], [Build accelerated indirect GLX (default: enabled)]), - [AIGLX=$enableval], - [AIGLX=yes]) -AC_ARG_ENABLE(glx-tls, AS_HELP_STRING([--enable-glx-tls], [Build GLX with TLS support (default: disabled)]), - [GLX_USE_TLS=$enableval], - [GLX_USE_TLS=no]) - -dnl Extensions. -AC_ARG_ENABLE(registry, AS_HELP_STRING([--disable-registry], [Build string registry module (default: enabled)]), [XREGISTRY=$enableval], [XREGISTRY=yes]) -AC_ARG_ENABLE(composite, AS_HELP_STRING([--disable-composite], [Build Composite extension (default: enabled)]), [COMPOSITE=$enableval], [COMPOSITE=yes]) -AC_ARG_ENABLE(mitshm, AS_HELP_STRING([--disable-shm], [Build SHM extension (default: enabled)]), [MITSHM=$enableval], [MITSHM=yes]) -AC_ARG_ENABLE(xres, AS_HELP_STRING([--disable-xres], [Build XRes extension (default: enabled)]), [RES=$enableval], [RES=yes]) -AC_ARG_ENABLE(record, AS_HELP_STRING([--disable-record], [Build Record extension (default: enabled)]), [RECORD=$enableval], [RECORD=yes]) -AC_ARG_ENABLE(xv, AS_HELP_STRING([--disable-xv], [Build Xv extension (default: enabled)]), [XV=$enableval], [XV=yes]) -AC_ARG_ENABLE(xvmc, AS_HELP_STRING([--disable-xvmc], [Build XvMC extension (default: enabled)]), [XVMC=$enableval], [XVMC=yes]) -AC_ARG_ENABLE(dga, AS_HELP_STRING([--disable-dga], [Build DGA extension (default: auto)]), [DGA=$enableval], [DGA=auto]) -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(glx, AS_HELP_STRING([--disable-glx], [Build GLX extension (default: enabled)]), [GLX=$enableval], [GLX=yes]) -AC_ARG_ENABLE(dri, AS_HELP_STRING([--enable-dri], [Build DRI extension (default: auto)]), [DRI=$enableval]) -AC_ARG_ENABLE(dri2, AS_HELP_STRING([--enable-dri2], [Build DRI2 extension (default: auto)]), [DRI2=$enableval], [DRI2=auto]) -AC_ARG_ENABLE(xinerama, AS_HELP_STRING([--disable-xinerama], [Build Xinerama extension (default: enabled)]), [XINERAMA=$enableval], [XINERAMA=yes]) -AC_ARG_ENABLE(xf86vidmode, AS_HELP_STRING([--disable-xf86vidmode], [Build XF86VidMode extension (default: auto)]), [XF86VIDMODE=$enableval], [XF86VIDMODE=auto]) -AC_ARG_ENABLE(xace, AS_HELP_STRING([--disable-xace], [Build X-ACE extension (default: enabled)]), [XACE=$enableval], [XACE=yes]) -AC_ARG_ENABLE(xselinux, AS_HELP_STRING([--enable-xselinux], [Build SELinux extension (default: disabled)]), [XSELINUX=$enableval], [XSELINUX=no]) -AC_ARG_ENABLE(xcsecurity, AS_HELP_STRING([--enable-xcsecurity], [Build Security extension (default: disabled)]), [XCSECURITY=$enableval], [XCSECURITY=no]) -AC_ARG_ENABLE(xcalibrate, AS_HELP_STRING([--enable-xcalibrate], [Build XCalibrate extension (default: disabled)]), [XCALIBRATE=$enableval], [XCALIBRATE=no]) -AC_ARG_ENABLE(tslib, AS_HELP_STRING([--enable-tslib], [Build kdrive tslib touchscreen support (default: disabled)]), [TSLIB=$enableval], [TSLIB=no]) -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([--enable-xf86bigfont], [Build XF86 Big Font extension (default: disabled)]), [XF86BIGFONT=$enableval], [XF86BIGFONT=no]) -AC_ARG_ENABLE(dpms, AS_HELP_STRING([--disable-dpms], [Build DPMS extension (default: enabled)]), [DPMSExtension=$enableval], [DPMSExtension=yes]) -AC_ARG_ENABLE(config-udev, AS_HELP_STRING([--enable-config-udev], [Build udev support (default: auto)]), [CONFIG_UDEV=$enableval], [CONFIG_UDEV=auto]) -AC_ARG_ENABLE(config-dbus, AS_HELP_STRING([--enable-config-dbus], [Build D-BUS API support (default: no)]), [CONFIG_DBUS_API=$enableval], [CONFIG_DBUS_API=no]) -AC_ARG_ENABLE(config-hal, AS_HELP_STRING([--disable-config-hal], [Build HAL support (default: auto)]), [CONFIG_HAL=$enableval], [CONFIG_HAL=auto]) -AC_ARG_ENABLE(xfree86-utils, AS_HELP_STRING([--enable-xfree86-utils], [Build xfree86 DDX utilities (default: enabled)]), [XF86UTILS=$enableval], [XF86UTILS=yes]) -AC_ARG_ENABLE(xaa, AS_HELP_STRING([--enable-xaa], [Build XAA (default: enabled)]), [XAA=$enableval], [XAA=yes]) -AC_ARG_ENABLE(vgahw, AS_HELP_STRING([--enable-vgahw], [Build Xorg with vga access (default: enabled)]), [VGAHW=$enableval], [VGAHW=yes]) -AC_ARG_ENABLE(vbe, AS_HELP_STRING([--enable-vbe], [Build Xorg with VBE module (default: enabled)]), [VBE=$enableval], [VBE=yes]) -AC_ARG_ENABLE(int10-module, AS_HELP_STRING([--enable-int10-module], [Build Xorg with int10 module (default: enabled)]), [INT10MODULE=$enableval], [INT10MODULE=yes]) -AC_ARG_ENABLE(windowswm, AS_HELP_STRING([--enable-windowswm], [Build XWin with WindowsWM extension (default: no)]), [WINDOWSWM=$enableval], [WINDOWSWM=no]) - -dnl DDXes. -AC_ARG_ENABLE(xorg, AS_HELP_STRING([--enable-xorg], [Build Xorg server (default: auto)]), [XORG=$enableval], [XORG=auto]) -AC_ARG_ENABLE(dmx, AS_HELP_STRING([--enable-dmx], [Build DMX server (default: auto)]), [DMX=$enableval], [DMX=auto]) -AC_ARG_ENABLE(xvfb, AS_HELP_STRING([--enable-xvfb], [Build Xvfb server (default: yes)]), [XVFB=$enableval], [XVFB=yes]) -AC_ARG_ENABLE(xnest, AS_HELP_STRING([--enable-xnest], [Build Xnest server (default: auto)]), [XNEST=$enableval], [XNEST=auto]) -AC_ARG_ENABLE(xquartz, AS_HELP_STRING([--enable-xquartz], [Build Xquartz server for OS-X (default: auto)]), [XQUARTZ=$enableval], [XQUARTZ=auto]) -AC_ARG_ENABLE(standalone-xpbproxy, AS_HELP_STRING([--enable-standalone-xpbproxy], [Build a standalone xpbproxy (in addition to the one integrated into Xquartz as a separate thread) (default: no)]), [STANDALONE_XPBPROXY=$enableval], [STANDALONE_XPBPROXY=no]) -AC_ARG_ENABLE(xwin, AS_HELP_STRING([--enable-xwin], [Build XWin server (default: auto)]), [XWIN=$enableval], [XWIN=auto]) -dnl kdrive and its subsystems -AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) -AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) -AC_ARG_ENABLE(xfake, AS_HELP_STRING([--enable-xfake], [Build the kdrive 'fake' server (default: auto)]), [XFAKE=$enableval], [XFAKE=auto]) -AC_ARG_ENABLE(xfbdev, AS_HELP_STRING([--enable-xfbdev], [Build the kdrive framebuffer device server (default: auto)]), [XFBDEV=$enableval], [XFBDEV=auto]) -dnl kdrive options -AC_ARG_ENABLE(kdrive-kbd, AS_HELP_STRING([--enable-kdrive-kbd], [Build kbd driver for kdrive (default: auto)]), [KDRIVE_KBD=$enableval], [KDRIVE_KBD=auto]) -AC_ARG_ENABLE(kdrive-mouse, AC_HELP_STRING([--enable-kdrive-mouse], [Build mouse driver for kdrive (default: auto)]), [KDRIVE_MOUSE=$enableval], [KDRIVE_MOUSE=auto]) -AC_ARG_ENABLE(kdrive-evdev, AC_HELP_STRING([--enable-kdrive-evdev], [Build evdev driver for kdrive (default: auto)]), [KDRIVE_EVDEV=$enableval], [KDRIVE_EVDEV=auto]) - - -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 - cygwin*) SETUID="no" ;; - 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(SECURE_RPC, [test "x$SECURE_RPC" = xyes]) - -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 Handle building documentation -AM_CONDITIONAL(BUILDDOCS, test "x$BUILDDOCS" = xyes) - -dnl Only build sgml docs when linuxdoc is available and -dnl def.ents has been installed -XORG_CHECK_LINUXDOC - -dnl Handle installing libxf86config -AM_CONDITIONAL(INSTALL_LIBXF86CONFIG, [test "x$INSTALL_LIBXF86CONFIG" = xyes]) - -dnl DDX Detection... Yes, it's ugly to have it here... but we need to -dnl handle this early on so that we don't require unsupported extensions -case $host_os in - cygwin*) - DGA=no - DRI2=no - XF86VIDMODE=no - XSELINUX=no - XV=no - ;; - darwin*) - DRI2=no - - if test x$XQUARTZ = xauto; then - AC_CACHE_CHECK([whether to build Xquartz],xorg_cv_Carbon_framework,[ - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -framework Carbon" - AC_LINK_IFELSE([char FSFindFolder(); int main() { FSFindFolder(); return 0;}], - [xorg_cv_Carbon_framework=yes], - [xorg_cv_Carbon_framework=no]) - LDFLAGS=$save_LDFLAGS]) - - if test "X$xorg_cv_Carbon_framework" = Xyes; then - XQUARTZ=yes - else - XQUARTZ=no - fi - fi - - if test "x$XQUARTZ" = xyes ; then - XQUARTZ=yes - XVFB=no - XNEST=no - - COMPOSITE=no - DGA=no - DPMSExtension=no - XF86VIDMODE=no - fi - ;; - *) XQUARTZ=no ;; -esac - -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 Optional modules -VIDEOPROTO="videoproto" -COMPOSITEPROTO="compositeproto >= 0.4" -RECORDPROTO="recordproto >= 1.13.99.1" -SCRNSAVERPROTO="scrnsaverproto >= 1.1" -RESOURCEPROTO="resourceproto" -DRIPROTO="xf86driproto >= 2.1.0" -DRI2PROTO="dri2proto >= 2.2" -XINERAMAPROTO="xineramaproto" -BIGFONTPROTO="xf86bigfontproto >= 1.2.0" -XCALIBRATEPROTO="xcalibrateproto" -DGAPROTO="xf86dgaproto >= 2.0.99.1" -GLPROTO="glproto >= 1.4.10" -DMXPROTO="dmxproto >= 2.2.99.1" -VIDMODEPROTO="xf86vidmodeproto >= 2.2.99.1" -WINDOWSWMPROTO="windowswmproto" -APPLEWMPROTO="applewmproto >= 1.4" - -dnl Core modules for most extensions, et al. -REQUIRED_MODULES="[randrproto >= 1.2.99.3] [renderproto >= 0.11] [fixesproto >= 4.1] [damageproto >= 1.1] [xcmiscproto >= 1.2.0] [xextproto >= 7.0.99.3] [xproto >= 7.0.13] [xtrans >= 1.2.2] [bigreqsproto >= 1.1.0] fontsproto [inputproto >= 1.9.99.902] [kbproto >= 1.0.3]" -REQUIRED_LIBS="xfont xau [pixman-1 >= 0.15.20]" - -dnl List of libraries that require a specific version -LIBAPPLEWM="applewm >= 1.4" -LIBDMX="dmx >= 1.0.99.1" -LIBDRI="dri >= 7.8.0" -LIBDRM="libdrm >= 2.3.0" -LIBGL="gl >= 7.1.0" -LIBXEXT="xext >= 1.0.99.4" -LIBXI="xi >= 1.2.99.1" -LIBXTST="xtst >= 1.0.99.2" -LIBPCIACCESS="pciaccess >= 0.8.0" -LIBGLIB="glib-2.0 >= 2.16" -LIBUDEV="libudev >= 143" -LIBSELINUX="libselinux >= 2.0.86" - -if test "x$CONFIG_UDEV" = xyes && - { test "x$CONFIG_DBUS_API" = xyes || test "x$CONFIG_HAL" = xyes; }; then - AC_MSG_ERROR([Hotplugging through both libudev and dbus/hal not allowed]) -fi - -PKG_CHECK_MODULES(UDEV, $LIBUDEV, [HAVE_LIBUDEV=yes], [HAVE_LIBUDEV=no]) -if test "x$CONFIG_UDEV" = xauto; then - CONFIG_UDEV="$HAVE_LIBUDEV" -fi -AM_CONDITIONAL(CONFIG_UDEV, [test "x$CONFIG_UDEV" = xyes]) -if test "x$CONFIG_UDEV" = xyes; then - CONFIG_DBUS_API=no - CONFIG_HAL=no - if ! test "x$HAVE_LIBUDEV" = xyes; then - AC_MSG_ERROR([udev configuration API requested, but libudev is not installed]) - fi - AC_DEFINE(CONFIG_UDEV, 1, [Use libudev for input hotplug]) -fi - -dnl HAVE_DBUS is true if we actually have the D-Bus library, whereas -dnl CONFIG_DBUS_API is true if we want to enable the D-Bus config -dnl API. -PKG_CHECK_MODULES(DBUS, dbus-1, [HAVE_DBUS=yes], [HAVE_DBUS=no]) -if test "x$HAVE_DBUS" = xyes; then - AC_DEFINE(HAVE_DBUS, 1, [Have D-Bus support]) -fi -AM_CONDITIONAL(HAVE_DBUS, [test "x$HAVE_DBUS" = xyes]) - -if test "x$CONFIG_DBUS_API" = xauto; then - CONFIG_DBUS_API="$HAVE_DBUS" -fi -if test "x$CONFIG_DBUS_API" = xyes; then - if ! test "x$HAVE_DBUS" = xyes; then - AC_MSG_ERROR([D-Bus configuration API requested, but D-Bus is not installed.]) - fi - - AC_DEFINE(CONFIG_DBUS_API, 1, [Use the D-Bus input configuration API]) - CONFIG_NEED_DBUS="yes" -fi -AM_CONDITIONAL(CONFIG_DBUS_API, [test "x$CONFIG_DBUS_API" = xyes]) - -PKG_CHECK_MODULES(HAL, hal, [HAVE_HAL=yes], [HAVE_HAL=no]) -if test "x$CONFIG_HAL" = xauto; then - CONFIG_HAL="$HAVE_HAL" -fi -if test "x$CONFIG_HAL" = xyes; then - if ! test "x$HAVE_HAL" = xyes; then - AC_MSG_ERROR([HAL hotplug API requested, but HAL is not installed.]) - fi - - AC_DEFINE(CONFIG_HAL, 1, [Use the HAL hotplug API]) - CONFIG_NEED_DBUS="yes" -fi -AM_CONDITIONAL(CONFIG_HAL, [test "x$CONFIG_HAL" = xyes]) - -if test "x$CONFIG_NEED_DBUS" = xyes; then - AC_DEFINE(CONFIG_NEED_DBUS, 1, [Use D-Bus for input hotplug]) -fi -AM_CONDITIONAL(CONFIG_NEED_DBUS, [test "x$CONFIG_NEED_DBUS" = xyes]) -CONFIG_LIB='$(top_builddir)/config/libconfig.la' - -if test "x$USE_SIGIO_BY_DEFAULT" = xyes; then - USE_SIGIO_BY_DEFAULT_VALUE=TRUE -else - USE_SIGIO_BY_DEFAULT_VALUE=FALSE -fi -AC_DEFINE_UNQUOTED([USE_SIGIO_BY_DEFAULT], [$USE_SIGIO_BY_DEFAULT_VALUE], - [Use SIGIO handlers for input device events by default]) - -AC_MSG_CHECKING([for glibc...]) -AC_PREPROC_IFELSE([ -#include -#ifndef __GLIBC__ -#error -#endif -], glibc=yes, glibc=no) -AC_MSG_RESULT([$glibc]) - -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 - CLOCK_LIBS="$have_clock_gettime" - else - CLOCK_LIBS="" - fi - - LIBS_SAVE="$LIBS" - LIBS="$CLOCK_LIBS" - CPPFLAGS_SAVE="$CPPFLAGS" - - if test x"$glibc" = xyes; then - CPPFLAGS="$CPPFLAGS -D_POSIX_C_SOURCE=200112L" - fi - - AC_RUN_IFELSE([ -#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"]) - - LIBS="$LIBS_SAVE" - CPPFLAGS="$CPPFLAGS_SAVE" -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()]) - LIBS="$LIBS $CLOCK_LIBS" -fi - -AM_CONDITIONAL(XV, [test "x$XV" = xyes]) -if test "x$XV" = xyes; then - AC_DEFINE(XV, 1, [Support Xv extension]) - AC_DEFINE(XvExtension, 1, [Build Xv extension]) - REQUIRED_MODULES="$REQUIRED_MODULES $VIDEOPROTO" -else - XVMC=no -fi - -AM_CONDITIONAL(XVMC, [test "x$XVMC" = xyes]) -if test "x$XVMC" = xyes; then - AC_DEFINE(XvMCExtension, 1, [Build XvMC extension]) -fi - -AM_CONDITIONAL(XREGISTRY, [test "x$XREGISTRY" = xyes]) -if test "x$XREGISTRY" = xyes; then - AC_DEFINE(XREGISTRY, 1, [Build registry module]) -fi - -AM_CONDITIONAL(COMPOSITE, [test "x$COMPOSITE" = xyes]) -if test "x$COMPOSITE" = xyes; then - AC_DEFINE(COMPOSITE, 1, [Support Composite Extension]) - REQUIRED_MODULES="$REQUIRED_MODULES $COMPOSITEPROTO" - COMPOSITE_LIB='$(top_builddir)/composite/libcomposite.la' - COMPOSITE_INC='-I$(top_srcdir)/composite' -fi - -AM_CONDITIONAL(MITSHM, [test "x$MITSHM" = xyes]) -if test "x$MITSHM" = xyes; then - AC_DEFINE(MITSHM, 1, [Support MIT-SHM extension]) - AC_DEFINE(HAS_SHM, 1, [Support SHM]) -fi - -AM_CONDITIONAL(RECORD, [test "x$RECORD" = xyes]) -if test "x$RECORD" = xyes; then - AC_DEFINE(XRECORD, 1, [Support Record extension]) - REQUIRED_MODULES="$REQUIRED_MODULES $RECORDPROTO" - RECORD_LIB='$(top_builddir)/record/librecord.la' -fi - -AM_CONDITIONAL(SCREENSAVER, [test "x$SCREENSAVER" = xyes]) -if test "x$SCREENSAVER" = xyes; then - AC_DEFINE(SCREENSAVER, 1, [Support MIT-SCREEN-SAVER extension]) - REQUIRED_MODULES="$REQUIRED_MODULES $SCRNSAVERPROTO" -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 - -if test "x$GLX" = xyes; then - PKG_CHECK_MODULES([XLIB], [x11]) - PKG_CHECK_MODULES([GL], $GLPROTO $LIBGL) - AC_SUBST(XLIB_CFLAGS) - AC_DEFINE(GLXEXT, 1, [Build GLX extension]) - GLX_LIBS='$(top_builddir)/glx/libglx.la' - GLX_SYS_LIBS="$GLX_SYS_LIBS" -else - GLX=no -fi -AM_CONDITIONAL(GLX, test "x$GLX" = xyes) - -if test "x$AIGLX" = xyes -a "x$GLX" = xyes -a "x$DRI" = xyes; then - AC_DEFINE(AIGLX, 1, [Build AIGLX loader]) -else - AIGLX=no -fi -AM_CONDITIONAL(AIGLX, test "x$AIGLX" = xyes) - -if test "x$GLX_USE_TLS" = xyes -a "x$AIGLX" = xyes; then - GLX_DEFINES="-DGLX_USE_TLS -DPTHREADS" - GLX_SYS_LIBS="$GLX_SYS_LIBS -lpthread" -fi -AC_SUBST([GLX_DEFINES]) - -AM_CONDITIONAL(DRI, test "x$DRI" = xyes) -if test "x$DRI" = xyes; then - AC_DEFINE(XF86DRI, 1, [Build DRI extension]) - PKG_CHECK_MODULES([DRIPROTO], [$DRIPROTO]) - PKG_CHECK_MODULES([DRI], $GLPROTO $LIBDRI) - AC_SUBST(DRIPROTO_CFLAGS) -fi - -PKG_CHECK_MODULES([DRI2PROTO], $DRI2PROTO, - [HAVE_DRI2PROTO=yes], [HAVE_DRI2PROTO=no]) -case "$DRI2,$HAVE_DRI2PROTO" in - yes,no) - AC_MSG_ERROR([DRI2 requested, but dri2proto not found.]) - ;; - yes,yes | auto,yes) - AC_DEFINE(DRI2, 1, [Build DRI2 extension]) - DRI2=yes - ;; -esac -AM_CONDITIONAL(DRI2, test "x$DRI2" = xyes) - -if test "x$DRI" = xyes || test "x$DRI2" = xyes; then - PKG_CHECK_MODULES([LIBDRM], $LIBDRM) - AC_SUBST(LIBDRM_CFLAGS) - AC_SUBST(LIBDRM_LIBS) -fi - -if test "x$DRI2" = xyes; then - save_CFLAGS=$CFLAGS - CFLAGS="$GL_CFLAGS $LIBDRM_CFLAGS" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include -#include -#ifndef __DRI_DRI2 -#error DRI2 extension not available. -#endif]])], - [HAVE_DRI2EXTENSION=yes], - [HAVE_DRI2EXTENSION=no]) - CFLAGS=$save_CFLAGS - if test "x$HAVE_DRI2EXTENSION" = xyes; then - AC_DEFINE(DRI2_AIGLX, 1, [Build DRI2 AIGLX loader]) - DRI2_AIGLX=yes - else - AC_MSG_NOTICE([DRI2 AIGLX disabled, __DRI_DRI2 not defined in dri_interface.h.]) - DRI2_AIGLX=no - fi -fi -AM_CONDITIONAL(DRI2_AIGLX, test "x$DRI2_AIGLX" = xyes) - - -AM_CONDITIONAL(XINERAMA, [test "x$XINERAMA" = xyes]) -if test "x$XINERAMA" = xyes; then - AC_DEFINE(XINERAMA, 1, [Support Xinerama extension]) - AC_DEFINE(PANORAMIX, 1, [Internal define for Xinerama]) - REQUIRED_MODULES="$REQUIRED_MODULES $XINERAMAPROTO" -fi - -AM_CONDITIONAL(XACE, [test "x$XACE" = xyes]) -if test "x$XACE" = xyes; then - AC_DEFINE(XACE, 1, [Build X-ACE extension]) -fi - -AM_CONDITIONAL(XSELINUX, [test "x$XSELINUX" = xyes]) -if test "x$XSELINUX" = xyes; then - if test "x$XACE" != xyes; then - AC_MSG_ERROR([cannot build SELinux extension without X-ACE]) - fi - AC_CHECK_HEADERS([libaudit.h], [], AC_MSG_ERROR([SELinux extension requires audit system headers])) - AC_CHECK_LIB(audit, audit_open, [], AC_MSG_ERROR([SELinux extension requires audit system library])) - PKG_CHECK_MODULES([SELINUX], $LIBSELINUX) - SELINUX_LIBS="$SELINUX_LIBS -laudit" - AC_DEFINE(XSELINUX, 1, [Build SELinux extension]) -fi - -AM_CONDITIONAL(XCSECURITY, [test "x$XCSECURITY" = xyes]) -if test "x$XCSECURITY" = xyes; then - if test "x$XACE" != xyes; then - AC_MSG_ERROR([cannot build Security extension without X-ACE]) - fi - AC_DEFINE(XCSECURITY, 1, [Build Security extension]) -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]) - REQUIRED_MODULES="$REQUIRED_MODULES $BIGFONTPROTO" -fi - -AM_CONDITIONAL(DPMSExtension, [test "x$DPMSExtension" = xyes]) -if test "x$DPMSExtension" = xyes; then - AC_DEFINE(DPMSExtension, 1, [Support DPMS extension]) -fi - -if test "x$XCALIBRATE" = xyes && test "$KDRIVE" = yes; then - AC_DEFINE(XCALIBRATE, 1, [Build XCalibrate extension]) - REQUIRED_MODULES="$REQUIRED_MODULES $XCALIBRATEPROTO" -else - XCALIBRATE=no -fi -AM_CONDITIONAL(XCALIBRATE, [test "x$XCALIBRATE" = xyes]) - -AC_DEFINE(RENDER, 1, [Support RENDER extension]) -RENDER_LIB='$(top_builddir)/render/librender.la' -RENDER_INC='-I$(top_srcdir)/render' - -AC_DEFINE(RANDR, 1, [Support RANDR extension]) -RANDR_LIB='$(top_builddir)/randr/librandr.la' -RANDR_INC='-I$(top_srcdir)/randr' - -AC_DEFINE(XFIXES,1,[Support XFixes extension]) -FIXES_LIB='$(top_builddir)/xfixes/libxfixes.la' -FIXES_INC='-I$(top_srcdir)/xfixes' - -AC_DEFINE(DAMAGE,1,[Support Damage extension]) -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' - -# XINPUT extension is integral part of the server -AC_DEFINE(XINPUT, 1, [Support X Input extension]) -XI_LIB='$(top_builddir)/Xi/libXi.la' -XI_INC='-I$(top_srcdir)/Xi' - -AM_CONDITIONAL(XF86UTILS, test "x$XF86UTILS" = xyes) -AM_CONDITIONAL(XAA, test "x$XAA" = xyes) -AM_CONDITIONAL(VGAHW, test "x$VGAHW" = xyes) -AM_CONDITIONAL(VBE, test "x$VBE" = xyes) -AM_CONDITIONAL(INT10MODULE, test "x$INT10MODULE" = xyes) - -AC_DEFINE(SHAPE, 1, [Support SHAPE extension]) - -AC_DEFINE_DIR(XKB_BASE_DIRECTORY, XKBPATH, [Path to XKB data]) -AC_ARG_WITH(xkb-bin-directory, - AS_HELP_STRING([--with-xkb-bin-directory=DIR], [Directory containing xkbcomp program]), - [XKB_BIN_DIRECTORY="$withval"], - [XKB_BIN_DIRECTORY="$bindir"]) - -AC_DEFINE_DIR(XKB_BIN_DIRECTORY, XKB_BIN_DIRECTORY, [Path to XKB bin dir]) - -dnl Make sure XKM_OUTPUT_DIR is an absolute path -XKBOUTPUT_FIRSTCHAR=`echo $XKBOUTPUT | cut -b 1` -if [[ x$XKBOUTPUT_FIRSTCHAR != x/ -a x$XKBOUTPUT_FIRSTCHAR != 'x$' ]] ; then - XKBOUTPUT="$XKB_BASE_DIRECTORY/$XKBOUTPUT" -fi - -dnl XKM_OUTPUT_DIR (used in code) must end in / or file names get hosed -dnl XKB_COMPILED_DIR (used in Makefiles) must not or install-sh gets confused - -XKBOUTPUT=`echo $XKBOUTPUT/ | $SED 's|/*$|/|'` -XKB_COMPILED_DIR=`echo $XKBOUTPUT | $SED 's|/*$||'` -AC_DEFINE_DIR(XKM_OUTPUT_DIR, XKBOUTPUT, [Path to XKB output dir]) -AC_SUBST(XKB_COMPILED_DIR) - -if test "x$XKB_DFLT_RULES" = x; then - case $host_os in - linux*) - dnl doesn't take AutoAddDevices into account, but whatever. - if test "x$CONFIG_HAL" = xyes; then - XKB_DFLT_RULES="evdev" - else - XKB_DFLT_RULES="base" - fi - ;; - *) - XKB_DFLT_RULES="base" - ;; - esac -fi -AC_DEFINE_UNQUOTED(XKB_DFLT_RULES, ["$XKB_DFLT_RULES"], [Default XKB ruleset]) -AC_DEFINE_UNQUOTED(XKB_DFLT_MODEL, ["$XKB_DFLT_MODEL"], [Default XKB model]) -AC_DEFINE_UNQUOTED(XKB_DFLT_LAYOUT, ["$XKB_DFLT_LAYOUT"], [Default XKB layout]) -AC_DEFINE_UNQUOTED(XKB_DFLT_VARIANT, ["$XKB_DFLT_VARIANT"], [Default XKB variant]) -AC_DEFINE_UNQUOTED(XKB_DFLT_OPTIONS, ["$XKB_DFLT_OPTIONS"], [Default XKB options]) - -XKB_LIB='$(top_builddir)/xkb/libxkb.la' -XKB_STUB_LIB='$(top_builddir)/xkb/libxkbstubs.la' -REQUIRED_MODULES="$REQUIRED_MODULES xkbfile" - -AC_CHECK_FUNC(strcasecmp, [], AC_DEFINE([NEED_STRCASECMP], 1, - [Do not have 'strcasecmp'.])) -AC_CHECK_FUNC(strncasecmp, [], AC_DEFINE([NEED_STRNCASECMP], 1, - [Do not have 'strncasecmp'.])) -AC_CHECK_FUNC(strcasestr, [], AC_DEFINE([NEED_STRCASESTR], 1, - [Do not have 'strcasestr'.])) - -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 - -AC_DEFINE_DIR(COMPILEDDEFAULTFONTPATH, FONTPATH, [Default font path]) -AC_DEFINE_DIR(PCI_TXT_IDS_PATH, PCI_TXT_IDS_DIR, [Default PCI text file ID path]) -AC_DEFINE_DIR(SERVER_MISC_CONFIG_PATH, SERVERCONFIG, [Server miscellaneous config path]) -AC_DEFINE_DIR(BASE_FONT_PATH, FONTROOTDIR, [Default base font path]) -AC_DEFINE_DIR(DRI_DRIVER_PATH, DRI_DRIVER_PATH, [Default DRI driver path]) -AC_DEFINE_UNQUOTED(XVENDORNAME, ["$VENDOR_NAME"], [Vendor name]) -AC_DEFINE_UNQUOTED(XVENDORNAMESHORT, ["$VENDOR_NAME_SHORT"], [Short vendor name]) -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]) - -if test -z "$OSNAME"; then - OSNAME="UNKNOWN" -fi - -AC_DEFINE_UNQUOTED(OSNAME, ["$OSNAME"], [Operating System Name]) -AC_DEFINE_UNQUOTED(OSVENDOR, ["$OSVENDOR"], [Operating System Vendor]) -AC_DEFINE_UNQUOTED(BUILDERSTRING, ["$BUILDERSTRING"], [Builder string]) - -AC_SUBST([VENDOR_NAME_SHORT]) -AC_DEFINE_UNQUOTED(VENDOR_NAME, ["$VENDOR_NAME"], [Vendor name]) -AC_DEFINE_UNQUOTED(VENDOR_NAME_SHORT, ["$VENDOR_NAME_SHORT"], [Vendor name]) -AC_DEFINE_UNQUOTED(VENDOR_RELEASE, [$VENDOR_RELEASE], [Vendor release]) -AC_DEFINE_UNQUOTED(VENDOR_MAN_VERSION, ["$VENDOR_MAN_VERSION"], [Vendor man version]) - -AC_DEFINE(NO_LIBCWRAPPER, 1, [Define to 1 if modules should avoid the libcwrapper]) - -if test "x$DEBUGGING" = xyes; then - AC_DEFINE(DEBUG, 1, [Enable debugging code]) -fi -AM_CONDITIONAL(DEBUG, [test "x$DEBUGGING" = xyes]) - -# If unittests aren't explicitly disabled, check for required support -if test "x$UNITTESTS" != xno ; then - PKG_CHECK_MODULES([GLIB], $LIBGLIB, - [HAVE_GLIB=yes], [HAVE_GLIB=no]) - - # Check if linker supports -wrap, passed via compiler flags - # When cross-compiling, reports no, since unit tests run from - # "make check", so would be running on build machine, not target - AC_MSG_CHECKING([whether the linker supports -wrap]) - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -Wl,-wrap,exit" - AC_RUN_IFELSE([AC_LANG_PROGRAM([[ - void __wrap_exit (int s) - { - __real_exit (0); - }]], - [[exit (1);]])], - [linker_can_wrap="yes"], - [linker_can_wrap="no"], - [linker_can_wrap="no"]) - AC_MSG_RESULT([$linker_can_wrap]) - LDFLAGS="$save_LDFLAGS" -fi - -if test "x$UNITTESTS" = xauto; then - if test "x$HAVE_GLIB" = xyes && test "x$linker_can_wrap" = xyes; then - UNITTESTS=yes - else - UNITTESTS=no - fi -fi -if test "x$UNITTESTS" = xyes; then - if test "x$HAVE_GLIB" = xno; then - AC_MSG_ERROR([glib required to build unit tests]) - fi - if test "x$linker_can_wrap" = xno; then - AC_MSG_ERROR([ld -wrap support required to build unit tests]) - fi - AC_DEFINE(UNITTESTS, 1, [Enable unit tests]) - AC_SUBST([GLIB_LIBS]) - AC_SUBST([GLIB_CFLAGS]) -fi -AM_CONDITIONAL(UNITTESTS, [test "x$UNITTESTS" = xyes]) - -AC_DEFINE(XTEST, 1, [Support XTest extension]) -AC_DEFINE(XSYNC, 1, [Support XSync extension]) -AC_DEFINE(XCMISC, 1, [Support XCMisc extension]) -AC_DEFINE(BIGREQS, 1, [Support BigRequests extension]) - -if test "x$SPECIAL_DTRACE_OBJECTS" = "xyes" ; then - DIX_LIB='$(top_builddir)/dix/dix.O' - OS_LIB='$(top_builddir)/os/os.O $(SHA1_LIBS)' -else - DIX_LIB='$(top_builddir)/dix/libdix.la' - OS_LIB='$(top_builddir)/os/libos.la' -fi -AC_SUBST([DIX_LIB]) -AC_SUBST([OS_LIB]) - -MAIN_LIB='$(top_builddir)/dix/libmain.la' -AC_SUBST([MAIN_LIB]) - -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' - -# SHA1 hashing -AC_ARG_WITH([sha1], - [AS_HELP_STRING([--with-sha1=libc|libmd|libgcrypt|libcrypto|libsha1|CommonCrypto], - [choose SHA1 implementation])]) -AC_CHECK_FUNC([SHA1Init], [HAVE_SHA1_IN_LIBC=yes]) -if test "x$with_sha1" = x && test "x$HAVE_SHA1_IN_LIBC" = xyes; then - with_sha1=libc -fi -if test "x$with_sha1" = xlibc && test "x$HAVE_SHA1_IN_LIBC" != xyes; then - AC_MSG_ERROR([libc requested but not found]) -fi -if test "x$with_sha1" = xlibc; then - AC_DEFINE([HAVE_SHA1_IN_LIBC], [1], - [Use libc SHA1 functions]) - SHA1_LIBS="" -fi -AC_CHECK_FUNC([CC_SHA1_Init], [HAVE_SHA1_IN_COMMONCRYPTO=yes]) -if test "x$with_sha1" = x && test "x$HAVE_SHA1_IN_COMMONCRYPTO" = xyes; then - with_sha1=CommonCrypto -fi -if test "x$with_sha1" = xCommonCrypto && test "x$HAVE_SHA1_IN_COMMONCRYPTO" != xyes; then - AC_MSG_ERROR([CommonCrypto requested but not found]) -fi -if test "x$with_sha1" = xCommonCrypto; then - AC_DEFINE([HAVE_SHA1_IN_COMMONCRYPTO], [1], - [Use CommonCrypto SHA1 functions]) - SHA1_LIBS="" -fi -AC_CHECK_LIB([md], [SHA1Init], [HAVE_LIBMD=yes]) -if test "x$with_sha1" = x && test "x$HAVE_LIBMD" = xyes; then - with_sha1=libmd -fi -if test "x$with_sha1" = xlibmd && test "x$HAVE_LIBMD" != xyes; then - AC_MSG_ERROR([libmd requested but not found]) -fi -if test "x$with_sha1" = xlibmd; then - AC_DEFINE([HAVE_SHA1_IN_LIBMD], [1], - [Use libmd SHA1 functions]) - SHA1_LIBS=-lmd -fi -AC_CHECK_LIB([sha1], [sha1_begin], [HAVE_LIBSHA1=yes]) -if test "x$with_sha1" = x && test "x$HAVE_LIBSHA1" = xyes; then - with_sha1=libsha1 -fi -if test "x$with_sha1" = xlibsha1 && test "x$HAVE_LIBSHA1" != xyes; then - AC_MSG_ERROR([libsha1 requested but not found]) -fi -if test "x$with_sha1" = xlibsha1; then - AC_DEFINE([HAVE_SHA1_IN_LIBSHA1], [1], - [Use libsha1 for SHA1]) - SHA1_LIBS=-lsha1 -fi -AC_CHECK_LIB([gcrypt], [gcry_md_open], [HAVE_LIBGCRYPT=yes]) -if test "x$with_sha1" = x && test "x$HAVE_LIBGCRYPT" = xyes; then - with_sha1=libgcrypt -fi -if test "x$with_sha1" = xlibgcrypt && test "x$HAVE_LIBGCRYPT" != xyes; then - AC_MSG_ERROR([libgcrypt requested but not found]) -fi -if test "x$with_sha1" = xlibgcrypt; then - AC_DEFINE([HAVE_SHA1_IN_LIBGCRYPT], [1], - [Use libgcrypt SHA1 functions]) - SHA1_LIBS=-lgcrypt -fi -# We don't need all of the OpenSSL libraries, just libcrypto -AC_CHECK_LIB([crypto], [SHA1_Init], [HAVE_LIBCRYPTO=yes]) -PKG_CHECK_MODULES([OPENSSL], [openssl], [HAVE_OPENSSL_PKC=yes], - [HAVE_OPENSSL_PKC=no]) -if test "x$HAVE_LIBCRYPTO" = xyes || test "x$HAVE_OPENSSL_PKC" = xyes; then - if test "x$with_sha1" = x; then - with_sha1=libcrypto - fi -else - if test "x$with_sha1" = xlibcrypto; then - AC_MSG_ERROR([OpenSSL libcrypto requested but not found]) - fi -fi -if test "x$with_sha1" = xlibcrypto; then - if test "x$HAVE_LIBCRYPTO" = xyes; then - SHA1_LIBS=-lcrypto - else - SHA1_LIBS="$OPENSSL_LIBS" - SHA1_CFLAGS="$OPENSSL_CFLAGS" - fi -fi -AC_MSG_CHECKING([for SHA1 implementation]) -if test "x$with_sha1" = x; then - AC_MSG_ERROR([No suitable SHA1 implementation found]) -fi -AC_MSG_RESULT([$with_sha1]) -AC_SUBST(SHA1_LIBS) -AC_SUBST(SHA1_CFLAGS) - -PKG_CHECK_MODULES([XSERVERCFLAGS], [$REQUIRED_MODULES $REQUIRED_LIBS]) -PKG_CHECK_MODULES([XSERVERLIBS], [$REQUIRED_LIBS]) - -# Autotools has some unfortunate issues with library handling. In order to -# get a server to rebuild when a dependency in the tree is changed, it must -# be listed in SERVERNAME_DEPENDENCIES. However, no system libraries may be -# listed there, or some versions of autotools will break (especially if a -L -# is required to find the library). So, we keep two sets of libraries -# detected: NAMESPACE_LIBS for in-tree libraries to be linked against, which -# will go into the _DEPENDENCIES and _LDADD of the server, and -# NAMESPACE_SYS_LIBS which will go into only the _LDADD. The -# NAMESPACEMODULES_LIBS detected from pkgconfig should always go in -# NAMESPACE_SYS_LIBS. -# -# XSERVER_LIBS is the set of in-tree libraries which all servers require. -# XSERVER_SYS_LIBS is the set of out-of-tree libraries which all servers -# require. -# -XSERVER_CFLAGS="${XSERVER_CFLAGS} ${XSERVERCFLAGS_CFLAGS}" -XSERVER_LIBS="$DIX_LIB $CONFIG_LIB $MI_LIB $OS_LIB" -XSERVER_SYS_LIBS="${XSERVERLIBS_LIBS} ${SYS_LIBS} ${LIBS}" -AC_SUBST([XSERVER_LIBS]) -AC_SUBST([XSERVER_SYS_LIBS]) - -UTILS_SYS_LIBS="${SYS_LIBS}" -AC_SUBST([UTILS_SYS_LIBS]) - -# The Xorg binary needs to export symbols so that they can be used from modules -# Some platforms require extra flags to do this. libtool should set the -# necessary flags for each platform when -export-dynamic is passed to it. -LD_EXPORT_SYMBOLS_FLAG="-export-dynamic" -AC_SUBST([LD_EXPORT_SYMBOLS_FLAG]) - -dnl Imake defines SVR4 on SVR4 systems, and many files check for it, so -dnl we need to replicate that here until those can all be fixed -AC_MSG_CHECKING([if SVR4 needs to be defined]) -AC_EGREP_CPP([I_AM_SVR4],[ -#if defined(SVR4) || defined(__svr4__) || defined(__SVR4) - I_AM_SVR4 -#endif -],[ -AC_DEFINE([SVR4],1,[Define to 1 on systems derived from System V Release 4]) -AC_MSG_RESULT([yes])], AC_MSG_RESULT([no])) - -XSERVER_CFLAGS="$XSERVER_CFLAGS $CORE_INCS $XEXT_INC $COMPOSITE_INC $DAMAGE_INC $FIXES_INC $XI_INC $MI_INC $MIEXT_SHADOW_INC $MIEXT_LAYER_INC $MIEXT_DAMAGE_INC $RENDER_INC $RANDR_INC $FB_INC" - -dnl --------------------------------------------------------------------------- -dnl DDX section. -dnl --------------------------------------------------------------------------- - -dnl Xvfb DDX - -AC_MSG_CHECKING([whether to build Xvfb DDX]) -AC_MSG_RESULT([$XVFB]) -AM_CONDITIONAL(XVFB, [test "x$XVFB" = xyes]) - -if test "x$XVFB" = xyes; then - XVFB_LIBS="$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB" - XVFB_SYS_LIBS="$XVFBMODULES_LIBS $GLX_SYS_LIBS" - AC_SUBST([XVFB_LIBS]) - AC_SUBST([XVFB_SYS_LIBS]) -fi - - -dnl Xnest DDX - -PKG_CHECK_MODULES(XNESTMODULES, [xfont $LIBXEXT x11 xau $XDMCP_MODULES], [have_xnest=yes], [have_xnest=no]) -AC_MSG_CHECKING([whether to build Xnest DDX]) -if test "x$XNEST" = xauto; then - XNEST="$have_xnest" -fi -AC_MSG_RESULT([$XNEST]) -AM_CONDITIONAL(XNEST, [test "x$XNEST" = xyes]) - -if test "x$XNEST" = xyes; then - if test "x$have_xnest" = xno; then - AC_MSG_ERROR([Xnest build explicitly requested, but required modules not found.]) - fi - XNEST_LIBS="$FB_LIB $FIXES_LIB $MI_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $DIX_LIB $MAIN_LIB $OS_LIB $CONFIG_LIB" - XNEST_SYS_LIBS="$XNESTMODULES_LIBS $GLX_SYS_LIBS" - AC_SUBST([XNEST_LIBS]) - AC_SUBST([XNEST_SYS_LIBS]) -fi - - -dnl Xorg DDX - -AC_MSG_CHECKING([whether to build Xorg DDX]) -if test "x$XORG" = xauto; then - XORG="yes" - case $host_os in - cygwin*) XORG="no" ;; - darwin*) XORG="no" ;; - esac -fi -AC_MSG_RESULT([$XORG]) - -xorg_bus_linuxpci=no -xorg_bus_bsdpci=no -xorg_bus_sparc=no - -if test "x$XORG" = xyes; then - XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' - XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' - XORG_INCS="$XORG_DDXINCS $XORG_OSINCS" - XORG_CFLAGS="$XORGSERVER_CFLAGS -DHAVE_XORG_CONFIG_H" - XORG_LIBS="$COMPOSITE_LIB $FIXES_LIB $XEXTXORG_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB" - - dnl ================================================================== - dnl symbol visibility - symbol_visibility= - have_visibility=disabled - if test x$SYMBOL_VISIBILITY != xno; then - AC_MSG_CHECKING(for symbol visibility support) - if test x$GCC = xyes; then - VISIBILITY_CFLAGS="-fvisibility=hidden" - else - AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"]) - if test x$SUNCC = xyes; then - VISIBILITY_CFLAGS="-xldscope=hidden" - else - have_visibility=no - fi - fi - if test x$have_visibility != xno; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $VISIBILITY_CFLAGS" - AC_TRY_COMPILE( - [#include - extern _X_HIDDEN int hidden_int; - extern _X_EXPORT int public_int; - extern _X_HIDDEN int hidden_int_func(void); - extern _X_EXPORT int public_int_func(void);], - [], - have_visibility=yes, - have_visibility=no) - CFLAGS=$save_CFLAGS - fi - AC_MSG_RESULT([$have_visibility]) - if test x$have_visibility != xno; then - symbol_visibility=$VISIBILITY_CFLAGS - XORG_CFLAGS="$XORG_CFLAGS $VISIBILITY_CFLAGS" - XSERVER_CFLAGS="$XSERVER_CFLAGS $VISIBILITY_CFLAGS" - fi - fi - dnl added to xorg-server.pc - AC_SUBST([symbol_visibility]) - dnl =================================================================== - - PKG_CHECK_MODULES([PCIACCESS], $LIBPCIACCESS) - SAVE_LIBS=$LIBS - SAVE_CFLAGS=$CFLAGS - CFLAGS=$PCIACCESS_CFLAGS - LIBS=$PCIACCESS_LIBS - AC_CHECK_FUNCS([pci_system_init_dev_mem]) - AC_CHECK_FUNCS([pci_device_enable]) - AC_CHECK_FUNCS([pci_device_is_boot_vga]) - AC_CHECK_FUNCS([pci_device_vgaarb_init]) - LIBS=$SAVE_LIBS - CFLAGS=$SAVE_CFLAGS - XORG_SYS_LIBS="$XORG_SYS_LIBS $PCIACCESS_LIBS $GLX_SYS_LIBS" - XORG_CFLAGS="$XORG_CFLAGS $PCIACCESS_CFLAGS" - - case $host_os in - linux*) - if test "x$LNXAPM" = xyes; then - XORG_CFLAGS="$XORG_CFLAGS -DXF86PM" - fi - XORG_OS="linux" - XORG_OS_SUBDIR="linux" - xorg_bus_linuxpci="yes" - linux_acpi="no" - case $host_cpu in - ia64*) - linux_ia64=yes - linux_acpi="yes" - ;; - alpha*) - linux_alpha=yes - ;; - i*86|amd64*|x86_64*) - linux_acpi="yes" - ;; - *) - ;; - esac - ;; - freebsd* | kfreebsd*-gnu | dragonfly*) - XORG_OS="freebsd" - XORG_OS_SUBDIR="bsd" - xorg_bus_bsdpci="yes" - ;; - netbsd*) - XORG_OS="netbsd" - XORG_OS_SUBDIR="bsd" - xorg_bus_bsdpci="yes" - ;; - openbsd*) - if test "x$ac_cv_BSD_APM" = xyes \ - -o "x$ac_cv_BSD_KQUEUE_APM" = xyes; then - XORG_CFLAGS="$XORG_CFLAGS -DXF86PM" - fi - XORG_OS="openbsd" - XORG_OS_SUBDIR="bsd" - xorg_bus_bsdpci="yes" - ;; - solaris*) - XORG_OS="solaris" - XORG_OS_SUBDIR="solaris" - XORG_CFLAGS="$XORG_CFLAGS -DXF86PM" - # Use the same stubs as BSD for old functions, since we now - # use libpciaccess for PCI - xorg_bus_bsdpci="yes" - AC_CHECK_HEADERS([sys/kd.h]) - AC_CHECK_HEADERS([sys/vt.h], [solaris_vt=yes], [solaris_vt=no]) - # Check for minimum supported release - AC_MSG_CHECKING([Solaris version]) - OS_MINOR=`echo ${host_os}|$SED -e 's/^.*solaris2\.//' -e s'/\..*$//'` - if test "${OS_MINOR}" -ge 7 ; then - AC_MSG_RESULT(Solaris ${OS_MINOR}) - else - AC_MSG_RESULT(Solaris `echo ${host_os}|$SED -e 's/^.*solaris//`) - fi - if test "${OS_MINOR}" -lt 8 ; then - AC_MSG_ERROR([This release no longer supports Solaris versions older than Solaris 8.]) - fi - AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"]) - if test "x$SUNCC" = "xyes"; then - solaris_asm_inline="yes" - fi - AC_CHECK_DECL([_LP64], [SOLARIS_64="yes"], [SOLARIS_64="no"]) - - case $host_cpu in - sparc*) - SOLARIS_INOUT_ARCH="sparcv8plus" - ;; - i*86) - if test x$SOLARIS_64 = xyes ; then - SOLARIS_INOUT_ARCH="amd64" - else - SOLARIS_INOUT_ARCH="ia32" - fi - ;; - *) - AC_MSG_ERROR([Unsupported Solaris platform. Only SPARC & x86 \ - are supported on Solaris in this release. If you are \ - interested in porting Xorg to your platform, please email \ - xorg@lists.freedesktop.org.]) ;; - esac - AC_SUBST([SOLARIS_INOUT_ARCH]) - if test x$solaris_asm_inline = xyes ; then - SOLARIS_ASM_CFLAGS='$(top_srcdir)/hw/xfree86/os-support/solaris/solaris-$(SOLARIS_INOUT_ARCH).il' - XORG_CFLAGS="${XORG_CFLAGS} "'$(SOLARIS_ASM_CFLAGS)' - fi - AC_SUBST([SOLARIS_ASM_CFLAGS]) - if test "x$SUPPORT_PC98" = xauto; then - SUPPORT_PC98="no" - fi - ;; - gnu*) - XORG_OS="gnu" - XORG_OS_SUBDIR="hurd" - # Use the same stubs as BSD for old functions, since we now - # use libpciaccess for PCI - xorg_bus_bsdpci="yes" - ;; - *) - XORG_OS="unknown" - XORG_OS_SUBDIR="unknown" - AC_MSG_ERROR([Your OS is unknown. Xorg currently only supports Linux, \ - Free/Open/NetBSD, Solaris, and OS X. If you are interested in porting \ - Xorg to your platform, please email xorg@lists.freedesktop.org.]) - ;; - esac - - case $host_cpu in - sparc*) - xorg_bus_sparc="yes" - ;; - i*86) - if test "x$SUPPORT_PC98" = xauto; then - SUPPORT_PC98="yes" - fi - ;; - esac - - if test "x$SUPPORT_PC98" = xauto; then - SUPPORT_PC98="no" - fi - if test "x$SUPPORT_PC98" = xyes; then - AC_DEFINE(SUPPORT_PC98, 1, [Support PC98]) - fi - if test "x$XORG_OS_PCI" = x ; then - XORG_OS_PCI=$XORG_OS - fi - if test "x$DGA" = xauto; then - PKG_CHECK_MODULES(DGA, $DGAPROTO, [DGA=yes], [DGA=no]) - fi - if test "x$DGA" = xyes; then - XORG_MODULES="$XORG_MODULES $DGAPROTO" - PKG_CHECK_MODULES(DGA, $DGAPROTO) - AC_DEFINE(DGA, 1, [Support DGA extension]) - AC_DEFINE(XFreeXDGA, 1, [Build XDGA support]) - fi - - if test "x$XF86VIDMODE" = xauto; then - PKG_CHECK_MODULES(XF86VIDMODE, $VIDMODEPROTO, [XF86VIDMODE=yes], [XF86VIDMODE=no]) - fi - if test "x$XF86VIDMODE" = xyes; then - XORG_MODULES="$XORG_MODULES $VIDMODEPROTO" - PKG_CHECK_MODULES(XF86VIDMODE, $VIDMODEPROTO) - AC_DEFINE(XF86VIDMODE, 1, [Support XFree86 Video Mode extension]) - fi - - if test -n "$XORG_MODULES"; then - PKG_CHECK_MODULES(XORG_MODULES, [$XORG_MODULES]) - XORG_CFLAGS="$XORG_CFLAGS $XORG_MODULES_CFLAGS" - XORG_SYS_LIBS="$XORG_SYS_LIBS $XORG_MODULES_LIBS" - fi - - AC_SUBST([XORG_LIBS]) - AC_SUBST([XORG_SYS_LIBS]) - AC_SUBST([XORG_INCS]) - AC_SUBST([XORG_OS]) - AC_SUBST([XORG_OS_SUBDIR]) - - AC_PATH_PROG(PERL, perl, no) - dnl unlikely as this may be ... - if test "x$PERL" = xno; then - AC_MSG_ERROR([Perl is required to build the XFree86/Xorg DDX.]) - fi - AC_SUBST(PERL) - - AC_SUBST([XORG_CFLAGS]) - - dnl these only go in xorg-config.h - XF86CONFIGFILE="xorg.conf" - XF86CONFIGDIR="xorg.conf.d" - AC_SUBST(XF86CONFIGDIR) - CONFIGFILE="$sysconfdir/$XF86CONFIGFILE" - LOGPREFIX="$logdir/Xorg." - AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) - AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) - AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) - AC_DEFINE(XFree86LOADER, 1, [Building loadable XFree86 server]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) - AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) - AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) - AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) - AC_DEFINE_DIR(__XCONFIGFILE__, XF86CONFIGFILE, [Name of configuration file]) - AC_DEFINE_DIR(XF86CONFIGFILE, XF86CONFIGFILE, [Name of configuration file]) - AC_DEFINE_DIR(__XCONFIGDIR__, XF86CONFIGDIR, [Name of configuration directory]) - AC_DEFINE_DIR(DEFAULT_MODULE_PATH, moduledir, [Default module search path]) - AC_DEFINE_DIR(DEFAULT_LIBRARY_PATH, libdir, [Default library install path]) - AC_DEFINE_DIR(DEFAULT_LOGPREFIX, LOGPREFIX, [Default log location]) - AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support]) - AC_DEFINE(XSERVER_LIBPCIACCESS, 1, [Use libpciaccess for all pci manipulation]) - if test "x$VGAHW" = xyes; then - AC_DEFINE(WITH_VGAHW, 1, [Building vgahw module]) - fi - - driverdir="$moduledir/drivers" - AC_SUBST([moduledir]) - AC_SUBST([driverdir]) - sdkdir="$includedir/xorg" - extdir="$includedir/X11/extensions" - sysconfigdir="$datadir/X11/$XF86CONFIGDIR" - AC_SUBST([sdkdir]) - AC_SUBST([extdir]) - AC_SUBST([sysconfigdir]) - AC_SUBST([logdir]) - - # stuff the ABI versions into the pc file too - extract_abi() { - grep ^.define.*${1}_VERSION ${srcdir}/hw/xfree86/common/xf86Module.h | tr '(),' ' .' | awk '{ print $4$5 }' - } - abi_ansic=`extract_abi ANSIC` - abi_videodrv=`extract_abi VIDEODRV` - abi_xinput=`extract_abi XINPUT` - abi_extension=`extract_abi EXTENSION` - AC_SUBST([abi_ansic]) - AC_SUBST([abi_videodrv]) - AC_SUBST([abi_xinput]) - AC_SUBST([abi_extension]) -fi -AM_CONDITIONAL([XORG], [test "x$XORG" = xyes]) -AM_CONDITIONAL([XORG_BUS_LINUXPCI], [test "x$xorg_bus_linuxpci" = xyes]) -AM_CONDITIONAL([XORG_BUS_BSDPCI], [test "x$xorg_bus_bsdpci" = xyes]) -AM_CONDITIONAL([XORG_BUS_SPARC], [test "x$xorg_bus_sparc" = 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]) -AM_CONDITIONAL([SOLARIS_ASM_INLINE], [test "x$solaris_asm_inline" = xyes]) -AM_CONDITIONAL([SOLARIS_VT], [test "x$solaris_vt" = xyes]) -AM_CONDITIONAL([DGA], [test "x$DGA" = xyes]) -AM_CONDITIONAL([XF86VIDMODE], [test "x$XF86VIDMODE" = xyes]) - -dnl XWin DDX - -AC_MSG_CHECKING([whether to build XWin DDX]) -if test "x$XWIN" = xauto; then - case $host_os in - cygwin*) XWIN="yes" ;; - mingw*) XWIN="yes" ;; - *) XWIN="no" ;; - esac -fi -AC_MSG_RESULT([$XWIN]) - -if test "x$XWIN" = xyes; then - AC_DEFINE_DIR(SYSCONFDIR, sysconfdir, [Location of system.XWinrc]) - AC_DEFINE_DIR(DEFAULT_LOGDIR, logdir, [Default log location]) - AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) - AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support]) - AC_CHECK_TOOL(WINDRES, windres) - - PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau xfont]) - - if test "x$WINDOWSWM" = xauto; then - PKG_CHECK_EXISTS($WINDOWSWMPROTO, [WINDOWSWM=yes], [WINDOWSWM=no]) - fi - if test "x$WINDOWSWM" = xyes ; then - PKG_CHECK_MODULES(WINDOWSWM, $WINDOWSWMPROTO) - XWINMODULES_CFLAGS="$XWINMODULES_CFLAGS $WINDOWSWM_CFLAGS" - AC_DEFINE(ROOTLESS,1,[Build Rootless code]) - fi - - case $host_os in - cygwin*) - XWIN_SERVER_NAME=XWin - AC_DEFINE(HAS_DEVWINDOWS,1,[Cygwin has /dev/windows for signaling new win32 messages]) - ;; - mingw*) - XWIN_SERVER_NAME=Xming - AC_DEFINE(RELOCATE_PROJECTROOT,1,[Make PROJECT_ROOT relative to the xserver location]) - AC_DEFINE(HAS_WINSOCK,1,[Use Windows sockets]) - XWIN_SYS_LIBS=-lwinsock2 - ;; - esac - XWIN_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $RANDR_LIB $RENDER_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $OS_LIB" - XWIN_SYS_LIBS="$XWIN_SYS_LIBS $XWINMODULES_LIBS" - AC_SUBST(XWIN_LIBS) - AC_SUBST(XWIN_SERVER_NAME) - AC_SUBST(XWIN_SYS_LIBS) - - if test "x$DEBUGGING" = xyes; then - AC_DEFINE(CYGDEBUG, 1, [Simple debug messages]) - AC_DEFINE(CYGWINDOWING_DEBUG, 1, [Debug messages for window handling]) - AC_DEFINE(CYGMULTIWINDOW_DEBUG, 1, [Debug window manager]) - fi - - AC_DEFINE(DDXOSVERRORF, 1, [Use OsVendorVErrorF]) - AC_DEFINE(DDXBEFORERESET, 1, [Use ddxBeforeReset ]) -fi -AM_CONDITIONAL(XWIN, [test "x$XWIN" = xyes]) -AM_CONDITIONAL(XWIN_MULTIWINDOW, [test "x$XWIN" = xyes]) -AM_CONDITIONAL(XWIN_MULTIWINDOWEXTWM, [test "x$XWIN" = xyes && test "x$WINDOWSWM" = xyes]) -AM_CONDITIONAL(XWIN_CLIPBOARD, [test "x$XWIN" = xyes]) -AM_CONDITIONAL(XWIN_GLX_WINDOWS, [test "x$XWIN" = xyes && false]) -AM_CONDITIONAL(XWIN_NATIVEGDI, [test "x$XWIN" = xyes && false]) -AM_CONDITIONAL(XWIN_PRIMARYFB, [test "x$XWIN" = xyes && false]) -AM_CONDITIONAL(XWIN_RANDR, [test "x$XWIN" = xyes]) -AM_CONDITIONAL(XWIN_XV, [test "x$XWIN" = xyes && test "x$XV" = xyes]) - -dnl Darwin / OS X DDX -if test "x$XQUARTZ" = xyes; then - AC_DEFINE(XQUARTZ,1,[Have Quartz]) - AC_DEFINE(ROOTLESS,1,[Build Rootless code]) - - DARWIN_LIBS="$MI_LIB $OS_LIB $DIX_LIB $MAIN_LIB $FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $XPSTUBS_LIB" - AC_SUBST([DARWIN_LIBS]) - - AC_CHECK_LIB([Xplugin],[xp_init],[:]) - - CFLAGS="${CFLAGS} -DROOTLESS_WORKAROUND -DROOTLESS_SAFEALPHA -DNO_ALLOCA" - - PKG_CHECK_MODULES(XPBPROXY, $APPLEWMPROTO $LIBAPPLEWM xfixes x11) - - if test "x$XQUARTZ_SPARKLE" = xyes ; then - AC_DEFINE(XQUARTZ_SPARKLE,1,[Support application updating through sparkle.]) - fi - - if test "x$STANDALONE_XPBPROXY" = xyes ; then - AC_DEFINE(STANDALONE_XPBPROXY,1,[Build a standalone xpbproxy]) - fi -fi - -# Support for objc in autotools is minimal and not documented. -OBJC='$(CC)' -OBJCLD='$(CCLD)' -OBJCLINK='$(LINK)' -OBJCFLAGS='$(CFLAGS)' -AC_SUBST([OBJC]) -AC_SUBST([OBJCCLD]) -AC_SUBST([OBJCLINK]) -AC_SUBST([OBJCFLAGS]) -# internal, undocumented automake func follows :( -_AM_DEPENDENCIES([OBJC]) -AM_CONDITIONAL(XQUARTZ, [test "x$XQUARTZ" = xyes]) -AM_CONDITIONAL(XQUARTZ_SPARKLE, [test "x$XQUARTZ_SPARKLE" != "xno"]) -AM_CONDITIONAL(STANDALONE_XPBPROXY, [test "x$STANDALONE_XPBPROXY" = xyes]) - -dnl DMX DDX -PKG_CHECK_MODULES( - [DMXMODULES], - [xmuu $LIBXEXT x11 xrender xfixes xfont $LIBXI $DMXPROTO xau $XDMCP_MODULES], - [PKG_CHECK_MODULES( - [XDMXCONFIG_DEP], - [xaw7 xmu xt xpm x11], - [have_dmx=yes], - [have_dmx=no])], - [have_dmx=no]) -AC_MSG_CHECKING([whether to build Xdmx DDX]) -if test "x$DMX" = xauto; then - DMX="$have_dmx" - case $host_os in - cygwin*) DMX="no" ;; - darwin*) DMX="no" ;; - esac -fi -AC_MSG_RESULT([$DMX]) -AM_CONDITIONAL(DMX, [test "x$DMX" = xyes]) - -if test "x$DMX" = xyes; then - if test "x$have_dmx" = xno; then - AC_MSG_ERROR([Xdmx build explicitly requested, but required - modules not found.]) - fi - DMX_INCLUDES="$XEXT_INC $RENDER_INC $RECORD_INC" - XDMX_CFLAGS="$DMXMODULES_CFLAGS" - XDMX_LIBS="$FB_LIB $MI_LIB $RENDER_LIB $RECORD_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $MIEXT_SHADOW_LIB $MIEXT_DAMAGE_LIB $XEXT_LIB $MAIN_LIB $DIX_LIB $CONFIG_LIB $OS_LIB $FIXES_LIB" - XDMX_SYS_LIBS="$DMXMODULES_LIBS" - AC_SUBST([XDMX_CFLAGS]) - AC_SUBST([XDMX_LIBS]) - AC_SUBST([XDMX_SYS_LIBS]) - -dnl USB sources in DMX require - AC_CHECK_HEADER([linux/input.h], DMX_BUILD_USB="yes", - DMX_BUILD_USB="no") -dnl Linux sources in DMX require - AC_CHECK_HEADER([linux/keyboard.h], DMX_BUILD_LNX="yes", - DMX_BUILD_LNX="no") - AC_SUBST(XDMXCONFIG_DEP_CFLAGS) - AC_SUBST(XDMXCONFIG_DEP_LIBS) - PKG_CHECK_MODULES([DMXEXAMPLES_DEP], [$LIBDMX $LIBXEXT x11]) - AC_SUBST(DMXEXAMPLES_DEP_LIBS) - PKG_CHECK_MODULES([DMXXMUEXAMPLES_DEP], [$LIBDMX xmu $LIBXEXT x11]) - AC_SUBST(DMXXMUEXAMPLES_DEP_LIBS) - PKG_CHECK_MODULES([DMXXIEXAMPLES_DEP], [$LIBDMX $LIBXI $LIBXEXT x11]) - AC_SUBST(DMXXIEXAMPLES_DEP_LIBS) - PKG_CHECK_MODULES([XTSTEXAMPLES_DEP], [$LIBXTST $LIBXEXT x11]) - AC_SUBST(XTSTEXAMPLES_DEP_LIBS) - PKG_CHECK_MODULES([XRESEXAMPLES_DEP], [xres $LIBXEXT x11]) - AC_SUBST(XRESEXAMPLES_DEP_LIBS) - PKG_CHECK_MODULES([X11EXAMPLES_DEP], [$LIBXEXT x11]) - AC_SUBST(X11EXAMPLES_DEP_LIBS) - -fi -AM_CONDITIONAL([DMX_BUILD_LNX], [test "x$DMX_BUILD_LNX" = xyes]) -AM_CONDITIONAL([DMX_BUILD_USB], [test "x$DMX_BUILD_USB" = xyes]) - -dnl kdrive DDX - -XEPHYR_LIBS= -XEPHYR_INCS= - -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([linux/fb.h]) - if test "$ac_cv_header_linux_fb_h" = yes && test "x$XFBDEV" = xauto; then - XFBDEV=yes - fi - - if test "x$XFBDEV" = xyes; then - KDRIVEFBDEVLIB=yes - AC_DEFINE(KDRIVEFBDEV, 1, [Build fbdev-based kdrive server]) - fi - - - PKG_CHECK_MODULES([TSLIB], [tslib-0.0], [HAVE_TSLIB="yes"], [HAVE_TSLIB="no"]) - if test "x$HAVE_TSLIB" = xno; then - AC_CHECK_LIB(ts, ts_open, [HAVE_TSLIB="yes"]) - fi - - if test "xTSLIB" = xauto; then - TSLIB="$HAVE_TSLIB" - fi - - if test "x$TSLIB" = xyes; then - if ! test "x$HAVE_TSLIB" = xyes; then - AC_MSG_ERROR([tslib must be installed to build the tslib driver. See http://tslib.berlios.de/]) - else - AC_DEFINE(TSLIB, 1, [Have tslib support]) - fi - fi - - if test "x$KDRIVE_KBD" = xyes; then - AC_DEFINE(KDRIVE_KBD, 1, [Enable KDrive kbd driver]) - fi - if test "x$KDRIVE_EVDEV" = xyes; then - AC_DEFINE(KDRIVE_EVDEV, 1, [Enable KDrive evdev driver]) - fi - if test "x$KDRIVE_MOUSE" = xyes; then - AC_DEFINE(KDRIVE_MOUSE, 1, [Enable KDrive mouse driver]) - fi - - XEPHYR_REQUIRED_LIBS="x11 $LIBXEXT xfont xau xdmcp" - if test "x$XV" = xyes; then - XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xv" - fi - if test "x$DRI" = xyes && test "x$GLX" = xyes; then - XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS $LIBGL libdrm" - fi - - PKG_CHECK_MODULES(XEPHYR, $XEPHYR_REQUIRED_LIBS, [xephyr="yes"], [xephyr="no"]) - if test "x$XEPHYR" = xauto; then - XEPHYR=$xephyr - fi - - # Xephyr needs nanosleep() which is in librt on Solaris - AC_CHECK_FUNC([nanosleep], [], - AC_CHECK_LIB([rt], [nanosleep], XEPHYR_LIBS="$XEPHYR_LIBS -lrt")) - - # damage shadow extension glx (NOTYET) fb mi - KDRIVE_INC='-I$(top_srcdir)/hw/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)/hw/kdrive/linux' - KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" - - KDRIVE_CFLAGS="$XSERVER_CFLAGS -DHAVE_KDRIVE_CONFIG_H $TSLIB_CFLAGS" - - KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" - KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' - case $host_os in - *linux*) - KDRIVE_OS_LIB='$(top_builddir)/hw/kdrive/linux/liblinux.la' - KDRIVELINUX=yes - if test "x$KDRIVE_EVDEV" = xauto; then - KDRIVE_EVDEV=yes - fi - if test "x$KDRIVE_KBD" = xauto; then - KDRIVE_KBD=yes - fi - if test "x$KDRIVE_MOUSE" = xauto; then - KDRIVE_MOUSE=yes - fi - ;; - *) - if test "x$KDRIVE_EVDEV" = xauto; then - KDRIVE_EVDEV=no - fi - if test "x$KDRIVE_KBD" = xauto; then - KDRIVE_KBD=no - fi - if test "x$KDRIVE_MOUSE" = xauto; then - KDRIVE_MOUSE=no - fi - ;; - esac - KDRIVE_STUB_LIB='$(top_builddir)/hw/kdrive/src/libkdrivestubs.la' - KDRIVE_LOCAL_LIBS="$MAIN_LIB $DIX_LIB $KDRIVE_LIB $KDRIVE_STUB_LIB $CONFIG_LIB" - KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" - KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB $OS_LIB" - KDRIVE_LIBS="$TSLIB_LIBS $KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" - - AC_SUBST([XEPHYR_LIBS]) - AC_SUBST([XEPHYR_INCS]) -fi -AC_SUBST([KDRIVE_INCS]) -AC_SUBST([KDRIVE_PURE_INCS]) -AC_SUBST([KDRIVE_CFLAGS]) -AC_SUBST([KDRIVE_PURE_LIBS]) -AC_SUBST([KDRIVE_LOCAL_LIBS]) -AC_SUBST([KDRIVE_LIBS]) -AM_CONDITIONAL(KDRIVELINUX, [test "x$KDRIVELINUX" = xyes]) -AM_CONDITIONAL(KDRIVE_EVDEV, [test "x$KDRIVE_EVDEV" = xyes]) -AM_CONDITIONAL(KDRIVE_KBD, [test "x$KDRIVE_KBD" = xyes]) -AM_CONDITIONAL(KDRIVE_MOUSE, [test "x$KDRIVE_MOUSE" = xyes]) -AM_CONDITIONAL(TSLIB, [test "x$HAVE_TSLIB" = xyes]) -AM_CONDITIONAL(KDRIVEFBDEV, [test "x$XFBDEV" = xyes]) -AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) -AM_CONDITIONAL(BUILD_KDRIVEFBDEVLIB, [test "x$KDRIVE" = xyes && test "x$KDRIVEFBDEVLIB" = xyes]) -AM_CONDITIONAL(XFAKESERVER, [test "x$KDRIVE" = xyes && test "x$XFAKE" = xyes]) - -dnl and the rest of these are generic, so they're in config.h -dnl -dnl though, thanks to the passing of some significant amount of time, the -dnl above is probably a complete fallacy, and you should not rely on it. -dnl but this is still actually better than imake, honest. -daniels - -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])]) - -AC_DEFINE_DIR(PROJECTROOT, prefix, [Overall prefix]) - -BUILD_DATE="`date +'%Y%m%d'`" -AC_SUBST([BUILD_DATE]) -BUILD_TIME="`date +'1%H%M%S'`" -AC_SUBST([BUILD_TIME]) - -DIX_CFLAGS="-DHAVE_DIX_CONFIG_H $XSERVER_CFLAGS" - -AC_SUBST([DIX_CFLAGS]) - -AC_SUBST([libdir]) -AC_SUBST([exec_prefix]) -AC_SUBST([prefix]) - -AC_OUTPUT([ -Makefile -glx/Makefile -include/Makefile -composite/Makefile -damageext/Makefile -dbe/Makefile -dix/Makefile -doc/Makefile -fb/Makefile -record/Makefile -config/Makefile -mi/Makefile -miext/Makefile -miext/damage/Makefile -miext/shadow/Makefile -miext/cw/Makefile -miext/rootless/Makefile -os/Makefile -randr/Makefile -render/Makefile -xkb/Makefile -Xext/Makefile -Xi/Makefile -xfixes/Makefile -exa/Makefile -hw/Makefile -hw/xfree86/Makefile -hw/xfree86/common/Makefile -hw/xfree86/common/xf86Build.h -hw/xfree86/ddc/Makefile -hw/xfree86/dixmods/Makefile -hw/xfree86/dixmods/extmod/Makefile -hw/xfree86/doc/Makefile -hw/xfree86/doc/devel/Makefile -hw/xfree86/doc/man/Makefile -hw/xfree86/doc/sgml/Makefile -hw/xfree86/dri/Makefile -hw/xfree86/dri2/Makefile -hw/xfree86/exa/Makefile -hw/xfree86/fbdevhw/Makefile -hw/xfree86/i2c/Makefile -hw/xfree86/int10/Makefile -hw/xfree86/loader/Makefile -hw/xfree86/modes/Makefile -hw/xfree86/os-support/Makefile -hw/xfree86/os-support/bsd/Makefile -hw/xfree86/os-support/bus/Makefile -hw/xfree86/os-support/hurd/Makefile -hw/xfree86/os-support/misc/Makefile -hw/xfree86/os-support/linux/Makefile -hw/xfree86/os-support/sco/Makefile -hw/xfree86/os-support/solaris/Makefile -hw/xfree86/os-support/sysv/Makefile -hw/xfree86/parser/Makefile -hw/xfree86/ramdac/Makefile -hw/xfree86/shadowfb/Makefile -hw/xfree86/vbe/Makefile -hw/xfree86/vgahw/Makefile -hw/xfree86/x86emu/Makefile -hw/xfree86/xaa/Makefile -hw/xfree86/xf8_16bpp/Makefile -hw/xfree86/utils/Makefile -hw/xfree86/utils/cvt/Makefile -hw/xfree86/utils/gtf/Makefile -hw/dmx/config/Makefile -hw/dmx/doc/Makefile -hw/dmx/examples/Makefile -hw/dmx/input/Makefile -hw/dmx/glxProxy/Makefile -hw/dmx/Makefile -hw/vfb/Makefile -hw/xnest/Makefile -hw/xwin/Makefile -hw/xwin/glx/Makefile -hw/xquartz/Makefile -hw/xquartz/GL/Makefile -hw/xquartz/bundle/Makefile -hw/xquartz/doc/Makefile -hw/xquartz/mach-startup/Makefile -hw/xquartz/pbproxy/Makefile -hw/xquartz/xpr/Makefile -hw/kdrive/Makefile -hw/kdrive/ephyr/Makefile -hw/kdrive/fake/Makefile -hw/kdrive/fbdev/Makefile -hw/kdrive/linux/Makefile -hw/kdrive/src/Makefile -test/Makefile -test/xi2/Makefile -xorg-server.pc -]) +dnl Copyright © 2003-2007 Keith Packard, Daniel Stone +dnl +dnl Permission is hereby granted, free of charge, to any person obtaining a +dnl copy of this software and associated documentation files (the "Software"), +dnl to deal in the Software without restriction, including without limitation +dnl the rights to use, copy, modify, merge, publish, distribute, sublicense, +dnl and/or sell copies of the Software, and to permit persons to whom the +dnl Software is furnished to do so, subject to the following conditions: +dnl +dnl The above copyright notice and this permission notice (including the next +dnl paragraph) shall be included in all copies or substantial portions of the +dnl Software. +dnl +dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +dnl IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +dnl FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +dnl THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +dnl LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +dnl FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +dnl DEALINGS IN THE SOFTWARE. +dnl +dnl Authors: Keith Packard +dnl Daniel Stone +dnl an unwitting cast of miscellaneous others +dnl +dnl Process this file with autoconf to create configure. + +AC_PREREQ(2.57) +AC_INIT([xorg-server], 1.8.99.0, [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], xorg-server) +RELEASE_DATE="unreleased" +AC_CONFIG_SRCDIR([Makefile.am]) +AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_MAINTAINER_MODE + +# Require xorg-macros: XORG_DEFAULT_OPTIONS +m4_ifndef([XORG_MACROS_VERSION], + [m4_fatal([must install xorg-macros 1.6 or later before running autoconf/autogen])]) +XORG_MACROS_VERSION(1.6) +XORG_DEFAULT_OPTIONS +XORG_WITH_DOXYGEN(1.6.1) + +m4_ifndef([XORG_FONT_MACROS_VERSION], [m4_fatal([must install fontutil 1.1 or later before running autoconf/autogen])]) +XORG_FONT_MACROS_VERSION(1.1) + +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 xorg-server.h is an external header, designed to be included by loadable +dnl drivers. +AC_CONFIG_HEADERS(include/xorg-server.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 xorg-config.h covers the Xorg DDX. +AC_CONFIG_HEADERS(include/xorg-config.h) +dnl xkb-config.h covers XKB for the Xorg and Xnest DDXs. +AC_CONFIG_HEADERS(include/xkb-config.h) +dnl xwin-config.h covers the XWin DDX. +AC_CONFIG_HEADERS(include/xwin-config.h) +dnl kdrive-config.h covers the kdrive DDX +AC_CONFIG_HEADERS(include/kdrive-config.h) +dnl version-config.h covers the version numbers so they can be bumped without +dnl forcing an entire recompile.x +AC_CONFIG_HEADERS(include/version-config.h) + +AC_PROG_CC +AM_PROG_AS +AC_PROG_INSTALL +AC_PROG_LN_S +AC_LIBTOOL_WIN32_DLL +AC_DISABLE_STATIC +AC_PROG_LIBTOOL +DOLT +AC_PROG_MAKE_SET +PKG_PROG_PKG_CONFIG +AC_PROG_LEX +AC_PROG_YACC +AC_SYS_LARGEFILE +XORG_PROG_RAWCPP +AC_PROG_SED + +# Quoted so that make will expand $(CWARNFLAGS) in makefiles to allow +# easier overrides at build time. +XSERVER_CFLAGS='$(CWARNFLAGS)' + +dnl Check for dtrace program (needed to build Xserver dtrace probes) +dnl Also checks for , since some Linux distros have an +dnl ISDN trace program named dtrace +AC_ARG_WITH(dtrace, AS_HELP_STRING([--with-dtrace=PATH], + [Enable dtrace probes (default: enabled if dtrace found)]), + [WDTRACE=$withval], [WDTRACE=auto]) +if test "x$WDTRACE" = "xyes" -o "x$WDTRACE" = "xauto" ; then + AC_PATH_PROG(DTRACE, [dtrace], [not_found], [$PATH:/usr/sbin]) + if test "x$DTRACE" = "xnot_found" ; then + if test "x$WDTRACE" = "xyes" ; then + AC_MSG_FAILURE([dtrace requested but not found]) + fi + WDTRACE="no" + else + AC_CHECK_HEADER(sys/sdt.h, [HAS_SDT_H="yes"], [HAS_SDT_H="no"]) + if test "x$WDTRACE" = "xauto" -a "x$HAS_SDT_H" = "xno" ; then + WDTRACE="no" + fi + fi +fi +if test "x$WDTRACE" != "xno" ; then + AC_DEFINE(XSERVER_DTRACE, 1, + [Define to 1 if the DTrace Xserver provider probes should be built in.]) + +# Solaris/OpenSolaris require dtrace -G to build dtrace probe information into +# object files, and require linking with those as relocatable objects, not .a +# archives. MacOS X handles all this in the normal compiler toolchain, and on +# some releases (like Tiger), will error out on dtrace -G. For now, other +# platforms with Dtrace ports are assumed to support -G (the FreeBSD and Linux +# ports appear to, based on my web searches, but have not yet been tested). + case $host_os in + darwin*) SPECIAL_DTRACE_OBJECTS=no ;; + *) SPECIAL_DTRACE_OBJECTS=yes ;; + esac +fi +AM_CONDITIONAL(XSERVER_DTRACE, [test "x$WDTRACE" != "xno"]) +AM_CONDITIONAL(SPECIAL_DTRACE_OBJECTS, [test "x$SPECIAL_DTRACE_OBJECTS" = "xyes"]) + +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h dlfcn.h stropts.h fnmatch.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 + +# Checks for headers/macros for byte swapping +# Known variants: +# bswap_16, bswap_32, bswap_64 (glibc) +# __swap16, __swap32, __swap64 (OpenBSD) +# bswap16, bswap32, bswap64 (other BSD's) +# and a fallback to local macros if none of the above are found + +# if is found, assume it's the correct version +AC_CHECK_HEADERS([byteswap.h]) + +# if is found, have to check which version +AC_CHECK_HEADER([sys/endian.h], [HAVE_SYS_ENDIAN_H="yes"], [HAVE_SYS_ENDIAN_H="no"]) + +if test "x$HAVE_SYS_ENDIAN_H" = "xyes" ; then + AC_MSG_CHECKING([for __swap16 variant of byteswapping macros]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#include +#include + ], [ +int a = 1, b; +b = __swap16(a); + ]) +], [SYS_ENDIAN__SWAP='yes'], [SYS_ENDIAN__SWAP='no']) + AC_MSG_RESULT([$SYS_ENDIAN__SWAP]) + + AC_MSG_CHECKING([for bswap16 variant of byteswapping macros]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#include +#include + ], [ +int a = 1, b; +b = bswap16(a); + ]) +], [SYS_ENDIAN_BSWAP='yes'], [SYS_ENDIAN_BSWAP='no']) + AC_MSG_RESULT([$SYS_ENDIAN_BSWAP]) + + if test "$SYS_ENDIAN_BSWAP" = "yes" ; then + USE_SYS_ENDIAN_H=yes + BSWAP=bswap + else + if test "$SYS_ENDIAN__SWAP" = "yes" ; then + USE_SYS_ENDIAN_H=yes + BSWAP=__swap + else + USE_SYS_ENDIAN_H=no + fi + fi + + if test "$USE_SYS_ENDIAN_H" = "yes" ; then + AC_DEFINE([USE_SYS_ENDIAN_H], 1, + [Define to use byteswap macros from ]) + AC_DEFINE_UNQUOTED([bswap_16], ${BSWAP}16, + [Define to 16-bit byteswap macro]) + AC_DEFINE_UNQUOTED([bswap_32], ${BSWAP}32, + [Define to 32-bit byteswap macro]) + AC_DEFINE_UNQUOTED([bswap_64], ${BSWAP}64, + [Define to 64-bit byteswap macro]) + fi +fi + +dnl Check to see if dlopen is in default libraries (like Solaris, which +dnl has it in libc), or if libdl is needed to get it. +AC_CHECK_FUNC([dlopen], [], + AC_CHECK_LIB([dl], [dlopen], DLOPEN_LIBS="-ldl")) +AC_SUBST(DLOPEN_LIBS) + +dnl Checks for library functions. +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([geteuid getuid link memmove memset mkstemp strchr strrchr \ + strtol getopt getopt_long vsnprintf walkcontext backtrace \ + getisax getzoneid shmctl64 strcasestr ffs]) +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]) +AC_CHECK_FUNC([strlcpy], AC_DEFINE(HAS_STRLCPY, 1, [Have the 'strlcpy' function])) + +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) +AC_CHECK_LIB(m, cbrt, AC_DEFINE(HAVE_CBRT, 1, [Have the 'cbrt' function])) + +AC_CHECK_HEADERS([ndbm.h dbm.h rpcsvc/dbm.h]) + +dnl AGPGART headers +AC_CHECK_HEADERS([linux/agpgart.h sys/agpio.h sys/agpgart.h], AGP=yes) +AM_CONDITIONAL(AGP, [test "x$AGP" = xyes]) + +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 +#include +#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 OpenBSD /dev/xf86 aperture driver +if test -c /dev/xf86 ; then + AC_DEFINE(HAS_APERTURE_DRV, 1, [System has /dev/xf86 aperture driver]) +fi + +dnl BSD APM support +AC_CHECK_HEADER([machine/apmvar.h],[ + AC_CHECK_HEADER([sys/event.h], + ac_cv_BSD_KQUEUE_APM=yes, + ac_cv_BSD_APM=yes)]) + +AM_CONDITIONAL(BSD_APM, [test "x$ac_cv_BSD_APM" = xyes]) +AM_CONDITIONAL(BSD_KQUEUE_APM, [test "x$ac_cv_BSD_KQUEUE_APM" = xyes]) + +dnl glibc backtrace support check (hw/xfree86/common/xf86Events.c) +AC_CHECK_HEADER([execinfo.h],[ + AC_CHECK_LIB(c, backtrace, [ + AC_DEFINE(HAVE_BACKTRACE, 1, [Has backtrace support]) + AC_DEFINE(HAVE_EXECINFO_H, 1, [Have execinfo.h]) + ])] +) + +dnl ARM needs additional compiler flags for proper backtraces if GCC is +dnl used. Compile a dummy program with the -mapcs-frame option. If it +dnl succeeds, we know that we are building for ARM with GCC. +old_CFLAGS="$CFLAGS" +CFLAGS="-mapcs-frame" +AC_COMPILE_IFELSE( + AC_LANG_PROGRAM([[ ]]), + ARM_BACKTRACE_CFLAGS="$CFLAGS", + ARM_BACKTRACE_CFLAGS="" +) +CFLAGS="$old_CFLAGS" +AC_SUBST(ARM_BACKTRACE_CFLAGS) + +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 + *freebsd*) SYS_LIBS=-lio ;; + *netbsd*) AC_DEFINE(USE_ALPHA_PIO, 1, [NetBSD PIO alpha IO]) ;; + esac + GLX_ARCH_DEFINES="-D__GLX_ALIGN64 -mieee" + ;; + arm*) + ARM_VIDEO=yes + ;; + i*86) + I386_VIDEO=yes + case $host_os in + *freebsd*) AC_DEFINE(USE_DEV_IO) ;; + *dragonfly*) 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*) + SPARC64_VIDEO=yes + BSD_ARCH_SOURCES="sparc64_video.c ioperm_noop.c" + GLX_ARCH_DEFINES="-D__GLX_ALIGN64" + ;; + x86_64*|amd64*) + I386_VIDEO=yes + case $host_os in + *freebsd*) AC_DEFINE(USE_DEV_IO, 1, [BSD /dev/io]) ;; + *dragonfly*) 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 + GLX_ARCH_DEFINES="-D__GLX_ALIGN64" + ;; + ia64*) + GLX_ARCH_DEFINES="-D__GLX_ALIGN64" + ;; + s390*) + GLX_ARCH_DEFINES="-D__GLX_ALIGN64" + ;; +esac +AC_SUBST(GLX_ARCH_DEFINES) + +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 +USE_SIGIO_BY_DEFAULT="yes" +dnl it would be nice to autodetect these *CONS_SUPPORTs +case $host_os in + *freebsd* | *dragonfly*) + 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]) + DRI=yes + ;; + *netbsd*) + AC_DEFINE(CSRG_BASED, 1, [System is BSD-like]) + AC_DEFINE(PCCONS_SUPPORT, 1, [System has PC console]) + AC_DEFINE(PCVT_SUPPORT, 1, [System has PCVT console]) + AC_DEFINE(WSCONS_SUPPORT, 1, [System has wscons console]) + DRI=yes + ;; + *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]) + ;; + *linux*) + DRI=yes + ;; + *solaris*) + PKG_CHECK_EXISTS(libdrm, DRI=yes, DRI=no) + # Disable use of SIGIO by default until some system bugs are + # fixed - see Sun/OpenSolaris bug id 6879897 + USE_SIGIO_BY_DEFAULT="no" + ;; + darwin*) + AC_DEFINE(CSRG_BASED, 1, [System is BSD-like]) + ;; + cygwin*) + CFLAGS="$CFLAGS -DFD_SETSIZE=256" + ;; +esac + +dnl augment XORG_RELEASE_VERSION for our snapshot number and to expose the +dnl major number +PVMAJOR=`echo $PACKAGE_VERSION | cut -d . -f 1` +PVS=`echo $PACKAGE_VERSION | cut -d . -f 4 | cut -d - -f 1` +if test "x$PVS" = "x"; then + PVS="0" +fi + +VENDOR_RELEASE="((($PVMAJOR) * 10000000) + (($PVM) * 100000) + (($PVP) * 1000) + $PVS)" +VENDOR_MAN_VERSION="Version ${PACKAGE_VERSION}" + +VENDOR_NAME="The X.Org Foundation" +VENDOR_NAME_SHORT="X.Org" +VENDOR_WEB="http://wiki.x.org" + +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], + [Obsolete - use --enable-strict-compilation instead]), + AC_MSG_ERROR([--enable-werror has been replaced by --enable-strict-compilation])) + +AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], + [Enable debugging (default: disabled)]), + [DEBUGGING=$enableval], [DEBUGGING=no]) +AC_ARG_ENABLE(unit-tests, AS_HELP_STRING([--enable-unit-tests], + [Enable unit-tests (default: auto)]), + [UNITTESTS=$enableval], [UNITTESTS=auto]) +AC_ARG_ENABLE(use-sigio-by-default, AS_HELP_STRING([--enable-use-sigio-by-default] + [Enable SIGIO input handlers by default (default: $USE_SIGIO_BY_DEFAULT)]), + [USE_SIGIO_BY_DEFAULT=$enableval], []) +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-name=VENDOR], + [Vendor string reported by the server]), + [ VENDOR_NAME="$withval" ], []) +AC_ARG_WITH(vendor-name-short, AS_HELP_STRING([--with-vendor-name-short=VENDOR], + [Short version of vendor string reported by the server]), + [ VENDOR_NAME_SHORT="$withval" ], []) +AC_ARG_WITH(vendor-web, AS_HELP_STRING([--with-vendor-web=URL], + [Vendor web address reported by the server]), + [ VENDOR_WEB="$withval" ], []) +AC_ARG_WITH(module-dir, AS_HELP_STRING([--with-module-dir=DIR], + [Directory where modules are installed (default: $libdir/xorg/modules)]), + [ moduledir="$withval" ], + [ moduledir="${libdir}/xorg/modules" ]) +AC_ARG_WITH(log-dir, AS_HELP_STRING([--with-log-dir=DIR], + [Directory where log files are kept (default: $localstatedir/log)]), + [ logdir="$withval" ], + [ logdir="$localstatedir/log" ]) +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(os-name, AS_HELP_STRING([--with-os-name=OSNAME], [Name of OS (default: output of "uname -srm")]), + [ OSNAME="$withval" ], + [ OSNAME=`uname -srm` ]) +AC_ARG_WITH(os-vendor, AS_HELP_STRING([--with-os-vendor=OSVENDOR], [Name of OS vendor]), + [ OSVENDOR="$withval" ], + [ OSVENDOR="" ]) +AC_ARG_WITH(builderstring, AS_HELP_STRING([--with-builderstring=BUILDERSTRING], [Additional builder string]), + [ BUILDERSTRING="$withval" ] + [ ]) + +dnl Determine font path +XORG_FONTROOTDIR +XORG_FONTSUBDIR(FONTMISCDIR, fontmiscdir, misc) +XORG_FONTSUBDIR(FONTOTFDIR, fontotfdir, OTF) +XORG_FONTSUBDIR(FONTTTFDIR, fontttfdir, TTF) +XORG_FONTSUBDIR(FONTTYPE1DIR, fonttype1dir, Type1) +XORG_FONTSUBDIR(FONT75DPIDIR, font75dpidir, 75dpi) +XORG_FONTSUBDIR(FONT100DPIDIR, font100dpidir, 100dpi) + +dnl Uses --default-font-path if set, otherwise checks for /etc/X11/fontpath.d, +dnl otherwise uses standard subdirectories of FONTROOTDIR. When cross +dnl compiling, assume default font path uses standard FONTROOTDIR directories. +DEFAULT_FONT_PATH="${FONTMISCDIR}/,${FONTTTFDIR}/,${FONTOTFDIR}/,${FONTTYPE1DIR}/,${FONT100DPIDIR}/,${FONT75DPIDIR}/" +if test "$cross_compiling" != yes; then + AC_CHECK_FILE([${sysconfdir}/X11/fontpath.d], + [DEFAULT_FONT_PATH='catalogue:${sysconfdir}/X11/fontpath.d'], + [case $host_os in + darwin*) DEFAULT_FONT_PATH="${DEFAULT_FONT_PATH},/Library/Fonts,/System/Library/Fonts" ;; + esac]) +fi +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}" ]) + +AC_MSG_CHECKING([for default font path]) +AC_MSG_RESULT([$FONTPATH]) + +AC_ARG_WITH(xkb-path, AS_HELP_STRING([--with-xkb-path=PATH], [Path to XKB base dir (default: ${datadir}/X11/xkb)]), + [ XKBPATH="$withval" ], + [ XKBPATH="${datadir}/X11/xkb" ]) +AC_ARG_WITH(xkb-output, AS_HELP_STRING([--with-xkb-output=PATH], [Path to XKB output dir (default: ${datadir}/X11/xkb/compiled)]), + [ XKBOUTPUT="$withval" ], + [ XKBOUTPUT="compiled" ]) +AC_ARG_WITH(default-xkb-rules, AS_HELP_STRING([--with-default-xkb-rules=RULES], + [Keyboard ruleset (default: base/evdev)]), + [ XKB_DFLT_RULES="$withval" ], + [ XKB_DFLT_RULES="" ]) +AC_ARG_WITH(default-xkb-model, AS_HELP_STRING([--with-default-xkb-model=MODEL], + [Keyboard model (default: pc105)]), + [ XKB_DFLT_MODEL="$withval" ], + [ XKB_DFLT_MODEL="pc105" ]) +AC_ARG_WITH(default-xkb-layout, AS_HELP_STRING([--with-default-xkb-layout=LAYOUT], + [Keyboard layout (default: us)]), + [ XKB_DFLT_LAYOUT="$withval" ], + [ XKB_DFLT_LAYOUT="us" ]) +AC_ARG_WITH(default-xkb-variant, AS_HELP_STRING([--with-default-xkb-variant=VARIANT], + [Keyboard variant (default: (none))]), + [ XKB_DFLT_VARIANT="$withval" ], + [ XKB_DFLT_VARIANT="" ]) +AC_ARG_WITH(default-xkb-options, AS_HELP_STRING([--with-default-xkb-options=OPTIONS], + [Keyboard layout options (default: (none))]), + [ XKB_DFLT_OPTIONS="$withval" ], + [ XKB_DFLT_OPTIONS="" ]) +AC_ARG_WITH(serverconfig-path, AS_HELP_STRING([--with-serverconfig-path=PATH], + [Directory where ancillary server config files are installed (default: ${libdir}/xorg)]), + [ SERVERCONFIG="$withval" ], + [ SERVERCONFIG="${libdir}/xorg" ]) +AC_ARG_WITH(apple-applications-dir,AS_HELP_STRING([--with-apple-applications-dir=PATH], [Path to the Applications directory (default: /Applications/Utilities)]), + [ APPLE_APPLICATIONS_DIR="${withval}" ], + [ APPLE_APPLICATIONS_DIR="/Applications/Utilities" ]) +AC_SUBST([APPLE_APPLICATIONS_DIR]) +AC_ARG_WITH(apple-application-name,AS_HELP_STRING([--with-apple-application-name=NAME], [Name for the .app (default: X11)]), + [ APPLE_APPLICATION_NAME="${withval}" ], + [ APPLE_APPLICATION_NAME="X11" ]) +AC_SUBST([APPLE_APPLICATION_NAME]) +AC_ARG_WITH(launchd-id-prefix, AS_HELP_STRING([--with-launchd-id-prefix=PATH], [Prefix to use for launchd identifiers (default: org.x)]), + [ LAUNCHD_ID_PREFIX="${withval}" ], + [ LAUNCHD_ID_PREFIX="org.x" ]) +AC_SUBST([LAUNCHD_ID_PREFIX]) +AC_DEFINE_UNQUOTED(LAUNCHD_ID_PREFIX, "$LAUNCHD_ID_PREFIX", [Prefix to use for launchd identifiers]) +AC_ARG_ENABLE(sparkle,AS_HELP_STRING([--enable-sparkle], [Enable updating of X11.app using the Sparkle Framework (default: disabled)]), + [ XQUARTZ_SPARKLE="${enableval}" ], + [ XQUARTZ_SPARKLE="no" ]) +AC_SUBST([XQUARTZ_SPARKLE]) +AC_ARG_ENABLE(builddocs, AS_HELP_STRING([--enable-builddocs], [Build docs (default: disabled)]), + [BUILDDOCS=$enableval], + [BUILDDOCS=no]) +AC_ARG_ENABLE(install-libxf86config, + AS_HELP_STRING([--enable-install-libxf86config], + [Install libxf86config (default: disabled)]), + [INSTALL_LIBXF86CONFIG=$enableval], + [INSTALL_LIBXF86CONFIG=no]) +AC_ARG_ENABLE(visibility, AC_HELP_STRING([--enable-visibility], [Enable symbol visibility (default: auto)]), + [SYMBOL_VISIBILITY=$enableval], + [SYMBOL_VISIBILITY=auto]) +AC_ARG_ENABLE(pc98, AC_HELP_STRING([--enable-pc98], [Enable PC98 support in Xorg (default: auto)]), + [SUPPORT_PC98=$enableval], + [SUPPORT_PC98=auto]) + +dnl GLX build options +AC_ARG_WITH(dri-driver-path, AS_HELP_STRING([--with-dri-driver-path=PATH], [Path to DRI drivers (default: ${libdir}/dri)]), + [ DRI_DRIVER_PATH="$withval" ], + [ DRI_DRIVER_PATH="${libdir}/dri" ]) +AC_ARG_ENABLE(aiglx, AS_HELP_STRING([--enable-aiglx], [Build accelerated indirect GLX (default: enabled)]), + [AIGLX=$enableval], + [AIGLX=yes]) +AC_ARG_ENABLE(glx-tls, AS_HELP_STRING([--enable-glx-tls], [Build GLX with TLS support (default: disabled)]), + [GLX_USE_TLS=$enableval], + [GLX_USE_TLS=no]) + +dnl Extensions. +AC_ARG_ENABLE(registry, AS_HELP_STRING([--disable-registry], [Build string registry module (default: enabled)]), [XREGISTRY=$enableval], [XREGISTRY=yes]) +AC_ARG_ENABLE(composite, AS_HELP_STRING([--disable-composite], [Build Composite extension (default: enabled)]), [COMPOSITE=$enableval], [COMPOSITE=yes]) +AC_ARG_ENABLE(mitshm, AS_HELP_STRING([--disable-shm], [Build SHM extension (default: enabled)]), [MITSHM=$enableval], [MITSHM=yes]) +AC_ARG_ENABLE(xres, AS_HELP_STRING([--disable-xres], [Build XRes extension (default: enabled)]), [RES=$enableval], [RES=yes]) +AC_ARG_ENABLE(record, AS_HELP_STRING([--disable-record], [Build Record extension (default: enabled)]), [RECORD=$enableval], [RECORD=yes]) +AC_ARG_ENABLE(xv, AS_HELP_STRING([--disable-xv], [Build Xv extension (default: enabled)]), [XV=$enableval], [XV=yes]) +AC_ARG_ENABLE(xvmc, AS_HELP_STRING([--disable-xvmc], [Build XvMC extension (default: enabled)]), [XVMC=$enableval], [XVMC=yes]) +AC_ARG_ENABLE(dga, AS_HELP_STRING([--disable-dga], [Build DGA extension (default: auto)]), [DGA=$enableval], [DGA=auto]) +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(glx, AS_HELP_STRING([--disable-glx], [Build GLX extension (default: enabled)]), [GLX=$enableval], [GLX=yes]) +AC_ARG_ENABLE(dri, AS_HELP_STRING([--enable-dri], [Build DRI extension (default: auto)]), [DRI=$enableval]) +AC_ARG_ENABLE(dri2, AS_HELP_STRING([--enable-dri2], [Build DRI2 extension (default: auto)]), [DRI2=$enableval], [DRI2=auto]) +AC_ARG_ENABLE(xinerama, AS_HELP_STRING([--disable-xinerama], [Build Xinerama extension (default: enabled)]), [XINERAMA=$enableval], [XINERAMA=yes]) +AC_ARG_ENABLE(xf86vidmode, AS_HELP_STRING([--disable-xf86vidmode], [Build XF86VidMode extension (default: auto)]), [XF86VIDMODE=$enableval], [XF86VIDMODE=auto]) +AC_ARG_ENABLE(xace, AS_HELP_STRING([--disable-xace], [Build X-ACE extension (default: enabled)]), [XACE=$enableval], [XACE=yes]) +AC_ARG_ENABLE(xselinux, AS_HELP_STRING([--enable-xselinux], [Build SELinux extension (default: disabled)]), [XSELINUX=$enableval], [XSELINUX=no]) +AC_ARG_ENABLE(xcsecurity, AS_HELP_STRING([--enable-xcsecurity], [Build Security extension (default: disabled)]), [XCSECURITY=$enableval], [XCSECURITY=no]) +AC_ARG_ENABLE(xcalibrate, AS_HELP_STRING([--enable-xcalibrate], [Build XCalibrate extension (default: disabled)]), [XCALIBRATE=$enableval], [XCALIBRATE=no]) +AC_ARG_ENABLE(tslib, AS_HELP_STRING([--enable-tslib], [Build kdrive tslib touchscreen support (default: disabled)]), [TSLIB=$enableval], [TSLIB=no]) +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([--enable-xf86bigfont], [Build XF86 Big Font extension (default: disabled)]), [XF86BIGFONT=$enableval], [XF86BIGFONT=no]) +AC_ARG_ENABLE(dpms, AS_HELP_STRING([--disable-dpms], [Build DPMS extension (default: enabled)]), [DPMSExtension=$enableval], [DPMSExtension=yes]) +AC_ARG_ENABLE(config-udev, AS_HELP_STRING([--enable-config-udev], [Build udev support (default: auto)]), [CONFIG_UDEV=$enableval], [CONFIG_UDEV=auto]) +AC_ARG_ENABLE(config-dbus, AS_HELP_STRING([--enable-config-dbus], [Build D-BUS API support (default: no)]), [CONFIG_DBUS_API=$enableval], [CONFIG_DBUS_API=no]) +AC_ARG_ENABLE(config-hal, AS_HELP_STRING([--disable-config-hal], [Build HAL support (default: auto)]), [CONFIG_HAL=$enableval], [CONFIG_HAL=auto]) +AC_ARG_ENABLE(xfree86-utils, AS_HELP_STRING([--enable-xfree86-utils], [Build xfree86 DDX utilities (default: enabled)]), [XF86UTILS=$enableval], [XF86UTILS=yes]) +AC_ARG_ENABLE(xaa, AS_HELP_STRING([--enable-xaa], [Build XAA (default: enabled)]), [XAA=$enableval], [XAA=yes]) +AC_ARG_ENABLE(vgahw, AS_HELP_STRING([--enable-vgahw], [Build Xorg with vga access (default: enabled)]), [VGAHW=$enableval], [VGAHW=yes]) +AC_ARG_ENABLE(vbe, AS_HELP_STRING([--enable-vbe], [Build Xorg with VBE module (default: enabled)]), [VBE=$enableval], [VBE=yes]) +AC_ARG_ENABLE(int10-module, AS_HELP_STRING([--enable-int10-module], [Build Xorg with int10 module (default: enabled)]), [INT10MODULE=$enableval], [INT10MODULE=yes]) +AC_ARG_ENABLE(windowswm, AS_HELP_STRING([--enable-windowswm], [Build XWin with WindowsWM extension (default: no)]), [WINDOWSWM=$enableval], [WINDOWSWM=no]) + +dnl DDXes. +AC_ARG_ENABLE(xorg, AS_HELP_STRING([--enable-xorg], [Build Xorg server (default: auto)]), [XORG=$enableval], [XORG=auto]) +AC_ARG_ENABLE(dmx, AS_HELP_STRING([--enable-dmx], [Build DMX server (default: auto)]), [DMX=$enableval], [DMX=auto]) +AC_ARG_ENABLE(xvfb, AS_HELP_STRING([--enable-xvfb], [Build Xvfb server (default: yes)]), [XVFB=$enableval], [XVFB=yes]) +AC_ARG_ENABLE(xnest, AS_HELP_STRING([--enable-xnest], [Build Xnest server (default: auto)]), [XNEST=$enableval], [XNEST=auto]) +AC_ARG_ENABLE(xquartz, AS_HELP_STRING([--enable-xquartz], [Build Xquartz server for OS-X (default: auto)]), [XQUARTZ=$enableval], [XQUARTZ=auto]) +AC_ARG_ENABLE(standalone-xpbproxy, AS_HELP_STRING([--enable-standalone-xpbproxy], [Build a standalone xpbproxy (in addition to the one integrated into Xquartz as a separate thread) (default: no)]), [STANDALONE_XPBPROXY=$enableval], [STANDALONE_XPBPROXY=no]) +AC_ARG_ENABLE(xwin, AS_HELP_STRING([--enable-xwin], [Build XWin server (default: auto)]), [XWIN=$enableval], [XWIN=auto]) +dnl kdrive and its subsystems +AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: no)]), [KDRIVE=$enableval], [KDRIVE=no]) +AC_ARG_ENABLE(xephyr, AS_HELP_STRING([--enable-xephyr], [Build the kdrive Xephyr server (default: auto)]), [XEPHYR=$enableval], [XEPHYR=auto]) +AC_ARG_ENABLE(xfake, AS_HELP_STRING([--enable-xfake], [Build the kdrive 'fake' server (default: auto)]), [XFAKE=$enableval], [XFAKE=auto]) +AC_ARG_ENABLE(xfbdev, AS_HELP_STRING([--enable-xfbdev], [Build the kdrive framebuffer device server (default: auto)]), [XFBDEV=$enableval], [XFBDEV=auto]) +dnl kdrive options +AC_ARG_ENABLE(kdrive-kbd, AS_HELP_STRING([--enable-kdrive-kbd], [Build kbd driver for kdrive (default: auto)]), [KDRIVE_KBD=$enableval], [KDRIVE_KBD=auto]) +AC_ARG_ENABLE(kdrive-mouse, AC_HELP_STRING([--enable-kdrive-mouse], [Build mouse driver for kdrive (default: auto)]), [KDRIVE_MOUSE=$enableval], [KDRIVE_MOUSE=auto]) +AC_ARG_ENABLE(kdrive-evdev, AC_HELP_STRING([--enable-kdrive-evdev], [Build evdev driver for kdrive (default: auto)]), [KDRIVE_EVDEV=$enableval], [KDRIVE_EVDEV=auto]) + + +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 + cygwin*) SETUID="no" ;; + 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(SECURE_RPC, [test "x$SECURE_RPC" = xyes]) + +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 Handle building documentation +AM_CONDITIONAL(BUILDDOCS, test "x$BUILDDOCS" = xyes) + +dnl Only build sgml docs when linuxdoc is available and +dnl def.ents has been installed +XORG_CHECK_LINUXDOC + +dnl Handle installing libxf86config +AM_CONDITIONAL(INSTALL_LIBXF86CONFIG, [test "x$INSTALL_LIBXF86CONFIG" = xyes]) + +dnl DDX Detection... Yes, it's ugly to have it here... but we need to +dnl handle this early on so that we don't require unsupported extensions +case $host_os in + cygwin*) + DGA=no + DRI2=no + XF86VIDMODE=no + XSELINUX=no + XV=no + ;; + darwin*) + DRI2=no + + if test x$XQUARTZ = xauto; then + AC_CACHE_CHECK([whether to build Xquartz],xorg_cv_Carbon_framework,[ + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -framework Carbon" + AC_LINK_IFELSE([char FSFindFolder(); int main() { FSFindFolder(); return 0;}], + [xorg_cv_Carbon_framework=yes], + [xorg_cv_Carbon_framework=no]) + LDFLAGS=$save_LDFLAGS]) + + if test "X$xorg_cv_Carbon_framework" = Xyes; then + XQUARTZ=yes + else + XQUARTZ=no + fi + fi + + if test "x$XQUARTZ" = xyes ; then + XQUARTZ=yes + XVFB=no + XNEST=no + + COMPOSITE=no + DGA=no + DPMSExtension=no + XF86VIDMODE=no + fi + ;; + *) XQUARTZ=no ;; +esac + +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 Optional modules +VIDEOPROTO="videoproto" +COMPOSITEPROTO="compositeproto >= 0.4" +RECORDPROTO="recordproto >= 1.13.99.1" +SCRNSAVERPROTO="scrnsaverproto >= 1.1" +RESOURCEPROTO="resourceproto" +DRIPROTO="xf86driproto >= 2.1.0" +DRI2PROTO="dri2proto >= 2.3" +XINERAMAPROTO="xineramaproto" +BIGFONTPROTO="xf86bigfontproto >= 1.2.0" +XCALIBRATEPROTO="xcalibrateproto" +DGAPROTO="xf86dgaproto >= 2.0.99.1" +GLPROTO="glproto >= 1.4.10" +DMXPROTO="dmxproto >= 2.2.99.1" +VIDMODEPROTO="xf86vidmodeproto >= 2.2.99.1" +WINDOWSWMPROTO="windowswmproto" +APPLEWMPROTO="applewmproto >= 1.4" + +dnl Core modules for most extensions, et al. +REQUIRED_MODULES="[randrproto >= 1.2.99.3] [renderproto >= 0.11] [fixesproto >= 4.1] [damageproto >= 1.1] [xcmiscproto >= 1.2.0] [xextproto >= 7.0.99.3] [xproto >= 7.0.13] [xtrans >= 1.2.2] [bigreqsproto >= 1.1.0] fontsproto [inputproto >= 1.9.99.902] [kbproto >= 1.0.3]" +REQUIRED_LIBS="xfont xau [pixman-1 >= 0.15.20]" + +dnl List of libraries that require a specific version +LIBAPPLEWM="applewm >= 1.4" +LIBDMX="dmx >= 1.0.99.1" +LIBDRI="dri >= 7.8.0" +LIBDRM="libdrm >= 2.3.0" +LIBGL="gl >= 7.1.0" +LIBXEXT="xext >= 1.0.99.4" +LIBXI="xi >= 1.2.99.1" +LIBXTST="xtst >= 1.0.99.2" +LIBPCIACCESS="pciaccess >= 0.8.0" +LIBGLIB="glib-2.0 >= 2.16" +LIBUDEV="libudev >= 143" +LIBSELINUX="libselinux >= 2.0.86" + +if test "x$CONFIG_UDEV" = xyes && + { test "x$CONFIG_DBUS_API" = xyes || test "x$CONFIG_HAL" = xyes; }; then + AC_MSG_ERROR([Hotplugging through both libudev and dbus/hal not allowed]) +fi + +PKG_CHECK_MODULES(UDEV, $LIBUDEV, [HAVE_LIBUDEV=yes], [HAVE_LIBUDEV=no]) +if test "x$CONFIG_UDEV" = xauto; then + CONFIG_UDEV="$HAVE_LIBUDEV" +fi +AM_CONDITIONAL(CONFIG_UDEV, [test "x$CONFIG_UDEV" = xyes]) +if test "x$CONFIG_UDEV" = xyes; then + CONFIG_DBUS_API=no + CONFIG_HAL=no + if ! test "x$HAVE_LIBUDEV" = xyes; then + AC_MSG_ERROR([udev configuration API requested, but libudev is not installed]) + fi + AC_DEFINE(CONFIG_UDEV, 1, [Use libudev for input hotplug]) +fi + +dnl HAVE_DBUS is true if we actually have the D-Bus library, whereas +dnl CONFIG_DBUS_API is true if we want to enable the D-Bus config +dnl API. +PKG_CHECK_MODULES(DBUS, dbus-1, [HAVE_DBUS=yes], [HAVE_DBUS=no]) +if test "x$HAVE_DBUS" = xyes; then + AC_DEFINE(HAVE_DBUS, 1, [Have D-Bus support]) +fi +AM_CONDITIONAL(HAVE_DBUS, [test "x$HAVE_DBUS" = xyes]) + +if test "x$CONFIG_DBUS_API" = xauto; then + CONFIG_DBUS_API="$HAVE_DBUS" +fi +if test "x$CONFIG_DBUS_API" = xyes; then + if ! test "x$HAVE_DBUS" = xyes; then + AC_MSG_ERROR([D-Bus configuration API requested, but D-Bus is not installed.]) + fi + + AC_DEFINE(CONFIG_DBUS_API, 1, [Use the D-Bus input configuration API]) + CONFIG_NEED_DBUS="yes" +fi +AM_CONDITIONAL(CONFIG_DBUS_API, [test "x$CONFIG_DBUS_API" = xyes]) + +PKG_CHECK_MODULES(HAL, hal, [HAVE_HAL=yes], [HAVE_HAL=no]) +if test "x$CONFIG_HAL" = xauto; then + CONFIG_HAL="$HAVE_HAL" +fi +if test "x$CONFIG_HAL" = xyes; then + if ! test "x$HAVE_HAL" = xyes; then + AC_MSG_ERROR([HAL hotplug API requested, but HAL is not installed.]) + fi + + AC_DEFINE(CONFIG_HAL, 1, [Use the HAL hotplug API]) + CONFIG_NEED_DBUS="yes" +fi +AM_CONDITIONAL(CONFIG_HAL, [test "x$CONFIG_HAL" = xyes]) + +if test "x$CONFIG_NEED_DBUS" = xyes; then + AC_DEFINE(CONFIG_NEED_DBUS, 1, [Use D-Bus for input hotplug]) +fi +AM_CONDITIONAL(CONFIG_NEED_DBUS, [test "x$CONFIG_NEED_DBUS" = xyes]) +CONFIG_LIB='$(top_builddir)/config/libconfig.la' + +if test "x$USE_SIGIO_BY_DEFAULT" = xyes; then + USE_SIGIO_BY_DEFAULT_VALUE=TRUE +else + USE_SIGIO_BY_DEFAULT_VALUE=FALSE +fi +AC_DEFINE_UNQUOTED([USE_SIGIO_BY_DEFAULT], [$USE_SIGIO_BY_DEFAULT_VALUE], + [Use SIGIO handlers for input device events by default]) + +AC_MSG_CHECKING([for glibc...]) +AC_PREPROC_IFELSE([ +#include +#ifndef __GLIBC__ +#error +#endif +], glibc=yes, glibc=no) +AC_MSG_RESULT([$glibc]) + +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 + CLOCK_LIBS="$have_clock_gettime" + else + CLOCK_LIBS="" + fi + + LIBS_SAVE="$LIBS" + LIBS="$CLOCK_LIBS" + CPPFLAGS_SAVE="$CPPFLAGS" + + if test x"$glibc" = xyes; then + CPPFLAGS="$CPPFLAGS -D_POSIX_C_SOURCE=200112L" + fi + + AC_RUN_IFELSE([ +#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"]) + + LIBS="$LIBS_SAVE" + CPPFLAGS="$CPPFLAGS_SAVE" +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()]) + LIBS="$LIBS $CLOCK_LIBS" +fi + +AM_CONDITIONAL(XV, [test "x$XV" = xyes]) +if test "x$XV" = xyes; then + AC_DEFINE(XV, 1, [Support Xv extension]) + AC_DEFINE(XvExtension, 1, [Build Xv extension]) + REQUIRED_MODULES="$REQUIRED_MODULES $VIDEOPROTO" +else + XVMC=no +fi + +AM_CONDITIONAL(XVMC, [test "x$XVMC" = xyes]) +if test "x$XVMC" = xyes; then + AC_DEFINE(XvMCExtension, 1, [Build XvMC extension]) +fi + +AM_CONDITIONAL(XREGISTRY, [test "x$XREGISTRY" = xyes]) +if test "x$XREGISTRY" = xyes; then + AC_DEFINE(XREGISTRY, 1, [Build registry module]) +fi + +AM_CONDITIONAL(COMPOSITE, [test "x$COMPOSITE" = xyes]) +if test "x$COMPOSITE" = xyes; then + AC_DEFINE(COMPOSITE, 1, [Support Composite Extension]) + REQUIRED_MODULES="$REQUIRED_MODULES $COMPOSITEPROTO" + COMPOSITE_LIB='$(top_builddir)/composite/libcomposite.la' + COMPOSITE_INC='-I$(top_srcdir)/composite' +fi + +AM_CONDITIONAL(MITSHM, [test "x$MITSHM" = xyes]) +if test "x$MITSHM" = xyes; then + AC_DEFINE(MITSHM, 1, [Support MIT-SHM extension]) + AC_DEFINE(HAS_SHM, 1, [Support SHM]) +fi + +AM_CONDITIONAL(RECORD, [test "x$RECORD" = xyes]) +if test "x$RECORD" = xyes; then + AC_DEFINE(XRECORD, 1, [Support Record extension]) + REQUIRED_MODULES="$REQUIRED_MODULES $RECORDPROTO" + RECORD_LIB='$(top_builddir)/record/librecord.la' +fi + +AM_CONDITIONAL(SCREENSAVER, [test "x$SCREENSAVER" = xyes]) +if test "x$SCREENSAVER" = xyes; then + AC_DEFINE(SCREENSAVER, 1, [Support MIT-SCREEN-SAVER extension]) + REQUIRED_MODULES="$REQUIRED_MODULES $SCRNSAVERPROTO" +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 + +if test "x$GLX" = xyes; then + PKG_CHECK_MODULES([XLIB], [x11]) + PKG_CHECK_MODULES([GL], $GLPROTO $LIBGL) + AC_SUBST(XLIB_CFLAGS) + AC_DEFINE(GLXEXT, 1, [Build GLX extension]) + GLX_LIBS='$(top_builddir)/glx/libglx.la' + GLX_SYS_LIBS="$GLX_SYS_LIBS" +else + GLX=no +fi +AM_CONDITIONAL(GLX, test "x$GLX" = xyes) + +if test "x$AIGLX" = xyes -a "x$GLX" = xyes -a "x$DRI" = xyes; then + AC_DEFINE(AIGLX, 1, [Build AIGLX loader]) +else + AIGLX=no +fi +AM_CONDITIONAL(AIGLX, test "x$AIGLX" = xyes) + +if test "x$GLX_USE_TLS" = xyes -a "x$AIGLX" = xyes; then + GLX_DEFINES="-DGLX_USE_TLS -DPTHREADS" + GLX_SYS_LIBS="$GLX_SYS_LIBS -lpthread" +fi +AC_SUBST([GLX_DEFINES]) + +AM_CONDITIONAL(DRI, test "x$DRI" = xyes) +if test "x$DRI" = xyes; then + AC_DEFINE(XF86DRI, 1, [Build DRI extension]) + PKG_CHECK_MODULES([DRIPROTO], [$DRIPROTO]) + PKG_CHECK_MODULES([DRI], $GLPROTO $LIBDRI) + AC_SUBST(DRIPROTO_CFLAGS) +fi + +PKG_CHECK_MODULES([DRI2PROTO], $DRI2PROTO, + [HAVE_DRI2PROTO=yes], [HAVE_DRI2PROTO=no]) +case "$DRI2,$HAVE_DRI2PROTO" in + yes,no) + AC_MSG_ERROR([DRI2 requested, but dri2proto not found.]) + ;; + yes,yes | auto,yes) + AC_DEFINE(DRI2, 1, [Build DRI2 extension]) + DRI2=yes + ;; +esac +AM_CONDITIONAL(DRI2, test "x$DRI2" = xyes) + +if test "x$DRI" = xyes || test "x$DRI2" = xyes; then + PKG_CHECK_MODULES([LIBDRM], $LIBDRM) + AC_SUBST(LIBDRM_CFLAGS) + AC_SUBST(LIBDRM_LIBS) +fi + +if test "x$DRI2" = xyes; then + save_CFLAGS=$CFLAGS + CFLAGS="$GL_CFLAGS $LIBDRM_CFLAGS" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include +#include +#ifndef __DRI_DRI2 +#error DRI2 extension not available. +#endif]])], + [HAVE_DRI2EXTENSION=yes], + [HAVE_DRI2EXTENSION=no]) + CFLAGS=$save_CFLAGS + if test "x$HAVE_DRI2EXTENSION" = xyes; then + AC_DEFINE(DRI2_AIGLX, 1, [Build DRI2 AIGLX loader]) + DRI2_AIGLX=yes + else + AC_MSG_NOTICE([DRI2 AIGLX disabled, __DRI_DRI2 not defined in dri_interface.h.]) + DRI2_AIGLX=no + fi +fi +AM_CONDITIONAL(DRI2_AIGLX, test "x$DRI2_AIGLX" = xyes) + + +AM_CONDITIONAL(XINERAMA, [test "x$XINERAMA" = xyes]) +if test "x$XINERAMA" = xyes; then + AC_DEFINE(XINERAMA, 1, [Support Xinerama extension]) + AC_DEFINE(PANORAMIX, 1, [Internal define for Xinerama]) + REQUIRED_MODULES="$REQUIRED_MODULES $XINERAMAPROTO" +fi + +AM_CONDITIONAL(XACE, [test "x$XACE" = xyes]) +if test "x$XACE" = xyes; then + AC_DEFINE(XACE, 1, [Build X-ACE extension]) +fi + +AM_CONDITIONAL(XSELINUX, [test "x$XSELINUX" = xyes]) +if test "x$XSELINUX" = xyes; then + if test "x$XACE" != xyes; then + AC_MSG_ERROR([cannot build SELinux extension without X-ACE]) + fi + AC_CHECK_HEADERS([libaudit.h], [], AC_MSG_ERROR([SELinux extension requires audit system headers])) + AC_CHECK_LIB(audit, audit_open, [], AC_MSG_ERROR([SELinux extension requires audit system library])) + PKG_CHECK_MODULES([SELINUX], $LIBSELINUX) + SELINUX_LIBS="$SELINUX_LIBS -laudit" + AC_DEFINE(XSELINUX, 1, [Build SELinux extension]) +fi + +AM_CONDITIONAL(XCSECURITY, [test "x$XCSECURITY" = xyes]) +if test "x$XCSECURITY" = xyes; then + if test "x$XACE" != xyes; then + AC_MSG_ERROR([cannot build Security extension without X-ACE]) + fi + AC_DEFINE(XCSECURITY, 1, [Build Security extension]) +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]) + REQUIRED_MODULES="$REQUIRED_MODULES $BIGFONTPROTO" +fi + +AM_CONDITIONAL(DPMSExtension, [test "x$DPMSExtension" = xyes]) +if test "x$DPMSExtension" = xyes; then + AC_DEFINE(DPMSExtension, 1, [Support DPMS extension]) +fi + +if test "x$XCALIBRATE" = xyes && test "$KDRIVE" = yes; then + AC_DEFINE(XCALIBRATE, 1, [Build XCalibrate extension]) + REQUIRED_MODULES="$REQUIRED_MODULES $XCALIBRATEPROTO" +else + XCALIBRATE=no +fi +AM_CONDITIONAL(XCALIBRATE, [test "x$XCALIBRATE" = xyes]) + +AC_DEFINE(RENDER, 1, [Support RENDER extension]) +RENDER_LIB='$(top_builddir)/render/librender.la' +RENDER_INC='-I$(top_srcdir)/render' + +AC_DEFINE(RANDR, 1, [Support RANDR extension]) +RANDR_LIB='$(top_builddir)/randr/librandr.la' +RANDR_INC='-I$(top_srcdir)/randr' + +AC_DEFINE(XFIXES,1,[Support XFixes extension]) +FIXES_LIB='$(top_builddir)/xfixes/libxfixes.la' +FIXES_INC='-I$(top_srcdir)/xfixes' + +AC_DEFINE(DAMAGE,1,[Support Damage extension]) +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' + +# XINPUT extension is integral part of the server +AC_DEFINE(XINPUT, 1, [Support X Input extension]) +XI_LIB='$(top_builddir)/Xi/libXi.la' +XI_INC='-I$(top_srcdir)/Xi' + +AM_CONDITIONAL(XF86UTILS, test "x$XF86UTILS" = xyes) +AM_CONDITIONAL(XAA, test "x$XAA" = xyes) +AM_CONDITIONAL(VGAHW, test "x$VGAHW" = xyes) +AM_CONDITIONAL(VBE, test "x$VBE" = xyes) +AM_CONDITIONAL(INT10MODULE, test "x$INT10MODULE" = xyes) + +AC_DEFINE(SHAPE, 1, [Support SHAPE extension]) + +AC_DEFINE_DIR(XKB_BASE_DIRECTORY, XKBPATH, [Path to XKB data]) +AC_ARG_WITH(xkb-bin-directory, + AS_HELP_STRING([--with-xkb-bin-directory=DIR], [Directory containing xkbcomp program]), + [XKB_BIN_DIRECTORY="$withval"], + [XKB_BIN_DIRECTORY="$bindir"]) + +AC_DEFINE_DIR(XKB_BIN_DIRECTORY, XKB_BIN_DIRECTORY, [Path to XKB bin dir]) + +dnl Make sure XKM_OUTPUT_DIR is an absolute path +XKBOUTPUT_FIRSTCHAR=`echo $XKBOUTPUT | cut -b 1` +if [[ x$XKBOUTPUT_FIRSTCHAR != x/ -a x$XKBOUTPUT_FIRSTCHAR != 'x$' ]] ; then + XKBOUTPUT="$XKB_BASE_DIRECTORY/$XKBOUTPUT" +fi + +dnl XKM_OUTPUT_DIR (used in code) must end in / or file names get hosed +dnl XKB_COMPILED_DIR (used in Makefiles) must not or install-sh gets confused + +XKBOUTPUT=`echo $XKBOUTPUT/ | $SED 's|/*$|/|'` +XKB_COMPILED_DIR=`echo $XKBOUTPUT | $SED 's|/*$||'` +AC_DEFINE_DIR(XKM_OUTPUT_DIR, XKBOUTPUT, [Path to XKB output dir]) +AC_SUBST(XKB_COMPILED_DIR) + +if test "x$XKB_DFLT_RULES" = x; then + case $host_os in + linux*) + dnl doesn't take AutoAddDevices into account, but whatever. + if test "x$CONFIG_HAL" = xyes; then + XKB_DFLT_RULES="evdev" + else + XKB_DFLT_RULES="base" + fi + ;; + *) + XKB_DFLT_RULES="base" + ;; + esac +fi +AC_DEFINE_UNQUOTED(XKB_DFLT_RULES, ["$XKB_DFLT_RULES"], [Default XKB ruleset]) +AC_DEFINE_UNQUOTED(XKB_DFLT_MODEL, ["$XKB_DFLT_MODEL"], [Default XKB model]) +AC_DEFINE_UNQUOTED(XKB_DFLT_LAYOUT, ["$XKB_DFLT_LAYOUT"], [Default XKB layout]) +AC_DEFINE_UNQUOTED(XKB_DFLT_VARIANT, ["$XKB_DFLT_VARIANT"], [Default XKB variant]) +AC_DEFINE_UNQUOTED(XKB_DFLT_OPTIONS, ["$XKB_DFLT_OPTIONS"], [Default XKB options]) + +XKB_LIB='$(top_builddir)/xkb/libxkb.la' +XKB_STUB_LIB='$(top_builddir)/xkb/libxkbstubs.la' +REQUIRED_MODULES="$REQUIRED_MODULES xkbfile" + +AC_CHECK_FUNC(strcasecmp, [], AC_DEFINE([NEED_STRCASECMP], 1, + [Do not have 'strcasecmp'.])) +AC_CHECK_FUNC(strncasecmp, [], AC_DEFINE([NEED_STRNCASECMP], 1, + [Do not have 'strncasecmp'.])) +AC_CHECK_FUNC(strcasestr, [], AC_DEFINE([NEED_STRCASESTR], 1, + [Do not have 'strcasestr'.])) + +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 + +AC_DEFINE_DIR(COMPILEDDEFAULTFONTPATH, FONTPATH, [Default font path]) +AC_DEFINE_DIR(PCI_TXT_IDS_PATH, PCI_TXT_IDS_DIR, [Default PCI text file ID path]) +AC_DEFINE_DIR(SERVER_MISC_CONFIG_PATH, SERVERCONFIG, [Server miscellaneous config path]) +AC_DEFINE_DIR(BASE_FONT_PATH, FONTROOTDIR, [Default base font path]) +AC_DEFINE_DIR(DRI_DRIVER_PATH, DRI_DRIVER_PATH, [Default DRI driver path]) +AC_DEFINE_UNQUOTED(XVENDORNAME, ["$VENDOR_NAME"], [Vendor name]) +AC_DEFINE_UNQUOTED(XVENDORNAMESHORT, ["$VENDOR_NAME_SHORT"], [Short vendor name]) +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]) + +if test -z "$OSNAME"; then + OSNAME="UNKNOWN" +fi + +AC_DEFINE_UNQUOTED(OSNAME, ["$OSNAME"], [Operating System Name]) +AC_DEFINE_UNQUOTED(OSVENDOR, ["$OSVENDOR"], [Operating System Vendor]) +AC_DEFINE_UNQUOTED(BUILDERSTRING, ["$BUILDERSTRING"], [Builder string]) + +AC_SUBST([VENDOR_NAME_SHORT]) +AC_DEFINE_UNQUOTED(VENDOR_NAME, ["$VENDOR_NAME"], [Vendor name]) +AC_DEFINE_UNQUOTED(VENDOR_NAME_SHORT, ["$VENDOR_NAME_SHORT"], [Vendor name]) +AC_DEFINE_UNQUOTED(VENDOR_RELEASE, [$VENDOR_RELEASE], [Vendor release]) +AC_DEFINE_UNQUOTED(VENDOR_MAN_VERSION, ["$VENDOR_MAN_VERSION"], [Vendor man version]) + +AC_DEFINE(NO_LIBCWRAPPER, 1, [Define to 1 if modules should avoid the libcwrapper]) + +if test "x$DEBUGGING" = xyes; then + AC_DEFINE(DEBUG, 1, [Enable debugging code]) +fi +AM_CONDITIONAL(DEBUG, [test "x$DEBUGGING" = xyes]) + +# If unittests aren't explicitly disabled, check for required support +if test "x$UNITTESTS" != xno ; then + PKG_CHECK_MODULES([GLIB], $LIBGLIB, + [HAVE_GLIB=yes], [HAVE_GLIB=no]) + + # Check if linker supports -wrap, passed via compiler flags + # When cross-compiling, reports no, since unit tests run from + # "make check", so would be running on build machine, not target + AC_MSG_CHECKING([whether the linker supports -wrap]) + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,-wrap,exit" + AC_RUN_IFELSE([AC_LANG_PROGRAM([[ + void __wrap_exit (int s) + { + __real_exit (0); + }]], + [[exit (1);]])], + [linker_can_wrap="yes"], + [linker_can_wrap="no"], + [linker_can_wrap="no"]) + AC_MSG_RESULT([$linker_can_wrap]) + LDFLAGS="$save_LDFLAGS" +fi + +if test "x$UNITTESTS" = xauto; then + if test "x$HAVE_GLIB" = xyes && test "x$linker_can_wrap" = xyes; then + UNITTESTS=yes + else + UNITTESTS=no + fi +fi +if test "x$UNITTESTS" = xyes; then + if test "x$HAVE_GLIB" = xno; then + AC_MSG_ERROR([glib required to build unit tests]) + fi + if test "x$linker_can_wrap" = xno; then + AC_MSG_ERROR([ld -wrap support required to build unit tests]) + fi + AC_DEFINE(UNITTESTS, 1, [Enable unit tests]) + AC_SUBST([GLIB_LIBS]) + AC_SUBST([GLIB_CFLAGS]) +fi +AM_CONDITIONAL(UNITTESTS, [test "x$UNITTESTS" = xyes]) + +AC_DEFINE(XTEST, 1, [Support XTest extension]) +AC_DEFINE(XSYNC, 1, [Support XSync extension]) +AC_DEFINE(XCMISC, 1, [Support XCMisc extension]) +AC_DEFINE(BIGREQS, 1, [Support BigRequests extension]) + +if test "x$SPECIAL_DTRACE_OBJECTS" = "xyes" ; then + DIX_LIB='$(top_builddir)/dix/dix.O' + OS_LIB='$(top_builddir)/os/os.O $(SHA1_LIBS)' +else + DIX_LIB='$(top_builddir)/dix/libdix.la' + OS_LIB='$(top_builddir)/os/libos.la' +fi +AC_SUBST([DIX_LIB]) +AC_SUBST([OS_LIB]) + +MAIN_LIB='$(top_builddir)/dix/libmain.la' +AC_SUBST([MAIN_LIB]) + +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' + +# SHA1 hashing +AC_ARG_WITH([sha1], + [AS_HELP_STRING([--with-sha1=libc|libmd|libgcrypt|libcrypto|libsha1|CommonCrypto], + [choose SHA1 implementation])]) +AC_CHECK_FUNC([SHA1Init], [HAVE_SHA1_IN_LIBC=yes]) +if test "x$with_sha1" = x && test "x$HAVE_SHA1_IN_LIBC" = xyes; then + with_sha1=libc +fi +if test "x$with_sha1" = xlibc && test "x$HAVE_SHA1_IN_LIBC" != xyes; then + AC_MSG_ERROR([libc requested but not found]) +fi +if test "x$with_sha1" = xlibc; then + AC_DEFINE([HAVE_SHA1_IN_LIBC], [1], + [Use libc SHA1 functions]) + SHA1_LIBS="" +fi +AC_CHECK_FUNC([CC_SHA1_Init], [HAVE_SHA1_IN_COMMONCRYPTO=yes]) +if test "x$with_sha1" = x && test "x$HAVE_SHA1_IN_COMMONCRYPTO" = xyes; then + with_sha1=CommonCrypto +fi +if test "x$with_sha1" = xCommonCrypto && test "x$HAVE_SHA1_IN_COMMONCRYPTO" != xyes; then + AC_MSG_ERROR([CommonCrypto requested but not found]) +fi +if test "x$with_sha1" = xCommonCrypto; then + AC_DEFINE([HAVE_SHA1_IN_COMMONCRYPTO], [1], + [Use CommonCrypto SHA1 functions]) + SHA1_LIBS="" +fi +AC_CHECK_LIB([md], [SHA1Init], [HAVE_LIBMD=yes]) +if test "x$with_sha1" = x && test "x$HAVE_LIBMD" = xyes; then + with_sha1=libmd +fi +if test "x$with_sha1" = xlibmd && test "x$HAVE_LIBMD" != xyes; then + AC_MSG_ERROR([libmd requested but not found]) +fi +if test "x$with_sha1" = xlibmd; then + AC_DEFINE([HAVE_SHA1_IN_LIBMD], [1], + [Use libmd SHA1 functions]) + SHA1_LIBS=-lmd +fi +AC_CHECK_LIB([sha1], [sha1_begin], [HAVE_LIBSHA1=yes]) +if test "x$with_sha1" = x && test "x$HAVE_LIBSHA1" = xyes; then + with_sha1=libsha1 +fi +if test "x$with_sha1" = xlibsha1 && test "x$HAVE_LIBSHA1" != xyes; then + AC_MSG_ERROR([libsha1 requested but not found]) +fi +if test "x$with_sha1" = xlibsha1; then + AC_DEFINE([HAVE_SHA1_IN_LIBSHA1], [1], + [Use libsha1 for SHA1]) + SHA1_LIBS=-lsha1 +fi +AC_CHECK_LIB([gcrypt], [gcry_md_open], [HAVE_LIBGCRYPT=yes]) +if test "x$with_sha1" = x && test "x$HAVE_LIBGCRYPT" = xyes; then + with_sha1=libgcrypt +fi +if test "x$with_sha1" = xlibgcrypt && test "x$HAVE_LIBGCRYPT" != xyes; then + AC_MSG_ERROR([libgcrypt requested but not found]) +fi +if test "x$with_sha1" = xlibgcrypt; then + AC_DEFINE([HAVE_SHA1_IN_LIBGCRYPT], [1], + [Use libgcrypt SHA1 functions]) + SHA1_LIBS=-lgcrypt +fi +# We don't need all of the OpenSSL libraries, just libcrypto +AC_CHECK_LIB([crypto], [SHA1_Init], [HAVE_LIBCRYPTO=yes]) +PKG_CHECK_MODULES([OPENSSL], [openssl], [HAVE_OPENSSL_PKC=yes], + [HAVE_OPENSSL_PKC=no]) +if test "x$HAVE_LIBCRYPTO" = xyes || test "x$HAVE_OPENSSL_PKC" = xyes; then + if test "x$with_sha1" = x; then + with_sha1=libcrypto + fi +else + if test "x$with_sha1" = xlibcrypto; then + AC_MSG_ERROR([OpenSSL libcrypto requested but not found]) + fi +fi +if test "x$with_sha1" = xlibcrypto; then + if test "x$HAVE_LIBCRYPTO" = xyes; then + SHA1_LIBS=-lcrypto + else + SHA1_LIBS="$OPENSSL_LIBS" + SHA1_CFLAGS="$OPENSSL_CFLAGS" + fi +fi +AC_MSG_CHECKING([for SHA1 implementation]) +if test "x$with_sha1" = x; then + AC_MSG_ERROR([No suitable SHA1 implementation found]) +fi +AC_MSG_RESULT([$with_sha1]) +AC_SUBST(SHA1_LIBS) +AC_SUBST(SHA1_CFLAGS) + +PKG_CHECK_MODULES([XSERVERCFLAGS], [$REQUIRED_MODULES $REQUIRED_LIBS]) +PKG_CHECK_MODULES([XSERVERLIBS], [$REQUIRED_LIBS]) + +# Autotools has some unfortunate issues with library handling. In order to +# get a server to rebuild when a dependency in the tree is changed, it must +# be listed in SERVERNAME_DEPENDENCIES. However, no system libraries may be +# listed there, or some versions of autotools will break (especially if a -L +# is required to find the library). So, we keep two sets of libraries +# detected: NAMESPACE_LIBS for in-tree libraries to be linked against, which +# will go into the _DEPENDENCIES and _LDADD of the server, and +# NAMESPACE_SYS_LIBS which will go into only the _LDADD. The +# NAMESPACEMODULES_LIBS detected from pkgconfig should always go in +# NAMESPACE_SYS_LIBS. +# +# XSERVER_LIBS is the set of in-tree libraries which all servers require. +# XSERVER_SYS_LIBS is the set of out-of-tree libraries which all servers +# require. +# +XSERVER_CFLAGS="${XSERVER_CFLAGS} ${XSERVERCFLAGS_CFLAGS}" +XSERVER_LIBS="$DIX_LIB $CONFIG_LIB $MI_LIB $OS_LIB" +XSERVER_SYS_LIBS="${XSERVERLIBS_LIBS} ${SYS_LIBS} ${LIBS}" +AC_SUBST([XSERVER_LIBS]) +AC_SUBST([XSERVER_SYS_LIBS]) + +UTILS_SYS_LIBS="${SYS_LIBS}" +AC_SUBST([UTILS_SYS_LIBS]) + +# The Xorg binary needs to export symbols so that they can be used from modules +# Some platforms require extra flags to do this. libtool should set the +# necessary flags for each platform when -export-dynamic is passed to it. +LD_EXPORT_SYMBOLS_FLAG="-export-dynamic" +AC_SUBST([LD_EXPORT_SYMBOLS_FLAG]) + +dnl Imake defines SVR4 on SVR4 systems, and many files check for it, so +dnl we need to replicate that here until those can all be fixed +AC_MSG_CHECKING([if SVR4 needs to be defined]) +AC_EGREP_CPP([I_AM_SVR4],[ +#if defined(SVR4) || defined(__svr4__) || defined(__SVR4) + I_AM_SVR4 +#endif +],[ +AC_DEFINE([SVR4],1,[Define to 1 on systems derived from System V Release 4]) +AC_MSG_RESULT([yes])], AC_MSG_RESULT([no])) + +XSERVER_CFLAGS="$XSERVER_CFLAGS $CORE_INCS $XEXT_INC $COMPOSITE_INC $DAMAGE_INC $FIXES_INC $XI_INC $MI_INC $MIEXT_SHADOW_INC $MIEXT_LAYER_INC $MIEXT_DAMAGE_INC $RENDER_INC $RANDR_INC $FB_INC" + +dnl --------------------------------------------------------------------------- +dnl DDX section. +dnl --------------------------------------------------------------------------- + +dnl Xvfb DDX + +AC_MSG_CHECKING([whether to build Xvfb DDX]) +AC_MSG_RESULT([$XVFB]) +AM_CONDITIONAL(XVFB, [test "x$XVFB" = xyes]) + +if test "x$XVFB" = xyes; then + XVFB_LIBS="$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB" + XVFB_SYS_LIBS="$XVFBMODULES_LIBS $GLX_SYS_LIBS" + AC_SUBST([XVFB_LIBS]) + AC_SUBST([XVFB_SYS_LIBS]) +fi + + +dnl Xnest DDX + +PKG_CHECK_MODULES(XNESTMODULES, [xfont $LIBXEXT x11 xau $XDMCP_MODULES], [have_xnest=yes], [have_xnest=no]) +AC_MSG_CHECKING([whether to build Xnest DDX]) +if test "x$XNEST" = xauto; then + XNEST="$have_xnest" +fi +AC_MSG_RESULT([$XNEST]) +AM_CONDITIONAL(XNEST, [test "x$XNEST" = xyes]) + +if test "x$XNEST" = xyes; then + if test "x$have_xnest" = xno; then + AC_MSG_ERROR([Xnest build explicitly requested, but required modules not found.]) + fi + XNEST_LIBS="$FB_LIB $FIXES_LIB $MI_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $DIX_LIB $MAIN_LIB $OS_LIB $CONFIG_LIB" + XNEST_SYS_LIBS="$XNESTMODULES_LIBS $GLX_SYS_LIBS" + AC_SUBST([XNEST_LIBS]) + AC_SUBST([XNEST_SYS_LIBS]) +fi + + +dnl Xorg DDX + +AC_MSG_CHECKING([whether to build Xorg DDX]) +if test "x$XORG" = xauto; then + XORG="yes" + case $host_os in + cygwin*) XORG="no" ;; + darwin*) XORG="no" ;; + esac +fi +AC_MSG_RESULT([$XORG]) + +xorg_bus_linuxpci=no +xorg_bus_bsdpci=no +xorg_bus_sparc=no + +if test "x$XORG" = xyes; then + XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' + XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' + XORG_INCS="$XORG_DDXINCS $XORG_OSINCS" + XORG_CFLAGS="$XORGSERVER_CFLAGS -DHAVE_XORG_CONFIG_H" + XORG_LIBS="$COMPOSITE_LIB $FIXES_LIB $XEXTXORG_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB" + + dnl ================================================================== + dnl symbol visibility + symbol_visibility= + have_visibility=disabled + if test x$SYMBOL_VISIBILITY != xno; then + AC_MSG_CHECKING(for symbol visibility support) + if test x$GCC = xyes; then + VISIBILITY_CFLAGS="-fvisibility=hidden" + else + AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"]) + if test x$SUNCC = xyes; then + VISIBILITY_CFLAGS="-xldscope=hidden" + else + have_visibility=no + fi + fi + if test x$have_visibility != xno; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $VISIBILITY_CFLAGS" + AC_TRY_COMPILE( + [#include + extern _X_HIDDEN int hidden_int; + extern _X_EXPORT int public_int; + extern _X_HIDDEN int hidden_int_func(void); + extern _X_EXPORT int public_int_func(void);], + [], + have_visibility=yes, + have_visibility=no) + CFLAGS=$save_CFLAGS + fi + AC_MSG_RESULT([$have_visibility]) + if test x$have_visibility != xno; then + symbol_visibility=$VISIBILITY_CFLAGS + XORG_CFLAGS="$XORG_CFLAGS $VISIBILITY_CFLAGS" + XSERVER_CFLAGS="$XSERVER_CFLAGS $VISIBILITY_CFLAGS" + fi + fi + dnl added to xorg-server.pc + AC_SUBST([symbol_visibility]) + dnl =================================================================== + + PKG_CHECK_MODULES([PCIACCESS], $LIBPCIACCESS) + SAVE_LIBS=$LIBS + SAVE_CFLAGS=$CFLAGS + CFLAGS=$PCIACCESS_CFLAGS + LIBS=$PCIACCESS_LIBS + AC_CHECK_FUNCS([pci_system_init_dev_mem]) + AC_CHECK_FUNCS([pci_device_enable]) + AC_CHECK_FUNCS([pci_device_is_boot_vga]) + AC_CHECK_FUNCS([pci_device_vgaarb_init]) + LIBS=$SAVE_LIBS + CFLAGS=$SAVE_CFLAGS + XORG_SYS_LIBS="$XORG_SYS_LIBS $PCIACCESS_LIBS $GLX_SYS_LIBS" + XORG_CFLAGS="$XORG_CFLAGS $PCIACCESS_CFLAGS" + + case $host_os in + linux*) + if test "x$LNXAPM" = xyes; then + XORG_CFLAGS="$XORG_CFLAGS -DXF86PM" + fi + XORG_OS="linux" + XORG_OS_SUBDIR="linux" + xorg_bus_linuxpci="yes" + linux_acpi="no" + case $host_cpu in + ia64*) + linux_ia64=yes + linux_acpi="yes" + ;; + alpha*) + linux_alpha=yes + ;; + i*86|amd64*|x86_64*) + linux_acpi="yes" + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + XORG_OS="freebsd" + XORG_OS_SUBDIR="bsd" + xorg_bus_bsdpci="yes" + ;; + netbsd*) + XORG_OS="netbsd" + XORG_OS_SUBDIR="bsd" + xorg_bus_bsdpci="yes" + ;; + openbsd*) + if test "x$ac_cv_BSD_APM" = xyes \ + -o "x$ac_cv_BSD_KQUEUE_APM" = xyes; then + XORG_CFLAGS="$XORG_CFLAGS -DXF86PM" + fi + XORG_OS="openbsd" + XORG_OS_SUBDIR="bsd" + xorg_bus_bsdpci="yes" + ;; + solaris*) + XORG_OS="solaris" + XORG_OS_SUBDIR="solaris" + XORG_CFLAGS="$XORG_CFLAGS -DXF86PM" + # Use the same stubs as BSD for old functions, since we now + # use libpciaccess for PCI + xorg_bus_bsdpci="yes" + AC_CHECK_HEADERS([sys/kd.h]) + AC_CHECK_HEADERS([sys/vt.h], [solaris_vt=yes], [solaris_vt=no]) + # Check for minimum supported release + AC_MSG_CHECKING([Solaris version]) + OS_MINOR=`echo ${host_os}|$SED -e 's/^.*solaris2\.//' -e s'/\..*$//'` + if test "${OS_MINOR}" -ge 7 ; then + AC_MSG_RESULT(Solaris ${OS_MINOR}) + else + AC_MSG_RESULT(Solaris `echo ${host_os}|$SED -e 's/^.*solaris//`) + fi + if test "${OS_MINOR}" -lt 8 ; then + AC_MSG_ERROR([This release no longer supports Solaris versions older than Solaris 8.]) + fi + AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"]) + if test "x$SUNCC" = "xyes"; then + solaris_asm_inline="yes" + fi + AC_CHECK_DECL([_LP64], [SOLARIS_64="yes"], [SOLARIS_64="no"]) + + case $host_cpu in + sparc*) + SOLARIS_INOUT_ARCH="sparcv8plus" + ;; + i*86) + if test x$SOLARIS_64 = xyes ; then + SOLARIS_INOUT_ARCH="amd64" + else + SOLARIS_INOUT_ARCH="ia32" + fi + ;; + *) + AC_MSG_ERROR([Unsupported Solaris platform. Only SPARC & x86 \ + are supported on Solaris in this release. If you are \ + interested in porting Xorg to your platform, please email \ + xorg@lists.freedesktop.org.]) ;; + esac + AC_SUBST([SOLARIS_INOUT_ARCH]) + if test x$solaris_asm_inline = xyes ; then + SOLARIS_ASM_CFLAGS='$(top_srcdir)/hw/xfree86/os-support/solaris/solaris-$(SOLARIS_INOUT_ARCH).il' + XORG_CFLAGS="${XORG_CFLAGS} "'$(SOLARIS_ASM_CFLAGS)' + fi + AC_SUBST([SOLARIS_ASM_CFLAGS]) + if test "x$SUPPORT_PC98" = xauto; then + SUPPORT_PC98="no" + fi + ;; + gnu*) + XORG_OS="gnu" + XORG_OS_SUBDIR="hurd" + # Use the same stubs as BSD for old functions, since we now + # use libpciaccess for PCI + xorg_bus_bsdpci="yes" + ;; + *) + XORG_OS="unknown" + XORG_OS_SUBDIR="unknown" + AC_MSG_ERROR([m4_text_wrap(m4_join([ ], + [Your OS is unknown. Xorg currently only supports Linux,], + [Free/Open/Net/DragonFlyBSD, Solaris/OpenSolaris, & GNU Hurd.], + [If you are interested in porting Xorg to your platform,], + [please email xorg@lists.freedesktop.org.]))]) + ;; + esac + + case $host_cpu in + sparc*) + xorg_bus_sparc="yes" + ;; + i*86) + if test "x$SUPPORT_PC98" = xauto; then + SUPPORT_PC98="yes" + fi + ;; + esac + + if test "x$SUPPORT_PC98" = xauto; then + SUPPORT_PC98="no" + fi + if test "x$SUPPORT_PC98" = xyes; then + AC_DEFINE(SUPPORT_PC98, 1, [Support PC98]) + fi + if test "x$XORG_OS_PCI" = x ; then + XORG_OS_PCI=$XORG_OS + fi + if test "x$DGA" = xauto; then + PKG_CHECK_MODULES(DGA, $DGAPROTO, [DGA=yes], [DGA=no]) + fi + if test "x$DGA" = xyes; then + XORG_MODULES="$XORG_MODULES $DGAPROTO" + PKG_CHECK_MODULES(DGA, $DGAPROTO) + AC_DEFINE(DGA, 1, [Support DGA extension]) + AC_DEFINE(XFreeXDGA, 1, [Build XDGA support]) + fi + + if test "x$XF86VIDMODE" = xauto; then + PKG_CHECK_MODULES(XF86VIDMODE, $VIDMODEPROTO, [XF86VIDMODE=yes], [XF86VIDMODE=no]) + fi + if test "x$XF86VIDMODE" = xyes; then + XORG_MODULES="$XORG_MODULES $VIDMODEPROTO" + PKG_CHECK_MODULES(XF86VIDMODE, $VIDMODEPROTO) + AC_DEFINE(XF86VIDMODE, 1, [Support XFree86 Video Mode extension]) + fi + + if test -n "$XORG_MODULES"; then + PKG_CHECK_MODULES(XORG_MODULES, [$XORG_MODULES]) + XORG_CFLAGS="$XORG_CFLAGS $XORG_MODULES_CFLAGS" + XORG_SYS_LIBS="$XORG_SYS_LIBS $XORG_MODULES_LIBS" + fi + + AC_SUBST([XORG_LIBS]) + AC_SUBST([XORG_SYS_LIBS]) + AC_SUBST([XORG_INCS]) + AC_SUBST([XORG_OS]) + AC_SUBST([XORG_OS_SUBDIR]) + + AC_PATH_PROG(PERL, perl, no) + dnl unlikely as this may be ... + if test "x$PERL" = xno; then + AC_MSG_ERROR([Perl is required to build the XFree86/Xorg DDX.]) + fi + AC_SUBST(PERL) + + AC_SUBST([XORG_CFLAGS]) + + dnl these only go in xorg-config.h + XF86CONFIGFILE="xorg.conf" + XF86CONFIGDIR="xorg.conf.d" + AC_SUBST(XF86CONFIGDIR) + CONFIGFILE="$sysconfdir/$XF86CONFIGFILE" + LOGPREFIX="$logdir/Xorg." + AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) + AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) + AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) + AC_DEFINE(XFree86LOADER, 1, [Building loadable XFree86 server]) + AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) + AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) + AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) + AC_DEFINE_DIR(__XCONFIGFILE__, XF86CONFIGFILE, [Name of configuration file]) + AC_DEFINE_DIR(XF86CONFIGFILE, XF86CONFIGFILE, [Name of configuration file]) + AC_DEFINE_DIR(__XCONFIGDIR__, XF86CONFIGDIR, [Name of configuration directory]) + AC_DEFINE_DIR(DEFAULT_MODULE_PATH, moduledir, [Default module search path]) + AC_DEFINE_DIR(DEFAULT_LIBRARY_PATH, libdir, [Default library install path]) + AC_DEFINE_DIR(DEFAULT_LOGPREFIX, LOGPREFIX, [Default log location]) + AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support]) + AC_DEFINE(XSERVER_LIBPCIACCESS, 1, [Use libpciaccess for all pci manipulation]) + if test "x$VGAHW" = xyes; then + AC_DEFINE(WITH_VGAHW, 1, [Building vgahw module]) + fi + + driverdir="$moduledir/drivers" + AC_SUBST([moduledir]) + AC_SUBST([driverdir]) + sdkdir="$includedir/xorg" + extdir="$includedir/X11/extensions" + sysconfigdir="$datadir/X11/$XF86CONFIGDIR" + AC_SUBST([sdkdir]) + AC_SUBST([extdir]) + AC_SUBST([sysconfigdir]) + AC_SUBST([logdir]) + + # stuff the ABI versions into the pc file too + extract_abi() { + grep ^.define.*${1}_VERSION ${srcdir}/hw/xfree86/common/xf86Module.h | tr '(),' ' .' | awk '{ print $4$5 }' + } + abi_ansic=`extract_abi ANSIC` + abi_videodrv=`extract_abi VIDEODRV` + abi_xinput=`extract_abi XINPUT` + abi_extension=`extract_abi EXTENSION` + AC_SUBST([abi_ansic]) + AC_SUBST([abi_videodrv]) + AC_SUBST([abi_xinput]) + AC_SUBST([abi_extension]) +fi +AM_CONDITIONAL([XORG], [test "x$XORG" = xyes]) +AM_CONDITIONAL([XORG_BUS_LINUXPCI], [test "x$xorg_bus_linuxpci" = xyes]) +AM_CONDITIONAL([XORG_BUS_BSDPCI], [test "x$xorg_bus_bsdpci" = xyes]) +AM_CONDITIONAL([XORG_BUS_SPARC], [test "x$xorg_bus_sparc" = 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]) +AM_CONDITIONAL([SOLARIS_ASM_INLINE], [test "x$solaris_asm_inline" = xyes]) +AM_CONDITIONAL([SOLARIS_VT], [test "x$solaris_vt" = xyes]) +AM_CONDITIONAL([DGA], [test "x$DGA" = xyes]) +AM_CONDITIONAL([XF86VIDMODE], [test "x$XF86VIDMODE" = xyes]) + +dnl XWin DDX + +AC_MSG_CHECKING([whether to build XWin DDX]) +if test "x$XWIN" = xauto; then + case $host_os in + cygwin*) XWIN="yes" ;; + mingw*) XWIN="yes" ;; + *) XWIN="no" ;; + esac +fi +AC_MSG_RESULT([$XWIN]) + +if test "x$XWIN" = xyes; then + AC_DEFINE_DIR(SYSCONFDIR, sysconfdir, [Location of system.XWinrc]) + AC_DEFINE_DIR(DEFAULT_LOGDIR, logdir, [Default log location]) + AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support]) + AC_CHECK_TOOL(WINDRES, windres) + + PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau xfont]) + + if test "x$WINDOWSWM" = xauto; then + PKG_CHECK_EXISTS($WINDOWSWMPROTO, [WINDOWSWM=yes], [WINDOWSWM=no]) + fi + if test "x$WINDOWSWM" = xyes ; then + PKG_CHECK_MODULES(WINDOWSWM, $WINDOWSWMPROTO) + XWINMODULES_CFLAGS="$XWINMODULES_CFLAGS $WINDOWSWM_CFLAGS" + AC_DEFINE(ROOTLESS,1,[Build Rootless code]) + fi + + case $host_os in + cygwin*) + XWIN_SERVER_NAME=XWin + AC_DEFINE(HAS_DEVWINDOWS,1,[Cygwin has /dev/windows for signaling new win32 messages]) + ;; + mingw*) + XWIN_SERVER_NAME=Xming + AC_DEFINE(RELOCATE_PROJECTROOT,1,[Make PROJECT_ROOT relative to the xserver location]) + AC_DEFINE(HAS_WINSOCK,1,[Use Windows sockets]) + XWIN_SYS_LIBS=-lwinsock2 + ;; + esac + XWIN_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $RANDR_LIB $RENDER_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $OS_LIB" + XWIN_SYS_LIBS="$XWIN_SYS_LIBS $XWINMODULES_LIBS" + AC_SUBST(XWIN_LIBS) + AC_SUBST(XWIN_SERVER_NAME) + AC_SUBST(XWIN_SYS_LIBS) + + if test "x$DEBUGGING" = xyes; then + AC_DEFINE(CYGDEBUG, 1, [Simple debug messages]) + AC_DEFINE(CYGWINDOWING_DEBUG, 1, [Debug messages for window handling]) + AC_DEFINE(CYGMULTIWINDOW_DEBUG, 1, [Debug window manager]) + fi + + AC_DEFINE(DDXOSVERRORF, 1, [Use OsVendorVErrorF]) + AC_DEFINE(DDXBEFORERESET, 1, [Use ddxBeforeReset ]) +fi +AM_CONDITIONAL(XWIN, [test "x$XWIN" = xyes]) +AM_CONDITIONAL(XWIN_MULTIWINDOW, [test "x$XWIN" = xyes]) +AM_CONDITIONAL(XWIN_MULTIWINDOWEXTWM, [test "x$XWIN" = xyes && test "x$WINDOWSWM" = xyes]) +AM_CONDITIONAL(XWIN_CLIPBOARD, [test "x$XWIN" = xyes]) +AM_CONDITIONAL(XWIN_GLX_WINDOWS, [test "x$XWIN" = xyes && false]) +AM_CONDITIONAL(XWIN_NATIVEGDI, [test "x$XWIN" = xyes && false]) +AM_CONDITIONAL(XWIN_PRIMARYFB, [test "x$XWIN" = xyes && false]) +AM_CONDITIONAL(XWIN_RANDR, [test "x$XWIN" = xyes]) +AM_CONDITIONAL(XWIN_XV, [test "x$XWIN" = xyes && test "x$XV" = xyes]) + +dnl Darwin / OS X DDX +if test "x$XQUARTZ" = xyes; then + AC_DEFINE(XQUARTZ,1,[Have Quartz]) + AC_DEFINE(ROOTLESS,1,[Build Rootless code]) + + DARWIN_LIBS="$MI_LIB $OS_LIB $DIX_LIB $MAIN_LIB $FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $XPSTUBS_LIB" + AC_SUBST([DARWIN_LIBS]) + + AC_CHECK_LIB([Xplugin],[xp_init],[:]) + + CFLAGS="${CFLAGS} -DROOTLESS_WORKAROUND -DROOTLESS_SAFEALPHA -DNO_ALLOCA" + + PKG_CHECK_MODULES(XPBPROXY, $APPLEWMPROTO $LIBAPPLEWM xfixes x11) + + if test "x$XQUARTZ_SPARKLE" = xyes ; then + AC_DEFINE(XQUARTZ_SPARKLE,1,[Support application updating through sparkle.]) + fi + + if test "x$STANDALONE_XPBPROXY" = xyes ; then + AC_DEFINE(STANDALONE_XPBPROXY,1,[Build a standalone xpbproxy]) + fi +fi + +# Support for objc in autotools is minimal and not documented. +OBJC='$(CC)' +OBJCLD='$(CCLD)' +OBJCLINK='$(LINK)' +OBJCFLAGS='$(CFLAGS)' +AC_SUBST([OBJC]) +AC_SUBST([OBJCCLD]) +AC_SUBST([OBJCLINK]) +AC_SUBST([OBJCFLAGS]) +# internal, undocumented automake func follows :( +_AM_DEPENDENCIES([OBJC]) +AM_CONDITIONAL(XQUARTZ, [test "x$XQUARTZ" = xyes]) +AM_CONDITIONAL(XQUARTZ_SPARKLE, [test "x$XQUARTZ_SPARKLE" != "xno"]) +AM_CONDITIONAL(STANDALONE_XPBPROXY, [test "x$STANDALONE_XPBPROXY" = xyes]) + +dnl DMX DDX +PKG_CHECK_MODULES( + [DMXMODULES], + [xmuu $LIBXEXT x11 xrender xfixes xfont $LIBXI $DMXPROTO xau $XDMCP_MODULES], + [PKG_CHECK_MODULES( + [XDMXCONFIG_DEP], + [xaw7 xmu xt xpm x11], + [have_dmx=yes], + [have_dmx=no])], + [have_dmx=no]) +AC_MSG_CHECKING([whether to build Xdmx DDX]) +if test "x$DMX" = xauto; then + DMX="$have_dmx" + case $host_os in + cygwin*) DMX="no" ;; + darwin*) DMX="no" ;; + esac +fi +AC_MSG_RESULT([$DMX]) +AM_CONDITIONAL(DMX, [test "x$DMX" = xyes]) + +if test "x$DMX" = xyes; then + if test "x$have_dmx" = xno; then + AC_MSG_ERROR([Xdmx build explicitly requested, but required + modules not found.]) + fi + DMX_INCLUDES="$XEXT_INC $RENDER_INC $RECORD_INC" + XDMX_CFLAGS="$DMXMODULES_CFLAGS" + XDMX_LIBS="$FB_LIB $MI_LIB $RENDER_LIB $RECORD_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $MIEXT_SHADOW_LIB $MIEXT_DAMAGE_LIB $XEXT_LIB $MAIN_LIB $DIX_LIB $CONFIG_LIB $OS_LIB $FIXES_LIB" + XDMX_SYS_LIBS="$DMXMODULES_LIBS" + AC_SUBST([XDMX_CFLAGS]) + AC_SUBST([XDMX_LIBS]) + AC_SUBST([XDMX_SYS_LIBS]) + +dnl USB sources in DMX require + AC_CHECK_HEADER([linux/input.h], DMX_BUILD_USB="yes", + DMX_BUILD_USB="no") +dnl Linux sources in DMX require + AC_CHECK_HEADER([linux/keyboard.h], DMX_BUILD_LNX="yes", + DMX_BUILD_LNX="no") + AC_SUBST(XDMXCONFIG_DEP_CFLAGS) + AC_SUBST(XDMXCONFIG_DEP_LIBS) + PKG_CHECK_MODULES([DMXEXAMPLES_DEP], [$LIBDMX $LIBXEXT x11]) + AC_SUBST(DMXEXAMPLES_DEP_LIBS) + PKG_CHECK_MODULES([DMXXMUEXAMPLES_DEP], [$LIBDMX xmu $LIBXEXT x11]) + AC_SUBST(DMXXMUEXAMPLES_DEP_LIBS) + PKG_CHECK_MODULES([DMXXIEXAMPLES_DEP], [$LIBDMX $LIBXI $LIBXEXT x11]) + AC_SUBST(DMXXIEXAMPLES_DEP_LIBS) + PKG_CHECK_MODULES([XTSTEXAMPLES_DEP], [$LIBXTST $LIBXEXT x11]) + AC_SUBST(XTSTEXAMPLES_DEP_LIBS) + PKG_CHECK_MODULES([XRESEXAMPLES_DEP], [xres $LIBXEXT x11]) + AC_SUBST(XRESEXAMPLES_DEP_LIBS) + PKG_CHECK_MODULES([X11EXAMPLES_DEP], [$LIBXEXT x11]) + AC_SUBST(X11EXAMPLES_DEP_LIBS) + +fi +AM_CONDITIONAL([DMX_BUILD_LNX], [test "x$DMX_BUILD_LNX" = xyes]) +AM_CONDITIONAL([DMX_BUILD_USB], [test "x$DMX_BUILD_USB" = xyes]) + +dnl kdrive DDX + +XEPHYR_LIBS= +XEPHYR_INCS= + +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([linux/fb.h]) + if test "$ac_cv_header_linux_fb_h" = yes && test "x$XFBDEV" = xauto; then + XFBDEV=yes + fi + + if test "x$XFBDEV" = xyes; then + KDRIVEFBDEVLIB=yes + AC_DEFINE(KDRIVEFBDEV, 1, [Build fbdev-based kdrive server]) + fi + + + PKG_CHECK_MODULES([TSLIB], [tslib-0.0], [HAVE_TSLIB="yes"], [HAVE_TSLIB="no"]) + if test "x$HAVE_TSLIB" = xno; then + AC_CHECK_LIB(ts, ts_open, [HAVE_TSLIB="yes"]) + fi + + if test "xTSLIB" = xauto; then + TSLIB="$HAVE_TSLIB" + fi + + if test "x$TSLIB" = xyes; then + if ! test "x$HAVE_TSLIB" = xyes; then + AC_MSG_ERROR([tslib must be installed to build the tslib driver. See http://tslib.berlios.de/]) + else + AC_DEFINE(TSLIB, 1, [Have tslib support]) + fi + fi + + if test "x$KDRIVE_KBD" = xyes; then + AC_DEFINE(KDRIVE_KBD, 1, [Enable KDrive kbd driver]) + fi + if test "x$KDRIVE_EVDEV" = xyes; then + AC_DEFINE(KDRIVE_EVDEV, 1, [Enable KDrive evdev driver]) + fi + if test "x$KDRIVE_MOUSE" = xyes; then + AC_DEFINE(KDRIVE_MOUSE, 1, [Enable KDrive mouse driver]) + fi + + XEPHYR_REQUIRED_LIBS="x11 $LIBXEXT xfont xau xdmcp" + if test "x$XV" = xyes; then + XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xv" + fi + if test "x$DRI" = xyes && test "x$GLX" = xyes; then + XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS $LIBGL libdrm" + fi + + PKG_CHECK_MODULES(XEPHYR, $XEPHYR_REQUIRED_LIBS, [xephyr="yes"], [xephyr="no"]) + if test "x$XEPHYR" = xauto; then + XEPHYR=$xephyr + fi + + # Xephyr needs nanosleep() which is in librt on Solaris + AC_CHECK_FUNC([nanosleep], [], + AC_CHECK_LIB([rt], [nanosleep], XEPHYR_LIBS="$XEPHYR_LIBS -lrt")) + + # damage shadow extension glx (NOTYET) fb mi + KDRIVE_INC='-I$(top_srcdir)/hw/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)/hw/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS -DHAVE_KDRIVE_CONFIG_H $TSLIB_CFLAGS" + + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + case $host_os in + *linux*) + KDRIVE_OS_LIB='$(top_builddir)/hw/kdrive/linux/liblinux.la' + KDRIVELINUX=yes + if test "x$KDRIVE_EVDEV" = xauto; then + KDRIVE_EVDEV=yes + fi + if test "x$KDRIVE_KBD" = xauto; then + KDRIVE_KBD=yes + fi + if test "x$KDRIVE_MOUSE" = xauto; then + KDRIVE_MOUSE=yes + fi + ;; + *) + if test "x$KDRIVE_EVDEV" = xauto; then + KDRIVE_EVDEV=no + fi + if test "x$KDRIVE_KBD" = xauto; then + KDRIVE_KBD=no + fi + if test "x$KDRIVE_MOUSE" = xauto; then + KDRIVE_MOUSE=no + fi + ;; + esac + KDRIVE_STUB_LIB='$(top_builddir)/hw/kdrive/src/libkdrivestubs.la' + KDRIVE_LOCAL_LIBS="$MAIN_LIB $DIX_LIB $KDRIVE_LIB $KDRIVE_STUB_LIB $CONFIG_LIB" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $FB_LIB $MI_LIB $KDRIVE_PURE_LIBS" + KDRIVE_LOCAL_LIBS="$KDRIVE_LOCAL_LIBS $KDRIVE_OS_LIB $OS_LIB" + KDRIVE_LIBS="$TSLIB_LIBS $KDRIVE_LOCAL_LIBS $XSERVER_SYS_LIBS $GLX_SYS_LIBS $DLOPEN_LIBS" + + AC_SUBST([XEPHYR_LIBS]) + AC_SUBST([XEPHYR_INCS]) +fi +AC_SUBST([KDRIVE_INCS]) +AC_SUBST([KDRIVE_PURE_INCS]) +AC_SUBST([KDRIVE_CFLAGS]) +AC_SUBST([KDRIVE_PURE_LIBS]) +AC_SUBST([KDRIVE_LOCAL_LIBS]) +AC_SUBST([KDRIVE_LIBS]) +AM_CONDITIONAL(KDRIVELINUX, [test "x$KDRIVELINUX" = xyes]) +AM_CONDITIONAL(KDRIVE_EVDEV, [test "x$KDRIVE_EVDEV" = xyes]) +AM_CONDITIONAL(KDRIVE_KBD, [test "x$KDRIVE_KBD" = xyes]) +AM_CONDITIONAL(KDRIVE_MOUSE, [test "x$KDRIVE_MOUSE" = xyes]) +AM_CONDITIONAL(TSLIB, [test "x$HAVE_TSLIB" = xyes]) +AM_CONDITIONAL(KDRIVEFBDEV, [test "x$XFBDEV" = xyes]) +AM_CONDITIONAL(XEPHYR, [test "x$KDRIVE" = xyes && test "x$XEPHYR" = xyes]) +AM_CONDITIONAL(BUILD_KDRIVEFBDEVLIB, [test "x$KDRIVE" = xyes && test "x$KDRIVEFBDEVLIB" = xyes]) +AM_CONDITIONAL(XFAKESERVER, [test "x$KDRIVE" = xyes && test "x$XFAKE" = xyes]) + +dnl and the rest of these are generic, so they're in config.h +dnl +dnl though, thanks to the passing of some significant amount of time, the +dnl above is probably a complete fallacy, and you should not rely on it. +dnl but this is still actually better than imake, honest. -daniels + +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])]) + +AC_DEFINE_DIR(PROJECTROOT, prefix, [Overall prefix]) + +BUILD_DATE="`date +'%Y%m%d'`" +AC_SUBST([BUILD_DATE]) +BUILD_TIME="`date +'1%H%M%S'`" +AC_SUBST([BUILD_TIME]) + +DIX_CFLAGS="-DHAVE_DIX_CONFIG_H $XSERVER_CFLAGS" + +AC_SUBST([DIX_CFLAGS]) + +AC_SUBST([libdir]) +AC_SUBST([exec_prefix]) +AC_SUBST([prefix]) + +AC_OUTPUT([ +Makefile +glx/Makefile +include/Makefile +composite/Makefile +damageext/Makefile +dbe/Makefile +dix/Makefile +doc/Makefile +fb/Makefile +record/Makefile +config/Makefile +mi/Makefile +miext/Makefile +miext/damage/Makefile +miext/shadow/Makefile +miext/cw/Makefile +miext/rootless/Makefile +os/Makefile +randr/Makefile +render/Makefile +xkb/Makefile +Xext/Makefile +Xi/Makefile +xfixes/Makefile +exa/Makefile +hw/Makefile +hw/xfree86/Makefile +hw/xfree86/common/Makefile +hw/xfree86/common/xf86Build.h +hw/xfree86/ddc/Makefile +hw/xfree86/dixmods/Makefile +hw/xfree86/dixmods/extmod/Makefile +hw/xfree86/doc/Makefile +hw/xfree86/doc/devel/Makefile +hw/xfree86/doc/man/Makefile +hw/xfree86/doc/sgml/Makefile +hw/xfree86/dri/Makefile +hw/xfree86/dri2/Makefile +hw/xfree86/exa/Makefile +hw/xfree86/fbdevhw/Makefile +hw/xfree86/i2c/Makefile +hw/xfree86/int10/Makefile +hw/xfree86/loader/Makefile +hw/xfree86/modes/Makefile +hw/xfree86/os-support/Makefile +hw/xfree86/os-support/bsd/Makefile +hw/xfree86/os-support/bus/Makefile +hw/xfree86/os-support/hurd/Makefile +hw/xfree86/os-support/misc/Makefile +hw/xfree86/os-support/linux/Makefile +hw/xfree86/os-support/sco/Makefile +hw/xfree86/os-support/solaris/Makefile +hw/xfree86/os-support/sysv/Makefile +hw/xfree86/parser/Makefile +hw/xfree86/ramdac/Makefile +hw/xfree86/shadowfb/Makefile +hw/xfree86/vbe/Makefile +hw/xfree86/vgahw/Makefile +hw/xfree86/x86emu/Makefile +hw/xfree86/xaa/Makefile +hw/xfree86/xf8_16bpp/Makefile +hw/xfree86/utils/Makefile +hw/xfree86/utils/cvt/Makefile +hw/xfree86/utils/gtf/Makefile +hw/dmx/config/Makefile +hw/dmx/doc/Makefile +hw/dmx/examples/Makefile +hw/dmx/input/Makefile +hw/dmx/glxProxy/Makefile +hw/dmx/Makefile +hw/vfb/Makefile +hw/xnest/Makefile +hw/xwin/Makefile +hw/xwin/glx/Makefile +hw/xquartz/Makefile +hw/xquartz/GL/Makefile +hw/xquartz/bundle/Makefile +hw/xquartz/doc/Makefile +hw/xquartz/mach-startup/Makefile +hw/xquartz/pbproxy/Makefile +hw/xquartz/xpr/Makefile +hw/kdrive/Makefile +hw/kdrive/ephyr/Makefile +hw/kdrive/fake/Makefile +hw/kdrive/fbdev/Makefile +hw/kdrive/linux/Makefile +hw/kdrive/src/Makefile +test/Makefile +test/xi2/Makefile +xorg-server.pc +]) diff --git a/xorg-server/damageext/damageext.c b/xorg-server/damageext/damageext.c index 2608e60b3..dfb26c7d7 100644 --- a/xorg-server/damageext/damageext.c +++ b/xorg-server/damageext/damageext.c @@ -162,7 +162,7 @@ ProcDamageQueryVersion(ClientPtr client) swapl(&rep.minorVersion, n); } WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *)&rep); - return(client->noClientException); + return Success; } static int @@ -201,7 +201,7 @@ ProcDamageCreate (ClientPtr client) return BadValue; } - pDamageExt = xalloc (sizeof (DamageExtRec)); + pDamageExt = malloc(sizeof (DamageExtRec)); if (!pDamageExt) return BadAlloc; pDamageExt->id = stuff->damage; @@ -217,7 +217,7 @@ ProcDamageCreate (ClientPtr client) pDamageExt); if (!pDamageExt->pDamage) { - xfree (pDamageExt); + free(pDamageExt); return BadAlloc; } if (!AddResource (stuff->damage, DamageExtType, (pointer) pDamageExt)) @@ -231,7 +231,7 @@ ProcDamageCreate (ClientPtr client) DamageRegionAppend(pDrawable, pRegion); } - return (client->noClientException); + return Success; } static int @@ -243,7 +243,7 @@ ProcDamageDestroy (ClientPtr client) REQUEST_SIZE_MATCH(xDamageDestroyReq); VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess); FreeResource (stuff->damage, RT_NONE); - return (client->noClientException); + return Success; } static int @@ -276,7 +276,7 @@ ProcDamageSubtract (ClientPtr client) DamageEmpty (pDamage); } } - return (client->noClientException); + return Success; } static int @@ -301,7 +301,7 @@ ProcDamageAdd (ClientPtr client) DamageRegionAppend(pDrawable, pRegion); REGION_TRANSLATE(pScreen, pRegion, -pDrawable->x, -pDrawable->y); - return (client->noClientException); + return Success; } /* Major version controls available requests */ @@ -457,7 +457,7 @@ FreeDamageExt (pointer value, XID did) DamageUnregister (pDamageExt->pDrawable, pDamageExt->pDamage); DamageDestroy (pDamageExt->pDamage); } - xfree (pDamageExt); + free(pDamageExt); return Success; } diff --git a/xorg-server/dbe/dbe.c b/xorg-server/dbe/dbe.c index 825d2e08f..a6c1c4f56 100644 --- a/xorg-server/dbe/dbe.c +++ b/xorg-server/dbe/dbe.c @@ -1,1685 +1,1679 @@ -/****************************************************************************** - * - * 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 -#if HAVE_STDINT_H -#include -#elif !defined(UINT32_MAX) -#define UINT32_MAX 0xffffffffU -#endif - -#include -#include -#include "scrnintstr.h" -#include "extnsionst.h" -#include "gcstruct.h" -#include "dixstruct.h" -#define NEED_DBE_PROTOCOL -#include "dbestruct.h" -#include "midbe.h" -#include "xace.h" - -/* GLOBALS */ - -/* These are static globals copied to DBE's screen private for use by DDX */ -static int dbeScreenPrivKeyIndex; -static DevPrivateKey dbeScreenPrivKey = &dbeScreenPrivKeyIndex; -static int dbeWindowPrivKeyIndex; -static DevPrivateKey dbeWindowPrivKey = &dbeWindowPrivKeyIndex; - -/* These are static globals copied to DBE's screen private for use by DDX */ -static RESTYPE dbeDrawableResType; -static RESTYPE dbeWindowPrivResType; - -/* Used to generate DBE's BadBuffer error. */ -static int dbeErrorBase; - -/****************************************************************************** - * - * 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; - - /* 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; - - (*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; - register int n; - - - 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, n); - } - - 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; - register int i; - Bool visualMatched = FALSE; - xDbeSwapAction swapAction; - VisualID visual; - int status; - int add_index; - - - REQUEST_SIZE_MATCH(xDbeAllocateBackBufferNameReq); - - /* The window must be valid. */ - status = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); - if (status != Success) - return status; - - /* 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. */ - xfree(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. - */ - - pDbeWindowPriv = xcalloc(1, sizeof(DbeWindowPrivRec)); - if (!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; - - add_index = 0; - for (i = 0; i < DBE_INIT_MAX_IDS; i++) - { - pDbeWindowPriv->IDs[i] = DBE_FREE_ID_ELEMENT; - } - - /* Actually connect the window priv to the window. */ - dixSetPrivate(&pWin->devPrivates, dbeWindowPrivKey, 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 *)xrealloc(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; - } - - add_index = i; - - } /* 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->IDs[add_index] = stuff->buffer; - if (!AddResource(stuff->buffer, dbeWindowPrivResType, - (pointer)pDbeWindowPriv)) - { - pDbeWindowPriv->IDs[add_index] = DBE_FREE_ID_ELEMENT; - - if (pDbeWindowPriv->nBufferIDs == 0) { - status = BadAlloc; - goto out_free; - } - } - } else { - /* The DDX buffer allocation routine failed for the first buffer of - * this window. - */ - if (pDbeWindowPriv->nBufferIDs == 0) { - goto out_free; - } - } - - /* Increment the number of buffers (XIDs) associated with this window. */ - pDbeWindowPriv->nBufferIDs++; - - /* Set swap action on all calls. */ - pDbeWindowPriv->swapAction = stuff->swapAction; - - return(status); - -out_free: - dixSetPrivate(&pWin->devPrivates, dbeWindowPrivKey, NULL); - xfree(pDbeWindowPriv); - 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 rc, i; - pointer val; - - - REQUEST_SIZE_MATCH(xDbeDeallocateBackBufferNameReq); - - /* Buffer name must be valid */ - rc = dixLookupResourceByType((pointer *)&pDbeWindowPriv, stuff->buffer, - dbeWindowPrivResType, client, - DixDestroyAccess); - if (rc != Success) - return (rc == BadValue) ? dbeErrorBase + DbeBadBuffer : rc; - - rc = dixLookupResourceByType(&val, stuff->buffer, dbeDrawableResType, - client, DixDestroyAccess); - if (rc != Success) - return (rc == BadValue) ? dbeErrorBase + DbeBadBuffer : rc; - - /* 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; - register 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 = (DbeSwapInfoPtr)Xalloc(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. */ - error = dixLookupWindow(&pWin, dbeSwapInfo[i].window, client, - DixWriteAccess); - if (error != Success) { - Xfree(swapInfo); - return error; - } - - /* Each window must be double-buffered - BadMatch. */ - if (DBE_WINDOW_PRIV(pWin) == NULL) - { - Xfree(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) - { - Xfree(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 )) - { - Xfree(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) - { - Xfree(swapInfo); - return(error); - } - } - - Xfree(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; - register 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; - register int i, j, n, rc; - register int count; /* number of visual infos in reply */ - register 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 = (DrawablePtr *)Xalloc(stuff->n * - sizeof(DrawablePtr)))) - { - return(BadAlloc); - } - - drawables = (Drawable *)&stuff[1]; - - for (i = 0; i < stuff->n; i++) - { - rc = dixLookupDrawable(pDrawables+i, drawables[i], client, 0, - DixGetAttrAccess); - if (rc != Success) { - Xfree(pDrawables); - return rc; - } - } - } - - count = (stuff->n == 0) ? screenInfo.numScreens : stuff->n; - if (!(pScrVisInfo = (XdbeScreenVisualInfo *)xalloc(count * - sizeof(XdbeScreenVisualInfo)))) - { - if (pDrawables) - { - Xfree(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); - - rc = XaceHook(XACE_SCREEN_ACCESS, client, pScreen, DixGetAttrAccess); - if ((rc != Success) || - !(*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++) - { - xfree(pScrVisInfo[j].visinfo); - } - - /* Free pDrawables if we needed to allocate it above. */ - if (pDrawables) - { - Xfree(pDrawables); - } - - return (rc == Success) ? BadAlloc : rc; - } - - /* 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 = bytes_to_int32(length); - rep.m = count; - - if (client->swapped) - { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.m, n); - } - - /* 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, n); - } - - 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, n); - - /* 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++) - { - xfree(pScrVisInfo[i].visinfo); - } - xfree(pScrVisInfo); - - if (pDrawables) - { - Xfree(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; - int rc, n; - - - REQUEST_SIZE_MATCH(xDbeGetBackBufferAttributesReq); - - rc = dixLookupResourceByType((pointer *)&pDbeWindowPriv, stuff->buffer, - dbeWindowPrivResType, client, - DixGetAttrAccess); - if (rc == Success) - { - rep.attributes = pDbeWindowPriv->pWindow->drawable.id; - } - else - { - rep.attributes = None; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - - if (client->swapped) - { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.attributes, n); - } - - 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(ProcDbeBeginIdiom(client)); - - 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); - register int n; - - - swaps(&stuff->length, n); - 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); - register int n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDbeAllocateBackBufferNameReq); - - swapl(&stuff->window, n); - swapl(&stuff->buffer, n); - /* 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); - register int n; - - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDbeDeallocateBackBufferNameReq); - - swapl(&stuff->buffer, n); - - 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); - register int i, n; - xDbeSwapInfo *pSwapInfo; - - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDbeSwapBuffersReq); - - swapl(&stuff->n, 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, n); - } - } - - 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); - register int n; - - swaps(&stuff->length, n); - 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); - register int n; - - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDbeGetVisualInfoReq); - - swapl(&stuff->n, 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); - register int n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDbeGetBackBufferAttributesReq); - - swapl(&stuff->buffer, n); - - 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. */ - xfree(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. */ - dixSetPrivate(&pDbeWindowPriv->pWindow->devPrivates, dbeWindowPrivKey, - NULL); - - /* We are done with the window priv. */ - dixFreePrivates(pDbeWindowPriv->devPrivates); - xfree(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; - - 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); - - dixFreePrivates(pDbeScreenPriv->devPrivates); - xfree(pDbeScreenPriv); - } - } -} /* 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; - register int i, j; - ScreenPtr pScreen = NULL; - DbeScreenPrivPtr pDbeScreenPriv; - int nStubbedScreens = 0; - Bool ddxInitSuccess; - -#ifdef PANORAMIX - if(!noPanoramiXExtension) return; -#endif - - /* Create the resource types. */ - dbeDrawableResType = - CreateNewResourceType(DbeDrawableDelete, "dbeDrawable"); - if (!dbeDrawableResType) - return; - dbeDrawableResType |= RC_DRAWABLE; - - dbeWindowPrivResType = - CreateNewResourceType(DbeWindowPrivDelete, "dbeWindow"); - if (!dbeWindowPrivResType) - return; - - if (!dixRegisterPrivateOffset(dbeDrawableResType, - offsetof(PixmapRec, devPrivates))) - return; - - 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 (!(pDbeScreenPriv = - (DbeScreenPrivPtr)Xcalloc(sizeof(DbeScreenPrivRec)))) - { - /* 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++) - { - xfree(dixLookupPrivate(&screenInfo.screens[j]->devPrivates, - dbeScreenPrivKey)); - dixSetPrivate(&screenInfo.screens[j]->devPrivates, - dbeScreenPrivKey, NULL); - } - return; - } - - dixSetPrivate(&pScreen->devPrivates, dbeScreenPrivKey, pDbeScreenPriv); - - /* Copy the resource types */ - pDbeScreenPriv->dbeDrawableResType = dbeDrawableResType; - pDbeScreenPriv->dbeWindowPrivResType = dbeWindowPrivResType; - - /* Copy the private indices */ - pDbeScreenPriv->dbeScreenPrivKey = dbeScreenPrivKey; - pDbeScreenPriv->dbeWindowPrivKey = dbeWindowPrivKey; - - { - /* We don't have DDX support for DBE anymore */ - -#ifndef DISABLE_MI_DBE_BY_DEFAULT - /* Setup DIX. */ - pDbeScreenPriv->SetupBackgroundPainter = DbeSetupBackgroundPainter; - - /* 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++) - { - xfree(dixLookupPrivate(&screenInfo.screens[i]->devPrivates, - dbeScreenPrivKey)); - dixSetPrivate(&pScreen->devPrivates, dbeScreenPrivKey, NULL); - } - return; - } - - - /* Now add the extension. */ - extEntry = AddExtension(DBE_PROTOCOL_NAME, DbeNumberEvents, - DbeNumberErrors, ProcDbeDispatch, SProcDbeDispatch, - DbeResetProc, StandardMinorOpcode); - - dbeErrorBase = extEntry->errorBase; - -} /* DbeExtensionInit() */ - +/****************************************************************************** + * + * 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 +#if HAVE_STDINT_H +#include +#elif !defined(UINT32_MAX) +#define UINT32_MAX 0xffffffffU +#endif + +#include +#include +#include "scrnintstr.h" +#include "extnsionst.h" +#include "gcstruct.h" +#include "dixstruct.h" +#define NEED_DBE_PROTOCOL +#include "dbestruct.h" +#include "midbe.h" +#include "xace.h" + +/* GLOBALS */ + +/* These are static globals copied to DBE's screen private for use by DDX */ +static int dbeScreenPrivKeyIndex; +static DevPrivateKey dbeScreenPrivKey = &dbeScreenPrivKeyIndex; +static int dbeWindowPrivKeyIndex; +static DevPrivateKey dbeWindowPrivKey = &dbeWindowPrivKeyIndex; + +/* These are static globals copied to DBE's screen private for use by DDX */ +static RESTYPE dbeDrawableResType; +static RESTYPE dbeWindowPrivResType; + +/* Used to generate DBE's BadBuffer error. */ +static int dbeErrorBase; + +/****************************************************************************** + * + * 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; + + /* 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; + + (*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; + register int n; + + + 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, n); + } + + WriteToClient(client, sizeof(xDbeGetVersionReply), (char *)&rep); + + return Success; + +} /* 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; + register int i; + Bool visualMatched = FALSE; + xDbeSwapAction swapAction; + VisualID visual; + int status; + int add_index; + + + REQUEST_SIZE_MATCH(xDbeAllocateBackBufferNameReq); + + /* The window must be valid. */ + status = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); + if (status != Success) + return status; + + /* 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. + */ + + pDbeWindowPriv = calloc(1, sizeof(DbeWindowPrivRec)); + if (!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; + + add_index = 0; + for (i = 0; i < DBE_INIT_MAX_IDS; i++) + { + pDbeWindowPriv->IDs[i] = DBE_FREE_ID_ELEMENT; + } + + /* Actually connect the window priv to the window. */ + dixSetPrivate(&pWin->devPrivates, dbeWindowPrivKey, 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; + } + + add_index = i; + + } /* 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->IDs[add_index] = stuff->buffer; + if (!AddResource(stuff->buffer, dbeWindowPrivResType, + (pointer)pDbeWindowPriv)) + { + pDbeWindowPriv->IDs[add_index] = DBE_FREE_ID_ELEMENT; + + if (pDbeWindowPriv->nBufferIDs == 0) { + status = BadAlloc; + goto out_free; + } + } + } else { + /* The DDX buffer allocation routine failed for the first buffer of + * this window. + */ + if (pDbeWindowPriv->nBufferIDs == 0) { + goto out_free; + } + } + + /* Increment the number of buffers (XIDs) associated with this window. */ + pDbeWindowPriv->nBufferIDs++; + + /* Set swap action on all calls. */ + pDbeWindowPriv->swapAction = stuff->swapAction; + + return(status); + +out_free: + dixSetPrivate(&pWin->devPrivates, dbeWindowPrivKey, NULL); + free(pDbeWindowPriv); + 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 rc, i; + pointer val; + + + REQUEST_SIZE_MATCH(xDbeDeallocateBackBufferNameReq); + + /* Buffer name must be valid */ + rc = dixLookupResourceByType((pointer *)&pDbeWindowPriv, stuff->buffer, + dbeWindowPrivResType, client, + DixDestroyAccess); + if (rc != Success) + return (rc == BadValue) ? dbeErrorBase + DbeBadBuffer : rc; + + rc = dixLookupResourceByType(&val, stuff->buffer, dbeDrawableResType, + client, DixDestroyAccess); + if (rc != Success) + return (rc == BadValue) ? dbeErrorBase + DbeBadBuffer : rc; + + /* 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; + register 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 = (DbeSwapInfoPtr)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. */ + error = dixLookupWindow(&pWin, dbeSwapInfo[i].window, client, + DixWriteAccess); + if (error != Success) { + free(swapInfo); + return error; + } + + /* 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; + register 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; + register int i, j, n, rc; + register int count; /* number of visual infos in reply */ + register 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 = (DrawablePtr *)malloc(stuff->n * + sizeof(DrawablePtr)))) + { + return(BadAlloc); + } + + drawables = (Drawable *)&stuff[1]; + + for (i = 0; i < stuff->n; i++) + { + rc = dixLookupDrawable(pDrawables+i, drawables[i], client, 0, + DixGetAttrAccess); + if (rc != Success) { + free(pDrawables); + return rc; + } + } + } + + count = (stuff->n == 0) ? screenInfo.numScreens : stuff->n; + if (!(pScrVisInfo = (XdbeScreenVisualInfo *)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); + + rc = XaceHook(XACE_SCREEN_ACCESS, client, pScreen, DixGetAttrAccess); + if ((rc != Success) || + !(*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 (rc == Success) ? BadAlloc : rc; + } + + /* 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 = bytes_to_int32(length); + rep.m = count; + + if (client->swapped) + { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.m, n); + } + + /* 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, n); + } + + 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, n); + + /* 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 Success; + +} /* 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; + int rc, n; + + + REQUEST_SIZE_MATCH(xDbeGetBackBufferAttributesReq); + + rc = dixLookupResourceByType((pointer *)&pDbeWindowPriv, stuff->buffer, + dbeWindowPrivResType, client, + DixGetAttrAccess); + if (rc == Success) + { + rep.attributes = pDbeWindowPriv->pWindow->drawable.id; + } + else + { + rep.attributes = None; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + + if (client->swapped) + { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.attributes, n); + } + + WriteToClient(client, sizeof(xDbeGetBackBufferAttributesReply), + (char *)&rep); + return Success; + +} /* 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(ProcDbeBeginIdiom(client)); + + 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); + register int n; + + + swaps(&stuff->length, n); + 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); + register int n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDbeAllocateBackBufferNameReq); + + swapl(&stuff->window, n); + swapl(&stuff->buffer, n); + /* 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); + register int n; + + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDbeDeallocateBackBufferNameReq); + + swapl(&stuff->buffer, n); + + 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); + register int i, n; + xDbeSwapInfo *pSwapInfo; + + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDbeSwapBuffersReq); + + swapl(&stuff->n, 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, n); + } + } + + 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); + register int n; + + swaps(&stuff->length, n); + 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); + register int n; + + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDbeGetVisualInfoReq); + + swapl(&stuff->n, 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); + register int n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDbeGetBackBufferAttributesReq); + + swapl(&stuff->buffer, n); + + 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) +{ + ChangeGCVal 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].val = background.pixel; + gcvalues[1].val = FillSolid; + gcmask = GCForeground|GCFillStyle; + break; + + case BackgroundPixmap: + gcvalues[0].val = FillTiled; + gcvalues[1].ptr = background.pixmap; + gcvalues[2].val = ts_x_origin; + gcvalues[3].val = ts_y_origin; + gcmask = GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin; + break; + + default: + /* pWin->backgroundState == None */ + return(FALSE); + } + + return ChangeGC(NullClient, pGC, gcmask, gcvalues) == 0; +} /* 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. */ + dixSetPrivate(&pDbeWindowPriv->pWindow->devPrivates, dbeWindowPrivKey, + NULL); + + /* We are done with the window priv. */ + dixFreePrivates(pDbeWindowPriv->devPrivates); + 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; + + 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); + + dixFreePrivates(pDbeScreenPriv->devPrivates); + free(pDbeScreenPriv); + } + } +} /* 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; + register int i, j; + ScreenPtr pScreen = NULL; + DbeScreenPrivPtr pDbeScreenPriv; + int nStubbedScreens = 0; + Bool ddxInitSuccess; + +#ifdef PANORAMIX + if(!noPanoramiXExtension) return; +#endif + + /* Create the resource types. */ + dbeDrawableResType = + CreateNewResourceType(DbeDrawableDelete, "dbeDrawable"); + if (!dbeDrawableResType) + return; + dbeDrawableResType |= RC_DRAWABLE; + + dbeWindowPrivResType = + CreateNewResourceType(DbeWindowPrivDelete, "dbeWindow"); + if (!dbeWindowPrivResType) + return; + + if (!dixRegisterPrivateOffset(dbeDrawableResType, + offsetof(PixmapRec, devPrivates))) + return; + + 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 (!(pDbeScreenPriv = + (DbeScreenPrivPtr)calloc(1, sizeof(DbeScreenPrivRec)))) + { + /* 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(dixLookupPrivate(&screenInfo.screens[j]->devPrivates, + dbeScreenPrivKey)); + dixSetPrivate(&screenInfo.screens[j]->devPrivates, + dbeScreenPrivKey, NULL); + } + return; + } + + dixSetPrivate(&pScreen->devPrivates, dbeScreenPrivKey, pDbeScreenPriv); + + /* Copy the resource types */ + pDbeScreenPriv->dbeDrawableResType = dbeDrawableResType; + pDbeScreenPriv->dbeWindowPrivResType = dbeWindowPrivResType; + + /* Copy the private indices */ + pDbeScreenPriv->dbeScreenPrivKey = dbeScreenPrivKey; + pDbeScreenPriv->dbeWindowPrivKey = dbeWindowPrivKey; + + { + /* We don't have DDX support for DBE anymore */ + +#ifndef DISABLE_MI_DBE_BY_DEFAULT + /* Setup DIX. */ + pDbeScreenPriv->SetupBackgroundPainter = DbeSetupBackgroundPainter; + + /* 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(dixLookupPrivate(&screenInfo.screens[i]->devPrivates, + dbeScreenPrivKey)); + dixSetPrivate(&pScreen->devPrivates, dbeScreenPrivKey, NULL); + } + return; + } + + + /* Now add the extension. */ + extEntry = AddExtension(DBE_PROTOCOL_NAME, DbeNumberEvents, + DbeNumberErrors, ProcDbeDispatch, SProcDbeDispatch, + DbeResetProc, StandardMinorOpcode); + + dbeErrorBase = extEntry->errorBase; + +} /* DbeExtensionInit() */ + diff --git a/xorg-server/dbe/midbe.c b/xorg-server/dbe/midbe.c index 4426c9d85..cba386c0b 100644 --- a/xorg-server/dbe/midbe.c +++ b/xorg-server/dbe/midbe.c @@ -1,809 +1,809 @@ -/****************************************************************************** - * - * 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 "xace.h" - -#include - -static int miDbeWindowPrivPrivKeyIndex; -static DevPrivateKey miDbeWindowPrivPrivKey = &miDbeWindowPrivPrivKeyIndex; -static RESTYPE dbeDrawableResType; -static RESTYPE dbeWindowPrivResType; -static int dbeScreenPrivKeyIndex; -static DevPrivateKey dbeScreenPrivKey = &dbeScreenPrivKeyIndex; -static int dbeWindowPrivKeyIndex; -static DevPrivateKey dbeWindowPrivKey = &dbeWindowPrivKeyIndex; - - -/****************************************************************************** - * - * 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) -{ - register int i, j, k; - register 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; - } - - /* Allocate an array of XdbeVisualInfo items. */ - if (!(visInfo = (XdbeVisualInfo *)xalloc(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; - int rc; - - - 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, 0))) - { - return(BadAlloc); - } - - /* Get a back pixmap. */ - if (!(pDbeWindowPrivPriv->pBackBuffer = - (*pScreen->CreatePixmap)(pScreen, pDbeWindowPriv->width, - pDbeWindowPriv->height, - pWin->drawable.depth, 0))) - { - (*pScreen->DestroyPixmap)(pDbeWindowPrivPriv->pFrontBuffer); - return(BadAlloc); - } - - /* Security creation/labeling check. */ - rc = XaceHook(XACE_RESOURCE_ACCESS, serverClient, bufId, - dbeDrawableResType, pDbeWindowPrivPriv->pBackBuffer, - RT_WINDOW, pWin, DixCreateAccess); - - /* Make the back pixmap a DBE drawable resource. */ - if (rc != Success || !AddResource(bufId, dbeDrawableResType, - pDbeWindowPrivPriv->pBackBuffer)) - { - /* free the buffer and the drawable resource */ - FreeResource(bufId, RT_NONE); - return (rc == Success) ? BadAlloc : rc; - } - - - /* Attach the priv priv to the priv. */ - dixSetPrivate(&pDbeWindowPriv->devPrivates, miDbeWindowPrivPrivKey, - 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, 0); - - pBackBuffer = (*pScreen->CreatePixmap)(pScreen, width, height, - pWin->drawable.depth, 0); - - 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() */ - - -/****************************************************************************** - * - * 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 */ - dbeScreenPrivKey = pDbeScreenPriv->dbeScreenPrivKey; - dbeWindowPrivKey = pDbeScreenPriv->dbeWindowPrivKey; - - if (!dixRequestPrivate(miDbeWindowPrivPrivKey, - 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; - - return(TRUE); - -} /* miDbeInit() */ +/****************************************************************************** + * + * 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 "xace.h" + +#include + +static int miDbeWindowPrivPrivKeyIndex; +static DevPrivateKey miDbeWindowPrivPrivKey = &miDbeWindowPrivPrivKeyIndex; +static RESTYPE dbeDrawableResType; +static RESTYPE dbeWindowPrivResType; +static int dbeScreenPrivKeyIndex; +static DevPrivateKey dbeScreenPrivKey = &dbeScreenPrivKeyIndex; +static int dbeWindowPrivKeyIndex; +static DevPrivateKey dbeWindowPrivKey = &dbeWindowPrivKeyIndex; + + +/****************************************************************************** + * + * 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) +{ + register int i, j, k; + register 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; + } + + /* Allocate an array of XdbeVisualInfo items. */ + if (!(visInfo = (XdbeVisualInfo *)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; + int rc; + + + 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, 0))) + { + return(BadAlloc); + } + + /* Get a back pixmap. */ + if (!(pDbeWindowPrivPriv->pBackBuffer = + (*pScreen->CreatePixmap)(pScreen, pDbeWindowPriv->width, + pDbeWindowPriv->height, + pWin->drawable.depth, 0))) + { + (*pScreen->DestroyPixmap)(pDbeWindowPrivPriv->pFrontBuffer); + return(BadAlloc); + } + + /* Security creation/labeling check. */ + rc = XaceHook(XACE_RESOURCE_ACCESS, serverClient, bufId, + dbeDrawableResType, pDbeWindowPrivPriv->pBackBuffer, + RT_WINDOW, pWin, DixCreateAccess); + + /* Make the back pixmap a DBE drawable resource. */ + if (rc != Success || !AddResource(bufId, dbeDrawableResType, + pDbeWindowPrivPriv->pBackBuffer)) + { + /* free the buffer and the drawable resource */ + FreeResource(bufId, RT_NONE); + return (rc == Success) ? BadAlloc : rc; + } + + + /* Attach the priv priv to the priv. */ + dixSetPrivate(&pDbeWindowPriv->devPrivates, miDbeWindowPrivPrivKey, + 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, 0); + + pBackBuffer = (*pScreen->CreatePixmap)(pScreen, width, height, + pWin->drawable.depth, 0); + + 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() */ + + +/****************************************************************************** + * + * 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 */ + dbeScreenPrivKey = pDbeScreenPriv->dbeScreenPrivKey; + dbeWindowPrivKey = pDbeScreenPriv->dbeWindowPrivKey; + + if (!dixRequestPrivate(miDbeWindowPrivPrivKey, + 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; + + return(TRUE); + +} /* miDbeInit() */ diff --git a/xorg-server/dix/atom.c b/xorg-server/dix/atom.c index f5bf8ad7e..210641bd4 100644 --- a/xorg-server/dix/atom.c +++ b/xorg-server/dix/atom.c @@ -1,212 +1,218 @@ -/*********************************************************** - -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; - const char *string; -} NodeRec, *NodePtr; - -static Atom lastAtom = None; -static NodePtr atomRoot = (NodePtr)NULL; -static unsigned long tableLength; -static NodePtr *nodeTable; - -void FreeAtom(NodePtr patom); - -Atom -MakeAtom(const 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 = xalloc(sizeof(NodeRec)); - if (!nd) - return BAD_RESOURCE; - if (lastAtom < XA_LAST_PREDEFINED) - { - nd->string = string; - } - else - { - char *newstring = xalloc(len + 1); - if (!newstring) { - xfree(nd); - return BAD_RESOURCE; - } - strncpy(newstring, string, (int)len); - newstring[len] = 0; - nd->string = newstring; - } - if ((lastAtom + 1) >= tableLength) { - NodePtr *table; - - table = (NodePtr *) xrealloc(nodeTable, - tableLength * (2 * sizeof(NodePtr))); - if (!table) { - if (nd->string != string) - xfree(nd->string); - xfree(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; -} - -Bool -ValidAtom(Atom atom) -{ - return (atom != None) && (atom <= lastAtom); -} - -const char * -NameForAtom(Atom atom) -{ - NodePtr node; - if (atom > lastAtom) return 0; - if ((node = nodeTable[atom]) == (NodePtr)NULL) return 0; - return node->string; -} - -void -AtomError(void) -{ - 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) - xfree(patom->string); - xfree(patom); -} - -void -FreeAllAtoms(void) -{ - if(atomRoot == (NodePtr)NULL) - return; - FreeAtom(atomRoot); - atomRoot = (NodePtr)NULL; - xfree(nodeTable); - nodeTable = (NodePtr *)NULL; - lastAtom = None; -} - -void -InitAtoms(void) -{ - FreeAllAtoms(); - tableLength = InitialTableSize; - nodeTable = xalloc(InitialTableSize*sizeof(NodePtr)); - if (!nodeTable) - AtomError(); - nodeTable[None] = (NodePtr)NULL; - MakePredeclaredAtoms(); - if (lastAtom != XA_LAST_PREDEFINED) - AtomError (); -} +/*********************************************************** + +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; + const char *string; +} NodeRec, *NodePtr; + +static Atom lastAtom = None; +static NodePtr atomRoot = NULL; +static unsigned long tableLength; +static NodePtr *nodeTable; + +void FreeAtom(NodePtr patom); + +Atom +MakeAtom(const 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 != 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 + { + char *newstring = malloc(len + 1); + if (!newstring) { + free(nd); + return BAD_RESOURCE; + } + strncpy(newstring, string, (int)len); + newstring[len] = 0; + nd->string = newstring; + } + if ((lastAtom + 1) >= tableLength) { + NodePtr *table; + + table = realloc(nodeTable, tableLength * (2 * sizeof(NodePtr))); + if (!table) { + if (nd->string != string) { + /* nd->string has been strdup'ed */ + free((char *)nd->string); + } + free(nd); + return BAD_RESOURCE; + } + tableLength <<= 1; + nodeTable = table; + } + *np = nd; + nd->left = nd->right = NULL; + nd->fingerPrint = fp; + nd->a = ++lastAtom; + nodeTable[lastAtom] = nd; + return nd->a; + } + else + return None; +} + +Bool +ValidAtom(Atom atom) +{ + return (atom != None) && (atom <= lastAtom); +} + +const char * +NameForAtom(Atom atom) +{ + NodePtr node; + if (atom > lastAtom) return 0; + if ((node = nodeTable[atom]) == NULL) return 0; + return node->string; +} + +void +AtomError(void) +{ + 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) { + /* + * All strings above XA_LAST_PREDEFINED are strdup'ed, so it's safe to + * cast here + */ + free((char *)patom->string); + } + free(patom); +} + +void +FreeAllAtoms(void) +{ + if (atomRoot == NULL) + return; + FreeAtom(atomRoot); + atomRoot = NULL; + free(nodeTable); + nodeTable = NULL; + lastAtom = None; +} + +void +InitAtoms(void) +{ + FreeAllAtoms(); + tableLength = InitialTableSize; + nodeTable = malloc(InitialTableSize * sizeof(NodePtr)); + if (!nodeTable) + AtomError(); + nodeTable[None] = NULL; + MakePredeclaredAtoms(); + if (lastAtom != XA_LAST_PREDEFINED) + AtomError(); +} diff --git a/xorg-server/dix/colormap.c b/xorg-server/dix/colormap.c index bf9794125..06bb0cbf4 100644 --- a/xorg-server/dix/colormap.c +++ b/xorg-server/dix/colormap.c @@ -1,2759 +1,2757 @@ -/*********************************************************** - -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" -#include "privates.h" -#include "xace.h" - -extern XID clientErrorValue; - -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( - ColormapPtr /*pmap*/, - 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) -#if COMPOSITE -#define ALPHAMASK(vis) ((vis)->nplanes < 32 ? 0 : \ - (CARD32) ~((vis)->redMask|(vis)->greenMask|(vis)->blueMask)) -#else -#define ALPHAMASK(vis) 0 -#endif - -#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 - */ -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 = xalloc(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 = xalloc(size * sizeof(Pixel)); - if (!ppix) - { - xfree(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 = xalloc(size * sizeof(Pixel)); - if (!ppix) - { - xfree(pmap->clientPixelsRed[client]); - xfree(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 = xalloc(size * sizeof(Pixel)); - if (!ppix) - { - xfree(pmap->clientPixelsGreen[client]); - xfree(pmap->clientPixelsRed[client]); - xfree(pmap); - return(BadAlloc); - } - pmap->clientPixelsBlue[client] = ppix; - for(i = 0; i < size; i++) - ppix[i] = i; - pmap->numPixelsBlue[client] = size; - } - } - pmap->devPrivates = NULL; - pmap->flags |= BeingCreated; - - if (!AddResource(mid, RT_COLORMAP, (pointer)pmap)) - return (BadAlloc); - - /* - * Security creation/labeling check - */ - i = XaceHook(XACE_RESOURCE_ACCESS, clients[client], mid, RT_COLORMAP, - pmap, RT_NONE, NULL, DixCreateAccess); - if (i != Success) { - FreeResource(mid, RT_NONE); - return i; - } - - /* 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 */ - 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++) - xfree(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) - xfree(pent->co.shco.red); - if (--pent->co.shco.green->refcnt == 0) - xfree(pent->co.shco.green); - if (--pent->co.shco.blue->refcnt == 0) - xfree(pent->co.shco.blue); - } - } - } - if((pmap->class | DynamicClass) == DirectColor) - { - for(i = 0; i < MAXCLIENTS; i++) - { - xfree(pmap->clientPixelsGreen[i]); - xfree(pmap->clientPixelsBlue[i]); - } - } - - dixFreePrivates(pmap->devPrivates); - xfree(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; -#ifdef PANORAMIX - if(noPanoramiXExtension || !pwin->drawable.pScreen->myNum) -#endif - DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); - if (pwin->optional) { - pwin->optional->colormap = None; - CheckWindowOptionalNeed (pwin); - } - } - - return (WT_WALKCHILDREN); -} - -/* Tell window that pmid got uninstalled */ -int -TellLostMap (WindowPtr pwin, pointer value) -{ - Colormap *pmid = (Colormap *)value; - xEvent xE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) - return WT_STOPWALKING; -#endif - 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 */ -int -TellGainedMap (WindowPtr pwin, pointer value) -{ - Colormap *pmid = (Colormap *)value; - xEvent xE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) - return WT_STOPWALKING; -#endif - 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) - xfree(pent->co.shco.red); - if(--pent->co.shco.green->refcnt == 0) - xfree(pent->co.shco.green); - if(--pent->co.shco.blue->refcnt == 0) - xfree(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 = xalloc(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); - xfree(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 - */ -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 *) xrealloc(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 *) xrealloc(pmap->clientPixelsRed[client], - (npix + 1) * sizeof(Pixel)); - if (!ppix) - return (BadAlloc); - ppix[npix] = pixR; - pmap->clientPixelsRed[client] = ppix; - npix = pmap->numPixelsGreen[client]; - ppix = (Pixel *) xrealloc(pmap->clientPixelsGreen[client], - (npix + 1) * sizeof(Pixel)); - if (!ppix) - return (BadAlloc); - ppix[npix] = pixG; - pmap->clientPixelsGreen[client] = ppix; - npix = pmap->numPixelsBlue[client]; - ppix = (Pixel *) xrealloc(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; - dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, - RT_COLORMAP, clients[client], DixReadAccess); - - 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; - dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, - RT_COLORMAP, clients[client], DixReadAccess); - - 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 = xalloc(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. - */ - -void -FakeAllocColor (ColormapPtr pmap, 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: - temp = 0; - 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 */ -void -FakeFreeColor(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 *) xrealloc (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 */ - -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(ColormapPtr pmap, int client) -{ - Pixel *ppix, *ppixStart; - int n; - int class; - - class = pmap->class; - ppixStart = pmap->clientPixelsRed[client]; - if (class & DynamicClass) - { - n = pmap->numPixelsRed[client]; - for (ppix = ppixStart; --n >= 0; ) - { - FreeCell(pmap, *ppix, REDMAP); - ppix++; - } - } - - xfree(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); - xfree(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); - xfree(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) -{ - pointer pmap; - colorResource *pcr = value; - int rc; - - rc = dixLookupResourceByType(&pmap, pcr->mid, RT_COLORMAP, serverClient, - DixRemoveAccess); - if (rc == Success) - FreePixels((ColormapPtr)pmap, pcr->client); - xfree(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 = xalloc(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) - xfree(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 = xalloc(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) - xfree(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 = xalloc(npixR * sizeof(Pixel)); - ppixGreen = xalloc(npixG * sizeof(Pixel)); - ppixBlue = xalloc(npixB * sizeof(Pixel)); - if (!ppixRed || !ppixGreen || !ppixBlue) - { - if (ppixBlue) xfree(ppixBlue); - if (ppixGreen) xfree(ppixGreen); - if (ppixRed) xfree(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 *) xrealloc(pmap->clientPixelsRed[client], - (pmap->numPixelsRed[client] + (c << r)) * - sizeof(Pixel)); - if (rpix) - pmap->clientPixelsRed[client] = rpix; - gpix = (Pixel *) xrealloc(pmap->clientPixelsGreen[client], - (pmap->numPixelsGreen[client] + (c << g)) * - sizeof(Pixel)); - if (gpix) - pmap->clientPixelsGreen[client] = gpix; - bpix = (Pixel *) xrealloc(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; - xfree(ppixBlue); - xfree(ppixGreen); - xfree(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); - - xfree(ppixBlue); - xfree(ppixGreen); - xfree(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 = xalloc(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 *)xrealloc(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; - } - xfree(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 = xalloc(npixShared * sizeof(SHAREDCOLOR *)); - if (!psharedList) - return FALSE; - ppshared = psharedList; - for (z = npixShared; --z >= 0; ) - { - if (!(ppshared[z] = xalloc(sizeof(SHAREDCOLOR)))) - { - for (z++ ; z < npixShared; z++) - xfree(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; - } - } - } - } - xfree(psharedList); - return TRUE; -} - - -/** FreeColors - * Free colors and/or cells (probably slow for large numbers) - */ -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 *)xrealloc(ppixClient, npixNew * sizeof(Pixel)); - if (pptr) - ppixClient = pptr; - npixClient = npixNew; - } - else - { - npixClient = 0; - xfree(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 */ -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 = xalloc(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; - } - } - xfree(pmaps); - return (found); -} - -struct colormap_lookup_data { - ScreenPtr pScreen; - VisualPtr visuals; -}; - -static void _colormap_find_resource(pointer value, XID id, - pointer cdata) -{ - struct colormap_lookup_data *cmap_data = cdata; - VisualPtr visuals = cmap_data->visuals; - ScreenPtr pScreen = cmap_data->pScreen; - ColormapPtr cmap = value; - int j; - - if (pScreen != cmap->pScreen) - return; - - j = cmap->pVisual - pScreen->visuals; - cmap->pVisual = &visuals[j]; -} - -/* something has realloced the visuals, instead of breaking - ABI fix it up here - glx and compsite did this wrong */ -Bool -ResizeVisualArray(ScreenPtr pScreen, int new_visual_count, - DepthPtr depth) -{ - struct colormap_lookup_data cdata; - int numVisuals; - VisualPtr visuals; - XID *vids, vid; - int first_new_vid, first_new_visual, i; - - first_new_vid = depth->numVids; - first_new_visual = pScreen->numVisuals; - - vids = xrealloc(depth->vids, (depth->numVids + new_visual_count) * sizeof(XID)); - if (!vids) - return FALSE; - - /* its realloced now no going back if we fail the next one */ - depth->vids = vids; - - numVisuals = pScreen->numVisuals + new_visual_count; - visuals = xrealloc(pScreen->visuals, numVisuals * sizeof(VisualRec)); - if (!visuals) { - return FALSE; - } - - cdata.visuals = visuals; - cdata.pScreen = pScreen; - FindClientResourcesByType(serverClient, RT_COLORMAP, _colormap_find_resource, &cdata); - - pScreen->visuals = visuals; - - for (i = 0; i < new_visual_count; i++) { - vid = FakeClientID(0); - pScreen->visuals[first_new_visual + i].vid = vid; - vids[first_new_vid + i] = vid; - } - - depth->numVids += new_visual_count; - pScreen->numVisuals += new_visual_count; - - return TRUE; -} +/*********************************************************** + +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" +#include "privates.h" +#include "xace.h" + +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( + ColormapPtr /*pmap*/, + 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) +#if COMPOSITE +#define ALPHAMASK(vis) ((vis)->nplanes < 32 ? 0 : \ + (CARD32) ~((vis)->redMask|(vis)->greenMask|(vis)->blueMask)) +#else +#define ALPHAMASK(vis) 0 +#endif + +#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 + */ +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; + } + } + pmap->devPrivates = NULL; + pmap->flags |= BeingCreated; + + if (!AddResource(mid, RT_COLORMAP, (pointer)pmap)) + return (BadAlloc); + + /* + * Security creation/labeling check + */ + i = XaceHook(XACE_RESOURCE_ACCESS, clients[client], mid, RT_COLORMAP, + pmap, RT_NONE, NULL, DixCreateAccess); + if (i != Success) { + FreeResource(mid, RT_NONE); + return i; + } + + /* 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 */ + 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]); + } + } + + dixFreePrivates(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; +#ifdef PANORAMIX + if(noPanoramiXExtension || !pwin->drawable.pScreen->myNum) +#endif + DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); + if (pwin->optional) { + pwin->optional->colormap = None; + CheckWindowOptionalNeed (pwin); + } + } + + return (WT_WALKCHILDREN); +} + +/* Tell window that pmid got uninstalled */ +int +TellLostMap (WindowPtr pwin, pointer value) +{ + Colormap *pmid = (Colormap *)value; + xEvent xE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) + return WT_STOPWALKING; +#endif + 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 */ +int +TellGainedMap (WindowPtr pwin, pointer value) +{ + Colormap *pmid = (Colormap *)value; + xEvent xE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) + return WT_STOPWALKING; +#endif + 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 = malloc(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); + free(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 + */ +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; + dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, + RT_COLORMAP, clients[client], DixReadAccess); + + 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; + dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, + RT_COLORMAP, clients[client], DixReadAccess); + + 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. + */ + +void +FakeAllocColor (ColormapPtr pmap, 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: + temp = 0; + 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 */ +void +FakeFreeColor(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 */ + +int +QueryColors (ColormapPtr pmap, int count, Pixel *ppixIn, xrgb *prgbList, ClientPtr client) +{ + 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) { + client->errorValue = pixel; + errVal = BadValue; + continue; + } + i = (pixel & pVisual->redMask) >> pVisual->offsetRed; + if (i >= numred) + { + client->errorValue = pixel; + errVal = BadValue; + continue; + } + prgb->red = pmap->red[i].co.local.red; + i = (pixel & pVisual->greenMask) >> pVisual->offsetGreen; + if (i >= numgreen) + { + client->errorValue = pixel; + errVal = BadValue; + continue; + } + prgb->green = pmap->green[i].co.local.green; + i = (pixel & pVisual->blueMask) >> pVisual->offsetBlue; + if (i >= numblue) + { + client->errorValue = 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) + { + client->errorValue = 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(ColormapPtr pmap, int client) +{ + Pixel *ppix, *ppixStart; + int n; + int class; + + 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) +{ + pointer pmap; + colorResource *pcr = value; + int rc; + + rc = dixLookupResourceByType(&pmap, pcr->mid, RT_COLORMAP, serverClient, + DixRemoveAccess); + if (rc == Success) + FreePixels((ColormapPtr)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 = malloc(npixR * sizeof(Pixel)); + ppixGreen = malloc(npixG * sizeof(Pixel)); + ppixBlue = malloc(npixB * sizeof(Pixel)); + if (!ppixRed || !ppixGreen || !ppixBlue) + { + if (ppixBlue) free(ppixBlue); + if (ppixGreen) free(ppixGreen); + if (ppixRed) free(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; + free(ppixBlue); + free(ppixGreen); + free(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); + + free(ppixBlue); + free(ppixGreen); + free(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 = malloc(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; + } + free(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 = malloc(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; + } + } + } + } + free(psharedList); + return TRUE; +} + + +/** FreeColors + * Free colors and/or cells (probably slow for large numbers) + */ +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) + { + clients[client]->errorValue = *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)) + { + clients[client]->errorValue = *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 */ +int +StoreColors (ColormapPtr pmap, int count, xColorItem *defs, ClientPtr client) +{ + 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; + client->errorValue = 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 + client->errorValue = pdef->pixel; + } + } + else + { + for (pdef = defs, n = 0; n < count; pdef++, n++) + { + + ok = TRUE; + if (pdef->pixel >= pVisual->ColormapEntries) + { + client->errorValue = 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 = malloc(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; + } + } + free(pmaps); + return (found); +} + +struct colormap_lookup_data { + ScreenPtr pScreen; + VisualPtr visuals; +}; + +static void _colormap_find_resource(pointer value, XID id, + pointer cdata) +{ + struct colormap_lookup_data *cmap_data = cdata; + VisualPtr visuals = cmap_data->visuals; + ScreenPtr pScreen = cmap_data->pScreen; + ColormapPtr cmap = value; + int j; + + if (pScreen != cmap->pScreen) + return; + + j = cmap->pVisual - pScreen->visuals; + cmap->pVisual = &visuals[j]; +} + +/* something has realloced the visuals, instead of breaking + ABI fix it up here - glx and compsite did this wrong */ +Bool +ResizeVisualArray(ScreenPtr pScreen, int new_visual_count, + DepthPtr depth) +{ + struct colormap_lookup_data cdata; + int numVisuals; + VisualPtr visuals; + XID *vids, vid; + int first_new_vid, first_new_visual, i; + + first_new_vid = depth->numVids; + first_new_visual = pScreen->numVisuals; + + vids = realloc(depth->vids, (depth->numVids + new_visual_count) * sizeof(XID)); + if (!vids) + return FALSE; + + /* its realloced now no going back if we fail the next one */ + depth->vids = vids; + + numVisuals = pScreen->numVisuals + new_visual_count; + visuals = realloc(pScreen->visuals, numVisuals * sizeof(VisualRec)); + if (!visuals) { + return FALSE; + } + + cdata.visuals = visuals; + cdata.pScreen = pScreen; + FindClientResourcesByType(serverClient, RT_COLORMAP, _colormap_find_resource, &cdata); + + pScreen->visuals = visuals; + + for (i = 0; i < new_visual_count; i++) { + vid = FakeClientID(0); + pScreen->visuals[first_new_visual + i].vid = vid; + vids[first_new_vid + i] = vid; + } + + depth->numVids += new_visual_count; + pScreen->numVisuals += new_visual_count; + + return TRUE; +} diff --git a/xorg-server/dix/cursor.c b/xorg-server/dix/cursor.c index 5d9c8b080..01d08bd6e 100644 --- a/xorg-server/dix/cursor.c +++ b/xorg-server/dix/cursor.c @@ -1,512 +1,512 @@ -/*********************************************************** - -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" -#include "inputstr.h" -#include "xace.h" - -typedef struct _GlyphShare { - FontPtr font; - unsigned short sourceChar; - unsigned short maskChar; - CursorBitsPtr bits; - struct _GlyphShare *next; -} GlyphShare, *GlyphSharePtr; - -static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL; - -#ifdef XFIXES -static CARD32 cursorSerial; -#endif - -static void -FreeCursorBits(CursorBitsPtr bits) -{ - if (--bits->refcnt > 0) - return; - xfree(bits->source); - xfree(bits->mask); -#ifdef ARGB_CURSOR - xfree(bits->argb); -#endif - dixFreePrivates(bits->devPrivates); - bits->devPrivates = NULL; - 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); - xfree(this); - } - xfree(bits); - } -} - -/** - * To be called indirectly by DeleteResource; must use exactly two args. - * - * \param value must conform to DeleteType - */ -int -FreeCursor(pointer value, XID cid) -{ - int nscr; - CursorPtr pCurs = (CursorPtr)value; - - ScreenPtr pscr; - DeviceIntPtr pDev = NULL; /* unused anyway */ - - if ( --pCurs->refcnt != 0) - return(Success); - - for (nscr = 0; nscr < screenInfo.numScreens; nscr++) - { - pscr = screenInfo.screens[nscr]; - (void)( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); - } - dixFreePrivates(pCurs->devPrivates); - FreeCursorBits(pCurs->bits); - xfree( 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; -} - -/** - * realize the cursor for every screen. Do not change the refcnt, this will be - * changed when ChangeToCursor actually changes the sprite. - * - * @return Success if all cursors realize on all screens, BadAlloc if realize - * failed for a device on a given screen. - */ -static int -RealizeCursorAllScreens(CursorPtr pCurs) -{ - DeviceIntPtr pDev; - ScreenPtr pscr; - int nscr; - - for (nscr = 0; nscr < screenInfo.numScreens; nscr++) - { - pscr = screenInfo.screens[nscr]; - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs)) - { - /* Realize failed for device pDev on screen pscr. - * We have to assume that for all devices before, realize - * worked. We need to rollback all devices so far on the - * current screen and then all devices on previous - * screens. - */ - DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/ - while(pDevIt && pDevIt != pDev) - { - if (DevHasCursor(pDevIt)) - ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); - pDevIt = pDevIt->next; - } - while (--nscr >= 0) - { - pscr = screenInfo.screens[nscr]; - /* now unrealize all devices on previous screens */ - pDevIt = inputInfo.devices; - while (pDevIt) - { - if (DevHasCursor(pDevIt)) - ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); - pDevIt = pDevIt->next; - } - ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); - } - return BadAlloc; - } - } - } - } - - return Success; -} - -/** - * 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 - */ -int -AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits, - CARD32 *argb, CursorMetricPtr cm, - unsigned foreRed, unsigned foreGreen, unsigned foreBlue, - unsigned backRed, unsigned backGreen, unsigned backBlue, - CursorPtr *ppCurs, ClientPtr client, XID cid) -{ - CursorBitsPtr bits; - CursorPtr pCurs; - int rc; - - *ppCurs = NULL; - pCurs = (CursorPtr)xcalloc(sizeof(CursorRec) + sizeof(CursorBits), 1); - if (!pCurs) - { - xfree(psrcbits); - xfree(pmaskbits); - return BadAlloc; - } - 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; - pCurs->refcnt = 1; - bits->devPrivates = NULL; - bits->refcnt = -1; - CheckForEmptyMask(bits); - pCurs->bits = bits; -#ifdef XFIXES - pCurs->serialNumber = ++cursorSerial; - pCurs->name = None; -#endif - - pCurs->foreRed = foreRed; - pCurs->foreGreen = foreGreen; - pCurs->foreBlue = foreBlue; - - pCurs->backRed = backRed; - pCurs->backGreen = backGreen; - pCurs->backBlue = backBlue; - - pCurs->id = cid; - pCurs->devPrivates = NULL; - - /* security creation/labeling check */ - rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, - pCurs, RT_NONE, NULL, DixCreateAccess); - if (rc != Success) - goto error; - - rc = RealizeCursorAllScreens(pCurs); - if (rc != Success) - goto error; - - *ppCurs = pCurs; - return Success; - -error: - dixFreePrivates(pCurs->devPrivates); - FreeCursorBits(bits); - xfree(pCurs); - - return rc; -} - -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, XID cid) -{ - FontPtr sourcefont, maskfont; - unsigned char *srcbits; - unsigned char *mskbits; - CursorMetricRec cm; - int rc; - CursorBitsPtr bits; - CursorPtr pCurs; - GlyphSharePtr pShare; - - rc = dixLookupResourceByType((pointer *)&sourcefont, source, RT_FONT, client, - DixUseAccess); - if (rc != Success) - { - client->errorValue = source; - return (rc == BadValue) ? BadFont : rc; - } - rc = dixLookupResourceByType((pointer *)&maskfont, mask, RT_FONT, client, - DixUseAccess); - if (rc != Success && mask != None) - { - client->errorValue = mask; - return (rc == BadValue) ? BadFont : rc; - } - 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 = (CursorPtr)xcalloc(sizeof(CursorRec), 1); - 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 = xalloc(n); - if (!mskptr) - return BadAlloc; - while (--n >= 0) - *mskptr++ = ~0; - } - else - { - if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm)) - { - client->errorValue = maskChar; - return BadValue; - } - if ((rc = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits))) - return rc; - } - if ((rc = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits))) - { - xfree(mskbits); - return rc; - } - if (sourcefont != maskfont) - { - pCurs = - (CursorPtr)xcalloc(sizeof(CursorRec) + sizeof(CursorBits), 1); - if (pCurs) - bits = (CursorBitsPtr)((char *)pCurs + sizeof(CursorRec)); - else - bits = (CursorBitsPtr)NULL; - } - else - { - pCurs = (CursorPtr)xcalloc(sizeof(CursorRec), 1); - if (pCurs) - bits = (CursorBitsPtr)xcalloc(sizeof(CursorBits), 1); - else - bits = (CursorBitsPtr)NULL; - } - if (!bits) - { - xfree(pCurs); - xfree(mskbits); - xfree(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; - bits->devPrivates = NULL; - if (sourcefont != maskfont) - bits->refcnt = -1; - else - { - bits->refcnt = 1; - pShare = xalloc(sizeof(GlyphShare)); - if (!pShare) - { - FreeCursorBits(bits); - 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; -#ifdef XFIXES - pCurs->serialNumber = ++cursorSerial; - pCurs->name = None; -#endif - - pCurs->foreRed = foreRed; - pCurs->foreGreen = foreGreen; - pCurs->foreBlue = foreBlue; - - pCurs->backRed = backRed; - pCurs->backGreen = backGreen; - pCurs->backBlue = backBlue; - - pCurs->id = cid; - pCurs->devPrivates = NULL; - - /* security creation/labeling check */ - rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, - pCurs, RT_NONE, NULL, DixCreateAccess); - if (rc != Success) - goto error; - - rc = RealizeCursorAllScreens(pCurs); - if (rc != Success) - goto error; - - *ppCurs = pCurs; - return Success; - -error: - dixFreePrivates(pCurs->devPrivates); - FreeCursorBits(bits); - xfree(pCurs); - - return rc; -} - -/** 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 *unused1, unsigned int unused2) -{ - CursorPtr curs; - FontPtr cursorfont; - int err; - XID fontID; - - fontID = FakeClientID(0); - err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync, - (unsigned)strlen(defaultCursorFont), defaultCursorFont); - if (err != Success) - return NullCursor; - - err = dixLookupResourceByType((pointer *)&cursorfont, fontID, RT_FONT, - serverClient, DixReadAccess); - if (err != Success) - return NullCursor; - if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0, - &curs, serverClient, (XID)0) != Success) - return NullCursor; - - if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs)) - return NullCursor; - - return curs; -} +/*********************************************************** + +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" +#include "inputstr.h" +#include "xace.h" + +typedef struct _GlyphShare { + FontPtr font; + unsigned short sourceChar; + unsigned short maskChar; + CursorBitsPtr bits; + struct _GlyphShare *next; +} GlyphShare, *GlyphSharePtr; + +static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL; + +#ifdef XFIXES +static CARD32 cursorSerial; +#endif + +static void +FreeCursorBits(CursorBitsPtr bits) +{ + if (--bits->refcnt > 0) + return; + free(bits->source); + free(bits->mask); +#ifdef ARGB_CURSOR + free(bits->argb); +#endif + dixFreePrivates(bits->devPrivates); + bits->devPrivates = NULL; + 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 + */ +int +FreeCursor(pointer value, XID cid) +{ + int nscr; + CursorPtr pCurs = (CursorPtr)value; + + ScreenPtr pscr; + DeviceIntPtr pDev = NULL; /* unused anyway */ + + if ( --pCurs->refcnt != 0) + return(Success); + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) + { + pscr = screenInfo.screens[nscr]; + (void)( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); + } + dixFreePrivates(pCurs->devPrivates); + 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; +} + +/** + * realize the cursor for every screen. Do not change the refcnt, this will be + * changed when ChangeToCursor actually changes the sprite. + * + * @return Success if all cursors realize on all screens, BadAlloc if realize + * failed for a device on a given screen. + */ +static int +RealizeCursorAllScreens(CursorPtr pCurs) +{ + DeviceIntPtr pDev; + ScreenPtr pscr; + int nscr; + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) + { + pscr = screenInfo.screens[nscr]; + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs)) + { + /* Realize failed for device pDev on screen pscr. + * We have to assume that for all devices before, realize + * worked. We need to rollback all devices so far on the + * current screen and then all devices on previous + * screens. + */ + DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/ + while(pDevIt && pDevIt != pDev) + { + if (DevHasCursor(pDevIt)) + ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); + pDevIt = pDevIt->next; + } + while (--nscr >= 0) + { + pscr = screenInfo.screens[nscr]; + /* now unrealize all devices on previous screens */ + pDevIt = inputInfo.devices; + while (pDevIt) + { + if (DevHasCursor(pDevIt)) + ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); + pDevIt = pDevIt->next; + } + ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); + } + return BadAlloc; + } + } + } + } + + return Success; +} + +/** + * 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 + */ +int +AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits, + CARD32 *argb, CursorMetricPtr cm, + unsigned foreRed, unsigned foreGreen, unsigned foreBlue, + unsigned backRed, unsigned backGreen, unsigned backBlue, + CursorPtr *ppCurs, ClientPtr client, XID cid) +{ + CursorBitsPtr bits; + CursorPtr pCurs; + int rc; + + *ppCurs = NULL; + pCurs = (CursorPtr)calloc(sizeof(CursorRec) + sizeof(CursorBits), 1); + if (!pCurs) + { + free(psrcbits); + free(pmaskbits); + return BadAlloc; + } + 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; + pCurs->refcnt = 1; + bits->devPrivates = NULL; + bits->refcnt = -1; + CheckForEmptyMask(bits); + pCurs->bits = bits; +#ifdef XFIXES + pCurs->serialNumber = ++cursorSerial; + pCurs->name = None; +#endif + + pCurs->foreRed = foreRed; + pCurs->foreGreen = foreGreen; + pCurs->foreBlue = foreBlue; + + pCurs->backRed = backRed; + pCurs->backGreen = backGreen; + pCurs->backBlue = backBlue; + + pCurs->id = cid; + pCurs->devPrivates = NULL; + + /* security creation/labeling check */ + rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, + pCurs, RT_NONE, NULL, DixCreateAccess); + if (rc != Success) + goto error; + + rc = RealizeCursorAllScreens(pCurs); + if (rc != Success) + goto error; + + *ppCurs = pCurs; + return Success; + +error: + dixFreePrivates(pCurs->devPrivates); + FreeCursorBits(bits); + free(pCurs); + + return rc; +} + +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, XID cid) +{ + FontPtr sourcefont, maskfont; + unsigned char *srcbits; + unsigned char *mskbits; + CursorMetricRec cm; + int rc; + CursorBitsPtr bits; + CursorPtr pCurs; + GlyphSharePtr pShare; + + rc = dixLookupResourceByType((pointer *)&sourcefont, source, RT_FONT, client, + DixUseAccess); + if (rc != Success) + { + client->errorValue = source; + return (rc == BadValue) ? BadFont : rc; + } + rc = dixLookupResourceByType((pointer *)&maskfont, mask, RT_FONT, client, + DixUseAccess); + if (rc != Success && mask != None) + { + client->errorValue = mask; + return (rc == BadValue) ? BadFont : rc; + } + 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 = (CursorPtr)calloc(sizeof(CursorRec), 1); + 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 ((rc = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits))) + return rc; + } + if ((rc = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits))) + { + free(mskbits); + return rc; + } + if (sourcefont != maskfont) + { + pCurs = + (CursorPtr)calloc(sizeof(CursorRec) + sizeof(CursorBits), 1); + if (pCurs) + bits = (CursorBitsPtr)((char *)pCurs + sizeof(CursorRec)); + else + bits = (CursorBitsPtr)NULL; + } + else + { + pCurs = (CursorPtr)calloc(sizeof(CursorRec), 1); + if (pCurs) + bits = (CursorBitsPtr)calloc(sizeof(CursorBits), 1); + 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; + bits->devPrivates = NULL; + if (sourcefont != maskfont) + bits->refcnt = -1; + else + { + bits->refcnt = 1; + pShare = malloc(sizeof(GlyphShare)); + if (!pShare) + { + FreeCursorBits(bits); + 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; +#ifdef XFIXES + pCurs->serialNumber = ++cursorSerial; + pCurs->name = None; +#endif + + pCurs->foreRed = foreRed; + pCurs->foreGreen = foreGreen; + pCurs->foreBlue = foreBlue; + + pCurs->backRed = backRed; + pCurs->backGreen = backGreen; + pCurs->backBlue = backBlue; + + pCurs->id = cid; + pCurs->devPrivates = NULL; + + /* security creation/labeling check */ + rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, + pCurs, RT_NONE, NULL, DixCreateAccess); + if (rc != Success) + goto error; + + rc = RealizeCursorAllScreens(pCurs); + if (rc != Success) + goto error; + + *ppCurs = pCurs; + return Success; + +error: + dixFreePrivates(pCurs->devPrivates); + FreeCursorBits(bits); + free(pCurs); + + return rc; +} + +/** 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 *unused1, unsigned int unused2) +{ + CursorPtr curs; + FontPtr cursorfont; + int err; + XID fontID; + + fontID = FakeClientID(0); + err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync, + (unsigned)strlen(defaultCursorFont), defaultCursorFont); + if (err != Success) + return NullCursor; + + err = dixLookupResourceByType((pointer *)&cursorfont, fontID, RT_FONT, + serverClient, DixReadAccess); + if (err != Success) + return NullCursor; + if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0, + &curs, serverClient, (XID)0) != Success) + return NullCursor; + + if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs)) + return NullCursor; + + return curs; +} diff --git a/xorg-server/dix/devices.c b/xorg-server/dix/devices.c index a33df4d0a..f419a98fd 100644 --- a/xorg-server/dix/devices.c +++ b/xorg-server/dix/devices.c @@ -1,2518 +1,2518 @@ -/************************************************************ - -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 -#include "windowstr.h" -#include "inputstr.h" -#include "scrnintstr.h" -#include "cursorstr.h" -#include "dixstruct.h" -#include "ptrveloc.h" -#include "site.h" -#include "xkbsrv.h" -#include "privates.h" -#include "xace.h" -#include "mi.h" - -#include "dispatch.h" -#include "swaprep.h" -#include "dixevents.h" -#include "mipointer.h" -#include "eventstr.h" - -#include -#include -#include -#include "exglobals.h" -#include "exevents.h" -#include "xiquerydevice.h" /* for SizeDeviceClasses */ -#include "xiproperty.h" -#include "enterleave.h" /* for EnterWindow() */ -#include "xserver-properties.h" -#include "xichangehierarchy.h" /* For XISendDeviceHierarchyEvent */ - -/** @file - * This file handles input device-related stuff. - */ - -static void RecalculateMasterButtons(DeviceIntPtr slave); - -/** - * DIX property handler. - */ -static int -DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop, - BOOL checkonly) -{ - if (property == XIGetKnownProperty(XI_PROP_ENABLED)) - { - if (prop->format != 8 || prop->type != XA_INTEGER || prop->size != 1) - return BadValue; - - /* Don't allow disabling of VCP/VCK */ - if ((dev == inputInfo.pointer || dev == inputInfo.keyboard) && - !(*(CARD8*)prop->data)) - return BadAccess; - - if (!checkonly) - { - if ((*((CARD8*)prop->data)) && !dev->enabled) - EnableDevice(dev, TRUE); - else if (!(*((CARD8*)prop->data)) && dev->enabled) - DisableDevice(dev, TRUE); - } - } - - return Success; -} - -/* Pair the keyboard to the pointer device. Keyboard events will follow the - * pointer sprite. Only applicable for master devices. - * If the client is set, the request to pair comes from some client. In this - * case, we need to check for access. If the client is NULL, it's from an - * internal automatic pairing, we must always permit this. - */ -static int -PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd) -{ - if (!ptr) - return BadDevice; - - /* Don't allow pairing for slave devices */ - if (!IsMaster(ptr) || !IsMaster(kbd)) - return BadDevice; - - if (ptr->spriteInfo->paired) - return BadDevice; - - if (kbd->spriteInfo->spriteOwner) - { - xfree(kbd->spriteInfo->sprite); - kbd->spriteInfo->sprite = NULL; - kbd->spriteInfo->spriteOwner = FALSE; - } - - kbd->spriteInfo->sprite = ptr->spriteInfo->sprite; - kbd->spriteInfo->paired = ptr; - ptr->spriteInfo->paired = kbd; - return Success; -} - - -/** - * Find and return the next unpaired MD pointer device. - */ -static DeviceIntPtr -NextFreePointerDevice(void) -{ - DeviceIntPtr dev; - for (dev = inputInfo.devices; dev; dev = dev->next) - if (IsMaster(dev) && - dev->spriteInfo->spriteOwner && - !dev->spriteInfo->paired) - return dev; - return NULL; -} - -/** - * Create a new input device and init it to sane values. The device is added - * to the server's off_devices list. - * - * @param deviceProc Callback for device control function (switch dev on/off). - * @return The newly created device. - */ -DeviceIntPtr -AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) -{ - DeviceIntPtr dev, *prev; /* not a typo */ - DeviceIntPtr devtmp; - int devid; - char devind[MAXDEVICES]; - BOOL enabled; - - /* Find next available id, 0 and 1 are reserved */ - memset(devind, 0, sizeof(char)*MAXDEVICES); - for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next) - devind[devtmp->id]++; - for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next) - devind[devtmp->id]++; - for (devid = 2; devid < MAXDEVICES && devind[devid]; devid++) - ; - - if (devid >= MAXDEVICES) - return (DeviceIntPtr)NULL; - dev = xcalloc(sizeof(DeviceIntRec) + sizeof(SpriteInfoRec), 1); - if (!dev) - return (DeviceIntPtr)NULL; - dev->id = devid; - dev->public.processInputProc = (ProcessInputProc)NoopDDA; - dev->public.realInputProc = (ProcessInputProc)NoopDDA; - dev->public.enqueueInputProc = EnqueueEvent; - dev->deviceProc = deviceProc; - dev->startup = autoStart; - - /* device grab defaults */ - dev->deviceGrab.grabTime = currentTime; - dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; - dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; - - dev->coreEvents = TRUE; - - /* sprite defaults */ - dev->spriteInfo = (SpriteInfoPtr)&dev[1]; - - /* security creation/labeling check - */ - if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixCreateAccess)) { - xfree(dev); - return NULL; - } - - inputInfo.numDevices++; - - for (prev = &inputInfo.off_devices; *prev; prev = &(*prev)->next) - ; - *prev = dev; - dev->next = NULL; - - enabled = FALSE; - XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), - XA_INTEGER, 8, PropModeReplace, 1, &enabled, - FALSE); - XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE); - XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL); - - return dev; -} - -void -SendDevicePresenceEvent(int deviceid, int type) -{ - DeviceIntRec dummyDev; - devicePresenceNotify ev; - - memset(&dummyDev, 0, sizeof(DeviceIntRec)); - ev.type = DevicePresenceNotify; - ev.time = currentTime.milliseconds; - ev.devchange = type; - ev.deviceid = deviceid; - dummyDev.id = XIAllDevices; - SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, - (xEvent*)&ev, 1); -} - -/** - * Enable the device through the driver, add the device to the device list. - * Switch device ON through the driver and push it onto the global device - * list. Initialize the DIX sprite or pair the device. All clients are - * notified about the device being enabled. - * - * A master pointer device needs to be enabled before a master keyboard - * device. - * - * @param The device to be enabled. - * @param sendevent True if an XI2 event should be sent. - * @return TRUE on success or FALSE otherwise. - */ -Bool -EnableDevice(DeviceIntPtr dev, BOOL sendevent) -{ - DeviceIntPtr *prev; - int ret; - DeviceIntPtr other; - BOOL enabled; - int flags[MAXDEVICES] = {0}; - - for (prev = &inputInfo.off_devices; - *prev && (*prev != dev); - prev = &(*prev)->next) - ; - - if (!dev->spriteInfo->sprite) - { - if (IsMaster(dev)) - { - /* Sprites appear on first root window, so we can hardcode it */ - if (dev->spriteInfo->spriteOwner) - { - InitializeSprite(dev, WindowTable[0]); - /* mode doesn't matter */ - EnterWindow(dev, WindowTable[0], NotifyAncestor); - } - else if ((other = NextFreePointerDevice()) == NULL) - { - ErrorF("[dix] cannot find pointer to pair with. " - "This is a bug.\n"); - return FALSE; - } else - PairDevices(NULL, other, dev); - } else - { - if (dev->coreEvents) - other = (IsPointerDevice(dev)) ? inputInfo.pointer : - inputInfo.keyboard; - else - other = NULL; /* auto-float non-core devices */ - AttachDevice(NULL, dev, other); - } - } - - /* Before actually enabling the device, we need to make sure the event - * list's events have enough memory for a ClassesChangedEvent from the - * device - */ - if ((*prev != dev) || !dev->inited || - ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) { - ErrorF("[dix] couldn't enable device %d\n", dev->id); - return FALSE; - } - dev->enabled = TRUE; - *prev = dev->next; - - for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next) - ; - *prev = dev; - dev->next = NULL; - - enabled = TRUE; - XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), - XA_INTEGER, 8, PropModeReplace, 1, &enabled, - TRUE); - - SendDevicePresenceEvent(dev->id, DeviceEnabled); - if (sendevent) - { - flags[dev->id] |= XIDeviceEnabled; - XISendDeviceHierarchyEvent(flags); - } - - RecalculateMasterButtons(dev); - - return TRUE; -} - -/** - * Switch a device off through the driver and push it onto the off_devices - * list. A device will not send events while disabled. All clients are - * notified about the device being disabled. - * - * Master keyboard devices have to be disabled before master pointer devices - * otherwise things turn bad. - * - * @param sendevent True if an XI2 event should be sent. - * @return TRUE on success or FALSE otherwise. - */ -Bool -DisableDevice(DeviceIntPtr dev, BOOL sendevent) -{ - DeviceIntPtr *prev, other; - BOOL enabled; - int flags[MAXDEVICES] = {0}; - - for (prev = &inputInfo.devices; - *prev && (*prev != dev); - prev = &(*prev)->next) - ; - if (*prev != dev) - return FALSE; - - /* float attached devices */ - if (IsMaster(dev)) - { - for (other = inputInfo.devices; other; other = other->next) - { - if (other->u.master == dev) - { - AttachDevice(NULL, other, NULL); - flags[other->id] |= XISlaveDetached; - } - } - } - else - { - for (other = inputInfo.devices; other; other = other->next) - { - if (IsMaster(other) && other->u.lastSlave == dev) - other->u.lastSlave = NULL; - } - } - - if (IsMaster(dev) && dev->spriteInfo->sprite) - { - for (other = inputInfo.devices; other; other = other->next) - { - if (other->spriteInfo->paired == dev) - { - ErrorF("[dix] cannot disable device, still paired. " - "This is a bug. \n"); - return FALSE; - } - } - } - - (void)(*dev->deviceProc)(dev, DEVICE_OFF); - dev->enabled = FALSE; - - /* now that the device is disabled, we can reset the signal handler's - * last.slave */ - OsBlockSignals(); - for (other = inputInfo.devices; other; other = other->next) - { - if (other->last.slave == dev) - other->last.slave = NULL; - } - OsReleaseSignals(); - - LeaveWindow(dev); - SetFocusOut(dev); - - *prev = dev->next; - dev->next = inputInfo.off_devices; - inputInfo.off_devices = dev; - - enabled = FALSE; - XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), - XA_INTEGER, 8, PropModeReplace, 1, &enabled, - TRUE); - - SendDevicePresenceEvent(dev->id, DeviceDisabled); - if (sendevent) - { - flags[dev->id] = XIDeviceDisabled; - XISendDeviceHierarchyEvent(flags); - } - - RecalculateMasterButtons(dev); - - return TRUE; -} - -/** - * Initialise a new device through the driver and tell all clients about the - * new device. - * - * Must be called before EnableDevice. - * The device will NOT send events until it is enabled! - * - * @param sendevent True if an XI2 event should be sent. - * @return Success or an error code on failure. - */ -int -ActivateDevice(DeviceIntPtr dev, BOOL sendevent) -{ - int ret = Success; - ScreenPtr pScreen = screenInfo.screens[0]; - - if (!dev || !dev->deviceProc) - return BadImplementation; - - ret = (*dev->deviceProc) (dev, DEVICE_INIT); - dev->inited = (ret == Success); - if (!dev->inited) - return ret; - - /* Initialize memory for sprites. */ - if (IsMaster(dev) && dev->spriteInfo->spriteOwner) - pScreen->DeviceCursorInitialize(dev, pScreen); - - SendDevicePresenceEvent(dev->id, DeviceAdded); - if (sendevent) - { - int flags[MAXDEVICES] = {0}; - flags[dev->id] = XISlaveAdded; - XISendDeviceHierarchyEvent(flags); - } - return ret; -} - -/** - * Ring the bell. - * The actual task of ringing the bell is the job of the DDX. - */ -static void -CoreKeyboardBell(int volume, DeviceIntPtr pDev, pointer arg, int something) -{ - KeybdCtrl *ctrl = arg; - - DDXRingBell(volume, ctrl->bell_pitch, ctrl->bell_duration); -} - -static void -CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl) -{ - return; -} - -/** - * Device control function for the Virtual Core Keyboard. - */ -int -CoreKeyboardProc(DeviceIntPtr pDev, int what) -{ - - switch (what) { - case DEVICE_INIT: - if (!InitKeyboardDeviceStruct(pDev, NULL, CoreKeyboardBell, - CoreKeyboardCtl)) - { - ErrorF("Keyboard initialization failed. This could be a missing " - "or incorrect setup of xkeyboard-config.\n"); - return BadValue; - } - return Success; - - case DEVICE_ON: - case DEVICE_OFF: - return Success; - - case DEVICE_CLOSE: - return Success; - } - - return BadMatch; -} - -/** - * Device control function for the Virtual Core Pointer. - */ -int -CorePointerProc(DeviceIntPtr pDev, int what) -{ -#define NBUTTONS 10 -#define NAXES 2 - BYTE map[NBUTTONS + 1]; - int i = 0; - Atom btn_labels[NBUTTONS] = {0}; - Atom axes_labels[NAXES] = {0}; - - switch (what) { - case DEVICE_INIT: - for (i = 1; i <= NBUTTONS; i++) - map[i] = i; - - btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); - btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); - btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); - btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); - btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); - btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); - btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); - /* don't know about the rest */ - - axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); - axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); - - if (!InitPointerDeviceStruct((DevicePtr)pDev, map, NBUTTONS, btn_labels, - (PtrCtrlProcPtr)NoopDDA, - GetMotionHistorySize(), NAXES, axes_labels)) - { - ErrorF("Could not initialize device '%s'. Out of memory.\n", - pDev->name); - return BadAlloc; /* IPDS only fails on allocs */ - } - pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; - pDev->last.valuators[0] = pDev->valuator->axisVal[0]; - pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; - pDev->last.valuators[1] = pDev->valuator->axisVal[1]; - break; - - case DEVICE_CLOSE: - break; - - default: - break; - } - - return Success; - -#undef NBUTTONS -#undef NAXES -} - -/** - * Initialise the two core devices, VCP and VCK (see events.c). - * Both devices are not tied to physical devices, but guarantee that there is - * always a keyboard and a pointer present and keep the protocol semantics. - * - * Note that the server MUST have two core devices at all times, even if there - * is no physical device connected. - */ -void -InitCoreDevices(void) -{ - if (AllocDevicePair(serverClient, "Virtual core", - &inputInfo.pointer, &inputInfo.keyboard, - CorePointerProc, CoreKeyboardProc, - TRUE) != Success) - FatalError("Failed to allocate core devices"); - - if (ActivateDevice(inputInfo.pointer, TRUE) != Success || - ActivateDevice(inputInfo.keyboard, TRUE) != Success) - FatalError("Failed to activate core devices."); - if (!EnableDevice(inputInfo.pointer, TRUE) || - !EnableDevice(inputInfo.keyboard, TRUE)) - FatalError("Failed to enable core devices."); - - InitXTestDevices(); -} - -/** - * Activate all switched-off devices and then enable all those devices. - * - * Will return an error if no core keyboard or core pointer is present. - * In theory this should never happen if you call InitCoreDevices() first. - * - * InitAndStartDevices needs to be called AFTER the windows are initialized. - * Devices will start sending events after InitAndStartDevices() has - * completed. - * - * @return Success or error code on failure. - */ -int -InitAndStartDevices(void) -{ - DeviceIntPtr dev, next; - - for (dev = inputInfo.off_devices; dev; dev = dev->next) { - DebugF("(dix) initialising device %d\n", dev->id); - if (!dev->inited) - ActivateDevice(dev, TRUE); - } - - /* enable real devices */ - for (dev = inputInfo.off_devices; dev; dev = next) - { - DebugF("(dix) enabling device %d\n", dev->id); - next = dev->next; - if (dev->inited && dev->startup) - EnableDevice(dev, TRUE); - } - - return Success; -} - -/** - * Free the given device class and reset the pointer to NULL. - */ -static void -FreeDeviceClass(int type, pointer *class) -{ - if (!(*class)) - return; - - switch(type) - { - case KeyClass: - { - KeyClassPtr* k = (KeyClassPtr*)class; - if ((*k)->xkbInfo) - { - XkbFreeInfo((*k)->xkbInfo); - (*k)->xkbInfo = NULL; - } - xfree((*k)); - break; - } - case ButtonClass: - { - ButtonClassPtr *b = (ButtonClassPtr*)class; - if ((*b)->xkb_acts) - xfree((*b)->xkb_acts); - xfree((*b)); - break; - } - case ValuatorClass: - { - ValuatorClassPtr *v = (ValuatorClassPtr*)class; - - if ((*v)->motion) - xfree((*v)->motion); - xfree((*v)); - break; - } - case FocusClass: - { - FocusClassPtr *f = (FocusClassPtr*)class; - xfree((*f)->trace); - xfree((*f)); - break; - } - case ProximityClass: - { - ProximityClassPtr *p = (ProximityClassPtr*)class; - xfree((*p)); - break; - } - } - *class = NULL; -} - -static void -FreeFeedbackClass(int type, pointer *class) -{ - if (!(*class)) - return; - - switch(type) - { - case KbdFeedbackClass: - { - KbdFeedbackPtr *kbdfeed = (KbdFeedbackPtr*)class; - KbdFeedbackPtr k, knext; - for (k = (*kbdfeed); k; k = knext) { - knext = k->next; - if (k->xkb_sli) - XkbFreeSrvLedInfo(k->xkb_sli); - xfree(k); - } - break; - } - case PtrFeedbackClass: - { - PtrFeedbackPtr *ptrfeed = (PtrFeedbackPtr*)class; - PtrFeedbackPtr p, pnext; - - for (p = (*ptrfeed); p; p = pnext) { - pnext = p->next; - xfree(p); - } - break; - } - case IntegerFeedbackClass: - { - IntegerFeedbackPtr *intfeed = (IntegerFeedbackPtr*)class; - IntegerFeedbackPtr i, inext; - - for (i = (*intfeed); i; i = inext) { - inext = i->next; - xfree(i); - } - break; - } - case StringFeedbackClass: - { - StringFeedbackPtr *stringfeed = (StringFeedbackPtr*)class; - StringFeedbackPtr s, snext; - - for (s = (*stringfeed); s; s = snext) { - snext = s->next; - xfree(s->ctrl.symbols_supported); - xfree(s->ctrl.symbols_displayed); - xfree(s); - } - break; - } - case BellFeedbackClass: - { - BellFeedbackPtr *bell = (BellFeedbackPtr*)class; - BellFeedbackPtr b, bnext; - - for (b = (*bell); b; b = bnext) { - bnext = b->next; - xfree(b); - } - break; - } - case LedFeedbackClass: - { - LedFeedbackPtr *leds = (LedFeedbackPtr*)class; - LedFeedbackPtr l, lnext; - - for (l = (*leds); l; l = lnext) { - lnext = l->next; - if (l->xkb_sli) - XkbFreeSrvLedInfo(l->xkb_sli); - xfree(l); - } - break; - } - } - *class = NULL; -} - -static void -FreeAllDeviceClasses(ClassesPtr classes) -{ - if (!classes) - return; - - FreeDeviceClass(KeyClass, (pointer)&classes->key); - FreeDeviceClass(ValuatorClass, (pointer)&classes->valuator); - FreeDeviceClass(ButtonClass, (pointer)&classes->button); - FreeDeviceClass(FocusClass, (pointer)&classes->focus); - FreeDeviceClass(ProximityClass, (pointer)&classes->proximity); - - FreeFeedbackClass(KbdFeedbackClass, (pointer)&classes->kbdfeed); - FreeFeedbackClass(PtrFeedbackClass, (pointer)&classes->ptrfeed); - FreeFeedbackClass(IntegerFeedbackClass, (pointer)&classes->intfeed); - FreeFeedbackClass(StringFeedbackClass, (pointer)&classes->stringfeed); - FreeFeedbackClass(BellFeedbackClass, (pointer)&classes->bell); - FreeFeedbackClass(LedFeedbackClass, (pointer)&classes->leds); - -} - -/** - * Close down a device and free all resources. - * Once closed down, the driver will probably not expect you that you'll ever - * enable it again and free associated structs. If you want the device to just - * be disabled, DisableDevice(). - * Don't call this function directly, use RemoveDevice() instead. - */ -static void -CloseDevice(DeviceIntPtr dev) -{ - ScreenPtr screen = screenInfo.screens[0]; - ClassesPtr classes; - int j; - - if (!dev) - return; - - XIDeleteAllDeviceProperties(dev); - - if (dev->inited) - (void)(*dev->deviceProc)(dev, DEVICE_CLOSE); - - /* free sprite memory */ - if (IsMaster(dev) && dev->spriteInfo->sprite) - screen->DeviceCursorCleanup(dev, screen); - - /* free acceleration info */ - if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc) - dev->valuator->accelScheme.AccelCleanupProc(dev); - - while (dev->xkb_interest) - XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource); - - xfree(dev->name); - - classes = (ClassesPtr)&dev->key; - FreeAllDeviceClasses(classes); - - if (IsMaster(dev)) - { - classes = dev->unused_classes; - FreeAllDeviceClasses(classes); - xfree(classes); - } - - if (DevHasCursor(dev) && dev->spriteInfo->sprite) { - if (dev->spriteInfo->sprite->current) - FreeCursor(dev->spriteInfo->sprite->current, None); - xfree(dev->spriteInfo->sprite->spriteTrace); - xfree(dev->spriteInfo->sprite); - } - - /* a client may have the device set as client pointer */ - for (j = 0; j < currentMaxClients; j++) - { - if (clients[j] && clients[j]->clientPtr == dev) - { - clients[j]->clientPtr = NULL; - clients[j]->clientPtr = PickPointer(clients[j]); - } - } - - xfree(dev->deviceGrab.sync.event); - dixFreePrivates(dev->devPrivates); - xfree(dev); -} - -/** - * Shut down all devices of one list and free all resources. - */ -static -void -CloseDeviceList(DeviceIntPtr *listHead) -{ - /* Used to mark devices that we tried to free */ - Bool freedIds[MAXDEVICES]; - DeviceIntPtr dev; - int i; - - if (listHead == NULL) - return; - - for (i = 0; i < MAXDEVICES; i++) - freedIds[i] = FALSE; - - dev = *listHead; - while (dev != NULL) - { - freedIds[dev->id] = TRUE; - DeleteInputDeviceRequest(dev); - - dev = *listHead; - while (dev != NULL && freedIds[dev->id]) - dev = dev->next; - } -} - -/** - * Shut down all devices, free all resources, etc. - * Only useful if you're shutting down the server! - */ -void -CloseDownDevices(void) -{ - DeviceIntPtr dev; - - /* Float all SDs before closing them. Note that at this point resources - * (e.g. cursors) have been freed already, so we can't just call - * AttachDevice(NULL, dev, NULL). Instead, we have to forcibly set master - * to NULL and pretend nothing happened. - */ - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (!IsMaster(dev) && dev->u.master) - dev->u.master = NULL; - } - - CloseDeviceList(&inputInfo.devices); - CloseDeviceList(&inputInfo.off_devices); - - CloseDevice(inputInfo.pointer); - CloseDevice(inputInfo.keyboard); - - inputInfo.devices = NULL; - inputInfo.off_devices = NULL; - inputInfo.keyboard = NULL; - inputInfo.pointer = NULL; - XkbDeleteRulesDflts(); -} - -/** - * Remove the cursor sprite for all devices. This needs to be done before any - * resources are freed or any device is deleted. - */ -void -UndisplayDevices(void) -{ - DeviceIntPtr dev; - ScreenPtr screen = screenInfo.screens[0]; - - for (dev = inputInfo.devices; dev; dev = dev->next) - screen->DisplayCursor(dev, screen, NullCursor); -} - -/** - * Remove a device from the device list, closes it and thus frees all - * resources. - * Removes both enabled and disabled devices and notifies all devices about - * the removal of the device. - * - * No PresenceNotify is sent for device that the client never saw. This can - * happen if a malloc fails during the addition of master devices. If - * dev->init is FALSE it means the client never received a DeviceAdded event, - * so let's not send a DeviceRemoved event either. - * - * @param sendevent True if an XI2 event should be sent. - */ -int -RemoveDevice(DeviceIntPtr dev, BOOL sendevent) -{ - DeviceIntPtr prev,tmp,next; - int ret = BadMatch; - ScreenPtr screen = screenInfo.screens[0]; - int deviceid; - int initialized; - int flags[MAXDEVICES] = {0}; - - DebugF("(dix) removing device %d\n", dev->id); - - if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer) - return BadImplementation; - - initialized = dev->inited; - deviceid = dev->id; - - if (initialized) - { - if (DevHasCursor(dev)) - screen->DisplayCursor(dev, screen, NullCursor); - - DisableDevice(dev, sendevent); - flags[dev->id] = XIDeviceDisabled; - } - - prev = NULL; - for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) { - next = tmp->next; - if (tmp == dev) { - - if (prev==NULL) - inputInfo.devices = next; - else - prev->next = next; - - flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved; - CloseDevice(tmp); - ret = Success; - } - } - - prev = NULL; - for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) { - next = tmp->next; - if (tmp == dev) { - flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved; - CloseDevice(tmp); - - if (prev == NULL) - inputInfo.off_devices = next; - else - prev->next = next; - - ret = Success; - } - } - - if (ret == Success && initialized) { - inputInfo.numDevices--; - SendDevicePresenceEvent(deviceid, DeviceRemoved); - if (sendevent) - XISendDeviceHierarchyEvent(flags); - } - - return ret; -} - -int -NumMotionEvents(void) -{ - /* only called to fill data in initial connection reply. - * VCP is ok here, it is the only fixed device we have. */ - return inputInfo.pointer->valuator->numMotionEvents; -} - -void -RegisterPointerDevice(DeviceIntPtr device) -{ - RegisterOtherDevice(device); -} - -void -RegisterKeyboardDevice(DeviceIntPtr device) -{ - RegisterOtherDevice(device); -} - -int -dixLookupDevice(DeviceIntPtr *pDev, int id, ClientPtr client, Mask access_mode) -{ - DeviceIntPtr dev; - int rc; - *pDev = NULL; - - for (dev=inputInfo.devices; dev; dev=dev->next) { - if (dev->id == id) - goto found; - } - for (dev=inputInfo.off_devices; dev; dev=dev->next) { - if (dev->id == id) - goto found; - } - return BadDevice; - -found: - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc == Success) - *pDev = dev; - return rc; -} - -void -QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode) -{ - if (inputInfo.keyboard) { - *minCode = inputInfo.keyboard->key->xkbInfo->desc->min_key_code; - *maxCode = inputInfo.keyboard->key->xkbInfo->desc->max_key_code; - } -} - -/* Notably, this function does not expand the destination's keycode range, or - * notify clients. */ -Bool -SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src) -{ - int i, j; - KeySym *tmp; - 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) { - i = sizeof(KeySym) * src->mapWidth * - (dst->maxKeyCode - dst->minKeyCode + 1); - tmp = xcalloc(sizeof(KeySym), i); - if (!tmp) - return FALSE; - - if (dst->map) { - for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++) - memmove(&tmp[i * src->mapWidth], &dst->map[i * dst->mapWidth], - dst->mapWidth * sizeof(KeySym)); - xfree(dst->map); - } - dst->mapWidth = src->mapWidth; - dst->map = tmp; - } - else if (!dst->map) { - i = sizeof(KeySym) * src->mapWidth * - (dst->maxKeyCode - dst->minKeyCode + 1); - tmp = xcalloc(sizeof(KeySym), i); - if (!tmp) - return FALSE; - - dst->map = tmp; - dst->mapWidth = src->mapWidth; - } - - memmove(&dst->map[rowDif * dst->mapWidth], src->map, - (src->maxKeyCode - src->minKeyCode + 1) * - dst->mapWidth * sizeof(KeySym)); - - return TRUE; -} - -Bool -InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, Atom* labels, - CARD8 *map) -{ - ButtonClassPtr butc; - int i; - - butc = xcalloc(1, sizeof(ButtonClassRec)); - if (!butc) - return FALSE; - butc->numButtons = numButtons; - butc->sourceid = dev->id; - for (i = 1; i <= numButtons; i++) - butc->map[i] = map[i]; - for (i = numButtons + 1; i < MAP_LENGTH; i++) - butc->map[i] = i; - memcpy(butc->labels, labels, numButtons * sizeof(Atom)); - dev->button = butc; - return TRUE; -} - -Bool -InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels, - int numMotionEvents, int mode) -{ - int i; - ValuatorClassPtr valc; - - if (!dev) - return FALSE; - - if (numAxes >= MAX_VALUATORS) - { - LogMessage(X_WARNING, - "Device '%s' has %d axes, only using first %d.\n", - dev->name, numAxes, MAX_VALUATORS); - numAxes = MAX_VALUATORS; - } - - valc = (ValuatorClassPtr)xcalloc(1, sizeof(ValuatorClassRec) + - numAxes * sizeof(AxisInfo) + - numAxes * sizeof(double)); - if (!valc) - return FALSE; - - valc->sourceid = dev->id; - valc->motion = NULL; - valc->first_motion = 0; - valc->last_motion = 0; - - valc->numMotionEvents = numMotionEvents; - valc->motionHintWindow = NullWindow; - valc->numAxes = numAxes; - valc->mode = mode; - valc->axes = (AxisInfoPtr)(valc + 1); - valc->axisVal = (double *)(valc->axes + numAxes); - dev->valuator = valc; - - AllocateMotionHistory(dev); - - for (i=0; iaxisVal[i]=0; - } - - dev->last.numValuators = numAxes; - - if (IsMaster(dev) || /* do not accelerate master or xtest devices */ - IsXTestDevice(dev, NULL)) - InitPointerAccelerationScheme(dev, PtrAccelNoOp); - else - InitPointerAccelerationScheme(dev, PtrAccelDefault); - return TRUE; -} - -/* global list of acceleration schemes */ -ValuatorAccelerationRec pointerAccelerationScheme[] = { - {PtrAccelNoOp, NULL, NULL, NULL}, - {PtrAccelPredictable, acceleratePointerPredictable, NULL, AccelerationDefaultCleanup}, - {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL}, - {-1, NULL, NULL, NULL} /* terminator */ -}; - -/** - * install an acceleration scheme. returns TRUE on success, and should not - * change anything if unsuccessful. - */ -Bool -InitPointerAccelerationScheme(DeviceIntPtr dev, - int scheme) -{ - int x, i = -1; - void* data = NULL; - ValuatorClassPtr val; - - val = dev->valuator; - - if(!val) - return FALSE; - - if(IsMaster(dev) && scheme != PtrAccelNoOp) - return FALSE; - - for(x = 0; pointerAccelerationScheme[x].number >= 0; x++) { - if(pointerAccelerationScheme[x].number == scheme){ - i = x; - break; - } - } - - if(-1 == i) - return FALSE; - - if (val->accelScheme.AccelCleanupProc) - val->accelScheme.AccelCleanupProc(dev); - - /* init scheme-specific data */ - switch(scheme){ - case PtrAccelPredictable: - { - DeviceVelocityPtr s; - s = xalloc(sizeof(DeviceVelocityRec)); - if(!s) - return FALSE; - InitVelocityData(s); - data = s; - break; - } - default: - break; - } - - val->accelScheme = pointerAccelerationScheme[i]; - val->accelScheme.accelData = data; - - /* post-init scheme */ - switch(scheme){ - case PtrAccelPredictable: - InitializePredictableAccelerationProperties(dev); - break; - - default: - break; - } - - return TRUE; -} - -Bool -InitAbsoluteClassDeviceStruct(DeviceIntPtr dev) -{ - AbsoluteClassPtr abs; - - abs = xalloc(sizeof(AbsoluteClassRec)); - if (!abs) - return FALSE; - - /* we don't do anything sensible with these, but should */ - abs->min_x = NO_AXIS_LIMITS; - abs->min_y = NO_AXIS_LIMITS; - abs->max_x = NO_AXIS_LIMITS; - abs->max_y = NO_AXIS_LIMITS; - abs->flip_x = 0; - abs->flip_y = 0; - abs->rotation = 0; - abs->button_threshold = 0; - - abs->offset_x = 0; - abs->offset_y = 0; - abs->width = NO_AXIS_LIMITS; - abs->height = NO_AXIS_LIMITS; - abs->following = 0; - abs->screen = 0; - - abs->sourceid = dev->id; - - dev->absolute = abs; - - return TRUE; -} - -Bool -InitFocusClassDeviceStruct(DeviceIntPtr dev) -{ - FocusClassPtr focc; - - focc = xalloc(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; - focc->sourceid = dev->id; - dev->focus = focc; - return TRUE; -} - -Bool -InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc) -{ - PtrFeedbackPtr feedc; - - feedc = xalloc(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; -} - - -static LedCtrl defaultLedControl = { - DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0}; - -static BellCtrl defaultBellControl = { - DEFAULT_BELL, - DEFAULT_BELL_PITCH, - DEFAULT_BELL_DURATION, - 0}; - -static IntegerCtrl defaultIntegerControl = { - DEFAULT_INT_RESOLUTION, - DEFAULT_INT_MIN_VALUE, - DEFAULT_INT_MAX_VALUE, - DEFAULT_INT_DISPLAYED, - 0}; - -Bool -InitStringFeedbackClassDeviceStruct ( - DeviceIntPtr dev, StringCtrlProcPtr controlProc, - int max_symbols, int num_symbols_supported, KeySym *symbols) -{ - int i; - StringFeedbackPtr feedc; - - feedc = xalloc(sizeof(StringFeedbackClassRec)); - if (!feedc) - return FALSE; - feedc->CtrlProc = controlProc; - feedc->ctrl.num_symbols_supported = num_symbols_supported; - feedc->ctrl.num_symbols_displayed = 0; - feedc->ctrl.max_symbols = max_symbols; - feedc->ctrl.symbols_supported = xalloc (sizeof (KeySym) * num_symbols_supported); - feedc->ctrl.symbols_displayed = xalloc (sizeof (KeySym) * max_symbols); - if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed) - { - if (feedc->ctrl.symbols_supported) - xfree(feedc->ctrl.symbols_supported); - if (feedc->ctrl.symbols_displayed) - xfree(feedc->ctrl.symbols_displayed); - xfree(feedc); - return FALSE; - } - for (i=0; ictrl.symbols_supported+i) = *symbols++; - for (i=0; ictrl.symbols_displayed+i) = (KeySym) 0; - feedc->ctrl.id = 0; - if ( (feedc->next = dev->stringfeed) ) - feedc->ctrl.id = dev->stringfeed->ctrl.id + 1; - dev->stringfeed = feedc; - (*controlProc)(dev, &feedc->ctrl); - return TRUE; -} - -Bool -InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc, - BellCtrlProcPtr controlProc) -{ - BellFeedbackPtr feedc; - - feedc = xalloc(sizeof(BellFeedbackClassRec)); - if (!feedc) - return FALSE; - feedc->CtrlProc = controlProc; - feedc->BellProc = bellProc; - feedc->ctrl = defaultBellControl; - feedc->ctrl.id = 0; - if ( (feedc->next = dev->bell) ) - feedc->ctrl.id = dev->bell->ctrl.id + 1; - dev->bell = feedc; - (*controlProc)(dev, &feedc->ctrl); - return TRUE; -} - -Bool -InitLedFeedbackClassDeviceStruct (DeviceIntPtr dev, LedCtrlProcPtr controlProc) -{ - LedFeedbackPtr feedc; - - feedc = xalloc(sizeof(LedFeedbackClassRec)); - if (!feedc) - return FALSE; - feedc->CtrlProc = controlProc; - feedc->ctrl = defaultLedControl; - feedc->ctrl.id = 0; - if ( (feedc->next = dev->leds) ) - feedc->ctrl.id = dev->leds->ctrl.id + 1; - feedc->xkb_sli= NULL; - dev->leds = feedc; - (*controlProc)(dev, &feedc->ctrl); - return TRUE; -} - -Bool -InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr controlProc) -{ - IntegerFeedbackPtr feedc; - - feedc = xalloc(sizeof(IntegerFeedbackClassRec)); - if (!feedc) - return FALSE; - feedc->CtrlProc = controlProc; - feedc->ctrl = defaultIntegerControl; - feedc->ctrl.id = 0; - if ( (feedc->next = dev->intfeed) ) - feedc->ctrl.id = dev->intfeed->ctrl.id + 1; - dev->intfeed = feedc; - (*controlProc)(dev, &feedc->ctrl); - return TRUE; -} - -Bool -InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, Atom* btn_labels, - PtrCtrlProcPtr controlProc, int numMotionEvents, - int numAxes, Atom *axes_labels) -{ - DeviceIntPtr dev = (DeviceIntPtr)device; - - return(InitButtonClassDeviceStruct(dev, numButtons, btn_labels, map) && - InitValuatorClassDeviceStruct(dev, numAxes, axes_labels, - numMotionEvents, 0) && - InitPtrFeedbackClassDeviceStruct(dev, controlProc)); -} - -/* - * Check if the given buffer contains elements between low (inclusive) and - * high (inclusive) only. - * - * @return TRUE if the device map is invalid, FALSE otherwise. - */ -Bool -BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval) -{ - int i; - - 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; - } - } - return FALSE; -} - -int -ProcSetModifierMapping(ClientPtr client) -{ - xSetModifierMappingReply rep; - int rc; - REQUEST(xSetModifierMappingReq); - REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq); - - if (client->req_len != ((stuff->numKeyPerModifier << 1) + - bytes_to_int32(sizeof(xSetModifierMappingReq)))) - return BadLength; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = change_modmap(client, PickKeyboard(client), (KeyCode *)&stuff[1], - stuff->numKeyPerModifier); - if (rc == MappingFailed || rc == -1) - return BadValue; - if (rc != Success && rc != MappingSuccess && rc != MappingFailed && - rc != MappingBusy) - return rc; - - rep.success = rc; - - WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep); - return client->noClientException; -} - -int -ProcGetModifierMapping(ClientPtr client) -{ - xGetModifierMappingReply rep; - int max_keys_per_mod = 0; - KeyCode *modkeymap = NULL; - REQUEST_SIZE_MATCH(xReq); - - generate_modkeymap(client, PickKeyboard(client), &modkeymap, - &max_keys_per_mod); - - memset(&rep, 0, sizeof(xGetModifierMappingReply)); - rep.type = X_Reply; - rep.numKeyPerModifier = max_keys_per_mod; - rep.sequenceNumber = client->sequence; - /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */ - rep.length = max_keys_per_mod << 1; - - WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep); - (void)WriteToClient(client, max_keys_per_mod * 8, (char *) modkeymap); - - xfree(modkeymap); - - return client->noClientException; -} - -int -ProcChangeKeyboardMapping(ClientPtr client) -{ - REQUEST(xChangeKeyboardMappingReq); - unsigned len; - KeySymsRec keysyms; - DeviceIntPtr pDev, tmp; - int rc; - REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq); - - len = client->req_len - bytes_to_int32(sizeof(xChangeKeyboardMappingReq)); - if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode)) - return BadLength; - - pDev = PickKeyboard(client); - - if ((stuff->firstKeyCode < pDev->key->xkbInfo->desc->min_key_code) || - (stuff->firstKeyCode > pDev->key->xkbInfo->desc->max_key_code)) { - client->errorValue = stuff->firstKeyCode; - return BadValue; - - } - if (((unsigned)(stuff->firstKeyCode + stuff->keyCodes - 1) > - pDev->key->xkbInfo->desc->max_key_code) || - (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]; - - rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); - if (rc != Success) - return rc; - - XkbApplyMappingChange(pDev, &keysyms, stuff->firstKeyCode, - stuff->keyCodes, NULL, client); - - for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if (IsMaster(tmp) || tmp->u.master != pDev) - continue; - if (!tmp->key) - continue; - - rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); - if (rc != Success) - continue; - - XkbApplyMappingChange(tmp, &keysyms, stuff->firstKeyCode, - stuff->keyCodes, NULL, client); - } - - return client->noClientException; -} - -int -ProcSetPointerMapping(ClientPtr client) -{ - BYTE *map; - int ret; - int i, j; - DeviceIntPtr ptr = PickPointer(client); - xSetPointerMappingReply rep; - REQUEST(xSetPointerMappingReq); - REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq); - - if (client->req_len != - bytes_to_int32(sizeof(xSetPointerMappingReq) + stuff->nElts)) - return BadLength; - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.success = MappingSuccess; - map = (BYTE *)&stuff[1]; - - /* So we're bounded here by the number of core buttons. This check - * probably wants disabling through XFixes. */ - /* MPX: With ClientPointer, we can return the right number of buttons. - * Let's just hope nobody changed ClientPointer between GetPointerMapping - * and SetPointerMapping - */ - if (stuff->nElts != ptr->button->numButtons) { - client->errorValue = stuff->nElts; - return BadValue; - } - - /* Core protocol specs don't allow for duplicate mappings; this check - * almost certainly wants disabling through XFixes too. */ - for (i = 0; i < stuff->nElts; i++) { - for (j = i + 1; j < stuff->nElts; j++) { - if (map[i] && map[i] == map[j]) { - client->errorValue = map[i]; - return BadValue; - } - } - } - - ret = ApplyPointerMapping(ptr, map, stuff->nElts, client); - if (ret == MappingBusy) - rep.success = ret; - else if (ret == -1) - return BadValue; - else if (ret != Success) - return ret; - - WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); - return Success; -} - -int -ProcGetKeyboardMapping(ClientPtr client) -{ - xGetKeyboardMappingReply rep; - DeviceIntPtr kbd = PickKeyboard(client); - XkbDescPtr xkb; - KeySymsPtr syms; - int rc; - REQUEST(xGetKeyboardMappingReq); - REQUEST_SIZE_MATCH(xGetKeyboardMappingReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); - if (rc != Success) - return rc; - - xkb = kbd->key->xkbInfo->desc; - - if ((stuff->firstKeyCode < xkb->min_key_code) || - (stuff->firstKeyCode > xkb->max_key_code)) { - client->errorValue = stuff->firstKeyCode; - return BadValue; - } - if (stuff->firstKeyCode + stuff->count > xkb->max_key_code + 1) { - client->errorValue = stuff->count; - return BadValue; - } - - syms = XkbGetCoreMap(kbd); - if (!syms) - return BadAlloc; - - memset(&rep, 0, sizeof(xGetKeyboardMappingReply)); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.keySymsPerKeyCode = syms->mapWidth; - /* length is a count of 4 byte quantities and KeySyms are 4 bytes */ - rep.length = syms->mapWidth * stuff->count; - WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep); - client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; - WriteSwappedDataToClient(client, - syms->mapWidth * stuff->count * sizeof(KeySym), - &syms->map[syms->mapWidth * (stuff->firstKeyCode - - syms->minKeyCode)]); - xfree(syms->map); - xfree(syms); - - return client->noClientException; -} - -int -ProcGetPointerMapping(ClientPtr client) -{ - xGetPointerMappingReply rep; - /* Apps may get different values each time they call GetPointerMapping as - * the ClientPointer could change. */ - DeviceIntPtr ptr = PickPointer(client); - ButtonClassPtr butc = ptr->button; - int rc; - REQUEST_SIZE_MATCH(xReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.nElts = (butc) ? butc->numButtons : 0; - rep.length = ((unsigned)rep.nElts + (4-1))/4; - WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep); - if (butc) - 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)); -} - -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); -} - -static int -DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist, - BITS32 vmask) -{ -#define DO_ALL (-1) - KeybdCtrl ctrl; - int t; - int led = DO_ALL; - int key = DO_ALL; - BITS32 index2; - int mask = vmask, i; - XkbEventCauseRec cause; - - 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 (!(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; - } - - XkbSetCauseCoreReq(&cause,X_ChangeKeyboardControl,client); - XkbSetIndicators(keybd,((led == DO_ALL) ? ~0L : (1L<<(led-1))), - ctrl.leds, &cause); - ctrl.leds = keybd->kbdfeed->ctrl.leds; - - break; - case KBKey: - key = (KeyCode)*vlist; - vlist++; - if ((KeyCode)key < keybd->key->xkbInfo->desc->min_key_code || - (KeyCode)key > keybd->key->xkbInfo->desc->max_key_code) { - client->errorValue = key; - return BadValue; - } - if (!(mask & KBAutoRepeatMode)) - return BadMatch; - break; - case KBAutoRepeatMode: - i = (key >> 3); - mask = (1 << (key & 7)); - t = (CARD8)*vlist; - vlist++; - if (key != DO_ALL) - XkbDisableComputedAutoRepeats(keybd,key); - 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 = mask; - return BadValue; - } - } - keybd->kbdfeed->ctrl = ctrl; - - /* The XKB RepeatKeys control and core protocol global autorepeat */ - /* value are linked */ - XkbSetRepeatKeys(keybd, key, keybd->kbdfeed->ctrl.autoRepeat); - - return Success; - -#undef DO_ALL -} - -/** - * Changes kbd control on the ClientPointer and all attached SDs. - */ -int -ProcChangeKeyboardControl (ClientPtr client) -{ - XID *vlist; - BITS32 vmask; - int ret = Success, error = Success; - DeviceIntPtr pDev = NULL, keyboard; - REQUEST(xChangeKeyboardControlReq); - - REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq); - - vmask = stuff->mask; - vlist = (XID *)&stuff[1]; - - if (client->req_len != (sizeof(xChangeKeyboardControlReq)>>2)+Ones(vmask)) - return BadLength; - - keyboard = PickKeyboard(client); - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { - if ((pDev == keyboard || (!IsMaster(keyboard) && pDev->u.master == keyboard)) && - pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { - ret = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); - if (ret != Success) - return ret; - } - } - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { - if ((pDev == keyboard || (!IsMaster(keyboard) && pDev->u.master == keyboard)) && - pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { - ret = DoChangeKeyboardControl(client, pDev, vlist, vmask); - if (ret != Success) - error = ret; - } - } - - return error; -} - -int -ProcGetKeyboardControl (ClientPtr client) -{ - int rc, i; - DeviceIntPtr kbd = PickKeyboard(client); - KeybdCtrl *ctrl = &kbd->kbdfeed->ctrl; - xGetKeyboardControlReply rep; - REQUEST_SIZE_MATCH(xReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); - if (rc != Success) - return rc; - - 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 dev, keybd = PickKeyboard(client); - int base = keybd->kbdfeed->ctrl.bell; - int newpercent; - int rc; - 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; - - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev == keybd || (!IsMaster(dev) && dev->u.master == keybd)) && - dev->kbdfeed && dev->kbdfeed->BellProc) { - - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixBellAccess); - if (rc != Success) - return rc; - XkbHandleBell(FALSE, FALSE, dev, newpercent, - &dev->kbdfeed->ctrl, 0, None, NULL, client); - } - } - - return Success; -} - -int -ProcChangePointerControl(ClientPtr client) -{ - DeviceIntPtr dev, mouse = PickPointer(client); - PtrCtrl ctrl; /* might get BadValue part way through */ - int rc; - REQUEST(xChangePointerControlReq); - REQUEST_SIZE_MATCH(xChangePointerControlReq); - - if (!mouse->ptrfeed->CtrlProc) - return BadDevice; - - 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; - } - } - - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev == mouse || (!IsMaster(dev) && dev->u.master == mouse)) && - dev->ptrfeed && dev->ptrfeed->CtrlProc) { - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); - if (rc != Success) - return rc; - } - } - - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev == mouse || (!IsMaster(dev) && dev->u.master == mouse)) && - dev->ptrfeed && dev->ptrfeed->CtrlProc) { - dev->ptrfeed->ctrl = ctrl; - (*dev->ptrfeed->CtrlProc)(dev, &mouse->ptrfeed->ctrl); - } - } - - return Success; -} - -int -ProcGetPointerControl(ClientPtr client) -{ - DeviceIntPtr ptr = PickPointer(client); - PtrCtrl *ctrl = &ptr->ptrfeed->ctrl; - xGetPointerControlReply rep; - int rc; - REQUEST_SIZE_MATCH(xReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); - if (rc != Success) - return rc; - - 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(DeviceIntPtr dev, ClientPtr client) -{ - GrabPtr grab = dev->deviceGrab.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, rc; - unsigned long nEvents; - DeviceIntPtr mouse = PickPointer(client); - TimeStamp start, stop; - REQUEST(xGetMotionEventsReq); - REQUEST_SIZE_MATCH(xGetMotionEventsReq); - - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); - if (rc != Success) - return rc; - - 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; - count = GetMotionHistory(mouse, &coords, start.milliseconds, - stop.milliseconds, pWin->drawable.pScreen, - TRUE); - 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 * bytes_to_int32(sizeof(xTimecoord)); - rep.nEvents = nEvents; - WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep); - if (nEvents) - { - client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite; - WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord), - (char *)coords); - } - if (coords) - xfree(coords); - return Success; -} - -int -ProcQueryKeymap(ClientPtr client) -{ - xQueryKeymapReply rep; - int rc, i; - DeviceIntPtr keybd = PickKeyboard(client); - CARD8 *down = keybd->key->down; - - REQUEST_SIZE_MATCH(xReq); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 2; - - rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess); - if (rc != Success && rc != BadAccess) - return rc; - - for (i = 0; i<32; i++) - rep.map[i] = down[i]; - - if (rc == BadAccess) - memset(rep.map, 0, 32); - - WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep); - - return Success; -} - - -/** - * Recalculate the number of buttons for the master device. The number of - * buttons on the master device is equal to the number of buttons on the - * slave device with the highest number of buttons. - */ -static void -RecalculateMasterButtons(DeviceIntPtr slave) -{ - DeviceIntPtr dev, master; - int maxbuttons = 0; - - if (!slave->button || IsMaster(slave)) - return; - - master = GetMaster(slave, MASTER_POINTER); - if (!master) - return; - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (IsMaster(dev) || - dev->u.master != master || - !dev->button) - continue; - - maxbuttons = max(maxbuttons, dev->button->numButtons); - } - - if (master->button->numButtons != maxbuttons) - { - int i; - DeviceChangedEvent event; - - memset(&event, 0, sizeof(event)); - - master->button->numButtons = maxbuttons; - - event.header = ET_Internal; - event.type = ET_DeviceChanged; - event.time = CurrentTime; - event.deviceid = master->id; - event.flags = DEVCHANGE_POINTER_EVENT | DEVCHANGE_DEVICE_CHANGE; - event.buttons.num_buttons = maxbuttons; - memcpy(&event.buttons.names, master->button->labels, maxbuttons * - sizeof(Atom)); - - if (master->valuator) - { - event.num_valuators = master->valuator->numAxes; - for (i = 0; i < event.num_valuators; i++) - { - event.valuators[i].min = master->valuator->axes[i].min_value; - event.valuators[i].max = master->valuator->axes[i].max_value; - event.valuators[i].resolution = master->valuator->axes[i].resolution; - /* This should, eventually, be a per-axis mode */ - event.valuators[i].mode = master->valuator->mode; - event.valuators[i].name = master->valuator->axes[i].label; - } - } - - if (master->key) - { - event.keys.min_keycode = master->key->xkbInfo->desc->min_key_code; - event.keys.max_keycode = master->key->xkbInfo->desc->max_key_code; - } - - XISendDeviceChangedEvent(master, master, &event); - } -} - -/** - * Attach device 'dev' to device 'master'. - * Client is set to the client that issued the request, or NULL if it comes - * from some internal automatic pairing. - * - * Master may be NULL to set the device floating. - * - * We don't allow multi-layer hierarchies right now. You can't attach a slave - * to another slave. - */ -int -AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master) -{ - ScreenPtr screen; - DeviceIntPtr oldmaster; - if (!dev || IsMaster(dev)) - return BadDevice; - - if (master && !IsMaster(master)) /* can't attach to slaves */ - return BadDevice; - - /* set from floating to floating? */ - if (!dev->u.master && !master && dev->enabled) - return Success; - - /* free the existing sprite. */ - if (!dev->u.master && dev->spriteInfo->paired == dev) - { - screen = miPointerGetScreen(dev); - screen->DeviceCursorCleanup(dev, screen); - xfree(dev->spriteInfo->sprite); - } - - oldmaster = dev->u.master; - dev->u.master = master; - - /* If device is set to floating, we need to create a sprite for it, - * otherwise things go bad. However, we don't want to render the cursor, - * so we reset spriteOwner. - * Sprite has to be forced to NULL first, otherwise InitializeSprite won't - * alloc new memory but overwrite the previous one. - */ - if (!master) - { - WindowPtr currentRoot; - - if (dev->spriteInfo->sprite) - currentRoot = dev->spriteInfo->sprite->spriteTrace[0]; - else /* new device auto-set to floating */ - currentRoot = WindowTable[0]; - - /* we need to init a fake sprite */ - screen = currentRoot->drawable.pScreen; - screen->DeviceCursorInitialize(dev, screen); - dev->spriteInfo->sprite = NULL; - InitializeSprite(dev, currentRoot); - dev->spriteInfo->spriteOwner = FALSE; - dev->spriteInfo->paired = dev; - } else - { - dev->spriteInfo->sprite = master->spriteInfo->sprite; - dev->spriteInfo->paired = master; - dev->spriteInfo->spriteOwner = FALSE; - - RecalculateMasterButtons(master); - } - - /* XXX: in theory, the MD should change back to its old, original - * classes when the last SD is detached. Thanks to the XTEST devices, - * we'll always have an SD attached until the MD is removed. - * So let's not worry about that. - */ - - return Success; -} - -/** - * Return the device paired with the given device or NULL. - * Returns the device paired with the parent master if the given device is a - * slave device. - */ -DeviceIntPtr -GetPairedDevice(DeviceIntPtr dev) -{ - if (!IsMaster(dev) && dev->u.master) - dev = dev->u.master; - - return dev->spriteInfo->paired; -} - - -/** - * Returns the right master for the type of event needed. If the event is a - * keyboard event. - * This function may be called with a master device as argument. If so, the - * returned master is either the device itself or the paired master device. - * If dev is a floating slave device, NULL is returned. - * - * @type ::MASTER_KEYBOARD or ::MASTER_POINTER - */ -DeviceIntPtr -GetMaster(DeviceIntPtr dev, int which) -{ - DeviceIntPtr master; - - if (IsMaster(dev)) - master = dev; - else - master = dev->u.master; - - if (master) - { - if (which == MASTER_KEYBOARD) - { - if (master->type != MASTER_KEYBOARD) - master = GetPairedDevice(master); - } else - { - if (master->type != MASTER_POINTER) - master = GetPairedDevice(master); - } - } - - return master; -} - -/** - * Create a new device pair (== one pointer, one keyboard device). - * Only allocates the devices, you will need to call ActivateDevice() and - * EnableDevice() manually. - * Either a master or a slave device can be created depending on - * the value for master. - */ -int -AllocDevicePair (ClientPtr client, char* name, - DeviceIntPtr* ptr, - DeviceIntPtr* keybd, - DeviceProc ptr_proc, - DeviceProc keybd_proc, - Bool master) -{ - DeviceIntPtr pointer; - DeviceIntPtr keyboard; - *ptr = *keybd = NULL; - - pointer = AddInputDevice(client, ptr_proc, TRUE); - if (!pointer) - return BadAlloc; - - pointer->name = xcalloc(strlen(name) + strlen(" pointer") + 1, sizeof(char)); - strcpy(pointer->name, name); - strcat(pointer->name, " pointer"); - - pointer->public.processInputProc = ProcessOtherEvent; - pointer->public.realInputProc = ProcessOtherEvent; - XkbSetExtension(pointer, ProcessPointerEvent); - pointer->deviceGrab.ActivateGrab = ActivatePointerGrab; - pointer->deviceGrab.DeactivateGrab = DeactivatePointerGrab; - pointer->coreEvents = TRUE; - pointer->spriteInfo->spriteOwner = TRUE; - - pointer->u.lastSlave = NULL; - pointer->last.slave = NULL; - pointer->type = (master) ? MASTER_POINTER : SLAVE; - - keyboard = AddInputDevice(client, keybd_proc, TRUE); - if (!keyboard) - { - RemoveDevice(pointer, FALSE); - return BadAlloc; - } - - keyboard->name = xcalloc(strlen(name) + strlen(" keyboard") + 1, sizeof(char)); - strcpy(keyboard->name, name); - strcat(keyboard->name, " keyboard"); - - keyboard->public.processInputProc = ProcessOtherEvent; - keyboard->public.realInputProc = ProcessOtherEvent; - XkbSetExtension(keyboard, ProcessKeyboardEvent); - keyboard->deviceGrab.ActivateGrab = ActivateKeyboardGrab; - keyboard->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; - keyboard->coreEvents = TRUE; - keyboard->spriteInfo->spriteOwner = FALSE; - - keyboard->u.lastSlave = NULL; - keyboard->last.slave = NULL; - keyboard->type = (master) ? MASTER_KEYBOARD : SLAVE; - - /* The ClassesRec stores the device classes currently not used. */ - pointer->unused_classes = xcalloc(1, sizeof(ClassesRec)); - keyboard->unused_classes = xcalloc(1, sizeof(ClassesRec)); - - *ptr = pointer; - *keybd = keyboard; - - return Success; -} - +/************************************************************ + +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 +#include "windowstr.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "ptrveloc.h" +#include "site.h" +#include "xkbsrv.h" +#include "privates.h" +#include "xace.h" +#include "mi.h" + +#include "dispatch.h" +#include "swaprep.h" +#include "dixevents.h" +#include "mipointer.h" +#include "eventstr.h" + +#include +#include +#include +#include "exglobals.h" +#include "exevents.h" +#include "xiquerydevice.h" /* for SizeDeviceClasses */ +#include "xiproperty.h" +#include "enterleave.h" /* for EnterWindow() */ +#include "xserver-properties.h" +#include "xichangehierarchy.h" /* For XISendDeviceHierarchyEvent */ + +/** @file + * This file handles input device-related stuff. + */ + +static void RecalculateMasterButtons(DeviceIntPtr slave); + +/** + * DIX property handler. + */ +static int +DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop, + BOOL checkonly) +{ + if (property == XIGetKnownProperty(XI_PROP_ENABLED)) + { + if (prop->format != 8 || prop->type != XA_INTEGER || prop->size != 1) + return BadValue; + + /* Don't allow disabling of VCP/VCK */ + if ((dev == inputInfo.pointer || dev == inputInfo.keyboard) && + !(*(CARD8*)prop->data)) + return BadAccess; + + if (!checkonly) + { + if ((*((CARD8*)prop->data)) && !dev->enabled) + EnableDevice(dev, TRUE); + else if (!(*((CARD8*)prop->data)) && dev->enabled) + DisableDevice(dev, TRUE); + } + } + + return Success; +} + +/* Pair the keyboard to the pointer device. Keyboard events will follow the + * pointer sprite. Only applicable for master devices. + * If the client is set, the request to pair comes from some client. In this + * case, we need to check for access. If the client is NULL, it's from an + * internal automatic pairing, we must always permit this. + */ +static int +PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd) +{ + if (!ptr) + return BadDevice; + + /* Don't allow pairing for slave devices */ + if (!IsMaster(ptr) || !IsMaster(kbd)) + return BadDevice; + + if (ptr->spriteInfo->paired) + return BadDevice; + + if (kbd->spriteInfo->spriteOwner) + { + free(kbd->spriteInfo->sprite); + kbd->spriteInfo->sprite = NULL; + kbd->spriteInfo->spriteOwner = FALSE; + } + + kbd->spriteInfo->sprite = ptr->spriteInfo->sprite; + kbd->spriteInfo->paired = ptr; + ptr->spriteInfo->paired = kbd; + return Success; +} + + +/** + * Find and return the next unpaired MD pointer device. + */ +static DeviceIntPtr +NextFreePointerDevice(void) +{ + DeviceIntPtr dev; + for (dev = inputInfo.devices; dev; dev = dev->next) + if (IsMaster(dev) && + dev->spriteInfo->spriteOwner && + !dev->spriteInfo->paired) + return dev; + return NULL; +} + +/** + * Create a new input device and init it to sane values. The device is added + * to the server's off_devices list. + * + * @param deviceProc Callback for device control function (switch dev on/off). + * @return The newly created device. + */ +DeviceIntPtr +AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) +{ + DeviceIntPtr dev, *prev; /* not a typo */ + DeviceIntPtr devtmp; + int devid; + char devind[MAXDEVICES]; + BOOL enabled; + + /* Find next available id, 0 and 1 are reserved */ + memset(devind, 0, sizeof(char)*MAXDEVICES); + for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next) + devind[devtmp->id]++; + for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next) + devind[devtmp->id]++; + for (devid = 2; devid < MAXDEVICES && devind[devid]; devid++) + ; + + if (devid >= MAXDEVICES) + return (DeviceIntPtr)NULL; + dev = calloc(sizeof(DeviceIntRec) + sizeof(SpriteInfoRec), 1); + if (!dev) + return (DeviceIntPtr)NULL; + dev->id = devid; + dev->public.processInputProc = (ProcessInputProc)NoopDDA; + dev->public.realInputProc = (ProcessInputProc)NoopDDA; + dev->public.enqueueInputProc = EnqueueEvent; + dev->deviceProc = deviceProc; + dev->startup = autoStart; + + /* device grab defaults */ + dev->deviceGrab.grabTime = currentTime; + dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; + dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; + + dev->coreEvents = TRUE; + + /* sprite defaults */ + dev->spriteInfo = (SpriteInfoPtr)&dev[1]; + + /* security creation/labeling check + */ + if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixCreateAccess)) { + free(dev); + return NULL; + } + + inputInfo.numDevices++; + + for (prev = &inputInfo.off_devices; *prev; prev = &(*prev)->next) + ; + *prev = dev; + dev->next = NULL; + + enabled = FALSE; + XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), + XA_INTEGER, 8, PropModeReplace, 1, &enabled, + FALSE); + XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE); + XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL); + + return dev; +} + +void +SendDevicePresenceEvent(int deviceid, int type) +{ + DeviceIntRec dummyDev; + devicePresenceNotify ev; + + memset(&dummyDev, 0, sizeof(DeviceIntRec)); + ev.type = DevicePresenceNotify; + ev.time = currentTime.milliseconds; + ev.devchange = type; + ev.deviceid = deviceid; + dummyDev.id = XIAllDevices; + SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, + (xEvent*)&ev, 1); +} + +/** + * Enable the device through the driver, add the device to the device list. + * Switch device ON through the driver and push it onto the global device + * list. Initialize the DIX sprite or pair the device. All clients are + * notified about the device being enabled. + * + * A master pointer device needs to be enabled before a master keyboard + * device. + * + * @param The device to be enabled. + * @param sendevent True if an XI2 event should be sent. + * @return TRUE on success or FALSE otherwise. + */ +Bool +EnableDevice(DeviceIntPtr dev, BOOL sendevent) +{ + DeviceIntPtr *prev; + int ret; + DeviceIntPtr other; + BOOL enabled; + int flags[MAXDEVICES] = {0}; + + for (prev = &inputInfo.off_devices; + *prev && (*prev != dev); + prev = &(*prev)->next) + ; + + if (!dev->spriteInfo->sprite) + { + if (IsMaster(dev)) + { + /* Sprites appear on first root window, so we can hardcode it */ + if (dev->spriteInfo->spriteOwner) + { + InitializeSprite(dev, WindowTable[0]); + /* mode doesn't matter */ + EnterWindow(dev, WindowTable[0], NotifyAncestor); + } + else if ((other = NextFreePointerDevice()) == NULL) + { + ErrorF("[dix] cannot find pointer to pair with. " + "This is a bug.\n"); + return FALSE; + } else + PairDevices(NULL, other, dev); + } else + { + if (dev->coreEvents) + other = (IsPointerDevice(dev)) ? inputInfo.pointer : + inputInfo.keyboard; + else + other = NULL; /* auto-float non-core devices */ + AttachDevice(NULL, dev, other); + } + } + + /* Before actually enabling the device, we need to make sure the event + * list's events have enough memory for a ClassesChangedEvent from the + * device + */ + if ((*prev != dev) || !dev->inited || + ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) { + ErrorF("[dix] couldn't enable device %d\n", dev->id); + return FALSE; + } + dev->enabled = TRUE; + *prev = dev->next; + + for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next) + ; + *prev = dev; + dev->next = NULL; + + enabled = TRUE; + XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), + XA_INTEGER, 8, PropModeReplace, 1, &enabled, + TRUE); + + SendDevicePresenceEvent(dev->id, DeviceEnabled); + if (sendevent) + { + flags[dev->id] |= XIDeviceEnabled; + XISendDeviceHierarchyEvent(flags); + } + + RecalculateMasterButtons(dev); + + return TRUE; +} + +/** + * Switch a device off through the driver and push it onto the off_devices + * list. A device will not send events while disabled. All clients are + * notified about the device being disabled. + * + * Master keyboard devices have to be disabled before master pointer devices + * otherwise things turn bad. + * + * @param sendevent True if an XI2 event should be sent. + * @return TRUE on success or FALSE otherwise. + */ +Bool +DisableDevice(DeviceIntPtr dev, BOOL sendevent) +{ + DeviceIntPtr *prev, other; + BOOL enabled; + int flags[MAXDEVICES] = {0}; + + for (prev = &inputInfo.devices; + *prev && (*prev != dev); + prev = &(*prev)->next) + ; + if (*prev != dev) + return FALSE; + + /* float attached devices */ + if (IsMaster(dev)) + { + for (other = inputInfo.devices; other; other = other->next) + { + if (other->u.master == dev) + { + AttachDevice(NULL, other, NULL); + flags[other->id] |= XISlaveDetached; + } + } + } + else + { + for (other = inputInfo.devices; other; other = other->next) + { + if (IsMaster(other) && other->u.lastSlave == dev) + other->u.lastSlave = NULL; + } + } + + if (IsMaster(dev) && dev->spriteInfo->sprite) + { + for (other = inputInfo.devices; other; other = other->next) + { + if (other->spriteInfo->paired == dev) + { + ErrorF("[dix] cannot disable device, still paired. " + "This is a bug. \n"); + return FALSE; + } + } + } + + (void)(*dev->deviceProc)(dev, DEVICE_OFF); + dev->enabled = FALSE; + + /* now that the device is disabled, we can reset the signal handler's + * last.slave */ + OsBlockSignals(); + for (other = inputInfo.devices; other; other = other->next) + { + if (other->last.slave == dev) + other->last.slave = NULL; + } + OsReleaseSignals(); + + LeaveWindow(dev); + SetFocusOut(dev); + + *prev = dev->next; + dev->next = inputInfo.off_devices; + inputInfo.off_devices = dev; + + enabled = FALSE; + XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), + XA_INTEGER, 8, PropModeReplace, 1, &enabled, + TRUE); + + SendDevicePresenceEvent(dev->id, DeviceDisabled); + if (sendevent) + { + flags[dev->id] = XIDeviceDisabled; + XISendDeviceHierarchyEvent(flags); + } + + RecalculateMasterButtons(dev); + + return TRUE; +} + +/** + * Initialise a new device through the driver and tell all clients about the + * new device. + * + * Must be called before EnableDevice. + * The device will NOT send events until it is enabled! + * + * @param sendevent True if an XI2 event should be sent. + * @return Success or an error code on failure. + */ +int +ActivateDevice(DeviceIntPtr dev, BOOL sendevent) +{ + int ret = Success; + ScreenPtr pScreen = screenInfo.screens[0]; + + if (!dev || !dev->deviceProc) + return BadImplementation; + + ret = (*dev->deviceProc) (dev, DEVICE_INIT); + dev->inited = (ret == Success); + if (!dev->inited) + return ret; + + /* Initialize memory for sprites. */ + if (IsMaster(dev) && dev->spriteInfo->spriteOwner) + pScreen->DeviceCursorInitialize(dev, pScreen); + + SendDevicePresenceEvent(dev->id, DeviceAdded); + if (sendevent) + { + int flags[MAXDEVICES] = {0}; + flags[dev->id] = XISlaveAdded; + XISendDeviceHierarchyEvent(flags); + } + return ret; +} + +/** + * Ring the bell. + * The actual task of ringing the bell is the job of the DDX. + */ +static void +CoreKeyboardBell(int volume, DeviceIntPtr pDev, pointer arg, int something) +{ + KeybdCtrl *ctrl = arg; + + DDXRingBell(volume, ctrl->bell_pitch, ctrl->bell_duration); +} + +static void +CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl) +{ + return; +} + +/** + * Device control function for the Virtual Core Keyboard. + */ +int +CoreKeyboardProc(DeviceIntPtr pDev, int what) +{ + + switch (what) { + case DEVICE_INIT: + if (!InitKeyboardDeviceStruct(pDev, NULL, CoreKeyboardBell, + CoreKeyboardCtl)) + { + ErrorF("Keyboard initialization failed. This could be a missing " + "or incorrect setup of xkeyboard-config.\n"); + return BadValue; + } + return Success; + + case DEVICE_ON: + case DEVICE_OFF: + return Success; + + case DEVICE_CLOSE: + return Success; + } + + return BadMatch; +} + +/** + * Device control function for the Virtual Core Pointer. + */ +int +CorePointerProc(DeviceIntPtr pDev, int what) +{ +#define NBUTTONS 10 +#define NAXES 2 + BYTE map[NBUTTONS + 1]; + int i = 0; + Atom btn_labels[NBUTTONS] = {0}; + Atom axes_labels[NAXES] = {0}; + + switch (what) { + case DEVICE_INIT: + for (i = 1; i <= NBUTTONS; i++) + map[i] = i; + + btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); + btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); + btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); + btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); + btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); + /* don't know about the rest */ + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); + + if (!InitPointerDeviceStruct((DevicePtr)pDev, map, NBUTTONS, btn_labels, + (PtrCtrlProcPtr)NoopDDA, + GetMotionHistorySize(), NAXES, axes_labels)) + { + ErrorF("Could not initialize device '%s'. Out of memory.\n", + pDev->name); + return BadAlloc; /* IPDS only fails on allocs */ + } + pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; + pDev->last.valuators[0] = pDev->valuator->axisVal[0]; + pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; + pDev->last.valuators[1] = pDev->valuator->axisVal[1]; + break; + + case DEVICE_CLOSE: + break; + + default: + break; + } + + return Success; + +#undef NBUTTONS +#undef NAXES +} + +/** + * Initialise the two core devices, VCP and VCK (see events.c). + * Both devices are not tied to physical devices, but guarantee that there is + * always a keyboard and a pointer present and keep the protocol semantics. + * + * Note that the server MUST have two core devices at all times, even if there + * is no physical device connected. + */ +void +InitCoreDevices(void) +{ + if (AllocDevicePair(serverClient, "Virtual core", + &inputInfo.pointer, &inputInfo.keyboard, + CorePointerProc, CoreKeyboardProc, + TRUE) != Success) + FatalError("Failed to allocate core devices"); + + if (ActivateDevice(inputInfo.pointer, TRUE) != Success || + ActivateDevice(inputInfo.keyboard, TRUE) != Success) + FatalError("Failed to activate core devices."); + if (!EnableDevice(inputInfo.pointer, TRUE) || + !EnableDevice(inputInfo.keyboard, TRUE)) + FatalError("Failed to enable core devices."); + + InitXTestDevices(); +} + +/** + * Activate all switched-off devices and then enable all those devices. + * + * Will return an error if no core keyboard or core pointer is present. + * In theory this should never happen if you call InitCoreDevices() first. + * + * InitAndStartDevices needs to be called AFTER the windows are initialized. + * Devices will start sending events after InitAndStartDevices() has + * completed. + * + * @return Success or error code on failure. + */ +int +InitAndStartDevices(void) +{ + DeviceIntPtr dev, next; + + for (dev = inputInfo.off_devices; dev; dev = dev->next) { + DebugF("(dix) initialising device %d\n", dev->id); + if (!dev->inited) + ActivateDevice(dev, TRUE); + } + + /* enable real devices */ + for (dev = inputInfo.off_devices; dev; dev = next) + { + DebugF("(dix) enabling device %d\n", dev->id); + next = dev->next; + if (dev->inited && dev->startup) + EnableDevice(dev, TRUE); + } + + return Success; +} + +/** + * Free the given device class and reset the pointer to NULL. + */ +static void +FreeDeviceClass(int type, pointer *class) +{ + if (!(*class)) + return; + + switch(type) + { + case KeyClass: + { + KeyClassPtr* k = (KeyClassPtr*)class; + if ((*k)->xkbInfo) + { + XkbFreeInfo((*k)->xkbInfo); + (*k)->xkbInfo = NULL; + } + free((*k)); + break; + } + case ButtonClass: + { + ButtonClassPtr *b = (ButtonClassPtr*)class; + if ((*b)->xkb_acts) + free((*b)->xkb_acts); + free((*b)); + break; + } + case ValuatorClass: + { + ValuatorClassPtr *v = (ValuatorClassPtr*)class; + + if ((*v)->motion) + free((*v)->motion); + free((*v)); + break; + } + case FocusClass: + { + FocusClassPtr *f = (FocusClassPtr*)class; + free((*f)->trace); + free((*f)); + break; + } + case ProximityClass: + { + ProximityClassPtr *p = (ProximityClassPtr*)class; + free((*p)); + break; + } + } + *class = NULL; +} + +static void +FreeFeedbackClass(int type, pointer *class) +{ + if (!(*class)) + return; + + switch(type) + { + case KbdFeedbackClass: + { + KbdFeedbackPtr *kbdfeed = (KbdFeedbackPtr*)class; + KbdFeedbackPtr k, knext; + for (k = (*kbdfeed); k; k = knext) { + knext = k->next; + if (k->xkb_sli) + XkbFreeSrvLedInfo(k->xkb_sli); + free(k); + } + break; + } + case PtrFeedbackClass: + { + PtrFeedbackPtr *ptrfeed = (PtrFeedbackPtr*)class; + PtrFeedbackPtr p, pnext; + + for (p = (*ptrfeed); p; p = pnext) { + pnext = p->next; + free(p); + } + break; + } + case IntegerFeedbackClass: + { + IntegerFeedbackPtr *intfeed = (IntegerFeedbackPtr*)class; + IntegerFeedbackPtr i, inext; + + for (i = (*intfeed); i; i = inext) { + inext = i->next; + free(i); + } + break; + } + case StringFeedbackClass: + { + StringFeedbackPtr *stringfeed = (StringFeedbackPtr*)class; + StringFeedbackPtr s, snext; + + for (s = (*stringfeed); s; s = snext) { + snext = s->next; + free(s->ctrl.symbols_supported); + free(s->ctrl.symbols_displayed); + free(s); + } + break; + } + case BellFeedbackClass: + { + BellFeedbackPtr *bell = (BellFeedbackPtr*)class; + BellFeedbackPtr b, bnext; + + for (b = (*bell); b; b = bnext) { + bnext = b->next; + free(b); + } + break; + } + case LedFeedbackClass: + { + LedFeedbackPtr *leds = (LedFeedbackPtr*)class; + LedFeedbackPtr l, lnext; + + for (l = (*leds); l; l = lnext) { + lnext = l->next; + if (l->xkb_sli) + XkbFreeSrvLedInfo(l->xkb_sli); + free(l); + } + break; + } + } + *class = NULL; +} + +static void +FreeAllDeviceClasses(ClassesPtr classes) +{ + if (!classes) + return; + + FreeDeviceClass(KeyClass, (pointer)&classes->key); + FreeDeviceClass(ValuatorClass, (pointer)&classes->valuator); + FreeDeviceClass(ButtonClass, (pointer)&classes->button); + FreeDeviceClass(FocusClass, (pointer)&classes->focus); + FreeDeviceClass(ProximityClass, (pointer)&classes->proximity); + + FreeFeedbackClass(KbdFeedbackClass, (pointer)&classes->kbdfeed); + FreeFeedbackClass(PtrFeedbackClass, (pointer)&classes->ptrfeed); + FreeFeedbackClass(IntegerFeedbackClass, (pointer)&classes->intfeed); + FreeFeedbackClass(StringFeedbackClass, (pointer)&classes->stringfeed); + FreeFeedbackClass(BellFeedbackClass, (pointer)&classes->bell); + FreeFeedbackClass(LedFeedbackClass, (pointer)&classes->leds); + +} + +/** + * Close down a device and free all resources. + * Once closed down, the driver will probably not expect you that you'll ever + * enable it again and free associated structs. If you want the device to just + * be disabled, DisableDevice(). + * Don't call this function directly, use RemoveDevice() instead. + */ +static void +CloseDevice(DeviceIntPtr dev) +{ + ScreenPtr screen = screenInfo.screens[0]; + ClassesPtr classes; + int j; + + if (!dev) + return; + + XIDeleteAllDeviceProperties(dev); + + if (dev->inited) + (void)(*dev->deviceProc)(dev, DEVICE_CLOSE); + + /* free sprite memory */ + if (IsMaster(dev) && dev->spriteInfo->sprite) + screen->DeviceCursorCleanup(dev, screen); + + /* free acceleration info */ + if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc) + dev->valuator->accelScheme.AccelCleanupProc(dev); + + while (dev->xkb_interest) + XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource); + + free(dev->name); + + classes = (ClassesPtr)&dev->key; + FreeAllDeviceClasses(classes); + + if (IsMaster(dev)) + { + classes = dev->unused_classes; + FreeAllDeviceClasses(classes); + free(classes); + } + + if (DevHasCursor(dev) && dev->spriteInfo->sprite) { + if (dev->spriteInfo->sprite->current) + FreeCursor(dev->spriteInfo->sprite->current, None); + free(dev->spriteInfo->sprite->spriteTrace); + free(dev->spriteInfo->sprite); + } + + /* a client may have the device set as client pointer */ + for (j = 0; j < currentMaxClients; j++) + { + if (clients[j] && clients[j]->clientPtr == dev) + { + clients[j]->clientPtr = NULL; + clients[j]->clientPtr = PickPointer(clients[j]); + } + } + + free(dev->deviceGrab.sync.event); + dixFreePrivates(dev->devPrivates); + free(dev); +} + +/** + * Shut down all devices of one list and free all resources. + */ +static +void +CloseDeviceList(DeviceIntPtr *listHead) +{ + /* Used to mark devices that we tried to free */ + Bool freedIds[MAXDEVICES]; + DeviceIntPtr dev; + int i; + + if (listHead == NULL) + return; + + for (i = 0; i < MAXDEVICES; i++) + freedIds[i] = FALSE; + + dev = *listHead; + while (dev != NULL) + { + freedIds[dev->id] = TRUE; + DeleteInputDeviceRequest(dev); + + dev = *listHead; + while (dev != NULL && freedIds[dev->id]) + dev = dev->next; + } +} + +/** + * Shut down all devices, free all resources, etc. + * Only useful if you're shutting down the server! + */ +void +CloseDownDevices(void) +{ + DeviceIntPtr dev; + + /* Float all SDs before closing them. Note that at this point resources + * (e.g. cursors) have been freed already, so we can't just call + * AttachDevice(NULL, dev, NULL). Instead, we have to forcibly set master + * to NULL and pretend nothing happened. + */ + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!IsMaster(dev) && dev->u.master) + dev->u.master = NULL; + } + + CloseDeviceList(&inputInfo.devices); + CloseDeviceList(&inputInfo.off_devices); + + CloseDevice(inputInfo.pointer); + CloseDevice(inputInfo.keyboard); + + inputInfo.devices = NULL; + inputInfo.off_devices = NULL; + inputInfo.keyboard = NULL; + inputInfo.pointer = NULL; + XkbDeleteRulesDflts(); +} + +/** + * Remove the cursor sprite for all devices. This needs to be done before any + * resources are freed or any device is deleted. + */ +void +UndisplayDevices(void) +{ + DeviceIntPtr dev; + ScreenPtr screen = screenInfo.screens[0]; + + for (dev = inputInfo.devices; dev; dev = dev->next) + screen->DisplayCursor(dev, screen, NullCursor); +} + +/** + * Remove a device from the device list, closes it and thus frees all + * resources. + * Removes both enabled and disabled devices and notifies all devices about + * the removal of the device. + * + * No PresenceNotify is sent for device that the client never saw. This can + * happen if a malloc fails during the addition of master devices. If + * dev->init is FALSE it means the client never received a DeviceAdded event, + * so let's not send a DeviceRemoved event either. + * + * @param sendevent True if an XI2 event should be sent. + */ +int +RemoveDevice(DeviceIntPtr dev, BOOL sendevent) +{ + DeviceIntPtr prev,tmp,next; + int ret = BadMatch; + ScreenPtr screen = screenInfo.screens[0]; + int deviceid; + int initialized; + int flags[MAXDEVICES] = {0}; + + DebugF("(dix) removing device %d\n", dev->id); + + if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer) + return BadImplementation; + + initialized = dev->inited; + deviceid = dev->id; + + if (initialized) + { + if (DevHasCursor(dev)) + screen->DisplayCursor(dev, screen, NullCursor); + + DisableDevice(dev, sendevent); + flags[dev->id] = XIDeviceDisabled; + } + + prev = NULL; + for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) { + next = tmp->next; + if (tmp == dev) { + + if (prev==NULL) + inputInfo.devices = next; + else + prev->next = next; + + flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved; + CloseDevice(tmp); + ret = Success; + } + } + + prev = NULL; + for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) { + next = tmp->next; + if (tmp == dev) { + flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved; + CloseDevice(tmp); + + if (prev == NULL) + inputInfo.off_devices = next; + else + prev->next = next; + + ret = Success; + } + } + + if (ret == Success && initialized) { + inputInfo.numDevices--; + SendDevicePresenceEvent(deviceid, DeviceRemoved); + if (sendevent) + XISendDeviceHierarchyEvent(flags); + } + + return ret; +} + +int +NumMotionEvents(void) +{ + /* only called to fill data in initial connection reply. + * VCP is ok here, it is the only fixed device we have. */ + return inputInfo.pointer->valuator->numMotionEvents; +} + +void +RegisterPointerDevice(DeviceIntPtr device) +{ + RegisterOtherDevice(device); +} + +void +RegisterKeyboardDevice(DeviceIntPtr device) +{ + RegisterOtherDevice(device); +} + +int +dixLookupDevice(DeviceIntPtr *pDev, int id, ClientPtr client, Mask access_mode) +{ + DeviceIntPtr dev; + int rc; + *pDev = NULL; + + for (dev=inputInfo.devices; dev; dev=dev->next) { + if (dev->id == id) + goto found; + } + for (dev=inputInfo.off_devices; dev; dev=dev->next) { + if (dev->id == id) + goto found; + } + return BadDevice; + +found: + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc == Success) + *pDev = dev; + return rc; +} + +void +QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode) +{ + if (inputInfo.keyboard) { + *minCode = inputInfo.keyboard->key->xkbInfo->desc->min_key_code; + *maxCode = inputInfo.keyboard->key->xkbInfo->desc->max_key_code; + } +} + +/* Notably, this function does not expand the destination's keycode range, or + * notify clients. */ +Bool +SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src) +{ + int i, j; + KeySym *tmp; + 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) { + i = sizeof(KeySym) * src->mapWidth * + (dst->maxKeyCode - dst->minKeyCode + 1); + tmp = calloc(sizeof(KeySym), i); + if (!tmp) + return FALSE; + + if (dst->map) { + for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++) + memmove(&tmp[i * src->mapWidth], &dst->map[i * dst->mapWidth], + dst->mapWidth * sizeof(KeySym)); + free(dst->map); + } + dst->mapWidth = src->mapWidth; + dst->map = tmp; + } + else if (!dst->map) { + i = sizeof(KeySym) * src->mapWidth * + (dst->maxKeyCode - dst->minKeyCode + 1); + tmp = calloc(sizeof(KeySym), i); + if (!tmp) + return FALSE; + + dst->map = tmp; + dst->mapWidth = src->mapWidth; + } + + memmove(&dst->map[rowDif * dst->mapWidth], src->map, + (src->maxKeyCode - src->minKeyCode + 1) * + dst->mapWidth * sizeof(KeySym)); + + return TRUE; +} + +Bool +InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, Atom* labels, + CARD8 *map) +{ + ButtonClassPtr butc; + int i; + + butc = calloc(1, sizeof(ButtonClassRec)); + if (!butc) + return FALSE; + butc->numButtons = numButtons; + butc->sourceid = dev->id; + for (i = 1; i <= numButtons; i++) + butc->map[i] = map[i]; + for (i = numButtons + 1; i < MAP_LENGTH; i++) + butc->map[i] = i; + memcpy(butc->labels, labels, numButtons * sizeof(Atom)); + dev->button = butc; + return TRUE; +} + +Bool +InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels, + int numMotionEvents, int mode) +{ + int i; + ValuatorClassPtr valc; + + if (!dev) + return FALSE; + + if (numAxes >= MAX_VALUATORS) + { + LogMessage(X_WARNING, + "Device '%s' has %d axes, only using first %d.\n", + dev->name, numAxes, MAX_VALUATORS); + numAxes = MAX_VALUATORS; + } + + valc = (ValuatorClassPtr)calloc(1, sizeof(ValuatorClassRec) + + numAxes * sizeof(AxisInfo) + + numAxes * sizeof(double)); + if (!valc) + return FALSE; + + valc->sourceid = dev->id; + valc->motion = NULL; + valc->first_motion = 0; + valc->last_motion = 0; + + valc->numMotionEvents = numMotionEvents; + valc->motionHintWindow = NullWindow; + valc->numAxes = numAxes; + valc->mode = mode; + valc->axes = (AxisInfoPtr)(valc + 1); + valc->axisVal = (double *)(valc->axes + numAxes); + dev->valuator = valc; + + AllocateMotionHistory(dev); + + for (i=0; iaxisVal[i]=0; + } + + dev->last.numValuators = numAxes; + + if (IsMaster(dev) || /* do not accelerate master or xtest devices */ + IsXTestDevice(dev, NULL)) + InitPointerAccelerationScheme(dev, PtrAccelNoOp); + else + InitPointerAccelerationScheme(dev, PtrAccelDefault); + return TRUE; +} + +/* global list of acceleration schemes */ +ValuatorAccelerationRec pointerAccelerationScheme[] = { + {PtrAccelNoOp, NULL, NULL, NULL}, + {PtrAccelPredictable, acceleratePointerPredictable, NULL, AccelerationDefaultCleanup}, + {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL}, + {-1, NULL, NULL, NULL} /* terminator */ +}; + +/** + * install an acceleration scheme. returns TRUE on success, and should not + * change anything if unsuccessful. + */ +Bool +InitPointerAccelerationScheme(DeviceIntPtr dev, + int scheme) +{ + int x, i = -1; + void* data = NULL; + ValuatorClassPtr val; + + val = dev->valuator; + + if(!val) + return FALSE; + + if(IsMaster(dev) && scheme != PtrAccelNoOp) + return FALSE; + + for(x = 0; pointerAccelerationScheme[x].number >= 0; x++) { + if(pointerAccelerationScheme[x].number == scheme){ + i = x; + break; + } + } + + if(-1 == i) + return FALSE; + + if (val->accelScheme.AccelCleanupProc) + val->accelScheme.AccelCleanupProc(dev); + + /* init scheme-specific data */ + switch(scheme){ + case PtrAccelPredictable: + { + DeviceVelocityPtr s; + s = malloc(sizeof(DeviceVelocityRec)); + if(!s) + return FALSE; + InitVelocityData(s); + data = s; + break; + } + default: + break; + } + + val->accelScheme = pointerAccelerationScheme[i]; + val->accelScheme.accelData = data; + + /* post-init scheme */ + switch(scheme){ + case PtrAccelPredictable: + InitializePredictableAccelerationProperties(dev); + break; + + default: + break; + } + + return TRUE; +} + +Bool +InitAbsoluteClassDeviceStruct(DeviceIntPtr dev) +{ + AbsoluteClassPtr abs; + + abs = malloc(sizeof(AbsoluteClassRec)); + if (!abs) + return FALSE; + + /* we don't do anything sensible with these, but should */ + abs->min_x = NO_AXIS_LIMITS; + abs->min_y = NO_AXIS_LIMITS; + abs->max_x = NO_AXIS_LIMITS; + abs->max_y = NO_AXIS_LIMITS; + abs->flip_x = 0; + abs->flip_y = 0; + abs->rotation = 0; + abs->button_threshold = 0; + + abs->offset_x = 0; + abs->offset_y = 0; + abs->width = NO_AXIS_LIMITS; + abs->height = NO_AXIS_LIMITS; + abs->following = 0; + abs->screen = 0; + + abs->sourceid = dev->id; + + dev->absolute = abs; + + return TRUE; +} + +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; + focc->sourceid = dev->id; + dev->focus = focc; + return TRUE; +} + +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; +} + + +static LedCtrl defaultLedControl = { + DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0}; + +static BellCtrl defaultBellControl = { + DEFAULT_BELL, + DEFAULT_BELL_PITCH, + DEFAULT_BELL_DURATION, + 0}; + +static IntegerCtrl defaultIntegerControl = { + DEFAULT_INT_RESOLUTION, + DEFAULT_INT_MIN_VALUE, + DEFAULT_INT_MAX_VALUE, + DEFAULT_INT_DISPLAYED, + 0}; + +Bool +InitStringFeedbackClassDeviceStruct ( + DeviceIntPtr dev, StringCtrlProcPtr controlProc, + int max_symbols, int num_symbols_supported, KeySym *symbols) +{ + int i; + StringFeedbackPtr feedc; + + feedc = malloc(sizeof(StringFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl.num_symbols_supported = num_symbols_supported; + feedc->ctrl.num_symbols_displayed = 0; + feedc->ctrl.max_symbols = max_symbols; + feedc->ctrl.symbols_supported = malloc(sizeof (KeySym) * num_symbols_supported); + feedc->ctrl.symbols_displayed = malloc(sizeof (KeySym) * max_symbols); + if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed) + { + if (feedc->ctrl.symbols_supported) + free(feedc->ctrl.symbols_supported); + if (feedc->ctrl.symbols_displayed) + free(feedc->ctrl.symbols_displayed); + free(feedc); + return FALSE; + } + for (i=0; ictrl.symbols_supported+i) = *symbols++; + for (i=0; ictrl.symbols_displayed+i) = (KeySym) 0; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->stringfeed) ) + feedc->ctrl.id = dev->stringfeed->ctrl.id + 1; + dev->stringfeed = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +Bool +InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc, + BellCtrlProcPtr controlProc) +{ + BellFeedbackPtr feedc; + + feedc = malloc(sizeof(BellFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->BellProc = bellProc; + feedc->ctrl = defaultBellControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->bell) ) + feedc->ctrl.id = dev->bell->ctrl.id + 1; + dev->bell = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +Bool +InitLedFeedbackClassDeviceStruct (DeviceIntPtr dev, LedCtrlProcPtr controlProc) +{ + LedFeedbackPtr feedc; + + feedc = malloc(sizeof(LedFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultLedControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->leds) ) + feedc->ctrl.id = dev->leds->ctrl.id + 1; + feedc->xkb_sli= NULL; + dev->leds = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +Bool +InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr controlProc) +{ + IntegerFeedbackPtr feedc; + + feedc = malloc(sizeof(IntegerFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultIntegerControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->intfeed) ) + feedc->ctrl.id = dev->intfeed->ctrl.id + 1; + dev->intfeed = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +Bool +InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, Atom* btn_labels, + PtrCtrlProcPtr controlProc, int numMotionEvents, + int numAxes, Atom *axes_labels) +{ + DeviceIntPtr dev = (DeviceIntPtr)device; + + return(InitButtonClassDeviceStruct(dev, numButtons, btn_labels, map) && + InitValuatorClassDeviceStruct(dev, numAxes, axes_labels, + numMotionEvents, 0) && + InitPtrFeedbackClassDeviceStruct(dev, controlProc)); +} + +/* + * Check if the given buffer contains elements between low (inclusive) and + * high (inclusive) only. + * + * @return TRUE if the device map is invalid, FALSE otherwise. + */ +Bool +BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval) +{ + int i; + + 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; + } + } + return FALSE; +} + +int +ProcSetModifierMapping(ClientPtr client) +{ + xSetModifierMappingReply rep; + int rc; + REQUEST(xSetModifierMappingReq); + REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq); + + if (client->req_len != ((stuff->numKeyPerModifier << 1) + + bytes_to_int32(sizeof(xSetModifierMappingReq)))) + return BadLength; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = change_modmap(client, PickKeyboard(client), (KeyCode *)&stuff[1], + stuff->numKeyPerModifier); + if (rc == MappingFailed || rc == -1) + return BadValue; + if (rc != Success && rc != MappingSuccess && rc != MappingFailed && + rc != MappingBusy) + return rc; + + rep.success = rc; + + WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep); + return Success; +} + +int +ProcGetModifierMapping(ClientPtr client) +{ + xGetModifierMappingReply rep; + int max_keys_per_mod = 0; + KeyCode *modkeymap = NULL; + REQUEST_SIZE_MATCH(xReq); + + generate_modkeymap(client, PickKeyboard(client), &modkeymap, + &max_keys_per_mod); + + memset(&rep, 0, sizeof(xGetModifierMappingReply)); + rep.type = X_Reply; + rep.numKeyPerModifier = max_keys_per_mod; + rep.sequenceNumber = client->sequence; + /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */ + rep.length = max_keys_per_mod << 1; + + WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep); + (void)WriteToClient(client, max_keys_per_mod * 8, (char *) modkeymap); + + free(modkeymap); + + return Success; +} + +int +ProcChangeKeyboardMapping(ClientPtr client) +{ + REQUEST(xChangeKeyboardMappingReq); + unsigned len; + KeySymsRec keysyms; + DeviceIntPtr pDev, tmp; + int rc; + REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq); + + len = client->req_len - bytes_to_int32(sizeof(xChangeKeyboardMappingReq)); + if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode)) + return BadLength; + + pDev = PickKeyboard(client); + + if ((stuff->firstKeyCode < pDev->key->xkbInfo->desc->min_key_code) || + (stuff->firstKeyCode > pDev->key->xkbInfo->desc->max_key_code)) { + client->errorValue = stuff->firstKeyCode; + return BadValue; + + } + if (((unsigned)(stuff->firstKeyCode + stuff->keyCodes - 1) > + pDev->key->xkbInfo->desc->max_key_code) || + (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]; + + rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); + if (rc != Success) + return rc; + + XkbApplyMappingChange(pDev, &keysyms, stuff->firstKeyCode, + stuff->keyCodes, NULL, client); + + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { + if (IsMaster(tmp) || tmp->u.master != pDev) + continue; + if (!tmp->key) + continue; + + rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); + if (rc != Success) + continue; + + XkbApplyMappingChange(tmp, &keysyms, stuff->firstKeyCode, + stuff->keyCodes, NULL, client); + } + + return Success; +} + +int +ProcSetPointerMapping(ClientPtr client) +{ + BYTE *map; + int ret; + int i, j; + DeviceIntPtr ptr = PickPointer(client); + xSetPointerMappingReply rep; + REQUEST(xSetPointerMappingReq); + REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq); + + if (client->req_len != + bytes_to_int32(sizeof(xSetPointerMappingReq) + stuff->nElts)) + return BadLength; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.success = MappingSuccess; + map = (BYTE *)&stuff[1]; + + /* So we're bounded here by the number of core buttons. This check + * probably wants disabling through XFixes. */ + /* MPX: With ClientPointer, we can return the right number of buttons. + * Let's just hope nobody changed ClientPointer between GetPointerMapping + * and SetPointerMapping + */ + if (stuff->nElts != ptr->button->numButtons) { + client->errorValue = stuff->nElts; + return BadValue; + } + + /* Core protocol specs don't allow for duplicate mappings; this check + * almost certainly wants disabling through XFixes too. */ + for (i = 0; i < stuff->nElts; i++) { + for (j = i + 1; j < stuff->nElts; j++) { + if (map[i] && map[i] == map[j]) { + client->errorValue = map[i]; + return BadValue; + } + } + } + + ret = ApplyPointerMapping(ptr, map, stuff->nElts, client); + if (ret == MappingBusy) + rep.success = ret; + else if (ret == -1) + return BadValue; + else if (ret != Success) + return ret; + + WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); + return Success; +} + +int +ProcGetKeyboardMapping(ClientPtr client) +{ + xGetKeyboardMappingReply rep; + DeviceIntPtr kbd = PickKeyboard(client); + XkbDescPtr xkb; + KeySymsPtr syms; + int rc; + REQUEST(xGetKeyboardMappingReq); + REQUEST_SIZE_MATCH(xGetKeyboardMappingReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); + if (rc != Success) + return rc; + + xkb = kbd->key->xkbInfo->desc; + + if ((stuff->firstKeyCode < xkb->min_key_code) || + (stuff->firstKeyCode > xkb->max_key_code)) { + client->errorValue = stuff->firstKeyCode; + return BadValue; + } + if (stuff->firstKeyCode + stuff->count > xkb->max_key_code + 1) { + client->errorValue = stuff->count; + return BadValue; + } + + syms = XkbGetCoreMap(kbd); + if (!syms) + return BadAlloc; + + memset(&rep, 0, sizeof(xGetKeyboardMappingReply)); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.keySymsPerKeyCode = syms->mapWidth; + /* length is a count of 4 byte quantities and KeySyms are 4 bytes */ + rep.length = syms->mapWidth * stuff->count; + WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep); + client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; + WriteSwappedDataToClient(client, + syms->mapWidth * stuff->count * sizeof(KeySym), + &syms->map[syms->mapWidth * (stuff->firstKeyCode - + syms->minKeyCode)]); + free(syms->map); + free(syms); + + return Success; +} + +int +ProcGetPointerMapping(ClientPtr client) +{ + xGetPointerMappingReply rep; + /* Apps may get different values each time they call GetPointerMapping as + * the ClientPointer could change. */ + DeviceIntPtr ptr = PickPointer(client); + ButtonClassPtr butc = ptr->button; + int rc; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.nElts = (butc) ? butc->numButtons : 0; + rep.length = ((unsigned)rep.nElts + (4-1))/4; + WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep); + if (butc) + 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)); +} + +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); +} + +static int +DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist, + BITS32 vmask) +{ +#define DO_ALL (-1) + KeybdCtrl ctrl; + int t; + int led = DO_ALL; + int key = DO_ALL; + BITS32 index2; + int mask = vmask, i; + XkbEventCauseRec cause; + + 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 (!(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; + } + + XkbSetCauseCoreReq(&cause,X_ChangeKeyboardControl,client); + XkbSetIndicators(keybd,((led == DO_ALL) ? ~0L : (1L<<(led-1))), + ctrl.leds, &cause); + ctrl.leds = keybd->kbdfeed->ctrl.leds; + + break; + case KBKey: + key = (KeyCode)*vlist; + vlist++; + if ((KeyCode)key < keybd->key->xkbInfo->desc->min_key_code || + (KeyCode)key > keybd->key->xkbInfo->desc->max_key_code) { + client->errorValue = key; + return BadValue; + } + if (!(mask & KBAutoRepeatMode)) + return BadMatch; + break; + case KBAutoRepeatMode: + i = (key >> 3); + mask = (1 << (key & 7)); + t = (CARD8)*vlist; + vlist++; + if (key != DO_ALL) + XkbDisableComputedAutoRepeats(keybd,key); + 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 = mask; + return BadValue; + } + } + keybd->kbdfeed->ctrl = ctrl; + + /* The XKB RepeatKeys control and core protocol global autorepeat */ + /* value are linked */ + XkbSetRepeatKeys(keybd, key, keybd->kbdfeed->ctrl.autoRepeat); + + return Success; + +#undef DO_ALL +} + +/** + * Changes kbd control on the ClientPointer and all attached SDs. + */ +int +ProcChangeKeyboardControl (ClientPtr client) +{ + XID *vlist; + BITS32 vmask; + int ret = Success, error = Success; + DeviceIntPtr pDev = NULL, keyboard; + REQUEST(xChangeKeyboardControlReq); + + REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq); + + vmask = stuff->mask; + vlist = (XID *)&stuff[1]; + + if (client->req_len != (sizeof(xChangeKeyboardControlReq)>>2)+Ones(vmask)) + return BadLength; + + keyboard = PickKeyboard(client); + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + if ((pDev == keyboard || (!IsMaster(keyboard) && pDev->u.master == keyboard)) && + pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { + ret = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); + if (ret != Success) + return ret; + } + } + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + if ((pDev == keyboard || (!IsMaster(keyboard) && pDev->u.master == keyboard)) && + pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { + ret = DoChangeKeyboardControl(client, pDev, vlist, vmask); + if (ret != Success) + error = ret; + } + } + + return error; +} + +int +ProcGetKeyboardControl (ClientPtr client) +{ + int rc, i; + DeviceIntPtr kbd = PickKeyboard(client); + KeybdCtrl *ctrl = &kbd->kbdfeed->ctrl; + xGetKeyboardControlReply rep; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); + if (rc != Success) + return rc; + + 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 dev, keybd = PickKeyboard(client); + int base = keybd->kbdfeed->ctrl.bell; + int newpercent; + int rc; + 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; + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if ((dev == keybd || (!IsMaster(dev) && dev->u.master == keybd)) && + dev->kbdfeed && dev->kbdfeed->BellProc) { + + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixBellAccess); + if (rc != Success) + return rc; + XkbHandleBell(FALSE, FALSE, dev, newpercent, + &dev->kbdfeed->ctrl, 0, None, NULL, client); + } + } + + return Success; +} + +int +ProcChangePointerControl(ClientPtr client) +{ + DeviceIntPtr dev, mouse = PickPointer(client); + PtrCtrl ctrl; /* might get BadValue part way through */ + int rc; + REQUEST(xChangePointerControlReq); + REQUEST_SIZE_MATCH(xChangePointerControlReq); + + if (!mouse->ptrfeed->CtrlProc) + return BadDevice; + + 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; + } + } + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if ((dev == mouse || (!IsMaster(dev) && dev->u.master == mouse)) && + dev->ptrfeed && dev->ptrfeed->CtrlProc) { + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); + if (rc != Success) + return rc; + } + } + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if ((dev == mouse || (!IsMaster(dev) && dev->u.master == mouse)) && + dev->ptrfeed && dev->ptrfeed->CtrlProc) { + dev->ptrfeed->ctrl = ctrl; + (*dev->ptrfeed->CtrlProc)(dev, &mouse->ptrfeed->ctrl); + } + } + + return Success; +} + +int +ProcGetPointerControl(ClientPtr client) +{ + DeviceIntPtr ptr = PickPointer(client); + PtrCtrl *ctrl = &ptr->ptrfeed->ctrl; + xGetPointerControlReply rep; + int rc; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); + if (rc != Success) + return rc; + + 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(DeviceIntPtr dev, ClientPtr client) +{ + GrabPtr grab = dev->deviceGrab.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, rc; + unsigned long nEvents; + DeviceIntPtr mouse = PickPointer(client); + TimeStamp start, stop; + REQUEST(xGetMotionEventsReq); + REQUEST_SIZE_MATCH(xGetMotionEventsReq); + + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); + if (rc != Success) + return rc; + + 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; + count = GetMotionHistory(mouse, &coords, start.milliseconds, + stop.milliseconds, pWin->drawable.pScreen, + TRUE); + 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 * bytes_to_int32(sizeof(xTimecoord)); + rep.nEvents = nEvents; + WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep); + if (nEvents) + { + client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite; + WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord), + (char *)coords); + } + if (coords) + free(coords); + return Success; +} + +int +ProcQueryKeymap(ClientPtr client) +{ + xQueryKeymapReply rep; + int rc, i; + DeviceIntPtr keybd = PickKeyboard(client); + CARD8 *down = keybd->key->down; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 2; + + rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess); + if (rc != Success && rc != BadAccess) + return rc; + + for (i = 0; i<32; i++) + rep.map[i] = down[i]; + + if (rc == BadAccess) + memset(rep.map, 0, 32); + + WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep); + + return Success; +} + + +/** + * Recalculate the number of buttons for the master device. The number of + * buttons on the master device is equal to the number of buttons on the + * slave device with the highest number of buttons. + */ +static void +RecalculateMasterButtons(DeviceIntPtr slave) +{ + DeviceIntPtr dev, master; + int maxbuttons = 0; + + if (!slave->button || IsMaster(slave)) + return; + + master = GetMaster(slave, MASTER_POINTER); + if (!master) + return; + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (IsMaster(dev) || + dev->u.master != master || + !dev->button) + continue; + + maxbuttons = max(maxbuttons, dev->button->numButtons); + } + + if (master->button->numButtons != maxbuttons) + { + int i; + DeviceChangedEvent event; + + memset(&event, 0, sizeof(event)); + + master->button->numButtons = maxbuttons; + + event.header = ET_Internal; + event.type = ET_DeviceChanged; + event.time = CurrentTime; + event.deviceid = master->id; + event.flags = DEVCHANGE_POINTER_EVENT | DEVCHANGE_DEVICE_CHANGE; + event.buttons.num_buttons = maxbuttons; + memcpy(&event.buttons.names, master->button->labels, maxbuttons * + sizeof(Atom)); + + if (master->valuator) + { + event.num_valuators = master->valuator->numAxes; + for (i = 0; i < event.num_valuators; i++) + { + event.valuators[i].min = master->valuator->axes[i].min_value; + event.valuators[i].max = master->valuator->axes[i].max_value; + event.valuators[i].resolution = master->valuator->axes[i].resolution; + /* This should, eventually, be a per-axis mode */ + event.valuators[i].mode = master->valuator->mode; + event.valuators[i].name = master->valuator->axes[i].label; + } + } + + if (master->key) + { + event.keys.min_keycode = master->key->xkbInfo->desc->min_key_code; + event.keys.max_keycode = master->key->xkbInfo->desc->max_key_code; + } + + XISendDeviceChangedEvent(master, master, &event); + } +} + +/** + * Attach device 'dev' to device 'master'. + * Client is set to the client that issued the request, or NULL if it comes + * from some internal automatic pairing. + * + * Master may be NULL to set the device floating. + * + * We don't allow multi-layer hierarchies right now. You can't attach a slave + * to another slave. + */ +int +AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master) +{ + ScreenPtr screen; + DeviceIntPtr oldmaster; + if (!dev || IsMaster(dev)) + return BadDevice; + + if (master && !IsMaster(master)) /* can't attach to slaves */ + return BadDevice; + + /* set from floating to floating? */ + if (!dev->u.master && !master && dev->enabled) + return Success; + + /* free the existing sprite. */ + if (!dev->u.master && dev->spriteInfo->paired == dev) + { + screen = miPointerGetScreen(dev); + screen->DeviceCursorCleanup(dev, screen); + free(dev->spriteInfo->sprite); + } + + oldmaster = dev->u.master; + dev->u.master = master; + + /* If device is set to floating, we need to create a sprite for it, + * otherwise things go bad. However, we don't want to render the cursor, + * so we reset spriteOwner. + * Sprite has to be forced to NULL first, otherwise InitializeSprite won't + * alloc new memory but overwrite the previous one. + */ + if (!master) + { + WindowPtr currentRoot; + + if (dev->spriteInfo->sprite) + currentRoot = dev->spriteInfo->sprite->spriteTrace[0]; + else /* new device auto-set to floating */ + currentRoot = WindowTable[0]; + + /* we need to init a fake sprite */ + screen = currentRoot->drawable.pScreen; + screen->DeviceCursorInitialize(dev, screen); + dev->spriteInfo->sprite = NULL; + InitializeSprite(dev, currentRoot); + dev->spriteInfo->spriteOwner = FALSE; + dev->spriteInfo->paired = dev; + } else + { + dev->spriteInfo->sprite = master->spriteInfo->sprite; + dev->spriteInfo->paired = master; + dev->spriteInfo->spriteOwner = FALSE; + + RecalculateMasterButtons(master); + } + + /* XXX: in theory, the MD should change back to its old, original + * classes when the last SD is detached. Thanks to the XTEST devices, + * we'll always have an SD attached until the MD is removed. + * So let's not worry about that. + */ + + return Success; +} + +/** + * Return the device paired with the given device or NULL. + * Returns the device paired with the parent master if the given device is a + * slave device. + */ +DeviceIntPtr +GetPairedDevice(DeviceIntPtr dev) +{ + if (!IsMaster(dev) && dev->u.master) + dev = dev->u.master; + + return dev->spriteInfo->paired; +} + + +/** + * Returns the right master for the type of event needed. If the event is a + * keyboard event. + * This function may be called with a master device as argument. If so, the + * returned master is either the device itself or the paired master device. + * If dev is a floating slave device, NULL is returned. + * + * @type ::MASTER_KEYBOARD or ::MASTER_POINTER + */ +DeviceIntPtr +GetMaster(DeviceIntPtr dev, int which) +{ + DeviceIntPtr master; + + if (IsMaster(dev)) + master = dev; + else + master = dev->u.master; + + if (master) + { + if (which == MASTER_KEYBOARD) + { + if (master->type != MASTER_KEYBOARD) + master = GetPairedDevice(master); + } else + { + if (master->type != MASTER_POINTER) + master = GetPairedDevice(master); + } + } + + return master; +} + +/** + * Create a new device pair (== one pointer, one keyboard device). + * Only allocates the devices, you will need to call ActivateDevice() and + * EnableDevice() manually. + * Either a master or a slave device can be created depending on + * the value for master. + */ +int +AllocDevicePair (ClientPtr client, char* name, + DeviceIntPtr* ptr, + DeviceIntPtr* keybd, + DeviceProc ptr_proc, + DeviceProc keybd_proc, + Bool master) +{ + DeviceIntPtr pointer; + DeviceIntPtr keyboard; + *ptr = *keybd = NULL; + + pointer = AddInputDevice(client, ptr_proc, TRUE); + if (!pointer) + return BadAlloc; + + pointer->name = calloc(strlen(name) + strlen(" pointer") + 1, sizeof(char)); + strcpy(pointer->name, name); + strcat(pointer->name, " pointer"); + + pointer->public.processInputProc = ProcessOtherEvent; + pointer->public.realInputProc = ProcessOtherEvent; + XkbSetExtension(pointer, ProcessPointerEvent); + pointer->deviceGrab.ActivateGrab = ActivatePointerGrab; + pointer->deviceGrab.DeactivateGrab = DeactivatePointerGrab; + pointer->coreEvents = TRUE; + pointer->spriteInfo->spriteOwner = TRUE; + + pointer->u.lastSlave = NULL; + pointer->last.slave = NULL; + pointer->type = (master) ? MASTER_POINTER : SLAVE; + + keyboard = AddInputDevice(client, keybd_proc, TRUE); + if (!keyboard) + { + RemoveDevice(pointer, FALSE); + return BadAlloc; + } + + keyboard->name = calloc(strlen(name) + strlen(" keyboard") + 1, sizeof(char)); + strcpy(keyboard->name, name); + strcat(keyboard->name, " keyboard"); + + keyboard->public.processInputProc = ProcessOtherEvent; + keyboard->public.realInputProc = ProcessOtherEvent; + XkbSetExtension(keyboard, ProcessKeyboardEvent); + keyboard->deviceGrab.ActivateGrab = ActivateKeyboardGrab; + keyboard->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; + keyboard->coreEvents = TRUE; + keyboard->spriteInfo->spriteOwner = FALSE; + + keyboard->u.lastSlave = NULL; + keyboard->last.slave = NULL; + keyboard->type = (master) ? MASTER_KEYBOARD : SLAVE; + + /* The ClassesRec stores the device classes currently not used. */ + pointer->unused_classes = calloc(1, sizeof(ClassesRec)); + keyboard->unused_classes = calloc(1, sizeof(ClassesRec)); + + *ptr = pointer; + *keybd = keyboard; + + return Success; +} + diff --git a/xorg-server/dix/dispatch.c b/xorg-server/dix/dispatch.c index ec95b7ae3..fa11155cc 100644 --- a/xorg-server/dix/dispatch.c +++ b/xorg-server/dix/dispatch.c @@ -176,13 +176,6 @@ CallbackListPtr ClientStateCallback; volatile char dispatchException = 0; 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)) @@ -359,7 +352,7 @@ Dispatch(void) nextFreeClientID = 1; nClients = 0; - clientReady = xalloc(sizeof(int) * MaxClients); + clientReady = malloc(sizeof(int) * MaxClients); if (!clientReady) return; @@ -444,16 +437,18 @@ Dispatch(void) client->sequence, client->index, result); #endif - if (result != Success) + if (client->noClientException != Success) { - if (client->noClientException != Success) - CloseDownClient(client); - else - SendErrorToClient(client, MAJOROP, - MinorOpcodeOfRequest(client), - client->errorValue, result); + CloseDownClient(client); break; - } + } + else if (result != Success) + { + SendErrorToClient(client, MAJOROP, + MinorOpcodeOfRequest(client), + client->errorValue, result); + break; + } } FlushAllOutput(); client = clients[clientReady[nready]]; @@ -466,7 +461,7 @@ Dispatch(void) ddxBeforeReset (); #endif KillAllClients(); - xfree(clientReady); + free(clientReady); dispatchException &= ~DE_RESET; SmartScheduleLatencyLimited = 0; } @@ -530,7 +525,7 @@ CreateConnectionBlock(void) pad_to_int32(setup.nbytesVendor) + (setup.numFormats * sizeof(xPixmapFormat)) + (setup.numRoots * sizeof(xWindowRoot)); - ConnectionInfo = xalloc(lenofblock); + ConnectionInfo = malloc(lenofblock); if (!ConnectionInfo) return FALSE; @@ -592,10 +587,10 @@ CreateConnectionBlock(void) { lenofblock += sizeof(xDepth) + (pDepth->numVids * sizeof(xVisualType)); - pBuf = (char *)xrealloc(ConnectionInfo, lenofblock); + pBuf = (char *)realloc(ConnectionInfo, lenofblock); if (!pBuf) { - xfree(ConnectionInfo); + free(ConnectionInfo); return FALSE; } ConnectionInfo = pBuf; @@ -675,10 +670,7 @@ ProcCreateWindow(ClientPtr client) return BadAlloc; pWin->eventMask = mask; } - if (client->noClientException != Success) - return(client->noClientException); - else - return rc; + return rc; } int @@ -686,7 +678,7 @@ ProcChangeWindowAttributes(ClientPtr client) { WindowPtr pWin; REQUEST(xChangeWindowAttributesReq); - int result, len, rc; + int len, rc; Mask access_mode = 0; REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq); @@ -698,14 +690,10 @@ ProcChangeWindowAttributes(ClientPtr client) len = client->req_len - bytes_to_int32(sizeof(xChangeWindowAttributesReq)); if (len != Ones(stuff->valueMask)) return BadLength; - result = ChangeWindowAttributes(pWin, + return ChangeWindowAttributes(pWin, stuff->valueMask, (XID *) &stuff[1], client); - if (client->noClientException != Success) - return(client->noClientException); - else - return(result); } int @@ -723,7 +711,7 @@ ProcGetWindowAttributes(ClientPtr client) memset(&wa, 0, sizeof(xGetWindowAttributesReply)); GetWindowAttributes(pWin, client, &wa); WriteReplyToClient(client, sizeof(xGetWindowAttributesReply), &wa); - return(client->noClientException); + return Success; } int @@ -744,7 +732,7 @@ ProcDestroyWindow(ClientPtr client) return rc; FreeResource(stuff->id, RT_NONE); } - return(client->noClientException); + return Success; } int @@ -759,7 +747,7 @@ ProcDestroySubwindows(ClientPtr client) if (rc != Success) return rc; DestroySubwindows(pWin, client); - return(client->noClientException); + return Success; } int @@ -767,7 +755,7 @@ ProcChangeSaveSet(ClientPtr client) { WindowPtr pWin; REQUEST(xChangeSaveSetReq); - int result, rc; + int rc; REQUEST_SIZE_MATCH(xChangeSaveSetReq); rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); @@ -776,18 +764,9 @@ ProcChangeSaveSet(ClientPtr client) 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 ); - } + return AlterSaveSetForClient(client, pWin, stuff->mode, FALSE, TRUE); + client->errorValue = stuff->mode; + return BadValue; } int @@ -795,7 +774,7 @@ ProcReparentWindow(ClientPtr client) { WindowPtr pWin, pParent; REQUEST(xReparentWindowReq); - int result, rc; + int rc; REQUEST_SIZE_MATCH(xReparentWindowReq); rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); @@ -804,23 +783,16 @@ ProcReparentWindow(ClientPtr client) rc = dixLookupWindow(&pParent, stuff->parent, client, DixAddAccess); if (rc != Success) return rc; - 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); + if (!SAME_SCREENS(pWin->drawable, pParent->drawable)) + return BadMatch; + if ((pWin->backgroundState == ParentRelative) && + (pParent->drawable.depth != pWin->drawable.depth)) + return BadMatch; + if ((pWin->drawable.class != InputOnly) && + (pParent->drawable.class == InputOnly)) + return BadMatch; + return ReparentWindow(pWin, pParent, + (short)stuff->x, (short)stuff->y, client); } int @@ -836,7 +808,7 @@ ProcMapWindow(ClientPtr client) return rc; MapWindow(pWin, client); /* update cache to say it is mapped */ - return(client->noClientException); + return Success; } int @@ -852,7 +824,7 @@ ProcMapSubwindows(ClientPtr client) return rc; MapSubwindows(pWin, client); /* update cache to say it is mapped */ - return(client->noClientException); + return Success; } int @@ -868,7 +840,7 @@ ProcUnmapWindow(ClientPtr client) return rc; UnmapWindow(pWin, FALSE); /* update cache to say it is mapped */ - return(client->noClientException); + return Success; } int @@ -883,7 +855,7 @@ ProcUnmapSubwindows(ClientPtr client) if (rc != Success) return rc; UnmapSubwindows(pWin); - return(client->noClientException); + return Success; } int @@ -891,7 +863,6 @@ ProcConfigureWindow(ClientPtr client) { WindowPtr pWin; REQUEST(xConfigureWindowReq); - int result; int len, rc; REQUEST_AT_LEAST_SIZE(xConfigureWindowReq); @@ -902,12 +873,7 @@ ProcConfigureWindow(ClientPtr client) len = client->req_len - bytes_to_int32(sizeof(xConfigureWindowReq)); 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); + return ConfigureWindow(pWin, (Mask)stuff->mask, (XID *) &stuff[1], client); } int @@ -928,7 +894,7 @@ ProcCirculateWindow(ClientPtr client) if (rc != Success) return rc; CirculateWindow(pWin, (int)stuff->direction, client); - return(client->noClientException); + return Success; } static int @@ -987,7 +953,7 @@ ProcGetGeometry(ClientPtr client) return status; WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep); - return(client->noClientException); + return Success; } @@ -1019,7 +985,7 @@ ProcQueryTree(ClientPtr client) { int curChild = 0; - childIDs = xalloc(numChildren * sizeof(Window)); + childIDs = malloc(numChildren * sizeof(Window)); if (!childIDs) return BadAlloc; for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) @@ -1034,10 +1000,10 @@ ProcQueryTree(ClientPtr client) { client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; WriteSwappedDataToClient(client, numChildren * sizeof(Window), childIDs); - xfree(childIDs); + free(childIDs); } - return(client->noClientException); + return Success; } int @@ -1064,7 +1030,7 @@ ProcInternAtom(ClientPtr client) reply.sequenceNumber = client->sequence; reply.atom = atom; WriteReplyToClient(client, sizeof(xInternAtomReply), &reply); - return(client->noClientException); + return Success; } else return (BadAlloc); @@ -1089,7 +1055,7 @@ ProcGetAtomName(ClientPtr client) reply.nameLength = len; WriteReplyToClient(client, sizeof(xGetAtomNameReply), &reply); (void)WriteToClient(client, len, str); - return(client->noClientException); + return Success; } else { @@ -1109,7 +1075,7 @@ ProcGrabServer(ClientPtr client) client->sequence--; BITSET(grabWaiters, client->index); IgnoreClient(client); - return(client->noClientException); + return Success; } rc = OnlyListenToOneClient(client); if (rc != Success) @@ -1125,7 +1091,7 @@ ProcGrabServer(ClientPtr client) CallCallbacks(&ServerGrabCallback, (pointer)&grabinfo); } - return(client->noClientException); + return Success; } static void @@ -1160,7 +1126,7 @@ ProcUngrabServer(ClientPtr client) { REQUEST_SIZE_MATCH(xReq); UngrabServer(client); - return(client->noClientException); + return Success; } int @@ -1234,7 +1200,7 @@ ProcTranslateCoords(ClientPtr client) rep.dstY = y - pDst->drawable.y; } WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep); - return(client->noClientException); + return Success; } int @@ -1250,7 +1216,7 @@ ProcOpenFont(ClientPtr client) stuff->nbytes, (char *)&stuff[1]); if (err == Success) { - return(client->noClientException); + return Success; } else return err; @@ -1269,7 +1235,7 @@ ProcCloseFont(ClientPtr client) if (rc == Success) { FreeResource(stuff->id, RT_NONE); - return(client->noClientException); + return Success; } else { @@ -1308,7 +1274,7 @@ ProcQueryFont(ClientPtr client) rlength = sizeof(xQueryFontReply) + FONTINFONPROPS(FONTCHARSET(pFont)) * sizeof(xFontProp) + nprotoxcistructs * sizeof(xCharInfo); - reply = xcalloc(1, rlength); + reply = calloc(1, rlength); if(!reply) { return(BadAlloc); @@ -1320,8 +1286,8 @@ ProcQueryFont(ClientPtr client) QueryFont( pFont, reply, nprotoxcistructs); WriteReplyToClient(client, rlength, reply); - xfree(reply); - return(client->noClientException); + free(reply); + return Success; } } @@ -1362,7 +1328,7 @@ ProcQueryTextExtents(ClientPtr client) reply.overallLeft = info.overallLeft; reply.overallRight = info.overallRight; WriteReplyToClient(client, sizeof(xQueryTextExtentsReply), &reply); - return(client->noClientException); + return Success; } int @@ -1463,7 +1429,7 @@ CreatePmap: return rc; } if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap)) - return(client->noClientException); + return Success; (*pDraw->pScreen->DestroyPixmap)(pMap); } return (BadAlloc); @@ -1482,7 +1448,7 @@ ProcFreePixmap(ClientPtr client) if (rc == Success) { FreeResource(stuff->id, RT_NONE); - return(client->noClientException); + return Success; } else { @@ -1517,7 +1483,7 @@ ProcCreateGC(ClientPtr client) return error; if (!AddResource(stuff->gc, RT_GC, (pointer)pGC)) return (BadAlloc); - return(client->noClientException); + return Success; } int @@ -1537,14 +1503,7 @@ ProcChangeGC(ClientPtr client) 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); - } + return ChangeGCXIDs(client, pGC, stuff->mask, (CARD32 *) &stuff[1]); } int @@ -1564,14 +1523,12 @@ ProcCopyGC(ClientPtr client) return result; 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 + if (stuff->mask & ~GCAllBits) { - client->errorValue = clientErrorValue; - return(result); + client->errorValue = stuff->mask; + return BadValue; } + return CopyGC(pGC, dstGC, stuff->mask); } int @@ -1592,15 +1549,11 @@ ProcSetDashes(ClientPtr client) if (result != Success) return result; - result = SetDashes(pGC, stuff->dashOffset, stuff->nDashes, + /* If there's an error, either there's no sensible errorValue, + * or there was a dash segment of 0. */ + client->errorValue = 0; + return SetDashes(pGC, stuff->dashOffset, stuff->nDashes, (unsigned char *)&stuff[1]); - if (client->noClientException != Success) - return(client->noClientException); - else - { - client->errorValue = clientErrorValue; - return(result); - } } int @@ -1625,12 +1578,8 @@ ProcSetClipRectangles(ClientPtr client) if (nr & 4) return(BadLength); nr >>= 3; - result = SetClipRects(pGC, stuff->xOrigin, stuff->yOrigin, + return SetClipRects(pGC, stuff->xOrigin, stuff->yOrigin, nr, (xRectangle *)&stuff[1], (int)stuff->ordering); - if (client->noClientException != Success) - return(client->noClientException); - else - return(result); } int @@ -1646,7 +1595,7 @@ ProcFreeGC(ClientPtr client) return rc; FreeResource(stuff->id, RT_NONE); - return(client->noClientException); + return Success; } int @@ -1673,7 +1622,7 @@ ProcClearToBackground(ClientPtr client) (*pWin->drawable.pScreen->ClearToBackground)(pWin, stuff->x, stuff->y, stuff->width, stuff->height, (Bool)stuff->exposures); - return(client->noClientException); + return Success; } int @@ -1715,7 +1664,7 @@ ProcCopyArea(ClientPtr client) REGION_DESTROY(pDst->pScreen, pRgn); } - return(client->noClientException); + return Success; } int @@ -1764,7 +1713,7 @@ ProcCopyPlane(ClientPtr client) if (pRgn) REGION_DESTROY(pdstDraw->pScreen, pRgn); } - return(client->noClientException); + return Success; } int @@ -1787,7 +1736,7 @@ ProcPolyPoint(ClientPtr client) if (npoint) (*pGC->ops->PolyPoint)(pDraw, pGC, stuff->coordMode, npoint, (xPoint *) &stuff[1]); - return (client->noClientException); + return Success; } int @@ -1810,7 +1759,7 @@ ProcPolyLine(ClientPtr client) if (npoint > 1) (*pGC->ops->Polylines)(pDraw, pGC, stuff->coordMode, npoint, (DDXPointPtr) &stuff[1]); - return(client->noClientException); + return Success; } int @@ -1829,7 +1778,7 @@ ProcPolySegment(ClientPtr client) nsegs >>= 3; if (nsegs) (*pGC->ops->PolySegment)(pDraw, pGC, nsegs, (xSegment *) &stuff[1]); - return (client->noClientException); + return Success; } int @@ -1849,7 +1798,7 @@ ProcPolyRectangle (ClientPtr client) if (nrects) (*pGC->ops->PolyRectangle)(pDraw, pGC, nrects, (xRectangle *) &stuff[1]); - return(client->noClientException); + return Success; } int @@ -1868,7 +1817,7 @@ ProcPolyArc(ClientPtr client) narcs /= sizeof(xArc); if (narcs) (*pGC->ops->PolyArc)(pDraw, pGC, narcs, (xArc *) &stuff[1]); - return (client->noClientException); + return Success; } int @@ -1899,7 +1848,7 @@ ProcFillPoly(ClientPtr client) (*pGC->ops->FillPolygon) (pDraw, pGC, stuff->shape, stuff->coordMode, things, (DDXPointPtr) &stuff[1]); - return(client->noClientException); + return Success; } int @@ -1920,7 +1869,7 @@ ProcPolyFillRectangle(ClientPtr client) if (things) (*pGC->ops->PolyFillRect) (pDraw, pGC, things, (xRectangle *) &stuff[1]); - return (client->noClientException); + return Success; } int @@ -1939,7 +1888,7 @@ ProcPolyFillArc(ClientPtr client) narcs /= sizeof(xArc); if (narcs) (*pGC->ops->PolyFillArc) (pDraw, pGC, narcs, (xArc *) &stuff[1]); - return (client->noClientException); + return Success; } #ifdef MATCH_CLIENT_ENDIAN @@ -2050,7 +1999,7 @@ ProcPutImage(ClientPtr client) stuff->width, stuff->height, stuff->leftPad, stuff->format, tmpImage); - return (client->noClientException); + return Success; } static int @@ -2154,7 +2103,7 @@ DoGetImage(ClientPtr client, int format, Drawable drawable, xgi.length = length; if (im_return) { - pBuf = xcalloc(1, sz_xGetImageReply + length); + pBuf = calloc(1, sz_xGetImageReply + length); if (!pBuf) return (BadAlloc); if (widthBytesLine == 0) @@ -2192,7 +2141,7 @@ DoGetImage(ClientPtr client, int format, Drawable drawable, length += widthBytesLine; } } - if(!(pBuf = xcalloc(1, length))) + if(!(pBuf = calloc(1, length))) return (BadAlloc); WriteReplyToClient(client, sizeof (xGetImageReply), &xgi); } @@ -2293,8 +2242,8 @@ DoGetImage(ClientPtr client, int format, Drawable drawable, if (pVisibleRegion) REGION_DESTROY(pDraw->pScreen, pVisibleRegion); if (!im_return) - xfree(pBuf); - return (client->noClientException); + free(pBuf); + return Success; } int @@ -2333,7 +2282,7 @@ ProcPolyText(ClientPtr client) if (err == Success) { - return(client->noClientException); + return Success; } else return err; @@ -2363,7 +2312,7 @@ ProcImageText8(ClientPtr client) if (err == Success) { - return(client->noClientException); + return Success; } else return err; @@ -2393,7 +2342,7 @@ ProcImageText16(ClientPtr client) if (err == Success) { - return(client->noClientException); + return Success; } else return err; @@ -2431,12 +2380,8 @@ ProcCreateColormap(ClientPtr client) { if (pVisual->vid != stuff->visual) continue; - result = CreateColormap(mid, pScreen, pVisual, &pmap, + return 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); @@ -2457,7 +2402,7 @@ ProcFreeColormap(ClientPtr client) /* Freeing a default colormap is a no-op */ if (!(pmap->flags & IsDefault)) FreeResource(stuff->id, RT_NONE); - return (client->noClientException); + return Success; } else { @@ -2481,18 +2426,9 @@ ProcCopyColormapAndFree(ClientPtr client) rc = dixLookupResourceByType((pointer *)&pSrcMap, stuff->srcCmap, RT_COLORMAP, client, DixReadAccess|DixRemoveAccess); if (rc == Success) - { - rc = CopyColormapAndFree(mid, pSrcMap, client->index); - if (client->noClientException != Success) - return(client->noClientException); - else - return rc; - } - else - { - client->errorValue = stuff->srcCmap; - return (rc == BadValue) ? BadColor : rc; - } + return CopyColormapAndFree(mid, pSrcMap, client->index); + client->errorValue = stuff->srcCmap; + return (rc == BadValue) ? BadColor : rc; } int @@ -2513,8 +2449,8 @@ ProcInstallColormap(ClientPtr client) goto out; (*(pcmp->pScreen->InstallColormap)) (pcmp); + return Success; - rc = client->noClientException; out: client->errorValue = stuff->id; return (rc == BadValue) ? BadColor : rc; @@ -2539,8 +2475,8 @@ ProcUninstallColormap(ClientPtr client) if(pcmp->mid != pcmp->pScreen->defColormap) (*(pcmp->pScreen->UninstallColormap)) (pcmp); + return Success; - rc = client->noClientException; out: client->errorValue = stuff->id; return (rc == BadValue) ? BadColor : rc; @@ -2557,14 +2493,14 @@ ProcListInstalledColormaps(ClientPtr client) rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); if (rc != Success) - goto out; + return rc; rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, DixGetAttrAccess); if (rc != Success) - goto out; + return rc; - preply = xalloc(sizeof(xListInstalledColormapsReply) + + preply = malloc(sizeof(xListInstalledColormapsReply) + pWin->drawable.pScreen->maxInstalledCmaps * sizeof(Colormap)); if(!preply) @@ -2579,10 +2515,8 @@ ProcListInstalledColormaps(ClientPtr client) WriteReplyToClient(client, sizeof (xListInstalledColormapsReply), preply); client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; WriteSwappedDataToClient(client, nummaps * sizeof(Colormap), &preply[1]); - xfree(preply); - rc = client->noClientException; -out: - return rc; + free(preply); + return Success; } int @@ -2607,17 +2541,12 @@ ProcAllocColor (ClientPtr client) acr.pixel = 0; if( (rc = AllocColor(pmap, &acr.red, &acr.green, &acr.blue, &acr.pixel, client->index)) ) - { - if (client->noClientException != Success) - return(client->noClientException); - else - return rc; - } + return rc; #ifdef PANORAMIX if (noPanoramiXExtension || !pmap->pScreen->myNum) #endif WriteReplyToClient(client, sizeof(xAllocColorReply), &acr); - return (client->noClientException); + return Success; } else @@ -2655,17 +2584,12 @@ ProcAllocNamedColor (ClientPtr client) if( (rc = AllocColor(pcmp, &ancr.screenRed, &ancr.screenGreen, &ancr.screenBlue, &ancr.pixel, client->index)) ) - { - if (client->noClientException != Success) - return(client->noClientException); - else - return rc; - } + return rc; #ifdef PANORAMIX if (noPanoramiXExtension || !pcmp->pScreen->myNum) #endif WriteReplyToClient(client, sizeof (xAllocNamedColorReply), &ancr); - return (client->noClientException); + return Success; } else return(BadName); @@ -2708,7 +2632,7 @@ ProcAllocColorCells (ClientPtr client) } nmasks = stuff->planes; length = ((long)npixels + (long)nmasks) * sizeof(Pixel); - ppixels = xalloc(length); + ppixels = malloc(length); if(!ppixels) return(BadAlloc); pmasks = ppixels + npixels; @@ -2716,11 +2640,8 @@ ProcAllocColorCells (ClientPtr client) if( (rc = AllocColorCells(client->index, pcmp, npixels, nmasks, (Bool)stuff->contiguous, ppixels, pmasks)) ) { - xfree(ppixels); - if (client->noClientException != Success) - return(client->noClientException); - else - return rc; + free(ppixels); + return rc; } #ifdef PANORAMIX if (noPanoramiXExtension || !pcmp->pScreen->myNum) @@ -2735,8 +2656,8 @@ ProcAllocColorCells (ClientPtr client) client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; WriteSwappedDataToClient(client, length, ppixels); } - xfree(ppixels); - return (client->noClientException); + free(ppixels); + return Success; } else { @@ -2777,7 +2698,7 @@ ProcAllocColorPlanes(ClientPtr client) acpr.sequenceNumber = client->sequence; acpr.nPixels = npixels; length = (long)npixels * sizeof(Pixel); - ppixels = xalloc(length); + ppixels = malloc(length); if(!ppixels) return(BadAlloc); if( (rc = AllocColorPlanes(client->index, pcmp, npixels, @@ -2785,11 +2706,8 @@ ProcAllocColorPlanes(ClientPtr client) (Bool)stuff->contiguous, ppixels, &acpr.redMask, &acpr.greenMask, &acpr.blueMask)) ) { - xfree(ppixels); - if (client->noClientException != Success) - return(client->noClientException); - else - return rc; + free(ppixels); + return rc; } acpr.length = bytes_to_int32(length); #ifdef PANORAMIX @@ -2800,8 +2718,8 @@ ProcAllocColorPlanes(ClientPtr client) client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; WriteSwappedDataToClient(client, length, ppixels); } - xfree(ppixels); - return (client->noClientException); + free(ppixels); + return Success; } else { @@ -2827,16 +2745,8 @@ ProcFreeColors(ClientPtr client) if(pcmp->flags & AllAllocated) return(BadAccess); count = bytes_to_int32((client->req_len << 2) - sizeof(xFreeColorsReq)); - rc = FreeColors(pcmp, client->index, count, + return FreeColors(pcmp, client->index, count, (Pixel *)&stuff[1], (Pixel)stuff->planeMask); - if (client->noClientException != Success) - return(client->noClientException); - else - { - client->errorValue = clientErrorValue; - return rc; - } - } else { @@ -2863,14 +2773,7 @@ ProcStoreColors (ClientPtr client) if (count % sizeof(xColorItem)) return(BadLength); count /= sizeof(xColorItem); - rc = StoreColors(pcmp, count, (xColorItem *)&stuff[1]); - if (client->noClientException != Success) - return(client->noClientException); - else - { - client->errorValue = clientErrorValue; - return rc; - } + return StoreColors(pcmp, count, (xColorItem *)&stuff[1], client); } else { @@ -2898,11 +2801,7 @@ ProcStoreNamedColor (ClientPtr client) { def.flags = stuff->flags; def.pixel = stuff->pixel; - rc = StoreColors(pcmp, 1, &def); - if (client->noClientException != Success) - return(client->noClientException); - else - return rc; + return StoreColors(pcmp, 1, &def, client); } return (BadName); } @@ -2930,19 +2829,13 @@ ProcQueryColors(ClientPtr client) xQueryColorsReply qcr; count = bytes_to_int32((client->req_len << 2) - sizeof(xQueryColorsReq)); - prgbs = xcalloc(1, count * sizeof(xrgb)); + prgbs = calloc(1, count * sizeof(xrgb)); if(!prgbs && count) return(BadAlloc); - if( (rc = QueryColors(pcmp, count, (Pixel *)&stuff[1], prgbs)) ) + if( (rc = QueryColors(pcmp, count, (Pixel *)&stuff[1], prgbs, client)) ) { - if (prgbs) xfree(prgbs); - if (client->noClientException != Success) - return(client->noClientException); - else - { - client->errorValue = clientErrorValue; - return rc; - } + if (prgbs) free(prgbs); + return rc; } memset(&qcr, 0, sizeof(xQueryColorsReply)); qcr.type = X_Reply; @@ -2955,8 +2848,8 @@ ProcQueryColors(ClientPtr client) client->pSwapReplyFunc = (ReplySwapPtr) SQColorsExtend; WriteSwappedDataToClient(client, count * sizeof(xrgb), prgbs); } - if (prgbs) xfree(prgbs); - return(client->noClientException); + if (prgbs) free(prgbs); + return Success; } else @@ -2994,7 +2887,7 @@ ProcLookupColor(ClientPtr client) &lcr.screenBlue, pcmp->pVisual); WriteReplyToClient(client, sizeof(xLookupColorReply), &lcr); - return(client->noClientException); + return Success; } return (BadName); } @@ -3054,13 +2947,13 @@ ProcCreateCursor (ClientPtr client) return (BadMatch); n = BitmapBytePad(width)*height; - srcbits = xcalloc(1, n); + srcbits = calloc(1, n); if (!srcbits) return (BadAlloc); - mskbits = xalloc(n); + mskbits = malloc(n); if (!mskbits) { - xfree(srcbits); + free(srcbits); return (BadAlloc); } @@ -3093,7 +2986,7 @@ ProcCreateCursor (ClientPtr client) if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) return BadAlloc; - return client->noClientException; + return Success; } int @@ -3115,7 +3008,7 @@ ProcCreateGlyphCursor (ClientPtr client) if (res != Success) return res; if (AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) - return client->noClientException; + return Success; return BadAlloc; } @@ -3133,7 +3026,7 @@ ProcFreeCursor (ClientPtr client) if (rc == Success) { FreeResource(stuff->id, RT_NONE); - return (client->noClientException); + return Success; } else { @@ -3179,7 +3072,7 @@ ProcQueryBestSize (ClientPtr client) reply.width = stuff->width; reply.height = stuff->height; WriteReplyToClient(client, sizeof(xQueryBestSizeReply), &reply); - return (client->noClientException); + return Success; } @@ -3243,7 +3136,7 @@ ProcSetScreenSaver (ClientPtr client) ScreenSaverInterval = defaultScreenSaverInterval; SetScreenSaverTimer(); - return (client->noClientException); + return Success; } int @@ -3268,31 +3161,24 @@ ProcGetScreenSaver(ClientPtr client) rep.preferBlanking = ScreenSaverBlanking; rep.allowExposures = ScreenSaverAllowExposures; WriteReplyToClient(client, sizeof(xGetScreenSaverReply), &rep); - return (client->noClientException); + return Success; } int ProcChangeHosts(ClientPtr client) { REQUEST(xChangeHostsReq); - int result; REQUEST_FIXED_SIZE(xChangeHostsReq, stuff->hostLength); if(stuff->mode == HostInsert) - result = AddHost(client, (int)stuff->hostFamily, + return AddHost(client, (int)stuff->hostFamily, stuff->hostLength, (pointer)&stuff[1]); - else if (stuff->mode == HostDelete) - result = RemoveHost(client, (int)stuff->hostFamily, + if (stuff->mode == HostDelete) + return RemoveHost(client, (int)stuff->hostFamily, stuff->hostLength, (pointer)&stuff[1]); - else - { - client->errorValue = stuff->mode; - return BadValue; - } - if (!result) - result = client->noClientException; - return (result); + client->errorValue = stuff->mode; + return BadValue; } int @@ -3323,14 +3209,13 @@ ProcListHosts(ClientPtr client) client->pSwapReplyFunc = (ReplySwapPtr) SLHostsExtend; WriteSwappedDataToClient(client, len, pdata); } - xfree(pdata); - return (client->noClientException); + free(pdata); + return Success; } int ProcChangeAccessControl(ClientPtr client) { - int result; REQUEST(xSetAccessControlReq); REQUEST_SIZE_MATCH(xSetAccessControlReq); @@ -3339,10 +3224,7 @@ ProcChangeAccessControl(ClientPtr client) client->errorValue = stuff->mode; return BadValue; } - result = ChangeAccessControl(client, stuff->mode == EnableAccess); - if (!result) - result = client->noClientException; - return (result); + return ChangeAccessControl(client, stuff->mode == EnableAccess); } /********************* @@ -3378,7 +3260,7 @@ ProcKillClient(ClientPtr client) if (stuff->id == AllTemporary) { CloseDownRetainedResources(); - return (client->noClientException); + return Success; } rc = dixLookupClient(&killclient, stuff->id, client, DixDestroyAccess); @@ -3393,7 +3275,7 @@ ProcKillClient(ClientPtr client) isItTimeToYield = TRUE; return (Success); } - return (client->noClientException); + return Success; } else return rc; @@ -3405,8 +3287,7 @@ ProcSetFontPath(ClientPtr client) unsigned char *ptr; unsigned long nbytes, total; long nfonts; - int n, result; - int error; + int n; REQUEST(xSetFontPathReq); REQUEST_AT_LEAST_SIZE(xSetFontPathReq); @@ -3424,14 +3305,7 @@ ProcSetFontPath(ClientPtr client) } 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); + return SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1]); } int @@ -3455,7 +3329,7 @@ ProcGetFontPath(ClientPtr client) WriteReplyToClient(client, sizeof(xGetFontPathReply), &reply); if (stringLens || numpaths) (void)WriteToClient(client, stringLens + numpaths, (char *)bufferStart); - return(client->noClientException); + return Success; } int @@ -3474,7 +3348,7 @@ ProcChangeCloseDownMode(ClientPtr client) (stuff->mode == RetainTemporary)) { client->closeDownMode = stuff->mode; - return (client->noClientException); + return Success; } else { @@ -3499,7 +3373,7 @@ int ProcForceScreenSaver(ClientPtr client) rc = dixSaveScreens(client, SCREEN_SAVER_FORCER, (int)stuff->mode); if (rc != Success) return rc; - return client->noClientException; + return Success; } int ProcNoOperation(ClientPtr client) @@ -3507,7 +3381,7 @@ int ProcNoOperation(ClientPtr client) REQUEST_AT_LEAST_SIZE(xReq); /* noop -- don't do anything */ - return(client->noClientException); + return Success; } void @@ -3619,7 +3493,7 @@ CloseDownClient(ClientPtr client) clients[client->index] = NullClient; SmartLastClient = NullClient; dixFreePrivates(client->devPrivates); - xfree(client); + free(client); while (!clients[currentMaxClients-1]) currentMaxClients--; @@ -3668,13 +3542,13 @@ ClientPtr NextAvailableClient(pointer ospriv) i = nextFreeClientID; if (i == MAXCLIENTS) return (ClientPtr)NULL; - clients[i] = client = xalloc(sizeof(ClientRec)); + clients[i] = client = malloc(sizeof(ClientRec)); if (!client) return (ClientPtr)NULL; InitClient(client, i, ospriv); if (!InitClientResources(client)) { - xfree(client); + free(client); return (ClientPtr)NULL; } data.reqType = 1; @@ -3682,7 +3556,7 @@ ClientPtr NextAvailableClient(pointer ospriv) if (!InsertFakeRequest(client, (char *)&data, sz_xReq)) { FreeClientResources(client); - xfree(client); + free(client); return (ClientPtr)NULL; } if (i == currentMaxClients) @@ -3725,7 +3599,7 @@ ProcInitialConnection(ClientPtr client) swaps(&stuff->length, whichbyte); } ResetCurrentRequest(client); - return (client->noClientException); + return Success; } static int @@ -3822,7 +3696,7 @@ SendConnSetup(ClientPtr client, char *reason) clientinfo.setup = (xConnSetup *)lConnectionInfo; CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); } - return (client->noClientException); + return Success; } int @@ -3856,7 +3730,7 @@ ProcEstablishConnection(ClientPtr client) client->clientState = ClientStateCheckedSecurity; else if (client->clientState != ClientStateAuthenticating) return(SendConnSetup(client, reason)); - return(client->noClientException); + return Success; } void @@ -3985,7 +3859,7 @@ AddScreen( if (i == MAXSCREENS) return -1; - pScreen = (ScreenPtr) xcalloc(1, sizeof(ScreenRec)); + pScreen = (ScreenPtr) calloc(1, sizeof(ScreenRec)); if (!pScreen) return -1; @@ -4044,7 +3918,7 @@ AddScreen( if (!(*pfnInit)(i, pScreen, argc, argv)) { dixFreePrivates(pScreen->devPrivates); - xfree(pScreen); + free(pScreen); screenInfo.numScreens--; return -1; } diff --git a/xorg-server/dix/dixfonts.c b/xorg-server/dix/dixfonts.c index 6dc819313..77bb52fb3 100644 --- a/xorg-server/dix/dixfonts.c +++ b/xorg-server/dix/dixfonts.c @@ -1,2101 +1,2106 @@ -/************************************************************************ -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" -#include "dixfont.h" -#include "xace.h" - -#ifdef DEBUG -#include -#endif - -#ifdef XF86BIGFONT -#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; -static 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; - -static int -FontToXError(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; - } -} - -static 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; -} - -/* - * 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; - err = dixLookupResourceByType((pointer *)&pf, fid, RT_FONT, serverClient, - DixReadAccess); - if (err != Success) - 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 *) - xrealloc(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); - xfree(fpe->name); - xfree(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 *) xrealloc(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) { - /* We've tried resolving this alias 20 times, we're - * probably stuck in an infinite loop of aliases pointing - * to each other - time to take emergency exit! - */ - err = BadImplementation; - 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; - } - /* check values for firstCol, lastCol, firstRow, and lastRow */ - if (pfont->info.firstCol > pfont->info.lastCol || - pfont->info.firstRow > pfont->info.lastRow || - pfont->info.lastCol - pfont->info.firstCol > 255) { - err = AllocError; - 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]); - } - xfree(c->fpe_list); - xfree(c->fontname); - xfree(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 = xalloc(lenfname + 1); - memmove(f, pfontname, lenfname); - f[lenfname] = '\0'; - ErrorF("[dix] OpenFont: fontname is \"%s\"\n", f); - xfree(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 = xalloc(sizeof(OFclosureRec)); - if (!c) - return BadAlloc; - c->fontname = xalloc(lenfname); - c->origFontName = pfontname; - c->origFontNameLen = lenfname; - if (!c->fontname) { - xfree(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 = xalloc(sizeof(FontPathElementPtr) * num_fpes); - if (!c->fpe_list) { - xfree(c->fontname); - xfree(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 - */ -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); - i = 0; - 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) xfree(resolved); - resolved = xalloc(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) - xfree(c->savedName); - c->savedName = xalloc(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; - - memset(&reply, 0, sizeof(xListFontsReply)); - reply.type = X_Reply; - reply.length = bytes_to_int32(stringLens + nnames); - reply.nFonts = nnames; - reply.sequenceNumber = client->sequence; - - bufptr = bufferStart = xalloc(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 = bytes_to_int32(stringLens + nnames); - client->pSwapReplyFunc = ReplySwapVector[X_ListFonts]; - WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply); - (void) WriteToClient(client, stringLens + nnames, bufferStart); - xfree(bufferStart); - -bail: - if (c->slept) - ClientWakeup(client); - for (i = 0; i < c->num_fpes; i++) - FreeFPE(c->fpe_list[i]); - xfree(c->fpe_list); - if (c->savedName) xfree(c->savedName); - FreeFontNames(names); - xfree(c); - if (resolved) xfree(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; - - i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); - if (i != Success) - return i; - - if (!(c = xalloc(sizeof *c))) - return BadAlloc; - c->fpe_list = xalloc(sizeof(FontPathElementPtr) * num_fpes); - if (!c->fpe_list) { - xfree(c); - return BadAlloc; - } - c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100); - if (!c->names) - { - xfree(c->fpe_list); - xfree(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) - xfree(c->savedName); - c->savedName = xalloc(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 *) xrealloc(c->reply, length); - if (!reply) - { - err = AllocError; - break; - } - memset((char*)reply + c->length, 0, length - c->length); - c->reply = reply; - c->length = length; - } - if (c->haveSaved) - { - numFonts = c->savedNumFonts; - name = c->savedName; - namelen = strlen(name); - } - reply->type = X_Reply; - reply->length = bytes_to_int32(sizeof *reply - sizeof(xGenericReply) + - pFontInfo->nprops * sizeof(xFontProp) + - namelen); - 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) - { - xfree(fontInfo.props); - xfree(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 = bytes_to_int32(sizeof(xListFontsWithInfoReply) - - sizeof(xGenericReply)); - WriteSwappedDataToClient(client, length, &finalReply); -bail: - if (c->slept) - ClientWakeup(client); - for (i = 0; i < c->num_fpes; i++) - FreeFPE(c->fpe_list[i]); - xfree(c->reply); - xfree(c->fpe_list); - if (c->savedName) xfree(c->savedName); - xfree(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; - - i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); - if (i != Success) - return i; - - if (!(c = xalloc(sizeof *c))) - goto badAlloc; - c->fpe_list = xalloc(sizeof(FontPathElementPtr) * num_fpes); - if (!c->fpe_list) - { - xfree(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, PTclosurePtr c) -{ - FontPtr pFont = c->pGC->font, oldpFont; - Font fid, oldfid; - 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) - { - DrawablePtr pDraw; - dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess); - if (c->pDraw != pDraw) { - /* 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; - oldfid = fid; - - fid = ((Font)*(c->pElt+4)) /* big-endian */ - | ((Font)*(c->pElt+3)) << 8 - | ((Font)*(c->pElt+2)) << 16 - | ((Font)*(c->pElt+1)) << 24; - err = dixLookupResourceByType((pointer *)&pFont, fid, RT_FONT, - client, DixReadAccess); - if (err != Success) - { - err = (err == BadValue) ? BadFont : err; - /* restore pFont and fid for step 4 (described below) */ - pFont = oldpFont; - fid = oldfid; - - /* 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 = xalloc(sizeof(PTclosureRec)); - if (!new_closure) - { - err = BadAlloc; - goto bail; - } - *new_closure = *c; - c = new_closure; - - len = c->endReq - c->pElt; - c->data = xalloc(len); - if (!c->data) - { - xfree(c); - err = BadAlloc; - goto bail; - } - memmove(c->data, c->pElt, len); - c->pElt = c->data; - c->endReq = c->pElt + len; - - /* Step 2 */ - - pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); - if (!pGC) - { - xfree(c->data); - xfree(c); - 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); - xfree(c->data); - xfree(c); - err = BadAlloc; - goto bail; - } - 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) { -#ifdef PANORAMIX - if (noPanoramiXExtension || !c->pGC->pScreen->myNum) -#endif - 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); - xfree(c->data); - xfree(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, 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) - { - DrawablePtr pDraw; - dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess); - if (c->pDraw != pDraw) { - /* 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; - - /* 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 = xalloc(sizeof(ITclosureRec)); - if (!new_closure) - { - err = BadAlloc; - goto bail; - } - *new_closure = *c; - c = new_closure; - - data = xalloc(c->nChars * c->itemSize); - if (!data) - { - xfree(c); - 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) - { - xfree(c->data); - xfree(c); - 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); - xfree(c->data); - xfree(c); - 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); - xfree(c->data); - xfree(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]); - } - xfree(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 = xalloc(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("[dix] 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 = xalloc(sizeof(FontPathElementRec)); - if (!fpe) - { - err = BadAlloc; - goto bail; - } - fpe->name = xalloc(len + 1); - if (!fpe->name) - { - xfree(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("[dix] Could not init font path element %s, removing from list!\n", - fpe->name); - } - xfree (fpe->name); - xfree (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]); - xfree(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 = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess); - if (err != Success) - return err; - - if (npaths == 0) { - if (SetDefaultFontPath(defaultFontPath) != Success) - return BadValue; - } else { - err = SetFontPathElements(npaths, paths, error, FALSE); - } - return err; -} - -int -SetDefaultFontPath(char *path) -{ - char *temp_path, - *start, - *end; - unsigned char *cp, - *pp, - *nump, - *newpath; - int num = 1, - len, - err, - size = 0, - bad; - - /* ensure temp_path contains "built-ins" */ - start = path; - while (1) { - start = strstr(start, "built-ins"); - if (start == NULL) - break; - end = start + strlen("built-ins"); - if ((start == path || start[-1] == ',') && (!*end || *end == ',')) - break; - start = end; - } - if (!start) { - temp_path = Xprintf("%s%sbuilt-ins", path, *path ? "," : ""); - } else { - temp_path = Xstrdup(path); - } - if (!temp_path) - return BadAlloc; - - /* get enough for string, plus values -- use up commas */ - len = strlen(temp_path) + 1; - nump = cp = newpath = xalloc(len); - if (!newpath) - return BadAlloc; - pp = (unsigned char *) temp_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); - - xfree(newpath); - xfree(temp_path); - - return err; -} - -int -GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result) -{ - int i; - unsigned char *c; - int len; - FontPathElementPtr fpe; - - i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); - if (i != Success) - return i; - - len = 0; - for (i = 0; i < num_fpes; i++) { - fpe = font_path_elements[i]; - len += fpe->name_length + 1; - } - font_path_string = (unsigned char *) xrealloc(font_path_string, len); - if (!font_path_string) - return BadAlloc; - - 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; - *result = font_path_string; - return Success; -} - -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 (void) -{ - patternCache = MakeFontPatternCache(); - - BuiltinRegisterFpeFunctions(); - FontFileRegisterFpeFunctions(); - fs_register_fpe_functions(); -} - -int -GetDefaultPointSize (void) -{ - return 120; -} - - -FontResolutionPtr -GetClientResolutions (int *num) -{ - 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 - */ - -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 *) xrealloc(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(void) -{ - if (patternCache) { - FreeFontPatternCache(patternCache); - patternCache = 0; - } - FreeFontPath(font_path_elements, num_fpes, TRUE); - font_path_elements = 0; - num_fpes = 0; - xfree(fpe_functions); - num_fpe_types = 0; - fpe_functions = (FPEFunctions *) 0; -} - -/* convenience functions for FS interface */ - -FontPtr -find_old_font(XID id) -{ - pointer pFont; - dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess); - return (FontPtr)pFont; -} - -Font -GetNewFontClientID(void) -{ - return FakeClientID(0); -} - -int -StoreFontClientFont(FontPtr pfont, Font id) -{ - return AddResource(id, RT_NONE, (pointer) pfont); -} - -void -DeleteFontClientID(Font id) -{ - FreeResource(id, RT_NONE); -} - -int -client_auth_generation(ClientPtr client) -{ - return 0; -} - -static int fs_handlers_installed = 0; -static unsigned int last_server_gen; - -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; -} - -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); -} +/************************************************************************ +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" +#include "dixfont.h" +#include "xace.h" + +#ifdef DEBUG +#include +#endif + +#ifdef XF86BIGFONT +#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; +static 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; + +static int +FontToXError(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; + } +} + +static 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; +} + +/* + * 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; + err = dixLookupResourceByType((pointer *)&pf, fid, RT_FONT, serverClient, + DixReadAccess); + if (err != Success) + 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) { + /* We've tried resolving this alias 20 times, we're + * probably stuck in an infinite loop of aliases pointing + * to each other - time to take emergency exit! + */ + err = BadImplementation; + 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; + } + /* check values for firstCol, lastCol, firstRow, and lastRow */ + if (pfont->info.firstCol > pfont->info.lastCol || + pfont->info.firstRow > pfont->info.lastRow || + pfont->info.lastCol - pfont->info.firstCol > 255) { + err = AllocError; + 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("[dix] 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 = 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 + */ +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); + i = 0; + 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; + + memset(&reply, 0, sizeof(xListFontsReply)); + reply.type = X_Reply; + reply.length = bytes_to_int32(stringLens + nnames); + reply.nFonts = nnames; + reply.sequenceNumber = client->sequence; + + bufptr = bufferStart = malloc(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 = bytes_to_int32(stringLens + nnames); + client->pSwapReplyFunc = ReplySwapVector[X_ListFonts]; + WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply); + (void) WriteToClient(client, stringLens + nnames, bufferStart); + free(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; + + i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); + if (i != Success) + return i; + + if (!(c = malloc(sizeof *c))) + return BadAlloc; + c->fpe_list = 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; + break; + } + memset((char*)reply + c->length, 0, length - c->length); + c->reply = reply; + c->length = length; + } + if (c->haveSaved) + { + numFonts = c->savedNumFonts; + name = c->savedName; + namelen = strlen(name); + } + reply->type = X_Reply; + reply->length = bytes_to_int32(sizeof *reply - sizeof(xGenericReply) + + pFontInfo->nprops * sizeof(xFontProp) + + namelen); + 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 = bytes_to_int32(sizeof(xListFontsWithInfoReply) + - sizeof(xGenericReply)); + WriteSwappedDataToClient(client, length, &finalReply); +bail: + 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; + + i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); + if (i != Success) + return i; + + if (!(c = malloc(sizeof *c))) + goto badAlloc; + c->fpe_list = 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 ChangeGCVal clearGC[] = { { .ptr = NullPixmap } }; +#define clearGCmask (GCClipMask) + +int +doPolyText(ClientPtr client, PTclosurePtr c) +{ + FontPtr pFont = c->pGC->font, oldpFont; + Font fid, oldfid; + 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) + { + DrawablePtr pDraw; + dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess); + if (c->pDraw != pDraw) { + /* 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; + oldfid = fid; + + fid = ((Font)*(c->pElt+4)) /* big-endian */ + | ((Font)*(c->pElt+3)) << 8 + | ((Font)*(c->pElt+2)) << 16 + | ((Font)*(c->pElt+1)) << 24; + err = dixLookupResourceByType((pointer *)&pFont, fid, RT_FONT, + client, DixUseAccess); + if (err != Success) + { + err = (err == BadValue) ? BadFont : err; + /* restore pFont and fid for step 4 (described below) */ + pFont = oldpFont; + fid = oldfid; + + /* 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) + { + ChangeGCVal val; + val.ptr = pFont; + ChangeGC(NullClient, c->pGC, GCFont, &val); + 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; + c = new_closure; + + len = c->endReq - c->pElt; + c->data = malloc(len); + if (!c->data) + { + free(c); + err = BadAlloc; + goto bail; + } + memmove(c->data, c->pElt, len); + c->pElt = c->data; + c->endReq = c->pElt + len; + + /* Step 2 */ + + pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); + if (!pGC) + { + free(c->data); + free(c); + 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); + err = BadAlloc; + goto bail; + } + 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) + { + ChangeGCVal val; + val.ptr = pFont; + ChangeGC(NullClient, origGC, GCFont, &val); + 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) { +#ifdef PANORAMIX + if (noPanoramiXExtension || !c->pGC->pScreen->myNum) +#endif + SendErrorToClient(c->client, c->reqType, 0, 0, err); + } + if (c->slept) + { + ClientWakeup(c->client); + ChangeGC(NullClient, 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, 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) + { + DrawablePtr pDraw; + dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess); + if (c->pDraw != pDraw) { + /* 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; + + /* 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; + } + *new_closure = *c; + c = new_closure; + + data = malloc(c->nChars * c->itemSize); + if (!data) + { + free(c); + 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); + 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); + 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(NullClient, 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(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 = 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("[dix] 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("[dix] 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); +} + +int +SetFontPath(ClientPtr client, int npaths, unsigned char *paths) +{ + int err = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess); + if (err != Success) + return err; + + if (npaths == 0) { + if (SetDefaultFontPath(defaultFontPath) != Success) + return BadValue; + } else { + int bad; + err = SetFontPathElements(npaths, paths, &bad, FALSE); + client->errorValue = bad; + } + return err; +} + +int +SetDefaultFontPath(char *path) +{ + char *temp_path, + *start, + *end; + unsigned char *cp, + *pp, + *nump, + *newpath; + int num = 1, + len, + err, + size = 0, + bad; + + /* ensure temp_path contains "built-ins" */ + start = path; + while (1) { + start = strstr(start, "built-ins"); + if (start == NULL) + break; + end = start + strlen("built-ins"); + if ((start == path || start[-1] == ',') && (!*end || *end == ',')) + break; + start = end; + } + if (!start) { + temp_path = Xprintf("%s%sbuilt-ins", path, *path ? "," : ""); + } else { + temp_path = xstrdup(path); + } + if (!temp_path) + return BadAlloc; + + /* get enough for string, plus values -- use up commas */ + len = strlen(temp_path) + 1; + nump = cp = newpath = malloc(len); + if (!newpath) + return BadAlloc; + pp = (unsigned char *) temp_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); + + free(newpath); + free(temp_path); + + return err; +} + +int +GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result) +{ + int i; + unsigned char *c; + int len; + FontPathElementPtr fpe; + + i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); + if (i != Success) + return i; + + 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 BadAlloc; + + 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; + *result = font_path_string; + return Success; +} + +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 (void) +{ + patternCache = MakeFontPatternCache(); + + BuiltinRegisterFpeFunctions(); + FontFileRegisterFpeFunctions(); + fs_register_fpe_functions(); +} + +int +GetDefaultPointSize (void) +{ + return 120; +} + + +FontResolutionPtr +GetClientResolutions (int *num) +{ + 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 + */ + +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(void) +{ + 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) +{ + pointer pFont; + dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess); + return (FontPtr)pFont; +} + +Font +GetNewFontClientID(void) +{ + return FakeClientID(0); +} + +int +StoreFontClientFont(FontPtr pfont, Font id) +{ + return AddResource(id, RT_NONE, (pointer) pfont); +} + +void +DeleteFontClientID(Font id) +{ + FreeResource(id, RT_NONE); +} + +int +client_auth_generation(ClientPtr client) +{ + return 0; +} + +static int fs_handlers_installed = 0; +static unsigned int last_server_gen; + +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; +} + +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/xorg-server/dix/dixutils.c b/xorg-server/dix/dixutils.c index 4b84a446b..9d5eb78eb 100644 --- a/xorg-server/dix/dixutils.c +++ b/xorg-server/dix/dixutils.c @@ -300,7 +300,7 @@ AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, if (j < numnow) /* duplicate */ return(Success); numnow++; - pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); + pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow); if (!pTmp) return(BadAlloc); client->saveSet = pTmp; @@ -320,13 +320,13 @@ AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, numnow--; if (numnow) { - pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); + pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow); if (pTmp) client->saveSet = pTmp; } else { - xfree(client->saveSet); + free(client->saveSet); client->saveSet = (SaveSetElt *)NULL; } client->numSaved = numnow; @@ -453,7 +453,7 @@ RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, if (numHandlers >= sizeHandlers) { - new = (BlockHandlerPtr) xrealloc (handlers, (numHandlers + 1) * + new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) * sizeof (BlockHandlerRec)); if (!new) return FALSE; @@ -498,7 +498,7 @@ RemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, void InitBlockAndWakeupHandlers (void) { - xfree (handlers); + free(handlers); handlers = (BlockHandlerPtr) 0; numHandlers = 0; sizeHandlers = 0; @@ -530,7 +530,7 @@ ProcessWorkQueue(void) { /* remove q from the list */ *p = q->next; /* don't fetch until after func called */ - xfree (q); + free(q); } else { @@ -553,7 +553,7 @@ ProcessWorkQueueZombies(void) (void) (*q->function) (q->client, q->closure); /* remove q from the list */ *p = q->next; /* don't fetch until after func called */ - xfree (q); + free(q); } else { @@ -570,7 +570,7 @@ QueueWorkProc ( { WorkQueuePtr q; - q = xalloc (sizeof *q); + q = malloc(sizeof *q); if (!q) return FALSE; q->function = function; @@ -604,7 +604,7 @@ ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure) { SleepQueuePtr q; - q = xalloc (sizeof *q); + q = malloc(sizeof *q); if (!q) return FALSE; @@ -641,7 +641,7 @@ ClientWakeup (ClientPtr client) if (q->client == client) { *prev = q->next; - xfree (q); + free(q); if (client->clientGone) /* Oops -- new zombie cleanup code ensures this only * happens from inside CloseDownClient; don't want to @@ -684,7 +684,7 @@ _AddCallback( { CallbackPtr cbr; - cbr = xalloc(sizeof(CallbackRec)); + cbr = malloc(sizeof(CallbackRec)); if (!cbr) return FALSE; cbr->proc = callback; @@ -724,7 +724,7 @@ _DeleteCallback( cbl->list = cbr->next; else pcbr->next = cbr->next; - xfree(cbr); + free(cbr); } return TRUE; } @@ -769,12 +769,12 @@ _CallCallbacks( if (pcbr) { cbr = cbr->next; - xfree(pcbr->next); + free(pcbr->next); pcbr->next = cbr; } else { cbr = cbr->next; - xfree(cbl->list); + free(cbl->list); cbl->list = cbr; } cbl->numDeleted--; @@ -814,9 +814,9 @@ _DeleteCallbackList( for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) { nextcbr = cbr->next; - xfree(cbr); + free(cbr); } - xfree(cbl); + free(cbl); *pcbl = NULL; } @@ -827,7 +827,7 @@ CreateCallbackList(CallbackListPtr *pcbl) int i; if (!pcbl) return FALSE; - cbl = xalloc(sizeof(CallbackListRec)); + cbl = malloc(sizeof(CallbackListRec)); if (!cbl) return FALSE; cbl->inCallback = 0; cbl->deleted = FALSE; @@ -895,7 +895,7 @@ InitCallbackManager(void) { DeleteCallbackList(listsToCleanup[i]); } - if (listsToCleanup) xfree(listsToCleanup); + if (listsToCleanup) free(listsToCleanup); numCallbackListsToCleanup = 0; listsToCleanup = NULL; diff --git a/xorg-server/dix/eventconvert.c b/xorg-server/dix/eventconvert.c index 878dba576..aa72708ed 100644 --- a/xorg-server/dix/eventconvert.c +++ b/xorg-server/dix/eventconvert.c @@ -1,719 +1,719 @@ -/* - * Copyright © 2009 Red Hat, Inc. - * - * 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. - * - */ - -/** - * @file eventconvert.c - * This file contains event conversion routines from InternalEvent to the - * matching protocol events. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "dix.h" -#include "inputstr.h" -#include "misc.h" -#include "eventstr.h" -#include "exglobals.h" -#include "eventconvert.h" -#include "xiquerydevice.h" -#include "xkbsrv.h" - - -static int countValuators(DeviceEvent *ev, int *first); -static int getValuatorEvents(DeviceEvent *ev, deviceValuator *xv); -static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count); -static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce); -static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi); -static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi); - -/* Do not use, read comments below */ -BOOL EventIsKeyRepeat(xEvent *event); - -/** - * Hack to allow detectable autorepeat for core and XI1 events. - * The sequence number is unused until we send to the client and can be - * misused to store data. More or less, anyway. - * - * Do not use this. It may change any time without warning, eat your babies - * and piss on your cat. - */ -static void -EventSetKeyRepeatFlag(xEvent *event, BOOL on) -{ - event->u.u.sequenceNumber = on; -} - -/** - * Check if the event was marked as a repeat event before. - * NOTE: This is a nasty hack and should NOT be used by anyone else but - * TryClientEvents. - */ -BOOL -EventIsKeyRepeat(xEvent *event) -{ - return !!event->u.u.sequenceNumber; -} - -/** - * Convert the given event to the respective core event. - * - * Return values: - * Success ... core contains the matching core event. - * BadValue .. One or more values in the internal event are invalid. - * BadMatch .. The event has no core equivalent. - * - * @param[in] event The event to convert into a core event. - * @param[in] core The memory location to store the core event at. - * @return Success or the matching error code. - */ -int -EventToCore(InternalEvent *event, xEvent *core) -{ - switch(event->any.type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - { - DeviceEvent *e = &event->device_event; - - if (e->detail.key > 0xFF) - return BadMatch; - - memset(core, 0, sizeof(xEvent)); - core->u.u.type = e->type - ET_KeyPress + KeyPress; - core->u.u.detail = e->detail.key & 0xFF; - core->u.keyButtonPointer.time = e->time; - core->u.keyButtonPointer.rootX = e->root_x; - core->u.keyButtonPointer.rootY = e->root_y; - core->u.keyButtonPointer.state = e->corestate; - core->u.keyButtonPointer.root = e->root; - EventSetKeyRepeatFlag(core, (e->type == ET_KeyPress && e->key_repeat)); - } - break; - case ET_ProximityIn: - case ET_ProximityOut: - case ET_RawKeyPress: - case ET_RawKeyRelease: - case ET_RawButtonPress: - case ET_RawButtonRelease: - case ET_RawMotion: - return BadMatch; - default: - /* XXX: */ - ErrorF("[dix] EventToCore: Not implemented yet \n"); - return BadImplementation; - } - return Success; -} - -/** - * Convert the given event to the respective XI 1.x event and store it in - * xi. xi is allocated on demand and must be freed by the caller. - * count returns the number of events in xi. If count is 1, and the type of - * xi is GenericEvent, then xi may be larger than 32 bytes. - * - * Return values: - * Success ... core contains the matching core event. - * BadValue .. One or more values in the internal event are invalid. - * BadMatch .. The event has no XI equivalent. - * - * @param[in] ev The event to convert into an XI 1 event. - * @param[out] xi Future memory location for the XI event. - * @param[out] count Number of elements in xi. - * - * @return Success or the error code. - */ -int -EventToXI(InternalEvent *ev, xEvent **xi, int *count) -{ - switch (ev->any.type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - return eventToKeyButtonPointer(&ev->device_event, xi, count); - case ET_DeviceChanged: - case ET_RawKeyPress: - case ET_RawKeyRelease: - case ET_RawButtonPress: - case ET_RawButtonRelease: - case ET_RawMotion: - *count = 0; - *xi = NULL; - return BadMatch; - default: - break; - } - - ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type); - return BadImplementation; -} - -/** - * Convert the given event to the respective XI 2.x event and store it in xi. - * xi is allocated on demand and must be freed by the caller. - * - * Return values: - * Success ... core contains the matching core event. - * BadValue .. One or more values in the internal event are invalid. - * BadMatch .. The event has no XI2 equivalent. - * - * @param[in] ev The event to convert into an XI2 event - * @param[out] xi Future memory location for the XI2 event. - * - * @return Success or the error code. - */ -int -EventToXI2(InternalEvent *ev, xEvent **xi) -{ - switch (ev->any.type) - { - /* Enter/FocusIn are for grabs. We don't need an actual event, since - * the real events delivered are triggered elsewhere */ - case ET_Enter: - case ET_FocusIn: - *xi = NULL; - return Success; - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - return eventToDeviceEvent(&ev->device_event, xi); - case ET_ProximityIn: - case ET_ProximityOut: - *xi = NULL; - return BadMatch; - case ET_DeviceChanged: - return eventToDeviceChanged(&ev->changed_event, xi); - case ET_RawKeyPress: - case ET_RawKeyRelease: - case ET_RawButtonPress: - case ET_RawButtonRelease: - case ET_RawMotion: - return eventToRawEvent(&ev->raw_event, xi); - default: - break; - } - - ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type); - return BadImplementation; -} - -static int -eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count) -{ - int num_events; - int first; /* dummy */ - deviceKeyButtonPointer *kbp; - - /* Sorry, XI 1.x protocol restrictions. */ - if (ev->detail.button > 0xFF || ev->deviceid >= 0x80) - { - *count = 0; - return Success; - } - - num_events = (countValuators(ev, &first) + 5)/6; /* valuator ev */ - num_events++; /* the actual event event */ - - *xi = xcalloc(num_events, sizeof(xEvent)); - if (!(*xi)) - { - return BadAlloc; - } - - kbp = (deviceKeyButtonPointer*)(*xi); - kbp->detail = ev->detail.button; - kbp->time = ev->time; - kbp->root = ev->root; - kbp->root_x = ev->root_x; - kbp->root_y = ev->root_y; - kbp->deviceid = ev->deviceid; - kbp->state = ev->corestate; - EventSetKeyRepeatFlag((xEvent*)kbp, - (ev->type == ET_KeyPress && ev->key_repeat)); - - if (num_events > 1) - kbp->deviceid |= MORE_EVENTS; - - switch(ev->type) - { - case ET_Motion: kbp->type = DeviceMotionNotify; break; - case ET_ButtonPress: kbp->type = DeviceButtonPress; break; - case ET_ButtonRelease: kbp->type = DeviceButtonRelease; break; - case ET_KeyPress: kbp->type = DeviceKeyPress; break; - case ET_KeyRelease: kbp->type = DeviceKeyRelease; break; - case ET_ProximityIn: kbp->type = ProximityIn; break; - case ET_ProximityOut: kbp->type = ProximityOut; break; - default: - break; - } - - if (num_events > 1) - { - getValuatorEvents(ev, (deviceValuator*)(kbp + 1)); - } - - *count = num_events; - return Success; -} - - -/** - * Set first to the first valuator in the event ev and return the number of - * valuators from first to the last set valuator. - */ -static int -countValuators(DeviceEvent *ev, int *first) -{ - int first_valuator = -1, last_valuator = -1, num_valuators = 0; - int i; - - for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) - { - if (BitIsOn(ev->valuators.mask, i)) - { - if (first_valuator == -1) - first_valuator = i; - last_valuator = i; - } - } - - if (first_valuator != -1) - { - num_valuators = last_valuator - first_valuator + 1; - *first = first_valuator; - } - - return num_valuators; -} - -static int -getValuatorEvents(DeviceEvent *ev, deviceValuator *xv) -{ - int i; - int state = 0; - int first_valuator, num_valuators; - - - num_valuators = countValuators(ev, &first_valuator); - if (num_valuators > 0) - { - DeviceIntPtr dev = NULL; - dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess); - /* State needs to be assembled BEFORE the device is updated. */ - state = (dev && dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->state) : 0; - state |= (dev && dev->button) ? (dev->button->state) : 0; - } - - /* FIXME: non-continuous valuator data in internal events*/ - for (i = 0; i < num_valuators; i += 6, xv++) { - xv->type = DeviceValuator; - xv->first_valuator = first_valuator + i; - xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i); - xv->deviceid = ev->deviceid; - xv->device_state = state; - switch (xv->num_valuators) { - case 6: - xv->valuator5 = ev->valuators.data[xv->first_valuator + 5]; - case 5: - xv->valuator4 = ev->valuators.data[xv->first_valuator + 4]; - case 4: - xv->valuator3 = ev->valuators.data[xv->first_valuator + 3]; - case 3: - xv->valuator2 = ev->valuators.data[xv->first_valuator + 2]; - case 2: - xv->valuator1 = ev->valuators.data[xv->first_valuator + 1]; - case 1: - xv->valuator0 = ev->valuators.data[xv->first_valuator + 0]; - } - - if (i + 6 < num_valuators) - xv->deviceid |= MORE_EVENTS; - } - - return (num_valuators + 5) / 6; -} - - -static int -appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo* info) -{ - uint32_t *kc; - int i; - - info->type = XIKeyClass; - info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1; - info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes; - info->sourceid = dce->sourceid; - - kc = (uint32_t*)&info[1]; - for (i = 0; i < info->num_keycodes; i++) - *kc++ = i + dce->keys.min_keycode; - - return info->length * 4; -} - -static int -appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo *info) -{ - unsigned char *bits; - int mask_len; - - mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons)); - - info->type = XIButtonClass; - info->num_buttons = dce->buttons.num_buttons; - info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + - info->num_buttons + mask_len; - info->sourceid = dce->sourceid; - - bits = (unsigned char*)&info[1]; - memset(bits, 0, mask_len * 4); - /* FIXME: is_down? */ - - bits += mask_len * 4; - memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom)); - - return info->length * 4; -} - -static int -appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo *info, int axisnumber) -{ - info->type = XIValuatorClass; - info->length = sizeof(xXIValuatorInfo)/4; - info->label = dce->valuators[axisnumber].name; - info->min.integral = dce->valuators[axisnumber].min; - info->min.frac = 0; - info->max.integral = dce->valuators[axisnumber].max; - info->max.frac = 0; - /* FIXME: value */ - info->value.integral = 0; - info->value.frac = 0; - info->resolution = dce->valuators[axisnumber].resolution; - info->number = axisnumber; - info->mode = dce->valuators[axisnumber].mode; /* Server doesn't have per-axis mode yet */ - info->sourceid = dce->sourceid; - - return info->length * 4; -} - -static int -eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi) -{ - xXIDeviceChangedEvent *dcce; - int len = sizeof(xXIDeviceChangedEvent); - int nkeys; - char *ptr; - - if (dce->buttons.num_buttons) - { - len += sizeof(xXIButtonInfo); - len += dce->buttons.num_buttons * sizeof(Atom); /* button names */ - len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons)); - } - if (dce->num_valuators) - len += sizeof(xXIValuatorInfo) * dce->num_valuators; - - nkeys = (dce->keys.max_keycode > 0) ? - dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0; - if (nkeys > 0) - { - len += sizeof(xXIKeyInfo); - len += sizeof(CARD32) * nkeys; /* keycodes */ - } - - dcce = xcalloc(1, len); - if (!dcce) - { - ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n"); - return BadAlloc; - } - - dcce->type = GenericEvent; - dcce->extension = IReqCode; - dcce->evtype = XI_DeviceChanged; - dcce->time = dce->time; - dcce->deviceid = dce->deviceid; - dcce->sourceid = dce->sourceid; - dcce->reason = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch; - dcce->num_classes = 0; - dcce->length = bytes_to_int32(len - sizeof(xEvent)); - - ptr = (char*)&dcce[1]; - if (dce->buttons.num_buttons) - { - dcce->num_classes++; - ptr += appendButtonInfo(dce, (xXIButtonInfo*)ptr); - } - - if (nkeys) - { - dcce->num_classes++; - ptr += appendKeyInfo(dce, (xXIKeyInfo*)ptr); - } - - if (dce->num_valuators) - { - int i; - - dcce->num_classes += dce->num_valuators; - for (i = 0; i < dce->num_valuators; i++) - ptr += appendValuatorInfo(dce, (xXIValuatorInfo*)ptr, i); - } - - *xi = (xEvent*)dcce; - - return Success; -} - -static int count_bits(unsigned char* ptr, int len) -{ - int bits = 0; - unsigned int i; - unsigned char x; - - for (i = 0; i < len; i++) - { - x = ptr[i]; - while(x > 0) - { - bits += (x & 0x1); - x >>= 1; - } - } - return bits; -} - -static int -eventToDeviceEvent(DeviceEvent *ev, xEvent **xi) -{ - int len = sizeof(xXIDeviceEvent); - xXIDeviceEvent *xde; - int i, btlen, vallen; - char *ptr; - FP3232 *axisval; - - /* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same - * with MAX_VALUATORS below */ - /* btlen is in 4 byte units */ - btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS)); - len += btlen * 4; /* buttonmask len */ - - - vallen = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)/sizeof(ev->valuators.mask[0])); - len += vallen * 2 * sizeof(uint32_t); /* axisvalues */ - vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS)); - len += vallen * 4; /* valuators mask */ - - *xi = xcalloc(1, len); - xde = (xXIDeviceEvent*)*xi; - xde->type = GenericEvent; - xde->extension = IReqCode; - xde->evtype = GetXI2Type((InternalEvent*)ev); - xde->time = ev->time; - xde->length = bytes_to_int32(len - sizeof(xEvent)); - xde->detail = ev->detail.button; - xde->root = ev->root; - xde->buttons_len = btlen; - xde->valuators_len = vallen; - xde->deviceid = ev->deviceid; - xde->sourceid = ev->sourceid; - xde->root_x = FP1616(ev->root_x, ev->root_x_frac); - xde->root_y = FP1616(ev->root_y, ev->root_y_frac); - - if (ev->key_repeat) - xde->flags |= XIKeyRepeat; - - xde->mods.base_mods = ev->mods.base; - xde->mods.latched_mods = ev->mods.latched; - xde->mods.locked_mods = ev->mods.locked; - xde->mods.effective_mods = ev->mods.effective; - - xde->group.base_group = ev->group.base; - xde->group.latched_group = ev->group.latched; - xde->group.locked_group = ev->group.locked; - xde->group.effective_group = ev->group.effective; - - ptr = (char*)&xde[1]; - for (i = 0; i < sizeof(ev->buttons) * 8; i++) - { - if (BitIsOn(ev->buttons, i)) - SetBit(ptr, i); - } - - ptr += xde->buttons_len * 4; - axisval = (FP3232*)(ptr + xde->valuators_len * 4); - for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) - { - if (BitIsOn(ev->valuators.mask, i)) - { - SetBit(ptr, i); - axisval->integral = ev->valuators.data[i]; - axisval->frac = ev->valuators.data_frac[i]; - axisval++; - } - } - - return Success; -} - -static int -eventToRawEvent(RawDeviceEvent *ev, xEvent **xi) -{ - xXIRawEvent* raw; - int vallen, nvals; - int i, len = sizeof(xXIRawEvent); - char *ptr; - FP3232 *axisval; - - nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)); - len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once - raw, once processed */ - vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS)); - len += vallen * 4; /* valuators mask */ - - *xi = xcalloc(1, len); - raw = (xXIRawEvent*)*xi; - raw->type = GenericEvent; - raw->extension = IReqCode; - raw->evtype = GetXI2Type((InternalEvent*)ev); - raw->time = ev->time; - raw->length = bytes_to_int32(len - sizeof(xEvent)); - raw->detail = ev->detail.button; - raw->deviceid = ev->deviceid; - raw->valuators_len = vallen; - - ptr = (char*)&raw[1]; - axisval = (FP3232*)(ptr + raw->valuators_len * 4); - for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) - { - if (BitIsOn(ev->valuators.mask, i)) - { - SetBit(ptr, i); - axisval->integral = ev->valuators.data[i]; - axisval->frac = ev->valuators.data_frac[i]; - (axisval + nvals)->integral = ev->valuators.data_raw[i]; - (axisval + nvals)->frac = ev->valuators.data_raw_frac[i]; - axisval++; - } - } - - return Success; -} - -/** - * Return the corresponding core type for the given event or 0 if no core - * equivalent exists. - */ -int -GetCoreType(InternalEvent *event) -{ - int coretype = 0; - switch(event->any.type) - { - case ET_Motion: coretype = MotionNotify; break; - case ET_ButtonPress: coretype = ButtonPress; break; - case ET_ButtonRelease: coretype = ButtonRelease; break; - case ET_KeyPress: coretype = KeyPress; break; - case ET_KeyRelease: coretype = KeyRelease; break; - default: - break; - } - return coretype; -} - -/** - * Return the corresponding XI 1.x type for the given event or 0 if no - * equivalent exists. - */ -int -GetXIType(InternalEvent *event) -{ - int xitype = 0; - switch(event->any.type) - { - case ET_Motion: xitype = DeviceMotionNotify; break; - case ET_ButtonPress: xitype = DeviceButtonPress; break; - case ET_ButtonRelease: xitype = DeviceButtonRelease; break; - case ET_KeyPress: xitype = DeviceKeyPress; break; - case ET_KeyRelease: xitype = DeviceKeyRelease; break; - case ET_ProximityIn: xitype = ProximityIn; break; - case ET_ProximityOut: xitype = ProximityOut; break; - default: - break; - } - return xitype; -} - -/** - * Return the corresponding XI 2.x type for the given event or 0 if no - * equivalent exists. - */ -int -GetXI2Type(InternalEvent *event) -{ - int xi2type = 0; - - switch(event->any.type) - { - case ET_Motion: xi2type = XI_Motion; break; - case ET_ButtonPress: xi2type = XI_ButtonPress; break; - case ET_ButtonRelease: xi2type = XI_ButtonRelease; break; - case ET_KeyPress: xi2type = XI_KeyPress; break; - case ET_KeyRelease: xi2type = XI_KeyRelease; break; - case ET_Enter: xi2type = XI_Enter; break; - case ET_Leave: xi2type = XI_Leave; break; - case ET_Hierarchy: xi2type = XI_HierarchyChanged; break; - case ET_DeviceChanged: xi2type = XI_DeviceChanged; break; - case ET_RawKeyPress: xi2type = XI_RawKeyPress; break; - case ET_RawKeyRelease: xi2type = XI_RawKeyRelease; break; - case ET_RawButtonPress: xi2type = XI_RawButtonPress; break; - case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break; - case ET_RawMotion: xi2type = XI_RawMotion; break; - case ET_FocusIn: xi2type = XI_FocusIn; break; - case ET_FocusOut: xi2type = XI_FocusOut; break; - default: - break; - } - return xi2type; -} +/* + * Copyright © 2009 Red Hat, Inc. + * + * 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. + * + */ + +/** + * @file eventconvert.c + * This file contains event conversion routines from InternalEvent to the + * matching protocol events. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "dix.h" +#include "inputstr.h" +#include "misc.h" +#include "eventstr.h" +#include "exglobals.h" +#include "eventconvert.h" +#include "xiquerydevice.h" +#include "xkbsrv.h" + + +static int countValuators(DeviceEvent *ev, int *first); +static int getValuatorEvents(DeviceEvent *ev, deviceValuator *xv); +static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count); +static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce); +static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi); +static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi); + +/* Do not use, read comments below */ +BOOL EventIsKeyRepeat(xEvent *event); + +/** + * Hack to allow detectable autorepeat for core and XI1 events. + * The sequence number is unused until we send to the client and can be + * misused to store data. More or less, anyway. + * + * Do not use this. It may change any time without warning, eat your babies + * and piss on your cat. + */ +static void +EventSetKeyRepeatFlag(xEvent *event, BOOL on) +{ + event->u.u.sequenceNumber = on; +} + +/** + * Check if the event was marked as a repeat event before. + * NOTE: This is a nasty hack and should NOT be used by anyone else but + * TryClientEvents. + */ +BOOL +EventIsKeyRepeat(xEvent *event) +{ + return !!event->u.u.sequenceNumber; +} + +/** + * Convert the given event to the respective core event. + * + * Return values: + * Success ... core contains the matching core event. + * BadValue .. One or more values in the internal event are invalid. + * BadMatch .. The event has no core equivalent. + * + * @param[in] event The event to convert into a core event. + * @param[in] core The memory location to store the core event at. + * @return Success or the matching error code. + */ +int +EventToCore(InternalEvent *event, xEvent *core) +{ + switch(event->any.type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + { + DeviceEvent *e = &event->device_event; + + if (e->detail.key > 0xFF) + return BadMatch; + + memset(core, 0, sizeof(xEvent)); + core->u.u.type = e->type - ET_KeyPress + KeyPress; + core->u.u.detail = e->detail.key & 0xFF; + core->u.keyButtonPointer.time = e->time; + core->u.keyButtonPointer.rootX = e->root_x; + core->u.keyButtonPointer.rootY = e->root_y; + core->u.keyButtonPointer.state = e->corestate; + core->u.keyButtonPointer.root = e->root; + EventSetKeyRepeatFlag(core, (e->type == ET_KeyPress && e->key_repeat)); + } + break; + case ET_ProximityIn: + case ET_ProximityOut: + case ET_RawKeyPress: + case ET_RawKeyRelease: + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: + return BadMatch; + default: + /* XXX: */ + ErrorF("[dix] EventToCore: Not implemented yet \n"); + return BadImplementation; + } + return Success; +} + +/** + * Convert the given event to the respective XI 1.x event and store it in + * xi. xi is allocated on demand and must be freed by the caller. + * count returns the number of events in xi. If count is 1, and the type of + * xi is GenericEvent, then xi may be larger than 32 bytes. + * + * Return values: + * Success ... core contains the matching core event. + * BadValue .. One or more values in the internal event are invalid. + * BadMatch .. The event has no XI equivalent. + * + * @param[in] ev The event to convert into an XI 1 event. + * @param[out] xi Future memory location for the XI event. + * @param[out] count Number of elements in xi. + * + * @return Success or the error code. + */ +int +EventToXI(InternalEvent *ev, xEvent **xi, int *count) +{ + switch (ev->any.type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + return eventToKeyButtonPointer(&ev->device_event, xi, count); + case ET_DeviceChanged: + case ET_RawKeyPress: + case ET_RawKeyRelease: + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: + *count = 0; + *xi = NULL; + return BadMatch; + default: + break; + } + + ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type); + return BadImplementation; +} + +/** + * Convert the given event to the respective XI 2.x event and store it in xi. + * xi is allocated on demand and must be freed by the caller. + * + * Return values: + * Success ... core contains the matching core event. + * BadValue .. One or more values in the internal event are invalid. + * BadMatch .. The event has no XI2 equivalent. + * + * @param[in] ev The event to convert into an XI2 event + * @param[out] xi Future memory location for the XI2 event. + * + * @return Success or the error code. + */ +int +EventToXI2(InternalEvent *ev, xEvent **xi) +{ + switch (ev->any.type) + { + /* Enter/FocusIn are for grabs. We don't need an actual event, since + * the real events delivered are triggered elsewhere */ + case ET_Enter: + case ET_FocusIn: + *xi = NULL; + return Success; + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + return eventToDeviceEvent(&ev->device_event, xi); + case ET_ProximityIn: + case ET_ProximityOut: + *xi = NULL; + return BadMatch; + case ET_DeviceChanged: + return eventToDeviceChanged(&ev->changed_event, xi); + case ET_RawKeyPress: + case ET_RawKeyRelease: + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: + return eventToRawEvent(&ev->raw_event, xi); + default: + break; + } + + ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type); + return BadImplementation; +} + +static int +eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count) +{ + int num_events; + int first; /* dummy */ + deviceKeyButtonPointer *kbp; + + /* Sorry, XI 1.x protocol restrictions. */ + if (ev->detail.button > 0xFF || ev->deviceid >= 0x80) + { + *count = 0; + return Success; + } + + num_events = (countValuators(ev, &first) + 5)/6; /* valuator ev */ + num_events++; /* the actual event event */ + + *xi = calloc(num_events, sizeof(xEvent)); + if (!(*xi)) + { + return BadAlloc; + } + + kbp = (deviceKeyButtonPointer*)(*xi); + kbp->detail = ev->detail.button; + kbp->time = ev->time; + kbp->root = ev->root; + kbp->root_x = ev->root_x; + kbp->root_y = ev->root_y; + kbp->deviceid = ev->deviceid; + kbp->state = ev->corestate; + EventSetKeyRepeatFlag((xEvent*)kbp, + (ev->type == ET_KeyPress && ev->key_repeat)); + + if (num_events > 1) + kbp->deviceid |= MORE_EVENTS; + + switch(ev->type) + { + case ET_Motion: kbp->type = DeviceMotionNotify; break; + case ET_ButtonPress: kbp->type = DeviceButtonPress; break; + case ET_ButtonRelease: kbp->type = DeviceButtonRelease; break; + case ET_KeyPress: kbp->type = DeviceKeyPress; break; + case ET_KeyRelease: kbp->type = DeviceKeyRelease; break; + case ET_ProximityIn: kbp->type = ProximityIn; break; + case ET_ProximityOut: kbp->type = ProximityOut; break; + default: + break; + } + + if (num_events > 1) + { + getValuatorEvents(ev, (deviceValuator*)(kbp + 1)); + } + + *count = num_events; + return Success; +} + + +/** + * Set first to the first valuator in the event ev and return the number of + * valuators from first to the last set valuator. + */ +static int +countValuators(DeviceEvent *ev, int *first) +{ + int first_valuator = -1, last_valuator = -1, num_valuators = 0; + int i; + + for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) + { + if (BitIsOn(ev->valuators.mask, i)) + { + if (first_valuator == -1) + first_valuator = i; + last_valuator = i; + } + } + + if (first_valuator != -1) + { + num_valuators = last_valuator - first_valuator + 1; + *first = first_valuator; + } + + return num_valuators; +} + +static int +getValuatorEvents(DeviceEvent *ev, deviceValuator *xv) +{ + int i; + int state = 0; + int first_valuator, num_valuators; + + + num_valuators = countValuators(ev, &first_valuator); + if (num_valuators > 0) + { + DeviceIntPtr dev = NULL; + dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess); + /* State needs to be assembled BEFORE the device is updated. */ + state = (dev && dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->state) : 0; + state |= (dev && dev->button) ? (dev->button->state) : 0; + } + + /* FIXME: non-continuous valuator data in internal events*/ + for (i = 0; i < num_valuators; i += 6, xv++) { + xv->type = DeviceValuator; + xv->first_valuator = first_valuator + i; + xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i); + xv->deviceid = ev->deviceid; + xv->device_state = state; + switch (xv->num_valuators) { + case 6: + xv->valuator5 = ev->valuators.data[xv->first_valuator + 5]; + case 5: + xv->valuator4 = ev->valuators.data[xv->first_valuator + 4]; + case 4: + xv->valuator3 = ev->valuators.data[xv->first_valuator + 3]; + case 3: + xv->valuator2 = ev->valuators.data[xv->first_valuator + 2]; + case 2: + xv->valuator1 = ev->valuators.data[xv->first_valuator + 1]; + case 1: + xv->valuator0 = ev->valuators.data[xv->first_valuator + 0]; + } + + if (i + 6 < num_valuators) + xv->deviceid |= MORE_EVENTS; + } + + return (num_valuators + 5) / 6; +} + + +static int +appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo* info) +{ + uint32_t *kc; + int i; + + info->type = XIKeyClass; + info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1; + info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes; + info->sourceid = dce->sourceid; + + kc = (uint32_t*)&info[1]; + for (i = 0; i < info->num_keycodes; i++) + *kc++ = i + dce->keys.min_keycode; + + return info->length * 4; +} + +static int +appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo *info) +{ + unsigned char *bits; + int mask_len; + + mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons)); + + info->type = XIButtonClass; + info->num_buttons = dce->buttons.num_buttons; + info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + + info->num_buttons + mask_len; + info->sourceid = dce->sourceid; + + bits = (unsigned char*)&info[1]; + memset(bits, 0, mask_len * 4); + /* FIXME: is_down? */ + + bits += mask_len * 4; + memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom)); + + return info->length * 4; +} + +static int +appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo *info, int axisnumber) +{ + info->type = XIValuatorClass; + info->length = sizeof(xXIValuatorInfo)/4; + info->label = dce->valuators[axisnumber].name; + info->min.integral = dce->valuators[axisnumber].min; + info->min.frac = 0; + info->max.integral = dce->valuators[axisnumber].max; + info->max.frac = 0; + /* FIXME: value */ + info->value.integral = 0; + info->value.frac = 0; + info->resolution = dce->valuators[axisnumber].resolution; + info->number = axisnumber; + info->mode = dce->valuators[axisnumber].mode; /* Server doesn't have per-axis mode yet */ + info->sourceid = dce->sourceid; + + return info->length * 4; +} + +static int +eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi) +{ + xXIDeviceChangedEvent *dcce; + int len = sizeof(xXIDeviceChangedEvent); + int nkeys; + char *ptr; + + if (dce->buttons.num_buttons) + { + len += sizeof(xXIButtonInfo); + len += dce->buttons.num_buttons * sizeof(Atom); /* button names */ + len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons)); + } + if (dce->num_valuators) + len += sizeof(xXIValuatorInfo) * dce->num_valuators; + + nkeys = (dce->keys.max_keycode > 0) ? + dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0; + if (nkeys > 0) + { + len += sizeof(xXIKeyInfo); + len += sizeof(CARD32) * nkeys; /* keycodes */ + } + + dcce = calloc(1, len); + if (!dcce) + { + ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n"); + return BadAlloc; + } + + dcce->type = GenericEvent; + dcce->extension = IReqCode; + dcce->evtype = XI_DeviceChanged; + dcce->time = dce->time; + dcce->deviceid = dce->deviceid; + dcce->sourceid = dce->sourceid; + dcce->reason = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch; + dcce->num_classes = 0; + dcce->length = bytes_to_int32(len - sizeof(xEvent)); + + ptr = (char*)&dcce[1]; + if (dce->buttons.num_buttons) + { + dcce->num_classes++; + ptr += appendButtonInfo(dce, (xXIButtonInfo*)ptr); + } + + if (nkeys) + { + dcce->num_classes++; + ptr += appendKeyInfo(dce, (xXIKeyInfo*)ptr); + } + + if (dce->num_valuators) + { + int i; + + dcce->num_classes += dce->num_valuators; + for (i = 0; i < dce->num_valuators; i++) + ptr += appendValuatorInfo(dce, (xXIValuatorInfo*)ptr, i); + } + + *xi = (xEvent*)dcce; + + return Success; +} + +static int count_bits(unsigned char* ptr, int len) +{ + int bits = 0; + unsigned int i; + unsigned char x; + + for (i = 0; i < len; i++) + { + x = ptr[i]; + while(x > 0) + { + bits += (x & 0x1); + x >>= 1; + } + } + return bits; +} + +static int +eventToDeviceEvent(DeviceEvent *ev, xEvent **xi) +{ + int len = sizeof(xXIDeviceEvent); + xXIDeviceEvent *xde; + int i, btlen, vallen; + char *ptr; + FP3232 *axisval; + + /* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same + * with MAX_VALUATORS below */ + /* btlen is in 4 byte units */ + btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS)); + len += btlen * 4; /* buttonmask len */ + + + vallen = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)/sizeof(ev->valuators.mask[0])); + len += vallen * 2 * sizeof(uint32_t); /* axisvalues */ + vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS)); + len += vallen * 4; /* valuators mask */ + + *xi = calloc(1, len); + xde = (xXIDeviceEvent*)*xi; + xde->type = GenericEvent; + xde->extension = IReqCode; + xde->evtype = GetXI2Type((InternalEvent*)ev); + xde->time = ev->time; + xde->length = bytes_to_int32(len - sizeof(xEvent)); + xde->detail = ev->detail.button; + xde->root = ev->root; + xde->buttons_len = btlen; + xde->valuators_len = vallen; + xde->deviceid = ev->deviceid; + xde->sourceid = ev->sourceid; + xde->root_x = FP1616(ev->root_x, ev->root_x_frac); + xde->root_y = FP1616(ev->root_y, ev->root_y_frac); + + if (ev->key_repeat) + xde->flags |= XIKeyRepeat; + + xde->mods.base_mods = ev->mods.base; + xde->mods.latched_mods = ev->mods.latched; + xde->mods.locked_mods = ev->mods.locked; + xde->mods.effective_mods = ev->mods.effective; + + xde->group.base_group = ev->group.base; + xde->group.latched_group = ev->group.latched; + xde->group.locked_group = ev->group.locked; + xde->group.effective_group = ev->group.effective; + + ptr = (char*)&xde[1]; + for (i = 0; i < sizeof(ev->buttons) * 8; i++) + { + if (BitIsOn(ev->buttons, i)) + SetBit(ptr, i); + } + + ptr += xde->buttons_len * 4; + axisval = (FP3232*)(ptr + xde->valuators_len * 4); + for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) + { + if (BitIsOn(ev->valuators.mask, i)) + { + SetBit(ptr, i); + axisval->integral = ev->valuators.data[i]; + axisval->frac = ev->valuators.data_frac[i]; + axisval++; + } + } + + return Success; +} + +static int +eventToRawEvent(RawDeviceEvent *ev, xEvent **xi) +{ + xXIRawEvent* raw; + int vallen, nvals; + int i, len = sizeof(xXIRawEvent); + char *ptr; + FP3232 *axisval; + + nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)); + len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once + raw, once processed */ + vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS)); + len += vallen * 4; /* valuators mask */ + + *xi = calloc(1, len); + raw = (xXIRawEvent*)*xi; + raw->type = GenericEvent; + raw->extension = IReqCode; + raw->evtype = GetXI2Type((InternalEvent*)ev); + raw->time = ev->time; + raw->length = bytes_to_int32(len - sizeof(xEvent)); + raw->detail = ev->detail.button; + raw->deviceid = ev->deviceid; + raw->valuators_len = vallen; + + ptr = (char*)&raw[1]; + axisval = (FP3232*)(ptr + raw->valuators_len * 4); + for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) + { + if (BitIsOn(ev->valuators.mask, i)) + { + SetBit(ptr, i); + axisval->integral = ev->valuators.data[i]; + axisval->frac = ev->valuators.data_frac[i]; + (axisval + nvals)->integral = ev->valuators.data_raw[i]; + (axisval + nvals)->frac = ev->valuators.data_raw_frac[i]; + axisval++; + } + } + + return Success; +} + +/** + * Return the corresponding core type for the given event or 0 if no core + * equivalent exists. + */ +int +GetCoreType(InternalEvent *event) +{ + int coretype = 0; + switch(event->any.type) + { + case ET_Motion: coretype = MotionNotify; break; + case ET_ButtonPress: coretype = ButtonPress; break; + case ET_ButtonRelease: coretype = ButtonRelease; break; + case ET_KeyPress: coretype = KeyPress; break; + case ET_KeyRelease: coretype = KeyRelease; break; + default: + break; + } + return coretype; +} + +/** + * Return the corresponding XI 1.x type for the given event or 0 if no + * equivalent exists. + */ +int +GetXIType(InternalEvent *event) +{ + int xitype = 0; + switch(event->any.type) + { + case ET_Motion: xitype = DeviceMotionNotify; break; + case ET_ButtonPress: xitype = DeviceButtonPress; break; + case ET_ButtonRelease: xitype = DeviceButtonRelease; break; + case ET_KeyPress: xitype = DeviceKeyPress; break; + case ET_KeyRelease: xitype = DeviceKeyRelease; break; + case ET_ProximityIn: xitype = ProximityIn; break; + case ET_ProximityOut: xitype = ProximityOut; break; + default: + break; + } + return xitype; +} + +/** + * Return the corresponding XI 2.x type for the given event or 0 if no + * equivalent exists. + */ +int +GetXI2Type(InternalEvent *event) +{ + int xi2type = 0; + + switch(event->any.type) + { + case ET_Motion: xi2type = XI_Motion; break; + case ET_ButtonPress: xi2type = XI_ButtonPress; break; + case ET_ButtonRelease: xi2type = XI_ButtonRelease; break; + case ET_KeyPress: xi2type = XI_KeyPress; break; + case ET_KeyRelease: xi2type = XI_KeyRelease; break; + case ET_Enter: xi2type = XI_Enter; break; + case ET_Leave: xi2type = XI_Leave; break; + case ET_Hierarchy: xi2type = XI_HierarchyChanged; break; + case ET_DeviceChanged: xi2type = XI_DeviceChanged; break; + case ET_RawKeyPress: xi2type = XI_RawKeyPress; break; + case ET_RawKeyRelease: xi2type = XI_RawKeyRelease; break; + case ET_RawButtonPress: xi2type = XI_RawButtonPress; break; + case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break; + case ET_RawMotion: xi2type = XI_RawMotion; break; + case ET_FocusIn: xi2type = XI_FocusIn; break; + case ET_FocusOut: xi2type = XI_FocusOut; break; + default: + break; + } + return xi2type; +} diff --git a/xorg-server/dix/events.c b/xorg-server/dix/events.c index f96fe1ce4..a537730a9 100644 --- a/xorg-server/dix/events.c +++ b/xorg-server/dix/events.c @@ -1,5912 +1,5912 @@ -/************************************************************ - -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, 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. - */ - -/** @file events.c - * This file handles event delivery and a big part of the server-side protocol - * handling (the parts for input devices). - */ - -#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" -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#include "globals.h" - -#include -#include "xkbsrv.h" -#include "xace.h" - -#ifdef XSERVER_DTRACE -#include -typedef const char *string; -#include "Xserver-dtrace.h" -#endif - -#include -#include -#include -#include -#include "exglobals.h" -#include "exevents.h" -#include "exglobals.h" -#include "extnsionst.h" - -#include "dixevents.h" -#include "dixgrabs.h" -#include "dispatch.h" - -#include -#include "geext.h" -#include "geint.h" - -#include "eventstr.h" -#include "enterleave.h" -#include "eventconvert.h" - -/* Extension events type numbering starts at EXTENSION_EVENT_BASE. */ -#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 LastEventMask OwnerGrabButtonMask -#define AllEventMasks (LastEventMask|(LastEventMask-1)) - - -#define CORE_EVENT(event) \ - (!((event)->u.u.type & EXTENSION_EVENT_BASE) && \ - (event)->u.u.type != GenericEvent) -#define XI2_EVENT(event) \ - (((event)->u.u.type == GenericEvent) && \ - ((xGenericEvent*)(event))->extension == IReqCode) - -/** - * Used to indicate a implicit passive grab created by a ButtonPress event. - * See DeliverEventsToWindow(). - */ -#define ImplicitGrabMask (1 << 7) - -#define WID(w) ((w) ? ((w)->drawable.id) : 0) - -#define XE_KBPTR (xE->u.keyButtonPointer) - - -#define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) - -CallbackListPtr EventCallback; -CallbackListPtr DeviceEventCallback; - -#define DNPMCOUNT 8 - -Mask DontPropagateMasks[DNPMCOUNT]; -static int DontPropagateRefCnts[DNPMCOUNT]; - -static void CheckVirtualMotion( DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin); -static void CheckPhysLimits(DeviceIntPtr pDev, - CursorPtr cursor, - Bool generateEvents, - Bool confineToScreen, - ScreenPtr pScreen); -static Bool CheckPassiveGrabsOnWindow(WindowPtr pWin, - DeviceIntPtr device, - DeviceEvent *event, - BOOL checkCore); - -/** Key repeat hack. Do not use but in TryClientEvents */ -extern BOOL EventIsKeyRepeat(xEvent *event); - -/** - * Main input device struct. - * inputInfo.pointer - * is the core pointer. Referred to as "virtual core pointer", "VCP", - * "core pointer" or inputInfo.pointer. The VCP is the first master - * pointer device and cannot be deleted. - * - * inputInfo.keyboard - * is the core keyboard ("virtual core keyboard", "VCK", "core keyboard"). - * See inputInfo.pointer. - * - * inputInfo.devices - * linked list containing all devices including VCP and VCK. - * - * inputInfo.off_devices - * Devices that have not been initialized and are thus turned off. - * - * inputInfo.numDevices - * Total number of devices. - * - * inputInfo.all_devices - * Virtual device used for XIAllDevices passive grabs. This device is - * not part of the inputInfo.devices list and mostly unset except for - * the deviceid. It exists because passivegrabs need a valid device - * reference. - * - * inputInfo.all_master_devices - * Virtual device used for XIAllMasterDevices passive grabs. This device - * is not part of the inputInfo.devices list and mostly unset except for - * the deviceid. It exists because passivegrabs need a valid device - * reference. - */ -InputInfo inputInfo; - -EventSyncInfoRec syncEvents; - -/** - * The root window the given device is currently on. - */ -#define RootWindow(dev) dev->spriteInfo->sprite->spriteTrace[0] - -static xEvent* swapEvent = NULL; -static int swapEventLen = 0; - -void -NotImplemented(xEvent *from, xEvent *to) -{ - FatalError("Not implemented"); -} - -/** - * Convert the given event type from an XI event to a core event. - * @param[in] The XI 1.x event type. - * @return The matching core event type or 0 if there is none. - */ -int -XItoCoreType(int xitype) -{ - int coretype = 0; - if (xitype == DeviceMotionNotify) - coretype = MotionNotify; - else if (xitype == DeviceButtonPress) - coretype = ButtonPress; - else if (xitype == DeviceButtonRelease) - coretype = ButtonRelease; - else if (xitype == DeviceKeyPress) - coretype = KeyPress; - else if (xitype == DeviceKeyRelease) - coretype = KeyRelease; - - return coretype; -} - -/** - * @return true if the device owns a cursor, false if device shares a cursor - * sprite with another device. - */ -Bool -DevHasCursor(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->spriteOwner; -} - -/* - * @return true if a device is a pointer, check is the same as used by XI to - * fill the 'use' field. - */ -Bool -IsPointerDevice(DeviceIntPtr dev) -{ - return (dev->type == MASTER_POINTER) || - (dev->valuator && dev->button) || - (dev->valuator && !dev->key); -} - -/* - * @return true if a device is a keyboard, check is the same as used by XI to - * fill the 'use' field. - * - * Some pointer devices have keys as well (e.g. multimedia keys). Try to not - * count them as keyboard devices. - */ -Bool -IsKeyboardDevice(DeviceIntPtr dev) -{ - return (dev->type == MASTER_KEYBOARD) || - ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev)); -} - -Bool -IsMaster(DeviceIntPtr dev) -{ - return (dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD); -} - -static WindowPtr XYToWindow( - DeviceIntPtr pDev, - int x, - int y -); - -/** - * Max event opcode. - */ -extern int lastEvent; - -extern int DeviceMotionNotify; - -#define CantBeFiltered NoEventMask -/** - * Event masks for each event type. - * - * One set of filters for each device, but only the first layer - * is initialized. The rest is memcpy'd in InitEvents. - * - * Filters are used whether a given event may be delivered to a client, - * usually in the form of if (window-event-mask & filter); then deliver event. - * - * One notable filter is for PointerMotion/DevicePointerMotion events. Each - * time a button is pressed, the filter is modified to also contain the - * matching ButtonXMotion mask. - */ -static Mask filters[MAXDEVICES][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 */ -}}; - -/** - * For the given event, return the matching event filter. This filter may then - * be AND'ed with the selected event mask. - * - * For XI2 events, the returned filter is simply the byte containing the event - * mask we're interested in. E.g. for a mask of (1 << 13), this would be - * byte[1]. - * - * @param[in] dev The device the event belongs to, may be NULL. - * @param[in] event The event to get the filter for. Only the type of the - * event matters, or the extension + evtype for GenericEvents. - * @return The filter mask for the given event. - * - * @see GetEventMask - */ -Mask -GetEventFilter(DeviceIntPtr dev, xEvent *event) -{ - if (event->u.u.type != GenericEvent) - return filters[dev ? dev->id : 0][event->u.u.type]; - else if (XI2_EVENT(event)) - return (1 << (((xXIDeviceEvent*)event)->evtype % 8)); - ErrorF("[dix] Unknown device type %d. No filter\n", event->u.u.type); - return 0; -} - -/** - * Return the windows complete XI2 mask for the given XI2 event type. - */ -Mask -GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev) -{ - OtherInputMasks *inputMasks = wOtherInputMasks(win); - int filter; - int evtype; - - if (!inputMasks || !XI2_EVENT(ev)) - return 0; - - evtype = ((xGenericEvent*)ev)->evtype; - filter = GetEventFilter(dev, ev); - - return ((inputMasks->xi2mask[dev->id][evtype/8] & filter) || - inputMasks->xi2mask[XIAllDevices][evtype/8] || - (inputMasks->xi2mask[XIAllMasterDevices][evtype/8] && IsMaster(dev))); -} - -static Mask -GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients* other) -{ - /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */ - if (XI2_EVENT(event)) - { - int byte = ((xGenericEvent*)event)->evtype / 8; - return (other->xi2mask[dev->id][byte] | - other->xi2mask[XIAllDevices][byte] | - (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0)); - } else if (CORE_EVENT(event)) - return other->mask[XIAllDevices]; - else - return other->mask[dev->id]; -} - - -static CARD8 criticalEvents[32] = -{ - 0x7c, 0x30, 0x40 /* key, button, expose, and configure events */ -}; - -static void -SyntheticMotion(DeviceIntPtr dev, int x, int y) { - int screenno = 0; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - screenno = dev->spriteInfo->sprite->screen->myNum; -#endif - PostSyntheticMotion(dev, x, y, screenno, - (syncEvents.playingEvents) ? syncEvents.time.milliseconds : currentTime.milliseconds); - -} - -#ifdef PANORAMIX -static void PostNewCursor(DeviceIntPtr pDev); - -static Bool -XineramaSetCursorPosition( - DeviceIntPtr pDev, - int x, - int y, - Bool generateEvent -){ - ScreenPtr pScreen; - BoxRec box; - int i; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - /* x,y are in Screen 0 coordinates. We need to decide what Screen - to send the message too and what the coordinates relative to - that screen are. */ - - pScreen = pSprite->screen; - x += panoramiXdataPtr[0].x; - y += panoramiXdataPtr[0].y; - - if(!POINT_IN_REGION(pScreen, &XineramaScreenRegions[pScreen->myNum], - x, y, &box)) - { - FOR_NSCREENS(i) - { - if(i == pScreen->myNum) - continue; - if(POINT_IN_REGION(pScreen, &XineramaScreenRegions[i], x, y, &box)) - { - pScreen = screenInfo.screens[i]; - break; - } - } - } - - pSprite->screen = pScreen; - pSprite->hotPhys.x = x - panoramiXdataPtr[0].x; - pSprite->hotPhys.y = y - panoramiXdataPtr[0].y; - x -= panoramiXdataPtr[pScreen->myNum].x; - y -= panoramiXdataPtr[pScreen->myNum].y; - - return (*pScreen->SetCursorPosition)(pDev, pScreen, x, y, generateEvent); -} - - -static void -XineramaConstrainCursor(DeviceIntPtr pDev) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - ScreenPtr pScreen; - BoxRec newBox; - - pScreen = pSprite->screen; - newBox = pSprite->physLimits; - - /* Translate the constraining box to the screen - the sprite is actually on */ - newBox.x1 += panoramiXdataPtr[0].x - panoramiXdataPtr[pScreen->myNum].x; - newBox.x2 += panoramiXdataPtr[0].x - panoramiXdataPtr[pScreen->myNum].x; - newBox.y1 += panoramiXdataPtr[0].y - panoramiXdataPtr[pScreen->myNum].y; - newBox.y2 += panoramiXdataPtr[0].y - panoramiXdataPtr[pScreen->myNum].y; - - (* pScreen->ConstrainCursor)(pDev, pScreen, &newBox); -} - - -static Bool -XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if(pWin == WindowTable[0]) { - memcpy(pSprite->windows, WindowTable, - PanoramiXNumScreens*sizeof(WindowPtr)); - } else { - PanoramiXRes *win; - int rc, i; - - rc = dixLookupResourceByType((pointer *)&win, pWin->drawable.id, - XRT_WINDOW, serverClient, DixReadAccess); - if (rc != Success) - return FALSE; - - for(i = 0; i < PanoramiXNumScreens; i++) { - rc = dixLookupWindow(pSprite->windows + i, win->info[i].id, - serverClient, DixReadAccess); - if (rc != Success) /* window is being unmapped */ - return FALSE; - } - } - return TRUE; -} - -static void -XineramaConfineCursorToWindow(DeviceIntPtr pDev, - WindowPtr pWin, - Bool generateEvents) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - int x, y, off_x, off_y, i; - - if(!XineramaSetWindowPntrs(pDev, pWin)) - return; - - i = PanoramiXNumScreens - 1; - - REGION_COPY(pSprite->screen, &pSprite->Reg1, - &pSprite->windows[i]->borderSize); - off_x = panoramiXdataPtr[i].x; - off_y = panoramiXdataPtr[i].y; - - while(i--) { - x = off_x - panoramiXdataPtr[i].x; - y = off_y - panoramiXdataPtr[i].y; - - if(x || y) - REGION_TRANSLATE(pSprite->screen, &pSprite->Reg1, x, y); - - REGION_UNION(pSprite->screen, &pSprite->Reg1, &pSprite->Reg1, - &pSprite->windows[i]->borderSize); - - off_x = panoramiXdataPtr[i].x; - off_y = panoramiXdataPtr[i].y; - } - - pSprite->hotLimits = *REGION_EXTENTS(pSprite->screen, &pSprite->Reg1); - - if(REGION_NUM_RECTS(&pSprite->Reg1) > 1) - pSprite->hotShape = &pSprite->Reg1; - else - pSprite->hotShape = NullRegion; - - pSprite->confined = FALSE; - pSprite->confineWin = (pWin == WindowTable[0]) ? NullWindow : pWin; - - CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL); -} - -#endif /* PANORAMIX */ - -/** - * Modifies the filter for the given protocol event type to the given masks. - * - * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent(). - * The latter initialises masks for the matching XI events, it's a once-off - * setting. - * UDS however changes the mask for MotionNotify and DeviceMotionNotify each - * time a button is pressed to include the matching ButtonXMotion mask in the - * filter. - * - * @param[in] deviceid The device to modify the filter for. - * @param[in] mask The new filter mask. - * @param[in] event Protocol event type. - */ -void -SetMaskForEvent(int deviceid, Mask mask, int event) -{ - if (deviceid < 0 || deviceid >= MAXDEVICES) - FatalError("SetMaskForEvent: bogus device id"); - filters[deviceid][event] = mask; -} - -void -SetCriticalEvent(int event) -{ - if (event >= 128) - FatalError("SetCriticalEvent: bogus event number"); - criticalEvents[event >> 3] |= 1 << (event & 7); -} - -void -ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py) -{ - BoxRec box; - int x = *px, y = *py; - int incx = 1, incy = 1; - SpritePtr pSprite; - - pSprite = pDev->spriteInfo->sprite; - if (POINT_IN_REGION(pSprite->hot.pScreen, shape, x, y, &box)) - return; - box = *REGION_EXTENTS(pSprite->hot.pScreen, 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(pSprite->hot.pScreen, shape, x, y, &box)); - *px = x; - *py = y; -} - -static void -CheckPhysLimits( - DeviceIntPtr pDev, - CursorPtr cursor, - Bool generateEvents, - Bool confineToScreen, /* unused if PanoramiX on */ - ScreenPtr pScreen) /* unused if PanoramiX on */ -{ - HotSpot new; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (!cursor) - return; - new = pSprite->hotPhys; -#ifdef PANORAMIX - if (!noPanoramiXExtension) - /* I don't care what the DDX has to say about it */ - pSprite->physLimits = pSprite->hotLimits; - else -#endif - { - if (pScreen) - new.pScreen = pScreen; - else - pScreen = new.pScreen; - (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits, - &pSprite->physLimits); - pSprite->confined = confineToScreen; - (* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits); - } - - /* constrain the pointer to those limits */ - if (new.x < pSprite->physLimits.x1) - new.x = pSprite->physLimits.x1; - else - if (new.x >= pSprite->physLimits.x2) - new.x = pSprite->physLimits.x2 - 1; - if (new.y < pSprite->physLimits.y1) - new.y = pSprite->physLimits.y1; - else - if (new.y >= pSprite->physLimits.y2) - new.y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y); - if (( -#ifdef PANORAMIX - noPanoramiXExtension && -#endif - (pScreen != pSprite->hotPhys.pScreen)) || - (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) - { -#ifdef PANORAMIX - if (!noPanoramiXExtension) - XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents); - else -#endif - { - if (pScreen != pSprite->hotPhys.pScreen) - pSprite->hotPhys = new; - (*pScreen->SetCursorPosition) - (pDev, pScreen, new.x, new.y, generateEvents); - } - if (!generateEvents) - SyntheticMotion(pDev, new.x, new.y); - } - -#ifdef PANORAMIX - /* Tell DDX what the limits are */ - if (!noPanoramiXExtension) - XineramaConstrainCursor(pDev); -#endif -} - -static void -CheckVirtualMotion( - DeviceIntPtr pDev, - QdEventPtr qe, - WindowPtr pWin) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - RegionPtr reg = NULL; - DeviceEvent *ev = NULL; - - if (qe) - { - ev = &qe->event->device_event; - switch(ev->type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - pSprite->hot.pScreen = qe->pScreen; - pSprite->hot.x = ev->root_x; - pSprite->hot.y = ev->root_y; - pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow; - break; - default: - break; - } - } - if (pWin) - { - BoxRec lims; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - int x, y, off_x, off_y, i; - - if(!XineramaSetWindowPntrs(pDev, pWin)) - return; - - i = PanoramiXNumScreens - 1; - - REGION_COPY(pSprite->screen, &pSprite->Reg2, - &pSprite->windows[i]->borderSize); - off_x = panoramiXdataPtr[i].x; - off_y = panoramiXdataPtr[i].y; - - while(i--) { - x = off_x - panoramiXdataPtr[i].x; - y = off_y - panoramiXdataPtr[i].y; - - if(x || y) - REGION_TRANSLATE(pSprite->screen, &pSprite->Reg2, x, y); - - REGION_UNION(pSprite->screen, &pSprite->Reg2, &pSprite->Reg2, - &pSprite->windows[i]->borderSize); - - off_x = panoramiXdataPtr[i].x; - off_y = panoramiXdataPtr[i].y; - } - } else -#endif - { - if (pSprite->hot.pScreen != pWin->drawable.pScreen) - { - pSprite->hot.pScreen = pWin->drawable.pScreen; - pSprite->hot.x = pSprite->hot.y = 0; - } - } - - lims = *REGION_EXTENTS(pWin->drawable.pScreen, &pWin->borderSize); - if (pSprite->hot.x < lims.x1) - pSprite->hot.x = lims.x1; - else if (pSprite->hot.x >= lims.x2) - pSprite->hot.x = lims.x2 - 1; - if (pSprite->hot.y < lims.y1) - pSprite->hot.y = lims.y1; - else if (pSprite->hot.y >= lims.y2) - pSprite->hot.y = lims.y2 - 1; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - if (REGION_NUM_RECTS(&pSprite->Reg2) > 1) - reg = &pSprite->Reg2; - - } else -#endif - { - if (wBoundingShape(pWin)) - reg = &pWin->borderSize; - } - - if (reg) - ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y); - - if (qe && ev) - { - qe->pScreen = pSprite->hot.pScreen; - ev->root_x = pSprite->hot.x; - ev->root_y = pSprite->hot.y; - } - } -#ifdef PANORAMIX - if (noPanoramiXExtension) /* No typo. Only set the root win if disabled */ -#endif - RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum]; -} - -static void -ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bool confineToScreen) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (syncEvents.playingEvents) - { - CheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin); - SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y); - } - else - { -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - XineramaConfineCursorToWindow(pDev, pWin, generateEvents); - return; - } -#endif - pSprite->hotLimits = *REGION_EXTENTS( pScreen, &pWin->borderSize); - pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize - : NullRegion; - CheckPhysLimits(pDev, pSprite->current, generateEvents, - confineToScreen, pScreen); - } -} - -Bool -PointerConfinedToScreen(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->sprite->confined; -} - -/** - * Update the sprite cursor to the given cursor. - * - * ChangeToCursor() will display the new cursor and free the old cursor (if - * applicable). If the provided cursor is already the updated cursor, nothing - * happens. - */ -static void -ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - ScreenPtr pScreen; - - if (cursor != pSprite->current) - { - if ((pSprite->current->bits->xhot != cursor->bits->xhot) || - (pSprite->current->bits->yhot != cursor->bits->yhot)) - CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined, - (ScreenPtr)NULL); -#ifdef PANORAMIX - /* XXX: is this really necessary?? (whot) */ - if (!noPanoramiXExtension) - pScreen = pSprite->screen; - else -#endif - pScreen = pSprite->hotPhys.pScreen; - - (*pScreen->DisplayCursor)(pDev, pScreen, cursor); - FreeCursor(pSprite->current, (Cursor)0); - pSprite->current = cursor; - pSprite->current->refcnt++; - } -} - -/** - * @returns true if b is a descendent of a - */ -Bool -IsParent(WindowPtr a, WindowPtr b) -{ - for (b = b->parent; b; b = b->parent) - if (b == a) return TRUE; - return FALSE; -} - -/** - * Update the cursor displayed on the screen. - * - * Called whenever a cursor may have changed shape or position. - */ -static void -PostNewCursor(DeviceIntPtr pDev) -{ - WindowPtr win; - GrabPtr grab = pDev->deviceGrab.grab; - SpritePtr pSprite = pDev->spriteInfo->sprite; - CursorPtr pCursor; - - if (syncEvents.playingEvents) - return; - if (grab) - { - if (grab->cursor) - { - ChangeToCursor(pDev, grab->cursor); - return; - } - if (IsParent(grab->window, pSprite->win)) - win = pSprite->win; - else - win = grab->window; - } - else - win = pSprite->win; - for (; win; win = win->parent) - { - if (win->optional) - { - pCursor = WindowGetDeviceCursor(win, pDev); - if (!pCursor && win->optional->cursor != NullCursor) - pCursor = win->optional->cursor; - if (pCursor) - { - ChangeToCursor(pDev, pCursor); - return; - } - } - } -} - - -/** - * @param dev device which you want to know its current root window - * @return root window where dev's sprite is located - */ -WindowPtr -GetCurrentRootWindow(DeviceIntPtr dev) -{ - return RootWindow(dev); -} - -/** - * @return window underneath the cursor sprite. - */ -WindowPtr -GetSpriteWindow(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->sprite->win; -} - -/** - * @return current sprite cursor. - */ -CursorPtr -GetSpriteCursor(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->sprite->current; -} - -/** - * Set x/y current sprite position in screen coordinates. - */ -void -GetSpritePosition(DeviceIntPtr pDev, int *px, int *py) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - *px = pSprite->hotPhys.x; - *py = pSprite->hotPhys.y; -} - -#ifdef PANORAMIX -int -XineramaGetCursorScreen(DeviceIntPtr pDev) -{ - if(!noPanoramiXExtension) { - return pDev->spriteInfo->sprite->screen->myNum; - } else { - return 0; - } -} -#endif /* PANORAMIX */ - -#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ - -static void -MonthChangedOrBadTime(InternalEvent *ev) -{ - /* 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 - ev->any.time) > TIMESLOP) - currentTime.months++; - else - ev->any.time = currentTime.milliseconds; -} - -static void -NoticeTime(InternalEvent *ev) -{ - if (ev->any.time < currentTime.milliseconds) - MonthChangedOrBadTime(ev); - currentTime.milliseconds = ev->any.time; - lastDeviceEventTime = currentTime; -} - -void -NoticeEventTime(InternalEvent *ev) -{ - if (!syncEvents.playingEvents) - NoticeTime(ev); -} - -/************************************************************************** - * The following procedures deal with synchronous events * - **************************************************************************/ - -/** - * EnqueueEvent is a device's processInputProc if a device is frozen. - * Instead of delivering the events to the client, the event is tacked onto a - * linked list for later delivery. - */ -void -EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) -{ - QdEventPtr tail = *syncEvents.pendtail; - QdEventPtr qe; - SpritePtr pSprite = device->spriteInfo->sprite; - int eventlen; - DeviceEvent *event = &ev->device_event; - - NoticeTime((InternalEvent*)event); - - /* Fix for key repeating bug. */ - if (device->key != NULL && device->key->xkbInfo != NULL && - event->type == ET_KeyRelease) - AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key); - - 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 (ev->any.type == ET_Motion) - ev->device_event.root = WindowTable[pSprite->hotPhys.pScreen->myNum]->drawable.id; - - eventinfo.event = ev; - eventinfo.device = device; - CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); - } - - if (event->type == ET_Motion) - { -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - event->root_x += panoramiXdataPtr[pSprite->screen->myNum].x - - panoramiXdataPtr[0].x; - event->root_y += panoramiXdataPtr[pSprite->screen->myNum].y - - panoramiXdataPtr[0].y; - } -#endif - pSprite->hotPhys.x = event->root_x; - pSprite->hotPhys.y = event->root_y; - /* do motion compression, but not if from different devices */ - if (tail && - (tail->event->any.type == ET_Motion) && - (tail->device == device) && - (tail->pScreen == pSprite->hotPhys.pScreen)) - { - DeviceEvent *tailev = &tail->event->device_event; - tailev->root_x = pSprite->hotPhys.x; - tailev->root_y = pSprite->hotPhys.y; - tailev->time = event->time; - tail->months = currentTime.months; - return; - } - } - - eventlen = event->length; - - qe = xalloc(sizeof(QdEventRec) + eventlen); - if (!qe) - return; - qe->next = (QdEventPtr)NULL; - qe->device = device; - qe->pScreen = pSprite->hotPhys.pScreen; - qe->months = currentTime.months; - qe->event = (InternalEvent *)(qe + 1); - memcpy(qe->event, event, eventlen); - if (tail) - syncEvents.pendtail = &tail->next; - *syncEvents.pendtail = qe; -} - -/** - * Run through the list of events queued up in syncEvents. - * For each event do: - * If the device for this event is not frozen anymore, take it and process it - * as usually. - * After that, check if there's any devices in the list that are not frozen. - * If there is none, we're done. If there is at least one device that is not - * frozen, then re-run from the beginning of the event queue. - */ -static void -PlayReleasedEvents(void) -{ - QdEventPtr *prev, qe; - DeviceIntPtr dev; - DeviceIntPtr pDev; - - prev = &syncEvents.pending; - while ( (qe = *prev) ) - { - if (!qe->device->deviceGrab.sync.frozen) - { - *prev = qe->next; - pDev = qe->device; - if (*syncEvents.pendtail == *prev) - syncEvents.pendtail = prev; - if (qe->event->any.type == ET_Motion) - CheckVirtualMotion(pDev, qe, NullWindow); - syncEvents.time.months = qe->months; - syncEvents.time.milliseconds = qe->event->any.time; -#ifdef PANORAMIX - /* Translate back to the sprite screen since processInputProc - will translate from sprite screen to screen 0 upon reentry - to the DIX layer */ - if(!noPanoramiXExtension) { - DeviceEvent *ev = &qe->event->device_event; - switch(ev->type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - ev->root_x += panoramiXdataPtr[0].x - - panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].x; - ev->root_y += panoramiXdataPtr[0].y - - panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].y; - break; - default: - break; - } - - } -#endif - (*qe->device->public.processInputProc)(qe->event, qe->device); - xfree(qe); - for (dev = inputInfo.devices; dev && dev->deviceGrab.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; - } -} - -/** - * Freeze or thaw the given devices. The device's processing proc is - * switched to either the real processing proc (in case of thawing) or an - * enqueuing processing proc (usually EnqueueEvent()). - * - * @param dev The device to freeze/thaw - * @param frozen True to freeze or false to thaw. - */ -static void -FreezeThaw(DeviceIntPtr dev, Bool frozen) -{ - dev->deviceGrab.sync.frozen = frozen; - if (frozen) - dev->public.processInputProc = dev->public.enqueueInputProc; - else - dev->public.processInputProc = dev->public.realInputProc; -} - -/** - * Unfreeze devices and replay all events to the respective clients. - * - * ComputeFreezes takes the first event in the device's frozen event queue. It - * runs up the sprite tree (spriteTrace) and searches for the window to replay - * the events from. If it is found, it checks for passive grabs one down from - * the window or delivers the events. - */ -static void -ComputeFreezes(void) -{ - DeviceIntPtr replayDev = syncEvents.replayDev; - int i; - WindowPtr w; - GrabPtr grab; - DeviceIntPtr dev; - - for (dev = inputInfo.devices; dev; dev = dev->next) - FreezeThaw(dev, dev->deviceGrab.sync.other || - (dev->deviceGrab.sync.state >= FROZEN)); - if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending)) - return; - syncEvents.playingEvents = TRUE; - if (replayDev) - { - DeviceEvent* event = replayDev->deviceGrab.sync.event; - - syncEvents.replayDev = (DeviceIntPtr)NULL; - - w = XYToWindow(replayDev, event->root_x, event->root_y); - for (i = 0; i < replayDev->spriteInfo->sprite->spriteTraceGood; i++) - { - if (syncEvents.replayWin == - replayDev->spriteInfo->sprite->spriteTrace[i]) - { - if (!CheckDeviceGrabs(replayDev, event, i+1)) { - if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) - DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); - else - DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, - NullWindow, replayDev); - } - goto playmore; - } - } - /* must not still be in the same stack */ - if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) - DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); - else - DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, - NullWindow, replayDev); - } -playmore: - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (!dev->deviceGrab.sync.frozen) - { - PlayReleasedEvents(); - break; - } - } - syncEvents.playingEvents = FALSE; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (DevHasCursor(dev)) - { - /* the following may have been skipped during replay, - so do it now */ - if ((grab = dev->deviceGrab.grab) && grab->confineTo) - { - if (grab->confineTo->drawable.pScreen != - dev->spriteInfo->sprite->hotPhys.pScreen) - dev->spriteInfo->sprite->hotPhys.x = - dev->spriteInfo->sprite->hotPhys.y = 0; - ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE); - } - else - ConfineCursorToWindow(dev, - WindowTable[dev->spriteInfo->sprite->hotPhys.pScreen->myNum], - TRUE, FALSE); - PostNewCursor(dev); - } - } -} - -#ifdef RANDR -void -ScreenRestructured (ScreenPtr pScreen) -{ - GrabPtr grab; - DeviceIntPtr pDev; - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (!DevHasCursor(pDev)) - continue; - - /* GrabDevice doesn't have a confineTo field, so we don't need to - * worry about it. */ - if ((grab = pDev->deviceGrab.grab) && grab->confineTo) - { - if (grab->confineTo->drawable.pScreen - != pDev->spriteInfo->sprite->hotPhys.pScreen) - pDev->spriteInfo->sprite->hotPhys.x = pDev->spriteInfo->sprite->hotPhys.y = 0; - ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); - } - else - ConfineCursorToWindow(pDev, - WindowTable[pDev->spriteInfo->sprite->hotPhys.pScreen->myNum], - TRUE, FALSE); - } -} -#endif - -static void -CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) -{ - GrabPtr grab = thisDev->deviceGrab.grab; - DeviceIntPtr dev; - - if (thisMode == GrabModeSync) - thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT; - else - { /* free both if same client owns both */ - thisDev->deviceGrab.sync.state = THAWED; - if (thisDev->deviceGrab.sync.other && - (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) == - CLIENT_BITS(grab->resource))) - thisDev->deviceGrab.sync.other = NullGrab; - } - - if (IsMaster(thisDev)) - { - dev = GetPairedDevice(thisDev); - if (otherMode == GrabModeSync) - dev->deviceGrab.sync.other = grab; - else - { /* free both if same client owns both */ - if (dev->deviceGrab.sync.other && - (CLIENT_BITS(dev->deviceGrab.sync.other->resource) == - CLIENT_BITS(grab->resource))) - dev->deviceGrab.sync.other = NullGrab; - } - } - ComputeFreezes(); -} - -/** - * Save the device's master device id. This needs to be done - * if a client directly grabs a slave device that is attached to a master. For - * the duration of the grab, the device is detached, ungrabbing re-attaches it - * though. - * - * We store the ID of the master device only in case the master disappears - * while the device has a grab. - */ -static void -DetachFromMaster(DeviceIntPtr dev) -{ - if (!dev->u.master) - return; - - dev->saved_master_id = dev->u.master->id; - - AttachDevice(NULL, dev, NULL); -} - -static void -ReattachToOldMaster(DeviceIntPtr dev) -{ - DeviceIntPtr master = NULL; - - if (IsMaster(dev)) - return; - - dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess); - - if (master) - { - AttachDevice(serverClient, dev, master); - dev->saved_master_id = 0; - } -} - -/** - * Activate a pointer grab on the given device. A pointer grab will cause all - * core pointer events of this device to be delivered to the grabbing client only. - * No other device will send core events to the grab client while the grab is - * on, but core events will be sent to other clients. - * Can cause the cursor to change if a grab cursor is set. - * - * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab - * is an implicit grab caused by a ButtonPress event. - * - * @param mouse The device to grab. - * @param grab The grab structure, needs to be setup. - * @param autoGrab True if the grab was caused by a button down event and not - * explicitely by a client. - */ -void -ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, - TimeStamp time, Bool autoGrab) -{ - GrabInfoPtr grabinfo = &mouse->deviceGrab; - WindowPtr oldWin = (grabinfo->grab) ? - grabinfo->grab->window - : mouse->spriteInfo->sprite->win; - Bool isPassive = autoGrab & ~ImplicitGrabMask; - - /* slave devices need to float for the duration of the grab. */ - if (grab->grabtype == GRABTYPE_XI2 && - !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse)) - DetachFromMaster(mouse); - - if (grab->confineTo) - { - if (grab->confineTo->drawable.pScreen - != mouse->spriteInfo->sprite->hotPhys.pScreen) - mouse->spriteInfo->sprite->hotPhys.x = - mouse->spriteInfo->sprite->hotPhys.y = 0; - ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE); - } - DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab); - mouse->valuator->motionHintWindow = NullWindow; - if (syncEvents.playingEvents) - grabinfo->grabTime = syncEvents.time; - else - grabinfo->grabTime = time; - if (grab->cursor) - grab->cursor->refcnt++; - grabinfo->activeGrab = *grab; - grabinfo->grab = &grabinfo->activeGrab; - grabinfo->fromPassiveGrab = isPassive; - grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; - PostNewCursor(mouse); - CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode); -} - -/** - * Delete grab on given device, update the sprite. - * - * Extension devices are set up for ActivateKeyboardGrab(). - */ -void -DeactivatePointerGrab(DeviceIntPtr mouse) -{ - GrabPtr grab = mouse->deviceGrab.grab; - DeviceIntPtr dev; - Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab && - mouse->deviceGrab.implicitGrab); - - mouse->valuator->motionHintWindow = NullWindow; - mouse->deviceGrab.grab = NullGrab; - mouse->deviceGrab.sync.state = NOT_GRABBED; - mouse->deviceGrab.fromPassiveGrab = FALSE; - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->deviceGrab.sync.other == grab) - dev->deviceGrab.sync.other = NullGrab; - } - DoEnterLeaveEvents(mouse, mouse->id, grab->window, - mouse->spriteInfo->sprite->win, NotifyUngrab); - if (grab->confineTo) - ConfineCursorToWindow(mouse, RootWindow(mouse), FALSE, FALSE); - PostNewCursor(mouse); - if (grab->cursor) - FreeCursor(grab->cursor, (Cursor)0); - - if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) - ReattachToOldMaster(mouse); - - ComputeFreezes(); -} - -/** - * Activate a keyboard grab on the given device. - * - * Extension devices have ActivateKeyboardGrab() set as their grabbing proc. - */ -void -ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool passive) -{ - GrabInfoPtr grabinfo = &keybd->deviceGrab; - WindowPtr oldWin; - - /* slave devices need to float for the duration of the grab. */ - if (grab->grabtype == GRABTYPE_XI2 && - !(passive & ImplicitGrabMask) && - !IsMaster(keybd)) - DetachFromMaster(keybd); - - if (grabinfo->grab) - oldWin = grabinfo->grab->window; - else if (keybd->focus) - oldWin = keybd->focus->win; - else - oldWin = keybd->spriteInfo->sprite->win; - if (oldWin == FollowKeyboardWin) - oldWin = keybd->focus->win; - if (keybd->valuator) - keybd->valuator->motionHintWindow = NullWindow; - DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab); - if (syncEvents.playingEvents) - grabinfo->grabTime = syncEvents.time; - else - grabinfo->grabTime = time; - grabinfo->activeGrab = *grab; - grabinfo->grab = &grabinfo->activeGrab; - grabinfo->fromPassiveGrab = passive; - grabinfo->implicitGrab = passive & ImplicitGrabMask; - CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode); -} - -/** - * Delete keyboard grab for the given device. - */ -void -DeactivateKeyboardGrab(DeviceIntPtr keybd) -{ - GrabPtr grab = keybd->deviceGrab.grab; - DeviceIntPtr dev; - WindowPtr focusWin = keybd->focus ? keybd->focus->win - : keybd->spriteInfo->sprite->win; - Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab && - keybd->deviceGrab.implicitGrab); - - if (focusWin == FollowKeyboardWin) - focusWin = inputInfo.keyboard->focus->win; - if (keybd->valuator) - keybd->valuator->motionHintWindow = NullWindow; - keybd->deviceGrab.grab = NullGrab; - keybd->deviceGrab.sync.state = NOT_GRABBED; - keybd->deviceGrab.fromPassiveGrab = FALSE; - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->deviceGrab.sync.other == grab) - dev->deviceGrab.sync.other = NullGrab; - } - DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab); - - if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) - ReattachToOldMaster(keybd); - - ComputeFreezes(); -} - -void -AllowSome(ClientPtr client, - TimeStamp time, - DeviceIntPtr thisDev, - int newState) -{ - Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced; - TimeStamp grabTime; - DeviceIntPtr dev; - GrabInfoPtr devgrabinfo, - grabinfo = &thisDev->deviceGrab; - - thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client); - thisSynced = FALSE; - otherGrabbed = FALSE; - othersFrozen = FALSE; - grabTime = grabinfo->grabTime; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - devgrabinfo = &dev->deviceGrab; - - if (dev == thisDev) - continue; - if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client)) - { - if (!(thisGrabbed || otherGrabbed) || - (CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER)) - grabTime = devgrabinfo->grabTime; - otherGrabbed = TRUE; - if (grabinfo->sync.other == devgrabinfo->grab) - thisSynced = TRUE; - if (devgrabinfo->sync.state >= FROZEN) - othersFrozen = TRUE; - } - } - if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced)) - return; - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, grabTime) == EARLIER)) - return; - switch (newState) - { - case THAWED: /* Async */ - if (thisGrabbed) - grabinfo->sync.state = THAWED; - if (thisSynced) - grabinfo->sync.other = NullGrab; - ComputeFreezes(); - break; - case FREEZE_NEXT_EVENT: /* Sync */ - if (thisGrabbed) - { - grabinfo->sync.state = FREEZE_NEXT_EVENT; - if (thisSynced) - grabinfo->sync.other = NullGrab; - ComputeFreezes(); - } - break; - case THAWED_BOTH: /* AsyncBoth */ - if (othersFrozen) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - devgrabinfo = &dev->deviceGrab; - if (devgrabinfo->grab - && SameClient(devgrabinfo->grab, client)) - devgrabinfo->sync.state = THAWED; - if (devgrabinfo->sync.other && - SameClient(devgrabinfo->sync.other, client)) - devgrabinfo->sync.other = NullGrab; - } - ComputeFreezes(); - } - break; - case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */ - if (othersFrozen) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - devgrabinfo = &dev->deviceGrab; - if (devgrabinfo->grab - && SameClient(devgrabinfo->grab, client)) - devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT; - if (devgrabinfo->sync.other - && SameClient(devgrabinfo->sync.other, client)) - devgrabinfo->sync.other = NullGrab; - } - ComputeFreezes(); - } - break; - case NOT_GRABBED: /* Replay */ - if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT) - { - if (thisSynced) - grabinfo->sync.other = NullGrab; - syncEvents.replayDev = thisDev; - syncEvents.replayWin = grabinfo->grab->window; - (*grabinfo->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; - devgrabinfo = &dev->deviceGrab; - if (devgrabinfo->grab - && SameClient(devgrabinfo->grab, client)) - devgrabinfo->sync.state = THAWED; - if (devgrabinfo->sync.other - && SameClient(devgrabinfo->sync.other, client)) - devgrabinfo->sync.other = NullGrab; - } - ComputeFreezes(); - } - break; - } -} - -/** - * Server-side protocol handling for AllowEvents request. - * - * Release some events from a frozen device. - */ -int -ProcAllowEvents(ClientPtr client) -{ - TimeStamp time; - DeviceIntPtr mouse = NULL; - DeviceIntPtr keybd = NULL; - REQUEST(xAllowEventsReq); - - REQUEST_SIZE_MATCH(xAllowEventsReq); - time = ClientTimeToServerTime(stuff->time); - - mouse = PickPointer(client); - keybd = PickKeyboard(client); - - 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; -} - -/** - * Deactivate grabs from any device that has been grabbed by the client. - */ -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->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) - { - (*dev->deviceGrab.DeactivateGrab)(dev); - done = FALSE; - } - } - } while (!done); -} - -/************************************************************************** - * The following procedures deal with delivering events * - **************************************************************************/ - -/** - * Deliver the given events to the given client. - * - * More than one event may be delivered at a time. This is the case with - * DeviceMotionNotifies which may be followed by DeviceValuator events. - * - * TryClientEvents() is the last station before actually writing the events to - * the socket. Anything that is not filtered here, will get delivered to the - * client. - * An event is only delivered if - * - mask and filter match up. - * - no other client has a grab on the device that caused the event. - * - * - * @param client The target client to deliver to. - * @param dev The device the event came from. May be NULL. - * @param pEvents The events to be delivered. - * @param count Number of elements in pEvents. - * @param mask Event mask as set by the window. - * @param filter Mask based on event type. - * @param grab Possible grab on the device that caused the event. - * - * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the - * client. - */ -int -TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, - int count, Mask mask, Mask filter, GrabPtr grab) -{ - int i; - int type; - -#ifdef DEBUG_EVENTS - ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s", - pEvents->u.u.type, pEvents->u.u.detail, mask, - client ? client->index : -1, - (client && client->clientGone) ? " (gone)" : ""); -#endif - - if (!client || client == serverClient || client->clientGone) { -#ifdef DEBUG_EVENTS - ErrorF(" not delivered to fake/dead client\n"); -#endif - return 0; - } - - if (filter != CantBeFiltered && !(mask & filter)) - { - #ifdef DEBUG_EVENTS - ErrorF(" filtered\n"); - #endif - return 0; - } - - if (grab && !SameClient(grab, client)) - { -#ifdef DEBUG_EVENTS - ErrorF(" not delivered due to grab\n"); -#endif - return -1; /* don't send, but notify caller */ - } - - type = pEvents->u.u.type; - if (type == MotionNotify) - { - if (mask & PointerMotionHintMask) - { - if (WID(dev->valuator->motionHintWindow) == - pEvents->u.keyButtonPointer.event) - { -#ifdef DEBUG_EVENTS - ErrorF("[dix] \n"); - ErrorF("[dix] 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; - } - } - else if (type == DeviceMotionNotify) - { - if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer*)pEvents, - mask) != 0) - return 1; - } else if (type == KeyPress) - { - if (EventIsKeyRepeat(pEvents)) - { - if (!_XkbWantsDetectableAutoRepeat(client)) - { - xEvent release = *pEvents; - release.u.u.type = KeyRelease; - release.u.u.sequenceNumber = client->sequence; - WriteEventsToClient(client, 1, &release); -#ifdef DEBUG_EVENTS - ErrorF(" (plus fake core release for repeat)"); -#endif - } else - { -#ifdef DEBUG_EVENTS - ErrorF(" (detectable autorepeat for core)"); -#endif - } - } - - } else if (type == DeviceKeyPress) - { - if (EventIsKeyRepeat(pEvents)) - { - if (!_XkbWantsDetectableAutoRepeat(client)) - { - deviceKeyButtonPointer release = *(deviceKeyButtonPointer *)pEvents; - release.type = DeviceKeyRelease; - release.sequenceNumber = client->sequence; -#ifdef DEBUG_EVENTS - ErrorF(" (plus fake xi1 release for repeat)"); -#endif - WriteEventsToClient(client, 1, (xEvent *) &release); - } - else { -#ifdef DEBUG_EVENTS - ErrorF(" (detectable autorepeat for core)"); -#endif - } - } - } - - 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)) - { - if (client->smart_priority < SMART_MAX_PRIORITY) - client->smart_priority++; - SetCriticalOutputPending(); - } - - WriteEventsToClient(client, count, pEvents); -#ifdef DEBUG_EVENTS - ErrorF("[dix] delivered\n"); -#endif - return 1; -} - -/** - * Deliver events to a window. At this point, we do not yet know if the event - * actually needs to be delivered. May activate a grab if the event is a - * button press. - * - * Core events are always delivered to the window owner. If the filter is - * something other than CantBeFiltered, the event is also delivered to other - * clients with the matching mask on the window. - * - * More than one event may be delivered at a time. This is the case with - * DeviceMotionNotifies which may be followed by DeviceValuator events. - * - * @param pWin The window that would get the event. - * @param pEvents The events to be delivered. - * @param count Number of elements in pEvents. - * @param filter Mask based on event type. - * @param grab Possible grab on the device that caused the event. - * - * @return Number of events delivered to various clients. - */ -int -DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent - *pEvents, int count, Mask filter, GrabPtr grab) -{ - 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; - - - /* Deliver to window owner */ - if ((filter == CantBeFiltered) || CORE_EVENT(pEvents)) - { - /* if nobody ever wants to see this event, skip some work */ - if (filter != CantBeFiltered && - !((wOtherEventMasks(pWin)|pWin->eventMask) & filter)) - return 0; - - if (IsInterferingGrab(wClient(pWin), pDev, pEvents)) - return 0; - - if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) - /* do nothing */; - else if ( (attempt = TryClientEvents(wClient(pWin), pDev, pEvents, - count, pWin->eventMask, - filter, grab)) ) - { - if (attempt > 0) - { - deliveries++; - client = wClient(pWin); - deliveryMask = pWin->eventMask; - } else - nondeliveries--; - } - } - - /* CantBeFiltered means only window owner gets the event */ - if (filter != CantBeFiltered) - { - if (CORE_EVENT(pEvents)) - other = (InputClients *)wOtherClients(pWin); - else if (XI2_EVENT(pEvents)) - { - OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - /* Has any client selected for the event? */ - if (!GetWindowXI2Mask(pDev, pWin, pEvents)) - return 0; - other = inputMasks->inputClients; - } else { - OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - /* Has any client selected for the event? */ - if (!inputMasks || - !(inputMasks->inputEvents[pDev->id] & filter)) - return 0; - - other = inputMasks->inputClients; - } - - for (; other; other = other->next) - { - Mask mask; - if (IsInterferingGrab(rClient(other), pDev, pEvents)) - continue; - - mask = GetEventMask(pDev, pEvents, other); - - if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, - pEvents, count)) - /* do nothing */; - else if ( (attempt = TryClientEvents(rClient(other), pDev, - pEvents, count, - mask, filter, grab)) ) - { - if (attempt > 0) - { - deliveries++; - client = rClient(other); - deliveryMask = mask; - } else - nondeliveries--; - } - } - } - /* - * Note that since core events are delivered first, an implicit grab may - * be activated on a core grab, stopping the XI events. - */ - if ((type == DeviceButtonPress || type == ButtonPress || - ((XI2_EVENT(pEvents) && ((xGenericEvent*)pEvents)->evtype == XI_ButtonPress))) - && deliveries - && (!grab)) - { - GrabRec tempGrab; - OtherInputMasks *inputMasks; - - memset(&tempGrab, 0, sizeof(GrabRec)); - tempGrab.next = NULL; - tempGrab.device = pDev; - 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; - tempGrab.type = type; - if (type == ButtonPress) - tempGrab.grabtype = GRABTYPE_CORE; - else if (type == DeviceButtonPress) - tempGrab.grabtype = GRABTYPE_XI; - else - { - tempGrab.type = ((xGenericEvent*)pEvents)->evtype; - tempGrab.grabtype = GRABTYPE_XI2; - } - - /* get the XI and XI2 device mask */ - inputMasks = wOtherInputMasks(pWin); - tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[pDev->id]: 0; - - if (inputMasks) - memcpy(tempGrab.xi2mask, inputMasks->xi2mask, - sizeof(tempGrab.xi2mask)); - - (*pDev->deviceGrab.ActivateGrab)(pDev, &tempGrab, - currentTime, TRUE | ImplicitGrabMask); - } - else if ((type == MotionNotify) && deliveries) - pDev->valuator->motionHintWindow = pWin; - else - { - if ((type == DeviceMotionNotify || type == DeviceButtonPress) && - deliveries) - CheckDeviceGrabAndHintWindow (pWin, type, - (deviceKeyButtonPointer*) pEvents, - grab, client, deliveryMask); - } - 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. -*/ - -#ifdef PANORAMIX -static int -XineramaTryClientEventsResult( - ClientPtr client, - GrabPtr grab, - Mask mask, - Mask filter -){ - if ((client) && (client != serverClient) && (!client->clientGone) && - ((filter == CantBeFiltered) || (mask & filter))) - { - if (grab && !SameClient(grab, client)) return -1; - else return 1; - } - return 0; -} -#endif - -/** - * Try to deliver events to the interested parties. - * - * @param pWin The window that would get the event. - * @param pEvents The events to be delivered. - * @param count Number of elements in pEvents. - * @param filter Mask based on event type. - * @param dontClient Don't deliver to the dontClient. - */ -int -MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents, - int count, Mask filter, ClientPtr dontClient) -{ - OtherClients *other; - - - if (pWin->eventMask & filter) - { - if (wClient(pWin) == dontClient) - return 0; -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) - return XineramaTryClientEventsResult( - wClient(pWin), NullGrab, pWin->eventMask, filter); -#endif - if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) - return 1; /* don't send, but pretend we did */ - return TryClientEvents(wClient(pWin), NULL, pEvents, count, - pWin->eventMask, filter, NullGrab); - } - for (other = wOtherClients(pWin); other; other = other->next) - { - if (other->mask & filter) - { - if (SameClient(other, dontClient)) - return 0; -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) - return XineramaTryClientEventsResult( - rClient(other), NullGrab, other->mask, filter); -#endif - if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, pEvents, - count)) - return 1; /* don't send, but pretend we did */ - return TryClientEvents(rClient(other), NULL, pEvents, count, - other->mask, filter, NullGrab); - } - } - return 2; -} - -static Window FindChildForEvent(DeviceIntPtr dev, WindowPtr event) -{ - SpritePtr pSprite = dev->spriteInfo->sprite; - WindowPtr w = pSprite->spriteTrace[pSprite->spriteTraceGood-1]; - Window child = None; - - /* 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 == event) - { - child = None; - break; - } - - if (w->parent == event) - { - child = w->drawable.id; - break; - } - w = w->parent; - } - return child; -} - -/** - * Adjust event fields to comply with the window properties. - * - * @param xE Event to be modified in place - * @param pWin The window to get the information from. - * @param child Child window setting for event (if applicable) - * @param calcChild If True, calculate the child window. - */ -void -FixUpEventFromWindow( - DeviceIntPtr pDev, - xEvent *xE, - WindowPtr pWin, - Window child, - Bool calcChild) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (calcChild) - child = FindChildForEvent(pDev, pWin); - - if (XI2_EVENT(xE)) - { - xXIDeviceEvent* event = (xXIDeviceEvent*)xE; - - if (event->evtype == XI_RawKeyPress || - event->evtype == XI_RawKeyRelease || - event->evtype == XI_RawButtonPress || - event->evtype == XI_RawButtonRelease || - event->evtype == XI_RawMotion || - event->evtype == XI_DeviceChanged || - event->evtype == XI_HierarchyChanged || - event->evtype == XI_PropertyEvent) - return; - - event->root = RootWindow(pDev)->drawable.id; - event->event = pWin->drawable.id; - if (pSprite->hot.pScreen == pWin->drawable.pScreen) - { - event->event_x = event->root_x - FP1616(pWin->drawable.x, 0); - event->event_y = event->root_y - FP1616(pWin->drawable.y, 0); - event->child = child; - } else - { - event->event_x = 0; - event->event_y = 0; - event->child = None; - } - - if (event->evtype == XI_Enter || event->evtype == XI_Leave || - event->evtype == XI_FocusIn || event->evtype == XI_FocusOut) - ((xXIEnterEvent*)event)->same_screen = - (pSprite->hot.pScreen == pWin->drawable.pScreen); - - } else - { - XE_KBPTR.root = RootWindow(pDev)->drawable.id; - XE_KBPTR.event = pWin->drawable.id; - if (pSprite->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; - } - } -} - -/** - * Return masks for EventIsDeliverable. - * @defgroup EventIsDeliverable return flags - * @{ - */ -#define XI_MASK (1 << 0) /**< XI mask set on window */ -#define CORE_MASK (1 << 1) /**< Core mask set on window */ -#define DONT_PROPAGATE_MASK (1 << 2) /**< DontPropagate mask set on window */ -#define XI2_MASK (1 << 3) /**< XI2 mask set on window */ -/* @} */ - -/** - * Check if a given event is deliverable at all on a given window. - * - * This function only checks if any client wants it, not for a specific - * client. - * - * @param[in] dev The device this event is being sent for. - * @param[in] event The event that is to be sent. - * @param[in] win The current event window. - * - * @return Bitmask of ::XI2_MASK, ::XI_MASK, ::CORE_MASK, and - * ::DONT_PROPAGATE_MASK. - */ -static int -EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win) -{ - int rc = 0; - int filter = 0; - int type; - OtherInputMasks *inputMasks = wOtherInputMasks(win); - xEvent ev; - - /* XXX: this makes me gag */ - type = GetXI2Type(event); - ev.u.u.type = GenericEvent; /* GetEventFilter only cares about type and evtype*/ - ((xGenericEvent*)&ev)->extension = IReqCode; - ((xGenericEvent*)&ev)->evtype = type; - filter = GetEventFilter(dev, &ev); - if (type && inputMasks && - ((inputMasks->xi2mask[XIAllDevices][type/8] & filter) || - ((inputMasks->xi2mask[XIAllMasterDevices][type/8] & filter) && IsMaster(dev)) || - (inputMasks->xi2mask[dev->id][type/8] & filter))) - rc |= XI2_MASK; - - type = GetXIType(event); - ev.u.u.type = type; - filter = GetEventFilter(dev, &ev); - - /* Check for XI mask */ - if (type && inputMasks && - (inputMasks->deliverableEvents[dev->id] & filter) && - (inputMasks->inputEvents[dev->id] & filter)) - rc |= XI_MASK; - - /* Check for XI DontPropagate mask */ - if (type && inputMasks && - (inputMasks->dontPropagateMask[dev->id] & filter)) - rc |= DONT_PROPAGATE_MASK; - - /* Check for core mask */ - type = GetCoreType(event); - if (type && (win->deliverableEvents & filter) && - ((wOtherEventMasks(win) | win->eventMask) & filter)) - rc |= CORE_MASK; - - /* Check for core DontPropagate mask */ - if (type && (filter & wDontPropagateMask(win))) - rc |= DONT_PROPAGATE_MASK; - - return rc; -} - -/** - * Deliver events caused by input devices. - * - * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is - * called directly from the processInputProc. - * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call - * DeliverDeviceEvents. - * For focused events, DeliverFocusedEvent is called first, and _may_ call - * DeliverDeviceEvents. - * - * @param pWin Window to deliver event to. - * @param event The events to deliver, not yet in wire format. - * @param grab Possible grab on a device. - * @param stopAt Don't recurse up to the root window. - * @param dev The device that is responsible for the event. - * - * @see DeliverGrabbedEvent - * @see DeliverFocusedEvent - */ -int -DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, - WindowPtr stopAt, DeviceIntPtr dev) -{ - Window child = None; - Mask filter; - int deliveries = 0; - xEvent core; - xEvent *xE = NULL; - int rc, mask, count = 0; - - CHECKEVENT(event); - - while (pWin) - { - if ((mask = EventIsDeliverable(dev, event, pWin))) - { - /* XI2 events first */ - if (mask & XI2_MASK) - { - xEvent *xi2 = NULL; - rc = EventToXI2(event, &xi2); - if (rc == Success) - { - /* XXX: XACE */ - filter = GetEventFilter(dev, xi2); - FixUpEventFromWindow(dev, xi2, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1, - filter, grab); - xfree(xi2); - if (deliveries > 0) - goto unwind; - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in DDE (%d).\n", - dev->name, rc); - } - - /* XI events */ - if (mask & XI_MASK) - { - rc = EventToXI(event, &xE, &count); - if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, xE, count) == Success) { - filter = GetEventFilter(dev, xE); - FixUpEventFromWindow(dev, xE, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, xE, count, - filter, grab); - if (deliveries > 0) - goto unwind; - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in DDE (%d, %d). Skipping delivery.\n", - dev->name, event->any.type, rc); - } - - /* Core event */ - if ((mask & CORE_MASK) && IsMaster(dev) && dev->coreEvents) - { - rc = EventToCore(event, &core); - if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, &core, 1) == Success) { - filter = GetEventFilter(dev, &core); - FixUpEventFromWindow(dev, &core, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, &core, 1, - filter, grab); - if (deliveries > 0) - goto unwind; - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: Core conversion failed in DDE (%d, %d).\n", - dev->name, event->any.type, rc); - } - - if ((deliveries < 0) || (pWin == stopAt) || - (mask & DONT_PROPAGATE_MASK)) - { - deliveries = 0; - goto unwind; - } - } - - child = pWin->drawable.id; - pWin = pWin->parent; - } - -unwind: - xfree(xE); - return deliveries; -} - -#undef XI_MASK -#undef CORE_MASK -#undef DONT_PROPAGATE_MASK - -/** - * Deliver event to a window and it's immediate parent. Used for most window - * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that - * propagate up the tree or extension events - * - * In case of a ReparentNotify event, the event will be delivered to the - * otherParent as well. - * - * @param pWin Window to deliver events to. - * @param xE Events to deliver. - * @param count number of events in xE. - * @param otherParent Used for ReparentNotify events. - */ -int -DeliverEvents(WindowPtr pWin, xEvent *xE, int count, - WindowPtr otherParent) -{ - Mask filter; - int deliveries; - DeviceIntRec dummy; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) - return count; -#endif - - if (!count) - return 0; - - dummy.id = XIAllDevices; - filter = GetEventFilter(&dummy, xE); - if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify)) - xE->u.destroyNotify.event = pWin->drawable.id; - if (filter != StructureAndSubMask) - return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, NullGrab); - deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count, - StructureNotifyMask, NullGrab); - if (pWin->parent) - { - xE->u.destroyNotify.event = pWin->parent->drawable.id; - deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count, - SubstructureNotifyMask, NullGrab); - if (xE->u.u.type == ReparentNotify) - { - xE->u.destroyNotify.event = otherParent->drawable.id; - deliveries += DeliverEventsToWindow(&dummy, - otherParent, xE, count, SubstructureNotifyMask, - NullGrab); - } - } - return deliveries; -} - - -static Bool -PointInBorderSize(WindowPtr pWin, int x, int y) -{ - BoxRec box; - - if(POINT_IN_REGION(pWin->drawable.pScreen, &pWin->borderSize, x, y, &box)) - return TRUE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && - XineramaSetWindowPntrs(inputInfo.pointer, pWin)) { - SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite; - int i; - - for(i = 1; i < PanoramiXNumScreens; i++) { - if(POINT_IN_REGION(pSprite->screen, - &pSprite->windows[i]->borderSize, - x + panoramiXdataPtr[0].x - panoramiXdataPtr[i].x, - y + panoramiXdataPtr[0].y - panoramiXdataPtr[i].y, - &box)) - return TRUE; - } - } -#endif - return FALSE; -} - -/** - * Traversed from the root window to the window at the position x/y. While - * traversing, it sets up the traversal history in the spriteTrace array. - * After completing, the spriteTrace history is set in the following way: - * spriteTrace[0] ... root window - * spriteTrace[1] ... top level window that encloses x/y - * ... - * spriteTrace[spriteTraceGood - 1] ... window at x/y - * - * @returns the window at the given coordinates. - */ -static WindowPtr -XYToWindow(DeviceIntPtr pDev, int x, int y) -{ - WindowPtr pWin; - BoxRec box; - SpritePtr pSprite; - - pSprite = pDev->spriteInfo->sprite; - pSprite->spriteTraceGood = 1; /* root window still there */ - pWin = RootWindow(pDev)->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(pWin->drawable.pScreen, - wInputShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box)) -#ifdef ROOTLESS - /* In rootless mode windows may be offscreen, even when - * they're in X's stack. (E.g. if the native window system - * implements some form of virtual desktop system). - */ - && !pWin->rootlessUnhittable -#endif - ) - { - if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize) - { - pSprite->spriteTraceSize += 10; - pSprite->spriteTrace = xrealloc(pSprite->spriteTrace, - pSprite->spriteTraceSize*sizeof(WindowPtr)); - } - pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin; - pWin = pWin->firstChild; - } - else - pWin = pWin->nextSib; - } - return pSprite->spriteTrace[pSprite->spriteTraceGood-1]; -} - -/** - * Ungrab a currently FocusIn grabbed device and grab the device on the - * given window. If the win given is the NoneWin, the device is ungrabbed if - * applicable and FALSE is returned. - * - * @returns TRUE if the device has been grabbed, or FALSE otherwise. - */ -BOOL -ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) -{ - BOOL rc = FALSE; - DeviceEvent event; - - if (dev->deviceGrab.grab && - dev->deviceGrab.fromPassiveGrab && - dev->deviceGrab.grab->type == XI_Enter) - { - if (dev->deviceGrab.grab->window == win || - IsParent(dev->deviceGrab.grab->window, win)) - return FALSE; - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); - (*dev->deviceGrab.DeactivateGrab)(dev); - } - - if (win == NoneWin || win == PointerRootWin) - return FALSE; - - memset(&event, 0, sizeof(DeviceEvent)); - event.header = ET_Internal; - event.type = ET_FocusIn; - event.length = sizeof(DeviceEvent); - event.time = GetTimeInMillis(); - event.deviceid = dev->id; - event.sourceid = dev->id; - event.detail.button = 0; - rc = CheckPassiveGrabsOnWindow(win, dev, &event, FALSE); - if (rc) - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); - return rc; -} - -/** - * Ungrab a currently Enter grabbed device and grab the device for the given - * window. - * - * @returns TRUE if the device has been grabbed, or FALSE otherwise. - */ -static BOOL -ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) -{ - BOOL rc = FALSE; - DeviceEvent event; - - if (dev->deviceGrab.grab && - dev->deviceGrab.fromPassiveGrab && - dev->deviceGrab.grab->type == XI_Enter) - { - if (dev->deviceGrab.grab->window == win || - IsParent(dev->deviceGrab.grab->window, win)) - return FALSE; - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); - (*dev->deviceGrab.DeactivateGrab)(dev); - } - - memset(&event, 0, sizeof(DeviceEvent)); - event.header = ET_Internal; - event.type = ET_Enter; - event.length = sizeof(DeviceEvent); - event.time = GetTimeInMillis(); - event.deviceid = dev->id; - event.sourceid = dev->id; - event.detail.button = 0; - rc = CheckPassiveGrabsOnWindow(win, dev, &event, FALSE); - if (rc) - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab); - - return rc; -} - -/** - * Update the sprite coordinates based on the event. Update the cursor - * position, then update the event with the new coordinates that may have been - * changed. If the window underneath the sprite has changed, change to new - * cursor and send enter/leave events. - * - * CheckMotion() will not do anything and return FALSE if the event is not a - * pointer event. - * - * @return TRUE if the sprite has moved or FALSE otherwise. - */ -Bool -CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev) -{ - WindowPtr prevSpriteWin, newSpriteWin; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - CHECKEVENT(ev); - - prevSpriteWin = pSprite->win; - - if (ev && !syncEvents.playingEvents) - { - /* GetPointerEvents() guarantees that pointer events have the correct - rootX/Y set already. */ - switch (ev->type) - { - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_Motion: - break; - default: - /* all other events return FALSE */ - return FALSE; - } - - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - /* Motion events entering DIX get translated to Screen 0 - coordinates. Replayed events have already been - translated since they've entered DIX before */ - ev->root_x += panoramiXdataPtr[pSprite->screen->myNum].x - - panoramiXdataPtr[0].x; - ev->root_y += panoramiXdataPtr[pSprite->screen->myNum].y - - panoramiXdataPtr[0].y; - } else -#endif - { - if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) - { - pSprite->hot.pScreen = pSprite->hotPhys.pScreen; - RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum]; - } - } - - pSprite->hot.x = ev->root_x; - pSprite->hot.y = ev->root_y; - if (pSprite->hot.x < pSprite->physLimits.x1) - pSprite->hot.x = pSprite->physLimits.x1; - else if (pSprite->hot.x >= pSprite->physLimits.x2) - pSprite->hot.x = pSprite->physLimits.x2 - 1; - if (pSprite->hot.y < pSprite->physLimits.y1) - pSprite->hot.y = pSprite->physLimits.y1; - else if (pSprite->hot.y >= pSprite->physLimits.y2) - pSprite->hot.y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y); - pSprite->hotPhys = pSprite->hot; - - if ((pSprite->hotPhys.x != ev->root_x) || - (pSprite->hotPhys.y != ev->root_y)) - { -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - XineramaSetCursorPosition( - pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); - } else -#endif - { - (*pSprite->hotPhys.pScreen->SetCursorPosition)( - pDev, pSprite->hotPhys.pScreen, - pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); - } - } - - ev->root_x = pSprite->hot.x; - ev->root_y = pSprite->hot.y; - } - - newSpriteWin = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y); - - if (newSpriteWin != prevSpriteWin) - { - int sourceid; - if (!ev) { - UpdateCurrentTimeIf(); - sourceid = pDev->id; /* when from WindowsRestructured */ - } else - sourceid = ev->sourceid; - - if (prevSpriteWin != NullWindow) { - if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin)) - DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin, - newSpriteWin, NotifyNormal); - } - /* set pSprite->win after ActivateEnterGrab, otherwise - sprite window == grab_window and no enter/leave events are - sent. */ - pSprite->win = newSpriteWin; - PostNewCursor(pDev); - return FALSE; - } - return TRUE; -} - -/** - * Windows have restructured, we need to update the sprite position and the - * sprite's cursor. - */ -void -WindowsRestructured(void) -{ - DeviceIntPtr pDev = inputInfo.devices; - while(pDev) - { - if (IsMaster(pDev) || !pDev->u.master) - CheckMotion(NULL, pDev); - pDev = pDev->next; - } -} - -#ifdef PANORAMIX -/* This was added to support reconfiguration under Xdmx. The problem is - * that if the 0th screen (i.e., WindowTable[0]) is moved to an origin - * other than 0,0, the information in the private sprite structure must - * be updated accordingly, or XYToWindow (and other routines) will not - * compute correctly. */ -void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff) -{ - GrabPtr grab; - DeviceIntPtr pDev; - SpritePtr pSprite; - - if (noPanoramiXExtension) return; - - pDev = inputInfo.devices; - while(pDev) - { - if (DevHasCursor(pDev)) - { - pSprite = pDev->spriteInfo->sprite; - pSprite->hot.x -= xoff; - pSprite->hot.y -= yoff; - - pSprite->hotPhys.x -= xoff; - pSprite->hotPhys.y -= yoff; - - pSprite->hotLimits.x1 -= xoff; - pSprite->hotLimits.y1 -= yoff; - pSprite->hotLimits.x2 -= xoff; - pSprite->hotLimits.y2 -= yoff; - - if (REGION_NOTEMPTY(pSprite->screen, &pSprite->Reg1)) - REGION_TRANSLATE(pSprite->screen, &pSprite->Reg1, xoff, yoff); - if (REGION_NOTEMPTY(pSprite->screen, &pSprite->Reg2)) - REGION_TRANSLATE(pSprite->screen, &pSprite->Reg2, xoff, yoff); - - /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */ - if ((grab = pDev->deviceGrab.grab) && grab->confineTo) { - if (grab->confineTo->drawable.pScreen - != pSprite->hotPhys.pScreen) - pSprite->hotPhys.x = pSprite->hotPhys.y = 0; - ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); - } else - ConfineCursorToWindow( - pDev, - WindowTable[pSprite->hotPhys.pScreen->myNum], - TRUE, FALSE); - - } - pDev = pDev->next; - } -} -#endif - -/** - * Initialize a sprite for the given device and set it to some sane values. If - * the device already has a sprite alloc'd, don't realloc but just reset to - * default values. - * If a window is supplied, the sprite will be initialized with the window's - * cursor and positioned in the center of the window's screen. The root window - * is a good choice to pass in here. - * - * It's a good idea to call it only for pointer devices, unless you have a - * really talented keyboard. - * - * @param pDev The device to initialize. - * @param pWin The window where to generate the sprite in. - * - */ -void -InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin) -{ - SpritePtr pSprite; - ScreenPtr pScreen; - CursorPtr pCursor; - - if (!pDev->spriteInfo->sprite) - { - DeviceIntPtr it; - - pDev->spriteInfo->sprite = (SpritePtr)xcalloc(1, sizeof(SpriteRec)); - if (!pDev->spriteInfo->sprite) - FatalError("InitializeSprite: failed to allocate sprite struct"); - - /* We may have paired another device with this device before our - * device had a actual sprite. We need to check for this and reset the - * sprite field for all paired devices. - * - * The VCK is always paired with the VCP before the VCP has a sprite. - */ - for (it = inputInfo.devices; it; it = it->next) - { - if (it->spriteInfo->paired == pDev) - it->spriteInfo->sprite = pDev->spriteInfo->sprite; - } - if (inputInfo.keyboard->spriteInfo->paired == pDev) - inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite; - } - - pSprite = pDev->spriteInfo->sprite; - pDev->spriteInfo->spriteOwner = TRUE; - - pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr)NULL; - pSprite->hot.pScreen = pScreen; - pSprite->hotPhys.pScreen = pScreen; - if (pScreen) - { - pSprite->hotPhys.x = pScreen->width / 2; - pSprite->hotPhys.y = pScreen->height / 2; - pSprite->hotLimits.x2 = pScreen->width; - pSprite->hotLimits.y2 = pScreen->height; - } - - pSprite->hot = pSprite->hotPhys; - pSprite->win = pWin; - - if (pWin) - { - pCursor = wCursor(pWin); - pSprite->spriteTrace = (WindowPtr *)xcalloc(1, 32*sizeof(WindowPtr)); - if (!pSprite->spriteTrace) - FatalError("Failed to allocate spriteTrace"); - pSprite->spriteTraceSize = 32; - - RootWindow(pDev) = pWin; - pSprite->spriteTraceGood = 1; - - pSprite->pEnqueueScreen = pScreen; - pSprite->pDequeueScreen = pSprite->pEnqueueScreen; - - } else { - pCursor = NullCursor; - pSprite->spriteTrace = NULL; - pSprite->spriteTraceSize = 0; - pSprite->spriteTraceGood = 0; - pSprite->pEnqueueScreen = screenInfo.screens[0]; - pSprite->pDequeueScreen = pSprite->pEnqueueScreen; - } - if (pCursor) - pCursor->refcnt++; - if (pSprite->current) - FreeCursor(pSprite->current, None); - pSprite->current = pCursor; - - if (pScreen) - { - (*pScreen->RealizeCursor) ( pDev, pScreen, pSprite->current); - (*pScreen->CursorLimits) ( pDev, pScreen, pSprite->current, - &pSprite->hotLimits, &pSprite->physLimits); - pSprite->confined = FALSE; - - (*pScreen->ConstrainCursor) (pDev, pScreen, - &pSprite->physLimits); - (*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x, - pSprite->hot.y, - FALSE); - (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); - } -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - pSprite->hotLimits.x1 = -panoramiXdataPtr[0].x; - pSprite->hotLimits.y1 = -panoramiXdataPtr[0].y; - pSprite->hotLimits.x2 = PanoramiXPixWidth - panoramiXdataPtr[0].x; - pSprite->hotLimits.y2 = PanoramiXPixHeight - panoramiXdataPtr[0].y; - pSprite->physLimits = pSprite->hotLimits; - pSprite->confineWin = NullWindow; - pSprite->hotShape = NullRegion; - pSprite->screen = pScreen; - /* gotta UNINIT these someplace */ - REGION_NULL(pScreen, &pSprite->Reg1); - REGION_NULL(pScreen, &pSprite->Reg2); - } -#endif -} - -/** - * Update the mouse sprite info when the server switches from a pScreen to another. - * Otherwise, the pScreen of the mouse sprite is never updated when we switch - * from a pScreen to another. Never updating the pScreen of the mouse sprite - * implies that windows that are in pScreen whose pScreen->myNum >0 will never - * get pointer events. This is because in CheckMotion(), sprite.hotPhys.pScreen - * always points to the first pScreen it has been set by - * DefineInitialRootWindow(). - * - * Calling this function is useful for use cases where the server - * has more than one pScreen. - * This function is similar to DefineInitialRootWindow() but it does not - * reset the mouse pointer position. - * @param win must be the new pScreen we are switching to. - */ -void -UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - SpritePtr pSprite = NULL; - WindowPtr win = NULL; - CursorPtr pCursor; - if (!pScreen) - return ; - - if (!pDev->spriteInfo->sprite) - return; - - pSprite = pDev->spriteInfo->sprite; - - win = WindowTable[pScreen->myNum]; - - pSprite->hotPhys.pScreen = pScreen; - pSprite->hot = pSprite->hotPhys; - pSprite->hotLimits.x2 = pScreen->width; - pSprite->hotLimits.y2 = pScreen->height; - pSprite->win = win; - pCursor = wCursor(win); - if (pCursor) - pCursor->refcnt++; - if (pSprite->current) - FreeCursor(pSprite->current, 0); - pSprite->current = pCursor; - pSprite->spriteTraceGood = 1; - pSprite->spriteTrace[0] = win; - (*pScreen->CursorLimits) (pDev, - pScreen, - pSprite->current, - &pSprite->hotLimits, - &pSprite->physLimits); - pSprite->confined = FALSE; - (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits); - (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - pSprite->hotLimits.x1 = -panoramiXdataPtr[0].x; - pSprite->hotLimits.y1 = -panoramiXdataPtr[0].y; - pSprite->hotLimits.x2 = PanoramiXPixWidth - panoramiXdataPtr[0].x; - pSprite->hotLimits.y2 = PanoramiXPixHeight - panoramiXdataPtr[0].y; - pSprite->physLimits = pSprite->hotLimits; - pSprite->screen = pScreen; - } -#endif -} - -/* - * 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) -{ - DeviceIntPtr pDev; - - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - if (DevHasCursor(pDev)) - PostNewCursor(pDev); -} - -void -NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - pSprite->hotPhys.x = x; - pSprite->hotPhys.y = y; -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - pSprite->hotPhys.x += panoramiXdataPtr[newScreen->myNum].x - - panoramiXdataPtr[0].x; - pSprite->hotPhys.y += panoramiXdataPtr[newScreen->myNum].y - - panoramiXdataPtr[0].y; - if (newScreen != pSprite->screen) { - pSprite->screen = newScreen; - /* Make sure we tell the DDX to update its copy of the screen */ - if(pSprite->confineWin) - XineramaConfineCursorToWindow(pDev, - pSprite->confineWin, TRUE); - else - XineramaConfineCursorToWindow(pDev, WindowTable[0], TRUE); - /* if the pointer wasn't confined, the DDX won't get - told of the pointer warp so we reposition it here */ - if(!syncEvents.playingEvents) - (*pSprite->screen->SetCursorPosition)( - pDev, - pSprite->screen, - pSprite->hotPhys.x + panoramiXdataPtr[0].x - - panoramiXdataPtr[pSprite->screen->myNum].x, - pSprite->hotPhys.y + panoramiXdataPtr[0].y - - panoramiXdataPtr[pSprite->screen->myNum].y, FALSE); - } - } else -#endif - if (newScreen != pSprite->hotPhys.pScreen) - ConfineCursorToWindow(pDev, WindowTable[newScreen->myNum], - TRUE, FALSE); -} - -#ifdef PANORAMIX - -static Bool -XineramaPointInWindowIsVisible( - WindowPtr pWin, - int x, - int y -) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - BoxRec box; - int i, xoff, yoff; - - if (!pWin->realized) return FALSE; - - if (POINT_IN_REGION(pScreen, &pWin->borderClip, x, y, &box)) - return TRUE; - - if(!XineramaSetWindowPntrs(inputInfo.pointer, pWin)) return FALSE; - - xoff = x + panoramiXdataPtr[0].x; - yoff = y + panoramiXdataPtr[0].y; - - for(i = 1; i < PanoramiXNumScreens; i++) { - pWin = inputInfo.pointer->spriteInfo->sprite->windows[i]; - pScreen = pWin->drawable.pScreen; - x = xoff - panoramiXdataPtr[i].x; - y = yoff - panoramiXdataPtr[i].y; - - if(POINT_IN_REGION(pScreen, &pWin->borderClip, x, y, &box) - && (!wInputShape(pWin) || - POINT_IN_REGION(pWin->drawable.pScreen, - wInputShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box))) - return TRUE; - - } - - return FALSE; -} - -static int -XineramaWarpPointer(ClientPtr client) -{ - WindowPtr dest = NULL; - int x, y, rc; - SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; - - REQUEST(xWarpPointerReq); - - - if (stuff->dstWid != None) { - rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess); - if (rc != Success) - return rc; - } - x = pSprite->hotPhys.x; - y = pSprite->hotPhys.y; - - if (stuff->srcWid != None) - { - int winX, winY; - XID winID = stuff->srcWid; - WindowPtr source; - - rc = dixLookupWindow(&source, winID, client, DixReadAccess); - if (rc != Success) - return rc; - - winX = source->drawable.x; - winY = source->drawable.y; - if(source == WindowTable[0]) { - winX -= panoramiXdataPtr[0].x; - winY -= panoramiXdataPtr[0].y; - } - if (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) || - !XineramaPointInWindowIsVisible(source, x, y)) - return Success; - } - if (dest) { - x = dest->drawable.x; - y = dest->drawable.y; - if(dest == WindowTable[0]) { - x -= panoramiXdataPtr[0].x; - y -= panoramiXdataPtr[0].y; - } - } - - x += stuff->dstX; - y += stuff->dstY; - - if (x < pSprite->physLimits.x1) - x = pSprite->physLimits.x1; - else if (x >= pSprite->physLimits.x2) - x = pSprite->physLimits.x2 - 1; - if (y < pSprite->physLimits.y1) - y = pSprite->physLimits.y1; - else if (y >= pSprite->physLimits.y2) - y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y); - - XineramaSetCursorPosition(PickPointer(client), x, y, TRUE); - - return Success; -} - -#endif - - -/** - * Server-side protocol handling for WarpPointer request. - * Warps the cursor position to the coordinates given in the request. - */ -int -ProcWarpPointer(ClientPtr client) -{ - WindowPtr dest = NULL; - int x, y, rc; - ScreenPtr newScreen; - DeviceIntPtr dev, tmp; - SpritePtr pSprite; - - REQUEST(xWarpPointerReq); - REQUEST_SIZE_MATCH(xWarpPointerReq); - - dev = PickPointer(client); - - for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if ((tmp == dev) || (!IsMaster(tmp) && tmp->u.master == dev)) { - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess); - if (rc != Success) - return rc; - } - } - - if (dev->u.lastSlave) - dev = dev->u.lastSlave; - pSprite = dev->spriteInfo->sprite; - -#ifdef PANORAMIX - if(!noPanoramiXExtension) - return XineramaWarpPointer(client); -#endif - - if (stuff->dstWid != None) { - rc = dixLookupWindow(&dest, stuff->dstWid, client, DixGetAttrAccess); - if (rc != Success) - return rc; - } - x = pSprite->hotPhys.x; - y = pSprite->hotPhys.y; - - if (stuff->srcWid != None) - { - int winX, winY; - XID winID = stuff->srcWid; - WindowPtr source; - - rc = dixLookupWindow(&source, winID, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - winX = source->drawable.x; - winY = source->drawable.y; - if (source->drawable.pScreen != pSprite->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 = pSprite->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 == pSprite->hotPhys.pScreen) - { - if (x < pSprite->physLimits.x1) - x = pSprite->physLimits.x1; - else if (x >= pSprite->physLimits.x2) - x = pSprite->physLimits.x2 - 1; - if (y < pSprite->physLimits.y1) - y = pSprite->physLimits.y1; - else if (y >= pSprite->physLimits.y2) - y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(dev, pSprite->hotShape, &x, &y); - (*newScreen->SetCursorPosition)(dev, newScreen, x, y, TRUE); - } - else if (!PointerConfinedToScreen(dev)) - { - NewCurrentScreen(dev, newScreen, x, y); - } - return Success; -} - -static Bool -BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin) -{ - if(REGION_NOTEMPTY(pDev->spriteInfo->sprite->hotPhys.pScreen, &pWin->borderSize)) - return TRUE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) { - int i; - - for(i = 1; i < PanoramiXNumScreens; i++) { - if(REGION_NOTEMPTY(pDev->spriteInfo->sprite->screen, - &pDev->spriteInfo->sprite->windows[i]->borderSize)) - return TRUE; - } - } -#endif - return FALSE; -} - -/** - * "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a - * passive grab set on the window to be activated. - * If a passive grab is activated, the event will be delivered to the client. - * - * @param pWin The window that may be subject to a passive grab. - * @param device Device that caused the event. - * @param event The current device event. - * @param checkCore Check for core grabs too. - */ - -static Bool -CheckPassiveGrabsOnWindow( - WindowPtr pWin, - DeviceIntPtr device, - DeviceEvent *event, - BOOL checkCore) -{ - GrabPtr grab = wPassiveGrabs(pWin); - GrabRec tempGrab; - GrabInfoPtr grabinfo; -#define CORE_MATCH 0x1 -#define XI_MATCH 0x2 -#define XI2_MATCH 0x4 - int match = 0; - - if (device->deviceGrab.grab) - return FALSE; - - if (!grab) - return FALSE; - /* Fill out the grab details, but leave the type for later before - * comparing */ - tempGrab.window = pWin; - tempGrab.device = device; - tempGrab.detail.exact = event->detail.key; - tempGrab.detail.pMask = NULL; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.next = NULL; - for (; grab; grab = grab->next) - { - DeviceIntPtr gdev; - XkbSrvInfoPtr xkbi = NULL; - Mask mask = 0; - - gdev= grab->modifierDevice; - if (grab->grabtype == GRABTYPE_CORE) - { - if (IsPointerDevice(device)) - gdev = GetPairedDevice(device); - else - gdev = device; - } else if (grab->grabtype == GRABTYPE_XI2) - { - /* if the device is an attached slave device, gdev must be the - * attached master keyboard. Since the slave may have been - * reattached after the grab, the modifier device may not be the - * same. */ - if (!IsMaster(grab->device) && device->u.master) - gdev = GetMaster(device, MASTER_KEYBOARD); - } - - - if (gdev && gdev->key) - xkbi= gdev->key->xkbInfo; - tempGrab.modifierDevice = grab->modifierDevice; - tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0; - - /* Check for XI2 and XI grabs first */ - tempGrab.type = GetXI2Type((InternalEvent*)event); - tempGrab.grabtype = GRABTYPE_XI2; - if (GrabMatchesSecond(&tempGrab, grab, FALSE)) - match = XI2_MATCH; - - tempGrab.detail.exact = event->detail.key; - if (!match) - { - tempGrab.type = GetXIType((InternalEvent*)event); - tempGrab.grabtype = GRABTYPE_XI; - if (GrabMatchesSecond(&tempGrab, grab, FALSE)) - match = XI_MATCH; - } - - /* Check for a core grab (ignore the device when comparing) */ - if (!match && checkCore) - { - tempGrab.grabtype = GRABTYPE_CORE; - if ((tempGrab.type = GetCoreType((InternalEvent*)event)) && - (GrabMatchesSecond(&tempGrab, grab, TRUE))) - match = CORE_MATCH; - } - - if (match && (!grab->confineTo || - (grab->confineTo->realized && - BorderSizeNotEmpty(device, grab->confineTo)))) - { - int rc, count = 0; - xEvent *xE = NULL; - xEvent core; - - event->corestate &= 0x1f00; - event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00); - grabinfo = &device->deviceGrab; - /* In some cases a passive core grab may exist, but the client - * already has a core grab on some other device. In this case we - * must not get the grab, otherwise we may never ungrab the - * device. - */ - - if (grab->grabtype == GRABTYPE_CORE) - { - DeviceIntPtr other; - BOOL interfering = FALSE; - - /* A passive grab may have been created for a different device - than it is assigned to at this point in time. - Update the grab's device and modifier device to reflect the - current state. - Since XGrabDeviceButton requires to specify the - modifierDevice explicitly, we don't override this choice. - */ - if (tempGrab.type < GenericEvent) - { - grab->device = device; - grab->modifierDevice = GetPairedDevice(device); - } - - for (other = inputInfo.devices; other; other = other->next) - { - GrabPtr othergrab = other->deviceGrab.grab; - if (othergrab && othergrab->grabtype == GRABTYPE_CORE && - SameClient(grab, rClient(othergrab)) && - ((IsPointerDevice(grab->device) && - IsPointerDevice(othergrab->device)) || - (IsKeyboardDevice(grab->device) && - IsKeyboardDevice(othergrab->device)))) - { - interfering = TRUE; - break; - } - } - if (interfering) - continue; - } - - - if (match & CORE_MATCH) - { - rc = EventToCore((InternalEvent*)event, &core); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: core conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->type, rc); - continue; - } - xE = &core; - count = 1; - mask = grab->eventMask; - if (grab->ownerEvents) - mask |= pWin->eventMask; - } else if (match & XI2_MATCH) - { - rc = EventToXI2((InternalEvent*)event, &xE); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->type, rc); - continue; - } - count = 1; - - /* FIXME: EventToXI2 returns NULL for enter events, so - * dereferencing the event is bad. Internal event types are - * aligned with core events, so the else clause is valid. - * long-term we should use internal events for enter/focus - * as well */ - if (xE) - mask = grab->xi2mask[device->id][((xGenericEvent*)xE)->evtype/8]; - else if (event->type == XI_Enter || event->type == XI_FocusIn) - mask = grab->xi2mask[device->id][event->type/8]; - - if (grab->ownerEvents && wOtherInputMasks(grab->window)) - { - InputClientsPtr icp = - wOtherInputMasks(grab->window)->inputClients; - - while(icp) - { - if (rClient(icp) == rClient(grab)) - { - int evtype = (xE) ? ((xGenericEvent*)xE)->evtype : event->type; - mask |= icp->xi2mask[device->id][evtype/8]; - break; - } - - icp = icp->next; - } - } - } else - { - rc = EventToXI((InternalEvent*)event, &xE, &count); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->type, rc); - continue; - } - mask = grab->eventMask; - if (grab->ownerEvents && wOtherInputMasks(grab->window)) - { - InputClientsPtr icp = - wOtherInputMasks(grab->window)->inputClients; - - while(icp) - { - if (rClient(icp) == rClient(grab)) - { - mask |= icp->mask[device->id]; - break; - } - - icp = icp->next; - } - } - } - - (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); - - if (xE) - { - FixUpEventFromWindow(device, xE, grab->window, None, TRUE); - - TryClientEvents(rClient(grab), device, xE, count, mask, - GetEventFilter(device, xE), grab); - } - - if (grabinfo->sync.state == FROZEN_NO_EVENT) - { - if (!grabinfo->sync.event) - grabinfo->sync.event = xcalloc(1, sizeof(InternalEvent)); - *grabinfo->sync.event = *event; - grabinfo->sync.state = FROZEN_WITH_EVENT; - } - - if (match & (XI_MATCH | XI2_MATCH)) - xfree(xE); /* on core match xE == &core */ - return TRUE; - } - } - return FALSE; -#undef CORE_MATCH -#undef XI_MATCH -#undef XI2_MATCH -} - -/** - * 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 the 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 - * - * If a grab is activated, the event has been sent to the client already! - * - * The event we pass in must always be an XI event. From this, we then emulate - * the core event and then check for grabs. - * - * @param device The device that caused the event. - * @param xE The event to handle (Device{Button|Key}Press). - * @param count Number of events in list. - * @return TRUE if a grab has been activated or false otherwise. -*/ - -Bool -CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, int checkFirst) -{ - int i; - WindowPtr pWin = NULL; - FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus; - BOOL sendCore = (IsMaster(device) && device->coreEvents); - - if (event->type != ET_ButtonPress && - event->type != ET_KeyPress) - return FALSE; - - if (event->type == ET_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, event, sendCore)) - return TRUE; - } - - if ((focus->win == NoneWin) || - (i >= device->spriteInfo->sprite->spriteTraceGood) || - ((i > checkFirst) && - (pWin != device->spriteInfo->sprite->spriteTrace[i-1]))) - return FALSE; - } - - for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) - { - pWin = device->spriteInfo->sprite->spriteTrace[i]; - if (pWin->optional && - CheckPassiveGrabsOnWindow(pWin, device, event, sendCore)) - return TRUE; - } - - return FALSE; -} - -/** - * Called for keyboard events to deliver event to whatever client owns the - * focus. - * - * The event is delivered to the keyboard's focus window, the root window or - * to the window owning the input focus. - * - * @param keybd The keyboard originating the event. - * @param event The event, not yet in wire format. - * @param window Window underneath the sprite. - */ -void -DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) -{ - DeviceIntPtr ptr; - WindowPtr focus = keybd->focus->win; - BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents); - xEvent core; - xEvent *xE = NULL, *xi2 = NULL; - int count, rc; - int deliveries = 0; - - if (focus == FollowKeyboardWin) - focus = inputInfo.keyboard->focus->win; - if (!focus) - return; - if (focus == PointerRootWin) - { - DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd); - return; - } - if ((focus == window) || IsParent(focus, window)) - { - if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd)) - return; - } - - /* just deliver it to the focus window */ - ptr = GetPairedDevice(keybd); - - - rc = EventToXI2(event, &xi2); - if (rc == Success) - { - /* XXX: XACE */ - int filter = GetEventFilter(keybd, xi2); - FixUpEventFromWindow(ptr, xi2, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1, - filter, NullGrab); - if (deliveries > 0) - goto unwind; - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n", - keybd->name, event->any.type, rc); - - rc = EventToXI(event, &xE, &count); - if (rc == Success && - XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success) - { - FixUpEventFromWindow(ptr, xE, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, xE, count, - GetEventFilter(keybd, xE), - NullGrab); - - if (deliveries > 0) - goto unwind; - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n", - keybd->name, event->any.type, rc); - - if (sendCore) - { - rc = EventToCore(event, &core); - if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, &core, 1) == Success) { - FixUpEventFromWindow(keybd, &core, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, &core, 1, - GetEventFilter(keybd, &core), - NullGrab); - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n", - keybd->name, event->any.type, rc); - } - -unwind: - if (xE) - xfree(xE); - if (xi2) - xfree(xi2); - return; -} - -/** - * Deliver an event from a device that is currently grabbed. Uses - * DeliverDeviceEvents() for further delivery if a ownerEvents is set on the - * grab. If not, TryClientEvents() is used. - * - * @param deactivateGrab True if the device's grab should be deactivated. - */ -void -DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, - Bool deactivateGrab) -{ - GrabPtr grab; - GrabInfoPtr grabinfo; - int deliveries = 0; - DeviceIntPtr dev; - SpritePtr pSprite = thisDev->spriteInfo->sprite; - BOOL sendCore = FALSE; - int rc, count = 0; - xEvent *xi = NULL; - xEvent *xi2 = NULL; - - grabinfo = &thisDev->deviceGrab; - grab = grabinfo->grab; - - if (grab->ownerEvents) - { - WindowPtr focus; - - /* Hack: Some pointer device have a focus class. So we need to check - * for the type of event, to see if we really want to deliver it to - * the focus window. For pointer events, the answer is no. - */ - if (IsPointerEvent(event)) - focus = PointerRootWin; - else if (thisDev->focus) - { - focus = thisDev->focus->win; - if (focus == FollowKeyboardWin) - focus = inputInfo.keyboard->focus->win; - } - else - focus = PointerRootWin; - if (focus == PointerRootWin) - deliveries = DeliverDeviceEvents(pSprite->win, event, grab, - NullWindow, thisDev); - else if (focus && (focus == pSprite->win || - IsParent(focus, pSprite->win))) - deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus, - thisDev); - else if (focus) - deliveries = DeliverDeviceEvents(focus, event, grab, focus, - thisDev); - } - if (!deliveries) - { - Mask mask; - - /* XXX: In theory, we could pass the internal events through to - * everything and only convert just before hitting the wire. We can't - * do that yet, so DGE is the last stop for internal events. From here - * onwards, we deal with core/XI events. - */ - - mask = grab->eventMask; - - sendCore = (IsMaster(thisDev) && thisDev->coreEvents); - /* try core event */ - if (sendCore && grab->grabtype == GRABTYPE_CORE) - { - xEvent core; - - rc = EventToCore(event, &core); - if (rc == Success) - { - FixUpEventFromWindow(thisDev, &core, grab->window, - None, TRUE); - if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, - grab->window, &core, 1) || - XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), - grab->window, &core, 1)) - deliveries = 1; /* don't send, but pretend we did */ - else if (!IsInterferingGrab(rClient(grab), thisDev, &core)) - { - deliveries = TryClientEvents(rClient(grab), thisDev, - &core, 1, mask, - GetEventFilter(thisDev, &core), - grab); - } - } else if (rc != BadMatch) - ErrorF("[dix] DeliverGrabbedEvent. Core conversion failed.\n"); - } - - if (!deliveries) - { - rc = EventToXI2(event, &xi2); - if (rc == Success) - { - int evtype = ((xGenericEvent*)xi2)->evtype; - mask = grab->xi2mask[XIAllDevices][evtype/8] | - grab->xi2mask[XIAllMasterDevices][evtype/8] | - grab->xi2mask[thisDev->id][evtype/8]; - /* try XI2 event */ - FixUpEventFromWindow(thisDev, xi2, grab->window, None, TRUE); - /* XXX: XACE */ - deliveries = TryClientEvents(rClient(grab), thisDev, xi2, 1, mask, - GetEventFilter(thisDev, xi2), grab); - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in DGE (%d, %d). Skipping delivery.\n", - thisDev->name, event->any.type, rc); - } - - if (!deliveries) - { - rc = EventToXI(event, &xi, &count); - if (rc == Success) - { - /* try XI event */ - if (grabinfo->fromPassiveGrab && - grabinfo->implicitGrab) - mask = grab->deviceMask; - else - mask = grab->eventMask; - - FixUpEventFromWindow(thisDev, xi, grab->window, - None, TRUE); - - if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, - grab->window, xi, count) || - XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), - grab->window, xi, count)) - deliveries = 1; /* don't send, but pretend we did */ - else - { - deliveries = - TryClientEvents(rClient(grab), thisDev, - xi, count, - mask, - GetEventFilter(thisDev, xi), - grab); - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in DGE (%d, %d). Skipping delivery.\n", - thisDev->name, event->any.type, rc); - } - - if (deliveries && (event->any.type == ET_Motion)) - thisDev->valuator->motionHintWindow = grab->window; - } - if (deliveries && !deactivateGrab && event->any.type != ET_Motion) - { - switch (grabinfo->sync.state) - { - case FREEZE_BOTH_NEXT_EVENT: - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev == thisDev) - continue; - FreezeThaw(dev, TRUE); - if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) && - (CLIENT_BITS(grab->resource) == - CLIENT_BITS(dev->deviceGrab.grab->resource))) - dev->deviceGrab.sync.state = FROZEN_NO_EVENT; - else - dev->deviceGrab.sync.other = grab; - } - /* fall through */ - case FREEZE_NEXT_EVENT: - grabinfo->sync.state = FROZEN_WITH_EVENT; - FreezeThaw(thisDev, TRUE); - if (!grabinfo->sync.event) - grabinfo->sync.event = xcalloc(1, sizeof(InternalEvent)); - *grabinfo->sync.event = event->device_event; - break; - } - } - - if (xi) - xfree(xi); - if (xi2) - xfree(xi2); -} - -/* This function is used to set the key pressed or key released state - - this is only used when the pressing of keys does not cause - the device's processInputProc to be called, as in for example Mouse Keys. -*/ -void -FixKeyState (DeviceEvent *event, DeviceIntPtr keybd) -{ - int key, bit; - BYTE *kptr; - KeyClassPtr keyc = keybd->key; - - key = event->detail.key; - kptr = &keyc->down[key >> 3]; - bit = 1 << (key & 7); - - if (event->type == ET_KeyPress) { - DebugF("FixKeyState: Key %d %s\n",key, - ((event->type == ET_KeyPress) ? "down" : "up")); - } - - if (event->type == ET_KeyPress) - *kptr |= bit; - else if (event->type == ET_KeyRelease) - *kptr &= ~bit; - else - FatalError("Impossible keyboard event"); -} - -#define AtMostOneClient \ - (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) -#define ManagerMask \ - (SubstructureRedirectMask | ResizeRedirectMask) - -/** - * Recalculate which events may be deliverable for the given window. - * Recalculated mask is used for quicker determination which events may be - * delivered to a window. - * - * The otherEventMasks on a WindowOptional is the combination of all event - * masks set by all clients on the window. - * deliverableEventMask is the combination of the eventMask and the - * otherEventMask plus the events that may be propagated to the parent. - * - * Traverses to siblings and parents of the window. - */ -void -RecalculateDeliverableEvents(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); - } - xfree(other); - RecalculateDeliverableEvents(pWin); - return(Success); - } - prev = other; - } - FatalError("client not on event list"); - /*NOTREACHED*/ - return -1; /* make compiler happy */ -} - -int -EventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask) -{ - Mask check; - OtherClients * others; - DeviceIntPtr dev; - int rc; - - if (mask & ~AllEventMasks) - { - client->errorValue = mask; - return BadValue; - } - check = (mask & ManagerMask); - if (check) { - rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, - RT_WINDOW, pWin, RT_NONE, NULL, DixManageAccess); - if (rc != Success) - return rc; - } - 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 = xalloc(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 ((mask & PointerMotionHintMask) && !(check & PointerMotionHintMask)) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->valuator && dev->valuator->motionHintWindow == pWin) - dev->valuator->motionHintWindow = NullWindow; - } - } - RecalculateDeliverableEvents(pWin); - return Success; -} - -int -EventSuppressForWindow(WindowPtr pWin, 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; -} - -/** - * Assembles an EnterNotify or LeaveNotify and sends it event to the client. - * Uses the paired keyboard to get some additional information. - */ -void -CoreEnterLeaveEvent( - DeviceIntPtr mouse, - int type, - int mode, - int detail, - WindowPtr pWin, - Window child) -{ - xEvent event; - WindowPtr focus; - DeviceIntPtr keybd; - GrabPtr grab = mouse->deviceGrab.grab; - Mask mask; - - keybd = GetPairedDevice(mouse); - - 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); - } - - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = type; - event.u.u.detail = detail; - event.u.enterLeave.time = currentTime.milliseconds; - event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x; - event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y; - /* Counts on the same initial structure of crossing & button events! */ - FixUpEventFromWindow(mouse, &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 = mouse->button ? (mouse->button->state & 0x1f00) : 0; - if (keybd) - event.u.enterLeave.state |= - XkbGrabStateFromRec(&keybd->key->xkbInfo->state); - event.u.enterLeave.mode = mode; - focus = (keybd) ? keybd->focus->win : None; - if ((focus != NoneWin) && - ((pWin == focus) || (focus == PointerRootWin) || - IsParent(focus, pWin))) - event.u.enterLeave.flags |= ELFlagFocus; - - if ((mask & GetEventFilter(mouse, &event))) - { - if (grab) - TryClientEvents(rClient(grab), mouse, &event, 1, mask, - GetEventFilter(mouse, &event), grab); - else - DeliverEventsToWindow(mouse, pWin, &event, 1, - GetEventFilter(mouse, &event), - NullGrab); - } - - if ((type == EnterNotify) && (mask & KeymapStateMask)) - { - xKeymapEvent ke; - ClientPtr client = grab ? rClient(grab) : wClient(pWin); - if (XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess)) - bzero((char *)&ke.map[0], 31); - else - memmove((char *)&ke.map[0], (char *)&keybd->key->down[1], 31); - - ke.type = KeymapNotify; - if (grab) - TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1, - mask, KeymapStateMask, grab); - else - DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1, - KeymapStateMask, NullGrab); - } -} - -void -DeviceEnterLeaveEvent( - DeviceIntPtr mouse, - int sourceid, - int type, - int mode, - int detail, - WindowPtr pWin, - Window child) -{ - GrabPtr grab = mouse->deviceGrab.grab; - xXIEnterEvent *event; - int filter; - int btlen, len, i; - DeviceIntPtr kbd; - - if ((mode == XINotifyPassiveGrab && type == XI_Leave) || - (mode == XINotifyPassiveUngrab && type == XI_Enter)) - return; - - btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; - btlen = bytes_to_int32(btlen); - len = sizeof(xXIEnterEvent) + btlen * 4; - - event = xcalloc(1, len); - event->type = GenericEvent; - event->extension = IReqCode; - event->evtype = type; - event->length = (len - sizeof(xEvent))/4; - event->buttons_len = btlen; - event->detail = detail; - event->time = currentTime.milliseconds; - event->deviceid = mouse->id; - event->sourceid = sourceid; - event->mode = mode; - event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); - event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); - - for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) - if (BitIsOn(mouse->button->down, i)) - SetBit(&event[1], i); - - kbd = (IsMaster(mouse) || mouse->u.master) ? GetPairedDevice(mouse) : NULL; - if (kbd && kbd->key) - { - event->mods.base_mods = kbd->key->xkbInfo->state.base_mods; - event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods; - event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods; - - event->group.base_group = kbd->key->xkbInfo->state.base_group; - event->group.latched_group = kbd->key->xkbInfo->state.latched_group; - event->group.locked_group = kbd->key->xkbInfo->state.locked_group; - } - - FixUpEventFromWindow(mouse, (xEvent*)event, pWin, None, FALSE); - - filter = GetEventFilter(mouse, (xEvent*)event); - - if (grab) - { - Mask mask; - mask = grab->xi2mask[XIAllDevices][type/8] | - grab->xi2mask[XIAllMasterDevices][type/8] | - grab->xi2mask[mouse->id][type/8]; - TryClientEvents(rClient(grab), mouse, (xEvent*)event, 1, mask, - filter, grab); - } else { - if (!GetWindowXI2Mask(mouse, pWin, (xEvent*)event)) - goto out; - DeliverEventsToWindow(mouse, pWin, (xEvent*)event, 1, filter, - NullGrab); - } - -out: - xfree(event); -} - -void -CoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin) -{ - xEvent event; - - memset(&event, 0, sizeof(xEvent)); - event.u.focus.mode = mode; - event.u.u.type = type; - event.u.u.detail = detail; - event.u.focus.window = pWin->drawable.id; - - DeliverEventsToWindow(dev, pWin, &event, 1, - GetEventFilter(dev, &event), NullGrab); - if ((type == FocusIn) && - ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) - { - xKeymapEvent ke; - ClientPtr client = wClient(pWin); - if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess)) - bzero((char *)&ke.map[0], 31); - else - memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31); - - ke.type = KeymapNotify; - DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1, - KeymapStateMask, NullGrab); - } -} - -/** - * Set the input focus to the given window. Subsequent keyboard events will be - * delivered to the given window. - * - * Usually called from ProcSetInputFocus as result of a client request. If so, - * the device is the inputInfo.keyboard. - * If called from ProcXSetInputFocus as result of a client xinput request, the - * device is set to the device specified by the client. - * - * @param client Client that requested input focus change. - * @param dev Focus device. - * @param focusID The window to obtain the focus. Can be PointerRoot or None. - * @param revertTo Specifies where the focus reverts to when window becomes - * unviewable. - * @param ctime Specifies the time. - * @param followOK True if pointer is allowed to follow the keyboard. - */ -int -SetInputFocus( - ClientPtr client, - DeviceIntPtr dev, - Window focusID, - CARD8 revertTo, - Time ctime, - Bool followOK) -{ - FocusClassPtr focus; - WindowPtr focusWin; - int mode, rc; - TimeStamp time; - DeviceIntPtr keybd; /* used for FollowKeyboard or FollowKeyboardWin */ - - - UpdateCurrentTime(); - if ((revertTo != RevertToParent) && - (revertTo != RevertToPointerRoot) && - (revertTo != RevertToNone) && - ((revertTo != RevertToFollowKeyboard) || !followOK)) - { - client->errorValue = revertTo; - return BadValue; - } - time = ClientTimeToServerTime(ctime); - - if (IsKeyboardDevice(dev)) - keybd = dev; - else - keybd = GetPairedDevice(dev); - - if ((focusID == None) || (focusID == PointerRoot)) - focusWin = (WindowPtr)(long)focusID; - else if ((focusID == FollowKeyboard) && followOK) - { - focusWin = keybd->focus->win; - } - else { - rc = dixLookupWindow(&focusWin, focusID, client, DixSetAttrAccess); - if (rc != Success) - return rc; - /* It is a match error to try to set the input focus to an - unviewable window. */ - if(!focusWin->realized) - return(BadMatch); - } - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixSetFocusAccess); - if (rc != Success) - return Success; - - focus = dev->focus; - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, focus->time) == EARLIER)) - return Success; - mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal; - if (focus->win == FollowKeyboardWin) - { - if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin)) - DoFocusEvents(dev, keybd->focus->win, focusWin, mode); - } else - { - if (!ActivateFocusInGrab(dev, focus->win, focusWin)) - 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; - focus->trace = xrealloc(focus->trace, - focus->traceSize * sizeof(WindowPtr)); - } - focus->traceGood = depth; - for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--) - focus->trace[depth] = pWin; - } - return Success; -} - -/** - * Server-side protocol handling for SetInputFocus request. - * - * Sets the input focus for the virtual core keyboard. - */ -int -ProcSetInputFocus(ClientPtr client) -{ - DeviceIntPtr kbd = PickKeyboard(client); - REQUEST(xSetInputFocusReq); - - REQUEST_SIZE_MATCH(xSetInputFocusReq); - - return SetInputFocus(client, kbd, stuff->focus, - stuff->revertTo, stuff->time, FALSE); -} - -/** - * Server-side protocol handling for GetInputFocus request. - * - * Sends the current input focus for the client's keyboard back to the - * client. - */ -int -ProcGetInputFocus(ClientPtr client) -{ - DeviceIntPtr kbd = PickKeyboard(client); - xGetInputFocusReply rep; - FocusClassPtr focus = kbd->focus; - int rc; - /* REQUEST(xReq); */ - REQUEST_SIZE_MATCH(xReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetFocusAccess); - if (rc != Success) - return rc; - - memset(&rep, 0, sizeof(xGetInputFocusReply)); - 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; -} - -/** - * Server-side protocol handling for GrabPointer request. - * - * Sets an active grab on the client's ClientPointer and returns success - * status to client. - */ -int -ProcGrabPointer(ClientPtr client) -{ - xGrabPointerReply rep; - DeviceIntPtr device = PickPointer(client); - GrabPtr grab; - GrabMask mask; - WindowPtr confineTo; - CursorPtr oldCursor; - REQUEST(xGrabPointerReq); - TimeStamp time; - int rc; - - REQUEST_SIZE_MATCH(xGrabPointerReq); - UpdateCurrentTime(); - - if (stuff->eventMask & ~PointerGrabMask) - { - client->errorValue = stuff->eventMask; - return BadValue; - } - - if (stuff->confineTo == None) - confineTo = NullWindow; - else - { - rc = dixLookupWindow(&confineTo, stuff->confineTo, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - - memset(&rep, 0, sizeof(xGrabPointerReply)); - oldCursor = NullCursor; - grab = device->deviceGrab.grab; - - if (grab) - { - if (grab->confineTo && !confineTo) - ConfineCursorToWindow(device, RootWindow(device), FALSE, FALSE); - oldCursor = grab->cursor; - } - - mask.core = stuff->eventMask; - - rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode, - stuff->grabWindow, stuff->ownerEvents, stuff->time, - &mask, GRABTYPE_CORE, stuff->cursor, - stuff->confineTo, &rep.status); - if (rc != Success) - return rc; - - if (oldCursor && rep.status == GrabSuccess) - FreeCursor (oldCursor, (Cursor)0); - - time = ClientTimeToServerTime(stuff->time); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); - return Success; -} - -/** - * Server-side protocol handling for ChangeActivePointerGrab request. - * - * Changes properties of the grab hold by the client. If the client does not - * hold an active grab on the device, nothing happens. - */ -int -ProcChangeActivePointerGrab(ClientPtr client) -{ - DeviceIntPtr device; - GrabPtr 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 - { - int rc = dixLookupResourceByType((pointer *)&newCursor, stuff->cursor, - RT_CURSOR, client, DixUseAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return (rc == BadValue) ? BadCursor : rc; - } - } - - device = PickPointer(client); - grab = device->deviceGrab.grab; - - if (!grab) - return Success; - if (!SameClient(grab, client)) - return Success; - time = ClientTimeToServerTime(stuff->time); - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER)) - return Success; - oldCursor = grab->cursor; - grab->cursor = newCursor; - if (newCursor) - newCursor->refcnt++; - PostNewCursor(device); - if (oldCursor) - FreeCursor(oldCursor, (Cursor)0); - grab->eventMask = stuff->eventMask; - return Success; -} - -/** - * Server-side protocol handling for UngrabPointer request. - * - * Deletes a pointer grab on a device the client has grabbed. - */ -int -ProcUngrabPointer(ClientPtr client) -{ - DeviceIntPtr device = PickPointer(client); - GrabPtr grab; - TimeStamp time; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - UpdateCurrentTime(); - grab = device->deviceGrab.grab; - - time = ClientTimeToServerTime(stuff->id); - if ((CompareTimeStamps(time, currentTime) != LATER) && - (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && - (grab) && SameClient(grab, client)) - (*device->deviceGrab.DeactivateGrab)(device); - return Success; -} - -/** - * Sets a grab on the given device. - * - * Called from ProcGrabKeyboard to work on the client's keyboard. - * Called from ProcXGrabDevice to work on the device specified by the client. - * - * The parameters this_mode and other_mode represent the keyboard_mode and - * pointer_mode parameters of XGrabKeyboard(). - * See man page for details on all the parameters - * - * @param client Client that owns the grab. - * @param dev The device to grab. - * @param this_mode GrabModeSync or GrabModeAsync - * @param other_mode GrabModeSync or GrabModeAsync - * @param status Return code to be returned to the caller. - * - * @returns Success or BadValue. - */ -int -GrabDevice(ClientPtr client, DeviceIntPtr dev, - unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow, - unsigned ownerEvents, Time ctime, GrabMask *mask, - int grabtype, Cursor curs, Window confineToWin, CARD8 *status) -{ - WindowPtr pWin, confineTo; - GrabPtr grab; - TimeStamp time; - Mask access_mode = DixGrabAccess; - int rc; - GrabInfoPtr grabInfo = &dev->deviceGrab; - CursorPtr cursor; - - UpdateCurrentTime(); - if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync)) - { - client->errorValue = keyboard_mode; - return BadValue; - } - if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync)) - { - client->errorValue = pointer_mode; - return BadValue; - } - if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) - { - client->errorValue = ownerEvents; - return BadValue; - } - - rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - if (confineToWin == None) - confineTo = NullWindow; - else - { - rc = dixLookupWindow(&confineTo, confineToWin, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - - if (curs == None) - cursor = NullCursor; - else - { - rc = dixLookupResourceByType((pointer *)&cursor, curs, RT_CURSOR, - client, DixUseAccess); - if (rc != Success) - { - client->errorValue = curs; - return (rc == BadValue) ? BadCursor : rc; - } - access_mode |= DixForceAccess; - } - - if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc != Success) - return rc; - - time = ClientTimeToServerTime(ctime); - grab = grabInfo->grab; - if (grab && grab->grabtype != grabtype) - *status = AlreadyGrabbed; - if (grab && !SameClient(grab, client)) - *status = AlreadyGrabbed; - else if ((!pWin->realized) || - (confineTo && - !(confineTo->realized - && BorderSizeNotEmpty(dev, confineTo)))) - *status = GrabNotViewable; - else if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER)) - *status = GrabInvalidTime; - else if (grabInfo->sync.frozen && - grabInfo->sync.other && !SameClient(grabInfo->sync.other, client)) - *status = GrabFrozen; - else - { - GrabRec tempGrab; - - /* Otherwise segfaults happen on grabbed MPX devices */ - memset(&tempGrab, 0, sizeof(GrabRec)); - - tempGrab.next = NULL; - tempGrab.window = pWin; - tempGrab.resource = client->clientAsMask; - tempGrab.ownerEvents = ownerEvents; - tempGrab.keyboardMode = keyboard_mode; - tempGrab.pointerMode = pointer_mode; - if (grabtype == GRABTYPE_CORE) - tempGrab.eventMask = mask->core; - else if (grabtype == GRABTYPE_XI) - tempGrab.eventMask = mask->xi; - else - memcpy(tempGrab.xi2mask, mask->xi2mask, sizeof(tempGrab.xi2mask)); - tempGrab.device = dev; - tempGrab.cursor = cursor; - tempGrab.confineTo = confineTo; - tempGrab.grabtype = grabtype; - (*grabInfo->ActivateGrab)(dev, &tempGrab, time, FALSE); - *status = GrabSuccess; - } - return Success; -} - -/** - * Server-side protocol handling for GrabKeyboard request. - * - * Grabs the client's keyboard and returns success status to client. - */ -int -ProcGrabKeyboard(ClientPtr client) -{ - xGrabKeyboardReply rep; - REQUEST(xGrabKeyboardReq); - int result; - DeviceIntPtr keyboard = PickKeyboard(client); - GrabMask mask; - - REQUEST_SIZE_MATCH(xGrabKeyboardReq); - - memset(&rep, 0, sizeof(xGrabKeyboardReply)); - mask.core = KeyPressMask | KeyReleaseMask; - - result = GrabDevice(client, keyboard, stuff->pointerMode, - stuff->keyboardMode, stuff->grabWindow, stuff->ownerEvents, - stuff->time, &mask, GRABTYPE_CORE, None, None, - &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; -} - -/** - * Server-side protocol handling for UngrabKeyboard request. - * - * Deletes a possible grab on the client's keyboard. - */ -int -ProcUngrabKeyboard(ClientPtr client) -{ - DeviceIntPtr device = PickKeyboard(client); - GrabPtr grab; - TimeStamp time; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - UpdateCurrentTime(); - - grab = device->deviceGrab.grab; - - time = ClientTimeToServerTime(stuff->id); - if ((CompareTimeStamps(time, currentTime) != LATER) && - (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && - (grab) && SameClient(grab, client) && grab->grabtype == GRABTYPE_CORE) - (*device->deviceGrab.DeactivateGrab)(device); - return Success; -} - -/** - * Server-side protocol handling for QueryPointer request. - * - * Returns the current state and position of the client's ClientPointer to the - * client. - */ -int -ProcQueryPointer(ClientPtr client) -{ - xQueryPointerReply rep; - WindowPtr pWin, t; - DeviceIntPtr mouse = PickPointer(client); - DeviceIntPtr keyboard; - SpritePtr pSprite; - int rc; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); - if (rc != Success) - return rc; - rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); - if (rc != Success && rc != BadAccess) - return rc; - - keyboard = GetPairedDevice(mouse); - - pSprite = mouse->spriteInfo->sprite; - if (mouse->valuator->motionHintWindow) - MaybeStopHint(mouse, client); - memset(&rep, 0, sizeof(xQueryPointerReply)); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.mask = mouse->button ? (mouse->button->state) : 0; - rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state); - rep.length = 0; - rep.root = (RootWindow(mouse))->drawable.id; - rep.rootX = pSprite->hot.x; - rep.rootY = pSprite->hot.y; - rep.child = None; - if (pSprite->hot.pScreen == pWin->drawable.pScreen) - { - rep.sameScreen = xTrue; - rep.winX = pSprite->hot.x - pWin->drawable.x; - rep.winY = pSprite->hot.y - pWin->drawable.y; - for (t = pSprite->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; - } - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - rep.rootX += panoramiXdataPtr[0].x; - rep.rootY += panoramiXdataPtr[0].y; - if(stuff->id == rep.root) { - rep.winX += panoramiXdataPtr[0].x; - rep.winY += panoramiXdataPtr[0].y; - } - } -#endif - - if (rc == BadAccess) { - rep.mask = 0; - rep.child = None; - rep.rootX = 0; - rep.rootY = 0; - rep.winX = 0; - rep.winY = 0; - } - - WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep); - - return(Success); -} - -/** - * Initializes the device list and the DIX sprite to sane values. Allocates - * trace memory used for quick window traversal. - */ -void -InitEvents(void) -{ - int i; - - inputInfo.numDevices = 0; - inputInfo.devices = (DeviceIntPtr)NULL; - inputInfo.off_devices = (DeviceIntPtr)NULL; - inputInfo.keyboard = (DeviceIntPtr)NULL; - inputInfo.pointer = (DeviceIntPtr)NULL; - /* The mask for pointer motion events may have changed in the last server - * generation. See comment above definition of filters. */ - filters[0][PointerMotionMask] = MotionNotify; - for (i = 1; i < MAXDEVICES; i++) - { - memcpy(&filters[i], filters[0], sizeof(filters[0])); - } - - syncEvents.replayDev = (DeviceIntPtr)NULL; - syncEvents.replayWin = NullWindow; - while (syncEvents.pending) - { - QdEventPtr next = syncEvents.pending->next; - xfree(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; - } - - InputEventListLen = GetMaximumEventsNum(); - InputEventList = InitEventList(InputEventListLen); - if (!InputEventList) - FatalError("[dix] Failed to allocate input event list.\n"); -} - -void -CloseDownEvents(void) -{ - FreeEventList(InputEventList, InputEventListLen); - InputEventListLen = 0; - InputEventList = NULL; -} - -/** - * Server-side protocol handling for SendEvent request. - * - * Locates the window to send the event to and forwards the event. - */ -int -ProcSendEvent(ClientPtr client) -{ - WindowPtr pWin; - WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ - DeviceIntPtr dev = PickPointer(client); - DeviceIntPtr keybd = GetPairedDevice(dev); - SpritePtr pSprite = dev->spriteInfo->sprite; - 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 = pSprite->win; - else if (stuff->destination == InputFocus) - { - WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin; - - 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 = pSprite->spriteTrace[0]; /* Root window! */ - - if (IsParent(inputFocus, pSprite->win)) - { - effectiveFocus = inputFocus; - pWin = pSprite->win; - } - else - effectiveFocus = pWin = inputFocus; - } - else - dixLookupWindow(&pWin, stuff->destination, client, DixSendAccess); - - 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 (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, - &stuff->event, 1)) - return Success; - if (DeliverEventsToWindow(dev, pWin, - &stuff->event, 1, stuff->eventMask, NullGrab)) - return Success; - if (pWin == effectiveFocus) - return Success; - stuff->eventMask &= ~wDontPropagateMask(pWin); - if (!stuff->eventMask) - break; - } - } - else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1)) - DeliverEventsToWindow(dev, pWin, &stuff->event, - 1, stuff->eventMask, NullGrab); - return Success; -} - -/** - * Server-side protocol handling for UngrabKey request. - * - * Deletes a passive grab for the given key. Works on the - * client's keyboard. - */ -int -ProcUngrabKey(ClientPtr client) -{ - REQUEST(xUngrabKeyReq); - WindowPtr pWin; - GrabRec tempGrab; - DeviceIntPtr keybd = PickKeyboard(client); - int rc; - - REQUEST_SIZE_MATCH(xUngrabKeyReq); - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || - (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) - && (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 = GetPairedDevice(keybd); - tempGrab.type = KeyPress; - tempGrab.grabtype = GRABTYPE_CORE; - tempGrab.detail.exact = stuff->key; - tempGrab.detail.pMask = NULL; - tempGrab.next = NULL; - - if (!DeletePassiveGrabFromList(&tempGrab)) - return(BadAlloc); - return(Success); -} - -/** - * Server-side protocol handling for GrabKey request. - * - * Creates a grab for the client's keyboard and adds it to the list of passive - * grabs. - */ -int -ProcGrabKey(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xGrabKeyReq); - GrabPtr grab; - DeviceIntPtr keybd = PickKeyboard(client); - int rc; - GrabParameters param; - GrabMask mask; - - REQUEST_SIZE_MATCH(xGrabKeyReq); - - memset(¶m, 0, sizeof(param)); - param.grabtype = GRABTYPE_CORE; - param.ownerEvents = stuff->ownerEvents; - param.this_device_mode = stuff->keyboardMode; - param.other_devices_mode = stuff->pointerMode; - param.modifiers = stuff->modifiers; - - rc = CheckGrabValues(client, ¶m); - if (rc != Success) - return rc; - - if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || - (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) - && (stuff->key != AnyKey)) - { - client->errorValue = stuff->key; - return BadValue; - } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - - mask.core = (KeyPressMask | KeyReleaseMask); - - grab = CreateGrab(client->index, keybd, keybd, pWin, GRABTYPE_CORE, &mask, - ¶m, KeyPress, stuff->key, NullWindow, NullCursor); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - - -/** - * Server-side protocol handling for GrabButton request. - * - * Creates a grab for the client's ClientPointer and adds it as a passive grab - * to the list. - */ -int -ProcGrabButton(ClientPtr client) -{ - WindowPtr pWin, confineTo; - REQUEST(xGrabButtonReq); - CursorPtr cursor; - GrabPtr grab; - DeviceIntPtr ptr, modifierDevice; - Mask access_mode = DixGrabAccess; - GrabMask mask; - GrabParameters param; - int rc; - - 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; - } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - if (stuff->confineTo == None) - confineTo = NullWindow; - else { - rc = dixLookupWindow(&confineTo, stuff->confineTo, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - if (stuff->cursor == None) - cursor = NullCursor; - else - { - rc = dixLookupResourceByType((pointer *)&cursor, stuff->cursor, RT_CURSOR, - client, DixUseAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return (rc == BadValue) ? BadCursor : rc; - } - access_mode |= DixForceAccess; - } - - ptr = PickPointer(client); - modifierDevice = GetPairedDevice(ptr); - if (stuff->pointerMode == GrabModeSync || - stuff->keyboardMode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, access_mode); - if (rc != Success) - return rc; - - memset(¶m, 0, sizeof(param)); - param.grabtype = GRABTYPE_CORE; - param.ownerEvents = stuff->ownerEvents; - param.this_device_mode = stuff->keyboardMode; - param.other_devices_mode = stuff->pointerMode; - param.modifiers = stuff->modifiers; - - mask.core = stuff->eventMask; - - grab = CreateGrab(client->index, ptr, modifierDevice, pWin, - GRABTYPE_CORE, &mask, ¶m, ButtonPress, - stuff->button, confineTo, cursor); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - -/** - * Server-side protocol handling for UngrabButton request. - * - * Deletes a passive grab on the client's ClientPointer from the list. - */ -int -ProcUngrabButton(ClientPtr client) -{ - REQUEST(xUngrabButtonReq); - WindowPtr pWin; - GrabRec tempGrab; - int rc; - DeviceIntPtr ptr; - - REQUEST_SIZE_MATCH(xUngrabButtonReq); - if ((stuff->modifiers != AnyModifier) && - (stuff->modifiers & ~AllModifiersMask)) - { - client->errorValue = stuff->modifiers; - return BadValue; - } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess); - if (rc != Success) - return rc; - - ptr = PickPointer(client); - - tempGrab.resource = client->clientAsMask; - tempGrab.device = ptr; - tempGrab.window = pWin; - tempGrab.modifiersDetail.exact = stuff->modifiers; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.modifierDevice = GetPairedDevice(ptr); - tempGrab.type = ButtonPress; - tempGrab.detail.exact = stuff->button; - tempGrab.grabtype = GRABTYPE_CORE; - tempGrab.detail.pMask = NULL; - tempGrab.next = NULL; - - if (!DeletePassiveGrabFromList(&tempGrab)) - return(BadAlloc); - return(Success); -} - -/** - * Deactivate any grab that may be on the window, remove the focus. - * Delete any XInput extension events from the window too. Does not change the - * window mask. Use just before the window is deleted. - * - * If freeResources is set, passive grabs on the window are deleted. - * - * @param pWin The window to delete events from. - * @param freeResources True if resources associated with the window should be - * deleted. - */ -void -DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources) -{ - WindowPtr parent; - DeviceIntPtr mouse = inputInfo.pointer; - DeviceIntPtr keybd = inputInfo.keyboard; - FocusClassPtr focus; - OtherClientsPtr oc; - GrabPtr passive; - GrabPtr grab; - - - /* Deactivate any grabs performed on this window, before making any - input focus changes. */ - grab = mouse->deviceGrab.grab; - if (grab && - ((grab->window == pWin) || (grab->confineTo == pWin))) - (*mouse->deviceGrab.DeactivateGrab)(mouse); - - - /* Deactivating a keyboard grab should cause focus events. */ - grab = keybd->deviceGrab.grab; - if (grab && (grab->window == pWin)) - (*keybd->deviceGrab.DeactivateGrab)(keybd); - - /* And now the real devices */ - for (mouse = inputInfo.devices; mouse; mouse = mouse->next) - { - grab = mouse->deviceGrab.grab; - if (grab && ((grab->window == pWin) || (grab->confineTo == pWin))) - (*mouse->deviceGrab.DeactivateGrab)(mouse); - } - - - for (keybd = inputInfo.devices; keybd; keybd = keybd->next) - { - if (IsKeyboardDevice(keybd)) - { - focus = keybd->focus; - - /* 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->deviceGrab.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 - || wClient(parent)->clientGone -#endif - ); - if (!ActivateFocusInGrab(keybd, pWin, parent)) - DoFocusEvents(keybd, pWin, parent, focusEventMode); - focus->win = parent; - focus->revert = RevertToNone; - break; - case RevertToPointerRoot: - if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin)) - DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); - focus->win = PointerRootWin; - focus->traceGood = 0; - break; - } - } - } - - if (IsPointerDevice(keybd)) - { - if (keybd->valuator->motionHintWindow == pWin) - keybd->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); - } - - DeleteWindowFromAnyExtEvents(pWin, freeResources); -} - -/** - * Call this whenever some window at or below pWin has changed geometry. If - * there is a grab on the window, the cursor will be re-confined into the - * window. - */ -void -CheckCursorConfinement(WindowPtr pWin) -{ - GrabPtr grab; - WindowPtr confineTo; - DeviceIntPtr pDev; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return; -#endif - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - grab = pDev->deviceGrab.grab; - if (grab && (confineTo = grab->confineTo)) - { - if (!BorderSizeNotEmpty(pDev, confineTo)) - (*pDev->deviceGrab.DeactivateGrab)(pDev); - else if ((pWin == confineTo) || IsParent(pWin, confineTo)) - ConfineCursorToWindow(pDev, 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; -} - -/** - * Server-side protocol handling for RecolorCursor request. - */ -int -ProcRecolorCursor(ClientPtr client) -{ - CursorPtr pCursor; - int rc, nscr; - ScreenPtr pscr; - Bool displayed; - SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; - REQUEST(xRecolorCursorReq); - - REQUEST_SIZE_MATCH(xRecolorCursorReq); - rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR, - client, DixWriteAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return (rc == BadValue) ? BadCursor : rc; - } - - 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]; -#ifdef PANORAMIX - if(!noPanoramiXExtension) - displayed = (pscr == pSprite->screen); - else -#endif - displayed = (pscr == pSprite->hotPhys.pScreen); - ( *pscr->RecolorCursor)(PickPointer(client), pscr, pCursor, - (pCursor == pSprite->current) && displayed); - } - return (Success); -} - -/** - * Write the given events to a client, swapping the byte order if necessary. - * To swap the byte ordering, a callback is called that has to be set up for - * the given event type. - * - * In the case of DeviceMotionNotify trailed by DeviceValuators, the events - * can be more than one. Usually it's just one event. - * - * Do not modify the event structure passed in. See comment below. - * - * @param pClient Client to send events to. - * @param count Number of events. - * @param events The event list. - */ -void -WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) -{ -#ifdef PANORAMIX - xEvent eventCopy; -#endif - xEvent *eventTo, *eventFrom; - int i, - eventlength = sizeof(xEvent); - - /* Let XKB rewrite the state, as it depends on client preferences. */ - XkbFilterEvents(pClient, count, events); - -#ifdef PANORAMIX - if(!noPanoramiXExtension && - (panoramiXdataPtr[0].x || panoramiXdataPtr[0].y)) - { - switch(events->u.u.type) { - case MotionNotify: - case ButtonPress: - case ButtonRelease: - case KeyPress: - case KeyRelease: - case EnterNotify: - case LeaveNotify: - /* - When multiple clients want the same event DeliverEventsToWindow - passes the same event structure multiple times so we can't - modify the one passed to us - */ - count = 1; /* should always be 1 */ - memcpy(&eventCopy, events, sizeof(xEvent)); - eventCopy.u.keyButtonPointer.rootX += panoramiXdataPtr[0].x; - eventCopy.u.keyButtonPointer.rootY += panoramiXdataPtr[0].y; - if(eventCopy.u.keyButtonPointer.event == - eventCopy.u.keyButtonPointer.root) - { - eventCopy.u.keyButtonPointer.eventX += panoramiXdataPtr[0].x; - eventCopy.u.keyButtonPointer.eventY += panoramiXdataPtr[0].y; - } - events = &eventCopy; - break; - default: break; - } - } -#endif - - if (EventCallback) - { - EventInfoRec eventinfo; - eventinfo.client = pClient; - eventinfo.events = events; - eventinfo.count = count; - CallCallbacks(&EventCallback, (pointer)&eventinfo); - } -#ifdef XSERVER_DTRACE - if (XSERVER_SEND_EVENT_ENABLED()) { - for (i = 0; i < count; i++) - { - XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]); - } - } -#endif - /* Just a safety check to make sure we only have one GenericEvent, it just - * makes things easier for me right now. (whot) */ - for (i = 1; i < count; i++) - { - if (events[i].u.u.type == GenericEvent) - { - ErrorF("[dix] TryClientEvents: Only one GenericEvent at a time.\n"); - return; - } - } - - if (events->u.u.type == GenericEvent) - { - eventlength += ((xGenericEvent*)events)->length * 4; - } - - if(pClient->swapped) - { - if (eventlength > swapEventLen) - { - swapEventLen = eventlength; - swapEvent = Xrealloc(swapEvent, swapEventLen); - if (!swapEvent) - { - FatalError("WriteEventsToClient: Out of memory.\n"); - return; - } - } - - for(i = 0; i < count; i++) - { - eventFrom = &events[i]; - eventTo = swapEvent; - - /* 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); - - WriteToClient(pClient, eventlength, (char *)eventTo); - } - } - else - { - /* only one GenericEvent, remember? that means either count is 1 and - * eventlength is arbitrary or eventlength is 32 and count doesn't - * matter. And we're all set. Woohoo. */ - WriteToClient(pClient, count * eventlength, (char *) events); - } -} - -/* - * Set the client pointer for the given client. - * - * A client can have exactly one ClientPointer. Each time a - * request/reply/event is processed and the choice of devices is ambiguous - * (e.g. QueryPointer request), the server will pick the ClientPointer (see - * PickPointer()). - * If a keyboard is needed, the first keyboard paired with the CP is used. - */ -int -SetClientPointer(ClientPtr client, DeviceIntPtr device) -{ - int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess); - if (rc != Success) - return rc; - - if (!IsMaster(device)) - { - ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n"); - return BadDevice; - } else if (!device->spriteInfo->spriteOwner) - { - ErrorF("[dix] Device %d does not have a sprite. " - "Cannot be ClientPointer\n", device->id); - return BadDevice; - } - client->clientPtr = device; - return Success; -} - -/* PickPointer will pick an appropriate pointer for the given client. - * - * An "appropriate device" is (in order of priority): - * 1) A device the given client has a core grab on. - * 2) A device set as ClientPointer for the given client. - * 3) The first master device. - */ -DeviceIntPtr -PickPointer(ClientPtr client) -{ - DeviceIntPtr it = inputInfo.devices; - - /* First, check if the client currently has a grab on a device. Even - * keyboards count. */ - for(it = inputInfo.devices; it; it = it->next) - { - GrabPtr grab = it->deviceGrab.grab; - if (grab && grab->grabtype == GRABTYPE_CORE && SameClient(grab, client)) - { - it = GetMaster(it, MASTER_POINTER); - return it; /* Always return a core grabbed device */ - } - } - - if (!client->clientPtr) - { - DeviceIntPtr it = inputInfo.devices; - while (it) - { - if (IsMaster(it) && it->spriteInfo->spriteOwner) - { - client->clientPtr = it; - break; - } - it = it->next; - } - } - return client->clientPtr; -} - -/* PickKeyboard will pick an appropriate keyboard for the given client by - * searching the list of devices for the keyboard device that is paired with - * the client's pointer. - */ -DeviceIntPtr -PickKeyboard(ClientPtr client) -{ - DeviceIntPtr ptr = PickPointer(client); - DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD); - - if (!kbd) - { - ErrorF("[dix] ClientPointer not paired with a keyboard. This " - "is a bug.\n"); - } - - return kbd; -} - -/* A client that has one or more core grabs does not get core events from - * devices it does not have a grab on. Legacy applications behave bad - * otherwise because they are not used to it and the events interfere. - * Only applies for core events. - * - * Return true if a core event from the device would interfere and should not - * be delivered. - */ -Bool -IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event) -{ - DeviceIntPtr it = inputInfo.devices; - - switch(event->u.u.type) - { - case KeyPress: - case KeyRelease: - case ButtonPress: - case ButtonRelease: - case MotionNotify: - case EnterNotify: - case LeaveNotify: - break; - default: - return FALSE; - } - - if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) - return FALSE; - - while(it) - { - if (it != dev) - { - if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client) - && !it->deviceGrab.fromPassiveGrab) - { - if ((IsPointerDevice(it) && IsPointerDevice(dev)) || - (IsKeyboardDevice(it) && IsKeyboardDevice(dev))) - return TRUE; - } - } - it = it->next; - } - - return FALSE; -} - +/************************************************************ + +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, 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. + */ + +/** @file events.c + * This file handles event delivery and a big part of the server-side protocol + * handling (the parts for input devices). + */ + +#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" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif +#include "globals.h" + +#include +#include "xkbsrv.h" +#include "xace.h" + +#ifdef XSERVER_DTRACE +#include +typedef const char *string; +#include "Xserver-dtrace.h" +#endif + +#include +#include +#include +#include +#include "exglobals.h" +#include "exevents.h" +#include "exglobals.h" +#include "extnsionst.h" + +#include "dixevents.h" +#include "dixgrabs.h" +#include "dispatch.h" + +#include +#include "geext.h" +#include "geint.h" + +#include "eventstr.h" +#include "enterleave.h" +#include "eventconvert.h" + +/* Extension events type numbering starts at EXTENSION_EVENT_BASE. */ +#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 LastEventMask OwnerGrabButtonMask +#define AllEventMasks (LastEventMask|(LastEventMask-1)) + + +#define CORE_EVENT(event) \ + (!((event)->u.u.type & EXTENSION_EVENT_BASE) && \ + (event)->u.u.type != GenericEvent) +#define XI2_EVENT(event) \ + (((event)->u.u.type == GenericEvent) && \ + ((xGenericEvent*)(event))->extension == IReqCode) + +/** + * Used to indicate a implicit passive grab created by a ButtonPress event. + * See DeliverEventsToWindow(). + */ +#define ImplicitGrabMask (1 << 7) + +#define WID(w) ((w) ? ((w)->drawable.id) : 0) + +#define XE_KBPTR (xE->u.keyButtonPointer) + + +#define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) + +CallbackListPtr EventCallback; +CallbackListPtr DeviceEventCallback; + +#define DNPMCOUNT 8 + +Mask DontPropagateMasks[DNPMCOUNT]; +static int DontPropagateRefCnts[DNPMCOUNT]; + +static void CheckVirtualMotion( DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin); +static void CheckPhysLimits(DeviceIntPtr pDev, + CursorPtr cursor, + Bool generateEvents, + Bool confineToScreen, + ScreenPtr pScreen); +static Bool CheckPassiveGrabsOnWindow(WindowPtr pWin, + DeviceIntPtr device, + DeviceEvent *event, + BOOL checkCore); + +/** Key repeat hack. Do not use but in TryClientEvents */ +extern BOOL EventIsKeyRepeat(xEvent *event); + +/** + * Main input device struct. + * inputInfo.pointer + * is the core pointer. Referred to as "virtual core pointer", "VCP", + * "core pointer" or inputInfo.pointer. The VCP is the first master + * pointer device and cannot be deleted. + * + * inputInfo.keyboard + * is the core keyboard ("virtual core keyboard", "VCK", "core keyboard"). + * See inputInfo.pointer. + * + * inputInfo.devices + * linked list containing all devices including VCP and VCK. + * + * inputInfo.off_devices + * Devices that have not been initialized and are thus turned off. + * + * inputInfo.numDevices + * Total number of devices. + * + * inputInfo.all_devices + * Virtual device used for XIAllDevices passive grabs. This device is + * not part of the inputInfo.devices list and mostly unset except for + * the deviceid. It exists because passivegrabs need a valid device + * reference. + * + * inputInfo.all_master_devices + * Virtual device used for XIAllMasterDevices passive grabs. This device + * is not part of the inputInfo.devices list and mostly unset except for + * the deviceid. It exists because passivegrabs need a valid device + * reference. + */ +InputInfo inputInfo; + +EventSyncInfoRec syncEvents; + +/** + * The root window the given device is currently on. + */ +#define RootWindow(dev) dev->spriteInfo->sprite->spriteTrace[0] + +static xEvent* swapEvent = NULL; +static int swapEventLen = 0; + +void +NotImplemented(xEvent *from, xEvent *to) +{ + FatalError("Not implemented"); +} + +/** + * Convert the given event type from an XI event to a core event. + * @param[in] The XI 1.x event type. + * @return The matching core event type or 0 if there is none. + */ +int +XItoCoreType(int xitype) +{ + int coretype = 0; + if (xitype == DeviceMotionNotify) + coretype = MotionNotify; + else if (xitype == DeviceButtonPress) + coretype = ButtonPress; + else if (xitype == DeviceButtonRelease) + coretype = ButtonRelease; + else if (xitype == DeviceKeyPress) + coretype = KeyPress; + else if (xitype == DeviceKeyRelease) + coretype = KeyRelease; + + return coretype; +} + +/** + * @return true if the device owns a cursor, false if device shares a cursor + * sprite with another device. + */ +Bool +DevHasCursor(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->spriteOwner; +} + +/* + * @return true if a device is a pointer, check is the same as used by XI to + * fill the 'use' field. + */ +Bool +IsPointerDevice(DeviceIntPtr dev) +{ + return (dev->type == MASTER_POINTER) || + (dev->valuator && dev->button) || + (dev->valuator && !dev->key); +} + +/* + * @return true if a device is a keyboard, check is the same as used by XI to + * fill the 'use' field. + * + * Some pointer devices have keys as well (e.g. multimedia keys). Try to not + * count them as keyboard devices. + */ +Bool +IsKeyboardDevice(DeviceIntPtr dev) +{ + return (dev->type == MASTER_KEYBOARD) || + ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev)); +} + +Bool +IsMaster(DeviceIntPtr dev) +{ + return (dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD); +} + +static WindowPtr XYToWindow( + DeviceIntPtr pDev, + int x, + int y +); + +/** + * Max event opcode. + */ +extern int lastEvent; + +extern int DeviceMotionNotify; + +#define CantBeFiltered NoEventMask +/** + * Event masks for each event type. + * + * One set of filters for each device, but only the first layer + * is initialized. The rest is memcpy'd in InitEvents. + * + * Filters are used whether a given event may be delivered to a client, + * usually in the form of if (window-event-mask & filter); then deliver event. + * + * One notable filter is for PointerMotion/DevicePointerMotion events. Each + * time a button is pressed, the filter is modified to also contain the + * matching ButtonXMotion mask. + */ +static Mask filters[MAXDEVICES][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 */ +}}; + +/** + * For the given event, return the matching event filter. This filter may then + * be AND'ed with the selected event mask. + * + * For XI2 events, the returned filter is simply the byte containing the event + * mask we're interested in. E.g. for a mask of (1 << 13), this would be + * byte[1]. + * + * @param[in] dev The device the event belongs to, may be NULL. + * @param[in] event The event to get the filter for. Only the type of the + * event matters, or the extension + evtype for GenericEvents. + * @return The filter mask for the given event. + * + * @see GetEventMask + */ +Mask +GetEventFilter(DeviceIntPtr dev, xEvent *event) +{ + if (event->u.u.type != GenericEvent) + return filters[dev ? dev->id : 0][event->u.u.type]; + else if (XI2_EVENT(event)) + return (1 << (((xXIDeviceEvent*)event)->evtype % 8)); + ErrorF("[dix] Unknown device type %d. No filter\n", event->u.u.type); + return 0; +} + +/** + * Return the windows complete XI2 mask for the given XI2 event type. + */ +Mask +GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev) +{ + OtherInputMasks *inputMasks = wOtherInputMasks(win); + int filter; + int evtype; + + if (!inputMasks || !XI2_EVENT(ev)) + return 0; + + evtype = ((xGenericEvent*)ev)->evtype; + filter = GetEventFilter(dev, ev); + + return ((inputMasks->xi2mask[dev->id][evtype/8] & filter) || + inputMasks->xi2mask[XIAllDevices][evtype/8] || + (inputMasks->xi2mask[XIAllMasterDevices][evtype/8] && IsMaster(dev))); +} + +static Mask +GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients* other) +{ + /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */ + if (XI2_EVENT(event)) + { + int byte = ((xGenericEvent*)event)->evtype / 8; + return (other->xi2mask[dev->id][byte] | + other->xi2mask[XIAllDevices][byte] | + (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0)); + } else if (CORE_EVENT(event)) + return other->mask[XIAllDevices]; + else + return other->mask[dev->id]; +} + + +static CARD8 criticalEvents[32] = +{ + 0x7c, 0x30, 0x40 /* key, button, expose, and configure events */ +}; + +static void +SyntheticMotion(DeviceIntPtr dev, int x, int y) { + int screenno = 0; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + screenno = dev->spriteInfo->sprite->screen->myNum; +#endif + PostSyntheticMotion(dev, x, y, screenno, + (syncEvents.playingEvents) ? syncEvents.time.milliseconds : currentTime.milliseconds); + +} + +#ifdef PANORAMIX +static void PostNewCursor(DeviceIntPtr pDev); + +static Bool +XineramaSetCursorPosition( + DeviceIntPtr pDev, + int x, + int y, + Bool generateEvent +){ + ScreenPtr pScreen; + BoxRec box; + int i; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + /* x,y are in Screen 0 coordinates. We need to decide what Screen + to send the message too and what the coordinates relative to + that screen are. */ + + pScreen = pSprite->screen; + x += panoramiXdataPtr[0].x; + y += panoramiXdataPtr[0].y; + + if(!POINT_IN_REGION(pScreen, &XineramaScreenRegions[pScreen->myNum], + x, y, &box)) + { + FOR_NSCREENS(i) + { + if(i == pScreen->myNum) + continue; + if(POINT_IN_REGION(pScreen, &XineramaScreenRegions[i], x, y, &box)) + { + pScreen = screenInfo.screens[i]; + break; + } + } + } + + pSprite->screen = pScreen; + pSprite->hotPhys.x = x - panoramiXdataPtr[0].x; + pSprite->hotPhys.y = y - panoramiXdataPtr[0].y; + x -= panoramiXdataPtr[pScreen->myNum].x; + y -= panoramiXdataPtr[pScreen->myNum].y; + + return (*pScreen->SetCursorPosition)(pDev, pScreen, x, y, generateEvent); +} + + +static void +XineramaConstrainCursor(DeviceIntPtr pDev) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + ScreenPtr pScreen; + BoxRec newBox; + + pScreen = pSprite->screen; + newBox = pSprite->physLimits; + + /* Translate the constraining box to the screen + the sprite is actually on */ + newBox.x1 += panoramiXdataPtr[0].x - panoramiXdataPtr[pScreen->myNum].x; + newBox.x2 += panoramiXdataPtr[0].x - panoramiXdataPtr[pScreen->myNum].x; + newBox.y1 += panoramiXdataPtr[0].y - panoramiXdataPtr[pScreen->myNum].y; + newBox.y2 += panoramiXdataPtr[0].y - panoramiXdataPtr[pScreen->myNum].y; + + (* pScreen->ConstrainCursor)(pDev, pScreen, &newBox); +} + + +static Bool +XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if(pWin == WindowTable[0]) { + memcpy(pSprite->windows, WindowTable, + PanoramiXNumScreens*sizeof(WindowPtr)); + } else { + PanoramiXRes *win; + int rc, i; + + rc = dixLookupResourceByType((pointer *)&win, pWin->drawable.id, + XRT_WINDOW, serverClient, DixReadAccess); + if (rc != Success) + return FALSE; + + for(i = 0; i < PanoramiXNumScreens; i++) { + rc = dixLookupWindow(pSprite->windows + i, win->info[i].id, + serverClient, DixReadAccess); + if (rc != Success) /* window is being unmapped */ + return FALSE; + } + } + return TRUE; +} + +static void +XineramaConfineCursorToWindow(DeviceIntPtr pDev, + WindowPtr pWin, + Bool generateEvents) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + int x, y, off_x, off_y, i; + + if(!XineramaSetWindowPntrs(pDev, pWin)) + return; + + i = PanoramiXNumScreens - 1; + + REGION_COPY(pSprite->screen, &pSprite->Reg1, + &pSprite->windows[i]->borderSize); + off_x = panoramiXdataPtr[i].x; + off_y = panoramiXdataPtr[i].y; + + while(i--) { + x = off_x - panoramiXdataPtr[i].x; + y = off_y - panoramiXdataPtr[i].y; + + if(x || y) + REGION_TRANSLATE(pSprite->screen, &pSprite->Reg1, x, y); + + REGION_UNION(pSprite->screen, &pSprite->Reg1, &pSprite->Reg1, + &pSprite->windows[i]->borderSize); + + off_x = panoramiXdataPtr[i].x; + off_y = panoramiXdataPtr[i].y; + } + + pSprite->hotLimits = *REGION_EXTENTS(pSprite->screen, &pSprite->Reg1); + + if(REGION_NUM_RECTS(&pSprite->Reg1) > 1) + pSprite->hotShape = &pSprite->Reg1; + else + pSprite->hotShape = NullRegion; + + pSprite->confined = FALSE; + pSprite->confineWin = (pWin == WindowTable[0]) ? NullWindow : pWin; + + CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL); +} + +#endif /* PANORAMIX */ + +/** + * Modifies the filter for the given protocol event type to the given masks. + * + * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent(). + * The latter initialises masks for the matching XI events, it's a once-off + * setting. + * UDS however changes the mask for MotionNotify and DeviceMotionNotify each + * time a button is pressed to include the matching ButtonXMotion mask in the + * filter. + * + * @param[in] deviceid The device to modify the filter for. + * @param[in] mask The new filter mask. + * @param[in] event Protocol event type. + */ +void +SetMaskForEvent(int deviceid, Mask mask, int event) +{ + if (deviceid < 0 || deviceid >= MAXDEVICES) + FatalError("SetMaskForEvent: bogus device id"); + filters[deviceid][event] = mask; +} + +void +SetCriticalEvent(int event) +{ + if (event >= 128) + FatalError("SetCriticalEvent: bogus event number"); + criticalEvents[event >> 3] |= 1 << (event & 7); +} + +void +ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py) +{ + BoxRec box; + int x = *px, y = *py; + int incx = 1, incy = 1; + SpritePtr pSprite; + + pSprite = pDev->spriteInfo->sprite; + if (POINT_IN_REGION(pSprite->hot.pScreen, shape, x, y, &box)) + return; + box = *REGION_EXTENTS(pSprite->hot.pScreen, 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(pSprite->hot.pScreen, shape, x, y, &box)); + *px = x; + *py = y; +} + +static void +CheckPhysLimits( + DeviceIntPtr pDev, + CursorPtr cursor, + Bool generateEvents, + Bool confineToScreen, /* unused if PanoramiX on */ + ScreenPtr pScreen) /* unused if PanoramiX on */ +{ + HotSpot new; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if (!cursor) + return; + new = pSprite->hotPhys; +#ifdef PANORAMIX + if (!noPanoramiXExtension) + /* I don't care what the DDX has to say about it */ + pSprite->physLimits = pSprite->hotLimits; + else +#endif + { + if (pScreen) + new.pScreen = pScreen; + else + pScreen = new.pScreen; + (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits, + &pSprite->physLimits); + pSprite->confined = confineToScreen; + (* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits); + } + + /* constrain the pointer to those limits */ + if (new.x < pSprite->physLimits.x1) + new.x = pSprite->physLimits.x1; + else + if (new.x >= pSprite->physLimits.x2) + new.x = pSprite->physLimits.x2 - 1; + if (new.y < pSprite->physLimits.y1) + new.y = pSprite->physLimits.y1; + else + if (new.y >= pSprite->physLimits.y2) + new.y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y); + if (( +#ifdef PANORAMIX + noPanoramiXExtension && +#endif + (pScreen != pSprite->hotPhys.pScreen)) || + (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) + { +#ifdef PANORAMIX + if (!noPanoramiXExtension) + XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents); + else +#endif + { + if (pScreen != pSprite->hotPhys.pScreen) + pSprite->hotPhys = new; + (*pScreen->SetCursorPosition) + (pDev, pScreen, new.x, new.y, generateEvents); + } + if (!generateEvents) + SyntheticMotion(pDev, new.x, new.y); + } + +#ifdef PANORAMIX + /* Tell DDX what the limits are */ + if (!noPanoramiXExtension) + XineramaConstrainCursor(pDev); +#endif +} + +static void +CheckVirtualMotion( + DeviceIntPtr pDev, + QdEventPtr qe, + WindowPtr pWin) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + RegionPtr reg = NULL; + DeviceEvent *ev = NULL; + + if (qe) + { + ev = &qe->event->device_event; + switch(ev->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + pSprite->hot.pScreen = qe->pScreen; + pSprite->hot.x = ev->root_x; + pSprite->hot.y = ev->root_y; + pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow; + break; + default: + break; + } + } + if (pWin) + { + BoxRec lims; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + int x, y, off_x, off_y, i; + + if(!XineramaSetWindowPntrs(pDev, pWin)) + return; + + i = PanoramiXNumScreens - 1; + + REGION_COPY(pSprite->screen, &pSprite->Reg2, + &pSprite->windows[i]->borderSize); + off_x = panoramiXdataPtr[i].x; + off_y = panoramiXdataPtr[i].y; + + while(i--) { + x = off_x - panoramiXdataPtr[i].x; + y = off_y - panoramiXdataPtr[i].y; + + if(x || y) + REGION_TRANSLATE(pSprite->screen, &pSprite->Reg2, x, y); + + REGION_UNION(pSprite->screen, &pSprite->Reg2, &pSprite->Reg2, + &pSprite->windows[i]->borderSize); + + off_x = panoramiXdataPtr[i].x; + off_y = panoramiXdataPtr[i].y; + } + } else +#endif + { + if (pSprite->hot.pScreen != pWin->drawable.pScreen) + { + pSprite->hot.pScreen = pWin->drawable.pScreen; + pSprite->hot.x = pSprite->hot.y = 0; + } + } + + lims = *REGION_EXTENTS(pWin->drawable.pScreen, &pWin->borderSize); + if (pSprite->hot.x < lims.x1) + pSprite->hot.x = lims.x1; + else if (pSprite->hot.x >= lims.x2) + pSprite->hot.x = lims.x2 - 1; + if (pSprite->hot.y < lims.y1) + pSprite->hot.y = lims.y1; + else if (pSprite->hot.y >= lims.y2) + pSprite->hot.y = lims.y2 - 1; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (REGION_NUM_RECTS(&pSprite->Reg2) > 1) + reg = &pSprite->Reg2; + + } else +#endif + { + if (wBoundingShape(pWin)) + reg = &pWin->borderSize; + } + + if (reg) + ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y); + + if (qe && ev) + { + qe->pScreen = pSprite->hot.pScreen; + ev->root_x = pSprite->hot.x; + ev->root_y = pSprite->hot.y; + } + } +#ifdef PANORAMIX + if (noPanoramiXExtension) /* No typo. Only set the root win if disabled */ +#endif + RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum]; +} + +static void +ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bool confineToScreen) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if (syncEvents.playingEvents) + { + CheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin); + SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y); + } + else + { +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + XineramaConfineCursorToWindow(pDev, pWin, generateEvents); + return; + } +#endif + pSprite->hotLimits = *REGION_EXTENTS( pScreen, &pWin->borderSize); + pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize + : NullRegion; + CheckPhysLimits(pDev, pSprite->current, generateEvents, + confineToScreen, pScreen); + } +} + +Bool +PointerConfinedToScreen(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->sprite->confined; +} + +/** + * Update the sprite cursor to the given cursor. + * + * ChangeToCursor() will display the new cursor and free the old cursor (if + * applicable). If the provided cursor is already the updated cursor, nothing + * happens. + */ +static void +ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + ScreenPtr pScreen; + + if (cursor != pSprite->current) + { + if ((pSprite->current->bits->xhot != cursor->bits->xhot) || + (pSprite->current->bits->yhot != cursor->bits->yhot)) + CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined, + (ScreenPtr)NULL); +#ifdef PANORAMIX + /* XXX: is this really necessary?? (whot) */ + if (!noPanoramiXExtension) + pScreen = pSprite->screen; + else +#endif + pScreen = pSprite->hotPhys.pScreen; + + (*pScreen->DisplayCursor)(pDev, pScreen, cursor); + FreeCursor(pSprite->current, (Cursor)0); + pSprite->current = cursor; + pSprite->current->refcnt++; + } +} + +/** + * @returns true if b is a descendent of a + */ +Bool +IsParent(WindowPtr a, WindowPtr b) +{ + for (b = b->parent; b; b = b->parent) + if (b == a) return TRUE; + return FALSE; +} + +/** + * Update the cursor displayed on the screen. + * + * Called whenever a cursor may have changed shape or position. + */ +static void +PostNewCursor(DeviceIntPtr pDev) +{ + WindowPtr win; + GrabPtr grab = pDev->deviceGrab.grab; + SpritePtr pSprite = pDev->spriteInfo->sprite; + CursorPtr pCursor; + + if (syncEvents.playingEvents) + return; + if (grab) + { + if (grab->cursor) + { + ChangeToCursor(pDev, grab->cursor); + return; + } + if (IsParent(grab->window, pSprite->win)) + win = pSprite->win; + else + win = grab->window; + } + else + win = pSprite->win; + for (; win; win = win->parent) + { + if (win->optional) + { + pCursor = WindowGetDeviceCursor(win, pDev); + if (!pCursor && win->optional->cursor != NullCursor) + pCursor = win->optional->cursor; + if (pCursor) + { + ChangeToCursor(pDev, pCursor); + return; + } + } + } +} + + +/** + * @param dev device which you want to know its current root window + * @return root window where dev's sprite is located + */ +WindowPtr +GetCurrentRootWindow(DeviceIntPtr dev) +{ + return RootWindow(dev); +} + +/** + * @return window underneath the cursor sprite. + */ +WindowPtr +GetSpriteWindow(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->sprite->win; +} + +/** + * @return current sprite cursor. + */ +CursorPtr +GetSpriteCursor(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->sprite->current; +} + +/** + * Set x/y current sprite position in screen coordinates. + */ +void +GetSpritePosition(DeviceIntPtr pDev, int *px, int *py) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + *px = pSprite->hotPhys.x; + *py = pSprite->hotPhys.y; +} + +#ifdef PANORAMIX +int +XineramaGetCursorScreen(DeviceIntPtr pDev) +{ + if(!noPanoramiXExtension) { + return pDev->spriteInfo->sprite->screen->myNum; + } else { + return 0; + } +} +#endif /* PANORAMIX */ + +#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ + +static void +MonthChangedOrBadTime(InternalEvent *ev) +{ + /* 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 - ev->any.time) > TIMESLOP) + currentTime.months++; + else + ev->any.time = currentTime.milliseconds; +} + +static void +NoticeTime(InternalEvent *ev) +{ + if (ev->any.time < currentTime.milliseconds) + MonthChangedOrBadTime(ev); + currentTime.milliseconds = ev->any.time; + lastDeviceEventTime = currentTime; +} + +void +NoticeEventTime(InternalEvent *ev) +{ + if (!syncEvents.playingEvents) + NoticeTime(ev); +} + +/************************************************************************** + * The following procedures deal with synchronous events * + **************************************************************************/ + +/** + * EnqueueEvent is a device's processInputProc if a device is frozen. + * Instead of delivering the events to the client, the event is tacked onto a + * linked list for later delivery. + */ +void +EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) +{ + QdEventPtr tail = *syncEvents.pendtail; + QdEventPtr qe; + SpritePtr pSprite = device->spriteInfo->sprite; + int eventlen; + DeviceEvent *event = &ev->device_event; + + NoticeTime((InternalEvent*)event); + + /* Fix for key repeating bug. */ + if (device->key != NULL && device->key->xkbInfo != NULL && + event->type == ET_KeyRelease) + AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key); + + 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 (ev->any.type == ET_Motion) + ev->device_event.root = WindowTable[pSprite->hotPhys.pScreen->myNum]->drawable.id; + + eventinfo.event = ev; + eventinfo.device = device; + CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); + } + + if (event->type == ET_Motion) + { +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + event->root_x += panoramiXdataPtr[pSprite->screen->myNum].x - + panoramiXdataPtr[0].x; + event->root_y += panoramiXdataPtr[pSprite->screen->myNum].y - + panoramiXdataPtr[0].y; + } +#endif + pSprite->hotPhys.x = event->root_x; + pSprite->hotPhys.y = event->root_y; + /* do motion compression, but not if from different devices */ + if (tail && + (tail->event->any.type == ET_Motion) && + (tail->device == device) && + (tail->pScreen == pSprite->hotPhys.pScreen)) + { + DeviceEvent *tailev = &tail->event->device_event; + tailev->root_x = pSprite->hotPhys.x; + tailev->root_y = pSprite->hotPhys.y; + tailev->time = event->time; + tail->months = currentTime.months; + return; + } + } + + eventlen = event->length; + + qe = malloc(sizeof(QdEventRec) + eventlen); + if (!qe) + return; + qe->next = (QdEventPtr)NULL; + qe->device = device; + qe->pScreen = pSprite->hotPhys.pScreen; + qe->months = currentTime.months; + qe->event = (InternalEvent *)(qe + 1); + memcpy(qe->event, event, eventlen); + if (tail) + syncEvents.pendtail = &tail->next; + *syncEvents.pendtail = qe; +} + +/** + * Run through the list of events queued up in syncEvents. + * For each event do: + * If the device for this event is not frozen anymore, take it and process it + * as usually. + * After that, check if there's any devices in the list that are not frozen. + * If there is none, we're done. If there is at least one device that is not + * frozen, then re-run from the beginning of the event queue. + */ +static void +PlayReleasedEvents(void) +{ + QdEventPtr *prev, qe; + DeviceIntPtr dev; + DeviceIntPtr pDev; + + prev = &syncEvents.pending; + while ( (qe = *prev) ) + { + if (!qe->device->deviceGrab.sync.frozen) + { + *prev = qe->next; + pDev = qe->device; + if (*syncEvents.pendtail == *prev) + syncEvents.pendtail = prev; + if (qe->event->any.type == ET_Motion) + CheckVirtualMotion(pDev, qe, NullWindow); + syncEvents.time.months = qe->months; + syncEvents.time.milliseconds = qe->event->any.time; +#ifdef PANORAMIX + /* Translate back to the sprite screen since processInputProc + will translate from sprite screen to screen 0 upon reentry + to the DIX layer */ + if(!noPanoramiXExtension) { + DeviceEvent *ev = &qe->event->device_event; + switch(ev->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + ev->root_x += panoramiXdataPtr[0].x - + panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].x; + ev->root_y += panoramiXdataPtr[0].y - + panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].y; + break; + default: + break; + } + + } +#endif + (*qe->device->public.processInputProc)(qe->event, qe->device); + free(qe); + for (dev = inputInfo.devices; dev && dev->deviceGrab.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; + } +} + +/** + * Freeze or thaw the given devices. The device's processing proc is + * switched to either the real processing proc (in case of thawing) or an + * enqueuing processing proc (usually EnqueueEvent()). + * + * @param dev The device to freeze/thaw + * @param frozen True to freeze or false to thaw. + */ +static void +FreezeThaw(DeviceIntPtr dev, Bool frozen) +{ + dev->deviceGrab.sync.frozen = frozen; + if (frozen) + dev->public.processInputProc = dev->public.enqueueInputProc; + else + dev->public.processInputProc = dev->public.realInputProc; +} + +/** + * Unfreeze devices and replay all events to the respective clients. + * + * ComputeFreezes takes the first event in the device's frozen event queue. It + * runs up the sprite tree (spriteTrace) and searches for the window to replay + * the events from. If it is found, it checks for passive grabs one down from + * the window or delivers the events. + */ +static void +ComputeFreezes(void) +{ + DeviceIntPtr replayDev = syncEvents.replayDev; + int i; + WindowPtr w; + GrabPtr grab; + DeviceIntPtr dev; + + for (dev = inputInfo.devices; dev; dev = dev->next) + FreezeThaw(dev, dev->deviceGrab.sync.other || + (dev->deviceGrab.sync.state >= FROZEN)); + if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending)) + return; + syncEvents.playingEvents = TRUE; + if (replayDev) + { + DeviceEvent* event = replayDev->deviceGrab.sync.event; + + syncEvents.replayDev = (DeviceIntPtr)NULL; + + w = XYToWindow(replayDev, event->root_x, event->root_y); + for (i = 0; i < replayDev->spriteInfo->sprite->spriteTraceGood; i++) + { + if (syncEvents.replayWin == + replayDev->spriteInfo->sprite->spriteTrace[i]) + { + if (!CheckDeviceGrabs(replayDev, event, i+1)) { + if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) + DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); + else + DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, + NullWindow, replayDev); + } + goto playmore; + } + } + /* must not still be in the same stack */ + if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) + DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); + else + DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, + NullWindow, replayDev); + } +playmore: + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!dev->deviceGrab.sync.frozen) + { + PlayReleasedEvents(); + break; + } + } + syncEvents.playingEvents = FALSE; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (DevHasCursor(dev)) + { + /* the following may have been skipped during replay, + so do it now */ + if ((grab = dev->deviceGrab.grab) && grab->confineTo) + { + if (grab->confineTo->drawable.pScreen != + dev->spriteInfo->sprite->hotPhys.pScreen) + dev->spriteInfo->sprite->hotPhys.x = + dev->spriteInfo->sprite->hotPhys.y = 0; + ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE); + } + else + ConfineCursorToWindow(dev, + WindowTable[dev->spriteInfo->sprite->hotPhys.pScreen->myNum], + TRUE, FALSE); + PostNewCursor(dev); + } + } +} + +#ifdef RANDR +void +ScreenRestructured (ScreenPtr pScreen) +{ + GrabPtr grab; + DeviceIntPtr pDev; + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (!DevHasCursor(pDev)) + continue; + + /* GrabDevice doesn't have a confineTo field, so we don't need to + * worry about it. */ + if ((grab = pDev->deviceGrab.grab) && grab->confineTo) + { + if (grab->confineTo->drawable.pScreen + != pDev->spriteInfo->sprite->hotPhys.pScreen) + pDev->spriteInfo->sprite->hotPhys.x = pDev->spriteInfo->sprite->hotPhys.y = 0; + ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); + } + else + ConfineCursorToWindow(pDev, + WindowTable[pDev->spriteInfo->sprite->hotPhys.pScreen->myNum], + TRUE, FALSE); + } +} +#endif + +static void +CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) +{ + GrabPtr grab = thisDev->deviceGrab.grab; + DeviceIntPtr dev; + + if (thisMode == GrabModeSync) + thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT; + else + { /* free both if same client owns both */ + thisDev->deviceGrab.sync.state = THAWED; + if (thisDev->deviceGrab.sync.other && + (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) == + CLIENT_BITS(grab->resource))) + thisDev->deviceGrab.sync.other = NullGrab; + } + + if (IsMaster(thisDev)) + { + dev = GetPairedDevice(thisDev); + if (otherMode == GrabModeSync) + dev->deviceGrab.sync.other = grab; + else + { /* free both if same client owns both */ + if (dev->deviceGrab.sync.other && + (CLIENT_BITS(dev->deviceGrab.sync.other->resource) == + CLIENT_BITS(grab->resource))) + dev->deviceGrab.sync.other = NullGrab; + } + } + ComputeFreezes(); +} + +/** + * Save the device's master device id. This needs to be done + * if a client directly grabs a slave device that is attached to a master. For + * the duration of the grab, the device is detached, ungrabbing re-attaches it + * though. + * + * We store the ID of the master device only in case the master disappears + * while the device has a grab. + */ +static void +DetachFromMaster(DeviceIntPtr dev) +{ + if (!dev->u.master) + return; + + dev->saved_master_id = dev->u.master->id; + + AttachDevice(NULL, dev, NULL); +} + +static void +ReattachToOldMaster(DeviceIntPtr dev) +{ + DeviceIntPtr master = NULL; + + if (IsMaster(dev)) + return; + + dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess); + + if (master) + { + AttachDevice(serverClient, dev, master); + dev->saved_master_id = 0; + } +} + +/** + * Activate a pointer grab on the given device. A pointer grab will cause all + * core pointer events of this device to be delivered to the grabbing client only. + * No other device will send core events to the grab client while the grab is + * on, but core events will be sent to other clients. + * Can cause the cursor to change if a grab cursor is set. + * + * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab + * is an implicit grab caused by a ButtonPress event. + * + * @param mouse The device to grab. + * @param grab The grab structure, needs to be setup. + * @param autoGrab True if the grab was caused by a button down event and not + * explicitely by a client. + */ +void +ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, + TimeStamp time, Bool autoGrab) +{ + GrabInfoPtr grabinfo = &mouse->deviceGrab; + WindowPtr oldWin = (grabinfo->grab) ? + grabinfo->grab->window + : mouse->spriteInfo->sprite->win; + Bool isPassive = autoGrab & ~ImplicitGrabMask; + + /* slave devices need to float for the duration of the grab. */ + if (grab->grabtype == GRABTYPE_XI2 && + !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse)) + DetachFromMaster(mouse); + + if (grab->confineTo) + { + if (grab->confineTo->drawable.pScreen + != mouse->spriteInfo->sprite->hotPhys.pScreen) + mouse->spriteInfo->sprite->hotPhys.x = + mouse->spriteInfo->sprite->hotPhys.y = 0; + ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE); + } + DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab); + mouse->valuator->motionHintWindow = NullWindow; + if (syncEvents.playingEvents) + grabinfo->grabTime = syncEvents.time; + else + grabinfo->grabTime = time; + if (grab->cursor) + grab->cursor->refcnt++; + grabinfo->activeGrab = *grab; + grabinfo->grab = &grabinfo->activeGrab; + grabinfo->fromPassiveGrab = isPassive; + grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; + PostNewCursor(mouse); + CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode); +} + +/** + * Delete grab on given device, update the sprite. + * + * Extension devices are set up for ActivateKeyboardGrab(). + */ +void +DeactivatePointerGrab(DeviceIntPtr mouse) +{ + GrabPtr grab = mouse->deviceGrab.grab; + DeviceIntPtr dev; + Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab && + mouse->deviceGrab.implicitGrab); + + mouse->valuator->motionHintWindow = NullWindow; + mouse->deviceGrab.grab = NullGrab; + mouse->deviceGrab.sync.state = NOT_GRABBED; + mouse->deviceGrab.fromPassiveGrab = FALSE; + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->deviceGrab.sync.other == grab) + dev->deviceGrab.sync.other = NullGrab; + } + DoEnterLeaveEvents(mouse, mouse->id, grab->window, + mouse->spriteInfo->sprite->win, NotifyUngrab); + if (grab->confineTo) + ConfineCursorToWindow(mouse, RootWindow(mouse), FALSE, FALSE); + PostNewCursor(mouse); + if (grab->cursor) + FreeCursor(grab->cursor, (Cursor)0); + + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(mouse); + + ComputeFreezes(); +} + +/** + * Activate a keyboard grab on the given device. + * + * Extension devices have ActivateKeyboardGrab() set as their grabbing proc. + */ +void +ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool passive) +{ + GrabInfoPtr grabinfo = &keybd->deviceGrab; + WindowPtr oldWin; + + /* slave devices need to float for the duration of the grab. */ + if (grab->grabtype == GRABTYPE_XI2 && + !(passive & ImplicitGrabMask) && + !IsMaster(keybd)) + DetachFromMaster(keybd); + + if (grabinfo->grab) + oldWin = grabinfo->grab->window; + else if (keybd->focus) + oldWin = keybd->focus->win; + else + oldWin = keybd->spriteInfo->sprite->win; + if (oldWin == FollowKeyboardWin) + oldWin = keybd->focus->win; + if (keybd->valuator) + keybd->valuator->motionHintWindow = NullWindow; + DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab); + if (syncEvents.playingEvents) + grabinfo->grabTime = syncEvents.time; + else + grabinfo->grabTime = time; + grabinfo->activeGrab = *grab; + grabinfo->grab = &grabinfo->activeGrab; + grabinfo->fromPassiveGrab = passive; + grabinfo->implicitGrab = passive & ImplicitGrabMask; + CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode); +} + +/** + * Delete keyboard grab for the given device. + */ +void +DeactivateKeyboardGrab(DeviceIntPtr keybd) +{ + GrabPtr grab = keybd->deviceGrab.grab; + DeviceIntPtr dev; + WindowPtr focusWin = keybd->focus ? keybd->focus->win + : keybd->spriteInfo->sprite->win; + Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab && + keybd->deviceGrab.implicitGrab); + + if (focusWin == FollowKeyboardWin) + focusWin = inputInfo.keyboard->focus->win; + if (keybd->valuator) + keybd->valuator->motionHintWindow = NullWindow; + keybd->deviceGrab.grab = NullGrab; + keybd->deviceGrab.sync.state = NOT_GRABBED; + keybd->deviceGrab.fromPassiveGrab = FALSE; + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->deviceGrab.sync.other == grab) + dev->deviceGrab.sync.other = NullGrab; + } + DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab); + + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(keybd); + + ComputeFreezes(); +} + +void +AllowSome(ClientPtr client, + TimeStamp time, + DeviceIntPtr thisDev, + int newState) +{ + Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced; + TimeStamp grabTime; + DeviceIntPtr dev; + GrabInfoPtr devgrabinfo, + grabinfo = &thisDev->deviceGrab; + + thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client); + thisSynced = FALSE; + otherGrabbed = FALSE; + othersFrozen = FALSE; + grabTime = grabinfo->grabTime; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + devgrabinfo = &dev->deviceGrab; + + if (dev == thisDev) + continue; + if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client)) + { + if (!(thisGrabbed || otherGrabbed) || + (CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER)) + grabTime = devgrabinfo->grabTime; + otherGrabbed = TRUE; + if (grabinfo->sync.other == devgrabinfo->grab) + thisSynced = TRUE; + if (devgrabinfo->sync.state >= FROZEN) + othersFrozen = TRUE; + } + } + if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced)) + return; + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, grabTime) == EARLIER)) + return; + switch (newState) + { + case THAWED: /* Async */ + if (thisGrabbed) + grabinfo->sync.state = THAWED; + if (thisSynced) + grabinfo->sync.other = NullGrab; + ComputeFreezes(); + break; + case FREEZE_NEXT_EVENT: /* Sync */ + if (thisGrabbed) + { + grabinfo->sync.state = FREEZE_NEXT_EVENT; + if (thisSynced) + grabinfo->sync.other = NullGrab; + ComputeFreezes(); + } + break; + case THAWED_BOTH: /* AsyncBoth */ + if (othersFrozen) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + devgrabinfo = &dev->deviceGrab; + if (devgrabinfo->grab + && SameClient(devgrabinfo->grab, client)) + devgrabinfo->sync.state = THAWED; + if (devgrabinfo->sync.other && + SameClient(devgrabinfo->sync.other, client)) + devgrabinfo->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */ + if (othersFrozen) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + devgrabinfo = &dev->deviceGrab; + if (devgrabinfo->grab + && SameClient(devgrabinfo->grab, client)) + devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT; + if (devgrabinfo->sync.other + && SameClient(devgrabinfo->sync.other, client)) + devgrabinfo->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + case NOT_GRABBED: /* Replay */ + if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT) + { + if (thisSynced) + grabinfo->sync.other = NullGrab; + syncEvents.replayDev = thisDev; + syncEvents.replayWin = grabinfo->grab->window; + (*grabinfo->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; + devgrabinfo = &dev->deviceGrab; + if (devgrabinfo->grab + && SameClient(devgrabinfo->grab, client)) + devgrabinfo->sync.state = THAWED; + if (devgrabinfo->sync.other + && SameClient(devgrabinfo->sync.other, client)) + devgrabinfo->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + } +} + +/** + * Server-side protocol handling for AllowEvents request. + * + * Release some events from a frozen device. + */ +int +ProcAllowEvents(ClientPtr client) +{ + TimeStamp time; + DeviceIntPtr mouse = NULL; + DeviceIntPtr keybd = NULL; + REQUEST(xAllowEventsReq); + + REQUEST_SIZE_MATCH(xAllowEventsReq); + time = ClientTimeToServerTime(stuff->time); + + mouse = PickPointer(client); + keybd = PickKeyboard(client); + + 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; +} + +/** + * Deactivate grabs from any device that has been grabbed by the client. + */ +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->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) + { + (*dev->deviceGrab.DeactivateGrab)(dev); + done = FALSE; + } + } + } while (!done); +} + +/************************************************************************** + * The following procedures deal with delivering events * + **************************************************************************/ + +/** + * Deliver the given events to the given client. + * + * More than one event may be delivered at a time. This is the case with + * DeviceMotionNotifies which may be followed by DeviceValuator events. + * + * TryClientEvents() is the last station before actually writing the events to + * the socket. Anything that is not filtered here, will get delivered to the + * client. + * An event is only delivered if + * - mask and filter match up. + * - no other client has a grab on the device that caused the event. + * + * + * @param client The target client to deliver to. + * @param dev The device the event came from. May be NULL. + * @param pEvents The events to be delivered. + * @param count Number of elements in pEvents. + * @param mask Event mask as set by the window. + * @param filter Mask based on event type. + * @param grab Possible grab on the device that caused the event. + * + * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the + * client. + */ +int +TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, + int count, Mask mask, Mask filter, GrabPtr grab) +{ + int i; + int type; + +#ifdef DEBUG_EVENTS + ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s", + pEvents->u.u.type, pEvents->u.u.detail, mask, + client ? client->index : -1, + (client && client->clientGone) ? " (gone)" : ""); +#endif + + if (!client || client == serverClient || client->clientGone) { +#ifdef DEBUG_EVENTS + ErrorF(" not delivered to fake/dead client\n"); +#endif + return 0; + } + + if (filter != CantBeFiltered && !(mask & filter)) + { + #ifdef DEBUG_EVENTS + ErrorF(" filtered\n"); + #endif + return 0; + } + + if (grab && !SameClient(grab, client)) + { +#ifdef DEBUG_EVENTS + ErrorF(" not delivered due to grab\n"); +#endif + return -1; /* don't send, but notify caller */ + } + + type = pEvents->u.u.type; + if (type == MotionNotify) + { + if (mask & PointerMotionHintMask) + { + if (WID(dev->valuator->motionHintWindow) == + pEvents->u.keyButtonPointer.event) + { +#ifdef DEBUG_EVENTS + ErrorF("[dix] \n"); + ErrorF("[dix] 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; + } + } + else if (type == DeviceMotionNotify) + { + if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer*)pEvents, + mask) != 0) + return 1; + } else if (type == KeyPress) + { + if (EventIsKeyRepeat(pEvents)) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + xEvent release = *pEvents; + release.u.u.type = KeyRelease; + release.u.u.sequenceNumber = client->sequence; + WriteEventsToClient(client, 1, &release); +#ifdef DEBUG_EVENTS + ErrorF(" (plus fake core release for repeat)"); +#endif + } else + { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#endif + } + } + + } else if (type == DeviceKeyPress) + { + if (EventIsKeyRepeat(pEvents)) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + deviceKeyButtonPointer release = *(deviceKeyButtonPointer *)pEvents; + release.type = DeviceKeyRelease; + release.sequenceNumber = client->sequence; +#ifdef DEBUG_EVENTS + ErrorF(" (plus fake xi1 release for repeat)"); +#endif + WriteEventsToClient(client, 1, (xEvent *) &release); + } + else { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#endif + } + } + } + + 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)) + { + if (client->smart_priority < SMART_MAX_PRIORITY) + client->smart_priority++; + SetCriticalOutputPending(); + } + + WriteEventsToClient(client, count, pEvents); +#ifdef DEBUG_EVENTS + ErrorF("[dix] delivered\n"); +#endif + return 1; +} + +/** + * Deliver events to a window. At this point, we do not yet know if the event + * actually needs to be delivered. May activate a grab if the event is a + * button press. + * + * Core events are always delivered to the window owner. If the filter is + * something other than CantBeFiltered, the event is also delivered to other + * clients with the matching mask on the window. + * + * More than one event may be delivered at a time. This is the case with + * DeviceMotionNotifies which may be followed by DeviceValuator events. + * + * @param pWin The window that would get the event. + * @param pEvents The events to be delivered. + * @param count Number of elements in pEvents. + * @param filter Mask based on event type. + * @param grab Possible grab on the device that caused the event. + * + * @return Number of events delivered to various clients. + */ +int +DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent + *pEvents, int count, Mask filter, GrabPtr grab) +{ + 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; + + + /* Deliver to window owner */ + if ((filter == CantBeFiltered) || CORE_EVENT(pEvents)) + { + /* if nobody ever wants to see this event, skip some work */ + if (filter != CantBeFiltered && + !((wOtherEventMasks(pWin)|pWin->eventMask) & filter)) + return 0; + + if (IsInterferingGrab(wClient(pWin), pDev, pEvents)) + return 0; + + if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) + /* do nothing */; + else if ( (attempt = TryClientEvents(wClient(pWin), pDev, pEvents, + count, pWin->eventMask, + filter, grab)) ) + { + if (attempt > 0) + { + deliveries++; + client = wClient(pWin); + deliveryMask = pWin->eventMask; + } else + nondeliveries--; + } + } + + /* CantBeFiltered means only window owner gets the event */ + if (filter != CantBeFiltered) + { + if (CORE_EVENT(pEvents)) + other = (InputClients *)wOtherClients(pWin); + else if (XI2_EVENT(pEvents)) + { + OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + /* Has any client selected for the event? */ + if (!GetWindowXI2Mask(pDev, pWin, pEvents)) + return 0; + other = inputMasks->inputClients; + } else { + OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + /* Has any client selected for the event? */ + if (!inputMasks || + !(inputMasks->inputEvents[pDev->id] & filter)) + return 0; + + other = inputMasks->inputClients; + } + + for (; other; other = other->next) + { + Mask mask; + if (IsInterferingGrab(rClient(other), pDev, pEvents)) + continue; + + mask = GetEventMask(pDev, pEvents, other); + + if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, + pEvents, count)) + /* do nothing */; + else if ( (attempt = TryClientEvents(rClient(other), pDev, + pEvents, count, + mask, filter, grab)) ) + { + if (attempt > 0) + { + deliveries++; + client = rClient(other); + deliveryMask = mask; + } else + nondeliveries--; + } + } + } + /* + * Note that since core events are delivered first, an implicit grab may + * be activated on a core grab, stopping the XI events. + */ + if ((type == DeviceButtonPress || type == ButtonPress || + ((XI2_EVENT(pEvents) && ((xGenericEvent*)pEvents)->evtype == XI_ButtonPress))) + && deliveries + && (!grab)) + { + GrabRec tempGrab; + OtherInputMasks *inputMasks; + + memset(&tempGrab, 0, sizeof(GrabRec)); + tempGrab.next = NULL; + tempGrab.device = pDev; + 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; + tempGrab.type = type; + if (type == ButtonPress) + tempGrab.grabtype = GRABTYPE_CORE; + else if (type == DeviceButtonPress) + tempGrab.grabtype = GRABTYPE_XI; + else + { + tempGrab.type = ((xGenericEvent*)pEvents)->evtype; + tempGrab.grabtype = GRABTYPE_XI2; + } + + /* get the XI and XI2 device mask */ + inputMasks = wOtherInputMasks(pWin); + tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[pDev->id]: 0; + + if (inputMasks) + memcpy(tempGrab.xi2mask, inputMasks->xi2mask, + sizeof(tempGrab.xi2mask)); + + (*pDev->deviceGrab.ActivateGrab)(pDev, &tempGrab, + currentTime, TRUE | ImplicitGrabMask); + } + else if ((type == MotionNotify) && deliveries) + pDev->valuator->motionHintWindow = pWin; + else + { + if ((type == DeviceMotionNotify || type == DeviceButtonPress) && + deliveries) + CheckDeviceGrabAndHintWindow (pWin, type, + (deviceKeyButtonPointer*) pEvents, + grab, client, deliveryMask); + } + 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. +*/ + +#ifdef PANORAMIX +static int +XineramaTryClientEventsResult( + ClientPtr client, + GrabPtr grab, + Mask mask, + Mask filter +){ + if ((client) && (client != serverClient) && (!client->clientGone) && + ((filter == CantBeFiltered) || (mask & filter))) + { + if (grab && !SameClient(grab, client)) return -1; + else return 1; + } + return 0; +} +#endif + +/** + * Try to deliver events to the interested parties. + * + * @param pWin The window that would get the event. + * @param pEvents The events to be delivered. + * @param count Number of elements in pEvents. + * @param filter Mask based on event type. + * @param dontClient Don't deliver to the dontClient. + */ +int +MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents, + int count, Mask filter, ClientPtr dontClient) +{ + OtherClients *other; + + + if (pWin->eventMask & filter) + { + if (wClient(pWin) == dontClient) + return 0; +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) + return XineramaTryClientEventsResult( + wClient(pWin), NullGrab, pWin->eventMask, filter); +#endif + if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) + return 1; /* don't send, but pretend we did */ + return TryClientEvents(wClient(pWin), NULL, pEvents, count, + pWin->eventMask, filter, NullGrab); + } + for (other = wOtherClients(pWin); other; other = other->next) + { + if (other->mask & filter) + { + if (SameClient(other, dontClient)) + return 0; +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) + return XineramaTryClientEventsResult( + rClient(other), NullGrab, other->mask, filter); +#endif + if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, pEvents, + count)) + return 1; /* don't send, but pretend we did */ + return TryClientEvents(rClient(other), NULL, pEvents, count, + other->mask, filter, NullGrab); + } + } + return 2; +} + +static Window FindChildForEvent(DeviceIntPtr dev, WindowPtr event) +{ + SpritePtr pSprite = dev->spriteInfo->sprite; + WindowPtr w = pSprite->spriteTrace[pSprite->spriteTraceGood-1]; + Window child = None; + + /* 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 == event) + { + child = None; + break; + } + + if (w->parent == event) + { + child = w->drawable.id; + break; + } + w = w->parent; + } + return child; +} + +/** + * Adjust event fields to comply with the window properties. + * + * @param xE Event to be modified in place + * @param pWin The window to get the information from. + * @param child Child window setting for event (if applicable) + * @param calcChild If True, calculate the child window. + */ +void +FixUpEventFromWindow( + DeviceIntPtr pDev, + xEvent *xE, + WindowPtr pWin, + Window child, + Bool calcChild) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if (calcChild) + child = FindChildForEvent(pDev, pWin); + + if (XI2_EVENT(xE)) + { + xXIDeviceEvent* event = (xXIDeviceEvent*)xE; + + if (event->evtype == XI_RawKeyPress || + event->evtype == XI_RawKeyRelease || + event->evtype == XI_RawButtonPress || + event->evtype == XI_RawButtonRelease || + event->evtype == XI_RawMotion || + event->evtype == XI_DeviceChanged || + event->evtype == XI_HierarchyChanged || + event->evtype == XI_PropertyEvent) + return; + + event->root = RootWindow(pDev)->drawable.id; + event->event = pWin->drawable.id; + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + event->event_x = event->root_x - FP1616(pWin->drawable.x, 0); + event->event_y = event->root_y - FP1616(pWin->drawable.y, 0); + event->child = child; + } else + { + event->event_x = 0; + event->event_y = 0; + event->child = None; + } + + if (event->evtype == XI_Enter || event->evtype == XI_Leave || + event->evtype == XI_FocusIn || event->evtype == XI_FocusOut) + ((xXIEnterEvent*)event)->same_screen = + (pSprite->hot.pScreen == pWin->drawable.pScreen); + + } else + { + XE_KBPTR.root = RootWindow(pDev)->drawable.id; + XE_KBPTR.event = pWin->drawable.id; + if (pSprite->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; + } + } +} + +/** + * Return masks for EventIsDeliverable. + * @defgroup EventIsDeliverable return flags + * @{ + */ +#define XI_MASK (1 << 0) /**< XI mask set on window */ +#define CORE_MASK (1 << 1) /**< Core mask set on window */ +#define DONT_PROPAGATE_MASK (1 << 2) /**< DontPropagate mask set on window */ +#define XI2_MASK (1 << 3) /**< XI2 mask set on window */ +/* @} */ + +/** + * Check if a given event is deliverable at all on a given window. + * + * This function only checks if any client wants it, not for a specific + * client. + * + * @param[in] dev The device this event is being sent for. + * @param[in] event The event that is to be sent. + * @param[in] win The current event window. + * + * @return Bitmask of ::XI2_MASK, ::XI_MASK, ::CORE_MASK, and + * ::DONT_PROPAGATE_MASK. + */ +static int +EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win) +{ + int rc = 0; + int filter = 0; + int type; + OtherInputMasks *inputMasks = wOtherInputMasks(win); + xEvent ev; + + /* XXX: this makes me gag */ + type = GetXI2Type(event); + ev.u.u.type = GenericEvent; /* GetEventFilter only cares about type and evtype*/ + ((xGenericEvent*)&ev)->extension = IReqCode; + ((xGenericEvent*)&ev)->evtype = type; + filter = GetEventFilter(dev, &ev); + if (type && inputMasks && + ((inputMasks->xi2mask[XIAllDevices][type/8] & filter) || + ((inputMasks->xi2mask[XIAllMasterDevices][type/8] & filter) && IsMaster(dev)) || + (inputMasks->xi2mask[dev->id][type/8] & filter))) + rc |= XI2_MASK; + + type = GetXIType(event); + ev.u.u.type = type; + filter = GetEventFilter(dev, &ev); + + /* Check for XI mask */ + if (type && inputMasks && + (inputMasks->deliverableEvents[dev->id] & filter) && + (inputMasks->inputEvents[dev->id] & filter)) + rc |= XI_MASK; + + /* Check for XI DontPropagate mask */ + if (type && inputMasks && + (inputMasks->dontPropagateMask[dev->id] & filter)) + rc |= DONT_PROPAGATE_MASK; + + /* Check for core mask */ + type = GetCoreType(event); + if (type && (win->deliverableEvents & filter) && + ((wOtherEventMasks(win) | win->eventMask) & filter)) + rc |= CORE_MASK; + + /* Check for core DontPropagate mask */ + if (type && (filter & wDontPropagateMask(win))) + rc |= DONT_PROPAGATE_MASK; + + return rc; +} + +/** + * Deliver events caused by input devices. + * + * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is + * called directly from the processInputProc. + * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call + * DeliverDeviceEvents. + * For focused events, DeliverFocusedEvent is called first, and _may_ call + * DeliverDeviceEvents. + * + * @param pWin Window to deliver event to. + * @param event The events to deliver, not yet in wire format. + * @param grab Possible grab on a device. + * @param stopAt Don't recurse up to the root window. + * @param dev The device that is responsible for the event. + * + * @see DeliverGrabbedEvent + * @see DeliverFocusedEvent + */ +int +DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, + WindowPtr stopAt, DeviceIntPtr dev) +{ + Window child = None; + Mask filter; + int deliveries = 0; + xEvent core; + xEvent *xE = NULL; + int rc, mask, count = 0; + + CHECKEVENT(event); + + while (pWin) + { + if ((mask = EventIsDeliverable(dev, event, pWin))) + { + /* XI2 events first */ + if (mask & XI2_MASK) + { + xEvent *xi2 = NULL; + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + /* XXX: XACE */ + filter = GetEventFilter(dev, xi2); + FixUpEventFromWindow(dev, xi2, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1, + filter, grab); + free(xi2); + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DDE (%d).\n", + dev->name, rc); + } + + /* XI events */ + if (mask & XI_MASK) + { + rc = EventToXI(event, &xE, &count); + if (rc == Success) { + if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, xE, count) == Success) { + filter = GetEventFilter(dev, xE); + FixUpEventFromWindow(dev, xE, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, xE, count, + filter, grab); + if (deliveries > 0) + goto unwind; + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DDE (%d, %d). Skipping delivery.\n", + dev->name, event->any.type, rc); + } + + /* Core event */ + if ((mask & CORE_MASK) && IsMaster(dev) && dev->coreEvents) + { + rc = EventToCore(event, &core); + if (rc == Success) { + if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, &core, 1) == Success) { + filter = GetEventFilter(dev, &core); + FixUpEventFromWindow(dev, &core, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, &core, 1, + filter, grab); + if (deliveries > 0) + goto unwind; + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: Core conversion failed in DDE (%d, %d).\n", + dev->name, event->any.type, rc); + } + + if ((deliveries < 0) || (pWin == stopAt) || + (mask & DONT_PROPAGATE_MASK)) + { + deliveries = 0; + goto unwind; + } + } + + child = pWin->drawable.id; + pWin = pWin->parent; + } + +unwind: + free(xE); + return deliveries; +} + +#undef XI_MASK +#undef CORE_MASK +#undef DONT_PROPAGATE_MASK + +/** + * Deliver event to a window and it's immediate parent. Used for most window + * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that + * propagate up the tree or extension events + * + * In case of a ReparentNotify event, the event will be delivered to the + * otherParent as well. + * + * @param pWin Window to deliver events to. + * @param xE Events to deliver. + * @param count number of events in xE. + * @param otherParent Used for ReparentNotify events. + */ +int +DeliverEvents(WindowPtr pWin, xEvent *xE, int count, + WindowPtr otherParent) +{ + Mask filter; + int deliveries; + DeviceIntRec dummy; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) + return count; +#endif + + if (!count) + return 0; + + dummy.id = XIAllDevices; + filter = GetEventFilter(&dummy, xE); + if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify)) + xE->u.destroyNotify.event = pWin->drawable.id; + if (filter != StructureAndSubMask) + return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, NullGrab); + deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count, + StructureNotifyMask, NullGrab); + if (pWin->parent) + { + xE->u.destroyNotify.event = pWin->parent->drawable.id; + deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count, + SubstructureNotifyMask, NullGrab); + if (xE->u.u.type == ReparentNotify) + { + xE->u.destroyNotify.event = otherParent->drawable.id; + deliveries += DeliverEventsToWindow(&dummy, + otherParent, xE, count, SubstructureNotifyMask, + NullGrab); + } + } + return deliveries; +} + + +static Bool +PointInBorderSize(WindowPtr pWin, int x, int y) +{ + BoxRec box; + + if(POINT_IN_REGION(pWin->drawable.pScreen, &pWin->borderSize, x, y, &box)) + return TRUE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && + XineramaSetWindowPntrs(inputInfo.pointer, pWin)) { + SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite; + int i; + + for(i = 1; i < PanoramiXNumScreens; i++) { + if(POINT_IN_REGION(pSprite->screen, + &pSprite->windows[i]->borderSize, + x + panoramiXdataPtr[0].x - panoramiXdataPtr[i].x, + y + panoramiXdataPtr[0].y - panoramiXdataPtr[i].y, + &box)) + return TRUE; + } + } +#endif + return FALSE; +} + +/** + * Traversed from the root window to the window at the position x/y. While + * traversing, it sets up the traversal history in the spriteTrace array. + * After completing, the spriteTrace history is set in the following way: + * spriteTrace[0] ... root window + * spriteTrace[1] ... top level window that encloses x/y + * ... + * spriteTrace[spriteTraceGood - 1] ... window at x/y + * + * @returns the window at the given coordinates. + */ +static WindowPtr +XYToWindow(DeviceIntPtr pDev, int x, int y) +{ + WindowPtr pWin; + BoxRec box; + SpritePtr pSprite; + + pSprite = pDev->spriteInfo->sprite; + pSprite->spriteTraceGood = 1; /* root window still there */ + pWin = RootWindow(pDev)->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(pWin->drawable.pScreen, + wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box)) +#ifdef ROOTLESS + /* In rootless mode windows may be offscreen, even when + * they're in X's stack. (E.g. if the native window system + * implements some form of virtual desktop system). + */ + && !pWin->rootlessUnhittable +#endif + ) + { + if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize) + { + pSprite->spriteTraceSize += 10; + pSprite->spriteTrace = realloc(pSprite->spriteTrace, + pSprite->spriteTraceSize*sizeof(WindowPtr)); + } + pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin; + pWin = pWin->firstChild; + } + else + pWin = pWin->nextSib; + } + return pSprite->spriteTrace[pSprite->spriteTraceGood-1]; +} + +/** + * Ungrab a currently FocusIn grabbed device and grab the device on the + * given window. If the win given is the NoneWin, the device is ungrabbed if + * applicable and FALSE is returned. + * + * @returns TRUE if the device has been grabbed, or FALSE otherwise. + */ +BOOL +ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) +{ + BOOL rc = FALSE; + DeviceEvent event; + + if (dev->deviceGrab.grab && + dev->deviceGrab.fromPassiveGrab && + dev->deviceGrab.grab->type == XI_Enter) + { + if (dev->deviceGrab.grab->window == win || + IsParent(dev->deviceGrab.grab->window, win)) + return FALSE; + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + (*dev->deviceGrab.DeactivateGrab)(dev); + } + + if (win == NoneWin || win == PointerRootWin) + return FALSE; + + memset(&event, 0, sizeof(DeviceEvent)); + event.header = ET_Internal; + event.type = ET_FocusIn; + event.length = sizeof(DeviceEvent); + event.time = GetTimeInMillis(); + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; + rc = CheckPassiveGrabsOnWindow(win, dev, &event, FALSE); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + return rc; +} + +/** + * Ungrab a currently Enter grabbed device and grab the device for the given + * window. + * + * @returns TRUE if the device has been grabbed, or FALSE otherwise. + */ +static BOOL +ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) +{ + BOOL rc = FALSE; + DeviceEvent event; + + if (dev->deviceGrab.grab && + dev->deviceGrab.fromPassiveGrab && + dev->deviceGrab.grab->type == XI_Enter) + { + if (dev->deviceGrab.grab->window == win || + IsParent(dev->deviceGrab.grab->window, win)) + return FALSE; + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + (*dev->deviceGrab.DeactivateGrab)(dev); + } + + memset(&event, 0, sizeof(DeviceEvent)); + event.header = ET_Internal; + event.type = ET_Enter; + event.length = sizeof(DeviceEvent); + event.time = GetTimeInMillis(); + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; + rc = CheckPassiveGrabsOnWindow(win, dev, &event, FALSE); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab); + + return rc; +} + +/** + * Update the sprite coordinates based on the event. Update the cursor + * position, then update the event with the new coordinates that may have been + * changed. If the window underneath the sprite has changed, change to new + * cursor and send enter/leave events. + * + * CheckMotion() will not do anything and return FALSE if the event is not a + * pointer event. + * + * @return TRUE if the sprite has moved or FALSE otherwise. + */ +Bool +CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev) +{ + WindowPtr prevSpriteWin, newSpriteWin; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + CHECKEVENT(ev); + + prevSpriteWin = pSprite->win; + + if (ev && !syncEvents.playingEvents) + { + /* GetPointerEvents() guarantees that pointer events have the correct + rootX/Y set already. */ + switch (ev->type) + { + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_Motion: + break; + default: + /* all other events return FALSE */ + return FALSE; + } + + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + /* Motion events entering DIX get translated to Screen 0 + coordinates. Replayed events have already been + translated since they've entered DIX before */ + ev->root_x += panoramiXdataPtr[pSprite->screen->myNum].x - + panoramiXdataPtr[0].x; + ev->root_y += panoramiXdataPtr[pSprite->screen->myNum].y - + panoramiXdataPtr[0].y; + } else +#endif + { + if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) + { + pSprite->hot.pScreen = pSprite->hotPhys.pScreen; + RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum]; + } + } + + pSprite->hot.x = ev->root_x; + pSprite->hot.y = ev->root_y; + if (pSprite->hot.x < pSprite->physLimits.x1) + pSprite->hot.x = pSprite->physLimits.x1; + else if (pSprite->hot.x >= pSprite->physLimits.x2) + pSprite->hot.x = pSprite->physLimits.x2 - 1; + if (pSprite->hot.y < pSprite->physLimits.y1) + pSprite->hot.y = pSprite->physLimits.y1; + else if (pSprite->hot.y >= pSprite->physLimits.y2) + pSprite->hot.y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y); + pSprite->hotPhys = pSprite->hot; + + if ((pSprite->hotPhys.x != ev->root_x) || + (pSprite->hotPhys.y != ev->root_y)) + { +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + XineramaSetCursorPosition( + pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); + } else +#endif + { + (*pSprite->hotPhys.pScreen->SetCursorPosition)( + pDev, pSprite->hotPhys.pScreen, + pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); + } + } + + ev->root_x = pSprite->hot.x; + ev->root_y = pSprite->hot.y; + } + + newSpriteWin = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y); + + if (newSpriteWin != prevSpriteWin) + { + int sourceid; + if (!ev) { + UpdateCurrentTimeIf(); + sourceid = pDev->id; /* when from WindowsRestructured */ + } else + sourceid = ev->sourceid; + + if (prevSpriteWin != NullWindow) { + if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin)) + DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin, + newSpriteWin, NotifyNormal); + } + /* set pSprite->win after ActivateEnterGrab, otherwise + sprite window == grab_window and no enter/leave events are + sent. */ + pSprite->win = newSpriteWin; + PostNewCursor(pDev); + return FALSE; + } + return TRUE; +} + +/** + * Windows have restructured, we need to update the sprite position and the + * sprite's cursor. + */ +void +WindowsRestructured(void) +{ + DeviceIntPtr pDev = inputInfo.devices; + while(pDev) + { + if (IsMaster(pDev) || !pDev->u.master) + CheckMotion(NULL, pDev); + pDev = pDev->next; + } +} + +#ifdef PANORAMIX +/* This was added to support reconfiguration under Xdmx. The problem is + * that if the 0th screen (i.e., WindowTable[0]) is moved to an origin + * other than 0,0, the information in the private sprite structure must + * be updated accordingly, or XYToWindow (and other routines) will not + * compute correctly. */ +void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff) +{ + GrabPtr grab; + DeviceIntPtr pDev; + SpritePtr pSprite; + + if (noPanoramiXExtension) return; + + pDev = inputInfo.devices; + while(pDev) + { + if (DevHasCursor(pDev)) + { + pSprite = pDev->spriteInfo->sprite; + pSprite->hot.x -= xoff; + pSprite->hot.y -= yoff; + + pSprite->hotPhys.x -= xoff; + pSprite->hotPhys.y -= yoff; + + pSprite->hotLimits.x1 -= xoff; + pSprite->hotLimits.y1 -= yoff; + pSprite->hotLimits.x2 -= xoff; + pSprite->hotLimits.y2 -= yoff; + + if (REGION_NOTEMPTY(pSprite->screen, &pSprite->Reg1)) + REGION_TRANSLATE(pSprite->screen, &pSprite->Reg1, xoff, yoff); + if (REGION_NOTEMPTY(pSprite->screen, &pSprite->Reg2)) + REGION_TRANSLATE(pSprite->screen, &pSprite->Reg2, xoff, yoff); + + /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */ + if ((grab = pDev->deviceGrab.grab) && grab->confineTo) { + if (grab->confineTo->drawable.pScreen + != pSprite->hotPhys.pScreen) + pSprite->hotPhys.x = pSprite->hotPhys.y = 0; + ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); + } else + ConfineCursorToWindow( + pDev, + WindowTable[pSprite->hotPhys.pScreen->myNum], + TRUE, FALSE); + + } + pDev = pDev->next; + } +} +#endif + +/** + * Initialize a sprite for the given device and set it to some sane values. If + * the device already has a sprite alloc'd, don't realloc but just reset to + * default values. + * If a window is supplied, the sprite will be initialized with the window's + * cursor and positioned in the center of the window's screen. The root window + * is a good choice to pass in here. + * + * It's a good idea to call it only for pointer devices, unless you have a + * really talented keyboard. + * + * @param pDev The device to initialize. + * @param pWin The window where to generate the sprite in. + * + */ +void +InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin) +{ + SpritePtr pSprite; + ScreenPtr pScreen; + CursorPtr pCursor; + + if (!pDev->spriteInfo->sprite) + { + DeviceIntPtr it; + + pDev->spriteInfo->sprite = (SpritePtr)calloc(1, sizeof(SpriteRec)); + if (!pDev->spriteInfo->sprite) + FatalError("InitializeSprite: failed to allocate sprite struct"); + + /* We may have paired another device with this device before our + * device had a actual sprite. We need to check for this and reset the + * sprite field for all paired devices. + * + * The VCK is always paired with the VCP before the VCP has a sprite. + */ + for (it = inputInfo.devices; it; it = it->next) + { + if (it->spriteInfo->paired == pDev) + it->spriteInfo->sprite = pDev->spriteInfo->sprite; + } + if (inputInfo.keyboard->spriteInfo->paired == pDev) + inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite; + } + + pSprite = pDev->spriteInfo->sprite; + pDev->spriteInfo->spriteOwner = TRUE; + + pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr)NULL; + pSprite->hot.pScreen = pScreen; + pSprite->hotPhys.pScreen = pScreen; + if (pScreen) + { + pSprite->hotPhys.x = pScreen->width / 2; + pSprite->hotPhys.y = pScreen->height / 2; + pSprite->hotLimits.x2 = pScreen->width; + pSprite->hotLimits.y2 = pScreen->height; + } + + pSprite->hot = pSprite->hotPhys; + pSprite->win = pWin; + + if (pWin) + { + pCursor = wCursor(pWin); + pSprite->spriteTrace = (WindowPtr *)calloc(1, 32*sizeof(WindowPtr)); + if (!pSprite->spriteTrace) + FatalError("Failed to allocate spriteTrace"); + pSprite->spriteTraceSize = 32; + + RootWindow(pDev) = pWin; + pSprite->spriteTraceGood = 1; + + pSprite->pEnqueueScreen = pScreen; + pSprite->pDequeueScreen = pSprite->pEnqueueScreen; + + } else { + pCursor = NullCursor; + pSprite->spriteTrace = NULL; + pSprite->spriteTraceSize = 0; + pSprite->spriteTraceGood = 0; + pSprite->pEnqueueScreen = screenInfo.screens[0]; + pSprite->pDequeueScreen = pSprite->pEnqueueScreen; + } + if (pCursor) + pCursor->refcnt++; + if (pSprite->current) + FreeCursor(pSprite->current, None); + pSprite->current = pCursor; + + if (pScreen) + { + (*pScreen->RealizeCursor) ( pDev, pScreen, pSprite->current); + (*pScreen->CursorLimits) ( pDev, pScreen, pSprite->current, + &pSprite->hotLimits, &pSprite->physLimits); + pSprite->confined = FALSE; + + (*pScreen->ConstrainCursor) (pDev, pScreen, + &pSprite->physLimits); + (*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x, + pSprite->hot.y, + FALSE); + (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); + } +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + pSprite->hotLimits.x1 = -panoramiXdataPtr[0].x; + pSprite->hotLimits.y1 = -panoramiXdataPtr[0].y; + pSprite->hotLimits.x2 = PanoramiXPixWidth - panoramiXdataPtr[0].x; + pSprite->hotLimits.y2 = PanoramiXPixHeight - panoramiXdataPtr[0].y; + pSprite->physLimits = pSprite->hotLimits; + pSprite->confineWin = NullWindow; + pSprite->hotShape = NullRegion; + pSprite->screen = pScreen; + /* gotta UNINIT these someplace */ + REGION_NULL(pScreen, &pSprite->Reg1); + REGION_NULL(pScreen, &pSprite->Reg2); + } +#endif +} + +/** + * Update the mouse sprite info when the server switches from a pScreen to another. + * Otherwise, the pScreen of the mouse sprite is never updated when we switch + * from a pScreen to another. Never updating the pScreen of the mouse sprite + * implies that windows that are in pScreen whose pScreen->myNum >0 will never + * get pointer events. This is because in CheckMotion(), sprite.hotPhys.pScreen + * always points to the first pScreen it has been set by + * DefineInitialRootWindow(). + * + * Calling this function is useful for use cases where the server + * has more than one pScreen. + * This function is similar to DefineInitialRootWindow() but it does not + * reset the mouse pointer position. + * @param win must be the new pScreen we are switching to. + */ +void +UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + SpritePtr pSprite = NULL; + WindowPtr win = NULL; + CursorPtr pCursor; + if (!pScreen) + return ; + + if (!pDev->spriteInfo->sprite) + return; + + pSprite = pDev->spriteInfo->sprite; + + win = WindowTable[pScreen->myNum]; + + pSprite->hotPhys.pScreen = pScreen; + pSprite->hot = pSprite->hotPhys; + pSprite->hotLimits.x2 = pScreen->width; + pSprite->hotLimits.y2 = pScreen->height; + pSprite->win = win; + pCursor = wCursor(win); + if (pCursor) + pCursor->refcnt++; + if (pSprite->current) + FreeCursor(pSprite->current, 0); + pSprite->current = pCursor; + pSprite->spriteTraceGood = 1; + pSprite->spriteTrace[0] = win; + (*pScreen->CursorLimits) (pDev, + pScreen, + pSprite->current, + &pSprite->hotLimits, + &pSprite->physLimits); + pSprite->confined = FALSE; + (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits); + (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + pSprite->hotLimits.x1 = -panoramiXdataPtr[0].x; + pSprite->hotLimits.y1 = -panoramiXdataPtr[0].y; + pSprite->hotLimits.x2 = PanoramiXPixWidth - panoramiXdataPtr[0].x; + pSprite->hotLimits.y2 = PanoramiXPixHeight - panoramiXdataPtr[0].y; + pSprite->physLimits = pSprite->hotLimits; + pSprite->screen = pScreen; + } +#endif +} + +/* + * 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) +{ + DeviceIntPtr pDev; + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + if (DevHasCursor(pDev)) + PostNewCursor(pDev); +} + +void +NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + pSprite->hotPhys.x = x; + pSprite->hotPhys.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + pSprite->hotPhys.x += panoramiXdataPtr[newScreen->myNum].x - + panoramiXdataPtr[0].x; + pSprite->hotPhys.y += panoramiXdataPtr[newScreen->myNum].y - + panoramiXdataPtr[0].y; + if (newScreen != pSprite->screen) { + pSprite->screen = newScreen; + /* Make sure we tell the DDX to update its copy of the screen */ + if(pSprite->confineWin) + XineramaConfineCursorToWindow(pDev, + pSprite->confineWin, TRUE); + else + XineramaConfineCursorToWindow(pDev, WindowTable[0], TRUE); + /* if the pointer wasn't confined, the DDX won't get + told of the pointer warp so we reposition it here */ + if(!syncEvents.playingEvents) + (*pSprite->screen->SetCursorPosition)( + pDev, + pSprite->screen, + pSprite->hotPhys.x + panoramiXdataPtr[0].x - + panoramiXdataPtr[pSprite->screen->myNum].x, + pSprite->hotPhys.y + panoramiXdataPtr[0].y - + panoramiXdataPtr[pSprite->screen->myNum].y, FALSE); + } + } else +#endif + if (newScreen != pSprite->hotPhys.pScreen) + ConfineCursorToWindow(pDev, WindowTable[newScreen->myNum], + TRUE, FALSE); +} + +#ifdef PANORAMIX + +static Bool +XineramaPointInWindowIsVisible( + WindowPtr pWin, + int x, + int y +) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + BoxRec box; + int i, xoff, yoff; + + if (!pWin->realized) return FALSE; + + if (POINT_IN_REGION(pScreen, &pWin->borderClip, x, y, &box)) + return TRUE; + + if(!XineramaSetWindowPntrs(inputInfo.pointer, pWin)) return FALSE; + + xoff = x + panoramiXdataPtr[0].x; + yoff = y + panoramiXdataPtr[0].y; + + for(i = 1; i < PanoramiXNumScreens; i++) { + pWin = inputInfo.pointer->spriteInfo->sprite->windows[i]; + pScreen = pWin->drawable.pScreen; + x = xoff - panoramiXdataPtr[i].x; + y = yoff - panoramiXdataPtr[i].y; + + if(POINT_IN_REGION(pScreen, &pWin->borderClip, x, y, &box) + && (!wInputShape(pWin) || + POINT_IN_REGION(pWin->drawable.pScreen, + wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box))) + return TRUE; + + } + + return FALSE; +} + +static int +XineramaWarpPointer(ClientPtr client) +{ + WindowPtr dest = NULL; + int x, y, rc; + SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; + + REQUEST(xWarpPointerReq); + + + if (stuff->dstWid != None) { + rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess); + if (rc != Success) + return rc; + } + x = pSprite->hotPhys.x; + y = pSprite->hotPhys.y; + + if (stuff->srcWid != None) + { + int winX, winY; + XID winID = stuff->srcWid; + WindowPtr source; + + rc = dixLookupWindow(&source, winID, client, DixReadAccess); + if (rc != Success) + return rc; + + winX = source->drawable.x; + winY = source->drawable.y; + if(source == WindowTable[0]) { + winX -= panoramiXdataPtr[0].x; + winY -= panoramiXdataPtr[0].y; + } + if (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) || + !XineramaPointInWindowIsVisible(source, x, y)) + return Success; + } + if (dest) { + x = dest->drawable.x; + y = dest->drawable.y; + if(dest == WindowTable[0]) { + x -= panoramiXdataPtr[0].x; + y -= panoramiXdataPtr[0].y; + } + } + + x += stuff->dstX; + y += stuff->dstY; + + if (x < pSprite->physLimits.x1) + x = pSprite->physLimits.x1; + else if (x >= pSprite->physLimits.x2) + x = pSprite->physLimits.x2 - 1; + if (y < pSprite->physLimits.y1) + y = pSprite->physLimits.y1; + else if (y >= pSprite->physLimits.y2) + y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y); + + XineramaSetCursorPosition(PickPointer(client), x, y, TRUE); + + return Success; +} + +#endif + + +/** + * Server-side protocol handling for WarpPointer request. + * Warps the cursor position to the coordinates given in the request. + */ +int +ProcWarpPointer(ClientPtr client) +{ + WindowPtr dest = NULL; + int x, y, rc; + ScreenPtr newScreen; + DeviceIntPtr dev, tmp; + SpritePtr pSprite; + + REQUEST(xWarpPointerReq); + REQUEST_SIZE_MATCH(xWarpPointerReq); + + dev = PickPointer(client); + + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { + if ((tmp == dev) || (!IsMaster(tmp) && tmp->u.master == dev)) { + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess); + if (rc != Success) + return rc; + } + } + + if (dev->u.lastSlave) + dev = dev->u.lastSlave; + pSprite = dev->spriteInfo->sprite; + +#ifdef PANORAMIX + if(!noPanoramiXExtension) + return XineramaWarpPointer(client); +#endif + + if (stuff->dstWid != None) { + rc = dixLookupWindow(&dest, stuff->dstWid, client, DixGetAttrAccess); + if (rc != Success) + return rc; + } + x = pSprite->hotPhys.x; + y = pSprite->hotPhys.y; + + if (stuff->srcWid != None) + { + int winX, winY; + XID winID = stuff->srcWid; + WindowPtr source; + + rc = dixLookupWindow(&source, winID, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + winX = source->drawable.x; + winY = source->drawable.y; + if (source->drawable.pScreen != pSprite->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 = pSprite->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 == pSprite->hotPhys.pScreen) + { + if (x < pSprite->physLimits.x1) + x = pSprite->physLimits.x1; + else if (x >= pSprite->physLimits.x2) + x = pSprite->physLimits.x2 - 1; + if (y < pSprite->physLimits.y1) + y = pSprite->physLimits.y1; + else if (y >= pSprite->physLimits.y2) + y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(dev, pSprite->hotShape, &x, &y); + (*newScreen->SetCursorPosition)(dev, newScreen, x, y, TRUE); + } + else if (!PointerConfinedToScreen(dev)) + { + NewCurrentScreen(dev, newScreen, x, y); + } + return Success; +} + +static Bool +BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin) +{ + if(REGION_NOTEMPTY(pDev->spriteInfo->sprite->hotPhys.pScreen, &pWin->borderSize)) + return TRUE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) { + int i; + + for(i = 1; i < PanoramiXNumScreens; i++) { + if(REGION_NOTEMPTY(pDev->spriteInfo->sprite->screen, + &pDev->spriteInfo->sprite->windows[i]->borderSize)) + return TRUE; + } + } +#endif + return FALSE; +} + +/** + * "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a + * passive grab set on the window to be activated. + * If a passive grab is activated, the event will be delivered to the client. + * + * @param pWin The window that may be subject to a passive grab. + * @param device Device that caused the event. + * @param event The current device event. + * @param checkCore Check for core grabs too. + */ + +static Bool +CheckPassiveGrabsOnWindow( + WindowPtr pWin, + DeviceIntPtr device, + DeviceEvent *event, + BOOL checkCore) +{ + GrabPtr grab = wPassiveGrabs(pWin); + GrabRec tempGrab; + GrabInfoPtr grabinfo; +#define CORE_MATCH 0x1 +#define XI_MATCH 0x2 +#define XI2_MATCH 0x4 + int match = 0; + + if (device->deviceGrab.grab) + return FALSE; + + if (!grab) + return FALSE; + /* Fill out the grab details, but leave the type for later before + * comparing */ + tempGrab.window = pWin; + tempGrab.device = device; + tempGrab.detail.exact = event->detail.key; + tempGrab.detail.pMask = NULL; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.next = NULL; + for (; grab; grab = grab->next) + { + DeviceIntPtr gdev; + XkbSrvInfoPtr xkbi = NULL; + Mask mask = 0; + + gdev= grab->modifierDevice; + if (grab->grabtype == GRABTYPE_CORE) + { + if (IsPointerDevice(device)) + gdev = GetPairedDevice(device); + else + gdev = device; + } else if (grab->grabtype == GRABTYPE_XI2) + { + /* if the device is an attached slave device, gdev must be the + * attached master keyboard. Since the slave may have been + * reattached after the grab, the modifier device may not be the + * same. */ + if (!IsMaster(grab->device) && device->u.master) + gdev = GetMaster(device, MASTER_KEYBOARD); + } + + + if (gdev && gdev->key) + xkbi= gdev->key->xkbInfo; + tempGrab.modifierDevice = grab->modifierDevice; + tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0; + + /* Check for XI2 and XI grabs first */ + tempGrab.type = GetXI2Type((InternalEvent*)event); + tempGrab.grabtype = GRABTYPE_XI2; + if (GrabMatchesSecond(&tempGrab, grab, FALSE)) + match = XI2_MATCH; + + tempGrab.detail.exact = event->detail.key; + if (!match) + { + tempGrab.type = GetXIType((InternalEvent*)event); + tempGrab.grabtype = GRABTYPE_XI; + if (GrabMatchesSecond(&tempGrab, grab, FALSE)) + match = XI_MATCH; + } + + /* Check for a core grab (ignore the device when comparing) */ + if (!match && checkCore) + { + tempGrab.grabtype = GRABTYPE_CORE; + if ((tempGrab.type = GetCoreType((InternalEvent*)event)) && + (GrabMatchesSecond(&tempGrab, grab, TRUE))) + match = CORE_MATCH; + } + + if (match && (!grab->confineTo || + (grab->confineTo->realized && + BorderSizeNotEmpty(device, grab->confineTo)))) + { + int rc, count = 0; + xEvent *xE = NULL; + xEvent core; + + event->corestate &= 0x1f00; + event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00); + grabinfo = &device->deviceGrab; + /* In some cases a passive core grab may exist, but the client + * already has a core grab on some other device. In this case we + * must not get the grab, otherwise we may never ungrab the + * device. + */ + + if (grab->grabtype == GRABTYPE_CORE) + { + DeviceIntPtr other; + BOOL interfering = FALSE; + + /* A passive grab may have been created for a different device + than it is assigned to at this point in time. + Update the grab's device and modifier device to reflect the + current state. + Since XGrabDeviceButton requires to specify the + modifierDevice explicitly, we don't override this choice. + */ + if (tempGrab.type < GenericEvent) + { + grab->device = device; + grab->modifierDevice = GetPairedDevice(device); + } + + for (other = inputInfo.devices; other; other = other->next) + { + GrabPtr othergrab = other->deviceGrab.grab; + if (othergrab && othergrab->grabtype == GRABTYPE_CORE && + SameClient(grab, rClient(othergrab)) && + ((IsPointerDevice(grab->device) && + IsPointerDevice(othergrab->device)) || + (IsKeyboardDevice(grab->device) && + IsKeyboardDevice(othergrab->device)))) + { + interfering = TRUE; + break; + } + } + if (interfering) + continue; + } + + + if (match & CORE_MATCH) + { + rc = EventToCore((InternalEvent*)event, &core); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: core conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->type, rc); + continue; + } + xE = &core; + count = 1; + mask = grab->eventMask; + if (grab->ownerEvents) + mask |= pWin->eventMask; + } else if (match & XI2_MATCH) + { + rc = EventToXI2((InternalEvent*)event, &xE); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->type, rc); + continue; + } + count = 1; + + /* FIXME: EventToXI2 returns NULL for enter events, so + * dereferencing the event is bad. Internal event types are + * aligned with core events, so the else clause is valid. + * long-term we should use internal events for enter/focus + * as well */ + if (xE) + mask = grab->xi2mask[device->id][((xGenericEvent*)xE)->evtype/8]; + else if (event->type == XI_Enter || event->type == XI_FocusIn) + mask = grab->xi2mask[device->id][event->type/8]; + + if (grab->ownerEvents && wOtherInputMasks(grab->window)) + { + InputClientsPtr icp = + wOtherInputMasks(grab->window)->inputClients; + + while(icp) + { + if (rClient(icp) == rClient(grab)) + { + int evtype = (xE) ? ((xGenericEvent*)xE)->evtype : event->type; + mask |= icp->xi2mask[device->id][evtype/8]; + break; + } + + icp = icp->next; + } + } + } else + { + rc = EventToXI((InternalEvent*)event, &xE, &count); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->type, rc); + continue; + } + mask = grab->eventMask; + if (grab->ownerEvents && wOtherInputMasks(grab->window)) + { + InputClientsPtr icp = + wOtherInputMasks(grab->window)->inputClients; + + while(icp) + { + if (rClient(icp) == rClient(grab)) + { + mask |= icp->mask[device->id]; + break; + } + + icp = icp->next; + } + } + } + + (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); + + if (xE) + { + FixUpEventFromWindow(device, xE, grab->window, None, TRUE); + + TryClientEvents(rClient(grab), device, xE, count, mask, + GetEventFilter(device, xE), grab); + } + + if (grabinfo->sync.state == FROZEN_NO_EVENT) + { + if (!grabinfo->sync.event) + grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); + *grabinfo->sync.event = *event; + grabinfo->sync.state = FROZEN_WITH_EVENT; + } + + if (match & (XI_MATCH | XI2_MATCH)) + free(xE); /* on core match xE == &core */ + return TRUE; + } + } + return FALSE; +#undef CORE_MATCH +#undef XI_MATCH +#undef XI2_MATCH +} + +/** + * 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 the 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 + * + * If a grab is activated, the event has been sent to the client already! + * + * The event we pass in must always be an XI event. From this, we then emulate + * the core event and then check for grabs. + * + * @param device The device that caused the event. + * @param xE The event to handle (Device{Button|Key}Press). + * @param count Number of events in list. + * @return TRUE if a grab has been activated or false otherwise. +*/ + +Bool +CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, int checkFirst) +{ + int i; + WindowPtr pWin = NULL; + FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus; + BOOL sendCore = (IsMaster(device) && device->coreEvents); + + if (event->type != ET_ButtonPress && + event->type != ET_KeyPress) + return FALSE; + + if (event->type == ET_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, event, sendCore)) + return TRUE; + } + + if ((focus->win == NoneWin) || + (i >= device->spriteInfo->sprite->spriteTraceGood) || + ((i > checkFirst) && + (pWin != device->spriteInfo->sprite->spriteTrace[i-1]))) + return FALSE; + } + + for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) + { + pWin = device->spriteInfo->sprite->spriteTrace[i]; + if (pWin->optional && + CheckPassiveGrabsOnWindow(pWin, device, event, sendCore)) + return TRUE; + } + + return FALSE; +} + +/** + * Called for keyboard events to deliver event to whatever client owns the + * focus. + * + * The event is delivered to the keyboard's focus window, the root window or + * to the window owning the input focus. + * + * @param keybd The keyboard originating the event. + * @param event The event, not yet in wire format. + * @param window Window underneath the sprite. + */ +void +DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) +{ + DeviceIntPtr ptr; + WindowPtr focus = keybd->focus->win; + BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents); + xEvent core; + xEvent *xE = NULL, *xi2 = NULL; + int count, rc; + int deliveries = 0; + + if (focus == FollowKeyboardWin) + focus = inputInfo.keyboard->focus->win; + if (!focus) + return; + if (focus == PointerRootWin) + { + DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd); + return; + } + if ((focus == window) || IsParent(focus, window)) + { + if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd)) + return; + } + + /* just deliver it to the focus window */ + ptr = GetPairedDevice(keybd); + + + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + /* XXX: XACE */ + int filter = GetEventFilter(keybd, xi2); + FixUpEventFromWindow(ptr, xi2, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1, + filter, NullGrab); + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + + rc = EventToXI(event, &xE, &count); + if (rc == Success && + XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success) + { + FixUpEventFromWindow(ptr, xE, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, xE, count, + GetEventFilter(keybd, xE), + NullGrab); + + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + + if (sendCore) + { + rc = EventToCore(event, &core); + if (rc == Success) { + if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, &core, 1) == Success) { + FixUpEventFromWindow(keybd, &core, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, &core, 1, + GetEventFilter(keybd, &core), + NullGrab); + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + } + +unwind: + if (xE) + free(xE); + if (xi2) + free(xi2); + return; +} + +/** + * Deliver an event from a device that is currently grabbed. Uses + * DeliverDeviceEvents() for further delivery if a ownerEvents is set on the + * grab. If not, TryClientEvents() is used. + * + * @param deactivateGrab True if the device's grab should be deactivated. + */ +void +DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, + Bool deactivateGrab) +{ + GrabPtr grab; + GrabInfoPtr grabinfo; + int deliveries = 0; + DeviceIntPtr dev; + SpritePtr pSprite = thisDev->spriteInfo->sprite; + BOOL sendCore = FALSE; + int rc, count = 0; + xEvent *xi = NULL; + xEvent *xi2 = NULL; + + grabinfo = &thisDev->deviceGrab; + grab = grabinfo->grab; + + if (grab->ownerEvents) + { + WindowPtr focus; + + /* Hack: Some pointer device have a focus class. So we need to check + * for the type of event, to see if we really want to deliver it to + * the focus window. For pointer events, the answer is no. + */ + if (IsPointerEvent(event)) + focus = PointerRootWin; + else if (thisDev->focus) + { + focus = thisDev->focus->win; + if (focus == FollowKeyboardWin) + focus = inputInfo.keyboard->focus->win; + } + else + focus = PointerRootWin; + if (focus == PointerRootWin) + deliveries = DeliverDeviceEvents(pSprite->win, event, grab, + NullWindow, thisDev); + else if (focus && (focus == pSprite->win || + IsParent(focus, pSprite->win))) + deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus, + thisDev); + else if (focus) + deliveries = DeliverDeviceEvents(focus, event, grab, focus, + thisDev); + } + if (!deliveries) + { + Mask mask; + + /* XXX: In theory, we could pass the internal events through to + * everything and only convert just before hitting the wire. We can't + * do that yet, so DGE is the last stop for internal events. From here + * onwards, we deal with core/XI events. + */ + + mask = grab->eventMask; + + sendCore = (IsMaster(thisDev) && thisDev->coreEvents); + /* try core event */ + if (sendCore && grab->grabtype == GRABTYPE_CORE) + { + xEvent core; + + rc = EventToCore(event, &core); + if (rc == Success) + { + FixUpEventFromWindow(thisDev, &core, grab->window, + None, TRUE); + if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, + grab->window, &core, 1) || + XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), + grab->window, &core, 1)) + deliveries = 1; /* don't send, but pretend we did */ + else if (!IsInterferingGrab(rClient(grab), thisDev, &core)) + { + deliveries = TryClientEvents(rClient(grab), thisDev, + &core, 1, mask, + GetEventFilter(thisDev, &core), + grab); + } + } else if (rc != BadMatch) + ErrorF("[dix] DeliverGrabbedEvent. Core conversion failed.\n"); + } + + if (!deliveries) + { + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + int evtype = ((xGenericEvent*)xi2)->evtype; + mask = grab->xi2mask[XIAllDevices][evtype/8] | + grab->xi2mask[XIAllMasterDevices][evtype/8] | + grab->xi2mask[thisDev->id][evtype/8]; + /* try XI2 event */ + FixUpEventFromWindow(thisDev, xi2, grab->window, None, TRUE); + /* XXX: XACE */ + deliveries = TryClientEvents(rClient(grab), thisDev, xi2, 1, mask, + GetEventFilter(thisDev, xi2), grab); + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DGE (%d, %d). Skipping delivery.\n", + thisDev->name, event->any.type, rc); + } + + if (!deliveries) + { + rc = EventToXI(event, &xi, &count); + if (rc == Success) + { + /* try XI event */ + if (grabinfo->fromPassiveGrab && + grabinfo->implicitGrab) + mask = grab->deviceMask; + else + mask = grab->eventMask; + + FixUpEventFromWindow(thisDev, xi, grab->window, + None, TRUE); + + if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, + grab->window, xi, count) || + XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), + grab->window, xi, count)) + deliveries = 1; /* don't send, but pretend we did */ + else + { + deliveries = + TryClientEvents(rClient(grab), thisDev, + xi, count, + mask, + GetEventFilter(thisDev, xi), + grab); + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DGE (%d, %d). Skipping delivery.\n", + thisDev->name, event->any.type, rc); + } + + if (deliveries && (event->any.type == ET_Motion)) + thisDev->valuator->motionHintWindow = grab->window; + } + if (deliveries && !deactivateGrab && event->any.type != ET_Motion) + { + switch (grabinfo->sync.state) + { + case FREEZE_BOTH_NEXT_EVENT: + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev == thisDev) + continue; + FreezeThaw(dev, TRUE); + if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) && + (CLIENT_BITS(grab->resource) == + CLIENT_BITS(dev->deviceGrab.grab->resource))) + dev->deviceGrab.sync.state = FROZEN_NO_EVENT; + else + dev->deviceGrab.sync.other = grab; + } + /* fall through */ + case FREEZE_NEXT_EVENT: + grabinfo->sync.state = FROZEN_WITH_EVENT; + FreezeThaw(thisDev, TRUE); + if (!grabinfo->sync.event) + grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); + *grabinfo->sync.event = event->device_event; + break; + } + } + + if (xi) + free(xi); + if (xi2) + free(xi2); +} + +/* This function is used to set the key pressed or key released state - + this is only used when the pressing of keys does not cause + the device's processInputProc to be called, as in for example Mouse Keys. +*/ +void +FixKeyState (DeviceEvent *event, DeviceIntPtr keybd) +{ + int key, bit; + BYTE *kptr; + KeyClassPtr keyc = keybd->key; + + key = event->detail.key; + kptr = &keyc->down[key >> 3]; + bit = 1 << (key & 7); + + if (event->type == ET_KeyPress) { + DebugF("FixKeyState: Key %d %s\n",key, + ((event->type == ET_KeyPress) ? "down" : "up")); + } + + if (event->type == ET_KeyPress) + *kptr |= bit; + else if (event->type == ET_KeyRelease) + *kptr &= ~bit; + else + FatalError("Impossible keyboard event"); +} + +#define AtMostOneClient \ + (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) +#define ManagerMask \ + (SubstructureRedirectMask | ResizeRedirectMask) + +/** + * Recalculate which events may be deliverable for the given window. + * Recalculated mask is used for quicker determination which events may be + * delivered to a window. + * + * The otherEventMasks on a WindowOptional is the combination of all event + * masks set by all clients on the window. + * deliverableEventMask is the combination of the eventMask and the + * otherEventMask plus the events that may be propagated to the parent. + * + * Traverses to siblings and parents of the window. + */ +void +RecalculateDeliverableEvents(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(WindowPtr pWin, ClientPtr client, Mask mask) +{ + Mask check; + OtherClients * others; + DeviceIntPtr dev; + int rc; + + if (mask & ~AllEventMasks) + { + client->errorValue = mask; + return BadValue; + } + check = (mask & ManagerMask); + if (check) { + rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, + RT_WINDOW, pWin, RT_NONE, NULL, DixManageAccess); + if (rc != Success) + return rc; + } + 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 ((mask & PointerMotionHintMask) && !(check & PointerMotionHintMask)) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->valuator && dev->valuator->motionHintWindow == pWin) + dev->valuator->motionHintWindow = NullWindow; + } + } + RecalculateDeliverableEvents(pWin); + return Success; +} + +int +EventSuppressForWindow(WindowPtr pWin, 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; +} + +/** + * Assembles an EnterNotify or LeaveNotify and sends it event to the client. + * Uses the paired keyboard to get some additional information. + */ +void +CoreEnterLeaveEvent( + DeviceIntPtr mouse, + int type, + int mode, + int detail, + WindowPtr pWin, + Window child) +{ + xEvent event; + WindowPtr focus; + DeviceIntPtr keybd; + GrabPtr grab = mouse->deviceGrab.grab; + Mask mask; + + keybd = GetPairedDevice(mouse); + + 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); + } + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = type; + event.u.u.detail = detail; + event.u.enterLeave.time = currentTime.milliseconds; + event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x; + event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y; + /* Counts on the same initial structure of crossing & button events! */ + FixUpEventFromWindow(mouse, &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 = mouse->button ? (mouse->button->state & 0x1f00) : 0; + if (keybd) + event.u.enterLeave.state |= + XkbGrabStateFromRec(&keybd->key->xkbInfo->state); + event.u.enterLeave.mode = mode; + focus = (keybd) ? keybd->focus->win : None; + if ((focus != NoneWin) && + ((pWin == focus) || (focus == PointerRootWin) || + IsParent(focus, pWin))) + event.u.enterLeave.flags |= ELFlagFocus; + + if ((mask & GetEventFilter(mouse, &event))) + { + if (grab) + TryClientEvents(rClient(grab), mouse, &event, 1, mask, + GetEventFilter(mouse, &event), grab); + else + DeliverEventsToWindow(mouse, pWin, &event, 1, + GetEventFilter(mouse, &event), + NullGrab); + } + + if ((type == EnterNotify) && (mask & KeymapStateMask)) + { + xKeymapEvent ke; + ClientPtr client = grab ? rClient(grab) : wClient(pWin); + if (XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess)) + bzero((char *)&ke.map[0], 31); + else + memmove((char *)&ke.map[0], (char *)&keybd->key->down[1], 31); + + ke.type = KeymapNotify; + if (grab) + TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1, + mask, KeymapStateMask, grab); + else + DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1, + KeymapStateMask, NullGrab); + } +} + +void +DeviceEnterLeaveEvent( + DeviceIntPtr mouse, + int sourceid, + int type, + int mode, + int detail, + WindowPtr pWin, + Window child) +{ + GrabPtr grab = mouse->deviceGrab.grab; + xXIEnterEvent *event; + int filter; + int btlen, len, i; + DeviceIntPtr kbd; + + if ((mode == XINotifyPassiveGrab && type == XI_Leave) || + (mode == XINotifyPassiveUngrab && type == XI_Enter)) + return; + + btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; + btlen = bytes_to_int32(btlen); + len = sizeof(xXIEnterEvent) + btlen * 4; + + event = calloc(1, len); + event->type = GenericEvent; + event->extension = IReqCode; + event->evtype = type; + event->length = (len - sizeof(xEvent))/4; + event->buttons_len = btlen; + event->detail = detail; + event->time = currentTime.milliseconds; + event->deviceid = mouse->id; + event->sourceid = sourceid; + event->mode = mode; + event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); + event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); + + for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) + if (BitIsOn(mouse->button->down, i)) + SetBit(&event[1], i); + + kbd = (IsMaster(mouse) || mouse->u.master) ? GetPairedDevice(mouse) : NULL; + if (kbd && kbd->key) + { + event->mods.base_mods = kbd->key->xkbInfo->state.base_mods; + event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods; + event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods; + + event->group.base_group = kbd->key->xkbInfo->state.base_group; + event->group.latched_group = kbd->key->xkbInfo->state.latched_group; + event->group.locked_group = kbd->key->xkbInfo->state.locked_group; + } + + FixUpEventFromWindow(mouse, (xEvent*)event, pWin, None, FALSE); + + filter = GetEventFilter(mouse, (xEvent*)event); + + if (grab) + { + Mask mask; + mask = grab->xi2mask[XIAllDevices][type/8] | + grab->xi2mask[XIAllMasterDevices][type/8] | + grab->xi2mask[mouse->id][type/8]; + TryClientEvents(rClient(grab), mouse, (xEvent*)event, 1, mask, + filter, grab); + } else { + if (!GetWindowXI2Mask(mouse, pWin, (xEvent*)event)) + goto out; + DeliverEventsToWindow(mouse, pWin, (xEvent*)event, 1, filter, + NullGrab); + } + +out: + free(event); +} + +void +CoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin) +{ + xEvent event; + + memset(&event, 0, sizeof(xEvent)); + event.u.focus.mode = mode; + event.u.u.type = type; + event.u.u.detail = detail; + event.u.focus.window = pWin->drawable.id; + + DeliverEventsToWindow(dev, pWin, &event, 1, + GetEventFilter(dev, &event), NullGrab); + if ((type == FocusIn) && + ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) + { + xKeymapEvent ke; + ClientPtr client = wClient(pWin); + if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess)) + bzero((char *)&ke.map[0], 31); + else + memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31); + + ke.type = KeymapNotify; + DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1, + KeymapStateMask, NullGrab); + } +} + +/** + * Set the input focus to the given window. Subsequent keyboard events will be + * delivered to the given window. + * + * Usually called from ProcSetInputFocus as result of a client request. If so, + * the device is the inputInfo.keyboard. + * If called from ProcXSetInputFocus as result of a client xinput request, the + * device is set to the device specified by the client. + * + * @param client Client that requested input focus change. + * @param dev Focus device. + * @param focusID The window to obtain the focus. Can be PointerRoot or None. + * @param revertTo Specifies where the focus reverts to when window becomes + * unviewable. + * @param ctime Specifies the time. + * @param followOK True if pointer is allowed to follow the keyboard. + */ +int +SetInputFocus( + ClientPtr client, + DeviceIntPtr dev, + Window focusID, + CARD8 revertTo, + Time ctime, + Bool followOK) +{ + FocusClassPtr focus; + WindowPtr focusWin; + int mode, rc; + TimeStamp time; + DeviceIntPtr keybd; /* used for FollowKeyboard or FollowKeyboardWin */ + + + UpdateCurrentTime(); + if ((revertTo != RevertToParent) && + (revertTo != RevertToPointerRoot) && + (revertTo != RevertToNone) && + ((revertTo != RevertToFollowKeyboard) || !followOK)) + { + client->errorValue = revertTo; + return BadValue; + } + time = ClientTimeToServerTime(ctime); + + if (IsKeyboardDevice(dev)) + keybd = dev; + else + keybd = GetPairedDevice(dev); + + if ((focusID == None) || (focusID == PointerRoot)) + focusWin = (WindowPtr)(long)focusID; + else if ((focusID == FollowKeyboard) && followOK) + { + focusWin = keybd->focus->win; + } + else { + rc = dixLookupWindow(&focusWin, focusID, client, DixSetAttrAccess); + if (rc != Success) + return rc; + /* It is a match error to try to set the input focus to an + unviewable window. */ + if(!focusWin->realized) + return(BadMatch); + } + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixSetFocusAccess); + if (rc != Success) + return Success; + + focus = dev->focus; + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, focus->time) == EARLIER)) + return Success; + mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal; + if (focus->win == FollowKeyboardWin) + { + if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin)) + DoFocusEvents(dev, keybd->focus->win, focusWin, mode); + } else + { + if (!ActivateFocusInGrab(dev, focus->win, focusWin)) + 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; + focus->trace = realloc(focus->trace, + focus->traceSize * sizeof(WindowPtr)); + } + focus->traceGood = depth; + for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--) + focus->trace[depth] = pWin; + } + return Success; +} + +/** + * Server-side protocol handling for SetInputFocus request. + * + * Sets the input focus for the virtual core keyboard. + */ +int +ProcSetInputFocus(ClientPtr client) +{ + DeviceIntPtr kbd = PickKeyboard(client); + REQUEST(xSetInputFocusReq); + + REQUEST_SIZE_MATCH(xSetInputFocusReq); + + return SetInputFocus(client, kbd, stuff->focus, + stuff->revertTo, stuff->time, FALSE); +} + +/** + * Server-side protocol handling for GetInputFocus request. + * + * Sends the current input focus for the client's keyboard back to the + * client. + */ +int +ProcGetInputFocus(ClientPtr client) +{ + DeviceIntPtr kbd = PickKeyboard(client); + xGetInputFocusReply rep; + FocusClassPtr focus = kbd->focus; + int rc; + /* REQUEST(xReq); */ + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetFocusAccess); + if (rc != Success) + return rc; + + memset(&rep, 0, sizeof(xGetInputFocusReply)); + 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; +} + +/** + * Server-side protocol handling for GrabPointer request. + * + * Sets an active grab on the client's ClientPointer and returns success + * status to client. + */ +int +ProcGrabPointer(ClientPtr client) +{ + xGrabPointerReply rep; + DeviceIntPtr device = PickPointer(client); + GrabPtr grab; + GrabMask mask; + WindowPtr confineTo; + CursorPtr oldCursor; + REQUEST(xGrabPointerReq); + TimeStamp time; + int rc; + + REQUEST_SIZE_MATCH(xGrabPointerReq); + UpdateCurrentTime(); + + if (stuff->eventMask & ~PointerGrabMask) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + + if (stuff->confineTo == None) + confineTo = NullWindow; + else + { + rc = dixLookupWindow(&confineTo, stuff->confineTo, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + + memset(&rep, 0, sizeof(xGrabPointerReply)); + oldCursor = NullCursor; + grab = device->deviceGrab.grab; + + if (grab) + { + if (grab->confineTo && !confineTo) + ConfineCursorToWindow(device, RootWindow(device), FALSE, FALSE); + oldCursor = grab->cursor; + } + + mask.core = stuff->eventMask; + + rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode, + stuff->grabWindow, stuff->ownerEvents, stuff->time, + &mask, GRABTYPE_CORE, stuff->cursor, + stuff->confineTo, &rep.status); + if (rc != Success) + return rc; + + if (oldCursor && rep.status == GrabSuccess) + FreeCursor (oldCursor, (Cursor)0); + + time = ClientTimeToServerTime(stuff->time); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); + return Success; +} + +/** + * Server-side protocol handling for ChangeActivePointerGrab request. + * + * Changes properties of the grab hold by the client. If the client does not + * hold an active grab on the device, nothing happens. + */ +int +ProcChangeActivePointerGrab(ClientPtr client) +{ + DeviceIntPtr device; + GrabPtr 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 + { + int rc = dixLookupResourceByType((pointer *)&newCursor, stuff->cursor, + RT_CURSOR, client, DixUseAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return (rc == BadValue) ? BadCursor : rc; + } + } + + device = PickPointer(client); + grab = device->deviceGrab.grab; + + if (!grab) + return Success; + if (!SameClient(grab, client)) + return Success; + time = ClientTimeToServerTime(stuff->time); + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER)) + return Success; + oldCursor = grab->cursor; + grab->cursor = newCursor; + if (newCursor) + newCursor->refcnt++; + PostNewCursor(device); + if (oldCursor) + FreeCursor(oldCursor, (Cursor)0); + grab->eventMask = stuff->eventMask; + return Success; +} + +/** + * Server-side protocol handling for UngrabPointer request. + * + * Deletes a pointer grab on a device the client has grabbed. + */ +int +ProcUngrabPointer(ClientPtr client) +{ + DeviceIntPtr device = PickPointer(client); + GrabPtr grab; + TimeStamp time; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + UpdateCurrentTime(); + grab = device->deviceGrab.grab; + + time = ClientTimeToServerTime(stuff->id); + if ((CompareTimeStamps(time, currentTime) != LATER) && + (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && + (grab) && SameClient(grab, client)) + (*device->deviceGrab.DeactivateGrab)(device); + return Success; +} + +/** + * Sets a grab on the given device. + * + * Called from ProcGrabKeyboard to work on the client's keyboard. + * Called from ProcXGrabDevice to work on the device specified by the client. + * + * The parameters this_mode and other_mode represent the keyboard_mode and + * pointer_mode parameters of XGrabKeyboard(). + * See man page for details on all the parameters + * + * @param client Client that owns the grab. + * @param dev The device to grab. + * @param this_mode GrabModeSync or GrabModeAsync + * @param other_mode GrabModeSync or GrabModeAsync + * @param status Return code to be returned to the caller. + * + * @returns Success or BadValue. + */ +int +GrabDevice(ClientPtr client, DeviceIntPtr dev, + unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow, + unsigned ownerEvents, Time ctime, GrabMask *mask, + int grabtype, Cursor curs, Window confineToWin, CARD8 *status) +{ + WindowPtr pWin, confineTo; + GrabPtr grab; + TimeStamp time; + Mask access_mode = DixGrabAccess; + int rc; + GrabInfoPtr grabInfo = &dev->deviceGrab; + CursorPtr cursor; + + UpdateCurrentTime(); + if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync)) + { + client->errorValue = keyboard_mode; + return BadValue; + } + if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync)) + { + client->errorValue = pointer_mode; + return BadValue; + } + if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) + { + client->errorValue = ownerEvents; + return BadValue; + } + + rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + if (confineToWin == None) + confineTo = NullWindow; + else + { + rc = dixLookupWindow(&confineTo, confineToWin, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + + if (curs == None) + cursor = NullCursor; + else + { + rc = dixLookupResourceByType((pointer *)&cursor, curs, RT_CURSOR, + client, DixUseAccess); + if (rc != Success) + { + client->errorValue = curs; + return (rc == BadValue) ? BadCursor : rc; + } + access_mode |= DixForceAccess; + } + + if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc != Success) + return rc; + + time = ClientTimeToServerTime(ctime); + grab = grabInfo->grab; + if (grab && grab->grabtype != grabtype) + *status = AlreadyGrabbed; + if (grab && !SameClient(grab, client)) + *status = AlreadyGrabbed; + else if ((!pWin->realized) || + (confineTo && + !(confineTo->realized + && BorderSizeNotEmpty(dev, confineTo)))) + *status = GrabNotViewable; + else if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER)) + *status = GrabInvalidTime; + else if (grabInfo->sync.frozen && + grabInfo->sync.other && !SameClient(grabInfo->sync.other, client)) + *status = GrabFrozen; + else + { + GrabRec tempGrab; + + /* Otherwise segfaults happen on grabbed MPX devices */ + memset(&tempGrab, 0, sizeof(GrabRec)); + + tempGrab.next = NULL; + tempGrab.window = pWin; + tempGrab.resource = client->clientAsMask; + tempGrab.ownerEvents = ownerEvents; + tempGrab.keyboardMode = keyboard_mode; + tempGrab.pointerMode = pointer_mode; + if (grabtype == GRABTYPE_CORE) + tempGrab.eventMask = mask->core; + else if (grabtype == GRABTYPE_XI) + tempGrab.eventMask = mask->xi; + else + memcpy(tempGrab.xi2mask, mask->xi2mask, sizeof(tempGrab.xi2mask)); + tempGrab.device = dev; + tempGrab.cursor = cursor; + tempGrab.confineTo = confineTo; + tempGrab.grabtype = grabtype; + (*grabInfo->ActivateGrab)(dev, &tempGrab, time, FALSE); + *status = GrabSuccess; + } + return Success; +} + +/** + * Server-side protocol handling for GrabKeyboard request. + * + * Grabs the client's keyboard and returns success status to client. + */ +int +ProcGrabKeyboard(ClientPtr client) +{ + xGrabKeyboardReply rep; + REQUEST(xGrabKeyboardReq); + int result; + DeviceIntPtr keyboard = PickKeyboard(client); + GrabMask mask; + + REQUEST_SIZE_MATCH(xGrabKeyboardReq); + + memset(&rep, 0, sizeof(xGrabKeyboardReply)); + mask.core = KeyPressMask | KeyReleaseMask; + + result = GrabDevice(client, keyboard, stuff->pointerMode, + stuff->keyboardMode, stuff->grabWindow, stuff->ownerEvents, + stuff->time, &mask, GRABTYPE_CORE, None, None, + &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; +} + +/** + * Server-side protocol handling for UngrabKeyboard request. + * + * Deletes a possible grab on the client's keyboard. + */ +int +ProcUngrabKeyboard(ClientPtr client) +{ + DeviceIntPtr device = PickKeyboard(client); + GrabPtr grab; + TimeStamp time; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + UpdateCurrentTime(); + + grab = device->deviceGrab.grab; + + time = ClientTimeToServerTime(stuff->id); + if ((CompareTimeStamps(time, currentTime) != LATER) && + (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && + (grab) && SameClient(grab, client) && grab->grabtype == GRABTYPE_CORE) + (*device->deviceGrab.DeactivateGrab)(device); + return Success; +} + +/** + * Server-side protocol handling for QueryPointer request. + * + * Returns the current state and position of the client's ClientPointer to the + * client. + */ +int +ProcQueryPointer(ClientPtr client) +{ + xQueryPointerReply rep; + WindowPtr pWin, t; + DeviceIntPtr mouse = PickPointer(client); + DeviceIntPtr keyboard; + SpritePtr pSprite; + int rc; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); + if (rc != Success) + return rc; + rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); + if (rc != Success && rc != BadAccess) + return rc; + + keyboard = GetPairedDevice(mouse); + + pSprite = mouse->spriteInfo->sprite; + if (mouse->valuator->motionHintWindow) + MaybeStopHint(mouse, client); + memset(&rep, 0, sizeof(xQueryPointerReply)); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.mask = mouse->button ? (mouse->button->state) : 0; + rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state); + rep.length = 0; + rep.root = (RootWindow(mouse))->drawable.id; + rep.rootX = pSprite->hot.x; + rep.rootY = pSprite->hot.y; + rep.child = None; + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + rep.sameScreen = xTrue; + rep.winX = pSprite->hot.x - pWin->drawable.x; + rep.winY = pSprite->hot.y - pWin->drawable.y; + for (t = pSprite->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; + } + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + rep.rootX += panoramiXdataPtr[0].x; + rep.rootY += panoramiXdataPtr[0].y; + if(stuff->id == rep.root) { + rep.winX += panoramiXdataPtr[0].x; + rep.winY += panoramiXdataPtr[0].y; + } + } +#endif + + if (rc == BadAccess) { + rep.mask = 0; + rep.child = None; + rep.rootX = 0; + rep.rootY = 0; + rep.winX = 0; + rep.winY = 0; + } + + WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep); + + return(Success); +} + +/** + * Initializes the device list and the DIX sprite to sane values. Allocates + * trace memory used for quick window traversal. + */ +void +InitEvents(void) +{ + int i; + + inputInfo.numDevices = 0; + inputInfo.devices = (DeviceIntPtr)NULL; + inputInfo.off_devices = (DeviceIntPtr)NULL; + inputInfo.keyboard = (DeviceIntPtr)NULL; + inputInfo.pointer = (DeviceIntPtr)NULL; + /* The mask for pointer motion events may have changed in the last server + * generation. See comment above definition of filters. */ + filters[0][PointerMotionMask] = MotionNotify; + for (i = 1; i < MAXDEVICES; i++) + { + memcpy(&filters[i], filters[0], sizeof(filters[0])); + } + + 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; + } + + InputEventListLen = GetMaximumEventsNum(); + InputEventList = InitEventList(InputEventListLen); + if (!InputEventList) + FatalError("[dix] Failed to allocate input event list.\n"); +} + +void +CloseDownEvents(void) +{ + FreeEventList(InputEventList, InputEventListLen); + InputEventListLen = 0; + InputEventList = NULL; +} + +/** + * Server-side protocol handling for SendEvent request. + * + * Locates the window to send the event to and forwards the event. + */ +int +ProcSendEvent(ClientPtr client) +{ + WindowPtr pWin; + WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ + DeviceIntPtr dev = PickPointer(client); + DeviceIntPtr keybd = GetPairedDevice(dev); + SpritePtr pSprite = dev->spriteInfo->sprite; + 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 = pSprite->win; + else if (stuff->destination == InputFocus) + { + WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin; + + 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 = pSprite->spriteTrace[0]; /* Root window! */ + + if (IsParent(inputFocus, pSprite->win)) + { + effectiveFocus = inputFocus; + pWin = pSprite->win; + } + else + effectiveFocus = pWin = inputFocus; + } + else + dixLookupWindow(&pWin, stuff->destination, client, DixSendAccess); + + 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 (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, + &stuff->event, 1)) + return Success; + if (DeliverEventsToWindow(dev, pWin, + &stuff->event, 1, stuff->eventMask, NullGrab)) + return Success; + if (pWin == effectiveFocus) + return Success; + stuff->eventMask &= ~wDontPropagateMask(pWin); + if (!stuff->eventMask) + break; + } + } + else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1)) + DeliverEventsToWindow(dev, pWin, &stuff->event, + 1, stuff->eventMask, NullGrab); + return Success; +} + +/** + * Server-side protocol handling for UngrabKey request. + * + * Deletes a passive grab for the given key. Works on the + * client's keyboard. + */ +int +ProcUngrabKey(ClientPtr client) +{ + REQUEST(xUngrabKeyReq); + WindowPtr pWin; + GrabRec tempGrab; + DeviceIntPtr keybd = PickKeyboard(client); + int rc; + + REQUEST_SIZE_MATCH(xUngrabKeyReq); + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || + (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) + && (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 = GetPairedDevice(keybd); + tempGrab.type = KeyPress; + tempGrab.grabtype = GRABTYPE_CORE; + tempGrab.detail.exact = stuff->key; + tempGrab.detail.pMask = NULL; + tempGrab.next = NULL; + + if (!DeletePassiveGrabFromList(&tempGrab)) + return(BadAlloc); + return(Success); +} + +/** + * Server-side protocol handling for GrabKey request. + * + * Creates a grab for the client's keyboard and adds it to the list of passive + * grabs. + */ +int +ProcGrabKey(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xGrabKeyReq); + GrabPtr grab; + DeviceIntPtr keybd = PickKeyboard(client); + int rc; + GrabParameters param; + GrabMask mask; + + REQUEST_SIZE_MATCH(xGrabKeyReq); + + memset(¶m, 0, sizeof(param)); + param.grabtype = GRABTYPE_CORE; + param.ownerEvents = stuff->ownerEvents; + param.this_device_mode = stuff->keyboardMode; + param.other_devices_mode = stuff->pointerMode; + param.modifiers = stuff->modifiers; + + rc = CheckGrabValues(client, ¶m); + if (rc != Success) + return rc; + + if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || + (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) + && (stuff->key != AnyKey)) + { + client->errorValue = stuff->key; + return BadValue; + } + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + + mask.core = (KeyPressMask | KeyReleaseMask); + + grab = CreateGrab(client->index, keybd, keybd, pWin, GRABTYPE_CORE, &mask, + ¶m, KeyPress, stuff->key, NullWindow, NullCursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + + +/** + * Server-side protocol handling for GrabButton request. + * + * Creates a grab for the client's ClientPointer and adds it as a passive grab + * to the list. + */ +int +ProcGrabButton(ClientPtr client) +{ + WindowPtr pWin, confineTo; + REQUEST(xGrabButtonReq); + CursorPtr cursor; + GrabPtr grab; + DeviceIntPtr ptr, modifierDevice; + Mask access_mode = DixGrabAccess; + GrabMask mask; + GrabParameters param; + int rc; + + 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; + } + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + if (stuff->confineTo == None) + confineTo = NullWindow; + else { + rc = dixLookupWindow(&confineTo, stuff->confineTo, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + if (stuff->cursor == None) + cursor = NullCursor; + else + { + rc = dixLookupResourceByType((pointer *)&cursor, stuff->cursor, RT_CURSOR, + client, DixUseAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return (rc == BadValue) ? BadCursor : rc; + } + access_mode |= DixForceAccess; + } + + ptr = PickPointer(client); + modifierDevice = GetPairedDevice(ptr); + if (stuff->pointerMode == GrabModeSync || + stuff->keyboardMode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, access_mode); + if (rc != Success) + return rc; + + memset(¶m, 0, sizeof(param)); + param.grabtype = GRABTYPE_CORE; + param.ownerEvents = stuff->ownerEvents; + param.this_device_mode = stuff->keyboardMode; + param.other_devices_mode = stuff->pointerMode; + param.modifiers = stuff->modifiers; + + mask.core = stuff->eventMask; + + grab = CreateGrab(client->index, ptr, modifierDevice, pWin, + GRABTYPE_CORE, &mask, ¶m, ButtonPress, + stuff->button, confineTo, cursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + +/** + * Server-side protocol handling for UngrabButton request. + * + * Deletes a passive grab on the client's ClientPointer from the list. + */ +int +ProcUngrabButton(ClientPtr client) +{ + REQUEST(xUngrabButtonReq); + WindowPtr pWin; + GrabRec tempGrab; + int rc; + DeviceIntPtr ptr; + + REQUEST_SIZE_MATCH(xUngrabButtonReq); + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) + { + client->errorValue = stuff->modifiers; + return BadValue; + } + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess); + if (rc != Success) + return rc; + + ptr = PickPointer(client); + + tempGrab.resource = client->clientAsMask; + tempGrab.device = ptr; + tempGrab.window = pWin; + tempGrab.modifiersDetail.exact = stuff->modifiers; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.modifierDevice = GetPairedDevice(ptr); + tempGrab.type = ButtonPress; + tempGrab.detail.exact = stuff->button; + tempGrab.grabtype = GRABTYPE_CORE; + tempGrab.detail.pMask = NULL; + tempGrab.next = NULL; + + if (!DeletePassiveGrabFromList(&tempGrab)) + return(BadAlloc); + return(Success); +} + +/** + * Deactivate any grab that may be on the window, remove the focus. + * Delete any XInput extension events from the window too. Does not change the + * window mask. Use just before the window is deleted. + * + * If freeResources is set, passive grabs on the window are deleted. + * + * @param pWin The window to delete events from. + * @param freeResources True if resources associated with the window should be + * deleted. + */ +void +DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources) +{ + WindowPtr parent; + DeviceIntPtr mouse = inputInfo.pointer; + DeviceIntPtr keybd = inputInfo.keyboard; + FocusClassPtr focus; + OtherClientsPtr oc; + GrabPtr passive; + GrabPtr grab; + + + /* Deactivate any grabs performed on this window, before making any + input focus changes. */ + grab = mouse->deviceGrab.grab; + if (grab && + ((grab->window == pWin) || (grab->confineTo == pWin))) + (*mouse->deviceGrab.DeactivateGrab)(mouse); + + + /* Deactivating a keyboard grab should cause focus events. */ + grab = keybd->deviceGrab.grab; + if (grab && (grab->window == pWin)) + (*keybd->deviceGrab.DeactivateGrab)(keybd); + + /* And now the real devices */ + for (mouse = inputInfo.devices; mouse; mouse = mouse->next) + { + grab = mouse->deviceGrab.grab; + if (grab && ((grab->window == pWin) || (grab->confineTo == pWin))) + (*mouse->deviceGrab.DeactivateGrab)(mouse); + } + + + for (keybd = inputInfo.devices; keybd; keybd = keybd->next) + { + if (IsKeyboardDevice(keybd)) + { + focus = keybd->focus; + + /* 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->deviceGrab.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 + || wClient(parent)->clientGone +#endif + ); + if (!ActivateFocusInGrab(keybd, pWin, parent)) + DoFocusEvents(keybd, pWin, parent, focusEventMode); + focus->win = parent; + focus->revert = RevertToNone; + break; + case RevertToPointerRoot: + if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin)) + DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); + focus->win = PointerRootWin; + focus->traceGood = 0; + break; + } + } + } + + if (IsPointerDevice(keybd)) + { + if (keybd->valuator->motionHintWindow == pWin) + keybd->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); + } + + DeleteWindowFromAnyExtEvents(pWin, freeResources); +} + +/** + * Call this whenever some window at or below pWin has changed geometry. If + * there is a grab on the window, the cursor will be re-confined into the + * window. + */ +void +CheckCursorConfinement(WindowPtr pWin) +{ + GrabPtr grab; + WindowPtr confineTo; + DeviceIntPtr pDev; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return; +#endif + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + grab = pDev->deviceGrab.grab; + if (grab && (confineTo = grab->confineTo)) + { + if (!BorderSizeNotEmpty(pDev, confineTo)) + (*pDev->deviceGrab.DeactivateGrab)(pDev); + else if ((pWin == confineTo) || IsParent(pWin, confineTo)) + ConfineCursorToWindow(pDev, 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; +} + +/** + * Server-side protocol handling for RecolorCursor request. + */ +int +ProcRecolorCursor(ClientPtr client) +{ + CursorPtr pCursor; + int rc, nscr; + ScreenPtr pscr; + Bool displayed; + SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; + REQUEST(xRecolorCursorReq); + + REQUEST_SIZE_MATCH(xRecolorCursorReq); + rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR, + client, DixWriteAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return (rc == BadValue) ? BadCursor : rc; + } + + 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]; +#ifdef PANORAMIX + if(!noPanoramiXExtension) + displayed = (pscr == pSprite->screen); + else +#endif + displayed = (pscr == pSprite->hotPhys.pScreen); + ( *pscr->RecolorCursor)(PickPointer(client), pscr, pCursor, + (pCursor == pSprite->current) && displayed); + } + return (Success); +} + +/** + * Write the given events to a client, swapping the byte order if necessary. + * To swap the byte ordering, a callback is called that has to be set up for + * the given event type. + * + * In the case of DeviceMotionNotify trailed by DeviceValuators, the events + * can be more than one. Usually it's just one event. + * + * Do not modify the event structure passed in. See comment below. + * + * @param pClient Client to send events to. + * @param count Number of events. + * @param events The event list. + */ +void +WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) +{ +#ifdef PANORAMIX + xEvent eventCopy; +#endif + xEvent *eventTo, *eventFrom; + int i, + eventlength = sizeof(xEvent); + + /* Let XKB rewrite the state, as it depends on client preferences. */ + XkbFilterEvents(pClient, count, events); + +#ifdef PANORAMIX + if(!noPanoramiXExtension && + (panoramiXdataPtr[0].x || panoramiXdataPtr[0].y)) + { + switch(events->u.u.type) { + case MotionNotify: + case ButtonPress: + case ButtonRelease: + case KeyPress: + case KeyRelease: + case EnterNotify: + case LeaveNotify: + /* + When multiple clients want the same event DeliverEventsToWindow + passes the same event structure multiple times so we can't + modify the one passed to us + */ + count = 1; /* should always be 1 */ + memcpy(&eventCopy, events, sizeof(xEvent)); + eventCopy.u.keyButtonPointer.rootX += panoramiXdataPtr[0].x; + eventCopy.u.keyButtonPointer.rootY += panoramiXdataPtr[0].y; + if(eventCopy.u.keyButtonPointer.event == + eventCopy.u.keyButtonPointer.root) + { + eventCopy.u.keyButtonPointer.eventX += panoramiXdataPtr[0].x; + eventCopy.u.keyButtonPointer.eventY += panoramiXdataPtr[0].y; + } + events = &eventCopy; + break; + default: break; + } + } +#endif + + if (EventCallback) + { + EventInfoRec eventinfo; + eventinfo.client = pClient; + eventinfo.events = events; + eventinfo.count = count; + CallCallbacks(&EventCallback, (pointer)&eventinfo); + } +#ifdef XSERVER_DTRACE + if (XSERVER_SEND_EVENT_ENABLED()) { + for (i = 0; i < count; i++) + { + XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]); + } + } +#endif + /* Just a safety check to make sure we only have one GenericEvent, it just + * makes things easier for me right now. (whot) */ + for (i = 1; i < count; i++) + { + if (events[i].u.u.type == GenericEvent) + { + ErrorF("[dix] TryClientEvents: Only one GenericEvent at a time.\n"); + return; + } + } + + if (events->u.u.type == GenericEvent) + { + eventlength += ((xGenericEvent*)events)->length * 4; + } + + if(pClient->swapped) + { + if (eventlength > swapEventLen) + { + swapEventLen = eventlength; + swapEvent = realloc(swapEvent, swapEventLen); + if (!swapEvent) + { + FatalError("WriteEventsToClient: Out of memory.\n"); + return; + } + } + + for(i = 0; i < count; i++) + { + eventFrom = &events[i]; + eventTo = swapEvent; + + /* 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); + + WriteToClient(pClient, eventlength, (char *)eventTo); + } + } + else + { + /* only one GenericEvent, remember? that means either count is 1 and + * eventlength is arbitrary or eventlength is 32 and count doesn't + * matter. And we're all set. Woohoo. */ + WriteToClient(pClient, count * eventlength, (char *) events); + } +} + +/* + * Set the client pointer for the given client. + * + * A client can have exactly one ClientPointer. Each time a + * request/reply/event is processed and the choice of devices is ambiguous + * (e.g. QueryPointer request), the server will pick the ClientPointer (see + * PickPointer()). + * If a keyboard is needed, the first keyboard paired with the CP is used. + */ +int +SetClientPointer(ClientPtr client, DeviceIntPtr device) +{ + int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess); + if (rc != Success) + return rc; + + if (!IsMaster(device)) + { + ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n"); + return BadDevice; + } else if (!device->spriteInfo->spriteOwner) + { + ErrorF("[dix] Device %d does not have a sprite. " + "Cannot be ClientPointer\n", device->id); + return BadDevice; + } + client->clientPtr = device; + return Success; +} + +/* PickPointer will pick an appropriate pointer for the given client. + * + * An "appropriate device" is (in order of priority): + * 1) A device the given client has a core grab on. + * 2) A device set as ClientPointer for the given client. + * 3) The first master device. + */ +DeviceIntPtr +PickPointer(ClientPtr client) +{ + DeviceIntPtr it = inputInfo.devices; + + /* First, check if the client currently has a grab on a device. Even + * keyboards count. */ + for(it = inputInfo.devices; it; it = it->next) + { + GrabPtr grab = it->deviceGrab.grab; + if (grab && grab->grabtype == GRABTYPE_CORE && SameClient(grab, client)) + { + it = GetMaster(it, MASTER_POINTER); + return it; /* Always return a core grabbed device */ + } + } + + if (!client->clientPtr) + { + DeviceIntPtr it = inputInfo.devices; + while (it) + { + if (IsMaster(it) && it->spriteInfo->spriteOwner) + { + client->clientPtr = it; + break; + } + it = it->next; + } + } + return client->clientPtr; +} + +/* PickKeyboard will pick an appropriate keyboard for the given client by + * searching the list of devices for the keyboard device that is paired with + * the client's pointer. + */ +DeviceIntPtr +PickKeyboard(ClientPtr client) +{ + DeviceIntPtr ptr = PickPointer(client); + DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD); + + if (!kbd) + { + ErrorF("[dix] ClientPointer not paired with a keyboard. This " + "is a bug.\n"); + } + + return kbd; +} + +/* A client that has one or more core grabs does not get core events from + * devices it does not have a grab on. Legacy applications behave bad + * otherwise because they are not used to it and the events interfere. + * Only applies for core events. + * + * Return true if a core event from the device would interfere and should not + * be delivered. + */ +Bool +IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event) +{ + DeviceIntPtr it = inputInfo.devices; + + switch(event->u.u.type) + { + case KeyPress: + case KeyRelease: + case ButtonPress: + case ButtonRelease: + case MotionNotify: + case EnterNotify: + case LeaveNotify: + break; + default: + return FALSE; + } + + if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) + return FALSE; + + while(it) + { + if (it != dev) + { + if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client) + && !it->deviceGrab.fromPassiveGrab) + { + if ((IsPointerDevice(it) && IsPointerDevice(dev)) || + (IsKeyboardDevice(it) && IsKeyboardDevice(dev))) + return TRUE; + } + } + it = it->next; + } + + return FALSE; +} + diff --git a/xorg-server/dix/extension.c b/xorg-server/dix/extension.c index f34866586..57aef003f 100644 --- a/xorg-server/dix/extension.c +++ b/xorg-server/dix/extension.c @@ -1,358 +1,358 @@ -/*********************************************************** - -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" -#include "privates.h" -#include "registry.h" -#include "xace.h" - -#define LAST_EVENT 128 -#define LAST_ERROR 255 - -static ExtensionEntry **extensions = (ExtensionEntry **)NULL; - -int lastEvent = EXTENSION_EVENT_BASE; -static int lastError = FirstExtensionError; -static unsigned int NumExtensions = 0; - -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 || !MinorOpcodeProc) - return((ExtensionEntry *) NULL); - if ((lastEvent + NumEvents > LAST_EVENT) || - (unsigned)(lastError + NumErrors > LAST_ERROR)) { - LogMessage(X_ERROR, "Not enabling extension %s: maximum number of " - "events or errors exceeded.\n", name); - return((ExtensionEntry *) NULL); - } - - ext = xalloc(sizeof(ExtensionEntry)); - if (!ext) - return(NULL); - ext->name = xalloc(strlen(name) + 1); - ext->num_aliases = 0; - ext->aliases = (char **)NULL; - ext->devPrivates = NULL; - if (!ext->name) - { - xfree(ext); - return((ExtensionEntry *) NULL); - } - strcpy(ext->name, name); - i = NumExtensions; - newexts = (ExtensionEntry **) xrealloc(extensions, - (i + 1) * sizeof(ExtensionEntry *)); - if (!newexts) - { - xfree(ext->name); - xfree(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; - } - - RegisterExtensionNames(ext); - return(ext); -} - -Bool AddExtensionAlias(char *alias, ExtensionEntry *ext) -{ - char *name; - char **aliases; - - if (!ext) - return FALSE ; - aliases = (char **)xrealloc(ext->aliases, - (ext->num_aliases + 1) * sizeof(char *)); - if (!aliases) - return FALSE; - ext->aliases = aliases; - name = xalloc(strlen(alias) + 1); - if (!name) - return FALSE; - strcpy(name, alias); - ext->aliases[ext->num_aliases] = name; - ext->num_aliases++; - return TRUE; -} - -static int -FindExtension(char *extname, int len) -{ - int i, j; - - for (i=0; iname) == 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); -} - -/* - * CheckExtension returns the extensions[] entry for the requested - * extension name. Maybe this could just return a Bool instead? - */ -ExtensionEntry * -CheckExtension(const char *extname) -{ - int n; - - n = FindExtension((char*)extname, strlen(extname)); - if (n != -1) - return extensions[n]; - else - return NULL; -} - -/* - * Added as part of Xace. - */ -ExtensionEntry * -GetExtensionEntry(int major) -{ - if (major < EXTENSION_BASE) - return NULL; - major -= EXTENSION_BASE; - if (major >= NumExtensions) - return NULL; - return extensions[major]; -} - -unsigned short -StandardMinorOpcode(ClientPtr client) -{ - return ((xReq *)client->requestBuffer)->data; -} - -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(void) -{ - int i,j; - - for (i = NumExtensions - 1; i >= 0; i--) - { - if (extensions[i]->CloseDown) - extensions[i]->CloseDown(extensions[i]); - NumExtensions = i; - xfree(extensions[i]->name); - for (j = extensions[i]->num_aliases; --j >= 0;) - xfree(extensions[i]->aliases[j]); - xfree(extensions[i]->aliases); - dixFreePrivates(extensions[i]->devPrivates); - xfree(extensions[i]); - } - xfree(extensions); - extensions = (ExtensionEntry **)NULL; - lastEvent = EXTENSION_EVENT_BASE; - lastError = FirstExtensionError; -} - -int -ProcQueryExtension(ClientPtr client) -{ - xQueryExtensionReply reply; - int i; - REQUEST(xQueryExtensionReq); - - REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes); - - memset(&reply, 0, sizeof(xQueryExtensionReply)); - 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 || XaceHook(XACE_EXT_ACCESS, client, extensions[i])) - 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; - char *bufptr, *buffer; - int total_length = 0; - - REQUEST_SIZE_MATCH(xReq); - - memset(&reply, 0, sizeof(xListExtensionsReply)); - reply.type = X_Reply; - reply.nExtensions = 0; - reply.length = 0; - reply.sequenceNumber = client->sequence; - buffer = NULL; - - if ( NumExtensions ) - { - int i, j; - - for (i=0; iname) + 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 = bytes_to_int32(total_length); - buffer = bufptr = xalloc(total_length); - if (!buffer) - return(BadAlloc); - for (i=0; iname); - 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); - xfree(buffer); - } - return(client->noClientException); -} +/*********************************************************** + +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" +#include "privates.h" +#include "registry.h" +#include "xace.h" + +#define LAST_EVENT 128 +#define LAST_ERROR 255 + +static ExtensionEntry **extensions = (ExtensionEntry **)NULL; + +int lastEvent = EXTENSION_EVENT_BASE; +static int lastError = FirstExtensionError; +static unsigned int NumExtensions = 0; + +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 || !MinorOpcodeProc) + return((ExtensionEntry *) NULL); + if ((lastEvent + NumEvents > LAST_EVENT) || + (unsigned)(lastError + NumErrors > LAST_ERROR)) { + LogMessage(X_ERROR, "Not enabling extension %s: maximum number of " + "events or errors exceeded.\n", name); + return((ExtensionEntry *) NULL); + } + + ext = malloc(sizeof(ExtensionEntry)); + if (!ext) + return(NULL); + ext->name = malloc(strlen(name) + 1); + ext->num_aliases = 0; + ext->aliases = (char **)NULL; + ext->devPrivates = 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; + } + + RegisterExtensionNames(ext); + return(ext); +} + +Bool AddExtensionAlias(char *alias, ExtensionEntry *ext) +{ + char *name; + char **aliases; + + if (!ext) + return FALSE ; + aliases = (char **)realloc(ext->aliases, + (ext->num_aliases + 1) * sizeof(char *)); + if (!aliases) + return FALSE; + ext->aliases = aliases; + name = malloc(strlen(alias) + 1); + if (!name) + return FALSE; + strcpy(name, alias); + ext->aliases[ext->num_aliases] = name; + ext->num_aliases++; + return TRUE; +} + +static int +FindExtension(char *extname, int len) +{ + int i, j; + + for (i=0; iname) == 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); +} + +/* + * CheckExtension returns the extensions[] entry for the requested + * extension name. Maybe this could just return a Bool instead? + */ +ExtensionEntry * +CheckExtension(const char *extname) +{ + int n; + + n = FindExtension((char*)extname, strlen(extname)); + if (n != -1) + return extensions[n]; + else + return NULL; +} + +/* + * Added as part of Xace. + */ +ExtensionEntry * +GetExtensionEntry(int major) +{ + if (major < EXTENSION_BASE) + return NULL; + major -= EXTENSION_BASE; + if (major >= NumExtensions) + return NULL; + return extensions[major]; +} + +unsigned short +StandardMinorOpcode(ClientPtr client) +{ + return ((xReq *)client->requestBuffer)->data; +} + +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(void) +{ + int i,j; + + for (i = NumExtensions - 1; i >= 0; i--) + { + if (extensions[i]->CloseDown) + 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); + dixFreePrivates(extensions[i]->devPrivates); + free(extensions[i]); + } + free(extensions); + extensions = (ExtensionEntry **)NULL; + lastEvent = EXTENSION_EVENT_BASE; + lastError = FirstExtensionError; +} + +int +ProcQueryExtension(ClientPtr client) +{ + xQueryExtensionReply reply; + int i; + REQUEST(xQueryExtensionReq); + + REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes); + + memset(&reply, 0, sizeof(xQueryExtensionReply)); + 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 || XaceHook(XACE_EXT_ACCESS, client, extensions[i])) + 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 Success; +} + +int +ProcListExtensions(ClientPtr client) +{ + xListExtensionsReply reply; + char *bufptr, *buffer; + int total_length = 0; + + REQUEST_SIZE_MATCH(xReq); + + memset(&reply, 0, sizeof(xListExtensionsReply)); + reply.type = X_Reply; + reply.nExtensions = 0; + reply.length = 0; + reply.sequenceNumber = client->sequence; + buffer = NULL; + + if ( NumExtensions ) + { + int i, j; + + for (i=0; iname) + 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 = bytes_to_int32(total_length); + buffer = bufptr = malloc(total_length); + if (!buffer) + return(BadAlloc); + for (i=0; iname); + 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); + free(buffer); + } + return Success; +} diff --git a/xorg-server/dix/gc.c b/xorg-server/dix/gc.c index 3058e1541..b738d4112 100644 --- a/xorg-server/dix/gc.c +++ b/xorg-server/dix/gc.c @@ -1,1234 +1,1158 @@ -/*********************************************************** - -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 "privates.h" -#include "dix.h" -#include "xace.h" -#include - -extern XID clientErrorValue; -extern FontPtr defaultFont; - -static Bool CreateDefaultTile(GCPtr pGC); - -static unsigned char DefaultDash[2] = {4, 4}; - -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++; } - -int -dixChangeGC(ClientPtr client, GC *pGC, BITS32 mask, CARD32 *pC32, ChangeGCValPtr pUnion) -{ - BITS32 index2; - int rc, 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: - if (pUnion) - { - NEXT_PTR(PixmapPtr, pPixmap); - } - else - { - XID newpix; - NEXTVAL(XID, newpix); - rc = dixLookupResourceByType((pointer *)&pPixmap, newpix, - RT_PIXMAP, client, DixReadAccess); - if (rc != Success) - { - clientErrorValue = newpix; - error = (rc == BadValue) ? BadPixmap : rc; - break; - } - } - 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; - } - break; - case GCStipple: - if (pUnion) - { - NEXT_PTR(PixmapPtr, pPixmap); - } - else - { - XID newstipple; - NEXTVAL(XID, newstipple) - rc = dixLookupResourceByType((pointer *)&pPixmap, newstipple, - RT_PIXMAP, client, DixReadAccess); - if (rc != Success) - { - clientErrorValue = newstipple; - error = (rc == BadValue) ? BadPixmap : rc; - break; - } - } - 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; - } - break; - case GCTileStipXOrigin: - NEXTVAL(INT16, pGC->patOrg.x); - break; - case GCTileStipYOrigin: - NEXTVAL(INT16, pGC->patOrg.y); - break; - case GCFont: - { - FontPtr pFont; - if (pUnion) - { - NEXT_PTR(FontPtr, pFont); - } - else - { - XID newfont; - NEXTVAL(XID, newfont) - rc = dixLookupResourceByType((pointer *)&pFont, newfont, - RT_FONT, client, DixUseAccess); - if (rc != Success) - { - clientErrorValue = newfont; - error = (rc == BadValue) ? BadFont : rc; - break; - } - } - pFont->refcnt++; - if (pGC->font) - CloseFont(pGC->font, (Font)0); - pGC->font = pFont; - 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: - if (pUnion) - { - NEXT_PTR(PixmapPtr, pPixmap); - } - else - { - Pixmap pid; - NEXTVAL(Pixmap, pid) - if (pid == None) - pPixmap = NullPixmap; - else { - rc = dixLookupResourceByType((pointer *)&pPixmap, pid, - RT_PIXMAP, client, - DixReadAccess); - if (rc != Success) { - clientErrorValue = pid; - error = (rc == BadValue) ? BadPixmap : rc; - break; - } - } - } - - if (pPixmap) - { - if ((pPixmap->drawable.depth != 1) || - (pPixmap->drawable.pScreen != pGC->pScreen)) - { - error = BadMatch; - break; - } - pPixmap->refcnt++; - } - (*pGC->funcs->ChangeClip)(pGC, pPixmap ? CT_PIXMAP : CT_NONE, - (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) - { - xfree(pGC->dash); - pGC->numInDashList = 2; - pGC->dash = DefaultDash; - } - } - else if (newdash != 0) - { - unsigned char *dash; - - dash = xalloc(2 * sizeof(unsigned char)); - if (dash) - { - if (pGC->dash != DefaultDash) - xfree(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 */ -int -ChangeGC(GC *pGC, 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 -*/ -int -DoChangeGC(GC *pGC, 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 - -*/ -GCPtr -CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus, - XID gcid, ClientPtr client) -{ - GCPtr pGC; - - pGC = xalloc(sizeof(GC)); - 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->devPrivates = NULL; - 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->tile.pixel = 0; - pGC->tile.pixmap = NullPixmap; - 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; - } - else - { - pGC->tileIsPixel = TRUE; - } - - 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++; - - /* security creation/labeling check */ - *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC, - RT_NONE, NULL, DixCreateAccess|DixSetAttrAccess); - if (*pStatus != Success) - goto out; - - pGC->stateChanges = (1 << (GCLastBit+1)) - 1; - if (!(*pGC->pScreen->CreateGC)(pGC)) - *pStatus = BadAlloc; - else if (mask) - *pStatus = ChangeGC(pGC, mask, pval); - else - *pStatus = Success; - -out: - 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, 0); - 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; -} - -int -CopyGC(GC *pgcSrc, GC *pgcDst, 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) - { - xfree(pgcDst->dash); - pgcDst->numInDashList = pgcSrc->numInDashList; - pgcDst->dash = pgcSrc->dash; - } - } - else - { - unsigned char *dash; - unsigned int i; - - dash = xalloc(pgcSrc->numInDashList * sizeof(unsigned char)); - if (dash) - { - if (pgcDst->dash != DefaultDash) - xfree(pgcDst->dash); - pgcDst->numInDashList = pgcSrc->numInDashList; - pgcDst->dash = dash; - for (i=0; inumInDashList; 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 - */ -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) - xfree(pGC->dash); - dixFreePrivates(pGC->devPrivates); - xfree(pGC); - return(Success); -} - -/* 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().) -*/ - -GCPtr -CreateScratchGC(ScreenPtr pScreen, unsigned depth) -{ - GCPtr pGC; - - pGC = xalloc(sizeof(GC)); - if (!pGC) - return (GCPtr)NULL; - - pGC->pScreen = pScreen; - pGC->depth = depth; - pGC->alu = GXcopy; /* dst <- src */ - pGC->planemask = ~0; - pGC->serialNumber = 0; - pGC->devPrivates = NULL; - 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->tile.pixmap = NullPixmap; - 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; inumDepths; 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, 0))) - 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]); -} - -int -SetDashes(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 = xalloc(2 * ndash * sizeof(unsigned char)); - else - p = xalloc(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) - xfree(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; -} - -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; -} - -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 = xalloc(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.) -*/ -GCPtr -GetScratchGC(unsigned depth, 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 -*/ -void -FreeScratchGC(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); -} +/*********************************************************** + +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 "privates.h" +#include "dix.h" +#include "xace.h" +#include + +extern FontPtr defaultFont; + +static Bool CreateDefaultTile(GCPtr pGC); + +static unsigned char DefaultDash[2] = {4, 4}; + +void +ValidateGC(DrawablePtr pDraw, GC *pGC) +{ + (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw); + pGC->stateChanges = 0; + pGC->serialNumber = pDraw->serialNumber; +} + + +/* + * ChangeGC/ChangeGCXIDs: + * + * 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. + * + * If you have any XIDs, you must use ChangeGCXIDs: + * + * CARD32 v[2]; + * v[0] = FillTiled; + * v[1] = pid; + * ChangeGCXIDs(client, pGC, GCFillStyle|GCTile, v); + * + * However, if you need to pass a pointer to a pixmap or font, you must + * use ChangeGC: + * + * ChangeGCVal v[2]; + * v[0].val = FillTiled; + * v[1].ptr = pPixmap; + * ChangeGC(client, pGC, GCFillStyle|GCTile, v); + * + * If you have neither XIDs nor pointers, you can use either function, + * but ChangeGC will do less work. + * + * ChangeGCVal v[2]; + * v[0].val = foreground; + * v[1].val = background; + * ChangeGC(client, pGC, GCForeground|GCBackground, v); + */ + +#define NEXTVAL(_type, _var) { \ + _var = (_type)(pUnion->val); pUnion++; \ + } + +#define NEXT_PTR(_type, _var) { \ + _var = (_type)pUnion->ptr; pUnion++; } + +int +ChangeGC(ClientPtr client, GC *pGC, BITS32 mask, ChangeGCValPtr pUnion) +{ + BITS32 index2; + int error = 0; + PixmapPtr pPixmap; + BITS32 maskQ; + + assert(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 + { + if (client) + client->errorValue = 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 + { + if (client) + client->errorValue = newlinestyle; + error = BadValue; + } + break; + } + case GCCapStyle: + { + unsigned int newcapstyle; + NEXTVAL(unsigned int, newcapstyle); + if (newcapstyle <= CapProjecting) + pGC->capStyle = newcapstyle; + else + { + if (client) + client->errorValue = newcapstyle; + error = BadValue; + } + break; + } + case GCJoinStyle: + { + unsigned int newjoinstyle; + NEXTVAL(unsigned int, newjoinstyle); + if (newjoinstyle <= JoinBevel) + pGC->joinStyle = newjoinstyle; + else + { + if (client) + client->errorValue = newjoinstyle; + error = BadValue; + } + break; + } + case GCFillStyle: + { + unsigned int newfillstyle; + NEXTVAL(unsigned int, newfillstyle); + if (newfillstyle <= FillOpaqueStippled) + pGC->fillStyle = newfillstyle; + else + { + if (client) + client->errorValue = newfillstyle; + error = BadValue; + } + break; + } + case GCFillRule: + { + unsigned int newfillrule; + NEXTVAL(unsigned int, newfillrule); + if (newfillrule <= WindingRule) + pGC->fillRule = newfillrule; + else + { + if (client) + client->errorValue = newfillrule; + error = BadValue; + } + break; + } + case GCTile: + NEXT_PTR(PixmapPtr, 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; + } + break; + case GCStipple: + NEXT_PTR(PixmapPtr, 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; + } + break; + case GCTileStipXOrigin: + NEXTVAL(INT16, pGC->patOrg.x); + break; + case GCTileStipYOrigin: + NEXTVAL(INT16, pGC->patOrg.y); + break; + case GCFont: + { + FontPtr pFont; + NEXT_PTR(FontPtr, pFont); + pFont->refcnt++; + if (pGC->font) + CloseFont(pGC->font, (Font)0); + pGC->font = pFont; + break; + } + case GCSubwindowMode: + { + unsigned int newclipmode; + NEXTVAL(unsigned int, newclipmode); + if (newclipmode <= IncludeInferiors) + pGC->subWindowMode = newclipmode; + else + { + if (client) + client->errorValue = newclipmode; + error = BadValue; + } + break; + } + case GCGraphicsExposures: + { + unsigned int newge; + NEXTVAL(unsigned int, newge); + if (newge <= xTrue) + pGC->graphicsExposures = newge; + else + { + if (client) + client->errorValue = newge; + error = BadValue; + } + break; + } + case GCClipXOrigin: + NEXTVAL(INT16, pGC->clipOrg.x); + break; + case GCClipYOrigin: + NEXTVAL(INT16, pGC->clipOrg.y); + break; + case GCClipMask: + NEXT_PTR(PixmapPtr, pPixmap); + if (pPixmap) + { + if ((pPixmap->drawable.depth != 1) || + (pPixmap->drawable.pScreen != pGC->pScreen)) + { + error = BadMatch; + break; + } + pPixmap->refcnt++; + } + (*pGC->funcs->ChangeClip)(pGC, pPixmap ? CT_PIXMAP : CT_NONE, + (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 + { + if (client) + client->errorValue = newdash; + error = BadValue; + } + break; + } + case GCArcMode: + { + unsigned int newarcmode; + NEXTVAL(unsigned int, newarcmode); + if (newarcmode <= ArcPieSlice) + pGC->arcMode = newarcmode; + else + { + if (client) + client->errorValue = newarcmode; + error = BadValue; + } + break; + } + default: + if (client) + client->errorValue = 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 + +static const struct { + BITS32 mask; + RESTYPE type; + Mask access_mode; +} xidfields[] = { + { GCTile, RT_PIXMAP, DixReadAccess }, + { GCStipple, RT_PIXMAP, DixReadAccess }, + { GCFont, RT_FONT, DixUseAccess }, + { GCClipMask, RT_PIXMAP, DixReadAccess }, +}; + +int +ChangeGCXIDs(ClientPtr client, GC *pGC, BITS32 mask, CARD32 *pC32) +{ + ChangeGCVal vals[GCLastBit + 1]; + int i; + if (mask & ~GCAllBits) + { + client->errorValue = mask; + return BadValue; + } + for (i = Ones(mask); i--; ) + vals[i].val = pC32[i]; + for (i = 0; i < sizeof(xidfields) / sizeof(*xidfields); ++i) + { + int offset, rc; + if (!(mask & xidfields[i].mask)) + continue; + offset = Ones(mask & (xidfields[i].mask - 1)); + if (xidfields[i].mask == GCClipMask && vals[offset].val == None) + { + vals[offset].ptr = NullPixmap; + continue; + } + rc = dixLookupResourceByType(&vals[offset].ptr, vals[offset].val, + xidfields[i].type, client, xidfields[i].access_mode); + if (rc != Success) + { + client->errorValue = vals[offset].val; + if (rc == BadValue) + rc = (xidfields[i].type == RT_PIXMAP) ? BadPixmap : BadFont; + return rc; + } + } + return ChangeGC(client, pGC, mask, vals); +} + +/* 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 + +*/ +GCPtr +CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus, + XID gcid, ClientPtr client) +{ + GCPtr pGC; + + pGC = malloc(sizeof(GC)); + 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->devPrivates = NULL; + 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->tile.pixel = 0; + pGC->tile.pixmap = NullPixmap; + 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; + } + else + { + pGC->tileIsPixel = TRUE; + } + + 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++; + + /* security creation/labeling check */ + *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC, + RT_NONE, NULL, DixCreateAccess|DixSetAttrAccess); + if (*pStatus != Success) + goto out; + + pGC->stateChanges = GCAllBits; + if (!(*pGC->pScreen->CreateGC)(pGC)) + *pStatus = BadAlloc; + else if (mask) + *pStatus = ChangeGCXIDs(client, pGC, mask, pval); + else + *pStatus = Success; + +out: + 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) +{ + ChangeGCVal 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, 0); + pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen); + if (!pTile || !pgcScratch) + { + if (pTile) + (*pTile->drawable.pScreen->DestroyPixmap)(pTile); + if (pgcScratch) + FreeScratchGC(pgcScratch); + return FALSE; + } + tmpval[0].val = GXcopy; + tmpval[1].val = pGC->tile.pixel; + tmpval[2].val = FillSolid; + (void)ChangeGC(NullClient, 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; +} + +int +CopyGC(GC *pgcSrc, GC *pgcDst, 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; inumInDashList; i++) + dash[i] = pgcSrc->dash[i]; + } + else + error = BadAlloc; + } + break; + case GCArcMode: + pgcDst->arcMode = pgcSrc->arcMode; + break; + default: + FatalError ("CopyGC: Unhandled mask!\n"); + } + } + 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 + */ +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); + dixFreePrivates(pGC->devPrivates); + free(pGC); + return(Success); +} + +/* 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().) +*/ + +GCPtr +CreateScratchGC(ScreenPtr pScreen, unsigned depth) +{ + GCPtr pGC; + + pGC = malloc(sizeof(GC)); + if (!pGC) + return (GCPtr)NULL; + + pGC->pScreen = pScreen; + pGC->depth = depth; + pGC->alu = GXcopy; /* dst <- src */ + pGC->planemask = ~0; + pGC->serialNumber = 0; + pGC->devPrivates = NULL; + 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->tile.pixmap = NullPixmap; + 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 = GCAllBits; + 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; inumDepths; 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; + ChangeGCVal 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, 0))) + return FALSE; + /* fill stipple with 1 */ + tmpval[0].val = GXcopy; + tmpval[1].val = 1; + tmpval[2].val = FillSolid; + pgcScratch = GetScratchGC(1, pScreen); + if (!pgcScratch) + { + (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]); + return FALSE; + } + (void)ChangeGC(NullClient, 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]); +} + +int +SetDashes(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 */ + 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; +} + +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; +} + +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.) +*/ +GCPtr +GetScratchGC(unsigned depth, 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 = GCAllBits; + 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 +*/ +void +FreeScratchGC(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/xorg-server/dix/getevents.c b/xorg-server/dix/getevents.c index 197deb4fb..7a24b801e 100644 --- a/xorg-server/dix/getevents.c +++ b/xorg-server/dix/getevents.c @@ -1,1208 +1,1208 @@ -/* - * Copyright © 2006 Nokia Corporation - * Copyright © 2006-2007 Daniel Stone - * Copyright © 2008 Red Hat, Inc. - * - * 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. - * - * Authors: Daniel Stone - * Peter Hutterer - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "misc.h" -#include "resource.h" -#include "inputstr.h" -#include "scrnintstr.h" -#include "cursorstr.h" -#include "dixstruct.h" -#include "globals.h" -#include "dixevents.h" -#include "mipointer.h" -#include "eventstr.h" -#include "eventconvert.h" - -#include -#include "xkbsrv.h" - -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif - -#include -#include -#include "exglobals.h" -#include "exevents.h" -#include "exglobals.h" -#include "extnsionst.h" -#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */ - -/* Number of motion history events to store. */ -#define MOTION_HISTORY_SIZE 256 - -/* InputEventList is the container list for all input events generated by the - * DDX. The DDX is expected to call GetEventList() and then pass the list into - * Get{Pointer|Keyboard}Events. - */ -EventListPtr InputEventList = NULL; -int InputEventListLen = 0; - -int -GetEventList(EventListPtr* list) -{ - *list = InputEventList; - return InputEventListLen; -} - -/** - * Pick some arbitrary size for Xi motion history. - */ -int -GetMotionHistorySize(void) -{ - return MOTION_HISTORY_SIZE; -} - -void -set_key_down(DeviceIntPtr pDev, int key_code, int type) -{ - if (type == KEY_PROCESSED) - pDev->key->down[key_code >> 3] |= (1 << (key_code & 7)); - else - pDev->key->postdown[key_code >> 3] |= (1 << (key_code & 7)); -} - -void -set_key_up(DeviceIntPtr pDev, int key_code, int type) -{ - if (type == KEY_PROCESSED) - pDev->key->down[key_code >> 3] &= ~(1 << (key_code & 7)); - else - pDev->key->postdown[key_code >> 3] &= ~(1 << (key_code & 7)); -} - -Bool -key_is_down(DeviceIntPtr pDev, int key_code, int type) -{ - int ret = 0; - - if (type & KEY_PROCESSED) - ret |= !!(pDev->key->down[key_code >> 3] & (1 << (key_code & 7))); - else if (type & KEY_POSTED) - ret |= !!(pDev->key->postdown[key_code >> 3] & (1 << (key_code & 7))); - - return ret; -} - -static Bool -key_autorepeats(DeviceIntPtr pDev, int key_code) -{ - return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] & - (1 << (key_code & 7))); -} - -static void -init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms) -{ - memset(event, 0, sizeof(DeviceEvent)); - event->header = ET_Internal; - event->length = sizeof(DeviceEvent); - event->time = ms; - event->deviceid = dev->id; - event->sourceid = dev->id; -} - -static void -init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail) -{ - memset(event, 0, sizeof(RawDeviceEvent)); - event->header = ET_Internal; - event->length = sizeof(RawDeviceEvent); - event->type = ET_RawKeyPress - ET_KeyPress + type; - event->time = ms; - event->deviceid = dev->id; - event->sourceid = dev->id; - event->detail.button = detail; -} - -static void -set_raw_valuators(RawDeviceEvent *event, int first, int num, int *valuators, int32_t* data) -{ - int i; - for (i = first; i < first + num; i++) - SetBit(event->valuators.mask, i); - - memcpy(&data[first], valuators, num * sizeof(uint32_t)); -} - - -static void -set_valuators(DeviceIntPtr dev, DeviceEvent* event, int first_valuator, - int num_valuators, int *valuators) -{ - int i; - - for (i = first_valuator; i < first_valuator + num_valuators; i++) - { - SetBit(event->valuators.mask, i); - if (dev->valuator->mode == Absolute) - SetBit(event->valuators.mode, i); - event->valuators.data_frac[i] = - dev->last.remainder[i] * (1 << 16) * (1 << 16); - } - - memcpy(&event->valuators.data[first_valuator], - valuators, num_valuators * sizeof(uint32_t)); - -} - -void -CreateClassesChangedEvent(EventList* event, - DeviceIntPtr master, - DeviceIntPtr slave, - int type) -{ - int i; - DeviceChangedEvent *dce; - CARD32 ms = GetTimeInMillis(); - - dce = (DeviceChangedEvent*)event->event; - memset(dce, 0, sizeof(DeviceChangedEvent)); - dce->deviceid = slave->id; - dce->masterid = master->id; - dce->header = ET_Internal; - dce->length = sizeof(DeviceChangedEvent); - dce->type = ET_DeviceChanged; - dce->time = ms; - dce->flags = type; - dce->flags |= DEVCHANGE_SLAVE_SWITCH; - dce->sourceid = slave->id; - - if (slave->button) - { - dce->buttons.num_buttons = slave->button->numButtons; - for (i = 0; i < dce->buttons.num_buttons; i++) - dce->buttons.names[i] = slave->button->labels[i]; - } - if (slave->valuator) - { - dce->num_valuators = slave->valuator->numAxes; - for (i = 0; i < dce->num_valuators; i++) - { - dce->valuators[i].min = slave->valuator->axes[i].min_value; - dce->valuators[i].max = slave->valuator->axes[i].max_value; - dce->valuators[i].resolution = slave->valuator->axes[i].resolution; - /* This should, eventually, be a per-axis mode */ - dce->valuators[i].mode = slave->valuator->mode; - dce->valuators[i].name = slave->valuator->axes[i].label; - } - } - if (slave->key) - { - dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code; - dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code; - } -} - -/** - * Rescale the coord between the two axis ranges. - */ -static int -rescaleValuatorAxis(int coord, float remainder, float *remainder_return, AxisInfoPtr from, AxisInfoPtr to, - int defmax) -{ - int fmin = 0, tmin = 0, fmax = defmax, tmax = defmax, coord_return; - float value; - - if(from && from->min_value < from->max_value) { - fmin = from->min_value; - fmax = from->max_value; - } - if(to && to->min_value < to->max_value) { - tmin = to->min_value; - tmax = to->max_value; - } - - if(fmin == tmin && fmax == tmax) { - if (remainder_return) - *remainder_return = remainder; - return coord; - } - - if(fmax == fmin) { /* avoid division by 0 */ - if (remainder_return) - *remainder_return = 0.0; - return 0; - } - - value = (coord + remainder - fmin) * (tmax - tmin) / (fmax - fmin) + tmin; - coord_return = lroundf(value); - if (remainder_return) - *remainder_return = value - coord_return; - return coord_return; -} - -/** - * Update all coordinates when changing to a different SD - * to ensure that relative reporting will work as expected - * without loss of precision. - * - * pDev->last.valuators will be in absolute device coordinates after this - * function. - */ -static void -updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev) -{ - ScreenPtr scr = miPointerGetScreen(pDev); - int i; - DeviceIntPtr lastSlave; - - /* master->last.valuators[0]/[1] is in screen coords and the actual - * position of the pointer */ - pDev->last.valuators[0] = master->last.valuators[0]; - pDev->last.valuators[1] = master->last.valuators[1]; - - if (!pDev->valuator) - return; - - /* scale back to device coordinates */ - if(pDev->valuator->numAxes > 0) - pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], pDev->last.remainder[0], - &pDev->last.remainder[0], NULL, pDev->valuator->axes + 0, scr->width); - if(pDev->valuator->numAxes > 1) - pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], pDev->last.remainder[1], - &pDev->last.remainder[1], NULL, pDev->valuator->axes + 1, scr->height); - - /* calculate the other axis as well based on info from the old - * slave-device. If the old slave had less axes than this one, - * last.valuators is reset to 0. - */ - if ((lastSlave = master->last.slave) && lastSlave->valuator) { - for (i = 2; i < pDev->valuator->numAxes; i++) { - if (i >= lastSlave->valuator->numAxes) - pDev->last.valuators[i] = 0; - else - pDev->last.valuators[i] = - rescaleValuatorAxis(pDev->last.valuators[i], - pDev->last.remainder[i], - &pDev->last.remainder[i], - lastSlave->valuator->axes + i, - pDev->valuator->axes + i, 0); - } - } - -} - -/** - * Allocate the motion history buffer. - */ -void -AllocateMotionHistory(DeviceIntPtr pDev) -{ - int size; - if (pDev->valuator->motion) - xfree(pDev->valuator->motion); - - if (pDev->valuator->numMotionEvents < 1) - return; - - /* An MD must have a motion history size large enough to keep all - * potential valuators, plus the respective range of the valuators. - * 3 * INT32 for (min_val, max_val, curr_val)) - */ - if (IsMaster(pDev)) - size = sizeof(INT32) * 3 * MAX_VALUATORS; - else - size = sizeof(INT32) * pDev->valuator->numAxes; - - size += sizeof(Time); - - pDev->valuator->motion = xcalloc(pDev->valuator->numMotionEvents, size); - pDev->valuator->first_motion = 0; - pDev->valuator->last_motion = 0; - if (!pDev->valuator->motion) - ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n", - pDev->name, size * pDev->valuator->numMotionEvents); -} - -/** - * Dump the motion history between start and stop into the supplied buffer. - * Only records the event for a given screen in theory, but in practice, we - * sort of ignore this. - * - * If core is set, we only generate x/y, in INT16, scaled to screen coords. - */ -int -GetMotionHistory(DeviceIntPtr pDev, xTimecoord **buff, unsigned long start, - unsigned long stop, ScreenPtr pScreen, BOOL core) -{ - char *ibuff = NULL, *obuff; - int i = 0, ret = 0; - int j, coord; - Time current; - /* The size of a single motion event. */ - int size; - int dflt; - AxisInfo from, *to; /* for scaling */ - INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */ - INT16 *corebuf; - AxisInfo core_axis = {0}; - - if (!pDev->valuator || !pDev->valuator->numMotionEvents) - return 0; - - if (core && !pScreen) - return 0; - - if (IsMaster(pDev)) - size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time); - else - size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); - - *buff = xalloc(size * pDev->valuator->numMotionEvents); - if (!(*buff)) - return 0; - obuff = (char *)*buff; - - for (i = pDev->valuator->first_motion; - i != pDev->valuator->last_motion; - i = (i + 1) % pDev->valuator->numMotionEvents) { - /* We index the input buffer by which element we're accessing, which - * is not monotonic, and the output buffer by how many events we've - * written so far. */ - ibuff = (char *) pDev->valuator->motion + (i * size); - memcpy(¤t, ibuff, sizeof(Time)); - - if (current > stop) { - return ret; - } - else if (current >= start) { - if (core) - { - memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ - - icbuf = (INT32*)(ibuff + sizeof(Time)); - corebuf = (INT16*)(obuff + sizeof(Time)); - - /* fetch x coordinate + range */ - memcpy(&from.min_value, icbuf++, sizeof(INT32)); - memcpy(&from.max_value, icbuf++, sizeof(INT32)); - memcpy(&coord, icbuf++, sizeof(INT32)); - - /* scale to screen coords */ - to = &core_axis; - to->max_value = pScreen->width; - coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->width); - - memcpy(corebuf, &coord, sizeof(INT16)); - corebuf++; - - /* fetch y coordinate + range */ - memcpy(&from.min_value, icbuf++, sizeof(INT32)); - memcpy(&from.max_value, icbuf++, sizeof(INT32)); - memcpy(&coord, icbuf++, sizeof(INT32)); - - to->max_value = pScreen->height; - coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->height); - memcpy(corebuf, &coord, sizeof(INT16)); - - } else if (IsMaster(pDev)) - { - memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ - - ocbuf = (INT32*)(obuff + sizeof(Time)); - icbuf = (INT32*)(ibuff + sizeof(Time)); - for (j = 0; j < MAX_VALUATORS; j++) - { - if (j >= pDev->valuator->numAxes) - break; - - /* fetch min/max/coordinate */ - memcpy(&from.min_value, icbuf++, sizeof(INT32)); - memcpy(&from.max_value, icbuf++, sizeof(INT32)); - memcpy(&coord, icbuf++, sizeof(INT32)); - - to = (j < pDev->valuator->numAxes) ? &pDev->valuator->axes[j] : NULL; - - /* x/y scaled to screen if no range is present */ - if (j == 0 && (from.max_value < from.min_value)) - from.max_value = pScreen->width; - else if (j == 1 && (from.max_value < from.min_value)) - from.max_value = pScreen->height; - - if (j == 0 && (to->max_value < to->min_value)) - dflt = pScreen->width; - else if (j == 1 && (to->max_value < to->min_value)) - dflt = pScreen->height; - else - dflt = 0; - - /* scale from stored range into current range */ - coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, 0); - memcpy(ocbuf, &coord, sizeof(INT32)); - ocbuf++; - } - } else - memcpy(obuff, ibuff, size); - - /* don't advance by size here. size may be different to the - * actually written size if the MD has less valuators than MAX */ - if (core) - obuff += sizeof(INT32) + sizeof(Time); - else - obuff += (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); - ret++; - } - } - - return ret; -} - - -/** - * Update the motion history for a specific device, with the list of - * valuators. - * - * Layout of the history buffer: - * for SDs: [time] [val0] [val1] ... [valn] - * for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn] - * - * For events that have some valuators unset (first_valuator > 0): - * min_val == max_val == val == 0. - */ -static void -updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, int first_valuator, - int num_valuators, int *valuators) -{ - char *buff = (char *) pDev->valuator->motion; - ValuatorClassPtr v; - int i; - - if (!pDev->valuator->numMotionEvents) - return; - - v = pDev->valuator; - if (IsMaster(pDev)) - { - buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) * - v->last_motion; - - memcpy(buff, &ms, sizeof(Time)); - buff += sizeof(Time); - - memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS); - buff += 3 * sizeof(INT32) * first_valuator; - - for (i = first_valuator; i < first_valuator + num_valuators; i++) - { - if (i >= v->numAxes) - break; - memcpy(buff, &v->axes[i].min_value, sizeof(INT32)); - buff += sizeof(INT32); - memcpy(buff, &v->axes[i].max_value, sizeof(INT32)); - buff += sizeof(INT32); - memcpy(buff, &valuators[i - first_valuator], sizeof(INT32)); - buff += sizeof(INT32); - } - } else - { - - buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) * - pDev->valuator->last_motion; - - memcpy(buff, &ms, sizeof(Time)); - buff += sizeof(Time); - - memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes); - buff += sizeof(INT32) * first_valuator; - - memcpy(buff, valuators, sizeof(INT32) * num_valuators); - } - - pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) % - pDev->valuator->numMotionEvents; - /* If we're wrapping around, just keep the circular buffer going. */ - if (pDev->valuator->first_motion == pDev->valuator->last_motion) - pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) % - pDev->valuator->numMotionEvents; - - return; -} - - -/** - * Returns the maximum number of events GetKeyboardEvents, - * GetKeyboardValuatorEvents, and GetPointerEvents will ever return. - * - * This MUST be absolutely constant, from init until exit. - */ -int -GetMaximumEventsNum(void) { - /* One raw event - * One device event - * One possible device changed event - */ - return 3; -} - - -/** - * Clip an axis to its bounds, which are declared in the call to - * InitValuatorAxisClassStruct. - */ -static void -clipAxis(DeviceIntPtr pDev, int axisNum, int *val) -{ - AxisInfoPtr axis; - - if (axisNum >= pDev->valuator->numAxes) - return; - - axis = pDev->valuator->axes + axisNum; - - /* If a value range is defined, clip. If not, do nothing */ - if (axis->max_value <= axis->min_value) - return; - - if (*val < axis->min_value) - *val = axis->min_value; - if (*val > axis->max_value) - *val = axis->max_value; -} - -/** - * Clip every axis in the list of valuators to its bounds. - */ -static void -clipValuators(DeviceIntPtr pDev, int first_valuator, int num_valuators, - int *valuators) -{ - int i; - - for (i = 0; i < num_valuators; i++) - clipAxis(pDev, i + first_valuator, &(valuators[i])); -} - -/** - * Create the DCCE event (does not update the master's device state yet, this - * is done in the event processing). - * Pull in the coordinates from the MD if necessary. - * - * @param events Pointer to a pre-allocated event list. - * @param dev The slave device that generated an event. - * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT - * @param num_events The current number of events, returns the number of - * events if a DCCE was generated. - * @return The updated @events pointer. - */ -static EventListPtr -updateFromMaster(EventListPtr events, DeviceIntPtr dev, int type, int *num_events) -{ - DeviceIntPtr master; - - master = GetMaster(dev, (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER : MASTER_KEYBOARD); - - if (master && master->last.slave != dev) - { - CreateClassesChangedEvent(events, master, dev, type); - if (IsPointerDevice(master)) - { - updateSlaveDeviceCoords(master, dev); - master->last.numValuators = dev->last.numValuators; - } - master->last.slave = dev; - (*num_events)++; - events++; - } - return events; -} - -/** - * Move the device's pointer to the position given in the valuators. - * - * @param dev The device which's pointer is to be moved. - * @param x Returns the x position of the pointer after the move. - * @param y Returns the y position of the pointer after the move. - * @param first The first valuator in @valuators - * @param num Total number of valuators in @valuators. - * @param valuators Valuator data for each axis between @first and - * @first+@num. - */ -static void -moveAbsolute(DeviceIntPtr dev, int *x, int *y, - int first, int num, int *valuators) -{ - int i; - - - if (num >= 1 && first == 0) - *x = *(valuators + 0); - else - *x = dev->last.valuators[0]; - - if (first <= 1 && num >= (2 - first)) - *y = *(valuators + 1 - first); - else - *y = dev->last.valuators[1]; - - clipAxis(dev, 0, x); - clipAxis(dev, 1, y); - - i = (first > 2) ? 0 : 2; - for (; i < num; i++) - { - dev->last.valuators[i + first] = valuators[i]; - clipAxis(dev, i, &dev->last.valuators[i + first]); - } -} - -/** - * Move the device's pointer by the values given in @valuators. - * - * @param dev The device which's pointer is to be moved. - * @param x Returns the x position of the pointer after the move. - * @param y Returns the y position of the pointer after the move. - * @param first The first valuator in @valuators - * @param num Total number of valuators in @valuators. - * @param valuators Valuator data for each axis between @first and - * @first+@num. - */ -static void -moveRelative(DeviceIntPtr dev, int *x, int *y, - int first, int num, int *valuators) -{ - int i; - - *x = dev->last.valuators[0]; - *y = dev->last.valuators[1]; - - if (num >= 1 && first == 0) - *x += *(valuators +0); - - if (first <= 1 && num >= (2 - first)) - *y += *(valuators + 1 - first); - - /* if attached, clip both x and y to the defined limits (usually - * co-ord space limit). If it is attached, we need x/y to go over the - * limits to be able to change screens. */ - if(dev->u.master && dev->valuator->mode == Absolute) { - clipAxis(dev, 0, x); - clipAxis(dev, 1, y); - } - - /* calc other axes, clip, drop back into valuators */ - i = (first > 2) ? 0 : 2; - for (; i < num; i++) - { - dev->last.valuators[i + first] += valuators[i]; - if (dev->valuator->mode == Absolute) - clipAxis(dev, i, &dev->last.valuators[i + first]); - valuators[i] = dev->last.valuators[i + first]; - } -} - -/** - * Accelerate the data in valuators based on the device's acceleration scheme. - * - * @param dev The device which's pointer is to be moved. - * @param first The first valuator in @valuators - * @param num Total number of valuators in @valuators. - * @param valuators Valuator data for each axis between @first and - * @first+@num. - * @param ms Current time. - */ -static void -accelPointer(DeviceIntPtr dev, int first, int num, int *valuators, CARD32 ms) -{ - if (dev->valuator->accelScheme.AccelSchemeProc) - dev->valuator->accelScheme.AccelSchemeProc(dev, first, num, valuators, ms); -} - -/** - * If we have HW cursors, this actually moves the visible sprite. If not, we - * just do all the screen crossing, etc. - * - * We scale from device to screen coordinates here, call - * miPointerSetPosition() and then scale back into device coordinates (if - * needed). miPSP will change x/y if the screen was crossed. - * - * @param dev The device to be moved. - * @param x Pointer to current x-axis value, may be modified. - * @param y Pointer to current y-axis value, may be modified. - * @param x_frac Fractional part of current x-axis value, may be modified. - * @param y_frac Fractional part of current y-axis value, may be modified. - * @param scr Screen the device's sprite is currently on. - * @param screenx Screen x coordinate the sprite is on after the update. - * @param screeny Screen y coordinate the sprite is on after the update. - * @param screenx_frac Fractional part of screen x coordinate, as above. - * @param screeny_frac Fractional part of screen y coordinate, as above. - */ -static void -positionSprite(DeviceIntPtr dev, int *x, int *y, float x_frac, float y_frac, - ScreenPtr scr, int *screenx, int *screeny, float *screenx_frac, float *screeny_frac) -{ - int old_screenx, old_screeny; - - /* scale x&y to screen */ - if (dev->valuator->numAxes > 0) { - *screenx = rescaleValuatorAxis(*x, x_frac, screenx_frac, - dev->valuator->axes + 0, NULL, scr->width); - } else { - *screenx = dev->last.valuators[0]; - *screenx_frac = dev->last.remainder[0]; - } - - if (dev->valuator->numAxes > 1) { - *screeny = rescaleValuatorAxis(*y, y_frac, screeny_frac, - dev->valuator->axes + 1, NULL, scr->height); - } else { - *screeny = dev->last.valuators[1]; - *screeny_frac = dev->last.remainder[1]; - } - - /* Hit the left screen edge? */ - if (*screenx <= 0 && *screenx_frac < 0.0f) - { - *screenx_frac = 0.0f; - x_frac = 0.0f; - } - if (*screeny <= 0 && *screeny_frac < 0.0f) - { - *screeny_frac = 0.0f; - y_frac = 0.0f; - } - - - old_screenx = *screenx; - old_screeny = *screeny; - /* This takes care of crossing screens for us, as well as clipping - * to the current screen. */ - miPointerSetPosition(dev, screenx, screeny); - - if (dev->u.master) { - dev->u.master->last.valuators[0] = *screenx; - dev->u.master->last.valuators[1] = *screeny; - dev->u.master->last.remainder[0] = *screenx_frac; - dev->u.master->last.remainder[1] = *screeny_frac; - } - - /* Crossed screen? Scale back to device coordiantes */ - if(*screenx != old_screenx) - { - scr = miPointerGetScreen(dev); - *x = rescaleValuatorAxis(*screenx, *screenx_frac, &x_frac, NULL, - dev->valuator->axes + 0, scr->width); - } - if(*screeny != old_screeny) - { - scr = miPointerGetScreen(dev); - *y = rescaleValuatorAxis(*screeny, *screeny_frac, &y_frac, NULL, - dev->valuator->axes + 1, scr->height); - } - - /* dropy x/y (device coordinates) back into valuators for next event */ - dev->last.valuators[0] = *x; - dev->last.valuators[1] = *y; - dev->last.remainder[0] = x_frac; - dev->last.remainder[1] = y_frac; -} - -/** - * Update the motion history for the device and (if appropriate) for its - * master device. - * @param dev Slave device to update. - * @param first First valuator to append to history. - * @param num Total number of valuators to append to history. - * @param ms Current time - */ -static void -updateHistory(DeviceIntPtr dev, int first, int num, CARD32 ms) -{ - updateMotionHistory(dev, ms, first, num, &dev->last.valuators[first]); - if (dev->u.master) - { - DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); - updateMotionHistory(master, ms, first, num, &dev->last.valuators[first]); - } -} - -/** - * Convenience wrapper around GetKeyboardValuatorEvents, that takes no - * valuators. - */ -int -GetKeyboardEvents(EventList *events, DeviceIntPtr pDev, int type, int key_code) { - return GetKeyboardValuatorEvents(events, pDev, type, key_code, 0, 0, NULL); -} - - -/** - * Returns a set of keyboard events for KeyPress/KeyRelease, optionally - * also with valuator events. Handles Xi and XKB. - * - * DOES NOT GENERATE CORE EVENTS! Core events are created when processing the - * event (ProcessOtherEvent). - * - * events is not NULL-terminated; the return value is the number of events. - * The DDX is responsible for allocating the event structure in the first - * place via GetMaximumEventsNum(), and for freeing it. - * - * This function does not change the core keymap to that of the device; - * that is done by SwitchCoreKeyboard, which is called from - * mieqProcessInputEvents. If replacing that function, take care to call - * SetCoreKeyboard before processInputProc, so keymaps are altered to suit. - */ -int -GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type, - int key_code, int first_valuator, - int num_valuators, int *valuators) { - int num_events = 0; - CARD32 ms = 0; - DeviceEvent *event; - RawDeviceEvent *raw; - - /* refuse events from disabled devices */ - if (!pDev->enabled) - return 0; - - if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed || - (type != KeyPress && type != KeyRelease) || - (key_code < 8 || key_code > 255)) - return 0; - - num_events = 1; - - events = updateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events); - - /* Handle core repeating, via press/release/press/release. */ - if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) { - /* If autorepeating is disabled either globally or just for that key, - * or we have a modifier, don't generate a repeat event. */ - if (!pDev->kbdfeed->ctrl.autoRepeat || - !key_autorepeats(pDev, key_code) || - pDev->key->xkbInfo->desc->map->modmap[key_code]) - return 0; - } - - ms = GetTimeInMillis(); - - raw = (RawDeviceEvent*)events->event; - events++; - num_events++; - - init_raw(pDev, raw, ms, type, key_code); - set_raw_valuators(raw, first_valuator, num_valuators, valuators, - raw->valuators.data_raw); - - if (num_valuators) - clipValuators(pDev, first_valuator, num_valuators, valuators); - - set_raw_valuators(raw, first_valuator, num_valuators, valuators, - raw->valuators.data); - - event = (DeviceEvent*) events->event; - init_event(pDev, event, ms); - event->detail.key = key_code; - - if (type == KeyPress) { - event->type = ET_KeyPress; - set_key_down(pDev, key_code, KEY_POSTED); - } - else if (type == KeyRelease) { - event->type = ET_KeyRelease; - set_key_up(pDev, key_code, KEY_POSTED); - } - - if (num_valuators) - clipValuators(pDev, first_valuator, num_valuators, valuators); - - set_valuators(pDev, event, first_valuator, num_valuators, valuators); - - return num_events; -} - -/** - * Initialize an event list and fill with 32 byte sized events. - * This event list is to be passed into GetPointerEvents() and - * GetKeyboardEvents(). - * - * @param num_events Number of elements in list. - */ -EventListPtr -InitEventList(int num_events) -{ - EventListPtr events; - int i; - - events = (EventListPtr)xcalloc(num_events, sizeof(EventList)); - if (!events) - return NULL; - - for (i = 0; i < num_events; i++) - { - events[i].evlen = sizeof(InternalEvent); - events[i].event = xcalloc(1, sizeof(InternalEvent)); - if (!events[i].event) - { - /* rollback */ - while(i--) - xfree(events[i].event); - xfree(events); - events = NULL; - break; - } - } - - return events; -} - -/** - * Free an event list. - * - * @param list The list to be freed. - * @param num_events Number of elements in list. - */ -void -FreeEventList(EventListPtr list, int num_events) -{ - if (!list) - return; - while(num_events--) - xfree(list[num_events].event); - xfree(list); -} - -/** - * Generate a series of xEvents (filled into the EventList) representing - * pointer motion, or button presses. Xi and XKB-aware. - * - * DOES NOT GENERATE CORE EVENTS! Core events are created when processing the - * event (ProcessOtherEvent). - * - * events is not NULL-terminated; the return value is the number of events. - * The DDX is responsible for allocating the event structure in the first - * place via InitEventList() and GetMaximumEventsNum(), and for freeing it. - * - * In the generated events rootX/Y will be in absolute screen coords and - * the valuator information in the absolute or relative device coords. - * - * last.valuators[x] of the device is always in absolute device coords. - * last.valuators[x] of the master device is in absolute screen coords. - * - * master->last.valuators[x] for x > 2 is undefined. - */ -int -GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons, - int flags, int first_valuator, int num_valuators, - int *valuators) { - int num_events = 1; - CARD32 ms; - DeviceEvent *event; - RawDeviceEvent *raw; - int x = 0, y = 0, /* device coords */ - cx, cy; /* only screen coordinates */ - float x_frac = 0.0, y_frac = 0.0, cx_frac, cy_frac; - ScreenPtr scr = miPointerGetScreen(pDev); - - /* refuse events from disabled devices */ - if (!pDev->enabled) - return 0; - - ms = GetTimeInMillis(); /* before pointer update to help precision */ - - if (!scr || !pDev->valuator || first_valuator < 0 || - ((num_valuators + first_valuator) > pDev->valuator->numAxes) || - (type != MotionNotify && type != ButtonPress && type != ButtonRelease) || - (type != MotionNotify && !pDev->button) || - ((type == ButtonPress || type == ButtonRelease) && !buttons) || - (type == MotionNotify && num_valuators <= 0)) - return 0; - - events = updateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); - - raw = (RawDeviceEvent*)events->event; - events++; - num_events++; - - init_raw(pDev, raw, ms, type, buttons); - set_raw_valuators(raw, first_valuator, num_valuators, valuators, - raw->valuators.data_raw); - - if (flags & POINTER_ABSOLUTE) - { - if (flags & POINTER_SCREEN) /* valuators are in screen coords */ - { - - if (num_valuators >= 1 && first_valuator == 0) - valuators[0] = rescaleValuatorAxis(valuators[0], 0.0, &x_frac, NULL, - pDev->valuator->axes + 0, - scr->width); - if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) - valuators[1 - first_valuator] = rescaleValuatorAxis(valuators[1 - first_valuator], 0.0, &y_frac, NULL, - pDev->valuator->axes + 1, - scr->height); - } - - moveAbsolute(pDev, &x, &y, first_valuator, num_valuators, valuators); - } else { - if (flags & POINTER_ACCELERATE) { - accelPointer(pDev, first_valuator, num_valuators, valuators, ms); - /* The pointer acceleration code modifies the fractional part - * in-place, so we need to extract this information first */ - x_frac = pDev->last.remainder[0]; - y_frac = pDev->last.remainder[1]; - } - moveRelative(pDev, &x, &y, first_valuator, num_valuators, valuators); - } - - set_raw_valuators(raw, first_valuator, num_valuators, valuators, - raw->valuators.data); - - positionSprite(pDev, &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac); - updateHistory(pDev, first_valuator, num_valuators, ms); - - /* Update the valuators with the true value sent to the client*/ - if (num_valuators >= 1 && first_valuator == 0) - valuators[0] = x; - if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) - valuators[1 - first_valuator] = y; - - if (num_valuators) - clipValuators(pDev, first_valuator, num_valuators, valuators); - - event = (DeviceEvent*) events->event; - init_event(pDev, event, ms); - - if (type == MotionNotify) { - event->type = ET_Motion; - event->detail.button = 0; - } - else { - if (type == ButtonPress) { - event->type = ET_ButtonPress; - pDev->button->postdown[buttons >> 3] |= (1 << (buttons & 7)); - } - else if (type == ButtonRelease) { - event->type = ET_ButtonRelease; - pDev->button->postdown[buttons >> 3] &= ~(1 << (buttons & 7)); - } - event->detail.button = buttons; - } - - event->root_x = cx; /* root_x/y always in screen coords */ - event->root_y = cy; - event->root_x_frac = cx_frac; - event->root_y_frac = cy_frac; - - set_valuators(pDev, event, first_valuator, num_valuators, valuators); - - return num_events; -} - - -/** - * Post ProximityIn/ProximityOut events, accompanied by valuators. - * - * events is not NULL-terminated; the return value is the number of events. - * The DDX is responsible for allocating the event structure in the first - * place via GetMaximumEventsNum(), and for freeing it. - */ -int -GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type, - int first_valuator, int num_valuators, int *valuators) -{ - int num_events = 1; - DeviceEvent *event; - - /* refuse events from disabled devices */ - if (!pDev->enabled) - return 0; - - /* Sanity checks. */ - if (type != ProximityIn && type != ProximityOut) - return 0; - if (!pDev->valuator) - return 0; - /* Do we need to send a DeviceValuator event? */ - if ((pDev->valuator->mode & 1) == Relative) - num_valuators = 0; - - /* You fail. */ - if (first_valuator < 0 || - (num_valuators + first_valuator) > pDev->valuator->numAxes) - return 0; - - events = updateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); - - event = (DeviceEvent *) events->event; - init_event(pDev, event, GetTimeInMillis()); - event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut; - - if (num_valuators) - clipValuators(pDev, first_valuator, num_valuators, valuators); - - set_valuators(pDev, event, first_valuator, num_valuators, valuators); - - return num_events; -} - -/** - * Synthesize a single motion event for the core pointer. - * - * Used in cursor functions, e.g. when cursor confinement changes, and we need - * to shift the pointer to get it inside the new bounds. - */ -void -PostSyntheticMotion(DeviceIntPtr pDev, - int x, - int y, - int screen, - unsigned long time) -{ - DeviceEvent ev; - -#ifdef PANORAMIX - /* Translate back to the sprite screen since processInputProc - will translate from sprite screen to screen 0 upon reentry - to the DIX layer. */ - if (!noPanoramiXExtension) { - x += panoramiXdataPtr[0].x - panoramiXdataPtr[screen].x; - y += panoramiXdataPtr[0].y - panoramiXdataPtr[screen].y; - } -#endif - - memset(&ev, 0, sizeof(DeviceEvent)); - init_event(pDev, &ev, time); - ev.root_x = x; - ev.root_y = y; - ev.type = ET_Motion; - ev.time = time; - - /* FIXME: MD/SD considerations? */ - (*pDev->public.processInputProc)((InternalEvent*)&ev, pDev); -} +/* + * Copyright © 2006 Nokia Corporation + * Copyright © 2006-2007 Daniel Stone + * Copyright © 2008 Red Hat, Inc. + * + * 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. + * + * Authors: Daniel Stone + * Peter Hutterer + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "misc.h" +#include "resource.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "globals.h" +#include "dixevents.h" +#include "mipointer.h" +#include "eventstr.h" +#include "eventconvert.h" + +#include +#include "xkbsrv.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +#include +#include +#include "exglobals.h" +#include "exevents.h" +#include "exglobals.h" +#include "extnsionst.h" +#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */ + +/* Number of motion history events to store. */ +#define MOTION_HISTORY_SIZE 256 + +/* InputEventList is the container list for all input events generated by the + * DDX. The DDX is expected to call GetEventList() and then pass the list into + * Get{Pointer|Keyboard}Events. + */ +EventListPtr InputEventList = NULL; +int InputEventListLen = 0; + +int +GetEventList(EventListPtr* list) +{ + *list = InputEventList; + return InputEventListLen; +} + +/** + * Pick some arbitrary size for Xi motion history. + */ +int +GetMotionHistorySize(void) +{ + return MOTION_HISTORY_SIZE; +} + +void +set_key_down(DeviceIntPtr pDev, int key_code, int type) +{ + if (type == KEY_PROCESSED) + pDev->key->down[key_code >> 3] |= (1 << (key_code & 7)); + else + pDev->key->postdown[key_code >> 3] |= (1 << (key_code & 7)); +} + +void +set_key_up(DeviceIntPtr pDev, int key_code, int type) +{ + if (type == KEY_PROCESSED) + pDev->key->down[key_code >> 3] &= ~(1 << (key_code & 7)); + else + pDev->key->postdown[key_code >> 3] &= ~(1 << (key_code & 7)); +} + +Bool +key_is_down(DeviceIntPtr pDev, int key_code, int type) +{ + int ret = 0; + + if (type & KEY_PROCESSED) + ret |= !!(pDev->key->down[key_code >> 3] & (1 << (key_code & 7))); + else if (type & KEY_POSTED) + ret |= !!(pDev->key->postdown[key_code >> 3] & (1 << (key_code & 7))); + + return ret; +} + +static Bool +key_autorepeats(DeviceIntPtr pDev, int key_code) +{ + return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] & + (1 << (key_code & 7))); +} + +static void +init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms) +{ + memset(event, 0, sizeof(DeviceEvent)); + event->header = ET_Internal; + event->length = sizeof(DeviceEvent); + event->time = ms; + event->deviceid = dev->id; + event->sourceid = dev->id; +} + +static void +init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail) +{ + memset(event, 0, sizeof(RawDeviceEvent)); + event->header = ET_Internal; + event->length = sizeof(RawDeviceEvent); + event->type = ET_RawKeyPress - ET_KeyPress + type; + event->time = ms; + event->deviceid = dev->id; + event->sourceid = dev->id; + event->detail.button = detail; +} + +static void +set_raw_valuators(RawDeviceEvent *event, int first, int num, int *valuators, int32_t* data) +{ + int i; + for (i = first; i < first + num; i++) + SetBit(event->valuators.mask, i); + + memcpy(&data[first], valuators, num * sizeof(uint32_t)); +} + + +static void +set_valuators(DeviceIntPtr dev, DeviceEvent* event, int first_valuator, + int num_valuators, int *valuators) +{ + int i; + + for (i = first_valuator; i < first_valuator + num_valuators; i++) + { + SetBit(event->valuators.mask, i); + if (dev->valuator->mode == Absolute) + SetBit(event->valuators.mode, i); + event->valuators.data_frac[i] = + dev->last.remainder[i] * (1 << 16) * (1 << 16); + } + + memcpy(&event->valuators.data[first_valuator], + valuators, num_valuators * sizeof(uint32_t)); + +} + +void +CreateClassesChangedEvent(EventList* event, + DeviceIntPtr master, + DeviceIntPtr slave, + int type) +{ + int i; + DeviceChangedEvent *dce; + CARD32 ms = GetTimeInMillis(); + + dce = (DeviceChangedEvent*)event->event; + memset(dce, 0, sizeof(DeviceChangedEvent)); + dce->deviceid = slave->id; + dce->masterid = master->id; + dce->header = ET_Internal; + dce->length = sizeof(DeviceChangedEvent); + dce->type = ET_DeviceChanged; + dce->time = ms; + dce->flags = type; + dce->flags |= DEVCHANGE_SLAVE_SWITCH; + dce->sourceid = slave->id; + + if (slave->button) + { + dce->buttons.num_buttons = slave->button->numButtons; + for (i = 0; i < dce->buttons.num_buttons; i++) + dce->buttons.names[i] = slave->button->labels[i]; + } + if (slave->valuator) + { + dce->num_valuators = slave->valuator->numAxes; + for (i = 0; i < dce->num_valuators; i++) + { + dce->valuators[i].min = slave->valuator->axes[i].min_value; + dce->valuators[i].max = slave->valuator->axes[i].max_value; + dce->valuators[i].resolution = slave->valuator->axes[i].resolution; + /* This should, eventually, be a per-axis mode */ + dce->valuators[i].mode = slave->valuator->mode; + dce->valuators[i].name = slave->valuator->axes[i].label; + } + } + if (slave->key) + { + dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code; + dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code; + } +} + +/** + * Rescale the coord between the two axis ranges. + */ +static int +rescaleValuatorAxis(int coord, float remainder, float *remainder_return, AxisInfoPtr from, AxisInfoPtr to, + int defmax) +{ + int fmin = 0, tmin = 0, fmax = defmax, tmax = defmax, coord_return; + float value; + + if(from && from->min_value < from->max_value) { + fmin = from->min_value; + fmax = from->max_value; + } + if(to && to->min_value < to->max_value) { + tmin = to->min_value; + tmax = to->max_value; + } + + if(fmin == tmin && fmax == tmax) { + if (remainder_return) + *remainder_return = remainder; + return coord; + } + + if(fmax == fmin) { /* avoid division by 0 */ + if (remainder_return) + *remainder_return = 0.0; + return 0; + } + + value = (coord + remainder - fmin) * (tmax - tmin) / (fmax - fmin) + tmin; + coord_return = lroundf(value); + if (remainder_return) + *remainder_return = value - coord_return; + return coord_return; +} + +/** + * Update all coordinates when changing to a different SD + * to ensure that relative reporting will work as expected + * without loss of precision. + * + * pDev->last.valuators will be in absolute device coordinates after this + * function. + */ +static void +updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev) +{ + ScreenPtr scr = miPointerGetScreen(pDev); + int i; + DeviceIntPtr lastSlave; + + /* master->last.valuators[0]/[1] is in screen coords and the actual + * position of the pointer */ + pDev->last.valuators[0] = master->last.valuators[0]; + pDev->last.valuators[1] = master->last.valuators[1]; + + if (!pDev->valuator) + return; + + /* scale back to device coordinates */ + if(pDev->valuator->numAxes > 0) + pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], pDev->last.remainder[0], + &pDev->last.remainder[0], NULL, pDev->valuator->axes + 0, scr->width); + if(pDev->valuator->numAxes > 1) + pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], pDev->last.remainder[1], + &pDev->last.remainder[1], NULL, pDev->valuator->axes + 1, scr->height); + + /* calculate the other axis as well based on info from the old + * slave-device. If the old slave had less axes than this one, + * last.valuators is reset to 0. + */ + if ((lastSlave = master->last.slave) && lastSlave->valuator) { + for (i = 2; i < pDev->valuator->numAxes; i++) { + if (i >= lastSlave->valuator->numAxes) + pDev->last.valuators[i] = 0; + else + pDev->last.valuators[i] = + rescaleValuatorAxis(pDev->last.valuators[i], + pDev->last.remainder[i], + &pDev->last.remainder[i], + lastSlave->valuator->axes + i, + pDev->valuator->axes + i, 0); + } + } + +} + +/** + * Allocate the motion history buffer. + */ +void +AllocateMotionHistory(DeviceIntPtr pDev) +{ + int size; + if (pDev->valuator->motion) + free(pDev->valuator->motion); + + if (pDev->valuator->numMotionEvents < 1) + return; + + /* An MD must have a motion history size large enough to keep all + * potential valuators, plus the respective range of the valuators. + * 3 * INT32 for (min_val, max_val, curr_val)) + */ + if (IsMaster(pDev)) + size = sizeof(INT32) * 3 * MAX_VALUATORS; + else + size = sizeof(INT32) * pDev->valuator->numAxes; + + size += sizeof(Time); + + pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size); + pDev->valuator->first_motion = 0; + pDev->valuator->last_motion = 0; + if (!pDev->valuator->motion) + ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n", + pDev->name, size * pDev->valuator->numMotionEvents); +} + +/** + * Dump the motion history between start and stop into the supplied buffer. + * Only records the event for a given screen in theory, but in practice, we + * sort of ignore this. + * + * If core is set, we only generate x/y, in INT16, scaled to screen coords. + */ +int +GetMotionHistory(DeviceIntPtr pDev, xTimecoord **buff, unsigned long start, + unsigned long stop, ScreenPtr pScreen, BOOL core) +{ + char *ibuff = NULL, *obuff; + int i = 0, ret = 0; + int j, coord; + Time current; + /* The size of a single motion event. */ + int size; + int dflt; + AxisInfo from, *to; /* for scaling */ + INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */ + INT16 *corebuf; + AxisInfo core_axis = {0}; + + if (!pDev->valuator || !pDev->valuator->numMotionEvents) + return 0; + + if (core && !pScreen) + return 0; + + if (IsMaster(pDev)) + size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time); + else + size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); + + *buff = malloc(size * pDev->valuator->numMotionEvents); + if (!(*buff)) + return 0; + obuff = (char *)*buff; + + for (i = pDev->valuator->first_motion; + i != pDev->valuator->last_motion; + i = (i + 1) % pDev->valuator->numMotionEvents) { + /* We index the input buffer by which element we're accessing, which + * is not monotonic, and the output buffer by how many events we've + * written so far. */ + ibuff = (char *) pDev->valuator->motion + (i * size); + memcpy(¤t, ibuff, sizeof(Time)); + + if (current > stop) { + return ret; + } + else if (current >= start) { + if (core) + { + memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ + + icbuf = (INT32*)(ibuff + sizeof(Time)); + corebuf = (INT16*)(obuff + sizeof(Time)); + + /* fetch x coordinate + range */ + memcpy(&from.min_value, icbuf++, sizeof(INT32)); + memcpy(&from.max_value, icbuf++, sizeof(INT32)); + memcpy(&coord, icbuf++, sizeof(INT32)); + + /* scale to screen coords */ + to = &core_axis; + to->max_value = pScreen->width; + coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->width); + + memcpy(corebuf, &coord, sizeof(INT16)); + corebuf++; + + /* fetch y coordinate + range */ + memcpy(&from.min_value, icbuf++, sizeof(INT32)); + memcpy(&from.max_value, icbuf++, sizeof(INT32)); + memcpy(&coord, icbuf++, sizeof(INT32)); + + to->max_value = pScreen->height; + coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->height); + memcpy(corebuf, &coord, sizeof(INT16)); + + } else if (IsMaster(pDev)) + { + memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ + + ocbuf = (INT32*)(obuff + sizeof(Time)); + icbuf = (INT32*)(ibuff + sizeof(Time)); + for (j = 0; j < MAX_VALUATORS; j++) + { + if (j >= pDev->valuator->numAxes) + break; + + /* fetch min/max/coordinate */ + memcpy(&from.min_value, icbuf++, sizeof(INT32)); + memcpy(&from.max_value, icbuf++, sizeof(INT32)); + memcpy(&coord, icbuf++, sizeof(INT32)); + + to = (j < pDev->valuator->numAxes) ? &pDev->valuator->axes[j] : NULL; + + /* x/y scaled to screen if no range is present */ + if (j == 0 && (from.max_value < from.min_value)) + from.max_value = pScreen->width; + else if (j == 1 && (from.max_value < from.min_value)) + from.max_value = pScreen->height; + + if (j == 0 && (to->max_value < to->min_value)) + dflt = pScreen->width; + else if (j == 1 && (to->max_value < to->min_value)) + dflt = pScreen->height; + else + dflt = 0; + + /* scale from stored range into current range */ + coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, 0); + memcpy(ocbuf, &coord, sizeof(INT32)); + ocbuf++; + } + } else + memcpy(obuff, ibuff, size); + + /* don't advance by size here. size may be different to the + * actually written size if the MD has less valuators than MAX */ + if (core) + obuff += sizeof(INT32) + sizeof(Time); + else + obuff += (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); + ret++; + } + } + + return ret; +} + + +/** + * Update the motion history for a specific device, with the list of + * valuators. + * + * Layout of the history buffer: + * for SDs: [time] [val0] [val1] ... [valn] + * for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn] + * + * For events that have some valuators unset (first_valuator > 0): + * min_val == max_val == val == 0. + */ +static void +updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, int first_valuator, + int num_valuators, int *valuators) +{ + char *buff = (char *) pDev->valuator->motion; + ValuatorClassPtr v; + int i; + + if (!pDev->valuator->numMotionEvents) + return; + + v = pDev->valuator; + if (IsMaster(pDev)) + { + buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) * + v->last_motion; + + memcpy(buff, &ms, sizeof(Time)); + buff += sizeof(Time); + + memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS); + buff += 3 * sizeof(INT32) * first_valuator; + + for (i = first_valuator; i < first_valuator + num_valuators; i++) + { + if (i >= v->numAxes) + break; + memcpy(buff, &v->axes[i].min_value, sizeof(INT32)); + buff += sizeof(INT32); + memcpy(buff, &v->axes[i].max_value, sizeof(INT32)); + buff += sizeof(INT32); + memcpy(buff, &valuators[i - first_valuator], sizeof(INT32)); + buff += sizeof(INT32); + } + } else + { + + buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) * + pDev->valuator->last_motion; + + memcpy(buff, &ms, sizeof(Time)); + buff += sizeof(Time); + + memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes); + buff += sizeof(INT32) * first_valuator; + + memcpy(buff, valuators, sizeof(INT32) * num_valuators); + } + + pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) % + pDev->valuator->numMotionEvents; + /* If we're wrapping around, just keep the circular buffer going. */ + if (pDev->valuator->first_motion == pDev->valuator->last_motion) + pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) % + pDev->valuator->numMotionEvents; + + return; +} + + +/** + * Returns the maximum number of events GetKeyboardEvents, + * GetKeyboardValuatorEvents, and GetPointerEvents will ever return. + * + * This MUST be absolutely constant, from init until exit. + */ +int +GetMaximumEventsNum(void) { + /* One raw event + * One device event + * One possible device changed event + */ + return 3; +} + + +/** + * Clip an axis to its bounds, which are declared in the call to + * InitValuatorAxisClassStruct. + */ +static void +clipAxis(DeviceIntPtr pDev, int axisNum, int *val) +{ + AxisInfoPtr axis; + + if (axisNum >= pDev->valuator->numAxes) + return; + + axis = pDev->valuator->axes + axisNum; + + /* If a value range is defined, clip. If not, do nothing */ + if (axis->max_value <= axis->min_value) + return; + + if (*val < axis->min_value) + *val = axis->min_value; + if (*val > axis->max_value) + *val = axis->max_value; +} + +/** + * Clip every axis in the list of valuators to its bounds. + */ +static void +clipValuators(DeviceIntPtr pDev, int first_valuator, int num_valuators, + int *valuators) +{ + int i; + + for (i = 0; i < num_valuators; i++) + clipAxis(pDev, i + first_valuator, &(valuators[i])); +} + +/** + * Create the DCCE event (does not update the master's device state yet, this + * is done in the event processing). + * Pull in the coordinates from the MD if necessary. + * + * @param events Pointer to a pre-allocated event list. + * @param dev The slave device that generated an event. + * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT + * @param num_events The current number of events, returns the number of + * events if a DCCE was generated. + * @return The updated @events pointer. + */ +static EventListPtr +updateFromMaster(EventListPtr events, DeviceIntPtr dev, int type, int *num_events) +{ + DeviceIntPtr master; + + master = GetMaster(dev, (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER : MASTER_KEYBOARD); + + if (master && master->last.slave != dev) + { + CreateClassesChangedEvent(events, master, dev, type); + if (IsPointerDevice(master)) + { + updateSlaveDeviceCoords(master, dev); + master->last.numValuators = dev->last.numValuators; + } + master->last.slave = dev; + (*num_events)++; + events++; + } + return events; +} + +/** + * Move the device's pointer to the position given in the valuators. + * + * @param dev The device which's pointer is to be moved. + * @param x Returns the x position of the pointer after the move. + * @param y Returns the y position of the pointer after the move. + * @param first The first valuator in @valuators + * @param num Total number of valuators in @valuators. + * @param valuators Valuator data for each axis between @first and + * @first+@num. + */ +static void +moveAbsolute(DeviceIntPtr dev, int *x, int *y, + int first, int num, int *valuators) +{ + int i; + + + if (num >= 1 && first == 0) + *x = *(valuators + 0); + else + *x = dev->last.valuators[0]; + + if (first <= 1 && num >= (2 - first)) + *y = *(valuators + 1 - first); + else + *y = dev->last.valuators[1]; + + clipAxis(dev, 0, x); + clipAxis(dev, 1, y); + + i = (first > 2) ? 0 : 2; + for (; i < num; i++) + { + dev->last.valuators[i + first] = valuators[i]; + clipAxis(dev, i, &dev->last.valuators[i + first]); + } +} + +/** + * Move the device's pointer by the values given in @valuators. + * + * @param dev The device which's pointer is to be moved. + * @param x Returns the x position of the pointer after the move. + * @param y Returns the y position of the pointer after the move. + * @param first The first valuator in @valuators + * @param num Total number of valuators in @valuators. + * @param valuators Valuator data for each axis between @first and + * @first+@num. + */ +static void +moveRelative(DeviceIntPtr dev, int *x, int *y, + int first, int num, int *valuators) +{ + int i; + + *x = dev->last.valuators[0]; + *y = dev->last.valuators[1]; + + if (num >= 1 && first == 0) + *x += *(valuators +0); + + if (first <= 1 && num >= (2 - first)) + *y += *(valuators + 1 - first); + + /* if attached, clip both x and y to the defined limits (usually + * co-ord space limit). If it is attached, we need x/y to go over the + * limits to be able to change screens. */ + if(dev->u.master && dev->valuator->mode == Absolute) { + clipAxis(dev, 0, x); + clipAxis(dev, 1, y); + } + + /* calc other axes, clip, drop back into valuators */ + i = (first > 2) ? 0 : 2; + for (; i < num; i++) + { + dev->last.valuators[i + first] += valuators[i]; + if (dev->valuator->mode == Absolute) + clipAxis(dev, i, &dev->last.valuators[i + first]); + valuators[i] = dev->last.valuators[i + first]; + } +} + +/** + * Accelerate the data in valuators based on the device's acceleration scheme. + * + * @param dev The device which's pointer is to be moved. + * @param first The first valuator in @valuators + * @param num Total number of valuators in @valuators. + * @param valuators Valuator data for each axis between @first and + * @first+@num. + * @param ms Current time. + */ +static void +accelPointer(DeviceIntPtr dev, int first, int num, int *valuators, CARD32 ms) +{ + if (dev->valuator->accelScheme.AccelSchemeProc) + dev->valuator->accelScheme.AccelSchemeProc(dev, first, num, valuators, ms); +} + +/** + * If we have HW cursors, this actually moves the visible sprite. If not, we + * just do all the screen crossing, etc. + * + * We scale from device to screen coordinates here, call + * miPointerSetPosition() and then scale back into device coordinates (if + * needed). miPSP will change x/y if the screen was crossed. + * + * @param dev The device to be moved. + * @param x Pointer to current x-axis value, may be modified. + * @param y Pointer to current y-axis value, may be modified. + * @param x_frac Fractional part of current x-axis value, may be modified. + * @param y_frac Fractional part of current y-axis value, may be modified. + * @param scr Screen the device's sprite is currently on. + * @param screenx Screen x coordinate the sprite is on after the update. + * @param screeny Screen y coordinate the sprite is on after the update. + * @param screenx_frac Fractional part of screen x coordinate, as above. + * @param screeny_frac Fractional part of screen y coordinate, as above. + */ +static void +positionSprite(DeviceIntPtr dev, int *x, int *y, float x_frac, float y_frac, + ScreenPtr scr, int *screenx, int *screeny, float *screenx_frac, float *screeny_frac) +{ + int old_screenx, old_screeny; + + /* scale x&y to screen */ + if (dev->valuator->numAxes > 0) { + *screenx = rescaleValuatorAxis(*x, x_frac, screenx_frac, + dev->valuator->axes + 0, NULL, scr->width); + } else { + *screenx = dev->last.valuators[0]; + *screenx_frac = dev->last.remainder[0]; + } + + if (dev->valuator->numAxes > 1) { + *screeny = rescaleValuatorAxis(*y, y_frac, screeny_frac, + dev->valuator->axes + 1, NULL, scr->height); + } else { + *screeny = dev->last.valuators[1]; + *screeny_frac = dev->last.remainder[1]; + } + + /* Hit the left screen edge? */ + if (*screenx <= 0 && *screenx_frac < 0.0f) + { + *screenx_frac = 0.0f; + x_frac = 0.0f; + } + if (*screeny <= 0 && *screeny_frac < 0.0f) + { + *screeny_frac = 0.0f; + y_frac = 0.0f; + } + + + old_screenx = *screenx; + old_screeny = *screeny; + /* This takes care of crossing screens for us, as well as clipping + * to the current screen. */ + miPointerSetPosition(dev, screenx, screeny); + + if (dev->u.master) { + dev->u.master->last.valuators[0] = *screenx; + dev->u.master->last.valuators[1] = *screeny; + dev->u.master->last.remainder[0] = *screenx_frac; + dev->u.master->last.remainder[1] = *screeny_frac; + } + + /* Crossed screen? Scale back to device coordiantes */ + if(*screenx != old_screenx) + { + scr = miPointerGetScreen(dev); + *x = rescaleValuatorAxis(*screenx, *screenx_frac, &x_frac, NULL, + dev->valuator->axes + 0, scr->width); + } + if(*screeny != old_screeny) + { + scr = miPointerGetScreen(dev); + *y = rescaleValuatorAxis(*screeny, *screeny_frac, &y_frac, NULL, + dev->valuator->axes + 1, scr->height); + } + + /* dropy x/y (device coordinates) back into valuators for next event */ + dev->last.valuators[0] = *x; + dev->last.valuators[1] = *y; + dev->last.remainder[0] = x_frac; + dev->last.remainder[1] = y_frac; +} + +/** + * Update the motion history for the device and (if appropriate) for its + * master device. + * @param dev Slave device to update. + * @param first First valuator to append to history. + * @param num Total number of valuators to append to history. + * @param ms Current time + */ +static void +updateHistory(DeviceIntPtr dev, int first, int num, CARD32 ms) +{ + updateMotionHistory(dev, ms, first, num, &dev->last.valuators[first]); + if (dev->u.master) + { + DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); + updateMotionHistory(master, ms, first, num, &dev->last.valuators[first]); + } +} + +/** + * Convenience wrapper around GetKeyboardValuatorEvents, that takes no + * valuators. + */ +int +GetKeyboardEvents(EventList *events, DeviceIntPtr pDev, int type, int key_code) { + return GetKeyboardValuatorEvents(events, pDev, type, key_code, 0, 0, NULL); +} + + +/** + * Returns a set of keyboard events for KeyPress/KeyRelease, optionally + * also with valuator events. Handles Xi and XKB. + * + * DOES NOT GENERATE CORE EVENTS! Core events are created when processing the + * event (ProcessOtherEvent). + * + * events is not NULL-terminated; the return value is the number of events. + * The DDX is responsible for allocating the event structure in the first + * place via GetMaximumEventsNum(), and for freeing it. + * + * This function does not change the core keymap to that of the device; + * that is done by SwitchCoreKeyboard, which is called from + * mieqProcessInputEvents. If replacing that function, take care to call + * SetCoreKeyboard before processInputProc, so keymaps are altered to suit. + */ +int +GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type, + int key_code, int first_valuator, + int num_valuators, int *valuators) { + int num_events = 0; + CARD32 ms = 0; + DeviceEvent *event; + RawDeviceEvent *raw; + + /* refuse events from disabled devices */ + if (!pDev->enabled) + return 0; + + if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed || + (type != KeyPress && type != KeyRelease) || + (key_code < 8 || key_code > 255)) + return 0; + + num_events = 1; + + events = updateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events); + + /* Handle core repeating, via press/release/press/release. */ + if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) { + /* If autorepeating is disabled either globally or just for that key, + * or we have a modifier, don't generate a repeat event. */ + if (!pDev->kbdfeed->ctrl.autoRepeat || + !key_autorepeats(pDev, key_code) || + pDev->key->xkbInfo->desc->map->modmap[key_code]) + return 0; + } + + ms = GetTimeInMillis(); + + raw = (RawDeviceEvent*)events->event; + events++; + num_events++; + + init_raw(pDev, raw, ms, type, key_code); + set_raw_valuators(raw, first_valuator, num_valuators, valuators, + raw->valuators.data_raw); + + if (num_valuators) + clipValuators(pDev, first_valuator, num_valuators, valuators); + + set_raw_valuators(raw, first_valuator, num_valuators, valuators, + raw->valuators.data); + + event = (DeviceEvent*) events->event; + init_event(pDev, event, ms); + event->detail.key = key_code; + + if (type == KeyPress) { + event->type = ET_KeyPress; + set_key_down(pDev, key_code, KEY_POSTED); + } + else if (type == KeyRelease) { + event->type = ET_KeyRelease; + set_key_up(pDev, key_code, KEY_POSTED); + } + + if (num_valuators) + clipValuators(pDev, first_valuator, num_valuators, valuators); + + set_valuators(pDev, event, first_valuator, num_valuators, valuators); + + return num_events; +} + +/** + * Initialize an event list and fill with 32 byte sized events. + * This event list is to be passed into GetPointerEvents() and + * GetKeyboardEvents(). + * + * @param num_events Number of elements in list. + */ +EventListPtr +InitEventList(int num_events) +{ + EventListPtr events; + int i; + + events = (EventListPtr)calloc(num_events, sizeof(EventList)); + if (!events) + return NULL; + + for (i = 0; i < num_events; i++) + { + events[i].evlen = sizeof(InternalEvent); + events[i].event = calloc(1, sizeof(InternalEvent)); + if (!events[i].event) + { + /* rollback */ + while(i--) + free(events[i].event); + free(events); + events = NULL; + break; + } + } + + return events; +} + +/** + * Free an event list. + * + * @param list The list to be freed. + * @param num_events Number of elements in list. + */ +void +FreeEventList(EventListPtr list, int num_events) +{ + if (!list) + return; + while(num_events--) + free(list[num_events].event); + free(list); +} + +/** + * Generate a series of xEvents (filled into the EventList) representing + * pointer motion, or button presses. Xi and XKB-aware. + * + * DOES NOT GENERATE CORE EVENTS! Core events are created when processing the + * event (ProcessOtherEvent). + * + * events is not NULL-terminated; the return value is the number of events. + * The DDX is responsible for allocating the event structure in the first + * place via InitEventList() and GetMaximumEventsNum(), and for freeing it. + * + * In the generated events rootX/Y will be in absolute screen coords and + * the valuator information in the absolute or relative device coords. + * + * last.valuators[x] of the device is always in absolute device coords. + * last.valuators[x] of the master device is in absolute screen coords. + * + * master->last.valuators[x] for x > 2 is undefined. + */ +int +GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons, + int flags, int first_valuator, int num_valuators, + int *valuators) { + int num_events = 1; + CARD32 ms; + DeviceEvent *event; + RawDeviceEvent *raw; + int x = 0, y = 0, /* device coords */ + cx, cy; /* only screen coordinates */ + float x_frac = 0.0, y_frac = 0.0, cx_frac, cy_frac; + ScreenPtr scr = miPointerGetScreen(pDev); + + /* refuse events from disabled devices */ + if (!pDev->enabled) + return 0; + + ms = GetTimeInMillis(); /* before pointer update to help precision */ + + if (!scr || !pDev->valuator || first_valuator < 0 || + ((num_valuators + first_valuator) > pDev->valuator->numAxes) || + (type != MotionNotify && type != ButtonPress && type != ButtonRelease) || + (type != MotionNotify && !pDev->button) || + ((type == ButtonPress || type == ButtonRelease) && !buttons) || + (type == MotionNotify && num_valuators <= 0)) + return 0; + + events = updateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); + + raw = (RawDeviceEvent*)events->event; + events++; + num_events++; + + init_raw(pDev, raw, ms, type, buttons); + set_raw_valuators(raw, first_valuator, num_valuators, valuators, + raw->valuators.data_raw); + + if (flags & POINTER_ABSOLUTE) + { + if (flags & POINTER_SCREEN) /* valuators are in screen coords */ + { + + if (num_valuators >= 1 && first_valuator == 0) + valuators[0] = rescaleValuatorAxis(valuators[0], 0.0, &x_frac, NULL, + pDev->valuator->axes + 0, + scr->width); + if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) + valuators[1 - first_valuator] = rescaleValuatorAxis(valuators[1 - first_valuator], 0.0, &y_frac, NULL, + pDev->valuator->axes + 1, + scr->height); + } + + moveAbsolute(pDev, &x, &y, first_valuator, num_valuators, valuators); + } else { + if (flags & POINTER_ACCELERATE) { + accelPointer(pDev, first_valuator, num_valuators, valuators, ms); + /* The pointer acceleration code modifies the fractional part + * in-place, so we need to extract this information first */ + x_frac = pDev->last.remainder[0]; + y_frac = pDev->last.remainder[1]; + } + moveRelative(pDev, &x, &y, first_valuator, num_valuators, valuators); + } + + set_raw_valuators(raw, first_valuator, num_valuators, valuators, + raw->valuators.data); + + positionSprite(pDev, &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac); + updateHistory(pDev, first_valuator, num_valuators, ms); + + /* Update the valuators with the true value sent to the client*/ + if (num_valuators >= 1 && first_valuator == 0) + valuators[0] = x; + if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) + valuators[1 - first_valuator] = y; + + if (num_valuators) + clipValuators(pDev, first_valuator, num_valuators, valuators); + + event = (DeviceEvent*) events->event; + init_event(pDev, event, ms); + + if (type == MotionNotify) { + event->type = ET_Motion; + event->detail.button = 0; + } + else { + if (type == ButtonPress) { + event->type = ET_ButtonPress; + pDev->button->postdown[buttons >> 3] |= (1 << (buttons & 7)); + } + else if (type == ButtonRelease) { + event->type = ET_ButtonRelease; + pDev->button->postdown[buttons >> 3] &= ~(1 << (buttons & 7)); + } + event->detail.button = buttons; + } + + event->root_x = cx; /* root_x/y always in screen coords */ + event->root_y = cy; + event->root_x_frac = cx_frac; + event->root_y_frac = cy_frac; + + set_valuators(pDev, event, first_valuator, num_valuators, valuators); + + return num_events; +} + + +/** + * Post ProximityIn/ProximityOut events, accompanied by valuators. + * + * events is not NULL-terminated; the return value is the number of events. + * The DDX is responsible for allocating the event structure in the first + * place via GetMaximumEventsNum(), and for freeing it. + */ +int +GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type, + int first_valuator, int num_valuators, int *valuators) +{ + int num_events = 1; + DeviceEvent *event; + + /* refuse events from disabled devices */ + if (!pDev->enabled) + return 0; + + /* Sanity checks. */ + if (type != ProximityIn && type != ProximityOut) + return 0; + if (!pDev->valuator) + return 0; + /* Do we need to send a DeviceValuator event? */ + if ((pDev->valuator->mode & 1) == Relative) + num_valuators = 0; + + /* You fail. */ + if (first_valuator < 0 || + (num_valuators + first_valuator) > pDev->valuator->numAxes) + return 0; + + events = updateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); + + event = (DeviceEvent *) events->event; + init_event(pDev, event, GetTimeInMillis()); + event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut; + + if (num_valuators) + clipValuators(pDev, first_valuator, num_valuators, valuators); + + set_valuators(pDev, event, first_valuator, num_valuators, valuators); + + return num_events; +} + +/** + * Synthesize a single motion event for the core pointer. + * + * Used in cursor functions, e.g. when cursor confinement changes, and we need + * to shift the pointer to get it inside the new bounds. + */ +void +PostSyntheticMotion(DeviceIntPtr pDev, + int x, + int y, + int screen, + unsigned long time) +{ + DeviceEvent ev; + +#ifdef PANORAMIX + /* Translate back to the sprite screen since processInputProc + will translate from sprite screen to screen 0 upon reentry + to the DIX layer. */ + if (!noPanoramiXExtension) { + x += panoramiXdataPtr[0].x - panoramiXdataPtr[screen].x; + y += panoramiXdataPtr[0].y - panoramiXdataPtr[screen].y; + } +#endif + + memset(&ev, 0, sizeof(DeviceEvent)); + init_event(pDev, &ev, time); + ev.root_x = x; + ev.root_y = y; + ev.type = ET_Motion; + ev.time = time; + + /* FIXME: MD/SD considerations? */ + (*pDev->public.processInputProc)((InternalEvent*)&ev, pDev); +} diff --git a/xorg-server/dix/glyphcurs.c b/xorg-server/dix/glyphcurs.c index f74b13730..946f447b2 100644 --- a/xorg-server/dix/glyphcurs.c +++ b/xorg-server/dix/glyphcurs.c @@ -1,192 +1,191 @@ -/************************************************************************ - -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, 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 = xcalloc(1, nby); - if (!pbits) - return BadAlloc; - - ppix = (PixmapPtr)(*pScreen->CreatePixmap)(pScreen, cm->width, - cm->height, 1, - CREATE_PIXMAP_USAGE_SCRATCH); - pGC = GetScratchGC(1, pScreen); - if (!ppix || !pGC) - { - if (ppix) - (*pScreen->DestroyPixmap)(ppix); - if (pGC) - FreeScratchGC(pGC); - xfree(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(FontPtr pfont, unsigned ch, 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; -} +/************************************************************************ + +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, 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 = calloc(1, nby); + if (!pbits) + return BadAlloc; + + ppix = (PixmapPtr)(*pScreen->CreatePixmap)(pScreen, cm->width, + cm->height, 1, + CREATE_PIXMAP_USAGE_SCRATCH); + 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; + ChangeGC(NullClient, pGC, GCFunction | GCForeground | GCFont, gcval); + ValidateGC((DrawablePtr)ppix, pGC); + (*pGC->ops->PolyFillRect)((DrawablePtr)ppix, pGC, 1, &rect); + + /* draw the glyph */ + gcval[0].val = 1; + ChangeGC(NullClient, pGC, GCForeground, 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(FontPtr pfont, unsigned ch, 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/xorg-server/dix/grabs.c b/xorg-server/dix/grabs.c index 4a351d647..1bc4998b2 100644 --- a/xorg-server/dix/grabs.c +++ b/xorg-server/dix/grabs.c @@ -1,560 +1,560 @@ -/* - -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 -#include "windowstr.h" -#include "inputstr.h" -#include "cursorstr.h" -#include "dixgrabs.h" -#include "xace.h" -#include "exevents.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, - DeviceIntPtr modDevice, - WindowPtr window, - GrabType grabtype, - GrabMask *mask, - GrabParameters *param, - int type, - KeyCode keybut, /* key or button */ - WindowPtr confineTo, - CursorPtr cursor) -{ - GrabPtr grab; - - grab = xcalloc(1, sizeof(GrabRec)); - if (!grab) - return (GrabPtr)NULL; - grab->resource = FakeClientID(client); - grab->device = device; - grab->window = window; - grab->eventMask = mask->core; /* same for XI */ - grab->deviceMask = 0; - grab->ownerEvents = param->ownerEvents; - grab->keyboardMode = param->this_device_mode; - grab->pointerMode = param->other_devices_mode; - grab->modifiersDetail.exact = param->modifiers; - grab->modifiersDetail.pMask = NULL; - grab->modifierDevice = modDevice; - grab->type = type; - grab->grabtype = grabtype; - grab->detail.exact = keybut; - grab->detail.pMask = NULL; - grab->confineTo = confineTo; - grab->cursor = cursor; - grab->next = NULL; - - if (grabtype == GRABTYPE_XI2) - memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask)); - if (cursor) - cursor->refcnt++; - return grab; - -} - -static void -FreeGrab(GrabPtr pGrab) -{ - if (pGrab->modifiersDetail.pMask != NULL) - xfree(pGrab->modifiersDetail.pMask); - - if (pGrab->detail.pMask != NULL) - xfree(pGrab->detail.pMask); - - if (pGrab->cursor) - FreeCursor(pGrab->cursor, (Cursor)0); - - xfree(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 int detail) -{ - Mask *mask; - int i; - - mask = xalloc(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 int 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 int firstExact, - unsigned int secondExact, - unsigned int exception) -{ - if ((firstExact == exception) || (secondExact == exception)) - return FALSE; - - if (firstExact == secondExact) - return TRUE; - - return FALSE; -} - -static Bool -DetailSupersedesSecond( - DetailRec firstDetail, - DetailRec secondDetail, - unsigned int 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) -{ - unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? - (unsigned int)XIAnyModifier : - (unsigned int)AnyModifier; - if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail, - pSecondGrab->modifiersDetail, - any_modifier)) - return FALSE; - - if (DetailSupersedesSecond(pFirstGrab->detail, - pSecondGrab->detail, (unsigned int)AnyKey)) - return TRUE; - - return FALSE; -} - -/** - * Compares two grabs and returns TRUE if the first grab matches the second - * grab. - * - * A match is when - * - the devices set for the grab are equal (this is optional). - * - the event types for both grabs are equal. - * - XXX - * - * @param ignoreDevice TRUE if the device settings on the grabs are to be - * ignored. - * @return TRUE if the grabs match or FALSE otherwise. - */ -Bool -GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice) -{ - unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? - (unsigned int)XIAnyModifier : - (unsigned int)AnyModifier; - - if (pFirstGrab->grabtype != pSecondGrab->grabtype) - return FALSE; - - if (pFirstGrab->grabtype == GRABTYPE_XI2) - { - if (pFirstGrab->device == inputInfo.all_devices || - pSecondGrab->device == inputInfo.all_devices) - { - /* do nothing */ - } else if (pFirstGrab->device == inputInfo.all_master_devices) - { - if (pSecondGrab->device != inputInfo.all_master_devices && - !IsMaster(pSecondGrab->device)) - return FALSE; - } else if (pSecondGrab->device == inputInfo.all_master_devices) - { - if (pFirstGrab->device != inputInfo.all_master_devices && - !IsMaster(pFirstGrab->device)) - return FALSE; - } else if (pSecondGrab->device != pFirstGrab->device) - return FALSE; - } else if (!ignoreDevice && - ((pFirstGrab->device != pSecondGrab->device) || - (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) - return FALSE; - - if (pFirstGrab->type != pSecondGrab->type) - return FALSE; - - if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || - GrabSupersedesSecond(pSecondGrab, pFirstGrab)) - return TRUE; - - if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail, - (unsigned int)AnyKey) - && - DetailSupersedesSecond(pFirstGrab->modifiersDetail, - pSecondGrab->modifiersDetail, - any_modifier)) - return TRUE; - - if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail, - (unsigned int)AnyKey) - && - DetailSupersedesSecond(pSecondGrab->modifiersDetail, - pFirstGrab->modifiersDetail, - any_modifier)) - return TRUE; - - return FALSE; -} - -static Bool -GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab) -{ - unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? - (unsigned int)XIAnyModifier : - (unsigned int)AnyModifier; - - if (pFirstGrab->grabtype != pSecondGrab->grabtype) - return FALSE; - - if (pFirstGrab->device != pSecondGrab->device || - (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || - (pFirstGrab->type != pSecondGrab->type)) - return FALSE; - - if (!(DetailSupersedesSecond(pFirstGrab->detail, - pSecondGrab->detail, - (unsigned int)AnyKey) && - DetailSupersedesSecond(pSecondGrab->detail, - pFirstGrab->detail, - (unsigned int)AnyKey))) - return FALSE; - - - if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail, - pSecondGrab->modifiersDetail, - any_modifier) && - DetailSupersedesSecond(pSecondGrab->modifiersDetail, - pFirstGrab->modifiersDetail, - any_modifier))) - return FALSE; - - return TRUE; -} - - -/** - * Prepend the new grab to the list of passive grabs on the window. - * Any previously existing grab that matches the new grab will be removed. - * Adding a new grab that would override another client's grab will result in - * a BadAccess. - * - * @return Success or X error code on failure. - */ -int -AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab) -{ - GrabPtr grab; - Mask access_mode = DixGrabAccess; - int rc; - - for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) - { - if (GrabMatchesSecond(pGrab, grab, FALSE)) - { - if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) - { - FreeGrab(pGrab); - return BadAccess; - } - } - } - - if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode); - if (rc != Success) - return rc; - - /* Remove all grabs that match the new one exactly */ - for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) - { - if (GrabsAreIdentical(pGrab, grab)) - { - DeletePassiveGrabFromList(grab); - break; - } - } - - 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; - unsigned int any_modifier; - unsigned int any_key; - -#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 = xalloc(i * sizeof(GrabPtr)); - adds = xalloc(i * sizeof(GrabPtr)); - updates = xalloc(i * sizeof(Mask **)); - details = xalloc(i * sizeof(Mask *)); - if (!deletes || !adds || !updates || !details) - { - if (details) xfree(details); - if (updates) xfree(updates); - if (adds) xfree(adds); - if (deletes) xfree(deletes); - return FALSE; - } - - any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? - (unsigned int)XIAnyModifier : (unsigned int)AnyModifier; - any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? - (unsigned int)XIAnyKeycode : (unsigned int)AnyKey; - 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, - (grab->grabtype == GRABTYPE_CORE))) - continue; - if (GrabSupersedesSecond(pMinuendGrab, grab)) - { - deletes[ndels++] = grab; - } - else if ((grab->detail.exact == any_key) - && (grab->modifiersDetail.exact != any_modifier)) - { - UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); - } - else if ((grab->modifiersDetail.exact == any_modifier) - && (grab->detail.exact != any_key)) - { - UPDATE(grab->modifiersDetail.pMask, - pMinuendGrab->modifiersDetail.exact); - } - else if ((pMinuendGrab->detail.exact != any_key) - && (pMinuendGrab->modifiersDetail.exact != any_modifier)) - { - GrabPtr pNewGrab; - GrabParameters param; - - UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); - - memset(¶m, 0, sizeof(param)); - param.ownerEvents = grab->ownerEvents; - param.this_device_mode = grab->keyboardMode; - param.other_devices_mode = grab->pointerMode; - param.modifiers = any_modifier; - - pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device, - grab->modifierDevice, grab->window, - grab->grabtype, - (GrabMask*)&grab->eventMask, - ¶m, (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 == any_key) - { - 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++) - xfree(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++) - { - xfree(*updates[i]); - *updates[i] = details[i]; - } - } - xfree(details); - xfree(updates); - xfree(adds); - xfree(deletes); - return ok; - -#undef UPDATE -} +/* + +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 +#include "windowstr.h" +#include "inputstr.h" +#include "cursorstr.h" +#include "dixgrabs.h" +#include "xace.h" +#include "exevents.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, + DeviceIntPtr modDevice, + WindowPtr window, + GrabType grabtype, + GrabMask *mask, + GrabParameters *param, + int type, + KeyCode keybut, /* key or button */ + WindowPtr confineTo, + CursorPtr cursor) +{ + GrabPtr grab; + + grab = calloc(1, sizeof(GrabRec)); + if (!grab) + return (GrabPtr)NULL; + grab->resource = FakeClientID(client); + grab->device = device; + grab->window = window; + grab->eventMask = mask->core; /* same for XI */ + grab->deviceMask = 0; + grab->ownerEvents = param->ownerEvents; + grab->keyboardMode = param->this_device_mode; + grab->pointerMode = param->other_devices_mode; + grab->modifiersDetail.exact = param->modifiers; + grab->modifiersDetail.pMask = NULL; + grab->modifierDevice = modDevice; + grab->type = type; + grab->grabtype = grabtype; + grab->detail.exact = keybut; + grab->detail.pMask = NULL; + grab->confineTo = confineTo; + grab->cursor = cursor; + grab->next = NULL; + + if (grabtype == GRABTYPE_XI2) + memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask)); + 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 int 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 int 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 int firstExact, + unsigned int secondExact, + unsigned int exception) +{ + if ((firstExact == exception) || (secondExact == exception)) + return FALSE; + + if (firstExact == secondExact) + return TRUE; + + return FALSE; +} + +static Bool +DetailSupersedesSecond( + DetailRec firstDetail, + DetailRec secondDetail, + unsigned int 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) +{ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; + if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + any_modifier)) + return FALSE; + + if (DetailSupersedesSecond(pFirstGrab->detail, + pSecondGrab->detail, (unsigned int)AnyKey)) + return TRUE; + + return FALSE; +} + +/** + * Compares two grabs and returns TRUE if the first grab matches the second + * grab. + * + * A match is when + * - the devices set for the grab are equal (this is optional). + * - the event types for both grabs are equal. + * - XXX + * + * @param ignoreDevice TRUE if the device settings on the grabs are to be + * ignored. + * @return TRUE if the grabs match or FALSE otherwise. + */ +Bool +GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice) +{ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; + + if (pFirstGrab->grabtype != pSecondGrab->grabtype) + return FALSE; + + if (pFirstGrab->grabtype == GRABTYPE_XI2) + { + if (pFirstGrab->device == inputInfo.all_devices || + pSecondGrab->device == inputInfo.all_devices) + { + /* do nothing */ + } else if (pFirstGrab->device == inputInfo.all_master_devices) + { + if (pSecondGrab->device != inputInfo.all_master_devices && + !IsMaster(pSecondGrab->device)) + return FALSE; + } else if (pSecondGrab->device == inputInfo.all_master_devices) + { + if (pFirstGrab->device != inputInfo.all_master_devices && + !IsMaster(pFirstGrab->device)) + return FALSE; + } else if (pSecondGrab->device != pFirstGrab->device) + return FALSE; + } else if (!ignoreDevice && + ((pFirstGrab->device != pSecondGrab->device) || + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) + return FALSE; + + if (pFirstGrab->type != pSecondGrab->type) + return FALSE; + + if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || + GrabSupersedesSecond(pSecondGrab, pFirstGrab)) + return TRUE; + + if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail, + (unsigned int)AnyKey) + && + DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + any_modifier)) + return TRUE; + + if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail, + (unsigned int)AnyKey) + && + DetailSupersedesSecond(pSecondGrab->modifiersDetail, + pFirstGrab->modifiersDetail, + any_modifier)) + return TRUE; + + return FALSE; +} + +static Bool +GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab) +{ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; + + if (pFirstGrab->grabtype != pSecondGrab->grabtype) + return FALSE; + + if (pFirstGrab->device != pSecondGrab->device || + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || + (pFirstGrab->type != pSecondGrab->type)) + return FALSE; + + if (!(DetailSupersedesSecond(pFirstGrab->detail, + pSecondGrab->detail, + (unsigned int)AnyKey) && + DetailSupersedesSecond(pSecondGrab->detail, + pFirstGrab->detail, + (unsigned int)AnyKey))) + return FALSE; + + + if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + any_modifier) && + DetailSupersedesSecond(pSecondGrab->modifiersDetail, + pFirstGrab->modifiersDetail, + any_modifier))) + return FALSE; + + return TRUE; +} + + +/** + * Prepend the new grab to the list of passive grabs on the window. + * Any previously existing grab that matches the new grab will be removed. + * Adding a new grab that would override another client's grab will result in + * a BadAccess. + * + * @return Success or X error code on failure. + */ +int +AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab) +{ + GrabPtr grab; + Mask access_mode = DixGrabAccess; + int rc; + + for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) + { + if (GrabMatchesSecond(pGrab, grab, FALSE)) + { + if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) + { + FreeGrab(pGrab); + return BadAccess; + } + } + } + + if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode); + if (rc != Success) + return rc; + + /* Remove all grabs that match the new one exactly */ + for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) + { + if (GrabsAreIdentical(pGrab, grab)) + { + DeletePassiveGrabFromList(grab); + break; + } + } + + 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; + unsigned int any_modifier; + unsigned int any_key; + +#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 = malloc(i * sizeof(GrabPtr)); + adds = malloc(i * sizeof(GrabPtr)); + updates = malloc(i * sizeof(Mask **)); + details = malloc(i * sizeof(Mask *)); + if (!deletes || !adds || !updates || !details) + { + if (details) free(details); + if (updates) free(updates); + if (adds) free(adds); + if (deletes) free(deletes); + return FALSE; + } + + any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : (unsigned int)AnyModifier; + any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyKeycode : (unsigned int)AnyKey; + 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, + (grab->grabtype == GRABTYPE_CORE))) + continue; + if (GrabSupersedesSecond(pMinuendGrab, grab)) + { + deletes[ndels++] = grab; + } + else if ((grab->detail.exact == any_key) + && (grab->modifiersDetail.exact != any_modifier)) + { + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + } + else if ((grab->modifiersDetail.exact == any_modifier) + && (grab->detail.exact != any_key)) + { + UPDATE(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail.exact); + } + else if ((pMinuendGrab->detail.exact != any_key) + && (pMinuendGrab->modifiersDetail.exact != any_modifier)) + { + GrabPtr pNewGrab; + GrabParameters param; + + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + + memset(¶m, 0, sizeof(param)); + param.ownerEvents = grab->ownerEvents; + param.this_device_mode = grab->keyboardMode; + param.other_devices_mode = grab->pointerMode; + param.modifiers = any_modifier; + + pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device, + grab->modifierDevice, grab->window, + grab->grabtype, + (GrabMask*)&grab->eventMask, + ¶m, (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 == any_key) + { + 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]; + } + } + free(details); + free(updates); + free(adds); + free(deletes); + return ok; + +#undef UPDATE +} diff --git a/xorg-server/dix/inpututils.c b/xorg-server/dix/inpututils.c index 4848c1bc2..55c27e80f 100644 --- a/xorg-server/dix/inpututils.c +++ b/xorg-server/dix/inpututils.c @@ -1,334 +1,334 @@ -/* - * Copyright © 2008 Daniel Stone - * - * 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. - * - * Author: Daniel Stone - */ - -#ifdef HAVE_DIX_CONFIG_H -#include "dix-config.h" -#endif - -#include "exevents.h" -#include "exglobals.h" -#include "misc.h" -#include "input.h" -#include "inputstr.h" -#include "xace.h" -#include "xkbsrv.h" -#include "xkbstr.h" - -/* Check if a button map change is okay with the device. - * Returns -1 for BadValue, as it collides with MappingBusy. */ -static int -check_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out, - ClientPtr client) -{ - int i, ret; - - if (!dev || !dev->button) - { - client->errorValue = (dev) ? dev->id : 0; - return BadDevice; - } - - ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); - if (ret != Success) - { - client->errorValue = dev->id; - return ret; - } - - for (i = 0; i < len; i++) { - if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1]) - return MappingBusy; - } - - return Success; -} - -static void -do_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) -{ - int i; - xEvent core_mn; - deviceMappingNotify xi_mn; - - /* The map in ButtonClassRec refers to button numbers, whereas the - * protocol is zero-indexed. Sigh. */ - memcpy(&(dev->button->map[1]), map, len); - - core_mn.u.u.type = MappingNotify; - core_mn.u.mappingNotify.request = MappingPointer; - - /* 0 is the server client. */ - for (i = 1; i < currentMaxClients; i++) { - /* Don't send irrelevant events to naïve clients. */ - if (!clients[i] || clients[i]->clientState != ClientStateRunning) - continue; - - if (!XIShouldNotify(clients[i], dev)) - continue; - - core_mn.u.u.sequenceNumber = clients[i]->sequence; - WriteEventsToClient(clients[i], 1, &core_mn); - } - - xi_mn.type = DeviceMappingNotify; - xi_mn.request = MappingPointer; - xi_mn.deviceid = dev->id; - xi_mn.time = GetTimeInMillis(); - - SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1); -} - -/* - * Does what it says on the box, both for core and Xi. - * - * Faithfully reports any errors encountered while trying to apply the map - * to the requested device, faithfully ignores any errors encountered while - * trying to apply the map to its master/slaves. - */ -int -ApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) -{ - int ret; - - /* If we can't perform the change on the requested device, bail out. */ - ret = check_butmap_change(dev, map, len, &client->errorValue, client); - if (ret != Success) - return ret; - do_butmap_change(dev, map, len, client); - - return Success; -} - -/* Check if a modifier map change is okay with the device. - * Returns -1 for BadValue, as it collides with MappingBusy; this particular - * caveat can be removed with LegalModifier, as we have no other reason to - * set MappingFailed. Sigh. */ -static int -check_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap) -{ - int ret, i; - XkbDescPtr xkb; - - ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); - if (ret != Success) - return ret; - - if (!dev->key) - return BadMatch; - xkb = dev->key->xkbInfo->desc; - - for (i = 0; i < MAP_LENGTH; i++) { - if (!modmap[i]) - continue; - - /* Check that all the new modifiers fall within the advertised - * keycode range. */ - if (i < xkb->min_key_code || i > xkb->max_key_code) { - client->errorValue = i; - return -1; - } - - /* Make sure the mapping is okay with the DDX. */ - if (!LegalModifier(i, dev)) { - client->errorValue = i; - return MappingFailed; - } - - /* None of the new modifiers may be down while we change the - * map. */ - if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { - client->errorValue = i; - return MappingBusy; - } - } - - /* None of the old modifiers may be down while we change the map, - * either. */ - for (i = xkb->min_key_code; i < xkb->max_key_code; i++) { - if (!xkb->map->modmap[i]) - continue; - if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { - client->errorValue = i; - return MappingBusy; - } - } - - return Success; -} - -static int -check_modmap_change_slave(ClientPtr client, DeviceIntPtr master, - DeviceIntPtr slave, CARD8 *modmap) -{ - XkbDescPtr master_xkb, slave_xkb; - int i, j; - - if (!slave->key || !master->key) - return 0; - - master_xkb = master->key->xkbInfo->desc; - slave_xkb = slave->key->xkbInfo->desc; - - /* Ignore devices with a clearly different keymap. */ - if (slave_xkb->min_key_code != master_xkb->min_key_code || - slave_xkb->max_key_code != master_xkb->max_key_code) - return 0; - - for (i = 0; i < MAP_LENGTH; i++) { - if (!modmap[i]) - continue; - - /* If we have different symbols for any modifier on an - * extended keyboard, ignore the whole remap request. */ - for (j = 0; - j < XkbKeyNumSyms(slave_xkb, i) && - j < XkbKeyNumSyms(master_xkb, i); - j++) - if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j]) - return 0; - } - - if (check_modmap_change(client, slave, modmap) != Success) - return 0; - - return 1; -} - -/* Actually change the modifier map, and send notifications. Cannot fail. */ -static void -do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap) -{ - XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient); -} - -/* Rebuild modmap (key -> mod) from map (mod -> key). */ -static int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap, - int max_keys_per_mod) -{ - int i, len = max_keys_per_mod * 8; - - memset(modmap, 0, MAP_LENGTH); - - for (i = 0; i < len; i++) { - if (!modkeymap[i]) - continue; - - if (modkeymap[i] >= MAP_LENGTH) - return BadValue; - - if (modmap[modkeymap[i]]) - return BadValue; - - modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod); - } - - return Success; -} - -int -change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap, - int max_keys_per_mod) -{ - int ret; - CARD8 modmap[MAP_LENGTH]; - DeviceIntPtr tmp; - - ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod); - if (ret != Success) - return ret; - - /* If we can't perform the change on the requested device, bail out. */ - ret = check_modmap_change(client, dev, modmap); - if (ret != Success) - return ret; - do_modmap_change(client, dev, modmap); - - /* Change any attached masters/slaves. */ - if (IsMaster(dev)) { - for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if (!IsMaster(tmp) && tmp->u.master == dev) - if (check_modmap_change_slave(client, dev, tmp, modmap)) - do_modmap_change(client, tmp, modmap); - } - } - else if (dev->u.master && dev->u.master->u.lastSlave == dev) { - /* If this fails, expect the results to be weird. */ - if (check_modmap_change(client, dev->u.master, modmap)) - do_modmap_change(client, dev->u.master, modmap); - } - - return Success; -} - -int generate_modkeymap(ClientPtr client, DeviceIntPtr dev, - KeyCode **modkeymap_out, int *max_keys_per_mod_out) -{ - CARD8 keys_per_mod[8]; - int max_keys_per_mod; - KeyCode *modkeymap; - int i, j, ret; - - ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); - if (ret != Success) - return ret; - - if (!dev->key) - return BadMatch; - - /* Count the number of keys per modifier to determine how wide we - * should make the map. */ - max_keys_per_mod = 0; - for (i = 0; i < 8; i++) - keys_per_mod[i] = 0; - for (i = 8; i < MAP_LENGTH; i++) { - for (j = 0; j < 8; j++) { - if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { - if (++keys_per_mod[j] > max_keys_per_mod) - max_keys_per_mod = keys_per_mod[j]; - } - } - } - - modkeymap = xcalloc(max_keys_per_mod * 8, sizeof(KeyCode)); - if (!modkeymap) - return BadAlloc; - - for (i = 0; i < 8; i++) - keys_per_mod[i] = 0; - - for (i = 8; i < MAP_LENGTH; i++) { - for (j = 0; j < 8; j++) { - if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { - modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i; - keys_per_mod[j]++; - } - } - } - - *max_keys_per_mod_out = max_keys_per_mod; - *modkeymap_out = modkeymap; - - return Success; -} +/* + * Copyright © 2008 Daniel Stone + * + * 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. + * + * Author: Daniel Stone + */ + +#ifdef HAVE_DIX_CONFIG_H +#include "dix-config.h" +#endif + +#include "exevents.h" +#include "exglobals.h" +#include "misc.h" +#include "input.h" +#include "inputstr.h" +#include "xace.h" +#include "xkbsrv.h" +#include "xkbstr.h" + +/* Check if a button map change is okay with the device. + * Returns -1 for BadValue, as it collides with MappingBusy. */ +static int +check_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out, + ClientPtr client) +{ + int i, ret; + + if (!dev || !dev->button) + { + client->errorValue = (dev) ? dev->id : 0; + return BadDevice; + } + + ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); + if (ret != Success) + { + client->errorValue = dev->id; + return ret; + } + + for (i = 0; i < len; i++) { + if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1]) + return MappingBusy; + } + + return Success; +} + +static void +do_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) +{ + int i; + xEvent core_mn; + deviceMappingNotify xi_mn; + + /* The map in ButtonClassRec refers to button numbers, whereas the + * protocol is zero-indexed. Sigh. */ + memcpy(&(dev->button->map[1]), map, len); + + core_mn.u.u.type = MappingNotify; + core_mn.u.mappingNotify.request = MappingPointer; + + /* 0 is the server client. */ + for (i = 1; i < currentMaxClients; i++) { + /* Don't send irrelevant events to naïve clients. */ + if (!clients[i] || clients[i]->clientState != ClientStateRunning) + continue; + + if (!XIShouldNotify(clients[i], dev)) + continue; + + core_mn.u.u.sequenceNumber = clients[i]->sequence; + WriteEventsToClient(clients[i], 1, &core_mn); + } + + xi_mn.type = DeviceMappingNotify; + xi_mn.request = MappingPointer; + xi_mn.deviceid = dev->id; + xi_mn.time = GetTimeInMillis(); + + SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1); +} + +/* + * Does what it says on the box, both for core and Xi. + * + * Faithfully reports any errors encountered while trying to apply the map + * to the requested device, faithfully ignores any errors encountered while + * trying to apply the map to its master/slaves. + */ +int +ApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) +{ + int ret; + + /* If we can't perform the change on the requested device, bail out. */ + ret = check_butmap_change(dev, map, len, &client->errorValue, client); + if (ret != Success) + return ret; + do_butmap_change(dev, map, len, client); + + return Success; +} + +/* Check if a modifier map change is okay with the device. + * Returns -1 for BadValue, as it collides with MappingBusy; this particular + * caveat can be removed with LegalModifier, as we have no other reason to + * set MappingFailed. Sigh. */ +static int +check_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap) +{ + int ret, i; + XkbDescPtr xkb; + + ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); + if (ret != Success) + return ret; + + if (!dev->key) + return BadMatch; + xkb = dev->key->xkbInfo->desc; + + for (i = 0; i < MAP_LENGTH; i++) { + if (!modmap[i]) + continue; + + /* Check that all the new modifiers fall within the advertised + * keycode range. */ + if (i < xkb->min_key_code || i > xkb->max_key_code) { + client->errorValue = i; + return -1; + } + + /* Make sure the mapping is okay with the DDX. */ + if (!LegalModifier(i, dev)) { + client->errorValue = i; + return MappingFailed; + } + + /* None of the new modifiers may be down while we change the + * map. */ + if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { + client->errorValue = i; + return MappingBusy; + } + } + + /* None of the old modifiers may be down while we change the map, + * either. */ + for (i = xkb->min_key_code; i < xkb->max_key_code; i++) { + if (!xkb->map->modmap[i]) + continue; + if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { + client->errorValue = i; + return MappingBusy; + } + } + + return Success; +} + +static int +check_modmap_change_slave(ClientPtr client, DeviceIntPtr master, + DeviceIntPtr slave, CARD8 *modmap) +{ + XkbDescPtr master_xkb, slave_xkb; + int i, j; + + if (!slave->key || !master->key) + return 0; + + master_xkb = master->key->xkbInfo->desc; + slave_xkb = slave->key->xkbInfo->desc; + + /* Ignore devices with a clearly different keymap. */ + if (slave_xkb->min_key_code != master_xkb->min_key_code || + slave_xkb->max_key_code != master_xkb->max_key_code) + return 0; + + for (i = 0; i < MAP_LENGTH; i++) { + if (!modmap[i]) + continue; + + /* If we have different symbols for any modifier on an + * extended keyboard, ignore the whole remap request. */ + for (j = 0; + j < XkbKeyNumSyms(slave_xkb, i) && + j < XkbKeyNumSyms(master_xkb, i); + j++) + if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j]) + return 0; + } + + if (check_modmap_change(client, slave, modmap) != Success) + return 0; + + return 1; +} + +/* Actually change the modifier map, and send notifications. Cannot fail. */ +static void +do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap) +{ + XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient); +} + +/* Rebuild modmap (key -> mod) from map (mod -> key). */ +static int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap, + int max_keys_per_mod) +{ + int i, len = max_keys_per_mod * 8; + + memset(modmap, 0, MAP_LENGTH); + + for (i = 0; i < len; i++) { + if (!modkeymap[i]) + continue; + + if (modkeymap[i] >= MAP_LENGTH) + return BadValue; + + if (modmap[modkeymap[i]]) + return BadValue; + + modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod); + } + + return Success; +} + +int +change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap, + int max_keys_per_mod) +{ + int ret; + CARD8 modmap[MAP_LENGTH]; + DeviceIntPtr tmp; + + ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod); + if (ret != Success) + return ret; + + /* If we can't perform the change on the requested device, bail out. */ + ret = check_modmap_change(client, dev, modmap); + if (ret != Success) + return ret; + do_modmap_change(client, dev, modmap); + + /* Change any attached masters/slaves. */ + if (IsMaster(dev)) { + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { + if (!IsMaster(tmp) && tmp->u.master == dev) + if (check_modmap_change_slave(client, dev, tmp, modmap)) + do_modmap_change(client, tmp, modmap); + } + } + else if (dev->u.master && dev->u.master->u.lastSlave == dev) { + /* If this fails, expect the results to be weird. */ + if (check_modmap_change(client, dev->u.master, modmap)) + do_modmap_change(client, dev->u.master, modmap); + } + + return Success; +} + +int generate_modkeymap(ClientPtr client, DeviceIntPtr dev, + KeyCode **modkeymap_out, int *max_keys_per_mod_out) +{ + CARD8 keys_per_mod[8]; + int max_keys_per_mod; + KeyCode *modkeymap; + int i, j, ret; + + ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); + if (ret != Success) + return ret; + + if (!dev->key) + return BadMatch; + + /* Count the number of keys per modifier to determine how wide we + * should make the map. */ + max_keys_per_mod = 0; + for (i = 0; i < 8; i++) + keys_per_mod[i] = 0; + for (i = 8; i < MAP_LENGTH; i++) { + for (j = 0; j < 8; j++) { + if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { + if (++keys_per_mod[j] > max_keys_per_mod) + max_keys_per_mod = keys_per_mod[j]; + } + } + } + + modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode)); + if (!modkeymap) + return BadAlloc; + + for (i = 0; i < 8; i++) + keys_per_mod[i] = 0; + + for (i = 8; i < MAP_LENGTH; i++) { + for (j = 0; j < 8; j++) { + if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { + modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i; + keys_per_mod[j]++; + } + } + } + + *max_keys_per_mod_out = max_keys_per_mod; + *modkeymap_out = modkeymap; + + return Success; +} diff --git a/xorg-server/dix/main.c b/xorg-server/dix/main.c index 2cff59c8e..259093236 100644 --- a/xorg-server/dix/main.c +++ b/xorg-server/dix/main.c @@ -1,345 +1,345 @@ -/*********************************************************** - -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 -#include -#endif - -#include -#include /* for unistd.h */ -#include -#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 "selection.h" -#include -#include "opaque.h" -#include "servermd.h" -#include "hotplug.h" -#include "site.h" -#include "dixfont.h" -#include "extnsionst.h" -#include "privates.h" -#include "registry.h" -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#else -#include "dixevents.h" /* InitEvents() */ -#include "dispatch.h" /* InitProcVectors() */ -#endif - -#ifdef DPMSExtension -#include -#include "dpmsproc.h" -#endif - -extern void Dispatch(void); - -extern void InitProcVectors(void); - -#ifdef XQUARTZ -#include - -BOOL serverInitComplete = FALSE; -pthread_mutex_t serverInitCompleteMutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t serverInitCompleteCond = PTHREAD_COND_INITIALIZER; - -int dix_main(int argc, char *argv[], char *envp[]); - -int dix_main(int argc, char *argv[], char *envp[]) -#else -int main(int argc, char *argv[], char *envp[]) -#endif -{ - int i; - HWEventQueueType alwaysCheckForInput[2]; - - display = "0"; - - InitRegions(); - - pixman_disable_out_of_bounds_workaround(); - - CheckUserParameters(argc, argv, envp); - - CheckUserAuthorization(); - - InitConnectionLimits(); - - ProcessCommandLine(argc, argv); - - alwaysCheckForInput[0] = 0; - alwaysCheckForInput[1] = 1; - while(1) - { - serverGeneration++; - ScreenSaverTime = defaultScreenSaverTime; - ScreenSaverInterval = defaultScreenSaverInterval; - ScreenSaverBlanking = defaultScreenSaverBlanking; - ScreenSaverAllowExposures = defaultScreenSaverAllowExposures; -#ifdef DPMSExtension - DPMSStandbyTime = DPMSSuspendTime = DPMSOffTime = ScreenSaverTime; - DPMSEnabled = TRUE; - DPMSPowerLevel = 0; -#endif - InitBlockAndWakeupHandlers(); - /* Perform any operating system dependent initializations you'd like */ - OsInit(); - if(serverGeneration == 1) - { - CreateWellKnownSockets(); - InitProcVectors(); - for (i=1; iCreateScreenResources && - !(*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"); - } - - InitFonts(); - if (SetDefaultFontPath(defaultFontPath) != Success) { - ErrorF("[dix] failed to set default font path '%s'", defaultFontPath); - } - if (!SetDefaultFont(defaultTextFont)) { - FatalError("could not open default font '%s'", defaultTextFont); - } - - if (!(rootCursor = CreateRootCursor(NULL, 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 - -#ifdef PANORAMIX - /* - * Consolidate window and colourmap information for each screen - */ - if (!noPanoramiXExtension) - PanoramiXConsolidate(); -#endif - - for (i = 0; i < screenInfo.numScreens; i++) - InitRootWindow(WindowTable[i]); - - InitCoreDevices(); - InitInput(argc, argv); - InitAndStartDevices(); - - dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - if (!PanoramiXCreateConnectionBlock()) { - FatalError("could not create connection block info"); - } - } else -#endif - { - if (!CreateConnectionBlock()) { - FatalError("could not create connection block info"); - } - } - -#ifdef XQUARTZ - /* Let the other threads know the server is done with its init */ - pthread_mutex_lock(&serverInitCompleteMutex); - serverInitComplete = TRUE; - pthread_cond_broadcast(&serverInitCompleteCond); - pthread_mutex_unlock(&serverInitCompleteMutex); -#endif - - NotifyParentProcess(); - - Dispatch(); - - UndisplayDevices(); - - /* Now free up whatever must be freed */ - if (screenIsSaved == SCREEN_SAVER_ON) - dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); - FreeScreenSaverTimer(); - CloseDownExtensions(); - -#ifdef PANORAMIX - { - Bool remember_it = noPanoramiXExtension; - noPanoramiXExtension = TRUE; - FreeAllResources(); - noPanoramiXExtension = remember_it; - } -#else - FreeAllResources(); -#endif - - CloseInput(); - - memset(WindowTable, 0, sizeof(WindowTable)); - CloseDownDevices(); - CloseDownEvents(); - - for (i = screenInfo.numScreens - 1; i >= 0; i--) - { - FreeScratchPixmapsForScreen(i); - FreeGCperDepth(i); - FreeDefaultStipple(i); - (* screenInfo.screens[i]->CloseScreen)(i, screenInfo.screens[i]); - dixFreePrivates(screenInfo.screens[i]->devPrivates); - xfree(screenInfo.screens[i]); - screenInfo.numScreens = i; - } - FreeFonts(); - - FreeAuditTimer(); - - dixFreePrivates(serverClient->devPrivates); - serverClient->devPrivates = NULL; - - if (dispatchException & DE_TERMINATE) - { - CloseWellKnownConnections(); - } - - OsCleanup((dispatchException & DE_TERMINATE) != 0); - - if (dispatchException & DE_TERMINATE) - { - ddxGiveUp(); - break; - } - - xfree(ConnectionInfo); - ConnectionInfo = NULL; - } - return(0); -} - +/*********************************************************** + +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 +#include +#endif + +#include +#include /* for unistd.h */ +#include +#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 "selection.h" +#include +#include "opaque.h" +#include "servermd.h" +#include "hotplug.h" +#include "site.h" +#include "dixfont.h" +#include "extnsionst.h" +#include "privates.h" +#include "registry.h" +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#else +#include "dixevents.h" /* InitEvents() */ +#include "dispatch.h" /* InitProcVectors() */ +#endif + +#ifdef DPMSExtension +#include +#include "dpmsproc.h" +#endif + +extern void Dispatch(void); + +extern void InitProcVectors(void); + +#ifdef XQUARTZ +#include + +BOOL serverInitComplete = FALSE; +pthread_mutex_t serverInitCompleteMutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t serverInitCompleteCond = PTHREAD_COND_INITIALIZER; + +int dix_main(int argc, char *argv[], char *envp[]); + +int dix_main(int argc, char *argv[], char *envp[]) +#else +int main(int argc, char *argv[], char *envp[]) +#endif +{ + int i; + HWEventQueueType alwaysCheckForInput[2]; + + display = "0"; + + InitRegions(); + + pixman_disable_out_of_bounds_workaround(); + + CheckUserParameters(argc, argv, envp); + + CheckUserAuthorization(); + + InitConnectionLimits(); + + ProcessCommandLine(argc, argv); + + alwaysCheckForInput[0] = 0; + alwaysCheckForInput[1] = 1; + while(1) + { + serverGeneration++; + ScreenSaverTime = defaultScreenSaverTime; + ScreenSaverInterval = defaultScreenSaverInterval; + ScreenSaverBlanking = defaultScreenSaverBlanking; + ScreenSaverAllowExposures = defaultScreenSaverAllowExposures; +#ifdef DPMSExtension + DPMSStandbyTime = DPMSSuspendTime = DPMSOffTime = ScreenSaverTime; + DPMSEnabled = TRUE; + DPMSPowerLevel = 0; +#endif + InitBlockAndWakeupHandlers(); + /* Perform any operating system dependent initializations you'd like */ + OsInit(); + if(serverGeneration == 1) + { + CreateWellKnownSockets(); + InitProcVectors(); + for (i=1; iCreateScreenResources && + !(*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"); + } + + InitFonts(); + if (SetDefaultFontPath(defaultFontPath) != Success) { + ErrorF("[dix] failed to set default font path '%s'", defaultFontPath); + } + if (!SetDefaultFont(defaultTextFont)) { + FatalError("could not open default font '%s'", defaultTextFont); + } + + if (!(rootCursor = CreateRootCursor(NULL, 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 + +#ifdef PANORAMIX + /* + * Consolidate window and colourmap information for each screen + */ + if (!noPanoramiXExtension) + PanoramiXConsolidate(); +#endif + + for (i = 0; i < screenInfo.numScreens; i++) + InitRootWindow(WindowTable[i]); + + InitCoreDevices(); + InitInput(argc, argv); + InitAndStartDevices(); + + dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + if (!PanoramiXCreateConnectionBlock()) { + FatalError("could not create connection block info"); + } + } else +#endif + { + if (!CreateConnectionBlock()) { + FatalError("could not create connection block info"); + } + } + +#ifdef XQUARTZ + /* Let the other threads know the server is done with its init */ + pthread_mutex_lock(&serverInitCompleteMutex); + serverInitComplete = TRUE; + pthread_cond_broadcast(&serverInitCompleteCond); + pthread_mutex_unlock(&serverInitCompleteMutex); +#endif + + NotifyParentProcess(); + + Dispatch(); + + UndisplayDevices(); + + /* Now free up whatever must be freed */ + if (screenIsSaved == SCREEN_SAVER_ON) + dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); + FreeScreenSaverTimer(); + CloseDownExtensions(); + +#ifdef PANORAMIX + { + Bool remember_it = noPanoramiXExtension; + noPanoramiXExtension = TRUE; + FreeAllResources(); + noPanoramiXExtension = remember_it; + } +#else + FreeAllResources(); +#endif + + CloseInput(); + + memset(WindowTable, 0, sizeof(WindowTable)); + CloseDownDevices(); + CloseDownEvents(); + + for (i = screenInfo.numScreens - 1; i >= 0; i--) + { + FreeScratchPixmapsForScreen(i); + FreeGCperDepth(i); + FreeDefaultStipple(i); + (* screenInfo.screens[i]->CloseScreen)(i, screenInfo.screens[i]); + dixFreePrivates(screenInfo.screens[i]->devPrivates); + free(screenInfo.screens[i]); + screenInfo.numScreens = i; + } + FreeFonts(); + + FreeAuditTimer(); + + dixFreePrivates(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); +} + diff --git a/xorg-server/dix/pixmap.c b/xorg-server/dix/pixmap.c index 10ec02a78..460da771e 100644 --- a/xorg-server/dix/pixmap.c +++ b/xorg-server/dix/pixmap.c @@ -1,122 +1,122 @@ -/* - -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 "scrnintstr.h" -#include "misc.h" -#include "os.h" -#include "windowstr.h" -#include "resource.h" -#include "dixstruct.h" -#include "gcstruct.h" -#include "servermd.h" -#include "site.h" - - -/* - * Scratch pixmap management and device independent pixmap allocation - * function. - */ - - -/* callable by ddx */ -PixmapPtr -GetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth, - int bitsPerPixel, int devKind, pointer pPixData) -{ - PixmapPtr pPixmap = pScreen->pScratchPixmap; - - if (pPixmap) - pScreen->pScratchPixmap = NULL; - else - /* width and height of 0 means don't allocate any pixmap data */ - pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0); - - if (pPixmap) { - if ((*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth, - bitsPerPixel, devKind, pPixData)) - return pPixmap; - (*pScreen->DestroyPixmap)(pPixmap); - } - return NullPixmap; -} - - -/* callable by ddx */ -void -FreeScratchPixmapHeader(PixmapPtr pPixmap) -{ - if (pPixmap) - { - ScreenPtr pScreen = pPixmap->drawable.pScreen; - - pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */ - if (pScreen->pScratchPixmap) - (*pScreen->DestroyPixmap)(pPixmap); - else - pScreen->pScratchPixmap = pPixmap; - } -} - - -Bool -CreateScratchPixmapsForScreen(int scrnum) -{ - /* let it be created on first use */ - screenInfo.screens[scrnum]->pScratchPixmap = NULL; - return TRUE; -} - - -void -FreeScratchPixmapsForScreen(int scrnum) -{ - FreeScratchPixmapHeader(screenInfo.screens[scrnum]->pScratchPixmap); -} - - -/* callable by ddx */ -PixmapPtr -AllocatePixmap(ScreenPtr pScreen, int pixDataSize) -{ - PixmapPtr pPixmap; - - if (pScreen->totalPixmapSize > ((size_t)-1) - pixDataSize) - return NullPixmap; - - pPixmap = xalloc(pScreen->totalPixmapSize + pixDataSize); - if (!pPixmap) - return NullPixmap; - - pPixmap->devPrivates = NULL; - return pPixmap; -} +/* + +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 "scrnintstr.h" +#include "misc.h" +#include "os.h" +#include "windowstr.h" +#include "resource.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "servermd.h" +#include "site.h" + + +/* + * Scratch pixmap management and device independent pixmap allocation + * function. + */ + + +/* callable by ddx */ +PixmapPtr +GetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + PixmapPtr pPixmap = pScreen->pScratchPixmap; + + if (pPixmap) + pScreen->pScratchPixmap = NULL; + else + /* width and height of 0 means don't allocate any pixmap data */ + pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0); + + if (pPixmap) { + if ((*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData)) + return pPixmap; + (*pScreen->DestroyPixmap)(pPixmap); + } + return NullPixmap; +} + + +/* callable by ddx */ +void +FreeScratchPixmapHeader(PixmapPtr pPixmap) +{ + if (pPixmap) + { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + + pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */ + if (pScreen->pScratchPixmap) + (*pScreen->DestroyPixmap)(pPixmap); + else + pScreen->pScratchPixmap = pPixmap; + } +} + + +Bool +CreateScratchPixmapsForScreen(int scrnum) +{ + /* let it be created on first use */ + screenInfo.screens[scrnum]->pScratchPixmap = NULL; + return TRUE; +} + + +void +FreeScratchPixmapsForScreen(int scrnum) +{ + FreeScratchPixmapHeader(screenInfo.screens[scrnum]->pScratchPixmap); +} + + +/* callable by ddx */ +PixmapPtr +AllocatePixmap(ScreenPtr pScreen, int pixDataSize) +{ + PixmapPtr pPixmap; + + if (pScreen->totalPixmapSize > ((size_t)-1) - pixDataSize) + return NullPixmap; + + pPixmap = malloc(pScreen->totalPixmapSize + pixDataSize); + if (!pPixmap) + return NullPixmap; + + pPixmap->devPrivates = NULL; + return pPixmap; +} diff --git a/xorg-server/dix/privates.c b/xorg-server/dix/privates.c index e3e727462..52a8df3f6 100644 --- a/xorg-server/dix/privates.c +++ b/xorg-server/dix/privates.c @@ -1,322 +1,282 @@ -/* - -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 "windowstr.h" -#include "resource.h" -#include "privates.h" -#include "gcstruct.h" -#include "cursorstr.h" -#include "colormapst.h" -#include "inputstr.h" - -struct _Private { - int state; - pointer value; -}; - -typedef struct _PrivateDesc { - DevPrivateKey key; - unsigned size; - CallbackListPtr initfuncs; - CallbackListPtr deletefuncs; -} PrivateDescRec; - -#define PRIV_MAX 256 -#define PRIV_STEP 16 - -/* list of all allocated privates */ -static PrivateDescRec items[PRIV_MAX]; -static int nextPriv; - -static PrivateDescRec * -findItem(const DevPrivateKey key) -{ - if (!*key) { - if (nextPriv >= PRIV_MAX) - return NULL; - - items[nextPriv].key = key; - *key = nextPriv; - nextPriv++; - } - - return items + *key; -} - -static _X_INLINE int -privateExists(PrivateRec **privates, const DevPrivateKey key) -{ - return *key && *privates && - (*privates)[0].state > *key && - (*privates)[*key].state; -} - -/* - * Request pre-allocated space. - */ -int -dixRequestPrivate(const DevPrivateKey key, unsigned size) -{ - PrivateDescRec *item = findItem(key); - if (!item) - return FALSE; - if (size > item->size) - item->size = size; - return TRUE; -} - -/* - * Allocate a private and attach it to an existing object. - */ -pointer * -dixAllocatePrivate(PrivateRec **privates, const DevPrivateKey key) -{ - PrivateDescRec *item = findItem(key); - PrivateCallbackRec calldata; - PrivateRec *ptr; - pointer value; - int oldsize, newsize; - - newsize = (*key / PRIV_STEP + 1) * PRIV_STEP; - - /* resize or init privates array */ - if (!item) - return NULL; - - /* initialize privates array if necessary */ - if (!*privates) { - ptr = xcalloc(newsize, sizeof(*ptr)); - if (!ptr) - return NULL; - *privates = ptr; - (*privates)[0].state = newsize; - } - - oldsize = (*privates)[0].state; - - /* resize privates array if necessary */ - if (*key >= oldsize) { - ptr = xrealloc(*privates, newsize * sizeof(*ptr)); - if (!ptr) - return NULL; - memset(ptr + oldsize, 0, (newsize - oldsize) * sizeof(*ptr)); - *privates = ptr; - (*privates)[0].state = newsize; - } - - /* initialize slot */ - ptr = *privates + *key; - ptr->state = 1; - if (item->size) { - value = xcalloc(item->size, 1); - if (!value) - return NULL; - ptr->value = value; - } - - calldata.key = key; - calldata.value = &ptr->value; - CallCallbacks(&item->initfuncs, &calldata); - - return &ptr->value; -} - -/* - * Look up a private pointer. - */ -pointer -dixLookupPrivate(PrivateRec **privates, const DevPrivateKey key) -{ - pointer *ptr; - - if (privateExists(privates, key)) - return (*privates)[*key].value; - - ptr = dixAllocatePrivate(privates, key); - return ptr ? *ptr : NULL; -} - -/* - * Look up the address of a private pointer. - */ -pointer * -dixLookupPrivateAddr(PrivateRec **privates, const DevPrivateKey key) -{ - if (privateExists(privates, key)) - return &(*privates)[*key].value; - - return dixAllocatePrivate(privates, key); -} - -/* - * Set a private pointer. - */ -int -dixSetPrivate(PrivateRec **privates, const DevPrivateKey key, pointer val) -{ - top: - if (privateExists(privates, key)) { - (*privates)[*key].value = val; - return TRUE; - } - - if (!dixAllocatePrivate(privates, key)) - return FALSE; - goto top; -} - -/* - * Called to free privates at object deletion time. - */ -void -dixFreePrivates(PrivateRec *privates) -{ - int i; - PrivateCallbackRec calldata; - - if (privates) - for (i = 1; i < privates->state; i++) - if (privates[i].state) { - /* call the delete callbacks */ - calldata.key = items[i].key; - calldata.value = &privates[i].value; - CallCallbacks(&items[i].deletefuncs, &calldata); - - /* free pre-allocated memory */ - if (items[i].size) - xfree(privates[i].value); - } - - xfree(privates); -} - -/* - * Callback registration - */ -int -dixRegisterPrivateInitFunc(const DevPrivateKey key, - CallbackProcPtr callback, pointer data) -{ - PrivateDescRec *item = findItem(key); - if (!item) - return FALSE; - - return AddCallback(&item->initfuncs, callback, data); -} - -int -dixRegisterPrivateDeleteFunc(const DevPrivateKey key, - CallbackProcPtr callback, pointer data) -{ - PrivateDescRec *item = findItem(key); - if (!item) - return FALSE; - - return AddCallback(&item->deletefuncs, callback, data); -} - -/* Table of devPrivates offsets */ -static const int offsetDefaults[] = { - -1, /* RT_NONE */ - offsetof(WindowRec, devPrivates), /* RT_WINDOW */ - offsetof(PixmapRec, devPrivates), /* RT_PIXMAP */ - offsetof(GC, devPrivates), /* RT_GC */ - -1, /* RT_FONT */ - offsetof(CursorRec, devPrivates), /* RT_CURSOR */ - offsetof(ColormapRec, devPrivates), /* RT_COLORMAP */ - -1, /* RT_CMAPENTRY */ - -1, /* RT_OTHERCLIENT */ - -1 /* RT_PASSIVEGRAB */ -}; - -static int *offsets = NULL; -static int offsetsSize = 0; - -/* - * Specify where the devPrivates field is located in a structure type - */ -int -dixRegisterPrivateOffset(RESTYPE type, int offset) -{ - type = type & TypeMask; - - /* resize offsets table if necessary */ - while (type >= offsetsSize) { - unsigned i = offsetsSize * 2 * sizeof(int); - offsets = (int *)xrealloc(offsets, i); - if (!offsets) { - offsetsSize = 0; - return FALSE; - } - for (i=offsetsSize; i < 2*offsetsSize; i++) - offsets[i] = -1; - offsetsSize *= 2; - } - - offsets[type] = offset; - return TRUE; -} - -int -dixLookupPrivateOffset(RESTYPE type) -{ - type = type & TypeMask; - assert(type < offsetsSize); - return offsets[type]; -} - -int -dixResetPrivates(void) -{ - int i; - - /* reset private descriptors */ - for (i = 1; i < nextPriv; i++) { - *items[i].key = 0; - items[i].size = 0; - DeleteCallbackList(&items[i].initfuncs); - DeleteCallbackList(&items[i].deletefuncs); - } - nextPriv = 1; - - /* reset offsets */ - if (offsets) - xfree(offsets); - offsetsSize = sizeof(offsetDefaults); - offsets = xalloc(offsetsSize); - offsetsSize /= sizeof(int); - if (!offsets) - return FALSE; - memcpy(offsets, offsetDefaults, sizeof(offsetDefaults)); - return TRUE; -} +/* + +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 "windowstr.h" +#include "resource.h" +#include "privates.h" +#include "gcstruct.h" +#include "cursorstr.h" +#include "colormapst.h" +#include "inputstr.h" + +struct _Private { + int state; + pointer value; +}; + +typedef struct _PrivateDesc { + DevPrivateKey key; + unsigned size; +} PrivateDescRec; + +#define PRIV_MAX 256 +#define PRIV_STEP 16 + +/* list of all allocated privates */ +static PrivateDescRec items[PRIV_MAX]; +static int nextPriv; + +static PrivateDescRec * +findItem(const DevPrivateKey key) +{ + if (!*key) { + if (nextPriv >= PRIV_MAX) + return NULL; + + items[nextPriv].key = key; + *key = nextPriv; + nextPriv++; + } + + return items + *key; +} + +static _X_INLINE int +privateExists(PrivateRec **privates, const DevPrivateKey key) +{ + return *key && *privates && + (*privates)[0].state > *key && + (*privates)[*key].state; +} + +/* + * Request pre-allocated space. + */ +int +dixRequestPrivate(const DevPrivateKey key, unsigned size) +{ + PrivateDescRec *item = findItem(key); + if (!item) + return FALSE; + if (size > item->size) + item->size = size; + return TRUE; +} + +/* + * Allocate a private and attach it to an existing object. + */ +pointer * +dixAllocatePrivate(PrivateRec **privates, const DevPrivateKey key) +{ + PrivateDescRec *item = findItem(key); + PrivateRec *ptr; + pointer value; + int oldsize, newsize; + + newsize = (*key / PRIV_STEP + 1) * PRIV_STEP; + + /* resize or init privates array */ + if (!item) + return NULL; + + /* initialize privates array if necessary */ + if (!*privates) { + ptr = calloc(newsize, sizeof(*ptr)); + if (!ptr) + return NULL; + *privates = ptr; + (*privates)[0].state = newsize; + } + + oldsize = (*privates)[0].state; + + /* resize privates array if necessary */ + if (*key >= oldsize) { + ptr = realloc(*privates, newsize * sizeof(*ptr)); + if (!ptr) + return NULL; + memset(ptr + oldsize, 0, (newsize - oldsize) * sizeof(*ptr)); + *privates = ptr; + (*privates)[0].state = newsize; + } + + /* initialize slot */ + ptr = *privates + *key; + ptr->state = 1; + if (item->size) { + value = calloc(item->size, 1); + if (!value) + return NULL; + ptr->value = value; + } + + return &ptr->value; +} + +/* + * Look up a private pointer. + */ +pointer +dixLookupPrivate(PrivateRec **privates, const DevPrivateKey key) +{ + pointer *ptr; + + if (privateExists(privates, key)) + return (*privates)[*key].value; + + ptr = dixAllocatePrivate(privates, key); + return ptr ? *ptr : NULL; +} + +/* + * Look up the address of a private pointer. + */ +pointer * +dixLookupPrivateAddr(PrivateRec **privates, const DevPrivateKey key) +{ + if (privateExists(privates, key)) + return &(*privates)[*key].value; + + return dixAllocatePrivate(privates, key); +} + +/* + * Set a private pointer. + */ +int +dixSetPrivate(PrivateRec **privates, const DevPrivateKey key, pointer val) +{ + top: + if (privateExists(privates, key)) { + (*privates)[*key].value = val; + return TRUE; + } + + if (!dixAllocatePrivate(privates, key)) + return FALSE; + goto top; +} + +/* + * Called to free privates at object deletion time. + */ +void +dixFreePrivates(PrivateRec *privates) +{ + int i; + + if (privates) + for (i = 1; i < privates->state; i++) + if (privates[i].state) { + /* free pre-allocated memory */ + if (items[i].size) + free(privates[i].value); + } + + free(privates); +} + +/* Table of devPrivates offsets */ +static const int offsetDefaults[] = { + -1, /* RT_NONE */ + offsetof(WindowRec, devPrivates), /* RT_WINDOW */ + offsetof(PixmapRec, devPrivates), /* RT_PIXMAP */ + offsetof(GC, devPrivates), /* RT_GC */ + -1, /* RT_FONT */ + offsetof(CursorRec, devPrivates), /* RT_CURSOR */ + offsetof(ColormapRec, devPrivates), /* RT_COLORMAP */ + -1, /* RT_CMAPENTRY */ + -1, /* RT_OTHERCLIENT */ + -1 /* RT_PASSIVEGRAB */ +}; + +static int *offsets = NULL; +static int offsetsSize = 0; + +/* + * Specify where the devPrivates field is located in a structure type + */ +int +dixRegisterPrivateOffset(RESTYPE type, int offset) +{ + type = type & TypeMask; + + /* resize offsets table if necessary */ + while (type >= offsetsSize) { + unsigned i = offsetsSize * 2 * sizeof(int); + offsets = (int *)realloc(offsets, i); + if (!offsets) { + offsetsSize = 0; + return FALSE; + } + for (i=offsetsSize; i < 2*offsetsSize; i++) + offsets[i] = -1; + offsetsSize *= 2; + } + + offsets[type] = offset; + return TRUE; +} + +int +dixLookupPrivateOffset(RESTYPE type) +{ + type = type & TypeMask; + assert(type < offsetsSize); + return offsets[type]; +} + +int +dixResetPrivates(void) +{ + int i; + + /* reset private descriptors */ + for (i = 1; i < nextPriv; i++) { + *items[i].key = 0; + items[i].size = 0; + } + nextPriv = 1; + + /* reset offsets */ + if (offsets) + free(offsets); + offsetsSize = sizeof(offsetDefaults); + offsets = malloc(offsetsSize); + offsetsSize /= sizeof(int); + if (!offsets) + return FALSE; + memcpy(offsets, offsetDefaults, sizeof(offsetDefaults)); + return TRUE; +} diff --git a/xorg-server/dix/property.c b/xorg-server/dix/property.c index 9ec5dc6ae..7c4bd62d2 100644 --- a/xorg-server/dix/property.c +++ b/xorg-server/dix/property.c @@ -1,649 +1,645 @@ -/*********************************************************** - -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 "windowstr.h" -#include "propertyst.h" -#include "dixstruct.h" -#include "dispatch.h" -#include "swaprep.h" -#include "xace.h" - -/***************************************************************** - * Property Stuff - * - * dixLookupProperty, dixChangeProperty, DeleteProperty - * - * Properties belong to windows. The list of properties should not be - * traversed directly. Instead, use the three functions listed above. - * - *****************************************************************/ - -#ifdef notdef -static void -PrintPropertys(WindowPtr pWin) -{ - PropertyPtr pProp; - int j; - - pProp = pWin->userProps; - while (pProp) - { - ErrorF("[dix] %x %x\n", pProp->propertyName, pProp->type); - ErrorF("[dix] property format: %d\n", pProp->format); - ErrorF("[dix] property data: \n"); - for (j=0; j<(pProp->format/8)*pProp->size; j++) - ErrorF("[dix] %c\n", pProp->data[j]); - pProp = pProp->next; - } -} -#endif - -int -dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName, - ClientPtr client, Mask access_mode) -{ - PropertyPtr pProp; - int rc = BadMatch; - client->errorValue = propertyName; - - for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) - if (pProp->propertyName == propertyName) - break; - - if (pProp) - rc = XaceHookPropertyAccess(client, pWin, &pProp, access_mode); - *result = pProp; - return rc; -} - -static void -deliverPropertyNotifyEvent(WindowPtr pWin, int state, Atom atom) -{ - xEvent event; - - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = PropertyNotify; - event.u.property.window = pWin->drawable.id; - event.u.property.state = state; - event.u.property.atom = atom; - event.u.property.time = currentTime.milliseconds; - DeliverEvents(pWin, &event, 1, (WindowPtr)NULL); -} - -int -ProcRotateProperties(ClientPtr client) -{ - int i, j, delta, rc; - REQUEST(xRotatePropertiesReq); - WindowPtr pWin; - Atom * atoms; - PropertyPtr * props; /* array of pointer */ - PropertyPtr pProp, saved; - - REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2); - UpdateCurrentTime(); - rc = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); - if (rc != Success || stuff->nAtoms <= 0) - return rc; - - atoms = (Atom *) & stuff[1]; - props = xalloc(stuff->nAtoms * sizeof(PropertyPtr)); - saved = xalloc(stuff->nAtoms * sizeof(PropertyRec)); - if (!props || !saved) { - rc = BadAlloc; - goto out; - } - - for (i = 0; i < stuff->nAtoms; i++) - { - if (!ValidAtom(atoms[i])) { - rc = BadAtom; - client->errorValue = atoms[i]; - goto out; - } - for (j = i + 1; j < stuff->nAtoms; j++) - if (atoms[j] == atoms[i]) - { - rc = BadMatch; - goto out; - } - - rc = dixLookupProperty(&pProp, pWin, atoms[i], client, - DixReadAccess|DixWriteAccess); - if (rc != Success) - goto out; - - props[i] = pProp; - saved[i] = *pProp; - } - delta = stuff->nPositions; - - /* If the rotation is a complete 360 degrees, then moving the properties - around and generating PropertyNotify events should be skipped. */ - - if (abs(delta) % stuff->nAtoms) - { - while (delta < 0) /* faster if abs value is small */ - delta += stuff->nAtoms; - for (i = 0; i < stuff->nAtoms; i++) - { - j = (i + delta) % stuff->nAtoms; - deliverPropertyNotifyEvent(pWin, PropertyNewValue, atoms[i]); - - /* Preserve name and devPrivates */ - props[j]->type = saved[i].type; - props[j]->format = saved[i].format; - props[j]->size = saved[i].size; - props[j]->data = saved[i].data; - } - } -out: - xfree(saved); - xfree(props); - return rc; -} - -int -ProcChangeProperty(ClientPtr client) -{ - WindowPtr pWin; - char format, mode; - unsigned long len; - int sizeInBytes, totalSize, err; - REQUEST(xChangePropertyReq); - - REQUEST_AT_LEAST_SIZE(xChangePropertyReq); - UpdateCurrentTime(); - format = stuff->format; - mode = stuff->mode; - if ((mode != PropModeReplace) && (mode != PropModeAppend) && - (mode != PropModePrepend)) - { - client->errorValue = mode; - return BadValue; - } - if ((format != 8) && (format != 16) && (format != 32)) - { - client->errorValue = format; - return BadValue; - } - len = stuff->nUnits; - if (len > bytes_to_int32(0xffffffff - sizeof(xChangePropertyReq))) - return BadLength; - sizeInBytes = format>>3; - totalSize = len * sizeInBytes; - REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize); - - err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); - if (err != Success) - return err; - if (!ValidAtom(stuff->property)) - { - client->errorValue = stuff->property; - return(BadAtom); - } - if (!ValidAtom(stuff->type)) - { - client->errorValue = stuff->type; - return(BadAtom); - } - - err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type, - (int)format, (int)mode, len, &stuff[1], - TRUE); - if (err != Success) - return err; - else - return client->noClientException; -} - -int -dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property, - Atom type, int format, int mode, unsigned long len, - pointer value, Bool sendevent) -{ - PropertyPtr pProp; - PropertyRec savedProp; - int sizeInBytes, totalSize, rc; - unsigned char *data; - Mask access_mode; - - sizeInBytes = format>>3; - totalSize = len * sizeInBytes; - access_mode = (mode == PropModeReplace) ? DixWriteAccess : DixBlendAccess; - - /* first see if property already exists */ - rc = dixLookupProperty(&pProp, pWin, property, pClient, access_mode); - - if (rc == BadMatch) /* just add to list */ - { - if (!pWin->optional && !MakeWindowOptional (pWin)) - return(BadAlloc); - pProp = xalloc(sizeof(PropertyRec)); - if (!pProp) - return(BadAlloc); - data = xalloc(totalSize); - if (!data && len) - { - xfree(pProp); - return(BadAlloc); - } - memcpy(data, value, totalSize); - pProp->propertyName = property; - pProp->type = type; - pProp->format = format; - pProp->data = data; - pProp->size = len; - pProp->devPrivates = NULL; - rc = XaceHookPropertyAccess(pClient, pWin, &pProp, - DixCreateAccess|DixWriteAccess); - if (rc != Success) { - xfree(data); - xfree(pProp); - pClient->errorValue = property; - return rc; - } - pProp->next = pWin->optional->userProps; - pWin->optional->userProps = pProp; - } - else if (rc == Success) - { - /* To append or prepend to a property the request format and type - must match those of the already defined property. The - existing format and type are irrelevant when using the mode - "PropModeReplace" since they will be written over. */ - - if ((format != pProp->format) && (mode != PropModeReplace)) - return(BadMatch); - if ((pProp->type != type) && (mode != PropModeReplace)) - return(BadMatch); - - /* save the old values for later */ - savedProp = *pProp; - - if (mode == PropModeReplace) - { - data = xalloc(totalSize); - if (!data && len) - return(BadAlloc); - memcpy(data, value, totalSize); - pProp->data = data; - pProp->size = len; - pProp->type = type; - pProp->format = format; - } - else if (len == 0) - { - /* do nothing */ - } - else if (mode == PropModeAppend) - { - data = xalloc((pProp->size + len) * sizeInBytes); - if (!data) - return(BadAlloc); - memcpy(data, pProp->data, pProp->size * sizeInBytes); - memcpy(data + pProp->size * sizeInBytes, value, totalSize); - pProp->data = data; - pProp->size += len; - } - else if (mode == PropModePrepend) - { - data = xalloc(sizeInBytes * (len + pProp->size)); - if (!data) - return(BadAlloc); - memcpy(data + totalSize, pProp->data, pProp->size * sizeInBytes); - memcpy(data, value, totalSize); - pProp->data = data; - pProp->size += len; - } - - /* Allow security modules to check the new content */ - access_mode |= DixPostAccess; - rc = XaceHookPropertyAccess(pClient, pWin, &pProp, access_mode); - if (rc == Success) - { - if (savedProp.data != pProp->data) - xfree(savedProp.data); - } - else - { - if (savedProp.data != pProp->data) - xfree(pProp->data); - *pProp = savedProp; - return rc; - } - } - else - return rc; - - if (sendevent) - deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp->propertyName); - - return(Success); -} - -int -ChangeWindowProperty(WindowPtr pWin, Atom property, Atom type, int format, - int mode, unsigned long len, pointer value, - Bool sendevent) -{ - return dixChangeWindowProperty(serverClient, pWin, property, type, format, - mode, len, value, sendevent); -} - -int -DeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName) -{ - PropertyPtr pProp, prevProp; - int rc; - - rc = dixLookupProperty(&pProp, pWin, propName, client, DixDestroyAccess); - if (rc == BadMatch) - return Success; /* Succeed if property does not exist */ - - if (rc == Success) { - if (pWin->optional->userProps == pProp) { - /* Takes care of head */ - if (!(pWin->optional->userProps = pProp->next)) - CheckWindowOptionalNeed (pWin); - } else { - /* Need to traverse to find the previous element */ - prevProp = pWin->optional->userProps; - while (prevProp->next != pProp) - prevProp = prevProp->next; - prevProp->next = pProp->next; - } - - deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName); - dixFreePrivates(pProp->devPrivates); - xfree(pProp->data); - xfree(pProp); - } - return rc; -} - -void -DeleteAllWindowProperties(WindowPtr pWin) -{ - PropertyPtr pProp, pNextProp; - - pProp = wUserProps (pWin); - while (pProp) - { - deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName); - pNextProp = pProp->next; - dixFreePrivates(pProp->devPrivates); - xfree(pProp->data); - xfree(pProp); - pProp = pNextProp; - } -} - -static int -NullPropertyReply( - ClientPtr client, - ATOM propertyType, - int format, - xGetPropertyReply *reply) -{ - reply->nItems = 0; - reply->length = 0; - reply->bytesAfter = 0; - reply->propertyType = propertyType; - reply->format = format; - WriteReplyToClient(client, sizeof(xGenericReply), reply); - return(client->noClientException); -} - -/***************** - * GetProperty - * If type Any is specified, returns the property from the specified - * window regardless of its type. If a type is specified, returns the - * property only if its type equals the specified type. - * If delete is True and a property is returned, the property is also - * deleted from the window and a PropertyNotify event is generated on the - * window. - *****************/ - -int -ProcGetProperty(ClientPtr client) -{ - PropertyPtr pProp, prevProp; - unsigned long n, len, ind; - int rc; - WindowPtr pWin; - xGetPropertyReply reply; - Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess; - REQUEST(xGetPropertyReq); - - REQUEST_SIZE_MATCH(xGetPropertyReq); - if (stuff->delete) { - UpdateCurrentTime(); - win_mode |= DixSetPropAccess; - prop_mode |= DixDestroyAccess; - } - rc = dixLookupWindow(&pWin, stuff->window, client, win_mode); - if (rc != Success) - return (rc == BadMatch) ? BadWindow : rc; - - if (!ValidAtom(stuff->property)) - { - client->errorValue = stuff->property; - return(BadAtom); - } - if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) - { - client->errorValue = stuff->delete; - return(BadValue); - } - if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) - { - client->errorValue = stuff->type; - return(BadAtom); - } - - memset(&reply, 0, sizeof(xGetPropertyReply)); - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode); - if (rc == BadMatch) - return NullPropertyReply(client, None, 0, &reply); - else if (rc != Success) - return rc; - - /* If the request type and actual type don't match. Return the - property information, but not the data. */ - - if (((stuff->type != pProp->type) && - (stuff->type != AnyPropertyType)) - ) - { - reply.bytesAfter = pProp->size; - reply.format = pProp->format; - reply.length = 0; - reply.nItems = 0; - reply.propertyType = pProp->type; - WriteReplyToClient(client, sizeof(xGenericReply), &reply); - return(Success); - } - -/* - * Return type, format, value to client - */ - n = (pProp->format/8) * pProp->size; /* size (bytes) of prop */ - ind = stuff->longOffset << 2; - - /* If longOffset is invalid such that it causes "len" to - be negative, it's a value error. */ - - if (n < ind) - { - client->errorValue = stuff->longOffset; - return BadValue; - } - - len = min(n - ind, 4 * stuff->longLength); - - reply.bytesAfter = n - (ind + len); - reply.format = pProp->format; - reply.length = bytes_to_int32(len); - reply.nItems = len / (pProp->format / 8 ); - reply.propertyType = pProp->type; - - if (stuff->delete && (reply.bytesAfter == 0)) - deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName); - - WriteReplyToClient(client, sizeof(xGenericReply), &reply); - if (len) - { - switch (reply.format) { - case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break; - case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break; - default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break; - } - WriteSwappedDataToClient(client, len, - (char *)pProp->data + ind); - } - - if (stuff->delete && (reply.bytesAfter == 0)) { - /* Delete the Property */ - if (pWin->optional->userProps == pProp) { - /* Takes care of head */ - if (!(pWin->optional->userProps = pProp->next)) - CheckWindowOptionalNeed (pWin); - } else { - /* Need to traverse to find the previous element */ - prevProp = pWin->optional->userProps; - while (prevProp->next != pProp) - prevProp = prevProp->next; - prevProp->next = pProp->next; - } - - dixFreePrivates(pProp->devPrivates); - xfree(pProp->data); - xfree(pProp); - } - return(client->noClientException); -} - -int -ProcListProperties(ClientPtr client) -{ - Atom *pAtoms = NULL, *temppAtoms; - xListPropertiesReply xlpr; - int rc, numProps = 0; - WindowPtr pWin; - PropertyPtr pProp, realProp; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess); - if (rc != Success) - return rc; - - for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) - numProps++; - - if (numProps && !(pAtoms = xalloc(numProps * sizeof(Atom)))) - return BadAlloc; - - numProps = 0; - temppAtoms = pAtoms; - for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) { - realProp = pProp; - rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess); - if (rc == Success && realProp == pProp) { - *temppAtoms++ = pProp->propertyName; - numProps++; - } - } - - xlpr.type = X_Reply; - xlpr.nProperties = numProps; - xlpr.length = bytes_to_int32(numProps * sizeof(Atom)); - xlpr.sequenceNumber = client->sequence; - WriteReplyToClient(client, sizeof(xGenericReply), &xlpr); - if (numProps) - { - client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; - WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); - } - xfree(pAtoms); - return(client->noClientException); -} - -int -ProcDeleteProperty(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xDeletePropertyReq); - int result; - - REQUEST_SIZE_MATCH(xDeletePropertyReq); - UpdateCurrentTime(); - result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); - if (result != Success) - return result; - if (!ValidAtom(stuff->property)) - { - client->errorValue = stuff->property; - return (BadAtom); - } - - result = DeleteProperty(client, pWin, stuff->property); - if (client->noClientException != Success) - return(client->noClientException); - else - return(result); -} +/*********************************************************** + +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 "windowstr.h" +#include "propertyst.h" +#include "dixstruct.h" +#include "dispatch.h" +#include "swaprep.h" +#include "xace.h" + +/***************************************************************** + * Property Stuff + * + * dixLookupProperty, dixChangeProperty, DeleteProperty + * + * Properties belong to windows. The list of properties should not be + * traversed directly. Instead, use the three functions listed above. + * + *****************************************************************/ + +#ifdef notdef +static void +PrintPropertys(WindowPtr pWin) +{ + PropertyPtr pProp; + int j; + + pProp = pWin->userProps; + while (pProp) + { + ErrorF("[dix] %x %x\n", pProp->propertyName, pProp->type); + ErrorF("[dix] property format: %d\n", pProp->format); + ErrorF("[dix] property data: \n"); + for (j=0; j<(pProp->format/8)*pProp->size; j++) + ErrorF("[dix] %c\n", pProp->data[j]); + pProp = pProp->next; + } +} +#endif + +int +dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName, + ClientPtr client, Mask access_mode) +{ + PropertyPtr pProp; + int rc = BadMatch; + client->errorValue = propertyName; + + for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) + if (pProp->propertyName == propertyName) + break; + + if (pProp) + rc = XaceHookPropertyAccess(client, pWin, &pProp, access_mode); + *result = pProp; + return rc; +} + +static void +deliverPropertyNotifyEvent(WindowPtr pWin, int state, Atom atom) +{ + xEvent event; + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = PropertyNotify; + event.u.property.window = pWin->drawable.id; + event.u.property.state = state; + event.u.property.atom = atom; + event.u.property.time = currentTime.milliseconds; + DeliverEvents(pWin, &event, 1, (WindowPtr)NULL); +} + +int +ProcRotateProperties(ClientPtr client) +{ + int i, j, delta, rc; + REQUEST(xRotatePropertiesReq); + WindowPtr pWin; + Atom * atoms; + PropertyPtr * props; /* array of pointer */ + PropertyPtr pProp, saved; + + REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2); + UpdateCurrentTime(); + rc = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); + if (rc != Success || stuff->nAtoms <= 0) + return rc; + + atoms = (Atom *) & stuff[1]; + props = malloc(stuff->nAtoms * sizeof(PropertyPtr)); + saved = malloc(stuff->nAtoms * sizeof(PropertyRec)); + if (!props || !saved) { + rc = BadAlloc; + goto out; + } + + for (i = 0; i < stuff->nAtoms; i++) + { + if (!ValidAtom(atoms[i])) { + rc = BadAtom; + client->errorValue = atoms[i]; + goto out; + } + for (j = i + 1; j < stuff->nAtoms; j++) + if (atoms[j] == atoms[i]) + { + rc = BadMatch; + goto out; + } + + rc = dixLookupProperty(&pProp, pWin, atoms[i], client, + DixReadAccess|DixWriteAccess); + if (rc != Success) + goto out; + + props[i] = pProp; + saved[i] = *pProp; + } + delta = stuff->nPositions; + + /* If the rotation is a complete 360 degrees, then moving the properties + around and generating PropertyNotify events should be skipped. */ + + if (abs(delta) % stuff->nAtoms) + { + while (delta < 0) /* faster if abs value is small */ + delta += stuff->nAtoms; + for (i = 0; i < stuff->nAtoms; i++) + { + j = (i + delta) % stuff->nAtoms; + deliverPropertyNotifyEvent(pWin, PropertyNewValue, atoms[i]); + + /* Preserve name and devPrivates */ + props[j]->type = saved[i].type; + props[j]->format = saved[i].format; + props[j]->size = saved[i].size; + props[j]->data = saved[i].data; + } + } +out: + free(saved); + free(props); + return rc; +} + +int +ProcChangeProperty(ClientPtr client) +{ + WindowPtr pWin; + char format, mode; + unsigned long len; + int sizeInBytes, totalSize, err; + REQUEST(xChangePropertyReq); + + REQUEST_AT_LEAST_SIZE(xChangePropertyReq); + UpdateCurrentTime(); + format = stuff->format; + mode = stuff->mode; + if ((mode != PropModeReplace) && (mode != PropModeAppend) && + (mode != PropModePrepend)) + { + client->errorValue = mode; + return BadValue; + } + if ((format != 8) && (format != 16) && (format != 32)) + { + client->errorValue = format; + return BadValue; + } + len = stuff->nUnits; + if (len > bytes_to_int32(0xffffffff - sizeof(xChangePropertyReq))) + return BadLength; + sizeInBytes = format>>3; + totalSize = len * sizeInBytes; + REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize); + + err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); + if (err != Success) + return err; + if (!ValidAtom(stuff->property)) + { + client->errorValue = stuff->property; + return(BadAtom); + } + if (!ValidAtom(stuff->type)) + { + client->errorValue = stuff->type; + return(BadAtom); + } + + err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type, + (int)format, (int)mode, len, &stuff[1], + TRUE); + if (err != Success) + return err; + else + return Success; +} + +int +dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property, + Atom type, int format, int mode, unsigned long len, + pointer value, Bool sendevent) +{ + PropertyPtr pProp; + PropertyRec savedProp; + int sizeInBytes, totalSize, rc; + unsigned char *data; + Mask access_mode; + + sizeInBytes = format>>3; + totalSize = len * sizeInBytes; + access_mode = (mode == PropModeReplace) ? DixWriteAccess : DixBlendAccess; + + /* first see if property already exists */ + rc = dixLookupProperty(&pProp, pWin, property, pClient, access_mode); + + if (rc == BadMatch) /* just add to list */ + { + if (!pWin->optional && !MakeWindowOptional (pWin)) + return(BadAlloc); + pProp = malloc(sizeof(PropertyRec)); + if (!pProp) + return(BadAlloc); + data = malloc(totalSize); + if (!data && len) + { + free(pProp); + return(BadAlloc); + } + memcpy(data, value, totalSize); + pProp->propertyName = property; + pProp->type = type; + pProp->format = format; + pProp->data = data; + pProp->size = len; + pProp->devPrivates = NULL; + rc = XaceHookPropertyAccess(pClient, pWin, &pProp, + DixCreateAccess|DixWriteAccess); + if (rc != Success) { + free(data); + free(pProp); + pClient->errorValue = property; + return rc; + } + pProp->next = pWin->optional->userProps; + pWin->optional->userProps = pProp; + } + else if (rc == Success) + { + /* To append or prepend to a property the request format and type + must match those of the already defined property. The + existing format and type are irrelevant when using the mode + "PropModeReplace" since they will be written over. */ + + if ((format != pProp->format) && (mode != PropModeReplace)) + return(BadMatch); + if ((pProp->type != type) && (mode != PropModeReplace)) + return(BadMatch); + + /* save the old values for later */ + savedProp = *pProp; + + if (mode == PropModeReplace) + { + data = malloc(totalSize); + if (!data && len) + return(BadAlloc); + memcpy(data, value, totalSize); + pProp->data = data; + pProp->size = len; + pProp->type = type; + pProp->format = format; + } + else if (len == 0) + { + /* do nothing */ + } + else if (mode == PropModeAppend) + { + data = malloc((pProp->size + len) * sizeInBytes); + if (!data) + return(BadAlloc); + memcpy(data, pProp->data, pProp->size * sizeInBytes); + memcpy(data + pProp->size * sizeInBytes, value, totalSize); + pProp->data = data; + pProp->size += len; + } + else if (mode == PropModePrepend) + { + data = malloc(sizeInBytes * (len + pProp->size)); + if (!data) + return(BadAlloc); + memcpy(data + totalSize, pProp->data, pProp->size * sizeInBytes); + memcpy(data, value, totalSize); + pProp->data = data; + pProp->size += len; + } + + /* Allow security modules to check the new content */ + access_mode |= DixPostAccess; + rc = XaceHookPropertyAccess(pClient, pWin, &pProp, access_mode); + if (rc == Success) + { + if (savedProp.data != pProp->data) + free(savedProp.data); + } + else + { + if (savedProp.data != pProp->data) + free(pProp->data); + *pProp = savedProp; + return rc; + } + } + else + return rc; + + if (sendevent) + deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp->propertyName); + + return(Success); +} + +int +ChangeWindowProperty(WindowPtr pWin, Atom property, Atom type, int format, + int mode, unsigned long len, pointer value, + Bool sendevent) +{ + return dixChangeWindowProperty(serverClient, pWin, property, type, format, + mode, len, value, sendevent); +} + +int +DeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName) +{ + PropertyPtr pProp, prevProp; + int rc; + + rc = dixLookupProperty(&pProp, pWin, propName, client, DixDestroyAccess); + if (rc == BadMatch) + return Success; /* Succeed if property does not exist */ + + if (rc == Success) { + if (pWin->optional->userProps == pProp) { + /* Takes care of head */ + if (!(pWin->optional->userProps = pProp->next)) + CheckWindowOptionalNeed (pWin); + } else { + /* Need to traverse to find the previous element */ + prevProp = pWin->optional->userProps; + while (prevProp->next != pProp) + prevProp = prevProp->next; + prevProp->next = pProp->next; + } + + deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName); + dixFreePrivates(pProp->devPrivates); + free(pProp->data); + free(pProp); + } + return rc; +} + +void +DeleteAllWindowProperties(WindowPtr pWin) +{ + PropertyPtr pProp, pNextProp; + + pProp = wUserProps (pWin); + while (pProp) + { + deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName); + pNextProp = pProp->next; + dixFreePrivates(pProp->devPrivates); + free(pProp->data); + free(pProp); + pProp = pNextProp; + } +} + +static int +NullPropertyReply( + ClientPtr client, + ATOM propertyType, + int format, + xGetPropertyReply *reply) +{ + reply->nItems = 0; + reply->length = 0; + reply->bytesAfter = 0; + reply->propertyType = propertyType; + reply->format = format; + WriteReplyToClient(client, sizeof(xGenericReply), reply); + return Success; +} + +/***************** + * GetProperty + * If type Any is specified, returns the property from the specified + * window regardless of its type. If a type is specified, returns the + * property only if its type equals the specified type. + * If delete is True and a property is returned, the property is also + * deleted from the window and a PropertyNotify event is generated on the + * window. + *****************/ + +int +ProcGetProperty(ClientPtr client) +{ + PropertyPtr pProp, prevProp; + unsigned long n, len, ind; + int rc; + WindowPtr pWin; + xGetPropertyReply reply; + Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess; + REQUEST(xGetPropertyReq); + + REQUEST_SIZE_MATCH(xGetPropertyReq); + if (stuff->delete) { + UpdateCurrentTime(); + win_mode |= DixSetPropAccess; + prop_mode |= DixDestroyAccess; + } + rc = dixLookupWindow(&pWin, stuff->window, client, win_mode); + if (rc != Success) + return (rc == BadMatch) ? BadWindow : rc; + + if (!ValidAtom(stuff->property)) + { + client->errorValue = stuff->property; + return(BadAtom); + } + if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) + { + client->errorValue = stuff->delete; + return(BadValue); + } + if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) + { + client->errorValue = stuff->type; + return(BadAtom); + } + + memset(&reply, 0, sizeof(xGetPropertyReply)); + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode); + if (rc == BadMatch) + return NullPropertyReply(client, None, 0, &reply); + else if (rc != Success) + return rc; + + /* If the request type and actual type don't match. Return the + property information, but not the data. */ + + if (((stuff->type != pProp->type) && + (stuff->type != AnyPropertyType)) + ) + { + reply.bytesAfter = pProp->size; + reply.format = pProp->format; + reply.length = 0; + reply.nItems = 0; + reply.propertyType = pProp->type; + WriteReplyToClient(client, sizeof(xGenericReply), &reply); + return(Success); + } + +/* + * Return type, format, value to client + */ + n = (pProp->format/8) * pProp->size; /* size (bytes) of prop */ + ind = stuff->longOffset << 2; + + /* If longOffset is invalid such that it causes "len" to + be negative, it's a value error. */ + + if (n < ind) + { + client->errorValue = stuff->longOffset; + return BadValue; + } + + len = min(n - ind, 4 * stuff->longLength); + + reply.bytesAfter = n - (ind + len); + reply.format = pProp->format; + reply.length = bytes_to_int32(len); + reply.nItems = len / (pProp->format / 8 ); + reply.propertyType = pProp->type; + + if (stuff->delete && (reply.bytesAfter == 0)) + deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName); + + WriteReplyToClient(client, sizeof(xGenericReply), &reply); + if (len) + { + switch (reply.format) { + case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break; + case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break; + default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break; + } + WriteSwappedDataToClient(client, len, + (char *)pProp->data + ind); + } + + if (stuff->delete && (reply.bytesAfter == 0)) { + /* Delete the Property */ + if (pWin->optional->userProps == pProp) { + /* Takes care of head */ + if (!(pWin->optional->userProps = pProp->next)) + CheckWindowOptionalNeed (pWin); + } else { + /* Need to traverse to find the previous element */ + prevProp = pWin->optional->userProps; + while (prevProp->next != pProp) + prevProp = prevProp->next; + prevProp->next = pProp->next; + } + + dixFreePrivates(pProp->devPrivates); + free(pProp->data); + free(pProp); + } + return Success; +} + +int +ProcListProperties(ClientPtr client) +{ + Atom *pAtoms = NULL, *temppAtoms; + xListPropertiesReply xlpr; + int rc, numProps = 0; + WindowPtr pWin; + PropertyPtr pProp, realProp; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess); + if (rc != Success) + return rc; + + for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) + numProps++; + + if (numProps && !(pAtoms = malloc(numProps * sizeof(Atom)))) + return BadAlloc; + + numProps = 0; + temppAtoms = pAtoms; + for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) { + realProp = pProp; + rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess); + if (rc == Success && realProp == pProp) { + *temppAtoms++ = pProp->propertyName; + numProps++; + } + } + + xlpr.type = X_Reply; + xlpr.nProperties = numProps; + xlpr.length = bytes_to_int32(numProps * sizeof(Atom)); + xlpr.sequenceNumber = client->sequence; + WriteReplyToClient(client, sizeof(xGenericReply), &xlpr); + if (numProps) + { + client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; + WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); + } + free(pAtoms); + return Success; +} + +int +ProcDeleteProperty(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xDeletePropertyReq); + int result; + + REQUEST_SIZE_MATCH(xDeletePropertyReq); + UpdateCurrentTime(); + result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); + if (result != Success) + return result; + if (!ValidAtom(stuff->property)) + { + client->errorValue = stuff->property; + return (BadAtom); + } + + return DeleteProperty(client, pWin, stuff->property); +} diff --git a/xorg-server/dix/ptrveloc.c b/xorg-server/dix/ptrveloc.c index 100d6f8be..37dd0548c 100644 --- a/xorg-server/dix/ptrveloc.c +++ b/xorg-server/dix/ptrveloc.c @@ -1,1177 +1,1177 @@ -/* - * - * Copyright © 2006-2009 Simon Thum simon dot thum at gmx dot de - * - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -/***************************************************************************** - * Predictable pointer acceleration - * - * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de) - * - * Serves 3 complementary functions: - * 1) provide a sophisticated ballistic velocity estimate to improve - * the relation between velocity (of the device) and acceleration - * 2) make arbitrary acceleration profiles possible - * 3) decelerate by two means (constant and adaptive) if enabled - * - * Important concepts are the - * - * - Scheme - * which selects the basic algorithm - * (see devices.c/InitPointerAccelerationScheme) - * - Profile - * which returns an acceleration - * for a given velocity - * - * The profile can be selected by the user at runtime. - * The classic profile is intended to cleanly perform old-style - * function selection (threshold =/!= 0) - * - ****************************************************************************/ - -/* fwds */ -int -SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); -static float -SimpleSmoothProfile(DeviceIntPtr dev, DeviceVelocityPtr vel, float velocity, - float threshold, float acc); -static PointerAccelerationProfileFunc -GetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); - -/*#define PTRACCEL_DEBUGGING*/ - -#ifdef PTRACCEL_DEBUGGING -#define DebugAccelF ErrorF -#else -#define DebugAccelF(...) /* */ -#endif - -/******************************** - * Init/Uninit - *******************************/ - -/* some int which is not a profile number */ -#define PROFILE_UNINITIALIZE (-100) - - -/** - * Init struct so it should match the average case - */ -void -InitVelocityData(DeviceVelocityPtr vel) -{ - memset(vel, 0, sizeof(DeviceVelocityRec)); - - vel->corr_mul = 10.0; /* dots per 10 milisecond should be usable */ - vel->const_acceleration = 1.0; /* no acceleration/deceleration */ - vel->reset_time = 300; - vel->use_softening = 1; - vel->min_acceleration = 1.0; /* don't decelerate */ - vel->max_rel_diff = 0.2; - vel->max_diff = 1.0; - vel->initial_range = 2; - vel->average_accel = TRUE; - SetAccelerationProfile(vel, AccelProfileClassic); - InitTrackers(vel, 16); -} - - -/** - * Clean up - */ -void -FreeVelocityData(DeviceVelocityPtr vel){ - xfree(vel->tracker); - SetAccelerationProfile(vel, PROFILE_UNINITIALIZE); -} - - -/* - * dix uninit helper, called through scheme - */ -void -AccelerationDefaultCleanup(DeviceIntPtr dev) -{ - /*sanity check*/ - if( dev->valuator->accelScheme.AccelSchemeProc == acceleratePointerPredictable - && dev->valuator->accelScheme.accelData != NULL){ - dev->valuator->accelScheme.AccelSchemeProc = NULL; - FreeVelocityData(dev->valuator->accelScheme.accelData); - xfree(dev->valuator->accelScheme.accelData); - dev->valuator->accelScheme.accelData = NULL; - DeletePredictableAccelerationProperties(dev); - } -} - - -/************************* - * Input property support - ************************/ - -/** - * choose profile - */ -static int -AccelSetProfileProperty(DeviceIntPtr dev, Atom atom, - XIPropertyValuePtr val, BOOL checkOnly) -{ - DeviceVelocityPtr vel; - int profile, *ptr = &profile; - int rc; - int nelem = 1; - - if (atom != XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER)) - return Success; - - vel = GetDevicePredictableAccelData(dev); - if (!vel) - return BadValue; - rc = XIPropToInt(val, &nelem, &ptr); - - if(checkOnly) - { - if (rc) - return rc; - - if (GetAccelerationProfile(vel, profile) == NULL) - return BadValue; - } else - SetAccelerationProfile(vel, profile); - - return Success; -} - -static long -AccelInitProfileProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) -{ - int profile = vel->statistics.profile_number; - Atom prop_profile_number = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); - - XIChangeDeviceProperty(dev, prop_profile_number, XA_INTEGER, 32, - PropModeReplace, 1, &profile, FALSE); - XISetDevicePropertyDeletable(dev, prop_profile_number, FALSE); - return XIRegisterPropertyHandler(dev, AccelSetProfileProperty, NULL, NULL); -} - -/** - * constant deceleration - */ -static int -AccelSetDecelProperty(DeviceIntPtr dev, Atom atom, - XIPropertyValuePtr val, BOOL checkOnly) -{ - DeviceVelocityPtr vel; - float v, *ptr = &v; - int rc; - int nelem = 1; - - if (atom != XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION)) - return Success; - - vel = GetDevicePredictableAccelData(dev); - if (!vel) - return BadValue; - rc = XIPropToFloat(val, &nelem, &ptr); - - if(checkOnly) - { - if (rc) - return rc; - return (v >= 1.0f) ? Success : BadValue; - } - - if(v >= 1.0f) - vel->const_acceleration = 1/v; - - return Success; -} - -static long -AccelInitDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) -{ - float fval = 1.0/vel->const_acceleration; - Atom prop_const_decel = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); - XIChangeDeviceProperty(dev, prop_const_decel, - XIGetKnownProperty(XATOM_FLOAT), 32, - PropModeReplace, 1, &fval, FALSE); - XISetDevicePropertyDeletable(dev, prop_const_decel, FALSE); - return XIRegisterPropertyHandler(dev, AccelSetDecelProperty, NULL, NULL); -} - - -/** - * adaptive deceleration - */ -static int -AccelSetAdaptDecelProperty(DeviceIntPtr dev, Atom atom, - XIPropertyValuePtr val, BOOL checkOnly) -{ - DeviceVelocityPtr veloc; - float v, *ptr = &v; - int rc; - int nelem = 1; - - if (atom != XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION)) - return Success; - - veloc = GetDevicePredictableAccelData(dev); - if (!veloc) - return BadValue; - rc = XIPropToFloat(val, &nelem, &ptr); - - if(checkOnly) - { - if (rc) - return rc; - return (v >= 1.0f) ? Success : BadValue; - } - - if(v >= 1.0f) - veloc->min_acceleration = 1/v; - - return Success; -} - -static long -AccelInitAdaptDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) -{ - float fval = 1.0/vel->min_acceleration; - Atom prop_adapt_decel = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); - - XIChangeDeviceProperty(dev, prop_adapt_decel, XIGetKnownProperty(XATOM_FLOAT), 32, - PropModeReplace, 1, &fval, FALSE); - XISetDevicePropertyDeletable(dev, prop_adapt_decel, FALSE); - return XIRegisterPropertyHandler(dev, AccelSetAdaptDecelProperty, NULL, NULL); -} - - -/** - * velocity scaling - */ -static int -AccelSetScaleProperty(DeviceIntPtr dev, Atom atom, - XIPropertyValuePtr val, BOOL checkOnly) -{ - DeviceVelocityPtr vel; - float v, *ptr = &v; - int rc; - int nelem = 1; - - if (atom != XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING)) - return Success; - - vel = GetDevicePredictableAccelData(dev); - if (!vel) - return BadValue; - rc = XIPropToFloat(val, &nelem, &ptr); - - if (checkOnly) - { - if (rc) - return rc; - - return (v > 0) ? Success : BadValue; - } - - if(v > 0) - vel->corr_mul = v; - - return Success; -} - -static long -AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) -{ - float fval = vel->corr_mul; - Atom prop_velo_scale = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); - - XIChangeDeviceProperty(dev, prop_velo_scale, XIGetKnownProperty(XATOM_FLOAT), 32, - PropModeReplace, 1, &fval, FALSE); - XISetDevicePropertyDeletable(dev, prop_velo_scale, FALSE); - return XIRegisterPropertyHandler(dev, AccelSetScaleProperty, NULL, NULL); -} - -BOOL -InitializePredictableAccelerationProperties(DeviceIntPtr dev) -{ - DeviceVelocityPtr vel = GetDevicePredictableAccelData(dev); - - if(!vel) - return FALSE; - - vel->prop_handlers[0] = AccelInitProfileProperty(dev, vel); - vel->prop_handlers[1] = AccelInitDecelProperty(dev, vel); - vel->prop_handlers[2] = AccelInitAdaptDecelProperty(dev, vel); - vel->prop_handlers[3] = AccelInitScaleProperty(dev, vel); - - return TRUE; -} - -BOOL -DeletePredictableAccelerationProperties(DeviceIntPtr dev) -{ - DeviceVelocityPtr vel; - Atom prop; - int i; - - prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); - XIDeleteDeviceProperty(dev, prop, FALSE); - prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); - XIDeleteDeviceProperty(dev, prop, FALSE); - prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); - XIDeleteDeviceProperty(dev, prop, FALSE); - prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); - XIDeleteDeviceProperty(dev, prop, FALSE); - - vel = GetDevicePredictableAccelData(dev); - for (i = 0; vel && i < NPROPS_PREDICTABLE_ACCEL; i++) - if (vel->prop_handlers[i]) - XIUnregisterPropertyHandler(dev, vel->prop_handlers[i]); - - return TRUE; -} - -/********************* - * Tracking logic - ********************/ - -void -InitTrackers(DeviceVelocityPtr vel, int ntracker) -{ - if(ntracker < 1){ - ErrorF("(dix ptracc) invalid number of trackers\n"); - return; - } - xfree(vel->tracker); - vel->tracker = (MotionTrackerPtr)xalloc(ntracker * sizeof(MotionTracker)); - memset(vel->tracker, 0, ntracker * sizeof(MotionTracker)); - vel->num_tracker = ntracker; -} - -/** - * return a bit field of possible directions. - * 0 = N, 2 = E, 4 = S, 6 = W, in-between is as you guess. - * There's no reason against widening to more precise directions (<45 degrees), - * should it not perform well. All this is needed for is sort out non-linear - * motion, so precision isn't paramount. However, one should not flag direction - * too narrow, since it would then cut the linear segment to zero size way too - * often. - */ -static int -DoGetDirection(int dx, int dy){ - float r; - int i1, i2; - /* on insignificant mickeys, flag 135 degrees */ - if(abs(dx) < 2 && abs(dy < 2)){ - /* first check diagonal cases */ - if(dx > 0 && dy > 0) - return 4+8+16; - if(dx > 0 && dy < 0) - return 1+2+4; - if(dx < 0 && dy < 0) - return 1+128+64; - if(dx < 0 && dy > 0) - return 16+32+64; - /* check axis-aligned directions */ - if(dx > 0) - return 2+4+8; /*E*/ - if(dx < 0) - return 128+64+32; /*W*/ - if(dy > 0) - return 32+16+8; /*S*/ - if(dy < 0) - return 128+1+2; /*N*/ - return 255; /* shouldn't happen */ - } - /* else, compute angle and set appropriate flags */ -#ifdef _ISOC99_SOURCE - r = atan2f(dy, dx); -#else - r = atan2(dy, dx); -#endif - /* find direction. We avoid r to become negative, - * since C has no well-defined modulo for such cases. */ - r = (r+(M_PI*2.5))/(M_PI/4); - /* this intends to flag 2 directions (90 degrees), - * except on very well-aligned mickeys. */ - i1 = (int)(r+0.1) % 8; - i2 = (int)(r+0.9) % 8; - if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7) - return 255; /* shouldn't happen */ - return 1 << i1 | 1 << i2; -} - -#define DIRECTION_CACHE_RANGE 5 -#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1) - -/* cache DoGetDirection(). */ -static int -GetDirection(int dx, int dy){ - static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE]; - int i; - if (abs(dx) <= DIRECTION_CACHE_RANGE && - abs(dy) <= DIRECTION_CACHE_RANGE) { - /* cacheable */ - i = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy]; - if(i != 0){ - return i; - }else{ - i = DoGetDirection(dx, dy); - cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = i; - return i; - } - }else{ - /* non-cacheable */ - return DoGetDirection(dx, dy); - } -} - -#undef DIRECTION_CACHE_RANGE -#undef DIRECTION_CACHE_SIZE - - -/* convert offset (age) to array index */ -#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker) - -static inline void -FeedTrackers(DeviceVelocityPtr vel, int dx, int dy, int cur_t) -{ - int n; - for(n = 0; n < vel->num_tracker; n++){ - vel->tracker[n].dx += dx; - vel->tracker[n].dy += dy; - } - n = (vel->cur_tracker + 1) % vel->num_tracker; - vel->tracker[n].dx = 0; - vel->tracker[n].dy = 0; - vel->tracker[n].time = cur_t; - vel->tracker[n].dir = GetDirection(dx, dy); - DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n", - dx, dy, vel->tracker[n].dir, - cur_t - vel->tracker[vel->cur_tracker].time); - vel->cur_tracker = n; -} - -/** - * calc velocity for given tracker, with - * velocity scaling. - * This assumes linear motion. - */ -static float -CalcTracker(DeviceVelocityPtr vel, int offset, int cur_t){ - int index = TRACKER_INDEX(vel, offset); - float dist = sqrt( vel->tracker[index].dx * vel->tracker[index].dx - + vel->tracker[index].dy * vel->tracker[index].dy); - int dtime = cur_t - vel->tracker[index].time; - if(dtime > 0) - return (dist / dtime); - else - return 0;/* synonymous for NaN, since we're not C99 */ -} - -/* find the most plausible velocity. That is, the most distant - * (in time) tracker which isn't too old, beyond a linear partition, - * or simply too much off initial velocity. - * - * May return 0. - */ -static float -QueryTrackers(DeviceVelocityPtr vel, int cur_t){ - int n, offset, dir = 255, i = -1, age_ms; - /* initial velocity: a low-offset, valid velocity */ - float iveloc = 0, res = 0, tmp, vdiff; - float vfac = vel->corr_mul * vel->const_acceleration; /* premultiply */ - /* loop from current to older data */ - for(offset = 1; offset < vel->num_tracker; offset++){ - n = TRACKER_INDEX(vel, offset); - - age_ms = cur_t - vel->tracker[n].time; - - /* bail out if data is too old and protect from overrun */ - if (age_ms >= vel->reset_time || age_ms < 0) { - DebugAccelF("(dix prtacc) query: tracker too old\n"); - break; - } - - /* - * this heuristic avoids using the linear-motion velocity formula - * in CalcTracker() on motion that isn't exactly linear. So to get - * even more precision we could subdivide as a final step, so possible - * non-linearities are accounted for. - */ - dir &= vel->tracker[n].dir; - if(dir == 0){ - DebugAccelF("(dix prtacc) query: no longer linear\n"); - /* instead of breaking it we might also inspect the partition after, - * but actual improvement with this is probably rare. */ - break; - } - - tmp = CalcTracker(vel, offset, cur_t) * vfac; - - if ((iveloc == 0 || offset <= vel->initial_range) && tmp != 0) { - /* set initial velocity and result */ - res = iveloc = tmp; - i = offset; - } else if (iveloc != 0 && tmp != 0) { - vdiff = fabs(iveloc - tmp); - if (vdiff <= vel->max_diff || - vdiff/(iveloc + tmp) < vel->max_rel_diff) { - /* we're in range with the initial velocity, - * so this result is likely better - * (it contains more information). */ - res = tmp; - i = offset; - }else{ - /* we're not in range, quit - it won't get better. */ - DebugAccelF("(dix prtacc) query: tracker too different:" - " old %2.2f initial %2.2f diff: %2.2f\n", - tmp, iveloc, vdiff); - break; - } - } - } - if(offset == vel->num_tracker){ - DebugAccelF("(dix prtacc) query: last tracker in effect\n"); - i = vel->num_tracker-1; - } - if(i>=0){ - n = TRACKER_INDEX(vel, i); - DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n", - i, - vel->tracker[n].dx, - vel->tracker[n].dy, - cur_t - vel->tracker[n].time); - } - return res; -} - -#undef TRACKER_INDEX - -/** - * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta). - * return true if non-visible state reset is suggested - */ -short -ProcessVelocityData2D( - DeviceVelocityPtr vel, - int dx, - int dy, - int time) -{ - float velocity; - - vel->last_velocity = vel->velocity; - - FeedTrackers(vel, dx, dy, time); - - velocity = QueryTrackers(vel, time); - - vel->velocity = velocity; - return velocity == 0; -} - -/** - * this flattens significant ( > 1) mickeys a little bit for more steady - * constant-velocity response - */ -static inline float -ApplySimpleSoftening(int od, int d) -{ - float res = d; - if (d <= 1 && d >= -1) - return res; - if (d > od) - res -= 0.5; - else if (d < od) - res += 0.5; - return res; -} - - -static void -ApplySofteningAndConstantDeceleration( - DeviceVelocityPtr vel, - int dx, - int dy, - float* fdx, - float* fdy, - short do_soften) -{ - if (do_soften && vel->use_softening) { - *fdx = ApplySimpleSoftening(vel->last_dx, dx); - *fdy = ApplySimpleSoftening(vel->last_dy, dy); - } else { - *fdx = dx; - *fdy = dy; - } - - *fdx *= vel->const_acceleration; - *fdy *= vel->const_acceleration; -} - -/* - * compute the acceleration for given velocity and enforce min_acceleartion - */ -float -BasicComputeAcceleration( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc){ - - float result; - result = vel->Profile(dev, vel, velocity, threshold, acc); - - /* enforce min_acceleration */ - if (result < vel->min_acceleration) - result = vel->min_acceleration; - return result; -} - -/** - * Compute acceleration. Takes into account averaging, nv-reset, etc. - */ -static float -ComputeAcceleration( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float threshold, - float acc){ - float res; - - if(vel->velocity <= 0){ - DebugAccelF("(dix ptracc) profile skipped\n"); - /* - * If we have no idea about device velocity, don't pretend it. - */ - return 1; - } - - if(vel->average_accel && vel->velocity != vel->last_velocity){ - /* use simpson's rule to average acceleration between - * current and previous velocity. - * Though being the more natural choice, it causes a minor delay - * in comparison, so it can be disabled. */ - res = BasicComputeAcceleration( - dev, vel, vel->velocity, threshold, acc); - res += BasicComputeAcceleration( - dev, vel, vel->last_velocity, threshold, acc); - res += 4.0f * BasicComputeAcceleration(dev, vel, - (vel->last_velocity + vel->velocity) / 2, - threshold, acc); - res /= 6.0f; - DebugAccelF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n", - vel->velocity, vel->last_velocity, res); - return res; - }else{ - res = BasicComputeAcceleration(dev, vel, - vel->velocity, threshold, acc); - DebugAccelF("(dix ptracc) profile sample [%.2f] is %.3f\n", - vel->velocity, res); - return res; - } -} - - -/***************************************** - * Acceleration functions and profiles - ****************************************/ - -/** - * Polynomial function similar previous one, but with f(1) = 1 - */ -static float -PolynomialAccelerationProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float ignored, - float acc) -{ - return pow(velocity, (acc - 1.0) * 0.5); -} - - -/** - * returns acceleration for velocity. - * This profile selects the two functions like the old scheme did - */ -static float -ClassicProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - if (threshold > 0) { - return SimpleSmoothProfile (dev, - vel, - velocity, - threshold, - acc); - } else { - return PolynomialAccelerationProfile (dev, - vel, - velocity, - 0, - acc); - } -} - - -/** - * Power profile - * This has a completely smooth transition curve, i.e. no jumps in the - * derivatives. - * - * This has the expense of overall response dependency on min-acceleration. - * In effect, min_acceleration mimics const_acceleration in this profile. - */ -static float -PowerProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - float vel_dist; - - acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */ - - if (velocity <= threshold) - return vel->min_acceleration; - vel_dist = velocity - threshold; - return (pow(acc, vel_dist)) * vel->min_acceleration; -} - - -/** - * just a smooth function in [0..1] -> [0..1] - * - point symmetry at 0.5 - * - f'(0) = f'(1) = 0 - * - starts faster than a sinoid - * - smoothness C1 (Cinf if you dare to ignore endpoints) - */ -static inline float -CalcPenumbralGradient(float x){ - x *= 2.0f; - x -= 1.0f; - return 0.5f + (x * sqrt(1.0f - x*x) + asin(x))/M_PI; -} - - -/** - * acceleration function similar to classic accelerated/unaccelerated, - * but with smooth transition in between (and towards zero for adaptive dec.). - */ -static float -SimpleSmoothProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - if(velocity < 1.0f) - return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f; - if(threshold < 1.0f) - threshold = 1.0f; - if (velocity <= threshold) - return 1; - velocity /= threshold; - if (velocity >= acc) - return acc; - else - return 1.0f + (CalcPenumbralGradient(velocity/acc) * (acc - 1.0f)); -} - - -/** - * This profile uses the first half of the penumbral gradient as a start - * and then scales linearly. - */ -static float -SmoothLinearProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - float res, nv; - - if(acc > 1.0f) - acc -= 1.0f; /*this is so acc = 1 is no acceleration */ - else - return 1.0f; - - nv = (velocity - threshold) * acc * 0.5f; - - if(nv < 0){ - res = 0; - }else if(nv < 2){ - res = CalcPenumbralGradient(nv*0.25f)*2.0f; - }else{ - nv -= 2.0f; - res = nv * 2.0f / M_PI /* steepness of gradient at 0.5 */ - + 1.0f; /* gradient crosses 2|1 */ - } - res += vel->min_acceleration; - return res; -} - - -/** - * From 0 to threshold, the response graduates smoothly from min_accel to - * acceleration. Beyond threshold it is exactly the specified acceleration. - */ -static float -SmoothLimitedProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - float res; - - if(velocity >= threshold || threshold == 0.0f) - return acc; - - velocity /= threshold; /* should be [0..1[ now */ - - res = CalcPenumbralGradient(velocity) * (acc - vel->min_acceleration); - - return vel->min_acceleration + res; -} - - -static float -LinearProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - return acc * velocity; -} - -static float -NoProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - return 1.0f; -} - -static PointerAccelerationProfileFunc -GetAccelerationProfile( - DeviceVelocityPtr vel, - int profile_num) -{ - switch(profile_num){ - case AccelProfileClassic: - return ClassicProfile; - case AccelProfileDeviceSpecific: - return vel->deviceSpecificProfile; - case AccelProfilePolynomial: - return PolynomialAccelerationProfile; - case AccelProfileSmoothLinear: - return SmoothLinearProfile; - case AccelProfileSimple: - return SimpleSmoothProfile; - case AccelProfilePower: - return PowerProfile; - case AccelProfileLinear: - return LinearProfile; - case AccelProfileSmoothLimited: - return SmoothLimitedProfile; - case AccelProfileNone: - return NoProfile; - default: - return NULL; - } -} - -/** - * Set the profile by number. - * Intended to make profiles exchangeable at runtime. - * If you created a profile, give it a number here and in the header to - * make it selectable. In case some profile-specific init is needed, here - * would be a good place, since FreeVelocityData() also calls this with - * PROFILE_UNINITIALIZE. - * - * returns FALSE if profile number is unavailable, TRUE otherwise. - */ -int -SetAccelerationProfile( - DeviceVelocityPtr vel, - int profile_num) -{ - PointerAccelerationProfileFunc profile; - profile = GetAccelerationProfile(vel, profile_num); - - if(profile == NULL && profile_num != PROFILE_UNINITIALIZE) - return FALSE; - - if(vel->profile_private != NULL){ - /* Here one could free old profile-private data */ - xfree(vel->profile_private); - vel->profile_private = NULL; - } - /* Here one could init profile-private data */ - vel->Profile = profile; - vel->statistics.profile_number = profile_num; - return TRUE; -} - -/********************************************** - * driver interaction - **********************************************/ - - -/** - * device-specific profile - * - * The device-specific profile is intended as a hook for a driver - * which may want to provide an own acceleration profile. - * It should not rely on profile-private data, instead - * it should do init/uninit in the driver (ie. with DEVICE_INIT and friends). - * Users may override or choose it. - */ -void -SetDeviceSpecificAccelerationProfile( - DeviceVelocityPtr vel, - PointerAccelerationProfileFunc profile) -{ - if(vel) - vel->deviceSpecificProfile = profile; -} - -/** - * Use this function to obtain a DeviceVelocityPtr for a device. Will return NULL if - * the predictable acceleration scheme is not in effect. - */ -DeviceVelocityPtr -GetDevicePredictableAccelData( - DeviceIntPtr dev) -{ - /*sanity check*/ - if(!dev){ - ErrorF("[dix] accel: DeviceIntPtr was NULL"); - return NULL; - } - if( dev->valuator && - dev->valuator->accelScheme.AccelSchemeProc == - acceleratePointerPredictable && - dev->valuator->accelScheme.accelData != NULL){ - - return (DeviceVelocityPtr)dev->valuator->accelScheme.accelData; - } - return NULL; -} - -/******************************** - * acceleration schemes - *******************************/ - -/** - * Modifies valuators in-place. - * This version employs a velocity approximation algorithm to - * enable fine-grained predictable acceleration profiles. - */ -void -acceleratePointerPredictable( - DeviceIntPtr dev, - int first_valuator, - int num_valuators, - int *valuators, - int evtime) -{ - float mult = 0.0; - int dx = 0, dy = 0; - int *px = NULL, *py = NULL; - DeviceVelocityPtr velocitydata = - (DeviceVelocityPtr) dev->valuator->accelScheme.accelData; - float fdx, fdy, tmp; /* no need to init */ - Bool soften = TRUE; - - if (!num_valuators || !valuators || !velocitydata) - return; - - if (velocitydata->statistics.profile_number == AccelProfileNone && - velocitydata->const_acceleration == 1.0f) { - return; /*we're inactive anyway, so skip the whole thing.*/ - } - - if (first_valuator == 0) { - dx = valuators[0]; - px = &valuators[0]; - } - if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) { - dy = valuators[1 - first_valuator]; - py = &valuators[1 - first_valuator]; - } - - if (dx || dy){ - /* reset non-visible state? */ - if (ProcessVelocityData2D(velocitydata, dx , dy, evtime)) { - soften = FALSE; - } - - if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { - /* invoke acceleration profile to determine acceleration */ - mult = ComputeAcceleration (dev, velocitydata, - dev->ptrfeed->ctrl.threshold, - (float)dev->ptrfeed->ctrl.num / - (float)dev->ptrfeed->ctrl.den); - - if(mult != 1.0 || velocitydata->const_acceleration != 1.0) { - ApplySofteningAndConstantDeceleration( velocitydata, - dx, dy, - &fdx, &fdy, - (mult > 1.0) && soften); - - if (dx) { - tmp = mult * fdx + dev->last.remainder[0]; - /* Since it may not be apparent: lrintf() does not offer - * strong statements about rounding; however because we - * process each axis conditionally, there's no danger - * of a toggling remainder. Its lack of guarantees likely - * makes it faster on the average target. */ - *px = lrintf(tmp); - dev->last.remainder[0] = tmp - (float)*px; - } - if (dy) { - tmp = mult * fdy + dev->last.remainder[1]; - *py = lrintf(tmp); - dev->last.remainder[1] = tmp - (float)*py; - } - DebugAccelF("pos (%i | %i) remainders x: %.3f y: %.3f delta x:%.3f y:%.3f\n", - *px, *py, dev->last.remainder[0], dev->last.remainder[1], fdx, fdy); - } - } - } - /* remember last motion delta (for softening/slow movement treatment) */ - velocitydata->last_dx = dx; - velocitydata->last_dy = dy; -} - - - -/** - * Originally a part of xf86PostMotionEvent; modifies valuators - * in-place. Retained mostly for embedded scenarios. - */ -void -acceleratePointerLightweight( - DeviceIntPtr dev, - int first_valuator, - int num_valuators, - int *valuators, - int ignored) -{ - float mult = 0.0; - int dx = 0, dy = 0; - int *px = NULL, *py = NULL; - - if (!num_valuators || !valuators) - return; - - if (first_valuator == 0) { - dx = valuators[0]; - px = &valuators[0]; - } - if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) { - dy = valuators[1 - first_valuator]; - py = &valuators[1 - first_valuator]; - } - - if (!dx && !dy) - return; - - if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { - /* modeled from xf86Events.c */ - if (dev->ptrfeed->ctrl.threshold) { - if ((abs(dx) + abs(dy)) >= dev->ptrfeed->ctrl.threshold) { - dev->last.remainder[0] = ((float)dx * - (float)(dev->ptrfeed->ctrl.num)) / - (float)(dev->ptrfeed->ctrl.den) + - dev->last.remainder[0]; - if (px) { - *px = (int)dev->last.remainder[0]; - dev->last.remainder[0] = dev->last.remainder[0] - - (float)(*px); - } - - dev->last.remainder[1] = ((float)dy * - (float)(dev->ptrfeed->ctrl.num)) / - (float)(dev->ptrfeed->ctrl.den) + - dev->last.remainder[1]; - if (py) { - *py = (int)dev->last.remainder[1]; - dev->last.remainder[1] = dev->last.remainder[1] - - (float)(*py); - } - } - } - else { - mult = pow((float)dx * (float)dx + (float)dy * (float)dy, - ((float)(dev->ptrfeed->ctrl.num) / - (float)(dev->ptrfeed->ctrl.den) - 1.0) / - 2.0) / 2.0; - if (dx) { - dev->last.remainder[0] = mult * (float)dx + - dev->last.remainder[0]; - *px = (int)dev->last.remainder[0]; - dev->last.remainder[0] = dev->last.remainder[0] - - (float)(*px); - } - if (dy) { - dev->last.remainder[1] = mult * (float)dy + - dev->last.remainder[1]; - *py = (int)dev->last.remainder[1]; - dev->last.remainder[1] = dev->last.remainder[1] - - (float)(*py); - } - } - } -} +/* + * + * Copyright © 2006-2009 Simon Thum simon dot thum at gmx dot de + * + * 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +/***************************************************************************** + * Predictable pointer acceleration + * + * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de) + * + * Serves 3 complementary functions: + * 1) provide a sophisticated ballistic velocity estimate to improve + * the relation between velocity (of the device) and acceleration + * 2) make arbitrary acceleration profiles possible + * 3) decelerate by two means (constant and adaptive) if enabled + * + * Important concepts are the + * + * - Scheme + * which selects the basic algorithm + * (see devices.c/InitPointerAccelerationScheme) + * - Profile + * which returns an acceleration + * for a given velocity + * + * The profile can be selected by the user at runtime. + * The classic profile is intended to cleanly perform old-style + * function selection (threshold =/!= 0) + * + ****************************************************************************/ + +/* fwds */ +int +SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); +static float +SimpleSmoothProfile(DeviceIntPtr dev, DeviceVelocityPtr vel, float velocity, + float threshold, float acc); +static PointerAccelerationProfileFunc +GetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); + +/*#define PTRACCEL_DEBUGGING*/ + +#ifdef PTRACCEL_DEBUGGING +#define DebugAccelF ErrorF +#else +#define DebugAccelF(...) /* */ +#endif + +/******************************** + * Init/Uninit + *******************************/ + +/* some int which is not a profile number */ +#define PROFILE_UNINITIALIZE (-100) + + +/** + * Init struct so it should match the average case + */ +void +InitVelocityData(DeviceVelocityPtr vel) +{ + memset(vel, 0, sizeof(DeviceVelocityRec)); + + vel->corr_mul = 10.0; /* dots per 10 milisecond should be usable */ + vel->const_acceleration = 1.0; /* no acceleration/deceleration */ + vel->reset_time = 300; + vel->use_softening = 1; + vel->min_acceleration = 1.0; /* don't decelerate */ + vel->max_rel_diff = 0.2; + vel->max_diff = 1.0; + vel->initial_range = 2; + vel->average_accel = TRUE; + SetAccelerationProfile(vel, AccelProfileClassic); + InitTrackers(vel, 16); +} + + +/** + * Clean up + */ +void +FreeVelocityData(DeviceVelocityPtr vel){ + free(vel->tracker); + SetAccelerationProfile(vel, PROFILE_UNINITIALIZE); +} + + +/* + * dix uninit helper, called through scheme + */ +void +AccelerationDefaultCleanup(DeviceIntPtr dev) +{ + /*sanity check*/ + if( dev->valuator->accelScheme.AccelSchemeProc == acceleratePointerPredictable + && dev->valuator->accelScheme.accelData != NULL){ + dev->valuator->accelScheme.AccelSchemeProc = NULL; + FreeVelocityData(dev->valuator->accelScheme.accelData); + free(dev->valuator->accelScheme.accelData); + dev->valuator->accelScheme.accelData = NULL; + DeletePredictableAccelerationProperties(dev); + } +} + + +/************************* + * Input property support + ************************/ + +/** + * choose profile + */ +static int +AccelSetProfileProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr vel; + int profile, *ptr = &profile; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER)) + return Success; + + vel = GetDevicePredictableAccelData(dev); + if (!vel) + return BadValue; + rc = XIPropToInt(val, &nelem, &ptr); + + if(checkOnly) + { + if (rc) + return rc; + + if (GetAccelerationProfile(vel, profile) == NULL) + return BadValue; + } else + SetAccelerationProfile(vel, profile); + + return Success; +} + +static long +AccelInitProfileProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + int profile = vel->statistics.profile_number; + Atom prop_profile_number = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); + + XIChangeDeviceProperty(dev, prop_profile_number, XA_INTEGER, 32, + PropModeReplace, 1, &profile, FALSE); + XISetDevicePropertyDeletable(dev, prop_profile_number, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetProfileProperty, NULL, NULL); +} + +/** + * constant deceleration + */ +static int +AccelSetDecelProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr vel; + float v, *ptr = &v; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION)) + return Success; + + vel = GetDevicePredictableAccelData(dev); + if (!vel) + return BadValue; + rc = XIPropToFloat(val, &nelem, &ptr); + + if(checkOnly) + { + if (rc) + return rc; + return (v >= 1.0f) ? Success : BadValue; + } + + if(v >= 1.0f) + vel->const_acceleration = 1/v; + + return Success; +} + +static long +AccelInitDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + float fval = 1.0/vel->const_acceleration; + Atom prop_const_decel = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); + XIChangeDeviceProperty(dev, prop_const_decel, + XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 1, &fval, FALSE); + XISetDevicePropertyDeletable(dev, prop_const_decel, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetDecelProperty, NULL, NULL); +} + + +/** + * adaptive deceleration + */ +static int +AccelSetAdaptDecelProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr veloc; + float v, *ptr = &v; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION)) + return Success; + + veloc = GetDevicePredictableAccelData(dev); + if (!veloc) + return BadValue; + rc = XIPropToFloat(val, &nelem, &ptr); + + if(checkOnly) + { + if (rc) + return rc; + return (v >= 1.0f) ? Success : BadValue; + } + + if(v >= 1.0f) + veloc->min_acceleration = 1/v; + + return Success; +} + +static long +AccelInitAdaptDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + float fval = 1.0/vel->min_acceleration; + Atom prop_adapt_decel = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); + + XIChangeDeviceProperty(dev, prop_adapt_decel, XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 1, &fval, FALSE); + XISetDevicePropertyDeletable(dev, prop_adapt_decel, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetAdaptDecelProperty, NULL, NULL); +} + + +/** + * velocity scaling + */ +static int +AccelSetScaleProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr vel; + float v, *ptr = &v; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING)) + return Success; + + vel = GetDevicePredictableAccelData(dev); + if (!vel) + return BadValue; + rc = XIPropToFloat(val, &nelem, &ptr); + + if (checkOnly) + { + if (rc) + return rc; + + return (v > 0) ? Success : BadValue; + } + + if(v > 0) + vel->corr_mul = v; + + return Success; +} + +static long +AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + float fval = vel->corr_mul; + Atom prop_velo_scale = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); + + XIChangeDeviceProperty(dev, prop_velo_scale, XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 1, &fval, FALSE); + XISetDevicePropertyDeletable(dev, prop_velo_scale, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetScaleProperty, NULL, NULL); +} + +BOOL +InitializePredictableAccelerationProperties(DeviceIntPtr dev) +{ + DeviceVelocityPtr vel = GetDevicePredictableAccelData(dev); + + if(!vel) + return FALSE; + + vel->prop_handlers[0] = AccelInitProfileProperty(dev, vel); + vel->prop_handlers[1] = AccelInitDecelProperty(dev, vel); + vel->prop_handlers[2] = AccelInitAdaptDecelProperty(dev, vel); + vel->prop_handlers[3] = AccelInitScaleProperty(dev, vel); + + return TRUE; +} + +BOOL +DeletePredictableAccelerationProperties(DeviceIntPtr dev) +{ + DeviceVelocityPtr vel; + Atom prop; + int i; + + prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); + XIDeleteDeviceProperty(dev, prop, FALSE); + prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); + XIDeleteDeviceProperty(dev, prop, FALSE); + prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); + XIDeleteDeviceProperty(dev, prop, FALSE); + prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); + XIDeleteDeviceProperty(dev, prop, FALSE); + + vel = GetDevicePredictableAccelData(dev); + for (i = 0; vel && i < NPROPS_PREDICTABLE_ACCEL; i++) + if (vel->prop_handlers[i]) + XIUnregisterPropertyHandler(dev, vel->prop_handlers[i]); + + return TRUE; +} + +/********************* + * Tracking logic + ********************/ + +void +InitTrackers(DeviceVelocityPtr vel, int ntracker) +{ + if(ntracker < 1){ + ErrorF("(dix ptracc) invalid number of trackers\n"); + return; + } + free(vel->tracker); + vel->tracker = (MotionTrackerPtr)malloc(ntracker * sizeof(MotionTracker)); + memset(vel->tracker, 0, ntracker * sizeof(MotionTracker)); + vel->num_tracker = ntracker; +} + +/** + * return a bit field of possible directions. + * 0 = N, 2 = E, 4 = S, 6 = W, in-between is as you guess. + * There's no reason against widening to more precise directions (<45 degrees), + * should it not perform well. All this is needed for is sort out non-linear + * motion, so precision isn't paramount. However, one should not flag direction + * too narrow, since it would then cut the linear segment to zero size way too + * often. + */ +static int +DoGetDirection(int dx, int dy){ + float r; + int i1, i2; + /* on insignificant mickeys, flag 135 degrees */ + if(abs(dx) < 2 && abs(dy < 2)){ + /* first check diagonal cases */ + if(dx > 0 && dy > 0) + return 4+8+16; + if(dx > 0 && dy < 0) + return 1+2+4; + if(dx < 0 && dy < 0) + return 1+128+64; + if(dx < 0 && dy > 0) + return 16+32+64; + /* check axis-aligned directions */ + if(dx > 0) + return 2+4+8; /*E*/ + if(dx < 0) + return 128+64+32; /*W*/ + if(dy > 0) + return 32+16+8; /*S*/ + if(dy < 0) + return 128+1+2; /*N*/ + return 255; /* shouldn't happen */ + } + /* else, compute angle and set appropriate flags */ +#ifdef _ISOC99_SOURCE + r = atan2f(dy, dx); +#else + r = atan2(dy, dx); +#endif + /* find direction. We avoid r to become negative, + * since C has no well-defined modulo for such cases. */ + r = (r+(M_PI*2.5))/(M_PI/4); + /* this intends to flag 2 directions (90 degrees), + * except on very well-aligned mickeys. */ + i1 = (int)(r+0.1) % 8; + i2 = (int)(r+0.9) % 8; + if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7) + return 255; /* shouldn't happen */ + return 1 << i1 | 1 << i2; +} + +#define DIRECTION_CACHE_RANGE 5 +#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1) + +/* cache DoGetDirection(). */ +static int +GetDirection(int dx, int dy){ + static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE]; + int i; + if (abs(dx) <= DIRECTION_CACHE_RANGE && + abs(dy) <= DIRECTION_CACHE_RANGE) { + /* cacheable */ + i = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy]; + if(i != 0){ + return i; + }else{ + i = DoGetDirection(dx, dy); + cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = i; + return i; + } + }else{ + /* non-cacheable */ + return DoGetDirection(dx, dy); + } +} + +#undef DIRECTION_CACHE_RANGE +#undef DIRECTION_CACHE_SIZE + + +/* convert offset (age) to array index */ +#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker) + +static inline void +FeedTrackers(DeviceVelocityPtr vel, int dx, int dy, int cur_t) +{ + int n; + for(n = 0; n < vel->num_tracker; n++){ + vel->tracker[n].dx += dx; + vel->tracker[n].dy += dy; + } + n = (vel->cur_tracker + 1) % vel->num_tracker; + vel->tracker[n].dx = 0; + vel->tracker[n].dy = 0; + vel->tracker[n].time = cur_t; + vel->tracker[n].dir = GetDirection(dx, dy); + DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n", + dx, dy, vel->tracker[n].dir, + cur_t - vel->tracker[vel->cur_tracker].time); + vel->cur_tracker = n; +} + +/** + * calc velocity for given tracker, with + * velocity scaling. + * This assumes linear motion. + */ +static float +CalcTracker(DeviceVelocityPtr vel, int offset, int cur_t){ + int index = TRACKER_INDEX(vel, offset); + float dist = sqrt( vel->tracker[index].dx * vel->tracker[index].dx + + vel->tracker[index].dy * vel->tracker[index].dy); + int dtime = cur_t - vel->tracker[index].time; + if(dtime > 0) + return (dist / dtime); + else + return 0;/* synonymous for NaN, since we're not C99 */ +} + +/* find the most plausible velocity. That is, the most distant + * (in time) tracker which isn't too old, beyond a linear partition, + * or simply too much off initial velocity. + * + * May return 0. + */ +static float +QueryTrackers(DeviceVelocityPtr vel, int cur_t){ + int n, offset, dir = 255, i = -1, age_ms; + /* initial velocity: a low-offset, valid velocity */ + float iveloc = 0, res = 0, tmp, vdiff; + float vfac = vel->corr_mul * vel->const_acceleration; /* premultiply */ + /* loop from current to older data */ + for(offset = 1; offset < vel->num_tracker; offset++){ + n = TRACKER_INDEX(vel, offset); + + age_ms = cur_t - vel->tracker[n].time; + + /* bail out if data is too old and protect from overrun */ + if (age_ms >= vel->reset_time || age_ms < 0) { + DebugAccelF("(dix prtacc) query: tracker too old\n"); + break; + } + + /* + * this heuristic avoids using the linear-motion velocity formula + * in CalcTracker() on motion that isn't exactly linear. So to get + * even more precision we could subdivide as a final step, so possible + * non-linearities are accounted for. + */ + dir &= vel->tracker[n].dir; + if(dir == 0){ + DebugAccelF("(dix prtacc) query: no longer linear\n"); + /* instead of breaking it we might also inspect the partition after, + * but actual improvement with this is probably rare. */ + break; + } + + tmp = CalcTracker(vel, offset, cur_t) * vfac; + + if ((iveloc == 0 || offset <= vel->initial_range) && tmp != 0) { + /* set initial velocity and result */ + res = iveloc = tmp; + i = offset; + } else if (iveloc != 0 && tmp != 0) { + vdiff = fabs(iveloc - tmp); + if (vdiff <= vel->max_diff || + vdiff/(iveloc + tmp) < vel->max_rel_diff) { + /* we're in range with the initial velocity, + * so this result is likely better + * (it contains more information). */ + res = tmp; + i = offset; + }else{ + /* we're not in range, quit - it won't get better. */ + DebugAccelF("(dix prtacc) query: tracker too different:" + " old %2.2f initial %2.2f diff: %2.2f\n", + tmp, iveloc, vdiff); + break; + } + } + } + if(offset == vel->num_tracker){ + DebugAccelF("(dix prtacc) query: last tracker in effect\n"); + i = vel->num_tracker-1; + } + if(i>=0){ + n = TRACKER_INDEX(vel, i); + DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n", + i, + vel->tracker[n].dx, + vel->tracker[n].dy, + cur_t - vel->tracker[n].time); + } + return res; +} + +#undef TRACKER_INDEX + +/** + * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta). + * return true if non-visible state reset is suggested + */ +short +ProcessVelocityData2D( + DeviceVelocityPtr vel, + int dx, + int dy, + int time) +{ + float velocity; + + vel->last_velocity = vel->velocity; + + FeedTrackers(vel, dx, dy, time); + + velocity = QueryTrackers(vel, time); + + vel->velocity = velocity; + return velocity == 0; +} + +/** + * this flattens significant ( > 1) mickeys a little bit for more steady + * constant-velocity response + */ +static inline float +ApplySimpleSoftening(int od, int d) +{ + float res = d; + if (d <= 1 && d >= -1) + return res; + if (d > od) + res -= 0.5; + else if (d < od) + res += 0.5; + return res; +} + + +static void +ApplySofteningAndConstantDeceleration( + DeviceVelocityPtr vel, + int dx, + int dy, + float* fdx, + float* fdy, + short do_soften) +{ + if (do_soften && vel->use_softening) { + *fdx = ApplySimpleSoftening(vel->last_dx, dx); + *fdy = ApplySimpleSoftening(vel->last_dy, dy); + } else { + *fdx = dx; + *fdy = dy; + } + + *fdx *= vel->const_acceleration; + *fdy *= vel->const_acceleration; +} + +/* + * compute the acceleration for given velocity and enforce min_acceleartion + */ +float +BasicComputeAcceleration( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc){ + + float result; + result = vel->Profile(dev, vel, velocity, threshold, acc); + + /* enforce min_acceleration */ + if (result < vel->min_acceleration) + result = vel->min_acceleration; + return result; +} + +/** + * Compute acceleration. Takes into account averaging, nv-reset, etc. + */ +static float +ComputeAcceleration( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float threshold, + float acc){ + float res; + + if(vel->velocity <= 0){ + DebugAccelF("(dix ptracc) profile skipped\n"); + /* + * If we have no idea about device velocity, don't pretend it. + */ + return 1; + } + + if(vel->average_accel && vel->velocity != vel->last_velocity){ + /* use simpson's rule to average acceleration between + * current and previous velocity. + * Though being the more natural choice, it causes a minor delay + * in comparison, so it can be disabled. */ + res = BasicComputeAcceleration( + dev, vel, vel->velocity, threshold, acc); + res += BasicComputeAcceleration( + dev, vel, vel->last_velocity, threshold, acc); + res += 4.0f * BasicComputeAcceleration(dev, vel, + (vel->last_velocity + vel->velocity) / 2, + threshold, acc); + res /= 6.0f; + DebugAccelF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n", + vel->velocity, vel->last_velocity, res); + return res; + }else{ + res = BasicComputeAcceleration(dev, vel, + vel->velocity, threshold, acc); + DebugAccelF("(dix ptracc) profile sample [%.2f] is %.3f\n", + vel->velocity, res); + return res; + } +} + + +/***************************************** + * Acceleration functions and profiles + ****************************************/ + +/** + * Polynomial function similar previous one, but with f(1) = 1 + */ +static float +PolynomialAccelerationProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float ignored, + float acc) +{ + return pow(velocity, (acc - 1.0) * 0.5); +} + + +/** + * returns acceleration for velocity. + * This profile selects the two functions like the old scheme did + */ +static float +ClassicProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + if (threshold > 0) { + return SimpleSmoothProfile (dev, + vel, + velocity, + threshold, + acc); + } else { + return PolynomialAccelerationProfile (dev, + vel, + velocity, + 0, + acc); + } +} + + +/** + * Power profile + * This has a completely smooth transition curve, i.e. no jumps in the + * derivatives. + * + * This has the expense of overall response dependency on min-acceleration. + * In effect, min_acceleration mimics const_acceleration in this profile. + */ +static float +PowerProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + float vel_dist; + + acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */ + + if (velocity <= threshold) + return vel->min_acceleration; + vel_dist = velocity - threshold; + return (pow(acc, vel_dist)) * vel->min_acceleration; +} + + +/** + * just a smooth function in [0..1] -> [0..1] + * - point symmetry at 0.5 + * - f'(0) = f'(1) = 0 + * - starts faster than a sinoid + * - smoothness C1 (Cinf if you dare to ignore endpoints) + */ +static inline float +CalcPenumbralGradient(float x){ + x *= 2.0f; + x -= 1.0f; + return 0.5f + (x * sqrt(1.0f - x*x) + asin(x))/M_PI; +} + + +/** + * acceleration function similar to classic accelerated/unaccelerated, + * but with smooth transition in between (and towards zero for adaptive dec.). + */ +static float +SimpleSmoothProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + if(velocity < 1.0f) + return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f; + if(threshold < 1.0f) + threshold = 1.0f; + if (velocity <= threshold) + return 1; + velocity /= threshold; + if (velocity >= acc) + return acc; + else + return 1.0f + (CalcPenumbralGradient(velocity/acc) * (acc - 1.0f)); +} + + +/** + * This profile uses the first half of the penumbral gradient as a start + * and then scales linearly. + */ +static float +SmoothLinearProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + float res, nv; + + if(acc > 1.0f) + acc -= 1.0f; /*this is so acc = 1 is no acceleration */ + else + return 1.0f; + + nv = (velocity - threshold) * acc * 0.5f; + + if(nv < 0){ + res = 0; + }else if(nv < 2){ + res = CalcPenumbralGradient(nv*0.25f)*2.0f; + }else{ + nv -= 2.0f; + res = nv * 2.0f / M_PI /* steepness of gradient at 0.5 */ + + 1.0f; /* gradient crosses 2|1 */ + } + res += vel->min_acceleration; + return res; +} + + +/** + * From 0 to threshold, the response graduates smoothly from min_accel to + * acceleration. Beyond threshold it is exactly the specified acceleration. + */ +static float +SmoothLimitedProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + float res; + + if(velocity >= threshold || threshold == 0.0f) + return acc; + + velocity /= threshold; /* should be [0..1[ now */ + + res = CalcPenumbralGradient(velocity) * (acc - vel->min_acceleration); + + return vel->min_acceleration + res; +} + + +static float +LinearProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + return acc * velocity; +} + +static float +NoProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + return 1.0f; +} + +static PointerAccelerationProfileFunc +GetAccelerationProfile( + DeviceVelocityPtr vel, + int profile_num) +{ + switch(profile_num){ + case AccelProfileClassic: + return ClassicProfile; + case AccelProfileDeviceSpecific: + return vel->deviceSpecificProfile; + case AccelProfilePolynomial: + return PolynomialAccelerationProfile; + case AccelProfileSmoothLinear: + return SmoothLinearProfile; + case AccelProfileSimple: + return SimpleSmoothProfile; + case AccelProfilePower: + return PowerProfile; + case AccelProfileLinear: + return LinearProfile; + case AccelProfileSmoothLimited: + return SmoothLimitedProfile; + case AccelProfileNone: + return NoProfile; + default: + return NULL; + } +} + +/** + * Set the profile by number. + * Intended to make profiles exchangeable at runtime. + * If you created a profile, give it a number here and in the header to + * make it selectable. In case some profile-specific init is needed, here + * would be a good place, since FreeVelocityData() also calls this with + * PROFILE_UNINITIALIZE. + * + * returns FALSE if profile number is unavailable, TRUE otherwise. + */ +int +SetAccelerationProfile( + DeviceVelocityPtr vel, + int profile_num) +{ + PointerAccelerationProfileFunc profile; + profile = GetAccelerationProfile(vel, profile_num); + + if(profile == NULL && profile_num != PROFILE_UNINITIALIZE) + return FALSE; + + if(vel->profile_private != NULL){ + /* Here one could free old profile-private data */ + free(vel->profile_private); + vel->profile_private = NULL; + } + /* Here one could init profile-private data */ + vel->Profile = profile; + vel->statistics.profile_number = profile_num; + return TRUE; +} + +/********************************************** + * driver interaction + **********************************************/ + + +/** + * device-specific profile + * + * The device-specific profile is intended as a hook for a driver + * which may want to provide an own acceleration profile. + * It should not rely on profile-private data, instead + * it should do init/uninit in the driver (ie. with DEVICE_INIT and friends). + * Users may override or choose it. + */ +void +SetDeviceSpecificAccelerationProfile( + DeviceVelocityPtr vel, + PointerAccelerationProfileFunc profile) +{ + if(vel) + vel->deviceSpecificProfile = profile; +} + +/** + * Use this function to obtain a DeviceVelocityPtr for a device. Will return NULL if + * the predictable acceleration scheme is not in effect. + */ +DeviceVelocityPtr +GetDevicePredictableAccelData( + DeviceIntPtr dev) +{ + /*sanity check*/ + if(!dev){ + ErrorF("[dix] accel: DeviceIntPtr was NULL"); + return NULL; + } + if( dev->valuator && + dev->valuator->accelScheme.AccelSchemeProc == + acceleratePointerPredictable && + dev->valuator->accelScheme.accelData != NULL){ + + return (DeviceVelocityPtr)dev->valuator->accelScheme.accelData; + } + return NULL; +} + +/******************************** + * acceleration schemes + *******************************/ + +/** + * Modifies valuators in-place. + * This version employs a velocity approximation algorithm to + * enable fine-grained predictable acceleration profiles. + */ +void +acceleratePointerPredictable( + DeviceIntPtr dev, + int first_valuator, + int num_valuators, + int *valuators, + int evtime) +{ + float mult = 0.0; + int dx = 0, dy = 0; + int *px = NULL, *py = NULL; + DeviceVelocityPtr velocitydata = + (DeviceVelocityPtr) dev->valuator->accelScheme.accelData; + float fdx, fdy, tmp; /* no need to init */ + Bool soften = TRUE; + + if (!num_valuators || !valuators || !velocitydata) + return; + + if (velocitydata->statistics.profile_number == AccelProfileNone && + velocitydata->const_acceleration == 1.0f) { + return; /*we're inactive anyway, so skip the whole thing.*/ + } + + if (first_valuator == 0) { + dx = valuators[0]; + px = &valuators[0]; + } + if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) { + dy = valuators[1 - first_valuator]; + py = &valuators[1 - first_valuator]; + } + + if (dx || dy){ + /* reset non-visible state? */ + if (ProcessVelocityData2D(velocitydata, dx , dy, evtime)) { + soften = FALSE; + } + + if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { + /* invoke acceleration profile to determine acceleration */ + mult = ComputeAcceleration (dev, velocitydata, + dev->ptrfeed->ctrl.threshold, + (float)dev->ptrfeed->ctrl.num / + (float)dev->ptrfeed->ctrl.den); + + if(mult != 1.0 || velocitydata->const_acceleration != 1.0) { + ApplySofteningAndConstantDeceleration( velocitydata, + dx, dy, + &fdx, &fdy, + (mult > 1.0) && soften); + + if (dx) { + tmp = mult * fdx + dev->last.remainder[0]; + /* Since it may not be apparent: lrintf() does not offer + * strong statements about rounding; however because we + * process each axis conditionally, there's no danger + * of a toggling remainder. Its lack of guarantees likely + * makes it faster on the average target. */ + *px = lrintf(tmp); + dev->last.remainder[0] = tmp - (float)*px; + } + if (dy) { + tmp = mult * fdy + dev->last.remainder[1]; + *py = lrintf(tmp); + dev->last.remainder[1] = tmp - (float)*py; + } + DebugAccelF("pos (%i | %i) remainders x: %.3f y: %.3f delta x:%.3f y:%.3f\n", + *px, *py, dev->last.remainder[0], dev->last.remainder[1], fdx, fdy); + } + } + } + /* remember last motion delta (for softening/slow movement treatment) */ + velocitydata->last_dx = dx; + velocitydata->last_dy = dy; +} + + + +/** + * Originally a part of xf86PostMotionEvent; modifies valuators + * in-place. Retained mostly for embedded scenarios. + */ +void +acceleratePointerLightweight( + DeviceIntPtr dev, + int first_valuator, + int num_valuators, + int *valuators, + int ignored) +{ + float mult = 0.0; + int dx = 0, dy = 0; + int *px = NULL, *py = NULL; + + if (!num_valuators || !valuators) + return; + + if (first_valuator == 0) { + dx = valuators[0]; + px = &valuators[0]; + } + if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) { + dy = valuators[1 - first_valuator]; + py = &valuators[1 - first_valuator]; + } + + if (!dx && !dy) + return; + + if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { + /* modeled from xf86Events.c */ + if (dev->ptrfeed->ctrl.threshold) { + if ((abs(dx) + abs(dy)) >= dev->ptrfeed->ctrl.threshold) { + dev->last.remainder[0] = ((float)dx * + (float)(dev->ptrfeed->ctrl.num)) / + (float)(dev->ptrfeed->ctrl.den) + + dev->last.remainder[0]; + if (px) { + *px = (int)dev->last.remainder[0]; + dev->last.remainder[0] = dev->last.remainder[0] - + (float)(*px); + } + + dev->last.remainder[1] = ((float)dy * + (float)(dev->ptrfeed->ctrl.num)) / + (float)(dev->ptrfeed->ctrl.den) + + dev->last.remainder[1]; + if (py) { + *py = (int)dev->last.remainder[1]; + dev->last.remainder[1] = dev->last.remainder[1] - + (float)(*py); + } + } + } + else { + mult = pow((float)dx * (float)dx + (float)dy * (float)dy, + ((float)(dev->ptrfeed->ctrl.num) / + (float)(dev->ptrfeed->ctrl.den) - 1.0) / + 2.0) / 2.0; + if (dx) { + dev->last.remainder[0] = mult * (float)dx + + dev->last.remainder[0]; + *px = (int)dev->last.remainder[0]; + dev->last.remainder[0] = dev->last.remainder[0] - + (float)(*px); + } + if (dy) { + dev->last.remainder[1] = mult * (float)dy + + dev->last.remainder[1]; + *py = (int)dev->last.remainder[1]; + dev->last.remainder[1] = dev->last.remainder[1] - + (float)(*py); + } + } + } +} diff --git a/xorg-server/dix/registry.c b/xorg-server/dix/registry.c index 1381a3dcd..9a83ff74e 100644 --- a/xorg-server/dix/registry.c +++ b/xorg-server/dix/registry.c @@ -1,336 +1,336 @@ -/************************************************************ - -Author: Eamon Walsh - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -this permission notice appear in supporting documentation. 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 -AUTHOR 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. - -********************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#ifdef XREGISTRY - -#include -#include -#include -#include -#include "resource.h" -#include "registry.h" - -#define BASE_SIZE 16 -#define CORE "X11" -#define FILENAME SERVER_MISC_CONFIG_PATH "/protocol.txt" - -#define PROT_COMMENT '#' -#define PROT_REQUEST 'R' -#define PROT_EVENT 'V' -#define PROT_ERROR 'E' - -static FILE *fh; - -static char ***requests, **events, **errors, **resources; -static unsigned nmajor, *nminor, nevent, nerror, nresource; - -/* - * File parsing routines - */ -static int double_size(void *p, unsigned n, unsigned size) -{ - char **ptr = (char **)p; - unsigned s, f; - - if (n) { - s = n * size; - n *= 2 * size; - f = n; - } else { - s = 0; - n = f = BASE_SIZE * size; - } - - *ptr = xrealloc(*ptr, n); - if (!*ptr) { - dixResetRegistry(); - return FALSE; - } - memset(*ptr + s, 0, f - s); - return TRUE; -} - -static void -RegisterRequestName(unsigned major, unsigned minor, char *name) -{ - while (major >= nmajor) { - if (!double_size(&requests, nmajor, sizeof(char **))) - return; - if (!double_size(&nminor, nmajor, sizeof(unsigned))) - return; - nmajor = nmajor ? nmajor * 2 : BASE_SIZE; - } - while (minor >= nminor[major]) { - if (!double_size(requests+major, nminor[major], sizeof(char *))) - return; - nminor[major] = nminor[major] ? nminor[major] * 2 : BASE_SIZE; - } - - free(requests[major][minor]); - requests[major][minor] = name; -} - -static void -RegisterEventName(unsigned event, char *name) { - while (event >= nevent) { - if (!double_size(&events, nevent, sizeof(char *))) - return; - nevent = nevent ? nevent * 2 : BASE_SIZE; - } - - free(events[event]); - events[event] = name; -} - -static void -RegisterErrorName(unsigned error, char *name) { - while (error >= nerror) { - if (!double_size(&errors, nerror, sizeof(char *))) - return; - nerror = nerror ? nerror * 2 : BASE_SIZE; - } - - free(errors[error]); - errors[error] = name; -} - -void -RegisterExtensionNames(ExtensionEntry *extEntry) -{ - char buf[256], *lineobj, *ptr; - unsigned offset; - - if (fh == NULL) - return; - - rewind(fh); - - while (fgets(buf, sizeof(buf), fh)) { - lineobj = NULL; - ptr = strchr(buf, '\n'); - if (ptr) - *ptr = 0; - - /* Check for comments or empty lines */ - switch (buf[0]) { - case PROT_REQUEST: - case PROT_EVENT: - case PROT_ERROR: - break; - case PROT_COMMENT: - case '\0': - continue; - default: - goto invalid; - } - - /* Check for space character in the fifth position */ - ptr = strchr(buf, ' '); - if (!ptr || ptr != buf + 4) - goto invalid; - - /* Duplicate the string after the space */ - lineobj = strdup(ptr + 1); - if (!lineobj) - continue; - - /* Check for a colon somewhere on the line */ - ptr = strchr(buf, ':'); - if (!ptr) - goto invalid; - - /* Compare the part before colon with the target extension name */ - *ptr = 0; - if (strcmp(buf + 5, extEntry->name)) - goto skip; - - /* Get the opcode for the request, event, or error */ - offset = strtol(buf + 1, &ptr, 10); - if (offset == 0 && ptr == buf + 1) - goto invalid; - - /* Save the strdup result in the registry */ - switch(buf[0]) { - case PROT_REQUEST: - if (extEntry->base) - RegisterRequestName(extEntry->base, offset, lineobj); - else - RegisterRequestName(offset, 0, lineobj); - continue; - case PROT_EVENT: - RegisterEventName(extEntry->eventBase + offset, lineobj); - continue; - case PROT_ERROR: - RegisterErrorName(extEntry->errorBase + offset, lineobj); - continue; - } - - invalid: - LogMessage(X_WARNING, "Invalid line in " FILENAME ", skipping\n"); - skip: - free(lineobj); - } -} - -/* - * Registration functions - */ - -void -RegisterResourceName(RESTYPE resource, char *name) -{ - resource &= TypeMask; - - while (resource >= nresource) { - if (!double_size(&resources, nresource, sizeof(char *))) - return; - nresource = nresource ? nresource * 2 : BASE_SIZE; - } - - resources[resource] = name; -} - -/* - * Lookup functions - */ - -const char * -LookupRequestName(int major, int minor) -{ - if (major >= nmajor) - return XREGISTRY_UNKNOWN; - if (minor >= nminor[major]) - return XREGISTRY_UNKNOWN; - - return requests[major][minor] ? requests[major][minor] : XREGISTRY_UNKNOWN; -} - -const char * -LookupMajorName(int major) -{ - if (major < 128) { - const char *retval; - - if (major >= nmajor) - return XREGISTRY_UNKNOWN; - if (0 >= nminor[major]) - return XREGISTRY_UNKNOWN; - - retval = requests[major][0]; - return retval ? retval + sizeof(CORE) : XREGISTRY_UNKNOWN; - } else { - ExtensionEntry *extEntry = GetExtensionEntry(major); - return extEntry ? extEntry->name : XREGISTRY_UNKNOWN; - } -} - -const char * -LookupEventName(int event) -{ - event &= 127; - if (event >= nevent) - return XREGISTRY_UNKNOWN; - - return events[event] ? events[event] : XREGISTRY_UNKNOWN; -} - -const char * -LookupErrorName(int error) -{ - if (error >= nerror) - return XREGISTRY_UNKNOWN; - - return errors[error] ? errors[error] : XREGISTRY_UNKNOWN; -} - -const char * -LookupResourceName(RESTYPE resource) -{ - resource &= TypeMask; - if (resource >= nresource) - return XREGISTRY_UNKNOWN; - - return resources[resource] ? resources[resource] : XREGISTRY_UNKNOWN; -} - -/* - * Setup and teardown - */ -void -dixResetRegistry(void) -{ - ExtensionEntry extEntry; - - /* Free all memory */ - while (nmajor--) { - while (nminor[nmajor]) - free(requests[nmajor][--nminor[nmajor]]); - xfree(requests[nmajor]); - } - xfree(requests); - xfree(nminor); - - while (nevent--) - free(events[nevent]); - xfree(events); - - while (nerror--) - free(errors[nerror]); - xfree(errors); - - xfree(resources); - - requests = NULL; - nminor = NULL; - events = NULL; - errors = NULL; - resources = NULL; - - nmajor = nevent = nerror = nresource = 0; - - /* Open the protocol file */ - if (fh) - fclose(fh); - fh = fopen(FILENAME, "r"); - if (!fh) - LogMessage(X_WARNING, "Failed to open protocol names file " FILENAME "\n"); - - /* Add built-in resources */ - 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"); - - /* Add the core protocol */ - memset(&extEntry, 0, sizeof(extEntry)); - extEntry.name = CORE; - RegisterExtensionNames(&extEntry); -} - -#endif /* XREGISTRY */ +/************************************************************ + +Author: Eamon Walsh + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +this permission notice appear in supporting documentation. 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 +AUTHOR 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. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifdef XREGISTRY + +#include +#include +#include +#include +#include "resource.h" +#include "registry.h" + +#define BASE_SIZE 16 +#define CORE "X11" +#define FILENAME SERVER_MISC_CONFIG_PATH "/protocol.txt" + +#define PROT_COMMENT '#' +#define PROT_REQUEST 'R' +#define PROT_EVENT 'V' +#define PROT_ERROR 'E' + +static FILE *fh; + +static char ***requests, **events, **errors, **resources; +static unsigned nmajor, *nminor, nevent, nerror, nresource; + +/* + * File parsing routines + */ +static int double_size(void *p, unsigned n, unsigned size) +{ + char **ptr = (char **)p; + unsigned s, f; + + if (n) { + s = n * size; + n *= 2 * size; + f = n; + } else { + s = 0; + n = f = BASE_SIZE * size; + } + + *ptr = realloc(*ptr, n); + if (!*ptr) { + dixResetRegistry(); + return FALSE; + } + memset(*ptr + s, 0, f - s); + return TRUE; +} + +static void +RegisterRequestName(unsigned major, unsigned minor, char *name) +{ + while (major >= nmajor) { + if (!double_size(&requests, nmajor, sizeof(char **))) + return; + if (!double_size(&nminor, nmajor, sizeof(unsigned))) + return; + nmajor = nmajor ? nmajor * 2 : BASE_SIZE; + } + while (minor >= nminor[major]) { + if (!double_size(requests+major, nminor[major], sizeof(char *))) + return; + nminor[major] = nminor[major] ? nminor[major] * 2 : BASE_SIZE; + } + + free(requests[major][minor]); + requests[major][minor] = name; +} + +static void +RegisterEventName(unsigned event, char *name) { + while (event >= nevent) { + if (!double_size(&events, nevent, sizeof(char *))) + return; + nevent = nevent ? nevent * 2 : BASE_SIZE; + } + + free(events[event]); + events[event] = name; +} + +static void +RegisterErrorName(unsigned error, char *name) { + while (error >= nerror) { + if (!double_size(&errors, nerror, sizeof(char *))) + return; + nerror = nerror ? nerror * 2 : BASE_SIZE; + } + + free(errors[error]); + errors[error] = name; +} + +void +RegisterExtensionNames(ExtensionEntry *extEntry) +{ + char buf[256], *lineobj, *ptr; + unsigned offset; + + if (fh == NULL) + return; + + rewind(fh); + + while (fgets(buf, sizeof(buf), fh)) { + lineobj = NULL; + ptr = strchr(buf, '\n'); + if (ptr) + *ptr = 0; + + /* Check for comments or empty lines */ + switch (buf[0]) { + case PROT_REQUEST: + case PROT_EVENT: + case PROT_ERROR: + break; + case PROT_COMMENT: + case '\0': + continue; + default: + goto invalid; + } + + /* Check for space character in the fifth position */ + ptr = strchr(buf, ' '); + if (!ptr || ptr != buf + 4) + goto invalid; + + /* Duplicate the string after the space */ + lineobj = strdup(ptr + 1); + if (!lineobj) + continue; + + /* Check for a colon somewhere on the line */ + ptr = strchr(buf, ':'); + if (!ptr) + goto invalid; + + /* Compare the part before colon with the target extension name */ + *ptr = 0; + if (strcmp(buf + 5, extEntry->name)) + goto skip; + + /* Get the opcode for the request, event, or error */ + offset = strtol(buf + 1, &ptr, 10); + if (offset == 0 && ptr == buf + 1) + goto invalid; + + /* Save the strdup result in the registry */ + switch(buf[0]) { + case PROT_REQUEST: + if (extEntry->base) + RegisterRequestName(extEntry->base, offset, lineobj); + else + RegisterRequestName(offset, 0, lineobj); + continue; + case PROT_EVENT: + RegisterEventName(extEntry->eventBase + offset, lineobj); + continue; + case PROT_ERROR: + RegisterErrorName(extEntry->errorBase + offset, lineobj); + continue; + } + + invalid: + LogMessage(X_WARNING, "Invalid line in " FILENAME ", skipping\n"); + skip: + free(lineobj); + } +} + +/* + * Registration functions + */ + +void +RegisterResourceName(RESTYPE resource, char *name) +{ + resource &= TypeMask; + + while (resource >= nresource) { + if (!double_size(&resources, nresource, sizeof(char *))) + return; + nresource = nresource ? nresource * 2 : BASE_SIZE; + } + + resources[resource] = name; +} + +/* + * Lookup functions + */ + +const char * +LookupRequestName(int major, int minor) +{ + if (major >= nmajor) + return XREGISTRY_UNKNOWN; + if (minor >= nminor[major]) + return XREGISTRY_UNKNOWN; + + return requests[major][minor] ? requests[major][minor] : XREGISTRY_UNKNOWN; +} + +const char * +LookupMajorName(int major) +{ + if (major < 128) { + const char *retval; + + if (major >= nmajor) + return XREGISTRY_UNKNOWN; + if (0 >= nminor[major]) + return XREGISTRY_UNKNOWN; + + retval = requests[major][0]; + return retval ? retval + sizeof(CORE) : XREGISTRY_UNKNOWN; + } else { + ExtensionEntry *extEntry = GetExtensionEntry(major); + return extEntry ? extEntry->name : XREGISTRY_UNKNOWN; + } +} + +const char * +LookupEventName(int event) +{ + event &= 127; + if (event >= nevent) + return XREGISTRY_UNKNOWN; + + return events[event] ? events[event] : XREGISTRY_UNKNOWN; +} + +const char * +LookupErrorName(int error) +{ + if (error >= nerror) + return XREGISTRY_UNKNOWN; + + return errors[error] ? errors[error] : XREGISTRY_UNKNOWN; +} + +const char * +LookupResourceName(RESTYPE resource) +{ + resource &= TypeMask; + if (resource >= nresource) + return XREGISTRY_UNKNOWN; + + return resources[resource] ? resources[resource] : XREGISTRY_UNKNOWN; +} + +/* + * Setup and teardown + */ +void +dixResetRegistry(void) +{ + ExtensionEntry extEntry; + + /* Free all memory */ + while (nmajor--) { + while (nminor[nmajor]) + free(requests[nmajor][--nminor[nmajor]]); + free(requests[nmajor]); + } + free(requests); + free(nminor); + + while (nevent--) + free(events[nevent]); + free(events); + + while (nerror--) + free(errors[nerror]); + free(errors); + + free(resources); + + requests = NULL; + nminor = NULL; + events = NULL; + errors = NULL; + resources = NULL; + + nmajor = nevent = nerror = nresource = 0; + + /* Open the protocol file */ + if (fh) + fclose(fh); + fh = fopen(FILENAME, "r"); + if (!fh) + LogMessage(X_WARNING, "Failed to open protocol names file " FILENAME "\n"); + + /* Add built-in resources */ + 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"); + + /* Add the core protocol */ + memset(&extEntry, 0, sizeof(extEntry)); + extEntry.name = CORE; + RegisterExtensionNames(&extEntry); +} + +#endif /* XREGISTRY */ diff --git a/xorg-server/dix/resource.c b/xorg-server/dix/resource.c index 2eb1b3697..00b3368a0 100644 --- a/xorg-server/dix/resource.c +++ b/xorg-server/dix/resource.c @@ -204,7 +204,7 @@ CreateNewResourceType(DeleteType deleteFunc, char *name) if (next & lastResourceClass) return 0; - funcs = (DeleteType *)xrealloc(DeleteFuncs, + funcs = (DeleteType *)realloc(DeleteFuncs, (next + 1) * sizeof(DeleteType)); if (!funcs) return 0; @@ -252,8 +252,8 @@ InitClientResources(ClientPtr client) lastResourceClass = RC_LASTPREDEF; TypeMask = RC_LASTPREDEF - 1; if (DeleteFuncs) - xfree(DeleteFuncs); - DeleteFuncs = xalloc((lastResourceType + 1) * sizeof(DeleteType)); + free(DeleteFuncs); + DeleteFuncs = malloc((lastResourceType + 1) * sizeof(DeleteType)); if (!DeleteFuncs) return FALSE; DeleteFuncs[RT_NONE & TypeMask] = (DeleteType)NoopDDA; @@ -268,7 +268,7 @@ InitClientResources(ClientPtr client) DeleteFuncs[RT_PASSIVEGRAB & TypeMask] = DeletePassiveGrab; } clientTable[i = client->index].resources = - xalloc(INITBUCKETS*sizeof(ResourcePtr)); + malloc(INITBUCKETS*sizeof(ResourcePtr)); if (!clientTable[i].resources) return FALSE; clientTable[i].buckets = INITBUCKETS; @@ -459,7 +459,7 @@ AddResource(XID id, RESTYPE type, pointer value) (rrec->hashsize < MAXHASHSIZE)) RebuildTable(client); head = &rrec->resources[Hash(client, id)]; - res = xalloc(sizeof(ResourceRec)); + res = malloc(sizeof(ResourceRec)); if (!res) { (*DeleteFuncs[type & TypeMask])(value, id); @@ -491,13 +491,13 @@ RebuildTable(int client) */ j = 2 * clientTable[client].buckets; - tails = xalloc(j * sizeof(ResourcePtr *)); + tails = malloc(j * sizeof(ResourcePtr *)); if (!tails) return; - resources = xalloc(j * sizeof(ResourcePtr)); + resources = malloc(j * sizeof(ResourcePtr)); if (!resources) { - xfree(tails); + free(tails); return; } for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) @@ -520,9 +520,9 @@ RebuildTable(int client) *tptr = &res->next; } } - xfree(tails); + free(tails); clientTable[client].buckets *= 2; - xfree(clientTable[client].resources); + free(clientTable[client].resources); clientTable[client].resources = resources; } @@ -558,7 +558,7 @@ FreeResource(XID id, RESTYPE skipDeleteFuncType) if (rtype != skipDeleteFuncType) (*DeleteFuncs[rtype & TypeMask])(res->value, res->id); - xfree(res); + free(res); if (*eltptr != elements) prev = head; /* prev may no longer be valid */ } @@ -595,7 +595,7 @@ FreeResourceByType(XID id, RESTYPE type, Bool skipFree) if (!skipFree) (*DeleteFuncs[type & TypeMask])(res->value, res->id); - xfree(res); + free(res); break; } else @@ -762,7 +762,7 @@ FreeClientNeverRetainResources(ClientPtr client) elements = *eltptr; (*DeleteFuncs[rtype & TypeMask])(this->value, this->id); - xfree(this); + free(this); if (*eltptr != elements) prev = &resources[j]; /* prev may no longer be valid */ } @@ -816,10 +816,10 @@ FreeClientResources(ClientPtr client) CallResourceStateCallback(ResourceStateFreeing, this); (*DeleteFuncs[rtype & TypeMask])(this->value, this->id); - xfree(this); + free(this); } } - xfree(clientTable[client->index].resources); + free(clientTable[client->index].resources); clientTable[client->index].resources = NULL; clientTable[client->index].buckets = 0; } diff --git a/xorg-server/dix/selection.c b/xorg-server/dix/selection.c index d72f381ca..947fc8d18 100644 --- a/xorg-server/dix/selection.c +++ b/xorg-server/dix/selection.c @@ -1,313 +1,313 @@ -/************************************************************ - -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. - -********************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "windowstr.h" -#include "dixstruct.h" -#include "dispatch.h" -#include "selection.h" -#include "xace.h" - -/***************************************************************** - * Selection Stuff - * - * dixLookupSelection - * - * Selections are global to the server. The list of selections should - * not be traversed directly. Instead, use the functions listed above. - * - *****************************************************************/ - -Selection *CurrentSelections; -CallbackListPtr SelectionCallback; - -int -dixLookupSelection(Selection **result, Atom selectionName, - ClientPtr client, Mask access_mode) -{ - Selection *pSel; - int rc = BadMatch; - client->errorValue = selectionName; - - for (pSel = CurrentSelections; pSel; pSel = pSel->next) - if (pSel->selection == selectionName) - break; - - if (pSel) - rc = XaceHookSelectionAccess(client, &pSel, access_mode); - *result = pSel; - return rc; -} - -void -InitSelections(void) -{ - Selection *pSel, *pNextSel; - - pSel = CurrentSelections; - while (pSel) { - pNextSel = pSel->next; - dixFreePrivates(pSel->devPrivates); - xfree(pSel); - pSel = pNextSel; - } - - CurrentSelections = NULL; -} - -static _X_INLINE void -CallSelectionCallback(Selection *pSel, ClientPtr client, - SelectionCallbackKind kind) -{ - SelectionInfoRec info = { pSel, client, kind }; - CallCallbacks(&SelectionCallback, &info); -} - -void -DeleteWindowFromAnySelections(WindowPtr pWin) -{ - Selection *pSel; - - for (pSel = CurrentSelections; pSel; pSel = pSel->next) - if (pSel->pWin == pWin) { - CallSelectionCallback(pSel, NULL, SelectionWindowDestroy); - - pSel->pWin = (WindowPtr)NULL; - pSel->window = None; - pSel->client = NullClient; - } -} - -void -DeleteClientFromAnySelections(ClientPtr client) -{ - Selection *pSel; - - for (pSel = CurrentSelections; pSel; pSel = pSel->next) - if (pSel->client == client) { - CallSelectionCallback(pSel, NULL, SelectionClientClose); - - pSel->pWin = (WindowPtr)NULL; - pSel->window = None; - pSel->client = NullClient; - } -} - -int -ProcSetSelectionOwner(ClientPtr client) -{ - WindowPtr pWin = NULL; - TimeStamp time; - Selection *pSel; - int rc; - - 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) { - rc = dixLookupWindow(&pWin, stuff->window, client, DixSetAttrAccess); - if (rc != Success) - return rc; - } - if (!ValidAtom(stuff->selection)) { - client->errorValue = stuff->selection; - return BadAtom; - } - - /* - * First, see if the selection is already set... - */ - rc = dixLookupSelection(&pSel, stuff->selection, client, DixSetAttrAccess); - - if (rc == Success) { - 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, pSel->lastTimeChanged) == EARLIER) - return Success; - if (pSel->client && (!pWin || (pSel->client != client))) - { - event.u.u.type = SelectionClear; - event.u.selectionClear.time = time.milliseconds; - event.u.selectionClear.window = pSel->window; - event.u.selectionClear.atom = pSel->selection; - TryClientEvents(pSel->client, NULL, &event, 1, NoEventMask, - NoEventMask /* CantBeFiltered */, NullGrab); - } - } - else if (rc == BadMatch) - { - /* - * It doesn't exist, so add it... - */ - pSel = xalloc(sizeof(Selection)); - if (!pSel) - return BadAlloc; - - pSel->selection = stuff->selection; - pSel->devPrivates = NULL; - - /* security creation/labeling check */ - rc = XaceHookSelectionAccess(client, &pSel, - DixCreateAccess|DixSetAttrAccess); - if (rc != Success) { - xfree(pSel); - return rc; - } - - pSel->next = CurrentSelections; - CurrentSelections = pSel; - } - else - return rc; - - pSel->lastTimeChanged = time; - pSel->window = stuff->window; - pSel->pWin = pWin; - pSel->client = (pWin ? client : NullClient); - - CallSelectionCallback(pSel, client, SelectionSetOwner); - return client->noClientException; -} - -int -ProcGetSelectionOwner(ClientPtr client) -{ - int rc; - Selection *pSel; - xGetSelectionOwnerReply reply; - - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - if (!ValidAtom(stuff->id)) { - client->errorValue = stuff->id; - return BadAtom; - } - - memset(&reply, 0, sizeof(xGetSelectionOwnerReply)); - reply.type = X_Reply; - reply.length = 0; - reply.sequenceNumber = client->sequence; - - rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess); - if (rc == Success) - reply.owner = pSel->window; - else if (rc == BadMatch) - reply.owner = None; - else - return rc; - - WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply); - return client->noClientException; -} - -int -ProcConvertSelection(ClientPtr client) -{ - Bool paramsOkay; - xEvent event; - WindowPtr pWin; - Selection *pSel; - int rc; - - REQUEST(xConvertSelectionReq); - REQUEST_SIZE_MATCH(xConvertSelectionReq); - - rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target); - paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property); - if (!paramsOkay) { - client->errorValue = stuff->property; - return BadAtom; - } - - rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess); - - memset(&event, 0, sizeof(xEvent)); - if (rc != Success && rc != BadMatch) - return rc; - else if (rc == Success && pSel->window != None) { - event.u.u.type = SelectionRequest; - event.u.selectionRequest.owner = pSel->window; - event.u.selectionRequest.time = stuff->time; - 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(pSel->client, NULL, &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; - TryClientEvents(client, NULL, &event, 1, NoEventMask, - NoEventMask /* CantBeFiltered */, NullGrab); - return client->noClientException; -} +/************************************************************ + +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. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "windowstr.h" +#include "dixstruct.h" +#include "dispatch.h" +#include "selection.h" +#include "xace.h" + +/***************************************************************** + * Selection Stuff + * + * dixLookupSelection + * + * Selections are global to the server. The list of selections should + * not be traversed directly. Instead, use the functions listed above. + * + *****************************************************************/ + +Selection *CurrentSelections; +CallbackListPtr SelectionCallback; + +int +dixLookupSelection(Selection **result, Atom selectionName, + ClientPtr client, Mask access_mode) +{ + Selection *pSel; + int rc = BadMatch; + client->errorValue = selectionName; + + for (pSel = CurrentSelections; pSel; pSel = pSel->next) + if (pSel->selection == selectionName) + break; + + if (pSel) + rc = XaceHookSelectionAccess(client, &pSel, access_mode); + *result = pSel; + return rc; +} + +void +InitSelections(void) +{ + Selection *pSel, *pNextSel; + + pSel = CurrentSelections; + while (pSel) { + pNextSel = pSel->next; + dixFreePrivates(pSel->devPrivates); + free(pSel); + pSel = pNextSel; + } + + CurrentSelections = NULL; +} + +static _X_INLINE void +CallSelectionCallback(Selection *pSel, ClientPtr client, + SelectionCallbackKind kind) +{ + SelectionInfoRec info = { pSel, client, kind }; + CallCallbacks(&SelectionCallback, &info); +} + +void +DeleteWindowFromAnySelections(WindowPtr pWin) +{ + Selection *pSel; + + for (pSel = CurrentSelections; pSel; pSel = pSel->next) + if (pSel->pWin == pWin) { + CallSelectionCallback(pSel, NULL, SelectionWindowDestroy); + + pSel->pWin = (WindowPtr)NULL; + pSel->window = None; + pSel->client = NullClient; + } +} + +void +DeleteClientFromAnySelections(ClientPtr client) +{ + Selection *pSel; + + for (pSel = CurrentSelections; pSel; pSel = pSel->next) + if (pSel->client == client) { + CallSelectionCallback(pSel, NULL, SelectionClientClose); + + pSel->pWin = (WindowPtr)NULL; + pSel->window = None; + pSel->client = NullClient; + } +} + +int +ProcSetSelectionOwner(ClientPtr client) +{ + WindowPtr pWin = NULL; + TimeStamp time; + Selection *pSel; + int rc; + + 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) { + rc = dixLookupWindow(&pWin, stuff->window, client, DixSetAttrAccess); + if (rc != Success) + return rc; + } + if (!ValidAtom(stuff->selection)) { + client->errorValue = stuff->selection; + return BadAtom; + } + + /* + * First, see if the selection is already set... + */ + rc = dixLookupSelection(&pSel, stuff->selection, client, DixSetAttrAccess); + + if (rc == Success) { + 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, pSel->lastTimeChanged) == EARLIER) + return Success; + if (pSel->client && (!pWin || (pSel->client != client))) + { + event.u.u.type = SelectionClear; + event.u.selectionClear.time = time.milliseconds; + event.u.selectionClear.window = pSel->window; + event.u.selectionClear.atom = pSel->selection; + TryClientEvents(pSel->client, NULL, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab); + } + } + else if (rc == BadMatch) + { + /* + * It doesn't exist, so add it... + */ + pSel = malloc(sizeof(Selection)); + if (!pSel) + return BadAlloc; + + pSel->selection = stuff->selection; + pSel->devPrivates = NULL; + + /* security creation/labeling check */ + rc = XaceHookSelectionAccess(client, &pSel, + DixCreateAccess|DixSetAttrAccess); + if (rc != Success) { + free(pSel); + return rc; + } + + pSel->next = CurrentSelections; + CurrentSelections = pSel; + } + else + return rc; + + pSel->lastTimeChanged = time; + pSel->window = stuff->window; + pSel->pWin = pWin; + pSel->client = (pWin ? client : NullClient); + + CallSelectionCallback(pSel, client, SelectionSetOwner); + return Success; +} + +int +ProcGetSelectionOwner(ClientPtr client) +{ + int rc; + Selection *pSel; + xGetSelectionOwnerReply reply; + + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + if (!ValidAtom(stuff->id)) { + client->errorValue = stuff->id; + return BadAtom; + } + + memset(&reply, 0, sizeof(xGetSelectionOwnerReply)); + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + + rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess); + if (rc == Success) + reply.owner = pSel->window; + else if (rc == BadMatch) + reply.owner = None; + else + return rc; + + WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply); + return Success; +} + +int +ProcConvertSelection(ClientPtr client) +{ + Bool paramsOkay; + xEvent event; + WindowPtr pWin; + Selection *pSel; + int rc; + + REQUEST(xConvertSelectionReq); + REQUEST_SIZE_MATCH(xConvertSelectionReq); + + rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target); + paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property); + if (!paramsOkay) { + client->errorValue = stuff->property; + return BadAtom; + } + + rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess); + + memset(&event, 0, sizeof(xEvent)); + if (rc != Success && rc != BadMatch) + return rc; + else if (rc == Success && pSel->window != None) { + event.u.u.type = SelectionRequest; + event.u.selectionRequest.owner = pSel->window; + event.u.selectionRequest.time = stuff->time; + 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(pSel->client, NULL, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab)) + return Success; + } + + 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; + TryClientEvents(client, NULL, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab); + return Success; +} diff --git a/xorg-server/dix/swaprep.c b/xorg-server/dix/swaprep.c index 12c6dbd26..936da6d1c 100644 --- a/xorg-server/dix/swaprep.c +++ b/xorg-server/dix/swaprep.c @@ -1,1308 +1,1308 @@ -/************************************************************ - -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 -#include "scrnintstr.h" -#include "swaprep.h" -#include "globals.h" - -static void SwapFontInfo(xQueryFontReply *pr); - -static void SwapCharInfo(xCharInfo *pInfo); - -static void SwapFont(xQueryFontReply *pr, Bool hasGlyphs); - -/** - * Thanks to Jack Palevich for testing and subsequently rewriting all this - * - * \param size size in bytes - */ -void -Swap32Write(ClientPtr pClient, int size, CARD32 *pbuf) -{ - int i; - char n; - - size >>= 2; - for(i = 0; i < size; i++) - /* brackets are mandatory here, because "swapl" macro expands - to several statements */ - { - swapl(&pbuf[i], n); - } - (void)WriteToClient(pClient, size << 2, (char *) pbuf); -} - -/** - * - * \param size size in bytes - */ -void -CopySwap32Write(ClientPtr pClient, int size, CARD32 *pbuf) -{ - int bufsize = size; - CARD32 *pbufT; - CARD32 *from, *to, *fromLast, *toLast; - CARD32 tmpbuf[1]; - - /* Allocate as big a buffer as we can... */ - while (!(pbufT = xalloc(bufsize))) - { - bufsize >>= 1; - if (bufsize == 4) - { - pbufT = tmpbuf; - break; - } - } - - /* convert lengths from # of bytes to # of longs */ - size >>= 2; - bufsize >>= 2; - - from = pbuf; - fromLast = from + size; - while (from < fromLast) { - int nbytes; - to = pbufT; - toLast = to + min (bufsize, fromLast - from); - nbytes = (toLast - to) << 2; - while (to < toLast) { - /* can't write "cpswapl(*from++, *to++)" because cpswapl is a macro - that evaulates its args more than once */ - cpswapl(*from, *to); - from++; - to++; - } - (void)WriteToClient (pClient, nbytes, (char *) pbufT); - } - - if (pbufT != tmpbuf) - xfree (pbufT); -} - -/** - * - * \param size size in bytes - */ -void -CopySwap16Write(ClientPtr pClient, int size, short *pbuf) -{ - int bufsize = size; - short *pbufT; - short *from, *to, *fromLast, *toLast; - short tmpbuf[2]; - - /* Allocate as big a buffer as we can... */ - while (!(pbufT = xalloc(bufsize))) - { - bufsize >>= 1; - if (bufsize == 4) - { - pbufT = tmpbuf; - break; - } - } - - /* convert lengths from # of bytes to # of shorts */ - size >>= 1; - bufsize >>= 1; - - from = pbuf; - fromLast = from + size; - while (from < fromLast) { - int nbytes; - to = pbufT; - toLast = to + min (bufsize, fromLast - from); - nbytes = (toLast - to) << 1; - while (to < toLast) { - /* can't write "cpswaps(*from++, *to++)" because cpswaps is a macro - that evaulates its args more than once */ - cpswaps(*from, *to); - from++; - to++; - } - (void)WriteToClient (pClient, nbytes, (char *) pbufT); - } - - if (pbufT != tmpbuf) - xfree (pbufT); -} - - -/* Extra-small reply */ -void -SGenericReply(ClientPtr pClient, int size, xGenericReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -/* Extra-large reply */ -void -SGetWindowAttributesReply(ClientPtr pClient, int size, - xGetWindowAttributesReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swapl(&pRep->visualID, n); - swaps(&pRep->class, n); - swapl(&pRep->backingBitPlanes, n); - swapl(&pRep->backingPixel, n); - swapl(&pRep->colormap, n); - swapl(&pRep->allEventMasks, n); - swapl(&pRep->yourEventMask, n); - swaps(&pRep->doNotPropagateMask, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetGeometryReply(ClientPtr pClient, int size, xGetGeometryReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->root, n); - swaps(&pRep->x, n); - swaps(&pRep->y, n); - swaps(&pRep->width, n); - swaps(&pRep->height, n); - swaps(&pRep->borderWidth, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SQueryTreeReply(ClientPtr pClient, int size, xQueryTreeReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swapl(&pRep->root, n); - swapl(&pRep->parent, n); - swaps(&pRep->nChildren, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SInternAtomReply(ClientPtr pClient, int size, xInternAtomReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->atom, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetAtomNameReply(ClientPtr pClient, int size, xGetAtomNameReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swaps(&pRep->nameLength, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - - -void -SGetPropertyReply(ClientPtr pClient, int size, xGetPropertyReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swapl(&pRep->propertyType, n); - swapl(&pRep->bytesAfter, n); - swapl(&pRep->nItems, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SListPropertiesReply(ClientPtr pClient, int size, xListPropertiesReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swaps(&pRep->nProperties, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetSelectionOwnerReply(ClientPtr pClient, int size, - xGetSelectionOwnerReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->owner, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - - -void -SQueryPointerReply(ClientPtr pClient, int size, xQueryPointerReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->root, n); - swapl(&pRep->child, n); - swaps(&pRep->rootX, n); - swaps(&pRep->rootY, n); - swaps(&pRep->winX, n); - swaps(&pRep->winY, n); - swaps(&pRep->mask, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -static void -SwapTimecoord(xTimecoord* pCoord) -{ - char n; - - swapl(&pCoord->time, n); - swaps(&pCoord->x, n); - swaps(&pCoord->y, n); -} - -void -SwapTimeCoordWrite(ClientPtr pClient, int size, xTimecoord *pRep) -{ - int i, n; - xTimecoord *pRepT; - - n = size / sizeof(xTimecoord); - pRepT = pRep; - for(i = 0; i < n; i++) - { - SwapTimecoord(pRepT); - pRepT++; - } - (void)WriteToClient(pClient, size, (char *) pRep); - -} -void -SGetMotionEventsReply(ClientPtr pClient, int size, xGetMotionEventsReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swapl(&pRep->nEvents, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -STranslateCoordsReply(ClientPtr pClient, int size, xTranslateCoordsReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->child, n); - swaps(&pRep->dstX, n); - swaps(&pRep->dstY, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetInputFocusReply(ClientPtr pClient, int size, xGetInputFocusReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->focus, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -/* extra long reply */ -void -SQueryKeymapReply(ClientPtr pClient, int size, xQueryKeymapReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -static void -SwapCharInfo(xCharInfo *pInfo) -{ - char n; - - swaps(&pInfo->leftSideBearing, n); - swaps(&pInfo->rightSideBearing, n); - swaps(&pInfo->characterWidth, n); - swaps(&pInfo->ascent, n); - swaps(&pInfo->descent, n); - swaps(&pInfo->attributes, n); -} - -static void -SwapFontInfo(xQueryFontReply *pr) -{ - char n; - - swaps(&pr->minCharOrByte2, n); - swaps(&pr->maxCharOrByte2, n); - swaps(&pr->defaultChar, n); - swaps(&pr->nFontProps, n); - swaps(&pr->fontAscent, n); - swaps(&pr->fontDescent, n); - SwapCharInfo( &pr->minBounds); - SwapCharInfo( &pr->maxBounds); - swapl(&pr->nCharInfos, n); -} - -static void -SwapFont(xQueryFontReply *pr, Bool hasGlyphs) -{ - unsigned i; - xCharInfo * pxci; - unsigned nchars, nprops; - char *pby; - char n; - - swaps(&pr->sequenceNumber, n); - swapl(&pr->length, n); - nchars = pr->nCharInfos; - nprops = pr->nFontProps; - SwapFontInfo(pr); - pby = (char *) &pr[1]; - /* Font properties are an atom and either an int32 or a CARD32, so - * they are always 2 4 byte values */ - for(i = 0; i < nprops; i++) - { - swapl(pby, n); - pby += 4; - swapl(pby, n); - pby += 4; - } - if (hasGlyphs) - { - pxci = (xCharInfo *)pby; - for(i = 0; i< nchars; i++, pxci++) - SwapCharInfo(pxci); - } -} - -void -SQueryFontReply(ClientPtr pClient, int size, xQueryFontReply *pRep) -{ - SwapFont(pRep, TRUE); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SQueryTextExtentsReply(ClientPtr pClient, int size, xQueryTextExtentsReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swaps(&pRep->fontAscent, n); - swaps(&pRep->fontDescent, n); - swaps(&pRep->overallAscent, n); - swaps(&pRep->overallDescent, n); - swapl(&pRep->overallWidth, n); - swapl(&pRep->overallLeft, n); - swapl(&pRep->overallRight, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SListFontsReply(ClientPtr pClient, int size, xListFontsReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swaps(&pRep->nFonts, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SListFontsWithInfoReply(ClientPtr pClient, int size, - xListFontsWithInfoReply *pRep) -{ - SwapFont((xQueryFontReply *)pRep, FALSE); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetFontPathReply(ClientPtr pClient, int size, xGetFontPathReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swaps(&pRep->nPaths, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetImageReply(ClientPtr pClient, int size, xGetImageReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swapl(&pRep->visual, n); - (void)WriteToClient(pClient, size, (char *) pRep); - /* Fortunately, image doesn't need swapping */ -} - -void -SListInstalledColormapsReply(ClientPtr pClient, int size, - xListInstalledColormapsReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swaps(&pRep->nColormaps, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SAllocColorReply(ClientPtr pClient, int size, xAllocColorReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swaps(&pRep->red, n); - swaps(&pRep->green, n); - swaps(&pRep->blue, n); - swapl(&pRep->pixel, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SAllocNamedColorReply(ClientPtr pClient, int size, xAllocNamedColorReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->pixel, n); - swaps(&pRep->exactRed, n); - swaps(&pRep->exactGreen, n); - swaps(&pRep->exactBlue, n); - swaps(&pRep->screenRed, n); - swaps(&pRep->screenGreen, n); - swaps(&pRep->screenBlue, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SAllocColorCellsReply(ClientPtr pClient, int size, xAllocColorCellsReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swaps(&pRep->nPixels, n); - swaps(&pRep->nMasks, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - - -void -SAllocColorPlanesReply(ClientPtr pClient, int size, xAllocColorPlanesReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swaps(&pRep->nPixels, n); - swapl(&pRep->redMask, n); - swapl(&pRep->greenMask, n); - swapl(&pRep->blueMask, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -static void -SwapRGB(xrgb *prgb) -{ - char n; - - swaps(&prgb->red, n); - swaps(&prgb->green, n); - swaps(&prgb->blue, n); -} - -void -SQColorsExtend(ClientPtr pClient, int size, xrgb *prgb) -{ - int i, n; - xrgb *prgbT; - - n = size / sizeof(xrgb); - prgbT = prgb; - for(i = 0; i < n; i++) - { - SwapRGB(prgbT); - prgbT++; - } - (void)WriteToClient(pClient, size, (char *) prgb); -} - -void -SQueryColorsReply(ClientPtr pClient, int size, xQueryColorsReply* pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swaps(&pRep->nColors, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SLookupColorReply(ClientPtr pClient, int size, xLookupColorReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swaps(&pRep->exactRed, n); - swaps(&pRep->exactGreen, n); - swaps(&pRep->exactBlue, n); - swaps(&pRep->screenRed, n); - swaps(&pRep->screenGreen, n); - swaps(&pRep->screenBlue, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SQueryBestSizeReply(ClientPtr pClient, int size, xQueryBestSizeReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swaps(&pRep->width, n); - swaps(&pRep->height, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SListExtensionsReply(ClientPtr pClient, int size, xListExtensionsReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetKeyboardMappingReply(ClientPtr pClient, int size, - xGetKeyboardMappingReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetPointerMappingReply(ClientPtr pClient, int size, - xGetPointerMappingReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetModifierMappingReply(ClientPtr pClient, int size, - xGetModifierMappingReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetKeyboardControlReply(ClientPtr pClient, int size, xGetKeyboardControlReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swapl(&pRep->ledMask, n); - swaps(&pRep->bellPitch, n); - swaps(&pRep->bellDuration, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetPointerControlReply(ClientPtr pClient, int size, xGetPointerControlReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swaps(&pRep->accelNumerator, n); - swaps(&pRep->accelDenominator, n); - swaps(&pRep->threshold, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SGetScreenSaverReply(ClientPtr pClient, int size, xGetScreenSaverReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swaps(&pRep->timeout, n); - swaps(&pRep->interval, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - -void -SLHostsExtend(ClientPtr pClient, int size, char *buf) -{ - char *bufT = buf; - char *endbuf = buf + size; - while (bufT < endbuf) { - xHostEntry *host = (xHostEntry *) bufT; - int len = host->length; - char n; - swaps (&host->length, n); - bufT += sizeof (xHostEntry) + pad_to_int32(len); - } - (void)WriteToClient (pClient, size, buf); -} - -void -SListHostsReply(ClientPtr pClient, int size, xListHostsReply *pRep) -{ - char n; - - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swaps(&pRep->nHosts, n); - (void)WriteToClient(pClient, size, (char *) pRep); -} - - - -void -SErrorEvent(xError *from, xError *to) -{ - to->type = X_Error; - to->errorCode = from->errorCode; - cpswaps(from->sequenceNumber, to->sequenceNumber); - cpswapl(from->resourceID, to->resourceID); - cpswaps(from->minorCode, to->minorCode); - to->majorCode = from->majorCode; -} - -void -SKeyButtonPtrEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - to->u.u.detail = from->u.u.detail; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.keyButtonPointer.time, - to->u.keyButtonPointer.time); - cpswapl(from->u.keyButtonPointer.root, - to->u.keyButtonPointer.root); - cpswapl(from->u.keyButtonPointer.event, - to->u.keyButtonPointer.event); - cpswapl(from->u.keyButtonPointer.child, - to->u.keyButtonPointer.child); - cpswaps(from->u.keyButtonPointer.rootX, - to->u.keyButtonPointer.rootX); - cpswaps(from->u.keyButtonPointer.rootY, - to->u.keyButtonPointer.rootY); - cpswaps(from->u.keyButtonPointer.eventX, - to->u.keyButtonPointer.eventX); - cpswaps(from->u.keyButtonPointer.eventY, - to->u.keyButtonPointer.eventY); - cpswaps(from->u.keyButtonPointer.state, - to->u.keyButtonPointer.state); - to->u.keyButtonPointer.sameScreen = - from->u.keyButtonPointer.sameScreen; -} - -void -SEnterLeaveEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - to->u.u.detail = from->u.u.detail; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.enterLeave.time, to->u.enterLeave.time); - cpswapl(from->u.enterLeave.root, to->u.enterLeave.root); - cpswapl(from->u.enterLeave.event, to->u.enterLeave.event); - cpswapl(from->u.enterLeave.child, to->u.enterLeave.child); - cpswaps(from->u.enterLeave.rootX, to->u.enterLeave.rootX); - cpswaps(from->u.enterLeave.rootY, to->u.enterLeave.rootY); - cpswaps(from->u.enterLeave.eventX, to->u.enterLeave.eventX); - cpswaps(from->u.enterLeave.eventY, to->u.enterLeave.eventY); - cpswaps(from->u.enterLeave.state, to->u.enterLeave.state); - to->u.enterLeave.mode = from->u.enterLeave.mode; - to->u.enterLeave.flags = from->u.enterLeave.flags; -} - -void -SFocusEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - to->u.u.detail = from->u.u.detail; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.focus.window, to->u.focus.window); - to->u.focus.mode = from->u.focus.mode; -} - -void -SExposeEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.expose.window, to->u.expose.window); - cpswaps(from->u.expose.x, to->u.expose.x); - cpswaps(from->u.expose.y, to->u.expose.y); - cpswaps(from->u.expose.width, to->u.expose.width); - cpswaps(from->u.expose.height, to->u.expose.height); - cpswaps(from->u.expose.count, to->u.expose.count); -} - -void -SGraphicsExposureEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.graphicsExposure.drawable, - to->u.graphicsExposure.drawable); - cpswaps(from->u.graphicsExposure.x, - to->u.graphicsExposure.x); - cpswaps(from->u.graphicsExposure.y, - to->u.graphicsExposure.y); - cpswaps(from->u.graphicsExposure.width, - to->u.graphicsExposure.width); - cpswaps(from->u.graphicsExposure.height, - to->u.graphicsExposure.height); - cpswaps(from->u.graphicsExposure.minorEvent, - to->u.graphicsExposure.minorEvent); - cpswaps(from->u.graphicsExposure.count, - to->u.graphicsExposure.count); - to->u.graphicsExposure.majorEvent = - from->u.graphicsExposure.majorEvent; -} - -void -SNoExposureEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.noExposure.drawable, to->u.noExposure.drawable); - cpswaps(from->u.noExposure.minorEvent, to->u.noExposure.minorEvent); - to->u.noExposure.majorEvent = from->u.noExposure.majorEvent; -} - -void -SVisibilityEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.visibility.window, to->u.visibility.window); - to->u.visibility.state = from->u.visibility.state; -} - -void -SCreateNotifyEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.createNotify.window, to->u.createNotify.window); - cpswapl(from->u.createNotify.parent, to->u.createNotify.parent); - cpswaps(from->u.createNotify.x, to->u.createNotify.x); - cpswaps(from->u.createNotify.y, to->u.createNotify.y); - cpswaps(from->u.createNotify.width, to->u.createNotify.width); - cpswaps(from->u.createNotify.height, to->u.createNotify.height); - cpswaps(from->u.createNotify.borderWidth, - to->u.createNotify.borderWidth); - to->u.createNotify.override = from->u.createNotify.override; -} - -void -SDestroyNotifyEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.destroyNotify.event, to->u.destroyNotify.event); - cpswapl(from->u.destroyNotify.window, to->u.destroyNotify.window); -} - -void -SUnmapNotifyEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.unmapNotify.event, to->u.unmapNotify.event); - cpswapl(from->u.unmapNotify.window, to->u.unmapNotify.window); - to->u.unmapNotify.fromConfigure = from->u.unmapNotify.fromConfigure; -} - -void -SMapNotifyEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.mapNotify.event, to->u.mapNotify.event); - cpswapl(from->u.mapNotify.window, to->u.mapNotify.window); - to->u.mapNotify.override = from->u.mapNotify.override; -} - -void -SMapRequestEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.mapRequest.parent, to->u.mapRequest.parent); - cpswapl(from->u.mapRequest.window, to->u.mapRequest.window); -} - -void -SReparentEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.reparent.event, to->u.reparent.event); - cpswapl(from->u.reparent.window, to->u.reparent.window); - cpswapl(from->u.reparent.parent, to->u.reparent.parent); - cpswaps(from->u.reparent.x, to->u.reparent.x); - cpswaps(from->u.reparent.y, to->u.reparent.y); - to->u.reparent.override = from->u.reparent.override; -} - -void -SConfigureNotifyEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.configureNotify.event, - to->u.configureNotify.event); - cpswapl(from->u.configureNotify.window, - to->u.configureNotify.window); - cpswapl(from->u.configureNotify.aboveSibling, - to->u.configureNotify.aboveSibling); - cpswaps(from->u.configureNotify.x, to->u.configureNotify.x); - cpswaps(from->u.configureNotify.y, to->u.configureNotify.y); - cpswaps(from->u.configureNotify.width, to->u.configureNotify.width); - cpswaps(from->u.configureNotify.height, - to->u.configureNotify.height); - cpswaps(from->u.configureNotify.borderWidth, - to->u.configureNotify.borderWidth); - to->u.configureNotify.override = from->u.configureNotify.override; -} - -void -SConfigureRequestEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - to->u.u.detail = from->u.u.detail; /* actually stack-mode */ - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.configureRequest.parent, - to->u.configureRequest.parent); - cpswapl(from->u.configureRequest.window, - to->u.configureRequest.window); - cpswapl(from->u.configureRequest.sibling, - to->u.configureRequest.sibling); - cpswaps(from->u.configureRequest.x, to->u.configureRequest.x); - cpswaps(from->u.configureRequest.y, to->u.configureRequest.y); - cpswaps(from->u.configureRequest.width, - to->u.configureRequest.width); - cpswaps(from->u.configureRequest.height, - to->u.configureRequest.height); - cpswaps(from->u.configureRequest.borderWidth, - to->u.configureRequest.borderWidth); - cpswaps(from->u.configureRequest.valueMask, - to->u.configureRequest.valueMask); -} - - -void -SGravityEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.gravity.event, to->u.gravity.event); - cpswapl(from->u.gravity.window, to->u.gravity.window); - cpswaps(from->u.gravity.x, to->u.gravity.x); - cpswaps(from->u.gravity.y, to->u.gravity.y); -} - -void -SResizeRequestEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.resizeRequest.window, to->u.resizeRequest.window); - cpswaps(from->u.resizeRequest.width, to->u.resizeRequest.width); - cpswaps(from->u.resizeRequest.height, to->u.resizeRequest.height); -} - -void -SCirculateEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - to->u.u.detail = from->u.u.detail; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.circulate.event, to->u.circulate.event); - cpswapl(from->u.circulate.window, to->u.circulate.window); - cpswapl(from->u.circulate.parent, to->u.circulate.parent); - to->u.circulate.place = from->u.circulate.place; -} - -void -SPropertyEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.property.window, to->u.property.window); - cpswapl(from->u.property.atom, to->u.property.atom); - cpswapl(from->u.property.time, to->u.property.time); - to->u.property.state = from->u.property.state; -} - -void -SSelectionClearEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.selectionClear.time, to->u.selectionClear.time); - cpswapl(from->u.selectionClear.window, to->u.selectionClear.window); - cpswapl(from->u.selectionClear.atom, to->u.selectionClear.atom); -} - -void -SSelectionRequestEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.selectionRequest.time, to->u.selectionRequest.time); - cpswapl(from->u.selectionRequest.owner, - to->u.selectionRequest.owner); - cpswapl(from->u.selectionRequest.requestor, - to->u.selectionRequest.requestor); - cpswapl(from->u.selectionRequest.selection, - to->u.selectionRequest.selection); - cpswapl(from->u.selectionRequest.target, - to->u.selectionRequest.target); - cpswapl(from->u.selectionRequest.property, - to->u.selectionRequest.property); -} - -void -SSelectionNotifyEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.selectionNotify.time, to->u.selectionNotify.time); - cpswapl(from->u.selectionNotify.requestor, - to->u.selectionNotify.requestor); - cpswapl(from->u.selectionNotify.selection, - to->u.selectionNotify.selection); - cpswapl(from->u.selectionNotify.target, - to->u.selectionNotify.target); - cpswapl(from->u.selectionNotify.property, - to->u.selectionNotify.property); -} - -void -SColormapEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.colormap.window, to->u.colormap.window); - cpswapl(from->u.colormap.colormap, to->u.colormap.colormap); - to->u.colormap.new = from->u.colormap.new; - to->u.colormap.state = from->u.colormap.state; -} - -void -SMappingEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - to->u.mappingNotify.request = from->u.mappingNotify.request; - to->u.mappingNotify.firstKeyCode = - from->u.mappingNotify.firstKeyCode; - to->u.mappingNotify.count = from->u.mappingNotify.count; -} - -void -SClientMessageEvent(xEvent *from, xEvent *to) -{ - to->u.u.type = from->u.u.type; - to->u.u.detail = from->u.u.detail; /* actually format */ - cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); - cpswapl(from->u.clientMessage.window, to->u.clientMessage.window); - cpswapl(from->u.clientMessage.u.l.type, - to->u.clientMessage.u.l.type); - switch (from->u.u.detail) { - case 8: - memmove(to->u.clientMessage.u.b.bytes, - from->u.clientMessage.u.b.bytes,20); - break; - case 16: - cpswaps(from->u.clientMessage.u.s.shorts0, - to->u.clientMessage.u.s.shorts0); - cpswaps(from->u.clientMessage.u.s.shorts1, - to->u.clientMessage.u.s.shorts1); - cpswaps(from->u.clientMessage.u.s.shorts2, - to->u.clientMessage.u.s.shorts2); - cpswaps(from->u.clientMessage.u.s.shorts3, - to->u.clientMessage.u.s.shorts3); - cpswaps(from->u.clientMessage.u.s.shorts4, - to->u.clientMessage.u.s.shorts4); - cpswaps(from->u.clientMessage.u.s.shorts5, - to->u.clientMessage.u.s.shorts5); - cpswaps(from->u.clientMessage.u.s.shorts6, - to->u.clientMessage.u.s.shorts6); - cpswaps(from->u.clientMessage.u.s.shorts7, - to->u.clientMessage.u.s.shorts7); - cpswaps(from->u.clientMessage.u.s.shorts8, - to->u.clientMessage.u.s.shorts8); - cpswaps(from->u.clientMessage.u.s.shorts9, - to->u.clientMessage.u.s.shorts9); - break; - case 32: - cpswapl(from->u.clientMessage.u.l.longs0, - to->u.clientMessage.u.l.longs0); - cpswapl(from->u.clientMessage.u.l.longs1, - to->u.clientMessage.u.l.longs1); - cpswapl(from->u.clientMessage.u.l.longs2, - to->u.clientMessage.u.l.longs2); - cpswapl(from->u.clientMessage.u.l.longs3, - to->u.clientMessage.u.l.longs3); - cpswapl(from->u.clientMessage.u.l.longs4, - to->u.clientMessage.u.l.longs4); - break; - } -} - -void -SKeymapNotifyEvent(xEvent *from, xEvent *to) -{ - /* Keymap notify events are special; they have no - sequence number field, and contain entirely 8-bit data */ - *to = *from; -} - -static void -SwapConnSetup(xConnSetup *pConnSetup, xConnSetup *pConnSetupT) -{ - cpswapl(pConnSetup->release, pConnSetupT->release); - cpswapl(pConnSetup->ridBase, pConnSetupT->ridBase); - cpswapl(pConnSetup->ridMask, pConnSetupT->ridMask); - cpswapl(pConnSetup->motionBufferSize, pConnSetupT->motionBufferSize); - cpswaps(pConnSetup->nbytesVendor, pConnSetupT->nbytesVendor); - cpswaps(pConnSetup->maxRequestSize, pConnSetupT->maxRequestSize); - pConnSetupT->minKeyCode = pConnSetup->minKeyCode; - pConnSetupT->maxKeyCode = pConnSetup->maxKeyCode; - pConnSetupT->numRoots = pConnSetup->numRoots; - pConnSetupT->numFormats = pConnSetup->numFormats; - pConnSetupT->imageByteOrder = pConnSetup->imageByteOrder; - pConnSetupT->bitmapBitOrder = pConnSetup->bitmapBitOrder; - pConnSetupT->bitmapScanlineUnit = pConnSetup->bitmapScanlineUnit; - pConnSetupT->bitmapScanlinePad = pConnSetup->bitmapScanlinePad; -} - -static void -SwapWinRoot(xWindowRoot *pRoot, xWindowRoot *pRootT) -{ - cpswapl(pRoot->windowId, pRootT->windowId); - cpswapl(pRoot->defaultColormap, pRootT->defaultColormap); - cpswapl(pRoot->whitePixel, pRootT->whitePixel); - cpswapl(pRoot->blackPixel, pRootT->blackPixel); - cpswapl(pRoot->currentInputMask, pRootT->currentInputMask); - cpswaps(pRoot->pixWidth, pRootT->pixWidth); - cpswaps(pRoot->pixHeight, pRootT->pixHeight); - cpswaps(pRoot->mmWidth, pRootT->mmWidth); - cpswaps(pRoot->mmHeight, pRootT->mmHeight); - cpswaps(pRoot->minInstalledMaps, pRootT->minInstalledMaps); - cpswaps(pRoot->maxInstalledMaps, pRootT->maxInstalledMaps); - cpswapl(pRoot->rootVisualID, pRootT->rootVisualID); - pRootT->backingStore = pRoot->backingStore; - pRootT->saveUnders = pRoot->saveUnders; - pRootT->rootDepth = pRoot->rootDepth; - pRootT->nDepths = pRoot->nDepths; -} - -static void -SwapVisual(xVisualType *pVis, xVisualType *pVisT) -{ - cpswapl(pVis->visualID, pVisT->visualID); - pVisT->class = pVis->class; - pVisT->bitsPerRGB = pVis->bitsPerRGB; - cpswaps(pVis->colormapEntries, pVisT->colormapEntries); - cpswapl(pVis->redMask, pVisT->redMask); - cpswapl(pVis->greenMask, pVisT->greenMask); - cpswapl(pVis->blueMask, pVisT->blueMask); -} - -void -SwapConnSetupInfo( - char *pInfo, - char *pInfoT -) -{ - int i, j, k; - xConnSetup *pConnSetup = (xConnSetup *)pInfo; - xDepth *depth; - xWindowRoot *root; - - SwapConnSetup(pConnSetup, (xConnSetup *)pInfoT); - pInfo += sizeof(xConnSetup); - pInfoT += sizeof(xConnSetup); - - /* Copy the vendor string */ - i = pad_to_int32(pConnSetup->nbytesVendor); - memcpy(pInfoT, pInfo, i); - pInfo += i; - pInfoT += i; - - /* The Pixmap formats don't need to be swapped, just copied. */ - i = sizeof(xPixmapFormat) * pConnSetup->numFormats; - memcpy(pInfoT, pInfo, i); - pInfo += i; - pInfoT += i; - - for(i = 0; i < pConnSetup->numRoots; i++) - { - root = (xWindowRoot*)pInfo; - SwapWinRoot(root, (xWindowRoot *)pInfoT); - pInfo += sizeof(xWindowRoot); - pInfoT += sizeof(xWindowRoot); - - for(j = 0; j < root->nDepths; j++) - { - depth = (xDepth*)pInfo; - ((xDepth *)pInfoT)->depth = depth->depth; - cpswaps(depth->nVisuals, ((xDepth *)pInfoT)->nVisuals); - pInfo += sizeof(xDepth); - pInfoT += sizeof(xDepth); - for(k = 0; k < depth->nVisuals; k++) - { - SwapVisual((xVisualType *)pInfo, (xVisualType *)pInfoT); - pInfo += sizeof(xVisualType); - pInfoT += sizeof(xVisualType); - } - } - } -} - -void -WriteSConnectionInfo(ClientPtr pClient, unsigned long size, char *pInfo) -{ - char *pInfoTBase; - - pInfoTBase = xalloc(size); - if (!pInfoTBase) - { - pClient->noClientException = -1; - return; - } - SwapConnSetupInfo(pInfo, pInfoTBase); - (void)WriteToClient(pClient, (int)size, (char *) pInfoTBase); - xfree(pInfoTBase); -} - -void -SwapConnSetupPrefix(xConnSetupPrefix *pcspFrom, xConnSetupPrefix *pcspTo) -{ - pcspTo->success = pcspFrom->success; - pcspTo->lengthReason = pcspFrom->lengthReason; - cpswaps(pcspFrom->majorVersion, pcspTo->majorVersion); - cpswaps(pcspFrom->minorVersion, pcspTo->minorVersion); - cpswaps(pcspFrom->length, pcspTo->length); -} - -void -WriteSConnSetupPrefix(ClientPtr pClient, xConnSetupPrefix *pcsp) -{ - xConnSetupPrefix cspT; - - SwapConnSetupPrefix(pcsp, &cspT); - (void)WriteToClient(pClient, sizeof(cspT), (char *) &cspT); -} - -/* - * Dummy entry for ReplySwapVector[] - */ - -void -ReplyNotSwappd( - ClientPtr pClient , - int size , - void * pbuf - ) -{ - FatalError("Not implemented"); -} - +/************************************************************ + +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 +#include "scrnintstr.h" +#include "swaprep.h" +#include "globals.h" + +static void SwapFontInfo(xQueryFontReply *pr); + +static void SwapCharInfo(xCharInfo *pInfo); + +static void SwapFont(xQueryFontReply *pr, Bool hasGlyphs); + +/** + * Thanks to Jack Palevich for testing and subsequently rewriting all this + * + * \param size size in bytes + */ +void +Swap32Write(ClientPtr pClient, int size, CARD32 *pbuf) +{ + int i; + char n; + + size >>= 2; + for(i = 0; i < size; i++) + /* brackets are mandatory here, because "swapl" macro expands + to several statements */ + { + swapl(&pbuf[i], n); + } + (void)WriteToClient(pClient, size << 2, (char *) pbuf); +} + +/** + * + * \param size size in bytes + */ +void +CopySwap32Write(ClientPtr pClient, int size, CARD32 *pbuf) +{ + int bufsize = size; + CARD32 *pbufT; + CARD32 *from, *to, *fromLast, *toLast; + CARD32 tmpbuf[1]; + + /* Allocate as big a buffer as we can... */ + while (!(pbufT = malloc(bufsize))) + { + bufsize >>= 1; + if (bufsize == 4) + { + pbufT = tmpbuf; + break; + } + } + + /* convert lengths from # of bytes to # of longs */ + size >>= 2; + bufsize >>= 2; + + from = pbuf; + fromLast = from + size; + while (from < fromLast) { + int nbytes; + to = pbufT; + toLast = to + min (bufsize, fromLast - from); + nbytes = (toLast - to) << 2; + while (to < toLast) { + /* can't write "cpswapl(*from++, *to++)" because cpswapl is a macro + that evaulates its args more than once */ + cpswapl(*from, *to); + from++; + to++; + } + (void)WriteToClient (pClient, nbytes, (char *) pbufT); + } + + if (pbufT != tmpbuf) + free(pbufT); +} + +/** + * + * \param size size in bytes + */ +void +CopySwap16Write(ClientPtr pClient, int size, short *pbuf) +{ + int bufsize = size; + short *pbufT; + short *from, *to, *fromLast, *toLast; + short tmpbuf[2]; + + /* Allocate as big a buffer as we can... */ + while (!(pbufT = malloc(bufsize))) + { + bufsize >>= 1; + if (bufsize == 4) + { + pbufT = tmpbuf; + break; + } + } + + /* convert lengths from # of bytes to # of shorts */ + size >>= 1; + bufsize >>= 1; + + from = pbuf; + fromLast = from + size; + while (from < fromLast) { + int nbytes; + to = pbufT; + toLast = to + min (bufsize, fromLast - from); + nbytes = (toLast - to) << 1; + while (to < toLast) { + /* can't write "cpswaps(*from++, *to++)" because cpswaps is a macro + that evaulates its args more than once */ + cpswaps(*from, *to); + from++; + to++; + } + (void)WriteToClient (pClient, nbytes, (char *) pbufT); + } + + if (pbufT != tmpbuf) + free(pbufT); +} + + +/* Extra-small reply */ +void +SGenericReply(ClientPtr pClient, int size, xGenericReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +/* Extra-large reply */ +void +SGetWindowAttributesReply(ClientPtr pClient, int size, + xGetWindowAttributesReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swapl(&pRep->visualID, n); + swaps(&pRep->class, n); + swapl(&pRep->backingBitPlanes, n); + swapl(&pRep->backingPixel, n); + swapl(&pRep->colormap, n); + swapl(&pRep->allEventMasks, n); + swapl(&pRep->yourEventMask, n); + swaps(&pRep->doNotPropagateMask, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetGeometryReply(ClientPtr pClient, int size, xGetGeometryReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->root, n); + swaps(&pRep->x, n); + swaps(&pRep->y, n); + swaps(&pRep->width, n); + swaps(&pRep->height, n); + swaps(&pRep->borderWidth, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SQueryTreeReply(ClientPtr pClient, int size, xQueryTreeReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swapl(&pRep->root, n); + swapl(&pRep->parent, n); + swaps(&pRep->nChildren, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SInternAtomReply(ClientPtr pClient, int size, xInternAtomReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->atom, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetAtomNameReply(ClientPtr pClient, int size, xGetAtomNameReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swaps(&pRep->nameLength, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + + +void +SGetPropertyReply(ClientPtr pClient, int size, xGetPropertyReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swapl(&pRep->propertyType, n); + swapl(&pRep->bytesAfter, n); + swapl(&pRep->nItems, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SListPropertiesReply(ClientPtr pClient, int size, xListPropertiesReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swaps(&pRep->nProperties, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetSelectionOwnerReply(ClientPtr pClient, int size, + xGetSelectionOwnerReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->owner, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + + +void +SQueryPointerReply(ClientPtr pClient, int size, xQueryPointerReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->root, n); + swapl(&pRep->child, n); + swaps(&pRep->rootX, n); + swaps(&pRep->rootY, n); + swaps(&pRep->winX, n); + swaps(&pRep->winY, n); + swaps(&pRep->mask, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +static void +SwapTimecoord(xTimecoord* pCoord) +{ + char n; + + swapl(&pCoord->time, n); + swaps(&pCoord->x, n); + swaps(&pCoord->y, n); +} + +void +SwapTimeCoordWrite(ClientPtr pClient, int size, xTimecoord *pRep) +{ + int i, n; + xTimecoord *pRepT; + + n = size / sizeof(xTimecoord); + pRepT = pRep; + for(i = 0; i < n; i++) + { + SwapTimecoord(pRepT); + pRepT++; + } + (void)WriteToClient(pClient, size, (char *) pRep); + +} +void +SGetMotionEventsReply(ClientPtr pClient, int size, xGetMotionEventsReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swapl(&pRep->nEvents, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +STranslateCoordsReply(ClientPtr pClient, int size, xTranslateCoordsReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->child, n); + swaps(&pRep->dstX, n); + swaps(&pRep->dstY, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetInputFocusReply(ClientPtr pClient, int size, xGetInputFocusReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->focus, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +/* extra long reply */ +void +SQueryKeymapReply(ClientPtr pClient, int size, xQueryKeymapReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +static void +SwapCharInfo(xCharInfo *pInfo) +{ + char n; + + swaps(&pInfo->leftSideBearing, n); + swaps(&pInfo->rightSideBearing, n); + swaps(&pInfo->characterWidth, n); + swaps(&pInfo->ascent, n); + swaps(&pInfo->descent, n); + swaps(&pInfo->attributes, n); +} + +static void +SwapFontInfo(xQueryFontReply *pr) +{ + char n; + + swaps(&pr->minCharOrByte2, n); + swaps(&pr->maxCharOrByte2, n); + swaps(&pr->defaultChar, n); + swaps(&pr->nFontProps, n); + swaps(&pr->fontAscent, n); + swaps(&pr->fontDescent, n); + SwapCharInfo( &pr->minBounds); + SwapCharInfo( &pr->maxBounds); + swapl(&pr->nCharInfos, n); +} + +static void +SwapFont(xQueryFontReply *pr, Bool hasGlyphs) +{ + unsigned i; + xCharInfo * pxci; + unsigned nchars, nprops; + char *pby; + char n; + + swaps(&pr->sequenceNumber, n); + swapl(&pr->length, n); + nchars = pr->nCharInfos; + nprops = pr->nFontProps; + SwapFontInfo(pr); + pby = (char *) &pr[1]; + /* Font properties are an atom and either an int32 or a CARD32, so + * they are always 2 4 byte values */ + for(i = 0; i < nprops; i++) + { + swapl(pby, n); + pby += 4; + swapl(pby, n); + pby += 4; + } + if (hasGlyphs) + { + pxci = (xCharInfo *)pby; + for(i = 0; i< nchars; i++, pxci++) + SwapCharInfo(pxci); + } +} + +void +SQueryFontReply(ClientPtr pClient, int size, xQueryFontReply *pRep) +{ + SwapFont(pRep, TRUE); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SQueryTextExtentsReply(ClientPtr pClient, int size, xQueryTextExtentsReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swaps(&pRep->fontAscent, n); + swaps(&pRep->fontDescent, n); + swaps(&pRep->overallAscent, n); + swaps(&pRep->overallDescent, n); + swapl(&pRep->overallWidth, n); + swapl(&pRep->overallLeft, n); + swapl(&pRep->overallRight, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SListFontsReply(ClientPtr pClient, int size, xListFontsReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swaps(&pRep->nFonts, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SListFontsWithInfoReply(ClientPtr pClient, int size, + xListFontsWithInfoReply *pRep) +{ + SwapFont((xQueryFontReply *)pRep, FALSE); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetFontPathReply(ClientPtr pClient, int size, xGetFontPathReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swaps(&pRep->nPaths, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetImageReply(ClientPtr pClient, int size, xGetImageReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swapl(&pRep->visual, n); + (void)WriteToClient(pClient, size, (char *) pRep); + /* Fortunately, image doesn't need swapping */ +} + +void +SListInstalledColormapsReply(ClientPtr pClient, int size, + xListInstalledColormapsReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swaps(&pRep->nColormaps, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SAllocColorReply(ClientPtr pClient, int size, xAllocColorReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swaps(&pRep->red, n); + swaps(&pRep->green, n); + swaps(&pRep->blue, n); + swapl(&pRep->pixel, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SAllocNamedColorReply(ClientPtr pClient, int size, xAllocNamedColorReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->pixel, n); + swaps(&pRep->exactRed, n); + swaps(&pRep->exactGreen, n); + swaps(&pRep->exactBlue, n); + swaps(&pRep->screenRed, n); + swaps(&pRep->screenGreen, n); + swaps(&pRep->screenBlue, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SAllocColorCellsReply(ClientPtr pClient, int size, xAllocColorCellsReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swaps(&pRep->nPixels, n); + swaps(&pRep->nMasks, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + + +void +SAllocColorPlanesReply(ClientPtr pClient, int size, xAllocColorPlanesReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swaps(&pRep->nPixels, n); + swapl(&pRep->redMask, n); + swapl(&pRep->greenMask, n); + swapl(&pRep->blueMask, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +static void +SwapRGB(xrgb *prgb) +{ + char n; + + swaps(&prgb->red, n); + swaps(&prgb->green, n); + swaps(&prgb->blue, n); +} + +void +SQColorsExtend(ClientPtr pClient, int size, xrgb *prgb) +{ + int i, n; + xrgb *prgbT; + + n = size / sizeof(xrgb); + prgbT = prgb; + for(i = 0; i < n; i++) + { + SwapRGB(prgbT); + prgbT++; + } + (void)WriteToClient(pClient, size, (char *) prgb); +} + +void +SQueryColorsReply(ClientPtr pClient, int size, xQueryColorsReply* pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swaps(&pRep->nColors, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SLookupColorReply(ClientPtr pClient, int size, xLookupColorReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swaps(&pRep->exactRed, n); + swaps(&pRep->exactGreen, n); + swaps(&pRep->exactBlue, n); + swaps(&pRep->screenRed, n); + swaps(&pRep->screenGreen, n); + swaps(&pRep->screenBlue, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SQueryBestSizeReply(ClientPtr pClient, int size, xQueryBestSizeReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swaps(&pRep->width, n); + swaps(&pRep->height, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SListExtensionsReply(ClientPtr pClient, int size, xListExtensionsReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetKeyboardMappingReply(ClientPtr pClient, int size, + xGetKeyboardMappingReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetPointerMappingReply(ClientPtr pClient, int size, + xGetPointerMappingReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetModifierMappingReply(ClientPtr pClient, int size, + xGetModifierMappingReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetKeyboardControlReply(ClientPtr pClient, int size, xGetKeyboardControlReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swapl(&pRep->ledMask, n); + swaps(&pRep->bellPitch, n); + swaps(&pRep->bellDuration, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetPointerControlReply(ClientPtr pClient, int size, xGetPointerControlReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swaps(&pRep->accelNumerator, n); + swaps(&pRep->accelDenominator, n); + swaps(&pRep->threshold, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SGetScreenSaverReply(ClientPtr pClient, int size, xGetScreenSaverReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swaps(&pRep->timeout, n); + swaps(&pRep->interval, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + +void +SLHostsExtend(ClientPtr pClient, int size, char *buf) +{ + char *bufT = buf; + char *endbuf = buf + size; + while (bufT < endbuf) { + xHostEntry *host = (xHostEntry *) bufT; + int len = host->length; + char n; + swaps (&host->length, n); + bufT += sizeof (xHostEntry) + pad_to_int32(len); + } + (void)WriteToClient (pClient, size, buf); +} + +void +SListHostsReply(ClientPtr pClient, int size, xListHostsReply *pRep) +{ + char n; + + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swaps(&pRep->nHosts, n); + (void)WriteToClient(pClient, size, (char *) pRep); +} + + + +void +SErrorEvent(xError *from, xError *to) +{ + to->type = X_Error; + to->errorCode = from->errorCode; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->resourceID, to->resourceID); + cpswaps(from->minorCode, to->minorCode); + to->majorCode = from->majorCode; +} + +void +SKeyButtonPtrEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + to->u.u.detail = from->u.u.detail; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.keyButtonPointer.time, + to->u.keyButtonPointer.time); + cpswapl(from->u.keyButtonPointer.root, + to->u.keyButtonPointer.root); + cpswapl(from->u.keyButtonPointer.event, + to->u.keyButtonPointer.event); + cpswapl(from->u.keyButtonPointer.child, + to->u.keyButtonPointer.child); + cpswaps(from->u.keyButtonPointer.rootX, + to->u.keyButtonPointer.rootX); + cpswaps(from->u.keyButtonPointer.rootY, + to->u.keyButtonPointer.rootY); + cpswaps(from->u.keyButtonPointer.eventX, + to->u.keyButtonPointer.eventX); + cpswaps(from->u.keyButtonPointer.eventY, + to->u.keyButtonPointer.eventY); + cpswaps(from->u.keyButtonPointer.state, + to->u.keyButtonPointer.state); + to->u.keyButtonPointer.sameScreen = + from->u.keyButtonPointer.sameScreen; +} + +void +SEnterLeaveEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + to->u.u.detail = from->u.u.detail; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.enterLeave.time, to->u.enterLeave.time); + cpswapl(from->u.enterLeave.root, to->u.enterLeave.root); + cpswapl(from->u.enterLeave.event, to->u.enterLeave.event); + cpswapl(from->u.enterLeave.child, to->u.enterLeave.child); + cpswaps(from->u.enterLeave.rootX, to->u.enterLeave.rootX); + cpswaps(from->u.enterLeave.rootY, to->u.enterLeave.rootY); + cpswaps(from->u.enterLeave.eventX, to->u.enterLeave.eventX); + cpswaps(from->u.enterLeave.eventY, to->u.enterLeave.eventY); + cpswaps(from->u.enterLeave.state, to->u.enterLeave.state); + to->u.enterLeave.mode = from->u.enterLeave.mode; + to->u.enterLeave.flags = from->u.enterLeave.flags; +} + +void +SFocusEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + to->u.u.detail = from->u.u.detail; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.focus.window, to->u.focus.window); + to->u.focus.mode = from->u.focus.mode; +} + +void +SExposeEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.expose.window, to->u.expose.window); + cpswaps(from->u.expose.x, to->u.expose.x); + cpswaps(from->u.expose.y, to->u.expose.y); + cpswaps(from->u.expose.width, to->u.expose.width); + cpswaps(from->u.expose.height, to->u.expose.height); + cpswaps(from->u.expose.count, to->u.expose.count); +} + +void +SGraphicsExposureEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.graphicsExposure.drawable, + to->u.graphicsExposure.drawable); + cpswaps(from->u.graphicsExposure.x, + to->u.graphicsExposure.x); + cpswaps(from->u.graphicsExposure.y, + to->u.graphicsExposure.y); + cpswaps(from->u.graphicsExposure.width, + to->u.graphicsExposure.width); + cpswaps(from->u.graphicsExposure.height, + to->u.graphicsExposure.height); + cpswaps(from->u.graphicsExposure.minorEvent, + to->u.graphicsExposure.minorEvent); + cpswaps(from->u.graphicsExposure.count, + to->u.graphicsExposure.count); + to->u.graphicsExposure.majorEvent = + from->u.graphicsExposure.majorEvent; +} + +void +SNoExposureEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.noExposure.drawable, to->u.noExposure.drawable); + cpswaps(from->u.noExposure.minorEvent, to->u.noExposure.minorEvent); + to->u.noExposure.majorEvent = from->u.noExposure.majorEvent; +} + +void +SVisibilityEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.visibility.window, to->u.visibility.window); + to->u.visibility.state = from->u.visibility.state; +} + +void +SCreateNotifyEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.createNotify.window, to->u.createNotify.window); + cpswapl(from->u.createNotify.parent, to->u.createNotify.parent); + cpswaps(from->u.createNotify.x, to->u.createNotify.x); + cpswaps(from->u.createNotify.y, to->u.createNotify.y); + cpswaps(from->u.createNotify.width, to->u.createNotify.width); + cpswaps(from->u.createNotify.height, to->u.createNotify.height); + cpswaps(from->u.createNotify.borderWidth, + to->u.createNotify.borderWidth); + to->u.createNotify.override = from->u.createNotify.override; +} + +void +SDestroyNotifyEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.destroyNotify.event, to->u.destroyNotify.event); + cpswapl(from->u.destroyNotify.window, to->u.destroyNotify.window); +} + +void +SUnmapNotifyEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.unmapNotify.event, to->u.unmapNotify.event); + cpswapl(from->u.unmapNotify.window, to->u.unmapNotify.window); + to->u.unmapNotify.fromConfigure = from->u.unmapNotify.fromConfigure; +} + +void +SMapNotifyEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.mapNotify.event, to->u.mapNotify.event); + cpswapl(from->u.mapNotify.window, to->u.mapNotify.window); + to->u.mapNotify.override = from->u.mapNotify.override; +} + +void +SMapRequestEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.mapRequest.parent, to->u.mapRequest.parent); + cpswapl(from->u.mapRequest.window, to->u.mapRequest.window); +} + +void +SReparentEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.reparent.event, to->u.reparent.event); + cpswapl(from->u.reparent.window, to->u.reparent.window); + cpswapl(from->u.reparent.parent, to->u.reparent.parent); + cpswaps(from->u.reparent.x, to->u.reparent.x); + cpswaps(from->u.reparent.y, to->u.reparent.y); + to->u.reparent.override = from->u.reparent.override; +} + +void +SConfigureNotifyEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.configureNotify.event, + to->u.configureNotify.event); + cpswapl(from->u.configureNotify.window, + to->u.configureNotify.window); + cpswapl(from->u.configureNotify.aboveSibling, + to->u.configureNotify.aboveSibling); + cpswaps(from->u.configureNotify.x, to->u.configureNotify.x); + cpswaps(from->u.configureNotify.y, to->u.configureNotify.y); + cpswaps(from->u.configureNotify.width, to->u.configureNotify.width); + cpswaps(from->u.configureNotify.height, + to->u.configureNotify.height); + cpswaps(from->u.configureNotify.borderWidth, + to->u.configureNotify.borderWidth); + to->u.configureNotify.override = from->u.configureNotify.override; +} + +void +SConfigureRequestEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + to->u.u.detail = from->u.u.detail; /* actually stack-mode */ + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.configureRequest.parent, + to->u.configureRequest.parent); + cpswapl(from->u.configureRequest.window, + to->u.configureRequest.window); + cpswapl(from->u.configureRequest.sibling, + to->u.configureRequest.sibling); + cpswaps(from->u.configureRequest.x, to->u.configureRequest.x); + cpswaps(from->u.configureRequest.y, to->u.configureRequest.y); + cpswaps(from->u.configureRequest.width, + to->u.configureRequest.width); + cpswaps(from->u.configureRequest.height, + to->u.configureRequest.height); + cpswaps(from->u.configureRequest.borderWidth, + to->u.configureRequest.borderWidth); + cpswaps(from->u.configureRequest.valueMask, + to->u.configureRequest.valueMask); +} + + +void +SGravityEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.gravity.event, to->u.gravity.event); + cpswapl(from->u.gravity.window, to->u.gravity.window); + cpswaps(from->u.gravity.x, to->u.gravity.x); + cpswaps(from->u.gravity.y, to->u.gravity.y); +} + +void +SResizeRequestEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.resizeRequest.window, to->u.resizeRequest.window); + cpswaps(from->u.resizeRequest.width, to->u.resizeRequest.width); + cpswaps(from->u.resizeRequest.height, to->u.resizeRequest.height); +} + +void +SCirculateEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + to->u.u.detail = from->u.u.detail; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.circulate.event, to->u.circulate.event); + cpswapl(from->u.circulate.window, to->u.circulate.window); + cpswapl(from->u.circulate.parent, to->u.circulate.parent); + to->u.circulate.place = from->u.circulate.place; +} + +void +SPropertyEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.property.window, to->u.property.window); + cpswapl(from->u.property.atom, to->u.property.atom); + cpswapl(from->u.property.time, to->u.property.time); + to->u.property.state = from->u.property.state; +} + +void +SSelectionClearEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.selectionClear.time, to->u.selectionClear.time); + cpswapl(from->u.selectionClear.window, to->u.selectionClear.window); + cpswapl(from->u.selectionClear.atom, to->u.selectionClear.atom); +} + +void +SSelectionRequestEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.selectionRequest.time, to->u.selectionRequest.time); + cpswapl(from->u.selectionRequest.owner, + to->u.selectionRequest.owner); + cpswapl(from->u.selectionRequest.requestor, + to->u.selectionRequest.requestor); + cpswapl(from->u.selectionRequest.selection, + to->u.selectionRequest.selection); + cpswapl(from->u.selectionRequest.target, + to->u.selectionRequest.target); + cpswapl(from->u.selectionRequest.property, + to->u.selectionRequest.property); +} + +void +SSelectionNotifyEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.selectionNotify.time, to->u.selectionNotify.time); + cpswapl(from->u.selectionNotify.requestor, + to->u.selectionNotify.requestor); + cpswapl(from->u.selectionNotify.selection, + to->u.selectionNotify.selection); + cpswapl(from->u.selectionNotify.target, + to->u.selectionNotify.target); + cpswapl(from->u.selectionNotify.property, + to->u.selectionNotify.property); +} + +void +SColormapEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.colormap.window, to->u.colormap.window); + cpswapl(from->u.colormap.colormap, to->u.colormap.colormap); + to->u.colormap.new = from->u.colormap.new; + to->u.colormap.state = from->u.colormap.state; +} + +void +SMappingEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + to->u.mappingNotify.request = from->u.mappingNotify.request; + to->u.mappingNotify.firstKeyCode = + from->u.mappingNotify.firstKeyCode; + to->u.mappingNotify.count = from->u.mappingNotify.count; +} + +void +SClientMessageEvent(xEvent *from, xEvent *to) +{ + to->u.u.type = from->u.u.type; + to->u.u.detail = from->u.u.detail; /* actually format */ + cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber); + cpswapl(from->u.clientMessage.window, to->u.clientMessage.window); + cpswapl(from->u.clientMessage.u.l.type, + to->u.clientMessage.u.l.type); + switch (from->u.u.detail) { + case 8: + memmove(to->u.clientMessage.u.b.bytes, + from->u.clientMessage.u.b.bytes,20); + break; + case 16: + cpswaps(from->u.clientMessage.u.s.shorts0, + to->u.clientMessage.u.s.shorts0); + cpswaps(from->u.clientMessage.u.s.shorts1, + to->u.clientMessage.u.s.shorts1); + cpswaps(from->u.clientMessage.u.s.shorts2, + to->u.clientMessage.u.s.shorts2); + cpswaps(from->u.clientMessage.u.s.shorts3, + to->u.clientMessage.u.s.shorts3); + cpswaps(from->u.clientMessage.u.s.shorts4, + to->u.clientMessage.u.s.shorts4); + cpswaps(from->u.clientMessage.u.s.shorts5, + to->u.clientMessage.u.s.shorts5); + cpswaps(from->u.clientMessage.u.s.shorts6, + to->u.clientMessage.u.s.shorts6); + cpswaps(from->u.clientMessage.u.s.shorts7, + to->u.clientMessage.u.s.shorts7); + cpswaps(from->u.clientMessage.u.s.shorts8, + to->u.clientMessage.u.s.shorts8); + cpswaps(from->u.clientMessage.u.s.shorts9, + to->u.clientMessage.u.s.shorts9); + break; + case 32: + cpswapl(from->u.clientMessage.u.l.longs0, + to->u.clientMessage.u.l.longs0); + cpswapl(from->u.clientMessage.u.l.longs1, + to->u.clientMessage.u.l.longs1); + cpswapl(from->u.clientMessage.u.l.longs2, + to->u.clientMessage.u.l.longs2); + cpswapl(from->u.clientMessage.u.l.longs3, + to->u.clientMessage.u.l.longs3); + cpswapl(from->u.clientMessage.u.l.longs4, + to->u.clientMessage.u.l.longs4); + break; + } +} + +void +SKeymapNotifyEvent(xEvent *from, xEvent *to) +{ + /* Keymap notify events are special; they have no + sequence number field, and contain entirely 8-bit data */ + *to = *from; +} + +static void +SwapConnSetup(xConnSetup *pConnSetup, xConnSetup *pConnSetupT) +{ + cpswapl(pConnSetup->release, pConnSetupT->release); + cpswapl(pConnSetup->ridBase, pConnSetupT->ridBase); + cpswapl(pConnSetup->ridMask, pConnSetupT->ridMask); + cpswapl(pConnSetup->motionBufferSize, pConnSetupT->motionBufferSize); + cpswaps(pConnSetup->nbytesVendor, pConnSetupT->nbytesVendor); + cpswaps(pConnSetup->maxRequestSize, pConnSetupT->maxRequestSize); + pConnSetupT->minKeyCode = pConnSetup->minKeyCode; + pConnSetupT->maxKeyCode = pConnSetup->maxKeyCode; + pConnSetupT->numRoots = pConnSetup->numRoots; + pConnSetupT->numFormats = pConnSetup->numFormats; + pConnSetupT->imageByteOrder = pConnSetup->imageByteOrder; + pConnSetupT->bitmapBitOrder = pConnSetup->bitmapBitOrder; + pConnSetupT->bitmapScanlineUnit = pConnSetup->bitmapScanlineUnit; + pConnSetupT->bitmapScanlinePad = pConnSetup->bitmapScanlinePad; +} + +static void +SwapWinRoot(xWindowRoot *pRoot, xWindowRoot *pRootT) +{ + cpswapl(pRoot->windowId, pRootT->windowId); + cpswapl(pRoot->defaultColormap, pRootT->defaultColormap); + cpswapl(pRoot->whitePixel, pRootT->whitePixel); + cpswapl(pRoot->blackPixel, pRootT->blackPixel); + cpswapl(pRoot->currentInputMask, pRootT->currentInputMask); + cpswaps(pRoot->pixWidth, pRootT->pixWidth); + cpswaps(pRoot->pixHeight, pRootT->pixHeight); + cpswaps(pRoot->mmWidth, pRootT->mmWidth); + cpswaps(pRoot->mmHeight, pRootT->mmHeight); + cpswaps(pRoot->minInstalledMaps, pRootT->minInstalledMaps); + cpswaps(pRoot->maxInstalledMaps, pRootT->maxInstalledMaps); + cpswapl(pRoot->rootVisualID, pRootT->rootVisualID); + pRootT->backingStore = pRoot->backingStore; + pRootT->saveUnders = pRoot->saveUnders; + pRootT->rootDepth = pRoot->rootDepth; + pRootT->nDepths = pRoot->nDepths; +} + +static void +SwapVisual(xVisualType *pVis, xVisualType *pVisT) +{ + cpswapl(pVis->visualID, pVisT->visualID); + pVisT->class = pVis->class; + pVisT->bitsPerRGB = pVis->bitsPerRGB; + cpswaps(pVis->colormapEntries, pVisT->colormapEntries); + cpswapl(pVis->redMask, pVisT->redMask); + cpswapl(pVis->greenMask, pVisT->greenMask); + cpswapl(pVis->blueMask, pVisT->blueMask); +} + +void +SwapConnSetupInfo( + char *pInfo, + char *pInfoT +) +{ + int i, j, k; + xConnSetup *pConnSetup = (xConnSetup *)pInfo; + xDepth *depth; + xWindowRoot *root; + + SwapConnSetup(pConnSetup, (xConnSetup *)pInfoT); + pInfo += sizeof(xConnSetup); + pInfoT += sizeof(xConnSetup); + + /* Copy the vendor string */ + i = pad_to_int32(pConnSetup->nbytesVendor); + memcpy(pInfoT, pInfo, i); + pInfo += i; + pInfoT += i; + + /* The Pixmap formats don't need to be swapped, just copied. */ + i = sizeof(xPixmapFormat) * pConnSetup->numFormats; + memcpy(pInfoT, pInfo, i); + pInfo += i; + pInfoT += i; + + for(i = 0; i < pConnSetup->numRoots; i++) + { + root = (xWindowRoot*)pInfo; + SwapWinRoot(root, (xWindowRoot *)pInfoT); + pInfo += sizeof(xWindowRoot); + pInfoT += sizeof(xWindowRoot); + + for(j = 0; j < root->nDepths; j++) + { + depth = (xDepth*)pInfo; + ((xDepth *)pInfoT)->depth = depth->depth; + cpswaps(depth->nVisuals, ((xDepth *)pInfoT)->nVisuals); + pInfo += sizeof(xDepth); + pInfoT += sizeof(xDepth); + for(k = 0; k < depth->nVisuals; k++) + { + SwapVisual((xVisualType *)pInfo, (xVisualType *)pInfoT); + pInfo += sizeof(xVisualType); + pInfoT += sizeof(xVisualType); + } + } + } +} + +void +WriteSConnectionInfo(ClientPtr pClient, unsigned long size, char *pInfo) +{ + char *pInfoTBase; + + pInfoTBase = malloc(size); + if (!pInfoTBase) + { + pClient->noClientException = -1; + return; + } + SwapConnSetupInfo(pInfo, pInfoTBase); + (void)WriteToClient(pClient, (int)size, (char *) pInfoTBase); + free(pInfoTBase); +} + +void +SwapConnSetupPrefix(xConnSetupPrefix *pcspFrom, xConnSetupPrefix *pcspTo) +{ + pcspTo->success = pcspFrom->success; + pcspTo->lengthReason = pcspFrom->lengthReason; + cpswaps(pcspFrom->majorVersion, pcspTo->majorVersion); + cpswaps(pcspFrom->minorVersion, pcspTo->minorVersion); + cpswaps(pcspFrom->length, pcspTo->length); +} + +void +WriteSConnSetupPrefix(ClientPtr pClient, xConnSetupPrefix *pcsp) +{ + xConnSetupPrefix cspT; + + SwapConnSetupPrefix(pcsp, &cspT); + (void)WriteToClient(pClient, sizeof(cspT), (char *) &cspT); +} + +/* + * Dummy entry for ReplySwapVector[] + */ + +void +ReplyNotSwappd( + ClientPtr pClient , + int size , + void * pbuf + ) +{ + FatalError("Not implemented"); +} + diff --git a/xorg-server/dix/window.c b/xorg-server/dix/window.c index 02451fc7e..6a12c9d05 100644 --- a/xorg-server/dix/window.c +++ b/xorg-server/dix/window.c @@ -1,3888 +1,3887 @@ -/* - -Copyright (c) 2006, Red Hat, Inc. - -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. - -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 "misc.h" -#include "scrnintstr.h" -#include "os.h" -#include "regionstr.h" -#include "validate.h" -#include "windowstr.h" -#include "input.h" -#include "inputstr.h" -#include "resource.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "dixstruct.h" -#include "gcstruct.h" -#include "servermd.h" -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#include "dixevents.h" -#include "globals.h" -#include "mi.h" /* miPaintWindow */ - -#include "privates.h" -#include "xace.h" - -/****** - * Window stuff for server - * - * CreateRootWindow, CreateWindow, ChangeWindowAttributes, - * GetWindowAttributes, DeleteWindow, DestroySubWindows, - * HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows, - * UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow, - * ChangeWindowDeviceCursor - ******/ - -static unsigned char _back_lsb[4] = {0x88, 0x22, 0x44, 0x11}; -static unsigned char _back_msb[4] = {0x11, 0x44, 0x22, 0x88}; - -static Bool WindowParentHasDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - CursorPtr pCurs); -static Bool -WindowSeekDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - DevCursNodePtr* pNode, - DevCursNodePtr* pPrev); - -int screenIsSaved = SCREEN_SAVER_OFF; - -ScreenSaverStuffRec savedScreenInfo[MAXSCREENS]; - -static int FocusPrivatesKeyIndex; -DevPrivateKey FocusPrivatesKey = &FocusPrivatesKeyIndex; - -static Bool TileScreenSaver(int i, int kind); - - -#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \ - CWDontPropagate | CWOverrideRedirect | CWCursor ) - -#define BOXES_OVERLAP(b1, b2) \ - (!( ((b1)->x2 <= (b2)->x1) || \ - ( ((b1)->x1 >= (b2)->x2)) || \ - ( ((b1)->y2 <= (b2)->y1)) || \ - ( ((b1)->y1 >= (b2)->y2)) ) ) - -#define RedirectSend(pWin) \ - ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureRedirectMask) - -#define SubSend(pWin) \ - ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask) - -#define StrSend(pWin) \ - ((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask) - -#define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent)) - -#ifdef DEBUG -/****** - * PrintWindowTree - * For debugging only - ******/ - -static void -PrintChildren(WindowPtr p1, int indent) -{ - WindowPtr p2; - int i; - - while (p1) - { - p2 = p1->firstChild; - ErrorF("[dix] "); - for (i=0; idrawable.id); - miPrintRegion(&p1->clipList); - PrintChildren(p2, indent+4); - p1 = p1->nextSib; - } -} - -static void -PrintWindowTree(void) -{ - int i; - WindowPtr pWin, p1; - - for (i=0; iclipList); - p1 = pWin->firstChild; - PrintChildren(p1, 4); - } -} -#endif - -int -TraverseTree(WindowPtr pWin, VisitWindowProcPtr func, pointer data) -{ - int result; - WindowPtr pChild; - - if (!(pChild = pWin)) - return(WT_NOMATCH); - while (1) - { - result = (* func)(pChild, data); - if (result == WT_STOPWALKING) - return(WT_STOPWALKING); - if ((result == WT_WALKCHILDREN) && pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } - return(WT_NOMATCH); -} - -/***** - * WalkTree - * Walk the window tree, for SCREEN, preforming FUNC(pWin, data) on - * each window. If FUNC returns WT_WALKCHILDREN, traverse the children, - * if it returns WT_DONTWALKCHILDREN, dont. If it returns WT_STOPWALKING - * exit WalkTree. Does depth-first traverse. - *****/ - -int -WalkTree(ScreenPtr pScreen, VisitWindowProcPtr func, pointer data) -{ - return(TraverseTree(WindowTable[pScreen->myNum], func, data)); -} - -/* hack for forcing backing store on all windows */ -int defaultBackingStore = NotUseful; -/* hack to force no backing store */ -Bool disableBackingStore = FALSE; -Bool enableBackingStore = FALSE; - -static void -SetWindowToDefaults(WindowPtr pWin) -{ - pWin->prevSib = NullWindow; - pWin->firstChild = NullWindow; - pWin->lastChild = NullWindow; - - pWin->valdata = (ValidatePtr)NULL; - pWin->optional = (WindowOptPtr)NULL; - pWin->cursorIsNone = TRUE; - - pWin->backingStore = NotUseful; - pWin->DIXsaveUnder = FALSE; - pWin->backStorage = (pointer) NULL; - - pWin->mapped = FALSE; /* off */ - pWin->realized = FALSE; /* off */ - pWin->viewable = FALSE; - pWin->visibility = VisibilityNotViewable; - pWin->overrideRedirect = FALSE; - pWin->saveUnder = FALSE; - - pWin->bitGravity = ForgetGravity; - pWin->winGravity = NorthWestGravity; - - pWin->eventMask = 0; - pWin->deliverableEvents = 0; - pWin->dontPropagate = 0; - pWin->forcedBS = FALSE; - pWin->redirectDraw = RedirectDrawNone; - pWin->forcedBG = FALSE; - -#ifdef ROOTLESS - pWin->rootlessUnhittable = FALSE; -#endif -} - -static void -MakeRootTile(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - GCPtr pGC; - unsigned char back[128]; - int len = BitmapBytePad(sizeof(long)); - unsigned char *from, *to; - int i, j; - - pWin->background.pixmap = (*pScreen->CreatePixmap)(pScreen, 4, 4, - pScreen->rootDepth, 0); - - pWin->backgroundState = BackgroundPixmap; - pGC = GetScratchGC(pScreen->rootDepth, pScreen); - if (!pWin->background.pixmap || !pGC) - FatalError("could not create root tile"); - - { - CARD32 attributes[2]; - - attributes[0] = pScreen->whitePixel; - attributes[1] = pScreen->blackPixel; - - (void)ChangeGC(pGC, GCForeground | GCBackground, attributes); - } - - ValidateGC((DrawablePtr)pWin->background.pixmap, pGC); - - from = (screenInfo.bitmapBitOrder == LSBFirst) ? _back_lsb : _back_msb; - to = back; - - for (i = 4; i > 0; i--, from++) - for (j = len; j > 0; j--) - *to++ = *from; - - (*pGC->ops->PutImage)((DrawablePtr)pWin->background.pixmap, pGC, 1, - 0, 0, len, 4, 0, XYBitmap, (char *)back); - - FreeScratchGC(pGC); - -} - -/***** - * CreateRootWindow - * Makes a window at initialization time for specified screen - *****/ - -Bool -CreateRootWindow(ScreenPtr pScreen) -{ - WindowPtr pWin; - BoxRec box; - PixmapFormatRec *format; - - pWin = xalloc(sizeof(WindowRec)); - if (!pWin) - return FALSE; - - savedScreenInfo[pScreen->myNum].pWindow = NULL; - savedScreenInfo[pScreen->myNum].wid = FakeClientID(0); - savedScreenInfo[pScreen->myNum].ExternalScreenSaver = NULL; - screenIsSaved = SCREEN_SAVER_OFF; - - WindowTable[pScreen->myNum] = pWin; - - pWin->drawable.pScreen = pScreen; - pWin->drawable.type = DRAWABLE_WINDOW; - pWin->devPrivates = NULL; - - pWin->drawable.depth = pScreen->rootDepth; - for (format = screenInfo.formats; - format->depth != pScreen->rootDepth; - format++) - ; - pWin->drawable.bitsPerPixel = format->bitsPerPixel; - - pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; - - pWin->parent = NullWindow; - SetWindowToDefaults(pWin); - - pWin->optional = xalloc (sizeof (WindowOptRec)); - if (!pWin->optional) - return FALSE; - - pWin->optional->dontPropagateMask = 0; - pWin->optional->otherEventMasks = 0; - pWin->optional->otherClients = NULL; - pWin->optional->passiveGrabs = NULL; - pWin->optional->userProps = NULL; - pWin->optional->backingBitPlanes = ~0L; - pWin->optional->backingPixel = 0; - pWin->optional->boundingShape = NULL; - pWin->optional->clipShape = NULL; - pWin->optional->inputShape = NULL; - pWin->optional->inputMasks = NULL; - pWin->optional->deviceCursors = NULL; - pWin->optional->colormap = pScreen->defColormap; - pWin->optional->visual = pScreen->rootVisual; - - pWin->nextSib = NullWindow; - - pWin->drawable.id = FakeClientID(0); - - pWin->origin.x = pWin->origin.y = 0; - pWin->drawable.height = pScreen->height; - pWin->drawable.width = pScreen->width; - pWin->drawable.x = pWin->drawable.y = 0; - - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - REGION_INIT(pScreen, &pWin->clipList, &box, 1); - REGION_INIT(pScreen, &pWin->winSize, &box, 1); - REGION_INIT(pScreen, &pWin->borderSize, &box, 1); - REGION_INIT(pScreen, &pWin->borderClip, &box, 1); - - pWin->drawable.class = InputOutput; - pWin->optional->visual = pScreen->rootVisual; - - pWin->backgroundState = BackgroundPixel; - pWin->background.pixel = pScreen->whitePixel; - - pWin->borderIsPixel = TRUE; - pWin->border.pixel = pScreen->blackPixel; - pWin->borderWidth = 0; - - /* security creation/labeling check - */ - if (XaceHook(XACE_RESOURCE_ACCESS, serverClient, pWin->drawable.id, - RT_WINDOW, pWin, RT_NONE, NULL, DixCreateAccess)) - return FALSE; - - if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer)pWin)) - return FALSE; - - if (disableBackingStore) - pScreen->backingStoreSupport = NotUseful; - if (enableBackingStore) - pScreen->backingStoreSupport = Always; - - pScreen->saveUnderSupport = NotUseful; - - return TRUE; -} - -void -InitRootWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - int backFlag = CWBorderPixel | CWCursor | CWBackingStore; - - if (!(*pScreen->CreateWindow)(pWin)) - return; /* XXX */ - (*pScreen->PositionWindow)(pWin, 0, 0); - - pWin->cursorIsNone = FALSE; - pWin->optional->cursor = rootCursor; - rootCursor->refcnt++; - - - if (party_like_its_1989) { - MakeRootTile(pWin); - backFlag |= CWBackPixmap; - } else { - if (whiteRoot) - pWin->background.pixel = pScreen->whitePixel; - else - pWin->background.pixel = pScreen->blackPixel; - backFlag |= CWBackPixel; - } - - pWin->backingStore = defaultBackingStore; - pWin->forcedBS = (defaultBackingStore != NotUseful); - /* We SHOULD check for an error value here XXX */ - (*pScreen->ChangeWindowAttributes)(pWin, backFlag); - - MapWindow(pWin, serverClient); -} - -/* Set the region to the intersection of the rectangle and the - * window's winSize. The window is typically the parent of the - * window from which the region came. - */ - -static void -ClippedRegionFromBox(WindowPtr pWin, RegionPtr Rgn, - int x, int y, - int w, int h) -{ - ScreenPtr pScreen; - BoxRec box; - - pScreen = pWin->drawable.pScreen; - - box = *(REGION_EXTENTS(pScreen, &pWin->winSize)); - /* we do these calculations to avoid overflows */ - if (x > box.x1) - box.x1 = x; - if (y > box.y1) - box.y1 = y; - x += w; - if (x < box.x2) - box.x2 = x; - y += h; - if (y < box.y2) - box.y2 = y; - if (box.x1 > box.x2) - box.x2 = box.x1; - if (box.y1 > box.y2) - box.y2 = box.y1; - REGION_RESET(pScreen, Rgn, &box); - REGION_INTERSECT(pScreen, Rgn, Rgn, &pWin->winSize); -} - -static RealChildHeadProc realChildHeadProc = NULL; - -void -RegisterRealChildHeadProc (RealChildHeadProc proc) -{ - realChildHeadProc = proc; -} - - -WindowPtr -RealChildHead(WindowPtr pWin) -{ - if (realChildHeadProc) { - return realChildHeadProc (pWin); - } - - if (!pWin->parent && - (screenIsSaved == SCREEN_SAVER_ON) && - (HasSaverWindow (pWin->drawable.pScreen->myNum))) - return (pWin->firstChild); - else - return (NullWindow); -} - -/***** - * CreateWindow - * Makes a window in response to client request - *****/ - -WindowPtr -CreateWindow(Window wid, WindowPtr pParent, int x, int y, unsigned w, - unsigned h, unsigned bw, unsigned class, Mask vmask, XID *vlist, - int depth, ClientPtr client, VisualID visual, int *error) -{ - WindowPtr pWin; - WindowPtr pHead; - ScreenPtr pScreen; - xEvent event; - int idepth, ivisual; - Bool fOK; - DepthPtr pDepth; - PixmapFormatRec *format; - WindowOptPtr ancwopt; - - if (class == CopyFromParent) - class = pParent->drawable.class; - - if ((class != InputOutput) && (class != InputOnly)) - { - *error = BadValue; - client->errorValue = class; - return NullWindow; - } - - if ((class != InputOnly) && (pParent->drawable.class == InputOnly)) - { - *error = BadMatch; - return NullWindow; - } - - if ((class == InputOnly) && ((bw != 0) || (depth != 0))) - { - *error = BadMatch; - return NullWindow; - } - - pScreen = pParent->drawable.pScreen; - 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) - { - *error = BadMatch; - return NullWindow; - } - } - - if (((vmask & (CWBorderPixmap | CWBorderPixel)) == 0) && - (class != InputOnly) && - (depth != pParent->drawable.depth)) - { - *error = BadMatch; - return NullWindow; - } - - if (((vmask & CWColormap) == 0) && - (class != InputOnly) && - ((visual != ancwopt->visual) || (ancwopt->colormap == None))) - { - *error = BadMatch; - return NullWindow; - } - - pWin = xalloc(sizeof(WindowRec)); - if (!pWin) - { - *error = BadAlloc; - return NullWindow; - } - pWin->drawable = pParent->drawable; - pWin->devPrivates = NULL; - pWin->drawable.depth = depth; - if (depth == pParent->drawable.depth) - pWin->drawable.bitsPerPixel = pParent->drawable.bitsPerPixel; - else - { - for (format = screenInfo.formats; format->depth != depth; format++) - ; - pWin->drawable.bitsPerPixel = format->bitsPerPixel; - } - if (class == InputOnly) - pWin->drawable.type = (short) UNDRAWABLE_WINDOW; - pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; - - pWin->drawable.id = wid; - pWin->drawable.class = class; - - pWin->parent = pParent; - SetWindowToDefaults(pWin); - - if (visual != ancwopt->visual) - { - if (!MakeWindowOptional (pWin)) - { - xfree (pWin); - *error = BadAlloc; - return NullWindow; - } - pWin->optional->visual = visual; - pWin->optional->colormap = None; - } - - pWin->borderWidth = bw; - - /* security creation/labeling check - */ - *error = XaceHook(XACE_RESOURCE_ACCESS, client, wid, RT_WINDOW, pWin, - RT_WINDOW, pWin->parent, DixCreateAccess|DixSetAttrAccess); - if (*error != Success) { - xfree(pWin); - return NullWindow; - } - - pWin->backgroundState = XaceBackgroundNoneState(pWin); - pWin->background.pixel = pScreen->whitePixel; - - pWin->borderIsPixel = pParent->borderIsPixel; - pWin->border = pParent->border; - if (pWin->borderIsPixel == FALSE) - pWin->border.pixmap->refcnt++; - - pWin->origin.x = x + (int)bw; - pWin->origin.y = y + (int)bw; - pWin->drawable.width = w; - pWin->drawable.height = h; - pWin->drawable.x = pParent->drawable.x + x + (int)bw; - pWin->drawable.y = pParent->drawable.y + y + (int)bw; - - /* set up clip list correctly for unobscured WindowPtr */ - REGION_NULL(pScreen, &pWin->clipList); - REGION_NULL(pScreen, &pWin->borderClip); - REGION_NULL(pScreen, &pWin->winSize); - REGION_NULL(pScreen, &pWin->borderSize); - - pHead = RealChildHead(pParent); - if (pHead) - { - pWin->nextSib = pHead->nextSib; - if (pHead->nextSib) - pHead->nextSib->prevSib = pWin; - else - pParent->lastChild = pWin; - pHead->nextSib = pWin; - pWin->prevSib = pHead; - } - else - { - pWin->nextSib = pParent->firstChild; - if (pParent->firstChild) - pParent->firstChild->prevSib = pWin; - else - pParent->lastChild = pWin; - pParent->firstChild = pWin; - } - - SetWinSize (pWin); - SetBorderSize (pWin); - - /* We SHOULD check for an error value here XXX */ - if (!(*pScreen->CreateWindow)(pWin)) - { - *error = BadAlloc; - DeleteWindow(pWin, None); - return NullWindow; - } - /* We SHOULD check for an error value here XXX */ - (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); - - if (!(vmask & CWEventMask)) - RecalculateDeliverableEvents(pWin); - - if (vmask) - *error = ChangeWindowAttributes(pWin, vmask, vlist, wClient (pWin)); - else - *error = Success; - - if (*error != Success) - { - DeleteWindow(pWin, None); - return NullWindow; - } - if (!(vmask & CWBackingStore) && (defaultBackingStore != NotUseful)) - { - XID value = defaultBackingStore; - (void)ChangeWindowAttributes(pWin, CWBackingStore, &value, wClient (pWin)); - pWin->forcedBS = TRUE; - } - - if (SubSend(pParent)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = CreateNotify; - event.u.createNotify.window = wid; - event.u.createNotify.parent = pParent->drawable.id; - event.u.createNotify.x = x; - event.u.createNotify.y = y; - event.u.createNotify.width = w; - event.u.createNotify.height = h; - event.u.createNotify.borderWidth = bw; - event.u.createNotify.override = pWin->overrideRedirect; - DeliverEvents(pParent, &event, 1, NullWindow); - } - return pWin; -} - -static void -DisposeWindowOptional (WindowPtr pWin) -{ - if (!pWin->optional) - return; - /* - * everything is peachy. Delete the optional record - * and clean up - */ - if (pWin->optional->cursor) - { - FreeCursor (pWin->optional->cursor, (Cursor)0); - pWin->cursorIsNone = FALSE; - } - else - pWin->cursorIsNone = TRUE; - - if (pWin->optional->deviceCursors) - { - DevCursorList pList; - DevCursorList pPrev; - pList = pWin->optional->deviceCursors; - while(pList) - { - if (pList->cursor) - FreeCursor(pList->cursor, (XID)0); - pPrev = pList; - pList = pList->next; - xfree(pPrev); - } - pWin->optional->deviceCursors = NULL; - } - - xfree (pWin->optional); - pWin->optional = NULL; -} - -static void -FreeWindowResources(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - DeleteWindowFromAnySaveSet(pWin); - DeleteWindowFromAnySelections(pWin); - DeleteWindowFromAnyEvents(pWin, TRUE); - REGION_UNINIT(pScreen, &pWin->clipList); - REGION_UNINIT(pScreen, &pWin->winSize); - REGION_UNINIT(pScreen, &pWin->borderClip); - REGION_UNINIT(pScreen, &pWin->borderSize); - if (wBoundingShape (pWin)) - REGION_DESTROY(pScreen, wBoundingShape (pWin)); - if (wClipShape (pWin)) - REGION_DESTROY(pScreen, wClipShape (pWin)); - if (wInputShape (pWin)) - REGION_DESTROY(pScreen, wInputShape (pWin)); - if (pWin->borderIsPixel == FALSE) - (*pScreen->DestroyPixmap)(pWin->border.pixmap); - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - - DeleteAllWindowProperties(pWin); - /* We SHOULD check for an error value here XXX */ - (*pScreen->DestroyWindow)(pWin); - DisposeWindowOptional (pWin); -} - -static void -CrushTree(WindowPtr pWin) -{ - WindowPtr pChild, pSib, pParent; - UnrealizeWindowProcPtr UnrealizeWindow; - xEvent event; - - if (!(pChild = pWin->firstChild)) - return; - UnrealizeWindow = pWin->drawable.pScreen->UnrealizeWindow; - while (1) - { - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - while (1) - { - pParent = pChild->parent; - if (SubStrSend(pChild, pParent)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = DestroyNotify; - event.u.destroyNotify.window = pChild->drawable.id; - DeliverEvents(pChild, &event, 1, NullWindow); - } - FreeResource(pChild->drawable.id, RT_WINDOW); - pSib = pChild->nextSib; - pChild->viewable = FALSE; - if (pChild->realized) - { - pChild->realized = FALSE; - (*UnrealizeWindow)(pChild); - } - FreeWindowResources(pChild); - dixFreePrivates(pChild->devPrivates); - xfree(pChild); - if ( (pChild = pSib) ) - break; - pChild = pParent; - pChild->firstChild = NullWindow; - pChild->lastChild = NullWindow; - if (pChild == pWin) - return; - } - } -} - -/***** - * DeleteWindow - * Deletes child of window then window itself - * If wid is None, don't send any events - *****/ - -int -DeleteWindow(pointer value, XID wid) - { - WindowPtr pParent; - WindowPtr pWin = (WindowPtr)value; - xEvent event; - - UnmapWindow(pWin, FALSE); - - CrushTree(pWin); - - pParent = pWin->parent; - if (wid && pParent && SubStrSend(pWin, pParent)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = DestroyNotify; - event.u.destroyNotify.window = pWin->drawable.id; - DeliverEvents(pWin, &event, 1, NullWindow); - } - - FreeWindowResources(pWin); - if (pParent) - { - if (pParent->firstChild == pWin) - pParent->firstChild = pWin->nextSib; - if (pParent->lastChild == pWin) - pParent->lastChild = pWin->prevSib; - if (pWin->nextSib) - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - } - xfree(dixLookupPrivate(&pWin->devPrivates, FocusPrivatesKey)); - dixFreePrivates(pWin->devPrivates); - xfree(pWin); - return Success; -} - -int -DestroySubwindows(WindowPtr pWin, ClientPtr client) -{ - /* XXX - * The protocol is quite clear that each window should be - * destroyed in turn, however, unmapping all of the first - * eliminates most of the calls to ValidateTree. So, - * this implementation is incorrect in that all of the - * UnmapNotifies occur before all of the DestroyNotifies. - * If you care, simply delete the call to UnmapSubwindows. - */ - UnmapSubwindows(pWin); - while (pWin->lastChild) { - int rc = XaceHook(XACE_RESOURCE_ACCESS, client, - pWin->lastChild->drawable.id, RT_WINDOW, - pWin->lastChild, RT_NONE, NULL, DixDestroyAccess); - if (rc != Success) - return rc; - FreeResource(pWin->lastChild->drawable.id, RT_NONE); - } - return Success; -} - -/***** - * ChangeWindowAttributes - * - * The value-mask specifies which attributes are to be changed; the - * value-list contains one value for each one bit in the mask, from least - * to most significant bit in the mask. - *****/ - -int -ChangeWindowAttributes(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client) -{ - XID *pVlist; - PixmapPtr pPixmap; - Pixmap pixID; - CursorPtr pCursor, pOldCursor; - Cursor cursorID; - WindowPtr pChild; - Colormap cmap; - ColormapPtr pCmap; - xEvent xE; - int error, rc; - ScreenPtr pScreen; - Mask index2, tmask, vmaskCopy = 0; - unsigned int val; - Bool checkOptional = FALSE, borderRelative = FALSE; - - if ((pWin->drawable.class == InputOnly) && (vmask & (~INPUTONLY_LEGAL_MASK))) - return BadMatch; - - error = Success; - pScreen = pWin->drawable.pScreen; - pVlist = vlist; - tmask = vmask; - while (tmask) - { - index2 = (Mask) lowbit (tmask); - tmask &= ~index2; - switch (index2) - { - case CWBackPixmap: - pixID = (Pixmap )*pVlist; - pVlist++; - if (pWin->backgroundState == ParentRelative) - borderRelative = TRUE; - if (pixID == None) - { - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - if (!pWin->parent) - MakeRootTile(pWin); - else { - pWin->backgroundState = XaceBackgroundNoneState(pWin); - pWin->background.pixel = pScreen->whitePixel; - } - } - else if (pixID == ParentRelative) - { - if (pWin->parent && - pWin->drawable.depth != pWin->parent->drawable.depth) - { - error = BadMatch; - goto PatchUp; - } - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - if (!pWin->parent) - MakeRootTile(pWin); - else - pWin->backgroundState = ParentRelative; - borderRelative = TRUE; - /* Note that the parent's backgroundTile's refcnt is NOT - * incremented. */ - } - else - { - rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, - client, DixReadAccess); - if (rc == Success) - { - if ((pPixmap->drawable.depth != pWin->drawable.depth) || - (pPixmap->drawable.pScreen != pScreen)) - { - error = BadMatch; - goto PatchUp; - } - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - pWin->backgroundState = BackgroundPixmap; - pWin->background.pixmap = pPixmap; - pPixmap->refcnt++; - } - else - { - error = (rc == BadValue) ? BadPixmap : rc; - client->errorValue = pixID; - goto PatchUp; - } - } - break; - case CWBackPixel: - if (pWin->backgroundState == ParentRelative) - borderRelative = TRUE; - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - pWin->backgroundState = BackgroundPixel; - pWin->background.pixel = (CARD32 ) *pVlist; - /* background pixel overrides background pixmap, - so don't let the ddx layer see both bits */ - vmaskCopy &= ~CWBackPixmap; - pVlist++; - break; - case CWBorderPixmap: - pixID = (Pixmap ) *pVlist; - pVlist++; - if (pixID == CopyFromParent) - { - if (!pWin->parent || - (pWin->drawable.depth != pWin->parent->drawable.depth)) - { - error = BadMatch; - goto PatchUp; - } - if (pWin->parent->borderIsPixel == TRUE) { - if (pWin->borderIsPixel == FALSE) - (*pScreen->DestroyPixmap)(pWin->border.pixmap); - pWin->border = pWin->parent->border; - pWin->borderIsPixel = TRUE; - index2 = CWBorderPixel; - break; - } - else - { - pixID = pWin->parent->border.pixmap->drawable.id; - } - } - rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, - client, DixReadAccess); - if (rc == Success) - { - if ((pPixmap->drawable.depth != pWin->drawable.depth) || - (pPixmap->drawable.pScreen != pScreen)) - { - error = BadMatch; - goto PatchUp; - } - if (pWin->borderIsPixel == FALSE) - (*pScreen->DestroyPixmap)(pWin->border.pixmap); - pWin->borderIsPixel = FALSE; - pWin->border.pixmap = pPixmap; - pPixmap->refcnt++; - } - else - { - error = (rc == BadValue) ? BadPixmap : rc; - client->errorValue = pixID; - goto PatchUp; - } - break; - case CWBorderPixel: - if (pWin->borderIsPixel == FALSE) - (*pScreen->DestroyPixmap)(pWin->border.pixmap); - pWin->borderIsPixel = TRUE; - pWin->border.pixel = (CARD32) *pVlist; - /* border pixel overrides border pixmap, - so don't let the ddx layer see both bits */ - vmaskCopy &= ~CWBorderPixmap; - pVlist++; - break; - case CWBitGravity: - val = (CARD8 )*pVlist; - pVlist++; - if (val > StaticGravity) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - pWin->bitGravity = val; - break; - case CWWinGravity: - val = (CARD8 )*pVlist; - pVlist++; - if (val > StaticGravity) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - pWin->winGravity = val; - break; - case CWBackingStore: - val = (CARD8 )*pVlist; - pVlist++; - if ((val != NotUseful) && (val != WhenMapped) && (val != Always)) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - pWin->backingStore = val; - pWin->forcedBS = FALSE; - break; - case CWBackingPlanes: - if (pWin->optional || ((CARD32)*pVlist != (CARD32)~0L)) { - if (!pWin->optional && !MakeWindowOptional (pWin)) - { - error = BadAlloc; - goto PatchUp; - } - pWin->optional->backingBitPlanes = (CARD32) *pVlist; - if ((CARD32)*pVlist == (CARD32)~0L) - checkOptional = TRUE; - } - pVlist++; - break; - case CWBackingPixel: - if (pWin->optional || (CARD32) *pVlist) { - if (!pWin->optional && !MakeWindowOptional (pWin)) - { - error = BadAlloc; - goto PatchUp; - } - pWin->optional->backingPixel = (CARD32) *pVlist; - if (!*pVlist) - checkOptional = TRUE; - } - pVlist++; - break; - case CWSaveUnder: - val = (BOOL) *pVlist; - pVlist++; - if ((val != xTrue) && (val != xFalse)) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - pWin->saveUnder = val; - break; - case CWEventMask: - rc = EventSelectForWindow(pWin, client, (Mask )*pVlist); - if (rc) - { - error = rc; - goto PatchUp; - } - pVlist++; - break; - case CWDontPropagate: - rc = EventSuppressForWindow(pWin, client, (Mask )*pVlist, - &checkOptional); - if (rc) - { - error = rc; - goto PatchUp; - } - pVlist++; - break; - case CWOverrideRedirect: - val = (BOOL ) *pVlist; - pVlist++; - if ((val != xTrue) && (val != xFalse)) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - if (val == xTrue) { - rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, - RT_WINDOW, pWin, RT_NONE, NULL, DixGrabAccess); - if (rc != Success) { - error = rc; - client->errorValue = pWin->drawable.id; - goto PatchUp; - } - } - pWin->overrideRedirect = val; - break; - case CWColormap: - cmap = (Colormap) *pVlist; - pVlist++; - if (cmap == CopyFromParent) - { - if (pWin->parent && - (!pWin->optional || - pWin->optional->visual == wVisual (pWin->parent))) - { - cmap = wColormap (pWin->parent); - } - else - cmap = None; - } - if (cmap == None) - { - error = BadMatch; - goto PatchUp; - } - rc = dixLookupResourceByType((pointer *)&pCmap, cmap, RT_COLORMAP, - client, DixUseAccess); - if (rc != Success) - { - error = (rc == BadValue) ? BadColor : rc; - client->errorValue = cmap; - goto PatchUp; - } - if (pCmap->pVisual->vid != wVisual (pWin) || - pCmap->pScreen != pScreen) - { - error = BadMatch; - goto PatchUp; - } - if (cmap != wColormap (pWin)) - { - if (!pWin->optional) - { - if (!MakeWindowOptional (pWin)) - { - error = BadAlloc; - goto PatchUp; - } - } - else if (pWin->parent && cmap == wColormap (pWin->parent)) - checkOptional = TRUE; - - /* - * propagate the original colormap to any children - * inheriting it - */ - - for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) - { - if (!pChild->optional && !MakeWindowOptional (pChild)) - { - error = BadAlloc; - goto PatchUp; - } - } - - pWin->optional->colormap = cmap; - - /* - * check on any children now matching the new colormap - */ - - for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) - { - if (pChild->optional->colormap == cmap) - CheckWindowOptionalNeed (pChild); - } - - xE.u.u.type = ColormapNotify; - xE.u.colormap.window = pWin->drawable.id; - xE.u.colormap.colormap = cmap; - xE.u.colormap.new = xTrue; - xE.u.colormap.state = IsMapInstalled(cmap, pWin); - DeliverEvents(pWin, &xE, 1, NullWindow); - } - break; - case CWCursor: - cursorID = (Cursor ) *pVlist; - pVlist++; - /* - * install the new - */ - if ( cursorID == None) - { - if (pWin == WindowTable[pWin->drawable.pScreen->myNum]) - pCursor = rootCursor; - else - pCursor = (CursorPtr) None; - } - else - { - rc = dixLookupResourceByType((pointer *)&pCursor, cursorID, - RT_CURSOR, client, DixUseAccess); - if (rc != Success) - { - error = (rc == BadValue) ? BadCursor : rc; - client->errorValue = cursorID; - goto PatchUp; - } - } - - if (pCursor != wCursor (pWin)) - { - /* - * patch up child windows so they don't lose cursors. - */ - - for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) - { - if (!pChild->optional && !pChild->cursorIsNone && - !MakeWindowOptional (pChild)) - { - error = BadAlloc; - goto PatchUp; - } - } - - pOldCursor = 0; - if (pCursor == (CursorPtr) None) - { - pWin->cursorIsNone = TRUE; - if (pWin->optional) - { - pOldCursor = pWin->optional->cursor; - pWin->optional->cursor = (CursorPtr) None; - checkOptional = TRUE; - } - } else { - if (!pWin->optional) - { - if (!MakeWindowOptional (pWin)) - { - error = BadAlloc; - goto PatchUp; - } - } - else if (pWin->parent && pCursor == wCursor (pWin->parent)) - checkOptional = TRUE; - pOldCursor = pWin->optional->cursor; - pWin->optional->cursor = pCursor; - pCursor->refcnt++; - pWin->cursorIsNone = FALSE; - /* - * check on any children now matching the new cursor - */ - - for (pChild=pWin->firstChild; pChild; pChild=pChild->nextSib) - { - if (pChild->optional && - (pChild->optional->cursor == pCursor)) - CheckWindowOptionalNeed (pChild); - } - } - - if (pWin->realized) - WindowHasNewCursor( pWin); - - /* Can't free cursor until here - old cursor - * is needed in WindowHasNewCursor - */ - if (pOldCursor) - FreeCursor (pOldCursor, (Cursor)0); - } - break; - default: - error = BadValue; - client->errorValue = vmask; - goto PatchUp; - } - vmaskCopy |= index2; - } -PatchUp: - if (checkOptional) - CheckWindowOptionalNeed (pWin); - - /* We SHOULD check for an error value here XXX */ - (*pScreen->ChangeWindowAttributes)(pWin, vmaskCopy); - - /* - If the border contents have changed, redraw the border. - Note that this has to be done AFTER pScreen->ChangeWindowAttributes - for the tile to be rotated, and the correct function selected. - */ - if (((vmaskCopy & (CWBorderPixel | CWBorderPixmap)) || borderRelative) - && pWin->viewable && HasBorder (pWin)) - { - RegionRec exposed; - - REGION_NULL(pScreen, &exposed); - REGION_SUBTRACT(pScreen, &exposed, &pWin->borderClip, &pWin->winSize); - miPaintWindow(pWin, &exposed, PW_BORDER); - REGION_UNINIT(pScreen, &exposed); - } - return error; -} - - -/***** - * GetWindowAttributes - * Notice that this is different than ChangeWindowAttributes - *****/ - -void -GetWindowAttributes(WindowPtr pWin, ClientPtr client, xGetWindowAttributesReply *wa) -{ - wa->type = X_Reply; - wa->bitGravity = pWin->bitGravity; - wa->winGravity = pWin->winGravity; - if (pWin->forcedBS && pWin->backingStore != Always) - wa->backingStore = NotUseful; - else - wa->backingStore = pWin->backingStore; - wa->length = bytes_to_int32(sizeof(xGetWindowAttributesReply) - - sizeof(xGenericReply)); - wa->sequenceNumber = client->sequence; - wa->backingBitPlanes = wBackingBitPlanes (pWin); - wa->backingPixel = wBackingPixel (pWin); - wa->saveUnder = (BOOL)pWin->saveUnder; - wa->override = pWin->overrideRedirect; - if (!pWin->mapped) - wa->mapState = IsUnmapped; - else if (pWin->realized) - wa->mapState = IsViewable; - else - wa->mapState = IsUnviewable; - - wa->colormap = wColormap (pWin); - wa->mapInstalled = (wa->colormap == None) ? xFalse - : IsMapInstalled(wa->colormap, pWin); - - wa->yourEventMask = EventMaskForClient(pWin, client); - wa->allEventMasks = pWin->eventMask | wOtherEventMasks (pWin); - wa->doNotPropagateMask = wDontPropagateMask (pWin); - wa->class = pWin->drawable.class; - wa->visualID = wVisual (pWin); -} - - -WindowPtr -MoveWindowInStack(WindowPtr pWin, WindowPtr pNextSib) -{ - WindowPtr pParent = pWin->parent; - WindowPtr pFirstChange = pWin; /* highest window where list changes */ - - if (pWin->nextSib != pNextSib) - { - WindowPtr pOldNextSib = pWin->nextSib; - - if (!pNextSib) /* move to bottom */ - { - if (pParent->firstChild == pWin) - pParent->firstChild = pWin->nextSib; - /* if (pWin->nextSib) */ /* is always True: pNextSib == NULL - * and pWin->nextSib != pNextSib - * therefore pWin->nextSib != NULL */ - pFirstChange = pWin->nextSib; - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - pParent->lastChild->nextSib = pWin; - pWin->prevSib = pParent->lastChild; - pWin->nextSib = NullWindow; - pParent->lastChild = pWin; - } - else if (pParent->firstChild == pNextSib) /* move to top */ - { - pFirstChange = pWin; - if (pParent->lastChild == pWin) - pParent->lastChild = pWin->prevSib; - if (pWin->nextSib) - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - pWin->nextSib = pParent->firstChild; - pWin->prevSib = (WindowPtr ) NULL; - pNextSib->prevSib = pWin; - pParent->firstChild = pWin; - } - else /* move in middle of list */ - { - WindowPtr pOldNext = pWin->nextSib; - - pFirstChange = NullWindow; - if (pParent->firstChild == pWin) - pFirstChange = pParent->firstChild = pWin->nextSib; - if (pParent->lastChild == pWin) { - pFirstChange = pWin; - pParent->lastChild = pWin->prevSib; - } - if (pWin->nextSib) - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - pWin->nextSib = pNextSib; - pWin->prevSib = pNextSib->prevSib; - if (pNextSib->prevSib) - pNextSib->prevSib->nextSib = pWin; - pNextSib->prevSib = pWin; - if (!pFirstChange) { /* do we know it yet? */ - pFirstChange = pParent->firstChild; /* no, search from top */ - while ((pFirstChange != pWin) && (pFirstChange != pOldNext)) - pFirstChange = pFirstChange->nextSib; - } - } - if(pWin->drawable.pScreen->RestackWindow) - (*pWin->drawable.pScreen->RestackWindow)(pWin, pOldNextSib); - } - -#ifdef ROOTLESS - /* - * In rootless mode we can't optimize away window restacks. - * There may be non-X windows around, so even if the window - * is in the correct position from X's point of view, - * the underlying window system may want to reorder it. - */ - else if (pWin->drawable.pScreen->RestackWindow) - (*pWin->drawable.pScreen->RestackWindow)(pWin, pWin->nextSib); -#endif - - return( pFirstChange ); -} - -void -SetWinSize (WindowPtr pWin) -{ -#ifdef COMPOSITE - if (pWin->redirectDraw != RedirectDrawNone) - { - BoxRec box; - - /* - * Redirected clients get clip list equal to their - * own geometry, not clipped to their parent - */ - box.x1 = pWin->drawable.x; - box.y1 = pWin->drawable.y; - box.x2 = pWin->drawable.x + pWin->drawable.width; - box.y2 = pWin->drawable.y + pWin->drawable.height; - REGION_RESET (pScreen, &pWin->winSize, &box); - } - else -#endif - ClippedRegionFromBox(pWin->parent, &pWin->winSize, - pWin->drawable.x, pWin->drawable.y, - (int)pWin->drawable.width, - (int)pWin->drawable.height); - if (wBoundingShape (pWin) || wClipShape (pWin)) { - ScreenPtr pScreen; - pScreen = pWin->drawable.pScreen; - - REGION_TRANSLATE(pScreen, &pWin->winSize, - pWin->drawable.x, - - pWin->drawable.y); - if (wBoundingShape (pWin)) - REGION_INTERSECT(pScreen, &pWin->winSize, &pWin->winSize, - wBoundingShape (pWin)); - if (wClipShape (pWin)) - REGION_INTERSECT(pScreen, &pWin->winSize, &pWin->winSize, - wClipShape (pWin)); - REGION_TRANSLATE(pScreen, &pWin->winSize, pWin->drawable.x, - pWin->drawable.y); - } -} - -void -SetBorderSize (WindowPtr pWin) -{ - int bw; - - if (HasBorder (pWin)) { - bw = wBorderWidth (pWin); -#ifdef COMPOSITE - if (pWin->redirectDraw != RedirectDrawNone) - { - BoxRec box; - - /* - * Redirected clients get clip list equal to their - * own geometry, not clipped to their parent - */ - box.x1 = pWin->drawable.x - bw; - box.y1 = pWin->drawable.y - bw; - box.x2 = pWin->drawable.x + pWin->drawable.width + bw; - box.y2 = pWin->drawable.y + pWin->drawable.height + bw; - REGION_RESET (pScreen, &pWin->borderSize, &box); - } - else -#endif - ClippedRegionFromBox(pWin->parent, &pWin->borderSize, - pWin->drawable.x - bw, pWin->drawable.y - bw, - (int)(pWin->drawable.width + (bw<<1)), - (int)(pWin->drawable.height + (bw<<1))); - if (wBoundingShape (pWin)) { - ScreenPtr pScreen; - pScreen = pWin->drawable.pScreen; - - REGION_TRANSLATE(pScreen, &pWin->borderSize, - pWin->drawable.x, - - pWin->drawable.y); - REGION_INTERSECT(pScreen, &pWin->borderSize, &pWin->borderSize, - wBoundingShape (pWin)); - REGION_TRANSLATE(pScreen, &pWin->borderSize, pWin->drawable.x, - pWin->drawable.y); - REGION_UNION(pScreen, &pWin->borderSize, &pWin->borderSize, - &pWin->winSize); - } - } else { - REGION_COPY(pWin->drawable.pScreen, &pWin->borderSize, - &pWin->winSize); - } -} - -/** - * - * \param x,y new window position - * \param oldx,oldy old window position - * \param destx,desty position relative to gravity - */ - -void -GravityTranslate (int x, int y, int oldx, int oldy, - int dw, int dh, unsigned gravity, - int *destx, int *desty) -{ - switch (gravity) { - case NorthGravity: - *destx = x + dw / 2; - *desty = y; - break; - case NorthEastGravity: - *destx = x + dw; - *desty = y; - break; - case WestGravity: - *destx = x; - *desty = y + dh / 2; - break; - case CenterGravity: - *destx = x + dw / 2; - *desty = y + dh / 2; - break; - case EastGravity: - *destx = x + dw; - *desty = y + dh / 2; - break; - case SouthWestGravity: - *destx = x; - *desty = y + dh; - break; - case SouthGravity: - *destx = x + dw / 2; - *desty = y + dh; - break; - case SouthEastGravity: - *destx = x + dw; - *desty = y + dh; - break; - case StaticGravity: - *destx = oldx; - *desty = oldy; - break; - default: - *destx = x; - *desty = y; - break; - } -} - -/* XXX need to retile border on each window with ParentRelative origin */ -void -ResizeChildrenWinSize(WindowPtr pWin, int dx, int dy, int dw, int dh) -{ - ScreenPtr pScreen; - WindowPtr pSib, pChild; - Bool resized = (dw || dh); - - pScreen = pWin->drawable.pScreen; - - for (pSib = pWin->firstChild; pSib; pSib = pSib->nextSib) - { - if (resized && (pSib->winGravity > NorthWestGravity)) - { - int cwsx, cwsy; - - cwsx = pSib->origin.x; - cwsy = pSib->origin.y; - GravityTranslate (cwsx, cwsy, cwsx - dx, cwsy - dy, dw, dh, - pSib->winGravity, &cwsx, &cwsy); - if (cwsx != pSib->origin.x || cwsy != pSib->origin.y) - { - xEvent event; - - event.u.u.type = GravityNotify; - event.u.gravity.window = pSib->drawable.id; - event.u.gravity.x = cwsx - wBorderWidth (pSib); - event.u.gravity.y = cwsy - wBorderWidth (pSib); - DeliverEvents (pSib, &event, 1, NullWindow); - pSib->origin.x = cwsx; - pSib->origin.y = cwsy; - } - } - pSib->drawable.x = pWin->drawable.x + pSib->origin.x; - pSib->drawable.y = pWin->drawable.y + pSib->origin.y; - SetWinSize (pSib); - SetBorderSize (pSib); - (*pScreen->PositionWindow)(pSib, pSib->drawable.x, pSib->drawable.y); - - if ( (pChild = pSib->firstChild) ) - { - while (1) - { - pChild->drawable.x = pChild->parent->drawable.x + - pChild->origin.x; - pChild->drawable.y = pChild->parent->drawable.y + - pChild->origin.y; - SetWinSize (pChild); - SetBorderSize (pChild); - (*pScreen->PositionWindow)(pChild, - pChild->drawable.x, pChild->drawable.y); - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - while (!pChild->nextSib && (pChild != pSib)) - pChild = pChild->parent; - if (pChild == pSib) - break; - pChild = pChild->nextSib; - } - } - } -} - -#define GET_INT16(m, f) \ - if (m & mask) \ - { \ - f = (INT16) *pVlist;\ - pVlist++; \ - } -#define GET_CARD16(m, f) \ - if (m & mask) \ - { \ - f = (CARD16) *pVlist;\ - pVlist++;\ - } - -#define GET_CARD8(m, f) \ - if (m & mask) \ - { \ - f = (CARD8) *pVlist;\ - pVlist++;\ - } - -#define ChangeMask ((Mask)(CWX | CWY | CWWidth | CWHeight)) - -#define IllegalInputOnlyConfigureMask (CWBorderWidth) - -/* - * IsSiblingAboveMe - * returns Above if pSib above pMe in stack or Below otherwise - */ - -static int -IsSiblingAboveMe( - WindowPtr pMe, - WindowPtr pSib) -{ - WindowPtr pWin; - - pWin = pMe->parent->firstChild; - while (pWin) - { - if (pWin == pSib) - return(Above); - else if (pWin == pMe) - return(Below); - pWin = pWin->nextSib; - } - return(Below); -} - -static BoxPtr -WindowExtents( - WindowPtr pWin, - BoxPtr pBox) -{ - pBox->x1 = pWin->drawable.x - wBorderWidth (pWin); - pBox->y1 = pWin->drawable.y - wBorderWidth (pWin); - pBox->x2 = pWin->drawable.x + (int)pWin->drawable.width - + wBorderWidth (pWin); - pBox->y2 = pWin->drawable.y + (int)pWin->drawable.height - + wBorderWidth (pWin); - return(pBox); -} - -#define IS_SHAPED(pWin) (wBoundingShape (pWin) != (RegionPtr) NULL) - -static RegionPtr -MakeBoundingRegion ( - WindowPtr pWin, - BoxPtr pBox) -{ - RegionPtr pRgn; - ScreenPtr pScreen; - pScreen = pWin->drawable.pScreen; - - pRgn = REGION_CREATE(pScreen, pBox, 1); - if (wBoundingShape (pWin)) { - REGION_TRANSLATE(pScreen, pRgn, -pWin->origin.x, - -pWin->origin.y); - REGION_INTERSECT(pScreen, pRgn, pRgn, wBoundingShape (pWin)); - REGION_TRANSLATE(pScreen, pRgn, pWin->origin.x, - pWin->origin.y); - } - return pRgn; -} - -static Bool -ShapeOverlap ( - WindowPtr pWin, - BoxPtr pWinBox, - WindowPtr pSib, - BoxPtr pSibBox) -{ - RegionPtr pWinRgn, pSibRgn; - ScreenPtr pScreen; - Bool ret; - - if (!IS_SHAPED(pWin) && !IS_SHAPED(pSib)) - return TRUE; - pScreen = pWin->drawable.pScreen; - pWinRgn = MakeBoundingRegion (pWin, pWinBox); - pSibRgn = MakeBoundingRegion (pSib, pSibBox); - REGION_INTERSECT(pScreen, pWinRgn, pWinRgn, pSibRgn); - ret = REGION_NOTEMPTY(pScreen, pWinRgn); - REGION_DESTROY(pScreen, pWinRgn); - REGION_DESTROY(pScreen, pSibRgn); - return ret; -} - -static Bool -AnyWindowOverlapsMe( - WindowPtr pWin, - WindowPtr pHead, - BoxPtr box) -{ - WindowPtr pSib; - BoxRec sboxrec; - BoxPtr sbox; - - for (pSib = pWin->prevSib; pSib != pHead; pSib = pSib->prevSib) - { - if (pSib->mapped) - { - sbox = WindowExtents(pSib, &sboxrec); - if (BOXES_OVERLAP(sbox, box) - && ShapeOverlap (pWin, box, pSib, sbox) - ) - return(TRUE); - } - } - return(FALSE); -} - -static Bool -IOverlapAnyWindow( - WindowPtr pWin, - BoxPtr box) -{ - WindowPtr pSib; - BoxRec sboxrec; - BoxPtr sbox; - - for (pSib = pWin->nextSib; pSib; pSib = pSib->nextSib) - { - if (pSib->mapped) - { - sbox = WindowExtents(pSib, &sboxrec); - if (BOXES_OVERLAP(sbox, box) - && ShapeOverlap (pWin, box, pSib, sbox) - ) - return(TRUE); - } - } - return(FALSE); -} - -/* - * WhereDoIGoInTheStack() - * Given pWin and pSib and the relationshipe smode, return - * the window that pWin should go ABOVE. - * If a pSib is specified: - * Above: pWin is placed just above pSib - * Below: pWin is placed just below pSib - * TopIf: if pSib occludes pWin, then pWin is placed - * at the top of the stack - * BottomIf: if pWin occludes pSib, then pWin is - * placed at the bottom of the stack - * Opposite: if pSib occludes pWin, then pWin is placed at the - * top of the stack, else if pWin occludes pSib, then - * pWin is placed at the bottom of the stack - * - * If pSib is NULL: - * Above: pWin is placed at the top of the stack - * Below: pWin is placed at the bottom of the stack - * TopIf: if any sibling occludes pWin, then pWin is placed at - * the top of the stack - * BottomIf: if pWin occludes any sibline, then pWin is placed at - * the bottom of the stack - * Opposite: if any sibling occludes pWin, then pWin is placed at - * the top of the stack, else if pWin occludes any - * sibling, then pWin is placed at the bottom of the stack - * - */ - -static WindowPtr -WhereDoIGoInTheStack( - WindowPtr pWin, - WindowPtr pSib, - short x, - short y, - unsigned short w, - unsigned short h, - int smode) -{ - BoxRec box; - ScreenPtr pScreen; - WindowPtr pHead, pFirst; - - if ((pWin == pWin->parent->firstChild) && - (pWin == pWin->parent->lastChild)) - return((WindowPtr ) NULL); - pHead = RealChildHead(pWin->parent); - pFirst = pHead ? pHead->nextSib : pWin->parent->firstChild; - pScreen = pWin->drawable.pScreen; - box.x1 = x; - box.y1 = y; - box.x2 = x + (int)w; - box.y2 = y + (int)h; - switch (smode) - { - case Above: - if (pSib) - return(pSib); - else if (pWin == pFirst) - return(pWin->nextSib); - else - return(pFirst); - case Below: - if (pSib) - if (pSib->nextSib != pWin) - return(pSib->nextSib); - else - return(pWin->nextSib); - else - return NullWindow; - case TopIf: - if ((!pWin->mapped || (pSib && !pSib->mapped))) - return(pWin->nextSib); - else if (pSib) - { - if ((IsSiblingAboveMe(pWin, pSib) == Above) && - (RECT_IN_REGION(pScreen, &pSib->borderSize, &box) != rgnOUT)) - return(pFirst); - else - return(pWin->nextSib); - } - else if (AnyWindowOverlapsMe(pWin, pHead, &box)) - return(pFirst); - else - return(pWin->nextSib); - case BottomIf: - if ((!pWin->mapped || (pSib && !pSib->mapped))) - return(pWin->nextSib); - else if (pSib) - { - if ((IsSiblingAboveMe(pWin, pSib) == Below) && - (RECT_IN_REGION(pScreen, &pSib->borderSize, &box) != rgnOUT)) - return NullWindow; - else - return(pWin->nextSib); - } - else if (IOverlapAnyWindow(pWin, &box)) - return NullWindow; - else - return(pWin->nextSib); - case Opposite: - if ((!pWin->mapped || (pSib && !pSib->mapped))) - return(pWin->nextSib); - else if (pSib) - { - if (RECT_IN_REGION(pScreen, &pSib->borderSize, &box) != rgnOUT) - { - if (IsSiblingAboveMe(pWin, pSib) == Above) - return(pFirst); - else - return NullWindow; - } - else - return(pWin->nextSib); - } - else if (AnyWindowOverlapsMe(pWin, pHead, &box)) - { - /* If I'm occluded, I can't possibly be the first child - * if (pWin == pWin->parent->firstChild) - * return pWin->nextSib; - */ - return(pFirst); - } - else if (IOverlapAnyWindow(pWin, &box)) - return NullWindow; - else - return pWin->nextSib; - default: - { - /* should never happen; make something up. */ - return pWin->nextSib; - } - } -} - -static void -ReflectStackChange( - WindowPtr pWin, - WindowPtr pSib, - VTKind kind) -{ -/* Note that pSib might be NULL */ - - Bool WasViewable = (Bool)pWin->viewable; - Bool anyMarked; - WindowPtr pFirstChange; - WindowPtr pLayerWin; - ScreenPtr pScreen = pWin->drawable.pScreen; - - /* if this is a root window, can't be restacked */ - if (!pWin->parent) - return; - - pFirstChange = MoveWindowInStack(pWin, pSib); - - if (WasViewable) - { - anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, - &pLayerWin); - if (pLayerWin != pWin) pFirstChange = pLayerWin; - if (anyMarked) - { - (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, kind); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pWin->drawable.pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, kind); - } - if (pWin->realized) - WindowsRestructured (); -} - -/***** - * ConfigureWindow - *****/ - -int -ConfigureWindow(WindowPtr pWin, Mask mask, XID *vlist, ClientPtr client) -{ -#define RESTACK_WIN 0 -#define MOVE_WIN 1 -#define RESIZE_WIN 2 -#define REBORDER_WIN 3 - WindowPtr pSib = NullWindow; - WindowPtr pParent = pWin->parent; - Window sibwid = 0; - Mask index2, tmask; - XID *pVlist; - short x, y, beforeX, beforeY; - unsigned short w = pWin->drawable.width, - h = pWin->drawable.height, - bw = pWin->borderWidth; - int rc, action, smode = Above; - xEvent event; - - if ((pWin->drawable.class == InputOnly) && (mask & IllegalInputOnlyConfigureMask)) - return(BadMatch); - - if ((mask & CWSibling) && !(mask & CWStackMode)) - return(BadMatch); - - pVlist = vlist; - - if (pParent) - { - x = pWin->drawable.x - pParent->drawable.x - (int)bw; - y = pWin->drawable.y - pParent->drawable.y - (int)bw; - } - else - { - x = pWin->drawable.x; - y = pWin->drawable.y; - } - beforeX = x; - beforeY = y; - action = RESTACK_WIN; - if ((mask & (CWX | CWY)) && (!(mask & (CWHeight | CWWidth)))) - { - GET_INT16(CWX, x); - GET_INT16(CWY, y); - action = MOVE_WIN; - } - /* or should be resized */ - else if (mask & (CWX | CWY | CWWidth | CWHeight)) - { - GET_INT16(CWX, x); - GET_INT16(CWY, y); - GET_CARD16(CWWidth, w); - GET_CARD16 (CWHeight, h); - if (!w || !h) - { - client->errorValue = 0; - return BadValue; - } - action = RESIZE_WIN; - } - tmask = mask & ~ChangeMask; - while (tmask) - { - index2 = (Mask)lowbit (tmask); - tmask &= ~index2; - switch (index2) - { - case CWBorderWidth: - GET_CARD16(CWBorderWidth, bw); - break; - case CWSibling: - sibwid = (Window ) *pVlist; - pVlist++; - rc = dixLookupWindow(&pSib, sibwid, client, DixGetAttrAccess); - if (rc != Success) - { - client->errorValue = sibwid; - return rc; - } - if (pSib->parent != pParent) - return(BadMatch); - if (pSib == pWin) - return(BadMatch); - break; - case CWStackMode: - GET_CARD8(CWStackMode, smode); - if ((smode != TopIf) && (smode != BottomIf) && - (smode != Opposite) && (smode != Above) && (smode != Below)) - { - client->errorValue = smode; - return(BadValue); - } - break; - default: - client->errorValue = mask; - return(BadValue); - } - } - /* root really can't be reconfigured, so just return */ - if (!pParent) - return Success; - - /* Figure out if the window should be moved. Doesnt - make the changes to the window if event sent */ - - if (mask & CWStackMode) - pSib = WhereDoIGoInTheStack(pWin, pSib, pParent->drawable.x + x, - pParent->drawable.y + y, - w + (bw << 1), h + (bw << 1), smode); - else - pSib = pWin->nextSib; - - - if ((!pWin->overrideRedirect) && - (RedirectSend(pParent) - )) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = ConfigureRequest; - event.u.configureRequest.window = pWin->drawable.id; - if (mask & CWSibling) - event.u.configureRequest.sibling = sibwid; - else - event.u.configureRequest.sibling = None; - if (mask & CWStackMode) - event.u.u.detail = smode; - else - event.u.u.detail = Above; - event.u.configureRequest.x = x; - event.u.configureRequest.y = y; -#ifdef PANORAMIX - if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { - event.u.configureRequest.x += panoramiXdataPtr[0].x; - event.u.configureRequest.y += panoramiXdataPtr[0].y; - } -#endif - event.u.configureRequest.width = w; - event.u.configureRequest.height = h; - event.u.configureRequest.borderWidth = bw; - event.u.configureRequest.valueMask = mask; - event.u.configureRequest.parent = pParent->drawable.id; - if (MaybeDeliverEventsToClient(pParent, &event, 1, - SubstructureRedirectMask, client) == 1) - return(Success); - } - if (action == RESIZE_WIN) - { - Bool size_change = (w != pWin->drawable.width) - || (h != pWin->drawable.height); - if (size_change && ((pWin->eventMask|wOtherEventMasks(pWin)) & ResizeRedirectMask)) - { - xEvent eventT; - memset(&eventT, 0, sizeof(xEvent)); - eventT.u.u.type = ResizeRequest; - eventT.u.resizeRequest.window = pWin->drawable.id; - eventT.u.resizeRequest.width = w; - eventT.u.resizeRequest.height = h; - if (MaybeDeliverEventsToClient(pWin, &eventT, 1, - ResizeRedirectMask, client) == 1) - { - /* if event is delivered, leave the actual size alone. */ - w = pWin->drawable.width; - h = pWin->drawable.height; - size_change = FALSE; - } - } - if (!size_change) - { - if (mask & (CWX | CWY)) - action = MOVE_WIN; - else if (mask & (CWStackMode | CWBorderWidth)) - action = RESTACK_WIN; - else /* really nothing to do */ - return(Success) ; - } - } - - if (action == RESIZE_WIN) - /* we've already checked whether there's really a size change */ - goto ActuallyDoSomething; - if ((mask & CWX) && (x != beforeX)) - goto ActuallyDoSomething; - if ((mask & CWY) && (y != beforeY)) - goto ActuallyDoSomething; - if ((mask & CWBorderWidth) && (bw != wBorderWidth (pWin))) - goto ActuallyDoSomething; - if (mask & CWStackMode) - { -#ifndef ROOTLESS - /* See above for why we always reorder in rootless mode. */ - if (pWin->nextSib != pSib) -#endif - goto ActuallyDoSomething; - } - return(Success); - -ActuallyDoSomething: - if (pWin->drawable.pScreen->ConfigNotify) - (*pWin->drawable.pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib); - - if (SubStrSend(pWin, pParent)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = ConfigureNotify; - event.u.configureNotify.window = pWin->drawable.id; - if (pSib) - event.u.configureNotify.aboveSibling = pSib->drawable.id; - else - event.u.configureNotify.aboveSibling = None; - event.u.configureNotify.x = x; - event.u.configureNotify.y = y; -#ifdef PANORAMIX - if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { - event.u.configureNotify.x += panoramiXdataPtr[0].x; - event.u.configureNotify.y += panoramiXdataPtr[0].y; - } -#endif - event.u.configureNotify.width = w; - event.u.configureNotify.height = h; - event.u.configureNotify.borderWidth = bw; - event.u.configureNotify.override = pWin->overrideRedirect; - DeliverEvents(pWin, &event, 1, NullWindow); - } - if (mask & CWBorderWidth) - { - if (action == RESTACK_WIN) - { - action = MOVE_WIN; - pWin->borderWidth = bw; - } - else if ((action == MOVE_WIN) && - (beforeX + wBorderWidth (pWin) == x + (int)bw) && - (beforeY + wBorderWidth (pWin) == y + (int)bw)) - { - action = REBORDER_WIN; - (*pWin->drawable.pScreen->ChangeBorderWidth)(pWin, bw); - } - else - pWin->borderWidth = bw; - } - if (action == MOVE_WIN) - (*pWin->drawable.pScreen->MoveWindow)(pWin, x, y, pSib, - (mask & CWBorderWidth) ? VTOther : VTMove); - else if (action == RESIZE_WIN) - (*pWin->drawable.pScreen->ResizeWindow)(pWin, x, y, w, h, pSib); - else if (mask & CWStackMode) - ReflectStackChange(pWin, pSib, VTOther); - - if (action != RESTACK_WIN) - CheckCursorConfinement(pWin); - return(Success); -#undef RESTACK_WIN -#undef MOVE_WIN -#undef RESIZE_WIN -#undef REBORDER_WIN -} - - -/****** - * - * CirculateWindow - * For RaiseLowest, raises the lowest mapped child (if any) that is - * obscured by another child to the top of the stack. For LowerHighest, - * lowers the highest mapped child (if any) that is obscuring another - * child to the bottom of the stack. Exposure processing is performed - * - ******/ - -int -CirculateWindow(WindowPtr pParent, int direction, ClientPtr client) -{ - WindowPtr pWin, pHead, pFirst; - xEvent event; - BoxRec box; - - pHead = RealChildHead(pParent); - pFirst = pHead ? pHead->nextSib : pParent->firstChild; - if (direction == RaiseLowest) - { - for (pWin = pParent->lastChild; - (pWin != pHead) && - !(pWin->mapped && - AnyWindowOverlapsMe(pWin, pHead, WindowExtents(pWin, &box))); - pWin = pWin->prevSib) ; - if (pWin == pHead) - return Success; - } - else - { - for (pWin = pFirst; - pWin && - !(pWin->mapped && - IOverlapAnyWindow(pWin, WindowExtents(pWin, &box))); - pWin = pWin->nextSib) ; - if (!pWin) - return Success; - } - - event.u.circulate.window = pWin->drawable.id; - event.u.circulate.parent = pParent->drawable.id; - event.u.circulate.event = pParent->drawable.id; - if (direction == RaiseLowest) - event.u.circulate.place = PlaceOnTop; - else - event.u.circulate.place = PlaceOnBottom; - - if (RedirectSend(pParent)) - { - event.u.u.type = CirculateRequest; - if (MaybeDeliverEventsToClient(pParent, &event, 1, - SubstructureRedirectMask, client) == 1) - return(Success); - } - - event.u.u.type = CirculateNotify; - DeliverEvents(pWin, &event, 1, NullWindow); - ReflectStackChange(pWin, - (direction == RaiseLowest) ? pFirst : NullWindow, - VTStack); - - return(Success); -} - -static int -CompareWIDs( - WindowPtr pWin, - pointer value) /* must conform to VisitWindowProcPtr */ -{ - Window *wid = (Window *)value; - - if (pWin->drawable.id == *wid) - return(WT_STOPWALKING); - else - return(WT_WALKCHILDREN); -} - -/***** - * ReparentWindow - *****/ - -int -ReparentWindow(WindowPtr pWin, WindowPtr pParent, - int x, int y, ClientPtr client) -{ - WindowPtr pPrev, pPriorParent; - Bool WasMapped = (Bool)(pWin->mapped); - xEvent event; - int bw = wBorderWidth (pWin); - ScreenPtr pScreen; - - pScreen = pWin->drawable.pScreen; - if (TraverseTree(pWin, CompareWIDs, (pointer)&pParent->drawable.id) == WT_STOPWALKING) - return(BadMatch); - if (!MakeWindowOptional(pWin)) - return(BadAlloc); - - if (WasMapped) - UnmapWindow(pWin, FALSE); - - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = ReparentNotify; - event.u.reparent.window = pWin->drawable.id; - event.u.reparent.parent = pParent->drawable.id; - event.u.reparent.x = x; - event.u.reparent.y = y; -#ifdef PANORAMIX - if(!noPanoramiXExtension && !pParent->parent) { - event.u.reparent.x += panoramiXdataPtr[0].x; - event.u.reparent.y += panoramiXdataPtr[0].y; - } -#endif - event.u.reparent.override = pWin->overrideRedirect; - DeliverEvents(pWin, &event, 1, pParent); - - /* take out of sibling chain */ - - pPriorParent = pPrev = pWin->parent; - if (pPrev->firstChild == pWin) - pPrev->firstChild = pWin->nextSib; - if (pPrev->lastChild == pWin) - pPrev->lastChild = pWin->prevSib; - - if (pWin->nextSib) - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - - /* insert at begining of pParent */ - pWin->parent = pParent; - pPrev = RealChildHead(pParent); - if (pPrev) - { - pWin->nextSib = pPrev->nextSib; - if (pPrev->nextSib) - pPrev->nextSib->prevSib = pWin; - else - pParent->lastChild = pWin; - pPrev->nextSib = pWin; - pWin->prevSib = pPrev; - } - else - { - pWin->nextSib = pParent->firstChild; - pWin->prevSib = NullWindow; - if (pParent->firstChild) - pParent->firstChild->prevSib = pWin; - else - pParent->lastChild = pWin; - pParent->firstChild = pWin; - } - - pWin->origin.x = x + bw; - pWin->origin.y = y + bw; - pWin->drawable.x = x + bw + pParent->drawable.x; - pWin->drawable.y = y + bw + pParent->drawable.y; - - /* clip to parent */ - SetWinSize (pWin); - SetBorderSize (pWin); - - if (pScreen->ReparentWindow) - (*pScreen->ReparentWindow)(pWin, pPriorParent); - (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); - ResizeChildrenWinSize(pWin, 0, 0, 0, 0); - - CheckWindowOptionalNeed(pWin); - - if (WasMapped) - MapWindow(pWin, client); - RecalculateDeliverableEvents(pWin); - return(Success); -} - -static void -RealizeTree(WindowPtr pWin) -{ - WindowPtr pChild; - RealizeWindowProcPtr Realize; - - Realize = pWin->drawable.pScreen->RealizeWindow; - pChild = pWin; - while (1) - { - if (pChild->mapped) - { - pChild->realized = TRUE; - pChild->viewable = (pChild->drawable.class == InputOutput); - (* Realize)(pChild); - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - return; - pChild = pChild->nextSib; - } -} - -static WindowPtr windowDisableMapUnmapEvents; - -void -DisableMapUnmapEvents(WindowPtr pWin) -{ - assert (windowDisableMapUnmapEvents == NULL); - - windowDisableMapUnmapEvents = pWin; -} - -void -EnableMapUnmapEvents(WindowPtr pWin) -{ - assert (windowDisableMapUnmapEvents != NULL); - - windowDisableMapUnmapEvents = NULL; -} - -static Bool -MapUnmapEventsEnabled(WindowPtr pWin) -{ - return pWin != windowDisableMapUnmapEvents; -} - -/***** - * MapWindow - * If some other client has selected SubStructureReDirect on the parent - * and override-redirect is xFalse, then a MapRequest event is generated, - * but the window remains unmapped. Otherwise, the window is mapped and a - * MapNotify event is generated. - *****/ - -int -MapWindow(WindowPtr pWin, ClientPtr client) -{ - ScreenPtr pScreen; - - WindowPtr pParent; - WindowPtr pLayerWin; - - if (pWin->mapped) - return(Success); - - /* general check for permission to map window */ - if (XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, RT_WINDOW, - pWin, RT_NONE, NULL, DixShowAccess) != Success) - return Success; - - pScreen = pWin->drawable.pScreen; - if ( (pParent = pWin->parent) ) - { - xEvent event; - Bool anyMarked; - - if ((!pWin->overrideRedirect) && - (RedirectSend(pParent) - )) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = MapRequest; - event.u.mapRequest.window = pWin->drawable.id; - event.u.mapRequest.parent = pParent->drawable.id; - - if (MaybeDeliverEventsToClient(pParent, &event, 1, - SubstructureRedirectMask, client) == 1) - return(Success); - } - - pWin->mapped = TRUE; - if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = MapNotify; - event.u.mapNotify.window = pWin->drawable.id; - event.u.mapNotify.override = pWin->overrideRedirect; - DeliverEvents(pWin, &event, 1, NullWindow); - } - - if (!pParent->realized) - return(Success); - RealizeTree(pWin); - if (pWin->viewable) - { - anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, - &pLayerWin); - if (anyMarked) - { - (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTMap); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, VTMap); - } - WindowsRestructured (); - } - else - { - RegionRec temp; - - pWin->mapped = TRUE; - pWin->realized = TRUE; /* for roots */ - pWin->viewable = pWin->drawable.class == InputOutput; - /* We SHOULD check for an error value here XXX */ - (*pScreen->RealizeWindow)(pWin); - if (pScreen->ClipNotify) - (*pScreen->ClipNotify) (pWin, 0, 0); - if (pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(NullWindow, pWin, VTMap); - REGION_NULL(pScreen, &temp); - REGION_COPY(pScreen, &temp, &pWin->clipList); - (*pScreen->WindowExposures) (pWin, &temp, NullRegion); - REGION_UNINIT(pScreen, &temp); - } - - return(Success); -} - - -/***** - * MapSubwindows - * Performs a MapWindow all unmapped children of the window, in top - * to bottom stacking order. - *****/ - -void -MapSubwindows(WindowPtr pParent, ClientPtr client) -{ - WindowPtr pWin; - WindowPtr pFirstMapped = NullWindow; - ScreenPtr pScreen; - Mask parentRedirect; - Mask parentNotify; - xEvent event; - Bool anyMarked; - WindowPtr pLayerWin; - - pScreen = pParent->drawable.pScreen; - parentRedirect = RedirectSend(pParent); - parentNotify = SubSend(pParent); - anyMarked = FALSE; - for (pWin = pParent->firstChild; pWin; pWin = pWin->nextSib) - { - if (!pWin->mapped) - { - if (parentRedirect && !pWin->overrideRedirect) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = MapRequest; - event.u.mapRequest.window = pWin->drawable.id; - event.u.mapRequest.parent = pParent->drawable.id; - - if (MaybeDeliverEventsToClient(pParent, &event, 1, - SubstructureRedirectMask, client) == 1) - continue; - } - - pWin->mapped = TRUE; - if (parentNotify || StrSend(pWin)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = MapNotify; - event.u.mapNotify.window = pWin->drawable.id; - event.u.mapNotify.override = pWin->overrideRedirect; - DeliverEvents(pWin, &event, 1, NullWindow); - } - - if (!pFirstMapped) - pFirstMapped = pWin; - if (pParent->realized) - { - RealizeTree(pWin); - if (pWin->viewable) - { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, - (WindowPtr *)NULL); - } - } - } - } - - if (pFirstMapped) - { - pLayerWin = (*pScreen->GetLayerWindow)(pParent); - if (pLayerWin->parent != pParent) { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pLayerWin, - pLayerWin, - (WindowPtr *)NULL); - pFirstMapped = pLayerWin; - } - if (anyMarked) - { - (*pScreen->ValidateTree)(pLayerWin->parent, pFirstMapped, VTMap); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstMapped, - VTMap); - WindowsRestructured (); - } -} - -static void -UnrealizeTree( - WindowPtr pWin, - Bool fromConfigure) -{ - WindowPtr pChild; - UnrealizeWindowProcPtr Unrealize; - MarkUnrealizedWindowProcPtr MarkUnrealizedWindow; - - Unrealize = pWin->drawable.pScreen->UnrealizeWindow; - MarkUnrealizedWindow = pWin->drawable.pScreen->MarkUnrealizedWindow; - pChild = pWin; - while (1) - { - if (pChild->realized) - { - pChild->realized = FALSE; - pChild->visibility = VisibilityNotViewable; -#ifdef PANORAMIX - if(!noPanoramiXExtension && !pChild->drawable.pScreen->myNum) { - PanoramiXRes *win; - int rc = dixLookupResourceByType((pointer *)&win, - pChild->drawable.id, XRT_WINDOW, - serverClient, DixWriteAccess); - if (rc == Success) - win->u.win.visibility = VisibilityNotViewable; - } -#endif - (* Unrealize)(pChild); - if (MapUnmapEventsEnabled(pWin)) - DeleteWindowFromAnyEvents(pChild, FALSE); - if (pChild->viewable) - { - pChild->viewable = FALSE; - (* MarkUnrealizedWindow)(pChild, pWin, fromConfigure); - pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; - } - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - return; - pChild = pChild->nextSib; - } -} - -/***** - * UnmapWindow - * If the window is already unmapped, this request has no effect. - * Otherwise, the window is unmapped and an UnMapNotify event is - * generated. Cannot unmap a root window. - *****/ - -int -UnmapWindow(WindowPtr pWin, Bool fromConfigure) -{ - WindowPtr pParent; - xEvent event; - Bool wasRealized = (Bool)pWin->realized; - Bool wasViewable = (Bool)pWin->viewable; - ScreenPtr pScreen = pWin->drawable.pScreen; - WindowPtr pLayerWin = pWin; - - if ((!pWin->mapped) || (!(pParent = pWin->parent))) - return(Success); - if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = UnmapNotify; - event.u.unmapNotify.window = pWin->drawable.id; - event.u.unmapNotify.fromConfigure = fromConfigure; - DeliverEvents(pWin, &event, 1, NullWindow); - } - if (wasViewable && !fromConfigure) - { - pWin->valdata = UnmapValData; - (*pScreen->MarkOverlappedWindows)(pWin, pWin->nextSib, &pLayerWin); - (*pScreen->MarkWindow)(pLayerWin->parent); - } - pWin->mapped = FALSE; - if (wasRealized) - UnrealizeTree(pWin, fromConfigure); - if (wasViewable) - { - if (!fromConfigure) - { - (*pScreen->ValidateTree)(pLayerWin->parent, pWin, VTUnmap); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (!fromConfigure && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap); - } - if (wasRealized && !fromConfigure) - WindowsRestructured (); - return(Success); -} - -/***** - * UnmapSubwindows - * Performs an UnmapWindow request with the specified mode on all mapped - * children of the window, in bottom to top stacking order. - *****/ - -void -UnmapSubwindows(WindowPtr pWin) -{ - WindowPtr pChild, pHead; - xEvent event; - Bool wasRealized = (Bool)pWin->realized; - Bool wasViewable = (Bool)pWin->viewable; - Bool anyMarked = FALSE; - Mask parentNotify; - WindowPtr pLayerWin = NULL; - ScreenPtr pScreen = pWin->drawable.pScreen; - - if (!pWin->firstChild) - return; - parentNotify = SubSend(pWin); - pHead = RealChildHead(pWin); - - if (wasViewable) - pLayerWin = (*pScreen->GetLayerWindow)(pWin); - - for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) - { - if (pChild->mapped) - { - if (parentNotify || StrSend(pChild)) - { - event.u.u.type = UnmapNotify; - event.u.unmapNotify.window = pChild->drawable.id; - event.u.unmapNotify.fromConfigure = xFalse; - DeliverEvents(pChild, &event, 1, NullWindow); - } - if (pChild->viewable) - { - pChild->valdata = UnmapValData; - anyMarked = TRUE; - } - pChild->mapped = FALSE; - if (pChild->realized) - UnrealizeTree(pChild, FALSE); - if (wasViewable) - { - } - } - } - if (wasViewable) - { - if (anyMarked) - { - if (pLayerWin->parent == pWin) - (*pScreen->MarkWindow)(pWin); - else - { - WindowPtr ptmp; - (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin, - (WindowPtr *)NULL); - (*pScreen->MarkWindow)(pLayerWin->parent); - - /* Windows between pWin and pLayerWin may not have been marked */ - ptmp = pWin; - - while (ptmp != pLayerWin->parent) - { - (*pScreen->MarkWindow)(ptmp); - ptmp = ptmp->parent; - } - pHead = pWin->firstChild; - } - (*pScreen->ValidateTree)(pLayerWin->parent, pHead, VTUnmap); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap); - } - if (wasRealized) - WindowsRestructured (); -} - - -void -HandleSaveSet(ClientPtr client) -{ - WindowPtr pParent, pWin; - int j; - - for (j=0; jnumSaved; j++) - { - pWin = SaveSetWindow(client->saveSet[j]); -#ifdef XFIXES - if (SaveSetToRoot(client->saveSet[j])) - pParent = WindowTable[pWin->drawable.pScreen->myNum]; - else -#endif - { - pParent = pWin->parent; - while (pParent && (wClient (pParent) == client)) - pParent = pParent->parent; - } - if (pParent) - { - if (pParent != pWin->parent) - { -#ifdef XFIXES - /* unmap first so that ReparentWindow doesn't remap */ - if (!SaveSetShouldMap (client->saveSet[j])) - UnmapWindow(pWin, FALSE); -#endif - ReparentWindow(pWin, pParent, - pWin->drawable.x - wBorderWidth (pWin) - pParent->drawable.x, - pWin->drawable.y - wBorderWidth (pWin) - pParent->drawable.y, - client); - if(!pWin->realized && pWin->mapped) - pWin->mapped = FALSE; - } -#ifdef XFIXES - if (SaveSetShouldMap (client->saveSet[j])) -#endif - MapWindow(pWin, client); - } - } - xfree(client->saveSet); - client->numSaved = 0; - client->saveSet = (SaveSetElt *)NULL; -} - -/** - * - * \param x,y in root - */ -Bool -PointInWindowIsVisible(WindowPtr pWin, int x, int y) -{ - BoxRec box; - - if (!pWin->realized) - return (FALSE); - if (POINT_IN_REGION(pWin->drawable.pScreen, &pWin->borderClip, - x, y, &box) - && (!wInputShape(pWin) || - POINT_IN_REGION(pWin->drawable.pScreen, - wInputShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box))) - return(TRUE); - return(FALSE); -} - - -RegionPtr -NotClippedByChildren(WindowPtr pWin) -{ - ScreenPtr pScreen; - RegionPtr pReg; - - pScreen = pWin->drawable.pScreen; - pReg = REGION_CREATE(pScreen, NullBox, 1); - if (pWin->parent || - screenIsSaved != SCREEN_SAVER_ON || - !HasSaverWindow (pWin->drawable.pScreen->myNum)) - { - REGION_INTERSECT(pScreen, pReg, &pWin->borderClip, &pWin->winSize); - } - return(pReg); -} - -void -SendVisibilityNotify(WindowPtr pWin) -{ - xEvent event; -#ifndef NO_XINERAMA_PORT - unsigned int visibility = pWin->visibility; -#endif - if (!MapUnmapEventsEnabled(pWin)) - return; -#ifdef PANORAMIX - /* This is not quite correct yet, but it's close */ - if(!noPanoramiXExtension) { - PanoramiXRes *win; - WindowPtr pWin2; - int rc, i, Scrnum; - - Scrnum = pWin->drawable.pScreen->myNum; - - win = PanoramiXFindIDByScrnum(XRT_WINDOW, pWin->drawable.id, Scrnum); - - if(!win || (win->u.win.visibility == visibility)) - return; - - switch(visibility) { - case VisibilityUnobscured: - for(i = 0; i < PanoramiXNumScreens; i++) { - if(i == Scrnum) continue; - - rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient, - DixWriteAccess); - - if (rc == Success) { - if(pWin2->visibility == VisibilityPartiallyObscured) - return; - - if(!i) pWin = pWin2; - } - } - break; - case VisibilityPartiallyObscured: - if(Scrnum) { - rc = dixLookupWindow(&pWin2, win->info[0].id, serverClient, - DixWriteAccess); - if (rc == Success) pWin = pWin2; - } - break; - case VisibilityFullyObscured: - for(i = 0; i < PanoramiXNumScreens; i++) { - if(i == Scrnum) continue; - - rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient, - DixWriteAccess); - - if (rc == Success) { - if(pWin2->visibility != VisibilityFullyObscured) - return; - - if(!i) pWin = pWin2; - } - } - break; - } - - win->u.win.visibility = visibility; - } -#endif - - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = VisibilityNotify; - event.u.visibility.window = pWin->drawable.id; - event.u.visibility.state = visibility; - DeliverEvents(pWin, &event, 1, NullWindow); -} - -#define RANDOM_WIDTH 32 - -#ifndef NOLOGOHACK -static void DrawLogo( - WindowPtr pWin -); -#endif - -int -dixSaveScreens(ClientPtr client, int on, int mode) -{ - int rc, i, what, type; - - if (on == SCREEN_SAVER_FORCER) - { - if (mode == ScreenSaverReset) - what = SCREEN_SAVER_OFF; - else - what = SCREEN_SAVER_ON; - type = what; - } - else - { - what = on; - type = what; - if (what == screenIsSaved) - type = SCREEN_SAVER_CYCLE; - } - - for (i = 0; i < screenInfo.numScreens; i++) { - rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i], - DixShowAccess | DixHideAccess); - if (rc != Success) - return rc; - } - for (i = 0; i < screenInfo.numScreens; i++) - { - if (on == SCREEN_SAVER_FORCER) - (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], on); - if (savedScreenInfo[i].ExternalScreenSaver) - { - if ((*savedScreenInfo[i].ExternalScreenSaver) - (screenInfo.screens[i], type, on == SCREEN_SAVER_FORCER)) - continue; - } - if (type == screenIsSaved) - continue; - switch (type) { - case SCREEN_SAVER_OFF: - if (savedScreenInfo[i].blanked == SCREEN_IS_BLANKED) - { - (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], - what); - } - else if (HasSaverWindow (i)) - { - savedScreenInfo[i].pWindow = NullWindow; - FreeResource(savedScreenInfo[i].wid, RT_NONE); - } - break; - case SCREEN_SAVER_CYCLE: - if (savedScreenInfo[i].blanked == SCREEN_IS_TILED) - { - WindowPtr pWin = savedScreenInfo[i].pWindow; - /* make it look like screen saver is off, so that - * NotClippedByChildren will compute a clip list - * for the root window, so miPaintWindow works - */ - screenIsSaved = SCREEN_SAVER_OFF; -#ifndef NOLOGOHACK - if (logoScreenSaver) - (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, FALSE); -#endif - (*pWin->drawable.pScreen->MoveWindow)(pWin, - (short)(-(rand() % RANDOM_WIDTH)), - (short)(-(rand() % RANDOM_WIDTH)), - pWin->nextSib, VTMove); -#ifndef NOLOGOHACK - if (logoScreenSaver) - DrawLogo(pWin); -#endif - screenIsSaved = SCREEN_SAVER_ON; - } - /* - * Call the DDX saver in case it wants to do something - * at cycle time - */ - else if (savedScreenInfo[i].blanked == SCREEN_IS_BLANKED) - { - (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], - type); - } - break; - case SCREEN_SAVER_ON: - if (ScreenSaverBlanking != DontPreferBlanking) - { - if ((* screenInfo.screens[i]->SaveScreen) - (screenInfo.screens[i], what)) - { - savedScreenInfo[i].blanked = SCREEN_IS_BLANKED; - continue; - } - if ((ScreenSaverAllowExposures != DontAllowExposures) && - TileScreenSaver(i, SCREEN_IS_BLACK)) - { - savedScreenInfo[i].blanked = SCREEN_IS_BLACK; - continue; - } - } - if ((ScreenSaverAllowExposures != DontAllowExposures) && - TileScreenSaver(i, SCREEN_IS_TILED)) - { - savedScreenInfo[i].blanked = SCREEN_IS_TILED; - } - else - savedScreenInfo[i].blanked = SCREEN_ISNT_SAVED; - break; - } - } - screenIsSaved = what; - if (mode == ScreenSaverReset) { - if (on == SCREEN_SAVER_FORCER) { - UpdateCurrentTimeIf(); - lastDeviceEventTime = currentTime; - } - SetScreenSaverTimer(); - } - return Success; -} - -int -SaveScreens(int on, int mode) -{ - return dixSaveScreens(serverClient, on, mode); -} - -static Bool -TileScreenSaver(int i, int kind) -{ - int j; - int result; - XID attributes[3]; - Mask mask; - WindowPtr pWin; - CursorMetricRec cm; - unsigned char *srcbits, *mskbits; - CursorPtr cursor; - XID cursorID = 0; - int attri; - - mask = 0; - attri = 0; - switch (kind) { - case SCREEN_IS_TILED: - switch (WindowTable[i]->backgroundState) { - case BackgroundPixel: - attributes[attri++] = WindowTable[i]->background.pixel; - mask |= CWBackPixel; - break; - case BackgroundPixmap: - attributes[attri++] = None; - mask |= CWBackPixmap; - break; - default: - break; - } - break; - case SCREEN_IS_BLACK: - attributes[attri++] = WindowTable[i]->drawable.pScreen->blackPixel; - mask |= CWBackPixel; - break; - } - mask |= CWOverrideRedirect; - attributes[attri++] = xTrue; - - /* - * create a blank cursor - */ - - cm.width=16; - cm.height=16; - cm.xhot=8; - cm.yhot=8; - srcbits = xalloc( BitmapBytePad(32)*16); - mskbits = xalloc( BitmapBytePad(32)*16); - if (!srcbits || !mskbits) - { - xfree(srcbits); - xfree(mskbits); - cursor = 0; - } - else - { - for (j=0; jwidth + RANDOM_WIDTH, - (unsigned short)screenInfo.screens[i]->height + RANDOM_WIDTH, - 0, InputOutput, mask, attributes, 0, serverClient, - wVisual (WindowTable[i]), &result); - - if (cursor) - FreeResource (cursorID, RT_NONE); - - if (!pWin) - return FALSE; - - if (!AddResource(pWin->drawable.id, RT_WINDOW, - (pointer)savedScreenInfo[i].pWindow)) - return FALSE; - - if (mask & CWBackPixmap) - { - MakeRootTile (pWin); - (*pWin->drawable.pScreen->ChangeWindowAttributes)(pWin, CWBackPixmap); - } - MapWindow(pWin, serverClient); -#ifndef NOLOGOHACK - if (kind == SCREEN_IS_TILED && logoScreenSaver) - DrawLogo(pWin); -#endif - return TRUE; -} - -/* - * FindWindowWithOptional - * - * search ancestors of the given window for an entry containing - * a WindowOpt structure. Assumptions: some parent will - * contain the structure. - */ - -WindowPtr -FindWindowWithOptional (WindowPtr w) -{ - do - w = w->parent; - while (!w->optional); - return w; -} - -/* - * CheckWindowOptionalNeed - * - * check each optional entry in the given window to see if - * the value is satisfied by the default rules. If so, - * release the optional record - */ - -void -CheckWindowOptionalNeed (WindowPtr w) -{ - WindowOptPtr optional; - WindowOptPtr parentOptional; - - if (!w->parent || !w->optional) - return; - optional = w->optional; - if (optional->dontPropagateMask != DontPropagateMasks[w->dontPropagate]) - return; - if (optional->otherEventMasks != 0) - return; - if (optional->otherClients != NULL) - return; - if (optional->passiveGrabs != NULL) - return; - if (optional->userProps != NULL) - return; - if (optional->backingBitPlanes != ~0L) - return; - if (optional->backingPixel != 0) - return; - if (optional->boundingShape != NULL) - return; - if (optional->clipShape != NULL) - return; - if (optional->inputShape != NULL) - return; - if (optional->inputMasks != NULL) - return; - if (optional->deviceCursors != NULL) - { - DevCursNodePtr pNode = optional->deviceCursors; - while(pNode) - { - if (pNode->cursor != None) - return; - pNode = pNode->next; - } - } - - parentOptional = FindWindowWithOptional(w)->optional; - if (optional->visual != parentOptional->visual) - return; - if (optional->cursor != None && - (optional->cursor != parentOptional->cursor || - w->parent->cursorIsNone)) - return; - if (optional->colormap != parentOptional->colormap) - return; - DisposeWindowOptional (w); -} - -/* - * MakeWindowOptional - * - * create an optional record and initialize it with the default - * values. - */ - -Bool -MakeWindowOptional (WindowPtr pWin) -{ - WindowOptPtr optional; - WindowOptPtr parentOptional; - - if (pWin->optional) - return TRUE; - optional = xalloc (sizeof (WindowOptRec)); - if (!optional) - return FALSE; - optional->dontPropagateMask = DontPropagateMasks[pWin->dontPropagate]; - optional->otherEventMasks = 0; - optional->otherClients = NULL; - optional->passiveGrabs = NULL; - optional->userProps = NULL; - optional->backingBitPlanes = ~0L; - optional->backingPixel = 0; - optional->boundingShape = NULL; - optional->clipShape = NULL; - optional->inputShape = NULL; - optional->inputMasks = NULL; - optional->deviceCursors = NULL; - - parentOptional = FindWindowWithOptional(pWin)->optional; - optional->visual = parentOptional->visual; - if (!pWin->cursorIsNone) - { - optional->cursor = parentOptional->cursor; - optional->cursor->refcnt++; - } - else - { - optional->cursor = None; - } - optional->colormap = parentOptional->colormap; - pWin->optional = optional; - return TRUE; -} - -/* - * Changes the cursor struct for the given device and the given window. - * A cursor that does not have a device cursor set will use whatever the - * standard cursor is for the window. If all devices have a cursor set, - * changing the window cursor (e.g. using XDefineCursor()) will not have any - * visible effect. Only when one of the device cursors is set to None again, - * this device's cursor will display the changed standard cursor. - * - * CursorIsNone of the window struct is NOT modified if you set a device - * cursor. - * - * Assumption: If there is a node for a device in the list, the device has a - * cursor. If the cursor is set to None, it is inherited by the parent. - */ -int -ChangeWindowDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - CursorPtr pCursor) -{ - DevCursNodePtr pNode, pPrev; - CursorPtr pOldCursor = NULL; - ScreenPtr pScreen; - WindowPtr pChild; - - if (!pWin->optional && !MakeWindowOptional(pWin)) - return BadAlloc; - - /* 1) Check if window has device cursor set - * Yes: 1.1) swap cursor with given cursor if parent does not have same - * cursor, free old cursor - * 1.2) free old cursor, use parent cursor - * No: 1.1) add node to beginning of list. - * 1.2) add cursor to node if parent does not have same cursor - * 1.3) use parent cursor if parent does not have same cursor - * 2) Patch up children if child has a devcursor - * 2.1) if child has cursor None, it inherited from parent, set to old - * cursor - * 2.2) if child has same cursor as new cursor, remove and set to None - */ - - pScreen = pWin->drawable.pScreen; - - if (WindowSeekDeviceCursor(pWin, pDev, &pNode, &pPrev)) - { - /* has device cursor */ - - if (pNode->cursor == pCursor) - return Success; - - pOldCursor = pNode->cursor; - - if (!pCursor) /* remove from list */ - { - if(pPrev) - pPrev->next = pNode->next; - else - /* first item in list */ - pWin->optional->deviceCursors = pNode->next; - - xfree(pNode); - goto out; - } - - } else - { - /* no device cursor yet */ - DevCursNodePtr pNewNode; - - if (!pCursor) - return Success; - - pNewNode = xalloc(sizeof(DevCursNodeRec)); - pNewNode->dev = pDev; - pNewNode->next = pWin->optional->deviceCursors; - pWin->optional->deviceCursors = pNewNode; - pNode = pNewNode; - - } - - if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor)) - pNode->cursor = None; - else - { - pNode->cursor = pCursor; - pCursor->refcnt++; - } - - pNode = pPrev = NULL; - /* fix up children */ - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev)) - { - if (pNode->cursor == None) /* inherited from parent */ - { - pNode->cursor = pOldCursor; - pOldCursor->refcnt++; - } else if (pNode->cursor == pCursor) - { - pNode->cursor = None; - FreeCursor(pCursor, (Cursor)0); /* fix up refcnt */ - } - } - } - -out: - if (pWin->realized) - WindowHasNewCursor(pWin); - - if (pOldCursor) - FreeCursor(pOldCursor, (Cursor)0); - - /* FIXME: We SHOULD check for an error value here XXX - (comment taken from ChangeWindowAttributes) */ - (*pScreen->ChangeWindowAttributes)(pWin, CWCursor); - - return Success; -} - -/* Get device cursor for given device or None if none is set */ -CursorPtr -WindowGetDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev) -{ - DevCursorList pList; - - if (!pWin->optional || !pWin->optional->deviceCursors) - return NULL; - - pList = pWin->optional->deviceCursors; - - while(pList) - { - if (pList->dev == pDev) - { - if (pList->cursor == None) /* inherited from parent */ - return WindowGetDeviceCursor(pWin->parent, pDev); - else - return pList->cursor; - } - pList = pList->next; - } - return NULL; -} - -/* Searches for a DevCursorNode for the given window and device. If one is - * found, return True and set pNode and pPrev to the node and to the node - * before the node respectively. Otherwise return False. - * If the device is the first in list, pPrev is set to NULL. - */ -static Bool -WindowSeekDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - DevCursNodePtr* pNode, - DevCursNodePtr* pPrev) -{ - DevCursorList pList; - - if (!pWin->optional) - return FALSE; - - pList = pWin->optional->deviceCursors; - - if (pList && pList->dev == pDev) - { - *pNode = pList; - *pPrev = NULL; - return TRUE; - } - - while(pList) - { - if (pList->next) - { - if (pList->next->dev == pDev) - { - *pNode = pList->next; - *pPrev = pList; - return TRUE; - } - } - pList = pList->next; - } - return FALSE; -} - -/* Return True if a parent has the same device cursor set or False if - * otherwise - */ -static Bool -WindowParentHasDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - CursorPtr pCursor) -{ - WindowPtr pParent; - DevCursNodePtr pParentNode, pParentPrev; - - pParent = pWin->parent; - while(pParent) - { - if (WindowSeekDeviceCursor(pParent, pDev, - &pParentNode, &pParentPrev)) - { - /* if there is a node in the list, the win has a dev cursor */ - if (!pParentNode->cursor) /* inherited. loop needs to cont. */ - { - } else if (pParentNode->cursor == pCursor) /* inherit */ - return TRUE; - else /* different cursor */ - return FALSE; - } - else - /* parent does not have a device cursor for our device */ - return FALSE; - } - return FALSE; -} - -#ifndef NOLOGOHACK -static void -DrawLogo(WindowPtr pWin) -{ - DrawablePtr pDraw; - ScreenPtr pScreen; - int x, y; - unsigned int width, height, size; - GC *pGC; - int rc, thin, gap, d31; - DDXPointRec poly[4]; - ChangeGCVal fore[2], back[2]; - xrgb rgb[2]; - BITS32 fmask, bmask; - ColormapPtr cmap; - - pDraw = (DrawablePtr)pWin; - pScreen = pDraw->pScreen; - x = -pWin->origin.x; - y = -pWin->origin.y; - width = pScreen->width; - height = pScreen->height; - pGC = GetScratchGC(pScreen->rootDepth, pScreen); - if (!pGC) - return; - - if ((rand() % 100) <= 17) /* make the probability for white fairly low */ - fore[0].val = pScreen->whitePixel; - else - fore[0].val = pScreen->blackPixel; - if (pWin->backgroundState == BackgroundPixel) { - rc = dixLookupResourceByType((pointer *)&cmap, wColormap(pWin), - RT_COLORMAP, serverClient, DixReadAccess); - if (rc == Success) { - Pixel querypixels[2]; - - querypixels[0] = fore[0].val; - querypixels[1] = pWin->background.pixel; - QueryColors(cmap, 2, querypixels, rgb); - if ((rgb[0].red == rgb[1].red) && - (rgb[0].green == rgb[1].green) && - (rgb[0].blue == rgb[1].blue)) { - if (fore[0].val == pScreen->blackPixel) - fore[0].val = pScreen->whitePixel; - else - fore[0].val = pScreen->blackPixel; - } - } - } - fore[1].val = FillSolid; - fmask = GCForeground|GCFillStyle; - if (pWin->backgroundState == BackgroundPixel) { - back[0].val = pWin->background.pixel; - back[1].val = FillSolid; - bmask = GCForeground|GCFillStyle; - } else { - back[0].val = 0; - back[1].val = 0; - dixChangeGC(NullClient, pGC, GCTileStipXOrigin|GCTileStipYOrigin, - NULL, back); - back[0].val = FillTiled; - back[1].ptr = pWin->background.pixmap; - bmask = GCFillStyle|GCTile; - } - - /* should be the same as the reference function XmuDrawLogo() */ - - size = width; - if (height < width) - size = height; - size = RANDOM_WIDTH + rand() % (size - RANDOM_WIDTH); - size &= ~1; - x += rand() % (width - size); - y += rand() % (height - size); - -/* - * Draw what will be the thin strokes. - * - * ----- - * / / - * / / - * / / - * / / - * /____/ - * d - * - * Point d is 9/44 (~1/5) of the way across. - */ - - thin = (size / 11); - if (thin < 1) thin = 1; - gap = (thin+3) / 4; - d31 = thin + thin + gap; - poly[0].x = x + size; poly[0].y = y; - poly[1].x = x + size-d31; poly[1].y = y; - poly[2].x = x + 0; poly[2].y = y + size; - poly[3].x = x + d31; poly[3].y = y + size; - dixChangeGC(NullClient, pGC, fmask, NULL, fore); - ValidateGC(pDraw, pGC); - (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); - -/* - * Erase area not needed for lower thin stroke. - * - * ------ - * / / - * / __ / - * / / / - * / / / - * /__/__/ - */ - - poly[0].x = x + d31/2; poly[0].y = y + size; - poly[1].x = x + size / 2; poly[1].y = y + size/2; - poly[2].x = x + (size/2)+(d31-(d31/2)); poly[2].y = y + size/2; - poly[3].x = x + d31; poly[3].y = y + size; - dixChangeGC(NullClient, pGC, bmask, NULL, back); - ValidateGC(pDraw, pGC); - (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); - -/* - * Erase area not needed for upper thin stroke. - * - * ------ - * / / / - * /--/ / - * / / - * / / - * /_____/ - */ - - poly[0].x = x + size - d31/2; poly[0].y = y; - poly[1].x = x + size / 2; poly[1].y = y + size/2; - poly[2].x = x + (size/2)-(d31-(d31/2)); poly[2].y = y + size/2; - poly[3].x = x + size - d31; poly[3].y = y; - ValidateGC(pDraw, pGC); - (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); - -/* - * Draw thick stroke. - * Point b is 1/4 of the way across. - * - * b - * ----- - * \ \ - * \ \ - * \ \ - * \ \ - * \____\ - */ - - poly[0].x = x; poly[0].y = y; - poly[1].x = x + size/4; poly[1].y = y; - poly[2].x = x + size; poly[2].y = y + size; - poly[3].x = x + size - size/4; poly[3].y = y + size; - dixChangeGC(NullClient, pGC, fmask, NULL, fore); - ValidateGC(pDraw, pGC); - (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); - -/* - * Erase to create gap. - * - * / - * / - * / - * / - * / - */ - - poly[0].x = x + size- thin; poly[0].y = y; - poly[1].x = x + size-( thin+gap); poly[1].y = y; - poly[2].x = x + thin; poly[2].y = y + size; - poly[3].x = x + thin + gap; poly[3].y = y + size; - dixChangeGC(NullClient, pGC, bmask, NULL, back); - ValidateGC(pDraw, pGC); - (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); - - FreeScratchGC(pGC); -} - -#endif +/* + +Copyright (c) 2006, Red Hat, Inc. + +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. + +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 "misc.h" +#include "scrnintstr.h" +#include "os.h" +#include "regionstr.h" +#include "validate.h" +#include "windowstr.h" +#include "input.h" +#include "inputstr.h" +#include "resource.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "servermd.h" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif +#include "dixevents.h" +#include "globals.h" +#include "mi.h" /* miPaintWindow */ + +#include "privates.h" +#include "xace.h" + +/****** + * Window stuff for server + * + * CreateRootWindow, CreateWindow, ChangeWindowAttributes, + * GetWindowAttributes, DeleteWindow, DestroySubWindows, + * HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows, + * UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow, + * ChangeWindowDeviceCursor + ******/ + +static unsigned char _back_lsb[4] = {0x88, 0x22, 0x44, 0x11}; +static unsigned char _back_msb[4] = {0x11, 0x44, 0x22, 0x88}; + +static Bool WindowParentHasDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + CursorPtr pCurs); +static Bool +WindowSeekDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + DevCursNodePtr* pNode, + DevCursNodePtr* pPrev); + +int screenIsSaved = SCREEN_SAVER_OFF; + +ScreenSaverStuffRec savedScreenInfo[MAXSCREENS]; + +static int FocusPrivatesKeyIndex; +DevPrivateKey FocusPrivatesKey = &FocusPrivatesKeyIndex; + +static Bool TileScreenSaver(int i, int kind); + + +#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \ + CWDontPropagate | CWOverrideRedirect | CWCursor ) + +#define BOXES_OVERLAP(b1, b2) \ + (!( ((b1)->x2 <= (b2)->x1) || \ + ( ((b1)->x1 >= (b2)->x2)) || \ + ( ((b1)->y2 <= (b2)->y1)) || \ + ( ((b1)->y1 >= (b2)->y2)) ) ) + +#define RedirectSend(pWin) \ + ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureRedirectMask) + +#define SubSend(pWin) \ + ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask) + +#define StrSend(pWin) \ + ((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask) + +#define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent)) + +#ifdef DEBUG +/****** + * PrintWindowTree + * For debugging only + ******/ + +static void +PrintChildren(WindowPtr p1, int indent) +{ + WindowPtr p2; + int i; + + while (p1) + { + p2 = p1->firstChild; + ErrorF("[dix] "); + for (i=0; idrawable.id); + miPrintRegion(&p1->clipList); + PrintChildren(p2, indent+4); + p1 = p1->nextSib; + } +} + +static void +PrintWindowTree(void) +{ + int i; + WindowPtr pWin, p1; + + for (i=0; iclipList); + p1 = pWin->firstChild; + PrintChildren(p1, 4); + } +} +#endif + +int +TraverseTree(WindowPtr pWin, VisitWindowProcPtr func, pointer data) +{ + int result; + WindowPtr pChild; + + if (!(pChild = pWin)) + return(WT_NOMATCH); + while (1) + { + result = (* func)(pChild, data); + if (result == WT_STOPWALKING) + return(WT_STOPWALKING); + if ((result == WT_WALKCHILDREN) && pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } + return(WT_NOMATCH); +} + +/***** + * WalkTree + * Walk the window tree, for SCREEN, preforming FUNC(pWin, data) on + * each window. If FUNC returns WT_WALKCHILDREN, traverse the children, + * if it returns WT_DONTWALKCHILDREN, dont. If it returns WT_STOPWALKING + * exit WalkTree. Does depth-first traverse. + *****/ + +int +WalkTree(ScreenPtr pScreen, VisitWindowProcPtr func, pointer data) +{ + return(TraverseTree(WindowTable[pScreen->myNum], func, data)); +} + +/* hack for forcing backing store on all windows */ +int defaultBackingStore = NotUseful; +/* hack to force no backing store */ +Bool disableBackingStore = FALSE; +Bool enableBackingStore = FALSE; + +static void +SetWindowToDefaults(WindowPtr pWin) +{ + pWin->prevSib = NullWindow; + pWin->firstChild = NullWindow; + pWin->lastChild = NullWindow; + + pWin->valdata = (ValidatePtr)NULL; + pWin->optional = (WindowOptPtr)NULL; + pWin->cursorIsNone = TRUE; + + pWin->backingStore = NotUseful; + pWin->DIXsaveUnder = FALSE; + pWin->backStorage = (pointer) NULL; + + pWin->mapped = FALSE; /* off */ + pWin->realized = FALSE; /* off */ + pWin->viewable = FALSE; + pWin->visibility = VisibilityNotViewable; + pWin->overrideRedirect = FALSE; + pWin->saveUnder = FALSE; + + pWin->bitGravity = ForgetGravity; + pWin->winGravity = NorthWestGravity; + + pWin->eventMask = 0; + pWin->deliverableEvents = 0; + pWin->dontPropagate = 0; + pWin->forcedBS = FALSE; + pWin->redirectDraw = RedirectDrawNone; + pWin->forcedBG = FALSE; + +#ifdef ROOTLESS + pWin->rootlessUnhittable = FALSE; +#endif +} + +static void +MakeRootTile(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + GCPtr pGC; + unsigned char back[128]; + int len = BitmapBytePad(sizeof(long)); + unsigned char *from, *to; + int i, j; + + pWin->background.pixmap = (*pScreen->CreatePixmap)(pScreen, 4, 4, + pScreen->rootDepth, 0); + + pWin->backgroundState = BackgroundPixmap; + pGC = GetScratchGC(pScreen->rootDepth, pScreen); + if (!pWin->background.pixmap || !pGC) + FatalError("could not create root tile"); + + { + ChangeGCVal attributes[2]; + + attributes[0].val = pScreen->whitePixel; + attributes[1].val = pScreen->blackPixel; + + (void)ChangeGC(NullClient, pGC, GCForeground | GCBackground, attributes); + } + + ValidateGC((DrawablePtr)pWin->background.pixmap, pGC); + + from = (screenInfo.bitmapBitOrder == LSBFirst) ? _back_lsb : _back_msb; + to = back; + + for (i = 4; i > 0; i--, from++) + for (j = len; j > 0; j--) + *to++ = *from; + + (*pGC->ops->PutImage)((DrawablePtr)pWin->background.pixmap, pGC, 1, + 0, 0, len, 4, 0, XYBitmap, (char *)back); + + FreeScratchGC(pGC); + +} + +/***** + * CreateRootWindow + * Makes a window at initialization time for specified screen + *****/ + +Bool +CreateRootWindow(ScreenPtr pScreen) +{ + WindowPtr pWin; + BoxRec box; + PixmapFormatRec *format; + + pWin = malloc(sizeof(WindowRec)); + if (!pWin) + return FALSE; + + savedScreenInfo[pScreen->myNum].pWindow = NULL; + savedScreenInfo[pScreen->myNum].wid = FakeClientID(0); + savedScreenInfo[pScreen->myNum].ExternalScreenSaver = NULL; + screenIsSaved = SCREEN_SAVER_OFF; + + WindowTable[pScreen->myNum] = pWin; + + pWin->drawable.pScreen = pScreen; + pWin->drawable.type = DRAWABLE_WINDOW; + pWin->devPrivates = NULL; + + pWin->drawable.depth = pScreen->rootDepth; + for (format = screenInfo.formats; + format->depth != pScreen->rootDepth; + format++) + ; + pWin->drawable.bitsPerPixel = format->bitsPerPixel; + + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + pWin->parent = NullWindow; + SetWindowToDefaults(pWin); + + pWin->optional = malloc(sizeof (WindowOptRec)); + if (!pWin->optional) + return FALSE; + + pWin->optional->dontPropagateMask = 0; + pWin->optional->otherEventMasks = 0; + pWin->optional->otherClients = NULL; + pWin->optional->passiveGrabs = NULL; + pWin->optional->userProps = NULL; + pWin->optional->backingBitPlanes = ~0L; + pWin->optional->backingPixel = 0; + pWin->optional->boundingShape = NULL; + pWin->optional->clipShape = NULL; + pWin->optional->inputShape = NULL; + pWin->optional->inputMasks = NULL; + pWin->optional->deviceCursors = NULL; + pWin->optional->colormap = pScreen->defColormap; + pWin->optional->visual = pScreen->rootVisual; + + pWin->nextSib = NullWindow; + + pWin->drawable.id = FakeClientID(0); + + pWin->origin.x = pWin->origin.y = 0; + pWin->drawable.height = pScreen->height; + pWin->drawable.width = pScreen->width; + pWin->drawable.x = pWin->drawable.y = 0; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + REGION_INIT(pScreen, &pWin->clipList, &box, 1); + REGION_INIT(pScreen, &pWin->winSize, &box, 1); + REGION_INIT(pScreen, &pWin->borderSize, &box, 1); + REGION_INIT(pScreen, &pWin->borderClip, &box, 1); + + pWin->drawable.class = InputOutput; + pWin->optional->visual = pScreen->rootVisual; + + pWin->backgroundState = BackgroundPixel; + pWin->background.pixel = pScreen->whitePixel; + + pWin->borderIsPixel = TRUE; + pWin->border.pixel = pScreen->blackPixel; + pWin->borderWidth = 0; + + /* security creation/labeling check + */ + if (XaceHook(XACE_RESOURCE_ACCESS, serverClient, pWin->drawable.id, + RT_WINDOW, pWin, RT_NONE, NULL, DixCreateAccess)) + return FALSE; + + if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer)pWin)) + return FALSE; + + if (disableBackingStore) + pScreen->backingStoreSupport = NotUseful; + if (enableBackingStore) + pScreen->backingStoreSupport = Always; + + pScreen->saveUnderSupport = NotUseful; + + return TRUE; +} + +void +InitRootWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + int backFlag = CWBorderPixel | CWCursor | CWBackingStore; + + if (!(*pScreen->CreateWindow)(pWin)) + return; /* XXX */ + (*pScreen->PositionWindow)(pWin, 0, 0); + + pWin->cursorIsNone = FALSE; + pWin->optional->cursor = rootCursor; + rootCursor->refcnt++; + + + if (party_like_its_1989) { + MakeRootTile(pWin); + backFlag |= CWBackPixmap; + } else { + if (whiteRoot) + pWin->background.pixel = pScreen->whitePixel; + else + pWin->background.pixel = pScreen->blackPixel; + backFlag |= CWBackPixel; + } + + pWin->backingStore = defaultBackingStore; + pWin->forcedBS = (defaultBackingStore != NotUseful); + /* We SHOULD check for an error value here XXX */ + (*pScreen->ChangeWindowAttributes)(pWin, backFlag); + + MapWindow(pWin, serverClient); +} + +/* Set the region to the intersection of the rectangle and the + * window's winSize. The window is typically the parent of the + * window from which the region came. + */ + +static void +ClippedRegionFromBox(WindowPtr pWin, RegionPtr Rgn, + int x, int y, + int w, int h) +{ + ScreenPtr pScreen; + BoxRec box; + + pScreen = pWin->drawable.pScreen; + + box = *(REGION_EXTENTS(pScreen, &pWin->winSize)); + /* we do these calculations to avoid overflows */ + if (x > box.x1) + box.x1 = x; + if (y > box.y1) + box.y1 = y; + x += w; + if (x < box.x2) + box.x2 = x; + y += h; + if (y < box.y2) + box.y2 = y; + if (box.x1 > box.x2) + box.x2 = box.x1; + if (box.y1 > box.y2) + box.y2 = box.y1; + REGION_RESET(pScreen, Rgn, &box); + REGION_INTERSECT(pScreen, Rgn, Rgn, &pWin->winSize); +} + +static RealChildHeadProc realChildHeadProc = NULL; + +void +RegisterRealChildHeadProc (RealChildHeadProc proc) +{ + realChildHeadProc = proc; +} + + +WindowPtr +RealChildHead(WindowPtr pWin) +{ + if (realChildHeadProc) { + return realChildHeadProc (pWin); + } + + if (!pWin->parent && + (screenIsSaved == SCREEN_SAVER_ON) && + (HasSaverWindow (pWin->drawable.pScreen->myNum))) + return (pWin->firstChild); + else + return (NullWindow); +} + +/***** + * CreateWindow + * Makes a window in response to client request + *****/ + +WindowPtr +CreateWindow(Window wid, WindowPtr pParent, int x, int y, unsigned w, + unsigned h, unsigned bw, unsigned class, Mask vmask, XID *vlist, + int depth, ClientPtr client, VisualID visual, int *error) +{ + WindowPtr pWin; + WindowPtr pHead; + ScreenPtr pScreen; + xEvent event; + int idepth, ivisual; + Bool fOK; + DepthPtr pDepth; + PixmapFormatRec *format; + WindowOptPtr ancwopt; + + if (class == CopyFromParent) + class = pParent->drawable.class; + + if ((class != InputOutput) && (class != InputOnly)) + { + *error = BadValue; + client->errorValue = class; + return NullWindow; + } + + if ((class != InputOnly) && (pParent->drawable.class == InputOnly)) + { + *error = BadMatch; + return NullWindow; + } + + if ((class == InputOnly) && ((bw != 0) || (depth != 0))) + { + *error = BadMatch; + return NullWindow; + } + + pScreen = pParent->drawable.pScreen; + 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) + { + *error = BadMatch; + return NullWindow; + } + } + + if (((vmask & (CWBorderPixmap | CWBorderPixel)) == 0) && + (class != InputOnly) && + (depth != pParent->drawable.depth)) + { + *error = BadMatch; + return NullWindow; + } + + if (((vmask & CWColormap) == 0) && + (class != InputOnly) && + ((visual != ancwopt->visual) || (ancwopt->colormap == None))) + { + *error = BadMatch; + return NullWindow; + } + + pWin = malloc(sizeof(WindowRec)); + if (!pWin) + { + *error = BadAlloc; + return NullWindow; + } + pWin->drawable = pParent->drawable; + pWin->devPrivates = NULL; + pWin->drawable.depth = depth; + if (depth == pParent->drawable.depth) + pWin->drawable.bitsPerPixel = pParent->drawable.bitsPerPixel; + else + { + for (format = screenInfo.formats; format->depth != depth; format++) + ; + pWin->drawable.bitsPerPixel = format->bitsPerPixel; + } + if (class == InputOnly) + pWin->drawable.type = (short) UNDRAWABLE_WINDOW; + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + pWin->drawable.id = wid; + pWin->drawable.class = class; + + pWin->parent = pParent; + SetWindowToDefaults(pWin); + + if (visual != ancwopt->visual) + { + if (!MakeWindowOptional (pWin)) + { + free(pWin); + *error = BadAlloc; + return NullWindow; + } + pWin->optional->visual = visual; + pWin->optional->colormap = None; + } + + pWin->borderWidth = bw; + + /* security creation/labeling check + */ + *error = XaceHook(XACE_RESOURCE_ACCESS, client, wid, RT_WINDOW, pWin, + RT_WINDOW, pWin->parent, DixCreateAccess|DixSetAttrAccess); + if (*error != Success) { + free(pWin); + return NullWindow; + } + + pWin->backgroundState = XaceBackgroundNoneState(pWin); + pWin->background.pixel = pScreen->whitePixel; + + pWin->borderIsPixel = pParent->borderIsPixel; + pWin->border = pParent->border; + if (pWin->borderIsPixel == FALSE) + pWin->border.pixmap->refcnt++; + + pWin->origin.x = x + (int)bw; + pWin->origin.y = y + (int)bw; + pWin->drawable.width = w; + pWin->drawable.height = h; + pWin->drawable.x = pParent->drawable.x + x + (int)bw; + pWin->drawable.y = pParent->drawable.y + y + (int)bw; + + /* set up clip list correctly for unobscured WindowPtr */ + REGION_NULL(pScreen, &pWin->clipList); + REGION_NULL(pScreen, &pWin->borderClip); + REGION_NULL(pScreen, &pWin->winSize); + REGION_NULL(pScreen, &pWin->borderSize); + + pHead = RealChildHead(pParent); + if (pHead) + { + pWin->nextSib = pHead->nextSib; + if (pHead->nextSib) + pHead->nextSib->prevSib = pWin; + else + pParent->lastChild = pWin; + pHead->nextSib = pWin; + pWin->prevSib = pHead; + } + else + { + pWin->nextSib = pParent->firstChild; + if (pParent->firstChild) + pParent->firstChild->prevSib = pWin; + else + pParent->lastChild = pWin; + pParent->firstChild = pWin; + } + + SetWinSize (pWin); + SetBorderSize (pWin); + + /* We SHOULD check for an error value here XXX */ + if (!(*pScreen->CreateWindow)(pWin)) + { + *error = BadAlloc; + DeleteWindow(pWin, None); + return NullWindow; + } + /* We SHOULD check for an error value here XXX */ + (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); + + if (!(vmask & CWEventMask)) + RecalculateDeliverableEvents(pWin); + + if (vmask) + *error = ChangeWindowAttributes(pWin, vmask, vlist, wClient (pWin)); + else + *error = Success; + + if (*error != Success) + { + DeleteWindow(pWin, None); + return NullWindow; + } + if (!(vmask & CWBackingStore) && (defaultBackingStore != NotUseful)) + { + XID value = defaultBackingStore; + (void)ChangeWindowAttributes(pWin, CWBackingStore, &value, wClient (pWin)); + pWin->forcedBS = TRUE; + } + + if (SubSend(pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = CreateNotify; + event.u.createNotify.window = wid; + event.u.createNotify.parent = pParent->drawable.id; + event.u.createNotify.x = x; + event.u.createNotify.y = y; + event.u.createNotify.width = w; + event.u.createNotify.height = h; + event.u.createNotify.borderWidth = bw; + event.u.createNotify.override = pWin->overrideRedirect; + DeliverEvents(pParent, &event, 1, NullWindow); + } + return pWin; +} + +static void +DisposeWindowOptional (WindowPtr pWin) +{ + if (!pWin->optional) + return; + /* + * everything is peachy. Delete the optional record + * and clean up + */ + if (pWin->optional->cursor) + { + FreeCursor (pWin->optional->cursor, (Cursor)0); + pWin->cursorIsNone = FALSE; + } + else + pWin->cursorIsNone = TRUE; + + if (pWin->optional->deviceCursors) + { + DevCursorList pList; + DevCursorList pPrev; + pList = pWin->optional->deviceCursors; + while(pList) + { + if (pList->cursor) + FreeCursor(pList->cursor, (XID)0); + pPrev = pList; + pList = pList->next; + free(pPrev); + } + pWin->optional->deviceCursors = NULL; + } + + free(pWin->optional); + pWin->optional = NULL; +} + +static void +FreeWindowResources(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + DeleteWindowFromAnySaveSet(pWin); + DeleteWindowFromAnySelections(pWin); + DeleteWindowFromAnyEvents(pWin, TRUE); + REGION_UNINIT(pScreen, &pWin->clipList); + REGION_UNINIT(pScreen, &pWin->winSize); + REGION_UNINIT(pScreen, &pWin->borderClip); + REGION_UNINIT(pScreen, &pWin->borderSize); + if (wBoundingShape (pWin)) + REGION_DESTROY(pScreen, wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_DESTROY(pScreen, wClipShape (pWin)); + if (wInputShape (pWin)) + REGION_DESTROY(pScreen, wInputShape (pWin)); + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + + DeleteAllWindowProperties(pWin); + /* We SHOULD check for an error value here XXX */ + (*pScreen->DestroyWindow)(pWin); + DisposeWindowOptional (pWin); +} + +static void +CrushTree(WindowPtr pWin) +{ + WindowPtr pChild, pSib, pParent; + UnrealizeWindowProcPtr UnrealizeWindow; + xEvent event; + + if (!(pChild = pWin->firstChild)) + return; + UnrealizeWindow = pWin->drawable.pScreen->UnrealizeWindow; + while (1) + { + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (1) + { + pParent = pChild->parent; + if (SubStrSend(pChild, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = DestroyNotify; + event.u.destroyNotify.window = pChild->drawable.id; + DeliverEvents(pChild, &event, 1, NullWindow); + } + FreeResource(pChild->drawable.id, RT_WINDOW); + pSib = pChild->nextSib; + pChild->viewable = FALSE; + if (pChild->realized) + { + pChild->realized = FALSE; + (*UnrealizeWindow)(pChild); + } + FreeWindowResources(pChild); + dixFreePrivates(pChild->devPrivates); + free(pChild); + if ( (pChild = pSib) ) + break; + pChild = pParent; + pChild->firstChild = NullWindow; + pChild->lastChild = NullWindow; + if (pChild == pWin) + return; + } + } +} + +/***** + * DeleteWindow + * Deletes child of window then window itself + * If wid is None, don't send any events + *****/ + +int +DeleteWindow(pointer value, XID wid) + { + WindowPtr pParent; + WindowPtr pWin = (WindowPtr)value; + xEvent event; + + UnmapWindow(pWin, FALSE); + + CrushTree(pWin); + + pParent = pWin->parent; + if (wid && pParent && SubStrSend(pWin, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = DestroyNotify; + event.u.destroyNotify.window = pWin->drawable.id; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + FreeWindowResources(pWin); + if (pParent) + { + if (pParent->firstChild == pWin) + pParent->firstChild = pWin->nextSib; + if (pParent->lastChild == pWin) + pParent->lastChild = pWin->prevSib; + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + } + free(dixLookupPrivate(&pWin->devPrivates, FocusPrivatesKey)); + dixFreePrivates(pWin->devPrivates); + free(pWin); + return Success; +} + +int +DestroySubwindows(WindowPtr pWin, ClientPtr client) +{ + /* XXX + * The protocol is quite clear that each window should be + * destroyed in turn, however, unmapping all of the first + * eliminates most of the calls to ValidateTree. So, + * this implementation is incorrect in that all of the + * UnmapNotifies occur before all of the DestroyNotifies. + * If you care, simply delete the call to UnmapSubwindows. + */ + UnmapSubwindows(pWin); + while (pWin->lastChild) { + int rc = XaceHook(XACE_RESOURCE_ACCESS, client, + pWin->lastChild->drawable.id, RT_WINDOW, + pWin->lastChild, RT_NONE, NULL, DixDestroyAccess); + if (rc != Success) + return rc; + FreeResource(pWin->lastChild->drawable.id, RT_NONE); + } + return Success; +} + +/***** + * ChangeWindowAttributes + * + * The value-mask specifies which attributes are to be changed; the + * value-list contains one value for each one bit in the mask, from least + * to most significant bit in the mask. + *****/ + +int +ChangeWindowAttributes(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client) +{ + XID *pVlist; + PixmapPtr pPixmap; + Pixmap pixID; + CursorPtr pCursor, pOldCursor; + Cursor cursorID; + WindowPtr pChild; + Colormap cmap; + ColormapPtr pCmap; + xEvent xE; + int error, rc; + ScreenPtr pScreen; + Mask index2, tmask, vmaskCopy = 0; + unsigned int val; + Bool checkOptional = FALSE, borderRelative = FALSE; + + if ((pWin->drawable.class == InputOnly) && (vmask & (~INPUTONLY_LEGAL_MASK))) + return BadMatch; + + error = Success; + pScreen = pWin->drawable.pScreen; + pVlist = vlist; + tmask = vmask; + while (tmask) + { + index2 = (Mask) lowbit (tmask); + tmask &= ~index2; + switch (index2) + { + case CWBackPixmap: + pixID = (Pixmap )*pVlist; + pVlist++; + if (pWin->backgroundState == ParentRelative) + borderRelative = TRUE; + if (pixID == None) + { + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + if (!pWin->parent) + MakeRootTile(pWin); + else { + pWin->backgroundState = XaceBackgroundNoneState(pWin); + pWin->background.pixel = pScreen->whitePixel; + } + } + else if (pixID == ParentRelative) + { + if (pWin->parent && + pWin->drawable.depth != pWin->parent->drawable.depth) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + if (!pWin->parent) + MakeRootTile(pWin); + else + pWin->backgroundState = ParentRelative; + borderRelative = TRUE; + /* Note that the parent's backgroundTile's refcnt is NOT + * incremented. */ + } + else + { + rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, + client, DixReadAccess); + if (rc == Success) + { + if ((pPixmap->drawable.depth != pWin->drawable.depth) || + (pPixmap->drawable.pScreen != pScreen)) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + pWin->backgroundState = BackgroundPixmap; + pWin->background.pixmap = pPixmap; + pPixmap->refcnt++; + } + else + { + error = (rc == BadValue) ? BadPixmap : rc; + client->errorValue = pixID; + goto PatchUp; + } + } + break; + case CWBackPixel: + if (pWin->backgroundState == ParentRelative) + borderRelative = TRUE; + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + pWin->backgroundState = BackgroundPixel; + pWin->background.pixel = (CARD32 ) *pVlist; + /* background pixel overrides background pixmap, + so don't let the ddx layer see both bits */ + vmaskCopy &= ~CWBackPixmap; + pVlist++; + break; + case CWBorderPixmap: + pixID = (Pixmap ) *pVlist; + pVlist++; + if (pixID == CopyFromParent) + { + if (!pWin->parent || + (pWin->drawable.depth != pWin->parent->drawable.depth)) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->parent->borderIsPixel == TRUE) { + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + pWin->border = pWin->parent->border; + pWin->borderIsPixel = TRUE; + index2 = CWBorderPixel; + break; + } + else + { + pixID = pWin->parent->border.pixmap->drawable.id; + } + } + rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, + client, DixReadAccess); + if (rc == Success) + { + if ((pPixmap->drawable.depth != pWin->drawable.depth) || + (pPixmap->drawable.pScreen != pScreen)) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + pWin->borderIsPixel = FALSE; + pWin->border.pixmap = pPixmap; + pPixmap->refcnt++; + } + else + { + error = (rc == BadValue) ? BadPixmap : rc; + client->errorValue = pixID; + goto PatchUp; + } + break; + case CWBorderPixel: + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + pWin->borderIsPixel = TRUE; + pWin->border.pixel = (CARD32) *pVlist; + /* border pixel overrides border pixmap, + so don't let the ddx layer see both bits */ + vmaskCopy &= ~CWBorderPixmap; + pVlist++; + break; + case CWBitGravity: + val = (CARD8 )*pVlist; + pVlist++; + if (val > StaticGravity) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->bitGravity = val; + break; + case CWWinGravity: + val = (CARD8 )*pVlist; + pVlist++; + if (val > StaticGravity) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->winGravity = val; + break; + case CWBackingStore: + val = (CARD8 )*pVlist; + pVlist++; + if ((val != NotUseful) && (val != WhenMapped) && (val != Always)) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->backingStore = val; + pWin->forcedBS = FALSE; + break; + case CWBackingPlanes: + if (pWin->optional || ((CARD32)*pVlist != (CARD32)~0L)) { + if (!pWin->optional && !MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + pWin->optional->backingBitPlanes = (CARD32) *pVlist; + if ((CARD32)*pVlist == (CARD32)~0L) + checkOptional = TRUE; + } + pVlist++; + break; + case CWBackingPixel: + if (pWin->optional || (CARD32) *pVlist) { + if (!pWin->optional && !MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + pWin->optional->backingPixel = (CARD32) *pVlist; + if (!*pVlist) + checkOptional = TRUE; + } + pVlist++; + break; + case CWSaveUnder: + val = (BOOL) *pVlist; + pVlist++; + if ((val != xTrue) && (val != xFalse)) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->saveUnder = val; + break; + case CWEventMask: + rc = EventSelectForWindow(pWin, client, (Mask )*pVlist); + if (rc) + { + error = rc; + goto PatchUp; + } + pVlist++; + break; + case CWDontPropagate: + rc = EventSuppressForWindow(pWin, client, (Mask )*pVlist, + &checkOptional); + if (rc) + { + error = rc; + goto PatchUp; + } + pVlist++; + break; + case CWOverrideRedirect: + val = (BOOL ) *pVlist; + pVlist++; + if ((val != xTrue) && (val != xFalse)) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + if (val == xTrue) { + rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, + RT_WINDOW, pWin, RT_NONE, NULL, DixGrabAccess); + if (rc != Success) { + error = rc; + client->errorValue = pWin->drawable.id; + goto PatchUp; + } + } + pWin->overrideRedirect = val; + break; + case CWColormap: + cmap = (Colormap) *pVlist; + pVlist++; + if (cmap == CopyFromParent) + { + if (pWin->parent && + (!pWin->optional || + pWin->optional->visual == wVisual (pWin->parent))) + { + cmap = wColormap (pWin->parent); + } + else + cmap = None; + } + if (cmap == None) + { + error = BadMatch; + goto PatchUp; + } + rc = dixLookupResourceByType((pointer *)&pCmap, cmap, RT_COLORMAP, + client, DixUseAccess); + if (rc != Success) + { + error = (rc == BadValue) ? BadColor : rc; + client->errorValue = cmap; + goto PatchUp; + } + if (pCmap->pVisual->vid != wVisual (pWin) || + pCmap->pScreen != pScreen) + { + error = BadMatch; + goto PatchUp; + } + if (cmap != wColormap (pWin)) + { + if (!pWin->optional) + { + if (!MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + } + else if (pWin->parent && cmap == wColormap (pWin->parent)) + checkOptional = TRUE; + + /* + * propagate the original colormap to any children + * inheriting it + */ + + for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (!pChild->optional && !MakeWindowOptional (pChild)) + { + error = BadAlloc; + goto PatchUp; + } + } + + pWin->optional->colormap = cmap; + + /* + * check on any children now matching the new colormap + */ + + for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (pChild->optional->colormap == cmap) + CheckWindowOptionalNeed (pChild); + } + + xE.u.u.type = ColormapNotify; + xE.u.colormap.window = pWin->drawable.id; + xE.u.colormap.colormap = cmap; + xE.u.colormap.new = xTrue; + xE.u.colormap.state = IsMapInstalled(cmap, pWin); + DeliverEvents(pWin, &xE, 1, NullWindow); + } + break; + case CWCursor: + cursorID = (Cursor ) *pVlist; + pVlist++; + /* + * install the new + */ + if ( cursorID == None) + { + if (pWin == WindowTable[pWin->drawable.pScreen->myNum]) + pCursor = rootCursor; + else + pCursor = (CursorPtr) None; + } + else + { + rc = dixLookupResourceByType((pointer *)&pCursor, cursorID, + RT_CURSOR, client, DixUseAccess); + if (rc != Success) + { + error = (rc == BadValue) ? BadCursor : rc; + client->errorValue = cursorID; + goto PatchUp; + } + } + + if (pCursor != wCursor (pWin)) + { + /* + * patch up child windows so they don't lose cursors. + */ + + for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (!pChild->optional && !pChild->cursorIsNone && + !MakeWindowOptional (pChild)) + { + error = BadAlloc; + goto PatchUp; + } + } + + pOldCursor = 0; + if (pCursor == (CursorPtr) None) + { + pWin->cursorIsNone = TRUE; + if (pWin->optional) + { + pOldCursor = pWin->optional->cursor; + pWin->optional->cursor = (CursorPtr) None; + checkOptional = TRUE; + } + } else { + if (!pWin->optional) + { + if (!MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + } + else if (pWin->parent && pCursor == wCursor (pWin->parent)) + checkOptional = TRUE; + pOldCursor = pWin->optional->cursor; + pWin->optional->cursor = pCursor; + pCursor->refcnt++; + pWin->cursorIsNone = FALSE; + /* + * check on any children now matching the new cursor + */ + + for (pChild=pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (pChild->optional && + (pChild->optional->cursor == pCursor)) + CheckWindowOptionalNeed (pChild); + } + } + + if (pWin->realized) + WindowHasNewCursor( pWin); + + /* Can't free cursor until here - old cursor + * is needed in WindowHasNewCursor + */ + if (pOldCursor) + FreeCursor (pOldCursor, (Cursor)0); + } + break; + default: + error = BadValue; + client->errorValue = vmask; + goto PatchUp; + } + vmaskCopy |= index2; + } +PatchUp: + if (checkOptional) + CheckWindowOptionalNeed (pWin); + + /* We SHOULD check for an error value here XXX */ + (*pScreen->ChangeWindowAttributes)(pWin, vmaskCopy); + + /* + If the border contents have changed, redraw the border. + Note that this has to be done AFTER pScreen->ChangeWindowAttributes + for the tile to be rotated, and the correct function selected. + */ + if (((vmaskCopy & (CWBorderPixel | CWBorderPixmap)) || borderRelative) + && pWin->viewable && HasBorder (pWin)) + { + RegionRec exposed; + + REGION_NULL(pScreen, &exposed); + REGION_SUBTRACT(pScreen, &exposed, &pWin->borderClip, &pWin->winSize); + miPaintWindow(pWin, &exposed, PW_BORDER); + REGION_UNINIT(pScreen, &exposed); + } + return error; +} + + +/***** + * GetWindowAttributes + * Notice that this is different than ChangeWindowAttributes + *****/ + +void +GetWindowAttributes(WindowPtr pWin, ClientPtr client, xGetWindowAttributesReply *wa) +{ + wa->type = X_Reply; + wa->bitGravity = pWin->bitGravity; + wa->winGravity = pWin->winGravity; + if (pWin->forcedBS && pWin->backingStore != Always) + wa->backingStore = NotUseful; + else + wa->backingStore = pWin->backingStore; + wa->length = bytes_to_int32(sizeof(xGetWindowAttributesReply) - + sizeof(xGenericReply)); + wa->sequenceNumber = client->sequence; + wa->backingBitPlanes = wBackingBitPlanes (pWin); + wa->backingPixel = wBackingPixel (pWin); + wa->saveUnder = (BOOL)pWin->saveUnder; + wa->override = pWin->overrideRedirect; + if (!pWin->mapped) + wa->mapState = IsUnmapped; + else if (pWin->realized) + wa->mapState = IsViewable; + else + wa->mapState = IsUnviewable; + + wa->colormap = wColormap (pWin); + wa->mapInstalled = (wa->colormap == None) ? xFalse + : IsMapInstalled(wa->colormap, pWin); + + wa->yourEventMask = EventMaskForClient(pWin, client); + wa->allEventMasks = pWin->eventMask | wOtherEventMasks (pWin); + wa->doNotPropagateMask = wDontPropagateMask (pWin); + wa->class = pWin->drawable.class; + wa->visualID = wVisual (pWin); +} + + +WindowPtr +MoveWindowInStack(WindowPtr pWin, WindowPtr pNextSib) +{ + WindowPtr pParent = pWin->parent; + WindowPtr pFirstChange = pWin; /* highest window where list changes */ + + if (pWin->nextSib != pNextSib) + { + WindowPtr pOldNextSib = pWin->nextSib; + + if (!pNextSib) /* move to bottom */ + { + if (pParent->firstChild == pWin) + pParent->firstChild = pWin->nextSib; + /* if (pWin->nextSib) */ /* is always True: pNextSib == NULL + * and pWin->nextSib != pNextSib + * therefore pWin->nextSib != NULL */ + pFirstChange = pWin->nextSib; + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + pParent->lastChild->nextSib = pWin; + pWin->prevSib = pParent->lastChild; + pWin->nextSib = NullWindow; + pParent->lastChild = pWin; + } + else if (pParent->firstChild == pNextSib) /* move to top */ + { + pFirstChange = pWin; + if (pParent->lastChild == pWin) + pParent->lastChild = pWin->prevSib; + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + pWin->nextSib = pParent->firstChild; + pWin->prevSib = (WindowPtr ) NULL; + pNextSib->prevSib = pWin; + pParent->firstChild = pWin; + } + else /* move in middle of list */ + { + WindowPtr pOldNext = pWin->nextSib; + + pFirstChange = NullWindow; + if (pParent->firstChild == pWin) + pFirstChange = pParent->firstChild = pWin->nextSib; + if (pParent->lastChild == pWin) { + pFirstChange = pWin; + pParent->lastChild = pWin->prevSib; + } + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + pWin->nextSib = pNextSib; + pWin->prevSib = pNextSib->prevSib; + if (pNextSib->prevSib) + pNextSib->prevSib->nextSib = pWin; + pNextSib->prevSib = pWin; + if (!pFirstChange) { /* do we know it yet? */ + pFirstChange = pParent->firstChild; /* no, search from top */ + while ((pFirstChange != pWin) && (pFirstChange != pOldNext)) + pFirstChange = pFirstChange->nextSib; + } + } + if(pWin->drawable.pScreen->RestackWindow) + (*pWin->drawable.pScreen->RestackWindow)(pWin, pOldNextSib); + } + +#ifdef ROOTLESS + /* + * In rootless mode we can't optimize away window restacks. + * There may be non-X windows around, so even if the window + * is in the correct position from X's point of view, + * the underlying window system may want to reorder it. + */ + else if (pWin->drawable.pScreen->RestackWindow) + (*pWin->drawable.pScreen->RestackWindow)(pWin, pWin->nextSib); +#endif + + return( pFirstChange ); +} + +void +SetWinSize (WindowPtr pWin) +{ +#ifdef COMPOSITE + if (pWin->redirectDraw != RedirectDrawNone) + { + BoxRec box; + + /* + * Redirected clients get clip list equal to their + * own geometry, not clipped to their parent + */ + box.x1 = pWin->drawable.x; + box.y1 = pWin->drawable.y; + box.x2 = pWin->drawable.x + pWin->drawable.width; + box.y2 = pWin->drawable.y + pWin->drawable.height; + REGION_RESET (pScreen, &pWin->winSize, &box); + } + else +#endif + ClippedRegionFromBox(pWin->parent, &pWin->winSize, + pWin->drawable.x, pWin->drawable.y, + (int)pWin->drawable.width, + (int)pWin->drawable.height); + if (wBoundingShape (pWin) || wClipShape (pWin)) { + ScreenPtr pScreen; + pScreen = pWin->drawable.pScreen; + + REGION_TRANSLATE(pScreen, &pWin->winSize, - pWin->drawable.x, + - pWin->drawable.y); + if (wBoundingShape (pWin)) + REGION_INTERSECT(pScreen, &pWin->winSize, &pWin->winSize, + wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_INTERSECT(pScreen, &pWin->winSize, &pWin->winSize, + wClipShape (pWin)); + REGION_TRANSLATE(pScreen, &pWin->winSize, pWin->drawable.x, + pWin->drawable.y); + } +} + +void +SetBorderSize (WindowPtr pWin) +{ + int bw; + + if (HasBorder (pWin)) { + bw = wBorderWidth (pWin); +#ifdef COMPOSITE + if (pWin->redirectDraw != RedirectDrawNone) + { + BoxRec box; + + /* + * Redirected clients get clip list equal to their + * own geometry, not clipped to their parent + */ + box.x1 = pWin->drawable.x - bw; + box.y1 = pWin->drawable.y - bw; + box.x2 = pWin->drawable.x + pWin->drawable.width + bw; + box.y2 = pWin->drawable.y + pWin->drawable.height + bw; + REGION_RESET (pScreen, &pWin->borderSize, &box); + } + else +#endif + ClippedRegionFromBox(pWin->parent, &pWin->borderSize, + pWin->drawable.x - bw, pWin->drawable.y - bw, + (int)(pWin->drawable.width + (bw<<1)), + (int)(pWin->drawable.height + (bw<<1))); + if (wBoundingShape (pWin)) { + ScreenPtr pScreen; + pScreen = pWin->drawable.pScreen; + + REGION_TRANSLATE(pScreen, &pWin->borderSize, - pWin->drawable.x, + - pWin->drawable.y); + REGION_INTERSECT(pScreen, &pWin->borderSize, &pWin->borderSize, + wBoundingShape (pWin)); + REGION_TRANSLATE(pScreen, &pWin->borderSize, pWin->drawable.x, + pWin->drawable.y); + REGION_UNION(pScreen, &pWin->borderSize, &pWin->borderSize, + &pWin->winSize); + } + } else { + REGION_COPY(pWin->drawable.pScreen, &pWin->borderSize, + &pWin->winSize); + } +} + +/** + * + * \param x,y new window position + * \param oldx,oldy old window position + * \param destx,desty position relative to gravity + */ + +void +GravityTranslate (int x, int y, int oldx, int oldy, + int dw, int dh, unsigned gravity, + int *destx, int *desty) +{ + switch (gravity) { + case NorthGravity: + *destx = x + dw / 2; + *desty = y; + break; + case NorthEastGravity: + *destx = x + dw; + *desty = y; + break; + case WestGravity: + *destx = x; + *desty = y + dh / 2; + break; + case CenterGravity: + *destx = x + dw / 2; + *desty = y + dh / 2; + break; + case EastGravity: + *destx = x + dw; + *desty = y + dh / 2; + break; + case SouthWestGravity: + *destx = x; + *desty = y + dh; + break; + case SouthGravity: + *destx = x + dw / 2; + *desty = y + dh; + break; + case SouthEastGravity: + *destx = x + dw; + *desty = y + dh; + break; + case StaticGravity: + *destx = oldx; + *desty = oldy; + break; + default: + *destx = x; + *desty = y; + break; + } +} + +/* XXX need to retile border on each window with ParentRelative origin */ +void +ResizeChildrenWinSize(WindowPtr pWin, int dx, int dy, int dw, int dh) +{ + ScreenPtr pScreen; + WindowPtr pSib, pChild; + Bool resized = (dw || dh); + + pScreen = pWin->drawable.pScreen; + + for (pSib = pWin->firstChild; pSib; pSib = pSib->nextSib) + { + if (resized && (pSib->winGravity > NorthWestGravity)) + { + int cwsx, cwsy; + + cwsx = pSib->origin.x; + cwsy = pSib->origin.y; + GravityTranslate (cwsx, cwsy, cwsx - dx, cwsy - dy, dw, dh, + pSib->winGravity, &cwsx, &cwsy); + if (cwsx != pSib->origin.x || cwsy != pSib->origin.y) + { + xEvent event; + + event.u.u.type = GravityNotify; + event.u.gravity.window = pSib->drawable.id; + event.u.gravity.x = cwsx - wBorderWidth (pSib); + event.u.gravity.y = cwsy - wBorderWidth (pSib); + DeliverEvents (pSib, &event, 1, NullWindow); + pSib->origin.x = cwsx; + pSib->origin.y = cwsy; + } + } + pSib->drawable.x = pWin->drawable.x + pSib->origin.x; + pSib->drawable.y = pWin->drawable.y + pSib->origin.y; + SetWinSize (pSib); + SetBorderSize (pSib); + (*pScreen->PositionWindow)(pSib, pSib->drawable.x, pSib->drawable.y); + + if ( (pChild = pSib->firstChild) ) + { + while (1) + { + pChild->drawable.x = pChild->parent->drawable.x + + pChild->origin.x; + pChild->drawable.y = pChild->parent->drawable.y + + pChild->origin.y; + SetWinSize (pChild); + SetBorderSize (pChild); + (*pScreen->PositionWindow)(pChild, + pChild->drawable.x, pChild->drawable.y); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pSib)) + pChild = pChild->parent; + if (pChild == pSib) + break; + pChild = pChild->nextSib; + } + } + } +} + +#define GET_INT16(m, f) \ + if (m & mask) \ + { \ + f = (INT16) *pVlist;\ + pVlist++; \ + } +#define GET_CARD16(m, f) \ + if (m & mask) \ + { \ + f = (CARD16) *pVlist;\ + pVlist++;\ + } + +#define GET_CARD8(m, f) \ + if (m & mask) \ + { \ + f = (CARD8) *pVlist;\ + pVlist++;\ + } + +#define ChangeMask ((Mask)(CWX | CWY | CWWidth | CWHeight)) + +#define IllegalInputOnlyConfigureMask (CWBorderWidth) + +/* + * IsSiblingAboveMe + * returns Above if pSib above pMe in stack or Below otherwise + */ + +static int +IsSiblingAboveMe( + WindowPtr pMe, + WindowPtr pSib) +{ + WindowPtr pWin; + + pWin = pMe->parent->firstChild; + while (pWin) + { + if (pWin == pSib) + return(Above); + else if (pWin == pMe) + return(Below); + pWin = pWin->nextSib; + } + return(Below); +} + +static BoxPtr +WindowExtents( + WindowPtr pWin, + BoxPtr pBox) +{ + pBox->x1 = pWin->drawable.x - wBorderWidth (pWin); + pBox->y1 = pWin->drawable.y - wBorderWidth (pWin); + pBox->x2 = pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth (pWin); + pBox->y2 = pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin); + return(pBox); +} + +#define IS_SHAPED(pWin) (wBoundingShape (pWin) != (RegionPtr) NULL) + +static RegionPtr +MakeBoundingRegion ( + WindowPtr pWin, + BoxPtr pBox) +{ + RegionPtr pRgn; + ScreenPtr pScreen; + pScreen = pWin->drawable.pScreen; + + pRgn = REGION_CREATE(pScreen, pBox, 1); + if (wBoundingShape (pWin)) { + REGION_TRANSLATE(pScreen, pRgn, -pWin->origin.x, + -pWin->origin.y); + REGION_INTERSECT(pScreen, pRgn, pRgn, wBoundingShape (pWin)); + REGION_TRANSLATE(pScreen, pRgn, pWin->origin.x, + pWin->origin.y); + } + return pRgn; +} + +static Bool +ShapeOverlap ( + WindowPtr pWin, + BoxPtr pWinBox, + WindowPtr pSib, + BoxPtr pSibBox) +{ + RegionPtr pWinRgn, pSibRgn; + ScreenPtr pScreen; + Bool ret; + + if (!IS_SHAPED(pWin) && !IS_SHAPED(pSib)) + return TRUE; + pScreen = pWin->drawable.pScreen; + pWinRgn = MakeBoundingRegion (pWin, pWinBox); + pSibRgn = MakeBoundingRegion (pSib, pSibBox); + REGION_INTERSECT(pScreen, pWinRgn, pWinRgn, pSibRgn); + ret = REGION_NOTEMPTY(pScreen, pWinRgn); + REGION_DESTROY(pScreen, pWinRgn); + REGION_DESTROY(pScreen, pSibRgn); + return ret; +} + +static Bool +AnyWindowOverlapsMe( + WindowPtr pWin, + WindowPtr pHead, + BoxPtr box) +{ + WindowPtr pSib; + BoxRec sboxrec; + BoxPtr sbox; + + for (pSib = pWin->prevSib; pSib != pHead; pSib = pSib->prevSib) + { + if (pSib->mapped) + { + sbox = WindowExtents(pSib, &sboxrec); + if (BOXES_OVERLAP(sbox, box) + && ShapeOverlap (pWin, box, pSib, sbox) + ) + return(TRUE); + } + } + return(FALSE); +} + +static Bool +IOverlapAnyWindow( + WindowPtr pWin, + BoxPtr box) +{ + WindowPtr pSib; + BoxRec sboxrec; + BoxPtr sbox; + + for (pSib = pWin->nextSib; pSib; pSib = pSib->nextSib) + { + if (pSib->mapped) + { + sbox = WindowExtents(pSib, &sboxrec); + if (BOXES_OVERLAP(sbox, box) + && ShapeOverlap (pWin, box, pSib, sbox) + ) + return(TRUE); + } + } + return(FALSE); +} + +/* + * WhereDoIGoInTheStack() + * Given pWin and pSib and the relationshipe smode, return + * the window that pWin should go ABOVE. + * If a pSib is specified: + * Above: pWin is placed just above pSib + * Below: pWin is placed just below pSib + * TopIf: if pSib occludes pWin, then pWin is placed + * at the top of the stack + * BottomIf: if pWin occludes pSib, then pWin is + * placed at the bottom of the stack + * Opposite: if pSib occludes pWin, then pWin is placed at the + * top of the stack, else if pWin occludes pSib, then + * pWin is placed at the bottom of the stack + * + * If pSib is NULL: + * Above: pWin is placed at the top of the stack + * Below: pWin is placed at the bottom of the stack + * TopIf: if any sibling occludes pWin, then pWin is placed at + * the top of the stack + * BottomIf: if pWin occludes any sibline, then pWin is placed at + * the bottom of the stack + * Opposite: if any sibling occludes pWin, then pWin is placed at + * the top of the stack, else if pWin occludes any + * sibling, then pWin is placed at the bottom of the stack + * + */ + +static WindowPtr +WhereDoIGoInTheStack( + WindowPtr pWin, + WindowPtr pSib, + short x, + short y, + unsigned short w, + unsigned short h, + int smode) +{ + BoxRec box; + ScreenPtr pScreen; + WindowPtr pHead, pFirst; + + if ((pWin == pWin->parent->firstChild) && + (pWin == pWin->parent->lastChild)) + return((WindowPtr ) NULL); + pHead = RealChildHead(pWin->parent); + pFirst = pHead ? pHead->nextSib : pWin->parent->firstChild; + pScreen = pWin->drawable.pScreen; + box.x1 = x; + box.y1 = y; + box.x2 = x + (int)w; + box.y2 = y + (int)h; + switch (smode) + { + case Above: + if (pSib) + return(pSib); + else if (pWin == pFirst) + return(pWin->nextSib); + else + return(pFirst); + case Below: + if (pSib) + if (pSib->nextSib != pWin) + return(pSib->nextSib); + else + return(pWin->nextSib); + else + return NullWindow; + case TopIf: + if ((!pWin->mapped || (pSib && !pSib->mapped))) + return(pWin->nextSib); + else if (pSib) + { + if ((IsSiblingAboveMe(pWin, pSib) == Above) && + (RECT_IN_REGION(pScreen, &pSib->borderSize, &box) != rgnOUT)) + return(pFirst); + else + return(pWin->nextSib); + } + else if (AnyWindowOverlapsMe(pWin, pHead, &box)) + return(pFirst); + else + return(pWin->nextSib); + case BottomIf: + if ((!pWin->mapped || (pSib && !pSib->mapped))) + return(pWin->nextSib); + else if (pSib) + { + if ((IsSiblingAboveMe(pWin, pSib) == Below) && + (RECT_IN_REGION(pScreen, &pSib->borderSize, &box) != rgnOUT)) + return NullWindow; + else + return(pWin->nextSib); + } + else if (IOverlapAnyWindow(pWin, &box)) + return NullWindow; + else + return(pWin->nextSib); + case Opposite: + if ((!pWin->mapped || (pSib && !pSib->mapped))) + return(pWin->nextSib); + else if (pSib) + { + if (RECT_IN_REGION(pScreen, &pSib->borderSize, &box) != rgnOUT) + { + if (IsSiblingAboveMe(pWin, pSib) == Above) + return(pFirst); + else + return NullWindow; + } + else + return(pWin->nextSib); + } + else if (AnyWindowOverlapsMe(pWin, pHead, &box)) + { + /* If I'm occluded, I can't possibly be the first child + * if (pWin == pWin->parent->firstChild) + * return pWin->nextSib; + */ + return(pFirst); + } + else if (IOverlapAnyWindow(pWin, &box)) + return NullWindow; + else + return pWin->nextSib; + default: + { + /* should never happen; make something up. */ + return pWin->nextSib; + } + } +} + +static void +ReflectStackChange( + WindowPtr pWin, + WindowPtr pSib, + VTKind kind) +{ +/* Note that pSib might be NULL */ + + Bool WasViewable = (Bool)pWin->viewable; + Bool anyMarked; + WindowPtr pFirstChange; + WindowPtr pLayerWin; + ScreenPtr pScreen = pWin->drawable.pScreen; + + /* if this is a root window, can't be restacked */ + if (!pWin->parent) + return; + + pFirstChange = MoveWindowInStack(pWin, pSib); + + if (WasViewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, + &pLayerWin); + if (pLayerWin != pWin) pFirstChange = pLayerWin; + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, kind); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pWin->drawable.pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, kind); + } + if (pWin->realized) + WindowsRestructured (); +} + +/***** + * ConfigureWindow + *****/ + +int +ConfigureWindow(WindowPtr pWin, Mask mask, XID *vlist, ClientPtr client) +{ +#define RESTACK_WIN 0 +#define MOVE_WIN 1 +#define RESIZE_WIN 2 +#define REBORDER_WIN 3 + WindowPtr pSib = NullWindow; + WindowPtr pParent = pWin->parent; + Window sibwid = 0; + Mask index2, tmask; + XID *pVlist; + short x, y, beforeX, beforeY; + unsigned short w = pWin->drawable.width, + h = pWin->drawable.height, + bw = pWin->borderWidth; + int rc, action, smode = Above; + xEvent event; + + if ((pWin->drawable.class == InputOnly) && (mask & IllegalInputOnlyConfigureMask)) + return(BadMatch); + + if ((mask & CWSibling) && !(mask & CWStackMode)) + return(BadMatch); + + pVlist = vlist; + + if (pParent) + { + x = pWin->drawable.x - pParent->drawable.x - (int)bw; + y = pWin->drawable.y - pParent->drawable.y - (int)bw; + } + else + { + x = pWin->drawable.x; + y = pWin->drawable.y; + } + beforeX = x; + beforeY = y; + action = RESTACK_WIN; + if ((mask & (CWX | CWY)) && (!(mask & (CWHeight | CWWidth)))) + { + GET_INT16(CWX, x); + GET_INT16(CWY, y); + action = MOVE_WIN; + } + /* or should be resized */ + else if (mask & (CWX | CWY | CWWidth | CWHeight)) + { + GET_INT16(CWX, x); + GET_INT16(CWY, y); + GET_CARD16(CWWidth, w); + GET_CARD16 (CWHeight, h); + if (!w || !h) + { + client->errorValue = 0; + return BadValue; + } + action = RESIZE_WIN; + } + tmask = mask & ~ChangeMask; + while (tmask) + { + index2 = (Mask)lowbit (tmask); + tmask &= ~index2; + switch (index2) + { + case CWBorderWidth: + GET_CARD16(CWBorderWidth, bw); + break; + case CWSibling: + sibwid = (Window ) *pVlist; + pVlist++; + rc = dixLookupWindow(&pSib, sibwid, client, DixGetAttrAccess); + if (rc != Success) + { + client->errorValue = sibwid; + return rc; + } + if (pSib->parent != pParent) + return(BadMatch); + if (pSib == pWin) + return(BadMatch); + break; + case CWStackMode: + GET_CARD8(CWStackMode, smode); + if ((smode != TopIf) && (smode != BottomIf) && + (smode != Opposite) && (smode != Above) && (smode != Below)) + { + client->errorValue = smode; + return(BadValue); + } + break; + default: + client->errorValue = mask; + return(BadValue); + } + } + /* root really can't be reconfigured, so just return */ + if (!pParent) + return Success; + + /* Figure out if the window should be moved. Doesnt + make the changes to the window if event sent */ + + if (mask & CWStackMode) + pSib = WhereDoIGoInTheStack(pWin, pSib, pParent->drawable.x + x, + pParent->drawable.y + y, + w + (bw << 1), h + (bw << 1), smode); + else + pSib = pWin->nextSib; + + + if ((!pWin->overrideRedirect) && + (RedirectSend(pParent) + )) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = ConfigureRequest; + event.u.configureRequest.window = pWin->drawable.id; + if (mask & CWSibling) + event.u.configureRequest.sibling = sibwid; + else + event.u.configureRequest.sibling = None; + if (mask & CWStackMode) + event.u.u.detail = smode; + else + event.u.u.detail = Above; + event.u.configureRequest.x = x; + event.u.configureRequest.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { + event.u.configureRequest.x += panoramiXdataPtr[0].x; + event.u.configureRequest.y += panoramiXdataPtr[0].y; + } +#endif + event.u.configureRequest.width = w; + event.u.configureRequest.height = h; + event.u.configureRequest.borderWidth = bw; + event.u.configureRequest.valueMask = mask; + event.u.configureRequest.parent = pParent->drawable.id; + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return(Success); + } + if (action == RESIZE_WIN) + { + Bool size_change = (w != pWin->drawable.width) + || (h != pWin->drawable.height); + if (size_change && ((pWin->eventMask|wOtherEventMasks(pWin)) & ResizeRedirectMask)) + { + xEvent eventT; + memset(&eventT, 0, sizeof(xEvent)); + eventT.u.u.type = ResizeRequest; + eventT.u.resizeRequest.window = pWin->drawable.id; + eventT.u.resizeRequest.width = w; + eventT.u.resizeRequest.height = h; + if (MaybeDeliverEventsToClient(pWin, &eventT, 1, + ResizeRedirectMask, client) == 1) + { + /* if event is delivered, leave the actual size alone. */ + w = pWin->drawable.width; + h = pWin->drawable.height; + size_change = FALSE; + } + } + if (!size_change) + { + if (mask & (CWX | CWY)) + action = MOVE_WIN; + else if (mask & (CWStackMode | CWBorderWidth)) + action = RESTACK_WIN; + else /* really nothing to do */ + return(Success) ; + } + } + + if (action == RESIZE_WIN) + /* we've already checked whether there's really a size change */ + goto ActuallyDoSomething; + if ((mask & CWX) && (x != beforeX)) + goto ActuallyDoSomething; + if ((mask & CWY) && (y != beforeY)) + goto ActuallyDoSomething; + if ((mask & CWBorderWidth) && (bw != wBorderWidth (pWin))) + goto ActuallyDoSomething; + if (mask & CWStackMode) + { +#ifndef ROOTLESS + /* See above for why we always reorder in rootless mode. */ + if (pWin->nextSib != pSib) +#endif + goto ActuallyDoSomething; + } + return(Success); + +ActuallyDoSomething: + if (pWin->drawable.pScreen->ConfigNotify) + (*pWin->drawable.pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib); + + if (SubStrSend(pWin, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = ConfigureNotify; + event.u.configureNotify.window = pWin->drawable.id; + if (pSib) + event.u.configureNotify.aboveSibling = pSib->drawable.id; + else + event.u.configureNotify.aboveSibling = None; + event.u.configureNotify.x = x; + event.u.configureNotify.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { + event.u.configureNotify.x += panoramiXdataPtr[0].x; + event.u.configureNotify.y += panoramiXdataPtr[0].y; + } +#endif + event.u.configureNotify.width = w; + event.u.configureNotify.height = h; + event.u.configureNotify.borderWidth = bw; + event.u.configureNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + if (mask & CWBorderWidth) + { + if (action == RESTACK_WIN) + { + action = MOVE_WIN; + pWin->borderWidth = bw; + } + else if ((action == MOVE_WIN) && + (beforeX + wBorderWidth (pWin) == x + (int)bw) && + (beforeY + wBorderWidth (pWin) == y + (int)bw)) + { + action = REBORDER_WIN; + (*pWin->drawable.pScreen->ChangeBorderWidth)(pWin, bw); + } + else + pWin->borderWidth = bw; + } + if (action == MOVE_WIN) + (*pWin->drawable.pScreen->MoveWindow)(pWin, x, y, pSib, + (mask & CWBorderWidth) ? VTOther : VTMove); + else if (action == RESIZE_WIN) + (*pWin->drawable.pScreen->ResizeWindow)(pWin, x, y, w, h, pSib); + else if (mask & CWStackMode) + ReflectStackChange(pWin, pSib, VTOther); + + if (action != RESTACK_WIN) + CheckCursorConfinement(pWin); + return(Success); +#undef RESTACK_WIN +#undef MOVE_WIN +#undef RESIZE_WIN +#undef REBORDER_WIN +} + + +/****** + * + * CirculateWindow + * For RaiseLowest, raises the lowest mapped child (if any) that is + * obscured by another child to the top of the stack. For LowerHighest, + * lowers the highest mapped child (if any) that is obscuring another + * child to the bottom of the stack. Exposure processing is performed + * + ******/ + +int +CirculateWindow(WindowPtr pParent, int direction, ClientPtr client) +{ + WindowPtr pWin, pHead, pFirst; + xEvent event; + BoxRec box; + + pHead = RealChildHead(pParent); + pFirst = pHead ? pHead->nextSib : pParent->firstChild; + if (direction == RaiseLowest) + { + for (pWin = pParent->lastChild; + (pWin != pHead) && + !(pWin->mapped && + AnyWindowOverlapsMe(pWin, pHead, WindowExtents(pWin, &box))); + pWin = pWin->prevSib) ; + if (pWin == pHead) + return Success; + } + else + { + for (pWin = pFirst; + pWin && + !(pWin->mapped && + IOverlapAnyWindow(pWin, WindowExtents(pWin, &box))); + pWin = pWin->nextSib) ; + if (!pWin) + return Success; + } + + event.u.circulate.window = pWin->drawable.id; + event.u.circulate.parent = pParent->drawable.id; + event.u.circulate.event = pParent->drawable.id; + if (direction == RaiseLowest) + event.u.circulate.place = PlaceOnTop; + else + event.u.circulate.place = PlaceOnBottom; + + if (RedirectSend(pParent)) + { + event.u.u.type = CirculateRequest; + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return(Success); + } + + event.u.u.type = CirculateNotify; + DeliverEvents(pWin, &event, 1, NullWindow); + ReflectStackChange(pWin, + (direction == RaiseLowest) ? pFirst : NullWindow, + VTStack); + + return(Success); +} + +static int +CompareWIDs( + WindowPtr pWin, + pointer value) /* must conform to VisitWindowProcPtr */ +{ + Window *wid = (Window *)value; + + if (pWin->drawable.id == *wid) + return(WT_STOPWALKING); + else + return(WT_WALKCHILDREN); +} + +/***** + * ReparentWindow + *****/ + +int +ReparentWindow(WindowPtr pWin, WindowPtr pParent, + int x, int y, ClientPtr client) +{ + WindowPtr pPrev, pPriorParent; + Bool WasMapped = (Bool)(pWin->mapped); + xEvent event; + int bw = wBorderWidth (pWin); + ScreenPtr pScreen; + + pScreen = pWin->drawable.pScreen; + if (TraverseTree(pWin, CompareWIDs, (pointer)&pParent->drawable.id) == WT_STOPWALKING) + return(BadMatch); + if (!MakeWindowOptional(pWin)) + return(BadAlloc); + + if (WasMapped) + UnmapWindow(pWin, FALSE); + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = ReparentNotify; + event.u.reparent.window = pWin->drawable.id; + event.u.reparent.parent = pParent->drawable.id; + event.u.reparent.x = x; + event.u.reparent.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && !pParent->parent) { + event.u.reparent.x += panoramiXdataPtr[0].x; + event.u.reparent.y += panoramiXdataPtr[0].y; + } +#endif + event.u.reparent.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, pParent); + + /* take out of sibling chain */ + + pPriorParent = pPrev = pWin->parent; + if (pPrev->firstChild == pWin) + pPrev->firstChild = pWin->nextSib; + if (pPrev->lastChild == pWin) + pPrev->lastChild = pWin->prevSib; + + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + + /* insert at begining of pParent */ + pWin->parent = pParent; + pPrev = RealChildHead(pParent); + if (pPrev) + { + pWin->nextSib = pPrev->nextSib; + if (pPrev->nextSib) + pPrev->nextSib->prevSib = pWin; + else + pParent->lastChild = pWin; + pPrev->nextSib = pWin; + pWin->prevSib = pPrev; + } + else + { + pWin->nextSib = pParent->firstChild; + pWin->prevSib = NullWindow; + if (pParent->firstChild) + pParent->firstChild->prevSib = pWin; + else + pParent->lastChild = pWin; + pParent->firstChild = pWin; + } + + pWin->origin.x = x + bw; + pWin->origin.y = y + bw; + pWin->drawable.x = x + bw + pParent->drawable.x; + pWin->drawable.y = y + bw + pParent->drawable.y; + + /* clip to parent */ + SetWinSize (pWin); + SetBorderSize (pWin); + + if (pScreen->ReparentWindow) + (*pScreen->ReparentWindow)(pWin, pPriorParent); + (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); + ResizeChildrenWinSize(pWin, 0, 0, 0, 0); + + CheckWindowOptionalNeed(pWin); + + if (WasMapped) + MapWindow(pWin, client); + RecalculateDeliverableEvents(pWin); + return(Success); +} + +static void +RealizeTree(WindowPtr pWin) +{ + WindowPtr pChild; + RealizeWindowProcPtr Realize; + + Realize = pWin->drawable.pScreen->RealizeWindow; + pChild = pWin; + while (1) + { + if (pChild->mapped) + { + pChild->realized = TRUE; + pChild->viewable = (pChild->drawable.class == InputOutput); + (* Realize)(pChild); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + return; + pChild = pChild->nextSib; + } +} + +static WindowPtr windowDisableMapUnmapEvents; + +void +DisableMapUnmapEvents(WindowPtr pWin) +{ + assert (windowDisableMapUnmapEvents == NULL); + + windowDisableMapUnmapEvents = pWin; +} + +void +EnableMapUnmapEvents(WindowPtr pWin) +{ + assert (windowDisableMapUnmapEvents != NULL); + + windowDisableMapUnmapEvents = NULL; +} + +static Bool +MapUnmapEventsEnabled(WindowPtr pWin) +{ + return pWin != windowDisableMapUnmapEvents; +} + +/***** + * MapWindow + * If some other client has selected SubStructureReDirect on the parent + * and override-redirect is xFalse, then a MapRequest event is generated, + * but the window remains unmapped. Otherwise, the window is mapped and a + * MapNotify event is generated. + *****/ + +int +MapWindow(WindowPtr pWin, ClientPtr client) +{ + ScreenPtr pScreen; + + WindowPtr pParent; + WindowPtr pLayerWin; + + if (pWin->mapped) + return(Success); + + /* general check for permission to map window */ + if (XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, RT_WINDOW, + pWin, RT_NONE, NULL, DixShowAccess) != Success) + return Success; + + pScreen = pWin->drawable.pScreen; + if ( (pParent = pWin->parent) ) + { + xEvent event; + Bool anyMarked; + + if ((!pWin->overrideRedirect) && + (RedirectSend(pParent) + )) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapRequest; + event.u.mapRequest.window = pWin->drawable.id; + event.u.mapRequest.parent = pParent->drawable.id; + + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return(Success); + } + + pWin->mapped = TRUE; + if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapNotify; + event.u.mapNotify.window = pWin->drawable.id; + event.u.mapNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + if (!pParent->realized) + return(Success); + RealizeTree(pWin); + if (pWin->viewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTMap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, VTMap); + } + WindowsRestructured (); + } + else + { + RegionRec temp; + + pWin->mapped = TRUE; + pWin->realized = TRUE; /* for roots */ + pWin->viewable = pWin->drawable.class == InputOutput; + /* We SHOULD check for an error value here XXX */ + (*pScreen->RealizeWindow)(pWin); + if (pScreen->ClipNotify) + (*pScreen->ClipNotify) (pWin, 0, 0); + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(NullWindow, pWin, VTMap); + REGION_NULL(pScreen, &temp); + REGION_COPY(pScreen, &temp, &pWin->clipList); + (*pScreen->WindowExposures) (pWin, &temp, NullRegion); + REGION_UNINIT(pScreen, &temp); + } + + return(Success); +} + + +/***** + * MapSubwindows + * Performs a MapWindow all unmapped children of the window, in top + * to bottom stacking order. + *****/ + +void +MapSubwindows(WindowPtr pParent, ClientPtr client) +{ + WindowPtr pWin; + WindowPtr pFirstMapped = NullWindow; + ScreenPtr pScreen; + Mask parentRedirect; + Mask parentNotify; + xEvent event; + Bool anyMarked; + WindowPtr pLayerWin; + + pScreen = pParent->drawable.pScreen; + parentRedirect = RedirectSend(pParent); + parentNotify = SubSend(pParent); + anyMarked = FALSE; + for (pWin = pParent->firstChild; pWin; pWin = pWin->nextSib) + { + if (!pWin->mapped) + { + if (parentRedirect && !pWin->overrideRedirect) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapRequest; + event.u.mapRequest.window = pWin->drawable.id; + event.u.mapRequest.parent = pParent->drawable.id; + + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + continue; + } + + pWin->mapped = TRUE; + if (parentNotify || StrSend(pWin)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapNotify; + event.u.mapNotify.window = pWin->drawable.id; + event.u.mapNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + if (!pFirstMapped) + pFirstMapped = pWin; + if (pParent->realized) + { + RealizeTree(pWin); + if (pWin->viewable) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, + (WindowPtr *)NULL); + } + } + } + } + + if (pFirstMapped) + { + pLayerWin = (*pScreen->GetLayerWindow)(pParent); + if (pLayerWin->parent != pParent) { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pLayerWin, + pLayerWin, + (WindowPtr *)NULL); + pFirstMapped = pLayerWin; + } + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pFirstMapped, VTMap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstMapped, + VTMap); + WindowsRestructured (); + } +} + +static void +UnrealizeTree( + WindowPtr pWin, + Bool fromConfigure) +{ + WindowPtr pChild; + UnrealizeWindowProcPtr Unrealize; + MarkUnrealizedWindowProcPtr MarkUnrealizedWindow; + + Unrealize = pWin->drawable.pScreen->UnrealizeWindow; + MarkUnrealizedWindow = pWin->drawable.pScreen->MarkUnrealizedWindow; + pChild = pWin; + while (1) + { + if (pChild->realized) + { + pChild->realized = FALSE; + pChild->visibility = VisibilityNotViewable; +#ifdef PANORAMIX + if(!noPanoramiXExtension && !pChild->drawable.pScreen->myNum) { + PanoramiXRes *win; + int rc = dixLookupResourceByType((pointer *)&win, + pChild->drawable.id, XRT_WINDOW, + serverClient, DixWriteAccess); + if (rc == Success) + win->u.win.visibility = VisibilityNotViewable; + } +#endif + (* Unrealize)(pChild); + if (MapUnmapEventsEnabled(pWin)) + DeleteWindowFromAnyEvents(pChild, FALSE); + if (pChild->viewable) + { + pChild->viewable = FALSE; + (* MarkUnrealizedWindow)(pChild, pWin, fromConfigure); + pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + return; + pChild = pChild->nextSib; + } +} + +/***** + * UnmapWindow + * If the window is already unmapped, this request has no effect. + * Otherwise, the window is unmapped and an UnMapNotify event is + * generated. Cannot unmap a root window. + *****/ + +int +UnmapWindow(WindowPtr pWin, Bool fromConfigure) +{ + WindowPtr pParent; + xEvent event; + Bool wasRealized = (Bool)pWin->realized; + Bool wasViewable = (Bool)pWin->viewable; + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pLayerWin = pWin; + + if ((!pWin->mapped) || (!(pParent = pWin->parent))) + return(Success); + if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = UnmapNotify; + event.u.unmapNotify.window = pWin->drawable.id; + event.u.unmapNotify.fromConfigure = fromConfigure; + DeliverEvents(pWin, &event, 1, NullWindow); + } + if (wasViewable && !fromConfigure) + { + pWin->valdata = UnmapValData; + (*pScreen->MarkOverlappedWindows)(pWin, pWin->nextSib, &pLayerWin); + (*pScreen->MarkWindow)(pLayerWin->parent); + } + pWin->mapped = FALSE; + if (wasRealized) + UnrealizeTree(pWin, fromConfigure); + if (wasViewable) + { + if (!fromConfigure) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pWin, VTUnmap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (!fromConfigure && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap); + } + if (wasRealized && !fromConfigure) + WindowsRestructured (); + return(Success); +} + +/***** + * UnmapSubwindows + * Performs an UnmapWindow request with the specified mode on all mapped + * children of the window, in bottom to top stacking order. + *****/ + +void +UnmapSubwindows(WindowPtr pWin) +{ + WindowPtr pChild, pHead; + xEvent event; + Bool wasRealized = (Bool)pWin->realized; + Bool wasViewable = (Bool)pWin->viewable; + Bool anyMarked = FALSE; + Mask parentNotify; + WindowPtr pLayerWin = NULL; + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (!pWin->firstChild) + return; + parentNotify = SubSend(pWin); + pHead = RealChildHead(pWin); + + if (wasViewable) + pLayerWin = (*pScreen->GetLayerWindow)(pWin); + + for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) + { + if (pChild->mapped) + { + if (parentNotify || StrSend(pChild)) + { + event.u.u.type = UnmapNotify; + event.u.unmapNotify.window = pChild->drawable.id; + event.u.unmapNotify.fromConfigure = xFalse; + DeliverEvents(pChild, &event, 1, NullWindow); + } + if (pChild->viewable) + { + pChild->valdata = UnmapValData; + anyMarked = TRUE; + } + pChild->mapped = FALSE; + if (pChild->realized) + UnrealizeTree(pChild, FALSE); + if (wasViewable) + { + } + } + } + if (wasViewable) + { + if (anyMarked) + { + if (pLayerWin->parent == pWin) + (*pScreen->MarkWindow)(pWin); + else + { + WindowPtr ptmp; + (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin, + (WindowPtr *)NULL); + (*pScreen->MarkWindow)(pLayerWin->parent); + + /* Windows between pWin and pLayerWin may not have been marked */ + ptmp = pWin; + + while (ptmp != pLayerWin->parent) + { + (*pScreen->MarkWindow)(ptmp); + ptmp = ptmp->parent; + } + pHead = pWin->firstChild; + } + (*pScreen->ValidateTree)(pLayerWin->parent, pHead, VTUnmap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap); + } + if (wasRealized) + WindowsRestructured (); +} + + +void +HandleSaveSet(ClientPtr client) +{ + WindowPtr pParent, pWin; + int j; + + for (j=0; jnumSaved; j++) + { + pWin = SaveSetWindow(client->saveSet[j]); +#ifdef XFIXES + if (SaveSetToRoot(client->saveSet[j])) + pParent = WindowTable[pWin->drawable.pScreen->myNum]; + else +#endif + { + pParent = pWin->parent; + while (pParent && (wClient (pParent) == client)) + pParent = pParent->parent; + } + if (pParent) + { + if (pParent != pWin->parent) + { +#ifdef XFIXES + /* unmap first so that ReparentWindow doesn't remap */ + if (!SaveSetShouldMap (client->saveSet[j])) + UnmapWindow(pWin, FALSE); +#endif + ReparentWindow(pWin, pParent, + pWin->drawable.x - wBorderWidth (pWin) - pParent->drawable.x, + pWin->drawable.y - wBorderWidth (pWin) - pParent->drawable.y, + client); + if(!pWin->realized && pWin->mapped) + pWin->mapped = FALSE; + } +#ifdef XFIXES + if (SaveSetShouldMap (client->saveSet[j])) +#endif + MapWindow(pWin, client); + } + } + free(client->saveSet); + client->numSaved = 0; + client->saveSet = (SaveSetElt *)NULL; +} + +/** + * + * \param x,y in root + */ +Bool +PointInWindowIsVisible(WindowPtr pWin, int x, int y) +{ + BoxRec box; + + if (!pWin->realized) + return (FALSE); + if (POINT_IN_REGION(pWin->drawable.pScreen, &pWin->borderClip, + x, y, &box) + && (!wInputShape(pWin) || + POINT_IN_REGION(pWin->drawable.pScreen, + wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box))) + return(TRUE); + return(FALSE); +} + + +RegionPtr +NotClippedByChildren(WindowPtr pWin) +{ + ScreenPtr pScreen; + RegionPtr pReg; + + pScreen = pWin->drawable.pScreen; + pReg = REGION_CREATE(pScreen, NullBox, 1); + if (pWin->parent || + screenIsSaved != SCREEN_SAVER_ON || + !HasSaverWindow (pWin->drawable.pScreen->myNum)) + { + REGION_INTERSECT(pScreen, pReg, &pWin->borderClip, &pWin->winSize); + } + return(pReg); +} + +void +SendVisibilityNotify(WindowPtr pWin) +{ + xEvent event; +#ifndef NO_XINERAMA_PORT + unsigned int visibility = pWin->visibility; +#endif + if (!MapUnmapEventsEnabled(pWin)) + return; +#ifdef PANORAMIX + /* This is not quite correct yet, but it's close */ + if(!noPanoramiXExtension) { + PanoramiXRes *win; + WindowPtr pWin2; + int rc, i, Scrnum; + + Scrnum = pWin->drawable.pScreen->myNum; + + win = PanoramiXFindIDByScrnum(XRT_WINDOW, pWin->drawable.id, Scrnum); + + if(!win || (win->u.win.visibility == visibility)) + return; + + switch(visibility) { + case VisibilityUnobscured: + for(i = 0; i < PanoramiXNumScreens; i++) { + if(i == Scrnum) continue; + + rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient, + DixWriteAccess); + + if (rc == Success) { + if(pWin2->visibility == VisibilityPartiallyObscured) + return; + + if(!i) pWin = pWin2; + } + } + break; + case VisibilityPartiallyObscured: + if(Scrnum) { + rc = dixLookupWindow(&pWin2, win->info[0].id, serverClient, + DixWriteAccess); + if (rc == Success) pWin = pWin2; + } + break; + case VisibilityFullyObscured: + for(i = 0; i < PanoramiXNumScreens; i++) { + if(i == Scrnum) continue; + + rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient, + DixWriteAccess); + + if (rc == Success) { + if(pWin2->visibility != VisibilityFullyObscured) + return; + + if(!i) pWin = pWin2; + } + } + break; + } + + win->u.win.visibility = visibility; + } +#endif + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = VisibilityNotify; + event.u.visibility.window = pWin->drawable.id; + event.u.visibility.state = visibility; + DeliverEvents(pWin, &event, 1, NullWindow); +} + +#define RANDOM_WIDTH 32 + +#ifndef NOLOGOHACK +static void DrawLogo( + WindowPtr pWin +); +#endif + +int +dixSaveScreens(ClientPtr client, int on, int mode) +{ + int rc, i, what, type; + + if (on == SCREEN_SAVER_FORCER) + { + if (mode == ScreenSaverReset) + what = SCREEN_SAVER_OFF; + else + what = SCREEN_SAVER_ON; + type = what; + } + else + { + what = on; + type = what; + if (what == screenIsSaved) + type = SCREEN_SAVER_CYCLE; + } + + for (i = 0; i < screenInfo.numScreens; i++) { + rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i], + DixShowAccess | DixHideAccess); + if (rc != Success) + return rc; + } + for (i = 0; i < screenInfo.numScreens; i++) + { + if (on == SCREEN_SAVER_FORCER) + (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], on); + if (savedScreenInfo[i].ExternalScreenSaver) + { + if ((*savedScreenInfo[i].ExternalScreenSaver) + (screenInfo.screens[i], type, on == SCREEN_SAVER_FORCER)) + continue; + } + if (type == screenIsSaved) + continue; + switch (type) { + case SCREEN_SAVER_OFF: + if (savedScreenInfo[i].blanked == SCREEN_IS_BLANKED) + { + (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], + what); + } + else if (HasSaverWindow (i)) + { + savedScreenInfo[i].pWindow = NullWindow; + FreeResource(savedScreenInfo[i].wid, RT_NONE); + } + break; + case SCREEN_SAVER_CYCLE: + if (savedScreenInfo[i].blanked == SCREEN_IS_TILED) + { + WindowPtr pWin = savedScreenInfo[i].pWindow; + /* make it look like screen saver is off, so that + * NotClippedByChildren will compute a clip list + * for the root window, so miPaintWindow works + */ + screenIsSaved = SCREEN_SAVER_OFF; +#ifndef NOLOGOHACK + if (logoScreenSaver) + (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, FALSE); +#endif + (*pWin->drawable.pScreen->MoveWindow)(pWin, + (short)(-(rand() % RANDOM_WIDTH)), + (short)(-(rand() % RANDOM_WIDTH)), + pWin->nextSib, VTMove); +#ifndef NOLOGOHACK + if (logoScreenSaver) + DrawLogo(pWin); +#endif + screenIsSaved = SCREEN_SAVER_ON; + } + /* + * Call the DDX saver in case it wants to do something + * at cycle time + */ + else if (savedScreenInfo[i].blanked == SCREEN_IS_BLANKED) + { + (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], + type); + } + break; + case SCREEN_SAVER_ON: + if (ScreenSaverBlanking != DontPreferBlanking) + { + if ((* screenInfo.screens[i]->SaveScreen) + (screenInfo.screens[i], what)) + { + savedScreenInfo[i].blanked = SCREEN_IS_BLANKED; + continue; + } + if ((ScreenSaverAllowExposures != DontAllowExposures) && + TileScreenSaver(i, SCREEN_IS_BLACK)) + { + savedScreenInfo[i].blanked = SCREEN_IS_BLACK; + continue; + } + } + if ((ScreenSaverAllowExposures != DontAllowExposures) && + TileScreenSaver(i, SCREEN_IS_TILED)) + { + savedScreenInfo[i].blanked = SCREEN_IS_TILED; + } + else + savedScreenInfo[i].blanked = SCREEN_ISNT_SAVED; + break; + } + } + screenIsSaved = what; + if (mode == ScreenSaverReset) { + if (on == SCREEN_SAVER_FORCER) { + UpdateCurrentTimeIf(); + lastDeviceEventTime = currentTime; + } + SetScreenSaverTimer(); + } + return Success; +} + +int +SaveScreens(int on, int mode) +{ + return dixSaveScreens(serverClient, on, mode); +} + +static Bool +TileScreenSaver(int i, int kind) +{ + int j; + int result; + XID attributes[3]; + Mask mask; + WindowPtr pWin; + CursorMetricRec cm; + unsigned char *srcbits, *mskbits; + CursorPtr cursor; + XID cursorID = 0; + int attri; + + mask = 0; + attri = 0; + switch (kind) { + case SCREEN_IS_TILED: + switch (WindowTable[i]->backgroundState) { + case BackgroundPixel: + attributes[attri++] = WindowTable[i]->background.pixel; + mask |= CWBackPixel; + break; + case BackgroundPixmap: + attributes[attri++] = None; + mask |= CWBackPixmap; + break; + default: + break; + } + break; + case SCREEN_IS_BLACK: + attributes[attri++] = WindowTable[i]->drawable.pScreen->blackPixel; + mask |= CWBackPixel; + break; + } + mask |= CWOverrideRedirect; + attributes[attri++] = xTrue; + + /* + * create a blank cursor + */ + + cm.width=16; + cm.height=16; + cm.xhot=8; + cm.yhot=8; + srcbits = malloc( BitmapBytePad(32)*16); + mskbits = malloc( BitmapBytePad(32)*16); + if (!srcbits || !mskbits) + { + free(srcbits); + free(mskbits); + cursor = 0; + } + else + { + for (j=0; jwidth + RANDOM_WIDTH, + (unsigned short)screenInfo.screens[i]->height + RANDOM_WIDTH, + 0, InputOutput, mask, attributes, 0, serverClient, + wVisual (WindowTable[i]), &result); + + if (cursor) + FreeResource (cursorID, RT_NONE); + + if (!pWin) + return FALSE; + + if (!AddResource(pWin->drawable.id, RT_WINDOW, + (pointer)savedScreenInfo[i].pWindow)) + return FALSE; + + if (mask & CWBackPixmap) + { + MakeRootTile (pWin); + (*pWin->drawable.pScreen->ChangeWindowAttributes)(pWin, CWBackPixmap); + } + MapWindow(pWin, serverClient); +#ifndef NOLOGOHACK + if (kind == SCREEN_IS_TILED && logoScreenSaver) + DrawLogo(pWin); +#endif + return TRUE; +} + +/* + * FindWindowWithOptional + * + * search ancestors of the given window for an entry containing + * a WindowOpt structure. Assumptions: some parent will + * contain the structure. + */ + +WindowPtr +FindWindowWithOptional (WindowPtr w) +{ + do + w = w->parent; + while (!w->optional); + return w; +} + +/* + * CheckWindowOptionalNeed + * + * check each optional entry in the given window to see if + * the value is satisfied by the default rules. If so, + * release the optional record + */ + +void +CheckWindowOptionalNeed (WindowPtr w) +{ + WindowOptPtr optional; + WindowOptPtr parentOptional; + + if (!w->parent || !w->optional) + return; + optional = w->optional; + if (optional->dontPropagateMask != DontPropagateMasks[w->dontPropagate]) + return; + if (optional->otherEventMasks != 0) + return; + if (optional->otherClients != NULL) + return; + if (optional->passiveGrabs != NULL) + return; + if (optional->userProps != NULL) + return; + if (optional->backingBitPlanes != ~0L) + return; + if (optional->backingPixel != 0) + return; + if (optional->boundingShape != NULL) + return; + if (optional->clipShape != NULL) + return; + if (optional->inputShape != NULL) + return; + if (optional->inputMasks != NULL) + return; + if (optional->deviceCursors != NULL) + { + DevCursNodePtr pNode = optional->deviceCursors; + while(pNode) + { + if (pNode->cursor != None) + return; + pNode = pNode->next; + } + } + + parentOptional = FindWindowWithOptional(w)->optional; + if (optional->visual != parentOptional->visual) + return; + if (optional->cursor != None && + (optional->cursor != parentOptional->cursor || + w->parent->cursorIsNone)) + return; + if (optional->colormap != parentOptional->colormap) + return; + DisposeWindowOptional (w); +} + +/* + * MakeWindowOptional + * + * create an optional record and initialize it with the default + * values. + */ + +Bool +MakeWindowOptional (WindowPtr pWin) +{ + WindowOptPtr optional; + WindowOptPtr parentOptional; + + if (pWin->optional) + return TRUE; + optional = malloc(sizeof (WindowOptRec)); + if (!optional) + return FALSE; + optional->dontPropagateMask = DontPropagateMasks[pWin->dontPropagate]; + optional->otherEventMasks = 0; + optional->otherClients = NULL; + optional->passiveGrabs = NULL; + optional->userProps = NULL; + optional->backingBitPlanes = ~0L; + optional->backingPixel = 0; + optional->boundingShape = NULL; + optional->clipShape = NULL; + optional->inputShape = NULL; + optional->inputMasks = NULL; + optional->deviceCursors = NULL; + + parentOptional = FindWindowWithOptional(pWin)->optional; + optional->visual = parentOptional->visual; + if (!pWin->cursorIsNone) + { + optional->cursor = parentOptional->cursor; + optional->cursor->refcnt++; + } + else + { + optional->cursor = None; + } + optional->colormap = parentOptional->colormap; + pWin->optional = optional; + return TRUE; +} + +/* + * Changes the cursor struct for the given device and the given window. + * A cursor that does not have a device cursor set will use whatever the + * standard cursor is for the window. If all devices have a cursor set, + * changing the window cursor (e.g. using XDefineCursor()) will not have any + * visible effect. Only when one of the device cursors is set to None again, + * this device's cursor will display the changed standard cursor. + * + * CursorIsNone of the window struct is NOT modified if you set a device + * cursor. + * + * Assumption: If there is a node for a device in the list, the device has a + * cursor. If the cursor is set to None, it is inherited by the parent. + */ +int +ChangeWindowDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + CursorPtr pCursor) +{ + DevCursNodePtr pNode, pPrev; + CursorPtr pOldCursor = NULL; + ScreenPtr pScreen; + WindowPtr pChild; + + if (!pWin->optional && !MakeWindowOptional(pWin)) + return BadAlloc; + + /* 1) Check if window has device cursor set + * Yes: 1.1) swap cursor with given cursor if parent does not have same + * cursor, free old cursor + * 1.2) free old cursor, use parent cursor + * No: 1.1) add node to beginning of list. + * 1.2) add cursor to node if parent does not have same cursor + * 1.3) use parent cursor if parent does not have same cursor + * 2) Patch up children if child has a devcursor + * 2.1) if child has cursor None, it inherited from parent, set to old + * cursor + * 2.2) if child has same cursor as new cursor, remove and set to None + */ + + pScreen = pWin->drawable.pScreen; + + if (WindowSeekDeviceCursor(pWin, pDev, &pNode, &pPrev)) + { + /* has device cursor */ + + if (pNode->cursor == pCursor) + return Success; + + pOldCursor = pNode->cursor; + + if (!pCursor) /* remove from list */ + { + if(pPrev) + pPrev->next = pNode->next; + else + /* first item in list */ + pWin->optional->deviceCursors = pNode->next; + + free(pNode); + goto out; + } + + } else + { + /* no device cursor yet */ + DevCursNodePtr pNewNode; + + if (!pCursor) + return Success; + + pNewNode = malloc(sizeof(DevCursNodeRec)); + pNewNode->dev = pDev; + pNewNode->next = pWin->optional->deviceCursors; + pWin->optional->deviceCursors = pNewNode; + pNode = pNewNode; + + } + + if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor)) + pNode->cursor = None; + else + { + pNode->cursor = pCursor; + pCursor->refcnt++; + } + + pNode = pPrev = NULL; + /* fix up children */ + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev)) + { + if (pNode->cursor == None) /* inherited from parent */ + { + pNode->cursor = pOldCursor; + pOldCursor->refcnt++; + } else if (pNode->cursor == pCursor) + { + pNode->cursor = None; + FreeCursor(pCursor, (Cursor)0); /* fix up refcnt */ + } + } + } + +out: + if (pWin->realized) + WindowHasNewCursor(pWin); + + if (pOldCursor) + FreeCursor(pOldCursor, (Cursor)0); + + /* FIXME: We SHOULD check for an error value here XXX + (comment taken from ChangeWindowAttributes) */ + (*pScreen->ChangeWindowAttributes)(pWin, CWCursor); + + return Success; +} + +/* Get device cursor for given device or None if none is set */ +CursorPtr +WindowGetDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev) +{ + DevCursorList pList; + + if (!pWin->optional || !pWin->optional->deviceCursors) + return NULL; + + pList = pWin->optional->deviceCursors; + + while(pList) + { + if (pList->dev == pDev) + { + if (pList->cursor == None) /* inherited from parent */ + return WindowGetDeviceCursor(pWin->parent, pDev); + else + return pList->cursor; + } + pList = pList->next; + } + return NULL; +} + +/* Searches for a DevCursorNode for the given window and device. If one is + * found, return True and set pNode and pPrev to the node and to the node + * before the node respectively. Otherwise return False. + * If the device is the first in list, pPrev is set to NULL. + */ +static Bool +WindowSeekDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + DevCursNodePtr* pNode, + DevCursNodePtr* pPrev) +{ + DevCursorList pList; + + if (!pWin->optional) + return FALSE; + + pList = pWin->optional->deviceCursors; + + if (pList && pList->dev == pDev) + { + *pNode = pList; + *pPrev = NULL; + return TRUE; + } + + while(pList) + { + if (pList->next) + { + if (pList->next->dev == pDev) + { + *pNode = pList->next; + *pPrev = pList; + return TRUE; + } + } + pList = pList->next; + } + return FALSE; +} + +/* Return True if a parent has the same device cursor set or False if + * otherwise + */ +static Bool +WindowParentHasDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + CursorPtr pCursor) +{ + WindowPtr pParent; + DevCursNodePtr pParentNode, pParentPrev; + + pParent = pWin->parent; + while(pParent) + { + if (WindowSeekDeviceCursor(pParent, pDev, + &pParentNode, &pParentPrev)) + { + /* if there is a node in the list, the win has a dev cursor */ + if (!pParentNode->cursor) /* inherited. loop needs to cont. */ + { + } else if (pParentNode->cursor == pCursor) /* inherit */ + return TRUE; + else /* different cursor */ + return FALSE; + } + else + /* parent does not have a device cursor for our device */ + return FALSE; + } + return FALSE; +} + +#ifndef NOLOGOHACK +static void +DrawLogo(WindowPtr pWin) +{ + DrawablePtr pDraw; + ScreenPtr pScreen; + int x, y; + unsigned int width, height, size; + GC *pGC; + int rc, thin, gap, d31; + DDXPointRec poly[4]; + ChangeGCVal fore[2], back[2]; + xrgb rgb[2]; + BITS32 fmask, bmask; + ColormapPtr cmap; + + pDraw = (DrawablePtr)pWin; + pScreen = pDraw->pScreen; + x = -pWin->origin.x; + y = -pWin->origin.y; + width = pScreen->width; + height = pScreen->height; + pGC = GetScratchGC(pScreen->rootDepth, pScreen); + if (!pGC) + return; + + if ((rand() % 100) <= 17) /* make the probability for white fairly low */ + fore[0].val = pScreen->whitePixel; + else + fore[0].val = pScreen->blackPixel; + if (pWin->backgroundState == BackgroundPixel) { + rc = dixLookupResourceByType((pointer *)&cmap, wColormap(pWin), + RT_COLORMAP, serverClient, DixReadAccess); + if (rc == Success) { + Pixel querypixels[2]; + + querypixels[0] = fore[0].val; + querypixels[1] = pWin->background.pixel; + QueryColors(cmap, 2, querypixels, rgb, serverClient); + if ((rgb[0].red == rgb[1].red) && + (rgb[0].green == rgb[1].green) && + (rgb[0].blue == rgb[1].blue)) { + if (fore[0].val == pScreen->blackPixel) + fore[0].val = pScreen->whitePixel; + else + fore[0].val = pScreen->blackPixel; + } + } + } + fore[1].val = FillSolid; + fmask = GCForeground|GCFillStyle; + if (pWin->backgroundState == BackgroundPixel) { + back[0].val = pWin->background.pixel; + back[1].val = FillSolid; + bmask = GCForeground|GCFillStyle; + } else { + back[0].val = 0; + back[1].val = 0; + ChangeGC(NullClient, pGC, GCTileStipXOrigin|GCTileStipYOrigin, back); + back[0].val = FillTiled; + back[1].ptr = pWin->background.pixmap; + bmask = GCFillStyle|GCTile; + } + + /* should be the same as the reference function XmuDrawLogo() */ + + size = width; + if (height < width) + size = height; + size = RANDOM_WIDTH + rand() % (size - RANDOM_WIDTH); + size &= ~1; + x += rand() % (width - size); + y += rand() % (height - size); + +/* + * Draw what will be the thin strokes. + * + * ----- + * / / + * / / + * / / + * / / + * /____/ + * d + * + * Point d is 9/44 (~1/5) of the way across. + */ + + thin = (size / 11); + if (thin < 1) thin = 1; + gap = (thin+3) / 4; + d31 = thin + thin + gap; + poly[0].x = x + size; poly[0].y = y; + poly[1].x = x + size-d31; poly[1].y = y; + poly[2].x = x + 0; poly[2].y = y + size; + poly[3].x = x + d31; poly[3].y = y + size; + ChangeGC(NullClient, pGC, fmask, fore); + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + +/* + * Erase area not needed for lower thin stroke. + * + * ------ + * / / + * / __ / + * / / / + * / / / + * /__/__/ + */ + + poly[0].x = x + d31/2; poly[0].y = y + size; + poly[1].x = x + size / 2; poly[1].y = y + size/2; + poly[2].x = x + (size/2)+(d31-(d31/2)); poly[2].y = y + size/2; + poly[3].x = x + d31; poly[3].y = y + size; + ChangeGC(NullClient, pGC, bmask, back); + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + +/* + * Erase area not needed for upper thin stroke. + * + * ------ + * / / / + * /--/ / + * / / + * / / + * /_____/ + */ + + poly[0].x = x + size - d31/2; poly[0].y = y; + poly[1].x = x + size / 2; poly[1].y = y + size/2; + poly[2].x = x + (size/2)-(d31-(d31/2)); poly[2].y = y + size/2; + poly[3].x = x + size - d31; poly[3].y = y; + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + +/* + * Draw thick stroke. + * Point b is 1/4 of the way across. + * + * b + * ----- + * \ \ + * \ \ + * \ \ + * \ \ + * \____\ + */ + + poly[0].x = x; poly[0].y = y; + poly[1].x = x + size/4; poly[1].y = y; + poly[2].x = x + size; poly[2].y = y + size; + poly[3].x = x + size - size/4; poly[3].y = y + size; + ChangeGC(NullClient, pGC, fmask, fore); + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + +/* + * Erase to create gap. + * + * / + * / + * / + * / + * / + */ + + poly[0].x = x + size- thin; poly[0].y = y; + poly[1].x = x + size-( thin+gap); poly[1].y = y; + poly[2].x = x + thin; poly[2].y = y + size; + poly[3].x = x + thin + gap; poly[3].y = y + size; + ChangeGC(NullClient, pGC, bmask, back); + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + + FreeScratchGC(pGC); +} + +#endif diff --git a/xorg-server/exa/exa.c b/xorg-server/exa/exa.c index da3797237..c16870e5d 100644 --- a/xorg-server/exa/exa.c +++ b/xorg-server/exa/exa.c @@ -1,1129 +1,1129 @@ -/* - * Copyright © 2001 Keith Packard - * - * Partly based on code that is Copyright © The XFree86 Project Inc. - * - * 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. - */ - -/** @file - * This file covers the initialization and teardown of EXA, and has various - * functions not responsible for performing rendering, pixmap migration, or - * memory management. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "exa_priv.h" -#include "exa.h" - -static int exaScreenPrivateKeyIndex; -DevPrivateKey exaScreenPrivateKey = &exaScreenPrivateKeyIndex; -static int exaPixmapPrivateKeyIndex; -DevPrivateKey exaPixmapPrivateKey = &exaPixmapPrivateKeyIndex; -static int exaGCPrivateKeyIndex; -DevPrivateKey exaGCPrivateKey = &exaGCPrivateKeyIndex; - -#ifdef MITSHM -static ShmFuncs exaShmFuncs = { NULL, NULL }; -#endif - -/** - * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of - * the beginning of the given pixmap. - * - * Note that drivers are free to, and often do, munge this offset as necessary - * for handing to the hardware -- for example, translating it into a different - * aperture. This function may need to be extended in the future if we grow - * support for having multiple card-accessible offscreen, such as an AGP memory - * pool alongside the framebuffer pool. - */ -unsigned long -exaGetPixmapOffset(PixmapPtr pPix) -{ - ExaScreenPriv (pPix->drawable.pScreen); - ExaPixmapPriv (pPix); - - return (CARD8 *)pExaPixmap->fb_ptr - pExaScr->info->memoryBase; -} - -void * -exaGetPixmapDriverPrivate(PixmapPtr pPix) -{ - ExaPixmapPriv(pPix); - - return pExaPixmap->driverPriv; -} - -/** - * exaGetPixmapPitch() returns the pitch (in bytes) of the given pixmap. - * - * This is a helper to make driver code more obvious, due to the rather obscure - * naming of the pitch field in the pixmap. - */ -unsigned long -exaGetPixmapPitch(PixmapPtr pPix) -{ - return pPix->devKind; -} - -/** - * exaGetPixmapSize() returns the size in bytes of the given pixmap in video - * memory. Only valid when the pixmap is currently in framebuffer. - */ -unsigned long -exaGetPixmapSize(PixmapPtr pPix) -{ - ExaPixmapPrivPtr pExaPixmap; - - pExaPixmap = ExaGetPixmapPriv(pPix); - if (pExaPixmap != NULL) - return pExaPixmap->fb_size; - return 0; -} - -/** - * exaGetDrawablePixmap() returns a backing pixmap for a given drawable. - * - * @param pDrawable the drawable being requested. - * - * This function returns the backing pixmap for a drawable, whether it is a - * redirected window, unredirected window, or already a pixmap. Note that - * coordinate translation is needed when drawing to the backing pixmap of a - * redirected window, and the translation coordinates are provided by calling - * exaGetOffscreenPixmap() on the drawable. - */ -PixmapPtr -exaGetDrawablePixmap(DrawablePtr pDrawable) -{ - if (pDrawable->type == DRAWABLE_WINDOW) - return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable); - else - return (PixmapPtr) pDrawable; -} - -/** - * Sets the offsets to add to coordinates to make them address the same bits in - * the backing drawable. These coordinates are nonzero only for redirected - * windows. - */ -void -exaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap, - int *xp, int *yp) -{ -#ifdef COMPOSITE - if (pDrawable->type == DRAWABLE_WINDOW) { - *xp = -pPixmap->screen_x; - *yp = -pPixmap->screen_y; - return; - } -#endif - - *xp = 0; - *yp = 0; -} - -/** - * exaPixmapDirty() marks a pixmap as dirty, allowing for - * optimizations in pixmap migration when no changes have occurred. - */ -void -exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) -{ - BoxRec box; - RegionRec region; - - box.x1 = max(x1, 0); - box.y1 = max(y1, 0); - box.x2 = min(x2, pPix->drawable.width); - box.y2 = min(y2, pPix->drawable.height); - - if (box.x1 >= box.x2 || box.y1 >= box.y2) - return; - - REGION_INIT(pScreen, ®ion, &box, 1); - DamageRegionAppend(&pPix->drawable, ®ion); - DamageRegionProcessPending(&pPix->drawable); - REGION_UNINIT(pScreen, ®ion); -} - -static int -exaLog2(int val) -{ - int bits; - - if (val <= 0) - return 0; - for (bits = 0; val != 0; bits++) - val >>= 1; - return bits - 1; -} - -void -exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, - int w, int h, int bpp) -{ - pExaPixmap->accel_blocked = 0; - - if (pExaScr->info->maxPitchPixels) { - int max_pitch = pExaScr->info->maxPitchPixels * bits_to_bytes(bpp); - - if (pExaPixmap->fb_pitch > max_pitch) - pExaPixmap->accel_blocked |= EXA_RANGE_PITCH; - } - - if (pExaScr->info->maxPitchBytes && - pExaPixmap->fb_pitch > pExaScr->info->maxPitchBytes) - pExaPixmap->accel_blocked |= EXA_RANGE_PITCH; - - if (w > pExaScr->info->maxX) - pExaPixmap->accel_blocked |= EXA_RANGE_WIDTH; - - if (h > pExaScr->info->maxY) - pExaPixmap->accel_blocked |= EXA_RANGE_HEIGHT; -} - -void -exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, - int w, int h, int bpp) -{ - if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1) - pExaPixmap->fb_pitch = bits_to_bytes((1 << (exaLog2(w - 1) + 1)) * bpp); - else - pExaPixmap->fb_pitch = bits_to_bytes(w * bpp); - - pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch, - pExaScr->info->pixmapPitchAlign); -} - -/** - * Returns TRUE if the pixmap is not movable. This is the case where it's a - * pixmap which has no private (almost always bad) or it's a scratch pixmap created by - * some X Server internal component (the score says it's pinned). - */ -Bool -exaPixmapIsPinned (PixmapPtr pPix) -{ - ExaPixmapPriv (pPix); - - if (pExaPixmap == NULL) - EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE); - - return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED; -} - -/** - * exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen - * memory, meaning that acceleration could probably be done to it, and that it - * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it - * with the CPU. - * - * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly - * deal with moving pixmaps in and out of system memory), EXA will give drivers - * pixmaps as arguments for which exaPixmapHasGpuCopy() is TRUE. - * - * @return TRUE if the given drawable is in framebuffer memory. - */ -Bool -exaPixmapHasGpuCopy(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv(pScreen); - - if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) - return FALSE; - - return (*pExaScr->pixmap_has_gpu_copy)(pPixmap); -} - -/** - * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapHasGpuCopy(). - */ -Bool -exaDrawableIsOffscreen (DrawablePtr pDrawable) -{ - return exaPixmapHasGpuCopy (exaGetDrawablePixmap (pDrawable)); -} - -/** - * Returns the pixmap which backs a drawable, and the offsets to add to - * coordinates to make them address the same bits in the backing drawable. - */ -PixmapPtr -exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp) -{ - PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); - - exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp); - - if (exaPixmapHasGpuCopy (pPixmap)) - return pPixmap; - else - return NULL; -} - -/** - * Returns TRUE if the pixmap GPU copy is being accessed. - */ -Bool -ExaDoPrepareAccess(PixmapPtr pPixmap, int index) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv (pScreen); - ExaPixmapPriv(pPixmap); - Bool has_gpu_copy, ret; - int i; - - if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) - return FALSE; - - if (pExaPixmap == NULL) - EXA_FatalErrorDebugWithRet(("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n"), FALSE); - - /* Handle repeated / nested calls. */ - for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) { - if (pExaScr->access[i].pixmap == pPixmap) { - pExaScr->access[i].count++; - return pExaScr->access[i].retval; - } - } - - /* If slot for this index is taken, find an empty slot */ - if (pExaScr->access[index].pixmap) { - for (index = EXA_NUM_PREPARE_INDICES - 1; index >= 0; index--) - if (!pExaScr->access[index].pixmap) - break; - } - - /* Access to this pixmap hasn't been prepared yet, so data pointer should be NULL. */ - if (pPixmap->devPrivate.ptr != NULL) { - EXA_FatalErrorDebug(("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n", - pPixmap->devPrivate.ptr)); - } - - has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); - - if (has_gpu_copy && pExaPixmap->fb_ptr) { - pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; - ret = TRUE; - } else { - pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; - ret = FALSE; - } - - /* Store so we can handle repeated / nested calls. */ - pExaScr->access[index].pixmap = pPixmap; - pExaScr->access[index].count = 1; - - if (!has_gpu_copy) - goto out; - - exaWaitSync (pScreen); - - if (pExaScr->info->PrepareAccess == NULL) - goto out; - - if (index >= EXA_PREPARE_AUX_DEST && - !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) { - if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) - FatalError("Unsupported AUX indices used on a pinned pixmap.\n"); - exaMoveOutPixmap (pPixmap); - ret = FALSE; - goto out; - } - - if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) { - if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED && - !(pExaScr->info->flags & EXA_MIXED_PIXMAPS)) - FatalError("Driver failed PrepareAccess on a pinned pixmap.\n"); - exaMoveOutPixmap (pPixmap); - ret = FALSE; - goto out; - } - - ret = TRUE; - -out: - pExaScr->access[index].retval = ret; - return ret; -} - -/** - * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler. - * - * It deals with waiting for synchronization with the card, determining if - * PrepareAccess() is necessary, and working around PrepareAccess() failure. - */ -void -exaPrepareAccess(DrawablePtr pDrawable, int index) -{ - PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); - ExaScreenPriv(pDrawable->pScreen); - - if (pExaScr->prepare_access_reg) - pExaScr->prepare_access_reg(pPixmap, index, NULL); - else - (void)ExaDoPrepareAccess(pPixmap, index); -} - -/** - * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler. - * - * It deals with calling the driver's FinishAccess() only if necessary. - */ -void -exaFinishAccess(DrawablePtr pDrawable, int index) -{ - ScreenPtr pScreen = pDrawable->pScreen; - ExaScreenPriv (pScreen); - PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); - ExaPixmapPriv (pPixmap); - int i; - - if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) - return; - - if (pExaPixmap == NULL) - EXA_FatalErrorDebugWithRet(("EXA bug: exaFinishAccesss was called on a non-exa pixmap.\n"),); - - /* Handle repeated / nested calls. */ - for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) { - if (pExaScr->access[i].pixmap == pPixmap) { - if (--pExaScr->access[i].count > 0) - return; - break; - } - } - - /* Catch unbalanced Prepare/FinishAccess calls. */ - if (i == EXA_NUM_PREPARE_INDICES) - EXA_FatalErrorDebugWithRet(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n", - pPixmap),); - - pExaScr->access[i].pixmap = NULL; - - /* We always hide the devPrivate.ptr. */ - pPixmap->devPrivate.ptr = NULL; - - if (!pExaScr->info->FinishAccess || !exaPixmapHasGpuCopy(pPixmap)) - return; - - if (i >= EXA_PREPARE_AUX_DEST && - !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) { - ErrorF("EXA bug: Trying to call driver FinishAccess hook with " - "unsupported index EXA_PREPARE_AUX*\n"); - return; - } - - (*pExaScr->info->FinishAccess) (pPixmap, i); -} - -/** - * Here begins EXA's GC code. - * Do not ever access the fb/mi layer directly. - */ - -static void -exaValidateGC(GCPtr pGC, - unsigned long changes, - DrawablePtr pDrawable); - -static void -exaDestroyGC(GCPtr pGC); - -static void -exaChangeGC (GCPtr pGC, - unsigned long mask); - -static void -exaCopyGC (GCPtr pGCSrc, - unsigned long mask, - GCPtr pGCDst); - -static void -exaChangeClip (GCPtr pGC, - int type, - pointer pvalue, - int nrects); - -static void -exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc); - -static void -exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc); - -static void -exaDestroyClip(GCPtr pGC); - -const GCFuncs exaGCFuncs = { - exaValidateGC, - exaChangeGC, - exaCopyGC, - exaDestroyGC, - exaChangeClip, - exaDestroyClip, - exaCopyClip -}; - -static void -exaValidateGC(GCPtr pGC, - unsigned long changes, - DrawablePtr pDrawable) -{ - /* fbValidateGC will do direct access to pixmaps if the tiling has changed. - * Do a few smart things so fbValidateGC can do it's work. - */ - - ScreenPtr pScreen = pDrawable->pScreen; - ExaScreenPriv(pScreen); - ExaGCPriv(pGC); - PixmapPtr pTile = NULL; - Bool finish_current_tile = FALSE; - - /* Either of these conditions is enough to trigger access to a tile pixmap. */ - /* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */ - if (pGC->fillStyle == FillTiled || ((changes & GCTile) && !pGC->tileIsPixel)) { - pTile = pGC->tile.pixmap; - - /* Sometimes tile pixmaps are swapped, you need access to: - * - The current tile if it depth matches. - * - Or the rotated tile if that one matches depth and !(changes & GCTile). - * - Or the current tile pixmap and a newly created one. - */ - if (pTile && pTile->drawable.depth != pDrawable->depth && !(changes & GCTile)) { - PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC); - if (pRotatedTile && pRotatedTile->drawable.depth == pDrawable->depth) - pTile = pRotatedTile; - else - finish_current_tile = TRUE; /* CreatePixmap will be called. */ - } - } - - if (pGC->stipple) - exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); - if (pTile) - exaPrepareAccess(&pTile->drawable, EXA_PREPARE_SRC); - - /* Calls to Create/DestroyPixmap have to be identified as special. */ - pExaScr->fallback_counter++; - swap(pExaGC, pGC, funcs); - (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable); - swap(pExaGC, pGC, funcs); - pExaScr->fallback_counter--; - - if (pTile) - exaFinishAccess(&pTile->drawable, EXA_PREPARE_SRC); - if (finish_current_tile && pGC->tile.pixmap) - exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_AUX_DEST); - if (pGC->stipple) - exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); -} - -/* Is exaPrepareAccessGC() needed? */ -static void -exaDestroyGC(GCPtr pGC) -{ - ExaGCPriv(pGC); - swap(pExaGC, pGC, funcs); - (*pGC->funcs->DestroyGC)(pGC); - swap(pExaGC, pGC, funcs); -} - -static void -exaChangeGC (GCPtr pGC, - unsigned long mask) -{ - ExaGCPriv(pGC); - swap(pExaGC, pGC, funcs); - (*pGC->funcs->ChangeGC) (pGC, mask); - swap(pExaGC, pGC, funcs); -} - -static void -exaCopyGC (GCPtr pGCSrc, - unsigned long mask, - GCPtr pGCDst) -{ - ExaGCPriv(pGCDst); - swap(pExaGC, pGCDst, funcs); - (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); - swap(pExaGC, pGCDst, funcs); -} - -static void -exaChangeClip (GCPtr pGC, - int type, - pointer pvalue, - int nrects) -{ - ExaGCPriv(pGC); - swap(pExaGC, pGC, funcs); - (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); - swap(pExaGC, pGC, funcs); -} - -static void -exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc) -{ - ExaGCPriv(pGCDst); - swap(pExaGC, pGCDst, funcs); - (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc); - swap(pExaGC, pGCDst, funcs); -} - -static void -exaDestroyClip(GCPtr pGC) -{ - ExaGCPriv(pGC); - swap(pExaGC, pGC, funcs); - (*pGC->funcs->DestroyClip)(pGC); - swap(pExaGC, pGC, funcs); -} - -/** - * exaCreateGC makes a new GC and hooks up its funcs handler, so that - * exaValidateGC() will get called. - */ -static int -exaCreateGC (GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - ExaScreenPriv(pScreen); - ExaGCPriv(pGC); - Bool ret; - - swap(pExaScr, pScreen, CreateGC); - if ((ret = (*pScreen->CreateGC) (pGC))) { - wrap(pExaGC, pGC, funcs, (GCFuncs *) &exaGCFuncs); - wrap(pExaGC, pGC, ops, (GCOps *) &exaOps); - } - swap(pExaScr, pScreen, CreateGC); - - return ret; -} - -static Bool -exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) -{ - Bool ret; - ScreenPtr pScreen = pWin->drawable.pScreen; - ExaScreenPriv(pScreen); - - if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) - exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); - - if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) - exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); - - pExaScr->fallback_counter++; - swap(pExaScr, pScreen, ChangeWindowAttributes); - ret = pScreen->ChangeWindowAttributes(pWin, mask); - swap(pExaScr, pScreen, ChangeWindowAttributes); - pExaScr->fallback_counter--; - - if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) - exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); - if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) - exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); - - return ret; -} - -static RegionPtr -exaBitmapToRegion(PixmapPtr pPix) -{ - RegionPtr ret; - ScreenPtr pScreen = pPix->drawable.pScreen; - ExaScreenPriv(pScreen); - - exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC); - swap(pExaScr, pScreen, BitmapToRegion); - ret = pScreen->BitmapToRegion(pPix); - swap(pExaScr, pScreen, BitmapToRegion); - exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC); - - return ret; -} - -static Bool -exaCreateScreenResources(ScreenPtr pScreen) -{ - ExaScreenPriv(pScreen); - PixmapPtr pScreenPixmap; - Bool b; - - swap(pExaScr, pScreen, CreateScreenResources); - b = pScreen->CreateScreenResources(pScreen); - swap(pExaScr, pScreen, CreateScreenResources); - - if (!b) - return FALSE; - - pScreenPixmap = pScreen->GetScreenPixmap(pScreen); - - if (pScreenPixmap) { - ExaPixmapPriv(pScreenPixmap); - - exaSetAccelBlock(pExaScr, pExaPixmap, - pScreenPixmap->drawable.width, - pScreenPixmap->drawable.height, - pScreenPixmap->drawable.bitsPerPixel); - } - - return TRUE; -} - -static void -ExaBlockHandler(int screenNum, pointer blockData, pointer pTimeout, - pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[screenNum]; - ExaScreenPriv(pScreen); - - /* Move any deferred results from a software fallback to the driver pixmap */ - if (pExaScr->deferred_mixed_pixmap) - exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap); - - unwrap(pExaScr, pScreen, BlockHandler); - (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); - wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler); - - /* The rest only applies to classic EXA */ - if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) - return; - - /* Try and keep the offscreen memory area tidy every now and then (at most - * once per second) when the server has been idle for at least 100ms. - */ - if (pExaScr->numOffscreenAvailable > 1) { - CARD32 now = GetTimeInMillis(); - - pExaScr->nextDefragment = now + - max(100, (INT32)(pExaScr->lastDefragment + 1000 - now)); - AdjustWaitForDelay(pTimeout, pExaScr->nextDefragment - now); - } -} - -static void -ExaWakeupHandler(int screenNum, pointer wakeupData, unsigned long result, - pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[screenNum]; - ExaScreenPriv(pScreen); - - unwrap(pExaScr, pScreen, WakeupHandler); - (*pScreen->WakeupHandler) (screenNum, wakeupData, result, pReadmask); - wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler); - - if (result == 0 && pExaScr->numOffscreenAvailable > 1) { - CARD32 now = GetTimeInMillis(); - - if ((int)(now - pExaScr->nextDefragment) > 0) { - ExaOffscreenDefragment(pScreen); - pExaScr->lastDefragment = now; - } - } -} - -/** - * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's - * screen private, before calling down to the next CloseSccreen. - */ -static Bool -exaCloseScreen(int i, ScreenPtr pScreen) -{ - ExaScreenPriv(pScreen); - PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); - - if (ps->Glyphs == exaGlyphs) - exaGlyphsFini(pScreen); - - if (pScreen->BlockHandler == ExaBlockHandler) - unwrap(pExaScr, pScreen, BlockHandler); - if (pScreen->WakeupHandler == ExaWakeupHandler) - unwrap(pExaScr, pScreen, WakeupHandler); - unwrap(pExaScr, pScreen, CreateGC); - unwrap(pExaScr, pScreen, CloseScreen); - unwrap(pExaScr, pScreen, GetImage); - unwrap(pExaScr, pScreen, GetSpans); - if (pExaScr->SavedCreatePixmap) - unwrap(pExaScr, pScreen, CreatePixmap); - if (pExaScr->SavedDestroyPixmap) - unwrap(pExaScr, pScreen, DestroyPixmap); - if (pExaScr->SavedModifyPixmapHeader) - unwrap(pExaScr, pScreen, ModifyPixmapHeader); - unwrap(pExaScr, pScreen, CopyWindow); - unwrap(pExaScr, pScreen, ChangeWindowAttributes); - unwrap(pExaScr, pScreen, BitmapToRegion); - unwrap(pExaScr, pScreen, CreateScreenResources); - unwrap(pExaScr, ps, Composite); - if (pExaScr->SavedGlyphs) - unwrap(pExaScr, ps, Glyphs); - unwrap(pExaScr, ps, Trapezoids); - unwrap(pExaScr, ps, Triangles); - unwrap(pExaScr, ps, AddTraps); - - xfree (pExaScr); - - return (*pScreen->CloseScreen) (i, pScreen); -} - -/** - * This function allocates a driver structure for EXA drivers to fill in. By - * having EXA allocate the structure, the driver structure can be extended - * without breaking ABI between EXA and the drivers. The driver's - * responsibility is to check beforehand that the EXA module has a matching - * major number and sufficient minor. Drivers are responsible for freeing the - * driver structure using xfree(). - * - * @return a newly allocated, zero-filled driver structure - */ -ExaDriverPtr -exaDriverAlloc(void) -{ - return xcalloc(1, sizeof(ExaDriverRec)); -} - -/** - * @param pScreen screen being initialized - * @param pScreenInfo EXA driver record - * - * exaDriverInit sets up EXA given a driver record filled in by the driver. - * pScreenInfo should have been allocated by exaDriverAlloc(). See the - * comments in _ExaDriver for what must be filled in and what is optional. - * - * @return TRUE if EXA was successfully initialized. - */ -Bool -exaDriverInit (ScreenPtr pScreen, - ExaDriverPtr pScreenInfo) -{ - ExaScreenPrivPtr pExaScr; - PictureScreenPtr ps; - - if (!pScreenInfo) - return FALSE; - - if (pScreenInfo->exa_major != EXA_VERSION_MAJOR || - pScreenInfo->exa_minor > EXA_VERSION_MINOR) - { - LogMessage(X_ERROR, "EXA(%d): driver's EXA version requirements " - "(%d.%d) are incompatible with EXA version (%d.%d)\n", - pScreen->myNum, - pScreenInfo->exa_major, pScreenInfo->exa_minor, - EXA_VERSION_MAJOR, EXA_VERSION_MINOR); - return FALSE; - } - - if (!pScreenInfo->CreatePixmap && !pScreenInfo->CreatePixmap2) { - if (!pScreenInfo->memoryBase) { - LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memoryBase " - "must be non-zero\n", pScreen->myNum); - return FALSE; - } - - if (!pScreenInfo->memorySize) { - LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memorySize must be " - "non-zero\n", pScreen->myNum); - return FALSE; - } - - if (pScreenInfo->offScreenBase > pScreenInfo->memorySize) { - LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::offScreenBase must " - "be <= ExaDriverRec::memorySize\n", pScreen->myNum); - return FALSE; - } - } - - if (!pScreenInfo->PrepareSolid) { - LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareSolid must be " - "non-NULL\n", pScreen->myNum); - return FALSE; - } - - if (!pScreenInfo->PrepareCopy) { - LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareCopy must be " - "non-NULL\n", pScreen->myNum); - return FALSE; - } - - if (!pScreenInfo->WaitMarker) { - LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::WaitMarker must be " - "non-NULL\n", pScreen->myNum); - return FALSE; - } - - /* If the driver doesn't set any max pitch values, we'll just assume - * that there's a limitation by pixels, and that it's the same as - * maxX. - * - * We want maxPitchPixels or maxPitchBytes to be set so we can check - * pixmaps against the max pitch in exaCreatePixmap() -- it matters - * whether a pixmap is rejected because of its pitch or - * because of its width. - */ - if (!pScreenInfo->maxPitchPixels && !pScreenInfo->maxPitchBytes) - { - pScreenInfo->maxPitchPixels = pScreenInfo->maxX; - } - - ps = GetPictureScreenIfSet(pScreen); - - pExaScr = xcalloc (sizeof (ExaScreenPrivRec), 1); - if (!pExaScr) { - LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n", - pScreen->myNum); - return FALSE; - } - - pExaScr->info = pScreenInfo; - - dixSetPrivate(&pScreen->devPrivates, exaScreenPrivateKey, pExaScr); - - pExaScr->migration = ExaMigrationAlways; - - exaDDXDriverInit(pScreen); - - if (!dixRequestPrivate(exaGCPrivateKey, sizeof(ExaGCPrivRec))) { - LogMessage(X_WARNING, - "EXA(%d): Failed to allocate GC private\n", - pScreen->myNum); - return FALSE; - } - - /* - * Replace various fb screen functions - */ - if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) && - (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) || - (pExaScr->info->flags & EXA_MIXED_PIXMAPS))) - wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler); - if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) && - !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) - wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler); - wrap(pExaScr, pScreen, CreateGC, exaCreateGC); - wrap(pExaScr, pScreen, CloseScreen, exaCloseScreen); - wrap(pExaScr, pScreen, GetImage, exaGetImage); - wrap(pExaScr, pScreen, GetSpans, ExaCheckGetSpans); - wrap(pExaScr, pScreen, CopyWindow, exaCopyWindow); - wrap(pExaScr, pScreen, ChangeWindowAttributes, exaChangeWindowAttributes); - wrap(pExaScr, pScreen, BitmapToRegion, exaBitmapToRegion); - wrap(pExaScr, pScreen, CreateScreenResources, exaCreateScreenResources); - - if (ps) { - wrap(pExaScr, ps, Composite, exaComposite); - if (pScreenInfo->PrepareComposite) - wrap(pExaScr, ps, Glyphs, exaGlyphs); - wrap(pExaScr, ps, Trapezoids, exaTrapezoids); - wrap(pExaScr, ps, Triangles, exaTriangles); - wrap(pExaScr, ps, AddTraps, ExaCheckAddTraps); - } - -#ifdef MITSHM - /* - * Don't allow shared pixmaps. - */ - ShmRegisterFuncs(pScreen, &exaShmFuncs); -#endif - /* - * Hookup offscreen pixmaps - */ - if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) - { - if (!dixRequestPrivate(exaPixmapPrivateKey, sizeof(ExaPixmapPrivRec))) { - LogMessage(X_WARNING, - "EXA(%d): Failed to allocate pixmap private\n", - pScreen->myNum); - return FALSE; - } - if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) { - if (pExaScr->info->flags & EXA_MIXED_PIXMAPS) { - wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_mixed); - wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_mixed); - wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_mixed); - pExaScr->do_migration = exaDoMigration_mixed; - pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_mixed; - pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed; - pExaScr->do_move_out_pixmap = NULL; - pExaScr->prepare_access_reg = exaPrepareAccessReg_mixed; - } else { - wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver); - wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver); - wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_driver); - pExaScr->do_migration = NULL; - pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_driver; - pExaScr->do_move_in_pixmap = NULL; - pExaScr->do_move_out_pixmap = NULL; - pExaScr->prepare_access_reg = NULL; - } - } else { - wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic); - wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_classic); - wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_classic); - pExaScr->do_migration = exaDoMigration_classic; - pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_classic; - pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic; - pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic; - pExaScr->prepare_access_reg = exaPrepareAccessReg_classic; - } - if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { - LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n", - pScreen->myNum, - pExaScr->info->memorySize - pExaScr->info->offScreenBase); - } else { - LogMessage(X_INFO, "EXA(%d): Driver allocated offscreen pixmaps\n", - pScreen->myNum); - - } - } - else - LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum); - - if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { - DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase, - pExaScr->info->memorySize)); - if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) { - if (!exaOffscreenInit (pScreen)) { - LogMessage(X_WARNING, "EXA(%d): Offscreen pixmap setup failed\n", - pScreen->myNum); - return FALSE; - } - } - } - - if (ps->Glyphs == exaGlyphs) - exaGlyphsInit(pScreen); - - LogMessage(X_INFO, "EXA(%d): Driver registered support for the following" - " operations:\n", pScreen->myNum); - assert(pScreenInfo->PrepareSolid != NULL); - LogMessage(X_INFO, " Solid\n"); - assert(pScreenInfo->PrepareCopy != NULL); - LogMessage(X_INFO, " Copy\n"); - if (pScreenInfo->PrepareComposite != NULL) { - LogMessage(X_INFO, " Composite (RENDER acceleration)\n"); - } - if (pScreenInfo->UploadToScreen != NULL) { - LogMessage(X_INFO, " UploadToScreen\n"); - } - if (pScreenInfo->DownloadFromScreen != NULL) { - LogMessage(X_INFO, " DownloadFromScreen\n"); - } - - return TRUE; -} - -/** - * exaDriverFini tears down EXA on a given screen. - * - * @param pScreen screen being torn down. - */ -void -exaDriverFini (ScreenPtr pScreen) -{ - /*right now does nothing*/ -} - -/** - * exaMarkSync() should be called after any asynchronous drawing by the hardware. - * - * @param pScreen screen which drawing occurred on - * - * exaMarkSync() sets a flag to indicate that some asynchronous drawing has - * happened and a WaitSync() will be necessary before relying on the contents of - * offscreen memory from the CPU's perspective. It also calls an optional - * driver MarkSync() callback, the return value of which may be used to do partial - * synchronization with the hardware in the future. - */ -void exaMarkSync(ScreenPtr pScreen) -{ - ExaScreenPriv(pScreen); - - pExaScr->info->needsSync = TRUE; - if (pExaScr->info->MarkSync != NULL) { - pExaScr->info->lastMarker = (*pExaScr->info->MarkSync)(pScreen); - } -} - -/** - * exaWaitSync() ensures that all drawing has been completed. - * - * @param pScreen screen being synchronized. - * - * Calls down into the driver to ensure that all previous drawing has completed. - * It should always be called before relying on the framebuffer contents - * reflecting previous drawing, from a CPU perspective. - */ -void exaWaitSync(ScreenPtr pScreen) -{ - ExaScreenPriv(pScreen); - - if (pExaScr->info->needsSync && !pExaScr->swappedOut) { - (*pExaScr->info->WaitMarker)(pScreen, pExaScr->info->lastMarker); - pExaScr->info->needsSync = FALSE; - } -} - -/** - * Performs migration of the pixmaps according to the operation information - * provided in pixmaps and can_accel and the migration scheme chosen in the - * config file. - */ -void -exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) -{ - ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; - ExaScreenPriv(pScreen); - - if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) - return; - - if (pExaScr->do_migration) - (*pExaScr->do_migration)(pixmaps, npixmaps, can_accel); -} - -void -exaMoveInPixmap (PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv(pScreen); - - if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) - return; - - if (pExaScr->do_move_in_pixmap) - (*pExaScr->do_move_in_pixmap)(pPixmap); -} - -void -exaMoveOutPixmap (PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv(pScreen); - - if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) - return; - - if (pExaScr->do_move_out_pixmap) - (*pExaScr->do_move_out_pixmap)(pPixmap); -} +/* + * Copyright © 2001 Keith Packard + * + * Partly based on code that is Copyright © The XFree86 Project Inc. + * + * 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. + */ + +/** @file + * This file covers the initialization and teardown of EXA, and has various + * functions not responsible for performing rendering, pixmap migration, or + * memory management. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "exa_priv.h" +#include "exa.h" + +static int exaScreenPrivateKeyIndex; +DevPrivateKey exaScreenPrivateKey = &exaScreenPrivateKeyIndex; +static int exaPixmapPrivateKeyIndex; +DevPrivateKey exaPixmapPrivateKey = &exaPixmapPrivateKeyIndex; +static int exaGCPrivateKeyIndex; +DevPrivateKey exaGCPrivateKey = &exaGCPrivateKeyIndex; + +#ifdef MITSHM +static ShmFuncs exaShmFuncs = { NULL, NULL }; +#endif + +/** + * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of + * the beginning of the given pixmap. + * + * Note that drivers are free to, and often do, munge this offset as necessary + * for handing to the hardware -- for example, translating it into a different + * aperture. This function may need to be extended in the future if we grow + * support for having multiple card-accessible offscreen, such as an AGP memory + * pool alongside the framebuffer pool. + */ +unsigned long +exaGetPixmapOffset(PixmapPtr pPix) +{ + ExaScreenPriv (pPix->drawable.pScreen); + ExaPixmapPriv (pPix); + + return (CARD8 *)pExaPixmap->fb_ptr - pExaScr->info->memoryBase; +} + +void * +exaGetPixmapDriverPrivate(PixmapPtr pPix) +{ + ExaPixmapPriv(pPix); + + return pExaPixmap->driverPriv; +} + +/** + * exaGetPixmapPitch() returns the pitch (in bytes) of the given pixmap. + * + * This is a helper to make driver code more obvious, due to the rather obscure + * naming of the pitch field in the pixmap. + */ +unsigned long +exaGetPixmapPitch(PixmapPtr pPix) +{ + return pPix->devKind; +} + +/** + * exaGetPixmapSize() returns the size in bytes of the given pixmap in video + * memory. Only valid when the pixmap is currently in framebuffer. + */ +unsigned long +exaGetPixmapSize(PixmapPtr pPix) +{ + ExaPixmapPrivPtr pExaPixmap; + + pExaPixmap = ExaGetPixmapPriv(pPix); + if (pExaPixmap != NULL) + return pExaPixmap->fb_size; + return 0; +} + +/** + * exaGetDrawablePixmap() returns a backing pixmap for a given drawable. + * + * @param pDrawable the drawable being requested. + * + * This function returns the backing pixmap for a drawable, whether it is a + * redirected window, unredirected window, or already a pixmap. Note that + * coordinate translation is needed when drawing to the backing pixmap of a + * redirected window, and the translation coordinates are provided by calling + * exaGetOffscreenPixmap() on the drawable. + */ +PixmapPtr +exaGetDrawablePixmap(DrawablePtr pDrawable) +{ + if (pDrawable->type == DRAWABLE_WINDOW) + return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable); + else + return (PixmapPtr) pDrawable; +} + +/** + * Sets the offsets to add to coordinates to make them address the same bits in + * the backing drawable. These coordinates are nonzero only for redirected + * windows. + */ +void +exaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap, + int *xp, int *yp) +{ +#ifdef COMPOSITE + if (pDrawable->type == DRAWABLE_WINDOW) { + *xp = -pPixmap->screen_x; + *yp = -pPixmap->screen_y; + return; + } +#endif + + *xp = 0; + *yp = 0; +} + +/** + * exaPixmapDirty() marks a pixmap as dirty, allowing for + * optimizations in pixmap migration when no changes have occurred. + */ +void +exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) +{ + BoxRec box; + RegionRec region; + + box.x1 = max(x1, 0); + box.y1 = max(y1, 0); + box.x2 = min(x2, pPix->drawable.width); + box.y2 = min(y2, pPix->drawable.height); + + if (box.x1 >= box.x2 || box.y1 >= box.y2) + return; + + REGION_INIT(pScreen, ®ion, &box, 1); + DamageRegionAppend(&pPix->drawable, ®ion); + DamageRegionProcessPending(&pPix->drawable); + REGION_UNINIT(pScreen, ®ion); +} + +static int +exaLog2(int val) +{ + int bits; + + if (val <= 0) + return 0; + for (bits = 0; val != 0; bits++) + val >>= 1; + return bits - 1; +} + +void +exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, + int w, int h, int bpp) +{ + pExaPixmap->accel_blocked = 0; + + if (pExaScr->info->maxPitchPixels) { + int max_pitch = pExaScr->info->maxPitchPixels * bits_to_bytes(bpp); + + if (pExaPixmap->fb_pitch > max_pitch) + pExaPixmap->accel_blocked |= EXA_RANGE_PITCH; + } + + if (pExaScr->info->maxPitchBytes && + pExaPixmap->fb_pitch > pExaScr->info->maxPitchBytes) + pExaPixmap->accel_blocked |= EXA_RANGE_PITCH; + + if (w > pExaScr->info->maxX) + pExaPixmap->accel_blocked |= EXA_RANGE_WIDTH; + + if (h > pExaScr->info->maxY) + pExaPixmap->accel_blocked |= EXA_RANGE_HEIGHT; +} + +void +exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, + int w, int h, int bpp) +{ + if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1) + pExaPixmap->fb_pitch = bits_to_bytes((1 << (exaLog2(w - 1) + 1)) * bpp); + else + pExaPixmap->fb_pitch = bits_to_bytes(w * bpp); + + pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch, + pExaScr->info->pixmapPitchAlign); +} + +/** + * Returns TRUE if the pixmap is not movable. This is the case where it's a + * pixmap which has no private (almost always bad) or it's a scratch pixmap created by + * some X Server internal component (the score says it's pinned). + */ +Bool +exaPixmapIsPinned (PixmapPtr pPix) +{ + ExaPixmapPriv (pPix); + + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE); + + return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED; +} + +/** + * exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen + * memory, meaning that acceleration could probably be done to it, and that it + * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it + * with the CPU. + * + * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly + * deal with moving pixmaps in and out of system memory), EXA will give drivers + * pixmaps as arguments for which exaPixmapHasGpuCopy() is TRUE. + * + * @return TRUE if the given drawable is in framebuffer memory. + */ +Bool +exaPixmapHasGpuCopy(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return FALSE; + + return (*pExaScr->pixmap_has_gpu_copy)(pPixmap); +} + +/** + * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapHasGpuCopy(). + */ +Bool +exaDrawableIsOffscreen (DrawablePtr pDrawable) +{ + return exaPixmapHasGpuCopy (exaGetDrawablePixmap (pDrawable)); +} + +/** + * Returns the pixmap which backs a drawable, and the offsets to add to + * coordinates to make them address the same bits in the backing drawable. + */ +PixmapPtr +exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp) +{ + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + + exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp); + + if (exaPixmapHasGpuCopy (pPixmap)) + return pPixmap; + else + return NULL; +} + +/** + * Returns TRUE if the pixmap GPU copy is being accessed. + */ +Bool +ExaDoPrepareAccess(PixmapPtr pPixmap, int index) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv (pScreen); + ExaPixmapPriv(pPixmap); + Bool has_gpu_copy, ret; + int i; + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return FALSE; + + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n"), FALSE); + + /* Handle repeated / nested calls. */ + for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) { + if (pExaScr->access[i].pixmap == pPixmap) { + pExaScr->access[i].count++; + return pExaScr->access[i].retval; + } + } + + /* If slot for this index is taken, find an empty slot */ + if (pExaScr->access[index].pixmap) { + for (index = EXA_NUM_PREPARE_INDICES - 1; index >= 0; index--) + if (!pExaScr->access[index].pixmap) + break; + } + + /* Access to this pixmap hasn't been prepared yet, so data pointer should be NULL. */ + if (pPixmap->devPrivate.ptr != NULL) { + EXA_FatalErrorDebug(("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n", + pPixmap->devPrivate.ptr)); + } + + has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + + if (has_gpu_copy && pExaPixmap->fb_ptr) { + pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; + ret = TRUE; + } else { + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + ret = FALSE; + } + + /* Store so we can handle repeated / nested calls. */ + pExaScr->access[index].pixmap = pPixmap; + pExaScr->access[index].count = 1; + + if (!has_gpu_copy) + goto out; + + exaWaitSync (pScreen); + + if (pExaScr->info->PrepareAccess == NULL) + goto out; + + if (index >= EXA_PREPARE_AUX_DEST && + !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) { + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) + FatalError("Unsupported AUX indices used on a pinned pixmap.\n"); + exaMoveOutPixmap (pPixmap); + ret = FALSE; + goto out; + } + + if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) { + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED && + !(pExaScr->info->flags & EXA_MIXED_PIXMAPS)) + FatalError("Driver failed PrepareAccess on a pinned pixmap.\n"); + exaMoveOutPixmap (pPixmap); + ret = FALSE; + goto out; + } + + ret = TRUE; + +out: + pExaScr->access[index].retval = ret; + return ret; +} + +/** + * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler. + * + * It deals with waiting for synchronization with the card, determining if + * PrepareAccess() is necessary, and working around PrepareAccess() failure. + */ +void +exaPrepareAccess(DrawablePtr pDrawable, int index) +{ + PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); + ExaScreenPriv(pDrawable->pScreen); + + if (pExaScr->prepare_access_reg) + pExaScr->prepare_access_reg(pPixmap, index, NULL); + else + (void)ExaDoPrepareAccess(pPixmap, index); +} + +/** + * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler. + * + * It deals with calling the driver's FinishAccess() only if necessary. + */ +void +exaFinishAccess(DrawablePtr pDrawable, int index) +{ + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv (pScreen); + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv (pPixmap); + int i; + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return; + + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaFinishAccesss was called on a non-exa pixmap.\n"),); + + /* Handle repeated / nested calls. */ + for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) { + if (pExaScr->access[i].pixmap == pPixmap) { + if (--pExaScr->access[i].count > 0) + return; + break; + } + } + + /* Catch unbalanced Prepare/FinishAccess calls. */ + if (i == EXA_NUM_PREPARE_INDICES) + EXA_FatalErrorDebugWithRet(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n", + pPixmap),); + + pExaScr->access[i].pixmap = NULL; + + /* We always hide the devPrivate.ptr. */ + pPixmap->devPrivate.ptr = NULL; + + if (!pExaScr->info->FinishAccess || !exaPixmapHasGpuCopy(pPixmap)) + return; + + if (i >= EXA_PREPARE_AUX_DEST && + !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) { + ErrorF("EXA bug: Trying to call driver FinishAccess hook with " + "unsupported index EXA_PREPARE_AUX*\n"); + return; + } + + (*pExaScr->info->FinishAccess) (pPixmap, i); +} + +/** + * Here begins EXA's GC code. + * Do not ever access the fb/mi layer directly. + */ + +static void +exaValidateGC(GCPtr pGC, + unsigned long changes, + DrawablePtr pDrawable); + +static void +exaDestroyGC(GCPtr pGC); + +static void +exaChangeGC (GCPtr pGC, + unsigned long mask); + +static void +exaCopyGC (GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst); + +static void +exaChangeClip (GCPtr pGC, + int type, + pointer pvalue, + int nrects); + +static void +exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc); + +static void +exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc); + +static void +exaDestroyClip(GCPtr pGC); + +const GCFuncs exaGCFuncs = { + exaValidateGC, + exaChangeGC, + exaCopyGC, + exaDestroyGC, + exaChangeClip, + exaDestroyClip, + exaCopyClip +}; + +static void +exaValidateGC(GCPtr pGC, + unsigned long changes, + DrawablePtr pDrawable) +{ + /* fbValidateGC will do direct access to pixmaps if the tiling has changed. + * Do a few smart things so fbValidateGC can do it's work. + */ + + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv(pScreen); + ExaGCPriv(pGC); + PixmapPtr pTile = NULL; + Bool finish_current_tile = FALSE; + + /* Either of these conditions is enough to trigger access to a tile pixmap. */ + /* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */ + if (pGC->fillStyle == FillTiled || ((changes & GCTile) && !pGC->tileIsPixel)) { + pTile = pGC->tile.pixmap; + + /* Sometimes tile pixmaps are swapped, you need access to: + * - The current tile if it depth matches. + * - Or the rotated tile if that one matches depth and !(changes & GCTile). + * - Or the current tile pixmap and a newly created one. + */ + if (pTile && pTile->drawable.depth != pDrawable->depth && !(changes & GCTile)) { + PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC); + if (pRotatedTile && pRotatedTile->drawable.depth == pDrawable->depth) + pTile = pRotatedTile; + else + finish_current_tile = TRUE; /* CreatePixmap will be called. */ + } + } + + if (pGC->stipple) + exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); + if (pTile) + exaPrepareAccess(&pTile->drawable, EXA_PREPARE_SRC); + + /* Calls to Create/DestroyPixmap have to be identified as special. */ + pExaScr->fallback_counter++; + swap(pExaGC, pGC, funcs); + (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable); + swap(pExaGC, pGC, funcs); + pExaScr->fallback_counter--; + + if (pTile) + exaFinishAccess(&pTile->drawable, EXA_PREPARE_SRC); + if (finish_current_tile && pGC->tile.pixmap) + exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_AUX_DEST); + if (pGC->stipple) + exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); +} + +/* Is exaPrepareAccessGC() needed? */ +static void +exaDestroyGC(GCPtr pGC) +{ + ExaGCPriv(pGC); + swap(pExaGC, pGC, funcs); + (*pGC->funcs->DestroyGC)(pGC); + swap(pExaGC, pGC, funcs); +} + +static void +exaChangeGC (GCPtr pGC, + unsigned long mask) +{ + ExaGCPriv(pGC); + swap(pExaGC, pGC, funcs); + (*pGC->funcs->ChangeGC) (pGC, mask); + swap(pExaGC, pGC, funcs); +} + +static void +exaCopyGC (GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst) +{ + ExaGCPriv(pGCDst); + swap(pExaGC, pGCDst, funcs); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + swap(pExaGC, pGCDst, funcs); +} + +static void +exaChangeClip (GCPtr pGC, + int type, + pointer pvalue, + int nrects) +{ + ExaGCPriv(pGC); + swap(pExaGC, pGC, funcs); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + swap(pExaGC, pGC, funcs); +} + +static void +exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc) +{ + ExaGCPriv(pGCDst); + swap(pExaGC, pGCDst, funcs); + (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc); + swap(pExaGC, pGCDst, funcs); +} + +static void +exaDestroyClip(GCPtr pGC) +{ + ExaGCPriv(pGC); + swap(pExaGC, pGC, funcs); + (*pGC->funcs->DestroyClip)(pGC); + swap(pExaGC, pGC, funcs); +} + +/** + * exaCreateGC makes a new GC and hooks up its funcs handler, so that + * exaValidateGC() will get called. + */ +static int +exaCreateGC (GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + ExaScreenPriv(pScreen); + ExaGCPriv(pGC); + Bool ret; + + swap(pExaScr, pScreen, CreateGC); + if ((ret = (*pScreen->CreateGC) (pGC))) { + wrap(pExaGC, pGC, funcs, (GCFuncs *) &exaGCFuncs); + wrap(pExaGC, pGC, ops, (GCOps *) &exaOps); + } + swap(pExaScr, pScreen, CreateGC); + + return ret; +} + +static Bool +exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) +{ + Bool ret; + ScreenPtr pScreen = pWin->drawable.pScreen; + ExaScreenPriv(pScreen); + + if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) + exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + + if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) + exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); + + pExaScr->fallback_counter++; + swap(pExaScr, pScreen, ChangeWindowAttributes); + ret = pScreen->ChangeWindowAttributes(pWin, mask); + swap(pExaScr, pScreen, ChangeWindowAttributes); + pExaScr->fallback_counter--; + + if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) + exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) + exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); + + return ret; +} + +static RegionPtr +exaBitmapToRegion(PixmapPtr pPix) +{ + RegionPtr ret; + ScreenPtr pScreen = pPix->drawable.pScreen; + ExaScreenPriv(pScreen); + + exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC); + swap(pExaScr, pScreen, BitmapToRegion); + ret = pScreen->BitmapToRegion(pPix); + swap(pExaScr, pScreen, BitmapToRegion); + exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC); + + return ret; +} + +static Bool +exaCreateScreenResources(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + PixmapPtr pScreenPixmap; + Bool b; + + swap(pExaScr, pScreen, CreateScreenResources); + b = pScreen->CreateScreenResources(pScreen); + swap(pExaScr, pScreen, CreateScreenResources); + + if (!b) + return FALSE; + + pScreenPixmap = pScreen->GetScreenPixmap(pScreen); + + if (pScreenPixmap) { + ExaPixmapPriv(pScreenPixmap); + + exaSetAccelBlock(pExaScr, pExaPixmap, + pScreenPixmap->drawable.width, + pScreenPixmap->drawable.height, + pScreenPixmap->drawable.bitsPerPixel); + } + + return TRUE; +} + +static void +ExaBlockHandler(int screenNum, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + ExaScreenPriv(pScreen); + + /* Move any deferred results from a software fallback to the driver pixmap */ + if (pExaScr->deferred_mixed_pixmap) + exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap); + + unwrap(pExaScr, pScreen, BlockHandler); + (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); + wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler); + + /* The rest only applies to classic EXA */ + if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) + return; + + /* Try and keep the offscreen memory area tidy every now and then (at most + * once per second) when the server has been idle for at least 100ms. + */ + if (pExaScr->numOffscreenAvailable > 1) { + CARD32 now = GetTimeInMillis(); + + pExaScr->nextDefragment = now + + max(100, (INT32)(pExaScr->lastDefragment + 1000 - now)); + AdjustWaitForDelay(pTimeout, pExaScr->nextDefragment - now); + } +} + +static void +ExaWakeupHandler(int screenNum, pointer wakeupData, unsigned long result, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + ExaScreenPriv(pScreen); + + unwrap(pExaScr, pScreen, WakeupHandler); + (*pScreen->WakeupHandler) (screenNum, wakeupData, result, pReadmask); + wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler); + + if (result == 0 && pExaScr->numOffscreenAvailable > 1) { + CARD32 now = GetTimeInMillis(); + + if ((int)(now - pExaScr->nextDefragment) > 0) { + ExaOffscreenDefragment(pScreen); + pExaScr->lastDefragment = now; + } + } +} + +/** + * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's + * screen private, before calling down to the next CloseSccreen. + */ +static Bool +exaCloseScreen(int i, ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + + if (ps->Glyphs == exaGlyphs) + exaGlyphsFini(pScreen); + + if (pScreen->BlockHandler == ExaBlockHandler) + unwrap(pExaScr, pScreen, BlockHandler); + if (pScreen->WakeupHandler == ExaWakeupHandler) + unwrap(pExaScr, pScreen, WakeupHandler); + unwrap(pExaScr, pScreen, CreateGC); + unwrap(pExaScr, pScreen, CloseScreen); + unwrap(pExaScr, pScreen, GetImage); + unwrap(pExaScr, pScreen, GetSpans); + if (pExaScr->SavedCreatePixmap) + unwrap(pExaScr, pScreen, CreatePixmap); + if (pExaScr->SavedDestroyPixmap) + unwrap(pExaScr, pScreen, DestroyPixmap); + if (pExaScr->SavedModifyPixmapHeader) + unwrap(pExaScr, pScreen, ModifyPixmapHeader); + unwrap(pExaScr, pScreen, CopyWindow); + unwrap(pExaScr, pScreen, ChangeWindowAttributes); + unwrap(pExaScr, pScreen, BitmapToRegion); + unwrap(pExaScr, pScreen, CreateScreenResources); + unwrap(pExaScr, ps, Composite); + if (pExaScr->SavedGlyphs) + unwrap(pExaScr, ps, Glyphs); + unwrap(pExaScr, ps, Trapezoids); + unwrap(pExaScr, ps, Triangles); + unwrap(pExaScr, ps, AddTraps); + + free(pExaScr); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +/** + * This function allocates a driver structure for EXA drivers to fill in. By + * having EXA allocate the structure, the driver structure can be extended + * without breaking ABI between EXA and the drivers. The driver's + * responsibility is to check beforehand that the EXA module has a matching + * major number and sufficient minor. Drivers are responsible for freeing the + * driver structure using free(). + * + * @return a newly allocated, zero-filled driver structure + */ +ExaDriverPtr +exaDriverAlloc(void) +{ + return calloc(1, sizeof(ExaDriverRec)); +} + +/** + * @param pScreen screen being initialized + * @param pScreenInfo EXA driver record + * + * exaDriverInit sets up EXA given a driver record filled in by the driver. + * pScreenInfo should have been allocated by exaDriverAlloc(). See the + * comments in _ExaDriver for what must be filled in and what is optional. + * + * @return TRUE if EXA was successfully initialized. + */ +Bool +exaDriverInit (ScreenPtr pScreen, + ExaDriverPtr pScreenInfo) +{ + ExaScreenPrivPtr pExaScr; + PictureScreenPtr ps; + + if (!pScreenInfo) + return FALSE; + + if (pScreenInfo->exa_major != EXA_VERSION_MAJOR || + pScreenInfo->exa_minor > EXA_VERSION_MINOR) + { + LogMessage(X_ERROR, "EXA(%d): driver's EXA version requirements " + "(%d.%d) are incompatible with EXA version (%d.%d)\n", + pScreen->myNum, + pScreenInfo->exa_major, pScreenInfo->exa_minor, + EXA_VERSION_MAJOR, EXA_VERSION_MINOR); + return FALSE; + } + + if (!pScreenInfo->CreatePixmap && !pScreenInfo->CreatePixmap2) { + if (!pScreenInfo->memoryBase) { + LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memoryBase " + "must be non-zero\n", pScreen->myNum); + return FALSE; + } + + if (!pScreenInfo->memorySize) { + LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memorySize must be " + "non-zero\n", pScreen->myNum); + return FALSE; + } + + if (pScreenInfo->offScreenBase > pScreenInfo->memorySize) { + LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::offScreenBase must " + "be <= ExaDriverRec::memorySize\n", pScreen->myNum); + return FALSE; + } + } + + if (!pScreenInfo->PrepareSolid) { + LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareSolid must be " + "non-NULL\n", pScreen->myNum); + return FALSE; + } + + if (!pScreenInfo->PrepareCopy) { + LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareCopy must be " + "non-NULL\n", pScreen->myNum); + return FALSE; + } + + if (!pScreenInfo->WaitMarker) { + LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::WaitMarker must be " + "non-NULL\n", pScreen->myNum); + return FALSE; + } + + /* If the driver doesn't set any max pitch values, we'll just assume + * that there's a limitation by pixels, and that it's the same as + * maxX. + * + * We want maxPitchPixels or maxPitchBytes to be set so we can check + * pixmaps against the max pitch in exaCreatePixmap() -- it matters + * whether a pixmap is rejected because of its pitch or + * because of its width. + */ + if (!pScreenInfo->maxPitchPixels && !pScreenInfo->maxPitchBytes) + { + pScreenInfo->maxPitchPixels = pScreenInfo->maxX; + } + + ps = GetPictureScreenIfSet(pScreen); + + pExaScr = calloc(sizeof (ExaScreenPrivRec), 1); + if (!pExaScr) { + LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n", + pScreen->myNum); + return FALSE; + } + + pExaScr->info = pScreenInfo; + + dixSetPrivate(&pScreen->devPrivates, exaScreenPrivateKey, pExaScr); + + pExaScr->migration = ExaMigrationAlways; + + exaDDXDriverInit(pScreen); + + if (!dixRequestPrivate(exaGCPrivateKey, sizeof(ExaGCPrivRec))) { + LogMessage(X_WARNING, + "EXA(%d): Failed to allocate GC private\n", + pScreen->myNum); + return FALSE; + } + + /* + * Replace various fb screen functions + */ + if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) && + (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) || + (pExaScr->info->flags & EXA_MIXED_PIXMAPS))) + wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler); + if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) && + !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) + wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler); + wrap(pExaScr, pScreen, CreateGC, exaCreateGC); + wrap(pExaScr, pScreen, CloseScreen, exaCloseScreen); + wrap(pExaScr, pScreen, GetImage, exaGetImage); + wrap(pExaScr, pScreen, GetSpans, ExaCheckGetSpans); + wrap(pExaScr, pScreen, CopyWindow, exaCopyWindow); + wrap(pExaScr, pScreen, ChangeWindowAttributes, exaChangeWindowAttributes); + wrap(pExaScr, pScreen, BitmapToRegion, exaBitmapToRegion); + wrap(pExaScr, pScreen, CreateScreenResources, exaCreateScreenResources); + + if (ps) { + wrap(pExaScr, ps, Composite, exaComposite); + if (pScreenInfo->PrepareComposite) + wrap(pExaScr, ps, Glyphs, exaGlyphs); + wrap(pExaScr, ps, Trapezoids, exaTrapezoids); + wrap(pExaScr, ps, Triangles, exaTriangles); + wrap(pExaScr, ps, AddTraps, ExaCheckAddTraps); + } + +#ifdef MITSHM + /* + * Don't allow shared pixmaps. + */ + ShmRegisterFuncs(pScreen, &exaShmFuncs); +#endif + /* + * Hookup offscreen pixmaps + */ + if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) + { + if (!dixRequestPrivate(exaPixmapPrivateKey, sizeof(ExaPixmapPrivRec))) { + LogMessage(X_WARNING, + "EXA(%d): Failed to allocate pixmap private\n", + pScreen->myNum); + return FALSE; + } + if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) { + if (pExaScr->info->flags & EXA_MIXED_PIXMAPS) { + wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_mixed); + wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_mixed); + wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_mixed); + pExaScr->do_migration = exaDoMigration_mixed; + pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_mixed; + pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed; + pExaScr->do_move_out_pixmap = NULL; + pExaScr->prepare_access_reg = exaPrepareAccessReg_mixed; + } else { + wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver); + wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver); + wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_driver); + pExaScr->do_migration = NULL; + pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_driver; + pExaScr->do_move_in_pixmap = NULL; + pExaScr->do_move_out_pixmap = NULL; + pExaScr->prepare_access_reg = NULL; + } + } else { + wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic); + wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_classic); + wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_classic); + pExaScr->do_migration = exaDoMigration_classic; + pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_classic; + pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic; + pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic; + pExaScr->prepare_access_reg = exaPrepareAccessReg_classic; + } + if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { + LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n", + pScreen->myNum, + pExaScr->info->memorySize - pExaScr->info->offScreenBase); + } else { + LogMessage(X_INFO, "EXA(%d): Driver allocated offscreen pixmaps\n", + pScreen->myNum); + + } + } + else + LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum); + + if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { + DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase, + pExaScr->info->memorySize)); + if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) { + if (!exaOffscreenInit (pScreen)) { + LogMessage(X_WARNING, "EXA(%d): Offscreen pixmap setup failed\n", + pScreen->myNum); + return FALSE; + } + } + } + + if (ps->Glyphs == exaGlyphs) + exaGlyphsInit(pScreen); + + LogMessage(X_INFO, "EXA(%d): Driver registered support for the following" + " operations:\n", pScreen->myNum); + assert(pScreenInfo->PrepareSolid != NULL); + LogMessage(X_INFO, " Solid\n"); + assert(pScreenInfo->PrepareCopy != NULL); + LogMessage(X_INFO, " Copy\n"); + if (pScreenInfo->PrepareComposite != NULL) { + LogMessage(X_INFO, " Composite (RENDER acceleration)\n"); + } + if (pScreenInfo->UploadToScreen != NULL) { + LogMessage(X_INFO, " UploadToScreen\n"); + } + if (pScreenInfo->DownloadFromScreen != NULL) { + LogMessage(X_INFO, " DownloadFromScreen\n"); + } + + return TRUE; +} + +/** + * exaDriverFini tears down EXA on a given screen. + * + * @param pScreen screen being torn down. + */ +void +exaDriverFini (ScreenPtr pScreen) +{ + /*right now does nothing*/ +} + +/** + * exaMarkSync() should be called after any asynchronous drawing by the hardware. + * + * @param pScreen screen which drawing occurred on + * + * exaMarkSync() sets a flag to indicate that some asynchronous drawing has + * happened and a WaitSync() will be necessary before relying on the contents of + * offscreen memory from the CPU's perspective. It also calls an optional + * driver MarkSync() callback, the return value of which may be used to do partial + * synchronization with the hardware in the future. + */ +void exaMarkSync(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + + pExaScr->info->needsSync = TRUE; + if (pExaScr->info->MarkSync != NULL) { + pExaScr->info->lastMarker = (*pExaScr->info->MarkSync)(pScreen); + } +} + +/** + * exaWaitSync() ensures that all drawing has been completed. + * + * @param pScreen screen being synchronized. + * + * Calls down into the driver to ensure that all previous drawing has completed. + * It should always be called before relying on the framebuffer contents + * reflecting previous drawing, from a CPU perspective. + */ +void exaWaitSync(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + + if (pExaScr->info->needsSync && !pExaScr->swappedOut) { + (*pExaScr->info->WaitMarker)(pScreen, pExaScr->info->lastMarker); + pExaScr->info->needsSync = FALSE; + } +} + +/** + * Performs migration of the pixmaps according to the operation information + * provided in pixmaps and can_accel and the migration scheme chosen in the + * config file. + */ +void +exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) +{ + ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; + ExaScreenPriv(pScreen); + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return; + + if (pExaScr->do_migration) + (*pExaScr->do_migration)(pixmaps, npixmaps, can_accel); +} + +void +exaMoveInPixmap (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return; + + if (pExaScr->do_move_in_pixmap) + (*pExaScr->do_move_in_pixmap)(pPixmap); +} + +void +exaMoveOutPixmap (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return; + + if (pExaScr->do_move_out_pixmap) + (*pExaScr->do_move_out_pixmap)(pPixmap); +} diff --git a/xorg-server/exa/exa_accel.c b/xorg-server/exa/exa_accel.c index 57029fdc5..e30ddce74 100644 --- a/xorg-server/exa/exa_accel.c +++ b/xorg-server/exa/exa_accel.c @@ -1,1304 +1,1304 @@ -/* - * Copyright © 2001 Keith Packard - * - * Partly based on code that is Copyright © The XFree86 Project Inc. - * - * 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. - * - * Authors: - * Eric Anholt - * Michel Dänzer - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif -#include "exa_priv.h" -#include -#include "dixfontstr.h" -#include "exa.h" - -static void -exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, - DDXPointPtr ppt, int *pwidth, int fSorted) -{ - ScreenPtr pScreen = pDrawable->pScreen; - ExaScreenPriv (pScreen); - RegionPtr pClip = fbGetCompositeClip(pGC); - PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); - ExaPixmapPriv (pPixmap); - BoxPtr pextent, pbox; - int nbox; - int extentX1, extentX2, extentY1, extentY2; - int fullX1, fullX2, fullY1; - int partX1, partX2; - int off_x, off_y; - - if (pExaScr->fallback_counter || - pExaScr->swappedOut || - pGC->fillStyle != FillSolid || - pExaPixmap->accel_blocked) - { - ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); - return; - } - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[1]; - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPixmap; - pixmaps[0].pReg = NULL; - - exaDoMigration (pixmaps, 1, TRUE); - } - - if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) || - !(*pExaScr->info->PrepareSolid) (pPixmap, - pGC->alu, - pGC->planemask, - pGC->fgPixel)) - { - ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); - return; - } - - pextent = REGION_EXTENTS(pGC->pScreen, pClip); - extentX1 = pextent->x1; - extentY1 = pextent->y1; - extentX2 = pextent->x2; - extentY2 = pextent->y2; - while (n--) - { - fullX1 = ppt->x; - fullY1 = ppt->y; - fullX2 = fullX1 + (int) *pwidth; - ppt++; - pwidth++; - - if (fullY1 < extentY1 || extentY2 <= fullY1) - continue; - - if (fullX1 < extentX1) - fullX1 = extentX1; - - if (fullX2 > extentX2) - fullX2 = extentX2; - - if (fullX1 >= fullX2) - continue; - - nbox = REGION_NUM_RECTS (pClip); - if (nbox == 1) - { - (*pExaScr->info->Solid) (pPixmap, - fullX1 + off_x, fullY1 + off_y, - fullX2 + off_x, fullY1 + 1 + off_y); - } - else - { - pbox = REGION_RECTS(pClip); - while(nbox--) - { - if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) - { - partX1 = pbox->x1; - if (partX1 < fullX1) - partX1 = fullX1; - partX2 = pbox->x2; - if (partX2 > fullX2) - partX2 = fullX2; - if (partX2 > partX1) { - (*pExaScr->info->Solid) (pPixmap, - partX1 + off_x, fullY1 + off_y, - partX2 + off_x, fullY1 + 1 + off_y); - } - } - pbox++; - } - } - } - (*pExaScr->info->DoneSolid) (pPixmap); - exaMarkSync(pScreen); -} - -static Bool -exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, - int w, int h, int format, char *bits, int src_stride) -{ - ExaScreenPriv (pDrawable->pScreen); - PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); - ExaPixmapPriv(pPix); - RegionPtr pClip; - BoxPtr pbox; - int nbox; - int xoff, yoff; - int bpp = pDrawable->bitsPerPixel; - Bool ret = TRUE; - - if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen) - return FALSE; - - /* If there's a system copy, we want to save the result there */ - if (pExaPixmap->pDamage) - return FALSE; - - /* Don't bother with under 8bpp, XYPixmaps. */ - if (format != ZPixmap || bpp < 8) - return FALSE; - - /* Only accelerate copies: no rop or planemask. */ - if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) - return FALSE; - - if (pExaScr->swappedOut) - return FALSE; - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[1]; - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPix; - pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); - - exaDoMigration (pixmaps, 1, TRUE); - } - - pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); - - if (!pPix) - return FALSE; - - x += pDrawable->x; - y += pDrawable->y; - - pClip = fbGetCompositeClip(pGC); - for (nbox = REGION_NUM_RECTS(pClip), - pbox = REGION_RECTS(pClip); - nbox--; - pbox++) - { - int x1 = x; - int y1 = y; - int x2 = x + w; - int y2 = y + h; - char *src; - Bool ok; - - if (x1 < pbox->x1) - x1 = pbox->x1; - if (y1 < pbox->y1) - y1 = pbox->y1; - if (x2 > pbox->x2) - x2 = pbox->x2; - if (y2 > pbox->y2) - y2 = pbox->y2; - if (x1 >= x2 || y1 >= y2) - continue; - - src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); - ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, - x2 - x1, y2 - y1, src, src_stride); - /* We have to fall back completely, and ignore what has already been completed. - * Messing with the fb layer directly like we used to is completely unacceptable. - */ - if (!ok) { - ret = FALSE; - break; - } - } - - if (ret) - exaMarkSync(pDrawable->pScreen); - - return ret; -} - -static void -exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, - int w, int h, int leftPad, int format, char *bits) -{ - if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits, - PixmapBytePad(w, pDrawable->depth))) - ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, - bits); -} - -static Bool inline -exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, - GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) -{ - ExaScreenPriv (pDstDrawable->pScreen); - PixmapPtr pSrcPixmap, pDstPixmap; - int src_off_x, src_off_y, dst_off_x, dst_off_y; - int dirsetup; - - /* Need to get both pixmaps to call the driver routines */ - pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y); - pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y); - if (!pSrcPixmap || !pDstPixmap) - return FALSE; - - /* - * Now the case of a chip that only supports xdir = ydir = 1 or - * xdir = ydir = -1, but we have xdir != ydir. - */ - dirsetup = 0; /* No direction set up yet. */ - for (; nbox; pbox++, nbox--) { - if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { - /* Do a xdir = ydir = -1 blit instead. */ - if (dirsetup != -1) { - if (dirsetup != 0) - pExaScr->info->DoneCopy(pDstPixmap); - dirsetup = -1; - if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, - pDstPixmap, - -1, -1, - pGC ? pGC->alu : GXcopy, - pGC ? pGC->planemask : - FB_ALLONES)) - return FALSE; - } - (*pExaScr->info->Copy)(pDstPixmap, - src_off_x + pbox->x1 + dx, - src_off_y + pbox->y1 + dy, - dst_off_x + pbox->x1, - dst_off_y + pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { - /* Do a xdir = ydir = 1 blit instead. */ - if (dirsetup != 1) { - if (dirsetup != 0) - pExaScr->info->DoneCopy(pDstPixmap); - dirsetup = 1; - if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, - pDstPixmap, - 1, 1, - pGC ? pGC->alu : GXcopy, - pGC ? pGC->planemask : - FB_ALLONES)) - return FALSE; - } - (*pExaScr->info->Copy)(pDstPixmap, - src_off_x + pbox->x1 + dx, - src_off_y + pbox->y1 + dy, - dst_off_x + pbox->x1, - dst_off_y + pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - } else if (dx >= 0) { - /* - * xdir = 1, ydir = -1. - * Perform line-by-line xdir = ydir = 1 blits, going up. - */ - int i; - if (dirsetup != 1) { - if (dirsetup != 0) - pExaScr->info->DoneCopy(pDstPixmap); - dirsetup = 1; - if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, - pDstPixmap, - 1, 1, - pGC ? pGC->alu : GXcopy, - pGC ? pGC->planemask : - FB_ALLONES)) - return FALSE; - } - for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) - (*pExaScr->info->Copy)(pDstPixmap, - src_off_x + pbox->x1 + dx, - src_off_y + pbox->y1 + dy + i, - dst_off_x + pbox->x1, - dst_off_y + pbox->y1 + i, - pbox->x2 - pbox->x1, 1); - } else { - /* - * xdir = -1, ydir = 1. - * Perform line-by-line xdir = ydir = -1 blits, going down. - */ - int i; - if (dirsetup != -1) { - if (dirsetup != 0) - pExaScr->info->DoneCopy(pDstPixmap); - dirsetup = -1; - if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, - pDstPixmap, - -1, -1, - pGC ? pGC->alu : GXcopy, - pGC ? pGC->planemask : - FB_ALLONES)) - return FALSE; - } - for (i = 0; i < pbox->y2 - pbox->y1; i++) - (*pExaScr->info->Copy)(pDstPixmap, - src_off_x + pbox->x1 + dx, - src_off_y + pbox->y1 + dy + i, - dst_off_x + pbox->x1, - dst_off_y + pbox->y1 + i, - pbox->x2 - pbox->x1, 1); - } - } - if (dirsetup != 0) - pExaScr->info->DoneCopy(pDstPixmap); - exaMarkSync(pDstDrawable->pScreen); - return TRUE; -} - -Bool -exaHWCopyNtoN (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - BoxPtr pbox, - int nbox, - int dx, - int dy, - Bool reverse, - Bool upsidedown) -{ - ExaScreenPriv (pDstDrawable->pScreen); - PixmapPtr pSrcPixmap, pDstPixmap; - ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap; - int src_off_x, src_off_y; - int dst_off_x, dst_off_y; - RegionPtr srcregion = NULL, dstregion = NULL; - xRectangle *rects; - Bool ret = TRUE; - - /* avoid doing copy operations if no boxes */ - if (nbox == 0) - return TRUE; - - pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); - pDstPixmap = exaGetDrawablePixmap (pDstDrawable); - - exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); - exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); - - rects = xalloc(nbox * sizeof(xRectangle)); - - if (rects) { - int i; - int ordering; - - for (i = 0; i < nbox; i++) { - rects[i].x = pbox[i].x1 + dx + src_off_x; - rects[i].y = pbox[i].y1 + dy + src_off_y; - rects[i].width = pbox[i].x2 - pbox[i].x1; - rects[i].height = pbox[i].y2 - pbox[i].y1; - } - - /* This must match the miRegionCopy() logic for reversing rect order */ - if (nbox == 1 || (dx > 0 && dy > 0) || - (pDstDrawable != pSrcDrawable && - (pDstDrawable->type != DRAWABLE_WINDOW || - pSrcDrawable->type != DRAWABLE_WINDOW))) - ordering = CT_YXBANDED; - else - ordering = CT_UNSORTED; - - srcregion = RECTS_TO_REGION(pScreen, nbox, rects, ordering); - xfree(rects); - - if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, - pGC->fillStyle, pGC->alu, - pGC->clientClipType)) { - dstregion = REGION_CREATE(pScreen, NullBox, 0); - REGION_COPY(pScreen, dstregion, srcregion); - REGION_TRANSLATE(pScreen, dstregion, dst_off_x - dx - src_off_x, - dst_off_y - dy - src_off_y); - } - } - - - pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap); - pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); - - /* Check whether the accelerator can use this pixmap. - * If the pitch of the pixmaps is out of range, there's nothing - * we can do but fall back to software rendering. - */ - if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || - pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) - goto fallback; - - /* If the width or the height of either of the pixmaps - * is out of range, check whether the boxes are actually out of the - * addressable range as well. If they aren't, we can still do - * the copying in hardware. - */ - if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { - int i; - - for (i = 0; i < nbox; i++) { - /* src */ - if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || - (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) - goto fallback; - - /* dst */ - if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || - (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) - goto fallback; - } - } - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[2]; - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pDstPixmap; - pixmaps[0].pReg = dstregion; - pixmaps[1].as_dst = FALSE; - pixmaps[1].as_src = TRUE; - pixmaps[1].pPix = pSrcPixmap; - pixmaps[1].pReg = srcregion; - - exaDoMigration (pixmaps, 2, TRUE); - } - - /* Mixed directions must be handled specially if the card is lame */ - if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && - reverse != upsidedown) { - if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, - dx, dy)) - goto out; - goto fallback; - } - - if (exaPixmapHasGpuCopy(pDstPixmap)) { - /* Normal blitting. */ - if (exaPixmapHasGpuCopy(pSrcPixmap)) { - if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, - upsidedown ? -1 : 1, - pGC ? pGC->alu : GXcopy, - pGC ? pGC->planemask : FB_ALLONES)) { - goto fallback; - } - - while (nbox--) - { - (*pExaScr->info->Copy) (pDstPixmap, - pbox->x1 + dx + src_off_x, - pbox->y1 + dy + src_off_y, - pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); - pbox++; - } - - (*pExaScr->info->DoneCopy) (pDstPixmap); - exaMarkSync (pDstDrawable->pScreen); - /* UTS: mainly for SHM PutImage's secondary path. - * - * Only taking this path for directly accessible pixmaps. - */ - } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) { - int bpp = pSrcDrawable->bitsPerPixel; - int src_stride = exaGetPixmapPitch(pSrcPixmap); - CARD8 *src = NULL; - - if (!pExaScr->info->UploadToScreen) - goto fallback; - - if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) - goto fallback; - - if (pSrcDrawable->bitsPerPixel < 8) - goto fallback; - - if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask))) - goto fallback; - - while (nbox--) - { - src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8); - if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x, - pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, - (char *) src, src_stride)) - goto fallback; - - pbox++; - } - } else - goto fallback; - } else - goto fallback; - - goto out; - -fallback: - ret = FALSE; - -out: - if (dstregion) { - REGION_UNINIT(pScreen, dstregion); - REGION_DESTROY(pScreen, dstregion); - } - if (srcregion) { - REGION_UNINIT(pScreen, srcregion); - REGION_DESTROY(pScreen, srcregion); - } - - return ret; -} - -void -exaCopyNtoN (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - BoxPtr pbox, - int nbox, - int dx, - int dy, - Bool reverse, - Bool upsidedown, - Pixel bitplane, - void *closure) -{ - ExaScreenPriv(pDstDrawable->pScreen); - - if (pExaScr->fallback_counter || - (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW)) - return; - - if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown)) - return; - - /* This is a CopyWindow, it's cleaner to fallback at the original call. */ - if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) { - pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; - return; - } - - /* fallback */ - ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure); -} - -RegionPtr -exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, - int srcx, int srcy, int width, int height, int dstx, int dsty) -{ - ExaScreenPriv (pDstDrawable->pScreen); - - if (pExaScr->fallback_counter || pExaScr->swappedOut) { - return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, - srcx, srcy, width, height, dstx, dsty); - } - - return miDoCopy (pSrcDrawable, pDstDrawable, pGC, - srcx, srcy, width, height, - dstx, dsty, exaCopyNtoN, 0, NULL); -} - -static void -exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, - DDXPointPtr ppt) -{ - ExaScreenPriv (pDrawable->pScreen); - int i; - xRectangle *prect; - - /* If we can't reuse the current GC as is, don't bother accelerating the - * points. - */ - if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) { - ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); - return; - } - - prect = xalloc(sizeof(xRectangle) * npt); - for (i = 0; i < npt; i++) { - prect[i].x = ppt[i].x; - prect[i].y = ppt[i].y; - if (i > 0 && mode == CoordModePrevious) { - prect[i].x += prect[i - 1].x; - prect[i].y += prect[i - 1].y; - } - prect[i].width = 1; - prect[i].height = 1; - } - pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); - xfree(prect); -} - -/** - * exaPolylines() checks if it can accelerate the lines as a group of - * horizontal or vertical lines (rectangles), and uses existing rectangle fill - * acceleration if so. - */ -static void -exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, - DDXPointPtr ppt) -{ - ExaScreenPriv (pDrawable->pScreen); - xRectangle *prect; - int x1, x2, y1, y2; - int i; - - if (pExaScr->fallback_counter) { - ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); - return; - } - - /* Don't try to do wide lines or non-solid fill style. */ - if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || - pGC->fillStyle != FillSolid) { - ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); - return; - } - - prect = xalloc(sizeof(xRectangle) * (npt - 1)); - x1 = ppt[0].x; - y1 = ppt[0].y; - /* If we have any non-horizontal/vertical, fall back. */ - for (i = 0; i < npt - 1; i++) { - if (mode == CoordModePrevious) { - x2 = x1 + ppt[i + 1].x; - y2 = y1 + ppt[i + 1].y; - } else { - x2 = ppt[i + 1].x; - y2 = ppt[i + 1].y; - } - - if (x1 != x2 && y1 != y2) { - xfree(prect); - ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); - return; - } - - if (x1 < x2) { - prect[i].x = x1; - prect[i].width = x2 - x1 + 1; - } else { - prect[i].x = x2; - prect[i].width = x1 - x2 + 1; - } - if (y1 < y2) { - prect[i].y = y1; - prect[i].height = y2 - y1 + 1; - } else { - prect[i].y = y2; - prect[i].height = y1 - y2 + 1; - } - - x1 = x2; - y1 = y2; - } - pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); - xfree(prect); -} - -/** - * exaPolySegment() checks if it can accelerate the lines as a group of - * horizontal or vertical lines (rectangles), and uses existing rectangle fill - * acceleration if so. - */ -static void -exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, - xSegment *pSeg) -{ - ExaScreenPriv (pDrawable->pScreen); - xRectangle *prect; - int i; - - /* Don't try to do wide lines or non-solid fill style. */ - if (pExaScr->fallback_counter || pGC->lineWidth != 0 || - pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) - { - ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); - return; - } - - /* If we have any non-horizontal/vertical, fall back. */ - for (i = 0; i < nseg; i++) { - if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { - ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); - return; - } - } - - prect = xalloc(sizeof(xRectangle) * nseg); - for (i = 0; i < nseg; i++) { - if (pSeg[i].x1 < pSeg[i].x2) { - prect[i].x = pSeg[i].x1; - prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; - } else { - prect[i].x = pSeg[i].x2; - prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; - } - if (pSeg[i].y1 < pSeg[i].y2) { - prect[i].y = pSeg[i].y1; - prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; - } else { - prect[i].y = pSeg[i].y2; - prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; - } - - /* don't paint last pixel */ - if (pGC->capStyle == CapNotLast) { - if (prect[i].width == 1) - prect[i].height--; - else - prect[i].width--; - } - } - pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); - xfree(prect); -} - -static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, - Pixel pixel, CARD32 planemask, CARD32 alu, - unsigned int clientClipType); - -static void -exaPolyFillRect(DrawablePtr pDrawable, - GCPtr pGC, - int nrect, - xRectangle *prect) -{ - ExaScreenPriv (pDrawable->pScreen); - RegionPtr pClip = fbGetCompositeClip(pGC); - PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); - ExaPixmapPriv (pPixmap); - register BoxPtr pbox; - BoxPtr pextent; - int extentX1, extentX2, extentY1, extentY2; - int fullX1, fullX2, fullY1, fullY2; - int partX1, partX2, partY1, partY2; - int xoff, yoff; - int xorg, yorg; - int n; - RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); - - /* Compute intersection of rects and clip region */ - REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); - REGION_INTERSECT(pScreen, pReg, pClip, pReg); - - if (!REGION_NUM_RECTS(pReg)) { - goto out; - } - - exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); - - if (pExaScr->fallback_counter || pExaScr->swappedOut || - pExaPixmap->accel_blocked) - { - goto fallback; - } - - /* For ROPs where overlaps don't matter, convert rectangles to region and - * call exaFillRegion{Solid,Tiled}. - */ - if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && - (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || - pGC->alu == GXnoop || pGC->alu == GXcopyInverted || - pGC->alu == GXset)) { - if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && - exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? - pGC->fgPixel : pGC->tile.pixel, pGC->planemask, - pGC->alu, pGC->clientClipType)) || - (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && - exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, - pGC->planemask, pGC->alu, - pGC->clientClipType))) { - goto out; - } - } - - if (pGC->fillStyle != FillSolid && - !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) - { - goto fallback; - } - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[1]; - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPixmap; - pixmaps[0].pReg = NULL; - - exaDoMigration (pixmaps, 1, TRUE); - } - - if (!exaPixmapHasGpuCopy (pPixmap) || - !(*pExaScr->info->PrepareSolid) (pPixmap, - pGC->alu, - pGC->planemask, - pGC->fgPixel)) - { -fallback: - ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); - goto out; - } - - xorg = pDrawable->x; - yorg = pDrawable->y; - - pextent = REGION_EXTENTS(pGC->pScreen, pClip); - extentX1 = pextent->x1; - extentY1 = pextent->y1; - extentX2 = pextent->x2; - extentY2 = pextent->y2; - while (nrect--) - { - fullX1 = prect->x + xorg; - fullY1 = prect->y + yorg; - fullX2 = fullX1 + (int) prect->width; - fullY2 = fullY1 + (int) prect->height; - prect++; - - if (fullX1 < extentX1) - fullX1 = extentX1; - - if (fullY1 < extentY1) - fullY1 = extentY1; - - if (fullX2 > extentX2) - fullX2 = extentX2; - - if (fullY2 > extentY2) - fullY2 = extentY2; - - if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) - continue; - n = REGION_NUM_RECTS (pClip); - if (n == 1) - { - (*pExaScr->info->Solid) (pPixmap, - fullX1 + xoff, fullY1 + yoff, - fullX2 + xoff, fullY2 + yoff); - } - else - { - pbox = REGION_RECTS(pClip); - /* - * clip the rectangle to each box in the clip region - * this is logically equivalent to calling Intersect(), - * but rectangles may overlap each other here. - */ - while(n--) - { - partX1 = pbox->x1; - if (partX1 < fullX1) - partX1 = fullX1; - partY1 = pbox->y1; - if (partY1 < fullY1) - partY1 = fullY1; - partX2 = pbox->x2; - if (partX2 > fullX2) - partX2 = fullX2; - partY2 = pbox->y2; - if (partY2 > fullY2) - partY2 = fullY2; - - pbox++; - - if (partX1 < partX2 && partY1 < partY2) { - (*pExaScr->info->Solid) (pPixmap, - partX1 + xoff, partY1 + yoff, - partX2 + xoff, partY2 + yoff); - } - } - } - } - (*pExaScr->info->DoneSolid) (pPixmap); - exaMarkSync(pDrawable->pScreen); - -out: - REGION_UNINIT(pScreen, pReg); - REGION_DESTROY(pScreen, pReg); -} - -const GCOps exaOps = { - exaFillSpans, - ExaCheckSetSpans, - exaPutImage, - exaCopyArea, - ExaCheckCopyPlane, - exaPolyPoint, - exaPolylines, - exaPolySegment, - miPolyRectangle, - ExaCheckPolyArc, - miFillPolygon, - exaPolyFillRect, - miPolyFillArc, - miPolyText8, - miPolyText16, - miImageText8, - miImageText16, - ExaCheckImageGlyphBlt, - ExaCheckPolyGlyphBlt, - ExaCheckPushPixels, -}; - -void -exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - RegionRec rgnDst; - int dx, dy; - PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); - ExaScreenPriv(pWin->drawable.pScreen); - - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); - - REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); - - REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); -#ifdef COMPOSITE - if (pPixmap->screen_x || pPixmap->screen_y) - REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, - -pPixmap->screen_x, -pPixmap->screen_y); -#endif - - if (pExaScr->fallback_counter) { - pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; - goto fallback; - } - - pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW; - miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, - NULL, - &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); - pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW; - -fallback: - REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); - - if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) { - pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW; - REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, dx, dy); - ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc); - } -} - -static Bool -exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, - CARD32 planemask, CARD32 alu, unsigned int clientClipType) -{ - ExaScreenPriv(pDrawable->pScreen); - PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); - ExaPixmapPriv (pPixmap); - int xoff, yoff; - Bool ret = FALSE; - - exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); - REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); - - if (pExaScr->fallback_counter || pExaPixmap->accel_blocked) - goto out; - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[1]; - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPixmap; - pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, - alu, clientClipType) ? NULL : pRegion; - - exaDoMigration (pixmaps, 1, TRUE); - } - - if (exaPixmapHasGpuCopy (pPixmap) && - (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) - { - int nbox; - BoxPtr pBox; - - nbox = REGION_NUM_RECTS (pRegion); - pBox = REGION_RECTS (pRegion); - - while (nbox--) - { - (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, - pBox->y2); - pBox++; - } - (*pExaScr->info->DoneSolid) (pPixmap); - exaMarkSync(pDrawable->pScreen); - - if (pExaPixmap->pDamage && - pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP && - pDrawable->width == 1 && pDrawable->height == 1 && - pDrawable->bitsPerPixel != 24) { - ExaPixmapPriv(pPixmap); - RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); - - switch (pDrawable->bitsPerPixel) { - case 32: - *(CARD32*)pExaPixmap->sys_ptr = pixel; - break; - case 16: - *(CARD16*)pExaPixmap->sys_ptr = pixel; - break; - case 8: - *(CARD8*)pExaPixmap->sys_ptr = pixel; - } - - REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, - pRegion); - REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, - pRegion); - REGION_SUBTRACT(pScreen, pending_damage, pending_damage, pRegion); - } - - ret = TRUE; - } - -out: - REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); - - return ret; -} - -/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. - * Based on fbFillRegionTiled(), fbTile(). - */ -Bool -exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, - DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, - unsigned int clientClipType) -{ - ExaScreenPriv(pDrawable->pScreen); - PixmapPtr pPixmap; - ExaPixmapPrivPtr pExaPixmap; - ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); - int xoff, yoff; - int tileWidth, tileHeight; - int nbox = REGION_NUM_RECTS (pRegion); - BoxPtr pBox = REGION_RECTS (pRegion); - Bool ret = FALSE; - int i; - - tileWidth = pTile->drawable.width; - tileHeight = pTile->drawable.height; - - /* If we're filling with a solid color, grab it out and go to - * FillRegionSolid, saving numerous copies. - */ - if (tileWidth == 1 && tileHeight == 1) - return exaFillRegionSolid(pDrawable, pRegion, - exaGetPixmapFirstPixel (pTile), planemask, - alu, clientClipType); - - pPixmap = exaGetDrawablePixmap (pDrawable); - pExaPixmap = ExaGetPixmapPriv (pPixmap); - - if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || - pTileExaPixmap->accel_blocked) - return FALSE; - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[2]; - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPixmap; - pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, - alu, clientClipType) ? NULL : pRegion; - pixmaps[1].as_dst = FALSE; - pixmaps[1].as_src = TRUE; - pixmaps[1].pPix = pTile; - pixmaps[1].pReg = NULL; - - exaDoMigration (pixmaps, 2, TRUE); - } - - pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); - - if (!pPixmap || !exaPixmapHasGpuCopy(pTile)) - return FALSE; - - if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) - { - if (xoff || yoff) - REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); - - for (i = 0; i < nbox; i++) - { - int height = pBox[i].y2 - pBox[i].y1; - int dstY = pBox[i].y1; - int tileY; - - if (alu == GXcopy) - height = min(height, tileHeight); - - modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); - - while (height > 0) { - int width = pBox[i].x2 - pBox[i].x1; - int dstX = pBox[i].x1; - int tileX; - int h = tileHeight - tileY; - - if (alu == GXcopy) - width = min(width, tileWidth); - - if (h > height) - h = height; - height -= h; - - modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, - tileX); - - while (width > 0) { - int w = tileWidth - tileX; - if (w > width) - w = width; - width -= w; - - (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, - w, h); - dstX += w; - tileX = 0; - } - dstY += h; - tileY = 0; - } - } - (*pExaScr->info->DoneCopy) (pPixmap); - - /* With GXcopy, we only need to do the basic algorithm up to the tile - * size; then, we can just keep doubling the destination in each - * direction until it fills the box. This way, the number of copy - * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where - * rx/ry is the ratio between box and tile width/height. This can make - * a big difference if each driver copy incurs a significant constant - * overhead. - */ - if (alu != GXcopy) - ret = TRUE; - else { - Bool more_copy = FALSE; - - for (i = 0; i < nbox; i++) { - int dstX = pBox[i].x1 + tileWidth; - int dstY = pBox[i].y1 + tileHeight; - - if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { - more_copy = TRUE; - break; - } - } - - if (more_copy == FALSE) - ret = TRUE; - - if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, - 1, 1, alu, planemask)) { - for (i = 0; i < nbox; i++) - { - int dstX = pBox[i].x1 + tileWidth; - int dstY = pBox[i].y1 + tileHeight; - int width = min(pBox[i].x2 - dstX, tileWidth); - int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); - - while (dstX < pBox[i].x2) { - (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, - dstX, pBox[i].y1, width, height); - dstX += width; - width = min(pBox[i].x2 - dstX, width * 2); - } - - width = pBox[i].x2 - pBox[i].x1; - height = min(pBox[i].y2 - dstY, tileHeight); - - while (dstY < pBox[i].y2) { - (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, - pBox[i].x1, dstY, width, height); - dstY += height; - height = min(pBox[i].y2 - dstY, height * 2); - } - } - - (*pExaScr->info->DoneCopy) (pPixmap); - - ret = TRUE; - } - } - - exaMarkSync(pDrawable->pScreen); - - if (xoff || yoff) - REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); - } - - return ret; -} - - -/** - * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. - * - * This is probably the only case we actually care about. The rest fall through - * to migration and fbGetImage, which hopefully will result in migration pushing - * the pixmap out of framebuffer. - */ -void -exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, - unsigned int format, unsigned long planeMask, char *d) -{ - ExaScreenPriv (pDrawable->pScreen); - PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); - ExaPixmapPriv(pPix); - int xoff, yoff; - Bool ok; - - if (pExaScr->fallback_counter || pExaScr->swappedOut) - goto fallback; - - /* If there's a system copy, we want to save the result there */ - if (pExaPixmap->pDamage) - goto fallback; - - pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); - - if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) - goto fallback; - - /* Only cover the ZPixmap, solid copy case. */ - if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) - goto fallback; - - /* Only try to handle the 8bpp and up cases, since we don't want to think - * about <8bpp. - */ - if (pDrawable->bitsPerPixel < 8) - goto fallback; - - ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, - pDrawable->y + y + yoff, w, h, d, - PixmapBytePad(w, pDrawable->depth)); - if (ok) { - exaWaitSync(pDrawable->pScreen); - return; - } - -fallback: - ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); -} +/* + * Copyright © 2001 Keith Packard + * + * Partly based on code that is Copyright © The XFree86 Project Inc. + * + * 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. + * + * Authors: + * Eric Anholt + * Michel Dänzer + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif +#include "exa_priv.h" +#include +#include "dixfontstr.h" +#include "exa.h" + +static void +exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv (pScreen); + RegionPtr pClip = fbGetCompositeClip(pGC); + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv (pPixmap); + BoxPtr pextent, pbox; + int nbox; + int extentX1, extentX2, extentY1, extentY2; + int fullX1, fullX2, fullY1; + int partX1, partX2; + int off_x, off_y; + + if (pExaScr->fallback_counter || + pExaScr->swappedOut || + pGC->fillStyle != FillSolid || + pExaPixmap->accel_blocked) + { + ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); + return; + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = NULL; + + exaDoMigration (pixmaps, 1, TRUE); + } + + if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) || + !(*pExaScr->info->PrepareSolid) (pPixmap, + pGC->alu, + pGC->planemask, + pGC->fgPixel)) + { + ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); + return; + } + + pextent = REGION_EXTENTS(pGC->pScreen, pClip); + extentX1 = pextent->x1; + extentY1 = pextent->y1; + extentX2 = pextent->x2; + extentY2 = pextent->y2; + while (n--) + { + fullX1 = ppt->x; + fullY1 = ppt->y; + fullX2 = fullX1 + (int) *pwidth; + ppt++; + pwidth++; + + if (fullY1 < extentY1 || extentY2 <= fullY1) + continue; + + if (fullX1 < extentX1) + fullX1 = extentX1; + + if (fullX2 > extentX2) + fullX2 = extentX2; + + if (fullX1 >= fullX2) + continue; + + nbox = REGION_NUM_RECTS (pClip); + if (nbox == 1) + { + (*pExaScr->info->Solid) (pPixmap, + fullX1 + off_x, fullY1 + off_y, + fullX2 + off_x, fullY1 + 1 + off_y); + } + else + { + pbox = REGION_RECTS(pClip); + while(nbox--) + { + if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) + { + partX1 = pbox->x1; + if (partX1 < fullX1) + partX1 = fullX1; + partX2 = pbox->x2; + if (partX2 > fullX2) + partX2 = fullX2; + if (partX2 > partX1) { + (*pExaScr->info->Solid) (pPixmap, + partX1 + off_x, fullY1 + off_y, + partX2 + off_x, fullY1 + 1 + off_y); + } + } + pbox++; + } + } + } + (*pExaScr->info->DoneSolid) (pPixmap); + exaMarkSync(pScreen); +} + +static Bool +exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, + int w, int h, int format, char *bits, int src_stride) +{ + ExaScreenPriv (pDrawable->pScreen); + PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv(pPix); + RegionPtr pClip; + BoxPtr pbox; + int nbox; + int xoff, yoff; + int bpp = pDrawable->bitsPerPixel; + Bool ret = TRUE; + + if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen) + return FALSE; + + /* If there's a system copy, we want to save the result there */ + if (pExaPixmap->pDamage) + return FALSE; + + /* Don't bother with under 8bpp, XYPixmaps. */ + if (format != ZPixmap || bpp < 8) + return FALSE; + + /* Only accelerate copies: no rop or planemask. */ + if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) + return FALSE; + + if (pExaScr->swappedOut) + return FALSE; + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPix; + pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); + + exaDoMigration (pixmaps, 1, TRUE); + } + + pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + + if (!pPix) + return FALSE; + + x += pDrawable->x; + y += pDrawable->y; + + pClip = fbGetCompositeClip(pGC); + for (nbox = REGION_NUM_RECTS(pClip), + pbox = REGION_RECTS(pClip); + nbox--; + pbox++) + { + int x1 = x; + int y1 = y; + int x2 = x + w; + int y2 = y + h; + char *src; + Bool ok; + + if (x1 < pbox->x1) + x1 = pbox->x1; + if (y1 < pbox->y1) + y1 = pbox->y1; + if (x2 > pbox->x2) + x2 = pbox->x2; + if (y2 > pbox->y2) + y2 = pbox->y2; + if (x1 >= x2 || y1 >= y2) + continue; + + src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); + ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, + x2 - x1, y2 - y1, src, src_stride); + /* We have to fall back completely, and ignore what has already been completed. + * Messing with the fb layer directly like we used to is completely unacceptable. + */ + if (!ok) { + ret = FALSE; + break; + } + } + + if (ret) + exaMarkSync(pDrawable->pScreen); + + return ret; +} + +static void +exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, + int w, int h, int leftPad, int format, char *bits) +{ + if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits, + PixmapBytePad(w, pDrawable->depth))) + ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, + bits); +} + +static Bool inline +exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) +{ + ExaScreenPriv (pDstDrawable->pScreen); + PixmapPtr pSrcPixmap, pDstPixmap; + int src_off_x, src_off_y, dst_off_x, dst_off_y; + int dirsetup; + + /* Need to get both pixmaps to call the driver routines */ + pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y); + pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y); + if (!pSrcPixmap || !pDstPixmap) + return FALSE; + + /* + * Now the case of a chip that only supports xdir = ydir = 1 or + * xdir = ydir = -1, but we have xdir != ydir. + */ + dirsetup = 0; /* No direction set up yet. */ + for (; nbox; pbox++, nbox--) { + if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { + /* Do a xdir = ydir = -1 blit instead. */ + if (dirsetup != -1) { + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + dirsetup = -1; + if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + -1, -1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + (*pExaScr->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { + /* Do a xdir = ydir = 1 blit instead. */ + if (dirsetup != 1) { + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + dirsetup = 1; + if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + 1, 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + (*pExaScr->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } else if (dx >= 0) { + /* + * xdir = 1, ydir = -1. + * Perform line-by-line xdir = ydir = 1 blits, going up. + */ + int i; + if (dirsetup != 1) { + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + dirsetup = 1; + if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + 1, 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) + (*pExaScr->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy + i, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1 + i, + pbox->x2 - pbox->x1, 1); + } else { + /* + * xdir = -1, ydir = 1. + * Perform line-by-line xdir = ydir = -1 blits, going down. + */ + int i; + if (dirsetup != -1) { + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + dirsetup = -1; + if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + -1, -1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + for (i = 0; i < pbox->y2 - pbox->y1; i++) + (*pExaScr->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy + i, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1 + i, + pbox->x2 - pbox->x1, 1); + } + } + if (dirsetup != 0) + pExaScr->info->DoneCopy(pDstPixmap); + exaMarkSync(pDstDrawable->pScreen); + return TRUE; +} + +Bool +exaHWCopyNtoN (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown) +{ + ExaScreenPriv (pDstDrawable->pScreen); + PixmapPtr pSrcPixmap, pDstPixmap; + ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap; + int src_off_x, src_off_y; + int dst_off_x, dst_off_y; + RegionPtr srcregion = NULL, dstregion = NULL; + xRectangle *rects; + Bool ret = TRUE; + + /* avoid doing copy operations if no boxes */ + if (nbox == 0) + return TRUE; + + pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); + pDstPixmap = exaGetDrawablePixmap (pDstDrawable); + + exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); + exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); + + rects = malloc(nbox * sizeof(xRectangle)); + + if (rects) { + int i; + int ordering; + + for (i = 0; i < nbox; i++) { + rects[i].x = pbox[i].x1 + dx + src_off_x; + rects[i].y = pbox[i].y1 + dy + src_off_y; + rects[i].width = pbox[i].x2 - pbox[i].x1; + rects[i].height = pbox[i].y2 - pbox[i].y1; + } + + /* This must match the miRegionCopy() logic for reversing rect order */ + if (nbox == 1 || (dx > 0 && dy > 0) || + (pDstDrawable != pSrcDrawable && + (pDstDrawable->type != DRAWABLE_WINDOW || + pSrcDrawable->type != DRAWABLE_WINDOW))) + ordering = CT_YXBANDED; + else + ordering = CT_UNSORTED; + + srcregion = RECTS_TO_REGION(pScreen, nbox, rects, ordering); + free(rects); + + if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, + pGC->fillStyle, pGC->alu, + pGC->clientClipType)) { + dstregion = REGION_CREATE(pScreen, NullBox, 0); + REGION_COPY(pScreen, dstregion, srcregion); + REGION_TRANSLATE(pScreen, dstregion, dst_off_x - dx - src_off_x, + dst_off_y - dy - src_off_y); + } + } + + + pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap); + pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); + + /* Check whether the accelerator can use this pixmap. + * If the pitch of the pixmaps is out of range, there's nothing + * we can do but fall back to software rendering. + */ + if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || + pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) + goto fallback; + + /* If the width or the height of either of the pixmaps + * is out of range, check whether the boxes are actually out of the + * addressable range as well. If they aren't, we can still do + * the copying in hardware. + */ + if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { + int i; + + for (i = 0; i < nbox; i++) { + /* src */ + if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || + (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) + goto fallback; + + /* dst */ + if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || + (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) + goto fallback; + } + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[2]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pDstPixmap; + pixmaps[0].pReg = dstregion; + pixmaps[1].as_dst = FALSE; + pixmaps[1].as_src = TRUE; + pixmaps[1].pPix = pSrcPixmap; + pixmaps[1].pReg = srcregion; + + exaDoMigration (pixmaps, 2, TRUE); + } + + /* Mixed directions must be handled specially if the card is lame */ + if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && + reverse != upsidedown) { + if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, + dx, dy)) + goto out; + goto fallback; + } + + if (exaPixmapHasGpuCopy(pDstPixmap)) { + /* Normal blitting. */ + if (exaPixmapHasGpuCopy(pSrcPixmap)) { + if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, + upsidedown ? -1 : 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : FB_ALLONES)) { + goto fallback; + } + + while (nbox--) + { + (*pExaScr->info->Copy) (pDstPixmap, + pbox->x1 + dx + src_off_x, + pbox->y1 + dy + src_off_y, + pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + + (*pExaScr->info->DoneCopy) (pDstPixmap); + exaMarkSync (pDstDrawable->pScreen); + /* UTS: mainly for SHM PutImage's secondary path. + * + * Only taking this path for directly accessible pixmaps. + */ + } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) { + int bpp = pSrcDrawable->bitsPerPixel; + int src_stride = exaGetPixmapPitch(pSrcPixmap); + CARD8 *src = NULL; + + if (!pExaScr->info->UploadToScreen) + goto fallback; + + if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) + goto fallback; + + if (pSrcDrawable->bitsPerPixel < 8) + goto fallback; + + if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask))) + goto fallback; + + while (nbox--) + { + src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8); + if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x, + pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, + (char *) src, src_stride)) + goto fallback; + + pbox++; + } + } else + goto fallback; + } else + goto fallback; + + goto out; + +fallback: + ret = FALSE; + +out: + if (dstregion) { + REGION_UNINIT(pScreen, dstregion); + REGION_DESTROY(pScreen, dstregion); + } + if (srcregion) { + REGION_UNINIT(pScreen, srcregion); + REGION_DESTROY(pScreen, srcregion); + } + + return ret; +} + +void +exaCopyNtoN (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure) +{ + ExaScreenPriv(pDstDrawable->pScreen); + + if (pExaScr->fallback_counter || + (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW)) + return; + + if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown)) + return; + + /* This is a CopyWindow, it's cleaner to fallback at the original call. */ + if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) { + pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; + return; + } + + /* fallback */ + ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure); +} + +RegionPtr +exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, + int srcx, int srcy, int width, int height, int dstx, int dsty) +{ + ExaScreenPriv (pDstDrawable->pScreen); + + if (pExaScr->fallback_counter || pExaScr->swappedOut) { + return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty); + } + + return miDoCopy (pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, + dstx, dsty, exaCopyNtoN, 0, NULL); +} + +static void +exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr ppt) +{ + ExaScreenPriv (pDrawable->pScreen); + int i; + xRectangle *prect; + + /* If we can't reuse the current GC as is, don't bother accelerating the + * points. + */ + if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) { + ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); + return; + } + + prect = malloc(sizeof(xRectangle) * npt); + for (i = 0; i < npt; i++) { + prect[i].x = ppt[i].x; + prect[i].y = ppt[i].y; + if (i > 0 && mode == CoordModePrevious) { + prect[i].x += prect[i - 1].x; + prect[i].y += prect[i - 1].y; + } + prect[i].width = 1; + prect[i].height = 1; + } + pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); + free(prect); +} + +/** + * exaPolylines() checks if it can accelerate the lines as a group of + * horizontal or vertical lines (rectangles), and uses existing rectangle fill + * acceleration if so. + */ +static void +exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr ppt) +{ + ExaScreenPriv (pDrawable->pScreen); + xRectangle *prect; + int x1, x2, y1, y2; + int i; + + if (pExaScr->fallback_counter) { + ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); + return; + } + + /* Don't try to do wide lines or non-solid fill style. */ + if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || + pGC->fillStyle != FillSolid) { + ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); + return; + } + + prect = malloc(sizeof(xRectangle) * (npt - 1)); + x1 = ppt[0].x; + y1 = ppt[0].y; + /* If we have any non-horizontal/vertical, fall back. */ + for (i = 0; i < npt - 1; i++) { + if (mode == CoordModePrevious) { + x2 = x1 + ppt[i + 1].x; + y2 = y1 + ppt[i + 1].y; + } else { + x2 = ppt[i + 1].x; + y2 = ppt[i + 1].y; + } + + if (x1 != x2 && y1 != y2) { + free(prect); + ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); + return; + } + + if (x1 < x2) { + prect[i].x = x1; + prect[i].width = x2 - x1 + 1; + } else { + prect[i].x = x2; + prect[i].width = x1 - x2 + 1; + } + if (y1 < y2) { + prect[i].y = y1; + prect[i].height = y2 - y1 + 1; + } else { + prect[i].y = y2; + prect[i].height = y1 - y2 + 1; + } + + x1 = x2; + y1 = y2; + } + pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); + free(prect); +} + +/** + * exaPolySegment() checks if it can accelerate the lines as a group of + * horizontal or vertical lines (rectangles), and uses existing rectangle fill + * acceleration if so. + */ +static void +exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *pSeg) +{ + ExaScreenPriv (pDrawable->pScreen); + xRectangle *prect; + int i; + + /* Don't try to do wide lines or non-solid fill style. */ + if (pExaScr->fallback_counter || pGC->lineWidth != 0 || + pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) + { + ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); + return; + } + + /* If we have any non-horizontal/vertical, fall back. */ + for (i = 0; i < nseg; i++) { + if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { + ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); + return; + } + } + + prect = malloc(sizeof(xRectangle) * nseg); + for (i = 0; i < nseg; i++) { + if (pSeg[i].x1 < pSeg[i].x2) { + prect[i].x = pSeg[i].x1; + prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; + } else { + prect[i].x = pSeg[i].x2; + prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; + } + if (pSeg[i].y1 < pSeg[i].y2) { + prect[i].y = pSeg[i].y1; + prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; + } else { + prect[i].y = pSeg[i].y2; + prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; + } + + /* don't paint last pixel */ + if (pGC->capStyle == CapNotLast) { + if (prect[i].width == 1) + prect[i].height--; + else + prect[i].width--; + } + } + pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); + free(prect); +} + +static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, + Pixel pixel, CARD32 planemask, CARD32 alu, + unsigned int clientClipType); + +static void +exaPolyFillRect(DrawablePtr pDrawable, + GCPtr pGC, + int nrect, + xRectangle *prect) +{ + ExaScreenPriv (pDrawable->pScreen); + RegionPtr pClip = fbGetCompositeClip(pGC); + PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); + ExaPixmapPriv (pPixmap); + register BoxPtr pbox; + BoxPtr pextent; + int extentX1, extentX2, extentY1, extentY2; + int fullX1, fullX2, fullY1, fullY2; + int partX1, partX2, partY1, partY2; + int xoff, yoff; + int xorg, yorg; + int n; + RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); + + /* Compute intersection of rects and clip region */ + REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); + REGION_INTERSECT(pScreen, pReg, pClip, pReg); + + if (!REGION_NUM_RECTS(pReg)) { + goto out; + } + + exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); + + if (pExaScr->fallback_counter || pExaScr->swappedOut || + pExaPixmap->accel_blocked) + { + goto fallback; + } + + /* For ROPs where overlaps don't matter, convert rectangles to region and + * call exaFillRegion{Solid,Tiled}. + */ + if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && + (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || + pGC->alu == GXnoop || pGC->alu == GXcopyInverted || + pGC->alu == GXset)) { + if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && + exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? + pGC->fgPixel : pGC->tile.pixel, pGC->planemask, + pGC->alu, pGC->clientClipType)) || + (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && + exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, + pGC->planemask, pGC->alu, + pGC->clientClipType))) { + goto out; + } + } + + if (pGC->fillStyle != FillSolid && + !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) + { + goto fallback; + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = NULL; + + exaDoMigration (pixmaps, 1, TRUE); + } + + if (!exaPixmapHasGpuCopy (pPixmap) || + !(*pExaScr->info->PrepareSolid) (pPixmap, + pGC->alu, + pGC->planemask, + pGC->fgPixel)) + { +fallback: + ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); + goto out; + } + + xorg = pDrawable->x; + yorg = pDrawable->y; + + pextent = REGION_EXTENTS(pGC->pScreen, pClip); + extentX1 = pextent->x1; + extentY1 = pextent->y1; + extentX2 = pextent->x2; + extentY2 = pextent->y2; + while (nrect--) + { + fullX1 = prect->x + xorg; + fullY1 = prect->y + yorg; + fullX2 = fullX1 + (int) prect->width; + fullY2 = fullY1 + (int) prect->height; + prect++; + + if (fullX1 < extentX1) + fullX1 = extentX1; + + if (fullY1 < extentY1) + fullY1 = extentY1; + + if (fullX2 > extentX2) + fullX2 = extentX2; + + if (fullY2 > extentY2) + fullY2 = extentY2; + + if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) + continue; + n = REGION_NUM_RECTS (pClip); + if (n == 1) + { + (*pExaScr->info->Solid) (pPixmap, + fullX1 + xoff, fullY1 + yoff, + fullX2 + xoff, fullY2 + yoff); + } + else + { + pbox = REGION_RECTS(pClip); + /* + * clip the rectangle to each box in the clip region + * this is logically equivalent to calling Intersect(), + * but rectangles may overlap each other here. + */ + while(n--) + { + partX1 = pbox->x1; + if (partX1 < fullX1) + partX1 = fullX1; + partY1 = pbox->y1; + if (partY1 < fullY1) + partY1 = fullY1; + partX2 = pbox->x2; + if (partX2 > fullX2) + partX2 = fullX2; + partY2 = pbox->y2; + if (partY2 > fullY2) + partY2 = fullY2; + + pbox++; + + if (partX1 < partX2 && partY1 < partY2) { + (*pExaScr->info->Solid) (pPixmap, + partX1 + xoff, partY1 + yoff, + partX2 + xoff, partY2 + yoff); + } + } + } + } + (*pExaScr->info->DoneSolid) (pPixmap); + exaMarkSync(pDrawable->pScreen); + +out: + REGION_UNINIT(pScreen, pReg); + REGION_DESTROY(pScreen, pReg); +} + +const GCOps exaOps = { + exaFillSpans, + ExaCheckSetSpans, + exaPutImage, + exaCopyArea, + ExaCheckCopyPlane, + exaPolyPoint, + exaPolylines, + exaPolySegment, + miPolyRectangle, + ExaCheckPolyArc, + miFillPolygon, + exaPolyFillRect, + miPolyFillArc, + miPolyText8, + miPolyText16, + miImageText8, + miImageText16, + ExaCheckImageGlyphBlt, + ExaCheckPolyGlyphBlt, + ExaCheckPushPixels, +}; + +void +exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + RegionRec rgnDst; + int dx, dy; + PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); + ExaScreenPriv(pWin->drawable.pScreen); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); + + REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); + + REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); +#ifdef COMPOSITE + if (pPixmap->screen_x || pPixmap->screen_y) + REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, + -pPixmap->screen_x, -pPixmap->screen_y); +#endif + + if (pExaScr->fallback_counter) { + pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; + goto fallback; + } + + pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW; + miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, + NULL, + &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); + pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW; + +fallback: + REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); + + if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) { + pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW; + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, dx, dy); + ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc); + } +} + +static Bool +exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, + CARD32 planemask, CARD32 alu, unsigned int clientClipType) +{ + ExaScreenPriv(pDrawable->pScreen); + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv (pPixmap); + int xoff, yoff; + Bool ret = FALSE; + + exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); + REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + + if (pExaScr->fallback_counter || pExaPixmap->accel_blocked) + goto out; + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, + alu, clientClipType) ? NULL : pRegion; + + exaDoMigration (pixmaps, 1, TRUE); + } + + if (exaPixmapHasGpuCopy (pPixmap) && + (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) + { + int nbox; + BoxPtr pBox; + + nbox = REGION_NUM_RECTS (pRegion); + pBox = REGION_RECTS (pRegion); + + while (nbox--) + { + (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, + pBox->y2); + pBox++; + } + (*pExaScr->info->DoneSolid) (pPixmap); + exaMarkSync(pDrawable->pScreen); + + if (pExaPixmap->pDamage && + pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP && + pDrawable->width == 1 && pDrawable->height == 1 && + pDrawable->bitsPerPixel != 24) { + ExaPixmapPriv(pPixmap); + RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); + + switch (pDrawable->bitsPerPixel) { + case 32: + *(CARD32*)pExaPixmap->sys_ptr = pixel; + break; + case 16: + *(CARD16*)pExaPixmap->sys_ptr = pixel; + break; + case 8: + *(CARD8*)pExaPixmap->sys_ptr = pixel; + } + + REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, + pRegion); + REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, + pRegion); + REGION_SUBTRACT(pScreen, pending_damage, pending_damage, pRegion); + } + + ret = TRUE; + } + +out: + REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); + + return ret; +} + +/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. + * Based on fbFillRegionTiled(), fbTile(). + */ +Bool +exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, + DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, + unsigned int clientClipType) +{ + ExaScreenPriv(pDrawable->pScreen); + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); + int xoff, yoff; + int tileWidth, tileHeight; + int nbox = REGION_NUM_RECTS (pRegion); + BoxPtr pBox = REGION_RECTS (pRegion); + Bool ret = FALSE; + int i; + + tileWidth = pTile->drawable.width; + tileHeight = pTile->drawable.height; + + /* If we're filling with a solid color, grab it out and go to + * FillRegionSolid, saving numerous copies. + */ + if (tileWidth == 1 && tileHeight == 1) + return exaFillRegionSolid(pDrawable, pRegion, + exaGetPixmapFirstPixel (pTile), planemask, + alu, clientClipType); + + pPixmap = exaGetDrawablePixmap (pDrawable); + pExaPixmap = ExaGetPixmapPriv (pPixmap); + + if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || + pTileExaPixmap->accel_blocked) + return FALSE; + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[2]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, + alu, clientClipType) ? NULL : pRegion; + pixmaps[1].as_dst = FALSE; + pixmaps[1].as_src = TRUE; + pixmaps[1].pPix = pTile; + pixmaps[1].pReg = NULL; + + exaDoMigration (pixmaps, 2, TRUE); + } + + pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + + if (!pPixmap || !exaPixmapHasGpuCopy(pTile)) + return FALSE; + + if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) + { + if (xoff || yoff) + REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + + for (i = 0; i < nbox; i++) + { + int height = pBox[i].y2 - pBox[i].y1; + int dstY = pBox[i].y1; + int tileY; + + if (alu == GXcopy) + height = min(height, tileHeight); + + modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); + + while (height > 0) { + int width = pBox[i].x2 - pBox[i].x1; + int dstX = pBox[i].x1; + int tileX; + int h = tileHeight - tileY; + + if (alu == GXcopy) + width = min(width, tileWidth); + + if (h > height) + h = height; + height -= h; + + modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, + tileX); + + while (width > 0) { + int w = tileWidth - tileX; + if (w > width) + w = width; + width -= w; + + (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, + w, h); + dstX += w; + tileX = 0; + } + dstY += h; + tileY = 0; + } + } + (*pExaScr->info->DoneCopy) (pPixmap); + + /* With GXcopy, we only need to do the basic algorithm up to the tile + * size; then, we can just keep doubling the destination in each + * direction until it fills the box. This way, the number of copy + * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where + * rx/ry is the ratio between box and tile width/height. This can make + * a big difference if each driver copy incurs a significant constant + * overhead. + */ + if (alu != GXcopy) + ret = TRUE; + else { + Bool more_copy = FALSE; + + for (i = 0; i < nbox; i++) { + int dstX = pBox[i].x1 + tileWidth; + int dstY = pBox[i].y1 + tileHeight; + + if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { + more_copy = TRUE; + break; + } + } + + if (more_copy == FALSE) + ret = TRUE; + + if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, + 1, 1, alu, planemask)) { + for (i = 0; i < nbox; i++) + { + int dstX = pBox[i].x1 + tileWidth; + int dstY = pBox[i].y1 + tileHeight; + int width = min(pBox[i].x2 - dstX, tileWidth); + int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); + + while (dstX < pBox[i].x2) { + (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, + dstX, pBox[i].y1, width, height); + dstX += width; + width = min(pBox[i].x2 - dstX, width * 2); + } + + width = pBox[i].x2 - pBox[i].x1; + height = min(pBox[i].y2 - dstY, tileHeight); + + while (dstY < pBox[i].y2) { + (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, + pBox[i].x1, dstY, width, height); + dstY += height; + height = min(pBox[i].y2 - dstY, height * 2); + } + } + + (*pExaScr->info->DoneCopy) (pPixmap); + + ret = TRUE; + } + } + + exaMarkSync(pDrawable->pScreen); + + if (xoff || yoff) + REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); + } + + return ret; +} + + +/** + * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. + * + * This is probably the only case we actually care about. The rest fall through + * to migration and fbGetImage, which hopefully will result in migration pushing + * the pixmap out of framebuffer. + */ +void +exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d) +{ + ExaScreenPriv (pDrawable->pScreen); + PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv(pPix); + int xoff, yoff; + Bool ok; + + if (pExaScr->fallback_counter || pExaScr->swappedOut) + goto fallback; + + /* If there's a system copy, we want to save the result there */ + if (pExaPixmap->pDamage) + goto fallback; + + pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + + if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) + goto fallback; + + /* Only cover the ZPixmap, solid copy case. */ + if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) + goto fallback; + + /* Only try to handle the 8bpp and up cases, since we don't want to think + * about <8bpp. + */ + if (pDrawable->bitsPerPixel < 8) + goto fallback; + + ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, + pDrawable->y + y + yoff, w, h, d, + PixmapBytePad(w, pDrawable->depth)); + if (ok) { + exaWaitSync(pDrawable->pScreen); + return; + } + +fallback: + ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); +} diff --git a/xorg-server/exa/exa_glyphs.c b/xorg-server/exa/exa_glyphs.c index fd14e9b87..36217dc59 100644 --- a/xorg-server/exa/exa_glyphs.c +++ b/xorg-server/exa/exa_glyphs.c @@ -1,867 +1,867 @@ -/* - * Copyright © 2008 Red Hat, Inc. - * Partly based on code Copyright © 2000 SuSE, Inc. - * - * 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 Red Hat not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. Red Hat makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - * - * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat - * 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. - * - * 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 SuSE not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. SuSE makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - * - * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE - * 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. - * - * Author: Owen Taylor - * Based on code by: Keith Packard - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "exa_priv.h" - -#include "mipict.h" - -#if DEBUG_GLYPH_CACHE -#define DBG_GLYPH_CACHE(a) ErrorF a -#else -#define DBG_GLYPH_CACHE(a) -#endif - -/* Width of the pixmaps we use for the caches; this should be less than - * max texture size of the driver; this may need to actually come from - * the driver. - */ -#define CACHE_PICTURE_WIDTH 1024 - -/* Maximum number of glyphs we buffer on the stack before flushing - * rendering to the mask or destination surface. - */ -#define GLYPH_BUFFER_SIZE 256 - -typedef struct { - PicturePtr mask; - ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; - int count; -} ExaGlyphBuffer, *ExaGlyphBufferPtr; - -typedef enum { - ExaGlyphSuccess, /* Glyph added to render buffer */ - ExaGlyphFail, /* out of memory, etc */ - ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */ -} ExaGlyphCacheResult; - -void -exaGlyphsInit(ScreenPtr pScreen) -{ - ExaScreenPriv(pScreen); - int i = 0; - - memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches)); - - pExaScr->glyphCaches[i].format = PICT_a8; - pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; - i++; - pExaScr->glyphCaches[i].format = PICT_a8; - pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; - i++; - pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; - pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; - i++; - pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; - pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; - i++; - - assert(i == EXA_NUM_GLYPH_CACHES); - - for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { - pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth; - pExaScr->glyphCaches[i].size = 256; - pExaScr->glyphCaches[i].hashSize = 557; - } -} - -static void -exaUnrealizeGlyphCaches(ScreenPtr pScreen, - unsigned int format) -{ - ExaScreenPriv(pScreen); - int i; - - for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { - ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; - - if (cache->format != format) - continue; - - if (cache->picture) { - FreePicture ((pointer) cache->picture, (XID) 0); - cache->picture = NULL; - } - - if (cache->hashEntries) { - xfree(cache->hashEntries); - cache->hashEntries = NULL; - } - - if (cache->glyphs) { - xfree(cache->glyphs); - cache->glyphs = NULL; - } - cache->glyphCount = 0; - } -} - -#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) - -/* All caches for a single format share a single pixmap for glyph storage, - * allowing mixing glyphs of different sizes without paying a penalty - * for switching between mask pixmaps. (Note that for a size of font - * right at the border between two sizes, we might be switching for almost - * every glyph.) - * - * This function allocates the storage pixmap, and then fills in the - * rest of the allocated structures for all caches with the given format. - */ -static Bool -exaRealizeGlyphCaches(ScreenPtr pScreen, - unsigned int format) -{ - ExaScreenPriv(pScreen); - - int depth = PIXMAN_FORMAT_DEPTH(format); - PictFormatPtr pPictFormat; - PixmapPtr pPixmap; - PicturePtr pPicture; - CARD32 component_alpha; - int height; - int i; - int error; - - pPictFormat = PictureMatchFormat(pScreen, depth, format); - if (!pPictFormat) - return FALSE; - - /* Compute the total vertical size needed for the format */ - - height = 0; - for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { - ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; - int rows; - - if (cache->format != format) - continue; - - cache->yOffset = height; - - rows = (cache->size + cache->columns - 1) / cache->columns; - height += rows * cache->glyphHeight; - } - - /* Now allocate the pixmap and picture */ - pPixmap = (*pScreen->CreatePixmap) (pScreen, - CACHE_PICTURE_WIDTH, - height, depth, 0); - if (!pPixmap) - return FALSE; - - component_alpha = NeedsComponent(pPictFormat->format); - pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, - CPComponentAlpha, &component_alpha, serverClient, - &error); - - (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ - - if (!pPicture) - return FALSE; - - /* And store the picture in all the caches for the format */ - for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { - ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; - int j; - - if (cache->format != format) - continue; - - cache->picture = pPicture; - cache->picture->refcnt++; - cache->hashEntries = xalloc(sizeof(int) * cache->hashSize); - cache->glyphs = xalloc(sizeof(ExaCachedGlyphRec) * cache->size); - cache->glyphCount = 0; - - if (!cache->hashEntries || !cache->glyphs) - goto bail; - - for (j = 0; j < cache->hashSize; j++) - cache->hashEntries[j] = -1; - - cache->evictionPosition = rand() % cache->size; - } - - /* Each cache references the picture individually */ - FreePicture ((pointer) pPicture, (XID) 0); - return TRUE; - -bail: - exaUnrealizeGlyphCaches(pScreen, format); - return FALSE; -} - -void -exaGlyphsFini (ScreenPtr pScreen) -{ - ExaScreenPriv(pScreen); - int i; - - for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { - ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; - - if (cache->picture) - exaUnrealizeGlyphCaches(pScreen, cache->format); - } -} - -static int -exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, - GlyphPtr pGlyph) -{ - int slot; - - slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; - - while (TRUE) { /* hash table can never be full */ - int entryPos = cache->hashEntries[slot]; - if (entryPos == -1) - return -1; - - if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ - return entryPos; - } - - slot--; - if (slot < 0) - slot = cache->hashSize - 1; - } -} - -static void -exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, - GlyphPtr pGlyph, - int pos) -{ - int slot; - - memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); - - slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; - - while (TRUE) { /* hash table can never be full */ - if (cache->hashEntries[slot] == -1) { - cache->hashEntries[slot] = pos; - return; - } - - slot--; - if (slot < 0) - slot = cache->hashSize - 1; - } -} - -static void -exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, - int pos) -{ - int slot; - int emptiedSlot = -1; - - slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; - - while (TRUE) { /* hash table can never be full */ - int entryPos = cache->hashEntries[slot]; - - if (entryPos == -1) - return; - - if (entryPos == pos) { - cache->hashEntries[slot] = -1; - emptiedSlot = slot; - } else if (emptiedSlot != -1) { - /* See if we can move this entry into the emptied slot, we can't - * do that if if entry would have hashed between the current position - * and the emptied slot. (taking wrapping into account). Bad positions - * are: - * - * | XXXXXXXXXX | - * i j - * - * |XXX XXXX| - * j i - * - * i - slot, j - emptiedSlot - * - * (Knuth 6.4R) - */ - - int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize; - - if (!((entrySlot >= slot && entrySlot < emptiedSlot) || - (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) - { - cache->hashEntries[emptiedSlot] = entryPos; - cache->hashEntries[slot] = -1; - emptiedSlot = slot; - } - } - - slot--; - if (slot < 0) - slot = cache->hashSize - 1; - } -} - -#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) -#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) - -/* The most efficient thing to way to upload the glyph to the screen - * is to use the UploadToScreen() driver hook; this allows us to - * pipeline glyph uploads and to avoid creating gpu backed pixmaps for - * glyphs that we'll never use again. - * - * If we can't do it with UploadToScreen (because the glyph has a gpu copy, - * etc), we fall back to CompositePicture. - * - * We need to damage the cache pixmap manually in either case because the damage - * layer unwrapped the picture screen before calling exaGlyphs. - */ -static void -exaGlyphCacheUploadGlyph(ScreenPtr pScreen, - ExaGlyphCachePtr cache, - int x, - int y, - GlyphPtr pGlyph) -{ - ExaScreenPriv(pScreen); - PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; - PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable; - ExaPixmapPriv(pGlyphPixmap); - PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; - - if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked) - goto composite; - - /* If the glyph pixmap is already uploaded, no point in doing - * things this way */ - if (exaPixmapHasGpuCopy(pGlyphPixmap)) - goto composite; - - /* UploadToScreen only works if bpp match */ - if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel) - goto composite; - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[1]; - - /* cache pixmap must have a gpu copy. */ - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pCachePixmap; - pixmaps[0].pReg = NULL; - exaDoMigration (pixmaps, 1, TRUE); - } - - if (!exaPixmapHasGpuCopy(pCachePixmap)) - goto composite; - - /* x,y are in pixmap coordinates, no need for cache{X,Y}off */ - if (pExaScr->info->UploadToScreen(pCachePixmap, - x, - y, - pGlyph->info.width, - pGlyph->info.height, - (char *)pExaPixmap->sys_ptr, - pExaPixmap->sys_pitch)) - goto damage; - -composite: - CompositePicture (PictOpSrc, - pGlyphPicture, - None, - cache->picture, - 0, 0, - 0, 0, - x, - y, - pGlyph->info.width, - pGlyph->info.height); - -damage: - /* The cache pixmap isn't a window, so no need to offset coordinates. */ - exaPixmapDirty (pCachePixmap, - x, - y, - x + cache->glyphWidth, - y + cache->glyphHeight); -} - -static ExaGlyphCacheResult -exaGlyphCacheBufferGlyph(ScreenPtr pScreen, - ExaGlyphCachePtr cache, - ExaGlyphBufferPtr buffer, - GlyphPtr pGlyph, - PicturePtr pSrc, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst) -{ - ExaCompositeRectPtr rect; - int pos; - int x, y; - - if (buffer->mask && buffer->mask != cache->picture) - return ExaGlyphNeedFlush; - - if (!cache->picture) { - if (!exaRealizeGlyphCaches(pScreen, cache->format)) - return ExaGlyphFail; - } - - DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", - cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB", - (long)*(CARD32 *) pGlyph->sha1)); - - pos = exaGlyphCacheHashLookup(cache, pGlyph); - if (pos != -1) { - DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); - x = CACHE_X(pos); - y = CACHE_Y(pos); - } else { - if (cache->glyphCount < cache->size) { - /* Space remaining; we fill from the start */ - pos = cache->glyphCount; - x = CACHE_X(pos); - y = CACHE_Y(pos); - cache->glyphCount++; - DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); - - exaGlyphCacheHashInsert(cache, pGlyph, pos); - - } else { - /* Need to evict an entry. We have to see if any glyphs - * already in the output buffer were at this position in - * the cache - */ - pos = cache->evictionPosition; - x = CACHE_X(pos); - y = CACHE_Y(pos); - DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); - if (buffer->count) { - int i; - - for (i = 0; i < buffer->count; i++) { - if (pSrc ? - (buffer->rects[i].xMask == x && buffer->rects[i].yMask == y) : - (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y)) { - DBG_GLYPH_CACHE((" must flush buffer\n")); - return ExaGlyphNeedFlush; - } - } - } - - /* OK, we're all set, swap in the new glyph */ - exaGlyphCacheHashRemove(cache, pos); - exaGlyphCacheHashInsert(cache, pGlyph, pos); - - /* And pick a new eviction position */ - cache->evictionPosition = rand() % cache->size; - } - - exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph); - } - - buffer->mask = cache->picture; - - rect = &buffer->rects[buffer->count]; - - if (pSrc) - { - rect->xSrc = xSrc; - rect->ySrc = ySrc; - rect->xMask = x; - rect->yMask = y; - } - else - { - rect->xSrc = x; - rect->ySrc = y; - rect->xMask = 0; - rect->yMask = 0; - } - - rect->pDst = pDst; - rect->xDst = xDst; - rect->yDst = yDst; - rect->width = pGlyph->info.width; - rect->height = pGlyph->info.height; - - buffer->count++; - - return ExaGlyphSuccess; -} - -#undef CACHE_X -#undef CACHE_Y - -static ExaGlyphCacheResult -exaBufferGlyph(ScreenPtr pScreen, - ExaGlyphBufferPtr buffer, - GlyphPtr pGlyph, - PicturePtr pSrc, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst) -{ - ExaScreenPriv(pScreen); - unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; - int width = pGlyph->info.width; - int height = pGlyph->info.height; - ExaCompositeRectPtr rect; - PicturePtr mask; - int i; - - if (buffer->count == GLYPH_BUFFER_SIZE) - return ExaGlyphNeedFlush; - - if (PICT_FORMAT_BPP(format) == 1) - format = PICT_a8; - - for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { - ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; - - if (format == cache->format && - width <= cache->glyphWidth && - height <= cache->glyphHeight) { - ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, - &pExaScr->glyphCaches[i], - buffer, - pGlyph, - pSrc, - pDst, - xSrc, ySrc, - xMask, yMask, - xDst, yDst); - switch (result) { - case ExaGlyphFail: - break; - case ExaGlyphSuccess: - case ExaGlyphNeedFlush: - return result; - } - } - } - - /* Couldn't find the glyph in the cache, use the glyph picture directly */ - - mask = GlyphPicture(pGlyph)[pScreen->myNum]; - if (buffer->mask && buffer->mask != mask) - return ExaGlyphNeedFlush; - - buffer->mask = mask; - - rect = &buffer->rects[buffer->count]; - rect->xSrc = xSrc; - rect->ySrc = ySrc; - rect->xMask = xMask; - rect->yMask = yMask; - rect->xDst = xDst; - rect->yDst = yDst; - rect->width = width; - rect->height = height; - - buffer->count++; - - return ExaGlyphSuccess; -} - -static void -exaGlyphsToMask(PicturePtr pMask, - ExaGlyphBufferPtr buffer) -{ - exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask, - buffer->count, buffer->rects); - - buffer->count = 0; - buffer->mask = NULL; -} - -static void -exaGlyphsToDst(PicturePtr pSrc, - PicturePtr pDst, - ExaGlyphBufferPtr buffer) -{ - exaCompositeRects(PictOpOver, pSrc, buffer->mask, pDst, buffer->count, - buffer->rects); - - buffer->count = 0; - buffer->mask = NULL; -} - -/* Cut and paste from render/glyph.c - probably should export it instead */ -static void -GlyphExtents (int nlist, - GlyphListPtr list, - GlyphPtr *glyphs, - BoxPtr extents) -{ - int x1, x2, y1, y2; - int n; - GlyphPtr glyph; - int x, y; - - x = 0; - y = 0; - extents->x1 = MAXSHORT; - extents->x2 = MINSHORT; - extents->y1 = MAXSHORT; - extents->y2 = MINSHORT; - while (nlist--) - { - x += list->xOff; - y += list->yOff; - n = list->len; - list++; - while (n--) - { - glyph = *glyphs++; - x1 = x - glyph->info.x; - if (x1 < MINSHORT) - x1 = MINSHORT; - y1 = y - glyph->info.y; - if (y1 < MINSHORT) - y1 = MINSHORT; - x2 = x1 + glyph->info.width; - if (x2 > MAXSHORT) - x2 = MAXSHORT; - y2 = y1 + glyph->info.height; - if (y2 > MAXSHORT) - y2 = MAXSHORT; - if (x1 < extents->x1) - extents->x1 = x1; - if (x2 > extents->x2) - extents->x2 = x2; - if (y1 < extents->y1) - extents->y1 = y1; - if (y2 > extents->y2) - extents->y2 = y2; - x += glyph->info.xOff; - y += glyph->info.yOff; - } - } -} - -void -exaGlyphs (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int nlist, - GlyphListPtr list, - GlyphPtr *glyphs) -{ - PixmapPtr pMaskPixmap = 0; - PicturePtr pMask = NULL; - ScreenPtr pScreen = pDst->pDrawable->pScreen; - int width = 0, height = 0; - int x, y; - int first_xOff = list->xOff, first_yOff = list->yOff; - int n; - GlyphPtr glyph; - int error; - BoxRec extents = {0, 0, 0, 0}; - CARD32 component_alpha; - ExaGlyphBuffer buffer; - - if (maskFormat) - { - ExaScreenPriv(pScreen); - GCPtr pGC; - xRectangle rect; - - GlyphExtents (nlist, list, glyphs, &extents); - - if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) - return; - width = extents.x2 - extents.x1; - height = extents.y2 - extents.y1; - - if (maskFormat->depth == 1) { - PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8); - - if (a8Format) - maskFormat = a8Format; - } - - pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, - maskFormat->depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pMaskPixmap) - return; - component_alpha = NeedsComponent(maskFormat->format); - pMask = CreatePicture (0, &pMaskPixmap->drawable, - maskFormat, CPComponentAlpha, &component_alpha, - serverClient, &error); - if (!pMask || - (!component_alpha && pExaScr->info->CheckComposite && - !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask))) - { - PictFormatPtr argbFormat; - - (*pScreen->DestroyPixmap) (pMaskPixmap); - - if (!pMask) - return; - - /* The driver can't seem to composite to a8, let's try argb (but - * without component-alpha) */ - FreePicture ((pointer) pMask, (XID) 0); - - argbFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); - - if (argbFormat) - maskFormat = argbFormat; - - pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, - maskFormat->depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pMaskPixmap) - return; - - pMask = CreatePicture (0, &pMaskPixmap->drawable, maskFormat, 0, 0, - serverClient, &error); - if (!pMask) { - (*pScreen->DestroyPixmap) (pMaskPixmap); - return; - } - } - pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); - ValidateGC (&pMaskPixmap->drawable, pGC); - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); - FreeScratchGC (pGC); - x = -extents.x1; - y = -extents.y1; - } - else - { - x = 0; - y = 0; - } - buffer.count = 0; - buffer.mask = NULL; - while (nlist--) - { - x += list->xOff; - y += list->yOff; - n = list->len; - while (n--) - { - glyph = *glyphs++; - - if (glyph->info.width > 0 && glyph->info.height > 0) - { - /* pGlyph->info.{x,y} compensate for empty space in the glyph. */ - if (maskFormat) - { - if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, - 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush) - { - exaGlyphsToMask(pMask, &buffer); - exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, - 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y); - } - } - else - { - if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, - xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, - 0, 0, x - glyph->info.x, y - glyph->info.y) - == ExaGlyphNeedFlush) - { - exaGlyphsToDst(pSrc, pDst, &buffer); - exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, - xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, - 0, 0, x - glyph->info.x, y - glyph->info.y); - } - } - } - - x += glyph->info.xOff; - y += glyph->info.yOff; - } - list++; - } - - if (buffer.count) { - if (maskFormat) - exaGlyphsToMask(pMask, &buffer); - else - exaGlyphsToDst(pSrc, pDst, &buffer); - } - - if (maskFormat) - { - x = extents.x1; - y = extents.y1; - CompositePicture (op, - pSrc, - pMask, - pDst, - xSrc + x - first_xOff, - ySrc + y - first_yOff, - 0, 0, - x, y, - width, height); - FreePicture ((pointer) pMask, (XID) 0); - (*pScreen->DestroyPixmap) (pMaskPixmap); - } -} +/* + * Copyright © 2008 Red Hat, Inc. + * Partly based on code Copyright © 2000 SuSE, Inc. + * + * 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 Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat + * 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. + * + * 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 SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * 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. + * + * Author: Owen Taylor + * Based on code by: Keith Packard + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "exa_priv.h" + +#include "mipict.h" + +#if DEBUG_GLYPH_CACHE +#define DBG_GLYPH_CACHE(a) ErrorF a +#else +#define DBG_GLYPH_CACHE(a) +#endif + +/* Width of the pixmaps we use for the caches; this should be less than + * max texture size of the driver; this may need to actually come from + * the driver. + */ +#define CACHE_PICTURE_WIDTH 1024 + +/* Maximum number of glyphs we buffer on the stack before flushing + * rendering to the mask or destination surface. + */ +#define GLYPH_BUFFER_SIZE 256 + +typedef struct { + PicturePtr mask; + ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; + int count; +} ExaGlyphBuffer, *ExaGlyphBufferPtr; + +typedef enum { + ExaGlyphSuccess, /* Glyph added to render buffer */ + ExaGlyphFail, /* out of memory, etc */ + ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */ +} ExaGlyphCacheResult; + +void +exaGlyphsInit(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + int i = 0; + + memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches)); + + pExaScr->glyphCaches[i].format = PICT_a8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; + i++; + pExaScr->glyphCaches[i].format = PICT_a8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; + i++; + pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; + i++; + pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; + i++; + + assert(i == EXA_NUM_GLYPH_CACHES); + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth; + pExaScr->glyphCaches[i].size = 256; + pExaScr->glyphCaches[i].hashSize = 557; + } +} + +static void +exaUnrealizeGlyphCaches(ScreenPtr pScreen, + unsigned int format) +{ + ExaScreenPriv(pScreen); + int i; + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + + if (cache->format != format) + continue; + + if (cache->picture) { + FreePicture ((pointer) cache->picture, (XID) 0); + cache->picture = NULL; + } + + if (cache->hashEntries) { + free(cache->hashEntries); + cache->hashEntries = NULL; + } + + if (cache->glyphs) { + free(cache->glyphs); + cache->glyphs = NULL; + } + cache->glyphCount = 0; + } +} + +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) + +/* All caches for a single format share a single pixmap for glyph storage, + * allowing mixing glyphs of different sizes without paying a penalty + * for switching between mask pixmaps. (Note that for a size of font + * right at the border between two sizes, we might be switching for almost + * every glyph.) + * + * This function allocates the storage pixmap, and then fills in the + * rest of the allocated structures for all caches with the given format. + */ +static Bool +exaRealizeGlyphCaches(ScreenPtr pScreen, + unsigned int format) +{ + ExaScreenPriv(pScreen); + + int depth = PIXMAN_FORMAT_DEPTH(format); + PictFormatPtr pPictFormat; + PixmapPtr pPixmap; + PicturePtr pPicture; + CARD32 component_alpha; + int height; + int i; + int error; + + pPictFormat = PictureMatchFormat(pScreen, depth, format); + if (!pPictFormat) + return FALSE; + + /* Compute the total vertical size needed for the format */ + + height = 0; + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + int rows; + + if (cache->format != format) + continue; + + cache->yOffset = height; + + rows = (cache->size + cache->columns - 1) / cache->columns; + height += rows * cache->glyphHeight; + } + + /* Now allocate the pixmap and picture */ + pPixmap = (*pScreen->CreatePixmap) (pScreen, + CACHE_PICTURE_WIDTH, + height, depth, 0); + if (!pPixmap) + return FALSE; + + component_alpha = NeedsComponent(pPictFormat->format); + pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, + CPComponentAlpha, &component_alpha, serverClient, + &error); + + (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ + + if (!pPicture) + return FALSE; + + /* And store the picture in all the caches for the format */ + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + int j; + + if (cache->format != format) + continue; + + cache->picture = pPicture; + cache->picture->refcnt++; + cache->hashEntries = malloc(sizeof(int) * cache->hashSize); + cache->glyphs = malloc(sizeof(ExaCachedGlyphRec) * cache->size); + cache->glyphCount = 0; + + if (!cache->hashEntries || !cache->glyphs) + goto bail; + + for (j = 0; j < cache->hashSize; j++) + cache->hashEntries[j] = -1; + + cache->evictionPosition = rand() % cache->size; + } + + /* Each cache references the picture individually */ + FreePicture ((pointer) pPicture, (XID) 0); + return TRUE; + +bail: + exaUnrealizeGlyphCaches(pScreen, format); + return FALSE; +} + +void +exaGlyphsFini (ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + int i; + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + + if (cache->picture) + exaUnrealizeGlyphCaches(pScreen, cache->format); + } +} + +static int +exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, + GlyphPtr pGlyph) +{ + int slot; + + slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + int entryPos = cache->hashEntries[slot]; + if (entryPos == -1) + return -1; + + if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ + return entryPos; + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +static void +exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, + GlyphPtr pGlyph, + int pos) +{ + int slot; + + memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); + + slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + if (cache->hashEntries[slot] == -1) { + cache->hashEntries[slot] = pos; + return; + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +static void +exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, + int pos) +{ + int slot; + int emptiedSlot = -1; + + slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + int entryPos = cache->hashEntries[slot]; + + if (entryPos == -1) + return; + + if (entryPos == pos) { + cache->hashEntries[slot] = -1; + emptiedSlot = slot; + } else if (emptiedSlot != -1) { + /* See if we can move this entry into the emptied slot, we can't + * do that if if entry would have hashed between the current position + * and the emptied slot. (taking wrapping into account). Bad positions + * are: + * + * | XXXXXXXXXX | + * i j + * + * |XXX XXXX| + * j i + * + * i - slot, j - emptiedSlot + * + * (Knuth 6.4R) + */ + + int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize; + + if (!((entrySlot >= slot && entrySlot < emptiedSlot) || + (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) + { + cache->hashEntries[emptiedSlot] = entryPos; + cache->hashEntries[slot] = -1; + emptiedSlot = slot; + } + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) +#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) + +/* The most efficient thing to way to upload the glyph to the screen + * is to use the UploadToScreen() driver hook; this allows us to + * pipeline glyph uploads and to avoid creating gpu backed pixmaps for + * glyphs that we'll never use again. + * + * If we can't do it with UploadToScreen (because the glyph has a gpu copy, + * etc), we fall back to CompositePicture. + * + * We need to damage the cache pixmap manually in either case because the damage + * layer unwrapped the picture screen before calling exaGlyphs. + */ +static void +exaGlyphCacheUploadGlyph(ScreenPtr pScreen, + ExaGlyphCachePtr cache, + int x, + int y, + GlyphPtr pGlyph) +{ + ExaScreenPriv(pScreen); + PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; + PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable; + ExaPixmapPriv(pGlyphPixmap); + PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; + + if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked) + goto composite; + + /* If the glyph pixmap is already uploaded, no point in doing + * things this way */ + if (exaPixmapHasGpuCopy(pGlyphPixmap)) + goto composite; + + /* UploadToScreen only works if bpp match */ + if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel) + goto composite; + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + /* cache pixmap must have a gpu copy. */ + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pCachePixmap; + pixmaps[0].pReg = NULL; + exaDoMigration (pixmaps, 1, TRUE); + } + + if (!exaPixmapHasGpuCopy(pCachePixmap)) + goto composite; + + /* x,y are in pixmap coordinates, no need for cache{X,Y}off */ + if (pExaScr->info->UploadToScreen(pCachePixmap, + x, + y, + pGlyph->info.width, + pGlyph->info.height, + (char *)pExaPixmap->sys_ptr, + pExaPixmap->sys_pitch)) + goto damage; + +composite: + CompositePicture (PictOpSrc, + pGlyphPicture, + None, + cache->picture, + 0, 0, + 0, 0, + x, + y, + pGlyph->info.width, + pGlyph->info.height); + +damage: + /* The cache pixmap isn't a window, so no need to offset coordinates. */ + exaPixmapDirty (pCachePixmap, + x, + y, + x + cache->glyphWidth, + y + cache->glyphHeight); +} + +static ExaGlyphCacheResult +exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + ExaGlyphCachePtr cache, + ExaGlyphBufferPtr buffer, + GlyphPtr pGlyph, + PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst) +{ + ExaCompositeRectPtr rect; + int pos; + int x, y; + + if (buffer->mask && buffer->mask != cache->picture) + return ExaGlyphNeedFlush; + + if (!cache->picture) { + if (!exaRealizeGlyphCaches(pScreen, cache->format)) + return ExaGlyphFail; + } + + DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", + cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB", + (long)*(CARD32 *) pGlyph->sha1)); + + pos = exaGlyphCacheHashLookup(cache, pGlyph); + if (pos != -1) { + DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); + x = CACHE_X(pos); + y = CACHE_Y(pos); + } else { + if (cache->glyphCount < cache->size) { + /* Space remaining; we fill from the start */ + pos = cache->glyphCount; + x = CACHE_X(pos); + y = CACHE_Y(pos); + cache->glyphCount++; + DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); + + exaGlyphCacheHashInsert(cache, pGlyph, pos); + + } else { + /* Need to evict an entry. We have to see if any glyphs + * already in the output buffer were at this position in + * the cache + */ + pos = cache->evictionPosition; + x = CACHE_X(pos); + y = CACHE_Y(pos); + DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); + if (buffer->count) { + int i; + + for (i = 0; i < buffer->count; i++) { + if (pSrc ? + (buffer->rects[i].xMask == x && buffer->rects[i].yMask == y) : + (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y)) { + DBG_GLYPH_CACHE((" must flush buffer\n")); + return ExaGlyphNeedFlush; + } + } + } + + /* OK, we're all set, swap in the new glyph */ + exaGlyphCacheHashRemove(cache, pos); + exaGlyphCacheHashInsert(cache, pGlyph, pos); + + /* And pick a new eviction position */ + cache->evictionPosition = rand() % cache->size; + } + + exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph); + } + + buffer->mask = cache->picture; + + rect = &buffer->rects[buffer->count]; + + if (pSrc) + { + rect->xSrc = xSrc; + rect->ySrc = ySrc; + rect->xMask = x; + rect->yMask = y; + } + else + { + rect->xSrc = x; + rect->ySrc = y; + rect->xMask = 0; + rect->yMask = 0; + } + + rect->pDst = pDst; + rect->xDst = xDst; + rect->yDst = yDst; + rect->width = pGlyph->info.width; + rect->height = pGlyph->info.height; + + buffer->count++; + + return ExaGlyphSuccess; +} + +#undef CACHE_X +#undef CACHE_Y + +static ExaGlyphCacheResult +exaBufferGlyph(ScreenPtr pScreen, + ExaGlyphBufferPtr buffer, + GlyphPtr pGlyph, + PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst) +{ + ExaScreenPriv(pScreen); + unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; + int width = pGlyph->info.width; + int height = pGlyph->info.height; + ExaCompositeRectPtr rect; + PicturePtr mask; + int i; + + if (buffer->count == GLYPH_BUFFER_SIZE) + return ExaGlyphNeedFlush; + + if (PICT_FORMAT_BPP(format) == 1) + format = PICT_a8; + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + + if (format == cache->format && + width <= cache->glyphWidth && + height <= cache->glyphHeight) { + ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, + &pExaScr->glyphCaches[i], + buffer, + pGlyph, + pSrc, + pDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst); + switch (result) { + case ExaGlyphFail: + break; + case ExaGlyphSuccess: + case ExaGlyphNeedFlush: + return result; + } + } + } + + /* Couldn't find the glyph in the cache, use the glyph picture directly */ + + mask = GlyphPicture(pGlyph)[pScreen->myNum]; + if (buffer->mask && buffer->mask != mask) + return ExaGlyphNeedFlush; + + buffer->mask = mask; + + rect = &buffer->rects[buffer->count]; + rect->xSrc = xSrc; + rect->ySrc = ySrc; + rect->xMask = xMask; + rect->yMask = yMask; + rect->xDst = xDst; + rect->yDst = yDst; + rect->width = width; + rect->height = height; + + buffer->count++; + + return ExaGlyphSuccess; +} + +static void +exaGlyphsToMask(PicturePtr pMask, + ExaGlyphBufferPtr buffer) +{ + exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask, + buffer->count, buffer->rects); + + buffer->count = 0; + buffer->mask = NULL; +} + +static void +exaGlyphsToDst(PicturePtr pSrc, + PicturePtr pDst, + ExaGlyphBufferPtr buffer) +{ + exaCompositeRects(PictOpOver, pSrc, buffer->mask, pDst, buffer->count, + buffer->rects); + + buffer->count = 0; + buffer->mask = NULL; +} + +/* Cut and paste from render/glyph.c - probably should export it instead */ +static void +GlyphExtents (int nlist, + GlyphListPtr list, + GlyphPtr *glyphs, + BoxPtr extents) +{ + int x1, x2, y1, y2; + int n; + GlyphPtr glyph; + int x, y; + + x = 0; + y = 0; + extents->x1 = MAXSHORT; + extents->x2 = MINSHORT; + extents->y1 = MAXSHORT; + extents->y2 = MINSHORT; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) + { + glyph = *glyphs++; + x1 = x - glyph->info.x; + if (x1 < MINSHORT) + x1 = MINSHORT; + y1 = y - glyph->info.y; + if (y1 < MINSHORT) + y1 = MINSHORT; + x2 = x1 + glyph->info.width; + if (x2 > MAXSHORT) + x2 = MAXSHORT; + y2 = y1 + glyph->info.height; + if (y2 > MAXSHORT) + y2 = MAXSHORT; + if (x1 < extents->x1) + extents->x1 = x1; + if (x2 > extents->x2) + extents->x2 = x2; + if (y1 < extents->y1) + extents->y1 = y1; + if (y2 > extents->y2) + extents->y2 = y2; + x += glyph->info.xOff; + y += glyph->info.yOff; + } + } +} + +void +exaGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ + PixmapPtr pMaskPixmap = 0; + PicturePtr pMask = NULL; + ScreenPtr pScreen = pDst->pDrawable->pScreen; + int width = 0, height = 0; + int x, y; + int first_xOff = list->xOff, first_yOff = list->yOff; + int n; + GlyphPtr glyph; + int error; + BoxRec extents = {0, 0, 0, 0}; + CARD32 component_alpha; + ExaGlyphBuffer buffer; + + if (maskFormat) + { + ExaScreenPriv(pScreen); + GCPtr pGC; + xRectangle rect; + + GlyphExtents (nlist, list, glyphs, &extents); + + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + + if (maskFormat->depth == 1) { + PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8); + + if (a8Format) + maskFormat = a8Format; + } + + pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pMaskPixmap) + return; + component_alpha = NeedsComponent(maskFormat->format); + pMask = CreatePicture (0, &pMaskPixmap->drawable, + maskFormat, CPComponentAlpha, &component_alpha, + serverClient, &error); + if (!pMask || + (!component_alpha && pExaScr->info->CheckComposite && + !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask))) + { + PictFormatPtr argbFormat; + + (*pScreen->DestroyPixmap) (pMaskPixmap); + + if (!pMask) + return; + + /* The driver can't seem to composite to a8, let's try argb (but + * without component-alpha) */ + FreePicture ((pointer) pMask, (XID) 0); + + argbFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); + + if (argbFormat) + maskFormat = argbFormat; + + pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pMaskPixmap) + return; + + pMask = CreatePicture (0, &pMaskPixmap->drawable, maskFormat, 0, 0, + serverClient, &error); + if (!pMask) { + (*pScreen->DestroyPixmap) (pMaskPixmap); + return; + } + } + pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); + ValidateGC (&pMaskPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); + FreeScratchGC (pGC); + x = -extents.x1; + y = -extents.y1; + } + else + { + x = 0; + y = 0; + } + buffer.count = 0; + buffer.mask = NULL; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) + { + glyph = *glyphs++; + + if (glyph->info.width > 0 && glyph->info.height > 0) + { + /* pGlyph->info.{x,y} compensate for empty space in the glyph. */ + if (maskFormat) + { + if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, + 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush) + { + exaGlyphsToMask(pMask, &buffer); + exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, + 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y); + } + } + else + { + if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, + xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, + 0, 0, x - glyph->info.x, y - glyph->info.y) + == ExaGlyphNeedFlush) + { + exaGlyphsToDst(pSrc, pDst, &buffer); + exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, + xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, + 0, 0, x - glyph->info.x, y - glyph->info.y); + } + } + } + + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + + if (buffer.count) { + if (maskFormat) + exaGlyphsToMask(pMask, &buffer); + else + exaGlyphsToDst(pSrc, pDst, &buffer); + } + + if (maskFormat) + { + x = extents.x1; + y = extents.y1; + CompositePicture (op, + pSrc, + pMask, + pDst, + xSrc + x - first_xOff, + ySrc + y - first_yOff, + 0, 0, + x, y, + width, height); + FreePicture ((pointer) pMask, (XID) 0); + (*pScreen->DestroyPixmap) (pMaskPixmap); + } +} diff --git a/xorg-server/exa/exa_offscreen.c b/xorg-server/exa/exa_offscreen.c index e3a9ab2f6..506da616d 100644 --- a/xorg-server/exa/exa_offscreen.c +++ b/xorg-server/exa/exa_offscreen.c @@ -1,696 +1,696 @@ -/* - * Copyright © 2003 Anders Carlsson - * - * 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 Anders Carlsson not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Anders Carlsson makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL ANDERS CARLSSON 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. - */ - -/** @file - * This allocator allocates blocks of memory by maintaining a list of areas. - * When allocating, the contiguous block of areas with the minimum eviction - * cost is found and evicted in order to make room for the new allocation. - */ - -#include "exa_priv.h" - -#include -#include -#include - -#if DEBUG_OFFSCREEN -#define DBG_OFFSCREEN(a) ErrorF a -#else -#define DBG_OFFSCREEN(a) -#endif - -#if DEBUG_OFFSCREEN -static void -ExaOffscreenValidate (ScreenPtr pScreen) -{ - ExaScreenPriv (pScreen); - ExaOffscreenArea *prev = 0, *area; - - assert (pExaScr->info->offScreenAreas->base_offset == - pExaScr->info->offScreenBase); - for (area = pExaScr->info->offScreenAreas; area; area = area->next) - { - assert (area->offset >= area->base_offset && - area->offset < (area->base_offset + area->size)); - if (prev) - assert (prev->base_offset + prev->size == area->base_offset); - prev = area; - } - assert (prev->base_offset + prev->size == pExaScr->info->memorySize); -} -#else -#define ExaOffscreenValidate(s) -#endif - -static ExaOffscreenArea * -ExaOffscreenKickOut (ScreenPtr pScreen, ExaOffscreenArea *area) -{ - if (area->save) - (*area->save) (pScreen, area); - return exaOffscreenFree (pScreen, area); -} - -static void -exaUpdateEvictionCost(ExaOffscreenArea *area, unsigned offScreenCounter) -{ - unsigned age; - - if (area->state == ExaOffscreenAvail) - return; - - age = offScreenCounter - area->last_use; - - /* This is unlikely to happen, but could result in a division by zero... */ - if (age > (UINT_MAX / 2)) { - age = UINT_MAX / 2; - area->last_use = offScreenCounter - age; - } - - area->eviction_cost = area->size / age; -} - -static ExaOffscreenArea * -exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align) -{ - ExaOffscreenArea *begin, *end, *best; - unsigned cost, best_cost; - int avail, real_size; - - best_cost = UINT_MAX; - begin = end = pExaScr->info->offScreenAreas; - avail = 0; - cost = 0; - best = 0; - - while (end != NULL) - { - restart: - while (begin != NULL && begin->state == ExaOffscreenLocked) - begin = end = begin->next; - - if (begin == NULL) - break; - - /* adjust size needed to account for alignment loss for this area */ - real_size = size + (begin->base_offset + begin->size - size) % align; - - while (avail < real_size && end != NULL) - { - if (end->state == ExaOffscreenLocked) { - /* Can't more room here, restart after this locked area */ - avail = 0; - cost = 0; - begin = end; - goto restart; - } - avail += end->size; - exaUpdateEvictionCost(end, pExaScr->offScreenCounter); - cost += end->eviction_cost; - end = end->next; - } - - /* Check the cost, update best */ - if (avail >= real_size && cost < best_cost) { - best = begin; - best_cost = cost; - } - - avail -= begin->size; - cost -= begin->eviction_cost; - begin = begin->next; - } - - return best; -} - -/** - * exaOffscreenAlloc allocates offscreen memory - * - * @param pScreen current screen - * @param size size in bytes of the allocation - * @param align byte alignment requirement for the offset of the allocated area - * @param locked whether the allocated area is locked and can't be kicked out - * @param save callback for when the area is evicted from memory - * @param privdata private data for the save callback. - * - * Allocates offscreen memory from the device associated with pScreen. size - * and align deteremine where and how large the allocated area is, and locked - * will mark whether it should be held in card memory. privdata may be any - * pointer for the save callback when the area is removed. - * - * Note that locked areas do get evicted on VT switch unless the driver - * requested version 2.1 or newer behavior. In that case, the save callback is - * still called. - */ -ExaOffscreenArea * -exaOffscreenAlloc (ScreenPtr pScreen, int size, int align, - Bool locked, - ExaOffscreenSaveProc save, - pointer privData) -{ - ExaOffscreenArea *area; - ExaScreenPriv (pScreen); - int real_size = 0, largest_avail = 0; -#if DEBUG_OFFSCREEN - static int number = 0; - ErrorF("================= ============ allocating a new pixmap %d\n", ++number); -#endif - - ExaOffscreenValidate (pScreen); - if (!align) - align = 1; - - if (!size) - { - DBG_OFFSCREEN (("Alloc 0x%x -> EMPTY\n", size)); - return NULL; - } - - /* throw out requests that cannot fit */ - if (size > (pExaScr->info->memorySize - pExaScr->info->offScreenBase)) - { - DBG_OFFSCREEN (("Alloc 0x%x vs (0x%lx) -> TOBIG\n", size, - pExaScr->info->memorySize - - pExaScr->info->offScreenBase)); - return NULL; - } - - /* Try to find a free space that'll fit. */ - for (area = pExaScr->info->offScreenAreas; area; area = area->next) - { - /* skip allocated areas */ - if (area->state != ExaOffscreenAvail) - continue; - - /* adjust size to match alignment requirement */ - real_size = size + (area->base_offset + area->size - size) % align; - - /* does it fit? */ - if (real_size <= area->size) - break; - - if (area->size > largest_avail) - largest_avail = area->size; - } - - if (!area) - { - area = exaFindAreaToEvict(pExaScr, size, align); - - if (!area) - { - DBG_OFFSCREEN (("Alloc 0x%x -> NOSPACE\n", size)); - /* Could not allocate memory */ - ExaOffscreenValidate (pScreen); - return NULL; - } - - /* adjust size needed to account for alignment loss for this area */ - real_size = size + (area->base_offset + area->size - size) % align; - - /* - * Kick out first area if in use - */ - if (area->state != ExaOffscreenAvail) - area = ExaOffscreenKickOut (pScreen, area); - /* - * Now get the system to merge the other needed areas together - */ - while (area->size < real_size) - { - assert (area->next && area->next->state == ExaOffscreenRemovable); - (void) ExaOffscreenKickOut (pScreen, area->next); - } - } - - /* save extra space in new area */ - if (real_size < area->size) - { - ExaOffscreenArea *new_area = xalloc (sizeof (ExaOffscreenArea)); - if (!new_area) - return NULL; - new_area->base_offset = area->base_offset; - - new_area->offset = new_area->base_offset; - new_area->align = 0; - new_area->size = area->size - real_size; - new_area->state = ExaOffscreenAvail; - new_area->save = NULL; - new_area->last_use = 0; - new_area->eviction_cost = 0; - new_area->next = area; - new_area->prev = area->prev; - if (area->prev->next) - area->prev->next = new_area; - else - pExaScr->info->offScreenAreas = new_area; - area->prev = new_area; - area->base_offset = new_area->base_offset + new_area->size; - area->size = real_size; - } else - pExaScr->numOffscreenAvailable--; - - /* - * Mark this area as in use - */ - if (locked) - area->state = ExaOffscreenLocked; - else - area->state = ExaOffscreenRemovable; - area->privData = privData; - area->save = save; - area->last_use = pExaScr->offScreenCounter++; - area->offset = (area->base_offset + align - 1); - area->offset -= area->offset % align; - area->align = align; - - ExaOffscreenValidate (pScreen); - - DBG_OFFSCREEN (("Alloc 0x%x -> 0x%x (0x%x)\n", size, - area->base_offset, area->offset)); - return area; -} - -/** - * Ejects all offscreen areas, and uninitializes the offscreen memory manager. - */ -void -ExaOffscreenSwapOut (ScreenPtr pScreen) -{ - ExaScreenPriv (pScreen); - - ExaOffscreenValidate (pScreen); - /* loop until a single free area spans the space */ - for (;;) - { - ExaOffscreenArea *area = pExaScr->info->offScreenAreas; - - if (!area) - break; - if (area->state == ExaOffscreenAvail) - { - area = area->next; - if (!area) - break; - } - assert (area->state != ExaOffscreenAvail); - (void) ExaOffscreenKickOut (pScreen, area); - ExaOffscreenValidate (pScreen); - } - ExaOffscreenValidate (pScreen); - ExaOffscreenFini (pScreen); -} - -/** Ejects all pixmaps managed by EXA. */ -static void -ExaOffscreenEjectPixmaps (ScreenPtr pScreen) -{ - ExaScreenPriv (pScreen); - - ExaOffscreenValidate (pScreen); - /* loop until a single free area spans the space */ - for (;;) - { - ExaOffscreenArea *area; - - for (area = pExaScr->info->offScreenAreas; area != NULL; - area = area->next) - { - if (area->state == ExaOffscreenRemovable && - area->save == exaPixmapSave) - { - (void) ExaOffscreenKickOut (pScreen, area); - ExaOffscreenValidate (pScreen); - break; - } - } - if (area == NULL) - break; - } - ExaOffscreenValidate (pScreen); -} - -void -ExaOffscreenSwapIn (ScreenPtr pScreen) -{ - exaOffscreenInit (pScreen); -} - -/** - * Prepares EXA for disabling of FB access, or restoring it. - * - * In version 2.1, the disabling results in pixmaps being ejected, while other - * allocations remain. With this plus the prevention of migration while - * swappedOut is set, EXA by itself should not cause any access of the - * framebuffer to occur while swapped out. Any remaining issues are the - * responsibility of the driver. - * - * Prior to version 2.1, all allocations, including locked ones, are ejected - * when access is disabled, and the allocator is torn down while swappedOut - * is set. This is more drastic, and caused implementation difficulties for - * many drivers that could otherwise handle the lack of FB access while - * swapped out. - */ -void -exaEnableDisableFBAccess (int index, Bool enable) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - ExaScreenPriv (pScreen); - - if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) - return; - - if (!enable && pExaScr->disableFbCount++ == 0) { - if (pExaScr->info->exa_minor < 1) - ExaOffscreenSwapOut (pScreen); - else - ExaOffscreenEjectPixmaps (pScreen); - pExaScr->swappedOut = TRUE; - } - - if (enable && --pExaScr->disableFbCount == 0) { - if (pExaScr->info->exa_minor < 1) - ExaOffscreenSwapIn (pScreen); - pExaScr->swappedOut = FALSE; - } -} - -/* merge the next free area into this one */ -static void -ExaOffscreenMerge (ExaScreenPrivPtr pExaScr, ExaOffscreenArea *area) -{ - ExaOffscreenArea *next = area->next; - - /* account for space */ - area->size += next->size; - /* frob pointer */ - area->next = next->next; - if (area->next) - area->next->prev = area; - else - pExaScr->info->offScreenAreas->prev = area; - xfree (next); - - pExaScr->numOffscreenAvailable--; -} - -/** - * exaOffscreenFree frees an allocation. - * - * @param pScreen current screen - * @param area offscreen area to free - * - * exaOffscreenFree frees an allocation created by exaOffscreenAlloc. Note that - * the save callback of the area is not called, and it is up to the driver to - * do any cleanup necessary as a result. - * - * @return pointer to the newly freed area. This behavior should not be relied - * on. - */ -ExaOffscreenArea * -exaOffscreenFree (ScreenPtr pScreen, ExaOffscreenArea *area) -{ - ExaScreenPriv(pScreen); - ExaOffscreenArea *next = area->next; - ExaOffscreenArea *prev; - - DBG_OFFSCREEN (("Free 0x%x -> 0x%x (0x%x)\n", area->size, - area->base_offset, area->offset)); - ExaOffscreenValidate (pScreen); - - area->state = ExaOffscreenAvail; - area->save = NULL; - area->last_use = 0; - area->eviction_cost = 0; - /* - * Find previous area - */ - if (area == pExaScr->info->offScreenAreas) - prev = NULL; - else - prev = area->prev; - - pExaScr->numOffscreenAvailable++; - - /* link with next area if free */ - if (next && next->state == ExaOffscreenAvail) - ExaOffscreenMerge (pExaScr, area); - - /* link with prev area if free */ - if (prev && prev->state == ExaOffscreenAvail) - { - area = prev; - ExaOffscreenMerge (pExaScr, area); - } - - ExaOffscreenValidate (pScreen); - DBG_OFFSCREEN(("\tdone freeing\n")); - return area; -} - -void -ExaOffscreenMarkUsed (PixmapPtr pPixmap) -{ - ExaPixmapPriv (pPixmap); - ExaScreenPriv (pPixmap->drawable.pScreen); - - if (!pExaPixmap || !pExaPixmap->area) - return; - - pExaPixmap->area->last_use = pExaScr->offScreenCounter++; -} - -/** - * Defragment offscreen memory by compacting allocated areas at the end of it, - * leaving the total amount of memory available as a single area at the - * beginning (when there are no pinned allocations). - */ -_X_HIDDEN ExaOffscreenArea* -ExaOffscreenDefragment (ScreenPtr pScreen) -{ - ExaScreenPriv (pScreen); - ExaOffscreenArea *area, *largest_available = NULL; - int largest_size = 0; - PixmapPtr pDstPix; - ExaPixmapPrivPtr pExaDstPix; - - pDstPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, 0, 0); - - if (!pDstPix) - return NULL; - - pExaDstPix = ExaGetPixmapPriv (pDstPix); - pExaDstPix->use_gpu_copy = TRUE; - - for (area = pExaScr->info->offScreenAreas->prev; - area != pExaScr->info->offScreenAreas; - ) - { - ExaOffscreenArea *prev = area->prev; - PixmapPtr pSrcPix; - ExaPixmapPrivPtr pExaSrcPix; - Bool save_use_gpu_copy; - int save_pitch; - - if (area->state != ExaOffscreenAvail || - prev->state == ExaOffscreenLocked || - (prev->state == ExaOffscreenRemovable && - prev->save != exaPixmapSave)) { - area = prev; - continue; - } - - if (prev->state == ExaOffscreenAvail) { - if (area == largest_available) { - largest_available = prev; - largest_size += prev->size; - } - area = prev; - ExaOffscreenMerge (pExaScr, area); - continue; - } - - if (area->size > largest_size) { - largest_available = area; - largest_size = area->size; - } - - pSrcPix = prev->privData; - pExaSrcPix = ExaGetPixmapPriv (pSrcPix); - - pExaDstPix->fb_ptr = pExaScr->info->memoryBase + - area->base_offset + area->size - prev->size + prev->base_offset - - prev->offset; - pExaDstPix->fb_ptr -= (unsigned long)pExaDstPix->fb_ptr % prev->align; - - if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) { - area = prev; - continue; - } - - if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) && - (pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) { - area = prev; - continue; - } - - save_use_gpu_copy = pExaSrcPix->use_gpu_copy; - save_pitch = pSrcPix->devKind; - - pExaSrcPix->use_gpu_copy = TRUE; - pSrcPix->devKind = pExaSrcPix->fb_pitch; - - pDstPix->drawable.width = pSrcPix->drawable.width; - pDstPix->devKind = pSrcPix->devKind; - pDstPix->drawable.height = pSrcPix->drawable.height; - pDstPix->drawable.depth = pSrcPix->drawable.depth; - pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel; - - if (!pExaScr->info->PrepareCopy (pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) { - pExaSrcPix->use_gpu_copy = save_use_gpu_copy; - pSrcPix->devKind = save_pitch; - area = prev; - continue; - } - - pExaScr->info->Copy (pDstPix, 0, 0, 0, 0, pDstPix->drawable.width, - pDstPix->drawable.height); - pExaScr->info->DoneCopy (pDstPix); - exaMarkSync (pScreen); - - DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", - prev->base_offset, prev->offset, prev->base_offset + prev->size, - area->base_offset, area->offset, area->base_offset + area->size)); - - /* Calculate swapped area offsets and sizes */ - area->base_offset = prev->base_offset; - area->offset = area->base_offset; - prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr; - assert(prev->offset >= pExaScr->info->offScreenBase && - prev->offset < pExaScr->info->memorySize); - prev->base_offset = prev->offset; - if (area->next) - prev->size = area->next->base_offset - prev->base_offset; - else - prev->size = pExaScr->info->memorySize - prev->base_offset; - area->size = prev->base_offset - area->base_offset; - - DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", - area->base_offset, area->offset, area->base_offset + area->size, - prev->base_offset, prev->offset, prev->base_offset + prev->size)); - - /* Swap areas in list */ - if (area->next) - area->next->prev = prev; - else - pExaScr->info->offScreenAreas->prev = prev; - if (prev->prev->next) - prev->prev->next = area; - else - pExaScr->info->offScreenAreas = area; - prev->next = area->next; - area->next = prev; - area->prev = prev->prev; - prev->prev = area; - if (!area->prev->next) - pExaScr->info->offScreenAreas = area; - -#if DEBUG_OFFSCREEN - if (prev->prev == prev || prev->next == prev) - ErrorF("Whoops, prev points to itself!\n"); - - if (area->prev == area || area->next == area) - ErrorF("Whoops, area points to itself!\n"); -#endif - - pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr; - pExaSrcPix->use_gpu_copy = save_use_gpu_copy; - pSrcPix->devKind = save_pitch; - } - - pDstPix->drawable.width = 0; - pDstPix->drawable.height = 0; - pDstPix->drawable.depth = 0; - pDstPix->drawable.bitsPerPixel = 0; - - (*pScreen->DestroyPixmap) (pDstPix); - - if (area->state == ExaOffscreenAvail && area->size > largest_size) - return area; - - return largest_available; -} - -/** - * exaOffscreenInit initializes the offscreen memory manager. - * - * @param pScreen current screen - * - * exaOffscreenInit is called by exaDriverInit to set up the memory manager for - * the screen, if any offscreen memory is available. - */ -Bool -exaOffscreenInit (ScreenPtr pScreen) -{ - ExaScreenPriv (pScreen); - ExaOffscreenArea *area; - - /* Allocate a big free area */ - area = xalloc (sizeof (ExaOffscreenArea)); - - if (!area) - return FALSE; - - area->state = ExaOffscreenAvail; - area->base_offset = pExaScr->info->offScreenBase; - area->offset = area->base_offset; - area->align = 0; - area->size = pExaScr->info->memorySize - area->base_offset; - area->save = NULL; - area->next = NULL; - area->prev = area; - area->last_use = 0; - area->eviction_cost = 0; - - /* Add it to the free areas */ - pExaScr->info->offScreenAreas = area; - pExaScr->offScreenCounter = 1; - pExaScr->numOffscreenAvailable = 1; - - ExaOffscreenValidate (pScreen); - - return TRUE; -} - -void -ExaOffscreenFini (ScreenPtr pScreen) -{ - ExaScreenPriv (pScreen); - ExaOffscreenArea *area; - - /* just free all of the area records */ - while ((area = pExaScr->info->offScreenAreas)) - { - pExaScr->info->offScreenAreas = area->next; - xfree (area); - } -} +/* + * Copyright © 2003 Anders Carlsson + * + * 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 Anders Carlsson not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Anders Carlsson makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ANDERS CARLSSON 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. + */ + +/** @file + * This allocator allocates blocks of memory by maintaining a list of areas. + * When allocating, the contiguous block of areas with the minimum eviction + * cost is found and evicted in order to make room for the new allocation. + */ + +#include "exa_priv.h" + +#include +#include +#include + +#if DEBUG_OFFSCREEN +#define DBG_OFFSCREEN(a) ErrorF a +#else +#define DBG_OFFSCREEN(a) +#endif + +#if DEBUG_OFFSCREEN +static void +ExaOffscreenValidate (ScreenPtr pScreen) +{ + ExaScreenPriv (pScreen); + ExaOffscreenArea *prev = 0, *area; + + assert (pExaScr->info->offScreenAreas->base_offset == + pExaScr->info->offScreenBase); + for (area = pExaScr->info->offScreenAreas; area; area = area->next) + { + assert (area->offset >= area->base_offset && + area->offset < (area->base_offset + area->size)); + if (prev) + assert (prev->base_offset + prev->size == area->base_offset); + prev = area; + } + assert (prev->base_offset + prev->size == pExaScr->info->memorySize); +} +#else +#define ExaOffscreenValidate(s) +#endif + +static ExaOffscreenArea * +ExaOffscreenKickOut (ScreenPtr pScreen, ExaOffscreenArea *area) +{ + if (area->save) + (*area->save) (pScreen, area); + return exaOffscreenFree (pScreen, area); +} + +static void +exaUpdateEvictionCost(ExaOffscreenArea *area, unsigned offScreenCounter) +{ + unsigned age; + + if (area->state == ExaOffscreenAvail) + return; + + age = offScreenCounter - area->last_use; + + /* This is unlikely to happen, but could result in a division by zero... */ + if (age > (UINT_MAX / 2)) { + age = UINT_MAX / 2; + area->last_use = offScreenCounter - age; + } + + area->eviction_cost = area->size / age; +} + +static ExaOffscreenArea * +exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align) +{ + ExaOffscreenArea *begin, *end, *best; + unsigned cost, best_cost; + int avail, real_size; + + best_cost = UINT_MAX; + begin = end = pExaScr->info->offScreenAreas; + avail = 0; + cost = 0; + best = 0; + + while (end != NULL) + { + restart: + while (begin != NULL && begin->state == ExaOffscreenLocked) + begin = end = begin->next; + + if (begin == NULL) + break; + + /* adjust size needed to account for alignment loss for this area */ + real_size = size + (begin->base_offset + begin->size - size) % align; + + while (avail < real_size && end != NULL) + { + if (end->state == ExaOffscreenLocked) { + /* Can't more room here, restart after this locked area */ + avail = 0; + cost = 0; + begin = end; + goto restart; + } + avail += end->size; + exaUpdateEvictionCost(end, pExaScr->offScreenCounter); + cost += end->eviction_cost; + end = end->next; + } + + /* Check the cost, update best */ + if (avail >= real_size && cost < best_cost) { + best = begin; + best_cost = cost; + } + + avail -= begin->size; + cost -= begin->eviction_cost; + begin = begin->next; + } + + return best; +} + +/** + * exaOffscreenAlloc allocates offscreen memory + * + * @param pScreen current screen + * @param size size in bytes of the allocation + * @param align byte alignment requirement for the offset of the allocated area + * @param locked whether the allocated area is locked and can't be kicked out + * @param save callback for when the area is evicted from memory + * @param privdata private data for the save callback. + * + * Allocates offscreen memory from the device associated with pScreen. size + * and align deteremine where and how large the allocated area is, and locked + * will mark whether it should be held in card memory. privdata may be any + * pointer for the save callback when the area is removed. + * + * Note that locked areas do get evicted on VT switch unless the driver + * requested version 2.1 or newer behavior. In that case, the save callback is + * still called. + */ +ExaOffscreenArea * +exaOffscreenAlloc (ScreenPtr pScreen, int size, int align, + Bool locked, + ExaOffscreenSaveProc save, + pointer privData) +{ + ExaOffscreenArea *area; + ExaScreenPriv (pScreen); + int real_size = 0, largest_avail = 0; +#if DEBUG_OFFSCREEN + static int number = 0; + ErrorF("================= ============ allocating a new pixmap %d\n", ++number); +#endif + + ExaOffscreenValidate (pScreen); + if (!align) + align = 1; + + if (!size) + { + DBG_OFFSCREEN (("Alloc 0x%x -> EMPTY\n", size)); + return NULL; + } + + /* throw out requests that cannot fit */ + if (size > (pExaScr->info->memorySize - pExaScr->info->offScreenBase)) + { + DBG_OFFSCREEN (("Alloc 0x%x vs (0x%lx) -> TOBIG\n", size, + pExaScr->info->memorySize - + pExaScr->info->offScreenBase)); + return NULL; + } + + /* Try to find a free space that'll fit. */ + for (area = pExaScr->info->offScreenAreas; area; area = area->next) + { + /* skip allocated areas */ + if (area->state != ExaOffscreenAvail) + continue; + + /* adjust size to match alignment requirement */ + real_size = size + (area->base_offset + area->size - size) % align; + + /* does it fit? */ + if (real_size <= area->size) + break; + + if (area->size > largest_avail) + largest_avail = area->size; + } + + if (!area) + { + area = exaFindAreaToEvict(pExaScr, size, align); + + if (!area) + { + DBG_OFFSCREEN (("Alloc 0x%x -> NOSPACE\n", size)); + /* Could not allocate memory */ + ExaOffscreenValidate (pScreen); + return NULL; + } + + /* adjust size needed to account for alignment loss for this area */ + real_size = size + (area->base_offset + area->size - size) % align; + + /* + * Kick out first area if in use + */ + if (area->state != ExaOffscreenAvail) + area = ExaOffscreenKickOut (pScreen, area); + /* + * Now get the system to merge the other needed areas together + */ + while (area->size < real_size) + { + assert (area->next && area->next->state == ExaOffscreenRemovable); + (void) ExaOffscreenKickOut (pScreen, area->next); + } + } + + /* save extra space in new area */ + if (real_size < area->size) + { + ExaOffscreenArea *new_area = malloc(sizeof (ExaOffscreenArea)); + if (!new_area) + return NULL; + new_area->base_offset = area->base_offset; + + new_area->offset = new_area->base_offset; + new_area->align = 0; + new_area->size = area->size - real_size; + new_area->state = ExaOffscreenAvail; + new_area->save = NULL; + new_area->last_use = 0; + new_area->eviction_cost = 0; + new_area->next = area; + new_area->prev = area->prev; + if (area->prev->next) + area->prev->next = new_area; + else + pExaScr->info->offScreenAreas = new_area; + area->prev = new_area; + area->base_offset = new_area->base_offset + new_area->size; + area->size = real_size; + } else + pExaScr->numOffscreenAvailable--; + + /* + * Mark this area as in use + */ + if (locked) + area->state = ExaOffscreenLocked; + else + area->state = ExaOffscreenRemovable; + area->privData = privData; + area->save = save; + area->last_use = pExaScr->offScreenCounter++; + area->offset = (area->base_offset + align - 1); + area->offset -= area->offset % align; + area->align = align; + + ExaOffscreenValidate (pScreen); + + DBG_OFFSCREEN (("Alloc 0x%x -> 0x%x (0x%x)\n", size, + area->base_offset, area->offset)); + return area; +} + +/** + * Ejects all offscreen areas, and uninitializes the offscreen memory manager. + */ +void +ExaOffscreenSwapOut (ScreenPtr pScreen) +{ + ExaScreenPriv (pScreen); + + ExaOffscreenValidate (pScreen); + /* loop until a single free area spans the space */ + for (;;) + { + ExaOffscreenArea *area = pExaScr->info->offScreenAreas; + + if (!area) + break; + if (area->state == ExaOffscreenAvail) + { + area = area->next; + if (!area) + break; + } + assert (area->state != ExaOffscreenAvail); + (void) ExaOffscreenKickOut (pScreen, area); + ExaOffscreenValidate (pScreen); + } + ExaOffscreenValidate (pScreen); + ExaOffscreenFini (pScreen); +} + +/** Ejects all pixmaps managed by EXA. */ +static void +ExaOffscreenEjectPixmaps (ScreenPtr pScreen) +{ + ExaScreenPriv (pScreen); + + ExaOffscreenValidate (pScreen); + /* loop until a single free area spans the space */ + for (;;) + { + ExaOffscreenArea *area; + + for (area = pExaScr->info->offScreenAreas; area != NULL; + area = area->next) + { + if (area->state == ExaOffscreenRemovable && + area->save == exaPixmapSave) + { + (void) ExaOffscreenKickOut (pScreen, area); + ExaOffscreenValidate (pScreen); + break; + } + } + if (area == NULL) + break; + } + ExaOffscreenValidate (pScreen); +} + +void +ExaOffscreenSwapIn (ScreenPtr pScreen) +{ + exaOffscreenInit (pScreen); +} + +/** + * Prepares EXA for disabling of FB access, or restoring it. + * + * In version 2.1, the disabling results in pixmaps being ejected, while other + * allocations remain. With this plus the prevention of migration while + * swappedOut is set, EXA by itself should not cause any access of the + * framebuffer to occur while swapped out. Any remaining issues are the + * responsibility of the driver. + * + * Prior to version 2.1, all allocations, including locked ones, are ejected + * when access is disabled, and the allocator is torn down while swappedOut + * is set. This is more drastic, and caused implementation difficulties for + * many drivers that could otherwise handle the lack of FB access while + * swapped out. + */ +void +exaEnableDisableFBAccess (int index, Bool enable) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + ExaScreenPriv (pScreen); + + if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) + return; + + if (!enable && pExaScr->disableFbCount++ == 0) { + if (pExaScr->info->exa_minor < 1) + ExaOffscreenSwapOut (pScreen); + else + ExaOffscreenEjectPixmaps (pScreen); + pExaScr->swappedOut = TRUE; + } + + if (enable && --pExaScr->disableFbCount == 0) { + if (pExaScr->info->exa_minor < 1) + ExaOffscreenSwapIn (pScreen); + pExaScr->swappedOut = FALSE; + } +} + +/* merge the next free area into this one */ +static void +ExaOffscreenMerge (ExaScreenPrivPtr pExaScr, ExaOffscreenArea *area) +{ + ExaOffscreenArea *next = area->next; + + /* account for space */ + area->size += next->size; + /* frob pointer */ + area->next = next->next; + if (area->next) + area->next->prev = area; + else + pExaScr->info->offScreenAreas->prev = area; + free(next); + + pExaScr->numOffscreenAvailable--; +} + +/** + * exaOffscreenFree frees an allocation. + * + * @param pScreen current screen + * @param area offscreen area to free + * + * exaOffscreenFree frees an allocation created by exaOffscreenAlloc. Note that + * the save callback of the area is not called, and it is up to the driver to + * do any cleanup necessary as a result. + * + * @return pointer to the newly freed area. This behavior should not be relied + * on. + */ +ExaOffscreenArea * +exaOffscreenFree (ScreenPtr pScreen, ExaOffscreenArea *area) +{ + ExaScreenPriv(pScreen); + ExaOffscreenArea *next = area->next; + ExaOffscreenArea *prev; + + DBG_OFFSCREEN (("Free 0x%x -> 0x%x (0x%x)\n", area->size, + area->base_offset, area->offset)); + ExaOffscreenValidate (pScreen); + + area->state = ExaOffscreenAvail; + area->save = NULL; + area->last_use = 0; + area->eviction_cost = 0; + /* + * Find previous area + */ + if (area == pExaScr->info->offScreenAreas) + prev = NULL; + else + prev = area->prev; + + pExaScr->numOffscreenAvailable++; + + /* link with next area if free */ + if (next && next->state == ExaOffscreenAvail) + ExaOffscreenMerge (pExaScr, area); + + /* link with prev area if free */ + if (prev && prev->state == ExaOffscreenAvail) + { + area = prev; + ExaOffscreenMerge (pExaScr, area); + } + + ExaOffscreenValidate (pScreen); + DBG_OFFSCREEN(("\tdone freeing\n")); + return area; +} + +void +ExaOffscreenMarkUsed (PixmapPtr pPixmap) +{ + ExaPixmapPriv (pPixmap); + ExaScreenPriv (pPixmap->drawable.pScreen); + + if (!pExaPixmap || !pExaPixmap->area) + return; + + pExaPixmap->area->last_use = pExaScr->offScreenCounter++; +} + +/** + * Defragment offscreen memory by compacting allocated areas at the end of it, + * leaving the total amount of memory available as a single area at the + * beginning (when there are no pinned allocations). + */ +_X_HIDDEN ExaOffscreenArea* +ExaOffscreenDefragment (ScreenPtr pScreen) +{ + ExaScreenPriv (pScreen); + ExaOffscreenArea *area, *largest_available = NULL; + int largest_size = 0; + PixmapPtr pDstPix; + ExaPixmapPrivPtr pExaDstPix; + + pDstPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, 0, 0); + + if (!pDstPix) + return NULL; + + pExaDstPix = ExaGetPixmapPriv (pDstPix); + pExaDstPix->use_gpu_copy = TRUE; + + for (area = pExaScr->info->offScreenAreas->prev; + area != pExaScr->info->offScreenAreas; + ) + { + ExaOffscreenArea *prev = area->prev; + PixmapPtr pSrcPix; + ExaPixmapPrivPtr pExaSrcPix; + Bool save_use_gpu_copy; + int save_pitch; + + if (area->state != ExaOffscreenAvail || + prev->state == ExaOffscreenLocked || + (prev->state == ExaOffscreenRemovable && + prev->save != exaPixmapSave)) { + area = prev; + continue; + } + + if (prev->state == ExaOffscreenAvail) { + if (area == largest_available) { + largest_available = prev; + largest_size += prev->size; + } + area = prev; + ExaOffscreenMerge (pExaScr, area); + continue; + } + + if (area->size > largest_size) { + largest_available = area; + largest_size = area->size; + } + + pSrcPix = prev->privData; + pExaSrcPix = ExaGetPixmapPriv (pSrcPix); + + pExaDstPix->fb_ptr = pExaScr->info->memoryBase + + area->base_offset + area->size - prev->size + prev->base_offset - + prev->offset; + pExaDstPix->fb_ptr -= (unsigned long)pExaDstPix->fb_ptr % prev->align; + + if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) { + area = prev; + continue; + } + + if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) && + (pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) { + area = prev; + continue; + } + + save_use_gpu_copy = pExaSrcPix->use_gpu_copy; + save_pitch = pSrcPix->devKind; + + pExaSrcPix->use_gpu_copy = TRUE; + pSrcPix->devKind = pExaSrcPix->fb_pitch; + + pDstPix->drawable.width = pSrcPix->drawable.width; + pDstPix->devKind = pSrcPix->devKind; + pDstPix->drawable.height = pSrcPix->drawable.height; + pDstPix->drawable.depth = pSrcPix->drawable.depth; + pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel; + + if (!pExaScr->info->PrepareCopy (pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) { + pExaSrcPix->use_gpu_copy = save_use_gpu_copy; + pSrcPix->devKind = save_pitch; + area = prev; + continue; + } + + pExaScr->info->Copy (pDstPix, 0, 0, 0, 0, pDstPix->drawable.width, + pDstPix->drawable.height); + pExaScr->info->DoneCopy (pDstPix); + exaMarkSync (pScreen); + + DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", + prev->base_offset, prev->offset, prev->base_offset + prev->size, + area->base_offset, area->offset, area->base_offset + area->size)); + + /* Calculate swapped area offsets and sizes */ + area->base_offset = prev->base_offset; + area->offset = area->base_offset; + prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr; + assert(prev->offset >= pExaScr->info->offScreenBase && + prev->offset < pExaScr->info->memorySize); + prev->base_offset = prev->offset; + if (area->next) + prev->size = area->next->base_offset - prev->base_offset; + else + prev->size = pExaScr->info->memorySize - prev->base_offset; + area->size = prev->base_offset - area->base_offset; + + DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", + area->base_offset, area->offset, area->base_offset + area->size, + prev->base_offset, prev->offset, prev->base_offset + prev->size)); + + /* Swap areas in list */ + if (area->next) + area->next->prev = prev; + else + pExaScr->info->offScreenAreas->prev = prev; + if (prev->prev->next) + prev->prev->next = area; + else + pExaScr->info->offScreenAreas = area; + prev->next = area->next; + area->next = prev; + area->prev = prev->prev; + prev->prev = area; + if (!area->prev->next) + pExaScr->info->offScreenAreas = area; + +#if DEBUG_OFFSCREEN + if (prev->prev == prev || prev->next == prev) + ErrorF("Whoops, prev points to itself!\n"); + + if (area->prev == area || area->next == area) + ErrorF("Whoops, area points to itself!\n"); +#endif + + pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr; + pExaSrcPix->use_gpu_copy = save_use_gpu_copy; + pSrcPix->devKind = save_pitch; + } + + pDstPix->drawable.width = 0; + pDstPix->drawable.height = 0; + pDstPix->drawable.depth = 0; + pDstPix->drawable.bitsPerPixel = 0; + + (*pScreen->DestroyPixmap) (pDstPix); + + if (area->state == ExaOffscreenAvail && area->size > largest_size) + return area; + + return largest_available; +} + +/** + * exaOffscreenInit initializes the offscreen memory manager. + * + * @param pScreen current screen + * + * exaOffscreenInit is called by exaDriverInit to set up the memory manager for + * the screen, if any offscreen memory is available. + */ +Bool +exaOffscreenInit (ScreenPtr pScreen) +{ + ExaScreenPriv (pScreen); + ExaOffscreenArea *area; + + /* Allocate a big free area */ + area = malloc(sizeof (ExaOffscreenArea)); + + if (!area) + return FALSE; + + area->state = ExaOffscreenAvail; + area->base_offset = pExaScr->info->offScreenBase; + area->offset = area->base_offset; + area->align = 0; + area->size = pExaScr->info->memorySize - area->base_offset; + area->save = NULL; + area->next = NULL; + area->prev = area; + area->last_use = 0; + area->eviction_cost = 0; + + /* Add it to the free areas */ + pExaScr->info->offScreenAreas = area; + pExaScr->offScreenCounter = 1; + pExaScr->numOffscreenAvailable = 1; + + ExaOffscreenValidate (pScreen); + + return TRUE; +} + +void +ExaOffscreenFini (ScreenPtr pScreen) +{ + ExaScreenPriv (pScreen); + ExaOffscreenArea *area; + + /* just free all of the area records */ + while ((area = pExaScr->info->offScreenAreas)) + { + pExaScr->info->offScreenAreas = area->next; + free(area); + } +} diff --git a/xorg-server/fb/fballpriv.c b/xorg-server/fb/fballpriv.c index c40796c11..6aee50bce 100644 --- a/xorg-server/fb/fballpriv.c +++ b/xorg-server/fb/fballpriv.c @@ -1,76 +1,76 @@ -/* - * Copyright © 1998 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 "fb.h" - -#ifdef FB_SCREEN_PRIVATE -static int fbScreenPrivateKeyIndex; -static DevPrivateKey fbScreenPrivateKey = &fbScreenPrivateKeyIndex; -DevPrivateKey fbGetScreenPrivateKey(void) -{ - return fbScreenPrivateKey; -} -#endif - -static int fbGCPrivateKeyIndex; -static DevPrivateKey fbGCPrivateKey = &fbGCPrivateKeyIndex; -DevPrivateKey fbGetGCPrivateKey(void) -{ - return fbGCPrivateKey; -} - -static int fbWinPrivateKeyIndex; -static DevPrivateKey fbWinPrivateKey = &fbWinPrivateKeyIndex; -DevPrivateKey fbGetWinPrivateKey(void) -{ - return fbWinPrivateKey; -} - -Bool -fbAllocatePrivates(ScreenPtr pScreen, DevPrivateKey *pGCKey) -{ - if (pGCKey) - *pGCKey = fbGCPrivateKey; - - if (!dixRequestPrivate(fbGCPrivateKey, sizeof(FbGCPrivRec))) - return FALSE; -#ifdef FB_SCREEN_PRIVATE - { - FbScreenPrivPtr pScreenPriv; - - pScreenPriv = (FbScreenPrivPtr) xalloc (sizeof (FbScreenPrivRec)); - if (!pScreenPriv) - return FALSE; - dixSetPrivate(&pScreen->devPrivates, fbScreenPrivateKey, pScreenPriv); - } -#endif - return TRUE; -} - -#ifdef FB_ACCESS_WRAPPER -ReadMemoryProcPtr wfbReadMemory; -WriteMemoryProcPtr wfbWriteMemory; -#endif +/* + * Copyright © 1998 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 "fb.h" + +#ifdef FB_SCREEN_PRIVATE +static int fbScreenPrivateKeyIndex; +static DevPrivateKey fbScreenPrivateKey = &fbScreenPrivateKeyIndex; +DevPrivateKey fbGetScreenPrivateKey(void) +{ + return fbScreenPrivateKey; +} +#endif + +static int fbGCPrivateKeyIndex; +static DevPrivateKey fbGCPrivateKey = &fbGCPrivateKeyIndex; +DevPrivateKey fbGetGCPrivateKey(void) +{ + return fbGCPrivateKey; +} + +static int fbWinPrivateKeyIndex; +static DevPrivateKey fbWinPrivateKey = &fbWinPrivateKeyIndex; +DevPrivateKey fbGetWinPrivateKey(void) +{ + return fbWinPrivateKey; +} + +Bool +fbAllocatePrivates(ScreenPtr pScreen, DevPrivateKey *pGCKey) +{ + if (pGCKey) + *pGCKey = fbGCPrivateKey; + + if (!dixRequestPrivate(fbGCPrivateKey, sizeof(FbGCPrivRec))) + return FALSE; +#ifdef FB_SCREEN_PRIVATE + { + FbScreenPrivPtr pScreenPriv; + + pScreenPriv = (FbScreenPrivPtr) malloc(sizeof (FbScreenPrivRec)); + if (!pScreenPriv) + return FALSE; + dixSetPrivate(&pScreen->devPrivates, fbScreenPrivateKey, pScreenPriv); + } +#endif + return TRUE; +} + +#ifdef FB_ACCESS_WRAPPER +ReadMemoryProcPtr wfbReadMemory; +WriteMemoryProcPtr wfbWriteMemory; +#endif diff --git a/xorg-server/fb/fbcmap.c b/xorg-server/fb/fbcmap.c index b775bc335..e656c2399 100644 --- a/xorg-server/fb/fbcmap.c +++ b/xorg-server/fb/fbcmap.c @@ -1,586 +1,586 @@ -/* - * Copyright © 1987 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, 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include "scrnintstr.h" -#include "colormapst.h" -#include "resource.h" -#include "fb.h" - -#ifdef XFree86Server -#error "You should be compiling fbcmap_mi.c instead of fbcmap.c!" -#endif - -static int cmapScrPrivateKeyIndex; -static DevPrivateKey cmapScrPrivateKey = &cmapScrPrivateKeyIndex; - -#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey)) -#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c)) - -int -fbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) -{ - /* By the time we are processing requests, we can guarantee that there - * is always a colormap installed */ - *pmaps = GetInstalledColormap(pScreen)->mid; - return (1); -} - - -void -fbInstallColormap(ColormapPtr pmap) -{ - ColormapPtr oldpmap = GetInstalledColormap(pmap->pScreen); - - if(pmap != oldpmap) - { - /* Uninstall pInstalledMap. No hardware changes required, just - * notify all interested parties. */ - if(oldpmap != (ColormapPtr)None) - WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); - /* Install pmap */ - SetInstalledColormap(pmap->pScreen, pmap); - WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); - } -} - -void -fbUninstallColormap(ColormapPtr pmap) -{ - ColormapPtr curpmap = GetInstalledColormap(pmap->pScreen); - - if(pmap == curpmap) - { - if (pmap->mid != pmap->pScreen->defColormap) - { - dixLookupResourceByType((pointer *)&curpmap, - pmap->pScreen->defColormap, - RT_COLORMAP, - serverClient, DixInstallAccess); - (*pmap->pScreen->InstallColormap)(curpmap); - } - } -} - -void -fbResolveColor(unsigned short *pred, - unsigned short *pgreen, - unsigned short *pblue, - VisualPtr pVisual) -{ - int shift = 16 - pVisual->bitsPerRGBValue; - unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1; - - if ((pVisual->class | DynamicClass) == GrayScale) - { - /* rescale to gray then rgb bits */ - *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100; - *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim; - } - else - { - /* rescale to rgb bits */ - *pred = ((*pred >> shift) * 65535) / lim; - *pgreen = ((*pgreen >> shift) * 65535) / lim; - *pblue = ((*pblue >> shift) * 65535) / lim; - } -} - -Bool -fbInitializeColormap(ColormapPtr pmap) -{ - register unsigned i; - register VisualPtr pVisual; - unsigned lim, maxent, shift; - - pVisual = pmap->pVisual; - lim = (1 << pVisual->bitsPerRGBValue) - 1; - shift = 16 - pVisual->bitsPerRGBValue; - maxent = pVisual->ColormapEntries - 1; - if (pVisual->class == TrueColor) - { - unsigned limr, limg, limb; - - limr = pVisual->redMask >> pVisual->offsetRed; - limg = pVisual->greenMask >> pVisual->offsetGreen; - limb = pVisual->blueMask >> pVisual->offsetBlue; - for(i = 0; i <= maxent; i++) - { - /* rescale to [0..65535] then rgb bits */ - pmap->red[i].co.local.red = - ((((i * 65535) / limr) >> shift) * 65535) / lim; - pmap->green[i].co.local.green = - ((((i * 65535) / limg) >> shift) * 65535) / lim; - pmap->blue[i].co.local.blue = - ((((i * 65535) / limb) >> shift) * 65535) / lim; - } - } - else if (pVisual->class == StaticColor) - { - unsigned n; - unsigned r, g, b; - unsigned red, green, blue; - - for (n = 0; n*n*n < pVisual->ColormapEntries; n++) - ; - n--; - i = 0; - for (r = 0; r < n; r++) - { - red = (((r * 65535 / (n - 1)) >> shift) * 65535) / lim; - for (g = 0; g < n; g++) - { - green = (((g * 65535 / (n - 1)) >> shift) * 65535) / lim; - for (b = 0; b < n; b++) - { - blue = (((b * 65535 / (n - 1)) >> shift) * 65535) / lim; - pmap->red[i].co.local.red = red; - pmap->red[i].co.local.green = green; - pmap->red[i].co.local.blue = blue; - i++; - } - } - } - n = pVisual->ColormapEntries - i; - for (r = 0; r < n; r++) - { - red = (((r * 65535 / (n - 1)) >> shift) * 65535) / lim; - pmap->red[i].co.local.red = red; - pmap->red[i].co.local.green = red; - pmap->red[i].co.local.blue = red; - i++; - } - } - else if (pVisual->class == StaticGray) - { - for(i = 0; i <= maxent; i++) - { - /* rescale to [0..65535] then rgb bits */ - pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift) - * 65535) / lim; - pmap->red[i].co.local.green = pmap->red[i].co.local.red; - pmap->red[i].co.local.blue = pmap->red[i].co.local.red; - } - } - return TRUE; -} - -/* When simulating DirectColor on PseudoColor hardware, multiple - entries of the colormap must be updated - */ - -#define AddElement(mask) { \ - pixel = red | green | blue; \ - for (i = 0; i < nresult; i++) \ - if (outdefs[i].pixel == pixel) \ - break; \ - if (i == nresult) \ - { \ - nresult++; \ - outdefs[i].pixel = pixel; \ - outdefs[i].flags = 0; \ - } \ - outdefs[i].flags |= (mask); \ - outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \ - outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \ - outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \ -} - -int -fbExpandDirectColors (ColormapPtr pmap, - int ndef, - xColorItem *indefs, - xColorItem *outdefs) -{ - register int red, green, blue; - int maxred, maxgreen, maxblue; - int stepred, stepgreen, stepblue; - VisualPtr pVisual; - register int pixel; - register int nresult; - register int i; - - pVisual = pmap->pVisual; - - stepred = 1 << pVisual->offsetRed; - stepgreen = 1 << pVisual->offsetGreen; - stepblue = 1 << pVisual->offsetBlue; - maxred = pVisual->redMask; - maxgreen = pVisual->greenMask; - maxblue = pVisual->blueMask; - nresult = 0; - for (;ndef--; indefs++) - { - if (indefs->flags & DoRed) - { - red = indefs->pixel & pVisual->redMask; - for (green = 0; green <= maxgreen; green += stepgreen) - { - for (blue = 0; blue <= maxblue; blue += stepblue) - { - AddElement (DoRed) - } - } - } - if (indefs->flags & DoGreen) - { - green = indefs->pixel & pVisual->greenMask; - for (red = 0; red <= maxred; red += stepred) - { - for (blue = 0; blue <= maxblue; blue += stepblue) - { - AddElement (DoGreen) - } - } - } - if (indefs->flags & DoBlue) - { - blue = indefs->pixel & pVisual->blueMask; - for (red = 0; red <= maxred; red += stepred) - { - for (green = 0; green <= maxgreen; green += stepgreen) - { - AddElement (DoBlue) - } - } - } - } - return nresult; -} - -Bool -fbCreateDefColormap(ScreenPtr pScreen) -{ - unsigned short zero = 0, ones = 0xFFFF; - VisualPtr pVisual; - ColormapPtr cmap; - Pixel wp, bp; - - for (pVisual = pScreen->visuals; - pVisual->vid != pScreen->rootVisual; - pVisual++) - ; - - if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap, - (pVisual->class & DynamicClass) ? AllocNone : AllocAll, - 0) - != Success) - return FALSE; - wp = pScreen->whitePixel; - bp = pScreen->blackPixel; - if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) != - Success) || - (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) != - Success)) - return FALSE; - pScreen->whitePixel = wp; - pScreen->blackPixel = bp; - (*pScreen->InstallColormap)(cmap); - return TRUE; -} - -extern int defaultColorVisualClass; - -#define _RZ(d) ((d + 2) / 3) -#define _RS(d) 0 -#define _RM(d) ((1 << _RZ(d)) - 1) -#define _GZ(d) ((d - _RZ(d) + 1) / 2) -#define _GS(d) _RZ(d) -#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d)) -#define _BZ(d) (d - _RZ(d) - _GZ(d)) -#define _BS(d) (_RZ(d) + _GZ(d)) -#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d)) -#define _CE(d) (1 << _RZ(d)) - -#define MAX_PSEUDO_DEPTH 10 /* largest DAC size I know */ - -#define StaticGrayMask (1 << StaticGray) -#define GrayScaleMask (1 << GrayScale) -#define StaticColorMask (1 << StaticColor) -#define PseudoColorMask (1 << PseudoColor) -#define TrueColorMask (1 << TrueColor) -#define DirectColorMask (1 << DirectColor) - -#define ALL_VISUALS (StaticGrayMask|\ - GrayScaleMask|\ - StaticColorMask|\ - PseudoColorMask|\ - TrueColorMask|\ - DirectColorMask) - -#define LARGE_VISUALS (TrueColorMask|\ - DirectColorMask) - -typedef struct _fbVisuals { - struct _fbVisuals *next; - int depth; - int bitsPerRGB; - int visuals; - int count; - Pixel redMask, greenMask, blueMask; -} fbVisualsRec, *fbVisualsPtr; - -static const int fbVisualPriority[] = { - PseudoColor, DirectColor, GrayScale, StaticColor, TrueColor, StaticGray -}; - -#define NUM_PRIORITY 6 - -static fbVisualsPtr fbVisuals; - -static int -popCount (int i) -{ - int count; - - count = (i >> 1) & 033333333333; - count = i - count - ((count >> 1) & 033333333333); - count = (((count + (count >> 3)) & 030707070707) % 077); /* HAKMEM 169 */ - return count; -} - -/* - * Distance to least significant one bit - */ -static int -maskShift (Pixel p) -{ - int s; - - if (!p) return 0; - s = 0; - while (!(p & 1)) - { - s++; - p >>= 1; - } - return s; -} - -Bool -fbSetVisualTypesAndMasks (int depth, int visuals, int bitsPerRGB, - Pixel redMask, Pixel greenMask, Pixel blueMask) -{ - fbVisualsPtr new, *prev, v; - - new = (fbVisualsPtr) xalloc (sizeof *new); - if (!new) - return FALSE; - if (!redMask || !greenMask || !blueMask) - { - redMask = _RM(depth); - greenMask = _GM(depth); - blueMask = _BM(depth); - } - new->next = 0; - new->depth = depth; - new->visuals = visuals; - new->bitsPerRGB = bitsPerRGB; - new->redMask = redMask; - new->greenMask = greenMask; - new->blueMask = blueMask; - new->count = popCount (visuals); - for (prev = &fbVisuals; (v = *prev); prev = &v->next); - *prev = new; - return TRUE; -} - -Bool -fbHasVisualTypes (int depth) -{ - fbVisualsPtr v; - - for (v = fbVisuals; v; v = v->next) - if (v->depth == depth) - return TRUE; - return FALSE; -} - -Bool -fbSetVisualTypes (int depth, int visuals, int bitsPerRGB) -{ - return fbSetVisualTypesAndMasks (depth, visuals, bitsPerRGB, - _RM(depth), _GM(depth), _BM(depth)); -} - -/* - * Given a list of formats for a screen, create a list - * of visuals and depths for the screen which coorespond to - * the set which can be used with this version of fb. - */ - -Bool -fbInitVisuals (VisualPtr *visualp, - DepthPtr *depthp, - int *nvisualp, - int *ndepthp, - int *rootDepthp, - VisualID *defaultVisp, - unsigned long sizes, - int bitsPerRGB) -{ - int i, j = 0, k; - VisualPtr visual; - DepthPtr depth; - VisualID *vid; - int d, b; - int f; - int ndepth, nvisual; - int nvtype; - int vtype; - fbVisualsPtr visuals, nextVisuals; - - /* none specified, we'll guess from pixmap formats */ - if (!fbVisuals) - { - for (f = 0; f < screenInfo.numPixmapFormats; f++) - { - d = screenInfo.formats[f].depth; - b = screenInfo.formats[f].bitsPerPixel; - if (sizes & (1 << (b - 1))) - { - if (d > MAX_PSEUDO_DEPTH) - vtype = LARGE_VISUALS; - else if (d == 1) - vtype = StaticGrayMask; - else - vtype = ALL_VISUALS; - } - else - vtype = 0; - if (!fbSetVisualTypes (d, vtype, bitsPerRGB)) - return FALSE; - } - } - nvisual = 0; - ndepth = 0; - for (visuals = fbVisuals; visuals; visuals = nextVisuals) - { - nextVisuals = visuals->next; - ndepth++; - nvisual += visuals->count; - } - depth = (DepthPtr) xalloc (ndepth * sizeof (DepthRec)); - visual = (VisualPtr) xalloc (nvisual * sizeof (VisualRec)); - if (!depth || !visual) - { - xfree (depth); - xfree (visual); - return FALSE; - } - *depthp = depth; - *visualp = visual; - *ndepthp = ndepth; - *nvisualp = nvisual; - for (visuals = fbVisuals; visuals; visuals = nextVisuals) - { - nextVisuals = visuals->next; - d = visuals->depth; - vtype = visuals->visuals; - nvtype = visuals->count; - vid = NULL; - if (nvtype) - { - vid = (VisualID *) xalloc (nvtype * sizeof (VisualID)); - if (!vid) - return FALSE; - } - depth->depth = d; - depth->numVids = nvtype; - depth->vids = vid; - depth++; - for (i = 0; i < NUM_PRIORITY; i++) { - if (! (vtype & (1 << fbVisualPriority[i]))) - continue; - visual->class = fbVisualPriority[i]; - visual->bitsPerRGBValue = visuals->bitsPerRGB; - visual->ColormapEntries = 1 << d; - visual->nplanes = d; - visual->vid = *vid = FakeClientID (0); - switch (visual->class) { - case PseudoColor: - case GrayScale: - case StaticGray: - case StaticColor: - visual->redMask = 0; - visual->greenMask = 0; - visual->blueMask = 0; - visual->offsetRed = 0; - visual->offsetGreen = 0; - visual->offsetBlue = 0; - break; - case DirectColor: - case TrueColor: - visual->ColormapEntries = _CE(d); - visual->redMask = visuals->redMask; - visual->greenMask = visuals->greenMask; - visual->blueMask = visuals->blueMask; - visual->offsetRed = maskShift (visuals->redMask); - visual->offsetGreen = maskShift (visuals->greenMask); - visual->offsetBlue = maskShift (visuals->blueMask); - } - vid++; - visual++; - } - xfree (visuals); - } - fbVisuals = NULL; - visual = *visualp; - depth = *depthp; - for (i = 0; i < ndepth; i++) - { - if (*rootDepthp && *rootDepthp != depth[i].depth) - continue; - for (j = 0; j < depth[i].numVids; j++) - { - for (k = 0; k < nvisual; k++) - if (visual[k].vid == depth[i].vids[j]) - break; - if (k == nvisual) - continue; - if (defaultColorVisualClass < 0 || - visual[k].class == defaultColorVisualClass) - break; - } - if (j != depth[i].numVids) - break; - } - if (i == ndepth) { - for (i = 0; i < ndepth; i++) - { - if (depth[i].numVids) - break; - } - if (i == ndepth) - return FALSE; - j = 0; - } - *rootDepthp = depth[i].depth; - *defaultVisp = depth[i].vids[j]; - return TRUE; -} +/* + * Copyright © 1987 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, 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "scrnintstr.h" +#include "colormapst.h" +#include "resource.h" +#include "fb.h" + +#ifdef XFree86Server +#error "You should be compiling fbcmap_mi.c instead of fbcmap.c!" +#endif + +static int cmapScrPrivateKeyIndex; +static DevPrivateKey cmapScrPrivateKey = &cmapScrPrivateKeyIndex; + +#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey)) +#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c)) + +int +fbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) +{ + /* By the time we are processing requests, we can guarantee that there + * is always a colormap installed */ + *pmaps = GetInstalledColormap(pScreen)->mid; + return (1); +} + + +void +fbInstallColormap(ColormapPtr pmap) +{ + ColormapPtr oldpmap = GetInstalledColormap(pmap->pScreen); + + if(pmap != oldpmap) + { + /* Uninstall pInstalledMap. No hardware changes required, just + * notify all interested parties. */ + if(oldpmap != (ColormapPtr)None) + WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); + /* Install pmap */ + SetInstalledColormap(pmap->pScreen, pmap); + WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); + } +} + +void +fbUninstallColormap(ColormapPtr pmap) +{ + ColormapPtr curpmap = GetInstalledColormap(pmap->pScreen); + + if(pmap == curpmap) + { + if (pmap->mid != pmap->pScreen->defColormap) + { + dixLookupResourceByType((pointer *)&curpmap, + pmap->pScreen->defColormap, + RT_COLORMAP, + serverClient, DixInstallAccess); + (*pmap->pScreen->InstallColormap)(curpmap); + } + } +} + +void +fbResolveColor(unsigned short *pred, + unsigned short *pgreen, + unsigned short *pblue, + VisualPtr pVisual) +{ + int shift = 16 - pVisual->bitsPerRGBValue; + unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1; + + if ((pVisual->class | DynamicClass) == GrayScale) + { + /* rescale to gray then rgb bits */ + *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100; + *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim; + } + else + { + /* rescale to rgb bits */ + *pred = ((*pred >> shift) * 65535) / lim; + *pgreen = ((*pgreen >> shift) * 65535) / lim; + *pblue = ((*pblue >> shift) * 65535) / lim; + } +} + +Bool +fbInitializeColormap(ColormapPtr pmap) +{ + register unsigned i; + register VisualPtr pVisual; + unsigned lim, maxent, shift; + + pVisual = pmap->pVisual; + lim = (1 << pVisual->bitsPerRGBValue) - 1; + shift = 16 - pVisual->bitsPerRGBValue; + maxent = pVisual->ColormapEntries - 1; + if (pVisual->class == TrueColor) + { + unsigned limr, limg, limb; + + limr = pVisual->redMask >> pVisual->offsetRed; + limg = pVisual->greenMask >> pVisual->offsetGreen; + limb = pVisual->blueMask >> pVisual->offsetBlue; + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = + ((((i * 65535) / limr) >> shift) * 65535) / lim; + pmap->green[i].co.local.green = + ((((i * 65535) / limg) >> shift) * 65535) / lim; + pmap->blue[i].co.local.blue = + ((((i * 65535) / limb) >> shift) * 65535) / lim; + } + } + else if (pVisual->class == StaticColor) + { + unsigned n; + unsigned r, g, b; + unsigned red, green, blue; + + for (n = 0; n*n*n < pVisual->ColormapEntries; n++) + ; + n--; + i = 0; + for (r = 0; r < n; r++) + { + red = (((r * 65535 / (n - 1)) >> shift) * 65535) / lim; + for (g = 0; g < n; g++) + { + green = (((g * 65535 / (n - 1)) >> shift) * 65535) / lim; + for (b = 0; b < n; b++) + { + blue = (((b * 65535 / (n - 1)) >> shift) * 65535) / lim; + pmap->red[i].co.local.red = red; + pmap->red[i].co.local.green = green; + pmap->red[i].co.local.blue = blue; + i++; + } + } + } + n = pVisual->ColormapEntries - i; + for (r = 0; r < n; r++) + { + red = (((r * 65535 / (n - 1)) >> shift) * 65535) / lim; + pmap->red[i].co.local.red = red; + pmap->red[i].co.local.green = red; + pmap->red[i].co.local.blue = red; + i++; + } + } + else if (pVisual->class == StaticGray) + { + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift) + * 65535) / lim; + pmap->red[i].co.local.green = pmap->red[i].co.local.red; + pmap->red[i].co.local.blue = pmap->red[i].co.local.red; + } + } + return TRUE; +} + +/* When simulating DirectColor on PseudoColor hardware, multiple + entries of the colormap must be updated + */ + +#define AddElement(mask) { \ + pixel = red | green | blue; \ + for (i = 0; i < nresult; i++) \ + if (outdefs[i].pixel == pixel) \ + break; \ + if (i == nresult) \ + { \ + nresult++; \ + outdefs[i].pixel = pixel; \ + outdefs[i].flags = 0; \ + } \ + outdefs[i].flags |= (mask); \ + outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \ + outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \ + outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \ +} + +int +fbExpandDirectColors (ColormapPtr pmap, + int ndef, + xColorItem *indefs, + xColorItem *outdefs) +{ + register int red, green, blue; + int maxred, maxgreen, maxblue; + int stepred, stepgreen, stepblue; + VisualPtr pVisual; + register int pixel; + register int nresult; + register int i; + + pVisual = pmap->pVisual; + + stepred = 1 << pVisual->offsetRed; + stepgreen = 1 << pVisual->offsetGreen; + stepblue = 1 << pVisual->offsetBlue; + maxred = pVisual->redMask; + maxgreen = pVisual->greenMask; + maxblue = pVisual->blueMask; + nresult = 0; + for (;ndef--; indefs++) + { + if (indefs->flags & DoRed) + { + red = indefs->pixel & pVisual->redMask; + for (green = 0; green <= maxgreen; green += stepgreen) + { + for (blue = 0; blue <= maxblue; blue += stepblue) + { + AddElement (DoRed) + } + } + } + if (indefs->flags & DoGreen) + { + green = indefs->pixel & pVisual->greenMask; + for (red = 0; red <= maxred; red += stepred) + { + for (blue = 0; blue <= maxblue; blue += stepblue) + { + AddElement (DoGreen) + } + } + } + if (indefs->flags & DoBlue) + { + blue = indefs->pixel & pVisual->blueMask; + for (red = 0; red <= maxred; red += stepred) + { + for (green = 0; green <= maxgreen; green += stepgreen) + { + AddElement (DoBlue) + } + } + } + } + return nresult; +} + +Bool +fbCreateDefColormap(ScreenPtr pScreen) +{ + unsigned short zero = 0, ones = 0xFFFF; + VisualPtr pVisual; + ColormapPtr cmap; + Pixel wp, bp; + + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++) + ; + + if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap, + (pVisual->class & DynamicClass) ? AllocNone : AllocAll, + 0) + != Success) + return FALSE; + wp = pScreen->whitePixel; + bp = pScreen->blackPixel; + if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) != + Success) || + (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) != + Success)) + return FALSE; + pScreen->whitePixel = wp; + pScreen->blackPixel = bp; + (*pScreen->InstallColormap)(cmap); + return TRUE; +} + +extern int defaultColorVisualClass; + +#define _RZ(d) ((d + 2) / 3) +#define _RS(d) 0 +#define _RM(d) ((1 << _RZ(d)) - 1) +#define _GZ(d) ((d - _RZ(d) + 1) / 2) +#define _GS(d) _RZ(d) +#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d)) +#define _BZ(d) (d - _RZ(d) - _GZ(d)) +#define _BS(d) (_RZ(d) + _GZ(d)) +#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d)) +#define _CE(d) (1 << _RZ(d)) + +#define MAX_PSEUDO_DEPTH 10 /* largest DAC size I know */ + +#define StaticGrayMask (1 << StaticGray) +#define GrayScaleMask (1 << GrayScale) +#define StaticColorMask (1 << StaticColor) +#define PseudoColorMask (1 << PseudoColor) +#define TrueColorMask (1 << TrueColor) +#define DirectColorMask (1 << DirectColor) + +#define ALL_VISUALS (StaticGrayMask|\ + GrayScaleMask|\ + StaticColorMask|\ + PseudoColorMask|\ + TrueColorMask|\ + DirectColorMask) + +#define LARGE_VISUALS (TrueColorMask|\ + DirectColorMask) + +typedef struct _fbVisuals { + struct _fbVisuals *next; + int depth; + int bitsPerRGB; + int visuals; + int count; + Pixel redMask, greenMask, blueMask; +} fbVisualsRec, *fbVisualsPtr; + +static const int fbVisualPriority[] = { + PseudoColor, DirectColor, GrayScale, StaticColor, TrueColor, StaticGray +}; + +#define NUM_PRIORITY 6 + +static fbVisualsPtr fbVisuals; + +static int +popCount (int i) +{ + int count; + + count = (i >> 1) & 033333333333; + count = i - count - ((count >> 1) & 033333333333); + count = (((count + (count >> 3)) & 030707070707) % 077); /* HAKMEM 169 */ + return count; +} + +/* + * Distance to least significant one bit + */ +static int +maskShift (Pixel p) +{ + int s; + + if (!p) return 0; + s = 0; + while (!(p & 1)) + { + s++; + p >>= 1; + } + return s; +} + +Bool +fbSetVisualTypesAndMasks (int depth, int visuals, int bitsPerRGB, + Pixel redMask, Pixel greenMask, Pixel blueMask) +{ + fbVisualsPtr new, *prev, v; + + new = (fbVisualsPtr) malloc(sizeof *new); + if (!new) + return FALSE; + if (!redMask || !greenMask || !blueMask) + { + redMask = _RM(depth); + greenMask = _GM(depth); + blueMask = _BM(depth); + } + new->next = 0; + new->depth = depth; + new->visuals = visuals; + new->bitsPerRGB = bitsPerRGB; + new->redMask = redMask; + new->greenMask = greenMask; + new->blueMask = blueMask; + new->count = popCount (visuals); + for (prev = &fbVisuals; (v = *prev); prev = &v->next); + *prev = new; + return TRUE; +} + +Bool +fbHasVisualTypes (int depth) +{ + fbVisualsPtr v; + + for (v = fbVisuals; v; v = v->next) + if (v->depth == depth) + return TRUE; + return FALSE; +} + +Bool +fbSetVisualTypes (int depth, int visuals, int bitsPerRGB) +{ + return fbSetVisualTypesAndMasks (depth, visuals, bitsPerRGB, + _RM(depth), _GM(depth), _BM(depth)); +} + +/* + * Given a list of formats for a screen, create a list + * of visuals and depths for the screen which coorespond to + * the set which can be used with this version of fb. + */ + +Bool +fbInitVisuals (VisualPtr *visualp, + DepthPtr *depthp, + int *nvisualp, + int *ndepthp, + int *rootDepthp, + VisualID *defaultVisp, + unsigned long sizes, + int bitsPerRGB) +{ + int i, j = 0, k; + VisualPtr visual; + DepthPtr depth; + VisualID *vid; + int d, b; + int f; + int ndepth, nvisual; + int nvtype; + int vtype; + fbVisualsPtr visuals, nextVisuals; + + /* none specified, we'll guess from pixmap formats */ + if (!fbVisuals) + { + for (f = 0; f < screenInfo.numPixmapFormats; f++) + { + d = screenInfo.formats[f].depth; + b = screenInfo.formats[f].bitsPerPixel; + if (sizes & (1 << (b - 1))) + { + if (d > MAX_PSEUDO_DEPTH) + vtype = LARGE_VISUALS; + else if (d == 1) + vtype = StaticGrayMask; + else + vtype = ALL_VISUALS; + } + else + vtype = 0; + if (!fbSetVisualTypes (d, vtype, bitsPerRGB)) + return FALSE; + } + } + nvisual = 0; + ndepth = 0; + for (visuals = fbVisuals; visuals; visuals = nextVisuals) + { + nextVisuals = visuals->next; + ndepth++; + nvisual += visuals->count; + } + depth = (DepthPtr) malloc(ndepth * sizeof (DepthRec)); + visual = (VisualPtr) malloc(nvisual * sizeof (VisualRec)); + if (!depth || !visual) + { + free(depth); + free(visual); + return FALSE; + } + *depthp = depth; + *visualp = visual; + *ndepthp = ndepth; + *nvisualp = nvisual; + for (visuals = fbVisuals; visuals; visuals = nextVisuals) + { + nextVisuals = visuals->next; + d = visuals->depth; + vtype = visuals->visuals; + nvtype = visuals->count; + vid = NULL; + if (nvtype) + { + vid = (VisualID *) malloc(nvtype * sizeof (VisualID)); + if (!vid) + return FALSE; + } + depth->depth = d; + depth->numVids = nvtype; + depth->vids = vid; + depth++; + for (i = 0; i < NUM_PRIORITY; i++) { + if (! (vtype & (1 << fbVisualPriority[i]))) + continue; + visual->class = fbVisualPriority[i]; + visual->bitsPerRGBValue = visuals->bitsPerRGB; + visual->ColormapEntries = 1 << d; + visual->nplanes = d; + visual->vid = *vid = FakeClientID (0); + switch (visual->class) { + case PseudoColor: + case GrayScale: + case StaticGray: + case StaticColor: + visual->redMask = 0; + visual->greenMask = 0; + visual->blueMask = 0; + visual->offsetRed = 0; + visual->offsetGreen = 0; + visual->offsetBlue = 0; + break; + case DirectColor: + case TrueColor: + visual->ColormapEntries = _CE(d); + visual->redMask = visuals->redMask; + visual->greenMask = visuals->greenMask; + visual->blueMask = visuals->blueMask; + visual->offsetRed = maskShift (visuals->redMask); + visual->offsetGreen = maskShift (visuals->greenMask); + visual->offsetBlue = maskShift (visuals->blueMask); + } + vid++; + visual++; + } + free(visuals); + } + fbVisuals = NULL; + visual = *visualp; + depth = *depthp; + for (i = 0; i < ndepth; i++) + { + if (*rootDepthp && *rootDepthp != depth[i].depth) + continue; + for (j = 0; j < depth[i].numVids; j++) + { + for (k = 0; k < nvisual; k++) + if (visual[k].vid == depth[i].vids[j]) + break; + if (k == nvisual) + continue; + if (defaultColorVisualClass < 0 || + visual[k].class == defaultColorVisualClass) + break; + } + if (j != depth[i].numVids) + break; + } + if (i == ndepth) { + for (i = 0; i < ndepth; i++) + { + if (depth[i].numVids) + break; + } + if (i == ndepth) + return FALSE; + j = 0; + } + *rootDepthp = depth[i].depth; + *defaultVisp = depth[i].vids[j]; + return TRUE; +} diff --git a/xorg-server/fb/fbcopy.c b/xorg-server/fb/fbcopy.c index 07eb663c6..30cbf7b25 100644 --- a/xorg-server/fb/fbcopy.c +++ b/xorg-server/fb/fbcopy.c @@ -1,374 +1,374 @@ -/* - * Copyright © 1998 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 - -#include "fb.h" - -/* Compatibility wrapper, to be removed at next ABI change. */ -void -fbCopyRegion (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - RegionPtr pDstRegion, - int dx, - int dy, - fbCopyProc copyProc, - Pixel bitPlane, - void *closure) -{ - miCopyRegion(pSrcDrawable, pDstDrawable, pGC, pDstRegion, dx, dy, copyProc, bitPlane, closure); -} - -/* Compatibility wrapper, to be removed at next ABI change. */ -RegionPtr -fbDoCopy (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - int xIn, - int yIn, - int widthSrc, - int heightSrc, - int xOut, - int yOut, - fbCopyProc copyProc, - Pixel bitPlane, - void *closure) -{ - return miDoCopy(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, widthSrc, heightSrc, xOut, yOut, copyProc, bitPlane, closure); -} - -void -fbCopyNtoN (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - BoxPtr pbox, - int nbox, - int dx, - int dy, - Bool reverse, - Bool upsidedown, - Pixel bitplane, - void *closure) -{ - CARD8 alu = pGC ? pGC->alu : GXcopy; - FbBits pm = pGC ? fbGetGCPrivate(pGC)->pm : FB_ALLONES; - FbBits *src; - FbStride srcStride; - int srcBpp; - int srcXoff, srcYoff; - FbBits *dst; - FbStride dstStride; - int dstBpp; - int dstXoff, dstYoff; - - fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); - fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); - - while (nbox--) - { -#ifndef FB_ACCESS_WRAPPER /* pixman_blt() doesn't support accessors yet */ - if (pm == FB_ALLONES && alu == GXcopy && !reverse && - !upsidedown) - { - if (!pixman_blt ((uint32_t *)src, (uint32_t *)dst, srcStride, dstStride, srcBpp, dstBpp, - (pbox->x1 + dx + srcXoff), - (pbox->y1 + dy + srcYoff), - (pbox->x1 + dstXoff), - (pbox->y1 + dstYoff), - (pbox->x2 - pbox->x1), - (pbox->y2 - pbox->y1))) - goto fallback; - else - goto next; - } - fallback: -#endif - fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride, - srcStride, - (pbox->x1 + dx + srcXoff) * srcBpp, - - dst + (pbox->y1 + dstYoff) * dstStride, - dstStride, - (pbox->x1 + dstXoff) * dstBpp, - - (pbox->x2 - pbox->x1) * dstBpp, - (pbox->y2 - pbox->y1), - - alu, - pm, - dstBpp, - - reverse, - upsidedown); -#ifndef FB_ACCESS_WRAPPER - next: -#endif - pbox++; - } - fbFinishAccess (pDstDrawable); - fbFinishAccess (pSrcDrawable); -} - -void -fbCopy1toN (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - BoxPtr pbox, - int nbox, - int dx, - int dy, - Bool reverse, - Bool upsidedown, - Pixel bitplane, - void *closure) -{ - FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); - FbBits *src; - FbStride srcStride; - int srcBpp; - int srcXoff, srcYoff; - FbBits *dst; - FbStride dstStride; - int dstBpp; - int dstXoff, dstYoff; - - fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); - fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); - - while (nbox--) - { - if (dstBpp == 1) - { - fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride, - srcStride, - (pbox->x1 + dx + srcXoff) * srcBpp, - - dst + (pbox->y1 + dstYoff) * dstStride, - dstStride, - (pbox->x1 + dstXoff) * dstBpp, - - (pbox->x2 - pbox->x1) * dstBpp, - (pbox->y2 - pbox->y1), - - FbOpaqueStipple1Rop(pGC->alu, - pGC->fgPixel,pGC->bgPixel), - pPriv->pm, - dstBpp, - - reverse, - upsidedown); - } - else - { - fbBltOne ((FbStip *) (src + (pbox->y1 + dy + srcYoff) * srcStride), - srcStride*(FB_UNIT/FB_STIP_UNIT), - (pbox->x1 + dx + srcXoff), - - dst + (pbox->y1 + dstYoff) * dstStride, - dstStride, - (pbox->x1 + dstXoff) * dstBpp, - dstBpp, - - (pbox->x2 - pbox->x1) * dstBpp, - (pbox->y2 - pbox->y1), - - pPriv->and, pPriv->xor, - pPriv->bgand, pPriv->bgxor); - } - pbox++; - } - - fbFinishAccess (pDstDrawable); - fbFinishAccess (pSrcDrawable); -} - -void -fbCopyNto1 (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - BoxPtr pbox, - int nbox, - int dx, - int dy, - Bool reverse, - Bool upsidedown, - Pixel bitplane, - void *closure) -{ - FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); - - while (nbox--) - { - if (pDstDrawable->bitsPerPixel == 1) - { - FbBits *src; - FbStride srcStride; - int srcBpp; - int srcXoff, srcYoff; - - FbStip *dst; - FbStride dstStride; - int dstBpp; - int dstXoff, dstYoff; - - fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); - fbGetStipDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); - fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride, - srcStride, - (pbox->x1 + dx + srcXoff) * srcBpp, - srcBpp, - - dst + (pbox->y1 + dstYoff) * dstStride, - dstStride, - (pbox->x1 + dstXoff) * dstBpp, - - (pbox->x2 - pbox->x1) * srcBpp, - (pbox->y2 - pbox->y1), - - (FbStip) pPriv->and, (FbStip) pPriv->xor, - (FbStip) pPriv->bgand, (FbStip) pPriv->bgxor, - bitplane); - fbFinishAccess (pDstDrawable); - fbFinishAccess (pSrcDrawable); - } - else - { - FbBits *src; - FbStride srcStride; - int srcBpp; - int srcXoff, srcYoff; - - FbBits *dst; - FbStride dstStride; - int dstBpp; - int dstXoff, dstYoff; - - FbStip *tmp; - FbStride tmpStride; - int width, height; - - width = pbox->x2 - pbox->x1; - height = pbox->y2 - pbox->y1; - - tmpStride = ((width + FB_STIP_MASK) >> FB_STIP_SHIFT); - tmp = xalloc (tmpStride * height * sizeof (FbStip)); - if (!tmp) - return; - - fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); - fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); - - fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride, - srcStride, - (pbox->x1 + dx + srcXoff) * srcBpp, - srcBpp, - - tmp, - tmpStride, - 0, - - width * srcBpp, - height, - - fbAndStip(GXcopy,FB_ALLONES,FB_ALLONES), - fbXorStip(GXcopy,FB_ALLONES,FB_ALLONES), - fbAndStip(GXcopy,0,FB_ALLONES), - fbXorStip(GXcopy,0,FB_ALLONES), - bitplane); - fbBltOne (tmp, - tmpStride, - 0, - - dst + (pbox->y1 + dstYoff) * dstStride, - dstStride, - (pbox->x1 + dstXoff) * dstBpp, - dstBpp, - - width * dstBpp, - height, - - pPriv->and, pPriv->xor, - pPriv->bgand, pPriv->bgxor); - xfree (tmp); - - fbFinishAccess (pDstDrawable); - fbFinishAccess (pSrcDrawable); - } - pbox++; - } -} - -RegionPtr -fbCopyArea (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - int xIn, - int yIn, - int widthSrc, - int heightSrc, - int xOut, - int yOut) -{ - miCopyProc copy; - -#ifdef FB_24_32BIT - if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) - copy = fb24_32CopyMtoN; - else -#endif - copy = fbCopyNtoN; - return miDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn, - widthSrc, heightSrc, xOut, yOut, copy, 0, 0); -} - -RegionPtr -fbCopyPlane (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - int xIn, - int yIn, - int widthSrc, - int heightSrc, - int xOut, - int yOut, - unsigned long bitplane) -{ - if (pSrcDrawable->bitsPerPixel > 1) - return miDoCopy (pSrcDrawable, pDstDrawable, pGC, - xIn, yIn, widthSrc, heightSrc, - xOut, yOut, fbCopyNto1, (Pixel) bitplane, 0); - else if (bitplane & 1) - return miDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn, - widthSrc, heightSrc, xOut, yOut, fbCopy1toN, - (Pixel) bitplane, 0); - else - return miHandleExposures(pSrcDrawable, pDstDrawable, pGC, - xIn, yIn, - widthSrc, - heightSrc, - xOut, yOut, bitplane); -} +/* + * Copyright © 1998 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 + +#include "fb.h" + +/* Compatibility wrapper, to be removed at next ABI change. */ +void +fbCopyRegion (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + RegionPtr pDstRegion, + int dx, + int dy, + fbCopyProc copyProc, + Pixel bitPlane, + void *closure) +{ + miCopyRegion(pSrcDrawable, pDstDrawable, pGC, pDstRegion, dx, dy, copyProc, bitPlane, closure); +} + +/* Compatibility wrapper, to be removed at next ABI change. */ +RegionPtr +fbDoCopy (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int yOut, + fbCopyProc copyProc, + Pixel bitPlane, + void *closure) +{ + return miDoCopy(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, widthSrc, heightSrc, xOut, yOut, copyProc, bitPlane, closure); +} + +void +fbCopyNtoN (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure) +{ + CARD8 alu = pGC ? pGC->alu : GXcopy; + FbBits pm = pGC ? fbGetGCPrivate(pGC)->pm : FB_ALLONES; + FbBits *src; + FbStride srcStride; + int srcBpp; + int srcXoff, srcYoff; + FbBits *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + + fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); + fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + + while (nbox--) + { +#ifndef FB_ACCESS_WRAPPER /* pixman_blt() doesn't support accessors yet */ + if (pm == FB_ALLONES && alu == GXcopy && !reverse && + !upsidedown) + { + if (!pixman_blt ((uint32_t *)src, (uint32_t *)dst, srcStride, dstStride, srcBpp, dstBpp, + (pbox->x1 + dx + srcXoff), + (pbox->y1 + dy + srcYoff), + (pbox->x1 + dstXoff), + (pbox->y1 + dstYoff), + (pbox->x2 - pbox->x1), + (pbox->y2 - pbox->y1))) + goto fallback; + else + goto next; + } + fallback: +#endif + fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride, + srcStride, + (pbox->x1 + dx + srcXoff) * srcBpp, + + dst + (pbox->y1 + dstYoff) * dstStride, + dstStride, + (pbox->x1 + dstXoff) * dstBpp, + + (pbox->x2 - pbox->x1) * dstBpp, + (pbox->y2 - pbox->y1), + + alu, + pm, + dstBpp, + + reverse, + upsidedown); +#ifndef FB_ACCESS_WRAPPER + next: +#endif + pbox++; + } + fbFinishAccess (pDstDrawable); + fbFinishAccess (pSrcDrawable); +} + +void +fbCopy1toN (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure) +{ + FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); + FbBits *src; + FbStride srcStride; + int srcBpp; + int srcXoff, srcYoff; + FbBits *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + + fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); + fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + + while (nbox--) + { + if (dstBpp == 1) + { + fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride, + srcStride, + (pbox->x1 + dx + srcXoff) * srcBpp, + + dst + (pbox->y1 + dstYoff) * dstStride, + dstStride, + (pbox->x1 + dstXoff) * dstBpp, + + (pbox->x2 - pbox->x1) * dstBpp, + (pbox->y2 - pbox->y1), + + FbOpaqueStipple1Rop(pGC->alu, + pGC->fgPixel,pGC->bgPixel), + pPriv->pm, + dstBpp, + + reverse, + upsidedown); + } + else + { + fbBltOne ((FbStip *) (src + (pbox->y1 + dy + srcYoff) * srcStride), + srcStride*(FB_UNIT/FB_STIP_UNIT), + (pbox->x1 + dx + srcXoff), + + dst + (pbox->y1 + dstYoff) * dstStride, + dstStride, + (pbox->x1 + dstXoff) * dstBpp, + dstBpp, + + (pbox->x2 - pbox->x1) * dstBpp, + (pbox->y2 - pbox->y1), + + pPriv->and, pPriv->xor, + pPriv->bgand, pPriv->bgxor); + } + pbox++; + } + + fbFinishAccess (pDstDrawable); + fbFinishAccess (pSrcDrawable); +} + +void +fbCopyNto1 (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure) +{ + FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); + + while (nbox--) + { + if (pDstDrawable->bitsPerPixel == 1) + { + FbBits *src; + FbStride srcStride; + int srcBpp; + int srcXoff, srcYoff; + + FbStip *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + + fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); + fbGetStipDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride, + srcStride, + (pbox->x1 + dx + srcXoff) * srcBpp, + srcBpp, + + dst + (pbox->y1 + dstYoff) * dstStride, + dstStride, + (pbox->x1 + dstXoff) * dstBpp, + + (pbox->x2 - pbox->x1) * srcBpp, + (pbox->y2 - pbox->y1), + + (FbStip) pPriv->and, (FbStip) pPriv->xor, + (FbStip) pPriv->bgand, (FbStip) pPriv->bgxor, + bitplane); + fbFinishAccess (pDstDrawable); + fbFinishAccess (pSrcDrawable); + } + else + { + FbBits *src; + FbStride srcStride; + int srcBpp; + int srcXoff, srcYoff; + + FbBits *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + + FbStip *tmp; + FbStride tmpStride; + int width, height; + + width = pbox->x2 - pbox->x1; + height = pbox->y2 - pbox->y1; + + tmpStride = ((width + FB_STIP_MASK) >> FB_STIP_SHIFT); + tmp = malloc(tmpStride * height * sizeof (FbStip)); + if (!tmp) + return; + + fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); + fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + + fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride, + srcStride, + (pbox->x1 + dx + srcXoff) * srcBpp, + srcBpp, + + tmp, + tmpStride, + 0, + + width * srcBpp, + height, + + fbAndStip(GXcopy,FB_ALLONES,FB_ALLONES), + fbXorStip(GXcopy,FB_ALLONES,FB_ALLONES), + fbAndStip(GXcopy,0,FB_ALLONES), + fbXorStip(GXcopy,0,FB_ALLONES), + bitplane); + fbBltOne (tmp, + tmpStride, + 0, + + dst + (pbox->y1 + dstYoff) * dstStride, + dstStride, + (pbox->x1 + dstXoff) * dstBpp, + dstBpp, + + width * dstBpp, + height, + + pPriv->and, pPriv->xor, + pPriv->bgand, pPriv->bgxor); + free(tmp); + + fbFinishAccess (pDstDrawable); + fbFinishAccess (pSrcDrawable); + } + pbox++; + } +} + +RegionPtr +fbCopyArea (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int yOut) +{ + miCopyProc copy; + +#ifdef FB_24_32BIT + if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) + copy = fb24_32CopyMtoN; + else +#endif + copy = fbCopyNtoN; + return miDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn, + widthSrc, heightSrc, xOut, yOut, copy, 0, 0); +} + +RegionPtr +fbCopyPlane (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int yOut, + unsigned long bitplane) +{ + if (pSrcDrawable->bitsPerPixel > 1) + return miDoCopy (pSrcDrawable, pDstDrawable, pGC, + xIn, yIn, widthSrc, heightSrc, + xOut, yOut, fbCopyNto1, (Pixel) bitplane, 0); + else if (bitplane & 1) + return miDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn, + widthSrc, heightSrc, xOut, yOut, fbCopy1toN, + (Pixel) bitplane, 0); + else + return miHandleExposures(pSrcDrawable, pDstDrawable, pGC, + xIn, yIn, + widthSrc, + heightSrc, + xOut, yOut, bitplane); +} diff --git a/xorg-server/fb/fboverlay.c b/xorg-server/fb/fboverlay.c index 99939e8bf..f14187cba 100644 --- a/xorg-server/fb/fboverlay.c +++ b/xorg-server/fb/fboverlay.c @@ -1,437 +1,437 @@ -/* - * - * Copyright © 2000 SuSE, Inc. - * - * 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 SuSE not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. SuSE makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - * - * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE - * 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. - * - * Author: Keith Packard, SuSE, Inc. - */ - - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "fb.h" -#include "fboverlay.h" -#include "shmint.h" - -static int fbOverlayScreenPrivateKeyIndex; -static DevPrivateKey fbOverlayScreenPrivateKey = &fbOverlayScreenPrivateKeyIndex; - -DevPrivateKey fbOverlayGetScreenPrivateKey(void) -{ - return fbOverlayScreenPrivateKey; -} - -/* - * Replace this if you want something supporting - * multiple overlays with the same depth - */ -Bool -fbOverlayCreateWindow(WindowPtr pWin) -{ - FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); - int i; - PixmapPtr pPixmap; - - if (pWin->drawable.class != InputOutput) - return TRUE; - -#ifdef FB_SCREEN_PRIVATE - if (pWin->drawable.bitsPerPixel == 32) - pWin->drawable.bitsPerPixel = fbGetScreenPrivate(pWin->drawable.pScreen)->win32bpp; -#endif - - for (i = 0; i < pScrPriv->nlayers; i++) - { - pPixmap = pScrPriv->layer[i].u.run.pixmap; - if (pWin->drawable.depth == pPixmap->drawable.depth) - { - dixSetPrivate(&pWin->devPrivates, fbGetWinPrivateKey(), pPixmap); - /* - * Make sure layer keys are written correctly by - * having non-root layers set to full while the - * root layer is set to empty. This will cause - * all of the layers to get painted when the root - * is mapped - */ - if (!pWin->parent) - { - REGION_EMPTY (pWin->drawable.pScreen, - &pScrPriv->layer[i].u.run.region); - } - return TRUE; - } - } - return FALSE; -} - -Bool -fbOverlayCloseScreen (int iScreen, ScreenPtr pScreen) -{ - FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); - int i; - - for (i = 0; i < pScrPriv->nlayers; i++) - { - (*pScreen->DestroyPixmap)(pScrPriv->layer[i].u.run.pixmap); - REGION_UNINIT (pScreen, &pScrPriv->layer[i].u.run.region); - } - return TRUE; -} - -/* - * Return layer containing this window - */ -int -fbOverlayWindowLayer(WindowPtr pWin) -{ - FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); - int i; - - for (i = 0; i < pScrPriv->nlayers; i++) - if (dixLookupPrivate(&pWin->devPrivates, fbGetWinPrivateKey()) == - (pointer) pScrPriv->layer[i].u.run.pixmap) - return i; - return 0; -} - -Bool -fbOverlayCreateScreenResources(ScreenPtr pScreen) -{ - int i; - FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); - PixmapPtr pPixmap; - pointer pbits; - int width; - int depth; - BoxRec box; - - if (!miCreateScreenResources(pScreen)) - return FALSE; - - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - for (i = 0; i < pScrPriv->nlayers; i++) - { - pbits = pScrPriv->layer[i].u.init.pbits; - width = pScrPriv->layer[i].u.init.width; - depth = pScrPriv->layer[i].u.init.depth; - pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0); - if (!pPixmap) - return FALSE; - if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width, - pScreen->height, depth, - BitsPerPixel(depth), - PixmapBytePad(width, depth), - pbits)) - return FALSE; - pScrPriv->layer[i].u.run.pixmap = pPixmap; - REGION_INIT(pScreen, &pScrPriv->layer[i].u.run.region, &box, 0); - } - pScreen->devPrivate = pScrPriv->layer[0].u.run.pixmap; - return TRUE; -} - -void -fbOverlayPaintKey (DrawablePtr pDrawable, - RegionPtr pRegion, - CARD32 pixel, - int layer) -{ - fbFillRegionSolid (pDrawable, pRegion, 0, - fbReplicatePixel (pixel, pDrawable->bitsPerPixel)); -} - -/* - * Track visible region for each layer - */ -void -fbOverlayUpdateLayerRegion (ScreenPtr pScreen, - int layer, - RegionPtr prgn) -{ - FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); - int i; - RegionRec rgnNew; - - if (!prgn || !REGION_NOTEMPTY(pScreen, prgn)) - return; - for (i = 0; i < pScrPriv->nlayers; i++) - { - if (i == layer) - { - /* add new piece to this fb */ - REGION_UNION (pScreen, - &pScrPriv->layer[i].u.run.region, - &pScrPriv->layer[i].u.run.region, - prgn); - } - else if (REGION_NOTEMPTY (pScreen, - &pScrPriv->layer[i].u.run.region)) - { - /* paint new piece with chroma key */ - REGION_NULL (pScreen, &rgnNew); - REGION_INTERSECT (pScreen, - &rgnNew, - prgn, - &pScrPriv->layer[i].u.run.region); - (*pScrPriv->PaintKey) (&pScrPriv->layer[i].u.run.pixmap->drawable, - &rgnNew, - pScrPriv->layer[i].key, - i); - REGION_UNINIT(pScreen, &rgnNew); - /* remove piece from other fbs */ - REGION_SUBTRACT (pScreen, - &pScrPriv->layer[i].u.run.region, - &pScrPriv->layer[i].u.run.region, - prgn); - } - } -} - -/* - * Copy only areas in each layer containing real bits - */ -void -fbOverlayCopyWindow(WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); - RegionRec rgnDst; - int dx, dy; - int i; - RegionRec layerRgn[FB_OVERLAY_MAX]; - PixmapPtr pPixmap; - - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - - /* - * Clip to existing bits - */ - REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); - REGION_NULL (pScreen, &rgnDst); - REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); - REGION_TRANSLATE(pScreen, &rgnDst, dx, dy); - /* - * Compute the portion of each fb affected by this copy - */ - for (i = 0; i < pScrPriv->nlayers; i++) - { - REGION_NULL (pScreen, &layerRgn[i]); - REGION_INTERSECT(pScreen, &layerRgn[i], &rgnDst, - &pScrPriv->layer[i].u.run.region); - if (REGION_NOTEMPTY (pScreen, &layerRgn[i])) - { - REGION_TRANSLATE(pScreen, &layerRgn[i], -dx, -dy); - pPixmap = pScrPriv->layer[i].u.run.pixmap; - miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, - 0, - &layerRgn[i], dx, dy, pScrPriv->CopyWindow, 0, - (void *)(long) i); - } - } - /* - * Update regions - */ - for (i = 0; i < pScrPriv->nlayers; i++) - { - if (REGION_NOTEMPTY (pScreen, &layerRgn[i])) - fbOverlayUpdateLayerRegion (pScreen, i, &layerRgn[i]); - - REGION_UNINIT(pScreen, &layerRgn[i]); - } - REGION_UNINIT(pScreen, &rgnDst); -} - -void -fbOverlayWindowExposures (WindowPtr pWin, - RegionPtr prgn, - RegionPtr other_exposed) -{ - fbOverlayUpdateLayerRegion (pWin->drawable.pScreen, - fbOverlayWindowLayer (pWin), - prgn); - miWindowExposures(pWin, prgn, other_exposed); -} - -Bool -fbOverlaySetupScreen(ScreenPtr pScreen, - pointer pbits1, - pointer pbits2, - int xsize, - int ysize, - int dpix, - int dpiy, - int width1, - int width2, - int bpp1, - int bpp2) -{ - return fbSetupScreen (pScreen, - pbits1, - xsize, - ysize, - dpix, - dpiy, - width1, - bpp1); -} - -static Bool -fb24_32OverlayCreateScreenResources(ScreenPtr pScreen) -{ - FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); - int pitch; - Bool retval; - int i; - - if((retval = fbOverlayCreateScreenResources(pScreen))) { - for (i = 0; i < pScrPriv->nlayers; i++) - { - /* fix the screen pixmap */ - PixmapPtr pPix = (PixmapPtr) pScrPriv->layer[i].u.run.pixmap; - if (pPix->drawable.bitsPerPixel == 32) { - pPix->drawable.bitsPerPixel = 24; - pitch = BitmapBytePad(pPix->drawable.width * 24); - pPix->devKind = pitch; - } - } - } - - return retval; -} - -Bool -fbOverlayFinishScreenInit(ScreenPtr pScreen, - pointer pbits1, - pointer pbits2, - int xsize, - int ysize, - int dpix, - int dpiy, - int width1, - int width2, - int bpp1, - int bpp2, - int depth1, - int depth2) -{ - VisualPtr visuals; - DepthPtr depths; - int nvisuals; - int ndepths; - int bpp = 0, imagebpp = 32; - VisualID defaultVisual; - FbOverlayScrPrivPtr pScrPriv; - - pScrPriv = xalloc (sizeof (FbOverlayScrPrivRec)); - if (!pScrPriv) - return FALSE; - -#ifdef FB_24_32BIT - if (bpp1 == 32 || bpp2 == 32) - bpp = 32; - else if (bpp1 == 24 || bpp2 == 24) - bpp = 24; - - if (bpp == 24) - { - int f; - - imagebpp = 32; - /* - * Check to see if we're advertising a 24bpp image format, - * in which case windows will use it in preference to a 32 bit - * format. - */ - for (f = 0; f < screenInfo.numPixmapFormats; f++) - { - if (screenInfo.formats[f].bitsPerPixel == 24) - { - imagebpp = 24; - break; - } - } - } -#endif -#ifdef FB_SCREEN_PRIVATE - if (imagebpp == 32) - { - fbGetScreenPrivate(pScreen)->win32bpp = bpp; - fbGetScreenPrivate(pScreen)->pix32bpp = bpp; - } - else - { - fbGetScreenPrivate(pScreen)->win32bpp = 32; - fbGetScreenPrivate(pScreen)->pix32bpp = 32; - } -#endif - - if (!fbInitVisuals (&visuals, &depths, &nvisuals, &ndepths, &depth1, - &defaultVisual, ((unsigned long)1<<(bpp1-1)) | - ((unsigned long)1<<(bpp2-1)), 8)) - return FALSE; - if (! miScreenInit(pScreen, 0, xsize, ysize, dpix, dpiy, 0, - depth1, ndepths, depths, - defaultVisual, nvisuals, visuals)) - return FALSE; - /* MI thinks there's no frame buffer */ -#ifdef MITSHM - ShmRegisterFbFuncs(pScreen); -#endif - pScreen->minInstalledCmaps = 1; - pScreen->maxInstalledCmaps = 2; - - pScrPriv->nlayers = 2; - pScrPriv->PaintKey = fbOverlayPaintKey; - pScrPriv->CopyWindow = fbCopyWindowProc; - pScrPriv->layer[0].u.init.pbits = pbits1; - pScrPriv->layer[0].u.init.width = width1; - pScrPriv->layer[0].u.init.depth = depth1; - - pScrPriv->layer[1].u.init.pbits = pbits2; - pScrPriv->layer[1].u.init.width = width2; - pScrPriv->layer[1].u.init.depth = depth2; - - dixSetPrivate(&pScreen->devPrivates, fbOverlayScreenPrivateKey, pScrPriv); - - /* overwrite miCloseScreen with our own */ - pScreen->CloseScreen = fbOverlayCloseScreen; - pScreen->CreateScreenResources = fbOverlayCreateScreenResources; - pScreen->CreateWindow = fbOverlayCreateWindow; - pScreen->WindowExposures = fbOverlayWindowExposures; - pScreen->CopyWindow = fbOverlayCopyWindow; -#ifdef FB_24_32BIT - if (bpp == 24 && imagebpp == 32) - { - pScreen->ModifyPixmapHeader = fb24_32ModifyPixmapHeader; - pScreen->CreateScreenResources = fb24_32OverlayCreateScreenResources; - } -#endif - - return TRUE; -} +/* + * + * Copyright © 2000 SuSE, Inc. + * + * 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 SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * 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. + * + * Author: Keith Packard, SuSE, Inc. + */ + + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "fb.h" +#include "fboverlay.h" +#include "shmint.h" + +static int fbOverlayScreenPrivateKeyIndex; +static DevPrivateKey fbOverlayScreenPrivateKey = &fbOverlayScreenPrivateKeyIndex; + +DevPrivateKey fbOverlayGetScreenPrivateKey(void) +{ + return fbOverlayScreenPrivateKey; +} + +/* + * Replace this if you want something supporting + * multiple overlays with the same depth + */ +Bool +fbOverlayCreateWindow(WindowPtr pWin) +{ + FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); + int i; + PixmapPtr pPixmap; + + if (pWin->drawable.class != InputOutput) + return TRUE; + +#ifdef FB_SCREEN_PRIVATE + if (pWin->drawable.bitsPerPixel == 32) + pWin->drawable.bitsPerPixel = fbGetScreenPrivate(pWin->drawable.pScreen)->win32bpp; +#endif + + for (i = 0; i < pScrPriv->nlayers; i++) + { + pPixmap = pScrPriv->layer[i].u.run.pixmap; + if (pWin->drawable.depth == pPixmap->drawable.depth) + { + dixSetPrivate(&pWin->devPrivates, fbGetWinPrivateKey(), pPixmap); + /* + * Make sure layer keys are written correctly by + * having non-root layers set to full while the + * root layer is set to empty. This will cause + * all of the layers to get painted when the root + * is mapped + */ + if (!pWin->parent) + { + REGION_EMPTY (pWin->drawable.pScreen, + &pScrPriv->layer[i].u.run.region); + } + return TRUE; + } + } + return FALSE; +} + +Bool +fbOverlayCloseScreen (int iScreen, ScreenPtr pScreen) +{ + FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); + int i; + + for (i = 0; i < pScrPriv->nlayers; i++) + { + (*pScreen->DestroyPixmap)(pScrPriv->layer[i].u.run.pixmap); + REGION_UNINIT (pScreen, &pScrPriv->layer[i].u.run.region); + } + return TRUE; +} + +/* + * Return layer containing this window + */ +int +fbOverlayWindowLayer(WindowPtr pWin) +{ + FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); + int i; + + for (i = 0; i < pScrPriv->nlayers; i++) + if (dixLookupPrivate(&pWin->devPrivates, fbGetWinPrivateKey()) == + (pointer) pScrPriv->layer[i].u.run.pixmap) + return i; + return 0; +} + +Bool +fbOverlayCreateScreenResources(ScreenPtr pScreen) +{ + int i; + FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); + PixmapPtr pPixmap; + pointer pbits; + int width; + int depth; + BoxRec box; + + if (!miCreateScreenResources(pScreen)) + return FALSE; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + for (i = 0; i < pScrPriv->nlayers; i++) + { + pbits = pScrPriv->layer[i].u.init.pbits; + width = pScrPriv->layer[i].u.init.width; + depth = pScrPriv->layer[i].u.init.depth; + pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0); + if (!pPixmap) + return FALSE; + if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width, + pScreen->height, depth, + BitsPerPixel(depth), + PixmapBytePad(width, depth), + pbits)) + return FALSE; + pScrPriv->layer[i].u.run.pixmap = pPixmap; + REGION_INIT(pScreen, &pScrPriv->layer[i].u.run.region, &box, 0); + } + pScreen->devPrivate = pScrPriv->layer[0].u.run.pixmap; + return TRUE; +} + +void +fbOverlayPaintKey (DrawablePtr pDrawable, + RegionPtr pRegion, + CARD32 pixel, + int layer) +{ + fbFillRegionSolid (pDrawable, pRegion, 0, + fbReplicatePixel (pixel, pDrawable->bitsPerPixel)); +} + +/* + * Track visible region for each layer + */ +void +fbOverlayUpdateLayerRegion (ScreenPtr pScreen, + int layer, + RegionPtr prgn) +{ + FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); + int i; + RegionRec rgnNew; + + if (!prgn || !REGION_NOTEMPTY(pScreen, prgn)) + return; + for (i = 0; i < pScrPriv->nlayers; i++) + { + if (i == layer) + { + /* add new piece to this fb */ + REGION_UNION (pScreen, + &pScrPriv->layer[i].u.run.region, + &pScrPriv->layer[i].u.run.region, + prgn); + } + else if (REGION_NOTEMPTY (pScreen, + &pScrPriv->layer[i].u.run.region)) + { + /* paint new piece with chroma key */ + REGION_NULL (pScreen, &rgnNew); + REGION_INTERSECT (pScreen, + &rgnNew, + prgn, + &pScrPriv->layer[i].u.run.region); + (*pScrPriv->PaintKey) (&pScrPriv->layer[i].u.run.pixmap->drawable, + &rgnNew, + pScrPriv->layer[i].key, + i); + REGION_UNINIT(pScreen, &rgnNew); + /* remove piece from other fbs */ + REGION_SUBTRACT (pScreen, + &pScrPriv->layer[i].u.run.region, + &pScrPriv->layer[i].u.run.region, + prgn); + } + } +} + +/* + * Copy only areas in each layer containing real bits + */ +void +fbOverlayCopyWindow(WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); + RegionRec rgnDst; + int dx, dy; + int i; + RegionRec layerRgn[FB_OVERLAY_MAX]; + PixmapPtr pPixmap; + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + + /* + * Clip to existing bits + */ + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + REGION_NULL (pScreen, &rgnDst); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + REGION_TRANSLATE(pScreen, &rgnDst, dx, dy); + /* + * Compute the portion of each fb affected by this copy + */ + for (i = 0; i < pScrPriv->nlayers; i++) + { + REGION_NULL (pScreen, &layerRgn[i]); + REGION_INTERSECT(pScreen, &layerRgn[i], &rgnDst, + &pScrPriv->layer[i].u.run.region); + if (REGION_NOTEMPTY (pScreen, &layerRgn[i])) + { + REGION_TRANSLATE(pScreen, &layerRgn[i], -dx, -dy); + pPixmap = pScrPriv->layer[i].u.run.pixmap; + miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, + 0, + &layerRgn[i], dx, dy, pScrPriv->CopyWindow, 0, + (void *)(long) i); + } + } + /* + * Update regions + */ + for (i = 0; i < pScrPriv->nlayers; i++) + { + if (REGION_NOTEMPTY (pScreen, &layerRgn[i])) + fbOverlayUpdateLayerRegion (pScreen, i, &layerRgn[i]); + + REGION_UNINIT(pScreen, &layerRgn[i]); + } + REGION_UNINIT(pScreen, &rgnDst); +} + +void +fbOverlayWindowExposures (WindowPtr pWin, + RegionPtr prgn, + RegionPtr other_exposed) +{ + fbOverlayUpdateLayerRegion (pWin->drawable.pScreen, + fbOverlayWindowLayer (pWin), + prgn); + miWindowExposures(pWin, prgn, other_exposed); +} + +Bool +fbOverlaySetupScreen(ScreenPtr pScreen, + pointer pbits1, + pointer pbits2, + int xsize, + int ysize, + int dpix, + int dpiy, + int width1, + int width2, + int bpp1, + int bpp2) +{ + return fbSetupScreen (pScreen, + pbits1, + xsize, + ysize, + dpix, + dpiy, + width1, + bpp1); +} + +static Bool +fb24_32OverlayCreateScreenResources(ScreenPtr pScreen) +{ + FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); + int pitch; + Bool retval; + int i; + + if((retval = fbOverlayCreateScreenResources(pScreen))) { + for (i = 0; i < pScrPriv->nlayers; i++) + { + /* fix the screen pixmap */ + PixmapPtr pPix = (PixmapPtr) pScrPriv->layer[i].u.run.pixmap; + if (pPix->drawable.bitsPerPixel == 32) { + pPix->drawable.bitsPerPixel = 24; + pitch = BitmapBytePad(pPix->drawable.width * 24); + pPix->devKind = pitch; + } + } + } + + return retval; +} + +Bool +fbOverlayFinishScreenInit(ScreenPtr pScreen, + pointer pbits1, + pointer pbits2, + int xsize, + int ysize, + int dpix, + int dpiy, + int width1, + int width2, + int bpp1, + int bpp2, + int depth1, + int depth2) +{ + VisualPtr visuals; + DepthPtr depths; + int nvisuals; + int ndepths; + int bpp = 0, imagebpp = 32; + VisualID defaultVisual; + FbOverlayScrPrivPtr pScrPriv; + + pScrPriv = malloc(sizeof (FbOverlayScrPrivRec)); + if (!pScrPriv) + return FALSE; + +#ifdef FB_24_32BIT + if (bpp1 == 32 || bpp2 == 32) + bpp = 32; + else if (bpp1 == 24 || bpp2 == 24) + bpp = 24; + + if (bpp == 24) + { + int f; + + imagebpp = 32; + /* + * Check to see if we're advertising a 24bpp image format, + * in which case windows will use it in preference to a 32 bit + * format. + */ + for (f = 0; f < screenInfo.numPixmapFormats; f++) + { + if (screenInfo.formats[f].bitsPerPixel == 24) + { + imagebpp = 24; + break; + } + } + } +#endif +#ifdef FB_SCREEN_PRIVATE + if (imagebpp == 32) + { + fbGetScreenPrivate(pScreen)->win32bpp = bpp; + fbGetScreenPrivate(pScreen)->pix32bpp = bpp; + } + else + { + fbGetScreenPrivate(pScreen)->win32bpp = 32; + fbGetScreenPrivate(pScreen)->pix32bpp = 32; + } +#endif + + if (!fbInitVisuals (&visuals, &depths, &nvisuals, &ndepths, &depth1, + &defaultVisual, ((unsigned long)1<<(bpp1-1)) | + ((unsigned long)1<<(bpp2-1)), 8)) + return FALSE; + if (! miScreenInit(pScreen, 0, xsize, ysize, dpix, dpiy, 0, + depth1, ndepths, depths, + defaultVisual, nvisuals, visuals)) + return FALSE; + /* MI thinks there's no frame buffer */ +#ifdef MITSHM + ShmRegisterFbFuncs(pScreen); +#endif + pScreen->minInstalledCmaps = 1; + pScreen->maxInstalledCmaps = 2; + + pScrPriv->nlayers = 2; + pScrPriv->PaintKey = fbOverlayPaintKey; + pScrPriv->CopyWindow = fbCopyWindowProc; + pScrPriv->layer[0].u.init.pbits = pbits1; + pScrPriv->layer[0].u.init.width = width1; + pScrPriv->layer[0].u.init.depth = depth1; + + pScrPriv->layer[1].u.init.pbits = pbits2; + pScrPriv->layer[1].u.init.width = width2; + pScrPriv->layer[1].u.init.depth = depth2; + + dixSetPrivate(&pScreen->devPrivates, fbOverlayScreenPrivateKey, pScrPriv); + + /* overwrite miCloseScreen with our own */ + pScreen->CloseScreen = fbOverlayCloseScreen; + pScreen->CreateScreenResources = fbOverlayCreateScreenResources; + pScreen->CreateWindow = fbOverlayCreateWindow; + pScreen->WindowExposures = fbOverlayWindowExposures; + pScreen->CopyWindow = fbOverlayCopyWindow; +#ifdef FB_24_32BIT + if (bpp == 24 && imagebpp == 32) + { + pScreen->ModifyPixmapHeader = fb24_32ModifyPixmapHeader; + pScreen->CreateScreenResources = fb24_32OverlayCreateScreenResources; + } +#endif + + return TRUE; +} diff --git a/xorg-server/fb/fbpixmap.c b/xorg-server/fb/fbpixmap.c index 311da9e62..d9ee21391 100644 --- a/xorg-server/fb/fbpixmap.c +++ b/xorg-server/fb/fbpixmap.c @@ -1,392 +1,392 @@ -/* - * Copyright © 1998 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 - -#include "fb.h" - -PixmapPtr -fbCreatePixmapBpp (ScreenPtr pScreen, int width, int height, int depth, int bpp, - unsigned usage_hint) -{ - PixmapPtr pPixmap; - size_t datasize; - size_t paddedWidth; - int adjust; - int base; - - paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); - if (paddedWidth / 4 > 32767 || height > 32767) - return NullPixmap; - datasize = height * paddedWidth; - base = pScreen->totalPixmapSize; - adjust = 0; - if (base & 7) - adjust = 8 - (base & 7); - datasize += adjust; -#ifdef FB_DEBUG - datasize += 2 * paddedWidth; -#endif - pPixmap = AllocatePixmap(pScreen, datasize); - if (!pPixmap) - return NullPixmap; - pPixmap->drawable.type = DRAWABLE_PIXMAP; - pPixmap->drawable.class = 0; - pPixmap->drawable.pScreen = pScreen; - pPixmap->drawable.depth = depth; - pPixmap->drawable.bitsPerPixel = bpp; - pPixmap->drawable.id = 0; - pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - pPixmap->drawable.x = 0; - pPixmap->drawable.y = 0; - pPixmap->drawable.width = width; - pPixmap->drawable.height = height; - pPixmap->devKind = paddedWidth; - pPixmap->refcnt = 1; - pPixmap->devPrivate.ptr = (pointer) ((char *)pPixmap + base + adjust); -#ifdef FB_DEBUG - pPixmap->devPrivate.ptr = (void *) ((char *) pPixmap->devPrivate.ptr + paddedWidth); - fbInitializeDrawable (&pPixmap->drawable); -#endif - -#ifdef COMPOSITE - pPixmap->screen_x = 0; - pPixmap->screen_y = 0; -#endif - - pPixmap->usage_hint = usage_hint; - - return pPixmap; -} - -PixmapPtr -fbCreatePixmap (ScreenPtr pScreen, int width, int height, int depth, - unsigned usage_hint) -{ - int bpp; - bpp = BitsPerPixel (depth); -#ifdef FB_SCREEN_PRIVATE - if (bpp == 32 && depth <= 24) - bpp = fbGetScreenPrivate(pScreen)->pix32bpp; -#endif - return fbCreatePixmapBpp (pScreen, width, height, depth, bpp, usage_hint); -} - -Bool -fbDestroyPixmap (PixmapPtr pPixmap) -{ - if(--pPixmap->refcnt) - return TRUE; - dixFreePrivates(pPixmap->devPrivates); - xfree(pPixmap); - return TRUE; -} - -#define ADDRECT(reg,r,fr,rx1,ry1,rx2,ry2) \ -if (((rx1) < (rx2)) && ((ry1) < (ry2)) && \ - (!((reg)->data->numRects && \ - ((r-1)->y1 == (ry1)) && \ - ((r-1)->y2 == (ry2)) && \ - ((r-1)->x1 <= (rx1)) && \ - ((r-1)->x2 >= (rx2))))) \ -{ \ - if ((reg)->data->numRects == (reg)->data->size) \ - { \ - miRectAlloc(reg, 1); \ - fr = REGION_BOXPTR(reg); \ - r = fr + (reg)->data->numRects; \ - } \ - r->x1 = (rx1); \ - r->y1 = (ry1); \ - r->x2 = (rx2); \ - r->y2 = (ry2); \ - (reg)->data->numRects++; \ - if(r->x1 < (reg)->extents.x1) \ - (reg)->extents.x1 = r->x1; \ - if(r->x2 > (reg)->extents.x2) \ - (reg)->extents.x2 = r->x2; \ - r++; \ -} - -/* Convert bitmap clip mask into clipping region. - * First, goes through each line and makes boxes by noting the transitions - * from 0 to 1 and 1 to 0. - * Then it coalesces the current line with the previous if they have boxes - * at the same X coordinates. - */ -RegionPtr -fbPixmapToRegion(PixmapPtr pPix) -{ - register RegionPtr pReg; - FbBits *pw, w; - register int ib; - int width, h, base, rx1 = 0, crects; - FbBits *pwLineEnd; - int irectPrevStart, irectLineStart; - register BoxPtr prectO, prectN; - BoxPtr FirstRect, rects, prectLineStart; - Bool fInBox, fSame; - register FbBits mask0 = FB_ALLONES & ~FbScrRight(FB_ALLONES, 1); - FbBits *pwLine; - int nWidth; - - pReg = REGION_CREATE(pPix->drawable.pScreen, NULL, 1); - if(!pReg) - return NullRegion; - FirstRect = REGION_BOXPTR(pReg); - rects = FirstRect; - - fbPrepareAccess(&pPix->drawable); - - pwLine = (FbBits *) pPix->devPrivate.ptr; - nWidth = pPix->devKind >> (FB_SHIFT-3); - - width = pPix->drawable.width; - pReg->extents.x1 = width - 1; - pReg->extents.x2 = 0; - irectPrevStart = -1; - for(h = 0; h < pPix->drawable.height; h++) - { - pw = pwLine; - pwLine += nWidth; - irectLineStart = rects - FirstRect; - /* If the Screen left most bit of the word is set, we're starting in - * a box */ - if(READ(pw) & mask0) - { - fInBox = TRUE; - rx1 = 0; - } - else - fInBox = FALSE; - /* Process all words which are fully in the pixmap */ - pwLineEnd = pw + (width >> FB_SHIFT); - for (base = 0; pw < pwLineEnd; base += FB_UNIT) - { - w = READ(pw++); - if (fInBox) - { - if (!~w) - continue; - } - else - { - if (!w) - continue; - } - for(ib = 0; ib < FB_UNIT; ib++) - { - /* If the Screen left most bit of the word is set, we're - * starting a box */ - if(w & mask0) - { - if(!fInBox) - { - rx1 = base + ib; - /* start new box */ - fInBox = TRUE; - } - } - else - { - if(fInBox) - { - /* end box */ - ADDRECT(pReg, rects, FirstRect, - rx1, h, base + ib, h + 1); - fInBox = FALSE; - } - } - /* Shift the word VISUALLY left one. */ - w = FbScrLeft(w, 1); - } - } - if(width & FB_MASK) - { - /* Process final partial word on line */ - w = READ(pw++); - for(ib = 0; ib < (width & FB_MASK); ib++) - { - /* If the Screen left most bit of the word is set, we're - * starting a box */ - if(w & mask0) - { - if(!fInBox) - { - rx1 = base + ib; - /* start new box */ - fInBox = TRUE; - } - } - else - { - if(fInBox) - { - /* end box */ - ADDRECT(pReg, rects, FirstRect, - rx1, h, base + ib, h + 1); - fInBox = FALSE; - } - } - /* Shift the word VISUALLY left one. */ - w = FbScrLeft(w, 1); - } - } - /* If scanline ended with last bit set, end the box */ - if(fInBox) - { - ADDRECT(pReg, rects, FirstRect, - rx1, h, base + (width & FB_MASK), h + 1); - } - /* if all rectangles on this line have the same x-coords as - * those on the previous line, then add 1 to all the previous y2s and - * throw away all the rectangles from this line - */ - fSame = FALSE; - if(irectPrevStart != -1) - { - crects = irectLineStart - irectPrevStart; - if(crects == ((rects - FirstRect) - irectLineStart)) - { - prectO = FirstRect + irectPrevStart; - prectN = prectLineStart = FirstRect + irectLineStart; - fSame = TRUE; - while(prectO < prectLineStart) - { - if((prectO->x1 != prectN->x1) || (prectO->x2 != prectN->x2)) - { - fSame = FALSE; - break; - } - prectO++; - prectN++; - } - if (fSame) - { - prectO = FirstRect + irectPrevStart; - while(prectO < prectLineStart) - { - prectO->y2 += 1; - prectO++; - } - rects -= crects; - pReg->data->numRects -= crects; - } - } - } - if(!fSame) - irectPrevStart = irectLineStart; - } - if (!pReg->data->numRects) - pReg->extents.x1 = pReg->extents.x2 = 0; - else - { - pReg->extents.y1 = REGION_BOXPTR(pReg)->y1; - pReg->extents.y2 = REGION_END(pReg)->y2; - if (pReg->data->numRects == 1) - { - xfree(pReg->data); - pReg->data = (RegDataPtr)NULL; - } - } - - fbFinishAccess(&pPix->drawable); -#ifdef DEBUG - if (!miValidRegion(pReg)) - FatalError("Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__); -#endif - return(pReg); -} - -#ifdef FB_DEBUG - -#ifndef WIN32 -#include -#else -#include -#endif - -static Bool -fbValidateBits (FbStip *bits, int stride, FbStip data) -{ - while (stride--) - { - if (*bits != data) - { -#ifdef WIN32 - NCD_DEBUG ((DEBUG_FAILURE, "fdValidateBits failed at 0x%x (is 0x%x want 0x%x)", - bits, *bits, data)); -#else - fprintf (stderr, "fbValidateBits failed\n"); -#endif - return FALSE; - } - bits++; - } -} - -void -fbValidateDrawable (DrawablePtr pDrawable) -{ - FbStip *bits, *first, *last; - int stride, bpp; - int xoff, yoff; - int height; - Bool failed; - - if (pDrawable->type != DRAWABLE_PIXMAP) - pDrawable = (DrawablePtr) fbGetWindowPixmap(pDrawable); - fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff); - first = bits - stride; - last = bits + stride * pDrawable->height; - if (!fbValidateBits (first, stride, FB_HEAD_BITS) || - !fbValidateBits (last, stride, FB_TAIL_BITS)) - fbInitializeDrawable(pDrawable); - fbFinishAccess (pDrawable); -} - -void -fbSetBits (FbStip *bits, int stride, FbStip data) -{ - while (stride--) - *bits++ = data; -} - -void -fbInitializeDrawable (DrawablePtr pDrawable) -{ - FbStip *bits, *first, *last; - int stride, bpp; - int xoff, yoff; - - fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff); - first = bits - stride; - last = bits + stride * pDrawable->height; - fbSetBits (first, stride, FB_HEAD_BITS); - fbSetBits (last, stride, FB_TAIL_BITS); - fbFinishAccess (pDrawable); -} -#endif /* FB_DEBUG */ +/* + * Copyright © 1998 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 + +#include "fb.h" + +PixmapPtr +fbCreatePixmapBpp (ScreenPtr pScreen, int width, int height, int depth, int bpp, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + size_t datasize; + size_t paddedWidth; + int adjust; + int base; + + paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); + if (paddedWidth / 4 > 32767 || height > 32767) + return NullPixmap; + datasize = height * paddedWidth; + base = pScreen->totalPixmapSize; + adjust = 0; + if (base & 7) + adjust = 8 - (base & 7); + datasize += adjust; +#ifdef FB_DEBUG + datasize += 2 * paddedWidth; +#endif + pPixmap = AllocatePixmap(pScreen, datasize); + if (!pPixmap) + return NullPixmap; + pPixmap->drawable.type = DRAWABLE_PIXMAP; + pPixmap->drawable.class = 0; + pPixmap->drawable.pScreen = pScreen; + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bpp; + pPixmap->drawable.id = 0; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = paddedWidth; + pPixmap->refcnt = 1; + pPixmap->devPrivate.ptr = (pointer) ((char *)pPixmap + base + adjust); +#ifdef FB_DEBUG + pPixmap->devPrivate.ptr = (void *) ((char *) pPixmap->devPrivate.ptr + paddedWidth); + fbInitializeDrawable (&pPixmap->drawable); +#endif + +#ifdef COMPOSITE + pPixmap->screen_x = 0; + pPixmap->screen_y = 0; +#endif + + pPixmap->usage_hint = usage_hint; + + return pPixmap; +} + +PixmapPtr +fbCreatePixmap (ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint) +{ + int bpp; + bpp = BitsPerPixel (depth); +#ifdef FB_SCREEN_PRIVATE + if (bpp == 32 && depth <= 24) + bpp = fbGetScreenPrivate(pScreen)->pix32bpp; +#endif + return fbCreatePixmapBpp (pScreen, width, height, depth, bpp, usage_hint); +} + +Bool +fbDestroyPixmap (PixmapPtr pPixmap) +{ + if(--pPixmap->refcnt) + return TRUE; + dixFreePrivates(pPixmap->devPrivates); + free(pPixmap); + return TRUE; +} + +#define ADDRECT(reg,r,fr,rx1,ry1,rx2,ry2) \ +if (((rx1) < (rx2)) && ((ry1) < (ry2)) && \ + (!((reg)->data->numRects && \ + ((r-1)->y1 == (ry1)) && \ + ((r-1)->y2 == (ry2)) && \ + ((r-1)->x1 <= (rx1)) && \ + ((r-1)->x2 >= (rx2))))) \ +{ \ + if ((reg)->data->numRects == (reg)->data->size) \ + { \ + miRectAlloc(reg, 1); \ + fr = REGION_BOXPTR(reg); \ + r = fr + (reg)->data->numRects; \ + } \ + r->x1 = (rx1); \ + r->y1 = (ry1); \ + r->x2 = (rx2); \ + r->y2 = (ry2); \ + (reg)->data->numRects++; \ + if(r->x1 < (reg)->extents.x1) \ + (reg)->extents.x1 = r->x1; \ + if(r->x2 > (reg)->extents.x2) \ + (reg)->extents.x2 = r->x2; \ + r++; \ +} + +/* Convert bitmap clip mask into clipping region. + * First, goes through each line and makes boxes by noting the transitions + * from 0 to 1 and 1 to 0. + * Then it coalesces the current line with the previous if they have boxes + * at the same X coordinates. + */ +RegionPtr +fbPixmapToRegion(PixmapPtr pPix) +{ + register RegionPtr pReg; + FbBits *pw, w; + register int ib; + int width, h, base, rx1 = 0, crects; + FbBits *pwLineEnd; + int irectPrevStart, irectLineStart; + register BoxPtr prectO, prectN; + BoxPtr FirstRect, rects, prectLineStart; + Bool fInBox, fSame; + register FbBits mask0 = FB_ALLONES & ~FbScrRight(FB_ALLONES, 1); + FbBits *pwLine; + int nWidth; + + pReg = REGION_CREATE(pPix->drawable.pScreen, NULL, 1); + if(!pReg) + return NullRegion; + FirstRect = REGION_BOXPTR(pReg); + rects = FirstRect; + + fbPrepareAccess(&pPix->drawable); + + pwLine = (FbBits *) pPix->devPrivate.ptr; + nWidth = pPix->devKind >> (FB_SHIFT-3); + + width = pPix->drawable.width; + pReg->extents.x1 = width - 1; + pReg->extents.x2 = 0; + irectPrevStart = -1; + for(h = 0; h < pPix->drawable.height; h++) + { + pw = pwLine; + pwLine += nWidth; + irectLineStart = rects - FirstRect; + /* If the Screen left most bit of the word is set, we're starting in + * a box */ + if(READ(pw) & mask0) + { + fInBox = TRUE; + rx1 = 0; + } + else + fInBox = FALSE; + /* Process all words which are fully in the pixmap */ + pwLineEnd = pw + (width >> FB_SHIFT); + for (base = 0; pw < pwLineEnd; base += FB_UNIT) + { + w = READ(pw++); + if (fInBox) + { + if (!~w) + continue; + } + else + { + if (!w) + continue; + } + for(ib = 0; ib < FB_UNIT; ib++) + { + /* If the Screen left most bit of the word is set, we're + * starting a box */ + if(w & mask0) + { + if(!fInBox) + { + rx1 = base + ib; + /* start new box */ + fInBox = TRUE; + } + } + else + { + if(fInBox) + { + /* end box */ + ADDRECT(pReg, rects, FirstRect, + rx1, h, base + ib, h + 1); + fInBox = FALSE; + } + } + /* Shift the word VISUALLY left one. */ + w = FbScrLeft(w, 1); + } + } + if(width & FB_MASK) + { + /* Process final partial word on line */ + w = READ(pw++); + for(ib = 0; ib < (width & FB_MASK); ib++) + { + /* If the Screen left most bit of the word is set, we're + * starting a box */ + if(w & mask0) + { + if(!fInBox) + { + rx1 = base + ib; + /* start new box */ + fInBox = TRUE; + } + } + else + { + if(fInBox) + { + /* end box */ + ADDRECT(pReg, rects, FirstRect, + rx1, h, base + ib, h + 1); + fInBox = FALSE; + } + } + /* Shift the word VISUALLY left one. */ + w = FbScrLeft(w, 1); + } + } + /* If scanline ended with last bit set, end the box */ + if(fInBox) + { + ADDRECT(pReg, rects, FirstRect, + rx1, h, base + (width & FB_MASK), h + 1); + } + /* if all rectangles on this line have the same x-coords as + * those on the previous line, then add 1 to all the previous y2s and + * throw away all the rectangles from this line + */ + fSame = FALSE; + if(irectPrevStart != -1) + { + crects = irectLineStart - irectPrevStart; + if(crects == ((rects - FirstRect) - irectLineStart)) + { + prectO = FirstRect + irectPrevStart; + prectN = prectLineStart = FirstRect + irectLineStart; + fSame = TRUE; + while(prectO < prectLineStart) + { + if((prectO->x1 != prectN->x1) || (prectO->x2 != prectN->x2)) + { + fSame = FALSE; + break; + } + prectO++; + prectN++; + } + if (fSame) + { + prectO = FirstRect + irectPrevStart; + while(prectO < prectLineStart) + { + prectO->y2 += 1; + prectO++; + } + rects -= crects; + pReg->data->numRects -= crects; + } + } + } + if(!fSame) + irectPrevStart = irectLineStart; + } + if (!pReg->data->numRects) + pReg->extents.x1 = pReg->extents.x2 = 0; + else + { + pReg->extents.y1 = REGION_BOXPTR(pReg)->y1; + pReg->extents.y2 = REGION_END(pReg)->y2; + if (pReg->data->numRects == 1) + { + free(pReg->data); + pReg->data = (RegDataPtr)NULL; + } + } + + fbFinishAccess(&pPix->drawable); +#ifdef DEBUG + if (!miValidRegion(pReg)) + FatalError("Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__); +#endif + return(pReg); +} + +#ifdef FB_DEBUG + +#ifndef WIN32 +#include +#else +#include +#endif + +static Bool +fbValidateBits (FbStip *bits, int stride, FbStip data) +{ + while (stride--) + { + if (*bits != data) + { +#ifdef WIN32 + NCD_DEBUG ((DEBUG_FAILURE, "fdValidateBits failed at 0x%x (is 0x%x want 0x%x)", + bits, *bits, data)); +#else + fprintf (stderr, "fbValidateBits failed\n"); +#endif + return FALSE; + } + bits++; + } +} + +void +fbValidateDrawable (DrawablePtr pDrawable) +{ + FbStip *bits, *first, *last; + int stride, bpp; + int xoff, yoff; + int height; + Bool failed; + + if (pDrawable->type != DRAWABLE_PIXMAP) + pDrawable = (DrawablePtr) fbGetWindowPixmap(pDrawable); + fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff); + first = bits - stride; + last = bits + stride * pDrawable->height; + if (!fbValidateBits (first, stride, FB_HEAD_BITS) || + !fbValidateBits (last, stride, FB_TAIL_BITS)) + fbInitializeDrawable(pDrawable); + fbFinishAccess (pDrawable); +} + +void +fbSetBits (FbStip *bits, int stride, FbStip data) +{ + while (stride--) + *bits++ = data; +} + +void +fbInitializeDrawable (DrawablePtr pDrawable) +{ + FbStip *bits, *first, *last; + int stride, bpp; + int xoff, yoff; + + fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff); + first = bits - stride; + last = bits + stride * pDrawable->height; + fbSetBits (first, stride, FB_HEAD_BITS); + fbSetBits (last, stride, FB_TAIL_BITS); + fbFinishAccess (pDrawable); +} +#endif /* FB_DEBUG */ diff --git a/xorg-server/fb/fbscreen.c b/xorg-server/fb/fbscreen.c index 53e2ada9f..65af64074 100644 --- a/xorg-server/fb/fbscreen.c +++ b/xorg-server/fb/fbscreen.c @@ -1,291 +1,291 @@ -/* - * Copyright © 1998 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 "fb.h" - -Bool -fbCloseScreen (int index, ScreenPtr pScreen) -{ - int d; - DepthPtr depths = pScreen->allowedDepths; - - for (d = 0; d < pScreen->numDepths; d++) - xfree (depths[d].vids); - xfree (depths); - xfree (pScreen->visuals); - xfree (pScreen->devPrivate); -#ifdef FB_SCREEN_PRIVATE - xfree (dixLookupPrivate(&pScreen->devPrivates, fbGetScreenPrivateKey())); -#endif - return TRUE; -} - -Bool -fbRealizeFont(ScreenPtr pScreen, FontPtr pFont) -{ - return (TRUE); -} - -Bool -fbUnrealizeFont(ScreenPtr pScreen, FontPtr pFont) -{ - return (TRUE); -} - -void -fbQueryBestSize (int class, - unsigned short *width, unsigned short *height, - ScreenPtr pScreen) -{ - unsigned short w; - - switch (class) { - case CursorShape: - if (*width > pScreen->width) - *width = pScreen->width; - if (*height > pScreen->height) - *height = pScreen->height; - break; - case TileShape: - case StippleShape: - w = *width; - if ((w & (w - 1)) && w < FB_UNIT) - { - for (w = 1; w < *width; w <<= 1) - ; - *width = w; - } - } -} - -PixmapPtr -_fbGetWindowPixmap (WindowPtr pWindow) -{ - return fbGetWindowPixmap (pWindow); -} - -void -_fbSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap) -{ - dixSetPrivate(&pWindow->devPrivates, fbGetWinPrivateKey(), pPixmap); -} - -Bool -fbSetupScreen(ScreenPtr pScreen, - pointer pbits, /* pointer to screen bitmap */ - int xsize, /* in pixels */ - int ysize, - int dpix, /* dots per inch */ - int dpiy, - int width, /* pixel width of frame buffer */ - int bpp) /* bits per pixel for screen */ -{ - if (!fbAllocatePrivates(pScreen, NULL)) - return FALSE; - pScreen->defColormap = FakeClientID(0); - /* let CreateDefColormap do whatever it wants for pixels */ - pScreen->blackPixel = pScreen->whitePixel = (Pixel) 0; - pScreen->QueryBestSize = fbQueryBestSize; - /* SaveScreen */ - pScreen->GetImage = fbGetImage; - pScreen->GetSpans = fbGetSpans; - pScreen->CreateWindow = fbCreateWindow; - pScreen->DestroyWindow = fbDestroyWindow; - pScreen->PositionWindow = fbPositionWindow; - pScreen->ChangeWindowAttributes = fbChangeWindowAttributes; - pScreen->RealizeWindow = fbMapWindow; - pScreen->UnrealizeWindow = fbUnmapWindow; - pScreen->CopyWindow = fbCopyWindow; - pScreen->CreatePixmap = fbCreatePixmap; - pScreen->DestroyPixmap = fbDestroyPixmap; - pScreen->RealizeFont = fbRealizeFont; - pScreen->UnrealizeFont = fbUnrealizeFont; - pScreen->CreateGC = fbCreateGC; - pScreen->CreateColormap = fbInitializeColormap; - pScreen->DestroyColormap = (void (*)(ColormapPtr))NoopDDA; - pScreen->InstallColormap = fbInstallColormap; - pScreen->UninstallColormap = fbUninstallColormap; - pScreen->ListInstalledColormaps = fbListInstalledColormaps; - pScreen->StoreColors = (void (*)(ColormapPtr, int, xColorItem *))NoopDDA; - pScreen->ResolveColor = fbResolveColor; - pScreen->BitmapToRegion = fbPixmapToRegion; - - pScreen->GetWindowPixmap = _fbGetWindowPixmap; - pScreen->SetWindowPixmap = _fbSetWindowPixmap; - - return TRUE; -} - -#ifdef FB_ACCESS_WRAPPER -Bool -wfbFinishScreenInit(ScreenPtr pScreen, - pointer pbits, - int xsize, - int ysize, - int dpix, - int dpiy, - int width, - int bpp, - SetupWrapProcPtr setupWrap, - FinishWrapProcPtr finishWrap) -#else -Bool -fbFinishScreenInit(ScreenPtr pScreen, - pointer pbits, - int xsize, - int ysize, - int dpix, - int dpiy, - int width, - int bpp) -#endif -{ - VisualPtr visuals; - DepthPtr depths; - int nvisuals; - int ndepths; - int rootdepth; - VisualID defaultVisual; - int imagebpp = bpp; - -#ifdef FB_DEBUG - int stride; - - ysize -= 2; - stride = (width * bpp) / 8; - fbSetBits ((FbStip *) pbits, - stride / sizeof (FbStip), FB_HEAD_BITS); - pbits = (void *) ((char *) pbits + stride); - fbSetBits ((FbStip *) ((char *) pbits + stride * ysize), - stride / sizeof (FbStip), FB_TAIL_BITS); -#endif - /* - * By default, a 24bpp screen will use 32bpp images, this avoids - * problems with many applications which just can't handle packed - * pixels. If you want real 24bit images, include a 24bpp - * format in the pixmap formats - */ -#ifdef FB_24_32BIT - if (bpp == 24) - { - int f; - - imagebpp = 32; - /* - * Check to see if we're advertising a 24bpp image format, - * in which case windows will use it in preference to a 32 bit - * format. - */ - for (f = 0; f < screenInfo.numPixmapFormats; f++) - { - if (screenInfo.formats[f].bitsPerPixel == 24) - { - imagebpp = 24; - break; - } - } - } -#endif -#ifdef FB_SCREEN_PRIVATE - if (imagebpp == 32) - { - fbGetScreenPrivate(pScreen)->win32bpp = bpp; - fbGetScreenPrivate(pScreen)->pix32bpp = bpp; - } - else - { - fbGetScreenPrivate(pScreen)->win32bpp = 32; - fbGetScreenPrivate(pScreen)->pix32bpp = 32; - } -#ifdef FB_ACCESS_WRAPPER - fbGetScreenPrivate(pScreen)->setupWrap = setupWrap; - fbGetScreenPrivate(pScreen)->finishWrap = finishWrap; -#endif -#endif - rootdepth = 0; - if (!fbInitVisuals (&visuals, &depths, &nvisuals, &ndepths, &rootdepth, - &defaultVisual,((unsigned long)1<<(imagebpp-1)), 8)) - { - xfree (visuals); - xfree (depths); - return FALSE; - } - if (! miScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, width, - rootdepth, ndepths, depths, - defaultVisual, nvisuals, visuals)) - return FALSE; - /* overwrite miCloseScreen with our own */ - pScreen->CloseScreen = fbCloseScreen; -#ifdef FB_24_32BIT - if (bpp == 24 && imagebpp == 32) - { - pScreen->ModifyPixmapHeader = fb24_32ModifyPixmapHeader; - pScreen->CreateScreenResources = fb24_32CreateScreenResources; - } -#endif - return TRUE; -} - -/* dts * (inch/dot) * (25.4 mm / inch) = mm */ -#ifdef FB_ACCESS_WRAPPER -Bool -wfbScreenInit(ScreenPtr pScreen, - pointer pbits, - int xsize, - int ysize, - int dpix, - int dpiy, - int width, - int bpp, - SetupWrapProcPtr setupWrap, - FinishWrapProcPtr finishWrap) -{ - if (!fbSetupScreen(pScreen, pbits, xsize, ysize, dpix, dpiy, width, bpp)) - return FALSE; - if (!wfbFinishScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, - width, bpp, setupWrap, finishWrap)) - return FALSE; - return TRUE; -} -#else -Bool -fbScreenInit(ScreenPtr pScreen, - pointer pbits, - int xsize, - int ysize, - int dpix, - int dpiy, - int width, - int bpp) -{ - if (!fbSetupScreen(pScreen, pbits, xsize, ysize, dpix, dpiy, width, bpp)) - return FALSE; - if (!fbFinishScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, - width, bpp)) - return FALSE; - return TRUE; -} -#endif +/* + * Copyright © 1998 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 "fb.h" + +Bool +fbCloseScreen (int index, ScreenPtr pScreen) +{ + int d; + DepthPtr depths = pScreen->allowedDepths; + + for (d = 0; d < pScreen->numDepths; d++) + free(depths[d].vids); + free(depths); + free(pScreen->visuals); + free(pScreen->devPrivate); +#ifdef FB_SCREEN_PRIVATE + free(dixLookupPrivate(&pScreen->devPrivates, fbGetScreenPrivateKey())); +#endif + return TRUE; +} + +Bool +fbRealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + return (TRUE); +} + +Bool +fbUnrealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + return (TRUE); +} + +void +fbQueryBestSize (int class, + unsigned short *width, unsigned short *height, + ScreenPtr pScreen) +{ + unsigned short w; + + switch (class) { + case CursorShape: + if (*width > pScreen->width) + *width = pScreen->width; + if (*height > pScreen->height) + *height = pScreen->height; + break; + case TileShape: + case StippleShape: + w = *width; + if ((w & (w - 1)) && w < FB_UNIT) + { + for (w = 1; w < *width; w <<= 1) + ; + *width = w; + } + } +} + +PixmapPtr +_fbGetWindowPixmap (WindowPtr pWindow) +{ + return fbGetWindowPixmap (pWindow); +} + +void +_fbSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap) +{ + dixSetPrivate(&pWindow->devPrivates, fbGetWinPrivateKey(), pPixmap); +} + +Bool +fbSetupScreen(ScreenPtr pScreen, + pointer pbits, /* pointer to screen bitmap */ + int xsize, /* in pixels */ + int ysize, + int dpix, /* dots per inch */ + int dpiy, + int width, /* pixel width of frame buffer */ + int bpp) /* bits per pixel for screen */ +{ + if (!fbAllocatePrivates(pScreen, NULL)) + return FALSE; + pScreen->defColormap = FakeClientID(0); + /* let CreateDefColormap do whatever it wants for pixels */ + pScreen->blackPixel = pScreen->whitePixel = (Pixel) 0; + pScreen->QueryBestSize = fbQueryBestSize; + /* SaveScreen */ + pScreen->GetImage = fbGetImage; + pScreen->GetSpans = fbGetSpans; + pScreen->CreateWindow = fbCreateWindow; + pScreen->DestroyWindow = fbDestroyWindow; + pScreen->PositionWindow = fbPositionWindow; + pScreen->ChangeWindowAttributes = fbChangeWindowAttributes; + pScreen->RealizeWindow = fbMapWindow; + pScreen->UnrealizeWindow = fbUnmapWindow; + pScreen->CopyWindow = fbCopyWindow; + pScreen->CreatePixmap = fbCreatePixmap; + pScreen->DestroyPixmap = fbDestroyPixmap; + pScreen->RealizeFont = fbRealizeFont; + pScreen->UnrealizeFont = fbUnrealizeFont; + pScreen->CreateGC = fbCreateGC; + pScreen->CreateColormap = fbInitializeColormap; + pScreen->DestroyColormap = (void (*)(ColormapPtr))NoopDDA; + pScreen->InstallColormap = fbInstallColormap; + pScreen->UninstallColormap = fbUninstallColormap; + pScreen->ListInstalledColormaps = fbListInstalledColormaps; + pScreen->StoreColors = (void (*)(ColormapPtr, int, xColorItem *))NoopDDA; + pScreen->ResolveColor = fbResolveColor; + pScreen->BitmapToRegion = fbPixmapToRegion; + + pScreen->GetWindowPixmap = _fbGetWindowPixmap; + pScreen->SetWindowPixmap = _fbSetWindowPixmap; + + return TRUE; +} + +#ifdef FB_ACCESS_WRAPPER +Bool +wfbFinishScreenInit(ScreenPtr pScreen, + pointer pbits, + int xsize, + int ysize, + int dpix, + int dpiy, + int width, + int bpp, + SetupWrapProcPtr setupWrap, + FinishWrapProcPtr finishWrap) +#else +Bool +fbFinishScreenInit(ScreenPtr pScreen, + pointer pbits, + int xsize, + int ysize, + int dpix, + int dpiy, + int width, + int bpp) +#endif +{ + VisualPtr visuals; + DepthPtr depths; + int nvisuals; + int ndepths; + int rootdepth; + VisualID defaultVisual; + int imagebpp = bpp; + +#ifdef FB_DEBUG + int stride; + + ysize -= 2; + stride = (width * bpp) / 8; + fbSetBits ((FbStip *) pbits, + stride / sizeof (FbStip), FB_HEAD_BITS); + pbits = (void *) ((char *) pbits + stride); + fbSetBits ((FbStip *) ((char *) pbits + stride * ysize), + stride / sizeof (FbStip), FB_TAIL_BITS); +#endif + /* + * By default, a 24bpp screen will use 32bpp images, this avoids + * problems with many applications which just can't handle packed + * pixels. If you want real 24bit images, include a 24bpp + * format in the pixmap formats + */ +#ifdef FB_24_32BIT + if (bpp == 24) + { + int f; + + imagebpp = 32; + /* + * Check to see if we're advertising a 24bpp image format, + * in which case windows will use it in preference to a 32 bit + * format. + */ + for (f = 0; f < screenInfo.numPixmapFormats; f++) + { + if (screenInfo.formats[f].bitsPerPixel == 24) + { + imagebpp = 24; + break; + } + } + } +#endif +#ifdef FB_SCREEN_PRIVATE + if (imagebpp == 32) + { + fbGetScreenPrivate(pScreen)->win32bpp = bpp; + fbGetScreenPrivate(pScreen)->pix32bpp = bpp; + } + else + { + fbGetScreenPrivate(pScreen)->win32bpp = 32; + fbGetScreenPrivate(pScreen)->pix32bpp = 32; + } +#ifdef FB_ACCESS_WRAPPER + fbGetScreenPrivate(pScreen)->setupWrap = setupWrap; + fbGetScreenPrivate(pScreen)->finishWrap = finishWrap; +#endif +#endif + rootdepth = 0; + if (!fbInitVisuals (&visuals, &depths, &nvisuals, &ndepths, &rootdepth, + &defaultVisual,((unsigned long)1<<(imagebpp-1)), 8)) + { + free(visuals); + free(depths); + return FALSE; + } + if (! miScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, width, + rootdepth, ndepths, depths, + defaultVisual, nvisuals, visuals)) + return FALSE; + /* overwrite miCloseScreen with our own */ + pScreen->CloseScreen = fbCloseScreen; +#ifdef FB_24_32BIT + if (bpp == 24 && imagebpp == 32) + { + pScreen->ModifyPixmapHeader = fb24_32ModifyPixmapHeader; + pScreen->CreateScreenResources = fb24_32CreateScreenResources; + } +#endif + return TRUE; +} + +/* dts * (inch/dot) * (25.4 mm / inch) = mm */ +#ifdef FB_ACCESS_WRAPPER +Bool +wfbScreenInit(ScreenPtr pScreen, + pointer pbits, + int xsize, + int ysize, + int dpix, + int dpiy, + int width, + int bpp, + SetupWrapProcPtr setupWrap, + FinishWrapProcPtr finishWrap) +{ + if (!fbSetupScreen(pScreen, pbits, xsize, ysize, dpix, dpiy, width, bpp)) + return FALSE; + if (!wfbFinishScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, + width, bpp, setupWrap, finishWrap)) + return FALSE; + return TRUE; +} +#else +Bool +fbScreenInit(ScreenPtr pScreen, + pointer pbits, + int xsize, + int ysize, + int dpix, + int dpiy, + int width, + int bpp) +{ + if (!fbSetupScreen(pScreen, pbits, xsize, ysize, dpix, dpiy, width, bpp)) + return FALSE; + if (!fbFinishScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, + width, bpp)) + return FALSE; + return TRUE; +} +#endif diff --git a/xorg-server/fb/fbseg.c b/xorg-server/fb/fbseg.c index 80ce7404e..0236721ab 100644 --- a/xorg-server/fb/fbseg.c +++ b/xorg-server/fb/fbseg.c @@ -1,734 +1,736 @@ -/* - * Copyright © 1998 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 - -#include "fb.h" -#include "miline.h" - -#define fbBresShiftMask(mask,dir,bpp) ((bpp == FB_STIP_UNIT) ? 0 : \ - ((dir < 0) ? FbStipLeft(mask,bpp) : \ - FbStipRight(mask,bpp))) - -void -fbBresSolid (DrawablePtr pDrawable, - GCPtr pGC, - int dashOffset, - int signdx, - int signdy, - int axis, - int x1, - int y1, - int e, - int e1, - int e3, - int len) -{ - FbStip *dst; - FbStride dstStride; - int dstBpp; - int dstXoff, dstYoff; - FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); - FbStip and = (FbStip) pPriv->and; - FbStip xor = (FbStip) pPriv->xor; - FbStip mask, mask0; - FbStip bits; - - fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); - dst += ((y1 + dstYoff) * dstStride); - x1 = (x1 + dstXoff) * dstBpp; - dst += x1 >> FB_STIP_SHIFT; - x1 &= FB_STIP_MASK; - mask0 = FbStipMask(0, dstBpp); - mask = FbStipRight (mask0, x1); - if (signdx < 0) - mask0 = FbStipRight (mask0, FB_STIP_UNIT - dstBpp); - if (signdy < 0) - dstStride = -dstStride; - if (axis == X_AXIS) - { - bits = 0; - while (len--) - { - bits |= mask; - mask = fbBresShiftMask(mask,signdx,dstBpp); - if (!mask) - { - WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); - bits = 0; - dst += signdx; - mask = mask0; - } - e += e1; - if (e >= 0) - { - WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); - bits = 0; - dst += dstStride; - e += e3; - } - } - if (bits) - WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); - } - else - { - while (len--) - { - WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, mask)); - dst += dstStride; - e += e1; - if (e >= 0) - { - e += e3; - mask = fbBresShiftMask(mask,signdx,dstBpp); - if (!mask) - { - dst += signdx; - mask = mask0; - } - } - } - } - - fbFinishAccess (pDrawable); -} - -void -fbBresDash (DrawablePtr pDrawable, - GCPtr pGC, - int dashOffset, - int signdx, - int signdy, - int axis, - int x1, - int y1, - int e, - int e1, - int e3, - int len) -{ - FbStip *dst; - FbStride dstStride; - int dstBpp; - int dstXoff, dstYoff; - FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); - FbStip and = (FbStip) pPriv->and; - FbStip xor = (FbStip) pPriv->xor; - FbStip bgand = (FbStip) pPriv->bgand; - FbStip bgxor = (FbStip) pPriv->bgxor; - FbStip mask, mask0; - FbDashDeclare; - int dashlen; - Bool even; - Bool doOdd; - - fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); - doOdd = pGC->lineStyle == LineDoubleDash; - - FbDashInit (pGC, pPriv, dashOffset, dashlen, even); - - dst += ((y1 + dstYoff) * dstStride); - x1 = (x1 + dstXoff) * dstBpp; - dst += x1 >> FB_STIP_SHIFT; - x1 &= FB_STIP_MASK; - mask0 = FbStipMask(0, dstBpp); - mask = FbStipRight (mask0, x1); - if (signdx < 0) - mask0 = FbStipRight (mask0, FB_STIP_UNIT - dstBpp); - if (signdy < 0) - dstStride = -dstStride; - while (len--) - { - if (even) - WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, mask)); - else if (doOdd) - WRITE(dst, FbDoMaskRRop (READ(dst), bgand, bgxor, mask)); - if (axis == X_AXIS) - { - mask = fbBresShiftMask(mask,signdx,dstBpp); - if (!mask) - { - dst += signdx; - mask = mask0; - } - e += e1; - if (e >= 0) - { - dst += dstStride; - e += e3; - } - } - else - { - dst += dstStride; - e += e1; - if (e >= 0) - { - e += e3; - mask = fbBresShiftMask(mask,signdx,dstBpp); - if (!mask) - { - dst += signdx; - mask = mask0; - } - } - } - FbDashStep (dashlen, even); - } - - fbFinishAccess (pDrawable); -} - -void -fbBresFill (DrawablePtr pDrawable, - GCPtr pGC, - int dashOffset, - int signdx, - int signdy, - int axis, - int x1, - int y1, - int e, - int e1, - int e3, - int len) -{ - while (len--) - { - fbFill (pDrawable, pGC, x1, y1, 1, 1); - if (axis == X_AXIS) - { - x1 += signdx; - e += e1; - if (e >= 0) - { - e += e3; - y1 += signdy; - } - } - else - { - y1 += signdy; - e += e1; - if (e >= 0) - { - e += e3; - x1 += signdx; - } - } - } -} - -static void -fbSetFg (DrawablePtr pDrawable, - GCPtr pGC, - Pixel fg) -{ - if (fg != pGC->fgPixel) - { - DoChangeGC (pGC, GCForeground, (XID *) &fg, FALSE); - ValidateGC (pDrawable, pGC); - } -} - -void -fbBresFillDash (DrawablePtr pDrawable, - GCPtr pGC, - int dashOffset, - int signdx, - int signdy, - int axis, - int x1, - int y1, - int e, - int e1, - int e3, - int len) -{ - FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); - FbDashDeclare; - int dashlen; - Bool even; - Bool doOdd; - Bool doBg; - Pixel fg, bg; - - fg = pGC->fgPixel; - bg = pGC->bgPixel; - - /* whether to fill the odd dashes */ - doOdd = pGC->lineStyle == LineDoubleDash; - /* whether to switch fg to bg when filling odd dashes */ - doBg = doOdd && (pGC->fillStyle == FillSolid || - pGC->fillStyle == FillStippled); - - /* compute current dash position */ - FbDashInit (pGC, pPriv, dashOffset, dashlen, even); - - while (len--) - { - if (even || doOdd) - { - if (doBg) - { - if (even) - fbSetFg (pDrawable, pGC, fg); - else - fbSetFg (pDrawable, pGC, bg); - } - fbFill (pDrawable, pGC, x1, y1, 1, 1); - } - if (axis == X_AXIS) - { - x1 += signdx; - e += e1; - if (e >= 0) - { - e += e3; - y1 += signdy; - } - } - else - { - y1 += signdy; - e += e1; - if (e >= 0) - { - e += e3; - x1 += signdx; - } - } - FbDashStep (dashlen, even); - } - if (doBg) - fbSetFg (pDrawable, pGC, fg); -} - -#ifdef FB_24BIT -static void -fbBresSolid24RRop (DrawablePtr pDrawable, - GCPtr pGC, - int dashOffset, - int signdx, - int signdy, - int axis, - int x1, - int y1, - int e, - int e1, - int e3, - int len) -{ - FbStip *dst; - FbStride dstStride; - int dstBpp; - int dstXoff, dstYoff; - FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); - FbStip and = pPriv->and; - FbStip xor = pPriv->xor; - FbStip leftMask, rightMask; - int nl; - FbStip *d; - int x; - int rot; - FbStip andT, xorT; - - fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); - dst += ((y1 + dstYoff) * dstStride); - x1 = (x1 + dstXoff) * 24; - if (signdy < 0) - dstStride = -dstStride; - signdx *= 24; - while (len--) - { - d = dst + (x1 >> FB_STIP_SHIFT); - x = x1 & FB_STIP_MASK; - rot = FbFirst24Rot (x); - andT = FbRot24Stip(and,rot); - xorT = FbRot24Stip(xor,rot); - FbMaskStip (x, 24, leftMask, nl, rightMask); - if (leftMask) - { - WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask)); - d++; - andT = FbNext24Stip (andT); - xorT = FbNext24Stip (xorT); - } - if (rightMask) - WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask)); - if (axis == X_AXIS) - { - x1 += signdx; - e += e1; - if (e >= 0) - { - e += e3; - dst += dstStride; - } - } - else - { - dst += dstStride; - e += e1; - if (e >= 0) - { - e += e3; - x1 += signdx; - } - } - } - - fbFinishAccess (pDrawable); -} - -static void -fbBresDash24RRop (DrawablePtr pDrawable, - GCPtr pGC, - int dashOffset, - int signdx, - int signdy, - int axis, - int x1, - int y1, - int e, - int e1, - int e3, - int len) -{ - FbStip *dst; - FbStride dstStride; - int dstBpp; - int dstXoff, dstYoff; - FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); - FbStip andT, xorT; - FbStip fgand = pPriv->and; - FbStip fgxor = pPriv->xor; - FbStip bgand = pPriv->bgand; - FbStip bgxor = pPriv->bgxor; - FbStip leftMask, rightMask; - int nl; - FbStip *d; - int x; - int rot; - FbDashDeclare; - int dashlen; - Bool even; - Bool doOdd; - - fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); - doOdd = pGC->lineStyle == LineDoubleDash; - - /* compute current dash position */ - FbDashInit(pGC, pPriv, dashOffset, dashlen, even); - - dst += ((y1 + dstYoff) * dstStride); - x1 = (x1 + dstXoff) * 24; - if (signdy < 0) - dstStride = -dstStride; - signdx *= 24; - while (len--) - { - if (even || doOdd) - { - if (even) - { - andT = fgand; - xorT = fgxor; - } - else - { - andT = bgand; - xorT = bgxor; - } - d = dst + (x1 >> FB_STIP_SHIFT); - x = x1 & FB_STIP_MASK; - rot = FbFirst24Rot (x); - andT = FbRot24Stip (andT, rot); - xorT = FbRot24Stip (xorT, rot); - FbMaskStip (x, 24, leftMask, nl, rightMask); - if (leftMask) - { - WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask)); - d++; - andT = FbNext24Stip (andT); - xorT = FbNext24Stip (xorT); - } - if (rightMask) - WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask)); - } - if (axis == X_AXIS) - { - x1 += signdx; - e += e1; - if (e >= 0) - { - e += e3; - dst += dstStride; - } - } - else - { - dst += dstStride; - e += e1; - if (e >= 0) - { - e += e3; - x1 += signdx; - } - } - FbDashStep (dashlen, even); - } - - fbFinishAccess (pDrawable); -} -#endif - -/* - * For drivers that want to bail drawing some lines, this - * function takes care of selecting the appropriate rasterizer - * based on the contents of the specified GC. - */ - -FbBres * -fbSelectBres (DrawablePtr pDrawable, - GCPtr pGC) -{ - FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); - int dstBpp = pDrawable->bitsPerPixel; - FbBres * bres; - - if (pGC->lineStyle == LineSolid) - { - bres = fbBresFill; - if (pGC->fillStyle == FillSolid) - { - bres = fbBresSolid; -#ifdef FB_24BIT - if (dstBpp == 24) - bres = fbBresSolid24RRop; -#endif -#ifndef FBNOPIXADDR - if (pPriv->and == 0) - { - switch (dstBpp) { - case 8: bres = fbBresSolid8; break; - case 16: bres = fbBresSolid16; break; -#ifdef FB_24BIT - case 24: bres = fbBresSolid24; break; -#endif - case 32: bres = fbBresSolid32; break; - } - } -#endif - } - } - else - { - bres = fbBresFillDash; - if (pGC->fillStyle == FillSolid) - { - bres = fbBresDash; -#ifdef FB_24BIT - if (dstBpp == 24) - bres = fbBresDash24RRop; -#endif -#ifndef FBNOPIXADDR - if (pPriv->and == 0 && - (pGC->lineStyle == LineOnOffDash || pPriv->bgand == 0)) - { - switch (dstBpp) { - case 8: bres = fbBresDash8; break; - case 16: bres = fbBresDash16; break; -#ifdef FB_24BIT - case 24: bres = fbBresDash24; break; -#endif - case 32: bres = fbBresDash32; break; - } - } -#endif - } - } - return bres; -} - -void -fbBres (DrawablePtr pDrawable, - GCPtr pGC, - int dashOffset, - int signdx, - int signdy, - int axis, - int x1, - int y1, - int e, - int e1, - int e3, - int len) -{ - (*fbSelectBres (pDrawable, pGC)) (pDrawable, pGC, dashOffset, - signdx, signdy, axis, x1, y1, - e, e1, e3, len); -} - -void -fbSegment (DrawablePtr pDrawable, - GCPtr pGC, - int x1, - int y1, - int x2, - int y2, - Bool drawLast, - int *dashOffset) -{ - FbBres * bres; - RegionPtr pClip = fbGetCompositeClip(pGC); - BoxPtr pBox; - int nBox; - int adx; /* abs values of dx and dy */ - int ady; - int signdx; /* sign of dx and dy */ - int signdy; - int e, e1, e2, e3; /* bresenham error and increments */ - int len; /* length of segment */ - int axis; /* major axis */ - int octant; - int dashoff; - int doff; - unsigned int bias = miGetZeroLineBias(pDrawable->pScreen); - unsigned int oc1; /* outcode of point 1 */ - unsigned int oc2; /* outcode of point 2 */ - - nBox = REGION_NUM_RECTS (pClip); - pBox = REGION_RECTS (pClip); - - bres = fbSelectBres (pDrawable, pGC); - - CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, - 1, 1, octant); - - if (adx > ady) - { - axis = X_AXIS; - e1 = ady << 1; - e2 = e1 - (adx << 1); - e = e1 - adx; - len = adx; - } - else - { - axis = Y_AXIS; - e1 = adx << 1; - e2 = e1 - (ady << 1); - e = e1 - ady; - SetYMajorOctant(octant); - len = ady; - } - - FIXUP_ERROR (e, octant, bias); - - /* - * Adjust error terms to compare against zero - */ - e3 = e2 - e1; - e = e - e1; - - /* we have bresenham parameters and two points. - all we have to do now is clip and draw. - */ - - if (drawLast) - len++; - dashoff = *dashOffset; - *dashOffset = dashoff + len; - while(nBox--) - { - oc1 = 0; - oc2 = 0; - OUTCODES(oc1, x1, y1, pBox); - OUTCODES(oc2, x2, y2, pBox); - if ((oc1 | oc2) == 0) - { - (*bres) (pDrawable, pGC, dashoff, - signdx, signdy, axis, x1, y1, - e, e1, e3, len); - break; - } - else if (oc1 & oc2) - { - pBox++; - } - else - { - int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2; - int clip1 = 0, clip2 = 0; - int clipdx, clipdy; - int err; - - if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2-1, - pBox->y2-1, - &new_x1, &new_y1, &new_x2, &new_y2, - adx, ady, &clip1, &clip2, - octant, bias, oc1, oc2) == -1) - { - pBox++; - continue; - } - - if (axis == X_AXIS) - len = abs(new_x2 - new_x1); - else - len = abs(new_y2 - new_y1); - if (clip2 != 0 || drawLast) - len++; - if (len) - { - /* unwind bresenham error term to first point */ - doff = dashoff; - err = e; - if (clip1) - { - clipdx = abs(new_x1 - x1); - clipdy = abs(new_y1 - y1); - if (axis == X_AXIS) - { - doff += clipdx; - err += e3 * clipdy + e1 * clipdx; - } - else - { - doff += clipdy; - err += e3 * clipdx + e1 * clipdy; - } - } - (*bres) (pDrawable, pGC, doff, - signdx, signdy, axis, new_x1, new_y1, - err, e1, e3, len); - } - pBox++; - } - } /* while (nBox--) */ -} +/* + * Copyright © 1998 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 + +#include "fb.h" +#include "miline.h" + +#define fbBresShiftMask(mask,dir,bpp) ((bpp == FB_STIP_UNIT) ? 0 : \ + ((dir < 0) ? FbStipLeft(mask,bpp) : \ + FbStipRight(mask,bpp))) + +void +fbBresSolid (DrawablePtr pDrawable, + GCPtr pGC, + int dashOffset, + int signdx, + int signdy, + int axis, + int x1, + int y1, + int e, + int e1, + int e3, + int len) +{ + FbStip *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); + FbStip and = (FbStip) pPriv->and; + FbStip xor = (FbStip) pPriv->xor; + FbStip mask, mask0; + FbStip bits; + + fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + dst += ((y1 + dstYoff) * dstStride); + x1 = (x1 + dstXoff) * dstBpp; + dst += x1 >> FB_STIP_SHIFT; + x1 &= FB_STIP_MASK; + mask0 = FbStipMask(0, dstBpp); + mask = FbStipRight (mask0, x1); + if (signdx < 0) + mask0 = FbStipRight (mask0, FB_STIP_UNIT - dstBpp); + if (signdy < 0) + dstStride = -dstStride; + if (axis == X_AXIS) + { + bits = 0; + while (len--) + { + bits |= mask; + mask = fbBresShiftMask(mask,signdx,dstBpp); + if (!mask) + { + WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); + bits = 0; + dst += signdx; + mask = mask0; + } + e += e1; + if (e >= 0) + { + WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); + bits = 0; + dst += dstStride; + e += e3; + } + } + if (bits) + WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); + } + else + { + while (len--) + { + WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, mask)); + dst += dstStride; + e += e1; + if (e >= 0) + { + e += e3; + mask = fbBresShiftMask(mask,signdx,dstBpp); + if (!mask) + { + dst += signdx; + mask = mask0; + } + } + } + } + + fbFinishAccess (pDrawable); +} + +void +fbBresDash (DrawablePtr pDrawable, + GCPtr pGC, + int dashOffset, + int signdx, + int signdy, + int axis, + int x1, + int y1, + int e, + int e1, + int e3, + int len) +{ + FbStip *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); + FbStip and = (FbStip) pPriv->and; + FbStip xor = (FbStip) pPriv->xor; + FbStip bgand = (FbStip) pPriv->bgand; + FbStip bgxor = (FbStip) pPriv->bgxor; + FbStip mask, mask0; + FbDashDeclare; + int dashlen; + Bool even; + Bool doOdd; + + fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + doOdd = pGC->lineStyle == LineDoubleDash; + + FbDashInit (pGC, pPriv, dashOffset, dashlen, even); + + dst += ((y1 + dstYoff) * dstStride); + x1 = (x1 + dstXoff) * dstBpp; + dst += x1 >> FB_STIP_SHIFT; + x1 &= FB_STIP_MASK; + mask0 = FbStipMask(0, dstBpp); + mask = FbStipRight (mask0, x1); + if (signdx < 0) + mask0 = FbStipRight (mask0, FB_STIP_UNIT - dstBpp); + if (signdy < 0) + dstStride = -dstStride; + while (len--) + { + if (even) + WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, mask)); + else if (doOdd) + WRITE(dst, FbDoMaskRRop (READ(dst), bgand, bgxor, mask)); + if (axis == X_AXIS) + { + mask = fbBresShiftMask(mask,signdx,dstBpp); + if (!mask) + { + dst += signdx; + mask = mask0; + } + e += e1; + if (e >= 0) + { + dst += dstStride; + e += e3; + } + } + else + { + dst += dstStride; + e += e1; + if (e >= 0) + { + e += e3; + mask = fbBresShiftMask(mask,signdx,dstBpp); + if (!mask) + { + dst += signdx; + mask = mask0; + } + } + } + FbDashStep (dashlen, even); + } + + fbFinishAccess (pDrawable); +} + +void +fbBresFill (DrawablePtr pDrawable, + GCPtr pGC, + int dashOffset, + int signdx, + int signdy, + int axis, + int x1, + int y1, + int e, + int e1, + int e3, + int len) +{ + while (len--) + { + fbFill (pDrawable, pGC, x1, y1, 1, 1); + if (axis == X_AXIS) + { + x1 += signdx; + e += e1; + if (e >= 0) + { + e += e3; + y1 += signdy; + } + } + else + { + y1 += signdy; + e += e1; + if (e >= 0) + { + e += e3; + x1 += signdx; + } + } + } +} + +static void +fbSetFg (DrawablePtr pDrawable, + GCPtr pGC, + Pixel fg) +{ + if (fg != pGC->fgPixel) + { + ChangeGCVal val; + val.val = fg; + ChangeGC (NullClient, pGC, GCForeground, &val); + ValidateGC (pDrawable, pGC); + } +} + +void +fbBresFillDash (DrawablePtr pDrawable, + GCPtr pGC, + int dashOffset, + int signdx, + int signdy, + int axis, + int x1, + int y1, + int e, + int e1, + int e3, + int len) +{ + FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); + FbDashDeclare; + int dashlen; + Bool even; + Bool doOdd; + Bool doBg; + Pixel fg, bg; + + fg = pGC->fgPixel; + bg = pGC->bgPixel; + + /* whether to fill the odd dashes */ + doOdd = pGC->lineStyle == LineDoubleDash; + /* whether to switch fg to bg when filling odd dashes */ + doBg = doOdd && (pGC->fillStyle == FillSolid || + pGC->fillStyle == FillStippled); + + /* compute current dash position */ + FbDashInit (pGC, pPriv, dashOffset, dashlen, even); + + while (len--) + { + if (even || doOdd) + { + if (doBg) + { + if (even) + fbSetFg (pDrawable, pGC, fg); + else + fbSetFg (pDrawable, pGC, bg); + } + fbFill (pDrawable, pGC, x1, y1, 1, 1); + } + if (axis == X_AXIS) + { + x1 += signdx; + e += e1; + if (e >= 0) + { + e += e3; + y1 += signdy; + } + } + else + { + y1 += signdy; + e += e1; + if (e >= 0) + { + e += e3; + x1 += signdx; + } + } + FbDashStep (dashlen, even); + } + if (doBg) + fbSetFg (pDrawable, pGC, fg); +} + +#ifdef FB_24BIT +static void +fbBresSolid24RRop (DrawablePtr pDrawable, + GCPtr pGC, + int dashOffset, + int signdx, + int signdy, + int axis, + int x1, + int y1, + int e, + int e1, + int e3, + int len) +{ + FbStip *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); + FbStip and = pPriv->and; + FbStip xor = pPriv->xor; + FbStip leftMask, rightMask; + int nl; + FbStip *d; + int x; + int rot; + FbStip andT, xorT; + + fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + dst += ((y1 + dstYoff) * dstStride); + x1 = (x1 + dstXoff) * 24; + if (signdy < 0) + dstStride = -dstStride; + signdx *= 24; + while (len--) + { + d = dst + (x1 >> FB_STIP_SHIFT); + x = x1 & FB_STIP_MASK; + rot = FbFirst24Rot (x); + andT = FbRot24Stip(and,rot); + xorT = FbRot24Stip(xor,rot); + FbMaskStip (x, 24, leftMask, nl, rightMask); + if (leftMask) + { + WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask)); + d++; + andT = FbNext24Stip (andT); + xorT = FbNext24Stip (xorT); + } + if (rightMask) + WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask)); + if (axis == X_AXIS) + { + x1 += signdx; + e += e1; + if (e >= 0) + { + e += e3; + dst += dstStride; + } + } + else + { + dst += dstStride; + e += e1; + if (e >= 0) + { + e += e3; + x1 += signdx; + } + } + } + + fbFinishAccess (pDrawable); +} + +static void +fbBresDash24RRop (DrawablePtr pDrawable, + GCPtr pGC, + int dashOffset, + int signdx, + int signdy, + int axis, + int x1, + int y1, + int e, + int e1, + int e3, + int len) +{ + FbStip *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); + FbStip andT, xorT; + FbStip fgand = pPriv->and; + FbStip fgxor = pPriv->xor; + FbStip bgand = pPriv->bgand; + FbStip bgxor = pPriv->bgxor; + FbStip leftMask, rightMask; + int nl; + FbStip *d; + int x; + int rot; + FbDashDeclare; + int dashlen; + Bool even; + Bool doOdd; + + fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + doOdd = pGC->lineStyle == LineDoubleDash; + + /* compute current dash position */ + FbDashInit(pGC, pPriv, dashOffset, dashlen, even); + + dst += ((y1 + dstYoff) * dstStride); + x1 = (x1 + dstXoff) * 24; + if (signdy < 0) + dstStride = -dstStride; + signdx *= 24; + while (len--) + { + if (even || doOdd) + { + if (even) + { + andT = fgand; + xorT = fgxor; + } + else + { + andT = bgand; + xorT = bgxor; + } + d = dst + (x1 >> FB_STIP_SHIFT); + x = x1 & FB_STIP_MASK; + rot = FbFirst24Rot (x); + andT = FbRot24Stip (andT, rot); + xorT = FbRot24Stip (xorT, rot); + FbMaskStip (x, 24, leftMask, nl, rightMask); + if (leftMask) + { + WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask)); + d++; + andT = FbNext24Stip (andT); + xorT = FbNext24Stip (xorT); + } + if (rightMask) + WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask)); + } + if (axis == X_AXIS) + { + x1 += signdx; + e += e1; + if (e >= 0) + { + e += e3; + dst += dstStride; + } + } + else + { + dst += dstStride; + e += e1; + if (e >= 0) + { + e += e3; + x1 += signdx; + } + } + FbDashStep (dashlen, even); + } + + fbFinishAccess (pDrawable); +} +#endif + +/* + * For drivers that want to bail drawing some lines, this + * function takes care of selecting the appropriate rasterizer + * based on the contents of the specified GC. + */ + +FbBres * +fbSelectBres (DrawablePtr pDrawable, + GCPtr pGC) +{ + FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); + int dstBpp = pDrawable->bitsPerPixel; + FbBres * bres; + + if (pGC->lineStyle == LineSolid) + { + bres = fbBresFill; + if (pGC->fillStyle == FillSolid) + { + bres = fbBresSolid; +#ifdef FB_24BIT + if (dstBpp == 24) + bres = fbBresSolid24RRop; +#endif +#ifndef FBNOPIXADDR + if (pPriv->and == 0) + { + switch (dstBpp) { + case 8: bres = fbBresSolid8; break; + case 16: bres = fbBresSolid16; break; +#ifdef FB_24BIT + case 24: bres = fbBresSolid24; break; +#endif + case 32: bres = fbBresSolid32; break; + } + } +#endif + } + } + else + { + bres = fbBresFillDash; + if (pGC->fillStyle == FillSolid) + { + bres = fbBresDash; +#ifdef FB_24BIT + if (dstBpp == 24) + bres = fbBresDash24RRop; +#endif +#ifndef FBNOPIXADDR + if (pPriv->and == 0 && + (pGC->lineStyle == LineOnOffDash || pPriv->bgand == 0)) + { + switch (dstBpp) { + case 8: bres = fbBresDash8; break; + case 16: bres = fbBresDash16; break; +#ifdef FB_24BIT + case 24: bres = fbBresDash24; break; +#endif + case 32: bres = fbBresDash32; break; + } + } +#endif + } + } + return bres; +} + +void +fbBres (DrawablePtr pDrawable, + GCPtr pGC, + int dashOffset, + int signdx, + int signdy, + int axis, + int x1, + int y1, + int e, + int e1, + int e3, + int len) +{ + (*fbSelectBres (pDrawable, pGC)) (pDrawable, pGC, dashOffset, + signdx, signdy, axis, x1, y1, + e, e1, e3, len); +} + +void +fbSegment (DrawablePtr pDrawable, + GCPtr pGC, + int x1, + int y1, + int x2, + int y2, + Bool drawLast, + int *dashOffset) +{ + FbBres * bres; + RegionPtr pClip = fbGetCompositeClip(pGC); + BoxPtr pBox; + int nBox; + int adx; /* abs values of dx and dy */ + int ady; + int signdx; /* sign of dx and dy */ + int signdy; + int e, e1, e2, e3; /* bresenham error and increments */ + int len; /* length of segment */ + int axis; /* major axis */ + int octant; + int dashoff; + int doff; + unsigned int bias = miGetZeroLineBias(pDrawable->pScreen); + unsigned int oc1; /* outcode of point 1 */ + unsigned int oc2; /* outcode of point 2 */ + + nBox = REGION_NUM_RECTS (pClip); + pBox = REGION_RECTS (pClip); + + bres = fbSelectBres (pDrawable, pGC); + + CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, + 1, 1, octant); + + if (adx > ady) + { + axis = X_AXIS; + e1 = ady << 1; + e2 = e1 - (adx << 1); + e = e1 - adx; + len = adx; + } + else + { + axis = Y_AXIS; + e1 = adx << 1; + e2 = e1 - (ady << 1); + e = e1 - ady; + SetYMajorOctant(octant); + len = ady; + } + + FIXUP_ERROR (e, octant, bias); + + /* + * Adjust error terms to compare against zero + */ + e3 = e2 - e1; + e = e - e1; + + /* we have bresenham parameters and two points. + all we have to do now is clip and draw. + */ + + if (drawLast) + len++; + dashoff = *dashOffset; + *dashOffset = dashoff + len; + while(nBox--) + { + oc1 = 0; + oc2 = 0; + OUTCODES(oc1, x1, y1, pBox); + OUTCODES(oc2, x2, y2, pBox); + if ((oc1 | oc2) == 0) + { + (*bres) (pDrawable, pGC, dashoff, + signdx, signdy, axis, x1, y1, + e, e1, e3, len); + break; + } + else if (oc1 & oc2) + { + pBox++; + } + else + { + int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2; + int clip1 = 0, clip2 = 0; + int clipdx, clipdy; + int err; + + if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2-1, + pBox->y2-1, + &new_x1, &new_y1, &new_x2, &new_y2, + adx, ady, &clip1, &clip2, + octant, bias, oc1, oc2) == -1) + { + pBox++; + continue; + } + + if (axis == X_AXIS) + len = abs(new_x2 - new_x1); + else + len = abs(new_y2 - new_y1); + if (clip2 != 0 || drawLast) + len++; + if (len) + { + /* unwind bresenham error term to first point */ + doff = dashoff; + err = e; + if (clip1) + { + clipdx = abs(new_x1 - x1); + clipdy = abs(new_y1 - y1); + if (axis == X_AXIS) + { + doff += clipdx; + err += e3 * clipdy + e1 * clipdx; + } + else + { + doff += clipdy; + err += e3 * clipdx + e1 * clipdy; + } + } + (*bres) (pDrawable, pGC, doff, + signdx, signdy, axis, new_x1, new_y1, + err, e1, e3, len); + } + pBox++; + } + } /* while (nBox--) */ +} diff --git a/xorg-server/glx/glxcmds.c b/xorg-server/glx/glxcmds.c index 1000f2179..7ce1f4fcf 100644 --- a/xorg-server/glx/glxcmds.c +++ b/xorg-server/glx/glxcmds.c @@ -196,7 +196,7 @@ __glXContextDestroy(__GLXcontext *context) static void __glXdirectContextDestroy(__GLXcontext *context) { __glXContextDestroy(context); - xfree(context); + free(context); } static __GLXcontext *__glXdirectContextCreate(__GLXscreen *screen, @@ -205,7 +205,7 @@ static __GLXcontext *__glXdirectContextCreate(__GLXscreen *screen, { __GLXcontext *context; - context = xcalloc (1, sizeof (__GLXcontext)); + context = calloc(1, sizeof (__GLXcontext)); if (context == NULL) return NULL; @@ -407,9 +407,9 @@ static int AddCurrentContext(__GLXclientState *cl, __GLXcontext *glxc) ** Didn't find a free slot, so we'll have to grow the table. */ if (!num) { - table = (__GLXcontext **) xalloc(sizeof(__GLXcontext *)); + table = (__GLXcontext **) malloc(sizeof(__GLXcontext *)); } else { - table = (__GLXcontext **) xrealloc(table, + table = (__GLXcontext **) realloc(table, (num+1)*sizeof(__GLXcontext *)); } table[num] = glxc; @@ -1527,7 +1527,7 @@ DoQueryContext(__GLXclientState *cl, GLXContextID gcId) reply.n = nProps; nReplyBytes = reply.length << 2; - sendBuf = (int *)xalloc((size_t)nReplyBytes); + sendBuf = (int *)malloc((size_t)nReplyBytes); if (sendBuf == NULL) { return __glXError(GLXBadContext); /* XXX: Is this correct? */ } @@ -1545,7 +1545,7 @@ DoQueryContext(__GLXclientState *cl, GLXContextID gcId) WriteToClient(client, sz_xGLXQueryContextInfoEXTReply, (char *)&reply); WriteToClient(client, nReplyBytes, (char *)sendBuf); } - xfree((char *)sendBuf); + free((char *)sendBuf); return Success; } @@ -1947,9 +1947,9 @@ int __glXDisp_RenderLarge(__GLXclientState *cl, GLbyte *pc) */ if (cl->largeCmdBufSize < cmdlen) { if (!cl->largeCmdBuf) { - cl->largeCmdBuf = (GLbyte *) xalloc(cmdlen); + cl->largeCmdBuf = (GLbyte *) malloc(cmdlen); } else { - cl->largeCmdBuf = (GLbyte *) xrealloc(cl->largeCmdBuf, cmdlen); + cl->largeCmdBuf = (GLbyte *) realloc(cl->largeCmdBuf, cmdlen); } if (!cl->largeCmdBuf) { return BadAlloc; @@ -2351,7 +2351,7 @@ int __glXDisp_QueryExtensionsString(__GLXclientState *cl, GLbyte *pc) reply.n = n; /* Allocate buffer to make sure it's a multiple of 4 bytes big.*/ - buf = (char *) xalloc(length << 2); + buf = (char *) malloc(length << 2); if (buf == NULL) return BadAlloc; memcpy(buf, pGlxScreen->GLXextensions, n); @@ -2363,7 +2363,7 @@ int __glXDisp_QueryExtensionsString(__GLXclientState *cl, GLbyte *pc) WriteToClient(client, (int)(length << 2), (char *)buf); } - xfree(buf); + free(buf); return Success; } @@ -2407,7 +2407,7 @@ int __glXDisp_QueryServerString(__GLXclientState *cl, GLbyte *pc) reply.length = length; reply.n = n; - buf = (char *) xalloc(length << 2); + buf = (char *) malloc(length << 2); if (buf == NULL) { return BadAlloc; } @@ -2420,7 +2420,7 @@ int __glXDisp_QueryServerString(__GLXclientState *cl, GLbyte *pc) WriteToClient(client, (int)(length << 2), buf); } - xfree(buf); + free(buf); return Success; } @@ -2432,7 +2432,7 @@ int __glXDisp_ClientInfo(__GLXclientState *cl, GLbyte *pc) cl->GLClientmajorVersion = req->major; cl->GLClientminorVersion = req->minor; if (cl->GLClientextensions) - xfree(cl->GLClientextensions); + free(cl->GLClientextensions); buf = (const char *)(req+1); cl->GLClientextensions = xstrdup(buf); diff --git a/xorg-server/glx/glxdri.c b/xorg-server/glx/glxdri.c index 7ee3d9938..d92115bc0 100644 --- a/xorg-server/glx/glxdri.c +++ b/xorg-server/glx/glxdri.c @@ -242,7 +242,7 @@ __glXDRIdrawableDestroy(__GLXdrawable *drawable) __glXDrawableRelease(drawable); - xfree(private); + free(private); } static GLboolean @@ -299,7 +299,7 @@ __glXDRIcontextDestroy(__GLXcontext *baseContext) __glXleaveServer(GL_FALSE); __glXContextDestroy(&context->base); - xfree(context); + free(context); } static int @@ -495,7 +495,7 @@ nooverride: unsigned pitch = PixmapBytePad(pixmap->drawable.width, pixmap->drawable.depth); - data = xalloc(pitch * pixmap->drawable.height); + data = malloc(pitch * pixmap->drawable.height); __glXenterServer(GL_FALSE); pScreen->GetImage(&pixmap->drawable, 0 /*pixmap->drawable.x*/, @@ -526,7 +526,7 @@ nooverride: type, data) ); - xfree(data); + free(data); } else if (!override) { int i, numRects; BoxPtr p; @@ -541,7 +541,7 @@ nooverride: { unsigned pitch = PixmapBytePad(p[i].x2 - p[i].x1, pixmap->drawable.depth); - void *data = xalloc(pitch * (p[i].y2 - p[i].y1)); + void *data = malloc(pitch * (p[i].y2 - p[i].y1)); __glXenterServer(GL_FALSE); pScreen->GetImage(&pixmap->drawable, /*pixmap->drawable.x +*/ p[i].x1, @@ -567,7 +567,7 @@ nooverride: type, data) ); - xfree(data); + free(data); } } @@ -607,7 +607,7 @@ __glXDRIscreenDestroy(__GLXscreen *baseScreen) __glXScreenDestroy(baseScreen); - xfree(screen); + free(screen); } static __GLXcontext * @@ -634,7 +634,7 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, if (baseShareContext && baseShareContext->isDirect) return NULL; - context = xcalloc(1, sizeof *context); + context = calloc(1, sizeof *context); if (context == NULL) return NULL; @@ -675,7 +675,7 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, __glXenterServer(GL_FALSE); retval = DRIDestroyContext(baseScreen->pScreen, context->hwContextID); __glXleaveServer(GL_FALSE); - xfree(context); + free(context); return NULL; } @@ -697,13 +697,13 @@ __glXDRIscreenCreateDrawable(ClientPtr client, GLboolean retval; drm_drawable_t hwDrawable; - private = xcalloc(1, sizeof *private); + private = calloc(1, sizeof *private); if (private == NULL) return NULL; if (!__glXDrawableInit(&private->base, screen, pDraw, type, glxDrawId, glxConfig)) { - xfree(private); + free(private); return NULL; } @@ -719,7 +719,7 @@ __glXDRIscreenCreateDrawable(ClientPtr client, __glXleaveServer(GL_FALSE); if (!retval) { - xfree(private); + free(private); return NULL; } @@ -735,7 +735,7 @@ __glXDRIscreenCreateDrawable(ClientPtr client, __glXenterServer(GL_FALSE); DRIDestroyDrawable(screen->pScreen, serverClient, pDraw); __glXleaveServer(GL_FALSE); - xfree(private); + free(private); return NULL; } @@ -772,7 +772,7 @@ getDrawableInfo(__DRIdrawable *driDrawable, if (retval && *numClipRects > 0) { size = sizeof (drm_clip_rect_t) * *numClipRects; - *ppClipRects = xalloc (size); + *ppClipRects = malloc(size); /* Clip cliprects to screen dimensions (redirected windows) */ if (*ppClipRects != NULL) { @@ -792,7 +792,7 @@ getDrawableInfo(__DRIdrawable *driDrawable, if (*numClipRects != j) { *numClipRects = j; - *ppClipRects = xrealloc (*ppClipRects, + *ppClipRects = realloc(*ppClipRects, sizeof (drm_clip_rect_t) * *numClipRects); } @@ -806,7 +806,7 @@ getDrawableInfo(__DRIdrawable *driDrawable, if (retval && *numBackClipRects > 0) { size = sizeof (drm_clip_rect_t) * *numBackClipRects; - *ppBackClipRects = xalloc (size); + *ppBackClipRects = malloc(size); if (*ppBackClipRects != NULL) memcpy (*ppBackClipRects, pBackClipRects, size); else @@ -977,7 +977,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) return NULL; } - screen = xcalloc(1, sizeof *screen); + screen = calloc(1, sizeof *screen); if (screen == NULL) return NULL; @@ -1148,7 +1148,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); if (buffer_size > 0) { if (screen->base.GLXextensions != NULL) { - xfree(screen->base.GLXextensions); + free(screen->base.GLXextensions); } screen->base.GLXextensions = xnfalloc(buffer_size); @@ -1183,7 +1183,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) if (screen->driver) dlclose(screen->driver); - xfree(screen); + free(screen); LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); diff --git a/xorg-server/glx/glxdri2.c b/xorg-server/glx/glxdri2.c index f1396b54d..a02e71a71 100644 --- a/xorg-server/glx/glxdri2.c +++ b/xorg-server/glx/glxdri2.c @@ -107,7 +107,7 @@ __glXDRIdrawableDestroy(__GLXdrawable *drawable) __glXDrawableRelease(drawable); - xfree(private); + free(private); } static void @@ -248,7 +248,7 @@ __glXDRIcontextDestroy(__GLXcontext *baseContext) (*screen->core->destroyContext)(context->driContext); __glXContextDestroy(&context->base); - xfree(context); + free(context); } static int @@ -386,7 +386,7 @@ __glXDRIscreenDestroy(__GLXscreen *baseScreen) __glXScreenDestroy(baseScreen); - xfree(screen); + free(screen); } static __GLXcontext * @@ -405,7 +405,7 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, else driShare = NULL; - context = xcalloc(1, sizeof *context); + context = calloc(1, sizeof *context); if (context == NULL) return NULL; @@ -422,13 +422,24 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, config->driConfig, driShare, context); if (context->driContext == NULL) { - xfree(context); + free(context); return NULL; } return &context->base; } +static void +__glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv) +{ +#if __DRI2_FLUSH_VERSION >= 3 + __GLXDRIdrawable *private = priv; + __GLXDRIscreen *screen = private->screen; + + (*screen->flush->invalidate)(private->driDrawable); +#endif +} + static __GLXdrawable * __glXDRIscreenCreateDrawable(ClientPtr client, __GLXscreen *screen, @@ -442,14 +453,14 @@ __glXDRIscreenCreateDrawable(ClientPtr client, __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; __GLXDRIdrawable *private; - private = xcalloc(1, sizeof *private); + private = calloc(1, sizeof *private); if (private == NULL) return NULL; private->screen = driScreen; if (!__glXDrawableInit(&private->base, screen, pDraw, type, glxDrawId, glxConfig)) { - xfree(private); + free(private); return NULL; } @@ -459,8 +470,9 @@ __glXDRIscreenCreateDrawable(ClientPtr client, private->base.waitGL = __glXDRIdrawableWaitGL; private->base.waitX = __glXDRIdrawableWaitX; - if (DRI2CreateDrawable(client, pDraw, drawId)) { - xfree(private); + if (DRI2CreateDrawable(client, pDraw, drawId, + __glXDRIinvalidateBuffers, private)) { + free(private); return NULL; } @@ -573,9 +585,18 @@ static const __DRIdri2LoaderExtension loaderExtension = { dri2GetBuffersWithFormat, }; +#ifdef __DRI_USE_INVALIDATE +static const __DRIuseInvalidateExtension dri2UseInvalidate = { + { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } +}; +#endif + static const __DRIextension *loader_extensions[] = { &systemTimeExtension.base, &loaderExtension.base, +#ifdef __DRI_USE_INVALIDATE + &dri2UseInvalidate, +#endif NULL }; @@ -676,7 +697,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) const __DRIconfig **driConfigs; int i; - screen = xcalloc(1, sizeof *screen); + screen = calloc(1, sizeof *screen); if (screen == NULL) return NULL; @@ -759,7 +780,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); if (buffer_size > 0) { if (screen->base.GLXextensions != NULL) { - xfree(screen->base.GLXextensions); + free(screen->base.GLXextensions); } screen->base.GLXextensions = xnfalloc(buffer_size); @@ -793,7 +814,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) if (screen->driver) dlclose(screen->driver); - xfree(screen); + free(screen); LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); diff --git a/xorg-server/glx/glxdricommon.c b/xorg-server/glx/glxdricommon.c index 454aa5587..44078fb41 100644 --- a/xorg-server/glx/glxdricommon.c +++ b/xorg-server/glx/glxdricommon.c @@ -1,206 +1,206 @@ -/* - * Copyright © 2008 Red Hat, Inc - * - * 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 the - * copyright holders not be used in advertising or publicity - * pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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 -#include -#include "glxserver.h" -#include "glxcontext.h" -#include "glxscreens.h" -#include "glxdricommon.h" - -static int -getUST(int64_t *ust) -{ - struct timeval tv; - - if (ust == NULL) - return -EFAULT; - - if (gettimeofday(&tv, NULL) == 0) { - ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec; - return 0; - } else { - return -errno; - } -} - -const __DRIsystemTimeExtension systemTimeExtension = { - { __DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION }, - getUST, - NULL, -}; - -#define __ATTRIB(attrib, field) \ - { attrib, offsetof(__GLXconfig, field) } - -static const struct { unsigned int attrib, offset; } attribMap[] = { - __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits), - __ATTRIB(__DRI_ATTRIB_LEVEL, level), - __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits), - __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits), - __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits), - __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits), - __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits), - __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits), - __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits), - __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits), - __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits), - __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits), - __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers), - __ATTRIB(__DRI_ATTRIB_SAMPLES, samples), - __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode), - __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode), - __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentPixel), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha), - __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask), - __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask), - __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask), - __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask), - __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth), - __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight), - __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels), - __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth), - __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight), - __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod), - __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb), - __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba), - __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture), - __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted), -}; - -#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) - -static void -setScalar(__GLXconfig *config, unsigned int attrib, unsigned int value) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(attribMap); i++) - if (attribMap[i].attrib == attrib) { - *(unsigned int *) ((char *) config + attribMap[i].offset) = value; - return; - } -} - -static __GLXconfig * -createModeFromConfig(const __DRIcoreExtension *core, - const __DRIconfig *driConfig, - unsigned int visualType, unsigned int drawableType) -{ - __GLXDRIconfig *config; - unsigned int attrib, value; - int i; - - config = xalloc(sizeof *config); - - config->driConfig = driConfig; - - i = 0; - while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) { - switch (attrib) { - case __DRI_ATTRIB_RENDER_TYPE: - config->config.renderType = 0; - if (value & __DRI_ATTRIB_RGBA_BIT) - config->config.renderType |= GLX_RGBA_BIT; - if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) - config->config.renderType |= GLX_COLOR_INDEX_BIT; - break; - case __DRI_ATTRIB_CONFIG_CAVEAT: - if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) - config->config.visualRating = GLX_NON_CONFORMANT_CONFIG; - else if (value & __DRI_ATTRIB_SLOW_BIT) - config->config.visualRating = GLX_SLOW_CONFIG; - else - config->config.visualRating = GLX_NONE; - break; - case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS: - config->config.bindToTextureTargets = 0; - if (value & __DRI_ATTRIB_TEXTURE_1D_BIT) - config->config.bindToTextureTargets |= GLX_TEXTURE_1D_BIT_EXT; - if (value & __DRI_ATTRIB_TEXTURE_2D_BIT) - config->config.bindToTextureTargets |= GLX_TEXTURE_2D_BIT_EXT; - if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT) - config->config.bindToTextureTargets |= GLX_TEXTURE_RECTANGLE_BIT_EXT; - break; - default: - setScalar(&config->config, attrib, value); - break; - } - } - - config->config.next = NULL; - config->config.xRenderable = GL_TRUE; - config->config.visualType = visualType; - config->config.drawableType = drawableType; - - return &config->config; -} - -__GLXconfig * -glxConvertConfigs(const __DRIcoreExtension *core, - const __DRIconfig **configs, unsigned int drawableType) -{ - __GLXconfig head, *tail; - int i; - - tail = &head; - head.next = NULL; - - for (i = 0; configs[i]; i++) { - tail->next = createModeFromConfig(core, - configs[i], GLX_TRUE_COLOR, - drawableType); - if (tail->next == NULL) - break; - - tail = tail->next; - } - - for (i = 0; configs[i]; i++) { - tail->next = createModeFromConfig(core, - configs[i], GLX_DIRECT_COLOR, - drawableType); - if (tail->next == NULL) - break; - - tail = tail->next; - } - - return head.next; -} +/* + * Copyright © 2008 Red Hat, Inc + * + * 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 the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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 +#include +#include "glxserver.h" +#include "glxcontext.h" +#include "glxscreens.h" +#include "glxdricommon.h" + +static int +getUST(int64_t *ust) +{ + struct timeval tv; + + if (ust == NULL) + return -EFAULT; + + if (gettimeofday(&tv, NULL) == 0) { + ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec; + return 0; + } else { + return -errno; + } +} + +const __DRIsystemTimeExtension systemTimeExtension = { + { __DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION }, + getUST, + NULL, +}; + +#define __ATTRIB(attrib, field) \ + { attrib, offsetof(__GLXconfig, field) } + +static const struct { unsigned int attrib, offset; } attribMap[] = { + __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits), + __ATTRIB(__DRI_ATTRIB_LEVEL, level), + __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits), + __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits), + __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits), + __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits), + __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits), + __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits), + __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits), + __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits), + __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits), + __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits), + __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers), + __ATTRIB(__DRI_ATTRIB_SAMPLES, samples), + __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode), + __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode), + __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers), + __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel), + __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentPixel), + __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed), + __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen), + __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue), + __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha), + __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask), + __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask), + __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask), + __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask), + __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth), + __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight), + __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels), + __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth), + __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight), + __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod), + __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb), + __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba), + __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture), + __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted), +}; + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +static void +setScalar(__GLXconfig *config, unsigned int attrib, unsigned int value) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(attribMap); i++) + if (attribMap[i].attrib == attrib) { + *(unsigned int *) ((char *) config + attribMap[i].offset) = value; + return; + } +} + +static __GLXconfig * +createModeFromConfig(const __DRIcoreExtension *core, + const __DRIconfig *driConfig, + unsigned int visualType, unsigned int drawableType) +{ + __GLXDRIconfig *config; + unsigned int attrib, value; + int i; + + config = malloc(sizeof *config); + + config->driConfig = driConfig; + + i = 0; + while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) { + switch (attrib) { + case __DRI_ATTRIB_RENDER_TYPE: + config->config.renderType = 0; + if (value & __DRI_ATTRIB_RGBA_BIT) + config->config.renderType |= GLX_RGBA_BIT; + if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) + config->config.renderType |= GLX_COLOR_INDEX_BIT; + break; + case __DRI_ATTRIB_CONFIG_CAVEAT: + if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) + config->config.visualRating = GLX_NON_CONFORMANT_CONFIG; + else if (value & __DRI_ATTRIB_SLOW_BIT) + config->config.visualRating = GLX_SLOW_CONFIG; + else + config->config.visualRating = GLX_NONE; + break; + case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS: + config->config.bindToTextureTargets = 0; + if (value & __DRI_ATTRIB_TEXTURE_1D_BIT) + config->config.bindToTextureTargets |= GLX_TEXTURE_1D_BIT_EXT; + if (value & __DRI_ATTRIB_TEXTURE_2D_BIT) + config->config.bindToTextureTargets |= GLX_TEXTURE_2D_BIT_EXT; + if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT) + config->config.bindToTextureTargets |= GLX_TEXTURE_RECTANGLE_BIT_EXT; + break; + default: + setScalar(&config->config, attrib, value); + break; + } + } + + config->config.next = NULL; + config->config.xRenderable = GL_TRUE; + config->config.visualType = visualType; + config->config.drawableType = drawableType; + + return &config->config; +} + +__GLXconfig * +glxConvertConfigs(const __DRIcoreExtension *core, + const __DRIconfig **configs, unsigned int drawableType) +{ + __GLXconfig head, *tail; + int i; + + tail = &head; + head.next = NULL; + + for (i = 0; configs[i]; i++) { + tail->next = createModeFromConfig(core, + configs[i], GLX_TRUE_COLOR, + drawableType); + if (tail->next == NULL) + break; + + tail = tail->next; + } + + for (i = 0; configs[i]; i++) { + tail->next = createModeFromConfig(core, + configs[i], GLX_DIRECT_COLOR, + drawableType); + if (tail->next == NULL) + break; + + tail = tail->next; + } + + return head.next; +} diff --git a/xorg-server/glx/glxdriswrast.c b/xorg-server/glx/glxdriswrast.c index 8ab3daa46..acdcc645c 100644 --- a/xorg-server/glx/glxdriswrast.c +++ b/xorg-server/glx/glxdriswrast.c @@ -104,7 +104,7 @@ __glXDRIdrawableDestroy(__GLXdrawable *drawable) __glXDrawableRelease(drawable); - xfree(private); + free(private); } static GLboolean @@ -138,7 +138,7 @@ __glXDRIcontextDestroy(__GLXcontext *baseContext) (*screen->core->destroyContext)(context->driContext); __glXContextDestroy(&context->base); - xfree(context); + free(context); } static int @@ -254,7 +254,7 @@ __glXDRIscreenDestroy(__GLXscreen *baseScreen) __glXScreenDestroy(baseScreen); - xfree(screen); + free(screen); } static __GLXcontext * @@ -274,7 +274,7 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, else driShare = NULL; - context = xcalloc(1, sizeof *context); + context = calloc(1, sizeof *context); if (context == NULL) return NULL; @@ -292,14 +292,6 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, return &context->base; } -static void -glxChangeGC(GCPtr gc, BITS32 mask, CARD32 val) -{ - CARD32 v[1]; - v[0] = val; - dixChangeGC(NullClient, gc, mask, v, NULL); -} - static __GLXdrawable * __glXDRIscreenCreateDrawable(ClientPtr client, __GLXscreen *screen, @@ -309,20 +301,21 @@ __glXDRIscreenCreateDrawable(ClientPtr client, XID glxDrawId, __GLXconfig *glxConfig) { + ChangeGCVal gcvals[2]; __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; __GLXDRIdrawable *private; ScreenPtr pScreen = driScreen->base.pScreen; - private = xcalloc(1, sizeof *private); + private = calloc(1, sizeof *private); if (private == NULL) return NULL; private->screen = driScreen; if (!__glXDrawableInit(&private->base, screen, pDraw, type, glxDrawId, glxConfig)) { - xfree(private); + free(private); return NULL; } @@ -333,9 +326,10 @@ __glXDRIscreenCreateDrawable(ClientPtr client, private->gc = CreateScratchGC(pScreen, pDraw->depth); private->swapgc = CreateScratchGC(pScreen, pDraw->depth); - glxChangeGC(private->gc, GCFunction, GXcopy); - glxChangeGC(private->swapgc, GCFunction, GXcopy); - glxChangeGC(private->swapgc, GCGraphicsExposures, FALSE); + gcvals[0].val = GXcopy; + ChangeGC(NullClient, private->gc, GCFunction, gcvals); + gcvals[1].val = FALSE; + ChangeGC(NullClient, private->gc, GCFunction | GCGraphicsExposures, gcvals); private->driDrawable = (*driScreen->swrast->createNewDrawable)(driScreen->driScreen, @@ -450,7 +444,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) const __DRIconfig **driConfigs; int i; - screen = xcalloc(1, sizeof *screen); + screen = calloc(1, sizeof *screen); if (screen == NULL) return NULL; @@ -527,7 +521,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) if (screen->driver) dlclose(screen->driver); - xfree(screen); + free(screen); LogMessage(X_ERROR, "GLX: could not load software renderer\n"); diff --git a/xorg-server/glx/glxext.c b/xorg-server/glx/glxext.c index 89e58b0b0..349b0f983 100644 --- a/xorg-server/glx/glxext.c +++ b/xorg-server/glx/glxext.c @@ -1,610 +1,610 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include "glxserver.h" -#include -#include -#include -#include "privates.h" -#include -#include "g_disptab.h" -#include "unpack.h" -#include "glxutil.h" -#include "glxext.h" -#include "indirect_table.h" -#include "indirect_util.h" - -/* -** The last context used by the server. It is the context that is current -** from the server's perspective. -*/ -__GLXcontext *__glXLastContext; -__GLXcontext *__glXContextList; - -/* -** X resources. -*/ -RESTYPE __glXContextRes; -RESTYPE __glXDrawableRes; -RESTYPE __glXSwapBarrierRes; - -/* -** Reply for most singles. -*/ -xGLXSingleReply __glXReply; - -static int glxClientPrivateKeyIndex; -static DevPrivateKey glxClientPrivateKey = &glxClientPrivateKeyIndex; - -/* -** Client that called into GLX dispatch. -*/ -ClientPtr __pGlxClient; - -/* -** Forward declarations. -*/ -static int __glXDispatch(ClientPtr); - -/* -** Called when the extension is reset. -*/ -static void ResetExtension(ExtensionEntry* extEntry) -{ - __glXFlushContextCache(); -} - -/* -** Reset state used to keep track of large (multi-request) commands. -*/ -void __glXResetLargeCommandStatus(__GLXclientState *cl) -{ - cl->largeCmdBytesSoFar = 0; - cl->largeCmdBytesTotal = 0; - cl->largeCmdRequestsSoFar = 0; - cl->largeCmdRequestsTotal = 0; -} - -/* -** This procedure is called when the client who created the context goes -** away OR when glXDestroyContext is called. In either case, all we do is -** flag that the ID is no longer valid, and (maybe) free the context. -** use. -*/ -static int ContextGone(__GLXcontext* cx, XID id) -{ - cx->idExists = GL_FALSE; - if (!cx->isCurrent) { - __glXFreeContext(cx); - } - - return True; -} - -static __GLXcontext *glxPendingDestroyContexts; -static __GLXcontext *glxAllContexts; -static int glxServerLeaveCount; -static int glxBlockClients; - -/* -** Destroy routine that gets called when a drawable is freed. A drawable -** contains the ancillary buffers needed for rendering. -*/ -static Bool DrawableGone(__GLXdrawable *glxPriv, XID xid) -{ - __GLXcontext *c; - - /* If this drawable was created using glx 1.3 drawable - * constructors, we added it as a glx drawable resource under both - * its glx drawable ID and it X drawable ID. Remove the other - * resource now so we don't a callback for freed memory. */ - if (glxPriv->drawId != glxPriv->pDraw->id) { - if (xid == glxPriv->drawId) - FreeResourceByType(glxPriv->pDraw->id, __glXDrawableRes, TRUE); - else - FreeResourceByType(glxPriv->drawId, __glXDrawableRes, TRUE); - } - - for (c = glxAllContexts; c; c = c->next) { - if (c->isCurrent && (c->drawPriv == glxPriv || c->readPriv == glxPriv)) { - int i; - - (*c->loseCurrent)(c); - c->isCurrent = GL_FALSE; - if (c == __glXLastContext) - __glXFlushContextCache(); - - for (i = 1; i < currentMaxClients; i++) { - if (clients[i]) { - __GLXclientState *cl = glxGetClient(clients[i]); - - if (cl->inUse) { - int j; - - for (j = 0; j < cl->numCurrentContexts; j++) { - if (cl->currentContexts[j] == c) - cl->currentContexts[j] = NULL; - } - } - } - } - - if (!c->idExists) { - __glXFreeContext(c); - } - } - if (c->drawPriv == glxPriv) - c->drawPriv = NULL; - if (c->readPriv == glxPriv) - c->readPriv = NULL; - } - - glxPriv->destroy(glxPriv); - - return True; -} - -void __glXAddToContextList(__GLXcontext *cx) -{ - cx->next = glxAllContexts; - glxAllContexts = cx; -} - -static void __glXRemoveFromContextList(__GLXcontext *cx) -{ - __GLXcontext *c, *prev; - - if (cx == glxAllContexts) - glxAllContexts = cx->next; - else { - prev = glxAllContexts; - for (c = glxAllContexts; c; c = c->next) { - if (c == cx) - prev->next = c->next; - prev = c; - } - } -} - -/* -** Free a context. -*/ -GLboolean __glXFreeContext(__GLXcontext *cx) -{ - if (cx->idExists || cx->isCurrent) return GL_FALSE; - - if (cx->feedbackBuf) xfree(cx->feedbackBuf); - if (cx->selectBuf) xfree(cx->selectBuf); - if (cx == __glXLastContext) { - __glXFlushContextCache(); - } - - __glXRemoveFromContextList(cx); - - /* We can get here through both regular dispatching from - * __glXDispatch() or as a callback from the resource manager. In - * the latter case we need to lift the DRI lock manually. */ - - if (!glxBlockClients) { - __glXleaveServer(GL_FALSE); - cx->destroy(cx); - __glXenterServer(GL_FALSE); - } else { - cx->next = glxPendingDestroyContexts; - glxPendingDestroyContexts = cx; - } - - return GL_TRUE; -} - -extern RESTYPE __glXSwapBarrierRes; - -static int SwapBarrierGone(int screen, XID drawable) -{ - __GLXscreen *pGlxScreen = glxGetScreen(screenInfo.screens[screen]); - - if (pGlxScreen->swapBarrierFuncs) { - pGlxScreen->swapBarrierFuncs->bindSwapBarrierFunc(screen, drawable, 0); - } - FreeResourceByType(drawable, __glXSwapBarrierRes, FALSE); - return True; -} - -/************************************************************************/ - -/* -** These routines can be used to check whether a particular GL command -** has caused an error. Specifically, we use them to check whether a -** given query has caused an error, in which case a zero-length data -** reply is sent to the client. -*/ - -static GLboolean errorOccured = GL_FALSE; - -/* -** The GL was will call this routine if an error occurs. -*/ -void __glXErrorCallBack(GLenum code) -{ - errorOccured = GL_TRUE; -} - -/* -** Clear the error flag before calling the GL command. -*/ -void __glXClearErrorOccured(void) -{ - errorOccured = GL_FALSE; -} - -/* -** Check if the GL command caused an error. -*/ -GLboolean __glXErrorOccured(void) -{ - return errorOccured; -} - -static int __glXErrorBase; -int __glXEventBase; - -int __glXError(int error) -{ - return __glXErrorBase + error; -} - -__GLXclientState * -glxGetClient(ClientPtr pClient) -{ - return dixLookupPrivate(&pClient->devPrivates, glxClientPrivateKey); -} - -static void -glxClientCallback (CallbackListPtr *list, - pointer closure, - pointer data) -{ - NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; - ClientPtr pClient = clientinfo->client; - __GLXclientState *cl = glxGetClient(pClient); - __GLXcontext *cx; - int i; - - switch (pClient->clientState) { - case ClientStateRunning: - /* - ** By default, assume that the client supports - ** GLX major version 1 minor version 0 protocol. - */ - cl->GLClientmajorVersion = 1; - cl->GLClientminorVersion = 0; - cl->client = pClient; - break; - - case ClientStateGone: - for (i = 0; i < cl->numCurrentContexts; i++) { - cx = cl->currentContexts[i]; - if (cx) { - cx->isCurrent = GL_FALSE; - if (!cx->idExists) - __glXFreeContext(cx); - } - } - - if (cl->returnBuf) xfree(cl->returnBuf); - if (cl->largeCmdBuf) xfree(cl->largeCmdBuf); - if (cl->currentContexts) xfree(cl->currentContexts); - if (cl->GLClientextensions) xfree(cl->GLClientextensions); - break; - - default: - break; - } -} - -/************************************************************************/ - -static __GLXprovider *__glXProviderStack; - -void GlxPushProvider(__GLXprovider *provider) -{ - provider->next = __glXProviderStack; - __glXProviderStack = provider; -} - -/* -** Initialize the GLX extension. -*/ -void GlxExtensionInit(void) -{ - ExtensionEntry *extEntry; - ScreenPtr pScreen; - int i; - __GLXprovider *p; - Bool glx_provided = False; - - __glXContextRes = CreateNewResourceType((DeleteType)ContextGone, - "GLXContext"); - __glXDrawableRes = CreateNewResourceType((DeleteType)DrawableGone, - "GLXDrawable"); - __glXSwapBarrierRes = CreateNewResourceType((DeleteType)SwapBarrierGone, - "GLXSwapBarrier"); - if (!__glXContextRes || !__glXDrawableRes || !__glXSwapBarrierRes) - return; - - if (!dixRequestPrivate(glxClientPrivateKey, sizeof (__GLXclientState))) - return; - if (!AddCallback (&ClientStateCallback, glxClientCallback, 0)) - return; - - for (i = 0; i < screenInfo.numScreens; i++) { - pScreen = screenInfo.screens[i]; - - for (p = __glXProviderStack; p != NULL; p = p->next) { - __GLXscreen *glxScreen; - - glxScreen = p->screenProbe(pScreen); - if (glxScreen != NULL) { - if (glxScreen->GLXminor < glxMinorVersion) - glxMinorVersion = glxScreen->GLXminor; - LogMessage(X_INFO, - "GLX: Initialized %s GL provider for screen %d\n", - p->name, i); - break; - } - - } - - if (!p) - LogMessage(X_INFO, - "GLX: no usable GL providers found for screen %d\n", i); - else - glx_provided = True; - } - - /* don't register extension if GL is not provided on any screen */ - if (!glx_provided) - return; - - /* - ** Add extension to server extensions. - */ - extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS, - __GLX_NUMBER_ERRORS, __glXDispatch, - __glXDispatch, ResetExtension, - StandardMinorOpcode); - if (!extEntry) { - FatalError("__glXExtensionInit: AddExtensions failed\n"); - return; - } - if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) { - ErrorF("__glXExtensionInit: AddExtensionAlias failed\n"); - return; - } - - __glXErrorBase = extEntry->errorBase; - __glXEventBase = extEntry->eventBase; -} - -/************************************************************************/ - -void __glXFlushContextCache(void) -{ - __glXLastContext = 0; -} - -/* -** Make a context the current one for the GL (in this implementation, there -** is only one instance of the GL, and we use it to serve all GL clients by -** switching it between different contexts). While we are at it, look up -** a context by its tag and return its (__GLXcontext *). -*/ -__GLXcontext *__glXForceCurrent(__GLXclientState *cl, GLXContextTag tag, - int *error) -{ - __GLXcontext *cx; - - /* - ** See if the context tag is legal; it is managed by the extension, - ** so if it's invalid, we have an implementation error. - */ - cx = (__GLXcontext *) __glXLookupContextByTag(cl, tag); - if (!cx) { - cl->client->errorValue = tag; - *error = __glXError(GLXBadContextTag); - return 0; - } - - if (!cx->isDirect) { - if (cx->drawPriv == NULL) { - /* - ** The drawable has vanished. It must be a window, because only - ** windows can be destroyed from under us; GLX pixmaps are - ** refcounted and don't go away until no one is using them. - */ - *error = __glXError(GLXBadCurrentWindow); - return 0; - } - } - - if (cx->wait && (*cx->wait)(cx, cl, error)) - return NULL; - - if (cx == __glXLastContext) { - /* No need to re-bind */ - return cx; - } - - /* Make this context the current one for the GL. */ - if (!cx->isDirect) { - if (!(*cx->forceCurrent)(cx)) { - /* Bind failed, and set the error code. Bummer */ - cl->client->errorValue = cx->id; - *error = __glXError(GLXBadContextState); - return 0; - } - } - __glXLastContext = cx; - return cx; -} - -/************************************************************************/ - -void glxSuspendClients(void) -{ - int i; - - for (i = 1; i < currentMaxClients; i++) { - if (clients[i] && glxGetClient(clients[i])->inUse) - IgnoreClient(clients[i]); - } - - glxBlockClients = TRUE; -} - -void glxResumeClients(void) -{ - __GLXcontext *cx, *next; - int i; - - glxBlockClients = FALSE; - - for (i = 1; i < currentMaxClients; i++) { - if (clients[i] && glxGetClient(clients[i])->inUse) - AttendClient(clients[i]); - } - - __glXleaveServer(GL_FALSE); - for (cx = glxPendingDestroyContexts; cx != NULL; cx = next) { - next = cx->next; - - cx->destroy(cx); - } - glxPendingDestroyContexts = NULL; - __glXenterServer(GL_FALSE); -} - -static void -__glXnopEnterServer(GLboolean rendering) -{ -} - -static void -__glXnopLeaveServer(GLboolean rendering) -{ -} - -static void (*__glXenterServerFunc)(GLboolean) = __glXnopEnterServer; -static void (*__glXleaveServerFunc)(GLboolean) = __glXnopLeaveServer; - -void __glXsetEnterLeaveServerFuncs(void (*enter)(GLboolean), - void (*leave)(GLboolean)) -{ - __glXenterServerFunc = enter; - __glXleaveServerFunc = leave; -} - - -void __glXenterServer(GLboolean rendering) -{ - glxServerLeaveCount--; - - if (glxServerLeaveCount == 0) - (*__glXenterServerFunc)(rendering); -} - -void __glXleaveServer(GLboolean rendering) -{ - if (glxServerLeaveCount == 0) - (*__glXleaveServerFunc)(rendering); - - glxServerLeaveCount++; -} - -/* -** Top level dispatcher; all commands are executed from here down. -*/ -static int __glXDispatch(ClientPtr client) -{ - REQUEST(xGLXSingleReq); - CARD8 opcode; - __GLXdispatchSingleProcPtr proc; - __GLXclientState *cl; - int retval; - - opcode = stuff->glxCode; - cl = glxGetClient(client); - /* Mark it in use so we suspend it on VT switch. */ - cl->inUse = TRUE; - - /* - ** If we're expecting a glXRenderLarge request, this better be one. - */ - if ((cl->largeCmdRequestsSoFar != 0) && (opcode != X_GLXRenderLarge)) { - client->errorValue = stuff->glxCode; - return __glXError(GLXBadLargeRequest); - } - - /* If we're currently blocking GLX clients, just put this guy to - * sleep, reset the request and return. */ - if (glxBlockClients) { - ResetCurrentRequest(client); - client->sequence--; - IgnoreClient(client); - return(client->noClientException); - } - - /* - ** Use the opcode to index into the procedure table. - */ - proc = (__GLXdispatchSingleProcPtr) __glXGetProtocolDecodeFunction(& Single_dispatch_info, - opcode, - client->swapped); - if (proc != NULL) { - GLboolean rendering = opcode <= X_GLXRenderLarge; - __glXleaveServer(rendering); - - __pGlxClient = client; - - retval = (*proc)(cl, (GLbyte *) stuff); - - __glXenterServer(rendering); - } - else { - retval = BadRequest; - } - - return retval; -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "glxserver.h" +#include +#include +#include +#include "privates.h" +#include +#include "g_disptab.h" +#include "unpack.h" +#include "glxutil.h" +#include "glxext.h" +#include "indirect_table.h" +#include "indirect_util.h" + +/* +** The last context used by the server. It is the context that is current +** from the server's perspective. +*/ +__GLXcontext *__glXLastContext; +__GLXcontext *__glXContextList; + +/* +** X resources. +*/ +RESTYPE __glXContextRes; +RESTYPE __glXDrawableRes; +RESTYPE __glXSwapBarrierRes; + +/* +** Reply for most singles. +*/ +xGLXSingleReply __glXReply; + +static int glxClientPrivateKeyIndex; +static DevPrivateKey glxClientPrivateKey = &glxClientPrivateKeyIndex; + +/* +** Client that called into GLX dispatch. +*/ +ClientPtr __pGlxClient; + +/* +** Forward declarations. +*/ +static int __glXDispatch(ClientPtr); + +/* +** Called when the extension is reset. +*/ +static void ResetExtension(ExtensionEntry* extEntry) +{ + __glXFlushContextCache(); +} + +/* +** Reset state used to keep track of large (multi-request) commands. +*/ +void __glXResetLargeCommandStatus(__GLXclientState *cl) +{ + cl->largeCmdBytesSoFar = 0; + cl->largeCmdBytesTotal = 0; + cl->largeCmdRequestsSoFar = 0; + cl->largeCmdRequestsTotal = 0; +} + +/* +** This procedure is called when the client who created the context goes +** away OR when glXDestroyContext is called. In either case, all we do is +** flag that the ID is no longer valid, and (maybe) free the context. +** use. +*/ +static int ContextGone(__GLXcontext* cx, XID id) +{ + cx->idExists = GL_FALSE; + if (!cx->isCurrent) { + __glXFreeContext(cx); + } + + return True; +} + +static __GLXcontext *glxPendingDestroyContexts; +static __GLXcontext *glxAllContexts; +static int glxServerLeaveCount; +static int glxBlockClients; + +/* +** Destroy routine that gets called when a drawable is freed. A drawable +** contains the ancillary buffers needed for rendering. +*/ +static Bool DrawableGone(__GLXdrawable *glxPriv, XID xid) +{ + __GLXcontext *c; + + /* If this drawable was created using glx 1.3 drawable + * constructors, we added it as a glx drawable resource under both + * its glx drawable ID and it X drawable ID. Remove the other + * resource now so we don't a callback for freed memory. */ + if (glxPriv->drawId != glxPriv->pDraw->id) { + if (xid == glxPriv->drawId) + FreeResourceByType(glxPriv->pDraw->id, __glXDrawableRes, TRUE); + else + FreeResourceByType(glxPriv->drawId, __glXDrawableRes, TRUE); + } + + for (c = glxAllContexts; c; c = c->next) { + if (c->isCurrent && (c->drawPriv == glxPriv || c->readPriv == glxPriv)) { + int i; + + (*c->loseCurrent)(c); + c->isCurrent = GL_FALSE; + if (c == __glXLastContext) + __glXFlushContextCache(); + + for (i = 1; i < currentMaxClients; i++) { + if (clients[i]) { + __GLXclientState *cl = glxGetClient(clients[i]); + + if (cl->inUse) { + int j; + + for (j = 0; j < cl->numCurrentContexts; j++) { + if (cl->currentContexts[j] == c) + cl->currentContexts[j] = NULL; + } + } + } + } + + if (!c->idExists) { + __glXFreeContext(c); + } + } + if (c->drawPriv == glxPriv) + c->drawPriv = NULL; + if (c->readPriv == glxPriv) + c->readPriv = NULL; + } + + glxPriv->destroy(glxPriv); + + return True; +} + +void __glXAddToContextList(__GLXcontext *cx) +{ + cx->next = glxAllContexts; + glxAllContexts = cx; +} + +static void __glXRemoveFromContextList(__GLXcontext *cx) +{ + __GLXcontext *c, *prev; + + if (cx == glxAllContexts) + glxAllContexts = cx->next; + else { + prev = glxAllContexts; + for (c = glxAllContexts; c; c = c->next) { + if (c == cx) + prev->next = c->next; + prev = c; + } + } +} + +/* +** Free a context. +*/ +GLboolean __glXFreeContext(__GLXcontext *cx) +{ + if (cx->idExists || cx->isCurrent) return GL_FALSE; + + if (cx->feedbackBuf) free(cx->feedbackBuf); + if (cx->selectBuf) free(cx->selectBuf); + if (cx == __glXLastContext) { + __glXFlushContextCache(); + } + + __glXRemoveFromContextList(cx); + + /* We can get here through both regular dispatching from + * __glXDispatch() or as a callback from the resource manager. In + * the latter case we need to lift the DRI lock manually. */ + + if (!glxBlockClients) { + __glXleaveServer(GL_FALSE); + cx->destroy(cx); + __glXenterServer(GL_FALSE); + } else { + cx->next = glxPendingDestroyContexts; + glxPendingDestroyContexts = cx; + } + + return GL_TRUE; +} + +extern RESTYPE __glXSwapBarrierRes; + +static int SwapBarrierGone(int screen, XID drawable) +{ + __GLXscreen *pGlxScreen = glxGetScreen(screenInfo.screens[screen]); + + if (pGlxScreen->swapBarrierFuncs) { + pGlxScreen->swapBarrierFuncs->bindSwapBarrierFunc(screen, drawable, 0); + } + FreeResourceByType(drawable, __glXSwapBarrierRes, FALSE); + return True; +} + +/************************************************************************/ + +/* +** These routines can be used to check whether a particular GL command +** has caused an error. Specifically, we use them to check whether a +** given query has caused an error, in which case a zero-length data +** reply is sent to the client. +*/ + +static GLboolean errorOccured = GL_FALSE; + +/* +** The GL was will call this routine if an error occurs. +*/ +void __glXErrorCallBack(GLenum code) +{ + errorOccured = GL_TRUE; +} + +/* +** Clear the error flag before calling the GL command. +*/ +void __glXClearErrorOccured(void) +{ + errorOccured = GL_FALSE; +} + +/* +** Check if the GL command caused an error. +*/ +GLboolean __glXErrorOccured(void) +{ + return errorOccured; +} + +static int __glXErrorBase; +int __glXEventBase; + +int __glXError(int error) +{ + return __glXErrorBase + error; +} + +__GLXclientState * +glxGetClient(ClientPtr pClient) +{ + return dixLookupPrivate(&pClient->devPrivates, glxClientPrivateKey); +} + +static void +glxClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + __GLXclientState *cl = glxGetClient(pClient); + __GLXcontext *cx; + int i; + + switch (pClient->clientState) { + case ClientStateRunning: + /* + ** By default, assume that the client supports + ** GLX major version 1 minor version 0 protocol. + */ + cl->GLClientmajorVersion = 1; + cl->GLClientminorVersion = 0; + cl->client = pClient; + break; + + case ClientStateGone: + for (i = 0; i < cl->numCurrentContexts; i++) { + cx = cl->currentContexts[i]; + if (cx) { + cx->isCurrent = GL_FALSE; + if (!cx->idExists) + __glXFreeContext(cx); + } + } + + if (cl->returnBuf) free(cl->returnBuf); + if (cl->largeCmdBuf) free(cl->largeCmdBuf); + if (cl->currentContexts) free(cl->currentContexts); + if (cl->GLClientextensions) free(cl->GLClientextensions); + break; + + default: + break; + } +} + +/************************************************************************/ + +static __GLXprovider *__glXProviderStack; + +void GlxPushProvider(__GLXprovider *provider) +{ + provider->next = __glXProviderStack; + __glXProviderStack = provider; +} + +/* +** Initialize the GLX extension. +*/ +void GlxExtensionInit(void) +{ + ExtensionEntry *extEntry; + ScreenPtr pScreen; + int i; + __GLXprovider *p; + Bool glx_provided = False; + + __glXContextRes = CreateNewResourceType((DeleteType)ContextGone, + "GLXContext"); + __glXDrawableRes = CreateNewResourceType((DeleteType)DrawableGone, + "GLXDrawable"); + __glXSwapBarrierRes = CreateNewResourceType((DeleteType)SwapBarrierGone, + "GLXSwapBarrier"); + if (!__glXContextRes || !__glXDrawableRes || !__glXSwapBarrierRes) + return; + + if (!dixRequestPrivate(glxClientPrivateKey, sizeof (__GLXclientState))) + return; + if (!AddCallback (&ClientStateCallback, glxClientCallback, 0)) + return; + + for (i = 0; i < screenInfo.numScreens; i++) { + pScreen = screenInfo.screens[i]; + + for (p = __glXProviderStack; p != NULL; p = p->next) { + __GLXscreen *glxScreen; + + glxScreen = p->screenProbe(pScreen); + if (glxScreen != NULL) { + if (glxScreen->GLXminor < glxMinorVersion) + glxMinorVersion = glxScreen->GLXminor; + LogMessage(X_INFO, + "GLX: Initialized %s GL provider for screen %d\n", + p->name, i); + break; + } + + } + + if (!p) + LogMessage(X_INFO, + "GLX: no usable GL providers found for screen %d\n", i); + else + glx_provided = True; + } + + /* don't register extension if GL is not provided on any screen */ + if (!glx_provided) + return; + + /* + ** Add extension to server extensions. + */ + extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS, + __GLX_NUMBER_ERRORS, __glXDispatch, + __glXDispatch, ResetExtension, + StandardMinorOpcode); + if (!extEntry) { + FatalError("__glXExtensionInit: AddExtensions failed\n"); + return; + } + if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) { + ErrorF("__glXExtensionInit: AddExtensionAlias failed\n"); + return; + } + + __glXErrorBase = extEntry->errorBase; + __glXEventBase = extEntry->eventBase; +} + +/************************************************************************/ + +void __glXFlushContextCache(void) +{ + __glXLastContext = 0; +} + +/* +** Make a context the current one for the GL (in this implementation, there +** is only one instance of the GL, and we use it to serve all GL clients by +** switching it between different contexts). While we are at it, look up +** a context by its tag and return its (__GLXcontext *). +*/ +__GLXcontext *__glXForceCurrent(__GLXclientState *cl, GLXContextTag tag, + int *error) +{ + __GLXcontext *cx; + + /* + ** See if the context tag is legal; it is managed by the extension, + ** so if it's invalid, we have an implementation error. + */ + cx = (__GLXcontext *) __glXLookupContextByTag(cl, tag); + if (!cx) { + cl->client->errorValue = tag; + *error = __glXError(GLXBadContextTag); + return 0; + } + + if (!cx->isDirect) { + if (cx->drawPriv == NULL) { + /* + ** The drawable has vanished. It must be a window, because only + ** windows can be destroyed from under us; GLX pixmaps are + ** refcounted and don't go away until no one is using them. + */ + *error = __glXError(GLXBadCurrentWindow); + return 0; + } + } + + if (cx->wait && (*cx->wait)(cx, cl, error)) + return NULL; + + if (cx == __glXLastContext) { + /* No need to re-bind */ + return cx; + } + + /* Make this context the current one for the GL. */ + if (!cx->isDirect) { + if (!(*cx->forceCurrent)(cx)) { + /* Bind failed, and set the error code. Bummer */ + cl->client->errorValue = cx->id; + *error = __glXError(GLXBadContextState); + return 0; + } + } + __glXLastContext = cx; + return cx; +} + +/************************************************************************/ + +void glxSuspendClients(void) +{ + int i; + + for (i = 1; i < currentMaxClients; i++) { + if (clients[i] && glxGetClient(clients[i])->inUse) + IgnoreClient(clients[i]); + } + + glxBlockClients = TRUE; +} + +void glxResumeClients(void) +{ + __GLXcontext *cx, *next; + int i; + + glxBlockClients = FALSE; + + for (i = 1; i < currentMaxClients; i++) { + if (clients[i] && glxGetClient(clients[i])->inUse) + AttendClient(clients[i]); + } + + __glXleaveServer(GL_FALSE); + for (cx = glxPendingDestroyContexts; cx != NULL; cx = next) { + next = cx->next; + + cx->destroy(cx); + } + glxPendingDestroyContexts = NULL; + __glXenterServer(GL_FALSE); +} + +static void +__glXnopEnterServer(GLboolean rendering) +{ +} + +static void +__glXnopLeaveServer(GLboolean rendering) +{ +} + +static void (*__glXenterServerFunc)(GLboolean) = __glXnopEnterServer; +static void (*__glXleaveServerFunc)(GLboolean) = __glXnopLeaveServer; + +void __glXsetEnterLeaveServerFuncs(void (*enter)(GLboolean), + void (*leave)(GLboolean)) +{ + __glXenterServerFunc = enter; + __glXleaveServerFunc = leave; +} + + +void __glXenterServer(GLboolean rendering) +{ + glxServerLeaveCount--; + + if (glxServerLeaveCount == 0) + (*__glXenterServerFunc)(rendering); +} + +void __glXleaveServer(GLboolean rendering) +{ + if (glxServerLeaveCount == 0) + (*__glXleaveServerFunc)(rendering); + + glxServerLeaveCount++; +} + +/* +** Top level dispatcher; all commands are executed from here down. +*/ +static int __glXDispatch(ClientPtr client) +{ + REQUEST(xGLXSingleReq); + CARD8 opcode; + __GLXdispatchSingleProcPtr proc; + __GLXclientState *cl; + int retval; + + opcode = stuff->glxCode; + cl = glxGetClient(client); + /* Mark it in use so we suspend it on VT switch. */ + cl->inUse = TRUE; + + /* + ** If we're expecting a glXRenderLarge request, this better be one. + */ + if ((cl->largeCmdRequestsSoFar != 0) && (opcode != X_GLXRenderLarge)) { + client->errorValue = stuff->glxCode; + return __glXError(GLXBadLargeRequest); + } + + /* If we're currently blocking GLX clients, just put this guy to + * sleep, reset the request and return. */ + if (glxBlockClients) { + ResetCurrentRequest(client); + client->sequence--; + IgnoreClient(client); + return Success; + } + + /* + ** Use the opcode to index into the procedure table. + */ + proc = (__GLXdispatchSingleProcPtr) __glXGetProtocolDecodeFunction(& Single_dispatch_info, + opcode, + client->swapped); + if (proc != NULL) { + GLboolean rendering = opcode <= X_GLXRenderLarge; + __glXleaveServer(rendering); + + __pGlxClient = client; + + retval = (*proc)(cl, (GLbyte *) stuff); + + __glXenterServer(rendering); + } + else { + retval = BadRequest; + } + + return retval; +} diff --git a/xorg-server/glx/glxscreens.c b/xorg-server/glx/glxscreens.c index 3d3c23feb..4bd2eed5e 100644 --- a/xorg-server/glx/glxscreens.c +++ b/xorg-server/glx/glxscreens.c @@ -378,7 +378,7 @@ void __glXScreenInit(__GLXscreen *pGlxScreen, ScreenPtr pScreen) pGlxScreen->numFBConfigs = i; pGlxScreen->visuals = - xcalloc(pGlxScreen->numFBConfigs, sizeof (__GLXconfig *)); + calloc(pGlxScreen->numFBConfigs, sizeof (__GLXconfig *)); /* First, try to choose featureful FBconfigs for the existing X visuals. * Note that if multiple X visuals end up with the same FBconfig being @@ -440,7 +440,7 @@ void __glXScreenInit(__GLXscreen *pGlxScreen, ScreenPtr pScreen) void __glXScreenDestroy(__GLXscreen *screen) { - xfree(screen->GLXvendor); - xfree(screen->GLXextensions); - xfree(screen->GLextensions); + free(screen->GLXvendor); + free(screen->GLXextensions); + free(screen->GLextensions); } diff --git a/xorg-server/glx/indirect_util.c b/xorg-server/glx/indirect_util.c index 44309104e..d00523249 100644 --- a/xorg-server/glx/indirect_util.c +++ b/xorg-server/glx/indirect_util.c @@ -1,310 +1,310 @@ -/* - * (C) Copyright IBM Corporation 2005 - * 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, sub license, - * 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 NON-INFRINGEMENT. IN NO EVENT SHALL - * IBM, - * AND/OR THEIR SUPPLIERS 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include -#include -#include -#include -#include "indirect_size.h" -#include "indirect_size_get.h" -#include "indirect_dispatch.h" -#include "glxserver.h" -#include "glxbyteorder.h" -#include "singlesize.h" -#include "glapitable.h" -#include "glapi.h" -#include "glthread.h" -#include "dispatch.h" -#include "glxext.h" -#include "indirect_table.h" -#include "indirect_util.h" - - -#define __GLX_PAD(a) (((a)+3)&~3) - -extern xGLXSingleReply __glXReply; - - -GLint -__glGetBooleanv_variable_size( GLenum e ) -{ - if ( e == GL_COMPRESSED_TEXTURE_FORMATS ) { - GLint temp; - - CALL_GetIntegerv( GET_DISPATCH(), - (GL_NUM_COMPRESSED_TEXTURE_FORMATS, & temp) ); - return temp; - } - else { - return 0; - } -} - - -/** - * Get a properly aligned buffer to hold reply data. - * - * \warning - * This function assumes that \c local_buffer is already properly aligned. - * It also assumes that \c alignment is a power of two. - */ -void * -__glXGetAnswerBuffer( __GLXclientState * cl, size_t required_size, - void * local_buffer, size_t local_size, unsigned alignment ) -{ - void * buffer = local_buffer; - const unsigned mask = alignment - 1; - - if ( local_size < required_size ) { - const size_t worst_case_size = required_size + alignment; - intptr_t temp_buf; - - if ( cl->returnBufSize < worst_case_size ) { - void * temp = xrealloc( cl->returnBuf, worst_case_size ); - - if ( temp == NULL ) { - return NULL; - } - - cl->returnBuf = temp; - cl->returnBufSize = worst_case_size; - } - - temp_buf = (intptr_t) cl->returnBuf; - temp_buf = (temp_buf + mask) & ~mask; - buffer = (void *) temp_buf; - } - - return buffer; -} - - -/** - * Send a GLX reply to the client. - * - * Technically speaking, there are several different ways to encode a GLX - * reply. The primary difference is whether or not certain fields (e.g., - * retval, size, and "pad3") are set. This function gets around that by - * always setting all of the fields to "reasonable" values. This does no - * harm to clients, but it does make the server-side code much more compact. - */ -void -__glXSendReply( ClientPtr client, const void * data, size_t elements, - size_t element_size, GLboolean always_array, CARD32 retval ) -{ - size_t reply_ints = 0; - - if ( __glXErrorOccured() ) { - elements = 0; - } - else if ( (elements > 1) || always_array ) { - reply_ints = bytes_to_int32(elements * element_size); - } - - __glXReply.length = reply_ints; - __glXReply.type = X_Reply; - __glXReply.sequenceNumber = client->sequence; - __glXReply.size = elements; - __glXReply.retval = retval; - - - /* It is faster on almost always every architecture to just copy the 8 - * bytes, even when not necessary, than check to see of the value of - * elements requires it. Copying the data when not needed will do no - * harm. - */ - - (void) memcpy( & __glXReply.pad3, data, 8 ); - WriteToClient( client, sz_xGLXSingleReply, (char *) & __glXReply ); - - if ( reply_ints != 0 ) { - WriteToClient( client, reply_ints * 4, (char *) data ); - } -} - - -/** - * Send a GLX reply to the client. - * - * Technically speaking, there are several different ways to encode a GLX - * reply. The primary difference is whether or not certain fields (e.g., - * retval, size, and "pad3") are set. This function gets around that by - * always setting all of the fields to "reasonable" values. This does no - * harm to clients, but it does make the server-side code much more compact. - * - * \warning - * This function assumes that values stored in \c data will be byte-swapped - * by the caller if necessary. - */ -void -__glXSendReplySwap( ClientPtr client, const void * data, size_t elements, - size_t element_size, GLboolean always_array, CARD32 retval ) -{ - size_t reply_ints = 0; - - if ( __glXErrorOccured() ) { - elements = 0; - } - else if ( (elements > 1) || always_array ) { - reply_ints = bytes_to_int32(elements * element_size); - } - - __glXReply.length = bswap_32( reply_ints ); - __glXReply.type = X_Reply; - __glXReply.sequenceNumber = bswap_16( client->sequence ); - __glXReply.size = bswap_32( elements ); - __glXReply.retval = bswap_32( retval ); - - - /* It is faster on almost always every architecture to just copy the 8 - * bytes, even when not necessary, than check to see of the value of - * elements requires it. Copying the data when not needed will do no - * harm. - */ - - (void) memcpy( & __glXReply.pad3, data, 8 ); - WriteToClient( client, sz_xGLXSingleReply, (char *) & __glXReply ); - - if ( reply_ints != 0 ) { - WriteToClient( client, reply_ints * 4, (char *) data ); - } -} - - -static int -get_decode_index(const struct __glXDispatchInfo *dispatch_info, - unsigned opcode) -{ - int remaining_bits; - int next_remain; - const int_fast16_t * const tree = dispatch_info->dispatch_tree; - int_fast16_t index; - - - remaining_bits = dispatch_info->bits; - if (opcode >= (1U << remaining_bits)) { - return -1; - } - - index = 0; - for (/* empty */; remaining_bits > 0; remaining_bits = next_remain) { - unsigned mask; - unsigned child_index; - - - /* Calculate the slice of bits used by this node. - * - * If remaining_bits = 8 and tree[index] = 3, the mask of just the - * remaining bits is 0x00ff and the mask for the remaining bits after - * this node is 0x001f. By taking 0x00ff & ~0x001f, we get 0x00e0. - * This masks the 3 bits that we would want for this node. - */ - - next_remain = remaining_bits - tree[index]; - mask = ((1 << remaining_bits) - 1) & - ~((1 << next_remain) - 1); - - - /* Using the mask, calculate the index of the opcode in the node. - * With that index, fetch the index of the next node. - */ - - child_index = (opcode & mask) >> next_remain; - index = tree[index + 1 + child_index]; - - - /* If the next node is an empty leaf, the opcode is for a non-existant - * function. We're done. - * - * If the next node is a non-empty leaf, look up the function pointer - * and return it. - */ - - if (index == EMPTY_LEAF) { - return -1; - } - else if (IS_LEAF_INDEX(index)) { - unsigned func_index; - - - /* The value stored in the tree for a leaf node is the base of - * the function pointers for that leaf node. The offset for the - * function for a particular opcode is the remaining bits in the - * opcode. - */ - - func_index = -index; - func_index += opcode & ((1 << next_remain) - 1); - return func_index; - } - } - - /* We should *never* get here!!! - */ - return -1; -} - - -void * -__glXGetProtocolDecodeFunction(const struct __glXDispatchInfo *dispatch_info, - int opcode, int swapped_version) -{ - const int func_index = get_decode_index(dispatch_info, opcode); - - return (func_index < 0) - ? NULL - : (void *) dispatch_info->dispatch_functions[func_index][swapped_version]; -} - - -int -__glXGetProtocolSizeData(const struct __glXDispatchInfo *dispatch_info, - int opcode, __GLXrenderSizeData *data) -{ - if (dispatch_info->size_table != NULL) { - const int func_index = get_decode_index(dispatch_info, opcode); - - if ((func_index >= 0) - && (dispatch_info->size_table[func_index][0] != 0)) { - const int var_offset = - dispatch_info->size_table[func_index][1]; - - data->bytes = dispatch_info->size_table[func_index][0]; - data->varsize = (var_offset != ~0) - ? dispatch_info->size_func_table[var_offset] - : NULL; - - return 0; - } - } - - return -1; -} +/* + * (C) Copyright IBM Corporation 2005 + * 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, sub license, + * 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * IBM, + * AND/OR THEIR SUPPLIERS 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include "indirect_size.h" +#include "indirect_size_get.h" +#include "indirect_dispatch.h" +#include "glxserver.h" +#include "glxbyteorder.h" +#include "singlesize.h" +#include "glapitable.h" +#include "glapi.h" +#include "glthread.h" +#include "dispatch.h" +#include "glxext.h" +#include "indirect_table.h" +#include "indirect_util.h" + + +#define __GLX_PAD(a) (((a)+3)&~3) + +extern xGLXSingleReply __glXReply; + + +GLint +__glGetBooleanv_variable_size( GLenum e ) +{ + if ( e == GL_COMPRESSED_TEXTURE_FORMATS ) { + GLint temp; + + CALL_GetIntegerv( GET_DISPATCH(), + (GL_NUM_COMPRESSED_TEXTURE_FORMATS, & temp) ); + return temp; + } + else { + return 0; + } +} + + +/** + * Get a properly aligned buffer to hold reply data. + * + * \warning + * This function assumes that \c local_buffer is already properly aligned. + * It also assumes that \c alignment is a power of two. + */ +void * +__glXGetAnswerBuffer( __GLXclientState * cl, size_t required_size, + void * local_buffer, size_t local_size, unsigned alignment ) +{ + void * buffer = local_buffer; + const unsigned mask = alignment - 1; + + if ( local_size < required_size ) { + const size_t worst_case_size = required_size + alignment; + intptr_t temp_buf; + + if ( cl->returnBufSize < worst_case_size ) { + void * temp = realloc( cl->returnBuf, worst_case_size ); + + if ( temp == NULL ) { + return NULL; + } + + cl->returnBuf = temp; + cl->returnBufSize = worst_case_size; + } + + temp_buf = (intptr_t) cl->returnBuf; + temp_buf = (temp_buf + mask) & ~mask; + buffer = (void *) temp_buf; + } + + return buffer; +} + + +/** + * Send a GLX reply to the client. + * + * Technically speaking, there are several different ways to encode a GLX + * reply. The primary difference is whether or not certain fields (e.g., + * retval, size, and "pad3") are set. This function gets around that by + * always setting all of the fields to "reasonable" values. This does no + * harm to clients, but it does make the server-side code much more compact. + */ +void +__glXSendReply( ClientPtr client, const void * data, size_t elements, + size_t element_size, GLboolean always_array, CARD32 retval ) +{ + size_t reply_ints = 0; + + if ( __glXErrorOccured() ) { + elements = 0; + } + else if ( (elements > 1) || always_array ) { + reply_ints = bytes_to_int32(elements * element_size); + } + + __glXReply.length = reply_ints; + __glXReply.type = X_Reply; + __glXReply.sequenceNumber = client->sequence; + __glXReply.size = elements; + __glXReply.retval = retval; + + + /* It is faster on almost always every architecture to just copy the 8 + * bytes, even when not necessary, than check to see of the value of + * elements requires it. Copying the data when not needed will do no + * harm. + */ + + (void) memcpy( & __glXReply.pad3, data, 8 ); + WriteToClient( client, sz_xGLXSingleReply, (char *) & __glXReply ); + + if ( reply_ints != 0 ) { + WriteToClient( client, reply_ints * 4, (char *) data ); + } +} + + +/** + * Send a GLX reply to the client. + * + * Technically speaking, there are several different ways to encode a GLX + * reply. The primary difference is whether or not certain fields (e.g., + * retval, size, and "pad3") are set. This function gets around that by + * always setting all of the fields to "reasonable" values. This does no + * harm to clients, but it does make the server-side code much more compact. + * + * \warning + * This function assumes that values stored in \c data will be byte-swapped + * by the caller if necessary. + */ +void +__glXSendReplySwap( ClientPtr client, const void * data, size_t elements, + size_t element_size, GLboolean always_array, CARD32 retval ) +{ + size_t reply_ints = 0; + + if ( __glXErrorOccured() ) { + elements = 0; + } + else if ( (elements > 1) || always_array ) { + reply_ints = bytes_to_int32(elements * element_size); + } + + __glXReply.length = bswap_32( reply_ints ); + __glXReply.type = X_Reply; + __glXReply.sequenceNumber = bswap_16( client->sequence ); + __glXReply.size = bswap_32( elements ); + __glXReply.retval = bswap_32( retval ); + + + /* It is faster on almost always every architecture to just copy the 8 + * bytes, even when not necessary, than check to see of the value of + * elements requires it. Copying the data when not needed will do no + * harm. + */ + + (void) memcpy( & __glXReply.pad3, data, 8 ); + WriteToClient( client, sz_xGLXSingleReply, (char *) & __glXReply ); + + if ( reply_ints != 0 ) { + WriteToClient( client, reply_ints * 4, (char *) data ); + } +} + + +static int +get_decode_index(const struct __glXDispatchInfo *dispatch_info, + unsigned opcode) +{ + int remaining_bits; + int next_remain; + const int_fast16_t * const tree = dispatch_info->dispatch_tree; + int_fast16_t index; + + + remaining_bits = dispatch_info->bits; + if (opcode >= (1U << remaining_bits)) { + return -1; + } + + index = 0; + for (/* empty */; remaining_bits > 0; remaining_bits = next_remain) { + unsigned mask; + unsigned child_index; + + + /* Calculate the slice of bits used by this node. + * + * If remaining_bits = 8 and tree[index] = 3, the mask of just the + * remaining bits is 0x00ff and the mask for the remaining bits after + * this node is 0x001f. By taking 0x00ff & ~0x001f, we get 0x00e0. + * This masks the 3 bits that we would want for this node. + */ + + next_remain = remaining_bits - tree[index]; + mask = ((1 << remaining_bits) - 1) & + ~((1 << next_remain) - 1); + + + /* Using the mask, calculate the index of the opcode in the node. + * With that index, fetch the index of the next node. + */ + + child_index = (opcode & mask) >> next_remain; + index = tree[index + 1 + child_index]; + + + /* If the next node is an empty leaf, the opcode is for a non-existant + * function. We're done. + * + * If the next node is a non-empty leaf, look up the function pointer + * and return it. + */ + + if (index == EMPTY_LEAF) { + return -1; + } + else if (IS_LEAF_INDEX(index)) { + unsigned func_index; + + + /* The value stored in the tree for a leaf node is the base of + * the function pointers for that leaf node. The offset for the + * function for a particular opcode is the remaining bits in the + * opcode. + */ + + func_index = -index; + func_index += opcode & ((1 << next_remain) - 1); + return func_index; + } + } + + /* We should *never* get here!!! + */ + return -1; +} + + +void * +__glXGetProtocolDecodeFunction(const struct __glXDispatchInfo *dispatch_info, + int opcode, int swapped_version) +{ + const int func_index = get_decode_index(dispatch_info, opcode); + + return (func_index < 0) + ? NULL + : (void *) dispatch_info->dispatch_functions[func_index][swapped_version]; +} + + +int +__glXGetProtocolSizeData(const struct __glXDispatchInfo *dispatch_info, + int opcode, __GLXrenderSizeData *data) +{ + if (dispatch_info->size_table != NULL) { + const int func_index = get_decode_index(dispatch_info, opcode); + + if ((func_index >= 0) + && (dispatch_info->size_table[func_index][0] != 0)) { + const int var_offset = + dispatch_info->size_table[func_index][1]; + + data->bytes = dispatch_info->size_table[func_index][0]; + data->varsize = (var_offset != ~0) + ? dispatch_info->size_func_table[var_offset] + : NULL; + + return 0; + } + } + + return -1; +} diff --git a/xorg-server/glx/single2.c b/xorg-server/glx/single2.c index 50a59ed71..754cc0b86 100644 --- a/xorg-server/glx/single2.c +++ b/xorg-server/glx/single2.c @@ -1,391 +1,391 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "glxserver.h" -#include "glxutil.h" -#include "glxext.h" -#include "indirect_dispatch.h" -#include "unpack.h" -#include "glapitable.h" -#include "glapi.h" -#include "glthread.h" -#include "dispatch.h" - -int __glXDisp_FeedbackBuffer(__GLXclientState *cl, GLbyte *pc) -{ - GLsizei size; - GLenum type; - __GLXcontext *cx; - int error; - - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - pc += __GLX_SINGLE_HDR_SIZE; - size = *(GLsizei *)(pc+0); - type = *(GLenum *)(pc+4); - if (cx->feedbackBufSize < size) { - cx->feedbackBuf = (GLfloat *) xrealloc(cx->feedbackBuf, - (size_t)size - * __GLX_SIZE_FLOAT32); - if (!cx->feedbackBuf) { - cl->client->errorValue = size; - return BadAlloc; - } - cx->feedbackBufSize = size; - } - CALL_FeedbackBuffer( GET_DISPATCH(), (size, type, cx->feedbackBuf) ); - __GLX_NOTE_UNFLUSHED_CMDS(cx); - return Success; -} - -int __glXDisp_SelectBuffer(__GLXclientState *cl, GLbyte *pc) -{ - __GLXcontext *cx; - GLsizei size; - int error; - - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - pc += __GLX_SINGLE_HDR_SIZE; - size = *(GLsizei *)(pc+0); - if (cx->selectBufSize < size) { - cx->selectBuf = (GLuint *) xrealloc(cx->selectBuf, - (size_t) size - * __GLX_SIZE_CARD32); - if (!cx->selectBuf) { - cl->client->errorValue = size; - return BadAlloc; - } - cx->selectBufSize = size; - } - CALL_SelectBuffer( GET_DISPATCH(), (size, cx->selectBuf) ); - __GLX_NOTE_UNFLUSHED_CMDS(cx); - return Success; -} - -int __glXDisp_RenderMode(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client; - xGLXRenderModeReply reply; - __GLXcontext *cx; - GLint nitems=0, retBytes=0, retval, newModeCheck; - GLubyte *retBuffer = NULL; - GLenum newMode; - int error; - - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - pc += __GLX_SINGLE_HDR_SIZE; - newMode = *(GLenum*) pc; - retval = CALL_RenderMode( GET_DISPATCH(), (newMode) ); - - /* Check that render mode worked */ - CALL_GetIntegerv( GET_DISPATCH(), (GL_RENDER_MODE, &newModeCheck) ); - if (newModeCheck != newMode) { - /* Render mode change failed. Bail */ - newMode = newModeCheck; - goto noChangeAllowed; - } - - /* - ** Render mode might have still failed if we get here. But in this - ** case we can't really tell, nor does it matter. If it did fail, it - ** will return 0, and thus we won't send any data across the wire. - */ - - switch (cx->renderMode) { - case GL_RENDER: - cx->renderMode = newMode; - break; - case GL_FEEDBACK: - if (retval < 0) { - /* Overflow happened. Copy the entire buffer */ - nitems = cx->feedbackBufSize; - } else { - nitems = retval; - } - retBytes = nitems * __GLX_SIZE_FLOAT32; - retBuffer = (GLubyte*) cx->feedbackBuf; - cx->renderMode = newMode; - break; - case GL_SELECT: - if (retval < 0) { - /* Overflow happened. Copy the entire buffer */ - nitems = cx->selectBufSize; - } else { - GLuint *bp = cx->selectBuf; - GLint i; - - /* - ** Figure out how many bytes of data need to be sent. Parse - ** the selection buffer to determine this fact as the - ** return value is the number of hits, not the number of - ** items in the buffer. - */ - nitems = 0; - i = retval; - while (--i >= 0) { - GLuint n; - - /* Parse select data for this hit */ - n = *bp; - bp += 3 + n; - } - nitems = bp - cx->selectBuf; - } - retBytes = nitems * __GLX_SIZE_CARD32; - retBuffer = (GLubyte*) cx->selectBuf; - cx->renderMode = newMode; - break; - } - - /* - ** First reply is the number of elements returned in the feedback or - ** selection array, as per the API for glRenderMode itself. - */ - noChangeAllowed:; - client = cl->client; - reply.length = nitems; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.retval = retval; - reply.size = nitems; - reply.newMode = newMode; - WriteToClient(client, sz_xGLXRenderModeReply, (char *)&reply); - if (retBytes) { - WriteToClient(client, retBytes, (char *)retBuffer); - } - return Success; -} - -int __glXDisp_Flush(__GLXclientState *cl, GLbyte *pc) -{ - __GLXcontext *cx; - int error; - - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - CALL_Flush( GET_DISPATCH(), () ); - __GLX_NOTE_FLUSHED_CMDS(cx); - return Success; -} - -int __glXDisp_Finish(__GLXclientState *cl, GLbyte *pc) -{ - __GLXcontext *cx; - ClientPtr client; - int error; - - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - /* Do a local glFinish */ - CALL_Finish( GET_DISPATCH(), () ); - __GLX_NOTE_FLUSHED_CMDS(cx); - - /* Send empty reply packet to indicate finish is finished */ - client = cl->client; - __GLX_BEGIN_REPLY(0); - __GLX_SEND_HEADER(); - return Success; -} - -#define SEPARATOR " " - -char *__glXcombine_strings(const char *cext_string, const char *sext_string) -{ - size_t clen, slen; - char *combo_string, *token, *s1; - const char *s2, *end; - - /* safeguard to prevent potentially fatal errors in the string functions */ - if (!cext_string) - cext_string = ""; - if (!sext_string) - sext_string = ""; - - /* - ** String can't be longer than min(cstring, sstring) - ** pull tokens out of shortest string - ** include space in combo_string for final separator and null terminator - */ - clen = strlen(cext_string); - slen = strlen(sext_string); - if (clen > slen) { - combo_string = (char *) xalloc(slen + 2); - s1 = (char *) xalloc(slen + 2); - if (s1) strcpy(s1, sext_string); - s2 = cext_string; - } else { - combo_string = (char *) xalloc(clen + 2); - s1 = (char *) xalloc(clen + 2); - if (s1) strcpy(s1, cext_string); - s2 = sext_string; - } - if (!combo_string || !s1) { - if (combo_string) - xfree(combo_string); - if (s1) - xfree(s1); - return NULL; - } - combo_string[0] = '\0'; - - /* Get first extension token */ - token = strtok( s1, SEPARATOR); - while ( token != NULL ) { - - /* - ** if token in second string then save it - ** beware of extension names which are prefixes of other extension names - */ - const char *p = s2; - end = p + strlen(p); - while (p < end) { - size_t n = strcspn(p, SEPARATOR); - if ((strlen(token) == n) && (strncmp(token, p, n) == 0)) { - combo_string = strcat(combo_string, token); - combo_string = strcat(combo_string, SEPARATOR); - } - p += (n + 1); - } - - /* Get next extension token */ - token = strtok( NULL, SEPARATOR); - } - xfree(s1); - return combo_string; -} - -int DoGetString(__GLXclientState *cl, GLbyte *pc, GLboolean need_swap) -{ - ClientPtr client; - __GLXcontext *cx; - GLenum name; - const char *string; - __GLX_DECLARE_SWAP_VARIABLES; - int error; - char *buf = NULL, *buf1 = NULL; - GLint length = 0; - - /* If the client has the opposite byte order, swap the contextTag and - * the name. - */ - if ( need_swap ) { - __GLX_SWAP_INT(pc + 4); - __GLX_SWAP_INT(pc + __GLX_SINGLE_HDR_SIZE); - } - - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - pc += __GLX_SINGLE_HDR_SIZE; - name = *(GLenum *)(pc + 0); - string = (const char *) CALL_GetString( GET_DISPATCH(), (name) ); - client = cl->client; - - if (string == NULL) - string = ""; - - /* - ** Restrict extensions to those that are supported by both the - ** implementation and the connection. That is, return the - ** intersection of client, server, and core extension strings. - */ - if (name == GL_EXTENSIONS) { - buf1 = __glXcombine_strings(string, - cl->GLClientextensions); - buf = __glXcombine_strings(buf1, - cx->pGlxScreen->GLextensions); - if (buf1 != NULL) { - xfree(buf1); - } - string = buf; - } - else if ( name == GL_VERSION ) { - if ( atof( string ) > atof( GLServerVersion ) ) { - buf = xalloc( strlen( string ) + strlen( GLServerVersion ) + 4 ); - if ( buf == NULL ) { - string = GLServerVersion; - } - else { - sprintf( buf, "%s (%s)", GLServerVersion, string ); - string = buf; - } - } - } - if (string) { - length = strlen((const char *) string) + 1; - } - - __GLX_BEGIN_REPLY(length); - __GLX_PUT_SIZE(length); - - if ( need_swap ) { - __GLX_SWAP_REPLY_SIZE(); - __GLX_SWAP_REPLY_HEADER(); - } - - __GLX_SEND_HEADER(); - WriteToClient(client, length, (char *) string); - if (buf != NULL) - xfree(buf); - - return Success; -} - -int __glXDisp_GetString(__GLXclientState *cl, GLbyte *pc) -{ - return DoGetString(cl, pc, GL_FALSE); -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "glxserver.h" +#include "glxutil.h" +#include "glxext.h" +#include "indirect_dispatch.h" +#include "unpack.h" +#include "glapitable.h" +#include "glapi.h" +#include "glthread.h" +#include "dispatch.h" + +int __glXDisp_FeedbackBuffer(__GLXclientState *cl, GLbyte *pc) +{ + GLsizei size; + GLenum type; + __GLXcontext *cx; + int error; + + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + pc += __GLX_SINGLE_HDR_SIZE; + size = *(GLsizei *)(pc+0); + type = *(GLenum *)(pc+4); + if (cx->feedbackBufSize < size) { + cx->feedbackBuf = (GLfloat *) realloc(cx->feedbackBuf, + (size_t)size + * __GLX_SIZE_FLOAT32); + if (!cx->feedbackBuf) { + cl->client->errorValue = size; + return BadAlloc; + } + cx->feedbackBufSize = size; + } + CALL_FeedbackBuffer( GET_DISPATCH(), (size, type, cx->feedbackBuf) ); + __GLX_NOTE_UNFLUSHED_CMDS(cx); + return Success; +} + +int __glXDisp_SelectBuffer(__GLXclientState *cl, GLbyte *pc) +{ + __GLXcontext *cx; + GLsizei size; + int error; + + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + pc += __GLX_SINGLE_HDR_SIZE; + size = *(GLsizei *)(pc+0); + if (cx->selectBufSize < size) { + cx->selectBuf = (GLuint *) realloc(cx->selectBuf, + (size_t) size + * __GLX_SIZE_CARD32); + if (!cx->selectBuf) { + cl->client->errorValue = size; + return BadAlloc; + } + cx->selectBufSize = size; + } + CALL_SelectBuffer( GET_DISPATCH(), (size, cx->selectBuf) ); + __GLX_NOTE_UNFLUSHED_CMDS(cx); + return Success; +} + +int __glXDisp_RenderMode(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client; + xGLXRenderModeReply reply; + __GLXcontext *cx; + GLint nitems=0, retBytes=0, retval, newModeCheck; + GLubyte *retBuffer = NULL; + GLenum newMode; + int error; + + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + pc += __GLX_SINGLE_HDR_SIZE; + newMode = *(GLenum*) pc; + retval = CALL_RenderMode( GET_DISPATCH(), (newMode) ); + + /* Check that render mode worked */ + CALL_GetIntegerv( GET_DISPATCH(), (GL_RENDER_MODE, &newModeCheck) ); + if (newModeCheck != newMode) { + /* Render mode change failed. Bail */ + newMode = newModeCheck; + goto noChangeAllowed; + } + + /* + ** Render mode might have still failed if we get here. But in this + ** case we can't really tell, nor does it matter. If it did fail, it + ** will return 0, and thus we won't send any data across the wire. + */ + + switch (cx->renderMode) { + case GL_RENDER: + cx->renderMode = newMode; + break; + case GL_FEEDBACK: + if (retval < 0) { + /* Overflow happened. Copy the entire buffer */ + nitems = cx->feedbackBufSize; + } else { + nitems = retval; + } + retBytes = nitems * __GLX_SIZE_FLOAT32; + retBuffer = (GLubyte*) cx->feedbackBuf; + cx->renderMode = newMode; + break; + case GL_SELECT: + if (retval < 0) { + /* Overflow happened. Copy the entire buffer */ + nitems = cx->selectBufSize; + } else { + GLuint *bp = cx->selectBuf; + GLint i; + + /* + ** Figure out how many bytes of data need to be sent. Parse + ** the selection buffer to determine this fact as the + ** return value is the number of hits, not the number of + ** items in the buffer. + */ + nitems = 0; + i = retval; + while (--i >= 0) { + GLuint n; + + /* Parse select data for this hit */ + n = *bp; + bp += 3 + n; + } + nitems = bp - cx->selectBuf; + } + retBytes = nitems * __GLX_SIZE_CARD32; + retBuffer = (GLubyte*) cx->selectBuf; + cx->renderMode = newMode; + break; + } + + /* + ** First reply is the number of elements returned in the feedback or + ** selection array, as per the API for glRenderMode itself. + */ + noChangeAllowed:; + client = cl->client; + reply.length = nitems; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.retval = retval; + reply.size = nitems; + reply.newMode = newMode; + WriteToClient(client, sz_xGLXRenderModeReply, (char *)&reply); + if (retBytes) { + WriteToClient(client, retBytes, (char *)retBuffer); + } + return Success; +} + +int __glXDisp_Flush(__GLXclientState *cl, GLbyte *pc) +{ + __GLXcontext *cx; + int error; + + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + CALL_Flush( GET_DISPATCH(), () ); + __GLX_NOTE_FLUSHED_CMDS(cx); + return Success; +} + +int __glXDisp_Finish(__GLXclientState *cl, GLbyte *pc) +{ + __GLXcontext *cx; + ClientPtr client; + int error; + + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + /* Do a local glFinish */ + CALL_Finish( GET_DISPATCH(), () ); + __GLX_NOTE_FLUSHED_CMDS(cx); + + /* Send empty reply packet to indicate finish is finished */ + client = cl->client; + __GLX_BEGIN_REPLY(0); + __GLX_SEND_HEADER(); + return Success; +} + +#define SEPARATOR " " + +char *__glXcombine_strings(const char *cext_string, const char *sext_string) +{ + size_t clen, slen; + char *combo_string, *token, *s1; + const char *s2, *end; + + /* safeguard to prevent potentially fatal errors in the string functions */ + if (!cext_string) + cext_string = ""; + if (!sext_string) + sext_string = ""; + + /* + ** String can't be longer than min(cstring, sstring) + ** pull tokens out of shortest string + ** include space in combo_string for final separator and null terminator + */ + clen = strlen(cext_string); + slen = strlen(sext_string); + if (clen > slen) { + combo_string = (char *) malloc(slen + 2); + s1 = (char *) malloc(slen + 2); + if (s1) strcpy(s1, sext_string); + s2 = cext_string; + } else { + combo_string = (char *) malloc(clen + 2); + s1 = (char *) malloc(clen + 2); + if (s1) strcpy(s1, cext_string); + s2 = sext_string; + } + if (!combo_string || !s1) { + if (combo_string) + free(combo_string); + if (s1) + free(s1); + return NULL; + } + combo_string[0] = '\0'; + + /* Get first extension token */ + token = strtok( s1, SEPARATOR); + while ( token != NULL ) { + + /* + ** if token in second string then save it + ** beware of extension names which are prefixes of other extension names + */ + const char *p = s2; + end = p + strlen(p); + while (p < end) { + size_t n = strcspn(p, SEPARATOR); + if ((strlen(token) == n) && (strncmp(token, p, n) == 0)) { + combo_string = strcat(combo_string, token); + combo_string = strcat(combo_string, SEPARATOR); + } + p += (n + 1); + } + + /* Get next extension token */ + token = strtok( NULL, SEPARATOR); + } + free(s1); + return combo_string; +} + +int DoGetString(__GLXclientState *cl, GLbyte *pc, GLboolean need_swap) +{ + ClientPtr client; + __GLXcontext *cx; + GLenum name; + const char *string; + __GLX_DECLARE_SWAP_VARIABLES; + int error; + char *buf = NULL, *buf1 = NULL; + GLint length = 0; + + /* If the client has the opposite byte order, swap the contextTag and + * the name. + */ + if ( need_swap ) { + __GLX_SWAP_INT(pc + 4); + __GLX_SWAP_INT(pc + __GLX_SINGLE_HDR_SIZE); + } + + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + pc += __GLX_SINGLE_HDR_SIZE; + name = *(GLenum *)(pc + 0); + string = (const char *) CALL_GetString( GET_DISPATCH(), (name) ); + client = cl->client; + + if (string == NULL) + string = ""; + + /* + ** Restrict extensions to those that are supported by both the + ** implementation and the connection. That is, return the + ** intersection of client, server, and core extension strings. + */ + if (name == GL_EXTENSIONS) { + buf1 = __glXcombine_strings(string, + cl->GLClientextensions); + buf = __glXcombine_strings(buf1, + cx->pGlxScreen->GLextensions); + if (buf1 != NULL) { + free(buf1); + } + string = buf; + } + else if ( name == GL_VERSION ) { + if ( atof( string ) > atof( GLServerVersion ) ) { + buf = malloc( strlen( string ) + strlen( GLServerVersion ) + 4 ); + if ( buf == NULL ) { + string = GLServerVersion; + } + else { + sprintf( buf, "%s (%s)", GLServerVersion, string ); + string = buf; + } + } + } + if (string) { + length = strlen((const char *) string) + 1; + } + + __GLX_BEGIN_REPLY(length); + __GLX_PUT_SIZE(length); + + if ( need_swap ) { + __GLX_SWAP_REPLY_SIZE(); + __GLX_SWAP_REPLY_HEADER(); + } + + __GLX_SEND_HEADER(); + WriteToClient(client, length, (char *) string); + if (buf != NULL) + free(buf); + + return Success; +} + +int __glXDisp_GetString(__GLXclientState *cl, GLbyte *pc) +{ + return DoGetString(cl, pc, GL_FALSE); +} diff --git a/xorg-server/glx/single2swap.c b/xorg-server/glx/single2swap.c index cf83bdc88..62f3a5eac 100644 --- a/xorg-server/glx/single2swap.c +++ b/xorg-server/glx/single2swap.c @@ -1,266 +1,266 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "glxserver.h" -#include "glxutil.h" -#include "glxext.h" -#include "indirect_dispatch.h" -#include "unpack.h" -#include "glapitable.h" -#include "glapi.h" -#include "glthread.h" -#include "dispatch.h" - -int __glXDispSwap_FeedbackBuffer(__GLXclientState *cl, GLbyte *pc) -{ - GLsizei size; - GLenum type; - __GLX_DECLARE_SWAP_VARIABLES; - __GLXcontext *cx; - int error; - - __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - pc += __GLX_SINGLE_HDR_SIZE; - __GLX_SWAP_INT(pc+0); - __GLX_SWAP_INT(pc+4); - size = *(GLsizei *)(pc+0); - type = *(GLenum *)(pc+4); - if (cx->feedbackBufSize < size) { - cx->feedbackBuf = (GLfloat *) xrealloc(cx->feedbackBuf, - (size_t) size - * __GLX_SIZE_FLOAT32); - if (!cx->feedbackBuf) { - cl->client->errorValue = size; - return BadAlloc; - } - cx->feedbackBufSize = size; - } - CALL_FeedbackBuffer( GET_DISPATCH(), (size, type, cx->feedbackBuf) ); - __GLX_NOTE_UNFLUSHED_CMDS(cx); - return Success; -} - -int __glXDispSwap_SelectBuffer(__GLXclientState *cl, GLbyte *pc) -{ - __GLXcontext *cx; - GLsizei size; - __GLX_DECLARE_SWAP_VARIABLES; - int error; - - __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - pc += __GLX_SINGLE_HDR_SIZE; - __GLX_SWAP_INT(pc+0); - size = *(GLsizei *)(pc+0); - if (cx->selectBufSize < size) { - cx->selectBuf = (GLuint *) xrealloc(cx->selectBuf, - (size_t) size - * __GLX_SIZE_CARD32); - if (!cx->selectBuf) { - cl->client->errorValue = size; - return BadAlloc; - } - cx->selectBufSize = size; - } - CALL_SelectBuffer( GET_DISPATCH(), (size, cx->selectBuf) ); - __GLX_NOTE_UNFLUSHED_CMDS(cx); - return Success; -} - -int __glXDispSwap_RenderMode(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client; - __GLXcontext *cx; - xGLXRenderModeReply reply; - GLint nitems=0, retBytes=0, retval, newModeCheck; - GLubyte *retBuffer = NULL; - GLenum newMode; - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_DECLARE_SWAP_ARRAY_VARIABLES; - int error; - - __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - pc += __GLX_SINGLE_HDR_SIZE; - __GLX_SWAP_INT(pc); - newMode = *(GLenum*) pc; - retval = CALL_RenderMode( GET_DISPATCH(), (newMode) ); - - /* Check that render mode worked */ - CALL_GetIntegerv( GET_DISPATCH(), (GL_RENDER_MODE, &newModeCheck) ); - if (newModeCheck != newMode) { - /* Render mode change failed. Bail */ - newMode = newModeCheck; - goto noChangeAllowed; - } - - /* - ** Render mode might have still failed if we get here. But in this - ** case we can't really tell, nor does it matter. If it did fail, it - ** will return 0, and thus we won't send any data across the wire. - */ - - switch (cx->renderMode) { - case GL_RENDER: - cx->renderMode = newMode; - break; - case GL_FEEDBACK: - if (retval < 0) { - /* Overflow happened. Copy the entire buffer */ - nitems = cx->feedbackBufSize; - } else { - nitems = retval; - } - retBytes = nitems * __GLX_SIZE_FLOAT32; - retBuffer = (GLubyte*) cx->feedbackBuf; - __GLX_SWAP_FLOAT_ARRAY((GLbyte *)retBuffer, nitems); - cx->renderMode = newMode; - break; - case GL_SELECT: - if (retval < 0) { - /* Overflow happened. Copy the entire buffer */ - nitems = cx->selectBufSize; - } else { - GLuint *bp = cx->selectBuf; - GLint i; - - /* - ** Figure out how many bytes of data need to be sent. Parse - ** the selection buffer to determine this fact as the - ** return value is the number of hits, not the number of - ** items in the buffer. - */ - nitems = 0; - i = retval; - while (--i >= 0) { - GLuint n; - - /* Parse select data for this hit */ - n = *bp; - bp += 3 + n; - } - nitems = bp - cx->selectBuf; - } - retBytes = nitems * __GLX_SIZE_CARD32; - retBuffer = (GLubyte*) cx->selectBuf; - __GLX_SWAP_INT_ARRAY((GLbyte *)retBuffer, nitems); - cx->renderMode = newMode; - break; - } - - /* - ** First reply is the number of elements returned in the feedback or - ** selection array, as per the API for glRenderMode itself. - */ - noChangeAllowed:; - client = cl->client; - reply.length = nitems; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.retval = retval; - reply.size = nitems; - reply.newMode = newMode; - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - __GLX_SWAP_INT(&reply.retval); - __GLX_SWAP_INT(&reply.size); - __GLX_SWAP_INT(&reply.newMode); - WriteToClient(client, sz_xGLXRenderModeReply, (char *)&reply); - if (retBytes) { - WriteToClient(client, retBytes, (char *)retBuffer); - } - return Success; -} - -int __glXDispSwap_Flush(__GLXclientState *cl, GLbyte *pc) -{ - __GLXcontext *cx; - int error; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - CALL_Flush( GET_DISPATCH(), () ); - __GLX_NOTE_FLUSHED_CMDS(cx); - return Success; -} - -int __glXDispSwap_Finish(__GLXclientState *cl, GLbyte *pc) -{ - __GLXcontext *cx; - ClientPtr client; - int error; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); - cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); - if (!cx) { - return error; - } - - /* Do a local glFinish */ - CALL_Finish( GET_DISPATCH(), () ); - __GLX_NOTE_FLUSHED_CMDS(cx); - - /* Send empty reply packet to indicate finish is finished */ - client = cl->client; - __GLX_BEGIN_REPLY(0); - __GLX_PUT_RETVAL(0); - __GLX_SWAP_REPLY_HEADER(); - __GLX_SEND_HEADER(); - - return Success; -} - -int __glXDispSwap_GetString(__GLXclientState *cl, GLbyte *pc) -{ - return DoGetString(cl, pc, GL_TRUE); -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "glxserver.h" +#include "glxutil.h" +#include "glxext.h" +#include "indirect_dispatch.h" +#include "unpack.h" +#include "glapitable.h" +#include "glapi.h" +#include "glthread.h" +#include "dispatch.h" + +int __glXDispSwap_FeedbackBuffer(__GLXclientState *cl, GLbyte *pc) +{ + GLsizei size; + GLenum type; + __GLX_DECLARE_SWAP_VARIABLES; + __GLXcontext *cx; + int error; + + __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + pc += __GLX_SINGLE_HDR_SIZE; + __GLX_SWAP_INT(pc+0); + __GLX_SWAP_INT(pc+4); + size = *(GLsizei *)(pc+0); + type = *(GLenum *)(pc+4); + if (cx->feedbackBufSize < size) { + cx->feedbackBuf = (GLfloat *) realloc(cx->feedbackBuf, + (size_t) size + * __GLX_SIZE_FLOAT32); + if (!cx->feedbackBuf) { + cl->client->errorValue = size; + return BadAlloc; + } + cx->feedbackBufSize = size; + } + CALL_FeedbackBuffer( GET_DISPATCH(), (size, type, cx->feedbackBuf) ); + __GLX_NOTE_UNFLUSHED_CMDS(cx); + return Success; +} + +int __glXDispSwap_SelectBuffer(__GLXclientState *cl, GLbyte *pc) +{ + __GLXcontext *cx; + GLsizei size; + __GLX_DECLARE_SWAP_VARIABLES; + int error; + + __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + pc += __GLX_SINGLE_HDR_SIZE; + __GLX_SWAP_INT(pc+0); + size = *(GLsizei *)(pc+0); + if (cx->selectBufSize < size) { + cx->selectBuf = (GLuint *) realloc(cx->selectBuf, + (size_t) size + * __GLX_SIZE_CARD32); + if (!cx->selectBuf) { + cl->client->errorValue = size; + return BadAlloc; + } + cx->selectBufSize = size; + } + CALL_SelectBuffer( GET_DISPATCH(), (size, cx->selectBuf) ); + __GLX_NOTE_UNFLUSHED_CMDS(cx); + return Success; +} + +int __glXDispSwap_RenderMode(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client; + __GLXcontext *cx; + xGLXRenderModeReply reply; + GLint nitems=0, retBytes=0, retval, newModeCheck; + GLubyte *retBuffer = NULL; + GLenum newMode; + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_DECLARE_SWAP_ARRAY_VARIABLES; + int error; + + __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + pc += __GLX_SINGLE_HDR_SIZE; + __GLX_SWAP_INT(pc); + newMode = *(GLenum*) pc; + retval = CALL_RenderMode( GET_DISPATCH(), (newMode) ); + + /* Check that render mode worked */ + CALL_GetIntegerv( GET_DISPATCH(), (GL_RENDER_MODE, &newModeCheck) ); + if (newModeCheck != newMode) { + /* Render mode change failed. Bail */ + newMode = newModeCheck; + goto noChangeAllowed; + } + + /* + ** Render mode might have still failed if we get here. But in this + ** case we can't really tell, nor does it matter. If it did fail, it + ** will return 0, and thus we won't send any data across the wire. + */ + + switch (cx->renderMode) { + case GL_RENDER: + cx->renderMode = newMode; + break; + case GL_FEEDBACK: + if (retval < 0) { + /* Overflow happened. Copy the entire buffer */ + nitems = cx->feedbackBufSize; + } else { + nitems = retval; + } + retBytes = nitems * __GLX_SIZE_FLOAT32; + retBuffer = (GLubyte*) cx->feedbackBuf; + __GLX_SWAP_FLOAT_ARRAY((GLbyte *)retBuffer, nitems); + cx->renderMode = newMode; + break; + case GL_SELECT: + if (retval < 0) { + /* Overflow happened. Copy the entire buffer */ + nitems = cx->selectBufSize; + } else { + GLuint *bp = cx->selectBuf; + GLint i; + + /* + ** Figure out how many bytes of data need to be sent. Parse + ** the selection buffer to determine this fact as the + ** return value is the number of hits, not the number of + ** items in the buffer. + */ + nitems = 0; + i = retval; + while (--i >= 0) { + GLuint n; + + /* Parse select data for this hit */ + n = *bp; + bp += 3 + n; + } + nitems = bp - cx->selectBuf; + } + retBytes = nitems * __GLX_SIZE_CARD32; + retBuffer = (GLubyte*) cx->selectBuf; + __GLX_SWAP_INT_ARRAY((GLbyte *)retBuffer, nitems); + cx->renderMode = newMode; + break; + } + + /* + ** First reply is the number of elements returned in the feedback or + ** selection array, as per the API for glRenderMode itself. + */ + noChangeAllowed:; + client = cl->client; + reply.length = nitems; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.retval = retval; + reply.size = nitems; + reply.newMode = newMode; + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + __GLX_SWAP_INT(&reply.retval); + __GLX_SWAP_INT(&reply.size); + __GLX_SWAP_INT(&reply.newMode); + WriteToClient(client, sz_xGLXRenderModeReply, (char *)&reply); + if (retBytes) { + WriteToClient(client, retBytes, (char *)retBuffer); + } + return Success; +} + +int __glXDispSwap_Flush(__GLXclientState *cl, GLbyte *pc) +{ + __GLXcontext *cx; + int error; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + CALL_Flush( GET_DISPATCH(), () ); + __GLX_NOTE_FLUSHED_CMDS(cx); + return Success; +} + +int __glXDispSwap_Finish(__GLXclientState *cl, GLbyte *pc) +{ + __GLXcontext *cx; + ClientPtr client; + int error; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_INT(&((xGLXSingleReq *)pc)->contextTag); + cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); + if (!cx) { + return error; + } + + /* Do a local glFinish */ + CALL_Finish( GET_DISPATCH(), () ); + __GLX_NOTE_FLUSHED_CMDS(cx); + + /* Send empty reply packet to indicate finish is finished */ + client = cl->client; + __GLX_BEGIN_REPLY(0); + __GLX_PUT_RETVAL(0); + __GLX_SWAP_REPLY_HEADER(); + __GLX_SEND_HEADER(); + + return Success; +} + +int __glXDispSwap_GetString(__GLXclientState *cl, GLbyte *pc) +{ + return DoGetString(cl, pc, GL_TRUE); +} diff --git a/xorg-server/glx/unpack.h b/xorg-server/glx/unpack.h index 90cb71bd7..7e6a55105 100644 --- a/xorg-server/glx/unpack.h +++ b/xorg-server/glx/unpack.h @@ -1,234 +1,234 @@ -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#ifndef __GLX_unpack_h__ -#define __GLX_unpack_h__ - -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#define __GLX_PAD(s) (((s)+3) & (GLuint)~3) - -/* -** Fetch the context-id out of a SingleReq request pointed to by pc. -*/ -#define __GLX_GET_SINGLE_CONTEXT_TAG(pc) (((xGLXSingleReq*)pc)->contextTag) -#define __GLX_GET_VENDPRIV_CONTEXT_TAG(pc) (((xGLXVendorPrivateReq*)pc)->contextTag) - -/* -** Fetch a double from potentially unaligned memory. -*/ -#ifdef __GLX_ALIGN64 -#define __GLX_MEM_COPY(dst,src,n) if (src != NULL && dst != NULL) memcpy(dst,src,n) -#define __GLX_GET_DOUBLE(dst,src) __GLX_MEM_COPY(&dst,src,8) -#else -#define __GLX_GET_DOUBLE(dst,src) (dst) = *((GLdouble*)(src)) -#endif - -extern void __glXMemInit(void); - -extern xGLXSingleReply __glXReply; - -#define __GLX_BEGIN_REPLY(size) \ - __glXReply.length = __GLX_PAD(size) >> 2; \ - __glXReply.type = X_Reply; \ - __glXReply.sequenceNumber = client->sequence; - -#define __GLX_SEND_HEADER() \ - WriteToClient( client, sz_xGLXSingleReply, (char *)&__glXReply); - -#define __GLX_PUT_RETVAL(a) \ - __glXReply.retval = (a); - -#define __GLX_PUT_SIZE(a) \ - __glXReply.size = (a); - -#define __GLX_PUT_RENDERMODE(m) \ - __glXReply.pad3 = (m) - -/* -** Get a buffer to hold returned data, with the given alignment. If we have -** to realloc, allocate size+align, in case the pointer has to be bumped for -** alignment. The answerBuffer should already be aligned. -** -** NOTE: the cast (long)res below assumes a long is large enough to hold a -** pointer. -*/ -#define __GLX_GET_ANSWER_BUFFER(res,cl,size,align) \ - if ((size) > sizeof(answerBuffer)) { \ - int bump; \ - if ((cl)->returnBufSize < (size)+(align)) { \ - (cl)->returnBuf = (GLbyte*)Xrealloc((cl)->returnBuf, \ - (size)+(align)); \ - if (!(cl)->returnBuf) { \ - return BadAlloc; \ - } \ - (cl)->returnBufSize = (size)+(align); \ - } \ - res = (char*)cl->returnBuf; \ - bump = (long)(res) % (align); \ - if (bump) res += (align) - (bump); \ - } else { \ - res = (char *)answerBuffer; \ - } - -#define __GLX_PUT_BYTE() \ - *(GLbyte *)&__glXReply.pad3 = *(GLbyte *)answer - -#define __GLX_PUT_SHORT() \ - *(GLshort *)&__glXReply.pad3 = *(GLshort *)answer - -#define __GLX_PUT_INT() \ - *(GLint *)&__glXReply.pad3 = *(GLint *)answer - -#define __GLX_PUT_FLOAT() \ - *(GLfloat *)&__glXReply.pad3 = *(GLfloat *)answer - -#define __GLX_PUT_DOUBLE() \ - *(GLdouble *)&__glXReply.pad3 = *(GLdouble *)answer - -#define __GLX_SEND_BYTE_ARRAY(len) \ - WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT8), (char *)answer) - -#define __GLX_SEND_SHORT_ARRAY(len) \ - WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT16), (char *)answer) - -#define __GLX_SEND_INT_ARRAY(len) \ - WriteToClient(client, (len)*__GLX_SIZE_INT32, (char *)answer) - -#define __GLX_SEND_FLOAT_ARRAY(len) \ - WriteToClient(client, (len)*__GLX_SIZE_FLOAT32, (char *)answer) - -#define __GLX_SEND_DOUBLE_ARRAY(len) \ - WriteToClient(client, (len)*__GLX_SIZE_FLOAT64, (char *)answer) - - -#define __GLX_SEND_VOID_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) -#define __GLX_SEND_UBYTE_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) -#define __GLX_SEND_USHORT_ARRAY(len) __GLX_SEND_SHORT_ARRAY(len) -#define __GLX_SEND_UINT_ARRAY(len) __GLX_SEND_INT_ARRAY(len) - -/* -** PERFORMANCE NOTE: -** Machine dependent optimizations abound here; these swapping macros can -** conceivably be replaced with routines that do the job faster. -*/ -#define __GLX_DECLARE_SWAP_VARIABLES \ - GLbyte sw - -#define __GLX_DECLARE_SWAP_ARRAY_VARIABLES \ - GLbyte *swapPC; \ - GLbyte *swapEnd - - -#define __GLX_SWAP_INT(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ - ((GLbyte *)(pc))[3] = sw; \ - sw = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ - ((GLbyte *)(pc))[2] = sw; - -#define __GLX_SWAP_SHORT(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = sw; - -#define __GLX_SWAP_DOUBLE(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[7]; \ - ((GLbyte *)(pc))[7] = sw; \ - sw = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[6]; \ - ((GLbyte *)(pc))[6] = sw; \ - sw = ((GLbyte *)(pc))[2]; \ - ((GLbyte *)(pc))[2] = ((GLbyte *)(pc))[5]; \ - ((GLbyte *)(pc))[5] = sw; \ - sw = ((GLbyte *)(pc))[3]; \ - ((GLbyte *)(pc))[3] = ((GLbyte *)(pc))[4]; \ - ((GLbyte *)(pc))[4] = sw; - -#define __GLX_SWAP_FLOAT(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ - ((GLbyte *)(pc))[3] = sw; \ - sw = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ - ((GLbyte *)(pc))[2] = sw; - -#define __GLX_SWAP_INT_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT32;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_INT(swapPC); \ - swapPC += __GLX_SIZE_INT32; \ - } - -#define __GLX_SWAP_SHORT_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT16;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_SHORT(swapPC); \ - swapPC += __GLX_SIZE_INT16; \ - } - -#define __GLX_SWAP_DOUBLE_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT64;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_DOUBLE(swapPC); \ - swapPC += __GLX_SIZE_FLOAT64; \ - } - -#define __GLX_SWAP_FLOAT_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT32;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_FLOAT(swapPC); \ - swapPC += __GLX_SIZE_FLOAT32; \ - } - -#define __GLX_SWAP_REPLY_HEADER() \ - __GLX_SWAP_SHORT(&__glXReply.sequenceNumber); \ - __GLX_SWAP_INT(&__glXReply.length); - -#define __GLX_SWAP_REPLY_RETVAL() \ - __GLX_SWAP_INT(&__glXReply.retval) - -#define __GLX_SWAP_REPLY_SIZE() \ - __GLX_SWAP_INT(&__glXReply.size) - -#endif /* !__GLX_unpack_h__ */ - - - - - +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef __GLX_unpack_h__ +#define __GLX_unpack_h__ + +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#define __GLX_PAD(s) (((s)+3) & (GLuint)~3) + +/* +** Fetch the context-id out of a SingleReq request pointed to by pc. +*/ +#define __GLX_GET_SINGLE_CONTEXT_TAG(pc) (((xGLXSingleReq*)pc)->contextTag) +#define __GLX_GET_VENDPRIV_CONTEXT_TAG(pc) (((xGLXVendorPrivateReq*)pc)->contextTag) + +/* +** Fetch a double from potentially unaligned memory. +*/ +#ifdef __GLX_ALIGN64 +#define __GLX_MEM_COPY(dst,src,n) if (src != NULL && dst != NULL) memcpy(dst,src,n) +#define __GLX_GET_DOUBLE(dst,src) __GLX_MEM_COPY(&dst,src,8) +#else +#define __GLX_GET_DOUBLE(dst,src) (dst) = *((GLdouble*)(src)) +#endif + +extern void __glXMemInit(void); + +extern xGLXSingleReply __glXReply; + +#define __GLX_BEGIN_REPLY(size) \ + __glXReply.length = __GLX_PAD(size) >> 2; \ + __glXReply.type = X_Reply; \ + __glXReply.sequenceNumber = client->sequence; + +#define __GLX_SEND_HEADER() \ + WriteToClient( client, sz_xGLXSingleReply, (char *)&__glXReply); + +#define __GLX_PUT_RETVAL(a) \ + __glXReply.retval = (a); + +#define __GLX_PUT_SIZE(a) \ + __glXReply.size = (a); + +#define __GLX_PUT_RENDERMODE(m) \ + __glXReply.pad3 = (m) + +/* +** Get a buffer to hold returned data, with the given alignment. If we have +** to realloc, allocate size+align, in case the pointer has to be bumped for +** alignment. The answerBuffer should already be aligned. +** +** NOTE: the cast (long)res below assumes a long is large enough to hold a +** pointer. +*/ +#define __GLX_GET_ANSWER_BUFFER(res,cl,size,align) \ + if ((size) > sizeof(answerBuffer)) { \ + int bump; \ + if ((cl)->returnBufSize < (size)+(align)) { \ + (cl)->returnBuf = (GLbyte*)realloc((cl)->returnBuf, \ + (size)+(align)); \ + if (!(cl)->returnBuf) { \ + return BadAlloc; \ + } \ + (cl)->returnBufSize = (size)+(align); \ + } \ + res = (char*)cl->returnBuf; \ + bump = (long)(res) % (align); \ + if (bump) res += (align) - (bump); \ + } else { \ + res = (char *)answerBuffer; \ + } + +#define __GLX_PUT_BYTE() \ + *(GLbyte *)&__glXReply.pad3 = *(GLbyte *)answer + +#define __GLX_PUT_SHORT() \ + *(GLshort *)&__glXReply.pad3 = *(GLshort *)answer + +#define __GLX_PUT_INT() \ + *(GLint *)&__glXReply.pad3 = *(GLint *)answer + +#define __GLX_PUT_FLOAT() \ + *(GLfloat *)&__glXReply.pad3 = *(GLfloat *)answer + +#define __GLX_PUT_DOUBLE() \ + *(GLdouble *)&__glXReply.pad3 = *(GLdouble *)answer + +#define __GLX_SEND_BYTE_ARRAY(len) \ + WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT8), (char *)answer) + +#define __GLX_SEND_SHORT_ARRAY(len) \ + WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT16), (char *)answer) + +#define __GLX_SEND_INT_ARRAY(len) \ + WriteToClient(client, (len)*__GLX_SIZE_INT32, (char *)answer) + +#define __GLX_SEND_FLOAT_ARRAY(len) \ + WriteToClient(client, (len)*__GLX_SIZE_FLOAT32, (char *)answer) + +#define __GLX_SEND_DOUBLE_ARRAY(len) \ + WriteToClient(client, (len)*__GLX_SIZE_FLOAT64, (char *)answer) + + +#define __GLX_SEND_VOID_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) +#define __GLX_SEND_UBYTE_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) +#define __GLX_SEND_USHORT_ARRAY(len) __GLX_SEND_SHORT_ARRAY(len) +#define __GLX_SEND_UINT_ARRAY(len) __GLX_SEND_INT_ARRAY(len) + +/* +** PERFORMANCE NOTE: +** Machine dependent optimizations abound here; these swapping macros can +** conceivably be replaced with routines that do the job faster. +*/ +#define __GLX_DECLARE_SWAP_VARIABLES \ + GLbyte sw + +#define __GLX_DECLARE_SWAP_ARRAY_VARIABLES \ + GLbyte *swapPC; \ + GLbyte *swapEnd + + +#define __GLX_SWAP_INT(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ + ((GLbyte *)(pc))[3] = sw; \ + sw = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ + ((GLbyte *)(pc))[2] = sw; + +#define __GLX_SWAP_SHORT(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = sw; + +#define __GLX_SWAP_DOUBLE(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[7]; \ + ((GLbyte *)(pc))[7] = sw; \ + sw = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[6]; \ + ((GLbyte *)(pc))[6] = sw; \ + sw = ((GLbyte *)(pc))[2]; \ + ((GLbyte *)(pc))[2] = ((GLbyte *)(pc))[5]; \ + ((GLbyte *)(pc))[5] = sw; \ + sw = ((GLbyte *)(pc))[3]; \ + ((GLbyte *)(pc))[3] = ((GLbyte *)(pc))[4]; \ + ((GLbyte *)(pc))[4] = sw; + +#define __GLX_SWAP_FLOAT(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ + ((GLbyte *)(pc))[3] = sw; \ + sw = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ + ((GLbyte *)(pc))[2] = sw; + +#define __GLX_SWAP_INT_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT32;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_INT(swapPC); \ + swapPC += __GLX_SIZE_INT32; \ + } + +#define __GLX_SWAP_SHORT_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT16;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_SHORT(swapPC); \ + swapPC += __GLX_SIZE_INT16; \ + } + +#define __GLX_SWAP_DOUBLE_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT64;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_DOUBLE(swapPC); \ + swapPC += __GLX_SIZE_FLOAT64; \ + } + +#define __GLX_SWAP_FLOAT_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT32;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_FLOAT(swapPC); \ + swapPC += __GLX_SIZE_FLOAT32; \ + } + +#define __GLX_SWAP_REPLY_HEADER() \ + __GLX_SWAP_SHORT(&__glXReply.sequenceNumber); \ + __GLX_SWAP_INT(&__glXReply.length); + +#define __GLX_SWAP_REPLY_RETVAL() \ + __GLX_SWAP_INT(&__glXReply.retval) + +#define __GLX_SWAP_REPLY_SIZE() \ + __GLX_SWAP_INT(&__glXReply.size) + +#endif /* !__GLX_unpack_h__ */ + + + + + diff --git a/xorg-server/glx/xfont.c b/xorg-server/glx/xfont.c index 9bd432a80..abcad1240 100644 --- a/xorg-server/glx/xfont.c +++ b/xorg-server/glx/xfont.c @@ -46,8 +46,6 @@ #include #include -extern XID clientErrorValue; /* imported kludge from dix layer */ - /* ** Make a single GL bitmap from a single X glyph */ @@ -76,7 +74,7 @@ static int __glXMakeBitmapFromGlyph(FontPtr font, CharInfoPtr pci) p = buf; allocbuf = 0; } else { - p = (unsigned char *) xalloc(allocBytes); + p = (unsigned char *) malloc(allocBytes); if (!p) return BadAlloc; allocbuf = p; @@ -100,7 +98,7 @@ static int __glXMakeBitmapFromGlyph(FontPtr font, CharInfoPtr pci) allocbuf ? allocbuf : buf) ); if (allocbuf) { - xfree(allocbuf); + free(allocbuf); } return Success; #undef __GL_CHAR_BUF_SIZE diff --git a/xorg-server/hw/dmx/dmx.c b/xorg-server/hw/dmx/dmx.c index a1afe76cf..b201fb8a7 100644 --- a/xorg-server/hw/dmx/dmx.c +++ b/xorg-server/hw/dmx/dmx.c @@ -1,1127 +1,1127 @@ -/* - * Copyright 2002-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * This file implements the server-side part of the DMX protocol. A - * vector of fucntions is provided at extension initialization time, so - * most all of the useful functions in this file are declared static and - * do not appear in the doxygen documentation. - * - * Much of the low-level work is done by functions in \a dmxextension.c - * - * Please see the Client-to-Server DMX Extension to the X Protocol - * document for details about the protocol. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include -#include -#include "misc.h" -#include "os.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "opaque.h" - -#include "dmxextension.h" -#include -#include -#include "protocol-versions.h" - -#ifdef PANORAMIX -#include "panoramiX.h" -extern unsigned long XRT_WINDOW; -extern int PanoramiXNumScreens; -#endif - -extern void DMXExtensionInit(void); - -static unsigned char DMXCode; - -static DISPATCH_PROC(ProcDMXDispatch); -static DISPATCH_PROC(ProcDMXQueryVersion); -static DISPATCH_PROC(ProcDMXSync); -static DISPATCH_PROC(ProcDMXForceWindowCreation); -static DISPATCH_PROC(ProcDMXGetScreenCount); -static DISPATCH_PROC(ProcDMXGetScreenAttributes); -static DISPATCH_PROC(ProcDMXChangeScreensAttributes); -static DISPATCH_PROC(ProcDMXAddScreen); -static DISPATCH_PROC(ProcDMXRemoveScreen); -static DISPATCH_PROC(ProcDMXGetWindowAttributes); -static DISPATCH_PROC(ProcDMXGetDesktopAttributes); -static DISPATCH_PROC(ProcDMXChangeDesktopAttributes); -static DISPATCH_PROC(ProcDMXGetInputCount); -static DISPATCH_PROC(ProcDMXGetInputAttributes); -static DISPATCH_PROC(ProcDMXAddInput); -static DISPATCH_PROC(ProcDMXRemoveInput); - -static DISPATCH_PROC(SProcDMXDispatch); -static DISPATCH_PROC(SProcDMXQueryVersion); -static DISPATCH_PROC(SProcDMXSync); -static DISPATCH_PROC(SProcDMXForceWindowCreation); -static DISPATCH_PROC(SProcDMXGetScreenCount); -static DISPATCH_PROC(SProcDMXGetScreenAttributes); -static DISPATCH_PROC(SProcDMXChangeScreensAttributes); -static DISPATCH_PROC(SProcDMXAddScreen); -static DISPATCH_PROC(SProcDMXRemoveScreen); -static DISPATCH_PROC(SProcDMXGetWindowAttributes); -static DISPATCH_PROC(SProcDMXGetDesktopAttributes); -static DISPATCH_PROC(SProcDMXChangeDesktopAttributes); -static DISPATCH_PROC(SProcDMXGetInputCount); -static DISPATCH_PROC(SProcDMXGetInputAttributes); -static DISPATCH_PROC(SProcDMXAddInput); -static DISPATCH_PROC(SProcDMXRemoveInput); - -static int _DMXXineramaActive(void) -{ -#ifdef PANORAMIX - return !noPanoramiXExtension; -#endif - return 0; -} - -/** Initialize the extension. */ -void DMXExtensionInit(void) -{ - ExtensionEntry *extEntry; - - if ((extEntry = AddExtension(DMX_EXTENSION_NAME, 0, 0, - ProcDMXDispatch, SProcDMXDispatch, - NULL, StandardMinorOpcode))) - DMXCode = extEntry->base; -} - -static void dmxSetScreenAttribute(int bit, DMXScreenAttributesPtr attr, - CARD32 value) -{ - switch (1 << bit) { - case DMXScreenWindowWidth: attr->screenWindowWidth = value; break; - case DMXScreenWindowHeight: attr->screenWindowHeight = value; break; - case DMXScreenWindowXoffset: attr->screenWindowXoffset = value; break; - case DMXScreenWindowYoffset: attr->screenWindowYoffset = value; break; - case DMXRootWindowWidth: attr->rootWindowWidth = value; break; - case DMXRootWindowHeight: attr->rootWindowHeight = value; break; - case DMXRootWindowXoffset: attr->rootWindowXoffset = value; break; - case DMXRootWindowYoffset: attr->rootWindowYoffset = value; break; - case DMXRootWindowXorigin: attr->rootWindowXorigin = value; break; - case DMXRootWindowYorigin: attr->rootWindowYorigin = value; break; - } -} - -static int dmxFetchScreenAttributes(unsigned int mask, - DMXScreenAttributesPtr attr, - CARD32 *value_list) -{ - int i; - CARD32 *value = value_list; - int count = 0; - - for (i = 0; i < 32; i++) { - if (mask & (1 << i)) { - dmxSetScreenAttribute(i, attr, *value); - ++value; - ++count; - } - } - return count; -} - -static void dmxSetDesktopAttribute(int bit, DMXDesktopAttributesPtr attr, - CARD32 value) -{ - switch (1 << bit) { - case DMXDesktopWidth: attr->width = value; break; - case DMXDesktopHeight: attr->height = value; break; - case DMXDesktopShiftX: attr->shiftX = value; break; - case DMXDesktopShiftY: attr->shiftY = value; break; - } -} - -static int dmxFetchDesktopAttributes(unsigned int mask, - DMXDesktopAttributesPtr attr, - CARD32 *value_list) -{ - int i; - CARD32 *value = value_list; - int count = 0; - - for (i = 0; i < 32; i++) { - if (mask & (1 << i)) { - dmxSetDesktopAttribute(i, attr, *value); - ++value; - ++count; - } - } - return count; -} - -static void dmxSetInputAttribute(int bit, DMXInputAttributesPtr attr, - CARD32 value) -{ - switch (1 << bit) { - case DMXInputType: attr->inputType = value; break; - case DMXInputPhysicalScreen: attr->physicalScreen = value; break; - case DMXInputSendsCore: attr->sendsCore = !!value; break; - } -} - -static int dmxFetchInputAttributes(unsigned int mask, - DMXInputAttributesPtr attr, - CARD32 *value_list) -{ - int i; - CARD32 *value = value_list; - int count = 0; - - for (i = 0; i < 32; i++) { - if (mask & (1 << i)) { - dmxSetInputAttribute(i, attr, *value); - ++value; - ++count; - } - } - return count; -} - -static int ProcDMXQueryVersion(ClientPtr client) -{ - xDMXQueryVersionReply rep; - int n; - - REQUEST_SIZE_MATCH(xDMXQueryVersionReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.majorVersion = SERVER_DMX_MAJOR_VERSION; - rep.minorVersion = SERVER_DMX_MINOR_VERSION; - rep.patchVersion = SERVER_DMX_PATCH_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.majorVersion, n); - swapl(&rep.minorVersion, n); - swapl(&rep.patchVersion, n); - } - WriteToClient(client, sizeof(xDMXQueryVersionReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXSync(ClientPtr client) -{ - xDMXSyncReply rep; - int n; - - REQUEST_SIZE_MATCH(xDMXSyncReq); - - dmxFlushPendingSyncs(); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = 0; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, sizeof(xDMXSyncReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXForceWindowCreation(ClientPtr client) -{ - xDMXForceWindowCreationReply rep; - REQUEST(xDMXForceWindowCreationReq); - WindowPtr pWin; - int n; - - REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq); - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - PanoramiXRes *win; - int i; - - if (!(win = SecurityLookupIDByType(client, stuff->window, XRT_WINDOW, - DixReadAccess))) - return -1; /* BadWindow */ - - FOR_NSCREENS(i) { - if (Success != dixLookupWindow(&pWin, win->info[i].id, client, - DixReadAccess)) - return -1; /* BadWindow */ - - dmxForceWindowCreation(pWin); - } - goto doreply; - } -#endif - - if (Success != dixLookupWindow(&pWin, stuff->window, client, - DixReadAccess)) - return -1; /* BadWindow */ - - dmxForceWindowCreation(pWin); - doreply: - dmxFlushPendingSyncs(); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = 0; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, sizeof(xDMXForceWindowCreationReply), (char *)&rep); - return Success; -} - -static int ProcDMXGetScreenCount(ClientPtr client) -{ - xDMXGetScreenCountReply rep; - int n; - - REQUEST_SIZE_MATCH(xDMXGetScreenCountReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.screenCount = dmxGetNumScreens(); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.screenCount, n); - } - WriteToClient(client, sizeof(xDMXGetScreenCountReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXGetScreenAttributes(ClientPtr client) -{ - REQUEST(xDMXGetScreenAttributesReq); - xDMXGetScreenAttributesReply rep; - int n; - int length; - int paddedLength; - DMXScreenAttributesRec attr; - - REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq); - - if (stuff->physicalScreen < 0 - || stuff->physicalScreen >= dmxGetNumScreens()) return BadValue; - - if (!dmxGetScreenAttributes(stuff->physicalScreen, &attr)) - return BadValue; - - rep.logicalScreen = attr.logicalScreen; - rep.screenWindowWidth = attr.screenWindowWidth; - rep.screenWindowHeight = attr.screenWindowHeight; - rep.screenWindowXoffset = attr.screenWindowXoffset; - rep.screenWindowYoffset = attr.screenWindowYoffset; - rep.rootWindowWidth = attr.rootWindowWidth; - rep.rootWindowHeight = attr.rootWindowHeight; - rep.rootWindowXoffset = attr.rootWindowXoffset; - rep.rootWindowYoffset = attr.rootWindowYoffset; - rep.rootWindowXorigin = attr.rootWindowXorigin; - rep.rootWindowYorigin = attr.rootWindowYorigin; - - length = attr.displayName ? strlen(attr.displayName) : 0; - paddedLength = pad_to_int32(length); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = bytes_to_int32((sizeof(xDMXGetScreenAttributesReply) - sizeof(xGenericReply)) - + paddedLength); - rep.displayNameLength = length; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.displayNameLength, n); - swapl(&rep.logicalScreen, n); - swaps(&rep.screenWindowWidth, n); - swaps(&rep.screenWindowHeight, n); - swaps(&rep.screenWindowXoffset, n); - swaps(&rep.screenWindowYoffset, n); - swaps(&rep.rootWindowWidth, n); - swaps(&rep.rootWindowHeight, n); - swaps(&rep.rootWindowXoffset, n); - swaps(&rep.rootWindowYoffset, n); - swaps(&rep.rootWindowXorigin, n); - swaps(&rep.rootWindowYorigin, n); - } - WriteToClient(client, sizeof(xDMXGetScreenAttributesReply), (char *)&rep); - if (length) WriteToClient(client, length, (char *)attr.displayName); - return client->noClientException; -} - -static int ProcDMXChangeScreensAttributes(ClientPtr client) -{ - REQUEST(xDMXChangeScreensAttributesReq); - xDMXChangeScreensAttributesReply rep; - int n; - int status = DMX_BAD_XINERAMA; - unsigned int mask = 0; - unsigned int i; - CARD32 *screen_list; - CARD32 *mask_list; - CARD32 *value_list; - DMXScreenAttributesPtr attribs; - int errorScreen = 0; - unsigned int len; - int ones = 0; - - - REQUEST_AT_LEAST_SIZE(xDMXChangeScreensAttributesReq); - len = client->req_len - bytes_to_int32(sizeof(xDMXChangeScreensAttributesReq)); - if (len < stuff->screenCount + stuff->maskCount) - return BadLength; - - screen_list = (CARD32 *)(stuff + 1); - mask_list = &screen_list[stuff->screenCount]; - value_list = &mask_list[stuff->maskCount]; - - for (i = 0; i < stuff->maskCount; i++) ones += Ones(mask_list[i]); - if (len != stuff->screenCount + stuff->maskCount + ones) - return BadLength; - - if (!_DMXXineramaActive()) goto noxinerama; - - if (!(attribs = xalloc(stuff->screenCount * sizeof(*attribs)))) - return BadAlloc; - - for (i = 0; i < stuff->screenCount; i++) { - int count; - - if (i < stuff->maskCount) mask = mask_list[i]; - dmxGetScreenAttributes(screen_list[i], &attribs[i]); - count = dmxFetchScreenAttributes(mask, &attribs[i], value_list); - value_list += count; - } - -#if PANORAMIX - status = dmxConfigureScreenWindows(stuff->screenCount, - screen_list, - attribs, - &errorScreen); -#endif - - xfree(attribs); - - if (status == BadValue) return status; - - noxinerama: - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - rep.errorScreen = errorScreen; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - swapl(&rep.errorScreen, n); - } - WriteToClient(client, - sizeof(xDMXChangeScreensAttributesReply), - (char *)&rep); - return client->noClientException; -} - -static int ProcDMXAddScreen(ClientPtr client) -{ - REQUEST(xDMXAddScreenReq); - xDMXAddScreenReply rep; - int n; - int status = 0; - CARD32 *value_list; - DMXScreenAttributesRec attr; - int count; - char *name; - int len; - int paddedLength; - - REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq); - paddedLength = pad_to_int32(stuff->displayNameLength); - len = client->req_len - bytes_to_int32(sizeof(xDMXAddScreenReq)); - if (len != Ones(stuff->valueMask) + paddedLength/4) - return BadLength; - - memset(&attr, 0, sizeof(attr)); - dmxGetScreenAttributes(stuff->physicalScreen, &attr); - value_list = (CARD32 *)(stuff + 1); - count = dmxFetchScreenAttributes(stuff->valueMask, &attr, value_list); - - if (!(name = xalloc(stuff->displayNameLength + 1 + 4))) - return BadAlloc; - memcpy(name, &value_list[count], stuff->displayNameLength); - name[stuff->displayNameLength] = '\0'; - attr.displayName = name; - - status = dmxAttachScreen(stuff->physicalScreen, &attr); - - xfree(name); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - rep.physicalScreen = stuff->physicalScreen; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - swapl(&rep.physicalScreen, n); - } - WriteToClient(client, - sizeof(xDMXAddScreenReply), - (char *)&rep); - return client->noClientException; -} - -static int ProcDMXRemoveScreen(ClientPtr client) -{ - REQUEST(xDMXRemoveScreenReq); - xDMXRemoveScreenReply rep; - int n; - int status = 0; - - REQUEST_SIZE_MATCH(xDMXRemoveScreenReq); - - status = dmxDetachScreen(stuff->physicalScreen); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, - sizeof(xDMXRemoveScreenReply), - (char *)&rep); - return client->noClientException; -} - - -#ifdef PANORAMIX -static int dmxPopulatePanoramiX(ClientPtr client, Window window, - CARD32 *screens, CARD32 *windows, - xRectangle *pos, xRectangle *vis) -{ - WindowPtr pWin; - PanoramiXRes *win; - int i; - int count = 0; - DMXWindowAttributesRec attr; - - if (!(win = SecurityLookupIDByType(client, window, XRT_WINDOW, - DixReadAccess))) - return -1; /* BadWindow */ - - FOR_NSCREENS(i) { - if (Success != dixLookupWindow(&pWin, win->info[i].id, client, - DixReadAccess)) - return -1; /* BadWindow */ - if (dmxGetWindowAttributes(pWin, &attr)) { - screens[count] = attr.screen; - windows[count] = attr.window; - pos[count] = attr.pos; - vis[count] = attr.vis; - ++count; /* Only count existing windows */ - } - } - return count; -} -#endif - -static int dmxPopulate(ClientPtr client, Window window, CARD32 *screens, - CARD32 *windows, xRectangle *pos, xRectangle *vis) -{ - WindowPtr pWin; - DMXWindowAttributesRec attr; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - return dmxPopulatePanoramiX(client, window, screens, windows, - pos, vis); -#endif - - if (Success != dixLookupWindow(&pWin, window, client, DixReadAccess)) - return -1; /* BadWindow */ - - dmxGetWindowAttributes(pWin, &attr); - *screens = attr.screen; - *windows = attr.window; - *pos = attr.pos; - *vis = attr.vis; - return 1; -} - -static int dmxMaxNumScreens(void) -{ -#ifdef PANORAMIX - if (!noPanoramiXExtension) return PanoramiXNumScreens; -#endif - return 1; -} - -static int ProcDMXGetWindowAttributes(ClientPtr client) -{ - REQUEST(xDMXGetWindowAttributesReq); - xDMXGetWindowAttributesReply rep; - int i, n; - CARD32 *screens; - CARD32 *windows; - xRectangle *pos, *vis; - int count = dmxMaxNumScreens(); - - REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq); - - if (!(screens = xalloc(count * sizeof(*screens)))) - return BadAlloc; - if (!(windows = xalloc(count * sizeof(*windows)))) { - xfree(screens); - return BadAlloc; - } - if (!(pos = xalloc(count * sizeof(*pos)))) { - xfree(windows); - xfree(screens); - return BadAlloc; - } - if (!(vis = xalloc(count * sizeof(*vis)))) { - xfree(pos); - xfree(windows); - xfree(screens); - return BadAlloc; - } - - if ((count = dmxPopulate(client, stuff->window, screens, windows, - pos, vis)) < 0) { - xfree(vis); - xfree(pos); - xfree(windows); - xfree(screens); - return BadWindow; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = count * 6; - rep.screenCount = count; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.screenCount, n); - for (i = 0; i < count; i++) { - swapl(&screens[i], n); - swapl(&windows[i], n); - - swaps(&pos[i].x, n); - swaps(&pos[i].y, n); - swaps(&pos[i].width, n); - swaps(&pos[i].height, n); - - swaps(&vis[i].x, n); - swaps(&vis[i].y, n); - swaps(&vis[i].width, n); - swaps(&vis[i].height, n); - } - } - - dmxFlushPendingSyncs(); - - WriteToClient(client, sizeof(xDMXGetWindowAttributesReply), (char *)&rep); - if (count) { - WriteToClient(client, count * sizeof(*screens), (char *)screens); - WriteToClient(client, count * sizeof(*windows), (char *)windows); - WriteToClient(client, count * sizeof(*pos), (char *)pos); - WriteToClient(client, count * sizeof(*vis), (char *)vis); - } - - xfree(vis); - xfree(pos); - xfree(windows); - xfree(screens); - - return client->noClientException; -} - -static int ProcDMXGetDesktopAttributes(ClientPtr client) -{ - xDMXGetDesktopAttributesReply rep; - int n; - DMXDesktopAttributesRec attr; - - REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq); - - dmxGetDesktopAttributes(&attr); - - rep.width = attr.width; - rep.height = attr.height; - rep.shiftX = attr.shiftX; - rep.shiftY = attr.shiftY; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.width, n); - swapl(&rep.height, n); - swapl(&rep.shiftX, n); - swapl(&rep.shiftY, n); - } - WriteToClient(client, sizeof(xDMXGetDesktopAttributesReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXChangeDesktopAttributes(ClientPtr client) -{ - REQUEST(xDMXChangeDesktopAttributesReq); - xDMXChangeDesktopAttributesReply rep; - int n; - int status = DMX_BAD_XINERAMA; - CARD32 *value_list; - DMXDesktopAttributesRec attr; - int len; - - REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq); - len = client->req_len - (sizeof(xDMXChangeDesktopAttributesReq) >> 2); - if (len != Ones(stuff->valueMask)) - return BadLength; - - if (!_DMXXineramaActive()) goto noxinerama; - - value_list = (CARD32 *)(stuff + 1); - - dmxGetDesktopAttributes(&attr); - dmxFetchDesktopAttributes(stuff->valueMask, &attr, value_list); - -#if PANORAMIX - status = dmxConfigureDesktop(&attr); -#endif - if (status == BadValue) return status; - - noxinerama: - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, - sizeof(xDMXChangeDesktopAttributesReply), - (char *)&rep); - return client->noClientException; -} - -static int ProcDMXGetInputCount(ClientPtr client) -{ - xDMXGetInputCountReply rep; - int n; - - REQUEST_SIZE_MATCH(xDMXGetInputCountReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.inputCount = dmxGetInputCount(); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.inputCount, n); - } - WriteToClient(client, sizeof(xDMXGetInputCountReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXGetInputAttributes(ClientPtr client) -{ - REQUEST(xDMXGetInputAttributesReq); - xDMXGetInputAttributesReply rep; - int n; - int length; - int paddedLength; - DMXInputAttributesRec attr; - - REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq); - - if (dmxGetInputAttributes(stuff->deviceId, &attr)) return BadValue; - rep.inputType = attr.inputType; - rep.physicalScreen = attr.physicalScreen; - rep.physicalId = attr.physicalId; - rep.isCore = attr.isCore; - rep.sendsCore = attr.sendsCore; - rep.detached = attr.detached; - - length = attr.name ? strlen(attr.name) : 0; - paddedLength = pad_to_int32(length); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = bytes_to_int32(paddedLength); - rep.nameLength = length; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.inputType, n); - swapl(&rep.physicalScreen, n); - swapl(&rep.physicalId, n); - swapl(&rep.nameLength, n); - } - WriteToClient(client, sizeof(xDMXGetInputAttributesReply), (char *)&rep); - if (length) WriteToClient(client, length, (char *)attr.name); - return client->noClientException; -} - -static int ProcDMXAddInput(ClientPtr client) -{ - REQUEST(xDMXAddInputReq); - xDMXAddInputReply rep; - int n; - int status = 0; - CARD32 *value_list; - DMXInputAttributesRec attr; - int count; - char *name; - int len; - int paddedLength; - int id = -1; - - REQUEST_AT_LEAST_SIZE(xDMXAddInputReq); - paddedLength = pad_to_int32(stuff->displayNameLength); - len = client->req_len - (sizeof(xDMXAddInputReq) >> 2); - if (len != Ones(stuff->valueMask) + paddedLength/4) - return BadLength; - - memset(&attr, 0, sizeof(attr)); - value_list = (CARD32 *)(stuff + 1); - count = dmxFetchInputAttributes(stuff->valueMask, &attr, value_list); - - if (!(name = xalloc(stuff->displayNameLength + 1 + 4))) - return BadAlloc; - memcpy(name, &value_list[count], stuff->displayNameLength); - name[stuff->displayNameLength] = '\0'; - attr.name = name; - - status = dmxAddInput(&attr, &id); - - xfree(name); - - if (status) return status; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - rep.physicalId = id; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - swapl(&rep.physicalId, n); - } - WriteToClient(client, sizeof(xDMXAddInputReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXRemoveInput(ClientPtr client) -{ - REQUEST(xDMXRemoveInputReq); - xDMXRemoveInputReply rep; - int n; - int status = 0; - - REQUEST_SIZE_MATCH(xDMXRemoveInputReq); - - status = dmxRemoveInput(stuff->physicalId); - - if (status) return status; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, sizeof(xDMXRemoveInputReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXDispatch(ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) { - case X_DMXQueryVersion: return ProcDMXQueryVersion(client); - case X_DMXSync: return ProcDMXSync(client); - case X_DMXForceWindowCreation: return ProcDMXForceWindowCreation(client); - case X_DMXGetScreenCount: return ProcDMXGetScreenCount(client); - case X_DMXGetScreenAttributes: return ProcDMXGetScreenAttributes(client); - case X_DMXChangeScreensAttributes: - return ProcDMXChangeScreensAttributes(client); - case X_DMXAddScreen: return ProcDMXAddScreen(client); - case X_DMXRemoveScreen: return ProcDMXRemoveScreen(client); - case X_DMXGetWindowAttributes: return ProcDMXGetWindowAttributes(client); - case X_DMXGetDesktopAttributes: return ProcDMXGetDesktopAttributes(client); - case X_DMXChangeDesktopAttributes: - return ProcDMXChangeDesktopAttributes(client); - case X_DMXGetInputCount: return ProcDMXGetInputCount(client); - case X_DMXGetInputAttributes: return ProcDMXGetInputAttributes(client); - case X_DMXAddInput: return ProcDMXAddInput(client); - case X_DMXRemoveInput: return ProcDMXRemoveInput(client); - - case X_DMXGetScreenInformationDEPRECATED: - case X_DMXForceWindowCreationDEPRECATED: - case X_DMXReconfigureScreenDEPRECATED: - return BadImplementation; - - default: return BadRequest; - } -} - -static int SProcDMXQueryVersion(ClientPtr client) -{ - int n; - REQUEST(xDMXQueryVersionReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXQueryVersionReq); - return ProcDMXQueryVersion(client); -} - -static int SProcDMXSync(ClientPtr client) -{ - int n; - REQUEST(xDMXSyncReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXSyncReq); - return ProcDMXSync(client); -} - -static int SProcDMXForceWindowCreation(ClientPtr client) -{ - int n; - REQUEST(xDMXForceWindowCreationReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq); - swaps(&stuff->window, n); - return ProcDMXForceWindowCreation(client); -} - -static int SProcDMXGetScreenCount(ClientPtr client) -{ - int n; - REQUEST(xDMXGetScreenCountReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetScreenCountReq); - return ProcDMXGetScreenCount(client); -} - -static int SProcDMXGetScreenAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXGetScreenAttributesReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq); - swapl(&stuff->physicalScreen, n); - return ProcDMXGetScreenAttributes(client); -} - -static int SProcDMXChangeScreensAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXChangeScreensAttributesReq); - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDMXGetScreenAttributesReq); - swapl(&stuff->screenCount, n); - swapl(&stuff->maskCount, n); - SwapRestL(stuff); - return ProcDMXGetScreenAttributes(client); -} - -static int SProcDMXAddScreen(ClientPtr client) -{ - int n; - int paddedLength; - REQUEST(xDMXAddScreenReq); - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq); - swapl(&stuff->displayNameLength, n); - swapl(&stuff->valueMask, n); - paddedLength = pad_to_int32(stuff->displayNameLength); - SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4); - return ProcDMXAddScreen(client); -} - -static int SProcDMXRemoveScreen(ClientPtr client) -{ - int n; - REQUEST(xDMXRemoveScreenReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXRemoveScreenReq); - swapl(&stuff->physicalScreen, n); - return ProcDMXRemoveScreen(client); -} - -static int SProcDMXGetWindowAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXGetWindowAttributesReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq); - swapl(&stuff->window, n); - return ProcDMXGetWindowAttributes(client); -} - -static int SProcDMXGetDesktopAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXGetDesktopAttributesReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq); - return ProcDMXGetDesktopAttributes(client); -} - -static int SProcDMXChangeDesktopAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXChangeDesktopAttributesReq); - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq); - swapl(&stuff->valueMask, n); - SwapRestL(stuff); - return ProcDMXChangeDesktopAttributes(client); -} - -static int SProcDMXGetInputCount(ClientPtr client) -{ - int n; - REQUEST(xDMXGetInputCountReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetInputCountReq); - return ProcDMXGetInputCount(client); -} - -static int SProcDMXGetInputAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXGetInputAttributesReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq); - swapl(&stuff->deviceId, n); - return ProcDMXGetInputAttributes(client); -} - -static int SProcDMXAddInput(ClientPtr client) -{ - int n; - int paddedLength; - REQUEST(xDMXAddInputReq); - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDMXAddInputReq); - swapl(&stuff->displayNameLength, n); - swapl(&stuff->valueMask, n); - paddedLength = pad_to_int32(stuff->displayNameLength); - SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4); - return ProcDMXAddInput(client); -} - -static int SProcDMXRemoveInput(ClientPtr client) -{ - int n; - REQUEST(xDMXRemoveInputReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXRemoveInputReq); - swapl(&stuff->physicalId, n); - return ProcDMXRemoveInput(client); -} - -static int SProcDMXDispatch (ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) { - case X_DMXQueryVersion: return SProcDMXQueryVersion(client); - case X_DMXSync: return SProcDMXSync(client); - case X_DMXForceWindowCreation: return SProcDMXForceWindowCreation(client); - case X_DMXGetScreenCount: return SProcDMXGetScreenCount(client); - case X_DMXGetScreenAttributes: return SProcDMXGetScreenAttributes(client); - case X_DMXChangeScreensAttributes: - return SProcDMXChangeScreensAttributes(client); - case X_DMXAddScreen: return SProcDMXAddScreen(client); - case X_DMXRemoveScreen: return SProcDMXRemoveScreen(client); - case X_DMXGetWindowAttributes: return SProcDMXGetWindowAttributes(client); - case X_DMXGetDesktopAttributes: - return SProcDMXGetDesktopAttributes(client); - case X_DMXChangeDesktopAttributes: - return SProcDMXChangeDesktopAttributes(client); - case X_DMXGetInputCount: return SProcDMXGetInputCount(client); - case X_DMXGetInputAttributes: return SProcDMXGetInputAttributes(client); - case X_DMXAddInput: return SProcDMXAddInput(client); - case X_DMXRemoveInput: return SProcDMXRemoveInput(client); - - case X_DMXGetScreenInformationDEPRECATED: - case X_DMXForceWindowCreationDEPRECATED: - case X_DMXReconfigureScreenDEPRECATED: - return BadImplementation; - - default: return BadRequest; - } -} +/* + * Copyright 2002-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * This file implements the server-side part of the DMX protocol. A + * vector of fucntions is provided at extension initialization time, so + * most all of the useful functions in this file are declared static and + * do not appear in the doxygen documentation. + * + * Much of the low-level work is done by functions in \a dmxextension.c + * + * Please see the Client-to-Server DMX Extension to the X Protocol + * document for details about the protocol. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "opaque.h" + +#include "dmxextension.h" +#include +#include +#include "protocol-versions.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +extern unsigned long XRT_WINDOW; +extern int PanoramiXNumScreens; +#endif + +extern void DMXExtensionInit(void); + +static unsigned char DMXCode; + +static DISPATCH_PROC(ProcDMXDispatch); +static DISPATCH_PROC(ProcDMXQueryVersion); +static DISPATCH_PROC(ProcDMXSync); +static DISPATCH_PROC(ProcDMXForceWindowCreation); +static DISPATCH_PROC(ProcDMXGetScreenCount); +static DISPATCH_PROC(ProcDMXGetScreenAttributes); +static DISPATCH_PROC(ProcDMXChangeScreensAttributes); +static DISPATCH_PROC(ProcDMXAddScreen); +static DISPATCH_PROC(ProcDMXRemoveScreen); +static DISPATCH_PROC(ProcDMXGetWindowAttributes); +static DISPATCH_PROC(ProcDMXGetDesktopAttributes); +static DISPATCH_PROC(ProcDMXChangeDesktopAttributes); +static DISPATCH_PROC(ProcDMXGetInputCount); +static DISPATCH_PROC(ProcDMXGetInputAttributes); +static DISPATCH_PROC(ProcDMXAddInput); +static DISPATCH_PROC(ProcDMXRemoveInput); + +static DISPATCH_PROC(SProcDMXDispatch); +static DISPATCH_PROC(SProcDMXQueryVersion); +static DISPATCH_PROC(SProcDMXSync); +static DISPATCH_PROC(SProcDMXForceWindowCreation); +static DISPATCH_PROC(SProcDMXGetScreenCount); +static DISPATCH_PROC(SProcDMXGetScreenAttributes); +static DISPATCH_PROC(SProcDMXChangeScreensAttributes); +static DISPATCH_PROC(SProcDMXAddScreen); +static DISPATCH_PROC(SProcDMXRemoveScreen); +static DISPATCH_PROC(SProcDMXGetWindowAttributes); +static DISPATCH_PROC(SProcDMXGetDesktopAttributes); +static DISPATCH_PROC(SProcDMXChangeDesktopAttributes); +static DISPATCH_PROC(SProcDMXGetInputCount); +static DISPATCH_PROC(SProcDMXGetInputAttributes); +static DISPATCH_PROC(SProcDMXAddInput); +static DISPATCH_PROC(SProcDMXRemoveInput); + +static int _DMXXineramaActive(void) +{ +#ifdef PANORAMIX + return !noPanoramiXExtension; +#endif + return 0; +} + +/** Initialize the extension. */ +void DMXExtensionInit(void) +{ + ExtensionEntry *extEntry; + + if ((extEntry = AddExtension(DMX_EXTENSION_NAME, 0, 0, + ProcDMXDispatch, SProcDMXDispatch, + NULL, StandardMinorOpcode))) + DMXCode = extEntry->base; +} + +static void dmxSetScreenAttribute(int bit, DMXScreenAttributesPtr attr, + CARD32 value) +{ + switch (1 << bit) { + case DMXScreenWindowWidth: attr->screenWindowWidth = value; break; + case DMXScreenWindowHeight: attr->screenWindowHeight = value; break; + case DMXScreenWindowXoffset: attr->screenWindowXoffset = value; break; + case DMXScreenWindowYoffset: attr->screenWindowYoffset = value; break; + case DMXRootWindowWidth: attr->rootWindowWidth = value; break; + case DMXRootWindowHeight: attr->rootWindowHeight = value; break; + case DMXRootWindowXoffset: attr->rootWindowXoffset = value; break; + case DMXRootWindowYoffset: attr->rootWindowYoffset = value; break; + case DMXRootWindowXorigin: attr->rootWindowXorigin = value; break; + case DMXRootWindowYorigin: attr->rootWindowYorigin = value; break; + } +} + +static int dmxFetchScreenAttributes(unsigned int mask, + DMXScreenAttributesPtr attr, + CARD32 *value_list) +{ + int i; + CARD32 *value = value_list; + int count = 0; + + for (i = 0; i < 32; i++) { + if (mask & (1 << i)) { + dmxSetScreenAttribute(i, attr, *value); + ++value; + ++count; + } + } + return count; +} + +static void dmxSetDesktopAttribute(int bit, DMXDesktopAttributesPtr attr, + CARD32 value) +{ + switch (1 << bit) { + case DMXDesktopWidth: attr->width = value; break; + case DMXDesktopHeight: attr->height = value; break; + case DMXDesktopShiftX: attr->shiftX = value; break; + case DMXDesktopShiftY: attr->shiftY = value; break; + } +} + +static int dmxFetchDesktopAttributes(unsigned int mask, + DMXDesktopAttributesPtr attr, + CARD32 *value_list) +{ + int i; + CARD32 *value = value_list; + int count = 0; + + for (i = 0; i < 32; i++) { + if (mask & (1 << i)) { + dmxSetDesktopAttribute(i, attr, *value); + ++value; + ++count; + } + } + return count; +} + +static void dmxSetInputAttribute(int bit, DMXInputAttributesPtr attr, + CARD32 value) +{ + switch (1 << bit) { + case DMXInputType: attr->inputType = value; break; + case DMXInputPhysicalScreen: attr->physicalScreen = value; break; + case DMXInputSendsCore: attr->sendsCore = !!value; break; + } +} + +static int dmxFetchInputAttributes(unsigned int mask, + DMXInputAttributesPtr attr, + CARD32 *value_list) +{ + int i; + CARD32 *value = value_list; + int count = 0; + + for (i = 0; i < 32; i++) { + if (mask & (1 << i)) { + dmxSetInputAttribute(i, attr, *value); + ++value; + ++count; + } + } + return count; +} + +static int ProcDMXQueryVersion(ClientPtr client) +{ + xDMXQueryVersionReply rep; + int n; + + REQUEST_SIZE_MATCH(xDMXQueryVersionReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.majorVersion = SERVER_DMX_MAJOR_VERSION; + rep.minorVersion = SERVER_DMX_MINOR_VERSION; + rep.patchVersion = SERVER_DMX_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + swapl(&rep.patchVersion, n); + } + WriteToClient(client, sizeof(xDMXQueryVersionReply), (char *)&rep); + return Success; +} + +static int ProcDMXSync(ClientPtr client) +{ + xDMXSyncReply rep; + int n; + + REQUEST_SIZE_MATCH(xDMXSyncReq); + + dmxFlushPendingSyncs(); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = 0; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, sizeof(xDMXSyncReply), (char *)&rep); + return Success; +} + +static int ProcDMXForceWindowCreation(ClientPtr client) +{ + xDMXForceWindowCreationReply rep; + REQUEST(xDMXForceWindowCreationReq); + WindowPtr pWin; + int n; + + REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + PanoramiXRes *win; + int i; + + if (!(win = SecurityLookupIDByType(client, stuff->window, XRT_WINDOW, + DixReadAccess))) + return -1; /* BadWindow */ + + FOR_NSCREENS(i) { + if (Success != dixLookupWindow(&pWin, win->info[i].id, client, + DixReadAccess)) + return -1; /* BadWindow */ + + dmxForceWindowCreation(pWin); + } + goto doreply; + } +#endif + + if (Success != dixLookupWindow(&pWin, stuff->window, client, + DixReadAccess)) + return -1; /* BadWindow */ + + dmxForceWindowCreation(pWin); + doreply: + dmxFlushPendingSyncs(); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = 0; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, sizeof(xDMXForceWindowCreationReply), (char *)&rep); + return Success; +} + +static int ProcDMXGetScreenCount(ClientPtr client) +{ + xDMXGetScreenCountReply rep; + int n; + + REQUEST_SIZE_MATCH(xDMXGetScreenCountReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.screenCount = dmxGetNumScreens(); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.screenCount, n); + } + WriteToClient(client, sizeof(xDMXGetScreenCountReply), (char *)&rep); + return Success; +} + +static int ProcDMXGetScreenAttributes(ClientPtr client) +{ + REQUEST(xDMXGetScreenAttributesReq); + xDMXGetScreenAttributesReply rep; + int n; + int length; + int paddedLength; + DMXScreenAttributesRec attr; + + REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq); + + if (stuff->physicalScreen < 0 + || stuff->physicalScreen >= dmxGetNumScreens()) return BadValue; + + if (!dmxGetScreenAttributes(stuff->physicalScreen, &attr)) + return BadValue; + + rep.logicalScreen = attr.logicalScreen; + rep.screenWindowWidth = attr.screenWindowWidth; + rep.screenWindowHeight = attr.screenWindowHeight; + rep.screenWindowXoffset = attr.screenWindowXoffset; + rep.screenWindowYoffset = attr.screenWindowYoffset; + rep.rootWindowWidth = attr.rootWindowWidth; + rep.rootWindowHeight = attr.rootWindowHeight; + rep.rootWindowXoffset = attr.rootWindowXoffset; + rep.rootWindowYoffset = attr.rootWindowYoffset; + rep.rootWindowXorigin = attr.rootWindowXorigin; + rep.rootWindowYorigin = attr.rootWindowYorigin; + + length = attr.displayName ? strlen(attr.displayName) : 0; + paddedLength = pad_to_int32(length); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = bytes_to_int32((sizeof(xDMXGetScreenAttributesReply) - sizeof(xGenericReply)) + + paddedLength); + rep.displayNameLength = length; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.displayNameLength, n); + swapl(&rep.logicalScreen, n); + swaps(&rep.screenWindowWidth, n); + swaps(&rep.screenWindowHeight, n); + swaps(&rep.screenWindowXoffset, n); + swaps(&rep.screenWindowYoffset, n); + swaps(&rep.rootWindowWidth, n); + swaps(&rep.rootWindowHeight, n); + swaps(&rep.rootWindowXoffset, n); + swaps(&rep.rootWindowYoffset, n); + swaps(&rep.rootWindowXorigin, n); + swaps(&rep.rootWindowYorigin, n); + } + WriteToClient(client, sizeof(xDMXGetScreenAttributesReply), (char *)&rep); + if (length) WriteToClient(client, length, (char *)attr.displayName); + return Success; +} + +static int ProcDMXChangeScreensAttributes(ClientPtr client) +{ + REQUEST(xDMXChangeScreensAttributesReq); + xDMXChangeScreensAttributesReply rep; + int n; + int status = DMX_BAD_XINERAMA; + unsigned int mask = 0; + unsigned int i; + CARD32 *screen_list; + CARD32 *mask_list; + CARD32 *value_list; + DMXScreenAttributesPtr attribs; + int errorScreen = 0; + unsigned int len; + int ones = 0; + + + REQUEST_AT_LEAST_SIZE(xDMXChangeScreensAttributesReq); + len = client->req_len - bytes_to_int32(sizeof(xDMXChangeScreensAttributesReq)); + if (len < stuff->screenCount + stuff->maskCount) + return BadLength; + + screen_list = (CARD32 *)(stuff + 1); + mask_list = &screen_list[stuff->screenCount]; + value_list = &mask_list[stuff->maskCount]; + + for (i = 0; i < stuff->maskCount; i++) ones += Ones(mask_list[i]); + if (len != stuff->screenCount + stuff->maskCount + ones) + return BadLength; + + if (!_DMXXineramaActive()) goto noxinerama; + + if (!(attribs = malloc(stuff->screenCount * sizeof(*attribs)))) + return BadAlloc; + + for (i = 0; i < stuff->screenCount; i++) { + int count; + + if (i < stuff->maskCount) mask = mask_list[i]; + dmxGetScreenAttributes(screen_list[i], &attribs[i]); + count = dmxFetchScreenAttributes(mask, &attribs[i], value_list); + value_list += count; + } + +#if PANORAMIX + status = dmxConfigureScreenWindows(stuff->screenCount, + screen_list, + attribs, + &errorScreen); +#endif + + free(attribs); + + if (status == BadValue) return status; + + noxinerama: + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + rep.errorScreen = errorScreen; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + swapl(&rep.errorScreen, n); + } + WriteToClient(client, + sizeof(xDMXChangeScreensAttributesReply), + (char *)&rep); + return Success; +} + +static int ProcDMXAddScreen(ClientPtr client) +{ + REQUEST(xDMXAddScreenReq); + xDMXAddScreenReply rep; + int n; + int status = 0; + CARD32 *value_list; + DMXScreenAttributesRec attr; + int count; + char *name; + int len; + int paddedLength; + + REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq); + paddedLength = pad_to_int32(stuff->displayNameLength); + len = client->req_len - bytes_to_int32(sizeof(xDMXAddScreenReq)); + if (len != Ones(stuff->valueMask) + paddedLength/4) + return BadLength; + + memset(&attr, 0, sizeof(attr)); + dmxGetScreenAttributes(stuff->physicalScreen, &attr); + value_list = (CARD32 *)(stuff + 1); + count = dmxFetchScreenAttributes(stuff->valueMask, &attr, value_list); + + if (!(name = malloc(stuff->displayNameLength + 1 + 4))) + return BadAlloc; + memcpy(name, &value_list[count], stuff->displayNameLength); + name[stuff->displayNameLength] = '\0'; + attr.displayName = name; + + status = dmxAttachScreen(stuff->physicalScreen, &attr); + + free(name); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + rep.physicalScreen = stuff->physicalScreen; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + swapl(&rep.physicalScreen, n); + } + WriteToClient(client, + sizeof(xDMXAddScreenReply), + (char *)&rep); + return Success; +} + +static int ProcDMXRemoveScreen(ClientPtr client) +{ + REQUEST(xDMXRemoveScreenReq); + xDMXRemoveScreenReply rep; + int n; + int status = 0; + + REQUEST_SIZE_MATCH(xDMXRemoveScreenReq); + + status = dmxDetachScreen(stuff->physicalScreen); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, + sizeof(xDMXRemoveScreenReply), + (char *)&rep); + return Success; +} + + +#ifdef PANORAMIX +static int dmxPopulatePanoramiX(ClientPtr client, Window window, + CARD32 *screens, CARD32 *windows, + xRectangle *pos, xRectangle *vis) +{ + WindowPtr pWin; + PanoramiXRes *win; + int i; + int count = 0; + DMXWindowAttributesRec attr; + + if (!(win = SecurityLookupIDByType(client, window, XRT_WINDOW, + DixReadAccess))) + return -1; /* BadWindow */ + + FOR_NSCREENS(i) { + if (Success != dixLookupWindow(&pWin, win->info[i].id, client, + DixReadAccess)) + return -1; /* BadWindow */ + if (dmxGetWindowAttributes(pWin, &attr)) { + screens[count] = attr.screen; + windows[count] = attr.window; + pos[count] = attr.pos; + vis[count] = attr.vis; + ++count; /* Only count existing windows */ + } + } + return count; +} +#endif + +static int dmxPopulate(ClientPtr client, Window window, CARD32 *screens, + CARD32 *windows, xRectangle *pos, xRectangle *vis) +{ + WindowPtr pWin; + DMXWindowAttributesRec attr; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + return dmxPopulatePanoramiX(client, window, screens, windows, + pos, vis); +#endif + + if (Success != dixLookupWindow(&pWin, window, client, DixReadAccess)) + return -1; /* BadWindow */ + + dmxGetWindowAttributes(pWin, &attr); + *screens = attr.screen; + *windows = attr.window; + *pos = attr.pos; + *vis = attr.vis; + return 1; +} + +static int dmxMaxNumScreens(void) +{ +#ifdef PANORAMIX + if (!noPanoramiXExtension) return PanoramiXNumScreens; +#endif + return 1; +} + +static int ProcDMXGetWindowAttributes(ClientPtr client) +{ + REQUEST(xDMXGetWindowAttributesReq); + xDMXGetWindowAttributesReply rep; + int i, n; + CARD32 *screens; + CARD32 *windows; + xRectangle *pos, *vis; + int count = dmxMaxNumScreens(); + + REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq); + + if (!(screens = malloc(count * sizeof(*screens)))) + return BadAlloc; + if (!(windows = malloc(count * sizeof(*windows)))) { + free(screens); + return BadAlloc; + } + if (!(pos = malloc(count * sizeof(*pos)))) { + free(windows); + free(screens); + return BadAlloc; + } + if (!(vis = malloc(count * sizeof(*vis)))) { + free(pos); + free(windows); + free(screens); + return BadAlloc; + } + + if ((count = dmxPopulate(client, stuff->window, screens, windows, + pos, vis)) < 0) { + free(vis); + free(pos); + free(windows); + free(screens); + return BadWindow; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = count * 6; + rep.screenCount = count; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.screenCount, n); + for (i = 0; i < count; i++) { + swapl(&screens[i], n); + swapl(&windows[i], n); + + swaps(&pos[i].x, n); + swaps(&pos[i].y, n); + swaps(&pos[i].width, n); + swaps(&pos[i].height, n); + + swaps(&vis[i].x, n); + swaps(&vis[i].y, n); + swaps(&vis[i].width, n); + swaps(&vis[i].height, n); + } + } + + dmxFlushPendingSyncs(); + + WriteToClient(client, sizeof(xDMXGetWindowAttributesReply), (char *)&rep); + if (count) { + WriteToClient(client, count * sizeof(*screens), (char *)screens); + WriteToClient(client, count * sizeof(*windows), (char *)windows); + WriteToClient(client, count * sizeof(*pos), (char *)pos); + WriteToClient(client, count * sizeof(*vis), (char *)vis); + } + + free(vis); + free(pos); + free(windows); + free(screens); + + return Success; +} + +static int ProcDMXGetDesktopAttributes(ClientPtr client) +{ + xDMXGetDesktopAttributesReply rep; + int n; + DMXDesktopAttributesRec attr; + + REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq); + + dmxGetDesktopAttributes(&attr); + + rep.width = attr.width; + rep.height = attr.height; + rep.shiftX = attr.shiftX; + rep.shiftY = attr.shiftY; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.width, n); + swapl(&rep.height, n); + swapl(&rep.shiftX, n); + swapl(&rep.shiftY, n); + } + WriteToClient(client, sizeof(xDMXGetDesktopAttributesReply), (char *)&rep); + return Success; +} + +static int ProcDMXChangeDesktopAttributes(ClientPtr client) +{ + REQUEST(xDMXChangeDesktopAttributesReq); + xDMXChangeDesktopAttributesReply rep; + int n; + int status = DMX_BAD_XINERAMA; + CARD32 *value_list; + DMXDesktopAttributesRec attr; + int len; + + REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq); + len = client->req_len - (sizeof(xDMXChangeDesktopAttributesReq) >> 2); + if (len != Ones(stuff->valueMask)) + return BadLength; + + if (!_DMXXineramaActive()) goto noxinerama; + + value_list = (CARD32 *)(stuff + 1); + + dmxGetDesktopAttributes(&attr); + dmxFetchDesktopAttributes(stuff->valueMask, &attr, value_list); + +#if PANORAMIX + status = dmxConfigureDesktop(&attr); +#endif + if (status == BadValue) return status; + + noxinerama: + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, + sizeof(xDMXChangeDesktopAttributesReply), + (char *)&rep); + return Success; +} + +static int ProcDMXGetInputCount(ClientPtr client) +{ + xDMXGetInputCountReply rep; + int n; + + REQUEST_SIZE_MATCH(xDMXGetInputCountReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.inputCount = dmxGetInputCount(); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.inputCount, n); + } + WriteToClient(client, sizeof(xDMXGetInputCountReply), (char *)&rep); + return Success; +} + +static int ProcDMXGetInputAttributes(ClientPtr client) +{ + REQUEST(xDMXGetInputAttributesReq); + xDMXGetInputAttributesReply rep; + int n; + int length; + int paddedLength; + DMXInputAttributesRec attr; + + REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq); + + if (dmxGetInputAttributes(stuff->deviceId, &attr)) return BadValue; + rep.inputType = attr.inputType; + rep.physicalScreen = attr.physicalScreen; + rep.physicalId = attr.physicalId; + rep.isCore = attr.isCore; + rep.sendsCore = attr.sendsCore; + rep.detached = attr.detached; + + length = attr.name ? strlen(attr.name) : 0; + paddedLength = pad_to_int32(length); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = bytes_to_int32(paddedLength); + rep.nameLength = length; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.inputType, n); + swapl(&rep.physicalScreen, n); + swapl(&rep.physicalId, n); + swapl(&rep.nameLength, n); + } + WriteToClient(client, sizeof(xDMXGetInputAttributesReply), (char *)&rep); + if (length) WriteToClient(client, length, (char *)attr.name); + return Success; +} + +static int ProcDMXAddInput(ClientPtr client) +{ + REQUEST(xDMXAddInputReq); + xDMXAddInputReply rep; + int n; + int status = 0; + CARD32 *value_list; + DMXInputAttributesRec attr; + int count; + char *name; + int len; + int paddedLength; + int id = -1; + + REQUEST_AT_LEAST_SIZE(xDMXAddInputReq); + paddedLength = pad_to_int32(stuff->displayNameLength); + len = client->req_len - (sizeof(xDMXAddInputReq) >> 2); + if (len != Ones(stuff->valueMask) + paddedLength/4) + return BadLength; + + memset(&attr, 0, sizeof(attr)); + value_list = (CARD32 *)(stuff + 1); + count = dmxFetchInputAttributes(stuff->valueMask, &attr, value_list); + + if (!(name = malloc(stuff->displayNameLength + 1 + 4))) + return BadAlloc; + memcpy(name, &value_list[count], stuff->displayNameLength); + name[stuff->displayNameLength] = '\0'; + attr.name = name; + + status = dmxAddInput(&attr, &id); + + free(name); + + if (status) return status; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + rep.physicalId = id; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + swapl(&rep.physicalId, n); + } + WriteToClient(client, sizeof(xDMXAddInputReply), (char *)&rep); + return Success; +} + +static int ProcDMXRemoveInput(ClientPtr client) +{ + REQUEST(xDMXRemoveInputReq); + xDMXRemoveInputReply rep; + int n; + int status = 0; + + REQUEST_SIZE_MATCH(xDMXRemoveInputReq); + + status = dmxRemoveInput(stuff->physicalId); + + if (status) return status; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, sizeof(xDMXRemoveInputReply), (char *)&rep); + return Success; +} + +static int ProcDMXDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_DMXQueryVersion: return ProcDMXQueryVersion(client); + case X_DMXSync: return ProcDMXSync(client); + case X_DMXForceWindowCreation: return ProcDMXForceWindowCreation(client); + case X_DMXGetScreenCount: return ProcDMXGetScreenCount(client); + case X_DMXGetScreenAttributes: return ProcDMXGetScreenAttributes(client); + case X_DMXChangeScreensAttributes: + return ProcDMXChangeScreensAttributes(client); + case X_DMXAddScreen: return ProcDMXAddScreen(client); + case X_DMXRemoveScreen: return ProcDMXRemoveScreen(client); + case X_DMXGetWindowAttributes: return ProcDMXGetWindowAttributes(client); + case X_DMXGetDesktopAttributes: return ProcDMXGetDesktopAttributes(client); + case X_DMXChangeDesktopAttributes: + return ProcDMXChangeDesktopAttributes(client); + case X_DMXGetInputCount: return ProcDMXGetInputCount(client); + case X_DMXGetInputAttributes: return ProcDMXGetInputAttributes(client); + case X_DMXAddInput: return ProcDMXAddInput(client); + case X_DMXRemoveInput: return ProcDMXRemoveInput(client); + + case X_DMXGetScreenInformationDEPRECATED: + case X_DMXForceWindowCreationDEPRECATED: + case X_DMXReconfigureScreenDEPRECATED: + return BadImplementation; + + default: return BadRequest; + } +} + +static int SProcDMXQueryVersion(ClientPtr client) +{ + int n; + REQUEST(xDMXQueryVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXQueryVersionReq); + return ProcDMXQueryVersion(client); +} + +static int SProcDMXSync(ClientPtr client) +{ + int n; + REQUEST(xDMXSyncReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXSyncReq); + return ProcDMXSync(client); +} + +static int SProcDMXForceWindowCreation(ClientPtr client) +{ + int n; + REQUEST(xDMXForceWindowCreationReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq); + swaps(&stuff->window, n); + return ProcDMXForceWindowCreation(client); +} + +static int SProcDMXGetScreenCount(ClientPtr client) +{ + int n; + REQUEST(xDMXGetScreenCountReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetScreenCountReq); + return ProcDMXGetScreenCount(client); +} + +static int SProcDMXGetScreenAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXGetScreenAttributesReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq); + swapl(&stuff->physicalScreen, n); + return ProcDMXGetScreenAttributes(client); +} + +static int SProcDMXChangeScreensAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXChangeScreensAttributesReq); + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDMXGetScreenAttributesReq); + swapl(&stuff->screenCount, n); + swapl(&stuff->maskCount, n); + SwapRestL(stuff); + return ProcDMXGetScreenAttributes(client); +} + +static int SProcDMXAddScreen(ClientPtr client) +{ + int n; + int paddedLength; + REQUEST(xDMXAddScreenReq); + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq); + swapl(&stuff->displayNameLength, n); + swapl(&stuff->valueMask, n); + paddedLength = pad_to_int32(stuff->displayNameLength); + SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4); + return ProcDMXAddScreen(client); +} + +static int SProcDMXRemoveScreen(ClientPtr client) +{ + int n; + REQUEST(xDMXRemoveScreenReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXRemoveScreenReq); + swapl(&stuff->physicalScreen, n); + return ProcDMXRemoveScreen(client); +} + +static int SProcDMXGetWindowAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXGetWindowAttributesReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq); + swapl(&stuff->window, n); + return ProcDMXGetWindowAttributes(client); +} + +static int SProcDMXGetDesktopAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXGetDesktopAttributesReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq); + return ProcDMXGetDesktopAttributes(client); +} + +static int SProcDMXChangeDesktopAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXChangeDesktopAttributesReq); + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq); + swapl(&stuff->valueMask, n); + SwapRestL(stuff); + return ProcDMXChangeDesktopAttributes(client); +} + +static int SProcDMXGetInputCount(ClientPtr client) +{ + int n; + REQUEST(xDMXGetInputCountReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetInputCountReq); + return ProcDMXGetInputCount(client); +} + +static int SProcDMXGetInputAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXGetInputAttributesReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq); + swapl(&stuff->deviceId, n); + return ProcDMXGetInputAttributes(client); +} + +static int SProcDMXAddInput(ClientPtr client) +{ + int n; + int paddedLength; + REQUEST(xDMXAddInputReq); + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDMXAddInputReq); + swapl(&stuff->displayNameLength, n); + swapl(&stuff->valueMask, n); + paddedLength = pad_to_int32(stuff->displayNameLength); + SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4); + return ProcDMXAddInput(client); +} + +static int SProcDMXRemoveInput(ClientPtr client) +{ + int n; + REQUEST(xDMXRemoveInputReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXRemoveInputReq); + swapl(&stuff->physicalId, n); + return ProcDMXRemoveInput(client); +} + +static int SProcDMXDispatch (ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_DMXQueryVersion: return SProcDMXQueryVersion(client); + case X_DMXSync: return SProcDMXSync(client); + case X_DMXForceWindowCreation: return SProcDMXForceWindowCreation(client); + case X_DMXGetScreenCount: return SProcDMXGetScreenCount(client); + case X_DMXGetScreenAttributes: return SProcDMXGetScreenAttributes(client); + case X_DMXChangeScreensAttributes: + return SProcDMXChangeScreensAttributes(client); + case X_DMXAddScreen: return SProcDMXAddScreen(client); + case X_DMXRemoveScreen: return SProcDMXRemoveScreen(client); + case X_DMXGetWindowAttributes: return SProcDMXGetWindowAttributes(client); + case X_DMXGetDesktopAttributes: + return SProcDMXGetDesktopAttributes(client); + case X_DMXChangeDesktopAttributes: + return SProcDMXChangeDesktopAttributes(client); + case X_DMXGetInputCount: return SProcDMXGetInputCount(client); + case X_DMXGetInputAttributes: return SProcDMXGetInputAttributes(client); + case X_DMXAddInput: return SProcDMXAddInput(client); + case X_DMXRemoveInput: return SProcDMXRemoveInput(client); + + case X_DMXGetScreenInformationDEPRECATED: + case X_DMXForceWindowCreationDEPRECATED: + case X_DMXReconfigureScreenDEPRECATED: + return BadImplementation; + + default: return BadRequest; + } +} diff --git a/xorg-server/hw/dmx/dmx_glxvisuals.c b/xorg-server/hw/dmx/dmx_glxvisuals.c index ec33468be..50a23e30f 100644 --- a/xorg-server/hw/dmx/dmx_glxvisuals.c +++ b/xorg-server/hw/dmx/dmx_glxvisuals.c @@ -1,601 +1,601 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include -#include -#include -#include - -#include "dmx_glxvisuals.h" - -__GLXvisualConfig *GetGLXVisualConfigs(Display *dpy, int screen, int *nconfigs) -{ - xGLXGetVisualConfigsReq *req; - xGLXGetVisualConfigsReply reply; - __GLXvisualConfig *config, *configs; - GLint i, j, nvisuals, nprops; - INT32 *props, *p; - int majorOpcode, dummy; - int num_good_visuals; - - if (!XQueryExtension(dpy, "GLX", &majorOpcode, &dummy, &dummy)) { - return(NULL); - } - - /* Send the glXGetVisualConfigs request */ - LockDisplay(dpy); - GetReq(GLXGetVisualConfigs,req); - req->reqType = majorOpcode; - req->glxCode = X_GLXGetVisualConfigs; - req->screen = screen; - if (!_XReply(dpy, (xReply*) &reply, 0, False)) { - /* Something is busted. Punt. */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - nvisuals = (int)reply.numVisuals; - if (!nvisuals) { - /* This screen does not support GL rendering */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - /* Check number of properties per visual */ - nprops = (int)reply.numProps; - if (nprops < __GLX_MIN_CONFIG_PROPS) { - /* Huh? Not in protocol defined limits. Punt */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - props = (INT32*) Xmalloc(nprops * __GLX_SIZE_CARD32); - if (!props) { - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - /* Allocate memory for our config structure */ - config = (__GLXvisualConfig*) - Xmalloc(nvisuals * sizeof(__GLXvisualConfig)); - if (!config) { - Xfree(props); - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - memset(config, 0, nvisuals * sizeof(__GLXvisualConfig)); - configs = config; - num_good_visuals = 0; - - /* Convert config structure into our format */ - for (i=0; ivisualRating = GLX_NONE_EXT; - config->transparentPixel = GLX_NONE_EXT; - - /* Copy in the first set of properties */ - config->vid = props[0]; - config->class = props[1]; - - config->rgba = (Bool) props[2]; - - config->redSize = props[3]; - config->greenSize = props[4]; - config->blueSize = props[5]; - config->alphaSize = props[6]; - - config->accumRedSize = props[7]; - config->accumGreenSize = props[8]; - config->accumBlueSize = props[9]; - config->accumAlphaSize = props[10]; - - config->doubleBuffer = (Bool) props[11]; - config->stereo = (Bool) props[12]; - - config->bufferSize = props[13]; - config->depthSize = props[14]; - config->stencilSize = props[15]; - - config->auxBuffers = props[16]; - config->level = props[17]; - - /* Process remaining properties */ - p = &props[18]; - for (j=__GLX_MIN_CONFIG_PROPS; jmultiSampleSize = value; - break; - case GLX_SAMPLE_BUFFERS_SGIS: - config->nMultiSampleBuffers = value; - break; - - case GLX_TRANSPARENT_TYPE_EXT: - config->transparentPixel = value; - break; - case GLX_TRANSPARENT_INDEX_VALUE_EXT: - config->transparentIndex = value; - break; - case GLX_TRANSPARENT_RED_VALUE_EXT: - config->transparentRed = value; - break; - case GLX_TRANSPARENT_GREEN_VALUE_EXT: - config->transparentGreen = value; - break; - case GLX_TRANSPARENT_BLUE_VALUE_EXT: - config->transparentBlue = value; - break; - case GLX_TRANSPARENT_ALPHA_VALUE_EXT: - config->transparentAlpha = value; - break; - - case GLX_VISUAL_CAVEAT_EXT: - config->visualRating = value; - break; - - /* visualSelectGroup is an internal used property */ - case GLX_VISUAL_SELECT_GROUP_SGIX: - config->visualSelectGroup = value; - break; - - default : - /* Ignore properties we don't recognize */ - break; - } - } /* for j */ - - /* - // filter out overlay visuals (dmx does not support overlays) - */ - if (config->level == 0) { - config++; - num_good_visuals++; - } - - } /* for i */ - - UnlockDisplay(dpy); - - nvisuals = num_good_visuals; - - config = configs; - for (i=0; ivid; - vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask, - &template, &n); - - if (vis != NULL) { - config->redMask = vis->red_mask; - config->greenMask = vis->green_mask; - config->blueMask = vis->blue_mask; - config->alphaMask = 0; /* XXX */ - free(vis); - } - } - config++; - } /* for i */ - - XFree(props); - SyncHandle(); - - *nconfigs = nvisuals; - return( configs ); -} - - -__GLXFBConfig *GetGLXFBConfigs(Display *dpy, int glxMajorOpcode, int *nconfigs) -{ - xGLXGetFBConfigsReq *req; - xGLXGetFBConfigsReply reply; - __GLXFBConfig *config, *fbconfigs; - GLint i, j, numFBConfigs, numAttribs; - INT32 *attrs, *p; - int screen = DefaultScreen( dpy ); - int numValidConfigs = 0; - - /* Send the glXGetFBConfigs request */ - LockDisplay(dpy); - GetReq(GLXGetFBConfigs, req); - req->reqType = glxMajorOpcode; - req->glxCode = X_GLXGetFBConfigs; - req->screen = screen; - - *nconfigs = 0; - - if (!_XReply(dpy, (xReply*) &reply, 0, False)) { - /* Something is busted. Punt. */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - numFBConfigs = (int)reply.numFBConfigs; - if (!numFBConfigs) { - /* This screen does not support GL rendering */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - numAttribs = (int)reply.numAttribs; - if (!numAttribs) { - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - attrs = (INT32*) Xmalloc(2*numAttribs * __GLX_SIZE_CARD32); - if (!attrs) { - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - /* Allocate memory for our config structure */ - config = (__GLXFBConfig*) - Xmalloc(numFBConfigs * sizeof(__GLXFBConfig)); - if (!config) { - Xfree(attrs); - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - memset(config, 0, numFBConfigs * sizeof(__GLXFBConfig)); - fbconfigs = config; - - /* Convert attribute list into our format */ - for (i=0; itransparentType = GLX_NONE_EXT; - config->visualCaveat = GLX_NONE_EXT; - config->minRed = 0.; - config->maxRed = 1.; - config->minGreen = 0.; - config->maxGreen = 1.; - config->minBlue = 0.; - config->maxBlue = 1.; - config->minAlpha = 0.; - config->maxAlpha = 1.; - - /* Read attribute list */ - _XRead(dpy, (char *)attrs, (2*numAttribs * __GLX_SIZE_CARD32)); - - p = attrs; - for (j=0; jid = value; - break; - case GLX_BUFFER_SIZE: - config->indexBits = value; - break; - case GLX_LEVEL: - config->level = value; - break; - case GLX_DOUBLEBUFFER: - config->doubleBufferMode = value; - break; - case GLX_STEREO: - config->stereoMode = value; - break; - case GLX_AUX_BUFFERS: - config->maxAuxBuffers = value; - break; - case GLX_RED_SIZE: - config->redBits = value; - break; - case GLX_GREEN_SIZE: - config->greenBits = value; - break; - case GLX_BLUE_SIZE: - config->blueBits = value; - break; - case GLX_ALPHA_SIZE: - config->alphaBits = value; - break; - case GLX_DEPTH_SIZE: - config->depthBits = value; - break; - case GLX_STENCIL_SIZE: - config->stencilBits = value; - break; - case GLX_ACCUM_RED_SIZE: - config->accumRedBits = value; - break; - case GLX_ACCUM_GREEN_SIZE: - config->accumGreenBits = value; - break; - case GLX_ACCUM_BLUE_SIZE: - config->accumBlueBits = value; - break; - case GLX_ACCUM_ALPHA_SIZE: - config->accumAlphaBits = value; - break; - case GLX_RENDER_TYPE: - config->renderType = value; - break; - case GLX_DRAWABLE_TYPE: - config->drawableType = value; - break; - case GLX_X_VISUAL_TYPE: - config->visualType = value; - break; - case GLX_CONFIG_CAVEAT: - config->visualCaveat = value; - break; - case GLX_TRANSPARENT_TYPE: - config->transparentType = value; - break; - case GLX_TRANSPARENT_INDEX_VALUE: - config->transparentIndex = value; - break; - case GLX_TRANSPARENT_RED_VALUE: - config->transparentRed = value; - break; - case GLX_TRANSPARENT_GREEN_VALUE: - config->transparentGreen = value; - break; - case GLX_TRANSPARENT_BLUE_VALUE: - config->transparentBlue = value; - break; - case GLX_TRANSPARENT_ALPHA_VALUE: - config->transparentAlpha = value; - break; - case GLX_MAX_PBUFFER_WIDTH: - config->maxPbufferWidth = value; - break; - case GLX_MAX_PBUFFER_HEIGHT: - config->maxPbufferHeight = value; - break; - case GLX_MAX_PBUFFER_PIXELS: - config->maxPbufferPixels = value; - break; - case GLX_VISUAL_ID: - config->associatedVisualId = value; - break; - - /* visualSelectGroup is an internal used property */ - case GLX_VISUAL_SELECT_GROUP_SGIX: - config->visualSelectGroup = value; - break; - - /* SGIS_multisample attributes */ - case GLX_SAMPLES_SGIS: - config->multiSampleSize = value; - break; - case GLX_SAMPLE_BUFFERS_SGIS: - config->nMultiSampleBuffers = value; - break; - - /* SGIX_pbuffer specific attributes */ - case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: - config->optimalPbufferWidth = value; - break; - case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: - config->optimalPbufferHeight = value; - break; - - default: - /* Ignore attributes we don't recognize */ - break; - } - } /* for j */ - - /* Fill in derived values */ - config->screen = screen; - - config->rgbMode = config->renderType & GLX_RGBA_BIT; - config->colorIndexMode = !config->rgbMode; - - config->haveAccumBuffer = - config->accumRedBits > 0 || - config->accumGreenBits > 0 || - config->accumBlueBits > 0; - /* Can't have alpha without color */ - - config->haveDepthBuffer = config->depthBits > 0; - config->haveStencilBuffer = config->stencilBits > 0; - - /* overlay visuals are not valid for now */ - if (!config->level) { - config++; - numValidConfigs++; - } - - } /* for i */ - UnlockDisplay(dpy); - - config = fbconfigs; - for (i=0; iassociatedVisualId != 0) { - XVisualInfo *vis, template; - int n; - - template.screen = screen; - template.visualid = config->associatedVisualId; - vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask, - &template, &n); - - if (vis != NULL) { - config->redMask = (GLuint)vis->red_mask; - config->greenMask = (GLuint)vis->green_mask; - config->blueMask = (GLuint)vis->blue_mask; - config->alphaMask = 0; /* XXX */ - free(vis); - } - } - - config++; - } /* for i */ - - XFree(attrs); - SyncHandle(); - - *nconfigs = numValidConfigs; - return fbconfigs; -} - -__GLXvisualConfig * -GetGLXVisualConfigsFromFBConfigs(__GLXFBConfig *fbconfigs, int nfbconfigs, - XVisualInfo *visuals, int nvisuals, - __GLXvisualConfig *glxConfigs, int nGlxConfigs, - int *nconfigs) -{ - __GLXvisualConfig *configs = NULL; - int i; - - if (!fbconfigs || !nfbconfigs || !nconfigs) return(NULL); - *nconfigs = 0; - - /* Allocate memory for our config structure */ - configs = (__GLXvisualConfig*) - Xmalloc(nfbconfigs * sizeof(__GLXvisualConfig)); - if (!configs) { - return NULL; - } - memset(configs, 0, nfbconfigs * sizeof(__GLXvisualConfig)); - - for (i=0; iassociatedVisualId > 0) { - __GLXvisualConfig *cfg = configs + (*nconfigs); - int j; - XVisualInfo *vinfo = NULL; - - for (j=0; jassociatedVisualId) { - vinfo = &visuals[j]; - break; - } - } - if (!vinfo) continue; - - /* skip 16 bit colormap visuals */ - if (vinfo->depth == 16 && - vinfo->class != TrueColor && - vinfo->class != DirectColor ) { - continue; - } - - (*nconfigs)++; - - /* - * if the same visualid exists in the glx configs, - * copy the glx attributes from the glx config - */ - for (j=0; jvisualid) - break; - } - if (j < nGlxConfigs) { - memcpy(cfg, &glxConfigs[j], sizeof(__GLXvisualConfig) ); - continue; - } - - /* - * make glx attributes from the FB config attributes - */ - cfg->vid = fbcfg->associatedVisualId; - cfg->class = vinfo->class; - cfg->rgba = !(fbcfg->renderType & GLX_COLOR_INDEX_BIT_SGIX); - cfg->redSize = fbcfg->redBits; - cfg->greenSize = fbcfg->greenBits; - cfg->blueSize = fbcfg->blueBits; - cfg->alphaSize = fbcfg->alphaBits; - cfg->redMask = fbcfg->redMask; - cfg->greenMask = fbcfg->greenMask; - cfg->blueMask = fbcfg->blueMask; - cfg->alphaMask = fbcfg->alphaMask; - cfg->accumRedSize = fbcfg->accumRedBits; - cfg->accumGreenSize = fbcfg->accumGreenBits; - cfg->accumBlueSize = fbcfg->accumBlueBits; - cfg->accumAlphaSize = fbcfg->accumAlphaBits; - cfg->doubleBuffer = fbcfg->doubleBufferMode; - cfg->stereo = fbcfg->stereoMode; - if (vinfo->class == TrueColor || vinfo->class == DirectColor) { - cfg->bufferSize = (fbcfg->rgbMode ? (fbcfg->redBits + - fbcfg->greenBits + - fbcfg->blueBits + - fbcfg->alphaBits) - : fbcfg->indexBits ); - } - else { - cfg->bufferSize = vinfo->depth; - } - cfg->depthSize = fbcfg->depthBits; - cfg->stencilSize = fbcfg->stencilBits; - cfg->auxBuffers = fbcfg->maxAuxBuffers; - cfg->level = fbcfg->level; - cfg->visualRating = fbcfg->visualCaveat; - cfg->transparentPixel = fbcfg->transparentType; - cfg->transparentRed = fbcfg->transparentRed; - cfg->transparentGreen = fbcfg->transparentGreen; - cfg->transparentBlue = fbcfg->transparentBlue; - cfg->transparentAlpha = fbcfg->transparentAlpha; - cfg->transparentIndex = fbcfg->transparentIndex; - cfg->multiSampleSize = fbcfg->multiSampleSize; - cfg->nMultiSampleBuffers = fbcfg->nMultiSampleBuffers; - cfg->visualSelectGroup = fbcfg->visualSelectGroup; - } - } - - return( configs ); -} - +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include +#include +#include +#include + +#include "dmx_glxvisuals.h" + +__GLXvisualConfig *GetGLXVisualConfigs(Display *dpy, int screen, int *nconfigs) +{ + xGLXGetVisualConfigsReq *req; + xGLXGetVisualConfigsReply reply; + __GLXvisualConfig *config, *configs; + GLint i, j, nvisuals, nprops; + INT32 *props, *p; + int majorOpcode, dummy; + int num_good_visuals; + + if (!XQueryExtension(dpy, "GLX", &majorOpcode, &dummy, &dummy)) { + return(NULL); + } + + /* Send the glXGetVisualConfigs request */ + LockDisplay(dpy); + GetReq(GLXGetVisualConfigs,req); + req->reqType = majorOpcode; + req->glxCode = X_GLXGetVisualConfigs; + req->screen = screen; + if (!_XReply(dpy, (xReply*) &reply, 0, False)) { + /* Something is busted. Punt. */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + nvisuals = (int)reply.numVisuals; + if (!nvisuals) { + /* This screen does not support GL rendering */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + /* Check number of properties per visual */ + nprops = (int)reply.numProps; + if (nprops < __GLX_MIN_CONFIG_PROPS) { + /* Huh? Not in protocol defined limits. Punt */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + props = (INT32*) Xmalloc(nprops * __GLX_SIZE_CARD32); + if (!props) { + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + /* Allocate memory for our config structure */ + config = (__GLXvisualConfig*) + Xmalloc(nvisuals * sizeof(__GLXvisualConfig)); + if (!config) { + free(props); + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + memset(config, 0, nvisuals * sizeof(__GLXvisualConfig)); + configs = config; + num_good_visuals = 0; + + /* Convert config structure into our format */ + for (i=0; ivisualRating = GLX_NONE_EXT; + config->transparentPixel = GLX_NONE_EXT; + + /* Copy in the first set of properties */ + config->vid = props[0]; + config->class = props[1]; + + config->rgba = (Bool) props[2]; + + config->redSize = props[3]; + config->greenSize = props[4]; + config->blueSize = props[5]; + config->alphaSize = props[6]; + + config->accumRedSize = props[7]; + config->accumGreenSize = props[8]; + config->accumBlueSize = props[9]; + config->accumAlphaSize = props[10]; + + config->doubleBuffer = (Bool) props[11]; + config->stereo = (Bool) props[12]; + + config->bufferSize = props[13]; + config->depthSize = props[14]; + config->stencilSize = props[15]; + + config->auxBuffers = props[16]; + config->level = props[17]; + + /* Process remaining properties */ + p = &props[18]; + for (j=__GLX_MIN_CONFIG_PROPS; jmultiSampleSize = value; + break; + case GLX_SAMPLE_BUFFERS_SGIS: + config->nMultiSampleBuffers = value; + break; + + case GLX_TRANSPARENT_TYPE_EXT: + config->transparentPixel = value; + break; + case GLX_TRANSPARENT_INDEX_VALUE_EXT: + config->transparentIndex = value; + break; + case GLX_TRANSPARENT_RED_VALUE_EXT: + config->transparentRed = value; + break; + case GLX_TRANSPARENT_GREEN_VALUE_EXT: + config->transparentGreen = value; + break; + case GLX_TRANSPARENT_BLUE_VALUE_EXT: + config->transparentBlue = value; + break; + case GLX_TRANSPARENT_ALPHA_VALUE_EXT: + config->transparentAlpha = value; + break; + + case GLX_VISUAL_CAVEAT_EXT: + config->visualRating = value; + break; + + /* visualSelectGroup is an internal used property */ + case GLX_VISUAL_SELECT_GROUP_SGIX: + config->visualSelectGroup = value; + break; + + default : + /* Ignore properties we don't recognize */ + break; + } + } /* for j */ + + /* + // filter out overlay visuals (dmx does not support overlays) + */ + if (config->level == 0) { + config++; + num_good_visuals++; + } + + } /* for i */ + + UnlockDisplay(dpy); + + nvisuals = num_good_visuals; + + config = configs; + for (i=0; ivid; + vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask, + &template, &n); + + if (vis != NULL) { + config->redMask = vis->red_mask; + config->greenMask = vis->green_mask; + config->blueMask = vis->blue_mask; + config->alphaMask = 0; /* XXX */ + free(vis); + } + } + config++; + } /* for i */ + + XFree(props); + SyncHandle(); + + *nconfigs = nvisuals; + return( configs ); +} + + +__GLXFBConfig *GetGLXFBConfigs(Display *dpy, int glxMajorOpcode, int *nconfigs) +{ + xGLXGetFBConfigsReq *req; + xGLXGetFBConfigsReply reply; + __GLXFBConfig *config, *fbconfigs; + GLint i, j, numFBConfigs, numAttribs; + INT32 *attrs, *p; + int screen = DefaultScreen( dpy ); + int numValidConfigs = 0; + + /* Send the glXGetFBConfigs request */ + LockDisplay(dpy); + GetReq(GLXGetFBConfigs, req); + req->reqType = glxMajorOpcode; + req->glxCode = X_GLXGetFBConfigs; + req->screen = screen; + + *nconfigs = 0; + + if (!_XReply(dpy, (xReply*) &reply, 0, False)) { + /* Something is busted. Punt. */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + numFBConfigs = (int)reply.numFBConfigs; + if (!numFBConfigs) { + /* This screen does not support GL rendering */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + numAttribs = (int)reply.numAttribs; + if (!numAttribs) { + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + attrs = (INT32*) Xmalloc(2*numAttribs * __GLX_SIZE_CARD32); + if (!attrs) { + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + /* Allocate memory for our config structure */ + config = (__GLXFBConfig*) + Xmalloc(numFBConfigs * sizeof(__GLXFBConfig)); + if (!config) { + free(attrs); + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + memset(config, 0, numFBConfigs * sizeof(__GLXFBConfig)); + fbconfigs = config; + + /* Convert attribute list into our format */ + for (i=0; itransparentType = GLX_NONE_EXT; + config->visualCaveat = GLX_NONE_EXT; + config->minRed = 0.; + config->maxRed = 1.; + config->minGreen = 0.; + config->maxGreen = 1.; + config->minBlue = 0.; + config->maxBlue = 1.; + config->minAlpha = 0.; + config->maxAlpha = 1.; + + /* Read attribute list */ + _XRead(dpy, (char *)attrs, (2*numAttribs * __GLX_SIZE_CARD32)); + + p = attrs; + for (j=0; jid = value; + break; + case GLX_BUFFER_SIZE: + config->indexBits = value; + break; + case GLX_LEVEL: + config->level = value; + break; + case GLX_DOUBLEBUFFER: + config->doubleBufferMode = value; + break; + case GLX_STEREO: + config->stereoMode = value; + break; + case GLX_AUX_BUFFERS: + config->maxAuxBuffers = value; + break; + case GLX_RED_SIZE: + config->redBits = value; + break; + case GLX_GREEN_SIZE: + config->greenBits = value; + break; + case GLX_BLUE_SIZE: + config->blueBits = value; + break; + case GLX_ALPHA_SIZE: + config->alphaBits = value; + break; + case GLX_DEPTH_SIZE: + config->depthBits = value; + break; + case GLX_STENCIL_SIZE: + config->stencilBits = value; + break; + case GLX_ACCUM_RED_SIZE: + config->accumRedBits = value; + break; + case GLX_ACCUM_GREEN_SIZE: + config->accumGreenBits = value; + break; + case GLX_ACCUM_BLUE_SIZE: + config->accumBlueBits = value; + break; + case GLX_ACCUM_ALPHA_SIZE: + config->accumAlphaBits = value; + break; + case GLX_RENDER_TYPE: + config->renderType = value; + break; + case GLX_DRAWABLE_TYPE: + config->drawableType = value; + break; + case GLX_X_VISUAL_TYPE: + config->visualType = value; + break; + case GLX_CONFIG_CAVEAT: + config->visualCaveat = value; + break; + case GLX_TRANSPARENT_TYPE: + config->transparentType = value; + break; + case GLX_TRANSPARENT_INDEX_VALUE: + config->transparentIndex = value; + break; + case GLX_TRANSPARENT_RED_VALUE: + config->transparentRed = value; + break; + case GLX_TRANSPARENT_GREEN_VALUE: + config->transparentGreen = value; + break; + case GLX_TRANSPARENT_BLUE_VALUE: + config->transparentBlue = value; + break; + case GLX_TRANSPARENT_ALPHA_VALUE: + config->transparentAlpha = value; + break; + case GLX_MAX_PBUFFER_WIDTH: + config->maxPbufferWidth = value; + break; + case GLX_MAX_PBUFFER_HEIGHT: + config->maxPbufferHeight = value; + break; + case GLX_MAX_PBUFFER_PIXELS: + config->maxPbufferPixels = value; + break; + case GLX_VISUAL_ID: + config->associatedVisualId = value; + break; + + /* visualSelectGroup is an internal used property */ + case GLX_VISUAL_SELECT_GROUP_SGIX: + config->visualSelectGroup = value; + break; + + /* SGIS_multisample attributes */ + case GLX_SAMPLES_SGIS: + config->multiSampleSize = value; + break; + case GLX_SAMPLE_BUFFERS_SGIS: + config->nMultiSampleBuffers = value; + break; + + /* SGIX_pbuffer specific attributes */ + case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: + config->optimalPbufferWidth = value; + break; + case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: + config->optimalPbufferHeight = value; + break; + + default: + /* Ignore attributes we don't recognize */ + break; + } + } /* for j */ + + /* Fill in derived values */ + config->screen = screen; + + config->rgbMode = config->renderType & GLX_RGBA_BIT; + config->colorIndexMode = !config->rgbMode; + + config->haveAccumBuffer = + config->accumRedBits > 0 || + config->accumGreenBits > 0 || + config->accumBlueBits > 0; + /* Can't have alpha without color */ + + config->haveDepthBuffer = config->depthBits > 0; + config->haveStencilBuffer = config->stencilBits > 0; + + /* overlay visuals are not valid for now */ + if (!config->level) { + config++; + numValidConfigs++; + } + + } /* for i */ + UnlockDisplay(dpy); + + config = fbconfigs; + for (i=0; iassociatedVisualId != 0) { + XVisualInfo *vis, template; + int n; + + template.screen = screen; + template.visualid = config->associatedVisualId; + vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask, + &template, &n); + + if (vis != NULL) { + config->redMask = (GLuint)vis->red_mask; + config->greenMask = (GLuint)vis->green_mask; + config->blueMask = (GLuint)vis->blue_mask; + config->alphaMask = 0; /* XXX */ + free(vis); + } + } + + config++; + } /* for i */ + + XFree(attrs); + SyncHandle(); + + *nconfigs = numValidConfigs; + return fbconfigs; +} + +__GLXvisualConfig * +GetGLXVisualConfigsFromFBConfigs(__GLXFBConfig *fbconfigs, int nfbconfigs, + XVisualInfo *visuals, int nvisuals, + __GLXvisualConfig *glxConfigs, int nGlxConfigs, + int *nconfigs) +{ + __GLXvisualConfig *configs = NULL; + int i; + + if (!fbconfigs || !nfbconfigs || !nconfigs) return(NULL); + *nconfigs = 0; + + /* Allocate memory for our config structure */ + configs = (__GLXvisualConfig*) + Xmalloc(nfbconfigs * sizeof(__GLXvisualConfig)); + if (!configs) { + return NULL; + } + memset(configs, 0, nfbconfigs * sizeof(__GLXvisualConfig)); + + for (i=0; iassociatedVisualId > 0) { + __GLXvisualConfig *cfg = configs + (*nconfigs); + int j; + XVisualInfo *vinfo = NULL; + + for (j=0; jassociatedVisualId) { + vinfo = &visuals[j]; + break; + } + } + if (!vinfo) continue; + + /* skip 16 bit colormap visuals */ + if (vinfo->depth == 16 && + vinfo->class != TrueColor && + vinfo->class != DirectColor ) { + continue; + } + + (*nconfigs)++; + + /* + * if the same visualid exists in the glx configs, + * copy the glx attributes from the glx config + */ + for (j=0; jvisualid) + break; + } + if (j < nGlxConfigs) { + memcpy(cfg, &glxConfigs[j], sizeof(__GLXvisualConfig) ); + continue; + } + + /* + * make glx attributes from the FB config attributes + */ + cfg->vid = fbcfg->associatedVisualId; + cfg->class = vinfo->class; + cfg->rgba = !(fbcfg->renderType & GLX_COLOR_INDEX_BIT_SGIX); + cfg->redSize = fbcfg->redBits; + cfg->greenSize = fbcfg->greenBits; + cfg->blueSize = fbcfg->blueBits; + cfg->alphaSize = fbcfg->alphaBits; + cfg->redMask = fbcfg->redMask; + cfg->greenMask = fbcfg->greenMask; + cfg->blueMask = fbcfg->blueMask; + cfg->alphaMask = fbcfg->alphaMask; + cfg->accumRedSize = fbcfg->accumRedBits; + cfg->accumGreenSize = fbcfg->accumGreenBits; + cfg->accumBlueSize = fbcfg->accumBlueBits; + cfg->accumAlphaSize = fbcfg->accumAlphaBits; + cfg->doubleBuffer = fbcfg->doubleBufferMode; + cfg->stereo = fbcfg->stereoMode; + if (vinfo->class == TrueColor || vinfo->class == DirectColor) { + cfg->bufferSize = (fbcfg->rgbMode ? (fbcfg->redBits + + fbcfg->greenBits + + fbcfg->blueBits + + fbcfg->alphaBits) + : fbcfg->indexBits ); + } + else { + cfg->bufferSize = vinfo->depth; + } + cfg->depthSize = fbcfg->depthBits; + cfg->stencilSize = fbcfg->stencilBits; + cfg->auxBuffers = fbcfg->maxAuxBuffers; + cfg->level = fbcfg->level; + cfg->visualRating = fbcfg->visualCaveat; + cfg->transparentPixel = fbcfg->transparentType; + cfg->transparentRed = fbcfg->transparentRed; + cfg->transparentGreen = fbcfg->transparentGreen; + cfg->transparentBlue = fbcfg->transparentBlue; + cfg->transparentAlpha = fbcfg->transparentAlpha; + cfg->transparentIndex = fbcfg->transparentIndex; + cfg->multiSampleSize = fbcfg->multiSampleSize; + cfg->nMultiSampleBuffers = fbcfg->nMultiSampleBuffers; + cfg->visualSelectGroup = fbcfg->visualSelectGroup; + } + } + + return( configs ); +} + diff --git a/xorg-server/hw/dmx/dmxcmap.c b/xorg-server/hw/dmx/dmxcmap.c index 4aa586aff..5a56afda2 100644 --- a/xorg-server/hw/dmx/dmxcmap.c +++ b/xorg-server/hw/dmx/dmxcmap.c @@ -1,212 +1,212 @@ -/* - * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Kevin E. Martin - * - */ - -/** \file - * Colormap support. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxlog.h" -#include "dmxsync.h" -#include "dmxcmap.h" -#include "dmxvisual.h" - -#include "micmap.h" - -static Bool dmxAllocateColormapPrivates(ColormapPtr pColormap) -{ - dmxColormapPrivPtr pCmapPriv; - - pCmapPriv = (dmxColormapPrivPtr)xalloc(sizeof(*pCmapPriv)); - if (!pCmapPriv) - return FALSE; - pCmapPriv->cmap = (Colormap)0; - - DMX_SET_COLORMAP_PRIV(pColormap, pCmapPriv); - - return TRUE; -} - -/** Create \a pColormap on the back-end server. */ -Bool dmxBECreateColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - VisualPtr pVisual = pColormap->pVisual; - Visual *visual = dmxLookupVisual(pScreen, pVisual); - - if (visual) { - pCmapPriv->cmap = XCreateColormap(dmxScreen->beDisplay, - dmxScreen->scrnWin, - visual, - (pVisual->class & DynamicClass ? - AllocAll : AllocNone)); - return (pCmapPriv->cmap != 0); - } - else { - dmxLog(dmxWarning, "dmxBECreateColormap: No visual found\n"); - return 0; - } -} - -/** Create colormap on back-end server associated with \a pColormap's - * screen. */ -Bool dmxCreateColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - - if (!dmxAllocateColormapPrivates(pColormap)) - return FALSE; - - if (dmxScreen->beDisplay) { - if (!dmxBECreateColormap(pColormap)) - return FALSE; - } - - DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); - if (pScreen->CreateColormap) - ret = pScreen->CreateColormap(pColormap); - DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); - - return ret; -} - -/** Destroy \a pColormap on the back-end server. */ -Bool dmxBEFreeColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - - if (pCmapPriv->cmap) { - XFreeColormap(dmxScreen->beDisplay, pCmapPriv->cmap); - pCmapPriv->cmap = (Colormap)0; - return TRUE; - } - - return FALSE; -} - -/** Destroy colormap on back-end server associated with \a pColormap's - * screen. */ -void dmxDestroyColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - - if (dmxScreen->beDisplay) - dmxBEFreeColormap(pColormap); - xfree(pCmapPriv); - DMX_SET_COLORMAP_PRIV(pColormap, NULL); - - DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); - if (pScreen->DestroyColormap) - pScreen->DestroyColormap(pColormap); - DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); -} - -/** Install colormap on back-end server associated with \a pColormap's - * screen. */ -void dmxInstallColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - - DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); - if (pScreen->InstallColormap) - pScreen->InstallColormap(pColormap); - DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); - - if (dmxScreen->beDisplay) { - XInstallColormap(dmxScreen->beDisplay, pCmapPriv->cmap); - dmxSync(dmxScreen, FALSE); - } -} - -/** Store colors in \a pColormap on back-end server associated with \a - * pColormap's screen. */ -void dmxStoreColors(ColormapPtr pColormap, int ndef, xColorItem *pdef) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - - if (dmxScreen->beDisplay && (pColormap->pVisual->class & DynamicClass)) { - XColor *color = xalloc(sizeof(*color) * ndef); - int i; - - if (color) { - for (i = 0; i < ndef; i++) { - color[i].pixel = pdef[i].pixel; - color[i].red = pdef[i].red; - color[i].blue = pdef[i].blue; - color[i].green = pdef[i].green; - color[i].flags = pdef[i].flags; - color[i].pad = pdef[i].pad; - } - XStoreColors(dmxScreen->beDisplay, pCmapPriv->cmap, color, ndef); - xfree(color); - } else { /* xalloc failed, so fallback */ - XColor c; - for (i = 0; i < ndef; i++) { - c.pixel = pdef[i].pixel; - c.red = pdef[i].red; - c.blue = pdef[i].blue; - c.green = pdef[i].green; - c.flags = pdef[i].flags; - c.pad = pdef[i].pad; - XStoreColor(dmxScreen->beDisplay, pCmapPriv->cmap, &c); - } - } - dmxSync(dmxScreen, FALSE); - } - - DMX_UNWRAP(StoreColors, dmxScreen, pScreen); - if (pScreen->StoreColors) - pScreen->StoreColors(pColormap, ndef, pdef); - DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); -} - -/** Create the DMX server's default colormap. */ -Bool dmxCreateDefColormap(ScreenPtr pScreen) -{ - return miCreateDefColormap(pScreen); -} +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Kevin E. Martin + * + */ + +/** \file + * Colormap support. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxlog.h" +#include "dmxsync.h" +#include "dmxcmap.h" +#include "dmxvisual.h" + +#include "micmap.h" + +static Bool dmxAllocateColormapPrivates(ColormapPtr pColormap) +{ + dmxColormapPrivPtr pCmapPriv; + + pCmapPriv = (dmxColormapPrivPtr)malloc(sizeof(*pCmapPriv)); + if (!pCmapPriv) + return FALSE; + pCmapPriv->cmap = (Colormap)0; + + DMX_SET_COLORMAP_PRIV(pColormap, pCmapPriv); + + return TRUE; +} + +/** Create \a pColormap on the back-end server. */ +Bool dmxBECreateColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + VisualPtr pVisual = pColormap->pVisual; + Visual *visual = dmxLookupVisual(pScreen, pVisual); + + if (visual) { + pCmapPriv->cmap = XCreateColormap(dmxScreen->beDisplay, + dmxScreen->scrnWin, + visual, + (pVisual->class & DynamicClass ? + AllocAll : AllocNone)); + return (pCmapPriv->cmap != 0); + } + else { + dmxLog(dmxWarning, "dmxBECreateColormap: No visual found\n"); + return 0; + } +} + +/** Create colormap on back-end server associated with \a pColormap's + * screen. */ +Bool dmxCreateColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + + if (!dmxAllocateColormapPrivates(pColormap)) + return FALSE; + + if (dmxScreen->beDisplay) { + if (!dmxBECreateColormap(pColormap)) + return FALSE; + } + + DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); + if (pScreen->CreateColormap) + ret = pScreen->CreateColormap(pColormap); + DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); + + return ret; +} + +/** Destroy \a pColormap on the back-end server. */ +Bool dmxBEFreeColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + + if (pCmapPriv->cmap) { + XFreeColormap(dmxScreen->beDisplay, pCmapPriv->cmap); + pCmapPriv->cmap = (Colormap)0; + return TRUE; + } + + return FALSE; +} + +/** Destroy colormap on back-end server associated with \a pColormap's + * screen. */ +void dmxDestroyColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + + if (dmxScreen->beDisplay) + dmxBEFreeColormap(pColormap); + free(pCmapPriv); + DMX_SET_COLORMAP_PRIV(pColormap, NULL); + + DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); + if (pScreen->DestroyColormap) + pScreen->DestroyColormap(pColormap); + DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); +} + +/** Install colormap on back-end server associated with \a pColormap's + * screen. */ +void dmxInstallColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + + DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); + if (pScreen->InstallColormap) + pScreen->InstallColormap(pColormap); + DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); + + if (dmxScreen->beDisplay) { + XInstallColormap(dmxScreen->beDisplay, pCmapPriv->cmap); + dmxSync(dmxScreen, FALSE); + } +} + +/** Store colors in \a pColormap on back-end server associated with \a + * pColormap's screen. */ +void dmxStoreColors(ColormapPtr pColormap, int ndef, xColorItem *pdef) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + + if (dmxScreen->beDisplay && (pColormap->pVisual->class & DynamicClass)) { + XColor *color = malloc(sizeof(*color) * ndef); + int i; + + if (color) { + for (i = 0; i < ndef; i++) { + color[i].pixel = pdef[i].pixel; + color[i].red = pdef[i].red; + color[i].blue = pdef[i].blue; + color[i].green = pdef[i].green; + color[i].flags = pdef[i].flags; + color[i].pad = pdef[i].pad; + } + XStoreColors(dmxScreen->beDisplay, pCmapPriv->cmap, color, ndef); + free(color); + } else { /* xalloc failed, so fallback */ + XColor c; + for (i = 0; i < ndef; i++) { + c.pixel = pdef[i].pixel; + c.red = pdef[i].red; + c.blue = pdef[i].blue; + c.green = pdef[i].green; + c.flags = pdef[i].flags; + c.pad = pdef[i].pad; + XStoreColor(dmxScreen->beDisplay, pCmapPriv->cmap, &c); + } + } + dmxSync(dmxScreen, FALSE); + } + + DMX_UNWRAP(StoreColors, dmxScreen, pScreen); + if (pScreen->StoreColors) + pScreen->StoreColors(pColormap, ndef, pdef); + DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); +} + +/** Create the DMX server's default colormap. */ +Bool dmxCreateDefColormap(ScreenPtr pScreen) +{ + return miCreateDefColormap(pScreen); +} diff --git a/xorg-server/hw/dmx/dmxcursor.c b/xorg-server/hw/dmx/dmxcursor.c index 37e66d758..2d0243343 100644 --- a/xorg-server/hw/dmx/dmxcursor.c +++ b/xorg-server/hw/dmx/dmxcursor.c @@ -1,985 +1,985 @@ -/* - * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * David H. Dawes - * Kevin E. Martin - * Rickard E. (Rik) Faith - * - */ - -/** \file - * This file contains code than supports cursor movement, including the - * code that initializes and reinitializes the screen positions and - * computes screen overlap. - * - * "This code is based very closely on the XFree86 equivalent - * (xfree86/common/xf86Cursor.c)." --David Dawes. - * - * "This code was then extensively re-written, as explained here." - * --Rik Faith - * - * The code in xf86Cursor.c used edge lists to implement the - * CursorOffScreen function. The edge list computation was complex - * (especially in the face of arbitrarily overlapping screens) compared - * with the speed savings in the CursorOffScreen function. The new - * implementation has erred on the side of correctness, readability, and - * maintainability over efficiency. For the common (non-edge) case, the - * dmxCursorOffScreen function does avoid a loop over all the screens. - * When the cursor has left the screen, all the screens are searched, - * and the first screen (in dmxScreens order) containing the cursor will - * be returned. If run-time profiling shows that this routing is a - * performance bottle-neck, then an edge list may have to be - * reimplemented. An edge list algorithm is O(edges) whereas the new - * algorithm is O(dmxNumScreens). Since edges is usually 1-3 and - * dmxNumScreens may be 30-60 for large backend walls, this trade off - * may be compelling. - * - * The xf86InitOrigins routine uses bit masks during the computation and - * is therefore limited to the length of a word (e.g., 32 or 64 bits) - * screens. Because Xdmx is expected to be used with a large number of - * backend displays, this limitation was removed. The new - * implementation has erred on the side of readability over efficiency, - * using the dmxSL* routines to manage a screen list instead of a - * bitmap, and a function call to decrease the length of the main - * routine. Both algorithms are of the same order, and both are called - * only at server generation time, so trading clarity and long-term - * maintainability for efficiency does not seem justified in this case. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#define DMX_CURSOR_DEBUG 0 - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxcursor.h" -#include "dmxlog.h" -#include "dmxprop.h" -#include "dmxinput.h" - -#include "mipointer.h" -#include "windowstr.h" -#include "globals.h" -#include "cursorstr.h" -#include "dixevents.h" /* For GetSpriteCursor() */ -#include "inputstr.h" /* for inputInfo.pointer */ - -#if DMX_CURSOR_DEBUG -#define DMXDBG0(f) dmxLog(dmxDebug,f) -#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) -#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) -#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) -#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) -#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) -#else -#define DMXDBG0(f) -#define DMXDBG1(f,a) -#define DMXDBG2(f,a,b) -#define DMXDBG3(f,a,b,c) -#define DMXDBG4(f,a,b,c,d) -#define DMXDBG5(f,a,b,c,d,e) -#define DMXDBG6(f,a,b,c,d,e,g) -#define DMXDBG7(f,a,b,c,d,e,g,h) -#endif - -static int dmxCursorDoMultiCursors = 1; - -/** Turn off support for displaying multiple cursors on overlapped - back-end displays. See #dmxCursorDoMultiCursors. */ -void dmxCursorNoMulti(void) -{ - dmxCursorDoMultiCursors = 0; -} - -static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) -{ - DMXScreenInfo *dmxScreen; - int i; - int localX = *x; - int localY = *y; - int globalX; - int globalY; - - if (screenInfo.numScreens == 1) - return FALSE; - - /* On current screen? */ - dmxScreen = &dmxScreens[(*ppScreen)->myNum]; - if (localX >= 0 - && localX < dmxScreen->rootWidth - && localY >= 0 - && localY < dmxScreen->rootHeight) - return FALSE; - - /* Convert to global coordinate space */ - globalX = dmxScreen->rootXOrigin + localX; - globalY = dmxScreen->rootYOrigin + localY; - - /* Is cursor on the current screen? - * This efficiently exits this routine - * for the most common case. */ - if (ppScreen && *ppScreen) { - dmxScreen = &dmxScreens[(*ppScreen)->myNum]; - if (globalX >= dmxScreen->rootXOrigin - && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth - && globalY >= dmxScreen->rootYOrigin - && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) - return FALSE; - } - - /* Find first screen cursor is on */ - for (i = 0; i < dmxNumScreens; i++) { - dmxScreen = &dmxScreens[i]; - if (globalX >= dmxScreen->rootXOrigin - && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth - && globalY >= dmxScreen->rootYOrigin - && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) { - if (dmxScreen->index == (*ppScreen)->myNum) - return FALSE; - *ppScreen = screenInfo.screens[dmxScreen->index]; - *x = globalX - dmxScreen->rootXOrigin; - *y = globalY - dmxScreen->rootYOrigin; - return TRUE; - } - } - return FALSE; -} - -static void dmxCrossScreen(ScreenPtr pScreen, Bool entering) -{ -} - -static void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y); -#if 11 /*BP*/ - /* This call is depracated. Replace with???? */ - miPointerWarpCursor(pDev, pScreen, x, y); -#else - pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE); -#endif -} - -miPointerScreenFuncRec dmxPointerCursorFuncs = -{ - dmxCursorOffScreen, - dmxCrossScreen, - dmxWarpCursor, - NULL, - NULL, -}; - - -/** Create a list of screens that we'll manipulate. */ -static int *dmxSLCreate(void) -{ - int *list = malloc(dmxNumScreens * sizeof(*list)); - int i; - - for (i = 0; i < dmxNumScreens; i++) - list[i] = 1; - return list; -} - -/** Free list. */ -static void dmxSLFree(int *list) -{ - free(list); -} - -/** Find next uninitialized entry in list. */ -static int dmxSLFindNext(int *list) -{ - int i; - for (i = 0; i < dmxNumScreens; i++) - if (list[i]) - return i; - return -1; -} - -/** Make one pass over all the screens and return the number updated. */ -static int dmxTryComputeScreenOrigins(int *screensLeft) -{ - ScreenPtr pScreen; - DMXScreenInfo *screen; - int i, ref; - int changed = 0; - - for (i = 0; i < dmxNumScreens; i++) { - if (!screensLeft[i]) - continue; - screen = &dmxScreens[i]; - switch (screen->where) { - case PosAbsolute: - dixScreenOrigins[i].x = screen->whereX; - dixScreenOrigins[i].y = screen->whereY; - ++changed, screensLeft[i] = 0; - break; - case PosRelative: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->whereX; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->whereY; - ++changed, screensLeft[i] = 0; - break; - case PosRightOf: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[ref]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x + pScreen->width; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y; - ++changed, screensLeft[i] = 0; - break; - case PosLeftOf: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[i]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x - pScreen->width; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y; - ++changed, screensLeft[i] = 0; - break; - case PosBelow: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[ref]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y + pScreen->height; - ++changed, screensLeft[i] = 0; - break; - case PosAbove: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[i]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y - pScreen->height; - ++changed, screensLeft[i] = 0; - break; - case PosNone: - dmxLog(dmxFatal, "No position information for screen %d\n", i); - } - } - return changed; -} - -static void dmxComputeScreenOrigins(void) -{ - int *screensLeft; - int i, ref; - int minX, minY; - - /* Compute origins based on - * configuration information. */ - screensLeft = dmxSLCreate(); - while ((i = dmxSLFindNext(screensLeft)) >= 0) { - while (dmxTryComputeScreenOrigins(screensLeft)); - if ((i = dmxSLFindNext(screensLeft)) >= 0) { - /* All of the remaining screens are referencing each other. - * Assign a value to one of them and go through again. This - * guarantees that we will eventually terminate. - */ - ref = dmxScreens[i].whereRefScreen; - dixScreenOrigins[ref].x = dixScreenOrigins[ref].y = 0; - screensLeft[ref] = 0; - } - } - dmxSLFree(screensLeft); - - - /* Justify the topmost and leftmost to - * (0,0). */ - minX = dixScreenOrigins[0].x; - minY = dixScreenOrigins[0].y; - for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */ - if (dixScreenOrigins[i].x < minX) - minX = dixScreenOrigins[i].x; - if (dixScreenOrigins[i].y < minY) - minY = dixScreenOrigins[i].y; - } - if (minX || minY) { - for (i = 0; i < dmxNumScreens; i++) { - dixScreenOrigins[i].x -= minX; - dixScreenOrigins[i].y -= minY; - } - } -} - -/** Recompute origin information in the #dmxScreens list. This is - * called from #dmxInitOrigins. */ -void dmxReInitOrigins(void) -{ - int i; - - if (dmxNumScreens > MAXSCREENS) - dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", - dmxNumScreens, MAXSCREENS); - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - dmxLogOutput(dmxScreen, - "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d" - " (be=%dx%d depth=%d bpp=%d)\n", - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, - - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - - dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, - dmxScreen->beWidth, dmxScreen->beHeight, - dmxScreen->beDepth, dmxScreen->beBPP); - } -} - -/** Initialize screen origins (and relative position). This is called - * for each server generation. For dynamic reconfiguration, use - * #dmxReInitOrigins() instead. */ -void dmxInitOrigins(void) -{ - int i; - - if (dmxNumScreens > MAXSCREENS) - dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", - dmxNumScreens, MAXSCREENS); - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - dmxLogOutput(dmxScreen, - "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)" - " (be=%dx%d depth=%d bpp=%d)\n", - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, - - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - - dmxScreen->whereX, dmxScreen->whereY, - dmxScreen->where, - - dmxScreen->beWidth, dmxScreen->beHeight, - dmxScreen->beDepth, dmxScreen->beBPP); - } - - dmxComputeScreenOrigins(); - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - dmxScreen->rootXOrigin = dixScreenOrigins[i].x; - dmxScreen->rootYOrigin = dixScreenOrigins[i].y; - } - - dmxReInitOrigins(); -} - -/** Returns non-zero if the global \a x, \a y coordinate is on the - * screen window of the \a dmxScreen. */ -int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen) -{ -#if DMX_CURSOR_DEBUG > 1 - dmxLog(dmxDebug, - "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n", - dmxScreen->index, x, y, - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY); -#endif - if (x >= dmxScreen->rootXOrigin - && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth - && y >= dmxScreen->rootYOrigin - && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1; - return 0; -} - -/** Returns non-zero if \a a overlaps \a b. */ -static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b) -{ - if (dmxOnScreen(a->rootXOrigin, - a->rootYOrigin, b)) - return 1; - - if (dmxOnScreen(a->rootXOrigin, - a->rootYOrigin + a->scrnWidth, b)) - return 1; - - if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, - a->rootYOrigin, b)) - return 1; - - if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, - a->rootYOrigin + a->scrnWidth, b)) - return 1; - - if (dmxOnScreen(b->rootXOrigin, - b->rootYOrigin, a)) - return 1; - - if (dmxOnScreen(b->rootXOrigin, - b->rootYOrigin + b->scrnWidth, a)) - return 1; - - if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, - b->rootYOrigin, a)) - return 1; - - if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, - b->rootYOrigin + b->scrnWidth, a)) - return 1; - - return 0; -} - -/** Used with \a dmxInterateOverlap to print out a list of screens which - * overlap each other. */ -static void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure) -{ - DMXScreenInfo *a = closure; - if (dmxScreen != a) { - if (dmxScreen->cursorNotShared) - dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name); - else - dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name); - } - return NULL; -} - -/** Iterate over the screens which overlap with the \a start screen, - * calling \a f with the \a closure for each argument. Often used with - * #dmxPrintOverlap. */ -static void *dmxIterateOverlap(DMXScreenInfo *start, - void *(*f)(DMXScreenInfo *dmxScreen, void *), - void *closure) -{ - DMXScreenInfo *pt; - - if (!start->over) return f(start, closure); - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - void *retval; - if ((retval = f(pt, closure))) return retval; - if (pt == start) break; - } - return NULL; -} - -/** Used with #dmxPropertyIterate to determine if screen \a a is the - * same as the screen \a closure. */ -static void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure) -{ - DMXScreenInfo *b = closure; - - if (a == b) - return a; - return NULL; -} - -/** Detects overlapping dmxScreens and creates circular lists. This - * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and - * the computation only needs to be performed for every server - * generation or dynamic reconfiguration . */ -void dmxInitOverlap(void) -{ - int i, j; - DMXScreenInfo *a, *b, *pt; - - for (i = 0; i < dmxNumScreens; i++) - dmxScreens[i].over = NULL; - - for (i = 0; i < dmxNumScreens; i++) { - a = &dmxScreens[i]; - - for (j = i+1; j < dmxNumScreens; j++) { - b = &dmxScreens[j]; - if (b->over) - continue; - - if (dmxDoesOverlap(a, b)) { - DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n", - a->index, b->index, a, a->over, b, b->over); - b->over = (a->over ? a->over : a); - a->over = b; - } - } - } - - for (i = 0; i < dmxNumScreens; i++) { - a = &dmxScreens[i]; - - if (!a->over) - continue; - - /* Flag all pairs that are on same display */ - for (pt = a->over; pt != a; pt = pt->over) { - if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) { - /* The ->over sets contain the transitive set of screens - * that overlap. For screens that are on the same - * backend display, we only want to exclude pairs of - * screens that mutually overlap on the backend display, - * so we call dmxDoesOverlap, which is stricter than the - * ->over set. */ - if (!dmxDoesOverlap(a, pt)) - continue; - a->cursorNotShared = 1; - pt->cursorNotShared = 1; - dmxLog(dmxInfo, - "Screen %d and %d overlap on %s\n", - a->index, pt->index, a->name); - } - } - } - - for (i = 0; i < dmxNumScreens; i++) { - a = &dmxScreens[i]; - - if (a->over) { - dmxLogOutput(a, "Overlaps"); - dmxIterateOverlap(a, dmxPrintOverlap, a); - dmxLogOutputCont(a, "\n"); - } - } -} - -/** Create \a pCursor on the back-end associated with \a pScreen. */ -void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - CursorBitsPtr pBits = pCursor->bits; - Pixmap src, msk; - XColor fg, bg; - XImage *img; - XlibGC gc = NULL; - XGCValues v; - unsigned long m; - int i; - - if (!pCursorPriv) - return; - - m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask; - v.function = GXcopy; - v.plane_mask = AllPlanes; - v.foreground = 1L; - v.background = 0L; - v.clip_mask = None; - - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - if (dmxScreen->bePixmapFormats[i].depth == 1) { - /* Create GC in the back-end servers */ - gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i], - m, &v); - break; - } - } - if (!gc) - dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n"); - - src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, - pBits->width, pBits->height, 1); - msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, - pBits->width, pBits->height, 1); - - img = XCreateImage(dmxScreen->beDisplay, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - 1, XYBitmap, 0, (char *)pBits->source, - pBits->width, pBits->height, - BitmapPad(dmxScreen->beDisplay), 0); - - XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0, - pBits->width, pBits->height); - - XFree(img); - - img = XCreateImage(dmxScreen->beDisplay, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - 1, XYBitmap, 0, (char *)pBits->mask, - pBits->width, pBits->height, - BitmapPad(dmxScreen->beDisplay), 0); - - XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0, - pBits->width, pBits->height); - - XFree(img); - - fg.red = pCursor->foreRed; - fg.green = pCursor->foreGreen; - fg.blue = pCursor->foreBlue; - - bg.red = pCursor->backRed; - bg.green = pCursor->backGreen; - bg.blue = pCursor->backBlue; - - pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay, - src, msk, - &fg, &bg, - pBits->xhot, pBits->yhot); - - XFreePixmap(dmxScreen->beDisplay, src); - XFreePixmap(dmxScreen->beDisplay, msk); - XFreeGC(dmxScreen->beDisplay, gc); - - dmxSync(dmxScreen, FALSE); -} - -static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxCursorPrivPtr pCursorPriv; - - DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor); - - DMX_SET_CURSOR_PRIV(pCursor, pScreen, xalloc(sizeof(*pCursorPriv))); - if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen)) - return FALSE; - - pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - pCursorPriv->cursor = (Cursor)0; - - if (!dmxScreen->beDisplay) - return TRUE; - - dmxBECreateCursor(pScreen, pCursor); - return TRUE; -} - -/** Free \a pCursor on the back-end associated with \a pScreen. */ -Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - - if (pCursorPriv) { - XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor); - pCursorPriv->cursor = (Cursor)0; - return TRUE; - } - - return FALSE; -} - -static Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", - pScreen->myNum, pCursor); - - if (dmxScreen->beDisplay) { - if (dmxBEFreeCursor(pScreen, pCursor)) - xfree(DMX_GET_CURSOR_PRIV(pCursor, pScreen)); - } - DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL); - - return TRUE; -} - -static void _dmxMoveCursor(ScreenPtr pScreen, int x, int y) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - int newX = x + dmxScreen->rootX; - int newY = y + dmxScreen->rootY; - - if (newX < 0) newX = 0; - if (newY < 0) newY = 0; - - DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n", - pScreen->myNum, x, y, newX, newY); - if (dmxScreen->beDisplay) { - XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin, - 0, 0, 0, 0, newX, newY); - dmxSync(dmxScreen, TRUE); - } -} - -static void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y); - - if (pCursor) { - dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) { - if (dmxScreen->beDisplay) - XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, - pCursorPriv->cursor); - dmxScreen->cursor = pCursor; - dmxScreen->curCursor = pCursorPriv->cursor; - dmxScreen->cursorVisible = 1; - } - _dmxMoveCursor(pScreen, x, y); - } else { - if (dmxScreen->beDisplay) - XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, - dmxScreen->noCursor); - dmxScreen->cursor = NULL; - dmxScreen->curCursor = (Cursor)0; - dmxScreen->cursorVisible = 0; - } - if (dmxScreen->beDisplay) dmxSync(dmxScreen, TRUE); -} - -static Bool dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) - return _dmxRealizeCursor(pScreen, pCursor); - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor); - if (pt == start) - break; - } - return TRUE; -} - -static Bool dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) - return _dmxUnrealizeCursor(pScreen, pCursor); - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor); - if (pt == start) - break; - } - return TRUE; -} - -static CursorPtr dmxFindCursor(DMXScreenInfo *start) -{ - DMXScreenInfo *pt; - - if (!start || !start->over) - return GetSpriteCursor(inputInfo.pointer); - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursor) - return pt->cursor; - if (pt == start) - break; - } - return GetSpriteCursor(inputInfo.pointer); -} - -/** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This - * function is usually called via #dmxPointerSpriteFuncs, except during - * reconfiguration when the cursor is repositioned to force an update on - * newley overlapping screens and on screens that no longer overlap. - * - * The coords (x,y) are in global coord space. We'll loop over the - * back-end screens and see if they contain the global coord. If so, call - * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen. - */ -void dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - - DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y); - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { - _dmxMoveCursor(pScreen, x, y); - return; - } - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { - if (/* pt != start && */ !pt->cursorVisible) { - if (!pt->cursor) { - /* This only happens during - * reconfiguration when a new overlap - * occurs. */ - CursorPtr pCursor; - - if ((pCursor = dmxFindCursor(start))) - _dmxRealizeCursor(screenInfo.screens[pt->index], - pt->cursor = pCursor); - - } - _dmxSetCursor(screenInfo.screens[pt->index], - pt->cursor, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } - _dmxMoveCursor(screenInfo.screens[pt->index], - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } else if (/* pt != start && */ pt->cursorVisible) { - _dmxSetCursor(screenInfo.screens[pt->index], - NULL, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } - if (pt == start) - break; - } -} - -static void dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - int GX, GY, gx, gy; - - DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n", - pScreen->myNum, start, pCursor, x, y); - - /* We do this check here because of two cases: - * - * 1) if a client calls XWarpPointer() - * and Xinerama is not running, we can - * have mi's notion of the pointer - * position out of phase with DMX's - * notion. - * - * 2) if a down button is held while the - * cursor moves outside the root window, - * mi's notion of the pointer position - * is out of phase with DMX's notion and - * the cursor can remain visible when it - * shouldn't be. */ - - dmxGetGlobalPosition(&GX, &GY); - gx = start->rootXOrigin + x; - gy = start->rootYOrigin + y; - if (x && y && (GX != gx || GY != gy)) - dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK); - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { - _dmxSetCursor(pScreen, pCursor, x, y); - return; - } - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { - _dmxSetCursor(screenInfo.screens[pt->index], pCursor, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } else { - _dmxSetCursor(screenInfo.screens[pt->index], NULL, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } - if (pt == start) - break; - } -} - - -/** This routine is used by the backend input routines to hide the - * cursor on a screen that is being used for relative input. \see - * dmxbackend.c */ -void dmxHideCursor(DMXScreenInfo *dmxScreen) -{ - int x, y; - ScreenPtr pScreen = screenInfo.screens[dmxScreen->index]; - - dmxGetGlobalPosition(&x, &y); - _dmxSetCursor(pScreen, NULL, x, y); -} - -/** This routine is called during reconfiguration to make sure the - * cursor is visible. */ -void dmxCheckCursor(void) -{ - int i; - int x, y; - ScreenPtr pScreen; - DMXScreenInfo *firstScreen; - - dmxGetGlobalPosition(&x, &y); - firstScreen = dmxFindFirstScreen(x, y); - - DMXDBG2("dmxCheckCursor %d %d\n", x, y); - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - pScreen = screenInfo.screens[dmxScreen->index]; - - if (!dmxOnScreen(x, y, dmxScreen)) { - if (firstScreen && i == miPointerGetScreen(inputInfo.pointer)->myNum) - miPointerSetScreen(inputInfo.pointer, firstScreen->index, x, y); - _dmxSetCursor(pScreen, NULL, - x - dmxScreen->rootXOrigin, - y - dmxScreen->rootYOrigin); - } else { - if (!dmxScreen->cursor) { - CursorPtr pCursor; - - if ((pCursor = dmxFindCursor(dmxScreen))) { - _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor); - } - } - _dmxSetCursor(pScreen, dmxScreen->cursor, - x - dmxScreen->rootXOrigin, - y - dmxScreen->rootYOrigin); - } - } - DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y); -} - -static Bool dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr) -{ - return TRUE; -} - -static void dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr) -{ -} - -miPointerSpriteFuncRec dmxPointerSpriteFuncs = -{ - dmxRealizeCursor, - dmxUnrealizeCursor, - dmxSetCursor, - dmxMoveCursor, - dmxDeviceCursorInitialize, - dmxDeviceCursorCleanup -}; +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * David H. Dawes + * Kevin E. Martin + * Rickard E. (Rik) Faith + * + */ + +/** \file + * This file contains code than supports cursor movement, including the + * code that initializes and reinitializes the screen positions and + * computes screen overlap. + * + * "This code is based very closely on the XFree86 equivalent + * (xfree86/common/xf86Cursor.c)." --David Dawes. + * + * "This code was then extensively re-written, as explained here." + * --Rik Faith + * + * The code in xf86Cursor.c used edge lists to implement the + * CursorOffScreen function. The edge list computation was complex + * (especially in the face of arbitrarily overlapping screens) compared + * with the speed savings in the CursorOffScreen function. The new + * implementation has erred on the side of correctness, readability, and + * maintainability over efficiency. For the common (non-edge) case, the + * dmxCursorOffScreen function does avoid a loop over all the screens. + * When the cursor has left the screen, all the screens are searched, + * and the first screen (in dmxScreens order) containing the cursor will + * be returned. If run-time profiling shows that this routing is a + * performance bottle-neck, then an edge list may have to be + * reimplemented. An edge list algorithm is O(edges) whereas the new + * algorithm is O(dmxNumScreens). Since edges is usually 1-3 and + * dmxNumScreens may be 30-60 for large backend walls, this trade off + * may be compelling. + * + * The xf86InitOrigins routine uses bit masks during the computation and + * is therefore limited to the length of a word (e.g., 32 or 64 bits) + * screens. Because Xdmx is expected to be used with a large number of + * backend displays, this limitation was removed. The new + * implementation has erred on the side of readability over efficiency, + * using the dmxSL* routines to manage a screen list instead of a + * bitmap, and a function call to decrease the length of the main + * routine. Both algorithms are of the same order, and both are called + * only at server generation time, so trading clarity and long-term + * maintainability for efficiency does not seem justified in this case. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#define DMX_CURSOR_DEBUG 0 + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxcursor.h" +#include "dmxlog.h" +#include "dmxprop.h" +#include "dmxinput.h" + +#include "mipointer.h" +#include "windowstr.h" +#include "globals.h" +#include "cursorstr.h" +#include "dixevents.h" /* For GetSpriteCursor() */ +#include "inputstr.h" /* for inputInfo.pointer */ + +#if DMX_CURSOR_DEBUG +#define DMXDBG0(f) dmxLog(dmxDebug,f) +#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) +#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) +#else +#define DMXDBG0(f) +#define DMXDBG1(f,a) +#define DMXDBG2(f,a,b) +#define DMXDBG3(f,a,b,c) +#define DMXDBG4(f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) +#endif + +static int dmxCursorDoMultiCursors = 1; + +/** Turn off support for displaying multiple cursors on overlapped + back-end displays. See #dmxCursorDoMultiCursors. */ +void dmxCursorNoMulti(void) +{ + dmxCursorDoMultiCursors = 0; +} + +static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) +{ + DMXScreenInfo *dmxScreen; + int i; + int localX = *x; + int localY = *y; + int globalX; + int globalY; + + if (screenInfo.numScreens == 1) + return FALSE; + + /* On current screen? */ + dmxScreen = &dmxScreens[(*ppScreen)->myNum]; + if (localX >= 0 + && localX < dmxScreen->rootWidth + && localY >= 0 + && localY < dmxScreen->rootHeight) + return FALSE; + + /* Convert to global coordinate space */ + globalX = dmxScreen->rootXOrigin + localX; + globalY = dmxScreen->rootYOrigin + localY; + + /* Is cursor on the current screen? + * This efficiently exits this routine + * for the most common case. */ + if (ppScreen && *ppScreen) { + dmxScreen = &dmxScreens[(*ppScreen)->myNum]; + if (globalX >= dmxScreen->rootXOrigin + && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth + && globalY >= dmxScreen->rootYOrigin + && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) + return FALSE; + } + + /* Find first screen cursor is on */ + for (i = 0; i < dmxNumScreens; i++) { + dmxScreen = &dmxScreens[i]; + if (globalX >= dmxScreen->rootXOrigin + && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth + && globalY >= dmxScreen->rootYOrigin + && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) { + if (dmxScreen->index == (*ppScreen)->myNum) + return FALSE; + *ppScreen = screenInfo.screens[dmxScreen->index]; + *x = globalX - dmxScreen->rootXOrigin; + *y = globalY - dmxScreen->rootYOrigin; + return TRUE; + } + } + return FALSE; +} + +static void dmxCrossScreen(ScreenPtr pScreen, Bool entering) +{ +} + +static void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y); +#if 11 /*BP*/ + /* This call is depracated. Replace with???? */ + miPointerWarpCursor(pDev, pScreen, x, y); +#else + pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE); +#endif +} + +miPointerScreenFuncRec dmxPointerCursorFuncs = +{ + dmxCursorOffScreen, + dmxCrossScreen, + dmxWarpCursor, + NULL, + NULL, +}; + + +/** Create a list of screens that we'll manipulate. */ +static int *dmxSLCreate(void) +{ + int *list = malloc(dmxNumScreens * sizeof(*list)); + int i; + + for (i = 0; i < dmxNumScreens; i++) + list[i] = 1; + return list; +} + +/** Free list. */ +static void dmxSLFree(int *list) +{ + free(list); +} + +/** Find next uninitialized entry in list. */ +static int dmxSLFindNext(int *list) +{ + int i; + for (i = 0; i < dmxNumScreens; i++) + if (list[i]) + return i; + return -1; +} + +/** Make one pass over all the screens and return the number updated. */ +static int dmxTryComputeScreenOrigins(int *screensLeft) +{ + ScreenPtr pScreen; + DMXScreenInfo *screen; + int i, ref; + int changed = 0; + + for (i = 0; i < dmxNumScreens; i++) { + if (!screensLeft[i]) + continue; + screen = &dmxScreens[i]; + switch (screen->where) { + case PosAbsolute: + dixScreenOrigins[i].x = screen->whereX; + dixScreenOrigins[i].y = screen->whereY; + ++changed, screensLeft[i] = 0; + break; + case PosRelative: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->whereX; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->whereY; + ++changed, screensLeft[i] = 0; + break; + case PosRightOf: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + pScreen = screenInfo.screens[ref]; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x + pScreen->width; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y; + ++changed, screensLeft[i] = 0; + break; + case PosLeftOf: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + pScreen = screenInfo.screens[i]; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x - pScreen->width; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y; + ++changed, screensLeft[i] = 0; + break; + case PosBelow: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + pScreen = screenInfo.screens[ref]; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y + pScreen->height; + ++changed, screensLeft[i] = 0; + break; + case PosAbove: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + pScreen = screenInfo.screens[i]; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y - pScreen->height; + ++changed, screensLeft[i] = 0; + break; + case PosNone: + dmxLog(dmxFatal, "No position information for screen %d\n", i); + } + } + return changed; +} + +static void dmxComputeScreenOrigins(void) +{ + int *screensLeft; + int i, ref; + int minX, minY; + + /* Compute origins based on + * configuration information. */ + screensLeft = dmxSLCreate(); + while ((i = dmxSLFindNext(screensLeft)) >= 0) { + while (dmxTryComputeScreenOrigins(screensLeft)); + if ((i = dmxSLFindNext(screensLeft)) >= 0) { + /* All of the remaining screens are referencing each other. + * Assign a value to one of them and go through again. This + * guarantees that we will eventually terminate. + */ + ref = dmxScreens[i].whereRefScreen; + dixScreenOrigins[ref].x = dixScreenOrigins[ref].y = 0; + screensLeft[ref] = 0; + } + } + dmxSLFree(screensLeft); + + + /* Justify the topmost and leftmost to + * (0,0). */ + minX = dixScreenOrigins[0].x; + minY = dixScreenOrigins[0].y; + for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */ + if (dixScreenOrigins[i].x < minX) + minX = dixScreenOrigins[i].x; + if (dixScreenOrigins[i].y < minY) + minY = dixScreenOrigins[i].y; + } + if (minX || minY) { + for (i = 0; i < dmxNumScreens; i++) { + dixScreenOrigins[i].x -= minX; + dixScreenOrigins[i].y -= minY; + } + } +} + +/** Recompute origin information in the #dmxScreens list. This is + * called from #dmxInitOrigins. */ +void dmxReInitOrigins(void) +{ + int i; + + if (dmxNumScreens > MAXSCREENS) + dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", + dmxNumScreens, MAXSCREENS); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + dmxLogOutput(dmxScreen, + "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d" + " (be=%dx%d depth=%d bpp=%d)\n", + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY, + + dmxScreen->rootWidth, dmxScreen->rootHeight, + dmxScreen->rootX, dmxScreen->rootY, + + dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, + dmxScreen->beWidth, dmxScreen->beHeight, + dmxScreen->beDepth, dmxScreen->beBPP); + } +} + +/** Initialize screen origins (and relative position). This is called + * for each server generation. For dynamic reconfiguration, use + * #dmxReInitOrigins() instead. */ +void dmxInitOrigins(void) +{ + int i; + + if (dmxNumScreens > MAXSCREENS) + dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", + dmxNumScreens, MAXSCREENS); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + dmxLogOutput(dmxScreen, + "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)" + " (be=%dx%d depth=%d bpp=%d)\n", + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY, + + dmxScreen->rootWidth, dmxScreen->rootHeight, + dmxScreen->rootX, dmxScreen->rootY, + + dmxScreen->whereX, dmxScreen->whereY, + dmxScreen->where, + + dmxScreen->beWidth, dmxScreen->beHeight, + dmxScreen->beDepth, dmxScreen->beBPP); + } + + dmxComputeScreenOrigins(); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + dmxScreen->rootXOrigin = dixScreenOrigins[i].x; + dmxScreen->rootYOrigin = dixScreenOrigins[i].y; + } + + dmxReInitOrigins(); +} + +/** Returns non-zero if the global \a x, \a y coordinate is on the + * screen window of the \a dmxScreen. */ +int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen) +{ +#if DMX_CURSOR_DEBUG > 1 + dmxLog(dmxDebug, + "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n", + dmxScreen->index, x, y, + dmxScreen->rootWidth, dmxScreen->rootHeight, + dmxScreen->rootX, dmxScreen->rootY, + dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY); +#endif + if (x >= dmxScreen->rootXOrigin + && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth + && y >= dmxScreen->rootYOrigin + && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1; + return 0; +} + +/** Returns non-zero if \a a overlaps \a b. */ +static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b) +{ + if (dmxOnScreen(a->rootXOrigin, + a->rootYOrigin, b)) + return 1; + + if (dmxOnScreen(a->rootXOrigin, + a->rootYOrigin + a->scrnWidth, b)) + return 1; + + if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, + a->rootYOrigin, b)) + return 1; + + if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, + a->rootYOrigin + a->scrnWidth, b)) + return 1; + + if (dmxOnScreen(b->rootXOrigin, + b->rootYOrigin, a)) + return 1; + + if (dmxOnScreen(b->rootXOrigin, + b->rootYOrigin + b->scrnWidth, a)) + return 1; + + if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, + b->rootYOrigin, a)) + return 1; + + if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, + b->rootYOrigin + b->scrnWidth, a)) + return 1; + + return 0; +} + +/** Used with \a dmxInterateOverlap to print out a list of screens which + * overlap each other. */ +static void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure) +{ + DMXScreenInfo *a = closure; + if (dmxScreen != a) { + if (dmxScreen->cursorNotShared) + dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name); + else + dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name); + } + return NULL; +} + +/** Iterate over the screens which overlap with the \a start screen, + * calling \a f with the \a closure for each argument. Often used with + * #dmxPrintOverlap. */ +static void *dmxIterateOverlap(DMXScreenInfo *start, + void *(*f)(DMXScreenInfo *dmxScreen, void *), + void *closure) +{ + DMXScreenInfo *pt; + + if (!start->over) return f(start, closure); + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + void *retval; + if ((retval = f(pt, closure))) return retval; + if (pt == start) break; + } + return NULL; +} + +/** Used with #dmxPropertyIterate to determine if screen \a a is the + * same as the screen \a closure. */ +static void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure) +{ + DMXScreenInfo *b = closure; + + if (a == b) + return a; + return NULL; +} + +/** Detects overlapping dmxScreens and creates circular lists. This + * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and + * the computation only needs to be performed for every server + * generation or dynamic reconfiguration . */ +void dmxInitOverlap(void) +{ + int i, j; + DMXScreenInfo *a, *b, *pt; + + for (i = 0; i < dmxNumScreens; i++) + dmxScreens[i].over = NULL; + + for (i = 0; i < dmxNumScreens; i++) { + a = &dmxScreens[i]; + + for (j = i+1; j < dmxNumScreens; j++) { + b = &dmxScreens[j]; + if (b->over) + continue; + + if (dmxDoesOverlap(a, b)) { + DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n", + a->index, b->index, a, a->over, b, b->over); + b->over = (a->over ? a->over : a); + a->over = b; + } + } + } + + for (i = 0; i < dmxNumScreens; i++) { + a = &dmxScreens[i]; + + if (!a->over) + continue; + + /* Flag all pairs that are on same display */ + for (pt = a->over; pt != a; pt = pt->over) { + if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) { + /* The ->over sets contain the transitive set of screens + * that overlap. For screens that are on the same + * backend display, we only want to exclude pairs of + * screens that mutually overlap on the backend display, + * so we call dmxDoesOverlap, which is stricter than the + * ->over set. */ + if (!dmxDoesOverlap(a, pt)) + continue; + a->cursorNotShared = 1; + pt->cursorNotShared = 1; + dmxLog(dmxInfo, + "Screen %d and %d overlap on %s\n", + a->index, pt->index, a->name); + } + } + } + + for (i = 0; i < dmxNumScreens; i++) { + a = &dmxScreens[i]; + + if (a->over) { + dmxLogOutput(a, "Overlaps"); + dmxIterateOverlap(a, dmxPrintOverlap, a); + dmxLogOutputCont(a, "\n"); + } + } +} + +/** Create \a pCursor on the back-end associated with \a pScreen. */ +void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); + CursorBitsPtr pBits = pCursor->bits; + Pixmap src, msk; + XColor fg, bg; + XImage *img; + XlibGC gc = NULL; + XGCValues v; + unsigned long m; + int i; + + if (!pCursorPriv) + return; + + m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask; + v.function = GXcopy; + v.plane_mask = AllPlanes; + v.foreground = 1L; + v.background = 0L; + v.clip_mask = None; + + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (dmxScreen->bePixmapFormats[i].depth == 1) { + /* Create GC in the back-end servers */ + gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i], + m, &v); + break; + } + } + if (!gc) + dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n"); + + src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, + pBits->width, pBits->height, 1); + msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, + pBits->width, pBits->height, 1); + + img = XCreateImage(dmxScreen->beDisplay, + dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, + 1, XYBitmap, 0, (char *)pBits->source, + pBits->width, pBits->height, + BitmapPad(dmxScreen->beDisplay), 0); + + XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0, + pBits->width, pBits->height); + + XFree(img); + + img = XCreateImage(dmxScreen->beDisplay, + dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, + 1, XYBitmap, 0, (char *)pBits->mask, + pBits->width, pBits->height, + BitmapPad(dmxScreen->beDisplay), 0); + + XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0, + pBits->width, pBits->height); + + XFree(img); + + fg.red = pCursor->foreRed; + fg.green = pCursor->foreGreen; + fg.blue = pCursor->foreBlue; + + bg.red = pCursor->backRed; + bg.green = pCursor->backGreen; + bg.blue = pCursor->backBlue; + + pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay, + src, msk, + &fg, &bg, + pBits->xhot, pBits->yhot); + + XFreePixmap(dmxScreen->beDisplay, src); + XFreePixmap(dmxScreen->beDisplay, msk); + XFreeGC(dmxScreen->beDisplay, gc); + + dmxSync(dmxScreen, FALSE); +} + +static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxCursorPrivPtr pCursorPriv; + + DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor); + + DMX_SET_CURSOR_PRIV(pCursor, pScreen, malloc(sizeof(*pCursorPriv))); + if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen)) + return FALSE; + + pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); + pCursorPriv->cursor = (Cursor)0; + + if (!dmxScreen->beDisplay) + return TRUE; + + dmxBECreateCursor(pScreen, pCursor); + return TRUE; +} + +/** Free \a pCursor on the back-end associated with \a pScreen. */ +Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); + + if (pCursorPriv) { + XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor); + pCursorPriv->cursor = (Cursor)0; + return TRUE; + } + + return FALSE; +} + +static Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", + pScreen->myNum, pCursor); + + if (dmxScreen->beDisplay) { + if (dmxBEFreeCursor(pScreen, pCursor)) + free(DMX_GET_CURSOR_PRIV(pCursor, pScreen)); + } + DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL); + + return TRUE; +} + +static void _dmxMoveCursor(ScreenPtr pScreen, int x, int y) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int newX = x + dmxScreen->rootX; + int newY = y + dmxScreen->rootY; + + if (newX < 0) newX = 0; + if (newY < 0) newY = 0; + + DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n", + pScreen->myNum, x, y, newX, newY); + if (dmxScreen->beDisplay) { + XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin, + 0, 0, 0, 0, newX, newY); + dmxSync(dmxScreen, TRUE); + } +} + +static void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y); + + if (pCursor) { + dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); + if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) { + if (dmxScreen->beDisplay) + XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, + pCursorPriv->cursor); + dmxScreen->cursor = pCursor; + dmxScreen->curCursor = pCursorPriv->cursor; + dmxScreen->cursorVisible = 1; + } + _dmxMoveCursor(pScreen, x, y); + } else { + if (dmxScreen->beDisplay) + XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, + dmxScreen->noCursor); + dmxScreen->cursor = NULL; + dmxScreen->curCursor = (Cursor)0; + dmxScreen->cursorVisible = 0; + } + if (dmxScreen->beDisplay) dmxSync(dmxScreen, TRUE); +} + +static Bool dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; + DMXScreenInfo *pt; + + if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) + return _dmxRealizeCursor(pScreen, pCursor); + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursorNotShared) + continue; + _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor); + if (pt == start) + break; + } + return TRUE; +} + +static Bool dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; + DMXScreenInfo *pt; + + if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) + return _dmxUnrealizeCursor(pScreen, pCursor); + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursorNotShared) + continue; + _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor); + if (pt == start) + break; + } + return TRUE; +} + +static CursorPtr dmxFindCursor(DMXScreenInfo *start) +{ + DMXScreenInfo *pt; + + if (!start || !start->over) + return GetSpriteCursor(inputInfo.pointer); + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursor) + return pt->cursor; + if (pt == start) + break; + } + return GetSpriteCursor(inputInfo.pointer); +} + +/** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This + * function is usually called via #dmxPointerSpriteFuncs, except during + * reconfiguration when the cursor is repositioned to force an update on + * newley overlapping screens and on screens that no longer overlap. + * + * The coords (x,y) are in global coord space. We'll loop over the + * back-end screens and see if they contain the global coord. If so, call + * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen. + */ +void dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; + DMXScreenInfo *pt; + + DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y); + + if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { + _dmxMoveCursor(pScreen, x, y); + return; + } + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursorNotShared) + continue; + if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { + if (/* pt != start && */ !pt->cursorVisible) { + if (!pt->cursor) { + /* This only happens during + * reconfiguration when a new overlap + * occurs. */ + CursorPtr pCursor; + + if ((pCursor = dmxFindCursor(start))) + _dmxRealizeCursor(screenInfo.screens[pt->index], + pt->cursor = pCursor); + + } + _dmxSetCursor(screenInfo.screens[pt->index], + pt->cursor, + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } + _dmxMoveCursor(screenInfo.screens[pt->index], + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } else if (/* pt != start && */ pt->cursorVisible) { + _dmxSetCursor(screenInfo.screens[pt->index], + NULL, + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } + if (pt == start) + break; + } +} + +static void dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ + DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; + DMXScreenInfo *pt; + int GX, GY, gx, gy; + + DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n", + pScreen->myNum, start, pCursor, x, y); + + /* We do this check here because of two cases: + * + * 1) if a client calls XWarpPointer() + * and Xinerama is not running, we can + * have mi's notion of the pointer + * position out of phase with DMX's + * notion. + * + * 2) if a down button is held while the + * cursor moves outside the root window, + * mi's notion of the pointer position + * is out of phase with DMX's notion and + * the cursor can remain visible when it + * shouldn't be. */ + + dmxGetGlobalPosition(&GX, &GY); + gx = start->rootXOrigin + x; + gy = start->rootYOrigin + y; + if (x && y && (GX != gx || GY != gy)) + dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK); + + if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { + _dmxSetCursor(pScreen, pCursor, x, y); + return; + } + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursorNotShared) + continue; + if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { + _dmxSetCursor(screenInfo.screens[pt->index], pCursor, + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } else { + _dmxSetCursor(screenInfo.screens[pt->index], NULL, + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } + if (pt == start) + break; + } +} + + +/** This routine is used by the backend input routines to hide the + * cursor on a screen that is being used for relative input. \see + * dmxbackend.c */ +void dmxHideCursor(DMXScreenInfo *dmxScreen) +{ + int x, y; + ScreenPtr pScreen = screenInfo.screens[dmxScreen->index]; + + dmxGetGlobalPosition(&x, &y); + _dmxSetCursor(pScreen, NULL, x, y); +} + +/** This routine is called during reconfiguration to make sure the + * cursor is visible. */ +void dmxCheckCursor(void) +{ + int i; + int x, y; + ScreenPtr pScreen; + DMXScreenInfo *firstScreen; + + dmxGetGlobalPosition(&x, &y); + firstScreen = dmxFindFirstScreen(x, y); + + DMXDBG2("dmxCheckCursor %d %d\n", x, y); + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + pScreen = screenInfo.screens[dmxScreen->index]; + + if (!dmxOnScreen(x, y, dmxScreen)) { + if (firstScreen && i == miPointerGetScreen(inputInfo.pointer)->myNum) + miPointerSetScreen(inputInfo.pointer, firstScreen->index, x, y); + _dmxSetCursor(pScreen, NULL, + x - dmxScreen->rootXOrigin, + y - dmxScreen->rootYOrigin); + } else { + if (!dmxScreen->cursor) { + CursorPtr pCursor; + + if ((pCursor = dmxFindCursor(dmxScreen))) { + _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor); + } + } + _dmxSetCursor(pScreen, dmxScreen->cursor, + x - dmxScreen->rootXOrigin, + y - dmxScreen->rootYOrigin); + } + } + DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y); +} + +static Bool dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr) +{ + return TRUE; +} + +static void dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr) +{ +} + +miPointerSpriteFuncRec dmxPointerSpriteFuncs = +{ + dmxRealizeCursor, + dmxUnrealizeCursor, + dmxSetCursor, + dmxMoveCursor, + dmxDeviceCursorInitialize, + dmxDeviceCursorCleanup +}; diff --git a/xorg-server/hw/dmx/dmxfont.c b/xorg-server/hw/dmx/dmxfont.c index c33aee79a..3f0264edb 100644 --- a/xorg-server/hw/dmx/dmxfont.c +++ b/xorg-server/hw/dmx/dmxfont.c @@ -1,559 +1,551 @@ -/* - * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Kevin E. Martin - * - */ - -/** \file - * This file provides support for fonts. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#define DMX_FONTPATH_DEBUG 0 - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxfont.h" -#include "dmxlog.h" - -#include -#include "dixfont.h" -#include "dixstruct.h" - -static int (*dmxSaveProcVector[256])(ClientPtr); -static int dmxFontLastError; - -static int dmxFontErrorHandler(Display *dpy, XErrorEvent *ev) -{ - dmxFontLastError = ev->error_code; - - return 0; -} - -static char **dmxGetFontPath(int *npaths) -{ - char **fp; - unsigned char *c, *paths; - char *newfp; - int len, l, i; - - GetFontPath(serverClient, npaths, &len, &paths); - - newfp = xalloc(*npaths + len); - c = (unsigned char *)newfp; - fp = xalloc(*npaths * sizeof(*fp)); - - memmove(newfp, paths+1, *npaths + len - 1); - l = *paths; - for (i = 0; i < *npaths; i++) { - fp[i] = (char *)c; - c += l; - l = *c; - *c++ = '\0'; - } - -#if DMX_FONTPATH_DEBUG - for (i = 0; i < *npaths; i++) - dmxLog(dmxDebug, "FontPath[%d] = %s\n", i, fp[i]); -#endif - - return fp; -} - -static void dmxFreeFontPath(char **fp) -{ - xfree(fp[0]); - xfree(fp); -} - -static Bool dmxCheckFontPathElement(DMXScreenInfo *dmxScreen, char *fp) -{ - int (*oldErrorHandler)(Display *, XErrorEvent *); - - if (!dmxScreen->beDisplay) - return TRUE; - - dmxFontLastError = 0; - oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); - XSetFontPath(dmxScreen->beDisplay, &fp, 1); - dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ - XSetErrorHandler(oldErrorHandler); - - return (dmxFontLastError == 0); -} - -static int dmxSetFontPath(DMXScreenInfo *dmxScreen) -{ - int (*oldErrorHandler)(Display *, XErrorEvent *); - char **fp; - int result = Success; - int npaths; - - if (!dmxScreen->beDisplay) - return result; - - fp = dmxGetFontPath(&npaths); - if (!fp) return BadAlloc; - - dmxFontLastError = 0; - oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); - XSetFontPath(dmxScreen->beDisplay, fp, npaths); - dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ - XSetErrorHandler(oldErrorHandler); - - if (dmxFontLastError) { - result = dmxFontLastError; - /* We could set *error here to the offending path, but it is - * ignored, so we don't bother figuring out which path is bad. - * If we do add this support in the future, we'll need to add - * error to the function's argument list. - */ - } - - dmxFreeFontPath(fp); - - return result; -} - -static int dmxCheckFontPath(DMXScreenInfo *dmxScreen, int *error) -{ - char **oldFontPath; - int nOldPaths; - int result = Success; - - if (!dmxScreen->beDisplay) - return result; - - /* Save old font path */ - oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); - - result = dmxSetFontPath(dmxScreen); - - /* Restore old font path */ - XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); - XFreeFontPath(oldFontPath); - dmxSync(dmxScreen, FALSE); - - return result; -} - -static int dmxProcSetFontPath(ClientPtr client) -{ - unsigned char *ptr; - unsigned long nbytes, total, n; - long nfonts; - int i, result; - int error; - unsigned char *oldFontPath, *tmpFontPath; - int nOldPaths; - int lenOldPaths; - 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; - - GetFontPath(serverClient, &nOldPaths, &lenOldPaths, &tmpFontPath); - oldFontPath = xalloc(nOldPaths + lenOldPaths); - memmove(oldFontPath, tmpFontPath, nOldPaths + lenOldPaths); - - result = SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1], - &error); - if (!result) { - for (i = 0; i < dmxNumScreens; i++) - if ((result = dmxCheckFontPath(&dmxScreens[i], &error))) - break; - - if (result) { - int ignoreresult, ignoreerror; - - /* Restore old fontpath in the DMX server */ - ignoreresult = SetFontPath(client, nOldPaths, oldFontPath, - &ignoreerror); - } else { - result = client->noClientException; - client->errorValue = error; - } - } - - xfree(oldFontPath); - return result; -} - -/** Initialize font support. In addition to the screen function call - * pointers, DMX also hooks in at the ProcVector[] level. Here the old - * ProcVector function pointers are saved and the new ProcVector - * function pointers are initialized. */ -void dmxInitFonts(void) -{ - int i; - - for (i = 0; i < 256; i++) - dmxSaveProcVector[i] = ProcVector[i]; - - ProcVector[X_SetFontPath] = dmxProcSetFontPath; -} - -/** Reset font support by restoring the original ProcVector function - * pointers. */ -void dmxResetFonts(void) -{ - int i; - - for (i = 0; i < 256; i++) - ProcVector[i] = dmxSaveProcVector[i]; -} - -/** Load the font, \a pFont, on the back-end server associated with \a - * pScreen. When a font is loaded, the font path on back-end server is - * first initialized to that specified on the command line with the - * -fontpath options, and then the font is loaded. */ -Bool dmxBELoadFont(ScreenPtr pScreen, FontPtr pFont) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); - const char *name; - char **oldFontPath = NULL; - int nOldPaths; - Atom name_atom, value_atom; - int i; - - /* Make sure we have a font private struct to work with */ - if (!pFontPriv) - return FALSE; - - /* Don't load a font over top of itself */ - if (pFontPriv->font[pScreen->myNum]) { - return TRUE; /* Already loaded font */ - } - - /* Save old font path */ - oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); - - /* Set the font path for the font about to be loaded on the back-end */ - if (dmxSetFontPath(dmxScreen)) { - char **fp; - int npaths; - Bool *goodfps; - - /* This could fail only when first starting the X server and - * loading the default font. If it fails here, then the default - * font path is invalid, no default font path will be set, the - * DMX server will fail to load the default font, and it will - * exit with an error unless we remove the offending font paths - * with the -ignorebadfontpaths command line option. - */ - - fp = dmxGetFontPath(&npaths); - if (!fp) { - dmxLog(dmxError, - "No default font path set.\n"); - dmxLog(dmxError, - "Please see the Xdmx man page for information on how to\n"); - dmxLog(dmxError, - "initialize the DMX server's default font path.\n"); - XFreeFontPath(oldFontPath); - return FALSE; - } - - if (!dmxFontPath) - dmxLog(dmxWarning, "No default font path is set.\n"); - - goodfps = xalloc(npaths * sizeof(*goodfps)); - - dmxLog(dmxError, - "The DMX server failed to set the following font paths on " - "screen #%d:\n", pScreen->myNum); - - for (i = 0; i < npaths; i++) - if (!(goodfps[i] = dmxCheckFontPathElement(dmxScreen, fp[i]))) - dmxLog(dmxError, " %s\n", fp[i]); - - if (dmxIgnoreBadFontPaths) { - char *newfp; - int newnpaths = 0; - int len = 0; - int j = 0; - int error; - - dmxLog(dmxError, - "These font paths will not be used because the " - "\"-ignorebadfontpaths\"\n"); - dmxLog(dmxError, - "option is set.\n"); - - for (i = 0; i < npaths; i++) - if (goodfps[i]) { - len += strlen(fp[i]) + 1; - newnpaths++; - } - - if (!newnpaths) { - /* No valid font paths were found */ - dmxLog(dmxError, - "After removing the font paths above, no valid font " - "paths were\n"); - dmxLog(dmxError, - "available. Please check that the font paths set on " - "the command\n"); - dmxLog(dmxError, - "line or in the configuration file via the " - "\"-fontpath\" option\n"); - dmxLog(dmxError, - "are valid on all back-end servers. See the Xdmx man " - "page for\n"); - dmxLog(dmxError, - "more information on font paths.\n"); - dmxFreeFontPath(fp); - XFreeFontPath(oldFontPath); - xfree(goodfps); - return FALSE; - } - - newfp = xalloc(len * sizeof(*newfp)); - for (i = 0; i < npaths; i++) { - if (goodfps[i]) { - int n = strlen(fp[i]); - newfp[j++] = n; - strncpy(&newfp[j], fp[i], n); - j += n; - } - } - - if (SetFontPath(serverClient, newnpaths, (unsigned char *)newfp, - &error)) { - /* Note that this should never happen since all of the - * FPEs were previously valid. */ - dmxLog(dmxError, "Cannot reset the default font path.\n"); - } - } else if (dmxFontPath) { - dmxLog(dmxError, - "Please remove these font paths from the command line " - "or\n"); - dmxLog(dmxError, - "configuration file, or set the \"-ignorebadfontpaths\" " - "option to\n"); - dmxLog(dmxError, - "ignore them. For more information on these options, see " - "the\n"); - dmxLog(dmxError, - "Xdmx man page.\n"); - } else { - dmxLog(dmxError, - "Please specify the font paths that are available on all " - "back-end\n"); - dmxLog(dmxError, - "servers with the \"-fontpath\" option, or use the " - "\"-ignorebadfontpaths\"\n"); - dmxLog(dmxError, - "to ignore bad defaults. For more information on " - "these and other\n"); - dmxLog(dmxError, - "font-path-related options, see the Xdmx man page.\n"); - } - - if (!dmxIgnoreBadFontPaths || - (dmxIgnoreBadFontPaths && dmxSetFontPath(dmxScreen))) { - /* We still have errors so return with error */ - dmxFreeFontPath(fp); - XFreeFontPath(oldFontPath); - xfree(goodfps); - return FALSE; - } - } - - /* Find requested font on back-end server */ - name_atom = MakeAtom("FONT", 4, TRUE); - value_atom = 0L; - - for (i = 0; i < pFont->info.nprops; i++) { - if ((Atom)pFont->info.props[i].name == name_atom) { - value_atom = pFont->info.props[i].value; - break; - } - } - if (!value_atom) return FALSE; - - name = NameForAtom(value_atom); - if (!name) return FALSE; - - pFontPriv->font[pScreen->myNum] = - XLoadQueryFont(dmxScreen->beDisplay, name); - - /* Restore old font path */ - XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); - XFreeFontPath(oldFontPath); - dmxSync(dmxScreen, FALSE); - - if (!pFontPriv->font[pScreen->myNum]) return FALSE; - - return TRUE; -} - -/** Realize the font, \a pFont, on the back-end server associated with - * \a pScreen. */ -Bool dmxRealizeFont(ScreenPtr pScreen, FontPtr pFont) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxFontPrivPtr pFontPriv; - - if (!(pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) { - FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); - pFontPriv = xalloc(sizeof(dmxFontPrivRec)); - if (!pFontPriv) return FALSE; - pFontPriv->font = NULL; - MAXSCREENSALLOC(pFontPriv->font); - if (!pFontPriv->font) { - xfree(pFontPriv); - return FALSE; - } - pFontPriv->refcnt = 0; - } - - FontSetPrivate(pFont, dmxFontPrivateIndex, (pointer)pFontPriv); - - if (dmxScreen->beDisplay) { - if (!dmxBELoadFont(pScreen, pFont)) - return FALSE; - - pFontPriv->refcnt++; - } else { - pFontPriv->font[pScreen->myNum] = NULL; - } - - return TRUE; -} - -/** Free \a pFont on the back-end associated with \a pScreen. */ -Bool dmxBEFreeFont(ScreenPtr pScreen, FontPtr pFont) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); - - if (pFontPriv && pFontPriv->font[pScreen->myNum]) { - XFreeFont(dmxScreen->beDisplay, pFontPriv->font[pScreen->myNum]); - pFontPriv->font[pScreen->myNum] = NULL; - return TRUE; - } - - return FALSE; -} - -/** Unrealize the font, \a pFont, on the back-end server associated with - * \a pScreen. */ -Bool dmxUnrealizeFont(ScreenPtr pScreen, FontPtr pFont) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxFontPrivPtr pFontPriv; - - if ((pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) { - /* In case the font failed to load properly */ - if (!pFontPriv->refcnt) { - MAXSCREENSFREE(pFontPriv->font); - xfree(pFontPriv); - FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); - } else if (pFontPriv->font[pScreen->myNum]) { - if (dmxScreen->beDisplay) - dmxBEFreeFont(pScreen, pFont); - - /* The code below is non-obvious, so here's an explanation... - * - * When creating the default GC, the server opens up the - * default font once for each screen, which in turn calls - * the RealizeFont function pointer once for each screen. - * During this process both dix's font refcnt and DMX's font - * refcnt are incremented once for each screen. - * - * Later, when shutting down the X server, dix shuts down - * each screen in reverse order. During this shutdown - * procedure, each screen's default GC is freed and then - * that screen is closed by calling the CloseScreen function - * pointer. screenInfo.numScreens is then decremented after - * closing each screen. This procedure means that the dix's - * font refcnt for the font used by the default GC's is - * decremented once for each screen # greater than 0. - * However, since dix's refcnt for the default font is not - * yet 0 for each screen greater than 0, no call to the - * UnrealizeFont function pointer is made for those screens. - * Then, when screen 0 is being closed, dix's font refcnt - * for the default GC's font is finally 0 and the font is - * unrealized. However, since screenInfo.numScreens has - * been decremented already down to 1, only one call to - * UnrealizeFont is made (for screen 0). Thus, even though - * RealizeFont was called once for each screen, - * UnrealizeFont is only called for screen 0. - * - * This is a bug in dix. - * - * To avoid the memory leak of pFontPriv for each server - * generation, we can also free pFontPriv if the refcnt is - * not yet 0 but the # of screens is 1 -- i.e., the case - * described in the dix bug above. This is only a temporary - * workaround until the bug in dix is solved. - * - * The other problem is that the font structure allocated by - * XLoadQueryFont() above is not freed for screens > 0. - * This problem cannot be worked around here since the back- - * end displays for screens > 0 have already been closed by - * the time this code is called from dix. - * - * When the bug in dix described above is fixed, then we can - * remove the "|| screenInfo.numScreens == 1" code below and - * the memory leaks will be eliminated. - */ - if (--pFontPriv->refcnt == 0 -#if 1 - /* Remove this code when the dix bug is fixed */ - || screenInfo.numScreens == 1 -#endif - ) { - MAXSCREENSFREE(pFontPriv->font); - xfree(pFontPriv); - FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); - } - } - } - - return TRUE; -} +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Kevin E. Martin + * + */ + +/** \file + * This file provides support for fonts. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#define DMX_FONTPATH_DEBUG 0 + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxfont.h" +#include "dmxlog.h" + +#include +#include "dixfont.h" +#include "dixstruct.h" + +static int (*dmxSaveProcVector[256])(ClientPtr); +static int dmxFontLastError; + +static int dmxFontErrorHandler(Display *dpy, XErrorEvent *ev) +{ + dmxFontLastError = ev->error_code; + + return 0; +} + +static char **dmxGetFontPath(int *npaths) +{ + char **fp; + unsigned char *c, *paths; + char *newfp; + int len, l, i; + + GetFontPath(serverClient, npaths, &len, &paths); + + newfp = malloc(*npaths + len); + c = (unsigned char *)newfp; + fp = malloc(*npaths * sizeof(*fp)); + + memmove(newfp, paths+1, *npaths + len - 1); + l = *paths; + for (i = 0; i < *npaths; i++) { + fp[i] = (char *)c; + c += l; + l = *c; + *c++ = '\0'; + } + +#if DMX_FONTPATH_DEBUG + for (i = 0; i < *npaths; i++) + dmxLog(dmxDebug, "FontPath[%d] = %s\n", i, fp[i]); +#endif + + return fp; +} + +static void dmxFreeFontPath(char **fp) +{ + free(fp[0]); + free(fp); +} + +static Bool dmxCheckFontPathElement(DMXScreenInfo *dmxScreen, char *fp) +{ + int (*oldErrorHandler)(Display *, XErrorEvent *); + + if (!dmxScreen->beDisplay) + return TRUE; + + dmxFontLastError = 0; + oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); + XSetFontPath(dmxScreen->beDisplay, &fp, 1); + dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ + XSetErrorHandler(oldErrorHandler); + + return (dmxFontLastError == 0); +} + +static int dmxSetFontPath(DMXScreenInfo *dmxScreen) +{ + int (*oldErrorHandler)(Display *, XErrorEvent *); + char **fp; + int result = Success; + int npaths; + + if (!dmxScreen->beDisplay) + return result; + + fp = dmxGetFontPath(&npaths); + if (!fp) return BadAlloc; + + dmxFontLastError = 0; + oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); + XSetFontPath(dmxScreen->beDisplay, fp, npaths); + dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ + XSetErrorHandler(oldErrorHandler); + + if (dmxFontLastError) { + result = dmxFontLastError; + /* We could set *error here to the offending path, but it is + * ignored, so we don't bother figuring out which path is bad. + * If we do add this support in the future, we'll need to add + * error to the function's argument list. + */ + } + + dmxFreeFontPath(fp); + + return result; +} + +static int dmxCheckFontPath(DMXScreenInfo *dmxScreen, int *error) +{ + char **oldFontPath; + int nOldPaths; + int result = Success; + + if (!dmxScreen->beDisplay) + return result; + + /* Save old font path */ + oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); + + result = dmxSetFontPath(dmxScreen); + + /* Restore old font path */ + XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); + XFreeFontPath(oldFontPath); + dmxSync(dmxScreen, FALSE); + + return result; +} + +static int dmxProcSetFontPath(ClientPtr client) +{ + unsigned char *ptr; + unsigned long nbytes, total, n; + long nfonts; + int i, result; + unsigned char *oldFontPath, *tmpFontPath; + int nOldPaths; + int lenOldPaths; + 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; + + GetFontPath(serverClient, &nOldPaths, &lenOldPaths, &tmpFontPath); + oldFontPath = malloc(nOldPaths + lenOldPaths); + memmove(oldFontPath, tmpFontPath, nOldPaths + lenOldPaths); + + result = SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1]); + if (!result) { + int error = 0; + for (i = 0; i < dmxNumScreens; i++) + if ((result = dmxCheckFontPath(&dmxScreens[i], &error))) + break; + + if (result) { + /* Restore old fontpath in the DMX server */ + SetFontPath(client, nOldPaths, oldFontPath); + client->errorValue = error; + } + } + + free(oldFontPath); + return result; +} + +/** Initialize font support. In addition to the screen function call + * pointers, DMX also hooks in at the ProcVector[] level. Here the old + * ProcVector function pointers are saved and the new ProcVector + * function pointers are initialized. */ +void dmxInitFonts(void) +{ + int i; + + for (i = 0; i < 256; i++) + dmxSaveProcVector[i] = ProcVector[i]; + + ProcVector[X_SetFontPath] = dmxProcSetFontPath; +} + +/** Reset font support by restoring the original ProcVector function + * pointers. */ +void dmxResetFonts(void) +{ + int i; + + for (i = 0; i < 256; i++) + ProcVector[i] = dmxSaveProcVector[i]; +} + +/** Load the font, \a pFont, on the back-end server associated with \a + * pScreen. When a font is loaded, the font path on back-end server is + * first initialized to that specified on the command line with the + * -fontpath options, and then the font is loaded. */ +Bool dmxBELoadFont(ScreenPtr pScreen, FontPtr pFont) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); + const char *name; + char **oldFontPath = NULL; + int nOldPaths; + Atom name_atom, value_atom; + int i; + + /* Make sure we have a font private struct to work with */ + if (!pFontPriv) + return FALSE; + + /* Don't load a font over top of itself */ + if (pFontPriv->font[pScreen->myNum]) { + return TRUE; /* Already loaded font */ + } + + /* Save old font path */ + oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); + + /* Set the font path for the font about to be loaded on the back-end */ + if (dmxSetFontPath(dmxScreen)) { + char **fp; + int npaths; + Bool *goodfps; + + /* This could fail only when first starting the X server and + * loading the default font. If it fails here, then the default + * font path is invalid, no default font path will be set, the + * DMX server will fail to load the default font, and it will + * exit with an error unless we remove the offending font paths + * with the -ignorebadfontpaths command line option. + */ + + fp = dmxGetFontPath(&npaths); + if (!fp) { + dmxLog(dmxError, + "No default font path set.\n"); + dmxLog(dmxError, + "Please see the Xdmx man page for information on how to\n"); + dmxLog(dmxError, + "initialize the DMX server's default font path.\n"); + XFreeFontPath(oldFontPath); + return FALSE; + } + + if (!dmxFontPath) + dmxLog(dmxWarning, "No default font path is set.\n"); + + goodfps = malloc(npaths * sizeof(*goodfps)); + + dmxLog(dmxError, + "The DMX server failed to set the following font paths on " + "screen #%d:\n", pScreen->myNum); + + for (i = 0; i < npaths; i++) + if (!(goodfps[i] = dmxCheckFontPathElement(dmxScreen, fp[i]))) + dmxLog(dmxError, " %s\n", fp[i]); + + if (dmxIgnoreBadFontPaths) { + char *newfp; + int newnpaths = 0; + int len = 0; + int j = 0; + + dmxLog(dmxError, + "These font paths will not be used because the " + "\"-ignorebadfontpaths\"\n"); + dmxLog(dmxError, + "option is set.\n"); + + for (i = 0; i < npaths; i++) + if (goodfps[i]) { + len += strlen(fp[i]) + 1; + newnpaths++; + } + + if (!newnpaths) { + /* No valid font paths were found */ + dmxLog(dmxError, + "After removing the font paths above, no valid font " + "paths were\n"); + dmxLog(dmxError, + "available. Please check that the font paths set on " + "the command\n"); + dmxLog(dmxError, + "line or in the configuration file via the " + "\"-fontpath\" option\n"); + dmxLog(dmxError, + "are valid on all back-end servers. See the Xdmx man " + "page for\n"); + dmxLog(dmxError, + "more information on font paths.\n"); + dmxFreeFontPath(fp); + XFreeFontPath(oldFontPath); + free(goodfps); + return FALSE; + } + + newfp = malloc(len * sizeof(*newfp)); + for (i = 0; i < npaths; i++) { + if (goodfps[i]) { + int n = strlen(fp[i]); + newfp[j++] = n; + strncpy(&newfp[j], fp[i], n); + j += n; + } + } + + if (SetFontPath(serverClient, newnpaths, (unsigned char *)newfp)) { + /* Note that this should never happen since all of the + * FPEs were previously valid. */ + dmxLog(dmxError, "Cannot reset the default font path.\n"); + } + } else if (dmxFontPath) { + dmxLog(dmxError, + "Please remove these font paths from the command line " + "or\n"); + dmxLog(dmxError, + "configuration file, or set the \"-ignorebadfontpaths\" " + "option to\n"); + dmxLog(dmxError, + "ignore them. For more information on these options, see " + "the\n"); + dmxLog(dmxError, + "Xdmx man page.\n"); + } else { + dmxLog(dmxError, + "Please specify the font paths that are available on all " + "back-end\n"); + dmxLog(dmxError, + "servers with the \"-fontpath\" option, or use the " + "\"-ignorebadfontpaths\"\n"); + dmxLog(dmxError, + "to ignore bad defaults. For more information on " + "these and other\n"); + dmxLog(dmxError, + "font-path-related options, see the Xdmx man page.\n"); + } + + if (!dmxIgnoreBadFontPaths || + (dmxIgnoreBadFontPaths && dmxSetFontPath(dmxScreen))) { + /* We still have errors so return with error */ + dmxFreeFontPath(fp); + XFreeFontPath(oldFontPath); + free(goodfps); + return FALSE; + } + } + + /* Find requested font on back-end server */ + name_atom = MakeAtom("FONT", 4, TRUE); + value_atom = 0L; + + for (i = 0; i < pFont->info.nprops; i++) { + if ((Atom)pFont->info.props[i].name == name_atom) { + value_atom = pFont->info.props[i].value; + break; + } + } + if (!value_atom) return FALSE; + + name = NameForAtom(value_atom); + if (!name) return FALSE; + + pFontPriv->font[pScreen->myNum] = + XLoadQueryFont(dmxScreen->beDisplay, name); + + /* Restore old font path */ + XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); + XFreeFontPath(oldFontPath); + dmxSync(dmxScreen, FALSE); + + if (!pFontPriv->font[pScreen->myNum]) return FALSE; + + return TRUE; +} + +/** Realize the font, \a pFont, on the back-end server associated with + * \a pScreen. */ +Bool dmxRealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxFontPrivPtr pFontPriv; + + if (!(pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) { + FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); + pFontPriv = malloc(sizeof(dmxFontPrivRec)); + if (!pFontPriv) return FALSE; + pFontPriv->font = NULL; + MAXSCREENSALLOC(pFontPriv->font); + if (!pFontPriv->font) { + free(pFontPriv); + return FALSE; + } + pFontPriv->refcnt = 0; + } + + FontSetPrivate(pFont, dmxFontPrivateIndex, (pointer)pFontPriv); + + if (dmxScreen->beDisplay) { + if (!dmxBELoadFont(pScreen, pFont)) + return FALSE; + + pFontPriv->refcnt++; + } else { + pFontPriv->font[pScreen->myNum] = NULL; + } + + return TRUE; +} + +/** Free \a pFont on the back-end associated with \a pScreen. */ +Bool dmxBEFreeFont(ScreenPtr pScreen, FontPtr pFont) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); + + if (pFontPriv && pFontPriv->font[pScreen->myNum]) { + XFreeFont(dmxScreen->beDisplay, pFontPriv->font[pScreen->myNum]); + pFontPriv->font[pScreen->myNum] = NULL; + return TRUE; + } + + return FALSE; +} + +/** Unrealize the font, \a pFont, on the back-end server associated with + * \a pScreen. */ +Bool dmxUnrealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxFontPrivPtr pFontPriv; + + if ((pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) { + /* In case the font failed to load properly */ + if (!pFontPriv->refcnt) { + MAXSCREENSFREE(pFontPriv->font); + free(pFontPriv); + FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); + } else if (pFontPriv->font[pScreen->myNum]) { + if (dmxScreen->beDisplay) + dmxBEFreeFont(pScreen, pFont); + + /* The code below is non-obvious, so here's an explanation... + * + * When creating the default GC, the server opens up the + * default font once for each screen, which in turn calls + * the RealizeFont function pointer once for each screen. + * During this process both dix's font refcnt and DMX's font + * refcnt are incremented once for each screen. + * + * Later, when shutting down the X server, dix shuts down + * each screen in reverse order. During this shutdown + * procedure, each screen's default GC is freed and then + * that screen is closed by calling the CloseScreen function + * pointer. screenInfo.numScreens is then decremented after + * closing each screen. This procedure means that the dix's + * font refcnt for the font used by the default GC's is + * decremented once for each screen # greater than 0. + * However, since dix's refcnt for the default font is not + * yet 0 for each screen greater than 0, no call to the + * UnrealizeFont function pointer is made for those screens. + * Then, when screen 0 is being closed, dix's font refcnt + * for the default GC's font is finally 0 and the font is + * unrealized. However, since screenInfo.numScreens has + * been decremented already down to 1, only one call to + * UnrealizeFont is made (for screen 0). Thus, even though + * RealizeFont was called once for each screen, + * UnrealizeFont is only called for screen 0. + * + * This is a bug in dix. + * + * To avoid the memory leak of pFontPriv for each server + * generation, we can also free pFontPriv if the refcnt is + * not yet 0 but the # of screens is 1 -- i.e., the case + * described in the dix bug above. This is only a temporary + * workaround until the bug in dix is solved. + * + * The other problem is that the font structure allocated by + * XLoadQueryFont() above is not freed for screens > 0. + * This problem cannot be worked around here since the back- + * end displays for screens > 0 have already been closed by + * the time this code is called from dix. + * + * When the bug in dix described above is fixed, then we can + * remove the "|| screenInfo.numScreens == 1" code below and + * the memory leaks will be eliminated. + */ + if (--pFontPriv->refcnt == 0 +#if 1 + /* Remove this code when the dix bug is fixed */ + || screenInfo.numScreens == 1 +#endif + ) { + MAXSCREENSFREE(pFontPriv->font); + free(pFontPriv); + FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); + } + } + } + + return TRUE; +} diff --git a/xorg-server/hw/dmx/dmxgc.c b/xorg-server/hw/dmx/dmxgc.c index eb21d3c60..82f74b6e6 100644 --- a/xorg-server/hw/dmx/dmxgc.c +++ b/xorg-server/hw/dmx/dmxgc.c @@ -1,421 +1,421 @@ -/* - * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Kevin E. Martin - * - */ - -/** \file - * This file provides support for GCs. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxgc.h" -#include "dmxgcops.h" -#include "dmxpixmap.h" -#include "dmxfont.h" - -#include "gcstruct.h" -#include "pixmapstr.h" -#include "migc.h" - -static GCFuncs dmxGCFuncs = { - dmxValidateGC, - dmxChangeGC, - dmxCopyGC, - dmxDestroyGC, - dmxChangeClip, - dmxDestroyClip, - dmxCopyClip, -}; - -static GCOps dmxGCOps = { - dmxFillSpans, - dmxSetSpans, - dmxPutImage, - dmxCopyArea, - dmxCopyPlane, - dmxPolyPoint, - dmxPolylines, - dmxPolySegment, - dmxPolyRectangle, - dmxPolyArc, - dmxFillPolygon, - dmxPolyFillRect, - dmxPolyFillArc, - dmxPolyText8, - dmxPolyText16, - dmxImageText8, - dmxImageText16, - dmxImageGlyphBlt, - dmxPolyGlyphBlt, - dmxPushPixels -}; - -/** Initialize the GC on \a pScreen */ -Bool dmxInitGC(ScreenPtr pScreen) -{ - if (!dixRequestPrivate(dmxGCPrivateKey, sizeof(dmxGCPrivRec))) - return FALSE; - return TRUE; -} - -/** Create the GC on the back-end server. */ -void dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - int i; - - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) { - unsigned long mask; - XGCValues gcvals; - - mask = GCGraphicsExposures; - gcvals.graphics_exposures = FALSE; - - /* Create GC in the back-end servers */ - pGCPriv->gc = XCreateGC(dmxScreen->beDisplay, - dmxScreen->scrnDefDrawables[i], - mask, &gcvals); - break; - } - } -} - -/** Create a graphics context on the back-end server associated /a pGC's - * screen. */ -Bool dmxCreateGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - Bool ret; - - DMX_UNWRAP(CreateGC, dmxScreen, pScreen); - if ((ret = pScreen->CreateGC(pGC))) { - /* Save the old funcs */ - pGCPriv->funcs = pGC->funcs; - pGCPriv->ops = NULL; - - pGC->funcs = &dmxGCFuncs; - - if (dmxScreen->beDisplay) { - dmxBECreateGC(pScreen, pGC); - } else { - pGCPriv->gc = NULL; - } - - /* Check for "magic special case" - * 1. see CreateGC in dix/gc.c for more info - * 2. see dmxChangeGC for more info - */ - pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap); - } - DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); - - return ret; -} - -/** Validate a graphics context, \a pGC, locally in the DMX server and - * recompute the composite clip, if necessary. */ -void dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) -{ - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - - DMX_GC_FUNC_PROLOGUE(pGC); -#if 0 - pGC->funcs->ValidateGC(pGC, changes, pDrawable); -#endif - - if (pDrawable->type == DRAWABLE_WINDOW || - pDrawable->type == DRAWABLE_PIXMAP) { - /* Save the old ops, since we're about to change the ops in the - * epilogue. - */ - pGCPriv->ops = pGC->ops; - } else { - pGCPriv->ops = NULL; - } - - /* If the client clip is different or moved OR the subwindowMode has - * changed OR the window's clip has changed since the last - * validation, then we need to recompute the composite clip. - */ - if ((changes & (GCClipXOrigin | - GCClipYOrigin | - GCClipMask | - GCSubwindowMode)) || - (pDrawable->serialNumber != - (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) { - miComputeCompositeClip(pGC, pDrawable); - } - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Set the values in the graphics context on the back-end server - * associated with \a pGC's screen. */ -void dmxChangeGC(GCPtr pGC, unsigned long mask) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - XGCValues v; - - DMX_GC_FUNC_PROLOGUE(pGC); -#if 0 - pGC->funcs->ChangeGC(pGC, mask); -#endif - - /* Handle "magic special case" from CreateGC */ - if (pGCPriv->msc) { - /* The "magic special case" is used to handle the case where a - * foreground pixel is set when the GC is created so that a - * "pseudo default-tile" can be created and used in case the - * fillstyle was set to FillTiled. This specific case is tested - * in xtest (XCreateGC test #3). What has happened in dix by - * the time it reaches here is (1) the pGC->tile.pixel has been - * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a - * tile has also been set, then pGC->tileIsPixel is unset and - * pGC->tile.pixmap is initialized; else, the default tile is - * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is - * initialized to the "pseudo default-tile". In either case, - * pGC->tile.pixmap is set; however, in the "magic special case" - * the mask is not updated to allow us to detect that we should - * initialize the GCTile in the back-end server. Thus, we catch - * this case in dmxCreateGC and add GCTile to the mask here. - * Are there any cases that I've missed? - */ - - /* Make sure that the tile.pixmap is set, just in case the user - * set GCTile in the mask but forgot to set vals.pixmap - */ - if (pGC->tile.pixmap) mask |= GCTile; - - /* This only happens once when the GC is created */ - pGCPriv->msc = FALSE; - } - - /* Update back-end server's gc */ - if (mask & GCFunction) v.function = pGC->alu; - if (mask & GCPlaneMask) v.plane_mask = pGC->planemask; - if (mask & GCForeground) v.foreground = pGC->fgPixel; - if (mask & GCBackground) v.background = pGC->bgPixel; - if (mask & GCLineWidth) v.line_width = pGC->lineWidth; - if (mask & GCLineStyle) v.line_style = pGC->lineStyle; - if (mask & GCCapStyle) v.cap_style = pGC->capStyle; - if (mask & GCJoinStyle) v.join_style = pGC->joinStyle; - if (mask & GCFillStyle) v.fill_style = pGC->fillStyle; - if (mask & GCFillRule) v.fill_rule = pGC->fillRule; - if (mask & GCTile) { - if (pGC->tileIsPixel) { - mask &= ~GCTile; - } else { - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap); - v.tile = (Drawable)pPixPriv->pixmap; - } - } - if (mask & GCStipple) { - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple); - v.stipple = (Drawable)pPixPriv->pixmap; - } - if (mask & GCTileStipXOrigin) v.ts_x_origin = pGC->patOrg.x; - if (mask & GCTileStipYOrigin) v.ts_y_origin = pGC->patOrg.y; - if (mask & GCFont) { - if (dmxScreen->beDisplay) { - dmxFontPrivPtr pFontPriv; - pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex); - v.font = pFontPriv->font[pScreen->myNum]->fid; - } else { - mask &= ~GCFont; - } - } - if (mask & GCSubwindowMode) v.subwindow_mode = pGC->subWindowMode; - - /* Graphics exposures are not needed on the back-ends since they can - be generated on the front-end thereby saving bandwidth. */ - if (mask & GCGraphicsExposures) mask &= ~GCGraphicsExposures; - - if (mask & GCClipXOrigin) v.clip_x_origin = pGC->clipOrg.x; - if (mask & GCClipYOrigin) v.clip_y_origin = pGC->clipOrg.y; - if (mask & GCClipMask) mask &= ~GCClipMask; /* See ChangeClip */ - if (mask & GCDashOffset) v.dash_offset = pGC->dashOffset; - if (mask & GCDashList) { - mask &= ~GCDashList; - if (dmxScreen->beDisplay) - XSetDashes(dmxScreen->beDisplay, pGCPriv->gc, - pGC->dashOffset, (char *)pGC->dash, - pGC->numInDashList); - } - if (mask & GCArcMode) v.arc_mode = pGC->arcMode; - - if (mask && dmxScreen->beDisplay) { - XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v); - dmxSync(dmxScreen, FALSE); - } - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Copy \a pGCSrc to \a pGCDst on the back-end server associated with - * \a pGCSrc's screen. */ -void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) -{ - ScreenPtr pScreen = pGCSrc->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCSrcPriv = DMX_GET_GC_PRIV(pGCSrc); - dmxGCPrivPtr pGCDstPriv = DMX_GET_GC_PRIV(pGCDst); - - DMX_GC_FUNC_PROLOGUE(pGCDst); - pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst); - - /* Copy the GC on the back-end server */ - if (dmxScreen->beDisplay) - XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc); - - DMX_GC_FUNC_EPILOGUE(pGCDst); -} - -/** Free the \a pGC on the back-end server. */ -Bool dmxBEFreeGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - - if (pGCPriv->gc) { - XFreeGC(dmxScreen->beDisplay, pGCPriv->gc); - pGCPriv->gc = NULL; - return TRUE; - } - - return FALSE; -} - -/** Destroy the graphics context, \a pGC and free the corresponding GC - * on the back-end server. */ -void dmxDestroyGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - DMX_GC_FUNC_PROLOGUE(pGC); - - /* Free the GC on the back-end server */ - if (dmxScreen->beDisplay) - dmxBEFreeGC(pGC); - - pGC->funcs->DestroyGC(pGC); - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Change the clip rects for a GC. */ -void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - XRectangle *pRects; - BoxPtr pBox; - int i, nRects; - - DMX_GC_FUNC_PROLOGUE(pGC); - pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); - - /* Set the client clip on the back-end server */ - switch (pGC->clientClipType) { - case CT_NONE: - if (dmxScreen->beDisplay) - XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); - break; - - case CT_REGION: - if (dmxScreen->beDisplay) { - nRects = REGION_NUM_RECTS((RegionPtr)pGC->clientClip); - pRects = xalloc(nRects * sizeof(*pRects)); - pBox = REGION_RECTS((RegionPtr)pGC->clientClip); - - for (i = 0; i < nRects; i++) { - pRects[i].x = pBox[i].x1; - pRects[i].y = pBox[i].y1; - pRects[i].width = pBox[i].x2 - pBox[i].x1; - pRects[i].height = pBox[i].y2 - pBox[i].y1; - } - - XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc, - pGC->clipOrg.x, pGC->clipOrg.y, - pRects, nRects, Unsorted); - - xfree(pRects); - } - break; - - case CT_PIXMAP: - case CT_UNSORTED: - case CT_YSORTED: - case CT_YXSORTED: - case CT_YXBANDED: - /* These clip types are condensed down to either NONE or REGION - in the mi code */ - break; - } - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Destroy a GC's clip rects. */ -void dmxDestroyClip(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - - DMX_GC_FUNC_PROLOGUE(pGC); - pGC->funcs->DestroyClip(pGC); - - /* Set the client clip on the back-end server to None */ - if (dmxScreen->beDisplay) - XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Copy a GC's clip rects. */ -void dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc) -{ - DMX_GC_FUNC_PROLOGUE(pGCDst); - pGCDst->funcs->CopyClip(pGCDst, pGCSrc); - DMX_GC_FUNC_EPILOGUE(pGCDst); -} +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Kevin E. Martin + * + */ + +/** \file + * This file provides support for GCs. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxgc.h" +#include "dmxgcops.h" +#include "dmxpixmap.h" +#include "dmxfont.h" + +#include "gcstruct.h" +#include "pixmapstr.h" +#include "migc.h" + +static GCFuncs dmxGCFuncs = { + dmxValidateGC, + dmxChangeGC, + dmxCopyGC, + dmxDestroyGC, + dmxChangeClip, + dmxDestroyClip, + dmxCopyClip, +}; + +static GCOps dmxGCOps = { + dmxFillSpans, + dmxSetSpans, + dmxPutImage, + dmxCopyArea, + dmxCopyPlane, + dmxPolyPoint, + dmxPolylines, + dmxPolySegment, + dmxPolyRectangle, + dmxPolyArc, + dmxFillPolygon, + dmxPolyFillRect, + dmxPolyFillArc, + dmxPolyText8, + dmxPolyText16, + dmxImageText8, + dmxImageText16, + dmxImageGlyphBlt, + dmxPolyGlyphBlt, + dmxPushPixels +}; + +/** Initialize the GC on \a pScreen */ +Bool dmxInitGC(ScreenPtr pScreen) +{ + if (!dixRequestPrivate(dmxGCPrivateKey, sizeof(dmxGCPrivRec))) + return FALSE; + return TRUE; +} + +/** Create the GC on the back-end server. */ +void dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + int i; + + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) { + unsigned long mask; + XGCValues gcvals; + + mask = GCGraphicsExposures; + gcvals.graphics_exposures = FALSE; + + /* Create GC in the back-end servers */ + pGCPriv->gc = XCreateGC(dmxScreen->beDisplay, + dmxScreen->scrnDefDrawables[i], + mask, &gcvals); + break; + } + } +} + +/** Create a graphics context on the back-end server associated /a pGC's + * screen. */ +Bool dmxCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + Bool ret; + + DMX_UNWRAP(CreateGC, dmxScreen, pScreen); + if ((ret = pScreen->CreateGC(pGC))) { + /* Save the old funcs */ + pGCPriv->funcs = pGC->funcs; + pGCPriv->ops = NULL; + + pGC->funcs = &dmxGCFuncs; + + if (dmxScreen->beDisplay) { + dmxBECreateGC(pScreen, pGC); + } else { + pGCPriv->gc = NULL; + } + + /* Check for "magic special case" + * 1. see CreateGC in dix/gc.c for more info + * 2. see dmxChangeGC for more info + */ + pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap); + } + DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); + + return ret; +} + +/** Validate a graphics context, \a pGC, locally in the DMX server and + * recompute the composite clip, if necessary. */ +void dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + + DMX_GC_FUNC_PROLOGUE(pGC); +#if 0 + pGC->funcs->ValidateGC(pGC, changes, pDrawable); +#endif + + if (pDrawable->type == DRAWABLE_WINDOW || + pDrawable->type == DRAWABLE_PIXMAP) { + /* Save the old ops, since we're about to change the ops in the + * epilogue. + */ + pGCPriv->ops = pGC->ops; + } else { + pGCPriv->ops = NULL; + } + + /* If the client clip is different or moved OR the subwindowMode has + * changed OR the window's clip has changed since the last + * validation, then we need to recompute the composite clip. + */ + if ((changes & (GCClipXOrigin | + GCClipYOrigin | + GCClipMask | + GCSubwindowMode)) || + (pDrawable->serialNumber != + (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) { + miComputeCompositeClip(pGC, pDrawable); + } + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Set the values in the graphics context on the back-end server + * associated with \a pGC's screen. */ +void dmxChangeGC(GCPtr pGC, unsigned long mask) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + XGCValues v; + + DMX_GC_FUNC_PROLOGUE(pGC); +#if 0 + pGC->funcs->ChangeGC(pGC, mask); +#endif + + /* Handle "magic special case" from CreateGC */ + if (pGCPriv->msc) { + /* The "magic special case" is used to handle the case where a + * foreground pixel is set when the GC is created so that a + * "pseudo default-tile" can be created and used in case the + * fillstyle was set to FillTiled. This specific case is tested + * in xtest (XCreateGC test #3). What has happened in dix by + * the time it reaches here is (1) the pGC->tile.pixel has been + * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a + * tile has also been set, then pGC->tileIsPixel is unset and + * pGC->tile.pixmap is initialized; else, the default tile is + * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is + * initialized to the "pseudo default-tile". In either case, + * pGC->tile.pixmap is set; however, in the "magic special case" + * the mask is not updated to allow us to detect that we should + * initialize the GCTile in the back-end server. Thus, we catch + * this case in dmxCreateGC and add GCTile to the mask here. + * Are there any cases that I've missed? + */ + + /* Make sure that the tile.pixmap is set, just in case the user + * set GCTile in the mask but forgot to set vals.pixmap + */ + if (pGC->tile.pixmap) mask |= GCTile; + + /* This only happens once when the GC is created */ + pGCPriv->msc = FALSE; + } + + /* Update back-end server's gc */ + if (mask & GCFunction) v.function = pGC->alu; + if (mask & GCPlaneMask) v.plane_mask = pGC->planemask; + if (mask & GCForeground) v.foreground = pGC->fgPixel; + if (mask & GCBackground) v.background = pGC->bgPixel; + if (mask & GCLineWidth) v.line_width = pGC->lineWidth; + if (mask & GCLineStyle) v.line_style = pGC->lineStyle; + if (mask & GCCapStyle) v.cap_style = pGC->capStyle; + if (mask & GCJoinStyle) v.join_style = pGC->joinStyle; + if (mask & GCFillStyle) v.fill_style = pGC->fillStyle; + if (mask & GCFillRule) v.fill_rule = pGC->fillRule; + if (mask & GCTile) { + if (pGC->tileIsPixel) { + mask &= ~GCTile; + } else { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap); + v.tile = (Drawable)pPixPriv->pixmap; + } + } + if (mask & GCStipple) { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple); + v.stipple = (Drawable)pPixPriv->pixmap; + } + if (mask & GCTileStipXOrigin) v.ts_x_origin = pGC->patOrg.x; + if (mask & GCTileStipYOrigin) v.ts_y_origin = pGC->patOrg.y; + if (mask & GCFont) { + if (dmxScreen->beDisplay) { + dmxFontPrivPtr pFontPriv; + pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex); + v.font = pFontPriv->font[pScreen->myNum]->fid; + } else { + mask &= ~GCFont; + } + } + if (mask & GCSubwindowMode) v.subwindow_mode = pGC->subWindowMode; + + /* Graphics exposures are not needed on the back-ends since they can + be generated on the front-end thereby saving bandwidth. */ + if (mask & GCGraphicsExposures) mask &= ~GCGraphicsExposures; + + if (mask & GCClipXOrigin) v.clip_x_origin = pGC->clipOrg.x; + if (mask & GCClipYOrigin) v.clip_y_origin = pGC->clipOrg.y; + if (mask & GCClipMask) mask &= ~GCClipMask; /* See ChangeClip */ + if (mask & GCDashOffset) v.dash_offset = pGC->dashOffset; + if (mask & GCDashList) { + mask &= ~GCDashList; + if (dmxScreen->beDisplay) + XSetDashes(dmxScreen->beDisplay, pGCPriv->gc, + pGC->dashOffset, (char *)pGC->dash, + pGC->numInDashList); + } + if (mask & GCArcMode) v.arc_mode = pGC->arcMode; + + if (mask && dmxScreen->beDisplay) { + XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v); + dmxSync(dmxScreen, FALSE); + } + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Copy \a pGCSrc to \a pGCDst on the back-end server associated with + * \a pGCSrc's screen. */ +void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) +{ + ScreenPtr pScreen = pGCSrc->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCSrcPriv = DMX_GET_GC_PRIV(pGCSrc); + dmxGCPrivPtr pGCDstPriv = DMX_GET_GC_PRIV(pGCDst); + + DMX_GC_FUNC_PROLOGUE(pGCDst); + pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst); + + /* Copy the GC on the back-end server */ + if (dmxScreen->beDisplay) + XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc); + + DMX_GC_FUNC_EPILOGUE(pGCDst); +} + +/** Free the \a pGC on the back-end server. */ +Bool dmxBEFreeGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + + if (pGCPriv->gc) { + XFreeGC(dmxScreen->beDisplay, pGCPriv->gc); + pGCPriv->gc = NULL; + return TRUE; + } + + return FALSE; +} + +/** Destroy the graphics context, \a pGC and free the corresponding GC + * on the back-end server. */ +void dmxDestroyGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + DMX_GC_FUNC_PROLOGUE(pGC); + + /* Free the GC on the back-end server */ + if (dmxScreen->beDisplay) + dmxBEFreeGC(pGC); + + pGC->funcs->DestroyGC(pGC); + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Change the clip rects for a GC. */ +void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + XRectangle *pRects; + BoxPtr pBox; + int i, nRects; + + DMX_GC_FUNC_PROLOGUE(pGC); + pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); + + /* Set the client clip on the back-end server */ + switch (pGC->clientClipType) { + case CT_NONE: + if (dmxScreen->beDisplay) + XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); + break; + + case CT_REGION: + if (dmxScreen->beDisplay) { + nRects = REGION_NUM_RECTS((RegionPtr)pGC->clientClip); + pRects = malloc(nRects * sizeof(*pRects)); + pBox = REGION_RECTS((RegionPtr)pGC->clientClip); + + for (i = 0; i < nRects; i++) { + pRects[i].x = pBox[i].x1; + pRects[i].y = pBox[i].y1; + pRects[i].width = pBox[i].x2 - pBox[i].x1; + pRects[i].height = pBox[i].y2 - pBox[i].y1; + } + + XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc, + pGC->clipOrg.x, pGC->clipOrg.y, + pRects, nRects, Unsorted); + + free(pRects); + } + break; + + case CT_PIXMAP: + case CT_UNSORTED: + case CT_YSORTED: + case CT_YXSORTED: + case CT_YXBANDED: + /* These clip types are condensed down to either NONE or REGION + in the mi code */ + break; + } + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Destroy a GC's clip rects. */ +void dmxDestroyClip(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + + DMX_GC_FUNC_PROLOGUE(pGC); + pGC->funcs->DestroyClip(pGC); + + /* Set the client clip on the back-end server to None */ + if (dmxScreen->beDisplay) + XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Copy a GC's clip rects. */ +void dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc) +{ + DMX_GC_FUNC_PROLOGUE(pGCDst); + pGCDst->funcs->CopyClip(pGCDst, pGCSrc); + DMX_GC_FUNC_EPILOGUE(pGCDst); +} diff --git a/xorg-server/hw/dmx/dmxinit.c b/xorg-server/hw/dmx/dmxinit.c index cc9ea0b97..94643ea94 100644 --- a/xorg-server/hw/dmx/dmxinit.c +++ b/xorg-server/hw/dmx/dmxinit.c @@ -1,1037 +1,1037 @@ -/* - * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Kevin E. Martin - * David H. Dawes - * Rickard E. (Rik) Faith - * - */ - -/** \file - * Provide expected functions for initialization from the ddx layer and - * global variables for the DMX server. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxinit.h" -#include "dmxsync.h" -#include "dmxlog.h" -#include "dmxinput.h" -#include "dmxscrinit.h" -#include "dmxcursor.h" -#include "dmxfont.h" -#include "config/dmxconfig.h" -#include "dmxcb.h" -#include "dmxprop.h" -#include "dmxstat.h" -#include "dmxpict.h" - -#include /* For gettimeofday */ -#include "dixstruct.h" -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -#include /* For SIGQUIT */ - -#ifdef GLXEXT -#include -#include -#include "dmx_glxvisuals.h" -#include -#include - -extern void GlxSetVisualConfigs( - int nconfigs, - __GLXvisualConfig *configs, - void **configprivs -); -#endif /* GLXEXT */ - -/* Global variables available to all Xserver/hw/dmx routines. */ -int dmxNumScreens; -DMXScreenInfo *dmxScreens; - -int dmxNumInputs; -DMXInputInfo *dmxInputs; - -int dmxShadowFB = FALSE; - -XErrorEvent dmxLastErrorEvent; -Bool dmxErrorOccurred = FALSE; - -char *dmxFontPath = NULL; - -Bool dmxOffScreenOpt = TRUE; - -Bool dmxSubdividePrimitives = TRUE; - -Bool dmxLazyWindowCreation = TRUE; - -Bool dmxUseXKB = TRUE; - -int dmxDepth = 0; - -#ifndef GLXEXT -static Bool dmxGLXProxy = FALSE; -#else -Bool dmxGLXProxy = TRUE; - -Bool dmxGLXSwapGroupSupport = TRUE; - -Bool dmxGLXSyncSwap = FALSE; - -Bool dmxGLXFinishSwap = FALSE; -#endif - -Bool dmxIgnoreBadFontPaths = FALSE; - -Bool dmxAddRemoveScreens = FALSE; - -/* dmxErrorHandler catches errors that occur when calling one of the - * back-end servers. Some of this code is based on _XPrintDefaultError - * in xc/lib/X11/XlibInt.c */ -static int dmxErrorHandler(Display *dpy, XErrorEvent *ev) -{ -#define DMX_ERROR_BUF_SIZE 256 - /* RATS: these buffers are only used in - * length-limited calls. */ - char buf[DMX_ERROR_BUF_SIZE]; - char request[DMX_ERROR_BUF_SIZE]; - _XExtension *ext = NULL; - - dmxErrorOccurred = TRUE; - dmxLastErrorEvent = *ev; - - XGetErrorText(dpy, ev->error_code, buf, sizeof(buf)); - dmxLog(dmxWarning, "dmxErrorHandler: %s\n", buf); - - /* Find major opcode name */ - if (ev->request_code < 128) { - XmuSnprintf(request, sizeof(request), "%d", ev->request_code); - XGetErrorDatabaseText(dpy, "XRequest", request, "", buf, sizeof(buf)); - } else { - for (ext = dpy->ext_procs; - ext && ext->codes.major_opcode != ev->request_code; - ext = ext->next); - if (ext) strncpy(buf, ext->name, sizeof(buf)); - else buf[0] = '\0'; - } - dmxLog(dmxWarning, " Major opcode: %d (%s)\n", - ev->request_code, buf); - - /* Find minor opcode name */ - if (ev->request_code >= 128 && ext) { - XmuSnprintf(request, sizeof(request), "%d", ev->request_code); - XmuSnprintf(request, sizeof(request), "%s.%d", - ext->name, ev->minor_code); - XGetErrorDatabaseText(dpy, "XRequest", request, "", buf, sizeof(buf)); - dmxLog(dmxWarning, " Minor opcode: %d (%s)\n", - ev->minor_code, buf); - } - - /* Provide value information */ - switch (ev->error_code) { - case BadValue: - dmxLog(dmxWarning, " Value: 0x%x\n", - ev->resourceid); - break; - case BadAtom: - dmxLog(dmxWarning, " AtomID: 0x%x\n", - ev->resourceid); - break; - default: - dmxLog(dmxWarning, " ResourceID: 0x%x\n", - ev->resourceid); - break; - } - - /* Provide serial number information */ - dmxLog(dmxWarning, " Failed serial number: %d\n", - ev->serial); - dmxLog(dmxWarning, " Current serial number: %d\n", - dpy->request); - return 0; -} - -#ifdef GLXEXT -static int dmxNOPErrorHandler(Display *dpy, XErrorEvent *ev) -{ - return 0; -} -#endif - -Bool dmxOpenDisplay(DMXScreenInfo *dmxScreen) -{ - if (!(dmxScreen->beDisplay = XOpenDisplay(dmxScreen->name))) - return FALSE; - - dmxPropertyDisplay(dmxScreen); - return TRUE; -} - -void dmxSetErrorHandler(DMXScreenInfo *dmxScreen) -{ - XSetErrorHandler(dmxErrorHandler); -} - -static void dmxPrintScreenInfo(DMXScreenInfo *dmxScreen) -{ - XWindowAttributes attribs; - int ndepths = 0, *depths = NULL; - int i; - Display *dpy = dmxScreen->beDisplay; - Screen *s = DefaultScreenOfDisplay(dpy); - int scr = DefaultScreen(dpy); - - XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs); - if (!(depths = XListDepths(dpy, scr, &ndepths))) ndepths = 0; - - dmxLogOutput(dmxScreen, "Name of display: %s\n", DisplayString(dpy)); - dmxLogOutput(dmxScreen, "Version number: %d.%d\n", - ProtocolVersion(dpy), ProtocolRevision(dpy)); - dmxLogOutput(dmxScreen, "Vendor string: %s\n", ServerVendor(dpy)); - if (!strstr(ServerVendor(dpy), "XFree86")) { - dmxLogOutput(dmxScreen, "Vendor release: %d\n", VendorRelease(dpy)); - } else { - /* This code based on xdpyinfo.c */ - int v = VendorRelease(dpy); - int major = -1, minor = -1, patch = -1, subpatch = -1; - - if (v < 336) - major = v / 100, minor = (v / 10) % 10, patch = v % 10; - else if (v < 3900) { - major = v / 1000; - minor = (v / 100) % 10; - if (((v / 10) % 10) || (v % 10)) { - patch = (v / 10) % 10; - if (v % 10) subpatch = v % 10; - } - } else if (v < 40000000) { - major = v / 1000; - minor = (v / 10) % 10; - if (v % 10) patch = v % 10; - } else { - major = v / 10000000; - minor = (v / 100000) % 100; - patch = (v / 1000) % 100; - if (v % 1000) subpatch = v % 1000; - } - dmxLogOutput(dmxScreen, "Vendor release: %d (XFree86 version: %d.%d", - v, major, minor); - if (patch > 0) dmxLogOutputCont(dmxScreen, ".%d", patch); - if (subpatch > 0) dmxLogOutputCont(dmxScreen, ".%d", subpatch); - dmxLogOutputCont(dmxScreen, ")\n"); - } - - - dmxLogOutput(dmxScreen, "Dimensions: %dx%d pixels\n", - attribs.width, attribs.height); - dmxLogOutput(dmxScreen, "%d depths on screen %d: ", ndepths, scr); - for (i = 0; i < ndepths; i++) - dmxLogOutputCont(dmxScreen, "%c%d", i ? ',' : ' ', depths[i]); - dmxLogOutputCont(dmxScreen, "\n"); - dmxLogOutput(dmxScreen, "Depth of root window: %d plane%s (%d)\n", - attribs.depth, attribs.depth == 1 ? "" : "s", - DisplayPlanes(dpy, scr)); - dmxLogOutput(dmxScreen, "Number of colormaps: %d min, %d max\n", - MinCmapsOfScreen(s), MaxCmapsOfScreen(s)); - dmxLogOutput(dmxScreen, "Options: backing-store %s, save-unders %s\n", - (DoesBackingStore (s) == NotUseful) ? "no" : - ((DoesBackingStore (s) == Always) ? "yes" : "when mapped"), - DoesSaveUnders (s) ? "yes" : "no"); - dmxLogOutput(dmxScreen, "Window Manager running: %s\n", - (dmxScreen->WMRunningOnBE) ? "yes" : "no"); - - if (dmxScreen->WMRunningOnBE) { - dmxLogOutputWarning(dmxScreen, - "Window manager running " - "-- colormaps not supported\n"); - } - XFree(depths); -} - -void dmxGetScreenAttribs(DMXScreenInfo *dmxScreen) -{ - XWindowAttributes attribs; - Display *dpy = dmxScreen->beDisplay; -#ifdef GLXEXT - int dummy; -#endif - - XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs); - - dmxScreen->beWidth = attribs.width; - dmxScreen->beHeight = attribs.height; - - /* Fill in missing geometry information */ - if (dmxScreen->scrnXSign < 0) { - if (dmxScreen->scrnWidth) { - dmxScreen->scrnX = (attribs.width - dmxScreen->scrnWidth - - dmxScreen->scrnX); - } else { - dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX; - dmxScreen->scrnX = 0; - } - } - if (dmxScreen->scrnYSign < 0) { - if (dmxScreen->scrnHeight) { - dmxScreen->scrnY = (attribs.height - dmxScreen->scrnHeight - - dmxScreen->scrnY); - } else { - dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY; - dmxScreen->scrnY = 0; - } - } - if (!dmxScreen->scrnWidth) - dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX; - if (!dmxScreen->scrnHeight) - dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY; - - if (!dmxScreen->rootWidth) dmxScreen->rootWidth = dmxScreen->scrnWidth; - if (!dmxScreen->rootHeight) dmxScreen->rootHeight = dmxScreen->scrnHeight; - if (dmxScreen->rootWidth + dmxScreen->rootX > dmxScreen->scrnWidth) - dmxScreen->rootWidth = dmxScreen->scrnWidth - dmxScreen->rootX; - if (dmxScreen->rootHeight + dmxScreen->rootY > dmxScreen->scrnHeight) - dmxScreen->rootHeight = dmxScreen->scrnHeight - dmxScreen->rootY; - - /* FIXME: Get these from the back-end server */ - dmxScreen->beXDPI = 75; - dmxScreen->beYDPI = 75; - - dmxScreen->beDepth = attribs.depth; /* FIXME: verify that this - * works always. In - * particular, this will work - * well for depth=16, will fail - * because of colormap issues - * at depth 8. More work needs - * to be done here. */ - - if (dmxScreen->beDepth <= 8) dmxScreen->beBPP = 8; - else if (dmxScreen->beDepth <= 16) dmxScreen->beBPP = 16; - else dmxScreen->beBPP = 32; - -#ifdef GLXEXT - /* get the majorOpcode for the back-end GLX extension */ - XQueryExtension(dpy, "GLX", &dmxScreen->glxMajorOpcode, - &dummy, &dmxScreen->glxErrorBase); -#endif - - dmxPrintScreenInfo(dmxScreen); - dmxLogOutput(dmxScreen, "%dx%d+%d+%d on %dx%d at depth=%d, bpp=%d\n", - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, - dmxScreen->beWidth, dmxScreen->beHeight, - dmxScreen->beDepth, dmxScreen->beBPP); - if (dmxScreen->beDepth == 8) - dmxLogOutputWarning(dmxScreen, - "Support for depth == 8 is not complete\n"); -} - -Bool dmxGetVisualInfo(DMXScreenInfo *dmxScreen) -{ - int i; - XVisualInfo visinfo; - - visinfo.screen = DefaultScreen(dmxScreen->beDisplay); - dmxScreen->beVisuals = XGetVisualInfo(dmxScreen->beDisplay, - VisualScreenMask, - &visinfo, - &dmxScreen->beNumVisuals); - - dmxScreen->beDefVisualIndex = -1; - - if (defaultColorVisualClass >= 0 || dmxDepth > 0) { - for (i = 0; i < dmxScreen->beNumVisuals; i++) - if (defaultColorVisualClass >= 0) { - if (dmxScreen->beVisuals[i].class == defaultColorVisualClass) { - if (dmxDepth > 0) { - if (dmxScreen->beVisuals[i].depth == dmxDepth) { - dmxScreen->beDefVisualIndex = i; - break; - } - } else { - dmxScreen->beDefVisualIndex = i; - break; - } - } - } else if (dmxScreen->beVisuals[i].depth == dmxDepth) { - dmxScreen->beDefVisualIndex = i; - break; - } - } else { - visinfo.visualid = - XVisualIDFromVisual(DefaultVisual(dmxScreen->beDisplay, - visinfo.screen)); - - for (i = 0; i < dmxScreen->beNumVisuals; i++) - if (visinfo.visualid == dmxScreen->beVisuals[i].visualid) { - dmxScreen->beDefVisualIndex = i; - break; - } - } - - for (i = 0; i < dmxScreen->beNumVisuals; i++) - dmxLogVisual(dmxScreen, &dmxScreen->beVisuals[i], - (i == dmxScreen->beDefVisualIndex)); - - return (dmxScreen->beDefVisualIndex >= 0); -} - -void dmxGetColormaps(DMXScreenInfo *dmxScreen) -{ - int i; - - dmxScreen->beNumDefColormaps = dmxScreen->beNumVisuals; - dmxScreen->beDefColormaps = xalloc(dmxScreen->beNumDefColormaps * - sizeof(*dmxScreen->beDefColormaps)); - - for (i = 0; i < dmxScreen->beNumDefColormaps; i++) - dmxScreen->beDefColormaps[i] = - XCreateColormap(dmxScreen->beDisplay, - DefaultRootWindow(dmxScreen->beDisplay), - dmxScreen->beVisuals[i].visual, - AllocNone); - - dmxScreen->beBlackPixel = BlackPixel(dmxScreen->beDisplay, - DefaultScreen(dmxScreen->beDisplay)); - dmxScreen->beWhitePixel = WhitePixel(dmxScreen->beDisplay, - DefaultScreen(dmxScreen->beDisplay)); -} - -void dmxGetPixmapFormats(DMXScreenInfo *dmxScreen) -{ - dmxScreen->beDepths = - XListDepths(dmxScreen->beDisplay, DefaultScreen(dmxScreen->beDisplay), - &dmxScreen->beNumDepths); - - dmxScreen->bePixmapFormats = - XListPixmapFormats(dmxScreen->beDisplay, - &dmxScreen->beNumPixmapFormats); -} - -static Bool dmxSetPixmapFormats(ScreenInfo *pScreenInfo, - DMXScreenInfo *dmxScreen) -{ - XPixmapFormatValues *bePixmapFormat; - PixmapFormatRec *format; - int i, j; - - pScreenInfo->imageByteOrder = ImageByteOrder(dmxScreen->beDisplay); - pScreenInfo->bitmapScanlineUnit = BitmapUnit(dmxScreen->beDisplay); - pScreenInfo->bitmapScanlinePad = BitmapPad(dmxScreen->beDisplay); - pScreenInfo->bitmapBitOrder = BitmapBitOrder(dmxScreen->beDisplay); - - pScreenInfo->numPixmapFormats = 0; - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - bePixmapFormat = &dmxScreen->bePixmapFormats[i]; - for (j = 0; j < dmxScreen->beNumDepths; j++) - if ((bePixmapFormat->depth == 1) || - (bePixmapFormat->depth == dmxScreen->beDepths[j])) { - format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats]; - - format->depth = bePixmapFormat->depth; - format->bitsPerPixel = bePixmapFormat->bits_per_pixel; - format->scanlinePad = bePixmapFormat->scanline_pad; - - pScreenInfo->numPixmapFormats++; - break; - } - } - - return TRUE; -} - -void dmxCheckForWM(DMXScreenInfo *dmxScreen) -{ - Status status; - XWindowAttributes xwa; - - status = XGetWindowAttributes(dmxScreen->beDisplay, - DefaultRootWindow(dmxScreen->beDisplay), - &xwa); - dmxScreen->WMRunningOnBE = - (status && - ((xwa.all_event_masks & SubstructureRedirectMask) || - (xwa.all_event_masks & SubstructureNotifyMask))); -} - -/** Initialize the display and collect relevant information about the - * display properties */ -static void dmxDisplayInit(DMXScreenInfo *dmxScreen) -{ - if (!dmxOpenDisplay(dmxScreen)) - dmxLog(dmxFatal, - "dmxOpenDisplay: Unable to open display %s\n", - dmxScreen->name); - - dmxSetErrorHandler(dmxScreen); - dmxCheckForWM(dmxScreen); - dmxGetScreenAttribs(dmxScreen); - - if (!dmxGetVisualInfo(dmxScreen)) - dmxLog(dmxFatal, "dmxGetVisualInfo: No matching visuals found\n"); - - dmxGetColormaps(dmxScreen); - dmxGetPixmapFormats(dmxScreen); -} - -/* If this doesn't compile, just add || defined(yoursystem) to the line - * below. This information is to help with bug reports and is not - * critical. */ -#if !defined(_POSIX_SOURCE) -static const char *dmxExecOS(void) { return ""; } -#else -#include -static const char *dmxExecOS(void) -{ - static char buffer[128]; - static int initialized = 0; - struct utsname u; - - if (!initialized++) { - memset(buffer, 0, sizeof(buffer)); - uname(&u); - XmuSnprintf(buffer, sizeof(buffer)-1, "%s %s %s", - u.sysname, u.release, u.version); - } - return buffer; -} -#endif - -static const char *dmxBuildCompiler(void) -{ - static char buffer[128]; - static int initialized = 0; - - if (!initialized++) { - memset(buffer, 0, sizeof(buffer)); -#if defined(__GNUC__) && defined(__GNUC_MINOR__) &&defined(__GNUC_PATCHLEVEL__) - XmuSnprintf(buffer, sizeof(buffer)-1, "gcc %d.%d.%d", - __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); -#endif - } - return buffer; -} - -static const char *dmxExecHost(void) -{ - static char buffer[128]; - static int initialized = 0; - - if (!initialized++) { - memset(buffer, 0, sizeof(buffer)); - XmuGetHostname(buffer, sizeof(buffer) - 1); - } - return buffer; -} - -/** This routine is called in Xserver/dix/main.c from \a main(). */ -void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) -{ - int i; - static unsigned long dmxGeneration = 0; -#ifdef GLXEXT - Bool glxSupported = TRUE; -#endif - - if (dmxGeneration != serverGeneration) { - int vendrel = VENDOR_RELEASE; - int major, minor, year, month, day; - - dmxGeneration = serverGeneration; - - major = vendrel / 100000000; - vendrel -= major * 100000000; - minor = vendrel / 1000000; - vendrel -= minor * 1000000; - year = vendrel / 10000; - vendrel -= year * 10000; - month = vendrel / 100; - vendrel -= month * 100; - day = vendrel; - - /* Add other epoch tests here */ - if (major > 0 && minor > 0) year += 2000; - - dmxLog(dmxInfo, "Generation: %d\n", dmxGeneration); - dmxLog(dmxInfo, "DMX version: %d.%d.%02d%02d%02d (%s)\n", - major, minor, year, month, day, VENDOR_STRING); - - SetVendorRelease(VENDOR_RELEASE); - SetVendorString(VENDOR_STRING); - - if (dmxGeneration == 1) { - dmxLog(dmxInfo, "DMX Build OS: %s (%s)\n", OSNAME, OSVENDOR); - dmxLog(dmxInfo, "DMX Build Compiler: %s\n", dmxBuildCompiler()); - dmxLog(dmxInfo, "DMX Execution OS: %s\n", dmxExecOS()); - dmxLog(dmxInfo, "DMX Execution Host: %s\n", dmxExecHost()); - } - dmxLog(dmxInfo, "MAXSCREENS: %d\n", MAXSCREENS); - - for (i = 0; i < dmxNumScreens; i++) { - if (dmxScreens[i].beDisplay) - dmxLog(dmxWarning, "Display \"%s\" still open\n", - dmxScreens[i].name); - dmxStatFree(dmxScreens[i].stat); - dmxScreens[i].stat = NULL; - } - for (i = 0; i < dmxNumInputs; i++) dmxInputFree(&dmxInputs[i]); - if (dmxScreens) free(dmxScreens); - if (dmxInputs) free(dmxInputs); - dmxScreens = NULL; - dmxInputs = NULL; - dmxNumScreens = 0; - dmxNumInputs = 0; - } - - /* Make sure that the command-line arguments are sane. */ - if (dmxAddRemoveScreens && dmxGLXProxy) { - /* Currently it is not possible to support GLX and Render - * extensions with dynamic screen addition/removal due to the - * state that each extension keeps, which cannot be restored. */ - dmxLog(dmxWarning, - "GLX Proxy and Render extensions do not yet support dynamic\n"); - dmxLog(dmxWarning, - "screen addition and removal. Please specify -noglxproxy\n"); - dmxLog(dmxWarning, - "and -norender on the command line or in the configuration\n"); - dmxLog(dmxWarning, - "file to disable these two extensions if you wish to use\n"); - dmxLog(dmxWarning, - "the dynamic addition and removal of screens support.\n"); - dmxLog(dmxFatal, - "Dynamic screen addition/removal error (see above).\n"); - } - - /* ddxProcessArgument has been called at this point, but any data - * from the configuration file has not been applied. Do so, and be - * sure we have at least one back-end display. */ - dmxConfigConfigure(); - if (!dmxNumScreens) - dmxLog(dmxFatal, "InitOutput: no back-end displays found\n"); - if (!dmxNumInputs) - dmxLog(dmxInfo, "InitOutput: no inputs found\n"); - - /* Disable lazy window creation optimization if offscreen - * optimization is disabled */ - if (!dmxOffScreenOpt && dmxLazyWindowCreation) { - dmxLog(dmxInfo, - "InitOutput: Disabling lazy window creation optimization\n"); - dmxLog(dmxInfo, - " since it requires the offscreen optimization\n"); - dmxLog(dmxInfo, - " to function properly.\n"); - dmxLazyWindowCreation = FALSE; - } - - /* Open each display and gather information about it. */ - for (i = 0; i < dmxNumScreens; i++) - dmxDisplayInit(&dmxScreens[i]); - -#if PANORAMIX - /* Register a Xinerama callback which will run from within - * PanoramiXCreateConnectionBlock. We can use the callback to - * determine if Xinerama is loaded and to check the visuals - * determined by PanoramiXConsolidate. */ - XineramaRegisterConnectionBlockCallback(dmxConnectionBlockCallback); -#endif - - /* Since we only have a single screen thus far, we only need to set - the pixmap formats to match that screen. FIXME: this isn't true.*/ - if (!dmxSetPixmapFormats(pScreenInfo, &dmxScreens[0])) return; - - /* Might want to install a signal handler to allow cleaning up after - * unexpected signals. The DIX/OS layer already handles SIGINT and - * SIGTERM, so everything is OK for expected signals. --DD - * - * SIGHUP, SIGINT, and SIGTERM are trapped in os/connection.c - * SIGQUIT is another common signal that is sent from the keyboard. - * Trap it here, to ensure that the keyboard modifier map and other - * state for the input devices are restored. (This makes the - * behavior of SIGQUIT somewhat unexpected, since it will be the - * same as the behavior of SIGINT. However, leaving the modifier - * map of the input devices empty is even more unexpected.) --RF - */ - OsSignal(SIGQUIT, GiveUp); - -#ifdef GLXEXT - /* Check if GLX extension exists on all back-end servers */ - for (i = 0; i < dmxNumScreens; i++) - glxSupported &= (dmxScreens[i].glxMajorOpcode > 0); -#endif - - /* Tell dix layer about the backend displays */ - for (i = 0; i < dmxNumScreens; i++) { - -#ifdef GLXEXT - if (glxSupported) { - /* - * Builds GLX configurations from the list of visuals - * supported by the back-end server, and give that - * configuration list to the glx layer - so that he will - * build the visuals accordingly. - */ - - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - __GLXvisualConfig *configs = NULL; - dmxGlxVisualPrivate **configprivs = NULL; - int nconfigs = 0; - int (*oldErrorHandler)(Display *, XErrorEvent *); - int i; - - /* Catch errors if when using an older GLX w/o FBconfigs */ - oldErrorHandler = XSetErrorHandler(dmxNOPErrorHandler); - - /* Get FBConfigs of the back-end server */ - dmxScreen->fbconfigs = GetGLXFBConfigs(dmxScreen->beDisplay, - dmxScreen->glxMajorOpcode, - &dmxScreen->numFBConfigs); - - XSetErrorHandler(oldErrorHandler); - - dmxScreen->glxVisuals = - GetGLXVisualConfigs(dmxScreen->beDisplay, - DefaultScreen(dmxScreen->beDisplay), - &dmxScreen->numGlxVisuals); - - if (dmxScreen->fbconfigs) { - configs = - GetGLXVisualConfigsFromFBConfigs(dmxScreen->fbconfigs, - dmxScreen->numFBConfigs, - dmxScreen->beVisuals, - dmxScreen->beNumVisuals, - dmxScreen->glxVisuals, - dmxScreen->numGlxVisuals, - &nconfigs); - } else { - configs = dmxScreen->glxVisuals; - nconfigs = dmxScreen->numGlxVisuals; - } - - configprivs = xalloc(nconfigs * sizeof(dmxGlxVisualPrivate*)); - - if (configs != NULL && configprivs != NULL) { - - /* Initialize our private info for each visual - * (currently only x_visual_depth and x_visual_class) - */ - for (i = 0; i < nconfigs; i++) { - - configprivs[i] = (dmxGlxVisualPrivate *) - xalloc(sizeof(dmxGlxVisualPrivate)); - configprivs[i]->x_visual_depth = 0; - configprivs[i]->x_visual_class = 0; - - /* Find the visual depth */ - if (configs[i].vid > 0) { - int j; - for (j = 0; j < dmxScreen->beNumVisuals; j++) { - if (dmxScreen->beVisuals[j].visualid == - configs[i].vid) { - configprivs[i]->x_visual_depth = - dmxScreen->beVisuals[j].depth; - configprivs[i]->x_visual_class = - dmxScreen->beVisuals[j].class; - break; - } - } - } - } - - /* Hand out the glx configs to glx extension */ - GlxSetVisualConfigs(nconfigs, configs, (void**)configprivs); - - XFlush(dmxScreen->beDisplay); - } - } -#endif /* GLXEXT */ - - AddScreen(dmxScreenInit, argc, argv); - } - - /* Compute origin information. */ - dmxInitOrigins(); - - /* Compute overlap information. */ - dmxInitOverlap(); - - /* Make sure there is a global width/height available */ - dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX); - - /* FIXME: The following is temporarily placed here. When the DMX - * extension is available, it will be move there. - */ - dmxInitFonts(); - - /* Initialize the render extension */ - if (!noRenderExtension) - dmxInitRender(); - - /* Initialized things that need timer hooks */ - dmxStatInit(); - dmxSyncInit(); /* Calls RegisterBlockAndWakeupHandlers */ - - dmxLog(dmxInfo, "Shadow framebuffer support %s\n", - dmxShadowFB ? "enabled" : "disabled"); -} - -/* RATS: Assuming the fp string (which comes from the command-line argv - vector) is NULL-terminated, the buffer is large enough for the - strcpy. */ -static void dmxSetDefaultFontPath(char *fp) -{ - int fplen = strlen(fp) + 1; - - if (dmxFontPath) { - int len; - - len = strlen(dmxFontPath); - dmxFontPath = xrealloc(dmxFontPath, len+fplen+1); - dmxFontPath[len] = ','; - strncpy(&dmxFontPath[len+1], fp, fplen); - } else { - dmxFontPath = xalloc(fplen); - strncpy(dmxFontPath, fp, fplen); - } - - defaultFontPath = dmxFontPath; -} - -/** This function is called in Xserver/os/utils.c from \a AbortServer(). - * We must ensure that backend and console state is restored in the - * event the server shutdown wasn't clean. */ -void AbortDDX(void) -{ - int i; - - for (i=0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - - if (dmxScreen->beDisplay) XCloseDisplay(dmxScreen->beDisplay); - dmxScreen->beDisplay = NULL; - } -} - -#ifdef DDXBEFORERESET -void ddxBeforeReset(void) -{ -} -#endif - -/** This function is called in Xserver/dix/main.c from \a main() when - * dispatchException & DE_TERMINATE (which is the only way to exit the - * main loop without an interruption. */ -void ddxGiveUp(void) -{ - AbortDDX(); -} - -/** This function is called in Xserver/os/osinit.c from \a OsInit(). */ -void OsVendorInit(void) -{ -} - -/** This function is called in Xserver/os/utils.c from \a FatalError() - * and \a VFatalError(). (Note that setting the function pointer \a - * OsVendorVErrorFProc will cause \a VErrorF() (which is called by the - * two routines mentioned here, as well as by others) to use the - * referenced routine instead of \a vfprintf().) */ -void OsVendorFatalError(void) -{ -} - -/** Process our command line arguments. */ -int ddxProcessArgument(int argc, char *argv[], int i) -{ - int retval = 0; - - if (!strcmp(argv[i], "-display")) { - if (++i < argc) dmxConfigStoreDisplay(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-inputfrom") || !strcmp(argv[i], "-input")) { - if (++i < argc) dmxConfigStoreInput(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-xinputfrom") || !strcmp(argv[i],"-xinput")) { - if (++i < argc) dmxConfigStoreXInput(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-noshadowfb")) { - dmxLog(dmxWarning, - "-noshadowfb has been deprecated " - "since it is now the default\n"); - dmxShadowFB = FALSE; - retval = 1; - } else if (!strcmp(argv[i], "-nomulticursor")) { - dmxCursorNoMulti(); - retval = 1; - } else if (!strcmp(argv[i], "-shadowfb")) { - dmxShadowFB = TRUE; - retval = 1; - } else if (!strcmp(argv[i], "-configfile")) { - if (++i < argc) dmxConfigStoreFile(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-config")) { - if (++i < argc) dmxConfigStoreConfig(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-fontpath")) { - if (++i < argc) dmxSetDefaultFontPath(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-stat")) { - if ((i += 2) < argc) dmxStatActivate(argv[i-1], argv[i]); - retval = 3; - } else if (!strcmp(argv[i], "-syncbatch")) { - if (++i < argc) dmxSyncActivate(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-nooffscreenopt")) { - dmxOffScreenOpt = FALSE; - retval = 1; - } else if (!strcmp(argv[i], "-nosubdivprims")) { - dmxSubdividePrimitives = FALSE; - retval = 1; - } else if (!strcmp(argv[i], "-nowindowopt")) { - dmxLazyWindowCreation = FALSE; - retval = 1; - } else if (!strcmp(argv[i], "-noxkb")) { - dmxUseXKB = FALSE; - retval = 1; - } else if (!strcmp(argv[i], "-depth")) { - if (++i < argc) dmxDepth = atoi(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-norender")) { - noRenderExtension = TRUE; - retval = 1; -#ifdef GLXEXT - } else if (!strcmp(argv[i], "-noglxproxy")) { - dmxGLXProxy = FALSE; - retval = 1; - } else if (!strcmp(argv[i], "-noglxswapgroup")) { - dmxGLXSwapGroupSupport = FALSE; - retval = 1; - } else if (!strcmp(argv[i], "-glxsyncswap")) { - dmxGLXSyncSwap = TRUE; - retval = 1; - } else if (!strcmp(argv[i], "-glxfinishswap")) { - dmxGLXFinishSwap = TRUE; - retval = 1; -#endif - } else if (!strcmp(argv[i], "-ignorebadfontpaths")) { - dmxIgnoreBadFontPaths = TRUE; - retval = 1; - } else if (!strcmp(argv[i], "-addremovescreens")) { - dmxAddRemoveScreens = TRUE; - retval = 1; - } else if (!strcmp(argv[i], "-param")) { - if ((i += 2) < argc) { - if (!strcasecmp(argv[i-1], "xkbrules")) - dmxConfigSetXkbRules(argv[i]); - else if (!strcasecmp(argv[i-1], "xkbmodel")) - dmxConfigSetXkbModel(argv[i]); - else if (!strcasecmp(argv[i-1], "xkblayout")) - dmxConfigSetXkbLayout(argv[i]); - else if (!strcasecmp(argv[i-1], "xkbvariant")) - dmxConfigSetXkbVariant(argv[i]); - else if (!strcasecmp(argv[i-1], "xkboptions")) - dmxConfigSetXkbOptions(argv[i]); - else - dmxLog(dmxWarning, - "-param requires: XkbRules, XkbModel, XkbLayout," - " XkbVariant, or XkbOptions\n"); - } - retval = 3; - } - if (!serverGeneration) dmxConfigSetMaxScreens(); - return retval; -} - -/** Provide succinct usage information for the DMX server. */ -void ddxUseMsg(void) -{ - ErrorF("\n\nDevice Dependent Usage:\n"); - ErrorF("-display string Specify the back-end display(s)\n"); - ErrorF("-input string Specify input source for core device\n"); - ErrorF("-xinput string Specify input source for XInput device\n"); - ErrorF("-shadowfb Enable shadow frame buffer\n"); - ErrorF("-configfile file Read from a configuration file\n"); - ErrorF("-config config Select a specific configuration\n"); - ErrorF("-nomulticursor Turn of multiple cursor support\n"); - ErrorF("-fontpath Sets the default font path\n"); - ErrorF("-stat inter scrns Print out performance statistics\n"); - ErrorF("-syncbatch inter Set interval for XSync batching\n"); - ErrorF("-nooffscreenopt Disable offscreen optimization\n"); - ErrorF("-nosubdivprims Disable primitive subdivision\n"); - ErrorF(" optimization\n"); - ErrorF("-nowindowopt Disable lazy window creation optimization\n"); - ErrorF("-noxkb Disable use of the XKB extension with\n"); - ErrorF(" backend displays (cf. -kb).\n"); - ErrorF("-depth Specify the default root window depth\n"); - ErrorF("-norender Disable RENDER extension support\n"); -#ifdef GLXEXT - ErrorF("-noglxproxy Disable GLX Proxy\n"); - ErrorF("-noglxswapgroup Disable swap group and swap barrier\n"); - ErrorF(" extensions in GLX proxy\n"); - ErrorF("-glxsyncswap Force XSync after swap buffers\n"); - ErrorF("-glxfinishswap Force glFinish after swap buffers\n"); -#endif - ErrorF("-ignorebadfontpaths Ignore bad font paths during initialization\n"); - ErrorF("-addremovescreens Enable dynamic screen addition/removal\n"); - ErrorF("-param ... Specify configuration parameters (e.g.,\n"); - ErrorF(" XkbRules, XkbModel, XkbLayout, etc.)\n"); - ErrorF("\n"); - ErrorF(" If the -input string matches a -display string, then input\n" - " is taken from that backend display. (XInput cannot be taken\n" - " from a backend display.) Placing \",console\" after the\n" - " display name will force a console window to be opened on\n" - " that display in addition to the backend input. This is\n" - " useful if the backend window does not cover the whole\n" - " physical display.\n\n"); - - ErrorF(" Otherwise, if the -input or -xinput string specifies another\n" - " X display, then a console window will be created on that\n" - " display. Placing \",windows\" or \",nowindows\" after the\n" - " display name will control the display of window outlines in\n" - " the console.\n\n"); - - ErrorF(" -input or -xinput dummy specifies no input.\n"); - ErrorF(" -input or -xinput local specifies the use of a raw keyboard,\n" - " mouse, or other (extension) device:\n" - " -input local,kbd,ps2 will use a ps2 mouse\n" - " -input local,kbd,ms will use a serial mouse\n" - " -input local,usb-kbd,usb-mou will use USB devices \n" - " -xinput local,usb-oth will use a non-mouse and\n" - " non-keyboard USB device with XInput\n\n"); - - ErrorF(" Special Keys:\n"); - ErrorF(" Ctrl-Alt-g Server grab/ungrab (console only)\n"); - ErrorF(" Ctrl-Alt-f Fine (1-pixel) mouse mode (console only)\n"); - ErrorF(" Ctrl-Alt-q Quit (core devices only)\n"); - ErrorF(" Ctrl-Alt-F* Switch to VC (local only)\n"); -} +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Kevin E. Martin + * David H. Dawes + * Rickard E. (Rik) Faith + * + */ + +/** \file + * Provide expected functions for initialization from the ddx layer and + * global variables for the DMX server. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxinit.h" +#include "dmxsync.h" +#include "dmxlog.h" +#include "dmxinput.h" +#include "dmxscrinit.h" +#include "dmxcursor.h" +#include "dmxfont.h" +#include "config/dmxconfig.h" +#include "dmxcb.h" +#include "dmxprop.h" +#include "dmxstat.h" +#include "dmxpict.h" + +#include /* For gettimeofday */ +#include "dixstruct.h" +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +#include /* For SIGQUIT */ + +#ifdef GLXEXT +#include +#include +#include "dmx_glxvisuals.h" +#include +#include + +extern void GlxSetVisualConfigs( + int nconfigs, + __GLXvisualConfig *configs, + void **configprivs +); +#endif /* GLXEXT */ + +/* Global variables available to all Xserver/hw/dmx routines. */ +int dmxNumScreens; +DMXScreenInfo *dmxScreens; + +int dmxNumInputs; +DMXInputInfo *dmxInputs; + +int dmxShadowFB = FALSE; + +XErrorEvent dmxLastErrorEvent; +Bool dmxErrorOccurred = FALSE; + +char *dmxFontPath = NULL; + +Bool dmxOffScreenOpt = TRUE; + +Bool dmxSubdividePrimitives = TRUE; + +Bool dmxLazyWindowCreation = TRUE; + +Bool dmxUseXKB = TRUE; + +int dmxDepth = 0; + +#ifndef GLXEXT +static Bool dmxGLXProxy = FALSE; +#else +Bool dmxGLXProxy = TRUE; + +Bool dmxGLXSwapGroupSupport = TRUE; + +Bool dmxGLXSyncSwap = FALSE; + +Bool dmxGLXFinishSwap = FALSE; +#endif + +Bool dmxIgnoreBadFontPaths = FALSE; + +Bool dmxAddRemoveScreens = FALSE; + +/* dmxErrorHandler catches errors that occur when calling one of the + * back-end servers. Some of this code is based on _XPrintDefaultError + * in xc/lib/X11/XlibInt.c */ +static int dmxErrorHandler(Display *dpy, XErrorEvent *ev) +{ +#define DMX_ERROR_BUF_SIZE 256 + /* RATS: these buffers are only used in + * length-limited calls. */ + char buf[DMX_ERROR_BUF_SIZE]; + char request[DMX_ERROR_BUF_SIZE]; + _XExtension *ext = NULL; + + dmxErrorOccurred = TRUE; + dmxLastErrorEvent = *ev; + + XGetErrorText(dpy, ev->error_code, buf, sizeof(buf)); + dmxLog(dmxWarning, "dmxErrorHandler: %s\n", buf); + + /* Find major opcode name */ + if (ev->request_code < 128) { + XmuSnprintf(request, sizeof(request), "%d", ev->request_code); + XGetErrorDatabaseText(dpy, "XRequest", request, "", buf, sizeof(buf)); + } else { + for (ext = dpy->ext_procs; + ext && ext->codes.major_opcode != ev->request_code; + ext = ext->next); + if (ext) strncpy(buf, ext->name, sizeof(buf)); + else buf[0] = '\0'; + } + dmxLog(dmxWarning, " Major opcode: %d (%s)\n", + ev->request_code, buf); + + /* Find minor opcode name */ + if (ev->request_code >= 128 && ext) { + XmuSnprintf(request, sizeof(request), "%d", ev->request_code); + XmuSnprintf(request, sizeof(request), "%s.%d", + ext->name, ev->minor_code); + XGetErrorDatabaseText(dpy, "XRequest", request, "", buf, sizeof(buf)); + dmxLog(dmxWarning, " Minor opcode: %d (%s)\n", + ev->minor_code, buf); + } + + /* Provide value information */ + switch (ev->error_code) { + case BadValue: + dmxLog(dmxWarning, " Value: 0x%x\n", + ev->resourceid); + break; + case BadAtom: + dmxLog(dmxWarning, " AtomID: 0x%x\n", + ev->resourceid); + break; + default: + dmxLog(dmxWarning, " ResourceID: 0x%x\n", + ev->resourceid); + break; + } + + /* Provide serial number information */ + dmxLog(dmxWarning, " Failed serial number: %d\n", + ev->serial); + dmxLog(dmxWarning, " Current serial number: %d\n", + dpy->request); + return 0; +} + +#ifdef GLXEXT +static int dmxNOPErrorHandler(Display *dpy, XErrorEvent *ev) +{ + return 0; +} +#endif + +Bool dmxOpenDisplay(DMXScreenInfo *dmxScreen) +{ + if (!(dmxScreen->beDisplay = XOpenDisplay(dmxScreen->name))) + return FALSE; + + dmxPropertyDisplay(dmxScreen); + return TRUE; +} + +void dmxSetErrorHandler(DMXScreenInfo *dmxScreen) +{ + XSetErrorHandler(dmxErrorHandler); +} + +static void dmxPrintScreenInfo(DMXScreenInfo *dmxScreen) +{ + XWindowAttributes attribs; + int ndepths = 0, *depths = NULL; + int i; + Display *dpy = dmxScreen->beDisplay; + Screen *s = DefaultScreenOfDisplay(dpy); + int scr = DefaultScreen(dpy); + + XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs); + if (!(depths = XListDepths(dpy, scr, &ndepths))) ndepths = 0; + + dmxLogOutput(dmxScreen, "Name of display: %s\n", DisplayString(dpy)); + dmxLogOutput(dmxScreen, "Version number: %d.%d\n", + ProtocolVersion(dpy), ProtocolRevision(dpy)); + dmxLogOutput(dmxScreen, "Vendor string: %s\n", ServerVendor(dpy)); + if (!strstr(ServerVendor(dpy), "XFree86")) { + dmxLogOutput(dmxScreen, "Vendor release: %d\n", VendorRelease(dpy)); + } else { + /* This code based on xdpyinfo.c */ + int v = VendorRelease(dpy); + int major = -1, minor = -1, patch = -1, subpatch = -1; + + if (v < 336) + major = v / 100, minor = (v / 10) % 10, patch = v % 10; + else if (v < 3900) { + major = v / 1000; + minor = (v / 100) % 10; + if (((v / 10) % 10) || (v % 10)) { + patch = (v / 10) % 10; + if (v % 10) subpatch = v % 10; + } + } else if (v < 40000000) { + major = v / 1000; + minor = (v / 10) % 10; + if (v % 10) patch = v % 10; + } else { + major = v / 10000000; + minor = (v / 100000) % 100; + patch = (v / 1000) % 100; + if (v % 1000) subpatch = v % 1000; + } + dmxLogOutput(dmxScreen, "Vendor release: %d (XFree86 version: %d.%d", + v, major, minor); + if (patch > 0) dmxLogOutputCont(dmxScreen, ".%d", patch); + if (subpatch > 0) dmxLogOutputCont(dmxScreen, ".%d", subpatch); + dmxLogOutputCont(dmxScreen, ")\n"); + } + + + dmxLogOutput(dmxScreen, "Dimensions: %dx%d pixels\n", + attribs.width, attribs.height); + dmxLogOutput(dmxScreen, "%d depths on screen %d: ", ndepths, scr); + for (i = 0; i < ndepths; i++) + dmxLogOutputCont(dmxScreen, "%c%d", i ? ',' : ' ', depths[i]); + dmxLogOutputCont(dmxScreen, "\n"); + dmxLogOutput(dmxScreen, "Depth of root window: %d plane%s (%d)\n", + attribs.depth, attribs.depth == 1 ? "" : "s", + DisplayPlanes(dpy, scr)); + dmxLogOutput(dmxScreen, "Number of colormaps: %d min, %d max\n", + MinCmapsOfScreen(s), MaxCmapsOfScreen(s)); + dmxLogOutput(dmxScreen, "Options: backing-store %s, save-unders %s\n", + (DoesBackingStore (s) == NotUseful) ? "no" : + ((DoesBackingStore (s) == Always) ? "yes" : "when mapped"), + DoesSaveUnders (s) ? "yes" : "no"); + dmxLogOutput(dmxScreen, "Window Manager running: %s\n", + (dmxScreen->WMRunningOnBE) ? "yes" : "no"); + + if (dmxScreen->WMRunningOnBE) { + dmxLogOutputWarning(dmxScreen, + "Window manager running " + "-- colormaps not supported\n"); + } + XFree(depths); +} + +void dmxGetScreenAttribs(DMXScreenInfo *dmxScreen) +{ + XWindowAttributes attribs; + Display *dpy = dmxScreen->beDisplay; +#ifdef GLXEXT + int dummy; +#endif + + XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs); + + dmxScreen->beWidth = attribs.width; + dmxScreen->beHeight = attribs.height; + + /* Fill in missing geometry information */ + if (dmxScreen->scrnXSign < 0) { + if (dmxScreen->scrnWidth) { + dmxScreen->scrnX = (attribs.width - dmxScreen->scrnWidth + - dmxScreen->scrnX); + } else { + dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX; + dmxScreen->scrnX = 0; + } + } + if (dmxScreen->scrnYSign < 0) { + if (dmxScreen->scrnHeight) { + dmxScreen->scrnY = (attribs.height - dmxScreen->scrnHeight + - dmxScreen->scrnY); + } else { + dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY; + dmxScreen->scrnY = 0; + } + } + if (!dmxScreen->scrnWidth) + dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX; + if (!dmxScreen->scrnHeight) + dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY; + + if (!dmxScreen->rootWidth) dmxScreen->rootWidth = dmxScreen->scrnWidth; + if (!dmxScreen->rootHeight) dmxScreen->rootHeight = dmxScreen->scrnHeight; + if (dmxScreen->rootWidth + dmxScreen->rootX > dmxScreen->scrnWidth) + dmxScreen->rootWidth = dmxScreen->scrnWidth - dmxScreen->rootX; + if (dmxScreen->rootHeight + dmxScreen->rootY > dmxScreen->scrnHeight) + dmxScreen->rootHeight = dmxScreen->scrnHeight - dmxScreen->rootY; + + /* FIXME: Get these from the back-end server */ + dmxScreen->beXDPI = 75; + dmxScreen->beYDPI = 75; + + dmxScreen->beDepth = attribs.depth; /* FIXME: verify that this + * works always. In + * particular, this will work + * well for depth=16, will fail + * because of colormap issues + * at depth 8. More work needs + * to be done here. */ + + if (dmxScreen->beDepth <= 8) dmxScreen->beBPP = 8; + else if (dmxScreen->beDepth <= 16) dmxScreen->beBPP = 16; + else dmxScreen->beBPP = 32; + +#ifdef GLXEXT + /* get the majorOpcode for the back-end GLX extension */ + XQueryExtension(dpy, "GLX", &dmxScreen->glxMajorOpcode, + &dummy, &dmxScreen->glxErrorBase); +#endif + + dmxPrintScreenInfo(dmxScreen); + dmxLogOutput(dmxScreen, "%dx%d+%d+%d on %dx%d at depth=%d, bpp=%d\n", + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY, + dmxScreen->beWidth, dmxScreen->beHeight, + dmxScreen->beDepth, dmxScreen->beBPP); + if (dmxScreen->beDepth == 8) + dmxLogOutputWarning(dmxScreen, + "Support for depth == 8 is not complete\n"); +} + +Bool dmxGetVisualInfo(DMXScreenInfo *dmxScreen) +{ + int i; + XVisualInfo visinfo; + + visinfo.screen = DefaultScreen(dmxScreen->beDisplay); + dmxScreen->beVisuals = XGetVisualInfo(dmxScreen->beDisplay, + VisualScreenMask, + &visinfo, + &dmxScreen->beNumVisuals); + + dmxScreen->beDefVisualIndex = -1; + + if (defaultColorVisualClass >= 0 || dmxDepth > 0) { + for (i = 0; i < dmxScreen->beNumVisuals; i++) + if (defaultColorVisualClass >= 0) { + if (dmxScreen->beVisuals[i].class == defaultColorVisualClass) { + if (dmxDepth > 0) { + if (dmxScreen->beVisuals[i].depth == dmxDepth) { + dmxScreen->beDefVisualIndex = i; + break; + } + } else { + dmxScreen->beDefVisualIndex = i; + break; + } + } + } else if (dmxScreen->beVisuals[i].depth == dmxDepth) { + dmxScreen->beDefVisualIndex = i; + break; + } + } else { + visinfo.visualid = + XVisualIDFromVisual(DefaultVisual(dmxScreen->beDisplay, + visinfo.screen)); + + for (i = 0; i < dmxScreen->beNumVisuals; i++) + if (visinfo.visualid == dmxScreen->beVisuals[i].visualid) { + dmxScreen->beDefVisualIndex = i; + break; + } + } + + for (i = 0; i < dmxScreen->beNumVisuals; i++) + dmxLogVisual(dmxScreen, &dmxScreen->beVisuals[i], + (i == dmxScreen->beDefVisualIndex)); + + return (dmxScreen->beDefVisualIndex >= 0); +} + +void dmxGetColormaps(DMXScreenInfo *dmxScreen) +{ + int i; + + dmxScreen->beNumDefColormaps = dmxScreen->beNumVisuals; + dmxScreen->beDefColormaps = malloc(dmxScreen->beNumDefColormaps * + sizeof(*dmxScreen->beDefColormaps)); + + for (i = 0; i < dmxScreen->beNumDefColormaps; i++) + dmxScreen->beDefColormaps[i] = + XCreateColormap(dmxScreen->beDisplay, + DefaultRootWindow(dmxScreen->beDisplay), + dmxScreen->beVisuals[i].visual, + AllocNone); + + dmxScreen->beBlackPixel = BlackPixel(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay)); + dmxScreen->beWhitePixel = WhitePixel(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay)); +} + +void dmxGetPixmapFormats(DMXScreenInfo *dmxScreen) +{ + dmxScreen->beDepths = + XListDepths(dmxScreen->beDisplay, DefaultScreen(dmxScreen->beDisplay), + &dmxScreen->beNumDepths); + + dmxScreen->bePixmapFormats = + XListPixmapFormats(dmxScreen->beDisplay, + &dmxScreen->beNumPixmapFormats); +} + +static Bool dmxSetPixmapFormats(ScreenInfo *pScreenInfo, + DMXScreenInfo *dmxScreen) +{ + XPixmapFormatValues *bePixmapFormat; + PixmapFormatRec *format; + int i, j; + + pScreenInfo->imageByteOrder = ImageByteOrder(dmxScreen->beDisplay); + pScreenInfo->bitmapScanlineUnit = BitmapUnit(dmxScreen->beDisplay); + pScreenInfo->bitmapScanlinePad = BitmapPad(dmxScreen->beDisplay); + pScreenInfo->bitmapBitOrder = BitmapBitOrder(dmxScreen->beDisplay); + + pScreenInfo->numPixmapFormats = 0; + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + bePixmapFormat = &dmxScreen->bePixmapFormats[i]; + for (j = 0; j < dmxScreen->beNumDepths; j++) + if ((bePixmapFormat->depth == 1) || + (bePixmapFormat->depth == dmxScreen->beDepths[j])) { + format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats]; + + format->depth = bePixmapFormat->depth; + format->bitsPerPixel = bePixmapFormat->bits_per_pixel; + format->scanlinePad = bePixmapFormat->scanline_pad; + + pScreenInfo->numPixmapFormats++; + break; + } + } + + return TRUE; +} + +void dmxCheckForWM(DMXScreenInfo *dmxScreen) +{ + Status status; + XWindowAttributes xwa; + + status = XGetWindowAttributes(dmxScreen->beDisplay, + DefaultRootWindow(dmxScreen->beDisplay), + &xwa); + dmxScreen->WMRunningOnBE = + (status && + ((xwa.all_event_masks & SubstructureRedirectMask) || + (xwa.all_event_masks & SubstructureNotifyMask))); +} + +/** Initialize the display and collect relevant information about the + * display properties */ +static void dmxDisplayInit(DMXScreenInfo *dmxScreen) +{ + if (!dmxOpenDisplay(dmxScreen)) + dmxLog(dmxFatal, + "dmxOpenDisplay: Unable to open display %s\n", + dmxScreen->name); + + dmxSetErrorHandler(dmxScreen); + dmxCheckForWM(dmxScreen); + dmxGetScreenAttribs(dmxScreen); + + if (!dmxGetVisualInfo(dmxScreen)) + dmxLog(dmxFatal, "dmxGetVisualInfo: No matching visuals found\n"); + + dmxGetColormaps(dmxScreen); + dmxGetPixmapFormats(dmxScreen); +} + +/* If this doesn't compile, just add || defined(yoursystem) to the line + * below. This information is to help with bug reports and is not + * critical. */ +#if !defined(_POSIX_SOURCE) +static const char *dmxExecOS(void) { return ""; } +#else +#include +static const char *dmxExecOS(void) +{ + static char buffer[128]; + static int initialized = 0; + struct utsname u; + + if (!initialized++) { + memset(buffer, 0, sizeof(buffer)); + uname(&u); + XmuSnprintf(buffer, sizeof(buffer)-1, "%s %s %s", + u.sysname, u.release, u.version); + } + return buffer; +} +#endif + +static const char *dmxBuildCompiler(void) +{ + static char buffer[128]; + static int initialized = 0; + + if (!initialized++) { + memset(buffer, 0, sizeof(buffer)); +#if defined(__GNUC__) && defined(__GNUC_MINOR__) &&defined(__GNUC_PATCHLEVEL__) + XmuSnprintf(buffer, sizeof(buffer)-1, "gcc %d.%d.%d", + __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +#endif + } + return buffer; +} + +static const char *dmxExecHost(void) +{ + static char buffer[128]; + static int initialized = 0; + + if (!initialized++) { + memset(buffer, 0, sizeof(buffer)); + XmuGetHostname(buffer, sizeof(buffer) - 1); + } + return buffer; +} + +/** This routine is called in Xserver/dix/main.c from \a main(). */ +void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) +{ + int i; + static unsigned long dmxGeneration = 0; +#ifdef GLXEXT + Bool glxSupported = TRUE; +#endif + + if (dmxGeneration != serverGeneration) { + int vendrel = VENDOR_RELEASE; + int major, minor, year, month, day; + + dmxGeneration = serverGeneration; + + major = vendrel / 100000000; + vendrel -= major * 100000000; + minor = vendrel / 1000000; + vendrel -= minor * 1000000; + year = vendrel / 10000; + vendrel -= year * 10000; + month = vendrel / 100; + vendrel -= month * 100; + day = vendrel; + + /* Add other epoch tests here */ + if (major > 0 && minor > 0) year += 2000; + + dmxLog(dmxInfo, "Generation: %d\n", dmxGeneration); + dmxLog(dmxInfo, "DMX version: %d.%d.%02d%02d%02d (%s)\n", + major, minor, year, month, day, VENDOR_STRING); + + SetVendorRelease(VENDOR_RELEASE); + SetVendorString(VENDOR_STRING); + + if (dmxGeneration == 1) { + dmxLog(dmxInfo, "DMX Build OS: %s (%s)\n", OSNAME, OSVENDOR); + dmxLog(dmxInfo, "DMX Build Compiler: %s\n", dmxBuildCompiler()); + dmxLog(dmxInfo, "DMX Execution OS: %s\n", dmxExecOS()); + dmxLog(dmxInfo, "DMX Execution Host: %s\n", dmxExecHost()); + } + dmxLog(dmxInfo, "MAXSCREENS: %d\n", MAXSCREENS); + + for (i = 0; i < dmxNumScreens; i++) { + if (dmxScreens[i].beDisplay) + dmxLog(dmxWarning, "Display \"%s\" still open\n", + dmxScreens[i].name); + dmxStatFree(dmxScreens[i].stat); + dmxScreens[i].stat = NULL; + } + for (i = 0; i < dmxNumInputs; i++) dmxInputFree(&dmxInputs[i]); + if (dmxScreens) free(dmxScreens); + if (dmxInputs) free(dmxInputs); + dmxScreens = NULL; + dmxInputs = NULL; + dmxNumScreens = 0; + dmxNumInputs = 0; + } + + /* Make sure that the command-line arguments are sane. */ + if (dmxAddRemoveScreens && dmxGLXProxy) { + /* Currently it is not possible to support GLX and Render + * extensions with dynamic screen addition/removal due to the + * state that each extension keeps, which cannot be restored. */ + dmxLog(dmxWarning, + "GLX Proxy and Render extensions do not yet support dynamic\n"); + dmxLog(dmxWarning, + "screen addition and removal. Please specify -noglxproxy\n"); + dmxLog(dmxWarning, + "and -norender on the command line or in the configuration\n"); + dmxLog(dmxWarning, + "file to disable these two extensions if you wish to use\n"); + dmxLog(dmxWarning, + "the dynamic addition and removal of screens support.\n"); + dmxLog(dmxFatal, + "Dynamic screen addition/removal error (see above).\n"); + } + + /* ddxProcessArgument has been called at this point, but any data + * from the configuration file has not been applied. Do so, and be + * sure we have at least one back-end display. */ + dmxConfigConfigure(); + if (!dmxNumScreens) + dmxLog(dmxFatal, "InitOutput: no back-end displays found\n"); + if (!dmxNumInputs) + dmxLog(dmxInfo, "InitOutput: no inputs found\n"); + + /* Disable lazy window creation optimization if offscreen + * optimization is disabled */ + if (!dmxOffScreenOpt && dmxLazyWindowCreation) { + dmxLog(dmxInfo, + "InitOutput: Disabling lazy window creation optimization\n"); + dmxLog(dmxInfo, + " since it requires the offscreen optimization\n"); + dmxLog(dmxInfo, + " to function properly.\n"); + dmxLazyWindowCreation = FALSE; + } + + /* Open each display and gather information about it. */ + for (i = 0; i < dmxNumScreens; i++) + dmxDisplayInit(&dmxScreens[i]); + +#if PANORAMIX + /* Register a Xinerama callback which will run from within + * PanoramiXCreateConnectionBlock. We can use the callback to + * determine if Xinerama is loaded and to check the visuals + * determined by PanoramiXConsolidate. */ + XineramaRegisterConnectionBlockCallback(dmxConnectionBlockCallback); +#endif + + /* Since we only have a single screen thus far, we only need to set + the pixmap formats to match that screen. FIXME: this isn't true.*/ + if (!dmxSetPixmapFormats(pScreenInfo, &dmxScreens[0])) return; + + /* Might want to install a signal handler to allow cleaning up after + * unexpected signals. The DIX/OS layer already handles SIGINT and + * SIGTERM, so everything is OK for expected signals. --DD + * + * SIGHUP, SIGINT, and SIGTERM are trapped in os/connection.c + * SIGQUIT is another common signal that is sent from the keyboard. + * Trap it here, to ensure that the keyboard modifier map and other + * state for the input devices are restored. (This makes the + * behavior of SIGQUIT somewhat unexpected, since it will be the + * same as the behavior of SIGINT. However, leaving the modifier + * map of the input devices empty is even more unexpected.) --RF + */ + OsSignal(SIGQUIT, GiveUp); + +#ifdef GLXEXT + /* Check if GLX extension exists on all back-end servers */ + for (i = 0; i < dmxNumScreens; i++) + glxSupported &= (dmxScreens[i].glxMajorOpcode > 0); +#endif + + /* Tell dix layer about the backend displays */ + for (i = 0; i < dmxNumScreens; i++) { + +#ifdef GLXEXT + if (glxSupported) { + /* + * Builds GLX configurations from the list of visuals + * supported by the back-end server, and give that + * configuration list to the glx layer - so that he will + * build the visuals accordingly. + */ + + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + __GLXvisualConfig *configs = NULL; + dmxGlxVisualPrivate **configprivs = NULL; + int nconfigs = 0; + int (*oldErrorHandler)(Display *, XErrorEvent *); + int i; + + /* Catch errors if when using an older GLX w/o FBconfigs */ + oldErrorHandler = XSetErrorHandler(dmxNOPErrorHandler); + + /* Get FBConfigs of the back-end server */ + dmxScreen->fbconfigs = GetGLXFBConfigs(dmxScreen->beDisplay, + dmxScreen->glxMajorOpcode, + &dmxScreen->numFBConfigs); + + XSetErrorHandler(oldErrorHandler); + + dmxScreen->glxVisuals = + GetGLXVisualConfigs(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay), + &dmxScreen->numGlxVisuals); + + if (dmxScreen->fbconfigs) { + configs = + GetGLXVisualConfigsFromFBConfigs(dmxScreen->fbconfigs, + dmxScreen->numFBConfigs, + dmxScreen->beVisuals, + dmxScreen->beNumVisuals, + dmxScreen->glxVisuals, + dmxScreen->numGlxVisuals, + &nconfigs); + } else { + configs = dmxScreen->glxVisuals; + nconfigs = dmxScreen->numGlxVisuals; + } + + configprivs = malloc(nconfigs * sizeof(dmxGlxVisualPrivate*)); + + if (configs != NULL && configprivs != NULL) { + + /* Initialize our private info for each visual + * (currently only x_visual_depth and x_visual_class) + */ + for (i = 0; i < nconfigs; i++) { + + configprivs[i] = (dmxGlxVisualPrivate *) + malloc(sizeof(dmxGlxVisualPrivate)); + configprivs[i]->x_visual_depth = 0; + configprivs[i]->x_visual_class = 0; + + /* Find the visual depth */ + if (configs[i].vid > 0) { + int j; + for (j = 0; j < dmxScreen->beNumVisuals; j++) { + if (dmxScreen->beVisuals[j].visualid == + configs[i].vid) { + configprivs[i]->x_visual_depth = + dmxScreen->beVisuals[j].depth; + configprivs[i]->x_visual_class = + dmxScreen->beVisuals[j].class; + break; + } + } + } + } + + /* Hand out the glx configs to glx extension */ + GlxSetVisualConfigs(nconfigs, configs, (void**)configprivs); + + XFlush(dmxScreen->beDisplay); + } + } +#endif /* GLXEXT */ + + AddScreen(dmxScreenInit, argc, argv); + } + + /* Compute origin information. */ + dmxInitOrigins(); + + /* Compute overlap information. */ + dmxInitOverlap(); + + /* Make sure there is a global width/height available */ + dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX); + + /* FIXME: The following is temporarily placed here. When the DMX + * extension is available, it will be move there. + */ + dmxInitFonts(); + + /* Initialize the render extension */ + if (!noRenderExtension) + dmxInitRender(); + + /* Initialized things that need timer hooks */ + dmxStatInit(); + dmxSyncInit(); /* Calls RegisterBlockAndWakeupHandlers */ + + dmxLog(dmxInfo, "Shadow framebuffer support %s\n", + dmxShadowFB ? "enabled" : "disabled"); +} + +/* RATS: Assuming the fp string (which comes from the command-line argv + vector) is NULL-terminated, the buffer is large enough for the + strcpy. */ +static void dmxSetDefaultFontPath(char *fp) +{ + int fplen = strlen(fp) + 1; + + if (dmxFontPath) { + int len; + + len = strlen(dmxFontPath); + dmxFontPath = realloc(dmxFontPath, len+fplen+1); + dmxFontPath[len] = ','; + strncpy(&dmxFontPath[len+1], fp, fplen); + } else { + dmxFontPath = malloc(fplen); + strncpy(dmxFontPath, fp, fplen); + } + + defaultFontPath = dmxFontPath; +} + +/** This function is called in Xserver/os/utils.c from \a AbortServer(). + * We must ensure that backend and console state is restored in the + * event the server shutdown wasn't clean. */ +void AbortDDX(void) +{ + int i; + + for (i=0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (dmxScreen->beDisplay) XCloseDisplay(dmxScreen->beDisplay); + dmxScreen->beDisplay = NULL; + } +} + +#ifdef DDXBEFORERESET +void ddxBeforeReset(void) +{ +} +#endif + +/** This function is called in Xserver/dix/main.c from \a main() when + * dispatchException & DE_TERMINATE (which is the only way to exit the + * main loop without an interruption. */ +void ddxGiveUp(void) +{ + AbortDDX(); +} + +/** This function is called in Xserver/os/osinit.c from \a OsInit(). */ +void OsVendorInit(void) +{ +} + +/** This function is called in Xserver/os/utils.c from \a FatalError() + * and \a VFatalError(). (Note that setting the function pointer \a + * OsVendorVErrorFProc will cause \a VErrorF() (which is called by the + * two routines mentioned here, as well as by others) to use the + * referenced routine instead of \a vfprintf().) */ +void OsVendorFatalError(void) +{ +} + +/** Process our command line arguments. */ +int ddxProcessArgument(int argc, char *argv[], int i) +{ + int retval = 0; + + if (!strcmp(argv[i], "-display")) { + if (++i < argc) dmxConfigStoreDisplay(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-inputfrom") || !strcmp(argv[i], "-input")) { + if (++i < argc) dmxConfigStoreInput(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-xinputfrom") || !strcmp(argv[i],"-xinput")) { + if (++i < argc) dmxConfigStoreXInput(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-noshadowfb")) { + dmxLog(dmxWarning, + "-noshadowfb has been deprecated " + "since it is now the default\n"); + dmxShadowFB = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-nomulticursor")) { + dmxCursorNoMulti(); + retval = 1; + } else if (!strcmp(argv[i], "-shadowfb")) { + dmxShadowFB = TRUE; + retval = 1; + } else if (!strcmp(argv[i], "-configfile")) { + if (++i < argc) dmxConfigStoreFile(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-config")) { + if (++i < argc) dmxConfigStoreConfig(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-fontpath")) { + if (++i < argc) dmxSetDefaultFontPath(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-stat")) { + if ((i += 2) < argc) dmxStatActivate(argv[i-1], argv[i]); + retval = 3; + } else if (!strcmp(argv[i], "-syncbatch")) { + if (++i < argc) dmxSyncActivate(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-nooffscreenopt")) { + dmxOffScreenOpt = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-nosubdivprims")) { + dmxSubdividePrimitives = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-nowindowopt")) { + dmxLazyWindowCreation = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-noxkb")) { + dmxUseXKB = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-depth")) { + if (++i < argc) dmxDepth = atoi(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-norender")) { + noRenderExtension = TRUE; + retval = 1; +#ifdef GLXEXT + } else if (!strcmp(argv[i], "-noglxproxy")) { + dmxGLXProxy = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-noglxswapgroup")) { + dmxGLXSwapGroupSupport = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-glxsyncswap")) { + dmxGLXSyncSwap = TRUE; + retval = 1; + } else if (!strcmp(argv[i], "-glxfinishswap")) { + dmxGLXFinishSwap = TRUE; + retval = 1; +#endif + } else if (!strcmp(argv[i], "-ignorebadfontpaths")) { + dmxIgnoreBadFontPaths = TRUE; + retval = 1; + } else if (!strcmp(argv[i], "-addremovescreens")) { + dmxAddRemoveScreens = TRUE; + retval = 1; + } else if (!strcmp(argv[i], "-param")) { + if ((i += 2) < argc) { + if (!strcasecmp(argv[i-1], "xkbrules")) + dmxConfigSetXkbRules(argv[i]); + else if (!strcasecmp(argv[i-1], "xkbmodel")) + dmxConfigSetXkbModel(argv[i]); + else if (!strcasecmp(argv[i-1], "xkblayout")) + dmxConfigSetXkbLayout(argv[i]); + else if (!strcasecmp(argv[i-1], "xkbvariant")) + dmxConfigSetXkbVariant(argv[i]); + else if (!strcasecmp(argv[i-1], "xkboptions")) + dmxConfigSetXkbOptions(argv[i]); + else + dmxLog(dmxWarning, + "-param requires: XkbRules, XkbModel, XkbLayout," + " XkbVariant, or XkbOptions\n"); + } + retval = 3; + } + if (!serverGeneration) dmxConfigSetMaxScreens(); + return retval; +} + +/** Provide succinct usage information for the DMX server. */ +void ddxUseMsg(void) +{ + ErrorF("\n\nDevice Dependent Usage:\n"); + ErrorF("-display string Specify the back-end display(s)\n"); + ErrorF("-input string Specify input source for core device\n"); + ErrorF("-xinput string Specify input source for XInput device\n"); + ErrorF("-shadowfb Enable shadow frame buffer\n"); + ErrorF("-configfile file Read from a configuration file\n"); + ErrorF("-config config Select a specific configuration\n"); + ErrorF("-nomulticursor Turn of multiple cursor support\n"); + ErrorF("-fontpath Sets the default font path\n"); + ErrorF("-stat inter scrns Print out performance statistics\n"); + ErrorF("-syncbatch inter Set interval for XSync batching\n"); + ErrorF("-nooffscreenopt Disable offscreen optimization\n"); + ErrorF("-nosubdivprims Disable primitive subdivision\n"); + ErrorF(" optimization\n"); + ErrorF("-nowindowopt Disable lazy window creation optimization\n"); + ErrorF("-noxkb Disable use of the XKB extension with\n"); + ErrorF(" backend displays (cf. -kb).\n"); + ErrorF("-depth Specify the default root window depth\n"); + ErrorF("-norender Disable RENDER extension support\n"); +#ifdef GLXEXT + ErrorF("-noglxproxy Disable GLX Proxy\n"); + ErrorF("-noglxswapgroup Disable swap group and swap barrier\n"); + ErrorF(" extensions in GLX proxy\n"); + ErrorF("-glxsyncswap Force XSync after swap buffers\n"); + ErrorF("-glxfinishswap Force glFinish after swap buffers\n"); +#endif + ErrorF("-ignorebadfontpaths Ignore bad font paths during initialization\n"); + ErrorF("-addremovescreens Enable dynamic screen addition/removal\n"); + ErrorF("-param ... Specify configuration parameters (e.g.,\n"); + ErrorF(" XkbRules, XkbModel, XkbLayout, etc.)\n"); + ErrorF("\n"); + ErrorF(" If the -input string matches a -display string, then input\n" + " is taken from that backend display. (XInput cannot be taken\n" + " from a backend display.) Placing \",console\" after the\n" + " display name will force a console window to be opened on\n" + " that display in addition to the backend input. This is\n" + " useful if the backend window does not cover the whole\n" + " physical display.\n\n"); + + ErrorF(" Otherwise, if the -input or -xinput string specifies another\n" + " X display, then a console window will be created on that\n" + " display. Placing \",windows\" or \",nowindows\" after the\n" + " display name will control the display of window outlines in\n" + " the console.\n\n"); + + ErrorF(" -input or -xinput dummy specifies no input.\n"); + ErrorF(" -input or -xinput local specifies the use of a raw keyboard,\n" + " mouse, or other (extension) device:\n" + " -input local,kbd,ps2 will use a ps2 mouse\n" + " -input local,kbd,ms will use a serial mouse\n" + " -input local,usb-kbd,usb-mou will use USB devices \n" + " -xinput local,usb-oth will use a non-mouse and\n" + " non-keyboard USB device with XInput\n\n"); + + ErrorF(" Special Keys:\n"); + ErrorF(" Ctrl-Alt-g Server grab/ungrab (console only)\n"); + ErrorF(" Ctrl-Alt-f Fine (1-pixel) mouse mode (console only)\n"); + ErrorF(" Ctrl-Alt-q Quit (core devices only)\n"); + ErrorF(" Ctrl-Alt-F* Switch to VC (local only)\n"); +} diff --git a/xorg-server/hw/dmx/dmxpict.c b/xorg-server/hw/dmx/dmxpict.c index efb2e41c9..c7bcd5b91 100644 --- a/xorg-server/hw/dmx/dmxpict.c +++ b/xorg-server/hw/dmx/dmxpict.c @@ -274,7 +274,7 @@ static int dmxProcRenderCreateGlyphSet(ClientPtr client) glyphSet = SecurityLookupIDByType(client, stuff->gsid, GlyphSetType, DixDestroyAccess); - glyphPriv = xalloc(sizeof(dmxGlyphPrivRec)); + glyphPriv = malloc(sizeof(dmxGlyphPrivRec)); if (!glyphPriv) return BadAlloc; glyphPriv->glyphSets = NULL; MAXSCREENSALLOC_RETURN(glyphPriv->glyphSets, BadAlloc); @@ -331,7 +331,7 @@ static int dmxProcRenderFreeGlyphSet(ClientPtr client) } MAXSCREENSFREE(glyphPriv->glyphSets); - xfree(glyphPriv); + free(glyphPriv); DMX_SET_GLYPH_PRIV(glyphSet, NULL); } @@ -369,7 +369,7 @@ static int dmxProcRenderAddGlyphs(ClientPtr client) sizeof(xRenderAddGlyphsReq) - (sizeof(CARD32) + sizeof(xGlyphInfo)) * nglyphs); - gidsCopy = xalloc(sizeof(*gidsCopy) * nglyphs); + gidsCopy = malloc(sizeof(*gidsCopy) * nglyphs); for (i = 0; i < nglyphs; i++) gidsCopy[i] = gids[i]; /* FIXME: Will this ever fail? */ @@ -387,7 +387,7 @@ static int dmxProcRenderAddGlyphs(ClientPtr client) dmxSync(dmxScreen, FALSE); } } - xfree(gidsCopy); + free(gidsCopy); } return ret; @@ -411,7 +411,7 @@ static int dmxProcRenderFreeGlyphs(ClientPtr client) nglyphs = ((client->req_len << 2) - sizeof(xRenderFreeGlyphsReq)) >> 2; if (nglyphs) { - gids = xalloc(sizeof(*gids) * nglyphs); + gids = malloc(sizeof(*gids) * nglyphs); for (i = 0; i < nglyphs; i++) gids[i] = ((CARD32 *)(stuff + 1))[i]; @@ -424,7 +424,7 @@ static int dmxProcRenderFreeGlyphs(ClientPtr client) dmxSync(dmxScreen, FALSE); } } - xfree(gids); + free(gids); } } @@ -531,13 +531,13 @@ static int dmxProcRenderCompositeGlyphs(ClientPtr client) /* The following only works for Render version > 0.2 */ /* All of the XGlyphElt* structure sizes are identical */ - elts = xalloc(nelt * sizeof(XGlyphElt8)); + elts = malloc(nelt * sizeof(XGlyphElt8)); if (!elts) return BadAlloc; - glyphs = xalloc(nglyph * size); + glyphs = malloc(nglyph * size); if (!glyphs) { - xfree(elts); + free(elts); return BadAlloc; } @@ -605,8 +605,8 @@ static int dmxProcRenderCompositeGlyphs(ClientPtr client) dmxSync(dmxScreen, FALSE); - xfree(elts); - xfree(glyphs); + free(elts); + free(glyphs); } return ret; @@ -878,7 +878,7 @@ int dmxChangePictureClip(PicturePtr pPicture, int clipType, int nRects; nRects = nBox; - pRects = pRect = xalloc(nRects * sizeof(*pRect)); + pRects = pRect = malloc(nRects * sizeof(*pRect)); while (nBox--) { pRect->x = pBox->x1; @@ -894,7 +894,7 @@ int dmxChangePictureClip(PicturePtr pPicture, int clipType, 0, 0, pRects, nRects); - xfree(pRects); + free(pRects); } else { XRenderSetPictureClipRectangles(dmxScreen->beDisplay, pPictPriv->pict, diff --git a/xorg-server/hw/dmx/dmxpixmap.c b/xorg-server/hw/dmx/dmxpixmap.c index 66224031a..bcbcc3a88 100644 --- a/xorg-server/hw/dmx/dmxpixmap.c +++ b/xorg-server/hw/dmx/dmxpixmap.c @@ -1,253 +1,253 @@ -/* - * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Kevin E. Martin - * - */ - -/** \file - * Provides pixmap support. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxpixmap.h" - -#include "pixmapstr.h" -#include "servermd.h" -#include "privates.h" - -/** Initialize a private area in \a pScreen for pixmap information. */ -Bool dmxInitPixmap(ScreenPtr pScreen) -{ - if (!dixRequestPrivate(dmxPixPrivateKey, sizeof(dmxPixPrivRec))) - return FALSE; - - return TRUE; -} - -/** Create a pixmap on the back-end server. */ -void dmxBECreatePixmap(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - - /* Make sure we haven't already created this pixmap. This can - * happen when the pixmap is used elsewhere (e.g., as a background - * or border for a window) and the refcnt > 1. - */ - if (pPixPriv->pixmap) - return; - - if (pPixmap->drawable.width && pPixmap->drawable.height) { - pPixPriv->pixmap = XCreatePixmap(dmxScreen->beDisplay, - dmxScreen->scrnWin, - pPixmap->drawable.width, - pPixmap->drawable.height, - pPixmap->drawable.depth); - dmxSync(dmxScreen, FALSE); - } -} - -/** Create a pixmap for \a pScreen with the specified \a width, \a - * height, and \a depth. */ -PixmapPtr dmxCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, - unsigned usage_hint) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - PixmapPtr pPixmap; - int bpp; - dmxPixPrivPtr pPixPriv; - -#if 0 - DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); - if (pScreen->CreatePixmap) - ret = pScreen->CreatePixmap(pPixmap); -#endif - - /* Create pixmap on back-end server */ - if (depth == 24) bpp = 32; - else bpp = depth; - - pPixmap = AllocatePixmap(pScreen, 0); - if (!pPixmap) - return NullPixmap; - - pPixmap->drawable.type = DRAWABLE_PIXMAP; - pPixmap->drawable.class = 0; - pPixmap->drawable.pScreen = pScreen; - pPixmap->drawable.depth = depth; - pPixmap->drawable.bitsPerPixel = bpp; - pPixmap->drawable.id = 0; - pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - pPixmap->drawable.x = 0; - pPixmap->drawable.y = 0; - pPixmap->drawable.width = width; - pPixmap->drawable.height = height; - pPixmap->devKind = PixmapBytePad(width, bpp); - pPixmap->refcnt = 1; - pPixmap->usage_hint = usage_hint; - - pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - pPixPriv->pixmap = (Pixmap)0; - pPixPriv->detachedImage = NULL; - - /* Create the pixmap on the back-end server */ - if (dmxScreen->beDisplay) { - dmxBECreatePixmap(pPixmap); - } - -#if 0 - DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); -#endif - - return pPixmap; -} - -/** Destroy the pixmap on the back-end server. */ -Bool dmxBEFreePixmap(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - - if (pPixPriv->pixmap) { - XFreePixmap(dmxScreen->beDisplay, pPixPriv->pixmap); - pPixPriv->pixmap = (Pixmap)0; - return TRUE; - } - - return FALSE; -} - -/** Destroy the pixmap pointed to by \a pPixmap. */ -Bool dmxDestroyPixmap(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - -#if 0 - DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); -#endif - - if (--pPixmap->refcnt) - return TRUE; - - /* Destroy pixmap on back-end server */ - if (dmxScreen->beDisplay) { - if (dmxBEFreePixmap(pPixmap)) { - /* Also make sure that we destroy any detached image */ - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - if (pPixPriv->detachedImage) - XDestroyImage(pPixPriv->detachedImage); - dmxSync(dmxScreen, FALSE); - } - } - dixFreePrivates(pPixmap->devPrivates); - xfree(pPixmap); - -#if 0 - if (pScreen->DestroyPixmap) - ret = pScreen->DestroyPixmap(pPixmap); - DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); -#endif - - return ret; -} - -/** Create and return a region based on the pixmap pointed to by \a - * pPixmap. */ -RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - XImage *ximage; - RegionPtr pReg, pTmpReg; - int x, y; - unsigned long previousPixel, currentPixel; - BoxRec Box; - Bool overlap; - - if (!dmxScreen->beDisplay) { - pReg = REGION_CREATE(pScreen, NullBox, 1); - return pReg; - } - - ximage = XGetImage(dmxScreen->beDisplay, pPixPriv->pixmap, 0, 0, - pPixmap->drawable.width, pPixmap->drawable.height, - 1, XYPixmap); - - pReg = REGION_CREATE(pScreen, NullBox, 1); - pTmpReg = REGION_CREATE(pScreen, NullBox, 1); - if(!pReg || !pTmpReg) { - XDestroyImage(ximage); - return NullRegion; - } - - for (y = 0; y < pPixmap->drawable.height; y++) { - Box.y1 = y; - Box.y2 = y + 1; - previousPixel = 0L; - for (x = 0; x < pPixmap->drawable.width; x++) { - currentPixel = XGetPixel(ximage, x, y); - if (previousPixel != currentPixel) { - if (previousPixel == 0L) { - /* left edge */ - Box.x1 = x; - } else if (currentPixel == 0L) { - /* right edge */ - Box.x2 = x; - REGION_RESET(pScreen, pTmpReg, &Box); - REGION_APPEND(pScreen, pReg, pTmpReg); - } - previousPixel = currentPixel; - } - } - if (previousPixel != 0L) { - /* right edge because of the end of pixmap */ - Box.x2 = pPixmap->drawable.width; - REGION_RESET(pScreen, pTmpReg, &Box); - REGION_APPEND(pScreen, pReg, pTmpReg); - } - } - - REGION_DESTROY(pScreen, pTmpReg); - XDestroyImage(ximage); - - REGION_VALIDATE(pScreen, pReg, &overlap); - - dmxSync(dmxScreen, FALSE); - return(pReg); -} +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Kevin E. Martin + * + */ + +/** \file + * Provides pixmap support. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxpixmap.h" + +#include "pixmapstr.h" +#include "servermd.h" +#include "privates.h" + +/** Initialize a private area in \a pScreen for pixmap information. */ +Bool dmxInitPixmap(ScreenPtr pScreen) +{ + if (!dixRequestPrivate(dmxPixPrivateKey, sizeof(dmxPixPrivRec))) + return FALSE; + + return TRUE; +} + +/** Create a pixmap on the back-end server. */ +void dmxBECreatePixmap(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + /* Make sure we haven't already created this pixmap. This can + * happen when the pixmap is used elsewhere (e.g., as a background + * or border for a window) and the refcnt > 1. + */ + if (pPixPriv->pixmap) + return; + + if (pPixmap->drawable.width && pPixmap->drawable.height) { + pPixPriv->pixmap = XCreatePixmap(dmxScreen->beDisplay, + dmxScreen->scrnWin, + pPixmap->drawable.width, + pPixmap->drawable.height, + pPixmap->drawable.depth); + dmxSync(dmxScreen, FALSE); + } +} + +/** Create a pixmap for \a pScreen with the specified \a width, \a + * height, and \a depth. */ +PixmapPtr dmxCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PixmapPtr pPixmap; + int bpp; + dmxPixPrivPtr pPixPriv; + +#if 0 + DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); + if (pScreen->CreatePixmap) + ret = pScreen->CreatePixmap(pPixmap); +#endif + + /* Create pixmap on back-end server */ + if (depth == 24) bpp = 32; + else bpp = depth; + + pPixmap = AllocatePixmap(pScreen, 0); + if (!pPixmap) + return NullPixmap; + + pPixmap->drawable.type = DRAWABLE_PIXMAP; + pPixmap->drawable.class = 0; + pPixmap->drawable.pScreen = pScreen; + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bpp; + pPixmap->drawable.id = 0; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = PixmapBytePad(width, bpp); + pPixmap->refcnt = 1; + pPixmap->usage_hint = usage_hint; + + pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + pPixPriv->pixmap = (Pixmap)0; + pPixPriv->detachedImage = NULL; + + /* Create the pixmap on the back-end server */ + if (dmxScreen->beDisplay) { + dmxBECreatePixmap(pPixmap); + } + +#if 0 + DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); +#endif + + return pPixmap; +} + +/** Destroy the pixmap on the back-end server. */ +Bool dmxBEFreePixmap(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + if (pPixPriv->pixmap) { + XFreePixmap(dmxScreen->beDisplay, pPixPriv->pixmap); + pPixPriv->pixmap = (Pixmap)0; + return TRUE; + } + + return FALSE; +} + +/** Destroy the pixmap pointed to by \a pPixmap. */ +Bool dmxDestroyPixmap(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + +#if 0 + DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); +#endif + + if (--pPixmap->refcnt) + return TRUE; + + /* Destroy pixmap on back-end server */ + if (dmxScreen->beDisplay) { + if (dmxBEFreePixmap(pPixmap)) { + /* Also make sure that we destroy any detached image */ + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + if (pPixPriv->detachedImage) + XDestroyImage(pPixPriv->detachedImage); + dmxSync(dmxScreen, FALSE); + } + } + dixFreePrivates(pPixmap->devPrivates); + free(pPixmap); + +#if 0 + if (pScreen->DestroyPixmap) + ret = pScreen->DestroyPixmap(pPixmap); + DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); +#endif + + return ret; +} + +/** Create and return a region based on the pixmap pointed to by \a + * pPixmap. */ +RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + XImage *ximage; + RegionPtr pReg, pTmpReg; + int x, y; + unsigned long previousPixel, currentPixel; + BoxRec Box; + Bool overlap; + + if (!dmxScreen->beDisplay) { + pReg = REGION_CREATE(pScreen, NullBox, 1); + return pReg; + } + + ximage = XGetImage(dmxScreen->beDisplay, pPixPriv->pixmap, 0, 0, + pPixmap->drawable.width, pPixmap->drawable.height, + 1, XYPixmap); + + pReg = REGION_CREATE(pScreen, NullBox, 1); + pTmpReg = REGION_CREATE(pScreen, NullBox, 1); + if(!pReg || !pTmpReg) { + XDestroyImage(ximage); + return NullRegion; + } + + for (y = 0; y < pPixmap->drawable.height; y++) { + Box.y1 = y; + Box.y2 = y + 1; + previousPixel = 0L; + for (x = 0; x < pPixmap->drawable.width; x++) { + currentPixel = XGetPixel(ximage, x, y); + if (previousPixel != currentPixel) { + if (previousPixel == 0L) { + /* left edge */ + Box.x1 = x; + } else if (currentPixel == 0L) { + /* right edge */ + Box.x2 = x; + REGION_RESET(pScreen, pTmpReg, &Box); + REGION_APPEND(pScreen, pReg, pTmpReg); + } + previousPixel = currentPixel; + } + } + if (previousPixel != 0L) { + /* right edge because of the end of pixmap */ + Box.x2 = pPixmap->drawable.width; + REGION_RESET(pScreen, pTmpReg, &Box); + REGION_APPEND(pScreen, pReg, pTmpReg); + } + } + + REGION_DESTROY(pScreen, pTmpReg); + XDestroyImage(ximage); + + REGION_VALIDATE(pScreen, pReg, &overlap); + + dmxSync(dmxScreen, FALSE); + return(pReg); +} diff --git a/xorg-server/hw/dmx/dmxprop.c b/xorg-server/hw/dmx/dmxprop.c index 376313d8d..95efcb0e0 100644 --- a/xorg-server/hw/dmx/dmxprop.c +++ b/xorg-server/hw/dmx/dmxprop.c @@ -1,347 +1,347 @@ -/* - * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * - * It is possible for one of the DMX "backend displays" to actually be - * smaller than the dimensions of the backend X server. Therefore, it - * is possible for more than one of the DMX "backend displays" to be - * physically located on the same backend X server. This situation must - * be detected so that cursor motion can be handled in an expected - * fashion. - * - * We could analyze the names used for the DMX "backend displays" (e.g., - * the names passed to the -display command-line parameter), but there - * are many possible names for a single X display, and failing to detect - * sameness leads to very unexpected results. Therefore, whenever the - * DMX server opens a window on a backend X server, a property value is - * queried and set on that backend to detect when another window is - * already open on that server. - * - * Further, it is possible that two different DMX server instantiations - * both have windows on the same physical backend X server. This case - * is also detected so that pointer input is not taken from that - * particular backend X server. - * - * The routines in this file handle the property management. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxprop.h" -#include "dmxlog.h" - -/** Holds the window id of all DMX windows on the backend X server. */ -#define DMX_ATOMNAME "DMX_NAME" - -/** The identification string of this DMX server */ -#define DMX_IDENT "Xdmx" - -extern char *display; - -static int dmxPropertyErrorHandler(Display *dpy, XErrorEvent *ev) -{ - return 0; -} - -static const unsigned char *dmxPropertyIdentifier(void) -{ - /* RATS: These buffers are only used in - * length-limited calls. */ - char hostname[256]; - static char buf[128]; - static int initialized = 0; - - if (initialized++) return (unsigned char *)buf; - - XmuGetHostname(hostname, sizeof(hostname)); - XmuSnprintf(buf, sizeof(buf), "%s:%s:%s", DMX_IDENT, hostname, display); - return (unsigned char *)buf; -} - -/** Starting with the \a start screen, iterate over all of the screens - * on the same physical X server as \a start, calling \a f with the - * screen and the \a closure. (The common case is that \a start is the - * only DMX window on the backend X server.) */ -void *dmxPropertyIterate(DMXScreenInfo *start, - void *(*f)(DMXScreenInfo *dmxScreen, void *), - void *closure) -{ - DMXScreenInfo *pt; - - if (!start->next) { - if (!start->beDisplay) return NULL; - return f(start, closure); - } - - for (pt = start->next; /* condition at end of loop */; pt = pt->next) { - void *retval; - /* beDisplay ban be NULL if a screen was detached */ - dmxLog(dmxDebug, "pt = %p\n", pt); - dmxLog(dmxDebug, "pt->beDisplay = %p\n", pt->beDisplay); - if (pt->beDisplay && (retval = f(pt, closure))) return retval; - if (pt == start) break; - } - return NULL; -} - -/** Returns 0 if this is the only Xdmx session on the display; 1 - * otherwise. */ -static int dmxPropertyCheckOtherServers(DMXScreenInfo *dmxScreen, Atom atom) -{ - Display *dpy = dmxScreen->beDisplay; - XTextProperty tp; - XTextProperty tproot; - const char *pt; - int retcode = 0; - char **list = NULL; - int count = 0; - int i; - int (*dmxOldHandler)(Display *, XErrorEvent *); - - if (!dpy) - return 0; - - if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) - || !tproot.nitems) return 0; - - /* Ignore BadWindow errors for this - * routine because the window id stored - * in the property might be old */ - dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); - for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { - if ((pt = strchr(pt, ','))) { - Window win = strtol(pt+1, NULL, 10); - if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { - if (!strncmp((char *)tp.value, DMX_IDENT, strlen(DMX_IDENT))) { - int flag = 0; - for (i = 0; i < count; i++) - if (!strcmp(list[i], (char *)tp.value)) { - ++flag; - break; - } - if (flag) continue; - ++retcode; - dmxLogOutputWarning(dmxScreen, - "%s also running on %s\n", - tp.value, dmxScreen->name); - list = xrealloc(list, ++count * sizeof(*list)); - list[count-1] = xalloc(tp.nitems + 2); - strncpy(list[count-1], (char *)tp.value, tp.nitems + 1); - } - XFree(tp.value); - } - } - } - XSetErrorHandler(dmxOldHandler); - - for (i = 0; i < count; i++) xfree(list[i]); - xfree(list); - XFree(tproot.value); - if (!retcode) - dmxLogOutput(dmxScreen, "No Xdmx server running on backend\n"); - return retcode; -} - -/** Returns NULL if this is the only Xdmx window on the display. - * Otherwise, returns a pointer to the dmxScreen of the other windows on - * the display. */ -static DMXScreenInfo *dmxPropertyCheckOtherWindows(DMXScreenInfo *dmxScreen, - Atom atom) -{ - Display *dpy = dmxScreen->beDisplay; - const unsigned char *id = dmxPropertyIdentifier(); - XTextProperty tproot; - XTextProperty tp; - const char *pt; - int (*dmxOldHandler)(Display *, XErrorEvent *); - - if (!dpy) - return NULL; - - if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) - || !tproot.nitems) return 0; - - /* Ignore BadWindow errors for this - * routine because the window id stored - * in the property might be old */ - dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); - for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { - if ((pt = strchr(pt, ','))) { - Window win = strtol(pt+1, NULL, 10); - if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { - dmxLog(dmxDebug,"On %s/%lu: %s\n", - dmxScreen->name, win, tp.value); - if (!strncmp((char *)tp.value, (char *)id, - strlen((char *)id))) { - int idx; - - if (!(pt = strchr((char *)tp.value, ','))) continue; - idx = strtol(pt+1, NULL, 10); - if (idx < 0 || idx >= dmxNumScreens) continue; - if (dmxScreens[idx].scrnWin != win) continue; - XSetErrorHandler(dmxOldHandler); - return &dmxScreens[idx]; - } - XFree(tp.value); - } - } - } - XSetErrorHandler(dmxOldHandler); - XFree(tproot.value); - return 0; -} - -/** Returns 0 if this is the only Xdmx session on the display; 1 - * otherwise. */ -int dmxPropertyDisplay(DMXScreenInfo *dmxScreen) -{ - Atom atom; - const unsigned char *id = dmxPropertyIdentifier(); - Display *dpy = dmxScreen->beDisplay; - - if (!dpy) - return 0; - - atom = XInternAtom(dpy, DMX_ATOMNAME, False); - if (dmxPropertyCheckOtherServers(dmxScreen, atom)) { - dmxScreen->shared = 1; - return 1; - } - XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, - PropModeReplace, id, strlen((char *)id)); - return 0; -} - -/** Returns 1 if the dmxScreen and the display in \a name are on the - * same display, or 0 otherwise. We can't just compare the display - * names because there can be multiple synonyms for the same display, - * some of which cannot be determined without accessing the display - * itself (e.g., domain aliases or machines with multiple NICs). */ -int dmxPropertySameDisplay(DMXScreenInfo *dmxScreen, const char *name) -{ - Display *dpy0 = dmxScreen->beDisplay; - Atom atom0; - XTextProperty tp0; - Display *dpy1 = NULL; - Atom atom1; - XTextProperty tp1; - int retval = 0; - - if (!dpy0) - return 0; - - tp0.nitems = 0; - tp1.nitems = 0; - - if ((atom0 = XInternAtom(dpy0, DMX_ATOMNAME, True)) == None) { - dmxLog(dmxWarning, "No atom on %s\n", dmxScreen->name); - return 0; - } - if (!XGetTextProperty(dpy0, RootWindow(dpy0,0), &tp0, atom0) - || !tp0.nitems) { - dmxLog(dmxWarning, "No text property on %s\n", dmxScreen->name); - return 0; - } - - if (!(dpy1 = XOpenDisplay(name))) { - dmxLog(dmxWarning, "Cannot open %s\n", name); - goto cleanup; - } - atom1 = XInternAtom(dpy1, DMX_ATOMNAME, True); - if (atom1 == None) { - dmxLog(dmxDebug, "No atom on %s\n", name); - goto cleanup; - } - if (!XGetTextProperty(dpy1, RootWindow(dpy1,0), &tp1, atom1) - || !tp1.nitems) { - dmxLog(dmxDebug, "No text property on %s\n", name); - goto cleanup; - } - if (!strcmp((char *)tp0.value, (char *)tp1.value)) retval = 1; - - cleanup: - if (tp0.nitems) XFree(tp0.value); - if (tp1.nitems) XFree(tp1.value); - if (dpy1) XCloseDisplay(dpy1); - return retval; -} - -/** Prints a log message if \a dmxScreen is on the same backend X server - * as some other DMX backend (output) screen. Modifies the property - * (#DMX_ATOMNAME) on the backend X server to reflect the creation of \a - * dmxScreen. - * - * The root window of the backend X server holds a list of window ids - * for all DMX windows (on this DMX server or some other DMX server). - * - * This list can then be iterated, and the property for each window can - * be examined. This property contains the following tuple (no quotes): - * - * "#DMX_IDENT::," - */ -void dmxPropertyWindow(DMXScreenInfo *dmxScreen) -{ - Atom atom; - const unsigned char *id = dmxPropertyIdentifier(); - Display *dpy = dmxScreen->beDisplay; - Window win = dmxScreen->scrnWin; - DMXScreenInfo *other; - char buf[128]; /* RATS: only used with XmuSnprintf */ - - if (!dpy) - return; /* FIXME: What should be done here if Xdmx is started - * with this screen initially detached? - */ - - atom = XInternAtom(dpy, DMX_ATOMNAME, False); - if ((other = dmxPropertyCheckOtherWindows(dmxScreen, atom))) { - DMXScreenInfo *tmp = dmxScreen->next; - dmxScreen->next = (other->next ? other->next : other); - other->next = (tmp ? tmp : dmxScreen); - dmxLog(dmxDebug, "%d/%s/%lu and %d/%s/%lu are on the same backend\n", - dmxScreen->index, dmxScreen->name, dmxScreen->scrnWin, - other->index, other->name, other->scrnWin); - } - - XmuSnprintf(buf, sizeof(buf), ".%d,%lu", dmxScreen->index, - (long unsigned)win); - XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, - PropModeAppend, (unsigned char *)buf, strlen(buf)); - - XmuSnprintf(buf, sizeof(buf), "%s,%d", id, dmxScreen->index); - XChangeProperty(dpy, win, atom, XA_STRING, 8, - PropModeAppend, (unsigned char *)buf, strlen(buf)); -} +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * + * It is possible for one of the DMX "backend displays" to actually be + * smaller than the dimensions of the backend X server. Therefore, it + * is possible for more than one of the DMX "backend displays" to be + * physically located on the same backend X server. This situation must + * be detected so that cursor motion can be handled in an expected + * fashion. + * + * We could analyze the names used for the DMX "backend displays" (e.g., + * the names passed to the -display command-line parameter), but there + * are many possible names for a single X display, and failing to detect + * sameness leads to very unexpected results. Therefore, whenever the + * DMX server opens a window on a backend X server, a property value is + * queried and set on that backend to detect when another window is + * already open on that server. + * + * Further, it is possible that two different DMX server instantiations + * both have windows on the same physical backend X server. This case + * is also detected so that pointer input is not taken from that + * particular backend X server. + * + * The routines in this file handle the property management. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxprop.h" +#include "dmxlog.h" + +/** Holds the window id of all DMX windows on the backend X server. */ +#define DMX_ATOMNAME "DMX_NAME" + +/** The identification string of this DMX server */ +#define DMX_IDENT "Xdmx" + +extern char *display; + +static int dmxPropertyErrorHandler(Display *dpy, XErrorEvent *ev) +{ + return 0; +} + +static const unsigned char *dmxPropertyIdentifier(void) +{ + /* RATS: These buffers are only used in + * length-limited calls. */ + char hostname[256]; + static char buf[128]; + static int initialized = 0; + + if (initialized++) return (unsigned char *)buf; + + XmuGetHostname(hostname, sizeof(hostname)); + XmuSnprintf(buf, sizeof(buf), "%s:%s:%s", DMX_IDENT, hostname, display); + return (unsigned char *)buf; +} + +/** Starting with the \a start screen, iterate over all of the screens + * on the same physical X server as \a start, calling \a f with the + * screen and the \a closure. (The common case is that \a start is the + * only DMX window on the backend X server.) */ +void *dmxPropertyIterate(DMXScreenInfo *start, + void *(*f)(DMXScreenInfo *dmxScreen, void *), + void *closure) +{ + DMXScreenInfo *pt; + + if (!start->next) { + if (!start->beDisplay) return NULL; + return f(start, closure); + } + + for (pt = start->next; /* condition at end of loop */; pt = pt->next) { + void *retval; + /* beDisplay ban be NULL if a screen was detached */ + dmxLog(dmxDebug, "pt = %p\n", pt); + dmxLog(dmxDebug, "pt->beDisplay = %p\n", pt->beDisplay); + if (pt->beDisplay && (retval = f(pt, closure))) return retval; + if (pt == start) break; + } + return NULL; +} + +/** Returns 0 if this is the only Xdmx session on the display; 1 + * otherwise. */ +static int dmxPropertyCheckOtherServers(DMXScreenInfo *dmxScreen, Atom atom) +{ + Display *dpy = dmxScreen->beDisplay; + XTextProperty tp; + XTextProperty tproot; + const char *pt; + int retcode = 0; + char **list = NULL; + int count = 0; + int i; + int (*dmxOldHandler)(Display *, XErrorEvent *); + + if (!dpy) + return 0; + + if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) + || !tproot.nitems) return 0; + + /* Ignore BadWindow errors for this + * routine because the window id stored + * in the property might be old */ + dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); + for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { + if ((pt = strchr(pt, ','))) { + Window win = strtol(pt+1, NULL, 10); + if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { + if (!strncmp((char *)tp.value, DMX_IDENT, strlen(DMX_IDENT))) { + int flag = 0; + for (i = 0; i < count; i++) + if (!strcmp(list[i], (char *)tp.value)) { + ++flag; + break; + } + if (flag) continue; + ++retcode; + dmxLogOutputWarning(dmxScreen, + "%s also running on %s\n", + tp.value, dmxScreen->name); + list = realloc(list, ++count * sizeof(*list)); + list[count-1] = malloc(tp.nitems + 2); + strncpy(list[count-1], (char *)tp.value, tp.nitems + 1); + } + XFree(tp.value); + } + } + } + XSetErrorHandler(dmxOldHandler); + + for (i = 0; i < count; i++) free(list[i]); + free(list); + XFree(tproot.value); + if (!retcode) + dmxLogOutput(dmxScreen, "No Xdmx server running on backend\n"); + return retcode; +} + +/** Returns NULL if this is the only Xdmx window on the display. + * Otherwise, returns a pointer to the dmxScreen of the other windows on + * the display. */ +static DMXScreenInfo *dmxPropertyCheckOtherWindows(DMXScreenInfo *dmxScreen, + Atom atom) +{ + Display *dpy = dmxScreen->beDisplay; + const unsigned char *id = dmxPropertyIdentifier(); + XTextProperty tproot; + XTextProperty tp; + const char *pt; + int (*dmxOldHandler)(Display *, XErrorEvent *); + + if (!dpy) + return NULL; + + if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) + || !tproot.nitems) return 0; + + /* Ignore BadWindow errors for this + * routine because the window id stored + * in the property might be old */ + dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); + for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { + if ((pt = strchr(pt, ','))) { + Window win = strtol(pt+1, NULL, 10); + if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { + dmxLog(dmxDebug,"On %s/%lu: %s\n", + dmxScreen->name, win, tp.value); + if (!strncmp((char *)tp.value, (char *)id, + strlen((char *)id))) { + int idx; + + if (!(pt = strchr((char *)tp.value, ','))) continue; + idx = strtol(pt+1, NULL, 10); + if (idx < 0 || idx >= dmxNumScreens) continue; + if (dmxScreens[idx].scrnWin != win) continue; + XSetErrorHandler(dmxOldHandler); + return &dmxScreens[idx]; + } + XFree(tp.value); + } + } + } + XSetErrorHandler(dmxOldHandler); + XFree(tproot.value); + return 0; +} + +/** Returns 0 if this is the only Xdmx session on the display; 1 + * otherwise. */ +int dmxPropertyDisplay(DMXScreenInfo *dmxScreen) +{ + Atom atom; + const unsigned char *id = dmxPropertyIdentifier(); + Display *dpy = dmxScreen->beDisplay; + + if (!dpy) + return 0; + + atom = XInternAtom(dpy, DMX_ATOMNAME, False); + if (dmxPropertyCheckOtherServers(dmxScreen, atom)) { + dmxScreen->shared = 1; + return 1; + } + XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, + PropModeReplace, id, strlen((char *)id)); + return 0; +} + +/** Returns 1 if the dmxScreen and the display in \a name are on the + * same display, or 0 otherwise. We can't just compare the display + * names because there can be multiple synonyms for the same display, + * some of which cannot be determined without accessing the display + * itself (e.g., domain aliases or machines with multiple NICs). */ +int dmxPropertySameDisplay(DMXScreenInfo *dmxScreen, const char *name) +{ + Display *dpy0 = dmxScreen->beDisplay; + Atom atom0; + XTextProperty tp0; + Display *dpy1 = NULL; + Atom atom1; + XTextProperty tp1; + int retval = 0; + + if (!dpy0) + return 0; + + tp0.nitems = 0; + tp1.nitems = 0; + + if ((atom0 = XInternAtom(dpy0, DMX_ATOMNAME, True)) == None) { + dmxLog(dmxWarning, "No atom on %s\n", dmxScreen->name); + return 0; + } + if (!XGetTextProperty(dpy0, RootWindow(dpy0,0), &tp0, atom0) + || !tp0.nitems) { + dmxLog(dmxWarning, "No text property on %s\n", dmxScreen->name); + return 0; + } + + if (!(dpy1 = XOpenDisplay(name))) { + dmxLog(dmxWarning, "Cannot open %s\n", name); + goto cleanup; + } + atom1 = XInternAtom(dpy1, DMX_ATOMNAME, True); + if (atom1 == None) { + dmxLog(dmxDebug, "No atom on %s\n", name); + goto cleanup; + } + if (!XGetTextProperty(dpy1, RootWindow(dpy1,0), &tp1, atom1) + || !tp1.nitems) { + dmxLog(dmxDebug, "No text property on %s\n", name); + goto cleanup; + } + if (!strcmp((char *)tp0.value, (char *)tp1.value)) retval = 1; + + cleanup: + if (tp0.nitems) XFree(tp0.value); + if (tp1.nitems) XFree(tp1.value); + if (dpy1) XCloseDisplay(dpy1); + return retval; +} + +/** Prints a log message if \a dmxScreen is on the same backend X server + * as some other DMX backend (output) screen. Modifies the property + * (#DMX_ATOMNAME) on the backend X server to reflect the creation of \a + * dmxScreen. + * + * The root window of the backend X server holds a list of window ids + * for all DMX windows (on this DMX server or some other DMX server). + * + * This list can then be iterated, and the property for each window can + * be examined. This property contains the following tuple (no quotes): + * + * "#DMX_IDENT::," + */ +void dmxPropertyWindow(DMXScreenInfo *dmxScreen) +{ + Atom atom; + const unsigned char *id = dmxPropertyIdentifier(); + Display *dpy = dmxScreen->beDisplay; + Window win = dmxScreen->scrnWin; + DMXScreenInfo *other; + char buf[128]; /* RATS: only used with XmuSnprintf */ + + if (!dpy) + return; /* FIXME: What should be done here if Xdmx is started + * with this screen initially detached? + */ + + atom = XInternAtom(dpy, DMX_ATOMNAME, False); + if ((other = dmxPropertyCheckOtherWindows(dmxScreen, atom))) { + DMXScreenInfo *tmp = dmxScreen->next; + dmxScreen->next = (other->next ? other->next : other); + other->next = (tmp ? tmp : dmxScreen); + dmxLog(dmxDebug, "%d/%s/%lu and %d/%s/%lu are on the same backend\n", + dmxScreen->index, dmxScreen->name, dmxScreen->scrnWin, + other->index, other->name, other->scrnWin); + } + + XmuSnprintf(buf, sizeof(buf), ".%d,%lu", dmxScreen->index, + (long unsigned)win); + XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, + PropModeAppend, (unsigned char *)buf, strlen(buf)); + + XmuSnprintf(buf, sizeof(buf), "%s,%d", id, dmxScreen->index); + XChangeProperty(dpy, win, atom, XA_STRING, 8, + PropModeAppend, (unsigned char *)buf, strlen(buf)); +} diff --git a/xorg-server/hw/dmx/dmxscrinit.c b/xorg-server/hw/dmx/dmxscrinit.c index c1beb9ba5..edb14a23a 100644 --- a/xorg-server/hw/dmx/dmxscrinit.c +++ b/xorg-server/hw/dmx/dmxscrinit.c @@ -1,524 +1,524 @@ -/* - * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Kevin E. Martin - * David H. Dawes - * - */ - -/** \file - * This file provides support for screen initialization. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxshadow.h" -#include "dmxscrinit.h" -#include "dmxcursor.h" -#include "dmxgc.h" -#include "dmxgcops.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxfont.h" -#include "dmxcmap.h" -#include "dmxprop.h" -#include "dmxdpms.h" - -#include "dmxpict.h" - -#include "fb.h" -#include "mipointer.h" -#include "micmap.h" - -extern Bool dmxCloseScreen(int idx, ScreenPtr pScreen); -static Bool dmxSaveScreen(ScreenPtr pScreen, int what); - -static unsigned long dmxGeneration; -static unsigned long *dmxCursorGeneration; - -static int dmxGCPrivateKeyIndex; -DevPrivateKey dmxGCPrivateKey = &dmxGCPrivateKeyIndex; /**< Private index for GCs */ -static int dmxWinPrivateKeyIndex; -DevPrivateKey dmxWinPrivateKey = &dmxWinPrivateKeyIndex; /**< Private index for Windows */ -static int dmxPixPrivateKeyIndex; -DevPrivateKey dmxPixPrivateKey = &dmxPixPrivateKeyIndex; /**< Private index for Pixmaps */ -int dmxFontPrivateIndex; /**< Private index for Fonts */ -static int dmxScreenPrivateKeyIndex; -DevPrivateKey dmxScreenPrivateKey = &dmxScreenPrivateKeyIndex; /**< Private index for Screens */ -static int dmxColormapPrivateKeyIndex; -DevPrivateKey dmxColormapPrivateKey = &dmxColormapPrivateKeyIndex; /**< Private index for Colormaps */ -static int dmxPictPrivateKeyIndex; -DevPrivateKey dmxPictPrivateKey = &dmxPictPrivateKeyIndex; /**< Private index for Picts */ -static int dmxGlyphSetPrivateKeyIndex; -DevPrivateKey dmxGlyphSetPrivateKey = &dmxGlyphSetPrivateKeyIndex; /**< Private index for GlyphSets */ - -/** Initialize the parts of screen \a idx that require access to the - * back-end server. */ -void dmxBEScreenInit(int idx, ScreenPtr pScreen) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - XSetWindowAttributes attribs; - XGCValues gcvals; - unsigned long mask; - int i, j; - - /* FIXME: The dmxScreenInit() code currently assumes that it will - * not be called if the Xdmx server is started with this screen - * detached -- i.e., it assumes that dmxScreen->beDisplay is always - * valid. This is not necessarily a valid assumption when full - * addition/removal of screens is implemented, but when this code is - * broken out for screen reattachment, then we will reevaluate this - * assumption. - */ - - pScreen->mmWidth = DisplayWidthMM(dmxScreen->beDisplay, - DefaultScreen(dmxScreen->beDisplay)); - pScreen->mmHeight = DisplayHeightMM(dmxScreen->beDisplay, - DefaultScreen(dmxScreen->beDisplay)); - - pScreen->whitePixel = dmxScreen->beWhitePixel; - pScreen->blackPixel = dmxScreen->beBlackPixel; - - /* Handle screen savers and DPMS on the backend */ - dmxDPMSInit(dmxScreen); - - /* Create root window for screen */ - mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; - attribs.background_pixel = dmxScreen->beBlackPixel; - attribs.event_mask = (KeyPressMask - | KeyReleaseMask - | ButtonPressMask - | ButtonReleaseMask - | EnterWindowMask - | LeaveWindowMask - | PointerMotionMask - | KeymapStateMask - | FocusChangeMask); - attribs.colormap = dmxScreen->beDefColormaps[dmxScreen->beDefVisualIndex]; - attribs.override_redirect = True; - - dmxScreen->scrnWin = - XCreateWindow(dmxScreen->beDisplay, - DefaultRootWindow(dmxScreen->beDisplay), - dmxScreen->scrnX, - dmxScreen->scrnY, - dmxScreen->scrnWidth, - dmxScreen->scrnHeight, - 0, - pScreen->rootDepth, - InputOutput, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - mask, - &attribs); - dmxPropertyWindow(dmxScreen); - - /* - * This turns off the cursor by defining a cursor with no visible - * components. - */ - { - char noCursorData[] = {0, 0, 0, 0, - 0, 0, 0, 0}; - Pixmap pixmap; - XColor color, tmp; - - pixmap = XCreateBitmapFromData(dmxScreen->beDisplay, dmxScreen->scrnWin, - noCursorData, 8, 8); - XAllocNamedColor(dmxScreen->beDisplay, dmxScreen->beDefColormaps[0], - "black", &color, &tmp); - dmxScreen->noCursor = XCreatePixmapCursor(dmxScreen->beDisplay, - pixmap, pixmap, - &color, &color, 0, 0); - XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, - dmxScreen->noCursor); - - XFreePixmap(dmxScreen->beDisplay, pixmap); - } - - XMapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); - - if (dmxShadowFB) { - mask = (GCFunction - | GCPlaneMask - | GCClipMask); - gcvals.function = GXcopy; - gcvals.plane_mask = AllPlanes; - gcvals.clip_mask = None; - - dmxScreen->shadowGC = XCreateGC(dmxScreen->beDisplay, - dmxScreen->scrnWin, - mask, &gcvals); - - dmxScreen->shadowFBImage = - XCreateImage(dmxScreen->beDisplay, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - dmxScreen->beDepth, - ZPixmap, - 0, - (char *)dmxScreen->shadow, - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->beBPP, - PixmapBytePad(dmxScreen->scrnWidth, - dmxScreen->beBPP)); - } else { - /* Create default drawables (used during GC creation) */ - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) - for (j = 0; j < dmxScreen->beNumDepths; j++) - if ((dmxScreen->bePixmapFormats[i].depth == 1) || - (dmxScreen->bePixmapFormats[i].depth == - dmxScreen->beDepths[j])) { - dmxScreen->scrnDefDrawables[i] = (Drawable) - XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, - 1, 1, dmxScreen->bePixmapFormats[i].depth); - break; - } - } -} - -/** Initialize screen number \a idx. */ -Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - int i, j; - - if (dmxGeneration != serverGeneration) { - /* Allocate font private index */ - dmxFontPrivateIndex = AllocateFontPrivateIndex(); - if (dmxFontPrivateIndex == -1) - return FALSE; - - dmxGeneration = serverGeneration; - } - - if (dmxShadowFB) { - dmxScreen->shadow = shadowAlloc(dmxScreen->scrnWidth, - dmxScreen->scrnHeight, - dmxScreen->beBPP); - } else { - if (!dmxInitGC(pScreen)) return FALSE; - if (!dmxInitWindow(pScreen)) return FALSE; - if (!dmxInitPixmap(pScreen)) return FALSE; - } - - /* - * Initalise the visual types. miSetVisualTypesAndMasks() requires - * that all of the types for each depth be collected together. It's - * intended for slightly different usage to what we would like here. - * Maybe a miAddVisualTypeAndMask() function will be added to make - * things easier here. - */ - for (i = 0; i < dmxScreen->beNumDepths; i++) { - int depth; - int visuals = 0; - int bitsPerRgb = 0; - int preferredClass = -1; - Pixel redMask = 0; - Pixel greenMask = 0; - Pixel blueMask = 0; - - depth = dmxScreen->beDepths[i]; - for (j = 0; j < dmxScreen->beNumVisuals; j++) { - XVisualInfo *vi; - - vi = &dmxScreen->beVisuals[j]; - if (vi->depth == depth) { - /* Assume the masks are all the same. */ - visuals |= (1 << vi->class); - bitsPerRgb = vi->bits_per_rgb; - redMask = vi->red_mask; - greenMask = vi->green_mask; - blueMask = vi->blue_mask; - if (j == dmxScreen->beDefVisualIndex) { - preferredClass = vi->class; - } - } - } - miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, preferredClass, - redMask, greenMask, blueMask); - } - - fbScreenInit(pScreen, - dmxShadowFB ? dmxScreen->shadow : NULL, - dmxScreen->scrnWidth, - dmxScreen->scrnHeight, - dmxScreen->beXDPI, - dmxScreen->beXDPI, - dmxScreen->scrnWidth, - dmxScreen->beBPP); - (void)dmxPictureInit(pScreen, 0, 0); - - /* Not yet... */ - pScreen->GetWindowPixmap = NULL; - pScreen->SetWindowPixmap = NULL; - - if (dmxShadowFB && !shadowInit(pScreen, dmxShadowUpdateProc, NULL)) - return FALSE; - - miInitializeBackingStore(pScreen); - - if (dmxShadowFB) { - miDCInitialize(pScreen, &dmxPointerCursorFuncs); - } else { - MAXSCREENSALLOC(dmxCursorGeneration); - if (dmxCursorGeneration[idx] != serverGeneration) { - if (!(miPointerInitialize(pScreen, - &dmxPointerSpriteFuncs, - &dmxPointerCursorFuncs, - FALSE))) - return FALSE; - - dmxCursorGeneration[idx] = serverGeneration; - } - } - - DMX_WRAP(CloseScreen, dmxCloseScreen, dmxScreen, pScreen); - DMX_WRAP(SaveScreen, dmxSaveScreen, dmxScreen, pScreen); - - dmxBEScreenInit(idx, pScreen); - - if (!dmxShadowFB) { - /* Wrap GC functions */ - DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); - - /* Wrap Window functions */ - DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); - DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); - DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); - DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, - pScreen); - DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); - DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); - DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); - DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); - DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); - - DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); - DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); - - DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); - - /* Wrap Image functions */ - DMX_WRAP(GetImage, dmxGetImage, dmxScreen, pScreen); - DMX_WRAP(GetSpans, dmxGetSpans, dmxScreen, pScreen); - - /* Wrap Pixmap functions */ - DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); - DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); - DMX_WRAP(BitmapToRegion, dmxBitmapToRegion, dmxScreen, pScreen); - - /* Wrap Font functions */ - DMX_WRAP(RealizeFont, dmxRealizeFont, dmxScreen, pScreen); - DMX_WRAP(UnrealizeFont, dmxUnrealizeFont, dmxScreen, pScreen); - - /* Wrap Colormap functions */ - DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); - DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); - DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); - DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); - - /* Wrap Shape functions */ - DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); - } - - if (!dmxCreateDefColormap(pScreen)) - return FALSE; - - return TRUE; -} - -/** Close the \a pScreen resources on the back-end server. */ -void dmxBECloseScreen(ScreenPtr pScreen) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - int i; - - /* Restore the back-end screen-saver and DPMS state. */ - dmxDPMSTerm(dmxScreen); - - /* Free the screen resources */ - - XFreeCursor(dmxScreen->beDisplay, dmxScreen->noCursor); - dmxScreen->noCursor = (Cursor)0; - - XUnmapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); - XDestroyWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); - dmxScreen->scrnWin = (Window)0; - - if (dmxShadowFB) { - /* Free the shadow GC and image assocated with the back-end server */ - XFreeGC(dmxScreen->beDisplay, dmxScreen->shadowGC); - dmxScreen->shadowGC = NULL; - XFree(dmxScreen->shadowFBImage); - dmxScreen->shadowFBImage = NULL; - } else { - /* Free the default drawables */ - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - if (dmxScreen->scrnDefDrawables[i]) { - XFreePixmap(dmxScreen->beDisplay, - dmxScreen->scrnDefDrawables[i]); - dmxScreen->scrnDefDrawables[i] = (Drawable)0; - } - } - } - - /* Free resources allocated during initialization (in dmxinit.c) */ - for (i = 0; i < dmxScreen->beNumDefColormaps; i++) - XFreeColormap(dmxScreen->beDisplay, dmxScreen->beDefColormaps[i]); - xfree(dmxScreen->beDefColormaps); - dmxScreen->beDefColormaps = NULL; - -#if 0 - /* Do not free visuals, depths and pixmap formats here. Free them - * in dmxCloseScreen() instead -- see comment below. */ - XFree(dmxScreen->beVisuals); - dmxScreen->beVisuals = NULL; - - XFree(dmxScreen->beDepths); - dmxScreen->beDepths = NULL; - - XFree(dmxScreen->bePixmapFormats); - dmxScreen->bePixmapFormats = NULL; -#endif - -#ifdef GLXEXT - if (dmxScreen->glxVisuals) { - XFree(dmxScreen->glxVisuals); - dmxScreen->glxVisuals = NULL; - dmxScreen->numGlxVisuals = 0; - } -#endif - - /* Close display */ - XCloseDisplay(dmxScreen->beDisplay); - dmxScreen->beDisplay = NULL; -} - -/** Close screen number \a idx. */ -Bool dmxCloseScreen(int idx, ScreenPtr pScreen) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - - /* Reset the proc vectors */ - if (idx == 0) { - dmxResetRender(); - dmxResetFonts(); - } - - if (dmxShadowFB) { - /* Free the shadow framebuffer */ - xfree(dmxScreen->shadow); - } else { - - /* Unwrap Shape functions */ - DMX_UNWRAP(SetShape, dmxScreen, pScreen); - - /* Unwrap the pScreen functions */ - DMX_UNWRAP(CreateGC, dmxScreen, pScreen); - - DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); - DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); - DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); - DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); - DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); - DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); - DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); - DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); - DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); - - DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); - DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); - - DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); - - DMX_UNWRAP(GetImage, dmxScreen, pScreen); - DMX_UNWRAP(GetSpans, dmxScreen, pScreen); - - DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); - DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); - DMX_UNWRAP(BitmapToRegion, dmxScreen, pScreen); - - DMX_UNWRAP(RealizeFont, dmxScreen, pScreen); - DMX_UNWRAP(UnrealizeFont, dmxScreen, pScreen); - - DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); - DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); - DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); - DMX_UNWRAP(StoreColors, dmxScreen, pScreen); - } - - DMX_UNWRAP(SaveScreen, dmxScreen, pScreen); - - if (dmxScreen->beDisplay) { - dmxBECloseScreen(pScreen); - -#if 1 - /* Free visuals, depths and pixmap formats here so that they - * won't be freed when a screen is detached, thereby allowing - * the screen to be reattached to be compared to the one - * previously removed. - */ - XFree(dmxScreen->beVisuals); - dmxScreen->beVisuals = NULL; - - XFree(dmxScreen->beDepths); - dmxScreen->beDepths = NULL; - - XFree(dmxScreen->bePixmapFormats); - dmxScreen->bePixmapFormats = NULL; -#endif - } - - DMX_UNWRAP(CloseScreen, dmxScreen, pScreen); - return pScreen->CloseScreen(idx, pScreen); -} - -static Bool dmxSaveScreen(ScreenPtr pScreen, int what) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - if (dmxScreen->beDisplay) { - switch (what) { - case SCREEN_SAVER_OFF: - case SCREEN_SAVER_FORCER: - XResetScreenSaver(dmxScreen->beDisplay); - dmxSync(dmxScreen, FALSE); - break; - case SCREEN_SAVER_ON: - case SCREEN_SAVER_CYCLE: - XActivateScreenSaver(dmxScreen->beDisplay); - dmxSync(dmxScreen, FALSE); - break; - } - } - - return TRUE; -} +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Kevin E. Martin + * David H. Dawes + * + */ + +/** \file + * This file provides support for screen initialization. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxshadow.h" +#include "dmxscrinit.h" +#include "dmxcursor.h" +#include "dmxgc.h" +#include "dmxgcops.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxfont.h" +#include "dmxcmap.h" +#include "dmxprop.h" +#include "dmxdpms.h" + +#include "dmxpict.h" + +#include "fb.h" +#include "mipointer.h" +#include "micmap.h" + +extern Bool dmxCloseScreen(int idx, ScreenPtr pScreen); +static Bool dmxSaveScreen(ScreenPtr pScreen, int what); + +static unsigned long dmxGeneration; +static unsigned long *dmxCursorGeneration; + +static int dmxGCPrivateKeyIndex; +DevPrivateKey dmxGCPrivateKey = &dmxGCPrivateKeyIndex; /**< Private index for GCs */ +static int dmxWinPrivateKeyIndex; +DevPrivateKey dmxWinPrivateKey = &dmxWinPrivateKeyIndex; /**< Private index for Windows */ +static int dmxPixPrivateKeyIndex; +DevPrivateKey dmxPixPrivateKey = &dmxPixPrivateKeyIndex; /**< Private index for Pixmaps */ +int dmxFontPrivateIndex; /**< Private index for Fonts */ +static int dmxScreenPrivateKeyIndex; +DevPrivateKey dmxScreenPrivateKey = &dmxScreenPrivateKeyIndex; /**< Private index for Screens */ +static int dmxColormapPrivateKeyIndex; +DevPrivateKey dmxColormapPrivateKey = &dmxColormapPrivateKeyIndex; /**< Private index for Colormaps */ +static int dmxPictPrivateKeyIndex; +DevPrivateKey dmxPictPrivateKey = &dmxPictPrivateKeyIndex; /**< Private index for Picts */ +static int dmxGlyphSetPrivateKeyIndex; +DevPrivateKey dmxGlyphSetPrivateKey = &dmxGlyphSetPrivateKeyIndex; /**< Private index for GlyphSets */ + +/** Initialize the parts of screen \a idx that require access to the + * back-end server. */ +void dmxBEScreenInit(int idx, ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + XSetWindowAttributes attribs; + XGCValues gcvals; + unsigned long mask; + int i, j; + + /* FIXME: The dmxScreenInit() code currently assumes that it will + * not be called if the Xdmx server is started with this screen + * detached -- i.e., it assumes that dmxScreen->beDisplay is always + * valid. This is not necessarily a valid assumption when full + * addition/removal of screens is implemented, but when this code is + * broken out for screen reattachment, then we will reevaluate this + * assumption. + */ + + pScreen->mmWidth = DisplayWidthMM(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay)); + pScreen->mmHeight = DisplayHeightMM(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay)); + + pScreen->whitePixel = dmxScreen->beWhitePixel; + pScreen->blackPixel = dmxScreen->beBlackPixel; + + /* Handle screen savers and DPMS on the backend */ + dmxDPMSInit(dmxScreen); + + /* Create root window for screen */ + mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; + attribs.background_pixel = dmxScreen->beBlackPixel; + attribs.event_mask = (KeyPressMask + | KeyReleaseMask + | ButtonPressMask + | ButtonReleaseMask + | EnterWindowMask + | LeaveWindowMask + | PointerMotionMask + | KeymapStateMask + | FocusChangeMask); + attribs.colormap = dmxScreen->beDefColormaps[dmxScreen->beDefVisualIndex]; + attribs.override_redirect = True; + + dmxScreen->scrnWin = + XCreateWindow(dmxScreen->beDisplay, + DefaultRootWindow(dmxScreen->beDisplay), + dmxScreen->scrnX, + dmxScreen->scrnY, + dmxScreen->scrnWidth, + dmxScreen->scrnHeight, + 0, + pScreen->rootDepth, + InputOutput, + dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, + mask, + &attribs); + dmxPropertyWindow(dmxScreen); + + /* + * This turns off the cursor by defining a cursor with no visible + * components. + */ + { + char noCursorData[] = {0, 0, 0, 0, + 0, 0, 0, 0}; + Pixmap pixmap; + XColor color, tmp; + + pixmap = XCreateBitmapFromData(dmxScreen->beDisplay, dmxScreen->scrnWin, + noCursorData, 8, 8); + XAllocNamedColor(dmxScreen->beDisplay, dmxScreen->beDefColormaps[0], + "black", &color, &tmp); + dmxScreen->noCursor = XCreatePixmapCursor(dmxScreen->beDisplay, + pixmap, pixmap, + &color, &color, 0, 0); + XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, + dmxScreen->noCursor); + + XFreePixmap(dmxScreen->beDisplay, pixmap); + } + + XMapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); + + if (dmxShadowFB) { + mask = (GCFunction + | GCPlaneMask + | GCClipMask); + gcvals.function = GXcopy; + gcvals.plane_mask = AllPlanes; + gcvals.clip_mask = None; + + dmxScreen->shadowGC = XCreateGC(dmxScreen->beDisplay, + dmxScreen->scrnWin, + mask, &gcvals); + + dmxScreen->shadowFBImage = + XCreateImage(dmxScreen->beDisplay, + dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, + dmxScreen->beDepth, + ZPixmap, + 0, + (char *)dmxScreen->shadow, + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->beBPP, + PixmapBytePad(dmxScreen->scrnWidth, + dmxScreen->beBPP)); + } else { + /* Create default drawables (used during GC creation) */ + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) + for (j = 0; j < dmxScreen->beNumDepths; j++) + if ((dmxScreen->bePixmapFormats[i].depth == 1) || + (dmxScreen->bePixmapFormats[i].depth == + dmxScreen->beDepths[j])) { + dmxScreen->scrnDefDrawables[i] = (Drawable) + XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, + 1, 1, dmxScreen->bePixmapFormats[i].depth); + break; + } + } +} + +/** Initialize screen number \a idx. */ +Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + int i, j; + + if (dmxGeneration != serverGeneration) { + /* Allocate font private index */ + dmxFontPrivateIndex = AllocateFontPrivateIndex(); + if (dmxFontPrivateIndex == -1) + return FALSE; + + dmxGeneration = serverGeneration; + } + + if (dmxShadowFB) { + dmxScreen->shadow = shadowAlloc(dmxScreen->scrnWidth, + dmxScreen->scrnHeight, + dmxScreen->beBPP); + } else { + if (!dmxInitGC(pScreen)) return FALSE; + if (!dmxInitWindow(pScreen)) return FALSE; + if (!dmxInitPixmap(pScreen)) return FALSE; + } + + /* + * Initalise the visual types. miSetVisualTypesAndMasks() requires + * that all of the types for each depth be collected together. It's + * intended for slightly different usage to what we would like here. + * Maybe a miAddVisualTypeAndMask() function will be added to make + * things easier here. + */ + for (i = 0; i < dmxScreen->beNumDepths; i++) { + int depth; + int visuals = 0; + int bitsPerRgb = 0; + int preferredClass = -1; + Pixel redMask = 0; + Pixel greenMask = 0; + Pixel blueMask = 0; + + depth = dmxScreen->beDepths[i]; + for (j = 0; j < dmxScreen->beNumVisuals; j++) { + XVisualInfo *vi; + + vi = &dmxScreen->beVisuals[j]; + if (vi->depth == depth) { + /* Assume the masks are all the same. */ + visuals |= (1 << vi->class); + bitsPerRgb = vi->bits_per_rgb; + redMask = vi->red_mask; + greenMask = vi->green_mask; + blueMask = vi->blue_mask; + if (j == dmxScreen->beDefVisualIndex) { + preferredClass = vi->class; + } + } + } + miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, preferredClass, + redMask, greenMask, blueMask); + } + + fbScreenInit(pScreen, + dmxShadowFB ? dmxScreen->shadow : NULL, + dmxScreen->scrnWidth, + dmxScreen->scrnHeight, + dmxScreen->beXDPI, + dmxScreen->beXDPI, + dmxScreen->scrnWidth, + dmxScreen->beBPP); + (void)dmxPictureInit(pScreen, 0, 0); + + /* Not yet... */ + pScreen->GetWindowPixmap = NULL; + pScreen->SetWindowPixmap = NULL; + + if (dmxShadowFB && !shadowInit(pScreen, dmxShadowUpdateProc, NULL)) + return FALSE; + + miInitializeBackingStore(pScreen); + + if (dmxShadowFB) { + miDCInitialize(pScreen, &dmxPointerCursorFuncs); + } else { + MAXSCREENSALLOC(dmxCursorGeneration); + if (dmxCursorGeneration[idx] != serverGeneration) { + if (!(miPointerInitialize(pScreen, + &dmxPointerSpriteFuncs, + &dmxPointerCursorFuncs, + FALSE))) + return FALSE; + + dmxCursorGeneration[idx] = serverGeneration; + } + } + + DMX_WRAP(CloseScreen, dmxCloseScreen, dmxScreen, pScreen); + DMX_WRAP(SaveScreen, dmxSaveScreen, dmxScreen, pScreen); + + dmxBEScreenInit(idx, pScreen); + + if (!dmxShadowFB) { + /* Wrap GC functions */ + DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); + + /* Wrap Window functions */ + DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); + DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); + DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); + DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, + pScreen); + DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); + DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); + DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); + DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); + DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); + + DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); + DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); + + DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); + + /* Wrap Image functions */ + DMX_WRAP(GetImage, dmxGetImage, dmxScreen, pScreen); + DMX_WRAP(GetSpans, dmxGetSpans, dmxScreen, pScreen); + + /* Wrap Pixmap functions */ + DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); + DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); + DMX_WRAP(BitmapToRegion, dmxBitmapToRegion, dmxScreen, pScreen); + + /* Wrap Font functions */ + DMX_WRAP(RealizeFont, dmxRealizeFont, dmxScreen, pScreen); + DMX_WRAP(UnrealizeFont, dmxUnrealizeFont, dmxScreen, pScreen); + + /* Wrap Colormap functions */ + DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); + DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); + DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); + DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); + + /* Wrap Shape functions */ + DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); + } + + if (!dmxCreateDefColormap(pScreen)) + return FALSE; + + return TRUE; +} + +/** Close the \a pScreen resources on the back-end server. */ +void dmxBECloseScreen(ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int i; + + /* Restore the back-end screen-saver and DPMS state. */ + dmxDPMSTerm(dmxScreen); + + /* Free the screen resources */ + + XFreeCursor(dmxScreen->beDisplay, dmxScreen->noCursor); + dmxScreen->noCursor = (Cursor)0; + + XUnmapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); + XDestroyWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); + dmxScreen->scrnWin = (Window)0; + + if (dmxShadowFB) { + /* Free the shadow GC and image assocated with the back-end server */ + XFreeGC(dmxScreen->beDisplay, dmxScreen->shadowGC); + dmxScreen->shadowGC = NULL; + XFree(dmxScreen->shadowFBImage); + dmxScreen->shadowFBImage = NULL; + } else { + /* Free the default drawables */ + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (dmxScreen->scrnDefDrawables[i]) { + XFreePixmap(dmxScreen->beDisplay, + dmxScreen->scrnDefDrawables[i]); + dmxScreen->scrnDefDrawables[i] = (Drawable)0; + } + } + } + + /* Free resources allocated during initialization (in dmxinit.c) */ + for (i = 0; i < dmxScreen->beNumDefColormaps; i++) + XFreeColormap(dmxScreen->beDisplay, dmxScreen->beDefColormaps[i]); + free(dmxScreen->beDefColormaps); + dmxScreen->beDefColormaps = NULL; + +#if 0 + /* Do not free visuals, depths and pixmap formats here. Free them + * in dmxCloseScreen() instead -- see comment below. */ + XFree(dmxScreen->beVisuals); + dmxScreen->beVisuals = NULL; + + XFree(dmxScreen->beDepths); + dmxScreen->beDepths = NULL; + + XFree(dmxScreen->bePixmapFormats); + dmxScreen->bePixmapFormats = NULL; +#endif + +#ifdef GLXEXT + if (dmxScreen->glxVisuals) { + XFree(dmxScreen->glxVisuals); + dmxScreen->glxVisuals = NULL; + dmxScreen->numGlxVisuals = 0; + } +#endif + + /* Close display */ + XCloseDisplay(dmxScreen->beDisplay); + dmxScreen->beDisplay = NULL; +} + +/** Close screen number \a idx. */ +Bool dmxCloseScreen(int idx, ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + + /* Reset the proc vectors */ + if (idx == 0) { + dmxResetRender(); + dmxResetFonts(); + } + + if (dmxShadowFB) { + /* Free the shadow framebuffer */ + free(dmxScreen->shadow); + } else { + + /* Unwrap Shape functions */ + DMX_UNWRAP(SetShape, dmxScreen, pScreen); + + /* Unwrap the pScreen functions */ + DMX_UNWRAP(CreateGC, dmxScreen, pScreen); + + DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); + DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); + DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); + DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); + DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); + DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); + DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); + DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); + DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); + + DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); + DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); + + DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); + + DMX_UNWRAP(GetImage, dmxScreen, pScreen); + DMX_UNWRAP(GetSpans, dmxScreen, pScreen); + + DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); + DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); + DMX_UNWRAP(BitmapToRegion, dmxScreen, pScreen); + + DMX_UNWRAP(RealizeFont, dmxScreen, pScreen); + DMX_UNWRAP(UnrealizeFont, dmxScreen, pScreen); + + DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); + DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); + DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); + DMX_UNWRAP(StoreColors, dmxScreen, pScreen); + } + + DMX_UNWRAP(SaveScreen, dmxScreen, pScreen); + + if (dmxScreen->beDisplay) { + dmxBECloseScreen(pScreen); + +#if 1 + /* Free visuals, depths and pixmap formats here so that they + * won't be freed when a screen is detached, thereby allowing + * the screen to be reattached to be compared to the one + * previously removed. + */ + XFree(dmxScreen->beVisuals); + dmxScreen->beVisuals = NULL; + + XFree(dmxScreen->beDepths); + dmxScreen->beDepths = NULL; + + XFree(dmxScreen->bePixmapFormats); + dmxScreen->bePixmapFormats = NULL; +#endif + } + + DMX_UNWRAP(CloseScreen, dmxScreen, pScreen); + return pScreen->CloseScreen(idx, pScreen); +} + +static Bool dmxSaveScreen(ScreenPtr pScreen, int what) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (dmxScreen->beDisplay) { + switch (what) { + case SCREEN_SAVER_OFF: + case SCREEN_SAVER_FORCER: + XResetScreenSaver(dmxScreen->beDisplay); + dmxSync(dmxScreen, FALSE); + break; + case SCREEN_SAVER_ON: + case SCREEN_SAVER_CYCLE: + XActivateScreenSaver(dmxScreen->beDisplay); + dmxSync(dmxScreen, FALSE); + break; + } + } + + return TRUE; +} diff --git a/xorg-server/hw/dmx/dmxsync.c b/xorg-server/hw/dmx/dmxsync.c index 2cec1b97c..8ace59470 100644 --- a/xorg-server/hw/dmx/dmxsync.c +++ b/xorg-server/hw/dmx/dmxsync.c @@ -1,193 +1,193 @@ -/* - * Copyright 2002-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * - * The DMX server code is written to call #dmxSync() whenever an XSync() - * might be necessary. However, since XSync() requires a two way - * communication with the other X server, eliminating unnecessary - * XSync() calls is a key performance optimization. Support for this - * optimization is provided here. Statistics about XSync() calls and - * latency are gathered in \a dmxstat.c. - * - * During the initial conversion from calling XSync() immediately to the - * XSync() batching method implemented in this file, it was noted that, - * out of more than 300 \a x11perf tests, 8 tests became more than 100 - * times faster, with 68 more than 50X faster, 114 more than 10X faster, - * and 181 more than 2X faster. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxstat.h" -#include "dmxlog.h" -#include - -static int dmxSyncInterval = 100; /* Default interval in milliseconds */ -static OsTimerPtr dmxSyncTimer; -static int dmxSyncPending; - -static void dmxDoSync(DMXScreenInfo *dmxScreen) -{ - dmxScreen->needsSync = FALSE; - - if (!dmxScreen->beDisplay) - return; /* FIXME: Is this correct behavior for sync stats? */ - - if (!dmxStatInterval) { - XSync(dmxScreen->beDisplay, False); - } else { - struct timeval start, stop; - - gettimeofday(&start, 0); - XSync(dmxScreen->beDisplay, False); - gettimeofday(&stop, 0); - dmxStatSync(dmxScreen, &stop, &start, dmxSyncPending); - } -} - -static CARD32 dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg) -{ - int i; - - if (dmxSyncPending) { - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - if (dmxScreen->needsSync) dmxDoSync(dmxScreen); - } - } - dmxSyncPending = 0; - return 0; /* Do not place on queue again */ -} - -static void dmxSyncBlockHandler(pointer blockData, OSTimePtr pTimeout, - pointer pReadMask) -{ - TimerForce(dmxSyncTimer); -} - -static void dmxSyncWakeupHandler(pointer blockData, int result, - pointer pReadMask) -{ -} - -/** Request the XSync() batching optimization with the specified \a - * interval (in mS). If the \a interval is 0, 100mS is used. If the \a - * interval is less than 0, then the XSync() batching optimization is - * not requested (e.g., so the -syncbatch -1 command line option can - * turn off the default 100mS XSync() batching). - * - * Note that the parameter to this routine is a string, since it will - * usually be called from #ddxProcessArgument in \a dmxinit.c */ -void dmxSyncActivate(const char *interval) -{ - dmxSyncInterval = (interval ? atoi(interval) : 100); - - if (dmxSyncInterval < 0) dmxSyncInterval = 0; -} - -/** Initialize the XSync() batching optimization, but only if - * #dmxSyncActivate was last called with a non-negative value. */ -void dmxSyncInit(void) -{ - if (dmxSyncInterval) { - RegisterBlockAndWakeupHandlers(dmxSyncBlockHandler, - dmxSyncWakeupHandler, - NULL); - dmxLog(dmxInfo, "XSync batching with %d ms interval\n", - dmxSyncInterval); - } else { - dmxLog(dmxInfo, "XSync batching disabled\n"); - } -} - -/** Request an XSync() to the display used by \a dmxScreen. If \a now - * is TRUE, call XSync() immediately instead of waiting for the next - * XSync() batching point. Note that if XSync() batching was deselected - * with #dmxSyncActivate() before #dmxSyncInit() was called, then no - * XSync() batching is performed and this function always calles XSync() - * immediately. - * - * (Note that this function uses TimerSet but works correctly in the - * face of a server generation. See the source for details.) - * - * If \a dmxScreen is \a NULL, then all pending syncs will be flushed - * immediately. - */ -void dmxSync(DMXScreenInfo *dmxScreen, Bool now) -{ - static unsigned long dmxGeneration = 0; - - if (dmxSyncInterval) { - if (dmxGeneration != serverGeneration) { - /* Server generation does a TimerInit, which frees all - * timers. So, at this point dmxSyncTimer is either: - * 1) NULL, iff dmxGeneration == 0, - * 2) freed, if it was on a queue (dmxSyncPending != 0), or - * 3) allocated, if it wasn't on a queue (dmxSyncPending == 0) - */ - if (dmxSyncTimer && !dmxSyncPending) xfree(dmxSyncTimer); - dmxSyncTimer = NULL; - now = TRUE; - dmxGeneration = serverGeneration; - } - /* Queue sync */ - if (dmxScreen) { - dmxScreen->needsSync = TRUE; - ++dmxSyncPending; - } - - /* Do sync or set time for later */ - if (now || !dmxScreen) { - if (!TimerForce(dmxSyncTimer)) dmxSyncCallback(NULL, 0, NULL); - /* At this point, dmxSyncPending == 0 because - * dmxSyncCallback must have been called. */ - if (dmxSyncPending) - dmxLog(dmxFatal, "dmxSync(%s,%d): dmxSyncPending = %d\n", - dmxScreen ? dmxScreen->name : "", now, dmxSyncPending); - } else { - dmxScreen->needsSync = TRUE; - if (dmxSyncPending == 1) - dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval, - dmxSyncCallback, NULL); - } - } else { - /* If dmxSyncInterval is not being used, - * then all the backends are already - * up-to-date. */ - if (dmxScreen) dmxDoSync(dmxScreen); - } -} +/* + * Copyright 2002-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * + * The DMX server code is written to call #dmxSync() whenever an XSync() + * might be necessary. However, since XSync() requires a two way + * communication with the other X server, eliminating unnecessary + * XSync() calls is a key performance optimization. Support for this + * optimization is provided here. Statistics about XSync() calls and + * latency are gathered in \a dmxstat.c. + * + * During the initial conversion from calling XSync() immediately to the + * XSync() batching method implemented in this file, it was noted that, + * out of more than 300 \a x11perf tests, 8 tests became more than 100 + * times faster, with 68 more than 50X faster, 114 more than 10X faster, + * and 181 more than 2X faster. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxstat.h" +#include "dmxlog.h" +#include + +static int dmxSyncInterval = 100; /* Default interval in milliseconds */ +static OsTimerPtr dmxSyncTimer; +static int dmxSyncPending; + +static void dmxDoSync(DMXScreenInfo *dmxScreen) +{ + dmxScreen->needsSync = FALSE; + + if (!dmxScreen->beDisplay) + return; /* FIXME: Is this correct behavior for sync stats? */ + + if (!dmxStatInterval) { + XSync(dmxScreen->beDisplay, False); + } else { + struct timeval start, stop; + + gettimeofday(&start, 0); + XSync(dmxScreen->beDisplay, False); + gettimeofday(&stop, 0); + dmxStatSync(dmxScreen, &stop, &start, dmxSyncPending); + } +} + +static CARD32 dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg) +{ + int i; + + if (dmxSyncPending) { + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + if (dmxScreen->needsSync) dmxDoSync(dmxScreen); + } + } + dmxSyncPending = 0; + return 0; /* Do not place on queue again */ +} + +static void dmxSyncBlockHandler(pointer blockData, OSTimePtr pTimeout, + pointer pReadMask) +{ + TimerForce(dmxSyncTimer); +} + +static void dmxSyncWakeupHandler(pointer blockData, int result, + pointer pReadMask) +{ +} + +/** Request the XSync() batching optimization with the specified \a + * interval (in mS). If the \a interval is 0, 100mS is used. If the \a + * interval is less than 0, then the XSync() batching optimization is + * not requested (e.g., so the -syncbatch -1 command line option can + * turn off the default 100mS XSync() batching). + * + * Note that the parameter to this routine is a string, since it will + * usually be called from #ddxProcessArgument in \a dmxinit.c */ +void dmxSyncActivate(const char *interval) +{ + dmxSyncInterval = (interval ? atoi(interval) : 100); + + if (dmxSyncInterval < 0) dmxSyncInterval = 0; +} + +/** Initialize the XSync() batching optimization, but only if + * #dmxSyncActivate was last called with a non-negative value. */ +void dmxSyncInit(void) +{ + if (dmxSyncInterval) { + RegisterBlockAndWakeupHandlers(dmxSyncBlockHandler, + dmxSyncWakeupHandler, + NULL); + dmxLog(dmxInfo, "XSync batching with %d ms interval\n", + dmxSyncInterval); + } else { + dmxLog(dmxInfo, "XSync batching disabled\n"); + } +} + +/** Request an XSync() to the display used by \a dmxScreen. If \a now + * is TRUE, call XSync() immediately instead of waiting for the next + * XSync() batching point. Note that if XSync() batching was deselected + * with #dmxSyncActivate() before #dmxSyncInit() was called, then no + * XSync() batching is performed and this function always calles XSync() + * immediately. + * + * (Note that this function uses TimerSet but works correctly in the + * face of a server generation. See the source for details.) + * + * If \a dmxScreen is \a NULL, then all pending syncs will be flushed + * immediately. + */ +void dmxSync(DMXScreenInfo *dmxScreen, Bool now) +{ + static unsigned long dmxGeneration = 0; + + if (dmxSyncInterval) { + if (dmxGeneration != serverGeneration) { + /* Server generation does a TimerInit, which frees all + * timers. So, at this point dmxSyncTimer is either: + * 1) NULL, iff dmxGeneration == 0, + * 2) freed, if it was on a queue (dmxSyncPending != 0), or + * 3) allocated, if it wasn't on a queue (dmxSyncPending == 0) + */ + if (dmxSyncTimer && !dmxSyncPending) free(dmxSyncTimer); + dmxSyncTimer = NULL; + now = TRUE; + dmxGeneration = serverGeneration; + } + /* Queue sync */ + if (dmxScreen) { + dmxScreen->needsSync = TRUE; + ++dmxSyncPending; + } + + /* Do sync or set time for later */ + if (now || !dmxScreen) { + if (!TimerForce(dmxSyncTimer)) dmxSyncCallback(NULL, 0, NULL); + /* At this point, dmxSyncPending == 0 because + * dmxSyncCallback must have been called. */ + if (dmxSyncPending) + dmxLog(dmxFatal, "dmxSync(%s,%d): dmxSyncPending = %d\n", + dmxScreen ? dmxScreen->name : "", now, dmxSyncPending); + } else { + dmxScreen->needsSync = TRUE; + if (dmxSyncPending == 1) + dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval, + dmxSyncCallback, NULL); + } + } else { + /* If dmxSyncInterval is not being used, + * then all the backends are already + * up-to-date. */ + if (dmxScreen) dmxDoSync(dmxScreen); + } +} diff --git a/xorg-server/hw/dmx/dmxwindow.c b/xorg-server/hw/dmx/dmxwindow.c index ea2f2c579..3466f074f 100644 --- a/xorg-server/hw/dmx/dmxwindow.c +++ b/xorg-server/hw/dmx/dmxwindow.c @@ -1,1015 +1,1015 @@ -/* - * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Kevin E. Martin - * - */ - -/** \file - * This file provides support for window-related functions. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxcmap.h" -#include "dmxvisual.h" -#include "dmxinput.h" -#include "dmxextension.h" -#include "dmxpict.h" - -#include "windowstr.h" - -static void dmxDoRestackWindow(WindowPtr pWindow); -static void dmxDoChangeWindowAttributes(WindowPtr pWindow, - unsigned long *mask, - XSetWindowAttributes *attribs); - -static void dmxDoSetShape(WindowPtr pWindow); - -/** Initialize the private area for the window functions. */ -Bool dmxInitWindow(ScreenPtr pScreen) -{ - if (!dixRequestPrivate(dmxWinPrivateKey, sizeof(dmxWinPrivRec))) - return FALSE; - - return TRUE; -} - - -Window dmxCreateRootWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - Window parent; - Visual *visual; - unsigned long mask; - XSetWindowAttributes attribs; - ColormapPtr pCmap; - dmxColormapPrivPtr pCmapPriv; - - /* Create root window */ - - parent = dmxScreen->scrnWin; /* This is our "Screen" window */ - visual = dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual; - - pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); - pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); - - mask = CWEventMask | CWBackingStore | CWColormap | CWBorderPixel; - attribs.event_mask = ExposureMask; - attribs.backing_store = NotUseful; - attribs.colormap = pCmapPriv->cmap; - attribs.border_pixel = 0; - - /* Incorporate new attributes, if needed */ - if (pWinPriv->attribMask) { - dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); - mask |= pWinPriv->attribMask; - } - - return XCreateWindow(dmxScreen->beDisplay, - parent, - pWindow->origin.x - wBorderWidth(pWindow), - pWindow->origin.y - wBorderWidth(pWindow), - pWindow->drawable.width, - pWindow->drawable.height, - pWindow->borderWidth, - pWindow->drawable.depth, - pWindow->drawable.class, - visual, - mask, - &attribs); -} - -/** Change the location and size of the "screen" window. Called from - * #dmxConfigureScreenWindow(). */ -void dmxResizeScreenWindow(ScreenPtr pScreen, - int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - unsigned int m; - XWindowChanges c; - - if (!dmxScreen->beDisplay) - return; - - /* Handle resizing on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = x; - c.y = y; - c.width = w; - c.height = h; - - XConfigureWindow(dmxScreen->beDisplay, dmxScreen->scrnWin, m, &c); - dmxSync(dmxScreen, False); -} - -/** Change the location and size of the "root" window. Called from - * #dmxConfigureRootWindow. */ -void dmxResizeRootWindow(WindowPtr pRoot, - int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pRoot->drawable.pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot); - unsigned int m; - XWindowChanges c; - - /* Handle resizing on back-end server */ - if (dmxScreen->beDisplay) { - m = CWX | CWY | CWWidth | CWHeight; - c.x = x; - c.y = y; - c.width = (w > 0) ? w : 1; - c.height = (h > 0) ? h : 1; - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - } - - if (w == 0 || h == 0) { - if (pWinPriv->mapped) { - if (dmxScreen->beDisplay) - XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); - pWinPriv->mapped = FALSE; - } - } else if (!pWinPriv->mapped) { - if (dmxScreen->beDisplay) - XMapWindow(dmxScreen->beDisplay, pWinPriv->window); - pWinPriv->mapped = TRUE; - } - - if (dmxScreen->beDisplay) - dmxSync(dmxScreen, False); -} - -void dmxGetDefaultWindowAttributes(WindowPtr pWindow, - Colormap *cmap, - Visual **visual) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - - if (pWindow->drawable.class != InputOnly && - pWindow->optional && - pWindow->optional->visual != wVisual(pWindow->parent)) { - - /* Find the matching visual */ - *visual = dmxLookupVisualFromID(pScreen, wVisual(pWindow)); - - /* Handle optional colormaps */ - if (pWindow->optional->colormap) { - ColormapPtr pCmap; - dmxColormapPrivPtr pCmapPriv; - - pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), - RT_COLORMAP); - pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); - *cmap = pCmapPriv->cmap; - } else { - *cmap = dmxColormapFromDefaultVisual(pScreen, *visual); - } - } else { - *visual = CopyFromParent; - *cmap = (Colormap)0; - } -} - -static Window dmxCreateNonRootWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - Window parent; - unsigned long mask = 0L; - XSetWindowAttributes attribs; - dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); - - /* Create window on back-end server */ - - parent = pParentPriv->window; - - /* The parent won't exist if this call to CreateNonRootWindow came - from ReparentWindow and the grandparent window has not yet been - created */ - if (!parent) { - dmxCreateAndRealizeWindow(pWindow->parent, FALSE); - parent = pParentPriv->window; - } - - /* Incorporate new attributes, if needed */ - if (pWinPriv->attribMask) { - dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); - mask |= pWinPriv->attribMask; - } - - /* Add in default attributes */ - if (pWindow->drawable.class != InputOnly) { - mask |= CWBackingStore; - attribs.backing_store = NotUseful; - - if (!(mask & CWColormap) && pWinPriv->cmap) { - mask |= CWColormap; - attribs.colormap = pWinPriv->cmap; - if (!(mask & CWBorderPixel)) { - mask |= CWBorderPixel; - attribs.border_pixel = 0; - } - } - } - - /* Handle case where subwindows are being mapped, but created out of - order -- if current window has a previous sibling, then it cannot - be created on top of the stack, so we must restack the windows */ - pWinPriv->restacked = (pWindow->prevSib != NullWindow); - - return XCreateWindow(dmxScreen->beDisplay, - parent, - pWindow->origin.x - wBorderWidth(pWindow), - pWindow->origin.y - wBorderWidth(pWindow), - pWindow->drawable.width, - pWindow->drawable.height, - pWindow->borderWidth, - pWindow->drawable.depth, - pWindow->drawable.class, - pWinPriv->visual, - mask, - &attribs); -} - -/** This function handles lazy window creation and realization. Window - * creation is handled by #dmxCreateNonRootWindow(). It also handles - * any stacking changes that have occured since the window was - * originally created by calling #dmxDoRestackWindow(). If the window - * is shaped, the shape is set on the back-end server by calling - * #dmxDoSetShape(), and if the window has pictures (from RENDER) - * associated with it, those pictures are created on the back-end - * server by calling #dmxCreatePictureList(). If \a doSync is TRUE, - * then #dmxSync() is called. */ -void dmxCreateAndRealizeWindow(WindowPtr pWindow, Bool doSync) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - if (!dmxScreen->beDisplay) return; - - pWinPriv->window = dmxCreateNonRootWindow(pWindow); - if (pWinPriv->restacked) dmxDoRestackWindow(pWindow); - if (pWinPriv->isShaped) dmxDoSetShape(pWindow); - if (pWinPriv->hasPict) dmxCreatePictureList(pWindow); - if (pWinPriv->mapped) XMapWindow(dmxScreen->beDisplay, - pWinPriv->window); - if (doSync) dmxSync(dmxScreen, False); -} - -/** Create \a pWindow on the back-end server. If the lazy window - * creation optimization is enabled, then the actual creation and - * realization of the window is handled by - * #dmxCreateAndRealizeWindow(). */ -Bool dmxCreateWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - Bool ret = TRUE; - - DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->CreateWindow) - ret = pScreen->CreateWindow(pWindow); -#endif - - /* Set up the defaults */ - pWinPriv->window = (Window)0; - pWinPriv->offscreen = TRUE; - pWinPriv->mapped = FALSE; - pWinPriv->restacked = FALSE; - pWinPriv->attribMask = 0; - pWinPriv->isShaped = FALSE; - pWinPriv->hasPict = FALSE; -#ifdef GLXEXT - pWinPriv->swapGroup = NULL; - pWinPriv->barrier = 0; -#endif - - if (dmxScreen->beDisplay) { - /* Only create the root window at this stage -- non-root windows are - created when they are mapped and are on-screen */ - if (!pWindow->parent) { - dmxScreen->rootWin = pWinPriv->window - = dmxCreateRootWindow(pWindow); - if (dmxScreen->scrnX != dmxScreen->rootX - || dmxScreen->scrnY != dmxScreen->rootY - || dmxScreen->scrnWidth != dmxScreen->rootWidth - || dmxScreen->scrnHeight != dmxScreen->rootHeight) { - dmxResizeRootWindow(pWindow, - dmxScreen->rootX, - dmxScreen->rootY, - dmxScreen->rootWidth, - dmxScreen->rootHeight); - dmxUpdateScreenResources(screenInfo.screens[dmxScreen->index], - dmxScreen->rootX, - dmxScreen->rootY, - dmxScreen->rootWidth, - dmxScreen->rootHeight); - pWindow->origin.x = dmxScreen->rootX; - pWindow->origin.y = dmxScreen->rootY; - } - } else { - dmxGetDefaultWindowAttributes(pWindow, - &pWinPriv->cmap, - &pWinPriv->visual); - - if (dmxLazyWindowCreation) { - /* Save parent's visual for use later */ - if (pWinPriv->visual == CopyFromParent) - pWinPriv->visual = - dmxLookupVisualFromID(pScreen, - wVisual(pWindow->parent)); - } else { - pWinPriv->window = dmxCreateNonRootWindow(pWindow); - } - } - - dmxSync(dmxScreen, False); - } - - DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); - - return ret; -} - -/** Destroy \a pWindow on the back-end server. */ -Bool dmxBEDestroyWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - if (pWinPriv->window) { - XDestroyWindow(dmxScreen->beDisplay, pWinPriv->window); - pWinPriv->window = (Window)0; - return TRUE; - } - - return FALSE; -} - -/** Destroy \a pWindow on the back-end server. If any RENDER pictures - were created, destroy them as well. */ -Bool dmxDestroyWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - Bool needSync = FALSE; -#ifdef GLXEXT - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); -#endif - - DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); - - /* Destroy any picture list associated with this window */ - needSync |= dmxDestroyPictureList(pWindow); - - /* Destroy window on back-end server */ - needSync |= dmxBEDestroyWindow(pWindow); - if (needSync) dmxSync(dmxScreen, FALSE); - -#ifdef GLXEXT - if (pWinPriv->swapGroup && pWinPriv->windowDestroyed) - pWinPriv->windowDestroyed(pWindow); -#endif - - if (pScreen->DestroyWindow) - ret = pScreen->DestroyWindow(pWindow); - - DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); - - return ret; -} - -/** Change the position of \a pWindow to be \a x, \a y. */ -Bool dmxPositionWindow(WindowPtr pWindow, int x, int y) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - unsigned int m; - XWindowChanges c; - - DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->PositionWindow) - ret = pScreen->PositionWindow(pWindow, x, y); -#endif - - /* Determine if the window is completely off the visible portion of - the screen */ - pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); - - /* If the window is now on-screen and it is mapped and it has not - been created yet, create it and map it */ - if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { - dmxCreateAndRealizeWindow(pWindow, TRUE); - } else if (pWinPriv->window) { - /* Position window on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = pWindow->origin.x - wBorderWidth(pWindow); - c.y = pWindow->origin.y - wBorderWidth(pWindow); - c.width = pWindow->drawable.width; - c.height = pWindow->drawable.height; - if (pWindow->drawable.class != InputOnly) { - m |= CWBorderWidth; - c.border_width = pWindow->borderWidth; - } - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); - - return ret; -} - -static void dmxDoChangeWindowAttributes(WindowPtr pWindow, - unsigned long *mask, - XSetWindowAttributes *attribs) -{ - dmxPixPrivPtr pPixPriv; - - if (*mask & CWBackPixmap) { - switch (pWindow->backgroundState) { - case None: - attribs->background_pixmap = None; - break; - - case ParentRelative: - attribs->background_pixmap = ParentRelative; - break; - - case BackgroundPixmap: - pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->background.pixmap); - attribs->background_pixmap = pPixPriv->pixmap; - break; - - case BackgroundPixel: - *mask &= ~CWBackPixmap; - break; - } - } - - if (*mask & CWBackPixel) { - if (pWindow->backgroundState == BackgroundPixel) - attribs->background_pixel = pWindow->background.pixel; - else - *mask &= ~CWBackPixel; - } - - if (*mask & CWBorderPixmap) { - if (pWindow->borderIsPixel) - *mask &= ~CWBorderPixmap; - else { - pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->border.pixmap); - attribs->border_pixmap = pPixPriv->pixmap; - } - } - - if (*mask & CWBorderPixel) { - if (pWindow->borderIsPixel) - attribs->border_pixel = pWindow->border.pixel; - else - *mask &= ~CWBorderPixel; - } - - if (*mask & CWBitGravity) - attribs->bit_gravity = pWindow->bitGravity; - - if (*mask & CWWinGravity) - *mask &= ~CWWinGravity; /* Handled by dix */ - - if (*mask & CWBackingStore) - *mask &= ~CWBackingStore; /* Backing store not supported */ - - if (*mask & CWBackingPlanes) - *mask &= ~CWBackingPlanes; /* Backing store not supported */ - - if (*mask & CWBackingPixel) - *mask &= ~CWBackingPixel; /* Backing store not supported */ - - if (*mask & CWOverrideRedirect) - attribs->override_redirect = pWindow->overrideRedirect; - - if (*mask & CWSaveUnder) - *mask &= ~CWSaveUnder; /* Save unders not supported */ - - if (*mask & CWEventMask) - *mask &= ~CWEventMask; /* Events are handled by dix */ - - if (*mask & CWDontPropagate) - *mask &= ~CWDontPropagate; /* Events are handled by dix */ - - if (*mask & CWColormap) { - ColormapPtr pCmap; - dmxColormapPrivPtr pCmapPriv; - - pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); - pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); - attribs->colormap = pCmapPriv->cmap; - } - - if (*mask & CWCursor) - *mask &= ~CWCursor; /* Handled by the cursor code */ -} - -/** Change the window attributes of \a pWindow. */ -Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - XSetWindowAttributes attribs; - - DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); -#if 0 - if (pScreen->ChangeWindowAttributes) - ret = pScreen->ChangeWindowAttributes(pWindow, mask); -#endif - - /* Change window attribs on back-end server */ - dmxDoChangeWindowAttributes(pWindow, &mask, &attribs); - - /* Save mask for lazy window creation optimization */ - pWinPriv->attribMask |= mask; - - if (mask && pWinPriv->window) { - XChangeWindowAttributes(dmxScreen->beDisplay, pWinPriv->window, - mask, &attribs); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, - pScreen); - - return ret; -} - -/** Realize \a pWindow on the back-end server. If the lazy window - * creation optimization is enabled, the window is only realized when - * it at least partially overlaps the screen. */ -Bool dmxRealizeWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->RealizeWindow) - ret = pScreen->RealizeWindow(pWindow); -#endif - - /* Determine if the window is completely off the visible portion of - the screen */ - pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); - - /* If the window hasn't been created and it's not offscreen, then - create it */ - if (!pWinPriv->window && !pWinPriv->offscreen) { - dmxCreateAndRealizeWindow(pWindow, FALSE); - } - - if (pWinPriv->window) { - /* Realize window on back-end server */ - XMapWindow(dmxScreen->beDisplay, pWinPriv->window); - dmxSync(dmxScreen, False); - } - - /* Let the other functions know that the window is now mapped */ - pWinPriv->mapped = TRUE; - - DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); - - dmxUpdateWindowInfo(DMX_UPDATE_REALIZE, pWindow); - return ret; -} - -/** Unrealize \a pWindow on the back-end server. */ -Bool dmxUnrealizeWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->UnrealizeWindow) - ret = pScreen->UnrealizeWindow(pWindow); -#endif - - if (pWinPriv->window) { - /* Unrealize window on back-end server */ - XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); - dmxSync(dmxScreen, False); - } - - /* When unrealized (i.e., unmapped), the window is always considered - off of the visible portion of the screen */ - pWinPriv->offscreen = TRUE; - pWinPriv->mapped = FALSE; - -#ifdef GLXEXT - if (pWinPriv->swapGroup && pWinPriv->windowUnmapped) - pWinPriv->windowUnmapped(pWindow); -#endif - - DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); - - dmxUpdateWindowInfo(DMX_UPDATE_UNREALIZE, pWindow); - return ret; -} - -static void dmxDoRestackWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - WindowPtr pNextSib = pWindow->nextSib; - unsigned int m; - XWindowChanges c; - - if (pNextSib == NullWindow) { - /* Window is at the bottom of the stack */ - m = CWStackMode; - c.sibling = (Window)0; - c.stack_mode = Below; - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - } else { - /* Window is not at the bottom of the stack */ - dmxWinPrivPtr pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); - - /* Handle case where siblings have not yet been created due to - lazy window creation optimization by first finding the next - sibling in the sibling list that has been created (if any) - and then putting the current window just above that sibling, - and if no next siblings have been created yet, then put it at - the bottom of the stack (since it might have a previous - sibling that should be above it). */ - while (!pNextSibPriv->window) { - pNextSib = pNextSib->nextSib; - if (pNextSib == NullWindow) { - /* Window is at the bottom of the stack */ - m = CWStackMode; - c.sibling = (Window)0; - c.stack_mode = Below; - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - return; - } - pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); - } - - m = CWStackMode | CWSibling; - c.sibling = pNextSibPriv->window; - c.stack_mode = Above; - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - } -} - -/** Handle window restacking. The actual restacking occurs in - * #dmxDoRestackWindow(). */ -void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->RestackWindow) - pScreen->RestackWindow(pWindow, pOldNextSib); -#endif - - if (pOldNextSib != pWindow->nextSib) { - /* Track restacking for lazy window creation optimization */ - pWinPriv->restacked = TRUE; - - /* Restack window on back-end server */ - if (pWinPriv->window) { - dmxDoRestackWindow(pWindow); - dmxSync(dmxScreen, False); - } - } - - DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_RESTACK, pWindow); -} - -static Bool dmxWindowExposurePredicate(Display *dpy, XEvent *ev, XPointer ptr) -{ - return (ev->type == Expose && ev->xexpose.window == *(Window *)ptr); -} - -/** Handle exposures on \a pWindow. Since window exposures are handled - * in DMX, the events that are generated by the back-end server are - * redundant, so we eat them here. */ -void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn, - RegionPtr other_exposed) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - XEvent ev; - - DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); - - dmxSync(dmxScreen, False); - - if (pWinPriv->window) { - while (XCheckIfEvent(dmxScreen->beDisplay, &ev, - dmxWindowExposurePredicate, - (XPointer)&pWinPriv->window)) { - /* Handle expose events -- this should not be necessary - since the base window in which the root window was - created is guaranteed to be on top (override_redirect), - so we should just swallow these events. If for some - reason the window is not on top, then we'd need to - collect these events and send them to the client later - (e.g., during the block handler as Xnest does). */ - } - } - -#if 1 - if (pScreen->WindowExposures) - pScreen->WindowExposures(pWindow, prgn, other_exposed); -#endif - DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); -} - -/** Move \a pWindow on the back-end server. Determine whether or not it - * is on or offscreen, and realize it if it is newly on screen and the - * lazy window creation optimization is enabled. */ -void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - unsigned int m; - XWindowChanges c; - - DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->CopyWindow) - pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc); -#endif - - /* Determine if the window is completely off the visible portion of - the screen */ - pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); - - /* If the window is now on-screen and it is mapped and it has not - been created yet, create it and map it */ - if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { - dmxCreateAndRealizeWindow(pWindow, TRUE); - } else if (pWinPriv->window) { - /* Move window on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = pWindow->origin.x - wBorderWidth(pWindow); - c.y = pWindow->origin.y - wBorderWidth(pWindow); - c.width = pWindow->drawable.width; - c.height = pWindow->drawable.height; - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_COPY, pWindow); -} - -/** Resize \a pWindow on the back-end server. Determine whether or not - * it is on or offscreen, and realize it if it is newly on screen and - * the lazy window creation optimization is enabled. */ -void dmxResizeWindow(WindowPtr pWindow, int x, int y, - unsigned int w, unsigned int h, WindowPtr pSib) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - dmxWinPrivPtr pSibPriv; - unsigned int m; - XWindowChanges c; - - if (pSib) - pSibPriv = DMX_GET_WINDOW_PRIV(pSib); - - DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); -#if 1 - if (pScreen->ResizeWindow) - pScreen->ResizeWindow(pWindow, x, y, w, h, pSib); -#endif - - /* Determine if the window is completely off the visible portion of - the screen */ - pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); - - /* If the window is now on-screen and it is mapped and it has not - been created yet, create it and map it */ - if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { - dmxCreateAndRealizeWindow(pWindow, TRUE); - } else if (pWinPriv->window) { - /* Handle resizing on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = pWindow->origin.x - wBorderWidth(pWindow); - c.y = pWindow->origin.y - wBorderWidth(pWindow); - c.width = pWindow->drawable.width; - c.height = pWindow->drawable.height; - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_RESIZE, pWindow); -} - -/** Reparent \a pWindow on the back-end server. */ -void dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); - - DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->ReparentWindow) - pScreen->ReparentWindow(pWindow, pPriorParent); -#endif - - if (pWinPriv->window) { - if (!pParentPriv->window) { - dmxCreateAndRealizeWindow(pWindow->parent, FALSE); - } - - /* Handle reparenting on back-end server */ - XReparentWindow(dmxScreen->beDisplay, pWinPriv->window, - pParentPriv->window, - pWindow->origin.x - wBorderWidth(pWindow), - pWindow->origin.x - wBorderWidth(pWindow)); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_REPARENT, pWindow); -} - -/** Change border width for \a pWindow to \a width pixels. */ -void dmxChangeBorderWidth(WindowPtr pWindow, unsigned int width) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - unsigned int m; - XWindowChanges c; - - DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); -#if 1 - if (pScreen->ChangeBorderWidth) - pScreen->ChangeBorderWidth(pWindow, width); -#endif - - /* NOTE: Do we need to check for on/off screen here? */ - - if (pWinPriv->window) { - /* Handle border width change on back-end server */ - m = CWBorderWidth; - c.border_width = width; - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); -} - -static void dmxDoSetShape(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - int nBox; - BoxPtr pBox; - int nRect; - XRectangle *pRect; - XRectangle *pRectFirst; - - /* First, set the bounding shape */ - if (wBoundingShape(pWindow)) { - pBox = REGION_RECTS(wBoundingShape(pWindow)); - nRect = nBox = REGION_NUM_RECTS(wBoundingShape(pWindow)); - pRectFirst = pRect = xalloc(nRect * sizeof(*pRect)); - while (nBox--) { - pRect->x = pBox->x1; - pRect->y = pBox->y1; - pRect->width = pBox->x2 - pBox->x1; - pRect->height = pBox->y2 - pBox->y1; - pBox++; - pRect++; - } - XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, - ShapeBounding, 0, 0, - pRectFirst, nRect, - ShapeSet, YXBanded); - xfree(pRectFirst); - } else { - XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, - ShapeBounding, 0, 0, None, ShapeSet); - } - - /* Next, set the clip shape */ - if (wClipShape(pWindow)) { - pBox = REGION_RECTS(wClipShape(pWindow)); - nRect = nBox = REGION_NUM_RECTS(wClipShape(pWindow)); - pRectFirst = pRect = xalloc(nRect * sizeof(*pRect)); - while (nBox--) { - pRect->x = pBox->x1; - pRect->y = pBox->y1; - pRect->width = pBox->x2 - pBox->x1; - pRect->height = pBox->y2 - pBox->y1; - pBox++; - pRect++; - } - XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, - ShapeClip, 0, 0, - pRectFirst, nRect, - ShapeSet, YXBanded); - xfree(pRectFirst); - } else { - XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, - ShapeClip, 0, 0, None, ShapeSet); - } - - if (XShapeInputSelected(dmxScreen->beDisplay, pWinPriv->window)) { - ErrorF("Input selected for window %x on Screen %d\n", - (unsigned int)pWinPriv->window, pScreen->myNum); - } -} - -/** Set shape of \a pWindow on the back-end server. */ -void dmxSetShape(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - DMX_UNWRAP(SetShape, dmxScreen, pScreen); -#if 1 - if (pScreen->SetShape) - pScreen->SetShape(pWindow); -#endif - - if (pWinPriv->window) { - /* Handle setting the current shape on the back-end server */ - dmxDoSetShape(pWindow); - dmxSync(dmxScreen, False); - } else { - pWinPriv->isShaped = TRUE; - } - - DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); -} +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Kevin E. Martin + * + */ + +/** \file + * This file provides support for window-related functions. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxcmap.h" +#include "dmxvisual.h" +#include "dmxinput.h" +#include "dmxextension.h" +#include "dmxpict.h" + +#include "windowstr.h" + +static void dmxDoRestackWindow(WindowPtr pWindow); +static void dmxDoChangeWindowAttributes(WindowPtr pWindow, + unsigned long *mask, + XSetWindowAttributes *attribs); + +static void dmxDoSetShape(WindowPtr pWindow); + +/** Initialize the private area for the window functions. */ +Bool dmxInitWindow(ScreenPtr pScreen) +{ + if (!dixRequestPrivate(dmxWinPrivateKey, sizeof(dmxWinPrivRec))) + return FALSE; + + return TRUE; +} + + +Window dmxCreateRootWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + Window parent; + Visual *visual; + unsigned long mask; + XSetWindowAttributes attribs; + ColormapPtr pCmap; + dmxColormapPrivPtr pCmapPriv; + + /* Create root window */ + + parent = dmxScreen->scrnWin; /* This is our "Screen" window */ + visual = dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual; + + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + + mask = CWEventMask | CWBackingStore | CWColormap | CWBorderPixel; + attribs.event_mask = ExposureMask; + attribs.backing_store = NotUseful; + attribs.colormap = pCmapPriv->cmap; + attribs.border_pixel = 0; + + /* Incorporate new attributes, if needed */ + if (pWinPriv->attribMask) { + dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); + mask |= pWinPriv->attribMask; + } + + return XCreateWindow(dmxScreen->beDisplay, + parent, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.y - wBorderWidth(pWindow), + pWindow->drawable.width, + pWindow->drawable.height, + pWindow->borderWidth, + pWindow->drawable.depth, + pWindow->drawable.class, + visual, + mask, + &attribs); +} + +/** Change the location and size of the "screen" window. Called from + * #dmxConfigureScreenWindow(). */ +void dmxResizeScreenWindow(ScreenPtr pScreen, + int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + unsigned int m; + XWindowChanges c; + + if (!dmxScreen->beDisplay) + return; + + /* Handle resizing on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = x; + c.y = y; + c.width = w; + c.height = h; + + XConfigureWindow(dmxScreen->beDisplay, dmxScreen->scrnWin, m, &c); + dmxSync(dmxScreen, False); +} + +/** Change the location and size of the "root" window. Called from + * #dmxConfigureRootWindow. */ +void dmxResizeRootWindow(WindowPtr pRoot, + int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pRoot->drawable.pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot); + unsigned int m; + XWindowChanges c; + + /* Handle resizing on back-end server */ + if (dmxScreen->beDisplay) { + m = CWX | CWY | CWWidth | CWHeight; + c.x = x; + c.y = y; + c.width = (w > 0) ? w : 1; + c.height = (h > 0) ? h : 1; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + } + + if (w == 0 || h == 0) { + if (pWinPriv->mapped) { + if (dmxScreen->beDisplay) + XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); + pWinPriv->mapped = FALSE; + } + } else if (!pWinPriv->mapped) { + if (dmxScreen->beDisplay) + XMapWindow(dmxScreen->beDisplay, pWinPriv->window); + pWinPriv->mapped = TRUE; + } + + if (dmxScreen->beDisplay) + dmxSync(dmxScreen, False); +} + +void dmxGetDefaultWindowAttributes(WindowPtr pWindow, + Colormap *cmap, + Visual **visual) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + + if (pWindow->drawable.class != InputOnly && + pWindow->optional && + pWindow->optional->visual != wVisual(pWindow->parent)) { + + /* Find the matching visual */ + *visual = dmxLookupVisualFromID(pScreen, wVisual(pWindow)); + + /* Handle optional colormaps */ + if (pWindow->optional->colormap) { + ColormapPtr pCmap; + dmxColormapPrivPtr pCmapPriv; + + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), + RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + *cmap = pCmapPriv->cmap; + } else { + *cmap = dmxColormapFromDefaultVisual(pScreen, *visual); + } + } else { + *visual = CopyFromParent; + *cmap = (Colormap)0; + } +} + +static Window dmxCreateNonRootWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + Window parent; + unsigned long mask = 0L; + XSetWindowAttributes attribs; + dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); + + /* Create window on back-end server */ + + parent = pParentPriv->window; + + /* The parent won't exist if this call to CreateNonRootWindow came + from ReparentWindow and the grandparent window has not yet been + created */ + if (!parent) { + dmxCreateAndRealizeWindow(pWindow->parent, FALSE); + parent = pParentPriv->window; + } + + /* Incorporate new attributes, if needed */ + if (pWinPriv->attribMask) { + dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); + mask |= pWinPriv->attribMask; + } + + /* Add in default attributes */ + if (pWindow->drawable.class != InputOnly) { + mask |= CWBackingStore; + attribs.backing_store = NotUseful; + + if (!(mask & CWColormap) && pWinPriv->cmap) { + mask |= CWColormap; + attribs.colormap = pWinPriv->cmap; + if (!(mask & CWBorderPixel)) { + mask |= CWBorderPixel; + attribs.border_pixel = 0; + } + } + } + + /* Handle case where subwindows are being mapped, but created out of + order -- if current window has a previous sibling, then it cannot + be created on top of the stack, so we must restack the windows */ + pWinPriv->restacked = (pWindow->prevSib != NullWindow); + + return XCreateWindow(dmxScreen->beDisplay, + parent, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.y - wBorderWidth(pWindow), + pWindow->drawable.width, + pWindow->drawable.height, + pWindow->borderWidth, + pWindow->drawable.depth, + pWindow->drawable.class, + pWinPriv->visual, + mask, + &attribs); +} + +/** This function handles lazy window creation and realization. Window + * creation is handled by #dmxCreateNonRootWindow(). It also handles + * any stacking changes that have occured since the window was + * originally created by calling #dmxDoRestackWindow(). If the window + * is shaped, the shape is set on the back-end server by calling + * #dmxDoSetShape(), and if the window has pictures (from RENDER) + * associated with it, those pictures are created on the back-end + * server by calling #dmxCreatePictureList(). If \a doSync is TRUE, + * then #dmxSync() is called. */ +void dmxCreateAndRealizeWindow(WindowPtr pWindow, Bool doSync) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + if (!dmxScreen->beDisplay) return; + + pWinPriv->window = dmxCreateNonRootWindow(pWindow); + if (pWinPriv->restacked) dmxDoRestackWindow(pWindow); + if (pWinPriv->isShaped) dmxDoSetShape(pWindow); + if (pWinPriv->hasPict) dmxCreatePictureList(pWindow); + if (pWinPriv->mapped) XMapWindow(dmxScreen->beDisplay, + pWinPriv->window); + if (doSync) dmxSync(dmxScreen, False); +} + +/** Create \a pWindow on the back-end server. If the lazy window + * creation optimization is enabled, then the actual creation and + * realization of the window is handled by + * #dmxCreateAndRealizeWindow(). */ +Bool dmxCreateWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + Bool ret = TRUE; + + DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->CreateWindow) + ret = pScreen->CreateWindow(pWindow); +#endif + + /* Set up the defaults */ + pWinPriv->window = (Window)0; + pWinPriv->offscreen = TRUE; + pWinPriv->mapped = FALSE; + pWinPriv->restacked = FALSE; + pWinPriv->attribMask = 0; + pWinPriv->isShaped = FALSE; + pWinPriv->hasPict = FALSE; +#ifdef GLXEXT + pWinPriv->swapGroup = NULL; + pWinPriv->barrier = 0; +#endif + + if (dmxScreen->beDisplay) { + /* Only create the root window at this stage -- non-root windows are + created when they are mapped and are on-screen */ + if (!pWindow->parent) { + dmxScreen->rootWin = pWinPriv->window + = dmxCreateRootWindow(pWindow); + if (dmxScreen->scrnX != dmxScreen->rootX + || dmxScreen->scrnY != dmxScreen->rootY + || dmxScreen->scrnWidth != dmxScreen->rootWidth + || dmxScreen->scrnHeight != dmxScreen->rootHeight) { + dmxResizeRootWindow(pWindow, + dmxScreen->rootX, + dmxScreen->rootY, + dmxScreen->rootWidth, + dmxScreen->rootHeight); + dmxUpdateScreenResources(screenInfo.screens[dmxScreen->index], + dmxScreen->rootX, + dmxScreen->rootY, + dmxScreen->rootWidth, + dmxScreen->rootHeight); + pWindow->origin.x = dmxScreen->rootX; + pWindow->origin.y = dmxScreen->rootY; + } + } else { + dmxGetDefaultWindowAttributes(pWindow, + &pWinPriv->cmap, + &pWinPriv->visual); + + if (dmxLazyWindowCreation) { + /* Save parent's visual for use later */ + if (pWinPriv->visual == CopyFromParent) + pWinPriv->visual = + dmxLookupVisualFromID(pScreen, + wVisual(pWindow->parent)); + } else { + pWinPriv->window = dmxCreateNonRootWindow(pWindow); + } + } + + dmxSync(dmxScreen, False); + } + + DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); + + return ret; +} + +/** Destroy \a pWindow on the back-end server. */ +Bool dmxBEDestroyWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + if (pWinPriv->window) { + XDestroyWindow(dmxScreen->beDisplay, pWinPriv->window); + pWinPriv->window = (Window)0; + return TRUE; + } + + return FALSE; +} + +/** Destroy \a pWindow on the back-end server. If any RENDER pictures + were created, destroy them as well. */ +Bool dmxDestroyWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + Bool needSync = FALSE; +#ifdef GLXEXT + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); +#endif + + DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); + + /* Destroy any picture list associated with this window */ + needSync |= dmxDestroyPictureList(pWindow); + + /* Destroy window on back-end server */ + needSync |= dmxBEDestroyWindow(pWindow); + if (needSync) dmxSync(dmxScreen, FALSE); + +#ifdef GLXEXT + if (pWinPriv->swapGroup && pWinPriv->windowDestroyed) + pWinPriv->windowDestroyed(pWindow); +#endif + + if (pScreen->DestroyWindow) + ret = pScreen->DestroyWindow(pWindow); + + DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); + + return ret; +} + +/** Change the position of \a pWindow to be \a x, \a y. */ +Bool dmxPositionWindow(WindowPtr pWindow, int x, int y) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + unsigned int m; + XWindowChanges c; + + DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->PositionWindow) + ret = pScreen->PositionWindow(pWindow, x, y); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window is now on-screen and it is mapped and it has not + been created yet, create it and map it */ + if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, TRUE); + } else if (pWinPriv->window) { + /* Position window on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = pWindow->origin.x - wBorderWidth(pWindow); + c.y = pWindow->origin.y - wBorderWidth(pWindow); + c.width = pWindow->drawable.width; + c.height = pWindow->drawable.height; + if (pWindow->drawable.class != InputOnly) { + m |= CWBorderWidth; + c.border_width = pWindow->borderWidth; + } + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); + + return ret; +} + +static void dmxDoChangeWindowAttributes(WindowPtr pWindow, + unsigned long *mask, + XSetWindowAttributes *attribs) +{ + dmxPixPrivPtr pPixPriv; + + if (*mask & CWBackPixmap) { + switch (pWindow->backgroundState) { + case None: + attribs->background_pixmap = None; + break; + + case ParentRelative: + attribs->background_pixmap = ParentRelative; + break; + + case BackgroundPixmap: + pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->background.pixmap); + attribs->background_pixmap = pPixPriv->pixmap; + break; + + case BackgroundPixel: + *mask &= ~CWBackPixmap; + break; + } + } + + if (*mask & CWBackPixel) { + if (pWindow->backgroundState == BackgroundPixel) + attribs->background_pixel = pWindow->background.pixel; + else + *mask &= ~CWBackPixel; + } + + if (*mask & CWBorderPixmap) { + if (pWindow->borderIsPixel) + *mask &= ~CWBorderPixmap; + else { + pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->border.pixmap); + attribs->border_pixmap = pPixPriv->pixmap; + } + } + + if (*mask & CWBorderPixel) { + if (pWindow->borderIsPixel) + attribs->border_pixel = pWindow->border.pixel; + else + *mask &= ~CWBorderPixel; + } + + if (*mask & CWBitGravity) + attribs->bit_gravity = pWindow->bitGravity; + + if (*mask & CWWinGravity) + *mask &= ~CWWinGravity; /* Handled by dix */ + + if (*mask & CWBackingStore) + *mask &= ~CWBackingStore; /* Backing store not supported */ + + if (*mask & CWBackingPlanes) + *mask &= ~CWBackingPlanes; /* Backing store not supported */ + + if (*mask & CWBackingPixel) + *mask &= ~CWBackingPixel; /* Backing store not supported */ + + if (*mask & CWOverrideRedirect) + attribs->override_redirect = pWindow->overrideRedirect; + + if (*mask & CWSaveUnder) + *mask &= ~CWSaveUnder; /* Save unders not supported */ + + if (*mask & CWEventMask) + *mask &= ~CWEventMask; /* Events are handled by dix */ + + if (*mask & CWDontPropagate) + *mask &= ~CWDontPropagate; /* Events are handled by dix */ + + if (*mask & CWColormap) { + ColormapPtr pCmap; + dmxColormapPrivPtr pCmapPriv; + + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + attribs->colormap = pCmapPriv->cmap; + } + + if (*mask & CWCursor) + *mask &= ~CWCursor; /* Handled by the cursor code */ +} + +/** Change the window attributes of \a pWindow. */ +Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + XSetWindowAttributes attribs; + + DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); +#if 0 + if (pScreen->ChangeWindowAttributes) + ret = pScreen->ChangeWindowAttributes(pWindow, mask); +#endif + + /* Change window attribs on back-end server */ + dmxDoChangeWindowAttributes(pWindow, &mask, &attribs); + + /* Save mask for lazy window creation optimization */ + pWinPriv->attribMask |= mask; + + if (mask && pWinPriv->window) { + XChangeWindowAttributes(dmxScreen->beDisplay, pWinPriv->window, + mask, &attribs); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, + pScreen); + + return ret; +} + +/** Realize \a pWindow on the back-end server. If the lazy window + * creation optimization is enabled, the window is only realized when + * it at least partially overlaps the screen. */ +Bool dmxRealizeWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->RealizeWindow) + ret = pScreen->RealizeWindow(pWindow); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window hasn't been created and it's not offscreen, then + create it */ + if (!pWinPriv->window && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, FALSE); + } + + if (pWinPriv->window) { + /* Realize window on back-end server */ + XMapWindow(dmxScreen->beDisplay, pWinPriv->window); + dmxSync(dmxScreen, False); + } + + /* Let the other functions know that the window is now mapped */ + pWinPriv->mapped = TRUE; + + DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); + + dmxUpdateWindowInfo(DMX_UPDATE_REALIZE, pWindow); + return ret; +} + +/** Unrealize \a pWindow on the back-end server. */ +Bool dmxUnrealizeWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->UnrealizeWindow) + ret = pScreen->UnrealizeWindow(pWindow); +#endif + + if (pWinPriv->window) { + /* Unrealize window on back-end server */ + XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); + dmxSync(dmxScreen, False); + } + + /* When unrealized (i.e., unmapped), the window is always considered + off of the visible portion of the screen */ + pWinPriv->offscreen = TRUE; + pWinPriv->mapped = FALSE; + +#ifdef GLXEXT + if (pWinPriv->swapGroup && pWinPriv->windowUnmapped) + pWinPriv->windowUnmapped(pWindow); +#endif + + DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); + + dmxUpdateWindowInfo(DMX_UPDATE_UNREALIZE, pWindow); + return ret; +} + +static void dmxDoRestackWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + WindowPtr pNextSib = pWindow->nextSib; + unsigned int m; + XWindowChanges c; + + if (pNextSib == NullWindow) { + /* Window is at the bottom of the stack */ + m = CWStackMode; + c.sibling = (Window)0; + c.stack_mode = Below; + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + } else { + /* Window is not at the bottom of the stack */ + dmxWinPrivPtr pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); + + /* Handle case where siblings have not yet been created due to + lazy window creation optimization by first finding the next + sibling in the sibling list that has been created (if any) + and then putting the current window just above that sibling, + and if no next siblings have been created yet, then put it at + the bottom of the stack (since it might have a previous + sibling that should be above it). */ + while (!pNextSibPriv->window) { + pNextSib = pNextSib->nextSib; + if (pNextSib == NullWindow) { + /* Window is at the bottom of the stack */ + m = CWStackMode; + c.sibling = (Window)0; + c.stack_mode = Below; + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + return; + } + pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); + } + + m = CWStackMode | CWSibling; + c.sibling = pNextSibPriv->window; + c.stack_mode = Above; + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + } +} + +/** Handle window restacking. The actual restacking occurs in + * #dmxDoRestackWindow(). */ +void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->RestackWindow) + pScreen->RestackWindow(pWindow, pOldNextSib); +#endif + + if (pOldNextSib != pWindow->nextSib) { + /* Track restacking for lazy window creation optimization */ + pWinPriv->restacked = TRUE; + + /* Restack window on back-end server */ + if (pWinPriv->window) { + dmxDoRestackWindow(pWindow); + dmxSync(dmxScreen, False); + } + } + + DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_RESTACK, pWindow); +} + +static Bool dmxWindowExposurePredicate(Display *dpy, XEvent *ev, XPointer ptr) +{ + return (ev->type == Expose && ev->xexpose.window == *(Window *)ptr); +} + +/** Handle exposures on \a pWindow. Since window exposures are handled + * in DMX, the events that are generated by the back-end server are + * redundant, so we eat them here. */ +void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn, + RegionPtr other_exposed) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + XEvent ev; + + DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); + + dmxSync(dmxScreen, False); + + if (pWinPriv->window) { + while (XCheckIfEvent(dmxScreen->beDisplay, &ev, + dmxWindowExposurePredicate, + (XPointer)&pWinPriv->window)) { + /* Handle expose events -- this should not be necessary + since the base window in which the root window was + created is guaranteed to be on top (override_redirect), + so we should just swallow these events. If for some + reason the window is not on top, then we'd need to + collect these events and send them to the client later + (e.g., during the block handler as Xnest does). */ + } + } + +#if 1 + if (pScreen->WindowExposures) + pScreen->WindowExposures(pWindow, prgn, other_exposed); +#endif + DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); +} + +/** Move \a pWindow on the back-end server. Determine whether or not it + * is on or offscreen, and realize it if it is newly on screen and the + * lazy window creation optimization is enabled. */ +void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + unsigned int m; + XWindowChanges c; + + DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->CopyWindow) + pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window is now on-screen and it is mapped and it has not + been created yet, create it and map it */ + if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, TRUE); + } else if (pWinPriv->window) { + /* Move window on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = pWindow->origin.x - wBorderWidth(pWindow); + c.y = pWindow->origin.y - wBorderWidth(pWindow); + c.width = pWindow->drawable.width; + c.height = pWindow->drawable.height; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_COPY, pWindow); +} + +/** Resize \a pWindow on the back-end server. Determine whether or not + * it is on or offscreen, and realize it if it is newly on screen and + * the lazy window creation optimization is enabled. */ +void dmxResizeWindow(WindowPtr pWindow, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + dmxWinPrivPtr pSibPriv; + unsigned int m; + XWindowChanges c; + + if (pSib) + pSibPriv = DMX_GET_WINDOW_PRIV(pSib); + + DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); +#if 1 + if (pScreen->ResizeWindow) + pScreen->ResizeWindow(pWindow, x, y, w, h, pSib); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window is now on-screen and it is mapped and it has not + been created yet, create it and map it */ + if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, TRUE); + } else if (pWinPriv->window) { + /* Handle resizing on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = pWindow->origin.x - wBorderWidth(pWindow); + c.y = pWindow->origin.y - wBorderWidth(pWindow); + c.width = pWindow->drawable.width; + c.height = pWindow->drawable.height; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_RESIZE, pWindow); +} + +/** Reparent \a pWindow on the back-end server. */ +void dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); + + DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->ReparentWindow) + pScreen->ReparentWindow(pWindow, pPriorParent); +#endif + + if (pWinPriv->window) { + if (!pParentPriv->window) { + dmxCreateAndRealizeWindow(pWindow->parent, FALSE); + } + + /* Handle reparenting on back-end server */ + XReparentWindow(dmxScreen->beDisplay, pWinPriv->window, + pParentPriv->window, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.x - wBorderWidth(pWindow)); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_REPARENT, pWindow); +} + +/** Change border width for \a pWindow to \a width pixels. */ +void dmxChangeBorderWidth(WindowPtr pWindow, unsigned int width) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + unsigned int m; + XWindowChanges c; + + DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); +#if 1 + if (pScreen->ChangeBorderWidth) + pScreen->ChangeBorderWidth(pWindow, width); +#endif + + /* NOTE: Do we need to check for on/off screen here? */ + + if (pWinPriv->window) { + /* Handle border width change on back-end server */ + m = CWBorderWidth; + c.border_width = width; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); +} + +static void dmxDoSetShape(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + int nBox; + BoxPtr pBox; + int nRect; + XRectangle *pRect; + XRectangle *pRectFirst; + + /* First, set the bounding shape */ + if (wBoundingShape(pWindow)) { + pBox = REGION_RECTS(wBoundingShape(pWindow)); + nRect = nBox = REGION_NUM_RECTS(wBoundingShape(pWindow)); + pRectFirst = pRect = malloc(nRect * sizeof(*pRect)); + while (nBox--) { + pRect->x = pBox->x1; + pRect->y = pBox->y1; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + pBox++; + pRect++; + } + XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, + ShapeBounding, 0, 0, + pRectFirst, nRect, + ShapeSet, YXBanded); + free(pRectFirst); + } else { + XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, + ShapeBounding, 0, 0, None, ShapeSet); + } + + /* Next, set the clip shape */ + if (wClipShape(pWindow)) { + pBox = REGION_RECTS(wClipShape(pWindow)); + nRect = nBox = REGION_NUM_RECTS(wClipShape(pWindow)); + pRectFirst = pRect = malloc(nRect * sizeof(*pRect)); + while (nBox--) { + pRect->x = pBox->x1; + pRect->y = pBox->y1; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + pBox++; + pRect++; + } + XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, + ShapeClip, 0, 0, + pRectFirst, nRect, + ShapeSet, YXBanded); + free(pRectFirst); + } else { + XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, + ShapeClip, 0, 0, None, ShapeSet); + } + + if (XShapeInputSelected(dmxScreen->beDisplay, pWinPriv->window)) { + ErrorF("Input selected for window %x on Screen %d\n", + (unsigned int)pWinPriv->window, pScreen->myNum); + } +} + +/** Set shape of \a pWindow on the back-end server. */ +void dmxSetShape(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(SetShape, dmxScreen, pScreen); +#if 1 + if (pScreen->SetShape) + pScreen->SetShape(pWindow); +#endif + + if (pWinPriv->window) { + /* Handle setting the current shape on the back-end server */ + dmxDoSetShape(pWindow); + dmxSync(dmxScreen, False); + } else { + pWinPriv->isShaped = TRUE; + } + + DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); +} diff --git a/xorg-server/hw/dmx/doc/dmx.sgml b/xorg-server/hw/dmx/doc/dmx.sgml index ef66d1195..4342c2fce 100644 --- a/xorg-server/hw/dmx/doc/dmx.sgml +++ b/xorg-server/hw/dmx/doc/dmx.sgml @@ -1,2778 +1,2777 @@ - -
- - - Distributed Multihead X design - <author>Kevin E. Martin, David H. Dawes, and Rickard E. Faith - <date>29 June 2004 (created 25 July 2001) - <abstract> - This document covers the motivation, background, design, and - implementation of the distributed multihead X (DMX) system. It - is a living document and describes the current design and - implementation details of the DMX system. As the project - progresses, this document will be continually updated to reflect - the changes in the code and/or design. <it>Copyright 2001 by VA - Linux Systems, Inc., Fremont, California. Copyright 2001-2004 - by Red Hat, Inc., Raleigh, North Carolina</it> - </abstract> - - <!-- Table of contents --> - <toc> - -<!-- Begin the document --> -<sect>Introduction - -<sect1>The Distributed Multihead X Server - -<p>Current Open Source multihead solutions are limited to a single -physical machine. A single X server controls multiple display devices, -which can be arranged as independent heads or unified into a single -desktop (with Xinerama). These solutions are limited to the number of -physical devices that can co-exist in a single machine (e.g., due to the -number of AGP/PCI slots available for graphics cards). Thus, large -tiled displays are not currently possible. The work described in this -paper will eliminate the requirement that the display devices reside in -the same physical machine. This will be accomplished by developing a -front-end proxy X server that will control multiple back-end X servers -that make up the large display. - -<p>The overall structure of the distributed multihead X (DMX) project is -as follows: A single front-end X server will act as a proxy to a set of -back-end X servers, which handle all of the visible rendering. X -clients will connect to the front-end server just as they normally would -to a regular X server. The front-end server will present an abstracted -view to the client of a single large display. This will ensure that all -standard X clients will continue to operate without modification -(limited, as always, by the visuals and extensions provided by the X -server). Clients that are DMX-aware will be able to use an extension to -obtain information about the back-end servers (e.g., for placement of -pop-up windows, window alignments by the window manager, etc.). - -<p>The architecture of the DMX server is divided into two main sections: -input (e.g., mouse and keyboard events) and output (e.g., rendering and -windowing requests). Each of these are describe briefly below, and the -rest of this design document will describe them in greater detail. - -<p>The DMX server can receive input from three general types of input -devices: "local" devices that are physically attached to the machine on -which DMX is running, "backend" devices that are physically attached to -one or more of the back-end X servers (and that generate events via the -X protocol stream from the backend), and "console" devices that can be -abstracted from any non-back-end X server. Backend and console devices -are treated differently because the pointer device on the back-end X -server also controls the location of the hardware X cursor. Full -support for XInput extension devices is provided. - -<p>Rendering requests will be accepted by the front-end server; however, -rendering to visible windows will be broken down as needed and sent to -the appropriate back-end server(s) via X11 library calls for actual -rendering. The basic framework will follow a Xnest-style approach. GC -state will be managed in the front-end server and sent to the -appropriate back-end server(s) as required. Pixmap rendering will (at -least initially) be handled by the front-end X server. Windowing -requests (e.g., ordering, mapping, moving, etc.) will handled in the -front-end server. If the request requires a visible change, the -windowing operation will be translated into requests for the appropriate -back-end server(s). Window state will be mirrored in the back-end -server(s) as needed. - -<sect1>Layout of Paper - -<p>The next section describes the general development plan that was -actually used for implementation. The final section discusses -outstanding issues at the conclusion of development. The first appendix -provides low-level technical detail that may be of interest to those -intimately familiar with the X server architecture. The final appendix -describes the four phases of development that were performed during the -first two years of development. - -<p>The final year of work was divided into 9 tasks that are not -described in specific sections of this document. The major tasks during -that time were the enhancement of the reconfiguration ability added in -Phase IV, addition of support for a dynamic number of back-end displays -(instead of a hard-coded limit), and the support for back-end display -and input removal and addition. This work is mentioned in this paper, -but is not covered in detail. - -<!-- ============================================================ --> -<sect>Development plan - -<p>This section describes the development plan from approximately June -2001 through July 2003. - -<sect1>Bootstrap code - -<p>To allow for rapid development of the DMX server by multiple -developers during the first development stage, the problem will be -broken down into three tasks: the overall DMX framework, back-end -rendering services and input device handling services. However, before -the work begins on these tasks, a simple framework that each developer -could use was implemented to bootstrap the development effort. This -framework renders to a single back-end server and provides dummy input -devices (i.e., the keyboard and mouse). The simple back-end rendering -service was implemented using the shadow framebuffer support currently -available in the XFree86 environment. - -<p>Using this bootstrapping framework, each developer has been able to -work on each of the tasks listed above independently as follows: the -framework will be extended to handle arbitrary back-end server -configurations; the back-end rendering services will be transitioned to -the more efficient Xnest-style implementation; and, an input device -framework to handle various input devices via the input extension will -be developed. - -<p>Status: The boot strap code is complete. <!-- August 2001 --> - - -<sect1>Input device handling - -<p>An X server (including the front-end X server) requires two core -input devices -- a keyboard and a pointer (mouse). These core devices -are handled and required by the core X11 protocol. Additional types of -input devices may be attached and utilized via the XInput extension. -These are usually referred to as ``XInput extension devices'', - -<p>There are some options as to how the front-end X server gets its core -input devices: - -<enum> - <item>Local Input. The physical input devices (e.g., keyboard and - mouse) can be attached directly to the front-end X server. In this - case, the keyboard and mouse on the machine running the front-end X - server will be used. The front-end will have drivers to read the - raw input from those devices and convert it into the required X - input events (e.g., key press/release, pointer button press/release, - pointer motion). The front-end keyboard driver will keep track of - keyboard properties such as key and modifier mappings, autorepeat - state, keyboard sound and led state. Similarly the front-end - pointer driver will keep track if pointer properties such as the - button mapping and movement acceleration parameters. With this - option, input is handled fully in the front-end X server, and the - back-end X servers are used in a display-only mode. This option was - implemented and works for a limited number of Linux-specific - devices. Adding additional local input devices for other - architectures is expected to be relatively simple. - - <p>The following options are available for implementing local input - devices: - - <enum> - <item>The XFree86 X server has modular input drivers that could - be adapted for this purpose. The mouse driver supports a wide - range of mouse types and interfaces, as well as a range of - Operating System platforms. The keyboard driver in XFree86 is - not currently as modular as the mouse driver, but could be made - so. The XFree86 X server also has a range of other input - drivers for extended input devices such as tablets and touch - screens. Unfortunately, the XFree86 drivers are generally - complex, often simultaneously providing support for multiple - devices across multiple architectures; and rely so heavily on - XFree86-specific helper-functions, that this option was not - pursued. - - - <item>The <tt/kdrive/ X server in XFree86 has built-in drivers that - support PS/2 mice and keyboard under Linux. The mouse driver - can indirectly handle other mouse types if the Linux utility - <tt/gpm/ is used as to translate the native mouse protocol into - PS/2 mouse format. These drivers could be adapted and built in - to the front-end X server if this range of hardware and OS - support is sufficient. While much simpler than the XFree86 - drivers, the <tt/kdrive/ drivers were not used for the DMX - implementation. - - <item>Reimplementation of keyboard and mouse drivers from - scratch for the DMX framework. Because keyboard and mouse - drivers are relatively trivial to implement, this pathway was - selected. Other drivers in the X source tree were referenced, - and significant contributions from other drivers are noted in - the DMX source code. - </enum> - - <item>Backend Input. The front-end can make use of the core input - devices attached to one or more of the back-end X servers. Core - input events from multiple back-ends are merged into a single input - event stream. This can work sanely when only a single set of input - devices is used at any given time. The keyboard and pointer state - will be handled in the front-end, with changes propagated to the - back-end servers as needed. This option was implemented and works - well. Because the core pointer on a back-end controls the hardware - mouse on that back-end, core pointers cannot be treated as XInput - extension devices. However, all back-end XInput extensions devices - can be mapped to either DMX core or DMX XInput extension devices. - - <item>Console Input. The front-end server could create a console - window that is displayed on an X server independent of the back-end - X servers. This console window could display things like the - physical screen layout, and the front-end could get its core input - events from events delivered to the console window. This option was - implemented and works well. To help the human navigate, window - outlines are also displayed in the console window. Further, console - windows can be used as either core or XInput extension devices. - - <item>Other options were initially explored, but they were all - partial subsets of the options listed above and, hence, are - irrelevant. - -</enum> - -<p>Although extended input devices are not specifically mentioned in the -Distributed X requirements, the options above were all implemented so -that XInput extension devices were supported. - -<p>The bootstrap code (Xdmx) had dummy input devices, and these are -still supported in the final version. These do the necessary -initialization to satisfy the X server's requirements for core pointer -and keyboard devices, but no input events are ever generated. - -<p>Status: The input code is complete. Because of the complexity of the -XFree86 input device drivers (and their heavy reliance on XFree86 -infrastructure), separate low-level device drivers were implemented for -Xdmx. The following kinds of drivers are supported (in general, the -devices can be treated arbitrarily as "core" input devices or as XInput -"extension" devices; and multiple instances of different kinds of -devices can be simultaneously available): - <enum> - <item> A "dummy" device drive that never generates events. - - <item> "Local" input is from the low-level hardware on which the - Xdmx binary is running. This is the only area where using the - XFree86 driver infrastructure would have been helpful, and then - only partially, since good support for generic USB devices does - not yet exist in XFree86 (in any case, XFree86 and kdrive driver - code was used where possible). Currently, the following local - devices are supported under Linux (porting to other operating - systems should be fairly straightforward): - <itemize> - <item>Linux keyboard - <item>Linux serial mouse (MS) - <item>Linux PS/2 mouse - <item>USB keyboard - <item>USB mouse - <item>USB generic device (e.g., joystick, gamepad, etc.) - </itemize> - - <item> "Backend" input is taken from one or more of the back-end - displays. In this case, events are taken from the back-end X - server and are converted to Xdmx events. Care must be taken so - that the sprite moves properly on the display from which input - is being taken. - - <item> "Console" input is taken from an X window that Xdmx - creates on the operator's display (i.e., on the machine running - the Xdmx binary). When the operator's mouse is inside the - console window, then those events are converted to Xdmx events. - Several special features are available: the console can display - outlines of windows that are on the Xdmx display (to facilitate - navigation), the cursor can be confined to the console, and a - "fine" mode can be activated to allow very precise cursor - positioning. - </enum> - - -<!-- May 2002; July 2003 --> - -<sect1>Output device handling - -<p>The output of the DMX system displays rendering and windowing -requests across multiple screens. The screens are typically arranged in -a grid such that together they represent a single large display. - -<p>The output section of the DMX code consists of two parts. The first -is in the front-end proxy X server (Xdmx), which accepts client -connections, manages the windows, and potentially renders primitives but -does not actually display any of the drawing primitives. The second -part is the back-end X server(s), which accept commands from the -front-end server and display the results on their screens. - -<sect2>Initialization - -<p>The DMX front-end must first initialize its screens by connecting to -each of the back-end X servers and collecting information about each of -these screens. However, the information collected from the back-end X -servers might be inconsistent. Handling these cases can be difficult -and/or inefficient. For example, a two screen system has one back-end X -server running at 16bpp while the second is running at 32bpp. -Converting rendering requests (e.g., XPutImage() or XGetImage() -requests) to the appropriate bit depth can be very time consuming. -Analyzing these cases to determine how or even if it is possible to -handle them is required. The current Xinerama code handles many of -these cases (e.g., in PanoramiXConsolidate()) and will be used as a -starting point. In general, the best solution is to use homogeneous X -servers and display devices. Using back-end servers with the same depth -is a requirement of the final DMX implementation. - -<p>Once this screen consolidation is finished, the relative position of -each back-end X server's screen in the unified screen is initialized. A -full-screen window is opened on each of the back-end X servers, and the -cursor on each screen is turned off. The final DMX implementation can -also make use of a partial-screen window, or multiple windows per -back-end screen. - -<sect2>Handling rendering requests - -<p>After initialization, X applications connect to the front-end server. -There are two possible implementations of how rendering and windowing -requests are handled in the DMX system: - -<enum> - <item>A shadow framebuffer is used in the front-end server as the - render target. In this option, all protocol requests are completely - handled in the front-end server. All state and resources are - maintained in the front-end including a shadow copy of the entire - framebuffer. The framebuffers attached to the back-end servers are - updated by XPutImage() calls with data taken directly from the - shadow framebuffer. - - <p>This solution suffers from two main problems. First, it does not - take advantage of any accelerated hardware available in the system. - Second, the size of the XPutImage() calls can be quite large and - thus will be limited by the bandwidth available. - - <p>The initial DMX implementation used a shadow framebuffer by - default. - - <item>Rendering requests are sent to each back-end server for - handling (as is done in the Xnest server described above). In this - option, certain protocol requests are handled in the front-end - server and certain requests are repackaged and then sent to the - back-end servers. The framebuffer is distributed across the - multiple back-end servers. Rendering to the framebuffer is handled - on each back-end and can take advantage of any acceleration - available on the back-end servers' graphics display device. State - is maintained both in the front and back-end servers. - - <p>This solution suffers from two main drawbacks. First, protocol - requests are sent to all back-end servers -- even those that will - completely clip the rendering primitive -- which wastes bandwidth - and processing time. Second, state is maintained both in the front- - and back-end servers. These drawbacks are not as severe as in - option 1 (above) and can either be overcome through optimizations or - are acceptable. Therefore, this option will be used in the final - implementation. - - <p>The final DMX implementation defaults to this mechanism, but also - supports the shadow framebuffer mechanism. Several optimizations - were implemented to eliminate the drawbacks of the default - mechanism. These optimizations are described the section below and - in Phase II of the Development Results (see appendix). - -</enum> - -<p>Status: Both the shadow framebuffer and Xnest-style code is complete. -<!-- May 2002 --> - - -<sect1>Optimizing DMX - -<p>Initially, the Xnest-style solution's performance will be measured -and analyzed to determine where the performance bottlenecks exist. -There are four main areas that will be addressed. - -<p>First, to obtain reasonable interactivity with the first development -phase, XSync() was called after each protocol request. The XSync() -function flushes any pending protocol requests. It then waits for the -back-end to process the request and send a reply that the request has -completed. This happens with each back-end server and performance -greatly suffers. As a result of the way XSync() is called in the first -development phase, the batching that the X11 library performs is -effectively defeated. The XSync() call usage will be analyzed and -optimized by batching calls and performing them at regular intervals, -except where interactivity will suffer (e.g., on cursor movements). - -<p>Second, the initial Xnest-style solution described above sends the -repackaged protocol requests to all back-end servers regardless of -whether or not they would be completely clipped out. The requests that -are trivially rejected on the back-end server wastes the limited -bandwidth available. By tracking clipping changes in the DMX X server's -windowing code (e.g., by opening, closing, moving or resizing windows), -we can determine whether or not back-end windows are visible so that -trivial tests in the front-end server's GC ops drawing functions can -eliminate these unnecessary protocol requests. - -<p>Third, each protocol request will be analyzed to determine if it is -possible to break the request into smaller pieces at display boundaries. -The initial ones to be analyzed are put and get image requests since -they will require the greatest bandwidth to transmit data between the -front and back-end servers. Other protocol requests will be analyzed -and those that will benefit from breaking them into smaller requests -will be implemented. - -<p>Fourth, an extension is being considered that will allow font glyphs to -be transferred from the front-end DMX X server to each back-end server. -This extension will permit the front-end to handle all font requests and -eliminate the requirement that all back-end X servers share the exact -same fonts as the front-end server. We are investigating the -feasibility of this extension during this development phase. - -<p>Other potential optimizations will be determined from the performance -analysis. - -<p>Please note that in our initial design, we proposed optimizing BLT -operations (e.g., XCopyArea() and window moves) by developing an -extension that would allow individual back-end servers to directly copy -pixel data to other back-end servers. This potential optimization was -in response to the simple image movement implementation that required -potentially many calls to GetImage() and PutImage(). However, the -current Xinerama implementation handles these BLT operations -differently. Instead of copying data to and from screens, they generate -expose events -- just as happens in the case when a window is moved from -off a screen to on screen. This approach saves the limited bandwidth -available between front and back-end servers and is being standardized -with Xinerama. It also eliminates the potential setup problems and -security issues resulting from having each back-end server open -connections to all other back-end servers. Therefore, we suggest -accepting Xinerama's expose event solution. - -<p>Also note that the approach proposed in the second and third -optimizations might cause backing store algorithms in the back-end to be -defeated, so a DMX X server configuration flag will be added to disable -these optimizations. - -<p>Status: The optimizations proposed above are complete. It was -determined that the using the xfs font server was sufficient and -creating a new mechanism to pass glyphs was redundant; therefore, the -fourth optimization proposed above was not included in DMX. -<!-- September 2002 --> - - -<sect1>DMX X extension support - -<p>The DMX X server keeps track of all the windowing information on the -back-end X servers, but does not currently export this information to -any client applications. An extension will be developed to pass the -screen information and back-end window IDs to DMX-aware clients. These -clients can then use this information to directly connect to and render -to the back-end windows. Bypassing the DMX X server allows DMX-aware -clients to break up complex rendering requests on their own and send -them directly to the windows on the back-end server's screens. An -example of a client that can make effective use of this extension is -Chromium. - -<p>Status: The extension, as implemented, is fully documented in -"Client-to-Server DMX Extension to the X Protocol". Future changes -might be required based on feedback and other proposed enhancements to -DMX. Currently, the following facilities are supported: -<enum> - <item> - Screen information (clipping rectangle for each screen relative - to the virtual screen) - <item> - Window information (window IDs and clipping information for each - back-end window that corresponds to each DMX window) - <item> - Input device information (mappings from DMX device IDs to - back-end device IDs) - <item> - Force window creation (so that a client can override the - server-side lazy window creation optimization) - <item> - Reconfiguration (so that a client can request that a screen - position be changed) - <item> - Addition and removal of back-end servers and back-end and - console inputs. -</enum> -<!-- September 2002; July 2003 --> - - -<sect1>Common X extension support - -<p>The XInput, XKeyboard and Shape extensions are commonly used -extensions to the base X11 protocol. XInput allows multiple and -non-standard input devices to be accessed simultaneously. These input -devices can be connected to either the front-end or back-end servers. -XKeyboard allows much better keyboard mappings control. Shape adds -support for arbitrarily shaped windows and is used by various window -managers. Nearly all potential back-end X servers make these extensions -available, and support for each one will be added to the DMX system. - -<p>In addition to the extensions listed above, support for the X -Rendering extension (Render) is being developed. Render adds digital -image composition to the rendering model used by the X Window System. -While this extension is still under development by Keith Packard of HP, -support for the current version will be added to the DMX system. - -<p>Support for the XTest extension was added during the first -development phase. - -<!-- WARNING: this list is duplicated in the Phase IV discussion --> -<p>Status: The following extensions are supported and are discussed in -more detail in Phase IV of the Development Results (see appendix): - BIG-REQUESTS, - DEC-XTRAP, - DMX, - DPMS, - Extended-Visual-Information, - GLX, - LBX, - RECORD, - RENDER, - SECURITY, - SHAPE, - SYNC, - X-Resource, - XC-APPGROUP, - XC-MISC, - XFree86-Bigfont, - XINERAMA, - XInputExtension, - XKEYBOARD, and - XTEST. -<!-- November 2002; updated February 2003, July 2003 --> - -<sect1>OpenGL support - -<p>OpenGL support using the Mesa code base exists in XFree86 release 4 -and later. Currently, the direct rendering infrastructure (DRI) -provides accelerated OpenGL support for local clients and unaccelerated -OpenGL support (i.e., software rendering) is provided for non-local -clients. - -<p>The single head OpenGL support in XFree86 4.x will be extended to use -the DMX system. When the front and back-end servers are on the same -physical hardware, it is possible to use the DRI to directly render to -the back-end servers. First, the existing DRI will be extended to -support multiple display heads, and then to support the DMX system. -OpenGL rendering requests will be direct rendering to each back-end X -server. The DRI will request the screen layout (either from the -existing Xinerama extension or a DMX-specific extension). Support for -synchronized swap buffers will also be added (on hardware that supports -it). Note that a single front-end server with a single back-end server -on the same physical machine can emulate accelerated indirect rendering. - -<p>When the front and back-end servers are on different physical -hardware or are using non-XFree86 4.x X servers, a mechanism to render -primitives across the back-end servers will be provided. There are -several options as to how this can be implemented. - -<enum> - <item>The existing OpenGL support in each back-end server can be - used by repackaging rendering primitives and sending them to each - back-end server. This option is similar to the unoptimized - Xnest-style approach mentioned above. Optimization of this solution - is beyond the scope of this project and is better suited to other - distributed rendering systems. - - <item>Rendering to a pixmap in the front-end server using the - current XFree86 4.x code, and then displaying to the back-ends via - calls to XPutImage() is another option. This option is similar to - the shadow frame buffer approach mentioned above. It is slower and - bandwidth intensive, but has the advantage that the back-end servers - are not required to have OpenGL support. -</enum> - -<p>These, and other, options will be investigated in this phase of the -work. - -<p>Work by others have made Chromium DMX-aware. Chromium will use the -DMX X protocol extension to obtain information about the back-end -servers and will render directly to those servers, bypassing DMX. - -<p>Status: OpenGL support by the glxProxy extension was implemented by -SGI and has been integrated into the DMX code base. -<!-- May 2003--> - - -<!-- ============================================================ --> -<sect>Current issues - -<p>In this sections the current issues are outlined that require further -investigation. - -<sect1>Fonts - -<p>The font path and glyphs need to be the same for the front-end and -each of the back-end servers. Font glyphs could be sent to the back-end -servers as necessary but this would consume a significant amount of -available bandwidth during font rendering for clients that use many -different fonts (e.g., Netscape). Initially, the font server (xfs) will -be used to provide the fonts to both the front-end and back-end servers. -Other possibilities will be investigated during development. - -<sect1>Zero width rendering primitives - -<p>To allow pixmap and on-screen rendering to be pixel perfect, all -back-end servers must render zero width primitives exactly the same as -the front-end renders the primitives to pixmaps. For those back-end -servers that do not exactly match, zero width primitives will be -automatically converted to one width primitives. This can be handled in -the front-end server via the GC state. - -<sect1>Output scaling - -<p>With very large tiled displays, it might be difficult to read the -information on the standard X desktop. In particular, the cursor can be -easily lost and fonts could be difficult to read. Automatic primitive -scaling might prove to be very useful. We will investigate the -possibility of scaling the cursor and providing a set of alternate -pre-scaled fonts to replace the standard fonts that many applications -use (e.g., fixed). Other options for automatic scaling will also be -investigated. - -<sect1>Per-screen colormaps - -<p>Each screen's default colormap in the set of back-end X servers -should be able to be adjusted via a configuration utility. This support -is would allow the back-end screens to be calibrated via custom gamma -tables. On 24-bit systems that support a DirectColor visual, this type -of correction can be accommodated. One possible implementation would be -to advertise to X client of the DMX server a TrueColor visual while -using DirectColor visuals on the back-end servers to implement this type -of color correction. Other options will be investigated. - -<!-- ============================================================ --> -<appendix> - -<sect>Background - -<p>This section describes the existing Open Source architectures that -can be used to handle multiple screens and upon which this development -project is based. This section was written before the implementation -was finished, and may not reflect actual details of the implementation. -It is left for historical interest only. - -<sect1>Core input device handling - -<p>The following is a description of how core input devices are handled -by an X server. - -<sect2>InitInput() - -<p>InitInput() is a DDX function that is called at the start of each -server generation from the X server's main() function. Its purpose is -to determine what input devices are connected to the X server, register -them with the DIX and MI layers, and initialize the input event queue. -InitInput() does not have a return value, but the X server will abort if -either a core keyboard device or a core pointer device are not -registered. Extended input (XInput) devices can also be registered in -InitInput(). - -<p>InitInput() usually has implementation specific code to determine -which input devices are available. For each input device it will be -using, it calls AddInputDevice(): - -<descrip> -<tag/AddInputDevice()/ This DIX function allocates the device structure, -registers a callback function (which handles device init, close, on and -off), and returns the input handle, which can be treated as opaque. It -is called once for each input device. -</descrip> - -<p>Once input handles for core keyboard and core pointer devices have -been obtained from AddInputDevice(), they are registered as core devices -by calling RegisterPointerDevice() and RegisterKeyboardDevice(). Each -of these should be called once. If both core devices are not -registered, then the X server will exit with a fatal error when it -attempts to start the input devices in InitAndStartDevices(), which is -called directly after InitInput() (see below). - -<descrip> -<tag/Register{Pointer,Keyboard}Device()/ These DIX functions take a -handle returned from AddInputDevice() and initialize the core input -device fields in inputInfo, and initialize the input processing and grab -functions for each core input device. -</descrip> - -<p>The core pointer device is then registered with the miPointer code -(which does the high level cursor handling). While this registration -is not necessary for correct miPointer operation in the current XFree86 -code, it is still done mostly for compatibility reasons. - -<descrip> -<tag/miRegisterPointerDevice()/ This MI function registers the core -pointer's input handle with with the miPointer code. -</descrip> - -<p>The final part of InitInput() is the initialization of the input -event queue handling. In most cases, the event queue handling provided -in the MI layer is used. The primary XFree86 X server uses its own -event queue handling to support some special cases related to the XInput -extension and the XFree86-specific DGA extension. For our purposes, the -MI event queue handling should be suitable. It is initialized by -calling mieqInit(): - -<descrip> -<tag/mieqInit()/ This MI function initializes the MI event queue for the -core devices, and is passed the public component of the input handles -for the two core devices. -</descrip> - -<p>If a wakeup handler is required to deliver synchronous input -events, it can be registered here by calling the DIX function -RegisterBlockAndWakeupHandlers(). (See the devReadInput() description -below.) - -<sect2>InitAndStartDevices() - -<p>InitAndStartDevices() is a DIX function that is called immediately -after InitInput() from the X server's main() function. Its purpose is -to initialize each input device that was registered with -AddInputDevice(), enable each input device that was successfully -initialized, and create the list of enabled input devices. Once each -registered device is processed in this way, the list of enabled input -devices is checked to make sure that both a core keyboard device and -core pointer device were registered and successfully enabled. If not, -InitAndStartDevices() returns failure, and results in the the X server -exiting with a fatal error. - -<p>Each registered device is initialized by calling its callback -(dev->deviceProc) with the DEVICE_INIT argument: - -<descrip> -<tag/(*dev->deviceProc)(dev, DEVICE_INIT)/ This function initializes the -device structs with core information relevant to the device. - -<p>For pointer devices, this means specifying the number of buttons, -default button mapping, the function used to get motion events (usually -miPointerGetMotionEvents()), the function used to change/control the -core pointer motion parameters (acceleration and threshold), and the -motion buffer size. - -<p>For keyboard devices, this means specifying the keycode range, -default keycode to keysym mapping, default modifier mapping, and the -functions used to sound the keyboard bell and modify/control the -keyboard parameters (LEDs, bell pitch and duration, key click, which -keys are auto-repeating, etc). -</descrip> - -<p>Each initialized device is enabled by calling EnableDevice(): - -<descrip> -<tag/EnableDevice()/ EnableDevice() calls the device callback with -DEVICE_ON: - <descrip> - <tag/(*dev->deviceProc)(dev, DEVICE_ON)/ This typically opens and - initializes the relevant physical device, and when appropriate, - registers the device's file descriptor (or equivalent) as a valid - input source. - </descrip> - - <p>EnableDevice() then adds the device handle to the X server's - global list of enabled devices. -</descrip> - -<p>InitAndStartDevices() then verifies that a valid core keyboard and -pointer has been initialized and enabled. It returns failure if either -are missing. - -<sect2>devReadInput() - -<p>Each device will have some function that gets called to read its -physical input. These may be called in a number of different ways. In -the case of synchronous I/O, they will be called from a DDX -wakeup-handler that gets called after the server detects that new input is -available. In the case of asynchronous I/O, they will be called from a -(SIGIO) signal handler triggered when new input is available. This -function should do at least two things: make sure that input events get -enqueued, and make sure that the cursor gets moved for motion events -(except if these are handled later by the driver's own event queue -processing function, which cannot be done when using the MI event queue -handling). - -<p>Events are queued by calling mieqEnqueue(): - -<descrip> -<tag/mieqEnqueue()/ This MI function is used to add input events to the -event queue. It is simply passed the event to be queued. -</descrip> - -<p>The cursor position should be updated when motion events are -enqueued, by calling either miPointerAbsoluteCursor() or -miPointerDeltaCursor(): - -<descrip> -<tag/miPointerAbsoluteCursor()/ This MI function is used to move the -cursor to the absolute coordinates provided. -<tag/miPointerDeltaCursor()/ This MI function is used to move the cursor -relative to its current position. -</descrip> - -<sect2>ProcessInputEvents() - -<p>ProcessInputEvents() is a DDX function that is called from the X -server's main dispatch loop when new events are available in the input -event queue. It typically processes the enqueued events, and updates -the cursor/pointer position. It may also do other DDX-specific event -processing. - -<p>Enqueued events are processed by mieqProcessInputEvents() and passed -to the DIX layer for transmission to clients: - -<descrip> -<tag/mieqProcessInputEvents()/ This function processes each event in the -event queue, and passes it to the device's input processing function. -The DIX layer provides default functions to do this processing, and they -handle the task of getting the events passed back to the relevant -clients. -<tag/miPointerUpdate()/ This function resynchronized the cursor position -with the new pointer position. It also takes care of moving the cursor -between screens when needed in multi-head configurations. -</descrip> - - -<sect2>DisableDevice() - -<p>DisableDevice is a DIX function that removes an input device from the -list of enabled devices. The result of this is that the device no -longer generates input events. The device's data structures are kept in -place, and disabling a device like this can be reversed by calling -EnableDevice(). DisableDevice() may be called from the DDX when it is -desirable to do so (e.g., the XFree86 server does this when VT -switching). Except for special cases, this is not normally called for -core input devices. - -<p>DisableDevice() calls the device's callback function with -<tt/DEVICE_OFF/: - -<descrip> -<tag/(*dev->deviceProc)(dev, DEVICE_OFF)/ This typically closes the -relevant physical device, and when appropriate, unregisters the device's -file descriptor (or equivalent) as a valid input source. -</descrip> - -<p>DisableDevice() then removes the device handle from the X server's -global list of enabled devices. - - -<sect2>CloseDevice() - -<p>CloseDevice is a DIX function that removes an input device from the -list of available devices. It disables input from the device and frees -all data structures associated with the device. This function is -usually called from CloseDownDevices(), which is called from main() at -the end of each server generation to close all input devices. - -<p>CloseDevice() calls the device's callback function with -<tt/DEVICE_CLOSE/: - -<descrip> -<tag/(*dev->deviceProc)(dev, DEVICE_CLOSE)/ This typically closes the -relevant physical device, and when appropriate, unregisters the device's -file descriptor (or equivalent) as a valid input source. If any device -specific data structures were allocated when the device was initialized, -they are freed here. -</descrip> - -<p>CloseDevice() then frees the data structures that were allocated -for the device when it was registered/initialized. - - -<sect2>LegalModifier() -<!-- dmx/dmxinput.c - currently returns TRUE --> -<p>LegalModifier() is a required DDX function that can be used to -restrict which keys may be modifier keys. This seems to be present for -historical reasons, so this function should simply return TRUE -unconditionally. - - -<sect1>Output handling - -<p>The following sections describe the main functions required to -initialize, use and close the output device(s) for each screen in the X -server. - -<sect2>InitOutput() - -<p>This DDX function is called near the start of each server generation -from the X server's main() function. InitOutput()'s main purpose is to -initialize each screen and fill in the global screenInfo structure for -each screen. It is passed three arguments: a pointer to the screenInfo -struct, which it is to initialize, and argc and argv from main(), which -can be used to determine additional configuration information. - -<p>The primary tasks for this function are outlined below: - -<enum> - <item><bf/Parse configuration info:/ The first task of InitOutput() - is to parses any configuration information from the configuration - file. In addition to the XF86Config file, other configuration - information can be taken from the command line. The command line - options can be gathered either in InitOutput() or earlier in the - ddxProcessArgument() function, which is called by - ProcessCommandLine(). The configuration information determines the - characteristics of the screen(s). For example, in the XFree86 X - server, the XF86Config file specifies the monitor information, the - screen resolution, the graphics devices and slots in which they are - located, and, for Xinerama, the screens' layout. - - <item><bf/Initialize screen info:/ The next task is to initialize - the screen-dependent internal data structures. For example, part of - what the XFree86 X server does is to allocate its screen and pixmap - private indices, probe for graphics devices, compare the probed - devices to the ones listed in the XF86Config file, and add the ones that - match to the internal xf86Screens[] structure. - - <item><bf/Set pixmap formats:/ The next task is to initialize the - screenInfo's image byte order, bitmap bit order and bitmap scanline - unit/pad. The screenInfo's pixmap format's depth, bits per pixel - and scanline padding is also initialized at this stage. - - <item><bf/Unify screen info:/ An optional task that might be done at - this stage is to compare all of the information from the various - screens and determines if they are compatible (i.e., if the set of - screens can be unified into a single desktop). This task has - potential to be useful to the DMX front-end server, if Xinerama's - PanoramiXConsolidate() function is not sufficient. -</enum> - -<p>Once these tasks are complete, the valid screens are known and each -of these screens can be initialized by calling AddScreen(). - -<sect2>AddScreen() - -<p>This DIX function is called from InitOutput(), in the DDX layer, to -add each new screen to the screenInfo structure. The DDX screen -initialization function and command line arguments (i.e., argc and argv) -are passed to it as arguments. - -<p>This function first allocates a new Screen structure and any privates -that are required. It then initializes some of the fields in the Screen -struct and sets up the pixmap padding information. Finally, it calls -the DDX screen initialization function ScreenInit(), which is described -below. It returns the number of the screen that were just added, or -1 -if there is insufficient memory to add the screen or if the DDX screen -initialization fails. - -<sect2>ScreenInit() - -<p>This DDX function initializes the rest of the Screen structure with -either generic or screen-specific functions (as necessary). It also -fills in various screen attributes (e.g., width and height in -millimeters, black and white pixel values). - -<p>The screen init function usually calls several functions to perform -certain screen initialization functions. They are described below: - -<descrip> -<tag/{mi,*fb}ScreenInit()/ The DDX layer's ScreenInit() function usually -calls another layer's ScreenInit() function (e.g., miScreenInit() or -fbScreenInit()) to initialize the fallbacks that the DDX driver does not -specifically handle. - -<p>After calling another layer's ScreenInit() function, any -screen-specific functions either wrap or replace the other layer's -function pointers. If a function is to be wrapped, each of the old -function pointers from the other layer are stored in a screen private -area. Common functions to wrap are CloseScreen() and SaveScreen(). - -<tag/miInitializeBackingStore()/ This MI function initializes the -screen's backing storage functions, which are used to save areas of -windows that are currently covered by other windows. - -<tag/miDCInitialize()/ This MI function initializes the MI cursor -display structures and function pointers. If a hardware cursor is used, -the DDX layer's ScreenInit() function will wrap additional screen and -the MI cursor display function pointers. -</descrip> - -<p>Another common task for ScreenInit() function is to initialize the -output device state. For example, in the XFree86 X server, the -ScreenInit() function saves the original state of the video card and -then initializes the video mode of the graphics device. - -<sect2>CloseScreen() - -<p>This function restores any wrapped screen functions (and in -particular the wrapped CloseScreen() function) and restores the state of -the output device to its original state. It should also free any -private data it created during the screen initialization. - -<sect2>GC operations - -<p>When the X server is requested to render drawing primitives, it does -so by calling drawing functions through the graphics context's operation -function pointer table (i.e., the GCOps functions). These functions -render the basic graphics operations such as drawing rectangles, lines, -text or copying pixmaps. Default routines are provided either by the MI -layer, which draws indirectly through a simple span interface, or by the -framebuffer layers (e.g., CFB, MFB, FB), which draw directly to a -linearly mapped frame buffer. - -<p>To take advantage of special hardware on the graphics device, -specific GCOps functions can be replaced by device specific code. -However, many times the graphics devices can handle only a subset of the -possible states of the GC, so during graphics context validation, -appropriate routines are selected based on the state and capabilities of -the hardware. For example, some graphics hardware can accelerate single -pixel width lines with certain dash patterns. Thus, for dash patterns -that are not supported by hardware or for width 2 or greater lines, the -default routine is chosen during GC validation. - -<p>Note that some pointers to functions that draw to the screen are -stored in the Screen structure. They include GetImage(), GetSpans(), -PaintWindowBackground(), PaintWindowBorder(), CopyWindow() and -RestoreAreas(). - -<sect2>Xnest - -<p>The Xnest X server is a special proxy X server that relays the X -protocol requests that it receives to a ``real'' X server that then -processes the requests and displays the results, if applicable. To the X -applications, Xnest appears as if it is a regular X server. However, -Xnest is both server to the X application and client of the real X -server, which will actually handle the requests. - -<p>The Xnest server implements all of the standard input and output -initialization steps outlined above. - -<descrip> -<tag/InitOutput()/ Xnest takes its configuration information from -command line arguments via ddxProcessArguments(). This information -includes the real X server display to connect to, its default visual -class, the screen depth, the Xnest window's geometry, etc. Xnest then -connects to the real X server and gathers visual, colormap, depth and -pixmap information about that server's display, creates a window on that -server, which will be used as the root window for Xnest. - -<p>Next, Xnest initializes its internal data structures and uses the -data from the real X server's pixmaps to initialize its own pixmap -formats. Finally, it calls AddScreen(xnestOpenScreen, argc, argv) to -initialize each of its screens. - -<tag/ScreenInit()/ Xnest's ScreenInit() function is called -xnestOpenScreen(). This function initializes its screen's depth and -visual information, and then calls miScreenInit() to set up the default -screen functions. It then calls miInitializeBackingStore() and -miDCInitialize() to initialize backing store and the software cursor. -Finally, it replaces many of the screen functions with its own -functions that repackage and send the requests to the real X server to -which Xnest is attached. - -<tag/CloseScreen()/ This function frees its internal data structure -allocations. Since it replaces instead of wrapping screen functions, -there are no function pointers to unwrap. This can potentially lead to -problems during server regeneration. - -<tag/GC operations/ The GC operations in Xnest are very simple since -they leave all of the drawing to the real X server to which Xnest is -attached. Each of the GCOps takes the request and sends it to the -real X server using standard Xlib calls. For example, the X -application issues a XDrawLines() call. This function turns into a -protocol request to Xnest, which calls the xnestPolylines() function -through Xnest's GCOps function pointer table. The xnestPolylines() -function is only a single line, which calls XDrawLines() using the same -arguments that were passed into it. Other GCOps functions are very -similar. Two exceptions to the simple GCOps functions described above -are the image functions and the BLT operations. - -<p>The image functions, GetImage() and PutImage(), must use a temporary -image to hold the image to be put of the image that was just grabbed -from the screen while it is in transit to the real X server or the -client. When the image has been transmitted, the temporary image is -destroyed. - -<p>The BLT operations, CopyArea() and CopyPlane(), handle not only the -copy function, which is the same as the simple cases described above, -but also the graphics exposures that result when the GC's graphics -exposure bit is set to True. Graphics exposures are handled in a helper -function, xnestBitBlitHelper(). This function collects the exposure -events from the real X server and, if any resulting in regions being -exposed, then those regions are passed back to the MI layer so that it -can generate exposure events for the X application. -</descrip> - -<p>The Xnest server takes its input from the X server to which it is -connected. When the mouse is in the Xnest server's window, keyboard and -mouse events are received by the Xnest server, repackaged and sent back -to any client that requests those events. - -<sect2>Shadow framebuffer - -<p>The most common type of framebuffer is a linear array memory that -maps to the video memory on the graphics device. However, accessing -that video memory over an I/O bus (e.g., ISA or PCI) can be slow. The -shadow framebuffer layer allows the developer to keep the entire -framebuffer in main memory and copy it back to video memory at regular -intervals. It also has been extended to handle planar video memory and -rotated framebuffers. - -<p>There are two main entry points to the shadow framebuffer code: - -<descrip> -<tag/shadowAlloc(width, height, bpp)/ This function allocates the in -memory copy of the framebuffer of size width*height*bpp. It returns a -pointer to that memory, which will be used by the framebuffer -ScreenInit() code during the screen's initialization. - -<tag/shadowInit(pScreen, updateProc, windowProc)/ This function -initializes the shadow framebuffer layer. It wraps several screen -drawing functions, and registers a block handler that will update the -screen. The updateProc is a function that will copy the damaged regions -to the screen, and the windowProc is a function that is used when the -entire linear video memory range cannot be accessed simultaneously so -that only a window into that memory is available (e.g., when using the -VGA aperture). -</descrip> - -<p>The shadow framebuffer code keeps track of the damaged area of each -screen by calculating the bounding box of all drawing operations that -have occurred since the last screen update. Then, when the block handler -is next called, only the damaged portion of the screen is updated. - -<p>Note that since the shadow framebuffer is kept in main memory, all -drawing operations are performed by the CPU and, thus, no accelerated -hardware drawing operations are possible. - - -<sect1>Xinerama - -<p>Xinerama is an X extension that allows multiple physical screens -controlled by a single X server to appear as a single screen. Although -the extension allows clients to find the physical screen layout via -extension requests, it is completely transparent to clients at the core -X11 protocol level. The original public implementation of Xinerama came -from Digital/Compaq. XFree86 rewrote it, filling in some missing pieces -and improving both X11 core protocol compliance and performance. The -Xinerama extension will be passing through X.Org's standardization -process in the near future, and the sample implementation will be based -on this rewritten version. - -<p>The current implementation of Xinerama is based primarily in the DIX -(device independent) and MI (machine independent) layers of the X -server. With few exceptions the DDX layers do not need any changes to -support Xinerama. X server extensions often do need modifications to -provide full Xinerama functionality. - -<p>The following is a code-level description of how Xinerama functions. - -<p>Note: Because the Xinerama extension was originally called the -PanoramiX extension, many of the Xinerama functions still have the -PanoramiX prefix. - -<descrip> - <tag/PanoramiXExtensionInit()/ PanoramiXExtensionInit() is a - device-independent extension function that is called at the start of - each server generation from InitExtensions(), which is called from - the X server's main() function after all output devices have been - initialized, but before any input devices have been initialized. - - <p>PanoramiXNumScreens is set to the number of physical screens. If - only one physical screen is present, the extension is disabled, and - PanoramiXExtensionInit() returns without doing anything else. - - <p>The Xinerama extension is registered by calling AddExtension(). - - <p>A local per-screen array of data structures - (panoramiXdataPtr[]) - is allocated for each physical screen, and GC and Screen private - indexes are allocated, and both GC and Screen private areas are - allocated for each physical screen. These hold Xinerama-specific - per-GC and per-Screen data. Each screen's CreateGC and CloseScreen - functions are wrapped by XineramaCreateGC() and - XineramaCloseScreen() respectively. Some new resource classes are - created for Xinerama drawables and GCs, and resource types for - Xinerama windows, pixmaps and colormaps. - - <p>A region (XineramaScreenRegions[i]) is initialized for each - physical screen, and single region (PanoramiXScreenRegion) is - initialized to be the union of the screen regions. The - panoramiXdataPtr[] array is also initialized with the size and - origin of each screen. The relative positioning information for the - physical screens is taken from the array - dixScreenOrigins[], which - the DDX layer must initialize in InitOutput(). The bounds of the - combined screen is also calculated (PanoramiXPixWidth and - PanoramiXPixHeight). - - <p>The DIX layer has a list of function pointers - (ProcVector[]) that - holds the entry points for the functions that process core protocol - requests. The requests that Xinerama must intercept and break up - into physical screen-specific requests are wrapped. The original - set is copied to SavedProcVector[]. The types of requests - intercepted are Window requests, GC requests, colormap requests, - drawing requests, and some geometry-related requests. This wrapping - allows the bulk of the protocol request processing to be handled - transparently to the DIX layer. Some operations cannot be dealt with - in this way and are handled with Xinerama-specific code within the - DIX layer. - - <tag/PanoramiXConsolidate()/ PanoramiXConsolidate() is a - device-independent extension function that is called directly from - the X server's main() function after extensions and input/output - devices have been initialized, and before the root windows are - defined and initialized. - - <p>This function finds the set of depths (PanoramiXDepths[]) and - visuals (PanoramiXVisuals[]) - common to all of the physical screens. - PanoramiXNumDepths is set to the number of common depths, and - PanoramiXNumVisuals is set to the number of common visuals. - Resources are created for the single root window and the default - colormap. Each of these resources has per-physical screen entries. - - <tag/PanoramiXCreateConnectionBlock()/ PanoramiXConsolidate() is a - device-independent extension function that is called directly from - the X server's main() function after the per-physical screen root - windows are created. It is called instead of the standard DIX - CreateConnectionBlock() function. If this function returns FALSE, - the X server exits with a fatal error. This function will return - FALSE if no common depths were found in PanoramiXConsolidate(). - With no common depths, Xinerama mode is not possible. - - <p>The connection block holds the information that clients get when - they open a connection to the X server. It includes information - such as the supported pixmap formats, number of screens and the - sizes, depths, visuals, default colormap information, etc, for each - of the screens (much of information that <tt/xdpyinfo/ shows). The - connection block is initialized with the combined single screen - values that were calculated in the above two functions. - - <p>The Xinerama extension allows the registration of connection - block callback functions. The purpose of these is to allow other - extensions to do processing at this point. These callbacks can be - registered by calling XineramaRegisterConnectionBlockCallback() from - the other extension's ExtensionInit() function. Each registered - connection block callback is called at the end of - PanoramiXCreateConnectionBlock(). -</descrip> - -<sect2>Xinerama-specific changes to the DIX code - -<p>There are a few types of Xinerama-specific changes within the DIX -code. The main ones are described here. - -<p>Functions that deal with colormap or GC -related operations outside of -the intercepted protocol requests have a test added to only do the -processing for screen numbers > 0. This is because they are handled for -the single Xinerama screen and the processing is done once for screen 0. - -<p>The handling of motion events does some coordinate translation between -the physical screen's origin and screen zero's origin. Also, motion -events must be reported relative to the composite screen origin rather -than the physical screen origins. - -<p>There is some special handling for cursor, window and event processing -that cannot (either not at all or not conveniently) be done via the -intercepted protocol requests. A particular case is the handling of -pointers moving between physical screens. - -<sect2>Xinerama-specific changes to the MI code - -<p>The only Xinerama-specific change to the MI code is in miSendExposures() -to handle the coordinate (and window ID) translation for expose events. - -<sect2>Intercepted DIX core requests - -<p>Xinerama breaks up drawing requests for dispatch to each physical -screen. It also breaks up windows into pieces for each physical screen. -GCs are translated into per-screen GCs. Colormaps are replicated on -each physical screen. The functions handling the intercepted requests -take care of breaking the requests and repackaging them so that they can -be passed to the standard request handling functions for each screen in -turn. In addition, and to aid the repackaging, the information from -many of the intercepted requests is used to keep up to date the -necessary state information for the single composite screen. Requests -(usually those with replies) that can be satisfied completely from this -stored state information do not call the standard request handling -functions. - -<!-- ============================================================ --> - -<sect>Development Results - -<p>In this section the results of each phase of development are -discussed. This development took place between approximately June 2001 -and July 2003. - -<sect1>Phase I - -<p>The initial development phase dealt with the basic implementation -including the bootstrap code, which used the shadow framebuffer, and the -unoptimized implementation, based on an Xnest-style implementation. - -<sect2>Scope - -<p>The goal of Phase I is to provide fundamental functionality that can -act as a foundation for ongoing work: -<enum> - <item>Develop the proxy X server - <itemize> - <item>The proxy X server will operate on the X11 protocol and - relay requests as necessary to correctly perform the request. - <item>Work will be based on the existing work for Xinerama and - Xnest. - <item>Input events and windowing operations are handled in the - proxy server and rendering requests are repackaged and sent to - each of the back-end servers for display. - <item>The multiple screen layout (including support for - overlapping screens) will be user configurable via a - configuration file or through the configuration tool. - </itemize> - <item>Develop graphical configuration tool - <itemize> - <item>There will be potentially a large number of X servers to - configure into a single display. The tool will allow the user - to specify which servers are involved in the configuration and - how they should be laid out. - </itemize> - <item>Pass the X Test Suite - <itemize> - <item>The X Test Suite covers the basic X11 operations. All - tests known to succeed must correctly operate in the distributed - X environment. - </itemize> -</enum> - -<p>For this phase, the back-end X servers are assumed to be unmodified X -servers that do not support any DMX-related protocol extensions; future -optimization pathways are considered, but are not implemented; and the -configuration tool is assumed to rely only on libraries in the X source -tree (e.g., Xt). - -<sect2>Results - -<p>The proxy X server, Xdmx, was developed to distribute X11 protocol -requests to the set of back-end X servers. It opens a window on each -back-end server, which represents the part of the front-end's root -window that is visible on that screen. It mirrors window, pixmap and -other state in each back-end server. Drawing requests are sent to -either windows or pixmaps on each back-end server. This code is based -on Xnest and uses the existing Xinerama extension. - -<p>Input events can be taken from (1) devices attached to the back-end -server, (2) core devices attached directly to the Xdmx server, or (3) -from a ``console'' window on another X server. Events for these devices -are gathered, processed and delivered to clients attached to the Xdmx -server. - -<p>An intuitive configuration format was developed to help the user -easily configure the multiple back-end X servers. It was defined (see -grammar in Xdmx man page) and a parser was implemented that is used by -the Xdmx server and by a standalone xdmxconfig utility. The parsing -support was implemented such that it can be easily factored out of the X -source tree for use with other tools (e.g., vdl). Support for -converting legacy vdl-format configuration files to the DMX format is -provided by the vdltodmx utility. - -<p>Originally, the configuration file was going to be a subsection of -XFree86's XF86Config file, but that was not possible since Xdmx is a -completely separate X server. Thus, a separate config file format was -developed. In addition, a graphical configuration -tool, xdmxconfig, was developed to allow the user to create and arrange -the screens in the configuration file. The <bf/-configfile/ and <bf/-config/ -command-line options can be used to start Xdmx using a configuration -file. - -<p>An extension that enables remote input testing is required for the X -Test Suite to function. During this phase, this extension (XTEST) was -implemented in the Xdmx server. The results from running the X Test -Suite are described in detail below. - -<sect2>X Test Suite - - <sect3> Introduction - <p> - The X Test Suite contains tests that verify Xlib functions - operate correctly. The test suite is designed to run on a - single X server; however, since X applications will not be - able to tell the difference between the DMX server and a - standard X server, the X Test Suite should also run on the - DMX server. - <p> - The Xdmx server was tested with the X Test Suite, and the - existing failures are noted in this section. To put these - results in perspective, we first discuss expected X Test - failures and how errors in underlying systems can impact - Xdmx test results. - - <sect3>Expected Failures for a Single Head - <p> - A correctly implemented X server with a single screen is - expected to fail certain X Test tests. The following - well-known errors occur because of rounding error in the X - server code: - <verb> -XDrawArc: Tests 42, 63, 66, 73 -XDrawArcs: Tests 45, 66, 69, 76 - </verb> - <p> - The following failures occur because of the high-level X - server implementation: - <verb> -XLoadQueryFont: Test 1 -XListFontsWithInfo: Tests 3, 4 -XQueryFont: Tests 1, 2 - </verb> - <p> - The following test fails when running the X server as root - under Linux because of the way directory modes are - interpreted: - <verb> -XWriteBitmapFile: Test 3 - </verb> - <p> - Depending on the video card used for the back-end, other - failures may also occur because of bugs in the low-level - driver implementation. Over time, failures of this kind - are usually fixed by XFree86, but will show up in Xdmx - testing until then. - - <sect3>Expected Failures for Xinerama - <p> - Xinerama fails several X Test Suite tests because of - design decisions made for the current implementation of - Xinerama. Over time, many of these errors will be - corrected by XFree86 and the group working on a new - Xinerama implementation. Therefore, Xdmx will also share - X Suite Test failures with Xinerama. - <p> - We may be able to fix or work-around some of these - failures at the Xdmx level, but this will require - additional exploration that was not part of Phase I. - <p> - Xinerama is constantly improving, and the list of - Xinerama-related failures depends on XFree86 version and - the underlying graphics hardware. We tested with a - variety of hardware, including nVidia, S3, ATI Radeon, - and Matrox G400 (in dual-head mode). The list below - includes only those failures that appear to be from the - Xinerama layer, and does not include failures listed in - the previous section, or failures that appear to be from - the low-level graphics driver itself: - <p> - These failures were noted with multiple Xinerama - configurations: - <verb> -XCopyPlane: Tests 13, 22, 31 (well-known Xinerama implementation issue) -XSetFontPath: Test 4 -XGetDefault: Test 5 -XMatchVisualInfo: Test 1 - </verb> - <p> - These failures were noted only when using one dual-head - video card with a 4.2.99.x XFree86 server: - <verb> -XListPixmapFormats: Test 1 -XDrawRectangles: Test 45 - </verb> - <p> - These failures were noted only when using two video cards - from different vendors with a 4.1.99.x XFree86 server: - <verb> -XChangeWindowAttributes: Test 32 -XCreateWindow: Test 30 -XDrawLine: Test 22 -XFillArc: Test 22 -XChangeKeyboardControl: Tests 9, 10 -XRebindKeysym: Test 1 - </verb> - - <sect3>Additional Failures from Xdmx - <p> - When running Xdmx, no unexpected failures were noted. - Since the Xdmx server is based on Xinerama, we expect to - have most of the Xinerama failures present in the Xdmx - server. Similarly, since the Xdmx server must rely on the - low-level device drivers on each back-end server, we also - expect that Xdmx will exhibit most of the back-end - failures. Here is a summary: - <verb> -XListPixmapFormats: Test 1 (configuration dependent) -XChangeWindowAttributes: Test 32 -XCreateWindow: Test 30 -XCopyPlane: Test 13, 22, 31 -XSetFontPath: Test 4 -XGetDefault: Test 5 (configuration dependent) -XMatchVisualInfo: Test 1 -XRebindKeysym: Test 1 (configuration dependent) - </verb> - <p> - Note that this list is shorter than the combined list for - Xinerama because Xdmx uses different code paths to perform - some Xinerama operations. Further, some Xinerama failures - have been fixed in the XFree86 4.2.99.x CVS repository. - - <sect3>Summary and Future Work - <p> - Running the X Test Suite on Xdmx does not produce any - failures that cannot be accounted for by the underlying - Xinerama subsystem used by the front-end or by the - low-level device-driver code running on the back-end X - servers. The Xdmx server therefore is as ``correct'' as - possible with respect to the standard set of X Test Suite - tests. - <p> - During the following phases, we will continue to verify - Xdmx correctness using the X Test Suite. We may also use - other tests suites or write additional tests that run - under the X Test Suite that specifically verify the - expected behavior of DMX. - -<sect2>Fonts - -<p>In Phase I, fonts are handled directly by both the front-end and the -back-end servers, which is required since we must treat each back-end -server during this phase as a ``black box''. What this requires is that -<bf/the front- and back-end servers must share the exact same font -path/. There are two ways to help make sure that all servers share the -same font path: - -<enum> - <item>First, each server can be configured to use the same font - server. The font server, xfs, can be configured to serve fonts to - multiple X servers via TCP. - - <item>Second, each server can be configured to use the same font - path and either those font paths can be copied to each back-end - machine or they can be mounted (e.g., via NFS) on each back-end - machine. -</enum> - -<p>One additional concern is that a client program can set its own font -path, and if it does so, then that font path must be available on each -back-end machine. - -<p>The -fontpath command line option was added to allow users to -initialize the font path of the front end server. This font path is -propagated to each back-end server when the default font is loaded. If -there are any problems, an error message is printed, which will describe -the problem and list the current font path. For more information about -setting the font path, see the -fontpath option description in the man -page. - -<sect2>Performance - -<p>Phase I of development was not intended to optimize performance. Its -focus was on completely and correctly handling the base X11 protocol in -the Xdmx server. However, several insights were gained during Phase I, -which are listed here for reference during the next phase of -development. - -<enum> - <item>Calls to XSync() can slow down rendering since it requires a - complete round trip to and from a back-end server. This is - especially problematic when communicating over long haul networks. - <item>Sending drawing requests to only the screens that they overlap - should improve performance. -</enum> - -<sect2>Pixmaps - -<p>Pixmaps were originally expected to be handled entirely in the -front-end X server; however, it was found that this overly complicated -the rendering code and would have required sending potentially large -images to each back server that required them when copying from pixmap -to screen. Thus, pixmap state is mirrored in the back-end server just -as it is with regular window state. With this implementation, the same -rendering code that draws to windows can be used to draw to pixmaps on -the back-end server, and no large image transfers are required to copy -from pixmap to window. - -<!-- ============================================================ --> -<sect1>Phase II - -<p>The second phase of development concentrates on performance -optimizations. These optimizations are documented here, with -<tt/x11perf/ data to show how the optimizations improve performance. - -<p>All benchmarks were performed by running Xdmx on a dual processor -1.4GHz AMD Athlon machine with 1GB of RAM connecting over 100baseT to -two single-processor 1GHz Pentium III machines with 256MB of RAM and ATI -Rage 128 (RF) video cards. The front end was running Linux -2.4.20-pre1-ac1 and the back ends were running Linux 2.4.7-10 and -version 4.2.99.1 of XFree86 pulled from the XFree86 CVS repository on -August 7, 2002. All systems were running Red Hat Linux 7.2. - -<sect2>Moving from XFree86 4.1.99.1 to 4.2.0.0 - -<p>For phase II, the working source tree was moved to the branch tagged -with dmx-1-0-branch and was updated from version 4.1.99.1 (20 August -2001) of the XFree86 sources to version 4.2.0.0 (18 January 2002). -After this update, the following tests were noted to be more than 10% -faster: - <verb> -1.13 Fill 300x300 opaque stippled trapezoid (161x145 stipple) -1.16 Fill 1x1 tiled trapezoid (161x145 tile) -1.13 Fill 10x10 tiled trapezoid (161x145 tile) -1.17 Fill 100x100 tiled trapezoid (161x145 tile) -1.16 Fill 1x1 tiled trapezoid (216x208 tile) -1.20 Fill 10x10 tiled trapezoid (216x208 tile) -1.15 Fill 100x100 tiled trapezoid (216x208 tile) -1.37 Circulate Unmapped window (200 kids) - </verb> -And the following tests were noted to be more than 10% slower: - <verb> -0.88 Unmap window via parent (25 kids) -0.75 Circulate Unmapped window (4 kids) -0.79 Circulate Unmapped window (16 kids) -0.80 Circulate Unmapped window (25 kids) -0.82 Circulate Unmapped window (50 kids) -0.85 Circulate Unmapped window (75 kids) - </verb> -<p>These changes were not caused by any changes in the DMX system, and -may point to changes in the XFree86 tree or to tests that have more -"jitter" than most other <tt/x11perf/ tests. - -<sect2>Global changes - -<p>During the development of the Phase II DMX server, several global -changes were made. These changes were also compared with the Phase I -server. The following tests were noted to be more than 10% faster: - <verb> -1.13 Fill 300x300 opaque stippled trapezoid (161x145 stipple) -1.15 Fill 1x1 tiled trapezoid (161x145 tile) -1.13 Fill 10x10 tiled trapezoid (161x145 tile) -1.17 Fill 100x100 tiled trapezoid (161x145 tile) -1.16 Fill 1x1 tiled trapezoid (216x208 tile) -1.19 Fill 10x10 tiled trapezoid (216x208 tile) -1.15 Fill 100x100 tiled trapezoid (216x208 tile) -1.15 Circulate Unmapped window (4 kids) - </verb> - -<p>The following tests were noted to be more than 10% slower: - <verb> -0.69 Scroll 10x10 pixels -0.68 Scroll 100x100 pixels -0.68 Copy 10x10 from window to window -0.68 Copy 100x100 from window to window -0.76 Circulate Unmapped window (75 kids) -0.83 Circulate Unmapped window (100 kids) - </verb> - -<p>For the remainder of this analysis, the baseline of comparison will -be the Phase II deliverable with all optimizations disabled (unless -otherwise noted). This will highlight how the optimizations in -isolation impact performance. - -<sect2>XSync() Batching - -<p>During the Phase I implementation, XSync() was called after every -protocol request made by the DMX server. This provided the DMX server -with an interactive feel, but defeated X11's protocol buffering system -and introduced round-trip wire latency into every operation. During -Phase II, DMX was changed so that protocol requests are no longer -followed by calls to XSync(). Instead, the need for an XSync() is -noted, and XSync() calls are only made every 100mS or when the DMX -server specifically needs to make a call to guarantee interactivity. -With this new system, X11 buffers protocol as much as possible during a -100mS interval, and many unnecessary XSync() calls are avoided. - -<p>Out of more than 300 <tt/x11perf/ tests, 8 tests became more than 100 -times faster, with 68 more than 50X faster, 114 more than 10X faster, -and 181 more than 2X faster. See table below for summary. - -<p>The following tests were noted to be more than 10% slower with -XSync() batching on: - <verb> -0.88 500x500 tiled rectangle (161x145 tile) -0.89 Copy 500x500 from window to window - </verb> - -<sect2>Offscreen Optimization - -<p>Windows span one or more of the back-end servers' screens; however, -during Phase I development, windows were created on every back-end -server and every rendering request was sent to every window regardless -of whether or not that window was visible. With the offscreen -optimization, the DMX server tracks when a window is completely off of a -back-end server's screen and, in that case, it does not send rendering -requests to those back-end windows. This optimization saves bandwidth -between the front and back-end servers, and it reduces the number of -XSync() calls. The performance tests were run on a DMX system with only -two back-end servers. Greater performance gains will be had as the -number of back-end servers increases. - -<p>Out of more than 300 <tt/x11perf/ tests, 3 tests were at least twice as -fast, and 146 tests were at least 10% faster. Two tests were more than -10% slower with the offscreen optimization: - <verb> -0.88 Hide/expose window via popup (4 kids) -0.89 Resize unmapped window (75 kids) - </verb> - -<sect2>Lazy Window Creation Optimization - -<p>As mentioned above, during Phase I, windows were created on every -back-end server even if they were not visible on that back-end. With -the lazy window creation optimization, the DMX server does not create -windows on a back-end server until they are either visible or they -become the parents of a visible window. This optimization builds on the -offscreen optimization (described above) and requires it to be enabled. - -<p>The lazy window creation optimization works by creating the window -data structures in the front-end server when a client creates a window, -but delays creation of the window on the back-end server(s). A private -window structure in the DMX server saves the relevant window data and -tracks changes to the window's attributes and stacking order for later -use. The only times a window is created on a back-end server are (1) -when it is mapped and is at least partially overlapping the back-end -server's screen (tracked by the offscreen optimization), or (2) when the -window becomes the parent of a previously visible window. The first -case occurs when a window is mapped or when a visible window is copied, -moved or resized and now overlaps the back-end server's screen. The -second case occurs when starting a window manager after having created -windows to which the window manager needs to add decorations. - -<p>When either case occurs, a window on the back-end server is created -using the data saved in the DMX server's window private data structure. -The stacking order is then adjusted to correctly place the window on the -back-end and lastly the window is mapped. From this time forward, the -window is handled exactly as if the window had been created at the time -of the client's request. - -<p>Note that when a window is no longer visible on a back-end server's -screen (e.g., it is moved offscreen), the window is not destroyed; -rather, it is kept and reused later if the window once again becomes -visible on the back-end server's screen. Originally with this -optimization, destroying windows was implemented but was later rejected -because it increased bandwidth when windows were opaquely moved or -resized, which is common in many window managers. - -<p>The performance tests were run on a DMX system with only two back-end -servers. Greater performance gains will be had as the number of -back-end servers increases. - -<p>This optimization improved the following <tt/x11perf/ tests by more -than 10%: - <verb> -1.10 500x500 rectangle outline -1.12 Fill 100x100 stippled trapezoid (161x145 stipple) -1.20 Circulate Unmapped window (50 kids) -1.19 Circulate Unmapped window (75 kids) - </verb> - -<sect2>Subdividing Rendering Primitives - -<p>X11 imaging requests transfer significant data between the client and -the X server. During Phase I, the DMX server would then transfer the -image data to each back-end server. Even with the offscreen -optimization (above), these requests still required transferring -significant data to each back-end server that contained a visible -portion of the window. For example, if the client uses XPutImage() to -copy an image to a window that overlaps the entire DMX screen, then the -entire image is copied by the DMX server to every back-end server. - -<p>To reduce the amount of data transferred between the DMX server and -the back-end servers when XPutImage() is called, the image data is -subdivided and only the data that will be visible on a back-end server's -screen is sent to that back-end server. Xinerama already implements a -subdivision algorithm for XGetImage() and no further optimization was -needed. - -<p>Other rendering primitives were analyzed, but the time required to -subdivide these primitives was a significant proportion of the time -required to send the entire rendering request to the back-end server, so -this optimization was rejected for the other rendering primitives. - -<p>Again, the performance tests were run on a DMX system with only two -back-end servers. Greater performance gains will be had as the number -of back-end servers increases. - -<p>This optimization improved the following <tt/x11perf/ tests by more -than 10%: - <verb> -1.12 Fill 100x100 stippled trapezoid (161x145 stipple) -1.26 PutImage 10x10 square -1.83 PutImage 100x100 square -1.91 PutImage 500x500 square -1.40 PutImage XY 10x10 square -1.48 PutImage XY 100x100 square -1.50 PutImage XY 500x500 square -1.45 Circulate Unmapped window (75 kids) -1.74 Circulate Unmapped window (100 kids) - </verb> - -<p>The following test was noted to be more than 10% slower with this -optimization: - <verb> -0.88 10-pixel fill chord partial circle - </verb> - -<sect2>Summary of x11perf Data - -<p>With all of the optimizations on, 53 <tt/x11perf/ tests are more than -100X faster than the unoptimized Phase II deliverable, with 69 more than -50X faster, 73 more than 10X faster, and 199 more than twice as fast. -No tests were more than 10% slower than the unoptimized Phase II -deliverable. (Compared with the Phase I deliverable, only Circulate -Unmapped window (100 kids) was more than 10% slower than the Phase II -deliverable. As noted above, this test seems to have wider variability -than other <tt/x11perf/ tests.) - -<p>The following table summarizes relative <tt/x11perf/ test changes for -all optimizations individually and collectively. Note that some of the -optimizations have a synergistic effect when used together. - <verb> - -1: XSync() batching only -2: Off screen optimizations only -3: Window optimizations only -4: Subdivprims only -5: All optimizations - - 1 2 3 4 5 Operation ------- ---- ---- ---- ------ --------- - 2.14 1.85 1.00 1.00 4.13 Dot - 1.67 1.80 1.00 1.00 3.31 1x1 rectangle - 2.38 1.43 1.00 1.00 2.44 10x10 rectangle - 1.00 1.00 0.92 0.98 1.00 100x100 rectangle - 1.00 1.00 1.00 1.00 1.00 500x500 rectangle - 1.83 1.85 1.05 1.06 3.54 1x1 stippled rectangle (8x8 stipple) - 2.43 1.43 1.00 1.00 2.41 10x10 stippled rectangle (8x8 stipple) - 0.98 1.00 1.00 1.00 1.00 100x100 stippled rectangle (8x8 stipple) - 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (8x8 stipple) - 1.75 1.75 1.00 1.00 3.40 1x1 opaque stippled rectangle (8x8 stipple) - 2.38 1.42 1.00 1.00 2.34 10x10 opaque stippled rectangle (8x8 stipple) - 1.00 1.00 0.97 0.97 1.00 100x100 opaque stippled rectangle (8x8 stipple) - 1.00 1.00 1.00 1.00 0.99 500x500 opaque stippled rectangle (8x8 stipple) - 1.82 1.82 1.04 1.04 3.56 1x1 tiled rectangle (4x4 tile) - 2.33 1.42 1.00 1.00 2.37 10x10 tiled rectangle (4x4 tile) - 1.00 0.92 1.00 1.00 1.00 100x100 tiled rectangle (4x4 tile) - 1.00 1.00 1.00 1.00 1.00 500x500 tiled rectangle (4x4 tile) - 1.94 1.62 1.00 1.00 3.66 1x1 stippled rectangle (17x15 stipple) - 1.74 1.28 1.00 1.00 1.73 10x10 stippled rectangle (17x15 stipple) - 1.00 1.00 1.00 0.89 0.98 100x100 stippled rectangle (17x15 stipple) - 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (17x15 stipple) - 1.94 1.62 1.00 1.00 3.67 1x1 opaque stippled rectangle (17x15 stipple) - 1.69 1.26 1.00 1.00 1.66 10x10 opaque stippled rectangle (17x15 stipple) - 1.00 0.95 1.00 1.00 1.00 100x100 opaque stippled rectangle (17x15 stipple) - 1.00 1.00 1.00 1.00 0.97 500x500 opaque stippled rectangle (17x15 stipple) - 1.93 1.61 0.99 0.99 3.69 1x1 tiled rectangle (17x15 tile) - 1.73 1.27 1.00 1.00 1.72 10x10 tiled rectangle (17x15 tile) - 1.00 1.00 1.00 1.00 0.98 100x100 tiled rectangle (17x15 tile) - 1.00 1.00 0.97 0.97 1.00 500x500 tiled rectangle (17x15 tile) - 1.95 1.63 1.00 1.00 3.83 1x1 stippled rectangle (161x145 stipple) - 1.80 1.30 1.00 1.00 1.83 10x10 stippled rectangle (161x145 stipple) - 0.97 1.00 1.00 1.00 1.01 100x100 stippled rectangle (161x145 stipple) - 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (161x145 stipple) - 1.95 1.63 1.00 1.00 3.56 1x1 opaque stippled rectangle (161x145 stipple) - 1.65 1.25 1.00 1.00 1.68 10x10 opaque stippled rectangle (161x145 stipple) - 1.00 1.00 1.00 1.00 1.01 100x100 opaque stippled rectangle (161x145... - 1.00 1.00 1.00 1.00 0.97 500x500 opaque stippled rectangle (161x145... - 1.95 1.63 0.98 0.99 3.80 1x1 tiled rectangle (161x145 tile) - 1.67 1.26 1.00 1.00 1.67 10x10 tiled rectangle (161x145 tile) - 1.13 1.14 1.14 1.14 1.14 100x100 tiled rectangle (161x145 tile) - 0.88 1.00 1.00 1.00 0.99 500x500 tiled rectangle (161x145 tile) - 1.93 1.63 1.00 1.00 3.53 1x1 tiled rectangle (216x208 tile) - 1.69 1.26 1.00 1.00 1.66 10x10 tiled rectangle (216x208 tile) - 1.00 1.00 1.00 1.00 1.00 100x100 tiled rectangle (216x208 tile) - 1.00 1.00 1.00 1.00 1.00 500x500 tiled rectangle (216x208 tile) - 1.82 1.70 1.00 1.00 3.38 1-pixel line segment - 2.07 1.56 0.90 1.00 3.31 10-pixel line segment - 1.29 1.10 1.00 1.00 1.27 100-pixel line segment - 1.05 1.06 1.03 1.03 1.09 500-pixel line segment - 1.30 1.13 1.00 1.00 1.29 100-pixel line segment (1 kid) - 1.32 1.15 1.00 1.00 1.32 100-pixel line segment (2 kids) - 1.33 1.16 1.00 1.00 1.33 100-pixel line segment (3 kids) - 1.92 1.64 1.00 1.00 3.73 10-pixel dashed segment - 1.34 1.16 1.00 1.00 1.34 100-pixel dashed segment - 1.24 1.11 0.99 0.97 1.23 100-pixel double-dashed segment - 1.72 1.77 1.00 1.00 3.25 10-pixel horizontal line segment - 1.83 1.66 1.01 1.00 3.54 100-pixel horizontal line segment - 1.86 1.30 1.00 1.00 1.84 500-pixel horizontal line segment - 2.11 1.52 1.00 0.99 3.02 10-pixel vertical line segment - 1.21 1.10 1.00 1.00 1.20 100-pixel vertical line segment - 1.03 1.03 1.00 1.00 1.02 500-pixel vertical line segment - 4.42 1.68 1.00 1.01 4.64 10x1 wide horizontal line segment - 1.83 1.31 1.00 1.00 1.83 100x10 wide horizontal line segment - 1.07 1.00 0.96 1.00 1.07 500x50 wide horizontal line segment - 4.10 1.67 1.00 1.00 4.62 10x1 wide vertical line segment - 1.50 1.24 1.06 1.06 1.48 100x10 wide vertical line segment - 1.06 1.03 1.00 1.00 1.05 500x50 wide vertical line segment - 2.54 1.61 1.00 1.00 3.61 1-pixel line - 2.71 1.48 1.00 1.00 2.67 10-pixel line - 1.19 1.09 1.00 1.00 1.19 100-pixel line - 1.04 1.02 1.00 1.00 1.03 500-pixel line - 2.68 1.51 0.98 1.00 3.17 10-pixel dashed line - 1.23 1.11 0.99 0.99 1.23 100-pixel dashed line - 1.15 1.08 1.00 1.00 1.15 100-pixel double-dashed line - 2.27 1.39 1.00 1.00 2.23 10x1 wide line - 1.20 1.09 1.00 1.00 1.20 100x10 wide line - 1.04 1.02 1.00 1.00 1.04 500x50 wide line - 1.52 1.45 1.00 1.00 1.52 100x10 wide dashed line - 1.54 1.47 1.00 1.00 1.54 100x10 wide double-dashed line - 1.97 1.30 0.96 0.95 1.95 10x10 rectangle outline - 1.44 1.27 1.00 1.00 1.43 100x100 rectangle outline - 3.22 2.16 1.10 1.09 3.61 500x500 rectangle outline - 1.95 1.34 1.00 1.00 1.90 10x10 wide rectangle outline - 1.14 1.14 1.00 1.00 1.13 100x100 wide rectangle outline - 1.00 1.00 1.00 1.00 1.00 500x500 wide rectangle outline - 1.57 1.72 1.00 1.00 3.03 1-pixel circle - 1.96 1.35 1.00 1.00 1.92 10-pixel circle - 1.21 1.07 0.86 0.97 1.20 100-pixel circle - 1.08 1.04 1.00 1.00 1.08 500-pixel circle - 1.39 1.19 1.03 1.03 1.38 100-pixel dashed circle - 1.21 1.11 1.00 1.00 1.23 100-pixel double-dashed circle - 1.59 1.28 1.00 1.00 1.58 10-pixel wide circle - 1.22 1.12 0.99 1.00 1.22 100-pixel wide circle - 1.06 1.04 1.00 1.00 1.05 500-pixel wide circle - 1.87 1.84 1.00 1.00 1.85 100-pixel wide dashed circle - 1.90 1.93 1.01 1.01 1.90 100-pixel wide double-dashed circle - 2.13 1.43 1.00 1.00 2.32 10-pixel partial circle - 1.42 1.18 1.00 1.00 1.42 100-pixel partial circle - 1.92 1.85 1.01 1.01 1.89 10-pixel wide partial circle - 1.73 1.67 1.00 1.00 1.73 100-pixel wide partial circle - 1.36 1.95 1.00 1.00 2.64 1-pixel solid circle - 2.02 1.37 1.00 1.00 2.03 10-pixel solid circle - 1.19 1.09 1.00 1.00 1.19 100-pixel solid circle - 1.02 0.99 1.00 1.00 1.01 500-pixel solid circle - 1.74 1.28 1.00 0.88 1.73 10-pixel fill chord partial circle - 1.31 1.13 1.00 1.00 1.31 100-pixel fill chord partial circle - 1.67 1.31 1.03 1.03 1.72 10-pixel fill slice partial circle - 1.30 1.13 1.00 1.00 1.28 100-pixel fill slice partial circle - 2.45 1.49 1.01 1.00 2.71 10-pixel ellipse - 1.22 1.10 1.00 1.00 1.22 100-pixel ellipse - 1.09 1.04 1.00 1.00 1.09 500-pixel ellipse - 1.90 1.28 1.00 1.00 1.89 100-pixel dashed ellipse - 1.62 1.24 0.96 0.97 1.61 100-pixel double-dashed ellipse - 2.43 1.50 1.00 1.00 2.42 10-pixel wide ellipse - 1.61 1.28 1.03 1.03 1.60 100-pixel wide ellipse - 1.08 1.05 1.00 1.00 1.08 500-pixel wide ellipse - 1.93 1.88 1.00 1.00 1.88 100-pixel wide dashed ellipse - 1.94 1.89 1.01 1.00 1.94 100-pixel wide double-dashed ellipse - 2.31 1.48 1.00 1.00 2.67 10-pixel partial ellipse - 1.38 1.17 1.00 1.00 1.38 100-pixel partial ellipse - 2.00 1.85 0.98 0.97 1.98 10-pixel wide partial ellipse - 1.89 1.86 1.00 1.00 1.89 100-pixel wide partial ellipse - 3.49 1.60 1.00 1.00 3.65 10-pixel filled ellipse - 1.67 1.26 1.00 1.00 1.67 100-pixel filled ellipse - 1.06 1.04 1.00 1.00 1.06 500-pixel filled ellipse - 2.38 1.43 1.01 1.00 2.32 10-pixel fill chord partial ellipse - 2.06 1.30 1.00 1.00 2.05 100-pixel fill chord partial ellipse - 2.27 1.41 1.00 1.00 2.27 10-pixel fill slice partial ellipse - 1.98 1.33 1.00 0.97 1.97 100-pixel fill slice partial ellipse - 57.46 1.99 1.01 1.00 114.92 Fill 1x1 equivalent triangle - 56.94 1.98 1.01 1.00 73.89 Fill 10x10 equivalent triangle - 6.07 1.75 1.00 1.00 6.07 Fill 100x100 equivalent triangle - 51.12 1.98 1.00 1.00 102.81 Fill 1x1 trapezoid - 51.42 1.82 1.01 1.00 94.89 Fill 10x10 trapezoid - 6.47 1.80 1.00 1.00 6.44 Fill 100x100 trapezoid - 1.56 1.28 1.00 0.99 1.56 Fill 300x300 trapezoid - 51.27 1.97 0.96 0.97 102.54 Fill 1x1 stippled trapezoid (8x8 stipple) - 51.73 2.00 1.02 1.02 67.92 Fill 10x10 stippled trapezoid (8x8 stipple) - 5.36 1.72 1.00 1.00 5.36 Fill 100x100 stippled trapezoid (8x8 stipple) - 1.54 1.26 1.00 1.00 1.59 Fill 300x300 stippled trapezoid (8x8 stipple) - 51.41 1.94 1.01 1.00 102.82 Fill 1x1 opaque stippled trapezoid (8x8 stipple) - 50.71 1.95 0.99 1.00 65.44 Fill 10x10 opaque stippled trapezoid (8x8... - 5.33 1.73 1.00 1.00 5.36 Fill 100x100 opaque stippled trapezoid (8x8... - 1.58 1.25 1.00 1.00 1.58 Fill 300x300 opaque stippled trapezoid (8x8... - 51.56 1.96 0.99 0.90 103.68 Fill 1x1 tiled trapezoid (4x4 tile) - 51.59 1.99 1.01 1.01 62.25 Fill 10x10 tiled trapezoid (4x4 tile) - 5.38 1.72 1.00 1.00 5.38 Fill 100x100 tiled trapezoid (4x4 tile) - 1.54 1.25 1.00 0.99 1.58 Fill 300x300 tiled trapezoid (4x4 tile) - 51.70 1.98 1.01 1.01 103.98 Fill 1x1 stippled trapezoid (17x15 stipple) - 44.86 1.97 1.00 1.00 44.86 Fill 10x10 stippled trapezoid (17x15 stipple) - 2.74 1.56 1.00 1.00 2.73 Fill 100x100 stippled trapezoid (17x15 stipple) - 1.29 1.14 1.00 1.00 1.27 Fill 300x300 stippled trapezoid (17x15 stipple) - 51.41 1.96 0.96 0.95 103.39 Fill 1x1 opaque stippled trapezoid (17x15... - 45.14 1.96 1.01 1.00 45.14 Fill 10x10 opaque stippled trapezoid (17x15... - 2.68 1.56 1.00 1.00 2.68 Fill 100x100 opaque stippled trapezoid (17x15... - 1.26 1.10 1.00 1.00 1.28 Fill 300x300 opaque stippled trapezoid (17x15... - 51.13 1.97 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (17x15 tile) - 47.58 1.96 1.00 1.00 47.86 Fill 10x10 tiled trapezoid (17x15 tile) - 2.74 1.56 1.00 1.00 2.74 Fill 100x100 tiled trapezoid (17x15 tile) - 1.29 1.14 1.00 1.00 1.28 Fill 300x300 tiled trapezoid (17x15 tile) - 51.13 1.97 0.99 0.97 103.39 Fill 1x1 stippled trapezoid (161x145 stipple) - 45.14 1.97 1.00 1.00 44.29 Fill 10x10 stippled trapezoid (161x145 stipple) - 3.02 1.77 1.12 1.12 3.38 Fill 100x100 stippled trapezoid (161x145 stipple) - 1.31 1.13 1.00 1.00 1.30 Fill 300x300 stippled trapezoid (161x145 stipple) - 51.27 1.97 1.00 1.00 103.10 Fill 1x1 opaque stippled trapezoid (161x145... - 45.01 1.97 1.00 1.00 45.01 Fill 10x10 opaque stippled trapezoid (161x145... - 2.67 1.56 1.00 1.00 2.69 Fill 100x100 opaque stippled trapezoid (161x145.. - 1.29 1.13 1.00 1.01 1.27 Fill 300x300 opaque stippled trapezoid (161x145.. - 51.41 1.96 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (161x145 tile) - 45.01 1.96 0.98 1.00 45.01 Fill 10x10 tiled trapezoid (161x145 tile) - 2.62 1.36 1.00 1.00 2.69 Fill 100x100 tiled trapezoid (161x145 tile) - 1.27 1.13 1.00 1.00 1.22 Fill 300x300 tiled trapezoid (161x145 tile) - 51.13 1.98 1.00 1.00 103.39 Fill 1x1 tiled trapezoid (216x208 tile) - 45.14 1.97 1.01 0.99 45.14 Fill 10x10 tiled trapezoid (216x208 tile) - 2.62 1.55 1.00 1.00 2.71 Fill 100x100 tiled trapezoid (216x208 tile) - 1.28 1.13 1.00 1.00 1.20 Fill 300x300 tiled trapezoid (216x208 tile) - 50.71 1.95 1.00 1.00 54.70 Fill 10x10 equivalent complex polygon - 5.51 1.71 0.96 0.98 5.47 Fill 100x100 equivalent complex polygons - 8.39 1.97 1.00 1.00 16.75 Fill 10x10 64-gon (Convex) - 8.38 1.83 1.00 1.00 8.43 Fill 100x100 64-gon (Convex) - 8.50 1.96 1.00 1.00 16.64 Fill 10x10 64-gon (Complex) - 8.26 1.83 1.00 1.00 8.35 Fill 100x100 64-gon (Complex) - 14.09 1.87 1.00 1.00 14.05 Char in 80-char line (6x13) - 11.91 1.87 1.00 1.00 11.95 Char in 70-char line (8x13) - 11.16 1.85 1.01 1.00 11.10 Char in 60-char line (9x15) - 10.09 1.78 1.00 1.00 10.09 Char16 in 40-char line (k14) - 6.15 1.75 1.00 1.00 6.31 Char16 in 23-char line (k24) - 11.92 1.90 1.03 1.03 11.88 Char in 80-char line (TR 10) - 8.18 1.78 1.00 0.99 8.17 Char in 30-char line (TR 24) - 42.83 1.44 1.01 1.00 42.11 Char in 20/40/20 line (6x13, TR 10) - 27.45 1.43 1.01 1.01 27.45 Char16 in 7/14/7 line (k14, k24) - 12.13 1.85 1.00 1.00 12.05 Char in 80-char image line (6x13) - 10.00 1.84 1.00 1.00 10.00 Char in 70-char image line (8x13) - 9.18 1.83 1.00 1.00 9.12 Char in 60-char image line (9x15) - 9.66 1.82 0.98 0.95 9.66 Char16 in 40-char image line (k14) - 5.82 1.72 1.00 1.00 5.99 Char16 in 23-char image line (k24) - 8.70 1.80 1.00 1.00 8.65 Char in 80-char image line (TR 10) - 4.67 1.66 1.00 1.00 4.67 Char in 30-char image line (TR 24) - 84.43 1.47 1.00 1.00 124.18 Scroll 10x10 pixels - 3.73 1.50 1.00 0.98 3.73 Scroll 100x100 pixels - 1.00 1.00 1.00 1.00 1.00 Scroll 500x500 pixels - 84.43 1.51 1.00 1.00 134.02 Copy 10x10 from window to window - 3.62 1.51 0.98 0.98 3.62 Copy 100x100 from window to window - 0.89 1.00 1.00 1.00 1.00 Copy 500x500 from window to window - 57.06 1.99 1.00 1.00 88.64 Copy 10x10 from pixmap to window - 2.49 2.00 1.00 1.00 2.48 Copy 100x100 from pixmap to window - 1.00 0.91 1.00 1.00 0.98 Copy 500x500 from pixmap to window - 2.04 1.01 1.00 1.00 2.03 Copy 10x10 from window to pixmap - 1.05 1.00 1.00 1.00 1.05 Copy 100x100 from window to pixmap - 1.00 1.00 0.93 1.00 1.04 Copy 500x500 from window to pixmap - 58.52 1.03 1.03 1.02 57.95 Copy 10x10 from pixmap to pixmap - 2.40 1.00 1.00 1.00 2.45 Copy 100x100 from pixmap to pixmap - 1.00 1.00 1.00 1.00 1.00 Copy 500x500 from pixmap to pixmap - 51.57 1.92 1.00 1.00 85.75 Copy 10x10 1-bit deep plane - 6.37 1.75 1.01 1.01 6.37 Copy 100x100 1-bit deep plane - 1.26 1.11 1.00 1.00 1.24 Copy 500x500 1-bit deep plane - 4.23 1.63 0.98 0.97 4.38 Copy 10x10 n-bit deep plane - 1.04 1.02 1.00 1.00 1.04 Copy 100x100 n-bit deep plane - 1.00 1.00 1.00 1.00 1.00 Copy 500x500 n-bit deep plane - 6.45 1.98 1.00 1.26 12.80 PutImage 10x10 square - 1.10 1.87 1.00 1.83 2.11 PutImage 100x100 square - 1.02 1.93 1.00 1.91 1.91 PutImage 500x500 square - 4.17 1.78 1.00 1.40 7.18 PutImage XY 10x10 square - 1.27 1.49 0.97 1.48 2.10 PutImage XY 100x100 square - 1.00 1.50 1.00 1.50 1.52 PutImage XY 500x500 square - 1.07 1.01 1.00 1.00 1.06 GetImage 10x10 square - 1.01 1.00 1.00 1.00 1.01 GetImage 100x100 square - 1.00 1.00 1.00 1.00 1.00 GetImage 500x500 square - 1.56 1.00 0.99 0.97 1.56 GetImage XY 10x10 square - 1.02 1.00 1.00 1.00 1.02 GetImage XY 100x100 square - 1.00 1.00 1.00 1.00 1.00 GetImage XY 500x500 square - 1.00 1.00 1.01 0.98 0.95 X protocol NoOperation - 1.02 1.03 1.04 1.03 1.00 QueryPointer - 1.03 1.02 1.04 1.03 1.00 GetProperty -100.41 1.51 1.00 1.00 198.76 Change graphics context - 45.81 1.00 0.99 0.97 57.10 Create and map subwindows (4 kids) - 78.45 1.01 1.02 1.02 63.07 Create and map subwindows (16 kids) - 73.91 1.01 1.00 1.00 56.37 Create and map subwindows (25 kids) - 73.22 1.00 1.00 1.00 49.07 Create and map subwindows (50 kids) - 72.36 1.01 0.99 1.00 32.14 Create and map subwindows (75 kids) - 70.34 1.00 1.00 1.00 30.12 Create and map subwindows (100 kids) - 55.00 1.00 1.00 0.99 23.75 Create and map subwindows (200 kids) - 55.30 1.01 1.00 1.00 141.03 Create unmapped window (4 kids) - 55.38 1.01 1.01 1.00 163.25 Create unmapped window (16 kids) - 54.75 0.96 1.00 0.99 166.95 Create unmapped window (25 kids) - 54.83 1.00 1.00 0.99 178.81 Create unmapped window (50 kids) - 55.38 1.01 1.01 1.00 181.20 Create unmapped window (75 kids) - 55.38 1.01 1.01 1.00 181.20 Create unmapped window (100 kids) - 54.87 1.01 1.01 1.00 182.05 Create unmapped window (200 kids) - 28.13 1.00 1.00 1.00 30.75 Map window via parent (4 kids) - 36.14 1.01 1.01 1.01 32.58 Map window via parent (16 kids) - 26.13 1.00 0.98 0.95 29.85 Map window via parent (25 kids) - 40.07 1.00 1.01 1.00 27.57 Map window via parent (50 kids) - 23.26 0.99 1.00 1.00 18.23 Map window via parent (75 kids) - 22.91 0.99 1.00 0.99 16.52 Map window via parent (100 kids) - 27.79 1.00 1.00 0.99 12.50 Map window via parent (200 kids) - 22.35 1.00 1.00 1.00 56.19 Unmap window via parent (4 kids) - 9.57 1.00 0.99 1.00 89.78 Unmap window via parent (16 kids) - 80.77 1.01 1.00 1.00 103.85 Unmap window via parent (25 kids) - 96.34 1.00 1.00 1.00 116.06 Unmap window via parent (50 kids) - 99.72 1.00 1.00 1.00 124.93 Unmap window via parent (75 kids) -112.36 1.00 1.00 1.00 125.27 Unmap window via parent (100 kids) -105.41 1.00 1.00 0.99 120.00 Unmap window via parent (200 kids) - 51.29 1.03 1.02 1.02 74.19 Destroy window via parent (4 kids) - 86.75 0.99 0.99 0.99 116.87 Destroy window via parent (16 kids) -106.43 1.01 1.01 1.01 127.49 Destroy window via parent (25 kids) -120.34 1.01 1.01 1.00 140.11 Destroy window via parent (50 kids) -126.67 1.00 0.99 0.99 145.00 Destroy window via parent (75 kids) -126.11 1.01 1.01 1.00 140.56 Destroy window via parent (100 kids) -128.57 1.01 1.00 1.00 137.91 Destroy window via parent (200 kids) - 16.04 0.88 1.00 1.00 20.36 Hide/expose window via popup (4 kids) - 19.04 1.01 1.00 1.00 23.48 Hide/expose window via popup (16 kids) - 19.22 1.00 1.00 1.00 20.44 Hide/expose window via popup (25 kids) - 17.41 1.00 0.91 0.97 17.68 Hide/expose window via popup (50 kids) - 17.29 1.01 1.00 1.01 17.07 Hide/expose window via popup (75 kids) - 16.74 1.00 1.00 1.00 16.17 Hide/expose window via popup (100 kids) - 10.30 1.00 1.00 1.00 10.51 Hide/expose window via popup (200 kids) - 16.48 1.01 1.00 1.00 26.05 Move window (4 kids) - 17.01 0.95 1.00 1.00 23.97 Move window (16 kids) - 16.95 1.00 1.00 1.00 22.90 Move window (25 kids) - 16.05 1.01 1.00 1.00 21.32 Move window (50 kids) - 15.58 1.00 0.98 0.98 19.44 Move window (75 kids) - 14.98 1.02 1.03 1.03 18.17 Move window (100 kids) - 10.90 1.01 1.01 1.00 12.68 Move window (200 kids) - 49.42 1.00 1.00 1.00 198.27 Moved unmapped window (4 kids) - 50.72 0.97 1.00 1.00 193.66 Moved unmapped window (16 kids) - 50.87 1.00 0.99 1.00 195.09 Moved unmapped window (25 kids) - 50.72 1.00 1.00 1.00 189.34 Moved unmapped window (50 kids) - 50.87 1.00 1.00 1.00 191.33 Moved unmapped window (75 kids) - 50.87 1.00 1.00 0.90 186.71 Moved unmapped window (100 kids) - 50.87 1.00 1.00 1.00 179.19 Moved unmapped window (200 kids) - 41.04 1.00 1.00 1.00 56.61 Move window via parent (4 kids) - 69.81 1.00 1.00 1.00 130.82 Move window via parent (16 kids) - 95.81 1.00 1.00 1.00 141.92 Move window via parent (25 kids) - 95.98 1.00 1.00 1.00 149.43 Move window via parent (50 kids) - 96.59 1.01 1.01 1.00 153.98 Move window via parent (75 kids) - 97.19 1.00 1.00 1.00 157.30 Move window via parent (100 kids) - 96.67 1.00 0.99 0.96 159.44 Move window via parent (200 kids) - 17.75 1.01 1.00 1.00 27.61 Resize window (4 kids) - 17.94 1.00 1.00 0.99 25.42 Resize window (16 kids) - 17.92 1.01 1.00 1.00 24.47 Resize window (25 kids) - 17.24 0.97 1.00 1.00 24.14 Resize window (50 kids) - 16.81 1.00 1.00 0.99 22.75 Resize window (75 kids) - 16.08 1.00 1.00 1.00 21.20 Resize window (100 kids) - 12.92 1.00 0.99 1.00 16.26 Resize window (200 kids) - 52.94 1.01 1.00 1.00 327.12 Resize unmapped window (4 kids) - 53.60 1.01 1.01 1.01 333.71 Resize unmapped window (16 kids) - 52.99 1.00 1.00 1.00 337.29 Resize unmapped window (25 kids) - 51.98 1.00 1.00 1.00 329.38 Resize unmapped window (50 kids) - 53.05 0.89 1.00 1.00 322.60 Resize unmapped window (75 kids) - 53.05 1.00 1.00 1.00 318.08 Resize unmapped window (100 kids) - 53.11 1.00 1.00 0.99 306.21 Resize unmapped window (200 kids) - 16.76 1.00 0.96 1.00 19.46 Circulate window (4 kids) - 17.24 1.00 1.00 0.97 16.24 Circulate window (16 kids) - 16.30 1.03 1.03 1.03 15.85 Circulate window (25 kids) - 13.45 1.00 1.00 1.00 14.90 Circulate window (50 kids) - 12.91 1.00 1.00 1.00 13.06 Circulate window (75 kids) - 11.30 0.98 1.00 1.00 11.03 Circulate window (100 kids) - 7.58 1.01 1.01 0.99 7.47 Circulate window (200 kids) - 1.01 1.01 0.98 1.00 0.95 Circulate Unmapped window (4 kids) - 1.07 1.07 1.01 1.07 1.02 Circulate Unmapped window (16 kids) - 1.04 1.09 1.06 1.05 0.97 Circulate Unmapped window (25 kids) - 1.04 1.23 1.20 1.18 1.05 Circulate Unmapped window (50 kids) - 1.18 1.53 1.19 1.45 1.24 Circulate Unmapped window (75 kids) - 1.08 1.02 1.01 1.74 1.01 Circulate Unmapped window (100 kids) - 1.01 1.12 0.98 0.91 0.97 Circulate Unmapped window (200 kids) - </verb> - -<sect2>Profiling with OProfile - -<p>OProfile (available from http://oprofile.sourceforge.net/) is a -system-wide profiler for Linux systems that uses processor-level -counters to collect sampling data. OProfile can provide information -that is similar to that provided by <tt/gprof/, but without the -necessity of recompiling the program with special instrumentation (i.e., -OProfile can collect statistical profiling information about optimized -programs). A test harness was developed to collect OProfile data for -each <tt/x11perf/ test individually. - -<p>Test runs were performed using the RETIRED_INSNS counter on the AMD -Athlon and the CPU_CLK_HALTED counter on the Intel Pentium III (with a -test configuration different from the one described above). We have -examined OProfile output and have compared it with <tt/gprof/ output. -This investigation has not produced results that yield performance -increases in <tt/x11perf/ numbers. - -<!-- -<sect3>Retired Instructions - -<p>The initial tests using OProfile were done using the RETIRED_INSNS -counter with DMX running on the dual-processor AMD Athlon machine - the -same test configuration that was described above and that was used for -other tests. The RETIRED_INSNS counter counts retired instructions and -showed drawing, text, copying, and image tests to be dominated (> -30%) by calls to Hash(), SecurityLookupIDByClass(), -SecurityLookupIDByType(), and StandardReadRequestFromClient(). Some of -these tests also executed significant instructions in -WaitForSomething(). - -<p>In contrast, the window tests executed significant -instructions in SecurityLookupIDByType(), Hash(), -StandardReadRequestFromClient(), but also executed significant -instructions in other routines, such as ConfigureWindow(). Some time -was spent looking at Hash() function, but optimizations in this routine -did not lead to a dramatic increase in <tt/x11perf/ performance. ---> - -<!-- -<sect3>Clock Cycles - -<p>Retired instructions can be misleading because Intel/AMD instructions -execute in variable amounts of time. The OProfile tests were repeated -using the Intel CPU_CLK_HALTED counter with DMX running on the second -back-end machine. Note that this is a different test configuration that -the one described above. However, these tests show the amount of time -(as measured in CPU cycles) that are spent in each routine. Because -<tt/x11perf/ was running on the first back-end machine and because -window optimizations were on, the load on the second back-end machine -was not significant. - -<p>Using CPU_CLK_HALTED, DMX showed simple drawing -tests spending more than 10% of their time in -StandardReadRequestFromClient(), with significant time (> 20% total) -spent in SecurityLookupIDByClass(), WaitForSomething(), and Dispatch(). -For these tests, < 5% of the time was spent in Hash(), which explains -why optimizing the Hash() routine did not impact <tt/x11perf/ results. - -<p>The trapezoid, text, scrolling, copying, and image tests were -dominated by time in ProcFillPoly(), PanoramiXFillPoly(), dmxFillPolygon(), -SecurityLookupIDByClass(), SecurityLookupIDByType(), and -StandardReadRequestFromClient(). Hash() time was generally above 5% but -less than 10% of total time. ---> - -<sect2>X Test Suite - -<p>The X Test Suite was run on the fully optimized DMX server using the -configuration described above. The following failures were noted: - <verb> -XListPixmapFormats: Test 1 [1] -XChangeWindowAttributes: Test 32 [1] -XCreateWindow: Test 30 [1] -XFreeColors: Test 4 [3] -XCopyArea: Test 13, 17, 21, 25, 30 [2] -XCopyPlane: Test 11, 15, 27, 31 [2] -XSetFontPath: Test 4 [1] -XChangeKeyboardControl: Test 9, 10 [1] - -[1] Previously documented errors expected from the Xinerama - implementation (see Phase I discussion). -[2] Newly noted errors that have been verified as expected - behavior of the Xinerama implementation. -[3] Newly noted error that has been verified as a Xinerama - implementation bug. - </verb> - -<!-- ============================================================ --> -<sect1>Phase III - -<p>During the third phase of development, support was provided for the -following extensions: SHAPE, RENDER, XKEYBOARD, XInput. - -<sect2>SHAPE - -<p>The SHAPE extension is supported. Test applications (e.g., xeyes and -oclock) and window managers that make use of the SHAPE extension will -work as expected. - -<sect2>RENDER - -<p>The RENDER extension is supported. The version included in the DMX -CVS tree is version 0.2, and this version is fully supported by Xdmx. -Applications using only version 0.2 functions will work correctly; -however, some apps that make use of functions from later versions do not -properly check the extension's major/minor version numbers. These apps -will fail with a Bad Implementation error when using post-version 0.2 -functions. This is expected behavior. When the DMX CVS tree is updated -to include newer versions of RENDER, support for these newer functions -will be added to the DMX X server. - -<sect2>XKEYBOARD - -<p>The XKEYBOARD extension is supported. If present on the back-end X -servers, the XKEYBOARD extension will be used to obtain information -about the type of the keyboard for initialization. Otherwise, the -keyboard will be initialized using defaults. Note that this departs -from older behavior: when Xdmx is compiled without XKEYBOARD support, -the map from the back-end X server will be preserved. With XKEYBOARD -support, the map is not preserved because better information and control -of the keyboard is available. - -<sect2>XInput - -<p>The XInput extension is supported. Any device can be used as a core -device and be used as an XInput extension device, with the exception of -core devices on the back-end servers. This limitation is present -because cursor handling on the back-end requires that the back-end -cursor sometimes track the Xdmx core cursor -- behavior that is -incompatible with using the back-end pointer as a non-core device. - -<p>Currently, back-end extension devices are not available as Xdmx -extension devices, but this limitation should be removed in the future. - -<p>To demonstrate the XInput extension, and to provide more examples for -low-level input device driver writers, USB device drivers have been -written for mice (usb-mou), keyboards (usb-kbd), and -non-mouse/non-keyboard USB devices (usb-oth). Please see the man page -for information on Linux kernel drivers that are required for using -these Xdmx drivers. - -<sect2>DPMS - -<p>The DPMS extension is exported but does not do anything at this time. - -<sect2>Other Extensions - -<p>The LBX, - SECURITY, - XC-APPGROUP, and - XFree86-Bigfont -extensions do not require any special Xdmx support and have been exported. - -<p>The - BIG-REQUESTS, - DEC-XTRAP, - DOUBLE-BUFFER, - Extended-Visual-Information, - FontCache, - GLX, - MIT-SCREEN-SAVER, - MIT-SHM, - MIT-SUNDRY-NONSTANDARD, - RECORD, - SECURITY, - SGI-GLX, - SYNC, - TOG-CUP, - X-Resource, - XC-MISC, - XFree86-DGA, - XFree86-DRI, - XFree86-Misc, - XFree86-VidModeExtension, and - XVideo -extensions are <it/not/ supported at this time, but will be evaluated -for inclusion in future DMX releases. <bf>See below for additional work -on extensions after Phase III.</bf> - -<sect1>Phase IV - -<sect2>Moving to XFree86 4.3.0 - -<p>For Phase IV, the recent release of XFree86 4.3.0 (27 February 2003) -was merged onto the dmx.sourceforge.net CVS trunk and all work is -proceeding using this tree. - -<sect2>Extensions - -<sect3>XC-MISC (supported) - -<p>XC-MISC is used internally by the X library to recycle XIDs from the -X server. This is important for long-running X server sessions. Xdmx -supports this extension. The X Test Suite passed and failed the exact -same tests before and after this extension was enabled. -<!-- Tested February/March 2003 --> - -<sect3>Extended-Visual-Information (supported) - -<p>The Extended-Visual-Information extension provides a method for an X -client to obtain detailed visual information. Xdmx supports this -extension. It was tested using the <tt>hw/dmx/examples/evi</tt> example -program. <bf/Note that this extension is not Xinerama-aware/ -- it will -return visual information for each screen even though Xinerama is -causing the X server to export a single logical screen. -<!-- Tested March 2003 --> - -<sect3>RES (supported) - -<p>The X-Resource extension provides a mechanism for a client to obtain -detailed information about the resources used by other clients. This -extension was tested with the <tt>hw/dmx/examples/res</tt> program. The -X Test Suite passed and failed the exact same tests before and after -this extension was enabled. -<!-- Tested March 2003 --> - -<sect3>BIG-REQUESTS (supported) - -<p>This extension enables the X11 protocol to handle requests longer -than 262140 bytes. The X Test Suite passed and failed the exact same -tests before and after this extension was enabled. -<!-- Tested March 2003 --> - -<sect3>XSYNC (supported) - -<p>This extension provides facilities for two different X clients to -synchronize their requests. This extension was minimally tested with -<tt/xdpyinfo/ and the X Test Suite passed and failed the exact same -tests before and after this extension was enabled. -<!-- Tested March 2003 --> - -<sect3>XTEST, RECORD, DEC-XTRAP (supported) and XTestExtension1 (not supported) - -<p>The XTEST and RECORD extension were developed by the X Consortium for -use in the X Test Suite and are supported as a standard in the X11R6 -tree. They are also supported in Xdmx. When X Test Suite tests that -make use of the XTEST extension are run, Xdmx passes and fails exactly -the same tests as does a standard XFree86 X server. When the -<tt/rcrdtest/ test (a part of the X Test Suite that verifies the RECORD -extension) is run, Xdmx passes and fails exactly the same tests as does -a standard XFree86 X server. <!-- Tested February/March 2003 --> - -<p>There are two older XTEST-like extensions: DEC-XTRAP and -XTestExtension1. The XTestExtension1 extension was developed for use by -the X Testing Consortium for use with a test suite that eventually -became (part of?) the X Test Suite. Unlike XTEST, which only allows -events to be sent to the server, the XTestExtension1 extension also -allowed events to be recorded (similar to the RECORD extension). The -second is the DEC-XTRAP extension that was developed by the Digital -Equipment Corporation. - -<p>The DEC-XTRAP extension is available from Xdmx and has been tested -with the <tt/xtrap*/ tools which are distributed as standard X11R6 -clients. <!-- Tested March 2003 --> - -<p>The XTestExtension1 is <em/not/ supported because it does not appear -to be used by any modern X clients (the few that support it also support -XTEST) and because there are no good methods available for testing that -it functions correctly (unlike XTEST and DEC-XTRAP, the code for -XTestExtension1 is not part of the standard X server source tree, so -additional testing is important). <!-- Tested March 2003 --> - -<p>Most of these extensions are documented in the X11R6 source tree. -Further, several original papers exist that this author was unable to -locate -- for completeness and historical interest, citations are -provide: -<descrip> -<tag/XRECORD/ Martha Zimet. Extending X For Recording. 8th Annual X -Technical Conference Boston, MA January 24-26, 1994. -<tag/DEC-XTRAP/ Dick Annicchiarico, Robert Chesler, Alan Jamison. XTrap -Architecture. Digital Equipment Corporation, July 1991. -<tag/XTestExtension1/ Larry Woestman. X11 Input Synthesis Extension -Proposal. Hewlett Packard, November 1991. -</descrip> - -<sect3>MIT-MISC (not supported) - -<p>The MIT-MISC extension is used to control a bug-compatibility flag -that provides compatibility with xterm programs from X11R1 and X11R2. -There does not appear to be a single client available that makes use of -this extension and there is not way to verify that it works correctly. -The Xdmx server does <em/not/ support MIT-MISC. - -<sect3>SCREENSAVER (not supported) - -<p>This extension provides special support for the X screen saver. It -was tested with beforelight, which appears to be the only client that -works with it. When Xinerama was not active, <tt/beforelight/ behaved -as expected. However, when Xinerama was active, <tt/beforelight/ did -not behave as expected. Further, when this extension is not active, -<tt/xscreensaver/ (a widely-used X screen saver program) did not behave -as expected. Since this extension is not Xinerama-aware and is not -commonly used with expected results by clients, we have left this -extension disabled at this time. - -<sect3>GLX (supported) - -<p>The GLX extension provides OpenGL and GLX windowing support. In -Xdmx, the extension is called glxProxy, and it is Xinerama aware. It -works by either feeding requests forward through Xdmx to each of the -back-end servers or handling them locally. All rendering requests are -handled on the back-end X servers. This code was donated to the DMX -project by SGI. For the X Test Suite results comparison, see below. - -<sect3>RENDER (supported) - -<p>The X Rendering Extension (RENDER) provides support for digital image -composition. Geometric and text rendering are supported. RENDER is -partially Xinerama-aware, with text and the most basic compositing -operator; however, its higher level primitives (triangles, triangle -strips, and triangle fans) are not yet Xinerama-aware. The RENDER -extension is still under development, and is currently at version 0.8. -Additional support will be required in DMX as more primitives and/or -requests are added to the extension. - -<p>There is currently no test suite for the X Rendering Extension; -however, there has been discussion of developing a test suite as the -extension matures. When that test suite becomes available, additional -testing can be performed with Xdmx. The X Test Suite passed and failed -the exact same tests before and after this extension was enabled. - -<sect3>Summary - -<!-- WARNING: this list is duplicated in the "Common X extension -support" section --> -<p>To summarize, the following extensions are currently supported: - BIG-REQUESTS, - DEC-XTRAP, - DMX, - DPMS, - Extended-Visual-Information, - GLX, - LBX, - RECORD, - RENDER, - SECURITY, - SHAPE, - SYNC, - X-Resource, - XC-APPGROUP, - XC-MISC, - XFree86-Bigfont, - XINERAMA, - XInputExtension, - XKEYBOARD, and - XTEST. - -<p>The following extensions are <em/not/ supported at this time: - DOUBLE-BUFFER, - FontCache, - MIT-SCREEN-SAVER, - MIT-SHM, - MIT-SUNDRY-NONSTANDARD, - TOG-CUP, - XFree86-DGA, - XFree86-Misc, - XFree86-VidModeExtension, - XTestExtensionExt1, and - XVideo. - -<sect2>Additional Testing with the X Test Suite - -<sect3>XFree86 without XTEST - -<p>After the release of XFree86 4.3.0, we retested the XFree86 X server -with and without using the XTEST extension. When the XTEST extension -was <em/not/ used for testing, the XFree86 4.3.0 server running on our -usual test system with a Radeon VE card reported unexpected failures in -the following tests: -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XGetDefault: Test 5 -XRebindKeysym: Test 1 -</verb> - -<sect3>XFree86 with XTEST - -<p>When using the XTEST extension, the XFree86 4.3.0 server reported the -following errors: -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XGetDefault: Test 5 -XRebindKeysym: Test 1 - -XAllowEvents: Tests 20, 21, 24 -XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 -XGrabKey: Test 8 -XSetPointerMapping: Test 3 -XUngrabButton: Test 4 -</verb> - -<p>While these errors may be important, they will probably be fixed -eventually in the XFree86 source tree. We are particularly interested -in demonstrating that the Xdmx server does not introduce additional -failures that are not known Xinerama failures. - -<sect3>Xdmx with XTEST, without Xinerama, without GLX - -<p>Without Xinerama, but using the XTEST extension, the following errors -were reported from Xdmx (note that these are the same as for the XFree86 -4.3.0, except that XGetDefault no longer fails): -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XRebindKeysym: Test 1 - -XAllowEvents: Tests 20, 21, 24 -XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 -XGrabKey: Test 8 -XSetPointerMapping: Test 3 -XUngrabButton: Test 4 -</verb> - -<sect3>Xdmx with XTEST, with Xinerama, without GLX - -<p>With Xinerama, using the XTEST extension, the following errors -were reported from Xdmx: -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XRebindKeysym: Test 1 - -XAllowEvents: Tests 20, 21, 24 -XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 -XGrabKey: Test 8 -XSetPointerMapping: Test 3 -XUngrabButton: Test 4 - -XCopyPlane: Tests 13, 22, 31 (well-known XTEST/Xinerama interaction issue) -XDrawLine: Test 67 -XDrawLines: Test 91 -XDrawSegments: Test 68 -</verb> -Note that the first two sets of errors are the same as for the XFree86 -4.3.0 server, and that the XCopyPlane error is a well-known error -resulting from an XTEST/Xinerama interaction when the request crosses a -screen boundary. The XDraw* errors are resolved when the tests are run -individually and they do not cross a screen boundary. We will -investigate these errors further to determine their cause. - -<sect3>Xdmx with XTEST, with Xinerama, with GLX - -<p>With GLX enabled, using the XTEST extension, the following errors -were reported from Xdmx (these results are from early during the Phase -IV development, but were confirmed with a late Phase IV snapshot): -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XRebindKeysym: Test 1 - -XAllowEvents: Tests 20, 21, 24 -XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 -XGrabKey: Test 8 -XSetPointerMapping: Test 3 -XUngrabButton: Test 4 - -XClearArea: Test 8 -XCopyArea: Tests 4, 5, 11, 14, 17, 23, 25, 27, 30 -XCopyPlane: Tests 6, 7, 10, 19, 22, 31 -XDrawArcs: Tests 89, 100, 102 -XDrawLine: Test 67 -XDrawSegments: Test 68 -</verb> -Note that the first two sets of errors are the same as for the XFree86 -4.3.0 server, and that the third set has different failures than when -Xdmx does not include GLX support. Since the GLX extension adds new -visuals to support GLX's visual configs and the X Test Suite runs tests -over the entire set of visuals, additional rendering tests were run and -presumably more of them crossed a screen boundary. This conclusion is -supported by the fact that nearly all of the rendering errors reported -are resolved when the tests are run individually and they do no cross a -screen boundary. - -<p>Further, when hardware rendering is disabled on the back-end displays, -many of the errors in the third set are eliminated, leaving only: -<verb> -XClearArea: Test 8 -XCopyArea: Test 4, 5, 11, 14, 17, 23, 25, 27, 30 -XCopyPlane: Test 6, 7, 10, 19, 22, 31 -</verb> - -<sect3>Conclusion - -<p>We conclude that all of the X Test Suite errors reported for Xdmx are -the result of errors in the back-end X server or the Xinerama -implementation. Further, all of these errors that can be reasonably -fixed at the Xdmx layer have been. (Where appropriate, we have -submitted patches to the XFree86 and Xinerama upstream maintainers.) - -<sect2>Dynamic Reconfiguration - -<p>During this development phase, dynamic reconfiguration support was -added to DMX. This support allows an application to change the position -and offset of a back-end server's screen. For example, if the -application would like to shift a screen slightly to the left, it could -query Xdmx for the screen's <x,y> position and then dynamically -reconfigure that screen to be at position <x+10,y>. When a screen -is dynamically reconfigured, input handling and a screen's root window -dimensions are adjusted as needed. These adjustments are transparent to -the user. - -<sect3>Dynamic reconfiguration extension - -<p>The application interface to DMX's dynamic reconfiguration is through -a function in the DMX extension library: -<verb> -Bool DMXReconfigureScreen(Display *dpy, int screen, int x, int y) -</verb> -where <it/dpy/ is DMX server's display, <it/screen/ is the number of the -screen to be reconfigured, and <it/x/ and <it/y/ are the new upper, -left-hand coordinates of the screen to be reconfigured. - -<p>The coordinates are not limited other than as required by the X -protocol, which limits all coordinates to a signed 16 bit number. In -addition, all coordinates within a screen must also be legal values. -Therefore, setting a screen's upper, left-hand coordinates such that the -right or bottom edges of the screen is greater than 32,767 is illegal. - -<sect3>Bounding box - -<p>When the Xdmx server is started, a bounding box is calculated from -the screens' layout given either on the command line or in the -configuration file. This bounding box is currently fixed for the -lifetime of the Xdmx server. - -<p>While it is possible to move a screen outside of the bounding box, it -is currently not possible to change the dimensions of the bounding box. -For example, it is possible to specify coordinates of <-100,-100> -for the upper, left-hand corner of the bounding box, which was -previously at coordinates <0,0>. As expected, the screen is moved -down and to the right; however, since the bounding box is fixed, the -left side and upper portions of the screen exposed by the -reconfiguration are no longer accessible on that screen. Those -inaccessible regions are filled with black. - -<p>This fixed bounding box limitation will be addressed in a future -development phase. - -<sect3>Sample applications - -<p>An example of where this extension is useful is in setting up a video -wall. It is not always possible to get everything perfectly aligned, -and sometimes the positions are changed (e.g., someone might bump into a -projector). Instead of physically moving projectors or monitors, it is -now possible to adjust the positions of the back-end server's screens -using the dynamic reconfiguration support in DMX. - -<p>Other applications, such as automatic setup and calibration tools, -can make use of dynamic reconfiguration to correct for projector -alignment problems, as long as the projectors are still arranged -rectilinearly. Horizontal and vertical keystone correction could be -applied to projectors to correct for non-rectilinear alignment problems; -however, this must be done external to Xdmx. - -<p>A sample test program is included in the DMX server's examples -directory to demonstrate the interface and how an application might use -dynamic reconfiguration. See <tt/dmxreconfig.c/ for details. - -<sect3>Additional notes - -<p>In the original development plan, Phase IV was primarily devoted to -adding OpenGL support to DMX; however, SGI became interested in the DMX -project and developed code to support OpenGL/GLX. This code was later -donated to the DMX project and integrated into the DMX code base, which -freed the DMX developers to concentrate on dynamic reconfiguration (as -described above). - -<sect2>Doxygen documentation - -<p>Doxygen is an open-source (GPL) documentation system for generating -browseable documentation from stylized comments in the source code. We -have placed all of the Xdmx server and DMX protocol source code files -under Doxygen so that comprehensive documentation for the Xdmx source -code is available in an easily browseable format. - -<sect2>Valgrind - -<p>Valgrind, an open-source (GPL) memory debugger for Linux, was used to -search for memory management errors. Several memory leaks were detected -and repaired. The following errors were not addressed: -<enum> - <item> - When the X11 transport layer sends a reply to the client, only - those fields that are required by the protocol are filled in -- - unused fields are left as uninitialized memory and are therefore - noted by valgrind. These instances are not errors and were not - repaired. - <item> - At each server generation, glxInitVisuals allocates memory that - is never freed. The amount of memory lost each generation - approximately equal to 128 bytes for each back-end visual. - Because the code involved is automatically generated, this bug - has not been fixed and will be referred to SGI. - <item> - At each server generation, dmxRealizeFont calls XLoadQueryFont, - which allocates a font structure that is not freed. - dmxUnrealizeFont can free the font structure for the first - screen, but cannot free it for the other screens since they are - already closed by the time dmxUnrealizeFont could free them. - The amount of memory lost each generation is approximately equal - to 80 bytes per font per back-end. When this bug is fixed in - the the X server's device-independent (dix) code, DMX will be - able to properly free the memory allocated by XLoadQueryFont. -</enum> - -<sect2>RATS - -<p>RATS (Rough Auditing Tool for Security) is an open-source (GPL) -security analysis tool that scans source code for common -security-related programming errors (e.g., buffer overflows and TOCTOU -races). RATS was used to audit all of the code in the hw/dmx directory -and all "High" notations were checked manually. The code was either -re-written to eliminate the warning, or a comment containing "RATS" was -inserted on the line to indicate that a human had checked the code. -Unrepaired warnings are as follows: -<enum> - <item> - Fixed-size buffers are used in many areas, but code has been - added to protect against buffer overflows (e.g., XmuSnprint). - The only instances that have not yet been fixed are in - config/xdmxconfig.c (which is not part of the Xdmx server) and - input/usb-common.c. - <item> - vprintf and vfprintf are used in the logging routines. In - general, all uses of these functions (e.g., dmxLog) provide a - constant format string from a trusted source, so the use is - relatively benign. - <item> - glxProxy/glxscreens.c uses getenv and strcat. The use of these - functions is safe and will remain safe as long as - ExtensionsString is longer then GLXServerExtensions (ensuring - this may not be ovious to the casual programmer, but this is in - automatically generated code, so we hope that the generator - enforces this constraint). -</enum> - - </article> - - <!-- Local Variables: --> - <!-- fill-column: 72 --> - <!-- End: --> +<!DOCTYPE linuxdoc PUBLIC "-//XFree86//DTD linuxdoc//EN"> + <article> + + <!-- Title information --> + <title>Distributed Multihead X design + <author>Kevin E. Martin, David H. Dawes, and Rickard E. Faith + <date>29 June 2004 (created 25 July 2001) + <abstract> + This document covers the motivation, background, design, and + implementation of the distributed multihead X (DMX) system. It + is a living document and describes the current design and + implementation details of the DMX system. As the project + progresses, this document will be continually updated to reflect + the changes in the code and/or design. <it>Copyright 2001 by VA + Linux Systems, Inc., Fremont, California. Copyright 2001-2004 + by Red Hat, Inc., Raleigh, North Carolina</it> + </abstract> + + <!-- Table of contents --> + <toc> + +<!-- Begin the document --> +<sect>Introduction + +<sect1>The Distributed Multihead X Server + +<p>Current Open Source multihead solutions are limited to a single +physical machine. A single X server controls multiple display devices, +which can be arranged as independent heads or unified into a single +desktop (with Xinerama). These solutions are limited to the number of +physical devices that can co-exist in a single machine (e.g., due to the +number of AGP/PCI slots available for graphics cards). Thus, large +tiled displays are not currently possible. The work described in this +paper will eliminate the requirement that the display devices reside in +the same physical machine. This will be accomplished by developing a +front-end proxy X server that will control multiple back-end X servers +that make up the large display. + +<p>The overall structure of the distributed multihead X (DMX) project is +as follows: A single front-end X server will act as a proxy to a set of +back-end X servers, which handle all of the visible rendering. X +clients will connect to the front-end server just as they normally would +to a regular X server. The front-end server will present an abstracted +view to the client of a single large display. This will ensure that all +standard X clients will continue to operate without modification +(limited, as always, by the visuals and extensions provided by the X +server). Clients that are DMX-aware will be able to use an extension to +obtain information about the back-end servers (e.g., for placement of +pop-up windows, window alignments by the window manager, etc.). + +<p>The architecture of the DMX server is divided into two main sections: +input (e.g., mouse and keyboard events) and output (e.g., rendering and +windowing requests). Each of these are describe briefly below, and the +rest of this design document will describe them in greater detail. + +<p>The DMX server can receive input from three general types of input +devices: "local" devices that are physically attached to the machine on +which DMX is running, "backend" devices that are physically attached to +one or more of the back-end X servers (and that generate events via the +X protocol stream from the backend), and "console" devices that can be +abstracted from any non-back-end X server. Backend and console devices +are treated differently because the pointer device on the back-end X +server also controls the location of the hardware X cursor. Full +support for XInput extension devices is provided. + +<p>Rendering requests will be accepted by the front-end server; however, +rendering to visible windows will be broken down as needed and sent to +the appropriate back-end server(s) via X11 library calls for actual +rendering. The basic framework will follow a Xnest-style approach. GC +state will be managed in the front-end server and sent to the +appropriate back-end server(s) as required. Pixmap rendering will (at +least initially) be handled by the front-end X server. Windowing +requests (e.g., ordering, mapping, moving, etc.) will handled in the +front-end server. If the request requires a visible change, the +windowing operation will be translated into requests for the appropriate +back-end server(s). Window state will be mirrored in the back-end +server(s) as needed. + +<sect1>Layout of Paper + +<p>The next section describes the general development plan that was +actually used for implementation. The final section discusses +outstanding issues at the conclusion of development. The first appendix +provides low-level technical detail that may be of interest to those +intimately familiar with the X server architecture. The final appendix +describes the four phases of development that were performed during the +first two years of development. + +<p>The final year of work was divided into 9 tasks that are not +described in specific sections of this document. The major tasks during +that time were the enhancement of the reconfiguration ability added in +Phase IV, addition of support for a dynamic number of back-end displays +(instead of a hard-coded limit), and the support for back-end display +and input removal and addition. This work is mentioned in this paper, +but is not covered in detail. + +<!-- ============================================================ --> +<sect>Development plan + +<p>This section describes the development plan from approximately June +2001 through July 2003. + +<sect1>Bootstrap code + +<p>To allow for rapid development of the DMX server by multiple +developers during the first development stage, the problem will be +broken down into three tasks: the overall DMX framework, back-end +rendering services and input device handling services. However, before +the work begins on these tasks, a simple framework that each developer +could use was implemented to bootstrap the development effort. This +framework renders to a single back-end server and provides dummy input +devices (i.e., the keyboard and mouse). The simple back-end rendering +service was implemented using the shadow framebuffer support currently +available in the XFree86 environment. + +<p>Using this bootstrapping framework, each developer has been able to +work on each of the tasks listed above independently as follows: the +framework will be extended to handle arbitrary back-end server +configurations; the back-end rendering services will be transitioned to +the more efficient Xnest-style implementation; and, an input device +framework to handle various input devices via the input extension will +be developed. + +<p>Status: The boot strap code is complete. <!-- August 2001 --> + + +<sect1>Input device handling + +<p>An X server (including the front-end X server) requires two core +input devices -- a keyboard and a pointer (mouse). These core devices +are handled and required by the core X11 protocol. Additional types of +input devices may be attached and utilized via the XInput extension. +These are usually referred to as ``XInput extension devices'', + +<p>There are some options as to how the front-end X server gets its core +input devices: + +<enum> + <item>Local Input. The physical input devices (e.g., keyboard and + mouse) can be attached directly to the front-end X server. In this + case, the keyboard and mouse on the machine running the front-end X + server will be used. The front-end will have drivers to read the + raw input from those devices and convert it into the required X + input events (e.g., key press/release, pointer button press/release, + pointer motion). The front-end keyboard driver will keep track of + keyboard properties such as key and modifier mappings, autorepeat + state, keyboard sound and led state. Similarly the front-end + pointer driver will keep track if pointer properties such as the + button mapping and movement acceleration parameters. With this + option, input is handled fully in the front-end X server, and the + back-end X servers are used in a display-only mode. This option was + implemented and works for a limited number of Linux-specific + devices. Adding additional local input devices for other + architectures is expected to be relatively simple. + + <p>The following options are available for implementing local input + devices: + + <enum> + <item>The XFree86 X server has modular input drivers that could + be adapted for this purpose. The mouse driver supports a wide + range of mouse types and interfaces, as well as a range of + Operating System platforms. The keyboard driver in XFree86 is + not currently as modular as the mouse driver, but could be made + so. The XFree86 X server also has a range of other input + drivers for extended input devices such as tablets and touch + screens. Unfortunately, the XFree86 drivers are generally + complex, often simultaneously providing support for multiple + devices across multiple architectures; and rely so heavily on + XFree86-specific helper-functions, that this option was not + pursued. + + + <item>The <tt/kdrive/ X server in XFree86 has built-in drivers that + support PS/2 mice and keyboard under Linux. The mouse driver + can indirectly handle other mouse types if the Linux utility + <tt/gpm/ is used as to translate the native mouse protocol into + PS/2 mouse format. These drivers could be adapted and built in + to the front-end X server if this range of hardware and OS + support is sufficient. While much simpler than the XFree86 + drivers, the <tt/kdrive/ drivers were not used for the DMX + implementation. + + <item>Reimplementation of keyboard and mouse drivers from + scratch for the DMX framework. Because keyboard and mouse + drivers are relatively trivial to implement, this pathway was + selected. Other drivers in the X source tree were referenced, + and significant contributions from other drivers are noted in + the DMX source code. + </enum> + + <item>Backend Input. The front-end can make use of the core input + devices attached to one or more of the back-end X servers. Core + input events from multiple back-ends are merged into a single input + event stream. This can work sanely when only a single set of input + devices is used at any given time. The keyboard and pointer state + will be handled in the front-end, with changes propagated to the + back-end servers as needed. This option was implemented and works + well. Because the core pointer on a back-end controls the hardware + mouse on that back-end, core pointers cannot be treated as XInput + extension devices. However, all back-end XInput extensions devices + can be mapped to either DMX core or DMX XInput extension devices. + + <item>Console Input. The front-end server could create a console + window that is displayed on an X server independent of the back-end + X servers. This console window could display things like the + physical screen layout, and the front-end could get its core input + events from events delivered to the console window. This option was + implemented and works well. To help the human navigate, window + outlines are also displayed in the console window. Further, console + windows can be used as either core or XInput extension devices. + + <item>Other options were initially explored, but they were all + partial subsets of the options listed above and, hence, are + irrelevant. + +</enum> + +<p>Although extended input devices are not specifically mentioned in the +Distributed X requirements, the options above were all implemented so +that XInput extension devices were supported. + +<p>The bootstrap code (Xdmx) had dummy input devices, and these are +still supported in the final version. These do the necessary +initialization to satisfy the X server's requirements for core pointer +and keyboard devices, but no input events are ever generated. + +<p>Status: The input code is complete. Because of the complexity of the +XFree86 input device drivers (and their heavy reliance on XFree86 +infrastructure), separate low-level device drivers were implemented for +Xdmx. The following kinds of drivers are supported (in general, the +devices can be treated arbitrarily as "core" input devices or as XInput +"extension" devices; and multiple instances of different kinds of +devices can be simultaneously available): + <enum> + <item> A "dummy" device drive that never generates events. + + <item> "Local" input is from the low-level hardware on which the + Xdmx binary is running. This is the only area where using the + XFree86 driver infrastructure would have been helpful, and then + only partially, since good support for generic USB devices does + not yet exist in XFree86 (in any case, XFree86 and kdrive driver + code was used where possible). Currently, the following local + devices are supported under Linux (porting to other operating + systems should be fairly straightforward): + <itemize> + <item>Linux keyboard + <item>Linux serial mouse (MS) + <item>Linux PS/2 mouse + <item>USB keyboard + <item>USB mouse + <item>USB generic device (e.g., joystick, gamepad, etc.) + </itemize> + + <item> "Backend" input is taken from one or more of the back-end + displays. In this case, events are taken from the back-end X + server and are converted to Xdmx events. Care must be taken so + that the sprite moves properly on the display from which input + is being taken. + + <item> "Console" input is taken from an X window that Xdmx + creates on the operator's display (i.e., on the machine running + the Xdmx binary). When the operator's mouse is inside the + console window, then those events are converted to Xdmx events. + Several special features are available: the console can display + outlines of windows that are on the Xdmx display (to facilitate + navigation), the cursor can be confined to the console, and a + "fine" mode can be activated to allow very precise cursor + positioning. + </enum> + + +<!-- May 2002; July 2003 --> + +<sect1>Output device handling + +<p>The output of the DMX system displays rendering and windowing +requests across multiple screens. The screens are typically arranged in +a grid such that together they represent a single large display. + +<p>The output section of the DMX code consists of two parts. The first +is in the front-end proxy X server (Xdmx), which accepts client +connections, manages the windows, and potentially renders primitives but +does not actually display any of the drawing primitives. The second +part is the back-end X server(s), which accept commands from the +front-end server and display the results on their screens. + +<sect2>Initialization + +<p>The DMX front-end must first initialize its screens by connecting to +each of the back-end X servers and collecting information about each of +these screens. However, the information collected from the back-end X +servers might be inconsistent. Handling these cases can be difficult +and/or inefficient. For example, a two screen system has one back-end X +server running at 16bpp while the second is running at 32bpp. +Converting rendering requests (e.g., XPutImage() or XGetImage() +requests) to the appropriate bit depth can be very time consuming. +Analyzing these cases to determine how or even if it is possible to +handle them is required. The current Xinerama code handles many of +these cases (e.g., in PanoramiXConsolidate()) and will be used as a +starting point. In general, the best solution is to use homogeneous X +servers and display devices. Using back-end servers with the same depth +is a requirement of the final DMX implementation. + +<p>Once this screen consolidation is finished, the relative position of +each back-end X server's screen in the unified screen is initialized. A +full-screen window is opened on each of the back-end X servers, and the +cursor on each screen is turned off. The final DMX implementation can +also make use of a partial-screen window, or multiple windows per +back-end screen. + +<sect2>Handling rendering requests + +<p>After initialization, X applications connect to the front-end server. +There are two possible implementations of how rendering and windowing +requests are handled in the DMX system: + +<enum> + <item>A shadow framebuffer is used in the front-end server as the + render target. In this option, all protocol requests are completely + handled in the front-end server. All state and resources are + maintained in the front-end including a shadow copy of the entire + framebuffer. The framebuffers attached to the back-end servers are + updated by XPutImage() calls with data taken directly from the + shadow framebuffer. + + <p>This solution suffers from two main problems. First, it does not + take advantage of any accelerated hardware available in the system. + Second, the size of the XPutImage() calls can be quite large and + thus will be limited by the bandwidth available. + + <p>The initial DMX implementation used a shadow framebuffer by + default. + + <item>Rendering requests are sent to each back-end server for + handling (as is done in the Xnest server described above). In this + option, certain protocol requests are handled in the front-end + server and certain requests are repackaged and then sent to the + back-end servers. The framebuffer is distributed across the + multiple back-end servers. Rendering to the framebuffer is handled + on each back-end and can take advantage of any acceleration + available on the back-end servers' graphics display device. State + is maintained both in the front and back-end servers. + + <p>This solution suffers from two main drawbacks. First, protocol + requests are sent to all back-end servers -- even those that will + completely clip the rendering primitive -- which wastes bandwidth + and processing time. Second, state is maintained both in the front- + and back-end servers. These drawbacks are not as severe as in + option 1 (above) and can either be overcome through optimizations or + are acceptable. Therefore, this option will be used in the final + implementation. + + <p>The final DMX implementation defaults to this mechanism, but also + supports the shadow framebuffer mechanism. Several optimizations + were implemented to eliminate the drawbacks of the default + mechanism. These optimizations are described the section below and + in Phase II of the Development Results (see appendix). + +</enum> + +<p>Status: Both the shadow framebuffer and Xnest-style code is complete. +<!-- May 2002 --> + + +<sect1>Optimizing DMX + +<p>Initially, the Xnest-style solution's performance will be measured +and analyzed to determine where the performance bottlenecks exist. +There are four main areas that will be addressed. + +<p>First, to obtain reasonable interactivity with the first development +phase, XSync() was called after each protocol request. The XSync() +function flushes any pending protocol requests. It then waits for the +back-end to process the request and send a reply that the request has +completed. This happens with each back-end server and performance +greatly suffers. As a result of the way XSync() is called in the first +development phase, the batching that the X11 library performs is +effectively defeated. The XSync() call usage will be analyzed and +optimized by batching calls and performing them at regular intervals, +except where interactivity will suffer (e.g., on cursor movements). + +<p>Second, the initial Xnest-style solution described above sends the +repackaged protocol requests to all back-end servers regardless of +whether or not they would be completely clipped out. The requests that +are trivially rejected on the back-end server wastes the limited +bandwidth available. By tracking clipping changes in the DMX X server's +windowing code (e.g., by opening, closing, moving or resizing windows), +we can determine whether or not back-end windows are visible so that +trivial tests in the front-end server's GC ops drawing functions can +eliminate these unnecessary protocol requests. + +<p>Third, each protocol request will be analyzed to determine if it is +possible to break the request into smaller pieces at display boundaries. +The initial ones to be analyzed are put and get image requests since +they will require the greatest bandwidth to transmit data between the +front and back-end servers. Other protocol requests will be analyzed +and those that will benefit from breaking them into smaller requests +will be implemented. + +<p>Fourth, an extension is being considered that will allow font glyphs to +be transferred from the front-end DMX X server to each back-end server. +This extension will permit the front-end to handle all font requests and +eliminate the requirement that all back-end X servers share the exact +same fonts as the front-end server. We are investigating the +feasibility of this extension during this development phase. + +<p>Other potential optimizations will be determined from the performance +analysis. + +<p>Please note that in our initial design, we proposed optimizing BLT +operations (e.g., XCopyArea() and window moves) by developing an +extension that would allow individual back-end servers to directly copy +pixel data to other back-end servers. This potential optimization was +in response to the simple image movement implementation that required +potentially many calls to GetImage() and PutImage(). However, the +current Xinerama implementation handles these BLT operations +differently. Instead of copying data to and from screens, they generate +expose events -- just as happens in the case when a window is moved from +off a screen to on screen. This approach saves the limited bandwidth +available between front and back-end servers and is being standardized +with Xinerama. It also eliminates the potential setup problems and +security issues resulting from having each back-end server open +connections to all other back-end servers. Therefore, we suggest +accepting Xinerama's expose event solution. + +<p>Also note that the approach proposed in the second and third +optimizations might cause backing store algorithms in the back-end to be +defeated, so a DMX X server configuration flag will be added to disable +these optimizations. + +<p>Status: The optimizations proposed above are complete. It was +determined that the using the xfs font server was sufficient and +creating a new mechanism to pass glyphs was redundant; therefore, the +fourth optimization proposed above was not included in DMX. +<!-- September 2002 --> + + +<sect1>DMX X extension support + +<p>The DMX X server keeps track of all the windowing information on the +back-end X servers, but does not currently export this information to +any client applications. An extension will be developed to pass the +screen information and back-end window IDs to DMX-aware clients. These +clients can then use this information to directly connect to and render +to the back-end windows. Bypassing the DMX X server allows DMX-aware +clients to break up complex rendering requests on their own and send +them directly to the windows on the back-end server's screens. An +example of a client that can make effective use of this extension is +Chromium. + +<p>Status: The extension, as implemented, is fully documented in +"Client-to-Server DMX Extension to the X Protocol". Future changes +might be required based on feedback and other proposed enhancements to +DMX. Currently, the following facilities are supported: +<enum> + <item> + Screen information (clipping rectangle for each screen relative + to the virtual screen) + <item> + Window information (window IDs and clipping information for each + back-end window that corresponds to each DMX window) + <item> + Input device information (mappings from DMX device IDs to + back-end device IDs) + <item> + Force window creation (so that a client can override the + server-side lazy window creation optimization) + <item> + Reconfiguration (so that a client can request that a screen + position be changed) + <item> + Addition and removal of back-end servers and back-end and + console inputs. +</enum> +<!-- September 2002; July 2003 --> + + +<sect1>Common X extension support + +<p>The XInput, XKeyboard and Shape extensions are commonly used +extensions to the base X11 protocol. XInput allows multiple and +non-standard input devices to be accessed simultaneously. These input +devices can be connected to either the front-end or back-end servers. +XKeyboard allows much better keyboard mappings control. Shape adds +support for arbitrarily shaped windows and is used by various window +managers. Nearly all potential back-end X servers make these extensions +available, and support for each one will be added to the DMX system. + +<p>In addition to the extensions listed above, support for the X +Rendering extension (Render) is being developed. Render adds digital +image composition to the rendering model used by the X Window System. +While this extension is still under development by Keith Packard of HP, +support for the current version will be added to the DMX system. + +<p>Support for the XTest extension was added during the first +development phase. + +<!-- WARNING: this list is duplicated in the Phase IV discussion --> +<p>Status: The following extensions are supported and are discussed in +more detail in Phase IV of the Development Results (see appendix): + BIG-REQUESTS, + DEC-XTRAP, + DMX, + DPMS, + Extended-Visual-Information, + GLX, + LBX, + RECORD, + RENDER, + SECURITY, + SHAPE, + SYNC, + X-Resource, + XC-APPGROUP, + XC-MISC, + XFree86-Bigfont, + XINERAMA, + XInputExtension, + XKEYBOARD, and + XTEST. +<!-- November 2002; updated February 2003, July 2003 --> + +<sect1>OpenGL support + +<p>OpenGL support using the Mesa code base exists in XFree86 release 4 +and later. Currently, the direct rendering infrastructure (DRI) +provides accelerated OpenGL support for local clients and unaccelerated +OpenGL support (i.e., software rendering) is provided for non-local +clients. + +<p>The single head OpenGL support in XFree86 4.x will be extended to use +the DMX system. When the front and back-end servers are on the same +physical hardware, it is possible to use the DRI to directly render to +the back-end servers. First, the existing DRI will be extended to +support multiple display heads, and then to support the DMX system. +OpenGL rendering requests will be direct rendering to each back-end X +server. The DRI will request the screen layout (either from the +existing Xinerama extension or a DMX-specific extension). Support for +synchronized swap buffers will also be added (on hardware that supports +it). Note that a single front-end server with a single back-end server +on the same physical machine can emulate accelerated indirect rendering. + +<p>When the front and back-end servers are on different physical +hardware or are using non-XFree86 4.x X servers, a mechanism to render +primitives across the back-end servers will be provided. There are +several options as to how this can be implemented. + +<enum> + <item>The existing OpenGL support in each back-end server can be + used by repackaging rendering primitives and sending them to each + back-end server. This option is similar to the unoptimized + Xnest-style approach mentioned above. Optimization of this solution + is beyond the scope of this project and is better suited to other + distributed rendering systems. + + <item>Rendering to a pixmap in the front-end server using the + current XFree86 4.x code, and then displaying to the back-ends via + calls to XPutImage() is another option. This option is similar to + the shadow frame buffer approach mentioned above. It is slower and + bandwidth intensive, but has the advantage that the back-end servers + are not required to have OpenGL support. +</enum> + +<p>These, and other, options will be investigated in this phase of the +work. + +<p>Work by others have made Chromium DMX-aware. Chromium will use the +DMX X protocol extension to obtain information about the back-end +servers and will render directly to those servers, bypassing DMX. + +<p>Status: OpenGL support by the glxProxy extension was implemented by +SGI and has been integrated into the DMX code base. +<!-- May 2003--> + + +<!-- ============================================================ --> +<sect>Current issues + +<p>In this sections the current issues are outlined that require further +investigation. + +<sect1>Fonts + +<p>The font path and glyphs need to be the same for the front-end and +each of the back-end servers. Font glyphs could be sent to the back-end +servers as necessary but this would consume a significant amount of +available bandwidth during font rendering for clients that use many +different fonts (e.g., Netscape). Initially, the font server (xfs) will +be used to provide the fonts to both the front-end and back-end servers. +Other possibilities will be investigated during development. + +<sect1>Zero width rendering primitives + +<p>To allow pixmap and on-screen rendering to be pixel perfect, all +back-end servers must render zero width primitives exactly the same as +the front-end renders the primitives to pixmaps. For those back-end +servers that do not exactly match, zero width primitives will be +automatically converted to one width primitives. This can be handled in +the front-end server via the GC state. + +<sect1>Output scaling + +<p>With very large tiled displays, it might be difficult to read the +information on the standard X desktop. In particular, the cursor can be +easily lost and fonts could be difficult to read. Automatic primitive +scaling might prove to be very useful. We will investigate the +possibility of scaling the cursor and providing a set of alternate +pre-scaled fonts to replace the standard fonts that many applications +use (e.g., fixed). Other options for automatic scaling will also be +investigated. + +<sect1>Per-screen colormaps + +<p>Each screen's default colormap in the set of back-end X servers +should be able to be adjusted via a configuration utility. This support +is would allow the back-end screens to be calibrated via custom gamma +tables. On 24-bit systems that support a DirectColor visual, this type +of correction can be accommodated. One possible implementation would be +to advertise to X client of the DMX server a TrueColor visual while +using DirectColor visuals on the back-end servers to implement this type +of color correction. Other options will be investigated. + +<!-- ============================================================ --> +<appendix> + +<sect>Background + +<p>This section describes the existing Open Source architectures that +can be used to handle multiple screens and upon which this development +project is based. This section was written before the implementation +was finished, and may not reflect actual details of the implementation. +It is left for historical interest only. + +<sect1>Core input device handling + +<p>The following is a description of how core input devices are handled +by an X server. + +<sect2>InitInput() + +<p>InitInput() is a DDX function that is called at the start of each +server generation from the X server's main() function. Its purpose is +to determine what input devices are connected to the X server, register +them with the DIX and MI layers, and initialize the input event queue. +InitInput() does not have a return value, but the X server will abort if +either a core keyboard device or a core pointer device are not +registered. Extended input (XInput) devices can also be registered in +InitInput(). + +<p>InitInput() usually has implementation specific code to determine +which input devices are available. For each input device it will be +using, it calls AddInputDevice(): + +<descrip> +<tag/AddInputDevice()/ This DIX function allocates the device structure, +registers a callback function (which handles device init, close, on and +off), and returns the input handle, which can be treated as opaque. It +is called once for each input device. +</descrip> + +<p>Once input handles for core keyboard and core pointer devices have +been obtained from AddInputDevice(), they are registered as core devices +by calling RegisterPointerDevice() and RegisterKeyboardDevice(). Each +of these should be called once. If both core devices are not +registered, then the X server will exit with a fatal error when it +attempts to start the input devices in InitAndStartDevices(), which is +called directly after InitInput() (see below). + +<descrip> +<tag/Register{Pointer,Keyboard}Device()/ These DIX functions take a +handle returned from AddInputDevice() and initialize the core input +device fields in inputInfo, and initialize the input processing and grab +functions for each core input device. +</descrip> + +<p>The core pointer device is then registered with the miPointer code +(which does the high level cursor handling). While this registration +is not necessary for correct miPointer operation in the current XFree86 +code, it is still done mostly for compatibility reasons. + +<descrip> +<tag/miRegisterPointerDevice()/ This MI function registers the core +pointer's input handle with with the miPointer code. +</descrip> + +<p>The final part of InitInput() is the initialization of the input +event queue handling. In most cases, the event queue handling provided +in the MI layer is used. The primary XFree86 X server uses its own +event queue handling to support some special cases related to the XInput +extension and the XFree86-specific DGA extension. For our purposes, the +MI event queue handling should be suitable. It is initialized by +calling mieqInit(): + +<descrip> +<tag/mieqInit()/ This MI function initializes the MI event queue for the +core devices, and is passed the public component of the input handles +for the two core devices. +</descrip> + +<p>If a wakeup handler is required to deliver synchronous input +events, it can be registered here by calling the DIX function +RegisterBlockAndWakeupHandlers(). (See the devReadInput() description +below.) + +<sect2>InitAndStartDevices() + +<p>InitAndStartDevices() is a DIX function that is called immediately +after InitInput() from the X server's main() function. Its purpose is +to initialize each input device that was registered with +AddInputDevice(), enable each input device that was successfully +initialized, and create the list of enabled input devices. Once each +registered device is processed in this way, the list of enabled input +devices is checked to make sure that both a core keyboard device and +core pointer device were registered and successfully enabled. If not, +InitAndStartDevices() returns failure, and results in the the X server +exiting with a fatal error. + +<p>Each registered device is initialized by calling its callback +(dev->deviceProc) with the DEVICE_INIT argument: + +<descrip> +<tag/(*dev->deviceProc)(dev, DEVICE_INIT)/ This function initializes the +device structs with core information relevant to the device. + +<p>For pointer devices, this means specifying the number of buttons, +default button mapping, the function used to get motion events (usually +miPointerGetMotionEvents()), the function used to change/control the +core pointer motion parameters (acceleration and threshold), and the +motion buffer size. + +<p>For keyboard devices, this means specifying the keycode range, +default keycode to keysym mapping, default modifier mapping, and the +functions used to sound the keyboard bell and modify/control the +keyboard parameters (LEDs, bell pitch and duration, key click, which +keys are auto-repeating, etc). +</descrip> + +<p>Each initialized device is enabled by calling EnableDevice(): + +<descrip> +<tag/EnableDevice()/ EnableDevice() calls the device callback with +DEVICE_ON: + <descrip> + <tag/(*dev->deviceProc)(dev, DEVICE_ON)/ This typically opens and + initializes the relevant physical device, and when appropriate, + registers the device's file descriptor (or equivalent) as a valid + input source. + </descrip> + + <p>EnableDevice() then adds the device handle to the X server's + global list of enabled devices. +</descrip> + +<p>InitAndStartDevices() then verifies that a valid core keyboard and +pointer has been initialized and enabled. It returns failure if either +are missing. + +<sect2>devReadInput() + +<p>Each device will have some function that gets called to read its +physical input. These may be called in a number of different ways. In +the case of synchronous I/O, they will be called from a DDX +wakeup-handler that gets called after the server detects that new input is +available. In the case of asynchronous I/O, they will be called from a +(SIGIO) signal handler triggered when new input is available. This +function should do at least two things: make sure that input events get +enqueued, and make sure that the cursor gets moved for motion events +(except if these are handled later by the driver's own event queue +processing function, which cannot be done when using the MI event queue +handling). + +<p>Events are queued by calling mieqEnqueue(): + +<descrip> +<tag/mieqEnqueue()/ This MI function is used to add input events to the +event queue. It is simply passed the event to be queued. +</descrip> + +<p>The cursor position should be updated when motion events are +enqueued, by calling either miPointerAbsoluteCursor() or +miPointerDeltaCursor(): + +<descrip> +<tag/miPointerAbsoluteCursor()/ This MI function is used to move the +cursor to the absolute coordinates provided. +<tag/miPointerDeltaCursor()/ This MI function is used to move the cursor +relative to its current position. +</descrip> + +<sect2>ProcessInputEvents() + +<p>ProcessInputEvents() is a DDX function that is called from the X +server's main dispatch loop when new events are available in the input +event queue. It typically processes the enqueued events, and updates +the cursor/pointer position. It may also do other DDX-specific event +processing. + +<p>Enqueued events are processed by mieqProcessInputEvents() and passed +to the DIX layer for transmission to clients: + +<descrip> +<tag/mieqProcessInputEvents()/ This function processes each event in the +event queue, and passes it to the device's input processing function. +The DIX layer provides default functions to do this processing, and they +handle the task of getting the events passed back to the relevant +clients. +<tag/miPointerUpdate()/ This function resynchronized the cursor position +with the new pointer position. It also takes care of moving the cursor +between screens when needed in multi-head configurations. +</descrip> + + +<sect2>DisableDevice() + +<p>DisableDevice is a DIX function that removes an input device from the +list of enabled devices. The result of this is that the device no +longer generates input events. The device's data structures are kept in +place, and disabling a device like this can be reversed by calling +EnableDevice(). DisableDevice() may be called from the DDX when it is +desirable to do so (e.g., the XFree86 server does this when VT +switching). Except for special cases, this is not normally called for +core input devices. + +<p>DisableDevice() calls the device's callback function with +<tt/DEVICE_OFF/: + +<descrip> +<tag/(*dev->deviceProc)(dev, DEVICE_OFF)/ This typically closes the +relevant physical device, and when appropriate, unregisters the device's +file descriptor (or equivalent) as a valid input source. +</descrip> + +<p>DisableDevice() then removes the device handle from the X server's +global list of enabled devices. + + +<sect2>CloseDevice() + +<p>CloseDevice is a DIX function that removes an input device from the +list of available devices. It disables input from the device and frees +all data structures associated with the device. This function is +usually called from CloseDownDevices(), which is called from main() at +the end of each server generation to close all input devices. + +<p>CloseDevice() calls the device's callback function with +<tt/DEVICE_CLOSE/: + +<descrip> +<tag/(*dev->deviceProc)(dev, DEVICE_CLOSE)/ This typically closes the +relevant physical device, and when appropriate, unregisters the device's +file descriptor (or equivalent) as a valid input source. If any device +specific data structures were allocated when the device was initialized, +they are freed here. +</descrip> + +<p>CloseDevice() then frees the data structures that were allocated +for the device when it was registered/initialized. + + +<sect2>LegalModifier() +<!-- dmx/dmxinput.c - currently returns TRUE --> +<p>LegalModifier() is a required DDX function that can be used to +restrict which keys may be modifier keys. This seems to be present for +historical reasons, so this function should simply return TRUE +unconditionally. + + +<sect1>Output handling + +<p>The following sections describe the main functions required to +initialize, use and close the output device(s) for each screen in the X +server. + +<sect2>InitOutput() + +<p>This DDX function is called near the start of each server generation +from the X server's main() function. InitOutput()'s main purpose is to +initialize each screen and fill in the global screenInfo structure for +each screen. It is passed three arguments: a pointer to the screenInfo +struct, which it is to initialize, and argc and argv from main(), which +can be used to determine additional configuration information. + +<p>The primary tasks for this function are outlined below: + +<enum> + <item><bf/Parse configuration info:/ The first task of InitOutput() + is to parses any configuration information from the configuration + file. In addition to the XF86Config file, other configuration + information can be taken from the command line. The command line + options can be gathered either in InitOutput() or earlier in the + ddxProcessArgument() function, which is called by + ProcessCommandLine(). The configuration information determines the + characteristics of the screen(s). For example, in the XFree86 X + server, the XF86Config file specifies the monitor information, the + screen resolution, the graphics devices and slots in which they are + located, and, for Xinerama, the screens' layout. + + <item><bf/Initialize screen info:/ The next task is to initialize + the screen-dependent internal data structures. For example, part of + what the XFree86 X server does is to allocate its screen and pixmap + private indices, probe for graphics devices, compare the probed + devices to the ones listed in the XF86Config file, and add the ones that + match to the internal xf86Screens[] structure. + + <item><bf/Set pixmap formats:/ The next task is to initialize the + screenInfo's image byte order, bitmap bit order and bitmap scanline + unit/pad. The screenInfo's pixmap format's depth, bits per pixel + and scanline padding is also initialized at this stage. + + <item><bf/Unify screen info:/ An optional task that might be done at + this stage is to compare all of the information from the various + screens and determines if they are compatible (i.e., if the set of + screens can be unified into a single desktop). This task has + potential to be useful to the DMX front-end server, if Xinerama's + PanoramiXConsolidate() function is not sufficient. +</enum> + +<p>Once these tasks are complete, the valid screens are known and each +of these screens can be initialized by calling AddScreen(). + +<sect2>AddScreen() + +<p>This DIX function is called from InitOutput(), in the DDX layer, to +add each new screen to the screenInfo structure. The DDX screen +initialization function and command line arguments (i.e., argc and argv) +are passed to it as arguments. + +<p>This function first allocates a new Screen structure and any privates +that are required. It then initializes some of the fields in the Screen +struct and sets up the pixmap padding information. Finally, it calls +the DDX screen initialization function ScreenInit(), which is described +below. It returns the number of the screen that were just added, or -1 +if there is insufficient memory to add the screen or if the DDX screen +initialization fails. + +<sect2>ScreenInit() + +<p>This DDX function initializes the rest of the Screen structure with +either generic or screen-specific functions (as necessary). It also +fills in various screen attributes (e.g., width and height in +millimeters, black and white pixel values). + +<p>The screen init function usually calls several functions to perform +certain screen initialization functions. They are described below: + +<descrip> +<tag/{mi,*fb}ScreenInit()/ The DDX layer's ScreenInit() function usually +calls another layer's ScreenInit() function (e.g., miScreenInit() or +fbScreenInit()) to initialize the fallbacks that the DDX driver does not +specifically handle. + +<p>After calling another layer's ScreenInit() function, any +screen-specific functions either wrap or replace the other layer's +function pointers. If a function is to be wrapped, each of the old +function pointers from the other layer are stored in a screen private +area. Common functions to wrap are CloseScreen() and SaveScreen(). + +<tag/miInitializeBackingStore()/ This MI function initializes the +screen's backing storage functions, which are used to save areas of +windows that are currently covered by other windows. + +<tag/miDCInitialize()/ This MI function initializes the MI cursor +display structures and function pointers. If a hardware cursor is used, +the DDX layer's ScreenInit() function will wrap additional screen and +the MI cursor display function pointers. +</descrip> + +<p>Another common task for ScreenInit() function is to initialize the +output device state. For example, in the XFree86 X server, the +ScreenInit() function saves the original state of the video card and +then initializes the video mode of the graphics device. + +<sect2>CloseScreen() + +<p>This function restores any wrapped screen functions (and in +particular the wrapped CloseScreen() function) and restores the state of +the output device to its original state. It should also free any +private data it created during the screen initialization. + +<sect2>GC operations + +<p>When the X server is requested to render drawing primitives, it does +so by calling drawing functions through the graphics context's operation +function pointer table (i.e., the GCOps functions). These functions +render the basic graphics operations such as drawing rectangles, lines, +text or copying pixmaps. Default routines are provided either by the MI +layer, which draws indirectly through a simple span interface, or by the +framebuffer layers (e.g., CFB, MFB, FB), which draw directly to a +linearly mapped frame buffer. + +<p>To take advantage of special hardware on the graphics device, +specific GCOps functions can be replaced by device specific code. +However, many times the graphics devices can handle only a subset of the +possible states of the GC, so during graphics context validation, +appropriate routines are selected based on the state and capabilities of +the hardware. For example, some graphics hardware can accelerate single +pixel width lines with certain dash patterns. Thus, for dash patterns +that are not supported by hardware or for width 2 or greater lines, the +default routine is chosen during GC validation. + +<p>Note that some pointers to functions that draw to the screen are +stored in the Screen structure. They include GetImage(), GetSpans(), +CopyWindow() and RestoreAreas(). + +<sect2>Xnest + +<p>The Xnest X server is a special proxy X server that relays the X +protocol requests that it receives to a ``real'' X server that then +processes the requests and displays the results, if applicable. To the X +applications, Xnest appears as if it is a regular X server. However, +Xnest is both server to the X application and client of the real X +server, which will actually handle the requests. + +<p>The Xnest server implements all of the standard input and output +initialization steps outlined above. + +<descrip> +<tag/InitOutput()/ Xnest takes its configuration information from +command line arguments via ddxProcessArguments(). This information +includes the real X server display to connect to, its default visual +class, the screen depth, the Xnest window's geometry, etc. Xnest then +connects to the real X server and gathers visual, colormap, depth and +pixmap information about that server's display, creates a window on that +server, which will be used as the root window for Xnest. + +<p>Next, Xnest initializes its internal data structures and uses the +data from the real X server's pixmaps to initialize its own pixmap +formats. Finally, it calls AddScreen(xnestOpenScreen, argc, argv) to +initialize each of its screens. + +<tag/ScreenInit()/ Xnest's ScreenInit() function is called +xnestOpenScreen(). This function initializes its screen's depth and +visual information, and then calls miScreenInit() to set up the default +screen functions. It then calls miInitializeBackingStore() and +miDCInitialize() to initialize backing store and the software cursor. +Finally, it replaces many of the screen functions with its own +functions that repackage and send the requests to the real X server to +which Xnest is attached. + +<tag/CloseScreen()/ This function frees its internal data structure +allocations. Since it replaces instead of wrapping screen functions, +there are no function pointers to unwrap. This can potentially lead to +problems during server regeneration. + +<tag/GC operations/ The GC operations in Xnest are very simple since +they leave all of the drawing to the real X server to which Xnest is +attached. Each of the GCOps takes the request and sends it to the +real X server using standard Xlib calls. For example, the X +application issues a XDrawLines() call. This function turns into a +protocol request to Xnest, which calls the xnestPolylines() function +through Xnest's GCOps function pointer table. The xnestPolylines() +function is only a single line, which calls XDrawLines() using the same +arguments that were passed into it. Other GCOps functions are very +similar. Two exceptions to the simple GCOps functions described above +are the image functions and the BLT operations. + +<p>The image functions, GetImage() and PutImage(), must use a temporary +image to hold the image to be put of the image that was just grabbed +from the screen while it is in transit to the real X server or the +client. When the image has been transmitted, the temporary image is +destroyed. + +<p>The BLT operations, CopyArea() and CopyPlane(), handle not only the +copy function, which is the same as the simple cases described above, +but also the graphics exposures that result when the GC's graphics +exposure bit is set to True. Graphics exposures are handled in a helper +function, xnestBitBlitHelper(). This function collects the exposure +events from the real X server and, if any resulting in regions being +exposed, then those regions are passed back to the MI layer so that it +can generate exposure events for the X application. +</descrip> + +<p>The Xnest server takes its input from the X server to which it is +connected. When the mouse is in the Xnest server's window, keyboard and +mouse events are received by the Xnest server, repackaged and sent back +to any client that requests those events. + +<sect2>Shadow framebuffer + +<p>The most common type of framebuffer is a linear array memory that +maps to the video memory on the graphics device. However, accessing +that video memory over an I/O bus (e.g., ISA or PCI) can be slow. The +shadow framebuffer layer allows the developer to keep the entire +framebuffer in main memory and copy it back to video memory at regular +intervals. It also has been extended to handle planar video memory and +rotated framebuffers. + +<p>There are two main entry points to the shadow framebuffer code: + +<descrip> +<tag/shadowAlloc(width, height, bpp)/ This function allocates the in +memory copy of the framebuffer of size width*height*bpp. It returns a +pointer to that memory, which will be used by the framebuffer +ScreenInit() code during the screen's initialization. + +<tag/shadowInit(pScreen, updateProc, windowProc)/ This function +initializes the shadow framebuffer layer. It wraps several screen +drawing functions, and registers a block handler that will update the +screen. The updateProc is a function that will copy the damaged regions +to the screen, and the windowProc is a function that is used when the +entire linear video memory range cannot be accessed simultaneously so +that only a window into that memory is available (e.g., when using the +VGA aperture). +</descrip> + +<p>The shadow framebuffer code keeps track of the damaged area of each +screen by calculating the bounding box of all drawing operations that +have occurred since the last screen update. Then, when the block handler +is next called, only the damaged portion of the screen is updated. + +<p>Note that since the shadow framebuffer is kept in main memory, all +drawing operations are performed by the CPU and, thus, no accelerated +hardware drawing operations are possible. + + +<sect1>Xinerama + +<p>Xinerama is an X extension that allows multiple physical screens +controlled by a single X server to appear as a single screen. Although +the extension allows clients to find the physical screen layout via +extension requests, it is completely transparent to clients at the core +X11 protocol level. The original public implementation of Xinerama came +from Digital/Compaq. XFree86 rewrote it, filling in some missing pieces +and improving both X11 core protocol compliance and performance. The +Xinerama extension will be passing through X.Org's standardization +process in the near future, and the sample implementation will be based +on this rewritten version. + +<p>The current implementation of Xinerama is based primarily in the DIX +(device independent) and MI (machine independent) layers of the X +server. With few exceptions the DDX layers do not need any changes to +support Xinerama. X server extensions often do need modifications to +provide full Xinerama functionality. + +<p>The following is a code-level description of how Xinerama functions. + +<p>Note: Because the Xinerama extension was originally called the +PanoramiX extension, many of the Xinerama functions still have the +PanoramiX prefix. + +<descrip> + <tag/PanoramiXExtensionInit()/ PanoramiXExtensionInit() is a + device-independent extension function that is called at the start of + each server generation from InitExtensions(), which is called from + the X server's main() function after all output devices have been + initialized, but before any input devices have been initialized. + + <p>PanoramiXNumScreens is set to the number of physical screens. If + only one physical screen is present, the extension is disabled, and + PanoramiXExtensionInit() returns without doing anything else. + + <p>The Xinerama extension is registered by calling AddExtension(). + + <p>A local per-screen array of data structures + (panoramiXdataPtr[]) + is allocated for each physical screen, and GC and Screen private + indexes are allocated, and both GC and Screen private areas are + allocated for each physical screen. These hold Xinerama-specific + per-GC and per-Screen data. Each screen's CreateGC and CloseScreen + functions are wrapped by XineramaCreateGC() and + XineramaCloseScreen() respectively. Some new resource classes are + created for Xinerama drawables and GCs, and resource types for + Xinerama windows, pixmaps and colormaps. + + <p>A region (XineramaScreenRegions[i]) is initialized for each + physical screen, and single region (PanoramiXScreenRegion) is + initialized to be the union of the screen regions. The + panoramiXdataPtr[] array is also initialized with the size and + origin of each screen. The relative positioning information for the + physical screens is taken from the array + dixScreenOrigins[], which + the DDX layer must initialize in InitOutput(). The bounds of the + combined screen is also calculated (PanoramiXPixWidth and + PanoramiXPixHeight). + + <p>The DIX layer has a list of function pointers + (ProcVector[]) that + holds the entry points for the functions that process core protocol + requests. The requests that Xinerama must intercept and break up + into physical screen-specific requests are wrapped. The original + set is copied to SavedProcVector[]. The types of requests + intercepted are Window requests, GC requests, colormap requests, + drawing requests, and some geometry-related requests. This wrapping + allows the bulk of the protocol request processing to be handled + transparently to the DIX layer. Some operations cannot be dealt with + in this way and are handled with Xinerama-specific code within the + DIX layer. + + <tag/PanoramiXConsolidate()/ PanoramiXConsolidate() is a + device-independent extension function that is called directly from + the X server's main() function after extensions and input/output + devices have been initialized, and before the root windows are + defined and initialized. + + <p>This function finds the set of depths (PanoramiXDepths[]) and + visuals (PanoramiXVisuals[]) + common to all of the physical screens. + PanoramiXNumDepths is set to the number of common depths, and + PanoramiXNumVisuals is set to the number of common visuals. + Resources are created for the single root window and the default + colormap. Each of these resources has per-physical screen entries. + + <tag/PanoramiXCreateConnectionBlock()/ PanoramiXConsolidate() is a + device-independent extension function that is called directly from + the X server's main() function after the per-physical screen root + windows are created. It is called instead of the standard DIX + CreateConnectionBlock() function. If this function returns FALSE, + the X server exits with a fatal error. This function will return + FALSE if no common depths were found in PanoramiXConsolidate(). + With no common depths, Xinerama mode is not possible. + + <p>The connection block holds the information that clients get when + they open a connection to the X server. It includes information + such as the supported pixmap formats, number of screens and the + sizes, depths, visuals, default colormap information, etc, for each + of the screens (much of information that <tt/xdpyinfo/ shows). The + connection block is initialized with the combined single screen + values that were calculated in the above two functions. + + <p>The Xinerama extension allows the registration of connection + block callback functions. The purpose of these is to allow other + extensions to do processing at this point. These callbacks can be + registered by calling XineramaRegisterConnectionBlockCallback() from + the other extension's ExtensionInit() function. Each registered + connection block callback is called at the end of + PanoramiXCreateConnectionBlock(). +</descrip> + +<sect2>Xinerama-specific changes to the DIX code + +<p>There are a few types of Xinerama-specific changes within the DIX +code. The main ones are described here. + +<p>Functions that deal with colormap or GC -related operations outside of +the intercepted protocol requests have a test added to only do the +processing for screen numbers > 0. This is because they are handled for +the single Xinerama screen and the processing is done once for screen 0. + +<p>The handling of motion events does some coordinate translation between +the physical screen's origin and screen zero's origin. Also, motion +events must be reported relative to the composite screen origin rather +than the physical screen origins. + +<p>There is some special handling for cursor, window and event processing +that cannot (either not at all or not conveniently) be done via the +intercepted protocol requests. A particular case is the handling of +pointers moving between physical screens. + +<sect2>Xinerama-specific changes to the MI code + +<p>The only Xinerama-specific change to the MI code is in miSendExposures() +to handle the coordinate (and window ID) translation for expose events. + +<sect2>Intercepted DIX core requests + +<p>Xinerama breaks up drawing requests for dispatch to each physical +screen. It also breaks up windows into pieces for each physical screen. +GCs are translated into per-screen GCs. Colormaps are replicated on +each physical screen. The functions handling the intercepted requests +take care of breaking the requests and repackaging them so that they can +be passed to the standard request handling functions for each screen in +turn. In addition, and to aid the repackaging, the information from +many of the intercepted requests is used to keep up to date the +necessary state information for the single composite screen. Requests +(usually those with replies) that can be satisfied completely from this +stored state information do not call the standard request handling +functions. + +<!-- ============================================================ --> + +<sect>Development Results + +<p>In this section the results of each phase of development are +discussed. This development took place between approximately June 2001 +and July 2003. + +<sect1>Phase I + +<p>The initial development phase dealt with the basic implementation +including the bootstrap code, which used the shadow framebuffer, and the +unoptimized implementation, based on an Xnest-style implementation. + +<sect2>Scope + +<p>The goal of Phase I is to provide fundamental functionality that can +act as a foundation for ongoing work: +<enum> + <item>Develop the proxy X server + <itemize> + <item>The proxy X server will operate on the X11 protocol and + relay requests as necessary to correctly perform the request. + <item>Work will be based on the existing work for Xinerama and + Xnest. + <item>Input events and windowing operations are handled in the + proxy server and rendering requests are repackaged and sent to + each of the back-end servers for display. + <item>The multiple screen layout (including support for + overlapping screens) will be user configurable via a + configuration file or through the configuration tool. + </itemize> + <item>Develop graphical configuration tool + <itemize> + <item>There will be potentially a large number of X servers to + configure into a single display. The tool will allow the user + to specify which servers are involved in the configuration and + how they should be laid out. + </itemize> + <item>Pass the X Test Suite + <itemize> + <item>The X Test Suite covers the basic X11 operations. All + tests known to succeed must correctly operate in the distributed + X environment. + </itemize> +</enum> + +<p>For this phase, the back-end X servers are assumed to be unmodified X +servers that do not support any DMX-related protocol extensions; future +optimization pathways are considered, but are not implemented; and the +configuration tool is assumed to rely only on libraries in the X source +tree (e.g., Xt). + +<sect2>Results + +<p>The proxy X server, Xdmx, was developed to distribute X11 protocol +requests to the set of back-end X servers. It opens a window on each +back-end server, which represents the part of the front-end's root +window that is visible on that screen. It mirrors window, pixmap and +other state in each back-end server. Drawing requests are sent to +either windows or pixmaps on each back-end server. This code is based +on Xnest and uses the existing Xinerama extension. + +<p>Input events can be taken from (1) devices attached to the back-end +server, (2) core devices attached directly to the Xdmx server, or (3) +from a ``console'' window on another X server. Events for these devices +are gathered, processed and delivered to clients attached to the Xdmx +server. + +<p>An intuitive configuration format was developed to help the user +easily configure the multiple back-end X servers. It was defined (see +grammar in Xdmx man page) and a parser was implemented that is used by +the Xdmx server and by a standalone xdmxconfig utility. The parsing +support was implemented such that it can be easily factored out of the X +source tree for use with other tools (e.g., vdl). Support for +converting legacy vdl-format configuration files to the DMX format is +provided by the vdltodmx utility. + +<p>Originally, the configuration file was going to be a subsection of +XFree86's XF86Config file, but that was not possible since Xdmx is a +completely separate X server. Thus, a separate config file format was +developed. In addition, a graphical configuration +tool, xdmxconfig, was developed to allow the user to create and arrange +the screens in the configuration file. The <bf/-configfile/ and <bf/-config/ +command-line options can be used to start Xdmx using a configuration +file. + +<p>An extension that enables remote input testing is required for the X +Test Suite to function. During this phase, this extension (XTEST) was +implemented in the Xdmx server. The results from running the X Test +Suite are described in detail below. + +<sect2>X Test Suite + + <sect3> Introduction + <p> + The X Test Suite contains tests that verify Xlib functions + operate correctly. The test suite is designed to run on a + single X server; however, since X applications will not be + able to tell the difference between the DMX server and a + standard X server, the X Test Suite should also run on the + DMX server. + <p> + The Xdmx server was tested with the X Test Suite, and the + existing failures are noted in this section. To put these + results in perspective, we first discuss expected X Test + failures and how errors in underlying systems can impact + Xdmx test results. + + <sect3>Expected Failures for a Single Head + <p> + A correctly implemented X server with a single screen is + expected to fail certain X Test tests. The following + well-known errors occur because of rounding error in the X + server code: + <verb> +XDrawArc: Tests 42, 63, 66, 73 +XDrawArcs: Tests 45, 66, 69, 76 + </verb> + <p> + The following failures occur because of the high-level X + server implementation: + <verb> +XLoadQueryFont: Test 1 +XListFontsWithInfo: Tests 3, 4 +XQueryFont: Tests 1, 2 + </verb> + <p> + The following test fails when running the X server as root + under Linux because of the way directory modes are + interpreted: + <verb> +XWriteBitmapFile: Test 3 + </verb> + <p> + Depending on the video card used for the back-end, other + failures may also occur because of bugs in the low-level + driver implementation. Over time, failures of this kind + are usually fixed by XFree86, but will show up in Xdmx + testing until then. + + <sect3>Expected Failures for Xinerama + <p> + Xinerama fails several X Test Suite tests because of + design decisions made for the current implementation of + Xinerama. Over time, many of these errors will be + corrected by XFree86 and the group working on a new + Xinerama implementation. Therefore, Xdmx will also share + X Suite Test failures with Xinerama. + <p> + We may be able to fix or work-around some of these + failures at the Xdmx level, but this will require + additional exploration that was not part of Phase I. + <p> + Xinerama is constantly improving, and the list of + Xinerama-related failures depends on XFree86 version and + the underlying graphics hardware. We tested with a + variety of hardware, including nVidia, S3, ATI Radeon, + and Matrox G400 (in dual-head mode). The list below + includes only those failures that appear to be from the + Xinerama layer, and does not include failures listed in + the previous section, or failures that appear to be from + the low-level graphics driver itself: + <p> + These failures were noted with multiple Xinerama + configurations: + <verb> +XCopyPlane: Tests 13, 22, 31 (well-known Xinerama implementation issue) +XSetFontPath: Test 4 +XGetDefault: Test 5 +XMatchVisualInfo: Test 1 + </verb> + <p> + These failures were noted only when using one dual-head + video card with a 4.2.99.x XFree86 server: + <verb> +XListPixmapFormats: Test 1 +XDrawRectangles: Test 45 + </verb> + <p> + These failures were noted only when using two video cards + from different vendors with a 4.1.99.x XFree86 server: + <verb> +XChangeWindowAttributes: Test 32 +XCreateWindow: Test 30 +XDrawLine: Test 22 +XFillArc: Test 22 +XChangeKeyboardControl: Tests 9, 10 +XRebindKeysym: Test 1 + </verb> + + <sect3>Additional Failures from Xdmx + <p> + When running Xdmx, no unexpected failures were noted. + Since the Xdmx server is based on Xinerama, we expect to + have most of the Xinerama failures present in the Xdmx + server. Similarly, since the Xdmx server must rely on the + low-level device drivers on each back-end server, we also + expect that Xdmx will exhibit most of the back-end + failures. Here is a summary: + <verb> +XListPixmapFormats: Test 1 (configuration dependent) +XChangeWindowAttributes: Test 32 +XCreateWindow: Test 30 +XCopyPlane: Test 13, 22, 31 +XSetFontPath: Test 4 +XGetDefault: Test 5 (configuration dependent) +XMatchVisualInfo: Test 1 +XRebindKeysym: Test 1 (configuration dependent) + </verb> + <p> + Note that this list is shorter than the combined list for + Xinerama because Xdmx uses different code paths to perform + some Xinerama operations. Further, some Xinerama failures + have been fixed in the XFree86 4.2.99.x CVS repository. + + <sect3>Summary and Future Work + <p> + Running the X Test Suite on Xdmx does not produce any + failures that cannot be accounted for by the underlying + Xinerama subsystem used by the front-end or by the + low-level device-driver code running on the back-end X + servers. The Xdmx server therefore is as ``correct'' as + possible with respect to the standard set of X Test Suite + tests. + <p> + During the following phases, we will continue to verify + Xdmx correctness using the X Test Suite. We may also use + other tests suites or write additional tests that run + under the X Test Suite that specifically verify the + expected behavior of DMX. + +<sect2>Fonts + +<p>In Phase I, fonts are handled directly by both the front-end and the +back-end servers, which is required since we must treat each back-end +server during this phase as a ``black box''. What this requires is that +<bf/the front- and back-end servers must share the exact same font +path/. There are two ways to help make sure that all servers share the +same font path: + +<enum> + <item>First, each server can be configured to use the same font + server. The font server, xfs, can be configured to serve fonts to + multiple X servers via TCP. + + <item>Second, each server can be configured to use the same font + path and either those font paths can be copied to each back-end + machine or they can be mounted (e.g., via NFS) on each back-end + machine. +</enum> + +<p>One additional concern is that a client program can set its own font +path, and if it does so, then that font path must be available on each +back-end machine. + +<p>The -fontpath command line option was added to allow users to +initialize the font path of the front end server. This font path is +propagated to each back-end server when the default font is loaded. If +there are any problems, an error message is printed, which will describe +the problem and list the current font path. For more information about +setting the font path, see the -fontpath option description in the man +page. + +<sect2>Performance + +<p>Phase I of development was not intended to optimize performance. Its +focus was on completely and correctly handling the base X11 protocol in +the Xdmx server. However, several insights were gained during Phase I, +which are listed here for reference during the next phase of +development. + +<enum> + <item>Calls to XSync() can slow down rendering since it requires a + complete round trip to and from a back-end server. This is + especially problematic when communicating over long haul networks. + <item>Sending drawing requests to only the screens that they overlap + should improve performance. +</enum> + +<sect2>Pixmaps + +<p>Pixmaps were originally expected to be handled entirely in the +front-end X server; however, it was found that this overly complicated +the rendering code and would have required sending potentially large +images to each back server that required them when copying from pixmap +to screen. Thus, pixmap state is mirrored in the back-end server just +as it is with regular window state. With this implementation, the same +rendering code that draws to windows can be used to draw to pixmaps on +the back-end server, and no large image transfers are required to copy +from pixmap to window. + +<!-- ============================================================ --> +<sect1>Phase II + +<p>The second phase of development concentrates on performance +optimizations. These optimizations are documented here, with +<tt/x11perf/ data to show how the optimizations improve performance. + +<p>All benchmarks were performed by running Xdmx on a dual processor +1.4GHz AMD Athlon machine with 1GB of RAM connecting over 100baseT to +two single-processor 1GHz Pentium III machines with 256MB of RAM and ATI +Rage 128 (RF) video cards. The front end was running Linux +2.4.20-pre1-ac1 and the back ends were running Linux 2.4.7-10 and +version 4.2.99.1 of XFree86 pulled from the XFree86 CVS repository on +August 7, 2002. All systems were running Red Hat Linux 7.2. + +<sect2>Moving from XFree86 4.1.99.1 to 4.2.0.0 + +<p>For phase II, the working source tree was moved to the branch tagged +with dmx-1-0-branch and was updated from version 4.1.99.1 (20 August +2001) of the XFree86 sources to version 4.2.0.0 (18 January 2002). +After this update, the following tests were noted to be more than 10% +faster: + <verb> +1.13 Fill 300x300 opaque stippled trapezoid (161x145 stipple) +1.16 Fill 1x1 tiled trapezoid (161x145 tile) +1.13 Fill 10x10 tiled trapezoid (161x145 tile) +1.17 Fill 100x100 tiled trapezoid (161x145 tile) +1.16 Fill 1x1 tiled trapezoid (216x208 tile) +1.20 Fill 10x10 tiled trapezoid (216x208 tile) +1.15 Fill 100x100 tiled trapezoid (216x208 tile) +1.37 Circulate Unmapped window (200 kids) + </verb> +And the following tests were noted to be more than 10% slower: + <verb> +0.88 Unmap window via parent (25 kids) +0.75 Circulate Unmapped window (4 kids) +0.79 Circulate Unmapped window (16 kids) +0.80 Circulate Unmapped window (25 kids) +0.82 Circulate Unmapped window (50 kids) +0.85 Circulate Unmapped window (75 kids) + </verb> +<p>These changes were not caused by any changes in the DMX system, and +may point to changes in the XFree86 tree or to tests that have more +"jitter" than most other <tt/x11perf/ tests. + +<sect2>Global changes + +<p>During the development of the Phase II DMX server, several global +changes were made. These changes were also compared with the Phase I +server. The following tests were noted to be more than 10% faster: + <verb> +1.13 Fill 300x300 opaque stippled trapezoid (161x145 stipple) +1.15 Fill 1x1 tiled trapezoid (161x145 tile) +1.13 Fill 10x10 tiled trapezoid (161x145 tile) +1.17 Fill 100x100 tiled trapezoid (161x145 tile) +1.16 Fill 1x1 tiled trapezoid (216x208 tile) +1.19 Fill 10x10 tiled trapezoid (216x208 tile) +1.15 Fill 100x100 tiled trapezoid (216x208 tile) +1.15 Circulate Unmapped window (4 kids) + </verb> + +<p>The following tests were noted to be more than 10% slower: + <verb> +0.69 Scroll 10x10 pixels +0.68 Scroll 100x100 pixels +0.68 Copy 10x10 from window to window +0.68 Copy 100x100 from window to window +0.76 Circulate Unmapped window (75 kids) +0.83 Circulate Unmapped window (100 kids) + </verb> + +<p>For the remainder of this analysis, the baseline of comparison will +be the Phase II deliverable with all optimizations disabled (unless +otherwise noted). This will highlight how the optimizations in +isolation impact performance. + +<sect2>XSync() Batching + +<p>During the Phase I implementation, XSync() was called after every +protocol request made by the DMX server. This provided the DMX server +with an interactive feel, but defeated X11's protocol buffering system +and introduced round-trip wire latency into every operation. During +Phase II, DMX was changed so that protocol requests are no longer +followed by calls to XSync(). Instead, the need for an XSync() is +noted, and XSync() calls are only made every 100mS or when the DMX +server specifically needs to make a call to guarantee interactivity. +With this new system, X11 buffers protocol as much as possible during a +100mS interval, and many unnecessary XSync() calls are avoided. + +<p>Out of more than 300 <tt/x11perf/ tests, 8 tests became more than 100 +times faster, with 68 more than 50X faster, 114 more than 10X faster, +and 181 more than 2X faster. See table below for summary. + +<p>The following tests were noted to be more than 10% slower with +XSync() batching on: + <verb> +0.88 500x500 tiled rectangle (161x145 tile) +0.89 Copy 500x500 from window to window + </verb> + +<sect2>Offscreen Optimization + +<p>Windows span one or more of the back-end servers' screens; however, +during Phase I development, windows were created on every back-end +server and every rendering request was sent to every window regardless +of whether or not that window was visible. With the offscreen +optimization, the DMX server tracks when a window is completely off of a +back-end server's screen and, in that case, it does not send rendering +requests to those back-end windows. This optimization saves bandwidth +between the front and back-end servers, and it reduces the number of +XSync() calls. The performance tests were run on a DMX system with only +two back-end servers. Greater performance gains will be had as the +number of back-end servers increases. + +<p>Out of more than 300 <tt/x11perf/ tests, 3 tests were at least twice as +fast, and 146 tests were at least 10% faster. Two tests were more than +10% slower with the offscreen optimization: + <verb> +0.88 Hide/expose window via popup (4 kids) +0.89 Resize unmapped window (75 kids) + </verb> + +<sect2>Lazy Window Creation Optimization + +<p>As mentioned above, during Phase I, windows were created on every +back-end server even if they were not visible on that back-end. With +the lazy window creation optimization, the DMX server does not create +windows on a back-end server until they are either visible or they +become the parents of a visible window. This optimization builds on the +offscreen optimization (described above) and requires it to be enabled. + +<p>The lazy window creation optimization works by creating the window +data structures in the front-end server when a client creates a window, +but delays creation of the window on the back-end server(s). A private +window structure in the DMX server saves the relevant window data and +tracks changes to the window's attributes and stacking order for later +use. The only times a window is created on a back-end server are (1) +when it is mapped and is at least partially overlapping the back-end +server's screen (tracked by the offscreen optimization), or (2) when the +window becomes the parent of a previously visible window. The first +case occurs when a window is mapped or when a visible window is copied, +moved or resized and now overlaps the back-end server's screen. The +second case occurs when starting a window manager after having created +windows to which the window manager needs to add decorations. + +<p>When either case occurs, a window on the back-end server is created +using the data saved in the DMX server's window private data structure. +The stacking order is then adjusted to correctly place the window on the +back-end and lastly the window is mapped. From this time forward, the +window is handled exactly as if the window had been created at the time +of the client's request. + +<p>Note that when a window is no longer visible on a back-end server's +screen (e.g., it is moved offscreen), the window is not destroyed; +rather, it is kept and reused later if the window once again becomes +visible on the back-end server's screen. Originally with this +optimization, destroying windows was implemented but was later rejected +because it increased bandwidth when windows were opaquely moved or +resized, which is common in many window managers. + +<p>The performance tests were run on a DMX system with only two back-end +servers. Greater performance gains will be had as the number of +back-end servers increases. + +<p>This optimization improved the following <tt/x11perf/ tests by more +than 10%: + <verb> +1.10 500x500 rectangle outline +1.12 Fill 100x100 stippled trapezoid (161x145 stipple) +1.20 Circulate Unmapped window (50 kids) +1.19 Circulate Unmapped window (75 kids) + </verb> + +<sect2>Subdividing Rendering Primitives + +<p>X11 imaging requests transfer significant data between the client and +the X server. During Phase I, the DMX server would then transfer the +image data to each back-end server. Even with the offscreen +optimization (above), these requests still required transferring +significant data to each back-end server that contained a visible +portion of the window. For example, if the client uses XPutImage() to +copy an image to a window that overlaps the entire DMX screen, then the +entire image is copied by the DMX server to every back-end server. + +<p>To reduce the amount of data transferred between the DMX server and +the back-end servers when XPutImage() is called, the image data is +subdivided and only the data that will be visible on a back-end server's +screen is sent to that back-end server. Xinerama already implements a +subdivision algorithm for XGetImage() and no further optimization was +needed. + +<p>Other rendering primitives were analyzed, but the time required to +subdivide these primitives was a significant proportion of the time +required to send the entire rendering request to the back-end server, so +this optimization was rejected for the other rendering primitives. + +<p>Again, the performance tests were run on a DMX system with only two +back-end servers. Greater performance gains will be had as the number +of back-end servers increases. + +<p>This optimization improved the following <tt/x11perf/ tests by more +than 10%: + <verb> +1.12 Fill 100x100 stippled trapezoid (161x145 stipple) +1.26 PutImage 10x10 square +1.83 PutImage 100x100 square +1.91 PutImage 500x500 square +1.40 PutImage XY 10x10 square +1.48 PutImage XY 100x100 square +1.50 PutImage XY 500x500 square +1.45 Circulate Unmapped window (75 kids) +1.74 Circulate Unmapped window (100 kids) + </verb> + +<p>The following test was noted to be more than 10% slower with this +optimization: + <verb> +0.88 10-pixel fill chord partial circle + </verb> + +<sect2>Summary of x11perf Data + +<p>With all of the optimizations on, 53 <tt/x11perf/ tests are more than +100X faster than the unoptimized Phase II deliverable, with 69 more than +50X faster, 73 more than 10X faster, and 199 more than twice as fast. +No tests were more than 10% slower than the unoptimized Phase II +deliverable. (Compared with the Phase I deliverable, only Circulate +Unmapped window (100 kids) was more than 10% slower than the Phase II +deliverable. As noted above, this test seems to have wider variability +than other <tt/x11perf/ tests.) + +<p>The following table summarizes relative <tt/x11perf/ test changes for +all optimizations individually and collectively. Note that some of the +optimizations have a synergistic effect when used together. + <verb> + +1: XSync() batching only +2: Off screen optimizations only +3: Window optimizations only +4: Subdivprims only +5: All optimizations + + 1 2 3 4 5 Operation +------ ---- ---- ---- ------ --------- + 2.14 1.85 1.00 1.00 4.13 Dot + 1.67 1.80 1.00 1.00 3.31 1x1 rectangle + 2.38 1.43 1.00 1.00 2.44 10x10 rectangle + 1.00 1.00 0.92 0.98 1.00 100x100 rectangle + 1.00 1.00 1.00 1.00 1.00 500x500 rectangle + 1.83 1.85 1.05 1.06 3.54 1x1 stippled rectangle (8x8 stipple) + 2.43 1.43 1.00 1.00 2.41 10x10 stippled rectangle (8x8 stipple) + 0.98 1.00 1.00 1.00 1.00 100x100 stippled rectangle (8x8 stipple) + 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (8x8 stipple) + 1.75 1.75 1.00 1.00 3.40 1x1 opaque stippled rectangle (8x8 stipple) + 2.38 1.42 1.00 1.00 2.34 10x10 opaque stippled rectangle (8x8 stipple) + 1.00 1.00 0.97 0.97 1.00 100x100 opaque stippled rectangle (8x8 stipple) + 1.00 1.00 1.00 1.00 0.99 500x500 opaque stippled rectangle (8x8 stipple) + 1.82 1.82 1.04 1.04 3.56 1x1 tiled rectangle (4x4 tile) + 2.33 1.42 1.00 1.00 2.37 10x10 tiled rectangle (4x4 tile) + 1.00 0.92 1.00 1.00 1.00 100x100 tiled rectangle (4x4 tile) + 1.00 1.00 1.00 1.00 1.00 500x500 tiled rectangle (4x4 tile) + 1.94 1.62 1.00 1.00 3.66 1x1 stippled rectangle (17x15 stipple) + 1.74 1.28 1.00 1.00 1.73 10x10 stippled rectangle (17x15 stipple) + 1.00 1.00 1.00 0.89 0.98 100x100 stippled rectangle (17x15 stipple) + 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (17x15 stipple) + 1.94 1.62 1.00 1.00 3.67 1x1 opaque stippled rectangle (17x15 stipple) + 1.69 1.26 1.00 1.00 1.66 10x10 opaque stippled rectangle (17x15 stipple) + 1.00 0.95 1.00 1.00 1.00 100x100 opaque stippled rectangle (17x15 stipple) + 1.00 1.00 1.00 1.00 0.97 500x500 opaque stippled rectangle (17x15 stipple) + 1.93 1.61 0.99 0.99 3.69 1x1 tiled rectangle (17x15 tile) + 1.73 1.27 1.00 1.00 1.72 10x10 tiled rectangle (17x15 tile) + 1.00 1.00 1.00 1.00 0.98 100x100 tiled rectangle (17x15 tile) + 1.00 1.00 0.97 0.97 1.00 500x500 tiled rectangle (17x15 tile) + 1.95 1.63 1.00 1.00 3.83 1x1 stippled rectangle (161x145 stipple) + 1.80 1.30 1.00 1.00 1.83 10x10 stippled rectangle (161x145 stipple) + 0.97 1.00 1.00 1.00 1.01 100x100 stippled rectangle (161x145 stipple) + 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (161x145 stipple) + 1.95 1.63 1.00 1.00 3.56 1x1 opaque stippled rectangle (161x145 stipple) + 1.65 1.25 1.00 1.00 1.68 10x10 opaque stippled rectangle (161x145 stipple) + 1.00 1.00 1.00 1.00 1.01 100x100 opaque stippled rectangle (161x145... + 1.00 1.00 1.00 1.00 0.97 500x500 opaque stippled rectangle (161x145... + 1.95 1.63 0.98 0.99 3.80 1x1 tiled rectangle (161x145 tile) + 1.67 1.26 1.00 1.00 1.67 10x10 tiled rectangle (161x145 tile) + 1.13 1.14 1.14 1.14 1.14 100x100 tiled rectangle (161x145 tile) + 0.88 1.00 1.00 1.00 0.99 500x500 tiled rectangle (161x145 tile) + 1.93 1.63 1.00 1.00 3.53 1x1 tiled rectangle (216x208 tile) + 1.69 1.26 1.00 1.00 1.66 10x10 tiled rectangle (216x208 tile) + 1.00 1.00 1.00 1.00 1.00 100x100 tiled rectangle (216x208 tile) + 1.00 1.00 1.00 1.00 1.00 500x500 tiled rectangle (216x208 tile) + 1.82 1.70 1.00 1.00 3.38 1-pixel line segment + 2.07 1.56 0.90 1.00 3.31 10-pixel line segment + 1.29 1.10 1.00 1.00 1.27 100-pixel line segment + 1.05 1.06 1.03 1.03 1.09 500-pixel line segment + 1.30 1.13 1.00 1.00 1.29 100-pixel line segment (1 kid) + 1.32 1.15 1.00 1.00 1.32 100-pixel line segment (2 kids) + 1.33 1.16 1.00 1.00 1.33 100-pixel line segment (3 kids) + 1.92 1.64 1.00 1.00 3.73 10-pixel dashed segment + 1.34 1.16 1.00 1.00 1.34 100-pixel dashed segment + 1.24 1.11 0.99 0.97 1.23 100-pixel double-dashed segment + 1.72 1.77 1.00 1.00 3.25 10-pixel horizontal line segment + 1.83 1.66 1.01 1.00 3.54 100-pixel horizontal line segment + 1.86 1.30 1.00 1.00 1.84 500-pixel horizontal line segment + 2.11 1.52 1.00 0.99 3.02 10-pixel vertical line segment + 1.21 1.10 1.00 1.00 1.20 100-pixel vertical line segment + 1.03 1.03 1.00 1.00 1.02 500-pixel vertical line segment + 4.42 1.68 1.00 1.01 4.64 10x1 wide horizontal line segment + 1.83 1.31 1.00 1.00 1.83 100x10 wide horizontal line segment + 1.07 1.00 0.96 1.00 1.07 500x50 wide horizontal line segment + 4.10 1.67 1.00 1.00 4.62 10x1 wide vertical line segment + 1.50 1.24 1.06 1.06 1.48 100x10 wide vertical line segment + 1.06 1.03 1.00 1.00 1.05 500x50 wide vertical line segment + 2.54 1.61 1.00 1.00 3.61 1-pixel line + 2.71 1.48 1.00 1.00 2.67 10-pixel line + 1.19 1.09 1.00 1.00 1.19 100-pixel line + 1.04 1.02 1.00 1.00 1.03 500-pixel line + 2.68 1.51 0.98 1.00 3.17 10-pixel dashed line + 1.23 1.11 0.99 0.99 1.23 100-pixel dashed line + 1.15 1.08 1.00 1.00 1.15 100-pixel double-dashed line + 2.27 1.39 1.00 1.00 2.23 10x1 wide line + 1.20 1.09 1.00 1.00 1.20 100x10 wide line + 1.04 1.02 1.00 1.00 1.04 500x50 wide line + 1.52 1.45 1.00 1.00 1.52 100x10 wide dashed line + 1.54 1.47 1.00 1.00 1.54 100x10 wide double-dashed line + 1.97 1.30 0.96 0.95 1.95 10x10 rectangle outline + 1.44 1.27 1.00 1.00 1.43 100x100 rectangle outline + 3.22 2.16 1.10 1.09 3.61 500x500 rectangle outline + 1.95 1.34 1.00 1.00 1.90 10x10 wide rectangle outline + 1.14 1.14 1.00 1.00 1.13 100x100 wide rectangle outline + 1.00 1.00 1.00 1.00 1.00 500x500 wide rectangle outline + 1.57 1.72 1.00 1.00 3.03 1-pixel circle + 1.96 1.35 1.00 1.00 1.92 10-pixel circle + 1.21 1.07 0.86 0.97 1.20 100-pixel circle + 1.08 1.04 1.00 1.00 1.08 500-pixel circle + 1.39 1.19 1.03 1.03 1.38 100-pixel dashed circle + 1.21 1.11 1.00 1.00 1.23 100-pixel double-dashed circle + 1.59 1.28 1.00 1.00 1.58 10-pixel wide circle + 1.22 1.12 0.99 1.00 1.22 100-pixel wide circle + 1.06 1.04 1.00 1.00 1.05 500-pixel wide circle + 1.87 1.84 1.00 1.00 1.85 100-pixel wide dashed circle + 1.90 1.93 1.01 1.01 1.90 100-pixel wide double-dashed circle + 2.13 1.43 1.00 1.00 2.32 10-pixel partial circle + 1.42 1.18 1.00 1.00 1.42 100-pixel partial circle + 1.92 1.85 1.01 1.01 1.89 10-pixel wide partial circle + 1.73 1.67 1.00 1.00 1.73 100-pixel wide partial circle + 1.36 1.95 1.00 1.00 2.64 1-pixel solid circle + 2.02 1.37 1.00 1.00 2.03 10-pixel solid circle + 1.19 1.09 1.00 1.00 1.19 100-pixel solid circle + 1.02 0.99 1.00 1.00 1.01 500-pixel solid circle + 1.74 1.28 1.00 0.88 1.73 10-pixel fill chord partial circle + 1.31 1.13 1.00 1.00 1.31 100-pixel fill chord partial circle + 1.67 1.31 1.03 1.03 1.72 10-pixel fill slice partial circle + 1.30 1.13 1.00 1.00 1.28 100-pixel fill slice partial circle + 2.45 1.49 1.01 1.00 2.71 10-pixel ellipse + 1.22 1.10 1.00 1.00 1.22 100-pixel ellipse + 1.09 1.04 1.00 1.00 1.09 500-pixel ellipse + 1.90 1.28 1.00 1.00 1.89 100-pixel dashed ellipse + 1.62 1.24 0.96 0.97 1.61 100-pixel double-dashed ellipse + 2.43 1.50 1.00 1.00 2.42 10-pixel wide ellipse + 1.61 1.28 1.03 1.03 1.60 100-pixel wide ellipse + 1.08 1.05 1.00 1.00 1.08 500-pixel wide ellipse + 1.93 1.88 1.00 1.00 1.88 100-pixel wide dashed ellipse + 1.94 1.89 1.01 1.00 1.94 100-pixel wide double-dashed ellipse + 2.31 1.48 1.00 1.00 2.67 10-pixel partial ellipse + 1.38 1.17 1.00 1.00 1.38 100-pixel partial ellipse + 2.00 1.85 0.98 0.97 1.98 10-pixel wide partial ellipse + 1.89 1.86 1.00 1.00 1.89 100-pixel wide partial ellipse + 3.49 1.60 1.00 1.00 3.65 10-pixel filled ellipse + 1.67 1.26 1.00 1.00 1.67 100-pixel filled ellipse + 1.06 1.04 1.00 1.00 1.06 500-pixel filled ellipse + 2.38 1.43 1.01 1.00 2.32 10-pixel fill chord partial ellipse + 2.06 1.30 1.00 1.00 2.05 100-pixel fill chord partial ellipse + 2.27 1.41 1.00 1.00 2.27 10-pixel fill slice partial ellipse + 1.98 1.33 1.00 0.97 1.97 100-pixel fill slice partial ellipse + 57.46 1.99 1.01 1.00 114.92 Fill 1x1 equivalent triangle + 56.94 1.98 1.01 1.00 73.89 Fill 10x10 equivalent triangle + 6.07 1.75 1.00 1.00 6.07 Fill 100x100 equivalent triangle + 51.12 1.98 1.00 1.00 102.81 Fill 1x1 trapezoid + 51.42 1.82 1.01 1.00 94.89 Fill 10x10 trapezoid + 6.47 1.80 1.00 1.00 6.44 Fill 100x100 trapezoid + 1.56 1.28 1.00 0.99 1.56 Fill 300x300 trapezoid + 51.27 1.97 0.96 0.97 102.54 Fill 1x1 stippled trapezoid (8x8 stipple) + 51.73 2.00 1.02 1.02 67.92 Fill 10x10 stippled trapezoid (8x8 stipple) + 5.36 1.72 1.00 1.00 5.36 Fill 100x100 stippled trapezoid (8x8 stipple) + 1.54 1.26 1.00 1.00 1.59 Fill 300x300 stippled trapezoid (8x8 stipple) + 51.41 1.94 1.01 1.00 102.82 Fill 1x1 opaque stippled trapezoid (8x8 stipple) + 50.71 1.95 0.99 1.00 65.44 Fill 10x10 opaque stippled trapezoid (8x8... + 5.33 1.73 1.00 1.00 5.36 Fill 100x100 opaque stippled trapezoid (8x8... + 1.58 1.25 1.00 1.00 1.58 Fill 300x300 opaque stippled trapezoid (8x8... + 51.56 1.96 0.99 0.90 103.68 Fill 1x1 tiled trapezoid (4x4 tile) + 51.59 1.99 1.01 1.01 62.25 Fill 10x10 tiled trapezoid (4x4 tile) + 5.38 1.72 1.00 1.00 5.38 Fill 100x100 tiled trapezoid (4x4 tile) + 1.54 1.25 1.00 0.99 1.58 Fill 300x300 tiled trapezoid (4x4 tile) + 51.70 1.98 1.01 1.01 103.98 Fill 1x1 stippled trapezoid (17x15 stipple) + 44.86 1.97 1.00 1.00 44.86 Fill 10x10 stippled trapezoid (17x15 stipple) + 2.74 1.56 1.00 1.00 2.73 Fill 100x100 stippled trapezoid (17x15 stipple) + 1.29 1.14 1.00 1.00 1.27 Fill 300x300 stippled trapezoid (17x15 stipple) + 51.41 1.96 0.96 0.95 103.39 Fill 1x1 opaque stippled trapezoid (17x15... + 45.14 1.96 1.01 1.00 45.14 Fill 10x10 opaque stippled trapezoid (17x15... + 2.68 1.56 1.00 1.00 2.68 Fill 100x100 opaque stippled trapezoid (17x15... + 1.26 1.10 1.00 1.00 1.28 Fill 300x300 opaque stippled trapezoid (17x15... + 51.13 1.97 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (17x15 tile) + 47.58 1.96 1.00 1.00 47.86 Fill 10x10 tiled trapezoid (17x15 tile) + 2.74 1.56 1.00 1.00 2.74 Fill 100x100 tiled trapezoid (17x15 tile) + 1.29 1.14 1.00 1.00 1.28 Fill 300x300 tiled trapezoid (17x15 tile) + 51.13 1.97 0.99 0.97 103.39 Fill 1x1 stippled trapezoid (161x145 stipple) + 45.14 1.97 1.00 1.00 44.29 Fill 10x10 stippled trapezoid (161x145 stipple) + 3.02 1.77 1.12 1.12 3.38 Fill 100x100 stippled trapezoid (161x145 stipple) + 1.31 1.13 1.00 1.00 1.30 Fill 300x300 stippled trapezoid (161x145 stipple) + 51.27 1.97 1.00 1.00 103.10 Fill 1x1 opaque stippled trapezoid (161x145... + 45.01 1.97 1.00 1.00 45.01 Fill 10x10 opaque stippled trapezoid (161x145... + 2.67 1.56 1.00 1.00 2.69 Fill 100x100 opaque stippled trapezoid (161x145.. + 1.29 1.13 1.00 1.01 1.27 Fill 300x300 opaque stippled trapezoid (161x145.. + 51.41 1.96 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (161x145 tile) + 45.01 1.96 0.98 1.00 45.01 Fill 10x10 tiled trapezoid (161x145 tile) + 2.62 1.36 1.00 1.00 2.69 Fill 100x100 tiled trapezoid (161x145 tile) + 1.27 1.13 1.00 1.00 1.22 Fill 300x300 tiled trapezoid (161x145 tile) + 51.13 1.98 1.00 1.00 103.39 Fill 1x1 tiled trapezoid (216x208 tile) + 45.14 1.97 1.01 0.99 45.14 Fill 10x10 tiled trapezoid (216x208 tile) + 2.62 1.55 1.00 1.00 2.71 Fill 100x100 tiled trapezoid (216x208 tile) + 1.28 1.13 1.00 1.00 1.20 Fill 300x300 tiled trapezoid (216x208 tile) + 50.71 1.95 1.00 1.00 54.70 Fill 10x10 equivalent complex polygon + 5.51 1.71 0.96 0.98 5.47 Fill 100x100 equivalent complex polygons + 8.39 1.97 1.00 1.00 16.75 Fill 10x10 64-gon (Convex) + 8.38 1.83 1.00 1.00 8.43 Fill 100x100 64-gon (Convex) + 8.50 1.96 1.00 1.00 16.64 Fill 10x10 64-gon (Complex) + 8.26 1.83 1.00 1.00 8.35 Fill 100x100 64-gon (Complex) + 14.09 1.87 1.00 1.00 14.05 Char in 80-char line (6x13) + 11.91 1.87 1.00 1.00 11.95 Char in 70-char line (8x13) + 11.16 1.85 1.01 1.00 11.10 Char in 60-char line (9x15) + 10.09 1.78 1.00 1.00 10.09 Char16 in 40-char line (k14) + 6.15 1.75 1.00 1.00 6.31 Char16 in 23-char line (k24) + 11.92 1.90 1.03 1.03 11.88 Char in 80-char line (TR 10) + 8.18 1.78 1.00 0.99 8.17 Char in 30-char line (TR 24) + 42.83 1.44 1.01 1.00 42.11 Char in 20/40/20 line (6x13, TR 10) + 27.45 1.43 1.01 1.01 27.45 Char16 in 7/14/7 line (k14, k24) + 12.13 1.85 1.00 1.00 12.05 Char in 80-char image line (6x13) + 10.00 1.84 1.00 1.00 10.00 Char in 70-char image line (8x13) + 9.18 1.83 1.00 1.00 9.12 Char in 60-char image line (9x15) + 9.66 1.82 0.98 0.95 9.66 Char16 in 40-char image line (k14) + 5.82 1.72 1.00 1.00 5.99 Char16 in 23-char image line (k24) + 8.70 1.80 1.00 1.00 8.65 Char in 80-char image line (TR 10) + 4.67 1.66 1.00 1.00 4.67 Char in 30-char image line (TR 24) + 84.43 1.47 1.00 1.00 124.18 Scroll 10x10 pixels + 3.73 1.50 1.00 0.98 3.73 Scroll 100x100 pixels + 1.00 1.00 1.00 1.00 1.00 Scroll 500x500 pixels + 84.43 1.51 1.00 1.00 134.02 Copy 10x10 from window to window + 3.62 1.51 0.98 0.98 3.62 Copy 100x100 from window to window + 0.89 1.00 1.00 1.00 1.00 Copy 500x500 from window to window + 57.06 1.99 1.00 1.00 88.64 Copy 10x10 from pixmap to window + 2.49 2.00 1.00 1.00 2.48 Copy 100x100 from pixmap to window + 1.00 0.91 1.00 1.00 0.98 Copy 500x500 from pixmap to window + 2.04 1.01 1.00 1.00 2.03 Copy 10x10 from window to pixmap + 1.05 1.00 1.00 1.00 1.05 Copy 100x100 from window to pixmap + 1.00 1.00 0.93 1.00 1.04 Copy 500x500 from window to pixmap + 58.52 1.03 1.03 1.02 57.95 Copy 10x10 from pixmap to pixmap + 2.40 1.00 1.00 1.00 2.45 Copy 100x100 from pixmap to pixmap + 1.00 1.00 1.00 1.00 1.00 Copy 500x500 from pixmap to pixmap + 51.57 1.92 1.00 1.00 85.75 Copy 10x10 1-bit deep plane + 6.37 1.75 1.01 1.01 6.37 Copy 100x100 1-bit deep plane + 1.26 1.11 1.00 1.00 1.24 Copy 500x500 1-bit deep plane + 4.23 1.63 0.98 0.97 4.38 Copy 10x10 n-bit deep plane + 1.04 1.02 1.00 1.00 1.04 Copy 100x100 n-bit deep plane + 1.00 1.00 1.00 1.00 1.00 Copy 500x500 n-bit deep plane + 6.45 1.98 1.00 1.26 12.80 PutImage 10x10 square + 1.10 1.87 1.00 1.83 2.11 PutImage 100x100 square + 1.02 1.93 1.00 1.91 1.91 PutImage 500x500 square + 4.17 1.78 1.00 1.40 7.18 PutImage XY 10x10 square + 1.27 1.49 0.97 1.48 2.10 PutImage XY 100x100 square + 1.00 1.50 1.00 1.50 1.52 PutImage XY 500x500 square + 1.07 1.01 1.00 1.00 1.06 GetImage 10x10 square + 1.01 1.00 1.00 1.00 1.01 GetImage 100x100 square + 1.00 1.00 1.00 1.00 1.00 GetImage 500x500 square + 1.56 1.00 0.99 0.97 1.56 GetImage XY 10x10 square + 1.02 1.00 1.00 1.00 1.02 GetImage XY 100x100 square + 1.00 1.00 1.00 1.00 1.00 GetImage XY 500x500 square + 1.00 1.00 1.01 0.98 0.95 X protocol NoOperation + 1.02 1.03 1.04 1.03 1.00 QueryPointer + 1.03 1.02 1.04 1.03 1.00 GetProperty +100.41 1.51 1.00 1.00 198.76 Change graphics context + 45.81 1.00 0.99 0.97 57.10 Create and map subwindows (4 kids) + 78.45 1.01 1.02 1.02 63.07 Create and map subwindows (16 kids) + 73.91 1.01 1.00 1.00 56.37 Create and map subwindows (25 kids) + 73.22 1.00 1.00 1.00 49.07 Create and map subwindows (50 kids) + 72.36 1.01 0.99 1.00 32.14 Create and map subwindows (75 kids) + 70.34 1.00 1.00 1.00 30.12 Create and map subwindows (100 kids) + 55.00 1.00 1.00 0.99 23.75 Create and map subwindows (200 kids) + 55.30 1.01 1.00 1.00 141.03 Create unmapped window (4 kids) + 55.38 1.01 1.01 1.00 163.25 Create unmapped window (16 kids) + 54.75 0.96 1.00 0.99 166.95 Create unmapped window (25 kids) + 54.83 1.00 1.00 0.99 178.81 Create unmapped window (50 kids) + 55.38 1.01 1.01 1.00 181.20 Create unmapped window (75 kids) + 55.38 1.01 1.01 1.00 181.20 Create unmapped window (100 kids) + 54.87 1.01 1.01 1.00 182.05 Create unmapped window (200 kids) + 28.13 1.00 1.00 1.00 30.75 Map window via parent (4 kids) + 36.14 1.01 1.01 1.01 32.58 Map window via parent (16 kids) + 26.13 1.00 0.98 0.95 29.85 Map window via parent (25 kids) + 40.07 1.00 1.01 1.00 27.57 Map window via parent (50 kids) + 23.26 0.99 1.00 1.00 18.23 Map window via parent (75 kids) + 22.91 0.99 1.00 0.99 16.52 Map window via parent (100 kids) + 27.79 1.00 1.00 0.99 12.50 Map window via parent (200 kids) + 22.35 1.00 1.00 1.00 56.19 Unmap window via parent (4 kids) + 9.57 1.00 0.99 1.00 89.78 Unmap window via parent (16 kids) + 80.77 1.01 1.00 1.00 103.85 Unmap window via parent (25 kids) + 96.34 1.00 1.00 1.00 116.06 Unmap window via parent (50 kids) + 99.72 1.00 1.00 1.00 124.93 Unmap window via parent (75 kids) +112.36 1.00 1.00 1.00 125.27 Unmap window via parent (100 kids) +105.41 1.00 1.00 0.99 120.00 Unmap window via parent (200 kids) + 51.29 1.03 1.02 1.02 74.19 Destroy window via parent (4 kids) + 86.75 0.99 0.99 0.99 116.87 Destroy window via parent (16 kids) +106.43 1.01 1.01 1.01 127.49 Destroy window via parent (25 kids) +120.34 1.01 1.01 1.00 140.11 Destroy window via parent (50 kids) +126.67 1.00 0.99 0.99 145.00 Destroy window via parent (75 kids) +126.11 1.01 1.01 1.00 140.56 Destroy window via parent (100 kids) +128.57 1.01 1.00 1.00 137.91 Destroy window via parent (200 kids) + 16.04 0.88 1.00 1.00 20.36 Hide/expose window via popup (4 kids) + 19.04 1.01 1.00 1.00 23.48 Hide/expose window via popup (16 kids) + 19.22 1.00 1.00 1.00 20.44 Hide/expose window via popup (25 kids) + 17.41 1.00 0.91 0.97 17.68 Hide/expose window via popup (50 kids) + 17.29 1.01 1.00 1.01 17.07 Hide/expose window via popup (75 kids) + 16.74 1.00 1.00 1.00 16.17 Hide/expose window via popup (100 kids) + 10.30 1.00 1.00 1.00 10.51 Hide/expose window via popup (200 kids) + 16.48 1.01 1.00 1.00 26.05 Move window (4 kids) + 17.01 0.95 1.00 1.00 23.97 Move window (16 kids) + 16.95 1.00 1.00 1.00 22.90 Move window (25 kids) + 16.05 1.01 1.00 1.00 21.32 Move window (50 kids) + 15.58 1.00 0.98 0.98 19.44 Move window (75 kids) + 14.98 1.02 1.03 1.03 18.17 Move window (100 kids) + 10.90 1.01 1.01 1.00 12.68 Move window (200 kids) + 49.42 1.00 1.00 1.00 198.27 Moved unmapped window (4 kids) + 50.72 0.97 1.00 1.00 193.66 Moved unmapped window (16 kids) + 50.87 1.00 0.99 1.00 195.09 Moved unmapped window (25 kids) + 50.72 1.00 1.00 1.00 189.34 Moved unmapped window (50 kids) + 50.87 1.00 1.00 1.00 191.33 Moved unmapped window (75 kids) + 50.87 1.00 1.00 0.90 186.71 Moved unmapped window (100 kids) + 50.87 1.00 1.00 1.00 179.19 Moved unmapped window (200 kids) + 41.04 1.00 1.00 1.00 56.61 Move window via parent (4 kids) + 69.81 1.00 1.00 1.00 130.82 Move window via parent (16 kids) + 95.81 1.00 1.00 1.00 141.92 Move window via parent (25 kids) + 95.98 1.00 1.00 1.00 149.43 Move window via parent (50 kids) + 96.59 1.01 1.01 1.00 153.98 Move window via parent (75 kids) + 97.19 1.00 1.00 1.00 157.30 Move window via parent (100 kids) + 96.67 1.00 0.99 0.96 159.44 Move window via parent (200 kids) + 17.75 1.01 1.00 1.00 27.61 Resize window (4 kids) + 17.94 1.00 1.00 0.99 25.42 Resize window (16 kids) + 17.92 1.01 1.00 1.00 24.47 Resize window (25 kids) + 17.24 0.97 1.00 1.00 24.14 Resize window (50 kids) + 16.81 1.00 1.00 0.99 22.75 Resize window (75 kids) + 16.08 1.00 1.00 1.00 21.20 Resize window (100 kids) + 12.92 1.00 0.99 1.00 16.26 Resize window (200 kids) + 52.94 1.01 1.00 1.00 327.12 Resize unmapped window (4 kids) + 53.60 1.01 1.01 1.01 333.71 Resize unmapped window (16 kids) + 52.99 1.00 1.00 1.00 337.29 Resize unmapped window (25 kids) + 51.98 1.00 1.00 1.00 329.38 Resize unmapped window (50 kids) + 53.05 0.89 1.00 1.00 322.60 Resize unmapped window (75 kids) + 53.05 1.00 1.00 1.00 318.08 Resize unmapped window (100 kids) + 53.11 1.00 1.00 0.99 306.21 Resize unmapped window (200 kids) + 16.76 1.00 0.96 1.00 19.46 Circulate window (4 kids) + 17.24 1.00 1.00 0.97 16.24 Circulate window (16 kids) + 16.30 1.03 1.03 1.03 15.85 Circulate window (25 kids) + 13.45 1.00 1.00 1.00 14.90 Circulate window (50 kids) + 12.91 1.00 1.00 1.00 13.06 Circulate window (75 kids) + 11.30 0.98 1.00 1.00 11.03 Circulate window (100 kids) + 7.58 1.01 1.01 0.99 7.47 Circulate window (200 kids) + 1.01 1.01 0.98 1.00 0.95 Circulate Unmapped window (4 kids) + 1.07 1.07 1.01 1.07 1.02 Circulate Unmapped window (16 kids) + 1.04 1.09 1.06 1.05 0.97 Circulate Unmapped window (25 kids) + 1.04 1.23 1.20 1.18 1.05 Circulate Unmapped window (50 kids) + 1.18 1.53 1.19 1.45 1.24 Circulate Unmapped window (75 kids) + 1.08 1.02 1.01 1.74 1.01 Circulate Unmapped window (100 kids) + 1.01 1.12 0.98 0.91 0.97 Circulate Unmapped window (200 kids) + </verb> + +<sect2>Profiling with OProfile + +<p>OProfile (available from http://oprofile.sourceforge.net/) is a +system-wide profiler for Linux systems that uses processor-level +counters to collect sampling data. OProfile can provide information +that is similar to that provided by <tt/gprof/, but without the +necessity of recompiling the program with special instrumentation (i.e., +OProfile can collect statistical profiling information about optimized +programs). A test harness was developed to collect OProfile data for +each <tt/x11perf/ test individually. + +<p>Test runs were performed using the RETIRED_INSNS counter on the AMD +Athlon and the CPU_CLK_HALTED counter on the Intel Pentium III (with a +test configuration different from the one described above). We have +examined OProfile output and have compared it with <tt/gprof/ output. +This investigation has not produced results that yield performance +increases in <tt/x11perf/ numbers. + +<!-- +<sect3>Retired Instructions + +<p>The initial tests using OProfile were done using the RETIRED_INSNS +counter with DMX running on the dual-processor AMD Athlon machine - the +same test configuration that was described above and that was used for +other tests. The RETIRED_INSNS counter counts retired instructions and +showed drawing, text, copying, and image tests to be dominated (> +30%) by calls to Hash(), SecurityLookupIDByClass(), +SecurityLookupIDByType(), and StandardReadRequestFromClient(). Some of +these tests also executed significant instructions in +WaitForSomething(). + +<p>In contrast, the window tests executed significant +instructions in SecurityLookupIDByType(), Hash(), +StandardReadRequestFromClient(), but also executed significant +instructions in other routines, such as ConfigureWindow(). Some time +was spent looking at Hash() function, but optimizations in this routine +did not lead to a dramatic increase in <tt/x11perf/ performance. +--> + +<!-- +<sect3>Clock Cycles + +<p>Retired instructions can be misleading because Intel/AMD instructions +execute in variable amounts of time. The OProfile tests were repeated +using the Intel CPU_CLK_HALTED counter with DMX running on the second +back-end machine. Note that this is a different test configuration that +the one described above. However, these tests show the amount of time +(as measured in CPU cycles) that are spent in each routine. Because +<tt/x11perf/ was running on the first back-end machine and because +window optimizations were on, the load on the second back-end machine +was not significant. + +<p>Using CPU_CLK_HALTED, DMX showed simple drawing +tests spending more than 10% of their time in +StandardReadRequestFromClient(), with significant time (> 20% total) +spent in SecurityLookupIDByClass(), WaitForSomething(), and Dispatch(). +For these tests, < 5% of the time was spent in Hash(), which explains +why optimizing the Hash() routine did not impact <tt/x11perf/ results. + +<p>The trapezoid, text, scrolling, copying, and image tests were +dominated by time in ProcFillPoly(), PanoramiXFillPoly(), dmxFillPolygon(), +SecurityLookupIDByClass(), SecurityLookupIDByType(), and +StandardReadRequestFromClient(). Hash() time was generally above 5% but +less than 10% of total time. +--> + +<sect2>X Test Suite + +<p>The X Test Suite was run on the fully optimized DMX server using the +configuration described above. The following failures were noted: + <verb> +XListPixmapFormats: Test 1 [1] +XChangeWindowAttributes: Test 32 [1] +XCreateWindow: Test 30 [1] +XFreeColors: Test 4 [3] +XCopyArea: Test 13, 17, 21, 25, 30 [2] +XCopyPlane: Test 11, 15, 27, 31 [2] +XSetFontPath: Test 4 [1] +XChangeKeyboardControl: Test 9, 10 [1] + +[1] Previously documented errors expected from the Xinerama + implementation (see Phase I discussion). +[2] Newly noted errors that have been verified as expected + behavior of the Xinerama implementation. +[3] Newly noted error that has been verified as a Xinerama + implementation bug. + </verb> + +<!-- ============================================================ --> +<sect1>Phase III + +<p>During the third phase of development, support was provided for the +following extensions: SHAPE, RENDER, XKEYBOARD, XInput. + +<sect2>SHAPE + +<p>The SHAPE extension is supported. Test applications (e.g., xeyes and +oclock) and window managers that make use of the SHAPE extension will +work as expected. + +<sect2>RENDER + +<p>The RENDER extension is supported. The version included in the DMX +CVS tree is version 0.2, and this version is fully supported by Xdmx. +Applications using only version 0.2 functions will work correctly; +however, some apps that make use of functions from later versions do not +properly check the extension's major/minor version numbers. These apps +will fail with a Bad Implementation error when using post-version 0.2 +functions. This is expected behavior. When the DMX CVS tree is updated +to include newer versions of RENDER, support for these newer functions +will be added to the DMX X server. + +<sect2>XKEYBOARD + +<p>The XKEYBOARD extension is supported. If present on the back-end X +servers, the XKEYBOARD extension will be used to obtain information +about the type of the keyboard for initialization. Otherwise, the +keyboard will be initialized using defaults. Note that this departs +from older behavior: when Xdmx is compiled without XKEYBOARD support, +the map from the back-end X server will be preserved. With XKEYBOARD +support, the map is not preserved because better information and control +of the keyboard is available. + +<sect2>XInput + +<p>The XInput extension is supported. Any device can be used as a core +device and be used as an XInput extension device, with the exception of +core devices on the back-end servers. This limitation is present +because cursor handling on the back-end requires that the back-end +cursor sometimes track the Xdmx core cursor -- behavior that is +incompatible with using the back-end pointer as a non-core device. + +<p>Currently, back-end extension devices are not available as Xdmx +extension devices, but this limitation should be removed in the future. + +<p>To demonstrate the XInput extension, and to provide more examples for +low-level input device driver writers, USB device drivers have been +written for mice (usb-mou), keyboards (usb-kbd), and +non-mouse/non-keyboard USB devices (usb-oth). Please see the man page +for information on Linux kernel drivers that are required for using +these Xdmx drivers. + +<sect2>DPMS + +<p>The DPMS extension is exported but does not do anything at this time. + +<sect2>Other Extensions + +<p>The LBX, + SECURITY, + XC-APPGROUP, and + XFree86-Bigfont +extensions do not require any special Xdmx support and have been exported. + +<p>The + BIG-REQUESTS, + DEC-XTRAP, + DOUBLE-BUFFER, + Extended-Visual-Information, + FontCache, + GLX, + MIT-SCREEN-SAVER, + MIT-SHM, + MIT-SUNDRY-NONSTANDARD, + RECORD, + SECURITY, + SGI-GLX, + SYNC, + TOG-CUP, + X-Resource, + XC-MISC, + XFree86-DGA, + XFree86-DRI, + XFree86-Misc, + XFree86-VidModeExtension, and + XVideo +extensions are <it/not/ supported at this time, but will be evaluated +for inclusion in future DMX releases. <bf>See below for additional work +on extensions after Phase III.</bf> + +<sect1>Phase IV + +<sect2>Moving to XFree86 4.3.0 + +<p>For Phase IV, the recent release of XFree86 4.3.0 (27 February 2003) +was merged onto the dmx.sourceforge.net CVS trunk and all work is +proceeding using this tree. + +<sect2>Extensions + +<sect3>XC-MISC (supported) + +<p>XC-MISC is used internally by the X library to recycle XIDs from the +X server. This is important for long-running X server sessions. Xdmx +supports this extension. The X Test Suite passed and failed the exact +same tests before and after this extension was enabled. +<!-- Tested February/March 2003 --> + +<sect3>Extended-Visual-Information (supported) + +<p>The Extended-Visual-Information extension provides a method for an X +client to obtain detailed visual information. Xdmx supports this +extension. It was tested using the <tt>hw/dmx/examples/evi</tt> example +program. <bf/Note that this extension is not Xinerama-aware/ -- it will +return visual information for each screen even though Xinerama is +causing the X server to export a single logical screen. +<!-- Tested March 2003 --> + +<sect3>RES (supported) + +<p>The X-Resource extension provides a mechanism for a client to obtain +detailed information about the resources used by other clients. This +extension was tested with the <tt>hw/dmx/examples/res</tt> program. The +X Test Suite passed and failed the exact same tests before and after +this extension was enabled. +<!-- Tested March 2003 --> + +<sect3>BIG-REQUESTS (supported) + +<p>This extension enables the X11 protocol to handle requests longer +than 262140 bytes. The X Test Suite passed and failed the exact same +tests before and after this extension was enabled. +<!-- Tested March 2003 --> + +<sect3>XSYNC (supported) + +<p>This extension provides facilities for two different X clients to +synchronize their requests. This extension was minimally tested with +<tt/xdpyinfo/ and the X Test Suite passed and failed the exact same +tests before and after this extension was enabled. +<!-- Tested March 2003 --> + +<sect3>XTEST, RECORD, DEC-XTRAP (supported) and XTestExtension1 (not supported) + +<p>The XTEST and RECORD extension were developed by the X Consortium for +use in the X Test Suite and are supported as a standard in the X11R6 +tree. They are also supported in Xdmx. When X Test Suite tests that +make use of the XTEST extension are run, Xdmx passes and fails exactly +the same tests as does a standard XFree86 X server. When the +<tt/rcrdtest/ test (a part of the X Test Suite that verifies the RECORD +extension) is run, Xdmx passes and fails exactly the same tests as does +a standard XFree86 X server. <!-- Tested February/March 2003 --> + +<p>There are two older XTEST-like extensions: DEC-XTRAP and +XTestExtension1. The XTestExtension1 extension was developed for use by +the X Testing Consortium for use with a test suite that eventually +became (part of?) the X Test Suite. Unlike XTEST, which only allows +events to be sent to the server, the XTestExtension1 extension also +allowed events to be recorded (similar to the RECORD extension). The +second is the DEC-XTRAP extension that was developed by the Digital +Equipment Corporation. + +<p>The DEC-XTRAP extension is available from Xdmx and has been tested +with the <tt/xtrap*/ tools which are distributed as standard X11R6 +clients. <!-- Tested March 2003 --> + +<p>The XTestExtension1 is <em/not/ supported because it does not appear +to be used by any modern X clients (the few that support it also support +XTEST) and because there are no good methods available for testing that +it functions correctly (unlike XTEST and DEC-XTRAP, the code for +XTestExtension1 is not part of the standard X server source tree, so +additional testing is important). <!-- Tested March 2003 --> + +<p>Most of these extensions are documented in the X11R6 source tree. +Further, several original papers exist that this author was unable to +locate -- for completeness and historical interest, citations are +provide: +<descrip> +<tag/XRECORD/ Martha Zimet. Extending X For Recording. 8th Annual X +Technical Conference Boston, MA January 24-26, 1994. +<tag/DEC-XTRAP/ Dick Annicchiarico, Robert Chesler, Alan Jamison. XTrap +Architecture. Digital Equipment Corporation, July 1991. +<tag/XTestExtension1/ Larry Woestman. X11 Input Synthesis Extension +Proposal. Hewlett Packard, November 1991. +</descrip> + +<sect3>MIT-MISC (not supported) + +<p>The MIT-MISC extension is used to control a bug-compatibility flag +that provides compatibility with xterm programs from X11R1 and X11R2. +There does not appear to be a single client available that makes use of +this extension and there is not way to verify that it works correctly. +The Xdmx server does <em/not/ support MIT-MISC. + +<sect3>SCREENSAVER (not supported) + +<p>This extension provides special support for the X screen saver. It +was tested with beforelight, which appears to be the only client that +works with it. When Xinerama was not active, <tt/beforelight/ behaved +as expected. However, when Xinerama was active, <tt/beforelight/ did +not behave as expected. Further, when this extension is not active, +<tt/xscreensaver/ (a widely-used X screen saver program) did not behave +as expected. Since this extension is not Xinerama-aware and is not +commonly used with expected results by clients, we have left this +extension disabled at this time. + +<sect3>GLX (supported) + +<p>The GLX extension provides OpenGL and GLX windowing support. In +Xdmx, the extension is called glxProxy, and it is Xinerama aware. It +works by either feeding requests forward through Xdmx to each of the +back-end servers or handling them locally. All rendering requests are +handled on the back-end X servers. This code was donated to the DMX +project by SGI. For the X Test Suite results comparison, see below. + +<sect3>RENDER (supported) + +<p>The X Rendering Extension (RENDER) provides support for digital image +composition. Geometric and text rendering are supported. RENDER is +partially Xinerama-aware, with text and the most basic compositing +operator; however, its higher level primitives (triangles, triangle +strips, and triangle fans) are not yet Xinerama-aware. The RENDER +extension is still under development, and is currently at version 0.8. +Additional support will be required in DMX as more primitives and/or +requests are added to the extension. + +<p>There is currently no test suite for the X Rendering Extension; +however, there has been discussion of developing a test suite as the +extension matures. When that test suite becomes available, additional +testing can be performed with Xdmx. The X Test Suite passed and failed +the exact same tests before and after this extension was enabled. + +<sect3>Summary + +<!-- WARNING: this list is duplicated in the "Common X extension +support" section --> +<p>To summarize, the following extensions are currently supported: + BIG-REQUESTS, + DEC-XTRAP, + DMX, + DPMS, + Extended-Visual-Information, + GLX, + LBX, + RECORD, + RENDER, + SECURITY, + SHAPE, + SYNC, + X-Resource, + XC-APPGROUP, + XC-MISC, + XFree86-Bigfont, + XINERAMA, + XInputExtension, + XKEYBOARD, and + XTEST. + +<p>The following extensions are <em/not/ supported at this time: + DOUBLE-BUFFER, + FontCache, + MIT-SCREEN-SAVER, + MIT-SHM, + MIT-SUNDRY-NONSTANDARD, + TOG-CUP, + XFree86-DGA, + XFree86-Misc, + XFree86-VidModeExtension, + XTestExtensionExt1, and + XVideo. + +<sect2>Additional Testing with the X Test Suite + +<sect3>XFree86 without XTEST + +<p>After the release of XFree86 4.3.0, we retested the XFree86 X server +with and without using the XTEST extension. When the XTEST extension +was <em/not/ used for testing, the XFree86 4.3.0 server running on our +usual test system with a Radeon VE card reported unexpected failures in +the following tests: +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XGetDefault: Test 5 +XRebindKeysym: Test 1 +</verb> + +<sect3>XFree86 with XTEST + +<p>When using the XTEST extension, the XFree86 4.3.0 server reported the +following errors: +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XGetDefault: Test 5 +XRebindKeysym: Test 1 + +XAllowEvents: Tests 20, 21, 24 +XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 +XGrabKey: Test 8 +XSetPointerMapping: Test 3 +XUngrabButton: Test 4 +</verb> + +<p>While these errors may be important, they will probably be fixed +eventually in the XFree86 source tree. We are particularly interested +in demonstrating that the Xdmx server does not introduce additional +failures that are not known Xinerama failures. + +<sect3>Xdmx with XTEST, without Xinerama, without GLX + +<p>Without Xinerama, but using the XTEST extension, the following errors +were reported from Xdmx (note that these are the same as for the XFree86 +4.3.0, except that XGetDefault no longer fails): +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XRebindKeysym: Test 1 + +XAllowEvents: Tests 20, 21, 24 +XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 +XGrabKey: Test 8 +XSetPointerMapping: Test 3 +XUngrabButton: Test 4 +</verb> + +<sect3>Xdmx with XTEST, with Xinerama, without GLX + +<p>With Xinerama, using the XTEST extension, the following errors +were reported from Xdmx: +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XRebindKeysym: Test 1 + +XAllowEvents: Tests 20, 21, 24 +XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 +XGrabKey: Test 8 +XSetPointerMapping: Test 3 +XUngrabButton: Test 4 + +XCopyPlane: Tests 13, 22, 31 (well-known XTEST/Xinerama interaction issue) +XDrawLine: Test 67 +XDrawLines: Test 91 +XDrawSegments: Test 68 +</verb> +Note that the first two sets of errors are the same as for the XFree86 +4.3.0 server, and that the XCopyPlane error is a well-known error +resulting from an XTEST/Xinerama interaction when the request crosses a +screen boundary. The XDraw* errors are resolved when the tests are run +individually and they do not cross a screen boundary. We will +investigate these errors further to determine their cause. + +<sect3>Xdmx with XTEST, with Xinerama, with GLX + +<p>With GLX enabled, using the XTEST extension, the following errors +were reported from Xdmx (these results are from early during the Phase +IV development, but were confirmed with a late Phase IV snapshot): +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XRebindKeysym: Test 1 + +XAllowEvents: Tests 20, 21, 24 +XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 +XGrabKey: Test 8 +XSetPointerMapping: Test 3 +XUngrabButton: Test 4 + +XClearArea: Test 8 +XCopyArea: Tests 4, 5, 11, 14, 17, 23, 25, 27, 30 +XCopyPlane: Tests 6, 7, 10, 19, 22, 31 +XDrawArcs: Tests 89, 100, 102 +XDrawLine: Test 67 +XDrawSegments: Test 68 +</verb> +Note that the first two sets of errors are the same as for the XFree86 +4.3.0 server, and that the third set has different failures than when +Xdmx does not include GLX support. Since the GLX extension adds new +visuals to support GLX's visual configs and the X Test Suite runs tests +over the entire set of visuals, additional rendering tests were run and +presumably more of them crossed a screen boundary. This conclusion is +supported by the fact that nearly all of the rendering errors reported +are resolved when the tests are run individually and they do no cross a +screen boundary. + +<p>Further, when hardware rendering is disabled on the back-end displays, +many of the errors in the third set are eliminated, leaving only: +<verb> +XClearArea: Test 8 +XCopyArea: Test 4, 5, 11, 14, 17, 23, 25, 27, 30 +XCopyPlane: Test 6, 7, 10, 19, 22, 31 +</verb> + +<sect3>Conclusion + +<p>We conclude that all of the X Test Suite errors reported for Xdmx are +the result of errors in the back-end X server or the Xinerama +implementation. Further, all of these errors that can be reasonably +fixed at the Xdmx layer have been. (Where appropriate, we have +submitted patches to the XFree86 and Xinerama upstream maintainers.) + +<sect2>Dynamic Reconfiguration + +<p>During this development phase, dynamic reconfiguration support was +added to DMX. This support allows an application to change the position +and offset of a back-end server's screen. For example, if the +application would like to shift a screen slightly to the left, it could +query Xdmx for the screen's <x,y> position and then dynamically +reconfigure that screen to be at position <x+10,y>. When a screen +is dynamically reconfigured, input handling and a screen's root window +dimensions are adjusted as needed. These adjustments are transparent to +the user. + +<sect3>Dynamic reconfiguration extension + +<p>The application interface to DMX's dynamic reconfiguration is through +a function in the DMX extension library: +<verb> +Bool DMXReconfigureScreen(Display *dpy, int screen, int x, int y) +</verb> +where <it/dpy/ is DMX server's display, <it/screen/ is the number of the +screen to be reconfigured, and <it/x/ and <it/y/ are the new upper, +left-hand coordinates of the screen to be reconfigured. + +<p>The coordinates are not limited other than as required by the X +protocol, which limits all coordinates to a signed 16 bit number. In +addition, all coordinates within a screen must also be legal values. +Therefore, setting a screen's upper, left-hand coordinates such that the +right or bottom edges of the screen is greater than 32,767 is illegal. + +<sect3>Bounding box + +<p>When the Xdmx server is started, a bounding box is calculated from +the screens' layout given either on the command line or in the +configuration file. This bounding box is currently fixed for the +lifetime of the Xdmx server. + +<p>While it is possible to move a screen outside of the bounding box, it +is currently not possible to change the dimensions of the bounding box. +For example, it is possible to specify coordinates of <-100,-100> +for the upper, left-hand corner of the bounding box, which was +previously at coordinates <0,0>. As expected, the screen is moved +down and to the right; however, since the bounding box is fixed, the +left side and upper portions of the screen exposed by the +reconfiguration are no longer accessible on that screen. Those +inaccessible regions are filled with black. + +<p>This fixed bounding box limitation will be addressed in a future +development phase. + +<sect3>Sample applications + +<p>An example of where this extension is useful is in setting up a video +wall. It is not always possible to get everything perfectly aligned, +and sometimes the positions are changed (e.g., someone might bump into a +projector). Instead of physically moving projectors or monitors, it is +now possible to adjust the positions of the back-end server's screens +using the dynamic reconfiguration support in DMX. + +<p>Other applications, such as automatic setup and calibration tools, +can make use of dynamic reconfiguration to correct for projector +alignment problems, as long as the projectors are still arranged +rectilinearly. Horizontal and vertical keystone correction could be +applied to projectors to correct for non-rectilinear alignment problems; +however, this must be done external to Xdmx. + +<p>A sample test program is included in the DMX server's examples +directory to demonstrate the interface and how an application might use +dynamic reconfiguration. See <tt/dmxreconfig.c/ for details. + +<sect3>Additional notes + +<p>In the original development plan, Phase IV was primarily devoted to +adding OpenGL support to DMX; however, SGI became interested in the DMX +project and developed code to support OpenGL/GLX. This code was later +donated to the DMX project and integrated into the DMX code base, which +freed the DMX developers to concentrate on dynamic reconfiguration (as +described above). + +<sect2>Doxygen documentation + +<p>Doxygen is an open-source (GPL) documentation system for generating +browseable documentation from stylized comments in the source code. We +have placed all of the Xdmx server and DMX protocol source code files +under Doxygen so that comprehensive documentation for the Xdmx source +code is available in an easily browseable format. + +<sect2>Valgrind + +<p>Valgrind, an open-source (GPL) memory debugger for Linux, was used to +search for memory management errors. Several memory leaks were detected +and repaired. The following errors were not addressed: +<enum> + <item> + When the X11 transport layer sends a reply to the client, only + those fields that are required by the protocol are filled in -- + unused fields are left as uninitialized memory and are therefore + noted by valgrind. These instances are not errors and were not + repaired. + <item> + At each server generation, glxInitVisuals allocates memory that + is never freed. The amount of memory lost each generation + approximately equal to 128 bytes for each back-end visual. + Because the code involved is automatically generated, this bug + has not been fixed and will be referred to SGI. + <item> + At each server generation, dmxRealizeFont calls XLoadQueryFont, + which allocates a font structure that is not freed. + dmxUnrealizeFont can free the font structure for the first + screen, but cannot free it for the other screens since they are + already closed by the time dmxUnrealizeFont could free them. + The amount of memory lost each generation is approximately equal + to 80 bytes per font per back-end. When this bug is fixed in + the the X server's device-independent (dix) code, DMX will be + able to properly free the memory allocated by XLoadQueryFont. +</enum> + +<sect2>RATS + +<p>RATS (Rough Auditing Tool for Security) is an open-source (GPL) +security analysis tool that scans source code for common +security-related programming errors (e.g., buffer overflows and TOCTOU +races). RATS was used to audit all of the code in the hw/dmx directory +and all "High" notations were checked manually. The code was either +re-written to eliminate the warning, or a comment containing "RATS" was +inserted on the line to indicate that a human had checked the code. +Unrepaired warnings are as follows: +<enum> + <item> + Fixed-size buffers are used in many areas, but code has been + added to protect against buffer overflows (e.g., XmuSnprint). + The only instances that have not yet been fixed are in + config/xdmxconfig.c (which is not part of the Xdmx server) and + input/usb-common.c. + <item> + vprintf and vfprintf are used in the logging routines. In + general, all uses of these functions (e.g., dmxLog) provide a + constant format string from a trusted source, so the use is + relatively benign. + <item> + glxProxy/glxscreens.c uses getenv and strcat. The use of these + functions is safe and will remain safe as long as + ExtensionsString is longer then GLXServerExtensions (ensuring + this may not be ovious to the casual programmer, but this is in + automatically generated code, so we hope that the generator + enforces this constraint). +</enum> + + </article> + + <!-- Local Variables: --> + <!-- fill-column: 72 --> + <!-- End: --> diff --git a/xorg-server/hw/dmx/glxProxy/glxcmds.c b/xorg-server/hw/dmx/glxProxy/glxcmds.c index 31fd431e7..a2fe0b27b 100644 --- a/xorg-server/hw/dmx/glxProxy/glxcmds.c +++ b/xorg-server/hw/dmx/glxProxy/glxcmds.c @@ -1,3610 +1,3610 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxfont.h" -#include "dmxsync.h" - -#undef Xmalloc -#undef Xcalloc -#undef Xrealloc -#undef Xfree - -#include "glxserver.h" -#include <GL/glxtokens.h> -#include "g_disptab.h" -#include <pixmapstr.h> -#include <windowstr.h> -#include "glxutil.h" -#include "glxext.h" -#include "unpack.h" - -#include "GL/glxproto.h" -#include "glxvendor.h" -#include "glxvisuals.h" -#include "glxswap.h" - -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -extern __GLXFBConfig **__glXFBConfigs; -extern int __glXNumFBConfigs; - -extern __GLXFBConfig *glxLookupFBConfig( GLXFBConfigID id ); -extern __GLXFBConfig *glxLookupFBConfigByVID( VisualID vid ); -extern __GLXFBConfig *glxLookupBackEndFBConfig( GLXFBConfigID id, int screen ); -extern int glxIsExtensionSupported( char *ext ); -extern int __glXGetFBConfigsSGIX(__GLXclientState *cl, GLbyte *pc); - -#define BE_TO_CLIENT_ERROR(x) \ - ( (x) >= __glXerrorBase ? \ - (x) - dmxScreen->glxErrorBase + __glXerrorBase \ - : (x) ) - -Display *GetBackEndDisplay( __GLXclientState *cl, int s ) -{ - if (! cl->be_displays[s] ) { - cl->be_displays[s] = XOpenDisplay( DisplayString(dmxScreens[s].beDisplay) ); - } - return( cl->be_displays[s] ); -} - -/* -** Create a GL context with the given properties. -*/ -static int CreateContext(__GLXclientState *cl, - GLXContextID gcId, - VisualID vid, GLXFBConfigID fbconfigId, - int screen, - GLXContextID shareList, - int isDirect ) -{ - ClientPtr client = cl->client; - xGLXCreateContextReq *be_req; - xGLXCreateNewContextReq *be_new_req; - VisualPtr pVisual; - ScreenPtr pScreen; - __GLXcontext *glxc, *shareglxc; - __GLXvisualConfig *pGlxVisual; - __GLXscreenInfo *pGlxScreen; - VisualID visual = vid; - GLint i; - int from_screen = screen; - int to_screen = screen; - DMXScreenInfo *dmxScreen; - VisualID be_vid; - GLXFBConfigID be_fbconfigId; - int num_be_screens; - Display *dpy; - - /* - ** Check if screen exists. - */ - if (screen >= screenInfo.numScreens) { - client->errorValue = screen; - return BadValue; - } - - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - /* - ** Find the display list space that we want to share. - ** - */ - if (shareList == None) { - shareglxc = NULL; - } else { - shareglxc = (__GLXcontext *) LookupIDByType(shareList, __glXContextRes); - if (!shareglxc) { - client->errorValue = shareList; - return __glXBadContext; - } - } - - /* - ** Allocate memory for the new context - */ - glxc = __glXCalloc(1, sizeof(__GLXcontext)); - if (!glxc) { - return BadAlloc; - } - - pScreen = screenInfo.screens[screen]; - pGlxScreen = &__glXActiveScreens[screen]; - - if (fbconfigId != None) { - glxc->pFBConfig = glxLookupFBConfig( fbconfigId ); - if (!glxc->pFBConfig) { - client->errorValue = fbconfigId; - __glXFree( glxc ); - return BadValue; - } - visual = glxc->pFBConfig->associatedVisualId; - } - else { - glxc->pFBConfig = NULL; - } - - if (visual != None) { - /* - ** Check if the visual ID is valid for this screen. - */ - pVisual = pScreen->visuals; - for (i = 0; i < pScreen->numVisuals; i++, pVisual++) { - if (pVisual->vid == visual) { - break; - } - } - if (i == pScreen->numVisuals) { - client->errorValue = visual; - __glXFree( glxc ); - return BadValue; - } - - pGlxVisual = pGlxScreen->pGlxVisual; - for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { - if (pGlxVisual->vid == visual) { - break; - } - } - if (i == pGlxScreen->numVisuals) { - /* - ** Visual not support on this screen by this OpenGL implementation. - */ - client->errorValue = visual; - __glXFree( glxc ); - return BadValue; - } - - if ( glxc->pFBConfig == NULL ) { - glxc->pFBConfig = glxLookupFBConfigByVID( visual ); - - if ( glxc->pFBConfig == NULL ) { - /* - * visual does not have an FBConfig ??? - client->errorValue = visual; - __glXFree( glxc ); - return BadValue; - */ - } - } - } - else { - pVisual = NULL; - pGlxVisual = NULL; - } - - glxc->pScreen = pScreen; - glxc->pGlxScreen = pGlxScreen; - glxc->pVisual = pVisual; - glxc->pGlxVisual = pGlxVisual; - - /* - * allocate memory for back-end servers info - */ - num_be_screens = to_screen - from_screen + 1; - glxc->real_ids = (XID *)__glXMalloc(sizeof(XID) * num_be_screens); - if (!glxc->real_ids) { - return BadAlloc; - } - glxc->real_vids = (XID *)__glXMalloc(sizeof(XID) * num_be_screens); - if (!glxc->real_vids) { - return BadAlloc; - } - - for (screen = from_screen; screen <= to_screen; screen++) { - int sent = 0; - pScreen = screenInfo.screens[screen]; - pGlxScreen = &__glXActiveScreens[screen]; - dmxScreen = &dmxScreens[screen]; - - if (glxc->pFBConfig) { - __GLXFBConfig *beFBConfig = glxLookupBackEndFBConfig( glxc->pFBConfig->id, - screen ); - be_fbconfigId = beFBConfig->id; - } - - if (pGlxVisual) { - - be_vid = glxMatchGLXVisualInConfigList( pGlxVisual, - dmxScreen->glxVisuals, - dmxScreen->numGlxVisuals ); - - if (!be_vid) { - /* visual is not supported on the back-end server */ - __glXFree( glxc->real_ids ); - __glXFree( glxc->real_vids ); - __glXFree( glxc ); - return BadValue; - } - } - - glxc->real_ids[screen-from_screen] = XAllocID(GetBackEndDisplay(cl,screen)); - - /* send the create context request to the back-end server */ - dpy = GetBackEndDisplay(cl,screen); - if (glxc->pFBConfig) { - /*Since for a certain visual both RGB and COLOR INDEX - *can be on then the only parmeter to choose the renderType - * should be the class of the colormap since all 4 first - * classes does not support RGB mode only COLOR INDEX , - * and so TrueColor and DirectColor does not support COLOR INDEX*/ - int renderType = glxc->pFBConfig->renderType; - if ( pVisual ) { - switch ( pVisual->class ){ - case PseudoColor: - case StaticColor: - case GrayScale: - case StaticGray: - renderType = GLX_COLOR_INDEX_TYPE; - break; - case TrueColor: - case DirectColor: - default: - renderType = GLX_RGBA_TYPE; - break; - } - } - if ( __GLX_IS_VERSION_SUPPORTED(1,3) ) { - LockDisplay(dpy); - GetReq(GLXCreateNewContext,be_new_req); - be_new_req->reqType = dmxScreen->glxMajorOpcode; - be_new_req->glxCode = X_GLXCreateNewContext; - be_new_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; - be_new_req->fbconfig = (unsigned int)be_fbconfigId; - be_new_req->screen = DefaultScreen(dpy); - be_new_req->renderType = renderType; - - be_new_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); - be_new_req->isDirect = 0; - UnlockDisplay(dpy); - glxc->real_vids[screen-from_screen] = be_fbconfigId; - sent = 1; - } - else if (glxIsExtensionSupported("GLX_SGIX_fbconfig")) { - - xGLXCreateContextWithConfigSGIXReq *ext_req; - xGLXVendorPrivateReq *vpreq; - LockDisplay(dpy); - GetReqExtra(GLXVendorPrivate, - sz_xGLXCreateContextWithConfigSGIXReq - sz_xGLXVendorPrivateReq, - vpreq); - ext_req = (xGLXCreateContextWithConfigSGIXReq *)vpreq; - ext_req->reqType = dmxScreen->glxMajorOpcode; - ext_req->glxCode = X_GLXVendorPrivate; - ext_req->vendorCode = X_GLXvop_CreateContextWithConfigSGIX; - ext_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; - ext_req->fbconfig = (unsigned int)be_fbconfigId; - ext_req->screen = DefaultScreen(dpy); - ext_req->renderType = renderType; - ext_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); - ext_req->isDirect = 0; - UnlockDisplay(dpy); - glxc->real_vids[screen-from_screen] = be_fbconfigId; - sent = 1; - } - } - - if (!sent) { - LockDisplay(dpy); - GetReq(GLXCreateContext,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXCreateContext; - be_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; - be_req->visual = (unsigned int)be_vid; - be_req->screen = DefaultScreen(dpy); - be_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); - be_req->isDirect = 0; - UnlockDisplay(dpy); - glxc->real_vids[screen-from_screen] = be_vid; - } - SyncHandle(); - - } - - /* - ** Register this context as a resource. - */ - if (!AddResource(gcId, __glXContextRes, (pointer)glxc)) { - __glXFree( glxc->real_ids ); - __glXFree( glxc->real_vids ); - __glXFree( glxc ); - client->errorValue = gcId; - return BadAlloc; - } - - /* - ** Finally, now that everything is working, setup the rest of the - ** context. - */ - glxc->id = gcId; - glxc->share_id = shareList; - glxc->idExists = GL_TRUE; - glxc->isCurrent = GL_FALSE; - - return Success; -} - -int __glXCreateContext(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; - - return( CreateContext(cl, req->context,req->visual, None, - req->screen, req->shareList, req->isDirect) ); - -} - -int __glXCreateNewContext(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc; - - return( CreateContext(cl, req->context,None, req->fbconfig, - req->screen, req->shareList, req->isDirect) ); - -} - -int __glXCreateContextWithConfigSGIX(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateContextWithConfigSGIXReq *req = (xGLXCreateContextWithConfigSGIXReq *) pc; - - return( CreateContext(cl, req->context, None, req->fbconfig, - req->screen, req->shareList, req->isDirect) ); - -} - -int __glXQueryMaxSwapBarriersSGIX(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXQueryMaxSwapBarriersSGIXReq *req = - (xGLXQueryMaxSwapBarriersSGIXReq *)pc; - xGLXQueryMaxSwapBarriersSGIXReply reply; - - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = 0; - reply.max = QueryMaxSwapBarriersSGIX(req->screen); - - if (client->swapped) { - __glXSwapQueryMaxSwapBarriersSGIXReply(client, &reply); - } else { - WriteToClient(client, sz_xGLXQueryMaxSwapBarriersSGIXReply, - (char *)&reply); - } - - return Success; -} - -int __glXBindSwapBarrierSGIX(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXBindSwapBarrierSGIXReq *req = (xGLXBindSwapBarrierSGIXReq *)pc; - DrawablePtr pDraw; - __GLXpixmap *pGlxPixmap = NULL; - __glXWindow *pGlxWindow = NULL; - int rc; - - rc = dixLookupDrawable(&pDraw, req->drawable, client, 0, DixGetAttrAccess); - if (rc != Success) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->drawable, - __glXPixmapRes); - if (pGlxPixmap) pDraw = pGlxPixmap->pDraw; - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(req->drawable, - __glXWindowRes); - if (pGlxWindow) pDraw = pGlxWindow->pDraw; - } - - if (!pDraw) { - client->errorValue = req->drawable; - return __glXBadDrawable; - } - - return BindSwapBarrierSGIX(pDraw, req->barrier); -} - -int __glXJoinSwapGroupSGIX(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXJoinSwapGroupSGIXReq *req = (xGLXJoinSwapGroupSGIXReq *)pc; - DrawablePtr pDraw, pMember = NULL; - __GLXpixmap *pGlxPixmap = NULL; - __glXWindow *pGlxWindow = NULL; - int rc; - - rc = dixLookupDrawable(&pDraw, req->drawable, client, 0, DixManageAccess); - if (rc != Success) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->drawable, - __glXPixmapRes); - if (pGlxPixmap) pDraw = pGlxPixmap->pDraw; - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(req->drawable, - __glXWindowRes); - if (pGlxWindow) pDraw = pGlxWindow->pDraw; - } - - if (!pDraw) { - client->errorValue = req->drawable; - return __glXBadDrawable; - } - - if (req->member != None) { - rc = dixLookupDrawable(&pMember, req->member, client, 0, - DixGetAttrAccess); - if (rc != Success) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->member, - __glXPixmapRes); - if (pGlxPixmap) pMember = pGlxPixmap->pDraw; - } - - if (!pMember && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(req->member, - __glXWindowRes); - if (pGlxWindow) pMember = pGlxWindow->pDraw; - } - - if (!pMember) { - client->errorValue = req->member; - return __glXBadDrawable; - } - } - - return JoinSwapGroupSGIX(pDraw, pMember); -} - - -/* -** Destroy a GL context as an X resource. -*/ -int __glXDestroyContext(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc; - xGLXDestroyContextReq *be_req; - GLXContextID gcId = req->context; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int s; - - glxc = (__GLXcontext *) LookupIDByType(gcId, __glXContextRes); - if (glxc) { - /* - ** Just free the resource; don't actually destroy the context, - ** because it might be in use. The - ** destroy method will be called by the resource destruction routine - ** if necessary. - */ - FreeResourceByType(gcId, __glXContextRes, FALSE); - - from_screen = to_screen = glxc->pScreen->myNum; - - } else { - client->errorValue = gcId; - return __glXBadContext; - } - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - /* - * send DestroyContext request to all back-end servers - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXDestroyContext,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXDestroyContext; - be_req->context = glxc->real_ids[s-from_screen]; - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -/*****************************************************************************/ - -/* -** For each client, the server keeps a table of all the contexts that are -** current for that client (each thread of a client may have its own current -** context). These routines add, change, and lookup contexts in the table. -*/ - -/* -** Add a current context, and return the tag that will be used to refer to it. -*/ -static int AddCurrentContext(__GLXclientState *cl, __GLXcontext *glxc, DrawablePtr pDraw) -{ - int i; - int num = cl->numCurrentContexts; - __GLXcontext **table = cl->currentContexts; - - if (!glxc) return -1; - - /* - ** Try to find an empty slot and use it. - */ - for (i=0; i < num; i++) { - if (!table[i]) { - table[i] = glxc; - return i+1; - } - } - /* - ** Didn't find a free slot, so we'll have to grow the table. - */ - if (!num) { - table = (__GLXcontext **) __glXMalloc(sizeof(__GLXcontext *)); - cl->currentDrawables = (DrawablePtr *) __glXMalloc(sizeof(DrawablePtr)); - cl->be_currentCTag = (GLXContextTag *) __glXMalloc(screenInfo.numScreens *sizeof(GLXContextTag)); - } else { - table = (__GLXcontext **) __glXRealloc(table, - (num+1)*sizeof(__GLXcontext *)); - cl->currentDrawables = (DrawablePtr *) __glXRealloc( - cl->currentDrawables , - (num+1)*sizeof(DrawablePtr)); - cl->be_currentCTag = (GLXContextTag *) __glXRealloc(cl->be_currentCTag, - (num+1)*screenInfo.numScreens*sizeof(GLXContextTag)); - } - table[num] = glxc; - cl->currentDrawables[num] = pDraw; - cl->currentContexts = table; - cl->numCurrentContexts++; - - memset(cl->be_currentCTag + num*screenInfo.numScreens, 0, - screenInfo.numScreens * sizeof(GLXContextTag)); - - return num+1; -} - -/* -** Given a tag, change the current context for the corresponding entry. -*/ -static void ChangeCurrentContext(__GLXclientState *cl, __GLXcontext *glxc, - GLXContextTag tag) -{ - __GLXcontext **table = cl->currentContexts; - table[tag-1] = glxc; -} - -/* -** Given a tag, and back-end screen number, retrives the current back-end -** tag. -*/ -int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s) -{ - if (tag >0) { - return( cl->be_currentCTag[ (tag-1)*screenInfo.numScreens + s ] ); - } - else { - return( 0 ); - } -} - -/* -** Given a tag, and back-end screen number, sets the current back-end -** tag. -*/ -static void SetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s, GLXContextTag be_tag) -{ - if (tag >0) { - cl->be_currentCTag[ (tag-1)*screenInfo.numScreens + s ] = be_tag; - } -} - -/* -** For this implementation we have chosen to simply use the index of the -** context's entry in the table as the context tag. A tag must be greater -** than 0. -*/ -__GLXcontext *__glXLookupContextByTag(__GLXclientState *cl, GLXContextTag tag) -{ - int num = cl->numCurrentContexts; - - if (tag < 1 || tag > num) { - return 0; - } else { - return cl->currentContexts[tag-1]; - } -} - -DrawablePtr __glXLookupDrawableByTag(__GLXclientState *cl, GLXContextTag tag) -{ - int num = cl->numCurrentContexts; - - if (tag < 1 || tag > num) { - return 0; - } else { - return cl->currentDrawables[tag-1]; - } -} - -/*****************************************************************************/ - -static void StopUsingContext(__GLXcontext *glxc) -{ - if (glxc) { - if (glxc == __glXLastContext) { - /* Tell server GL library */ - __glXLastContext = 0; - } - glxc->isCurrent = GL_FALSE; - if (!glxc->idExists) { - __glXFreeContext(glxc); - } - } -} - -static void StartUsingContext(__GLXclientState *cl, __GLXcontext *glxc) -{ - glxc->isCurrent = GL_TRUE; -} - -/*****************************************************************************/ -/* -** Make an OpenGL context and drawable current. -*/ -static int MakeCurrent(__GLXclientState *cl, - GLXDrawable drawable, - GLXDrawable readdrawable, - GLXContextID context, - GLXContextTag oldContextTag) -{ - ClientPtr client = cl->client; - DrawablePtr pDraw = NULL; - DrawablePtr pReadDraw = NULL; - xGLXMakeCurrentReadSGIReply new_reply; - xGLXMakeCurrentReq *be_req; - xGLXMakeCurrentReply be_reply; - xGLXMakeContextCurrentReq *be_new_req; - xGLXMakeContextCurrentReply be_new_reply; - GLXDrawable drawId = drawable; - GLXDrawable readId = readdrawable; - GLXContextID contextId = context; - __GLXpixmap *pGlxPixmap = 0; - __GLXpixmap *pReadGlxPixmap = 0; - __GLXcontext *glxc, *prevglxc; - GLXContextTag tag = oldContextTag; - WindowPtr pWin = NULL; - WindowPtr pReadWin = NULL; - __glXWindow *pGlxWindow = NULL; - __glXWindow *pGlxReadWindow = NULL; - __glXPbuffer *pGlxPbuffer = NULL; - __glXPbuffer *pGlxReadPbuffer = NULL; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; - PanoramiXRes *pXinReadDraw = NULL; -#endif - int from_screen = 0; - int to_screen = 0; - int s, rc; - - /* - ** If one is None and the other isn't, it's a bad match. - */ - if ((drawId == None && contextId != None) || - (drawId != None && contextId == None)) { - return BadMatch; - } - - /* - ** Lookup old context. If we have one, it must be in a usable state. - */ - if (tag != 0) { - prevglxc = __glXLookupContextByTag(cl, tag); - if (!prevglxc) { - /* - ** Tag for previous context is invalid. - */ - return __glXBadContextTag; - } - } else { - prevglxc = 0; - } - - /* - ** Lookup new context. It must not be current for someone else. - */ - if (contextId != None) { - glxc = (__GLXcontext *) LookupIDByType(contextId, __glXContextRes); - if (!glxc) { - client->errorValue = contextId; - return __glXBadContext; - } - if ((glxc != prevglxc) && glxc->isCurrent) { - /* Context is current to somebody else */ - return BadAccess; - } - } else { - /* Switching to no context. Ignore new drawable. */ - glxc = 0; - } - - if (drawId != None) { - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); - if (rc == Success) { - if (pDraw->type == DRAWABLE_WINDOW) { - /* - ** Drawable is an X Window. - */ - VisualID vid; - pWin = (WindowPtr)pDraw; - vid = wVisual(pWin); - - new_reply.writeVid = (glxc->pFBConfig ? glxc->pFBConfig->id : vid); - new_reply.writeType = GLX_WINDOW_TYPE; - - /* - ** Check if window and context are similar. - */ - if ((vid != glxc->pVisual->vid) || - (pWin->drawable.pScreen != glxc->pScreen)) { - client->errorValue = drawId; - return BadMatch; - } - - from_screen = to_screen = pWin->drawable.pScreen->myNum; - - } else { - /* - ** An X Pixmap is not allowed as a parameter (a GLX Pixmap - ** is, but it must first be created with glxCreateGLXPixmap). - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - /* - ** Check if pixmap and context are similar. - */ - if (pGlxPixmap->pScreen != glxc->pScreen || - pGlxPixmap->pGlxVisual != glxc->pGlxVisual) { - client->errorValue = drawId; - return BadMatch; - } - pDraw = pGlxPixmap->pDraw; - - new_reply.writeVid = (glxc->pFBConfig ? glxc->pFBConfig->id : - pGlxPixmap->pGlxVisual->vid); - - new_reply.writeType = GLX_PIXMAP_TYPE; - - from_screen = to_screen = pGlxPixmap->pScreen->myNum; - - } - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - /* - ** Drawable is a GLXWindow. - ** - ** Check if GLX window and context are similar. - */ - if (pGlxWindow->pScreen != glxc->pScreen || - pGlxWindow->pGlxFBConfig != glxc->pFBConfig) { - client->errorValue = drawId; - return BadMatch; - } - - pDraw = pGlxWindow->pDraw; - new_reply.writeVid = pGlxWindow->pGlxFBConfig->id; - new_reply.writeType = GLX_GLXWINDOW_TYPE; - } - - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); - if (pGlxPbuffer) { - if (pGlxPbuffer->pScreen != glxc->pScreen || - pGlxPbuffer->pFBConfig != glxc->pFBConfig) { - client->errorValue = drawId; - return BadMatch; - } - - pDraw = (DrawablePtr)pGlxPbuffer; - new_reply.writeVid = pGlxPbuffer->pFBConfig->id; - new_reply.writeType = GLX_PBUFFER_TYPE; - } - } - - if (!pDraw) { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - - } else { - pDraw = 0; - } - - if (readId != None && readId != drawId ) { - rc = dixLookupDrawable(&pReadDraw, readId, client, 0, DixReadAccess); - if (rc == Success) { - if (pReadDraw->type == DRAWABLE_WINDOW) { - /* - ** Drawable is an X Window. - */ - VisualID vid; - pReadWin = (WindowPtr)pDraw; - vid = wVisual(pReadWin); - - new_reply.readVid = (glxc->pFBConfig ? glxc->pFBConfig->id : vid); - new_reply.readType = GLX_WINDOW_TYPE; - - /* - ** Check if window and context are similar. - */ - if ((vid != glxc->pVisual->vid) || - (pReadWin->drawable.pScreen != glxc->pScreen)) { - client->errorValue = readId; - return BadMatch; - } - - } else { - - /* - ** An X Pixmap is not allowed as a parameter (a GLX Pixmap - ** is, but it must first be created with glxCreateGLXPixmap). - */ - client->errorValue = readId; - return __glXBadDrawable; - } - } - - if (!pReadDraw) { - pReadGlxPixmap = (__GLXpixmap *) LookupIDByType(readId, - __glXPixmapRes); - if (pReadGlxPixmap) { - /* - ** Check if pixmap and context are similar. - */ - if (pReadGlxPixmap->pScreen != glxc->pScreen || - pReadGlxPixmap->pGlxVisual != glxc->pGlxVisual) { - client->errorValue = readId; - return BadMatch; - } - pReadDraw = pReadGlxPixmap->pDraw; - - new_reply.readVid = (glxc->pFBConfig ? glxc->pFBConfig->id : - pReadGlxPixmap->pGlxVisual->vid ); - new_reply.readType = GLX_PIXMAP_TYPE; - - } - } - - if (!pReadDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxReadWindow = (__glXWindow *) - LookupIDByType(readId, __glXWindowRes); - if (pGlxReadWindow) { - /* - ** Drawable is a GLXWindow. - ** - ** Check if GLX window and context are similar. - */ - if (pGlxReadWindow->pScreen != glxc->pScreen || - pGlxReadWindow->pGlxFBConfig != glxc->pFBConfig) { - client->errorValue = readId; - return BadMatch; - } - - pReadDraw = pGlxReadWindow->pDraw; - new_reply.readVid = pGlxReadWindow->pGlxFBConfig->id; - new_reply.readType = GLX_GLXWINDOW_TYPE; - } - } - - if (!pReadDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxReadPbuffer = (__glXPbuffer *)LookupIDByType(readId, __glXPbufferRes); - if (pGlxReadPbuffer) { - if (pGlxReadPbuffer->pScreen != glxc->pScreen || - pGlxReadPbuffer->pFBConfig != glxc->pFBConfig) { - client->errorValue = drawId; - return BadMatch; - } - - pReadDraw = (DrawablePtr)pGlxReadPbuffer; - new_reply.readVid = pGlxReadPbuffer->pFBConfig->id; - new_reply.readType = GLX_PBUFFER_TYPE; - } - } - - if (!pReadDraw) { - /* - ** Drawable is neither a Window nor a GLXPixmap. - */ - client->errorValue = readId; - return __glXBadDrawable; - } - - } else { - pReadDraw = pDraw; - pReadGlxPixmap = pGlxPixmap; - pReadWin = pWin; - new_reply.readVid = new_reply.writeVid; - new_reply.readType = new_reply.writeType; - } - - if (prevglxc) { - - if (prevglxc->pGlxPixmap) { - /* - ** The previous drawable was a glx pixmap, release it. - */ - prevglxc->pGlxPixmap->refcnt--; - __glXFreeGLXPixmap( prevglxc->pGlxPixmap ); - prevglxc->pGlxPixmap = 0; - } - - if (prevglxc->pGlxReadPixmap) { - /* - ** The previous drawable was a glx pixmap, release it. - */ - prevglxc->pGlxReadPixmap->refcnt--; - __glXFreeGLXPixmap( prevglxc->pGlxReadPixmap ); - prevglxc->pGlxReadPixmap = 0; - } - - if (prevglxc->pGlxWindow) { - /* - ** The previous drawable was a glx window, release it. - */ - prevglxc->pGlxWindow->refcnt--; - __glXFreeGLXWindow( prevglxc->pGlxWindow ); - prevglxc->pGlxWindow = 0; - } - - if (prevglxc->pGlxReadWindow) { - /* - ** The previous drawable was a glx window, release it. - */ - prevglxc->pGlxReadWindow->refcnt--; - __glXFreeGLXWindow( prevglxc->pGlxReadWindow ); - prevglxc->pGlxReadWindow = 0; - } - - if (prevglxc->pGlxPbuffer) { - /* - ** The previous drawable was a glx Pbuffer, release it. - */ - prevglxc->pGlxPbuffer->refcnt--; - __glXFreeGLXPbuffer( prevglxc->pGlxPbuffer ); - prevglxc->pGlxPbuffer = 0; - } - - if (prevglxc->pGlxReadPbuffer) { - /* - ** The previous drawable was a glx Pbuffer, release it. - */ - prevglxc->pGlxReadPbuffer->refcnt--; - __glXFreeGLXPbuffer( prevglxc->pGlxReadPbuffer ); - prevglxc->pGlxReadPbuffer = 0; - } - - ChangeCurrentContext(cl, glxc, tag); - ChangeCurrentContext(cl, glxc, tag); - StopUsingContext(prevglxc); - } else { - tag = AddCurrentContext(cl, glxc, pDraw); - } - if (glxc) { - - glxc->pGlxPixmap = pGlxPixmap; - glxc->pGlxReadPixmap = pReadGlxPixmap; - glxc->pGlxWindow = pGlxWindow; - glxc->pGlxReadWindow = pGlxReadWindow; - glxc->pGlxPbuffer = pGlxPbuffer; - glxc->pGlxReadPbuffer = pGlxReadPbuffer; - - if (pGlxPixmap) { - pGlxPixmap->refcnt++; - } - - if (pReadGlxPixmap) { - pReadGlxPixmap->refcnt++; - } - - if (pGlxWindow) { - pGlxWindow->refcnt++; - } - - if (pGlxReadWindow) { - pGlxReadWindow->refcnt++; - } - - if (pGlxPbuffer) { - pGlxPbuffer->refcnt++; - } - - if (pGlxReadPbuffer) { - pGlxReadPbuffer->refcnt++; - } - - StartUsingContext(cl, glxc); - new_reply.contextTag = tag; - } else { - new_reply.contextTag = 0; - } - new_reply.length = 0; - new_reply.type = X_Reply; - new_reply.sequenceNumber = client->sequence; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - - if (pDraw && new_reply.writeType != GLX_PBUFFER_TYPE) { - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - } - - if (pReadDraw && pReadDraw != pDraw && - new_reply.readType != GLX_PBUFFER_TYPE) { - pXinReadDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pReadDraw->id, XRC_DRAWABLE, DixReadAccess); - } - else { - pXinReadDraw = pXinDraw; - } - } -#endif - - - /* send the MakeCurrent request to all required - * back-end servers. - */ - for (s = from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - unsigned int be_draw = None; - unsigned int be_read_draw = None; - - if (pGlxPixmap) { - be_draw = pGlxPixmap->be_xids[s]; - } - else if (pGlxPbuffer) { - be_draw = pGlxPbuffer->be_xids[s]; - } -#ifdef PANORAMIX - else if (pXinDraw) { - dixLookupWindow(&pWin, pXinDraw->info[s].id, client, DixReadAccess); - } -#endif - else if (pGlxWindow) { - pWin = (WindowPtr)pGlxWindow->pDraw; - } - - if (pWin && be_draw == None) { - be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - if (!be_draw) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pWin, TRUE ); - be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - } - } - - /* - * Before sending the MakeCurrent request - sync the - * X11 connection to the back-end servers to make sure - * that drawable is already created - */ - dmxSync( dmxScreen, 1 ); - - if (drawId == readId) { - LockDisplay(dpy); - GetReq(GLXMakeCurrent, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXMakeCurrent; - be_req->drawable = be_draw; - be_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); - be_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); - if (!_XReply(dpy, (xReply *) &be_reply, 0, False)) { - - /* The make current failed */ - UnlockDisplay(dpy); - SyncHandle(); - return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); - } - - UnlockDisplay(dpy); - SyncHandle(); - - SetCurrentBackEndTag( cl, tag, s, be_reply.contextTag ); - } - else { - - if (pReadGlxPixmap) { - be_read_draw = pReadGlxPixmap->be_xids[s]; - } - else if (pGlxReadPbuffer) { - be_read_draw = pGlxReadPbuffer->be_xids[s]; - } -#ifdef PANORAMIX - else if (pXinReadDraw) { - dixLookupWindow(&pReadWin, pXinReadDraw->info[s].id, client, - DixReadAccess); - } -#endif - else if (pGlxReadWindow) { - pReadWin = (WindowPtr)pGlxReadWindow->pDraw; - } - - if (pReadWin && be_read_draw == None) { - be_read_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pReadWin))->window; - if (!be_read_draw) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pReadWin, TRUE ); - be_read_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pReadWin))->window; - dmxSync( dmxScreen, 1 ); - } - } - - if ( __GLX_IS_VERSION_SUPPORTED(1,3) ) { - LockDisplay(dpy); - GetReq(GLXMakeContextCurrent, be_new_req); - be_new_req->reqType = dmxScreen->glxMajorOpcode; - be_new_req->glxCode = X_GLXMakeContextCurrent; - be_new_req->drawable = be_draw; - be_new_req->readdrawable = be_read_draw; - be_new_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); - be_new_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); - if (!_XReply(dpy, (xReply *) &be_new_reply, 0, False)) { - - /* The make current failed */ - UnlockDisplay(dpy); - SyncHandle(); - return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); - } - - UnlockDisplay(dpy); - SyncHandle(); - - SetCurrentBackEndTag( cl, tag, s, be_new_reply.contextTag ); - } - else if (glxIsExtensionSupported("GLX_SGI_make_current_read")) { - xGLXMakeCurrentReadSGIReq *ext_req; - xGLXVendorPrivateWithReplyReq *vpreq; - xGLXMakeCurrentReadSGIReply ext_reply; - - LockDisplay(dpy); - GetReqExtra(GLXVendorPrivateWithReply, - sz_xGLXMakeCurrentReadSGIReq - sz_xGLXVendorPrivateWithReplyReq, - vpreq); - ext_req = (xGLXMakeCurrentReadSGIReq *)vpreq; - ext_req->reqType = dmxScreen->glxMajorOpcode; - ext_req->glxCode = X_GLXVendorPrivateWithReply; - ext_req->vendorCode = X_GLXvop_MakeCurrentReadSGI; - ext_req->drawable = be_draw; - ext_req->readable = be_read_draw; - ext_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); - ext_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); - if (!_XReply(dpy, (xReply *) &ext_reply, 0, False)) { - - /* The make current failed */ - UnlockDisplay(dpy); - SyncHandle(); - return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); - } - - UnlockDisplay(dpy); - SyncHandle(); - - SetCurrentBackEndTag( cl, tag, s, ext_reply.contextTag ); - - } - else { - return BadMatch; - } - } - - XFlush( dpy ); - } - - if (client->swapped) { - __glXSwapMakeCurrentReply(client, &new_reply); - } else { - WriteToClient(client, sz_xGLXMakeContextCurrentReply, (char *)&new_reply); - } - - return Success; -} - -int __glXMakeCurrent(__GLXclientState *cl, GLbyte *pc) -{ - xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc; - - return( MakeCurrent(cl, req->drawable, req->drawable, - req->context, req->oldContextTag ) ); -} - -int __glXMakeContextCurrent(__GLXclientState *cl, GLbyte *pc) -{ - xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc; - - return( MakeCurrent(cl, req->drawable, req->readdrawable, - req->context, req->oldContextTag ) ); -} - -int __glXMakeCurrentReadSGI(__GLXclientState *cl, GLbyte *pc) -{ - xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc; - - return( MakeCurrent(cl, req->drawable, req->readable, - req->context, req->oldContextTag ) ); -} - -int __glXIsDirect(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc; - xGLXIsDirectReply reply; - __GLXcontext *glxc; - - /* - ** Find the GL context. - */ - glxc = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); - if (!glxc) { - client->errorValue = req->context; - return __glXBadContext; - } - - reply.isDirect = 0; - reply.length = 0; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - __glXSwapIsDirectReply(client, &reply); - } else { - WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply); - } - - return Success; -} - -int __glXQueryVersion(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; -/* xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc; */ - xGLXQueryVersionReply reply; - - /* - ** Server should take into consideration the version numbers sent by the - ** client if it wants to work with older clients; however, in this - ** implementation the server just returns its version number. - */ - reply.majorVersion = __glXVersionMajor; - reply.minorVersion = __glXVersionMinor; - reply.length = 0; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - __glXSwapQueryVersionReply(client, &reply); - } else { - WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply); - } - return Success; -} - -int __glXWaitGL(__GLXclientState *cl, GLbyte *pc) -{ - xGLXWaitGLReq *req = (xGLXWaitGLReq *)pc; - xGLXWaitGLReq *be_req = (xGLXWaitGLReq *)pc; - int from_screen = 0; - int to_screen = 0; - int s; - __GLXcontext *glxc = NULL; - - if (req->contextTag != 0) { - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (glxc) { - from_screen = to_screen = glxc->pScreen->myNum; - } - } - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXWaitGL,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXWaitGL; - be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); - UnlockDisplay(dpy); - SyncHandle(); - - XSync(dpy, False); - } - - return Success; -} - -int __glXWaitX(__GLXclientState *cl, GLbyte *pc) -{ - xGLXWaitXReq *req = (xGLXWaitXReq *)pc; - xGLXWaitXReq *be_req; - int from_screen = 0; - int to_screen = 0; - int s; - __GLXcontext *glxc = NULL; - - if (req->contextTag != 0) { - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (glxc) { - from_screen = to_screen = glxc->pScreen->myNum; - } - } - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXWaitX,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXWaitX; - be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); - UnlockDisplay(dpy); - SyncHandle(); - - XFlush( dpy ); - } - - return Success; -} - -int __glXCopyContext(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXCopyContextReq *be_req; - xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc; - GLXContextID source = req->source; - GLXContextID dest = req->dest; - GLXContextTag tag = req->contextTag; - unsigned long mask = req->mask; - __GLXcontext *src, *dst; - int s; - int from_screen = 0; - int to_screen = 0; - - /* - ** Check that each context exists. - */ - src = (__GLXcontext *) LookupIDByType(source, __glXContextRes); - if (!src) { - client->errorValue = source; - return __glXBadContext; - } - dst = (__GLXcontext *) LookupIDByType(dest, __glXContextRes); - if (!dst) { - client->errorValue = dest; - return __glXBadContext; - } - - /* - ** They must be in the same address space, and same screen. - */ - if (src->pGlxScreen != dst->pGlxScreen) { - client->errorValue = source; - return BadMatch; - } - - /* - ** The destination context must not be current for any client. - */ - if (dst->isCurrent) { - client->errorValue = dest; - return BadAccess; - } - - if (tag) { - __GLXcontext *tagcx = __glXLookupContextByTag(cl, tag); - - if (!tagcx) { - return __glXBadContextTag; - } - if (tagcx != src) { - /* - ** This would be caused by a faulty implementation of the client - ** library. - */ - return BadMatch; - } - } - - from_screen = to_screen = src->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXCopyContext,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXCopyContext; - be_req->source = (unsigned int)src->real_ids[s-from_screen]; - be_req->dest = (unsigned int)dst->real_ids[s-from_screen]; - be_req->mask = mask; - be_req->contextTag = (tag ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -int __glXGetVisualConfigs(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc; - xGLXGetVisualConfigsReply reply; - __GLXscreenInfo *pGlxScreen; - __GLXvisualConfig *pGlxVisual; - CARD32 buf[__GLX_TOTAL_CONFIG]; - unsigned int screen; - int i, p; - - screen = req->screen; - if (screen > screenInfo.numScreens) { - /* The client library must send a valid screen number. */ - client->errorValue = screen; - return BadValue; - } - pGlxScreen = &__glXActiveScreens[screen]; - - reply.numVisuals = pGlxScreen->numGLXVisuals; - reply.numProps = __GLX_TOTAL_CONFIG; - reply.length = (pGlxScreen->numGLXVisuals * __GLX_SIZE_CARD32 * - __GLX_TOTAL_CONFIG) >> 2; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char *)&reply); - - for (i=0; i < pGlxScreen->numVisuals; i++) { - pGlxVisual = &pGlxScreen->pGlxVisual[i]; - if (!pGlxScreen->isGLXvis[i] || pGlxVisual->vid == 0) { - /* not a usable visual */ - continue; - } - p = 0; - buf[p++] = pGlxVisual->vid; - buf[p++] = pGlxVisual->class; - buf[p++] = pGlxVisual->rgba; - - buf[p++] = pGlxVisual->redSize; - buf[p++] = pGlxVisual->greenSize; - buf[p++] = pGlxVisual->blueSize; - buf[p++] = pGlxVisual->alphaSize; - buf[p++] = pGlxVisual->accumRedSize; - buf[p++] = pGlxVisual->accumGreenSize; - buf[p++] = pGlxVisual->accumBlueSize; - buf[p++] = pGlxVisual->accumAlphaSize; - - buf[p++] = pGlxVisual->doubleBuffer; - buf[p++] = pGlxVisual->stereo; - - buf[p++] = pGlxVisual->bufferSize; - buf[p++] = pGlxVisual->depthSize; - buf[p++] = pGlxVisual->stencilSize; - buf[p++] = pGlxVisual->auxBuffers; - buf[p++] = pGlxVisual->level; - /* - ** Add token/value pairs for extensions. - */ - buf[p++] = GLX_VISUAL_CAVEAT_EXT; - buf[p++] = pGlxVisual->visualRating; - buf[p++] = GLX_TRANSPARENT_TYPE_EXT; - buf[p++] = pGlxVisual->transparentPixel; - buf[p++] = GLX_TRANSPARENT_RED_VALUE_EXT; - buf[p++] = pGlxVisual->transparentRed; - buf[p++] = GLX_TRANSPARENT_GREEN_VALUE_EXT; - buf[p++] = pGlxVisual->transparentGreen; - buf[p++] = GLX_TRANSPARENT_BLUE_VALUE_EXT; - buf[p++] = pGlxVisual->transparentBlue; - buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE_EXT; - buf[p++] = pGlxVisual->transparentAlpha; - buf[p++] = GLX_TRANSPARENT_INDEX_VALUE_EXT; - buf[p++] = pGlxVisual->transparentIndex; - buf[p++] = GLX_SAMPLES_SGIS; - buf[p++] = pGlxVisual->multiSampleSize; - buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; - buf[p++] = pGlxVisual->nMultiSampleBuffers; - buf[p++] = GLX_VISUAL_SELECT_GROUP_SGIX; - buf[p++] = pGlxVisual->visualSelectGroup; - - WriteToClient(client, __GLX_SIZE_CARD32 * __GLX_TOTAL_CONFIG, - (char *)buf); - } - return Success; -} - -/* -** Create a GLX Pixmap from an X Pixmap. -*/ -static int CreateGLXPixmap(__GLXclientState *cl, - VisualID visual, GLXFBConfigID fbconfigId, - int screenNum, XID pixmapId, XID glxpixmapId ) -{ - ClientPtr client = cl->client; - xGLXCreateGLXPixmapReq *be_req; - xGLXCreatePixmapReq *be_new_req; - DrawablePtr pDraw; - ScreenPtr pScreen; - VisualPtr pVisual; - __GLXpixmap *pGlxPixmap; - __GLXscreenInfo *pGlxScreen; - __GLXvisualConfig *pGlxVisual; - __GLXFBConfig *pFBConfig; - int i, s, rc; - int from_screen, to_screen; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; -#endif - - rc = dixLookupDrawable(&pDraw, pixmapId, client, M_DRAWABLE_PIXMAP, - DixAddAccess); - if (rc != Success) - return rc; - - /* - ** Check if screen of visual matches screen of pixmap. - */ - pScreen = pDraw->pScreen; - if (screenNum != pScreen->myNum) { - return BadMatch; - } - - if (fbconfigId == NULL && visual == NULL) { - return BadValue; - } - - if (fbconfigId != None) { - pFBConfig = glxLookupFBConfig( fbconfigId ); - if (!pFBConfig) { - client->errorValue = fbconfigId; - return BadValue; - } - visual = pFBConfig->associatedVisualId; - } - else { - pFBConfig = NULL; - } - - if (visual != None) { - /* - ** Find the VisualRec for this visual. - */ - pVisual = pScreen->visuals; - for (i=0; i < pScreen->numVisuals; i++, pVisual++) { - if (pVisual->vid == visual) { - break; - } - } - if (i == pScreen->numVisuals) { - client->errorValue = visual; - return BadValue; - } - /* - ** Check if depth of visual matches depth of pixmap. - */ - if (pVisual->nplanes != pDraw->depth) { - client->errorValue = visual; - return BadMatch; - } - - /* - ** Get configuration of the visual. - */ - pGlxScreen = &__glXActiveScreens[screenNum]; - pGlxVisual = pGlxScreen->pGlxVisual; - for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { - if (pGlxVisual->vid == visual) { - break; - } - } - if (i == pGlxScreen->numVisuals) { - /* - ** Visual not support on this screen by this OpenGL implementation. - */ - client->errorValue = visual; - return BadValue; - } - - - /* find the FBConfig for that visual (if any) */ - if ( pFBConfig == NULL ) { - pFBConfig = glxLookupFBConfigByVID( visual ); - - if ( pFBConfig == NULL ) { - /* - * visual does not have an FBConfig ??? - client->errorValue = visual; - return BadValue; - */ - } - } - } - else { - pVisual = NULL; - pGlxVisual = NULL; - } - - pGlxPixmap = (__GLXpixmap *) __glXMalloc(sizeof(__GLXpixmap)); - if (!pGlxPixmap) { - return BadAlloc; - } - pGlxPixmap->be_xids = (XID *) __glXMalloc(sizeof(XID) * screenInfo.numScreens); - if (!pGlxPixmap->be_xids) { - __glXFree( pGlxPixmap ); - return BadAlloc; - } - - pGlxPixmap->pDraw = pDraw; - pGlxPixmap->pGlxScreen = pGlxScreen; - pGlxPixmap->pGlxVisual = pGlxVisual; - pGlxPixmap->pFBConfig = pFBConfig; - pGlxPixmap->pScreen = pScreen; - pGlxPixmap->idExists = True; - pGlxPixmap->refcnt = 0; - - /* - ** Bump the ref count on the X pixmap so it won't disappear. - */ - ((PixmapPtr) pDraw)->refcnt++; - - /* - * send the request to the back-end server(s) - */ - from_screen = to_screen = screenNum; -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - Pixmap be_pixmap; - DrawablePtr pRealDraw = pDraw; - -#ifdef PANORAMIX - if (pXinDraw) { - dixLookupDrawable(&pRealDraw, pXinDraw->info[s].id, client, 0, - DixAddAccess); - } -#endif - - be_pixmap = (DMX_GET_PIXMAP_PRIV((PixmapPtr)pRealDraw))->pixmap; - - /* make sure pixmap already created on back-end */ - dmxSync( dmxScreen, 1 ); - - if ( pFBConfig && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - __GLXFBConfig *be_FBConfig = glxLookupBackEndFBConfig( pFBConfig->id, s ); - - LockDisplay(dpy); - pGlxPixmap->be_xids[s] = XAllocID(dpy); - GetReq(GLXCreatePixmap,be_new_req); - be_new_req->reqType = dmxScreen->glxMajorOpcode; - be_new_req->glxCode = X_GLXCreatePixmap; - be_new_req->screen = DefaultScreen(dpy); - be_new_req->fbconfig = be_FBConfig->id; - be_new_req->pixmap = (unsigned int)be_pixmap; - be_new_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; - be_new_req->numAttribs = 0; - UnlockDisplay(dpy); - SyncHandle(); - } - else if (pFBConfig && glxIsExtensionSupported("GLX_SGIX_fbconfig")) { - __GLXFBConfig *be_FBConfig = glxLookupBackEndFBConfig( pFBConfig->id, s ); - xGLXCreateGLXPixmapWithConfigSGIXReq *ext_req; - xGLXVendorPrivateReq *vpreq; - - LockDisplay(dpy); - pGlxPixmap->be_xids[s] = XAllocID(dpy); - GetReqExtra(GLXVendorPrivate, - sz_xGLXCreateGLXPixmapWithConfigSGIXReq-sz_xGLXVendorPrivateReq, - vpreq); - ext_req = (xGLXCreateGLXPixmapWithConfigSGIXReq *)vpreq; - ext_req->reqType = dmxScreen->glxMajorOpcode; - ext_req->glxCode = X_GLXVendorPrivate; - ext_req->vendorCode = X_GLXvop_CreateGLXPixmapWithConfigSGIX; - ext_req->screen = DefaultScreen(dpy); - ext_req->fbconfig = be_FBConfig->id; - ext_req->pixmap = (unsigned int)be_pixmap; - ext_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; - UnlockDisplay(dpy); - SyncHandle(); - } - else if (pGlxVisual) { - LockDisplay(dpy); - pGlxPixmap->be_xids[s] = XAllocID(dpy); - GetReq(GLXCreateGLXPixmap,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXCreateGLXPixmap; - be_req->screen = DefaultScreen(dpy); - be_req->visual = (unsigned int)glxMatchGLXVisualInConfigList( - pGlxVisual, - dmxScreen->glxVisuals, - dmxScreen->numGlxVisuals ); - be_req->pixmap = (unsigned int)be_pixmap; - be_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; - UnlockDisplay(dpy); - SyncHandle(); - } - else { - client->errorValue = ( visual ? visual : fbconfigId ); - __glXFree( pGlxPixmap ); - return BadValue; - } - - XFlush( dpy ); - } - - if (!(AddResource(glxpixmapId, __glXPixmapRes, pGlxPixmap))) { - __glXFree( pGlxPixmap ); - return BadAlloc; - } - - return Success; -} - -int __glXCreateGLXPixmap(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc; - - return( CreateGLXPixmap(cl, req->visual, None, - req->screen, req->pixmap, req->glxpixmap) ); -} - -int __glXCreatePixmap(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreatePixmapReq *req = (xGLXCreatePixmapReq *) pc; - - return( CreateGLXPixmap(cl, None, req->fbconfig, - req->screen, req->pixmap, req->glxpixmap) ); -} - -int __glXDestroyGLXPixmap(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc; - XID glxpixmap = req->glxpixmap; - __GLXpixmap *pGlxPixmap; - int s; - int from_screen, to_screen; - - /* - ** Check if it's a valid GLX pixmap. - */ - pGlxPixmap = (__GLXpixmap *)LookupIDByType(glxpixmap, __glXPixmapRes); - if (!pGlxPixmap) { - client->errorValue = glxpixmap; - return __glXBadPixmap; - } - FreeResource(glxpixmap, FALSE); - - /* - * destroy the pixmap on the back-end server(s). - */ - from_screen = to_screen = pGlxPixmap->pDraw->pScreen->myNum; -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - /* make sure pixmap exist in back-end */ - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXDestroyGLXPixmap,req); - req->reqType = dmxScreen->glxMajorOpcode; - req->glxCode = X_GLXDestroyGLXPixmap; - req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; - UnlockDisplay(dpy); - SyncHandle(); - } - - - return Success; -} - -/*****************************************************************************/ - -/* -** NOTE: There is no portable implementation for swap buffers as of -** this time that is of value. Consequently, this code must be -** implemented by somebody other than SGI. -*/ -int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag) -{ - ClientPtr client = cl->client; - DrawablePtr pDraw; - xGLXSwapBuffersReq *be_req; - WindowPtr pWin = NULL; - __GLXpixmap *pGlxPixmap = NULL; - __GLXcontext *glxc = NULL; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; -#endif - __glXWindow *pGlxWindow = NULL; - int from_screen = 0; - int to_screen = 0; - int s, rc; - - /* - ** Check that the GLX drawable is valid. - */ - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); - if (rc == Success) { - from_screen = to_screen = pDraw->pScreen->myNum; - - if (pDraw->type == DRAWABLE_WINDOW) { - /* - ** Drawable is an X window. - */ - pWin = (WindowPtr)pDraw; - } else { - /* - ** Drawable is an X pixmap, which is not allowed. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - /* - ** Drawable is a GLX pixmap. - */ - pDraw = pGlxPixmap->pDraw; - from_screen = to_screen = pGlxPixmap->pScreen->myNum; - } - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - /* - ** Drawable is a GLXWindow. - */ - pDraw = pGlxWindow->pDraw; - from_screen = to_screen = pGlxWindow->pScreen->myNum; - } - } - - if (!pDraw) { - /* - ** Drawable is neither a X window nor a GLX pixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - - if (tag) { - glxc = __glXLookupContextByTag(cl, tag); - if (!glxc) { - return __glXBadContextTag; - } - } - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - } -#endif - - /* If requested, send a glFinish to all back-end servers before swapping. */ - if (dmxGLXFinishSwap) { - for (s=from_screen; s<=to_screen; s++) { - Display *dpy = GetBackEndDisplay(cl,s); - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - xGLXSingleReq *finishReq; - xGLXSingleReply reply; - -#define X_GLXSingle 0 /* needed by GetReq below */ - - LockDisplay(dpy); - GetReq(GLXSingle,finishReq); - finishReq->reqType = dmxScreen->glxMajorOpcode; - finishReq->glxCode = X_GLsop_Finish; - finishReq->contextTag = (tag ? GetCurrentBackEndTag(cl,tag,s) : 0); - (void) _XReply(dpy, (xReply*) &reply, 0, False); - UnlockDisplay(dpy); - SyncHandle(); - } - } - - /* If requested, send an XSync to all back-end servers before swapping. */ - if (dmxGLXSyncSwap) { - for (s=from_screen; s<=to_screen; s++) - XSync(GetBackEndDisplay(cl,s), False); - } - - - /* send the SwapBuffers request to all back-end servers */ - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - unsigned int be_draw = 0; - - if (pGlxPixmap) { - be_draw = (unsigned int)pGlxPixmap->be_xids[s]; - } -#ifdef PANORAMIX - else if (pXinDraw) { - dixLookupWindow(&pWin, pXinDraw->info[s].id, client, DixReadAccess); - } -#endif - else if (pGlxWindow) { - pWin = (WindowPtr)pGlxWindow->pDraw; - } - - if (pWin && !be_draw) { - be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - if (!be_draw) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pWin, TRUE ); - be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - } - } - - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXSwapBuffers,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXSwapBuffers; - be_req->drawable = be_draw; - be_req->contextTag = ( tag ? GetCurrentBackEndTag(cl,tag,s) : 0 ); - UnlockDisplay(dpy); - SyncHandle(); - XFlush(dpy); - } - - return Success; -} - -int __glXSwapBuffers(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - DrawablePtr pDraw; - xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc; - GLXContextTag tag = req->contextTag; - XID drawId = req->drawable; - __GLXpixmap *pGlxPixmap = NULL; - __GLXcontext *glxc = NULL; - __glXWindow *pGlxWindow = NULL; - int rc; - - /* - ** Check that the GLX drawable is valid. - */ - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); - if (rc == Success) { - if (pDraw->type != DRAWABLE_WINDOW) { - /* - ** Drawable is an X pixmap, which is not allowed. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - /* - ** Drawable is a GLX pixmap. - */ - pDraw = pGlxPixmap->pDraw; - } - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - /* - ** Drawable is a GLXWindow. - */ - pDraw = pGlxWindow->pDraw; - } - } - - if (!pDraw) { - /* - ** Drawable is neither a X window nor a GLX pixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - - if (tag) { - glxc = __glXLookupContextByTag(cl, tag); - if (!glxc) { - return __glXBadContextTag; - } - } - - if (pDraw && - pDraw->type == DRAWABLE_WINDOW && - DMX_GET_WINDOW_PRIV((WindowPtr)pDraw)->swapGroup) { - return SGSwapBuffers(cl, drawId, tag, pDraw); - } - - return __glXDoSwapBuffers(cl, drawId, tag); -} - - -/************************************************************************/ - -/* -** Render and Renderlarge are not in the GLX API. They are used by the GLX -** client library to send batches of GL rendering commands. -*/ - -/* -** Execute all the drawing commands in a request. -*/ -int __glXRender(__GLXclientState *cl, GLbyte *pc) -{ - xGLXRenderReq *req; - xGLXRenderReq *be_req; - int size; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int s; - - /* - ** NOTE: much of this code also appears in the byteswapping version of this - ** routine, __glXSwapRender(). Any changes made here should also be - ** duplicated there. - */ - - req = (xGLXRenderReq *) pc; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXRenderReq; - size = (req->length << 2) - sz_xGLXRenderReq; - - /* - * just forward the request to back-end server(s) - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXRender,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXRender; - be_req->length = req->length; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - _XSend(dpy, (const char *)pc, size); - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -/* -** Execute a large rendering request (one that spans multiple X requests). -*/ -int __glXRenderLarge(__GLXclientState *cl, GLbyte *pc) -{ - xGLXRenderLargeReq *req; - xGLXRenderLargeReq *be_req; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int s; - - /* - ** NOTE: much of this code also appears in the byteswapping version of this - ** routine, __glXSwapRenderLarge(). Any changes made here should also be - ** duplicated there. - */ - - req = (xGLXRenderLargeReq *) pc; - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXRenderLargeReq; - - /* - * just forward the request to back-end server(s) - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - GetReq(GLXRenderLarge,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXRenderLarge; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - be_req->length = req->length; - be_req->requestNumber = req->requestNumber; - be_req->requestTotal = req->requestTotal; - be_req->dataBytes = req->dataBytes; - Data(dpy, (const char *)pc, req->dataBytes); - UnlockDisplay(dpy); - SyncHandle(); - - } - - return Success; -} - - -/************************************************************************/ - -int __glXVendorPrivate(__GLXclientState *cl, GLbyte *pc) -{ - xGLXVendorPrivateReq *req; - - req = (xGLXVendorPrivateReq *) pc; - - switch( req->vendorCode ) { - - case X_GLvop_DeleteTexturesEXT: - return __glXVForwardSingleReq( cl, pc ); - break; - - case X_GLXvop_SwapIntervalSGI: - if (glxIsExtensionSupported("SGI_swap_control")) { - return __glXVForwardSingleReq( cl, pc ); - } - else { - return Success; - } - break; - -#if 0 /* glx 1.3 */ - case X_GLXvop_CreateGLXVideoSourceSGIX: - break; - case X_GLXvop_DestroyGLXVideoSourceSGIX: - break; - case X_GLXvop_CreateGLXPixmapWithConfigSGIX: - break; - case X_GLXvop_DestroyGLXPbufferSGIX: - break; - case X_GLXvop_ChangeDrawableAttributesSGIX: - break; -#endif - - case X_GLXvop_BindSwapBarrierSGIX: - return __glXBindSwapBarrierSGIX( cl, pc ); - break; - - case X_GLXvop_JoinSwapGroupSGIX: - return __glXJoinSwapGroupSGIX( cl, pc ); - break; - - case X_GLXvop_CreateContextWithConfigSGIX: - return __glXCreateContextWithConfigSGIX( cl, pc ); - break; - - default: - /* - ** unsupported private request - */ - cl->client->errorValue = req->vendorCode; - return __glXUnsupportedPrivateRequest; - } - - cl->client->errorValue = req->vendorCode; - return __glXUnsupportedPrivateRequest; - -} - -int __glXVendorPrivateWithReply(__GLXclientState *cl, GLbyte *pc) -{ - xGLXVendorPrivateWithReplyReq *req; - - req = (xGLXVendorPrivateWithReplyReq *) pc; - - switch( req->vendorCode ) { - - case X_GLvop_GetConvolutionFilterEXT: - case X_GLvop_GetConvolutionParameterfvEXT: - case X_GLvop_GetConvolutionParameterivEXT: - case X_GLvop_GetSeparableFilterEXT: - case X_GLvop_GetHistogramEXT: - case X_GLvop_GetHistogramParameterivEXT: - case X_GLvop_GetMinmaxEXT: - case X_GLvop_GetMinmaxParameterfvEXT: - case X_GLvop_GetMinmaxParameterivEXT: - case X_GLvop_AreTexturesResidentEXT: - case X_GLvop_IsTextureEXT: - return( __glXVForwardPipe0WithReply(cl, pc) ); - break; - - case X_GLvop_GenTexturesEXT: - return( __glXVForwardAllWithReply(cl, pc) ); - break; - - -#if 0 /* glx1.3 */ - case X_GLvop_GetDetailTexFuncSGIS: - case X_GLvop_GetSharpenTexFuncSGIS: - case X_GLvop_GetColorTableSGI: - case X_GLvop_GetColorTableParameterfvSGI: - case X_GLvop_GetColorTableParameterivSGI: - case X_GLvop_GetTexFilterFuncSGIS: - case X_GLvop_GetInstrumentsSGIX: - case X_GLvop_InstrumentsBufferSGIX: - case X_GLvop_PollInstrumentsSGIX: - case X_GLvop_FlushRasterSGIX: - case X_GLXvop_CreateGLXPbufferSGIX: - case X_GLXvop_GetDrawableAttributesSGIX: - case X_GLXvop_QueryHyperpipeNetworkSGIX: - case X_GLXvop_QueryHyperpipeConfigSGIX: - case X_GLXvop_HyperpipeConfigSGIX: - case X_GLXvop_DestroyHyperpipeConfigSGIX: -#endif - case X_GLXvop_QueryMaxSwapBarriersSGIX: - return( __glXQueryMaxSwapBarriersSGIX(cl, pc) ); - break; - - case X_GLXvop_GetFBConfigsSGIX: - return( __glXGetFBConfigsSGIX(cl, pc) ); - break; - - case X_GLXvop_MakeCurrentReadSGI: - return( __glXMakeCurrentReadSGI(cl, pc) ); - break; - - case X_GLXvop_QueryContextInfoEXT: - return( __glXQueryContextInfoEXT(cl,pc) ); - break; - - default: - /* - ** unsupported private request - */ - cl->client->errorValue = req->vendorCode; - return __glXUnsupportedPrivateRequest; - } - -} - -int __glXQueryExtensionsString(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXQueryExtensionsStringReq *req = (xGLXQueryExtensionsStringReq *) pc; - xGLXQueryExtensionsStringReply reply; - GLint screen; - size_t length; - int len, numbytes; - char *be_buf; - -#ifdef FWD_QUERY_REQ - xGLXQueryExtensionsStringReq *be_req; - xGLXQueryExtensionsStringReply be_reply; - DMXScreenInfo *dmxScreen; - Display *dpy; - int slop; -#endif - - screen = req->screen; - - /* - ** Check if screen exists. - */ - if ((screen < 0) || (screen >= screenInfo.numScreens)) { - client->errorValue = screen; - return BadValue; - } - -#ifdef FWD_QUERY_REQ - dmxScreen = &dmxScreens[screen]; - - /* Send the glXQueryServerString request */ - dpy = GetBackEndDisplay(cl,screen); - LockDisplay(dpy); - GetReq(GLXQueryExtensionsString,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXQueryServerString; - be_req->screen = DefaultScreen(dpy); - _XReply(dpy, (xReply*) &be_reply, 0, False); - len = (int)be_reply.length; - numbytes = (int)be_reply.n; - slop = numbytes * __GLX_SIZE_INT8 & 3; - be_buf = (char *)Xalloc(numbytes); - if (!be_buf) { - /* Throw data on the floor */ - _XEatData(dpy, len); - } else { - _XRead(dpy, (char *)be_buf, numbytes); - if (slop) _XEatData(dpy,4-slop); - } - UnlockDisplay(dpy); - SyncHandle(); - -#else - - be_buf = __glXGetServerString(GLX_EXTENSIONS); - numbytes = strlen(be_buf) + 1; - len = __GLX_PAD(numbytes) >> 2; - -#endif - - length = len; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = len; - reply.n = numbytes; - - if (client->swapped) { - glxSwapQueryExtensionsStringReply(client, &reply, be_buf); - } else { - WriteToClient(client, sz_xGLXQueryExtensionsStringReply,(char *)&reply); - WriteToClient(client, (int)(length << 2), (char *)be_buf); - } - - return Success; -} - -int __glXQueryServerString(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) pc; - xGLXQueryServerStringReply reply; - int name; - GLint screen; - size_t length; - int len, numbytes; - char *be_buf; -#ifdef FWD_QUERY_REQ - xGLXQueryServerStringReq *be_req; - xGLXQueryServerStringReply be_reply; - DMXScreenInfo *dmxScreen; - Display *dpy; - int slop; -#endif - - name = req->name; - screen = req->screen; - /* - ** Check if screen exists. - */ - if ((screen < 0) || (screen >= screenInfo.numScreens)) { - client->errorValue = screen; - return BadValue; - } - -#ifdef FWD_QUERY_REQ - dmxScreen = &dmxScreens[screen]; - - /* Send the glXQueryServerString request */ - dpy = GetBackEndDisplay(cl,screen); - LockDisplay(dpy); - GetReq(GLXQueryServerString,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXQueryServerString; - be_req->screen = DefaultScreen(dpy); - be_req->name = name; - _XReply(dpy, (xReply*) &be_reply, 0, False); - len = (int)be_reply.length; - numbytes = (int)be_reply.n; - slop = numbytes * __GLX_SIZE_INT8 & 3; - be_buf = (char *)Xalloc(numbytes); - if (!be_buf) { - /* Throw data on the floor */ - _XEatData(dpy, len); - } else { - _XRead(dpy, (char *)be_buf, numbytes); - if (slop) _XEatData(dpy,4-slop); - } - UnlockDisplay(dpy); - SyncHandle(); - -#else - be_buf = __glXGetServerString(name); - numbytes = strlen(be_buf) + 1; - len = __GLX_PAD(numbytes) >> 2; -#endif - - length = len; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = length; - reply.n = numbytes; - - if (client->swapped) { - glxSwapQueryServerStringReply(client, &reply, be_buf); - } else { - WriteToClient(client, sz_xGLXQueryServerStringReply, (char *)&reply); - WriteToClient(client, (int)(length << 2), be_buf); - } - - return Success; -} - -int __glXClientInfo(__GLXclientState *cl, GLbyte *pc) -{ - xGLXClientInfoReq *req = (xGLXClientInfoReq *) pc; - xGLXClientInfoReq *be_req; - const char *buf; - int from_screen = 0; - int to_screen = 0; - int s; - - cl->GLClientmajorVersion = req->major; - cl->GLClientminorVersion = req->minor; - if (cl->GLClientextensions) __glXFree(cl->GLClientextensions); - buf = (const char *)(req+1); - cl->GLClientextensions = strdup(buf); - - to_screen = screenInfo.numScreens - 1; - - for (s=from_screen; s<=to_screen; s++) - { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXClientInfo,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXClientInfo; - be_req->major = req->major; - be_req->minor = req->minor; - be_req->length = req->length; - be_req->numbytes = req->numbytes; - Data(dpy, buf, req->numbytes); - - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -int __glXUseXFont(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXUseXFontReq *req; - xGLXUseXFontReq *be_req; - FontPtr pFont; - __GLXcontext *glxc = NULL; - int from_screen = 0; - int to_screen = 0; - int s; - dmxFontPrivPtr pFontPriv; - DMXScreenInfo *dmxScreen; - Display *dpy; - - req = (xGLXUseXFontReq *) pc; - - if (req->contextTag != 0) { - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (glxc) { - from_screen = to_screen = glxc->pScreen->myNum; - } - } - - /* - ** Font can actually be either the ID of a font or the ID of a GC - ** containing a font. - */ - pFont = (FontPtr)LookupIDByType(req->font, RT_FONT); - if (!pFont) { - GC *pGC = (GC *)LookupIDByType(req->font, RT_GC); - if (!pGC) { - client->errorValue = req->font; - return BadFont; - } - pFont = pGC->font; - } - - pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - - for (s=from_screen; s<=to_screen; s++) { - dmxScreen = &dmxScreens[s]; - dpy = GetBackEndDisplay(cl,s); - - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXUseXFont,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXUseXFont; - be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); - be_req->font = pFontPriv->font[s]->fid; - be_req->first = req->first; - be_req->count = req->count; - be_req->listBase = req->listBase; - UnlockDisplay(dpy); - SyncHandle(); - - XSync( dpy, False ); - } - - return Success; -} - -/* - * start GLX 1.3 here - */ - -int __glXGetFBConfigs(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXGetFBConfigsReq *req = (xGLXGetFBConfigsReq *) pc; - xGLXGetFBConfigsReply reply; - __GLXFBConfig *pFBConfig; - CARD32 buf[2 * __GLX_TOTAL_FBCONFIG_PROPS]; - int numAttribs = __GLX_TOTAL_FBCONFIG_PROPS; - unsigned int screen = req->screen; - int numFBConfigs, i, p; - __GLXscreenInfo *pGlxScreen; - - if (screen > screenInfo.numScreens) { - /* The client library must send a valid screen number. */ - client->errorValue = screen; - return BadValue; - } - - pGlxScreen = &__glXActiveScreens[screen]; - numFBConfigs = __glXNumFBConfigs; - - reply.numFBConfigs = numFBConfigs; - reply.numAttribs = numAttribs; - reply.length = (numFBConfigs * 2 * numAttribs * __GLX_SIZE_CARD32) >> 2; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - __GLX_SWAP_INT(&reply.numFBConfigs); - __GLX_SWAP_INT(&reply.numAttribs); - } - WriteToClient(client, sz_xGLXGetFBConfigsReply, (char *)&reply); - - for (i=0; i < numFBConfigs; i++) { - int associatedVisualId = 0; - int drawableTypeIndex; - pFBConfig = __glXFBConfigs[ i * (screenInfo.numScreens+1) ]; - - p = 0; - /* core attributes */ - buf[p++] = GLX_FBCONFIG_ID; - buf[p++] = pFBConfig->id; - buf[p++] = GLX_BUFFER_SIZE; - buf[p++] = pFBConfig->indexBits; - buf[p++] = GLX_LEVEL; - buf[p++] = pFBConfig->level; - buf[p++] = GLX_DOUBLEBUFFER; - buf[p++] = pFBConfig->doubleBufferMode; - buf[p++] = GLX_STEREO; - buf[p++] = pFBConfig->stereoMode; - buf[p++] = GLX_AUX_BUFFERS; - buf[p++] = pFBConfig->maxAuxBuffers; - buf[p++] = GLX_RED_SIZE; - buf[p++] = pFBConfig->redBits; - buf[p++] = GLX_GREEN_SIZE; - buf[p++] = pFBConfig->greenBits; - buf[p++] = GLX_BLUE_SIZE; - buf[p++] = pFBConfig->blueBits; - buf[p++] = GLX_ALPHA_SIZE; - buf[p++] = pFBConfig->alphaBits; - buf[p++] = GLX_DEPTH_SIZE; - buf[p++] = pFBConfig->depthBits; - buf[p++] = GLX_STENCIL_SIZE; - buf[p++] = pFBConfig->stencilBits; - buf[p++] = GLX_ACCUM_RED_SIZE; - buf[p++] = pFBConfig->accumRedBits; - buf[p++] = GLX_ACCUM_GREEN_SIZE; - buf[p++] = pFBConfig->accumGreenBits; - buf[p++] = GLX_ACCUM_BLUE_SIZE; - buf[p++] = pFBConfig->accumBlueBits; - buf[p++] = GLX_ACCUM_ALPHA_SIZE; - buf[p++] = pFBConfig->accumAlphaBits; - buf[p++] = GLX_RENDER_TYPE; - buf[p++] = pFBConfig->renderType; - buf[p++] = GLX_DRAWABLE_TYPE; - drawableTypeIndex = p; - buf[p++] = pFBConfig->drawableType; - buf[p++] = GLX_X_VISUAL_TYPE; - buf[p++] = pFBConfig->visualType; - buf[p++] = GLX_CONFIG_CAVEAT; - buf[p++] = pFBConfig->visualCaveat; - buf[p++] = GLX_TRANSPARENT_TYPE; - buf[p++] = pFBConfig->transparentType; - buf[p++] = GLX_TRANSPARENT_RED_VALUE; - buf[p++] = pFBConfig->transparentRed; - buf[p++] = GLX_TRANSPARENT_GREEN_VALUE; - buf[p++] = pFBConfig->transparentGreen; - buf[p++] = GLX_TRANSPARENT_BLUE_VALUE; - buf[p++] = pFBConfig->transparentBlue; - buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE; - buf[p++] = pFBConfig->transparentAlpha; - buf[p++] = GLX_TRANSPARENT_INDEX_VALUE; - buf[p++] = pFBConfig->transparentIndex; - buf[p++] = GLX_MAX_PBUFFER_WIDTH; - buf[p++] = pFBConfig->maxPbufferWidth; - buf[p++] = GLX_MAX_PBUFFER_HEIGHT; - buf[p++] = pFBConfig->maxPbufferHeight; - buf[p++] = GLX_MAX_PBUFFER_PIXELS; - buf[p++] = pFBConfig->maxPbufferPixels; - - /* - * find the visual of the back-end server and match a visual - * on the proxy. - * do only once - if a visual is not yet associated. - */ - if (pFBConfig->associatedVisualId == (unsigned int)-1) { - DMXScreenInfo *dmxScreen = &dmxScreens[screen]; - __GLXFBConfig *be_pFBConfig = __glXFBConfigs[ i * (screenInfo.numScreens+1)+screen+1 ]; - __GLXvisualConfig *pGlxVisual = NULL; - int v; - int found = 0; - for (v=0; v<dmxScreen->numGlxVisuals; v++) { - if (dmxScreen->glxVisuals[v].vid == be_pFBConfig->associatedVisualId) { - pGlxVisual = &dmxScreen->glxVisuals[v]; - break; - } - } - - if (pGlxVisual) { - for (v=0; v<pGlxScreen->numVisuals; v++) { - if (glxVisualsMatch(&pGlxScreen->pGlxVisual[v], pGlxVisual)) { - associatedVisualId = pGlxScreen->pGlxVisual[v].vid; - found = 1; - break; - } - } - } - - if (!found) { - associatedVisualId = 0; - pFBConfig->drawableType &= ~(GLX_WINDOW_BIT); - buf[drawableTypeIndex] = pFBConfig->drawableType; - } -#ifdef PANORAMIX - else if (!noPanoramiXExtension) { - /* convert the associated visualId to the panoramix one */ - pFBConfig->associatedVisualId = - PanoramiXTranslateVisualID(screen, v); - } -#endif - } - else { - associatedVisualId = pFBConfig->associatedVisualId; - } - - buf[p++] = GLX_VISUAL_ID; - buf[p++] = associatedVisualId; - - /* SGIS_multisample attributes */ - buf[p++] = GLX_SAMPLES_SGIS; - buf[p++] = pFBConfig->multiSampleSize; - buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; - buf[p++] = pFBConfig->nMultiSampleBuffers; - - /* SGIX_pbuffer specific attributes */ - buf[p++] = GLX_OPTIMAL_PBUFFER_WIDTH_SGIX; - buf[p++] = pFBConfig->optimalPbufferWidth; - buf[p++] = GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX; - buf[p++] = pFBConfig->optimalPbufferHeight; - - buf[p++] = GLX_VISUAL_SELECT_GROUP_SGIX; - buf[p++] = pFBConfig->visualSelectGroup; - - if (client->swapped) { - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_INT_ARRAY((int *)buf, 2*numAttribs); - } - WriteToClient(client, 2*numAttribs * __GLX_SIZE_CARD32, (char *)buf); - } - return Success; -} - -int __glXGetFBConfigsSGIX(__GLXclientState *cl, GLbyte *pc) -{ - xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *)pc; - xGLXGetFBConfigsReq new_req; - - new_req.reqType = req->reqType; - new_req.glxCode = req->glxCode; - new_req.length = req->length; - new_req.screen = req->screen; - - return( __glXGetFBConfigs( cl, (GLbyte *)&new_req ) ); -} - - -int __glXCreateWindow(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXCreateWindowReq *req = (xGLXCreateWindowReq *) pc; - int screen = req->screen; - GLXFBConfigID fbconfigId = req->fbconfig; - XID windowId = req->window; - XID glxwindowId = req->glxwindow; - DrawablePtr pDraw; - ScreenPtr pScreen; - __glXWindow *pGlxWindow; - __GLXFBConfig *pGlxFBConfig = NULL; - VisualPtr pVisual; - VisualID visId; - int i, rc; - - /* - ** Check if windowId is valid - */ - rc = dixLookupDrawable(&pDraw, windowId, client, M_DRAWABLE_WINDOW, - DixAddAccess); - if (rc != Success) - return rc; - - /* - ** Check if screen of window matches screen of fbconfig. - */ - pScreen = pDraw->pScreen; - if (screen != pScreen->myNum) { - return BadMatch; - } - - /* - ** Find the FBConfigRec for this fbconfigid. - */ - if (!(pGlxFBConfig = glxLookupFBConfig(fbconfigId))) { - client->errorValue = fbconfigId; - return __glXBadFBConfig; - } - visId = pGlxFBConfig->associatedVisualId; - - /* - ** Check if the fbconfig supports rendering to windows - */ - if( !(pGlxFBConfig->drawableType & GLX_WINDOW_BIT) ) { - return BadMatch; - } - - if (visId != None) { - /* - ** Check if the visual ID is valid for this screen. - */ - pVisual = pScreen->visuals; - for (i = 0; i < pScreen->numVisuals; i++, pVisual++) { - if (pVisual->vid == visId) { - break; - } - } - if (i == pScreen->numVisuals) { - client->errorValue = visId; - return BadValue; - } - - /* - ** Check if color buffer depth of fbconfig matches depth - ** of window. - */ - if (pVisual->nplanes != pDraw->depth) { - return BadMatch; - } - } else - /* - ** The window was created with no visual that corresponds - ** to fbconfig - */ - return BadMatch; - - /* - ** Check if there is already a fbconfig associated with this window - */ - if ( LookupIDByType(glxwindowId, __glXWindowRes) ) { - client->errorValue = glxwindowId; - return BadAlloc; - } - - pGlxWindow = (__glXWindow *) xalloc(sizeof(__glXWindow)); - if (!pGlxWindow) { - return BadAlloc; - } - - /* - ** Register this GLX window as a resource - */ - if (!(AddResource(glxwindowId, __glXWindowRes, pGlxWindow))) { - return BadAlloc; - } - - pGlxWindow->pDraw = pDraw; - pGlxWindow->type = GLX_GLXWINDOW_TYPE; - pGlxWindow->idExists = True; - pGlxWindow->refcnt = 0; - pGlxWindow->pGlxFBConfig = pGlxFBConfig; - pGlxWindow->pScreen = pScreen; - - return Success; -} - -int __glXDestroyWindow(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc; - XID glxwindow = req->glxwindow; - - /* - ** Check if it's a valid GLX window. - */ - if (!LookupIDByType(glxwindow, __glXWindowRes)) { - client->errorValue = glxwindow; - return __glXBadDrawable; - } - /* - ** The glx window destructor will check whether it's current before - ** freeing anything. - */ - FreeResource(glxwindow, RT_NONE); - - return Success; -} - -int __glXQueryContext(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - __GLXcontext *ctx; - xGLXQueryContextReq *req; - xGLXQueryContextReply reply; - int nProps; - int *sendBuf, *pSendBuf; - int nReplyBytes; - - req = (xGLXQueryContextReq *)pc; - ctx = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); - if (!ctx) { - client->errorValue = req->context; - return __glXBadContext; - } - - nProps = 3; - - reply.length = nProps << 1; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.n = nProps; - - nReplyBytes = reply.length << 2; - sendBuf = (int *)xalloc(nReplyBytes); - pSendBuf = sendBuf; - *pSendBuf++ = GLX_FBCONFIG_ID; - *pSendBuf++ = (int)(ctx->pFBConfig->id); - *pSendBuf++ = GLX_RENDER_TYPE; - *pSendBuf++ = (int)(ctx->pFBConfig->renderType); - *pSendBuf++ = GLX_SCREEN; - *pSendBuf++ = (int)(ctx->pScreen->myNum); - - if (client->swapped) { - __glXSwapQueryContextReply(client, &reply, sendBuf); - } else { - WriteToClient(client, sz_xGLXQueryContextReply, (char *)&reply); - WriteToClient(client, nReplyBytes, (char *)sendBuf); - } - xfree((char *)sendBuf); - - return Success; -} - -int __glXQueryContextInfoEXT(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - __GLXcontext *ctx; - xGLXQueryContextInfoEXTReq *req; - xGLXQueryContextInfoEXTReply reply; - int nProps; - int *sendBuf, *pSendBuf; - int nReplyBytes; - - req = (xGLXQueryContextInfoEXTReq *)pc; - ctx = (__GLXcontext *) SecurityLookupIDByType(client, req->context, __glXContextRes, DixReadAccess); - if (!ctx) { - client->errorValue = req->context; - return __glXBadContext; - } - - nProps = 4; - - reply.length = nProps << 1; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.n = nProps; - - nReplyBytes = reply.length << 2; - sendBuf = (int *)xalloc(nReplyBytes); - pSendBuf = sendBuf; - *pSendBuf++ = GLX_SHARE_CONTEXT_EXT; - *pSendBuf++ = (int)(ctx->share_id); - *pSendBuf++ = GLX_VISUAL_ID_EXT; - *pSendBuf++ = (int)(ctx->pVisual ? ctx->pVisual->vid : 0); - *pSendBuf++ = GLX_SCREEN_EXT; - *pSendBuf++ = (int)(ctx->pScreen->myNum); - *pSendBuf++ = GLX_FBCONFIG_ID; - *pSendBuf++ = (int)(ctx->pFBConfig ? ctx->pFBConfig->id : 0); - - if (client->swapped) { - __glXSwapQueryContextInfoEXTReply(client, &reply, sendBuf); - } else { - WriteToClient(client, sz_xGLXQueryContextInfoEXTReply, (char *)&reply); - WriteToClient(client, nReplyBytes, (char *)sendBuf); - } - xfree((char *)sendBuf); - - return Success; -} - -int __glXCreatePbuffer(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXCreatePbufferReq *req = (xGLXCreatePbufferReq *)pc; - xGLXCreatePbufferReq *be_req; - int screen = req->screen; - GLXFBConfigID fbconfigId = req->fbconfig; - GLXPbuffer pbuffer = req->pbuffer; - __glXPbuffer *pGlxPbuffer; - int numAttribs = req->numAttribs; - int *attr; - ScreenPtr pScreen; - __GLXFBConfig *pGlxFBConfig; - __GLXFBConfig *be_pGlxFBConfig; - XID be_xid; - Display *dpy; - DMXScreenInfo *dmxScreen; - int s; - int from_screen, to_screen; - - /* - ** Look up screen and FBConfig. - */ - if (screen > screenInfo.numScreens) { - /* The client library must send a valid screen number. */ - client->errorValue = screen; - return BadValue; - } - pScreen = screenInfo.screens[screen]; - - /* - ** Find the FBConfigRec for this fbconfigid. - */ - if (!(pGlxFBConfig = glxLookupFBConfig(fbconfigId))) { - client->errorValue = fbconfigId; - return __glXBadFBConfig; - } - - /* - ** Create the GLX part of the Pbuffer. - */ - pGlxPbuffer = (__glXPbuffer *) xalloc(sizeof(__glXPbuffer)); - if (!pGlxPbuffer) { - return BadAlloc; - } - - pGlxPbuffer->be_xids = (XID *) xalloc( sizeof(XID) * screenInfo.numScreens ); - if (!pGlxPbuffer->be_xids) { - xfree(pGlxPbuffer); - return BadAlloc; - } - - /* - * Allocate an XID on the back-end server(s) and send him the request - */ - from_screen = to_screen = screen; -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - dpy = GetBackEndDisplay(cl,s); - be_xid = XAllocID(dpy); - dmxScreen = &dmxScreens[s]; - be_pGlxFBConfig = glxLookupBackEndFBConfig( pGlxFBConfig->id, s ); - - attr = (int *)( req+1 ); - - LockDisplay(dpy); - GetReqExtra(GLXCreatePbuffer, 2 * numAttribs * __GLX_SIZE_CARD32, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXCreatePbuffer; - be_req->screen = be_pGlxFBConfig->screen; - be_req->fbconfig = be_pGlxFBConfig->id; - be_req->pbuffer = be_xid; - be_req->numAttribs = numAttribs; - - /* Send attributes */ - if ( attr != NULL ) { - CARD32 *pc = (CARD32 *)(be_req + 1); - - while (numAttribs-- > 0) { - *pc++ = *attr++; /* token */ - *pc++ = *attr++; /* value */ - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - pGlxPbuffer->be_xids[s] = be_xid; - } - - - pGlxPbuffer->idExists = True; - pGlxPbuffer->refcnt = 0; - pGlxPbuffer->pFBConfig = pGlxFBConfig; - pGlxPbuffer->pScreen = pScreen; - - /* - ** Register the resource. - */ - if (!(AddResource(pbuffer, __glXPbufferRes, pGlxPbuffer))) { - return BadAlloc; - } - - return Success; - -} - -int __glXDestroyPbuffer(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXDestroyPbufferReq *req = (xGLXDestroyPbufferReq *) pc; - xGLXDestroyPbufferReq *be_req; - GLXPbuffer pbuffer = req->pbuffer; - Display *dpy; - int screen; - DMXScreenInfo *dmxScreen; - __glXPbuffer *pGlxPbuffer; - int s; - int from_screen, to_screen; - - /* - ** Check if it's a valid Pbuffer - */ - pGlxPbuffer = (__glXPbuffer *)LookupIDByType(pbuffer, __glXPbufferRes); - if (!pGlxPbuffer) { - client->errorValue = pbuffer; - return __glXBadPbuffer; - } - - screen = pGlxPbuffer->pScreen->myNum; - - from_screen = to_screen = screen; -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - dpy = GetBackEndDisplay(cl,s); - dmxScreen = &dmxScreens[s]; - - /* send the destroy request to the back-end server */ - LockDisplay(dpy); - GetReq(GLXDestroyPbuffer, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXDestroyPbuffer; - be_req->pbuffer = pGlxPbuffer->be_xids[s]; - UnlockDisplay(dpy); - SyncHandle(); - } - - FreeResource(pbuffer, RT_NONE); - - return Success; -} - -int __glXGetDrawableAttributes(__GLXclientState *cl, GLbyte *pc) -{ - xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *)pc; - xGLXGetDrawableAttributesReq *be_req; - xGLXGetDrawableAttributesReply reply; - ClientPtr client = cl->client; - GLXDrawable drawId = req->drawable; - GLXDrawable be_drawable = 0; - DrawablePtr pDraw = NULL; - Display *dpy; - int screen, rc; - DMXScreenInfo *dmxScreen; - CARD32 *attribs = NULL; - int attribs_size; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; -#endif - - if (drawId != None) { - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess); - if (rc == Success) { - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - be_drawable = 0; - screen = pWin->drawable.pScreen->myNum; - - } - else { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - __GLXpixmap *pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - pDraw = pGlxPixmap->pDraw; - screen = pGlxPixmap->pScreen->myNum; - be_drawable = pGlxPixmap->be_xids[screen]; - } - } - - if (!pDraw) { - __glXWindow *pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - pDraw = pGlxWindow->pDraw; - screen = pGlxWindow->pScreen->myNum; - be_drawable = 0; - } - } - - if (!pDraw) { - __glXPbuffer *pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); - if (pGlxPbuffer) { - pDraw = (DrawablePtr)pGlxPbuffer; - screen = pGlxPbuffer->pScreen->myNum; - be_drawable = pGlxPbuffer->be_xids[screen]; - } - } - - - if (!pDraw) { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - - /* if the drawable is a window or GLXWindow - - * we need to find the base id on the back-end server - */ - if (!be_drawable) { - WindowPtr pWin = (WindowPtr)pDraw; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - if (!pXinDraw) { - client->errorValue = drawId; - return __glXBadDrawable; - } - - dixLookupWindow(&pWin, pXinDraw->info[screen].id, client, - DixReadAccess); - } -#endif - - if (pWin) { - be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - if (!be_drawable) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pWin, TRUE ); - be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - } - } - else { - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - - /* send the request to the back-end server */ - dpy = GetBackEndDisplay(cl,screen); - dmxScreen = &dmxScreens[screen]; - - /* make sure drawable exists on back-end */ - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXGetDrawableAttributes, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXGetDrawableAttributes; - be_req->drawable = be_drawable; - be_req->length = req->length; - if (!_XReply(dpy, (xReply *) &reply, 0, False)) { - UnlockDisplay(dpy); - SyncHandle(); - return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); - } - - if (reply.numAttribs) { - attribs_size = 2 * reply.numAttribs * __GLX_SIZE_CARD32; - attribs = (CARD32 *) Xalloc(attribs_size); - if (attribs == NULL) { - UnlockDisplay(dpy); - SyncHandle(); - return BadAlloc; - } - - _XRead(dpy, (char *) attribs, attribs_size); - } - - UnlockDisplay(dpy); - SyncHandle(); - - - /* send the reply back to the client */ - reply.sequenceNumber = client->sequence; - if (client->swapped) { - __glXSwapGetDrawableAttributesReply(client, &reply, (int *)attribs); - } - else { - WriteToClient(client, sz_xGLXGetDrawableAttributesReply, (char *)&reply); - WriteToClient(client, attribs_size, (char *)attribs); - } - - Xfree(attribs); - - return Success; -} - -int __glXChangeDrawableAttributes(__GLXclientState *cl, GLbyte *pc) -{ - xGLXChangeDrawableAttributesReq *req = (xGLXChangeDrawableAttributesReq *)pc; - xGLXChangeDrawableAttributesReq *be_req; - ClientPtr client = cl->client; - GLXDrawable drawId = req->drawable; - GLXDrawable be_drawable = 0; - DrawablePtr pDraw = NULL; - Display *dpy; - int screen, rc; - DMXScreenInfo *dmxScreen; - char *attrbuf; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; - PanoramiXRes *pXinReadDraw = NULL; -#endif - - if (drawId != None) { - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixSetAttrAccess); - if (rc == Success) { - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - be_drawable = 0; - screen = pWin->drawable.pScreen->myNum; - - } - else { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - __GLXpixmap *pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - pDraw = pGlxPixmap->pDraw; - screen = pGlxPixmap->pScreen->myNum; - be_drawable = pGlxPixmap->be_xids[screen]; - } - } - - if (!pDraw) { - __glXWindow *pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - pDraw = pGlxWindow->pDraw; - screen = pGlxWindow->pScreen->myNum; - be_drawable = 0; - } - } - - if (!pDraw) { - __glXPbuffer *pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); - if (pGlxPbuffer) { - pDraw = (DrawablePtr)pGlxPbuffer; - screen = pGlxPbuffer->pScreen->myNum; - be_drawable = pGlxPbuffer->be_xids[screen]; - } - } - - - if (!pDraw) { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - - /* if the drawable is a window or GLXWindow - - * we need to find the base id on the back-end server - */ - if (!be_drawable) { - WindowPtr pWin = (WindowPtr)pDraw; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - if (!pXinDraw) { - client->errorValue = drawId; - return __glXBadDrawable; - } - - dixLookupWindow(&pWin, pXinDraw->info[screen].id, client, - DixReadAccess); - } -#endif - - if (pWin) { - be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - if (!be_drawable) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pWin, TRUE ); - be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - } - } - else { - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - - /* send the request to the back-end server */ - dpy = GetBackEndDisplay(cl,screen); - dmxScreen = &dmxScreens[screen]; - - /* make sure drawable exists on back-end */ - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReqExtra(GLXChangeDrawableAttributes, - 2 * req->numAttribs * __GLX_SIZE_CARD32, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXChangeDrawableAttributes; - be_req->drawable = be_drawable; - be_req->numAttribs = req->numAttribs; - be_req->length = req->length; - - UnlockDisplay(dpy); - SyncHandle(); - - return Success; -} - -int __glXSendLargeCommand(__GLXclientState *cl, GLXContextTag contextTag) -{ - ClientPtr client = cl->client; - xGLXRenderLargeReq *req; - GLint maxSize, amount; - GLint totalRequests, requestNumber; - GLint dataLen; - GLbyte *data; - __GLXcontext *glxc; - int s; - int from_screen, to_screen; - - maxSize = cl->largeCmdMaxReqDataSize - (GLint)sizeof(xGLXRenderLargeReq); - dataLen = cl->largeCmdBytesTotal; - totalRequests = (dataLen / maxSize); - if (dataLen % maxSize) totalRequests++; - - glxc = __glXLookupContextByTag(cl, contextTag); - if (!glxc) { - client->errorValue = contextTag; - return __glXBadContext; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - /* - ** Send enough requests until the whole array is sent. - */ - requestNumber = 1; - data = cl->largeCmdBuf; - while (dataLen > 0) { - amount = dataLen; - if (amount > maxSize) { - amount = maxSize; - } - - for (s=from_screen; s<=to_screen; s++) { - - Display *dpy = GetBackEndDisplay(cl,s); - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - - LockDisplay(dpy); - GetReq(GLXRenderLarge,req); - req->reqType = dmxScreen->glxMajorOpcode; - req->glxCode = X_GLXRenderLarge; - req->contextTag = GetCurrentBackEndTag(cl,contextTag,s); - req->length += (amount + 3) >> 2; - req->requestNumber = requestNumber++; - req->requestTotal = totalRequests; - req->dataBytes = amount; - Data(dpy, ((const char*)data), amount); - dataLen -= amount; - data = ((GLbyte *) data) + amount; - UnlockDisplay(dpy); - SyncHandle(); - } - } - - return Success; -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxfont.h" +#include "dmxsync.h" + +#undef Xmalloc +#undef Xcalloc +#undef Xrealloc +#undef Xfree + +#include "glxserver.h" +#include <GL/glxtokens.h> +#include "g_disptab.h" +#include <pixmapstr.h> +#include <windowstr.h> +#include "glxutil.h" +#include "glxext.h" +#include "unpack.h" + +#include "GL/glxproto.h" +#include "glxvendor.h" +#include "glxvisuals.h" +#include "glxswap.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +extern __GLXFBConfig **__glXFBConfigs; +extern int __glXNumFBConfigs; + +extern __GLXFBConfig *glxLookupFBConfig( GLXFBConfigID id ); +extern __GLXFBConfig *glxLookupFBConfigByVID( VisualID vid ); +extern __GLXFBConfig *glxLookupBackEndFBConfig( GLXFBConfigID id, int screen ); +extern int glxIsExtensionSupported( char *ext ); +extern int __glXGetFBConfigsSGIX(__GLXclientState *cl, GLbyte *pc); + +#define BE_TO_CLIENT_ERROR(x) \ + ( (x) >= __glXerrorBase ? \ + (x) - dmxScreen->glxErrorBase + __glXerrorBase \ + : (x) ) + +Display *GetBackEndDisplay( __GLXclientState *cl, int s ) +{ + if (! cl->be_displays[s] ) { + cl->be_displays[s] = XOpenDisplay( DisplayString(dmxScreens[s].beDisplay) ); + } + return( cl->be_displays[s] ); +} + +/* +** Create a GL context with the given properties. +*/ +static int CreateContext(__GLXclientState *cl, + GLXContextID gcId, + VisualID vid, GLXFBConfigID fbconfigId, + int screen, + GLXContextID shareList, + int isDirect ) +{ + ClientPtr client = cl->client; + xGLXCreateContextReq *be_req; + xGLXCreateNewContextReq *be_new_req; + VisualPtr pVisual; + ScreenPtr pScreen; + __GLXcontext *glxc, *shareglxc; + __GLXvisualConfig *pGlxVisual; + __GLXscreenInfo *pGlxScreen; + VisualID visual = vid; + GLint i; + int from_screen = screen; + int to_screen = screen; + DMXScreenInfo *dmxScreen; + VisualID be_vid; + GLXFBConfigID be_fbconfigId; + int num_be_screens; + Display *dpy; + + /* + ** Check if screen exists. + */ + if (screen >= screenInfo.numScreens) { + client->errorValue = screen; + return BadValue; + } + + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + /* + ** Find the display list space that we want to share. + ** + */ + if (shareList == None) { + shareglxc = NULL; + } else { + shareglxc = (__GLXcontext *) LookupIDByType(shareList, __glXContextRes); + if (!shareglxc) { + client->errorValue = shareList; + return __glXBadContext; + } + } + + /* + ** Allocate memory for the new context + */ + glxc = __glXCalloc(1, sizeof(__GLXcontext)); + if (!glxc) { + return BadAlloc; + } + + pScreen = screenInfo.screens[screen]; + pGlxScreen = &__glXActiveScreens[screen]; + + if (fbconfigId != None) { + glxc->pFBConfig = glxLookupFBConfig( fbconfigId ); + if (!glxc->pFBConfig) { + client->errorValue = fbconfigId; + __glXFree( glxc ); + return BadValue; + } + visual = glxc->pFBConfig->associatedVisualId; + } + else { + glxc->pFBConfig = NULL; + } + + if (visual != None) { + /* + ** Check if the visual ID is valid for this screen. + */ + pVisual = pScreen->visuals; + for (i = 0; i < pScreen->numVisuals; i++, pVisual++) { + if (pVisual->vid == visual) { + break; + } + } + if (i == pScreen->numVisuals) { + client->errorValue = visual; + __glXFree( glxc ); + return BadValue; + } + + pGlxVisual = pGlxScreen->pGlxVisual; + for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { + if (pGlxVisual->vid == visual) { + break; + } + } + if (i == pGlxScreen->numVisuals) { + /* + ** Visual not support on this screen by this OpenGL implementation. + */ + client->errorValue = visual; + __glXFree( glxc ); + return BadValue; + } + + if ( glxc->pFBConfig == NULL ) { + glxc->pFBConfig = glxLookupFBConfigByVID( visual ); + + if ( glxc->pFBConfig == NULL ) { + /* + * visual does not have an FBConfig ??? + client->errorValue = visual; + __glXFree( glxc ); + return BadValue; + */ + } + } + } + else { + pVisual = NULL; + pGlxVisual = NULL; + } + + glxc->pScreen = pScreen; + glxc->pGlxScreen = pGlxScreen; + glxc->pVisual = pVisual; + glxc->pGlxVisual = pGlxVisual; + + /* + * allocate memory for back-end servers info + */ + num_be_screens = to_screen - from_screen + 1; + glxc->real_ids = (XID *)__glXMalloc(sizeof(XID) * num_be_screens); + if (!glxc->real_ids) { + return BadAlloc; + } + glxc->real_vids = (XID *)__glXMalloc(sizeof(XID) * num_be_screens); + if (!glxc->real_vids) { + return BadAlloc; + } + + for (screen = from_screen; screen <= to_screen; screen++) { + int sent = 0; + pScreen = screenInfo.screens[screen]; + pGlxScreen = &__glXActiveScreens[screen]; + dmxScreen = &dmxScreens[screen]; + + if (glxc->pFBConfig) { + __GLXFBConfig *beFBConfig = glxLookupBackEndFBConfig( glxc->pFBConfig->id, + screen ); + be_fbconfigId = beFBConfig->id; + } + + if (pGlxVisual) { + + be_vid = glxMatchGLXVisualInConfigList( pGlxVisual, + dmxScreen->glxVisuals, + dmxScreen->numGlxVisuals ); + + if (!be_vid) { + /* visual is not supported on the back-end server */ + __glXFree( glxc->real_ids ); + __glXFree( glxc->real_vids ); + __glXFree( glxc ); + return BadValue; + } + } + + glxc->real_ids[screen-from_screen] = XAllocID(GetBackEndDisplay(cl,screen)); + + /* send the create context request to the back-end server */ + dpy = GetBackEndDisplay(cl,screen); + if (glxc->pFBConfig) { + /*Since for a certain visual both RGB and COLOR INDEX + *can be on then the only parmeter to choose the renderType + * should be the class of the colormap since all 4 first + * classes does not support RGB mode only COLOR INDEX , + * and so TrueColor and DirectColor does not support COLOR INDEX*/ + int renderType = glxc->pFBConfig->renderType; + if ( pVisual ) { + switch ( pVisual->class ){ + case PseudoColor: + case StaticColor: + case GrayScale: + case StaticGray: + renderType = GLX_COLOR_INDEX_TYPE; + break; + case TrueColor: + case DirectColor: + default: + renderType = GLX_RGBA_TYPE; + break; + } + } + if ( __GLX_IS_VERSION_SUPPORTED(1,3) ) { + LockDisplay(dpy); + GetReq(GLXCreateNewContext,be_new_req); + be_new_req->reqType = dmxScreen->glxMajorOpcode; + be_new_req->glxCode = X_GLXCreateNewContext; + be_new_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; + be_new_req->fbconfig = (unsigned int)be_fbconfigId; + be_new_req->screen = DefaultScreen(dpy); + be_new_req->renderType = renderType; + + be_new_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); + be_new_req->isDirect = 0; + UnlockDisplay(dpy); + glxc->real_vids[screen-from_screen] = be_fbconfigId; + sent = 1; + } + else if (glxIsExtensionSupported("GLX_SGIX_fbconfig")) { + + xGLXCreateContextWithConfigSGIXReq *ext_req; + xGLXVendorPrivateReq *vpreq; + LockDisplay(dpy); + GetReqExtra(GLXVendorPrivate, + sz_xGLXCreateContextWithConfigSGIXReq - sz_xGLXVendorPrivateReq, + vpreq); + ext_req = (xGLXCreateContextWithConfigSGIXReq *)vpreq; + ext_req->reqType = dmxScreen->glxMajorOpcode; + ext_req->glxCode = X_GLXVendorPrivate; + ext_req->vendorCode = X_GLXvop_CreateContextWithConfigSGIX; + ext_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; + ext_req->fbconfig = (unsigned int)be_fbconfigId; + ext_req->screen = DefaultScreen(dpy); + ext_req->renderType = renderType; + ext_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); + ext_req->isDirect = 0; + UnlockDisplay(dpy); + glxc->real_vids[screen-from_screen] = be_fbconfigId; + sent = 1; + } + } + + if (!sent) { + LockDisplay(dpy); + GetReq(GLXCreateContext,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXCreateContext; + be_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; + be_req->visual = (unsigned int)be_vid; + be_req->screen = DefaultScreen(dpy); + be_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); + be_req->isDirect = 0; + UnlockDisplay(dpy); + glxc->real_vids[screen-from_screen] = be_vid; + } + SyncHandle(); + + } + + /* + ** Register this context as a resource. + */ + if (!AddResource(gcId, __glXContextRes, (pointer)glxc)) { + __glXFree( glxc->real_ids ); + __glXFree( glxc->real_vids ); + __glXFree( glxc ); + client->errorValue = gcId; + return BadAlloc; + } + + /* + ** Finally, now that everything is working, setup the rest of the + ** context. + */ + glxc->id = gcId; + glxc->share_id = shareList; + glxc->idExists = GL_TRUE; + glxc->isCurrent = GL_FALSE; + + return Success; +} + +int __glXCreateContext(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; + + return( CreateContext(cl, req->context,req->visual, None, + req->screen, req->shareList, req->isDirect) ); + +} + +int __glXCreateNewContext(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc; + + return( CreateContext(cl, req->context,None, req->fbconfig, + req->screen, req->shareList, req->isDirect) ); + +} + +int __glXCreateContextWithConfigSGIX(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateContextWithConfigSGIXReq *req = (xGLXCreateContextWithConfigSGIXReq *) pc; + + return( CreateContext(cl, req->context, None, req->fbconfig, + req->screen, req->shareList, req->isDirect) ); + +} + +int __glXQueryMaxSwapBarriersSGIX(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXQueryMaxSwapBarriersSGIXReq *req = + (xGLXQueryMaxSwapBarriersSGIXReq *)pc; + xGLXQueryMaxSwapBarriersSGIXReply reply; + + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = 0; + reply.max = QueryMaxSwapBarriersSGIX(req->screen); + + if (client->swapped) { + __glXSwapQueryMaxSwapBarriersSGIXReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXQueryMaxSwapBarriersSGIXReply, + (char *)&reply); + } + + return Success; +} + +int __glXBindSwapBarrierSGIX(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXBindSwapBarrierSGIXReq *req = (xGLXBindSwapBarrierSGIXReq *)pc; + DrawablePtr pDraw; + __GLXpixmap *pGlxPixmap = NULL; + __glXWindow *pGlxWindow = NULL; + int rc; + + rc = dixLookupDrawable(&pDraw, req->drawable, client, 0, DixGetAttrAccess); + if (rc != Success) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->drawable, + __glXPixmapRes); + if (pGlxPixmap) pDraw = pGlxPixmap->pDraw; + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(req->drawable, + __glXWindowRes); + if (pGlxWindow) pDraw = pGlxWindow->pDraw; + } + + if (!pDraw) { + client->errorValue = req->drawable; + return __glXBadDrawable; + } + + return BindSwapBarrierSGIX(pDraw, req->barrier); +} + +int __glXJoinSwapGroupSGIX(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXJoinSwapGroupSGIXReq *req = (xGLXJoinSwapGroupSGIXReq *)pc; + DrawablePtr pDraw, pMember = NULL; + __GLXpixmap *pGlxPixmap = NULL; + __glXWindow *pGlxWindow = NULL; + int rc; + + rc = dixLookupDrawable(&pDraw, req->drawable, client, 0, DixManageAccess); + if (rc != Success) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->drawable, + __glXPixmapRes); + if (pGlxPixmap) pDraw = pGlxPixmap->pDraw; + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(req->drawable, + __glXWindowRes); + if (pGlxWindow) pDraw = pGlxWindow->pDraw; + } + + if (!pDraw) { + client->errorValue = req->drawable; + return __glXBadDrawable; + } + + if (req->member != None) { + rc = dixLookupDrawable(&pMember, req->member, client, 0, + DixGetAttrAccess); + if (rc != Success) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->member, + __glXPixmapRes); + if (pGlxPixmap) pMember = pGlxPixmap->pDraw; + } + + if (!pMember && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(req->member, + __glXWindowRes); + if (pGlxWindow) pMember = pGlxWindow->pDraw; + } + + if (!pMember) { + client->errorValue = req->member; + return __glXBadDrawable; + } + } + + return JoinSwapGroupSGIX(pDraw, pMember); +} + + +/* +** Destroy a GL context as an X resource. +*/ +int __glXDestroyContext(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc; + xGLXDestroyContextReq *be_req; + GLXContextID gcId = req->context; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int s; + + glxc = (__GLXcontext *) LookupIDByType(gcId, __glXContextRes); + if (glxc) { + /* + ** Just free the resource; don't actually destroy the context, + ** because it might be in use. The + ** destroy method will be called by the resource destruction routine + ** if necessary. + */ + FreeResourceByType(gcId, __glXContextRes, FALSE); + + from_screen = to_screen = glxc->pScreen->myNum; + + } else { + client->errorValue = gcId; + return __glXBadContext; + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + /* + * send DestroyContext request to all back-end servers + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXDestroyContext,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXDestroyContext; + be_req->context = glxc->real_ids[s-from_screen]; + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +/*****************************************************************************/ + +/* +** For each client, the server keeps a table of all the contexts that are +** current for that client (each thread of a client may have its own current +** context). These routines add, change, and lookup contexts in the table. +*/ + +/* +** Add a current context, and return the tag that will be used to refer to it. +*/ +static int AddCurrentContext(__GLXclientState *cl, __GLXcontext *glxc, DrawablePtr pDraw) +{ + int i; + int num = cl->numCurrentContexts; + __GLXcontext **table = cl->currentContexts; + + if (!glxc) return -1; + + /* + ** Try to find an empty slot and use it. + */ + for (i=0; i < num; i++) { + if (!table[i]) { + table[i] = glxc; + return i+1; + } + } + /* + ** Didn't find a free slot, so we'll have to grow the table. + */ + if (!num) { + table = (__GLXcontext **) __glXMalloc(sizeof(__GLXcontext *)); + cl->currentDrawables = (DrawablePtr *) __glXMalloc(sizeof(DrawablePtr)); + cl->be_currentCTag = (GLXContextTag *) __glXMalloc(screenInfo.numScreens *sizeof(GLXContextTag)); + } else { + table = (__GLXcontext **) __glXRealloc(table, + (num+1)*sizeof(__GLXcontext *)); + cl->currentDrawables = (DrawablePtr *) __glXRealloc( + cl->currentDrawables , + (num+1)*sizeof(DrawablePtr)); + cl->be_currentCTag = (GLXContextTag *) __glXRealloc(cl->be_currentCTag, + (num+1)*screenInfo.numScreens*sizeof(GLXContextTag)); + } + table[num] = glxc; + cl->currentDrawables[num] = pDraw; + cl->currentContexts = table; + cl->numCurrentContexts++; + + memset(cl->be_currentCTag + num*screenInfo.numScreens, 0, + screenInfo.numScreens * sizeof(GLXContextTag)); + + return num+1; +} + +/* +** Given a tag, change the current context for the corresponding entry. +*/ +static void ChangeCurrentContext(__GLXclientState *cl, __GLXcontext *glxc, + GLXContextTag tag) +{ + __GLXcontext **table = cl->currentContexts; + table[tag-1] = glxc; +} + +/* +** Given a tag, and back-end screen number, retrives the current back-end +** tag. +*/ +int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s) +{ + if (tag >0) { + return( cl->be_currentCTag[ (tag-1)*screenInfo.numScreens + s ] ); + } + else { + return( 0 ); + } +} + +/* +** Given a tag, and back-end screen number, sets the current back-end +** tag. +*/ +static void SetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s, GLXContextTag be_tag) +{ + if (tag >0) { + cl->be_currentCTag[ (tag-1)*screenInfo.numScreens + s ] = be_tag; + } +} + +/* +** For this implementation we have chosen to simply use the index of the +** context's entry in the table as the context tag. A tag must be greater +** than 0. +*/ +__GLXcontext *__glXLookupContextByTag(__GLXclientState *cl, GLXContextTag tag) +{ + int num = cl->numCurrentContexts; + + if (tag < 1 || tag > num) { + return 0; + } else { + return cl->currentContexts[tag-1]; + } +} + +DrawablePtr __glXLookupDrawableByTag(__GLXclientState *cl, GLXContextTag tag) +{ + int num = cl->numCurrentContexts; + + if (tag < 1 || tag > num) { + return 0; + } else { + return cl->currentDrawables[tag-1]; + } +} + +/*****************************************************************************/ + +static void StopUsingContext(__GLXcontext *glxc) +{ + if (glxc) { + if (glxc == __glXLastContext) { + /* Tell server GL library */ + __glXLastContext = 0; + } + glxc->isCurrent = GL_FALSE; + if (!glxc->idExists) { + __glXFreeContext(glxc); + } + } +} + +static void StartUsingContext(__GLXclientState *cl, __GLXcontext *glxc) +{ + glxc->isCurrent = GL_TRUE; +} + +/*****************************************************************************/ +/* +** Make an OpenGL context and drawable current. +*/ +static int MakeCurrent(__GLXclientState *cl, + GLXDrawable drawable, + GLXDrawable readdrawable, + GLXContextID context, + GLXContextTag oldContextTag) +{ + ClientPtr client = cl->client; + DrawablePtr pDraw = NULL; + DrawablePtr pReadDraw = NULL; + xGLXMakeCurrentReadSGIReply new_reply; + xGLXMakeCurrentReq *be_req; + xGLXMakeCurrentReply be_reply; + xGLXMakeContextCurrentReq *be_new_req; + xGLXMakeContextCurrentReply be_new_reply; + GLXDrawable drawId = drawable; + GLXDrawable readId = readdrawable; + GLXContextID contextId = context; + __GLXpixmap *pGlxPixmap = 0; + __GLXpixmap *pReadGlxPixmap = 0; + __GLXcontext *glxc, *prevglxc; + GLXContextTag tag = oldContextTag; + WindowPtr pWin = NULL; + WindowPtr pReadWin = NULL; + __glXWindow *pGlxWindow = NULL; + __glXWindow *pGlxReadWindow = NULL; + __glXPbuffer *pGlxPbuffer = NULL; + __glXPbuffer *pGlxReadPbuffer = NULL; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; + PanoramiXRes *pXinReadDraw = NULL; +#endif + int from_screen = 0; + int to_screen = 0; + int s, rc; + + /* + ** If one is None and the other isn't, it's a bad match. + */ + if ((drawId == None && contextId != None) || + (drawId != None && contextId == None)) { + return BadMatch; + } + + /* + ** Lookup old context. If we have one, it must be in a usable state. + */ + if (tag != 0) { + prevglxc = __glXLookupContextByTag(cl, tag); + if (!prevglxc) { + /* + ** Tag for previous context is invalid. + */ + return __glXBadContextTag; + } + } else { + prevglxc = 0; + } + + /* + ** Lookup new context. It must not be current for someone else. + */ + if (contextId != None) { + glxc = (__GLXcontext *) LookupIDByType(contextId, __glXContextRes); + if (!glxc) { + client->errorValue = contextId; + return __glXBadContext; + } + if ((glxc != prevglxc) && glxc->isCurrent) { + /* Context is current to somebody else */ + return BadAccess; + } + } else { + /* Switching to no context. Ignore new drawable. */ + glxc = 0; + } + + if (drawId != None) { + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); + if (rc == Success) { + if (pDraw->type == DRAWABLE_WINDOW) { + /* + ** Drawable is an X Window. + */ + VisualID vid; + pWin = (WindowPtr)pDraw; + vid = wVisual(pWin); + + new_reply.writeVid = (glxc->pFBConfig ? glxc->pFBConfig->id : vid); + new_reply.writeType = GLX_WINDOW_TYPE; + + /* + ** Check if window and context are similar. + */ + if ((vid != glxc->pVisual->vid) || + (pWin->drawable.pScreen != glxc->pScreen)) { + client->errorValue = drawId; + return BadMatch; + } + + from_screen = to_screen = pWin->drawable.pScreen->myNum; + + } else { + /* + ** An X Pixmap is not allowed as a parameter (a GLX Pixmap + ** is, but it must first be created with glxCreateGLXPixmap). + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + /* + ** Check if pixmap and context are similar. + */ + if (pGlxPixmap->pScreen != glxc->pScreen || + pGlxPixmap->pGlxVisual != glxc->pGlxVisual) { + client->errorValue = drawId; + return BadMatch; + } + pDraw = pGlxPixmap->pDraw; + + new_reply.writeVid = (glxc->pFBConfig ? glxc->pFBConfig->id : + pGlxPixmap->pGlxVisual->vid); + + new_reply.writeType = GLX_PIXMAP_TYPE; + + from_screen = to_screen = pGlxPixmap->pScreen->myNum; + + } + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + /* + ** Drawable is a GLXWindow. + ** + ** Check if GLX window and context are similar. + */ + if (pGlxWindow->pScreen != glxc->pScreen || + pGlxWindow->pGlxFBConfig != glxc->pFBConfig) { + client->errorValue = drawId; + return BadMatch; + } + + pDraw = pGlxWindow->pDraw; + new_reply.writeVid = pGlxWindow->pGlxFBConfig->id; + new_reply.writeType = GLX_GLXWINDOW_TYPE; + } + + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); + if (pGlxPbuffer) { + if (pGlxPbuffer->pScreen != glxc->pScreen || + pGlxPbuffer->pFBConfig != glxc->pFBConfig) { + client->errorValue = drawId; + return BadMatch; + } + + pDraw = (DrawablePtr)pGlxPbuffer; + new_reply.writeVid = pGlxPbuffer->pFBConfig->id; + new_reply.writeType = GLX_PBUFFER_TYPE; + } + } + + if (!pDraw) { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + + } else { + pDraw = 0; + } + + if (readId != None && readId != drawId ) { + rc = dixLookupDrawable(&pReadDraw, readId, client, 0, DixReadAccess); + if (rc == Success) { + if (pReadDraw->type == DRAWABLE_WINDOW) { + /* + ** Drawable is an X Window. + */ + VisualID vid; + pReadWin = (WindowPtr)pDraw; + vid = wVisual(pReadWin); + + new_reply.readVid = (glxc->pFBConfig ? glxc->pFBConfig->id : vid); + new_reply.readType = GLX_WINDOW_TYPE; + + /* + ** Check if window and context are similar. + */ + if ((vid != glxc->pVisual->vid) || + (pReadWin->drawable.pScreen != glxc->pScreen)) { + client->errorValue = readId; + return BadMatch; + } + + } else { + + /* + ** An X Pixmap is not allowed as a parameter (a GLX Pixmap + ** is, but it must first be created with glxCreateGLXPixmap). + */ + client->errorValue = readId; + return __glXBadDrawable; + } + } + + if (!pReadDraw) { + pReadGlxPixmap = (__GLXpixmap *) LookupIDByType(readId, + __glXPixmapRes); + if (pReadGlxPixmap) { + /* + ** Check if pixmap and context are similar. + */ + if (pReadGlxPixmap->pScreen != glxc->pScreen || + pReadGlxPixmap->pGlxVisual != glxc->pGlxVisual) { + client->errorValue = readId; + return BadMatch; + } + pReadDraw = pReadGlxPixmap->pDraw; + + new_reply.readVid = (glxc->pFBConfig ? glxc->pFBConfig->id : + pReadGlxPixmap->pGlxVisual->vid ); + new_reply.readType = GLX_PIXMAP_TYPE; + + } + } + + if (!pReadDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxReadWindow = (__glXWindow *) + LookupIDByType(readId, __glXWindowRes); + if (pGlxReadWindow) { + /* + ** Drawable is a GLXWindow. + ** + ** Check if GLX window and context are similar. + */ + if (pGlxReadWindow->pScreen != glxc->pScreen || + pGlxReadWindow->pGlxFBConfig != glxc->pFBConfig) { + client->errorValue = readId; + return BadMatch; + } + + pReadDraw = pGlxReadWindow->pDraw; + new_reply.readVid = pGlxReadWindow->pGlxFBConfig->id; + new_reply.readType = GLX_GLXWINDOW_TYPE; + } + } + + if (!pReadDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxReadPbuffer = (__glXPbuffer *)LookupIDByType(readId, __glXPbufferRes); + if (pGlxReadPbuffer) { + if (pGlxReadPbuffer->pScreen != glxc->pScreen || + pGlxReadPbuffer->pFBConfig != glxc->pFBConfig) { + client->errorValue = drawId; + return BadMatch; + } + + pReadDraw = (DrawablePtr)pGlxReadPbuffer; + new_reply.readVid = pGlxReadPbuffer->pFBConfig->id; + new_reply.readType = GLX_PBUFFER_TYPE; + } + } + + if (!pReadDraw) { + /* + ** Drawable is neither a Window nor a GLXPixmap. + */ + client->errorValue = readId; + return __glXBadDrawable; + } + + } else { + pReadDraw = pDraw; + pReadGlxPixmap = pGlxPixmap; + pReadWin = pWin; + new_reply.readVid = new_reply.writeVid; + new_reply.readType = new_reply.writeType; + } + + if (prevglxc) { + + if (prevglxc->pGlxPixmap) { + /* + ** The previous drawable was a glx pixmap, release it. + */ + prevglxc->pGlxPixmap->refcnt--; + __glXFreeGLXPixmap( prevglxc->pGlxPixmap ); + prevglxc->pGlxPixmap = 0; + } + + if (prevglxc->pGlxReadPixmap) { + /* + ** The previous drawable was a glx pixmap, release it. + */ + prevglxc->pGlxReadPixmap->refcnt--; + __glXFreeGLXPixmap( prevglxc->pGlxReadPixmap ); + prevglxc->pGlxReadPixmap = 0; + } + + if (prevglxc->pGlxWindow) { + /* + ** The previous drawable was a glx window, release it. + */ + prevglxc->pGlxWindow->refcnt--; + __glXFreeGLXWindow( prevglxc->pGlxWindow ); + prevglxc->pGlxWindow = 0; + } + + if (prevglxc->pGlxReadWindow) { + /* + ** The previous drawable was a glx window, release it. + */ + prevglxc->pGlxReadWindow->refcnt--; + __glXFreeGLXWindow( prevglxc->pGlxReadWindow ); + prevglxc->pGlxReadWindow = 0; + } + + if (prevglxc->pGlxPbuffer) { + /* + ** The previous drawable was a glx Pbuffer, release it. + */ + prevglxc->pGlxPbuffer->refcnt--; + __glXFreeGLXPbuffer( prevglxc->pGlxPbuffer ); + prevglxc->pGlxPbuffer = 0; + } + + if (prevglxc->pGlxReadPbuffer) { + /* + ** The previous drawable was a glx Pbuffer, release it. + */ + prevglxc->pGlxReadPbuffer->refcnt--; + __glXFreeGLXPbuffer( prevglxc->pGlxReadPbuffer ); + prevglxc->pGlxReadPbuffer = 0; + } + + ChangeCurrentContext(cl, glxc, tag); + ChangeCurrentContext(cl, glxc, tag); + StopUsingContext(prevglxc); + } else { + tag = AddCurrentContext(cl, glxc, pDraw); + } + if (glxc) { + + glxc->pGlxPixmap = pGlxPixmap; + glxc->pGlxReadPixmap = pReadGlxPixmap; + glxc->pGlxWindow = pGlxWindow; + glxc->pGlxReadWindow = pGlxReadWindow; + glxc->pGlxPbuffer = pGlxPbuffer; + glxc->pGlxReadPbuffer = pGlxReadPbuffer; + + if (pGlxPixmap) { + pGlxPixmap->refcnt++; + } + + if (pReadGlxPixmap) { + pReadGlxPixmap->refcnt++; + } + + if (pGlxWindow) { + pGlxWindow->refcnt++; + } + + if (pGlxReadWindow) { + pGlxReadWindow->refcnt++; + } + + if (pGlxPbuffer) { + pGlxPbuffer->refcnt++; + } + + if (pGlxReadPbuffer) { + pGlxReadPbuffer->refcnt++; + } + + StartUsingContext(cl, glxc); + new_reply.contextTag = tag; + } else { + new_reply.contextTag = 0; + } + new_reply.length = 0; + new_reply.type = X_Reply; + new_reply.sequenceNumber = client->sequence; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + + if (pDraw && new_reply.writeType != GLX_PBUFFER_TYPE) { + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + } + + if (pReadDraw && pReadDraw != pDraw && + new_reply.readType != GLX_PBUFFER_TYPE) { + pXinReadDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pReadDraw->id, XRC_DRAWABLE, DixReadAccess); + } + else { + pXinReadDraw = pXinDraw; + } + } +#endif + + + /* send the MakeCurrent request to all required + * back-end servers. + */ + for (s = from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + unsigned int be_draw = None; + unsigned int be_read_draw = None; + + if (pGlxPixmap) { + be_draw = pGlxPixmap->be_xids[s]; + } + else if (pGlxPbuffer) { + be_draw = pGlxPbuffer->be_xids[s]; + } +#ifdef PANORAMIX + else if (pXinDraw) { + dixLookupWindow(&pWin, pXinDraw->info[s].id, client, DixReadAccess); + } +#endif + else if (pGlxWindow) { + pWin = (WindowPtr)pGlxWindow->pDraw; + } + + if (pWin && be_draw == None) { + be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + if (!be_draw) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pWin, TRUE ); + be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + } + } + + /* + * Before sending the MakeCurrent request - sync the + * X11 connection to the back-end servers to make sure + * that drawable is already created + */ + dmxSync( dmxScreen, 1 ); + + if (drawId == readId) { + LockDisplay(dpy); + GetReq(GLXMakeCurrent, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXMakeCurrent; + be_req->drawable = be_draw; + be_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); + be_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); + if (!_XReply(dpy, (xReply *) &be_reply, 0, False)) { + + /* The make current failed */ + UnlockDisplay(dpy); + SyncHandle(); + return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); + } + + UnlockDisplay(dpy); + SyncHandle(); + + SetCurrentBackEndTag( cl, tag, s, be_reply.contextTag ); + } + else { + + if (pReadGlxPixmap) { + be_read_draw = pReadGlxPixmap->be_xids[s]; + } + else if (pGlxReadPbuffer) { + be_read_draw = pGlxReadPbuffer->be_xids[s]; + } +#ifdef PANORAMIX + else if (pXinReadDraw) { + dixLookupWindow(&pReadWin, pXinReadDraw->info[s].id, client, + DixReadAccess); + } +#endif + else if (pGlxReadWindow) { + pReadWin = (WindowPtr)pGlxReadWindow->pDraw; + } + + if (pReadWin && be_read_draw == None) { + be_read_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pReadWin))->window; + if (!be_read_draw) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pReadWin, TRUE ); + be_read_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pReadWin))->window; + dmxSync( dmxScreen, 1 ); + } + } + + if ( __GLX_IS_VERSION_SUPPORTED(1,3) ) { + LockDisplay(dpy); + GetReq(GLXMakeContextCurrent, be_new_req); + be_new_req->reqType = dmxScreen->glxMajorOpcode; + be_new_req->glxCode = X_GLXMakeContextCurrent; + be_new_req->drawable = be_draw; + be_new_req->readdrawable = be_read_draw; + be_new_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); + be_new_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); + if (!_XReply(dpy, (xReply *) &be_new_reply, 0, False)) { + + /* The make current failed */ + UnlockDisplay(dpy); + SyncHandle(); + return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); + } + + UnlockDisplay(dpy); + SyncHandle(); + + SetCurrentBackEndTag( cl, tag, s, be_new_reply.contextTag ); + } + else if (glxIsExtensionSupported("GLX_SGI_make_current_read")) { + xGLXMakeCurrentReadSGIReq *ext_req; + xGLXVendorPrivateWithReplyReq *vpreq; + xGLXMakeCurrentReadSGIReply ext_reply; + + LockDisplay(dpy); + GetReqExtra(GLXVendorPrivateWithReply, + sz_xGLXMakeCurrentReadSGIReq - sz_xGLXVendorPrivateWithReplyReq, + vpreq); + ext_req = (xGLXMakeCurrentReadSGIReq *)vpreq; + ext_req->reqType = dmxScreen->glxMajorOpcode; + ext_req->glxCode = X_GLXVendorPrivateWithReply; + ext_req->vendorCode = X_GLXvop_MakeCurrentReadSGI; + ext_req->drawable = be_draw; + ext_req->readable = be_read_draw; + ext_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); + ext_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); + if (!_XReply(dpy, (xReply *) &ext_reply, 0, False)) { + + /* The make current failed */ + UnlockDisplay(dpy); + SyncHandle(); + return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); + } + + UnlockDisplay(dpy); + SyncHandle(); + + SetCurrentBackEndTag( cl, tag, s, ext_reply.contextTag ); + + } + else { + return BadMatch; + } + } + + XFlush( dpy ); + } + + if (client->swapped) { + __glXSwapMakeCurrentReply(client, &new_reply); + } else { + WriteToClient(client, sz_xGLXMakeContextCurrentReply, (char *)&new_reply); + } + + return Success; +} + +int __glXMakeCurrent(__GLXclientState *cl, GLbyte *pc) +{ + xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc; + + return( MakeCurrent(cl, req->drawable, req->drawable, + req->context, req->oldContextTag ) ); +} + +int __glXMakeContextCurrent(__GLXclientState *cl, GLbyte *pc) +{ + xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc; + + return( MakeCurrent(cl, req->drawable, req->readdrawable, + req->context, req->oldContextTag ) ); +} + +int __glXMakeCurrentReadSGI(__GLXclientState *cl, GLbyte *pc) +{ + xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc; + + return( MakeCurrent(cl, req->drawable, req->readable, + req->context, req->oldContextTag ) ); +} + +int __glXIsDirect(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc; + xGLXIsDirectReply reply; + __GLXcontext *glxc; + + /* + ** Find the GL context. + */ + glxc = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); + if (!glxc) { + client->errorValue = req->context; + return __glXBadContext; + } + + reply.isDirect = 0; + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + __glXSwapIsDirectReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply); + } + + return Success; +} + +int __glXQueryVersion(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; +/* xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc; */ + xGLXQueryVersionReply reply; + + /* + ** Server should take into consideration the version numbers sent by the + ** client if it wants to work with older clients; however, in this + ** implementation the server just returns its version number. + */ + reply.majorVersion = __glXVersionMajor; + reply.minorVersion = __glXVersionMinor; + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + __glXSwapQueryVersionReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply); + } + return Success; +} + +int __glXWaitGL(__GLXclientState *cl, GLbyte *pc) +{ + xGLXWaitGLReq *req = (xGLXWaitGLReq *)pc; + xGLXWaitGLReq *be_req = (xGLXWaitGLReq *)pc; + int from_screen = 0; + int to_screen = 0; + int s; + __GLXcontext *glxc = NULL; + + if (req->contextTag != 0) { + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (glxc) { + from_screen = to_screen = glxc->pScreen->myNum; + } + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXWaitGL,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXWaitGL; + be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); + UnlockDisplay(dpy); + SyncHandle(); + + XSync(dpy, False); + } + + return Success; +} + +int __glXWaitX(__GLXclientState *cl, GLbyte *pc) +{ + xGLXWaitXReq *req = (xGLXWaitXReq *)pc; + xGLXWaitXReq *be_req; + int from_screen = 0; + int to_screen = 0; + int s; + __GLXcontext *glxc = NULL; + + if (req->contextTag != 0) { + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (glxc) { + from_screen = to_screen = glxc->pScreen->myNum; + } + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXWaitX,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXWaitX; + be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); + UnlockDisplay(dpy); + SyncHandle(); + + XFlush( dpy ); + } + + return Success; +} + +int __glXCopyContext(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXCopyContextReq *be_req; + xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc; + GLXContextID source = req->source; + GLXContextID dest = req->dest; + GLXContextTag tag = req->contextTag; + unsigned long mask = req->mask; + __GLXcontext *src, *dst; + int s; + int from_screen = 0; + int to_screen = 0; + + /* + ** Check that each context exists. + */ + src = (__GLXcontext *) LookupIDByType(source, __glXContextRes); + if (!src) { + client->errorValue = source; + return __glXBadContext; + } + dst = (__GLXcontext *) LookupIDByType(dest, __glXContextRes); + if (!dst) { + client->errorValue = dest; + return __glXBadContext; + } + + /* + ** They must be in the same address space, and same screen. + */ + if (src->pGlxScreen != dst->pGlxScreen) { + client->errorValue = source; + return BadMatch; + } + + /* + ** The destination context must not be current for any client. + */ + if (dst->isCurrent) { + client->errorValue = dest; + return BadAccess; + } + + if (tag) { + __GLXcontext *tagcx = __glXLookupContextByTag(cl, tag); + + if (!tagcx) { + return __glXBadContextTag; + } + if (tagcx != src) { + /* + ** This would be caused by a faulty implementation of the client + ** library. + */ + return BadMatch; + } + } + + from_screen = to_screen = src->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXCopyContext,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXCopyContext; + be_req->source = (unsigned int)src->real_ids[s-from_screen]; + be_req->dest = (unsigned int)dst->real_ids[s-from_screen]; + be_req->mask = mask; + be_req->contextTag = (tag ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +int __glXGetVisualConfigs(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc; + xGLXGetVisualConfigsReply reply; + __GLXscreenInfo *pGlxScreen; + __GLXvisualConfig *pGlxVisual; + CARD32 buf[__GLX_TOTAL_CONFIG]; + unsigned int screen; + int i, p; + + screen = req->screen; + if (screen > screenInfo.numScreens) { + /* The client library must send a valid screen number. */ + client->errorValue = screen; + return BadValue; + } + pGlxScreen = &__glXActiveScreens[screen]; + + reply.numVisuals = pGlxScreen->numGLXVisuals; + reply.numProps = __GLX_TOTAL_CONFIG; + reply.length = (pGlxScreen->numGLXVisuals * __GLX_SIZE_CARD32 * + __GLX_TOTAL_CONFIG) >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char *)&reply); + + for (i=0; i < pGlxScreen->numVisuals; i++) { + pGlxVisual = &pGlxScreen->pGlxVisual[i]; + if (!pGlxScreen->isGLXvis[i] || pGlxVisual->vid == 0) { + /* not a usable visual */ + continue; + } + p = 0; + buf[p++] = pGlxVisual->vid; + buf[p++] = pGlxVisual->class; + buf[p++] = pGlxVisual->rgba; + + buf[p++] = pGlxVisual->redSize; + buf[p++] = pGlxVisual->greenSize; + buf[p++] = pGlxVisual->blueSize; + buf[p++] = pGlxVisual->alphaSize; + buf[p++] = pGlxVisual->accumRedSize; + buf[p++] = pGlxVisual->accumGreenSize; + buf[p++] = pGlxVisual->accumBlueSize; + buf[p++] = pGlxVisual->accumAlphaSize; + + buf[p++] = pGlxVisual->doubleBuffer; + buf[p++] = pGlxVisual->stereo; + + buf[p++] = pGlxVisual->bufferSize; + buf[p++] = pGlxVisual->depthSize; + buf[p++] = pGlxVisual->stencilSize; + buf[p++] = pGlxVisual->auxBuffers; + buf[p++] = pGlxVisual->level; + /* + ** Add token/value pairs for extensions. + */ + buf[p++] = GLX_VISUAL_CAVEAT_EXT; + buf[p++] = pGlxVisual->visualRating; + buf[p++] = GLX_TRANSPARENT_TYPE_EXT; + buf[p++] = pGlxVisual->transparentPixel; + buf[p++] = GLX_TRANSPARENT_RED_VALUE_EXT; + buf[p++] = pGlxVisual->transparentRed; + buf[p++] = GLX_TRANSPARENT_GREEN_VALUE_EXT; + buf[p++] = pGlxVisual->transparentGreen; + buf[p++] = GLX_TRANSPARENT_BLUE_VALUE_EXT; + buf[p++] = pGlxVisual->transparentBlue; + buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE_EXT; + buf[p++] = pGlxVisual->transparentAlpha; + buf[p++] = GLX_TRANSPARENT_INDEX_VALUE_EXT; + buf[p++] = pGlxVisual->transparentIndex; + buf[p++] = GLX_SAMPLES_SGIS; + buf[p++] = pGlxVisual->multiSampleSize; + buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; + buf[p++] = pGlxVisual->nMultiSampleBuffers; + buf[p++] = GLX_VISUAL_SELECT_GROUP_SGIX; + buf[p++] = pGlxVisual->visualSelectGroup; + + WriteToClient(client, __GLX_SIZE_CARD32 * __GLX_TOTAL_CONFIG, + (char *)buf); + } + return Success; +} + +/* +** Create a GLX Pixmap from an X Pixmap. +*/ +static int CreateGLXPixmap(__GLXclientState *cl, + VisualID visual, GLXFBConfigID fbconfigId, + int screenNum, XID pixmapId, XID glxpixmapId ) +{ + ClientPtr client = cl->client; + xGLXCreateGLXPixmapReq *be_req; + xGLXCreatePixmapReq *be_new_req; + DrawablePtr pDraw; + ScreenPtr pScreen; + VisualPtr pVisual; + __GLXpixmap *pGlxPixmap; + __GLXscreenInfo *pGlxScreen; + __GLXvisualConfig *pGlxVisual; + __GLXFBConfig *pFBConfig; + int i, s, rc; + int from_screen, to_screen; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; +#endif + + rc = dixLookupDrawable(&pDraw, pixmapId, client, M_DRAWABLE_PIXMAP, + DixAddAccess); + if (rc != Success) + return rc; + + /* + ** Check if screen of visual matches screen of pixmap. + */ + pScreen = pDraw->pScreen; + if (screenNum != pScreen->myNum) { + return BadMatch; + } + + if (fbconfigId == NULL && visual == NULL) { + return BadValue; + } + + if (fbconfigId != None) { + pFBConfig = glxLookupFBConfig( fbconfigId ); + if (!pFBConfig) { + client->errorValue = fbconfigId; + return BadValue; + } + visual = pFBConfig->associatedVisualId; + } + else { + pFBConfig = NULL; + } + + if (visual != None) { + /* + ** Find the VisualRec for this visual. + */ + pVisual = pScreen->visuals; + for (i=0; i < pScreen->numVisuals; i++, pVisual++) { + if (pVisual->vid == visual) { + break; + } + } + if (i == pScreen->numVisuals) { + client->errorValue = visual; + return BadValue; + } + /* + ** Check if depth of visual matches depth of pixmap. + */ + if (pVisual->nplanes != pDraw->depth) { + client->errorValue = visual; + return BadMatch; + } + + /* + ** Get configuration of the visual. + */ + pGlxScreen = &__glXActiveScreens[screenNum]; + pGlxVisual = pGlxScreen->pGlxVisual; + for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { + if (pGlxVisual->vid == visual) { + break; + } + } + if (i == pGlxScreen->numVisuals) { + /* + ** Visual not support on this screen by this OpenGL implementation. + */ + client->errorValue = visual; + return BadValue; + } + + + /* find the FBConfig for that visual (if any) */ + if ( pFBConfig == NULL ) { + pFBConfig = glxLookupFBConfigByVID( visual ); + + if ( pFBConfig == NULL ) { + /* + * visual does not have an FBConfig ??? + client->errorValue = visual; + return BadValue; + */ + } + } + } + else { + pVisual = NULL; + pGlxVisual = NULL; + } + + pGlxPixmap = (__GLXpixmap *) __glXMalloc(sizeof(__GLXpixmap)); + if (!pGlxPixmap) { + return BadAlloc; + } + pGlxPixmap->be_xids = (XID *) __glXMalloc(sizeof(XID) * screenInfo.numScreens); + if (!pGlxPixmap->be_xids) { + __glXFree( pGlxPixmap ); + return BadAlloc; + } + + pGlxPixmap->pDraw = pDraw; + pGlxPixmap->pGlxScreen = pGlxScreen; + pGlxPixmap->pGlxVisual = pGlxVisual; + pGlxPixmap->pFBConfig = pFBConfig; + pGlxPixmap->pScreen = pScreen; + pGlxPixmap->idExists = True; + pGlxPixmap->refcnt = 0; + + /* + ** Bump the ref count on the X pixmap so it won't disappear. + */ + ((PixmapPtr) pDraw)->refcnt++; + + /* + * send the request to the back-end server(s) + */ + from_screen = to_screen = screenNum; +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + Pixmap be_pixmap; + DrawablePtr pRealDraw = pDraw; + +#ifdef PANORAMIX + if (pXinDraw) { + dixLookupDrawable(&pRealDraw, pXinDraw->info[s].id, client, 0, + DixAddAccess); + } +#endif + + be_pixmap = (DMX_GET_PIXMAP_PRIV((PixmapPtr)pRealDraw))->pixmap; + + /* make sure pixmap already created on back-end */ + dmxSync( dmxScreen, 1 ); + + if ( pFBConfig && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + __GLXFBConfig *be_FBConfig = glxLookupBackEndFBConfig( pFBConfig->id, s ); + + LockDisplay(dpy); + pGlxPixmap->be_xids[s] = XAllocID(dpy); + GetReq(GLXCreatePixmap,be_new_req); + be_new_req->reqType = dmxScreen->glxMajorOpcode; + be_new_req->glxCode = X_GLXCreatePixmap; + be_new_req->screen = DefaultScreen(dpy); + be_new_req->fbconfig = be_FBConfig->id; + be_new_req->pixmap = (unsigned int)be_pixmap; + be_new_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; + be_new_req->numAttribs = 0; + UnlockDisplay(dpy); + SyncHandle(); + } + else if (pFBConfig && glxIsExtensionSupported("GLX_SGIX_fbconfig")) { + __GLXFBConfig *be_FBConfig = glxLookupBackEndFBConfig( pFBConfig->id, s ); + xGLXCreateGLXPixmapWithConfigSGIXReq *ext_req; + xGLXVendorPrivateReq *vpreq; + + LockDisplay(dpy); + pGlxPixmap->be_xids[s] = XAllocID(dpy); + GetReqExtra(GLXVendorPrivate, + sz_xGLXCreateGLXPixmapWithConfigSGIXReq-sz_xGLXVendorPrivateReq, + vpreq); + ext_req = (xGLXCreateGLXPixmapWithConfigSGIXReq *)vpreq; + ext_req->reqType = dmxScreen->glxMajorOpcode; + ext_req->glxCode = X_GLXVendorPrivate; + ext_req->vendorCode = X_GLXvop_CreateGLXPixmapWithConfigSGIX; + ext_req->screen = DefaultScreen(dpy); + ext_req->fbconfig = be_FBConfig->id; + ext_req->pixmap = (unsigned int)be_pixmap; + ext_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; + UnlockDisplay(dpy); + SyncHandle(); + } + else if (pGlxVisual) { + LockDisplay(dpy); + pGlxPixmap->be_xids[s] = XAllocID(dpy); + GetReq(GLXCreateGLXPixmap,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXCreateGLXPixmap; + be_req->screen = DefaultScreen(dpy); + be_req->visual = (unsigned int)glxMatchGLXVisualInConfigList( + pGlxVisual, + dmxScreen->glxVisuals, + dmxScreen->numGlxVisuals ); + be_req->pixmap = (unsigned int)be_pixmap; + be_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; + UnlockDisplay(dpy); + SyncHandle(); + } + else { + client->errorValue = ( visual ? visual : fbconfigId ); + __glXFree( pGlxPixmap ); + return BadValue; + } + + XFlush( dpy ); + } + + if (!(AddResource(glxpixmapId, __glXPixmapRes, pGlxPixmap))) { + __glXFree( pGlxPixmap ); + return BadAlloc; + } + + return Success; +} + +int __glXCreateGLXPixmap(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc; + + return( CreateGLXPixmap(cl, req->visual, None, + req->screen, req->pixmap, req->glxpixmap) ); +} + +int __glXCreatePixmap(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreatePixmapReq *req = (xGLXCreatePixmapReq *) pc; + + return( CreateGLXPixmap(cl, None, req->fbconfig, + req->screen, req->pixmap, req->glxpixmap) ); +} + +int __glXDestroyGLXPixmap(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc; + XID glxpixmap = req->glxpixmap; + __GLXpixmap *pGlxPixmap; + int s; + int from_screen, to_screen; + + /* + ** Check if it's a valid GLX pixmap. + */ + pGlxPixmap = (__GLXpixmap *)LookupIDByType(glxpixmap, __glXPixmapRes); + if (!pGlxPixmap) { + client->errorValue = glxpixmap; + return __glXBadPixmap; + } + FreeResource(glxpixmap, FALSE); + + /* + * destroy the pixmap on the back-end server(s). + */ + from_screen = to_screen = pGlxPixmap->pDraw->pScreen->myNum; +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + /* make sure pixmap exist in back-end */ + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXDestroyGLXPixmap,req); + req->reqType = dmxScreen->glxMajorOpcode; + req->glxCode = X_GLXDestroyGLXPixmap; + req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; + UnlockDisplay(dpy); + SyncHandle(); + } + + + return Success; +} + +/*****************************************************************************/ + +/* +** NOTE: There is no portable implementation for swap buffers as of +** this time that is of value. Consequently, this code must be +** implemented by somebody other than SGI. +*/ +int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag) +{ + ClientPtr client = cl->client; + DrawablePtr pDraw; + xGLXSwapBuffersReq *be_req; + WindowPtr pWin = NULL; + __GLXpixmap *pGlxPixmap = NULL; + __GLXcontext *glxc = NULL; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; +#endif + __glXWindow *pGlxWindow = NULL; + int from_screen = 0; + int to_screen = 0; + int s, rc; + + /* + ** Check that the GLX drawable is valid. + */ + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); + if (rc == Success) { + from_screen = to_screen = pDraw->pScreen->myNum; + + if (pDraw->type == DRAWABLE_WINDOW) { + /* + ** Drawable is an X window. + */ + pWin = (WindowPtr)pDraw; + } else { + /* + ** Drawable is an X pixmap, which is not allowed. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + /* + ** Drawable is a GLX pixmap. + */ + pDraw = pGlxPixmap->pDraw; + from_screen = to_screen = pGlxPixmap->pScreen->myNum; + } + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + /* + ** Drawable is a GLXWindow. + */ + pDraw = pGlxWindow->pDraw; + from_screen = to_screen = pGlxWindow->pScreen->myNum; + } + } + + if (!pDraw) { + /* + ** Drawable is neither a X window nor a GLX pixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + + if (tag) { + glxc = __glXLookupContextByTag(cl, tag); + if (!glxc) { + return __glXBadContextTag; + } + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + } +#endif + + /* If requested, send a glFinish to all back-end servers before swapping. */ + if (dmxGLXFinishSwap) { + for (s=from_screen; s<=to_screen; s++) { + Display *dpy = GetBackEndDisplay(cl,s); + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + xGLXSingleReq *finishReq; + xGLXSingleReply reply; + +#define X_GLXSingle 0 /* needed by GetReq below */ + + LockDisplay(dpy); + GetReq(GLXSingle,finishReq); + finishReq->reqType = dmxScreen->glxMajorOpcode; + finishReq->glxCode = X_GLsop_Finish; + finishReq->contextTag = (tag ? GetCurrentBackEndTag(cl,tag,s) : 0); + (void) _XReply(dpy, (xReply*) &reply, 0, False); + UnlockDisplay(dpy); + SyncHandle(); + } + } + + /* If requested, send an XSync to all back-end servers before swapping. */ + if (dmxGLXSyncSwap) { + for (s=from_screen; s<=to_screen; s++) + XSync(GetBackEndDisplay(cl,s), False); + } + + + /* send the SwapBuffers request to all back-end servers */ + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + unsigned int be_draw = 0; + + if (pGlxPixmap) { + be_draw = (unsigned int)pGlxPixmap->be_xids[s]; + } +#ifdef PANORAMIX + else if (pXinDraw) { + dixLookupWindow(&pWin, pXinDraw->info[s].id, client, DixReadAccess); + } +#endif + else if (pGlxWindow) { + pWin = (WindowPtr)pGlxWindow->pDraw; + } + + if (pWin && !be_draw) { + be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + if (!be_draw) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pWin, TRUE ); + be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + } + } + + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXSwapBuffers,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXSwapBuffers; + be_req->drawable = be_draw; + be_req->contextTag = ( tag ? GetCurrentBackEndTag(cl,tag,s) : 0 ); + UnlockDisplay(dpy); + SyncHandle(); + XFlush(dpy); + } + + return Success; +} + +int __glXSwapBuffers(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + DrawablePtr pDraw; + xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc; + GLXContextTag tag = req->contextTag; + XID drawId = req->drawable; + __GLXpixmap *pGlxPixmap = NULL; + __GLXcontext *glxc = NULL; + __glXWindow *pGlxWindow = NULL; + int rc; + + /* + ** Check that the GLX drawable is valid. + */ + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); + if (rc == Success) { + if (pDraw->type != DRAWABLE_WINDOW) { + /* + ** Drawable is an X pixmap, which is not allowed. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + /* + ** Drawable is a GLX pixmap. + */ + pDraw = pGlxPixmap->pDraw; + } + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + /* + ** Drawable is a GLXWindow. + */ + pDraw = pGlxWindow->pDraw; + } + } + + if (!pDraw) { + /* + ** Drawable is neither a X window nor a GLX pixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + + if (tag) { + glxc = __glXLookupContextByTag(cl, tag); + if (!glxc) { + return __glXBadContextTag; + } + } + + if (pDraw && + pDraw->type == DRAWABLE_WINDOW && + DMX_GET_WINDOW_PRIV((WindowPtr)pDraw)->swapGroup) { + return SGSwapBuffers(cl, drawId, tag, pDraw); + } + + return __glXDoSwapBuffers(cl, drawId, tag); +} + + +/************************************************************************/ + +/* +** Render and Renderlarge are not in the GLX API. They are used by the GLX +** client library to send batches of GL rendering commands. +*/ + +/* +** Execute all the drawing commands in a request. +*/ +int __glXRender(__GLXclientState *cl, GLbyte *pc) +{ + xGLXRenderReq *req; + xGLXRenderReq *be_req; + int size; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int s; + + /* + ** NOTE: much of this code also appears in the byteswapping version of this + ** routine, __glXSwapRender(). Any changes made here should also be + ** duplicated there. + */ + + req = (xGLXRenderReq *) pc; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXRenderReq; + size = (req->length << 2) - sz_xGLXRenderReq; + + /* + * just forward the request to back-end server(s) + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXRender,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXRender; + be_req->length = req->length; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + _XSend(dpy, (const char *)pc, size); + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +/* +** Execute a large rendering request (one that spans multiple X requests). +*/ +int __glXRenderLarge(__GLXclientState *cl, GLbyte *pc) +{ + xGLXRenderLargeReq *req; + xGLXRenderLargeReq *be_req; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int s; + + /* + ** NOTE: much of this code also appears in the byteswapping version of this + ** routine, __glXSwapRenderLarge(). Any changes made here should also be + ** duplicated there. + */ + + req = (xGLXRenderLargeReq *) pc; + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXRenderLargeReq; + + /* + * just forward the request to back-end server(s) + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + GetReq(GLXRenderLarge,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXRenderLarge; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + be_req->length = req->length; + be_req->requestNumber = req->requestNumber; + be_req->requestTotal = req->requestTotal; + be_req->dataBytes = req->dataBytes; + Data(dpy, (const char *)pc, req->dataBytes); + UnlockDisplay(dpy); + SyncHandle(); + + } + + return Success; +} + + +/************************************************************************/ + +int __glXVendorPrivate(__GLXclientState *cl, GLbyte *pc) +{ + xGLXVendorPrivateReq *req; + + req = (xGLXVendorPrivateReq *) pc; + + switch( req->vendorCode ) { + + case X_GLvop_DeleteTexturesEXT: + return __glXVForwardSingleReq( cl, pc ); + break; + + case X_GLXvop_SwapIntervalSGI: + if (glxIsExtensionSupported("SGI_swap_control")) { + return __glXVForwardSingleReq( cl, pc ); + } + else { + return Success; + } + break; + +#if 0 /* glx 1.3 */ + case X_GLXvop_CreateGLXVideoSourceSGIX: + break; + case X_GLXvop_DestroyGLXVideoSourceSGIX: + break; + case X_GLXvop_CreateGLXPixmapWithConfigSGIX: + break; + case X_GLXvop_DestroyGLXPbufferSGIX: + break; + case X_GLXvop_ChangeDrawableAttributesSGIX: + break; +#endif + + case X_GLXvop_BindSwapBarrierSGIX: + return __glXBindSwapBarrierSGIX( cl, pc ); + break; + + case X_GLXvop_JoinSwapGroupSGIX: + return __glXJoinSwapGroupSGIX( cl, pc ); + break; + + case X_GLXvop_CreateContextWithConfigSGIX: + return __glXCreateContextWithConfigSGIX( cl, pc ); + break; + + default: + /* + ** unsupported private request + */ + cl->client->errorValue = req->vendorCode; + return __glXUnsupportedPrivateRequest; + } + + cl->client->errorValue = req->vendorCode; + return __glXUnsupportedPrivateRequest; + +} + +int __glXVendorPrivateWithReply(__GLXclientState *cl, GLbyte *pc) +{ + xGLXVendorPrivateWithReplyReq *req; + + req = (xGLXVendorPrivateWithReplyReq *) pc; + + switch( req->vendorCode ) { + + case X_GLvop_GetConvolutionFilterEXT: + case X_GLvop_GetConvolutionParameterfvEXT: + case X_GLvop_GetConvolutionParameterivEXT: + case X_GLvop_GetSeparableFilterEXT: + case X_GLvop_GetHistogramEXT: + case X_GLvop_GetHistogramParameterivEXT: + case X_GLvop_GetMinmaxEXT: + case X_GLvop_GetMinmaxParameterfvEXT: + case X_GLvop_GetMinmaxParameterivEXT: + case X_GLvop_AreTexturesResidentEXT: + case X_GLvop_IsTextureEXT: + return( __glXVForwardPipe0WithReply(cl, pc) ); + break; + + case X_GLvop_GenTexturesEXT: + return( __glXVForwardAllWithReply(cl, pc) ); + break; + + +#if 0 /* glx1.3 */ + case X_GLvop_GetDetailTexFuncSGIS: + case X_GLvop_GetSharpenTexFuncSGIS: + case X_GLvop_GetColorTableSGI: + case X_GLvop_GetColorTableParameterfvSGI: + case X_GLvop_GetColorTableParameterivSGI: + case X_GLvop_GetTexFilterFuncSGIS: + case X_GLvop_GetInstrumentsSGIX: + case X_GLvop_InstrumentsBufferSGIX: + case X_GLvop_PollInstrumentsSGIX: + case X_GLvop_FlushRasterSGIX: + case X_GLXvop_CreateGLXPbufferSGIX: + case X_GLXvop_GetDrawableAttributesSGIX: + case X_GLXvop_QueryHyperpipeNetworkSGIX: + case X_GLXvop_QueryHyperpipeConfigSGIX: + case X_GLXvop_HyperpipeConfigSGIX: + case X_GLXvop_DestroyHyperpipeConfigSGIX: +#endif + case X_GLXvop_QueryMaxSwapBarriersSGIX: + return( __glXQueryMaxSwapBarriersSGIX(cl, pc) ); + break; + + case X_GLXvop_GetFBConfigsSGIX: + return( __glXGetFBConfigsSGIX(cl, pc) ); + break; + + case X_GLXvop_MakeCurrentReadSGI: + return( __glXMakeCurrentReadSGI(cl, pc) ); + break; + + case X_GLXvop_QueryContextInfoEXT: + return( __glXQueryContextInfoEXT(cl,pc) ); + break; + + default: + /* + ** unsupported private request + */ + cl->client->errorValue = req->vendorCode; + return __glXUnsupportedPrivateRequest; + } + +} + +int __glXQueryExtensionsString(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXQueryExtensionsStringReq *req = (xGLXQueryExtensionsStringReq *) pc; + xGLXQueryExtensionsStringReply reply; + GLint screen; + size_t length; + int len, numbytes; + char *be_buf; + +#ifdef FWD_QUERY_REQ + xGLXQueryExtensionsStringReq *be_req; + xGLXQueryExtensionsStringReply be_reply; + DMXScreenInfo *dmxScreen; + Display *dpy; + int slop; +#endif + + screen = req->screen; + + /* + ** Check if screen exists. + */ + if ((screen < 0) || (screen >= screenInfo.numScreens)) { + client->errorValue = screen; + return BadValue; + } + +#ifdef FWD_QUERY_REQ + dmxScreen = &dmxScreens[screen]; + + /* Send the glXQueryServerString request */ + dpy = GetBackEndDisplay(cl,screen); + LockDisplay(dpy); + GetReq(GLXQueryExtensionsString,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXQueryServerString; + be_req->screen = DefaultScreen(dpy); + _XReply(dpy, (xReply*) &be_reply, 0, False); + len = (int)be_reply.length; + numbytes = (int)be_reply.n; + slop = numbytes * __GLX_SIZE_INT8 & 3; + be_buf = (char *)malloc(numbytes); + if (!be_buf) { + /* Throw data on the floor */ + _XEatData(dpy, len); + } else { + _XRead(dpy, (char *)be_buf, numbytes); + if (slop) _XEatData(dpy,4-slop); + } + UnlockDisplay(dpy); + SyncHandle(); + +#else + + be_buf = __glXGetServerString(GLX_EXTENSIONS); + numbytes = strlen(be_buf) + 1; + len = __GLX_PAD(numbytes) >> 2; + +#endif + + length = len; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = len; + reply.n = numbytes; + + if (client->swapped) { + glxSwapQueryExtensionsStringReply(client, &reply, be_buf); + } else { + WriteToClient(client, sz_xGLXQueryExtensionsStringReply,(char *)&reply); + WriteToClient(client, (int)(length << 2), (char *)be_buf); + } + + return Success; +} + +int __glXQueryServerString(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) pc; + xGLXQueryServerStringReply reply; + int name; + GLint screen; + size_t length; + int len, numbytes; + char *be_buf; +#ifdef FWD_QUERY_REQ + xGLXQueryServerStringReq *be_req; + xGLXQueryServerStringReply be_reply; + DMXScreenInfo *dmxScreen; + Display *dpy; + int slop; +#endif + + name = req->name; + screen = req->screen; + /* + ** Check if screen exists. + */ + if ((screen < 0) || (screen >= screenInfo.numScreens)) { + client->errorValue = screen; + return BadValue; + } + +#ifdef FWD_QUERY_REQ + dmxScreen = &dmxScreens[screen]; + + /* Send the glXQueryServerString request */ + dpy = GetBackEndDisplay(cl,screen); + LockDisplay(dpy); + GetReq(GLXQueryServerString,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXQueryServerString; + be_req->screen = DefaultScreen(dpy); + be_req->name = name; + _XReply(dpy, (xReply*) &be_reply, 0, False); + len = (int)be_reply.length; + numbytes = (int)be_reply.n; + slop = numbytes * __GLX_SIZE_INT8 & 3; + be_buf = (char *)malloc(numbytes); + if (!be_buf) { + /* Throw data on the floor */ + _XEatData(dpy, len); + } else { + _XRead(dpy, (char *)be_buf, numbytes); + if (slop) _XEatData(dpy,4-slop); + } + UnlockDisplay(dpy); + SyncHandle(); + +#else + be_buf = __glXGetServerString(name); + numbytes = strlen(be_buf) + 1; + len = __GLX_PAD(numbytes) >> 2; +#endif + + length = len; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = length; + reply.n = numbytes; + + if (client->swapped) { + glxSwapQueryServerStringReply(client, &reply, be_buf); + } else { + WriteToClient(client, sz_xGLXQueryServerStringReply, (char *)&reply); + WriteToClient(client, (int)(length << 2), be_buf); + } + + return Success; +} + +int __glXClientInfo(__GLXclientState *cl, GLbyte *pc) +{ + xGLXClientInfoReq *req = (xGLXClientInfoReq *) pc; + xGLXClientInfoReq *be_req; + const char *buf; + int from_screen = 0; + int to_screen = 0; + int s; + + cl->GLClientmajorVersion = req->major; + cl->GLClientminorVersion = req->minor; + if (cl->GLClientextensions) __glXFree(cl->GLClientextensions); + buf = (const char *)(req+1); + cl->GLClientextensions = strdup(buf); + + to_screen = screenInfo.numScreens - 1; + + for (s=from_screen; s<=to_screen; s++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXClientInfo,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXClientInfo; + be_req->major = req->major; + be_req->minor = req->minor; + be_req->length = req->length; + be_req->numbytes = req->numbytes; + Data(dpy, buf, req->numbytes); + + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +int __glXUseXFont(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXUseXFontReq *req; + xGLXUseXFontReq *be_req; + FontPtr pFont; + __GLXcontext *glxc = NULL; + int from_screen = 0; + int to_screen = 0; + int s; + dmxFontPrivPtr pFontPriv; + DMXScreenInfo *dmxScreen; + Display *dpy; + + req = (xGLXUseXFontReq *) pc; + + if (req->contextTag != 0) { + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (glxc) { + from_screen = to_screen = glxc->pScreen->myNum; + } + } + + /* + ** Font can actually be either the ID of a font or the ID of a GC + ** containing a font. + */ + pFont = (FontPtr)LookupIDByType(req->font, RT_FONT); + if (!pFont) { + GC *pGC = (GC *)LookupIDByType(req->font, RT_GC); + if (!pGC) { + client->errorValue = req->font; + return BadFont; + } + pFont = pGC->font; + } + + pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + + for (s=from_screen; s<=to_screen; s++) { + dmxScreen = &dmxScreens[s]; + dpy = GetBackEndDisplay(cl,s); + + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXUseXFont,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXUseXFont; + be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); + be_req->font = pFontPriv->font[s]->fid; + be_req->first = req->first; + be_req->count = req->count; + be_req->listBase = req->listBase; + UnlockDisplay(dpy); + SyncHandle(); + + XSync( dpy, False ); + } + + return Success; +} + +/* + * start GLX 1.3 here + */ + +int __glXGetFBConfigs(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXGetFBConfigsReq *req = (xGLXGetFBConfigsReq *) pc; + xGLXGetFBConfigsReply reply; + __GLXFBConfig *pFBConfig; + CARD32 buf[2 * __GLX_TOTAL_FBCONFIG_PROPS]; + int numAttribs = __GLX_TOTAL_FBCONFIG_PROPS; + unsigned int screen = req->screen; + int numFBConfigs, i, p; + __GLXscreenInfo *pGlxScreen; + + if (screen > screenInfo.numScreens) { + /* The client library must send a valid screen number. */ + client->errorValue = screen; + return BadValue; + } + + pGlxScreen = &__glXActiveScreens[screen]; + numFBConfigs = __glXNumFBConfigs; + + reply.numFBConfigs = numFBConfigs; + reply.numAttribs = numAttribs; + reply.length = (numFBConfigs * 2 * numAttribs * __GLX_SIZE_CARD32) >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + __GLX_SWAP_INT(&reply.numFBConfigs); + __GLX_SWAP_INT(&reply.numAttribs); + } + WriteToClient(client, sz_xGLXGetFBConfigsReply, (char *)&reply); + + for (i=0; i < numFBConfigs; i++) { + int associatedVisualId = 0; + int drawableTypeIndex; + pFBConfig = __glXFBConfigs[ i * (screenInfo.numScreens+1) ]; + + p = 0; + /* core attributes */ + buf[p++] = GLX_FBCONFIG_ID; + buf[p++] = pFBConfig->id; + buf[p++] = GLX_BUFFER_SIZE; + buf[p++] = pFBConfig->indexBits; + buf[p++] = GLX_LEVEL; + buf[p++] = pFBConfig->level; + buf[p++] = GLX_DOUBLEBUFFER; + buf[p++] = pFBConfig->doubleBufferMode; + buf[p++] = GLX_STEREO; + buf[p++] = pFBConfig->stereoMode; + buf[p++] = GLX_AUX_BUFFERS; + buf[p++] = pFBConfig->maxAuxBuffers; + buf[p++] = GLX_RED_SIZE; + buf[p++] = pFBConfig->redBits; + buf[p++] = GLX_GREEN_SIZE; + buf[p++] = pFBConfig->greenBits; + buf[p++] = GLX_BLUE_SIZE; + buf[p++] = pFBConfig->blueBits; + buf[p++] = GLX_ALPHA_SIZE; + buf[p++] = pFBConfig->alphaBits; + buf[p++] = GLX_DEPTH_SIZE; + buf[p++] = pFBConfig->depthBits; + buf[p++] = GLX_STENCIL_SIZE; + buf[p++] = pFBConfig->stencilBits; + buf[p++] = GLX_ACCUM_RED_SIZE; + buf[p++] = pFBConfig->accumRedBits; + buf[p++] = GLX_ACCUM_GREEN_SIZE; + buf[p++] = pFBConfig->accumGreenBits; + buf[p++] = GLX_ACCUM_BLUE_SIZE; + buf[p++] = pFBConfig->accumBlueBits; + buf[p++] = GLX_ACCUM_ALPHA_SIZE; + buf[p++] = pFBConfig->accumAlphaBits; + buf[p++] = GLX_RENDER_TYPE; + buf[p++] = pFBConfig->renderType; + buf[p++] = GLX_DRAWABLE_TYPE; + drawableTypeIndex = p; + buf[p++] = pFBConfig->drawableType; + buf[p++] = GLX_X_VISUAL_TYPE; + buf[p++] = pFBConfig->visualType; + buf[p++] = GLX_CONFIG_CAVEAT; + buf[p++] = pFBConfig->visualCaveat; + buf[p++] = GLX_TRANSPARENT_TYPE; + buf[p++] = pFBConfig->transparentType; + buf[p++] = GLX_TRANSPARENT_RED_VALUE; + buf[p++] = pFBConfig->transparentRed; + buf[p++] = GLX_TRANSPARENT_GREEN_VALUE; + buf[p++] = pFBConfig->transparentGreen; + buf[p++] = GLX_TRANSPARENT_BLUE_VALUE; + buf[p++] = pFBConfig->transparentBlue; + buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE; + buf[p++] = pFBConfig->transparentAlpha; + buf[p++] = GLX_TRANSPARENT_INDEX_VALUE; + buf[p++] = pFBConfig->transparentIndex; + buf[p++] = GLX_MAX_PBUFFER_WIDTH; + buf[p++] = pFBConfig->maxPbufferWidth; + buf[p++] = GLX_MAX_PBUFFER_HEIGHT; + buf[p++] = pFBConfig->maxPbufferHeight; + buf[p++] = GLX_MAX_PBUFFER_PIXELS; + buf[p++] = pFBConfig->maxPbufferPixels; + + /* + * find the visual of the back-end server and match a visual + * on the proxy. + * do only once - if a visual is not yet associated. + */ + if (pFBConfig->associatedVisualId == (unsigned int)-1) { + DMXScreenInfo *dmxScreen = &dmxScreens[screen]; + __GLXFBConfig *be_pFBConfig = __glXFBConfigs[ i * (screenInfo.numScreens+1)+screen+1 ]; + __GLXvisualConfig *pGlxVisual = NULL; + int v; + int found = 0; + for (v=0; v<dmxScreen->numGlxVisuals; v++) { + if (dmxScreen->glxVisuals[v].vid == be_pFBConfig->associatedVisualId) { + pGlxVisual = &dmxScreen->glxVisuals[v]; + break; + } + } + + if (pGlxVisual) { + for (v=0; v<pGlxScreen->numVisuals; v++) { + if (glxVisualsMatch(&pGlxScreen->pGlxVisual[v], pGlxVisual)) { + associatedVisualId = pGlxScreen->pGlxVisual[v].vid; + found = 1; + break; + } + } + } + + if (!found) { + associatedVisualId = 0; + pFBConfig->drawableType &= ~(GLX_WINDOW_BIT); + buf[drawableTypeIndex] = pFBConfig->drawableType; + } +#ifdef PANORAMIX + else if (!noPanoramiXExtension) { + /* convert the associated visualId to the panoramix one */ + pFBConfig->associatedVisualId = + PanoramiXTranslateVisualID(screen, v); + } +#endif + } + else { + associatedVisualId = pFBConfig->associatedVisualId; + } + + buf[p++] = GLX_VISUAL_ID; + buf[p++] = associatedVisualId; + + /* SGIS_multisample attributes */ + buf[p++] = GLX_SAMPLES_SGIS; + buf[p++] = pFBConfig->multiSampleSize; + buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; + buf[p++] = pFBConfig->nMultiSampleBuffers; + + /* SGIX_pbuffer specific attributes */ + buf[p++] = GLX_OPTIMAL_PBUFFER_WIDTH_SGIX; + buf[p++] = pFBConfig->optimalPbufferWidth; + buf[p++] = GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX; + buf[p++] = pFBConfig->optimalPbufferHeight; + + buf[p++] = GLX_VISUAL_SELECT_GROUP_SGIX; + buf[p++] = pFBConfig->visualSelectGroup; + + if (client->swapped) { + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_INT_ARRAY((int *)buf, 2*numAttribs); + } + WriteToClient(client, 2*numAttribs * __GLX_SIZE_CARD32, (char *)buf); + } + return Success; +} + +int __glXGetFBConfigsSGIX(__GLXclientState *cl, GLbyte *pc) +{ + xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *)pc; + xGLXGetFBConfigsReq new_req; + + new_req.reqType = req->reqType; + new_req.glxCode = req->glxCode; + new_req.length = req->length; + new_req.screen = req->screen; + + return( __glXGetFBConfigs( cl, (GLbyte *)&new_req ) ); +} + + +int __glXCreateWindow(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXCreateWindowReq *req = (xGLXCreateWindowReq *) pc; + int screen = req->screen; + GLXFBConfigID fbconfigId = req->fbconfig; + XID windowId = req->window; + XID glxwindowId = req->glxwindow; + DrawablePtr pDraw; + ScreenPtr pScreen; + __glXWindow *pGlxWindow; + __GLXFBConfig *pGlxFBConfig = NULL; + VisualPtr pVisual; + VisualID visId; + int i, rc; + + /* + ** Check if windowId is valid + */ + rc = dixLookupDrawable(&pDraw, windowId, client, M_DRAWABLE_WINDOW, + DixAddAccess); + if (rc != Success) + return rc; + + /* + ** Check if screen of window matches screen of fbconfig. + */ + pScreen = pDraw->pScreen; + if (screen != pScreen->myNum) { + return BadMatch; + } + + /* + ** Find the FBConfigRec for this fbconfigid. + */ + if (!(pGlxFBConfig = glxLookupFBConfig(fbconfigId))) { + client->errorValue = fbconfigId; + return __glXBadFBConfig; + } + visId = pGlxFBConfig->associatedVisualId; + + /* + ** Check if the fbconfig supports rendering to windows + */ + if( !(pGlxFBConfig->drawableType & GLX_WINDOW_BIT) ) { + return BadMatch; + } + + if (visId != None) { + /* + ** Check if the visual ID is valid for this screen. + */ + pVisual = pScreen->visuals; + for (i = 0; i < pScreen->numVisuals; i++, pVisual++) { + if (pVisual->vid == visId) { + break; + } + } + if (i == pScreen->numVisuals) { + client->errorValue = visId; + return BadValue; + } + + /* + ** Check if color buffer depth of fbconfig matches depth + ** of window. + */ + if (pVisual->nplanes != pDraw->depth) { + return BadMatch; + } + } else + /* + ** The window was created with no visual that corresponds + ** to fbconfig + */ + return BadMatch; + + /* + ** Check if there is already a fbconfig associated with this window + */ + if ( LookupIDByType(glxwindowId, __glXWindowRes) ) { + client->errorValue = glxwindowId; + return BadAlloc; + } + + pGlxWindow = (__glXWindow *) malloc(sizeof(__glXWindow)); + if (!pGlxWindow) { + return BadAlloc; + } + + /* + ** Register this GLX window as a resource + */ + if (!(AddResource(glxwindowId, __glXWindowRes, pGlxWindow))) { + return BadAlloc; + } + + pGlxWindow->pDraw = pDraw; + pGlxWindow->type = GLX_GLXWINDOW_TYPE; + pGlxWindow->idExists = True; + pGlxWindow->refcnt = 0; + pGlxWindow->pGlxFBConfig = pGlxFBConfig; + pGlxWindow->pScreen = pScreen; + + return Success; +} + +int __glXDestroyWindow(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc; + XID glxwindow = req->glxwindow; + + /* + ** Check if it's a valid GLX window. + */ + if (!LookupIDByType(glxwindow, __glXWindowRes)) { + client->errorValue = glxwindow; + return __glXBadDrawable; + } + /* + ** The glx window destructor will check whether it's current before + ** freeing anything. + */ + FreeResource(glxwindow, RT_NONE); + + return Success; +} + +int __glXQueryContext(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + __GLXcontext *ctx; + xGLXQueryContextReq *req; + xGLXQueryContextReply reply; + int nProps; + int *sendBuf, *pSendBuf; + int nReplyBytes; + + req = (xGLXQueryContextReq *)pc; + ctx = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); + if (!ctx) { + client->errorValue = req->context; + return __glXBadContext; + } + + nProps = 3; + + reply.length = nProps << 1; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.n = nProps; + + nReplyBytes = reply.length << 2; + sendBuf = (int *)malloc(nReplyBytes); + pSendBuf = sendBuf; + *pSendBuf++ = GLX_FBCONFIG_ID; + *pSendBuf++ = (int)(ctx->pFBConfig->id); + *pSendBuf++ = GLX_RENDER_TYPE; + *pSendBuf++ = (int)(ctx->pFBConfig->renderType); + *pSendBuf++ = GLX_SCREEN; + *pSendBuf++ = (int)(ctx->pScreen->myNum); + + if (client->swapped) { + __glXSwapQueryContextReply(client, &reply, sendBuf); + } else { + WriteToClient(client, sz_xGLXQueryContextReply, (char *)&reply); + WriteToClient(client, nReplyBytes, (char *)sendBuf); + } + free((char *)sendBuf); + + return Success; +} + +int __glXQueryContextInfoEXT(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + __GLXcontext *ctx; + xGLXQueryContextInfoEXTReq *req; + xGLXQueryContextInfoEXTReply reply; + int nProps; + int *sendBuf, *pSendBuf; + int nReplyBytes; + + req = (xGLXQueryContextInfoEXTReq *)pc; + ctx = (__GLXcontext *) SecurityLookupIDByType(client, req->context, __glXContextRes, DixReadAccess); + if (!ctx) { + client->errorValue = req->context; + return __glXBadContext; + } + + nProps = 4; + + reply.length = nProps << 1; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.n = nProps; + + nReplyBytes = reply.length << 2; + sendBuf = (int *)malloc(nReplyBytes); + pSendBuf = sendBuf; + *pSendBuf++ = GLX_SHARE_CONTEXT_EXT; + *pSendBuf++ = (int)(ctx->share_id); + *pSendBuf++ = GLX_VISUAL_ID_EXT; + *pSendBuf++ = (int)(ctx->pVisual ? ctx->pVisual->vid : 0); + *pSendBuf++ = GLX_SCREEN_EXT; + *pSendBuf++ = (int)(ctx->pScreen->myNum); + *pSendBuf++ = GLX_FBCONFIG_ID; + *pSendBuf++ = (int)(ctx->pFBConfig ? ctx->pFBConfig->id : 0); + + if (client->swapped) { + __glXSwapQueryContextInfoEXTReply(client, &reply, sendBuf); + } else { + WriteToClient(client, sz_xGLXQueryContextInfoEXTReply, (char *)&reply); + WriteToClient(client, nReplyBytes, (char *)sendBuf); + } + free((char *)sendBuf); + + return Success; +} + +int __glXCreatePbuffer(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXCreatePbufferReq *req = (xGLXCreatePbufferReq *)pc; + xGLXCreatePbufferReq *be_req; + int screen = req->screen; + GLXFBConfigID fbconfigId = req->fbconfig; + GLXPbuffer pbuffer = req->pbuffer; + __glXPbuffer *pGlxPbuffer; + int numAttribs = req->numAttribs; + int *attr; + ScreenPtr pScreen; + __GLXFBConfig *pGlxFBConfig; + __GLXFBConfig *be_pGlxFBConfig; + XID be_xid; + Display *dpy; + DMXScreenInfo *dmxScreen; + int s; + int from_screen, to_screen; + + /* + ** Look up screen and FBConfig. + */ + if (screen > screenInfo.numScreens) { + /* The client library must send a valid screen number. */ + client->errorValue = screen; + return BadValue; + } + pScreen = screenInfo.screens[screen]; + + /* + ** Find the FBConfigRec for this fbconfigid. + */ + if (!(pGlxFBConfig = glxLookupFBConfig(fbconfigId))) { + client->errorValue = fbconfigId; + return __glXBadFBConfig; + } + + /* + ** Create the GLX part of the Pbuffer. + */ + pGlxPbuffer = (__glXPbuffer *) malloc(sizeof(__glXPbuffer)); + if (!pGlxPbuffer) { + return BadAlloc; + } + + pGlxPbuffer->be_xids = (XID *) malloc( sizeof(XID) * screenInfo.numScreens ); + if (!pGlxPbuffer->be_xids) { + free(pGlxPbuffer); + return BadAlloc; + } + + /* + * Allocate an XID on the back-end server(s) and send him the request + */ + from_screen = to_screen = screen; +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + dpy = GetBackEndDisplay(cl,s); + be_xid = XAllocID(dpy); + dmxScreen = &dmxScreens[s]; + be_pGlxFBConfig = glxLookupBackEndFBConfig( pGlxFBConfig->id, s ); + + attr = (int *)( req+1 ); + + LockDisplay(dpy); + GetReqExtra(GLXCreatePbuffer, 2 * numAttribs * __GLX_SIZE_CARD32, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXCreatePbuffer; + be_req->screen = be_pGlxFBConfig->screen; + be_req->fbconfig = be_pGlxFBConfig->id; + be_req->pbuffer = be_xid; + be_req->numAttribs = numAttribs; + + /* Send attributes */ + if ( attr != NULL ) { + CARD32 *pc = (CARD32 *)(be_req + 1); + + while (numAttribs-- > 0) { + *pc++ = *attr++; /* token */ + *pc++ = *attr++; /* value */ + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + pGlxPbuffer->be_xids[s] = be_xid; + } + + + pGlxPbuffer->idExists = True; + pGlxPbuffer->refcnt = 0; + pGlxPbuffer->pFBConfig = pGlxFBConfig; + pGlxPbuffer->pScreen = pScreen; + + /* + ** Register the resource. + */ + if (!(AddResource(pbuffer, __glXPbufferRes, pGlxPbuffer))) { + return BadAlloc; + } + + return Success; + +} + +int __glXDestroyPbuffer(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyPbufferReq *req = (xGLXDestroyPbufferReq *) pc; + xGLXDestroyPbufferReq *be_req; + GLXPbuffer pbuffer = req->pbuffer; + Display *dpy; + int screen; + DMXScreenInfo *dmxScreen; + __glXPbuffer *pGlxPbuffer; + int s; + int from_screen, to_screen; + + /* + ** Check if it's a valid Pbuffer + */ + pGlxPbuffer = (__glXPbuffer *)LookupIDByType(pbuffer, __glXPbufferRes); + if (!pGlxPbuffer) { + client->errorValue = pbuffer; + return __glXBadPbuffer; + } + + screen = pGlxPbuffer->pScreen->myNum; + + from_screen = to_screen = screen; +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + dpy = GetBackEndDisplay(cl,s); + dmxScreen = &dmxScreens[s]; + + /* send the destroy request to the back-end server */ + LockDisplay(dpy); + GetReq(GLXDestroyPbuffer, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXDestroyPbuffer; + be_req->pbuffer = pGlxPbuffer->be_xids[s]; + UnlockDisplay(dpy); + SyncHandle(); + } + + FreeResource(pbuffer, RT_NONE); + + return Success; +} + +int __glXGetDrawableAttributes(__GLXclientState *cl, GLbyte *pc) +{ + xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *)pc; + xGLXGetDrawableAttributesReq *be_req; + xGLXGetDrawableAttributesReply reply; + ClientPtr client = cl->client; + GLXDrawable drawId = req->drawable; + GLXDrawable be_drawable = 0; + DrawablePtr pDraw = NULL; + Display *dpy; + int screen, rc; + DMXScreenInfo *dmxScreen; + CARD32 *attribs = NULL; + int attribs_size; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; +#endif + + if (drawId != None) { + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess); + if (rc == Success) { + if (pDraw->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDraw; + be_drawable = 0; + screen = pWin->drawable.pScreen->myNum; + + } + else { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + __GLXpixmap *pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + pDraw = pGlxPixmap->pDraw; + screen = pGlxPixmap->pScreen->myNum; + be_drawable = pGlxPixmap->be_xids[screen]; + } + } + + if (!pDraw) { + __glXWindow *pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + pDraw = pGlxWindow->pDraw; + screen = pGlxWindow->pScreen->myNum; + be_drawable = 0; + } + } + + if (!pDraw) { + __glXPbuffer *pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); + if (pGlxPbuffer) { + pDraw = (DrawablePtr)pGlxPbuffer; + screen = pGlxPbuffer->pScreen->myNum; + be_drawable = pGlxPbuffer->be_xids[screen]; + } + } + + + if (!pDraw) { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + + /* if the drawable is a window or GLXWindow - + * we need to find the base id on the back-end server + */ + if (!be_drawable) { + WindowPtr pWin = (WindowPtr)pDraw; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + if (!pXinDraw) { + client->errorValue = drawId; + return __glXBadDrawable; + } + + dixLookupWindow(&pWin, pXinDraw->info[screen].id, client, + DixReadAccess); + } +#endif + + if (pWin) { + be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + if (!be_drawable) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pWin, TRUE ); + be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + } + } + else { + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + + /* send the request to the back-end server */ + dpy = GetBackEndDisplay(cl,screen); + dmxScreen = &dmxScreens[screen]; + + /* make sure drawable exists on back-end */ + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXGetDrawableAttributes, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXGetDrawableAttributes; + be_req->drawable = be_drawable; + be_req->length = req->length; + if (!_XReply(dpy, (xReply *) &reply, 0, False)) { + UnlockDisplay(dpy); + SyncHandle(); + return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); + } + + if (reply.numAttribs) { + attribs_size = 2 * reply.numAttribs * __GLX_SIZE_CARD32; + attribs = (CARD32 *) malloc(attribs_size); + if (attribs == NULL) { + UnlockDisplay(dpy); + SyncHandle(); + return BadAlloc; + } + + _XRead(dpy, (char *) attribs, attribs_size); + } + + UnlockDisplay(dpy); + SyncHandle(); + + + /* send the reply back to the client */ + reply.sequenceNumber = client->sequence; + if (client->swapped) { + __glXSwapGetDrawableAttributesReply(client, &reply, (int *)attribs); + } + else { + WriteToClient(client, sz_xGLXGetDrawableAttributesReply, (char *)&reply); + WriteToClient(client, attribs_size, (char *)attribs); + } + + Xfree(attribs); + + return Success; +} + +int __glXChangeDrawableAttributes(__GLXclientState *cl, GLbyte *pc) +{ + xGLXChangeDrawableAttributesReq *req = (xGLXChangeDrawableAttributesReq *)pc; + xGLXChangeDrawableAttributesReq *be_req; + ClientPtr client = cl->client; + GLXDrawable drawId = req->drawable; + GLXDrawable be_drawable = 0; + DrawablePtr pDraw = NULL; + Display *dpy; + int screen, rc; + DMXScreenInfo *dmxScreen; + char *attrbuf; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; + PanoramiXRes *pXinReadDraw = NULL; +#endif + + if (drawId != None) { + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixSetAttrAccess); + if (rc == Success) { + if (pDraw->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDraw; + be_drawable = 0; + screen = pWin->drawable.pScreen->myNum; + + } + else { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + __GLXpixmap *pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + pDraw = pGlxPixmap->pDraw; + screen = pGlxPixmap->pScreen->myNum; + be_drawable = pGlxPixmap->be_xids[screen]; + } + } + + if (!pDraw) { + __glXWindow *pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + pDraw = pGlxWindow->pDraw; + screen = pGlxWindow->pScreen->myNum; + be_drawable = 0; + } + } + + if (!pDraw) { + __glXPbuffer *pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); + if (pGlxPbuffer) { + pDraw = (DrawablePtr)pGlxPbuffer; + screen = pGlxPbuffer->pScreen->myNum; + be_drawable = pGlxPbuffer->be_xids[screen]; + } + } + + + if (!pDraw) { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + + /* if the drawable is a window or GLXWindow - + * we need to find the base id on the back-end server + */ + if (!be_drawable) { + WindowPtr pWin = (WindowPtr)pDraw; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + if (!pXinDraw) { + client->errorValue = drawId; + return __glXBadDrawable; + } + + dixLookupWindow(&pWin, pXinDraw->info[screen].id, client, + DixReadAccess); + } +#endif + + if (pWin) { + be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + if (!be_drawable) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pWin, TRUE ); + be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + } + } + else { + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + + /* send the request to the back-end server */ + dpy = GetBackEndDisplay(cl,screen); + dmxScreen = &dmxScreens[screen]; + + /* make sure drawable exists on back-end */ + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReqExtra(GLXChangeDrawableAttributes, + 2 * req->numAttribs * __GLX_SIZE_CARD32, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXChangeDrawableAttributes; + be_req->drawable = be_drawable; + be_req->numAttribs = req->numAttribs; + be_req->length = req->length; + + UnlockDisplay(dpy); + SyncHandle(); + + return Success; +} + +int __glXSendLargeCommand(__GLXclientState *cl, GLXContextTag contextTag) +{ + ClientPtr client = cl->client; + xGLXRenderLargeReq *req; + GLint maxSize, amount; + GLint totalRequests, requestNumber; + GLint dataLen; + GLbyte *data; + __GLXcontext *glxc; + int s; + int from_screen, to_screen; + + maxSize = cl->largeCmdMaxReqDataSize - (GLint)sizeof(xGLXRenderLargeReq); + dataLen = cl->largeCmdBytesTotal; + totalRequests = (dataLen / maxSize); + if (dataLen % maxSize) totalRequests++; + + glxc = __glXLookupContextByTag(cl, contextTag); + if (!glxc) { + client->errorValue = contextTag; + return __glXBadContext; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + /* + ** Send enough requests until the whole array is sent. + */ + requestNumber = 1; + data = cl->largeCmdBuf; + while (dataLen > 0) { + amount = dataLen; + if (amount > maxSize) { + amount = maxSize; + } + + for (s=from_screen; s<=to_screen; s++) { + + Display *dpy = GetBackEndDisplay(cl,s); + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + + LockDisplay(dpy); + GetReq(GLXRenderLarge,req); + req->reqType = dmxScreen->glxMajorOpcode; + req->glxCode = X_GLXRenderLarge; + req->contextTag = GetCurrentBackEndTag(cl,contextTag,s); + req->length += (amount + 3) >> 2; + req->requestNumber = requestNumber++; + req->requestTotal = totalRequests; + req->dataBytes = amount; + Data(dpy, ((const char*)data), amount); + dataLen -= amount; + data = ((GLbyte *) data) + amount; + UnlockDisplay(dpy); + SyncHandle(); + } + } + + return Success; +} diff --git a/xorg-server/hw/dmx/glxProxy/glxext.c b/xorg-server/hw/dmx/glxProxy/glxext.c index 6cd8bb41a..6589e43bb 100644 --- a/xorg-server/hw/dmx/glxProxy/glxext.c +++ b/xorg-server/hw/dmx/glxProxy/glxext.c @@ -1,532 +1,532 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" - -#include "glxserver.h" -#include <windowstr.h> -#include <propertyst.h> -#include <os.h> -#include "g_disptab.h" -#include "glxutil.h" -#include "glxext.h" -#include "glxvisuals.h" -#include "micmap.h" -#include "glxswap.h" - -/* -** Stubs to satisfy miinitext.c references. -*/ -typedef int __GLXprovider; -__GLXprovider __glXDRISWRastProvider; -void GlxPushProvider(__GLXprovider *provider) { } - -/* -** Forward declarations. -*/ -static int __glXSwapDispatch(ClientPtr); -static int __glXDispatch(ClientPtr); - -/* -** Called when the extension is reset. -*/ -static void ResetExtension(ExtensionEntry* extEntry) -{ - __glXFlushContextCache(); - __glXScreenReset(); - SwapBarrierReset(); -} - -/* -** Initialize the per-client context storage. -*/ -static void ResetClientState(int clientIndex) -{ - __GLXclientState *cl = __glXClients[clientIndex]; - Display **keep_be_displays; - int i; - - if (cl->returnBuf) __glXFree(cl->returnBuf); - if (cl->currentContexts) __glXFree(cl->currentContexts); - if (cl->currentDrawables) __glXFree(cl->currentDrawables); - if (cl->largeCmdBuf) __glXFree(cl->largeCmdBuf); - - for (i=0; i< screenInfo.numScreens; i++) { - if (cl->be_displays[i]) - XCloseDisplay( cl->be_displays[i] ); - } - - keep_be_displays = cl->be_displays; - memset(cl, 0, sizeof(__GLXclientState)); - cl->be_displays = keep_be_displays; - - /* - ** By default, assume that the client supports - ** GLX major version 1 minor version 0 protocol. - */ - cl->GLClientmajorVersion = 1; - cl->GLClientminorVersion = 0; - if (cl->GLClientextensions) __glXFree(cl->GLClientextensions); - - memset(cl->be_displays, 0, screenInfo.numScreens * sizeof(Display *)); -} - - -/* -** This procedure is called when the client who created the context goes -** away OR when glXDestroyContext is called. In either case, all we do is -** flag that the ID is no longer valid, and (maybe) free the context. -** use. -*/ -static int ContextGone(__GLXcontext* cx, XID id) -{ - cx->idExists = GL_FALSE; - if (!cx->isCurrent) { - __glXFreeContext(cx); - } - - return True; -} - -/* -** Free a client's state. -*/ -static int ClientGone(int clientIndex, XID id) -{ - __GLXcontext *cx; - __GLXclientState *cl = __glXClients[clientIndex]; - int i; - - if (cl) { - /* - ** Free all the contexts that are current for this client. - */ - for (i=0; i < cl->numCurrentContexts; i++) { - cx = cl->currentContexts[i]; - if (cx) { - cx->isCurrent = GL_FALSE; - if (!cx->idExists) { - __glXFreeContext(cx); - } - } - } - /* - ** Re-initialize the client state structure. Don't free it because - ** we'll probably get another client with this index and use the struct - ** again. There is a maximum of MAXCLIENTS of these structures. - */ - ResetClientState(clientIndex); - } - - return True; -} - -/* -** Free a GLX Pixmap. -*/ -void __glXFreeGLXPixmap( __GLXpixmap *pGlxPixmap ) -{ - if (!pGlxPixmap->idExists && - !pGlxPixmap->refcnt) { - - PixmapPtr pPixmap = (PixmapPtr) pGlxPixmap->pDraw; - - /* - ** The DestroyPixmap routine should decrement the refcount and free - ** only if it's zero. - */ - (*pGlxPixmap->pScreen->DestroyPixmap)(pPixmap); - __glXFree(pGlxPixmap->be_xids); - __glXFree(pGlxPixmap); - } - -} - -static int PixmapGone(__GLXpixmap *pGlxPixmap, XID id) -{ - - pGlxPixmap->idExists = False; - __glXFreeGLXPixmap( pGlxPixmap ); - - return True; -} - -void __glXFreeGLXWindow(__glXWindow *pGlxWindow) -{ - if (!pGlxWindow->idExists && !pGlxWindow->refcnt) { - WindowPtr pWindow = (WindowPtr) pGlxWindow->pDraw; - - if (LookupIDByType(pWindow->drawable.id, RT_WINDOW) == pWindow) { - (*pGlxWindow->pScreen->DestroyWindow)(pWindow); - } - - xfree(pGlxWindow); - } -} - -static void WindowGone(__glXWindow *pGlxWindow, XID id) -{ - pGlxWindow->idExists = False; - __glXFreeGLXWindow(pGlxWindow); -} - -void __glXFreeGLXPbuffer(__glXPbuffer *pGlxPbuffer) -{ - if (!pGlxPbuffer->idExists && !pGlxPbuffer->refcnt) { - xfree(pGlxPbuffer->be_xids); - xfree(pGlxPbuffer); - } -} - -static void PbufferGone(__glXPbuffer *pGlxPbuffer, XID id) -{ - pGlxPbuffer->idExists = False; - __glXFreeGLXPbuffer(pGlxPbuffer); -} - -/* -** Free a context. -*/ -GLboolean __glXFreeContext(__GLXcontext *cx) -{ - if (cx->idExists || cx->isCurrent) return GL_FALSE; - - if (cx->feedbackBuf) __glXFree(cx->feedbackBuf); - if (cx->selectBuf) __glXFree(cx->selectBuf); - if (cx->real_ids) __glXFree(cx->real_ids); - if (cx->real_vids) __glXFree(cx->real_vids); - - if (cx->pGlxPixmap) { - /* - ** The previous drawable was a glx pixmap, release it. - */ - cx->pGlxPixmap->refcnt--; - __glXFreeGLXPixmap( cx->pGlxPixmap ); - cx->pGlxPixmap = 0; - } - - if (cx->pGlxReadPixmap) { - /* - ** The previous drawable was a glx pixmap, release it. - */ - cx->pGlxReadPixmap->refcnt--; - __glXFreeGLXPixmap( cx->pGlxReadPixmap ); - cx->pGlxReadPixmap = 0; - } - - if (cx->pGlxWindow) { - /* - ** The previous drawable was a glx window, release it. - */ - cx->pGlxWindow->refcnt--; - __glXFreeGLXWindow( cx->pGlxWindow ); - cx->pGlxWindow = 0; - } - - if (cx->pGlxReadWindow) { - /* - ** The previous drawable was a glx window, release it. - */ - cx->pGlxReadWindow->refcnt--; - __glXFreeGLXWindow( cx->pGlxReadWindow ); - cx->pGlxReadWindow = 0; - } - - __glXFree(cx); - - if (cx == __glXLastContext) { - __glXFlushContextCache(); - } - - return GL_TRUE; -} - -/* -** Initialize the GLX extension. -*/ -void GlxExtensionInit(void) -{ - ExtensionEntry *extEntry; - int i; - int glxSupported = 1; - - /* - // do not initialize GLX extension if GLX is not supported - // by ALL back-end servers. - */ - for (i=0; i<screenInfo.numScreens; i++) { - glxSupported &= (dmxScreens[i].glxMajorOpcode > 0); - } - - if (!glxSupported || !dmxGLXProxy) { - return; - } - - __glXContextRes = CreateNewResourceType((DeleteType)ContextGone, - "GLXContext"); - __glXClientRes = CreateNewResourceType((DeleteType)ClientGone, - "GLXClient"); - __glXPixmapRes = CreateNewResourceType((DeleteType)PixmapGone, - "GLXPixmap"); - __glXWindowRes = CreateNewResourceType((DeleteType)WindowGone, - "GLXWindow"); - __glXPbufferRes = CreateNewResourceType((DeleteType)PbufferGone, - "GLXPbuffer"); - - if (!__glXContextRes || !__glXClientRes || !__glXPixmapRes || - !__glXWindowRes || !__glXPbufferRes) - return; - - /* - ** Add extension to server extensions. - */ - extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS, - __GLX_NUMBER_ERRORS, __glXDispatch, - __glXSwapDispatch, ResetExtension, - StandardMinorOpcode); - if (!extEntry) { - FatalError("__glXExtensionInit: AddExtensions failed\n"); - return; - } - /* - if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) { - ErrorF("__glXExtensionInit: AddExtensionAlias failed\n"); - return; - } - */ - - __glXerrorBase = extEntry->errorBase; - __glXBadContext = extEntry->errorBase + GLXBadContext; - __glXBadContextState = extEntry->errorBase + GLXBadContextState; - __glXBadDrawable = extEntry->errorBase + GLXBadDrawable; - __glXBadPixmap = extEntry->errorBase + GLXBadPixmap; - __glXBadContextTag = extEntry->errorBase + GLXBadContextTag; - __glXBadCurrentWindow = extEntry->errorBase + GLXBadCurrentWindow; - __glXBadRenderRequest = extEntry->errorBase + GLXBadRenderRequest; - __glXBadLargeRequest = extEntry->errorBase + GLXBadLargeRequest; - __glXUnsupportedPrivateRequest = extEntry->errorBase + - GLXUnsupportedPrivateRequest; - __glXBadFBConfig = extEntry->errorBase + GLXBadFBConfig; - __glXBadPbuffer = extEntry->errorBase + GLXBadPbuffer; - - /* - ** Initialize table of client state. There is never a client 0. - */ - for (i=1; i <= MAXCLIENTS; i++) { - __glXClients[i] = 0; - } - - /* - ** Initialize screen specific data. - */ - __glXScreenInit(screenInfo.numScreens); - - /* - ** Initialize swap barrier support. - */ - SwapBarrierInit(); -} - -/************************************************************************/ - -Bool __glXCoreType(void) -{ - return 0; -} - -/************************************************************************/ - -void GlxSetVisualConfigs(int nconfigs, - __GLXvisualConfig *configs, void **privates) -{ - glxSetVisualConfigs(nconfigs, configs, privates); -} - -static miInitVisualsProcPtr saveInitVisualsProc; - -Bool GlxInitVisuals(VisualPtr *visualp, DepthPtr *depthp, - int *nvisualp, int *ndepthp, - int *rootDepthp, VisualID *defaultVisp, - unsigned long sizes, int bitsPerRGB, - int preferredVis) -{ - Bool ret; - - if (saveInitVisualsProc) { - ret = saveInitVisualsProc(visualp, depthp, nvisualp, ndepthp, - rootDepthp, defaultVisp, sizes, bitsPerRGB, - preferredVis); - if (!ret) - return False; - } - - glxInitVisuals(nvisualp, visualp, defaultVisp, *ndepthp, *depthp,*rootDepthp); - - return True; -} - -void -GlxWrapInitVisuals(miInitVisualsProcPtr *initVisProc) -{ - if (dmxGLXProxy) { - saveInitVisualsProc = *initVisProc; - *initVisProc = GlxInitVisuals; - } -} - -/************************************************************************/ - -void __glXFlushContextCache(void) -{ - __glXLastContext = 0; -} - -/************************************************************************/ - -/* -** Top level dispatcher; all commands are executed from here down. -*/ -static int __glXDispatch(ClientPtr client) -{ - REQUEST(xGLXSingleReq); - CARD8 opcode; - int (*proc)(__GLXclientState *cl, GLbyte *pc); - __GLXclientState *cl; - - opcode = stuff->glxCode; - cl = __glXClients[client->index]; - if (!cl) { - cl = __glXCalloc(1, sizeof(__GLXclientState)); - __glXClients[client->index] = cl; - if (!cl) { - return BadAlloc; - } - - cl->be_displays = __glXCalloc(screenInfo.numScreens, sizeof(Display *)); - if (!cl->be_displays) { - __glXFree( cl ); - return BadAlloc; - } - } - - if (!cl->inUse) { - /* - ** This is first request from this client. Associate a resource - ** with the client so we will be notified when the client dies. - */ - XID xid = FakeClientID(client->index); - if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) { - return BadAlloc; - } - ResetClientState(client->index); - cl->largeCmdRequestsTotal = 0; - cl->inUse = GL_TRUE; - cl->client = client; - } - - /* - ** Check for valid opcode. - */ - if (opcode >= __GLX_SINGLE_TABLE_SIZE) { - return BadRequest; - } - - /* - ** Use the opcode to index into the procedure table. - */ - proc = __glXSingleTable[opcode]; - return (*proc)(cl, (GLbyte *) stuff); -} - -static int __glXSwapDispatch(ClientPtr client) -{ - REQUEST(xGLXSingleReq); - CARD8 opcode; - int (*proc)(__GLXclientState *cl, GLbyte *pc); - __GLXclientState *cl; - - opcode = stuff->glxCode; - cl = __glXClients[client->index]; - if (!cl) { - cl = __glXCalloc(1, sizeof(__GLXclientState)); - __glXClients[client->index] = cl; - if (!cl) { - return BadAlloc; - } - - cl->be_displays = __glXCalloc(screenInfo.numScreens, sizeof(Display *)); - if (!cl->be_displays) { - __glXFree( cl ); - return BadAlloc; - } - } - - if (!cl->inUse) { - /* - ** This is first request from this client. Associate a resource - ** with the client so we will be notified when the client dies. - */ - XID xid = FakeClientID(client->index); - if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) { - return BadAlloc; - } - ResetClientState(client->index); - cl->inUse = GL_TRUE; - cl->client = client; - } - - /* - ** Check for valid opcode. - */ - if (opcode >= __GLX_SINGLE_TABLE_SIZE) { - return BadRequest; - } - - /* - ** Use the opcode to index into the procedure table. - */ - proc = __glXSwapSingleTable[opcode]; - return (*proc)(cl, (GLbyte *) stuff); -} - -int __glXNoSuchSingleOpcode(__GLXclientState *cl, GLbyte *pc) -{ - return BadRequest; -} - -void __glXNoSuchRenderOpcode(GLbyte *pc) -{ - return; -} - +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" + +#include "glxserver.h" +#include <windowstr.h> +#include <propertyst.h> +#include <os.h> +#include "g_disptab.h" +#include "glxutil.h" +#include "glxext.h" +#include "glxvisuals.h" +#include "micmap.h" +#include "glxswap.h" + +/* +** Stubs to satisfy miinitext.c references. +*/ +typedef int __GLXprovider; +__GLXprovider __glXDRISWRastProvider; +void GlxPushProvider(__GLXprovider *provider) { } + +/* +** Forward declarations. +*/ +static int __glXSwapDispatch(ClientPtr); +static int __glXDispatch(ClientPtr); + +/* +** Called when the extension is reset. +*/ +static void ResetExtension(ExtensionEntry* extEntry) +{ + __glXFlushContextCache(); + __glXScreenReset(); + SwapBarrierReset(); +} + +/* +** Initialize the per-client context storage. +*/ +static void ResetClientState(int clientIndex) +{ + __GLXclientState *cl = __glXClients[clientIndex]; + Display **keep_be_displays; + int i; + + if (cl->returnBuf) __glXFree(cl->returnBuf); + if (cl->currentContexts) __glXFree(cl->currentContexts); + if (cl->currentDrawables) __glXFree(cl->currentDrawables); + if (cl->largeCmdBuf) __glXFree(cl->largeCmdBuf); + + for (i=0; i< screenInfo.numScreens; i++) { + if (cl->be_displays[i]) + XCloseDisplay( cl->be_displays[i] ); + } + + keep_be_displays = cl->be_displays; + memset(cl, 0, sizeof(__GLXclientState)); + cl->be_displays = keep_be_displays; + + /* + ** By default, assume that the client supports + ** GLX major version 1 minor version 0 protocol. + */ + cl->GLClientmajorVersion = 1; + cl->GLClientminorVersion = 0; + if (cl->GLClientextensions) __glXFree(cl->GLClientextensions); + + memset(cl->be_displays, 0, screenInfo.numScreens * sizeof(Display *)); +} + + +/* +** This procedure is called when the client who created the context goes +** away OR when glXDestroyContext is called. In either case, all we do is +** flag that the ID is no longer valid, and (maybe) free the context. +** use. +*/ +static int ContextGone(__GLXcontext* cx, XID id) +{ + cx->idExists = GL_FALSE; + if (!cx->isCurrent) { + __glXFreeContext(cx); + } + + return True; +} + +/* +** Free a client's state. +*/ +static int ClientGone(int clientIndex, XID id) +{ + __GLXcontext *cx; + __GLXclientState *cl = __glXClients[clientIndex]; + int i; + + if (cl) { + /* + ** Free all the contexts that are current for this client. + */ + for (i=0; i < cl->numCurrentContexts; i++) { + cx = cl->currentContexts[i]; + if (cx) { + cx->isCurrent = GL_FALSE; + if (!cx->idExists) { + __glXFreeContext(cx); + } + } + } + /* + ** Re-initialize the client state structure. Don't free it because + ** we'll probably get another client with this index and use the struct + ** again. There is a maximum of MAXCLIENTS of these structures. + */ + ResetClientState(clientIndex); + } + + return True; +} + +/* +** Free a GLX Pixmap. +*/ +void __glXFreeGLXPixmap( __GLXpixmap *pGlxPixmap ) +{ + if (!pGlxPixmap->idExists && + !pGlxPixmap->refcnt) { + + PixmapPtr pPixmap = (PixmapPtr) pGlxPixmap->pDraw; + + /* + ** The DestroyPixmap routine should decrement the refcount and free + ** only if it's zero. + */ + (*pGlxPixmap->pScreen->DestroyPixmap)(pPixmap); + __glXFree(pGlxPixmap->be_xids); + __glXFree(pGlxPixmap); + } + +} + +static int PixmapGone(__GLXpixmap *pGlxPixmap, XID id) +{ + + pGlxPixmap->idExists = False; + __glXFreeGLXPixmap( pGlxPixmap ); + + return True; +} + +void __glXFreeGLXWindow(__glXWindow *pGlxWindow) +{ + if (!pGlxWindow->idExists && !pGlxWindow->refcnt) { + WindowPtr pWindow = (WindowPtr) pGlxWindow->pDraw; + + if (LookupIDByType(pWindow->drawable.id, RT_WINDOW) == pWindow) { + (*pGlxWindow->pScreen->DestroyWindow)(pWindow); + } + + free(pGlxWindow); + } +} + +static void WindowGone(__glXWindow *pGlxWindow, XID id) +{ + pGlxWindow->idExists = False; + __glXFreeGLXWindow(pGlxWindow); +} + +void __glXFreeGLXPbuffer(__glXPbuffer *pGlxPbuffer) +{ + if (!pGlxPbuffer->idExists && !pGlxPbuffer->refcnt) { + free(pGlxPbuffer->be_xids); + free(pGlxPbuffer); + } +} + +static void PbufferGone(__glXPbuffer *pGlxPbuffer, XID id) +{ + pGlxPbuffer->idExists = False; + __glXFreeGLXPbuffer(pGlxPbuffer); +} + +/* +** Free a context. +*/ +GLboolean __glXFreeContext(__GLXcontext *cx) +{ + if (cx->idExists || cx->isCurrent) return GL_FALSE; + + if (cx->feedbackBuf) __glXFree(cx->feedbackBuf); + if (cx->selectBuf) __glXFree(cx->selectBuf); + if (cx->real_ids) __glXFree(cx->real_ids); + if (cx->real_vids) __glXFree(cx->real_vids); + + if (cx->pGlxPixmap) { + /* + ** The previous drawable was a glx pixmap, release it. + */ + cx->pGlxPixmap->refcnt--; + __glXFreeGLXPixmap( cx->pGlxPixmap ); + cx->pGlxPixmap = 0; + } + + if (cx->pGlxReadPixmap) { + /* + ** The previous drawable was a glx pixmap, release it. + */ + cx->pGlxReadPixmap->refcnt--; + __glXFreeGLXPixmap( cx->pGlxReadPixmap ); + cx->pGlxReadPixmap = 0; + } + + if (cx->pGlxWindow) { + /* + ** The previous drawable was a glx window, release it. + */ + cx->pGlxWindow->refcnt--; + __glXFreeGLXWindow( cx->pGlxWindow ); + cx->pGlxWindow = 0; + } + + if (cx->pGlxReadWindow) { + /* + ** The previous drawable was a glx window, release it. + */ + cx->pGlxReadWindow->refcnt--; + __glXFreeGLXWindow( cx->pGlxReadWindow ); + cx->pGlxReadWindow = 0; + } + + __glXFree(cx); + + if (cx == __glXLastContext) { + __glXFlushContextCache(); + } + + return GL_TRUE; +} + +/* +** Initialize the GLX extension. +*/ +void GlxExtensionInit(void) +{ + ExtensionEntry *extEntry; + int i; + int glxSupported = 1; + + /* + // do not initialize GLX extension if GLX is not supported + // by ALL back-end servers. + */ + for (i=0; i<screenInfo.numScreens; i++) { + glxSupported &= (dmxScreens[i].glxMajorOpcode > 0); + } + + if (!glxSupported || !dmxGLXProxy) { + return; + } + + __glXContextRes = CreateNewResourceType((DeleteType)ContextGone, + "GLXContext"); + __glXClientRes = CreateNewResourceType((DeleteType)ClientGone, + "GLXClient"); + __glXPixmapRes = CreateNewResourceType((DeleteType)PixmapGone, + "GLXPixmap"); + __glXWindowRes = CreateNewResourceType((DeleteType)WindowGone, + "GLXWindow"); + __glXPbufferRes = CreateNewResourceType((DeleteType)PbufferGone, + "GLXPbuffer"); + + if (!__glXContextRes || !__glXClientRes || !__glXPixmapRes || + !__glXWindowRes || !__glXPbufferRes) + return; + + /* + ** Add extension to server extensions. + */ + extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS, + __GLX_NUMBER_ERRORS, __glXDispatch, + __glXSwapDispatch, ResetExtension, + StandardMinorOpcode); + if (!extEntry) { + FatalError("__glXExtensionInit: AddExtensions failed\n"); + return; + } + /* + if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) { + ErrorF("__glXExtensionInit: AddExtensionAlias failed\n"); + return; + } + */ + + __glXerrorBase = extEntry->errorBase; + __glXBadContext = extEntry->errorBase + GLXBadContext; + __glXBadContextState = extEntry->errorBase + GLXBadContextState; + __glXBadDrawable = extEntry->errorBase + GLXBadDrawable; + __glXBadPixmap = extEntry->errorBase + GLXBadPixmap; + __glXBadContextTag = extEntry->errorBase + GLXBadContextTag; + __glXBadCurrentWindow = extEntry->errorBase + GLXBadCurrentWindow; + __glXBadRenderRequest = extEntry->errorBase + GLXBadRenderRequest; + __glXBadLargeRequest = extEntry->errorBase + GLXBadLargeRequest; + __glXUnsupportedPrivateRequest = extEntry->errorBase + + GLXUnsupportedPrivateRequest; + __glXBadFBConfig = extEntry->errorBase + GLXBadFBConfig; + __glXBadPbuffer = extEntry->errorBase + GLXBadPbuffer; + + /* + ** Initialize table of client state. There is never a client 0. + */ + for (i=1; i <= MAXCLIENTS; i++) { + __glXClients[i] = 0; + } + + /* + ** Initialize screen specific data. + */ + __glXScreenInit(screenInfo.numScreens); + + /* + ** Initialize swap barrier support. + */ + SwapBarrierInit(); +} + +/************************************************************************/ + +Bool __glXCoreType(void) +{ + return 0; +} + +/************************************************************************/ + +void GlxSetVisualConfigs(int nconfigs, + __GLXvisualConfig *configs, void **privates) +{ + glxSetVisualConfigs(nconfigs, configs, privates); +} + +static miInitVisualsProcPtr saveInitVisualsProc; + +Bool GlxInitVisuals(VisualPtr *visualp, DepthPtr *depthp, + int *nvisualp, int *ndepthp, + int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB, + int preferredVis) +{ + Bool ret; + + if (saveInitVisualsProc) { + ret = saveInitVisualsProc(visualp, depthp, nvisualp, ndepthp, + rootDepthp, defaultVisp, sizes, bitsPerRGB, + preferredVis); + if (!ret) + return False; + } + + glxInitVisuals(nvisualp, visualp, defaultVisp, *ndepthp, *depthp,*rootDepthp); + + return True; +} + +void +GlxWrapInitVisuals(miInitVisualsProcPtr *initVisProc) +{ + if (dmxGLXProxy) { + saveInitVisualsProc = *initVisProc; + *initVisProc = GlxInitVisuals; + } +} + +/************************************************************************/ + +void __glXFlushContextCache(void) +{ + __glXLastContext = 0; +} + +/************************************************************************/ + +/* +** Top level dispatcher; all commands are executed from here down. +*/ +static int __glXDispatch(ClientPtr client) +{ + REQUEST(xGLXSingleReq); + CARD8 opcode; + int (*proc)(__GLXclientState *cl, GLbyte *pc); + __GLXclientState *cl; + + opcode = stuff->glxCode; + cl = __glXClients[client->index]; + if (!cl) { + cl = __glXCalloc(1, sizeof(__GLXclientState)); + __glXClients[client->index] = cl; + if (!cl) { + return BadAlloc; + } + + cl->be_displays = __glXCalloc(screenInfo.numScreens, sizeof(Display *)); + if (!cl->be_displays) { + __glXFree( cl ); + return BadAlloc; + } + } + + if (!cl->inUse) { + /* + ** This is first request from this client. Associate a resource + ** with the client so we will be notified when the client dies. + */ + XID xid = FakeClientID(client->index); + if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) { + return BadAlloc; + } + ResetClientState(client->index); + cl->largeCmdRequestsTotal = 0; + cl->inUse = GL_TRUE; + cl->client = client; + } + + /* + ** Check for valid opcode. + */ + if (opcode >= __GLX_SINGLE_TABLE_SIZE) { + return BadRequest; + } + + /* + ** Use the opcode to index into the procedure table. + */ + proc = __glXSingleTable[opcode]; + return (*proc)(cl, (GLbyte *) stuff); +} + +static int __glXSwapDispatch(ClientPtr client) +{ + REQUEST(xGLXSingleReq); + CARD8 opcode; + int (*proc)(__GLXclientState *cl, GLbyte *pc); + __GLXclientState *cl; + + opcode = stuff->glxCode; + cl = __glXClients[client->index]; + if (!cl) { + cl = __glXCalloc(1, sizeof(__GLXclientState)); + __glXClients[client->index] = cl; + if (!cl) { + return BadAlloc; + } + + cl->be_displays = __glXCalloc(screenInfo.numScreens, sizeof(Display *)); + if (!cl->be_displays) { + __glXFree( cl ); + return BadAlloc; + } + } + + if (!cl->inUse) { + /* + ** This is first request from this client. Associate a resource + ** with the client so we will be notified when the client dies. + */ + XID xid = FakeClientID(client->index); + if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) { + return BadAlloc; + } + ResetClientState(client->index); + cl->inUse = GL_TRUE; + cl->client = client; + } + + /* + ** Check for valid opcode. + */ + if (opcode >= __GLX_SINGLE_TABLE_SIZE) { + return BadRequest; + } + + /* + ** Use the opcode to index into the procedure table. + */ + proc = __glXSwapSingleTable[opcode]; + return (*proc)(cl, (GLbyte *) stuff); +} + +int __glXNoSuchSingleOpcode(__GLXclientState *cl, GLbyte *pc) +{ + return BadRequest; +} + +void __glXNoSuchRenderOpcode(GLbyte *pc) +{ + return; +} + diff --git a/xorg-server/hw/dmx/glxProxy/glxscreens.c b/xorg-server/hw/dmx/glxProxy/glxscreens.c index 39978a74d..4c40d2315 100644 --- a/xorg-server/hw/dmx/glxProxy/glxscreens.c +++ b/xorg-server/hw/dmx/glxProxy/glxscreens.c @@ -1,377 +1,377 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxlog.h" - -#undef Xmalloc -#undef Xcalloc -#undef Xrealloc -#undef Xfree - -#include "glxserver.h" - -#include <windowstr.h> - -#include "glxfbconfig.h" - -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -__GLXscreenInfo *__glXActiveScreens; -GLint __glXNumActiveScreens; - -__GLXFBConfig **__glXFBConfigs; -int __glXNumFBConfigs; - -static char GLXServerVendorName[] = "SGI DMX/glxProxy"; -static char GLXServerVersion[64]; -static char GLXServerExtensions[] = - "GLX_EXT_visual_info " - "GLX_EXT_visual_rating " - "GLX_EXT_import_context " - "GLX_SGIX_fbconfig " - "GLX_SGI_make_current_read " - "GLX_SGI_swap_control " - ; - -static char ExtensionsString[1024]; - -static void CalcServerVersionAndExtensions( void ) -{ - int s; - xGLXQueryVersionReq *req; - xGLXQueryVersionReply reply; - char **be_extensions; - char *ext; - char *denied_extensions; - - /* - * set the server glx version to be the minimum version - * supported by all back-end servers - */ - __glXVersionMajor = 0; - __glXVersionMinor = 0; - for (s=0; s<__glXNumActiveScreens; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = dmxScreen->beDisplay; - - /* Send the glXQueryVersion request */ - LockDisplay(dpy); - GetReq(GLXQueryVersion,req); - req->reqType = dmxScreen->glxMajorOpcode; - req->glxCode = X_GLXQueryVersion; - req->majorVersion = GLX_SERVER_MAJOR_VERSION; - req->minorVersion = GLX_SERVER_MINOR_VERSION; - _XReply(dpy, (xReply*) &reply, 0, False); - UnlockDisplay(dpy); - SyncHandle(); - - if (s == 0) { - __glXVersionMajor = reply.majorVersion; - __glXVersionMinor = reply.minorVersion; - } - else { - if (reply.majorVersion < __glXVersionMajor) { - __glXVersionMajor = reply.majorVersion; - __glXVersionMinor = reply.minorVersion; - } - else if ( (reply.majorVersion == __glXVersionMajor) && - (reply.minorVersion < __glXVersionMinor) ) { - __glXVersionMinor = reply.minorVersion; - } - } - - } - - if (GLX_SERVER_MAJOR_VERSION < __glXVersionMajor) { - __glXVersionMajor = GLX_SERVER_MAJOR_VERSION; - __glXVersionMinor = GLX_SERVER_MINOR_VERSION; - } - else if ( (GLX_SERVER_MAJOR_VERSION == __glXVersionMajor) && - (GLX_SERVER_MINOR_VERSION < __glXVersionMinor) ) { - __glXVersionMinor = GLX_SERVER_MINOR_VERSION; - } - - sprintf(GLXServerVersion, "%d.%d DMX %d back-end server(s)", - __glXVersionMajor, __glXVersionMinor, __glXNumActiveScreens ); - /* - * set the ExtensionsString to the minimum extensions string - */ - ExtensionsString[0] = '\0'; - - /* - * read extensions strings of all back-end servers - */ - be_extensions = (char **)Xalloc( __glXNumActiveScreens * sizeof(char *) ); - if (!be_extensions) - return; - - for (s=0; s<__glXNumActiveScreens; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = dmxScreen->beDisplay; - xGLXQueryServerStringReq *req; - xGLXQueryServerStringReply reply; - int length, numbytes, slop; - - /* Send the glXQueryServerString request */ - LockDisplay(dpy); - GetReq(GLXQueryServerString,req); - req->reqType = dmxScreen->glxMajorOpcode; - req->glxCode = X_GLXQueryServerString; - req->screen = DefaultScreen(dpy); - req->name = GLX_EXTENSIONS; - _XReply(dpy, (xReply*) &reply, 0, False); - - length = (int)reply.length; - numbytes = (int)reply.n; - slop = numbytes * __GLX_SIZE_INT8 & 3; - be_extensions[s] = (char *)Xalloc(numbytes); - if (!be_extensions[s]) { - /* Throw data on the floor */ - _XEatData(dpy, length); - } else { - _XRead(dpy, (char *)be_extensions[s], numbytes); - if (slop) _XEatData(dpy,4-slop); - } - UnlockDisplay(dpy); - SyncHandle(); - } - - /* - * extensions string will include only extensions that our - * server supports as well as all back-end servers supports. - * extensions that are in the DMX_DENY_EXTENSIONS string will - * not be supported. - */ - denied_extensions = getenv("DMX_DENY_GLX_EXTENSIONS"); - ext = strtok(GLXServerExtensions, " "); - while( ext ) { - int supported = 1; - - if (denied_extensions && strstr(denied_extensions, ext)) { - supported = 0; - } - else { - for (s=0; s<__glXNumActiveScreens && supported; s++) { - if ( !strstr(be_extensions[s], ext) ) { - supported = 0; - } - } - } - - if (supported) { - strcat(ExtensionsString, ext); - strcat(ExtensionsString, " "); - } - - ext = strtok(NULL, " "); - } - - /* - * release temporary storage - */ - for (s=0; s<__glXNumActiveScreens; s++) { - if (be_extensions[s]) Xfree(be_extensions[s]); - } - Xfree( be_extensions ); - - if (dmxGLXSwapGroupSupport) { - if (!denied_extensions || - !strstr(denied_extensions, "GLX_SGIX_swap_group")) { - strcat(ExtensionsString, "GLX_SGIX_swap_group"); - if (!denied_extensions || - !strstr(denied_extensions, "GLX_SGIX_swap_barrier")) { - strcat(ExtensionsString, " GLX_SGIX_swap_barrier"); - } - } - } - -} - -void __glXScreenInit(GLint numscreens) -{ - int s; - int c; - DMXScreenInfo *dmxScreen0 = &dmxScreens[0]; - __glXNumActiveScreens = numscreens; - - - CalcServerVersionAndExtensions(); - - - __glXFBConfigs = NULL; - __glXNumFBConfigs = 0; - - if ( (__glXVersionMajor == 1 && __glXVersionMinor >= 3) || - (__glXVersionMajor > 1) || - ( strstr(ExtensionsString, "GLX_SGIX_fbconfig") ) ) { - - /* - // Initialize FBConfig info. - // find the set of FBConfigs that are present on all back-end - // servers - only those configs will be supported - */ - __glXFBConfigs = (__GLXFBConfig **)Xalloc( dmxScreen0->numFBConfigs * - (numscreens+1) * sizeof(__GLXFBConfig *) ); - __glXNumFBConfigs = 0; - - for (c=0; c<dmxScreen0->numFBConfigs; c++) { - __GLXFBConfig *cfg = NULL; - - if (numscreens > 1) { - for (s=1; s<numscreens; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - __GLXscreenInfo *glxScreen = &__glXActiveScreens[s]; - - cfg = FindMatchingFBConfig( &dmxScreen0->fbconfigs[c], - dmxScreen->fbconfigs, - dmxScreen->numFBConfigs ); - __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + s + 1 ] = cfg; - if (!cfg) { - dmxLog(dmxInfo,"screen0 FBConfig 0x%x is missing on screen#%d\n", dmxScreen0->fbconfigs[c].id, s); - break; - } - else { - dmxLog(dmxInfo,"screen0 FBConfig 0x%x matched to 0x%x on screen#%d\n", dmxScreen0->fbconfigs[c].id, cfg->id, s); - } - } - } - else { - cfg = &dmxScreen0->fbconfigs[c]; - } - - if (cfg) { - - /* filter out overlay visuals */ - if (cfg->level == 0) { - __GLXFBConfig *proxy_cfg; - - __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + 1 ] = - &dmxScreen0->fbconfigs[c]; - - proxy_cfg = Xalloc( sizeof(__GLXFBConfig) ); - memcpy( proxy_cfg, cfg, sizeof(__GLXFBConfig) ); - proxy_cfg->id = FakeClientID(0); - /* visual will be associated later in __glXGetFBConfigs */ - proxy_cfg->associatedVisualId = (unsigned int)-1; - - __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + 0 ] = proxy_cfg; - - __glXNumFBConfigs++; - } - - } - - } - - } - -} - -void __glXScreenReset(void) -{ - __glXNumActiveScreens = 0; -} - -char *__glXGetServerString( unsigned int name ) -{ - char *ret = NULL; - - switch( name) { - - case GLX_VENDOR: - ret = GLXServerVendorName; - break; - - case GLX_VERSION: - ret = GLXServerVersion; - break; - - case GLX_EXTENSIONS: - ret = ExtensionsString; - break; - - default: - break; - } - - return( ret ); - -} - - -__GLXFBConfig *glxLookupFBConfig( GLXFBConfigID id ) -{ - int i,j; - - for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { - if ( __glXFBConfigs[j]->id == id) - return( __glXFBConfigs[j] ); - } - - return(NULL); -} - -__GLXFBConfig *glxLookupFBConfigByVID( VisualID vid ) -{ - int i,j; - - for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { - if ( __glXFBConfigs[j]->associatedVisualId == vid) - return( __glXFBConfigs[j] ); - } - - return(NULL); -} - -__GLXFBConfig *glxLookupBackEndFBConfig( GLXFBConfigID id, int screen ) -{ - int i; - int j; - - for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { - if ( __glXFBConfigs[j]->id == id) - return( __glXFBConfigs[j+screen+1] ); - } - - return(NULL); - -} - -int glxIsExtensionSupported( char *ext ) -{ - return( strstr(ExtensionsString, ext) != NULL ); -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxlog.h" + +#undef Xmalloc +#undef Xcalloc +#undef Xrealloc +#undef Xfree + +#include "glxserver.h" + +#include <windowstr.h> + +#include "glxfbconfig.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +__GLXscreenInfo *__glXActiveScreens; +GLint __glXNumActiveScreens; + +__GLXFBConfig **__glXFBConfigs; +int __glXNumFBConfigs; + +static char GLXServerVendorName[] = "SGI DMX/glxProxy"; +static char GLXServerVersion[64]; +static char GLXServerExtensions[] = + "GLX_EXT_visual_info " + "GLX_EXT_visual_rating " + "GLX_EXT_import_context " + "GLX_SGIX_fbconfig " + "GLX_SGI_make_current_read " + "GLX_SGI_swap_control " + ; + +static char ExtensionsString[1024]; + +static void CalcServerVersionAndExtensions( void ) +{ + int s; + xGLXQueryVersionReq *req; + xGLXQueryVersionReply reply; + char **be_extensions; + char *ext; + char *denied_extensions; + + /* + * set the server glx version to be the minimum version + * supported by all back-end servers + */ + __glXVersionMajor = 0; + __glXVersionMinor = 0; + for (s=0; s<__glXNumActiveScreens; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = dmxScreen->beDisplay; + + /* Send the glXQueryVersion request */ + LockDisplay(dpy); + GetReq(GLXQueryVersion,req); + req->reqType = dmxScreen->glxMajorOpcode; + req->glxCode = X_GLXQueryVersion; + req->majorVersion = GLX_SERVER_MAJOR_VERSION; + req->minorVersion = GLX_SERVER_MINOR_VERSION; + _XReply(dpy, (xReply*) &reply, 0, False); + UnlockDisplay(dpy); + SyncHandle(); + + if (s == 0) { + __glXVersionMajor = reply.majorVersion; + __glXVersionMinor = reply.minorVersion; + } + else { + if (reply.majorVersion < __glXVersionMajor) { + __glXVersionMajor = reply.majorVersion; + __glXVersionMinor = reply.minorVersion; + } + else if ( (reply.majorVersion == __glXVersionMajor) && + (reply.minorVersion < __glXVersionMinor) ) { + __glXVersionMinor = reply.minorVersion; + } + } + + } + + if (GLX_SERVER_MAJOR_VERSION < __glXVersionMajor) { + __glXVersionMajor = GLX_SERVER_MAJOR_VERSION; + __glXVersionMinor = GLX_SERVER_MINOR_VERSION; + } + else if ( (GLX_SERVER_MAJOR_VERSION == __glXVersionMajor) && + (GLX_SERVER_MINOR_VERSION < __glXVersionMinor) ) { + __glXVersionMinor = GLX_SERVER_MINOR_VERSION; + } + + sprintf(GLXServerVersion, "%d.%d DMX %d back-end server(s)", + __glXVersionMajor, __glXVersionMinor, __glXNumActiveScreens ); + /* + * set the ExtensionsString to the minimum extensions string + */ + ExtensionsString[0] = '\0'; + + /* + * read extensions strings of all back-end servers + */ + be_extensions = (char **)malloc( __glXNumActiveScreens * sizeof(char *) ); + if (!be_extensions) + return; + + for (s=0; s<__glXNumActiveScreens; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = dmxScreen->beDisplay; + xGLXQueryServerStringReq *req; + xGLXQueryServerStringReply reply; + int length, numbytes, slop; + + /* Send the glXQueryServerString request */ + LockDisplay(dpy); + GetReq(GLXQueryServerString,req); + req->reqType = dmxScreen->glxMajorOpcode; + req->glxCode = X_GLXQueryServerString; + req->screen = DefaultScreen(dpy); + req->name = GLX_EXTENSIONS; + _XReply(dpy, (xReply*) &reply, 0, False); + + length = (int)reply.length; + numbytes = (int)reply.n; + slop = numbytes * __GLX_SIZE_INT8 & 3; + be_extensions[s] = (char *)malloc(numbytes); + if (!be_extensions[s]) { + /* Throw data on the floor */ + _XEatData(dpy, length); + } else { + _XRead(dpy, (char *)be_extensions[s], numbytes); + if (slop) _XEatData(dpy,4-slop); + } + UnlockDisplay(dpy); + SyncHandle(); + } + + /* + * extensions string will include only extensions that our + * server supports as well as all back-end servers supports. + * extensions that are in the DMX_DENY_EXTENSIONS string will + * not be supported. + */ + denied_extensions = getenv("DMX_DENY_GLX_EXTENSIONS"); + ext = strtok(GLXServerExtensions, " "); + while( ext ) { + int supported = 1; + + if (denied_extensions && strstr(denied_extensions, ext)) { + supported = 0; + } + else { + for (s=0; s<__glXNumActiveScreens && supported; s++) { + if ( !strstr(be_extensions[s], ext) ) { + supported = 0; + } + } + } + + if (supported) { + strcat(ExtensionsString, ext); + strcat(ExtensionsString, " "); + } + + ext = strtok(NULL, " "); + } + + /* + * release temporary storage + */ + for (s=0; s<__glXNumActiveScreens; s++) { + if (be_extensions[s]) Xfree(be_extensions[s]); + } + Xfree( be_extensions ); + + if (dmxGLXSwapGroupSupport) { + if (!denied_extensions || + !strstr(denied_extensions, "GLX_SGIX_swap_group")) { + strcat(ExtensionsString, "GLX_SGIX_swap_group"); + if (!denied_extensions || + !strstr(denied_extensions, "GLX_SGIX_swap_barrier")) { + strcat(ExtensionsString, " GLX_SGIX_swap_barrier"); + } + } + } + +} + +void __glXScreenInit(GLint numscreens) +{ + int s; + int c; + DMXScreenInfo *dmxScreen0 = &dmxScreens[0]; + __glXNumActiveScreens = numscreens; + + + CalcServerVersionAndExtensions(); + + + __glXFBConfigs = NULL; + __glXNumFBConfigs = 0; + + if ( (__glXVersionMajor == 1 && __glXVersionMinor >= 3) || + (__glXVersionMajor > 1) || + ( strstr(ExtensionsString, "GLX_SGIX_fbconfig") ) ) { + + /* + // Initialize FBConfig info. + // find the set of FBConfigs that are present on all back-end + // servers - only those configs will be supported + */ + __glXFBConfigs = (__GLXFBConfig **)malloc( dmxScreen0->numFBConfigs * + (numscreens+1) * sizeof(__GLXFBConfig *) ); + __glXNumFBConfigs = 0; + + for (c=0; c<dmxScreen0->numFBConfigs; c++) { + __GLXFBConfig *cfg = NULL; + + if (numscreens > 1) { + for (s=1; s<numscreens; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + __GLXscreenInfo *glxScreen = &__glXActiveScreens[s]; + + cfg = FindMatchingFBConfig( &dmxScreen0->fbconfigs[c], + dmxScreen->fbconfigs, + dmxScreen->numFBConfigs ); + __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + s + 1 ] = cfg; + if (!cfg) { + dmxLog(dmxInfo,"screen0 FBConfig 0x%x is missing on screen#%d\n", dmxScreen0->fbconfigs[c].id, s); + break; + } + else { + dmxLog(dmxInfo,"screen0 FBConfig 0x%x matched to 0x%x on screen#%d\n", dmxScreen0->fbconfigs[c].id, cfg->id, s); + } + } + } + else { + cfg = &dmxScreen0->fbconfigs[c]; + } + + if (cfg) { + + /* filter out overlay visuals */ + if (cfg->level == 0) { + __GLXFBConfig *proxy_cfg; + + __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + 1 ] = + &dmxScreen0->fbconfigs[c]; + + proxy_cfg = malloc( sizeof(__GLXFBConfig) ); + memcpy( proxy_cfg, cfg, sizeof(__GLXFBConfig) ); + proxy_cfg->id = FakeClientID(0); + /* visual will be associated later in __glXGetFBConfigs */ + proxy_cfg->associatedVisualId = (unsigned int)-1; + + __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + 0 ] = proxy_cfg; + + __glXNumFBConfigs++; + } + + } + + } + + } + +} + +void __glXScreenReset(void) +{ + __glXNumActiveScreens = 0; +} + +char *__glXGetServerString( unsigned int name ) +{ + char *ret = NULL; + + switch( name) { + + case GLX_VENDOR: + ret = GLXServerVendorName; + break; + + case GLX_VERSION: + ret = GLXServerVersion; + break; + + case GLX_EXTENSIONS: + ret = ExtensionsString; + break; + + default: + break; + } + + return( ret ); + +} + + +__GLXFBConfig *glxLookupFBConfig( GLXFBConfigID id ) +{ + int i,j; + + for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { + if ( __glXFBConfigs[j]->id == id) + return( __glXFBConfigs[j] ); + } + + return(NULL); +} + +__GLXFBConfig *glxLookupFBConfigByVID( VisualID vid ) +{ + int i,j; + + for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { + if ( __glXFBConfigs[j]->associatedVisualId == vid) + return( __glXFBConfigs[j] ); + } + + return(NULL); +} + +__GLXFBConfig *glxLookupBackEndFBConfig( GLXFBConfigID id, int screen ) +{ + int i; + int j; + + for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { + if ( __glXFBConfigs[j]->id == id) + return( __glXFBConfigs[j+screen+1] ); + } + + return(NULL); + +} + +int glxIsExtensionSupported( char *ext ) +{ + return( strstr(ExtensionsString, ext) != NULL ); +} diff --git a/xorg-server/hw/dmx/glxProxy/glxsingle.c b/xorg-server/hw/dmx/glxProxy/glxsingle.c index dcc604052..19f12ad58 100644 --- a/xorg-server/hw/dmx/glxProxy/glxsingle.c +++ b/xorg-server/hw/dmx/glxProxy/glxsingle.c @@ -1,1012 +1,1012 @@ -/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED */ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxfont.h" -#include "dmxcb.h" - -#undef Xmalloc -#undef Xcalloc -#undef Xrealloc -#undef Xfree - -#include "glxserver.h" -#include "glxext.h" -#include "g_disptab.h" -/* #include "g_disptab_EXT.h" */ -#include "unpack.h" -#include "glxutil.h" - -#include "GL/glxproto.h" - -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -/* - * GetReqSingle - this is the equivalent of GetReq macro - * from Xlibint.h but it does not set the reqType field (the opcode). - * this is because the GL single opcodes has different naming convension - * the other X opcodes (ie. X_GLsop_GetFloatv). - */ -#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) -#define GetReqSingle(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x##name##Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ - req->length = (SIZEOF(x##name##Req))>>2;\ - dpy->bufptr += SIZEOF(x##name##Req);\ - dpy->request++ - -#else /* non-ANSI C uses empty comment instead of "##" for token concatenation */ -#define GetReqSingle(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x/**/name/**/Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ - req->length = (SIZEOF(x/**/name/**/Req))>>2;\ - dpy->bufptr += SIZEOF(x/**/name/**/Req);\ - dpy->request++ -#endif - -#define X_GLXSingle 0 /* needed by GetReqExtra */ - -extern Display *GetBackEndDisplay( __GLXclientState *cl, int s ); -extern int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s); - -static int swap_vec_element_size = 0; - -static void SendSwappedReply( ClientPtr client, - xGLXSingleReply *reply, - char *buf, - int buf_size ) -{ - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_SHORT(&reply->sequenceNumber); - __GLX_SWAP_INT(&reply->length); - __GLX_SWAP_INT(&reply->retval); - __GLX_SWAP_INT(&reply->size); - - if ( (buf_size == 0) && (swap_vec_element_size > 0) ) { - /* - * the reply has single component - need to swap pad3 - */ - if (swap_vec_element_size == 2) { - __GLX_SWAP_SHORT(&reply->pad3); - } - else if (swap_vec_element_size == 4) { - __GLX_SWAP_INT(&reply->pad3); - __GLX_SWAP_INT(&reply->pad4); /* some requests use also pad4 - * i.e GetConvolutionFilter - */ - } - else if (swap_vec_element_size == 8) { - __GLX_SWAP_DOUBLE(&reply->pad3); - } - } - else if ( (buf_size > 0) && (swap_vec_element_size > 0) ) { - /* - * the reply has vector of elements which needs to be swapped - */ - int vsize = buf_size / swap_vec_element_size; - char *p = buf; - int i; - - for (i=0; i<vsize; i++) { - if (swap_vec_element_size == 2) { - __GLX_SWAP_SHORT(p); - } - else if (swap_vec_element_size == 4) { - __GLX_SWAP_INT(p); - } - else if (swap_vec_element_size == 8) { - __GLX_SWAP_DOUBLE(p); - } - - p += swap_vec_element_size; - } - - /* - * swap pad words as well - for case that some single reply uses - * them as well - */ - __GLX_SWAP_INT(&reply->pad3); - __GLX_SWAP_INT(&reply->pad4); - __GLX_SWAP_INT(&reply->pad5); - __GLX_SWAP_INT(&reply->pad6); - - } - - WriteToClient(client, sizeof(xGLXSingleReply),(char *)reply); - if (buf_size > 0) - WriteToClient(client, buf_size, (char *)buf); - -} - -int __glXForwardSingleReq( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - xGLXSingleReq *be_req; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int buf_size; - int s; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXSingleReq; - buf_size = (req->length << 2) - sz_xGLXSingleReq; - - /* - * just forward the request to back-end server(s) - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReqSingle(GLXSingle,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - UnlockDisplay(dpy); - SyncHandle(); - - if (req->glxCode == X_GLsop_Flush) { - XFlush(dpy); - } - - } - - return Success; -} - -int __glXForwardPipe0WithReply( __GLXclientState *cl, GLbyte *pc ) -{ - ClientPtr client = cl->client; - xGLXSingleReq *req = (xGLXSingleReq *)pc; - xGLXSingleReq *be_req; - xGLXSingleReply reply; - xGLXSingleReply be_reply; - __GLXcontext *glxc; - int buf_size; - char *be_buf; - int be_buf_size; - DMXScreenInfo *dmxScreen; - Display *dpy; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return __glXBadContext; - } - - pc += sz_xGLXSingleReq; - buf_size = (req->length << 2) - sz_xGLXSingleReq; - - dmxScreen = &dmxScreens[glxc->pScreen->myNum]; - dpy = GetBackEndDisplay(cl, glxc->pScreen->myNum); - - /* - * send the request to the first back-end server - */ - LockDisplay(dpy); - GetReqSingle(GLXSingle,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,glxc->pScreen->myNum); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - - /* - * get the reply from the back-end server - */ - _XReply(dpy, (xReply*) &be_reply, 0, False); - be_buf_size = be_reply.length << 2; - if (be_buf_size > 0) { - be_buf = (char *)Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - /* - * send the reply to the client - */ - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = be_reply.length; - reply.retval = be_reply.retval; - reply.size = be_reply.size; - reply.pad3 = be_reply.pad3; - reply.pad4 = be_reply.pad4; - - if (client->swapped) { - SendSwappedReply( client, &reply, be_buf, be_buf_size ); - } - else { - WriteToClient(client, sizeof(xGLXSingleReply),(char *)&reply); - if (be_buf_size > 0) - WriteToClient(client, be_buf_size, (char *)be_buf); - } - - if (be_buf_size > 0) Xfree(be_buf); - - return Success; -} - -int __glXForwardAllWithReply( __GLXclientState *cl, GLbyte *pc ) -{ - ClientPtr client = cl->client; - xGLXSingleReq *req = (xGLXSingleReq *)pc; - xGLXSingleReq *be_req; - xGLXSingleReply reply; - xGLXSingleReply be_reply; - __GLXcontext *glxc; - int buf_size; - char *be_buf; - int be_buf_size; - int from_screen = 0; - int to_screen = 0; - int s; - - DMXScreenInfo *dmxScreen; - Display *dpy; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXSingleReq; - buf_size = (req->length << 2) - sz_xGLXSingleReq; - - /* - * send the request to the first back-end server(s) - */ - for (s=to_screen; s>=from_screen; s--) { - dmxScreen = &dmxScreens[s]; - dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReqSingle(GLXSingle,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - - /* - * get the reply from the back-end server - */ - _XReply(dpy, (xReply*) &be_reply, 0, False); - be_buf_size = be_reply.length << 2; - if (be_buf_size > 0) { - be_buf = (char *)Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - if (s > from_screen && be_buf_size > 0) { - Xfree(be_buf); - } - } - - /* - * send the reply to the client - */ - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = be_reply.length; - reply.retval = be_reply.retval; - reply.size = be_reply.size; - reply.pad3 = be_reply.pad3; - reply.pad4 = be_reply.pad4; - - if (client->swapped) { - SendSwappedReply( client, &reply, be_buf, be_buf_size ); - } - else { - WriteToClient(client, sizeof(xGLXSingleReply),(char *)&reply); - if (be_buf_size > 0) - WriteToClient(client, be_buf_size, (char *)be_buf); - } - - if (be_buf_size > 0) Xfree(be_buf); - - return Success; -} - -int __glXForwardSingleReqSwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXForwardSingleReq( cl, pc ) ); -} - -int __glXForwardPipe0WithReplySwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXForwardPipe0WithReply( cl, pc ) ); -} - -int __glXForwardPipe0WithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 2; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardPipe0WithReply( cl, pc ) ); -} - -int __glXForwardPipe0WithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 4; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardPipe0WithReply( cl, pc ) ); -} - -int __glXForwardPipe0WithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 8; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardPipe0WithReply( cl, pc ) ); -} - -int __glXForwardAllWithReplySwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardAllWithReply( cl, pc ) ); -} - -int __glXForwardAllWithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 2; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardAllWithReply( cl, pc ) ); -} - -int __glXForwardAllWithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 4; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardAllWithReply( cl, pc ) ); -} - -int __glXForwardAllWithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 8; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardAllWithReply( cl, pc ) ); -} - -static GLint __glReadPixels_size(GLenum format, GLenum type, GLint w, GLint h, - int *elementbits_return, int *rowbytes_return ) -{ - GLint elements, esize; - GLint rowsize, padding; - - if (w < 0 || h < 0) { - return -1; - } - switch (format) { - case GL_COLOR_INDEX: - case GL_STENCIL_INDEX: - case GL_DEPTH_COMPONENT: - elements = 1; - break; - case GL_RED: - case GL_GREEN: - case GL_BLUE: - case GL_ALPHA: - case GL_LUMINANCE: - elements = 1; - break; - case GL_LUMINANCE_ALPHA: - elements = 2; - break; - case GL_RGB: - case GL_BGR: - elements = 3; - break; - case GL_RGBA: - case GL_BGRA: - case GL_ABGR_EXT: - elements = 4; - break; - default: - return -1; - } - /* - ** According to the GLX protocol, each row must be padded to a multiple of - ** 4 bytes. 4 bytes also happens to be the default alignment in the pixel - ** store modes of the GL. - */ - switch (type) { - case GL_BITMAP: - if (format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX) { - rowsize = ((w * elements)+7)/8; - padding = rowsize % 4; - if (padding) { - rowsize += 4 - padding; - } - if (elementbits_return) *elementbits_return = elements; - if (rowbytes_return) *rowbytes_return = rowsize; - return (rowsize * h); - } else { - return -1; - } - case GL_BYTE: - case GL_UNSIGNED_BYTE: - esize = 1; - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - esize = 1; - elements = 1; - break; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - esize = 2; - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - esize = 2; - elements = 1; - break; - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - esize = 4; - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - esize = 4; - elements = 1; - break; - default: - return -1; - } - rowsize = w * elements * esize; - padding = rowsize % 4; - if (padding) { - rowsize += 4 - padding; - } - - if (elementbits_return) *elementbits_return = esize*elements*8; - if (rowbytes_return) *rowbytes_return = rowsize; - - return (rowsize * h); -} - -static int intersectRect( int x1, int x2, int y1, int y2, - int X1, int X2, int Y1, int Y2, - int *ix1, int *ix2, int *iy1, int *iy2 ) -{ - int right = (x2 < X2 ? x2 : X2); - int bottom = (y2 < Y2 ? y2 : Y2); - int left = (x1 > X1 ? x1 : X1); - int top = (y1 > Y1 ? y1 : Y1); - int width = right - left + 1; - int height = bottom - top + 1; - - if ( (width <= 0) || (height <= 0) ) { - *ix1 = *ix2 = *iy1 = *iy2 = 0; - return(0); - } - else { - *ix1 = left; - *ix2 = right; - *iy1 = top; - *iy2 = bottom; - return( width * height ); - } - -} - -int __glXDisp_ReadPixels(__GLXclientState *cl, GLbyte *pc) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - xGLXSingleReq *be_req; - xGLXReadPixelsReply reply; - xGLXReadPixelsReply be_reply; - GLbyte *be_pc; - GLint x,y; - GLsizei width, height; - GLenum format, type; - GLboolean swapBytes, lsbFirst; - ClientPtr client = cl->client; - DrawablePtr pDraw; - int error; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - char *buf; - int buf_size; - int s; - int win_x1, win_x2; - int win_y1, win_y2; - int ebits, rowsize; - __GLX_DECLARE_SWAP_VARIABLES; - - if (client->swapped) { - __GLX_SWAP_INT(&req->contextTag); - } - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXSingleReq; - x = *(GLint *)(pc + 0); - y = *(GLint *)(pc + 4); - width = *(GLsizei *)(pc + 8); - height = *(GLsizei *)(pc + 12); - format = *(GLenum *)(pc + 16); - type = *(GLenum *)(pc + 20); - swapBytes = *(GLboolean *)(pc + 24); - lsbFirst = *(GLboolean *)(pc + 25); - - if (client->swapped) { - __GLX_SWAP_INT(&x); - __GLX_SWAP_INT(&y); - __GLX_SWAP_INT(&width); - __GLX_SWAP_INT(&height); - __GLX_SWAP_INT(&format); - __GLX_SWAP_INT(&type); - swapBytes = !swapBytes; - } - - buf_size = __glReadPixels_size(format,type,width,height, &ebits, &rowsize); - if (buf_size > 0) { - buf = (char *) Xalloc( buf_size ); - if ( !buf ) { - return( BadAlloc ); - } - } - else { - buf_size = 0; - } - - if (buf_size > 0) { - /* - * Get the current drawable this context is bound to - */ - pDraw = __glXLookupDrawableByTag( cl, req->contextTag ); - win_x1 = pDraw->x + x; - win_x2 = win_x1 + width - 1; - win_y1 = (dmxGlobalHeight - pDraw->y - pDraw->height) + y; - win_y2 = win_y1 + height - 1; - if (pDraw->type != DRAWABLE_WINDOW) { - from_screen = to_screen = 0; - } - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - int scr_x1 = dmxScreen->rootXOrigin; - int scr_x2 = dmxScreen->rootXOrigin + dmxScreen->scrnWidth - 1; - int scr_y1 = dmxScreen->rootYOrigin; - int scr_y2 = dmxScreen->rootYOrigin + dmxScreen->scrnHeight - 1; - int wx1, wx2, wy1, wy2; - int sx, sy, sw, sh; - int npixels; - - /* - * find the window portion that is on the current screen - */ - if (pDraw->type == DRAWABLE_WINDOW) { - npixels = intersectRect( scr_x1, scr_x2, scr_y1, scr_y2, - win_x1, win_x2, win_y1, win_y2, - &wx1, &wx2, &wy1, &wy2 ); - } - else { - wx1 = win_x1; - wx2 = win_x2; - wy1 = win_y1; - wy2 = win_y2; - npixels = (wx2-wx1+1) * (wy2-wy1+1); - } - - if (npixels > 0) { - - /* send the request to the back-end server */ - LockDisplay(dpy); - GetReqExtra(GLXSingle,__GLX_PAD(26),be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLsop_ReadPixels; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - be_pc = ((GLbyte *)(be_req) + sz_xGLXSingleReq); - - sx = wx1 - pDraw->x; - sy = wy1 - (dmxGlobalHeight - pDraw->y - pDraw->height); - sw = (wx2-wx1+1); - sh = (wy2-wy1+1); - - *(GLint *)(be_pc + 0) = sx; /* x */ - *(GLint *)(be_pc + 4) = sy; /* y */ - *(GLsizei *)(be_pc + 8) = sw; /* width */ - *(GLsizei *)(be_pc + 12) = sh; /* height */ - *(GLenum *)(be_pc + 16) = format; - *(GLenum *)(be_pc + 20) = type; - *(GLboolean *)(be_pc + 24) = swapBytes; - *(GLboolean *)(be_pc + 25) = lsbFirst; - - _XReply(dpy, (xReply*) &be_reply, 0, False); - - if (be_reply.length > 0) { - char *be_buf; - int be_buf_size = be_reply.length << 2; - - be_buf = (char *) Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - - /* copy pixels data to the right location of the */ - /* reply buffer */ - if ( type != GL_BITMAP ) { - int pbytes = ebits / 8; - char *dst = buf + (sy-y)*rowsize + (sx-x)*pbytes; - char *src = be_buf; - int pad = (pbytes * sw) % 4; - int r; - - for (r=0; r<sh; r++) { - memcpy( dst, src, pbytes*sw ); - dst += rowsize; - src += (pbytes*sw + (pad ? 4-pad : 0) ); - } - } - else { - /* this is a GL_BITMAP pixel type, should copy bits */ - int r; - int src_rowsize = bits_to_bytes(sw * ebits); - int src_pad = src_rowsize % 4; - if ( src_pad ) { - src_rowsize += (4 - src_pad); - } - - for (r=0; r<sh; r++) { - unsigned char dst_mask = 0x80 >> (sx % 8); - unsigned char src_mask = 0x80; - char *dst = buf + (sy-y+r)*rowsize + (sx-x)/8; - char *src = be_buf + r*src_rowsize; - int b; - - for (b=0; b<sw*ebits; b++) { - if ( *src & src_mask ) { - *dst |= dst_mask; - } - else { - *dst &= ~dst_mask; - } - - if (dst_mask > 1) dst_mask >>= 1; - else { - dst_mask = 0x80; - dst++; - } - - if (src_mask > 1) src_mask >>= 1; - else { - src_mask = 0x80; - src++; - } - } - } - - } - - Xfree( be_buf ); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - Xfree( buf ); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - } /* of npixels > 0 */ - - } /* of for loop */ - - } /* of if buf_size > 0 */ - - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = buf_size >> 2; - - if (client->swapped) { - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - } - - WriteToClient(client, sizeof(xGLXReadPixelsReply),(char *)&reply); - if (buf_size > 0) { - WriteToClient(client, buf_size, (char *)buf); - Xfree( buf ); - } - - return Success; -} - -int __glXDispSwap_GetTexImage(__GLXclientState *cl, GLbyte *pc) -{ - __GLX_DECLARE_SWAP_VARIABLES; - GLbyte *lpc = pc; - - lpc += sz_xGLXSingleReq; - __GLX_SWAP_INT(lpc+0); - __GLX_SWAP_INT(lpc+4); - __GLX_SWAP_INT(lpc+8); - __GLX_SWAP_INT(lpc+12); - - /* reverse swapBytes */ - *(GLboolean *)(lpc + 16) = ! *(GLboolean *)(lpc + 16); - - return( __glXForwardPipe0WithReplySwap( cl, pc ) ); -} - -int __glXDispSwap_GetColorTable(__GLXclientState *cl, GLbyte *pc) -{ - __GLX_DECLARE_SWAP_VARIABLES; - GLbyte *lpc = pc; - - lpc += sz_xGLXSingleReq; - __GLX_SWAP_INT(lpc+0); - __GLX_SWAP_INT(lpc+4); - __GLX_SWAP_INT(lpc+8); - - /* reverse swapBytes */ - *(GLboolean *)(lpc + 12) = ! *(GLboolean *)(lpc + 12); - - return( __glXForwardPipe0WithReplySwap( cl, pc ) ); -} - - +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED */ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxfont.h" +#include "dmxcb.h" + +#undef Xmalloc +#undef Xcalloc +#undef Xrealloc +#undef Xfree + +#include "glxserver.h" +#include "glxext.h" +#include "g_disptab.h" +/* #include "g_disptab_EXT.h" */ +#include "unpack.h" +#include "glxutil.h" + +#include "GL/glxproto.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +/* + * GetReqSingle - this is the equivalent of GetReq macro + * from Xlibint.h but it does not set the reqType field (the opcode). + * this is because the GL single opcodes has different naming convension + * the other X opcodes (ie. X_GLsop_GetFloatv). + */ +#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) +#define GetReqSingle(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(x##name##Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ + req->length = (SIZEOF(x##name##Req))>>2;\ + dpy->bufptr += SIZEOF(x##name##Req);\ + dpy->request++ + +#else /* non-ANSI C uses empty comment instead of "##" for token concatenation */ +#define GetReqSingle(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(x/**/name/**/Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ + req->length = (SIZEOF(x/**/name/**/Req))>>2;\ + dpy->bufptr += SIZEOF(x/**/name/**/Req);\ + dpy->request++ +#endif + +#define X_GLXSingle 0 /* needed by GetReqExtra */ + +extern Display *GetBackEndDisplay( __GLXclientState *cl, int s ); +extern int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s); + +static int swap_vec_element_size = 0; + +static void SendSwappedReply( ClientPtr client, + xGLXSingleReply *reply, + char *buf, + int buf_size ) +{ + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_SHORT(&reply->sequenceNumber); + __GLX_SWAP_INT(&reply->length); + __GLX_SWAP_INT(&reply->retval); + __GLX_SWAP_INT(&reply->size); + + if ( (buf_size == 0) && (swap_vec_element_size > 0) ) { + /* + * the reply has single component - need to swap pad3 + */ + if (swap_vec_element_size == 2) { + __GLX_SWAP_SHORT(&reply->pad3); + } + else if (swap_vec_element_size == 4) { + __GLX_SWAP_INT(&reply->pad3); + __GLX_SWAP_INT(&reply->pad4); /* some requests use also pad4 + * i.e GetConvolutionFilter + */ + } + else if (swap_vec_element_size == 8) { + __GLX_SWAP_DOUBLE(&reply->pad3); + } + } + else if ( (buf_size > 0) && (swap_vec_element_size > 0) ) { + /* + * the reply has vector of elements which needs to be swapped + */ + int vsize = buf_size / swap_vec_element_size; + char *p = buf; + int i; + + for (i=0; i<vsize; i++) { + if (swap_vec_element_size == 2) { + __GLX_SWAP_SHORT(p); + } + else if (swap_vec_element_size == 4) { + __GLX_SWAP_INT(p); + } + else if (swap_vec_element_size == 8) { + __GLX_SWAP_DOUBLE(p); + } + + p += swap_vec_element_size; + } + + /* + * swap pad words as well - for case that some single reply uses + * them as well + */ + __GLX_SWAP_INT(&reply->pad3); + __GLX_SWAP_INT(&reply->pad4); + __GLX_SWAP_INT(&reply->pad5); + __GLX_SWAP_INT(&reply->pad6); + + } + + WriteToClient(client, sizeof(xGLXSingleReply),(char *)reply); + if (buf_size > 0) + WriteToClient(client, buf_size, (char *)buf); + +} + +int __glXForwardSingleReq( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + xGLXSingleReq *be_req; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int buf_size; + int s; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXSingleReq; + buf_size = (req->length << 2) - sz_xGLXSingleReq; + + /* + * just forward the request to back-end server(s) + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReqSingle(GLXSingle,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + UnlockDisplay(dpy); + SyncHandle(); + + if (req->glxCode == X_GLsop_Flush) { + XFlush(dpy); + } + + } + + return Success; +} + +int __glXForwardPipe0WithReply( __GLXclientState *cl, GLbyte *pc ) +{ + ClientPtr client = cl->client; + xGLXSingleReq *req = (xGLXSingleReq *)pc; + xGLXSingleReq *be_req; + xGLXSingleReply reply; + xGLXSingleReply be_reply; + __GLXcontext *glxc; + int buf_size; + char *be_buf; + int be_buf_size; + DMXScreenInfo *dmxScreen; + Display *dpy; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return __glXBadContext; + } + + pc += sz_xGLXSingleReq; + buf_size = (req->length << 2) - sz_xGLXSingleReq; + + dmxScreen = &dmxScreens[glxc->pScreen->myNum]; + dpy = GetBackEndDisplay(cl, glxc->pScreen->myNum); + + /* + * send the request to the first back-end server + */ + LockDisplay(dpy); + GetReqSingle(GLXSingle,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,glxc->pScreen->myNum); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + + /* + * get the reply from the back-end server + */ + _XReply(dpy, (xReply*) &be_reply, 0, False); + be_buf_size = be_reply.length << 2; + if (be_buf_size > 0) { + be_buf = (char *)malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + /* + * send the reply to the client + */ + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = be_reply.length; + reply.retval = be_reply.retval; + reply.size = be_reply.size; + reply.pad3 = be_reply.pad3; + reply.pad4 = be_reply.pad4; + + if (client->swapped) { + SendSwappedReply( client, &reply, be_buf, be_buf_size ); + } + else { + WriteToClient(client, sizeof(xGLXSingleReply),(char *)&reply); + if (be_buf_size > 0) + WriteToClient(client, be_buf_size, (char *)be_buf); + } + + if (be_buf_size > 0) Xfree(be_buf); + + return Success; +} + +int __glXForwardAllWithReply( __GLXclientState *cl, GLbyte *pc ) +{ + ClientPtr client = cl->client; + xGLXSingleReq *req = (xGLXSingleReq *)pc; + xGLXSingleReq *be_req; + xGLXSingleReply reply; + xGLXSingleReply be_reply; + __GLXcontext *glxc; + int buf_size; + char *be_buf; + int be_buf_size; + int from_screen = 0; + int to_screen = 0; + int s; + + DMXScreenInfo *dmxScreen; + Display *dpy; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXSingleReq; + buf_size = (req->length << 2) - sz_xGLXSingleReq; + + /* + * send the request to the first back-end server(s) + */ + for (s=to_screen; s>=from_screen; s--) { + dmxScreen = &dmxScreens[s]; + dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReqSingle(GLXSingle,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + + /* + * get the reply from the back-end server + */ + _XReply(dpy, (xReply*) &be_reply, 0, False); + be_buf_size = be_reply.length << 2; + if (be_buf_size > 0) { + be_buf = (char *)malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + if (s > from_screen && be_buf_size > 0) { + Xfree(be_buf); + } + } + + /* + * send the reply to the client + */ + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = be_reply.length; + reply.retval = be_reply.retval; + reply.size = be_reply.size; + reply.pad3 = be_reply.pad3; + reply.pad4 = be_reply.pad4; + + if (client->swapped) { + SendSwappedReply( client, &reply, be_buf, be_buf_size ); + } + else { + WriteToClient(client, sizeof(xGLXSingleReply),(char *)&reply); + if (be_buf_size > 0) + WriteToClient(client, be_buf_size, (char *)be_buf); + } + + if (be_buf_size > 0) Xfree(be_buf); + + return Success; +} + +int __glXForwardSingleReqSwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXForwardSingleReq( cl, pc ) ); +} + +int __glXForwardPipe0WithReplySwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXForwardPipe0WithReply( cl, pc ) ); +} + +int __glXForwardPipe0WithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 2; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardPipe0WithReply( cl, pc ) ); +} + +int __glXForwardPipe0WithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 4; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardPipe0WithReply( cl, pc ) ); +} + +int __glXForwardPipe0WithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 8; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardPipe0WithReply( cl, pc ) ); +} + +int __glXForwardAllWithReplySwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardAllWithReply( cl, pc ) ); +} + +int __glXForwardAllWithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 2; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardAllWithReply( cl, pc ) ); +} + +int __glXForwardAllWithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 4; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardAllWithReply( cl, pc ) ); +} + +int __glXForwardAllWithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 8; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardAllWithReply( cl, pc ) ); +} + +static GLint __glReadPixels_size(GLenum format, GLenum type, GLint w, GLint h, + int *elementbits_return, int *rowbytes_return ) +{ + GLint elements, esize; + GLint rowsize, padding; + + if (w < 0 || h < 0) { + return -1; + } + switch (format) { + case GL_COLOR_INDEX: + case GL_STENCIL_INDEX: + case GL_DEPTH_COMPONENT: + elements = 1; + break; + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + elements = 1; + break; + case GL_LUMINANCE_ALPHA: + elements = 2; + break; + case GL_RGB: + case GL_BGR: + elements = 3; + break; + case GL_RGBA: + case GL_BGRA: + case GL_ABGR_EXT: + elements = 4; + break; + default: + return -1; + } + /* + ** According to the GLX protocol, each row must be padded to a multiple of + ** 4 bytes. 4 bytes also happens to be the default alignment in the pixel + ** store modes of the GL. + */ + switch (type) { + case GL_BITMAP: + if (format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX) { + rowsize = ((w * elements)+7)/8; + padding = rowsize % 4; + if (padding) { + rowsize += 4 - padding; + } + if (elementbits_return) *elementbits_return = elements; + if (rowbytes_return) *rowbytes_return = rowsize; + return (rowsize * h); + } else { + return -1; + } + case GL_BYTE: + case GL_UNSIGNED_BYTE: + esize = 1; + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + esize = 1; + elements = 1; + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + esize = 2; + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + esize = 2; + elements = 1; + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + esize = 4; + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + esize = 4; + elements = 1; + break; + default: + return -1; + } + rowsize = w * elements * esize; + padding = rowsize % 4; + if (padding) { + rowsize += 4 - padding; + } + + if (elementbits_return) *elementbits_return = esize*elements*8; + if (rowbytes_return) *rowbytes_return = rowsize; + + return (rowsize * h); +} + +static int intersectRect( int x1, int x2, int y1, int y2, + int X1, int X2, int Y1, int Y2, + int *ix1, int *ix2, int *iy1, int *iy2 ) +{ + int right = (x2 < X2 ? x2 : X2); + int bottom = (y2 < Y2 ? y2 : Y2); + int left = (x1 > X1 ? x1 : X1); + int top = (y1 > Y1 ? y1 : Y1); + int width = right - left + 1; + int height = bottom - top + 1; + + if ( (width <= 0) || (height <= 0) ) { + *ix1 = *ix2 = *iy1 = *iy2 = 0; + return(0); + } + else { + *ix1 = left; + *ix2 = right; + *iy1 = top; + *iy2 = bottom; + return( width * height ); + } + +} + +int __glXDisp_ReadPixels(__GLXclientState *cl, GLbyte *pc) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + xGLXSingleReq *be_req; + xGLXReadPixelsReply reply; + xGLXReadPixelsReply be_reply; + GLbyte *be_pc; + GLint x,y; + GLsizei width, height; + GLenum format, type; + GLboolean swapBytes, lsbFirst; + ClientPtr client = cl->client; + DrawablePtr pDraw; + int error; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + char *buf; + int buf_size; + int s; + int win_x1, win_x2; + int win_y1, win_y2; + int ebits, rowsize; + __GLX_DECLARE_SWAP_VARIABLES; + + if (client->swapped) { + __GLX_SWAP_INT(&req->contextTag); + } + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXSingleReq; + x = *(GLint *)(pc + 0); + y = *(GLint *)(pc + 4); + width = *(GLsizei *)(pc + 8); + height = *(GLsizei *)(pc + 12); + format = *(GLenum *)(pc + 16); + type = *(GLenum *)(pc + 20); + swapBytes = *(GLboolean *)(pc + 24); + lsbFirst = *(GLboolean *)(pc + 25); + + if (client->swapped) { + __GLX_SWAP_INT(&x); + __GLX_SWAP_INT(&y); + __GLX_SWAP_INT(&width); + __GLX_SWAP_INT(&height); + __GLX_SWAP_INT(&format); + __GLX_SWAP_INT(&type); + swapBytes = !swapBytes; + } + + buf_size = __glReadPixels_size(format,type,width,height, &ebits, &rowsize); + if (buf_size > 0) { + buf = (char *) malloc( buf_size ); + if ( !buf ) { + return( BadAlloc ); + } + } + else { + buf_size = 0; + } + + if (buf_size > 0) { + /* + * Get the current drawable this context is bound to + */ + pDraw = __glXLookupDrawableByTag( cl, req->contextTag ); + win_x1 = pDraw->x + x; + win_x2 = win_x1 + width - 1; + win_y1 = (dmxGlobalHeight - pDraw->y - pDraw->height) + y; + win_y2 = win_y1 + height - 1; + if (pDraw->type != DRAWABLE_WINDOW) { + from_screen = to_screen = 0; + } + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + int scr_x1 = dmxScreen->rootXOrigin; + int scr_x2 = dmxScreen->rootXOrigin + dmxScreen->scrnWidth - 1; + int scr_y1 = dmxScreen->rootYOrigin; + int scr_y2 = dmxScreen->rootYOrigin + dmxScreen->scrnHeight - 1; + int wx1, wx2, wy1, wy2; + int sx, sy, sw, sh; + int npixels; + + /* + * find the window portion that is on the current screen + */ + if (pDraw->type == DRAWABLE_WINDOW) { + npixels = intersectRect( scr_x1, scr_x2, scr_y1, scr_y2, + win_x1, win_x2, win_y1, win_y2, + &wx1, &wx2, &wy1, &wy2 ); + } + else { + wx1 = win_x1; + wx2 = win_x2; + wy1 = win_y1; + wy2 = win_y2; + npixels = (wx2-wx1+1) * (wy2-wy1+1); + } + + if (npixels > 0) { + + /* send the request to the back-end server */ + LockDisplay(dpy); + GetReqExtra(GLXSingle,__GLX_PAD(26),be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLsop_ReadPixels; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + be_pc = ((GLbyte *)(be_req) + sz_xGLXSingleReq); + + sx = wx1 - pDraw->x; + sy = wy1 - (dmxGlobalHeight - pDraw->y - pDraw->height); + sw = (wx2-wx1+1); + sh = (wy2-wy1+1); + + *(GLint *)(be_pc + 0) = sx; /* x */ + *(GLint *)(be_pc + 4) = sy; /* y */ + *(GLsizei *)(be_pc + 8) = sw; /* width */ + *(GLsizei *)(be_pc + 12) = sh; /* height */ + *(GLenum *)(be_pc + 16) = format; + *(GLenum *)(be_pc + 20) = type; + *(GLboolean *)(be_pc + 24) = swapBytes; + *(GLboolean *)(be_pc + 25) = lsbFirst; + + _XReply(dpy, (xReply*) &be_reply, 0, False); + + if (be_reply.length > 0) { + char *be_buf; + int be_buf_size = be_reply.length << 2; + + be_buf = (char *) malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + + /* copy pixels data to the right location of the */ + /* reply buffer */ + if ( type != GL_BITMAP ) { + int pbytes = ebits / 8; + char *dst = buf + (sy-y)*rowsize + (sx-x)*pbytes; + char *src = be_buf; + int pad = (pbytes * sw) % 4; + int r; + + for (r=0; r<sh; r++) { + memcpy( dst, src, pbytes*sw ); + dst += rowsize; + src += (pbytes*sw + (pad ? 4-pad : 0) ); + } + } + else { + /* this is a GL_BITMAP pixel type, should copy bits */ + int r; + int src_rowsize = bits_to_bytes(sw * ebits); + int src_pad = src_rowsize % 4; + if ( src_pad ) { + src_rowsize += (4 - src_pad); + } + + for (r=0; r<sh; r++) { + unsigned char dst_mask = 0x80 >> (sx % 8); + unsigned char src_mask = 0x80; + char *dst = buf + (sy-y+r)*rowsize + (sx-x)/8; + char *src = be_buf + r*src_rowsize; + int b; + + for (b=0; b<sw*ebits; b++) { + if ( *src & src_mask ) { + *dst |= dst_mask; + } + else { + *dst &= ~dst_mask; + } + + if (dst_mask > 1) dst_mask >>= 1; + else { + dst_mask = 0x80; + dst++; + } + + if (src_mask > 1) src_mask >>= 1; + else { + src_mask = 0x80; + src++; + } + } + } + + } + + Xfree( be_buf ); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + Xfree( buf ); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + } /* of npixels > 0 */ + + } /* of for loop */ + + } /* of if buf_size > 0 */ + + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = buf_size >> 2; + + if (client->swapped) { + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + } + + WriteToClient(client, sizeof(xGLXReadPixelsReply),(char *)&reply); + if (buf_size > 0) { + WriteToClient(client, buf_size, (char *)buf); + Xfree( buf ); + } + + return Success; +} + +int __glXDispSwap_GetTexImage(__GLXclientState *cl, GLbyte *pc) +{ + __GLX_DECLARE_SWAP_VARIABLES; + GLbyte *lpc = pc; + + lpc += sz_xGLXSingleReq; + __GLX_SWAP_INT(lpc+0); + __GLX_SWAP_INT(lpc+4); + __GLX_SWAP_INT(lpc+8); + __GLX_SWAP_INT(lpc+12); + + /* reverse swapBytes */ + *(GLboolean *)(lpc + 16) = ! *(GLboolean *)(lpc + 16); + + return( __glXForwardPipe0WithReplySwap( cl, pc ) ); +} + +int __glXDispSwap_GetColorTable(__GLXclientState *cl, GLbyte *pc) +{ + __GLX_DECLARE_SWAP_VARIABLES; + GLbyte *lpc = pc; + + lpc += sz_xGLXSingleReq; + __GLX_SWAP_INT(lpc+0); + __GLX_SWAP_INT(lpc+4); + __GLX_SWAP_INT(lpc+8); + + /* reverse swapBytes */ + *(GLboolean *)(lpc + 12) = ! *(GLboolean *)(lpc + 12); + + return( __glXForwardPipe0WithReplySwap( cl, pc ) ); +} + + diff --git a/xorg-server/hw/dmx/glxProxy/glxswap.c b/xorg-server/hw/dmx/glxProxy/glxswap.c index 1e184f914..1471d8b5f 100644 --- a/xorg-server/hw/dmx/glxProxy/glxswap.c +++ b/xorg-server/hw/dmx/glxProxy/glxswap.c @@ -1,538 +1,538 @@ -/* - * Copyright 2003 Red Hat Inc., Raleigh, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Kevin E. Martin <kem@redhat.com> - * - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxwindow.h" -#include "glxserver.h" -#include "glxswap.h" - -extern int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId, - GLXContextTag tag); - -typedef struct _SwapGroup *SwapGroupPtr; - -static Bool SwapBarrierIsReadyToSwap(GLuint barrier); -static void SwapSwapBarrier(GLuint barrier); -static void UpdateSwapBarrierList(GLuint barrier, - SwapGroupPtr pOldSwap, - SwapGroupPtr pNewSwap); - - -/************************************************************************ - * - * Swap Groups - * - ************************************************************************/ - -typedef struct _SwapGroup { - WindowPtr pWin; - SwapGroupPtr pNext; - - Bool swapping; - Bool sleeping; - GLuint barrier; - - XID drawable; - GLXContextTag tag; - __GLXclientState *clState; -} SwapGroupRec; - - -static void SwapSwapGroup(SwapGroupPtr pSwap) -{ - SwapGroupPtr pCur; - - /* All drawables in swap group are ready to swap, so just swap all - * drawables buffers and then wake up those clients that were - * previously sleeping */ - - for (pCur = pSwap; pCur; pCur = pCur->pNext) { - if (pCur->swapping) { - /* Swap pCur's buffers */ - __glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag); - pCur->swapping = FALSE; - } - - /* Wakeup client */ - if (pCur->sleeping) { - ClientWakeup(pCur->clState->client); - pCur->sleeping = FALSE; - } - } -} - -static Bool SwapGroupIsReadyToSwap(SwapGroupPtr pSwap) -{ - Bool isReady = TRUE; - - /* The swap group is ready to swap when all drawables are ready to - * swap. NOTE: A drawable is also ready to swap if it is not - * currently mapped */ - for (; pSwap; pSwap = pSwap->pNext) { - isReady &= (pSwap->swapping || !pSwap->pWin->mapped); - /* FIXME: Should we use pSwap->pWin->mapped or ...->realized ??? */ - } - - return isReady; -} - -static Bool SGSwapCleanup(ClientPtr client, pointer closure) -{ - /* SwapGroupPtr pSwap = (SwapGroupPtr)closure; */ - - /* This should not be called unless the client has died in which - * case we should remove the buffer from the swap list */ - - return TRUE; -} - -int SGSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag, - DrawablePtr pDraw) -{ - WindowPtr pWin = (WindowPtr)pDraw; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pSwap = pWinPriv->swapGroup; - SwapGroupPtr pCur; - - for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext); - if (!pCur) - return BadDrawable; - - pCur->clState = cl; - pCur->drawable = drawId; - pCur->tag = tag; - - /* We are now in the process of swapping */ - pCur->swapping = TRUE; - - if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { - /* The swap group is bound to a barrier and the barrier is ready - * to swap, so swap all the swap groups that are bound to this - * group's swap barrier */ - SwapSwapBarrier(pSwap->barrier); - } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { - /* Do the swap if the entire swap group is ready to swap and the - * group is not bound to a swap barrier */ - SwapSwapGroup(pSwap); - } else { - /* The swap group/barrier is not yet ready to swap, so put - * client to sleep until the rest are ready to swap */ - ClientSleep(cl->client, SGSwapCleanup, (pointer)pWin); - pCur->sleeping = TRUE; - } - - return Success; -} - -static void SGWindowUnmapped(WindowPtr pWin) -{ - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pSwap = pWinPriv->swapGroup; - - /* Now that one of the windows in the swap group has been unmapped, - * see if the entire swap group/barrier is ready to swap */ - - if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { - SwapSwapBarrier(pSwap->barrier); - } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { - SwapSwapGroup(pSwap); - } -} - -static void SGWindowDestroyed(WindowPtr pWin) -{ - JoinSwapGroupSGIX((DrawablePtr)pWin, NULL); -} - -static SwapGroupPtr CreateSwapEntry(WindowPtr pWin) -{ - SwapGroupPtr pEntry; - - /* Allocate new swap group */ - pEntry = xalloc(sizeof(*pEntry)); - if (!pEntry) return NULL; - - /* Initialize swap group */ - pEntry->pWin = pWin; - pEntry->pNext = NULL; - pEntry->swapping = FALSE; - pEntry->sleeping = FALSE; - pEntry->barrier = 0; - /* The following are not initialized until SwapBuffers is called: - * pEntry->drawable - * pEntry->tag - * pEntry->clState - */ - - return pEntry; -} - -static void FreeSwapEntry(SwapGroupPtr pEntry) -{ - /* Since we have removed the drawable from its previous swap group - * and it won't be added to another swap group, the only thing that - * we need to do is to make sure that the drawable's client is not - * sleeping. This could happen if one thread is sleeping, while - * another thread called glxJoinSwapGroup(). Note that all sleeping - * threads should also be swapping, but there is a small window in - * the SGSwapBuffer() logic, above, where swapping can be set but - * sleeping is not. We check both independently here just to be - * pedantic. */ - - /* Handle swap buffer request */ - if (pEntry->swapping) - __glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag); - - /* Wake up client */ - if (pEntry->sleeping) - ClientWakeup(pEntry->clState->client); - - /* We can free the pEntry entry since it has already been removed - * from the swap group list and it won't be needed any longer */ - xfree(pEntry); -} - -int JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember) -{ - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pOldSwap = NULL; - SwapGroupPtr pEntry; - - /* If pDraw and pMember are already members of the same swap - * group, just return Success since there is nothing to do */ - for (pEntry = pWinPriv->swapGroup; pEntry; pEntry = pEntry->pNext) - if (pEntry->pWin == (WindowPtr)pMember) - return Success; - - /* Remove pDraw from its current swap group */ - if (pWinPriv->swapGroup) { - SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; - SwapGroupPtr pPrev; - - /* Find old swap entry in swap group and save in pOldSwap - * for later use */ - for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL; - pOldSwap && pOldSwap->pWin != pWin; - pPrev = pOldSwap, pOldSwap = pOldSwap->pNext); - if (!pOldSwap) - return BadDrawable; - - /* Remove pDraw's swap group entry from swap group list */ - if (pPrev) { - pPrev->pNext = pOldSwap->pNext; - } else { - /* pWin is at the head of the swap group list, so we - * need to update all other members of this swap - * group */ - for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext) - DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup - = pOldSwap->pNext; - - /* Update the barrier list as well */ - if (pOldSwap->barrier) - UpdateSwapBarrierList(pOldSwap->barrier, - pOldSwap, pOldSwap->pNext); - - /* Set pSwapGroup to point to the swap group without - * pOldSwap */ - pSwapGroup = pOldSwap->pNext; - } - - /* Check to see if current swap group can now swap since we - * know at this point that pDraw and pMember are guaranteed - * to previously be in different swap groups */ - if (pSwapGroup && SwapGroupIsReadyToSwap(pSwapGroup)) { - SwapSwapGroup(pSwapGroup); - } - - /* Make the old swap entry a standalone group */ - pOldSwap->pNext = NULL; - pOldSwap->barrier = 0; - - /* Reset pWin's swap group */ - pWinPriv->swapGroup = NULL; - pWinPriv->windowDestroyed = NULL; - pWinPriv->windowUnmapped = NULL; - } - - if (!pMember || pMember->type != DRAWABLE_WINDOW) { - /* Free old swap group since it is no longer needed */ - if (pOldSwap) FreeSwapEntry(pOldSwap); - } else if (pDraw == pMember && pOldSwap) { - /* Special case where pDraw was previously created and we - * are now just putting it to its own swap group */ - pWinPriv->swapGroup = pOldSwap; - pWinPriv->windowDestroyed = SGWindowDestroyed; - pWinPriv->windowUnmapped = SGWindowUnmapped; - - /* Check to see if pDraw is ready to swap */ - if (SwapGroupIsReadyToSwap(pOldSwap)) - SwapSwapGroup(pOldSwap); - } else if (pMember->type == DRAWABLE_WINDOW) { - WindowPtr pMemberWin = (WindowPtr)pMember; - dmxWinPrivPtr pMemberPriv = DMX_GET_WINDOW_PRIV(pMemberWin); - SwapGroupPtr pMemberSwapGroup = pMemberPriv->swapGroup; - - /* Finally, how we can add pDraw to pMember's swap group */ - - /* If pMember is not currently in a swap group, then create - * one for it since we are just about to add pDraw to it. */ - if (!pMemberSwapGroup) { - /* Create new swap group */ - pMemberSwapGroup = CreateSwapEntry(pMemberWin); - if (!pMemberSwapGroup) { - if (pOldSwap) FreeSwapEntry(pOldSwap); - return BadAlloc; - } - - /* Set pMember's swap group */ - pMemberPriv->swapGroup = pMemberSwapGroup; - pMemberPriv->windowDestroyed = SGWindowDestroyed; - pMemberPriv->windowUnmapped = SGWindowUnmapped; - } - - /* If pDraw == pMember, that means pDraw was not a member of - * a group previously (or it would have been handled by the - * special case above), so no additional work is required - * since we just created a new swap group for pMember (i.e., - * pDraw). */ - - if (pDraw != pMember) { - /* If pDraw was not previously in a swap group, then create - * an entry for it */ - if (!pOldSwap) { - /* Create new swap group */ - pOldSwap = CreateSwapEntry(pWin); - if (!pOldSwap) { - /* If we just created a swap group for pMember, we - * need to free it here */ - if (pMemberSwapGroup->pNext == NULL) { - FreeSwapEntry(pMemberSwapGroup); - pMemberPriv->swapGroup = NULL; - } - return BadAlloc; - } - } - - /* Find last entry in pMember's swap group */ - for (pEntry = pMemberSwapGroup; - pEntry->pNext; - pEntry = pEntry->pNext); - - /* Add pDraw's swap group entry to pMember's swap group list */ - pEntry->pNext = pOldSwap; - - /* Add pDraw to pMember's swap barrier */ - pOldSwap->barrier = pEntry->barrier; - - /* Set pDraw's swap group */ - pWinPriv->swapGroup = pMemberSwapGroup; - pWinPriv->windowDestroyed = SGWindowDestroyed; - pWinPriv->windowUnmapped = SGWindowUnmapped; - } - } - } - - return Success; -} - - -/************************************************************************ - * - * Swap Barriers - * - ************************************************************************/ - -#define GLX_MAX_SWAP_BARRIERS 10 - -typedef struct _SwapBarrier *SwapBarrierPtr; -typedef struct _SwapBarrier { - SwapGroupPtr pSwap; - SwapBarrierPtr pNext; -} SwapBarrierRec; - -static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS+1]; - -void SwapBarrierInit(void) -{ - int i; - - for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) - SwapBarrierList[i] = NULL; -} - -void SwapBarrierReset(void) -{ - int i; - - for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) { - SwapBarrierPtr pBarrier, pNextBarrier; - for (pBarrier = SwapBarrierList[i]; - pBarrier; - pBarrier = pNextBarrier) { - pNextBarrier = pBarrier->pNext; - xfree(pBarrier); - } - SwapBarrierList[i] = NULL; - } -} - -int QueryMaxSwapBarriersSGIX(int screen) -{ - return GLX_MAX_SWAP_BARRIERS; -} - -static Bool BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) -{ - SwapBarrierPtr pBarrier; - - pBarrier = xalloc(sizeof(*pBarrier)); - if (!pBarrier) return FALSE; - - /* Add the swap group to barrier's list */ - pBarrier->pSwap = pSwapGroup; - pBarrier->pNext = SwapBarrierList[barrier]; - SwapBarrierList[barrier] = pBarrier; - - return TRUE; -} - -static Bool UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) -{ - SwapBarrierPtr pBarrier, pPrevBarrier; - - /* Find the swap group in barrier's list */ - for (pBarrier = SwapBarrierList[barrier], pPrevBarrier = NULL; - pBarrier && pBarrier->pSwap != pSwapGroup; - pPrevBarrier = pBarrier, pBarrier = pBarrier->pNext); - if (!pBarrier) return FALSE; - - /* Remove the swap group from barrier's list */ - if (pPrevBarrier) pPrevBarrier->pNext = pBarrier->pNext; - else SwapBarrierList[barrier] = pBarrier->pNext; - - /* Free memory */ - xfree(pBarrier); - - return TRUE; -} - -static void UpdateSwapBarrierList(GLuint barrier, - SwapGroupPtr pOldSwap, - SwapGroupPtr pNewSwap) -{ - SwapBarrierPtr pBarrier; - - /* If the old swap group is being destroyed, then we need to remove - * the swap group from the list entirely */ - if (!pNewSwap) { - UnbindSwapGroupFromBarrier(barrier, pOldSwap); - return; - } - - /* Otherwise, find the old swap group in the barrier list and change - * it to the new swap group */ - for (pBarrier = SwapBarrierList[barrier]; - pBarrier; - pBarrier = pBarrier->pNext) { - if (pBarrier->pSwap == pOldSwap) { - pBarrier->pSwap = pNewSwap; - return; - } - } -} - -static Bool SwapBarrierIsReadyToSwap(GLuint barrier) -{ - SwapBarrierPtr pBarrier; - Bool isReady = TRUE; - - /* The swap barier is ready to swap when swap groups that are bound - * to barrier are ready to swap */ - for (pBarrier = SwapBarrierList[barrier]; - pBarrier; - pBarrier = pBarrier->pNext) - isReady &= SwapGroupIsReadyToSwap(pBarrier->pSwap); - - return isReady; -} - -static void SwapSwapBarrier(GLuint barrier) -{ - SwapBarrierPtr pBarrier; - - /* Swap each group that is a member of this barrier */ - for (pBarrier = SwapBarrierList[barrier]; - pBarrier; - pBarrier = pBarrier->pNext) - SwapSwapGroup(pBarrier->pSwap); -} - -int BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier) -{ - /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */ - - if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS) - return BadValue; - - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; - SwapGroupPtr pCur; - - if (!pSwapGroup) return BadDrawable; - if (barrier && pSwapGroup->barrier) return BadValue; - - /* Update the swap barrier list */ - if (barrier) { - if (!BindSwapGroupToBarrier(barrier, pSwapGroup)) - return BadAlloc; - } else { - if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup)) - return BadDrawable; - } - - /* Set the barrier for each member of this swap group */ - for (pCur = pSwapGroup; pCur; pCur = pCur->pNext) - pCur->barrier = barrier; - } - - return Success; -} +/* + * Copyright 2003 Red Hat Inc., Raleigh, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Kevin E. Martin <kem@redhat.com> + * + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxwindow.h" +#include "glxserver.h" +#include "glxswap.h" + +extern int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId, + GLXContextTag tag); + +typedef struct _SwapGroup *SwapGroupPtr; + +static Bool SwapBarrierIsReadyToSwap(GLuint barrier); +static void SwapSwapBarrier(GLuint barrier); +static void UpdateSwapBarrierList(GLuint barrier, + SwapGroupPtr pOldSwap, + SwapGroupPtr pNewSwap); + + +/************************************************************************ + * + * Swap Groups + * + ************************************************************************/ + +typedef struct _SwapGroup { + WindowPtr pWin; + SwapGroupPtr pNext; + + Bool swapping; + Bool sleeping; + GLuint barrier; + + XID drawable; + GLXContextTag tag; + __GLXclientState *clState; +} SwapGroupRec; + + +static void SwapSwapGroup(SwapGroupPtr pSwap) +{ + SwapGroupPtr pCur; + + /* All drawables in swap group are ready to swap, so just swap all + * drawables buffers and then wake up those clients that were + * previously sleeping */ + + for (pCur = pSwap; pCur; pCur = pCur->pNext) { + if (pCur->swapping) { + /* Swap pCur's buffers */ + __glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag); + pCur->swapping = FALSE; + } + + /* Wakeup client */ + if (pCur->sleeping) { + ClientWakeup(pCur->clState->client); + pCur->sleeping = FALSE; + } + } +} + +static Bool SwapGroupIsReadyToSwap(SwapGroupPtr pSwap) +{ + Bool isReady = TRUE; + + /* The swap group is ready to swap when all drawables are ready to + * swap. NOTE: A drawable is also ready to swap if it is not + * currently mapped */ + for (; pSwap; pSwap = pSwap->pNext) { + isReady &= (pSwap->swapping || !pSwap->pWin->mapped); + /* FIXME: Should we use pSwap->pWin->mapped or ...->realized ??? */ + } + + return isReady; +} + +static Bool SGSwapCleanup(ClientPtr client, pointer closure) +{ + /* SwapGroupPtr pSwap = (SwapGroupPtr)closure; */ + + /* This should not be called unless the client has died in which + * case we should remove the buffer from the swap list */ + + return TRUE; +} + +int SGSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag, + DrawablePtr pDraw) +{ + WindowPtr pWin = (WindowPtr)pDraw; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + SwapGroupPtr pSwap = pWinPriv->swapGroup; + SwapGroupPtr pCur; + + for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext); + if (!pCur) + return BadDrawable; + + pCur->clState = cl; + pCur->drawable = drawId; + pCur->tag = tag; + + /* We are now in the process of swapping */ + pCur->swapping = TRUE; + + if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { + /* The swap group is bound to a barrier and the barrier is ready + * to swap, so swap all the swap groups that are bound to this + * group's swap barrier */ + SwapSwapBarrier(pSwap->barrier); + } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { + /* Do the swap if the entire swap group is ready to swap and the + * group is not bound to a swap barrier */ + SwapSwapGroup(pSwap); + } else { + /* The swap group/barrier is not yet ready to swap, so put + * client to sleep until the rest are ready to swap */ + ClientSleep(cl->client, SGSwapCleanup, (pointer)pWin); + pCur->sleeping = TRUE; + } + + return Success; +} + +static void SGWindowUnmapped(WindowPtr pWin) +{ + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + SwapGroupPtr pSwap = pWinPriv->swapGroup; + + /* Now that one of the windows in the swap group has been unmapped, + * see if the entire swap group/barrier is ready to swap */ + + if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { + SwapSwapBarrier(pSwap->barrier); + } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { + SwapSwapGroup(pSwap); + } +} + +static void SGWindowDestroyed(WindowPtr pWin) +{ + JoinSwapGroupSGIX((DrawablePtr)pWin, NULL); +} + +static SwapGroupPtr CreateSwapEntry(WindowPtr pWin) +{ + SwapGroupPtr pEntry; + + /* Allocate new swap group */ + pEntry = malloc(sizeof(*pEntry)); + if (!pEntry) return NULL; + + /* Initialize swap group */ + pEntry->pWin = pWin; + pEntry->pNext = NULL; + pEntry->swapping = FALSE; + pEntry->sleeping = FALSE; + pEntry->barrier = 0; + /* The following are not initialized until SwapBuffers is called: + * pEntry->drawable + * pEntry->tag + * pEntry->clState + */ + + return pEntry; +} + +static void FreeSwapEntry(SwapGroupPtr pEntry) +{ + /* Since we have removed the drawable from its previous swap group + * and it won't be added to another swap group, the only thing that + * we need to do is to make sure that the drawable's client is not + * sleeping. This could happen if one thread is sleeping, while + * another thread called glxJoinSwapGroup(). Note that all sleeping + * threads should also be swapping, but there is a small window in + * the SGSwapBuffer() logic, above, where swapping can be set but + * sleeping is not. We check both independently here just to be + * pedantic. */ + + /* Handle swap buffer request */ + if (pEntry->swapping) + __glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag); + + /* Wake up client */ + if (pEntry->sleeping) + ClientWakeup(pEntry->clState->client); + + /* We can free the pEntry entry since it has already been removed + * from the swap group list and it won't be needed any longer */ + free(pEntry); +} + +int JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember) +{ + if (pDraw->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDraw; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + SwapGroupPtr pOldSwap = NULL; + SwapGroupPtr pEntry; + + /* If pDraw and pMember are already members of the same swap + * group, just return Success since there is nothing to do */ + for (pEntry = pWinPriv->swapGroup; pEntry; pEntry = pEntry->pNext) + if (pEntry->pWin == (WindowPtr)pMember) + return Success; + + /* Remove pDraw from its current swap group */ + if (pWinPriv->swapGroup) { + SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; + SwapGroupPtr pPrev; + + /* Find old swap entry in swap group and save in pOldSwap + * for later use */ + for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL; + pOldSwap && pOldSwap->pWin != pWin; + pPrev = pOldSwap, pOldSwap = pOldSwap->pNext); + if (!pOldSwap) + return BadDrawable; + + /* Remove pDraw's swap group entry from swap group list */ + if (pPrev) { + pPrev->pNext = pOldSwap->pNext; + } else { + /* pWin is at the head of the swap group list, so we + * need to update all other members of this swap + * group */ + for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext) + DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup + = pOldSwap->pNext; + + /* Update the barrier list as well */ + if (pOldSwap->barrier) + UpdateSwapBarrierList(pOldSwap->barrier, + pOldSwap, pOldSwap->pNext); + + /* Set pSwapGroup to point to the swap group without + * pOldSwap */ + pSwapGroup = pOldSwap->pNext; + } + + /* Check to see if current swap group can now swap since we + * know at this point that pDraw and pMember are guaranteed + * to previously be in different swap groups */ + if (pSwapGroup && SwapGroupIsReadyToSwap(pSwapGroup)) { + SwapSwapGroup(pSwapGroup); + } + + /* Make the old swap entry a standalone group */ + pOldSwap->pNext = NULL; + pOldSwap->barrier = 0; + + /* Reset pWin's swap group */ + pWinPriv->swapGroup = NULL; + pWinPriv->windowDestroyed = NULL; + pWinPriv->windowUnmapped = NULL; + } + + if (!pMember || pMember->type != DRAWABLE_WINDOW) { + /* Free old swap group since it is no longer needed */ + if (pOldSwap) FreeSwapEntry(pOldSwap); + } else if (pDraw == pMember && pOldSwap) { + /* Special case where pDraw was previously created and we + * are now just putting it to its own swap group */ + pWinPriv->swapGroup = pOldSwap; + pWinPriv->windowDestroyed = SGWindowDestroyed; + pWinPriv->windowUnmapped = SGWindowUnmapped; + + /* Check to see if pDraw is ready to swap */ + if (SwapGroupIsReadyToSwap(pOldSwap)) + SwapSwapGroup(pOldSwap); + } else if (pMember->type == DRAWABLE_WINDOW) { + WindowPtr pMemberWin = (WindowPtr)pMember; + dmxWinPrivPtr pMemberPriv = DMX_GET_WINDOW_PRIV(pMemberWin); + SwapGroupPtr pMemberSwapGroup = pMemberPriv->swapGroup; + + /* Finally, how we can add pDraw to pMember's swap group */ + + /* If pMember is not currently in a swap group, then create + * one for it since we are just about to add pDraw to it. */ + if (!pMemberSwapGroup) { + /* Create new swap group */ + pMemberSwapGroup = CreateSwapEntry(pMemberWin); + if (!pMemberSwapGroup) { + if (pOldSwap) FreeSwapEntry(pOldSwap); + return BadAlloc; + } + + /* Set pMember's swap group */ + pMemberPriv->swapGroup = pMemberSwapGroup; + pMemberPriv->windowDestroyed = SGWindowDestroyed; + pMemberPriv->windowUnmapped = SGWindowUnmapped; + } + + /* If pDraw == pMember, that means pDraw was not a member of + * a group previously (or it would have been handled by the + * special case above), so no additional work is required + * since we just created a new swap group for pMember (i.e., + * pDraw). */ + + if (pDraw != pMember) { + /* If pDraw was not previously in a swap group, then create + * an entry for it */ + if (!pOldSwap) { + /* Create new swap group */ + pOldSwap = CreateSwapEntry(pWin); + if (!pOldSwap) { + /* If we just created a swap group for pMember, we + * need to free it here */ + if (pMemberSwapGroup->pNext == NULL) { + FreeSwapEntry(pMemberSwapGroup); + pMemberPriv->swapGroup = NULL; + } + return BadAlloc; + } + } + + /* Find last entry in pMember's swap group */ + for (pEntry = pMemberSwapGroup; + pEntry->pNext; + pEntry = pEntry->pNext); + + /* Add pDraw's swap group entry to pMember's swap group list */ + pEntry->pNext = pOldSwap; + + /* Add pDraw to pMember's swap barrier */ + pOldSwap->barrier = pEntry->barrier; + + /* Set pDraw's swap group */ + pWinPriv->swapGroup = pMemberSwapGroup; + pWinPriv->windowDestroyed = SGWindowDestroyed; + pWinPriv->windowUnmapped = SGWindowUnmapped; + } + } + } + + return Success; +} + + +/************************************************************************ + * + * Swap Barriers + * + ************************************************************************/ + +#define GLX_MAX_SWAP_BARRIERS 10 + +typedef struct _SwapBarrier *SwapBarrierPtr; +typedef struct _SwapBarrier { + SwapGroupPtr pSwap; + SwapBarrierPtr pNext; +} SwapBarrierRec; + +static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS+1]; + +void SwapBarrierInit(void) +{ + int i; + + for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) + SwapBarrierList[i] = NULL; +} + +void SwapBarrierReset(void) +{ + int i; + + for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) { + SwapBarrierPtr pBarrier, pNextBarrier; + for (pBarrier = SwapBarrierList[i]; + pBarrier; + pBarrier = pNextBarrier) { + pNextBarrier = pBarrier->pNext; + free(pBarrier); + } + SwapBarrierList[i] = NULL; + } +} + +int QueryMaxSwapBarriersSGIX(int screen) +{ + return GLX_MAX_SWAP_BARRIERS; +} + +static Bool BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) +{ + SwapBarrierPtr pBarrier; + + pBarrier = malloc(sizeof(*pBarrier)); + if (!pBarrier) return FALSE; + + /* Add the swap group to barrier's list */ + pBarrier->pSwap = pSwapGroup; + pBarrier->pNext = SwapBarrierList[barrier]; + SwapBarrierList[barrier] = pBarrier; + + return TRUE; +} + +static Bool UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) +{ + SwapBarrierPtr pBarrier, pPrevBarrier; + + /* Find the swap group in barrier's list */ + for (pBarrier = SwapBarrierList[barrier], pPrevBarrier = NULL; + pBarrier && pBarrier->pSwap != pSwapGroup; + pPrevBarrier = pBarrier, pBarrier = pBarrier->pNext); + if (!pBarrier) return FALSE; + + /* Remove the swap group from barrier's list */ + if (pPrevBarrier) pPrevBarrier->pNext = pBarrier->pNext; + else SwapBarrierList[barrier] = pBarrier->pNext; + + /* Free memory */ + free(pBarrier); + + return TRUE; +} + +static void UpdateSwapBarrierList(GLuint barrier, + SwapGroupPtr pOldSwap, + SwapGroupPtr pNewSwap) +{ + SwapBarrierPtr pBarrier; + + /* If the old swap group is being destroyed, then we need to remove + * the swap group from the list entirely */ + if (!pNewSwap) { + UnbindSwapGroupFromBarrier(barrier, pOldSwap); + return; + } + + /* Otherwise, find the old swap group in the barrier list and change + * it to the new swap group */ + for (pBarrier = SwapBarrierList[barrier]; + pBarrier; + pBarrier = pBarrier->pNext) { + if (pBarrier->pSwap == pOldSwap) { + pBarrier->pSwap = pNewSwap; + return; + } + } +} + +static Bool SwapBarrierIsReadyToSwap(GLuint barrier) +{ + SwapBarrierPtr pBarrier; + Bool isReady = TRUE; + + /* The swap barier is ready to swap when swap groups that are bound + * to barrier are ready to swap */ + for (pBarrier = SwapBarrierList[barrier]; + pBarrier; + pBarrier = pBarrier->pNext) + isReady &= SwapGroupIsReadyToSwap(pBarrier->pSwap); + + return isReady; +} + +static void SwapSwapBarrier(GLuint barrier) +{ + SwapBarrierPtr pBarrier; + + /* Swap each group that is a member of this barrier */ + for (pBarrier = SwapBarrierList[barrier]; + pBarrier; + pBarrier = pBarrier->pNext) + SwapSwapGroup(pBarrier->pSwap); +} + +int BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier) +{ + /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */ + + if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS) + return BadValue; + + if (pDraw->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDraw; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; + SwapGroupPtr pCur; + + if (!pSwapGroup) return BadDrawable; + if (barrier && pSwapGroup->barrier) return BadValue; + + /* Update the swap barrier list */ + if (barrier) { + if (!BindSwapGroupToBarrier(barrier, pSwapGroup)) + return BadAlloc; + } else { + if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup)) + return BadDrawable; + } + + /* Set the barrier for each member of this swap group */ + for (pCur = pSwapGroup; pCur; pCur = pCur->pNext) + pCur->barrier = barrier; + } + + return Success; +} diff --git a/xorg-server/hw/dmx/glxProxy/glxutil.c b/xorg-server/hw/dmx/glxProxy/glxutil.c index d0ce50486..2460ed0dc 100644 --- a/xorg-server/hw/dmx/glxProxy/glxutil.c +++ b/xorg-server/hw/dmx/glxProxy/glxutil.c @@ -1,111 +1,111 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#include "glxserver.h" -#include <GL/glxtokens.h> -#include <pixmapstr.h> -#include <windowstr.h> -#include "glxutil.h" -#include <stdlib.h> - -/************************************************************************/ - -void __glXNop(void) {} - -/************************************************************************/ - -/* Memory Allocation for GLX */ - -void * -__glXMalloc(size_t size) -{ - void *addr; - - if (size == 0) { - return NULL; - } - addr = malloc(size); - if (addr == NULL) { - /* XXX: handle out of memory error */ - return NULL; - } - return addr; -} - -void * -__glXCalloc(size_t numElements, size_t elementSize) -{ - void *addr; - size_t size; - - if ((numElements == 0) || (elementSize == 0)) { - return NULL; - } - addr = calloc(numElements, elementSize); - if (addr == NULL) { - /* XXX: handle out of memory error */ - return NULL; - } - return addr; -} - -void * -__glXRealloc(void *addr, size_t newSize) -{ - void *newAddr; - - if (addr) { - if (newSize == 0) { - xfree(addr); - return NULL; - } else { - newAddr = realloc(addr, newSize); - } - } else { - if (newSize == 0) { - return NULL; - } else { - newAddr = malloc(newSize); - } - } - if (newAddr == NULL) { - return NULL; /* XXX: out of memory */ - } - - return newAddr; -} - -void -__glXFree(void *addr) -{ - if (addr) { - free(addr); - } -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#include "glxserver.h" +#include <GL/glxtokens.h> +#include <pixmapstr.h> +#include <windowstr.h> +#include "glxutil.h" +#include <stdlib.h> + +/************************************************************************/ + +void __glXNop(void) {} + +/************************************************************************/ + +/* Memory Allocation for GLX */ + +void * +__glXMalloc(size_t size) +{ + void *addr; + + if (size == 0) { + return NULL; + } + addr = malloc(size); + if (addr == NULL) { + /* XXX: handle out of memory error */ + return NULL; + } + return addr; +} + +void * +__glXCalloc(size_t numElements, size_t elementSize) +{ + void *addr; + size_t size; + + if ((numElements == 0) || (elementSize == 0)) { + return NULL; + } + addr = calloc(numElements, elementSize); + if (addr == NULL) { + /* XXX: handle out of memory error */ + return NULL; + } + return addr; +} + +void * +__glXRealloc(void *addr, size_t newSize) +{ + void *newAddr; + + if (addr) { + if (newSize == 0) { + free(addr); + return NULL; + } else { + newAddr = realloc(addr, newSize); + } + } else { + if (newSize == 0) { + return NULL; + } else { + newAddr = malloc(newSize); + } + } + if (newAddr == NULL) { + return NULL; /* XXX: out of memory */ + } + + return newAddr; +} + +void +__glXFree(void *addr) +{ + if (addr) { + free(addr); + } +} diff --git a/xorg-server/hw/dmx/glxProxy/glxvendor.c b/xorg-server/hw/dmx/glxProxy/glxvendor.c index 6b1f9a820..e8460fad8 100644 --- a/xorg-server/hw/dmx/glxProxy/glxvendor.c +++ b/xorg-server/hw/dmx/glxProxy/glxvendor.c @@ -1,582 +1,582 @@ -/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED */ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxfont.h" - -#undef Xmalloc -#undef Xcalloc -#undef Xrealloc -#undef Xfree - -#include "glxserver.h" -#include "glxext.h" -#include "g_disptab.h" -/* #include "g_disptab_EXT.h" */ -#include "unpack.h" -#include "glxutil.h" - -#include "GL/glxproto.h" - -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -/* - * GetReqVendorPrivate - this is the equivalent of GetReq macro - * from Xlibint.h but it does not set the reqType field (the opcode). - * this is because the GL single opcodes has different naming convension - * the other X opcodes (ie. X_GLsop_GetFloatv). - */ -#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) -#define GetReqVendorPrivate(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x##name##Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ - req->length = (SIZEOF(x##name##Req))>>2;\ - dpy->bufptr += SIZEOF(x##name##Req);\ - dpy->request++ - -#else /* non-ANSI C uses empty comment instead of "##" for token concatenation */ -#define GetReqVendorPrivate(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x/**/name/**/Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ - req->length = (SIZEOF(x/**/name/**/Req))>>2;\ - dpy->bufptr += SIZEOF(x/**/name/**/Req);\ - dpy->request++ -#endif - -extern Display *GetBackEndDisplay( __GLXclientState *cl, int s ); -extern int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s); - -static int swap_vec_element_size = 0; - -static void SendSwappedReply( ClientPtr client, - xGLXVendorPrivReply *reply, - char *buf, - int buf_size ) -{ - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_SHORT(&reply->sequenceNumber); - __GLX_SWAP_INT(&reply->length); - __GLX_SWAP_INT(&reply->retval); - __GLX_SWAP_INT(&reply->size); - - if ( (buf_size == 0) && (swap_vec_element_size > 0) ) { - /* - * the reply has single component - need to swap pad3 - */ - if (swap_vec_element_size == 2) { - __GLX_SWAP_SHORT(&reply->pad3); - } - else if (swap_vec_element_size == 4) { - __GLX_SWAP_INT(&reply->pad3); - __GLX_SWAP_INT(&reply->pad4); - } - else if (swap_vec_element_size == 8) { - __GLX_SWAP_DOUBLE(&reply->pad3); - } - } - else if ( (buf_size > 0) && (swap_vec_element_size > 0) ) { - /* - * the reply has vector of elements which needs to be swapped - */ - int vsize = buf_size / swap_vec_element_size; - char *p = buf; - int i; - - for (i=0; i<vsize; i++) { - if (swap_vec_element_size == 2) { - __GLX_SWAP_SHORT(p); - } - else if (swap_vec_element_size == 4) { - __GLX_SWAP_INT(p); - } - else if (swap_vec_element_size == 8) { - __GLX_SWAP_DOUBLE(p); - } - - p += swap_vec_element_size; - } - - __GLX_SWAP_INT(&reply->pad3); - __GLX_SWAP_INT(&reply->pad4); - __GLX_SWAP_INT(&reply->pad5); - __GLX_SWAP_INT(&reply->pad6); - - } - - WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)reply); - if (buf_size > 0) - WriteToClient(client, buf_size, (char *)buf); - -} - -int __glXVForwardSingleReq( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - xGLXVendorPrivateReq *be_req; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int buf_size; - int s; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXVendorPrivateReq; - buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; - - /* - * just forward the request to back-end server(s) - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReqVendorPrivate(GLXVendorPrivate,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->vendorCode = req->vendorCode; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -int __glXVForwardPipe0WithReply( __GLXclientState *cl, GLbyte *pc ) -{ - ClientPtr client = cl->client; - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - xGLXVendorPrivateReq *be_req; - xGLXVendorPrivReply reply; - xGLXVendorPrivReply be_reply; - __GLXcontext *glxc; - int buf_size; - char *be_buf; - int be_buf_size; - DMXScreenInfo *dmxScreen; - Display *dpy; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return __glXBadContext; - } - - pc += sz_xGLXVendorPrivateReq; - buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; - - dmxScreen = &dmxScreens[glxc->pScreen->myNum]; - dpy = GetBackEndDisplay(cl, glxc->pScreen->myNum); - - /* - * send the request to the first back-end server - */ - LockDisplay(dpy); - GetReqVendorPrivate(GLXVendorPrivate,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->vendorCode = req->vendorCode; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag, glxc->pScreen->myNum); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - - /* - * get the reply from the back-end server - */ - _XReply(dpy, (xReply*) &be_reply, 0, False); - be_buf_size = be_reply.length << 2; - if (be_buf_size > 0) { - be_buf = (char *)Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - /* - * send the reply to the client - */ - memcpy( &reply, &be_reply, sz_xGLXVendorPrivReply ); - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - SendSwappedReply( client, &reply, be_buf, be_buf_size ); - } - else { - WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)&reply); - if (be_buf_size > 0) - WriteToClient(client, be_buf_size, (char *)be_buf); - } - - if (be_buf_size > 0) Xfree(be_buf); - - return Success; -} - -int __glXVForwardAllWithReply( __GLXclientState *cl, GLbyte *pc ) -{ - ClientPtr client = cl->client; - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - xGLXVendorPrivateReq *be_req; - xGLXVendorPrivReply reply; - xGLXVendorPrivReply be_reply; - __GLXcontext *glxc; - int buf_size; - char *be_buf; - int be_buf_size; - int from_screen = 0; - int to_screen = 0; - int s; - - DMXScreenInfo *dmxScreen; - Display *dpy; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXVendorPrivateReq; - buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; - - /* - * send the request to the first back-end server(s) - */ - for (s=to_screen; s>=from_screen; s--) { - dmxScreen = &dmxScreens[s]; - dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReqVendorPrivate(GLXVendorPrivate,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->vendorCode = req->vendorCode; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - - /* - * get the reply from the back-end server - */ - _XReply(dpy, (xReply*) &be_reply, 0, False); - be_buf_size = be_reply.length << 2; - if (be_buf_size > 0) { - be_buf = (char *)Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - if (s > from_screen && be_buf_size > 0) { - Xfree(be_buf); - } - } - - /* - * send the reply to the client - */ - memcpy( &reply, &be_reply, sz_xGLXVendorPrivReply ); - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - SendSwappedReply( client, &reply, be_buf, be_buf_size ); - } - else { - WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)&reply); - if (be_buf_size > 0) - WriteToClient(client, be_buf_size, (char *)be_buf); - } - - if (be_buf_size > 0) Xfree(be_buf); - - return Success; -} - -int __glXVForwardSingleReqSwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - return( __glXVForwardSingleReq( cl, pc ) ); -} - -int __glXVForwardPipe0WithReplySwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardPipe0WithReply( cl, pc ) ); -} - -int __glXVForwardPipe0WithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 2; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardPipe0WithReply( cl, pc ) ); -} - -int __glXVForwardPipe0WithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 4; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardPipe0WithReply( cl, pc ) ); -} - -int __glXVForwardPipe0WithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 8; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardPipe0WithReply( cl, pc ) ); -} - -int __glXVForwardAllWithReplySwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardAllWithReply( cl, pc ) ); -} - -int __glXVForwardAllWithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 2; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardAllWithReply( cl, pc ) ); -} - -int __glXVForwardAllWithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 4; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardAllWithReply( cl, pc ) ); -} - -int __glXVForwardAllWithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 8; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardAllWithReply( cl, pc ) ); -} - +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED */ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxfont.h" + +#undef Xmalloc +#undef Xcalloc +#undef Xrealloc +#undef Xfree + +#include "glxserver.h" +#include "glxext.h" +#include "g_disptab.h" +/* #include "g_disptab_EXT.h" */ +#include "unpack.h" +#include "glxutil.h" + +#include "GL/glxproto.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +/* + * GetReqVendorPrivate - this is the equivalent of GetReq macro + * from Xlibint.h but it does not set the reqType field (the opcode). + * this is because the GL single opcodes has different naming convension + * the other X opcodes (ie. X_GLsop_GetFloatv). + */ +#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) +#define GetReqVendorPrivate(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(x##name##Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ + req->length = (SIZEOF(x##name##Req))>>2;\ + dpy->bufptr += SIZEOF(x##name##Req);\ + dpy->request++ + +#else /* non-ANSI C uses empty comment instead of "##" for token concatenation */ +#define GetReqVendorPrivate(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(x/**/name/**/Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ + req->length = (SIZEOF(x/**/name/**/Req))>>2;\ + dpy->bufptr += SIZEOF(x/**/name/**/Req);\ + dpy->request++ +#endif + +extern Display *GetBackEndDisplay( __GLXclientState *cl, int s ); +extern int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s); + +static int swap_vec_element_size = 0; + +static void SendSwappedReply( ClientPtr client, + xGLXVendorPrivReply *reply, + char *buf, + int buf_size ) +{ + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_SHORT(&reply->sequenceNumber); + __GLX_SWAP_INT(&reply->length); + __GLX_SWAP_INT(&reply->retval); + __GLX_SWAP_INT(&reply->size); + + if ( (buf_size == 0) && (swap_vec_element_size > 0) ) { + /* + * the reply has single component - need to swap pad3 + */ + if (swap_vec_element_size == 2) { + __GLX_SWAP_SHORT(&reply->pad3); + } + else if (swap_vec_element_size == 4) { + __GLX_SWAP_INT(&reply->pad3); + __GLX_SWAP_INT(&reply->pad4); + } + else if (swap_vec_element_size == 8) { + __GLX_SWAP_DOUBLE(&reply->pad3); + } + } + else if ( (buf_size > 0) && (swap_vec_element_size > 0) ) { + /* + * the reply has vector of elements which needs to be swapped + */ + int vsize = buf_size / swap_vec_element_size; + char *p = buf; + int i; + + for (i=0; i<vsize; i++) { + if (swap_vec_element_size == 2) { + __GLX_SWAP_SHORT(p); + } + else if (swap_vec_element_size == 4) { + __GLX_SWAP_INT(p); + } + else if (swap_vec_element_size == 8) { + __GLX_SWAP_DOUBLE(p); + } + + p += swap_vec_element_size; + } + + __GLX_SWAP_INT(&reply->pad3); + __GLX_SWAP_INT(&reply->pad4); + __GLX_SWAP_INT(&reply->pad5); + __GLX_SWAP_INT(&reply->pad6); + + } + + WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)reply); + if (buf_size > 0) + WriteToClient(client, buf_size, (char *)buf); + +} + +int __glXVForwardSingleReq( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + xGLXVendorPrivateReq *be_req; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int buf_size; + int s; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXVendorPrivateReq; + buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; + + /* + * just forward the request to back-end server(s) + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReqVendorPrivate(GLXVendorPrivate,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->vendorCode = req->vendorCode; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +int __glXVForwardPipe0WithReply( __GLXclientState *cl, GLbyte *pc ) +{ + ClientPtr client = cl->client; + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + xGLXVendorPrivateReq *be_req; + xGLXVendorPrivReply reply; + xGLXVendorPrivReply be_reply; + __GLXcontext *glxc; + int buf_size; + char *be_buf; + int be_buf_size; + DMXScreenInfo *dmxScreen; + Display *dpy; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return __glXBadContext; + } + + pc += sz_xGLXVendorPrivateReq; + buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; + + dmxScreen = &dmxScreens[glxc->pScreen->myNum]; + dpy = GetBackEndDisplay(cl, glxc->pScreen->myNum); + + /* + * send the request to the first back-end server + */ + LockDisplay(dpy); + GetReqVendorPrivate(GLXVendorPrivate,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->vendorCode = req->vendorCode; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag, glxc->pScreen->myNum); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + + /* + * get the reply from the back-end server + */ + _XReply(dpy, (xReply*) &be_reply, 0, False); + be_buf_size = be_reply.length << 2; + if (be_buf_size > 0) { + be_buf = (char *)malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + /* + * send the reply to the client + */ + memcpy( &reply, &be_reply, sz_xGLXVendorPrivReply ); + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + SendSwappedReply( client, &reply, be_buf, be_buf_size ); + } + else { + WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)&reply); + if (be_buf_size > 0) + WriteToClient(client, be_buf_size, (char *)be_buf); + } + + if (be_buf_size > 0) Xfree(be_buf); + + return Success; +} + +int __glXVForwardAllWithReply( __GLXclientState *cl, GLbyte *pc ) +{ + ClientPtr client = cl->client; + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + xGLXVendorPrivateReq *be_req; + xGLXVendorPrivReply reply; + xGLXVendorPrivReply be_reply; + __GLXcontext *glxc; + int buf_size; + char *be_buf; + int be_buf_size; + int from_screen = 0; + int to_screen = 0; + int s; + + DMXScreenInfo *dmxScreen; + Display *dpy; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXVendorPrivateReq; + buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; + + /* + * send the request to the first back-end server(s) + */ + for (s=to_screen; s>=from_screen; s--) { + dmxScreen = &dmxScreens[s]; + dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReqVendorPrivate(GLXVendorPrivate,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->vendorCode = req->vendorCode; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + + /* + * get the reply from the back-end server + */ + _XReply(dpy, (xReply*) &be_reply, 0, False); + be_buf_size = be_reply.length << 2; + if (be_buf_size > 0) { + be_buf = (char *)malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + if (s > from_screen && be_buf_size > 0) { + Xfree(be_buf); + } + } + + /* + * send the reply to the client + */ + memcpy( &reply, &be_reply, sz_xGLXVendorPrivReply ); + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + SendSwappedReply( client, &reply, be_buf, be_buf_size ); + } + else { + WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)&reply); + if (be_buf_size > 0) + WriteToClient(client, be_buf_size, (char *)be_buf); + } + + if (be_buf_size > 0) Xfree(be_buf); + + return Success; +} + +int __glXVForwardSingleReqSwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + return( __glXVForwardSingleReq( cl, pc ) ); +} + +int __glXVForwardPipe0WithReplySwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardPipe0WithReply( cl, pc ) ); +} + +int __glXVForwardPipe0WithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 2; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardPipe0WithReply( cl, pc ) ); +} + +int __glXVForwardPipe0WithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 4; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardPipe0WithReply( cl, pc ) ); +} + +int __glXVForwardPipe0WithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 8; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardPipe0WithReply( cl, pc ) ); +} + +int __glXVForwardAllWithReplySwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardAllWithReply( cl, pc ) ); +} + +int __glXVForwardAllWithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 2; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardAllWithReply( cl, pc ) ); +} + +int __glXVForwardAllWithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 4; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardAllWithReply( cl, pc ) ); +} + +int __glXVForwardAllWithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 8; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardAllWithReply( cl, pc ) ); +} + diff --git a/xorg-server/hw/dmx/glxProxy/glxvisuals.c b/xorg-server/hw/dmx/glxProxy/glxvisuals.c index 898c6be7b..6e30b4edc 100644 --- a/xorg-server/hw/dmx/glxProxy/glxvisuals.c +++ b/xorg-server/hw/dmx/glxProxy/glxvisuals.c @@ -1,539 +1,539 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include <assert.h> -#include "dmx.h" -#include "glxserver.h" -#include "glxutil.h" -#include "dmx_glxvisuals.h" -#include <stdlib.h> - -static int numConfigs = 0; -static __GLXvisualConfig *visualConfigs = NULL; -static void **visualPrivates = NULL; - -int glxVisualsMatch( __GLXvisualConfig *v1, __GLXvisualConfig *v2 ) -{ - if ( (v1->class == v2->class) && - (v1->rgba == v2->rgba) && - (v1->redSize == v2->redSize) && - (v1->greenSize == v2->greenSize) && - (v1->blueSize == v2->blueSize) && - (v1->alphaSize == v2->alphaSize) && - (v1->redMask == v2->redMask) && - (v1->greenMask == v2->greenMask) && - (v1->blueMask == v2->blueMask) && - (v1->alphaMask == v2->alphaMask) && - (v1->accumRedSize == v2->accumRedSize) && - (v1->accumGreenSize == v2->accumGreenSize) && - (v1->accumBlueSize == v2->accumBlueSize) && - (v1->accumAlphaSize == v2->accumAlphaSize) && - (v1->doubleBuffer == v2->doubleBuffer) && - (v1->stereo == v2->stereo) && - (v1->bufferSize == v2->bufferSize) && - (v1->depthSize == v2->depthSize) && - (v1->stencilSize == v2->stencilSize) && - (v1->auxBuffers == v2->auxBuffers) && - (v1->level == v2->level) && - (v1->visualRating == v2->visualRating) && - (v1->transparentPixel == v2->transparentPixel) && - (v1->transparentRed == v2->transparentRed) && - (v1->transparentGreen == v2->transparentGreen) && - (v1->transparentBlue == v2->transparentBlue) && - (v1->transparentAlpha == v2->transparentAlpha) && - (v1->transparentIndex == v2->transparentIndex) && - (v1->multiSampleSize == v2->multiSampleSize) && - (v1->nMultiSampleBuffers == v2->nMultiSampleBuffers) && - (v1->visualSelectGroup == v2->visualSelectGroup) ) { - - return(1); - - } - - return(0); - -} - -VisualID glxMatchGLXVisualInConfigList( __GLXvisualConfig *pGlxVisual, __GLXvisualConfig *configs, int nconfigs ) -{ - int i; - - for (i=0; i<nconfigs; i++) { - - if (glxVisualsMatch( pGlxVisual, &configs[i] )) { - - return( configs[i].vid ); - - } - } - - return(0); -} - -VisualID glxMatchVisualInConfigList( ScreenPtr pScreen, VisualPtr pVisual, __GLXvisualConfig *configs, int nconfigs ) -{ - __GLXscreenInfo *pGlxScreen; - __GLXvisualConfig *pGlxVisual; - int i; - - /* check that the glx extension has been initialized */ - if ( !__glXActiveScreens ) - return(0); - - pGlxScreen = &__glXActiveScreens[pScreen->myNum]; - pGlxVisual = pGlxScreen->pGlxVisual; - - /* find the glx visual info for pVisual */ - for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { - if (pGlxVisual->vid == pVisual->vid) { - break; - } - } - if (i == pGlxScreen->numVisuals) { - /* - * the visual is not supported by glx - */ - return(0); - } - - return( glxMatchGLXVisualInConfigList(pGlxVisual, configs, nconfigs) ); -} - -VisualPtr glxMatchVisual( ScreenPtr pScreen, VisualPtr pVisual, ScreenPtr pMatchScreen ) -{ - __GLXscreenInfo *pGlxScreen2; - int j; - VisualID vid; - - /* check that the glx extension has been initialized */ - if ( !__glXActiveScreens ) - return NULL; - - pGlxScreen2 = &__glXActiveScreens[pMatchScreen->myNum]; - - vid = glxMatchVisualInConfigList( pScreen, pVisual, - pGlxScreen2->pGlxVisual, - pGlxScreen2->numVisuals ); - if (vid) { - /* - * find the X visual of the matching glx visual - */ - for (j=0; j<pMatchScreen->numVisuals; j++) { - if (vid == pMatchScreen->visuals[j].vid) { - return( &pMatchScreen->visuals[j] ); - } - } - } - - return(0); -} - -void glxSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, - void **privates) -{ - numConfigs = nconfigs; - visualConfigs = configs; - visualPrivates = privates; -} - -static int count_bits(unsigned int n) -{ - int bits = 0; - - while (n > 0) { - if (n & 1) bits++; - n >>= 1; - } - return bits; -} - -static VisualID FindClosestVisual( VisualPtr pVisual, int rootDepth, - DepthPtr pdepth, int ndepths, - VisualPtr pNewVisual, int numNewVisuals) -{ - int d, v; - VisualPtr vis; - - /* - * find the first visual with the same or deeper depth - * of the same class. - */ - for (d=0; d<ndepths; d++) { - if (pdepth[d].depth >= rootDepth) { - for (v=0; v<pdepth[d].numVids; v++) { - - /* find the new visual structure */ - vis = pNewVisual; - while( pdepth[d].vids[v] != vis->vid ) vis++; - - if (vis->class == pVisual->class) { - return( pdepth[d].vids[v] ); - } - } - } - } - - /* - * did not find any. - * try to look for the same class only. - */ - for (d=0; d<ndepths; d++) { - for (v=0; v<pdepth[d].numVids; v++) { - - /* find the new visual structure */ - vis = pNewVisual; - while( pdepth[d].vids[v] != vis->vid ) vis++; - - if (vis->class == pVisual->class) { - return( pdepth[d].vids[v] ); - } - } - } - - /* - * if not found - just take the first visual - */ - return( pdepth[0].vids[0] ); -} - -Bool glxInitVisuals(int *nvisualp, VisualPtr *visualp, - VisualID *defaultVisp, - int ndepth, DepthPtr pdepth, - int rootDepth) -{ - int numRGBconfigs; - int numCIconfigs; - int numVisuals = *nvisualp; - int numNewVisuals; - int numNewConfigs; - VisualPtr pVisual = *visualp; - VisualPtr pVisualNew = NULL; - VisualID *orig_vid = NULL; - __GLXvisualConfig *glXVisualPtr = NULL; - __GLXvisualConfig *pNewVisualConfigs = NULL; - void **glXVisualPriv; - dmxGlxVisualPrivate **pNewVisualPriv; - int found_default; - int i, j, k; - int numGLXvis = 0; - GLint *isGLXvis; - - if (numConfigs > 0) - numNewConfigs = numConfigs; - else - return False; - - MAXSCREENSALLOC(__glXActiveScreens); - if (!__glXActiveScreens) - return False; - - /* Alloc space for the list of new GLX visuals */ - pNewVisualConfigs = (__GLXvisualConfig *) - __glXMalloc(numNewConfigs * sizeof(__GLXvisualConfig)); - if (!pNewVisualConfigs) { - return FALSE; - } - - /* Alloc space for the list of new GLX visual privates */ - pNewVisualPriv = (dmxGlxVisualPrivate **) __glXMalloc(numNewConfigs * sizeof(dmxGlxVisualPrivate *)); - if (!pNewVisualPriv) { - __glXFree(pNewVisualConfigs); - return FALSE; - } - - /* copy driver's visual config info */ - for (i = 0; i < numConfigs; i++) { - pNewVisualConfigs[i] = visualConfigs[i]; - pNewVisualPriv[i] = (dmxGlxVisualPrivate *)visualPrivates[i]; - } - -#if 1 - /* FIXME: This is a hack to workaround a hang in xtest caused by a - * mismatch between what the front end (i.e., DMX) server calculates - * for the visual configs and what the back-end servers have. - */ - { - int numTCRGBconfigs = 0; - int numDCRGBconfigs = 0; - - numRGBconfigs = 0; - numCIconfigs = 0; - - for (i = 0; i < numNewConfigs; i++) { - if (pNewVisualConfigs[i].rgba) { - if (pNewVisualConfigs[i].class == TrueColor) - numTCRGBconfigs++; - else - numDCRGBconfigs++; - numRGBconfigs++; - } else - numCIconfigs++; - } - - /* Count the total number of visuals to compute */ - numNewVisuals = 0; - for (i = 0; i < numVisuals; i++) { - numNewVisuals += - (pVisual[i].class == TrueColor) ? numTCRGBconfigs : - (pVisual[i].class == DirectColor) ? numDCRGBconfigs : - numCIconfigs; - } - } -#else - /* Count the number of RGB and CI visual configs */ - numRGBconfigs = 0; - numCIconfigs = 0; - for (i = 0; i < numNewConfigs; i++) { - if (pNewVisualConfigs[i].rgba) - numRGBconfigs++; - else - numCIconfigs++; - } - - /* Count the total number of visuals to compute */ - numNewVisuals = 0; - for (i = 0; i < numVisuals; i++) { - numNewVisuals += - (pVisual[i].class == TrueColor || pVisual[i].class == DirectColor) - ? numRGBconfigs : numCIconfigs; - } -#endif - - /* Reset variables for use with the next screen/driver's visual configs */ - visualConfigs = NULL; - numConfigs = 0; - - /* Alloc temp space for the list of orig VisualIDs for each new visual */ - orig_vid = (VisualID *)__glXMalloc(numNewVisuals * sizeof(VisualID)); - if (!orig_vid) { - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - return FALSE; - } - - /* Alloc space for the list of glXVisuals */ - glXVisualPtr = (__GLXvisualConfig *)__glXMalloc(numNewVisuals * - sizeof(__GLXvisualConfig)); - if (!glXVisualPtr) { - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - return FALSE; - } - - /* Alloc space for the list of glXVisualPrivates */ - glXVisualPriv = (void **)__glXMalloc(numNewVisuals * sizeof(void *)); - if (!glXVisualPriv) { - __glXFree(glXVisualPtr); - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - return FALSE; - } - - /* Alloc space for the new list of the X server's visuals */ - pVisualNew = (VisualPtr)__glXMalloc(numNewVisuals * sizeof(VisualRec)); - if (!pVisualNew) { - __glXFree(glXVisualPriv); - __glXFree(glXVisualPtr); - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - return FALSE; - } - - isGLXvis = (GLint *) __glXMalloc(numNewVisuals * sizeof(GLint)); - if (!isGLXvis) { - __glXFree(glXVisualPriv); - __glXFree(glXVisualPtr); - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - __glXFree(pVisualNew); - return FALSE; - } - - /* Initialize the new visuals */ - found_default = FALSE; - for (i = j = 0; i < numVisuals; i++) { - - for (k = 0; k < numNewConfigs; k++) { - - int new_depth; - int depth; - int d,v; - - /* find the depth of the new visual config */ - new_depth = pNewVisualPriv[k]->x_visual_depth; - - /* find the depth of the original visual */ - depth = 0; - d = 0; - while( (depth==0) && (d < ndepth) ) { - v = 0; - while( (depth==0) && (v < pdepth[d].numVids) ) { - if (pdepth[d].vids[v] == pVisual[i].vid) { - depth = pdepth[d].depth; - } - v++; - } - d++; - } - - /* check that the visual has the same class and depth - * as the new config - */ - if ( pVisual[i].class != pNewVisualPriv[k]->x_visual_class || - (depth != new_depth) ) - continue; - - /* Initialize the new visual */ - pVisualNew[j] = pVisual[i]; - pVisualNew[j].vid = FakeClientID(0); - - /* Check for the default visual */ - if (!found_default && pVisual[i].vid == *defaultVisp) { - *defaultVisp = pVisualNew[j].vid; - found_default = TRUE; - } - - /* Save the old VisualID */ - orig_vid[j] = pVisual[i].vid; - - /* Initialize the glXVisual */ - glXVisualPtr[j] = pNewVisualConfigs[k]; - glXVisualPtr[j].vid = pVisualNew[j].vid; - - /* - * If the class is -1, then assume the X visual information - * is identical to what GLX needs, and take them from the X - * visual. NOTE: if class != -1, then all other fields MUST - * be initialized. - */ - if (glXVisualPtr[j].class == -1) { - glXVisualPtr[j].class = pVisual[i].class; - glXVisualPtr[j].redSize = count_bits(pVisual[i].redMask); - glXVisualPtr[j].greenSize = count_bits(pVisual[i].greenMask); - glXVisualPtr[j].blueSize = count_bits(pVisual[i].blueMask); - glXVisualPtr[j].alphaSize = glXVisualPtr[j].alphaSize; - glXVisualPtr[j].redMask = pVisual[i].redMask; - glXVisualPtr[j].greenMask = pVisual[i].greenMask; - glXVisualPtr[j].blueMask = pVisual[i].blueMask; - glXVisualPtr[j].alphaMask = glXVisualPtr[j].alphaMask; - glXVisualPtr[j].bufferSize = rootDepth; - } - - /* Save the device-dependent private for this visual */ - glXVisualPriv[j] = pNewVisualPriv[k]; - - isGLXvis[j] = glxMatchGLXVisualInConfigList( &glXVisualPtr[j], - dmxScreens[screenInfo.numScreens-1].glxVisuals, - dmxScreens[screenInfo.numScreens-1].numGlxVisuals ); - if (isGLXvis[j]) numGLXvis++; - - j++; - } - } - - assert(j <= numNewVisuals); - numNewVisuals = j; /* correct number of new visuals */ - - /* Save the GLX visuals in the screen structure */ - __glXActiveScreens[screenInfo.numScreens-1].numVisuals = numNewVisuals; - __glXActiveScreens[screenInfo.numScreens-1].numGLXVisuals = numGLXvis; - __glXActiveScreens[screenInfo.numScreens-1].isGLXvis = isGLXvis; - __glXActiveScreens[screenInfo.numScreens-1].pGlxVisual = glXVisualPtr; - - - /* Set up depth's VisualIDs */ - for (i = 0; i < ndepth; i++) { - int numVids = 0; - VisualID *pVids = NULL; - int k, n = 0; - - /* Count the new number of VisualIDs at this depth */ - for (j = 0; j < pdepth[i].numVids; j++) - for (k = 0; k < numNewVisuals; k++) - if (pdepth[i].vids[j] == orig_vid[k]) - numVids++; - - /* Allocate a new list of VisualIDs for this depth */ - pVids = (VisualID *)__glXMalloc(numVids * sizeof(VisualID)); - - /* Initialize the new list of VisualIDs for this depth */ - for (j = 0; j < pdepth[i].numVids; j++) - for (k = 0; k < numNewVisuals; k++) - if (pdepth[i].vids[j] == orig_vid[k]) - pVids[n++] = pVisualNew[k].vid; - - /* Update this depth's list of VisualIDs */ - __glXFree(pdepth[i].vids); - pdepth[i].vids = pVids; - pdepth[i].numVids = numVids; - } - - /* - * if the default visual was rejected - need to choose new - * default visual ! - */ - if ( !found_default ) { - - for (i=0; i<numVisuals; i++) - if (pVisual[i].vid == *defaultVisp) - break; - - if (i < numVisuals) { - *defaultVisp = FindClosestVisual( &pVisual[i], rootDepth, pdepth, ndepth, pVisualNew, numNewVisuals ); - } - } - - /* Update the X server's visuals */ - *nvisualp = numNewVisuals; - *visualp = pVisualNew; - - /* Free the old list of the X server's visuals */ - __glXFree(pVisual); - - /* Clean up temporary allocations */ - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - - /* Free the private list created by DDX HW driver */ - if (visualPrivates) - xfree(visualPrivates); - visualPrivates = NULL; - - return TRUE; -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include <assert.h> +#include "dmx.h" +#include "glxserver.h" +#include "glxutil.h" +#include "dmx_glxvisuals.h" +#include <stdlib.h> + +static int numConfigs = 0; +static __GLXvisualConfig *visualConfigs = NULL; +static void **visualPrivates = NULL; + +int glxVisualsMatch( __GLXvisualConfig *v1, __GLXvisualConfig *v2 ) +{ + if ( (v1->class == v2->class) && + (v1->rgba == v2->rgba) && + (v1->redSize == v2->redSize) && + (v1->greenSize == v2->greenSize) && + (v1->blueSize == v2->blueSize) && + (v1->alphaSize == v2->alphaSize) && + (v1->redMask == v2->redMask) && + (v1->greenMask == v2->greenMask) && + (v1->blueMask == v2->blueMask) && + (v1->alphaMask == v2->alphaMask) && + (v1->accumRedSize == v2->accumRedSize) && + (v1->accumGreenSize == v2->accumGreenSize) && + (v1->accumBlueSize == v2->accumBlueSize) && + (v1->accumAlphaSize == v2->accumAlphaSize) && + (v1->doubleBuffer == v2->doubleBuffer) && + (v1->stereo == v2->stereo) && + (v1->bufferSize == v2->bufferSize) && + (v1->depthSize == v2->depthSize) && + (v1->stencilSize == v2->stencilSize) && + (v1->auxBuffers == v2->auxBuffers) && + (v1->level == v2->level) && + (v1->visualRating == v2->visualRating) && + (v1->transparentPixel == v2->transparentPixel) && + (v1->transparentRed == v2->transparentRed) && + (v1->transparentGreen == v2->transparentGreen) && + (v1->transparentBlue == v2->transparentBlue) && + (v1->transparentAlpha == v2->transparentAlpha) && + (v1->transparentIndex == v2->transparentIndex) && + (v1->multiSampleSize == v2->multiSampleSize) && + (v1->nMultiSampleBuffers == v2->nMultiSampleBuffers) && + (v1->visualSelectGroup == v2->visualSelectGroup) ) { + + return(1); + + } + + return(0); + +} + +VisualID glxMatchGLXVisualInConfigList( __GLXvisualConfig *pGlxVisual, __GLXvisualConfig *configs, int nconfigs ) +{ + int i; + + for (i=0; i<nconfigs; i++) { + + if (glxVisualsMatch( pGlxVisual, &configs[i] )) { + + return( configs[i].vid ); + + } + } + + return(0); +} + +VisualID glxMatchVisualInConfigList( ScreenPtr pScreen, VisualPtr pVisual, __GLXvisualConfig *configs, int nconfigs ) +{ + __GLXscreenInfo *pGlxScreen; + __GLXvisualConfig *pGlxVisual; + int i; + + /* check that the glx extension has been initialized */ + if ( !__glXActiveScreens ) + return(0); + + pGlxScreen = &__glXActiveScreens[pScreen->myNum]; + pGlxVisual = pGlxScreen->pGlxVisual; + + /* find the glx visual info for pVisual */ + for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { + if (pGlxVisual->vid == pVisual->vid) { + break; + } + } + if (i == pGlxScreen->numVisuals) { + /* + * the visual is not supported by glx + */ + return(0); + } + + return( glxMatchGLXVisualInConfigList(pGlxVisual, configs, nconfigs) ); +} + +VisualPtr glxMatchVisual( ScreenPtr pScreen, VisualPtr pVisual, ScreenPtr pMatchScreen ) +{ + __GLXscreenInfo *pGlxScreen2; + int j; + VisualID vid; + + /* check that the glx extension has been initialized */ + if ( !__glXActiveScreens ) + return NULL; + + pGlxScreen2 = &__glXActiveScreens[pMatchScreen->myNum]; + + vid = glxMatchVisualInConfigList( pScreen, pVisual, + pGlxScreen2->pGlxVisual, + pGlxScreen2->numVisuals ); + if (vid) { + /* + * find the X visual of the matching glx visual + */ + for (j=0; j<pMatchScreen->numVisuals; j++) { + if (vid == pMatchScreen->visuals[j].vid) { + return( &pMatchScreen->visuals[j] ); + } + } + } + + return(0); +} + +void glxSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **privates) +{ + numConfigs = nconfigs; + visualConfigs = configs; + visualPrivates = privates; +} + +static int count_bits(unsigned int n) +{ + int bits = 0; + + while (n > 0) { + if (n & 1) bits++; + n >>= 1; + } + return bits; +} + +static VisualID FindClosestVisual( VisualPtr pVisual, int rootDepth, + DepthPtr pdepth, int ndepths, + VisualPtr pNewVisual, int numNewVisuals) +{ + int d, v; + VisualPtr vis; + + /* + * find the first visual with the same or deeper depth + * of the same class. + */ + for (d=0; d<ndepths; d++) { + if (pdepth[d].depth >= rootDepth) { + for (v=0; v<pdepth[d].numVids; v++) { + + /* find the new visual structure */ + vis = pNewVisual; + while( pdepth[d].vids[v] != vis->vid ) vis++; + + if (vis->class == pVisual->class) { + return( pdepth[d].vids[v] ); + } + } + } + } + + /* + * did not find any. + * try to look for the same class only. + */ + for (d=0; d<ndepths; d++) { + for (v=0; v<pdepth[d].numVids; v++) { + + /* find the new visual structure */ + vis = pNewVisual; + while( pdepth[d].vids[v] != vis->vid ) vis++; + + if (vis->class == pVisual->class) { + return( pdepth[d].vids[v] ); + } + } + } + + /* + * if not found - just take the first visual + */ + return( pdepth[0].vids[0] ); +} + +Bool glxInitVisuals(int *nvisualp, VisualPtr *visualp, + VisualID *defaultVisp, + int ndepth, DepthPtr pdepth, + int rootDepth) +{ + int numRGBconfigs; + int numCIconfigs; + int numVisuals = *nvisualp; + int numNewVisuals; + int numNewConfigs; + VisualPtr pVisual = *visualp; + VisualPtr pVisualNew = NULL; + VisualID *orig_vid = NULL; + __GLXvisualConfig *glXVisualPtr = NULL; + __GLXvisualConfig *pNewVisualConfigs = NULL; + void **glXVisualPriv; + dmxGlxVisualPrivate **pNewVisualPriv; + int found_default; + int i, j, k; + int numGLXvis = 0; + GLint *isGLXvis; + + if (numConfigs > 0) + numNewConfigs = numConfigs; + else + return False; + + MAXSCREENSALLOC(__glXActiveScreens); + if (!__glXActiveScreens) + return False; + + /* Alloc space for the list of new GLX visuals */ + pNewVisualConfigs = (__GLXvisualConfig *) + __glXMalloc(numNewConfigs * sizeof(__GLXvisualConfig)); + if (!pNewVisualConfigs) { + return FALSE; + } + + /* Alloc space for the list of new GLX visual privates */ + pNewVisualPriv = (dmxGlxVisualPrivate **) __glXMalloc(numNewConfigs * sizeof(dmxGlxVisualPrivate *)); + if (!pNewVisualPriv) { + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* copy driver's visual config info */ + for (i = 0; i < numConfigs; i++) { + pNewVisualConfigs[i] = visualConfigs[i]; + pNewVisualPriv[i] = (dmxGlxVisualPrivate *)visualPrivates[i]; + } + +#if 1 + /* FIXME: This is a hack to workaround a hang in xtest caused by a + * mismatch between what the front end (i.e., DMX) server calculates + * for the visual configs and what the back-end servers have. + */ + { + int numTCRGBconfigs = 0; + int numDCRGBconfigs = 0; + + numRGBconfigs = 0; + numCIconfigs = 0; + + for (i = 0; i < numNewConfigs; i++) { + if (pNewVisualConfigs[i].rgba) { + if (pNewVisualConfigs[i].class == TrueColor) + numTCRGBconfigs++; + else + numDCRGBconfigs++; + numRGBconfigs++; + } else + numCIconfigs++; + } + + /* Count the total number of visuals to compute */ + numNewVisuals = 0; + for (i = 0; i < numVisuals; i++) { + numNewVisuals += + (pVisual[i].class == TrueColor) ? numTCRGBconfigs : + (pVisual[i].class == DirectColor) ? numDCRGBconfigs : + numCIconfigs; + } + } +#else + /* Count the number of RGB and CI visual configs */ + numRGBconfigs = 0; + numCIconfigs = 0; + for (i = 0; i < numNewConfigs; i++) { + if (pNewVisualConfigs[i].rgba) + numRGBconfigs++; + else + numCIconfigs++; + } + + /* Count the total number of visuals to compute */ + numNewVisuals = 0; + for (i = 0; i < numVisuals; i++) { + numNewVisuals += + (pVisual[i].class == TrueColor || pVisual[i].class == DirectColor) + ? numRGBconfigs : numCIconfigs; + } +#endif + + /* Reset variables for use with the next screen/driver's visual configs */ + visualConfigs = NULL; + numConfigs = 0; + + /* Alloc temp space for the list of orig VisualIDs for each new visual */ + orig_vid = (VisualID *)__glXMalloc(numNewVisuals * sizeof(VisualID)); + if (!orig_vid) { + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the list of glXVisuals */ + glXVisualPtr = (__GLXvisualConfig *)__glXMalloc(numNewVisuals * + sizeof(__GLXvisualConfig)); + if (!glXVisualPtr) { + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the list of glXVisualPrivates */ + glXVisualPriv = (void **)__glXMalloc(numNewVisuals * sizeof(void *)); + if (!glXVisualPriv) { + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the new list of the X server's visuals */ + pVisualNew = (VisualPtr)__glXMalloc(numNewVisuals * sizeof(VisualRec)); + if (!pVisualNew) { + __glXFree(glXVisualPriv); + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + isGLXvis = (GLint *) __glXMalloc(numNewVisuals * sizeof(GLint)); + if (!isGLXvis) { + __glXFree(glXVisualPriv); + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + __glXFree(pVisualNew); + return FALSE; + } + + /* Initialize the new visuals */ + found_default = FALSE; + for (i = j = 0; i < numVisuals; i++) { + + for (k = 0; k < numNewConfigs; k++) { + + int new_depth; + int depth; + int d,v; + + /* find the depth of the new visual config */ + new_depth = pNewVisualPriv[k]->x_visual_depth; + + /* find the depth of the original visual */ + depth = 0; + d = 0; + while( (depth==0) && (d < ndepth) ) { + v = 0; + while( (depth==0) && (v < pdepth[d].numVids) ) { + if (pdepth[d].vids[v] == pVisual[i].vid) { + depth = pdepth[d].depth; + } + v++; + } + d++; + } + + /* check that the visual has the same class and depth + * as the new config + */ + if ( pVisual[i].class != pNewVisualPriv[k]->x_visual_class || + (depth != new_depth) ) + continue; + + /* Initialize the new visual */ + pVisualNew[j] = pVisual[i]; + pVisualNew[j].vid = FakeClientID(0); + + /* Check for the default visual */ + if (!found_default && pVisual[i].vid == *defaultVisp) { + *defaultVisp = pVisualNew[j].vid; + found_default = TRUE; + } + + /* Save the old VisualID */ + orig_vid[j] = pVisual[i].vid; + + /* Initialize the glXVisual */ + glXVisualPtr[j] = pNewVisualConfigs[k]; + glXVisualPtr[j].vid = pVisualNew[j].vid; + + /* + * If the class is -1, then assume the X visual information + * is identical to what GLX needs, and take them from the X + * visual. NOTE: if class != -1, then all other fields MUST + * be initialized. + */ + if (glXVisualPtr[j].class == -1) { + glXVisualPtr[j].class = pVisual[i].class; + glXVisualPtr[j].redSize = count_bits(pVisual[i].redMask); + glXVisualPtr[j].greenSize = count_bits(pVisual[i].greenMask); + glXVisualPtr[j].blueSize = count_bits(pVisual[i].blueMask); + glXVisualPtr[j].alphaSize = glXVisualPtr[j].alphaSize; + glXVisualPtr[j].redMask = pVisual[i].redMask; + glXVisualPtr[j].greenMask = pVisual[i].greenMask; + glXVisualPtr[j].blueMask = pVisual[i].blueMask; + glXVisualPtr[j].alphaMask = glXVisualPtr[j].alphaMask; + glXVisualPtr[j].bufferSize = rootDepth; + } + + /* Save the device-dependent private for this visual */ + glXVisualPriv[j] = pNewVisualPriv[k]; + + isGLXvis[j] = glxMatchGLXVisualInConfigList( &glXVisualPtr[j], + dmxScreens[screenInfo.numScreens-1].glxVisuals, + dmxScreens[screenInfo.numScreens-1].numGlxVisuals ); + if (isGLXvis[j]) numGLXvis++; + + j++; + } + } + + assert(j <= numNewVisuals); + numNewVisuals = j; /* correct number of new visuals */ + + /* Save the GLX visuals in the screen structure */ + __glXActiveScreens[screenInfo.numScreens-1].numVisuals = numNewVisuals; + __glXActiveScreens[screenInfo.numScreens-1].numGLXVisuals = numGLXvis; + __glXActiveScreens[screenInfo.numScreens-1].isGLXvis = isGLXvis; + __glXActiveScreens[screenInfo.numScreens-1].pGlxVisual = glXVisualPtr; + + + /* Set up depth's VisualIDs */ + for (i = 0; i < ndepth; i++) { + int numVids = 0; + VisualID *pVids = NULL; + int k, n = 0; + + /* Count the new number of VisualIDs at this depth */ + for (j = 0; j < pdepth[i].numVids; j++) + for (k = 0; k < numNewVisuals; k++) + if (pdepth[i].vids[j] == orig_vid[k]) + numVids++; + + /* Allocate a new list of VisualIDs for this depth */ + pVids = (VisualID *)__glXMalloc(numVids * sizeof(VisualID)); + + /* Initialize the new list of VisualIDs for this depth */ + for (j = 0; j < pdepth[i].numVids; j++) + for (k = 0; k < numNewVisuals; k++) + if (pdepth[i].vids[j] == orig_vid[k]) + pVids[n++] = pVisualNew[k].vid; + + /* Update this depth's list of VisualIDs */ + __glXFree(pdepth[i].vids); + pdepth[i].vids = pVids; + pdepth[i].numVids = numVids; + } + + /* + * if the default visual was rejected - need to choose new + * default visual ! + */ + if ( !found_default ) { + + for (i=0; i<numVisuals; i++) + if (pVisual[i].vid == *defaultVisp) + break; + + if (i < numVisuals) { + *defaultVisp = FindClosestVisual( &pVisual[i], rootDepth, pdepth, ndepth, pVisualNew, numNewVisuals ); + } + } + + /* Update the X server's visuals */ + *nvisualp = numNewVisuals; + *visualp = pVisualNew; + + /* Free the old list of the X server's visuals */ + __glXFree(pVisual); + + /* Clean up temporary allocations */ + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + + /* Free the private list created by DDX HW driver */ + if (visualPrivates) + free(visualPrivates); + visualPrivates = NULL; + + return TRUE; +} diff --git a/xorg-server/hw/dmx/glxProxy/unpack.h b/xorg-server/hw/dmx/glxProxy/unpack.h index 98fa10ee7..73d0485e3 100644 --- a/xorg-server/hw/dmx/glxProxy/unpack.h +++ b/xorg-server/hw/dmx/glxProxy/unpack.h @@ -1,228 +1,228 @@ -#ifndef __GLX_unpack_h__ -#define __GLX_unpack_h__ - -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#define __GLX_PAD(s) (((s)+3) & (GLuint)~3) - -/* -** Fetch the context-id out of a SingleReq request pointed to by pc. -*/ -#define __GLX_GET_SINGLE_CONTEXT_TAG(pc) (((xGLXSingleReq*)pc)->contextTag) -#define __GLX_GET_VENDPRIV_CONTEXT_TAG(pc) (((xGLXVendorPrivateReq*)pc)->contextTag) - -/* -** Fetch a double from potentially unaligned memory. -*/ -#ifdef __GLX_ALIGN64 -#define __GLX_MEM_COPY(dst,src,n) memcpy(dst,src,n) -#define __GLX_GET_DOUBLE(dst,src) __GLX_MEM_COPY(&dst,src,8) -#else -#define __GLX_GET_DOUBLE(dst,src) (dst) = *((GLdouble*)(src)) -#endif - -extern void __glXMemInit(void); - -extern xGLXSingleReply __glXReply; - -#define __GLX_BEGIN_REPLY(size) \ - __glXReply.length = __GLX_PAD(size) >> 2; \ - __glXReply.type = X_Reply; \ - __glXReply.sequenceNumber = client->sequence; - -#define __GLX_SEND_HEADER() \ - WriteToClient( client, sz_xGLXSingleReply, (char *)&__glXReply); - -#define __GLX_PUT_RETVAL(a) \ - __glXReply.retval = (a); - -#define __GLX_PUT_SIZE(a) \ - __glXReply.size = (a); - -#define __GLX_PUT_RENDERMODE(m) \ - __glXReply.pad3 = (m) - -/* -** Get a buffer to hold returned data, with the given alignment. If we have -** to realloc, allocate size+align, in case the pointer has to be bumped for -** alignment. The answerBuffer should already be aligned. -** -** NOTE: the cast (long)res below assumes a long is large enough to hold a -** pointer. -*/ -#define __GLX_GET_ANSWER_BUFFER(res,cl,size,align) \ - if ((size) > sizeof(answerBuffer)) { \ - int bump; \ - if ((cl)->returnBufSize < (size)+(align)) { \ - (cl)->returnBuf = (GLbyte*)Xrealloc((cl)->returnBuf, \ - (size)+(align)); \ - if (!(cl)->returnBuf) { \ - return BadAlloc; \ - } \ - (cl)->returnBufSize = (size)+(align); \ - } \ - res = (char*)cl->returnBuf; \ - bump = (long)(res) % (align); \ - if (bump) res += (align) - (bump); \ - } else { \ - res = (char *)answerBuffer; \ - } - -#define __GLX_PUT_BYTE() \ - *(GLbyte *)&__glXReply.pad3 = *(GLbyte *)answer - -#define __GLX_PUT_SHORT() \ - *(GLshort *)&__glXReply.pad3 = *(GLshort *)answer - -#define __GLX_PUT_INT() \ - *(GLint *)&__glXReply.pad3 = *(GLint *)answer - -#define __GLX_PUT_FLOAT() \ - *(GLfloat *)&__glXReply.pad3 = *(GLfloat *)answer - -#define __GLX_PUT_DOUBLE() \ - *(GLdouble *)&__glXReply.pad3 = *(GLdouble *)answer - -#define __GLX_SEND_BYTE_ARRAY(len) \ - WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT8), (char *)answer) - -#define __GLX_SEND_SHORT_ARRAY(len) \ - WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT16), (char *)answer) - -#define __GLX_SEND_INT_ARRAY(len) \ - WriteToClient(client, (len)*__GLX_SIZE_INT32, (char *)answer) - -#define __GLX_SEND_FLOAT_ARRAY(len) \ - WriteToClient(client, (len)*__GLX_SIZE_FLOAT32, (char *)answer) - -#define __GLX_SEND_DOUBLE_ARRAY(len) \ - WriteToClient(client, (len)*__GLX_SIZE_FLOAT64, (char *)answer) - - -#define __GLX_SEND_VOID_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) -#define __GLX_SEND_UBYTE_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) -#define __GLX_SEND_USHORT_ARRAY(len) __GLX_SEND_SHORT_ARRAY(len) -#define __GLX_SEND_UINT_ARRAY(len) __GLX_SEND_INT_ARRAY(len) - -/* -** PERFORMANCE NOTE: -** Machine dependent optimizations abound here; these swapping macros can -** conceivably be replaced with routines that do the job faster. -*/ -#define __GLX_DECLARE_SWAP_VARIABLES \ - GLbyte sw; \ - GLbyte *swapPC; \ - GLbyte *swapEnd - - -#define __GLX_SWAP_INT(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ - ((GLbyte *)(pc))[3] = sw; \ - sw = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ - ((GLbyte *)(pc))[2] = sw; - -#define __GLX_SWAP_SHORT(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = sw; - -#define __GLX_SWAP_DOUBLE(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[7]; \ - ((GLbyte *)(pc))[7] = sw; \ - sw = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[6]; \ - ((GLbyte *)(pc))[6] = sw; \ - sw = ((GLbyte *)(pc))[2]; \ - ((GLbyte *)(pc))[2] = ((GLbyte *)(pc))[5]; \ - ((GLbyte *)(pc))[5] = sw; \ - sw = ((GLbyte *)(pc))[3]; \ - ((GLbyte *)(pc))[3] = ((GLbyte *)(pc))[4]; \ - ((GLbyte *)(pc))[4] = sw; - -#define __GLX_SWAP_FLOAT(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ - ((GLbyte *)(pc))[3] = sw; \ - sw = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ - ((GLbyte *)(pc))[2] = sw; - -#define __GLX_SWAP_INT_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT32;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_INT(swapPC); \ - swapPC += __GLX_SIZE_INT32; \ - } - -#define __GLX_SWAP_SHORT_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT16;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_SHORT(swapPC); \ - swapPC += __GLX_SIZE_INT16; \ - } - -#define __GLX_SWAP_DOUBLE_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT64;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_DOUBLE(swapPC); \ - swapPC += __GLX_SIZE_FLOAT64; \ - } - -#define __GLX_SWAP_FLOAT_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT32;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_FLOAT(swapPC); \ - swapPC += __GLX_SIZE_FLOAT32; \ - } - -#define __GLX_SWAP_REPLY_HEADER() \ - __GLX_SWAP_SHORT(&__glXReply.sequenceNumber); \ - __GLX_SWAP_INT(&__glXReply.length); - -#define __GLX_SWAP_REPLY_RETVAL() \ - __GLX_SWAP_INT(&__glXReply.retval) - -#define __GLX_SWAP_REPLY_SIZE() \ - __GLX_SWAP_INT(&__glXReply.size) - -#endif /* !__GLX_unpack_h__ */ - - - - - +#ifndef __GLX_unpack_h__ +#define __GLX_unpack_h__ + +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#define __GLX_PAD(s) (((s)+3) & (GLuint)~3) + +/* +** Fetch the context-id out of a SingleReq request pointed to by pc. +*/ +#define __GLX_GET_SINGLE_CONTEXT_TAG(pc) (((xGLXSingleReq*)pc)->contextTag) +#define __GLX_GET_VENDPRIV_CONTEXT_TAG(pc) (((xGLXVendorPrivateReq*)pc)->contextTag) + +/* +** Fetch a double from potentially unaligned memory. +*/ +#ifdef __GLX_ALIGN64 +#define __GLX_MEM_COPY(dst,src,n) memcpy(dst,src,n) +#define __GLX_GET_DOUBLE(dst,src) __GLX_MEM_COPY(&dst,src,8) +#else +#define __GLX_GET_DOUBLE(dst,src) (dst) = *((GLdouble*)(src)) +#endif + +extern void __glXMemInit(void); + +extern xGLXSingleReply __glXReply; + +#define __GLX_BEGIN_REPLY(size) \ + __glXReply.length = __GLX_PAD(size) >> 2; \ + __glXReply.type = X_Reply; \ + __glXReply.sequenceNumber = client->sequence; + +#define __GLX_SEND_HEADER() \ + WriteToClient( client, sz_xGLXSingleReply, (char *)&__glXReply); + +#define __GLX_PUT_RETVAL(a) \ + __glXReply.retval = (a); + +#define __GLX_PUT_SIZE(a) \ + __glXReply.size = (a); + +#define __GLX_PUT_RENDERMODE(m) \ + __glXReply.pad3 = (m) + +/* +** Get a buffer to hold returned data, with the given alignment. If we have +** to realloc, allocate size+align, in case the pointer has to be bumped for +** alignment. The answerBuffer should already be aligned. +** +** NOTE: the cast (long)res below assumes a long is large enough to hold a +** pointer. +*/ +#define __GLX_GET_ANSWER_BUFFER(res,cl,size,align) \ + if ((size) > sizeof(answerBuffer)) { \ + int bump; \ + if ((cl)->returnBufSize < (size)+(align)) { \ + (cl)->returnBuf = (GLbyte*)realloc((cl)->returnBuf, \ + (size)+(align)); \ + if (!(cl)->returnBuf) { \ + return BadAlloc; \ + } \ + (cl)->returnBufSize = (size)+(align); \ + } \ + res = (char*)cl->returnBuf; \ + bump = (long)(res) % (align); \ + if (bump) res += (align) - (bump); \ + } else { \ + res = (char *)answerBuffer; \ + } + +#define __GLX_PUT_BYTE() \ + *(GLbyte *)&__glXReply.pad3 = *(GLbyte *)answer + +#define __GLX_PUT_SHORT() \ + *(GLshort *)&__glXReply.pad3 = *(GLshort *)answer + +#define __GLX_PUT_INT() \ + *(GLint *)&__glXReply.pad3 = *(GLint *)answer + +#define __GLX_PUT_FLOAT() \ + *(GLfloat *)&__glXReply.pad3 = *(GLfloat *)answer + +#define __GLX_PUT_DOUBLE() \ + *(GLdouble *)&__glXReply.pad3 = *(GLdouble *)answer + +#define __GLX_SEND_BYTE_ARRAY(len) \ + WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT8), (char *)answer) + +#define __GLX_SEND_SHORT_ARRAY(len) \ + WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT16), (char *)answer) + +#define __GLX_SEND_INT_ARRAY(len) \ + WriteToClient(client, (len)*__GLX_SIZE_INT32, (char *)answer) + +#define __GLX_SEND_FLOAT_ARRAY(len) \ + WriteToClient(client, (len)*__GLX_SIZE_FLOAT32, (char *)answer) + +#define __GLX_SEND_DOUBLE_ARRAY(len) \ + WriteToClient(client, (len)*__GLX_SIZE_FLOAT64, (char *)answer) + + +#define __GLX_SEND_VOID_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) +#define __GLX_SEND_UBYTE_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) +#define __GLX_SEND_USHORT_ARRAY(len) __GLX_SEND_SHORT_ARRAY(len) +#define __GLX_SEND_UINT_ARRAY(len) __GLX_SEND_INT_ARRAY(len) + +/* +** PERFORMANCE NOTE: +** Machine dependent optimizations abound here; these swapping macros can +** conceivably be replaced with routines that do the job faster. +*/ +#define __GLX_DECLARE_SWAP_VARIABLES \ + GLbyte sw; \ + GLbyte *swapPC; \ + GLbyte *swapEnd + + +#define __GLX_SWAP_INT(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ + ((GLbyte *)(pc))[3] = sw; \ + sw = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ + ((GLbyte *)(pc))[2] = sw; + +#define __GLX_SWAP_SHORT(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = sw; + +#define __GLX_SWAP_DOUBLE(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[7]; \ + ((GLbyte *)(pc))[7] = sw; \ + sw = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[6]; \ + ((GLbyte *)(pc))[6] = sw; \ + sw = ((GLbyte *)(pc))[2]; \ + ((GLbyte *)(pc))[2] = ((GLbyte *)(pc))[5]; \ + ((GLbyte *)(pc))[5] = sw; \ + sw = ((GLbyte *)(pc))[3]; \ + ((GLbyte *)(pc))[3] = ((GLbyte *)(pc))[4]; \ + ((GLbyte *)(pc))[4] = sw; + +#define __GLX_SWAP_FLOAT(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ + ((GLbyte *)(pc))[3] = sw; \ + sw = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ + ((GLbyte *)(pc))[2] = sw; + +#define __GLX_SWAP_INT_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT32;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_INT(swapPC); \ + swapPC += __GLX_SIZE_INT32; \ + } + +#define __GLX_SWAP_SHORT_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT16;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_SHORT(swapPC); \ + swapPC += __GLX_SIZE_INT16; \ + } + +#define __GLX_SWAP_DOUBLE_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT64;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_DOUBLE(swapPC); \ + swapPC += __GLX_SIZE_FLOAT64; \ + } + +#define __GLX_SWAP_FLOAT_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT32;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_FLOAT(swapPC); \ + swapPC += __GLX_SIZE_FLOAT32; \ + } + +#define __GLX_SWAP_REPLY_HEADER() \ + __GLX_SWAP_SHORT(&__glXReply.sequenceNumber); \ + __GLX_SWAP_INT(&__glXReply.length); + +#define __GLX_SWAP_REPLY_RETVAL() \ + __GLX_SWAP_INT(&__glXReply.retval) + +#define __GLX_SWAP_REPLY_SIZE() \ + __GLX_SWAP_INT(&__glXReply.size) + +#endif /* !__GLX_unpack_h__ */ + + + + + diff --git a/xorg-server/hw/dmx/input/dmxinputinit.c b/xorg-server/hw/dmx/input/dmxinputinit.c index 5a486a464..f9acaa039 100644 --- a/xorg-server/hw/dmx/input/dmxinputinit.c +++ b/xorg-server/hw/dmx/input/dmxinputinit.c @@ -1,1311 +1,1311 @@ -/* - * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Rickard E. (Rik) Faith <faith@redhat.com> - * - */ - -/** \file - * This file provides generic input support. Functions here set up - * input and lead to the calling of low-level device drivers for - * input. */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#define DMX_WINDOW_DEBUG 0 - -#include "dmxinputinit.h" -#include "dmxextension.h" /* For dmxInputCount */ - -#include "dmxdummy.h" -#include "dmxbackend.h" -#include "dmxconsole.h" -#include "dmxcommon.h" -#include "dmxevents.h" -#include "dmxmotion.h" -#include "dmxprop.h" -#include "config/dmxconfig.h" -#include "dmxcursor.h" - -#include "lnx-keyboard.h" -#include "lnx-ms.h" -#include "lnx-ps2.h" -#include "usb-keyboard.h" -#include "usb-mouse.h" -#include "usb-other.h" -#include "usb-common.h" - -#include "dmxsigio.h" -#include "dmxarg.h" - -#include "inputstr.h" -#include "input.h" -#include "mipointer.h" -#include "windowstr.h" -#include "mi.h" -#include "xkbsrv.h" - -#include <X11/extensions/XI.h> -#include <X11/extensions/XIproto.h> -#include "exevents.h" -#include "extinit.h" - -DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; - -static DMXLocalInputInfoRec DMXDummyMou = { - "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo -}; - -static DMXLocalInputInfoRec DMXDummyKbd = { - "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo -}; - -static DMXLocalInputInfoRec DMXBackendMou = { - "backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2, - dmxBackendCreatePrivate, dmxBackendDestroyPrivate, - dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo, - dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition, - NULL, NULL, NULL, - dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL, - dmxCommonMouCtrl -}; - -static DMXLocalInputInfoRec DMXBackendKbd = { - "backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND, - 1, /* With backend-mou or console-mou */ - dmxCommonCopyPrivate, NULL, - dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo, - dmxCommonKbdOn, dmxCommonKbdOff, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, dmxCommonKbdCtrl, dmxCommonKbdBell -}; - -static DMXLocalInputInfoRec DMXConsoleMou = { - "console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2, - dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate, - dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo, - dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition, - NULL, NULL, NULL, - dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo, - dmxCommonMouCtrl -}; - -static DMXLocalInputInfoRec DMXConsoleKbd = { - "console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE, - 1, /* With backend-mou or console-mou */ - dmxCommonCopyPrivate, NULL, - dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo, - dmxCommonKbdOn, dmxCommonKbdOff, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, dmxCommonKbdCtrl, dmxCommonKbdBell -}; - -static DMXLocalInputInfoRec DMXCommonOth = { - "common-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_COMMON, 1, - dmxCommonCopyPrivate, NULL, - NULL, NULL, NULL, dmxCommonOthGetInfo, - dmxCommonOthOn, dmxCommonOthOff -}; - - -static DMXLocalInputInfoRec DMXLocalDevices[] = { - /* Dummy drivers that can compile on any OS */ -#ifdef __linux__ - /* Linux-specific drivers */ - { - "kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate, - kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo, - kbdLinuxOn, kbdLinuxOff, NULL, - kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch, - kbdLinuxRead, NULL, NULL, NULL, - NULL, kbdLinuxCtrl, kbdLinuxBell - }, - { - "ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - msLinuxCreatePrivate, msLinuxDestroyPrivate, - msLinuxInit, NULL, NULL, msLinuxGetInfo, - msLinuxOn, msLinuxOff, NULL, - msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL, - msLinuxRead - }, - { - "ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate, - ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo, - ps2LinuxOn, ps2LinuxOff, NULL, - ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL, - ps2LinuxRead - }, -#endif -#ifdef __linux__ - /* USB drivers, currently only for - Linux, but relatively easy to port to - other OSs */ - { - "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - usbCreatePrivate, usbDestroyPrivate, - kbdUSBInit, NULL, NULL, kbdUSBGetInfo, - kbdUSBOn, usbOff, NULL, - NULL, NULL, NULL, - kbdUSBRead, NULL, NULL, NULL, - NULL, kbdUSBCtrl - }, - { - "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - usbCreatePrivate, usbDestroyPrivate, - mouUSBInit, NULL, NULL, mouUSBGetInfo, - mouUSBOn, usbOff, NULL, - NULL, NULL, NULL, - mouUSBRead - }, - { - "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1, - usbCreatePrivate, usbDestroyPrivate, - othUSBInit, NULL, NULL, othUSBGetInfo, - othUSBOn, usbOff, NULL, - NULL, NULL, NULL, - othUSBRead - }, -#endif - { - "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo - }, - { - "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo - }, - { NULL } /* Must be last */ -}; - - -#if 11 /*BP*/ -void -DDXRingBell(int volume, int pitch, int duration) -{ - /* NO-OP */ -} - -/* taken from kdrive/src/kinput.c: */ -static void -dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) -{ -#if 0 - KdKeyboardInfo *ki; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev && ki->dixdev->id == pDevice->id) - break; - } - - if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) - return; - - KdSetLeds(ki, ctrl->leds); - ki->bellPitch = ctrl->bell_pitch; - ki->bellDuration = ctrl->bell_duration; -#endif -} - -/* taken from kdrive/src/kinput.c: */ -static void -dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something) -{ -#if 0 - KeybdCtrl *ctrl = arg; - KdKeyboardInfo *ki = NULL; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev && ki->dixdev->id == pDev->id) - break; - } - - if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) - return; - - KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); -#endif -} - -#endif /*BP*/ - -static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, - PtrCtrl *ctrl) -{ - if (!dmxLocal) return; - dmxLocal->mctrl = *ctrl; - if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl); -} - -/** Change the pointer control information for the \a pDevice. If the - * device sends core events, then also change the control information - * for all of the pointer devices that send core events. */ -void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl) -{ - GETDMXLOCALFROMPDEVICE; - int i, j; - - if (dmxLocal->sendsCore) { /* Do for all core devices */ - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->detached) continue; - for (j = 0; j < dmxInput->numDevs; j++) - if (dmxInput->devs[j]->sendsCore) - _dmxChangePointerControl(dmxInput->devs[j], ctrl); - } - } else { /* Do for this device only */ - _dmxChangePointerControl(dmxLocal, ctrl); - } -} - -static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, - KeybdCtrl *ctrl) -{ - dmxLocal->kctrl = *ctrl; - if (dmxLocal->kCtrl) { - dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl); - if (dmxLocal->pDevice->kbdfeed) { - XkbEventCauseRec cause; - XkbSetCauseUnknown(&cause); - /* Generate XKB events, as necessary */ - XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False, - NULL, &cause); - } - } -} - - -/** Change the keyboard control information for the \a pDevice. If the - * device sends core events, then also change the control information - * for all of the keyboard devices that send core events. */ -void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl) -{ - GETDMXLOCALFROMPDEVICE; - int i, j; - - if (dmxLocal->sendsCore) { /* Do for all core devices */ - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->detached) continue; - for (j = 0; j < dmxInput->numDevs; j++) - if (dmxInput->devs[j]->sendsCore) - _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl); - } - } else { /* Do for this device only */ - _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl); - } -} - -static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent) -{ - if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public, - percent, - dmxLocal->kctrl.bell, - dmxLocal->kctrl.bell_pitch, - dmxLocal->kctrl.bell_duration); -} - -/** Sound the bell on the device. If the device send core events, then - * sound the bell on all of the devices that send core events. */ -void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, - pointer ctrl, int unknown) -{ - GETDMXLOCALFROMPDEVICE; - int i, j; - - if (dmxLocal->sendsCore) { /* Do for all core devices */ - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->detached) continue; - for (j = 0; j < dmxInput->numDevs; j++) - if (dmxInput->devs[j]->sendsCore) - _dmxKeyboardBellProc(dmxInput->devs[j], percent); - } - } else { /* Do for this device only */ - _dmxKeyboardBellProc(dmxLocal, percent); - } -} - -static void dmxKeyboardFreeNames(XkbComponentNamesPtr names) -{ - if (names->keycodes) XFree(names->keycodes); - if (names->types) XFree(names->types); - if (names->compat) XFree(names->compat); - if (names->symbols) XFree(names->symbols); - if (names->geometry) XFree(names->geometry); -} - - -static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info) -{ - GETDMXINPUTFROMPDEVICE; - XkbRMLVOSet rmlvo; - - rmlvo.rules = dmxConfigGetXkbRules(); - rmlvo.model = dmxConfigGetXkbModel(); - rmlvo.layout = dmxConfigGetXkbLayout(); - rmlvo.variant = dmxConfigGetXkbVariant(); - rmlvo.options = dmxConfigGetXkbOptions(); - - XkbSetRulesDflts(&rmlvo); - if (!info->force && (dmxInput->keycodes - || dmxInput->symbols - || dmxInput->geometry)) { - if (info->freenames) dmxKeyboardFreeNames(&info->names); - info->freenames = 0; - info->names.keycodes = dmxInput->keycodes; - info->names.types = NULL; - info->names.compat = NULL; - info->names.symbols = dmxInput->symbols; - info->names.geometry = dmxInput->geometry; - - dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s", - info->names.keycodes); - if (info->names.symbols && *info->names.symbols) - dmxLogInputCont(dmxInput, " %s", info->names.symbols); - if (info->names.geometry && *info->names.geometry) - dmxLogInputCont(dmxInput, " %s", info->names.geometry); - dmxLogInputCont(dmxInput, "\n"); - } else if (info->names.keycodes) { - dmxLogInput(dmxInput, "XKEYBOARD: From device: %s", - info->names.keycodes); - if (info->names.symbols && *info->names.symbols) - dmxLogInputCont(dmxInput, " %s", info->names.symbols); - if (info->names.geometry && *info->names.geometry) - dmxLogInputCont(dmxInput, " %s", info->names.geometry); - dmxLogInputCont(dmxInput, "\n"); - } else { - dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n", - dmxConfigGetXkbRules(), - dmxConfigGetXkbLayout(), - dmxConfigGetXkbModel(), - dmxConfigGetXkbVariant() - ? dmxConfigGetXkbVariant() : "", - dmxConfigGetXkbOptions() - ? dmxConfigGetXkbOptions() : ""); - } - InitKeyboardDeviceStruct(pDevice, &rmlvo, - dmxKeyboardBellProc, - dmxKeyboardKbdCtrlProc); - - if (info->freenames) dmxKeyboardFreeNames(&info->names); - - return Success; -} - - -static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what) -{ - GETDMXINPUTFROMPDEVICE; - int fd; - DMXLocalInitInfo info; - int i; - Atom btn_labels[MAX_BUTTONS] = {0}; /* FIXME */ - Atom axis_labels[MAX_VALUATORS] = {0}; /* FIXME */ - - if (dmxInput->detached) return Success; - - memset(&info, 0, sizeof(info)); - switch (what) { - case DEVICE_INIT: - if (dmxLocal->init) - dmxLocal->init(pDev); - if (dmxLocal->get_info) - dmxLocal->get_info(pDev, &info); - if (info.keyboard) { /* XKEYBOARD makes this a special case */ - dmxKeyboardOn(pDevice, &info); - break; - } - if (info.keyClass) { - XkbRMLVOSet rmlvo; - - rmlvo.rules = dmxConfigGetXkbRules(); - rmlvo.model = dmxConfigGetXkbModel(); - rmlvo.layout = dmxConfigGetXkbLayout(); - rmlvo.variant = dmxConfigGetXkbVariant(); - rmlvo.options = dmxConfigGetXkbOptions(); - - InitKeyboardDeviceStruct(pDevice, - &rmlvo, - dmxBell, dmxKbdCtrl); - } - if (info.buttonClass) { - InitButtonClassDeviceStruct(pDevice, info.numButtons, - btn_labels, info.map); - } - if (info.valuatorClass) { - if (info.numRelAxes && dmxLocal->sendsCore) { - InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, - axis_labels, - GetMaximumEventsNum(), - Relative); - for (i = 0; i < info.numRelAxes; i++) - InitValuatorAxisStruct(pDevice, i, axis_labels[i], - info.minval[i], info.maxval[i], - info.res[i], - info.minres[i], info.maxres[i]); - } else if (info.numRelAxes) { - InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, - axis_labels, - dmxPointerGetMotionBufferSize(), - Relative); - for (i = 0; i < info.numRelAxes; i++) - InitValuatorAxisStruct(pDevice, i, axis_labels[i], - info.minval[i], - info.maxval[i], info.res[i], - info.minres[i], info.maxres[i]); - } else if (info.numAbsAxes) { - InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes, - axis_labels, - dmxPointerGetMotionBufferSize(), - Absolute); - for (i = 0; i < info.numAbsAxes; i++) - InitValuatorAxisStruct(pDevice, i, - axis_labels[i], - info.minval[i], info.maxval[i], - info.res[i], info.minres[i], - info.maxres[i]); - } - } - if (info.focusClass) InitFocusClassDeviceStruct(pDevice); - if (info.proximityClass) InitProximityClassDeviceStruct(pDevice); - if (info.ptrFeedbackClass) - InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl); - if (info.intFeedbackClass || info.strFeedbackClass) - dmxLog(dmxWarning, - "Integer and string feedback not supported for %s\n", - pDevice->name); - if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass)) - dmxLog(dmxWarning, - "Led and bel feedback not supported for non-keyboard %s\n", - pDevice->name); - break; - case DEVICE_ON: - if (!pDev->on) { - if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0) - dmxSigioRegister(dmxInput, fd); - pDev->on = TRUE; - } - break; - case DEVICE_OFF: - case DEVICE_CLOSE: - /* This can get called twice consecutively: once for a - * detached screen (DEVICE_OFF), and then again at server - * generation time (DEVICE_CLOSE). */ - if (pDev->on) { - dmxSigioUnregister(dmxInput); - if (dmxLocal->off) dmxLocal->off(pDev); - pDev->on = FALSE; - } - break; - } - if (info.keySyms.map && info.freemap) { - XFree(info.keySyms.map); - info.keySyms.map = NULL; - } - if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True); - return Success; -} - -static void dmxProcessInputEvents(DMXInputInfo *dmxInput) -{ - int i; - - mieqProcessInputEvents(); -#if 00 /*BP*/ - miPointerUpdate(); -#endif - if (dmxInput->detached) - return; - for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) - if (dmxInput->devs[i]->process_input) { -#if 11 /*BP*/ - miPointerUpdateSprite(dmxInput->devs[i]->pDevice); -#endif - dmxInput->devs[i]->process_input(dmxInput->devs[i]->private); - } - -#if 11 /*BP*/ - mieqProcessInputEvents(); -#endif -} - -static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput, - DMXUpdateType type, - WindowPtr pWindow) -{ - int i; - -#ifdef PANORAMIX - if (!noPanoramiXExtension && pWindow && pWindow->parent != WindowTable[0]) - return; -#endif -#if DMX_WINDOW_DEBUG - { - const char *name = "Unknown"; - switch (type) { - case DMX_UPDATE_REALIZE: name = "Realize"; break; - case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break; - case DMX_UPDATE_RESTACK: name = "Restack"; break; - case DMX_UPDATE_COPY: name = "Copy"; break; - case DMX_UPDATE_RESIZE: name = "Resize"; break; - case DMX_UPDATE_REPARENT: name = "Repaint"; break; - } - dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name); - } -#endif - - if (dmxInput->detached) - return; - for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) - if (dmxInput->devs[i]->update_info) - dmxInput->devs[i]->update_info(dmxInput->devs[i]->private, - type, pWindow); -} - -static void dmxCollectAll(DMXInputInfo *dmxInput) -{ - int i; - - if (dmxInput->detached) - return; - for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) - if (dmxInput->devs[i]->collect_events) - dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->public, - dmxMotion, - dmxEnqueue, - dmxCheckSpecialKeys, DMX_BLOCK); -} - -static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, - pointer pReadMask) -{ - DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; - static unsigned long generation = 0; - - if (generation != serverGeneration) { - generation = serverGeneration; - dmxCollectAll(dmxInput); - } -} - -static void dmxSwitchReturn(pointer p) -{ - DMXInputInfo *dmxInput = p; - int i; - - dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched); - - if (!dmxInput->vt_switched) - dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n"); - dmxSigioEnableInput(); - for (i = 0; i < dmxInput->numDevs; i++) - if (dmxInput->devs[i]->vt_post_switch) - dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private); - dmxInput->vt_switched = 0; -} - -static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask) -{ - DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; - int i; - - if (dmxInput->vt_switch_pending) { - dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending); - for (i = 0; i < dmxInput->numDevs; i++) - if (dmxInput->devs[i]->vt_pre_switch) - dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private); - dmxInput->vt_switched = dmxInput->vt_switch_pending; - dmxInput->vt_switch_pending = 0; - for (i = 0; i < dmxInput->numDevs; i++) { - if (dmxInput->devs[i]->vt_switch) { - dmxSigioDisableInput(); - if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private, - dmxInput->vt_switched, - dmxSwitchReturn, - dmxInput)) - dmxSwitchReturn(dmxInput); - break; /* Only call one vt_switch routine */ - } - } - } - dmxCollectAll(dmxInput); -} - -static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal) -{ - static int k = 0; - static int m = 0; - static int o = 0; - static unsigned long dmxGeneration = 0; -#define LEN 32 - char * buf = xalloc(LEN); - - if (dmxGeneration != serverGeneration) { - k = m = o = 0; - dmxGeneration = serverGeneration; - } - - switch (dmxLocal->type) { - case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break; - case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break; - default: XmuSnprintf(buf, LEN, "Other%d", o++); break; - } - - return buf; -} - -static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal) -{ - DeviceIntPtr pDevice; - Atom atom; - const char *name = NULL; - void (*registerProcPtr)(DeviceIntPtr) = NULL; - char *devname; - DMXInputInfo *dmxInput; - - if (!dmxLocal) - return NULL; - dmxInput = &dmxInputs[dmxLocal->inputIdx]; - - if (dmxLocal->sendsCore) { - if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) { - dmxLocal->isCore = 1; - dmxLocalCoreKeyboard = dmxLocal; - name = "keyboard"; - registerProcPtr = RegisterKeyboardDevice; - } - if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) { - dmxLocal->isCore = 1; - dmxLocalCorePointer = dmxLocal; - name = "pointer"; - registerProcPtr = RegisterPointerDevice; - } - } - - if (!name) { - name = "extension"; - registerProcPtr = RegisterOtherDevice; - } - - if (!name || !registerProcPtr) - dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name); - - pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE); - if (!pDevice) { - dmxLog(dmxError, "Too many devices -- cannot add device %s\n", - dmxLocal->name); - return NULL; - } - pDevice->public.devicePrivate = dmxLocal; - dmxLocal->pDevice = pDevice; - - devname = dmxMakeUniqueDeviceName(dmxLocal); - atom = MakeAtom((char *)devname, strlen(devname), TRUE); - pDevice->type = atom; - pDevice->name = devname; - - registerProcPtr(pDevice); - - if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) { -#if 00 /*BP*/ - miRegisterPointerDevice(screenInfo.screens[0], pDevice); -#else - /* Nothing? dmxDeviceOnOff() should get called to init, right? */ -#endif - } - - if (dmxLocal->create_private) - dmxLocal->private = dmxLocal->create_private(pDevice); - - dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n", - dmxLocal->name, name, devname, - dmxLocal->isCore - ? " [core]" - : (dmxLocal->sendsCore - ? " [sends core events]" - : "")); - - return pDevice; -} - -static DMXLocalInputInfoPtr dmxLookupLocal(const char *name) -{ - DMXLocalInputInfoPtr pt; - - for (pt = &DMXLocalDevices[0]; pt->name; ++pt) - if (!strcmp(pt->name, name)) return pt; /* search for device name */ - return NULL; -} - -/** Copy the local input information from \a s into a new \a devs slot - * in \a dmxInput. */ -DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, - DMXLocalInputInfoPtr s) -{ - DMXLocalInputInfoPtr dmxLocal = xalloc(sizeof(*dmxLocal)); - - if (!dmxLocal) - dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n"); - - memcpy(dmxLocal, s, sizeof(*dmxLocal)); - dmxLocal->inputIdx = dmxInput->inputIdx; - dmxLocal->sendsCore = dmxInput->core; - dmxLocal->savedSendsCore = dmxInput->core; - dmxLocal->deviceId = -1; - - ++dmxInput->numDevs; - dmxInput->devs = xrealloc(dmxInput->devs, - dmxInput->numDevs * sizeof(*dmxInput->devs)); - dmxInput->devs[dmxInput->numDevs-1] = dmxLocal; - - return dmxLocal; -} - -static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a) -{ - int i; - int help = 0; - DMXLocalInputInfoRec *pt; - - for (i = 1; i < dmxArgC(a); i++) { - const char *name = dmxArgV(a, i); - if ((pt = dmxLookupLocal(name))) { - dmxInputCopyLocal(dmxInput, pt); - } else { - if (strlen(name)) - dmxLog(dmxWarning, - "Could not find a driver called %s\n", name); - ++help; - } - } - if (help) { - dmxLog(dmxInfo, "Available local device drivers:\n"); - for (pt = &DMXLocalDevices[0]; pt->name; ++pt) { - const char *type; - switch (pt->type) { - case DMX_LOCAL_KEYBOARD: type = "keyboard"; break; - case DMX_LOCAL_MOUSE: type = "pointer"; break; - default: type = "unknown"; break; - } - dmxLog(dmxInfo, " %s (%s)\n", pt->name, type); - } - dmxLog(dmxFatal, "Must have valid local device driver\n"); - } -} - -int dmxInputExtensionErrorHandler(Display *dsp, char *name, char *reason) -{ - return 0; -} - -static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI) -{ - XExtensionVersion *ext; - XDeviceInfo *devices; - Display *display; - int num; - int i, j; - DMXLocalInputInfoPtr dmxLocal; - int (*handler)(Display *, char *, char *); - - if (!(display = XOpenDisplay(dmxInput->name))) return; - - /* Print out information about the XInput Extension. */ - handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); - ext = XGetExtensionVersion(display, INAME); - XSetExtensionErrorHandler(handler); - - if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { - dmxLogInput(dmxInput, "%s is not available\n", INAME); - } else { - dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n", - dmxInput->name, INAME, - ext->major_version, ext->minor_version); - devices = XListInputDevices(display, &num); - - XFree(ext); - ext = NULL; - - /* Print a list of all devices */ - for (i = 0; i < num; i++) { - const char *use = "Unknown"; - switch (devices[i].use) { - case IsXPointer: use = "XPointer"; break; - case IsXKeyboard: use = "XKeyboard"; break; - case IsXExtensionDevice: use = "XExtensionDevice"; break; - case IsXExtensionPointer: use = "XExtensionPointer"; break; - case IsXExtensionKeyboard: use = "XExtensionKeyboard"; break; - } - dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n", - devices[i].id, - devices[i].name ? devices[i].name : "", - use); - } - - /* Search for extensions */ - for (i = 0; i < num; i++) { - switch (devices[i].use) { - case IsXKeyboard: - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; - if (dmxL->type == DMX_LOCAL_KEYBOARD - && dmxL->deviceId < 0) { - dmxL->deviceId = devices[i].id; - dmxL->deviceName = (devices[i].name - ? xstrdup(devices[i].name) - : NULL); - } - } - break; - case IsXPointer: - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; - if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) { - dmxL->deviceId = devices[i].id; - dmxL->deviceName = (devices[i].name - ? xstrdup(devices[i].name) - : NULL); - } - } - break; -#if 0 - case IsXExtensionDevice: - case IsXExtensionKeyboard: - case IsXExtensionPointer: - if (doXI) { - if (!dmxInput->numDevs) { - dmxLog(dmxWarning, - "Cannot use remote (%s) XInput devices if" - " not also using core devices\n", - dmxInput->name); - } else { - dmxLocal = dmxInputCopyLocal(dmxInput, - &DMXCommonOth); - dmxLocal->isCore = FALSE; - dmxLocal->sendsCore = FALSE; - dmxLocal->deviceId = devices[i].id; - dmxLocal->deviceName = (devices[i].name - ? xstrdup(devices[i].name) - : NULL); - } - } - break; -#endif - } - } - XFreeDeviceList(devices); - } - XCloseDisplay(display); -} - -/** Re-initialize all the devices described in \a dmxInput. Called from - #dmxAdjustCursorBoundaries before the cursor is redisplayed. */ -void dmxInputReInit(DMXInputInfo *dmxInput) -{ - int i; - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - if (dmxLocal->reinit) - dmxLocal->reinit(&dmxLocal->pDevice->public); - } -} - -/** Re-initialize all the devices described in \a dmxInput. Called from - #dmxAdjustCursorBoundaries after the cursor is redisplayed. */ -void dmxInputLateReInit(DMXInputInfo *dmxInput) -{ - int i; - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - if (dmxLocal->latereinit) - dmxLocal->latereinit(&dmxLocal->pDevice->public); - } -} - -/** Initialize all of the devices described in \a dmxInput. */ -void dmxInputInit(DMXInputInfo *dmxInput) -{ - DeviceIntPtr pPointer = NULL, pKeyboard = NULL; - dmxArg a; - const char *name; - int i; - int doXI = 1; /* Include by default */ - int forceConsole = 0; - int doWindows = 1; /* On by default */ - int hasXkb = 0; - - a = dmxArgParse(dmxInput->name); - - for (i = 1; i < dmxArgC(a); i++) { - switch (hasXkb) { - case 1: - dmxInput->keycodes = xstrdup(dmxArgV(a, i)); - ++hasXkb; - break; - case 2: - dmxInput->symbols = xstrdup(dmxArgV(a, i)); - ++hasXkb; - break; - case 3: - dmxInput->geometry = xstrdup(dmxArgV(a, i)); - hasXkb = 0; - break; - case 0: - if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0; - else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1; - else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1; - else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0; - else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1; - else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0; - else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1; - else { - dmxLog(dmxFatal, - "Unknown input argument: %s\n", dmxArgV(a, i)); - } - } - } - - name = dmxArgV(a, 0); - - if (!strcmp(name, "local")) { - dmxPopulateLocal(dmxInput, a); - } else if (!strcmp(name, "dummy")) { - dmxInputCopyLocal(dmxInput, &DMXDummyMou); - dmxInputCopyLocal(dmxInput, &DMXDummyKbd); - dmxLogInput(dmxInput, "Using dummy input\n"); - } else { - int found; - - for (found = 0, i = 0; i < dmxNumScreens; i++) { - if (dmxPropertySameDisplay(&dmxScreens[i], name)) { - if (dmxScreens[i].shared) - dmxLog(dmxFatal, - "Cannot take input from shared backend (%s)\n", - name); - if (!dmxInput->core) { - dmxLog(dmxWarning, - "Cannot use core devices on a backend (%s)" - " as XInput devices\n", name); - } else { - char *pt; - for (pt = (char *)dmxInput->name; pt && *pt; pt++) - if (*pt == ',') *pt = '\0'; - dmxInputCopyLocal(dmxInput, &DMXBackendMou); - dmxInputCopyLocal(dmxInput, &DMXBackendKbd); - dmxInput->scrnIdx = i; - dmxLogInput(dmxInput, - "Using backend input from %s\n", name); - } - ++found; - break; - } - } - if (!found || forceConsole) { - char *pt; - if (found) dmxInput->console = TRUE; - for (pt = (char *)dmxInput->name; pt && *pt; pt++) - if (*pt == ',') *pt = '\0'; - dmxInputCopyLocal(dmxInput, &DMXConsoleMou); - dmxInputCopyLocal(dmxInput, &DMXConsoleKbd); - if (doWindows) { - dmxInput->windows = TRUE; - dmxInput->updateWindowInfo = dmxUpdateWindowInformation; - } - dmxLogInput(dmxInput, - "Using console input from %s (%s windows)\n", - name, doWindows ? "with" : "without"); - } - } - - dmxArgFree(a); - - /* Locate extensions we may be interested in */ - dmxInputScanForExtensions(dmxInput, doXI); - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - dmxLocal->pDevice = dmxAddDevice(dmxLocal); - if (dmxLocal->isCore) { - if (dmxLocal->type == DMX_LOCAL_MOUSE) - pPointer = dmxLocal->pDevice; - if (dmxLocal->type == DMX_LOCAL_KEYBOARD) - pKeyboard = dmxLocal->pDevice; - } - } - - dmxInput->processInputEvents = dmxProcessInputEvents; - dmxInput->detached = False; - - RegisterBlockAndWakeupHandlers(dmxBlockHandler, - dmxWakeupHandler, - (void *)dmxInput->inputIdx); -} - -static void dmxInputFreeLocal(DMXLocalInputInfoRec *local) -{ - if (!local) return; - if (local->isCore && local->type == DMX_LOCAL_MOUSE) - dmxLocalCorePointer = NULL; - if (local->isCore && local->type == DMX_LOCAL_KEYBOARD) - dmxLocalCoreKeyboard = NULL; - if (local->destroy_private) local->destroy_private(local->private); - if (local->history) xfree(local->history); - if (local->valuators) xfree(local->valuators); - if (local->deviceName) xfree(local->deviceName); - local->private = NULL; - local->history = NULL; - local->deviceName = NULL; - xfree(local); -} - -/** Free all of the memory associated with \a dmxInput */ -void dmxInputFree(DMXInputInfo *dmxInput) -{ - int i; - - if (!dmxInput) return; - - if (dmxInput->keycodes) xfree(dmxInput->keycodes); - if (dmxInput->symbols) xfree(dmxInput->symbols); - if (dmxInput->geometry) xfree(dmxInput->geometry); - - for (i = 0; i < dmxInput->numDevs; i++) { - dmxInputFreeLocal(dmxInput->devs[i]); - dmxInput->devs[i] = NULL; - } - xfree(dmxInput->devs); - dmxInput->devs = NULL; - dmxInput->numDevs = 0; - if (dmxInput->freename) xfree(dmxInput->name); - dmxInput->name = NULL; -} - -/** Log information about all of the known devices using #dmxLog(). */ -void dmxInputLogDevices(void) -{ - int i, j; - - dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount()); - dmxLog(dmxInfo, " Id Name Classes\n"); - for (j = 0; j < dmxNumInputs; j++) { - DMXInputInfo *dmxInput = &dmxInputs[j]; - const char *pt = strchr(dmxInput->name, ','); - int len = (pt - ? (size_t)(pt-dmxInput->name) - : strlen(dmxInput->name)); - - for (i = 0; i < dmxInput->numDevs; i++) { - DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice; - if (pDevice) { - dmxLog(dmxInfo, " %2d%c %-20.20s", - pDevice->id, - dmxInput->detached ? 'D' : ' ', - pDevice->name); - if (pDevice->key) dmxLogCont(dmxInfo, " key"); - if (pDevice->valuator) dmxLogCont(dmxInfo, " val"); - if (pDevice->button) dmxLogCont(dmxInfo, " btn"); - if (pDevice->focus) dmxLogCont(dmxInfo, " foc"); - if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd"); - if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr"); - if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int"); - if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str"); - if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel"); - if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led"); - if (!pDevice->key && !pDevice->valuator && !pDevice->button - && !pDevice->focus && !pDevice->kbdfeed - && !pDevice->ptrfeed && !pDevice->intfeed - && !pDevice->stringfeed && !pDevice->bell - && !pDevice->leds) dmxLogCont(dmxInfo, " (none)"); - - dmxLogCont(dmxInfo, "\t[i%d/%*.*s", - dmxInput->inputIdx, len, len, dmxInput->name); - if (dmxInput->devs[i]->deviceId >= 0) - dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId); - if (dmxInput->devs[i]->deviceName) - dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName); - dmxLogCont(dmxInfo, "] %s\n", - dmxInput->devs[i]->isCore - ? "core" - : (dmxInput->devs[i]->sendsCore - ? "extension (sends core events)" - : "extension")); - } - } - } -} - -/** Detach an input */ -int dmxInputDetach(DMXInputInfo *dmxInput) -{ - int i; - - if (dmxInput->detached) return BadAccess; - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n", - dmxLocal->pDevice->id, - dmxLocal->pDevice->name, - dmxLocal->isCore - ? " [core]" - : (dmxLocal->sendsCore - ? " [sends core events]" - : "")); - DisableDevice(dmxLocal->pDevice, TRUE); - } - dmxInput->detached = True; - dmxInputLogDevices(); - return 0; -} - -/** Search for input associated with \a dmxScreen, and detach. */ -void dmxInputDetachAll(DMXScreenInfo *dmxScreen) -{ - int i; - - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput); - } -} - -/** Search for input associated with \a deviceId, and detach. */ -int dmxInputDetachId(int id) -{ - DMXInputInfo *dmxInput = dmxInputLocateId(id); - - if (!dmxInput) return BadValue; - - return dmxInputDetach(dmxInput); -} - -DMXInputInfo *dmxInputLocateId(int id) -{ - int i, j; - - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; - if (dmxLocal->pDevice->id == id) return dmxInput; - } - } - return NULL; -} - -static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id) -{ - dmxInputInit(dmxInput); - InitAndStartDevices(); - if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id; - dmxInputLogDevices(); - return 0; -} - -static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id) -{ - int i; - - dmxInput->detached = False; - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - if (id) *id = dmxLocal->pDevice->id; - dmxLogInput(dmxInput, - "Attaching device id %d: %s%s\n", - dmxLocal->pDevice->id, - dmxLocal->pDevice->name, - dmxLocal->isCore - ? " [core]" - : (dmxLocal->sendsCore - ? " [sends core events]" - : "")); - EnableDevice(dmxLocal->pDevice, TRUE); - } - dmxInputLogDevices(); - return 0; -} - -int dmxInputAttachConsole(const char *name, int isCore, int *id) -{ - DMXInputInfo *dmxInput; - int i; - - for (i = 0; i < dmxNumInputs; i++) { - dmxInput = &dmxInputs[i]; - if (dmxInput->scrnIdx == -1 - && dmxInput->detached - && !strcmp(dmxInput->name, name)) { - /* Found match */ - dmxLogInput(dmxInput, "Reattaching detached console input\n"); - return dmxInputAttachOld(dmxInput, id); - } - } - - /* No match found */ - dmxInput = dmxConfigAddInput(xstrdup(name), isCore); - dmxInput->freename = TRUE; - dmxLogInput(dmxInput, "Attaching new console input\n"); - return dmxInputAttachNew(dmxInput, id); -} - -int dmxInputAttachBackend(int physicalScreen, int isCore, int *id) -{ - DMXInputInfo *dmxInput; - DMXScreenInfo *dmxScreen; - int i; - - if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue; - for (i = 0; i < dmxNumInputs; i++) { - dmxInput = &dmxInputs[i]; - if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) { - /* Found match */ - if (!dmxInput->detached) return BadAccess; /* Already attached */ - dmxScreen = &dmxScreens[physicalScreen]; - if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ - dmxLogInput(dmxInput, "Reattaching detached backend input\n"); - return dmxInputAttachOld(dmxInput, id); - } - } - /* No match found */ - dmxScreen = &dmxScreens[physicalScreen]; - if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ - dmxInput = dmxConfigAddInput(dmxScreen->name, isCore); - dmxLogInput(dmxInput, "Attaching new backend input\n"); - return dmxInputAttachNew(dmxInput, id); -} +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * This file provides generic input support. Functions here set up + * input and lead to the calling of low-level device drivers for + * input. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define DMX_WINDOW_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxextension.h" /* For dmxInputCount */ + +#include "dmxdummy.h" +#include "dmxbackend.h" +#include "dmxconsole.h" +#include "dmxcommon.h" +#include "dmxevents.h" +#include "dmxmotion.h" +#include "dmxprop.h" +#include "config/dmxconfig.h" +#include "dmxcursor.h" + +#include "lnx-keyboard.h" +#include "lnx-ms.h" +#include "lnx-ps2.h" +#include "usb-keyboard.h" +#include "usb-mouse.h" +#include "usb-other.h" +#include "usb-common.h" + +#include "dmxsigio.h" +#include "dmxarg.h" + +#include "inputstr.h" +#include "input.h" +#include "mipointer.h" +#include "windowstr.h" +#include "mi.h" +#include "xkbsrv.h" + +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "exevents.h" +#include "extinit.h" + +DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; + +static DMXLocalInputInfoRec DMXDummyMou = { + "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo +}; + +static DMXLocalInputInfoRec DMXDummyKbd = { + "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo +}; + +static DMXLocalInputInfoRec DMXBackendMou = { + "backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2, + dmxBackendCreatePrivate, dmxBackendDestroyPrivate, + dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo, + dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition, + NULL, NULL, NULL, + dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL, + dmxCommonMouCtrl +}; + +static DMXLocalInputInfoRec DMXBackendKbd = { + "backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND, + 1, /* With backend-mou or console-mou */ + dmxCommonCopyPrivate, NULL, + dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo, + dmxCommonKbdOn, dmxCommonKbdOff, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, dmxCommonKbdCtrl, dmxCommonKbdBell +}; + +static DMXLocalInputInfoRec DMXConsoleMou = { + "console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2, + dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate, + dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo, + dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition, + NULL, NULL, NULL, + dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo, + dmxCommonMouCtrl +}; + +static DMXLocalInputInfoRec DMXConsoleKbd = { + "console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE, + 1, /* With backend-mou or console-mou */ + dmxCommonCopyPrivate, NULL, + dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo, + dmxCommonKbdOn, dmxCommonKbdOff, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, dmxCommonKbdCtrl, dmxCommonKbdBell +}; + +static DMXLocalInputInfoRec DMXCommonOth = { + "common-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_COMMON, 1, + dmxCommonCopyPrivate, NULL, + NULL, NULL, NULL, dmxCommonOthGetInfo, + dmxCommonOthOn, dmxCommonOthOff +}; + + +static DMXLocalInputInfoRec DMXLocalDevices[] = { + /* Dummy drivers that can compile on any OS */ +#ifdef __linux__ + /* Linux-specific drivers */ + { + "kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate, + kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo, + kbdLinuxOn, kbdLinuxOff, NULL, + kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch, + kbdLinuxRead, NULL, NULL, NULL, + NULL, kbdLinuxCtrl, kbdLinuxBell + }, + { + "ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + msLinuxCreatePrivate, msLinuxDestroyPrivate, + msLinuxInit, NULL, NULL, msLinuxGetInfo, + msLinuxOn, msLinuxOff, NULL, + msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL, + msLinuxRead + }, + { + "ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate, + ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo, + ps2LinuxOn, ps2LinuxOff, NULL, + ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL, + ps2LinuxRead + }, +#endif +#ifdef __linux__ + /* USB drivers, currently only for + Linux, but relatively easy to port to + other OSs */ + { + "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + kbdUSBInit, NULL, NULL, kbdUSBGetInfo, + kbdUSBOn, usbOff, NULL, + NULL, NULL, NULL, + kbdUSBRead, NULL, NULL, NULL, + NULL, kbdUSBCtrl + }, + { + "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + mouUSBInit, NULL, NULL, mouUSBGetInfo, + mouUSBOn, usbOff, NULL, + NULL, NULL, NULL, + mouUSBRead + }, + { + "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + othUSBInit, NULL, NULL, othUSBGetInfo, + othUSBOn, usbOff, NULL, + NULL, NULL, NULL, + othUSBRead + }, +#endif + { + "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo + }, + { + "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo + }, + { NULL } /* Must be last */ +}; + + +#if 11 /*BP*/ +void +DDXRingBell(int volume, int pitch, int duration) +{ + /* NO-OP */ +} + +/* taken from kdrive/src/kinput.c: */ +static void +dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ +#if 0 + KdKeyboardInfo *ki; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDevice->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) + return; + + KdSetLeds(ki, ctrl->leds); + ki->bellPitch = ctrl->bell_pitch; + ki->bellDuration = ctrl->bell_duration; +#endif +} + +/* taken from kdrive/src/kinput.c: */ +static void +dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something) +{ +#if 0 + KeybdCtrl *ctrl = arg; + KdKeyboardInfo *ki = NULL; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDev->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) + return; + + KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); +#endif +} + +#endif /*BP*/ + +static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, + PtrCtrl *ctrl) +{ + if (!dmxLocal) return; + dmxLocal->mctrl = *ctrl; + if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl); +} + +/** Change the pointer control information for the \a pDevice. If the + * device sends core events, then also change the control information + * for all of the pointer devices that send core events. */ +void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxChangePointerControl(dmxInput->devs[j], ctrl); + } + } else { /* Do for this device only */ + _dmxChangePointerControl(dmxLocal, ctrl); + } +} + +static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, + KeybdCtrl *ctrl) +{ + dmxLocal->kctrl = *ctrl; + if (dmxLocal->kCtrl) { + dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl); + if (dmxLocal->pDevice->kbdfeed) { + XkbEventCauseRec cause; + XkbSetCauseUnknown(&cause); + /* Generate XKB events, as necessary */ + XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False, + NULL, &cause); + } + } +} + + +/** Change the keyboard control information for the \a pDevice. If the + * device sends core events, then also change the control information + * for all of the keyboard devices that send core events. */ +void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl); + } + } else { /* Do for this device only */ + _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl); + } +} + +static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent) +{ + if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public, + percent, + dmxLocal->kctrl.bell, + dmxLocal->kctrl.bell_pitch, + dmxLocal->kctrl.bell_duration); +} + +/** Sound the bell on the device. If the device send core events, then + * sound the bell on all of the devices that send core events. */ +void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, + pointer ctrl, int unknown) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxKeyboardBellProc(dmxInput->devs[j], percent); + } + } else { /* Do for this device only */ + _dmxKeyboardBellProc(dmxLocal, percent); + } +} + +static void dmxKeyboardFreeNames(XkbComponentNamesPtr names) +{ + if (names->keycodes) XFree(names->keycodes); + if (names->types) XFree(names->types); + if (names->compat) XFree(names->compat); + if (names->symbols) XFree(names->symbols); + if (names->geometry) XFree(names->geometry); +} + + +static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info) +{ + GETDMXINPUTFROMPDEVICE; + XkbRMLVOSet rmlvo; + + rmlvo.rules = dmxConfigGetXkbRules(); + rmlvo.model = dmxConfigGetXkbModel(); + rmlvo.layout = dmxConfigGetXkbLayout(); + rmlvo.variant = dmxConfigGetXkbVariant(); + rmlvo.options = dmxConfigGetXkbOptions(); + + XkbSetRulesDflts(&rmlvo); + if (!info->force && (dmxInput->keycodes + || dmxInput->symbols + || dmxInput->geometry)) { + if (info->freenames) dmxKeyboardFreeNames(&info->names); + info->freenames = 0; + info->names.keycodes = dmxInput->keycodes; + info->names.types = NULL; + info->names.compat = NULL; + info->names.symbols = dmxInput->symbols; + info->names.geometry = dmxInput->geometry; + + dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s", + info->names.keycodes); + if (info->names.symbols && *info->names.symbols) + dmxLogInputCont(dmxInput, " %s", info->names.symbols); + if (info->names.geometry && *info->names.geometry) + dmxLogInputCont(dmxInput, " %s", info->names.geometry); + dmxLogInputCont(dmxInput, "\n"); + } else if (info->names.keycodes) { + dmxLogInput(dmxInput, "XKEYBOARD: From device: %s", + info->names.keycodes); + if (info->names.symbols && *info->names.symbols) + dmxLogInputCont(dmxInput, " %s", info->names.symbols); + if (info->names.geometry && *info->names.geometry) + dmxLogInputCont(dmxInput, " %s", info->names.geometry); + dmxLogInputCont(dmxInput, "\n"); + } else { + dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n", + dmxConfigGetXkbRules(), + dmxConfigGetXkbLayout(), + dmxConfigGetXkbModel(), + dmxConfigGetXkbVariant() + ? dmxConfigGetXkbVariant() : "", + dmxConfigGetXkbOptions() + ? dmxConfigGetXkbOptions() : ""); + } + InitKeyboardDeviceStruct(pDevice, &rmlvo, + dmxKeyboardBellProc, + dmxKeyboardKbdCtrlProc); + + if (info->freenames) dmxKeyboardFreeNames(&info->names); + + return Success; +} + + +static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what) +{ + GETDMXINPUTFROMPDEVICE; + int fd; + DMXLocalInitInfo info; + int i; + Atom btn_labels[MAX_BUTTONS] = {0}; /* FIXME */ + Atom axis_labels[MAX_VALUATORS] = {0}; /* FIXME */ + + if (dmxInput->detached) return Success; + + memset(&info, 0, sizeof(info)); + switch (what) { + case DEVICE_INIT: + if (dmxLocal->init) + dmxLocal->init(pDev); + if (dmxLocal->get_info) + dmxLocal->get_info(pDev, &info); + if (info.keyboard) { /* XKEYBOARD makes this a special case */ + dmxKeyboardOn(pDevice, &info); + break; + } + if (info.keyClass) { + XkbRMLVOSet rmlvo; + + rmlvo.rules = dmxConfigGetXkbRules(); + rmlvo.model = dmxConfigGetXkbModel(); + rmlvo.layout = dmxConfigGetXkbLayout(); + rmlvo.variant = dmxConfigGetXkbVariant(); + rmlvo.options = dmxConfigGetXkbOptions(); + + InitKeyboardDeviceStruct(pDevice, + &rmlvo, + dmxBell, dmxKbdCtrl); + } + if (info.buttonClass) { + InitButtonClassDeviceStruct(pDevice, info.numButtons, + btn_labels, info.map); + } + if (info.valuatorClass) { + if (info.numRelAxes && dmxLocal->sendsCore) { + InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, + axis_labels, + GetMaximumEventsNum(), + Relative); + for (i = 0; i < info.numRelAxes; i++) + InitValuatorAxisStruct(pDevice, i, axis_labels[i], + info.minval[i], info.maxval[i], + info.res[i], + info.minres[i], info.maxres[i]); + } else if (info.numRelAxes) { + InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, + axis_labels, + dmxPointerGetMotionBufferSize(), + Relative); + for (i = 0; i < info.numRelAxes; i++) + InitValuatorAxisStruct(pDevice, i, axis_labels[i], + info.minval[i], + info.maxval[i], info.res[i], + info.minres[i], info.maxres[i]); + } else if (info.numAbsAxes) { + InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes, + axis_labels, + dmxPointerGetMotionBufferSize(), + Absolute); + for (i = 0; i < info.numAbsAxes; i++) + InitValuatorAxisStruct(pDevice, i, + axis_labels[i], + info.minval[i], info.maxval[i], + info.res[i], info.minres[i], + info.maxres[i]); + } + } + if (info.focusClass) InitFocusClassDeviceStruct(pDevice); + if (info.proximityClass) InitProximityClassDeviceStruct(pDevice); + if (info.ptrFeedbackClass) + InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl); + if (info.intFeedbackClass || info.strFeedbackClass) + dmxLog(dmxWarning, + "Integer and string feedback not supported for %s\n", + pDevice->name); + if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass)) + dmxLog(dmxWarning, + "Led and bel feedback not supported for non-keyboard %s\n", + pDevice->name); + break; + case DEVICE_ON: + if (!pDev->on) { + if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0) + dmxSigioRegister(dmxInput, fd); + pDev->on = TRUE; + } + break; + case DEVICE_OFF: + case DEVICE_CLOSE: + /* This can get called twice consecutively: once for a + * detached screen (DEVICE_OFF), and then again at server + * generation time (DEVICE_CLOSE). */ + if (pDev->on) { + dmxSigioUnregister(dmxInput); + if (dmxLocal->off) dmxLocal->off(pDev); + pDev->on = FALSE; + } + break; + } + if (info.keySyms.map && info.freemap) { + XFree(info.keySyms.map); + info.keySyms.map = NULL; + } + if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True); + return Success; +} + +static void dmxProcessInputEvents(DMXInputInfo *dmxInput) +{ + int i; + + mieqProcessInputEvents(); +#if 00 /*BP*/ + miPointerUpdate(); +#endif + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->process_input) { +#if 11 /*BP*/ + miPointerUpdateSprite(dmxInput->devs[i]->pDevice); +#endif + dmxInput->devs[i]->process_input(dmxInput->devs[i]->private); + } + +#if 11 /*BP*/ + mieqProcessInputEvents(); +#endif +} + +static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput, + DMXUpdateType type, + WindowPtr pWindow) +{ + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension && pWindow && pWindow->parent != WindowTable[0]) + return; +#endif +#if DMX_WINDOW_DEBUG + { + const char *name = "Unknown"; + switch (type) { + case DMX_UPDATE_REALIZE: name = "Realize"; break; + case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break; + case DMX_UPDATE_RESTACK: name = "Restack"; break; + case DMX_UPDATE_COPY: name = "Copy"; break; + case DMX_UPDATE_RESIZE: name = "Resize"; break; + case DMX_UPDATE_REPARENT: name = "Repaint"; break; + } + dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name); + } +#endif + + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->update_info) + dmxInput->devs[i]->update_info(dmxInput->devs[i]->private, + type, pWindow); +} + +static void dmxCollectAll(DMXInputInfo *dmxInput) +{ + int i; + + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->collect_events) + dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->public, + dmxMotion, + dmxEnqueue, + dmxCheckSpecialKeys, DMX_BLOCK); +} + +static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, + pointer pReadMask) +{ + DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; + static unsigned long generation = 0; + + if (generation != serverGeneration) { + generation = serverGeneration; + dmxCollectAll(dmxInput); + } +} + +static void dmxSwitchReturn(pointer p) +{ + DMXInputInfo *dmxInput = p; + int i; + + dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched); + + if (!dmxInput->vt_switched) + dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n"); + dmxSigioEnableInput(); + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i]->vt_post_switch) + dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private); + dmxInput->vt_switched = 0; +} + +static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask) +{ + DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; + int i; + + if (dmxInput->vt_switch_pending) { + dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending); + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i]->vt_pre_switch) + dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private); + dmxInput->vt_switched = dmxInput->vt_switch_pending; + dmxInput->vt_switch_pending = 0; + for (i = 0; i < dmxInput->numDevs; i++) { + if (dmxInput->devs[i]->vt_switch) { + dmxSigioDisableInput(); + if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private, + dmxInput->vt_switched, + dmxSwitchReturn, + dmxInput)) + dmxSwitchReturn(dmxInput); + break; /* Only call one vt_switch routine */ + } + } + } + dmxCollectAll(dmxInput); +} + +static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal) +{ + static int k = 0; + static int m = 0; + static int o = 0; + static unsigned long dmxGeneration = 0; +#define LEN 32 + char * buf = malloc(LEN); + + if (dmxGeneration != serverGeneration) { + k = m = o = 0; + dmxGeneration = serverGeneration; + } + + switch (dmxLocal->type) { + case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break; + case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break; + default: XmuSnprintf(buf, LEN, "Other%d", o++); break; + } + + return buf; +} + +static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal) +{ + DeviceIntPtr pDevice; + Atom atom; + const char *name = NULL; + void (*registerProcPtr)(DeviceIntPtr) = NULL; + char *devname; + DMXInputInfo *dmxInput; + + if (!dmxLocal) + return NULL; + dmxInput = &dmxInputs[dmxLocal->inputIdx]; + + if (dmxLocal->sendsCore) { + if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) { + dmxLocal->isCore = 1; + dmxLocalCoreKeyboard = dmxLocal; + name = "keyboard"; + registerProcPtr = RegisterKeyboardDevice; + } + if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) { + dmxLocal->isCore = 1; + dmxLocalCorePointer = dmxLocal; + name = "pointer"; + registerProcPtr = RegisterPointerDevice; + } + } + + if (!name) { + name = "extension"; + registerProcPtr = RegisterOtherDevice; + } + + if (!name || !registerProcPtr) + dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name); + + pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE); + if (!pDevice) { + dmxLog(dmxError, "Too many devices -- cannot add device %s\n", + dmxLocal->name); + return NULL; + } + pDevice->public.devicePrivate = dmxLocal; + dmxLocal->pDevice = pDevice; + + devname = dmxMakeUniqueDeviceName(dmxLocal); + atom = MakeAtom((char *)devname, strlen(devname), TRUE); + pDevice->type = atom; + pDevice->name = devname; + + registerProcPtr(pDevice); + + if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) { +#if 00 /*BP*/ + miRegisterPointerDevice(screenInfo.screens[0], pDevice); +#else + /* Nothing? dmxDeviceOnOff() should get called to init, right? */ +#endif + } + + if (dmxLocal->create_private) + dmxLocal->private = dmxLocal->create_private(pDevice); + + dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n", + dmxLocal->name, name, devname, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + + return pDevice; +} + +static DMXLocalInputInfoPtr dmxLookupLocal(const char *name) +{ + DMXLocalInputInfoPtr pt; + + for (pt = &DMXLocalDevices[0]; pt->name; ++pt) + if (!strcmp(pt->name, name)) return pt; /* search for device name */ + return NULL; +} + +/** Copy the local input information from \a s into a new \a devs slot + * in \a dmxInput. */ +DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, + DMXLocalInputInfoPtr s) +{ + DMXLocalInputInfoPtr dmxLocal = malloc(sizeof(*dmxLocal)); + + if (!dmxLocal) + dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n"); + + memcpy(dmxLocal, s, sizeof(*dmxLocal)); + dmxLocal->inputIdx = dmxInput->inputIdx; + dmxLocal->sendsCore = dmxInput->core; + dmxLocal->savedSendsCore = dmxInput->core; + dmxLocal->deviceId = -1; + + ++dmxInput->numDevs; + dmxInput->devs = realloc(dmxInput->devs, + dmxInput->numDevs * sizeof(*dmxInput->devs)); + dmxInput->devs[dmxInput->numDevs-1] = dmxLocal; + + return dmxLocal; +} + +static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a) +{ + int i; + int help = 0; + DMXLocalInputInfoRec *pt; + + for (i = 1; i < dmxArgC(a); i++) { + const char *name = dmxArgV(a, i); + if ((pt = dmxLookupLocal(name))) { + dmxInputCopyLocal(dmxInput, pt); + } else { + if (strlen(name)) + dmxLog(dmxWarning, + "Could not find a driver called %s\n", name); + ++help; + } + } + if (help) { + dmxLog(dmxInfo, "Available local device drivers:\n"); + for (pt = &DMXLocalDevices[0]; pt->name; ++pt) { + const char *type; + switch (pt->type) { + case DMX_LOCAL_KEYBOARD: type = "keyboard"; break; + case DMX_LOCAL_MOUSE: type = "pointer"; break; + default: type = "unknown"; break; + } + dmxLog(dmxInfo, " %s (%s)\n", pt->name, type); + } + dmxLog(dmxFatal, "Must have valid local device driver\n"); + } +} + +int dmxInputExtensionErrorHandler(Display *dsp, char *name, char *reason) +{ + return 0; +} + +static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI) +{ + XExtensionVersion *ext; + XDeviceInfo *devices; + Display *display; + int num; + int i, j; + DMXLocalInputInfoPtr dmxLocal; + int (*handler)(Display *, char *, char *); + + if (!(display = XOpenDisplay(dmxInput->name))) return; + + /* Print out information about the XInput Extension. */ + handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); + ext = XGetExtensionVersion(display, INAME); + XSetExtensionErrorHandler(handler); + + if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { + dmxLogInput(dmxInput, "%s is not available\n", INAME); + } else { + dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n", + dmxInput->name, INAME, + ext->major_version, ext->minor_version); + devices = XListInputDevices(display, &num); + + XFree(ext); + ext = NULL; + + /* Print a list of all devices */ + for (i = 0; i < num; i++) { + const char *use = "Unknown"; + switch (devices[i].use) { + case IsXPointer: use = "XPointer"; break; + case IsXKeyboard: use = "XKeyboard"; break; + case IsXExtensionDevice: use = "XExtensionDevice"; break; + case IsXExtensionPointer: use = "XExtensionPointer"; break; + case IsXExtensionKeyboard: use = "XExtensionKeyboard"; break; + } + dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n", + devices[i].id, + devices[i].name ? devices[i].name : "", + use); + } + + /* Search for extensions */ + for (i = 0; i < num; i++) { + switch (devices[i].use) { + case IsXKeyboard: + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; + if (dmxL->type == DMX_LOCAL_KEYBOARD + && dmxL->deviceId < 0) { + dmxL->deviceId = devices[i].id; + dmxL->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; + case IsXPointer: + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; + if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) { + dmxL->deviceId = devices[i].id; + dmxL->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; +#if 0 + case IsXExtensionDevice: + case IsXExtensionKeyboard: + case IsXExtensionPointer: + if (doXI) { + if (!dmxInput->numDevs) { + dmxLog(dmxWarning, + "Cannot use remote (%s) XInput devices if" + " not also using core devices\n", + dmxInput->name); + } else { + dmxLocal = dmxInputCopyLocal(dmxInput, + &DMXCommonOth); + dmxLocal->isCore = FALSE; + dmxLocal->sendsCore = FALSE; + dmxLocal->deviceId = devices[i].id; + dmxLocal->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; +#endif + } + } + XFreeDeviceList(devices); + } + XCloseDisplay(display); +} + +/** Re-initialize all the devices described in \a dmxInput. Called from + #dmxAdjustCursorBoundaries before the cursor is redisplayed. */ +void dmxInputReInit(DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (dmxLocal->reinit) + dmxLocal->reinit(&dmxLocal->pDevice->public); + } +} + +/** Re-initialize all the devices described in \a dmxInput. Called from + #dmxAdjustCursorBoundaries after the cursor is redisplayed. */ +void dmxInputLateReInit(DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (dmxLocal->latereinit) + dmxLocal->latereinit(&dmxLocal->pDevice->public); + } +} + +/** Initialize all of the devices described in \a dmxInput. */ +void dmxInputInit(DMXInputInfo *dmxInput) +{ + DeviceIntPtr pPointer = NULL, pKeyboard = NULL; + dmxArg a; + const char *name; + int i; + int doXI = 1; /* Include by default */ + int forceConsole = 0; + int doWindows = 1; /* On by default */ + int hasXkb = 0; + + a = dmxArgParse(dmxInput->name); + + for (i = 1; i < dmxArgC(a); i++) { + switch (hasXkb) { + case 1: + dmxInput->keycodes = xstrdup(dmxArgV(a, i)); + ++hasXkb; + break; + case 2: + dmxInput->symbols = xstrdup(dmxArgV(a, i)); + ++hasXkb; + break; + case 3: + dmxInput->geometry = xstrdup(dmxArgV(a, i)); + hasXkb = 0; + break; + case 0: + if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0; + else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1; + else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1; + else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0; + else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1; + else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0; + else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1; + else { + dmxLog(dmxFatal, + "Unknown input argument: %s\n", dmxArgV(a, i)); + } + } + } + + name = dmxArgV(a, 0); + + if (!strcmp(name, "local")) { + dmxPopulateLocal(dmxInput, a); + } else if (!strcmp(name, "dummy")) { + dmxInputCopyLocal(dmxInput, &DMXDummyMou); + dmxInputCopyLocal(dmxInput, &DMXDummyKbd); + dmxLogInput(dmxInput, "Using dummy input\n"); + } else { + int found; + + for (found = 0, i = 0; i < dmxNumScreens; i++) { + if (dmxPropertySameDisplay(&dmxScreens[i], name)) { + if (dmxScreens[i].shared) + dmxLog(dmxFatal, + "Cannot take input from shared backend (%s)\n", + name); + if (!dmxInput->core) { + dmxLog(dmxWarning, + "Cannot use core devices on a backend (%s)" + " as XInput devices\n", name); + } else { + char *pt; + for (pt = (char *)dmxInput->name; pt && *pt; pt++) + if (*pt == ',') *pt = '\0'; + dmxInputCopyLocal(dmxInput, &DMXBackendMou); + dmxInputCopyLocal(dmxInput, &DMXBackendKbd); + dmxInput->scrnIdx = i; + dmxLogInput(dmxInput, + "Using backend input from %s\n", name); + } + ++found; + break; + } + } + if (!found || forceConsole) { + char *pt; + if (found) dmxInput->console = TRUE; + for (pt = (char *)dmxInput->name; pt && *pt; pt++) + if (*pt == ',') *pt = '\0'; + dmxInputCopyLocal(dmxInput, &DMXConsoleMou); + dmxInputCopyLocal(dmxInput, &DMXConsoleKbd); + if (doWindows) { + dmxInput->windows = TRUE; + dmxInput->updateWindowInfo = dmxUpdateWindowInformation; + } + dmxLogInput(dmxInput, + "Using console input from %s (%s windows)\n", + name, doWindows ? "with" : "without"); + } + } + + dmxArgFree(a); + + /* Locate extensions we may be interested in */ + dmxInputScanForExtensions(dmxInput, doXI); + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + dmxLocal->pDevice = dmxAddDevice(dmxLocal); + if (dmxLocal->isCore) { + if (dmxLocal->type == DMX_LOCAL_MOUSE) + pPointer = dmxLocal->pDevice; + if (dmxLocal->type == DMX_LOCAL_KEYBOARD) + pKeyboard = dmxLocal->pDevice; + } + } + + dmxInput->processInputEvents = dmxProcessInputEvents; + dmxInput->detached = False; + + RegisterBlockAndWakeupHandlers(dmxBlockHandler, + dmxWakeupHandler, + (void *)dmxInput->inputIdx); +} + +static void dmxInputFreeLocal(DMXLocalInputInfoRec *local) +{ + if (!local) return; + if (local->isCore && local->type == DMX_LOCAL_MOUSE) + dmxLocalCorePointer = NULL; + if (local->isCore && local->type == DMX_LOCAL_KEYBOARD) + dmxLocalCoreKeyboard = NULL; + if (local->destroy_private) local->destroy_private(local->private); + if (local->history) free(local->history); + if (local->valuators) free(local->valuators); + if (local->deviceName) free(local->deviceName); + local->private = NULL; + local->history = NULL; + local->deviceName = NULL; + free(local); +} + +/** Free all of the memory associated with \a dmxInput */ +void dmxInputFree(DMXInputInfo *dmxInput) +{ + int i; + + if (!dmxInput) return; + + if (dmxInput->keycodes) free(dmxInput->keycodes); + if (dmxInput->symbols) free(dmxInput->symbols); + if (dmxInput->geometry) free(dmxInput->geometry); + + for (i = 0; i < dmxInput->numDevs; i++) { + dmxInputFreeLocal(dmxInput->devs[i]); + dmxInput->devs[i] = NULL; + } + free(dmxInput->devs); + dmxInput->devs = NULL; + dmxInput->numDevs = 0; + if (dmxInput->freename) free(dmxInput->name); + dmxInput->name = NULL; +} + +/** Log information about all of the known devices using #dmxLog(). */ +void dmxInputLogDevices(void) +{ + int i, j; + + dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount()); + dmxLog(dmxInfo, " Id Name Classes\n"); + for (j = 0; j < dmxNumInputs; j++) { + DMXInputInfo *dmxInput = &dmxInputs[j]; + const char *pt = strchr(dmxInput->name, ','); + int len = (pt + ? (size_t)(pt-dmxInput->name) + : strlen(dmxInput->name)); + + for (i = 0; i < dmxInput->numDevs; i++) { + DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice; + if (pDevice) { + dmxLog(dmxInfo, " %2d%c %-20.20s", + pDevice->id, + dmxInput->detached ? 'D' : ' ', + pDevice->name); + if (pDevice->key) dmxLogCont(dmxInfo, " key"); + if (pDevice->valuator) dmxLogCont(dmxInfo, " val"); + if (pDevice->button) dmxLogCont(dmxInfo, " btn"); + if (pDevice->focus) dmxLogCont(dmxInfo, " foc"); + if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd"); + if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr"); + if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int"); + if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str"); + if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel"); + if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led"); + if (!pDevice->key && !pDevice->valuator && !pDevice->button + && !pDevice->focus && !pDevice->kbdfeed + && !pDevice->ptrfeed && !pDevice->intfeed + && !pDevice->stringfeed && !pDevice->bell + && !pDevice->leds) dmxLogCont(dmxInfo, " (none)"); + + dmxLogCont(dmxInfo, "\t[i%d/%*.*s", + dmxInput->inputIdx, len, len, dmxInput->name); + if (dmxInput->devs[i]->deviceId >= 0) + dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId); + if (dmxInput->devs[i]->deviceName) + dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName); + dmxLogCont(dmxInfo, "] %s\n", + dmxInput->devs[i]->isCore + ? "core" + : (dmxInput->devs[i]->sendsCore + ? "extension (sends core events)" + : "extension")); + } + } + } +} + +/** Detach an input */ +int dmxInputDetach(DMXInputInfo *dmxInput) +{ + int i; + + if (dmxInput->detached) return BadAccess; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n", + dmxLocal->pDevice->id, + dmxLocal->pDevice->name, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + DisableDevice(dmxLocal->pDevice, TRUE); + } + dmxInput->detached = True; + dmxInputLogDevices(); + return 0; +} + +/** Search for input associated with \a dmxScreen, and detach. */ +void dmxInputDetachAll(DMXScreenInfo *dmxScreen) +{ + int i; + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput); + } +} + +/** Search for input associated with \a deviceId, and detach. */ +int dmxInputDetachId(int id) +{ + DMXInputInfo *dmxInput = dmxInputLocateId(id); + + if (!dmxInput) return BadValue; + + return dmxInputDetach(dmxInput); +} + +DMXInputInfo *dmxInputLocateId(int id) +{ + int i, j; + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + if (dmxLocal->pDevice->id == id) return dmxInput; + } + } + return NULL; +} + +static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id) +{ + dmxInputInit(dmxInput); + InitAndStartDevices(); + if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id; + dmxInputLogDevices(); + return 0; +} + +static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id) +{ + int i; + + dmxInput->detached = False; + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (id) *id = dmxLocal->pDevice->id; + dmxLogInput(dmxInput, + "Attaching device id %d: %s%s\n", + dmxLocal->pDevice->id, + dmxLocal->pDevice->name, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + EnableDevice(dmxLocal->pDevice, TRUE); + } + dmxInputLogDevices(); + return 0; +} + +int dmxInputAttachConsole(const char *name, int isCore, int *id) +{ + DMXInputInfo *dmxInput; + int i; + + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx == -1 + && dmxInput->detached + && !strcmp(dmxInput->name, name)) { + /* Found match */ + dmxLogInput(dmxInput, "Reattaching detached console input\n"); + return dmxInputAttachOld(dmxInput, id); + } + } + + /* No match found */ + dmxInput = dmxConfigAddInput(xstrdup(name), isCore); + dmxInput->freename = TRUE; + dmxLogInput(dmxInput, "Attaching new console input\n"); + return dmxInputAttachNew(dmxInput, id); +} + +int dmxInputAttachBackend(int physicalScreen, int isCore, int *id) +{ + DMXInputInfo *dmxInput; + DMXScreenInfo *dmxScreen; + int i; + + if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue; + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) { + /* Found match */ + if (!dmxInput->detached) return BadAccess; /* Already attached */ + dmxScreen = &dmxScreens[physicalScreen]; + if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ + dmxLogInput(dmxInput, "Reattaching detached backend input\n"); + return dmxInputAttachOld(dmxInput, id); + } + } + /* No match found */ + dmxScreen = &dmxScreens[physicalScreen]; + if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ + dmxInput = dmxConfigAddInput(dmxScreen->name, isCore); + dmxLogInput(dmxInput, "Attaching new backend input\n"); + return dmxInputAttachNew(dmxInput, id); +} diff --git a/xorg-server/hw/dmx/input/dmxmotion.c b/xorg-server/hw/dmx/input/dmxmotion.c index 73580a215..d1c79f126 100644 --- a/xorg-server/hw/dmx/input/dmxmotion.c +++ b/xorg-server/hw/dmx/input/dmxmotion.c @@ -1,142 +1,142 @@ -/* - * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Rickard E. (Rik) Faith <faith@redhat.com> - * - */ - -/** \file - * This file provides functions similar to miPointerGetMotionEvents and - * miPointerPutMotionEvents, with the exception that devices with more - * than two axes are fully supported. These routines may be used only - * for motion buffers for extension devices, and are \a not compatible - * replacements for the mi routines. */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "inputstr.h" -#include "dmxinputinit.h" -#include "dmxcommon.h" -#include "dmxmotion.h" - -#define OFFSET(offset,element) ((offset) * (numAxes + 1) + (element)) - -/** Return size of motion buffer. \see DMX_MOTION_SIZE */ -int dmxPointerGetMotionBufferSize(void) -{ - return DMX_MOTION_SIZE; -} - -/** This routine performs the same function as \a miPointerGetMotionEvents: - * the events in the motion history that are between the start and stop - * times (in mS) are placed in the coords vector, and the count of the - * number of items so placed is returned. This routine is called from - * dix/devices.c so that coords can hold valuator->numMotionEvents - * events. This routine is called from \a Xi/gtmotion.c with coords large - * enough to hold the same number of events in a variable-length - * extended \a xTimecoord structure. This provides sufficient data for the - * \a XGetDeviceMotionEvents library call, and would be identical to - * \a miPointerGetMotionEvents for devices with only 2 axes (i.e., core - * pointers) if \a xTimecoord used 32bit integers. - * - * Because DMX uses the mi* routines for all core devices, this routine - * only has to support extension devices using the polymorphic coords. - * Because compatibility with miPointerGetMotionEvents is not possible, - * it is not provided. */ -int dmxPointerGetMotionEvents(DeviceIntPtr pDevice, - xTimecoord *coords, - unsigned long start, - unsigned long stop, - ScreenPtr pScreen) -{ - GETDMXLOCALFROMPDEVICE; - int numAxes = pDevice->valuator->numAxes; - unsigned long *c = (unsigned long *)coords; - int count = 0; - int i, j; - - if (!dmxLocal->history) return 0; - for (i = dmxLocal->head; i != dmxLocal->tail;) { - if (dmxLocal->history[OFFSET(i,0)] >= stop) break; - if (dmxLocal->history[OFFSET(i,0)] >= start) { - for (j = 0; j < numAxes + 1; j++) - c[OFFSET(count,j)] = dmxLocal->history[OFFSET(i,j)]; - ++count; - } - if (++i >= DMX_MOTION_SIZE) i = 0; - } - return count; -} - -/** This routine adds an event to the motion history. A similar - * function is performed by miPointerMove for the mi versions of these - * routines. */ -void dmxPointerPutMotionEvent(DeviceIntPtr pDevice, - int firstAxis, int axesCount, int *v, - unsigned long time) -{ - GETDMXLOCALFROMPDEVICE; - int numAxes = pDevice->valuator->numAxes; - int i; - - if (!dmxLocal->history) { - dmxLocal->history = xalloc(sizeof(*dmxLocal->history) - * (numAxes + 1) - * DMX_MOTION_SIZE); - dmxLocal->head = 0; - dmxLocal->tail = 0; - dmxLocal->valuators = calloc(sizeof(*dmxLocal->valuators), numAxes); - } else { - if (++dmxLocal->tail >= DMX_MOTION_SIZE) dmxLocal->tail = 0; - if (dmxLocal->head == dmxLocal->tail) - if (++dmxLocal->head >= DMX_MOTION_SIZE) dmxLocal->head = 0; - } - - dmxLocal->history[OFFSET(dmxLocal->tail,0)] = time; - - /* Initialize the data from the known - * values (if Absolute) or to zero (if - * Relative) */ - if (pDevice->valuator->mode == Absolute) { - for (i = 0; i < numAxes; i++) - dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] - = dmxLocal->valuators[i]; - } else { - for (i = 0; i < numAxes; i++) - dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] = 0; - } - - for (i = firstAxis; i < axesCount; i++) { - dmxLocal->history[OFFSET(dmxLocal->tail,i+i)] - = (unsigned long)v[i-firstAxis]; - dmxLocal->valuators[i] = v[i-firstAxis]; - } -} +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * This file provides functions similar to miPointerGetMotionEvents and + * miPointerPutMotionEvents, with the exception that devices with more + * than two axes are fully supported. These routines may be used only + * for motion buffers for extension devices, and are \a not compatible + * replacements for the mi routines. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "inputstr.h" +#include "dmxinputinit.h" +#include "dmxcommon.h" +#include "dmxmotion.h" + +#define OFFSET(offset,element) ((offset) * (numAxes + 1) + (element)) + +/** Return size of motion buffer. \see DMX_MOTION_SIZE */ +int dmxPointerGetMotionBufferSize(void) +{ + return DMX_MOTION_SIZE; +} + +/** This routine performs the same function as \a miPointerGetMotionEvents: + * the events in the motion history that are between the start and stop + * times (in mS) are placed in the coords vector, and the count of the + * number of items so placed is returned. This routine is called from + * dix/devices.c so that coords can hold valuator->numMotionEvents + * events. This routine is called from \a Xi/gtmotion.c with coords large + * enough to hold the same number of events in a variable-length + * extended \a xTimecoord structure. This provides sufficient data for the + * \a XGetDeviceMotionEvents library call, and would be identical to + * \a miPointerGetMotionEvents for devices with only 2 axes (i.e., core + * pointers) if \a xTimecoord used 32bit integers. + * + * Because DMX uses the mi* routines for all core devices, this routine + * only has to support extension devices using the polymorphic coords. + * Because compatibility with miPointerGetMotionEvents is not possible, + * it is not provided. */ +int dmxPointerGetMotionEvents(DeviceIntPtr pDevice, + xTimecoord *coords, + unsigned long start, + unsigned long stop, + ScreenPtr pScreen) +{ + GETDMXLOCALFROMPDEVICE; + int numAxes = pDevice->valuator->numAxes; + unsigned long *c = (unsigned long *)coords; + int count = 0; + int i, j; + + if (!dmxLocal->history) return 0; + for (i = dmxLocal->head; i != dmxLocal->tail;) { + if (dmxLocal->history[OFFSET(i,0)] >= stop) break; + if (dmxLocal->history[OFFSET(i,0)] >= start) { + for (j = 0; j < numAxes + 1; j++) + c[OFFSET(count,j)] = dmxLocal->history[OFFSET(i,j)]; + ++count; + } + if (++i >= DMX_MOTION_SIZE) i = 0; + } + return count; +} + +/** This routine adds an event to the motion history. A similar + * function is performed by miPointerMove for the mi versions of these + * routines. */ +void dmxPointerPutMotionEvent(DeviceIntPtr pDevice, + int firstAxis, int axesCount, int *v, + unsigned long time) +{ + GETDMXLOCALFROMPDEVICE; + int numAxes = pDevice->valuator->numAxes; + int i; + + if (!dmxLocal->history) { + dmxLocal->history = malloc(sizeof(*dmxLocal->history) + * (numAxes + 1) + * DMX_MOTION_SIZE); + dmxLocal->head = 0; + dmxLocal->tail = 0; + dmxLocal->valuators = calloc(sizeof(*dmxLocal->valuators), numAxes); + } else { + if (++dmxLocal->tail >= DMX_MOTION_SIZE) dmxLocal->tail = 0; + if (dmxLocal->head == dmxLocal->tail) + if (++dmxLocal->head >= DMX_MOTION_SIZE) dmxLocal->head = 0; + } + + dmxLocal->history[OFFSET(dmxLocal->tail,0)] = time; + + /* Initialize the data from the known + * values (if Absolute) or to zero (if + * Relative) */ + if (pDevice->valuator->mode == Absolute) { + for (i = 0; i < numAxes; i++) + dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] + = dmxLocal->valuators[i]; + } else { + for (i = 0; i < numAxes; i++) + dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] = 0; + } + + for (i = firstAxis; i < axesCount; i++) { + dmxLocal->history[OFFSET(dmxLocal->tail,i+i)] + = (unsigned long)v[i-firstAxis]; + dmxLocal->valuators[i] = v[i-firstAxis]; + } +} diff --git a/xorg-server/hw/dmx/input/lnx-keyboard.c b/xorg-server/hw/dmx/input/lnx-keyboard.c index 939a32f07..11f21e25c 100644 --- a/xorg-server/hw/dmx/input/lnx-keyboard.c +++ b/xorg-server/hw/dmx/input/lnx-keyboard.c @@ -1,990 +1,990 @@ -/* Portions of this file were derived from the following files: - * - ********************************************************************** - * - * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c} - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * - * 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 Thomas Roell not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Thomas Roell makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THOMAS ROELL 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. - * - ********************************************************************** - * - * xfree86/common/xf86KbdLnx.c - * - * Linux version of keymapping setup. The kernel (since 0.99.14) has support - * for fully remapping the keyboard, but there are some differences between - * the Linux map and the SVR4 map (esp. in the extended keycodes). We also - * remove the restriction on what keycodes can be remapped. - * Orest Zborowski. - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * - * 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 Thomas Roell not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Thomas Roell makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THOMAS ROELL 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. - * - ********************************************************************** - * - * xfree86/os-support/linux/lnx_io.c - * - * Copyright 1992 by Orest Zborowski <obz@Kodak.com> - * Copyright 1993 by David Dawes <dawes@xfree86.org> - * - * 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 names of Orest Zborowski and David Dawes - * not be used in advertising or publicity pertaining to distribution of - * the software without specific, written prior permission. Orest Zborowski - * and David Dawes make no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * OREST ZBOROWSKI AND DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID DAWES 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. - * - */ - -/* - * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Rickard E. (Rik) Faith <faith@redhat.com> - * - */ - -/** \file - * - * This code implements a low-level device driver for the Linux - * keyboard. The code is derived from code by Thomas Roell, Orest - * Zborowski, and David Dawes (see the source code for complete - * references). */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -/*****************************************************************************/ -/* Define some macros to make it easier to move this file to another - * part of the Xserver tree. All calls to the dmx* layer are #defined - * here for the .c file. The .h file will also have to be edited. */ -#include "dmxinputinit.h" -#include "lnx-keyboard.h" - -#define GETPRIV myPrivate *priv \ - = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private - -#define LOG0(f) dmxLog(dmxDebug,f) -#define LOG1(f,a) dmxLog(dmxDebug,f,a) -#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define FATAL0(f) dmxLog(dmxFatal,f) -#define FATAL1(f,a) dmxLog(dmxFatal,f,a) -#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) -#define MOTIONPROC dmxMotionProcPtr -#define ENQUEUEPROC dmxEnqueueProcPtr -#define CHECKPROC dmxCheckSpecialProcPtr -#define SWITCHRETPROC dmxVTSwitchReturnProcPtr -#define BLOCK DMXBlockType -#define MESSAGE "\033c\n\n\nDMX taking input from this console..." -#define FINALMESSAGE "\033cDMX terminated." - -/* End of interface definitions. */ -/*****************************************************************************/ - -#include "inputstr.h" -#include <X11/Xos.h> -#include <sys/ioctl.h> -#include <errno.h> -#include <signal.h> -#include <sys/vt.h> -#include <sys/kd.h> -#include <termios.h> -#include "atKeynames.h" -#if 00 -#include "xf86Keymap.h" -#endif -#include <linux/keyboard.h> -#include <xkbsrv.h> - -#define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0])) -#define NUM_STATE_ENTRIES (256/32) - - -/* Private area for Linux-style keyboards. */ -typedef struct _myPrivate { - int fd; - int vtno; - int vtcurrent; - int kbdtrans; - struct termios kbdtty; - int kbdType; - CARD32 kbdState[NUM_STATE_ENTRIES]; - DeviceIntPtr pKeyboard; - unsigned char prefix; - - int switched; - SWITCHRETPROC switch_return; - void *switch_return_data; - - /* For bell */ - int pitch; - unsigned long duration; -} myPrivate; - -static myPrivate *PRIV = NULL; - -#undef SYSCALL -#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) - -static int kbdLinuxKeyDown(myPrivate *priv, int keyCode) -{ - CARD8 byte = keyCode >> 5; - CARD32 bit = 1 << (keyCode & 0x1f); - - if (byte > NUM_STATE_ENTRIES) return 0; - return priv->kbdState[byte] & bit; -} - -static void kbdLinuxKeyState(myPrivate *priv, int type, int keyCode) -{ - CARD8 byte = keyCode >> 5; - CARD32 bit = 1 << (keyCode & 0x1f); - - if (byte > NUM_STATE_ENTRIES) return; - if (type == KeyPress) priv->kbdState[byte] |= bit; - else priv->kbdState[byte] &= ~bit; -} - -static KeySym linux_to_x[256] = { - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, XK_Escape, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - XK_space, XK_exclam, XK_quotedbl, XK_numbersign, - XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, - XK_parenleft, XK_parenright, XK_asterisk, XK_plus, - XK_comma, XK_minus, XK_period, XK_slash, - XK_0, XK_1, XK_2, XK_3, - XK_4, XK_5, XK_6, XK_7, - XK_8, XK_9, XK_colon, XK_semicolon, - XK_less, XK_equal, XK_greater, XK_question, - XK_at, XK_A, XK_B, XK_C, - XK_D, XK_E, XK_F, XK_G, - XK_H, XK_I, XK_J, XK_K, - XK_L, XK_M, XK_N, XK_O, - XK_P, XK_Q, XK_R, XK_S, - XK_T, XK_U, XK_V, XK_W, - XK_X, XK_Y, XK_Z, XK_bracketleft, - XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore, - XK_grave, XK_a, XK_b, XK_c, - XK_d, XK_e, XK_f, XK_g, - XK_h, XK_i, XK_j, XK_k, - XK_l, XK_m, XK_n, XK_o, - XK_p, XK_q, XK_r, XK_s, - XK_t, XK_u, XK_v, XK_w, - XK_x, XK_y, XK_z, XK_braceleft, - XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling, - XK_currency, XK_yen, XK_brokenbar, XK_section, - XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, - XK_notsign, XK_hyphen, XK_registered, XK_macron, - XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, - XK_acute, XK_mu, XK_paragraph, XK_periodcentered, - XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, - XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown, - XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, - XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, - XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, - XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, - XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, - XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, - XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, - XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, - XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, - XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, - XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, - XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, - XK_eth, XK_ntilde, XK_ograve, XK_oacute, - XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, - XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, - XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis -}; - -/* - * Maps the AT keycodes to Linux keycodes - */ -static unsigned char at2lnx[NUM_KEYCODES] = -{ - 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ - 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ - 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ - 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ - 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ - 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ - 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ - 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ - 0x11, /* KEY_W */ 0x12, /* KEY_E */ - 0x13, /* KEY_R */ 0x14, /* KEY_T */ - 0x15, /* KEY_Y */ 0x16, /* KEY_U */ - 0x17, /* KEY_I */ 0x18, /* KEY_O */ - 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ - 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ - 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ - 0x1f, /* KEY_S */ 0x20, /* KEY_D */ - 0x21, /* KEY_F */ 0x22, /* KEY_G */ - 0x23, /* KEY_H */ 0x24, /* KEY_J */ - 0x25, /* KEY_K */ 0x26, /* KEY_L */ - 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ - 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ - 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ - 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ - 0x2f, /* KEY_V */ 0x30, /* KEY_B */ - 0x31, /* KEY_N */ 0x32, /* KEY_M */ - 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ - 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ - 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ - 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ - 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ - 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ - 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ - 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ - 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ - 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ - 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ - 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ - 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ - 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ - 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ - 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ - 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ - 0x00, /* 0x55 */ 0x56, /* KEY_Less */ - 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ - 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ - 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ - 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ - 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ - 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ - 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ - 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ - 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ - 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ - 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ - 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ - 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ - 0x00, /* 0x71 */ 0x00, /* 0x72 */ - 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ - 0x00, /* 0x75 */ 0x00, /* 0x76 */ - 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ - 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ - 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ - 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ - 0x00, /* 0x7f */ -}; - -/** Create a private structure for use within this file. */ -pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard) -{ - myPrivate *priv = calloc(1, sizeof(*priv)); - priv->fd = -1; - priv->pKeyboard = pKeyboard; - return priv; -} - -/** Destroy a private structure. */ -void kbdLinuxDestroyPrivate(pointer priv) -{ - if (priv) free(priv); -} - -/** Ring the bell. - * - * Note: we completely ignore the \a volume, since Linux's ioctl() - * interface does not provide a way to control it. If it did, the XBell - * manpage tells how the actual volume is a function of the percent and - * the (base) volume. - * - * Note that most of the other PC-based bell drivers compute the - * duration for KDMKTONE as a function of the volume and the duration. - * For some drivers, the duration is only measured in mS if the volume - * is 50, and is scaled by the volume for other values. This seems - * confusing and possibly incorrect (the xset man page says that the - * bell will be "as closely as it can to the user's specifications" -- - * if we ignore the volume and set the duration correctly, then we'll - * get one parameter "wrong" -- but if we use the volume to scale the - * duration, then we'll get both parameters "wrong"). */ -void kbdLinuxBell(DevicePtr pDev, int percent, - int volume, int pitch, int duration) -{ - GETPRIV; - - if (duration && pitch) { - ioctl(priv->fd, - KDMKTONE, - ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */ - | (duration << 16)); /* High bits are duration in msec */ - } -} - -/** Set the LEDs. */ -void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl) -{ - GETPRIV; - - ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07); -} - -static int kbdLinuxGetFreeVTNumber(void) -{ - int fd = -1; - int vtno; - int i; - const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; - - for (i = 0; tty0[i]; i++) - if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0) break; - if (fd < 0) - FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n", - strerror(errno)); - if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0) - FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n"); - return vtno; -} - -static int kbdLinuxOpenVT(int vtno) -{ - int fd = -1; - int i; - const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; - char name[64]; /* RATS: Only used in XmuSnprintf */ - - for (i = 0; vcs[i]; i++) { - XmuSnprintf(name, sizeof(name), vcs[i], vtno); - if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) break; - } - if (fd < 0) - FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n", - vtno, strerror(errno)); - return fd; -} - -static int kbdLinuxGetCurrentVTNumber(int fd) -{ - struct vt_stat vts; - - if (!ioctl(fd, VT_GETSTATE, &vts)) return vts.v_active; - return -1; -} - -static int kbdLinuxActivate(int fd, int vtno, int setSig); - -/** Currently unused hook called prior to an VT switch. */ -void kbdLinuxVTPreSwitch(pointer p) -{ -} - -/** Currently unused hook called after returning from a VT switch. */ -void kbdLinuxVTPostSwitch(pointer p) -{ -} - -/** Tell the operating system to switch to \a vt. The \a switch_return - * function is called with the \a switch_return_data when the VT is - * switched back to the pre-switch VT (i.e., the user returns to the DMX - * session). */ -int kbdLinuxVTSwitch(pointer p, int vt, - void (*switch_return)(pointer), - pointer switch_return_data) -{ - myPrivate *priv = p; - - if (priv->switched) FATAL0("kbdLinuxVTSwitch: already switched...\n"); - if (priv->vtno == vt) return 0; - - PRIV = priv; - priv->switched = 0; /* Will switch to 1 in handler */ - priv->switch_return = switch_return; - priv->switch_return_data = switch_return_data; - kbdLinuxActivate(priv->fd, vt, 0); - return 1; -} - -/* RATS: This function is only ever used to handle SIGUSR1. */ -static void kbdLinuxVTSignalHandler(int sig) -{ - myPrivate *priv = PRIV; - - signal(sig, kbdLinuxVTSignalHandler); - if (priv) { - ioctl(priv->fd, VT_RELDISP, VT_ACKACQ); - priv->switched = !priv->switched; - LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n", - sig, priv->switched); - if (!priv->switched && priv->switch_return) - priv->switch_return(priv->switch_return_data); - } -} - -static int kbdLinuxActivate(int fd, int vtno, int setSig) -{ - int result; - struct vt_mode VT; - - SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno)); - if (result) FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n"); - SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno)); - if (result) FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n"); - if (setSig) { - SYSCALL(result = ioctl(fd, VT_GETMODE, &VT)); - if (result < 0) FATAL0("kbdLinuxActivate: VT_GETMODE failed\n"); - VT.mode = VT_PROCESS; - VT.relsig = SIGUSR1; - VT.acqsig = SIGUSR1; - if (ioctl(fd, VT_SETMODE, &VT)) - FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n"); - signal(SIGUSR1, kbdLinuxVTSignalHandler); - } - return Success; -} - -static void kbdLinuxOpenConsole(DevicePtr pDev) -{ - GETPRIV; - const char *msg = MESSAGE; - - if (priv->fd >= 0) return; - priv->vtno = kbdLinuxGetFreeVTNumber(); - priv->fd = kbdLinuxOpenVT(priv->vtno); - priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd); - LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n", - priv->vtcurrent, priv->vtno); - kbdLinuxActivate(priv->fd, priv->vtno, 1); - ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */ - if (msg) write(priv->fd, msg, strlen(msg)); -} - -static void kbdLinuxCloseConsole(DevicePtr pDev) -{ - GETPRIV; - struct vt_mode VT; - const char *msg = FINALMESSAGE; - - if (priv->fd < 0) return; - - ioctl(priv->fd, KDSETMODE, KD_TEXT); - if (msg) write(priv->fd, msg, strlen(msg)); - if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) { - VT.mode = VT_AUTO; - ioctl(priv->fd, VT_SETMODE, &VT); - } - - LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent); - if (priv->vtcurrent >= 0) kbdLinuxActivate(priv->fd, priv->vtcurrent, 0); - - close(priv->fd); - priv->fd = -1; -} - -/** Initialize the \a pDev as a Linux keyboard. */ -void kbdLinuxInit(DevicePtr pDev) -{ - GETPRIV; - - if (priv->fd <= 0) kbdLinuxOpenConsole(pDev); - - ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans); - if (tcgetattr(priv->fd, &priv->kbdtty) < 0) - FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); -} - -static int kbdLinuxPrefix0Mapping(unsigned char *scanCode) -{ - /* Table from xfree86/common/xf86Events.c */ - switch (*scanCode) { - case KEY_KP_7: *scanCode = KEY_Home; break; /* curs home */ - case KEY_KP_8: *scanCode = KEY_Up; break; /* curs up */ - case KEY_KP_9: *scanCode = KEY_PgUp; break; /* curs pgup */ - case KEY_KP_4: *scanCode = KEY_Left; break; /* curs left */ - case KEY_KP_5: *scanCode = KEY_Begin; break; /* curs begin */ - case KEY_KP_6: *scanCode = KEY_Right; break; /* curs right */ - case KEY_KP_1: *scanCode = KEY_End; break; /* curs end */ - case KEY_KP_2: *scanCode = KEY_Down; break; /* curs down */ - case KEY_KP_3: *scanCode = KEY_PgDown; break; /* curs pgdown */ - case KEY_KP_0: *scanCode = KEY_Insert; break; /* curs insert */ - case KEY_KP_Decimal: *scanCode = KEY_Delete; break; /* curs delete */ - case KEY_Enter: *scanCode = KEY_KP_Enter; break; /* keypad enter */ - case KEY_LCtrl: *scanCode = KEY_RCtrl; break; /* right ctrl */ - case KEY_KP_Multiply: *scanCode = KEY_Print; break; /* print */ - case KEY_Slash: *scanCode = KEY_KP_Divide; break; /* keyp divide */ - case KEY_Alt: *scanCode = KEY_AltLang; break; /* right alt */ - case KEY_ScrollLock: *scanCode = KEY_Break; break; /* curs break */ - case 0x5b: *scanCode = KEY_LMeta; break; - case 0x5c: *scanCode = KEY_RMeta; break; - case 0x5d: *scanCode = KEY_Menu; break; - case KEY_F3: *scanCode = KEY_F13; break; - case KEY_F4: *scanCode = KEY_F14; break; - case KEY_F5: *scanCode = KEY_F15; break; - case KEY_F6: *scanCode = KEY_F16; break; - case KEY_F7: *scanCode = KEY_F17; break; - case KEY_KP_Plus: *scanCode = KEY_KP_DEC; break; - /* - * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) - */ - case 0x2A: - case 0x36: - return 1; - default: - /* - * "Internet" keyboards are generating lots of new codes. - * Let them pass. There is little consistency between them, - * so don't bother with symbolic names at this level. - */ - scanCode += 0x78; - } - return 0; -} - -static int kbdLinuxPrefixMapping(myPrivate *priv, unsigned char *scanCode) -{ - int pressed = *scanCode & 0x80; - unsigned char code = *scanCode & 0x7f; - - /* If we don't have a prefix, check for one */ - if (!priv->prefix) { - switch (code) { - case KEY_Prefix0: - case KEY_Prefix1: - priv->prefix = code; - return 1; - } - return 0; /* No change */ - } - - /* We have a prefix from the last scanCode */ - switch (priv->prefix) { - case KEY_Prefix0: - priv->prefix = 0; - if (kbdLinuxPrefix0Mapping(&code)) return 1; /* Skip sequence */ - break; - case KEY_Prefix1: - priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0; - return 1; /* Use new prefix */ - case KEY_LCtrl: - priv->prefix = 0; - if (code != KEY_NumLock) return 1; /* Skip sequence*/ - code = KEY_Pause; - break; - } - - *scanCode = code | (pressed ? 0x80 : 0x00); - return 0; /* Use old scanCode */ -} - -static void kbdLinuxConvert(DevicePtr pDev, - unsigned char scanCode, - ENQUEUEPROC enqueue, - CHECKPROC checkspecial, - BLOCK block) -{ - GETPRIV; - XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; - int type; - KeySym keySym = NoSymbol; - int keyCode; - int switching; - - /* Do special PC/AT prefix mapping -- may change scanCode! */ - if (kbdLinuxPrefixMapping(priv, &scanCode)) return; - - type = (scanCode & 0x80) ? KeyRelease : KeyPress; - keyCode = (scanCode & 0x7f) + MIN_KEYCODE; - - /* Handle repeats */ - - if (keyCode >= xkbi->desc->min_key_code && - keyCode <= xkbi->desc->max_key_code) { - - int effectiveGroup = XkbGetEffectiveGroup(xkbi, - &xkbi->state, - scanCode); - keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); -#if 0 - switch (keySym) { - case XK_Num_Lock: - case XK_Scroll_Lock: - case XK_Shift_Lock: - case XK_Caps_Lock: - /* Ignore releases and all but first press */ - if (kbdLinuxModIgnore(priv, &xE, keySym)) return; - if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; - else xE.u.u.type = KeyPress; - break; - } -#endif - - /* If key is already down, ignore or autorepeat */ - if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) { - KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed; - - /* No auto-repeat? */ - if ((feed && !feed->ctrl.autoRepeat) - || priv->pKeyboard->key->xkbInfo->desc->map->modmap[keyCode] - || (feed - && !(feed->ctrl.autoRepeats[keyCode >> 3] - & (1 << (keyCode & 7))))) return; /* Ignore */ - - /* Do auto-repeat */ - enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); - type = KeyPress; - } - - /* If key is already up, ignore */ - if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode)) return; - } - - switching = 0; - if (checkspecial && type == KeyPress) - switching = checkspecial(pDev, keySym); - if (!switching) { - if (enqueue) - enqueue(pDev, type, keyCode, keySym, NULL, block); - kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */ - } -} - -/** Read an event from the \a pDev device. If the event is a motion - * event, enqueue it with the \a motion function. Otherwise, check for - * special keys with the \a checkspecial function and enqueue the event - * with the \a enqueue function. The \a block type is passed to the - * functions so that they may block SIGIO handling as appropriate to the - * caller of this function. */ -void kbdLinuxRead(DevicePtr pDev, - MOTIONPROC motion, - ENQUEUEPROC enqueue, - CHECKPROC checkspecial, - BLOCK block) -{ - GETPRIV; - unsigned char buf[256]; /* RATS: Only used in length-limited call */ - unsigned char *pt; - int n; - - while ((n = read(priv->fd, buf, sizeof(buf))) > 0) - for (pt = buf; n; --n, ++pt) - kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block); -} - -/** Turn \a pDev on (i.e., take input from \a pDev). */ -int kbdLinuxOn(DevicePtr pDev) -{ - GETPRIV; - struct termios nTty; - - ioctl(priv->fd, KDSKBMODE, K_RAW); - - nTty = priv->kbdtty; - nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); - nTty.c_oflag = 0; - nTty.c_cflag = CREAD | CS8; - nTty.c_lflag = 0; - nTty.c_cc[VTIME] = 0; - nTty.c_cc[VMIN] = 1; - cfsetispeed(&nTty, B9600); - cfsetospeed(&nTty, B9600); - if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) - FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno)); - return priv->fd; -} - -/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ -void kbdLinuxOff(DevicePtr pDev) -{ - GETPRIV; - - ioctl(priv->fd, KDSKBMODE, priv->kbdtrans); - tcsetattr(priv->fd, TCSANOW, &priv->kbdtty); - kbdLinuxCloseConsole(pDev); -} - - -static void kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms) -{ - KeySym *k; - int i; - int maxkey; - static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */ - 0, /* unshifted */ - 1, /* shifted */ - 0, /* modeswitch unshifted */ - 0 /* modeswitch shifted */ - }; - - /* - * Read the mapping from the kernel. - * Since we're still using the XFree86 scancode->AT keycode mapping - * routines, we need to convert the AT keycodes to Linux keycodes, - * then translate the Linux keysyms into X keysyms. - * - * First, figure out which tables to use for the modeswitch columns - * above, from the XF86Config fields. - */ - tbl[2] = 8; /* alt */ - tbl[3] = tbl[2] | 1; - -#if 00/*BP*/ - k = map+GLYPHS_PER_KEY; -#else - ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n"); - return; -#endif - maxkey = NUM_AT2LNX; - - for (i = 0; i < maxkey; ++i) { - struct kbentry kbe; - int j; - - kbe.kb_index = at2lnx[i]; - - for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) { - unsigned short kval; - - *k = NoSymbol; - - kbe.kb_table = tbl[j]; - if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) continue; - - kval = KVAL(kbe.kb_value); - switch (KTYP(kbe.kb_value)) { - case KT_LATIN: - case KT_LETTER: *k = linux_to_x[kval]; break; - case KT_FN: - if (kval <= 19) *k = XK_F1 + kval; - else switch (kbe.kb_value) { - case K_FIND: *k = XK_Home; /* or XK_Find */ break; - case K_INSERT: *k = XK_Insert; break; - case K_REMOVE: *k = XK_Delete; break; - case K_SELECT: *k = XK_End; /* or XK_Select */ break; - case K_PGUP: *k = XK_Prior; break; - case K_PGDN: *k = XK_Next; break; - case K_HELP: *k = XK_Help; break; - case K_DO: *k = XK_Execute; break; - case K_PAUSE: *k = XK_Pause; break; - case K_MACRO: *k = XK_Menu; break; - default: break; - } - break; - case KT_SPEC: - switch (kbe.kb_value) { - case K_ENTER: *k = XK_Return; break; - case K_BREAK: *k = XK_Break; break; - case K_CAPS: *k = XK_Caps_Lock; break; - case K_NUM: *k = XK_Num_Lock; break; - case K_HOLD: *k = XK_Scroll_Lock; break; - case K_COMPOSE: *k = XK_Multi_key; break; - default: break; - } - break; - case KT_PAD: - switch (kbe.kb_value) { - case K_PPLUS: *k = XK_KP_Add; break; - case K_PMINUS: *k = XK_KP_Subtract; break; - case K_PSTAR: *k = XK_KP_Multiply; break; - case K_PSLASH: *k = XK_KP_Divide; break; - case K_PENTER: *k = XK_KP_Enter; break; - case K_PCOMMA: *k = XK_KP_Separator; break; - case K_PDOT: *k = XK_KP_Decimal; break; - case K_PPLUSMINUS: *k = XK_KP_Subtract; break; - default: if (kval <= 9) *k = XK_KP_0 + kval; break; - } - break; - case KT_DEAD: - /* KT_DEAD keys are for accelerated diacritical creation. */ - switch (kbe.kb_value) { - case K_DGRAVE: *k = XK_dead_grave; break; - case K_DACUTE: *k = XK_dead_acute; break; - case K_DCIRCM: *k = XK_dead_circumflex; break; - case K_DTILDE: *k = XK_dead_tilde; break; - case K_DDIERE: *k = XK_dead_diaeresis; break; - } - break; - case KT_CUR: - switch (kbe.kb_value) { - case K_DOWN: *k = XK_Down; break; - case K_LEFT: *k = XK_Left; break; - case K_RIGHT: *k = XK_Right; break; - case K_UP: *k = XK_Up; break; - } - break; - case KT_SHIFT: - switch (kbe.kb_value) { - case K_ALTGR: *k = XK_Alt_R; break; - case K_ALT: - *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L); - break; - case K_CTRL: - *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L); - break; - case K_CTRLL: *k = XK_Control_L; break; - case K_CTRLR: *k = XK_Control_R; break; - case K_SHIFT: - *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L); - break; - case K_SHIFTL: *k = XK_Shift_L; break; - case K_SHIFTR: *k = XK_Shift_R; break; - default: break; - } - break; - case KT_ASCII: - /* KT_ASCII keys accumulate a 3 digit decimal number that - * gets emitted when the shift state changes. We can't - * emulate that. - */ - break; - case KT_LOCK: - if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock; - break; - default: break; - } - } - - if (k[-1] == k[-2]) k[-1] = NoSymbol; - if (k[-2] == k[-3]) k[-2] = NoSymbol; - if (k[-3] == k[-4]) k[-3] = NoSymbol; - if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol; - if (k[-1] == k[-4] && k[-2] == k[-3] - && k[-2] == NoSymbol) k[-1] = NoSymbol; - } -} - -static void kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) -{ - GETPRIV; - KeySym *k, *mapCopy; - char type; - int i; - -#if 00/*BP*/ - mapCopy = xalloc(sizeof(map)); - memcpy(mapCopy, map, sizeof(map)); -#else - ErrorF("kbdLinuxGetMap() is broken/no-op'd\n"); - return; -#endif - - kbdLinuxReadKernelMapping(priv->fd, pKeySyms); - - /* compute the modifier map */ - for (i = 0; i < MAP_LENGTH; i++) - pModMap[i] = NoSymbol; /* make sure it is restored */ - - for (k = mapCopy, i = MIN_KEYCODE; - i < NUM_KEYCODES + MIN_KEYCODE; - i++, k += 4) { - switch(*k) { - case XK_Shift_L: - case XK_Shift_R: pModMap[i] = ShiftMask; break; - case XK_Control_L: - case XK_Control_R: pModMap[i] = ControlMask; break; - case XK_Caps_Lock: pModMap[i] = LockMask; break; - case XK_Alt_L: - case XK_Alt_R: pModMap[i] = AltMask; break; - case XK_Num_Lock: pModMap[i] = NumLockMask; break; - case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; - case XK_Kana_Lock: - case XK_Kana_Shift: pModMap[i] = KanaMask; break; - case XK_Mode_switch: pModMap[i] = AltLangMask; break; - } - } - - priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type; - - pKeySyms->map = mapCopy; /* Must be XFree'able */ - pKeySyms->mapWidth = GLYPHS_PER_KEY; - pKeySyms->minKeyCode = MIN_KEYCODE; - pKeySyms->maxKeyCode = MAX_KEYCODE; -} - -/** Fill the \a info structure with information needed to initialize \a - * pDev. */ -void kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) -{ - info->keyboard = 1; - info->keyClass = 1; - kbdLinuxGetMap(pDev, &info->keySyms, info->modMap); - info->focusClass = 1; - info->kbdFeedbackClass = 1; -} +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c} + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * 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 Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL 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. + * + ********************************************************************** + * + * xfree86/common/xf86KbdLnx.c + * + * Linux version of keymapping setup. The kernel (since 0.99.14) has support + * for fully remapping the keyboard, but there are some differences between + * the Linux map and the SVR4 map (esp. in the extended keycodes). We also + * remove the restriction on what keycodes can be remapped. + * Orest Zborowski. + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * 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 Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL 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. + * + ********************************************************************** + * + * xfree86/os-support/linux/lnx_io.c + * + * Copyright 1992 by Orest Zborowski <obz@Kodak.com> + * Copyright 1993 by David Dawes <dawes@xfree86.org> + * + * 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 names of Orest Zborowski and David Dawes + * not be used in advertising or publicity pertaining to distribution of + * the software without specific, written prior permission. Orest Zborowski + * and David Dawes make no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * OREST ZBOROWSKI AND DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID DAWES 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. + * + */ + +/* + * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for the Linux + * keyboard. The code is derived from code by Thomas Roell, Orest + * Zborowski, and David Dawes (see the source code for complete + * references). */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "dmxinputinit.h" +#include "lnx-keyboard.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define SWITCHRETPROC dmxVTSwitchReturnProcPtr +#define BLOCK DMXBlockType +#define MESSAGE "\033c\n\n\nDMX taking input from this console..." +#define FINALMESSAGE "\033cDMX terminated." + +/* End of interface definitions. */ +/*****************************************************************************/ + +#include "inputstr.h" +#include <X11/Xos.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <signal.h> +#include <sys/vt.h> +#include <sys/kd.h> +#include <termios.h> +#include "atKeynames.h" +#if 00 +#include "xf86Keymap.h" +#endif +#include <linux/keyboard.h> +#include <xkbsrv.h> + +#define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0])) +#define NUM_STATE_ENTRIES (256/32) + + +/* Private area for Linux-style keyboards. */ +typedef struct _myPrivate { + int fd; + int vtno; + int vtcurrent; + int kbdtrans; + struct termios kbdtty; + int kbdType; + CARD32 kbdState[NUM_STATE_ENTRIES]; + DeviceIntPtr pKeyboard; + unsigned char prefix; + + int switched; + SWITCHRETPROC switch_return; + void *switch_return_data; + + /* For bell */ + int pitch; + unsigned long duration; +} myPrivate; + +static myPrivate *PRIV = NULL; + +#undef SYSCALL +#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) + +static int kbdLinuxKeyDown(myPrivate *priv, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return 0; + return priv->kbdState[byte] & bit; +} + +static void kbdLinuxKeyState(myPrivate *priv, int type, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return; + if (type == KeyPress) priv->kbdState[byte] |= bit; + else priv->kbdState[byte] &= ~bit; +} + +static KeySym linux_to_x[256] = { + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, XK_Escape, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_space, XK_exclam, XK_quotedbl, XK_numbersign, + XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, + XK_parenleft, XK_parenright, XK_asterisk, XK_plus, + XK_comma, XK_minus, XK_period, XK_slash, + XK_0, XK_1, XK_2, XK_3, + XK_4, XK_5, XK_6, XK_7, + XK_8, XK_9, XK_colon, XK_semicolon, + XK_less, XK_equal, XK_greater, XK_question, + XK_at, XK_A, XK_B, XK_C, + XK_D, XK_E, XK_F, XK_G, + XK_H, XK_I, XK_J, XK_K, + XK_L, XK_M, XK_N, XK_O, + XK_P, XK_Q, XK_R, XK_S, + XK_T, XK_U, XK_V, XK_W, + XK_X, XK_Y, XK_Z, XK_bracketleft, + XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore, + XK_grave, XK_a, XK_b, XK_c, + XK_d, XK_e, XK_f, XK_g, + XK_h, XK_i, XK_j, XK_k, + XK_l, XK_m, XK_n, XK_o, + XK_p, XK_q, XK_r, XK_s, + XK_t, XK_u, XK_v, XK_w, + XK_x, XK_y, XK_z, XK_braceleft, + XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling, + XK_currency, XK_yen, XK_brokenbar, XK_section, + XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, + XK_notsign, XK_hyphen, XK_registered, XK_macron, + XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, + XK_acute, XK_mu, XK_paragraph, XK_periodcentered, + XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, + XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown, + XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, + XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, + XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, + XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, + XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, + XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, + XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, + XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, + XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, + XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, + XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, + XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, + XK_eth, XK_ntilde, XK_ograve, XK_oacute, + XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, + XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, + XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis +}; + +/* + * Maps the AT keycodes to Linux keycodes + */ +static unsigned char at2lnx[NUM_KEYCODES] = +{ + 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ + 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ + 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ + 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ + 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ + 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ + 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ + 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ + 0x11, /* KEY_W */ 0x12, /* KEY_E */ + 0x13, /* KEY_R */ 0x14, /* KEY_T */ + 0x15, /* KEY_Y */ 0x16, /* KEY_U */ + 0x17, /* KEY_I */ 0x18, /* KEY_O */ + 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ + 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ + 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ + 0x1f, /* KEY_S */ 0x20, /* KEY_D */ + 0x21, /* KEY_F */ 0x22, /* KEY_G */ + 0x23, /* KEY_H */ 0x24, /* KEY_J */ + 0x25, /* KEY_K */ 0x26, /* KEY_L */ + 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ + 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ + 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ + 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ + 0x2f, /* KEY_V */ 0x30, /* KEY_B */ + 0x31, /* KEY_N */ 0x32, /* KEY_M */ + 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ + 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ + 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ + 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ + 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ + 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ + 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ + 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ + 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ + 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ + 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ + 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ + 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ + 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ + 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ + 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ + 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ + 0x00, /* 0x55 */ 0x56, /* KEY_Less */ + 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ + 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ + 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ + 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ + 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ + 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ + 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ + 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ + 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ + 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ + 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ + 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ + 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ + 0x00, /* 0x71 */ 0x00, /* 0x72 */ + 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ + 0x00, /* 0x75 */ 0x00, /* 0x76 */ + 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ + 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ + 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ + 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ + 0x00, /* 0x7f */ +}; + +/** Create a private structure for use within this file. */ +pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard) +{ + myPrivate *priv = calloc(1, sizeof(*priv)); + priv->fd = -1; + priv->pKeyboard = pKeyboard; + return priv; +} + +/** Destroy a private structure. */ +void kbdLinuxDestroyPrivate(pointer priv) +{ + if (priv) free(priv); +} + +/** Ring the bell. + * + * Note: we completely ignore the \a volume, since Linux's ioctl() + * interface does not provide a way to control it. If it did, the XBell + * manpage tells how the actual volume is a function of the percent and + * the (base) volume. + * + * Note that most of the other PC-based bell drivers compute the + * duration for KDMKTONE as a function of the volume and the duration. + * For some drivers, the duration is only measured in mS if the volume + * is 50, and is scaled by the volume for other values. This seems + * confusing and possibly incorrect (the xset man page says that the + * bell will be "as closely as it can to the user's specifications" -- + * if we ignore the volume and set the duration correctly, then we'll + * get one parameter "wrong" -- but if we use the volume to scale the + * duration, then we'll get both parameters "wrong"). */ +void kbdLinuxBell(DevicePtr pDev, int percent, + int volume, int pitch, int duration) +{ + GETPRIV; + + if (duration && pitch) { + ioctl(priv->fd, + KDMKTONE, + ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */ + | (duration << 16)); /* High bits are duration in msec */ + } +} + +/** Set the LEDs. */ +void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl) +{ + GETPRIV; + + ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07); +} + +static int kbdLinuxGetFreeVTNumber(void) +{ + int fd = -1; + int vtno; + int i; + const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; + + for (i = 0; tty0[i]; i++) + if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0) break; + if (fd < 0) + FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n", + strerror(errno)); + if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0) + FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n"); + return vtno; +} + +static int kbdLinuxOpenVT(int vtno) +{ + int fd = -1; + int i; + const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; + char name[64]; /* RATS: Only used in XmuSnprintf */ + + for (i = 0; vcs[i]; i++) { + XmuSnprintf(name, sizeof(name), vcs[i], vtno); + if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) break; + } + if (fd < 0) + FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n", + vtno, strerror(errno)); + return fd; +} + +static int kbdLinuxGetCurrentVTNumber(int fd) +{ + struct vt_stat vts; + + if (!ioctl(fd, VT_GETSTATE, &vts)) return vts.v_active; + return -1; +} + +static int kbdLinuxActivate(int fd, int vtno, int setSig); + +/** Currently unused hook called prior to an VT switch. */ +void kbdLinuxVTPreSwitch(pointer p) +{ +} + +/** Currently unused hook called after returning from a VT switch. */ +void kbdLinuxVTPostSwitch(pointer p) +{ +} + +/** Tell the operating system to switch to \a vt. The \a switch_return + * function is called with the \a switch_return_data when the VT is + * switched back to the pre-switch VT (i.e., the user returns to the DMX + * session). */ +int kbdLinuxVTSwitch(pointer p, int vt, + void (*switch_return)(pointer), + pointer switch_return_data) +{ + myPrivate *priv = p; + + if (priv->switched) FATAL0("kbdLinuxVTSwitch: already switched...\n"); + if (priv->vtno == vt) return 0; + + PRIV = priv; + priv->switched = 0; /* Will switch to 1 in handler */ + priv->switch_return = switch_return; + priv->switch_return_data = switch_return_data; + kbdLinuxActivate(priv->fd, vt, 0); + return 1; +} + +/* RATS: This function is only ever used to handle SIGUSR1. */ +static void kbdLinuxVTSignalHandler(int sig) +{ + myPrivate *priv = PRIV; + + signal(sig, kbdLinuxVTSignalHandler); + if (priv) { + ioctl(priv->fd, VT_RELDISP, VT_ACKACQ); + priv->switched = !priv->switched; + LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n", + sig, priv->switched); + if (!priv->switched && priv->switch_return) + priv->switch_return(priv->switch_return_data); + } +} + +static int kbdLinuxActivate(int fd, int vtno, int setSig) +{ + int result; + struct vt_mode VT; + + SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno)); + if (result) FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n"); + SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno)); + if (result) FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n"); + if (setSig) { + SYSCALL(result = ioctl(fd, VT_GETMODE, &VT)); + if (result < 0) FATAL0("kbdLinuxActivate: VT_GETMODE failed\n"); + VT.mode = VT_PROCESS; + VT.relsig = SIGUSR1; + VT.acqsig = SIGUSR1; + if (ioctl(fd, VT_SETMODE, &VT)) + FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n"); + signal(SIGUSR1, kbdLinuxVTSignalHandler); + } + return Success; +} + +static void kbdLinuxOpenConsole(DevicePtr pDev) +{ + GETPRIV; + const char *msg = MESSAGE; + + if (priv->fd >= 0) return; + priv->vtno = kbdLinuxGetFreeVTNumber(); + priv->fd = kbdLinuxOpenVT(priv->vtno); + priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd); + LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n", + priv->vtcurrent, priv->vtno); + kbdLinuxActivate(priv->fd, priv->vtno, 1); + ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */ + if (msg) write(priv->fd, msg, strlen(msg)); +} + +static void kbdLinuxCloseConsole(DevicePtr pDev) +{ + GETPRIV; + struct vt_mode VT; + const char *msg = FINALMESSAGE; + + if (priv->fd < 0) return; + + ioctl(priv->fd, KDSETMODE, KD_TEXT); + if (msg) write(priv->fd, msg, strlen(msg)); + if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) { + VT.mode = VT_AUTO; + ioctl(priv->fd, VT_SETMODE, &VT); + } + + LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent); + if (priv->vtcurrent >= 0) kbdLinuxActivate(priv->fd, priv->vtcurrent, 0); + + close(priv->fd); + priv->fd = -1; +} + +/** Initialize the \a pDev as a Linux keyboard. */ +void kbdLinuxInit(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd <= 0) kbdLinuxOpenConsole(pDev); + + ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans); + if (tcgetattr(priv->fd, &priv->kbdtty) < 0) + FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); +} + +static int kbdLinuxPrefix0Mapping(unsigned char *scanCode) +{ + /* Table from xfree86/common/xf86Events.c */ + switch (*scanCode) { + case KEY_KP_7: *scanCode = KEY_Home; break; /* curs home */ + case KEY_KP_8: *scanCode = KEY_Up; break; /* curs up */ + case KEY_KP_9: *scanCode = KEY_PgUp; break; /* curs pgup */ + case KEY_KP_4: *scanCode = KEY_Left; break; /* curs left */ + case KEY_KP_5: *scanCode = KEY_Begin; break; /* curs begin */ + case KEY_KP_6: *scanCode = KEY_Right; break; /* curs right */ + case KEY_KP_1: *scanCode = KEY_End; break; /* curs end */ + case KEY_KP_2: *scanCode = KEY_Down; break; /* curs down */ + case KEY_KP_3: *scanCode = KEY_PgDown; break; /* curs pgdown */ + case KEY_KP_0: *scanCode = KEY_Insert; break; /* curs insert */ + case KEY_KP_Decimal: *scanCode = KEY_Delete; break; /* curs delete */ + case KEY_Enter: *scanCode = KEY_KP_Enter; break; /* keypad enter */ + case KEY_LCtrl: *scanCode = KEY_RCtrl; break; /* right ctrl */ + case KEY_KP_Multiply: *scanCode = KEY_Print; break; /* print */ + case KEY_Slash: *scanCode = KEY_KP_Divide; break; /* keyp divide */ + case KEY_Alt: *scanCode = KEY_AltLang; break; /* right alt */ + case KEY_ScrollLock: *scanCode = KEY_Break; break; /* curs break */ + case 0x5b: *scanCode = KEY_LMeta; break; + case 0x5c: *scanCode = KEY_RMeta; break; + case 0x5d: *scanCode = KEY_Menu; break; + case KEY_F3: *scanCode = KEY_F13; break; + case KEY_F4: *scanCode = KEY_F14; break; + case KEY_F5: *scanCode = KEY_F15; break; + case KEY_F6: *scanCode = KEY_F16; break; + case KEY_F7: *scanCode = KEY_F17; break; + case KEY_KP_Plus: *scanCode = KEY_KP_DEC; break; + /* + * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) + */ + case 0x2A: + case 0x36: + return 1; + default: + /* + * "Internet" keyboards are generating lots of new codes. + * Let them pass. There is little consistency between them, + * so don't bother with symbolic names at this level. + */ + scanCode += 0x78; + } + return 0; +} + +static int kbdLinuxPrefixMapping(myPrivate *priv, unsigned char *scanCode) +{ + int pressed = *scanCode & 0x80; + unsigned char code = *scanCode & 0x7f; + + /* If we don't have a prefix, check for one */ + if (!priv->prefix) { + switch (code) { + case KEY_Prefix0: + case KEY_Prefix1: + priv->prefix = code; + return 1; + } + return 0; /* No change */ + } + + /* We have a prefix from the last scanCode */ + switch (priv->prefix) { + case KEY_Prefix0: + priv->prefix = 0; + if (kbdLinuxPrefix0Mapping(&code)) return 1; /* Skip sequence */ + break; + case KEY_Prefix1: + priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0; + return 1; /* Use new prefix */ + case KEY_LCtrl: + priv->prefix = 0; + if (code != KEY_NumLock) return 1; /* Skip sequence*/ + code = KEY_Pause; + break; + } + + *scanCode = code | (pressed ? 0x80 : 0x00); + return 0; /* Use old scanCode */ +} + +static void kbdLinuxConvert(DevicePtr pDev, + unsigned char scanCode, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; + int type; + KeySym keySym = NoSymbol; + int keyCode; + int switching; + + /* Do special PC/AT prefix mapping -- may change scanCode! */ + if (kbdLinuxPrefixMapping(priv, &scanCode)) return; + + type = (scanCode & 0x80) ? KeyRelease : KeyPress; + keyCode = (scanCode & 0x7f) + MIN_KEYCODE; + + /* Handle repeats */ + + if (keyCode >= xkbi->desc->min_key_code && + keyCode <= xkbi->desc->max_key_code) { + + int effectiveGroup = XkbGetEffectiveGroup(xkbi, + &xkbi->state, + scanCode); + keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); +#if 0 + switch (keySym) { + case XK_Num_Lock: + case XK_Scroll_Lock: + case XK_Shift_Lock: + case XK_Caps_Lock: + /* Ignore releases and all but first press */ + if (kbdLinuxModIgnore(priv, &xE, keySym)) return; + if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; + else xE.u.u.type = KeyPress; + break; + } +#endif + + /* If key is already down, ignore or autorepeat */ + if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) { + KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed; + + /* No auto-repeat? */ + if ((feed && !feed->ctrl.autoRepeat) + || priv->pKeyboard->key->xkbInfo->desc->map->modmap[keyCode] + || (feed + && !(feed->ctrl.autoRepeats[keyCode >> 3] + & (1 << (keyCode & 7))))) return; /* Ignore */ + + /* Do auto-repeat */ + enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); + type = KeyPress; + } + + /* If key is already up, ignore */ + if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode)) return; + } + + switching = 0; + if (checkspecial && type == KeyPress) + switching = checkspecial(pDev, keySym); + if (!switching) { + if (enqueue) + enqueue(pDev, type, keyCode, keySym, NULL, block); + kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */ + } +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void kbdLinuxRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + unsigned char buf[256]; /* RATS: Only used in length-limited call */ + unsigned char *pt; + int n; + + while ((n = read(priv->fd, buf, sizeof(buf))) > 0) + for (pt = buf; n; --n, ++pt) + kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int kbdLinuxOn(DevicePtr pDev) +{ + GETPRIV; + struct termios nTty; + + ioctl(priv->fd, KDSKBMODE, K_RAW); + + nTty = priv->kbdtty; + nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); + nTty.c_oflag = 0; + nTty.c_cflag = CREAD | CS8; + nTty.c_lflag = 0; + nTty.c_cc[VTIME] = 0; + nTty.c_cc[VMIN] = 1; + cfsetispeed(&nTty, B9600); + cfsetospeed(&nTty, B9600); + if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) + FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno)); + return priv->fd; +} + +/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ +void kbdLinuxOff(DevicePtr pDev) +{ + GETPRIV; + + ioctl(priv->fd, KDSKBMODE, priv->kbdtrans); + tcsetattr(priv->fd, TCSANOW, &priv->kbdtty); + kbdLinuxCloseConsole(pDev); +} + + +static void kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms) +{ + KeySym *k; + int i; + int maxkey; + static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */ + 0, /* unshifted */ + 1, /* shifted */ + 0, /* modeswitch unshifted */ + 0 /* modeswitch shifted */ + }; + + /* + * Read the mapping from the kernel. + * Since we're still using the XFree86 scancode->AT keycode mapping + * routines, we need to convert the AT keycodes to Linux keycodes, + * then translate the Linux keysyms into X keysyms. + * + * First, figure out which tables to use for the modeswitch columns + * above, from the XF86Config fields. + */ + tbl[2] = 8; /* alt */ + tbl[3] = tbl[2] | 1; + +#if 00/*BP*/ + k = map+GLYPHS_PER_KEY; +#else + ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n"); + return; +#endif + maxkey = NUM_AT2LNX; + + for (i = 0; i < maxkey; ++i) { + struct kbentry kbe; + int j; + + kbe.kb_index = at2lnx[i]; + + for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) { + unsigned short kval; + + *k = NoSymbol; + + kbe.kb_table = tbl[j]; + if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) continue; + + kval = KVAL(kbe.kb_value); + switch (KTYP(kbe.kb_value)) { + case KT_LATIN: + case KT_LETTER: *k = linux_to_x[kval]; break; + case KT_FN: + if (kval <= 19) *k = XK_F1 + kval; + else switch (kbe.kb_value) { + case K_FIND: *k = XK_Home; /* or XK_Find */ break; + case K_INSERT: *k = XK_Insert; break; + case K_REMOVE: *k = XK_Delete; break; + case K_SELECT: *k = XK_End; /* or XK_Select */ break; + case K_PGUP: *k = XK_Prior; break; + case K_PGDN: *k = XK_Next; break; + case K_HELP: *k = XK_Help; break; + case K_DO: *k = XK_Execute; break; + case K_PAUSE: *k = XK_Pause; break; + case K_MACRO: *k = XK_Menu; break; + default: break; + } + break; + case KT_SPEC: + switch (kbe.kb_value) { + case K_ENTER: *k = XK_Return; break; + case K_BREAK: *k = XK_Break; break; + case K_CAPS: *k = XK_Caps_Lock; break; + case K_NUM: *k = XK_Num_Lock; break; + case K_HOLD: *k = XK_Scroll_Lock; break; + case K_COMPOSE: *k = XK_Multi_key; break; + default: break; + } + break; + case KT_PAD: + switch (kbe.kb_value) { + case K_PPLUS: *k = XK_KP_Add; break; + case K_PMINUS: *k = XK_KP_Subtract; break; + case K_PSTAR: *k = XK_KP_Multiply; break; + case K_PSLASH: *k = XK_KP_Divide; break; + case K_PENTER: *k = XK_KP_Enter; break; + case K_PCOMMA: *k = XK_KP_Separator; break; + case K_PDOT: *k = XK_KP_Decimal; break; + case K_PPLUSMINUS: *k = XK_KP_Subtract; break; + default: if (kval <= 9) *k = XK_KP_0 + kval; break; + } + break; + case KT_DEAD: + /* KT_DEAD keys are for accelerated diacritical creation. */ + switch (kbe.kb_value) { + case K_DGRAVE: *k = XK_dead_grave; break; + case K_DACUTE: *k = XK_dead_acute; break; + case K_DCIRCM: *k = XK_dead_circumflex; break; + case K_DTILDE: *k = XK_dead_tilde; break; + case K_DDIERE: *k = XK_dead_diaeresis; break; + } + break; + case KT_CUR: + switch (kbe.kb_value) { + case K_DOWN: *k = XK_Down; break; + case K_LEFT: *k = XK_Left; break; + case K_RIGHT: *k = XK_Right; break; + case K_UP: *k = XK_Up; break; + } + break; + case KT_SHIFT: + switch (kbe.kb_value) { + case K_ALTGR: *k = XK_Alt_R; break; + case K_ALT: + *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L); + break; + case K_CTRL: + *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L); + break; + case K_CTRLL: *k = XK_Control_L; break; + case K_CTRLR: *k = XK_Control_R; break; + case K_SHIFT: + *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L); + break; + case K_SHIFTL: *k = XK_Shift_L; break; + case K_SHIFTR: *k = XK_Shift_R; break; + default: break; + } + break; + case KT_ASCII: + /* KT_ASCII keys accumulate a 3 digit decimal number that + * gets emitted when the shift state changes. We can't + * emulate that. + */ + break; + case KT_LOCK: + if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock; + break; + default: break; + } + } + + if (k[-1] == k[-2]) k[-1] = NoSymbol; + if (k[-2] == k[-3]) k[-2] = NoSymbol; + if (k[-3] == k[-4]) k[-3] = NoSymbol; + if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol; + if (k[-1] == k[-4] && k[-2] == k[-3] + && k[-2] == NoSymbol) k[-1] = NoSymbol; + } +} + +static void kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) +{ + GETPRIV; + KeySym *k, *mapCopy; + char type; + int i; + +#if 00/*BP*/ + mapCopy = malloc(sizeof(map)); + memcpy(mapCopy, map, sizeof(map)); +#else + ErrorF("kbdLinuxGetMap() is broken/no-op'd\n"); + return; +#endif + + kbdLinuxReadKernelMapping(priv->fd, pKeySyms); + + /* compute the modifier map */ + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = NoSymbol; /* make sure it is restored */ + + for (k = mapCopy, i = MIN_KEYCODE; + i < NUM_KEYCODES + MIN_KEYCODE; + i++, k += 4) { + switch(*k) { + case XK_Shift_L: + case XK_Shift_R: pModMap[i] = ShiftMask; break; + case XK_Control_L: + case XK_Control_R: pModMap[i] = ControlMask; break; + case XK_Caps_Lock: pModMap[i] = LockMask; break; + case XK_Alt_L: + case XK_Alt_R: pModMap[i] = AltMask; break; + case XK_Num_Lock: pModMap[i] = NumLockMask; break; + case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; + case XK_Kana_Lock: + case XK_Kana_Shift: pModMap[i] = KanaMask; break; + case XK_Mode_switch: pModMap[i] = AltLangMask; break; + } + } + + priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type; + + pKeySyms->map = mapCopy; /* Must be XFree'able */ + pKeySyms->mapWidth = GLYPHS_PER_KEY; + pKeySyms->minKeyCode = MIN_KEYCODE; + pKeySyms->maxKeyCode = MAX_KEYCODE; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->keyboard = 1; + info->keyClass = 1; + kbdLinuxGetMap(pDev, &info->keySyms, info->modMap); + info->focusClass = 1; + info->kbdFeedbackClass = 1; +} diff --git a/xorg-server/hw/dmx/input/usb-keyboard.c b/xorg-server/hw/dmx/input/usb-keyboard.c index c4667a3c3..fcbea47f9 100644 --- a/xorg-server/hw/dmx/input/usb-keyboard.c +++ b/xorg-server/hw/dmx/input/usb-keyboard.c @@ -1,444 +1,444 @@ -/* Portions of this file were derived from the following files: - * - ********************************************************************** - * - * xfree86/common/xf86KbdLnx.c - * - * Linux version of keymapping setup. The kernel (since 0.99.14) has support - * for fully remapping the keyboard, but there are some differences between - * the Linux map and the SVR4 map (esp. in the extended keycodes). We also - * remove the restriction on what keycodes can be remapped. - * Orest Zborowski. - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * - * 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 Thomas Roell not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Thomas Roell makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THOMAS ROELL 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. - * - */ - -/* - * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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. - */ - -/* - * Authors: - * Rickard E. (Rik) Faith <faith@redhat.com> - * - */ - -/** \file - * - * This code implements a low-level device driver for a USB keyboard - * under Linux. The keymap description is derived from code by Thomas - * Roell, Orest Zborowski. */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "atKeynames.h" -#include "usb-private.h" - -#define USB_KEYBOARD_DEBUG 0 - -/*****************************************************************************/ -/* Define some macros to make it easier to move this file to another - * part of the Xserver tree. All calls to the dmx* layer are #defined - * here for the .c file. The .h file will also have to be edited. */ -#include "usb-keyboard.h" -#include <xkbsrv.h> - -#define GETPRIV myPrivate *priv \ - = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private - -#define LOG0(f) dmxLog(dmxDebug,f) -#define LOG1(f,a) dmxLog(dmxDebug,f,a) -#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define FATAL0(f) dmxLog(dmxFatal,f) -#define FATAL1(f,a) dmxLog(dmxFatal,f,a) -#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) -#define MOTIONPROC dmxMotionProcPtr -#define ENQUEUEPROC dmxEnqueueProcPtr -#define CHECKPROC dmxCheckSpecialProcPtr -#define BLOCK DMXBlockType - -/* End of interface definitions. */ -/*****************************************************************************/ - -#define GLYPHS_PER_KEY 4 -#define NUM_KEYCODES 248 -#define MIN_KEYCODE 8 -#define MAX_KEYCODE (NUM_KEYCODES + MIN_KEYCODE - 1) - -static KeySym map[NUM_KEYCODES * GLYPHS_PER_KEY] = { -/* Table modified from xc/programs/Xserver/hw/xfree86/common/xf86Keymap.h */ - /* 0x00 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x01 */ XK_Escape, NoSymbol, NoSymbol, NoSymbol, - /* 0x02 */ XK_1, XK_exclam, NoSymbol, NoSymbol, - /* 0x03 */ XK_2, XK_at, NoSymbol, NoSymbol, - /* 0x04 */ XK_3, XK_numbersign, NoSymbol, NoSymbol, - /* 0x05 */ XK_4, XK_dollar, NoSymbol, NoSymbol, - /* 0x06 */ XK_5, XK_percent, NoSymbol, NoSymbol, - /* 0x07 */ XK_6, XK_asciicircum, NoSymbol, NoSymbol, - /* 0x08 */ XK_7, XK_ampersand, NoSymbol, NoSymbol, - /* 0x09 */ XK_8, XK_asterisk, NoSymbol, NoSymbol, - /* 0x0a */ XK_9, XK_parenleft, NoSymbol, NoSymbol, - /* 0x0b */ XK_0, XK_parenright, NoSymbol, NoSymbol, - /* 0x0c */ XK_minus, XK_underscore, NoSymbol, NoSymbol, - /* 0x0d */ XK_equal, XK_plus, NoSymbol, NoSymbol, - /* 0x0e */ XK_BackSpace, NoSymbol, NoSymbol, NoSymbol, - /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,NoSymbol, NoSymbol, - /* 0x10 */ XK_Q, NoSymbol, NoSymbol, NoSymbol, - /* 0x11 */ XK_W, NoSymbol, NoSymbol, NoSymbol, - /* 0x12 */ XK_E, NoSymbol, NoSymbol, NoSymbol, - /* 0x13 */ XK_R, NoSymbol, NoSymbol, NoSymbol, - /* 0x14 */ XK_T, NoSymbol, NoSymbol, NoSymbol, - /* 0x15 */ XK_Y, NoSymbol, NoSymbol, NoSymbol, - /* 0x16 */ XK_U, NoSymbol, NoSymbol, NoSymbol, - /* 0x17 */ XK_I, NoSymbol, NoSymbol, NoSymbol, - /* 0x18 */ XK_O, NoSymbol, NoSymbol, NoSymbol, - /* 0x19 */ XK_P, NoSymbol, NoSymbol, NoSymbol, - /* 0x1a */ XK_bracketleft, XK_braceleft, NoSymbol, NoSymbol, - /* 0x1b */ XK_bracketright,XK_braceright, NoSymbol, NoSymbol, - /* 0x1c */ XK_Return, NoSymbol, NoSymbol, NoSymbol, - /* 0x1d */ XK_Control_L, NoSymbol, NoSymbol, NoSymbol, - /* 0x1e */ XK_A, NoSymbol, NoSymbol, NoSymbol, - /* 0x1f */ XK_S, NoSymbol, NoSymbol, NoSymbol, - /* 0x20 */ XK_D, NoSymbol, NoSymbol, NoSymbol, - /* 0x21 */ XK_F, NoSymbol, NoSymbol, NoSymbol, - /* 0x22 */ XK_G, NoSymbol, NoSymbol, NoSymbol, - /* 0x23 */ XK_H, NoSymbol, NoSymbol, NoSymbol, - /* 0x24 */ XK_J, NoSymbol, NoSymbol, NoSymbol, - /* 0x25 */ XK_K, NoSymbol, NoSymbol, NoSymbol, - /* 0x26 */ XK_L, NoSymbol, NoSymbol, NoSymbol, - /* 0x27 */ XK_semicolon, XK_colon, NoSymbol, NoSymbol, - /* 0x28 */ XK_quoteright, XK_quotedbl, NoSymbol, NoSymbol, - /* 0x29 */ XK_quoteleft, XK_asciitilde, NoSymbol, NoSymbol, - /* 0x2a */ XK_Shift_L, NoSymbol, NoSymbol, NoSymbol, - /* 0x2b */ XK_backslash, XK_bar, NoSymbol, NoSymbol, - /* 0x2c */ XK_Z, NoSymbol, NoSymbol, NoSymbol, - /* 0x2d */ XK_X, NoSymbol, NoSymbol, NoSymbol, - /* 0x2e */ XK_C, NoSymbol, NoSymbol, NoSymbol, - /* 0x2f */ XK_V, NoSymbol, NoSymbol, NoSymbol, - /* 0x30 */ XK_B, NoSymbol, NoSymbol, NoSymbol, - /* 0x31 */ XK_N, NoSymbol, NoSymbol, NoSymbol, - /* 0x32 */ XK_M, NoSymbol, NoSymbol, NoSymbol, - /* 0x33 */ XK_comma, XK_less, NoSymbol, NoSymbol, - /* 0x34 */ XK_period, XK_greater, NoSymbol, NoSymbol, - /* 0x35 */ XK_slash, XK_question, NoSymbol, NoSymbol, - /* 0x36 */ XK_Shift_R, NoSymbol, NoSymbol, NoSymbol, - /* 0x37 */ XK_KP_Multiply, NoSymbol, NoSymbol, NoSymbol, - /* 0x38 */ XK_Alt_L, XK_Meta_L, NoSymbol, NoSymbol, - /* 0x39 */ XK_space, NoSymbol, NoSymbol, NoSymbol, - /* 0x3a */ XK_Caps_Lock, NoSymbol, NoSymbol, NoSymbol, - /* 0x3b */ XK_F1, NoSymbol, NoSymbol, NoSymbol, - /* 0x3c */ XK_F2, NoSymbol, NoSymbol, NoSymbol, - /* 0x3d */ XK_F3, NoSymbol, NoSymbol, NoSymbol, - /* 0x3e */ XK_F4, NoSymbol, NoSymbol, NoSymbol, - /* 0x3f */ XK_F5, NoSymbol, NoSymbol, NoSymbol, - /* 0x40 */ XK_F6, NoSymbol, NoSymbol, NoSymbol, - /* 0x41 */ XK_F7, NoSymbol, NoSymbol, NoSymbol, - /* 0x42 */ XK_F8, NoSymbol, NoSymbol, NoSymbol, - /* 0x43 */ XK_F9, NoSymbol, NoSymbol, NoSymbol, - /* 0x44 */ XK_F10, NoSymbol, NoSymbol, NoSymbol, - /* 0x45 */ XK_Num_Lock, NoSymbol, NoSymbol, NoSymbol, - /* 0x46 */ XK_Scroll_Lock, NoSymbol, NoSymbol, NoSymbol, - /* 0x47 */ XK_KP_Home, XK_KP_7, NoSymbol, NoSymbol, - /* 0x48 */ XK_KP_Up, XK_KP_8, NoSymbol, NoSymbol, - /* 0x49 */ XK_KP_Prior, XK_KP_9, NoSymbol, NoSymbol, - /* 0x4a */ XK_KP_Subtract, NoSymbol, NoSymbol, NoSymbol, - /* 0x4b */ XK_KP_Left, XK_KP_4, NoSymbol, NoSymbol, - /* 0x4c */ XK_KP_Begin, XK_KP_5, NoSymbol, NoSymbol, - /* 0x4d */ XK_KP_Right, XK_KP_6, NoSymbol, NoSymbol, - /* 0x4e */ XK_KP_Add, NoSymbol, NoSymbol, NoSymbol, - /* 0x4f */ XK_KP_End, XK_KP_1, NoSymbol, NoSymbol, - /* 0x50 */ XK_KP_Down, XK_KP_2, NoSymbol, NoSymbol, - /* 0x51 */ XK_KP_Next, XK_KP_3, NoSymbol, NoSymbol, - /* 0x52 */ XK_KP_Insert, XK_KP_0, NoSymbol, NoSymbol, - /* 0x53 */ XK_KP_Delete, XK_KP_Decimal, NoSymbol, NoSymbol, - /* 0x54 */ XK_Sys_Req, NoSymbol, NoSymbol, NoSymbol, - /* 0x55 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x56 */ XK_less, XK_greater, NoSymbol, NoSymbol, - /* 0x57 */ XK_F11, NoSymbol, NoSymbol, NoSymbol, - /* 0x58 */ XK_F12, NoSymbol, NoSymbol, NoSymbol, - /* 0x59 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5a */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5d */ XK_Begin, NoSymbol, NoSymbol, NoSymbol, - /* 0x5e */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5f */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x60 */ XK_KP_Enter, NoSymbol, NoSymbol, NoSymbol, - /* 0x61 */ XK_Control_R, NoSymbol, NoSymbol, NoSymbol, - /* 0x62 */ XK_KP_Divide, NoSymbol, NoSymbol, NoSymbol, - /* 0x63 */ XK_Print, NoSymbol, NoSymbol, NoSymbol, - /* 0x64 */ XK_Alt_R, XK_Meta_R, NoSymbol, NoSymbol, - /* 0x65 */ XK_Break, NoSymbol, NoSymbol, NoSymbol, - /* 0x66 */ XK_Home, NoSymbol, NoSymbol, NoSymbol, - /* 0x67 */ XK_Up, NoSymbol, NoSymbol, NoSymbol, - /* 0x68 */ XK_Prior, NoSymbol, NoSymbol, NoSymbol, - /* 0x69 */ XK_Left, NoSymbol, NoSymbol, NoSymbol, - /* 0x6a */ XK_Right, NoSymbol, NoSymbol, NoSymbol, - /* 0x6b */ XK_End, NoSymbol, NoSymbol, NoSymbol, - /* 0x6c */ XK_Down, NoSymbol, NoSymbol, NoSymbol, - /* 0x6d */ XK_Next, NoSymbol, NoSymbol, NoSymbol, - /* 0x6e */ XK_Insert, NoSymbol, NoSymbol, NoSymbol, - /* 0x6f */ XK_Delete, NoSymbol, NoSymbol, NoSymbol, - /* 0x70 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x71 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x72 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x73 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x74 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x75 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x76 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x77 */ XK_Pause, NoSymbol, NoSymbol, NoSymbol, - /* 0x78 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x79 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x7a */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, - /* 0x7b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x7c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x7d */ XK_Super_L, NoSymbol, NoSymbol, NoSymbol, - /* 0x7e */ XK_Super_R, NoSymbol, NoSymbol, NoSymbol, - /* 0x7f */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, -}; - -static int kbdUSBKeyDown(myPrivate *priv, int keyCode) -{ - CARD8 byte = keyCode >> 5; - CARD32 bit = 1 << (keyCode & 0x1f); - - if (byte > NUM_STATE_ENTRIES) return 0; - return priv->kbdState[byte] & bit; -} - -static void kbdUSBKeyState(myPrivate *priv, int type, int keyCode) -{ - CARD8 byte = keyCode >> 5; - CARD32 bit = 1 << (keyCode & 0x1f); - - if (byte > NUM_STATE_ENTRIES) return; - if (type == KeyPress) priv->kbdState[byte] |= bit; - else priv->kbdState[byte] &= ~bit; -} - -/** Set the LEDs. */ -void kbdUSBCtrl(DevicePtr pDev, KeybdCtrl *ctrl) -{ - GETPRIV; - struct timeval tv; - struct input_event event; - int i, led; - - gettimeofday(&tv, NULL); - for (i = 0; i < 5; i++) { - event.time.tv_sec = tv.tv_sec; - event.time.tv_usec = tv.tv_usec; - event.type = EV_LED; - if (i == 0) led = 1; /* LED_CAPSL == 0x01 */ - else if (i == 1) led = 0; /* LED_NUML == 0x00 */ - else led = i; - event.code = led; - event.value = !!(ctrl->leds & (1 << led)); - write(priv->fd, &event, sizeof(event)); - } -} - -/** Initialize \a pDev using #usbInit. */ -void kbdUSBInit(DevicePtr pDev) -{ - usbInit(pDev, usbKeyboard); -} - -static void kbdUSBConvert(DevicePtr pDev, - unsigned int scanCode, - int value, - ENQUEUEPROC enqueue, - CHECKPROC checkspecial, - BLOCK block) -{ - GETPRIV; - XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; - int type; - int keyCode; - KeySym keySym = NoSymbol; - int switching; - - /* Set up xEvent information */ - type = value ? KeyPress : KeyRelease; - keyCode = (scanCode & 0xff) + MIN_KEYCODE; - - /* Handle repeats */ - - if (keyCode >= xkbi->desc->min_key_code && - keyCode <= xkbi->desc->max_key_code) { - - int effectiveGroup = XkbGetEffectiveGroup(xkbi, - &xkbi->state, - scanCode); - keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); -#if 0 - switch (keySym) { - case XK_Num_Lock: - case XK_Scroll_Lock: - case XK_Shift_Lock: - case XK_Caps_Lock: - /* Ignore releases and all but first press */ - if (kbdLinuxModIgnore(priv, &xE, keySym)) return; - if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; - else xE.u.u.type = KeyPress; - break; - } -#endif - - /* If key is already down, ignore or autorepeat */ - if (type == KeyPress && kbdUSBKeyDown(priv, keyCode)) { - KbdFeedbackClassRec *feed = priv->pDevice->kbdfeed; - - /* No auto-repeat? */ - if ((feed && !feed->ctrl.autoRepeat) - || priv->pDevice->key->xkbInfo->desc->map->modmap[keyCode] - || (feed - && !(feed->ctrl.autoRepeats[keyCode >> 3] - & (1 << (keyCode & 7))))) return; /* Ignore */ - - /* Do auto-repeat */ - enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); - type = KeyPress; - } - - /* If key is already up, ignore */ - if (type == KeyRelease && !kbdUSBKeyDown(priv, keyCode)) return; - } - - switching = 0; - if (checkspecial && type == KeyPress) - switching = checkspecial(pDev, keySym); - if (!switching) { - if (enqueue) - enqueue(pDev, type, keyCode, keySym, NULL, block); - kbdUSBKeyState(priv, type, keyCode); /* Update our state bitmap */ - } -} - -/** Read an event from the \a pDev device. If the event is a motion - * event, enqueue it with the \a motion function. Otherwise, check for - * special keys with the \a checkspecial function and enqueue the event - * with the \a enqueue function. The \a block type is passed to the - * functions so that they may block SIGIO handling as appropriate to the - * caller of this function. */ -void kbdUSBRead(DevicePtr pDev, - MOTIONPROC motion, - ENQUEUEPROC enqueue, - CHECKPROC checkspecial, - BLOCK block) -{ - GETPRIV; - struct input_event raw; - - while (read(priv->fd, &raw, sizeof(raw)) > 0) { -#if USB_KEYBOARD_DEBUG - LOG3("KBD: type = %d, code = 0x%02x, value = %d\n", - raw.type, raw.code, raw.value); -#endif - kbdUSBConvert(pDev, raw.code, raw.value, enqueue, checkspecial, block); - } -} - -/** Turn \a pDev on (i.e., take input from \a pDev). */ -int kbdUSBOn(DevicePtr pDev) -{ - GETPRIV; - - if (priv->fd < 0) kbdUSBInit(pDev); - return priv->fd; -} - -static void kbdUSBGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) -{ - KeySym *k, *mapCopy; - int i; - - mapCopy = xalloc(sizeof(map)); - memcpy(mapCopy, map, sizeof(map)); - - /* compute the modifier map */ - for (i = 0; i < MAP_LENGTH; i++) - pModMap[i] = NoSymbol; /* make sure it is restored */ - - for (k = mapCopy, i = MIN_KEYCODE; - i < NUM_KEYCODES + MIN_KEYCODE; - i++, k += 4) { - switch(*k) { - case XK_Shift_L: - case XK_Shift_R: pModMap[i] = ShiftMask; break; - case XK_Control_L: - case XK_Control_R: pModMap[i] = ControlMask; break; - case XK_Caps_Lock: pModMap[i] = LockMask; break; - case XK_Alt_L: - case XK_Alt_R: pModMap[i] = AltMask; break; - case XK_Num_Lock: pModMap[i] = NumLockMask; break; - case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; - case XK_Kana_Lock: - case XK_Kana_Shift: pModMap[i] = KanaMask; break; - case XK_Mode_switch: pModMap[i] = AltLangMask; break; - } - } - - pKeySyms->map = mapCopy; /* Must be XFree'able */ - pKeySyms->mapWidth = GLYPHS_PER_KEY; - pKeySyms->minKeyCode = MIN_KEYCODE; - pKeySyms->maxKeyCode = MAX_KEYCODE; -} - -/** Fill the \a info structure with information needed to initialize \a - * pDev. */ -void kbdUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) -{ - info->keyboard = 1; - info->keyClass = 1; - kbdUSBGetMap(pDev, &info->keySyms, info->modMap); - info->focusClass = 1; - info->kbdFeedbackClass = 1; - info->names.keycodes = xstrdup("powerpcps2"); - info->force = 1; -} +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * xfree86/common/xf86KbdLnx.c + * + * Linux version of keymapping setup. The kernel (since 0.99.14) has support + * for fully remapping the keyboard, but there are some differences between + * the Linux map and the SVR4 map (esp. in the extended keycodes). We also + * remove the restriction on what keycodes can be remapped. + * Orest Zborowski. + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * 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 Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL 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. + * + */ + +/* + * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for a USB keyboard + * under Linux. The keymap description is derived from code by Thomas + * Roell, Orest Zborowski. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "atKeynames.h" +#include "usb-private.h" + +#define USB_KEYBOARD_DEBUG 0 + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "usb-keyboard.h" +#include <xkbsrv.h> + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + +#define GLYPHS_PER_KEY 4 +#define NUM_KEYCODES 248 +#define MIN_KEYCODE 8 +#define MAX_KEYCODE (NUM_KEYCODES + MIN_KEYCODE - 1) + +static KeySym map[NUM_KEYCODES * GLYPHS_PER_KEY] = { +/* Table modified from xc/programs/Xserver/hw/xfree86/common/xf86Keymap.h */ + /* 0x00 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x01 */ XK_Escape, NoSymbol, NoSymbol, NoSymbol, + /* 0x02 */ XK_1, XK_exclam, NoSymbol, NoSymbol, + /* 0x03 */ XK_2, XK_at, NoSymbol, NoSymbol, + /* 0x04 */ XK_3, XK_numbersign, NoSymbol, NoSymbol, + /* 0x05 */ XK_4, XK_dollar, NoSymbol, NoSymbol, + /* 0x06 */ XK_5, XK_percent, NoSymbol, NoSymbol, + /* 0x07 */ XK_6, XK_asciicircum, NoSymbol, NoSymbol, + /* 0x08 */ XK_7, XK_ampersand, NoSymbol, NoSymbol, + /* 0x09 */ XK_8, XK_asterisk, NoSymbol, NoSymbol, + /* 0x0a */ XK_9, XK_parenleft, NoSymbol, NoSymbol, + /* 0x0b */ XK_0, XK_parenright, NoSymbol, NoSymbol, + /* 0x0c */ XK_minus, XK_underscore, NoSymbol, NoSymbol, + /* 0x0d */ XK_equal, XK_plus, NoSymbol, NoSymbol, + /* 0x0e */ XK_BackSpace, NoSymbol, NoSymbol, NoSymbol, + /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,NoSymbol, NoSymbol, + /* 0x10 */ XK_Q, NoSymbol, NoSymbol, NoSymbol, + /* 0x11 */ XK_W, NoSymbol, NoSymbol, NoSymbol, + /* 0x12 */ XK_E, NoSymbol, NoSymbol, NoSymbol, + /* 0x13 */ XK_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x14 */ XK_T, NoSymbol, NoSymbol, NoSymbol, + /* 0x15 */ XK_Y, NoSymbol, NoSymbol, NoSymbol, + /* 0x16 */ XK_U, NoSymbol, NoSymbol, NoSymbol, + /* 0x17 */ XK_I, NoSymbol, NoSymbol, NoSymbol, + /* 0x18 */ XK_O, NoSymbol, NoSymbol, NoSymbol, + /* 0x19 */ XK_P, NoSymbol, NoSymbol, NoSymbol, + /* 0x1a */ XK_bracketleft, XK_braceleft, NoSymbol, NoSymbol, + /* 0x1b */ XK_bracketright,XK_braceright, NoSymbol, NoSymbol, + /* 0x1c */ XK_Return, NoSymbol, NoSymbol, NoSymbol, + /* 0x1d */ XK_Control_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x1e */ XK_A, NoSymbol, NoSymbol, NoSymbol, + /* 0x1f */ XK_S, NoSymbol, NoSymbol, NoSymbol, + /* 0x20 */ XK_D, NoSymbol, NoSymbol, NoSymbol, + /* 0x21 */ XK_F, NoSymbol, NoSymbol, NoSymbol, + /* 0x22 */ XK_G, NoSymbol, NoSymbol, NoSymbol, + /* 0x23 */ XK_H, NoSymbol, NoSymbol, NoSymbol, + /* 0x24 */ XK_J, NoSymbol, NoSymbol, NoSymbol, + /* 0x25 */ XK_K, NoSymbol, NoSymbol, NoSymbol, + /* 0x26 */ XK_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x27 */ XK_semicolon, XK_colon, NoSymbol, NoSymbol, + /* 0x28 */ XK_quoteright, XK_quotedbl, NoSymbol, NoSymbol, + /* 0x29 */ XK_quoteleft, XK_asciitilde, NoSymbol, NoSymbol, + /* 0x2a */ XK_Shift_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x2b */ XK_backslash, XK_bar, NoSymbol, NoSymbol, + /* 0x2c */ XK_Z, NoSymbol, NoSymbol, NoSymbol, + /* 0x2d */ XK_X, NoSymbol, NoSymbol, NoSymbol, + /* 0x2e */ XK_C, NoSymbol, NoSymbol, NoSymbol, + /* 0x2f */ XK_V, NoSymbol, NoSymbol, NoSymbol, + /* 0x30 */ XK_B, NoSymbol, NoSymbol, NoSymbol, + /* 0x31 */ XK_N, NoSymbol, NoSymbol, NoSymbol, + /* 0x32 */ XK_M, NoSymbol, NoSymbol, NoSymbol, + /* 0x33 */ XK_comma, XK_less, NoSymbol, NoSymbol, + /* 0x34 */ XK_period, XK_greater, NoSymbol, NoSymbol, + /* 0x35 */ XK_slash, XK_question, NoSymbol, NoSymbol, + /* 0x36 */ XK_Shift_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x37 */ XK_KP_Multiply, NoSymbol, NoSymbol, NoSymbol, + /* 0x38 */ XK_Alt_L, XK_Meta_L, NoSymbol, NoSymbol, + /* 0x39 */ XK_space, NoSymbol, NoSymbol, NoSymbol, + /* 0x3a */ XK_Caps_Lock, NoSymbol, NoSymbol, NoSymbol, + /* 0x3b */ XK_F1, NoSymbol, NoSymbol, NoSymbol, + /* 0x3c */ XK_F2, NoSymbol, NoSymbol, NoSymbol, + /* 0x3d */ XK_F3, NoSymbol, NoSymbol, NoSymbol, + /* 0x3e */ XK_F4, NoSymbol, NoSymbol, NoSymbol, + /* 0x3f */ XK_F5, NoSymbol, NoSymbol, NoSymbol, + /* 0x40 */ XK_F6, NoSymbol, NoSymbol, NoSymbol, + /* 0x41 */ XK_F7, NoSymbol, NoSymbol, NoSymbol, + /* 0x42 */ XK_F8, NoSymbol, NoSymbol, NoSymbol, + /* 0x43 */ XK_F9, NoSymbol, NoSymbol, NoSymbol, + /* 0x44 */ XK_F10, NoSymbol, NoSymbol, NoSymbol, + /* 0x45 */ XK_Num_Lock, NoSymbol, NoSymbol, NoSymbol, + /* 0x46 */ XK_Scroll_Lock, NoSymbol, NoSymbol, NoSymbol, + /* 0x47 */ XK_KP_Home, XK_KP_7, NoSymbol, NoSymbol, + /* 0x48 */ XK_KP_Up, XK_KP_8, NoSymbol, NoSymbol, + /* 0x49 */ XK_KP_Prior, XK_KP_9, NoSymbol, NoSymbol, + /* 0x4a */ XK_KP_Subtract, NoSymbol, NoSymbol, NoSymbol, + /* 0x4b */ XK_KP_Left, XK_KP_4, NoSymbol, NoSymbol, + /* 0x4c */ XK_KP_Begin, XK_KP_5, NoSymbol, NoSymbol, + /* 0x4d */ XK_KP_Right, XK_KP_6, NoSymbol, NoSymbol, + /* 0x4e */ XK_KP_Add, NoSymbol, NoSymbol, NoSymbol, + /* 0x4f */ XK_KP_End, XK_KP_1, NoSymbol, NoSymbol, + /* 0x50 */ XK_KP_Down, XK_KP_2, NoSymbol, NoSymbol, + /* 0x51 */ XK_KP_Next, XK_KP_3, NoSymbol, NoSymbol, + /* 0x52 */ XK_KP_Insert, XK_KP_0, NoSymbol, NoSymbol, + /* 0x53 */ XK_KP_Delete, XK_KP_Decimal, NoSymbol, NoSymbol, + /* 0x54 */ XK_Sys_Req, NoSymbol, NoSymbol, NoSymbol, + /* 0x55 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x56 */ XK_less, XK_greater, NoSymbol, NoSymbol, + /* 0x57 */ XK_F11, NoSymbol, NoSymbol, NoSymbol, + /* 0x58 */ XK_F12, NoSymbol, NoSymbol, NoSymbol, + /* 0x59 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5a */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5d */ XK_Begin, NoSymbol, NoSymbol, NoSymbol, + /* 0x5e */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5f */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x60 */ XK_KP_Enter, NoSymbol, NoSymbol, NoSymbol, + /* 0x61 */ XK_Control_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x62 */ XK_KP_Divide, NoSymbol, NoSymbol, NoSymbol, + /* 0x63 */ XK_Print, NoSymbol, NoSymbol, NoSymbol, + /* 0x64 */ XK_Alt_R, XK_Meta_R, NoSymbol, NoSymbol, + /* 0x65 */ XK_Break, NoSymbol, NoSymbol, NoSymbol, + /* 0x66 */ XK_Home, NoSymbol, NoSymbol, NoSymbol, + /* 0x67 */ XK_Up, NoSymbol, NoSymbol, NoSymbol, + /* 0x68 */ XK_Prior, NoSymbol, NoSymbol, NoSymbol, + /* 0x69 */ XK_Left, NoSymbol, NoSymbol, NoSymbol, + /* 0x6a */ XK_Right, NoSymbol, NoSymbol, NoSymbol, + /* 0x6b */ XK_End, NoSymbol, NoSymbol, NoSymbol, + /* 0x6c */ XK_Down, NoSymbol, NoSymbol, NoSymbol, + /* 0x6d */ XK_Next, NoSymbol, NoSymbol, NoSymbol, + /* 0x6e */ XK_Insert, NoSymbol, NoSymbol, NoSymbol, + /* 0x6f */ XK_Delete, NoSymbol, NoSymbol, NoSymbol, + /* 0x70 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x71 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x72 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x73 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x74 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x75 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x76 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x77 */ XK_Pause, NoSymbol, NoSymbol, NoSymbol, + /* 0x78 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x79 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x7a */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, + /* 0x7b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x7c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x7d */ XK_Super_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x7e */ XK_Super_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x7f */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, +}; + +static int kbdUSBKeyDown(myPrivate *priv, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return 0; + return priv->kbdState[byte] & bit; +} + +static void kbdUSBKeyState(myPrivate *priv, int type, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return; + if (type == KeyPress) priv->kbdState[byte] |= bit; + else priv->kbdState[byte] &= ~bit; +} + +/** Set the LEDs. */ +void kbdUSBCtrl(DevicePtr pDev, KeybdCtrl *ctrl) +{ + GETPRIV; + struct timeval tv; + struct input_event event; + int i, led; + + gettimeofday(&tv, NULL); + for (i = 0; i < 5; i++) { + event.time.tv_sec = tv.tv_sec; + event.time.tv_usec = tv.tv_usec; + event.type = EV_LED; + if (i == 0) led = 1; /* LED_CAPSL == 0x01 */ + else if (i == 1) led = 0; /* LED_NUML == 0x00 */ + else led = i; + event.code = led; + event.value = !!(ctrl->leds & (1 << led)); + write(priv->fd, &event, sizeof(event)); + } +} + +/** Initialize \a pDev using #usbInit. */ +void kbdUSBInit(DevicePtr pDev) +{ + usbInit(pDev, usbKeyboard); +} + +static void kbdUSBConvert(DevicePtr pDev, + unsigned int scanCode, + int value, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; + int type; + int keyCode; + KeySym keySym = NoSymbol; + int switching; + + /* Set up xEvent information */ + type = value ? KeyPress : KeyRelease; + keyCode = (scanCode & 0xff) + MIN_KEYCODE; + + /* Handle repeats */ + + if (keyCode >= xkbi->desc->min_key_code && + keyCode <= xkbi->desc->max_key_code) { + + int effectiveGroup = XkbGetEffectiveGroup(xkbi, + &xkbi->state, + scanCode); + keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); +#if 0 + switch (keySym) { + case XK_Num_Lock: + case XK_Scroll_Lock: + case XK_Shift_Lock: + case XK_Caps_Lock: + /* Ignore releases and all but first press */ + if (kbdLinuxModIgnore(priv, &xE, keySym)) return; + if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; + else xE.u.u.type = KeyPress; + break; + } +#endif + + /* If key is already down, ignore or autorepeat */ + if (type == KeyPress && kbdUSBKeyDown(priv, keyCode)) { + KbdFeedbackClassRec *feed = priv->pDevice->kbdfeed; + + /* No auto-repeat? */ + if ((feed && !feed->ctrl.autoRepeat) + || priv->pDevice->key->xkbInfo->desc->map->modmap[keyCode] + || (feed + && !(feed->ctrl.autoRepeats[keyCode >> 3] + & (1 << (keyCode & 7))))) return; /* Ignore */ + + /* Do auto-repeat */ + enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); + type = KeyPress; + } + + /* If key is already up, ignore */ + if (type == KeyRelease && !kbdUSBKeyDown(priv, keyCode)) return; + } + + switching = 0; + if (checkspecial && type == KeyPress) + switching = checkspecial(pDev, keySym); + if (!switching) { + if (enqueue) + enqueue(pDev, type, keyCode, keySym, NULL, block); + kbdUSBKeyState(priv, type, keyCode); /* Update our state bitmap */ + } +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void kbdUSBRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + struct input_event raw; + + while (read(priv->fd, &raw, sizeof(raw)) > 0) { +#if USB_KEYBOARD_DEBUG + LOG3("KBD: type = %d, code = 0x%02x, value = %d\n", + raw.type, raw.code, raw.value); +#endif + kbdUSBConvert(pDev, raw.code, raw.value, enqueue, checkspecial, block); + } +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int kbdUSBOn(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd < 0) kbdUSBInit(pDev); + return priv->fd; +} + +static void kbdUSBGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) +{ + KeySym *k, *mapCopy; + int i; + + mapCopy = malloc(sizeof(map)); + memcpy(mapCopy, map, sizeof(map)); + + /* compute the modifier map */ + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = NoSymbol; /* make sure it is restored */ + + for (k = mapCopy, i = MIN_KEYCODE; + i < NUM_KEYCODES + MIN_KEYCODE; + i++, k += 4) { + switch(*k) { + case XK_Shift_L: + case XK_Shift_R: pModMap[i] = ShiftMask; break; + case XK_Control_L: + case XK_Control_R: pModMap[i] = ControlMask; break; + case XK_Caps_Lock: pModMap[i] = LockMask; break; + case XK_Alt_L: + case XK_Alt_R: pModMap[i] = AltMask; break; + case XK_Num_Lock: pModMap[i] = NumLockMask; break; + case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; + case XK_Kana_Lock: + case XK_Kana_Shift: pModMap[i] = KanaMask; break; + case XK_Mode_switch: pModMap[i] = AltLangMask; break; + } + } + + pKeySyms->map = mapCopy; /* Must be XFree'able */ + pKeySyms->mapWidth = GLYPHS_PER_KEY; + pKeySyms->minKeyCode = MIN_KEYCODE; + pKeySyms->maxKeyCode = MAX_KEYCODE; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void kbdUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->keyboard = 1; + info->keyClass = 1; + kbdUSBGetMap(pDev, &info->keySyms, info->modMap); + info->focusClass = 1; + info->kbdFeedbackClass = 1; + info->names.keycodes = xstrdup("powerpcps2"); + info->force = 1; +} diff --git a/xorg-server/hw/kdrive/ephyr/ephyr.c b/xorg-server/hw/kdrive/ephyr/ephyr.c index b21559bba..439a2b274 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyr.c +++ b/xorg-server/hw/kdrive/ephyr/ephyr.c @@ -1,1179 +1,1179 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum <mallum@openedhand.com> - * - * Copyright © 2004 Nokia - * - * 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 Nokia not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Nokia makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL NOKIA 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include "ephyr.h" - -#include "inputstr.h" -#include "scrnintstr.h" -#include "ephyrlog.h" - -#ifdef XF86DRI -#include "ephyrdri.h" -#include "ephyrdriext.h" -#include "ephyrglxext.h" -#endif /* XF86DRI */ - -extern int KdTsPhyScreen; -#ifdef GLXEXT -extern Bool noGlxVisualInit; -#endif - -KdKeyboardInfo *ephyrKbd; -KdPointerInfo *ephyrMouse; -EphyrKeySyms ephyrKeySyms; -Bool ephyrNoDRI=FALSE ; -Bool ephyrNoXV=FALSE ; - -static int mouseState = 0; - -typedef struct _EphyrInputPrivate { - Bool enabled; -} EphyrKbdPrivate, EphyrPointerPrivate; - -Bool EphyrWantGrayScale = 0; - - -Bool -ephyrInitialize (KdCardInfo *card, EphyrPriv *priv) -{ - OsSignal(SIGUSR1, hostx_handle_signal); - - priv->base = 0; - priv->bytes_per_line = 0; - return TRUE; -} - -Bool -ephyrCardInit (KdCardInfo *card) -{ - EphyrPriv *priv; - - priv = (EphyrPriv *) xalloc (sizeof (EphyrPriv)); - if (!priv) - return FALSE; - - if (!ephyrInitialize (card, priv)) - { - xfree (priv); - return FALSE; - } - card->driver = priv; - - return TRUE; -} - -Bool -ephyrScreenInitialize (KdScreenInfo *screen, EphyrScrPriv *scrpriv) -{ - int width = 640, height = 480; - CARD32 redMask, greenMask, blueMask; - - if (hostx_want_screen_size(screen, &width, &height) - || !screen->width || !screen->height) - { - screen->width = width; - screen->height = height; - } - - if (EphyrWantGrayScale) - screen->fb.depth = 8; - - if (screen->fb.depth && screen->fb.depth != hostx_get_depth()) - { - if (screen->fb.depth < hostx_get_depth() - && (screen->fb.depth == 24 || screen->fb.depth == 16 - || screen->fb.depth == 8)) - { - hostx_set_server_depth(screen, screen->fb.depth); - } - else - ErrorF("\nXephyr: requested screen depth not supported, setting to match hosts.\n"); - } - - screen->fb.depth = hostx_get_server_depth(screen); - screen->rate = 72; - - if (screen->fb.depth <= 8) - { - if (EphyrWantGrayScale) - screen->fb.visuals = ((1 << StaticGray) | (1 << GrayScale)); - else - screen->fb.visuals = ((1 << StaticGray) | - (1 << GrayScale) | - (1 << StaticColor) | - (1 << PseudoColor) | - (1 << TrueColor) | - (1 << DirectColor)); - - screen->fb.redMask = 0x00; - screen->fb.greenMask = 0x00; - screen->fb.blueMask = 0x00; - screen->fb.depth = 8; - screen->fb.bitsPerPixel = 8; - } - else - { - screen->fb.visuals = (1 << TrueColor); - - if (screen->fb.depth <= 15) - { - screen->fb.depth = 15; - screen->fb.bitsPerPixel = 16; - } - else if (screen->fb.depth <= 16) - { - screen->fb.depth = 16; - screen->fb.bitsPerPixel = 16; - } - else if (screen->fb.depth <= 24) - { - screen->fb.depth = 24; - screen->fb.bitsPerPixel = 32; - } - else if (screen->fb.depth <= 30) - { - screen->fb.depth = 30; - screen->fb.bitsPerPixel = 32; - } - else - { - ErrorF("\nXephyr: Unsupported screen depth %d\n", - screen->fb.depth); - return FALSE; - } - - hostx_get_visual_masks (screen, &redMask, &greenMask, &blueMask); - - screen->fb.redMask = (Pixel) redMask; - screen->fb.greenMask = (Pixel) greenMask; - screen->fb.blueMask = (Pixel) blueMask; - - } - - scrpriv->randr = screen->randr; - - return ephyrMapFramebuffer (screen); -} - -Bool -ephyrScreenInit (KdScreenInfo *screen) -{ - EphyrScrPriv *scrpriv; - - scrpriv = xcalloc (1, sizeof (EphyrScrPriv)); - - if (!scrpriv) - return FALSE; - - screen->driver = scrpriv; - - if (!ephyrScreenInitialize (screen, scrpriv)) - { - screen->driver = 0; - xfree (scrpriv); - return FALSE; - } - - return TRUE; -} - -void* -ephyrWindowLinear (ScreenPtr pScreen, - CARD32 row, - CARD32 offset, - int mode, - CARD32 *size, - void *closure) -{ - KdScreenPriv(pScreen); - EphyrPriv *priv = pScreenPriv->card->driver; - - if (!pScreenPriv->enabled) - return 0; - - *size = priv->bytes_per_line; - return priv->base + row * priv->bytes_per_line + offset; -} - -/** - * Figure out display buffer size. If fakexa is enabled, allocate a larger - * buffer so that fakexa has space to put offscreen pixmaps. - */ -int -ephyrBufferHeight(KdScreenInfo *screen) -{ - int buffer_height; - if (ephyrFuncs.initAccel == NULL) - buffer_height = screen->height; - else - buffer_height = 3 * screen->height; - return buffer_height; -} - - -Bool -ephyrMapFramebuffer (KdScreenInfo *screen) -{ - EphyrScrPriv *scrpriv = screen->driver; - EphyrPriv *priv = screen->card->driver; - KdPointerMatrix m; - int buffer_height; - - EPHYR_LOG("screen->width: %d, screen->height: %d index=%d", - screen->width, screen->height, screen->mynum); - - KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); - KdSetPointerMatrix (&m); - - priv->bytes_per_line = ((screen->width * screen->fb.bitsPerPixel + 31) >> 5) << 2; - - buffer_height = ephyrBufferHeight(screen); - - priv->base = hostx_screen_init (screen, screen->width, screen->height, buffer_height); - - if ((scrpriv->randr & RR_Rotate_0) && !(scrpriv->randr & RR_Reflect_All)) - { - scrpriv->shadow = FALSE; - - screen->fb.byteStride = priv->bytes_per_line; - screen->fb.pixelStride = screen->width; - screen->fb.frameBuffer = (CARD8 *) (priv->base); - } - else - { - /* Rotated/Reflected so we need to use shadow fb */ - scrpriv->shadow = TRUE; - - EPHYR_LOG("allocing shadow"); - - KdShadowFbAlloc (screen, - scrpriv->randr & (RR_Rotate_90|RR_Rotate_270)); - } - - return TRUE; -} - -void -ephyrSetScreenSizes (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - - if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) - { - pScreen->width = screen->width; - pScreen->height = screen->height; - pScreen->mmWidth = screen->width_mm; - pScreen->mmHeight = screen->height_mm; - } - else - { - pScreen->width = screen->height; - pScreen->height = screen->width; - pScreen->mmWidth = screen->height_mm; - pScreen->mmHeight = screen->width_mm; - } -} - -Bool -ephyrUnmapFramebuffer (KdScreenInfo *screen) -{ - EphyrScrPriv *scrpriv = screen->driver; - - if (scrpriv->shadow) - KdShadowFbFree (screen); - - /* Note, priv->base will get freed when XImage recreated */ - - return TRUE; -} - -void -ephyrShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - - EPHYR_LOG("slow paint"); - - /* FIXME: Slow Rotated/Reflected updates could be much - * much faster efficiently updating via tranforming - * pBuf->pDamage regions - */ - shadowUpdateRotatePacked(pScreen, pBuf); - hostx_paint_rect(screen, 0,0,0,0, screen->width, screen->height); -} - -static void -ephyrInternalDamageRedisplay (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - RegionPtr pRegion; - - if (!scrpriv || !scrpriv->pDamage) - return; - - pRegion = DamageRegion (scrpriv->pDamage); - - if (REGION_NOTEMPTY (pScreen, pRegion)) - { - int nbox; - BoxPtr pbox; - - nbox = REGION_NUM_RECTS (pRegion); - pbox = REGION_RECTS (pRegion); - - while (nbox--) - { - hostx_paint_rect(screen, - pbox->x1, pbox->y1, - pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - pbox++; - } - DamageEmpty (scrpriv->pDamage); - } -} - -static void -ephyrInternalDamageBlockHandler (pointer data, - OSTimePtr pTimeout, - pointer pRead) -{ - ScreenPtr pScreen = (ScreenPtr) data; - - ephyrInternalDamageRedisplay (pScreen); -} - -static void -ephyrInternalDamageWakeupHandler (pointer data, int i, pointer LastSelectMask) -{ - /* FIXME: Not needed ? */ -} - -Bool -ephyrSetInternalDamage (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - PixmapPtr pPixmap = NULL; - - scrpriv->pDamage = DamageCreate ((DamageReportFunc) 0, - (DamageDestroyFunc) 0, - DamageReportNone, - TRUE, - pScreen, - pScreen); - - if (!RegisterBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler, - ephyrInternalDamageWakeupHandler, - (pointer) pScreen)) - return FALSE; - - pPixmap = (*pScreen->GetScreenPixmap) (pScreen); - - DamageRegister (&pPixmap->drawable, scrpriv->pDamage); - - return TRUE; -} - -void -ephyrUnsetInternalDamage (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - PixmapPtr pPixmap = NULL; - - pPixmap = (*pScreen->GetScreenPixmap) (pScreen); - DamageUnregister (&pPixmap->drawable, scrpriv->pDamage); - DamageDestroy (scrpriv->pDamage); - - RemoveBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler, - ephyrInternalDamageWakeupHandler, - (pointer) pScreen); -} - -#ifdef RANDR -Bool -ephyrRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - RRScreenSizePtr pSize; - Rotation randr; - int n = 0; - - struct { int width, height; } sizes[] = - { - { 1600, 1200 }, - { 1400, 1050 }, - { 1280, 960 }, - { 1280, 1024 }, - { 1152, 864 }, - { 1024, 768 }, - { 832, 624 }, - { 800, 600 }, - { 720, 400 }, - { 480, 640 }, - { 640, 480 }, - { 640, 400 }, - { 320, 240 }, - { 240, 320 }, - { 160, 160 }, - { 0, 0 } - }; - - EPHYR_LOG("mark"); - - *rotations = RR_Rotate_All|RR_Reflect_All; - - if (!hostx_want_preexisting_window (screen) - && !hostx_want_fullscreen ()) /* only if no -parent switch */ - { - while (sizes[n].width != 0 && sizes[n].height != 0) - { - RRRegisterSize (pScreen, - sizes[n].width, - sizes[n].height, - (sizes[n].width * screen->width_mm)/screen->width, - (sizes[n].height *screen->height_mm)/screen->height - ); - n++; - } - } - - pSize = RRRegisterSize (pScreen, - screen->width, - screen->height, - screen->width_mm, - screen->height_mm); - - randr = KdSubRotation (scrpriv->randr, screen->randr); - - RRSetCurrentConfig (pScreen, randr, 0, pSize); - - return TRUE; -} - -Bool -ephyrRandRSetConfig (ScreenPtr pScreen, - Rotation randr, - int rate, - RRScreenSizePtr pSize) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - Bool wasEnabled = pScreenPriv->enabled; - EphyrScrPriv oldscr; - int oldwidth, oldheight, oldmmwidth, oldmmheight; - Bool oldshadow; - int newwidth, newheight; - - if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) - { - newwidth = pSize->width; - newheight = pSize->height; - } - else - { - newwidth = pSize->height; - newheight = pSize->width; - } - - if (wasEnabled) - KdDisableScreen (pScreen); - - oldscr = *scrpriv; - - oldwidth = screen->width; - oldheight = screen->height; - oldmmwidth = pScreen->mmWidth; - oldmmheight = pScreen->mmHeight; - oldshadow = scrpriv->shadow; - - /* - * Set new configuration - */ - - scrpriv->randr = KdAddRotation (screen->randr, randr); - - ephyrUnmapFramebuffer (screen); - - screen->width = newwidth; - screen->height = newheight; - - if (!ephyrMapFramebuffer (screen)) - goto bail4; - - /* FIXME below should go in own call */ - - if (oldshadow) - KdShadowUnset (screen->pScreen); - else - ephyrUnsetInternalDamage(screen->pScreen); - - if (scrpriv->shadow) - { - if (!KdShadowSet (screen->pScreen, - scrpriv->randr, - ephyrShadowUpdate, - ephyrWindowLinear)) - goto bail4; - } - else - { - /* Without shadow fb ( non rotated ) we need - * to use damage to efficiently update display - * via signal regions what to copy from 'fb'. - */ - if (!ephyrSetInternalDamage(screen->pScreen)) - goto bail4; - } - - ephyrSetScreenSizes (screen->pScreen); - - /* - * Set frame buffer mapping - */ - (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), - pScreen->width, - pScreen->height, - screen->fb.depth, - screen->fb.bitsPerPixel, - screen->fb.byteStride, - screen->fb.frameBuffer); - - /* set the subpixel order */ - - KdSetSubpixelOrder (pScreen, scrpriv->randr); - - if (wasEnabled) - KdEnableScreen (pScreen); - - return TRUE; - - bail4: - EPHYR_LOG("bailed"); - - ephyrUnmapFramebuffer (screen); - *scrpriv = oldscr; - (void) ephyrMapFramebuffer (screen); - - pScreen->width = oldwidth; - pScreen->height = oldheight; - pScreen->mmWidth = oldmmwidth; - pScreen->mmHeight = oldmmheight; - - if (wasEnabled) - KdEnableScreen (pScreen); - return FALSE; -} - -Bool -ephyrRandRInit (ScreenPtr pScreen) -{ - rrScrPrivPtr pScrPriv; - - if (!RRScreenInit (pScreen)) - return FALSE; - - pScrPriv = rrGetScrPriv(pScreen); - pScrPriv->rrGetInfo = ephyrRandRGetInfo; - pScrPriv->rrSetConfig = ephyrRandRSetConfig; - return TRUE; -} -#endif - -Bool -ephyrCreateColormap (ColormapPtr pmap) -{ - return fbInitializeColormap (pmap); -} - -Bool -ephyrInitScreen (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - - EPHYR_LOG ("pScreen->myNum:%d\n", pScreen->myNum) ; - hostx_set_screen_number (screen, pScreen->myNum); - hostx_set_win_title (screen, "(ctrl+shift grabs mouse and keyboard)") ; - pScreen->CreateColormap = ephyrCreateColormap; - -#ifdef XV - if (!ephyrNoXV) { - if (!ephyrInitVideo (pScreen)) { - EPHYR_LOG_ERROR ("failed to initialize xvideo\n") ; - } else { - EPHYR_LOG ("initialized xvideo okay\n") ; - } - } -#endif /*XV*/ - -#ifdef XF86DRI - if (!ephyrNoDRI && !hostx_has_dri ()) { - EPHYR_LOG ("host x does not support DRI. Disabling DRI forwarding\n") ; - ephyrNoDRI = TRUE ; -#ifdef GLXEXT - noGlxVisualInit = FALSE ; -#endif - } - if (!ephyrNoDRI) { - ephyrDRIExtensionInit (pScreen) ; - ephyrHijackGLXExtension () ; - } -#endif - -#ifdef GLXEXT - if (ephyrNoDRI) { - noGlxVisualInit = FALSE ; - } -#endif - - return TRUE; -} - -Bool -ephyrFinishInitScreen (ScreenPtr pScreen) -{ - /* FIXME: Calling this even if not using shadow. - * Seems harmless enough. But may be safer elsewhere. - */ - if (!shadowSetup (pScreen)) - return FALSE; - -#ifdef RANDR - if (!ephyrRandRInit (pScreen)) - return FALSE; -#endif - - return TRUE; -} - -Bool -ephyrCreateResources (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - - EPHYR_LOG("mark pScreen=%p mynum=%d shadow=%d", - pScreen, pScreen->myNum, scrpriv->shadow); - - if (scrpriv->shadow) - return KdShadowSet (pScreen, - scrpriv->randr, - ephyrShadowUpdate, - ephyrWindowLinear); - else - return ephyrSetInternalDamage(pScreen); -} - -void -ephyrPreserve (KdCardInfo *card) -{ -} - -Bool -ephyrEnable (ScreenPtr pScreen) -{ - return TRUE; -} - -Bool -ephyrDPMS (ScreenPtr pScreen, int mode) -{ - return TRUE; -} - -void -ephyrDisable (ScreenPtr pScreen) -{ -} - -void -ephyrRestore (KdCardInfo *card) -{ -} - -void -ephyrScreenFini (KdScreenInfo *screen) -{ - EphyrScrPriv *scrpriv = screen->driver; - if (scrpriv->shadow) { - KdShadowFbFree (screen); - } - xfree(screen->driver); - screen->driver = NULL; -} - -/* - * Port of Mark McLoughlin's Xnest fix for focus in + modifier bug. - * See https://bugs.freedesktop.org/show_bug.cgi?id=3030 - */ -void -ephyrUpdateModifierState(unsigned int state) -{ -#if 0 - DeviceIntPtr pkeydev; - KeyClassPtr keyc; - int i; - CARD8 mask; - - pkeydev = inputInfo.keyboard; - - if (!pkeydev) - return; - -/* This is pretty broken. - * - * What should happen is that focus out should do as a VT switch does in - * traditional servers: fake releases for all keys (and buttons too, come - * to think of it) currently down. Then, on focus in, get the state from - * the host, and fake keypresses for everything currently down. - * - * So I'm leaving this broken for a little while. Sorry, folks. - * - * -daniels - */ - - keyc = pkeydev->key; - - state = state & 0xff; - - if (keyc->state == state) - return; - - for (i = 0, mask = 1; i < 8; i++, mask <<= 1) - { - int key; - - /* Modifier is down, but shouldn't be */ - if ((keyc->state & mask) && !(state & mask)) - { - int count = keyc->modifierKeyCount[i]; - - for (key = 0; key < MAP_LENGTH; key++) - if (keyc->xkbInfo->desc->map->modmap[key] & mask) - { - int bit; - BYTE *kptr; - - kptr = &keyc->down[key >> 3]; - bit = 1 << (key & 7); - - if (*kptr & bit && ephyrKbd && - ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) - KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE); /* release */ - - if (--count == 0) - break; - } - } - - /* Modifier shoud be down, but isn't */ - if (!(keyc->state & mask) && (state & mask)) - for (key = 0; key < MAP_LENGTH; key++) - if (keyc->xkbInfo->desc->map->modmap[key] & mask) - { - if (keyc->xkbInfo->desc->map->modmap[key] & mask && ephyrKbd && - ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) - KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE); /* press */ - break; - } - } -#endif -} - -static void -ephyrBlockSigio (void) -{ - sigset_t set; - - sigemptyset (&set); - sigaddset (&set, SIGIO); - sigprocmask (SIG_BLOCK, &set, 0); -} - -static void -ephyrUnblockSigio (void) -{ - sigset_t set; - - sigemptyset (&set); - sigaddset (&set, SIGIO); - sigprocmask (SIG_UNBLOCK, &set, 0); -} - -static Bool -ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) -{ - return FALSE; -} - -static void -ephyrCrossScreen (ScreenPtr pScreen, Bool entering) -{ -} - -int ephyrCurScreen; /*current event screen*/ - -static void -ephyrWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - ephyrBlockSigio (); - ephyrCurScreen = pScreen->myNum; - miPointerWarpCursor (inputInfo.pointer, pScreen, x, y); - ephyrUnblockSigio (); -} - -miPointerScreenFuncRec ephyrPointerScreenFuncs = -{ - ephyrCursorOffScreen, - ephyrCrossScreen, - ephyrWarpCursor, - NULL, - NULL -}; - -#ifdef XF86DRI -/** - * find if the remote window denoted by a_remote - * is paired with an internal Window within the Xephyr server. - * If the remove window is paired with an internal window, send an - * expose event to the client insterested in the internal window expose event. - * - * Pairing happens when a drawable inside Xephyr is associated with - * a GL surface in a DRI environment. - * Look at the function ProcXF86DRICreateDrawable in ephyrdriext.c to - * know a paired window is created. - * - * This is useful to make GL drawables (only windows for now) handle - * expose events and send those events to clients. - */ -static void -ephyrExposePairedWindow (int a_remote) -{ - EphyrWindowPair *pair = NULL; - RegionRec reg; - ScreenPtr screen; - - if (!findWindowPairFromRemote (a_remote, &pair)) { - EPHYR_LOG ("did not find a pair for this window\n"); - return; - } - screen = pair->local->drawable.pScreen; - REGION_NULL (screen, ®); - REGION_COPY (screen, ®, &pair->local->clipList); - screen->WindowExposures (pair->local, ®, NullRegion); - REGION_UNINIT (screen, ®); -} -#endif /* XF86DRI */ - -void -ephyrPoll(void) -{ - EphyrHostXEvent ev; - - while (hostx_get_event(&ev)) - { - switch (ev.type) - { - case EPHYR_EV_MOUSE_MOTION: - if (!ephyrMouse || - !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) { - EPHYR_LOG ("skipping mouse motion:%d\n", ephyrCurScreen) ; - continue; - } - { - if (ev.data.mouse_motion.screen >=0 - && (ephyrCurScreen != ev.data.mouse_motion.screen)) - { - EPHYR_LOG ("warping mouse cursor. " - "cur_screen%d, motion_screen:%d\n", - ephyrCurScreen, ev.data.mouse_motion.screen) ; - if (ev.data.mouse_motion.screen >= 0) - { - ephyrWarpCursor - (inputInfo.pointer, screenInfo.screens[ev.data.mouse_motion.screen], - ev.data.mouse_motion.x, - ev.data.mouse_motion.y ); - } - } - else - { - int x=0, y=0; -#ifdef XF86DRI - EphyrWindowPair *pair = NULL; -#endif - EPHYR_LOG ("enqueuing mouse motion:%d\n", ephyrCurScreen) ; - x = ev.data.mouse_motion.x; - y = ev.data.mouse_motion.y; - EPHYR_LOG ("initial (x,y):(%d,%d)\n", x, y) ; -#ifdef XF86DRI - EPHYR_LOG ("is this window peered by a gl drawable ?\n") ; - if (findWindowPairFromRemote (ev.data.mouse_motion.window, - &pair)) - { - EPHYR_LOG ("yes, it is peered\n") ; - x += pair->local->drawable.x; - y += pair->local->drawable.y; - } - else - { - EPHYR_LOG ("no, it is not peered\n") ; - } - EPHYR_LOG ("final (x,y):(%d,%d)\n", x, y) ; -#endif - KdEnqueuePointerEvent(ephyrMouse, mouseState, x, y, 0); - } - } - break; - - case EPHYR_EV_MOUSE_PRESS: - if (!ephyrMouse || - !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) { - EPHYR_LOG ("skipping mouse press:%d\n", ephyrCurScreen) ; - continue; - } - EPHYR_LOG ("enqueuing mouse press:%d\n", ephyrCurScreen) ; - ephyrUpdateModifierState(ev.key_state); - mouseState |= ev.data.mouse_down.button_num; - KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0); - break; - - case EPHYR_EV_MOUSE_RELEASE: - if (!ephyrMouse || - !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) - continue; - ephyrUpdateModifierState(ev.key_state); - mouseState &= ~ev.data.mouse_up.button_num; - EPHYR_LOG ("enqueuing mouse release:%d\n", ephyrCurScreen) ; - KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0); - break; - - case EPHYR_EV_KEY_PRESS: - if (!ephyrKbd || - !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) - continue; - ephyrUpdateModifierState(ev.key_state); - KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_down.scancode, FALSE); - break; - - case EPHYR_EV_KEY_RELEASE: - if (!ephyrKbd || - !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) - continue; - KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_up.scancode, TRUE); - break; - -#ifdef XF86DRI - case EPHYR_EV_EXPOSE: - /* - * We only receive expose events when the expose event have - * be generated for a drawable that is a host X window managed - * by Xephyr. Host X windows managed by Xephyr exists for instance - * when Xephyr is asked to create a GL drawable in a DRI environment. - */ - ephyrExposePairedWindow (ev.data.expose.window); - break; -#endif /* XF86DRI */ - - default: - break; - } - } -} - -void -ephyrCardFini (KdCardInfo *card) -{ - EphyrPriv *priv = card->driver; - xfree (priv); -} - -void -ephyrGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - /* XXX Not sure if this is right */ - - EPHYR_LOG("mark"); - - while (n--) - { - pdefs->red = 0; - pdefs->green = 0; - pdefs->blue = 0; - pdefs++; - } - -} - -void -ephyrPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - int min, max, p; - - /* XXX Not sure if this is right */ - - min = 256; - max = 0; - - while (n--) - { - p = pdefs->pixel; - if (p < min) - min = p; - if (p > max) - max = p; - - hostx_set_cmap_entry(p, - pdefs->red >> 8, - pdefs->green >> 8, - pdefs->blue >> 8); - pdefs++; - } -} - -/* Mouse calls */ - -static Status -MouseInit (KdPointerInfo *pi) -{ - pi->driverPrivate = (EphyrPointerPrivate *) - xcalloc(sizeof(EphyrPointerPrivate), 1); - ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE; - pi->nAxes = 3; - pi->nButtons = 32; - xfree(pi->name); - pi->name = strdup("Xephyr virtual mouse"); - ephyrMouse = pi; - return Success; -} - -static Status -MouseEnable (KdPointerInfo *pi) -{ - ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = TRUE; - return Success; -} - -static void -MouseDisable (KdPointerInfo *pi) -{ - ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE; - return; -} - -static void -MouseFini (KdPointerInfo *pi) -{ - ephyrMouse = NULL; - return; -} - -KdPointerDriver EphyrMouseDriver = { - "ephyr", - MouseInit, - MouseEnable, - MouseDisable, - MouseFini, - NULL, -}; - -/* Keyboard */ - -static Status -EphyrKeyboardInit (KdKeyboardInfo *ki) -{ - ki->driverPrivate = (EphyrKbdPrivate *) - xcalloc(sizeof(EphyrKbdPrivate), 1); - hostx_load_keymap(); - if (!ephyrKeySyms.map) { - ErrorF("Couldn't load keymap from host\n"); - return BadAlloc; - } - ki->minScanCode = ephyrKeySyms.minKeyCode; - ki->maxScanCode = ephyrKeySyms.maxKeyCode; - xfree(ki->name); - ki->name = strdup("Xephyr virtual keyboard"); - ephyrKbd = ki; - return Success; -} - -static Status -EphyrKeyboardEnable (KdKeyboardInfo *ki) -{ - ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = TRUE; - - return Success; -} - -static void -EphyrKeyboardDisable (KdKeyboardInfo *ki) -{ - ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = FALSE; -} - -static void -EphyrKeyboardFini (KdKeyboardInfo *ki) -{ - ephyrKbd = NULL; - return; -} - -static void -EphyrKeyboardLeds (KdKeyboardInfo *ki, int leds) -{ -} - -static void -EphyrKeyboardBell (KdKeyboardInfo *ki, int volume, int frequency, int duration) -{ -} - - -KdKeyboardDriver EphyrKeyboardDriver = { - "ephyr", - EphyrKeyboardInit, - EphyrKeyboardEnable, - EphyrKeyboardLeds, - EphyrKeyboardBell, - EphyrKeyboardDisable, - EphyrKeyboardFini, - NULL, -}; +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum <mallum@openedhand.com> + * + * Copyright © 2004 Nokia + * + * 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 Nokia not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Nokia makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL NOKIA 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "ephyr.h" + +#include "inputstr.h" +#include "scrnintstr.h" +#include "ephyrlog.h" + +#ifdef XF86DRI +#include "ephyrdri.h" +#include "ephyrdriext.h" +#include "ephyrglxext.h" +#endif /* XF86DRI */ + +extern int KdTsPhyScreen; +#ifdef GLXEXT +extern Bool noGlxVisualInit; +#endif + +KdKeyboardInfo *ephyrKbd; +KdPointerInfo *ephyrMouse; +EphyrKeySyms ephyrKeySyms; +Bool ephyrNoDRI=FALSE ; +Bool ephyrNoXV=FALSE ; + +static int mouseState = 0; + +typedef struct _EphyrInputPrivate { + Bool enabled; +} EphyrKbdPrivate, EphyrPointerPrivate; + +Bool EphyrWantGrayScale = 0; + + +Bool +ephyrInitialize (KdCardInfo *card, EphyrPriv *priv) +{ + OsSignal(SIGUSR1, hostx_handle_signal); + + priv->base = 0; + priv->bytes_per_line = 0; + return TRUE; +} + +Bool +ephyrCardInit (KdCardInfo *card) +{ + EphyrPriv *priv; + + priv = (EphyrPriv *) malloc(sizeof (EphyrPriv)); + if (!priv) + return FALSE; + + if (!ephyrInitialize (card, priv)) + { + free(priv); + return FALSE; + } + card->driver = priv; + + return TRUE; +} + +Bool +ephyrScreenInitialize (KdScreenInfo *screen, EphyrScrPriv *scrpriv) +{ + int width = 640, height = 480; + CARD32 redMask, greenMask, blueMask; + + if (hostx_want_screen_size(screen, &width, &height) + || !screen->width || !screen->height) + { + screen->width = width; + screen->height = height; + } + + if (EphyrWantGrayScale) + screen->fb.depth = 8; + + if (screen->fb.depth && screen->fb.depth != hostx_get_depth()) + { + if (screen->fb.depth < hostx_get_depth() + && (screen->fb.depth == 24 || screen->fb.depth == 16 + || screen->fb.depth == 8)) + { + hostx_set_server_depth(screen, screen->fb.depth); + } + else + ErrorF("\nXephyr: requested screen depth not supported, setting to match hosts.\n"); + } + + screen->fb.depth = hostx_get_server_depth(screen); + screen->rate = 72; + + if (screen->fb.depth <= 8) + { + if (EphyrWantGrayScale) + screen->fb.visuals = ((1 << StaticGray) | (1 << GrayScale)); + else + screen->fb.visuals = ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)); + + screen->fb.redMask = 0x00; + screen->fb.greenMask = 0x00; + screen->fb.blueMask = 0x00; + screen->fb.depth = 8; + screen->fb.bitsPerPixel = 8; + } + else + { + screen->fb.visuals = (1 << TrueColor); + + if (screen->fb.depth <= 15) + { + screen->fb.depth = 15; + screen->fb.bitsPerPixel = 16; + } + else if (screen->fb.depth <= 16) + { + screen->fb.depth = 16; + screen->fb.bitsPerPixel = 16; + } + else if (screen->fb.depth <= 24) + { + screen->fb.depth = 24; + screen->fb.bitsPerPixel = 32; + } + else if (screen->fb.depth <= 30) + { + screen->fb.depth = 30; + screen->fb.bitsPerPixel = 32; + } + else + { + ErrorF("\nXephyr: Unsupported screen depth %d\n", + screen->fb.depth); + return FALSE; + } + + hostx_get_visual_masks (screen, &redMask, &greenMask, &blueMask); + + screen->fb.redMask = (Pixel) redMask; + screen->fb.greenMask = (Pixel) greenMask; + screen->fb.blueMask = (Pixel) blueMask; + + } + + scrpriv->randr = screen->randr; + + return ephyrMapFramebuffer (screen); +} + +Bool +ephyrScreenInit (KdScreenInfo *screen) +{ + EphyrScrPriv *scrpriv; + + scrpriv = calloc(1, sizeof (EphyrScrPriv)); + + if (!scrpriv) + return FALSE; + + screen->driver = scrpriv; + + if (!ephyrScreenInitialize (screen, scrpriv)) + { + screen->driver = 0; + free(scrpriv); + return FALSE; + } + + return TRUE; +} + +void* +ephyrWindowLinear (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size, + void *closure) +{ + KdScreenPriv(pScreen); + EphyrPriv *priv = pScreenPriv->card->driver; + + if (!pScreenPriv->enabled) + return 0; + + *size = priv->bytes_per_line; + return priv->base + row * priv->bytes_per_line + offset; +} + +/** + * Figure out display buffer size. If fakexa is enabled, allocate a larger + * buffer so that fakexa has space to put offscreen pixmaps. + */ +int +ephyrBufferHeight(KdScreenInfo *screen) +{ + int buffer_height; + if (ephyrFuncs.initAccel == NULL) + buffer_height = screen->height; + else + buffer_height = 3 * screen->height; + return buffer_height; +} + + +Bool +ephyrMapFramebuffer (KdScreenInfo *screen) +{ + EphyrScrPriv *scrpriv = screen->driver; + EphyrPriv *priv = screen->card->driver; + KdPointerMatrix m; + int buffer_height; + + EPHYR_LOG("screen->width: %d, screen->height: %d index=%d", + screen->width, screen->height, screen->mynum); + + KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); + KdSetPointerMatrix (&m); + + priv->bytes_per_line = ((screen->width * screen->fb.bitsPerPixel + 31) >> 5) << 2; + + buffer_height = ephyrBufferHeight(screen); + + priv->base = hostx_screen_init (screen, screen->width, screen->height, buffer_height); + + if ((scrpriv->randr & RR_Rotate_0) && !(scrpriv->randr & RR_Reflect_All)) + { + scrpriv->shadow = FALSE; + + screen->fb.byteStride = priv->bytes_per_line; + screen->fb.pixelStride = screen->width; + screen->fb.frameBuffer = (CARD8 *) (priv->base); + } + else + { + /* Rotated/Reflected so we need to use shadow fb */ + scrpriv->shadow = TRUE; + + EPHYR_LOG("allocing shadow"); + + KdShadowFbAlloc (screen, + scrpriv->randr & (RR_Rotate_90|RR_Rotate_270)); + } + + return TRUE; +} + +void +ephyrSetScreenSizes (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + + if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) + { + pScreen->width = screen->width; + pScreen->height = screen->height; + pScreen->mmWidth = screen->width_mm; + pScreen->mmHeight = screen->height_mm; + } + else + { + pScreen->width = screen->height; + pScreen->height = screen->width; + pScreen->mmWidth = screen->height_mm; + pScreen->mmHeight = screen->width_mm; + } +} + +Bool +ephyrUnmapFramebuffer (KdScreenInfo *screen) +{ + EphyrScrPriv *scrpriv = screen->driver; + + if (scrpriv->shadow) + KdShadowFbFree (screen); + + /* Note, priv->base will get freed when XImage recreated */ + + return TRUE; +} + +void +ephyrShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + + EPHYR_LOG("slow paint"); + + /* FIXME: Slow Rotated/Reflected updates could be much + * much faster efficiently updating via tranforming + * pBuf->pDamage regions + */ + shadowUpdateRotatePacked(pScreen, pBuf); + hostx_paint_rect(screen, 0,0,0,0, screen->width, screen->height); +} + +static void +ephyrInternalDamageRedisplay (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + RegionPtr pRegion; + + if (!scrpriv || !scrpriv->pDamage) + return; + + pRegion = DamageRegion (scrpriv->pDamage); + + if (REGION_NOTEMPTY (pScreen, pRegion)) + { + int nbox; + BoxPtr pbox; + + nbox = REGION_NUM_RECTS (pRegion); + pbox = REGION_RECTS (pRegion); + + while (nbox--) + { + hostx_paint_rect(screen, + pbox->x1, pbox->y1, + pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + DamageEmpty (scrpriv->pDamage); + } +} + +static void +ephyrInternalDamageBlockHandler (pointer data, + OSTimePtr pTimeout, + pointer pRead) +{ + ScreenPtr pScreen = (ScreenPtr) data; + + ephyrInternalDamageRedisplay (pScreen); +} + +static void +ephyrInternalDamageWakeupHandler (pointer data, int i, pointer LastSelectMask) +{ + /* FIXME: Not needed ? */ +} + +Bool +ephyrSetInternalDamage (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + PixmapPtr pPixmap = NULL; + + scrpriv->pDamage = DamageCreate ((DamageReportFunc) 0, + (DamageDestroyFunc) 0, + DamageReportNone, + TRUE, + pScreen, + pScreen); + + if (!RegisterBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler, + ephyrInternalDamageWakeupHandler, + (pointer) pScreen)) + return FALSE; + + pPixmap = (*pScreen->GetScreenPixmap) (pScreen); + + DamageRegister (&pPixmap->drawable, scrpriv->pDamage); + + return TRUE; +} + +void +ephyrUnsetInternalDamage (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + PixmapPtr pPixmap = NULL; + + pPixmap = (*pScreen->GetScreenPixmap) (pScreen); + DamageUnregister (&pPixmap->drawable, scrpriv->pDamage); + DamageDestroy (scrpriv->pDamage); + + RemoveBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler, + ephyrInternalDamageWakeupHandler, + (pointer) pScreen); +} + +#ifdef RANDR +Bool +ephyrRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + RRScreenSizePtr pSize; + Rotation randr; + int n = 0; + + struct { int width, height; } sizes[] = + { + { 1600, 1200 }, + { 1400, 1050 }, + { 1280, 960 }, + { 1280, 1024 }, + { 1152, 864 }, + { 1024, 768 }, + { 832, 624 }, + { 800, 600 }, + { 720, 400 }, + { 480, 640 }, + { 640, 480 }, + { 640, 400 }, + { 320, 240 }, + { 240, 320 }, + { 160, 160 }, + { 0, 0 } + }; + + EPHYR_LOG("mark"); + + *rotations = RR_Rotate_All|RR_Reflect_All; + + if (!hostx_want_preexisting_window (screen) + && !hostx_want_fullscreen ()) /* only if no -parent switch */ + { + while (sizes[n].width != 0 && sizes[n].height != 0) + { + RRRegisterSize (pScreen, + sizes[n].width, + sizes[n].height, + (sizes[n].width * screen->width_mm)/screen->width, + (sizes[n].height *screen->height_mm)/screen->height + ); + n++; + } + } + + pSize = RRRegisterSize (pScreen, + screen->width, + screen->height, + screen->width_mm, + screen->height_mm); + + randr = KdSubRotation (scrpriv->randr, screen->randr); + + RRSetCurrentConfig (pScreen, randr, 0, pSize); + + return TRUE; +} + +Bool +ephyrRandRSetConfig (ScreenPtr pScreen, + Rotation randr, + int rate, + RRScreenSizePtr pSize) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + Bool wasEnabled = pScreenPriv->enabled; + EphyrScrPriv oldscr; + int oldwidth, oldheight, oldmmwidth, oldmmheight; + Bool oldshadow; + int newwidth, newheight; + + if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) + { + newwidth = pSize->width; + newheight = pSize->height; + } + else + { + newwidth = pSize->height; + newheight = pSize->width; + } + + if (wasEnabled) + KdDisableScreen (pScreen); + + oldscr = *scrpriv; + + oldwidth = screen->width; + oldheight = screen->height; + oldmmwidth = pScreen->mmWidth; + oldmmheight = pScreen->mmHeight; + oldshadow = scrpriv->shadow; + + /* + * Set new configuration + */ + + scrpriv->randr = KdAddRotation (screen->randr, randr); + + ephyrUnmapFramebuffer (screen); + + screen->width = newwidth; + screen->height = newheight; + + if (!ephyrMapFramebuffer (screen)) + goto bail4; + + /* FIXME below should go in own call */ + + if (oldshadow) + KdShadowUnset (screen->pScreen); + else + ephyrUnsetInternalDamage(screen->pScreen); + + if (scrpriv->shadow) + { + if (!KdShadowSet (screen->pScreen, + scrpriv->randr, + ephyrShadowUpdate, + ephyrWindowLinear)) + goto bail4; + } + else + { + /* Without shadow fb ( non rotated ) we need + * to use damage to efficiently update display + * via signal regions what to copy from 'fb'. + */ + if (!ephyrSetInternalDamage(screen->pScreen)) + goto bail4; + } + + ephyrSetScreenSizes (screen->pScreen); + + /* + * Set frame buffer mapping + */ + (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), + pScreen->width, + pScreen->height, + screen->fb.depth, + screen->fb.bitsPerPixel, + screen->fb.byteStride, + screen->fb.frameBuffer); + + /* set the subpixel order */ + + KdSetSubpixelOrder (pScreen, scrpriv->randr); + + if (wasEnabled) + KdEnableScreen (pScreen); + + return TRUE; + + bail4: + EPHYR_LOG("bailed"); + + ephyrUnmapFramebuffer (screen); + *scrpriv = oldscr; + (void) ephyrMapFramebuffer (screen); + + pScreen->width = oldwidth; + pScreen->height = oldheight; + pScreen->mmWidth = oldmmwidth; + pScreen->mmHeight = oldmmheight; + + if (wasEnabled) + KdEnableScreen (pScreen); + return FALSE; +} + +Bool +ephyrRandRInit (ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) + return FALSE; + + pScrPriv = rrGetScrPriv(pScreen); + pScrPriv->rrGetInfo = ephyrRandRGetInfo; + pScrPriv->rrSetConfig = ephyrRandRSetConfig; + return TRUE; +} +#endif + +Bool +ephyrCreateColormap (ColormapPtr pmap) +{ + return fbInitializeColormap (pmap); +} + +Bool +ephyrInitScreen (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + + EPHYR_LOG ("pScreen->myNum:%d\n", pScreen->myNum) ; + hostx_set_screen_number (screen, pScreen->myNum); + hostx_set_win_title (screen, "(ctrl+shift grabs mouse and keyboard)") ; + pScreen->CreateColormap = ephyrCreateColormap; + +#ifdef XV + if (!ephyrNoXV) { + if (!ephyrInitVideo (pScreen)) { + EPHYR_LOG_ERROR ("failed to initialize xvideo\n") ; + } else { + EPHYR_LOG ("initialized xvideo okay\n") ; + } + } +#endif /*XV*/ + +#ifdef XF86DRI + if (!ephyrNoDRI && !hostx_has_dri ()) { + EPHYR_LOG ("host x does not support DRI. Disabling DRI forwarding\n") ; + ephyrNoDRI = TRUE ; +#ifdef GLXEXT + noGlxVisualInit = FALSE ; +#endif + } + if (!ephyrNoDRI) { + ephyrDRIExtensionInit (pScreen) ; + ephyrHijackGLXExtension () ; + } +#endif + +#ifdef GLXEXT + if (ephyrNoDRI) { + noGlxVisualInit = FALSE ; + } +#endif + + return TRUE; +} + +Bool +ephyrFinishInitScreen (ScreenPtr pScreen) +{ + /* FIXME: Calling this even if not using shadow. + * Seems harmless enough. But may be safer elsewhere. + */ + if (!shadowSetup (pScreen)) + return FALSE; + +#ifdef RANDR + if (!ephyrRandRInit (pScreen)) + return FALSE; +#endif + + return TRUE; +} + +Bool +ephyrCreateResources (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + + EPHYR_LOG("mark pScreen=%p mynum=%d shadow=%d", + pScreen, pScreen->myNum, scrpriv->shadow); + + if (scrpriv->shadow) + return KdShadowSet (pScreen, + scrpriv->randr, + ephyrShadowUpdate, + ephyrWindowLinear); + else + return ephyrSetInternalDamage(pScreen); +} + +void +ephyrPreserve (KdCardInfo *card) +{ +} + +Bool +ephyrEnable (ScreenPtr pScreen) +{ + return TRUE; +} + +Bool +ephyrDPMS (ScreenPtr pScreen, int mode) +{ + return TRUE; +} + +void +ephyrDisable (ScreenPtr pScreen) +{ +} + +void +ephyrRestore (KdCardInfo *card) +{ +} + +void +ephyrScreenFini (KdScreenInfo *screen) +{ + EphyrScrPriv *scrpriv = screen->driver; + if (scrpriv->shadow) { + KdShadowFbFree (screen); + } + free(screen->driver); + screen->driver = NULL; +} + +/* + * Port of Mark McLoughlin's Xnest fix for focus in + modifier bug. + * See https://bugs.freedesktop.org/show_bug.cgi?id=3030 + */ +void +ephyrUpdateModifierState(unsigned int state) +{ +#if 0 + DeviceIntPtr pkeydev; + KeyClassPtr keyc; + int i; + CARD8 mask; + + pkeydev = inputInfo.keyboard; + + if (!pkeydev) + return; + +/* This is pretty broken. + * + * What should happen is that focus out should do as a VT switch does in + * traditional servers: fake releases for all keys (and buttons too, come + * to think of it) currently down. Then, on focus in, get the state from + * the host, and fake keypresses for everything currently down. + * + * So I'm leaving this broken for a little while. Sorry, folks. + * + * -daniels + */ + + keyc = pkeydev->key; + + state = state & 0xff; + + if (keyc->state == state) + return; + + for (i = 0, mask = 1; i < 8; i++, mask <<= 1) + { + int key; + + /* Modifier is down, but shouldn't be */ + if ((keyc->state & mask) && !(state & mask)) + { + int count = keyc->modifierKeyCount[i]; + + for (key = 0; key < MAP_LENGTH; key++) + if (keyc->xkbInfo->desc->map->modmap[key] & mask) + { + int bit; + BYTE *kptr; + + kptr = &keyc->down[key >> 3]; + bit = 1 << (key & 7); + + if (*kptr & bit && ephyrKbd && + ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) + KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE); /* release */ + + if (--count == 0) + break; + } + } + + /* Modifier shoud be down, but isn't */ + if (!(keyc->state & mask) && (state & mask)) + for (key = 0; key < MAP_LENGTH; key++) + if (keyc->xkbInfo->desc->map->modmap[key] & mask) + { + if (keyc->xkbInfo->desc->map->modmap[key] & mask && ephyrKbd && + ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) + KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE); /* press */ + break; + } + } +#endif +} + +static void +ephyrBlockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_BLOCK, &set, 0); +} + +static void +ephyrUnblockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_UNBLOCK, &set, 0); +} + +static Bool +ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) +{ + return FALSE; +} + +static void +ephyrCrossScreen (ScreenPtr pScreen, Bool entering) +{ +} + +int ephyrCurScreen; /*current event screen*/ + +static void +ephyrWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + ephyrBlockSigio (); + ephyrCurScreen = pScreen->myNum; + miPointerWarpCursor (inputInfo.pointer, pScreen, x, y); + ephyrUnblockSigio (); +} + +miPointerScreenFuncRec ephyrPointerScreenFuncs = +{ + ephyrCursorOffScreen, + ephyrCrossScreen, + ephyrWarpCursor, + NULL, + NULL +}; + +#ifdef XF86DRI +/** + * find if the remote window denoted by a_remote + * is paired with an internal Window within the Xephyr server. + * If the remove window is paired with an internal window, send an + * expose event to the client insterested in the internal window expose event. + * + * Pairing happens when a drawable inside Xephyr is associated with + * a GL surface in a DRI environment. + * Look at the function ProcXF86DRICreateDrawable in ephyrdriext.c to + * know a paired window is created. + * + * This is useful to make GL drawables (only windows for now) handle + * expose events and send those events to clients. + */ +static void +ephyrExposePairedWindow (int a_remote) +{ + EphyrWindowPair *pair = NULL; + RegionRec reg; + ScreenPtr screen; + + if (!findWindowPairFromRemote (a_remote, &pair)) { + EPHYR_LOG ("did not find a pair for this window\n"); + return; + } + screen = pair->local->drawable.pScreen; + REGION_NULL (screen, ®); + REGION_COPY (screen, ®, &pair->local->clipList); + screen->WindowExposures (pair->local, ®, NullRegion); + REGION_UNINIT (screen, ®); +} +#endif /* XF86DRI */ + +void +ephyrPoll(void) +{ + EphyrHostXEvent ev; + + while (hostx_get_event(&ev)) + { + switch (ev.type) + { + case EPHYR_EV_MOUSE_MOTION: + if (!ephyrMouse || + !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) { + EPHYR_LOG ("skipping mouse motion:%d\n", ephyrCurScreen) ; + continue; + } + { + if (ev.data.mouse_motion.screen >=0 + && (ephyrCurScreen != ev.data.mouse_motion.screen)) + { + EPHYR_LOG ("warping mouse cursor. " + "cur_screen%d, motion_screen:%d\n", + ephyrCurScreen, ev.data.mouse_motion.screen) ; + if (ev.data.mouse_motion.screen >= 0) + { + ephyrWarpCursor + (inputInfo.pointer, screenInfo.screens[ev.data.mouse_motion.screen], + ev.data.mouse_motion.x, + ev.data.mouse_motion.y ); + } + } + else + { + int x=0, y=0; +#ifdef XF86DRI + EphyrWindowPair *pair = NULL; +#endif + EPHYR_LOG ("enqueuing mouse motion:%d\n", ephyrCurScreen) ; + x = ev.data.mouse_motion.x; + y = ev.data.mouse_motion.y; + EPHYR_LOG ("initial (x,y):(%d,%d)\n", x, y) ; +#ifdef XF86DRI + EPHYR_LOG ("is this window peered by a gl drawable ?\n") ; + if (findWindowPairFromRemote (ev.data.mouse_motion.window, + &pair)) + { + EPHYR_LOG ("yes, it is peered\n") ; + x += pair->local->drawable.x; + y += pair->local->drawable.y; + } + else + { + EPHYR_LOG ("no, it is not peered\n") ; + } + EPHYR_LOG ("final (x,y):(%d,%d)\n", x, y) ; +#endif + KdEnqueuePointerEvent(ephyrMouse, mouseState, x, y, 0); + } + } + break; + + case EPHYR_EV_MOUSE_PRESS: + if (!ephyrMouse || + !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) { + EPHYR_LOG ("skipping mouse press:%d\n", ephyrCurScreen) ; + continue; + } + EPHYR_LOG ("enqueuing mouse press:%d\n", ephyrCurScreen) ; + ephyrUpdateModifierState(ev.key_state); + mouseState |= ev.data.mouse_down.button_num; + KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0); + break; + + case EPHYR_EV_MOUSE_RELEASE: + if (!ephyrMouse || + !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) + continue; + ephyrUpdateModifierState(ev.key_state); + mouseState &= ~ev.data.mouse_up.button_num; + EPHYR_LOG ("enqueuing mouse release:%d\n", ephyrCurScreen) ; + KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0); + break; + + case EPHYR_EV_KEY_PRESS: + if (!ephyrKbd || + !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) + continue; + ephyrUpdateModifierState(ev.key_state); + KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_down.scancode, FALSE); + break; + + case EPHYR_EV_KEY_RELEASE: + if (!ephyrKbd || + !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) + continue; + KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_up.scancode, TRUE); + break; + +#ifdef XF86DRI + case EPHYR_EV_EXPOSE: + /* + * We only receive expose events when the expose event have + * be generated for a drawable that is a host X window managed + * by Xephyr. Host X windows managed by Xephyr exists for instance + * when Xephyr is asked to create a GL drawable in a DRI environment. + */ + ephyrExposePairedWindow (ev.data.expose.window); + break; +#endif /* XF86DRI */ + + default: + break; + } + } +} + +void +ephyrCardFini (KdCardInfo *card) +{ + EphyrPriv *priv = card->driver; + free(priv); +} + +void +ephyrGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + /* XXX Not sure if this is right */ + + EPHYR_LOG("mark"); + + while (n--) + { + pdefs->red = 0; + pdefs->green = 0; + pdefs->blue = 0; + pdefs++; + } + +} + +void +ephyrPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + int min, max, p; + + /* XXX Not sure if this is right */ + + min = 256; + max = 0; + + while (n--) + { + p = pdefs->pixel; + if (p < min) + min = p; + if (p > max) + max = p; + + hostx_set_cmap_entry(p, + pdefs->red >> 8, + pdefs->green >> 8, + pdefs->blue >> 8); + pdefs++; + } +} + +/* Mouse calls */ + +static Status +MouseInit (KdPointerInfo *pi) +{ + pi->driverPrivate = (EphyrPointerPrivate *) + calloc(sizeof(EphyrPointerPrivate), 1); + ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE; + pi->nAxes = 3; + pi->nButtons = 32; + free(pi->name); + pi->name = strdup("Xephyr virtual mouse"); + ephyrMouse = pi; + return Success; +} + +static Status +MouseEnable (KdPointerInfo *pi) +{ + ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = TRUE; + return Success; +} + +static void +MouseDisable (KdPointerInfo *pi) +{ + ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE; + return; +} + +static void +MouseFini (KdPointerInfo *pi) +{ + ephyrMouse = NULL; + return; +} + +KdPointerDriver EphyrMouseDriver = { + "ephyr", + MouseInit, + MouseEnable, + MouseDisable, + MouseFini, + NULL, +}; + +/* Keyboard */ + +static Status +EphyrKeyboardInit (KdKeyboardInfo *ki) +{ + ki->driverPrivate = (EphyrKbdPrivate *) + calloc(sizeof(EphyrKbdPrivate), 1); + hostx_load_keymap(); + if (!ephyrKeySyms.map) { + ErrorF("Couldn't load keymap from host\n"); + return BadAlloc; + } + ki->minScanCode = ephyrKeySyms.minKeyCode; + ki->maxScanCode = ephyrKeySyms.maxKeyCode; + free(ki->name); + ki->name = strdup("Xephyr virtual keyboard"); + ephyrKbd = ki; + return Success; +} + +static Status +EphyrKeyboardEnable (KdKeyboardInfo *ki) +{ + ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = TRUE; + + return Success; +} + +static void +EphyrKeyboardDisable (KdKeyboardInfo *ki) +{ + ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = FALSE; +} + +static void +EphyrKeyboardFini (KdKeyboardInfo *ki) +{ + ephyrKbd = NULL; + return; +} + +static void +EphyrKeyboardLeds (KdKeyboardInfo *ki, int leds) +{ +} + +static void +EphyrKeyboardBell (KdKeyboardInfo *ki, int volume, int frequency, int duration) +{ +} + + +KdKeyboardDriver EphyrKeyboardDriver = { + "ephyr", + EphyrKeyboardInit, + EphyrKeyboardEnable, + EphyrKeyboardLeds, + EphyrKeyboardBell, + EphyrKeyboardDisable, + EphyrKeyboardFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/ephyr/ephyr_draw.c b/xorg-server/hw/kdrive/ephyr/ephyr_draw.c index f9fac8007..f3e2be6eb 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyr_draw.c +++ b/xorg-server/hw/kdrive/ephyr/ephyr_draw.c @@ -1,524 +1,523 @@ -/* - * Copyright © 2006 Intel Corporation - * - * 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. - * - * Authors: - * Eric Anholt <eric@anholt.net> - * - */ - -#ifdef HAVE_CONFIG_H -#include <kdrive-config.h> -#endif - -#include "ephyr.h" -#include "exa_priv.h" -#include "fbpict.h" - -#define EPHYR_TRACE_DRAW 0 - -#if EPHYR_TRACE_DRAW -#define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__); -#else -#define TRACE_DRAW() do { } while (0) -#endif - -/* Use some oddball alignments, to expose issues in alignment handling in EXA. */ -#define EPHYR_OFFSET_ALIGN 24 -#define EPHYR_PITCH_ALIGN 24 - -#define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024) -#define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024) - -/** - * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to - * fb functions. - */ -static void -ephyrPreparePipelinedAccess(PixmapPtr pPix, int index) -{ - KdScreenPriv(pPix->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - assert(fakexa->saved_ptrs[index] == NULL); - fakexa->saved_ptrs[index] = pPix->devPrivate.ptr; - - if (pPix->devPrivate.ptr != NULL) - return; - - pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix); -} - -/** - * Restores the original devPrivate.ptr of the pixmap from before we messed with - * it. - */ -static void -ephyrFinishPipelinedAccess(PixmapPtr pPix, int index) -{ - KdScreenPriv(pPix->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - pPix->devPrivate.ptr = fakexa->saved_ptrs[index]; - fakexa->saved_ptrs[index] = NULL; -} - -/** - * Sets up a scratch GC for fbFill, and saves other parameters for the - * ephyrSolid implementation. - */ -static Bool -ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg) -{ - ScreenPtr pScreen = pPix->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - CARD32 tmpval[3]; - - ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST); - - fakexa->pDst = pPix; - fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen); - - tmpval[0] = alu; - tmpval[1] = pm; - tmpval[2] = fg; - ChangeGC(fakexa->pGC, GCFunction | GCPlaneMask | GCForeground, - tmpval); - - ValidateGC(&pPix->drawable, fakexa->pGC); - - TRACE_DRAW(); - - return TRUE; -} - -/** - * Does an fbFill of the rectangle to be drawn. - */ -static void -ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2) -{ - ScreenPtr pScreen = pPix->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1); -} - -/** - * Cleans up the scratch GC created in ephyrPrepareSolid. - */ -static void -ephyrDoneSolid(PixmapPtr pPix) -{ - ScreenPtr pScreen = pPix->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - FreeScratchGC(fakexa->pGC); - - ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST); -} - -/** - * Sets up a scratch GC for fbCopyArea, and saves other parameters for the - * ephyrCopy implementation. - */ -static Bool -ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu, - Pixel pm) -{ - ScreenPtr pScreen = pDst->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - CARD32 tmpval[2]; - - ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); - ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); - - fakexa->pSrc = pSrc; - fakexa->pDst = pDst; - fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen); - - tmpval[0] = alu; - tmpval[1] = pm; - ChangeGC (fakexa->pGC, GCFunction | GCPlaneMask, tmpval); - - ValidateGC(&pDst->drawable, fakexa->pGC); - - TRACE_DRAW(); - - return TRUE; -} - -/** - * Does an fbCopyArea to take care of the requested copy. - */ -static void -ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h) -{ - ScreenPtr pScreen = pDst->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC, - srcX, srcY, w, h, dstX, dstY); -} - -/** - * Cleans up the scratch GC created in ephyrPrepareCopy. - */ -static void -ephyrDoneCopy(PixmapPtr pDst) -{ - ScreenPtr pScreen = pDst->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - FreeScratchGC (fakexa->pGC); - - ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); - ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); -} - -/** - * Reports that we can always accelerate the given operation. This may not be - * desirable from an EXA testing standpoint -- testing the fallback paths would - * be useful, too. - */ -static Bool -ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, - PicturePtr pDstPicture) -{ - /* Exercise the component alpha helper, so fail on this case like a normal - * driver - */ - if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver) - return FALSE; - - return TRUE; -} - -/** - * Saves off the parameters for ephyrComposite. - */ -static Bool -ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, - PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, - PixmapPtr pDst) -{ - KdScreenPriv(pDst->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); - ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); - if (pMask != NULL) - ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK); - - fakexa->op = op; - fakexa->pSrcPicture = pSrcPicture; - fakexa->pMaskPicture = pMaskPicture; - fakexa->pDstPicture = pDstPicture; - fakexa->pSrc = pSrc; - fakexa->pMask = pMask; - fakexa->pDst = pDst; - - TRACE_DRAW(); - - return TRUE; -} - -/** - * Does an fbComposite to complete the requested drawing operation. - */ -static void -ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, - int dstX, int dstY, int w, int h) -{ - KdScreenPriv(pDst->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture, - fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY, - w, h); -} - -static void -ephyrDoneComposite(PixmapPtr pDst) -{ - KdScreenPriv(pDst->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - if (fakexa->pMask != NULL) - ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK); - ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); - ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); -} - -/** - * Does fake acceleration of DownloadFromScren using memcpy. - */ -static Bool -ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst, - int dst_pitch) -{ - KdScreenPriv(pSrc->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - unsigned char *src; - int src_pitch, cpp; - - if (pSrc->drawable.bitsPerPixel < 8) - return FALSE; - - ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); - - cpp = pSrc->drawable.bitsPerPixel / 8; - src_pitch = exaGetPixmapPitch(pSrc); - src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc); - src += y * src_pitch + x * cpp; - - for (; h > 0; h--) { - memcpy(dst, src, w * cpp); - dst += dst_pitch; - src += src_pitch; - } - - exaMarkSync(pSrc->drawable.pScreen); - - ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC); - - return TRUE; -} - -/** - * Does fake acceleration of UploadToScreen using memcpy. - */ -static Bool -ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src, - int src_pitch) -{ - KdScreenPriv(pDst->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - unsigned char *dst; - int dst_pitch, cpp; - - if (pDst->drawable.bitsPerPixel < 8) - return FALSE; - - ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); - - cpp = pDst->drawable.bitsPerPixel / 8; - dst_pitch = exaGetPixmapPitch(pDst); - dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst); - dst += y * dst_pitch + x * cpp; - - for (; h > 0; h--) { - memcpy(dst, src, w * cpp); - dst += dst_pitch; - src += src_pitch; - } - - exaMarkSync(pDst->drawable.pScreen); - - ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST); - - return TRUE; -} - -static Bool -ephyrPrepareAccess(PixmapPtr pPix, int index) -{ - /* Make sure we don't somehow end up with a pointer that is in framebuffer - * and hasn't been readied for us. - */ - assert(pPix->devPrivate.ptr != NULL); - - return TRUE; -} - -/** - * In fakexa, we currently only track whether we have synced to the latest - * "accelerated" drawing that has happened or not. It's not used for anything - * yet. - */ -static int -ephyrMarkSync(ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fakexa->is_synced = FALSE; - - return 0; -} - -/** - * Assumes that we're waiting on the latest marker. When EXA gets smarter and - * starts using markers in a fine-grained way (for example, waiting on drawing - * to required pixmaps to complete, rather than waiting for all drawing to - * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker - * implementation fine-grained as well. - */ -static void -ephyrWaitMarker(ScreenPtr pScreen, int marker) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fakexa->is_synced = TRUE; -} - -/** - * This function initializes EXA to use the fake acceleration implementation - * which just falls through to software. The purpose is to have a reliable, - * correct driver with which to test changes to the EXA core. - */ -Bool -ephyrDrawInit(ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrPriv *priv = screen->card->driver; - EphyrFakexaPriv *fakexa; - Bool success; - - fakexa = xcalloc(1, sizeof(*fakexa)); - if (fakexa == NULL) - return FALSE; - - fakexa->exa = exaDriverAlloc(); - if (fakexa->exa == NULL) { - xfree(fakexa); - return FALSE; - } - - fakexa->exa->memoryBase = (CARD8 *) (priv->base); - fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen); - fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height; - - /* Since we statically link against EXA, we shouldn't have to be smart about - * versioning. - */ - fakexa->exa->exa_major = 2; - fakexa->exa->exa_minor = 0; - - fakexa->exa->PrepareSolid = ephyrPrepareSolid; - fakexa->exa->Solid = ephyrSolid; - fakexa->exa->DoneSolid = ephyrDoneSolid; - - fakexa->exa->PrepareCopy = ephyrPrepareCopy; - fakexa->exa->Copy = ephyrCopy; - fakexa->exa->DoneCopy = ephyrDoneCopy; - - fakexa->exa->CheckComposite = ephyrCheckComposite; - fakexa->exa->PrepareComposite = ephyrPrepareComposite; - fakexa->exa->Composite = ephyrComposite; - fakexa->exa->DoneComposite = ephyrDoneComposite; - - fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen; - fakexa->exa->UploadToScreen = ephyrUploadToScreen; - - fakexa->exa->MarkSync = ephyrMarkSync; - fakexa->exa->WaitMarker = ephyrWaitMarker; - - fakexa->exa->PrepareAccess = ephyrPrepareAccess; - - fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN; - fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN; - - fakexa->exa->maxX = 1023; - fakexa->exa->maxY = 1023; - - fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS; - - success = exaDriverInit(pScreen, fakexa->exa); - if (success) { - ErrorF("Initialized fake EXA acceleration\n"); - scrpriv->fakexa = fakexa; - } else { - ErrorF("Failed to initialize EXA\n"); - xfree(fakexa->exa); - xfree(fakexa); - } - - return success; -} - -void -ephyrDrawEnable(ScreenPtr pScreen) -{ -} - -void -ephyrDrawDisable(ScreenPtr pScreen) -{ -} - -void -ephyrDrawFini(ScreenPtr pScreen) -{ -} - -/** - * exaDDXDriverInit is required by the top-level EXA module, and is used by - * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since - * we won't be enabling/disabling the FB. - */ -void -exaDDXDriverInit(ScreenPtr pScreen) -{ - ExaScreenPriv(pScreen); - - pExaScr->migration = ExaMigrationSmart; - pExaScr->checkDirtyCorrectness = TRUE; -} +/* + * Copyright © 2006 Intel Corporation + * + * 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. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif + +#include "ephyr.h" +#include "exa_priv.h" +#include "fbpict.h" + +#define EPHYR_TRACE_DRAW 0 + +#if EPHYR_TRACE_DRAW +#define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__); +#else +#define TRACE_DRAW() do { } while (0) +#endif + +/* Use some oddball alignments, to expose issues in alignment handling in EXA. */ +#define EPHYR_OFFSET_ALIGN 24 +#define EPHYR_PITCH_ALIGN 24 + +#define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024) +#define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024) + +/** + * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to + * fb functions. + */ +static void +ephyrPreparePipelinedAccess(PixmapPtr pPix, int index) +{ + KdScreenPriv(pPix->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + assert(fakexa->saved_ptrs[index] == NULL); + fakexa->saved_ptrs[index] = pPix->devPrivate.ptr; + + if (pPix->devPrivate.ptr != NULL) + return; + + pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix); +} + +/** + * Restores the original devPrivate.ptr of the pixmap from before we messed with + * it. + */ +static void +ephyrFinishPipelinedAccess(PixmapPtr pPix, int index) +{ + KdScreenPriv(pPix->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + pPix->devPrivate.ptr = fakexa->saved_ptrs[index]; + fakexa->saved_ptrs[index] = NULL; +} + +/** + * Sets up a scratch GC for fbFill, and saves other parameters for the + * ephyrSolid implementation. + */ +static Bool +ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + ChangeGCVal tmpval[3]; + + ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST); + + fakexa->pDst = pPix; + fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen); + + tmpval[0].val = alu; + tmpval[1].val = pm; + tmpval[2].val = fg; + ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask | GCForeground, tmpval); + + ValidateGC(&pPix->drawable, fakexa->pGC); + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbFill of the rectangle to be drawn. + */ +static void +ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1); +} + +/** + * Cleans up the scratch GC created in ephyrPrepareSolid. + */ +static void +ephyrDoneSolid(PixmapPtr pPix) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + FreeScratchGC(fakexa->pGC); + + ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST); +} + +/** + * Sets up a scratch GC for fbCopyArea, and saves other parameters for the + * ephyrCopy implementation. + */ +static Bool +ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu, + Pixel pm) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + ChangeGCVal tmpval[2]; + + ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); + ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); + + fakexa->pSrc = pSrc; + fakexa->pDst = pDst; + fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen); + + tmpval[0].val = alu; + tmpval[1].val = pm; + ChangeGC (NullClient, fakexa->pGC, GCFunction | GCPlaneMask, tmpval); + + ValidateGC(&pDst->drawable, fakexa->pGC); + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbCopyArea to take care of the requested copy. + */ +static void +ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC, + srcX, srcY, w, h, dstX, dstY); +} + +/** + * Cleans up the scratch GC created in ephyrPrepareCopy. + */ +static void +ephyrDoneCopy(PixmapPtr pDst) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + FreeScratchGC (fakexa->pGC); + + ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); + ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); +} + +/** + * Reports that we can always accelerate the given operation. This may not be + * desirable from an EXA testing standpoint -- testing the fallback paths would + * be useful, too. + */ +static Bool +ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + /* Exercise the component alpha helper, so fail on this case like a normal + * driver + */ + if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver) + return FALSE; + + return TRUE; +} + +/** + * Saves off the parameters for ephyrComposite. + */ +static Bool +ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, + PixmapPtr pDst) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); + ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); + if (pMask != NULL) + ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK); + + fakexa->op = op; + fakexa->pSrcPicture = pSrcPicture; + fakexa->pMaskPicture = pMaskPicture; + fakexa->pDstPicture = pDstPicture; + fakexa->pSrc = pSrc; + fakexa->pMask = pMask; + fakexa->pDst = pDst; + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbComposite to complete the requested drawing operation. + */ +static void +ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int w, int h) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture, + fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY, + w, h); +} + +static void +ephyrDoneComposite(PixmapPtr pDst) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + if (fakexa->pMask != NULL) + ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK); + ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); + ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); +} + +/** + * Does fake acceleration of DownloadFromScren using memcpy. + */ +static Bool +ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst, + int dst_pitch) +{ + KdScreenPriv(pSrc->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + unsigned char *src; + int src_pitch, cpp; + + if (pSrc->drawable.bitsPerPixel < 8) + return FALSE; + + ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); + + cpp = pSrc->drawable.bitsPerPixel / 8; + src_pitch = exaGetPixmapPitch(pSrc); + src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc); + src += y * src_pitch + x * cpp; + + for (; h > 0; h--) { + memcpy(dst, src, w * cpp); + dst += dst_pitch; + src += src_pitch; + } + + exaMarkSync(pSrc->drawable.pScreen); + + ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC); + + return TRUE; +} + +/** + * Does fake acceleration of UploadToScreen using memcpy. + */ +static Bool +ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src, + int src_pitch) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + unsigned char *dst; + int dst_pitch, cpp; + + if (pDst->drawable.bitsPerPixel < 8) + return FALSE; + + ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); + + cpp = pDst->drawable.bitsPerPixel / 8; + dst_pitch = exaGetPixmapPitch(pDst); + dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst); + dst += y * dst_pitch + x * cpp; + + for (; h > 0; h--) { + memcpy(dst, src, w * cpp); + dst += dst_pitch; + src += src_pitch; + } + + exaMarkSync(pDst->drawable.pScreen); + + ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST); + + return TRUE; +} + +static Bool +ephyrPrepareAccess(PixmapPtr pPix, int index) +{ + /* Make sure we don't somehow end up with a pointer that is in framebuffer + * and hasn't been readied for us. + */ + assert(pPix->devPrivate.ptr != NULL); + + return TRUE; +} + +/** + * In fakexa, we currently only track whether we have synced to the latest + * "accelerated" drawing that has happened or not. It's not used for anything + * yet. + */ +static int +ephyrMarkSync(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fakexa->is_synced = FALSE; + + return 0; +} + +/** + * Assumes that we're waiting on the latest marker. When EXA gets smarter and + * starts using markers in a fine-grained way (for example, waiting on drawing + * to required pixmaps to complete, rather than waiting for all drawing to + * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker + * implementation fine-grained as well. + */ +static void +ephyrWaitMarker(ScreenPtr pScreen, int marker) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fakexa->is_synced = TRUE; +} + +/** + * This function initializes EXA to use the fake acceleration implementation + * which just falls through to software. The purpose is to have a reliable, + * correct driver with which to test changes to the EXA core. + */ +Bool +ephyrDrawInit(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrPriv *priv = screen->card->driver; + EphyrFakexaPriv *fakexa; + Bool success; + + fakexa = calloc(1, sizeof(*fakexa)); + if (fakexa == NULL) + return FALSE; + + fakexa->exa = exaDriverAlloc(); + if (fakexa->exa == NULL) { + free(fakexa); + return FALSE; + } + + fakexa->exa->memoryBase = (CARD8 *) (priv->base); + fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen); + fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height; + + /* Since we statically link against EXA, we shouldn't have to be smart about + * versioning. + */ + fakexa->exa->exa_major = 2; + fakexa->exa->exa_minor = 0; + + fakexa->exa->PrepareSolid = ephyrPrepareSolid; + fakexa->exa->Solid = ephyrSolid; + fakexa->exa->DoneSolid = ephyrDoneSolid; + + fakexa->exa->PrepareCopy = ephyrPrepareCopy; + fakexa->exa->Copy = ephyrCopy; + fakexa->exa->DoneCopy = ephyrDoneCopy; + + fakexa->exa->CheckComposite = ephyrCheckComposite; + fakexa->exa->PrepareComposite = ephyrPrepareComposite; + fakexa->exa->Composite = ephyrComposite; + fakexa->exa->DoneComposite = ephyrDoneComposite; + + fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen; + fakexa->exa->UploadToScreen = ephyrUploadToScreen; + + fakexa->exa->MarkSync = ephyrMarkSync; + fakexa->exa->WaitMarker = ephyrWaitMarker; + + fakexa->exa->PrepareAccess = ephyrPrepareAccess; + + fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN; + fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN; + + fakexa->exa->maxX = 1023; + fakexa->exa->maxY = 1023; + + fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS; + + success = exaDriverInit(pScreen, fakexa->exa); + if (success) { + ErrorF("Initialized fake EXA acceleration\n"); + scrpriv->fakexa = fakexa; + } else { + ErrorF("Failed to initialize EXA\n"); + free(fakexa->exa); + free(fakexa); + } + + return success; +} + +void +ephyrDrawEnable(ScreenPtr pScreen) +{ +} + +void +ephyrDrawDisable(ScreenPtr pScreen) +{ +} + +void +ephyrDrawFini(ScreenPtr pScreen) +{ +} + +/** + * exaDDXDriverInit is required by the top-level EXA module, and is used by + * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since + * we won't be enabling/disabling the FB. + */ +void +exaDDXDriverInit(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + + pExaScr->migration = ExaMigrationSmart; + pExaScr->checkDirtyCorrectness = TRUE; +} diff --git a/xorg-server/hw/kdrive/ephyr/ephyrdriext.c b/xorg-server/hw/kdrive/ephyr/ephyrdriext.c index 5f5fd3bff..3d3d18a39 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyrdriext.c +++ b/xorg-server/hw/kdrive/ephyr/ephyrdriext.c @@ -1,1429 +1,1429 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum <mallum@openedhand.com> - * - * Copyright © 2007 OpenedHand Ltd - * - * 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 OpenedHand Ltd not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. OpenedHand Ltd makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OpenedHand Ltd 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 file is heavily copied from hw/xfree86/dri/xf86dri.c - * - * Authors: - * Dodji Seketeli <dodji@openedhand.com> - */ - -#ifdef HAVE_CONFIG_H -#include <kdrive-config.h> -#endif - -#include <string.h> - -#include <X11/X.h> -#include <X11/Xproto.h> -#define _XF86DRI_SERVER_ -#include <X11/dri/xf86dri.h> -#include <X11/dri/xf86driproto.h> -#include "misc.h" -#include "privates.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "windowstr.h" -#include "servermd.h" -#include "swaprep.h" -#include "ephyrdri.h" -#include "ephyrdriext.h" -#include "hostx.h" -#define _HAVE_XALLOC_DECLS -#include "ephyrlog.h" -#include "protocol-versions.h" - -typedef struct { - int foo; -} EphyrDRIWindowPrivRec; -typedef EphyrDRIWindowPrivRec* EphyrDRIWindowPrivPtr; - -typedef struct { - CreateWindowProcPtr CreateWindow ; - DestroyWindowProcPtr DestroyWindow ; - MoveWindowProcPtr MoveWindow ; - PositionWindowProcPtr PositionWindow ; - ClipNotifyProcPtr ClipNotify ; -} EphyrDRIScreenPrivRec; -typedef EphyrDRIScreenPrivRec* EphyrDRIScreenPrivPtr; - -static int DRIErrorBase; - -static DISPATCH_PROC(ProcXF86DRIQueryVersion); -static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable); -static DISPATCH_PROC(ProcXF86DRIOpenConnection); -static DISPATCH_PROC(ProcXF86DRICloseConnection); -static DISPATCH_PROC(ProcXF86DRIGetClientDriverName); -static DISPATCH_PROC(ProcXF86DRICreateContext); -static DISPATCH_PROC(ProcXF86DRIDestroyContext); -static DISPATCH_PROC(ProcXF86DRICreateDrawable); -static DISPATCH_PROC(ProcXF86DRIDestroyDrawable); -static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo); -static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo); -static DISPATCH_PROC(ProcXF86DRIDispatch); -static DISPATCH_PROC(ProcXF86DRIAuthConnection); - -static DISPATCH_PROC(SProcXF86DRIQueryVersion); -static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable); -static DISPATCH_PROC(SProcXF86DRIDispatch); - -static Bool ephyrDRIScreenInit (ScreenPtr a_screen) ; -static Bool ephyrDRICreateWindow (WindowPtr a_win) ; -static Bool ephyrDRIDestroyWindow (WindowPtr a_win) ; -static void ephyrDRIMoveWindow (WindowPtr a_win, - int a_x, int a_y, - WindowPtr a_siblings, - VTKind a_kind); -static Bool ephyrDRIPositionWindow (WindowPtr a_win, - int x, int y) ; -static void ephyrDRIClipNotify (WindowPtr a_win, - int a_x, int a_y) ; - -static Bool EphyrMirrorHostVisuals (ScreenPtr a_screen) ; -static Bool destroyHostPeerWindow (const WindowPtr a_win) ; -static Bool findWindowPairFromLocal (WindowPtr a_local, - EphyrWindowPair **a_pair); - -static unsigned char DRIReqCode = 0; - -static int ephyrDRIWindowKeyIndex; -static DevPrivateKey ephyrDRIWindowKey = &ephyrDRIWindowKeyIndex; -static int ephyrDRIScreenKeyIndex; -static DevPrivateKey ephyrDRIScreenKey = &ephyrDRIScreenKeyIndex; - -#define GET_EPHYR_DRI_WINDOW_PRIV(win) ((EphyrDRIWindowPrivPtr) \ - dixLookupPrivate(&(win)->devPrivates, ephyrDRIWindowKey)) -#define GET_EPHYR_DRI_SCREEN_PRIV(screen) ((EphyrDRIScreenPrivPtr) \ - dixLookupPrivate(&(screen)->devPrivates, ephyrDRIScreenKey)) - - -Bool -ephyrDRIExtensionInit (ScreenPtr a_screen) -{ - Bool is_ok=FALSE ; - ExtensionEntry* extEntry=NULL; - EphyrDRIScreenPrivPtr screen_priv=NULL ; - - EPHYR_LOG ("enter\n") ; - if (!hostx_has_dri ()) { - EPHYR_LOG ("host does not have DRI extension\n") ; - goto out ; - } - EPHYR_LOG ("host X does have DRI extension\n") ; - if (!hostx_has_xshape ()) { - EPHYR_LOG ("host does not have XShape extension\n") ; - goto out ; - } - EPHYR_LOG ("host X does have XShape extension\n") ; - -#ifdef XF86DRI_EVENTS - EventType = CreateNewResourceType (XF86DRIFreeEvents, "DRIEvents"); - if (!EventType) { - EPHYR_LOG_ERROR ("failed to register DRI event resource type\n") ; - goto out ; - } -#endif - - if ((extEntry = AddExtension(XF86DRINAME, - XF86DRINumberEvents, - XF86DRINumberErrors, - ProcXF86DRIDispatch, - SProcXF86DRIDispatch, - NULL, - StandardMinorOpcode))) { - DRIReqCode = (unsigned char)extEntry->base; - DRIErrorBase = extEntry->errorBase; - } else { - EPHYR_LOG_ERROR ("failed to register DRI extension\n") ; - goto out ; - } - screen_priv = xcalloc (1, sizeof (EphyrDRIScreenPrivRec)) ; - if (!screen_priv) { - EPHYR_LOG_ERROR ("failed to allocate screen_priv\n") ; - goto out ; - } - dixSetPrivate(&a_screen->devPrivates, ephyrDRIScreenKey, screen_priv); - - if (!ephyrDRIScreenInit (a_screen)) { - EPHYR_LOG_ERROR ("ephyrDRIScreenInit() failed\n") ; - goto out ; - } - EphyrMirrorHostVisuals (a_screen) ; - is_ok=TRUE ; -out: - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -static Bool -ephyrDRIScreenInit (ScreenPtr a_screen) -{ - Bool is_ok=FALSE ; - EphyrDRIScreenPrivPtr screen_priv=NULL ; - - EPHYR_RETURN_VAL_IF_FAIL (a_screen, FALSE) ; - - screen_priv=GET_EPHYR_DRI_SCREEN_PRIV (a_screen) ; - EPHYR_RETURN_VAL_IF_FAIL (screen_priv, FALSE) ; - - screen_priv->CreateWindow = a_screen->CreateWindow ; - screen_priv->DestroyWindow = a_screen->DestroyWindow ; - screen_priv->MoveWindow = a_screen->MoveWindow ; - screen_priv->PositionWindow = a_screen->PositionWindow ; - screen_priv->ClipNotify = a_screen->ClipNotify ; - - a_screen->CreateWindow = ephyrDRICreateWindow ; - a_screen->DestroyWindow = ephyrDRIDestroyWindow ; - a_screen->MoveWindow = ephyrDRIMoveWindow ; - a_screen->PositionWindow = ephyrDRIPositionWindow ; - a_screen->ClipNotify = ephyrDRIClipNotify ; - - is_ok = TRUE ; - - return is_ok ; -} - -static Bool -ephyrDRICreateWindow (WindowPtr a_win) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - - EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_VAL_IF_FAIL (screen_priv - && screen_priv->CreateWindow, - FALSE) ; - - EPHYR_LOG ("enter. win:%p\n", a_win) ; - - screen->CreateWindow = screen_priv->CreateWindow ; - is_ok = (*screen->CreateWindow) (a_win) ; - screen->CreateWindow = ephyrDRICreateWindow ; - - if (is_ok) { - dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); - } - return is_ok ; -} - -static Bool -ephyrDRIDestroyWindow (WindowPtr a_win) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - - EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_VAL_IF_FAIL (screen_priv - && screen_priv->DestroyWindow, - FALSE) ; - - screen->DestroyWindow = screen_priv->DestroyWindow ; - if (screen->DestroyWindow) { - is_ok = (*screen->DestroyWindow) (a_win) ; - } - screen->DestroyWindow = ephyrDRIDestroyWindow ; - - if (is_ok) { - EphyrDRIWindowPrivPtr win_priv=GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; - if (win_priv) { - destroyHostPeerWindow (a_win) ; - xfree (win_priv) ; - dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); - EPHYR_LOG ("destroyed the remote peer window\n") ; - } - } - return is_ok ; -} - -static void -ephyrDRIMoveWindow (WindowPtr a_win, - int a_x, int a_y, - WindowPtr a_siblings, - VTKind a_kind) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - EphyrDRIWindowPrivPtr win_priv=NULL ; - EphyrWindowPair *pair=NULL ; - EphyrBox geo; - int x=0,y=0;/*coords relative to parent window*/ - - EPHYR_RETURN_IF_FAIL (a_win) ; - - EPHYR_LOG ("enter\n") ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_IF_FAIL (screen) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_IF_FAIL (screen_priv - && screen_priv->MoveWindow) ; - - screen->MoveWindow = screen_priv->MoveWindow ; - if (screen->MoveWindow) { - (*screen->MoveWindow) (a_win, a_x, a_y, a_siblings, a_kind) ; - } - screen->MoveWindow = ephyrDRIMoveWindow ; - - EPHYR_LOG ("window: %p\n", a_win) ; - if (!a_win->parent) { - EPHYR_LOG ("cannot move root window\n") ; - is_ok = TRUE ; - goto out ; - } - win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; - if (!win_priv) { - EPHYR_LOG ("not a DRI peered window\n") ; - is_ok = TRUE ; - goto out ; - } - if (!findWindowPairFromLocal (a_win, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to get window pair\n") ; - goto out ; - } - /*compute position relative to parent window*/ - x = a_win->drawable.x - a_win->parent->drawable.x ; - y = a_win->drawable.y - a_win->parent->drawable.y ; - /*set the geometry to pass to hostx_set_window_geometry*/ - memset (&geo, 0, sizeof (geo)) ; - geo.x = x ; - geo.y = y ; - geo.width = a_win->drawable.width ; - geo.height = a_win->drawable.height ; - hostx_set_window_geometry (pair->remote, &geo) ; - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; - /*do cleanup here*/ -} - -static Bool -ephyrDRIPositionWindow (WindowPtr a_win, - int a_x, int a_y) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - EphyrDRIWindowPrivPtr win_priv=NULL ; - EphyrWindowPair *pair=NULL ; - EphyrBox geo; - - EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; - - EPHYR_LOG ("enter\n") ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_VAL_IF_FAIL (screen_priv - && screen_priv->PositionWindow, - FALSE) ; - - screen->PositionWindow = screen_priv->PositionWindow ; - if (screen->PositionWindow) { - (*screen->PositionWindow) (a_win, a_x, a_y) ; - } - screen->PositionWindow = ephyrDRIPositionWindow ; - - EPHYR_LOG ("window: %p\n", a_win) ; - win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; - if (!win_priv) { - EPHYR_LOG ("not a DRI peered window\n") ; - is_ok = TRUE ; - goto out ; - } - if (!findWindowPairFromLocal (a_win, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to get window pair\n") ; - goto out ; - } - /*set the geometry to pass to hostx_set_window_geometry*/ - memset (&geo, 0, sizeof (geo)) ; - geo.x = a_x ; - geo.y = a_y ; - geo.width = a_win->drawable.width ; - geo.height = a_win->drawable.height ; - hostx_set_window_geometry (pair->remote, &geo) ; - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; - /*do cleanup here*/ - return is_ok ; -} - -static void -ephyrDRIClipNotify (WindowPtr a_win, - int a_x, int a_y) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - EphyrDRIWindowPrivPtr win_priv=NULL ; - EphyrWindowPair *pair=NULL ; - EphyrRect *rects=NULL; - int i=0 ; - - EPHYR_RETURN_IF_FAIL (a_win) ; - - EPHYR_LOG ("enter\n") ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_IF_FAIL (screen) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_IF_FAIL (screen_priv && screen_priv->ClipNotify) ; - - screen->ClipNotify = screen_priv->ClipNotify ; - if (screen->ClipNotify) { - (*screen->ClipNotify) (a_win, a_x, a_y) ; - } - screen->ClipNotify = ephyrDRIClipNotify ; - - EPHYR_LOG ("window: %p\n", a_win) ; - win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; - if (!win_priv) { - EPHYR_LOG ("not a DRI peered window\n") ; - is_ok = TRUE ; - goto out ; - } - if (!findWindowPairFromLocal (a_win, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to get window pair\n") ; - goto out ; - } - rects = xcalloc (REGION_NUM_RECTS (&a_win->clipList), - sizeof (EphyrRect)) ; - for (i=0; i < REGION_NUM_RECTS (&a_win->clipList); i++) { - memmove (&rects[i], - ®ION_RECTS (&a_win->clipList)[i], - sizeof (EphyrRect)) ; - rects[i].x1 -= a_win->drawable.x; - rects[i].x2 -= a_win->drawable.x; - rects[i].y1 -= a_win->drawable.y; - rects[i].y2 -= a_win->drawable.y; - } - /* - * push the clipping region of this window - * to the peer window in the host - */ - is_ok = hostx_set_window_bounding_rectangles - (pair->remote, - rects, - REGION_NUM_RECTS (&a_win->clipList)) ; - is_ok = TRUE ; - -out: - xfree (rects) ; - rects = NULL ; - - EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; - /*do cleanup here*/ -} - -/** - * Duplicates a visual of a_screen - * In screen a_screen, for depth a_depth, find a visual which - * bitsPerRGBValue and colormap size equal - * a_bits_per_rgb_values and a_colormap_entries. - * The ID of that duplicated visual is set to a_new_id. - * That duplicated visual is then added to the list of visuals - * of the screen. - */ -static Bool -EphyrDuplicateVisual (unsigned int a_screen, - short a_depth, - short a_class, - short a_bits_per_rgb_values, - short a_colormap_entries, - unsigned int a_red_mask, - unsigned int a_green_mask, - unsigned int a_blue_mask, - unsigned int a_new_id) -{ - Bool is_ok = FALSE, found_visual=FALSE, found_depth=FALSE ; - ScreenPtr screen=NULL ; - VisualRec new_visual, *new_visuals=NULL ; - int i=0 ; - - EPHYR_LOG ("enter\n") ; - if (a_screen > screenInfo.numScreens) { - EPHYR_LOG_ERROR ("bad screen number\n") ; - goto out; - } - memset (&new_visual, 0, sizeof (VisualRec)) ; - - /*get the screen pointed to by a_screen*/ - screen = screenInfo.screens[a_screen] ; - EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; - - /* - * In that screen, first look for an existing visual that has the - * same characteristics as those passed in parameter - * to this function and copy it. - */ - for (i=0; i < screen->numVisuals; i++) { - if (screen->visuals[i].bitsPerRGBValue == a_bits_per_rgb_values && - screen->visuals[i].ColormapEntries == a_colormap_entries ) { - /*copy the visual found*/ - memcpy (&new_visual, &screen->visuals[i], sizeof (new_visual)) ; - new_visual.vid = a_new_id ; - new_visual.class = a_class ; - new_visual.redMask = a_red_mask ; - new_visual.greenMask = a_green_mask ; - new_visual.blueMask = a_blue_mask ; - found_visual = TRUE ; - EPHYR_LOG ("found a visual that matches visual id: %d\n", - a_new_id) ; - break; - } - } - if (!found_visual) { - EPHYR_LOG ("did not find any visual matching %d\n", a_new_id) ; - goto out ; - } - /* - * be prepare to extend screen->visuals to add new_visual to it - */ - new_visuals = xcalloc (screen->numVisuals+1, sizeof (VisualRec)) ; - memmove (new_visuals, - screen->visuals, - screen->numVisuals*sizeof (VisualRec)) ; - memmove (&new_visuals[screen->numVisuals], - &new_visual, - sizeof (VisualRec)) ; - /* - * Now, in that same screen, update the screen->allowedDepths member. - * In that array, each element represents the visuals applicable to - * a given depth. So we need to add an entry matching the new visual - * that we are going to add to screen->visuals - */ - for (i=0; i<screen->numDepths; i++) { - VisualID *vids=NULL; - DepthPtr cur_depth=NULL ; - /*find the entry matching a_depth*/ - if (screen->allowedDepths[i].depth != a_depth) - continue ; - cur_depth = &screen->allowedDepths[i]; - /* - * extend the list of visual IDs in that entry, - * so to add a_new_id in there. - */ - vids = xrealloc (cur_depth->vids, - (cur_depth->numVids+1)*sizeof (VisualID)); - if (!vids) { - EPHYR_LOG_ERROR ("failed to realloc numids\n") ; - goto out ; - } - vids[cur_depth->numVids] = a_new_id ; - /* - * Okay now commit our change. - * Do really update screen->allowedDepths[i] - */ - cur_depth->numVids++ ; - cur_depth->vids = vids ; - found_depth=TRUE; - } - if (!found_depth) { - EPHYR_LOG_ERROR ("failed to update screen[%d]->allowedDepth\n", - a_screen) ; - goto out ; - } - /* - * Commit our change to screen->visuals - */ - xfree (screen->visuals) ; - screen->visuals = new_visuals ; - screen->numVisuals++ ; - new_visuals = NULL ; - - is_ok = TRUE ; -out: - xfree (new_visuals) ; - new_visuals = NULL ; - - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -/** - * Duplicates the visuals of the host X server. - * This is necessary to have visuals that have the same - * ID as those of the host X. It is important to have that for - * GLX. - */ -static Bool -EphyrMirrorHostVisuals (ScreenPtr a_screen) -{ - Bool is_ok=FALSE; - EphyrHostVisualInfo *visuals=NULL; - int nb_visuals=0, i=0; - - EPHYR_LOG ("enter\n") ; - if (!hostx_get_visuals_info (&visuals, &nb_visuals)) { - EPHYR_LOG_ERROR ("failed to get host visuals\n") ; - goto out ; - } - for (i=0; i<nb_visuals; i++) { - if (!EphyrDuplicateVisual (a_screen->myNum, - visuals[i].depth, - visuals[i].class, - visuals[i].bits_per_rgb, - visuals[i].colormap_size, - visuals[i].red_mask, - visuals[i].green_mask, - visuals[i].blue_mask, - visuals[i].visualid)) { - EPHYR_LOG_ERROR ("failed to duplicate host visual %d\n", - (int)visuals[i].visualid) ; - } - } - - is_ok = TRUE ; -out: - EPHYR_LOG ("leave\n") ; - return is_ok; -} - - -static int -ProcXF86DRIQueryVersion (register ClientPtr client) -{ - xXF86DRIQueryVersionReply rep; - register int n; - REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq); - - EPHYR_LOG ("enter\n") ; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_XF86DRI_MAJOR_VERSION; - rep.minorVersion = SERVER_XF86DRI_MINOR_VERSION; - rep.patchVersion = SERVER_XF86DRI_PATCH_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - swapl(&rep.patchVersion, n); - } - WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) -{ - xXF86DRIQueryDirectRenderingCapableReply rep; - Bool isCapable; - register int n; - REQUEST(xXF86DRIQueryDirectRenderingCapableReq); - REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if (!ephyrDRIQueryDirectRenderingCapable (stuff->screen, &isCapable)) { - return BadValue; - } - rep.isCapable = isCapable; - - if (!LocalClient(client) || client->swapped) - rep.isCapable = 0; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - } - - WriteToClient(client, sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - - return (client->noClientException); -} - -static int -ProcXF86DRIOpenConnection (register ClientPtr client) -{ - xXF86DRIOpenConnectionReply rep; - drm_handle_t hSAREA; - char* busIdString; - REQUEST(xXF86DRIOpenConnectionReq); - REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - if (!ephyrDRIOpenConnection(stuff->screen, - &hSAREA, - &busIdString)) { - return BadValue; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.busIdStringLength = 0; - if (busIdString) - rep.busIdStringLength = strlen(busIdString); - rep.length = bytes_to_int32(SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) + - pad_to_int32(rep.busIdStringLength)); - - rep.hSAREALow = (CARD32)(hSAREA & 0xffffffff); -#if defined(LONG64) && !defined(__linux__) - rep.hSAREAHigh = (CARD32)(hSAREA >> 32); -#else - rep.hSAREAHigh = 0; -#endif - - WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep); - if (rep.busIdStringLength) - WriteToClient(client, rep.busIdStringLength, busIdString); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIAuthConnection (register ClientPtr client) -{ - xXF86DRIAuthConnectionReply rep; - REQUEST(xXF86DRIAuthConnectionReq); - REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.authenticated = 1; - - if (!ephyrDRIAuthConnection (stuff->screen, stuff->magic)) { - ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic); - rep.authenticated = 0; - } - WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRICloseConnection (register ClientPtr client) -{ - REQUEST(xXF86DRICloseConnectionReq); - REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq); - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - /* - DRICloseConnection( screenInfo.screens[stuff->screen]); - */ - - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIGetClientDriverName (register ClientPtr client) -{ - xXF86DRIGetClientDriverNameReply rep; - char* clientDriverName; - REQUEST(xXF86DRIGetClientDriverNameReq); - REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - ephyrDRIGetClientDriverName (stuff->screen, - (int *)&rep.ddxDriverMajorVersion, - (int *)&rep.ddxDriverMinorVersion, - (int *)&rep.ddxDriverPatchVersion, - &clientDriverName); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.clientDriverNameLength = 0; - if (clientDriverName) - rep.clientDriverNameLength = strlen(clientDriverName); - rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetClientDriverNameReply) - - SIZEOF(xGenericReply) + - pad_to_int32(rep.clientDriverNameLength)); - - WriteToClient(client, - sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep); - if (rep.clientDriverNameLength) - WriteToClient(client, - rep.clientDriverNameLength, - clientDriverName); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRICreateContext (register ClientPtr client) -{ - xXF86DRICreateContextReply rep; - ScreenPtr pScreen; - VisualPtr visual; - int i=0; - unsigned long context_id=0; - REQUEST(xXF86DRICreateContextReq); - REQUEST_SIZE_MATCH(xXF86DRICreateContextReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - pScreen = screenInfo.screens[stuff->screen]; - visual = pScreen->visuals; - - /* Find the requested X visual */ - for (i = 0; i < pScreen->numVisuals; i++, visual++) - if (visual->vid == stuff->visual) - break; - if (i == pScreen->numVisuals) { - /* No visual found */ - return BadValue; - } - - context_id = stuff->context ; - if (!ephyrDRICreateContext (stuff->screen, - stuff->visual, - &context_id, - (drm_context_t *)&rep.hHWContext)) { - return BadValue; - } - - WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIDestroyContext (register ClientPtr client) -{ - REQUEST(xXF86DRIDestroyContextReq); - REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq); - EPHYR_LOG ("enter\n") ; - - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - if (!ephyrDRIDestroyContext (stuff->screen, stuff->context)) { - return BadValue; - } - - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static Bool -getWindowVisual (const WindowPtr a_win, - VisualPtr *a_visual) -{ - int i=0, visual_id=0 ; - EPHYR_RETURN_VAL_IF_FAIL (a_win - && a_win->drawable.pScreen - && a_win->drawable.pScreen->visuals, - FALSE) ; - - visual_id = wVisual (a_win) ; - for (i=0; i < a_win->drawable.pScreen->numVisuals; i++) { - if (a_win->drawable.pScreen->visuals[i].vid == visual_id) { - *a_visual = &a_win->drawable.pScreen->visuals[i] ; - return TRUE ; - } - } - return FALSE ; -} - - -#define NUM_WINDOW_PAIRS 256 -static EphyrWindowPair window_pairs[NUM_WINDOW_PAIRS] ; - -static Bool -appendWindowPairToList (WindowPtr a_local, - int a_remote) -{ - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_local, FALSE) ; - - EPHYR_LOG ("(local,remote):(%p, %d)\n", a_local, a_remote) ; - - for (i=0; i < NUM_WINDOW_PAIRS; i++) { - if (window_pairs[i].local == NULL) { - window_pairs[i].local = a_local ; - window_pairs[i].remote = a_remote ; - return TRUE ; - } - } - return FALSE ; -} - -static Bool -findWindowPairFromLocal (WindowPtr a_local, - EphyrWindowPair **a_pair) -{ - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_pair && a_local, FALSE) ; - - for (i=0; i < NUM_WINDOW_PAIRS; i++) { - if (window_pairs[i].local == a_local) { - *a_pair = &window_pairs[i] ; - EPHYR_LOG ("found (%p, %d)\n", - (*a_pair)->local, - (*a_pair)->remote) ; - return TRUE ; - } - } - return FALSE ; -} - -Bool -findWindowPairFromRemote (int a_remote, - EphyrWindowPair **a_pair) -{ - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_pair, FALSE) ; - - for (i=0; i < NUM_WINDOW_PAIRS; i++) { - if (window_pairs[i].remote == a_remote) { - *a_pair = &window_pairs[i] ; - EPHYR_LOG ("found (%p, %d)\n", - (*a_pair)->local, - (*a_pair)->remote) ; - return TRUE ; - } - } - return FALSE ; -} - -static Bool -createHostPeerWindow (const WindowPtr a_win, - int *a_peer_win) -{ - Bool is_ok=FALSE ; - VisualPtr visual=NULL; - EphyrBox geo ; - - EPHYR_RETURN_VAL_IF_FAIL (a_win && a_peer_win, FALSE) ; - EPHYR_RETURN_VAL_IF_FAIL (a_win->drawable.pScreen, - FALSE) ; - - EPHYR_LOG ("enter. a_win '%p'\n", a_win) ; - if (!getWindowVisual (a_win, &visual)) { - EPHYR_LOG_ERROR ("failed to get window visual\n") ; - goto out ; - } - if (!visual) { - EPHYR_LOG_ERROR ("failed to create visual\n") ; - goto out ; - } - memset (&geo, 0, sizeof (geo)) ; - geo.x = a_win->drawable.x ; - geo.y = a_win->drawable.y ; - geo.width = a_win->drawable.width ; - geo.height = a_win->drawable.height ; - if (!hostx_create_window (a_win->drawable.pScreen->myNum, - &geo, visual->vid, a_peer_win)) { - EPHYR_LOG_ERROR ("failed to create host peer window\n") ; - goto out ; - } - if (!appendWindowPairToList (a_win, *a_peer_win)) { - EPHYR_LOG_ERROR ("failed to append window to pair list\n") ; - goto out ; - } - is_ok = TRUE ; -out: - EPHYR_LOG ("leave:remote win%d\n", *a_peer_win) ; - return is_ok ; -} - -static Bool -destroyHostPeerWindow (const WindowPtr a_win) -{ - Bool is_ok = FALSE ; - EphyrWindowPair *pair=NULL ; - EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - if (!findWindowPairFromLocal (a_win, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to find peer to local window\n") ; - goto out; - } - hostx_destroy_window (pair->remote) ; - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return is_ok; -} - -static int -ProcXF86DRICreateDrawable (ClientPtr client) -{ - xXF86DRICreateDrawableReply rep; - DrawablePtr drawable=NULL; - WindowPtr window=NULL ; - EphyrWindowPair *pair=NULL ; - EphyrDRIWindowPrivPtr win_priv=NULL; - int rc=0, remote_win=0; - REQUEST(xXF86DRICreateDrawableReq); - REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = dixLookupDrawable (&drawable, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - if (drawable->type != DRAWABLE_WINDOW) { - EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; - return BadImplementation ; - } - EPHYR_LOG ("lookedup drawable %p\n", drawable) ; - window = (WindowPtr)drawable; - if (findWindowPairFromLocal (window, &pair) && pair) { - remote_win = pair->remote ; - EPHYR_LOG ("found window '%p' paire with remote '%d'\n", - window, remote_win) ; - } else if (!createHostPeerWindow (window, &remote_win)) { - EPHYR_LOG_ERROR ("failed to create host peer window\n") ; - return BadAlloc ; - } - - if (!ephyrDRICreateDrawable (stuff->screen, - remote_win, - (drm_drawable_t *)&rep.hHWDrawable)) { - EPHYR_LOG_ERROR ("failed to create dri drawable\n") ; - return BadValue; - } - - win_priv = GET_EPHYR_DRI_WINDOW_PRIV (window) ; - if (!win_priv) { - win_priv = xcalloc (1, sizeof (EphyrDRIWindowPrivRec)) ; - if (!win_priv) { - EPHYR_LOG_ERROR ("failed to allocate window private\n") ; - return BadAlloc ; - } - dixSetPrivate(&window->devPrivates, ephyrDRIWindowKey, win_priv); - EPHYR_LOG ("paired window '%p' with remote '%d'\n", - window, remote_win) ; - } - - WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIDestroyDrawable (register ClientPtr client) -{ - DrawablePtr drawable=NULL; - WindowPtr window=NULL; - EphyrWindowPair *pair=NULL; - int rc=0; - REQUEST(xXF86DRIDestroyDrawableReq); - REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rc = dixLookupDrawable(&drawable, - stuff->drawable, - client, - 0, - DixReadAccess); - if (rc != Success) - return rc; - if (drawable->type != DRAWABLE_WINDOW) { - EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; - return BadImplementation ; - } - window = (WindowPtr)drawable; - if (!findWindowPairFromLocal (window, &pair) && pair) { - EPHYR_LOG_ERROR ("failed to find pair window\n") ; - return BadImplementation; - } - if (!ephyrDRIDestroyDrawable(stuff->screen, - pair->remote/*drawable in host x*/)) { - EPHYR_LOG_ERROR ("failed to destroy dri drawable\n") ; - return BadImplementation; - } - pair->local=NULL ; - pair->remote=0; - - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIGetDrawableInfo (register ClientPtr client) -{ - xXF86DRIGetDrawableInfoReply rep; - DrawablePtr drawable; - WindowPtr window=NULL; - EphyrWindowPair *pair=NULL; - int X=0, Y=0, W=0, H=0, backX=0, backY=0, rc=0, i=0; - drm_clip_rect_t *clipRects=NULL; - drm_clip_rect_t *backClipRects=NULL; - REQUEST(xXF86DRIGetDrawableInfoReq); - REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq); - - EPHYR_LOG ("enter\n") ; - memset (&rep, 0, sizeof (rep)) ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success || !drawable) { - EPHYR_LOG_ERROR ("could not get drawable\n") ; - return rc; - } - - if (drawable->type != DRAWABLE_WINDOW) { - EPHYR_LOG_ERROR ("non windows type drawables are not yes supported\n") ; - return BadImplementation ; - } - window = (WindowPtr)drawable ; - memset (&pair, 0, sizeof (pair)) ; - if (!findWindowPairFromLocal (window, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ; - return BadMatch ; - } - EPHYR_LOG ("clip list of xephyr gl drawable:\n") ; - for (i=0; i < REGION_NUM_RECTS (&window->clipList); i++) { - EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", - REGION_RECTS (&window->clipList)[i].x1, - REGION_RECTS (&window->clipList)[i].y1, - REGION_RECTS (&window->clipList)[i].x2, - REGION_RECTS (&window->clipList)[i].y2) ; - } - - if (!ephyrDRIGetDrawableInfo (stuff->screen, - pair->remote/*the drawable in hostx*/, - (unsigned int*)&rep.drawableTableIndex, - (unsigned int*)&rep.drawableTableStamp, - (int*)&X, - (int*)&Y, - (int*)&W, - (int*)&H, - (int*)&rep.numClipRects, - &clipRects, - &backX, - &backY, - (int*)&rep.numBackClipRects, - &backClipRects)) { - return BadValue; - } - EPHYR_LOG ("num clip rects:%d, num back clip rects:%d\n", - (int)rep.numClipRects, (int)rep.numBackClipRects) ; - - rep.drawableX = X; - rep.drawableY = Y; - rep.drawableWidth = W; - rep.drawableHeight = H; - rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) - - SIZEOF(xGenericReply)); - - rep.backX = backX; - rep.backY = backY; - - - if (rep.numClipRects) { - if (clipRects) { - ScreenPtr pScreen = screenInfo.screens[stuff->screen]; - int i=0; - EPHYR_LOG ("clip list of host gl drawable:\n") ; - for (i = 0; i < rep.numClipRects; i++) { - clipRects[i].x1 = max (clipRects[i].x1, 0); - clipRects[i].y1 = max (clipRects[i].y1, 0); - clipRects[i].x2 = min (clipRects[i].x2, - pScreen->width + clipRects[i].x1) ; - clipRects[i].y2 = min (clipRects[i].y2, - pScreen->width + clipRects[i].y1) ; - - EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", - clipRects[i].x1, clipRects[i].y1, - clipRects[i].x2, clipRects[i].y2) ; - } - } else { - rep.numClipRects = 0; - } - } else { - EPHYR_LOG ("got zero host gl drawable clipping rects\n") ; - } - rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects; - backClipRects = clipRects ; - rep.numBackClipRects = rep.numClipRects ; - if (rep.numBackClipRects) - rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects; - EPHYR_LOG ("num host clip rects:%d\n", (int)rep.numClipRects) ; - EPHYR_LOG ("num host back clip rects:%d\n", (int)rep.numBackClipRects) ; - - rep.length = bytes_to_int32(rep.length); - - WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep); - - if (rep.numClipRects) { - WriteToClient(client, - sizeof(drm_clip_rect_t) * rep.numClipRects, - (char *)clipRects); - } - - if (rep.numBackClipRects) { - WriteToClient(client, - sizeof(drm_clip_rect_t) * rep.numBackClipRects, - (char *)backClipRects); - } - xfree(clipRects); - clipRects = NULL ; - - EPHYR_LOG ("leave\n") ; - - return (client->noClientException); -} - -static int -ProcXF86DRIGetDeviceInfo (register ClientPtr client) -{ - xXF86DRIGetDeviceInfoReply rep; - drm_handle_t hFrameBuffer; - void *pDevPrivate; - REQUEST(xXF86DRIGetDeviceInfoReq); - REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if (!ephyrDRIGetDeviceInfo (stuff->screen, - &hFrameBuffer, - (int*)&rep.framebufferOrigin, - (int*)&rep.framebufferSize, - (int*)&rep.framebufferStride, - (int*)&rep.devPrivateSize, - &pDevPrivate)) { - return BadValue; - } - - rep.hFrameBufferLow = (CARD32)(hFrameBuffer & 0xffffffff); -#if defined(LONG64) && !defined(__linux__) - rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32); -#else - rep.hFrameBufferHigh = 0; -#endif - - rep.length = 0; - if (rep.devPrivateSize) { - rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetDeviceInfoReply) - - SIZEOF(xGenericReply) + - pad_to_int32(rep.devPrivateSize)); - } - - WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep); - if (rep.length) { - WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate); - } - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIDispatch (register ClientPtr client) -{ - REQUEST(xReq); - EPHYR_LOG ("enter\n") ; - - switch (stuff->data) - { - case X_XF86DRIQueryVersion: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIQueryVersion(client); - } - case X_XF86DRIQueryDirectRenderingCapable: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIQueryDirectRenderingCapable(client); - } - } - - if (!LocalClient(client)) - return DRIErrorBase + XF86DRIClientNotLocal; - - switch (stuff->data) - { - case X_XF86DRIOpenConnection: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIOpenConnection(client); - } - case X_XF86DRICloseConnection: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRICloseConnection(client); - } - case X_XF86DRIGetClientDriverName: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIGetClientDriverName(client); - } - case X_XF86DRICreateContext: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRICreateContext(client); - } - case X_XF86DRIDestroyContext: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIDestroyContext(client); - } - case X_XF86DRICreateDrawable: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRICreateDrawable(client); - } - case X_XF86DRIDestroyDrawable: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIDestroyDrawable(client); - } - case X_XF86DRIGetDrawableInfo: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIGetDrawableInfo(client); - } - case X_XF86DRIGetDeviceInfo: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIGetDeviceInfo(client); - } - case X_XF86DRIAuthConnection: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIAuthConnection(client); - } - /* {Open,Close}FullScreen are deprecated now */ - default: { - EPHYR_LOG ("leave\n") ; - return BadRequest; - } - } -} - -static int -SProcXF86DRIQueryVersion (register ClientPtr client) -{ - register int n; - REQUEST(xXF86DRIQueryVersionReq); - swaps(&stuff->length, n); - return ProcXF86DRIQueryVersion(client); -} - -static int -SProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) -{ - register int n; - REQUEST(xXF86DRIQueryDirectRenderingCapableReq); - swaps(&stuff->length, n); - swapl(&stuff->screen, n); - return ProcXF86DRIQueryDirectRenderingCapable(client); -} - -static int -SProcXF86DRIDispatch (register ClientPtr client) -{ - REQUEST(xReq); - - EPHYR_LOG ("enter\n") ; - /* - * Only local clients are allowed DRI access, but remote clients still need - * these requests to find out cleanly. - */ - switch (stuff->data) - { - case X_XF86DRIQueryVersion: { - EPHYR_LOG ("leave\n") ; - return SProcXF86DRIQueryVersion(client); - } - case X_XF86DRIQueryDirectRenderingCapable: { - EPHYR_LOG ("leave\n") ; - return SProcXF86DRIQueryDirectRenderingCapable(client); - } - default: { - EPHYR_LOG ("leave\n") ; - return DRIErrorBase + XF86DRIClientNotLocal; - } - } -} +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum <mallum@openedhand.com> + * + * Copyright © 2007 OpenedHand Ltd + * + * 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 OpenedHand Ltd not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. OpenedHand Ltd makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OpenedHand Ltd 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 file is heavily copied from hw/xfree86/dri/xf86dri.c + * + * Authors: + * Dodji Seketeli <dodji@openedhand.com> + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif + +#include <string.h> + +#include <X11/X.h> +#include <X11/Xproto.h> +#define _XF86DRI_SERVER_ +#include <X11/dri/xf86dri.h> +#include <X11/dri/xf86driproto.h> +#include "misc.h" +#include "privates.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "servermd.h" +#include "swaprep.h" +#include "ephyrdri.h" +#include "ephyrdriext.h" +#include "hostx.h" +#define _HAVE_XALLOC_DECLS +#include "ephyrlog.h" +#include "protocol-versions.h" + +typedef struct { + int foo; +} EphyrDRIWindowPrivRec; +typedef EphyrDRIWindowPrivRec* EphyrDRIWindowPrivPtr; + +typedef struct { + CreateWindowProcPtr CreateWindow ; + DestroyWindowProcPtr DestroyWindow ; + MoveWindowProcPtr MoveWindow ; + PositionWindowProcPtr PositionWindow ; + ClipNotifyProcPtr ClipNotify ; +} EphyrDRIScreenPrivRec; +typedef EphyrDRIScreenPrivRec* EphyrDRIScreenPrivPtr; + +static int DRIErrorBase; + +static DISPATCH_PROC(ProcXF86DRIQueryVersion); +static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable); +static DISPATCH_PROC(ProcXF86DRIOpenConnection); +static DISPATCH_PROC(ProcXF86DRICloseConnection); +static DISPATCH_PROC(ProcXF86DRIGetClientDriverName); +static DISPATCH_PROC(ProcXF86DRICreateContext); +static DISPATCH_PROC(ProcXF86DRIDestroyContext); +static DISPATCH_PROC(ProcXF86DRICreateDrawable); +static DISPATCH_PROC(ProcXF86DRIDestroyDrawable); +static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo); +static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo); +static DISPATCH_PROC(ProcXF86DRIDispatch); +static DISPATCH_PROC(ProcXF86DRIAuthConnection); + +static DISPATCH_PROC(SProcXF86DRIQueryVersion); +static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable); +static DISPATCH_PROC(SProcXF86DRIDispatch); + +static Bool ephyrDRIScreenInit (ScreenPtr a_screen) ; +static Bool ephyrDRICreateWindow (WindowPtr a_win) ; +static Bool ephyrDRIDestroyWindow (WindowPtr a_win) ; +static void ephyrDRIMoveWindow (WindowPtr a_win, + int a_x, int a_y, + WindowPtr a_siblings, + VTKind a_kind); +static Bool ephyrDRIPositionWindow (WindowPtr a_win, + int x, int y) ; +static void ephyrDRIClipNotify (WindowPtr a_win, + int a_x, int a_y) ; + +static Bool EphyrMirrorHostVisuals (ScreenPtr a_screen) ; +static Bool destroyHostPeerWindow (const WindowPtr a_win) ; +static Bool findWindowPairFromLocal (WindowPtr a_local, + EphyrWindowPair **a_pair); + +static unsigned char DRIReqCode = 0; + +static int ephyrDRIWindowKeyIndex; +static DevPrivateKey ephyrDRIWindowKey = &ephyrDRIWindowKeyIndex; +static int ephyrDRIScreenKeyIndex; +static DevPrivateKey ephyrDRIScreenKey = &ephyrDRIScreenKeyIndex; + +#define GET_EPHYR_DRI_WINDOW_PRIV(win) ((EphyrDRIWindowPrivPtr) \ + dixLookupPrivate(&(win)->devPrivates, ephyrDRIWindowKey)) +#define GET_EPHYR_DRI_SCREEN_PRIV(screen) ((EphyrDRIScreenPrivPtr) \ + dixLookupPrivate(&(screen)->devPrivates, ephyrDRIScreenKey)) + + +Bool +ephyrDRIExtensionInit (ScreenPtr a_screen) +{ + Bool is_ok=FALSE ; + ExtensionEntry* extEntry=NULL; + EphyrDRIScreenPrivPtr screen_priv=NULL ; + + EPHYR_LOG ("enter\n") ; + if (!hostx_has_dri ()) { + EPHYR_LOG ("host does not have DRI extension\n") ; + goto out ; + } + EPHYR_LOG ("host X does have DRI extension\n") ; + if (!hostx_has_xshape ()) { + EPHYR_LOG ("host does not have XShape extension\n") ; + goto out ; + } + EPHYR_LOG ("host X does have XShape extension\n") ; + +#ifdef XF86DRI_EVENTS + EventType = CreateNewResourceType (XF86DRIFreeEvents, "DRIEvents"); + if (!EventType) { + EPHYR_LOG_ERROR ("failed to register DRI event resource type\n") ; + goto out ; + } +#endif + + if ((extEntry = AddExtension(XF86DRINAME, + XF86DRINumberEvents, + XF86DRINumberErrors, + ProcXF86DRIDispatch, + SProcXF86DRIDispatch, + NULL, + StandardMinorOpcode))) { + DRIReqCode = (unsigned char)extEntry->base; + DRIErrorBase = extEntry->errorBase; + } else { + EPHYR_LOG_ERROR ("failed to register DRI extension\n") ; + goto out ; + } + screen_priv = calloc(1, sizeof (EphyrDRIScreenPrivRec)) ; + if (!screen_priv) { + EPHYR_LOG_ERROR ("failed to allocate screen_priv\n") ; + goto out ; + } + dixSetPrivate(&a_screen->devPrivates, ephyrDRIScreenKey, screen_priv); + + if (!ephyrDRIScreenInit (a_screen)) { + EPHYR_LOG_ERROR ("ephyrDRIScreenInit() failed\n") ; + goto out ; + } + EphyrMirrorHostVisuals (a_screen) ; + is_ok=TRUE ; +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +static Bool +ephyrDRIScreenInit (ScreenPtr a_screen) +{ + Bool is_ok=FALSE ; + EphyrDRIScreenPrivPtr screen_priv=NULL ; + + EPHYR_RETURN_VAL_IF_FAIL (a_screen, FALSE) ; + + screen_priv=GET_EPHYR_DRI_SCREEN_PRIV (a_screen) ; + EPHYR_RETURN_VAL_IF_FAIL (screen_priv, FALSE) ; + + screen_priv->CreateWindow = a_screen->CreateWindow ; + screen_priv->DestroyWindow = a_screen->DestroyWindow ; + screen_priv->MoveWindow = a_screen->MoveWindow ; + screen_priv->PositionWindow = a_screen->PositionWindow ; + screen_priv->ClipNotify = a_screen->ClipNotify ; + + a_screen->CreateWindow = ephyrDRICreateWindow ; + a_screen->DestroyWindow = ephyrDRIDestroyWindow ; + a_screen->MoveWindow = ephyrDRIMoveWindow ; + a_screen->PositionWindow = ephyrDRIPositionWindow ; + a_screen->ClipNotify = ephyrDRIClipNotify ; + + is_ok = TRUE ; + + return is_ok ; +} + +static Bool +ephyrDRICreateWindow (WindowPtr a_win) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + + EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_VAL_IF_FAIL (screen_priv + && screen_priv->CreateWindow, + FALSE) ; + + EPHYR_LOG ("enter. win:%p\n", a_win) ; + + screen->CreateWindow = screen_priv->CreateWindow ; + is_ok = (*screen->CreateWindow) (a_win) ; + screen->CreateWindow = ephyrDRICreateWindow ; + + if (is_ok) { + dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); + } + return is_ok ; +} + +static Bool +ephyrDRIDestroyWindow (WindowPtr a_win) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + + EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_VAL_IF_FAIL (screen_priv + && screen_priv->DestroyWindow, + FALSE) ; + + screen->DestroyWindow = screen_priv->DestroyWindow ; + if (screen->DestroyWindow) { + is_ok = (*screen->DestroyWindow) (a_win) ; + } + screen->DestroyWindow = ephyrDRIDestroyWindow ; + + if (is_ok) { + EphyrDRIWindowPrivPtr win_priv=GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; + if (win_priv) { + destroyHostPeerWindow (a_win) ; + free(win_priv) ; + dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); + EPHYR_LOG ("destroyed the remote peer window\n") ; + } + } + return is_ok ; +} + +static void +ephyrDRIMoveWindow (WindowPtr a_win, + int a_x, int a_y, + WindowPtr a_siblings, + VTKind a_kind) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + EphyrDRIWindowPrivPtr win_priv=NULL ; + EphyrWindowPair *pair=NULL ; + EphyrBox geo; + int x=0,y=0;/*coords relative to parent window*/ + + EPHYR_RETURN_IF_FAIL (a_win) ; + + EPHYR_LOG ("enter\n") ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_IF_FAIL (screen) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_IF_FAIL (screen_priv + && screen_priv->MoveWindow) ; + + screen->MoveWindow = screen_priv->MoveWindow ; + if (screen->MoveWindow) { + (*screen->MoveWindow) (a_win, a_x, a_y, a_siblings, a_kind) ; + } + screen->MoveWindow = ephyrDRIMoveWindow ; + + EPHYR_LOG ("window: %p\n", a_win) ; + if (!a_win->parent) { + EPHYR_LOG ("cannot move root window\n") ; + is_ok = TRUE ; + goto out ; + } + win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; + if (!win_priv) { + EPHYR_LOG ("not a DRI peered window\n") ; + is_ok = TRUE ; + goto out ; + } + if (!findWindowPairFromLocal (a_win, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to get window pair\n") ; + goto out ; + } + /*compute position relative to parent window*/ + x = a_win->drawable.x - a_win->parent->drawable.x ; + y = a_win->drawable.y - a_win->parent->drawable.y ; + /*set the geometry to pass to hostx_set_window_geometry*/ + memset (&geo, 0, sizeof (geo)) ; + geo.x = x ; + geo.y = y ; + geo.width = a_win->drawable.width ; + geo.height = a_win->drawable.height ; + hostx_set_window_geometry (pair->remote, &geo) ; + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; + /*do cleanup here*/ +} + +static Bool +ephyrDRIPositionWindow (WindowPtr a_win, + int a_x, int a_y) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + EphyrDRIWindowPrivPtr win_priv=NULL ; + EphyrWindowPair *pair=NULL ; + EphyrBox geo; + + EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; + + EPHYR_LOG ("enter\n") ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_VAL_IF_FAIL (screen_priv + && screen_priv->PositionWindow, + FALSE) ; + + screen->PositionWindow = screen_priv->PositionWindow ; + if (screen->PositionWindow) { + (*screen->PositionWindow) (a_win, a_x, a_y) ; + } + screen->PositionWindow = ephyrDRIPositionWindow ; + + EPHYR_LOG ("window: %p\n", a_win) ; + win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; + if (!win_priv) { + EPHYR_LOG ("not a DRI peered window\n") ; + is_ok = TRUE ; + goto out ; + } + if (!findWindowPairFromLocal (a_win, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to get window pair\n") ; + goto out ; + } + /*set the geometry to pass to hostx_set_window_geometry*/ + memset (&geo, 0, sizeof (geo)) ; + geo.x = a_x ; + geo.y = a_y ; + geo.width = a_win->drawable.width ; + geo.height = a_win->drawable.height ; + hostx_set_window_geometry (pair->remote, &geo) ; + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; + /*do cleanup here*/ + return is_ok ; +} + +static void +ephyrDRIClipNotify (WindowPtr a_win, + int a_x, int a_y) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + EphyrDRIWindowPrivPtr win_priv=NULL ; + EphyrWindowPair *pair=NULL ; + EphyrRect *rects=NULL; + int i=0 ; + + EPHYR_RETURN_IF_FAIL (a_win) ; + + EPHYR_LOG ("enter\n") ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_IF_FAIL (screen) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_IF_FAIL (screen_priv && screen_priv->ClipNotify) ; + + screen->ClipNotify = screen_priv->ClipNotify ; + if (screen->ClipNotify) { + (*screen->ClipNotify) (a_win, a_x, a_y) ; + } + screen->ClipNotify = ephyrDRIClipNotify ; + + EPHYR_LOG ("window: %p\n", a_win) ; + win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; + if (!win_priv) { + EPHYR_LOG ("not a DRI peered window\n") ; + is_ok = TRUE ; + goto out ; + } + if (!findWindowPairFromLocal (a_win, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to get window pair\n") ; + goto out ; + } + rects = calloc(REGION_NUM_RECTS (&a_win->clipList), + sizeof (EphyrRect)) ; + for (i=0; i < REGION_NUM_RECTS (&a_win->clipList); i++) { + memmove (&rects[i], + ®ION_RECTS (&a_win->clipList)[i], + sizeof (EphyrRect)) ; + rects[i].x1 -= a_win->drawable.x; + rects[i].x2 -= a_win->drawable.x; + rects[i].y1 -= a_win->drawable.y; + rects[i].y2 -= a_win->drawable.y; + } + /* + * push the clipping region of this window + * to the peer window in the host + */ + is_ok = hostx_set_window_bounding_rectangles + (pair->remote, + rects, + REGION_NUM_RECTS (&a_win->clipList)) ; + is_ok = TRUE ; + +out: + free(rects) ; + rects = NULL ; + + EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; + /*do cleanup here*/ +} + +/** + * Duplicates a visual of a_screen + * In screen a_screen, for depth a_depth, find a visual which + * bitsPerRGBValue and colormap size equal + * a_bits_per_rgb_values and a_colormap_entries. + * The ID of that duplicated visual is set to a_new_id. + * That duplicated visual is then added to the list of visuals + * of the screen. + */ +static Bool +EphyrDuplicateVisual (unsigned int a_screen, + short a_depth, + short a_class, + short a_bits_per_rgb_values, + short a_colormap_entries, + unsigned int a_red_mask, + unsigned int a_green_mask, + unsigned int a_blue_mask, + unsigned int a_new_id) +{ + Bool is_ok = FALSE, found_visual=FALSE, found_depth=FALSE ; + ScreenPtr screen=NULL ; + VisualRec new_visual, *new_visuals=NULL ; + int i=0 ; + + EPHYR_LOG ("enter\n") ; + if (a_screen > screenInfo.numScreens) { + EPHYR_LOG_ERROR ("bad screen number\n") ; + goto out; + } + memset (&new_visual, 0, sizeof (VisualRec)) ; + + /*get the screen pointed to by a_screen*/ + screen = screenInfo.screens[a_screen] ; + EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; + + /* + * In that screen, first look for an existing visual that has the + * same characteristics as those passed in parameter + * to this function and copy it. + */ + for (i=0; i < screen->numVisuals; i++) { + if (screen->visuals[i].bitsPerRGBValue == a_bits_per_rgb_values && + screen->visuals[i].ColormapEntries == a_colormap_entries ) { + /*copy the visual found*/ + memcpy (&new_visual, &screen->visuals[i], sizeof (new_visual)) ; + new_visual.vid = a_new_id ; + new_visual.class = a_class ; + new_visual.redMask = a_red_mask ; + new_visual.greenMask = a_green_mask ; + new_visual.blueMask = a_blue_mask ; + found_visual = TRUE ; + EPHYR_LOG ("found a visual that matches visual id: %d\n", + a_new_id) ; + break; + } + } + if (!found_visual) { + EPHYR_LOG ("did not find any visual matching %d\n", a_new_id) ; + goto out ; + } + /* + * be prepare to extend screen->visuals to add new_visual to it + */ + new_visuals = calloc(screen->numVisuals+1, sizeof (VisualRec)) ; + memmove (new_visuals, + screen->visuals, + screen->numVisuals*sizeof (VisualRec)) ; + memmove (&new_visuals[screen->numVisuals], + &new_visual, + sizeof (VisualRec)) ; + /* + * Now, in that same screen, update the screen->allowedDepths member. + * In that array, each element represents the visuals applicable to + * a given depth. So we need to add an entry matching the new visual + * that we are going to add to screen->visuals + */ + for (i=0; i<screen->numDepths; i++) { + VisualID *vids=NULL; + DepthPtr cur_depth=NULL ; + /*find the entry matching a_depth*/ + if (screen->allowedDepths[i].depth != a_depth) + continue ; + cur_depth = &screen->allowedDepths[i]; + /* + * extend the list of visual IDs in that entry, + * so to add a_new_id in there. + */ + vids = realloc(cur_depth->vids, + (cur_depth->numVids+1)*sizeof (VisualID)); + if (!vids) { + EPHYR_LOG_ERROR ("failed to realloc numids\n") ; + goto out ; + } + vids[cur_depth->numVids] = a_new_id ; + /* + * Okay now commit our change. + * Do really update screen->allowedDepths[i] + */ + cur_depth->numVids++ ; + cur_depth->vids = vids ; + found_depth=TRUE; + } + if (!found_depth) { + EPHYR_LOG_ERROR ("failed to update screen[%d]->allowedDepth\n", + a_screen) ; + goto out ; + } + /* + * Commit our change to screen->visuals + */ + free(screen->visuals) ; + screen->visuals = new_visuals ; + screen->numVisuals++ ; + new_visuals = NULL ; + + is_ok = TRUE ; +out: + free(new_visuals) ; + new_visuals = NULL ; + + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +/** + * Duplicates the visuals of the host X server. + * This is necessary to have visuals that have the same + * ID as those of the host X. It is important to have that for + * GLX. + */ +static Bool +EphyrMirrorHostVisuals (ScreenPtr a_screen) +{ + Bool is_ok=FALSE; + EphyrHostVisualInfo *visuals=NULL; + int nb_visuals=0, i=0; + + EPHYR_LOG ("enter\n") ; + if (!hostx_get_visuals_info (&visuals, &nb_visuals)) { + EPHYR_LOG_ERROR ("failed to get host visuals\n") ; + goto out ; + } + for (i=0; i<nb_visuals; i++) { + if (!EphyrDuplicateVisual (a_screen->myNum, + visuals[i].depth, + visuals[i].class, + visuals[i].bits_per_rgb, + visuals[i].colormap_size, + visuals[i].red_mask, + visuals[i].green_mask, + visuals[i].blue_mask, + visuals[i].visualid)) { + EPHYR_LOG_ERROR ("failed to duplicate host visual %d\n", + (int)visuals[i].visualid) ; + } + } + + is_ok = TRUE ; +out: + EPHYR_LOG ("leave\n") ; + return is_ok; +} + + +static int +ProcXF86DRIQueryVersion (register ClientPtr client) +{ + xXF86DRIQueryVersionReply rep; + register int n; + REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq); + + EPHYR_LOG ("enter\n") ; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_XF86DRI_MAJOR_VERSION; + rep.minorVersion = SERVER_XF86DRI_MINOR_VERSION; + rep.patchVersion = SERVER_XF86DRI_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + swapl(&rep.patchVersion, n); + } + WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) +{ + xXF86DRIQueryDirectRenderingCapableReply rep; + Bool isCapable; + register int n; + REQUEST(xXF86DRIQueryDirectRenderingCapableReq); + REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!ephyrDRIQueryDirectRenderingCapable (stuff->screen, &isCapable)) { + return BadValue; + } + rep.isCapable = isCapable; + + if (!LocalClient(client) || client->swapped) + rep.isCapable = 0; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + + WriteToClient(client, sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + + return Success; +} + +static int +ProcXF86DRIOpenConnection (register ClientPtr client) +{ + xXF86DRIOpenConnectionReply rep; + drm_handle_t hSAREA; + char* busIdString; + REQUEST(xXF86DRIOpenConnectionReq); + REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + if (!ephyrDRIOpenConnection(stuff->screen, + &hSAREA, + &busIdString)) { + return BadValue; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.busIdStringLength = 0; + if (busIdString) + rep.busIdStringLength = strlen(busIdString); + rep.length = bytes_to_int32(SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) + + pad_to_int32(rep.busIdStringLength)); + + rep.hSAREALow = (CARD32)(hSAREA & 0xffffffff); +#if defined(LONG64) && !defined(__linux__) + rep.hSAREAHigh = (CARD32)(hSAREA >> 32); +#else + rep.hSAREAHigh = 0; +#endif + + WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep); + if (rep.busIdStringLength) + WriteToClient(client, rep.busIdStringLength, busIdString); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIAuthConnection (register ClientPtr client) +{ + xXF86DRIAuthConnectionReply rep; + REQUEST(xXF86DRIAuthConnectionReq); + REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.authenticated = 1; + + if (!ephyrDRIAuthConnection (stuff->screen, stuff->magic)) { + ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic); + rep.authenticated = 0; + } + WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRICloseConnection (register ClientPtr client) +{ + REQUEST(xXF86DRICloseConnectionReq); + REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq); + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + /* + DRICloseConnection( screenInfo.screens[stuff->screen]); + */ + + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIGetClientDriverName (register ClientPtr client) +{ + xXF86DRIGetClientDriverNameReply rep; + char* clientDriverName; + REQUEST(xXF86DRIGetClientDriverNameReq); + REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + ephyrDRIGetClientDriverName (stuff->screen, + (int *)&rep.ddxDriverMajorVersion, + (int *)&rep.ddxDriverMinorVersion, + (int *)&rep.ddxDriverPatchVersion, + &clientDriverName); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.clientDriverNameLength = 0; + if (clientDriverName) + rep.clientDriverNameLength = strlen(clientDriverName); + rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetClientDriverNameReply) - + SIZEOF(xGenericReply) + + pad_to_int32(rep.clientDriverNameLength)); + + WriteToClient(client, + sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep); + if (rep.clientDriverNameLength) + WriteToClient(client, + rep.clientDriverNameLength, + clientDriverName); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRICreateContext (register ClientPtr client) +{ + xXF86DRICreateContextReply rep; + ScreenPtr pScreen; + VisualPtr visual; + int i=0; + unsigned long context_id=0; + REQUEST(xXF86DRICreateContextReq); + REQUEST_SIZE_MATCH(xXF86DRICreateContextReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + pScreen = screenInfo.screens[stuff->screen]; + visual = pScreen->visuals; + + /* Find the requested X visual */ + for (i = 0; i < pScreen->numVisuals; i++, visual++) + if (visual->vid == stuff->visual) + break; + if (i == pScreen->numVisuals) { + /* No visual found */ + return BadValue; + } + + context_id = stuff->context ; + if (!ephyrDRICreateContext (stuff->screen, + stuff->visual, + &context_id, + (drm_context_t *)&rep.hHWContext)) { + return BadValue; + } + + WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIDestroyContext (register ClientPtr client) +{ + REQUEST(xXF86DRIDestroyContextReq); + REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq); + EPHYR_LOG ("enter\n") ; + + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + if (!ephyrDRIDestroyContext (stuff->screen, stuff->context)) { + return BadValue; + } + + EPHYR_LOG ("leave\n") ; + return Success; +} + +static Bool +getWindowVisual (const WindowPtr a_win, + VisualPtr *a_visual) +{ + int i=0, visual_id=0 ; + EPHYR_RETURN_VAL_IF_FAIL (a_win + && a_win->drawable.pScreen + && a_win->drawable.pScreen->visuals, + FALSE) ; + + visual_id = wVisual (a_win) ; + for (i=0; i < a_win->drawable.pScreen->numVisuals; i++) { + if (a_win->drawable.pScreen->visuals[i].vid == visual_id) { + *a_visual = &a_win->drawable.pScreen->visuals[i] ; + return TRUE ; + } + } + return FALSE ; +} + + +#define NUM_WINDOW_PAIRS 256 +static EphyrWindowPair window_pairs[NUM_WINDOW_PAIRS] ; + +static Bool +appendWindowPairToList (WindowPtr a_local, + int a_remote) +{ + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_local, FALSE) ; + + EPHYR_LOG ("(local,remote):(%p, %d)\n", a_local, a_remote) ; + + for (i=0; i < NUM_WINDOW_PAIRS; i++) { + if (window_pairs[i].local == NULL) { + window_pairs[i].local = a_local ; + window_pairs[i].remote = a_remote ; + return TRUE ; + } + } + return FALSE ; +} + +static Bool +findWindowPairFromLocal (WindowPtr a_local, + EphyrWindowPair **a_pair) +{ + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_pair && a_local, FALSE) ; + + for (i=0; i < NUM_WINDOW_PAIRS; i++) { + if (window_pairs[i].local == a_local) { + *a_pair = &window_pairs[i] ; + EPHYR_LOG ("found (%p, %d)\n", + (*a_pair)->local, + (*a_pair)->remote) ; + return TRUE ; + } + } + return FALSE ; +} + +Bool +findWindowPairFromRemote (int a_remote, + EphyrWindowPair **a_pair) +{ + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_pair, FALSE) ; + + for (i=0; i < NUM_WINDOW_PAIRS; i++) { + if (window_pairs[i].remote == a_remote) { + *a_pair = &window_pairs[i] ; + EPHYR_LOG ("found (%p, %d)\n", + (*a_pair)->local, + (*a_pair)->remote) ; + return TRUE ; + } + } + return FALSE ; +} + +static Bool +createHostPeerWindow (const WindowPtr a_win, + int *a_peer_win) +{ + Bool is_ok=FALSE ; + VisualPtr visual=NULL; + EphyrBox geo ; + + EPHYR_RETURN_VAL_IF_FAIL (a_win && a_peer_win, FALSE) ; + EPHYR_RETURN_VAL_IF_FAIL (a_win->drawable.pScreen, + FALSE) ; + + EPHYR_LOG ("enter. a_win '%p'\n", a_win) ; + if (!getWindowVisual (a_win, &visual)) { + EPHYR_LOG_ERROR ("failed to get window visual\n") ; + goto out ; + } + if (!visual) { + EPHYR_LOG_ERROR ("failed to create visual\n") ; + goto out ; + } + memset (&geo, 0, sizeof (geo)) ; + geo.x = a_win->drawable.x ; + geo.y = a_win->drawable.y ; + geo.width = a_win->drawable.width ; + geo.height = a_win->drawable.height ; + if (!hostx_create_window (a_win->drawable.pScreen->myNum, + &geo, visual->vid, a_peer_win)) { + EPHYR_LOG_ERROR ("failed to create host peer window\n") ; + goto out ; + } + if (!appendWindowPairToList (a_win, *a_peer_win)) { + EPHYR_LOG_ERROR ("failed to append window to pair list\n") ; + goto out ; + } + is_ok = TRUE ; +out: + EPHYR_LOG ("leave:remote win%d\n", *a_peer_win) ; + return is_ok ; +} + +static Bool +destroyHostPeerWindow (const WindowPtr a_win) +{ + Bool is_ok = FALSE ; + EphyrWindowPair *pair=NULL ; + EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + if (!findWindowPairFromLocal (a_win, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to find peer to local window\n") ; + goto out; + } + hostx_destroy_window (pair->remote) ; + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return is_ok; +} + +static int +ProcXF86DRICreateDrawable (ClientPtr client) +{ + xXF86DRICreateDrawableReply rep; + DrawablePtr drawable=NULL; + WindowPtr window=NULL ; + EphyrWindowPair *pair=NULL ; + EphyrDRIWindowPrivPtr win_priv=NULL; + int rc=0, remote_win=0; + REQUEST(xXF86DRICreateDrawableReq); + REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = dixLookupDrawable (&drawable, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + if (drawable->type != DRAWABLE_WINDOW) { + EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; + return BadImplementation ; + } + EPHYR_LOG ("lookedup drawable %p\n", drawable) ; + window = (WindowPtr)drawable; + if (findWindowPairFromLocal (window, &pair) && pair) { + remote_win = pair->remote ; + EPHYR_LOG ("found window '%p' paire with remote '%d'\n", + window, remote_win) ; + } else if (!createHostPeerWindow (window, &remote_win)) { + EPHYR_LOG_ERROR ("failed to create host peer window\n") ; + return BadAlloc ; + } + + if (!ephyrDRICreateDrawable (stuff->screen, + remote_win, + (drm_drawable_t *)&rep.hHWDrawable)) { + EPHYR_LOG_ERROR ("failed to create dri drawable\n") ; + return BadValue; + } + + win_priv = GET_EPHYR_DRI_WINDOW_PRIV (window) ; + if (!win_priv) { + win_priv = calloc(1, sizeof (EphyrDRIWindowPrivRec)) ; + if (!win_priv) { + EPHYR_LOG_ERROR ("failed to allocate window private\n") ; + return BadAlloc ; + } + dixSetPrivate(&window->devPrivates, ephyrDRIWindowKey, win_priv); + EPHYR_LOG ("paired window '%p' with remote '%d'\n", + window, remote_win) ; + } + + WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIDestroyDrawable (register ClientPtr client) +{ + DrawablePtr drawable=NULL; + WindowPtr window=NULL; + EphyrWindowPair *pair=NULL; + int rc=0; + REQUEST(xXF86DRIDestroyDrawableReq); + REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rc = dixLookupDrawable(&drawable, + stuff->drawable, + client, + 0, + DixReadAccess); + if (rc != Success) + return rc; + if (drawable->type != DRAWABLE_WINDOW) { + EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; + return BadImplementation ; + } + window = (WindowPtr)drawable; + if (!findWindowPairFromLocal (window, &pair) && pair) { + EPHYR_LOG_ERROR ("failed to find pair window\n") ; + return BadImplementation; + } + if (!ephyrDRIDestroyDrawable(stuff->screen, + pair->remote/*drawable in host x*/)) { + EPHYR_LOG_ERROR ("failed to destroy dri drawable\n") ; + return BadImplementation; + } + pair->local=NULL ; + pair->remote=0; + + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIGetDrawableInfo (register ClientPtr client) +{ + xXF86DRIGetDrawableInfoReply rep; + DrawablePtr drawable; + WindowPtr window=NULL; + EphyrWindowPair *pair=NULL; + int X=0, Y=0, W=0, H=0, backX=0, backY=0, rc=0, i=0; + drm_clip_rect_t *clipRects=NULL; + drm_clip_rect_t *backClipRects=NULL; + REQUEST(xXF86DRIGetDrawableInfoReq); + REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq); + + EPHYR_LOG ("enter\n") ; + memset (&rep, 0, sizeof (rep)) ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success || !drawable) { + EPHYR_LOG_ERROR ("could not get drawable\n") ; + return rc; + } + + if (drawable->type != DRAWABLE_WINDOW) { + EPHYR_LOG_ERROR ("non windows type drawables are not yes supported\n") ; + return BadImplementation ; + } + window = (WindowPtr)drawable ; + memset (&pair, 0, sizeof (pair)) ; + if (!findWindowPairFromLocal (window, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ; + return BadMatch ; + } + EPHYR_LOG ("clip list of xephyr gl drawable:\n") ; + for (i=0; i < REGION_NUM_RECTS (&window->clipList); i++) { + EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", + REGION_RECTS (&window->clipList)[i].x1, + REGION_RECTS (&window->clipList)[i].y1, + REGION_RECTS (&window->clipList)[i].x2, + REGION_RECTS (&window->clipList)[i].y2) ; + } + + if (!ephyrDRIGetDrawableInfo (stuff->screen, + pair->remote/*the drawable in hostx*/, + (unsigned int*)&rep.drawableTableIndex, + (unsigned int*)&rep.drawableTableStamp, + (int*)&X, + (int*)&Y, + (int*)&W, + (int*)&H, + (int*)&rep.numClipRects, + &clipRects, + &backX, + &backY, + (int*)&rep.numBackClipRects, + &backClipRects)) { + return BadValue; + } + EPHYR_LOG ("num clip rects:%d, num back clip rects:%d\n", + (int)rep.numClipRects, (int)rep.numBackClipRects) ; + + rep.drawableX = X; + rep.drawableY = Y; + rep.drawableWidth = W; + rep.drawableHeight = H; + rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) - + SIZEOF(xGenericReply)); + + rep.backX = backX; + rep.backY = backY; + + + if (rep.numClipRects) { + if (clipRects) { + ScreenPtr pScreen = screenInfo.screens[stuff->screen]; + int i=0; + EPHYR_LOG ("clip list of host gl drawable:\n") ; + for (i = 0; i < rep.numClipRects; i++) { + clipRects[i].x1 = max (clipRects[i].x1, 0); + clipRects[i].y1 = max (clipRects[i].y1, 0); + clipRects[i].x2 = min (clipRects[i].x2, + pScreen->width + clipRects[i].x1) ; + clipRects[i].y2 = min (clipRects[i].y2, + pScreen->width + clipRects[i].y1) ; + + EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", + clipRects[i].x1, clipRects[i].y1, + clipRects[i].x2, clipRects[i].y2) ; + } + } else { + rep.numClipRects = 0; + } + } else { + EPHYR_LOG ("got zero host gl drawable clipping rects\n") ; + } + rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects; + backClipRects = clipRects ; + rep.numBackClipRects = rep.numClipRects ; + if (rep.numBackClipRects) + rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects; + EPHYR_LOG ("num host clip rects:%d\n", (int)rep.numClipRects) ; + EPHYR_LOG ("num host back clip rects:%d\n", (int)rep.numBackClipRects) ; + + rep.length = bytes_to_int32(rep.length); + + WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep); + + if (rep.numClipRects) { + WriteToClient(client, + sizeof(drm_clip_rect_t) * rep.numClipRects, + (char *)clipRects); + } + + if (rep.numBackClipRects) { + WriteToClient(client, + sizeof(drm_clip_rect_t) * rep.numBackClipRects, + (char *)backClipRects); + } + free(clipRects); + clipRects = NULL ; + + EPHYR_LOG ("leave\n") ; + + return Success; +} + +static int +ProcXF86DRIGetDeviceInfo (register ClientPtr client) +{ + xXF86DRIGetDeviceInfoReply rep; + drm_handle_t hFrameBuffer; + void *pDevPrivate; + REQUEST(xXF86DRIGetDeviceInfoReq); + REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!ephyrDRIGetDeviceInfo (stuff->screen, + &hFrameBuffer, + (int*)&rep.framebufferOrigin, + (int*)&rep.framebufferSize, + (int*)&rep.framebufferStride, + (int*)&rep.devPrivateSize, + &pDevPrivate)) { + return BadValue; + } + + rep.hFrameBufferLow = (CARD32)(hFrameBuffer & 0xffffffff); +#if defined(LONG64) && !defined(__linux__) + rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32); +#else + rep.hFrameBufferHigh = 0; +#endif + + rep.length = 0; + if (rep.devPrivateSize) { + rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetDeviceInfoReply) - + SIZEOF(xGenericReply) + + pad_to_int32(rep.devPrivateSize)); + } + + WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep); + if (rep.length) { + WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate); + } + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIDispatch (register ClientPtr client) +{ + REQUEST(xReq); + EPHYR_LOG ("enter\n") ; + + switch (stuff->data) + { + case X_XF86DRIQueryVersion: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIQueryVersion(client); + } + case X_XF86DRIQueryDirectRenderingCapable: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIQueryDirectRenderingCapable(client); + } + } + + if (!LocalClient(client)) + return DRIErrorBase + XF86DRIClientNotLocal; + + switch (stuff->data) + { + case X_XF86DRIOpenConnection: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIOpenConnection(client); + } + case X_XF86DRICloseConnection: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRICloseConnection(client); + } + case X_XF86DRIGetClientDriverName: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIGetClientDriverName(client); + } + case X_XF86DRICreateContext: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRICreateContext(client); + } + case X_XF86DRIDestroyContext: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIDestroyContext(client); + } + case X_XF86DRICreateDrawable: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRICreateDrawable(client); + } + case X_XF86DRIDestroyDrawable: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIDestroyDrawable(client); + } + case X_XF86DRIGetDrawableInfo: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIGetDrawableInfo(client); + } + case X_XF86DRIGetDeviceInfo: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIGetDeviceInfo(client); + } + case X_XF86DRIAuthConnection: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIAuthConnection(client); + } + /* {Open,Close}FullScreen are deprecated now */ + default: { + EPHYR_LOG ("leave\n") ; + return BadRequest; + } + } +} + +static int +SProcXF86DRIQueryVersion (register ClientPtr client) +{ + register int n; + REQUEST(xXF86DRIQueryVersionReq); + swaps(&stuff->length, n); + return ProcXF86DRIQueryVersion(client); +} + +static int +SProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) +{ + register int n; + REQUEST(xXF86DRIQueryDirectRenderingCapableReq); + swaps(&stuff->length, n); + swapl(&stuff->screen, n); + return ProcXF86DRIQueryDirectRenderingCapable(client); +} + +static int +SProcXF86DRIDispatch (register ClientPtr client) +{ + REQUEST(xReq); + + EPHYR_LOG ("enter\n") ; + /* + * Only local clients are allowed DRI access, but remote clients still need + * these requests to find out cleanly. + */ + switch (stuff->data) + { + case X_XF86DRIQueryVersion: { + EPHYR_LOG ("leave\n") ; + return SProcXF86DRIQueryVersion(client); + } + case X_XF86DRIQueryDirectRenderingCapable: { + EPHYR_LOG ("leave\n") ; + return SProcXF86DRIQueryDirectRenderingCapable(client); + } + default: { + EPHYR_LOG ("leave\n") ; + return DRIErrorBase + XF86DRIClientNotLocal; + } + } +} diff --git a/xorg-server/hw/kdrive/ephyr/ephyrglxext.c b/xorg-server/hw/kdrive/ephyr/ephyrglxext.c index a0278cc2b..d6b8ca66d 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyrglxext.c +++ b/xorg-server/hw/kdrive/ephyr/ephyrglxext.c @@ -1,723 +1,723 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum <mallum@openedhand.com> - * - * Copyright © 2007 OpenedHand Ltd - * - * 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 OpenedHand Ltd not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. OpenedHand Ltd makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OpenedHand Ltd 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. - * - * Authors: - * Dodji Seketeli <dodji@openedhand.com> - */ -#ifdef HAVE_CONFIG_H -#include <kdrive-config.h> -#endif - -#include "extnsionst.h" -#include "ephyrglxext.h" -#include "ephyrhostglx.h" -#define _HAVE_XALLOC_DECLS -#include "ephyrlog.h" -#include <GL/glxproto.h> -#include "glx/glxserver.h" -#include "glx/indirect_table.h" -#include "glx/indirect_util.h" -#include "glx/unpack.h" -#include "hostx.h" - - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - - -int ephyrGLXQueryVersion (__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXQueryVersionSwap (__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXGetVisualConfigs (__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXGetVisualConfigsSwap (__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXClientInfo(__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXClientInfoSwap(__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc); -int ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc); -int ephyrGLXCreateContext (__GLXclientState *a_cl, GLbyte *a_pc); -int ephyrGLXCreateContextSwap (__GLXclientState *a_cl, GLbyte *a_pc); -int ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; - -Bool -ephyrHijackGLXExtension (void) -{ - const void *(*dispatch_functions)[2]; - - if (!hostx_has_glx ()) { - EPHYR_LOG ("host X does not have GLX\n") ; - return FALSE ; - } - EPHYR_LOG ("host X does have GLX\n") ; - - if (!Single_dispatch_info.dispatch_functions) { - EPHYR_LOG_ERROR ("could not get dispatch functions table\n") ; - return FALSE ; - } - /* - * hijack some single entry point dispatch functions - */ - dispatch_functions = Single_dispatch_info.dispatch_functions ; - EPHYR_RETURN_VAL_IF_FAIL (dispatch_functions, FALSE) ; - - dispatch_functions[X_GLXQueryVersion][0] = ephyrGLXQueryVersion ; - dispatch_functions[X_GLXQueryVersion][1] = ephyrGLXQueryVersionSwap ; - - dispatch_functions[X_GLXGetVisualConfigs][0] = ephyrGLXGetVisualConfigs ; - dispatch_functions[X_GLXGetVisualConfigs][1] = ephyrGLXGetVisualConfigsSwap ; - dispatch_functions[X_GLXClientInfo][0] = ephyrGLXClientInfo ; - dispatch_functions[X_GLXClientInfo][1] = ephyrGLXClientInfoSwap ; - - dispatch_functions[X_GLXQueryServerString][0] = ephyrGLXQueryServerString ; - dispatch_functions[X_GLXQueryServerString][1] = - ephyrGLXQueryServerStringSwap ; - - dispatch_functions[X_GLXCreateContext][0] = ephyrGLXCreateContext ; - dispatch_functions[X_GLXCreateContext][1] = ephyrGLXCreateContextSwap ; - - dispatch_functions[X_GLXDestroyContext][0] = ephyrGLXDestroyContext ; - dispatch_functions[X_GLXDestroyContext][1] = ephyrGLXDestroyContextSwap ; - - dispatch_functions[X_GLXMakeCurrent][0] = ephyrGLXMakeCurrent ; - dispatch_functions[X_GLXMakeCurrent][1] = ephyrGLXMakeCurrentSwap ; - - dispatch_functions[X_GLXIsDirect][0] = ephyrGLXIsDirect ; - dispatch_functions[X_GLXIsDirect][1] = ephyrGLXIsDirectSwap ; - - dispatch_functions[73][0] = ephyrGLXGetString ; - dispatch_functions[73][1] = ephyrGLXGetStringSwap ; - - dispatch_functions[61][0] = ephyrGLXGetIntegerv ; - dispatch_functions[61][1] = ephyrGLXGetIntegervSwap ; - - /* - * hijack some vendor priv entry point dispatch functions - */ - dispatch_functions = VendorPriv_dispatch_info.dispatch_functions ; - dispatch_functions[92][0] = ephyrGLXGetFBConfigsSGIX; - dispatch_functions[92][1] = ephyrGLXGetFBConfigsSGIXSwap; - EPHYR_LOG ("hijacked glx entry points to forward requests to host X\n") ; - - return TRUE ; -} - -/********************* - * implementation of - * hijacked GLX entry - * points - ********************/ - -int -ephyrGLXQueryVersion(__GLXclientState *a_cl, GLbyte *a_pc) -{ - ClientPtr client = a_cl->client; - xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc; - xGLXQueryVersionReply reply; - int major, minor; - int res = BadImplementation ; - - EPHYR_LOG ("enter\n") ; - - major = req->majorVersion ; - minor = req->minorVersion ; - - if (!ephyrHostGLXQueryVersion (&major, &minor)) { - EPHYR_LOG_ERROR ("ephyrHostGLXQueryVersion() failed\n") ; - goto out ; - } - EPHYR_LOG ("major:%d, minor:%d\n", - major, minor); - reply.majorVersion = major ; - reply.minorVersion = minor ; - reply.length = 0 ; - reply.type = X_Reply ; - reply.sequenceNumber = client->sequence ; - - if (client->swapped) { - __glXSwapQueryVersionReply(client, &reply); - } else { - WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply); - } - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res; -} - -int -ephyrGLXQueryVersionSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT (&req->length); - __GLX_SWAP_INT (&req->majorVersion); - __GLX_SWAP_INT (&req->minorVersion); - return ephyrGLXQueryVersion (a_cl, a_pc) ; -} - -static int -ephyrGLXGetVisualConfigsReal (__GLXclientState *a_cl, - GLbyte *a_pc, - Bool a_do_swap) -{ - xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) a_pc; - ClientPtr client = a_cl->client; - xGLXGetVisualConfigsReply reply; - int32_t *props_buf=NULL, num_visuals=0, - num_props=0, res=BadImplementation, i=0, - props_per_visual_size=0, - props_buf_size=0; - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_DECLARE_SWAP_ARRAY_VARIABLES; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostGLXGetVisualConfigs (req->screen, - &num_visuals, - &num_props, - &props_buf_size, - &props_buf)) { - EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ; - goto out ; - } - EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ; - - reply.numVisuals = num_visuals; - reply.numProps = num_props; - reply.length = (num_visuals *__GLX_SIZE_CARD32 * num_props) >> 2; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (a_do_swap) { - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - __GLX_SWAP_INT(&reply.numVisuals); - __GLX_SWAP_INT(&reply.numProps); - __GLX_SWAP_INT_ARRAY (props_buf, num_props) ; - } - WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply); - props_per_visual_size = props_buf_size/num_visuals ; - for (i=0; i < num_visuals; i++) { - WriteToClient (client, - props_per_visual_size, - (char*)props_buf +i*props_per_visual_size); - } - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - xfree (props_buf) ; - props_buf = NULL ; - - return res ; -} - -static int -ephyrGLXGetFBConfigsSGIXReal (__GLXclientState *a_cl, - GLbyte *a_pc, - Bool a_do_swap) -{ - xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *)a_pc; - ClientPtr client = a_cl->client; - xGLXGetVisualConfigsReply reply; - int32_t *props_buf=NULL, num_visuals=0, - num_props=0, res=BadImplementation, i=0, - props_per_visual_size=0, - props_buf_size=0; - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_DECLARE_SWAP_ARRAY_VARIABLES; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostGLXVendorPrivGetFBConfigsSGIX (req->screen, - &num_visuals, - &num_props, - &props_buf_size, - &props_buf)) { - EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ; - goto out ; - } - EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ; - - reply.numVisuals = num_visuals; - reply.numProps = num_props; - reply.length = props_buf_size >> 2; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (a_do_swap) { - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - __GLX_SWAP_INT(&reply.numVisuals); - __GLX_SWAP_INT(&reply.numProps); - __GLX_SWAP_INT_ARRAY (props_buf, num_props) ; - } - WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply); - props_per_visual_size = props_buf_size/num_visuals ; - for (i=0; i < num_visuals; i++) { - WriteToClient (client, - props_per_visual_size, - &((char*)props_buf)[i*props_per_visual_size]); - } - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - xfree (props_buf) ; - props_buf = NULL ; - - return res ; -} - -int -ephyrGLXGetVisualConfigs (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXGetVisualConfigsSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, TRUE) ; -} - - -int -ephyrGLXClientInfo(__GLXclientState *a_cl, GLbyte *a_pc) -{ - int res=BadImplementation ; - xGLXClientInfoReq *req = (xGLXClientInfoReq *) a_pc; - - EPHYR_LOG ("enter\n") ; - if (!ephyrHostGLXSendClientInfo (req->major, req->minor, (char*)req+1)) { - EPHYR_LOG_ERROR ("failed to send client info to host\n") ; - goto out ; - } - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXClientInfoSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - xGLXClientInfoReq *req = (xGLXClientInfoReq *)a_pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT (&req->length); - __GLX_SWAP_INT (&req->major); - __GLX_SWAP_INT (&req->minor); - __GLX_SWAP_INT (&req->numbytes); - - return ephyrGLXClientInfo (a_cl, a_pc) ; -} - -int -ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc) -{ - int res = BadImplementation ; - ClientPtr client = a_cl->client; - xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) a_pc; - xGLXQueryServerStringReply reply; - char *server_string=NULL, *buf=NULL; - int length=0 ; - - EPHYR_LOG ("enter\n") ; - if (!ephyrHostGLXGetStringFromServer (req->screen, - req->name, - EPHYR_HOST_GLX_QueryServerString, - &server_string)) { - EPHYR_LOG_ERROR ("failed to query string from host\n") ; - goto out ; - } - EPHYR_LOG ("string: %s\n", server_string) ; - length= strlen (server_string) + 1; - reply.type = X_Reply ; - reply.sequenceNumber = client->sequence ; - reply.length = __GLX_PAD (length) >> 2 ; - reply.n = length ; - buf = xcalloc (reply.length << 2, 1); - if (!buf) { - EPHYR_LOG_ERROR ("failed to allocate string\n;"); - return BadAlloc; - } - memcpy (buf, server_string, length); - - WriteToClient(client, sz_xGLXQueryServerStringReply, (char*)&reply); - WriteToClient(client, (int)(reply.length << 2), server_string); - - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - xfree (server_string) ; - server_string = NULL; - - xfree (buf); - buf = NULL; - - return res ; -} - -int -ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc) -{ - EPHYR_LOG_ERROR ("not yet implemented\n") ; - return BadImplementation ; -} - - -int -ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXCreateContextReal (xGLXCreateContextReq *a_req, Bool a_do_swap) -{ - int res=BadImplementation; - EphyrHostWindowAttributes host_w_attrs ; - __GLX_DECLARE_SWAP_VARIABLES; - - EPHYR_RETURN_VAL_IF_FAIL (a_req, BadValue) ; - EPHYR_LOG ("enter\n") ; - - if (a_do_swap) { - __GLX_SWAP_SHORT(&a_req->length); - __GLX_SWAP_INT(&a_req->context); - __GLX_SWAP_INT(&a_req->visual); - __GLX_SWAP_INT(&a_req->screen); - __GLX_SWAP_INT(&a_req->shareList); - } - - EPHYR_LOG ("context creation requested. localid:%d, " - "screen:%d, visual:%d, direct:%d\n", - (int)a_req->context, (int)a_req->screen, - (int)a_req->visual, (int)a_req->isDirect) ; - - memset (&host_w_attrs, 0, sizeof (host_w_attrs)) ; - if (!hostx_get_window_attributes (hostx_get_window (a_req->screen), - &host_w_attrs)) { - EPHYR_LOG_ERROR ("failed to get host window attrs\n") ; - goto out ; - } - - EPHYR_LOG ("host window visual id: %d\n", host_w_attrs.visualid) ; - - if (!ephyrHostGLXCreateContext (a_req->screen, - host_w_attrs.visualid, - a_req->context, - a_req->shareList, - a_req->isDirect)) { - EPHYR_LOG_ERROR ("ephyrHostGLXCreateContext() failed\n") ; - goto out ; - } - res = Success; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXCreateContext (__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; - - return ephyrGLXCreateContextReal (req, FALSE) ; -} - -int ephyrGLXCreateContextSwap (__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; - return ephyrGLXCreateContextReal (req, TRUE) ; -} - -static int -ephyrGLXDestroyContextReal (__GLXclientState *a_cl, - GLbyte *a_pc, - Bool a_do_swap) -{ - int res=BadImplementation; - ClientPtr client = a_cl->client; - xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) a_pc; - - EPHYR_LOG ("enter. id:%d\n", (int)req->context) ; - if (!ephyrHostDestroyContext (req->context)) { - EPHYR_LOG_ERROR ("ephyrHostDestroyContext() failed\n") ; - client->errorValue = req->context ; - goto out ; - } - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXDestroyContextReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXDestroyContextReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXMakeCurrentReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) -{ - int res=BadImplementation; - xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) a_pc; - xGLXMakeCurrentReply reply ; - DrawablePtr drawable=NULL; - int rc=0; - - EPHYR_LOG ("enter\n") ; - rc = dixLookupDrawable (&drawable, - req->drawable, - a_cl->client, - 0, - DixReadAccess); - EPHYR_RETURN_VAL_IF_FAIL (drawable, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (drawable->pScreen, BadValue) ; - EPHYR_LOG ("screen nummber requested:%d\n", - drawable->pScreen->myNum) ; - - memset (&reply, 0, sizeof (reply)) ; - if (!ephyrHostGLXMakeCurrent (hostx_get_window (drawable->pScreen->myNum), - req->context, - req->oldContextTag, - (int*)&reply.contextTag)) { - EPHYR_LOG_ERROR ("ephyrHostGLXMakeCurrent() failed\n") ; - goto out; - } - reply.length = 0; - reply.type = X_Reply; - reply.sequenceNumber = a_cl->client->sequence; - if (a_do_swap) { - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - __GLX_SWAP_INT(&reply.contextTag); - } - WriteToClient(a_cl->client, sz_xGLXMakeCurrentReply, (char *)&reply); - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXMakeCurrentReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXMakeCurrentReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXGetStringReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) -{ - ClientPtr client=NULL ; - int context_tag=0, name=0, res=BadImplementation, length=0 ; - char *string=NULL; - __GLX_DECLARE_SWAP_VARIABLES; - - EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - client = a_cl->client ; - - if (a_do_swap) { - __GLX_SWAP_INT (a_pc + 4); - __GLX_SWAP_INT (a_pc + __GLX_SINGLE_HDR_SIZE); - } - context_tag = __GLX_GET_SINGLE_CONTEXT_TAG (a_pc) ; - a_pc += __GLX_SINGLE_HDR_SIZE; - name = *(GLenum*)(a_pc + 0); - EPHYR_LOG ("context_tag:%d, name:%d\n", context_tag, name) ; - if (!ephyrHostGLXGetStringFromServer (context_tag, - name, - EPHYR_HOST_GLX_GetString, - &string)) { - EPHYR_LOG_ERROR ("failed to get string from server\n") ; - goto out ; - } - if (string) { - length = strlen (string) + 1; - EPHYR_LOG ("got string:'%s', size:%d\n", string, length) ; - } else { - EPHYR_LOG ("got string: string (null)\n") ; - } - __GLX_BEGIN_REPLY (length); - __GLX_PUT_SIZE (length); - __GLX_SEND_HEADER (); - if (a_do_swap) { - __GLX_SWAP_REPLY_SIZE (); - __GLX_SWAP_REPLY_HEADER (); - } - WriteToClient (client, length, (char *)string); - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetStringReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetStringReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXGetIntegervReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) -{ - int res=BadImplementation; - xGLXSingleReq * const req = (xGLXSingleReq *) a_pc; - GLenum int_name ; - int value=0 ; - GLint answer_buf_room[200]; - GLint *buf=NULL ; - - EPHYR_LOG ("enter\n") ; - - a_pc += __GLX_SINGLE_HDR_SIZE; - - int_name = *(GLenum*) (a_pc+0) ; - if (!ephyrHostGetIntegerValue (req->contextTag, int_name, &value)) { - EPHYR_LOG_ERROR ("ephyrHostGetIntegerValue() failed\n") ; - goto out ; - } - buf = __glXGetAnswerBuffer (a_cl, sizeof (value), - answer_buf_room, - sizeof (answer_buf_room), - 4) ; - - if (!buf) { - EPHYR_LOG_ERROR ("failed to allocate reply buffer\n") ; - res = BadAlloc ; - goto out ; - } - __glXSendReply (a_cl->client, buf, 1, sizeof (value), GL_FALSE, 0) ; - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetIntegervReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetIntegervReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXIsDirectReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) -{ - int res=BadImplementation; - ClientPtr client = a_cl->client; - xGLXIsDirectReq *req = (xGLXIsDirectReq *) a_pc; - xGLXIsDirectReply reply; - int is_direct=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - memset (&reply, 0, sizeof (reply)) ; - if (!ephyrHostIsContextDirect (req->context, (int*)&is_direct)) { - EPHYR_LOG_ERROR ("ephyrHostIsContextDirect() failed\n") ; - goto out ; - } - reply.isDirect = is_direct ; - reply.length = 0; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply); - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXIsDirectReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXIsDirectReal (a_cl, a_pc, TRUE) ; -} +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum <mallum@openedhand.com> + * + * Copyright © 2007 OpenedHand Ltd + * + * 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 OpenedHand Ltd not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. OpenedHand Ltd makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OpenedHand Ltd 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. + * + * Authors: + * Dodji Seketeli <dodji@openedhand.com> + */ +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif + +#include "extnsionst.h" +#include "ephyrglxext.h" +#include "ephyrhostglx.h" +#define _HAVE_XALLOC_DECLS +#include "ephyrlog.h" +#include <GL/glxproto.h> +#include "glx/glxserver.h" +#include "glx/indirect_table.h" +#include "glx/indirect_util.h" +#include "glx/unpack.h" +#include "hostx.h" + + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +int ephyrGLXQueryVersion (__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXQueryVersionSwap (__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXGetVisualConfigs (__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXGetVisualConfigsSwap (__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXClientInfo(__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXClientInfoSwap(__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc); +int ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc); +int ephyrGLXCreateContext (__GLXclientState *a_cl, GLbyte *a_pc); +int ephyrGLXCreateContextSwap (__GLXclientState *a_cl, GLbyte *a_pc); +int ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; + +Bool +ephyrHijackGLXExtension (void) +{ + const void *(*dispatch_functions)[2]; + + if (!hostx_has_glx ()) { + EPHYR_LOG ("host X does not have GLX\n") ; + return FALSE ; + } + EPHYR_LOG ("host X does have GLX\n") ; + + if (!Single_dispatch_info.dispatch_functions) { + EPHYR_LOG_ERROR ("could not get dispatch functions table\n") ; + return FALSE ; + } + /* + * hijack some single entry point dispatch functions + */ + dispatch_functions = Single_dispatch_info.dispatch_functions ; + EPHYR_RETURN_VAL_IF_FAIL (dispatch_functions, FALSE) ; + + dispatch_functions[X_GLXQueryVersion][0] = ephyrGLXQueryVersion ; + dispatch_functions[X_GLXQueryVersion][1] = ephyrGLXQueryVersionSwap ; + + dispatch_functions[X_GLXGetVisualConfigs][0] = ephyrGLXGetVisualConfigs ; + dispatch_functions[X_GLXGetVisualConfigs][1] = ephyrGLXGetVisualConfigsSwap ; + dispatch_functions[X_GLXClientInfo][0] = ephyrGLXClientInfo ; + dispatch_functions[X_GLXClientInfo][1] = ephyrGLXClientInfoSwap ; + + dispatch_functions[X_GLXQueryServerString][0] = ephyrGLXQueryServerString ; + dispatch_functions[X_GLXQueryServerString][1] = + ephyrGLXQueryServerStringSwap ; + + dispatch_functions[X_GLXCreateContext][0] = ephyrGLXCreateContext ; + dispatch_functions[X_GLXCreateContext][1] = ephyrGLXCreateContextSwap ; + + dispatch_functions[X_GLXDestroyContext][0] = ephyrGLXDestroyContext ; + dispatch_functions[X_GLXDestroyContext][1] = ephyrGLXDestroyContextSwap ; + + dispatch_functions[X_GLXMakeCurrent][0] = ephyrGLXMakeCurrent ; + dispatch_functions[X_GLXMakeCurrent][1] = ephyrGLXMakeCurrentSwap ; + + dispatch_functions[X_GLXIsDirect][0] = ephyrGLXIsDirect ; + dispatch_functions[X_GLXIsDirect][1] = ephyrGLXIsDirectSwap ; + + dispatch_functions[73][0] = ephyrGLXGetString ; + dispatch_functions[73][1] = ephyrGLXGetStringSwap ; + + dispatch_functions[61][0] = ephyrGLXGetIntegerv ; + dispatch_functions[61][1] = ephyrGLXGetIntegervSwap ; + + /* + * hijack some vendor priv entry point dispatch functions + */ + dispatch_functions = VendorPriv_dispatch_info.dispatch_functions ; + dispatch_functions[92][0] = ephyrGLXGetFBConfigsSGIX; + dispatch_functions[92][1] = ephyrGLXGetFBConfigsSGIXSwap; + EPHYR_LOG ("hijacked glx entry points to forward requests to host X\n") ; + + return TRUE ; +} + +/********************* + * implementation of + * hijacked GLX entry + * points + ********************/ + +int +ephyrGLXQueryVersion(__GLXclientState *a_cl, GLbyte *a_pc) +{ + ClientPtr client = a_cl->client; + xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc; + xGLXQueryVersionReply reply; + int major, minor; + int res = BadImplementation ; + + EPHYR_LOG ("enter\n") ; + + major = req->majorVersion ; + minor = req->minorVersion ; + + if (!ephyrHostGLXQueryVersion (&major, &minor)) { + EPHYR_LOG_ERROR ("ephyrHostGLXQueryVersion() failed\n") ; + goto out ; + } + EPHYR_LOG ("major:%d, minor:%d\n", + major, minor); + reply.majorVersion = major ; + reply.minorVersion = minor ; + reply.length = 0 ; + reply.type = X_Reply ; + reply.sequenceNumber = client->sequence ; + + if (client->swapped) { + __glXSwapQueryVersionReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply); + } + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res; +} + +int +ephyrGLXQueryVersionSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT (&req->length); + __GLX_SWAP_INT (&req->majorVersion); + __GLX_SWAP_INT (&req->minorVersion); + return ephyrGLXQueryVersion (a_cl, a_pc) ; +} + +static int +ephyrGLXGetVisualConfigsReal (__GLXclientState *a_cl, + GLbyte *a_pc, + Bool a_do_swap) +{ + xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) a_pc; + ClientPtr client = a_cl->client; + xGLXGetVisualConfigsReply reply; + int32_t *props_buf=NULL, num_visuals=0, + num_props=0, res=BadImplementation, i=0, + props_per_visual_size=0, + props_buf_size=0; + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_DECLARE_SWAP_ARRAY_VARIABLES; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostGLXGetVisualConfigs (req->screen, + &num_visuals, + &num_props, + &props_buf_size, + &props_buf)) { + EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ; + goto out ; + } + EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ; + + reply.numVisuals = num_visuals; + reply.numProps = num_props; + reply.length = (num_visuals *__GLX_SIZE_CARD32 * num_props) >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (a_do_swap) { + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + __GLX_SWAP_INT(&reply.numVisuals); + __GLX_SWAP_INT(&reply.numProps); + __GLX_SWAP_INT_ARRAY (props_buf, num_props) ; + } + WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply); + props_per_visual_size = props_buf_size/num_visuals ; + for (i=0; i < num_visuals; i++) { + WriteToClient (client, + props_per_visual_size, + (char*)props_buf +i*props_per_visual_size); + } + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + free(props_buf) ; + props_buf = NULL ; + + return res ; +} + +static int +ephyrGLXGetFBConfigsSGIXReal (__GLXclientState *a_cl, + GLbyte *a_pc, + Bool a_do_swap) +{ + xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *)a_pc; + ClientPtr client = a_cl->client; + xGLXGetVisualConfigsReply reply; + int32_t *props_buf=NULL, num_visuals=0, + num_props=0, res=BadImplementation, i=0, + props_per_visual_size=0, + props_buf_size=0; + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_DECLARE_SWAP_ARRAY_VARIABLES; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostGLXVendorPrivGetFBConfigsSGIX (req->screen, + &num_visuals, + &num_props, + &props_buf_size, + &props_buf)) { + EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ; + goto out ; + } + EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ; + + reply.numVisuals = num_visuals; + reply.numProps = num_props; + reply.length = props_buf_size >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (a_do_swap) { + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + __GLX_SWAP_INT(&reply.numVisuals); + __GLX_SWAP_INT(&reply.numProps); + __GLX_SWAP_INT_ARRAY (props_buf, num_props) ; + } + WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply); + props_per_visual_size = props_buf_size/num_visuals ; + for (i=0; i < num_visuals; i++) { + WriteToClient (client, + props_per_visual_size, + &((char*)props_buf)[i*props_per_visual_size]); + } + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + free(props_buf) ; + props_buf = NULL ; + + return res ; +} + +int +ephyrGLXGetVisualConfigs (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXGetVisualConfigsSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, TRUE) ; +} + + +int +ephyrGLXClientInfo(__GLXclientState *a_cl, GLbyte *a_pc) +{ + int res=BadImplementation ; + xGLXClientInfoReq *req = (xGLXClientInfoReq *) a_pc; + + EPHYR_LOG ("enter\n") ; + if (!ephyrHostGLXSendClientInfo (req->major, req->minor, (char*)req+1)) { + EPHYR_LOG_ERROR ("failed to send client info to host\n") ; + goto out ; + } + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXClientInfoSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + xGLXClientInfoReq *req = (xGLXClientInfoReq *)a_pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT (&req->length); + __GLX_SWAP_INT (&req->major); + __GLX_SWAP_INT (&req->minor); + __GLX_SWAP_INT (&req->numbytes); + + return ephyrGLXClientInfo (a_cl, a_pc) ; +} + +int +ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc) +{ + int res = BadImplementation ; + ClientPtr client = a_cl->client; + xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) a_pc; + xGLXQueryServerStringReply reply; + char *server_string=NULL, *buf=NULL; + int length=0 ; + + EPHYR_LOG ("enter\n") ; + if (!ephyrHostGLXGetStringFromServer (req->screen, + req->name, + EPHYR_HOST_GLX_QueryServerString, + &server_string)) { + EPHYR_LOG_ERROR ("failed to query string from host\n") ; + goto out ; + } + EPHYR_LOG ("string: %s\n", server_string) ; + length= strlen (server_string) + 1; + reply.type = X_Reply ; + reply.sequenceNumber = client->sequence ; + reply.length = __GLX_PAD (length) >> 2 ; + reply.n = length ; + buf = calloc(reply.length << 2, 1); + if (!buf) { + EPHYR_LOG_ERROR ("failed to allocate string\n;"); + return BadAlloc; + } + memcpy (buf, server_string, length); + + WriteToClient(client, sz_xGLXQueryServerStringReply, (char*)&reply); + WriteToClient(client, (int)(reply.length << 2), server_string); + + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + free(server_string) ; + server_string = NULL; + + free(buf); + buf = NULL; + + return res ; +} + +int +ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc) +{ + EPHYR_LOG_ERROR ("not yet implemented\n") ; + return BadImplementation ; +} + + +int +ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXCreateContextReal (xGLXCreateContextReq *a_req, Bool a_do_swap) +{ + int res=BadImplementation; + EphyrHostWindowAttributes host_w_attrs ; + __GLX_DECLARE_SWAP_VARIABLES; + + EPHYR_RETURN_VAL_IF_FAIL (a_req, BadValue) ; + EPHYR_LOG ("enter\n") ; + + if (a_do_swap) { + __GLX_SWAP_SHORT(&a_req->length); + __GLX_SWAP_INT(&a_req->context); + __GLX_SWAP_INT(&a_req->visual); + __GLX_SWAP_INT(&a_req->screen); + __GLX_SWAP_INT(&a_req->shareList); + } + + EPHYR_LOG ("context creation requested. localid:%d, " + "screen:%d, visual:%d, direct:%d\n", + (int)a_req->context, (int)a_req->screen, + (int)a_req->visual, (int)a_req->isDirect) ; + + memset (&host_w_attrs, 0, sizeof (host_w_attrs)) ; + if (!hostx_get_window_attributes (hostx_get_window (a_req->screen), + &host_w_attrs)) { + EPHYR_LOG_ERROR ("failed to get host window attrs\n") ; + goto out ; + } + + EPHYR_LOG ("host window visual id: %d\n", host_w_attrs.visualid) ; + + if (!ephyrHostGLXCreateContext (a_req->screen, + host_w_attrs.visualid, + a_req->context, + a_req->shareList, + a_req->isDirect)) { + EPHYR_LOG_ERROR ("ephyrHostGLXCreateContext() failed\n") ; + goto out ; + } + res = Success; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXCreateContext (__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; + + return ephyrGLXCreateContextReal (req, FALSE) ; +} + +int ephyrGLXCreateContextSwap (__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; + return ephyrGLXCreateContextReal (req, TRUE) ; +} + +static int +ephyrGLXDestroyContextReal (__GLXclientState *a_cl, + GLbyte *a_pc, + Bool a_do_swap) +{ + int res=BadImplementation; + ClientPtr client = a_cl->client; + xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) a_pc; + + EPHYR_LOG ("enter. id:%d\n", (int)req->context) ; + if (!ephyrHostDestroyContext (req->context)) { + EPHYR_LOG_ERROR ("ephyrHostDestroyContext() failed\n") ; + client->errorValue = req->context ; + goto out ; + } + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXDestroyContextReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXDestroyContextReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXMakeCurrentReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) +{ + int res=BadImplementation; + xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) a_pc; + xGLXMakeCurrentReply reply ; + DrawablePtr drawable=NULL; + int rc=0; + + EPHYR_LOG ("enter\n") ; + rc = dixLookupDrawable (&drawable, + req->drawable, + a_cl->client, + 0, + DixReadAccess); + EPHYR_RETURN_VAL_IF_FAIL (drawable, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (drawable->pScreen, BadValue) ; + EPHYR_LOG ("screen nummber requested:%d\n", + drawable->pScreen->myNum) ; + + memset (&reply, 0, sizeof (reply)) ; + if (!ephyrHostGLXMakeCurrent (hostx_get_window (drawable->pScreen->myNum), + req->context, + req->oldContextTag, + (int*)&reply.contextTag)) { + EPHYR_LOG_ERROR ("ephyrHostGLXMakeCurrent() failed\n") ; + goto out; + } + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = a_cl->client->sequence; + if (a_do_swap) { + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + __GLX_SWAP_INT(&reply.contextTag); + } + WriteToClient(a_cl->client, sz_xGLXMakeCurrentReply, (char *)&reply); + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXMakeCurrentReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXMakeCurrentReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXGetStringReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) +{ + ClientPtr client=NULL ; + int context_tag=0, name=0, res=BadImplementation, length=0 ; + char *string=NULL; + __GLX_DECLARE_SWAP_VARIABLES; + + EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + client = a_cl->client ; + + if (a_do_swap) { + __GLX_SWAP_INT (a_pc + 4); + __GLX_SWAP_INT (a_pc + __GLX_SINGLE_HDR_SIZE); + } + context_tag = __GLX_GET_SINGLE_CONTEXT_TAG (a_pc) ; + a_pc += __GLX_SINGLE_HDR_SIZE; + name = *(GLenum*)(a_pc + 0); + EPHYR_LOG ("context_tag:%d, name:%d\n", context_tag, name) ; + if (!ephyrHostGLXGetStringFromServer (context_tag, + name, + EPHYR_HOST_GLX_GetString, + &string)) { + EPHYR_LOG_ERROR ("failed to get string from server\n") ; + goto out ; + } + if (string) { + length = strlen (string) + 1; + EPHYR_LOG ("got string:'%s', size:%d\n", string, length) ; + } else { + EPHYR_LOG ("got string: string (null)\n") ; + } + __GLX_BEGIN_REPLY (length); + __GLX_PUT_SIZE (length); + __GLX_SEND_HEADER (); + if (a_do_swap) { + __GLX_SWAP_REPLY_SIZE (); + __GLX_SWAP_REPLY_HEADER (); + } + WriteToClient (client, length, (char *)string); + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetStringReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetStringReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXGetIntegervReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) +{ + int res=BadImplementation; + xGLXSingleReq * const req = (xGLXSingleReq *) a_pc; + GLenum int_name ; + int value=0 ; + GLint answer_buf_room[200]; + GLint *buf=NULL ; + + EPHYR_LOG ("enter\n") ; + + a_pc += __GLX_SINGLE_HDR_SIZE; + + int_name = *(GLenum*) (a_pc+0) ; + if (!ephyrHostGetIntegerValue (req->contextTag, int_name, &value)) { + EPHYR_LOG_ERROR ("ephyrHostGetIntegerValue() failed\n") ; + goto out ; + } + buf = __glXGetAnswerBuffer (a_cl, sizeof (value), + answer_buf_room, + sizeof (answer_buf_room), + 4) ; + + if (!buf) { + EPHYR_LOG_ERROR ("failed to allocate reply buffer\n") ; + res = BadAlloc ; + goto out ; + } + __glXSendReply (a_cl->client, buf, 1, sizeof (value), GL_FALSE, 0) ; + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetIntegervReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetIntegervReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXIsDirectReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) +{ + int res=BadImplementation; + ClientPtr client = a_cl->client; + xGLXIsDirectReq *req = (xGLXIsDirectReq *) a_pc; + xGLXIsDirectReply reply; + int is_direct=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + memset (&reply, 0, sizeof (reply)) ; + if (!ephyrHostIsContextDirect (req->context, (int*)&is_direct)) { + EPHYR_LOG_ERROR ("ephyrHostIsContextDirect() failed\n") ; + goto out ; + } + reply.isDirect = is_direct ; + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply); + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXIsDirectReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXIsDirectReal (a_cl, a_pc, TRUE) ; +} diff --git a/xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c b/xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c index f4a1b9d17..60f200629 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c +++ b/xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c @@ -1,1012 +1,1012 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum <mallum@openedhand.com> - * - * Copyright © 2007 OpenedHand Ltd - * - * 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 OpenedHand Ltd not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. OpenedHand Ltd makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OpenedHand Ltd 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. - * - * Authors: - * Dodji Seketeli <dodji@openedhand.com> - */ -#ifdef HAVE_CONFIG_H -#include <kdrive-config.h> -#endif -/* - * including some server headers (like kdrive-config.h) - * might define the macro _XSERVER64 - * on 64 bits machines. That macro must _NOT_ be defined for Xlib - * client code, otherwise bad things happen. - * So let's undef that macro if necessary. - */ -#ifdef _XSERVER64 -#undef _XSERVER64 -#endif -#include <X11/Xutil.h> -#include <X11/Xlibint.h> -#include <X11/extensions/Xvlib.h> -#include <X11/extensions/Xvproto.h> -#include <X11/extensions/Xext.h> -#include <X11/extensions/extutil.h> -#define _HAVE_XALLOC_DECLS - -#include "hostx.h" -#include "ephyrhostvideo.h" -#include "ephyrlog.h" - -#ifndef TRUE -#define TRUE 1 -#endif /*TRUE*/ - -#ifndef FALSE -#define FALSE 0 -#endif /*FALSE*/ - -static XExtensionInfo _xv_info_data; -static XExtensionInfo *xv_info = &_xv_info_data; -static char *xv_extension_name = XvName; -static char *xv_error_string(Display *dpy, int code, XExtCodes *codes, - char * buf, int n); -static int xv_close_display(Display *dpy, XExtCodes *codes); -static Bool xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire); - -static XExtensionHooks xv_extension_hooks = { - NULL, /* create_gc */ - NULL, /* copy_gc */ - NULL, /* flush_gc */ - NULL, /* free_gc */ - NULL, /* create_font */ - NULL, /* free_font */ - xv_close_display, /* close_display */ - xv_wire_to_event, /* wire_to_event */ - NULL, /* event_to_wire */ - NULL, /* error */ - xv_error_string /* error_string */ -}; - - -static char *xv_error_list[] = -{ - "BadPort", /* XvBadPort */ - "BadEncoding", /* XvBadEncoding */ - "BadControl" /* XvBadControl */ -}; - - -#define XvCheckExtension(dpy, i, val) \ - XextCheckExtension(dpy, i, xv_extension_name, val) -#define XvGetReq(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(xv##name##Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (xv##name##Req *)(dpy->last_req = dpy->bufptr);\ - req->reqType = info->codes->major_opcode;\ - req->xvReqType = xv_##name; \ - req->length = (SIZEOF(xv##name##Req))>>2;\ - dpy->bufptr += SIZEOF(xv##name##Req);\ - dpy->request++ - -static XEXT_GENERATE_CLOSE_DISPLAY (xv_close_display, xv_info) - - -static XEXT_GENERATE_FIND_DISPLAY (xv_find_display, xv_info, - xv_extension_name, - &xv_extension_hooks, - XvNumEvents, NULL) - -static XEXT_GENERATE_ERROR_STRING (xv_error_string, xv_extension_name, - XvNumErrors, xv_error_list) - -struct _EphyrHostXVAdaptorArray { - XvAdaptorInfo *adaptors ; - unsigned int nb_adaptors ; -}; - -/*heavily copied from libx11*/ -#define BUFSIZE 2048 -static void -ephyrHostXVLogXErrorEvent (Display *a_display, - XErrorEvent *a_err_event, - FILE *a_fp) -{ - char buffer[BUFSIZ]; - char mesg[BUFSIZ]; - char number[32]; - const char *mtype = "XlibMessage"; - register _XExtension *ext = (_XExtension *)NULL; - _XExtension *bext = (_XExtension *)NULL; - Display *dpy = a_display ; - - XGetErrorText(dpy, a_err_event->error_code, buffer, BUFSIZ); - XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ); - (void) fprintf(a_fp, "%s: %s\n ", mesg, buffer); - XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", - mesg, BUFSIZ); - (void) fprintf(a_fp, mesg, a_err_event->request_code); - if (a_err_event->request_code < 128) { - sprintf(number, "%d", a_err_event->request_code); - XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ); - } else { - for (ext = dpy->ext_procs; - ext && (ext->codes.major_opcode != a_err_event->request_code); - ext = ext->next) - ; - if (ext) - strcpy(buffer, ext->name); - else - buffer[0] = '\0'; - } - (void) fprintf(a_fp, " (%s)\n", buffer); - if (a_err_event->request_code >= 128) { - XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d", - mesg, BUFSIZ); - fputs(" ", a_fp); - (void) fprintf(a_fp, mesg, a_err_event->minor_code); - if (ext) { - sprintf(mesg, "%s.%d", ext->name, a_err_event->minor_code); - XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ); - (void) fprintf(a_fp, " (%s)", buffer); - } - fputs("\n", a_fp); - } - if (a_err_event->error_code >= 128) { - /* kludge, try to find the extension that caused it */ - buffer[0] = '\0'; - for (ext = dpy->ext_procs; ext; ext = ext->next) { - if (ext->error_string) - (*ext->error_string)(dpy, a_err_event->error_code, &ext->codes, - buffer, BUFSIZ); - if (buffer[0]) { - bext = ext; - break; - } - if (ext->codes.first_error && - ext->codes.first_error < (int)a_err_event->error_code && - (!bext || ext->codes.first_error > bext->codes.first_error)) - bext = ext; - } - if (bext) - sprintf(buffer, "%s.%d", bext->name, - a_err_event->error_code - bext->codes.first_error); - else - strcpy(buffer, "Value"); - XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ); - if (mesg[0]) { - fputs(" ", a_fp); - (void) fprintf(a_fp, mesg, a_err_event->resourceid); - fputs("\n", a_fp); - } - /* let extensions try to print the values */ - for (ext = dpy->ext_procs; ext; ext = ext->next) { - if (ext->error_values) - (*ext->error_values)(dpy, a_err_event, a_fp); - } - } else if ((a_err_event->error_code == BadWindow) || - (a_err_event->error_code == BadPixmap) || - (a_err_event->error_code == BadCursor) || - (a_err_event->error_code == BadFont) || - (a_err_event->error_code == BadDrawable) || - (a_err_event->error_code == BadColor) || - (a_err_event->error_code == BadGC) || - (a_err_event->error_code == BadIDChoice) || - (a_err_event->error_code == BadValue) || - (a_err_event->error_code == BadAtom)) { - if (a_err_event->error_code == BadValue) - XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x", - mesg, BUFSIZ); - else if (a_err_event->error_code == BadAtom) - XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x", - mesg, BUFSIZ); - else - XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x", - mesg, BUFSIZ); - fputs(" ", a_fp); - (void) fprintf(a_fp, mesg, a_err_event->resourceid); - fputs("\n", a_fp); - } - XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", - mesg, BUFSIZ); - fputs(" ", a_fp); - (void) fprintf(a_fp, mesg, a_err_event->serial); - XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d", - mesg, BUFSIZ); - fputs("\n ", a_fp); - (void) fprintf(a_fp, mesg, dpy->request); - fputs("\n", a_fp); -} - -static int -ephyrHostXVErrorHandler (Display *a_display, - XErrorEvent *a_error_event) -{ - EPHYR_LOG_ERROR ("got an error from the host xserver:\n") ; - ephyrHostXVLogXErrorEvent (a_display, a_error_event, stderr) ; - return Success ; -} - -void -ephyrHostXVInit (void) -{ - static Bool s_initialized ; - - if (s_initialized) - return ; - XSetErrorHandler (ephyrHostXVErrorHandler) ; - s_initialized = TRUE ; -} - -Bool -ephyrHostXVQueryAdaptors (EphyrHostXVAdaptorArray **a_adaptors) -{ - EphyrHostXVAdaptorArray *result=NULL ; - int ret=0 ; - Bool is_ok=FALSE ; - - EPHYR_RETURN_VAL_IF_FAIL (a_adaptors, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - result = Xcalloc (1, sizeof (EphyrHostXVAdaptorArray)) ; - if (!result) - goto out ; - - ret = XvQueryAdaptors (hostx_get_display (), - DefaultRootWindow (hostx_get_display ()), - &result->nb_adaptors, - &result->adaptors) ; - if (ret != Success) { - EPHYR_LOG_ERROR ("failed to query host adaptors: %d\n", ret) ; - goto out ; - } - *a_adaptors = result ; - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -void -ephyrHostXVAdaptorArrayDelete (EphyrHostXVAdaptorArray *a_adaptors) -{ - if (!a_adaptors) - return ; - if (a_adaptors->adaptors) { - XvFreeAdaptorInfo (a_adaptors->adaptors) ; - a_adaptors->adaptors = NULL ; - a_adaptors->nb_adaptors = 0 ; - } - XFree (a_adaptors) ; -} - -int -ephyrHostXVAdaptorArrayGetSize (const EphyrHostXVAdaptorArray *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; - return a_this->nb_adaptors ; -} - -EphyrHostXVAdaptor* -ephyrHostXVAdaptorArrayAt (const EphyrHostXVAdaptorArray *a_this, - int a_index) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; - - if (a_index >= a_this->nb_adaptors) - return NULL ; - return (EphyrHostXVAdaptor*)&a_this->adaptors[a_index] ; -} - -char -ephyrHostXVAdaptorGetType (const EphyrHostXVAdaptor *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; - return ((XvAdaptorInfo*)a_this)->type ; -} - -const char* -ephyrHostXVAdaptorGetName (const EphyrHostXVAdaptor *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; - - return ((XvAdaptorInfo*)a_this)->name ; -} - -EphyrHostVideoFormat* -ephyrHostXVAdaptorGetVideoFormats (const EphyrHostXVAdaptor *a_this, - int *a_nb_formats) -{ - EphyrHostVideoFormat *formats=NULL ; - int nb_formats=0, i=0 ; - XVisualInfo *visual_info, visual_info_template ; - int nb_visual_info ; - - EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; - - nb_formats = ((XvAdaptorInfo*)a_this)->num_formats ; - formats = Xcalloc (nb_formats, sizeof (EphyrHostVideoFormat)) ; - for (i=0; i < nb_formats; i++) { - memset (&visual_info_template, 0, sizeof (visual_info_template)) ; - visual_info_template.visualid = - ((XvAdaptorInfo*)a_this)->formats[i].visual_id; - visual_info = XGetVisualInfo (hostx_get_display (), - VisualIDMask, - &visual_info_template, - &nb_visual_info) ; - formats[i].depth = ((XvAdaptorInfo*)a_this)->formats[i].depth ; - formats[i].visual_class = visual_info->class ; - XFree (visual_info) ; - } - if (a_nb_formats) - *a_nb_formats = nb_formats ; - return formats ; -} - -int -ephyrHostXVAdaptorGetNbPorts (const EphyrHostXVAdaptor *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; - - return ((XvAdaptorInfo*)a_this)->num_ports ; -} - -int -ephyrHostXVAdaptorGetFirstPortID (const EphyrHostXVAdaptor *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; - - return ((XvAdaptorInfo*)a_this)->base_id ; -} - -Bool -ephyrHostXVAdaptorHasPutVideo (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; - - if (((XvAdaptorInfo*)a_this)->type & XvVideoMask & XvInputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVAdaptorHasGetVideo (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - if (((XvAdaptorInfo*)a_this)->type & XvVideoMask & XvOutputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVAdaptorHasPutStill (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; - - if (((XvAdaptorInfo*)a_this)->type & XvStillMask && XvInputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVAdaptorHasGetStill (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; - - if (((XvAdaptorInfo*)a_this)->type & XvStillMask && XvOutputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVAdaptorHasPutImage (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; - - if (((XvAdaptorInfo*)a_this)->type & XvImageMask && XvInputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVQueryEncodings (int a_port_id, - EphyrHostEncoding **a_encodings, - unsigned int *a_num_encodings) -{ - EphyrHostEncoding *encodings=NULL ; - XvEncodingInfo *encoding_info=NULL ; - unsigned int num_encodings=0, i; - int ret=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, FALSE) ; - - ret = XvQueryEncodings (hostx_get_display (), - a_port_id, - &num_encodings, - &encoding_info) ; - if (num_encodings && encoding_info) { - encodings = Xcalloc (num_encodings, sizeof (EphyrHostEncoding)) ; - for (i=0; i<num_encodings; i++) { - encodings[i].id = encoding_info[i].encoding_id ; - encodings[i].name = strdup (encoding_info[i].name) ; - encodings[i].width = encoding_info[i].width ; - encodings[i].height = encoding_info[i].height ; - encodings[i].rate.numerator = encoding_info[i].rate.numerator ; - encodings[i].rate.denominator = encoding_info[i].rate.denominator ; - } - } - if (encoding_info) { - XvFreeEncodingInfo (encoding_info) ; - encoding_info = NULL ; - } - *a_encodings = encodings ; - *a_num_encodings = num_encodings ; - - if (ret != Success) - return FALSE ; - return TRUE ; -} - -void -ephyrHostEncodingsDelete (EphyrHostEncoding *a_encodings, - int a_num_encodings) -{ - int i=0 ; - - if (!a_encodings) - return ; - for (i=0; i < a_num_encodings; i++) { - xfree (a_encodings[i].name) ; - a_encodings[i].name = NULL ; - } - xfree (a_encodings) ; -} - -void -ephyrHostAttributesDelete (EphyrHostAttribute *a_attributes) -{ - if (!a_attributes) - return ; - XFree (a_attributes) ; -} - -Bool -ephyrHostXVQueryPortAttributes (int a_port_id, - EphyrHostAttribute **a_attributes, - int *a_num_attributes) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_attributes && a_num_attributes, FALSE) ; - - *a_attributes = - (EphyrHostAttribute*)XvQueryPortAttributes (hostx_get_display (), - a_port_id, - a_num_attributes); - - return TRUE ; -} - -Bool -ephyrHostXVQueryImageFormats (int a_port_id, - EphyrHostImageFormat **a_formats, - int *a_num_format) -{ - XvImageFormatValues *result=NULL ; - - EPHYR_RETURN_VAL_IF_FAIL (a_formats && a_num_format, FALSE) ; - - result = XvListImageFormats (hostx_get_display (), - a_port_id, - a_num_format) ; - *a_formats = (EphyrHostImageFormat*) result ; - return TRUE ; - -} - -Bool -ephyrHostXVSetPortAttribute (int a_port_id, - int a_atom, - int a_attr_value) -{ - int res=Success ; - - EPHYR_LOG ("atom,name,value: (%d,%s,%d)\n", - a_atom, - XGetAtomName (hostx_get_display (), a_atom), - a_attr_value) ; - - res = XvSetPortAttribute (hostx_get_display (), - a_port_id, - a_atom, - a_attr_value) ; - if (res != Success) { - EPHYR_LOG_ERROR ("XvSetPortAttribute() failed: %d\n", res) ; - return FALSE ; - } - XFlush (hostx_get_display ()) ; - EPHYR_LOG ("leave\n") ; - - return TRUE ; -} - -Bool -ephyrHostXVGetPortAttribute (int a_port_id, - int a_atom, - int *a_attr_value) -{ - int res=Success ; - Bool ret=FALSE ; - - EPHYR_RETURN_VAL_IF_FAIL (a_attr_value, FALSE) ; - - EPHYR_LOG ("enter, a_port_id: %d, a_atomid: %d, attr_name: %s\n", - a_port_id, a_atom, XGetAtomName (hostx_get_display (), a_atom)) ; - - res = XvGetPortAttribute (hostx_get_display (), - a_port_id, - a_atom, - a_attr_value) ; - if (res != Success) { - EPHYR_LOG_ERROR ("XvGetPortAttribute() failed: %d \n", res) ; - goto out ; - } - EPHYR_LOG ("atom,value: (%d, %d)\n", a_atom, *a_attr_value) ; - - ret = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return ret ; -} - -Bool -ephyrHostXVQueryBestSize (int a_port_id, - Bool a_motion, - unsigned int a_frame_w, - unsigned int a_frame_h, - unsigned int a_drw_w, - unsigned int a_drw_h, - unsigned int *a_actual_w, - unsigned int *a_actual_h) -{ - int res=0 ; - Bool is_ok=FALSE ; - - EPHYR_RETURN_VAL_IF_FAIL (a_actual_w && a_actual_h, FALSE) ; - - EPHYR_LOG ("enter: frame (%dx%d), drw (%dx%d)\n", - a_frame_w, a_frame_h, - a_drw_w, a_drw_h) ; - - res = XvQueryBestSize (hostx_get_display (), - a_port_id, - a_motion, - a_frame_w, a_frame_h, - a_drw_w, a_drw_h, - a_actual_w, a_actual_h) ; - if (res != Success) { - EPHYR_LOG_ERROR ("XvQueryBestSize() failed: %d\n", res) ; - goto out ; - } - XSync (hostx_get_display (), FALSE) ; - - EPHYR_LOG ("actual (%dx%d)\n", *a_actual_w, *a_actual_h) ; - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -static Bool -xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire) -{ - XExtDisplayInfo *info = xv_find_display (dpy); - XvEvent *re = (XvEvent *)host; - xvEvent *event = (xvEvent *)wire; - - XvCheckExtension(dpy, info, False); - - switch ((event->u.u.type & 0x7F) - info->codes->first_event) { - case XvVideoNotify: - re->xvvideo.type = event->u.u.type & 0x7f; - re->xvvideo.serial = - _XSetLastRequestRead(dpy, (xGenericReply *)event); - re->xvvideo.send_event = ((event->u.u.type & 0x80) != 0); - re->xvvideo.display = dpy; - re->xvvideo.time = event->u.videoNotify.time; - re->xvvideo.reason = event->u.videoNotify.reason; - re->xvvideo.drawable = event->u.videoNotify.drawable; - re->xvvideo.port_id = event->u.videoNotify.port; - break; - case XvPortNotify: - re->xvport.type = event->u.u.type & 0x7f; - re->xvport.serial = - _XSetLastRequestRead(dpy, (xGenericReply *)event); - re->xvport.send_event = ((event->u.u.type & 0x80) != 0); - re->xvport.display = dpy; - re->xvport.time = event->u.portNotify.time; - re->xvport.port_id = event->u.portNotify.port; - re->xvport.attribute = event->u.portNotify.attribute; - re->xvport.value = event->u.portNotify.value; - break; - default: - return False; - } - - return True ; -} - -Bool -ephyrHostXVQueryImageAttributes (int a_port_id, - int a_image_id /*image fourcc code*/, - unsigned short *a_width, - unsigned short *a_height, - int *a_image_size, - int *a_pitches, - int *a_offsets) -{ - Display *dpy = hostx_get_display () ; - Bool ret=FALSE ; - XExtDisplayInfo *info = xv_find_display (dpy); - xvQueryImageAttributesReq *req=NULL; - xvQueryImageAttributesReply rep; - - EPHYR_RETURN_VAL_IF_FAIL (a_width, FALSE) ; - EPHYR_RETURN_VAL_IF_FAIL (a_height, FALSE) ; - EPHYR_RETURN_VAL_IF_FAIL (a_image_size, FALSE) ; - - XvCheckExtension (dpy, info, FALSE); - - LockDisplay (dpy); - - XvGetReq (QueryImageAttributes, req); - req->id = a_image_id; - req->port = a_port_id; - req->width = *a_width; - req->height = *a_height; - /* - * read the reply - */ - if (!_XReply (dpy, (xReply *)&rep, 0, xFalse)) { - EPHYR_LOG_ERROR ("QeryImageAttribute req failed\n") ; - goto out ; - } - if (a_pitches && a_offsets) { - _XRead (dpy, - (char*)a_pitches, - rep.num_planes << 2); - _XRead (dpy, - (char*)a_offsets, - rep.num_planes << 2); - } else { - _XEatData(dpy, rep.length << 2); - } - *a_width = rep.width ; - *a_height = rep.height ; - *a_image_size = rep.data_size ; - - ret = TRUE ; - -out: - UnlockDisplay (dpy) ; - SyncHandle (); - return ret ; -} - -Bool -ephyrHostGetAtom (const char* a_name, - Bool a_create_if_not_exists, - int *a_atom) -{ - int atom=None ; - - EPHYR_RETURN_VAL_IF_FAIL (a_atom, FALSE) ; - - atom = XInternAtom (hostx_get_display (), a_name, a_create_if_not_exists); - if (atom == None) { - return FALSE ; - } - *a_atom = atom ; - return TRUE ; -} - -char* -ephyrHostGetAtomName (int a_atom) -{ - return XGetAtomName (hostx_get_display (), a_atom) ; -} - -void -ephyrHostFree (void *a_pointer) -{ - if (a_pointer) - XFree (a_pointer) ; -} - -Bool -ephyrHostXVPutImage (int a_screen_num, - int a_port_id, - int a_image_id, - int a_drw_x, - int a_drw_y, - int a_drw_w, - int a_drw_h, - int a_src_x, - int a_src_y, - int a_src_w, - int a_src_h, - int a_image_width, - int a_image_height, - unsigned char *a_buf, - EphyrHostBox *a_clip_rects, - int a_clip_rect_nums ) -{ - Bool is_ok=TRUE ; - XvImage *xv_image=NULL ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy = hostx_get_display () ; - XRectangle *rects=NULL ; - int res = 0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_buf, FALSE) ; - - EPHYR_LOG ("enter, num_clip_rects: %d\n", a_clip_rect_nums) ; - - memset (&gc_values, 0, sizeof (gc_values)) ; - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - xv_image = (XvImage*) XvCreateImage (hostx_get_display (), - a_port_id, a_image_id, - NULL, a_image_width, a_image_height) ; - if (!xv_image) { - EPHYR_LOG_ERROR ("failed to create image\n") ; - goto out ; - } - xv_image->data = (char*)a_buf ; - if (a_clip_rect_nums) { - int i=0 ; - rects = calloc (a_clip_rect_nums, sizeof (XRectangle)) ; - for (i=0; i < a_clip_rect_nums; i++) { - rects[i].x = a_clip_rects[i].x1 ; - rects[i].y = a_clip_rects[i].y1 ; - rects[i].width = a_clip_rects[i].x2 - a_clip_rects[i].x1; - rects[i].height = a_clip_rects[i].y2 - a_clip_rects[i].y1; - EPHYR_LOG ("(x,y,w,h): (%d,%d,%d,%d)\n", - rects[i].x, rects[i].y, - rects[i].width, rects[i].height) ; - } - XSetClipRectangles (dpy, gc, 0, 0, rects, a_clip_rect_nums, YXBanded) ; - /*this always returns 1*/ - } - res = XvPutImage (dpy, a_port_id, - hostx_get_window (a_screen_num), - gc, xv_image, - a_src_x, a_src_y, a_src_w, a_src_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - if (res != Success) { - EPHYR_LOG_ERROR ("XvPutImage() failed: %d\n", res) ; - goto out ; - } - is_ok = TRUE ; - -out: - if (xv_image) { - XFree (xv_image) ; - xv_image = NULL ; - } - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - if (rects) { - free (rects) ; - rects = NULL ; - } - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -Bool -ephyrHostXVPutVideo (int a_screen_num, int a_port_id, - int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, - int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) -{ - Bool is_ok=FALSE ; - int res=FALSE ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy=hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - res = XvPutVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - - if (res != Success) { - EPHYR_LOG_ERROR ("XvPutVideo() failed: %d\n", res) ; - goto out ; - } - - is_ok = TRUE ; - -out: - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - return is_ok ; -} - -Bool -ephyrHostXVGetVideo (int a_screen_num, int a_port_id, - int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, - int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) -{ - Bool is_ok=FALSE ; - int res=FALSE ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy=hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - res = XvGetVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - - if (res != Success) { - EPHYR_LOG_ERROR ("XvGetVideo() failed: %d\n", res) ; - goto out ; - } - - is_ok = TRUE ; - -out: - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - return is_ok ; -} - -Bool -ephyrHostXVPutStill (int a_screen_num, int a_port_id, - int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, - int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) -{ - Bool is_ok=FALSE ; - int res=FALSE ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy=hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - res = XvPutStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - - if (res != Success) { - EPHYR_LOG_ERROR ("XvPutStill() failed: %d\n", res) ; - goto out ; - } - - is_ok = TRUE ; - -out: - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - return is_ok ; -} - -Bool -ephyrHostXVGetStill (int a_screen_num, int a_port_id, - int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, - int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) -{ - Bool is_ok=FALSE ; - int res=FALSE ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy=hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - res = XvGetStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - - if (res != Success) { - EPHYR_LOG_ERROR ("XvGetStill() failed: %d\n", res) ; - goto out ; - } - - is_ok = TRUE ; - -out: - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - return is_ok ; -} - -Bool -ephyrHostXVStopVideo (int a_screen_num, int a_port_id) -{ - int ret=0 ; - Bool is_ok=FALSE ; - Display *dpy = hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - ret = XvStopVideo (dpy, a_port_id, hostx_get_window (a_screen_num)) ; - if (ret != Success) { - EPHYR_LOG_ERROR ("XvStopVideo() failed: %d \n", ret) ; - goto out ; - } - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum <mallum@openedhand.com> + * + * Copyright © 2007 OpenedHand Ltd + * + * 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 OpenedHand Ltd not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. OpenedHand Ltd makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OpenedHand Ltd 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. + * + * Authors: + * Dodji Seketeli <dodji@openedhand.com> + */ +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif +/* + * including some server headers (like kdrive-config.h) + * might define the macro _XSERVER64 + * on 64 bits machines. That macro must _NOT_ be defined for Xlib + * client code, otherwise bad things happen. + * So let's undef that macro if necessary. + */ +#ifdef _XSERVER64 +#undef _XSERVER64 +#endif +#include <X11/Xutil.h> +#include <X11/Xlibint.h> +#include <X11/extensions/Xvlib.h> +#include <X11/extensions/Xvproto.h> +#include <X11/extensions/Xext.h> +#include <X11/extensions/extutil.h> +#define _HAVE_XALLOC_DECLS + +#include "hostx.h" +#include "ephyrhostvideo.h" +#include "ephyrlog.h" + +#ifndef TRUE +#define TRUE 1 +#endif /*TRUE*/ + +#ifndef FALSE +#define FALSE 0 +#endif /*FALSE*/ + +static XExtensionInfo _xv_info_data; +static XExtensionInfo *xv_info = &_xv_info_data; +static char *xv_extension_name = XvName; +static char *xv_error_string(Display *dpy, int code, XExtCodes *codes, + char * buf, int n); +static int xv_close_display(Display *dpy, XExtCodes *codes); +static Bool xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire); + +static XExtensionHooks xv_extension_hooks = { + NULL, /* create_gc */ + NULL, /* copy_gc */ + NULL, /* flush_gc */ + NULL, /* free_gc */ + NULL, /* create_font */ + NULL, /* free_font */ + xv_close_display, /* close_display */ + xv_wire_to_event, /* wire_to_event */ + NULL, /* event_to_wire */ + NULL, /* error */ + xv_error_string /* error_string */ +}; + + +static char *xv_error_list[] = +{ + "BadPort", /* XvBadPort */ + "BadEncoding", /* XvBadEncoding */ + "BadControl" /* XvBadControl */ +}; + + +#define XvCheckExtension(dpy, i, val) \ + XextCheckExtension(dpy, i, xv_extension_name, val) +#define XvGetReq(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(xv##name##Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (xv##name##Req *)(dpy->last_req = dpy->bufptr);\ + req->reqType = info->codes->major_opcode;\ + req->xvReqType = xv_##name; \ + req->length = (SIZEOF(xv##name##Req))>>2;\ + dpy->bufptr += SIZEOF(xv##name##Req);\ + dpy->request++ + +static XEXT_GENERATE_CLOSE_DISPLAY (xv_close_display, xv_info) + + +static XEXT_GENERATE_FIND_DISPLAY (xv_find_display, xv_info, + xv_extension_name, + &xv_extension_hooks, + XvNumEvents, NULL) + +static XEXT_GENERATE_ERROR_STRING (xv_error_string, xv_extension_name, + XvNumErrors, xv_error_list) + +struct _EphyrHostXVAdaptorArray { + XvAdaptorInfo *adaptors ; + unsigned int nb_adaptors ; +}; + +/*heavily copied from libx11*/ +#define BUFSIZE 2048 +static void +ephyrHostXVLogXErrorEvent (Display *a_display, + XErrorEvent *a_err_event, + FILE *a_fp) +{ + char buffer[BUFSIZ]; + char mesg[BUFSIZ]; + char number[32]; + const char *mtype = "XlibMessage"; + register _XExtension *ext = (_XExtension *)NULL; + _XExtension *bext = (_XExtension *)NULL; + Display *dpy = a_display ; + + XGetErrorText(dpy, a_err_event->error_code, buffer, BUFSIZ); + XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ); + (void) fprintf(a_fp, "%s: %s\n ", mesg, buffer); + XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", + mesg, BUFSIZ); + (void) fprintf(a_fp, mesg, a_err_event->request_code); + if (a_err_event->request_code < 128) { + sprintf(number, "%d", a_err_event->request_code); + XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ); + } else { + for (ext = dpy->ext_procs; + ext && (ext->codes.major_opcode != a_err_event->request_code); + ext = ext->next) + ; + if (ext) + strcpy(buffer, ext->name); + else + buffer[0] = '\0'; + } + (void) fprintf(a_fp, " (%s)\n", buffer); + if (a_err_event->request_code >= 128) { + XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d", + mesg, BUFSIZ); + fputs(" ", a_fp); + (void) fprintf(a_fp, mesg, a_err_event->minor_code); + if (ext) { + sprintf(mesg, "%s.%d", ext->name, a_err_event->minor_code); + XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ); + (void) fprintf(a_fp, " (%s)", buffer); + } + fputs("\n", a_fp); + } + if (a_err_event->error_code >= 128) { + /* kludge, try to find the extension that caused it */ + buffer[0] = '\0'; + for (ext = dpy->ext_procs; ext; ext = ext->next) { + if (ext->error_string) + (*ext->error_string)(dpy, a_err_event->error_code, &ext->codes, + buffer, BUFSIZ); + if (buffer[0]) { + bext = ext; + break; + } + if (ext->codes.first_error && + ext->codes.first_error < (int)a_err_event->error_code && + (!bext || ext->codes.first_error > bext->codes.first_error)) + bext = ext; + } + if (bext) + sprintf(buffer, "%s.%d", bext->name, + a_err_event->error_code - bext->codes.first_error); + else + strcpy(buffer, "Value"); + XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ); + if (mesg[0]) { + fputs(" ", a_fp); + (void) fprintf(a_fp, mesg, a_err_event->resourceid); + fputs("\n", a_fp); + } + /* let extensions try to print the values */ + for (ext = dpy->ext_procs; ext; ext = ext->next) { + if (ext->error_values) + (*ext->error_values)(dpy, a_err_event, a_fp); + } + } else if ((a_err_event->error_code == BadWindow) || + (a_err_event->error_code == BadPixmap) || + (a_err_event->error_code == BadCursor) || + (a_err_event->error_code == BadFont) || + (a_err_event->error_code == BadDrawable) || + (a_err_event->error_code == BadColor) || + (a_err_event->error_code == BadGC) || + (a_err_event->error_code == BadIDChoice) || + (a_err_event->error_code == BadValue) || + (a_err_event->error_code == BadAtom)) { + if (a_err_event->error_code == BadValue) + XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x", + mesg, BUFSIZ); + else if (a_err_event->error_code == BadAtom) + XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x", + mesg, BUFSIZ); + else + XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x", + mesg, BUFSIZ); + fputs(" ", a_fp); + (void) fprintf(a_fp, mesg, a_err_event->resourceid); + fputs("\n", a_fp); + } + XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", + mesg, BUFSIZ); + fputs(" ", a_fp); + (void) fprintf(a_fp, mesg, a_err_event->serial); + XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d", + mesg, BUFSIZ); + fputs("\n ", a_fp); + (void) fprintf(a_fp, mesg, dpy->request); + fputs("\n", a_fp); +} + +static int +ephyrHostXVErrorHandler (Display *a_display, + XErrorEvent *a_error_event) +{ + EPHYR_LOG_ERROR ("got an error from the host xserver:\n") ; + ephyrHostXVLogXErrorEvent (a_display, a_error_event, stderr) ; + return Success ; +} + +void +ephyrHostXVInit (void) +{ + static Bool s_initialized ; + + if (s_initialized) + return ; + XSetErrorHandler (ephyrHostXVErrorHandler) ; + s_initialized = TRUE ; +} + +Bool +ephyrHostXVQueryAdaptors (EphyrHostXVAdaptorArray **a_adaptors) +{ + EphyrHostXVAdaptorArray *result=NULL ; + int ret=0 ; + Bool is_ok=FALSE ; + + EPHYR_RETURN_VAL_IF_FAIL (a_adaptors, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + result = Xcalloc (1, sizeof (EphyrHostXVAdaptorArray)) ; + if (!result) + goto out ; + + ret = XvQueryAdaptors (hostx_get_display (), + DefaultRootWindow (hostx_get_display ()), + &result->nb_adaptors, + &result->adaptors) ; + if (ret != Success) { + EPHYR_LOG_ERROR ("failed to query host adaptors: %d\n", ret) ; + goto out ; + } + *a_adaptors = result ; + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +void +ephyrHostXVAdaptorArrayDelete (EphyrHostXVAdaptorArray *a_adaptors) +{ + if (!a_adaptors) + return ; + if (a_adaptors->adaptors) { + XvFreeAdaptorInfo (a_adaptors->adaptors) ; + a_adaptors->adaptors = NULL ; + a_adaptors->nb_adaptors = 0 ; + } + XFree (a_adaptors) ; +} + +int +ephyrHostXVAdaptorArrayGetSize (const EphyrHostXVAdaptorArray *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; + return a_this->nb_adaptors ; +} + +EphyrHostXVAdaptor* +ephyrHostXVAdaptorArrayAt (const EphyrHostXVAdaptorArray *a_this, + int a_index) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; + + if (a_index >= a_this->nb_adaptors) + return NULL ; + return (EphyrHostXVAdaptor*)&a_this->adaptors[a_index] ; +} + +char +ephyrHostXVAdaptorGetType (const EphyrHostXVAdaptor *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; + return ((XvAdaptorInfo*)a_this)->type ; +} + +const char* +ephyrHostXVAdaptorGetName (const EphyrHostXVAdaptor *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; + + return ((XvAdaptorInfo*)a_this)->name ; +} + +EphyrHostVideoFormat* +ephyrHostXVAdaptorGetVideoFormats (const EphyrHostXVAdaptor *a_this, + int *a_nb_formats) +{ + EphyrHostVideoFormat *formats=NULL ; + int nb_formats=0, i=0 ; + XVisualInfo *visual_info, visual_info_template ; + int nb_visual_info ; + + EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; + + nb_formats = ((XvAdaptorInfo*)a_this)->num_formats ; + formats = Xcalloc (nb_formats, sizeof (EphyrHostVideoFormat)) ; + for (i=0; i < nb_formats; i++) { + memset (&visual_info_template, 0, sizeof (visual_info_template)) ; + visual_info_template.visualid = + ((XvAdaptorInfo*)a_this)->formats[i].visual_id; + visual_info = XGetVisualInfo (hostx_get_display (), + VisualIDMask, + &visual_info_template, + &nb_visual_info) ; + formats[i].depth = ((XvAdaptorInfo*)a_this)->formats[i].depth ; + formats[i].visual_class = visual_info->class ; + XFree (visual_info) ; + } + if (a_nb_formats) + *a_nb_formats = nb_formats ; + return formats ; +} + +int +ephyrHostXVAdaptorGetNbPorts (const EphyrHostXVAdaptor *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; + + return ((XvAdaptorInfo*)a_this)->num_ports ; +} + +int +ephyrHostXVAdaptorGetFirstPortID (const EphyrHostXVAdaptor *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; + + return ((XvAdaptorInfo*)a_this)->base_id ; +} + +Bool +ephyrHostXVAdaptorHasPutVideo (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; + + if (((XvAdaptorInfo*)a_this)->type & XvVideoMask & XvInputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVAdaptorHasGetVideo (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + if (((XvAdaptorInfo*)a_this)->type & XvVideoMask & XvOutputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVAdaptorHasPutStill (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; + + if (((XvAdaptorInfo*)a_this)->type & XvStillMask && XvInputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVAdaptorHasGetStill (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; + + if (((XvAdaptorInfo*)a_this)->type & XvStillMask && XvOutputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVAdaptorHasPutImage (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; + + if (((XvAdaptorInfo*)a_this)->type & XvImageMask && XvInputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVQueryEncodings (int a_port_id, + EphyrHostEncoding **a_encodings, + unsigned int *a_num_encodings) +{ + EphyrHostEncoding *encodings=NULL ; + XvEncodingInfo *encoding_info=NULL ; + unsigned int num_encodings=0, i; + int ret=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, FALSE) ; + + ret = XvQueryEncodings (hostx_get_display (), + a_port_id, + &num_encodings, + &encoding_info) ; + if (num_encodings && encoding_info) { + encodings = Xcalloc (num_encodings, sizeof (EphyrHostEncoding)) ; + for (i=0; i<num_encodings; i++) { + encodings[i].id = encoding_info[i].encoding_id ; + encodings[i].name = strdup (encoding_info[i].name) ; + encodings[i].width = encoding_info[i].width ; + encodings[i].height = encoding_info[i].height ; + encodings[i].rate.numerator = encoding_info[i].rate.numerator ; + encodings[i].rate.denominator = encoding_info[i].rate.denominator ; + } + } + if (encoding_info) { + XvFreeEncodingInfo (encoding_info) ; + encoding_info = NULL ; + } + *a_encodings = encodings ; + *a_num_encodings = num_encodings ; + + if (ret != Success) + return FALSE ; + return TRUE ; +} + +void +ephyrHostEncodingsDelete (EphyrHostEncoding *a_encodings, + int a_num_encodings) +{ + int i=0 ; + + if (!a_encodings) + return ; + for (i=0; i < a_num_encodings; i++) { + free(a_encodings[i].name) ; + a_encodings[i].name = NULL ; + } + free(a_encodings) ; +} + +void +ephyrHostAttributesDelete (EphyrHostAttribute *a_attributes) +{ + if (!a_attributes) + return ; + XFree (a_attributes) ; +} + +Bool +ephyrHostXVQueryPortAttributes (int a_port_id, + EphyrHostAttribute **a_attributes, + int *a_num_attributes) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_attributes && a_num_attributes, FALSE) ; + + *a_attributes = + (EphyrHostAttribute*)XvQueryPortAttributes (hostx_get_display (), + a_port_id, + a_num_attributes); + + return TRUE ; +} + +Bool +ephyrHostXVQueryImageFormats (int a_port_id, + EphyrHostImageFormat **a_formats, + int *a_num_format) +{ + XvImageFormatValues *result=NULL ; + + EPHYR_RETURN_VAL_IF_FAIL (a_formats && a_num_format, FALSE) ; + + result = XvListImageFormats (hostx_get_display (), + a_port_id, + a_num_format) ; + *a_formats = (EphyrHostImageFormat*) result ; + return TRUE ; + +} + +Bool +ephyrHostXVSetPortAttribute (int a_port_id, + int a_atom, + int a_attr_value) +{ + int res=Success ; + + EPHYR_LOG ("atom,name,value: (%d,%s,%d)\n", + a_atom, + XGetAtomName (hostx_get_display (), a_atom), + a_attr_value) ; + + res = XvSetPortAttribute (hostx_get_display (), + a_port_id, + a_atom, + a_attr_value) ; + if (res != Success) { + EPHYR_LOG_ERROR ("XvSetPortAttribute() failed: %d\n", res) ; + return FALSE ; + } + XFlush (hostx_get_display ()) ; + EPHYR_LOG ("leave\n") ; + + return TRUE ; +} + +Bool +ephyrHostXVGetPortAttribute (int a_port_id, + int a_atom, + int *a_attr_value) +{ + int res=Success ; + Bool ret=FALSE ; + + EPHYR_RETURN_VAL_IF_FAIL (a_attr_value, FALSE) ; + + EPHYR_LOG ("enter, a_port_id: %d, a_atomid: %d, attr_name: %s\n", + a_port_id, a_atom, XGetAtomName (hostx_get_display (), a_atom)) ; + + res = XvGetPortAttribute (hostx_get_display (), + a_port_id, + a_atom, + a_attr_value) ; + if (res != Success) { + EPHYR_LOG_ERROR ("XvGetPortAttribute() failed: %d \n", res) ; + goto out ; + } + EPHYR_LOG ("atom,value: (%d, %d)\n", a_atom, *a_attr_value) ; + + ret = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return ret ; +} + +Bool +ephyrHostXVQueryBestSize (int a_port_id, + Bool a_motion, + unsigned int a_frame_w, + unsigned int a_frame_h, + unsigned int a_drw_w, + unsigned int a_drw_h, + unsigned int *a_actual_w, + unsigned int *a_actual_h) +{ + int res=0 ; + Bool is_ok=FALSE ; + + EPHYR_RETURN_VAL_IF_FAIL (a_actual_w && a_actual_h, FALSE) ; + + EPHYR_LOG ("enter: frame (%dx%d), drw (%dx%d)\n", + a_frame_w, a_frame_h, + a_drw_w, a_drw_h) ; + + res = XvQueryBestSize (hostx_get_display (), + a_port_id, + a_motion, + a_frame_w, a_frame_h, + a_drw_w, a_drw_h, + a_actual_w, a_actual_h) ; + if (res != Success) { + EPHYR_LOG_ERROR ("XvQueryBestSize() failed: %d\n", res) ; + goto out ; + } + XSync (hostx_get_display (), FALSE) ; + + EPHYR_LOG ("actual (%dx%d)\n", *a_actual_w, *a_actual_h) ; + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +static Bool +xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire) +{ + XExtDisplayInfo *info = xv_find_display (dpy); + XvEvent *re = (XvEvent *)host; + xvEvent *event = (xvEvent *)wire; + + XvCheckExtension(dpy, info, False); + + switch ((event->u.u.type & 0x7F) - info->codes->first_event) { + case XvVideoNotify: + re->xvvideo.type = event->u.u.type & 0x7f; + re->xvvideo.serial = + _XSetLastRequestRead(dpy, (xGenericReply *)event); + re->xvvideo.send_event = ((event->u.u.type & 0x80) != 0); + re->xvvideo.display = dpy; + re->xvvideo.time = event->u.videoNotify.time; + re->xvvideo.reason = event->u.videoNotify.reason; + re->xvvideo.drawable = event->u.videoNotify.drawable; + re->xvvideo.port_id = event->u.videoNotify.port; + break; + case XvPortNotify: + re->xvport.type = event->u.u.type & 0x7f; + re->xvport.serial = + _XSetLastRequestRead(dpy, (xGenericReply *)event); + re->xvport.send_event = ((event->u.u.type & 0x80) != 0); + re->xvport.display = dpy; + re->xvport.time = event->u.portNotify.time; + re->xvport.port_id = event->u.portNotify.port; + re->xvport.attribute = event->u.portNotify.attribute; + re->xvport.value = event->u.portNotify.value; + break; + default: + return False; + } + + return True ; +} + +Bool +ephyrHostXVQueryImageAttributes (int a_port_id, + int a_image_id /*image fourcc code*/, + unsigned short *a_width, + unsigned short *a_height, + int *a_image_size, + int *a_pitches, + int *a_offsets) +{ + Display *dpy = hostx_get_display () ; + Bool ret=FALSE ; + XExtDisplayInfo *info = xv_find_display (dpy); + xvQueryImageAttributesReq *req=NULL; + xvQueryImageAttributesReply rep; + + EPHYR_RETURN_VAL_IF_FAIL (a_width, FALSE) ; + EPHYR_RETURN_VAL_IF_FAIL (a_height, FALSE) ; + EPHYR_RETURN_VAL_IF_FAIL (a_image_size, FALSE) ; + + XvCheckExtension (dpy, info, FALSE); + + LockDisplay (dpy); + + XvGetReq (QueryImageAttributes, req); + req->id = a_image_id; + req->port = a_port_id; + req->width = *a_width; + req->height = *a_height; + /* + * read the reply + */ + if (!_XReply (dpy, (xReply *)&rep, 0, xFalse)) { + EPHYR_LOG_ERROR ("QeryImageAttribute req failed\n") ; + goto out ; + } + if (a_pitches && a_offsets) { + _XRead (dpy, + (char*)a_pitches, + rep.num_planes << 2); + _XRead (dpy, + (char*)a_offsets, + rep.num_planes << 2); + } else { + _XEatData(dpy, rep.length << 2); + } + *a_width = rep.width ; + *a_height = rep.height ; + *a_image_size = rep.data_size ; + + ret = TRUE ; + +out: + UnlockDisplay (dpy) ; + SyncHandle (); + return ret ; +} + +Bool +ephyrHostGetAtom (const char* a_name, + Bool a_create_if_not_exists, + int *a_atom) +{ + int atom=None ; + + EPHYR_RETURN_VAL_IF_FAIL (a_atom, FALSE) ; + + atom = XInternAtom (hostx_get_display (), a_name, a_create_if_not_exists); + if (atom == None) { + return FALSE ; + } + *a_atom = atom ; + return TRUE ; +} + +char* +ephyrHostGetAtomName (int a_atom) +{ + return XGetAtomName (hostx_get_display (), a_atom) ; +} + +void +ephyrHostFree (void *a_pointer) +{ + if (a_pointer) + XFree (a_pointer) ; +} + +Bool +ephyrHostXVPutImage (int a_screen_num, + int a_port_id, + int a_image_id, + int a_drw_x, + int a_drw_y, + int a_drw_w, + int a_drw_h, + int a_src_x, + int a_src_y, + int a_src_w, + int a_src_h, + int a_image_width, + int a_image_height, + unsigned char *a_buf, + EphyrHostBox *a_clip_rects, + int a_clip_rect_nums ) +{ + Bool is_ok=TRUE ; + XvImage *xv_image=NULL ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy = hostx_get_display () ; + XRectangle *rects=NULL ; + int res = 0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_buf, FALSE) ; + + EPHYR_LOG ("enter, num_clip_rects: %d\n", a_clip_rect_nums) ; + + memset (&gc_values, 0, sizeof (gc_values)) ; + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + xv_image = (XvImage*) XvCreateImage (hostx_get_display (), + a_port_id, a_image_id, + NULL, a_image_width, a_image_height) ; + if (!xv_image) { + EPHYR_LOG_ERROR ("failed to create image\n") ; + goto out ; + } + xv_image->data = (char*)a_buf ; + if (a_clip_rect_nums) { + int i=0 ; + rects = calloc (a_clip_rect_nums, sizeof (XRectangle)) ; + for (i=0; i < a_clip_rect_nums; i++) { + rects[i].x = a_clip_rects[i].x1 ; + rects[i].y = a_clip_rects[i].y1 ; + rects[i].width = a_clip_rects[i].x2 - a_clip_rects[i].x1; + rects[i].height = a_clip_rects[i].y2 - a_clip_rects[i].y1; + EPHYR_LOG ("(x,y,w,h): (%d,%d,%d,%d)\n", + rects[i].x, rects[i].y, + rects[i].width, rects[i].height) ; + } + XSetClipRectangles (dpy, gc, 0, 0, rects, a_clip_rect_nums, YXBanded) ; + /*this always returns 1*/ + } + res = XvPutImage (dpy, a_port_id, + hostx_get_window (a_screen_num), + gc, xv_image, + a_src_x, a_src_y, a_src_w, a_src_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + if (res != Success) { + EPHYR_LOG_ERROR ("XvPutImage() failed: %d\n", res) ; + goto out ; + } + is_ok = TRUE ; + +out: + if (xv_image) { + XFree (xv_image) ; + xv_image = NULL ; + } + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + if (rects) { + free (rects) ; + rects = NULL ; + } + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +Bool +ephyrHostXVPutVideo (int a_screen_num, int a_port_id, + int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, + int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) +{ + Bool is_ok=FALSE ; + int res=FALSE ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy=hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + res = XvPutVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + + if (res != Success) { + EPHYR_LOG_ERROR ("XvPutVideo() failed: %d\n", res) ; + goto out ; + } + + is_ok = TRUE ; + +out: + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + return is_ok ; +} + +Bool +ephyrHostXVGetVideo (int a_screen_num, int a_port_id, + int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, + int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) +{ + Bool is_ok=FALSE ; + int res=FALSE ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy=hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + res = XvGetVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + + if (res != Success) { + EPHYR_LOG_ERROR ("XvGetVideo() failed: %d\n", res) ; + goto out ; + } + + is_ok = TRUE ; + +out: + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + return is_ok ; +} + +Bool +ephyrHostXVPutStill (int a_screen_num, int a_port_id, + int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, + int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) +{ + Bool is_ok=FALSE ; + int res=FALSE ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy=hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + res = XvPutStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + + if (res != Success) { + EPHYR_LOG_ERROR ("XvPutStill() failed: %d\n", res) ; + goto out ; + } + + is_ok = TRUE ; + +out: + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + return is_ok ; +} + +Bool +ephyrHostXVGetStill (int a_screen_num, int a_port_id, + int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, + int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) +{ + Bool is_ok=FALSE ; + int res=FALSE ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy=hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + res = XvGetStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + + if (res != Success) { + EPHYR_LOG_ERROR ("XvGetStill() failed: %d\n", res) ; + goto out ; + } + + is_ok = TRUE ; + +out: + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + return is_ok ; +} + +Bool +ephyrHostXVStopVideo (int a_screen_num, int a_port_id) +{ + int ret=0 ; + Bool is_ok=FALSE ; + Display *dpy = hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + ret = XvStopVideo (dpy, a_port_id, hostx_get_window (a_screen_num)) ; + if (ret != Success) { + EPHYR_LOG_ERROR ("XvStopVideo() failed: %d \n", ret) ; + goto out ; + } + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + diff --git a/xorg-server/hw/kdrive/ephyr/ephyrvideo.c b/xorg-server/hw/kdrive/ephyr/ephyrvideo.c index 6624ab98a..14213c966 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyrvideo.c +++ b/xorg-server/hw/kdrive/ephyr/ephyrvideo.c @@ -1,1273 +1,1273 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum <mallum@openedhand.com> - * - * Copyright © 2007 OpenedHand Ltd - * - * 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 OpenedHand Ltd not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. OpenedHand Ltd makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OpenedHand Ltd 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. - * - * Authors: - * Dodji Seketeli <dodji@openedhand.com> - */ - -#ifdef HAVE_CONFIG_H -#include <kdrive-config.h> -#endif -#include <string.h> -#include <X11/extensions/Xv.h> -#include "ephyrlog.h" -#include "kdrive.h" -#include "kxv.h" -#include "ephyr.h" -#include "hostx.h" -#include "ephyrhostvideo.h" - -struct _EphyrXVPriv { - EphyrHostXVAdaptorArray *host_adaptors ; - KdVideoAdaptorPtr adaptors ; - int num_adaptors ; -}; -typedef struct _EphyrXVPriv EphyrXVPriv ; - -struct _EphyrPortPriv { - int port_number ; - KdVideoAdaptorPtr current_adaptor ; - EphyrXVPriv *xv_priv; - unsigned char *image_buf ; - int image_buf_size ; - int image_id ; - int drw_x, drw_y, drw_w, drw_h ; - int src_x, src_y, src_w, src_h ; - int image_width, image_height ; -}; -typedef struct _EphyrPortPriv EphyrPortPriv ; - -static Bool DoSimpleClip (BoxPtr a_dst_drw, - BoxPtr a_clipper, - BoxPtr a_result) ; - -static Bool ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) ; - -/* -static Bool ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) ; -*/ - -static EphyrXVPriv* ephyrXVPrivNew (void) ; -static void ephyrXVPrivDelete (EphyrXVPriv *a_this) ; -static Bool ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) ; -static Bool ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) ; -static Bool ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, - ScreenPtr a_screen) ; - -static Bool ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, - int a_attrs_len, - const char *a_attr_name, - int a_attr_value, - Bool *a_is_valid) ; - -static Bool ephyrXVPrivGetImageBufSize (int a_port_id, - int a_image_id, - unsigned short a_width, - unsigned short a_height, - int *a_size) ; - -static Bool ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, - const unsigned char *a_image, - int a_image_len) ; - -static void ephyrStopVideo (KdScreenInfo *a_info, - pointer a_xv_priv, - Bool a_exit); - -static int ephyrSetPortAttribute (KdScreenInfo *a_info, - Atom a_attr_name, - int a_attr_value, - pointer a_port_priv); - -static int ephyrGetPortAttribute (KdScreenInfo *a_screen_info, - Atom a_attr_name, - int *a_attr_value, - pointer a_port_priv); - -static void ephyrQueryBestSize (KdScreenInfo *a_info, - Bool a_motion, - short a_src_w, - short a_src_h, - short a_drw_w, - short a_drw_h, - unsigned int *a_prefered_w, - unsigned int *a_prefered_h, - pointer a_port_priv); - -static int ephyrPutImage (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_src_x, - short a_src_y, - short a_drw_x, - short a_drw_y, - short a_src_w, - short a_src_h, - short a_drw_w, - short a_drw_h, - int a_id, - unsigned char *a_buf, - short a_width, - short a_height, - Bool a_sync, - RegionPtr a_clipping_region, - pointer a_port_priv); - -static int ephyrReputImage (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_drw_x, - short a_drw_y, - RegionPtr a_clipping_region, - pointer a_port_priv) ; - -static int ephyrPutVideo (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clip_region, - pointer a_port_priv) ; - -static int ephyrGetVideo (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clip_region, - pointer a_port_priv) ; - -static int ephyrPutStill (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clip_region, - pointer a_port_priv) ; - -static int ephyrGetStill (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clip_region, - pointer a_port_priv) ; - -static int ephyrQueryImageAttributes (KdScreenInfo *a_info, - int a_id, - unsigned short *a_w, - unsigned short *a_h, - int *a_pitches, - int *a_offsets); -static int s_base_port_id ; - -/************** - * <helpers> - * ************/ - -static Bool -DoSimpleClip (BoxPtr a_dst_box, - BoxPtr a_clipper, - BoxPtr a_result) -{ - BoxRec dstClippedBox ; - - EPHYR_RETURN_VAL_IF_FAIL (a_dst_box && a_clipper && a_result, FALSE) ; - - /* - * setup the clipbox inside the destination. - */ - dstClippedBox.x1 = a_dst_box->x1 ; - dstClippedBox.x2 = a_dst_box->x2 ; - dstClippedBox.y1 = a_dst_box->y1 ; - dstClippedBox.y2 = a_dst_box->y2 ; - - /* - * if the cliper leftmost edge is inside - * the destination area then the leftmost edge of the resulting - * clipped box is the leftmost edge of the cliper. - */ - if (a_clipper->x1 > dstClippedBox.x1) - dstClippedBox.x1 = a_clipper->x1 ; - - /* - * if the cliper top edge is inside the destination area - * then the bottom horizontal edge of the resulting clipped box - * is the bottom edge of the cliper - */ - if (a_clipper->y1 > dstClippedBox.y1) - dstClippedBox.y1 = a_clipper->y1 ; - - /*ditto for right edge*/ - if (a_clipper->x2 < dstClippedBox.x2) - dstClippedBox.x2 = a_clipper->x2 ; - - /*ditto for bottom edge*/ - if (a_clipper->y2 < dstClippedBox.y2) - dstClippedBox.y2 = a_clipper->y2 ; - - memcpy (a_result, &dstClippedBox, sizeof (dstClippedBox)) ; - return TRUE ; -} - -static Bool -ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) -{ - const char *atom_name=NULL; - int host_atom=None ; - - EPHYR_RETURN_VAL_IF_FAIL (a_host_atom, FALSE) ; - - if (!ValidAtom (a_local_atom)) - return FALSE ; - - atom_name = NameForAtom (a_local_atom) ; - - if (!atom_name) - return FALSE ; - - if (!ephyrHostGetAtom (atom_name, FALSE, &host_atom) || host_atom == None) { - EPHYR_LOG_ERROR ("no atom for string %s defined in host X\n", - atom_name) ; - return FALSE ; - } - *a_host_atom = host_atom ; - return TRUE ; -} - -/* - Not used yed. -static Bool -ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) -{ - Bool is_ok=FALSE ; - char *atom_name=NULL ; - int atom=None ; - - EPHYR_RETURN_VAL_IF_FAIL (a_local_atom, FALSE) ; - - atom_name = ephyrHostGetAtomName (a_host_atom) ; - if (!atom_name) - goto out ; - - atom = MakeAtom (atom_name, strlen (atom_name), TRUE) ; - if (atom == None) - goto out ; - - *a_local_atom = atom ; - is_ok = TRUE ; - -out: - if (atom_name) { - ephyrHostFree (atom_name) ; - } - return is_ok ; -} -*/ - -/************** - *</helpers> - * ************/ - -Bool -ephyrInitVideo (ScreenPtr pScreen) -{ - Bool is_ok = FALSE ; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - static EphyrXVPriv *xv_priv; - - EPHYR_LOG ("enter\n") ; - - if (screen->fb.bitsPerPixel == 8) { - EPHYR_LOG_ERROR ("8 bits depth not supported\n") ; - return FALSE ; - } - - if (!xv_priv) { - xv_priv = ephyrXVPrivNew () ; - } - if (!xv_priv) { - EPHYR_LOG_ERROR ("failed to create xv_priv\n") ; - goto out ; - } - - if (!ephyrXVPrivRegisterAdaptors (xv_priv, pScreen)) { - EPHYR_LOG_ERROR ("failed to register adaptors\n") ; - goto out ; - } - is_ok = TRUE ; - -out: - return is_ok ; -} - -static EphyrXVPriv* -ephyrXVPrivNew (void) -{ - EphyrXVPriv *xv_priv=NULL ; - - EPHYR_LOG ("enter\n") ; - - xv_priv = xcalloc (1, sizeof (EphyrXVPriv)) ; - if (!xv_priv) { - EPHYR_LOG_ERROR ("failed to create EphyrXVPriv\n") ; - goto error ; - } - - ephyrHostXVInit () ; - - if (!ephyrXVPrivQueryHostAdaptors (xv_priv)) { - EPHYR_LOG_ERROR ("failed to query the host x for xv properties\n") ; - goto error ; - } - if (!ephyrXVPrivSetAdaptorsHooks (xv_priv)) { - EPHYR_LOG_ERROR ("failed to set xv_priv hooks\n") ; - goto error ; - } - - EPHYR_LOG ("leave\n") ; - return xv_priv ; - -error: - if (xv_priv) { - ephyrXVPrivDelete (xv_priv) ; - xv_priv = NULL ; - } - return NULL ; -} - -static void -ephyrXVPrivDelete (EphyrXVPriv *a_this) -{ - EPHYR_LOG ("enter\n") ; - - if (!a_this) - return ; - if (a_this->host_adaptors) { - ephyrHostXVAdaptorArrayDelete (a_this->host_adaptors) ; - a_this->host_adaptors = NULL ; - } - xfree (a_this->adaptors) ; - a_this->adaptors = NULL ; - xfree (a_this) ; - EPHYR_LOG ("leave\n") ; -} - -static KdVideoEncodingPtr -videoEncodingDup (EphyrHostEncoding *a_encodings, - int a_num_encodings) -{ - KdVideoEncodingPtr result = NULL ; - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; - - result = xcalloc (a_num_encodings, sizeof (KdVideoEncodingRec)) ; - for (i=0 ; i < a_num_encodings; i++) { - result[i].id = a_encodings[i].id ; - result[i].name = strdup (a_encodings[i].name) ; - result[i].width = a_encodings[i].width ; - result[i].height = a_encodings[i].height ; - result[i].rate.numerator = a_encodings[i].rate.numerator ; - result[i].rate.denominator = a_encodings[i].rate.denominator ; - } - return result ; -} - -static KdAttributePtr -portAttributesDup (EphyrHostAttribute *a_encodings, - int a_num_encodings) -{ - int i=0 ; - KdAttributePtr result=NULL ; - - EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; - - result = xcalloc (a_num_encodings, sizeof (KdAttributeRec)) ; - if (!result) { - EPHYR_LOG_ERROR ("failed to allocate attributes\n") ; - return NULL ; - } - for (i=0; i < a_num_encodings; i++) { - result[i].flags = a_encodings[i].flags ; - result[i].min_value = a_encodings[i].min_value ; - result[i].max_value = a_encodings[i].max_value ; - result[i].name = strdup (a_encodings[i].name) ; - } - return result ; -} - -static Bool -ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) -{ - EphyrHostXVAdaptor *cur_host_adaptor=NULL ; - EphyrHostVideoFormat *video_formats=NULL ; - EphyrHostEncoding *encodings=NULL ; - EphyrHostAttribute *attributes=NULL ; - EphyrHostImageFormat *image_formats=NULL ; - int num_video_formats=0, base_port_id=0, - num_attributes=0, num_formats=0, i=0, - port_priv_offset=0; - unsigned num_encodings=0 ; - Bool is_ok = FALSE ; - - EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostXVQueryAdaptors (&a_this->host_adaptors)) { - EPHYR_LOG_ERROR ("failed to query host adaptors\n") ; - goto out ; - } - if (a_this->host_adaptors) - a_this->num_adaptors = - ephyrHostXVAdaptorArrayGetSize (a_this->host_adaptors) ; - if (a_this->num_adaptors < 0) { - EPHYR_LOG_ERROR ("failed to get number of host adaptors\n") ; - goto out ; - } - EPHYR_LOG ("host has %d adaptors\n", a_this->num_adaptors) ; - /* - * copy what we can from adaptors into a_this->adaptors - */ - if (a_this->num_adaptors) { - a_this->adaptors = xcalloc (a_this->num_adaptors, - sizeof (KdVideoAdaptorRec)) ; - if (!a_this->adaptors) { - EPHYR_LOG_ERROR ("failed to create internal adaptors\n") ; - goto out ; - } - } - for (i=0; i < a_this->num_adaptors; i++) { - int j=0 ; - cur_host_adaptor = - ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; - if (!cur_host_adaptor) - continue ; - a_this->adaptors[i].nPorts = - ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; - if (a_this->adaptors[i].nPorts <=0) { - EPHYR_LOG_ERROR ("Could not find any port of adaptor %d\n", i) ; - continue ; - } - a_this->adaptors[i].type = - ephyrHostXVAdaptorGetType (cur_host_adaptor) ; - a_this->adaptors[i].type |= XvWindowMask ; - a_this->adaptors[i].flags = - VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; - if (ephyrHostXVAdaptorGetName (cur_host_adaptor)) - a_this->adaptors[i].name = - strdup (ephyrHostXVAdaptorGetName (cur_host_adaptor)) ; - else - a_this->adaptors[i].name = strdup ("Xephyr Video Overlay"); - base_port_id = ephyrHostXVAdaptorGetFirstPortID (cur_host_adaptor) ; - if (base_port_id < 0) { - EPHYR_LOG_ERROR ("failed to get port id for adaptor %d\n", i) ; - continue ; - } - if (!s_base_port_id) - s_base_port_id = base_port_id ; - - if (!ephyrHostXVQueryEncodings (base_port_id, - &encodings, - &num_encodings)) { - EPHYR_LOG_ERROR ("failed to get encodings for port port id %d," - " adaptors %d\n", - base_port_id, i) ; - continue ; - } - a_this->adaptors[i].nEncodings = num_encodings ; - a_this->adaptors[i].pEncodings = - videoEncodingDup (encodings, num_encodings) ; - video_formats = (EphyrHostVideoFormat*) - ephyrHostXVAdaptorGetVideoFormats (cur_host_adaptor, - &num_video_formats); - a_this->adaptors[i].pFormats = (KdVideoFormatPtr) video_formats ; - a_this->adaptors[i].nFormats = num_video_formats ; - /* got a_this->adaptors[i].nPorts already - a_this->adaptors[i].nPorts = - ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; - */ - a_this->adaptors[i].pPortPrivates = - xcalloc (a_this->adaptors[i].nPorts, - sizeof (DevUnion) + sizeof (EphyrPortPriv)) ; - port_priv_offset = a_this->adaptors[i].nPorts; - for (j=0; j < a_this->adaptors[i].nPorts; j++) { - EphyrPortPriv *port_privs_base = - (EphyrPortPriv*)&a_this->adaptors[i].pPortPrivates[port_priv_offset]; - EphyrPortPriv *port_priv = &port_privs_base[j] ; - port_priv->port_number = base_port_id + j; - port_priv->current_adaptor = &a_this->adaptors[i] ; - port_priv->xv_priv = a_this ; - a_this->adaptors[i].pPortPrivates[j].ptr = port_priv; - } - if (!ephyrHostXVQueryPortAttributes (base_port_id, - &attributes, - &num_attributes)) { - EPHYR_LOG_ERROR ("failed to get port attribute " - "for adaptor %d\n", i) ; - continue ; - } - a_this->adaptors[i].pAttributes = - portAttributesDup (attributes, num_attributes); - a_this->adaptors[i].nAttributes = num_attributes ; - /*make sure atoms of attrs names are created in xephyr*/ - for (j=0; j < a_this->adaptors[i].nAttributes; j++) { - if (a_this->adaptors[i].pAttributes[j].name) - MakeAtom (a_this->adaptors[i].pAttributes[j].name, - strlen (a_this->adaptors[i].pAttributes[j].name), - TRUE) ; - } - if (!ephyrHostXVQueryImageFormats (base_port_id, - &image_formats, - &num_formats)) { - EPHYR_LOG_ERROR ("failed to get image formats " - "for adaptor %d\n", i) ; - continue ; - } - a_this->adaptors[i].pImages = (KdImagePtr) image_formats ; - a_this->adaptors[i].nImages = num_formats ; - } - is_ok = TRUE ; - -out: - if (encodings) { - ephyrHostEncodingsDelete (encodings, num_encodings) ; - encodings = NULL ; - } - if (attributes) { - ephyrHostAttributesDelete (attributes) ; - attributes = NULL ; - } - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -static Bool -ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) -{ - int i=0 ; - Bool has_it=FALSE ; - EphyrHostXVAdaptor *cur_host_adaptor=NULL ; - - EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - for (i=0; i < a_this->num_adaptors; i++) { - a_this->adaptors[i].ReputImage = ephyrReputImage ; - a_this->adaptors[i].StopVideo = ephyrStopVideo ; - a_this->adaptors[i].SetPortAttribute = ephyrSetPortAttribute ; - a_this->adaptors[i].GetPortAttribute = ephyrGetPortAttribute ; - a_this->adaptors[i].QueryBestSize = ephyrQueryBestSize ; - a_this->adaptors[i].QueryImageAttributes = ephyrQueryImageAttributes ; - - cur_host_adaptor = - ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; - if (!cur_host_adaptor) { - EPHYR_LOG_ERROR ("failed to get host adaptor at index %d\n", i) ; - continue ; - } - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasPutImage (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].PutImage = ephyrPutImage; - } - - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasPutVideo (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].PutVideo = ephyrPutVideo; - } - - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasGetVideo (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].GetVideo = ephyrGetVideo; - } - - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasPutStill (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].PutStill = ephyrPutStill; - } - - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasGetStill (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].GetStill = ephyrGetStill; - } - } - EPHYR_LOG ("leave\n") ; - return TRUE ; -} - -static Bool -ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, - ScreenPtr a_screen) -{ - KdScreenPriv(a_screen); - KdScreenInfo *screen = pScreenPriv->screen; - Bool is_ok = FALSE ; - KdVideoAdaptorPtr *adaptors=NULL, *registered_adaptors=NULL ; - int num_registered_adaptors=0, i=0, num_adaptors=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_screen, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - if (!a_this->num_adaptors) - goto out ; - num_registered_adaptors = - KdXVListGenericAdaptors (screen, ®istered_adaptors); - - num_adaptors = num_registered_adaptors + a_this->num_adaptors ; - adaptors = xcalloc (num_adaptors, sizeof (KdVideoAdaptorPtr)) ; - if (!adaptors) { - EPHYR_LOG_ERROR ("failed to allocate adaptors tab\n") ; - goto out ; - } - memmove (adaptors, registered_adaptors, num_registered_adaptors) ; - for (i=0 ; i < a_this->num_adaptors; i++) { - *(adaptors + num_registered_adaptors + i) = &a_this->adaptors[i] ; - } - if (!KdXVScreenInit (a_screen, adaptors, num_adaptors)) { - EPHYR_LOG_ERROR ("failed to register adaptors\n"); - goto out ; - } - EPHYR_LOG ("there are %d registered adaptors\n", num_adaptors) ; - is_ok = TRUE ; - -out: - xfree (registered_adaptors) ; - registered_adaptors = NULL ; - xfree (adaptors) ; - adaptors = NULL ; - - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -static Bool -ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, - int a_attrs_len, - const char *a_attr_name, - int a_attr_value, - Bool *a_is_valid) -{ - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_attrs && a_attr_name && a_is_valid, - FALSE) ; - - for (i=0; i < a_attrs_len; i++) { - if (a_attrs[i].name && strcmp (a_attrs[i].name, a_attr_name)) - continue ; - if (a_attrs[i].min_value > a_attr_value || - a_attrs[i].max_value < a_attr_value) { - *a_is_valid = FALSE ; - EPHYR_LOG_ERROR ("attribute was not valid\n" - "value:%d. min:%d. max:%d\n", - a_attr_value, - a_attrs[i].min_value, - a_attrs[i].max_value) ; - } else { - *a_is_valid = TRUE ; - } - return TRUE ; - } - return FALSE ; -} - -static Bool -ephyrXVPrivGetImageBufSize (int a_port_id, - int a_image_id, - unsigned short a_width, - unsigned short a_height, - int *a_size) -{ - Bool is_ok=FALSE ; - unsigned short width=a_width, height=a_height ; - - EPHYR_RETURN_VAL_IF_FAIL (a_size, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostXVQueryImageAttributes (a_port_id, a_image_id, - &width, &height, a_size, NULL, NULL)) { - EPHYR_LOG_ERROR ("failed to get image attributes\n") ; - goto out ; - } - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -static Bool -ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, - const unsigned char *a_image_buf, - int a_image_len) -{ - Bool is_ok=FALSE ; - - EPHYR_LOG ("enter\n") ; - - if (a_port_priv->image_buf_size < a_image_len) { - unsigned char *buf=NULL ; - buf = realloc (a_port_priv->image_buf, a_image_len) ; - if (!buf) { - EPHYR_LOG_ERROR ("failed to realloc image buffer\n") ; - goto out ; - } - a_port_priv->image_buf = buf ; - a_port_priv->image_buf_size = a_image_len; - } - memmove (a_port_priv->image_buf, a_image_buf, a_image_len) ; - is_ok = TRUE ; - -out: - return is_ok ; - EPHYR_LOG ("leave\n") ; -} - -static void -ephyrStopVideo (KdScreenInfo *a_info, pointer a_port_priv, Bool a_exit) -{ - EphyrPortPriv *port_priv = a_port_priv ; - - EPHYR_RETURN_IF_FAIL (a_info && a_info->pScreen) ; - EPHYR_RETURN_IF_FAIL (port_priv) ; - - EPHYR_LOG ("enter\n") ; - if (!ephyrHostXVStopVideo (a_info->pScreen->myNum, - port_priv->port_number)) { - EPHYR_LOG_ERROR ("XvStopVideo() failed\n") ; - } - EPHYR_LOG ("leave\n") ; -} - -static int -ephyrSetPortAttribute (KdScreenInfo *a_info, - Atom a_attr_name, - int a_attr_value, - pointer a_port_priv) -{ - int res=Success, host_atom=0 ; - EphyrPortPriv *port_priv = a_port_priv ; - Bool is_attr_valid=FALSE ; - - EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor, BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->pAttributes, - BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->nAttributes, - BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; - - EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s, attr_val:%d\n", - port_priv->port_number, - (int)a_attr_name, - NameForAtom (a_attr_name), - a_attr_value) ; - - if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { - EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; - res = BadMatch ; - goto out ; - } - - if (!ephyrXVPrivIsAttrValueValid (port_priv->current_adaptor->pAttributes, - port_priv->current_adaptor->nAttributes, - NameForAtom (a_attr_name), - a_attr_value, - &is_attr_valid)) { - EPHYR_LOG_ERROR ("failed to validate attribute %s\n", - NameForAtom (a_attr_name)) ; - /* - res = BadMatch ; - goto out ; - */ - } - if (!is_attr_valid) { - EPHYR_LOG_ERROR ("attribute %s is not valid\n", - NameForAtom (a_attr_name)) ; - /* - res = BadMatch ; - goto out ; - */ - } - - if (!ephyrHostXVSetPortAttribute (port_priv->port_number, - host_atom, - a_attr_value)) { - EPHYR_LOG_ERROR ("failed to set port attribute\n") ; - res = BadMatch ; - goto out ; - } - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -static int -ephyrGetPortAttribute (KdScreenInfo *a_screen_info, - Atom a_attr_name, - int *a_attr_value, - pointer a_port_priv) -{ - int res=Success, host_atom=0 ; - EphyrPortPriv *port_priv = a_port_priv ; - - EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; - - EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s\n", - port_priv->port_number, - (int)a_attr_name, - NameForAtom (a_attr_name)) ; - - if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { - EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; - res = BadMatch ; - goto out ; - } - - if (!ephyrHostXVGetPortAttribute (port_priv->port_number, - host_atom, - a_attr_value)) { - EPHYR_LOG_ERROR ("failed to get port attribute\n") ; - res = BadMatch ; - goto out ; - } - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -static void -ephyrQueryBestSize (KdScreenInfo *a_info, - Bool a_motion, - short a_src_w, - short a_src_h, - short a_drw_w, - short a_drw_h, - unsigned int *a_prefered_w, - unsigned int *a_prefered_h, - pointer a_port_priv) -{ - int res=0 ; - EphyrPortPriv *port_priv = a_port_priv ; - - EPHYR_RETURN_IF_FAIL (port_priv) ; - - EPHYR_LOG ("enter\n") ; - res = ephyrHostXVQueryBestSize (port_priv->port_number, - a_motion, - a_src_w, a_src_h, - a_drw_w, a_drw_h, - a_prefered_w, a_prefered_h) ; - if (!res) { - EPHYR_LOG_ERROR ("Failed to query best size\n") ; - } - EPHYR_LOG ("leave\n") ; -} - -static int -ephyrPutImage (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_src_x, - short a_src_y, - short a_drw_x, - short a_drw_y, - short a_src_w, - short a_src_h, - short a_drw_w, - short a_drw_h, - int a_id, - unsigned char *a_buf, - short a_width, - short a_height, - Bool a_sync, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - Bool is_ok=FALSE ; - int result=BadImplementation, image_size=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostXVPutImage (a_info->pScreen->myNum, - port_priv->port_number, - a_id, - a_drw_x, a_drw_y, a_drw_w, a_drw_h, - a_src_x, a_src_y, a_src_w, a_src_h, - a_width, a_height, a_buf, - (EphyrHostBox*)REGION_RECTS (a_clipping_region), - REGION_NUM_RECTS (a_clipping_region))) { - EPHYR_LOG_ERROR ("EphyrHostXVPutImage() failed\n") ; - goto out ; - } - - /* - * Now save the image so that we can resend it to host it - * later, in ReputImage. - */ - if (!ephyrXVPrivGetImageBufSize (port_priv->port_number, - a_id, a_width, a_height, &image_size)) { - EPHYR_LOG_ERROR ("failed to get image size\n") ; - /*this is a minor error so we won't get bail out abruptly*/ - is_ok = FALSE ; - } else { - is_ok = TRUE ; - } - if (is_ok) { - if (!ephyrXVPrivSaveImageToPortPriv (port_priv, a_buf, image_size)) { - is_ok=FALSE ; - } else { - port_priv->image_id = a_id; - port_priv->drw_x = a_drw_x; - port_priv->drw_y = a_drw_y; - port_priv->drw_w = a_drw_w ; - port_priv->drw_h = a_drw_h ; - port_priv->src_x = a_src_x; - port_priv->src_y = a_src_y ; - port_priv->src_w = a_src_w ; - port_priv->src_h = a_src_h ; - port_priv->image_width = a_width ; - port_priv->image_height = a_height ; - } - } - if (!is_ok) { - if (port_priv->image_buf) { - free (port_priv->image_buf) ; - port_priv->image_buf = NULL ; - port_priv->image_buf_size = 0 ; - } - } - - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrReputImage (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_drw_x, - short a_drw_y, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - int result=BadImplementation ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, FALSE) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - if (!port_priv->image_buf_size || !port_priv->image_buf) { - EPHYR_LOG_ERROR ("has null image buf in cache\n") ; - goto out ; - } - if (!ephyrHostXVPutImage (a_info->pScreen->myNum, - port_priv->port_number, - port_priv->image_id, - a_drw_x, a_drw_y, - port_priv->drw_w, port_priv->drw_h, - port_priv->src_x, port_priv->src_y, - port_priv->src_w, port_priv->src_h, - port_priv->image_width, port_priv->image_height, - port_priv->image_buf, - (EphyrHostBox*)REGION_RECTS (a_clipping_region), - REGION_NUM_RECTS (a_clipping_region))) { - EPHYR_LOG_ERROR ("ephyrHostXVPutImage() failed\n") ; - goto out ; - } - - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrPutVideo (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - BoxRec clipped_area, dst_box ; - int result=BadImplementation ; - int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - dst_box.x1 = a_drw_x ; - dst_box.x2 = a_drw_x + a_drw_w; - dst_box.y1 = a_drw_y ; - dst_box.y2 = a_drw_y + a_drw_h; - - if (!DoSimpleClip (&dst_box, - REGION_EXTENTS (pScreen->pScreen, a_clipping_region), - &clipped_area)) { - EPHYR_LOG_ERROR ("failed to simple clip\n") ; - goto out ; - } - - drw_x = clipped_area.x1 ; - drw_y = clipped_area.y1 ; - drw_w = clipped_area.x2 - clipped_area.x1 ; - drw_h = clipped_area.y2 - clipped_area.y1 ; - - if (!ephyrHostXVPutVideo (a_info->pScreen->myNum, - port_priv->port_number, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { - EPHYR_LOG_ERROR ("ephyrHostXVPutVideo() failed\n") ; - goto out ; - } - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrGetVideo (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - BoxRec clipped_area, dst_box ; - int result=BadImplementation ; - int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - dst_box.x1 = a_drw_x ; - dst_box.x2 = a_drw_x + a_drw_w; - dst_box.y1 = a_drw_y ; - dst_box.y2 = a_drw_y + a_drw_h; - - if (!DoSimpleClip (&dst_box, - REGION_EXTENTS (pScreen->pScreen, a_clipping_region), - &clipped_area)) { - EPHYR_LOG_ERROR ("failed to simple clip\n") ; - goto out ; - } - - drw_x = clipped_area.x1 ; - drw_y = clipped_area.y1 ; - drw_w = clipped_area.x2 - clipped_area.x1 ; - drw_h = clipped_area.y2 - clipped_area.y1 ; - - if (!ephyrHostXVGetVideo (a_info->pScreen->myNum, - port_priv->port_number, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { - EPHYR_LOG_ERROR ("ephyrHostXVGetVideo() failed\n") ; - goto out ; - } - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrPutStill (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - BoxRec clipped_area, dst_box ; - int result=BadImplementation ; - int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - dst_box.x1 = a_drw_x ; - dst_box.x2 = a_drw_x + a_drw_w; - dst_box.y1 = a_drw_y ; - dst_box.y2 = a_drw_y + a_drw_h; - - if (!DoSimpleClip (&dst_box, - REGION_EXTENTS (pScreen->pScreen, a_clipping_region), - &clipped_area)) { - EPHYR_LOG_ERROR ("failed to simple clip\n") ; - goto out ; - } - - drw_x = clipped_area.x1 ; - drw_y = clipped_area.y1 ; - drw_w = clipped_area.x2 - clipped_area.x1 ; - drw_h = clipped_area.y2 - clipped_area.y1 ; - - if (!ephyrHostXVPutStill (a_info->pScreen->myNum, - port_priv->port_number, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { - EPHYR_LOG_ERROR ("ephyrHostXVPutStill() failed\n") ; - goto out ; - } - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrGetStill (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - BoxRec clipped_area, dst_box ; - int result=BadImplementation ; - int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - dst_box.x1 = a_drw_x ; - dst_box.x2 = a_drw_x + a_drw_w; - dst_box.y1 = a_drw_y ; - dst_box.y2 = a_drw_y + a_drw_h; - - if (!DoSimpleClip (&dst_box, - REGION_EXTENTS (pScreen->pScreen, a_clipping_region), - &clipped_area)) { - EPHYR_LOG_ERROR ("failed to simple clip\n") ; - goto out ; - } - - drw_x = clipped_area.x1 ; - drw_y = clipped_area.y1 ; - drw_w = clipped_area.x2 - clipped_area.x1 ; - drw_h = clipped_area.y2 - clipped_area.y1 ; - - if (!ephyrHostXVGetStill (a_info->pScreen->myNum, - port_priv->port_number, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { - EPHYR_LOG_ERROR ("ephyrHostXVGetStill() failed\n") ; - goto out ; - } - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrQueryImageAttributes (KdScreenInfo *a_info, - int a_id, - unsigned short *a_w, - unsigned short *a_h, - int *a_pitches, - int *a_offsets) -{ - int image_size=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_w && a_h, FALSE) ; - - EPHYR_LOG ("enter: dim (%dx%d), pitches: %p, offsets: %p\n", - *a_w, *a_h, a_pitches, a_offsets) ; - - if (!ephyrHostXVQueryImageAttributes (s_base_port_id, - a_id, - a_w, a_h, - &image_size, - a_pitches, a_offsets)) { - EPHYR_LOG_ERROR ("EphyrHostXVQueryImageAttributes() failed\n") ; - goto out ; - } - EPHYR_LOG ("image size: %d, dim (%dx%d)\n", image_size, *a_w, *a_h) ; - -out: - EPHYR_LOG ("leave\n") ; - return image_size ; -} +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum <mallum@openedhand.com> + * + * Copyright © 2007 OpenedHand Ltd + * + * 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 OpenedHand Ltd not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. OpenedHand Ltd makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OpenedHand Ltd 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. + * + * Authors: + * Dodji Seketeli <dodji@openedhand.com> + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif +#include <string.h> +#include <X11/extensions/Xv.h> +#include "ephyrlog.h" +#include "kdrive.h" +#include "kxv.h" +#include "ephyr.h" +#include "hostx.h" +#include "ephyrhostvideo.h" + +struct _EphyrXVPriv { + EphyrHostXVAdaptorArray *host_adaptors ; + KdVideoAdaptorPtr adaptors ; + int num_adaptors ; +}; +typedef struct _EphyrXVPriv EphyrXVPriv ; + +struct _EphyrPortPriv { + int port_number ; + KdVideoAdaptorPtr current_adaptor ; + EphyrXVPriv *xv_priv; + unsigned char *image_buf ; + int image_buf_size ; + int image_id ; + int drw_x, drw_y, drw_w, drw_h ; + int src_x, src_y, src_w, src_h ; + int image_width, image_height ; +}; +typedef struct _EphyrPortPriv EphyrPortPriv ; + +static Bool DoSimpleClip (BoxPtr a_dst_drw, + BoxPtr a_clipper, + BoxPtr a_result) ; + +static Bool ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) ; + +/* +static Bool ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) ; +*/ + +static EphyrXVPriv* ephyrXVPrivNew (void) ; +static void ephyrXVPrivDelete (EphyrXVPriv *a_this) ; +static Bool ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) ; +static Bool ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) ; +static Bool ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, + ScreenPtr a_screen) ; + +static Bool ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, + int a_attrs_len, + const char *a_attr_name, + int a_attr_value, + Bool *a_is_valid) ; + +static Bool ephyrXVPrivGetImageBufSize (int a_port_id, + int a_image_id, + unsigned short a_width, + unsigned short a_height, + int *a_size) ; + +static Bool ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, + const unsigned char *a_image, + int a_image_len) ; + +static void ephyrStopVideo (KdScreenInfo *a_info, + pointer a_xv_priv, + Bool a_exit); + +static int ephyrSetPortAttribute (KdScreenInfo *a_info, + Atom a_attr_name, + int a_attr_value, + pointer a_port_priv); + +static int ephyrGetPortAttribute (KdScreenInfo *a_screen_info, + Atom a_attr_name, + int *a_attr_value, + pointer a_port_priv); + +static void ephyrQueryBestSize (KdScreenInfo *a_info, + Bool a_motion, + short a_src_w, + short a_src_h, + short a_drw_w, + short a_drw_h, + unsigned int *a_prefered_w, + unsigned int *a_prefered_h, + pointer a_port_priv); + +static int ephyrPutImage (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_src_x, + short a_src_y, + short a_drw_x, + short a_drw_y, + short a_src_w, + short a_src_h, + short a_drw_w, + short a_drw_h, + int a_id, + unsigned char *a_buf, + short a_width, + short a_height, + Bool a_sync, + RegionPtr a_clipping_region, + pointer a_port_priv); + +static int ephyrReputImage (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_drw_x, + short a_drw_y, + RegionPtr a_clipping_region, + pointer a_port_priv) ; + +static int ephyrPutVideo (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clip_region, + pointer a_port_priv) ; + +static int ephyrGetVideo (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clip_region, + pointer a_port_priv) ; + +static int ephyrPutStill (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clip_region, + pointer a_port_priv) ; + +static int ephyrGetStill (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clip_region, + pointer a_port_priv) ; + +static int ephyrQueryImageAttributes (KdScreenInfo *a_info, + int a_id, + unsigned short *a_w, + unsigned short *a_h, + int *a_pitches, + int *a_offsets); +static int s_base_port_id ; + +/************** + * <helpers> + * ************/ + +static Bool +DoSimpleClip (BoxPtr a_dst_box, + BoxPtr a_clipper, + BoxPtr a_result) +{ + BoxRec dstClippedBox ; + + EPHYR_RETURN_VAL_IF_FAIL (a_dst_box && a_clipper && a_result, FALSE) ; + + /* + * setup the clipbox inside the destination. + */ + dstClippedBox.x1 = a_dst_box->x1 ; + dstClippedBox.x2 = a_dst_box->x2 ; + dstClippedBox.y1 = a_dst_box->y1 ; + dstClippedBox.y2 = a_dst_box->y2 ; + + /* + * if the cliper leftmost edge is inside + * the destination area then the leftmost edge of the resulting + * clipped box is the leftmost edge of the cliper. + */ + if (a_clipper->x1 > dstClippedBox.x1) + dstClippedBox.x1 = a_clipper->x1 ; + + /* + * if the cliper top edge is inside the destination area + * then the bottom horizontal edge of the resulting clipped box + * is the bottom edge of the cliper + */ + if (a_clipper->y1 > dstClippedBox.y1) + dstClippedBox.y1 = a_clipper->y1 ; + + /*ditto for right edge*/ + if (a_clipper->x2 < dstClippedBox.x2) + dstClippedBox.x2 = a_clipper->x2 ; + + /*ditto for bottom edge*/ + if (a_clipper->y2 < dstClippedBox.y2) + dstClippedBox.y2 = a_clipper->y2 ; + + memcpy (a_result, &dstClippedBox, sizeof (dstClippedBox)) ; + return TRUE ; +} + +static Bool +ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) +{ + const char *atom_name=NULL; + int host_atom=None ; + + EPHYR_RETURN_VAL_IF_FAIL (a_host_atom, FALSE) ; + + if (!ValidAtom (a_local_atom)) + return FALSE ; + + atom_name = NameForAtom (a_local_atom) ; + + if (!atom_name) + return FALSE ; + + if (!ephyrHostGetAtom (atom_name, FALSE, &host_atom) || host_atom == None) { + EPHYR_LOG_ERROR ("no atom for string %s defined in host X\n", + atom_name) ; + return FALSE ; + } + *a_host_atom = host_atom ; + return TRUE ; +} + +/* + Not used yed. +static Bool +ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) +{ + Bool is_ok=FALSE ; + char *atom_name=NULL ; + int atom=None ; + + EPHYR_RETURN_VAL_IF_FAIL (a_local_atom, FALSE) ; + + atom_name = ephyrHostGetAtomName (a_host_atom) ; + if (!atom_name) + goto out ; + + atom = MakeAtom (atom_name, strlen (atom_name), TRUE) ; + if (atom == None) + goto out ; + + *a_local_atom = atom ; + is_ok = TRUE ; + +out: + if (atom_name) { + ephyrHostFree (atom_name) ; + } + return is_ok ; +} +*/ + +/************** + *</helpers> + * ************/ + +Bool +ephyrInitVideo (ScreenPtr pScreen) +{ + Bool is_ok = FALSE ; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + static EphyrXVPriv *xv_priv; + + EPHYR_LOG ("enter\n") ; + + if (screen->fb.bitsPerPixel == 8) { + EPHYR_LOG_ERROR ("8 bits depth not supported\n") ; + return FALSE ; + } + + if (!xv_priv) { + xv_priv = ephyrXVPrivNew () ; + } + if (!xv_priv) { + EPHYR_LOG_ERROR ("failed to create xv_priv\n") ; + goto out ; + } + + if (!ephyrXVPrivRegisterAdaptors (xv_priv, pScreen)) { + EPHYR_LOG_ERROR ("failed to register adaptors\n") ; + goto out ; + } + is_ok = TRUE ; + +out: + return is_ok ; +} + +static EphyrXVPriv* +ephyrXVPrivNew (void) +{ + EphyrXVPriv *xv_priv=NULL ; + + EPHYR_LOG ("enter\n") ; + + xv_priv = calloc(1, sizeof (EphyrXVPriv)) ; + if (!xv_priv) { + EPHYR_LOG_ERROR ("failed to create EphyrXVPriv\n") ; + goto error ; + } + + ephyrHostXVInit () ; + + if (!ephyrXVPrivQueryHostAdaptors (xv_priv)) { + EPHYR_LOG_ERROR ("failed to query the host x for xv properties\n") ; + goto error ; + } + if (!ephyrXVPrivSetAdaptorsHooks (xv_priv)) { + EPHYR_LOG_ERROR ("failed to set xv_priv hooks\n") ; + goto error ; + } + + EPHYR_LOG ("leave\n") ; + return xv_priv ; + +error: + if (xv_priv) { + ephyrXVPrivDelete (xv_priv) ; + xv_priv = NULL ; + } + return NULL ; +} + +static void +ephyrXVPrivDelete (EphyrXVPriv *a_this) +{ + EPHYR_LOG ("enter\n") ; + + if (!a_this) + return ; + if (a_this->host_adaptors) { + ephyrHostXVAdaptorArrayDelete (a_this->host_adaptors) ; + a_this->host_adaptors = NULL ; + } + free(a_this->adaptors) ; + a_this->adaptors = NULL ; + free(a_this) ; + EPHYR_LOG ("leave\n") ; +} + +static KdVideoEncodingPtr +videoEncodingDup (EphyrHostEncoding *a_encodings, + int a_num_encodings) +{ + KdVideoEncodingPtr result = NULL ; + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; + + result = calloc(a_num_encodings, sizeof (KdVideoEncodingRec)) ; + for (i=0 ; i < a_num_encodings; i++) { + result[i].id = a_encodings[i].id ; + result[i].name = strdup (a_encodings[i].name) ; + result[i].width = a_encodings[i].width ; + result[i].height = a_encodings[i].height ; + result[i].rate.numerator = a_encodings[i].rate.numerator ; + result[i].rate.denominator = a_encodings[i].rate.denominator ; + } + return result ; +} + +static KdAttributePtr +portAttributesDup (EphyrHostAttribute *a_encodings, + int a_num_encodings) +{ + int i=0 ; + KdAttributePtr result=NULL ; + + EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; + + result = calloc(a_num_encodings, sizeof (KdAttributeRec)) ; + if (!result) { + EPHYR_LOG_ERROR ("failed to allocate attributes\n") ; + return NULL ; + } + for (i=0; i < a_num_encodings; i++) { + result[i].flags = a_encodings[i].flags ; + result[i].min_value = a_encodings[i].min_value ; + result[i].max_value = a_encodings[i].max_value ; + result[i].name = strdup (a_encodings[i].name) ; + } + return result ; +} + +static Bool +ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) +{ + EphyrHostXVAdaptor *cur_host_adaptor=NULL ; + EphyrHostVideoFormat *video_formats=NULL ; + EphyrHostEncoding *encodings=NULL ; + EphyrHostAttribute *attributes=NULL ; + EphyrHostImageFormat *image_formats=NULL ; + int num_video_formats=0, base_port_id=0, + num_attributes=0, num_formats=0, i=0, + port_priv_offset=0; + unsigned num_encodings=0 ; + Bool is_ok = FALSE ; + + EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostXVQueryAdaptors (&a_this->host_adaptors)) { + EPHYR_LOG_ERROR ("failed to query host adaptors\n") ; + goto out ; + } + if (a_this->host_adaptors) + a_this->num_adaptors = + ephyrHostXVAdaptorArrayGetSize (a_this->host_adaptors) ; + if (a_this->num_adaptors < 0) { + EPHYR_LOG_ERROR ("failed to get number of host adaptors\n") ; + goto out ; + } + EPHYR_LOG ("host has %d adaptors\n", a_this->num_adaptors) ; + /* + * copy what we can from adaptors into a_this->adaptors + */ + if (a_this->num_adaptors) { + a_this->adaptors = calloc(a_this->num_adaptors, + sizeof (KdVideoAdaptorRec)) ; + if (!a_this->adaptors) { + EPHYR_LOG_ERROR ("failed to create internal adaptors\n") ; + goto out ; + } + } + for (i=0; i < a_this->num_adaptors; i++) { + int j=0 ; + cur_host_adaptor = + ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; + if (!cur_host_adaptor) + continue ; + a_this->adaptors[i].nPorts = + ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; + if (a_this->adaptors[i].nPorts <=0) { + EPHYR_LOG_ERROR ("Could not find any port of adaptor %d\n", i) ; + continue ; + } + a_this->adaptors[i].type = + ephyrHostXVAdaptorGetType (cur_host_adaptor) ; + a_this->adaptors[i].type |= XvWindowMask ; + a_this->adaptors[i].flags = + VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + if (ephyrHostXVAdaptorGetName (cur_host_adaptor)) + a_this->adaptors[i].name = + strdup (ephyrHostXVAdaptorGetName (cur_host_adaptor)) ; + else + a_this->adaptors[i].name = strdup ("Xephyr Video Overlay"); + base_port_id = ephyrHostXVAdaptorGetFirstPortID (cur_host_adaptor) ; + if (base_port_id < 0) { + EPHYR_LOG_ERROR ("failed to get port id for adaptor %d\n", i) ; + continue ; + } + if (!s_base_port_id) + s_base_port_id = base_port_id ; + + if (!ephyrHostXVQueryEncodings (base_port_id, + &encodings, + &num_encodings)) { + EPHYR_LOG_ERROR ("failed to get encodings for port port id %d," + " adaptors %d\n", + base_port_id, i) ; + continue ; + } + a_this->adaptors[i].nEncodings = num_encodings ; + a_this->adaptors[i].pEncodings = + videoEncodingDup (encodings, num_encodings) ; + video_formats = (EphyrHostVideoFormat*) + ephyrHostXVAdaptorGetVideoFormats (cur_host_adaptor, + &num_video_formats); + a_this->adaptors[i].pFormats = (KdVideoFormatPtr) video_formats ; + a_this->adaptors[i].nFormats = num_video_formats ; + /* got a_this->adaptors[i].nPorts already + a_this->adaptors[i].nPorts = + ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; + */ + a_this->adaptors[i].pPortPrivates = + calloc(a_this->adaptors[i].nPorts, + sizeof (DevUnion) + sizeof (EphyrPortPriv)) ; + port_priv_offset = a_this->adaptors[i].nPorts; + for (j=0; j < a_this->adaptors[i].nPorts; j++) { + EphyrPortPriv *port_privs_base = + (EphyrPortPriv*)&a_this->adaptors[i].pPortPrivates[port_priv_offset]; + EphyrPortPriv *port_priv = &port_privs_base[j] ; + port_priv->port_number = base_port_id + j; + port_priv->current_adaptor = &a_this->adaptors[i] ; + port_priv->xv_priv = a_this ; + a_this->adaptors[i].pPortPrivates[j].ptr = port_priv; + } + if (!ephyrHostXVQueryPortAttributes (base_port_id, + &attributes, + &num_attributes)) { + EPHYR_LOG_ERROR ("failed to get port attribute " + "for adaptor %d\n", i) ; + continue ; + } + a_this->adaptors[i].pAttributes = + portAttributesDup (attributes, num_attributes); + a_this->adaptors[i].nAttributes = num_attributes ; + /*make sure atoms of attrs names are created in xephyr*/ + for (j=0; j < a_this->adaptors[i].nAttributes; j++) { + if (a_this->adaptors[i].pAttributes[j].name) + MakeAtom (a_this->adaptors[i].pAttributes[j].name, + strlen (a_this->adaptors[i].pAttributes[j].name), + TRUE) ; + } + if (!ephyrHostXVQueryImageFormats (base_port_id, + &image_formats, + &num_formats)) { + EPHYR_LOG_ERROR ("failed to get image formats " + "for adaptor %d\n", i) ; + continue ; + } + a_this->adaptors[i].pImages = (KdImagePtr) image_formats ; + a_this->adaptors[i].nImages = num_formats ; + } + is_ok = TRUE ; + +out: + if (encodings) { + ephyrHostEncodingsDelete (encodings, num_encodings) ; + encodings = NULL ; + } + if (attributes) { + ephyrHostAttributesDelete (attributes) ; + attributes = NULL ; + } + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +static Bool +ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) +{ + int i=0 ; + Bool has_it=FALSE ; + EphyrHostXVAdaptor *cur_host_adaptor=NULL ; + + EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + for (i=0; i < a_this->num_adaptors; i++) { + a_this->adaptors[i].ReputImage = ephyrReputImage ; + a_this->adaptors[i].StopVideo = ephyrStopVideo ; + a_this->adaptors[i].SetPortAttribute = ephyrSetPortAttribute ; + a_this->adaptors[i].GetPortAttribute = ephyrGetPortAttribute ; + a_this->adaptors[i].QueryBestSize = ephyrQueryBestSize ; + a_this->adaptors[i].QueryImageAttributes = ephyrQueryImageAttributes ; + + cur_host_adaptor = + ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; + if (!cur_host_adaptor) { + EPHYR_LOG_ERROR ("failed to get host adaptor at index %d\n", i) ; + continue ; + } + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasPutImage (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].PutImage = ephyrPutImage; + } + + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasPutVideo (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].PutVideo = ephyrPutVideo; + } + + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasGetVideo (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].GetVideo = ephyrGetVideo; + } + + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasPutStill (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].PutStill = ephyrPutStill; + } + + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasGetStill (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].GetStill = ephyrGetStill; + } + } + EPHYR_LOG ("leave\n") ; + return TRUE ; +} + +static Bool +ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, + ScreenPtr a_screen) +{ + KdScreenPriv(a_screen); + KdScreenInfo *screen = pScreenPriv->screen; + Bool is_ok = FALSE ; + KdVideoAdaptorPtr *adaptors=NULL, *registered_adaptors=NULL ; + int num_registered_adaptors=0, i=0, num_adaptors=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_screen, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + if (!a_this->num_adaptors) + goto out ; + num_registered_adaptors = + KdXVListGenericAdaptors (screen, ®istered_adaptors); + + num_adaptors = num_registered_adaptors + a_this->num_adaptors ; + adaptors = calloc(num_adaptors, sizeof (KdVideoAdaptorPtr)) ; + if (!adaptors) { + EPHYR_LOG_ERROR ("failed to allocate adaptors tab\n") ; + goto out ; + } + memmove (adaptors, registered_adaptors, num_registered_adaptors) ; + for (i=0 ; i < a_this->num_adaptors; i++) { + *(adaptors + num_registered_adaptors + i) = &a_this->adaptors[i] ; + } + if (!KdXVScreenInit (a_screen, adaptors, num_adaptors)) { + EPHYR_LOG_ERROR ("failed to register adaptors\n"); + goto out ; + } + EPHYR_LOG ("there are %d registered adaptors\n", num_adaptors) ; + is_ok = TRUE ; + +out: + free(registered_adaptors) ; + registered_adaptors = NULL ; + free(adaptors) ; + adaptors = NULL ; + + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +static Bool +ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, + int a_attrs_len, + const char *a_attr_name, + int a_attr_value, + Bool *a_is_valid) +{ + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_attrs && a_attr_name && a_is_valid, + FALSE) ; + + for (i=0; i < a_attrs_len; i++) { + if (a_attrs[i].name && strcmp (a_attrs[i].name, a_attr_name)) + continue ; + if (a_attrs[i].min_value > a_attr_value || + a_attrs[i].max_value < a_attr_value) { + *a_is_valid = FALSE ; + EPHYR_LOG_ERROR ("attribute was not valid\n" + "value:%d. min:%d. max:%d\n", + a_attr_value, + a_attrs[i].min_value, + a_attrs[i].max_value) ; + } else { + *a_is_valid = TRUE ; + } + return TRUE ; + } + return FALSE ; +} + +static Bool +ephyrXVPrivGetImageBufSize (int a_port_id, + int a_image_id, + unsigned short a_width, + unsigned short a_height, + int *a_size) +{ + Bool is_ok=FALSE ; + unsigned short width=a_width, height=a_height ; + + EPHYR_RETURN_VAL_IF_FAIL (a_size, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostXVQueryImageAttributes (a_port_id, a_image_id, + &width, &height, a_size, NULL, NULL)) { + EPHYR_LOG_ERROR ("failed to get image attributes\n") ; + goto out ; + } + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +static Bool +ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, + const unsigned char *a_image_buf, + int a_image_len) +{ + Bool is_ok=FALSE ; + + EPHYR_LOG ("enter\n") ; + + if (a_port_priv->image_buf_size < a_image_len) { + unsigned char *buf=NULL ; + buf = realloc (a_port_priv->image_buf, a_image_len) ; + if (!buf) { + EPHYR_LOG_ERROR ("failed to realloc image buffer\n") ; + goto out ; + } + a_port_priv->image_buf = buf ; + a_port_priv->image_buf_size = a_image_len; + } + memmove (a_port_priv->image_buf, a_image_buf, a_image_len) ; + is_ok = TRUE ; + +out: + return is_ok ; + EPHYR_LOG ("leave\n") ; +} + +static void +ephyrStopVideo (KdScreenInfo *a_info, pointer a_port_priv, Bool a_exit) +{ + EphyrPortPriv *port_priv = a_port_priv ; + + EPHYR_RETURN_IF_FAIL (a_info && a_info->pScreen) ; + EPHYR_RETURN_IF_FAIL (port_priv) ; + + EPHYR_LOG ("enter\n") ; + if (!ephyrHostXVStopVideo (a_info->pScreen->myNum, + port_priv->port_number)) { + EPHYR_LOG_ERROR ("XvStopVideo() failed\n") ; + } + EPHYR_LOG ("leave\n") ; +} + +static int +ephyrSetPortAttribute (KdScreenInfo *a_info, + Atom a_attr_name, + int a_attr_value, + pointer a_port_priv) +{ + int res=Success, host_atom=0 ; + EphyrPortPriv *port_priv = a_port_priv ; + Bool is_attr_valid=FALSE ; + + EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor, BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->pAttributes, + BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->nAttributes, + BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; + + EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s, attr_val:%d\n", + port_priv->port_number, + (int)a_attr_name, + NameForAtom (a_attr_name), + a_attr_value) ; + + if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { + EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; + res = BadMatch ; + goto out ; + } + + if (!ephyrXVPrivIsAttrValueValid (port_priv->current_adaptor->pAttributes, + port_priv->current_adaptor->nAttributes, + NameForAtom (a_attr_name), + a_attr_value, + &is_attr_valid)) { + EPHYR_LOG_ERROR ("failed to validate attribute %s\n", + NameForAtom (a_attr_name)) ; + /* + res = BadMatch ; + goto out ; + */ + } + if (!is_attr_valid) { + EPHYR_LOG_ERROR ("attribute %s is not valid\n", + NameForAtom (a_attr_name)) ; + /* + res = BadMatch ; + goto out ; + */ + } + + if (!ephyrHostXVSetPortAttribute (port_priv->port_number, + host_atom, + a_attr_value)) { + EPHYR_LOG_ERROR ("failed to set port attribute\n") ; + res = BadMatch ; + goto out ; + } + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +static int +ephyrGetPortAttribute (KdScreenInfo *a_screen_info, + Atom a_attr_name, + int *a_attr_value, + pointer a_port_priv) +{ + int res=Success, host_atom=0 ; + EphyrPortPriv *port_priv = a_port_priv ; + + EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; + + EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s\n", + port_priv->port_number, + (int)a_attr_name, + NameForAtom (a_attr_name)) ; + + if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { + EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; + res = BadMatch ; + goto out ; + } + + if (!ephyrHostXVGetPortAttribute (port_priv->port_number, + host_atom, + a_attr_value)) { + EPHYR_LOG_ERROR ("failed to get port attribute\n") ; + res = BadMatch ; + goto out ; + } + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +static void +ephyrQueryBestSize (KdScreenInfo *a_info, + Bool a_motion, + short a_src_w, + short a_src_h, + short a_drw_w, + short a_drw_h, + unsigned int *a_prefered_w, + unsigned int *a_prefered_h, + pointer a_port_priv) +{ + int res=0 ; + EphyrPortPriv *port_priv = a_port_priv ; + + EPHYR_RETURN_IF_FAIL (port_priv) ; + + EPHYR_LOG ("enter\n") ; + res = ephyrHostXVQueryBestSize (port_priv->port_number, + a_motion, + a_src_w, a_src_h, + a_drw_w, a_drw_h, + a_prefered_w, a_prefered_h) ; + if (!res) { + EPHYR_LOG_ERROR ("Failed to query best size\n") ; + } + EPHYR_LOG ("leave\n") ; +} + +static int +ephyrPutImage (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_src_x, + short a_src_y, + short a_drw_x, + short a_drw_y, + short a_src_w, + short a_src_h, + short a_drw_w, + short a_drw_h, + int a_id, + unsigned char *a_buf, + short a_width, + short a_height, + Bool a_sync, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + Bool is_ok=FALSE ; + int result=BadImplementation, image_size=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostXVPutImage (a_info->pScreen->myNum, + port_priv->port_number, + a_id, + a_drw_x, a_drw_y, a_drw_w, a_drw_h, + a_src_x, a_src_y, a_src_w, a_src_h, + a_width, a_height, a_buf, + (EphyrHostBox*)REGION_RECTS (a_clipping_region), + REGION_NUM_RECTS (a_clipping_region))) { + EPHYR_LOG_ERROR ("EphyrHostXVPutImage() failed\n") ; + goto out ; + } + + /* + * Now save the image so that we can resend it to host it + * later, in ReputImage. + */ + if (!ephyrXVPrivGetImageBufSize (port_priv->port_number, + a_id, a_width, a_height, &image_size)) { + EPHYR_LOG_ERROR ("failed to get image size\n") ; + /*this is a minor error so we won't get bail out abruptly*/ + is_ok = FALSE ; + } else { + is_ok = TRUE ; + } + if (is_ok) { + if (!ephyrXVPrivSaveImageToPortPriv (port_priv, a_buf, image_size)) { + is_ok=FALSE ; + } else { + port_priv->image_id = a_id; + port_priv->drw_x = a_drw_x; + port_priv->drw_y = a_drw_y; + port_priv->drw_w = a_drw_w ; + port_priv->drw_h = a_drw_h ; + port_priv->src_x = a_src_x; + port_priv->src_y = a_src_y ; + port_priv->src_w = a_src_w ; + port_priv->src_h = a_src_h ; + port_priv->image_width = a_width ; + port_priv->image_height = a_height ; + } + } + if (!is_ok) { + if (port_priv->image_buf) { + free (port_priv->image_buf) ; + port_priv->image_buf = NULL ; + port_priv->image_buf_size = 0 ; + } + } + + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrReputImage (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_drw_x, + short a_drw_y, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + int result=BadImplementation ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, FALSE) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + if (!port_priv->image_buf_size || !port_priv->image_buf) { + EPHYR_LOG_ERROR ("has null image buf in cache\n") ; + goto out ; + } + if (!ephyrHostXVPutImage (a_info->pScreen->myNum, + port_priv->port_number, + port_priv->image_id, + a_drw_x, a_drw_y, + port_priv->drw_w, port_priv->drw_h, + port_priv->src_x, port_priv->src_y, + port_priv->src_w, port_priv->src_h, + port_priv->image_width, port_priv->image_height, + port_priv->image_buf, + (EphyrHostBox*)REGION_RECTS (a_clipping_region), + REGION_NUM_RECTS (a_clipping_region))) { + EPHYR_LOG_ERROR ("ephyrHostXVPutImage() failed\n") ; + goto out ; + } + + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrPutVideo (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + BoxRec clipped_area, dst_box ; + int result=BadImplementation ; + int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + dst_box.x1 = a_drw_x ; + dst_box.x2 = a_drw_x + a_drw_w; + dst_box.y1 = a_drw_y ; + dst_box.y2 = a_drw_y + a_drw_h; + + if (!DoSimpleClip (&dst_box, + REGION_EXTENTS (pScreen->pScreen, a_clipping_region), + &clipped_area)) { + EPHYR_LOG_ERROR ("failed to simple clip\n") ; + goto out ; + } + + drw_x = clipped_area.x1 ; + drw_y = clipped_area.y1 ; + drw_w = clipped_area.x2 - clipped_area.x1 ; + drw_h = clipped_area.y2 - clipped_area.y1 ; + + if (!ephyrHostXVPutVideo (a_info->pScreen->myNum, + port_priv->port_number, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { + EPHYR_LOG_ERROR ("ephyrHostXVPutVideo() failed\n") ; + goto out ; + } + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrGetVideo (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + BoxRec clipped_area, dst_box ; + int result=BadImplementation ; + int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + dst_box.x1 = a_drw_x ; + dst_box.x2 = a_drw_x + a_drw_w; + dst_box.y1 = a_drw_y ; + dst_box.y2 = a_drw_y + a_drw_h; + + if (!DoSimpleClip (&dst_box, + REGION_EXTENTS (pScreen->pScreen, a_clipping_region), + &clipped_area)) { + EPHYR_LOG_ERROR ("failed to simple clip\n") ; + goto out ; + } + + drw_x = clipped_area.x1 ; + drw_y = clipped_area.y1 ; + drw_w = clipped_area.x2 - clipped_area.x1 ; + drw_h = clipped_area.y2 - clipped_area.y1 ; + + if (!ephyrHostXVGetVideo (a_info->pScreen->myNum, + port_priv->port_number, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { + EPHYR_LOG_ERROR ("ephyrHostXVGetVideo() failed\n") ; + goto out ; + } + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrPutStill (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + BoxRec clipped_area, dst_box ; + int result=BadImplementation ; + int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + dst_box.x1 = a_drw_x ; + dst_box.x2 = a_drw_x + a_drw_w; + dst_box.y1 = a_drw_y ; + dst_box.y2 = a_drw_y + a_drw_h; + + if (!DoSimpleClip (&dst_box, + REGION_EXTENTS (pScreen->pScreen, a_clipping_region), + &clipped_area)) { + EPHYR_LOG_ERROR ("failed to simple clip\n") ; + goto out ; + } + + drw_x = clipped_area.x1 ; + drw_y = clipped_area.y1 ; + drw_w = clipped_area.x2 - clipped_area.x1 ; + drw_h = clipped_area.y2 - clipped_area.y1 ; + + if (!ephyrHostXVPutStill (a_info->pScreen->myNum, + port_priv->port_number, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { + EPHYR_LOG_ERROR ("ephyrHostXVPutStill() failed\n") ; + goto out ; + } + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrGetStill (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + BoxRec clipped_area, dst_box ; + int result=BadImplementation ; + int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + dst_box.x1 = a_drw_x ; + dst_box.x2 = a_drw_x + a_drw_w; + dst_box.y1 = a_drw_y ; + dst_box.y2 = a_drw_y + a_drw_h; + + if (!DoSimpleClip (&dst_box, + REGION_EXTENTS (pScreen->pScreen, a_clipping_region), + &clipped_area)) { + EPHYR_LOG_ERROR ("failed to simple clip\n") ; + goto out ; + } + + drw_x = clipped_area.x1 ; + drw_y = clipped_area.y1 ; + drw_w = clipped_area.x2 - clipped_area.x1 ; + drw_h = clipped_area.y2 - clipped_area.y1 ; + + if (!ephyrHostXVGetStill (a_info->pScreen->myNum, + port_priv->port_number, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { + EPHYR_LOG_ERROR ("ephyrHostXVGetStill() failed\n") ; + goto out ; + } + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrQueryImageAttributes (KdScreenInfo *a_info, + int a_id, + unsigned short *a_w, + unsigned short *a_h, + int *a_pitches, + int *a_offsets) +{ + int image_size=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_w && a_h, FALSE) ; + + EPHYR_LOG ("enter: dim (%dx%d), pitches: %p, offsets: %p\n", + *a_w, *a_h, a_pitches, a_offsets) ; + + if (!ephyrHostXVQueryImageAttributes (s_base_port_id, + a_id, + a_w, a_h, + &image_size, + a_pitches, a_offsets)) { + EPHYR_LOG_ERROR ("EphyrHostXVQueryImageAttributes() failed\n") ; + goto out ; + } + EPHYR_LOG ("image size: %d, dim (%dx%d)\n", image_size, *a_w, *a_h) ; + +out: + EPHYR_LOG ("leave\n") ; + return image_size ; +} diff --git a/xorg-server/hw/kdrive/fake/fake.c b/xorg-server/hw/kdrive/fake/fake.c index 809e309a6..9f2327d94 100644 --- a/xorg-server/hw/kdrive/fake/fake.c +++ b/xorg-server/hw/kdrive/fake/fake.c @@ -1,476 +1,476 @@ -/* - * Copyright © 2004 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include "fake.h" - -extern int KdTsPhyScreen; - -Bool -fakeInitialize (KdCardInfo *card, FakePriv *priv) -{ - priv->base = 0; - priv->bytes_per_line = 0; - return TRUE; -} - -Bool -fakeCardInit (KdCardInfo *card) -{ - FakePriv *priv; - - priv = (FakePriv *) xalloc (sizeof (FakePriv)); - if (!priv) - return FALSE; - - if (!fakeInitialize (card, priv)) - { - xfree (priv); - return FALSE; - } - card->driver = priv; - - return TRUE; -} - -Bool -fakeScreenInitialize (KdScreenInfo *screen, FakeScrPriv *scrpriv) -{ - if (!screen->width || !screen->height) - { - screen->width = 1024; - screen->height = 768; - screen->rate = 72; - } - - if (screen->width <= 0) - screen->width = 1; - if (screen->height <= 0) - screen->height = 1; - - if (!screen->fb.depth) - screen->fb.depth = 16; - - if (screen->fb.depth <= 8) - { - screen->fb.visuals = ((1 << StaticGray) | - (1 << GrayScale) | - (1 << StaticColor) | - (1 << PseudoColor) | - (1 << TrueColor) | - (1 << DirectColor)); - } - else - { - screen->fb.visuals = (1 << TrueColor); -#define Mask(o,l) (((1 << l) - 1) << o) - if (screen->fb.depth <= 15) - { - screen->fb.depth = 15; - screen->fb.bitsPerPixel = 16; - screen->fb.redMask = Mask (10, 5); - screen->fb.greenMask = Mask (5, 5); - screen->fb.blueMask = Mask (0, 5); - } - else if (screen->fb.depth <= 16) - { - screen->fb.depth = 16; - screen->fb.bitsPerPixel = 16; - screen->fb.redMask = Mask (11, 5); - screen->fb.greenMask = Mask (5, 6); - screen->fb.blueMask = Mask (0, 5); - } - else - { - screen->fb.depth = 24; - screen->fb.bitsPerPixel = 32; - screen->fb.redMask = Mask (16, 8); - screen->fb.greenMask = Mask (8, 8); - screen->fb.blueMask = Mask (0, 8); - } - } - - scrpriv->randr = screen->randr; - - return fakeMapFramebuffer (screen); -} - -Bool -fakeScreenInit (KdScreenInfo *screen) -{ - FakeScrPriv *scrpriv; - - scrpriv = xcalloc (1, sizeof (FakeScrPriv)); - if (!scrpriv) - return FALSE; - screen->driver = scrpriv; - if (!fakeScreenInitialize (screen, scrpriv)) - { - screen->driver = 0; - xfree (scrpriv); - return FALSE; - } - return TRUE; -} - -void * -fakeWindowLinear (ScreenPtr pScreen, - CARD32 row, - CARD32 offset, - int mode, - CARD32 *size, - void *closure) -{ - KdScreenPriv(pScreen); - FakePriv *priv = pScreenPriv->card->driver; - - if (!pScreenPriv->enabled) - return 0; - *size = priv->bytes_per_line; - return priv->base + row * priv->bytes_per_line; -} - -Bool -fakeMapFramebuffer (KdScreenInfo *screen) -{ - FakeScrPriv *scrpriv = screen->driver; - KdPointerMatrix m; - FakePriv *priv = screen->card->driver; - - if (scrpriv->randr != RR_Rotate_0) - scrpriv->shadow = TRUE; - else - scrpriv->shadow = FALSE; - - KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); - - KdSetPointerMatrix (&m); - - priv->bytes_per_line = ((screen->width * screen->fb.bitsPerPixel + 31) >> 5) << 2; - if (priv->base) - free (priv->base); - priv->base = malloc (priv->bytes_per_line * screen->height); - - if (scrpriv->shadow) - { - if (!KdShadowFbAlloc (screen, scrpriv->randr & (RR_Rotate_90|RR_Rotate_270))) - return FALSE; - } - else - { - screen->fb.byteStride = priv->bytes_per_line; - screen->fb.pixelStride = (priv->bytes_per_line * 8/ - screen->fb.bitsPerPixel); - screen->fb.frameBuffer = (CARD8 *) (priv->base); - } - - return TRUE; -} - -void -fakeSetScreenSizes (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FakeScrPriv *scrpriv = screen->driver; - - if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) - { - pScreen->width = screen->width; - pScreen->height = screen->height; - pScreen->mmWidth = screen->width_mm; - pScreen->mmHeight = screen->height_mm; - } - else - { - pScreen->width = screen->width; - pScreen->height = screen->height; - pScreen->mmWidth = screen->height_mm; - pScreen->mmHeight = screen->width_mm; - } -} - -Bool -fakeUnmapFramebuffer (KdScreenInfo *screen) -{ - FakePriv *priv = screen->card->driver; - KdShadowFbFree (screen); - if (priv->base) - { - free (priv->base); - priv->base = 0; - } - return TRUE; -} - -Bool -fakeSetShadow (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FakeScrPriv *scrpriv = screen->driver; - ShadowUpdateProc update; - ShadowWindowProc window; - - window = fakeWindowLinear; - update = 0; - if (scrpriv->randr) - update = shadowUpdateRotatePacked; - else - update = shadowUpdatePacked; - return KdShadowSet (pScreen, scrpriv->randr, update, window); -} - - -#ifdef RANDR -Bool -fakeRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FakeScrPriv *scrpriv = screen->driver; - RRScreenSizePtr pSize; - Rotation randr; - int n; - - *rotations = RR_Rotate_All|RR_Reflect_All; - - for (n = 0; n < pScreen->numDepths; n++) - if (pScreen->allowedDepths[n].numVids) - break; - if (n == pScreen->numDepths) - return FALSE; - - pSize = RRRegisterSize (pScreen, - screen->width, - screen->height, - screen->width_mm, - screen->height_mm); - - randr = KdSubRotation (scrpriv->randr, screen->randr); - - RRSetCurrentConfig (pScreen, randr, 0, pSize); - - return TRUE; -} - -Bool -fakeRandRSetConfig (ScreenPtr pScreen, - Rotation randr, - int rate, - RRScreenSizePtr pSize) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FakeScrPriv *scrpriv = screen->driver; - Bool wasEnabled = pScreenPriv->enabled; - FakeScrPriv oldscr; - int oldwidth; - int oldheight; - int oldmmwidth; - int oldmmheight; - int newwidth, newheight; - - if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) - { - newwidth = pSize->width; - newheight = pSize->height; - } - else - { - newwidth = pSize->height; - newheight = pSize->width; - } - - if (wasEnabled) - KdDisableScreen (pScreen); - - oldscr = *scrpriv; - - oldwidth = screen->width; - oldheight = screen->height; - oldmmwidth = pScreen->mmWidth; - oldmmheight = pScreen->mmHeight; - - /* - * Set new configuration - */ - - scrpriv->randr = KdAddRotation (screen->randr, randr); - - fakeUnmapFramebuffer (screen); - - if (!fakeMapFramebuffer (screen)) - goto bail4; - - KdShadowUnset (screen->pScreen); - - if (!fakeSetShadow (screen->pScreen)) - goto bail4; - - fakeSetScreenSizes (screen->pScreen); - - /* - * Set frame buffer mapping - */ - (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), - pScreen->width, - pScreen->height, - screen->fb.depth, - screen->fb.bitsPerPixel, - screen->fb.byteStride, - screen->fb.frameBuffer); - - /* set the subpixel order */ - - KdSetSubpixelOrder (pScreen, scrpriv->randr); - if (wasEnabled) - KdEnableScreen (pScreen); - - return TRUE; - -bail4: - fakeUnmapFramebuffer (screen); - *scrpriv = oldscr; - (void) fakeMapFramebuffer (screen); - pScreen->width = oldwidth; - pScreen->height = oldheight; - pScreen->mmWidth = oldmmwidth; - pScreen->mmHeight = oldmmheight; - - if (wasEnabled) - KdEnableScreen (pScreen); - return FALSE; -} - -Bool -fakeRandRInit (ScreenPtr pScreen) -{ - rrScrPrivPtr pScrPriv; - - if (!RRScreenInit (pScreen)) - return FALSE; - - pScrPriv = rrGetScrPriv(pScreen); - pScrPriv->rrGetInfo = fakeRandRGetInfo; - pScrPriv->rrSetConfig = fakeRandRSetConfig; - return TRUE; -} -#endif - -Bool -fakeCreateColormap (ColormapPtr pmap) -{ - return fbInitializeColormap (pmap); -} - -Bool -fakeInitScreen (ScreenPtr pScreen) -{ -#ifdef TOUCHSCREEN - KdTsPhyScreen = pScreen->myNum; -#endif - - pScreen->CreateColormap = fakeCreateColormap; - return TRUE; -} - -Bool -fakeFinishInitScreen (ScreenPtr pScreen) -{ - if (!shadowSetup (pScreen)) - return FALSE; - -#ifdef RANDR - if (!fakeRandRInit (pScreen)) - return FALSE; -#endif - - return TRUE; -} - - -Bool -fakeCreateResources (ScreenPtr pScreen) -{ - return fakeSetShadow (pScreen); -} - -void -fakePreserve (KdCardInfo *card) -{ -} - -Bool -fakeEnable (ScreenPtr pScreen) -{ - return TRUE; -} - -Bool -fakeDPMS (ScreenPtr pScreen, int mode) -{ - return TRUE; -} - -void -fakeDisable (ScreenPtr pScreen) -{ -} - -void -fakeRestore (KdCardInfo *card) -{ -} - -void -fakeScreenFini (KdScreenInfo *screen) -{ -} - -void -fakeCardFini (KdCardInfo *card) -{ - FakePriv *priv = card->driver; - - free (priv->base); - xfree (priv); -} - -void -fakeGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - while (n--) - { - pdefs->red = 0; - pdefs->green = 0; - pdefs->blue = 0; - pdefs++; - } -} - -void -fakePutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ -} +/* + * Copyright © 2004 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "fake.h" + +extern int KdTsPhyScreen; + +Bool +fakeInitialize (KdCardInfo *card, FakePriv *priv) +{ + priv->base = 0; + priv->bytes_per_line = 0; + return TRUE; +} + +Bool +fakeCardInit (KdCardInfo *card) +{ + FakePriv *priv; + + priv = (FakePriv *) malloc(sizeof (FakePriv)); + if (!priv) + return FALSE; + + if (!fakeInitialize (card, priv)) + { + free(priv); + return FALSE; + } + card->driver = priv; + + return TRUE; +} + +Bool +fakeScreenInitialize (KdScreenInfo *screen, FakeScrPriv *scrpriv) +{ + if (!screen->width || !screen->height) + { + screen->width = 1024; + screen->height = 768; + screen->rate = 72; + } + + if (screen->width <= 0) + screen->width = 1; + if (screen->height <= 0) + screen->height = 1; + + if (!screen->fb.depth) + screen->fb.depth = 16; + + if (screen->fb.depth <= 8) + { + screen->fb.visuals = ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)); + } + else + { + screen->fb.visuals = (1 << TrueColor); +#define Mask(o,l) (((1 << l) - 1) << o) + if (screen->fb.depth <= 15) + { + screen->fb.depth = 15; + screen->fb.bitsPerPixel = 16; + screen->fb.redMask = Mask (10, 5); + screen->fb.greenMask = Mask (5, 5); + screen->fb.blueMask = Mask (0, 5); + } + else if (screen->fb.depth <= 16) + { + screen->fb.depth = 16; + screen->fb.bitsPerPixel = 16; + screen->fb.redMask = Mask (11, 5); + screen->fb.greenMask = Mask (5, 6); + screen->fb.blueMask = Mask (0, 5); + } + else + { + screen->fb.depth = 24; + screen->fb.bitsPerPixel = 32; + screen->fb.redMask = Mask (16, 8); + screen->fb.greenMask = Mask (8, 8); + screen->fb.blueMask = Mask (0, 8); + } + } + + scrpriv->randr = screen->randr; + + return fakeMapFramebuffer (screen); +} + +Bool +fakeScreenInit (KdScreenInfo *screen) +{ + FakeScrPriv *scrpriv; + + scrpriv = calloc(1, sizeof (FakeScrPriv)); + if (!scrpriv) + return FALSE; + screen->driver = scrpriv; + if (!fakeScreenInitialize (screen, scrpriv)) + { + screen->driver = 0; + free(scrpriv); + return FALSE; + } + return TRUE; +} + +void * +fakeWindowLinear (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size, + void *closure) +{ + KdScreenPriv(pScreen); + FakePriv *priv = pScreenPriv->card->driver; + + if (!pScreenPriv->enabled) + return 0; + *size = priv->bytes_per_line; + return priv->base + row * priv->bytes_per_line; +} + +Bool +fakeMapFramebuffer (KdScreenInfo *screen) +{ + FakeScrPriv *scrpriv = screen->driver; + KdPointerMatrix m; + FakePriv *priv = screen->card->driver; + + if (scrpriv->randr != RR_Rotate_0) + scrpriv->shadow = TRUE; + else + scrpriv->shadow = FALSE; + + KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); + + KdSetPointerMatrix (&m); + + priv->bytes_per_line = ((screen->width * screen->fb.bitsPerPixel + 31) >> 5) << 2; + if (priv->base) + free (priv->base); + priv->base = malloc (priv->bytes_per_line * screen->height); + + if (scrpriv->shadow) + { + if (!KdShadowFbAlloc (screen, scrpriv->randr & (RR_Rotate_90|RR_Rotate_270))) + return FALSE; + } + else + { + screen->fb.byteStride = priv->bytes_per_line; + screen->fb.pixelStride = (priv->bytes_per_line * 8/ + screen->fb.bitsPerPixel); + screen->fb.frameBuffer = (CARD8 *) (priv->base); + } + + return TRUE; +} + +void +fakeSetScreenSizes (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FakeScrPriv *scrpriv = screen->driver; + + if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) + { + pScreen->width = screen->width; + pScreen->height = screen->height; + pScreen->mmWidth = screen->width_mm; + pScreen->mmHeight = screen->height_mm; + } + else + { + pScreen->width = screen->width; + pScreen->height = screen->height; + pScreen->mmWidth = screen->height_mm; + pScreen->mmHeight = screen->width_mm; + } +} + +Bool +fakeUnmapFramebuffer (KdScreenInfo *screen) +{ + FakePriv *priv = screen->card->driver; + KdShadowFbFree (screen); + if (priv->base) + { + free (priv->base); + priv->base = 0; + } + return TRUE; +} + +Bool +fakeSetShadow (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FakeScrPriv *scrpriv = screen->driver; + ShadowUpdateProc update; + ShadowWindowProc window; + + window = fakeWindowLinear; + update = 0; + if (scrpriv->randr) + update = shadowUpdateRotatePacked; + else + update = shadowUpdatePacked; + return KdShadowSet (pScreen, scrpriv->randr, update, window); +} + + +#ifdef RANDR +Bool +fakeRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FakeScrPriv *scrpriv = screen->driver; + RRScreenSizePtr pSize; + Rotation randr; + int n; + + *rotations = RR_Rotate_All|RR_Reflect_All; + + for (n = 0; n < pScreen->numDepths; n++) + if (pScreen->allowedDepths[n].numVids) + break; + if (n == pScreen->numDepths) + return FALSE; + + pSize = RRRegisterSize (pScreen, + screen->width, + screen->height, + screen->width_mm, + screen->height_mm); + + randr = KdSubRotation (scrpriv->randr, screen->randr); + + RRSetCurrentConfig (pScreen, randr, 0, pSize); + + return TRUE; +} + +Bool +fakeRandRSetConfig (ScreenPtr pScreen, + Rotation randr, + int rate, + RRScreenSizePtr pSize) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FakeScrPriv *scrpriv = screen->driver; + Bool wasEnabled = pScreenPriv->enabled; + FakeScrPriv oldscr; + int oldwidth; + int oldheight; + int oldmmwidth; + int oldmmheight; + int newwidth, newheight; + + if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) + { + newwidth = pSize->width; + newheight = pSize->height; + } + else + { + newwidth = pSize->height; + newheight = pSize->width; + } + + if (wasEnabled) + KdDisableScreen (pScreen); + + oldscr = *scrpriv; + + oldwidth = screen->width; + oldheight = screen->height; + oldmmwidth = pScreen->mmWidth; + oldmmheight = pScreen->mmHeight; + + /* + * Set new configuration + */ + + scrpriv->randr = KdAddRotation (screen->randr, randr); + + fakeUnmapFramebuffer (screen); + + if (!fakeMapFramebuffer (screen)) + goto bail4; + + KdShadowUnset (screen->pScreen); + + if (!fakeSetShadow (screen->pScreen)) + goto bail4; + + fakeSetScreenSizes (screen->pScreen); + + /* + * Set frame buffer mapping + */ + (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), + pScreen->width, + pScreen->height, + screen->fb.depth, + screen->fb.bitsPerPixel, + screen->fb.byteStride, + screen->fb.frameBuffer); + + /* set the subpixel order */ + + KdSetSubpixelOrder (pScreen, scrpriv->randr); + if (wasEnabled) + KdEnableScreen (pScreen); + + return TRUE; + +bail4: + fakeUnmapFramebuffer (screen); + *scrpriv = oldscr; + (void) fakeMapFramebuffer (screen); + pScreen->width = oldwidth; + pScreen->height = oldheight; + pScreen->mmWidth = oldmmwidth; + pScreen->mmHeight = oldmmheight; + + if (wasEnabled) + KdEnableScreen (pScreen); + return FALSE; +} + +Bool +fakeRandRInit (ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) + return FALSE; + + pScrPriv = rrGetScrPriv(pScreen); + pScrPriv->rrGetInfo = fakeRandRGetInfo; + pScrPriv->rrSetConfig = fakeRandRSetConfig; + return TRUE; +} +#endif + +Bool +fakeCreateColormap (ColormapPtr pmap) +{ + return fbInitializeColormap (pmap); +} + +Bool +fakeInitScreen (ScreenPtr pScreen) +{ +#ifdef TOUCHSCREEN + KdTsPhyScreen = pScreen->myNum; +#endif + + pScreen->CreateColormap = fakeCreateColormap; + return TRUE; +} + +Bool +fakeFinishInitScreen (ScreenPtr pScreen) +{ + if (!shadowSetup (pScreen)) + return FALSE; + +#ifdef RANDR + if (!fakeRandRInit (pScreen)) + return FALSE; +#endif + + return TRUE; +} + + +Bool +fakeCreateResources (ScreenPtr pScreen) +{ + return fakeSetShadow (pScreen); +} + +void +fakePreserve (KdCardInfo *card) +{ +} + +Bool +fakeEnable (ScreenPtr pScreen) +{ + return TRUE; +} + +Bool +fakeDPMS (ScreenPtr pScreen, int mode) +{ + return TRUE; +} + +void +fakeDisable (ScreenPtr pScreen) +{ +} + +void +fakeRestore (KdCardInfo *card) +{ +} + +void +fakeScreenFini (KdScreenInfo *screen) +{ +} + +void +fakeCardFini (KdCardInfo *card) +{ + FakePriv *priv = card->driver; + + free (priv->base); + free(priv); +} + +void +fakeGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + while (n--) + { + pdefs->red = 0; + pdefs->green = 0; + pdefs->blue = 0; + pdefs++; + } +} + +void +fakePutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ +} diff --git a/xorg-server/hw/kdrive/fbdev/fbdev.c b/xorg-server/hw/kdrive/fbdev/fbdev.c index d4604ad29..b127ab89b 100644 --- a/xorg-server/hw/kdrive/fbdev/fbdev.c +++ b/xorg-server/hw/kdrive/fbdev/fbdev.c @@ -1,826 +1,826 @@ -/* - * Copyright © 1999 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include "fbdev.h" -#include <sys/ioctl.h> - -#include <errno.h> - -extern int KdTsPhyScreen; - -char *fbdevDevicePath = NULL; - -static Bool -fbdevInitialize (KdCardInfo *card, FbdevPriv *priv) -{ - unsigned long off; - - if (fbdevDevicePath == NULL) - fbdevDevicePath = "/dev/fb0"; - - if ((priv->fd = open(fbdevDevicePath, O_RDWR)) < 0) - { - ErrorF("Error opening framebuffer %s: %s\n", - fbdevDevicePath, strerror(errno)); - return FALSE; - } - - /* quiet valgrind */ - memset (&priv->fix, '\0', sizeof (priv->fix)); - if (ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix) < 0) { - perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO"); - close (priv->fd); - return FALSE; - } - /* quiet valgrind */ - memset (&priv->var, '\0', sizeof (priv->var)); - if (ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var) < 0) { - perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO"); - close (priv->fd); - return FALSE; - } - - priv->fb_base = (char *) mmap ((caddr_t) NULL, - priv->fix.smem_len, - PROT_READ|PROT_WRITE, - MAP_SHARED, - priv->fd, 0); - - if (priv->fb_base == (char *)-1) - { - perror("ERROR: mmap framebuffer fails!"); - close (priv->fd); - return FALSE; - } - off = (unsigned long) priv->fix.smem_start % (unsigned long) getpagesize(); - priv->fb = priv->fb_base + off; - return TRUE; -} - -Bool -fbdevCardInit (KdCardInfo *card) -{ - FbdevPriv *priv; - - priv = (FbdevPriv *) xalloc (sizeof (FbdevPriv)); - if (!priv) - return FALSE; - - if (!fbdevInitialize (card, priv)) - { - xfree (priv); - return FALSE; - } - card->driver = priv; - - return TRUE; -} - -static Pixel -fbdevMakeContig (Pixel orig, Pixel others) -{ - Pixel low; - - low = lowbit (orig) >> 1; - while (low && (others & low) == 0) - { - orig |= low; - low >>= 1; - } - return orig; -} - -static Bool -fbdevModeSupported (KdScreenInfo *screen, - const KdMonitorTiming *t) -{ - return TRUE; -} - -static void -fbdevConvertMonitorTiming (const KdMonitorTiming *t, struct fb_var_screeninfo *var) -{ - memset (var, 0, sizeof (struct fb_var_screeninfo)); - - var->xres = t->horizontal; - var->yres = t->vertical; - var->xres_virtual = t->horizontal; - var->yres_virtual = t->vertical; - var->xoffset = 0; - var->yoffset = 0; - var->pixclock = t->clock ? 1000000000 / t->clock : 0; - var->left_margin = t->hbp; - var->right_margin = t->hfp; - var->upper_margin = t->vbp; - var->lower_margin = t->vfp; - var->hsync_len = t->hblank - t->hfp - t->hbp; - var->vsync_len = t->vblank - t->vfp - t->vbp; - - var->sync = 0; - var->vmode = 0; - - if (t->hpol == KdSyncPositive) - var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (t->vpol == KdSyncPositive) - var->sync |= FB_SYNC_VERT_HIGH_ACT; -} - -static Bool -fbdevScreenInitialize (KdScreenInfo *screen, FbdevScrPriv *scrpriv) -{ - FbdevPriv *priv = screen->card->driver; - Pixel allbits; - int depth; - Bool gray; - struct fb_var_screeninfo var; - const KdMonitorTiming *t; - int k; - - k = ioctl (priv->fd, FBIOGET_VSCREENINFO, &var); - - if (!screen->width || !screen->height) - { - if (k >= 0) - { - screen->width = var.xres; - screen->height = var.yres; - } - else - { - screen->width = 1024; - screen->height = 768; - } - screen->rate = 103; /* FIXME: should get proper value from fb driver */ - } - if (!screen->fb.depth) - { - if (k >= 0) - screen->fb.depth = var.bits_per_pixel; - else - screen->fb.depth = 16; - } - - if ((screen->width != var.xres) || (screen->height != var.yres)) - { - t = KdFindMode (screen, fbdevModeSupported); - screen->rate = t->rate; - screen->width = t->horizontal; - screen->height = t->vertical; - - /* Now try setting the mode */ - if (k < 0 || (t->horizontal != var.xres || t->vertical != var.yres)) - fbdevConvertMonitorTiming (t, &var); - } - - var.activate = FB_ACTIVATE_NOW; - var.bits_per_pixel = screen->fb.depth; - var.nonstd = 0; - var.grayscale = 0; - - k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &var); - - if (k < 0) - { - fprintf (stderr, "error: %s\n", strerror (errno)); - return FALSE; - } - - /* Re-get the "fixed" parameters since they might have changed */ - k = ioctl (priv->fd, FBIOGET_FSCREENINFO, &priv->fix); - if (k < 0) - perror ("FBIOGET_FSCREENINFO"); - - /* Now get the new screeninfo */ - ioctl (priv->fd, FBIOGET_VSCREENINFO, &priv->var); - depth = priv->var.bits_per_pixel; - gray = priv->var.grayscale; - - switch (priv->fix.visual) { - case FB_VISUAL_PSEUDOCOLOR: - if (gray) - { - screen->fb.visuals = (1 << StaticGray); - /* could also support GrayScale, but what's the point? */ - } - else - { - screen->fb.visuals = ((1 << StaticGray) | - (1 << GrayScale) | - (1 << StaticColor) | - (1 << PseudoColor) | - (1 << TrueColor) | - (1 << DirectColor)); - } - screen->fb.blueMask = 0x00; - screen->fb.greenMask = 0x00; - screen->fb.redMask = 0x00; - break; - case FB_VISUAL_STATIC_PSEUDOCOLOR: - if (gray) - { - screen->fb.visuals = (1 << StaticGray); - } - else - { - screen->fb.visuals = (1 << StaticColor); - } - screen->fb.blueMask = 0x00; - screen->fb.greenMask = 0x00; - screen->fb.redMask = 0x00; - break; - case FB_VISUAL_TRUECOLOR: - case FB_VISUAL_DIRECTCOLOR: - screen->fb.visuals = (1 << TrueColor); -#define Mask(o,l) (((1 << l) - 1) << o) - screen->fb.redMask = Mask (priv->var.red.offset, priv->var.red.length); - screen->fb.greenMask = Mask (priv->var.green.offset, priv->var.green.length); - screen->fb.blueMask = Mask (priv->var.blue.offset, priv->var.blue.length); - - /* - * This is a kludge so that Render will work -- fill in the gaps - * in the pixel - */ - screen->fb.redMask = fbdevMakeContig (screen->fb.redMask, - screen->fb.greenMask| - screen->fb.blueMask); - - screen->fb.greenMask = fbdevMakeContig (screen->fb.greenMask, - screen->fb.redMask| - screen->fb.blueMask); - - screen->fb.blueMask = fbdevMakeContig (screen->fb.blueMask, - screen->fb.redMask| - screen->fb.greenMask); - - allbits = screen->fb.redMask | screen->fb.greenMask | screen->fb.blueMask; - depth = 32; - while (depth && !(allbits & (1 << (depth - 1)))) - depth--; - break; - default: - return FALSE; - break; - } - screen->fb.depth = depth; - screen->fb.bitsPerPixel = priv->var.bits_per_pixel; - - scrpriv->randr = screen->randr; - - return fbdevMapFramebuffer (screen); -} - -Bool -fbdevScreenInit (KdScreenInfo *screen) -{ - FbdevScrPriv *scrpriv; - - scrpriv = xcalloc (1, sizeof (FbdevScrPriv)); - if (!scrpriv) - return FALSE; - screen->driver = scrpriv; - if (!fbdevScreenInitialize (screen, scrpriv)) - { - screen->driver = 0; - xfree (scrpriv); - return FALSE; - } - return TRUE; -} - -static void * -fbdevWindowLinear (ScreenPtr pScreen, - CARD32 row, - CARD32 offset, - int mode, - CARD32 *size, - void *closure) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - - if (!pScreenPriv->enabled) - return 0; - *size = priv->fix.line_length; - return (CARD8 *) priv->fb + row * priv->fix.line_length + offset; -} - -Bool -fbdevMapFramebuffer (KdScreenInfo *screen) -{ - FbdevScrPriv *scrpriv = screen->driver; - KdPointerMatrix m; - FbdevPriv *priv = screen->card->driver; - - if (scrpriv->randr != RR_Rotate_0) - scrpriv->shadow = TRUE; - else - scrpriv->shadow = FALSE; - - KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); - - KdSetPointerMatrix (&m); - - screen->width = priv->var.xres; - screen->height = priv->var.yres; - - if (scrpriv->shadow) - { - if (!KdShadowFbAlloc (screen, - scrpriv->randr & (RR_Rotate_90|RR_Rotate_270))) - return FALSE; - } - else - { - screen->fb.byteStride = priv->fix.line_length; - screen->fb.pixelStride = (priv->fix.line_length * 8 / - priv->var.bits_per_pixel); - screen->fb.frameBuffer = (CARD8 *) (priv->fb); - } - - return TRUE; -} - -static void -fbdevSetScreenSizes (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FbdevScrPriv *scrpriv = screen->driver; - FbdevPriv *priv = screen->card->driver; - - if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) - { - pScreen->width = priv->var.xres; - pScreen->height = priv->var.yres; - pScreen->mmWidth = screen->width_mm; - pScreen->mmHeight = screen->height_mm; - } - else - { - pScreen->width = priv->var.yres; - pScreen->height = priv->var.xres; - pScreen->mmWidth = screen->height_mm; - pScreen->mmHeight = screen->width_mm; - } -} - -static Bool -fbdevUnmapFramebuffer (KdScreenInfo *screen) -{ - KdShadowFbFree (screen); - return TRUE; -} - -static Bool -fbdevSetShadow (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FbdevScrPriv *scrpriv = screen->driver; - FbdevPriv *priv = screen->card->driver; - ShadowUpdateProc update; - ShadowWindowProc window; - int useYX = 0; - -#ifdef __arm__ - /* Use variant copy routines that always read left to right in the - shadow framebuffer. Reading vertical strips is exceptionally - slow on XScale due to cache effects. */ - useYX = 1; -#endif - - window = fbdevWindowLinear; - update = 0; - if (scrpriv->randr) - if (priv->var.bits_per_pixel == 16) { - switch (scrpriv->randr) { - case RR_Rotate_90: - if (useYX) - update = shadowUpdateRotate16_90YX; - else - update = shadowUpdateRotate16_90; - break; - case RR_Rotate_180: - update = shadowUpdateRotate16_180; - break; - case RR_Rotate_270: - if (useYX) - update = shadowUpdateRotate16_270YX; - else - update = shadowUpdateRotate16_270; - break; - default: - update = shadowUpdateRotate16; - break; - } - } else - update = shadowUpdateRotatePacked; - else - update = shadowUpdatePacked; - return KdShadowSet (pScreen, scrpriv->randr, update, window); -} - - -#ifdef RANDR -static Bool -fbdevRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FbdevScrPriv *scrpriv = screen->driver; - RRScreenSizePtr pSize; - Rotation randr; - int n; - - *rotations = RR_Rotate_All|RR_Reflect_All; - - for (n = 0; n < pScreen->numDepths; n++) - if (pScreen->allowedDepths[n].numVids) - break; - if (n == pScreen->numDepths) - return FALSE; - - pSize = RRRegisterSize (pScreen, - screen->width, - screen->height, - screen->width_mm, - screen->height_mm); - - randr = KdSubRotation (scrpriv->randr, screen->randr); - - RRSetCurrentConfig (pScreen, randr, 0, pSize); - - return TRUE; -} - -static Bool -fbdevRandRSetConfig (ScreenPtr pScreen, - Rotation randr, - int rate, - RRScreenSizePtr pSize) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FbdevScrPriv *scrpriv = screen->driver; - Bool wasEnabled = pScreenPriv->enabled; - FbdevScrPriv oldscr; - int oldwidth; - int oldheight; - int oldmmwidth; - int oldmmheight; - int newwidth, newheight; - - if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) - { - newwidth = pSize->width; - newheight = pSize->height; - } - else - { - newwidth = pSize->height; - newheight = pSize->width; - } - - if (wasEnabled) - KdDisableScreen (pScreen); - - oldscr = *scrpriv; - - oldwidth = screen->width; - oldheight = screen->height; - oldmmwidth = pScreen->mmWidth; - oldmmheight = pScreen->mmHeight; - - /* - * Set new configuration - */ - - scrpriv->randr = KdAddRotation (screen->randr, randr); - - fbdevUnmapFramebuffer (screen); - - if (!fbdevMapFramebuffer (screen)) - goto bail4; - - KdShadowUnset (screen->pScreen); - - if (!fbdevSetShadow (screen->pScreen)) - goto bail4; - - fbdevSetScreenSizes (screen->pScreen); - - /* - * Set frame buffer mapping - */ - (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), - pScreen->width, - pScreen->height, - screen->fb.depth, - screen->fb.bitsPerPixel, - screen->fb.byteStride, - screen->fb.frameBuffer); - - /* set the subpixel order */ - - KdSetSubpixelOrder (pScreen, scrpriv->randr); - if (wasEnabled) - KdEnableScreen (pScreen); - - return TRUE; - -bail4: - fbdevUnmapFramebuffer (screen); - *scrpriv = oldscr; - (void) fbdevMapFramebuffer (screen); - pScreen->width = oldwidth; - pScreen->height = oldheight; - pScreen->mmWidth = oldmmwidth; - pScreen->mmHeight = oldmmheight; - - if (wasEnabled) - KdEnableScreen (pScreen); - return FALSE; -} - -static Bool -fbdevRandRInit (ScreenPtr pScreen) -{ - rrScrPrivPtr pScrPriv; - - if (!RRScreenInit (pScreen)) - return FALSE; - - pScrPriv = rrGetScrPriv(pScreen); - pScrPriv->rrGetInfo = fbdevRandRGetInfo; - pScrPriv->rrSetConfig = fbdevRandRSetConfig; - return TRUE; -} -#endif - -static Bool -fbdevCreateColormap (ColormapPtr pmap) -{ - ScreenPtr pScreen = pmap->pScreen; - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - VisualPtr pVisual; - int i; - int nent; - xColorItem *pdefs; - - switch (priv->fix.visual) { - case FB_VISUAL_STATIC_PSEUDOCOLOR: - pVisual = pmap->pVisual; - nent = pVisual->ColormapEntries; - pdefs = xalloc (nent * sizeof (xColorItem)); - if (!pdefs) - return FALSE; - for (i = 0; i < nent; i++) - pdefs[i].pixel = i; - fbdevGetColors (pScreen, nent, pdefs); - for (i = 0; i < nent; i++) - { - pmap->red[i].co.local.red = pdefs[i].red; - pmap->red[i].co.local.green = pdefs[i].green; - pmap->red[i].co.local.blue = pdefs[i].blue; - } - xfree (pdefs); - return TRUE; - default: - return fbInitializeColormap (pmap); - } -} - -Bool -fbdevInitScreen (ScreenPtr pScreen) -{ -#ifdef TOUCHSCREEN - KdTsPhyScreen = pScreen->myNum; -#endif - - pScreen->CreateColormap = fbdevCreateColormap; - return TRUE; -} - -Bool -fbdevFinishInitScreen (ScreenPtr pScreen) -{ - if (!shadowSetup (pScreen)) - return FALSE; - -#ifdef RANDR - if (!fbdevRandRInit (pScreen)) - return FALSE; -#endif - - return TRUE; -} - - -Bool -fbdevCreateResources (ScreenPtr pScreen) -{ - return fbdevSetShadow (pScreen); -} - -void -fbdevPreserve (KdCardInfo *card) -{ -} - -static int -fbdevUpdateFbColormap(FbdevPriv *priv, int minidx, int maxidx) -{ - struct fb_cmap cmap; - - cmap.start = minidx; - cmap.len = maxidx - minidx + 1; - cmap.red = &priv->red[minidx]; - cmap.green = &priv->green[minidx]; - cmap.blue = &priv->blue[minidx]; - cmap.transp = 0; - - return ioctl(priv->fd, FBIOPUTCMAP, &cmap); -} - -Bool -fbdevEnable (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - int k; - - priv->var.activate = FB_ACTIVATE_NOW|FB_CHANGE_CMAP_VBL; - - /* display it on the LCD */ - k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &priv->var); - if (k < 0) - { - perror ("FBIOPUT_VSCREENINFO"); - return FALSE; - } - - if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR) - { - int i; - - for (i = 0; - i < (1 << priv->var.red.length) || - i < (1 << priv->var.green.length) || - i < (1 << priv->var.blue.length); i++) - { - priv->red[i] = i * 65535 / ((1 << priv->var.red.length) - 1); - priv->green[i] = i * 65535 / ((1 << priv->var.green.length) - 1); - priv->blue[i] = i * 65535 / ((1 << priv->var.blue.length) - 1); - } - - fbdevUpdateFbColormap(priv, 0, i); - } - return TRUE; -} - -Bool -fbdevDPMS (ScreenPtr pScreen, int mode) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - static int oldmode = -1; - - if (mode == oldmode) - return TRUE; -#ifdef FBIOPUT_POWERMODE - if (ioctl (priv->fd, FBIOPUT_POWERMODE, &mode) >= 0) - { - oldmode = mode; - return TRUE; - } -#endif -#ifdef FBIOBLANK - if (ioctl (priv->fd, FBIOBLANK, mode ? mode + 1 : 0) >= 0) - { - oldmode = mode; - return TRUE; - } -#endif - return FALSE; -} - -void -fbdevDisable (ScreenPtr pScreen) -{ -} - -void -fbdevRestore (KdCardInfo *card) -{ -} - -void -fbdevScreenFini (KdScreenInfo *screen) -{ -} - -void -fbdevCardFini (KdCardInfo *card) -{ - FbdevPriv *priv = card->driver; - - munmap (priv->fb_base, priv->fix.smem_len); - close (priv->fd); - xfree (priv); -} - -/* - * Retrieve actual colormap and return selected n entries in pdefs. - */ -void -fbdevGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - struct fb_cmap cmap; - int p; - int k; - int min, max; - - min = 256; - max = 0; - for (k = 0; k < n; k++) - { - if (pdefs[k].pixel < min) - min = pdefs[k].pixel; - if (pdefs[k].pixel > max) - max = pdefs[k].pixel; - } - cmap.start = min; - cmap.len = max - min + 1; - cmap.red = &priv->red[min]; - cmap.green = &priv->green[min]; - cmap.blue = &priv->blue[min]; - cmap.transp = 0; - k = ioctl (priv->fd, FBIOGETCMAP, &cmap); - if (k < 0) - { - perror ("can't get colormap"); - return; - } - while (n--) - { - p = pdefs->pixel; - pdefs->red = priv->red[p]; - pdefs->green = priv->green[p]; - pdefs->blue = priv->blue[p]; - pdefs++; - } -} - -/* - * Change colormap by updating n entries described in pdefs. - */ -void -fbdevPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - int p; - int min, max; - - min = 256; - max = 0; - while (n--) - { - p = pdefs->pixel; - priv->red[p] = pdefs->red; - priv->green[p] = pdefs->green; - priv->blue[p] = pdefs->blue; - if (p < min) - min = p; - if (p > max) - max = p; - pdefs++; - } - - fbdevUpdateFbColormap(priv, min, max); -} +/* + * Copyright © 1999 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "fbdev.h" +#include <sys/ioctl.h> + +#include <errno.h> + +extern int KdTsPhyScreen; + +char *fbdevDevicePath = NULL; + +static Bool +fbdevInitialize (KdCardInfo *card, FbdevPriv *priv) +{ + unsigned long off; + + if (fbdevDevicePath == NULL) + fbdevDevicePath = "/dev/fb0"; + + if ((priv->fd = open(fbdevDevicePath, O_RDWR)) < 0) + { + ErrorF("Error opening framebuffer %s: %s\n", + fbdevDevicePath, strerror(errno)); + return FALSE; + } + + /* quiet valgrind */ + memset (&priv->fix, '\0', sizeof (priv->fix)); + if (ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix) < 0) { + perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO"); + close (priv->fd); + return FALSE; + } + /* quiet valgrind */ + memset (&priv->var, '\0', sizeof (priv->var)); + if (ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var) < 0) { + perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO"); + close (priv->fd); + return FALSE; + } + + priv->fb_base = (char *) mmap ((caddr_t) NULL, + priv->fix.smem_len, + PROT_READ|PROT_WRITE, + MAP_SHARED, + priv->fd, 0); + + if (priv->fb_base == (char *)-1) + { + perror("ERROR: mmap framebuffer fails!"); + close (priv->fd); + return FALSE; + } + off = (unsigned long) priv->fix.smem_start % (unsigned long) getpagesize(); + priv->fb = priv->fb_base + off; + return TRUE; +} + +Bool +fbdevCardInit (KdCardInfo *card) +{ + FbdevPriv *priv; + + priv = (FbdevPriv *) malloc(sizeof (FbdevPriv)); + if (!priv) + return FALSE; + + if (!fbdevInitialize (card, priv)) + { + free(priv); + return FALSE; + } + card->driver = priv; + + return TRUE; +} + +static Pixel +fbdevMakeContig (Pixel orig, Pixel others) +{ + Pixel low; + + low = lowbit (orig) >> 1; + while (low && (others & low) == 0) + { + orig |= low; + low >>= 1; + } + return orig; +} + +static Bool +fbdevModeSupported (KdScreenInfo *screen, + const KdMonitorTiming *t) +{ + return TRUE; +} + +static void +fbdevConvertMonitorTiming (const KdMonitorTiming *t, struct fb_var_screeninfo *var) +{ + memset (var, 0, sizeof (struct fb_var_screeninfo)); + + var->xres = t->horizontal; + var->yres = t->vertical; + var->xres_virtual = t->horizontal; + var->yres_virtual = t->vertical; + var->xoffset = 0; + var->yoffset = 0; + var->pixclock = t->clock ? 1000000000 / t->clock : 0; + var->left_margin = t->hbp; + var->right_margin = t->hfp; + var->upper_margin = t->vbp; + var->lower_margin = t->vfp; + var->hsync_len = t->hblank - t->hfp - t->hbp; + var->vsync_len = t->vblank - t->vfp - t->vbp; + + var->sync = 0; + var->vmode = 0; + + if (t->hpol == KdSyncPositive) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (t->vpol == KdSyncPositive) + var->sync |= FB_SYNC_VERT_HIGH_ACT; +} + +static Bool +fbdevScreenInitialize (KdScreenInfo *screen, FbdevScrPriv *scrpriv) +{ + FbdevPriv *priv = screen->card->driver; + Pixel allbits; + int depth; + Bool gray; + struct fb_var_screeninfo var; + const KdMonitorTiming *t; + int k; + + k = ioctl (priv->fd, FBIOGET_VSCREENINFO, &var); + + if (!screen->width || !screen->height) + { + if (k >= 0) + { + screen->width = var.xres; + screen->height = var.yres; + } + else + { + screen->width = 1024; + screen->height = 768; + } + screen->rate = 103; /* FIXME: should get proper value from fb driver */ + } + if (!screen->fb.depth) + { + if (k >= 0) + screen->fb.depth = var.bits_per_pixel; + else + screen->fb.depth = 16; + } + + if ((screen->width != var.xres) || (screen->height != var.yres)) + { + t = KdFindMode (screen, fbdevModeSupported); + screen->rate = t->rate; + screen->width = t->horizontal; + screen->height = t->vertical; + + /* Now try setting the mode */ + if (k < 0 || (t->horizontal != var.xres || t->vertical != var.yres)) + fbdevConvertMonitorTiming (t, &var); + } + + var.activate = FB_ACTIVATE_NOW; + var.bits_per_pixel = screen->fb.depth; + var.nonstd = 0; + var.grayscale = 0; + + k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &var); + + if (k < 0) + { + fprintf (stderr, "error: %s\n", strerror (errno)); + return FALSE; + } + + /* Re-get the "fixed" parameters since they might have changed */ + k = ioctl (priv->fd, FBIOGET_FSCREENINFO, &priv->fix); + if (k < 0) + perror ("FBIOGET_FSCREENINFO"); + + /* Now get the new screeninfo */ + ioctl (priv->fd, FBIOGET_VSCREENINFO, &priv->var); + depth = priv->var.bits_per_pixel; + gray = priv->var.grayscale; + + switch (priv->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + if (gray) + { + screen->fb.visuals = (1 << StaticGray); + /* could also support GrayScale, but what's the point? */ + } + else + { + screen->fb.visuals = ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)); + } + screen->fb.blueMask = 0x00; + screen->fb.greenMask = 0x00; + screen->fb.redMask = 0x00; + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + if (gray) + { + screen->fb.visuals = (1 << StaticGray); + } + else + { + screen->fb.visuals = (1 << StaticColor); + } + screen->fb.blueMask = 0x00; + screen->fb.greenMask = 0x00; + screen->fb.redMask = 0x00; + break; + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_DIRECTCOLOR: + screen->fb.visuals = (1 << TrueColor); +#define Mask(o,l) (((1 << l) - 1) << o) + screen->fb.redMask = Mask (priv->var.red.offset, priv->var.red.length); + screen->fb.greenMask = Mask (priv->var.green.offset, priv->var.green.length); + screen->fb.blueMask = Mask (priv->var.blue.offset, priv->var.blue.length); + + /* + * This is a kludge so that Render will work -- fill in the gaps + * in the pixel + */ + screen->fb.redMask = fbdevMakeContig (screen->fb.redMask, + screen->fb.greenMask| + screen->fb.blueMask); + + screen->fb.greenMask = fbdevMakeContig (screen->fb.greenMask, + screen->fb.redMask| + screen->fb.blueMask); + + screen->fb.blueMask = fbdevMakeContig (screen->fb.blueMask, + screen->fb.redMask| + screen->fb.greenMask); + + allbits = screen->fb.redMask | screen->fb.greenMask | screen->fb.blueMask; + depth = 32; + while (depth && !(allbits & (1 << (depth - 1)))) + depth--; + break; + default: + return FALSE; + break; + } + screen->fb.depth = depth; + screen->fb.bitsPerPixel = priv->var.bits_per_pixel; + + scrpriv->randr = screen->randr; + + return fbdevMapFramebuffer (screen); +} + +Bool +fbdevScreenInit (KdScreenInfo *screen) +{ + FbdevScrPriv *scrpriv; + + scrpriv = calloc(1, sizeof (FbdevScrPriv)); + if (!scrpriv) + return FALSE; + screen->driver = scrpriv; + if (!fbdevScreenInitialize (screen, scrpriv)) + { + screen->driver = 0; + free(scrpriv); + return FALSE; + } + return TRUE; +} + +static void * +fbdevWindowLinear (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size, + void *closure) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + + if (!pScreenPriv->enabled) + return 0; + *size = priv->fix.line_length; + return (CARD8 *) priv->fb + row * priv->fix.line_length + offset; +} + +Bool +fbdevMapFramebuffer (KdScreenInfo *screen) +{ + FbdevScrPriv *scrpriv = screen->driver; + KdPointerMatrix m; + FbdevPriv *priv = screen->card->driver; + + if (scrpriv->randr != RR_Rotate_0) + scrpriv->shadow = TRUE; + else + scrpriv->shadow = FALSE; + + KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); + + KdSetPointerMatrix (&m); + + screen->width = priv->var.xres; + screen->height = priv->var.yres; + + if (scrpriv->shadow) + { + if (!KdShadowFbAlloc (screen, + scrpriv->randr & (RR_Rotate_90|RR_Rotate_270))) + return FALSE; + } + else + { + screen->fb.byteStride = priv->fix.line_length; + screen->fb.pixelStride = (priv->fix.line_length * 8 / + priv->var.bits_per_pixel); + screen->fb.frameBuffer = (CARD8 *) (priv->fb); + } + + return TRUE; +} + +static void +fbdevSetScreenSizes (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + FbdevPriv *priv = screen->card->driver; + + if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) + { + pScreen->width = priv->var.xres; + pScreen->height = priv->var.yres; + pScreen->mmWidth = screen->width_mm; + pScreen->mmHeight = screen->height_mm; + } + else + { + pScreen->width = priv->var.yres; + pScreen->height = priv->var.xres; + pScreen->mmWidth = screen->height_mm; + pScreen->mmHeight = screen->width_mm; + } +} + +static Bool +fbdevUnmapFramebuffer (KdScreenInfo *screen) +{ + KdShadowFbFree (screen); + return TRUE; +} + +static Bool +fbdevSetShadow (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + FbdevPriv *priv = screen->card->driver; + ShadowUpdateProc update; + ShadowWindowProc window; + int useYX = 0; + +#ifdef __arm__ + /* Use variant copy routines that always read left to right in the + shadow framebuffer. Reading vertical strips is exceptionally + slow on XScale due to cache effects. */ + useYX = 1; +#endif + + window = fbdevWindowLinear; + update = 0; + if (scrpriv->randr) + if (priv->var.bits_per_pixel == 16) { + switch (scrpriv->randr) { + case RR_Rotate_90: + if (useYX) + update = shadowUpdateRotate16_90YX; + else + update = shadowUpdateRotate16_90; + break; + case RR_Rotate_180: + update = shadowUpdateRotate16_180; + break; + case RR_Rotate_270: + if (useYX) + update = shadowUpdateRotate16_270YX; + else + update = shadowUpdateRotate16_270; + break; + default: + update = shadowUpdateRotate16; + break; + } + } else + update = shadowUpdateRotatePacked; + else + update = shadowUpdatePacked; + return KdShadowSet (pScreen, scrpriv->randr, update, window); +} + + +#ifdef RANDR +static Bool +fbdevRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + RRScreenSizePtr pSize; + Rotation randr; + int n; + + *rotations = RR_Rotate_All|RR_Reflect_All; + + for (n = 0; n < pScreen->numDepths; n++) + if (pScreen->allowedDepths[n].numVids) + break; + if (n == pScreen->numDepths) + return FALSE; + + pSize = RRRegisterSize (pScreen, + screen->width, + screen->height, + screen->width_mm, + screen->height_mm); + + randr = KdSubRotation (scrpriv->randr, screen->randr); + + RRSetCurrentConfig (pScreen, randr, 0, pSize); + + return TRUE; +} + +static Bool +fbdevRandRSetConfig (ScreenPtr pScreen, + Rotation randr, + int rate, + RRScreenSizePtr pSize) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + Bool wasEnabled = pScreenPriv->enabled; + FbdevScrPriv oldscr; + int oldwidth; + int oldheight; + int oldmmwidth; + int oldmmheight; + int newwidth, newheight; + + if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) + { + newwidth = pSize->width; + newheight = pSize->height; + } + else + { + newwidth = pSize->height; + newheight = pSize->width; + } + + if (wasEnabled) + KdDisableScreen (pScreen); + + oldscr = *scrpriv; + + oldwidth = screen->width; + oldheight = screen->height; + oldmmwidth = pScreen->mmWidth; + oldmmheight = pScreen->mmHeight; + + /* + * Set new configuration + */ + + scrpriv->randr = KdAddRotation (screen->randr, randr); + + fbdevUnmapFramebuffer (screen); + + if (!fbdevMapFramebuffer (screen)) + goto bail4; + + KdShadowUnset (screen->pScreen); + + if (!fbdevSetShadow (screen->pScreen)) + goto bail4; + + fbdevSetScreenSizes (screen->pScreen); + + /* + * Set frame buffer mapping + */ + (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), + pScreen->width, + pScreen->height, + screen->fb.depth, + screen->fb.bitsPerPixel, + screen->fb.byteStride, + screen->fb.frameBuffer); + + /* set the subpixel order */ + + KdSetSubpixelOrder (pScreen, scrpriv->randr); + if (wasEnabled) + KdEnableScreen (pScreen); + + return TRUE; + +bail4: + fbdevUnmapFramebuffer (screen); + *scrpriv = oldscr; + (void) fbdevMapFramebuffer (screen); + pScreen->width = oldwidth; + pScreen->height = oldheight; + pScreen->mmWidth = oldmmwidth; + pScreen->mmHeight = oldmmheight; + + if (wasEnabled) + KdEnableScreen (pScreen); + return FALSE; +} + +static Bool +fbdevRandRInit (ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) + return FALSE; + + pScrPriv = rrGetScrPriv(pScreen); + pScrPriv->rrGetInfo = fbdevRandRGetInfo; + pScrPriv->rrSetConfig = fbdevRandRSetConfig; + return TRUE; +} +#endif + +static Bool +fbdevCreateColormap (ColormapPtr pmap) +{ + ScreenPtr pScreen = pmap->pScreen; + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + VisualPtr pVisual; + int i; + int nent; + xColorItem *pdefs; + + switch (priv->fix.visual) { + case FB_VISUAL_STATIC_PSEUDOCOLOR: + pVisual = pmap->pVisual; + nent = pVisual->ColormapEntries; + pdefs = malloc(nent * sizeof (xColorItem)); + if (!pdefs) + return FALSE; + for (i = 0; i < nent; i++) + pdefs[i].pixel = i; + fbdevGetColors (pScreen, nent, pdefs); + for (i = 0; i < nent; i++) + { + pmap->red[i].co.local.red = pdefs[i].red; + pmap->red[i].co.local.green = pdefs[i].green; + pmap->red[i].co.local.blue = pdefs[i].blue; + } + free(pdefs); + return TRUE; + default: + return fbInitializeColormap (pmap); + } +} + +Bool +fbdevInitScreen (ScreenPtr pScreen) +{ +#ifdef TOUCHSCREEN + KdTsPhyScreen = pScreen->myNum; +#endif + + pScreen->CreateColormap = fbdevCreateColormap; + return TRUE; +} + +Bool +fbdevFinishInitScreen (ScreenPtr pScreen) +{ + if (!shadowSetup (pScreen)) + return FALSE; + +#ifdef RANDR + if (!fbdevRandRInit (pScreen)) + return FALSE; +#endif + + return TRUE; +} + + +Bool +fbdevCreateResources (ScreenPtr pScreen) +{ + return fbdevSetShadow (pScreen); +} + +void +fbdevPreserve (KdCardInfo *card) +{ +} + +static int +fbdevUpdateFbColormap(FbdevPriv *priv, int minidx, int maxidx) +{ + struct fb_cmap cmap; + + cmap.start = minidx; + cmap.len = maxidx - minidx + 1; + cmap.red = &priv->red[minidx]; + cmap.green = &priv->green[minidx]; + cmap.blue = &priv->blue[minidx]; + cmap.transp = 0; + + return ioctl(priv->fd, FBIOPUTCMAP, &cmap); +} + +Bool +fbdevEnable (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + int k; + + priv->var.activate = FB_ACTIVATE_NOW|FB_CHANGE_CMAP_VBL; + + /* display it on the LCD */ + k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &priv->var); + if (k < 0) + { + perror ("FBIOPUT_VSCREENINFO"); + return FALSE; + } + + if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR) + { + int i; + + for (i = 0; + i < (1 << priv->var.red.length) || + i < (1 << priv->var.green.length) || + i < (1 << priv->var.blue.length); i++) + { + priv->red[i] = i * 65535 / ((1 << priv->var.red.length) - 1); + priv->green[i] = i * 65535 / ((1 << priv->var.green.length) - 1); + priv->blue[i] = i * 65535 / ((1 << priv->var.blue.length) - 1); + } + + fbdevUpdateFbColormap(priv, 0, i); + } + return TRUE; +} + +Bool +fbdevDPMS (ScreenPtr pScreen, int mode) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + static int oldmode = -1; + + if (mode == oldmode) + return TRUE; +#ifdef FBIOPUT_POWERMODE + if (ioctl (priv->fd, FBIOPUT_POWERMODE, &mode) >= 0) + { + oldmode = mode; + return TRUE; + } +#endif +#ifdef FBIOBLANK + if (ioctl (priv->fd, FBIOBLANK, mode ? mode + 1 : 0) >= 0) + { + oldmode = mode; + return TRUE; + } +#endif + return FALSE; +} + +void +fbdevDisable (ScreenPtr pScreen) +{ +} + +void +fbdevRestore (KdCardInfo *card) +{ +} + +void +fbdevScreenFini (KdScreenInfo *screen) +{ +} + +void +fbdevCardFini (KdCardInfo *card) +{ + FbdevPriv *priv = card->driver; + + munmap (priv->fb_base, priv->fix.smem_len); + close (priv->fd); + free(priv); +} + +/* + * Retrieve actual colormap and return selected n entries in pdefs. + */ +void +fbdevGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + struct fb_cmap cmap; + int p; + int k; + int min, max; + + min = 256; + max = 0; + for (k = 0; k < n; k++) + { + if (pdefs[k].pixel < min) + min = pdefs[k].pixel; + if (pdefs[k].pixel > max) + max = pdefs[k].pixel; + } + cmap.start = min; + cmap.len = max - min + 1; + cmap.red = &priv->red[min]; + cmap.green = &priv->green[min]; + cmap.blue = &priv->blue[min]; + cmap.transp = 0; + k = ioctl (priv->fd, FBIOGETCMAP, &cmap); + if (k < 0) + { + perror ("can't get colormap"); + return; + } + while (n--) + { + p = pdefs->pixel; + pdefs->red = priv->red[p]; + pdefs->green = priv->green[p]; + pdefs->blue = priv->blue[p]; + pdefs++; + } +} + +/* + * Change colormap by updating n entries described in pdefs. + */ +void +fbdevPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + int p; + int min, max; + + min = 256; + max = 0; + while (n--) + { + p = pdefs->pixel; + priv->red[p] = pdefs->red; + priv->green[p] = pdefs->green; + priv->blue[p] = pdefs->blue; + if (p < min) + min = p; + if (p > max) + max = p; + pdefs++; + } + + fbdevUpdateFbColormap(priv, min, max); +} diff --git a/xorg-server/hw/kdrive/linux/evdev.c b/xorg-server/hw/kdrive/linux/evdev.c index 0e4c9f735..20df77b99 100644 --- a/xorg-server/hw/kdrive/linux/evdev.c +++ b/xorg-server/hw/kdrive/linux/evdev.c @@ -1,539 +1,539 @@ -/* - * Copyright © 2004 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include <errno.h> -#include <linux/input.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/Xpoll.h> -#include "inputstr.h" -#include "scrnintstr.h" -#include "kdrive.h" - -#define NUM_EVENTS 128 -#define ABS_UNSET -65535 - -#define BITS_PER_LONG (sizeof(long) * 8) -#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) -#define ISBITSET(x,y) ((x)[LONG(y)] & BIT(y)) -#define OFF(x) ((x)%BITS_PER_LONG) -#define LONG(x) ((x)/BITS_PER_LONG) -#define BIT(x) (1 << OFF(x)) - -typedef struct _kevdev { - /* current device state */ - int rel[REL_MAX + 1]; - int abs[ABS_MAX + 1]; - int prevabs[ABS_MAX + 1]; - long key[NBITS(KEY_MAX + 1)]; - - /* supported device info */ - long relbits[NBITS(REL_MAX + 1)]; - long absbits[NBITS(ABS_MAX + 1)]; - long keybits[NBITS(KEY_MAX + 1)]; - struct input_absinfo absinfo[ABS_MAX + 1]; - int max_rel; - int max_abs; - - int fd; -} Kevdev; - -static void -EvdevPtrBtn (KdPointerInfo *pi, struct input_event *ev) -{ - int flags = KD_MOUSE_DELTA | pi->buttonState; - - if (ev->code >= BTN_MOUSE && ev->code < BTN_JOYSTICK) { - switch (ev->code) { - case BTN_LEFT: - if (ev->value == 1) - flags |= KD_BUTTON_1; - else - flags &= ~KD_BUTTON_1; - break; - case BTN_MIDDLE: - if (ev->value == 1) - flags |= KD_BUTTON_2; - else - flags &= ~KD_BUTTON_2; - break; - case BTN_RIGHT: - if (ev->value == 1) - flags |= KD_BUTTON_3; - else - flags &= ~KD_BUTTON_3; - break; - default: - /* Unknow button */ - break; - } - - KdEnqueuePointerEvent (pi, flags, 0, 0, 0); - } -} -static void -EvdevPtrMotion (KdPointerInfo *pi, struct input_event *ev) -{ - Kevdev *ke = pi->driverPrivate; - int i; - int flags = KD_MOUSE_DELTA | pi->buttonState; - - for (i = 0; i <= ke->max_rel; i++) - if (ke->rel[i]) - { - int a; - for (a = 0; a <= ke->max_rel; a++) - { - if (ISBITSET (ke->relbits, a)) - { - if (a == 0) - KdEnqueuePointerEvent(pi, flags, ke->rel[a], 0, 0); - else if (a == 1) - KdEnqueuePointerEvent(pi, flags, 0, ke->rel[a], 0); - } - ke->rel[a] = 0; - } - break; - } - for (i = 0; i < ke->max_abs; i++) - if (ke->abs[i] != ke->prevabs[i]) - { - int a; - ErrorF ("abs"); - for (a = 0; a <= ke->max_abs; a++) - { - if (ISBITSET (ke->absbits, a)) - ErrorF (" %d=%d", a, ke->abs[a]); - ke->prevabs[a] = ke->abs[a]; - } - ErrorF ("\n"); - break; - } - - if (ev->code == REL_WHEEL) { - for (i = 0; i < abs (ev->value); i++) - { - if (ev->value > 0) - flags |= KD_BUTTON_4; - else - flags |= KD_BUTTON_5; - - KdEnqueuePointerEvent (pi, flags, 0, 0, 0); - - if (ev->value > 0) - flags &= ~KD_BUTTON_4; - else - flags &= ~KD_BUTTON_5; - - KdEnqueuePointerEvent (pi, flags, 0, 0, 0); - } - } - -} - -static void -EvdevPtrRead (int evdevPort, void *closure) -{ - KdPointerInfo *pi = closure; - Kevdev *ke = pi->driverPrivate; - int i; - struct input_event events[NUM_EVENTS]; - int n; - - n = read (evdevPort, &events, NUM_EVENTS * sizeof (struct input_event)); - if (n <= 0) { - if (errno == ENODEV) - DeleteInputDeviceRequest(pi->dixdev); - return; - } - - n /= sizeof (struct input_event); - for (i = 0; i < n; i++) - { - switch (events[i].type) { - case EV_SYN: - break; - case EV_KEY: - EvdevPtrBtn (pi, &events[i]); - break; - case EV_REL: - ke->rel[events[i].code] += events[i].value; - EvdevPtrMotion (pi, &events[i]); - break; - case EV_ABS: - ke->abs[events[i].code] = events[i].value; - EvdevPtrMotion (pi, &events[i]); - break; - } - } -} - -char *kdefaultEvdev[] = { - "/dev/input/event0", - "/dev/input/event1", - "/dev/input/event2", - "/dev/input/event3", -}; - -#define NUM_DEFAULT_EVDEV (sizeof (kdefaultEvdev) / sizeof (kdefaultEvdev[0])) - -static Status -EvdevPtrInit (KdPointerInfo *pi) -{ - int i; - int fd; - - if (!pi->path) { - for (i = 0; i < NUM_DEFAULT_EVDEV; i++) { - fd = open (kdefaultEvdev[i], 2); - if (fd >= 0) { - pi->path = strdup (kdefaultEvdev[i]); - break; - } - } - } - else { - fd = open (pi->path, O_RDWR); - if (fd < 0) { - ErrorF("Failed to open evdev device %s\n", pi->path); - return BadMatch; - } - } - - close(fd); - - pi->name = strdup("Evdev mouse"); - - return Success; -} - -static Status -EvdevPtrEnable (KdPointerInfo *pi) -{ - int fd; - unsigned long ev[NBITS(EV_MAX)]; - Kevdev *ke; - - if (!pi || !pi->path) - return BadImplementation; - - fd = open(pi->path, 2); - if (fd < 0) - return BadMatch; - - if (ioctl (fd, EVIOCGRAB, 1) < 0) - perror ("Grabbing evdev mouse device failed"); - - if (ioctl (fd, EVIOCGBIT(0 /*EV*/, sizeof (ev)), ev) < 0) - { - perror ("EVIOCGBIT 0"); - close (fd); - return BadMatch; - } - ke = xcalloc (1, sizeof (Kevdev)); - if (!ke) - { - close (fd); - return BadAlloc; - } - if (ISBITSET (ev, EV_KEY)) - { - if (ioctl (fd, EVIOCGBIT (EV_KEY, sizeof (ke->keybits)), - ke->keybits) < 0) - { - perror ("EVIOCGBIT EV_KEY"); - xfree (ke); - close (fd); - return BadMatch; - } - } - if (ISBITSET (ev, EV_REL)) - { - if (ioctl (fd, EVIOCGBIT (EV_REL, sizeof (ke->relbits)), - ke->relbits) < 0) - { - perror ("EVIOCGBIT EV_REL"); - xfree (ke); - close (fd); - return BadMatch; - } - for (ke->max_rel = REL_MAX; ke->max_rel >= 0; ke->max_rel--) - if (ISBITSET(ke->relbits, ke->max_rel)) - break; - } - if (ISBITSET (ev, EV_ABS)) - { - int i; - - if (ioctl (fd, EVIOCGBIT (EV_ABS, sizeof (ke->absbits)), - ke->absbits) < 0) - { - perror ("EVIOCGBIT EV_ABS"); - xfree (ke); - close (fd); - return BadMatch; - } - for (ke->max_abs = ABS_MAX; ke->max_abs >= 0; ke->max_abs--) - if (ISBITSET(ke->absbits, ke->max_abs)) - break; - for (i = 0; i <= ke->max_abs; i++) - { - if (ISBITSET (ke->absbits, i)) - if (ioctl (fd, EVIOCGABS(i), &ke->absinfo[i]) < 0) - { - perror ("EVIOCGABS"); - break; - } - ke->prevabs[i] = ABS_UNSET; - } - if (i <= ke->max_abs) - { - xfree (ke); - close (fd); - return BadValue; - } - } - if (!KdRegisterFd (fd, EvdevPtrRead, pi)) { - xfree (ke); - close (fd); - return BadAlloc; - } - pi->driverPrivate = ke; - ke->fd = fd; - - return Success; -} - -static void -EvdevPtrDisable (KdPointerInfo *pi) -{ - Kevdev *ke; - - ke = pi->driverPrivate; - - if (!pi || !pi->driverPrivate) - return; - - KdUnregisterFd (pi, ke->fd, TRUE); - - if (ioctl (ke->fd, EVIOCGRAB, 0) < 0) - perror ("Ungrabbing evdev mouse device failed"); - - xfree (ke); - pi->driverPrivate = 0; -} - -static void -EvdevPtrFini (KdPointerInfo *pi) -{ -} - - -/* - * Evdev keyboard functions - */ - -static void -readMapping (KdKeyboardInfo *ki) -{ - if (!ki) - return; - - ki->minScanCode = 0; - ki->maxScanCode = 247; -} - -static void -EvdevKbdRead (int evdevPort, void *closure) -{ - KdKeyboardInfo *ki = closure; - struct input_event events[NUM_EVENTS]; - int i, n; - - n = read (evdevPort, &events, NUM_EVENTS * sizeof (struct input_event)); - if (n <= 0) { - if (errno == ENODEV) - DeleteInputDeviceRequest(ki->dixdev); - return; - } - - n /= sizeof (struct input_event); - for (i = 0; i < n; i++) - { - if (events[i].type == EV_KEY) - KdEnqueueKeyboardEvent (ki, events[i].code, !events[i].value); -/* FIXME: must implement other types of events - else - ErrorF("Event type (%d) not delivered\n", events[i].type); -*/ - } -} - -static Status -EvdevKbdInit (KdKeyboardInfo *ki) -{ - int fd; - - if (!ki->path) { - ErrorF("Couldn't find evdev device path\n"); - return BadValue; - } - else { - fd = open (ki->path, O_RDWR); - if (fd < 0) { - ErrorF("Failed to open evdev device %s\n", ki->path); - return BadMatch; - } - } - - close (fd); - - ki->name = strdup("Evdev keyboard"); - - readMapping(ki); - - return Success; -} - -static Status -EvdevKbdEnable (KdKeyboardInfo *ki) -{ - unsigned long ev[NBITS(EV_MAX)]; - Kevdev *ke; - int fd; - - if (!ki || !ki->path) - return BadImplementation; - - fd = open(ki->path, O_RDWR); - if (fd < 0) - return BadMatch; - - if (ioctl (fd, EVIOCGRAB, 1) < 0) - perror ("Grabbing evdev keyboard device failed"); - - if (ioctl (fd, EVIOCGBIT(0 /*EV*/, sizeof (ev)), ev) < 0) { - perror ("EVIOCGBIT 0"); - close (fd); - return BadMatch; - } - - ke = xcalloc (1, sizeof (Kevdev)); - if (!ke) { - close (fd); - return BadAlloc; - } - - if (!KdRegisterFd (fd, EvdevKbdRead, ki)) { - xfree (ke); - close (fd); - return BadAlloc; - } - ki->driverPrivate = ke; - ke->fd = fd; - - return Success; -} - -static void -EvdevKbdLeds (KdKeyboardInfo *ki, int leds) -{ -/* struct input_event event; - Kevdev *ke; - - ki->driverPrivate = ke; - - memset(&event, 0, sizeof(event)); - - event.type = EV_LED; - event.code = LED_CAPSL; - event.value = leds & (1 << 0) ? 1 : 0; - write(ke->fd, (char *) &event, sizeof(event)); - - event.type = EV_LED; - event.code = LED_NUML; - event.value = leds & (1 << 1) ? 1 : 0; - write(ke->fd, (char *) &event, sizeof(event)); - - event.type = EV_LED; - event.code = LED_SCROLLL; - event.value = leds & (1 << 2) ? 1 : 0; - write(ke->fd, (char *) &event, sizeof(event)); - - event.type = EV_LED; - event.code = LED_COMPOSE; - event.value = leds & (1 << 3) ? 1 : 0; - write(ke->fd, (char *) &event, sizeof(event)); -*/ -} - -static void -EvdevKbdBell (KdKeyboardInfo *ki, int volume, int frequency, int duration) -{ -} - -static void -EvdevKbdDisable (KdKeyboardInfo *ki) -{ - Kevdev *ke; - - ke = ki->driverPrivate; - - if (!ki || !ki->driverPrivate) - return; - - KdUnregisterFd (ki, ke->fd, TRUE); - - if (ioctl (ke->fd, EVIOCGRAB, 0) < 0) - perror ("Ungrabbing evdev keyboard device failed"); - - xfree (ke); - ki->driverPrivate = 0; -} - -static void -EvdevKbdFini (KdKeyboardInfo *ki) -{ -} - -KdPointerDriver LinuxEvdevMouseDriver = { - "evdev", - EvdevPtrInit, - EvdevPtrEnable, - EvdevPtrDisable, - EvdevPtrFini, - NULL, -}; - -KdKeyboardDriver LinuxEvdevKeyboardDriver = { - "evdev", - EvdevKbdInit, - EvdevKbdEnable, - EvdevKbdLeds, - EvdevKbdBell, - EvdevKbdDisable, - EvdevKbdFini, - NULL, -}; +/* + * Copyright © 2004 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include <errno.h> +#include <linux/input.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/Xpoll.h> +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" + +#define NUM_EVENTS 128 +#define ABS_UNSET -65535 + +#define BITS_PER_LONG (sizeof(long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define ISBITSET(x,y) ((x)[LONG(y)] & BIT(y)) +#define OFF(x) ((x)%BITS_PER_LONG) +#define LONG(x) ((x)/BITS_PER_LONG) +#define BIT(x) (1 << OFF(x)) + +typedef struct _kevdev { + /* current device state */ + int rel[REL_MAX + 1]; + int abs[ABS_MAX + 1]; + int prevabs[ABS_MAX + 1]; + long key[NBITS(KEY_MAX + 1)]; + + /* supported device info */ + long relbits[NBITS(REL_MAX + 1)]; + long absbits[NBITS(ABS_MAX + 1)]; + long keybits[NBITS(KEY_MAX + 1)]; + struct input_absinfo absinfo[ABS_MAX + 1]; + int max_rel; + int max_abs; + + int fd; +} Kevdev; + +static void +EvdevPtrBtn (KdPointerInfo *pi, struct input_event *ev) +{ + int flags = KD_MOUSE_DELTA | pi->buttonState; + + if (ev->code >= BTN_MOUSE && ev->code < BTN_JOYSTICK) { + switch (ev->code) { + case BTN_LEFT: + if (ev->value == 1) + flags |= KD_BUTTON_1; + else + flags &= ~KD_BUTTON_1; + break; + case BTN_MIDDLE: + if (ev->value == 1) + flags |= KD_BUTTON_2; + else + flags &= ~KD_BUTTON_2; + break; + case BTN_RIGHT: + if (ev->value == 1) + flags |= KD_BUTTON_3; + else + flags &= ~KD_BUTTON_3; + break; + default: + /* Unknow button */ + break; + } + + KdEnqueuePointerEvent (pi, flags, 0, 0, 0); + } +} +static void +EvdevPtrMotion (KdPointerInfo *pi, struct input_event *ev) +{ + Kevdev *ke = pi->driverPrivate; + int i; + int flags = KD_MOUSE_DELTA | pi->buttonState; + + for (i = 0; i <= ke->max_rel; i++) + if (ke->rel[i]) + { + int a; + for (a = 0; a <= ke->max_rel; a++) + { + if (ISBITSET (ke->relbits, a)) + { + if (a == 0) + KdEnqueuePointerEvent(pi, flags, ke->rel[a], 0, 0); + else if (a == 1) + KdEnqueuePointerEvent(pi, flags, 0, ke->rel[a], 0); + } + ke->rel[a] = 0; + } + break; + } + for (i = 0; i < ke->max_abs; i++) + if (ke->abs[i] != ke->prevabs[i]) + { + int a; + ErrorF ("abs"); + for (a = 0; a <= ke->max_abs; a++) + { + if (ISBITSET (ke->absbits, a)) + ErrorF (" %d=%d", a, ke->abs[a]); + ke->prevabs[a] = ke->abs[a]; + } + ErrorF ("\n"); + break; + } + + if (ev->code == REL_WHEEL) { + for (i = 0; i < abs (ev->value); i++) + { + if (ev->value > 0) + flags |= KD_BUTTON_4; + else + flags |= KD_BUTTON_5; + + KdEnqueuePointerEvent (pi, flags, 0, 0, 0); + + if (ev->value > 0) + flags &= ~KD_BUTTON_4; + else + flags &= ~KD_BUTTON_5; + + KdEnqueuePointerEvent (pi, flags, 0, 0, 0); + } + } + +} + +static void +EvdevPtrRead (int evdevPort, void *closure) +{ + KdPointerInfo *pi = closure; + Kevdev *ke = pi->driverPrivate; + int i; + struct input_event events[NUM_EVENTS]; + int n; + + n = read (evdevPort, &events, NUM_EVENTS * sizeof (struct input_event)); + if (n <= 0) { + if (errno == ENODEV) + DeleteInputDeviceRequest(pi->dixdev); + return; + } + + n /= sizeof (struct input_event); + for (i = 0; i < n; i++) + { + switch (events[i].type) { + case EV_SYN: + break; + case EV_KEY: + EvdevPtrBtn (pi, &events[i]); + break; + case EV_REL: + ke->rel[events[i].code] += events[i].value; + EvdevPtrMotion (pi, &events[i]); + break; + case EV_ABS: + ke->abs[events[i].code] = events[i].value; + EvdevPtrMotion (pi, &events[i]); + break; + } + } +} + +char *kdefaultEvdev[] = { + "/dev/input/event0", + "/dev/input/event1", + "/dev/input/event2", + "/dev/input/event3", +}; + +#define NUM_DEFAULT_EVDEV (sizeof (kdefaultEvdev) / sizeof (kdefaultEvdev[0])) + +static Status +EvdevPtrInit (KdPointerInfo *pi) +{ + int i; + int fd; + + if (!pi->path) { + for (i = 0; i < NUM_DEFAULT_EVDEV; i++) { + fd = open (kdefaultEvdev[i], 2); + if (fd >= 0) { + pi->path = strdup (kdefaultEvdev[i]); + break; + } + } + } + else { + fd = open (pi->path, O_RDWR); + if (fd < 0) { + ErrorF("Failed to open evdev device %s\n", pi->path); + return BadMatch; + } + } + + close(fd); + + pi->name = strdup("Evdev mouse"); + + return Success; +} + +static Status +EvdevPtrEnable (KdPointerInfo *pi) +{ + int fd; + unsigned long ev[NBITS(EV_MAX)]; + Kevdev *ke; + + if (!pi || !pi->path) + return BadImplementation; + + fd = open(pi->path, 2); + if (fd < 0) + return BadMatch; + + if (ioctl (fd, EVIOCGRAB, 1) < 0) + perror ("Grabbing evdev mouse device failed"); + + if (ioctl (fd, EVIOCGBIT(0 /*EV*/, sizeof (ev)), ev) < 0) + { + perror ("EVIOCGBIT 0"); + close (fd); + return BadMatch; + } + ke = calloc(1, sizeof (Kevdev)); + if (!ke) + { + close (fd); + return BadAlloc; + } + if (ISBITSET (ev, EV_KEY)) + { + if (ioctl (fd, EVIOCGBIT (EV_KEY, sizeof (ke->keybits)), + ke->keybits) < 0) + { + perror ("EVIOCGBIT EV_KEY"); + free(ke); + close (fd); + return BadMatch; + } + } + if (ISBITSET (ev, EV_REL)) + { + if (ioctl (fd, EVIOCGBIT (EV_REL, sizeof (ke->relbits)), + ke->relbits) < 0) + { + perror ("EVIOCGBIT EV_REL"); + free(ke); + close (fd); + return BadMatch; + } + for (ke->max_rel = REL_MAX; ke->max_rel >= 0; ke->max_rel--) + if (ISBITSET(ke->relbits, ke->max_rel)) + break; + } + if (ISBITSET (ev, EV_ABS)) + { + int i; + + if (ioctl (fd, EVIOCGBIT (EV_ABS, sizeof (ke->absbits)), + ke->absbits) < 0) + { + perror ("EVIOCGBIT EV_ABS"); + free(ke); + close (fd); + return BadMatch; + } + for (ke->max_abs = ABS_MAX; ke->max_abs >= 0; ke->max_abs--) + if (ISBITSET(ke->absbits, ke->max_abs)) + break; + for (i = 0; i <= ke->max_abs; i++) + { + if (ISBITSET (ke->absbits, i)) + if (ioctl (fd, EVIOCGABS(i), &ke->absinfo[i]) < 0) + { + perror ("EVIOCGABS"); + break; + } + ke->prevabs[i] = ABS_UNSET; + } + if (i <= ke->max_abs) + { + free(ke); + close (fd); + return BadValue; + } + } + if (!KdRegisterFd (fd, EvdevPtrRead, pi)) { + free(ke); + close (fd); + return BadAlloc; + } + pi->driverPrivate = ke; + ke->fd = fd; + + return Success; +} + +static void +EvdevPtrDisable (KdPointerInfo *pi) +{ + Kevdev *ke; + + ke = pi->driverPrivate; + + if (!pi || !pi->driverPrivate) + return; + + KdUnregisterFd (pi, ke->fd, TRUE); + + if (ioctl (ke->fd, EVIOCGRAB, 0) < 0) + perror ("Ungrabbing evdev mouse device failed"); + + free(ke); + pi->driverPrivate = 0; +} + +static void +EvdevPtrFini (KdPointerInfo *pi) +{ +} + + +/* + * Evdev keyboard functions + */ + +static void +readMapping (KdKeyboardInfo *ki) +{ + if (!ki) + return; + + ki->minScanCode = 0; + ki->maxScanCode = 247; +} + +static void +EvdevKbdRead (int evdevPort, void *closure) +{ + KdKeyboardInfo *ki = closure; + struct input_event events[NUM_EVENTS]; + int i, n; + + n = read (evdevPort, &events, NUM_EVENTS * sizeof (struct input_event)); + if (n <= 0) { + if (errno == ENODEV) + DeleteInputDeviceRequest(ki->dixdev); + return; + } + + n /= sizeof (struct input_event); + for (i = 0; i < n; i++) + { + if (events[i].type == EV_KEY) + KdEnqueueKeyboardEvent (ki, events[i].code, !events[i].value); +/* FIXME: must implement other types of events + else + ErrorF("Event type (%d) not delivered\n", events[i].type); +*/ + } +} + +static Status +EvdevKbdInit (KdKeyboardInfo *ki) +{ + int fd; + + if (!ki->path) { + ErrorF("Couldn't find evdev device path\n"); + return BadValue; + } + else { + fd = open (ki->path, O_RDWR); + if (fd < 0) { + ErrorF("Failed to open evdev device %s\n", ki->path); + return BadMatch; + } + } + + close (fd); + + ki->name = strdup("Evdev keyboard"); + + readMapping(ki); + + return Success; +} + +static Status +EvdevKbdEnable (KdKeyboardInfo *ki) +{ + unsigned long ev[NBITS(EV_MAX)]; + Kevdev *ke; + int fd; + + if (!ki || !ki->path) + return BadImplementation; + + fd = open(ki->path, O_RDWR); + if (fd < 0) + return BadMatch; + + if (ioctl (fd, EVIOCGRAB, 1) < 0) + perror ("Grabbing evdev keyboard device failed"); + + if (ioctl (fd, EVIOCGBIT(0 /*EV*/, sizeof (ev)), ev) < 0) { + perror ("EVIOCGBIT 0"); + close (fd); + return BadMatch; + } + + ke = calloc(1, sizeof (Kevdev)); + if (!ke) { + close (fd); + return BadAlloc; + } + + if (!KdRegisterFd (fd, EvdevKbdRead, ki)) { + free(ke); + close (fd); + return BadAlloc; + } + ki->driverPrivate = ke; + ke->fd = fd; + + return Success; +} + +static void +EvdevKbdLeds (KdKeyboardInfo *ki, int leds) +{ +/* struct input_event event; + Kevdev *ke; + + ki->driverPrivate = ke; + + memset(&event, 0, sizeof(event)); + + event.type = EV_LED; + event.code = LED_CAPSL; + event.value = leds & (1 << 0) ? 1 : 0; + write(ke->fd, (char *) &event, sizeof(event)); + + event.type = EV_LED; + event.code = LED_NUML; + event.value = leds & (1 << 1) ? 1 : 0; + write(ke->fd, (char *) &event, sizeof(event)); + + event.type = EV_LED; + event.code = LED_SCROLLL; + event.value = leds & (1 << 2) ? 1 : 0; + write(ke->fd, (char *) &event, sizeof(event)); + + event.type = EV_LED; + event.code = LED_COMPOSE; + event.value = leds & (1 << 3) ? 1 : 0; + write(ke->fd, (char *) &event, sizeof(event)); +*/ +} + +static void +EvdevKbdBell (KdKeyboardInfo *ki, int volume, int frequency, int duration) +{ +} + +static void +EvdevKbdDisable (KdKeyboardInfo *ki) +{ + Kevdev *ke; + + ke = ki->driverPrivate; + + if (!ki || !ki->driverPrivate) + return; + + KdUnregisterFd (ki, ke->fd, TRUE); + + if (ioctl (ke->fd, EVIOCGRAB, 0) < 0) + perror ("Ungrabbing evdev keyboard device failed"); + + free(ke); + ki->driverPrivate = 0; +} + +static void +EvdevKbdFini (KdKeyboardInfo *ki) +{ +} + +KdPointerDriver LinuxEvdevMouseDriver = { + "evdev", + EvdevPtrInit, + EvdevPtrEnable, + EvdevPtrDisable, + EvdevPtrFini, + NULL, +}; + +KdKeyboardDriver LinuxEvdevKeyboardDriver = { + "evdev", + EvdevKbdInit, + EvdevKbdEnable, + EvdevKbdLeds, + EvdevKbdBell, + EvdevKbdDisable, + EvdevKbdFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/linux/keyboard.c b/xorg-server/hw/kdrive/linux/keyboard.c index 6eed7aed3..c888d14dc 100644 --- a/xorg-server/hw/kdrive/linux/keyboard.c +++ b/xorg-server/hw/kdrive/linux/keyboard.c @@ -1,765 +1,765 @@ -/* - * Copyright © 1999 Keith Packard - * XKB integration © 2006 Nokia Corporation, author: Tomas Frydrych <tf@o-hand.com> - * - * LinuxKeyboardRead() XKB code based on xf86KbdLnx.c: - * Copyright © 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * Copyright © 1994-2001 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -#ifdef HAVE_CONFIG_H -#include <kdrive-config.h> -#endif -#include "kdrive.h" -#include <linux/keyboard.h> -#include <linux/kd.h> -#define XK_PUBLISHING -#include <X11/keysym.h> -#include <termios.h> -#include <sys/ioctl.h> - -extern int LinuxConsoleFd; - -static const KeySym linux_to_x[256] = { - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, XK_Escape, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - XK_space, XK_exclam, XK_quotedbl, XK_numbersign, - XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, - XK_parenleft, XK_parenright, XK_asterisk, XK_plus, - XK_comma, XK_minus, XK_period, XK_slash, - XK_0, XK_1, XK_2, XK_3, - XK_4, XK_5, XK_6, XK_7, - XK_8, XK_9, XK_colon, XK_semicolon, - XK_less, XK_equal, XK_greater, XK_question, - XK_at, XK_A, XK_B, XK_C, - XK_D, XK_E, XK_F, XK_G, - XK_H, XK_I, XK_J, XK_K, - XK_L, XK_M, XK_N, XK_O, - XK_P, XK_Q, XK_R, XK_S, - XK_T, XK_U, XK_V, XK_W, - XK_X, XK_Y, XK_Z, XK_bracketleft, - XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore, - XK_grave, XK_a, XK_b, XK_c, - XK_d, XK_e, XK_f, XK_g, - XK_h, XK_i, XK_j, XK_k, - XK_l, XK_m, XK_n, XK_o, - XK_p, XK_q, XK_r, XK_s, - XK_t, XK_u, XK_v, XK_w, - XK_x, XK_y, XK_z, XK_braceleft, - XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling, - XK_currency, XK_yen, XK_brokenbar, XK_section, - XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, - XK_notsign, XK_hyphen, XK_registered, XK_macron, - XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, - XK_acute, XK_mu, XK_paragraph, XK_periodcentered, - XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, - XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown, - XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, - XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, - XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, - XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, - XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, - XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, - XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, - XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, - XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, - XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, - XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, - XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, - XK_eth, XK_ntilde, XK_ograve, XK_oacute, - XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, - XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, - XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis -}; - -/* - * Getting a keycode from scancode - * - * With XKB - * -------- - * - * We have to enqueue keyboard events using standard X keycodes which correspond - * to AT scancode + 8; this means that we need to translate the Linux scancode - * provided by the kernel to an AT scancode -- this translation is not linear - * and requires that we use a LUT. - * - * - * Without XKB - * ----------- - * - * We can use custom keycodes, which makes things simpler; we define our custom - * keycodes as Linux scancodes + KD_KEY_OFFSET -*/ - -/* - This LUT translates AT scancodes into Linux ones -- the keymap we create - for the core X keyboard protocol has to be AT-scancode based so that it - corresponds to the Xkb keymap. -*/ -#if 0 -static unsigned char at2lnx[] = -{ - 0x0, /* no valid scancode */ - 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ - 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ - 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ - 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ - 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ - 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ - 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ - 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ - 0x11, /* KEY_W */ 0x12, /* KEY_E */ - 0x13, /* KEY_R */ 0x14, /* KEY_T */ - 0x15, /* KEY_Y */ 0x16, /* KEY_U */ - 0x17, /* KEY_I */ 0x18, /* KEY_O */ - 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ - 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ - 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ - 0x1f, /* KEY_S */ 0x20, /* KEY_D */ - 0x21, /* KEY_F */ 0x22, /* KEY_G */ - 0x23, /* KEY_H */ 0x24, /* KEY_J */ - 0x25, /* KEY_K */ 0x26, /* KEY_L */ - 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ - 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ - 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ - 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ - 0x2f, /* KEY_V */ 0x30, /* KEY_B */ - 0x31, /* KEY_N */ 0x32, /* KEY_M */ - 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ - 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ - 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ - 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ - 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ - 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ - 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ - 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ - 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ - 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ - 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ - 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ - 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ - 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ - 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ - 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ - 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ - 0x00, /* 0x55 */ 0x56, /* KEY_Less */ - 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ - 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ - 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ - 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ - 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ - 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ - 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ - 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ - 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ - 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ - 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ - 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ - 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ - 0x00, /* 0x71 */ 0x00, /* 0x72 */ - 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ - 0x00, /* 0x75 */ 0x00, /* 0x76 */ - 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ - 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ - 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ - 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ - 0x00, /* 0x7f */ -}; - -#define NUM_AT_KEYS (sizeof(at2lnx)/sizeof(at2lnx[0])) -#define LNX_KEY_INDEX(n) n < NUM_AT_KEYS ? at2lnx[n] : 0 - -static unsigned char tbl[KD_MAX_WIDTH] = -{ - 0, - 1 << KG_SHIFT, - (1 << KG_ALTGR), - (1 << KG_ALTGR) | (1 << KG_SHIFT) -}; -#endif - -static void -readKernelMapping(KdKeyboardInfo *ki) -{ -#if 0 - KeySym *k; - int i, j; - struct kbentry kbe; - int minKeyCode, maxKeyCode; - int row; - int fd; - - if (!ki) - return; - - fd = LinuxConsoleFd; - - minKeyCode = NR_KEYS; - maxKeyCode = 0; - row = 0; - ki->keySyms.mapWidth = KD_MAX_WIDTH; - for (i = 0; i < NR_KEYS && row < KD_MAX_LENGTH; ++i) - { - kbe.kb_index = LNX_KEY_INDEX(i); - - k = ki->keySyms.map + row * ki->keySyms.mapWidth; - - for (j = 0; j < ki->keySyms.mapWidth; ++j) - { - unsigned short kval; - - k[j] = NoSymbol; - - kbe.kb_table = tbl[j]; - kbe.kb_value = 0; - if (ioctl(fd, KDGKBENT, &kbe)) - continue; - - kval = KVAL(kbe.kb_value); - switch (KTYP(kbe.kb_value)) - { - case KT_LATIN: - case KT_LETTER: - k[j] = linux_to_x[kval]; - break; - - case KT_FN: - if (kval <= 19) - k[j] = XK_F1 + kval; - else switch (kbe.kb_value) - { - case K_FIND: - k[j] = XK_Home; /* or XK_Find */ - break; - case K_INSERT: - k[j] = XK_Insert; - break; - case K_REMOVE: - k[j] = XK_Delete; - break; - case K_SELECT: - k[j] = XK_End; /* or XK_Select */ - break; - case K_PGUP: - k[j] = XK_Prior; - break; - case K_PGDN: - k[j] = XK_Next; - break; - case K_HELP: - k[j] = XK_Help; - break; - case K_DO: - k[j] = XK_Execute; - break; - case K_PAUSE: - k[j] = XK_Pause; - break; - case K_MACRO: - k[j] = XK_Menu; - break; - default: - break; - } - break; - - case KT_SPEC: - switch (kbe.kb_value) - { - case K_ENTER: - k[j] = XK_Return; - break; - case K_BREAK: - k[j] = XK_Break; - break; - case K_CAPS: - k[j] = XK_Caps_Lock; - break; - case K_NUM: - k[j] = XK_Num_Lock; - break; - case K_HOLD: - k[j] = XK_Scroll_Lock; - break; - case K_COMPOSE: - k[j] = XK_Multi_key; - break; - default: - break; - } - break; - - case KT_PAD: - switch (kbe.kb_value) - { - case K_PPLUS: - k[j] = XK_KP_Add; - break; - case K_PMINUS: - k[j] = XK_KP_Subtract; - break; - case K_PSTAR: - k[j] = XK_KP_Multiply; - break; - case K_PSLASH: - k[j] = XK_KP_Divide; - break; - case K_PENTER: - k[j] = XK_KP_Enter; - break; - case K_PCOMMA: - k[j] = XK_KP_Separator; - break; - case K_PDOT: - k[j] = XK_KP_Decimal; - break; - case K_PPLUSMINUS: - k[j] = XK_KP_Subtract; - break; - default: - if (kval <= 9) - k[j] = XK_KP_0 + kval; - break; - } - break; - - /* - * KT_DEAD keys are for accelerated diacritical creation. - */ - case KT_DEAD: - switch (kbe.kb_value) - { - case K_DGRAVE: - k[j] = XK_dead_grave; - break; - case K_DACUTE: - k[j] = XK_dead_acute; - break; - case K_DCIRCM: - k[j] = XK_dead_circumflex; - break; - case K_DTILDE: - k[j] = XK_dead_tilde; - break; - case K_DDIERE: - k[j] = XK_dead_diaeresis; - break; - } - break; - - case KT_CUR: - switch (kbe.kb_value) - { - case K_DOWN: - k[j] = XK_Down; - break; - case K_LEFT: - k[j] = XK_Left; - break; - case K_RIGHT: - k[j] = XK_Right; - break; - case K_UP: - k[j] = XK_Up; - break; - } - break; - - case KT_SHIFT: - switch (kbe.kb_value) - { - case K_ALTGR: - k[j] = XK_Mode_switch; - break; - case K_ALT: - k[j] = (kbe.kb_index == 0x64 ? - XK_Alt_R : XK_Alt_L); - break; - case K_CTRL: - k[j] = (kbe.kb_index == 0x61 ? - XK_Control_R : XK_Control_L); - break; - case K_CTRLL: - k[j] = XK_Control_L; - break; - case K_CTRLR: - k[j] = XK_Control_R; - break; - case K_SHIFT: - k[j] = (kbe.kb_index == 0x36 ? - XK_Shift_R : XK_Shift_L); - break; - case K_SHIFTL: - k[j] = XK_Shift_L; - break; - case K_SHIFTR: - k[j] = XK_Shift_R; - break; - default: - break; - } - break; - - /* - * KT_ASCII keys accumulate a 3 digit decimal number that gets - * emitted when the shift state changes. We can't emulate that. - */ - case KT_ASCII: - break; - - case KT_LOCK: - if (kbe.kb_value == K_SHIFTLOCK) - k[j] = XK_Shift_Lock; - break; - -#ifdef KT_X - case KT_X: - /* depends on new keyboard symbols in file linux/keyboard.h */ - if(kbe.kb_value == K_XMENU) k[j] = XK_Menu; - if(kbe.kb_value == K_XTELEPHONE) k[j] = XK_telephone; - break; -#endif -#ifdef KT_XF - case KT_XF: - /* special linux keysyms which map directly to XF86 keysyms */ - k[j] = (kbe.kb_value & 0xFF) + 0x1008FF00; - break; -#endif - - default: - break; - } - if (i < minKeyCode) - minKeyCode = i; - if (i > maxKeyCode) - maxKeyCode = i; - } - - if (minKeyCode == NR_KEYS) - continue; - - if (k[3] == k[2]) k[3] = NoSymbol; - if (k[2] == k[1]) k[2] = NoSymbol; - if (k[1] == k[0]) k[1] = NoSymbol; - if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; - if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] =NoSymbol; - row++; - } - ki->minScanCode = minKeyCode; - ki->maxScanCode = maxKeyCode; -#endif -} - -/* - * We need these to handle extended scancodes correctly (I could just use the - * numbers below, but this makes the code more readable - */ - -/* The prefix codes */ -#define KEY_Prefix0 /* special 0x60 */ 96 -#define KEY_Prefix1 /* special 0x61 */ 97 - -/* The raw scancodes */ -#define KEY_Enter /* Enter 0x1c */ 28 -#define KEY_LCtrl /* Ctrl(left) 0x1d */ 29 -#define KEY_Slash /* / (Slash) ? 0x35 */ 53 -#define KEY_KP_Multiply /* * 0x37 */ 55 -#define KEY_Alt /* Alt(left) 0x38 */ 56 -#define KEY_F3 /* F3 0x3d */ 61 -#define KEY_F4 /* F4 0x3e */ 62 -#define KEY_F5 /* F5 0x3f */ 63 -#define KEY_F6 /* F6 0x40 */ 64 -#define KEY_F7 /* F7 0x41 */ 65 -#define KEY_ScrollLock /* ScrollLock 0x46 */ 70 -#define KEY_KP_7 /* 7 Home 0x47 */ 71 -#define KEY_KP_8 /* 8 Up 0x48 */ 72 -#define KEY_KP_9 /* 9 PgUp 0x49 */ 73 -#define KEY_KP_Minus /* - (Minus) 0x4a */ 74 -#define KEY_KP_4 /* 4 Left 0x4b */ 75 -#define KEY_KP_5 /* 5 0x4c */ 76 -#define KEY_KP_6 /* 6 Right 0x4d */ 77 -#define KEY_KP_Plus /* + (Plus) 0x4e */ 78 -#define KEY_KP_1 /* 1 End 0x4f */ 79 -#define KEY_KP_2 /* 2 Down 0x50 */ 80 -#define KEY_KP_3 /* 3 PgDown 0x51 */ 81 -#define KEY_KP_0 /* 0 Insert 0x52 */ 82 -#define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83 -#define KEY_Home /* Home 0x59 */ 89 -#define KEY_Up /* Up 0x5a */ 90 -#define KEY_PgUp /* PgUp 0x5b */ 91 -#define KEY_Left /* Left 0x5c */ 92 -#define KEY_Begin /* Begin 0x5d */ 93 -#define KEY_Right /* Right 0x5e */ 94 -#define KEY_End /* End 0x5f */ 95 -#define KEY_Down /* Down 0x60 */ 96 -#define KEY_PgDown /* PgDown 0x61 */ 97 -#define KEY_Insert /* Insert 0x62 */ 98 -#define KEY_Delete /* Delete 0x63 */ 99 -#define KEY_KP_Enter /* Enter 0x64 */ 100 -#define KEY_RCtrl /* Ctrl(right) 0x65 */ 101 -#define KEY_Pause /* Pause 0x66 */ 102 -#define KEY_Print /* Print 0x67 */ 103 -#define KEY_KP_Divide /* Divide 0x68 */ 104 -#define KEY_AltLang /* AtlLang(right) 0x69 */ 105 -#define KEY_Break /* Break 0x6a */ 106 -#define KEY_LMeta /* Left Meta 0x6b */ 107 -#define KEY_RMeta /* Right Meta 0x6c */ 108 -#define KEY_Menu /* Menu 0x6d */ 109 -#define KEY_F13 /* F13 0x6e */ 110 -#define KEY_F14 /* F14 0x6f */ 111 -#define KEY_F15 /* F15 0x70 */ 112 -#define KEY_F16 /* F16 0x71 */ 113 -#define KEY_F17 /* F17 0x72 */ 114 -#define KEY_KP_DEC /* KP_DEC 0x73 */ 115 - -static void -LinuxKeyboardRead (int fd, void *closure) -{ - unsigned char buf[256], *b; - int n; - unsigned char prefix = 0, scancode = 0; - - while ((n = read (fd, buf, sizeof (buf))) > 0) { - b = buf; - while (n--) { - /* - * With xkb we use RAW mode for reading the console, which allows us - * process extended scancodes. - * - * See if this is a prefix extending the following keycode - */ - if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0)) - { - prefix = KEY_Prefix0; - /* swallow this up */ - b++; - continue; - } - else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1)) - { - prefix = KEY_Prefix1; - /* swallow this up */ - b++; - continue; - } - scancode = b[0] & 0x7f; - - switch (prefix) { - /* from xf86Events.c */ - case KEY_Prefix0: - { - switch (scancode) { - case KEY_KP_7: - scancode = KEY_Home; break; /* curs home */ - case KEY_KP_8: - scancode = KEY_Up; break; /* curs up */ - case KEY_KP_9: - scancode = KEY_PgUp; break; /* curs pgup */ - case KEY_KP_4: - scancode = KEY_Left; break; /* curs left */ - case KEY_KP_5: - scancode = KEY_Begin; break; /* curs begin */ - case KEY_KP_6: - scancode = KEY_Right; break; /* curs right */ - case KEY_KP_1: - scancode = KEY_End; break; /* curs end */ - case KEY_KP_2: - scancode = KEY_Down; break; /* curs down */ - case KEY_KP_3: - scancode = KEY_PgDown; break; /* curs pgdown */ - case KEY_KP_0: - scancode = KEY_Insert; break; /* curs insert */ - case KEY_KP_Decimal: - scancode = KEY_Delete; break; /* curs delete */ - case KEY_Enter: - scancode = KEY_KP_Enter; break; /* keypad enter */ - case KEY_LCtrl: - scancode = KEY_RCtrl; break; /* right ctrl */ - case KEY_KP_Multiply: - scancode = KEY_Print; break; /* print */ - case KEY_Slash: - scancode = KEY_KP_Divide; break; /* keyp divide */ - case KEY_Alt: - scancode = KEY_AltLang; break; /* right alt */ - case KEY_ScrollLock: - scancode = KEY_Break; break; /* curs break */ - case 0x5b: - scancode = KEY_LMeta; break; - case 0x5c: - scancode = KEY_RMeta; break; - case 0x5d: - scancode = KEY_Menu; break; - case KEY_F3: - scancode = KEY_F13; break; - case KEY_F4: - scancode = KEY_F14; break; - case KEY_F5: - scancode = KEY_F15; break; - case KEY_F6: - scancode = KEY_F16; break; - case KEY_F7: - scancode = KEY_F17; break; - case KEY_KP_Plus: - scancode = KEY_KP_DEC; break; - /* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */ - case 0x2A: - case 0x36: - b++; - prefix = 0; - continue; - default: - /* - * "Internet" keyboards are generating lots of new - * codes. Let them pass. There is little consistency - * between them, so don't bother with symbolic names at - * this level. - */ - scancode += 0x78; - } - break; - } - - case KEY_Prefix1: - { - /* we do no handle these */ - b++; - prefix = 0; - continue; - } - - default: /* should not happen*/ - case 0: /* do nothing */ - ; - } - - prefix = 0; - KdEnqueueKeyboardEvent (closure, scancode, b[0] & 0x80); - b++; - } - } -} - -static int LinuxKbdTrans; -static struct termios LinuxTermios; - -static Status -LinuxKeyboardEnable (KdKeyboardInfo *ki) -{ - struct termios nTty; - unsigned char buf[256]; - int n; - int fd; - - if (!ki) - return !Success; - - fd = LinuxConsoleFd; - ki->driverPrivate = (void *) fd; - - ioctl (fd, KDGKBMODE, &LinuxKbdTrans); - tcgetattr (fd, &LinuxTermios); - ioctl(fd, KDSKBMODE, K_RAW); - nTty = LinuxTermios; - nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); - nTty.c_oflag = 0; - nTty.c_cflag = CREAD | CS8; - nTty.c_lflag = 0; - nTty.c_cc[VTIME]=0; - nTty.c_cc[VMIN]=1; - cfsetispeed(&nTty, 9600); - cfsetospeed(&nTty, 9600); - tcsetattr(fd, TCSANOW, &nTty); - /* - * Flush any pending keystrokes - */ - while ((n = read (fd, buf, sizeof (buf))) > 0) - ; - KdRegisterFd (fd, LinuxKeyboardRead, ki); - return Success; -} - -static void -LinuxKeyboardDisable (KdKeyboardInfo *ki) -{ - int fd; - - if (!ki) - return; - - fd = (int) ki->driverPrivate; - - KdUnregisterFd(ki, fd, FALSE); - ioctl(fd, KDSKBMODE, LinuxKbdTrans); - tcsetattr(fd, TCSANOW, &LinuxTermios); -} - -static Status -LinuxKeyboardInit (KdKeyboardInfo *ki) -{ - if (!ki) - return !Success; - - xfree(ki->path); - ki->path = strdup("console"); - xfree(ki->name); - ki->name = strdup("Linux console keyboard"); - - readKernelMapping (ki); - - return Success; -} - -static void -LinuxKeyboardLeds (KdKeyboardInfo *ki, int leds) -{ - if (!ki) - return; - - ioctl ((int)ki->driverPrivate, KDSETLED, leds & 7); -} - -KdKeyboardDriver LinuxKeyboardDriver = { - "keyboard", - .Init = LinuxKeyboardInit, - .Enable = LinuxKeyboardEnable, - .Leds = LinuxKeyboardLeds, - .Disable = LinuxKeyboardDisable, -}; +/* + * Copyright © 1999 Keith Packard + * XKB integration © 2006 Nokia Corporation, author: Tomas Frydrych <tf@o-hand.com> + * + * LinuxKeyboardRead() XKB code based on xf86KbdLnx.c: + * Copyright © 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * Copyright © 1994-2001 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" +#include <linux/keyboard.h> +#include <linux/kd.h> +#define XK_PUBLISHING +#include <X11/keysym.h> +#include <termios.h> +#include <sys/ioctl.h> + +extern int LinuxConsoleFd; + +static const KeySym linux_to_x[256] = { + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, XK_Escape, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_space, XK_exclam, XK_quotedbl, XK_numbersign, + XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, + XK_parenleft, XK_parenright, XK_asterisk, XK_plus, + XK_comma, XK_minus, XK_period, XK_slash, + XK_0, XK_1, XK_2, XK_3, + XK_4, XK_5, XK_6, XK_7, + XK_8, XK_9, XK_colon, XK_semicolon, + XK_less, XK_equal, XK_greater, XK_question, + XK_at, XK_A, XK_B, XK_C, + XK_D, XK_E, XK_F, XK_G, + XK_H, XK_I, XK_J, XK_K, + XK_L, XK_M, XK_N, XK_O, + XK_P, XK_Q, XK_R, XK_S, + XK_T, XK_U, XK_V, XK_W, + XK_X, XK_Y, XK_Z, XK_bracketleft, + XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore, + XK_grave, XK_a, XK_b, XK_c, + XK_d, XK_e, XK_f, XK_g, + XK_h, XK_i, XK_j, XK_k, + XK_l, XK_m, XK_n, XK_o, + XK_p, XK_q, XK_r, XK_s, + XK_t, XK_u, XK_v, XK_w, + XK_x, XK_y, XK_z, XK_braceleft, + XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling, + XK_currency, XK_yen, XK_brokenbar, XK_section, + XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, + XK_notsign, XK_hyphen, XK_registered, XK_macron, + XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, + XK_acute, XK_mu, XK_paragraph, XK_periodcentered, + XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, + XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown, + XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, + XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, + XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, + XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, + XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, + XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, + XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, + XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, + XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, + XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, + XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, + XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, + XK_eth, XK_ntilde, XK_ograve, XK_oacute, + XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, + XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, + XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis +}; + +/* + * Getting a keycode from scancode + * + * With XKB + * -------- + * + * We have to enqueue keyboard events using standard X keycodes which correspond + * to AT scancode + 8; this means that we need to translate the Linux scancode + * provided by the kernel to an AT scancode -- this translation is not linear + * and requires that we use a LUT. + * + * + * Without XKB + * ----------- + * + * We can use custom keycodes, which makes things simpler; we define our custom + * keycodes as Linux scancodes + KD_KEY_OFFSET +*/ + +/* + This LUT translates AT scancodes into Linux ones -- the keymap we create + for the core X keyboard protocol has to be AT-scancode based so that it + corresponds to the Xkb keymap. +*/ +#if 0 +static unsigned char at2lnx[] = +{ + 0x0, /* no valid scancode */ + 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ + 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ + 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ + 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ + 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ + 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ + 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ + 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ + 0x11, /* KEY_W */ 0x12, /* KEY_E */ + 0x13, /* KEY_R */ 0x14, /* KEY_T */ + 0x15, /* KEY_Y */ 0x16, /* KEY_U */ + 0x17, /* KEY_I */ 0x18, /* KEY_O */ + 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ + 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ + 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ + 0x1f, /* KEY_S */ 0x20, /* KEY_D */ + 0x21, /* KEY_F */ 0x22, /* KEY_G */ + 0x23, /* KEY_H */ 0x24, /* KEY_J */ + 0x25, /* KEY_K */ 0x26, /* KEY_L */ + 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ + 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ + 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ + 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ + 0x2f, /* KEY_V */ 0x30, /* KEY_B */ + 0x31, /* KEY_N */ 0x32, /* KEY_M */ + 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ + 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ + 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ + 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ + 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ + 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ + 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ + 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ + 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ + 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ + 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ + 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ + 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ + 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ + 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ + 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ + 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ + 0x00, /* 0x55 */ 0x56, /* KEY_Less */ + 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ + 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ + 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ + 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ + 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ + 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ + 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ + 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ + 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ + 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ + 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ + 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ + 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ + 0x00, /* 0x71 */ 0x00, /* 0x72 */ + 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ + 0x00, /* 0x75 */ 0x00, /* 0x76 */ + 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ + 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ + 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ + 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ + 0x00, /* 0x7f */ +}; + +#define NUM_AT_KEYS (sizeof(at2lnx)/sizeof(at2lnx[0])) +#define LNX_KEY_INDEX(n) n < NUM_AT_KEYS ? at2lnx[n] : 0 + +static unsigned char tbl[KD_MAX_WIDTH] = +{ + 0, + 1 << KG_SHIFT, + (1 << KG_ALTGR), + (1 << KG_ALTGR) | (1 << KG_SHIFT) +}; +#endif + +static void +readKernelMapping(KdKeyboardInfo *ki) +{ +#if 0 + KeySym *k; + int i, j; + struct kbentry kbe; + int minKeyCode, maxKeyCode; + int row; + int fd; + + if (!ki) + return; + + fd = LinuxConsoleFd; + + minKeyCode = NR_KEYS; + maxKeyCode = 0; + row = 0; + ki->keySyms.mapWidth = KD_MAX_WIDTH; + for (i = 0; i < NR_KEYS && row < KD_MAX_LENGTH; ++i) + { + kbe.kb_index = LNX_KEY_INDEX(i); + + k = ki->keySyms.map + row * ki->keySyms.mapWidth; + + for (j = 0; j < ki->keySyms.mapWidth; ++j) + { + unsigned short kval; + + k[j] = NoSymbol; + + kbe.kb_table = tbl[j]; + kbe.kb_value = 0; + if (ioctl(fd, KDGKBENT, &kbe)) + continue; + + kval = KVAL(kbe.kb_value); + switch (KTYP(kbe.kb_value)) + { + case KT_LATIN: + case KT_LETTER: + k[j] = linux_to_x[kval]; + break; + + case KT_FN: + if (kval <= 19) + k[j] = XK_F1 + kval; + else switch (kbe.kb_value) + { + case K_FIND: + k[j] = XK_Home; /* or XK_Find */ + break; + case K_INSERT: + k[j] = XK_Insert; + break; + case K_REMOVE: + k[j] = XK_Delete; + break; + case K_SELECT: + k[j] = XK_End; /* or XK_Select */ + break; + case K_PGUP: + k[j] = XK_Prior; + break; + case K_PGDN: + k[j] = XK_Next; + break; + case K_HELP: + k[j] = XK_Help; + break; + case K_DO: + k[j] = XK_Execute; + break; + case K_PAUSE: + k[j] = XK_Pause; + break; + case K_MACRO: + k[j] = XK_Menu; + break; + default: + break; + } + break; + + case KT_SPEC: + switch (kbe.kb_value) + { + case K_ENTER: + k[j] = XK_Return; + break; + case K_BREAK: + k[j] = XK_Break; + break; + case K_CAPS: + k[j] = XK_Caps_Lock; + break; + case K_NUM: + k[j] = XK_Num_Lock; + break; + case K_HOLD: + k[j] = XK_Scroll_Lock; + break; + case K_COMPOSE: + k[j] = XK_Multi_key; + break; + default: + break; + } + break; + + case KT_PAD: + switch (kbe.kb_value) + { + case K_PPLUS: + k[j] = XK_KP_Add; + break; + case K_PMINUS: + k[j] = XK_KP_Subtract; + break; + case K_PSTAR: + k[j] = XK_KP_Multiply; + break; + case K_PSLASH: + k[j] = XK_KP_Divide; + break; + case K_PENTER: + k[j] = XK_KP_Enter; + break; + case K_PCOMMA: + k[j] = XK_KP_Separator; + break; + case K_PDOT: + k[j] = XK_KP_Decimal; + break; + case K_PPLUSMINUS: + k[j] = XK_KP_Subtract; + break; + default: + if (kval <= 9) + k[j] = XK_KP_0 + kval; + break; + } + break; + + /* + * KT_DEAD keys are for accelerated diacritical creation. + */ + case KT_DEAD: + switch (kbe.kb_value) + { + case K_DGRAVE: + k[j] = XK_dead_grave; + break; + case K_DACUTE: + k[j] = XK_dead_acute; + break; + case K_DCIRCM: + k[j] = XK_dead_circumflex; + break; + case K_DTILDE: + k[j] = XK_dead_tilde; + break; + case K_DDIERE: + k[j] = XK_dead_diaeresis; + break; + } + break; + + case KT_CUR: + switch (kbe.kb_value) + { + case K_DOWN: + k[j] = XK_Down; + break; + case K_LEFT: + k[j] = XK_Left; + break; + case K_RIGHT: + k[j] = XK_Right; + break; + case K_UP: + k[j] = XK_Up; + break; + } + break; + + case KT_SHIFT: + switch (kbe.kb_value) + { + case K_ALTGR: + k[j] = XK_Mode_switch; + break; + case K_ALT: + k[j] = (kbe.kb_index == 0x64 ? + XK_Alt_R : XK_Alt_L); + break; + case K_CTRL: + k[j] = (kbe.kb_index == 0x61 ? + XK_Control_R : XK_Control_L); + break; + case K_CTRLL: + k[j] = XK_Control_L; + break; + case K_CTRLR: + k[j] = XK_Control_R; + break; + case K_SHIFT: + k[j] = (kbe.kb_index == 0x36 ? + XK_Shift_R : XK_Shift_L); + break; + case K_SHIFTL: + k[j] = XK_Shift_L; + break; + case K_SHIFTR: + k[j] = XK_Shift_R; + break; + default: + break; + } + break; + + /* + * KT_ASCII keys accumulate a 3 digit decimal number that gets + * emitted when the shift state changes. We can't emulate that. + */ + case KT_ASCII: + break; + + case KT_LOCK: + if (kbe.kb_value == K_SHIFTLOCK) + k[j] = XK_Shift_Lock; + break; + +#ifdef KT_X + case KT_X: + /* depends on new keyboard symbols in file linux/keyboard.h */ + if(kbe.kb_value == K_XMENU) k[j] = XK_Menu; + if(kbe.kb_value == K_XTELEPHONE) k[j] = XK_telephone; + break; +#endif +#ifdef KT_XF + case KT_XF: + /* special linux keysyms which map directly to XF86 keysyms */ + k[j] = (kbe.kb_value & 0xFF) + 0x1008FF00; + break; +#endif + + default: + break; + } + if (i < minKeyCode) + minKeyCode = i; + if (i > maxKeyCode) + maxKeyCode = i; + } + + if (minKeyCode == NR_KEYS) + continue; + + if (k[3] == k[2]) k[3] = NoSymbol; + if (k[2] == k[1]) k[2] = NoSymbol; + if (k[1] == k[0]) k[1] = NoSymbol; + if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; + if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] =NoSymbol; + row++; + } + ki->minScanCode = minKeyCode; + ki->maxScanCode = maxKeyCode; +#endif +} + +/* + * We need these to handle extended scancodes correctly (I could just use the + * numbers below, but this makes the code more readable + */ + +/* The prefix codes */ +#define KEY_Prefix0 /* special 0x60 */ 96 +#define KEY_Prefix1 /* special 0x61 */ 97 + +/* The raw scancodes */ +#define KEY_Enter /* Enter 0x1c */ 28 +#define KEY_LCtrl /* Ctrl(left) 0x1d */ 29 +#define KEY_Slash /* / (Slash) ? 0x35 */ 53 +#define KEY_KP_Multiply /* * 0x37 */ 55 +#define KEY_Alt /* Alt(left) 0x38 */ 56 +#define KEY_F3 /* F3 0x3d */ 61 +#define KEY_F4 /* F4 0x3e */ 62 +#define KEY_F5 /* F5 0x3f */ 63 +#define KEY_F6 /* F6 0x40 */ 64 +#define KEY_F7 /* F7 0x41 */ 65 +#define KEY_ScrollLock /* ScrollLock 0x46 */ 70 +#define KEY_KP_7 /* 7 Home 0x47 */ 71 +#define KEY_KP_8 /* 8 Up 0x48 */ 72 +#define KEY_KP_9 /* 9 PgUp 0x49 */ 73 +#define KEY_KP_Minus /* - (Minus) 0x4a */ 74 +#define KEY_KP_4 /* 4 Left 0x4b */ 75 +#define KEY_KP_5 /* 5 0x4c */ 76 +#define KEY_KP_6 /* 6 Right 0x4d */ 77 +#define KEY_KP_Plus /* + (Plus) 0x4e */ 78 +#define KEY_KP_1 /* 1 End 0x4f */ 79 +#define KEY_KP_2 /* 2 Down 0x50 */ 80 +#define KEY_KP_3 /* 3 PgDown 0x51 */ 81 +#define KEY_KP_0 /* 0 Insert 0x52 */ 82 +#define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83 +#define KEY_Home /* Home 0x59 */ 89 +#define KEY_Up /* Up 0x5a */ 90 +#define KEY_PgUp /* PgUp 0x5b */ 91 +#define KEY_Left /* Left 0x5c */ 92 +#define KEY_Begin /* Begin 0x5d */ 93 +#define KEY_Right /* Right 0x5e */ 94 +#define KEY_End /* End 0x5f */ 95 +#define KEY_Down /* Down 0x60 */ 96 +#define KEY_PgDown /* PgDown 0x61 */ 97 +#define KEY_Insert /* Insert 0x62 */ 98 +#define KEY_Delete /* Delete 0x63 */ 99 +#define KEY_KP_Enter /* Enter 0x64 */ 100 +#define KEY_RCtrl /* Ctrl(right) 0x65 */ 101 +#define KEY_Pause /* Pause 0x66 */ 102 +#define KEY_Print /* Print 0x67 */ 103 +#define KEY_KP_Divide /* Divide 0x68 */ 104 +#define KEY_AltLang /* AtlLang(right) 0x69 */ 105 +#define KEY_Break /* Break 0x6a */ 106 +#define KEY_LMeta /* Left Meta 0x6b */ 107 +#define KEY_RMeta /* Right Meta 0x6c */ 108 +#define KEY_Menu /* Menu 0x6d */ 109 +#define KEY_F13 /* F13 0x6e */ 110 +#define KEY_F14 /* F14 0x6f */ 111 +#define KEY_F15 /* F15 0x70 */ 112 +#define KEY_F16 /* F16 0x71 */ 113 +#define KEY_F17 /* F17 0x72 */ 114 +#define KEY_KP_DEC /* KP_DEC 0x73 */ 115 + +static void +LinuxKeyboardRead (int fd, void *closure) +{ + unsigned char buf[256], *b; + int n; + unsigned char prefix = 0, scancode = 0; + + while ((n = read (fd, buf, sizeof (buf))) > 0) { + b = buf; + while (n--) { + /* + * With xkb we use RAW mode for reading the console, which allows us + * process extended scancodes. + * + * See if this is a prefix extending the following keycode + */ + if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0)) + { + prefix = KEY_Prefix0; + /* swallow this up */ + b++; + continue; + } + else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1)) + { + prefix = KEY_Prefix1; + /* swallow this up */ + b++; + continue; + } + scancode = b[0] & 0x7f; + + switch (prefix) { + /* from xf86Events.c */ + case KEY_Prefix0: + { + switch (scancode) { + case KEY_KP_7: + scancode = KEY_Home; break; /* curs home */ + case KEY_KP_8: + scancode = KEY_Up; break; /* curs up */ + case KEY_KP_9: + scancode = KEY_PgUp; break; /* curs pgup */ + case KEY_KP_4: + scancode = KEY_Left; break; /* curs left */ + case KEY_KP_5: + scancode = KEY_Begin; break; /* curs begin */ + case KEY_KP_6: + scancode = KEY_Right; break; /* curs right */ + case KEY_KP_1: + scancode = KEY_End; break; /* curs end */ + case KEY_KP_2: + scancode = KEY_Down; break; /* curs down */ + case KEY_KP_3: + scancode = KEY_PgDown; break; /* curs pgdown */ + case KEY_KP_0: + scancode = KEY_Insert; break; /* curs insert */ + case KEY_KP_Decimal: + scancode = KEY_Delete; break; /* curs delete */ + case KEY_Enter: + scancode = KEY_KP_Enter; break; /* keypad enter */ + case KEY_LCtrl: + scancode = KEY_RCtrl; break; /* right ctrl */ + case KEY_KP_Multiply: + scancode = KEY_Print; break; /* print */ + case KEY_Slash: + scancode = KEY_KP_Divide; break; /* keyp divide */ + case KEY_Alt: + scancode = KEY_AltLang; break; /* right alt */ + case KEY_ScrollLock: + scancode = KEY_Break; break; /* curs break */ + case 0x5b: + scancode = KEY_LMeta; break; + case 0x5c: + scancode = KEY_RMeta; break; + case 0x5d: + scancode = KEY_Menu; break; + case KEY_F3: + scancode = KEY_F13; break; + case KEY_F4: + scancode = KEY_F14; break; + case KEY_F5: + scancode = KEY_F15; break; + case KEY_F6: + scancode = KEY_F16; break; + case KEY_F7: + scancode = KEY_F17; break; + case KEY_KP_Plus: + scancode = KEY_KP_DEC; break; + /* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */ + case 0x2A: + case 0x36: + b++; + prefix = 0; + continue; + default: + /* + * "Internet" keyboards are generating lots of new + * codes. Let them pass. There is little consistency + * between them, so don't bother with symbolic names at + * this level. + */ + scancode += 0x78; + } + break; + } + + case KEY_Prefix1: + { + /* we do no handle these */ + b++; + prefix = 0; + continue; + } + + default: /* should not happen*/ + case 0: /* do nothing */ + ; + } + + prefix = 0; + KdEnqueueKeyboardEvent (closure, scancode, b[0] & 0x80); + b++; + } + } +} + +static int LinuxKbdTrans; +static struct termios LinuxTermios; + +static Status +LinuxKeyboardEnable (KdKeyboardInfo *ki) +{ + struct termios nTty; + unsigned char buf[256]; + int n; + int fd; + + if (!ki) + return !Success; + + fd = LinuxConsoleFd; + ki->driverPrivate = (void *) fd; + + ioctl (fd, KDGKBMODE, &LinuxKbdTrans); + tcgetattr (fd, &LinuxTermios); + ioctl(fd, KDSKBMODE, K_RAW); + nTty = LinuxTermios; + nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); + nTty.c_oflag = 0; + nTty.c_cflag = CREAD | CS8; + nTty.c_lflag = 0; + nTty.c_cc[VTIME]=0; + nTty.c_cc[VMIN]=1; + cfsetispeed(&nTty, 9600); + cfsetospeed(&nTty, 9600); + tcsetattr(fd, TCSANOW, &nTty); + /* + * Flush any pending keystrokes + */ + while ((n = read (fd, buf, sizeof (buf))) > 0) + ; + KdRegisterFd (fd, LinuxKeyboardRead, ki); + return Success; +} + +static void +LinuxKeyboardDisable (KdKeyboardInfo *ki) +{ + int fd; + + if (!ki) + return; + + fd = (int) ki->driverPrivate; + + KdUnregisterFd(ki, fd, FALSE); + ioctl(fd, KDSKBMODE, LinuxKbdTrans); + tcsetattr(fd, TCSANOW, &LinuxTermios); +} + +static Status +LinuxKeyboardInit (KdKeyboardInfo *ki) +{ + if (!ki) + return !Success; + + free(ki->path); + ki->path = strdup("console"); + free(ki->name); + ki->name = strdup("Linux console keyboard"); + + readKernelMapping (ki); + + return Success; +} + +static void +LinuxKeyboardLeds (KdKeyboardInfo *ki, int leds) +{ + if (!ki) + return; + + ioctl ((int)ki->driverPrivate, KDSETLED, leds & 7); +} + +KdKeyboardDriver LinuxKeyboardDriver = { + "keyboard", + .Init = LinuxKeyboardInit, + .Enable = LinuxKeyboardEnable, + .Leds = LinuxKeyboardLeds, + .Disable = LinuxKeyboardDisable, +}; diff --git a/xorg-server/hw/kdrive/linux/mouse.c b/xorg-server/hw/kdrive/linux/mouse.c index 007263e4b..2e39d240e 100644 --- a/xorg-server/hw/kdrive/linux/mouse.c +++ b/xorg-server/hw/kdrive/linux/mouse.c @@ -1,1030 +1,1030 @@ -/* - * Copyright © 2001 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include <errno.h> -#include <termios.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/Xpoll.h> -#include "inputstr.h" -#include "scrnintstr.h" -#include "kdrive.h" - -#undef DEBUG -#undef DEBUG_BYTES -#define KBUFIO_SIZE 256 -#define MOUSE_TIMEOUT 100 - -typedef struct _kbufio { - int fd; - unsigned char buf[KBUFIO_SIZE]; - int avail; - int used; -} Kbufio; - -static Bool -MouseWaitForReadable (int fd, int timeout) -{ - fd_set set; - struct timeval tv, *tp; - int n; - CARD32 done; - - done = GetTimeInMillis () + timeout; - for (;;) - { - FD_ZERO (&set); - FD_SET (fd, &set); - if (timeout == -1) - tp = 0; - else - { - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - tp = &tv; - } - n = select (fd + 1, &set, 0, 0, tp); - if (n > 0) - return TRUE; - if (n < 0 && (errno == EAGAIN || errno == EINTR)) - { - timeout = (int) (done - GetTimeInMillis ()); - if (timeout > 0) - continue; - } - break; - } - return FALSE; -} - -static int -MouseReadByte (Kbufio *b, int timeout) -{ - int n; - if (b->avail <= b->used) - { - if (timeout && !MouseWaitForReadable (b->fd, timeout)) - { -#ifdef DEBUG_BYTES - ErrorF ("\tTimeout %d\n", timeout); -#endif - return -1; - } - n = read (b->fd, b->buf, KBUFIO_SIZE); - if (n <= 0) - return -1; - b->avail = n; - b->used = 0; - } -#ifdef DEBUG_BYTES - ErrorF ("\tget %02x\n", b->buf[b->used]); -#endif - return b->buf[b->used++]; -} - -#if NOTUSED -static int -MouseFlush (Kbufio *b, char *buf, int size) -{ - CARD32 now = GetTimeInMillis (); - CARD32 done = now + 100; - int c; - int n = 0; - - while ((c = MouseReadByte (b, done - now)) != -1) - { - if (buf) - { - if (n == size) - { - memmove (buf, buf + 1, size - 1); - n--; - } - buf[n++] = c; - } - now = GetTimeInMillis (); - if ((INT32) (now - done) >= 0) - break; - } - return n; -} - -static int -MousePeekByte (Kbufio *b, int timeout) -{ - int c; - - c = MouseReadByte (b, timeout); - if (c != -1) - --b->used; - return c; -} -#endif /* NOTUSED */ - -static Bool -MouseWaitForWritable (int fd, int timeout) -{ - fd_set set; - struct timeval tv, *tp; - int n; - - FD_ZERO (&set); - FD_SET (fd, &set); - if (timeout == -1) - tp = 0; - else - { - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - tp = &tv; - } - n = select (fd + 1, 0, &set, 0, tp); - if (n > 0) - return TRUE; - return FALSE; -} - -static Bool -MouseWriteByte (int fd, unsigned char c, int timeout) -{ - int ret; - -#ifdef DEBUG_BYTES - ErrorF ("\tput %02x\n", c); -#endif - for (;;) - { - ret = write (fd, &c, 1); - if (ret == 1) - return TRUE; - if (ret == 0) - return FALSE; - if (errno != EWOULDBLOCK) - return FALSE; - if (!MouseWaitForWritable (fd, timeout)) - return FALSE; - } -} - -static Bool -MouseWriteBytes (int fd, unsigned char *c, int n, int timeout) -{ - while (n--) - if (!MouseWriteByte (fd, *c++, timeout)) - return FALSE; - return TRUE; -} - -#define MAX_MOUSE 10 /* maximum length of mouse protocol */ -#define MAX_SKIP 16 /* number of error bytes before switching */ -#define MAX_VALID 4 /* number of valid packets before accepting */ - -typedef struct _kmouseProt { - char *name; - Bool (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne); - int (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne); - Bool (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne); - Bool (*Init) (KdPointerInfo *pi); - unsigned char headerMask, headerValid; - unsigned char dataMask, dataValid; - Bool tty; - unsigned int c_iflag; - unsigned int c_oflag; - unsigned int c_lflag; - unsigned int c_cflag; - unsigned int speed; - unsigned char *init; - unsigned long state; -} KmouseProt; - -typedef enum _kmouseStage { - MouseBroken, MouseTesting, MouseWorking -} KmouseStage; - -typedef struct _kmouse { - Kbufio iob; - const KmouseProt *prot; - int i_prot; - KmouseStage stage; /* protocol verification stage */ - Bool tty; /* mouse device is a tty */ - int valid; /* sequential valid events */ - int tested; /* bytes scanned during Testing phase */ - int invalid;/* total invalid bytes for this protocol */ - unsigned long state; /* private per protocol, init to prot->state */ -} Kmouse; - -static int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - const KmouseProt *prot = km->prot; - int i; - - for (i = 0; i < ne; i++) - if ((ev[i] & prot->headerMask) == prot->headerValid) - break; - if (i != 0) - return i; - for (i = 1; i < ne; i++) - if ((ev[i] & prot->dataMask) != prot->dataValid) - return -1; - return 0; -} - -static Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - return ne == 3; -} - -static Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - return ne == 4; -} - -static Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - return ne == 5; -} - -static Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy) -{ - Kmouse *km = pi->driverPrivate; - - if (km->stage == MouseWorking) - return TRUE; - if (dx < -50 || dx > 50) - { -#ifdef DEBUG - ErrorF ("Large X %d\n", dx); -#endif - return FALSE; - } - if (dy < -50 || dy > 50) - { -#ifdef DEBUG - ErrorF ("Large Y %d\n", dy); -#endif - return FALSE; - } - return TRUE; -} - -/* - * Standard PS/2 mouse protocol - */ -static Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy, dz; - unsigned long flags; - unsigned long flagsrelease = 0; - - flags = KD_MOUSE_DELTA; - if (ev[0] & 4) - flags |= KD_BUTTON_2; - if (ev[0] & 2) - flags |= KD_BUTTON_3; - if (ev[0] & 1) - flags |= KD_BUTTON_1; - - if (ne > 3) - { - dz = (int) (signed char) ev[3]; - if (dz < 0) - { - flags |= KD_BUTTON_4; - flagsrelease = KD_BUTTON_4; - } - else if (dz > 0) - { - flags |= KD_BUTTON_5; - flagsrelease = KD_BUTTON_5; - } - } - - dx = ev[1]; - if (ev[0] & 0x10) - dx -= 256; - dy = ev[2]; - if (ev[0] & 0x20) - dy -= 256; - dy = -dy; - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - { - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - if (flagsrelease) - { - flags &= ~flagsrelease; - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - } - } - return TRUE; -} - -static Bool ps2Init (KdPointerInfo *pi); - -static const KmouseProt ps2Prot = { - "ps/2", - threeComplete, mouseValid, ps2Parse, ps2Init, - 0x08, 0x08, 0x00, 0x00, - FALSE -}; - -static const KmouseProt imps2Prot = { - "imps/2", - fourComplete, mouseValid, ps2Parse, ps2Init, - 0x08, 0x08, 0x00, 0x00, - FALSE -}; - -static const KmouseProt exps2Prot = { - "exps/2", - fourComplete, mouseValid, ps2Parse, ps2Init, - 0x08, 0x08, 0x00, 0x00, - FALSE -}; - -/* - * Once the mouse is known to speak ps/2 protocol, go and find out - * what advanced capabilities it has and turn them on - */ - -/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */ - -/* aux device commands (sent to KBD_DATA_PORT) */ -#define PSMC_SET_SCALING11 0x00e6 -#define PSMC_SET_SCALING21 0x00e7 -#define PSMC_SET_RESOLUTION 0x00e8 -#define PSMC_SEND_DEV_STATUS 0x00e9 -#define PSMC_SET_STREAM_MODE 0x00ea -#define PSMC_SEND_DEV_DATA 0x00eb -#define PSMC_SET_REMOTE_MODE 0x00f0 -#define PSMC_SEND_DEV_ID 0x00f2 -#define PSMC_SET_SAMPLING_RATE 0x00f3 -#define PSMC_ENABLE_DEV 0x00f4 -#define PSMC_DISABLE_DEV 0x00f5 -#define PSMC_SET_DEFAULTS 0x00f6 -#define PSMC_RESET_DEV 0x00ff - -/* PSMC_SET_RESOLUTION argument */ -#define PSMD_RES_LOW 0 /* typically 25ppi */ -#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */ -#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */ -#define PSMD_RES_HIGH 3 /* typically 200ppi */ -#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH - -/* PSMC_SET_SAMPLING_RATE */ -#define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */ - -/* aux device ID */ -#define PSM_MOUSE_ID 0 -#define PSM_BALLPOINT_ID 2 -#define PSM_INTELLI_ID 3 -#define PSM_EXPLORER_ID 4 -#define PSM_4DMOUSE_ID 6 -#define PSM_4DPLUS_ID 8 - -static unsigned char ps2_init[] = { - PSMC_ENABLE_DEV, - 0, -}; - -#define NINIT_PS2 1 - -static unsigned char wheel_3button_init[] = { - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 100, - PSMC_SET_SAMPLING_RATE, 80, - PSMC_SEND_DEV_ID, - 0, -}; - -#define NINIT_IMPS2 4 - -static unsigned char wheel_5button_init[] = { - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 100, - PSMC_SET_SAMPLING_RATE, 80, - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 80, - PSMC_SEND_DEV_ID, - 0 -}; - -#define NINIT_EXPS2 7 - -static unsigned char intelli_init[] = { - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 100, - PSMC_SET_SAMPLING_RATE, 80, - 0 -}; - -#define NINIT_INTELLI 3 - -static int -ps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next) -{ - Kmouse *km = pi->driverPrivate; - int c = -1; - int skipping; - Bool waiting; - - skipping = 0; - waiting = FALSE; - while (ninit || ret_next) - { - c = MouseReadByte (&km->iob, MOUSE_TIMEOUT); - if (c == -1) - break; - /* look for ACK */ - if (c == 0xfa) - { - ninit--; - if (ret_next) - waiting = TRUE; - } - /* look for packet start -- not the response */ - else if ((c & 0x08) == 0x08) - waiting = FALSE; - else if (waiting) - break; - } - return c; -} - -static Bool -ps2Init (KdPointerInfo *pi) -{ - Kmouse *km = pi->driverPrivate; - int skipping; - Bool waiting; - int id; - unsigned char *init; - int ninit; - - /* Send Intellimouse initialization sequence */ - MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100); - /* - * Send ID command - */ - if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100)) - return FALSE; - skipping = 0; - waiting = FALSE; - id = ps2SkipInit (pi, 0, TRUE); - switch (id) { - case 3: - init = wheel_3button_init; - ninit = NINIT_IMPS2; - km->prot = &imps2Prot; - break; - case 4: - init = wheel_5button_init; - ninit = NINIT_EXPS2; - km->prot = &exps2Prot; - break; - default: - init = ps2_init; - ninit = NINIT_PS2; - km->prot = &ps2Prot; - break; - } - if (init) - MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100); - /* - * Flush out the available data to eliminate responses to the - * initialization string. Make sure any partial event is - * skipped - */ - (void) ps2SkipInit (pi, ninit, FALSE); - return TRUE; -} - -static Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy; - unsigned long flags; - - flags = KD_MOUSE_DELTA; - dx = (signed char) ev[1]; - dy = -(signed char) ev[2]; - if ((ev[0] & 4) == 0) - flags |= KD_BUTTON_1; - if ((ev[0] & 2) == 0) - flags |= KD_BUTTON_2; - if ((ev[0] & 1) == 0) - flags |= KD_BUTTON_3; - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - return TRUE; -} - -static const KmouseProt busProt = { - "bus", - threeComplete, mouseValid, busParse, 0, - 0xf8, 0x00, 0x00, 0x00, - FALSE -}; - -/* - * Standard MS serial protocol, three bytes - */ - -static Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy; - unsigned long flags; - - flags = KD_MOUSE_DELTA; - - if (ev[0] & 0x20) - flags |= KD_BUTTON_1; - if (ev[0] & 0x10) - flags |= KD_BUTTON_3; - - dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); - dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - return TRUE; -} - -static const KmouseProt msProt = { - "ms", - threeComplete, mouseValid, msParse, 0, - 0xc0, 0x40, 0xc0, 0x00, - TRUE, - IGNPAR, - 0, - 0, - CS7 | CSTOPB | CREAD | CLOCAL, - B1200, -}; - -/* - * Logitech mice send 3 or 4 bytes, the only way to tell is to look at the - * first byte of a synchronized protocol stream and see if it's got - * any bits turned on that can't occur in that fourth byte - */ -static Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - - if ((ev[0] & 0x40) == 0x40) - return ne == 3; - if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0) - return ne == 1; - return FALSE; -} - -static int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - const KmouseProt *prot = km->prot; - int i; - - for (i = 0; i < ne; i++) - { - if ((ev[i] & 0x40) == 0x40) - break; - if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0) - break; - } - if (i != 0) - return i; - for (i = 1; i < ne; i++) - if ((ev[i] & prot->dataMask) != prot->dataValid) - return -1; - return 0; -} - -static Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy; - unsigned long flags; - - flags = KD_MOUSE_DELTA; - - if (ne == 3) - { - if (ev[0] & 0x20) - flags |= KD_BUTTON_1; - if (ev[0] & 0x10) - flags |= KD_BUTTON_3; - - dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); - dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); - flags |= km->state & KD_BUTTON_2; - } - else - { - if (ev[0] & 0x20) - flags |= KD_BUTTON_2; - dx = 0; - dy = 0; - flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3); - } - - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - return TRUE; -} - -static const KmouseProt logiProt = { - "logitech", - logiComplete, logiValid, logiParse, 0, - 0xc0, 0x40, 0xc0, 0x00, - TRUE, - IGNPAR, - 0, - 0, - CS7 | CSTOPB | CREAD | CLOCAL, - B1200, -}; - -/* - * Mouse systems protocol, 5 bytes - */ -static Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy; - unsigned long flags; - - flags = KD_MOUSE_DELTA; - - if (!(ev[0] & 0x4)) - flags |= KD_BUTTON_1; - if (!(ev[0] & 0x2)) - flags |= KD_BUTTON_2; - if (!(ev[0] & 0x1)) - flags |= KD_BUTTON_3; - dx = (signed char)(ev[1]) + (signed char)(ev[3]); - dy = - ((signed char)(ev[2]) + (signed char)(ev[4])); - - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - return TRUE; -} - -static const KmouseProt mscProt = { - "msc", - fiveComplete, mouseValid, mscParse, 0, - 0xf8, 0x80, 0x00, 0x00, - TRUE, - IGNPAR, - 0, - 0, - CS8 | CSTOPB | CREAD | CLOCAL, - B1200, -}; - -/* - * Use logitech before ms -- they're the same except that - * logitech sometimes has a fourth byte - */ -static const KmouseProt *kmouseProts[] = { - &ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt, -}; - -#define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0])) - -static void -MouseInitProtocol (Kmouse *km) -{ - int ret; - struct termios t; - - if (km->prot->tty) - { - ret = tcgetattr (km->iob.fd, &t); - - if (ret >= 0) - { - t.c_iflag = km->prot->c_iflag; - t.c_oflag = km->prot->c_oflag; - t.c_lflag = km->prot->c_lflag; - t.c_cflag = km->prot->c_cflag; - cfsetispeed (&t, km->prot->speed); - cfsetospeed (&t, km->prot->speed); - ret = tcsetattr (km->iob.fd, TCSANOW, &t); - } - } - km->stage = MouseBroken; - km->valid = 0; - km->tested = 0; - km->invalid = 0; - km->state = km->prot->state; -} - -static void -MouseFirstProtocol (Kmouse *km, char *prot) -{ - if (prot) - { - for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++) - if (!strcmp (prot, kmouseProts[km->i_prot]->name)) - break; - if (km->i_prot == NUM_PROT) - { - int i; - ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot); - for (i = 0; i < NUM_PROT; i++) - ErrorF (" %s", kmouseProts[i]->name); - ErrorF ("\n"); - } - else - { - km->prot = kmouseProts[km->i_prot]; - if (km->tty && !km->prot->tty) - ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n", - prot); - else if (!km->tty && km->prot->tty) - ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n", - prot); - } - } - if (!km->prot) - { - for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++) - ; - km->prot = kmouseProts[km->i_prot]; - } - MouseInitProtocol (km); -} - -static void -MouseNextProtocol (Kmouse *km) -{ - do - { - if (!km->prot) - km->i_prot = 0; - else - if (++km->i_prot == NUM_PROT) km->i_prot = 0; - km->prot = kmouseProts[km->i_prot]; - } while (km->prot->tty != km->tty); - MouseInitProtocol (km); - ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name); -} - -static void -MouseRead (int mousePort, void *closure) -{ - KdPointerInfo *pi = closure; - Kmouse *km = pi->driverPrivate; - unsigned char event[MAX_MOUSE]; - int ne; - int c; - int i; - int timeout; - - timeout = 0; - ne = 0; - for(;;) - { - c = MouseReadByte (&km->iob, timeout); - if (c == -1) - { - if (ne) - { - km->invalid += ne + km->tested; - km->valid = 0; - km->tested = 0; - km->stage = MouseBroken; - } - break; - } - event[ne++] = c; - i = (*km->prot->Valid) (pi, event, ne); - if (i != 0) - { -#ifdef DEBUG - ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n", - km->prot->name, i > 0 ? i : ne, ne); -#endif - if (i > 0 && i < ne) - { - ne -= i; - memmove (event, event + i, ne); - } - else - { - i = ne; - ne = 0; - } - km->invalid += i + km->tested; - km->valid = 0; - km->tested = 0; - if (km->stage == MouseWorking) - km->i_prot--; - km->stage = MouseBroken; - if (km->invalid > MAX_SKIP) - { - MouseNextProtocol (km); - ne = 0; - } - timeout = 0; - } - else - { - if ((*km->prot->Complete) (pi, event, ne)) - { - if ((*km->prot->Parse) (pi, event, ne)) - { - switch (km->stage) - { - case MouseBroken: -#ifdef DEBUG - ErrorF ("Mouse protocol %s seems OK\n", - km->prot->name); -#endif - /* do not zero invalid to accumulate invalid bytes */ - km->valid = 0; - km->tested = 0; - km->stage = MouseTesting; - /* fall through ... */ - case MouseTesting: - km->valid++; - km->tested += ne; - if (km->valid > MAX_VALID) - { -#ifdef DEBUG - ErrorF ("Mouse protocol %s working\n", - km->prot->name); -#endif - km->stage = MouseWorking; - km->invalid = 0; - km->tested = 0; - km->valid = 0; - if (km->prot->Init && !(*km->prot->Init) (pi)) - km->stage = MouseBroken; - } - break; - case MouseWorking: - break; - } - } - else - { - km->invalid += ne + km->tested; - km->valid = 0; - km->tested = 0; - km->stage = MouseBroken; - } - ne = 0; - timeout = 0; - } - else - timeout = MOUSE_TIMEOUT; - } - } -} - -int MouseInputType; - -char *kdefaultMouse[] = { - "/dev/input/mice", - "/dev/mouse", - "/dev/psaux", - "/dev/adbmouse", - "/dev/ttyS0", - "/dev/ttyS1", -}; - -#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0])) - -static Status -MouseInit (KdPointerInfo *pi) -{ - int i; - int fd; - Kmouse *km; - - if (!pi) - return BadImplementation; - - if (!pi->path || strcmp(pi->path, "auto") == 0) { - for (i = 0; i < NUM_DEFAULT_MOUSE; i++) { - fd = open (kdefaultMouse[i], 2); - if (fd >= 0) { - pi->path = strdup (kdefaultMouse[i]); - break; - } - } - } - else { - fd = open (pi->path, 2); - } - - if (fd < 0) - return BadMatch; - - close(fd); - - km = (Kmouse *) xalloc (sizeof (Kmouse)); - if (km) { - km->iob.avail = km->iob.used = 0; - MouseFirstProtocol(km, pi->protocol ? pi->protocol : "exps/2"); - /* MouseFirstProtocol sets state to MouseBroken for later protocol - * checks. Skip these checks if a protocol was supplied */ - if (pi->protocol) - km->state = MouseWorking; - km->i_prot = 0; - km->tty = isatty (fd); - km->iob.fd = -1; - pi->driverPrivate = km; - } - else { - close (fd); - return BadAlloc; - } - - return Success; -} - -static Status -MouseEnable (KdPointerInfo *pi) -{ - Kmouse *km; - - if (!pi || !pi->driverPrivate || !pi->path) - return BadImplementation; - - km = pi->driverPrivate; - - km->iob.fd = open(pi->path, 2); - if (km->iob.fd < 0) - return BadMatch; - - if (!KdRegisterFd (km->iob.fd, MouseRead, pi)) - { - close(km->iob.fd); - return BadAlloc; - } - - return Success; -} - -static void -MouseDisable (KdPointerInfo *pi) -{ - Kmouse *km; - if (!pi || !pi->driverPrivate) - return; - - km = pi->driverPrivate; - KdUnregisterFd (pi, km->iob.fd, TRUE); -} - -static void -MouseFini (KdPointerInfo *pi) -{ - xfree (pi->driverPrivate); - pi->driverPrivate = NULL; -} - -KdPointerDriver LinuxMouseDriver = { - "mouse", - MouseInit, - MouseEnable, - MouseDisable, - MouseFini, - NULL, -}; +/* + * Copyright © 2001 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include <errno.h> +#include <termios.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/Xpoll.h> +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" + +#undef DEBUG +#undef DEBUG_BYTES +#define KBUFIO_SIZE 256 +#define MOUSE_TIMEOUT 100 + +typedef struct _kbufio { + int fd; + unsigned char buf[KBUFIO_SIZE]; + int avail; + int used; +} Kbufio; + +static Bool +MouseWaitForReadable (int fd, int timeout) +{ + fd_set set; + struct timeval tv, *tp; + int n; + CARD32 done; + + done = GetTimeInMillis () + timeout; + for (;;) + { + FD_ZERO (&set); + FD_SET (fd, &set); + if (timeout == -1) + tp = 0; + else + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + tp = &tv; + } + n = select (fd + 1, &set, 0, 0, tp); + if (n > 0) + return TRUE; + if (n < 0 && (errno == EAGAIN || errno == EINTR)) + { + timeout = (int) (done - GetTimeInMillis ()); + if (timeout > 0) + continue; + } + break; + } + return FALSE; +} + +static int +MouseReadByte (Kbufio *b, int timeout) +{ + int n; + if (b->avail <= b->used) + { + if (timeout && !MouseWaitForReadable (b->fd, timeout)) + { +#ifdef DEBUG_BYTES + ErrorF ("\tTimeout %d\n", timeout); +#endif + return -1; + } + n = read (b->fd, b->buf, KBUFIO_SIZE); + if (n <= 0) + return -1; + b->avail = n; + b->used = 0; + } +#ifdef DEBUG_BYTES + ErrorF ("\tget %02x\n", b->buf[b->used]); +#endif + return b->buf[b->used++]; +} + +#if NOTUSED +static int +MouseFlush (Kbufio *b, char *buf, int size) +{ + CARD32 now = GetTimeInMillis (); + CARD32 done = now + 100; + int c; + int n = 0; + + while ((c = MouseReadByte (b, done - now)) != -1) + { + if (buf) + { + if (n == size) + { + memmove (buf, buf + 1, size - 1); + n--; + } + buf[n++] = c; + } + now = GetTimeInMillis (); + if ((INT32) (now - done) >= 0) + break; + } + return n; +} + +static int +MousePeekByte (Kbufio *b, int timeout) +{ + int c; + + c = MouseReadByte (b, timeout); + if (c != -1) + --b->used; + return c; +} +#endif /* NOTUSED */ + +static Bool +MouseWaitForWritable (int fd, int timeout) +{ + fd_set set; + struct timeval tv, *tp; + int n; + + FD_ZERO (&set); + FD_SET (fd, &set); + if (timeout == -1) + tp = 0; + else + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + tp = &tv; + } + n = select (fd + 1, 0, &set, 0, tp); + if (n > 0) + return TRUE; + return FALSE; +} + +static Bool +MouseWriteByte (int fd, unsigned char c, int timeout) +{ + int ret; + +#ifdef DEBUG_BYTES + ErrorF ("\tput %02x\n", c); +#endif + for (;;) + { + ret = write (fd, &c, 1); + if (ret == 1) + return TRUE; + if (ret == 0) + return FALSE; + if (errno != EWOULDBLOCK) + return FALSE; + if (!MouseWaitForWritable (fd, timeout)) + return FALSE; + } +} + +static Bool +MouseWriteBytes (int fd, unsigned char *c, int n, int timeout) +{ + while (n--) + if (!MouseWriteByte (fd, *c++, timeout)) + return FALSE; + return TRUE; +} + +#define MAX_MOUSE 10 /* maximum length of mouse protocol */ +#define MAX_SKIP 16 /* number of error bytes before switching */ +#define MAX_VALID 4 /* number of valid packets before accepting */ + +typedef struct _kmouseProt { + char *name; + Bool (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne); + int (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne); + Bool (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne); + Bool (*Init) (KdPointerInfo *pi); + unsigned char headerMask, headerValid; + unsigned char dataMask, dataValid; + Bool tty; + unsigned int c_iflag; + unsigned int c_oflag; + unsigned int c_lflag; + unsigned int c_cflag; + unsigned int speed; + unsigned char *init; + unsigned long state; +} KmouseProt; + +typedef enum _kmouseStage { + MouseBroken, MouseTesting, MouseWorking +} KmouseStage; + +typedef struct _kmouse { + Kbufio iob; + const KmouseProt *prot; + int i_prot; + KmouseStage stage; /* protocol verification stage */ + Bool tty; /* mouse device is a tty */ + int valid; /* sequential valid events */ + int tested; /* bytes scanned during Testing phase */ + int invalid;/* total invalid bytes for this protocol */ + unsigned long state; /* private per protocol, init to prot->state */ +} Kmouse; + +static int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + const KmouseProt *prot = km->prot; + int i; + + for (i = 0; i < ne; i++) + if ((ev[i] & prot->headerMask) == prot->headerValid) + break; + if (i != 0) + return i; + for (i = 1; i < ne; i++) + if ((ev[i] & prot->dataMask) != prot->dataValid) + return -1; + return 0; +} + +static Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + return ne == 3; +} + +static Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + return ne == 4; +} + +static Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + return ne == 5; +} + +static Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy) +{ + Kmouse *km = pi->driverPrivate; + + if (km->stage == MouseWorking) + return TRUE; + if (dx < -50 || dx > 50) + { +#ifdef DEBUG + ErrorF ("Large X %d\n", dx); +#endif + return FALSE; + } + if (dy < -50 || dy > 50) + { +#ifdef DEBUG + ErrorF ("Large Y %d\n", dy); +#endif + return FALSE; + } + return TRUE; +} + +/* + * Standard PS/2 mouse protocol + */ +static Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy, dz; + unsigned long flags; + unsigned long flagsrelease = 0; + + flags = KD_MOUSE_DELTA; + if (ev[0] & 4) + flags |= KD_BUTTON_2; + if (ev[0] & 2) + flags |= KD_BUTTON_3; + if (ev[0] & 1) + flags |= KD_BUTTON_1; + + if (ne > 3) + { + dz = (int) (signed char) ev[3]; + if (dz < 0) + { + flags |= KD_BUTTON_4; + flagsrelease = KD_BUTTON_4; + } + else if (dz > 0) + { + flags |= KD_BUTTON_5; + flagsrelease = KD_BUTTON_5; + } + } + + dx = ev[1]; + if (ev[0] & 0x10) + dx -= 256; + dy = ev[2]; + if (ev[0] & 0x20) + dy -= 256; + dy = -dy; + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + { + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + if (flagsrelease) + { + flags &= ~flagsrelease; + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + } + } + return TRUE; +} + +static Bool ps2Init (KdPointerInfo *pi); + +static const KmouseProt ps2Prot = { + "ps/2", + threeComplete, mouseValid, ps2Parse, ps2Init, + 0x08, 0x08, 0x00, 0x00, + FALSE +}; + +static const KmouseProt imps2Prot = { + "imps/2", + fourComplete, mouseValid, ps2Parse, ps2Init, + 0x08, 0x08, 0x00, 0x00, + FALSE +}; + +static const KmouseProt exps2Prot = { + "exps/2", + fourComplete, mouseValid, ps2Parse, ps2Init, + 0x08, 0x08, 0x00, 0x00, + FALSE +}; + +/* + * Once the mouse is known to speak ps/2 protocol, go and find out + * what advanced capabilities it has and turn them on + */ + +/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */ + +/* aux device commands (sent to KBD_DATA_PORT) */ +#define PSMC_SET_SCALING11 0x00e6 +#define PSMC_SET_SCALING21 0x00e7 +#define PSMC_SET_RESOLUTION 0x00e8 +#define PSMC_SEND_DEV_STATUS 0x00e9 +#define PSMC_SET_STREAM_MODE 0x00ea +#define PSMC_SEND_DEV_DATA 0x00eb +#define PSMC_SET_REMOTE_MODE 0x00f0 +#define PSMC_SEND_DEV_ID 0x00f2 +#define PSMC_SET_SAMPLING_RATE 0x00f3 +#define PSMC_ENABLE_DEV 0x00f4 +#define PSMC_DISABLE_DEV 0x00f5 +#define PSMC_SET_DEFAULTS 0x00f6 +#define PSMC_RESET_DEV 0x00ff + +/* PSMC_SET_RESOLUTION argument */ +#define PSMD_RES_LOW 0 /* typically 25ppi */ +#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */ +#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */ +#define PSMD_RES_HIGH 3 /* typically 200ppi */ +#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH + +/* PSMC_SET_SAMPLING_RATE */ +#define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */ + +/* aux device ID */ +#define PSM_MOUSE_ID 0 +#define PSM_BALLPOINT_ID 2 +#define PSM_INTELLI_ID 3 +#define PSM_EXPLORER_ID 4 +#define PSM_4DMOUSE_ID 6 +#define PSM_4DPLUS_ID 8 + +static unsigned char ps2_init[] = { + PSMC_ENABLE_DEV, + 0, +}; + +#define NINIT_PS2 1 + +static unsigned char wheel_3button_init[] = { + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 100, + PSMC_SET_SAMPLING_RATE, 80, + PSMC_SEND_DEV_ID, + 0, +}; + +#define NINIT_IMPS2 4 + +static unsigned char wheel_5button_init[] = { + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 100, + PSMC_SET_SAMPLING_RATE, 80, + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 80, + PSMC_SEND_DEV_ID, + 0 +}; + +#define NINIT_EXPS2 7 + +static unsigned char intelli_init[] = { + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 100, + PSMC_SET_SAMPLING_RATE, 80, + 0 +}; + +#define NINIT_INTELLI 3 + +static int +ps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next) +{ + Kmouse *km = pi->driverPrivate; + int c = -1; + int skipping; + Bool waiting; + + skipping = 0; + waiting = FALSE; + while (ninit || ret_next) + { + c = MouseReadByte (&km->iob, MOUSE_TIMEOUT); + if (c == -1) + break; + /* look for ACK */ + if (c == 0xfa) + { + ninit--; + if (ret_next) + waiting = TRUE; + } + /* look for packet start -- not the response */ + else if ((c & 0x08) == 0x08) + waiting = FALSE; + else if (waiting) + break; + } + return c; +} + +static Bool +ps2Init (KdPointerInfo *pi) +{ + Kmouse *km = pi->driverPrivate; + int skipping; + Bool waiting; + int id; + unsigned char *init; + int ninit; + + /* Send Intellimouse initialization sequence */ + MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100); + /* + * Send ID command + */ + if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100)) + return FALSE; + skipping = 0; + waiting = FALSE; + id = ps2SkipInit (pi, 0, TRUE); + switch (id) { + case 3: + init = wheel_3button_init; + ninit = NINIT_IMPS2; + km->prot = &imps2Prot; + break; + case 4: + init = wheel_5button_init; + ninit = NINIT_EXPS2; + km->prot = &exps2Prot; + break; + default: + init = ps2_init; + ninit = NINIT_PS2; + km->prot = &ps2Prot; + break; + } + if (init) + MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100); + /* + * Flush out the available data to eliminate responses to the + * initialization string. Make sure any partial event is + * skipped + */ + (void) ps2SkipInit (pi, ninit, FALSE); + return TRUE; +} + +static Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + dx = (signed char) ev[1]; + dy = -(signed char) ev[2]; + if ((ev[0] & 4) == 0) + flags |= KD_BUTTON_1; + if ((ev[0] & 2) == 0) + flags |= KD_BUTTON_2; + if ((ev[0] & 1) == 0) + flags |= KD_BUTTON_3; + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt busProt = { + "bus", + threeComplete, mouseValid, busParse, 0, + 0xf8, 0x00, 0x00, 0x00, + FALSE +}; + +/* + * Standard MS serial protocol, three bytes + */ + +static Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + + if (ev[0] & 0x20) + flags |= KD_BUTTON_1; + if (ev[0] & 0x10) + flags |= KD_BUTTON_3; + + dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); + dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt msProt = { + "ms", + threeComplete, mouseValid, msParse, 0, + 0xc0, 0x40, 0xc0, 0x00, + TRUE, + IGNPAR, + 0, + 0, + CS7 | CSTOPB | CREAD | CLOCAL, + B1200, +}; + +/* + * Logitech mice send 3 or 4 bytes, the only way to tell is to look at the + * first byte of a synchronized protocol stream and see if it's got + * any bits turned on that can't occur in that fourth byte + */ +static Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + + if ((ev[0] & 0x40) == 0x40) + return ne == 3; + if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0) + return ne == 1; + return FALSE; +} + +static int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + const KmouseProt *prot = km->prot; + int i; + + for (i = 0; i < ne; i++) + { + if ((ev[i] & 0x40) == 0x40) + break; + if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0) + break; + } + if (i != 0) + return i; + for (i = 1; i < ne; i++) + if ((ev[i] & prot->dataMask) != prot->dataValid) + return -1; + return 0; +} + +static Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + + if (ne == 3) + { + if (ev[0] & 0x20) + flags |= KD_BUTTON_1; + if (ev[0] & 0x10) + flags |= KD_BUTTON_3; + + dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); + dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); + flags |= km->state & KD_BUTTON_2; + } + else + { + if (ev[0] & 0x20) + flags |= KD_BUTTON_2; + dx = 0; + dy = 0; + flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3); + } + + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt logiProt = { + "logitech", + logiComplete, logiValid, logiParse, 0, + 0xc0, 0x40, 0xc0, 0x00, + TRUE, + IGNPAR, + 0, + 0, + CS7 | CSTOPB | CREAD | CLOCAL, + B1200, +}; + +/* + * Mouse systems protocol, 5 bytes + */ +static Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + + if (!(ev[0] & 0x4)) + flags |= KD_BUTTON_1; + if (!(ev[0] & 0x2)) + flags |= KD_BUTTON_2; + if (!(ev[0] & 0x1)) + flags |= KD_BUTTON_3; + dx = (signed char)(ev[1]) + (signed char)(ev[3]); + dy = - ((signed char)(ev[2]) + (signed char)(ev[4])); + + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt mscProt = { + "msc", + fiveComplete, mouseValid, mscParse, 0, + 0xf8, 0x80, 0x00, 0x00, + TRUE, + IGNPAR, + 0, + 0, + CS8 | CSTOPB | CREAD | CLOCAL, + B1200, +}; + +/* + * Use logitech before ms -- they're the same except that + * logitech sometimes has a fourth byte + */ +static const KmouseProt *kmouseProts[] = { + &ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt, +}; + +#define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0])) + +static void +MouseInitProtocol (Kmouse *km) +{ + int ret; + struct termios t; + + if (km->prot->tty) + { + ret = tcgetattr (km->iob.fd, &t); + + if (ret >= 0) + { + t.c_iflag = km->prot->c_iflag; + t.c_oflag = km->prot->c_oflag; + t.c_lflag = km->prot->c_lflag; + t.c_cflag = km->prot->c_cflag; + cfsetispeed (&t, km->prot->speed); + cfsetospeed (&t, km->prot->speed); + ret = tcsetattr (km->iob.fd, TCSANOW, &t); + } + } + km->stage = MouseBroken; + km->valid = 0; + km->tested = 0; + km->invalid = 0; + km->state = km->prot->state; +} + +static void +MouseFirstProtocol (Kmouse *km, char *prot) +{ + if (prot) + { + for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++) + if (!strcmp (prot, kmouseProts[km->i_prot]->name)) + break; + if (km->i_prot == NUM_PROT) + { + int i; + ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot); + for (i = 0; i < NUM_PROT; i++) + ErrorF (" %s", kmouseProts[i]->name); + ErrorF ("\n"); + } + else + { + km->prot = kmouseProts[km->i_prot]; + if (km->tty && !km->prot->tty) + ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n", + prot); + else if (!km->tty && km->prot->tty) + ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n", + prot); + } + } + if (!km->prot) + { + for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++) + ; + km->prot = kmouseProts[km->i_prot]; + } + MouseInitProtocol (km); +} + +static void +MouseNextProtocol (Kmouse *km) +{ + do + { + if (!km->prot) + km->i_prot = 0; + else + if (++km->i_prot == NUM_PROT) km->i_prot = 0; + km->prot = kmouseProts[km->i_prot]; + } while (km->prot->tty != km->tty); + MouseInitProtocol (km); + ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name); +} + +static void +MouseRead (int mousePort, void *closure) +{ + KdPointerInfo *pi = closure; + Kmouse *km = pi->driverPrivate; + unsigned char event[MAX_MOUSE]; + int ne; + int c; + int i; + int timeout; + + timeout = 0; + ne = 0; + for(;;) + { + c = MouseReadByte (&km->iob, timeout); + if (c == -1) + { + if (ne) + { + km->invalid += ne + km->tested; + km->valid = 0; + km->tested = 0; + km->stage = MouseBroken; + } + break; + } + event[ne++] = c; + i = (*km->prot->Valid) (pi, event, ne); + if (i != 0) + { +#ifdef DEBUG + ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n", + km->prot->name, i > 0 ? i : ne, ne); +#endif + if (i > 0 && i < ne) + { + ne -= i; + memmove (event, event + i, ne); + } + else + { + i = ne; + ne = 0; + } + km->invalid += i + km->tested; + km->valid = 0; + km->tested = 0; + if (km->stage == MouseWorking) + km->i_prot--; + km->stage = MouseBroken; + if (km->invalid > MAX_SKIP) + { + MouseNextProtocol (km); + ne = 0; + } + timeout = 0; + } + else + { + if ((*km->prot->Complete) (pi, event, ne)) + { + if ((*km->prot->Parse) (pi, event, ne)) + { + switch (km->stage) + { + case MouseBroken: +#ifdef DEBUG + ErrorF ("Mouse protocol %s seems OK\n", + km->prot->name); +#endif + /* do not zero invalid to accumulate invalid bytes */ + km->valid = 0; + km->tested = 0; + km->stage = MouseTesting; + /* fall through ... */ + case MouseTesting: + km->valid++; + km->tested += ne; + if (km->valid > MAX_VALID) + { +#ifdef DEBUG + ErrorF ("Mouse protocol %s working\n", + km->prot->name); +#endif + km->stage = MouseWorking; + km->invalid = 0; + km->tested = 0; + km->valid = 0; + if (km->prot->Init && !(*km->prot->Init) (pi)) + km->stage = MouseBroken; + } + break; + case MouseWorking: + break; + } + } + else + { + km->invalid += ne + km->tested; + km->valid = 0; + km->tested = 0; + km->stage = MouseBroken; + } + ne = 0; + timeout = 0; + } + else + timeout = MOUSE_TIMEOUT; + } + } +} + +int MouseInputType; + +char *kdefaultMouse[] = { + "/dev/input/mice", + "/dev/mouse", + "/dev/psaux", + "/dev/adbmouse", + "/dev/ttyS0", + "/dev/ttyS1", +}; + +#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0])) + +static Status +MouseInit (KdPointerInfo *pi) +{ + int i; + int fd; + Kmouse *km; + + if (!pi) + return BadImplementation; + + if (!pi->path || strcmp(pi->path, "auto") == 0) { + for (i = 0; i < NUM_DEFAULT_MOUSE; i++) { + fd = open (kdefaultMouse[i], 2); + if (fd >= 0) { + pi->path = strdup (kdefaultMouse[i]); + break; + } + } + } + else { + fd = open (pi->path, 2); + } + + if (fd < 0) + return BadMatch; + + close(fd); + + km = (Kmouse *) malloc(sizeof (Kmouse)); + if (km) { + km->iob.avail = km->iob.used = 0; + MouseFirstProtocol(km, pi->protocol ? pi->protocol : "exps/2"); + /* MouseFirstProtocol sets state to MouseBroken for later protocol + * checks. Skip these checks if a protocol was supplied */ + if (pi->protocol) + km->state = MouseWorking; + km->i_prot = 0; + km->tty = isatty (fd); + km->iob.fd = -1; + pi->driverPrivate = km; + } + else { + close (fd); + return BadAlloc; + } + + return Success; +} + +static Status +MouseEnable (KdPointerInfo *pi) +{ + Kmouse *km; + + if (!pi || !pi->driverPrivate || !pi->path) + return BadImplementation; + + km = pi->driverPrivate; + + km->iob.fd = open(pi->path, 2); + if (km->iob.fd < 0) + return BadMatch; + + if (!KdRegisterFd (km->iob.fd, MouseRead, pi)) + { + close(km->iob.fd); + return BadAlloc; + } + + return Success; +} + +static void +MouseDisable (KdPointerInfo *pi) +{ + Kmouse *km; + if (!pi || !pi->driverPrivate) + return; + + km = pi->driverPrivate; + KdUnregisterFd (pi, km->iob.fd, TRUE); +} + +static void +MouseFini (KdPointerInfo *pi) +{ + free(pi->driverPrivate); + pi->driverPrivate = NULL; +} + +KdPointerDriver LinuxMouseDriver = { + "mouse", + MouseInit, + MouseEnable, + MouseDisable, + MouseFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/linux/tslib.c b/xorg-server/hw/kdrive/linux/tslib.c index 322ccc7d5..ee0f779f3 100644 --- a/xorg-server/hw/kdrive/linux/tslib.c +++ b/xorg-server/hw/kdrive/linux/tslib.c @@ -1,190 +1,190 @@ -/* - * TSLIB based touchscreen driver for KDrive - * Porting to new input API and event queueing by Daniel Stone. - * Derived from ts.c by Keith Packard - * Derived from ps2.c by Jim Gettys - * - * Copyright © 1999 Keith Packard - * Copyright © 2000 Compaq Computer Corporation - * Copyright © 2002 MontaVista Software Inc. - * Copyright © 2005 OpenedHand Ltd. - * Copyright © 2006 Nokia Corporation - * - * 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 the authors and/or copyright holders - * not be used in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. The authors and/or - * copyright holders make no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * THE AUTHORS AND/OR COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS AND/OR COPYRIGHT HOLDERS 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_KDRIVE_CONFIG_H -#include <kdrive-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/Xpoll.h> -#include "inputstr.h" -#include "scrnintstr.h" -#include "kdrive.h" -#include <sys/ioctl.h> -#include <tslib.h> -#include <dirent.h> -#include <linux/input.h> - -struct TslibPrivate { - int fd; - int lastx, lasty; - struct tsdev *tsDev; - void (*raw_event_hook)(int x, int y, int pressure, void *closure); - void *raw_event_closure; - int phys_screen; -}; - - -static void -TsRead (int fd, void *closure) -{ - KdPointerInfo *pi = closure; - struct TslibPrivate *private = pi->driverPrivate; - struct ts_sample event; - long x = 0, y = 0; - unsigned long flags; - - if (private->raw_event_hook) { - while (ts_read_raw(private->tsDev, &event, 1) == 1) - private->raw_event_hook (event.x, event.y, event.pressure, - private->raw_event_closure); - return; - } - - while (ts_read(private->tsDev, &event, 1) == 1) { - if (event.pressure) { - flags = KD_BUTTON_1; - - /* - * Here we test for the touch screen driver actually being on the - * touch screen, if it is we send absolute coordinates. If not, - * then we send delta's so that we can track the entire vga screen. - */ - if (KdCurScreen == private->phys_screen) { - x = event.x; - y = event.y; - } else { - flags |= KD_MOUSE_DELTA; - if ((private->lastx == 0) || (private->lasty == 0)) { - x = event.x; - y = event.y; - } else { - x = event.x - private->lastx; - y = event.y - private->lasty; - } - } - private->lastx = event.x; - private->lasty = event.y; - } else { - flags = 0; - x = private->lastx; - y = private->lasty; - } - - KdEnqueuePointerEvent (pi, flags, x, y, event.pressure); - } -} - -static Status -TslibEnable (KdPointerInfo *pi) -{ - struct TslibPrivate *private = pi->driverPrivate; - - private->raw_event_hook = NULL; - private->raw_event_closure = NULL; - if (!pi->path) { - pi->path = strdup("/dev/input/touchscreen0"); - ErrorF("[tslib/TslibEnable] no device path given, trying %s\n", pi->path); - } - private->tsDev = ts_open(pi->path, 0); - private->fd = ts_fd(private->tsDev); - if (!private->tsDev || ts_config(private->tsDev) || private->fd < 0) { - ErrorF("[tslib/TslibEnable] failed to open %s\n", pi->path); - if (private->fd >= 0) - close(private->fd); - return BadAlloc; - } - - KdRegisterFd(private->fd, TsRead, pi); - - return Success; -} - - -static void -TslibDisable (KdPointerInfo *pi) -{ - struct TslibPrivate *private = pi->driverPrivate; - - if (private->fd) - KdUnregisterFd(pi, private->fd, TRUE); - - if (private->tsDev) - ts_close(private->tsDev); - - private->fd = 0; - private->tsDev = NULL; -} - - -static Status -TslibInit (KdPointerInfo *pi) -{ - struct TslibPrivate *private = NULL; - - if (!pi || !pi->dixdev) - return !Success; - - pi->driverPrivate = (struct TslibPrivate *) - xcalloc(sizeof(struct TslibPrivate), 1); - if (!pi->driverPrivate) - return !Success; - - private = pi->driverPrivate; - /* hacktastic */ - private->phys_screen = 0; - pi->nAxes = 3; - pi->name = strdup("Touchscreen"); - pi->inputClass = KD_TOUCHSCREEN; - - return Success; -} - - -static void -TslibFini (KdPointerInfo *pi) -{ - xfree(pi->driverPrivate); - pi->driverPrivate = NULL; -} - - -KdPointerDriver TsDriver = { - "tslib", - TslibInit, - TslibEnable, - TslibDisable, - TslibFini, - NULL, -}; +/* + * TSLIB based touchscreen driver for KDrive + * Porting to new input API and event queueing by Daniel Stone. + * Derived from ts.c by Keith Packard + * Derived from ps2.c by Jim Gettys + * + * Copyright © 1999 Keith Packard + * Copyright © 2000 Compaq Computer Corporation + * Copyright © 2002 MontaVista Software Inc. + * Copyright © 2005 OpenedHand Ltd. + * Copyright © 2006 Nokia Corporation + * + * 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 the authors and/or copyright holders + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. The authors and/or + * copyright holders make no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * THE AUTHORS AND/OR COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS AND/OR COPYRIGHT HOLDERS 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_KDRIVE_CONFIG_H +#include <kdrive-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/Xpoll.h> +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" +#include <sys/ioctl.h> +#include <tslib.h> +#include <dirent.h> +#include <linux/input.h> + +struct TslibPrivate { + int fd; + int lastx, lasty; + struct tsdev *tsDev; + void (*raw_event_hook)(int x, int y, int pressure, void *closure); + void *raw_event_closure; + int phys_screen; +}; + + +static void +TsRead (int fd, void *closure) +{ + KdPointerInfo *pi = closure; + struct TslibPrivate *private = pi->driverPrivate; + struct ts_sample event; + long x = 0, y = 0; + unsigned long flags; + + if (private->raw_event_hook) { + while (ts_read_raw(private->tsDev, &event, 1) == 1) + private->raw_event_hook (event.x, event.y, event.pressure, + private->raw_event_closure); + return; + } + + while (ts_read(private->tsDev, &event, 1) == 1) { + if (event.pressure) { + flags = KD_BUTTON_1; + + /* + * Here we test for the touch screen driver actually being on the + * touch screen, if it is we send absolute coordinates. If not, + * then we send delta's so that we can track the entire vga screen. + */ + if (KdCurScreen == private->phys_screen) { + x = event.x; + y = event.y; + } else { + flags |= KD_MOUSE_DELTA; + if ((private->lastx == 0) || (private->lasty == 0)) { + x = event.x; + y = event.y; + } else { + x = event.x - private->lastx; + y = event.y - private->lasty; + } + } + private->lastx = event.x; + private->lasty = event.y; + } else { + flags = 0; + x = private->lastx; + y = private->lasty; + } + + KdEnqueuePointerEvent (pi, flags, x, y, event.pressure); + } +} + +static Status +TslibEnable (KdPointerInfo *pi) +{ + struct TslibPrivate *private = pi->driverPrivate; + + private->raw_event_hook = NULL; + private->raw_event_closure = NULL; + if (!pi->path) { + pi->path = strdup("/dev/input/touchscreen0"); + ErrorF("[tslib/TslibEnable] no device path given, trying %s\n", pi->path); + } + private->tsDev = ts_open(pi->path, 0); + private->fd = ts_fd(private->tsDev); + if (!private->tsDev || ts_config(private->tsDev) || private->fd < 0) { + ErrorF("[tslib/TslibEnable] failed to open %s\n", pi->path); + if (private->fd >= 0) + close(private->fd); + return BadAlloc; + } + + KdRegisterFd(private->fd, TsRead, pi); + + return Success; +} + + +static void +TslibDisable (KdPointerInfo *pi) +{ + struct TslibPrivate *private = pi->driverPrivate; + + if (private->fd) + KdUnregisterFd(pi, private->fd, TRUE); + + if (private->tsDev) + ts_close(private->tsDev); + + private->fd = 0; + private->tsDev = NULL; +} + + +static Status +TslibInit (KdPointerInfo *pi) +{ + struct TslibPrivate *private = NULL; + + if (!pi || !pi->dixdev) + return !Success; + + pi->driverPrivate = (struct TslibPrivate *) + calloc(sizeof(struct TslibPrivate), 1); + if (!pi->driverPrivate) + return !Success; + + private = pi->driverPrivate; + /* hacktastic */ + private->phys_screen = 0; + pi->nAxes = 3; + pi->name = strdup("Touchscreen"); + pi->inputClass = KD_TOUCHSCREEN; + + return Success; +} + + +static void +TslibFini (KdPointerInfo *pi) +{ + free(pi->driverPrivate); + pi->driverPrivate = NULL; +} + + +KdPointerDriver TsDriver = { + "tslib", + TslibInit, + TslibEnable, + TslibDisable, + TslibFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/src/kcmap.c b/xorg-server/hw/kdrive/src/kcmap.c index 40697e091..127c7a078 100644 --- a/xorg-server/hw/kdrive/src/kcmap.c +++ b/xorg-server/hw/kdrive/src/kcmap.c @@ -1,246 +1,246 @@ -/* - * Copyright © 1999 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include "kdrive.h" - -/* - * Put the entire colormap into the DAC - */ - -void -KdSetColormap (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - ColormapPtr pCmap = pScreenPriv->pInstalledmap; - Pixel pixels[KD_MAX_PSEUDO_SIZE]; - xrgb colors[KD_MAX_PSEUDO_SIZE]; - xColorItem defs[KD_MAX_PSEUDO_SIZE]; - int i; - - if (!pScreenPriv->card->cfuncs->putColors) - return; - if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) - return; - - if (!pScreenPriv->enabled) - return; - - if (!pCmap) - return; - - /* - * Make DIX convert pixels into RGB values -- this handles - * true/direct as well as pseudo/static visuals - */ - - for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) - pixels[i] = i; - - QueryColors (pCmap, (1 << pScreenPriv->screen->fb.depth), pixels, colors); - - for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) - { - defs[i].pixel = i; - defs[i].red = colors[i].red; - defs[i].green = colors[i].green; - defs[i].blue = colors[i].blue; - defs[i].flags = DoRed|DoGreen|DoBlue; - } - - (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, - (1 << pScreenPriv->screen->fb.depth), - defs); - - /* recolor hardware cursor */ - if (pScreenPriv->card->cfuncs->recolorCursor) - (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, 0, 0); -} - -/* - * When the hardware is enabled, save the hardware colors and store - * the current colormap - */ -void -KdEnableColormap (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - int i; - - if (!pScreenPriv->card->cfuncs->putColors) - return; - - if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) - { - for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) - pScreenPriv->systemPalette[i].pixel = i; - (*pScreenPriv->card->cfuncs->getColors) (pScreen, - (1 << pScreenPriv->screen->fb.depth), - pScreenPriv->systemPalette); - } - KdSetColormap (pScreen); -} - -void -KdDisableColormap (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - - if (!pScreenPriv->card->cfuncs->putColors) - return; - - if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) - { - (*pScreenPriv->card->cfuncs->putColors) (pScreen, - (1 << pScreenPriv->screen->fb.depth), - pScreenPriv->systemPalette); - } -} - -/* - * KdInstallColormap - * - * This function is called when the server receives a request to install a - * colormap or when the server needs to install one on its own, like when - * there's no window manager running and the user has moved the pointer over - * an X client window. It needs to build an identity Windows palette for the - * colormap and realize it into the Windows system palette. - */ -void -KdInstallColormap (ColormapPtr pCmap) -{ - KdScreenPriv(pCmap->pScreen); - - if (pCmap == pScreenPriv->pInstalledmap) - return; - - /* Tell X clients that the installed colormap is going away. */ - if (pScreenPriv->pInstalledmap) - WalkTree(pScreenPriv->pInstalledmap->pScreen, TellLostMap, - (pointer) &(pScreenPriv->pInstalledmap->mid)); - - /* Take note of the new installed colorscreen-> */ - pScreenPriv->pInstalledmap = pCmap; - - KdSetColormap (pCmap->pScreen); - - /* Tell X clients of the new colormap */ - WalkTree(pCmap->pScreen, TellGainedMap, (pointer) &(pCmap->mid)); -} - -/* - * KdUninstallColormap - * - * This function uninstalls a colormap by either installing - * the default X colormap or erasing the installed colormap pointer. - * The default X colormap itself cannot be uninstalled. - */ -void -KdUninstallColormap (ColormapPtr pCmap) -{ - KdScreenPriv(pCmap->pScreen); - Colormap defMapID; - ColormapPtr defMap; - - /* ignore if not installed */ - if (pCmap != pScreenPriv->pInstalledmap) - return; - - /* ignore attempts to uninstall default colormap */ - defMapID = pCmap->pScreen->defColormap; - if ((Colormap) pCmap->mid == defMapID) - return; - - /* install default */ - dixLookupResourceByType((pointer *)&defMap, defMapID, RT_COLORMAP, - serverClient, DixInstallAccess); - if (defMap) - (*pCmap->pScreen->InstallColormap)(defMap); - else - { - /* uninstall and clear colormap pointer */ - WalkTree(pCmap->pScreen, TellLostMap, - (pointer) &(pCmap->mid)); - pScreenPriv->pInstalledmap = 0; - } -} - -int -KdListInstalledColormaps (ScreenPtr pScreen, Colormap *pCmaps) -{ - KdScreenPriv(pScreen); - int n = 0; - - if (pScreenPriv->pInstalledmap) - { - *pCmaps++ = pScreenPriv->pInstalledmap->mid; - n++; - } - return n; -} - -/* - * KdStoreColors - * - * This function is called whenever the server receives a request to store - * color values into one or more entries in the currently installed X - * colormap; it can be either the default colormap or a private colorscreen-> - */ -void -KdStoreColors (ColormapPtr pCmap, int ndef, xColorItem *pdefs) -{ - KdScreenPriv(pCmap->pScreen); - VisualPtr pVisual; - xColorItem expanddefs[KD_MAX_PSEUDO_SIZE]; - - if (pCmap != pScreenPriv->pInstalledmap) - return; - - if (!pScreenPriv->card->cfuncs->putColors) - return; - - if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) - return; - - if (!pScreenPriv->enabled) - return; - - /* Check for DirectColor or TrueColor being simulated on a PseudoColor device. */ - pVisual = pCmap->pVisual; - if ((pVisual->class | DynamicClass) == DirectColor) - { - /* - * Expand DirectColor or TrueColor color values into a PseudoColor - * format. Defer to the Color Framebuffer (CFB) code to do that. - */ - ndef = fbExpandDirectColors(pCmap, ndef, pdefs, expanddefs); - pdefs = expanddefs; - } - - (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, ndef, pdefs); - - /* recolor hardware cursor */ - if (pScreenPriv->card->cfuncs->recolorCursor) - (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, ndef, pdefs); -} +/* + * Copyright © 1999 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" + +/* + * Put the entire colormap into the DAC + */ + +void +KdSetColormap (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ColormapPtr pCmap = pScreenPriv->pInstalledmap; + Pixel pixels[KD_MAX_PSEUDO_SIZE]; + xrgb colors[KD_MAX_PSEUDO_SIZE]; + xColorItem defs[KD_MAX_PSEUDO_SIZE]; + int i; + + if (!pScreenPriv->card->cfuncs->putColors) + return; + if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) + return; + + if (!pScreenPriv->enabled) + return; + + if (!pCmap) + return; + + /* + * Make DIX convert pixels into RGB values -- this handles + * true/direct as well as pseudo/static visuals + */ + + for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) + pixels[i] = i; + + QueryColors (pCmap, (1 << pScreenPriv->screen->fb.depth), pixels, colors, serverClient); + + for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) + { + defs[i].pixel = i; + defs[i].red = colors[i].red; + defs[i].green = colors[i].green; + defs[i].blue = colors[i].blue; + defs[i].flags = DoRed|DoGreen|DoBlue; + } + + (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, + (1 << pScreenPriv->screen->fb.depth), + defs); + + /* recolor hardware cursor */ + if (pScreenPriv->card->cfuncs->recolorCursor) + (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, 0, 0); +} + +/* + * When the hardware is enabled, save the hardware colors and store + * the current colormap + */ +void +KdEnableColormap (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + int i; + + if (!pScreenPriv->card->cfuncs->putColors) + return; + + if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) + { + for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) + pScreenPriv->systemPalette[i].pixel = i; + (*pScreenPriv->card->cfuncs->getColors) (pScreen, + (1 << pScreenPriv->screen->fb.depth), + pScreenPriv->systemPalette); + } + KdSetColormap (pScreen); +} + +void +KdDisableColormap (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + + if (!pScreenPriv->card->cfuncs->putColors) + return; + + if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) + { + (*pScreenPriv->card->cfuncs->putColors) (pScreen, + (1 << pScreenPriv->screen->fb.depth), + pScreenPriv->systemPalette); + } +} + +/* + * KdInstallColormap + * + * This function is called when the server receives a request to install a + * colormap or when the server needs to install one on its own, like when + * there's no window manager running and the user has moved the pointer over + * an X client window. It needs to build an identity Windows palette for the + * colormap and realize it into the Windows system palette. + */ +void +KdInstallColormap (ColormapPtr pCmap) +{ + KdScreenPriv(pCmap->pScreen); + + if (pCmap == pScreenPriv->pInstalledmap) + return; + + /* Tell X clients that the installed colormap is going away. */ + if (pScreenPriv->pInstalledmap) + WalkTree(pScreenPriv->pInstalledmap->pScreen, TellLostMap, + (pointer) &(pScreenPriv->pInstalledmap->mid)); + + /* Take note of the new installed colorscreen-> */ + pScreenPriv->pInstalledmap = pCmap; + + KdSetColormap (pCmap->pScreen); + + /* Tell X clients of the new colormap */ + WalkTree(pCmap->pScreen, TellGainedMap, (pointer) &(pCmap->mid)); +} + +/* + * KdUninstallColormap + * + * This function uninstalls a colormap by either installing + * the default X colormap or erasing the installed colormap pointer. + * The default X colormap itself cannot be uninstalled. + */ +void +KdUninstallColormap (ColormapPtr pCmap) +{ + KdScreenPriv(pCmap->pScreen); + Colormap defMapID; + ColormapPtr defMap; + + /* ignore if not installed */ + if (pCmap != pScreenPriv->pInstalledmap) + return; + + /* ignore attempts to uninstall default colormap */ + defMapID = pCmap->pScreen->defColormap; + if ((Colormap) pCmap->mid == defMapID) + return; + + /* install default */ + dixLookupResourceByType((pointer *)&defMap, defMapID, RT_COLORMAP, + serverClient, DixInstallAccess); + if (defMap) + (*pCmap->pScreen->InstallColormap)(defMap); + else + { + /* uninstall and clear colormap pointer */ + WalkTree(pCmap->pScreen, TellLostMap, + (pointer) &(pCmap->mid)); + pScreenPriv->pInstalledmap = 0; + } +} + +int +KdListInstalledColormaps (ScreenPtr pScreen, Colormap *pCmaps) +{ + KdScreenPriv(pScreen); + int n = 0; + + if (pScreenPriv->pInstalledmap) + { + *pCmaps++ = pScreenPriv->pInstalledmap->mid; + n++; + } + return n; +} + +/* + * KdStoreColors + * + * This function is called whenever the server receives a request to store + * color values into one or more entries in the currently installed X + * colormap; it can be either the default colormap or a private colorscreen-> + */ +void +KdStoreColors (ColormapPtr pCmap, int ndef, xColorItem *pdefs) +{ + KdScreenPriv(pCmap->pScreen); + VisualPtr pVisual; + xColorItem expanddefs[KD_MAX_PSEUDO_SIZE]; + + if (pCmap != pScreenPriv->pInstalledmap) + return; + + if (!pScreenPriv->card->cfuncs->putColors) + return; + + if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) + return; + + if (!pScreenPriv->enabled) + return; + + /* Check for DirectColor or TrueColor being simulated on a PseudoColor device. */ + pVisual = pCmap->pVisual; + if ((pVisual->class | DynamicClass) == DirectColor) + { + /* + * Expand DirectColor or TrueColor color values into a PseudoColor + * format. Defer to the Color Framebuffer (CFB) code to do that. + */ + ndef = fbExpandDirectColors(pCmap, ndef, pdefs, expanddefs); + pdefs = expanddefs; + } + + (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, ndef, pdefs); + + /* recolor hardware cursor */ + if (pScreenPriv->card->cfuncs->recolorCursor) + (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, ndef, pdefs); +} diff --git a/xorg-server/hw/kdrive/src/kdrive.c b/xorg-server/hw/kdrive/src/kdrive.c index 765bd0ea7..d1f00fc69 100644 --- a/xorg-server/hw/kdrive/src/kdrive.c +++ b/xorg-server/hw/kdrive/src/kdrive.c @@ -1,1283 +1,1283 @@ -/* - * Copyright © 1999 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include "kdrive.h" -#include <mivalidate.h> -#include <dixstruct.h> -#include "privates.h" -#ifdef RANDR -#include <randrstr.h> -#endif - -#ifdef XV -#include "kxv.h" -#endif - -#ifdef DPMSExtension -#include "dpmsproc.h" -#endif - -#ifdef HAVE_EXECINFO_H -#include <execinfo.h> -#endif - -#include <signal.h> - -typedef struct _kdDepths { - CARD8 depth; - CARD8 bpp; -} KdDepths; - -KdDepths kdDepths[] = { - { 1, 1 }, - { 4, 4 }, - { 8, 8 }, - { 15, 16 }, - { 16, 16 }, - { 24, 32 }, - { 32, 32 } -}; - -#define NUM_KD_DEPTHS (sizeof (kdDepths) / sizeof (kdDepths[0])) - -#define KD_DEFAULT_BUTTONS 5 - -static int kdScreenPrivateKeyIndex; -DevPrivateKey kdScreenPrivateKey = &kdScreenPrivateKeyIndex; -unsigned long kdGeneration; - -Bool kdVideoTest; -unsigned long kdVideoTestTime; -Bool kdEmulateMiddleButton; -Bool kdRawPointerCoordinates; -Bool kdDisableZaphod; -Bool kdAllowZap; -Bool kdEnabled; -int kdSubpixelOrder; -int kdVirtualTerminal = -1; -Bool kdSwitchPending; -char *kdSwitchCmd; -DDXPointRec kdOrigin; -Bool kdHasPointer = FALSE; -Bool kdHasKbd = FALSE; - -static Bool kdCaughtSignal = FALSE; - -/* - * Carry arguments from InitOutput through driver initialization - * to KdScreenInit - */ - -KdOsFuncs *kdOsFuncs; - -void -KdSetRootClip (ScreenPtr pScreen, BOOL enable) -{ - WindowPtr pWin = WindowTable[pScreen->myNum]; - WindowPtr pChild; - Bool WasViewable; - Bool anyMarked = FALSE; - WindowPtr pLayerWin; - BoxRec box; - - if (!pWin) - return; - WasViewable = (Bool)(pWin->viewable); - if (WasViewable) - { - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - (void) (*pScreen->MarkOverlappedWindows)(pChild, - pChild, - &pLayerWin); - } - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - if (pWin->valdata) - { - if (HasBorder (pWin)) - { - RegionPtr borderVisible; - - borderVisible = REGION_CREATE(pScreen, NullBox, 1); - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, &pWin->winSize); - pWin->valdata->before.borderVisible = borderVisible; - } - pWin->valdata->before.resized = TRUE; - } - } - - if (enable) - { - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - pWin->drawable.width = pScreen->width; - pWin->drawable.height = pScreen->height; - REGION_INIT (pScreen, &pWin->winSize, &box, 1); - REGION_INIT (pScreen, &pWin->borderSize, &box, 1); - REGION_RESET(pScreen, &pWin->borderClip, &box); - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - else - { - REGION_EMPTY(pScreen, &pWin->borderClip); - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - - ResizeChildrenWinSize (pWin, 0, 0, 0, 0); - - if (WasViewable) - { - if (pWin->firstChild) - { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, - pWin->firstChild, - (WindowPtr *)NULL); - } - else - { - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - } - - - if (anyMarked) - (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); - } - - if (WasViewable) - { - if (anyMarked) - (*pScreen->HandleExposures)(pWin); - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); - } - if (pWin->realized) - WindowsRestructured (); -} - -void -KdDisableScreen (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - - if (!pScreenPriv->enabled) - return; - if (!pScreenPriv->closed) - KdSetRootClip (pScreen, FALSE); - KdDisableColormap (pScreen); - if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->disableAccel) - (*pScreenPriv->card->cfuncs->disableAccel) (pScreen); - if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->disableCursor) - (*pScreenPriv->card->cfuncs->disableCursor) (pScreen); - if (pScreenPriv->card->cfuncs->dpms) - (*pScreenPriv->card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL); - pScreenPriv->enabled = FALSE; - if(pScreenPriv->card->cfuncs->disable) - (*pScreenPriv->card->cfuncs->disable) (pScreen); -} - -static void -KdDoSwitchCmd (char *reason) -{ - if (kdSwitchCmd) - { - char *command = xalloc (strlen (kdSwitchCmd) + - 1 + - strlen (reason) + - 1); - if (!command) - return; - strcpy (command, kdSwitchCmd); - strcat (command, " "); - strcat (command, reason); - system (command); - xfree (command); - } -} - -void -KdSuspend (void) -{ - KdCardInfo *card; - KdScreenInfo *screen; - - if (kdEnabled) - { - for (card = kdCardInfo; card; card = card->next) - { - for (screen = card->screenList; screen; screen = screen->next) - if (screen->mynum == card->selected && screen->pScreen) - KdDisableScreen (screen->pScreen); - if (card->driver && card->cfuncs->restore) - (*card->cfuncs->restore) (card); - } - KdDisableInput (); - KdDoSwitchCmd ("suspend"); - } -} - -void -KdDisableScreens (void) -{ - KdSuspend (); - if (kdEnabled) - { - if (kdOsFuncs->Disable) - (*kdOsFuncs->Disable) (); - kdEnabled = FALSE; - } -} - -Bool -KdEnableScreen (ScreenPtr pScreen) -{ - KdScreenPriv (pScreen); - - if (pScreenPriv->enabled) - return TRUE; - if(pScreenPriv->card->cfuncs->enable) - if (!(*pScreenPriv->card->cfuncs->enable) (pScreen)) - return FALSE; - pScreenPriv->enabled = TRUE; - pScreenPriv->dpmsState = KD_DPMS_NORMAL; - pScreenPriv->card->selected = pScreenPriv->screen->mynum; - if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->enableCursor) - (*pScreenPriv->card->cfuncs->enableCursor) (pScreen); - if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->enableAccel) - (*pScreenPriv->card->cfuncs->enableAccel) (pScreen); - KdEnableColormap (pScreen); - KdSetRootClip (pScreen, TRUE); - if (pScreenPriv->card->cfuncs->dpms) - (*pScreenPriv->card->cfuncs->dpms) (pScreen, pScreenPriv->dpmsState); - return TRUE; -} - -void -KdResume (void) -{ - KdCardInfo *card; - KdScreenInfo *screen; - - if (kdEnabled) - { - KdDoSwitchCmd ("resume"); - for (card = kdCardInfo; card; card = card->next) - { - if(card->cfuncs->preserve) - (*card->cfuncs->preserve) (card); - for (screen = card->screenList; screen; screen = screen->next) - if (screen->mynum == card->selected && screen->pScreen) - KdEnableScreen (screen->pScreen); - } - KdEnableInput (); - KdReleaseAllKeys (); - } -} - -void -KdEnableScreens (void) -{ - if (!kdEnabled) - { - kdEnabled = TRUE; - if (kdOsFuncs->Enable) - (*kdOsFuncs->Enable) (); - } - KdResume (); -} - -void -KdProcessSwitch (void) -{ - if (kdEnabled) - KdDisableScreens (); - else - KdEnableScreens (); -} - -void -AbortDDX(void) -{ - KdDisableScreens (); - if (kdOsFuncs) - { - if (kdEnabled && kdOsFuncs->Disable) - (*kdOsFuncs->Disable) (); - if (kdOsFuncs->Fini) - (*kdOsFuncs->Fini) (); - KdDoSwitchCmd ("stop"); - } - - if (kdCaughtSignal) - OsAbort(); -} - -void -ddxGiveUp (void) -{ - AbortDDX (); -} - -Bool kdDumbDriver; -Bool kdSoftCursor; - -char * -KdParseFindNext (char *cur, char *delim, char *save, char *last) -{ - while (*cur && !strchr (delim, *cur)) - { - *save++ = *cur++; - } - *save = 0; - *last = *cur; - if (*cur) - cur++; - return cur; -} - -Rotation -KdAddRotation (Rotation a, Rotation b) -{ - Rotation rotate = (a & RR_Rotate_All) * (b & RR_Rotate_All); - Rotation reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All); - - if (rotate > RR_Rotate_270) - rotate /= (RR_Rotate_270 * RR_Rotate_90); - return reflect | rotate; -} - -Rotation -KdSubRotation (Rotation a, Rotation b) -{ - Rotation rotate = (a & RR_Rotate_All) * 16 / (b & RR_Rotate_All); - Rotation reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All); - - if (rotate > RR_Rotate_270) - rotate /= (RR_Rotate_270 * RR_Rotate_90); - return reflect | rotate; -} - -void -KdParseScreen (KdScreenInfo *screen, - char *arg) -{ - char delim; - char save[1024]; - int i; - int pixels, mm; - - screen->dumb = kdDumbDriver; - screen->softCursor = kdSoftCursor; - screen->origin = kdOrigin; - screen->randr = RR_Rotate_0; - screen->width = 0; - screen->height = 0; - screen->width_mm = 0; - screen->height_mm = 0; - screen->subpixel_order = kdSubpixelOrder; - screen->rate = 0; - screen->fb.depth = 0; - if (!arg) - return; - if (strlen (arg) >= sizeof (save)) - return; - - for (i = 0; i < 2; i++) - { - arg = KdParseFindNext (arg, "x/@XY", save, &delim); - if (!save[0]) - return; - - pixels = atoi(save); - mm = 0; - - if (delim == '/') - { - arg = KdParseFindNext (arg, "x@XY", save, &delim); - if (!save[0]) - return; - mm = atoi(save); - } - - if (i == 0) - { - screen->width = pixels; - screen->width_mm = mm; - } - else - { - screen->height = pixels; - screen->height_mm = mm; - } - if (delim != 'x' && delim != '@' && delim != 'X' && delim != 'Y') - return; - } - - kdOrigin.x += screen->width; - kdOrigin.y = 0; - kdDumbDriver = FALSE; - kdSoftCursor = FALSE; - kdSubpixelOrder = SubPixelUnknown; - - if (delim == '@') - { - arg = KdParseFindNext (arg, "xXY", save, &delim); - if (save[0]) - { - int rotate = atoi (save); - if (rotate < 45) - screen->randr = RR_Rotate_0; - else if (rotate < 135) - screen->randr = RR_Rotate_90; - else if (rotate < 225) - screen->randr = RR_Rotate_180; - else if (rotate < 315) - screen->randr = RR_Rotate_270; - else - screen->randr = RR_Rotate_0; - } - } - if (delim == 'X') - { - arg = KdParseFindNext (arg, "xY", save, &delim); - screen->randr |= RR_Reflect_X; - } - - if (delim == 'Y') - { - arg = KdParseFindNext (arg, "xY", save, &delim); - screen->randr |= RR_Reflect_Y; - } - - arg = KdParseFindNext (arg, "x/,", save, &delim); - if (save[0]) - { - screen->fb.depth = atoi(save); - if (delim == '/') - { - arg = KdParseFindNext (arg, "x,", save, &delim); - if (save[0]) - screen->fb.bitsPerPixel = atoi (save); - } - else - screen->fb.bitsPerPixel = 0; - } - - if (delim == 'x') - { - arg = KdParseFindNext (arg, "x", save, &delim); - if (save[0]) - screen->rate = atoi(save); - } -} - -/* - * Mouse argument syntax: - * - * device,protocol,options... - * - * Options are any of: - * 1-5 n button mouse - * 2button emulate middle button - * {NMO} Reorder buttons - */ - -void -KdParseRgba (char *rgba) -{ - if (!strcmp (rgba, "rgb")) - kdSubpixelOrder = SubPixelHorizontalRGB; - else if (!strcmp (rgba, "bgr")) - kdSubpixelOrder = SubPixelHorizontalBGR; - else if (!strcmp (rgba, "vrgb")) - kdSubpixelOrder = SubPixelVerticalRGB; - else if (!strcmp (rgba, "vbgr")) - kdSubpixelOrder = SubPixelVerticalBGR; - else if (!strcmp (rgba, "none")) - kdSubpixelOrder = SubPixelNone; - else - kdSubpixelOrder = SubPixelUnknown; -} - -void -KdUseMsg (void) -{ - ErrorF("\nTinyX Device Dependent Usage:\n"); - ErrorF("-screen WIDTH[/WIDTHMM]xHEIGHT[/HEIGHTMM][@ROTATION][X][Y][xDEPTH/BPP[xFREQ]] Specify screen characteristics\n"); - ErrorF("-rgba rgb/bgr/vrgb/vbgr/none Specify subpixel ordering for LCD panels\n"); - ErrorF("-mouse driver [,n,,options] Specify the pointer driver and its options (n is the number of buttons)\n"); - ErrorF("-keybd driver [,,options] Specify the keyboard driver and its options\n"); - ErrorF("-zaphod Disable cursor screen switching\n"); - ErrorF("-2button Emulate 3 button mouse\n"); - ErrorF("-3button Disable 3 button mouse emulation\n"); - ErrorF("-rawcoord Don't transform pointer coordinates on rotation\n"); - ErrorF("-dumb Disable hardware acceleration\n"); - ErrorF("-softCursor Force software cursor\n"); - ErrorF("-videoTest Start the server, pause momentarily and exit\n"); - ErrorF("-origin X,Y Locates the next screen in the the virtual screen (Xinerama)\n"); - ErrorF("-switchCmd Command to execute on vt switch\n"); - ErrorF("-zap Terminate server on Ctrl+Alt+Backspace\n"); - ErrorF("vtxx Use virtual terminal xx instead of the next available\n"); -} - -int -KdProcessArgument (int argc, char **argv, int i) -{ - KdCardInfo *card; - KdScreenInfo *screen; - - if (!strcmp (argv[i], "-screen")) - { - if ((i+1) < argc) - { - card = KdCardInfoLast (); - if (!card) - { - InitCard (0); - card = KdCardInfoLast (); - } - if (card) { - screen = KdScreenInfoAdd (card); - KdParseScreen (screen, argv[i+1]); - } else - ErrorF("No matching card found!\n"); - } - else - UseMsg (); - return 2; - } - if (!strcmp (argv[i], "-zaphod")) - { - kdDisableZaphod = TRUE; - return 1; - } - if (!strcmp (argv[i], "-zap")) - { - kdAllowZap = TRUE; - return 1; - } - if (!strcmp (argv[i], "-3button")) - { - kdEmulateMiddleButton = FALSE; - return 1; - } - if (!strcmp (argv[i], "-2button")) - { - kdEmulateMiddleButton = TRUE; - return 1; - } - if (!strcmp (argv[i], "-rawcoord")) - { - kdRawPointerCoordinates = 1; - return 1; - } - if (!strcmp (argv[i], "-dumb")) - { - kdDumbDriver = TRUE; - return 1; - } - if (!strcmp (argv[i], "-softCursor")) - { - kdSoftCursor = TRUE; - return 1; - } - if (!strcmp (argv[i], "-videoTest")) - { - kdVideoTest = TRUE; - return 1; - } - if (!strcmp (argv[i], "-origin")) - { - if ((i+1) < argc) - { - char *x = argv[i+1]; - char *y = strchr (x, ','); - if (x) - kdOrigin.x = atoi (x); - else - kdOrigin.x = 0; - if (y) - kdOrigin.y = atoi(y+1); - else - kdOrigin.y = 0; - } - else - UseMsg (); - return 2; - } - if (!strcmp (argv[i], "-rgba")) - { - if ((i+1) < argc) - KdParseRgba (argv[i+1]); - else - UseMsg (); - return 2; - } - if (!strcmp (argv[i], "-switchCmd")) - { - if ((i+1) < argc) - kdSwitchCmd = argv[i+1]; - else - UseMsg (); - return 2; - } - if (!strncmp (argv[i], "vt", 2) && - sscanf (argv[i], "vt%2d", &kdVirtualTerminal) == 1) - { - return 1; - } - if (!strcmp (argv[i], "-mouse") || - !strcmp (argv[i], "-pointer")) { - if (i + 1 >= argc) - UseMsg(); - KdAddConfigPointer(argv[i + 1]); - kdHasPointer = TRUE; - return 2; - } - if (!strcmp (argv[i], "-keybd")) { - if (i + 1 >= argc) - UseMsg(); - KdAddConfigKeyboard(argv[i + 1]); - kdHasKbd = TRUE; - return 2; - } - - return 0; -} - -/* - * These are getting tossed in here until I can think of where - * they really belong - */ - -void -KdOsInit (KdOsFuncs *pOsFuncs) -{ - kdOsFuncs = pOsFuncs; - if (pOsFuncs) - { - if (serverGeneration == 1) - { - KdDoSwitchCmd ("start"); - if (pOsFuncs->Init) - (*pOsFuncs->Init) (); - } - } -} - -Bool -KdAllocatePrivates (ScreenPtr pScreen) -{ - KdPrivScreenPtr pScreenPriv; - - if (kdGeneration != serverGeneration) - kdGeneration = serverGeneration; - - pScreenPriv = xcalloc(1, sizeof (*pScreenPriv)); - if (!pScreenPriv) - return FALSE; - KdSetScreenPriv (pScreen, pScreenPriv); - return TRUE; -} - -Bool -KdCreateScreenResources (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdCardInfo *card = pScreenPriv->card; - Bool ret; - - pScreen->CreateScreenResources = pScreenPriv->CreateScreenResources; - if(pScreen->CreateScreenResources) - ret = (*pScreen->CreateScreenResources) (pScreen); - else - ret= -1; - pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources; - pScreen->CreateScreenResources = KdCreateScreenResources; - if (ret && card->cfuncs->createRes) - ret = (*card->cfuncs->createRes) (pScreen); - return ret; -} - -Bool -KdCloseScreen (int index, ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - KdCardInfo *card = pScreenPriv->card; - Bool ret; - - pScreenPriv->closed = TRUE; - pScreen->CloseScreen = pScreenPriv->CloseScreen; - if(pScreen->CloseScreen) - ret = (*pScreen->CloseScreen) (index, pScreen); - else - ret = TRUE; - - if (pScreenPriv->dpmsState != KD_DPMS_NORMAL) - (*card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL); - - if (screen->mynum == card->selected) - KdDisableScreen (pScreen); - - /* - * Restore video hardware when last screen is closed - */ - if (screen == card->screenList) - { - if (kdEnabled && card->cfuncs->restore) - (*card->cfuncs->restore) (card); - } - - if (!pScreenPriv->screen->dumb && card->cfuncs->finiAccel) - (*card->cfuncs->finiAccel) (pScreen); - - if (!pScreenPriv->screen->softCursor && card->cfuncs->finiCursor) - (*card->cfuncs->finiCursor) (pScreen); - - if(card->cfuncs->scrfini) - (*card->cfuncs->scrfini) (screen); - - /* - * Clean up card when last screen is closed, DIX closes them in - * reverse order, thus we check for when the first in the list is closed - */ - if (screen == card->screenList) - { - if(card->cfuncs->cardfini) - (*card->cfuncs->cardfini) (card); - /* - * Clean up OS when last card is closed - */ - if (card == kdCardInfo) - { - if (kdEnabled) - { - kdEnabled = FALSE; - if(kdOsFuncs->Disable) - (*kdOsFuncs->Disable) (); - } - } - } - - pScreenPriv->screen->pScreen = 0; - - xfree ((pointer) pScreenPriv); - return ret; -} - -Bool -KdSaveScreen (ScreenPtr pScreen, int on) -{ - KdScreenPriv(pScreen); - int dpmsState; - - if (!pScreenPriv->card->cfuncs->dpms) - return FALSE; - - dpmsState = pScreenPriv->dpmsState; - switch (on) { - case SCREEN_SAVER_OFF: - dpmsState = KD_DPMS_NORMAL; - break; - case SCREEN_SAVER_ON: - if (dpmsState == KD_DPMS_NORMAL) - dpmsState = KD_DPMS_NORMAL+1; - break; - case SCREEN_SAVER_CYCLE: - if (dpmsState < KD_DPMS_MAX) - dpmsState++; - break; - case SCREEN_SAVER_FORCER: - break; - } - if (dpmsState != pScreenPriv->dpmsState) - { - if (pScreenPriv->enabled) - (*pScreenPriv->card->cfuncs->dpms) (pScreen, dpmsState); - pScreenPriv->dpmsState = dpmsState; - } - return TRUE; -} - -static Bool -KdCreateWindow (WindowPtr pWin) -{ -#ifndef PHOENIX - if (!pWin->parent) - { - KdScreenPriv(pWin->drawable.pScreen); - - if (!pScreenPriv->enabled) - { - REGION_EMPTY (pWin->drawable.pScreen, &pWin->borderClip); - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - } -#endif - return fbCreateWindow (pWin); -} - -void -KdSetSubpixelOrder (ScreenPtr pScreen, Rotation randr) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - int subpixel_order = screen->subpixel_order; - Rotation subpixel_dir; - int i; - - static struct { - int subpixel_order; - Rotation direction; - } orders[] = { - { SubPixelHorizontalRGB, RR_Rotate_0 }, - { SubPixelHorizontalBGR, RR_Rotate_180 }, - { SubPixelVerticalRGB, RR_Rotate_270 }, - { SubPixelVerticalBGR, RR_Rotate_90 }, - }; - - static struct { - int bit; - int normal; - int reflect; - } reflects[] = { - { RR_Reflect_X, SubPixelHorizontalRGB, SubPixelHorizontalBGR }, - { RR_Reflect_X, SubPixelHorizontalBGR, SubPixelHorizontalRGB }, - { RR_Reflect_Y, SubPixelVerticalRGB, SubPixelVerticalBGR }, - { RR_Reflect_Y, SubPixelVerticalRGB, SubPixelVerticalRGB }, - }; - - /* map subpixel to direction */ - for (i = 0; i < 4; i++) - if (orders[i].subpixel_order == subpixel_order) - break; - if (i < 4) - { - subpixel_dir = KdAddRotation (randr & RR_Rotate_All, orders[i].direction); - - /* map back to subpixel order */ - for (i = 0; i < 4; i++) - if (orders[i].direction & subpixel_dir) - { - subpixel_order = orders[i].subpixel_order; - break; - } - /* reflect */ - for (i = 0; i < 4; i++) - if ((randr & reflects[i].bit) && - reflects[i].normal == subpixel_order) - { - subpixel_order = reflects[i].reflect; - break; - } - } - PictureSetSubpixelOrder (pScreen, subpixel_order); -} - -/* Pass through AddScreen, which doesn't take any closure */ -static KdScreenInfo *kdCurrentScreen; - -Bool -KdScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) -{ - KdScreenInfo *screen = kdCurrentScreen; - KdCardInfo *card = screen->card; - KdPrivScreenPtr pScreenPriv; - /* - * note that screen->fb is set up for the nominal orientation - * of the screen; that means if randr is rotated, the values - * there should reflect a rotated frame buffer (or shadow). - */ - Bool rotated = (screen->randr & (RR_Rotate_90|RR_Rotate_270)) != 0; - int width, height, *width_mmp, *height_mmp; - - KdAllocatePrivates (pScreen); - - pScreenPriv = KdGetScreenPriv(pScreen); - - if (!rotated) - { - width = screen->width; - height = screen->height; - width_mmp = &screen->width_mm; - height_mmp = &screen->height_mm; - } - else - { - width = screen->height; - height = screen->width; - width_mmp = &screen->height_mm; - height_mmp = &screen->width_mm; - } - screen->pScreen = pScreen; - pScreenPriv->screen = screen; - pScreenPriv->card = card; - pScreenPriv->bytesPerPixel = screen->fb.bitsPerPixel >> 3; - pScreenPriv->dpmsState = KD_DPMS_NORMAL; -#ifdef PANORAMIX - dixScreenOrigins[pScreen->myNum] = screen->origin; -#endif - - if (!monitorResolution) - monitorResolution = 75; - /* - * This is done in this order so that backing store wraps - * our GC functions; fbFinishScreenInit initializes MI - * backing store - */ - if (!fbSetupScreen (pScreen, - screen->fb.frameBuffer, - width, height, - monitorResolution, monitorResolution, - screen->fb.pixelStride, - screen->fb.bitsPerPixel)) - { - return FALSE; - } - - /* - * Set colormap functions - */ - pScreen->InstallColormap = KdInstallColormap; - pScreen->UninstallColormap = KdUninstallColormap; - pScreen->ListInstalledColormaps = KdListInstalledColormaps; - pScreen->StoreColors = KdStoreColors; - - pScreen->SaveScreen = KdSaveScreen; - pScreen->CreateWindow = KdCreateWindow; - - if (!fbFinishScreenInit (pScreen, - screen->fb.frameBuffer, - width, height, - monitorResolution, monitorResolution, - screen->fb.pixelStride, - screen->fb.bitsPerPixel)) - { - return FALSE; - } - - /* - * Fix screen sizes; for some reason mi takes dpi instead of mm. - * Rounding errors are annoying - */ - if (*width_mmp) - pScreen->mmWidth = *width_mmp; - else - *width_mmp = pScreen->mmWidth; - if (*height_mmp) - pScreen->mmHeight = *height_mmp; - else - *height_mmp = pScreen->mmHeight; - - /* - * Plug in our own block/wakeup handlers. - * miScreenInit installs NoopDDA in both places - */ - pScreen->BlockHandler = KdBlockHandler; - pScreen->WakeupHandler = KdWakeupHandler; - - if (!fbPictureInit (pScreen, 0, 0)) - return FALSE; - if (card->cfuncs->initScreen) - if (!(*card->cfuncs->initScreen) (pScreen)) - return FALSE; - - if (!screen->dumb && card->cfuncs->initAccel) - if (!(*card->cfuncs->initAccel) (pScreen)) - screen->dumb = TRUE; - - if (card->cfuncs->finishInitScreen) - if (!(*card->cfuncs->finishInitScreen) (pScreen)) - return FALSE; - -#if 0 - fbInitValidateTree (pScreen); -#endif - -#if 0 - pScreen->backingStoreSupport = Always; - miInitializeBackingStore (pScreen); -#endif - - - /* - * Wrap CloseScreen, the order now is: - * KdCloseScreen - * miBSCloseScreen - * fbCloseScreen - */ - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = KdCloseScreen; - - pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources; - pScreen->CreateScreenResources = KdCreateScreenResources; - - if (screen->softCursor || - !card->cfuncs->initCursor || - !(*card->cfuncs->initCursor) (pScreen)) - { - /* Use MI for cursor display and event queueing. */ - screen->softCursor = TRUE; - miDCInitialize(pScreen, &kdPointerScreenFuncs); - } - - - if (!fbCreateDefColormap (pScreen)) - { - return FALSE; - } - - KdSetSubpixelOrder (pScreen, screen->randr); - - /* - * Enable the hardware - */ - if (!kdEnabled) - { - kdEnabled = TRUE; - if(kdOsFuncs->Enable) - (*kdOsFuncs->Enable) (); - } - - if (screen->mynum == card->selected) - { - if(card->cfuncs->preserve) - (*card->cfuncs->preserve) (card); - if(card->cfuncs->enable) - if (!(*card->cfuncs->enable) (pScreen)) - return FALSE; - pScreenPriv->enabled = TRUE; - if (!screen->softCursor && card->cfuncs->enableCursor) - (*card->cfuncs->enableCursor) (pScreen); - KdEnableColormap (pScreen); - if (!screen->dumb && card->cfuncs->enableAccel) - (*card->cfuncs->enableAccel) (pScreen); - } - - return TRUE; -} - -void -KdInitScreen (ScreenInfo *pScreenInfo, - KdScreenInfo *screen, - int argc, - char **argv) -{ - KdCardInfo *card = screen->card; - - (*card->cfuncs->scrinit) (screen); - - if (!card->cfuncs->initAccel) - screen->dumb = TRUE; - if (!card->cfuncs->initCursor) - screen->softCursor = TRUE; -} - -static Bool -KdSetPixmapFormats (ScreenInfo *pScreenInfo) -{ - CARD8 depthToBpp[33]; /* depth -> bpp map */ - KdCardInfo *card; - KdScreenInfo *screen; - int i; - int bpp; - PixmapFormatRec *format; - - for (i = 1; i <= 32; i++) - depthToBpp[i] = 0; - - /* - * Generate mappings between bitsPerPixel and depth, - * also ensure that all screens comply with protocol - * restrictions on equivalent formats for the same - * depth on different screens - */ - for (card = kdCardInfo; card; card = card->next) - { - for (screen = card->screenList; screen; screen = screen->next) - { - bpp = screen->fb.bitsPerPixel; - if (bpp == 24) - bpp = 32; - if (!depthToBpp[screen->fb.depth]) - depthToBpp[screen->fb.depth] = bpp; - else if (depthToBpp[screen->fb.depth] != bpp) - return FALSE; - } - } - - /* - * Fill in additional formats - */ - for (i = 0; i < NUM_KD_DEPTHS; i++) - if (!depthToBpp[kdDepths[i].depth]) - depthToBpp[kdDepths[i].depth] = kdDepths[i].bpp; - - pScreenInfo->imageByteOrder = IMAGE_BYTE_ORDER; - pScreenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; - pScreenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; - pScreenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; - - pScreenInfo->numPixmapFormats = 0; - - for (i = 1; i <= 32; i++) - { - if (depthToBpp[i]) - { - format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats++]; - format->depth = i; - format->bitsPerPixel = depthToBpp[i]; - format->scanlinePad = BITMAP_SCANLINE_PAD; - } - } - - return TRUE; -} - -static void -KdAddScreen (ScreenInfo *pScreenInfo, - KdScreenInfo *screen, - int argc, - char **argv) -{ - int i; - /* - * Fill in fb visual type masks for this screen - */ - for (i = 0; i < pScreenInfo->numPixmapFormats; i++) - { - unsigned long visuals; - Pixel rm, gm, bm; - - visuals = 0; - rm = gm = bm = 0; - if (pScreenInfo->formats[i].depth == screen->fb.depth) - { - visuals = screen->fb.visuals; - rm = screen->fb.redMask; - gm = screen->fb.greenMask; - bm = screen->fb.blueMask; - } - fbSetVisualTypesAndMasks (pScreenInfo->formats[i].depth, - visuals, - 8, - rm, gm, bm); - } - - kdCurrentScreen = screen; - - AddScreen (KdScreenInit, argc, argv); -} - -#if 0 /* This function is not used currently */ - -int -KdDepthToFb (ScreenPtr pScreen, int depth) -{ - KdScreenPriv(pScreen); - - for (fb = 0; fb <= KD_MAX_FB && pScreenPriv->screen->fb.frameBuffer; fb++) - if (pScreenPriv->screen->fb.depth == depth) - return fb; -} - -#endif - -static int -KdSignalWrapper (int signum) -{ - kdCaughtSignal = TRUE; - return 1; /* use generic OS layer cleanup & abort */ -} - -void -KdInitOutput (ScreenInfo *pScreenInfo, - int argc, - char **argv) -{ - KdCardInfo *card; - KdScreenInfo *screen; - - if (!kdCardInfo) - { - InitCard (0); - if (!(card = KdCardInfoLast ())) - FatalError("No matching cards found!\n"); - screen = KdScreenInfoAdd (card); - KdParseScreen (screen, 0); - } - /* - * Initialize all of the screens for all of the cards - */ - for (card = kdCardInfo; card; card = card->next) - { - int ret=1; - if(card->cfuncs->cardinit) - ret=(*card->cfuncs->cardinit) (card); - if (ret) - { - for (screen = card->screenList; screen; screen = screen->next) - KdInitScreen (pScreenInfo, screen, argc, argv); - } - } - - /* - * Merge the various pixmap formats together, this can fail - * when two screens share depth but not bitsPerPixel - */ - if (!KdSetPixmapFormats (pScreenInfo)) - return; - - /* - * Add all of the screens - */ - for (card = kdCardInfo; card; card = card->next) - for (screen = card->screenList; screen; screen = screen->next) - KdAddScreen (pScreenInfo, screen, argc, argv); - - OsRegisterSigWrapper(KdSignalWrapper); -} - -void -OsVendorFatalError(void) -{ -} - -int -DPMSSet(ClientPtr client, int level) -{ - return Success; -} - -Bool -DPMSSupported (void) -{ - return FALSE; -} +/* + * Copyright © 1999 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" +#include <mivalidate.h> +#include <dixstruct.h> +#include "privates.h" +#ifdef RANDR +#include <randrstr.h> +#endif + +#ifdef XV +#include "kxv.h" +#endif + +#ifdef DPMSExtension +#include "dpmsproc.h" +#endif + +#ifdef HAVE_EXECINFO_H +#include <execinfo.h> +#endif + +#include <signal.h> + +typedef struct _kdDepths { + CARD8 depth; + CARD8 bpp; +} KdDepths; + +KdDepths kdDepths[] = { + { 1, 1 }, + { 4, 4 }, + { 8, 8 }, + { 15, 16 }, + { 16, 16 }, + { 24, 32 }, + { 32, 32 } +}; + +#define NUM_KD_DEPTHS (sizeof (kdDepths) / sizeof (kdDepths[0])) + +#define KD_DEFAULT_BUTTONS 5 + +static int kdScreenPrivateKeyIndex; +DevPrivateKey kdScreenPrivateKey = &kdScreenPrivateKeyIndex; +unsigned long kdGeneration; + +Bool kdVideoTest; +unsigned long kdVideoTestTime; +Bool kdEmulateMiddleButton; +Bool kdRawPointerCoordinates; +Bool kdDisableZaphod; +Bool kdAllowZap; +Bool kdEnabled; +int kdSubpixelOrder; +int kdVirtualTerminal = -1; +Bool kdSwitchPending; +char *kdSwitchCmd; +DDXPointRec kdOrigin; +Bool kdHasPointer = FALSE; +Bool kdHasKbd = FALSE; + +static Bool kdCaughtSignal = FALSE; + +/* + * Carry arguments from InitOutput through driver initialization + * to KdScreenInit + */ + +KdOsFuncs *kdOsFuncs; + +void +KdSetRootClip (ScreenPtr pScreen, BOOL enable) +{ + WindowPtr pWin = WindowTable[pScreen->myNum]; + WindowPtr pChild; + Bool WasViewable; + Bool anyMarked = FALSE; + WindowPtr pLayerWin; + BoxRec box; + + if (!pWin) + return; + WasViewable = (Bool)(pWin->viewable); + if (WasViewable) + { + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + (void) (*pScreen->MarkOverlappedWindows)(pChild, + pChild, + &pLayerWin); + } + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + pWin->valdata->before.resized = TRUE; + } + } + + if (enable) + { + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + pWin->drawable.width = pScreen->width; + pWin->drawable.height = pScreen->height; + REGION_INIT (pScreen, &pWin->winSize, &box, 1); + REGION_INIT (pScreen, &pWin->borderSize, &box, 1); + REGION_RESET(pScreen, &pWin->borderClip, &box); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + else + { + REGION_EMPTY(pScreen, &pWin->borderClip); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + + ResizeChildrenWinSize (pWin, 0, 0, 0, 0); + + if (WasViewable) + { + if (pWin->firstChild) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, + pWin->firstChild, + (WindowPtr *)NULL); + } + else + { + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + } + + + if (anyMarked) + (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); + } + + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pWin); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +void +KdDisableScreen (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + + if (!pScreenPriv->enabled) + return; + if (!pScreenPriv->closed) + KdSetRootClip (pScreen, FALSE); + KdDisableColormap (pScreen); + if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->disableAccel) + (*pScreenPriv->card->cfuncs->disableAccel) (pScreen); + if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->disableCursor) + (*pScreenPriv->card->cfuncs->disableCursor) (pScreen); + if (pScreenPriv->card->cfuncs->dpms) + (*pScreenPriv->card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL); + pScreenPriv->enabled = FALSE; + if(pScreenPriv->card->cfuncs->disable) + (*pScreenPriv->card->cfuncs->disable) (pScreen); +} + +static void +KdDoSwitchCmd (char *reason) +{ + if (kdSwitchCmd) + { + char *command = malloc(strlen (kdSwitchCmd) + + 1 + + strlen (reason) + + 1); + if (!command) + return; + strcpy (command, kdSwitchCmd); + strcat (command, " "); + strcat (command, reason); + system (command); + free(command); + } +} + +void +KdSuspend (void) +{ + KdCardInfo *card; + KdScreenInfo *screen; + + if (kdEnabled) + { + for (card = kdCardInfo; card; card = card->next) + { + for (screen = card->screenList; screen; screen = screen->next) + if (screen->mynum == card->selected && screen->pScreen) + KdDisableScreen (screen->pScreen); + if (card->driver && card->cfuncs->restore) + (*card->cfuncs->restore) (card); + } + KdDisableInput (); + KdDoSwitchCmd ("suspend"); + } +} + +void +KdDisableScreens (void) +{ + KdSuspend (); + if (kdEnabled) + { + if (kdOsFuncs->Disable) + (*kdOsFuncs->Disable) (); + kdEnabled = FALSE; + } +} + +Bool +KdEnableScreen (ScreenPtr pScreen) +{ + KdScreenPriv (pScreen); + + if (pScreenPriv->enabled) + return TRUE; + if(pScreenPriv->card->cfuncs->enable) + if (!(*pScreenPriv->card->cfuncs->enable) (pScreen)) + return FALSE; + pScreenPriv->enabled = TRUE; + pScreenPriv->dpmsState = KD_DPMS_NORMAL; + pScreenPriv->card->selected = pScreenPriv->screen->mynum; + if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->enableCursor) + (*pScreenPriv->card->cfuncs->enableCursor) (pScreen); + if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->enableAccel) + (*pScreenPriv->card->cfuncs->enableAccel) (pScreen); + KdEnableColormap (pScreen); + KdSetRootClip (pScreen, TRUE); + if (pScreenPriv->card->cfuncs->dpms) + (*pScreenPriv->card->cfuncs->dpms) (pScreen, pScreenPriv->dpmsState); + return TRUE; +} + +void +KdResume (void) +{ + KdCardInfo *card; + KdScreenInfo *screen; + + if (kdEnabled) + { + KdDoSwitchCmd ("resume"); + for (card = kdCardInfo; card; card = card->next) + { + if(card->cfuncs->preserve) + (*card->cfuncs->preserve) (card); + for (screen = card->screenList; screen; screen = screen->next) + if (screen->mynum == card->selected && screen->pScreen) + KdEnableScreen (screen->pScreen); + } + KdEnableInput (); + KdReleaseAllKeys (); + } +} + +void +KdEnableScreens (void) +{ + if (!kdEnabled) + { + kdEnabled = TRUE; + if (kdOsFuncs->Enable) + (*kdOsFuncs->Enable) (); + } + KdResume (); +} + +void +KdProcessSwitch (void) +{ + if (kdEnabled) + KdDisableScreens (); + else + KdEnableScreens (); +} + +void +AbortDDX(void) +{ + KdDisableScreens (); + if (kdOsFuncs) + { + if (kdEnabled && kdOsFuncs->Disable) + (*kdOsFuncs->Disable) (); + if (kdOsFuncs->Fini) + (*kdOsFuncs->Fini) (); + KdDoSwitchCmd ("stop"); + } + + if (kdCaughtSignal) + OsAbort(); +} + +void +ddxGiveUp (void) +{ + AbortDDX (); +} + +Bool kdDumbDriver; +Bool kdSoftCursor; + +char * +KdParseFindNext (char *cur, char *delim, char *save, char *last) +{ + while (*cur && !strchr (delim, *cur)) + { + *save++ = *cur++; + } + *save = 0; + *last = *cur; + if (*cur) + cur++; + return cur; +} + +Rotation +KdAddRotation (Rotation a, Rotation b) +{ + Rotation rotate = (a & RR_Rotate_All) * (b & RR_Rotate_All); + Rotation reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All); + + if (rotate > RR_Rotate_270) + rotate /= (RR_Rotate_270 * RR_Rotate_90); + return reflect | rotate; +} + +Rotation +KdSubRotation (Rotation a, Rotation b) +{ + Rotation rotate = (a & RR_Rotate_All) * 16 / (b & RR_Rotate_All); + Rotation reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All); + + if (rotate > RR_Rotate_270) + rotate /= (RR_Rotate_270 * RR_Rotate_90); + return reflect | rotate; +} + +void +KdParseScreen (KdScreenInfo *screen, + char *arg) +{ + char delim; + char save[1024]; + int i; + int pixels, mm; + + screen->dumb = kdDumbDriver; + screen->softCursor = kdSoftCursor; + screen->origin = kdOrigin; + screen->randr = RR_Rotate_0; + screen->width = 0; + screen->height = 0; + screen->width_mm = 0; + screen->height_mm = 0; + screen->subpixel_order = kdSubpixelOrder; + screen->rate = 0; + screen->fb.depth = 0; + if (!arg) + return; + if (strlen (arg) >= sizeof (save)) + return; + + for (i = 0; i < 2; i++) + { + arg = KdParseFindNext (arg, "x/@XY", save, &delim); + if (!save[0]) + return; + + pixels = atoi(save); + mm = 0; + + if (delim == '/') + { + arg = KdParseFindNext (arg, "x@XY", save, &delim); + if (!save[0]) + return; + mm = atoi(save); + } + + if (i == 0) + { + screen->width = pixels; + screen->width_mm = mm; + } + else + { + screen->height = pixels; + screen->height_mm = mm; + } + if (delim != 'x' && delim != '@' && delim != 'X' && delim != 'Y') + return; + } + + kdOrigin.x += screen->width; + kdOrigin.y = 0; + kdDumbDriver = FALSE; + kdSoftCursor = FALSE; + kdSubpixelOrder = SubPixelUnknown; + + if (delim == '@') + { + arg = KdParseFindNext (arg, "xXY", save, &delim); + if (save[0]) + { + int rotate = atoi (save); + if (rotate < 45) + screen->randr = RR_Rotate_0; + else if (rotate < 135) + screen->randr = RR_Rotate_90; + else if (rotate < 225) + screen->randr = RR_Rotate_180; + else if (rotate < 315) + screen->randr = RR_Rotate_270; + else + screen->randr = RR_Rotate_0; + } + } + if (delim == 'X') + { + arg = KdParseFindNext (arg, "xY", save, &delim); + screen->randr |= RR_Reflect_X; + } + + if (delim == 'Y') + { + arg = KdParseFindNext (arg, "xY", save, &delim); + screen->randr |= RR_Reflect_Y; + } + + arg = KdParseFindNext (arg, "x/,", save, &delim); + if (save[0]) + { + screen->fb.depth = atoi(save); + if (delim == '/') + { + arg = KdParseFindNext (arg, "x,", save, &delim); + if (save[0]) + screen->fb.bitsPerPixel = atoi (save); + } + else + screen->fb.bitsPerPixel = 0; + } + + if (delim == 'x') + { + arg = KdParseFindNext (arg, "x", save, &delim); + if (save[0]) + screen->rate = atoi(save); + } +} + +/* + * Mouse argument syntax: + * + * device,protocol,options... + * + * Options are any of: + * 1-5 n button mouse + * 2button emulate middle button + * {NMO} Reorder buttons + */ + +void +KdParseRgba (char *rgba) +{ + if (!strcmp (rgba, "rgb")) + kdSubpixelOrder = SubPixelHorizontalRGB; + else if (!strcmp (rgba, "bgr")) + kdSubpixelOrder = SubPixelHorizontalBGR; + else if (!strcmp (rgba, "vrgb")) + kdSubpixelOrder = SubPixelVerticalRGB; + else if (!strcmp (rgba, "vbgr")) + kdSubpixelOrder = SubPixelVerticalBGR; + else if (!strcmp (rgba, "none")) + kdSubpixelOrder = SubPixelNone; + else + kdSubpixelOrder = SubPixelUnknown; +} + +void +KdUseMsg (void) +{ + ErrorF("\nTinyX Device Dependent Usage:\n"); + ErrorF("-screen WIDTH[/WIDTHMM]xHEIGHT[/HEIGHTMM][@ROTATION][X][Y][xDEPTH/BPP[xFREQ]] Specify screen characteristics\n"); + ErrorF("-rgba rgb/bgr/vrgb/vbgr/none Specify subpixel ordering for LCD panels\n"); + ErrorF("-mouse driver [,n,,options] Specify the pointer driver and its options (n is the number of buttons)\n"); + ErrorF("-keybd driver [,,options] Specify the keyboard driver and its options\n"); + ErrorF("-zaphod Disable cursor screen switching\n"); + ErrorF("-2button Emulate 3 button mouse\n"); + ErrorF("-3button Disable 3 button mouse emulation\n"); + ErrorF("-rawcoord Don't transform pointer coordinates on rotation\n"); + ErrorF("-dumb Disable hardware acceleration\n"); + ErrorF("-softCursor Force software cursor\n"); + ErrorF("-videoTest Start the server, pause momentarily and exit\n"); + ErrorF("-origin X,Y Locates the next screen in the the virtual screen (Xinerama)\n"); + ErrorF("-switchCmd Command to execute on vt switch\n"); + ErrorF("-zap Terminate server on Ctrl+Alt+Backspace\n"); + ErrorF("vtxx Use virtual terminal xx instead of the next available\n"); +} + +int +KdProcessArgument (int argc, char **argv, int i) +{ + KdCardInfo *card; + KdScreenInfo *screen; + + if (!strcmp (argv[i], "-screen")) + { + if ((i+1) < argc) + { + card = KdCardInfoLast (); + if (!card) + { + InitCard (0); + card = KdCardInfoLast (); + } + if (card) { + screen = KdScreenInfoAdd (card); + KdParseScreen (screen, argv[i+1]); + } else + ErrorF("No matching card found!\n"); + } + else + UseMsg (); + return 2; + } + if (!strcmp (argv[i], "-zaphod")) + { + kdDisableZaphod = TRUE; + return 1; + } + if (!strcmp (argv[i], "-zap")) + { + kdAllowZap = TRUE; + return 1; + } + if (!strcmp (argv[i], "-3button")) + { + kdEmulateMiddleButton = FALSE; + return 1; + } + if (!strcmp (argv[i], "-2button")) + { + kdEmulateMiddleButton = TRUE; + return 1; + } + if (!strcmp (argv[i], "-rawcoord")) + { + kdRawPointerCoordinates = 1; + return 1; + } + if (!strcmp (argv[i], "-dumb")) + { + kdDumbDriver = TRUE; + return 1; + } + if (!strcmp (argv[i], "-softCursor")) + { + kdSoftCursor = TRUE; + return 1; + } + if (!strcmp (argv[i], "-videoTest")) + { + kdVideoTest = TRUE; + return 1; + } + if (!strcmp (argv[i], "-origin")) + { + if ((i+1) < argc) + { + char *x = argv[i+1]; + char *y = strchr (x, ','); + if (x) + kdOrigin.x = atoi (x); + else + kdOrigin.x = 0; + if (y) + kdOrigin.y = atoi(y+1); + else + kdOrigin.y = 0; + } + else + UseMsg (); + return 2; + } + if (!strcmp (argv[i], "-rgba")) + { + if ((i+1) < argc) + KdParseRgba (argv[i+1]); + else + UseMsg (); + return 2; + } + if (!strcmp (argv[i], "-switchCmd")) + { + if ((i+1) < argc) + kdSwitchCmd = argv[i+1]; + else + UseMsg (); + return 2; + } + if (!strncmp (argv[i], "vt", 2) && + sscanf (argv[i], "vt%2d", &kdVirtualTerminal) == 1) + { + return 1; + } + if (!strcmp (argv[i], "-mouse") || + !strcmp (argv[i], "-pointer")) { + if (i + 1 >= argc) + UseMsg(); + KdAddConfigPointer(argv[i + 1]); + kdHasPointer = TRUE; + return 2; + } + if (!strcmp (argv[i], "-keybd")) { + if (i + 1 >= argc) + UseMsg(); + KdAddConfigKeyboard(argv[i + 1]); + kdHasKbd = TRUE; + return 2; + } + + return 0; +} + +/* + * These are getting tossed in here until I can think of where + * they really belong + */ + +void +KdOsInit (KdOsFuncs *pOsFuncs) +{ + kdOsFuncs = pOsFuncs; + if (pOsFuncs) + { + if (serverGeneration == 1) + { + KdDoSwitchCmd ("start"); + if (pOsFuncs->Init) + (*pOsFuncs->Init) (); + } + } +} + +Bool +KdAllocatePrivates (ScreenPtr pScreen) +{ + KdPrivScreenPtr pScreenPriv; + + if (kdGeneration != serverGeneration) + kdGeneration = serverGeneration; + + pScreenPriv = calloc(1, sizeof (*pScreenPriv)); + if (!pScreenPriv) + return FALSE; + KdSetScreenPriv (pScreen, pScreenPriv); + return TRUE; +} + +Bool +KdCreateScreenResources (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdCardInfo *card = pScreenPriv->card; + Bool ret; + + pScreen->CreateScreenResources = pScreenPriv->CreateScreenResources; + if(pScreen->CreateScreenResources) + ret = (*pScreen->CreateScreenResources) (pScreen); + else + ret= -1; + pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = KdCreateScreenResources; + if (ret && card->cfuncs->createRes) + ret = (*card->cfuncs->createRes) (pScreen); + return ret; +} + +Bool +KdCloseScreen (int index, ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = pScreenPriv->card; + Bool ret; + + pScreenPriv->closed = TRUE; + pScreen->CloseScreen = pScreenPriv->CloseScreen; + if(pScreen->CloseScreen) + ret = (*pScreen->CloseScreen) (index, pScreen); + else + ret = TRUE; + + if (pScreenPriv->dpmsState != KD_DPMS_NORMAL) + (*card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL); + + if (screen->mynum == card->selected) + KdDisableScreen (pScreen); + + /* + * Restore video hardware when last screen is closed + */ + if (screen == card->screenList) + { + if (kdEnabled && card->cfuncs->restore) + (*card->cfuncs->restore) (card); + } + + if (!pScreenPriv->screen->dumb && card->cfuncs->finiAccel) + (*card->cfuncs->finiAccel) (pScreen); + + if (!pScreenPriv->screen->softCursor && card->cfuncs->finiCursor) + (*card->cfuncs->finiCursor) (pScreen); + + if(card->cfuncs->scrfini) + (*card->cfuncs->scrfini) (screen); + + /* + * Clean up card when last screen is closed, DIX closes them in + * reverse order, thus we check for when the first in the list is closed + */ + if (screen == card->screenList) + { + if(card->cfuncs->cardfini) + (*card->cfuncs->cardfini) (card); + /* + * Clean up OS when last card is closed + */ + if (card == kdCardInfo) + { + if (kdEnabled) + { + kdEnabled = FALSE; + if(kdOsFuncs->Disable) + (*kdOsFuncs->Disable) (); + } + } + } + + pScreenPriv->screen->pScreen = 0; + + free((pointer) pScreenPriv); + return ret; +} + +Bool +KdSaveScreen (ScreenPtr pScreen, int on) +{ + KdScreenPriv(pScreen); + int dpmsState; + + if (!pScreenPriv->card->cfuncs->dpms) + return FALSE; + + dpmsState = pScreenPriv->dpmsState; + switch (on) { + case SCREEN_SAVER_OFF: + dpmsState = KD_DPMS_NORMAL; + break; + case SCREEN_SAVER_ON: + if (dpmsState == KD_DPMS_NORMAL) + dpmsState = KD_DPMS_NORMAL+1; + break; + case SCREEN_SAVER_CYCLE: + if (dpmsState < KD_DPMS_MAX) + dpmsState++; + break; + case SCREEN_SAVER_FORCER: + break; + } + if (dpmsState != pScreenPriv->dpmsState) + { + if (pScreenPriv->enabled) + (*pScreenPriv->card->cfuncs->dpms) (pScreen, dpmsState); + pScreenPriv->dpmsState = dpmsState; + } + return TRUE; +} + +static Bool +KdCreateWindow (WindowPtr pWin) +{ +#ifndef PHOENIX + if (!pWin->parent) + { + KdScreenPriv(pWin->drawable.pScreen); + + if (!pScreenPriv->enabled) + { + REGION_EMPTY (pWin->drawable.pScreen, &pWin->borderClip); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + } +#endif + return fbCreateWindow (pWin); +} + +void +KdSetSubpixelOrder (ScreenPtr pScreen, Rotation randr) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + int subpixel_order = screen->subpixel_order; + Rotation subpixel_dir; + int i; + + static struct { + int subpixel_order; + Rotation direction; + } orders[] = { + { SubPixelHorizontalRGB, RR_Rotate_0 }, + { SubPixelHorizontalBGR, RR_Rotate_180 }, + { SubPixelVerticalRGB, RR_Rotate_270 }, + { SubPixelVerticalBGR, RR_Rotate_90 }, + }; + + static struct { + int bit; + int normal; + int reflect; + } reflects[] = { + { RR_Reflect_X, SubPixelHorizontalRGB, SubPixelHorizontalBGR }, + { RR_Reflect_X, SubPixelHorizontalBGR, SubPixelHorizontalRGB }, + { RR_Reflect_Y, SubPixelVerticalRGB, SubPixelVerticalBGR }, + { RR_Reflect_Y, SubPixelVerticalRGB, SubPixelVerticalRGB }, + }; + + /* map subpixel to direction */ + for (i = 0; i < 4; i++) + if (orders[i].subpixel_order == subpixel_order) + break; + if (i < 4) + { + subpixel_dir = KdAddRotation (randr & RR_Rotate_All, orders[i].direction); + + /* map back to subpixel order */ + for (i = 0; i < 4; i++) + if (orders[i].direction & subpixel_dir) + { + subpixel_order = orders[i].subpixel_order; + break; + } + /* reflect */ + for (i = 0; i < 4; i++) + if ((randr & reflects[i].bit) && + reflects[i].normal == subpixel_order) + { + subpixel_order = reflects[i].reflect; + break; + } + } + PictureSetSubpixelOrder (pScreen, subpixel_order); +} + +/* Pass through AddScreen, which doesn't take any closure */ +static KdScreenInfo *kdCurrentScreen; + +Bool +KdScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) +{ + KdScreenInfo *screen = kdCurrentScreen; + KdCardInfo *card = screen->card; + KdPrivScreenPtr pScreenPriv; + /* + * note that screen->fb is set up for the nominal orientation + * of the screen; that means if randr is rotated, the values + * there should reflect a rotated frame buffer (or shadow). + */ + Bool rotated = (screen->randr & (RR_Rotate_90|RR_Rotate_270)) != 0; + int width, height, *width_mmp, *height_mmp; + + KdAllocatePrivates (pScreen); + + pScreenPriv = KdGetScreenPriv(pScreen); + + if (!rotated) + { + width = screen->width; + height = screen->height; + width_mmp = &screen->width_mm; + height_mmp = &screen->height_mm; + } + else + { + width = screen->height; + height = screen->width; + width_mmp = &screen->height_mm; + height_mmp = &screen->width_mm; + } + screen->pScreen = pScreen; + pScreenPriv->screen = screen; + pScreenPriv->card = card; + pScreenPriv->bytesPerPixel = screen->fb.bitsPerPixel >> 3; + pScreenPriv->dpmsState = KD_DPMS_NORMAL; +#ifdef PANORAMIX + dixScreenOrigins[pScreen->myNum] = screen->origin; +#endif + + if (!monitorResolution) + monitorResolution = 75; + /* + * This is done in this order so that backing store wraps + * our GC functions; fbFinishScreenInit initializes MI + * backing store + */ + if (!fbSetupScreen (pScreen, + screen->fb.frameBuffer, + width, height, + monitorResolution, monitorResolution, + screen->fb.pixelStride, + screen->fb.bitsPerPixel)) + { + return FALSE; + } + + /* + * Set colormap functions + */ + pScreen->InstallColormap = KdInstallColormap; + pScreen->UninstallColormap = KdUninstallColormap; + pScreen->ListInstalledColormaps = KdListInstalledColormaps; + pScreen->StoreColors = KdStoreColors; + + pScreen->SaveScreen = KdSaveScreen; + pScreen->CreateWindow = KdCreateWindow; + + if (!fbFinishScreenInit (pScreen, + screen->fb.frameBuffer, + width, height, + monitorResolution, monitorResolution, + screen->fb.pixelStride, + screen->fb.bitsPerPixel)) + { + return FALSE; + } + + /* + * Fix screen sizes; for some reason mi takes dpi instead of mm. + * Rounding errors are annoying + */ + if (*width_mmp) + pScreen->mmWidth = *width_mmp; + else + *width_mmp = pScreen->mmWidth; + if (*height_mmp) + pScreen->mmHeight = *height_mmp; + else + *height_mmp = pScreen->mmHeight; + + /* + * Plug in our own block/wakeup handlers. + * miScreenInit installs NoopDDA in both places + */ + pScreen->BlockHandler = KdBlockHandler; + pScreen->WakeupHandler = KdWakeupHandler; + + if (!fbPictureInit (pScreen, 0, 0)) + return FALSE; + if (card->cfuncs->initScreen) + if (!(*card->cfuncs->initScreen) (pScreen)) + return FALSE; + + if (!screen->dumb && card->cfuncs->initAccel) + if (!(*card->cfuncs->initAccel) (pScreen)) + screen->dumb = TRUE; + + if (card->cfuncs->finishInitScreen) + if (!(*card->cfuncs->finishInitScreen) (pScreen)) + return FALSE; + +#if 0 + fbInitValidateTree (pScreen); +#endif + +#if 0 + pScreen->backingStoreSupport = Always; + miInitializeBackingStore (pScreen); +#endif + + + /* + * Wrap CloseScreen, the order now is: + * KdCloseScreen + * miBSCloseScreen + * fbCloseScreen + */ + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = KdCloseScreen; + + pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = KdCreateScreenResources; + + if (screen->softCursor || + !card->cfuncs->initCursor || + !(*card->cfuncs->initCursor) (pScreen)) + { + /* Use MI for cursor display and event queueing. */ + screen->softCursor = TRUE; + miDCInitialize(pScreen, &kdPointerScreenFuncs); + } + + + if (!fbCreateDefColormap (pScreen)) + { + return FALSE; + } + + KdSetSubpixelOrder (pScreen, screen->randr); + + /* + * Enable the hardware + */ + if (!kdEnabled) + { + kdEnabled = TRUE; + if(kdOsFuncs->Enable) + (*kdOsFuncs->Enable) (); + } + + if (screen->mynum == card->selected) + { + if(card->cfuncs->preserve) + (*card->cfuncs->preserve) (card); + if(card->cfuncs->enable) + if (!(*card->cfuncs->enable) (pScreen)) + return FALSE; + pScreenPriv->enabled = TRUE; + if (!screen->softCursor && card->cfuncs->enableCursor) + (*card->cfuncs->enableCursor) (pScreen); + KdEnableColormap (pScreen); + if (!screen->dumb && card->cfuncs->enableAccel) + (*card->cfuncs->enableAccel) (pScreen); + } + + return TRUE; +} + +void +KdInitScreen (ScreenInfo *pScreenInfo, + KdScreenInfo *screen, + int argc, + char **argv) +{ + KdCardInfo *card = screen->card; + + (*card->cfuncs->scrinit) (screen); + + if (!card->cfuncs->initAccel) + screen->dumb = TRUE; + if (!card->cfuncs->initCursor) + screen->softCursor = TRUE; +} + +static Bool +KdSetPixmapFormats (ScreenInfo *pScreenInfo) +{ + CARD8 depthToBpp[33]; /* depth -> bpp map */ + KdCardInfo *card; + KdScreenInfo *screen; + int i; + int bpp; + PixmapFormatRec *format; + + for (i = 1; i <= 32; i++) + depthToBpp[i] = 0; + + /* + * Generate mappings between bitsPerPixel and depth, + * also ensure that all screens comply with protocol + * restrictions on equivalent formats for the same + * depth on different screens + */ + for (card = kdCardInfo; card; card = card->next) + { + for (screen = card->screenList; screen; screen = screen->next) + { + bpp = screen->fb.bitsPerPixel; + if (bpp == 24) + bpp = 32; + if (!depthToBpp[screen->fb.depth]) + depthToBpp[screen->fb.depth] = bpp; + else if (depthToBpp[screen->fb.depth] != bpp) + return FALSE; + } + } + + /* + * Fill in additional formats + */ + for (i = 0; i < NUM_KD_DEPTHS; i++) + if (!depthToBpp[kdDepths[i].depth]) + depthToBpp[kdDepths[i].depth] = kdDepths[i].bpp; + + pScreenInfo->imageByteOrder = IMAGE_BYTE_ORDER; + pScreenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + pScreenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + pScreenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; + + pScreenInfo->numPixmapFormats = 0; + + for (i = 1; i <= 32; i++) + { + if (depthToBpp[i]) + { + format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats++]; + format->depth = i; + format->bitsPerPixel = depthToBpp[i]; + format->scanlinePad = BITMAP_SCANLINE_PAD; + } + } + + return TRUE; +} + +static void +KdAddScreen (ScreenInfo *pScreenInfo, + KdScreenInfo *screen, + int argc, + char **argv) +{ + int i; + /* + * Fill in fb visual type masks for this screen + */ + for (i = 0; i < pScreenInfo->numPixmapFormats; i++) + { + unsigned long visuals; + Pixel rm, gm, bm; + + visuals = 0; + rm = gm = bm = 0; + if (pScreenInfo->formats[i].depth == screen->fb.depth) + { + visuals = screen->fb.visuals; + rm = screen->fb.redMask; + gm = screen->fb.greenMask; + bm = screen->fb.blueMask; + } + fbSetVisualTypesAndMasks (pScreenInfo->formats[i].depth, + visuals, + 8, + rm, gm, bm); + } + + kdCurrentScreen = screen; + + AddScreen (KdScreenInit, argc, argv); +} + +#if 0 /* This function is not used currently */ + +int +KdDepthToFb (ScreenPtr pScreen, int depth) +{ + KdScreenPriv(pScreen); + + for (fb = 0; fb <= KD_MAX_FB && pScreenPriv->screen->fb.frameBuffer; fb++) + if (pScreenPriv->screen->fb.depth == depth) + return fb; +} + +#endif + +static int +KdSignalWrapper (int signum) +{ + kdCaughtSignal = TRUE; + return 1; /* use generic OS layer cleanup & abort */ +} + +void +KdInitOutput (ScreenInfo *pScreenInfo, + int argc, + char **argv) +{ + KdCardInfo *card; + KdScreenInfo *screen; + + if (!kdCardInfo) + { + InitCard (0); + if (!(card = KdCardInfoLast ())) + FatalError("No matching cards found!\n"); + screen = KdScreenInfoAdd (card); + KdParseScreen (screen, 0); + } + /* + * Initialize all of the screens for all of the cards + */ + for (card = kdCardInfo; card; card = card->next) + { + int ret=1; + if(card->cfuncs->cardinit) + ret=(*card->cfuncs->cardinit) (card); + if (ret) + { + for (screen = card->screenList; screen; screen = screen->next) + KdInitScreen (pScreenInfo, screen, argc, argv); + } + } + + /* + * Merge the various pixmap formats together, this can fail + * when two screens share depth but not bitsPerPixel + */ + if (!KdSetPixmapFormats (pScreenInfo)) + return; + + /* + * Add all of the screens + */ + for (card = kdCardInfo; card; card = card->next) + for (screen = card->screenList; screen; screen = screen->next) + KdAddScreen (pScreenInfo, screen, argc, argv); + + OsRegisterSigWrapper(KdSignalWrapper); +} + +void +OsVendorFatalError(void) +{ +} + +int +DPMSSet(ClientPtr client, int level) +{ + return Success; +} + +Bool +DPMSSupported (void) +{ + return FALSE; +} diff --git a/xorg-server/hw/kdrive/src/kinfo.c b/xorg-server/hw/kdrive/src/kinfo.c index 0825ee24f..90fe37ae9 100644 --- a/xorg-server/hw/kdrive/src/kinfo.c +++ b/xorg-server/hw/kdrive/src/kinfo.c @@ -1,163 +1,163 @@ -/* - * Copyright © 1999 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include "kdrive.h" - -KdCardInfo *kdCardInfo; - -KdCardInfo * -KdCardInfoAdd (KdCardFuncs *funcs, - void *closure) -{ - KdCardInfo *ci, **prev; - - ci = xcalloc (1, sizeof (KdCardInfo)); - if (!ci) - return 0; - for (prev = &kdCardInfo; *prev; prev = &(*prev)->next); - *prev = ci; - ci->cfuncs = funcs; - ci->closure = closure; - ci->screenList = 0; - ci->selected = 0; - ci->next = 0; - return ci; -} - -KdCardInfo * -KdCardInfoLast (void) -{ - KdCardInfo *ci; - - if (!kdCardInfo) - return 0; - for (ci = kdCardInfo; ci->next; ci = ci->next); - return ci; -} - -void -KdCardInfoDispose (KdCardInfo *ci) -{ - KdCardInfo **prev; - - for (prev = &kdCardInfo; *prev; prev = &(*prev)->next) - if (*prev == ci) - { - *prev = ci->next; - xfree (ci); - break; - } -} - -KdScreenInfo * -KdScreenInfoAdd (KdCardInfo *ci) -{ - KdScreenInfo *si, **prev; - int n; - - si = xcalloc (1, sizeof (KdScreenInfo)); - if (!si) - return 0; - for (prev = &ci->screenList, n = 0; *prev; prev = &(*prev)->next, n++); - *prev = si; - si->next = 0; - si->card = ci; - si->mynum = n; - return si; -} - -void -KdScreenInfoDispose (KdScreenInfo *si) -{ - KdCardInfo *ci = si->card; - KdScreenInfo **prev; - - for (prev = &ci->screenList; *prev; prev = &(*prev)->next) { - if (*prev == si) - { - *prev = si->next; - xfree (si); - if (!ci->screenList) - KdCardInfoDispose (ci); - break; - } - } -} - -KdPointerInfo * -KdNewPointer (void) -{ - KdPointerInfo *pi; - int i; - - pi = (KdPointerInfo *)xcalloc(1, sizeof(KdPointerInfo)); - if (!pi) - return NULL; - - pi->name = strdup("Generic Pointer"); - pi->path = NULL; - pi->inputClass = KD_MOUSE; - pi->driver = NULL; - pi->driverPrivate = NULL; - pi->next = NULL; - pi->options = NULL; - pi->nAxes = 3; - pi->nButtons = KD_MAX_BUTTON; - for (i = 1; i < KD_MAX_BUTTON; i++) - pi->map[i] = i; - - return pi; -} - -void -KdFreePointer(KdPointerInfo *pi) -{ - InputOption *option, *prev = NULL; - - xfree(pi->name); - xfree(pi->path); - - for (option = pi->options; option; option = option->next) { - xfree(prev); - xfree(option->key); - xfree(option->value); - prev = option; - } - - xfree(prev); - xfree(pi); -} - -void -KdFreeKeyboard(KdKeyboardInfo *ki) -{ - xfree(ki->name); - xfree(ki->path); - xfree(ki->xkbRules); - xfree(ki->xkbModel); - xfree(ki->xkbLayout); - ki->next = NULL; - xfree(ki); -} +/* + * Copyright © 1999 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" + +KdCardInfo *kdCardInfo; + +KdCardInfo * +KdCardInfoAdd (KdCardFuncs *funcs, + void *closure) +{ + KdCardInfo *ci, **prev; + + ci = calloc(1, sizeof (KdCardInfo)); + if (!ci) + return 0; + for (prev = &kdCardInfo; *prev; prev = &(*prev)->next); + *prev = ci; + ci->cfuncs = funcs; + ci->closure = closure; + ci->screenList = 0; + ci->selected = 0; + ci->next = 0; + return ci; +} + +KdCardInfo * +KdCardInfoLast (void) +{ + KdCardInfo *ci; + + if (!kdCardInfo) + return 0; + for (ci = kdCardInfo; ci->next; ci = ci->next); + return ci; +} + +void +KdCardInfoDispose (KdCardInfo *ci) +{ + KdCardInfo **prev; + + for (prev = &kdCardInfo; *prev; prev = &(*prev)->next) + if (*prev == ci) + { + *prev = ci->next; + free(ci); + break; + } +} + +KdScreenInfo * +KdScreenInfoAdd (KdCardInfo *ci) +{ + KdScreenInfo *si, **prev; + int n; + + si = calloc(1, sizeof (KdScreenInfo)); + if (!si) + return 0; + for (prev = &ci->screenList, n = 0; *prev; prev = &(*prev)->next, n++); + *prev = si; + si->next = 0; + si->card = ci; + si->mynum = n; + return si; +} + +void +KdScreenInfoDispose (KdScreenInfo *si) +{ + KdCardInfo *ci = si->card; + KdScreenInfo **prev; + + for (prev = &ci->screenList; *prev; prev = &(*prev)->next) { + if (*prev == si) + { + *prev = si->next; + free(si); + if (!ci->screenList) + KdCardInfoDispose (ci); + break; + } + } +} + +KdPointerInfo * +KdNewPointer (void) +{ + KdPointerInfo *pi; + int i; + + pi = (KdPointerInfo *)calloc(1, sizeof(KdPointerInfo)); + if (!pi) + return NULL; + + pi->name = strdup("Generic Pointer"); + pi->path = NULL; + pi->inputClass = KD_MOUSE; + pi->driver = NULL; + pi->driverPrivate = NULL; + pi->next = NULL; + pi->options = NULL; + pi->nAxes = 3; + pi->nButtons = KD_MAX_BUTTON; + for (i = 1; i < KD_MAX_BUTTON; i++) + pi->map[i] = i; + + return pi; +} + +void +KdFreePointer(KdPointerInfo *pi) +{ + InputOption *option, *prev = NULL; + + free(pi->name); + free(pi->path); + + for (option = pi->options; option; option = option->next) { + free(prev); + free(option->key); + free(option->value); + prev = option; + } + + free(prev); + free(pi); +} + +void +KdFreeKeyboard(KdKeyboardInfo *ki) +{ + free(ki->name); + free(ki->path); + free(ki->xkbRules); + free(ki->xkbModel); + free(ki->xkbLayout); + ki->next = NULL; + free(ki); +} diff --git a/xorg-server/hw/kdrive/src/kinput.c b/xorg-server/hw/kdrive/src/kinput.c index a88f2dc61..024bce6bd 100644 --- a/xorg-server/hw/kdrive/src/kinput.c +++ b/xorg-server/hw/kdrive/src/kinput.c @@ -1,2360 +1,2360 @@ -/* - * Copyright © 1999 Keith Packard - * Copyright © 2006 Nokia Corporation - * - * 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 the authors not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. The authors make no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE AUTHORS 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include "kdrive.h" -#include "inputstr.h" - -#define XK_PUBLISHING -#include <X11/keysym.h> -#if HAVE_X11_XF86KEYSYM_H -#include <X11/XF86keysym.h> -#endif -#include <signal.h> -#include <stdio.h> -#ifdef sun -#include <sys/file.h> /* needed for FNONBLOCK & FASYNC */ -#endif - -#include "xkbsrv.h" - -#include <X11/extensions/XI.h> -#include <X11/extensions/XIproto.h> -#include "XIstubs.h" /* even though we don't use stubs. cute, no? */ -#include "exevents.h" -#include "extinit.h" -#include "exglobals.h" -#include "eventstr.h" -#include "xserver-properties.h" - -#define AtomFromName(x) MakeAtom(x, strlen(x), 1) - -struct KdConfigDevice { - char *line; - struct KdConfigDevice *next; -}; - -/* kdKeyboards and kdPointers hold all the real devices. */ -static KdKeyboardInfo *kdKeyboards = NULL; -static KdPointerInfo *kdPointers = NULL; -static struct KdConfigDevice *kdConfigKeyboards = NULL; -static struct KdConfigDevice *kdConfigPointers = NULL; - -static KdKeyboardDriver *kdKeyboardDrivers = NULL; -static KdPointerDriver *kdPointerDrivers = NULL; - -static EventListPtr kdEvents = NULL; - -static Bool kdInputEnabled; -static Bool kdOffScreen; -static unsigned long kdOffScreenTime; -static KdPointerMatrix kdPointerMatrix = { - { { 1, 0, 0 }, - { 0, 1, 0 } } -}; - -void KdResetInputMachine (void); - -#define KD_MAX_INPUT_FDS 8 - -typedef struct _kdInputFd { - int fd; - void (*read) (int fd, void *closure); - int (*enable) (int fd, void *closure); - void (*disable) (int fd, void *closure); - void *closure; -} KdInputFd; - -static KdInputFd kdInputFds[KD_MAX_INPUT_FDS]; -static int kdNumInputFds; - -extern Bool kdRawPointerCoordinates; - -static void -KdSigio (int sig) -{ - int i; - - for (i = 0; i < kdNumInputFds; i++) - (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); -} - -static void -KdBlockSigio (void) -{ - sigset_t set; - - sigemptyset (&set); - sigaddset (&set, SIGIO); - sigprocmask (SIG_BLOCK, &set, 0); -} - -static void -KdUnblockSigio (void) -{ - sigset_t set; - - sigemptyset (&set); - sigaddset (&set, SIGIO); - sigprocmask (SIG_UNBLOCK, &set, 0); -} - -#ifdef DEBUG_SIGIO - -void -KdAssertSigioBlocked (char *where) -{ - sigset_t set, old; - - sigemptyset (&set); - sigprocmask (SIG_BLOCK, &set, &old); - if (!sigismember (&old, SIGIO)) { - ErrorF ("SIGIO not blocked at %s\n", where); - KdBacktrace(0); - } -} - -#else - -#define KdAssertSigioBlocked(s) - -#endif - -static int kdnFds; - -#ifdef FNONBLOCK -#define NOBLOCK FNONBLOCK -#else -#define NOBLOCK FNDELAY -#endif - -void -KdResetInputMachine (void) -{ - KdPointerInfo *pi; - - for (pi = kdPointers; pi; pi = pi->next) { - pi->mouseState = start; - pi->eventHeld = FALSE; - } -} - -static void -KdNonBlockFd (int fd) -{ - int flags; - flags = fcntl (fd, F_GETFL); - flags |= FASYNC|NOBLOCK; - fcntl (fd, F_SETFL, flags); -} - -static void -KdAddFd (int fd) -{ - struct sigaction act; - sigset_t set; - - kdnFds++; - fcntl (fd, F_SETOWN, getpid()); - KdNonBlockFd (fd); - AddEnabledDevice (fd); - memset (&act, '\0', sizeof act); - act.sa_handler = KdSigio; - sigemptyset (&act.sa_mask); - sigaddset (&act.sa_mask, SIGIO); - sigaddset (&act.sa_mask, SIGALRM); - sigaddset (&act.sa_mask, SIGVTALRM); - sigaction (SIGIO, &act, 0); - sigemptyset (&set); - sigprocmask (SIG_SETMASK, &set, 0); -} - -static void -KdRemoveFd (int fd) -{ - struct sigaction act; - int flags; - - kdnFds--; - RemoveEnabledDevice (fd); - flags = fcntl (fd, F_GETFL); - flags &= ~(FASYNC|NOBLOCK); - fcntl (fd, F_SETFL, flags); - if (kdnFds == 0) - { - memset (&act, '\0', sizeof act); - act.sa_handler = SIG_IGN; - sigemptyset (&act.sa_mask); - sigaction (SIGIO, &act, 0); - } -} - -Bool -KdRegisterFd (int fd, void (*read) (int fd, void *closure), void *closure) -{ - if (kdNumInputFds == KD_MAX_INPUT_FDS) - return FALSE; - kdInputFds[kdNumInputFds].fd = fd; - kdInputFds[kdNumInputFds].read = read; - kdInputFds[kdNumInputFds].enable = 0; - kdInputFds[kdNumInputFds].disable = 0; - kdInputFds[kdNumInputFds].closure = closure; - kdNumInputFds++; - if (kdInputEnabled) - KdAddFd (fd); - return TRUE; -} - -void -KdUnregisterFd (void *closure, int fd, Bool do_close) -{ - int i, j; - - for (i = 0; i < kdNumInputFds; i++) { - if (kdInputFds[i].closure == closure && - (fd == -1 || kdInputFds[i].fd == fd)) { - if (kdInputEnabled) - KdRemoveFd (kdInputFds[i].fd); - if (do_close) - close (kdInputFds[i].fd); - kdNumInputFds--; - for (j = i; j < kdNumInputFds; j++) - kdInputFds[j] = kdInputFds[j+1]; - break; - } - } -} - -void -KdUnregisterFds (void *closure, Bool do_close) -{ - KdUnregisterFd(closure, -1, do_close); -} - -void -KdDisableInput (void) -{ - KdKeyboardInfo *ki; - KdPointerInfo *pi; - int found = 0, i = 0; - - KdBlockSigio(); - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->driver && ki->driver->Disable) - (*ki->driver->Disable) (ki); - } - - for (pi = kdPointers; pi; pi = pi->next) { - if (pi->driver && pi->driver->Disable) - (*pi->driver->Disable) (pi); - } - - if (kdNumInputFds) { - ErrorF("[KdDisableInput] Buggy drivers: still %d input fds left!", - kdNumInputFds); - i = 0; - while (i < kdNumInputFds) { - found = 0; - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki == kdInputFds[i].closure) { - ErrorF(" fd %d belongs to keybd driver %s\n", - kdInputFds[i].fd, - ki->driver && ki->driver->name ? - ki->driver->name : "(unnamed!)"); - found = 1; - break; - } - } - - if (found) { - i++; - continue; - } - - for (pi = kdPointers; pi; pi = pi->next) { - if (pi == kdInputFds[i].closure) { - ErrorF(" fd %d belongs to pointer driver %s\n", - kdInputFds[i].fd, - pi->driver && pi->driver->name ? - pi->driver->name : "(unnamed!)"); - break; - } - } - - if (found) { - i++; - continue; - } - - ErrorF(" fd %d not claimed by any active device!\n", - kdInputFds[i].fd); - KdUnregisterFd(kdInputFds[i].closure, kdInputFds[i].fd, TRUE); - } - } - - kdInputEnabled = FALSE; -} - -void -KdEnableInput (void) -{ - InternalEvent ev; - KdKeyboardInfo *ki; - KdPointerInfo *pi; - - kdInputEnabled = TRUE; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->driver && ki->driver->Enable) - (*ki->driver->Enable) (ki); - } - - for (pi = kdPointers; pi; pi = pi->next) { - if (pi->driver && pi->driver->Enable) - (*pi->driver->Enable) (pi); - } - - /* reset screen saver */ - ev.any.time = GetTimeInMillis (); - NoticeEventTime (&ev); - - KdUnblockSigio (); -} - -static KdKeyboardDriver * -KdFindKeyboardDriver (char *name) -{ - KdKeyboardDriver *ret; - - /* ask a stupid question ... */ - if (!name) - return NULL; - - for (ret = kdKeyboardDrivers; ret; ret = ret->next) { - if (strcmp(ret->name, name) == 0) - return ret; - } - - return NULL; -} - -static KdPointerDriver * -KdFindPointerDriver (char *name) -{ - KdPointerDriver *ret; - - /* ask a stupid question ... */ - if (!name) - return NULL; - - for (ret = kdPointerDrivers; ret; ret = ret->next) { - if (strcmp(ret->name, name) == 0) - return ret; - } - - return NULL; -} - -static int -KdPointerProc(DeviceIntPtr pDevice, int onoff) -{ - DevicePtr pDev = (DevicePtr)pDevice; - KdPointerInfo *pi; - Atom xiclass; - Atom *btn_labels; - Atom *axes_labels; - - if (!pDev) - return BadImplementation; - - for (pi = kdPointers; pi; pi = pi->next) { - if (pi->dixdev && pi->dixdev->id == pDevice->id) - break; - } - - if (!pi || !pi->dixdev || pi->dixdev->id != pDevice->id) { - ErrorF("[KdPointerProc] Failed to find pointer for device %d!\n", - pDevice->id); - return BadImplementation; - } - - switch (onoff) - { - case DEVICE_INIT: -#ifdef DEBUG - ErrorF("initialising pointer %s ...\n", pi->name); -#endif - if (!pi->driver) { - if (!pi->driverPrivate) { - ErrorF("no driver specified for %s\n", pi->name); - return BadImplementation; - } - - pi->driver = KdFindPointerDriver(pi->driverPrivate); - if (!pi->driver) { - ErrorF("Couldn't find pointer driver %s\n", - pi->driverPrivate ? (char *) pi->driverPrivate : - "(unnamed)"); - return !Success; - } - xfree(pi->driverPrivate); - pi->driverPrivate = NULL; - } - - if (!pi->driver->Init) { - ErrorF("no init function\n"); - return BadImplementation; - } - - if ((*pi->driver->Init) (pi) != Success) { - return !Success; - } - - btn_labels = xcalloc(pi->nButtons, sizeof(Atom)); - if (!btn_labels) - return BadAlloc; - axes_labels = xcalloc(pi->nAxes, sizeof(Atom)); - if (!axes_labels) { - xfree(btn_labels); - return BadAlloc; - } - - switch(pi->nAxes) - { - default: - case 7: - btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); - case 6: - btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); - case 5: - btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); - case 4: - btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); - case 3: - btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); - case 2: - btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); - case 1: - btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); - case 0: - break; - } - - if (pi->nAxes >= 2) { - axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); - axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); - } - - InitPointerDeviceStruct(pDev, pi->map, pi->nButtons, btn_labels, - (PtrCtrlProcPtr)NoopDDA, - GetMotionHistorySize(), pi->nAxes, axes_labels); - - xfree(btn_labels); - xfree(axes_labels); - - if (pi->inputClass == KD_TOUCHSCREEN) { - InitAbsoluteClassDeviceStruct(pDevice); - xiclass = AtomFromName(XI_TOUCHSCREEN); - } - else { - xiclass = AtomFromName(XI_MOUSE); - } - - AssignTypeAndName(pi->dixdev, xiclass, - pi->name ? pi->name : "Generic KDrive Pointer"); - - return Success; - - case DEVICE_ON: - if (pDev->on == TRUE) - return Success; - - if (!pi->driver->Enable) { - ErrorF("no enable function\n"); - return BadImplementation; - } - - if ((*pi->driver->Enable) (pi) == Success) { - pDev->on = TRUE; - return Success; - } - else { - return BadImplementation; - } - - return Success; - - case DEVICE_OFF: - if (pDev->on == FALSE) { - return Success; - } - - if (!pi->driver->Disable) { - return BadImplementation; - } - else { - (*pi->driver->Disable) (pi); - pDev->on = FALSE; - return Success; - } - - return Success; - - case DEVICE_CLOSE: - if (pDev->on) { - if (!pi->driver->Disable) { - return BadImplementation; - } - (*pi->driver->Disable) (pi); - pDev->on = FALSE; - } - - if (!pi->driver->Fini) - return BadImplementation; - - (*pi->driver->Fini) (pi); - - KdRemovePointer(pi); - - return Success; - } - - /* NOTREACHED */ - return BadImplementation; -} - -Bool -LegalModifier(unsigned int key, DeviceIntPtr pDev) -{ - return TRUE; -} - -static void -KdBell (int volume, DeviceIntPtr pDev, pointer arg, int something) -{ - KeybdCtrl *ctrl = arg; - KdKeyboardInfo *ki = NULL; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev && ki->dixdev->id == pDev->id) - break; - } - - if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) - return; - - KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); -} - -void -DDXRingBell(int volume, int pitch, int duration) -{ - KdKeyboardInfo *ki = NULL; - - if (kdOsFuncs->Bell) { - (*kdOsFuncs->Bell)(volume, pitch, duration); - } - else { - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev->coreEvents) - KdRingBell(ki, volume, pitch, duration); - } - } -} - -void -KdRingBell(KdKeyboardInfo *ki, int volume, int pitch, int duration) -{ - if (!ki || !ki->driver || !ki->driver->Bell) - return; - - if (kdInputEnabled) - (*ki->driver->Bell) (ki, volume, pitch, duration); -} - - -static void -KdSetLeds (KdKeyboardInfo *ki, int leds) -{ - if (!ki || !ki->driver) - return; - - if (kdInputEnabled) { - if (ki->driver->Leds) - (*ki->driver->Leds) (ki, leds); - } -} - -void -KdSetLed (KdKeyboardInfo *ki, int led, Bool on) -{ - if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed) - return; - - NoteLedState (ki->dixdev, led, on); - KdSetLeds (ki, ki->dixdev->kbdfeed->ctrl.leds); -} - -void -KdSetPointerMatrix (KdPointerMatrix *matrix) -{ - kdPointerMatrix = *matrix; -} - -void -KdComputePointerMatrix (KdPointerMatrix *m, Rotation randr, int width, - int height) -{ - int x_dir = 1, y_dir = 1; - int i, j; - int size[2]; - - size[0] = width; size[1] = height; - if (randr & RR_Reflect_X) - x_dir = -1; - if (randr & RR_Reflect_Y) - y_dir = -1; - switch (randr & (RR_Rotate_All)) { - case RR_Rotate_0: - m->matrix[0][0] = x_dir; m->matrix[0][1] = 0; - m->matrix[1][0] = 0; m->matrix[1][1] = y_dir; - break; - case RR_Rotate_90: - m->matrix[0][0] = 0; m->matrix[0][1] = -x_dir; - m->matrix[1][0] = y_dir; m->matrix[1][1] = 0; - break; - case RR_Rotate_180: - m->matrix[0][0] = -x_dir; m->matrix[0][1] = 0; - m->matrix[1][0] = 0; m->matrix[1][1] = -y_dir; - break; - case RR_Rotate_270: - m->matrix[0][0] = 0; m->matrix[0][1] = x_dir; - m->matrix[1][0] = -y_dir; m->matrix[1][1] = 0; - break; - } - for (i = 0; i < 2; i++) - { - m->matrix[i][2] = 0; - for (j = 0 ; j < 2; j++) - if (m->matrix[i][j] < 0) - m->matrix[i][2] = size[j] - 1; - } -} - -void -KdScreenToPointerCoords (int *x, int *y) -{ - int (*m)[3] = kdPointerMatrix.matrix; - int div = m[0][1] * m[1][0] - m[1][1] * m[0][0]; - int sx = *x; - int sy = *y; - - *x = (m[0][1] * sy - m[0][1] * m[1][2] + m[1][1] * m[0][2] - m[1][1] * sx) / div; - *y = (m[1][0] * sx + m[0][0] * m[1][2] - m[1][0] * m[0][2] - m[0][0] * sy) / div; -} - -static void -KdKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) -{ - KdKeyboardInfo *ki; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev && ki->dixdev->id == pDevice->id) - break; - } - - if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) - return; - - KdSetLeds(ki, ctrl->leds); - ki->bellPitch = ctrl->bell_pitch; - ki->bellDuration = ctrl->bell_duration; -} - -extern KeybdCtrl defaultKeyboardControl; - -static int -KdKeyboardProc(DeviceIntPtr pDevice, int onoff) -{ - Bool ret; - DevicePtr pDev = (DevicePtr)pDevice; - KdKeyboardInfo *ki; - Atom xiclass; - XkbRMLVOSet rmlvo; - - if (!pDev) - return BadImplementation; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev && ki->dixdev->id == pDevice->id) - break; - } - - if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id) { - return BadImplementation; - } - - switch (onoff) - { - case DEVICE_INIT: -#ifdef DEBUG - ErrorF("initialising keyboard %s\n", ki->name); -#endif - if (!ki->driver) { - if (!ki->driverPrivate) { - ErrorF("no driver specified!\n"); - return BadImplementation; - } - - ki->driver = KdFindKeyboardDriver(ki->driverPrivate); - if (!ki->driver) { - ErrorF("Couldn't find keyboard driver %s\n", - ki->driverPrivate ? (char *) ki->driverPrivate : - "(unnamed)"); - return !Success; - } - xfree(ki->driverPrivate); - ki->driverPrivate = NULL; - } - - if (!ki->driver->Init) { - ErrorF("Keyboard %s: no init function\n", ki->name); - return BadImplementation; - } - - if ((*ki->driver->Init) (ki) != Success) { - return !Success; - } - - memset(&rmlvo, 0, sizeof(rmlvo)); - rmlvo.rules = ki->xkbRules; - rmlvo.model = ki->xkbModel; - rmlvo.layout = ki->xkbLayout; - rmlvo.variant = ki->xkbVariant; - rmlvo.options = ki->xkbOptions; - ret = InitKeyboardDeviceStruct (pDevice, &rmlvo, KdBell, KdKbdCtrl); - if (!ret) { - ErrorF("Couldn't initialise keyboard %s\n", ki->name); - return BadImplementation; - } - - xiclass = AtomFromName(XI_KEYBOARD); - AssignTypeAndName(pDevice, xiclass, - ki->name ? ki->name : "Generic KDrive Keyboard"); - - KdResetInputMachine(); - - return Success; - - case DEVICE_ON: - if (pDev->on == TRUE) - return Success; - - if (!ki->driver->Enable) - return BadImplementation; - - if ((*ki->driver->Enable) (ki) != Success) { - return BadMatch; - } - - pDev->on = TRUE; - return Success; - - case DEVICE_OFF: - if (pDev->on == FALSE) - return Success; - - if (!ki->driver->Disable) - return BadImplementation; - - (*ki->driver->Disable) (ki); - pDev->on = FALSE; - - return Success; - - break; - - case DEVICE_CLOSE: - if (pDev->on) { - if (!ki->driver->Disable) - return BadImplementation; - - (*ki->driver->Disable) (ki); - pDev->on = FALSE; - } - - if (!ki->driver->Fini) - return BadImplementation; - - (*ki->driver->Fini) (ki); - - KdRemoveKeyboard(ki); - - return Success; - } - - /* NOTREACHED */ - return BadImplementation; -} - -void -KdAddPointerDriver (KdPointerDriver *driver) -{ - KdPointerDriver **prev; - - if (!driver) - return; - - for (prev = &kdPointerDrivers; *prev; prev = &(*prev)->next) { - if (*prev == driver) - return; - } - *prev = driver; -} - -void -KdRemovePointerDriver (KdPointerDriver *driver) -{ - KdPointerDriver *tmp; - - if (!driver) - return; - - /* FIXME remove all pointers using this driver */ - for (tmp = kdPointerDrivers; tmp; tmp = tmp->next) { - if (tmp->next == driver) - tmp->next = driver->next; - } - if (tmp == driver) - tmp = NULL; -} - -void -KdAddKeyboardDriver (KdKeyboardDriver *driver) -{ - KdKeyboardDriver **prev; - - if (!driver) - return; - - for (prev = &kdKeyboardDrivers; *prev; prev = &(*prev)->next) { - if (*prev == driver) - return; - } - *prev = driver; -} - -void -KdRemoveKeyboardDriver (KdKeyboardDriver *driver) -{ - KdKeyboardDriver *tmp; - - if (!driver) - return; - - /* FIXME remove all keyboards using this driver */ - for (tmp = kdKeyboardDrivers; tmp; tmp = tmp->next) { - if (tmp->next == driver) - tmp->next = driver->next; - } - if (tmp == driver) - tmp = NULL; -} - -KdKeyboardInfo * -KdNewKeyboard (void) -{ - KdKeyboardInfo *ki = xcalloc(sizeof(KdKeyboardInfo), 1); - if (!ki) - return NULL; - - ki->minScanCode = 0; - ki->maxScanCode = 0; - ki->leds = 0; - ki->bellPitch = 1000; - ki->bellDuration = 200; - ki->next = NULL; - ki->options = NULL; - ki->xkbRules = strdup(XKB_DFLT_RULES); - ki->xkbModel = strdup(XKB_DFLT_MODEL); - ki->xkbLayout = strdup(XKB_DFLT_LAYOUT); - ki->xkbVariant = strdup(XKB_DFLT_VARIANT); - ki->xkbOptions = strdup(XKB_DFLT_OPTIONS); - - return ki; -} - -int -KdAddConfigKeyboard (char *keyboard) -{ - struct KdConfigDevice **prev, *new; - - if (!keyboard) - return Success; - - new = (struct KdConfigDevice *) xcalloc(sizeof(struct KdConfigDevice), 1); - if (!new) - return BadAlloc; - - new->line = xstrdup(keyboard); - new->next = NULL; - - for (prev = &kdConfigKeyboards; *prev; prev = &(*prev)->next); - *prev = new; - - return Success; -} - -int -KdAddKeyboard (KdKeyboardInfo *ki) -{ - KdKeyboardInfo **prev; - - if (!ki) - return !Success; - - ki->dixdev = AddInputDevice(serverClient, KdKeyboardProc, TRUE); - if (!ki->dixdev) { - ErrorF("Couldn't register keyboard device %s\n", - ki->name ? ki->name : "(unnamed)"); - return !Success; - } - - ki->dixdev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; - ki->dixdev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; - RegisterOtherDevice(ki->dixdev); - -#ifdef DEBUG - ErrorF("added keyboard %s with dix id %d\n", ki->name, ki->dixdev->id); -#endif - - for (prev = &kdKeyboards; *prev; prev = &(*prev)->next); - *prev = ki; - - return Success; -} - -void -KdRemoveKeyboard (KdKeyboardInfo *ki) -{ - KdKeyboardInfo **prev; - - if (!ki) - return; - - for (prev = &kdKeyboards; *prev; prev = &(*prev)->next) { - if (*prev == ki) { - *prev = ki->next; - break; - } - } - - KdFreeKeyboard(ki); -} - -int -KdAddConfigPointer (char *pointer) -{ - struct KdConfigDevice **prev, *new; - - if (!pointer) - return Success; - - new = (struct KdConfigDevice *) xcalloc(sizeof(struct KdConfigDevice), 1); - if (!new) - return BadAlloc; - - new->line = xstrdup(pointer); - new->next = NULL; - - for (prev = &kdConfigPointers; *prev; prev = &(*prev)->next); - *prev = new; - - return Success; -} - -int -KdAddPointer (KdPointerInfo *pi) -{ - KdPointerInfo **prev; - - if (!pi) - return Success; - - pi->mouseState = start; - pi->eventHeld = FALSE; - - pi->dixdev = AddInputDevice(serverClient, KdPointerProc, TRUE); - if (!pi->dixdev) { - ErrorF("Couldn't add pointer device %s\n", - pi->name ? pi->name : "(unnamed)"); - return BadDevice; - } - - pi->dixdev->deviceGrab.ActivateGrab = ActivatePointerGrab; - pi->dixdev->deviceGrab.DeactivateGrab = DeactivatePointerGrab; - RegisterOtherDevice(pi->dixdev); - - for (prev = &kdPointers; *prev; prev = &(*prev)->next); - *prev = pi; - - return Success; -} - -void -KdRemovePointer (KdPointerInfo *pi) -{ - KdPointerInfo **prev; - - if (!pi) - return; - - for (prev = &kdPointers; *prev; prev = &(*prev)->next) { - if (*prev == pi) { - *prev = pi->next; - break; - } - } - - KdFreePointer(pi); -} - -/* - * You can call your kdriver server with something like: - * $ ./hw/kdrive/yourserver/X :1 -mouse evdev,,device=/dev/input/event4 -keybd - * evdev,,device=/dev/input/event1,xkbmodel=abnt2,xkblayout=br - */ -static Bool -KdGetOptions (InputOption **options, char *string) -{ - InputOption *newopt = NULL, **tmpo = NULL; - int tam_key = 0; - - newopt = xcalloc(1, sizeof (InputOption)); - if (!newopt) - return FALSE; - - for (tmpo = options; *tmpo; tmpo = &(*tmpo)->next) - ; /* Hello, I'm here */ - *tmpo = newopt; - - if (strchr(string, '=')) - { - tam_key = (strchr(string, '=') - string); - newopt->key = (char *)xalloc(tam_key); - strncpy(newopt->key, string, tam_key); - newopt->key[tam_key] = '\0'; - newopt->value = xstrdup(strchr(string, '=') + 1); - } - else - { - newopt->key = xstrdup(string); - newopt->value = NULL; - } - newopt->next = NULL; - - return TRUE; -} - -static void -KdParseKbdOptions (KdKeyboardInfo *ki) -{ - InputOption *option = NULL; - - for (option = ki->options; option; option = option->next) - { - if (strcasecmp(option->key, "XkbRules") == 0) - ki->xkbRules = option->value; - else if (strcasecmp(option->key, "XkbModel") == 0) - ki->xkbModel = option->value; - else if (strcasecmp(option->key, "XkbLayout") == 0) - ki->xkbLayout = option->value; - else if (strcasecmp(option->key, "XkbVariant") == 0) - ki->xkbVariant = option->value; - else if (strcasecmp(option->key, "XkbOptions") == 0) - ki->xkbOptions = option->value; - else if (!strcasecmp (option->key, "device")) - ki->path = strdup(option->value); - else - ErrorF("Kbd option key (%s) of value (%s) not assigned!\n", - option->key, option->value); - } -} - -KdKeyboardInfo * -KdParseKeyboard (char *arg) -{ - char save[1024]; - char delim; - InputOption *options = NULL; - KdKeyboardInfo *ki = NULL; - - ki = KdNewKeyboard(); - if (!ki) - return NULL; - - ki->name = strdup("Unknown KDrive Keyboard"); - ki->path = NULL; - ki->driver = NULL; - ki->driverPrivate = NULL; - ki->next = NULL; - - if (!arg) - { - ErrorF("keybd: no arg\n"); - KdFreeKeyboard (ki); - return NULL; - } - - if (strlen (arg) >= sizeof (save)) - { - ErrorF("keybd: arg too long\n"); - KdFreeKeyboard (ki); - return NULL; - } - - arg = KdParseFindNext (arg, ",", save, &delim); - if (!save[0]) - { - ErrorF("keybd: failed on save[0]\n"); - KdFreeKeyboard (ki); - return NULL; - } - - if (strcmp (save, "auto") == 0) - ki->driverPrivate = NULL; - else - ki->driverPrivate = xstrdup(save); - - if (delim != ',') - { - return ki; - } - - arg = KdParseFindNext (arg, ",", save, &delim); - - while (delim == ',') - { - arg = KdParseFindNext (arg, ",", save, &delim); - - if (!KdGetOptions(&options, save)) - { - KdFreeKeyboard(ki); - return NULL; - } - } - - if (options) - { - ki->options = options; - KdParseKbdOptions(ki); - } - - return ki; -} - -static void -KdParsePointerOptions (KdPointerInfo *pi) -{ - InputOption *option = NULL; - - for (option = pi->options; option; option = option->next) - { - if (!strcmp (option->key, "emulatemiddle")) - pi->emulateMiddleButton = TRUE; - else if (!strcmp (option->key, "noemulatemiddle")) - pi->emulateMiddleButton = FALSE; - else if (!strcmp (option->key, "transformcoord")) - pi->transformCoordinates = TRUE; - else if (!strcmp (option->key, "rawcoord")) - pi->transformCoordinates = FALSE; - else if (!strcasecmp (option->key, "device")) - pi->path = strdup(option->value); - else if (!strcasecmp (option->key, "protocol")) - pi->protocol = strdup(option->value); - else - ErrorF("Pointer option key (%s) of value (%s) not assigned!\n", - option->key, option->value); - } -} - -KdPointerInfo * -KdParsePointer (char *arg) -{ - char save[1024]; - char delim; - KdPointerInfo *pi = NULL; - InputOption *options = NULL; - int i = 0; - - pi = KdNewPointer(); - if (!pi) - return NULL; - pi->emulateMiddleButton = kdEmulateMiddleButton; - pi->transformCoordinates = !kdRawPointerCoordinates; - pi->protocol = NULL; - pi->nButtons = 5; /* XXX should not be hardcoded */ - pi->inputClass = KD_MOUSE; - - if (!arg) - { - ErrorF("mouse: no arg\n"); - KdFreePointer (pi); - return NULL; - } - - if (strlen (arg) >= sizeof (save)) - { - ErrorF("mouse: arg too long\n"); - KdFreePointer (pi); - return NULL; - } - arg = KdParseFindNext (arg, ",", save, &delim); - if (!save[0]) - { - ErrorF("failed on save[0]\n"); - KdFreePointer (pi); - return NULL; - } - - if (strcmp(save, "auto") == 0) - pi->driverPrivate = NULL; - else - pi->driverPrivate = xstrdup(save); - - if (delim != ',') - { - return pi; - } - - arg = KdParseFindNext (arg, ",", save, &delim); - - while (delim == ',') - { - arg = KdParseFindNext (arg, ",", save, &delim); - if (save[0] == '{') - { - char *s = save + 1; - i = 0; - while (*s && *s != '}') - { - if ('1' <= *s && *s <= '0' + pi->nButtons) - pi->map[i] = *s - '0'; - else - UseMsg (); - s++; - } - } - else - { - if (!KdGetOptions(&options, save)) - { - KdFreePointer(pi); - return NULL; - } - } - } - - if (options) - { - pi->options = options; - KdParsePointerOptions(pi); - } - - return pi; -} - - -void -KdInitInput (void) -{ - KdPointerInfo *pi; - KdKeyboardInfo *ki; - struct KdConfigDevice *dev; - - kdInputEnabled = TRUE; - - for (dev = kdConfigPointers; dev; dev = dev->next) { - pi = KdParsePointer(dev->line); - if (!pi) - ErrorF("Failed to parse pointer\n"); - if (KdAddPointer(pi) != Success) - ErrorF("Failed to add pointer!\n"); - } - for (dev = kdConfigKeyboards; dev; dev = dev->next) { - ki = KdParseKeyboard(dev->line); - if (!ki) - ErrorF("Failed to parse keyboard\n"); - if (KdAddKeyboard(ki) != Success) - ErrorF("Failed to add keyboard!\n"); - } - - mieqInit(); -} - -/* - * Middle button emulation state machine - * - * Possible transitions: - * Button 1 press v1 - * Button 1 release ^1 - * Button 2 press v2 - * Button 2 release ^2 - * Button 3 press v3 - * Button 3 release ^3 - * Button other press vo - * Button other release ^o - * Mouse motion <> - * Keyboard event k - * timeout ... - * outside box <-> - * - * States: - * start - * button_1_pend - * button_1_down - * button_2_down - * button_3_pend - * button_3_down - * synthetic_2_down_13 - * synthetic_2_down_3 - * synthetic_2_down_1 - * - * Transition diagram - * - * start - * v1 -> (hold) (settimeout) button_1_pend - * ^1 -> (deliver) start - * v2 -> (deliver) button_2_down - * ^2 -> (deliever) start - * v3 -> (hold) (settimeout) button_3_pend - * ^3 -> (deliver) start - * vo -> (deliver) start - * ^o -> (deliver) start - * <> -> (deliver) start - * k -> (deliver) start - * - * button_1_pend (button 1 is down, timeout pending) - * ^1 -> (release) (deliver) start - * v2 -> (release) (deliver) button_1_down - * ^2 -> (release) (deliver) button_1_down - * v3 -> (cleartimeout) (generate v2) synthetic_2_down_13 - * ^3 -> (release) (deliver) button_1_down - * vo -> (release) (deliver) button_1_down - * ^o -> (release) (deliver) button_1_down - * <-> -> (release) (deliver) button_1_down - * <> -> (deliver) button_1_pend - * k -> (release) (deliver) button_1_down - * ... -> (release) button_1_down - * - * button_1_down (button 1 is down) - * ^1 -> (deliver) start - * v2 -> (deliver) button_1_down - * ^2 -> (deliver) button_1_down - * v3 -> (deliver) button_1_down - * ^3 -> (deliver) button_1_down - * vo -> (deliver) button_1_down - * ^o -> (deliver) button_1_down - * <> -> (deliver) button_1_down - * k -> (deliver) button_1_down - * - * button_2_down (button 2 is down) - * v1 -> (deliver) button_2_down - * ^1 -> (deliver) button_2_down - * ^2 -> (deliver) start - * v3 -> (deliver) button_2_down - * ^3 -> (deliver) button_2_down - * vo -> (deliver) button_2_down - * ^o -> (deliver) button_2_down - * <> -> (deliver) button_2_down - * k -> (deliver) button_2_down - * - * button_3_pend (button 3 is down, timeout pending) - * v1 -> (generate v2) synthetic_2_down - * ^1 -> (release) (deliver) button_3_down - * v2 -> (release) (deliver) button_3_down - * ^2 -> (release) (deliver) button_3_down - * ^3 -> (release) (deliver) start - * vo -> (release) (deliver) button_3_down - * ^o -> (release) (deliver) button_3_down - * <-> -> (release) (deliver) button_3_down - * <> -> (deliver) button_3_pend - * k -> (release) (deliver) button_3_down - * ... -> (release) button_3_down - * - * button_3_down (button 3 is down) - * v1 -> (deliver) button_3_down - * ^1 -> (deliver) button_3_down - * v2 -> (deliver) button_3_down - * ^2 -> (deliver) button_3_down - * ^3 -> (deliver) start - * vo -> (deliver) button_3_down - * ^o -> (deliver) button_3_down - * <> -> (deliver) button_3_down - * k -> (deliver) button_3_down - * - * synthetic_2_down_13 (button 1 and 3 are down) - * ^1 -> (generate ^2) synthetic_2_down_3 - * v2 -> synthetic_2_down_13 - * ^2 -> synthetic_2_down_13 - * ^3 -> (generate ^2) synthetic_2_down_1 - * vo -> (deliver) synthetic_2_down_13 - * ^o -> (deliver) synthetic_2_down_13 - * <> -> (deliver) synthetic_2_down_13 - * k -> (deliver) synthetic_2_down_13 - * - * synthetic_2_down_3 (button 3 is down) - * v1 -> (deliver) synthetic_2_down_3 - * ^1 -> (deliver) synthetic_2_down_3 - * v2 -> synthetic_2_down_3 - * ^2 -> synthetic_2_down_3 - * ^3 -> start - * vo -> (deliver) synthetic_2_down_3 - * ^o -> (deliver) synthetic_2_down_3 - * <> -> (deliver) synthetic_2_down_3 - * k -> (deliver) synthetic_2_down_3 - * - * synthetic_2_down_1 (button 1 is down) - * ^1 -> start - * v2 -> synthetic_2_down_1 - * ^2 -> synthetic_2_down_1 - * v3 -> (deliver) synthetic_2_down_1 - * ^3 -> (deliver) synthetic_2_down_1 - * vo -> (deliver) synthetic_2_down_1 - * ^o -> (deliver) synthetic_2_down_1 - * <> -> (deliver) synthetic_2_down_1 - * k -> (deliver) synthetic_2_down_1 - */ - -typedef enum _inputClass { - down_1, up_1, - down_2, up_2, - down_3, up_3, - down_o, up_o, - motion, outside_box, - keyboard, timeout, - num_input_class -} KdInputClass; - -typedef enum _inputAction { - noop, - hold, - setto, - deliver, - release, - clearto, - gen_down_2, - gen_up_2 -} KdInputAction; - -#define MAX_ACTIONS 2 - -typedef struct _inputTransition { - KdInputAction actions[MAX_ACTIONS]; - KdPointerState nextState; -} KdInputTransition; - -static const -KdInputTransition kdInputMachine[num_input_states][num_input_class] = { - /* start */ - { - { { hold, setto }, button_1_pend }, /* v1 */ - { { deliver, noop }, start }, /* ^1 */ - { { deliver, noop }, button_2_down }, /* v2 */ - { { deliver, noop }, start }, /* ^2 */ - { { hold, setto }, button_3_pend }, /* v3 */ - { { deliver, noop }, start }, /* ^3 */ - { { deliver, noop }, start }, /* vo */ - { { deliver, noop }, start }, /* ^o */ - { { deliver, noop }, start }, /* <> */ - { { deliver, noop }, start }, /* <-> */ - { { noop, noop }, start }, /* k */ - { { noop, noop }, start }, /* ... */ - }, - /* button_1_pend */ - { - { { noop, noop }, button_1_pend }, /* v1 */ - { { release, deliver }, start }, /* ^1 */ - { { release, deliver }, button_1_down }, /* v2 */ - { { release, deliver }, button_1_down }, /* ^2 */ - { { clearto, gen_down_2 }, synth_2_down_13 }, /* v3 */ - { { release, deliver }, button_1_down }, /* ^3 */ - { { release, deliver }, button_1_down }, /* vo */ - { { release, deliver }, button_1_down }, /* ^o */ - { { deliver, noop }, button_1_pend }, /* <> */ - { { release, deliver }, button_1_down }, /* <-> */ - { { noop, noop }, button_1_down }, /* k */ - { { release, noop }, button_1_down }, /* ... */ - }, - /* button_1_down */ - { - { { noop, noop }, button_1_down }, /* v1 */ - { { deliver, noop }, start }, /* ^1 */ - { { deliver, noop }, button_1_down }, /* v2 */ - { { deliver, noop }, button_1_down }, /* ^2 */ - { { deliver, noop }, button_1_down }, /* v3 */ - { { deliver, noop }, button_1_down }, /* ^3 */ - { { deliver, noop }, button_1_down }, /* vo */ - { { deliver, noop }, button_1_down }, /* ^o */ - { { deliver, noop }, button_1_down }, /* <> */ - { { deliver, noop }, button_1_down }, /* <-> */ - { { noop, noop }, button_1_down }, /* k */ - { { noop, noop }, button_1_down }, /* ... */ - }, - /* button_2_down */ - { - { { deliver, noop }, button_2_down }, /* v1 */ - { { deliver, noop }, button_2_down }, /* ^1 */ - { { noop, noop }, button_2_down }, /* v2 */ - { { deliver, noop }, start }, /* ^2 */ - { { deliver, noop }, button_2_down }, /* v3 */ - { { deliver, noop }, button_2_down }, /* ^3 */ - { { deliver, noop }, button_2_down }, /* vo */ - { { deliver, noop }, button_2_down }, /* ^o */ - { { deliver, noop }, button_2_down }, /* <> */ - { { deliver, noop }, button_2_down }, /* <-> */ - { { noop, noop }, button_2_down }, /* k */ - { { noop, noop }, button_2_down }, /* ... */ - }, - /* button_3_pend */ - { - { { clearto, gen_down_2 }, synth_2_down_13 }, /* v1 */ - { { release, deliver }, button_3_down }, /* ^1 */ - { { release, deliver }, button_3_down }, /* v2 */ - { { release, deliver }, button_3_down }, /* ^2 */ - { { release, deliver }, button_3_down }, /* v3 */ - { { release, deliver }, start }, /* ^3 */ - { { release, deliver }, button_3_down }, /* vo */ - { { release, deliver }, button_3_down }, /* ^o */ - { { deliver, noop }, button_3_pend }, /* <> */ - { { release, deliver }, button_3_down }, /* <-> */ - { { release, noop }, button_3_down }, /* k */ - { { release, noop }, button_3_down }, /* ... */ - }, - /* button_3_down */ - { - { { deliver, noop }, button_3_down }, /* v1 */ - { { deliver, noop }, button_3_down }, /* ^1 */ - { { deliver, noop }, button_3_down }, /* v2 */ - { { deliver, noop }, button_3_down }, /* ^2 */ - { { noop, noop }, button_3_down }, /* v3 */ - { { deliver, noop }, start }, /* ^3 */ - { { deliver, noop }, button_3_down }, /* vo */ - { { deliver, noop }, button_3_down }, /* ^o */ - { { deliver, noop }, button_3_down }, /* <> */ - { { deliver, noop }, button_3_down }, /* <-> */ - { { noop, noop }, button_3_down }, /* k */ - { { noop, noop }, button_3_down }, /* ... */ - }, - /* synthetic_2_down_13 */ - { - { { noop, noop }, synth_2_down_13 }, /* v1 */ - { { gen_up_2, noop }, synth_2_down_3 }, /* ^1 */ - { { noop, noop }, synth_2_down_13 }, /* v2 */ - { { noop, noop }, synth_2_down_13 }, /* ^2 */ - { { noop, noop }, synth_2_down_13 }, /* v3 */ - { { gen_up_2, noop }, synth_2_down_1 }, /* ^3 */ - { { deliver, noop }, synth_2_down_13 }, /* vo */ - { { deliver, noop }, synth_2_down_13 }, /* ^o */ - { { deliver, noop }, synth_2_down_13 }, /* <> */ - { { deliver, noop }, synth_2_down_13 }, /* <-> */ - { { noop, noop }, synth_2_down_13 }, /* k */ - { { noop, noop }, synth_2_down_13 }, /* ... */ - }, - /* synthetic_2_down_3 */ - { - { { deliver, noop }, synth_2_down_3 }, /* v1 */ - { { deliver, noop }, synth_2_down_3 }, /* ^1 */ - { { deliver, noop }, synth_2_down_3 }, /* v2 */ - { { deliver, noop }, synth_2_down_3 }, /* ^2 */ - { { noop, noop }, synth_2_down_3 }, /* v3 */ - { { noop, noop }, start }, /* ^3 */ - { { deliver, noop }, synth_2_down_3 }, /* vo */ - { { deliver, noop }, synth_2_down_3 }, /* ^o */ - { { deliver, noop }, synth_2_down_3 }, /* <> */ - { { deliver, noop }, synth_2_down_3 }, /* <-> */ - { { noop, noop }, synth_2_down_3 }, /* k */ - { { noop, noop }, synth_2_down_3 }, /* ... */ - }, - /* synthetic_2_down_1 */ - { - { { noop, noop }, synth_2_down_1 }, /* v1 */ - { { noop, noop }, start }, /* ^1 */ - { { deliver, noop }, synth_2_down_1 }, /* v2 */ - { { deliver, noop }, synth_2_down_1 }, /* ^2 */ - { { deliver, noop }, synth_2_down_1 }, /* v3 */ - { { deliver, noop }, synth_2_down_1 }, /* ^3 */ - { { deliver, noop }, synth_2_down_1 }, /* vo */ - { { deliver, noop }, synth_2_down_1 }, /* ^o */ - { { deliver, noop }, synth_2_down_1 }, /* <> */ - { { deliver, noop }, synth_2_down_1 }, /* <-> */ - { { noop, noop }, synth_2_down_1 }, /* k */ - { { noop, noop }, synth_2_down_1 }, /* ... */ - }, -}; - -#define EMULATION_WINDOW 10 -#define EMULATION_TIMEOUT 100 - -static int -KdInsideEmulationWindow (KdPointerInfo *pi, int x, int y, int z) -{ - pi->emulationDx = pi->heldEvent.x - x; - pi->emulationDy = pi->heldEvent.y - y; - - return (abs (pi->emulationDx) < EMULATION_WINDOW && - abs (pi->emulationDy) < EMULATION_WINDOW); -} - -static KdInputClass -KdClassifyInput (KdPointerInfo *pi, int type, int x, int y, int z, int b) -{ - switch (type) { - case ButtonPress: - switch (b) { - case 1: return down_1; - case 2: return down_2; - case 3: return down_3; - default: return down_o; - } - break; - case ButtonRelease: - switch (b) { - case 1: return up_1; - case 2: return up_2; - case 3: return up_3; - default: return up_o; - } - break; - case MotionNotify: - if (pi->eventHeld && !KdInsideEmulationWindow(pi, x, y, z)) - return outside_box; - else - return motion; - default: - return keyboard; - } - return keyboard; -} - -#ifdef DEBUG -char *kdStateNames[] = { - "start", - "button_1_pend", - "button_1_down", - "button_2_down", - "button_3_pend", - "button_3_down", - "synth_2_down_13", - "synth_2_down_3", - "synthetic_2_down_1", - "num_input_states" -}; - -char *kdClassNames[] = { - "down_1", "up_1", - "down_2", "up_2", - "down_3", "up_3", - "motion", "ouside_box", - "keyboard", "timeout", - "num_input_class" -}; - -char *kdActionNames[] = { - "noop", - "hold", - "setto", - "deliver", - "release", - "clearto", - "gen_down_2", - "gen_up_2", -}; -#endif /* DEBUG */ - -static void -KdQueueEvent (DeviceIntPtr pDev, InternalEvent *ev) -{ - KdAssertSigioBlocked ("KdQueueEvent"); - mieqEnqueue (pDev, ev); -} - -/* We return true if we're stealing the event. */ -static Bool -KdRunMouseMachine (KdPointerInfo *pi, KdInputClass c, int type, int x, int y, - int z, int b, int absrel) -{ - const KdInputTransition *t; - int a; - - c = KdClassifyInput(pi, type, x, y, z, b); - t = &kdInputMachine[pi->mouseState][c]; - for (a = 0; a < MAX_ACTIONS; a++) - { - switch (t->actions[a]) { - case noop: - break; - case hold: - pi->eventHeld = TRUE; - pi->emulationDx = 0; - pi->emulationDy = 0; - pi->heldEvent.type = type; - pi->heldEvent.x = x; - pi->heldEvent.y = y; - pi->heldEvent.z = z; - pi->heldEvent.flags = b; - pi->heldEvent.absrel = absrel; - return TRUE; - break; - case setto: - pi->emulationTimeout = GetTimeInMillis () + EMULATION_TIMEOUT; - pi->timeoutPending = TRUE; - break; - case deliver: - _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x, - pi->heldEvent.y, pi->heldEvent.z, - pi->heldEvent.flags, pi->heldEvent.absrel, - TRUE); - break; - case release: - pi->eventHeld = FALSE; - pi->timeoutPending = FALSE; - _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x, - pi->heldEvent.y, pi->heldEvent.z, - pi->heldEvent.flags, pi->heldEvent.absrel, - TRUE); - return TRUE; - break; - case clearto: - pi->timeoutPending = FALSE; - break; - case gen_down_2: - _KdEnqueuePointerEvent (pi, ButtonPress, x, y, z, 2, absrel, - TRUE); - pi->eventHeld = FALSE; - return TRUE; - break; - case gen_up_2: - _KdEnqueuePointerEvent (pi, ButtonRelease, x, y, z, 2, absrel, - TRUE); - return TRUE; - break; - } - } - pi->mouseState = t->nextState; - return FALSE; -} - -static int -KdHandlePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z, int b, - int absrel) -{ - if (pi->emulateMiddleButton) - return KdRunMouseMachine (pi, KdClassifyInput(pi, type, x, y, z, b), - type, x, y, z, b, absrel); - return FALSE; -} - -static void -KdReceiveTimeout (KdPointerInfo *pi) -{ - KdRunMouseMachine (pi, timeout, 0, 0, 0, 0, 0, 0); -} - -/* - * kdCheckTermination - * - * This function checks for the key sequence that terminates the server. When - * detected, it sets the dispatchException flag and returns. The key sequence - * is: - * Control-Alt - * It's assumed that the server will be waken up by the caller when this - * function returns. - */ - -extern int nClients; - -void -KdReleaseAllKeys (void) -{ -#if 0 - int key, nEvents, i; - KdKeyboardInfo *ki; - - KdBlockSigio (); - - for (ki = kdKeyboards; ki; ki = ki->next) { - for (key = ki->keySyms.minKeyCode; key < ki->keySyms.maxKeyCode; - key++) { - if (key_is_down(ki->dixdev, key, KEY_POSTED | KEY_PROCESSED)) { - KdHandleKeyboardEvent(ki, KeyRelease, key); - GetEventList(&kdEvents); - nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, KeyRelease, key); - for (i = 0; i < nEvents; i++) - KdQueueEvent (ki->dixdev, (kdEvents + i)->event); - } - } - } - - KdUnblockSigio (); -#endif -} - -static void -KdCheckLock (void) -{ - KeyClassPtr keyc = NULL; - Bool isSet = FALSE, shouldBeSet = FALSE; - KdKeyboardInfo *tmp = NULL; - - for (tmp = kdKeyboards; tmp; tmp = tmp->next) { - if (tmp->LockLed && tmp->dixdev && tmp->dixdev->key) { - keyc = tmp->dixdev->key; - isSet = (tmp->leds & (1 << (tmp->LockLed-1))) != 0; - /* FIXME: Just use XKB indicators! */ - shouldBeSet = !!(XkbStateFieldFromRec(&keyc->xkbInfo->state) & LockMask); - if (isSet != shouldBeSet) - KdSetLed (tmp, tmp->LockLed, shouldBeSet); - } - } -} - -void -KdEnqueueKeyboardEvent(KdKeyboardInfo *ki, - unsigned char scan_code, - unsigned char is_up) -{ - unsigned char key_code; - KeyClassPtr keyc = NULL; - KeybdCtrl *ctrl = NULL; - int type, nEvents, i; - - if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed || !ki->dixdev->key) - return; - - keyc = ki->dixdev->key; - ctrl = &ki->dixdev->kbdfeed->ctrl; - - if (scan_code >= ki->minScanCode && scan_code <= ki->maxScanCode) - { - key_code = scan_code + KD_MIN_KEYCODE - ki->minScanCode; - - /* - * Set up this event -- the type may be modified below - */ - if (is_up) - type = KeyRelease; - else - type = KeyPress; - - GetEventList(&kdEvents); - - nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, type, key_code); - for (i = 0; i < nEvents; i++) - KdQueueEvent(ki->dixdev, (InternalEvent *)((kdEvents + i)->event)); - } - else { - ErrorF("driver %s wanted to post scancode %d outside of [%d, %d]!\n", - ki->name, scan_code, ki->minScanCode, ki->maxScanCode); - } -} - -/* - * kdEnqueuePointerEvent - * - * This function converts hardware mouse event information into X event - * information. A mouse movement event is passed off to MI to generate - * a MotionNotify event, if appropriate. Button events are created and - * passed off to MI for enqueueing. - */ - -/* FIXME do something a little more clever to deal with multiple axes here */ -void -KdEnqueuePointerEvent(KdPointerInfo *pi, unsigned long flags, int rx, int ry, - int rz) -{ - CARD32 ms; - unsigned char buttons; - int x, y, z; - int (*matrix)[3] = kdPointerMatrix.matrix; - unsigned long button; - int n; - int dixflags = 0; - - if (!pi) - return; - - ms = GetTimeInMillis(); - - /* we don't need to transform z, so we don't. */ - if (flags & KD_MOUSE_DELTA) { - if (pi->transformCoordinates) { - x = matrix[0][0] * rx + matrix[0][1] * ry; - y = matrix[1][0] * rx + matrix[1][1] * ry; - } - else { - x = rx; - y = ry; - } - } - else { - if (pi->transformCoordinates) { - x = matrix[0][0] * rx + matrix[0][1] * ry + matrix[0][2]; - y = matrix[1][0] * rx + matrix[1][1] * ry + matrix[1][2]; - } - else { - x = rx; - y = ry; - } - } - z = rz; - - if (flags & KD_MOUSE_DELTA) - { - if (x || y || z) - { - dixflags = POINTER_RELATIVE | POINTER_ACCELERATE; - _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE); - } - } else - { - dixflags = POINTER_ABSOLUTE; - if (x != pi->dixdev->last.valuators[0] || - y != pi->dixdev->last.valuators[1]) - _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE); - } - - buttons = flags; - - for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons; - button <<= 1, n++) { - if (((pi->buttonState & button) ^ (buttons & button)) && - !(buttons & button)) { - _KdEnqueuePointerEvent(pi, ButtonRelease, x, y, z, n, - dixflags, FALSE); - } - } - for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons; - button <<= 1, n++) { - if (((pi->buttonState & button) ^ (buttons & button)) && - (buttons & button)) { - _KdEnqueuePointerEvent(pi, ButtonPress, x, y, z, n, - dixflags, FALSE); - } - } - - pi->buttonState = buttons; -} - -void -_KdEnqueuePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z, - int b, int absrel, Bool force) -{ - int nEvents = 0, i = 0; - int valuators[3] = { x, y, z }; - - /* TRUE from KdHandlePointerEvent, means 'we swallowed the event'. */ - if (!force && KdHandlePointerEvent(pi, type, x, y, z, b, absrel)) - return; - - GetEventList(&kdEvents); - nEvents = GetPointerEvents(kdEvents, pi->dixdev, type, b, absrel, - 0, 3, valuators); - for (i = 0; i < nEvents; i++) - KdQueueEvent(pi->dixdev, (InternalEvent *)((kdEvents + i)->event)); -} - -void -KdBlockHandler (int screen, - pointer blockData, - pointer timeout, - pointer readmask) -{ - KdPointerInfo *pi; - int myTimeout=0; - - for (pi = kdPointers; pi; pi = pi->next) - { - if (pi->timeoutPending) - { - int ms; - - ms = pi->emulationTimeout - GetTimeInMillis (); - if (ms < 1) - ms = 1; - if(ms<myTimeout || myTimeout==0) - myTimeout=ms; - } - } - /* if we need to poll for events, do that */ - if(kdOsFuncs->pollEvents) - { - (*kdOsFuncs->pollEvents)(); - myTimeout=20; - } - if(myTimeout>0) - AdjustWaitForDelay (timeout, myTimeout); -} - -void -KdWakeupHandler (int screen, - pointer data, - unsigned long lresult, - pointer readmask) -{ - int result = (int) lresult; - fd_set *pReadmask = (fd_set *) readmask; - int i; - KdPointerInfo *pi; - - if (kdInputEnabled && result > 0) - { - for (i = 0; i < kdNumInputFds; i++) - if (FD_ISSET (kdInputFds[i].fd, pReadmask)) - { - KdBlockSigio (); - (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); - KdUnblockSigio (); - } - } - for (pi = kdPointers; pi; pi = pi->next) - { - if (pi->timeoutPending) - { - if ((long) (GetTimeInMillis () - pi->emulationTimeout) >= 0) - { - pi->timeoutPending = FALSE; - KdBlockSigio (); - KdReceiveTimeout (pi); - KdUnblockSigio (); - } - } - } - if (kdSwitchPending) - KdProcessSwitch (); -} - -#define KdScreenOrigin(pScreen) (&(KdGetScreenPriv(pScreen)->screen->origin)) - -static Bool -KdCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) -{ - ScreenPtr pScreen = *ppScreen; - ScreenPtr pNewScreen; - int n; - int dx, dy; - int best_x, best_y; - int n_best_x, n_best_y; - CARD32 ms; - - if (kdDisableZaphod || screenInfo.numScreens <= 1) - return FALSE; - - if (0 <= *x && *x < pScreen->width && 0 <= *y && *y < pScreen->height) - return FALSE; - - ms = GetTimeInMillis (); - if (kdOffScreen && (int) (ms - kdOffScreenTime) < 1000) - return FALSE; - kdOffScreen = TRUE; - kdOffScreenTime = ms; - n_best_x = -1; - best_x = 32767; - n_best_y = -1; - best_y = 32767; - for (n = 0; n < screenInfo.numScreens; n++) - { - pNewScreen = screenInfo.screens[n]; - if (pNewScreen == pScreen) - continue; - dx = KdScreenOrigin(pNewScreen)->x - KdScreenOrigin(pScreen)->x; - dy = KdScreenOrigin(pNewScreen)->y - KdScreenOrigin(pScreen)->y; - if (*x < 0) - { - if (dx <= 0 && -dx < best_x) - { - best_x = -dx; - n_best_x = n; - } - } - else if (*x >= pScreen->width) - { - if (dx >= 0 && dx < best_x) - { - best_x = dx; - n_best_x = n; - } - } - if (*y < 0) - { - if (dy <= 0 && -dy < best_y) - { - best_y = -dy; - n_best_y = n; - } - } - else if (*y >= pScreen->height) - { - if (dy >= 0 && dy < best_y) - { - best_y = dy; - n_best_y = n; - } - } - } - if (best_y < best_x) - n_best_x = n_best_y; - if (n_best_x == -1) - return FALSE; - pNewScreen = screenInfo.screens[n_best_x]; - - if (*x < 0) - *x += pNewScreen->width; - if (*y < 0) - *y += pNewScreen->height; - - if (*x >= pScreen->width) - *x -= pScreen->width; - if (*y >= pScreen->height) - *y -= pScreen->height; - - *ppScreen = pNewScreen; - return TRUE; -} - -static void -KdCrossScreen(ScreenPtr pScreen, Bool entering) -{ -#ifndef XIPAQ - if (entering) - KdEnableScreen (pScreen); - else - KdDisableScreen (pScreen); -#endif -} - -int KdCurScreen; /* current event screen */ - -static void -KdWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - KdBlockSigio (); - KdCurScreen = pScreen->myNum; - miPointerWarpCursor(pDev, pScreen, x, y); - KdUnblockSigio (); -} - -miPointerScreenFuncRec kdPointerScreenFuncs = -{ - KdCursorOffScreen, - KdCrossScreen, - KdWarpCursor -}; - -void -ProcessInputEvents (void) -{ - mieqProcessInputEvents(); - miPointerUpdateSprite(inputInfo.pointer); - if (kdSwitchPending) - KdProcessSwitch (); - KdCheckLock (); -} - -/* FIXME use XSECURITY to work out whether the client should be allowed to - * open and close. */ -void -OpenInputDevice(DeviceIntPtr pDev, ClientPtr client, int *status) -{ - if (!pDev) - *status = BadDevice; - else - *status = Success; -} - -void -CloseInputDevice(DeviceIntPtr pDev, ClientPtr client) -{ - return; -} - -/* We initialise all input devices at startup. */ -void -AddOtherInputDevices(void) -{ - return; -} - -/* At the moment, absolute/relative is up to the client. */ -int -SetDeviceMode(register ClientPtr client, DeviceIntPtr pDev, int mode) -{ - return BadMatch; -} - -int -SetDeviceValuators(register ClientPtr client, DeviceIntPtr pDev, - int *valuators, int first_valuator, int num_valuators) -{ - return BadMatch; -} - -int -ChangeDeviceControl(register ClientPtr client, DeviceIntPtr pDev, - xDeviceCtl *control) -{ - switch (control->control) { - case DEVICE_RESOLUTION: - /* FIXME do something more intelligent here */ - return BadMatch; - - case DEVICE_ABS_CALIB: - case DEVICE_ABS_AREA: - return Success; - - case DEVICE_CORE: - return BadMatch; - case DEVICE_ENABLE: - return Success; - - default: - return BadMatch; - } - - /* NOTREACHED */ - return BadImplementation; -} - -int -NewInputDeviceRequest(InputOption *options, InputAttributes *attrs, - DeviceIntPtr *pdev) -{ - InputOption *option = NULL; - KdPointerInfo *pi = NULL; - KdKeyboardInfo *ki = NULL; - - for (option = options; option; option = option->next) { - if (strcmp(option->key, "type") == 0) { - if (strcmp(option->value, "pointer") == 0) { - pi = KdNewPointer(); - if (!pi) - return BadAlloc; - } - else if (strcmp(option->value, "keyboard") == 0) { - ki = KdNewKeyboard(); - if (!ki) - return BadAlloc; - } - else { - ErrorF("unrecognised device type!\n"); - return BadValue; - } - } -#ifdef CONFIG_HAL - else if (strcmp(option->key, "_source") == 0 && - strcmp(option->value, "server/hal") == 0) - { - ErrorF("Ignoring device from HAL.\n"); - return BadValue; - } -#endif -#ifdef CONFIG_UDEV - else if (strcmp(option->key, "_source") == 0 && - strcmp(option->value, "server/udev") == 0) - { - ErrorF("Ignoring device from udev.\n"); - return BadValue; - } -#endif - } - - if (!ki && !pi) { - ErrorF("unrecognised device identifier!\n"); - return BadValue; - } - - /* FIXME: change this code below to use KdParseKbdOptions and - * KdParsePointerOptions */ - for (option = options; option; option = option->next) { - if (strcmp(option->key, "device") == 0) { - if (pi && option->value) - pi->path = strdup(option->value); - else if (ki && option->value) - ki->path = strdup(option->value); - } - else if (strcmp(option->key, "driver") == 0) { - if (pi) { - pi->driver = KdFindPointerDriver(option->value); - if (!pi->driver) { - ErrorF("couldn't find driver!\n"); - KdFreePointer(pi); - return BadValue; - } - pi->options = options; - } - else if (ki) { - ki->driver = KdFindKeyboardDriver(option->value); - if (!ki->driver) { - ErrorF("couldn't find driver!\n"); - KdFreeKeyboard(ki); - return BadValue; - } - ki->options = options; - } - } - } - - if (pi) { - if (KdAddPointer(pi) != Success || - ActivateDevice(pi->dixdev, TRUE) != Success || - EnableDevice(pi->dixdev, TRUE) != TRUE) { - ErrorF("couldn't add or enable pointer\n"); - return BadImplementation; - } - } - else if (ki) { - if (KdAddKeyboard(ki) != Success || - ActivateDevice(ki->dixdev, TRUE) != Success || - EnableDevice(ki->dixdev, TRUE) != TRUE) { - ErrorF("couldn't add or enable keyboard\n"); - return BadImplementation; - } - } - - if (pi) { - *pdev = pi->dixdev; - } else if(ki) { - *pdev = ki->dixdev; - } - - return Success; -} - -void -DeleteInputDeviceRequest(DeviceIntPtr pDev) -{ - RemoveDevice(pDev, TRUE); -} +/* + * Copyright © 1999 Keith Packard + * Copyright © 2006 Nokia Corporation + * + * 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 the authors not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHORS 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" +#include "inputstr.h" + +#define XK_PUBLISHING +#include <X11/keysym.h> +#if HAVE_X11_XF86KEYSYM_H +#include <X11/XF86keysym.h> +#endif +#include <signal.h> +#include <stdio.h> +#ifdef sun +#include <sys/file.h> /* needed for FNONBLOCK & FASYNC */ +#endif + +#include "xkbsrv.h" + +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "XIstubs.h" /* even though we don't use stubs. cute, no? */ +#include "exevents.h" +#include "extinit.h" +#include "exglobals.h" +#include "eventstr.h" +#include "xserver-properties.h" + +#define AtomFromName(x) MakeAtom(x, strlen(x), 1) + +struct KdConfigDevice { + char *line; + struct KdConfigDevice *next; +}; + +/* kdKeyboards and kdPointers hold all the real devices. */ +static KdKeyboardInfo *kdKeyboards = NULL; +static KdPointerInfo *kdPointers = NULL; +static struct KdConfigDevice *kdConfigKeyboards = NULL; +static struct KdConfigDevice *kdConfigPointers = NULL; + +static KdKeyboardDriver *kdKeyboardDrivers = NULL; +static KdPointerDriver *kdPointerDrivers = NULL; + +static EventListPtr kdEvents = NULL; + +static Bool kdInputEnabled; +static Bool kdOffScreen; +static unsigned long kdOffScreenTime; +static KdPointerMatrix kdPointerMatrix = { + { { 1, 0, 0 }, + { 0, 1, 0 } } +}; + +void KdResetInputMachine (void); + +#define KD_MAX_INPUT_FDS 8 + +typedef struct _kdInputFd { + int fd; + void (*read) (int fd, void *closure); + int (*enable) (int fd, void *closure); + void (*disable) (int fd, void *closure); + void *closure; +} KdInputFd; + +static KdInputFd kdInputFds[KD_MAX_INPUT_FDS]; +static int kdNumInputFds; + +extern Bool kdRawPointerCoordinates; + +static void +KdSigio (int sig) +{ + int i; + + for (i = 0; i < kdNumInputFds; i++) + (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); +} + +static void +KdBlockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_BLOCK, &set, 0); +} + +static void +KdUnblockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_UNBLOCK, &set, 0); +} + +#ifdef DEBUG_SIGIO + +void +KdAssertSigioBlocked (char *where) +{ + sigset_t set, old; + + sigemptyset (&set); + sigprocmask (SIG_BLOCK, &set, &old); + if (!sigismember (&old, SIGIO)) { + ErrorF ("SIGIO not blocked at %s\n", where); + KdBacktrace(0); + } +} + +#else + +#define KdAssertSigioBlocked(s) + +#endif + +static int kdnFds; + +#ifdef FNONBLOCK +#define NOBLOCK FNONBLOCK +#else +#define NOBLOCK FNDELAY +#endif + +void +KdResetInputMachine (void) +{ + KdPointerInfo *pi; + + for (pi = kdPointers; pi; pi = pi->next) { + pi->mouseState = start; + pi->eventHeld = FALSE; + } +} + +static void +KdNonBlockFd (int fd) +{ + int flags; + flags = fcntl (fd, F_GETFL); + flags |= FASYNC|NOBLOCK; + fcntl (fd, F_SETFL, flags); +} + +static void +KdAddFd (int fd) +{ + struct sigaction act; + sigset_t set; + + kdnFds++; + fcntl (fd, F_SETOWN, getpid()); + KdNonBlockFd (fd); + AddEnabledDevice (fd); + memset (&act, '\0', sizeof act); + act.sa_handler = KdSigio; + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGIO); + sigaddset (&act.sa_mask, SIGALRM); + sigaddset (&act.sa_mask, SIGVTALRM); + sigaction (SIGIO, &act, 0); + sigemptyset (&set); + sigprocmask (SIG_SETMASK, &set, 0); +} + +static void +KdRemoveFd (int fd) +{ + struct sigaction act; + int flags; + + kdnFds--; + RemoveEnabledDevice (fd); + flags = fcntl (fd, F_GETFL); + flags &= ~(FASYNC|NOBLOCK); + fcntl (fd, F_SETFL, flags); + if (kdnFds == 0) + { + memset (&act, '\0', sizeof act); + act.sa_handler = SIG_IGN; + sigemptyset (&act.sa_mask); + sigaction (SIGIO, &act, 0); + } +} + +Bool +KdRegisterFd (int fd, void (*read) (int fd, void *closure), void *closure) +{ + if (kdNumInputFds == KD_MAX_INPUT_FDS) + return FALSE; + kdInputFds[kdNumInputFds].fd = fd; + kdInputFds[kdNumInputFds].read = read; + kdInputFds[kdNumInputFds].enable = 0; + kdInputFds[kdNumInputFds].disable = 0; + kdInputFds[kdNumInputFds].closure = closure; + kdNumInputFds++; + if (kdInputEnabled) + KdAddFd (fd); + return TRUE; +} + +void +KdUnregisterFd (void *closure, int fd, Bool do_close) +{ + int i, j; + + for (i = 0; i < kdNumInputFds; i++) { + if (kdInputFds[i].closure == closure && + (fd == -1 || kdInputFds[i].fd == fd)) { + if (kdInputEnabled) + KdRemoveFd (kdInputFds[i].fd); + if (do_close) + close (kdInputFds[i].fd); + kdNumInputFds--; + for (j = i; j < kdNumInputFds; j++) + kdInputFds[j] = kdInputFds[j+1]; + break; + } + } +} + +void +KdUnregisterFds (void *closure, Bool do_close) +{ + KdUnregisterFd(closure, -1, do_close); +} + +void +KdDisableInput (void) +{ + KdKeyboardInfo *ki; + KdPointerInfo *pi; + int found = 0, i = 0; + + KdBlockSigio(); + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->driver && ki->driver->Disable) + (*ki->driver->Disable) (ki); + } + + for (pi = kdPointers; pi; pi = pi->next) { + if (pi->driver && pi->driver->Disable) + (*pi->driver->Disable) (pi); + } + + if (kdNumInputFds) { + ErrorF("[KdDisableInput] Buggy drivers: still %d input fds left!", + kdNumInputFds); + i = 0; + while (i < kdNumInputFds) { + found = 0; + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki == kdInputFds[i].closure) { + ErrorF(" fd %d belongs to keybd driver %s\n", + kdInputFds[i].fd, + ki->driver && ki->driver->name ? + ki->driver->name : "(unnamed!)"); + found = 1; + break; + } + } + + if (found) { + i++; + continue; + } + + for (pi = kdPointers; pi; pi = pi->next) { + if (pi == kdInputFds[i].closure) { + ErrorF(" fd %d belongs to pointer driver %s\n", + kdInputFds[i].fd, + pi->driver && pi->driver->name ? + pi->driver->name : "(unnamed!)"); + break; + } + } + + if (found) { + i++; + continue; + } + + ErrorF(" fd %d not claimed by any active device!\n", + kdInputFds[i].fd); + KdUnregisterFd(kdInputFds[i].closure, kdInputFds[i].fd, TRUE); + } + } + + kdInputEnabled = FALSE; +} + +void +KdEnableInput (void) +{ + InternalEvent ev; + KdKeyboardInfo *ki; + KdPointerInfo *pi; + + kdInputEnabled = TRUE; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->driver && ki->driver->Enable) + (*ki->driver->Enable) (ki); + } + + for (pi = kdPointers; pi; pi = pi->next) { + if (pi->driver && pi->driver->Enable) + (*pi->driver->Enable) (pi); + } + + /* reset screen saver */ + ev.any.time = GetTimeInMillis (); + NoticeEventTime (&ev); + + KdUnblockSigio (); +} + +static KdKeyboardDriver * +KdFindKeyboardDriver (char *name) +{ + KdKeyboardDriver *ret; + + /* ask a stupid question ... */ + if (!name) + return NULL; + + for (ret = kdKeyboardDrivers; ret; ret = ret->next) { + if (strcmp(ret->name, name) == 0) + return ret; + } + + return NULL; +} + +static KdPointerDriver * +KdFindPointerDriver (char *name) +{ + KdPointerDriver *ret; + + /* ask a stupid question ... */ + if (!name) + return NULL; + + for (ret = kdPointerDrivers; ret; ret = ret->next) { + if (strcmp(ret->name, name) == 0) + return ret; + } + + return NULL; +} + +static int +KdPointerProc(DeviceIntPtr pDevice, int onoff) +{ + DevicePtr pDev = (DevicePtr)pDevice; + KdPointerInfo *pi; + Atom xiclass; + Atom *btn_labels; + Atom *axes_labels; + + if (!pDev) + return BadImplementation; + + for (pi = kdPointers; pi; pi = pi->next) { + if (pi->dixdev && pi->dixdev->id == pDevice->id) + break; + } + + if (!pi || !pi->dixdev || pi->dixdev->id != pDevice->id) { + ErrorF("[KdPointerProc] Failed to find pointer for device %d!\n", + pDevice->id); + return BadImplementation; + } + + switch (onoff) + { + case DEVICE_INIT: +#ifdef DEBUG + ErrorF("initialising pointer %s ...\n", pi->name); +#endif + if (!pi->driver) { + if (!pi->driverPrivate) { + ErrorF("no driver specified for %s\n", pi->name); + return BadImplementation; + } + + pi->driver = KdFindPointerDriver(pi->driverPrivate); + if (!pi->driver) { + ErrorF("Couldn't find pointer driver %s\n", + pi->driverPrivate ? (char *) pi->driverPrivate : + "(unnamed)"); + return !Success; + } + free(pi->driverPrivate); + pi->driverPrivate = NULL; + } + + if (!pi->driver->Init) { + ErrorF("no init function\n"); + return BadImplementation; + } + + if ((*pi->driver->Init) (pi) != Success) { + return !Success; + } + + btn_labels = calloc(pi->nButtons, sizeof(Atom)); + if (!btn_labels) + return BadAlloc; + axes_labels = calloc(pi->nAxes, sizeof(Atom)); + if (!axes_labels) { + free(btn_labels); + return BadAlloc; + } + + switch(pi->nAxes) + { + default: + case 7: + btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); + case 6: + btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); + case 5: + btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); + case 4: + btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); + case 3: + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + case 2: + btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); + case 1: + btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); + case 0: + break; + } + + if (pi->nAxes >= 2) { + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); + } + + InitPointerDeviceStruct(pDev, pi->map, pi->nButtons, btn_labels, + (PtrCtrlProcPtr)NoopDDA, + GetMotionHistorySize(), pi->nAxes, axes_labels); + + free(btn_labels); + free(axes_labels); + + if (pi->inputClass == KD_TOUCHSCREEN) { + InitAbsoluteClassDeviceStruct(pDevice); + xiclass = AtomFromName(XI_TOUCHSCREEN); + } + else { + xiclass = AtomFromName(XI_MOUSE); + } + + AssignTypeAndName(pi->dixdev, xiclass, + pi->name ? pi->name : "Generic KDrive Pointer"); + + return Success; + + case DEVICE_ON: + if (pDev->on == TRUE) + return Success; + + if (!pi->driver->Enable) { + ErrorF("no enable function\n"); + return BadImplementation; + } + + if ((*pi->driver->Enable) (pi) == Success) { + pDev->on = TRUE; + return Success; + } + else { + return BadImplementation; + } + + return Success; + + case DEVICE_OFF: + if (pDev->on == FALSE) { + return Success; + } + + if (!pi->driver->Disable) { + return BadImplementation; + } + else { + (*pi->driver->Disable) (pi); + pDev->on = FALSE; + return Success; + } + + return Success; + + case DEVICE_CLOSE: + if (pDev->on) { + if (!pi->driver->Disable) { + return BadImplementation; + } + (*pi->driver->Disable) (pi); + pDev->on = FALSE; + } + + if (!pi->driver->Fini) + return BadImplementation; + + (*pi->driver->Fini) (pi); + + KdRemovePointer(pi); + + return Success; + } + + /* NOTREACHED */ + return BadImplementation; +} + +Bool +LegalModifier(unsigned int key, DeviceIntPtr pDev) +{ + return TRUE; +} + +static void +KdBell (int volume, DeviceIntPtr pDev, pointer arg, int something) +{ + KeybdCtrl *ctrl = arg; + KdKeyboardInfo *ki = NULL; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDev->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) + return; + + KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); +} + +void +DDXRingBell(int volume, int pitch, int duration) +{ + KdKeyboardInfo *ki = NULL; + + if (kdOsFuncs->Bell) { + (*kdOsFuncs->Bell)(volume, pitch, duration); + } + else { + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev->coreEvents) + KdRingBell(ki, volume, pitch, duration); + } + } +} + +void +KdRingBell(KdKeyboardInfo *ki, int volume, int pitch, int duration) +{ + if (!ki || !ki->driver || !ki->driver->Bell) + return; + + if (kdInputEnabled) + (*ki->driver->Bell) (ki, volume, pitch, duration); +} + + +static void +KdSetLeds (KdKeyboardInfo *ki, int leds) +{ + if (!ki || !ki->driver) + return; + + if (kdInputEnabled) { + if (ki->driver->Leds) + (*ki->driver->Leds) (ki, leds); + } +} + +void +KdSetLed (KdKeyboardInfo *ki, int led, Bool on) +{ + if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed) + return; + + NoteLedState (ki->dixdev, led, on); + KdSetLeds (ki, ki->dixdev->kbdfeed->ctrl.leds); +} + +void +KdSetPointerMatrix (KdPointerMatrix *matrix) +{ + kdPointerMatrix = *matrix; +} + +void +KdComputePointerMatrix (KdPointerMatrix *m, Rotation randr, int width, + int height) +{ + int x_dir = 1, y_dir = 1; + int i, j; + int size[2]; + + size[0] = width; size[1] = height; + if (randr & RR_Reflect_X) + x_dir = -1; + if (randr & RR_Reflect_Y) + y_dir = -1; + switch (randr & (RR_Rotate_All)) { + case RR_Rotate_0: + m->matrix[0][0] = x_dir; m->matrix[0][1] = 0; + m->matrix[1][0] = 0; m->matrix[1][1] = y_dir; + break; + case RR_Rotate_90: + m->matrix[0][0] = 0; m->matrix[0][1] = -x_dir; + m->matrix[1][0] = y_dir; m->matrix[1][1] = 0; + break; + case RR_Rotate_180: + m->matrix[0][0] = -x_dir; m->matrix[0][1] = 0; + m->matrix[1][0] = 0; m->matrix[1][1] = -y_dir; + break; + case RR_Rotate_270: + m->matrix[0][0] = 0; m->matrix[0][1] = x_dir; + m->matrix[1][0] = -y_dir; m->matrix[1][1] = 0; + break; + } + for (i = 0; i < 2; i++) + { + m->matrix[i][2] = 0; + for (j = 0 ; j < 2; j++) + if (m->matrix[i][j] < 0) + m->matrix[i][2] = size[j] - 1; + } +} + +void +KdScreenToPointerCoords (int *x, int *y) +{ + int (*m)[3] = kdPointerMatrix.matrix; + int div = m[0][1] * m[1][0] - m[1][1] * m[0][0]; + int sx = *x; + int sy = *y; + + *x = (m[0][1] * sy - m[0][1] * m[1][2] + m[1][1] * m[0][2] - m[1][1] * sx) / div; + *y = (m[1][0] * sx + m[0][0] * m[1][2] - m[1][0] * m[0][2] - m[0][0] * sy) / div; +} + +static void +KdKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ + KdKeyboardInfo *ki; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDevice->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) + return; + + KdSetLeds(ki, ctrl->leds); + ki->bellPitch = ctrl->bell_pitch; + ki->bellDuration = ctrl->bell_duration; +} + +extern KeybdCtrl defaultKeyboardControl; + +static int +KdKeyboardProc(DeviceIntPtr pDevice, int onoff) +{ + Bool ret; + DevicePtr pDev = (DevicePtr)pDevice; + KdKeyboardInfo *ki; + Atom xiclass; + XkbRMLVOSet rmlvo; + + if (!pDev) + return BadImplementation; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDevice->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id) { + return BadImplementation; + } + + switch (onoff) + { + case DEVICE_INIT: +#ifdef DEBUG + ErrorF("initialising keyboard %s\n", ki->name); +#endif + if (!ki->driver) { + if (!ki->driverPrivate) { + ErrorF("no driver specified!\n"); + return BadImplementation; + } + + ki->driver = KdFindKeyboardDriver(ki->driverPrivate); + if (!ki->driver) { + ErrorF("Couldn't find keyboard driver %s\n", + ki->driverPrivate ? (char *) ki->driverPrivate : + "(unnamed)"); + return !Success; + } + free(ki->driverPrivate); + ki->driverPrivate = NULL; + } + + if (!ki->driver->Init) { + ErrorF("Keyboard %s: no init function\n", ki->name); + return BadImplementation; + } + + if ((*ki->driver->Init) (ki) != Success) { + return !Success; + } + + memset(&rmlvo, 0, sizeof(rmlvo)); + rmlvo.rules = ki->xkbRules; + rmlvo.model = ki->xkbModel; + rmlvo.layout = ki->xkbLayout; + rmlvo.variant = ki->xkbVariant; + rmlvo.options = ki->xkbOptions; + ret = InitKeyboardDeviceStruct (pDevice, &rmlvo, KdBell, KdKbdCtrl); + if (!ret) { + ErrorF("Couldn't initialise keyboard %s\n", ki->name); + return BadImplementation; + } + + xiclass = AtomFromName(XI_KEYBOARD); + AssignTypeAndName(pDevice, xiclass, + ki->name ? ki->name : "Generic KDrive Keyboard"); + + KdResetInputMachine(); + + return Success; + + case DEVICE_ON: + if (pDev->on == TRUE) + return Success; + + if (!ki->driver->Enable) + return BadImplementation; + + if ((*ki->driver->Enable) (ki) != Success) { + return BadMatch; + } + + pDev->on = TRUE; + return Success; + + case DEVICE_OFF: + if (pDev->on == FALSE) + return Success; + + if (!ki->driver->Disable) + return BadImplementation; + + (*ki->driver->Disable) (ki); + pDev->on = FALSE; + + return Success; + + break; + + case DEVICE_CLOSE: + if (pDev->on) { + if (!ki->driver->Disable) + return BadImplementation; + + (*ki->driver->Disable) (ki); + pDev->on = FALSE; + } + + if (!ki->driver->Fini) + return BadImplementation; + + (*ki->driver->Fini) (ki); + + KdRemoveKeyboard(ki); + + return Success; + } + + /* NOTREACHED */ + return BadImplementation; +} + +void +KdAddPointerDriver (KdPointerDriver *driver) +{ + KdPointerDriver **prev; + + if (!driver) + return; + + for (prev = &kdPointerDrivers; *prev; prev = &(*prev)->next) { + if (*prev == driver) + return; + } + *prev = driver; +} + +void +KdRemovePointerDriver (KdPointerDriver *driver) +{ + KdPointerDriver *tmp; + + if (!driver) + return; + + /* FIXME remove all pointers using this driver */ + for (tmp = kdPointerDrivers; tmp; tmp = tmp->next) { + if (tmp->next == driver) + tmp->next = driver->next; + } + if (tmp == driver) + tmp = NULL; +} + +void +KdAddKeyboardDriver (KdKeyboardDriver *driver) +{ + KdKeyboardDriver **prev; + + if (!driver) + return; + + for (prev = &kdKeyboardDrivers; *prev; prev = &(*prev)->next) { + if (*prev == driver) + return; + } + *prev = driver; +} + +void +KdRemoveKeyboardDriver (KdKeyboardDriver *driver) +{ + KdKeyboardDriver *tmp; + + if (!driver) + return; + + /* FIXME remove all keyboards using this driver */ + for (tmp = kdKeyboardDrivers; tmp; tmp = tmp->next) { + if (tmp->next == driver) + tmp->next = driver->next; + } + if (tmp == driver) + tmp = NULL; +} + +KdKeyboardInfo * +KdNewKeyboard (void) +{ + KdKeyboardInfo *ki = calloc(sizeof(KdKeyboardInfo), 1); + if (!ki) + return NULL; + + ki->minScanCode = 0; + ki->maxScanCode = 0; + ki->leds = 0; + ki->bellPitch = 1000; + ki->bellDuration = 200; + ki->next = NULL; + ki->options = NULL; + ki->xkbRules = strdup(XKB_DFLT_RULES); + ki->xkbModel = strdup(XKB_DFLT_MODEL); + ki->xkbLayout = strdup(XKB_DFLT_LAYOUT); + ki->xkbVariant = strdup(XKB_DFLT_VARIANT); + ki->xkbOptions = strdup(XKB_DFLT_OPTIONS); + + return ki; +} + +int +KdAddConfigKeyboard (char *keyboard) +{ + struct KdConfigDevice **prev, *new; + + if (!keyboard) + return Success; + + new = (struct KdConfigDevice *) calloc(sizeof(struct KdConfigDevice), 1); + if (!new) + return BadAlloc; + + new->line = xstrdup(keyboard); + new->next = NULL; + + for (prev = &kdConfigKeyboards; *prev; prev = &(*prev)->next); + *prev = new; + + return Success; +} + +int +KdAddKeyboard (KdKeyboardInfo *ki) +{ + KdKeyboardInfo **prev; + + if (!ki) + return !Success; + + ki->dixdev = AddInputDevice(serverClient, KdKeyboardProc, TRUE); + if (!ki->dixdev) { + ErrorF("Couldn't register keyboard device %s\n", + ki->name ? ki->name : "(unnamed)"); + return !Success; + } + + ki->dixdev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; + ki->dixdev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; + RegisterOtherDevice(ki->dixdev); + +#ifdef DEBUG + ErrorF("added keyboard %s with dix id %d\n", ki->name, ki->dixdev->id); +#endif + + for (prev = &kdKeyboards; *prev; prev = &(*prev)->next); + *prev = ki; + + return Success; +} + +void +KdRemoveKeyboard (KdKeyboardInfo *ki) +{ + KdKeyboardInfo **prev; + + if (!ki) + return; + + for (prev = &kdKeyboards; *prev; prev = &(*prev)->next) { + if (*prev == ki) { + *prev = ki->next; + break; + } + } + + KdFreeKeyboard(ki); +} + +int +KdAddConfigPointer (char *pointer) +{ + struct KdConfigDevice **prev, *new; + + if (!pointer) + return Success; + + new = (struct KdConfigDevice *) calloc(sizeof(struct KdConfigDevice), 1); + if (!new) + return BadAlloc; + + new->line = xstrdup(pointer); + new->next = NULL; + + for (prev = &kdConfigPointers; *prev; prev = &(*prev)->next); + *prev = new; + + return Success; +} + +int +KdAddPointer (KdPointerInfo *pi) +{ + KdPointerInfo **prev; + + if (!pi) + return Success; + + pi->mouseState = start; + pi->eventHeld = FALSE; + + pi->dixdev = AddInputDevice(serverClient, KdPointerProc, TRUE); + if (!pi->dixdev) { + ErrorF("Couldn't add pointer device %s\n", + pi->name ? pi->name : "(unnamed)"); + return BadDevice; + } + + pi->dixdev->deviceGrab.ActivateGrab = ActivatePointerGrab; + pi->dixdev->deviceGrab.DeactivateGrab = DeactivatePointerGrab; + RegisterOtherDevice(pi->dixdev); + + for (prev = &kdPointers; *prev; prev = &(*prev)->next); + *prev = pi; + + return Success; +} + +void +KdRemovePointer (KdPointerInfo *pi) +{ + KdPointerInfo **prev; + + if (!pi) + return; + + for (prev = &kdPointers; *prev; prev = &(*prev)->next) { + if (*prev == pi) { + *prev = pi->next; + break; + } + } + + KdFreePointer(pi); +} + +/* + * You can call your kdriver server with something like: + * $ ./hw/kdrive/yourserver/X :1 -mouse evdev,,device=/dev/input/event4 -keybd + * evdev,,device=/dev/input/event1,xkbmodel=abnt2,xkblayout=br + */ +static Bool +KdGetOptions (InputOption **options, char *string) +{ + InputOption *newopt = NULL, **tmpo = NULL; + int tam_key = 0; + + newopt = calloc(1, sizeof (InputOption)); + if (!newopt) + return FALSE; + + for (tmpo = options; *tmpo; tmpo = &(*tmpo)->next) + ; /* Hello, I'm here */ + *tmpo = newopt; + + if (strchr(string, '=')) + { + tam_key = (strchr(string, '=') - string); + newopt->key = (char *)malloc(tam_key); + strncpy(newopt->key, string, tam_key); + newopt->key[tam_key] = '\0'; + newopt->value = xstrdup(strchr(string, '=') + 1); + } + else + { + newopt->key = xstrdup(string); + newopt->value = NULL; + } + newopt->next = NULL; + + return TRUE; +} + +static void +KdParseKbdOptions (KdKeyboardInfo *ki) +{ + InputOption *option = NULL; + + for (option = ki->options; option; option = option->next) + { + if (strcasecmp(option->key, "XkbRules") == 0) + ki->xkbRules = option->value; + else if (strcasecmp(option->key, "XkbModel") == 0) + ki->xkbModel = option->value; + else if (strcasecmp(option->key, "XkbLayout") == 0) + ki->xkbLayout = option->value; + else if (strcasecmp(option->key, "XkbVariant") == 0) + ki->xkbVariant = option->value; + else if (strcasecmp(option->key, "XkbOptions") == 0) + ki->xkbOptions = option->value; + else if (!strcasecmp (option->key, "device")) + ki->path = strdup(option->value); + else + ErrorF("Kbd option key (%s) of value (%s) not assigned!\n", + option->key, option->value); + } +} + +KdKeyboardInfo * +KdParseKeyboard (char *arg) +{ + char save[1024]; + char delim; + InputOption *options = NULL; + KdKeyboardInfo *ki = NULL; + + ki = KdNewKeyboard(); + if (!ki) + return NULL; + + ki->name = strdup("Unknown KDrive Keyboard"); + ki->path = NULL; + ki->driver = NULL; + ki->driverPrivate = NULL; + ki->next = NULL; + + if (!arg) + { + ErrorF("keybd: no arg\n"); + KdFreeKeyboard (ki); + return NULL; + } + + if (strlen (arg) >= sizeof (save)) + { + ErrorF("keybd: arg too long\n"); + KdFreeKeyboard (ki); + return NULL; + } + + arg = KdParseFindNext (arg, ",", save, &delim); + if (!save[0]) + { + ErrorF("keybd: failed on save[0]\n"); + KdFreeKeyboard (ki); + return NULL; + } + + if (strcmp (save, "auto") == 0) + ki->driverPrivate = NULL; + else + ki->driverPrivate = xstrdup(save); + + if (delim != ',') + { + return ki; + } + + arg = KdParseFindNext (arg, ",", save, &delim); + + while (delim == ',') + { + arg = KdParseFindNext (arg, ",", save, &delim); + + if (!KdGetOptions(&options, save)) + { + KdFreeKeyboard(ki); + return NULL; + } + } + + if (options) + { + ki->options = options; + KdParseKbdOptions(ki); + } + + return ki; +} + +static void +KdParsePointerOptions (KdPointerInfo *pi) +{ + InputOption *option = NULL; + + for (option = pi->options; option; option = option->next) + { + if (!strcmp (option->key, "emulatemiddle")) + pi->emulateMiddleButton = TRUE; + else if (!strcmp (option->key, "noemulatemiddle")) + pi->emulateMiddleButton = FALSE; + else if (!strcmp (option->key, "transformcoord")) + pi->transformCoordinates = TRUE; + else if (!strcmp (option->key, "rawcoord")) + pi->transformCoordinates = FALSE; + else if (!strcasecmp (option->key, "device")) + pi->path = strdup(option->value); + else if (!strcasecmp (option->key, "protocol")) + pi->protocol = strdup(option->value); + else + ErrorF("Pointer option key (%s) of value (%s) not assigned!\n", + option->key, option->value); + } +} + +KdPointerInfo * +KdParsePointer (char *arg) +{ + char save[1024]; + char delim; + KdPointerInfo *pi = NULL; + InputOption *options = NULL; + int i = 0; + + pi = KdNewPointer(); + if (!pi) + return NULL; + pi->emulateMiddleButton = kdEmulateMiddleButton; + pi->transformCoordinates = !kdRawPointerCoordinates; + pi->protocol = NULL; + pi->nButtons = 5; /* XXX should not be hardcoded */ + pi->inputClass = KD_MOUSE; + + if (!arg) + { + ErrorF("mouse: no arg\n"); + KdFreePointer (pi); + return NULL; + } + + if (strlen (arg) >= sizeof (save)) + { + ErrorF("mouse: arg too long\n"); + KdFreePointer (pi); + return NULL; + } + arg = KdParseFindNext (arg, ",", save, &delim); + if (!save[0]) + { + ErrorF("failed on save[0]\n"); + KdFreePointer (pi); + return NULL; + } + + if (strcmp(save, "auto") == 0) + pi->driverPrivate = NULL; + else + pi->driverPrivate = xstrdup(save); + + if (delim != ',') + { + return pi; + } + + arg = KdParseFindNext (arg, ",", save, &delim); + + while (delim == ',') + { + arg = KdParseFindNext (arg, ",", save, &delim); + if (save[0] == '{') + { + char *s = save + 1; + i = 0; + while (*s && *s != '}') + { + if ('1' <= *s && *s <= '0' + pi->nButtons) + pi->map[i] = *s - '0'; + else + UseMsg (); + s++; + } + } + else + { + if (!KdGetOptions(&options, save)) + { + KdFreePointer(pi); + return NULL; + } + } + } + + if (options) + { + pi->options = options; + KdParsePointerOptions(pi); + } + + return pi; +} + + +void +KdInitInput (void) +{ + KdPointerInfo *pi; + KdKeyboardInfo *ki; + struct KdConfigDevice *dev; + + kdInputEnabled = TRUE; + + for (dev = kdConfigPointers; dev; dev = dev->next) { + pi = KdParsePointer(dev->line); + if (!pi) + ErrorF("Failed to parse pointer\n"); + if (KdAddPointer(pi) != Success) + ErrorF("Failed to add pointer!\n"); + } + for (dev = kdConfigKeyboards; dev; dev = dev->next) { + ki = KdParseKeyboard(dev->line); + if (!ki) + ErrorF("Failed to parse keyboard\n"); + if (KdAddKeyboard(ki) != Success) + ErrorF("Failed to add keyboard!\n"); + } + + mieqInit(); +} + +/* + * Middle button emulation state machine + * + * Possible transitions: + * Button 1 press v1 + * Button 1 release ^1 + * Button 2 press v2 + * Button 2 release ^2 + * Button 3 press v3 + * Button 3 release ^3 + * Button other press vo + * Button other release ^o + * Mouse motion <> + * Keyboard event k + * timeout ... + * outside box <-> + * + * States: + * start + * button_1_pend + * button_1_down + * button_2_down + * button_3_pend + * button_3_down + * synthetic_2_down_13 + * synthetic_2_down_3 + * synthetic_2_down_1 + * + * Transition diagram + * + * start + * v1 -> (hold) (settimeout) button_1_pend + * ^1 -> (deliver) start + * v2 -> (deliver) button_2_down + * ^2 -> (deliever) start + * v3 -> (hold) (settimeout) button_3_pend + * ^3 -> (deliver) start + * vo -> (deliver) start + * ^o -> (deliver) start + * <> -> (deliver) start + * k -> (deliver) start + * + * button_1_pend (button 1 is down, timeout pending) + * ^1 -> (release) (deliver) start + * v2 -> (release) (deliver) button_1_down + * ^2 -> (release) (deliver) button_1_down + * v3 -> (cleartimeout) (generate v2) synthetic_2_down_13 + * ^3 -> (release) (deliver) button_1_down + * vo -> (release) (deliver) button_1_down + * ^o -> (release) (deliver) button_1_down + * <-> -> (release) (deliver) button_1_down + * <> -> (deliver) button_1_pend + * k -> (release) (deliver) button_1_down + * ... -> (release) button_1_down + * + * button_1_down (button 1 is down) + * ^1 -> (deliver) start + * v2 -> (deliver) button_1_down + * ^2 -> (deliver) button_1_down + * v3 -> (deliver) button_1_down + * ^3 -> (deliver) button_1_down + * vo -> (deliver) button_1_down + * ^o -> (deliver) button_1_down + * <> -> (deliver) button_1_down + * k -> (deliver) button_1_down + * + * button_2_down (button 2 is down) + * v1 -> (deliver) button_2_down + * ^1 -> (deliver) button_2_down + * ^2 -> (deliver) start + * v3 -> (deliver) button_2_down + * ^3 -> (deliver) button_2_down + * vo -> (deliver) button_2_down + * ^o -> (deliver) button_2_down + * <> -> (deliver) button_2_down + * k -> (deliver) button_2_down + * + * button_3_pend (button 3 is down, timeout pending) + * v1 -> (generate v2) synthetic_2_down + * ^1 -> (release) (deliver) button_3_down + * v2 -> (release) (deliver) button_3_down + * ^2 -> (release) (deliver) button_3_down + * ^3 -> (release) (deliver) start + * vo -> (release) (deliver) button_3_down + * ^o -> (release) (deliver) button_3_down + * <-> -> (release) (deliver) button_3_down + * <> -> (deliver) button_3_pend + * k -> (release) (deliver) button_3_down + * ... -> (release) button_3_down + * + * button_3_down (button 3 is down) + * v1 -> (deliver) button_3_down + * ^1 -> (deliver) button_3_down + * v2 -> (deliver) button_3_down + * ^2 -> (deliver) button_3_down + * ^3 -> (deliver) start + * vo -> (deliver) button_3_down + * ^o -> (deliver) button_3_down + * <> -> (deliver) button_3_down + * k -> (deliver) button_3_down + * + * synthetic_2_down_13 (button 1 and 3 are down) + * ^1 -> (generate ^2) synthetic_2_down_3 + * v2 -> synthetic_2_down_13 + * ^2 -> synthetic_2_down_13 + * ^3 -> (generate ^2) synthetic_2_down_1 + * vo -> (deliver) synthetic_2_down_13 + * ^o -> (deliver) synthetic_2_down_13 + * <> -> (deliver) synthetic_2_down_13 + * k -> (deliver) synthetic_2_down_13 + * + * synthetic_2_down_3 (button 3 is down) + * v1 -> (deliver) synthetic_2_down_3 + * ^1 -> (deliver) synthetic_2_down_3 + * v2 -> synthetic_2_down_3 + * ^2 -> synthetic_2_down_3 + * ^3 -> start + * vo -> (deliver) synthetic_2_down_3 + * ^o -> (deliver) synthetic_2_down_3 + * <> -> (deliver) synthetic_2_down_3 + * k -> (deliver) synthetic_2_down_3 + * + * synthetic_2_down_1 (button 1 is down) + * ^1 -> start + * v2 -> synthetic_2_down_1 + * ^2 -> synthetic_2_down_1 + * v3 -> (deliver) synthetic_2_down_1 + * ^3 -> (deliver) synthetic_2_down_1 + * vo -> (deliver) synthetic_2_down_1 + * ^o -> (deliver) synthetic_2_down_1 + * <> -> (deliver) synthetic_2_down_1 + * k -> (deliver) synthetic_2_down_1 + */ + +typedef enum _inputClass { + down_1, up_1, + down_2, up_2, + down_3, up_3, + down_o, up_o, + motion, outside_box, + keyboard, timeout, + num_input_class +} KdInputClass; + +typedef enum _inputAction { + noop, + hold, + setto, + deliver, + release, + clearto, + gen_down_2, + gen_up_2 +} KdInputAction; + +#define MAX_ACTIONS 2 + +typedef struct _inputTransition { + KdInputAction actions[MAX_ACTIONS]; + KdPointerState nextState; +} KdInputTransition; + +static const +KdInputTransition kdInputMachine[num_input_states][num_input_class] = { + /* start */ + { + { { hold, setto }, button_1_pend }, /* v1 */ + { { deliver, noop }, start }, /* ^1 */ + { { deliver, noop }, button_2_down }, /* v2 */ + { { deliver, noop }, start }, /* ^2 */ + { { hold, setto }, button_3_pend }, /* v3 */ + { { deliver, noop }, start }, /* ^3 */ + { { deliver, noop }, start }, /* vo */ + { { deliver, noop }, start }, /* ^o */ + { { deliver, noop }, start }, /* <> */ + { { deliver, noop }, start }, /* <-> */ + { { noop, noop }, start }, /* k */ + { { noop, noop }, start }, /* ... */ + }, + /* button_1_pend */ + { + { { noop, noop }, button_1_pend }, /* v1 */ + { { release, deliver }, start }, /* ^1 */ + { { release, deliver }, button_1_down }, /* v2 */ + { { release, deliver }, button_1_down }, /* ^2 */ + { { clearto, gen_down_2 }, synth_2_down_13 }, /* v3 */ + { { release, deliver }, button_1_down }, /* ^3 */ + { { release, deliver }, button_1_down }, /* vo */ + { { release, deliver }, button_1_down }, /* ^o */ + { { deliver, noop }, button_1_pend }, /* <> */ + { { release, deliver }, button_1_down }, /* <-> */ + { { noop, noop }, button_1_down }, /* k */ + { { release, noop }, button_1_down }, /* ... */ + }, + /* button_1_down */ + { + { { noop, noop }, button_1_down }, /* v1 */ + { { deliver, noop }, start }, /* ^1 */ + { { deliver, noop }, button_1_down }, /* v2 */ + { { deliver, noop }, button_1_down }, /* ^2 */ + { { deliver, noop }, button_1_down }, /* v3 */ + { { deliver, noop }, button_1_down }, /* ^3 */ + { { deliver, noop }, button_1_down }, /* vo */ + { { deliver, noop }, button_1_down }, /* ^o */ + { { deliver, noop }, button_1_down }, /* <> */ + { { deliver, noop }, button_1_down }, /* <-> */ + { { noop, noop }, button_1_down }, /* k */ + { { noop, noop }, button_1_down }, /* ... */ + }, + /* button_2_down */ + { + { { deliver, noop }, button_2_down }, /* v1 */ + { { deliver, noop }, button_2_down }, /* ^1 */ + { { noop, noop }, button_2_down }, /* v2 */ + { { deliver, noop }, start }, /* ^2 */ + { { deliver, noop }, button_2_down }, /* v3 */ + { { deliver, noop }, button_2_down }, /* ^3 */ + { { deliver, noop }, button_2_down }, /* vo */ + { { deliver, noop }, button_2_down }, /* ^o */ + { { deliver, noop }, button_2_down }, /* <> */ + { { deliver, noop }, button_2_down }, /* <-> */ + { { noop, noop }, button_2_down }, /* k */ + { { noop, noop }, button_2_down }, /* ... */ + }, + /* button_3_pend */ + { + { { clearto, gen_down_2 }, synth_2_down_13 }, /* v1 */ + { { release, deliver }, button_3_down }, /* ^1 */ + { { release, deliver }, button_3_down }, /* v2 */ + { { release, deliver }, button_3_down }, /* ^2 */ + { { release, deliver }, button_3_down }, /* v3 */ + { { release, deliver }, start }, /* ^3 */ + { { release, deliver }, button_3_down }, /* vo */ + { { release, deliver }, button_3_down }, /* ^o */ + { { deliver, noop }, button_3_pend }, /* <> */ + { { release, deliver }, button_3_down }, /* <-> */ + { { release, noop }, button_3_down }, /* k */ + { { release, noop }, button_3_down }, /* ... */ + }, + /* button_3_down */ + { + { { deliver, noop }, button_3_down }, /* v1 */ + { { deliver, noop }, button_3_down }, /* ^1 */ + { { deliver, noop }, button_3_down }, /* v2 */ + { { deliver, noop }, button_3_down }, /* ^2 */ + { { noop, noop }, button_3_down }, /* v3 */ + { { deliver, noop }, start }, /* ^3 */ + { { deliver, noop }, button_3_down }, /* vo */ + { { deliver, noop }, button_3_down }, /* ^o */ + { { deliver, noop }, button_3_down }, /* <> */ + { { deliver, noop }, button_3_down }, /* <-> */ + { { noop, noop }, button_3_down }, /* k */ + { { noop, noop }, button_3_down }, /* ... */ + }, + /* synthetic_2_down_13 */ + { + { { noop, noop }, synth_2_down_13 }, /* v1 */ + { { gen_up_2, noop }, synth_2_down_3 }, /* ^1 */ + { { noop, noop }, synth_2_down_13 }, /* v2 */ + { { noop, noop }, synth_2_down_13 }, /* ^2 */ + { { noop, noop }, synth_2_down_13 }, /* v3 */ + { { gen_up_2, noop }, synth_2_down_1 }, /* ^3 */ + { { deliver, noop }, synth_2_down_13 }, /* vo */ + { { deliver, noop }, synth_2_down_13 }, /* ^o */ + { { deliver, noop }, synth_2_down_13 }, /* <> */ + { { deliver, noop }, synth_2_down_13 }, /* <-> */ + { { noop, noop }, synth_2_down_13 }, /* k */ + { { noop, noop }, synth_2_down_13 }, /* ... */ + }, + /* synthetic_2_down_3 */ + { + { { deliver, noop }, synth_2_down_3 }, /* v1 */ + { { deliver, noop }, synth_2_down_3 }, /* ^1 */ + { { deliver, noop }, synth_2_down_3 }, /* v2 */ + { { deliver, noop }, synth_2_down_3 }, /* ^2 */ + { { noop, noop }, synth_2_down_3 }, /* v3 */ + { { noop, noop }, start }, /* ^3 */ + { { deliver, noop }, synth_2_down_3 }, /* vo */ + { { deliver, noop }, synth_2_down_3 }, /* ^o */ + { { deliver, noop }, synth_2_down_3 }, /* <> */ + { { deliver, noop }, synth_2_down_3 }, /* <-> */ + { { noop, noop }, synth_2_down_3 }, /* k */ + { { noop, noop }, synth_2_down_3 }, /* ... */ + }, + /* synthetic_2_down_1 */ + { + { { noop, noop }, synth_2_down_1 }, /* v1 */ + { { noop, noop }, start }, /* ^1 */ + { { deliver, noop }, synth_2_down_1 }, /* v2 */ + { { deliver, noop }, synth_2_down_1 }, /* ^2 */ + { { deliver, noop }, synth_2_down_1 }, /* v3 */ + { { deliver, noop }, synth_2_down_1 }, /* ^3 */ + { { deliver, noop }, synth_2_down_1 }, /* vo */ + { { deliver, noop }, synth_2_down_1 }, /* ^o */ + { { deliver, noop }, synth_2_down_1 }, /* <> */ + { { deliver, noop }, synth_2_down_1 }, /* <-> */ + { { noop, noop }, synth_2_down_1 }, /* k */ + { { noop, noop }, synth_2_down_1 }, /* ... */ + }, +}; + +#define EMULATION_WINDOW 10 +#define EMULATION_TIMEOUT 100 + +static int +KdInsideEmulationWindow (KdPointerInfo *pi, int x, int y, int z) +{ + pi->emulationDx = pi->heldEvent.x - x; + pi->emulationDy = pi->heldEvent.y - y; + + return (abs (pi->emulationDx) < EMULATION_WINDOW && + abs (pi->emulationDy) < EMULATION_WINDOW); +} + +static KdInputClass +KdClassifyInput (KdPointerInfo *pi, int type, int x, int y, int z, int b) +{ + switch (type) { + case ButtonPress: + switch (b) { + case 1: return down_1; + case 2: return down_2; + case 3: return down_3; + default: return down_o; + } + break; + case ButtonRelease: + switch (b) { + case 1: return up_1; + case 2: return up_2; + case 3: return up_3; + default: return up_o; + } + break; + case MotionNotify: + if (pi->eventHeld && !KdInsideEmulationWindow(pi, x, y, z)) + return outside_box; + else + return motion; + default: + return keyboard; + } + return keyboard; +} + +#ifdef DEBUG +char *kdStateNames[] = { + "start", + "button_1_pend", + "button_1_down", + "button_2_down", + "button_3_pend", + "button_3_down", + "synth_2_down_13", + "synth_2_down_3", + "synthetic_2_down_1", + "num_input_states" +}; + +char *kdClassNames[] = { + "down_1", "up_1", + "down_2", "up_2", + "down_3", "up_3", + "motion", "ouside_box", + "keyboard", "timeout", + "num_input_class" +}; + +char *kdActionNames[] = { + "noop", + "hold", + "setto", + "deliver", + "release", + "clearto", + "gen_down_2", + "gen_up_2", +}; +#endif /* DEBUG */ + +static void +KdQueueEvent (DeviceIntPtr pDev, InternalEvent *ev) +{ + KdAssertSigioBlocked ("KdQueueEvent"); + mieqEnqueue (pDev, ev); +} + +/* We return true if we're stealing the event. */ +static Bool +KdRunMouseMachine (KdPointerInfo *pi, KdInputClass c, int type, int x, int y, + int z, int b, int absrel) +{ + const KdInputTransition *t; + int a; + + c = KdClassifyInput(pi, type, x, y, z, b); + t = &kdInputMachine[pi->mouseState][c]; + for (a = 0; a < MAX_ACTIONS; a++) + { + switch (t->actions[a]) { + case noop: + break; + case hold: + pi->eventHeld = TRUE; + pi->emulationDx = 0; + pi->emulationDy = 0; + pi->heldEvent.type = type; + pi->heldEvent.x = x; + pi->heldEvent.y = y; + pi->heldEvent.z = z; + pi->heldEvent.flags = b; + pi->heldEvent.absrel = absrel; + return TRUE; + break; + case setto: + pi->emulationTimeout = GetTimeInMillis () + EMULATION_TIMEOUT; + pi->timeoutPending = TRUE; + break; + case deliver: + _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x, + pi->heldEvent.y, pi->heldEvent.z, + pi->heldEvent.flags, pi->heldEvent.absrel, + TRUE); + break; + case release: + pi->eventHeld = FALSE; + pi->timeoutPending = FALSE; + _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x, + pi->heldEvent.y, pi->heldEvent.z, + pi->heldEvent.flags, pi->heldEvent.absrel, + TRUE); + return TRUE; + break; + case clearto: + pi->timeoutPending = FALSE; + break; + case gen_down_2: + _KdEnqueuePointerEvent (pi, ButtonPress, x, y, z, 2, absrel, + TRUE); + pi->eventHeld = FALSE; + return TRUE; + break; + case gen_up_2: + _KdEnqueuePointerEvent (pi, ButtonRelease, x, y, z, 2, absrel, + TRUE); + return TRUE; + break; + } + } + pi->mouseState = t->nextState; + return FALSE; +} + +static int +KdHandlePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z, int b, + int absrel) +{ + if (pi->emulateMiddleButton) + return KdRunMouseMachine (pi, KdClassifyInput(pi, type, x, y, z, b), + type, x, y, z, b, absrel); + return FALSE; +} + +static void +KdReceiveTimeout (KdPointerInfo *pi) +{ + KdRunMouseMachine (pi, timeout, 0, 0, 0, 0, 0, 0); +} + +/* + * kdCheckTermination + * + * This function checks for the key sequence that terminates the server. When + * detected, it sets the dispatchException flag and returns. The key sequence + * is: + * Control-Alt + * It's assumed that the server will be waken up by the caller when this + * function returns. + */ + +extern int nClients; + +void +KdReleaseAllKeys (void) +{ +#if 0 + int key, nEvents, i; + KdKeyboardInfo *ki; + + KdBlockSigio (); + + for (ki = kdKeyboards; ki; ki = ki->next) { + for (key = ki->keySyms.minKeyCode; key < ki->keySyms.maxKeyCode; + key++) { + if (key_is_down(ki->dixdev, key, KEY_POSTED | KEY_PROCESSED)) { + KdHandleKeyboardEvent(ki, KeyRelease, key); + GetEventList(&kdEvents); + nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, KeyRelease, key); + for (i = 0; i < nEvents; i++) + KdQueueEvent (ki->dixdev, (kdEvents + i)->event); + } + } + } + + KdUnblockSigio (); +#endif +} + +static void +KdCheckLock (void) +{ + KeyClassPtr keyc = NULL; + Bool isSet = FALSE, shouldBeSet = FALSE; + KdKeyboardInfo *tmp = NULL; + + for (tmp = kdKeyboards; tmp; tmp = tmp->next) { + if (tmp->LockLed && tmp->dixdev && tmp->dixdev->key) { + keyc = tmp->dixdev->key; + isSet = (tmp->leds & (1 << (tmp->LockLed-1))) != 0; + /* FIXME: Just use XKB indicators! */ + shouldBeSet = !!(XkbStateFieldFromRec(&keyc->xkbInfo->state) & LockMask); + if (isSet != shouldBeSet) + KdSetLed (tmp, tmp->LockLed, shouldBeSet); + } + } +} + +void +KdEnqueueKeyboardEvent(KdKeyboardInfo *ki, + unsigned char scan_code, + unsigned char is_up) +{ + unsigned char key_code; + KeyClassPtr keyc = NULL; + KeybdCtrl *ctrl = NULL; + int type, nEvents, i; + + if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed || !ki->dixdev->key) + return; + + keyc = ki->dixdev->key; + ctrl = &ki->dixdev->kbdfeed->ctrl; + + if (scan_code >= ki->minScanCode && scan_code <= ki->maxScanCode) + { + key_code = scan_code + KD_MIN_KEYCODE - ki->minScanCode; + + /* + * Set up this event -- the type may be modified below + */ + if (is_up) + type = KeyRelease; + else + type = KeyPress; + + GetEventList(&kdEvents); + + nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, type, key_code); + for (i = 0; i < nEvents; i++) + KdQueueEvent(ki->dixdev, (InternalEvent *)((kdEvents + i)->event)); + } + else { + ErrorF("driver %s wanted to post scancode %d outside of [%d, %d]!\n", + ki->name, scan_code, ki->minScanCode, ki->maxScanCode); + } +} + +/* + * kdEnqueuePointerEvent + * + * This function converts hardware mouse event information into X event + * information. A mouse movement event is passed off to MI to generate + * a MotionNotify event, if appropriate. Button events are created and + * passed off to MI for enqueueing. + */ + +/* FIXME do something a little more clever to deal with multiple axes here */ +void +KdEnqueuePointerEvent(KdPointerInfo *pi, unsigned long flags, int rx, int ry, + int rz) +{ + CARD32 ms; + unsigned char buttons; + int x, y, z; + int (*matrix)[3] = kdPointerMatrix.matrix; + unsigned long button; + int n; + int dixflags = 0; + + if (!pi) + return; + + ms = GetTimeInMillis(); + + /* we don't need to transform z, so we don't. */ + if (flags & KD_MOUSE_DELTA) { + if (pi->transformCoordinates) { + x = matrix[0][0] * rx + matrix[0][1] * ry; + y = matrix[1][0] * rx + matrix[1][1] * ry; + } + else { + x = rx; + y = ry; + } + } + else { + if (pi->transformCoordinates) { + x = matrix[0][0] * rx + matrix[0][1] * ry + matrix[0][2]; + y = matrix[1][0] * rx + matrix[1][1] * ry + matrix[1][2]; + } + else { + x = rx; + y = ry; + } + } + z = rz; + + if (flags & KD_MOUSE_DELTA) + { + if (x || y || z) + { + dixflags = POINTER_RELATIVE | POINTER_ACCELERATE; + _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE); + } + } else + { + dixflags = POINTER_ABSOLUTE; + if (x != pi->dixdev->last.valuators[0] || + y != pi->dixdev->last.valuators[1]) + _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE); + } + + buttons = flags; + + for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons; + button <<= 1, n++) { + if (((pi->buttonState & button) ^ (buttons & button)) && + !(buttons & button)) { + _KdEnqueuePointerEvent(pi, ButtonRelease, x, y, z, n, + dixflags, FALSE); + } + } + for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons; + button <<= 1, n++) { + if (((pi->buttonState & button) ^ (buttons & button)) && + (buttons & button)) { + _KdEnqueuePointerEvent(pi, ButtonPress, x, y, z, n, + dixflags, FALSE); + } + } + + pi->buttonState = buttons; +} + +void +_KdEnqueuePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z, + int b, int absrel, Bool force) +{ + int nEvents = 0, i = 0; + int valuators[3] = { x, y, z }; + + /* TRUE from KdHandlePointerEvent, means 'we swallowed the event'. */ + if (!force && KdHandlePointerEvent(pi, type, x, y, z, b, absrel)) + return; + + GetEventList(&kdEvents); + nEvents = GetPointerEvents(kdEvents, pi->dixdev, type, b, absrel, + 0, 3, valuators); + for (i = 0; i < nEvents; i++) + KdQueueEvent(pi->dixdev, (InternalEvent *)((kdEvents + i)->event)); +} + +void +KdBlockHandler (int screen, + pointer blockData, + pointer timeout, + pointer readmask) +{ + KdPointerInfo *pi; + int myTimeout=0; + + for (pi = kdPointers; pi; pi = pi->next) + { + if (pi->timeoutPending) + { + int ms; + + ms = pi->emulationTimeout - GetTimeInMillis (); + if (ms < 1) + ms = 1; + if(ms<myTimeout || myTimeout==0) + myTimeout=ms; + } + } + /* if we need to poll for events, do that */ + if(kdOsFuncs->pollEvents) + { + (*kdOsFuncs->pollEvents)(); + myTimeout=20; + } + if(myTimeout>0) + AdjustWaitForDelay (timeout, myTimeout); +} + +void +KdWakeupHandler (int screen, + pointer data, + unsigned long lresult, + pointer readmask) +{ + int result = (int) lresult; + fd_set *pReadmask = (fd_set *) readmask; + int i; + KdPointerInfo *pi; + + if (kdInputEnabled && result > 0) + { + for (i = 0; i < kdNumInputFds; i++) + if (FD_ISSET (kdInputFds[i].fd, pReadmask)) + { + KdBlockSigio (); + (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); + KdUnblockSigio (); + } + } + for (pi = kdPointers; pi; pi = pi->next) + { + if (pi->timeoutPending) + { + if ((long) (GetTimeInMillis () - pi->emulationTimeout) >= 0) + { + pi->timeoutPending = FALSE; + KdBlockSigio (); + KdReceiveTimeout (pi); + KdUnblockSigio (); + } + } + } + if (kdSwitchPending) + KdProcessSwitch (); +} + +#define KdScreenOrigin(pScreen) (&(KdGetScreenPriv(pScreen)->screen->origin)) + +static Bool +KdCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) +{ + ScreenPtr pScreen = *ppScreen; + ScreenPtr pNewScreen; + int n; + int dx, dy; + int best_x, best_y; + int n_best_x, n_best_y; + CARD32 ms; + + if (kdDisableZaphod || screenInfo.numScreens <= 1) + return FALSE; + + if (0 <= *x && *x < pScreen->width && 0 <= *y && *y < pScreen->height) + return FALSE; + + ms = GetTimeInMillis (); + if (kdOffScreen && (int) (ms - kdOffScreenTime) < 1000) + return FALSE; + kdOffScreen = TRUE; + kdOffScreenTime = ms; + n_best_x = -1; + best_x = 32767; + n_best_y = -1; + best_y = 32767; + for (n = 0; n < screenInfo.numScreens; n++) + { + pNewScreen = screenInfo.screens[n]; + if (pNewScreen == pScreen) + continue; + dx = KdScreenOrigin(pNewScreen)->x - KdScreenOrigin(pScreen)->x; + dy = KdScreenOrigin(pNewScreen)->y - KdScreenOrigin(pScreen)->y; + if (*x < 0) + { + if (dx <= 0 && -dx < best_x) + { + best_x = -dx; + n_best_x = n; + } + } + else if (*x >= pScreen->width) + { + if (dx >= 0 && dx < best_x) + { + best_x = dx; + n_best_x = n; + } + } + if (*y < 0) + { + if (dy <= 0 && -dy < best_y) + { + best_y = -dy; + n_best_y = n; + } + } + else if (*y >= pScreen->height) + { + if (dy >= 0 && dy < best_y) + { + best_y = dy; + n_best_y = n; + } + } + } + if (best_y < best_x) + n_best_x = n_best_y; + if (n_best_x == -1) + return FALSE; + pNewScreen = screenInfo.screens[n_best_x]; + + if (*x < 0) + *x += pNewScreen->width; + if (*y < 0) + *y += pNewScreen->height; + + if (*x >= pScreen->width) + *x -= pScreen->width; + if (*y >= pScreen->height) + *y -= pScreen->height; + + *ppScreen = pNewScreen; + return TRUE; +} + +static void +KdCrossScreen(ScreenPtr pScreen, Bool entering) +{ +#ifndef XIPAQ + if (entering) + KdEnableScreen (pScreen); + else + KdDisableScreen (pScreen); +#endif +} + +int KdCurScreen; /* current event screen */ + +static void +KdWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + KdBlockSigio (); + KdCurScreen = pScreen->myNum; + miPointerWarpCursor(pDev, pScreen, x, y); + KdUnblockSigio (); +} + +miPointerScreenFuncRec kdPointerScreenFuncs = +{ + KdCursorOffScreen, + KdCrossScreen, + KdWarpCursor +}; + +void +ProcessInputEvents (void) +{ + mieqProcessInputEvents(); + miPointerUpdateSprite(inputInfo.pointer); + if (kdSwitchPending) + KdProcessSwitch (); + KdCheckLock (); +} + +/* FIXME use XSECURITY to work out whether the client should be allowed to + * open and close. */ +void +OpenInputDevice(DeviceIntPtr pDev, ClientPtr client, int *status) +{ + if (!pDev) + *status = BadDevice; + else + *status = Success; +} + +void +CloseInputDevice(DeviceIntPtr pDev, ClientPtr client) +{ + return; +} + +/* We initialise all input devices at startup. */ +void +AddOtherInputDevices(void) +{ + return; +} + +/* At the moment, absolute/relative is up to the client. */ +int +SetDeviceMode(register ClientPtr client, DeviceIntPtr pDev, int mode) +{ + return BadMatch; +} + +int +SetDeviceValuators(register ClientPtr client, DeviceIntPtr pDev, + int *valuators, int first_valuator, int num_valuators) +{ + return BadMatch; +} + +int +ChangeDeviceControl(register ClientPtr client, DeviceIntPtr pDev, + xDeviceCtl *control) +{ + switch (control->control) { + case DEVICE_RESOLUTION: + /* FIXME do something more intelligent here */ + return BadMatch; + + case DEVICE_ABS_CALIB: + case DEVICE_ABS_AREA: + return Success; + + case DEVICE_CORE: + return BadMatch; + case DEVICE_ENABLE: + return Success; + + default: + return BadMatch; + } + + /* NOTREACHED */ + return BadImplementation; +} + +int +NewInputDeviceRequest(InputOption *options, InputAttributes *attrs, + DeviceIntPtr *pdev) +{ + InputOption *option = NULL; + KdPointerInfo *pi = NULL; + KdKeyboardInfo *ki = NULL; + + for (option = options; option; option = option->next) { + if (strcmp(option->key, "type") == 0) { + if (strcmp(option->value, "pointer") == 0) { + pi = KdNewPointer(); + if (!pi) + return BadAlloc; + } + else if (strcmp(option->value, "keyboard") == 0) { + ki = KdNewKeyboard(); + if (!ki) + return BadAlloc; + } + else { + ErrorF("unrecognised device type!\n"); + return BadValue; + } + } +#ifdef CONFIG_HAL + else if (strcmp(option->key, "_source") == 0 && + strcmp(option->value, "server/hal") == 0) + { + ErrorF("Ignoring device from HAL.\n"); + return BadValue; + } +#endif +#ifdef CONFIG_UDEV + else if (strcmp(option->key, "_source") == 0 && + strcmp(option->value, "server/udev") == 0) + { + ErrorF("Ignoring device from udev.\n"); + return BadValue; + } +#endif + } + + if (!ki && !pi) { + ErrorF("unrecognised device identifier!\n"); + return BadValue; + } + + /* FIXME: change this code below to use KdParseKbdOptions and + * KdParsePointerOptions */ + for (option = options; option; option = option->next) { + if (strcmp(option->key, "device") == 0) { + if (pi && option->value) + pi->path = strdup(option->value); + else if (ki && option->value) + ki->path = strdup(option->value); + } + else if (strcmp(option->key, "driver") == 0) { + if (pi) { + pi->driver = KdFindPointerDriver(option->value); + if (!pi->driver) { + ErrorF("couldn't find driver!\n"); + KdFreePointer(pi); + return BadValue; + } + pi->options = options; + } + else if (ki) { + ki->driver = KdFindKeyboardDriver(option->value); + if (!ki->driver) { + ErrorF("couldn't find driver!\n"); + KdFreeKeyboard(ki); + return BadValue; + } + ki->options = options; + } + } + } + + if (pi) { + if (KdAddPointer(pi) != Success || + ActivateDevice(pi->dixdev, TRUE) != Success || + EnableDevice(pi->dixdev, TRUE) != TRUE) { + ErrorF("couldn't add or enable pointer\n"); + return BadImplementation; + } + } + else if (ki) { + if (KdAddKeyboard(ki) != Success || + ActivateDevice(ki->dixdev, TRUE) != Success || + EnableDevice(ki->dixdev, TRUE) != TRUE) { + ErrorF("couldn't add or enable keyboard\n"); + return BadImplementation; + } + } + + if (pi) { + *pdev = pi->dixdev; + } else if(ki) { + *pdev = ki->dixdev; + } + + return Success; +} + +void +DeleteInputDeviceRequest(DeviceIntPtr pDev) +{ + RemoveDevice(pDev, TRUE); +} diff --git a/xorg-server/hw/kdrive/src/kshadow.c b/xorg-server/hw/kdrive/src/kshadow.c index cf3391dba..4454020f0 100644 --- a/xorg-server/hw/kdrive/src/kshadow.c +++ b/xorg-server/hw/kdrive/src/kshadow.c @@ -1,81 +1,81 @@ -/* - * Copyright © 1999 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include "kdrive.h" - -Bool -KdShadowFbAlloc (KdScreenInfo *screen, Bool rotate) -{ - int paddedWidth; - void *buf; - int width = rotate ? screen->height : screen->width; - int height = rotate ? screen->width : screen->height; - int bpp = screen->fb.bitsPerPixel; - - /* use fb computation for width */ - paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); - buf = xalloc (paddedWidth * height); - if (!buf) - return FALSE; - if (screen->fb.shadow) - xfree (screen->fb.frameBuffer); - screen->fb.shadow = TRUE; - screen->fb.frameBuffer = buf; - screen->fb.byteStride = paddedWidth; - screen->fb.pixelStride = paddedWidth * 8 / bpp; - return TRUE; -} - -void -KdShadowFbFree (KdScreenInfo *screen) -{ - if (screen->fb.shadow) - { - xfree (screen->fb.frameBuffer); - screen->fb.frameBuffer = 0; - screen->fb.shadow = FALSE; - } -} - -Bool -KdShadowSet (ScreenPtr pScreen, int randr, ShadowUpdateProc update, ShadowWindowProc window) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - - shadowRemove (pScreen, pScreen->GetScreenPixmap(pScreen)); - if(screen->fb.shadow) - { - return shadowAdd (pScreen, pScreen->GetScreenPixmap(pScreen), - update, window, randr, 0); - } - return TRUE; -} - -void -KdShadowUnset (ScreenPtr pScreen) -{ - shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen)); -} +/* + * Copyright © 1999 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" + +Bool +KdShadowFbAlloc (KdScreenInfo *screen, Bool rotate) +{ + int paddedWidth; + void *buf; + int width = rotate ? screen->height : screen->width; + int height = rotate ? screen->width : screen->height; + int bpp = screen->fb.bitsPerPixel; + + /* use fb computation for width */ + paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); + buf = malloc(paddedWidth * height); + if (!buf) + return FALSE; + if (screen->fb.shadow) + free(screen->fb.frameBuffer); + screen->fb.shadow = TRUE; + screen->fb.frameBuffer = buf; + screen->fb.byteStride = paddedWidth; + screen->fb.pixelStride = paddedWidth * 8 / bpp; + return TRUE; +} + +void +KdShadowFbFree (KdScreenInfo *screen) +{ + if (screen->fb.shadow) + { + free(screen->fb.frameBuffer); + screen->fb.frameBuffer = 0; + screen->fb.shadow = FALSE; + } +} + +Bool +KdShadowSet (ScreenPtr pScreen, int randr, ShadowUpdateProc update, ShadowWindowProc window) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + + shadowRemove (pScreen, pScreen->GetScreenPixmap(pScreen)); + if(screen->fb.shadow) + { + return shadowAdd (pScreen, pScreen->GetScreenPixmap(pScreen), + update, window, randr, 0); + } + return TRUE; +} + +void +KdShadowUnset (ScreenPtr pScreen) +{ + shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen)); +} diff --git a/xorg-server/hw/kdrive/src/kxv.c b/xorg-server/hw/kdrive/src/kxv.c index 27ecc5d6c..9fef34d1f 100644 --- a/xorg-server/hw/kdrive/src/kxv.c +++ b/xorg-server/hw/kdrive/src/kxv.c @@ -1,1907 +1,1907 @@ -/* - - XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com) - Adapted for KDrive by Pontus Lidman <pontus.lidman@nokia.com> - - Copyright (C) 2000, 2001 - Nokia Home Communications - Copyright (C) 1998, 1999 - 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, 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_CONFIG_H -#include <kdrive-config.h> -#endif -#include "kdrive.h" - -#include "scrnintstr.h" -#include "regionstr.h" -#include "windowstr.h" -#include "pixmapstr.h" -#include "mivalidate.h" -#include "validate.h" -#include "resource.h" -#include "gcstruct.h" -#include "dixstruct.h" - -#include <X11/extensions/Xv.h> -#include <X11/extensions/Xvproto.h> - -#include "kxv.h" -#include "fourcc.h" - - -/* XvScreenRec fields */ - -static Bool KdXVCloseScreen(int, ScreenPtr); -static int KdXVQueryAdaptors(ScreenPtr, XvAdaptorPtr *, int *); - -/* XvAdaptorRec fields */ - -static int KdXVAllocatePort(unsigned long, XvPortPtr, XvPortPtr*); -static int KdXVFreePort(XvPortPtr); -static int KdXVPutVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int KdXVPutStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int KdXVGetVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int KdXVGetStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int KdXVStopVideo(ClientPtr, XvPortPtr, DrawablePtr); -static int KdXVSetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32); -static int KdXVGetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32 *); -static int KdXVQueryBestSize(ClientPtr, XvPortPtr, CARD8, - CARD16, CARD16,CARD16, CARD16, - unsigned int*, unsigned int*); -static int KdXVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16, - XvImagePtr, unsigned char*, Bool, - CARD16, CARD16); -static int KdXVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr, - CARD16*, CARD16*, int*, int*); - - -/* ScreenRec fields */ - -static Bool KdXVCreateWindow(WindowPtr pWin); -static Bool KdXVDestroyWindow(WindowPtr pWin); -static void KdXVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2); -static void KdXVClipNotify(WindowPtr pWin, int dx, int dy); - -/* misc */ -static Bool KdXVInitAdaptors(ScreenPtr, KdVideoAdaptorPtr*, int); - -static int KdXVWindowKeyIndex; -DevPrivateKey KdXVWindowKey = &KdXVWindowKeyIndex; -static int KdXvScreenKeyIndex; -DevPrivateKey KdXvScreenKey = &KdXvScreenKeyIndex; -static unsigned long KdXVGeneration = 0; -static unsigned long PortResource = 0; - -DevPrivateKey (*XvGetScreenKeyProc)(void) = XvGetScreenKey; -unsigned long (*XvGetRTPortProc)(void) = XvGetRTPort; -int (*XvScreenInitProc)(ScreenPtr) = XvScreenInit; - -#define GET_XV_SCREEN(pScreen) ((XvScreenPtr) \ - dixLookupPrivate(&(pScreen)->devPrivates, KdXvScreenKey)) - -#define GET_KDXV_SCREEN(pScreen) \ - ((KdXVScreenPtr)(GET_XV_SCREEN(pScreen)->devPriv.ptr)) - -#define GET_KDXV_WINDOW(pWin) ((KdXVWindowPtr) \ - dixLookupPrivate(&(pWin)->devPrivates, KdXVWindowKey)) - -static KdXVInitGenericAdaptorPtr *GenDrivers = NULL; -static int NumGenDrivers = 0; - -int -KdXVRegisterGenericAdaptorDriver( - KdXVInitGenericAdaptorPtr InitFunc -){ - KdXVInitGenericAdaptorPtr *newdrivers; - -/* fprintf(stderr,"KdXVRegisterGenericAdaptorDriver\n"); */ - - newdrivers = xrealloc(GenDrivers, sizeof(KdXVInitGenericAdaptorPtr) * - (1 + NumGenDrivers)); - if (!newdrivers) - return 0; - GenDrivers = newdrivers; - - GenDrivers[NumGenDrivers++] = InitFunc; - - return 1; -} - -int -KdXVListGenericAdaptors( - KdScreenInfo * screen, - KdVideoAdaptorPtr **adaptors -){ - int i,j,n,num; - KdVideoAdaptorPtr *DrivAdap,*new; - - num = 0; - *adaptors = NULL; - for (i = 0; i < NumGenDrivers; i++) { - n = GenDrivers[i](screen,&DrivAdap); - if (0 == n) - continue; - new = xrealloc(*adaptors, sizeof(KdVideoAdaptorPtr) * (num+n)); - if (NULL == new) - continue; - *adaptors = new; - for (j = 0; j < n; j++, num++) - (*adaptors)[num] = DrivAdap[j]; - } - return num; -} - -KdVideoAdaptorPtr -KdXVAllocateVideoAdaptorRec(KdScreenInfo * screen) -{ - return xcalloc(1, sizeof(KdVideoAdaptorRec)); -} - -void -KdXVFreeVideoAdaptorRec(KdVideoAdaptorPtr ptr) -{ - xfree(ptr); -} - - -Bool -KdXVScreenInit( - ScreenPtr pScreen, - KdVideoAdaptorPtr *adaptors, - int num -){ - KdXVScreenPtr ScreenPriv; - XvScreenPtr pxvs; - -/* fprintf(stderr,"KdXVScreenInit initializing %d adaptors\n",num); */ - - if (KdXVGeneration != serverGeneration) - KdXVGeneration = serverGeneration; - - if(!XvGetScreenKeyProc || !XvGetRTPortProc || !XvScreenInitProc) - return FALSE; - - if(Success != (*XvScreenInitProc)(pScreen)) return FALSE; - - KdXvScreenKey = (*XvGetScreenKeyProc)(); - PortResource = (*XvGetRTPortProc)(); - - pxvs = GET_XV_SCREEN(pScreen); - - - /* Anyone initializing the Xv layer must provide these two. - The Xv di layer calls them without even checking if they exist! */ - - pxvs->ddCloseScreen = KdXVCloseScreen; - pxvs->ddQueryAdaptors = KdXVQueryAdaptors; - - /* The Xv di layer provides us with a private hook so that we don't - have to allocate our own screen private. They also provide - a CloseScreen hook so that we don't have to wrap it. I'm not - sure that I appreciate that. */ - - ScreenPriv = xalloc(sizeof(KdXVScreenRec)); - pxvs->devPriv.ptr = (pointer)ScreenPriv; - - if(!ScreenPriv) return FALSE; - - - ScreenPriv->CreateWindow = pScreen->CreateWindow; - ScreenPriv->DestroyWindow = pScreen->DestroyWindow; - ScreenPriv->WindowExposures = pScreen->WindowExposures; - ScreenPriv->ClipNotify = pScreen->ClipNotify; - -/* fprintf(stderr,"XV: Wrapping screen funcs\n"); */ - - pScreen->CreateWindow = KdXVCreateWindow; - pScreen->DestroyWindow = KdXVDestroyWindow; - pScreen->WindowExposures = KdXVWindowExposures; - pScreen->ClipNotify = KdXVClipNotify; - - if(!KdXVInitAdaptors(pScreen, adaptors, num)) - return FALSE; - - return TRUE; -} - -static void -KdXVFreeAdaptor(XvAdaptorPtr pAdaptor) -{ - int i; - - xfree(pAdaptor->name); - - if(pAdaptor->pEncodings) { - XvEncodingPtr pEncode = pAdaptor->pEncodings; - - for(i = 0; i < pAdaptor->nEncodings; i++, pEncode++) { - xfree(pEncode->name); - } - xfree(pAdaptor->pEncodings); - } - - xfree(pAdaptor->pFormats); - - if(pAdaptor->pPorts) { - XvPortPtr pPort = pAdaptor->pPorts; - XvPortRecPrivatePtr pPriv; - - for(i = 0; i < pAdaptor->nPorts; i++, pPort++) { - pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; - if(pPriv) { - if(pPriv->clientClip) - REGION_DESTROY(pAdaptor->pScreen, pPriv->clientClip); - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pAdaptor->pScreen, pPriv->pCompositeClip); - xfree(pPriv); - } - } - xfree(pAdaptor->pPorts); - } - - if(pAdaptor->nAttributes) { - XvAttributePtr pAttribute = pAdaptor->pAttributes; - - for(i = 0; i < pAdaptor->nAttributes; i++, pAttribute++) { - xfree(pAttribute->name); - } - - xfree(pAdaptor->pAttributes); - } - - xfree(pAdaptor->pImages); - - xfree(pAdaptor->devPriv.ptr); -} - -static Bool -KdXVInitAdaptors( - ScreenPtr pScreen, - KdVideoAdaptorPtr *infoPtr, - int number -) { - KdScreenPriv(pScreen); - KdScreenInfo * screen = pScreenPriv->screen; - - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - KdVideoAdaptorPtr adaptorPtr; - XvAdaptorPtr pAdaptor, pa; - XvAdaptorRecPrivatePtr adaptorPriv; - int na, numAdaptor; - XvPortRecPrivatePtr portPriv; - XvPortPtr pPort, pp; - int numPort; - KdAttributePtr attributePtr; - XvAttributePtr pAttribute, pat; - KdVideoFormatPtr formatPtr; - XvFormatPtr pFormat, pf; - int numFormat, totFormat; - KdVideoEncodingPtr encodingPtr; - XvEncodingPtr pEncode, pe; - KdImagePtr imagePtr; - XvImagePtr pImage, pi; - int numVisuals; - VisualPtr pVisual; - int i; - - pxvs->nAdaptors = 0; - pxvs->pAdaptors = NULL; - - if(!(pAdaptor = xcalloc(number, sizeof(XvAdaptorRec)))) - return FALSE; - - for(pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) { - adaptorPtr = infoPtr[na]; - - if(!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute || - !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize) - continue; - - /* client libs expect at least one encoding */ - if(!adaptorPtr->nEncodings || !adaptorPtr->pEncodings) - continue; - - pa->type = adaptorPtr->type; - - if(!adaptorPtr->PutVideo && !adaptorPtr->GetVideo) - pa->type &= ~XvVideoMask; - - if(!adaptorPtr->PutStill && !adaptorPtr->GetStill) - pa->type &= ~XvStillMask; - - if(!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes) - pa->type &= ~XvImageMask; - - if(!adaptorPtr->PutVideo && !adaptorPtr->PutImage && - !adaptorPtr->PutStill) - pa->type &= ~XvInputMask; - - if(!adaptorPtr->GetVideo && !adaptorPtr->GetStill) - pa->type &= ~XvOutputMask; - - if(!(adaptorPtr->type & (XvPixmapMask | XvWindowMask))) - continue; - if(!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask))) - continue; - - pa->pScreen = pScreen; - pa->ddAllocatePort = KdXVAllocatePort; - pa->ddFreePort = KdXVFreePort; - pa->ddPutVideo = KdXVPutVideo; - pa->ddPutStill = KdXVPutStill; - pa->ddGetVideo = KdXVGetVideo; - pa->ddGetStill = KdXVGetStill; - pa->ddStopVideo = KdXVStopVideo; - pa->ddPutImage = KdXVPutImage; - pa->ddSetPortAttribute = KdXVSetPortAttribute; - pa->ddGetPortAttribute = KdXVGetPortAttribute; - pa->ddQueryBestSize = KdXVQueryBestSize; - pa->ddQueryImageAttributes = KdXVQueryImageAttributes; - if((pa->name = xalloc(strlen(adaptorPtr->name) + 1))) - strcpy(pa->name, adaptorPtr->name); - - if(adaptorPtr->nEncodings && - (pEncode = xcalloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) { - - for(pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0; - i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) - { - pe->id = encodingPtr->id; - pe->pScreen = pScreen; - if((pe->name = xalloc(strlen(encodingPtr->name) + 1))) - strcpy(pe->name, encodingPtr->name); - pe->width = encodingPtr->width; - pe->height = encodingPtr->height; - pe->rate.numerator = encodingPtr->rate.numerator; - pe->rate.denominator = encodingPtr->rate.denominator; - } - pa->nEncodings = adaptorPtr->nEncodings; - pa->pEncodings = pEncode; - } - - if(adaptorPtr->nImages && - (pImage = xcalloc(adaptorPtr->nImages, sizeof(XvImageRec)))) { - - for(i = 0, pi = pImage, imagePtr = adaptorPtr->pImages; - i < adaptorPtr->nImages; i++, pi++, imagePtr++) - { - pi->id = imagePtr->id; - pi->type = imagePtr->type; - pi->byte_order = imagePtr->byte_order; - memcpy(pi->guid, imagePtr->guid, 16); - pi->bits_per_pixel = imagePtr->bits_per_pixel; - pi->format = imagePtr->format; - pi->num_planes = imagePtr->num_planes; - pi->depth = imagePtr->depth; - pi->red_mask = imagePtr->red_mask; - pi->green_mask = imagePtr->green_mask; - pi->blue_mask = imagePtr->blue_mask; - pi->y_sample_bits = imagePtr->y_sample_bits; - pi->u_sample_bits = imagePtr->u_sample_bits; - pi->v_sample_bits = imagePtr->v_sample_bits; - pi->horz_y_period = imagePtr->horz_y_period; - pi->horz_u_period = imagePtr->horz_u_period; - pi->horz_v_period = imagePtr->horz_v_period; - pi->vert_y_period = imagePtr->vert_y_period; - pi->vert_u_period = imagePtr->vert_u_period; - pi->vert_v_period = imagePtr->vert_v_period; - memcpy(pi->component_order, imagePtr->component_order, 32); - pi->scanline_order = imagePtr->scanline_order; - } - pa->nImages = adaptorPtr->nImages; - pa->pImages = pImage; - } - - if(adaptorPtr->nAttributes && - (pAttribute = xcalloc(adaptorPtr->nAttributes, sizeof(XvAttributeRec)))) - { - for(pat = pAttribute, attributePtr = adaptorPtr->pAttributes, i = 0; - i < adaptorPtr->nAttributes; pat++, i++, attributePtr++) - { - pat->flags = attributePtr->flags; - pat->min_value = attributePtr->min_value; - pat->max_value = attributePtr->max_value; - if((pat->name = xalloc(strlen(attributePtr->name) + 1))) - strcpy(pat->name, attributePtr->name); - } - pa->nAttributes = adaptorPtr->nAttributes; - pa->pAttributes = pAttribute; - } - - - totFormat = adaptorPtr->nFormats; - - if(!(pFormat = xcalloc(totFormat, sizeof(XvFormatRec)))) { - KdXVFreeAdaptor(pa); - continue; - } - for(pf = pFormat, i = 0, numFormat = 0, formatPtr = adaptorPtr->pFormats; - i < adaptorPtr->nFormats; i++, formatPtr++) - { - numVisuals = pScreen->numVisuals; - pVisual = pScreen->visuals; - - while(numVisuals--) { - if((pVisual->class == formatPtr->class) && - (pVisual->nplanes == formatPtr->depth)) { - - if(numFormat >= totFormat) { - void *moreSpace; - totFormat *= 2; - moreSpace = xrealloc(pFormat, - totFormat * sizeof(XvFormatRec)); - if(!moreSpace) break; - pFormat = moreSpace; - pf = pFormat + numFormat; - } - - pf->visual = pVisual->vid; - pf->depth = formatPtr->depth; - - pf++; - numFormat++; - } - pVisual++; - } - } - pa->nFormats = numFormat; - pa->pFormats = pFormat; - if(!numFormat) { - KdXVFreeAdaptor(pa); - continue; - } - - if(!(adaptorPriv = xcalloc(1, sizeof(XvAdaptorRecPrivate)))) { - KdXVFreeAdaptor(pa); - continue; - } - - adaptorPriv->flags = adaptorPtr->flags; - adaptorPriv->PutVideo = adaptorPtr->PutVideo; - adaptorPriv->PutStill = adaptorPtr->PutStill; - adaptorPriv->GetVideo = adaptorPtr->GetVideo; - adaptorPriv->GetStill = adaptorPtr->GetStill; - adaptorPriv->StopVideo = adaptorPtr->StopVideo; - adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute; - adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute; - adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize; - adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes; - adaptorPriv->PutImage = adaptorPtr->PutImage; - adaptorPriv->ReputImage = adaptorPtr->ReputImage; - - pa->devPriv.ptr = (pointer)adaptorPriv; - - if(!(pPort = xcalloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) { - KdXVFreeAdaptor(pa); - continue; - } - for(pp = pPort, i = 0, numPort = 0; - i < adaptorPtr->nPorts; i++) { - - if(!(pp->id = FakeClientID(0))) - continue; - - if(!(portPriv = xcalloc(1, sizeof(XvPortRecPrivate)))) - continue; - - if(!AddResource(pp->id, PortResource, pp)) { - xfree(portPriv); - continue; - } - - pp->pAdaptor = pa; - pp->pNotify = (XvPortNotifyPtr)NULL; - pp->pDraw = (DrawablePtr)NULL; - pp->client = (ClientPtr)NULL; - pp->grab.client = (ClientPtr)NULL; - pp->time = currentTime; - pp->devPriv.ptr = portPriv; - - portPriv->screen = screen; - portPriv->AdaptorRec = adaptorPriv; - portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr; - - pp++; - numPort++; - } - pa->nPorts = numPort; - pa->pPorts = pPort; - if(!numPort) { - KdXVFreeAdaptor(pa); - continue; - } - - pa->base_id = pPort->id; - - pa++; - numAdaptor++; - } - - if(numAdaptor) { - pxvs->nAdaptors = numAdaptor; - pxvs->pAdaptors = pAdaptor; - } else { - xfree(pAdaptor); - return FALSE; - } - - return TRUE; -} - -/* Video should be clipped to the intersection of the window cliplist - and the client cliplist specified in the GC for which the video was - initialized. When we need to reclip a window, the GC that started - the video may not even be around anymore. That's why we save the - client clip from the GC when the video is initialized. We then - use KdXVUpdateCompositeClip to calculate the new composite clip - when we need it. This is different from what DEC did. They saved - the GC and used it's clip list when they needed to reclip the window, - even if the client clip was different from the one the video was - initialized with. If the original GC was destroyed, they had to stop - the video. I like the new method better (MArk). - - This function only works for windows. Will need to rewrite when - (if) we support pixmap rendering. -*/ - -static void -KdXVUpdateCompositeClip(XvPortRecPrivatePtr portPriv) -{ - RegionPtr pregWin, pCompositeClip; - WindowPtr pWin; - Bool freeCompClip = FALSE; - - if(portPriv->pCompositeClip) - return; - - pWin = (WindowPtr)portPriv->pDraw; - - /* get window clip list */ - if(portPriv->subWindowMode == IncludeInferiors) { - pregWin = NotClippedByChildren(pWin); - freeCompClip = TRUE; - } else - pregWin = &pWin->clipList; - - if(!portPriv->clientClip) { - portPriv->pCompositeClip = pregWin; - portPriv->FreeCompositeClip = freeCompClip; - return; - } - - pCompositeClip = REGION_CREATE(pWin->pScreen, NullBox, 1); - REGION_COPY(pWin->pScreen, pCompositeClip, portPriv->clientClip); - REGION_TRANSLATE(pWin->pScreen, pCompositeClip, - portPriv->pDraw->x + portPriv->clipOrg.x, - portPriv->pDraw->y + portPriv->clipOrg.y); - REGION_INTERSECT(pWin->pScreen, pCompositeClip, pregWin, pCompositeClip); - - portPriv->pCompositeClip = pCompositeClip; - portPriv->FreeCompositeClip = TRUE; - - if(freeCompClip) { - REGION_DESTROY(pWin->pScreen, pregWin); - } -} - -/* Save the current clientClip and update the CompositeClip whenever - we have a fresh GC */ - -static void -KdXVCopyClip( - XvPortRecPrivatePtr portPriv, - GCPtr pGC -){ - /* copy the new clip if it exists */ - if((pGC->clientClipType == CT_REGION) && pGC->clientClip) { - if(!portPriv->clientClip) - portPriv->clientClip = REGION_CREATE(pGC->pScreen, NullBox, 1); - /* Note: this is in window coordinates */ - REGION_COPY(pGC->pScreen, portPriv->clientClip, pGC->clientClip); - } else if(portPriv->clientClip) { /* free the old clientClip */ - REGION_DESTROY(pGC->pScreen, portPriv->clientClip); - portPriv->clientClip = NULL; - } - - /* get rid of the old clip list */ - if(portPriv->pCompositeClip && portPriv->FreeCompositeClip) { - REGION_DESTROY(pWin->pScreen, portPriv->pCompositeClip); - } - - portPriv->clipOrg = pGC->clipOrg; - portPriv->pCompositeClip = pGC->pCompositeClip; - portPriv->FreeCompositeClip = FALSE; - portPriv->subWindowMode = pGC->subWindowMode; -} - -static int -KdXVRegetVideo(XvPortRecPrivatePtr portPriv) -{ - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - KdXVUpdateCompositeClip(portPriv); - - /* translate the video region to the screen */ - WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; - WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; - WinBox.x2 = WinBox.x1 + portPriv->drw_w; - WinBox.y2 = WinBox.y1 + portPriv->drw_h; - - /* clip to the window composite clip */ - REGION_INIT(portPriv->pDraw->pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(portPriv->pDraw->pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(portPriv->pDraw->pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); - - /* that's all if it's totally obscured */ - if(!REGION_NOTEMPTY(portPriv->pDraw->pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(portPriv->pDraw->pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->GetVideo)(portPriv->screen, portPriv->pDraw, - portPriv->vid_x, portPriv->vid_y, - WinBox.x1, WinBox.y1, - portPriv->vid_w, portPriv->vid_h, - portPriv->drw_w, portPriv->drw_h, - &ClipRegion, portPriv->DevPriv.ptr); - - if(ret == Success) - portPriv->isOn = XV_ON; - -CLIP_VIDEO_BAILOUT: - - if((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - /* This clip was copied and only good for one shot */ - if(!portPriv->FreeCompositeClip) - portPriv->pCompositeClip = NULL; - - REGION_UNINIT(portPriv->pDraw->pScreen, &WinRegion); - REGION_UNINIT(portPriv->pDraw->pScreen, &ClipRegion); - - return ret; -} - - -static int -KdXVReputVideo(XvPortRecPrivatePtr portPriv) -{ - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - ScreenPtr pScreen = portPriv->pDraw->pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen=pScreenPriv->screen; - int ret = Success; - Bool clippedAway = FALSE; - - KdXVUpdateCompositeClip(portPriv); - - /* translate the video region to the screen */ - WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; - WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; - WinBox.x2 = WinBox.x1 + portPriv->drw_w; - WinBox.y2 = WinBox.y1 + portPriv->drw_h; - - /* clip to the window composite clip */ - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); - - /* clip and translate to the viewport */ - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = 0; - VPBox.y1 = 0; - VPBox.x2 = screen->width; - VPBox.y2 = screen->height; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - /* that's all if it's totally obscured */ - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - - /* bailout if we have to clip but the hardware doesn't support it */ - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->PutVideo)(portPriv->screen, portPriv->pDraw, - portPriv->vid_x, portPriv->vid_y, - WinBox.x1, WinBox.y1, - portPriv->vid_w, portPriv->vid_h, - portPriv->drw_w, portPriv->drw_h, - &ClipRegion, portPriv->DevPriv.ptr); - - if(ret == Success) portPriv->isOn = XV_ON; - -CLIP_VIDEO_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - /* This clip was copied and only good for one shot */ - if(!portPriv->FreeCompositeClip) - portPriv->pCompositeClip = NULL; - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - -static int -KdXVReputImage(XvPortRecPrivatePtr portPriv) -{ - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - ScreenPtr pScreen = portPriv->pDraw->pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen=pScreenPriv->screen; - int ret = Success; - Bool clippedAway = FALSE; - - KdXVUpdateCompositeClip(portPriv); - - /* translate the video region to the screen */ - WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; - WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; - WinBox.x2 = WinBox.x1 + portPriv->drw_w; - WinBox.y2 = WinBox.y1 + portPriv->drw_h; - - /* clip to the window composite clip */ - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); - - /* clip and translate to the viewport */ - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = 0; - VPBox.y1 = 0; - VPBox.x2 = screen->width; - VPBox.y2 = screen->height; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - /* that's all if it's totally obscured */ - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - - /* bailout if we have to clip but the hardware doesn't support it */ - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->ReputImage)(portPriv->screen, portPriv->pDraw, - WinBox.x1, WinBox.y1, - &ClipRegion, portPriv->DevPriv.ptr); - - portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF; - -CLIP_VIDEO_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - /* This clip was copied and only good for one shot */ - if(!portPriv->FreeCompositeClip) - portPriv->pCompositeClip = NULL; - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - -static int -KdXVReputAllVideo(WindowPtr pWin, pointer data) -{ - KdXVWindowPtr WinPriv; - - if (pWin->drawable.type != DRAWABLE_WINDOW) - return WT_DONTWALKCHILDREN; - - WinPriv = GET_KDXV_WINDOW(pWin); - - while(WinPriv) { - if(WinPriv->PortRec->type == XvInputMask) - KdXVReputVideo(WinPriv->PortRec); - else - KdXVRegetVideo(WinPriv->PortRec); - WinPriv = WinPriv->next; - } - - return WT_WALKCHILDREN; -} - -static int -KdXVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) -{ - KdXVWindowPtr winPriv, PrivRoot; - - winPriv = PrivRoot = GET_KDXV_WINDOW(pWin); - - /* Enlist our port in the window private */ - while(winPriv) { - if(winPriv->PortRec == portPriv) /* we're already listed */ - break; - winPriv = winPriv->next; - } - - if(!winPriv) { - winPriv = xalloc(sizeof(KdXVWindowRec)); - if(!winPriv) return BadAlloc; - winPriv->PortRec = portPriv; - winPriv->next = PrivRoot; - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv); - } - return Success; -} - - -static void -KdXVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) -{ - KdXVWindowPtr winPriv, prevPriv = NULL; - - winPriv = GET_KDXV_WINDOW(pWin); - - while(winPriv) { - if(winPriv->PortRec == portPriv) { - if(prevPriv) - prevPriv->next = winPriv->next; - else - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv->next); - xfree(winPriv); - break; - } - prevPriv = winPriv; - winPriv = winPriv->next; - } - portPriv->pDraw = NULL; -} - -/**** ScreenRec fields ****/ - - -static Bool -KdXVCreateWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - int ret; - - pScreen->CreateWindow = ScreenPriv->CreateWindow; - ret = (*pScreen->CreateWindow)(pWin); - pScreen->CreateWindow = KdXVCreateWindow; - - if (ret) - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, NULL); - - return ret; -} - - -static Bool -KdXVDestroyWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - KdXVWindowPtr tmp, WinPriv = GET_KDXV_WINDOW(pWin); - int ret; - - while(WinPriv) { - XvPortRecPrivatePtr pPriv = WinPriv->PortRec; - - if(pPriv->isOn > XV_OFF) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->screen, pPriv->DevPriv.ptr, TRUE); - pPriv->isOn = XV_OFF; - } - - pPriv->pDraw = NULL; - tmp = WinPriv; - WinPriv = WinPriv->next; - xfree(tmp); - } - - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, NULL); - - pScreen->DestroyWindow = ScreenPriv->DestroyWindow; - ret = (*pScreen->DestroyWindow)(pWin); - pScreen->DestroyWindow = KdXVDestroyWindow; - - return ret; -} - - -static void -KdXVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); - KdXVWindowPtr pPrev; - XvPortRecPrivatePtr pPriv; - Bool AreasExposed; - - AreasExposed = (WinPriv && reg1 && REGION_NOTEMPTY(pScreen, reg1)); - - pScreen->WindowExposures = ScreenPriv->WindowExposures; - (*pScreen->WindowExposures)(pWin, reg1, reg2); - pScreen->WindowExposures = KdXVWindowExposures; - - /* filter out XClearWindow/Area */ - if (!pWin->valdata) return; - - pPrev = NULL; - - while(WinPriv) { - pPriv = WinPriv->PortRec; - - /* Reput anyone with a reput function */ - - switch(pPriv->type) { - case XvInputMask: - KdXVReputVideo(pPriv); - break; - case XvOutputMask: - KdXVRegetVideo(pPriv); - break; - default: /* overlaid still/image*/ - if (pPriv->AdaptorRec->ReputImage) - KdXVReputImage(pPriv); - else if(AreasExposed) { - KdXVWindowPtr tmp; - - if (pPriv->isOn == XV_ON) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->screen, pPriv->DevPriv.ptr, FALSE); - pPriv->isOn = XV_PENDING; - } - pPriv->pDraw = NULL; - - if(!pPrev) - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, WinPriv->next); - else - pPrev->next = WinPriv->next; - tmp = WinPriv; - WinPriv = WinPriv->next; - xfree(tmp); - continue; - } - break; - } - pPrev = WinPriv; - WinPriv = WinPriv->next; - } -} - - -static void -KdXVClipNotify(WindowPtr pWin, int dx, int dy) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); - KdXVWindowPtr tmp, pPrev = NULL; - XvPortRecPrivatePtr pPriv; - Bool visible = (pWin->visibility == VisibilityUnobscured) || - (pWin->visibility == VisibilityPartiallyObscured); - - while(WinPriv) { - pPriv = WinPriv->PortRec; - - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pScreen, pPriv->pCompositeClip); - - pPriv->pCompositeClip = NULL; - - /* Stop everything except images, but stop them too if the - window isn't visible. But we only remove the images. */ - - if(pPriv->type || !visible) { - if(pPriv->isOn == XV_ON) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->screen, pPriv->DevPriv.ptr, FALSE); - pPriv->isOn = XV_PENDING; - } - - if(!pPriv->type) { /* overlaid still/image */ - pPriv->pDraw = NULL; - - if(!pPrev) - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, WinPriv->next); - else - pPrev->next = WinPriv->next; - tmp = WinPriv; - WinPriv = WinPriv->next; - xfree(tmp); - continue; - } - } - - pPrev = WinPriv; - WinPriv = WinPriv->next; - } - - if(ScreenPriv->ClipNotify) { - pScreen->ClipNotify = ScreenPriv->ClipNotify; - (*pScreen->ClipNotify)(pWin, dx, dy); - pScreen->ClipNotify = KdXVClipNotify; - } -} - - - -/**** Required XvScreenRec fields ****/ - -static Bool -KdXVCloseScreen(int i, ScreenPtr pScreen) -{ - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - XvAdaptorPtr pa; - int c; - - if(!ScreenPriv) return TRUE; - - pScreen->CreateWindow = ScreenPriv->CreateWindow; - pScreen->DestroyWindow = ScreenPriv->DestroyWindow; - pScreen->WindowExposures = ScreenPriv->WindowExposures; - pScreen->ClipNotify = ScreenPriv->ClipNotify; - -/* fprintf(stderr,"XV: Unwrapping screen funcs\n"); */ - - for(c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) { - KdXVFreeAdaptor(pa); - } - - xfree(pxvs->pAdaptors); - xfree(ScreenPriv); - - return TRUE; -} - - -static int -KdXVQueryAdaptors( - ScreenPtr pScreen, - XvAdaptorPtr *p_pAdaptors, - int *p_nAdaptors -){ - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - - *p_nAdaptors = pxvs->nAdaptors; - *p_pAdaptors = pxvs->pAdaptors; - - return (Success); -} - -static Bool -KdXVRunning (ScreenPtr pScreen) -{ - return (KdXVGeneration == serverGeneration && - GET_XV_SCREEN(pScreen) != 0); -} - -Bool -KdXVEnable(ScreenPtr pScreen) -{ - if (!KdXVRunning (pScreen)) - return TRUE; - - WalkTree(pScreen, KdXVReputAllVideo, 0); - - return TRUE; -} - -void -KdXVDisable(ScreenPtr pScreen) -{ - XvScreenPtr pxvs; - KdXVScreenPtr ScreenPriv; - XvAdaptorPtr pAdaptor; - XvPortPtr pPort; - XvPortRecPrivatePtr pPriv; - int i, j; - - if (!KdXVRunning (pScreen)) - return; - - pxvs = GET_XV_SCREEN(pScreen); - ScreenPriv = GET_KDXV_SCREEN(pScreen); - - for(i = 0; i < pxvs->nAdaptors; i++) { - pAdaptor = &pxvs->pAdaptors[i]; - for(j = 0; j < pAdaptor->nPorts; j++) { - pPort = &pAdaptor->pPorts[j]; - pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; - if(pPriv->isOn > XV_OFF) { - - (*pPriv->AdaptorRec->StopVideo)( - pPriv->screen, pPriv->DevPriv.ptr, TRUE); - pPriv->isOn = XV_OFF; - - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pScreen, pPriv->pCompositeClip); - - pPriv->pCompositeClip = NULL; - - if(!pPriv->type && pPriv->pDraw) { /* still */ - KdXVRemovePortFromWindow((WindowPtr)pPriv->pDraw, pPriv); - } - } - } - } -} - -/**** XvAdaptorRec fields ****/ - -static int -KdXVAllocatePort( - unsigned long port, - XvPortPtr pPort, - XvPortPtr *ppPort -){ - *ppPort = pPort; - return Success; -} - -static int -KdXVFreePort(XvPortPtr pPort) -{ - return Success; -} - -static int -KdXVPutVideo( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - KdScreenPriv(portPriv->screen->pScreen); - int result; - - /* No dumping video to pixmaps... For now anyhow */ - if(pDraw->type != DRAWABLE_WINDOW) { - pPort->pDraw = (DrawablePtr)NULL; - return BadAlloc; - } - - /* If we are changing windows, unregister our port in the old window */ - if(portPriv->pDraw && (portPriv->pDraw != pDraw)) - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - - /* Register our port with the new window */ - result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - if(result != Success) return result; - - portPriv->pDraw = pDraw; - portPriv->type = XvInputMask; - - /* save a copy of these parameters */ - portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; - portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - - /* make sure we have the most recent copy of the clientClip */ - KdXVCopyClip(portPriv, pGC); - - /* To indicate to the DI layer that we were successful */ - pPort->pDraw = pDraw; - - if (!pScreenPriv->enabled) return Success; - - return(KdXVReputVideo(portPriv)); -} - -static int -KdXVPutStill( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - ScreenPtr pScreen = pDraw->pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen=pScreenPriv->screen; - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - if (pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - if (!pScreenPriv->enabled) return Success; - - WinBox.x1 = pDraw->x + drw_x; - WinBox.y1 = pDraw->y + drw_y; - WinBox.x2 = WinBox.x1 + drw_w; - WinBox.y2 = WinBox.y1 + drw_h; - - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); - - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = 0; - VPBox.y1 = 0; - VPBox.x2 = screen->width; - VPBox.y2 = screen->height; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - if(portPriv->pDraw) { - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - } - - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto PUT_STILL_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto PUT_STILL_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->PutStill)(portPriv->screen, pDraw, - vid_x, vid_y, WinBox.x1, WinBox.y1, - vid_w, vid_h, drw_w, drw_h, - &ClipRegion, portPriv->DevPriv.ptr); - - if((ret == Success) && - (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) { - - KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - portPriv->isOn = XV_ON; - portPriv->pDraw = pDraw; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - portPriv->type = 0; /* no mask means it's transient and should - not be reput once it's removed */ - pPort->pDraw = pDraw; /* make sure we can get stop requests */ - } - -PUT_STILL_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - -static int -KdXVGetVideo( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - int result; - KdScreenPriv(portPriv->screen->pScreen); - - /* No pixmaps... For now anyhow */ - if(pDraw->type != DRAWABLE_WINDOW) { - pPort->pDraw = (DrawablePtr)NULL; - return BadAlloc; - } - - /* If we are changing windows, unregister our port in the old window */ - if(portPriv->pDraw && (portPriv->pDraw != pDraw)) - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - - /* Register our port with the new window */ - result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - if(result != Success) return result; - - portPriv->pDraw = pDraw; - portPriv->type = XvOutputMask; - - /* save a copy of these parameters */ - portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; - portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - - /* make sure we have the most recent copy of the clientClip */ - KdXVCopyClip(portPriv, pGC); - - /* To indicate to the DI layer that we were successful */ - pPort->pDraw = pDraw; - - if(!pScreenPriv->enabled) return Success; - - return(KdXVRegetVideo(portPriv)); -} - -static int -KdXVGetStill( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - ScreenPtr pScreen = pDraw->pScreen; - KdScreenPriv(pScreen); - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - if (pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - if(!pScreenPriv->enabled) return Success; - - WinBox.x1 = pDraw->x + drw_x; - WinBox.y1 = pDraw->y + drw_y; - WinBox.x2 = WinBox.x1 + drw_w; - WinBox.y2 = WinBox.y1 + drw_h; - - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); - - if(portPriv->pDraw) { - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - } - - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto GET_STILL_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->GetStill)(portPriv->screen, pDraw, - vid_x, vid_y, WinBox.x1, WinBox.y1, - vid_w, vid_h, drw_w, drw_h, - &ClipRegion, portPriv->DevPriv.ptr); - -GET_STILL_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - - -static int -KdXVStopVideo( - ClientPtr client, - XvPortPtr pPort, - DrawablePtr pDraw -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - KdScreenPriv(portPriv->screen->pScreen); - - if(pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - KdXVRemovePortFromWindow((WindowPtr)pDraw, portPriv); - - if(!pScreenPriv->enabled) return Success; - - /* Must free resources. */ - - if(portPriv->isOn > XV_OFF) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, TRUE); - portPriv->isOn = XV_OFF; - } - - return Success; -} - -static int -KdXVSetPortAttribute( - ClientPtr client, - XvPortPtr pPort, - Atom attribute, - INT32 value -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return((*portPriv->AdaptorRec->SetPortAttribute)(portPriv->screen, - attribute, value, portPriv->DevPriv.ptr)); -} - - -static int -KdXVGetPortAttribute( - ClientPtr client, - XvPortPtr pPort, - Atom attribute, - INT32 *p_value -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return((*portPriv->AdaptorRec->GetPortAttribute)(portPriv->screen, - attribute, (int *) p_value, portPriv->DevPriv.ptr)); -} - - - -static int -KdXVQueryBestSize( - ClientPtr client, - XvPortPtr pPort, - CARD8 motion, - CARD16 vid_w, CARD16 vid_h, - CARD16 drw_w, CARD16 drw_h, - unsigned int *p_w, unsigned int *p_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - (*portPriv->AdaptorRec->QueryBestSize)(portPriv->screen, - (Bool)motion, vid_w, vid_h, drw_w, drw_h, - p_w, p_h, portPriv->DevPriv.ptr); - - return Success; -} - - -static int -KdXVPutImage( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 src_x, INT16 src_y, - CARD16 src_w, CARD16 src_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h, - XvImagePtr format, - unsigned char* data, - Bool sync, - CARD16 width, CARD16 height -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - ScreenPtr pScreen = pDraw->pScreen; - KdScreenPriv(pScreen); - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - if (pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - if(!pScreenPriv->enabled) return Success; - - WinBox.x1 = pDraw->x + drw_x; - WinBox.y1 = pDraw->y + drw_y; - WinBox.x2 = WinBox.x1 + drw_w; - WinBox.y2 = WinBox.y1 + drw_h; - - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); - - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = 0; - VPBox.y1 = 0; - VPBox.x2 = pScreen->width; - VPBox.y2 = pScreen->height; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - if(portPriv->pDraw) { - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - } - - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto PUT_IMAGE_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto PUT_IMAGE_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->PutImage)(portPriv->screen, pDraw, - src_x, src_y, WinBox.x1, WinBox.y1, - src_w, src_h, drw_w, drw_h, format->id, data, width, height, - sync, &ClipRegion, portPriv->DevPriv.ptr); - - if((ret == Success) && - (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) { - - KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - portPriv->isOn = XV_ON; - portPriv->pDraw = pDraw; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - portPriv->type = 0; /* no mask means it's transient and should - not be reput once it's removed */ - pPort->pDraw = pDraw; /* make sure we can get stop requests */ - } - -PUT_IMAGE_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - -static int -KdXVQueryImageAttributes( - ClientPtr client, - XvPortPtr pPort, - XvImagePtr format, - CARD16 *width, - CARD16 *height, - int *pitches, - int *offsets -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return (*portPriv->AdaptorRec->QueryImageAttributes)(portPriv->screen, - format->id, width, height, pitches, offsets); -} - - -/**************** Common video manipulation functions *******************/ - -void -KdXVCopyPackedData(KdScreenInfo *screen, CARD8 *src, CARD8 *dst, int randr, - int srcPitch, int dstPitch, int srcW, int srcH, int top, int left, - int h, int w) -{ - int srcDown = srcPitch, srcRight = 2, srcNext; - int p; - - switch (randr & RR_Rotate_All) { - case RR_Rotate_0: - srcDown = srcPitch; - srcRight = 2; - break; - case RR_Rotate_90: - src += (srcH - 1) * 2; - srcDown = -2; - srcRight = srcPitch; - break; - case RR_Rotate_180: - src += srcPitch * (srcH - 1) + (srcW - 1) * 2; - srcDown = -srcPitch; - srcRight = -2; - break; - case RR_Rotate_270: - src += srcPitch * (srcW - 1); - srcDown = 2; - srcRight = -srcPitch; - break; - } - - src = src + top * srcDown + left * srcRight; - - w >>= 1; - /* srcRight >>= 1; */ - srcNext = srcRight >> 1; - while (h--) { - CARD16 *s = (CARD16 *)src; - CARD32 *d = (CARD32 *)dst; - p = w; - while (p--) { - *d++ = s[0] | (s[srcNext] << 16); - s += srcRight; - } - src += srcPitch; - dst += dstPitch; - } -} - -void -KdXVCopyPlanarData(KdScreenInfo *screen, CARD8 *src, CARD8 *dst, int randr, - int srcPitch, int srcPitch2, int dstPitch, int srcW, int srcH, int height, - int top, int left, int h, int w, int id) -{ - int i, j; - CARD8 *src1, *src2, *src3, *dst1; - int srcDown = srcPitch, srcDown2 = srcPitch2; - int srcRight = 2, srcRight2 = 1, srcNext = 1; - - /* compute source data pointers */ - src1 = src; - src2 = src1 + height * srcPitch; - src3 = src2 + (height >> 1) * srcPitch2; - switch (randr & RR_Rotate_All) { - case RR_Rotate_0: - srcDown = srcPitch; - srcDown2 = srcPitch2; - srcRight = 2; - srcRight2 = 1; - srcNext = 1; - break; - case RR_Rotate_90: - src1 = src1 + srcH - 1; - src2 = src2 + (srcH >> 1) - 1; - src3 = src3 + (srcH >> 1) - 1; - srcDown = -1; - srcDown2 = -1; - srcRight = srcPitch * 2; - srcRight2 = srcPitch2; - srcNext = srcPitch; - break; - case RR_Rotate_180: - src1 = src1 + srcPitch * (srcH - 1) + (srcW - 1); - src2 = src2 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); - src3 = src3 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); - srcDown = -srcPitch; - srcDown2 = -srcPitch2; - srcRight = -2; - srcRight2 = -1; - srcNext = -1; - break; - case RR_Rotate_270: - src1 = src1 + srcPitch * (srcW - 1); - src2 = src2 + srcPitch2 * ((srcW >> 1) - 1); - src3 = src3 + srcPitch2 * ((srcW >> 1) - 1); - srcDown = 1; - srcDown2 = 1; - srcRight = -srcPitch * 2; - srcRight2 = -srcPitch2; - srcNext = -srcPitch; - break; - } - - /* adjust for origin */ - src1 += top * srcDown + left * srcNext; - src2 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; - src3 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; - - if (id == FOURCC_I420) { - CARD8 *srct = src2; - src2 = src3; - src3 = srct; - } - - dst1 = dst; - - w >>= 1; - for (j = 0; j < h; j++) { - CARD32 *dst = (CARD32 *)dst1; - CARD8 *s1l = src1; - CARD8 *s1r = src1 + srcNext; - CARD8 *s2 = src2; - CARD8 *s3 = src3; - - for (i = 0; i < w; i++) { - *dst++ = *s1l | (*s1r << 16) | (*s3 << 8) | (*s2 << 24); - s1l += srcRight; - s1r += srcRight; - s2 += srcRight2; - s3 += srcRight2; - } - src1 += srcDown; - dst1 += dstPitch; - if (j & 1) { - src2 += srcDown2; - src3 += srcDown2; - } - } -} - -void -KXVPaintRegion (DrawablePtr pDraw, RegionPtr pRgn, Pixel fg) -{ - GCPtr pGC; - CARD32 val[2]; - xRectangle *rects, *r; - BoxPtr pBox = REGION_RECTS (pRgn); - int nBox = REGION_NUM_RECTS (pRgn); - - rects = xalloc (nBox * sizeof (xRectangle)); - if (!rects) - goto bail0; - r = rects; - while (nBox--) - { - r->x = pBox->x1 - pDraw->x; - r->y = pBox->y1 - pDraw->y; - r->width = pBox->x2 - pBox->x1; - r->height = pBox->y2 - pBox->y1; - r++; - pBox++; - } - - pGC = GetScratchGC (pDraw->depth, pDraw->pScreen); - if (!pGC) - goto bail1; - - val[0] = fg; - val[1] = IncludeInferiors; - ChangeGC (pGC, GCForeground|GCSubwindowMode, val); - - ValidateGC (pDraw, pGC); - - (*pGC->ops->PolyFillRect) (pDraw, pGC, - REGION_NUM_RECTS (pRgn), rects); - - FreeScratchGC (pGC); -bail1: - xfree (rects); -bail0: - ; -} +/* + + XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com) + Adapted for KDrive by Pontus Lidman <pontus.lidman@nokia.com> + + Copyright (C) 2000, 2001 - Nokia Home Communications + Copyright (C) 1998, 1999 - 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, 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_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" + +#include "scrnintstr.h" +#include "regionstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "mivalidate.h" +#include "validate.h" +#include "resource.h" +#include "gcstruct.h" +#include "dixstruct.h" + +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvproto.h> + +#include "kxv.h" +#include "fourcc.h" + + +/* XvScreenRec fields */ + +static Bool KdXVCloseScreen(int, ScreenPtr); +static int KdXVQueryAdaptors(ScreenPtr, XvAdaptorPtr *, int *); + +/* XvAdaptorRec fields */ + +static int KdXVAllocatePort(unsigned long, XvPortPtr, XvPortPtr*); +static int KdXVFreePort(XvPortPtr); +static int KdXVPutVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVPutStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVGetVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVGetStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVStopVideo(ClientPtr, XvPortPtr, DrawablePtr); +static int KdXVSetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32); +static int KdXVGetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32 *); +static int KdXVQueryBestSize(ClientPtr, XvPortPtr, CARD8, + CARD16, CARD16,CARD16, CARD16, + unsigned int*, unsigned int*); +static int KdXVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16, + XvImagePtr, unsigned char*, Bool, + CARD16, CARD16); +static int KdXVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr, + CARD16*, CARD16*, int*, int*); + + +/* ScreenRec fields */ + +static Bool KdXVCreateWindow(WindowPtr pWin); +static Bool KdXVDestroyWindow(WindowPtr pWin); +static void KdXVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2); +static void KdXVClipNotify(WindowPtr pWin, int dx, int dy); + +/* misc */ +static Bool KdXVInitAdaptors(ScreenPtr, KdVideoAdaptorPtr*, int); + +static int KdXVWindowKeyIndex; +DevPrivateKey KdXVWindowKey = &KdXVWindowKeyIndex; +static int KdXvScreenKeyIndex; +DevPrivateKey KdXvScreenKey = &KdXvScreenKeyIndex; +static unsigned long KdXVGeneration = 0; +static unsigned long PortResource = 0; + +DevPrivateKey (*XvGetScreenKeyProc)(void) = XvGetScreenKey; +unsigned long (*XvGetRTPortProc)(void) = XvGetRTPort; +int (*XvScreenInitProc)(ScreenPtr) = XvScreenInit; + +#define GET_XV_SCREEN(pScreen) ((XvScreenPtr) \ + dixLookupPrivate(&(pScreen)->devPrivates, KdXvScreenKey)) + +#define GET_KDXV_SCREEN(pScreen) \ + ((KdXVScreenPtr)(GET_XV_SCREEN(pScreen)->devPriv.ptr)) + +#define GET_KDXV_WINDOW(pWin) ((KdXVWindowPtr) \ + dixLookupPrivate(&(pWin)->devPrivates, KdXVWindowKey)) + +static KdXVInitGenericAdaptorPtr *GenDrivers = NULL; +static int NumGenDrivers = 0; + +int +KdXVRegisterGenericAdaptorDriver( + KdXVInitGenericAdaptorPtr InitFunc +){ + KdXVInitGenericAdaptorPtr *newdrivers; + +/* fprintf(stderr,"KdXVRegisterGenericAdaptorDriver\n"); */ + + newdrivers = realloc(GenDrivers, sizeof(KdXVInitGenericAdaptorPtr) * + (1 + NumGenDrivers)); + if (!newdrivers) + return 0; + GenDrivers = newdrivers; + + GenDrivers[NumGenDrivers++] = InitFunc; + + return 1; +} + +int +KdXVListGenericAdaptors( + KdScreenInfo * screen, + KdVideoAdaptorPtr **adaptors +){ + int i,j,n,num; + KdVideoAdaptorPtr *DrivAdap,*new; + + num = 0; + *adaptors = NULL; + for (i = 0; i < NumGenDrivers; i++) { + n = GenDrivers[i](screen,&DrivAdap); + if (0 == n) + continue; + new = realloc(*adaptors, sizeof(KdVideoAdaptorPtr) * (num+n)); + if (NULL == new) + continue; + *adaptors = new; + for (j = 0; j < n; j++, num++) + (*adaptors)[num] = DrivAdap[j]; + } + return num; +} + +KdVideoAdaptorPtr +KdXVAllocateVideoAdaptorRec(KdScreenInfo * screen) +{ + return calloc(1, sizeof(KdVideoAdaptorRec)); +} + +void +KdXVFreeVideoAdaptorRec(KdVideoAdaptorPtr ptr) +{ + free(ptr); +} + + +Bool +KdXVScreenInit( + ScreenPtr pScreen, + KdVideoAdaptorPtr *adaptors, + int num +){ + KdXVScreenPtr ScreenPriv; + XvScreenPtr pxvs; + +/* fprintf(stderr,"KdXVScreenInit initializing %d adaptors\n",num); */ + + if (KdXVGeneration != serverGeneration) + KdXVGeneration = serverGeneration; + + if(!XvGetScreenKeyProc || !XvGetRTPortProc || !XvScreenInitProc) + return FALSE; + + if(Success != (*XvScreenInitProc)(pScreen)) return FALSE; + + KdXvScreenKey = (*XvGetScreenKeyProc)(); + PortResource = (*XvGetRTPortProc)(); + + pxvs = GET_XV_SCREEN(pScreen); + + + /* Anyone initializing the Xv layer must provide these two. + The Xv di layer calls them without even checking if they exist! */ + + pxvs->ddCloseScreen = KdXVCloseScreen; + pxvs->ddQueryAdaptors = KdXVQueryAdaptors; + + /* The Xv di layer provides us with a private hook so that we don't + have to allocate our own screen private. They also provide + a CloseScreen hook so that we don't have to wrap it. I'm not + sure that I appreciate that. */ + + ScreenPriv = malloc(sizeof(KdXVScreenRec)); + pxvs->devPriv.ptr = (pointer)ScreenPriv; + + if(!ScreenPriv) return FALSE; + + + ScreenPriv->CreateWindow = pScreen->CreateWindow; + ScreenPriv->DestroyWindow = pScreen->DestroyWindow; + ScreenPriv->WindowExposures = pScreen->WindowExposures; + ScreenPriv->ClipNotify = pScreen->ClipNotify; + +/* fprintf(stderr,"XV: Wrapping screen funcs\n"); */ + + pScreen->CreateWindow = KdXVCreateWindow; + pScreen->DestroyWindow = KdXVDestroyWindow; + pScreen->WindowExposures = KdXVWindowExposures; + pScreen->ClipNotify = KdXVClipNotify; + + if(!KdXVInitAdaptors(pScreen, adaptors, num)) + return FALSE; + + return TRUE; +} + +static void +KdXVFreeAdaptor(XvAdaptorPtr pAdaptor) +{ + int i; + + free(pAdaptor->name); + + if(pAdaptor->pEncodings) { + XvEncodingPtr pEncode = pAdaptor->pEncodings; + + for(i = 0; i < pAdaptor->nEncodings; i++, pEncode++) { + free(pEncode->name); + } + free(pAdaptor->pEncodings); + } + + free(pAdaptor->pFormats); + + if(pAdaptor->pPorts) { + XvPortPtr pPort = pAdaptor->pPorts; + XvPortRecPrivatePtr pPriv; + + for(i = 0; i < pAdaptor->nPorts; i++, pPort++) { + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv) { + if(pPriv->clientClip) + REGION_DESTROY(pAdaptor->pScreen, pPriv->clientClip); + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pAdaptor->pScreen, pPriv->pCompositeClip); + free(pPriv); + } + } + free(pAdaptor->pPorts); + } + + if(pAdaptor->nAttributes) { + XvAttributePtr pAttribute = pAdaptor->pAttributes; + + for(i = 0; i < pAdaptor->nAttributes; i++, pAttribute++) { + free(pAttribute->name); + } + + free(pAdaptor->pAttributes); + } + + free(pAdaptor->pImages); + + free(pAdaptor->devPriv.ptr); +} + +static Bool +KdXVInitAdaptors( + ScreenPtr pScreen, + KdVideoAdaptorPtr *infoPtr, + int number +) { + KdScreenPriv(pScreen); + KdScreenInfo * screen = pScreenPriv->screen; + + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + KdVideoAdaptorPtr adaptorPtr; + XvAdaptorPtr pAdaptor, pa; + XvAdaptorRecPrivatePtr adaptorPriv; + int na, numAdaptor; + XvPortRecPrivatePtr portPriv; + XvPortPtr pPort, pp; + int numPort; + KdAttributePtr attributePtr; + XvAttributePtr pAttribute, pat; + KdVideoFormatPtr formatPtr; + XvFormatPtr pFormat, pf; + int numFormat, totFormat; + KdVideoEncodingPtr encodingPtr; + XvEncodingPtr pEncode, pe; + KdImagePtr imagePtr; + XvImagePtr pImage, pi; + int numVisuals; + VisualPtr pVisual; + int i; + + pxvs->nAdaptors = 0; + pxvs->pAdaptors = NULL; + + if(!(pAdaptor = calloc(number, sizeof(XvAdaptorRec)))) + return FALSE; + + for(pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) { + adaptorPtr = infoPtr[na]; + + if(!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute || + !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize) + continue; + + /* client libs expect at least one encoding */ + if(!adaptorPtr->nEncodings || !adaptorPtr->pEncodings) + continue; + + pa->type = adaptorPtr->type; + + if(!adaptorPtr->PutVideo && !adaptorPtr->GetVideo) + pa->type &= ~XvVideoMask; + + if(!adaptorPtr->PutStill && !adaptorPtr->GetStill) + pa->type &= ~XvStillMask; + + if(!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes) + pa->type &= ~XvImageMask; + + if(!adaptorPtr->PutVideo && !adaptorPtr->PutImage && + !adaptorPtr->PutStill) + pa->type &= ~XvInputMask; + + if(!adaptorPtr->GetVideo && !adaptorPtr->GetStill) + pa->type &= ~XvOutputMask; + + if(!(adaptorPtr->type & (XvPixmapMask | XvWindowMask))) + continue; + if(!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask))) + continue; + + pa->pScreen = pScreen; + pa->ddAllocatePort = KdXVAllocatePort; + pa->ddFreePort = KdXVFreePort; + pa->ddPutVideo = KdXVPutVideo; + pa->ddPutStill = KdXVPutStill; + pa->ddGetVideo = KdXVGetVideo; + pa->ddGetStill = KdXVGetStill; + pa->ddStopVideo = KdXVStopVideo; + pa->ddPutImage = KdXVPutImage; + pa->ddSetPortAttribute = KdXVSetPortAttribute; + pa->ddGetPortAttribute = KdXVGetPortAttribute; + pa->ddQueryBestSize = KdXVQueryBestSize; + pa->ddQueryImageAttributes = KdXVQueryImageAttributes; + if((pa->name = malloc(strlen(adaptorPtr->name) + 1))) + strcpy(pa->name, adaptorPtr->name); + + if(adaptorPtr->nEncodings && + (pEncode = calloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) { + + for(pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0; + i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) + { + pe->id = encodingPtr->id; + pe->pScreen = pScreen; + if((pe->name = malloc(strlen(encodingPtr->name) + 1))) + strcpy(pe->name, encodingPtr->name); + pe->width = encodingPtr->width; + pe->height = encodingPtr->height; + pe->rate.numerator = encodingPtr->rate.numerator; + pe->rate.denominator = encodingPtr->rate.denominator; + } + pa->nEncodings = adaptorPtr->nEncodings; + pa->pEncodings = pEncode; + } + + if(adaptorPtr->nImages && + (pImage = calloc(adaptorPtr->nImages, sizeof(XvImageRec)))) { + + for(i = 0, pi = pImage, imagePtr = adaptorPtr->pImages; + i < adaptorPtr->nImages; i++, pi++, imagePtr++) + { + pi->id = imagePtr->id; + pi->type = imagePtr->type; + pi->byte_order = imagePtr->byte_order; + memcpy(pi->guid, imagePtr->guid, 16); + pi->bits_per_pixel = imagePtr->bits_per_pixel; + pi->format = imagePtr->format; + pi->num_planes = imagePtr->num_planes; + pi->depth = imagePtr->depth; + pi->red_mask = imagePtr->red_mask; + pi->green_mask = imagePtr->green_mask; + pi->blue_mask = imagePtr->blue_mask; + pi->y_sample_bits = imagePtr->y_sample_bits; + pi->u_sample_bits = imagePtr->u_sample_bits; + pi->v_sample_bits = imagePtr->v_sample_bits; + pi->horz_y_period = imagePtr->horz_y_period; + pi->horz_u_period = imagePtr->horz_u_period; + pi->horz_v_period = imagePtr->horz_v_period; + pi->vert_y_period = imagePtr->vert_y_period; + pi->vert_u_period = imagePtr->vert_u_period; + pi->vert_v_period = imagePtr->vert_v_period; + memcpy(pi->component_order, imagePtr->component_order, 32); + pi->scanline_order = imagePtr->scanline_order; + } + pa->nImages = adaptorPtr->nImages; + pa->pImages = pImage; + } + + if(adaptorPtr->nAttributes && + (pAttribute = calloc(adaptorPtr->nAttributes, sizeof(XvAttributeRec)))) + { + for(pat = pAttribute, attributePtr = adaptorPtr->pAttributes, i = 0; + i < adaptorPtr->nAttributes; pat++, i++, attributePtr++) + { + pat->flags = attributePtr->flags; + pat->min_value = attributePtr->min_value; + pat->max_value = attributePtr->max_value; + if((pat->name = malloc(strlen(attributePtr->name) + 1))) + strcpy(pat->name, attributePtr->name); + } + pa->nAttributes = adaptorPtr->nAttributes; + pa->pAttributes = pAttribute; + } + + + totFormat = adaptorPtr->nFormats; + + if(!(pFormat = calloc(totFormat, sizeof(XvFormatRec)))) { + KdXVFreeAdaptor(pa); + continue; + } + for(pf = pFormat, i = 0, numFormat = 0, formatPtr = adaptorPtr->pFormats; + i < adaptorPtr->nFormats; i++, formatPtr++) + { + numVisuals = pScreen->numVisuals; + pVisual = pScreen->visuals; + + while(numVisuals--) { + if((pVisual->class == formatPtr->class) && + (pVisual->nplanes == formatPtr->depth)) { + + if(numFormat >= totFormat) { + void *moreSpace; + totFormat *= 2; + moreSpace = realloc(pFormat, + totFormat * sizeof(XvFormatRec)); + if(!moreSpace) break; + pFormat = moreSpace; + pf = pFormat + numFormat; + } + + pf->visual = pVisual->vid; + pf->depth = formatPtr->depth; + + pf++; + numFormat++; + } + pVisual++; + } + } + pa->nFormats = numFormat; + pa->pFormats = pFormat; + if(!numFormat) { + KdXVFreeAdaptor(pa); + continue; + } + + if(!(adaptorPriv = calloc(1, sizeof(XvAdaptorRecPrivate)))) { + KdXVFreeAdaptor(pa); + continue; + } + + adaptorPriv->flags = adaptorPtr->flags; + adaptorPriv->PutVideo = adaptorPtr->PutVideo; + adaptorPriv->PutStill = adaptorPtr->PutStill; + adaptorPriv->GetVideo = adaptorPtr->GetVideo; + adaptorPriv->GetStill = adaptorPtr->GetStill; + adaptorPriv->StopVideo = adaptorPtr->StopVideo; + adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute; + adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute; + adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize; + adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes; + adaptorPriv->PutImage = adaptorPtr->PutImage; + adaptorPriv->ReputImage = adaptorPtr->ReputImage; + + pa->devPriv.ptr = (pointer)adaptorPriv; + + if(!(pPort = calloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) { + KdXVFreeAdaptor(pa); + continue; + } + for(pp = pPort, i = 0, numPort = 0; + i < adaptorPtr->nPorts; i++) { + + if(!(pp->id = FakeClientID(0))) + continue; + + if(!(portPriv = calloc(1, sizeof(XvPortRecPrivate)))) + continue; + + if(!AddResource(pp->id, PortResource, pp)) { + free(portPriv); + continue; + } + + pp->pAdaptor = pa; + pp->pNotify = (XvPortNotifyPtr)NULL; + pp->pDraw = (DrawablePtr)NULL; + pp->client = (ClientPtr)NULL; + pp->grab.client = (ClientPtr)NULL; + pp->time = currentTime; + pp->devPriv.ptr = portPriv; + + portPriv->screen = screen; + portPriv->AdaptorRec = adaptorPriv; + portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr; + + pp++; + numPort++; + } + pa->nPorts = numPort; + pa->pPorts = pPort; + if(!numPort) { + KdXVFreeAdaptor(pa); + continue; + } + + pa->base_id = pPort->id; + + pa++; + numAdaptor++; + } + + if(numAdaptor) { + pxvs->nAdaptors = numAdaptor; + pxvs->pAdaptors = pAdaptor; + } else { + free(pAdaptor); + return FALSE; + } + + return TRUE; +} + +/* Video should be clipped to the intersection of the window cliplist + and the client cliplist specified in the GC for which the video was + initialized. When we need to reclip a window, the GC that started + the video may not even be around anymore. That's why we save the + client clip from the GC when the video is initialized. We then + use KdXVUpdateCompositeClip to calculate the new composite clip + when we need it. This is different from what DEC did. They saved + the GC and used it's clip list when they needed to reclip the window, + even if the client clip was different from the one the video was + initialized with. If the original GC was destroyed, they had to stop + the video. I like the new method better (MArk). + + This function only works for windows. Will need to rewrite when + (if) we support pixmap rendering. +*/ + +static void +KdXVUpdateCompositeClip(XvPortRecPrivatePtr portPriv) +{ + RegionPtr pregWin, pCompositeClip; + WindowPtr pWin; + Bool freeCompClip = FALSE; + + if(portPriv->pCompositeClip) + return; + + pWin = (WindowPtr)portPriv->pDraw; + + /* get window clip list */ + if(portPriv->subWindowMode == IncludeInferiors) { + pregWin = NotClippedByChildren(pWin); + freeCompClip = TRUE; + } else + pregWin = &pWin->clipList; + + if(!portPriv->clientClip) { + portPriv->pCompositeClip = pregWin; + portPriv->FreeCompositeClip = freeCompClip; + return; + } + + pCompositeClip = REGION_CREATE(pWin->pScreen, NullBox, 1); + REGION_COPY(pWin->pScreen, pCompositeClip, portPriv->clientClip); + REGION_TRANSLATE(pWin->pScreen, pCompositeClip, + portPriv->pDraw->x + portPriv->clipOrg.x, + portPriv->pDraw->y + portPriv->clipOrg.y); + REGION_INTERSECT(pWin->pScreen, pCompositeClip, pregWin, pCompositeClip); + + portPriv->pCompositeClip = pCompositeClip; + portPriv->FreeCompositeClip = TRUE; + + if(freeCompClip) { + REGION_DESTROY(pWin->pScreen, pregWin); + } +} + +/* Save the current clientClip and update the CompositeClip whenever + we have a fresh GC */ + +static void +KdXVCopyClip( + XvPortRecPrivatePtr portPriv, + GCPtr pGC +){ + /* copy the new clip if it exists */ + if((pGC->clientClipType == CT_REGION) && pGC->clientClip) { + if(!portPriv->clientClip) + portPriv->clientClip = REGION_CREATE(pGC->pScreen, NullBox, 1); + /* Note: this is in window coordinates */ + REGION_COPY(pGC->pScreen, portPriv->clientClip, pGC->clientClip); + } else if(portPriv->clientClip) { /* free the old clientClip */ + REGION_DESTROY(pGC->pScreen, portPriv->clientClip); + portPriv->clientClip = NULL; + } + + /* get rid of the old clip list */ + if(portPriv->pCompositeClip && portPriv->FreeCompositeClip) { + REGION_DESTROY(pWin->pScreen, portPriv->pCompositeClip); + } + + portPriv->clipOrg = pGC->clipOrg; + portPriv->pCompositeClip = pGC->pCompositeClip; + portPriv->FreeCompositeClip = FALSE; + portPriv->subWindowMode = pGC->subWindowMode; +} + +static int +KdXVRegetVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + KdXVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(portPriv->pDraw->pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(portPriv->pDraw->pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(portPriv->pDraw->pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(portPriv->pDraw->pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(portPriv->pDraw->pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetVideo)(portPriv->screen, portPriv->pDraw, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + + if(ret == Success) + portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(portPriv->pDraw->pScreen, &WinRegion); + REGION_UNINIT(portPriv->pDraw->pScreen, &ClipRegion); + + return ret; +} + + +static int +KdXVReputVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen = portPriv->pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + int ret = Success; + Bool clippedAway = FALSE; + + KdXVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutVideo)(portPriv->screen, portPriv->pDraw, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + + if(ret == Success) portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + +static int +KdXVReputImage(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen = portPriv->pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + int ret = Success; + Bool clippedAway = FALSE; + + KdXVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->ReputImage)(portPriv->screen, portPriv->pDraw, + WinBox.x1, WinBox.y1, + &ClipRegion, portPriv->DevPriv.ptr); + + portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +KdXVReputAllVideo(WindowPtr pWin, pointer data) +{ + KdXVWindowPtr WinPriv; + + if (pWin->drawable.type != DRAWABLE_WINDOW) + return WT_DONTWALKCHILDREN; + + WinPriv = GET_KDXV_WINDOW(pWin); + + while(WinPriv) { + if(WinPriv->PortRec->type == XvInputMask) + KdXVReputVideo(WinPriv->PortRec); + else + KdXVRegetVideo(WinPriv->PortRec); + WinPriv = WinPriv->next; + } + + return WT_WALKCHILDREN; +} + +static int +KdXVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + KdXVWindowPtr winPriv, PrivRoot; + + winPriv = PrivRoot = GET_KDXV_WINDOW(pWin); + + /* Enlist our port in the window private */ + while(winPriv) { + if(winPriv->PortRec == portPriv) /* we're already listed */ + break; + winPriv = winPriv->next; + } + + if(!winPriv) { + winPriv = malloc(sizeof(KdXVWindowRec)); + if(!winPriv) return BadAlloc; + winPriv->PortRec = portPriv; + winPriv->next = PrivRoot; + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv); + } + return Success; +} + + +static void +KdXVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + KdXVWindowPtr winPriv, prevPriv = NULL; + + winPriv = GET_KDXV_WINDOW(pWin); + + while(winPriv) { + if(winPriv->PortRec == portPriv) { + if(prevPriv) + prevPriv->next = winPriv->next; + else + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv->next); + free(winPriv); + break; + } + prevPriv = winPriv; + winPriv = winPriv->next; + } + portPriv->pDraw = NULL; +} + +/**** ScreenRec fields ****/ + + +static Bool +KdXVCreateWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + int ret; + + pScreen->CreateWindow = ScreenPriv->CreateWindow; + ret = (*pScreen->CreateWindow)(pWin); + pScreen->CreateWindow = KdXVCreateWindow; + + if (ret) + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, NULL); + + return ret; +} + + +static Bool +KdXVDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + KdXVWindowPtr tmp, WinPriv = GET_KDXV_WINDOW(pWin); + int ret; + + while(WinPriv) { + XvPortRecPrivatePtr pPriv = WinPriv->PortRec; + + if(pPriv->isOn > XV_OFF) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + } + + pPriv->pDraw = NULL; + tmp = WinPriv; + WinPriv = WinPriv->next; + free(tmp); + } + + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, NULL); + + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + ret = (*pScreen->DestroyWindow)(pWin); + pScreen->DestroyWindow = KdXVDestroyWindow; + + return ret; +} + + +static void +KdXVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); + KdXVWindowPtr pPrev; + XvPortRecPrivatePtr pPriv; + Bool AreasExposed; + + AreasExposed = (WinPriv && reg1 && REGION_NOTEMPTY(pScreen, reg1)); + + pScreen->WindowExposures = ScreenPriv->WindowExposures; + (*pScreen->WindowExposures)(pWin, reg1, reg2); + pScreen->WindowExposures = KdXVWindowExposures; + + /* filter out XClearWindow/Area */ + if (!pWin->valdata) return; + + pPrev = NULL; + + while(WinPriv) { + pPriv = WinPriv->PortRec; + + /* Reput anyone with a reput function */ + + switch(pPriv->type) { + case XvInputMask: + KdXVReputVideo(pPriv); + break; + case XvOutputMask: + KdXVRegetVideo(pPriv); + break; + default: /* overlaid still/image*/ + if (pPriv->AdaptorRec->ReputImage) + KdXVReputImage(pPriv); + else if(AreasExposed) { + KdXVWindowPtr tmp; + + if (pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, FALSE); + pPriv->isOn = XV_PENDING; + } + pPriv->pDraw = NULL; + + if(!pPrev) + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, WinPriv->next); + else + pPrev->next = WinPriv->next; + tmp = WinPriv; + WinPriv = WinPriv->next; + free(tmp); + continue; + } + break; + } + pPrev = WinPriv; + WinPriv = WinPriv->next; + } +} + + +static void +KdXVClipNotify(WindowPtr pWin, int dx, int dy) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); + KdXVWindowPtr tmp, pPrev = NULL; + XvPortRecPrivatePtr pPriv; + Bool visible = (pWin->visibility == VisibilityUnobscured) || + (pWin->visibility == VisibilityPartiallyObscured); + + while(WinPriv) { + pPriv = WinPriv->PortRec; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pScreen, pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + /* Stop everything except images, but stop them too if the + window isn't visible. But we only remove the images. */ + + if(pPriv->type || !visible) { + if(pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, FALSE); + pPriv->isOn = XV_PENDING; + } + + if(!pPriv->type) { /* overlaid still/image */ + pPriv->pDraw = NULL; + + if(!pPrev) + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, WinPriv->next); + else + pPrev->next = WinPriv->next; + tmp = WinPriv; + WinPriv = WinPriv->next; + free(tmp); + continue; + } + } + + pPrev = WinPriv; + WinPriv = WinPriv->next; + } + + if(ScreenPriv->ClipNotify) { + pScreen->ClipNotify = ScreenPriv->ClipNotify; + (*pScreen->ClipNotify)(pWin, dx, dy); + pScreen->ClipNotify = KdXVClipNotify; + } +} + + + +/**** Required XvScreenRec fields ****/ + +static Bool +KdXVCloseScreen(int i, ScreenPtr pScreen) +{ + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + XvAdaptorPtr pa; + int c; + + if(!ScreenPriv) return TRUE; + + pScreen->CreateWindow = ScreenPriv->CreateWindow; + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + pScreen->WindowExposures = ScreenPriv->WindowExposures; + pScreen->ClipNotify = ScreenPriv->ClipNotify; + +/* fprintf(stderr,"XV: Unwrapping screen funcs\n"); */ + + for(c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) { + KdXVFreeAdaptor(pa); + } + + free(pxvs->pAdaptors); + free(ScreenPriv); + + return TRUE; +} + + +static int +KdXVQueryAdaptors( + ScreenPtr pScreen, + XvAdaptorPtr *p_pAdaptors, + int *p_nAdaptors +){ + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + + *p_nAdaptors = pxvs->nAdaptors; + *p_pAdaptors = pxvs->pAdaptors; + + return (Success); +} + +static Bool +KdXVRunning (ScreenPtr pScreen) +{ + return (KdXVGeneration == serverGeneration && + GET_XV_SCREEN(pScreen) != 0); +} + +Bool +KdXVEnable(ScreenPtr pScreen) +{ + if (!KdXVRunning (pScreen)) + return TRUE; + + WalkTree(pScreen, KdXVReputAllVideo, 0); + + return TRUE; +} + +void +KdXVDisable(ScreenPtr pScreen) +{ + XvScreenPtr pxvs; + KdXVScreenPtr ScreenPriv; + XvAdaptorPtr pAdaptor; + XvPortPtr pPort; + XvPortRecPrivatePtr pPriv; + int i, j; + + if (!KdXVRunning (pScreen)) + return; + + pxvs = GET_XV_SCREEN(pScreen); + ScreenPriv = GET_KDXV_SCREEN(pScreen); + + for(i = 0; i < pxvs->nAdaptors; i++) { + pAdaptor = &pxvs->pAdaptors[i]; + for(j = 0; j < pAdaptor->nPorts; j++) { + pPort = &pAdaptor->pPorts[j]; + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv->isOn > XV_OFF) { + + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pScreen, pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + if(!pPriv->type && pPriv->pDraw) { /* still */ + KdXVRemovePortFromWindow((WindowPtr)pPriv->pDraw, pPriv); + } + } + } + } +} + +/**** XvAdaptorRec fields ****/ + +static int +KdXVAllocatePort( + unsigned long port, + XvPortPtr pPort, + XvPortPtr *ppPort +){ + *ppPort = pPort; + return Success; +} + +static int +KdXVFreePort(XvPortPtr pPort) +{ + return Success; +} + +static int +KdXVPutVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + KdScreenPriv(portPriv->screen->pScreen); + int result; + + /* No dumping video to pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->pDraw = pDraw; + portPriv->type = XvInputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + KdXVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if (!pScreenPriv->enabled) return Success; + + return(KdXVReputVideo(portPriv)); +} + +static int +KdXVPutStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen = pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if (!pScreenPriv->enabled) return Success; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + if(portPriv->pDraw) { + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutStill)(portPriv->screen, pDraw, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) { + + KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + portPriv->isOn = XV_ON; + portPriv->pDraw = pDraw; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + +static int +KdXVGetVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + int result; + KdScreenPriv(portPriv->screen->pScreen); + + /* No pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->pDraw = pDraw; + portPriv->type = XvOutputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + KdXVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if(!pScreenPriv->enabled) return Success; + + return(KdXVRegetVideo(portPriv)); +} + +static int +KdXVGetStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen = pDraw->pScreen; + KdScreenPriv(pScreen); + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!pScreenPriv->enabled) return Success; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->pDraw) { + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto GET_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetStill)(portPriv->screen, pDraw, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + +GET_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + + +static int +KdXVStopVideo( + ClientPtr client, + XvPortPtr pPort, + DrawablePtr pDraw +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + KdScreenPriv(portPriv->screen->pScreen); + + if(pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + KdXVRemovePortFromWindow((WindowPtr)pDraw, portPriv); + + if(!pScreenPriv->enabled) return Success; + + /* Must free resources. */ + + if(portPriv->isOn > XV_OFF) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, TRUE); + portPriv->isOn = XV_OFF; + } + + return Success; +} + +static int +KdXVSetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->SetPortAttribute)(portPriv->screen, + attribute, value, portPriv->DevPriv.ptr)); +} + + +static int +KdXVGetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 *p_value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->GetPortAttribute)(portPriv->screen, + attribute, (int *) p_value, portPriv->DevPriv.ptr)); +} + + + +static int +KdXVQueryBestSize( + ClientPtr client, + XvPortPtr pPort, + CARD8 motion, + CARD16 vid_w, CARD16 vid_h, + CARD16 drw_w, CARD16 drw_h, + unsigned int *p_w, unsigned int *p_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + (*portPriv->AdaptorRec->QueryBestSize)(portPriv->screen, + (Bool)motion, vid_w, vid_h, drw_w, drw_h, + p_w, p_h, portPriv->DevPriv.ptr); + + return Success; +} + + +static int +KdXVPutImage( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 src_x, INT16 src_y, + CARD16 src_w, CARD16 src_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h, + XvImagePtr format, + unsigned char* data, + Bool sync, + CARD16 width, CARD16 height +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen = pDraw->pScreen; + KdScreenPriv(pScreen); + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!pScreenPriv->enabled) return Success; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = pScreen->width; + VPBox.y2 = pScreen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + if(portPriv->pDraw) { + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutImage)(portPriv->screen, pDraw, + src_x, src_y, WinBox.x1, WinBox.y1, + src_w, src_h, drw_w, drw_h, format->id, data, width, height, + sync, &ClipRegion, portPriv->DevPriv.ptr); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) { + + KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + portPriv->isOn = XV_ON; + portPriv->pDraw = pDraw; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_IMAGE_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +KdXVQueryImageAttributes( + ClientPtr client, + XvPortPtr pPort, + XvImagePtr format, + CARD16 *width, + CARD16 *height, + int *pitches, + int *offsets +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return (*portPriv->AdaptorRec->QueryImageAttributes)(portPriv->screen, + format->id, width, height, pitches, offsets); +} + + +/**************** Common video manipulation functions *******************/ + +void +KdXVCopyPackedData(KdScreenInfo *screen, CARD8 *src, CARD8 *dst, int randr, + int srcPitch, int dstPitch, int srcW, int srcH, int top, int left, + int h, int w) +{ + int srcDown = srcPitch, srcRight = 2, srcNext; + int p; + + switch (randr & RR_Rotate_All) { + case RR_Rotate_0: + srcDown = srcPitch; + srcRight = 2; + break; + case RR_Rotate_90: + src += (srcH - 1) * 2; + srcDown = -2; + srcRight = srcPitch; + break; + case RR_Rotate_180: + src += srcPitch * (srcH - 1) + (srcW - 1) * 2; + srcDown = -srcPitch; + srcRight = -2; + break; + case RR_Rotate_270: + src += srcPitch * (srcW - 1); + srcDown = 2; + srcRight = -srcPitch; + break; + } + + src = src + top * srcDown + left * srcRight; + + w >>= 1; + /* srcRight >>= 1; */ + srcNext = srcRight >> 1; + while (h--) { + CARD16 *s = (CARD16 *)src; + CARD32 *d = (CARD32 *)dst; + p = w; + while (p--) { + *d++ = s[0] | (s[srcNext] << 16); + s += srcRight; + } + src += srcPitch; + dst += dstPitch; + } +} + +void +KdXVCopyPlanarData(KdScreenInfo *screen, CARD8 *src, CARD8 *dst, int randr, + int srcPitch, int srcPitch2, int dstPitch, int srcW, int srcH, int height, + int top, int left, int h, int w, int id) +{ + int i, j; + CARD8 *src1, *src2, *src3, *dst1; + int srcDown = srcPitch, srcDown2 = srcPitch2; + int srcRight = 2, srcRight2 = 1, srcNext = 1; + + /* compute source data pointers */ + src1 = src; + src2 = src1 + height * srcPitch; + src3 = src2 + (height >> 1) * srcPitch2; + switch (randr & RR_Rotate_All) { + case RR_Rotate_0: + srcDown = srcPitch; + srcDown2 = srcPitch2; + srcRight = 2; + srcRight2 = 1; + srcNext = 1; + break; + case RR_Rotate_90: + src1 = src1 + srcH - 1; + src2 = src2 + (srcH >> 1) - 1; + src3 = src3 + (srcH >> 1) - 1; + srcDown = -1; + srcDown2 = -1; + srcRight = srcPitch * 2; + srcRight2 = srcPitch2; + srcNext = srcPitch; + break; + case RR_Rotate_180: + src1 = src1 + srcPitch * (srcH - 1) + (srcW - 1); + src2 = src2 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); + src3 = src3 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); + srcDown = -srcPitch; + srcDown2 = -srcPitch2; + srcRight = -2; + srcRight2 = -1; + srcNext = -1; + break; + case RR_Rotate_270: + src1 = src1 + srcPitch * (srcW - 1); + src2 = src2 + srcPitch2 * ((srcW >> 1) - 1); + src3 = src3 + srcPitch2 * ((srcW >> 1) - 1); + srcDown = 1; + srcDown2 = 1; + srcRight = -srcPitch * 2; + srcRight2 = -srcPitch2; + srcNext = -srcPitch; + break; + } + + /* adjust for origin */ + src1 += top * srcDown + left * srcNext; + src2 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; + src3 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; + + if (id == FOURCC_I420) { + CARD8 *srct = src2; + src2 = src3; + src3 = srct; + } + + dst1 = dst; + + w >>= 1; + for (j = 0; j < h; j++) { + CARD32 *dst = (CARD32 *)dst1; + CARD8 *s1l = src1; + CARD8 *s1r = src1 + srcNext; + CARD8 *s2 = src2; + CARD8 *s3 = src3; + + for (i = 0; i < w; i++) { + *dst++ = *s1l | (*s1r << 16) | (*s3 << 8) | (*s2 << 24); + s1l += srcRight; + s1r += srcRight; + s2 += srcRight2; + s3 += srcRight2; + } + src1 += srcDown; + dst1 += dstPitch; + if (j & 1) { + src2 += srcDown2; + src3 += srcDown2; + } + } +} + +void +KXVPaintRegion (DrawablePtr pDraw, RegionPtr pRgn, Pixel fg) +{ + GCPtr pGC; + ChangeGCVal val[2]; + xRectangle *rects, *r; + BoxPtr pBox = REGION_RECTS (pRgn); + int nBox = REGION_NUM_RECTS (pRgn); + + rects = malloc(nBox * sizeof (xRectangle)); + if (!rects) + goto bail0; + r = rects; + while (nBox--) + { + r->x = pBox->x1 - pDraw->x; + r->y = pBox->y1 - pDraw->y; + r->width = pBox->x2 - pBox->x1; + r->height = pBox->y2 - pBox->y1; + r++; + pBox++; + } + + pGC = GetScratchGC (pDraw->depth, pDraw->pScreen); + if (!pGC) + goto bail1; + + val[0].val = fg; + val[1].val = IncludeInferiors; + ChangeGC (NullClient, pGC, GCForeground|GCSubwindowMode, val); + + ValidateGC (pDraw, pGC); + + (*pGC->ops->PolyFillRect) (pDraw, pGC, + REGION_NUM_RECTS (pRgn), rects); + + FreeScratchGC (pGC); +bail1: + free(rects); +bail0: + ; +} diff --git a/xorg-server/hw/vfb/InitOutput.c b/xorg-server/hw/vfb/InitOutput.c index 29857877e..30e68e5d3 100644 --- a/xorg-server/hw/vfb/InitOutput.c +++ b/xorg-server/hw/vfb/InitOutput.c @@ -1,973 +1,973 @@ -/* - -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 <dix-config.h> -#endif - -#if defined(WIN32) -#include <X11/Xwinsock.h> -#endif -#include <stdio.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/Xos.h> -#include "scrnintstr.h" -#include "servermd.h" -#define PSZ 8 -#include "fb.h" -#include "mibstore.h" -#include "colormapst.h" -#include "gcstruct.h" -#include "input.h" -#include "mipointer.h" -#include "micmap.h" -#include <sys/types.h> -#ifdef HAS_MMAP -#include <sys/mman.h> -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif -#endif /* HAS_MMAP */ -#include <sys/stat.h> -#include <errno.h> -#ifndef WIN32 -#include <sys/param.h> -#endif -#include <X11/XWDFile.h> -#ifdef HAS_SHM -#include <sys/ipc.h> -#include <sys/shm.h> -#endif /* HAS_SHM */ -#include "dix.h" -#include "miline.h" - -#define VFB_DEFAULT_WIDTH 1280 -#define VFB_DEFAULT_HEIGHT 1024 -#define VFB_DEFAULT_DEPTH 8 -#define VFB_DEFAULT_WHITEPIXEL 1 -#define VFB_DEFAULT_BLACKPIXEL 0 -#define VFB_DEFAULT_LINEBIAS 0 -#define XWD_WINDOW_NAME_LEN 60 - -typedef struct -{ - int width; - int paddedBytesWidth; - int paddedWidth; - int height; - int depth; - int bitsPerPixel; - int sizeInBytes; - int ncolors; - char *pfbMemory; - XWDColor *pXWDCmap; - XWDFileHeader *pXWDHeader; - Pixel blackPixel; - Pixel whitePixel; - unsigned int lineBias; - CloseScreenProcPtr closeScreen; - -#ifdef HAS_MMAP - int mmap_fd; - char mmap_file[MAXPATHLEN]; -#endif - -#ifdef HAS_SHM - int shmid; -#endif -} vfbScreenInfo, *vfbScreenInfoPtr; - -static int vfbNumScreens; -static vfbScreenInfo *vfbScreens; -static vfbScreenInfo defaultScreenInfo = { - .width = VFB_DEFAULT_WIDTH, - .height = VFB_DEFAULT_HEIGHT, - .depth = VFB_DEFAULT_DEPTH, - .blackPixel = VFB_DEFAULT_BLACKPIXEL, - .whitePixel = VFB_DEFAULT_WHITEPIXEL, - .lineBias = VFB_DEFAULT_LINEBIAS, -}; -static Bool vfbPixmapDepths[33]; -#ifdef HAS_MMAP -static char *pfbdir = NULL; -#endif -typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB, MMAPPED_FILE_FB } fbMemType; -static fbMemType fbmemtype = NORMAL_MEMORY_FB; -static char needswap = 0; -static Bool Render = TRUE; - -#define swapcopy16(_dst, _src) \ - if (needswap) { CARD16 _s = _src; cpswaps(_s, _dst); } \ - else _dst = _src; - -#define swapcopy32(_dst, _src) \ - if (needswap) { CARD32 _s = _src; cpswapl(_s, _dst); } \ - else _dst = _src; - - -static void -vfbInitializePixmapDepths(void) -{ - int i; - vfbPixmapDepths[1] = TRUE; /* always need bitmaps */ - for (i = 2; i <= 32; i++) - vfbPixmapDepths[i] = FALSE; -} - -static int -vfbBitsPerPixel(int depth) -{ - if (depth == 1) return 1; - else if (depth <= 8) return 8; - else if (depth <= 16) return 16; - else return 32; -} - -void -ddxGiveUp(void) -{ - int i; - - /* clean up the framebuffers */ - - switch (fbmemtype) - { -#ifdef HAS_MMAP - case MMAPPED_FILE_FB: - for (i = 0; i < vfbNumScreens; i++) - { - if (-1 == unlink(vfbScreens[i].mmap_file)) - { - perror("unlink"); - ErrorF("unlink %s failed, %s", - vfbScreens[i].mmap_file, strerror(errno)); - } - } - break; -#else /* HAS_MMAP */ - case MMAPPED_FILE_FB: - break; -#endif /* HAS_MMAP */ - -#ifdef HAS_SHM - case SHARED_MEMORY_FB: - for (i = 0; i < vfbNumScreens; i++) - { - if (-1 == shmdt((char *)vfbScreens[i].pXWDHeader)) - { - perror("shmdt"); - ErrorF("shmdt failed, %s", strerror(errno)); - } - } - break; -#else /* HAS_SHM */ - case SHARED_MEMORY_FB: - break; -#endif /* HAS_SHM */ - - case NORMAL_MEMORY_FB: - for (i = 0; i < vfbNumScreens; i++) - { - Xfree(vfbScreens[i].pXWDHeader); - } - break; - } -} - -void -AbortDDX(void) -{ - ddxGiveUp(); -} - -#ifdef __APPLE__ -void -DarwinHandleGUI(int argc, char *argv[]) -{ -} -#endif - -void -OsVendorInit(void) -{ -} - -void -OsVendorFatalError(void) -{ -} - -#if defined(DDXBEFORERESET) -void ddxBeforeReset(void) -{ - return; -} -#endif - -void -ddxUseMsg(void) -{ - ErrorF("-screen scrn WxHxD set screen's width, height, depth\n"); - ErrorF("-pixdepths list-of-int support given pixmap depths\n"); - ErrorF("+/-render turn on/off RENDER extension support" - "(default on)\n"); - ErrorF("-linebias n adjust thin line pixelization\n"); - ErrorF("-blackpixel n pixel value for black\n"); - ErrorF("-whitepixel n pixel value for white\n"); - -#ifdef HAS_MMAP - ErrorF("-fbdir directory put framebuffers in mmap'ed files in directory\n"); -#endif - -#ifdef HAS_SHM - ErrorF("-shmem put framebuffers in shared memory\n"); -#endif -} - -int -ddxProcessArgument(int argc, char *argv[], int i) -{ - static Bool firstTime = TRUE; - static int lastScreen = -1; - vfbScreenInfo *currentScreen; - - if (firstTime) - { - vfbInitializePixmapDepths(); - firstTime = FALSE; - } - - if (lastScreen == -1) - currentScreen = &defaultScreenInfo; - else - currentScreen = &vfbScreens[lastScreen]; - -#define CHECK_FOR_REQUIRED_ARGUMENTS(num) \ - if (((i + num) >= argc) || (!argv[i + num])) { \ - ErrorF("Required argument to %s not specified\n", argv[i]); \ - UseMsg(); \ - FatalError("Required argument to %s not specified\n", argv[i]); \ - } - - if (strcmp (argv[i], "-screen") == 0) /* -screen n WxHxD */ - { - int screenNum; - CHECK_FOR_REQUIRED_ARGUMENTS(2); - screenNum = atoi(argv[i+1]); - if (screenNum < 0) - { - ErrorF("Invalid screen number %d\n", screenNum); - UseMsg(); - FatalError("Invalid screen number %d passed to -screen\n", - screenNum); - } - - if (vfbNumScreens <= screenNum) - { - vfbScreens = xrealloc(vfbScreens, sizeof(*vfbScreens) * (screenNum + 1)); - if (!vfbScreens) - FatalError("Not enough memory for screen %d\n", screenNum); - for (; vfbNumScreens <= screenNum; ++vfbNumScreens) - vfbScreens[vfbNumScreens] = defaultScreenInfo; - } - - if (3 != sscanf(argv[i+2], "%dx%dx%d", - &vfbScreens[screenNum].width, - &vfbScreens[screenNum].height, - &vfbScreens[screenNum].depth)) - { - ErrorF("Invalid screen configuration %s\n", argv[i+2]); - UseMsg(); - FatalError("Invalid screen configuration %s for -screen %d\n", - argv[i+2], screenNum); - } - - lastScreen = screenNum; - return 3; - } - - if (strcmp (argv[i], "-pixdepths") == 0) /* -pixdepths list-of-depth */ - { - int depth, ret = 1; - - CHECK_FOR_REQUIRED_ARGUMENTS(1); - while ((++i < argc) && (depth = atoi(argv[i])) != 0) - { - if (depth < 0 || depth > 32) - { - ErrorF("Invalid pixmap depth %d\n", depth); - UseMsg(); - FatalError("Invalid pixmap depth %d passed to -pixdepths\n", - depth); - } - vfbPixmapDepths[depth] = TRUE; - ret++; - } - return ret; - } - - if (strcmp (argv[i], "+render") == 0) /* +render */ - { - Render = TRUE; - return 1; - } - - if (strcmp (argv[i], "-render") == 0) /* -render */ - { - Render = FALSE; -#ifdef COMPOSITE - noCompositeExtension = TRUE; -#endif - return 1; - } - - if (strcmp (argv[i], "-blackpixel") == 0) /* -blackpixel n */ - { - CHECK_FOR_REQUIRED_ARGUMENTS(1); - currentScreen->blackPixel = atoi(argv[++i]); - return 2; - } - - if (strcmp (argv[i], "-whitepixel") == 0) /* -whitepixel n */ - { - CHECK_FOR_REQUIRED_ARGUMENTS(1); - currentScreen->whitePixel = atoi(argv[++i]); - return 2; - } - - if (strcmp (argv[i], "-linebias") == 0) /* -linebias n */ - { - CHECK_FOR_REQUIRED_ARGUMENTS(1); - currentScreen->lineBias = atoi(argv[++i]); - return 2; - } - -#ifdef HAS_MMAP - if (strcmp (argv[i], "-fbdir") == 0) /* -fbdir directory */ - { - CHECK_FOR_REQUIRED_ARGUMENTS(1); - pfbdir = argv[++i]; - fbmemtype = MMAPPED_FILE_FB; - return 2; - } -#endif /* HAS_MMAP */ - -#ifdef HAS_SHM - if (strcmp (argv[i], "-shmem") == 0) /* -shmem */ - { - fbmemtype = SHARED_MEMORY_FB; - return 1; - } -#endif - - return 0; -} - -static int cmapScrPrivateKeyIndex; -static DevPrivateKey cmapScrPrivateKey = &cmapScrPrivateKeyIndex; - -#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey)) -#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c)) - -static int -vfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) -{ - /* By the time we are processing requests, we can guarantee that there - * is always a colormap installed */ - *pmaps = GetInstalledColormap(pScreen)->mid; - return (1); -} - - -static void -vfbInstallColormap(ColormapPtr pmap) -{ - ColormapPtr oldpmap = GetInstalledColormap(pmap->pScreen); - - if (pmap != oldpmap) - { - int entries; - XWDFileHeader *pXWDHeader; - XWDColor *pXWDCmap; - VisualPtr pVisual; - Pixel * ppix; - xrgb * prgb; - xColorItem *defs; - int i; - - if(oldpmap != (ColormapPtr)None) - WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); - /* Install pmap */ - SetInstalledColormap(pmap->pScreen, pmap); - WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); - - entries = pmap->pVisual->ColormapEntries; - pXWDHeader = vfbScreens[pmap->pScreen->myNum].pXWDHeader; - pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap; - pVisual = pmap->pVisual; - - swapcopy32(pXWDHeader->visual_class, pVisual->class); - swapcopy32(pXWDHeader->red_mask, pVisual->redMask); - swapcopy32(pXWDHeader->green_mask, pVisual->greenMask); - swapcopy32(pXWDHeader->blue_mask, pVisual->blueMask); - swapcopy32(pXWDHeader->bits_per_rgb, pVisual->bitsPerRGBValue); - swapcopy32(pXWDHeader->colormap_entries, pVisual->ColormapEntries); - - ppix = (Pixel *)xalloc(entries * sizeof(Pixel)); - prgb = (xrgb *)xalloc(entries * sizeof(xrgb)); - defs = (xColorItem *)xalloc(entries * sizeof(xColorItem)); - - for (i = 0; i < entries; i++) ppix[i] = i; - /* XXX truecolor */ - QueryColors(pmap, entries, ppix, prgb); - - for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */ - defs[i].pixel = ppix[i] & 0xff; /* change pixel to index */ - defs[i].red = prgb[i].red; - defs[i].green = prgb[i].green; - defs[i].blue = prgb[i].blue; - defs[i].flags = DoRed|DoGreen|DoBlue; - } - (*pmap->pScreen->StoreColors)(pmap, entries, defs); - - xfree(ppix); - xfree(prgb); - xfree(defs); - } -} - -static void -vfbUninstallColormap(ColormapPtr pmap) -{ - ColormapPtr curpmap = GetInstalledColormap(pmap->pScreen); - - if(pmap == curpmap) - { - if (pmap->mid != pmap->pScreen->defColormap) - { - dixLookupResourceByType((pointer *)&curpmap, - pmap->pScreen->defColormap, - RT_COLORMAP, serverClient, - DixInstallAccess); - (*pmap->pScreen->InstallColormap)(curpmap); - } - } -} - -static void -vfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs) -{ - XWDColor *pXWDCmap; - int i; - - if (pmap != GetInstalledColormap(pmap->pScreen)) - { - return; - } - - pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap; - - if ((pmap->pVisual->class | DynamicClass) == DirectColor) - { - return; - } - - for (i = 0; i < ndef; i++) - { - if (pdefs[i].flags & DoRed) - { - swapcopy16(pXWDCmap[pdefs[i].pixel].red, pdefs[i].red); - } - if (pdefs[i].flags & DoGreen) - { - swapcopy16(pXWDCmap[pdefs[i].pixel].green, pdefs[i].green); - } - if (pdefs[i].flags & DoBlue) - { - swapcopy16(pXWDCmap[pdefs[i].pixel].blue, pdefs[i].blue); - } - } -} - -static Bool -vfbSaveScreen(ScreenPtr pScreen, int on) -{ - return TRUE; -} - -#ifdef HAS_MMAP - -/* this flushes any changes to the screens out to the mmapped file */ -static void -vfbBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask) -{ - int i; - - for (i = 0; i < vfbNumScreens; i++) - { -#ifdef MS_ASYNC - if (-1 == msync((caddr_t)vfbScreens[i].pXWDHeader, - (size_t)vfbScreens[i].sizeInBytes, MS_ASYNC)) -#else - /* silly NetBSD and who else? */ - if (-1 == msync((caddr_t)vfbScreens[i].pXWDHeader, - (size_t)vfbScreens[i].sizeInBytes)) -#endif - { - perror("msync"); - ErrorF("msync failed, %s", strerror(errno)); - } - } -} - - -static void -vfbWakeupHandler(pointer blockData, int result, pointer pReadmask) -{ -} - - -static void -vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb) -{ -#define DUMMY_BUFFER_SIZE 65536 - char dummyBuffer[DUMMY_BUFFER_SIZE]; - int currentFileSize, writeThisTime; - - sprintf(pvfb->mmap_file, "%s/Xvfb_screen%d", pfbdir, (int) (pvfb - vfbScreens)); - if (-1 == (pvfb->mmap_fd = open(pvfb->mmap_file, O_CREAT|O_RDWR, 0666))) - { - perror("open"); - ErrorF("open %s failed, %s", pvfb->mmap_file, strerror(errno)); - return; - } - - /* Extend the file to be the proper size */ - - bzero(dummyBuffer, DUMMY_BUFFER_SIZE); - for (currentFileSize = 0; - currentFileSize < pvfb->sizeInBytes; - currentFileSize += writeThisTime) - { - writeThisTime = min(DUMMY_BUFFER_SIZE, - pvfb->sizeInBytes - currentFileSize); - if (-1 == write(pvfb->mmap_fd, dummyBuffer, writeThisTime)) - { - perror("write"); - ErrorF("write %s failed, %s", pvfb->mmap_file, strerror(errno)); - return; - } - } - - /* try to mmap the file */ - - pvfb->pXWDHeader = (XWDFileHeader *)mmap((caddr_t)NULL, pvfb->sizeInBytes, - PROT_READ|PROT_WRITE, - MAP_FILE|MAP_SHARED, - pvfb->mmap_fd, 0); - if (-1 == (long)pvfb->pXWDHeader) - { - perror("mmap"); - ErrorF("mmap %s failed, %s", pvfb->mmap_file, strerror(errno)); - pvfb->pXWDHeader = NULL; - return; - } - - if (!RegisterBlockAndWakeupHandlers(vfbBlockHandler, vfbWakeupHandler, - NULL)) - { - pvfb->pXWDHeader = NULL; - } -} -#endif /* HAS_MMAP */ - - -#ifdef HAS_SHM -static void -vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb) -{ - /* create the shared memory segment */ - - pvfb->shmid = shmget(IPC_PRIVATE, pvfb->sizeInBytes, IPC_CREAT|0777); - if (pvfb->shmid < 0) - { - perror("shmget"); - ErrorF("shmget %d bytes failed, %s", pvfb->sizeInBytes, strerror(errno)); - return; - } - - /* try to attach it */ - - pvfb->pXWDHeader = (XWDFileHeader *)shmat(pvfb->shmid, 0, 0); - if (-1 == (long)pvfb->pXWDHeader) - { - perror("shmat"); - ErrorF("shmat failed, %s", strerror(errno)); - pvfb->pXWDHeader = NULL; - return; - } - - ErrorF("screen %d shmid %d\n", (int) (pvfb - vfbScreens), pvfb->shmid); -} -#endif /* HAS_SHM */ - -static char * -vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb) -{ - if (pvfb->pfbMemory) return pvfb->pfbMemory; /* already done */ - - pvfb->sizeInBytes = pvfb->paddedBytesWidth * pvfb->height; - - /* Calculate how many entries in colormap. This is rather bogus, because - * the visuals haven't even been set up yet, but we need to know because we - * have to allocate space in the file for the colormap. The number 10 - * below comes from the MAX_PSEUDO_DEPTH define in cfbcmap.c. - */ - - if (pvfb->depth <= 10) - { /* single index colormaps */ - pvfb->ncolors = 1 << pvfb->depth; - } - else - { /* decomposed colormaps */ - int nplanes_per_color_component = pvfb->depth / 3; - if (pvfb->depth % 3) nplanes_per_color_component++; - pvfb->ncolors = 1 << nplanes_per_color_component; - } - - /* add extra bytes for XWDFileHeader, window name, and colormap */ - - pvfb->sizeInBytes += SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN + - pvfb->ncolors * SIZEOF(XWDColor); - - pvfb->pXWDHeader = NULL; - switch (fbmemtype) - { -#ifdef HAS_MMAP - case MMAPPED_FILE_FB: vfbAllocateMmappedFramebuffer(pvfb); break; -#else - case MMAPPED_FILE_FB: break; -#endif - -#ifdef HAS_SHM - case SHARED_MEMORY_FB: vfbAllocateSharedMemoryFramebuffer(pvfb); break; -#else - case SHARED_MEMORY_FB: break; -#endif - - case NORMAL_MEMORY_FB: - pvfb->pXWDHeader = (XWDFileHeader *)Xalloc(pvfb->sizeInBytes); - break; - } - - if (pvfb->pXWDHeader) - { - pvfb->pXWDCmap = (XWDColor *)((char *)pvfb->pXWDHeader - + SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN); - pvfb->pfbMemory = (char *)(pvfb->pXWDCmap + pvfb->ncolors); - - return pvfb->pfbMemory; - } - else - return NULL; -} - - -static void -vfbWriteXWDFileHeader(ScreenPtr pScreen) -{ - vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum]; - XWDFileHeader *pXWDHeader = pvfb->pXWDHeader; - char hostname[XWD_WINDOW_NAME_LEN]; - unsigned long swaptest = 1; - int i; - - needswap = *(char *) &swaptest; - - pXWDHeader->header_size = (char *)pvfb->pXWDCmap - (char *)pvfb->pXWDHeader; - pXWDHeader->file_version = XWD_FILE_VERSION; - - pXWDHeader->pixmap_format = ZPixmap; - pXWDHeader->pixmap_depth = pvfb->depth; - pXWDHeader->pixmap_height = pXWDHeader->window_height = pvfb->height; - pXWDHeader->xoffset = 0; - pXWDHeader->byte_order = IMAGE_BYTE_ORDER; - pXWDHeader->bitmap_bit_order = BITMAP_BIT_ORDER; -#ifndef INTERNAL_VS_EXTERNAL_PADDING - pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->width; - pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT; - pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD; -#else - pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->paddedWidth; - pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT_PROTO; - pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD_PROTO; -#endif - pXWDHeader->bits_per_pixel = pvfb->bitsPerPixel; - pXWDHeader->bytes_per_line = pvfb->paddedBytesWidth; - pXWDHeader->ncolors = pvfb->ncolors; - - /* visual related fields are written when colormap is installed */ - - pXWDHeader->window_x = pXWDHeader->window_y = 0; - pXWDHeader->window_bdrwidth = 0; - - /* write xwd "window" name: Xvfb hostname:server.screen */ - - if (-1 == gethostname(hostname, sizeof(hostname))) - hostname[0] = 0; - else - hostname[XWD_WINDOW_NAME_LEN-1] = 0; - sprintf((char *)(pXWDHeader+1), "Xvfb %s:%s.%d", hostname, display, - pScreen->myNum); - - /* write colormap pixel slot values */ - - for (i = 0; i < pvfb->ncolors; i++) - { - pvfb->pXWDCmap[i].pixel = i; - } - - /* byte swap to most significant byte first */ - - if (needswap) - { - SwapLongs((CARD32 *)pXWDHeader, SIZEOF(XWDheader)/4); - for (i = 0; i < pvfb->ncolors; i++) - { - register char n; - swapl(&pvfb->pXWDCmap[i].pixel, n); - } - } -} - - -static Bool -vfbCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y) -{ - return FALSE; -} - -static void -vfbCrossScreen (ScreenPtr pScreen, Bool entering) -{ -} - -static miPointerScreenFuncRec vfbPointerCursorFuncs = -{ - vfbCursorOffScreen, - vfbCrossScreen, - miPointerWarpCursor -}; - -static Bool -vfbCloseScreen(int index, ScreenPtr pScreen) -{ - vfbScreenInfoPtr pvfb = &vfbScreens[index]; - int i; - - pScreen->CloseScreen = pvfb->closeScreen; - - /* - * XXX probably lots of stuff to clean. For now, - * clear installed colormaps so that server reset works correctly. - */ - for (i = 0; i < screenInfo.numScreens; i++) - SetInstalledColormap(screenInfo.screens[i], NULL); - - return pScreen->CloseScreen(index, pScreen); -} - -static Bool -vfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) -{ - vfbScreenInfoPtr pvfb = &vfbScreens[index]; - int dpix = monitorResolution, dpiy = monitorResolution; - int ret; - char *pbits; - - if (dpix == 0) - dpix = 100; - - if (dpiy == 0) - dpiy = 100; - - pvfb->paddedBytesWidth = PixmapBytePad(pvfb->width, pvfb->depth); - pvfb->bitsPerPixel = vfbBitsPerPixel(pvfb->depth); - if (pvfb->bitsPerPixel >= 8 ) - pvfb->paddedWidth = pvfb->paddedBytesWidth / (pvfb->bitsPerPixel / 8); - else - pvfb->paddedWidth = pvfb->paddedBytesWidth * 8; - pbits = vfbAllocateFramebufferMemory(pvfb); - if (!pbits) return FALSE; - - switch (pvfb->depth) { - case 8: - miSetVisualTypesAndMasks (8, - ((1 << StaticGray) | - (1 << GrayScale) | - (1 << StaticColor) | - (1 << PseudoColor) | - (1 << TrueColor) | - (1 << DirectColor)), - 8, PseudoColor, 0, 0, 0); - break; - case 15: - miSetVisualTypesAndMasks (15, - ((1 << TrueColor) | - (1 << DirectColor)), - 8, TrueColor, 0x7c00, 0x03e0, 0x001f); - break; - case 16: - miSetVisualTypesAndMasks (16, - ((1 << TrueColor) | - (1 << DirectColor)), - 8, TrueColor, 0xf800, 0x07e0, 0x001f); - break; - case 24: - miSetVisualTypesAndMasks (24, - ((1 << TrueColor) | - (1 << DirectColor)), - 8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff); - break; - case 30: - miSetVisualTypesAndMasks (30, - ((1 << TrueColor) | - (1 << DirectColor)), - 10, TrueColor, 0x3ff00000, 0x000ffc00, 0x000003ff); - break; - } - - miSetPixmapDepths (); - - ret = fbScreenInit(pScreen, pbits, pvfb->width, pvfb->height, - dpix, dpiy, pvfb->paddedWidth,pvfb->bitsPerPixel); - if (ret && Render) - fbPictureInit (pScreen, 0, 0); - - if (!ret) return FALSE; - - miInitializeBackingStore(pScreen); - - /* - * Circumvent the backing store that was just initialised. This amounts - * to a truely bizarre way of initialising SaveDoomedAreas and friends. - */ - - pScreen->InstallColormap = vfbInstallColormap; - pScreen->UninstallColormap = vfbUninstallColormap; - pScreen->ListInstalledColormaps = vfbListInstalledColormaps; - - pScreen->SaveScreen = vfbSaveScreen; - pScreen->StoreColors = vfbStoreColors; - - miDCInitialize(pScreen, &vfbPointerCursorFuncs); - - vfbWriteXWDFileHeader(pScreen); - - pScreen->blackPixel = pvfb->blackPixel; - pScreen->whitePixel = pvfb->whitePixel; - - ret = fbCreateDefColormap(pScreen); - - miSetZeroLineBias(pScreen, pvfb->lineBias); - - pvfb->closeScreen = pScreen->CloseScreen; - pScreen->CloseScreen = vfbCloseScreen; - - return ret; - -} /* end vfbScreenInit */ - - -void -InitOutput(ScreenInfo *screenInfo, int argc, char **argv) -{ - int i; - int NumFormats = 0; - - /* initialize pixmap formats */ - - /* must have a pixmap depth to match every screen depth */ - for (i = 0; i < vfbNumScreens; i++) - { - vfbPixmapDepths[vfbScreens[i].depth] = TRUE; - } - - /* RENDER needs a good set of pixmaps. */ - if (Render) { - vfbPixmapDepths[1] = TRUE; - vfbPixmapDepths[4] = TRUE; - vfbPixmapDepths[8] = TRUE; -#if 0 - vfbPixmapDepths[12] = TRUE; -#endif -/* vfbPixmapDepths[15] = TRUE; */ - vfbPixmapDepths[16] = TRUE; - vfbPixmapDepths[24] = TRUE; -#if 0 - vfbPixmapDepths[30] = TRUE; -#endif - vfbPixmapDepths[32] = TRUE; - } - - for (i = 1; i <= 32; i++) - { - if (vfbPixmapDepths[i]) - { - if (NumFormats >= MAXFORMATS) - FatalError ("MAXFORMATS is too small for this server\n"); - screenInfo->formats[NumFormats].depth = i; - screenInfo->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i); - screenInfo->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD; - NumFormats++; - } - } - - screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; - screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; - screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; - screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; - screenInfo->numPixmapFormats = NumFormats; - - /* initialize screens */ - - if (vfbNumScreens < 1) - { - vfbScreens = &defaultScreenInfo; - vfbNumScreens = 1; - } - for (i = 0; i < vfbNumScreens; i++) - { - if (-1 == AddScreen(vfbScreenInit, argc, argv)) - { - FatalError("Couldn't add screen %d", i); - } - } - -} /* end InitOutput */ +/* + +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 <dix-config.h> +#endif + +#if defined(WIN32) +#include <X11/Xwinsock.h> +#endif +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/Xos.h> +#include "scrnintstr.h" +#include "servermd.h" +#define PSZ 8 +#include "fb.h" +#include "mibstore.h" +#include "colormapst.h" +#include "gcstruct.h" +#include "input.h" +#include "mipointer.h" +#include "micmap.h" +#include <sys/types.h> +#ifdef HAS_MMAP +#include <sys/mman.h> +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif +#endif /* HAS_MMAP */ +#include <sys/stat.h> +#include <errno.h> +#ifndef WIN32 +#include <sys/param.h> +#endif +#include <X11/XWDFile.h> +#ifdef HAS_SHM +#include <sys/ipc.h> +#include <sys/shm.h> +#endif /* HAS_SHM */ +#include "dix.h" +#include "miline.h" + +#define VFB_DEFAULT_WIDTH 1280 +#define VFB_DEFAULT_HEIGHT 1024 +#define VFB_DEFAULT_DEPTH 8 +#define VFB_DEFAULT_WHITEPIXEL 1 +#define VFB_DEFAULT_BLACKPIXEL 0 +#define VFB_DEFAULT_LINEBIAS 0 +#define XWD_WINDOW_NAME_LEN 60 + +typedef struct +{ + int width; + int paddedBytesWidth; + int paddedWidth; + int height; + int depth; + int bitsPerPixel; + int sizeInBytes; + int ncolors; + char *pfbMemory; + XWDColor *pXWDCmap; + XWDFileHeader *pXWDHeader; + Pixel blackPixel; + Pixel whitePixel; + unsigned int lineBias; + CloseScreenProcPtr closeScreen; + +#ifdef HAS_MMAP + int mmap_fd; + char mmap_file[MAXPATHLEN]; +#endif + +#ifdef HAS_SHM + int shmid; +#endif +} vfbScreenInfo, *vfbScreenInfoPtr; + +static int vfbNumScreens; +static vfbScreenInfo *vfbScreens; +static vfbScreenInfo defaultScreenInfo = { + .width = VFB_DEFAULT_WIDTH, + .height = VFB_DEFAULT_HEIGHT, + .depth = VFB_DEFAULT_DEPTH, + .blackPixel = VFB_DEFAULT_BLACKPIXEL, + .whitePixel = VFB_DEFAULT_WHITEPIXEL, + .lineBias = VFB_DEFAULT_LINEBIAS, +}; +static Bool vfbPixmapDepths[33]; +#ifdef HAS_MMAP +static char *pfbdir = NULL; +#endif +typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB, MMAPPED_FILE_FB } fbMemType; +static fbMemType fbmemtype = NORMAL_MEMORY_FB; +static char needswap = 0; +static Bool Render = TRUE; + +#define swapcopy16(_dst, _src) \ + if (needswap) { CARD16 _s = _src; cpswaps(_s, _dst); } \ + else _dst = _src; + +#define swapcopy32(_dst, _src) \ + if (needswap) { CARD32 _s = _src; cpswapl(_s, _dst); } \ + else _dst = _src; + + +static void +vfbInitializePixmapDepths(void) +{ + int i; + vfbPixmapDepths[1] = TRUE; /* always need bitmaps */ + for (i = 2; i <= 32; i++) + vfbPixmapDepths[i] = FALSE; +} + +static int +vfbBitsPerPixel(int depth) +{ + if (depth == 1) return 1; + else if (depth <= 8) return 8; + else if (depth <= 16) return 16; + else return 32; +} + +void +ddxGiveUp(void) +{ + int i; + + /* clean up the framebuffers */ + + switch (fbmemtype) + { +#ifdef HAS_MMAP + case MMAPPED_FILE_FB: + for (i = 0; i < vfbNumScreens; i++) + { + if (-1 == unlink(vfbScreens[i].mmap_file)) + { + perror("unlink"); + ErrorF("unlink %s failed, %s", + vfbScreens[i].mmap_file, strerror(errno)); + } + } + break; +#else /* HAS_MMAP */ + case MMAPPED_FILE_FB: + break; +#endif /* HAS_MMAP */ + +#ifdef HAS_SHM + case SHARED_MEMORY_FB: + for (i = 0; i < vfbNumScreens; i++) + { + if (-1 == shmdt((char *)vfbScreens[i].pXWDHeader)) + { + perror("shmdt"); + ErrorF("shmdt failed, %s", strerror(errno)); + } + } + break; +#else /* HAS_SHM */ + case SHARED_MEMORY_FB: + break; +#endif /* HAS_SHM */ + + case NORMAL_MEMORY_FB: + for (i = 0; i < vfbNumScreens; i++) + { + free(vfbScreens[i].pXWDHeader); + } + break; + } +} + +void +AbortDDX(void) +{ + ddxGiveUp(); +} + +#ifdef __APPLE__ +void +DarwinHandleGUI(int argc, char *argv[]) +{ +} +#endif + +void +OsVendorInit(void) +{ +} + +void +OsVendorFatalError(void) +{ +} + +#if defined(DDXBEFORERESET) +void ddxBeforeReset(void) +{ + return; +} +#endif + +void +ddxUseMsg(void) +{ + ErrorF("-screen scrn WxHxD set screen's width, height, depth\n"); + ErrorF("-pixdepths list-of-int support given pixmap depths\n"); + ErrorF("+/-render turn on/off RENDER extension support" + "(default on)\n"); + ErrorF("-linebias n adjust thin line pixelization\n"); + ErrorF("-blackpixel n pixel value for black\n"); + ErrorF("-whitepixel n pixel value for white\n"); + +#ifdef HAS_MMAP + ErrorF("-fbdir directory put framebuffers in mmap'ed files in directory\n"); +#endif + +#ifdef HAS_SHM + ErrorF("-shmem put framebuffers in shared memory\n"); +#endif +} + +int +ddxProcessArgument(int argc, char *argv[], int i) +{ + static Bool firstTime = TRUE; + static int lastScreen = -1; + vfbScreenInfo *currentScreen; + + if (firstTime) + { + vfbInitializePixmapDepths(); + firstTime = FALSE; + } + + if (lastScreen == -1) + currentScreen = &defaultScreenInfo; + else + currentScreen = &vfbScreens[lastScreen]; + +#define CHECK_FOR_REQUIRED_ARGUMENTS(num) \ + if (((i + num) >= argc) || (!argv[i + num])) { \ + ErrorF("Required argument to %s not specified\n", argv[i]); \ + UseMsg(); \ + FatalError("Required argument to %s not specified\n", argv[i]); \ + } + + if (strcmp (argv[i], "-screen") == 0) /* -screen n WxHxD */ + { + int screenNum; + CHECK_FOR_REQUIRED_ARGUMENTS(2); + screenNum = atoi(argv[i+1]); + if (screenNum < 0) + { + ErrorF("Invalid screen number %d\n", screenNum); + UseMsg(); + FatalError("Invalid screen number %d passed to -screen\n", + screenNum); + } + + if (vfbNumScreens <= screenNum) + { + vfbScreens = realloc(vfbScreens, sizeof(*vfbScreens) * (screenNum + 1)); + if (!vfbScreens) + FatalError("Not enough memory for screen %d\n", screenNum); + for (; vfbNumScreens <= screenNum; ++vfbNumScreens) + vfbScreens[vfbNumScreens] = defaultScreenInfo; + } + + if (3 != sscanf(argv[i+2], "%dx%dx%d", + &vfbScreens[screenNum].width, + &vfbScreens[screenNum].height, + &vfbScreens[screenNum].depth)) + { + ErrorF("Invalid screen configuration %s\n", argv[i+2]); + UseMsg(); + FatalError("Invalid screen configuration %s for -screen %d\n", + argv[i+2], screenNum); + } + + lastScreen = screenNum; + return 3; + } + + if (strcmp (argv[i], "-pixdepths") == 0) /* -pixdepths list-of-depth */ + { + int depth, ret = 1; + + CHECK_FOR_REQUIRED_ARGUMENTS(1); + while ((++i < argc) && (depth = atoi(argv[i])) != 0) + { + if (depth < 0 || depth > 32) + { + ErrorF("Invalid pixmap depth %d\n", depth); + UseMsg(); + FatalError("Invalid pixmap depth %d passed to -pixdepths\n", + depth); + } + vfbPixmapDepths[depth] = TRUE; + ret++; + } + return ret; + } + + if (strcmp (argv[i], "+render") == 0) /* +render */ + { + Render = TRUE; + return 1; + } + + if (strcmp (argv[i], "-render") == 0) /* -render */ + { + Render = FALSE; +#ifdef COMPOSITE + noCompositeExtension = TRUE; +#endif + return 1; + } + + if (strcmp (argv[i], "-blackpixel") == 0) /* -blackpixel n */ + { + CHECK_FOR_REQUIRED_ARGUMENTS(1); + currentScreen->blackPixel = atoi(argv[++i]); + return 2; + } + + if (strcmp (argv[i], "-whitepixel") == 0) /* -whitepixel n */ + { + CHECK_FOR_REQUIRED_ARGUMENTS(1); + currentScreen->whitePixel = atoi(argv[++i]); + return 2; + } + + if (strcmp (argv[i], "-linebias") == 0) /* -linebias n */ + { + CHECK_FOR_REQUIRED_ARGUMENTS(1); + currentScreen->lineBias = atoi(argv[++i]); + return 2; + } + +#ifdef HAS_MMAP + if (strcmp (argv[i], "-fbdir") == 0) /* -fbdir directory */ + { + CHECK_FOR_REQUIRED_ARGUMENTS(1); + pfbdir = argv[++i]; + fbmemtype = MMAPPED_FILE_FB; + return 2; + } +#endif /* HAS_MMAP */ + +#ifdef HAS_SHM + if (strcmp (argv[i], "-shmem") == 0) /* -shmem */ + { + fbmemtype = SHARED_MEMORY_FB; + return 1; + } +#endif + + return 0; +} + +static int cmapScrPrivateKeyIndex; +static DevPrivateKey cmapScrPrivateKey = &cmapScrPrivateKeyIndex; + +#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey)) +#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c)) + +static int +vfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) +{ + /* By the time we are processing requests, we can guarantee that there + * is always a colormap installed */ + *pmaps = GetInstalledColormap(pScreen)->mid; + return (1); +} + + +static void +vfbInstallColormap(ColormapPtr pmap) +{ + ColormapPtr oldpmap = GetInstalledColormap(pmap->pScreen); + + if (pmap != oldpmap) + { + int entries; + XWDFileHeader *pXWDHeader; + XWDColor *pXWDCmap; + VisualPtr pVisual; + Pixel * ppix; + xrgb * prgb; + xColorItem *defs; + int i; + + if(oldpmap != (ColormapPtr)None) + WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); + /* Install pmap */ + SetInstalledColormap(pmap->pScreen, pmap); + WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); + + entries = pmap->pVisual->ColormapEntries; + pXWDHeader = vfbScreens[pmap->pScreen->myNum].pXWDHeader; + pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap; + pVisual = pmap->pVisual; + + swapcopy32(pXWDHeader->visual_class, pVisual->class); + swapcopy32(pXWDHeader->red_mask, pVisual->redMask); + swapcopy32(pXWDHeader->green_mask, pVisual->greenMask); + swapcopy32(pXWDHeader->blue_mask, pVisual->blueMask); + swapcopy32(pXWDHeader->bits_per_rgb, pVisual->bitsPerRGBValue); + swapcopy32(pXWDHeader->colormap_entries, pVisual->ColormapEntries); + + ppix = (Pixel *)malloc(entries * sizeof(Pixel)); + prgb = (xrgb *)malloc(entries * sizeof(xrgb)); + defs = (xColorItem *)malloc(entries * sizeof(xColorItem)); + + for (i = 0; i < entries; i++) ppix[i] = i; + /* XXX truecolor */ + QueryColors(pmap, entries, ppix, prgb, serverClient); + + for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */ + defs[i].pixel = ppix[i] & 0xff; /* change pixel to index */ + defs[i].red = prgb[i].red; + defs[i].green = prgb[i].green; + defs[i].blue = prgb[i].blue; + defs[i].flags = DoRed|DoGreen|DoBlue; + } + (*pmap->pScreen->StoreColors)(pmap, entries, defs); + + free(ppix); + free(prgb); + free(defs); + } +} + +static void +vfbUninstallColormap(ColormapPtr pmap) +{ + ColormapPtr curpmap = GetInstalledColormap(pmap->pScreen); + + if(pmap == curpmap) + { + if (pmap->mid != pmap->pScreen->defColormap) + { + dixLookupResourceByType((pointer *)&curpmap, + pmap->pScreen->defColormap, + RT_COLORMAP, serverClient, + DixInstallAccess); + (*pmap->pScreen->InstallColormap)(curpmap); + } + } +} + +static void +vfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs) +{ + XWDColor *pXWDCmap; + int i; + + if (pmap != GetInstalledColormap(pmap->pScreen)) + { + return; + } + + pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap; + + if ((pmap->pVisual->class | DynamicClass) == DirectColor) + { + return; + } + + for (i = 0; i < ndef; i++) + { + if (pdefs[i].flags & DoRed) + { + swapcopy16(pXWDCmap[pdefs[i].pixel].red, pdefs[i].red); + } + if (pdefs[i].flags & DoGreen) + { + swapcopy16(pXWDCmap[pdefs[i].pixel].green, pdefs[i].green); + } + if (pdefs[i].flags & DoBlue) + { + swapcopy16(pXWDCmap[pdefs[i].pixel].blue, pdefs[i].blue); + } + } +} + +static Bool +vfbSaveScreen(ScreenPtr pScreen, int on) +{ + return TRUE; +} + +#ifdef HAS_MMAP + +/* this flushes any changes to the screens out to the mmapped file */ +static void +vfbBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask) +{ + int i; + + for (i = 0; i < vfbNumScreens; i++) + { +#ifdef MS_ASYNC + if (-1 == msync((caddr_t)vfbScreens[i].pXWDHeader, + (size_t)vfbScreens[i].sizeInBytes, MS_ASYNC)) +#else + /* silly NetBSD and who else? */ + if (-1 == msync((caddr_t)vfbScreens[i].pXWDHeader, + (size_t)vfbScreens[i].sizeInBytes)) +#endif + { + perror("msync"); + ErrorF("msync failed, %s", strerror(errno)); + } + } +} + + +static void +vfbWakeupHandler(pointer blockData, int result, pointer pReadmask) +{ +} + + +static void +vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb) +{ +#define DUMMY_BUFFER_SIZE 65536 + char dummyBuffer[DUMMY_BUFFER_SIZE]; + int currentFileSize, writeThisTime; + + sprintf(pvfb->mmap_file, "%s/Xvfb_screen%d", pfbdir, (int) (pvfb - vfbScreens)); + if (-1 == (pvfb->mmap_fd = open(pvfb->mmap_file, O_CREAT|O_RDWR, 0666))) + { + perror("open"); + ErrorF("open %s failed, %s", pvfb->mmap_file, strerror(errno)); + return; + } + + /* Extend the file to be the proper size */ + + bzero(dummyBuffer, DUMMY_BUFFER_SIZE); + for (currentFileSize = 0; + currentFileSize < pvfb->sizeInBytes; + currentFileSize += writeThisTime) + { + writeThisTime = min(DUMMY_BUFFER_SIZE, + pvfb->sizeInBytes - currentFileSize); + if (-1 == write(pvfb->mmap_fd, dummyBuffer, writeThisTime)) + { + perror("write"); + ErrorF("write %s failed, %s", pvfb->mmap_file, strerror(errno)); + return; + } + } + + /* try to mmap the file */ + + pvfb->pXWDHeader = (XWDFileHeader *)mmap((caddr_t)NULL, pvfb->sizeInBytes, + PROT_READ|PROT_WRITE, + MAP_FILE|MAP_SHARED, + pvfb->mmap_fd, 0); + if (-1 == (long)pvfb->pXWDHeader) + { + perror("mmap"); + ErrorF("mmap %s failed, %s", pvfb->mmap_file, strerror(errno)); + pvfb->pXWDHeader = NULL; + return; + } + + if (!RegisterBlockAndWakeupHandlers(vfbBlockHandler, vfbWakeupHandler, + NULL)) + { + pvfb->pXWDHeader = NULL; + } +} +#endif /* HAS_MMAP */ + + +#ifdef HAS_SHM +static void +vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb) +{ + /* create the shared memory segment */ + + pvfb->shmid = shmget(IPC_PRIVATE, pvfb->sizeInBytes, IPC_CREAT|0777); + if (pvfb->shmid < 0) + { + perror("shmget"); + ErrorF("shmget %d bytes failed, %s", pvfb->sizeInBytes, strerror(errno)); + return; + } + + /* try to attach it */ + + pvfb->pXWDHeader = (XWDFileHeader *)shmat(pvfb->shmid, 0, 0); + if (-1 == (long)pvfb->pXWDHeader) + { + perror("shmat"); + ErrorF("shmat failed, %s", strerror(errno)); + pvfb->pXWDHeader = NULL; + return; + } + + ErrorF("screen %d shmid %d\n", (int) (pvfb - vfbScreens), pvfb->shmid); +} +#endif /* HAS_SHM */ + +static char * +vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb) +{ + if (pvfb->pfbMemory) return pvfb->pfbMemory; /* already done */ + + pvfb->sizeInBytes = pvfb->paddedBytesWidth * pvfb->height; + + /* Calculate how many entries in colormap. This is rather bogus, because + * the visuals haven't even been set up yet, but we need to know because we + * have to allocate space in the file for the colormap. The number 10 + * below comes from the MAX_PSEUDO_DEPTH define in cfbcmap.c. + */ + + if (pvfb->depth <= 10) + { /* single index colormaps */ + pvfb->ncolors = 1 << pvfb->depth; + } + else + { /* decomposed colormaps */ + int nplanes_per_color_component = pvfb->depth / 3; + if (pvfb->depth % 3) nplanes_per_color_component++; + pvfb->ncolors = 1 << nplanes_per_color_component; + } + + /* add extra bytes for XWDFileHeader, window name, and colormap */ + + pvfb->sizeInBytes += SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN + + pvfb->ncolors * SIZEOF(XWDColor); + + pvfb->pXWDHeader = NULL; + switch (fbmemtype) + { +#ifdef HAS_MMAP + case MMAPPED_FILE_FB: vfbAllocateMmappedFramebuffer(pvfb); break; +#else + case MMAPPED_FILE_FB: break; +#endif + +#ifdef HAS_SHM + case SHARED_MEMORY_FB: vfbAllocateSharedMemoryFramebuffer(pvfb); break; +#else + case SHARED_MEMORY_FB: break; +#endif + + case NORMAL_MEMORY_FB: + pvfb->pXWDHeader = (XWDFileHeader *)malloc(pvfb->sizeInBytes); + break; + } + + if (pvfb->pXWDHeader) + { + pvfb->pXWDCmap = (XWDColor *)((char *)pvfb->pXWDHeader + + SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN); + pvfb->pfbMemory = (char *)(pvfb->pXWDCmap + pvfb->ncolors); + + return pvfb->pfbMemory; + } + else + return NULL; +} + + +static void +vfbWriteXWDFileHeader(ScreenPtr pScreen) +{ + vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum]; + XWDFileHeader *pXWDHeader = pvfb->pXWDHeader; + char hostname[XWD_WINDOW_NAME_LEN]; + unsigned long swaptest = 1; + int i; + + needswap = *(char *) &swaptest; + + pXWDHeader->header_size = (char *)pvfb->pXWDCmap - (char *)pvfb->pXWDHeader; + pXWDHeader->file_version = XWD_FILE_VERSION; + + pXWDHeader->pixmap_format = ZPixmap; + pXWDHeader->pixmap_depth = pvfb->depth; + pXWDHeader->pixmap_height = pXWDHeader->window_height = pvfb->height; + pXWDHeader->xoffset = 0; + pXWDHeader->byte_order = IMAGE_BYTE_ORDER; + pXWDHeader->bitmap_bit_order = BITMAP_BIT_ORDER; +#ifndef INTERNAL_VS_EXTERNAL_PADDING + pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->width; + pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT; + pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD; +#else + pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->paddedWidth; + pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT_PROTO; + pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD_PROTO; +#endif + pXWDHeader->bits_per_pixel = pvfb->bitsPerPixel; + pXWDHeader->bytes_per_line = pvfb->paddedBytesWidth; + pXWDHeader->ncolors = pvfb->ncolors; + + /* visual related fields are written when colormap is installed */ + + pXWDHeader->window_x = pXWDHeader->window_y = 0; + pXWDHeader->window_bdrwidth = 0; + + /* write xwd "window" name: Xvfb hostname:server.screen */ + + if (-1 == gethostname(hostname, sizeof(hostname))) + hostname[0] = 0; + else + hostname[XWD_WINDOW_NAME_LEN-1] = 0; + sprintf((char *)(pXWDHeader+1), "Xvfb %s:%s.%d", hostname, display, + pScreen->myNum); + + /* write colormap pixel slot values */ + + for (i = 0; i < pvfb->ncolors; i++) + { + pvfb->pXWDCmap[i].pixel = i; + } + + /* byte swap to most significant byte first */ + + if (needswap) + { + SwapLongs((CARD32 *)pXWDHeader, SIZEOF(XWDheader)/4); + for (i = 0; i < pvfb->ncolors; i++) + { + register char n; + swapl(&pvfb->pXWDCmap[i].pixel, n); + } + } +} + + +static Bool +vfbCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y) +{ + return FALSE; +} + +static void +vfbCrossScreen (ScreenPtr pScreen, Bool entering) +{ +} + +static miPointerScreenFuncRec vfbPointerCursorFuncs = +{ + vfbCursorOffScreen, + vfbCrossScreen, + miPointerWarpCursor +}; + +static Bool +vfbCloseScreen(int index, ScreenPtr pScreen) +{ + vfbScreenInfoPtr pvfb = &vfbScreens[index]; + int i; + + pScreen->CloseScreen = pvfb->closeScreen; + + /* + * XXX probably lots of stuff to clean. For now, + * clear installed colormaps so that server reset works correctly. + */ + for (i = 0; i < screenInfo.numScreens; i++) + SetInstalledColormap(screenInfo.screens[i], NULL); + + return pScreen->CloseScreen(index, pScreen); +} + +static Bool +vfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) +{ + vfbScreenInfoPtr pvfb = &vfbScreens[index]; + int dpix = monitorResolution, dpiy = monitorResolution; + int ret; + char *pbits; + + if (dpix == 0) + dpix = 100; + + if (dpiy == 0) + dpiy = 100; + + pvfb->paddedBytesWidth = PixmapBytePad(pvfb->width, pvfb->depth); + pvfb->bitsPerPixel = vfbBitsPerPixel(pvfb->depth); + if (pvfb->bitsPerPixel >= 8 ) + pvfb->paddedWidth = pvfb->paddedBytesWidth / (pvfb->bitsPerPixel / 8); + else + pvfb->paddedWidth = pvfb->paddedBytesWidth * 8; + pbits = vfbAllocateFramebufferMemory(pvfb); + if (!pbits) return FALSE; + + switch (pvfb->depth) { + case 8: + miSetVisualTypesAndMasks (8, + ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)), + 8, PseudoColor, 0, 0, 0); + break; + case 15: + miSetVisualTypesAndMasks (15, + ((1 << TrueColor) | + (1 << DirectColor)), + 8, TrueColor, 0x7c00, 0x03e0, 0x001f); + break; + case 16: + miSetVisualTypesAndMasks (16, + ((1 << TrueColor) | + (1 << DirectColor)), + 8, TrueColor, 0xf800, 0x07e0, 0x001f); + break; + case 24: + miSetVisualTypesAndMasks (24, + ((1 << TrueColor) | + (1 << DirectColor)), + 8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff); + break; + case 30: + miSetVisualTypesAndMasks (30, + ((1 << TrueColor) | + (1 << DirectColor)), + 10, TrueColor, 0x3ff00000, 0x000ffc00, 0x000003ff); + break; + } + + miSetPixmapDepths (); + + ret = fbScreenInit(pScreen, pbits, pvfb->width, pvfb->height, + dpix, dpiy, pvfb->paddedWidth,pvfb->bitsPerPixel); + if (ret && Render) + fbPictureInit (pScreen, 0, 0); + + if (!ret) return FALSE; + + miInitializeBackingStore(pScreen); + + /* + * Circumvent the backing store that was just initialised. This amounts + * to a truely bizarre way of initialising SaveDoomedAreas and friends. + */ + + pScreen->InstallColormap = vfbInstallColormap; + pScreen->UninstallColormap = vfbUninstallColormap; + pScreen->ListInstalledColormaps = vfbListInstalledColormaps; + + pScreen->SaveScreen = vfbSaveScreen; + pScreen->StoreColors = vfbStoreColors; + + miDCInitialize(pScreen, &vfbPointerCursorFuncs); + + vfbWriteXWDFileHeader(pScreen); + + pScreen->blackPixel = pvfb->blackPixel; + pScreen->whitePixel = pvfb->whitePixel; + + ret = fbCreateDefColormap(pScreen); + + miSetZeroLineBias(pScreen, pvfb->lineBias); + + pvfb->closeScreen = pScreen->CloseScreen; + pScreen->CloseScreen = vfbCloseScreen; + + return ret; + +} /* end vfbScreenInit */ + + +void +InitOutput(ScreenInfo *screenInfo, int argc, char **argv) +{ + int i; + int NumFormats = 0; + + /* initialize pixmap formats */ + + /* must have a pixmap depth to match every screen depth */ + for (i = 0; i < vfbNumScreens; i++) + { + vfbPixmapDepths[vfbScreens[i].depth] = TRUE; + } + + /* RENDER needs a good set of pixmaps. */ + if (Render) { + vfbPixmapDepths[1] = TRUE; + vfbPixmapDepths[4] = TRUE; + vfbPixmapDepths[8] = TRUE; +#if 0 + vfbPixmapDepths[12] = TRUE; +#endif +/* vfbPixmapDepths[15] = TRUE; */ + vfbPixmapDepths[16] = TRUE; + vfbPixmapDepths[24] = TRUE; +#if 0 + vfbPixmapDepths[30] = TRUE; +#endif + vfbPixmapDepths[32] = TRUE; + } + + for (i = 1; i <= 32; i++) + { + if (vfbPixmapDepths[i]) + { + if (NumFormats >= MAXFORMATS) + FatalError ("MAXFORMATS is too small for this server\n"); + screenInfo->formats[NumFormats].depth = i; + screenInfo->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i); + screenInfo->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD; + NumFormats++; + } + } + + screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; + screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; + screenInfo->numPixmapFormats = NumFormats; + + /* initialize screens */ + + if (vfbNumScreens < 1) + { + vfbScreens = &defaultScreenInfo; + vfbNumScreens = 1; + } + for (i = 0; i < vfbNumScreens; i++) + { + if (-1 == AddScreen(vfbScreenInit, argc, argv)) + { + FatalError("Couldn't add screen %d", i); + } + } + +} /* end InitOutput */ diff --git a/xorg-server/hw/xfree86/common/xf86.h b/xorg-server/hw/xfree86/common/xf86.h index e9266abd4..cddca37a3 100644 --- a/xorg-server/hw/xfree86/common/xf86.h +++ b/xorg-server/hw/xfree86/common/xf86.h @@ -1,354 +1,354 @@ -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * This file contains declarations for public XFree86 functions and variables, - * and definitions of public macros. - * - * "public" means available to video drivers. - */ - -#ifndef _XF86_H -#define _XF86_H - -#if HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#elif HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <pciaccess.h> - -#include "xf86str.h" -#include "xf86Opt.h" -#include <X11/Xfuncproto.h> -#include <stdarg.h> -#ifdef RANDR -#include <X11/extensions/randr.h> -#endif - -#include "propertyst.h" - -/* General parameters */ -extern _X_EXPORT int xf86DoConfigure; -extern _X_EXPORT int xf86DoShowOptions; -extern _X_EXPORT Bool xf86DoConfigurePass1; -extern _X_EXPORT DevPrivateKey xf86ScreenKey; -extern _X_EXPORT DevPrivateKey xf86CreateRootWindowKey; -extern _X_EXPORT DevPrivateKey xf86PixmapKey; -extern _X_EXPORT ScrnInfoPtr *xf86Screens; /* List of pointers to ScrnInfoRecs */ -extern _X_EXPORT const unsigned char byte_reversed[256]; -extern _X_EXPORT Bool pciSlotClaimed; -extern _X_EXPORT Bool fbSlotClaimed; -#if defined(__sparc__) || defined(__sparc) -extern _X_EXPORT Bool sbusSlotClaimed; -#endif -extern _X_EXPORT confDRIRec xf86ConfigDRI; -extern _X_EXPORT Bool xf86inSuspend; -extern _X_EXPORT Bool xf86DRI2Enabled(void); - -extern _X_EXPORT Bool VTSwitchEnabled; /* kbd driver */ - -#define XF86SCRNINFO(p) ((ScrnInfoPtr)dixLookupPrivate(&(p)->devPrivates, \ - xf86ScreenKey)) -#define XF86FLIP_PIXELS() \ - do { \ - if (xf86GetFlipPixels()) { \ - pScreen->whitePixel = (pScreen->whitePixel) ? 0 : 1; \ - pScreen->blackPixel = (pScreen->blackPixel) ? 0 : 1; \ - } \ - while (0) - -#define BOOLTOSTRING(b) ((b) ? "TRUE" : "FALSE") - -#define PIX24TOBPP(p) (((p) == Pix24Use24) ? 24 : \ - (((p) == Pix24Use32) ? 32 : 0)) - -/* Function Prototypes */ -#ifndef _NO_XF86_PROTOTYPES - -/* xf86Bus.c */ - -extern _X_EXPORT Bool xf86CheckPciSlot( const struct pci_device * ); -extern _X_EXPORT int xf86ClaimPciSlot( struct pci_device *, DriverPtr drvp, - int chipset, GDevPtr dev, Bool active); -extern _X_EXPORT void xf86UnclaimPciSlot(struct pci_device *); -extern _X_EXPORT Bool xf86ParsePciBusString(const char *busID, int *bus, int *device, - int *func); -extern _X_EXPORT Bool xf86ComparePciBusString(const char *busID, int bus, int device, int func); -extern _X_EXPORT void xf86FormatPciBusNumber(int busnum, char *buffer); -extern _X_EXPORT int xf86GetFbInfoForScreen(int scrnIndex); -extern _X_EXPORT int xf86ClaimFbSlot(DriverPtr drvp, int chipset, GDevPtr dev, Bool active); -extern _X_EXPORT int xf86ClaimNoSlot(DriverPtr drvp, int chipset, GDevPtr dev, Bool active); -extern _X_EXPORT void xf86EnableAccess(ScrnInfoPtr pScrn); -extern _X_EXPORT Bool xf86IsPrimaryPci(struct pci_device * pPci); -/* new RAC */ -extern _X_EXPORT Bool xf86DriverHasEntities(DriverPtr drvp); -extern _X_EXPORT void xf86AddEntityToScreen(ScrnInfoPtr pScrn, int entityIndex); -extern _X_EXPORT void xf86SetEntityInstanceForScreen(ScrnInfoPtr pScrn, int entityIndex, - int instance); -extern _X_EXPORT int xf86GetNumEntityInstances(int entityIndex); -extern _X_EXPORT GDevPtr xf86GetDevFromEntity(int entityIndex, int instance); -extern _X_EXPORT void xf86RemoveEntityFromScreen(ScrnInfoPtr pScrn, int entityIndex); -extern _X_EXPORT EntityInfoPtr xf86GetEntityInfo(int entityIndex); -extern _X_EXPORT struct pci_device * xf86GetPciInfoForEntity(int entityIndex); -extern _X_EXPORT Bool xf86SetEntityFuncs(int entityIndex, EntityProc init, - EntityProc enter, EntityProc leave, pointer); -extern _X_EXPORT Bool xf86CheckPciMemBase(struct pci_device * pPci, memType base); -extern _X_EXPORT Bool xf86IsEntityPrimary(int entityIndex); -extern _X_EXPORT void xf86EnterServerState(xf86State state); -extern _X_EXPORT ScrnInfoPtr xf86FindScreenForEntity(int entityIndex); - -extern _X_EXPORT int xf86GetLastScrnFlag(int entityIndex); -extern _X_EXPORT void xf86SetLastScrnFlag(int entityIndex, int scrnIndex); -extern _X_EXPORT Bool xf86IsEntityShared(int entityIndex); -extern _X_EXPORT void xf86SetEntityShared(int entityIndex); -extern _X_EXPORT Bool xf86IsEntitySharable(int entityIndex); -extern _X_EXPORT void xf86SetEntitySharable(int entityIndex); -extern _X_EXPORT Bool xf86IsPrimInitDone(int entityIndex); -extern _X_EXPORT void xf86SetPrimInitDone(int entityIndex); -extern _X_EXPORT void xf86ClearPrimInitDone(int entityIndex); -extern _X_EXPORT int xf86AllocateEntityPrivateIndex(void); -extern _X_EXPORT DevUnion *xf86GetEntityPrivate(int entityIndex, int privIndex); - -/* xf86Configure.c */ -extern _X_EXPORT GDevPtr xf86AddBusDeviceToConfigure(const char *driver, BusType bus, - void *busData, int chipset); - -/* xf86Cursor.c */ - -extern _X_EXPORT void xf86LockZoom(ScreenPtr pScreen, int lock); -extern _X_EXPORT void xf86InitViewport(ScrnInfoPtr pScr); -extern _X_EXPORT void xf86SetViewport(ScreenPtr pScreen, int x, int y); -extern _X_EXPORT void xf86ZoomViewport(ScreenPtr pScreen, int zoom); -extern _X_EXPORT Bool xf86SwitchMode(ScreenPtr pScreen, DisplayModePtr mode); -extern _X_EXPORT void *xf86GetPointerScreenFuncs(void); -extern _X_EXPORT void xf86InitOrigins(void); -extern _X_EXPORT void xf86ReconfigureLayout(void); - -/* xf86cvt.c */ -extern _X_EXPORT DisplayModePtr xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, - Bool Reduced, Bool Interlaced); - -/* xf86DPMS.c */ - -extern _X_EXPORT Bool xf86DPMSInit(ScreenPtr pScreen, DPMSSetProcPtr set, int flags); - -#ifdef DPMSExtension -extern _X_EXPORT int DPMSSet(ClientPtr client, int level); -extern _X_EXPORT Bool DPMSSupported(void); -#endif - - -/* xf86DGA.c */ - -#ifdef XFreeXDGA -extern _X_EXPORT Bool DGAInit(ScreenPtr pScreen, DGAFunctionPtr funcs, DGAModePtr modes, - int num); -extern _X_EXPORT Bool DGAReInitModes(ScreenPtr pScreen, DGAModePtr modes, int num); -extern _X_EXPORT xf86SetDGAModeProc xf86SetDGAMode; -#endif - -/* xf86Events.c */ - -extern _X_EXPORT void SetTimeSinceLastInputEvent(void); -extern _X_EXPORT pointer xf86AddInputHandler(int fd, InputHandlerProc proc, pointer data); -extern _X_EXPORT int xf86RemoveInputHandler(pointer handler); -extern _X_EXPORT void xf86DisableInputHandler(pointer handler); -extern _X_EXPORT void xf86EnableInputHandler(pointer handler); -extern _X_EXPORT pointer xf86AddGeneralHandler(int fd, InputHandlerProc proc, pointer data); -extern _X_EXPORT int xf86RemoveGeneralHandler(pointer handler); -extern _X_EXPORT void xf86DisableGeneralHandler(pointer handler); -extern _X_EXPORT void xf86EnableGeneralHandler(pointer handler); -extern _X_EXPORT void xf86InterceptSignals(int *signo); -extern _X_EXPORT void xf86InterceptSigIll(void (*sigillhandler)(void)); -extern _X_EXPORT Bool xf86EnableVTSwitch(Bool new); -extern _X_EXPORT void xf86ProcessActionEvent(ActionEvent action, void *arg); -extern _X_EXPORT void xf86PrintBacktrace(void); - -/* xf86Helper.c */ - -extern _X_EXPORT void xf86AddDriver(DriverPtr driver, pointer module, int flags); -extern _X_EXPORT void xf86DeleteDriver(int drvIndex); -extern _X_EXPORT ScrnInfoPtr xf86AllocateScreen(DriverPtr drv, int flags); -extern _X_EXPORT void xf86DeleteScreen(int scrnIndex, int flags); -extern _X_EXPORT int xf86AllocateScrnInfoPrivateIndex(void); -extern _X_EXPORT Bool xf86AddPixFormat(ScrnInfoPtr pScrn, int depth, int bpp, int pad); -extern _X_EXPORT Bool xf86SetDepthBpp(ScrnInfoPtr scrp, int depth, int bpp, int fbbpp, - int depth24flags); -extern _X_EXPORT void xf86PrintDepthBpp(ScrnInfoPtr scrp); -extern _X_EXPORT Bool xf86SetWeight(ScrnInfoPtr scrp, rgb weight, rgb mask); -extern _X_EXPORT Bool xf86SetDefaultVisual(ScrnInfoPtr scrp, int visual); -extern _X_EXPORT Bool xf86SetGamma(ScrnInfoPtr scrp, Gamma newGamma); -extern _X_EXPORT void xf86SetDpi(ScrnInfoPtr pScrn, int x, int y); -extern _X_EXPORT void xf86SetBlackWhitePixels(ScreenPtr pScreen); -extern _X_EXPORT void xf86EnableDisableFBAccess(int scrnIndex, Bool enable); -extern _X_EXPORT void xf86VDrvMsgVerb(int scrnIndex, MessageType type, int verb, - const char *format, va_list args); -extern _X_EXPORT void xf86DrvMsgVerb(int scrnIndex, MessageType type, int verb, - const char *format, ...) _printf_attribute(4,5); -extern _X_EXPORT void xf86DrvMsg(int scrnIndex, MessageType type, const char *format, ...) - _printf_attribute(3,4); -extern _X_EXPORT void xf86MsgVerb(MessageType type, int verb, const char *format, ...) - _printf_attribute(3,4); -extern _X_EXPORT void xf86Msg(MessageType type, const char *format, ...) _printf_attribute(2,3); -extern _X_EXPORT void xf86ErrorFVerb(int verb, const char *format, ...) _printf_attribute(2,3); -extern _X_EXPORT void xf86ErrorF(const char *format, ...) _printf_attribute(1,2); -extern _X_EXPORT const char *xf86TokenToString(SymTabPtr table, int token); -extern _X_EXPORT int xf86StringToToken(SymTabPtr table, const char *string); -extern _X_EXPORT void xf86ShowClocks(ScrnInfoPtr scrp, MessageType from); -extern _X_EXPORT void xf86PrintChipsets(const char *drvname, const char *drvmsg, - SymTabPtr chips); -extern _X_EXPORT int xf86MatchDevice(const char *drivername, GDevPtr **driversectlist); -extern _X_EXPORT int xf86MatchPciInstances(const char *driverName, int vendorID, - SymTabPtr chipsets, PciChipsets *PCIchipsets, - GDevPtr *devList, int numDevs, DriverPtr drvp, - int **foundEntities); -extern _X_EXPORT void xf86GetClocks(ScrnInfoPtr pScrn, int num, - Bool (*ClockFunc)(ScrnInfoPtr, int), - void (*ProtectRegs)(ScrnInfoPtr, Bool), - void (*BlankScreen)(ScrnInfoPtr, Bool), - IOADDRESS vertsyncreg, int maskval, - int knownclkindex, int knownclkvalue); -extern _X_EXPORT const char *xf86GetVisualName(int visual); -extern _X_EXPORT int xf86GetVerbosity(void); -extern _X_EXPORT Pix24Flags xf86GetPix24(void); -extern _X_EXPORT int xf86GetDepth(void); -extern _X_EXPORT rgb xf86GetWeight(void); -extern _X_EXPORT Gamma xf86GetGamma(void); -extern _X_EXPORT Bool xf86GetFlipPixels(void); -extern _X_EXPORT const char *xf86GetServerName(void); -extern _X_EXPORT Bool xf86ServerIsExiting(void); -extern _X_EXPORT Bool xf86ServerIsResetting(void); -extern _X_EXPORT Bool xf86ServerIsInitialising(void); -extern _X_EXPORT Bool xf86ServerIsOnlyDetecting(void); -extern _X_EXPORT Bool xf86CaughtSignal(void); -extern _X_EXPORT Bool xf86GetVidModeAllowNonLocal(void); -extern _X_EXPORT Bool xf86GetVidModeEnabled(void); -extern _X_EXPORT Bool xf86GetModInDevAllowNonLocal(void); -extern _X_EXPORT Bool xf86GetModInDevEnabled(void); -extern _X_EXPORT Bool xf86GetAllowMouseOpenFail(void); -extern _X_EXPORT Bool xf86IsPc98(void); -extern _X_EXPORT void xf86DisableRandR(void); -extern _X_EXPORT CARD32 xorgGetVersion(void); -extern _X_EXPORT CARD32 xf86GetModuleVersion(pointer module); -extern _X_EXPORT pointer xf86LoadDrvSubModule(DriverPtr drv, const char *name); -extern _X_EXPORT pointer xf86LoadSubModule(ScrnInfoPtr pScrn, const char *name); -extern _X_EXPORT pointer xf86LoadOneModule(char *name, pointer optlist); -extern _X_EXPORT void xf86UnloadSubModule(pointer mod); -extern _X_EXPORT Bool xf86LoaderCheckSymbol(const char *name); -extern _X_EXPORT void xf86SetBackingStore(ScreenPtr pScreen); -extern _X_EXPORT void xf86SetSilkenMouse(ScreenPtr pScreen); -extern _X_EXPORT pointer xf86FindXvOptions(int scrnIndex, int adapt_index, char *port_name, - char **adaptor_name, pointer *adaptor_options); -extern _X_EXPORT void xf86GetOS(const char **name, int *major, int *minor, int *teeny); -extern _X_EXPORT ScrnInfoPtr xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, - int entityIndex,PciChipsets *p_chip, - void *dummy, EntityProc init, - EntityProc enter, EntityProc leave, - pointer private); -extern _X_EXPORT ScrnInfoPtr xf86ConfigFbEntity(ScrnInfoPtr pScrn, int scrnFlag, - int entityIndex, EntityProc init, - EntityProc enter, EntityProc leave, - pointer private); - -/* Obsolete! don't use */ -extern _X_EXPORT Bool xf86ConfigActivePciEntity(ScrnInfoPtr pScrn, - int entityIndex,PciChipsets *p_chip, - void *dummy, EntityProc init, - EntityProc enter, EntityProc leave, - pointer private); - -extern _X_EXPORT Bool xf86IsScreenPrimary(int scrnIndex); -extern _X_EXPORT int xf86RegisterRootWindowProperty(int ScrnIndex, Atom property, Atom type, - int format, unsigned long len, - pointer value); -extern _X_EXPORT Bool xf86IsUnblank(int mode); - -/* xf86Init.c */ - -extern _X_EXPORT PixmapFormatPtr xf86GetPixFormat(ScrnInfoPtr pScrn, int depth); -extern _X_EXPORT int xf86GetBppFromDepth(ScrnInfoPtr pScrn, int depth); - -/* xf86Mode.c */ - -extern _X_EXPORT int xf86GetNearestClock(ScrnInfoPtr scrp, int freq, Bool allowDiv2, - int DivFactor, int MulFactor, int *divider); -extern _X_EXPORT const char *xf86ModeStatusToString(ModeStatus status); -extern _X_EXPORT ModeStatus xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep, - ClockRangePtr clockRanges, LookupModeFlags strategy); -extern _X_EXPORT ModeStatus xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor); -extern _X_EXPORT ModeStatus xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, - ClockRangePtr clockRanges, - LookupModeFlags strategy, - int maxPitch, int virtualX, - int virtualY); -extern _X_EXPORT ModeStatus xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, - int flags); -extern _X_EXPORT int xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, - char **modeNames, ClockRangePtr clockRanges, - int *linePitches, int minPitch, int maxPitch, - int minHeight, int maxHeight, int pitchInc, - int virtualX, int virtualY, int apertureSize, - LookupModeFlags strategy); -extern _X_EXPORT void xf86DeleteMode(DisplayModePtr *modeList, DisplayModePtr mode); -extern _X_EXPORT void xf86PruneDriverModes(ScrnInfoPtr scrp); -extern _X_EXPORT void xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags); -extern _X_EXPORT void xf86PrintModes(ScrnInfoPtr scrp); -extern _X_EXPORT void xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges); -extern _X_EXPORT double xf86ModeHSync(const DisplayModeRec *mode); -extern _X_EXPORT double xf86ModeVRefresh(const DisplayModeRec *mode); -extern _X_EXPORT void xf86SetModeDefaultName(DisplayModePtr mode); -extern _X_EXPORT void xf86SetModeCrtc(DisplayModePtr p, int adjustFlags); -extern _X_EXPORT DisplayModePtr xf86DuplicateMode(const DisplayModeRec *pMode); -extern _X_EXPORT DisplayModePtr xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList); -extern _X_EXPORT Bool xf86ModesEqual(const DisplayModeRec *pMode1, - const DisplayModeRec *pMode2); -extern _X_EXPORT void xf86PrintModeline(int scrnIndex,DisplayModePtr mode); -extern _X_EXPORT DisplayModePtr xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new); - -/* xf86Option.c */ - -extern _X_EXPORT void xf86CollectOptions(ScrnInfoPtr pScrn, pointer extraOpts); - - -/* xf86RandR.c */ -#ifdef RANDR -extern _X_EXPORT Bool xf86RandRInit (ScreenPtr pScreen); -extern _X_EXPORT Rotation xf86GetRotation(ScreenPtr pScreen); -extern _X_EXPORT Bool xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen, - int newvirtX, int newvirtY, - int newmmWidth, int newmmHeight, Bool resetMode); -#endif - -/* xf86VidModeExtentionInit.c */ - -extern _X_EXPORT Bool VidModeExtensionInit(ScreenPtr pScreen); - -#endif /* _NO_XF86_PROTOTYPES */ - -#endif /* _XF86_H */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * This file contains declarations for public XFree86 functions and variables, + * and definitions of public macros. + * + * "public" means available to video drivers. + */ + +#ifndef _XF86_H +#define _XF86_H + +#if HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#elif HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <pciaccess.h> + +#include "xf86str.h" +#include "xf86Opt.h" +#include <X11/Xfuncproto.h> +#include <stdarg.h> +#ifdef RANDR +#include <X11/extensions/randr.h> +#endif + +#include "propertyst.h" + +/* General parameters */ +extern _X_EXPORT int xf86DoConfigure; +extern _X_EXPORT int xf86DoShowOptions; +extern _X_EXPORT Bool xf86DoConfigurePass1; +extern _X_EXPORT DevPrivateKey xf86ScreenKey; +extern _X_EXPORT DevPrivateKey xf86CreateRootWindowKey; +extern _X_EXPORT DevPrivateKey xf86PixmapKey; +extern _X_EXPORT ScrnInfoPtr *xf86Screens; /* List of pointers to ScrnInfoRecs */ +extern _X_EXPORT const unsigned char byte_reversed[256]; +extern _X_EXPORT Bool pciSlotClaimed; +extern _X_EXPORT Bool fbSlotClaimed; +#if defined(__sparc__) || defined(__sparc) +extern _X_EXPORT Bool sbusSlotClaimed; +#endif +extern _X_EXPORT confDRIRec xf86ConfigDRI; +extern _X_EXPORT Bool xf86inSuspend; +extern _X_EXPORT Bool xf86DRI2Enabled(void); + +extern _X_EXPORT Bool VTSwitchEnabled; /* kbd driver */ + +#define XF86SCRNINFO(p) ((ScrnInfoPtr)dixLookupPrivate(&(p)->devPrivates, \ + xf86ScreenKey)) +#define XF86FLIP_PIXELS() \ + do { \ + if (xf86GetFlipPixels()) { \ + pScreen->whitePixel = (pScreen->whitePixel) ? 0 : 1; \ + pScreen->blackPixel = (pScreen->blackPixel) ? 0 : 1; \ + } \ + while (0) + +#define BOOLTOSTRING(b) ((b) ? "TRUE" : "FALSE") + +#define PIX24TOBPP(p) (((p) == Pix24Use24) ? 24 : \ + (((p) == Pix24Use32) ? 32 : 0)) + +/* Function Prototypes */ +#ifndef _NO_XF86_PROTOTYPES + +/* xf86Bus.c */ + +extern _X_EXPORT Bool xf86CheckPciSlot( const struct pci_device * ); +extern _X_EXPORT int xf86ClaimPciSlot( struct pci_device *, DriverPtr drvp, + int chipset, GDevPtr dev, Bool active); +extern _X_EXPORT void xf86UnclaimPciSlot(struct pci_device *); +extern _X_EXPORT Bool xf86ParsePciBusString(const char *busID, int *bus, int *device, + int *func); +extern _X_EXPORT Bool xf86ComparePciBusString(const char *busID, int bus, int device, int func); +extern _X_EXPORT void xf86FormatPciBusNumber(int busnum, char *buffer); +extern _X_EXPORT int xf86GetFbInfoForScreen(int scrnIndex); +extern _X_EXPORT int xf86ClaimFbSlot(DriverPtr drvp, int chipset, GDevPtr dev, Bool active); +extern _X_EXPORT int xf86ClaimNoSlot(DriverPtr drvp, int chipset, GDevPtr dev, Bool active); +extern _X_EXPORT void xf86EnableAccess(ScrnInfoPtr pScrn); +extern _X_EXPORT Bool xf86IsPrimaryPci(struct pci_device * pPci); +/* new RAC */ +extern _X_EXPORT Bool xf86DriverHasEntities(DriverPtr drvp); +extern _X_EXPORT void xf86AddEntityToScreen(ScrnInfoPtr pScrn, int entityIndex); +extern _X_EXPORT void xf86SetEntityInstanceForScreen(ScrnInfoPtr pScrn, int entityIndex, + int instance); +extern _X_EXPORT int xf86GetNumEntityInstances(int entityIndex); +extern _X_EXPORT GDevPtr xf86GetDevFromEntity(int entityIndex, int instance); +extern _X_EXPORT void xf86RemoveEntityFromScreen(ScrnInfoPtr pScrn, int entityIndex); +extern _X_EXPORT EntityInfoPtr xf86GetEntityInfo(int entityIndex); +extern _X_EXPORT struct pci_device * xf86GetPciInfoForEntity(int entityIndex); +extern _X_EXPORT Bool xf86SetEntityFuncs(int entityIndex, EntityProc init, + EntityProc enter, EntityProc leave, pointer); +extern _X_EXPORT Bool xf86CheckPciMemBase(struct pci_device * pPci, memType base); +extern _X_EXPORT Bool xf86IsEntityPrimary(int entityIndex); +extern _X_EXPORT void xf86EnterServerState(xf86State state); +extern _X_EXPORT ScrnInfoPtr xf86FindScreenForEntity(int entityIndex); + +extern _X_EXPORT int xf86GetLastScrnFlag(int entityIndex); +extern _X_EXPORT void xf86SetLastScrnFlag(int entityIndex, int scrnIndex); +extern _X_EXPORT Bool xf86IsEntityShared(int entityIndex); +extern _X_EXPORT void xf86SetEntityShared(int entityIndex); +extern _X_EXPORT Bool xf86IsEntitySharable(int entityIndex); +extern _X_EXPORT void xf86SetEntitySharable(int entityIndex); +extern _X_EXPORT Bool xf86IsPrimInitDone(int entityIndex); +extern _X_EXPORT void xf86SetPrimInitDone(int entityIndex); +extern _X_EXPORT void xf86ClearPrimInitDone(int entityIndex); +extern _X_EXPORT int xf86AllocateEntityPrivateIndex(void); +extern _X_EXPORT DevUnion *xf86GetEntityPrivate(int entityIndex, int privIndex); + +/* xf86Configure.c */ +extern _X_EXPORT GDevPtr xf86AddBusDeviceToConfigure(const char *driver, BusType bus, + void *busData, int chipset); + +/* xf86Cursor.c */ + +extern _X_EXPORT void xf86LockZoom(ScreenPtr pScreen, int lock); +extern _X_EXPORT void xf86InitViewport(ScrnInfoPtr pScr); +extern _X_EXPORT void xf86SetViewport(ScreenPtr pScreen, int x, int y); +extern _X_EXPORT void xf86ZoomViewport(ScreenPtr pScreen, int zoom); +extern _X_EXPORT Bool xf86SwitchMode(ScreenPtr pScreen, DisplayModePtr mode); +extern _X_EXPORT void *xf86GetPointerScreenFuncs(void); +extern _X_EXPORT void xf86InitOrigins(void); +extern _X_EXPORT void xf86ReconfigureLayout(void); + +/* xf86cvt.c */ +extern _X_EXPORT DisplayModePtr xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, + Bool Reduced, Bool Interlaced); + +/* xf86DPMS.c */ + +extern _X_EXPORT Bool xf86DPMSInit(ScreenPtr pScreen, DPMSSetProcPtr set, int flags); + +#ifdef DPMSExtension +extern _X_EXPORT int DPMSSet(ClientPtr client, int level); +extern _X_EXPORT Bool DPMSSupported(void); +#endif + + +/* xf86DGA.c */ + +#ifdef XFreeXDGA +extern _X_EXPORT Bool DGAInit(ScreenPtr pScreen, DGAFunctionPtr funcs, DGAModePtr modes, + int num); +extern _X_EXPORT Bool DGAReInitModes(ScreenPtr pScreen, DGAModePtr modes, int num); +extern _X_EXPORT xf86SetDGAModeProc xf86SetDGAMode; +#endif + +/* xf86Events.c */ + +extern _X_EXPORT void SetTimeSinceLastInputEvent(void); +extern _X_EXPORT pointer xf86AddInputHandler(int fd, InputHandlerProc proc, pointer data); +extern _X_EXPORT int xf86RemoveInputHandler(pointer handler); +extern _X_EXPORT void xf86DisableInputHandler(pointer handler); +extern _X_EXPORT void xf86EnableInputHandler(pointer handler); +extern _X_EXPORT pointer xf86AddGeneralHandler(int fd, InputHandlerProc proc, pointer data); +extern _X_EXPORT int xf86RemoveGeneralHandler(pointer handler); +extern _X_EXPORT void xf86DisableGeneralHandler(pointer handler); +extern _X_EXPORT void xf86EnableGeneralHandler(pointer handler); +extern _X_EXPORT void xf86InterceptSignals(int *signo); +extern _X_EXPORT void xf86InterceptSigIll(void (*sigillhandler)(void)); +extern _X_EXPORT Bool xf86EnableVTSwitch(Bool new); +extern _X_EXPORT void xf86ProcessActionEvent(ActionEvent action, void *arg); +extern _X_EXPORT void xf86PrintBacktrace(void); + +/* xf86Helper.c */ + +extern _X_EXPORT void xf86AddDriver(DriverPtr driver, pointer module, int flags); +extern _X_EXPORT void xf86DeleteDriver(int drvIndex); +extern _X_EXPORT ScrnInfoPtr xf86AllocateScreen(DriverPtr drv, int flags); +extern _X_EXPORT void xf86DeleteScreen(int scrnIndex, int flags); +extern _X_EXPORT int xf86AllocateScrnInfoPrivateIndex(void); +extern _X_EXPORT Bool xf86AddPixFormat(ScrnInfoPtr pScrn, int depth, int bpp, int pad); +extern _X_EXPORT Bool xf86SetDepthBpp(ScrnInfoPtr scrp, int depth, int bpp, int fbbpp, + int depth24flags); +extern _X_EXPORT void xf86PrintDepthBpp(ScrnInfoPtr scrp); +extern _X_EXPORT Bool xf86SetWeight(ScrnInfoPtr scrp, rgb weight, rgb mask); +extern _X_EXPORT Bool xf86SetDefaultVisual(ScrnInfoPtr scrp, int visual); +extern _X_EXPORT Bool xf86SetGamma(ScrnInfoPtr scrp, Gamma newGamma); +extern _X_EXPORT void xf86SetDpi(ScrnInfoPtr pScrn, int x, int y); +extern _X_EXPORT void xf86SetBlackWhitePixels(ScreenPtr pScreen); +extern _X_EXPORT void xf86EnableDisableFBAccess(int scrnIndex, Bool enable); +extern _X_EXPORT void xf86VDrvMsgVerb(int scrnIndex, MessageType type, int verb, + const char *format, va_list args); +extern _X_EXPORT void xf86DrvMsgVerb(int scrnIndex, MessageType type, int verb, + const char *format, ...) _X_ATTRIBUTE_PRINTF(4,5); +extern _X_EXPORT void xf86DrvMsg(int scrnIndex, MessageType type, const char *format, ...) + _X_ATTRIBUTE_PRINTF(3,4); +extern _X_EXPORT void xf86MsgVerb(MessageType type, int verb, const char *format, ...) + _X_ATTRIBUTE_PRINTF(3,4); +extern _X_EXPORT void xf86Msg(MessageType type, const char *format, ...) _X_ATTRIBUTE_PRINTF(2,3); +extern _X_EXPORT void xf86ErrorFVerb(int verb, const char *format, ...) _X_ATTRIBUTE_PRINTF(2,3); +extern _X_EXPORT void xf86ErrorF(const char *format, ...) _X_ATTRIBUTE_PRINTF(1,2); +extern _X_EXPORT const char *xf86TokenToString(SymTabPtr table, int token); +extern _X_EXPORT int xf86StringToToken(SymTabPtr table, const char *string); +extern _X_EXPORT void xf86ShowClocks(ScrnInfoPtr scrp, MessageType from); +extern _X_EXPORT void xf86PrintChipsets(const char *drvname, const char *drvmsg, + SymTabPtr chips); +extern _X_EXPORT int xf86MatchDevice(const char *drivername, GDevPtr **driversectlist); +extern _X_EXPORT int xf86MatchPciInstances(const char *driverName, int vendorID, + SymTabPtr chipsets, PciChipsets *PCIchipsets, + GDevPtr *devList, int numDevs, DriverPtr drvp, + int **foundEntities); +extern _X_EXPORT void xf86GetClocks(ScrnInfoPtr pScrn, int num, + Bool (*ClockFunc)(ScrnInfoPtr, int), + void (*ProtectRegs)(ScrnInfoPtr, Bool), + void (*BlankScreen)(ScrnInfoPtr, Bool), + IOADDRESS vertsyncreg, int maskval, + int knownclkindex, int knownclkvalue); +extern _X_EXPORT const char *xf86GetVisualName(int visual); +extern _X_EXPORT int xf86GetVerbosity(void); +extern _X_EXPORT Pix24Flags xf86GetPix24(void); +extern _X_EXPORT int xf86GetDepth(void); +extern _X_EXPORT rgb xf86GetWeight(void); +extern _X_EXPORT Gamma xf86GetGamma(void); +extern _X_EXPORT Bool xf86GetFlipPixels(void); +extern _X_EXPORT const char *xf86GetServerName(void); +extern _X_EXPORT Bool xf86ServerIsExiting(void); +extern _X_EXPORT Bool xf86ServerIsResetting(void); +extern _X_EXPORT Bool xf86ServerIsInitialising(void); +extern _X_EXPORT Bool xf86ServerIsOnlyDetecting(void); +extern _X_EXPORT Bool xf86CaughtSignal(void); +extern _X_EXPORT Bool xf86GetVidModeAllowNonLocal(void); +extern _X_EXPORT Bool xf86GetVidModeEnabled(void); +extern _X_EXPORT Bool xf86GetModInDevAllowNonLocal(void); +extern _X_EXPORT Bool xf86GetModInDevEnabled(void); +extern _X_EXPORT Bool xf86GetAllowMouseOpenFail(void); +extern _X_EXPORT Bool xf86IsPc98(void); +extern _X_EXPORT void xf86DisableRandR(void); +extern _X_EXPORT CARD32 xorgGetVersion(void); +extern _X_EXPORT CARD32 xf86GetModuleVersion(pointer module); +extern _X_EXPORT pointer xf86LoadDrvSubModule(DriverPtr drv, const char *name); +extern _X_EXPORT pointer xf86LoadSubModule(ScrnInfoPtr pScrn, const char *name); +extern _X_EXPORT pointer xf86LoadOneModule(char *name, pointer optlist); +extern _X_EXPORT void xf86UnloadSubModule(pointer mod); +extern _X_EXPORT Bool xf86LoaderCheckSymbol(const char *name); +extern _X_EXPORT void xf86SetBackingStore(ScreenPtr pScreen); +extern _X_EXPORT void xf86SetSilkenMouse(ScreenPtr pScreen); +extern _X_EXPORT pointer xf86FindXvOptions(int scrnIndex, int adapt_index, char *port_name, + char **adaptor_name, pointer *adaptor_options); +extern _X_EXPORT void xf86GetOS(const char **name, int *major, int *minor, int *teeny); +extern _X_EXPORT ScrnInfoPtr xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, + int entityIndex,PciChipsets *p_chip, + void *dummy, EntityProc init, + EntityProc enter, EntityProc leave, + pointer private); +extern _X_EXPORT ScrnInfoPtr xf86ConfigFbEntity(ScrnInfoPtr pScrn, int scrnFlag, + int entityIndex, EntityProc init, + EntityProc enter, EntityProc leave, + pointer private); + +/* Obsolete! don't use */ +extern _X_EXPORT Bool xf86ConfigActivePciEntity(ScrnInfoPtr pScrn, + int entityIndex,PciChipsets *p_chip, + void *dummy, EntityProc init, + EntityProc enter, EntityProc leave, + pointer private); + +extern _X_EXPORT Bool xf86IsScreenPrimary(int scrnIndex); +extern _X_EXPORT int xf86RegisterRootWindowProperty(int ScrnIndex, Atom property, Atom type, + int format, unsigned long len, + pointer value); +extern _X_EXPORT Bool xf86IsUnblank(int mode); + +/* xf86Init.c */ + +extern _X_EXPORT PixmapFormatPtr xf86GetPixFormat(ScrnInfoPtr pScrn, int depth); +extern _X_EXPORT int xf86GetBppFromDepth(ScrnInfoPtr pScrn, int depth); + +/* xf86Mode.c */ + +extern _X_EXPORT int xf86GetNearestClock(ScrnInfoPtr scrp, int freq, Bool allowDiv2, + int DivFactor, int MulFactor, int *divider); +extern _X_EXPORT const char *xf86ModeStatusToString(ModeStatus status); +extern _X_EXPORT ModeStatus xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep, + ClockRangePtr clockRanges, LookupModeFlags strategy); +extern _X_EXPORT ModeStatus xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor); +extern _X_EXPORT ModeStatus xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, + ClockRangePtr clockRanges, + LookupModeFlags strategy, + int maxPitch, int virtualX, + int virtualY); +extern _X_EXPORT ModeStatus xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, + int flags); +extern _X_EXPORT int xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, + char **modeNames, ClockRangePtr clockRanges, + int *linePitches, int minPitch, int maxPitch, + int minHeight, int maxHeight, int pitchInc, + int virtualX, int virtualY, int apertureSize, + LookupModeFlags strategy); +extern _X_EXPORT void xf86DeleteMode(DisplayModePtr *modeList, DisplayModePtr mode); +extern _X_EXPORT void xf86PruneDriverModes(ScrnInfoPtr scrp); +extern _X_EXPORT void xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags); +extern _X_EXPORT void xf86PrintModes(ScrnInfoPtr scrp); +extern _X_EXPORT void xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges); +extern _X_EXPORT double xf86ModeHSync(const DisplayModeRec *mode); +extern _X_EXPORT double xf86ModeVRefresh(const DisplayModeRec *mode); +extern _X_EXPORT void xf86SetModeDefaultName(DisplayModePtr mode); +extern _X_EXPORT void xf86SetModeCrtc(DisplayModePtr p, int adjustFlags); +extern _X_EXPORT DisplayModePtr xf86DuplicateMode(const DisplayModeRec *pMode); +extern _X_EXPORT DisplayModePtr xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList); +extern _X_EXPORT Bool xf86ModesEqual(const DisplayModeRec *pMode1, + const DisplayModeRec *pMode2); +extern _X_EXPORT void xf86PrintModeline(int scrnIndex,DisplayModePtr mode); +extern _X_EXPORT DisplayModePtr xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new); + +/* xf86Option.c */ + +extern _X_EXPORT void xf86CollectOptions(ScrnInfoPtr pScrn, pointer extraOpts); + + +/* xf86RandR.c */ +#ifdef RANDR +extern _X_EXPORT Bool xf86RandRInit (ScreenPtr pScreen); +extern _X_EXPORT Rotation xf86GetRotation(ScreenPtr pScreen); +extern _X_EXPORT Bool xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen, + int newvirtX, int newvirtY, + int newmmWidth, int newmmHeight, Bool resetMode); +#endif + +/* xf86VidModeExtentionInit.c */ + +extern _X_EXPORT Bool VidModeExtensionInit(ScreenPtr pScreen); + +#endif /* _NO_XF86_PROTOTYPES */ + +#endif /* _XF86_H */ diff --git a/xorg-server/hw/xfree86/common/xf86AutoConfig.c b/xorg-server/hw/xfree86/common/xf86AutoConfig.c index 7b836b00d..88891e5a7 100644 --- a/xorg-server/hw/xfree86/common/xf86AutoConfig.c +++ b/xorg-server/hw/xfree86/common/xf86AutoConfig.c @@ -1,638 +1,638 @@ -/* - * Copyright 2003 by David H. Dawes. - * Copyright 2003 by X-Oz Technologies. - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - * - * Author: David Dawes <dawes@XFree86.Org>. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86Parser.h" -#include "xf86tokens.h" -#include "xf86Config.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" -#ifdef __sparc__ -# include "xf86sbusBus.h" -#endif -#include "dirent.h" - -#ifdef sun -# include <sys/visual_io.h> -# include <ctype.h> -#endif - -/* Sections for the default built-in configuration. */ - -#define BUILTIN_DEVICE_NAME \ - "\"Builtin Default %s Device %d\"" - -#define BUILTIN_DEVICE_SECTION_PRE \ - "Section \"Device\"\n" \ - "\tIdentifier\t" BUILTIN_DEVICE_NAME "\n" \ - "\tDriver\t\"%s\"\n" - -#define BUILTIN_DEVICE_SECTION_POST \ - "EndSection\n\n" - -#define BUILTIN_DEVICE_SECTION \ - BUILTIN_DEVICE_SECTION_PRE \ - BUILTIN_DEVICE_SECTION_POST - -#define BUILTIN_SCREEN_NAME \ - "\"Builtin Default %s Screen %d\"" - -#define BUILTIN_SCREEN_SECTION \ - "Section \"Screen\"\n" \ - "\tIdentifier\t" BUILTIN_SCREEN_NAME "\n" \ - "\tDevice\t" BUILTIN_DEVICE_NAME "\n" \ - "EndSection\n\n" - -#define BUILTIN_LAYOUT_SECTION_PRE \ - "Section \"ServerLayout\"\n" \ - "\tIdentifier\t\"Builtin Default Layout\"\n" - -#define BUILTIN_LAYOUT_SCREEN_LINE \ - "\tScreen\t" BUILTIN_SCREEN_NAME "\n" - -#define BUILTIN_LAYOUT_SECTION_POST \ - "EndSection\n\n" - -static const char **builtinConfig = NULL; -static int builtinLines = 0; - -static void listPossibleVideoDrivers(char *matches[], int nmatches); - -/* - * A built-in config file is stored as an array of strings, with each string - * representing a single line. AppendToConfig() breaks up the string "s" - * into lines, and appends those lines it to builtinConfig. - */ - -static void -AppendToList(const char *s, const char ***list, int *lines) -{ - char *str, *newstr, *p; - - str = xnfstrdup(s); - for (p = strtok(str, "\n"); p; p = strtok(NULL, "\n")) { - (*lines)++; - *list = xnfrealloc(*list, (*lines + 1) * sizeof(**list)); - newstr = xnfalloc(strlen(p) + 2); - strcpy(newstr, p); - strcat(newstr, "\n"); - (*list)[*lines - 1] = newstr; - (*list)[*lines] = NULL; - } - xfree(str); -} - -static void -FreeList(const char ***list, int *lines) -{ - int i; - - for (i = 0; i < *lines; i++) { - if ((*list)[i]) - xfree((*list)[i]); - } - xfree(*list); - *list = NULL; - *lines = 0; -} - -static void -FreeConfig(void) -{ - FreeList(&builtinConfig, &builtinLines); -} - -static void -AppendToConfig(const char *s) -{ - AppendToList(s, &builtinConfig, &builtinLines); -} - -static int -videoPtrToDriverList(struct pci_device *dev, - char *returnList[], int returnListMax) -{ - int i; - /* Add more entries here if we ever return more than 4 drivers for - any device */ - char *driverList[5] = { NULL, NULL, NULL, NULL, NULL }; - - switch (dev->vendor_id) - { - /* AMD Geode LX */ - case 0x1022: - if (dev->device_id == 0x2081) - driverList[0] = "geode"; - break; - /* older Geode products acquired by AMD still carry an NSC vendor_id */ - case 0x100b: - if (dev->device_id == 0x0030) { - /* NSC Geode GX2 specifically */ - driverList[0] = "geode"; - /* GX2 support started its life in the NSC tree and was later - forked by AMD for GEODE so we keep it as a backup */ - driverList[1] = "nsc"; - } else - /* other NSC variant e.g. 0x0104 (SC1400), 0x0504 (SCx200) */ - driverList[0] = "nsc"; - break; - /* Cyrix Geode GX1 */ - case 0x1078: - if (dev->device_id == 0x0104) - driverList[0] = "cyrix"; - break; - case 0x1142: driverList[0] = "apm"; break; - case 0xedd8: driverList[0] = "ark"; break; - case 0x1a03: driverList[0] = "ast"; break; - case 0x1002: driverList[0] = "ati"; break; - case 0x102c: driverList[0] = "chips"; break; - case 0x1013: driverList[0] = "cirrus"; break; - case 0x3d3d: driverList[0] = "glint"; break; - case 0x105d: driverList[0] = "i128"; break; - case 0x8086: - if ((dev->device_id == 0x00d1) || (dev->device_id == 0x7800)) { - driverList[0] = "i740"; - } else if (dev->device_id == 0x8108) { - break; /* "hooray" for poulsbo */ - } else { - driverList[0] = "intel"; - } - break; - case 0x102b: driverList[0] = "mga"; break; - case 0x10c8: driverList[0] = "neomagic"; break; - case 0x10de: case 0x12d2: driverList[0] = "nv"; break; - case 0x1106: driverList[0] = "openchrome"; break; - case 0x1b36: driverList[0] = "qxl"; break; - case 0x1163: driverList[0] = "rendition"; break; - case 0x5333: - switch (dev->device_id) - { - case 0x88d0: case 0x88d1: case 0x88f0: case 0x8811: - case 0x8812: case 0x8814: case 0x8901: - driverList[0] = "s3"; break; - case 0x5631: case 0x883d: case 0x8a01: case 0x8a10: - case 0x8c01: case 0x8c03: case 0x8904: case 0x8a13: - driverList[0] = "s3virge"; break; - default: - driverList[0] = "savage"; break; - } - break; - case 0x1039: driverList[0] = "sis"; break; - case 0x126f: driverList[0] = "siliconmotion"; break; - case 0x121a: - if (dev->device_id < 0x0003) - driverList[0] = "voodoo"; - else - driverList[0] = "tdfx"; - break; - case 0x1011: driverList[0] = "tga"; break; - case 0x1023: driverList[0] = "trident"; break; - case 0x100c: driverList[0] = "tseng"; break; - case 0x80ee: driverList[0] = "vboxvideo"; break; - case 0x15ad: driverList[0] = "vmware"; break; - case 0x18ca: - if (dev->device_id == 0x47) - driverList[0] = "xgixp"; - else - driverList[0] = "xgi"; - break; - default: break; - } - for (i = 0; (i < returnListMax) && (driverList[i] != NULL); i++) { - returnList[i] = xnfstrdup(driverList[i]); - } - return i; /* Number of entries added */ -} - -Bool -xf86AutoConfig(void) -{ - char *deviceList[20]; - char **p; - const char **cp; - char buf[1024]; - ConfigStatus ret; - - listPossibleVideoDrivers(deviceList, 20); - - for (p = deviceList; *p; p++) { - snprintf(buf, sizeof(buf), BUILTIN_DEVICE_SECTION, *p, 0, *p); - AppendToConfig(buf); - snprintf(buf, sizeof(buf), BUILTIN_SCREEN_SECTION, *p, 0, *p, 0); - AppendToConfig(buf); - } - - AppendToConfig(BUILTIN_LAYOUT_SECTION_PRE); - for (p = deviceList; *p; p++) { - snprintf(buf, sizeof(buf), BUILTIN_LAYOUT_SCREEN_LINE, *p, 0); - AppendToConfig(buf); - } - AppendToConfig(BUILTIN_LAYOUT_SECTION_POST); - - for (p = deviceList; *p; p++) { - xfree(*p); - } - - xf86MsgVerb(X_DEFAULT, 0, - "Using default built-in configuration (%d lines)\n", - builtinLines); - - xf86MsgVerb(X_DEFAULT, 3, "--- Start of built-in configuration ---\n"); - for (cp = builtinConfig; *cp; cp++) - xf86ErrorFVerb(3, "\t%s", *cp); - xf86MsgVerb(X_DEFAULT, 3, "--- End of built-in configuration ---\n"); - - xf86initConfigFiles(); - xf86setBuiltinConfig(builtinConfig); - ret = xf86HandleConfigFile(TRUE); - FreeConfig(); - - if (ret != CONFIG_OK) - xf86Msg(X_ERROR, "Error parsing the built-in default configuration.\n"); - - return (ret == CONFIG_OK); -} - -static int -xchomp(char *line) -{ - size_t len = 0; - - if (!line) { - return 1; - } - - len = strlen(line); - if (line[len - 1] == '\n' && len > 0) { - line[len - 1] = '\0'; - } - return 0; -} - -#ifdef __linux__ -/* This function is used to provide a workaround for binary drivers that - * don't export their PCI ID's properly. If distros don't end up using this - * feature it can and should be removed because the symbol-based resolution - * scheme should be the primary one */ -static void -matchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip) -{ - DIR *idsdir; - FILE *fp; - struct dirent *direntry; - char *line = NULL; - size_t len; - ssize_t read; - char path_name[256], vendor_str[5], chip_str[5]; - uint16_t vendor, chip; - int i, j; - - idsdir = opendir(PCI_TXT_IDS_PATH); - if (!idsdir) - return; - - xf86Msg(X_INFO, "Scanning %s directory for additional PCI ID's supported by the drivers\n", PCI_TXT_IDS_PATH); - direntry = readdir(idsdir); - /* Read the directory */ - while (direntry) { - if (direntry->d_name[0] == '.') { - direntry = readdir(idsdir); - continue; - } - len = strlen(direntry->d_name); - /* A tiny bit of sanity checking. We should probably do better */ - if (strncmp(&(direntry->d_name[len-4]), ".ids", 4) == 0) { - /* We need the full path name to open the file */ - strncpy(path_name, PCI_TXT_IDS_PATH, 256); - strncat(path_name, "/", 1); - strncat(path_name, direntry->d_name, (256 - strlen(path_name) - 1)); - fp = fopen(path_name, "r"); - if (fp == NULL) { - xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n", path_name); - goto end; - } - /* Read the file */ -#ifdef __GLIBC__ - while ((read = getline(&line, &len, fp)) != -1) { -#else - while ((line = fgetln(fp, &len)) != (char *)NULL) { -#endif /* __GLIBC __ */ - xchomp(line); - if (isdigit(line[0])) { - strncpy(vendor_str, line, 4); - vendor_str[4] = '\0'; - vendor = (int)strtol(vendor_str, NULL, 16); - if ((strlen(&line[4])) == 0) { - chip_str[0] = '\0'; - chip = -1; - } else { - /* Handle trailing whitespace */ - if (isspace(line[4])) { - chip_str[0] = '\0'; - chip = -1; - } else { - /* Ok, it's a real ID */ - strncpy(chip_str, &line[4], 4); - chip_str[4] = '\0'; - chip = (int)strtol(chip_str, NULL, 16); - } - } - if (vendor == match_vendor && chip == match_chip ) { - i = 0; - while (matches[i]) { - i++; - } - matches[i] = (char*)xalloc(sizeof(char) * strlen(direntry->d_name) - 3); - if (!matches[i]) { - xf86Msg(X_ERROR, "Could not allocate space for the module name. Exiting.\n"); - goto end; - } - /* hack off the .ids suffix. This should guard - * against other problems, but it will end up - * taking off anything after the first '.' */ - for (j = 0; j < (strlen(direntry->d_name) - 3) ; j++) { - if (direntry->d_name[j] == '.') { - matches[i][j] = '\0'; - break; - } else { - matches[i][j] = direntry->d_name[j]; - } - } - xf86Msg(X_INFO, "Matched %s from file name %s\n", matches[i], direntry->d_name); - } - } else { - /* TODO Handle driver overrides here */ - } - } - fclose(fp); - } - direntry = readdir(idsdir); - } - end: - xfree(line); - closedir(idsdir); -} -#endif /* __linux__ */ - -static void -listPossibleVideoDrivers(char *matches[], int nmatches) -{ - struct pci_device * info = NULL; - struct pci_device_iterator *iter; - int i; - - for (i = 0 ; i < nmatches ; i++) { - matches[i] = NULL; - } - i = 0; - -#ifdef sun - /* Check for driver type based on /dev/fb type and if valid, use - it instead of PCI bus probe results */ - if (xf86Info.consoleFd >= 0) { - struct vis_identifier visid; - const char *cp; - extern char xf86SolarisFbDev[PATH_MAX]; - int iret; - - SYSCALL(iret = ioctl(xf86Info.consoleFd, VIS_GETIDENTIFIER, &visid)); - if (iret < 0) { - int fbfd; - - fbfd = open(xf86SolarisFbDev, O_RDONLY); - if (fbfd >= 0) { - SYSCALL(iret = ioctl(fbfd, VIS_GETIDENTIFIER, &visid)); - close(fbfd); - } - } - - if (iret < 0) { - xf86Msg(X_WARNING, - "could not get frame buffer identifier from %s\n", - xf86SolarisFbDev); - } else { - xf86Msg(X_PROBED, "console driver: %s\n", visid.name); - - /* Special case from before the general case was set */ - if (strcmp(visid.name, "NVDAnvda") == 0) { - matches[i++] = xnfstrdup("nvidia"); - } - - /* General case - split into vendor name (initial all-caps - prefix) & driver name (rest of the string). */ - if (strcmp(visid.name, "SUNWtext") != 0) { - for (cp = visid.name; (*cp != '\0') && isupper(*cp); cp++) { - /* find end of all uppercase vendor section */ - } - if ((cp != visid.name) && (*cp != '\0')) { - char *driverName = xnfstrdup(cp); - char *vendorName = xnfstrdup(visid.name); - vendorName[cp - visid.name] = '\0'; - - matches[i++] = vendorName; - matches[i++] = driverName; - } - } - } - } -#endif -#ifdef __sparc__ - { - char *sbusDriver = sparcDriverName(); - if (sbusDriver) - matches[i++] = xnfstrdup(sbusDriver); - } -#endif - - /* Find the primary device, and get some information about it. */ - iter = pci_slot_match_iterator_create(NULL); - while ((info = pci_device_next(iter)) != NULL) { - if (xf86IsPrimaryPci(info)) { - break; - } - } - - pci_iterator_destroy(iter); - - if (!info) { - ErrorF("Primary device is not PCI\n"); - } -#ifdef __linux__ - else { - matchDriverFromFiles(matches, info->vendor_id, info->device_id); - } -#endif /* __linux__ */ - - for (i = 0; (i < nmatches) && (matches[i]); i++) { - /* find end of matches list */ - } - - if ((info != NULL) && (i < nmatches)) { - i += videoPtrToDriverList(info, &(matches[i]), nmatches - i); - } - - /* Fallback to platform default hardware */ - if (i < (nmatches - 1)) { -#if defined(__i386__) || defined(__amd64__) || defined(__hurd__) - matches[i++] = xnfstrdup("vesa"); -#elif defined(__sparc__) && !defined(sun) - matches[i++] = xnfstrdup("sunffb"); -#endif - } - - /* Fallback to platform default frame buffer driver */ - if (i < (nmatches - 1)) { -#if !defined(__linux__) && defined(__sparc__) - matches[i++] = xnfstrdup("wsfb"); -#else - matches[i++] = xnfstrdup("fbdev"); -#endif - } -} - -/* copy a screen section and enter the desired driver - * and insert it at i in the list of screens */ -static Bool -copyScreen(confScreenPtr oscreen, GDevPtr odev, int i, char *driver) -{ - GDevPtr cptr = NULL; - - xf86ConfigLayout.screens[i].screen = xnfcalloc(1, sizeof(confScreenRec)); - if(!xf86ConfigLayout.screens[i].screen) - return FALSE; - memcpy(xf86ConfigLayout.screens[i].screen, oscreen, sizeof(confScreenRec)); - - cptr = xcalloc(1, sizeof(GDevRec)); - if (!cptr) - return FALSE; - memcpy(cptr, odev, sizeof(GDevRec)); - - cptr->identifier = Xprintf("Autoconfigured Video Device %s", driver); - cptr->driver = driver; - - /* now associate the new driver entry with the new screen entry */ - xf86ConfigLayout.screens[i].screen->device = cptr; - cptr->myScreenSection = xf86ConfigLayout.screens[i].screen; - - return TRUE; -} - -GDevPtr -autoConfigDevice(GDevPtr preconf_device) -{ - GDevPtr ptr = NULL; - char *matches[20]; /* If we have more than 20 drivers we're in trouble */ - int num_matches = 0, num_screens = 0, i; - screenLayoutPtr slp; - - if (!xf86configptr) { - return NULL; - } - - /* If there's a configured section with no driver chosen, use it */ - if (preconf_device) { - ptr = preconf_device; - } else { - ptr = xcalloc(1, sizeof(GDevRec)); - if (!ptr) { - return NULL; - } - ptr->chipID = -1; - ptr->chipRev = -1; - ptr->irq = -1; - - ptr->active = TRUE; - ptr->claimed = FALSE; - ptr->identifier = "Autoconfigured Video Device"; - ptr->driver = NULL; - } - if (!ptr->driver) { - /* get all possible video drivers and count them */ - listPossibleVideoDrivers(matches, 20); - for (; matches[num_matches]; num_matches++) { - xf86Msg(X_DEFAULT, "Matched %s as autoconfigured driver %d\n", - matches[num_matches], num_matches); - } - - slp = xf86ConfigLayout.screens; - if (slp) { - /* count the number of screens and make space for - * a new screen for each additional possible driver - * minus one for the already existing first one - * plus one for the terminating NULL */ - for (; slp[num_screens].screen; num_screens++); - xf86ConfigLayout.screens = xnfcalloc(num_screens + num_matches, - sizeof(screenLayoutRec)); - xf86ConfigLayout.screens[0] = slp[0]; - - /* do the first match and set that for the original first screen */ - ptr->driver = matches[0]; - if (!xf86ConfigLayout.screens[0].screen->device) { - xf86ConfigLayout.screens[0].screen->device = ptr; - ptr->myScreenSection = xf86ConfigLayout.screens[0].screen; - } - - /* for each other driver found, copy the first screen, insert it - * into the list of screens and set the driver */ - i = 0; - while (i++ < num_matches) { - if (!copyScreen(slp[0].screen, ptr, i, matches[i])) - return NULL; - } - - /* shift the rest of the original screen list - * to the end of the current screen list - * - * TODO Handle rest of multiple screen sections */ - for (i = 1; i < num_screens; i++) { - xf86ConfigLayout.screens[i+num_matches] = slp[i]; - } - xf86ConfigLayout.screens[num_screens+num_matches-1].screen = NULL; - xfree(slp); - } else { - /* layout does not have any screens, not much to do */ - ptr->driver = matches[0]; - for (i = 1; matches[i] ; i++) { - if (matches[i] != matches[0]) { - xfree(matches[i]); - } - } - } - } - - xf86Msg(X_DEFAULT, "Assigned the driver to the xf86ConfigLayout\n"); - - return ptr; -} +/* + * Copyright 2003 by David H. Dawes. + * Copyright 2003 by X-Oz Technologies. + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + * + * Author: David Dawes <dawes@XFree86.Org>. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "xf86Config.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#ifdef __sparc__ +# include "xf86sbusBus.h" +#endif +#include "dirent.h" + +#ifdef sun +# include <sys/visual_io.h> +# include <ctype.h> +#endif + +/* Sections for the default built-in configuration. */ + +#define BUILTIN_DEVICE_NAME \ + "\"Builtin Default %s Device %d\"" + +#define BUILTIN_DEVICE_SECTION_PRE \ + "Section \"Device\"\n" \ + "\tIdentifier\t" BUILTIN_DEVICE_NAME "\n" \ + "\tDriver\t\"%s\"\n" + +#define BUILTIN_DEVICE_SECTION_POST \ + "EndSection\n\n" + +#define BUILTIN_DEVICE_SECTION \ + BUILTIN_DEVICE_SECTION_PRE \ + BUILTIN_DEVICE_SECTION_POST + +#define BUILTIN_SCREEN_NAME \ + "\"Builtin Default %s Screen %d\"" + +#define BUILTIN_SCREEN_SECTION \ + "Section \"Screen\"\n" \ + "\tIdentifier\t" BUILTIN_SCREEN_NAME "\n" \ + "\tDevice\t" BUILTIN_DEVICE_NAME "\n" \ + "EndSection\n\n" + +#define BUILTIN_LAYOUT_SECTION_PRE \ + "Section \"ServerLayout\"\n" \ + "\tIdentifier\t\"Builtin Default Layout\"\n" + +#define BUILTIN_LAYOUT_SCREEN_LINE \ + "\tScreen\t" BUILTIN_SCREEN_NAME "\n" + +#define BUILTIN_LAYOUT_SECTION_POST \ + "EndSection\n\n" + +static const char **builtinConfig = NULL; +static int builtinLines = 0; + +static void listPossibleVideoDrivers(char *matches[], int nmatches); + +/* + * A built-in config file is stored as an array of strings, with each string + * representing a single line. AppendToConfig() breaks up the string "s" + * into lines, and appends those lines it to builtinConfig. + */ + +static void +AppendToList(const char *s, const char ***list, int *lines) +{ + char *str, *newstr, *p; + + str = xnfstrdup(s); + for (p = strtok(str, "\n"); p; p = strtok(NULL, "\n")) { + (*lines)++; + *list = xnfrealloc(*list, (*lines + 1) * sizeof(**list)); + newstr = xnfalloc(strlen(p) + 2); + strcpy(newstr, p); + strcat(newstr, "\n"); + (*list)[*lines - 1] = newstr; + (*list)[*lines] = NULL; + } + free(str); +} + +static void +FreeList(const char ***list, int *lines) +{ + int i; + + for (i = 0; i < *lines; i++) { + if ((*list)[i]) + free((*list)[i]); + } + free(*list); + *list = NULL; + *lines = 0; +} + +static void +FreeConfig(void) +{ + FreeList(&builtinConfig, &builtinLines); +} + +static void +AppendToConfig(const char *s) +{ + AppendToList(s, &builtinConfig, &builtinLines); +} + +static int +videoPtrToDriverList(struct pci_device *dev, + char *returnList[], int returnListMax) +{ + int i; + /* Add more entries here if we ever return more than 4 drivers for + any device */ + char *driverList[5] = { NULL, NULL, NULL, NULL, NULL }; + + switch (dev->vendor_id) + { + /* AMD Geode LX */ + case 0x1022: + if (dev->device_id == 0x2081) + driverList[0] = "geode"; + break; + /* older Geode products acquired by AMD still carry an NSC vendor_id */ + case 0x100b: + if (dev->device_id == 0x0030) { + /* NSC Geode GX2 specifically */ + driverList[0] = "geode"; + /* GX2 support started its life in the NSC tree and was later + forked by AMD for GEODE so we keep it as a backup */ + driverList[1] = "nsc"; + } else + /* other NSC variant e.g. 0x0104 (SC1400), 0x0504 (SCx200) */ + driverList[0] = "nsc"; + break; + /* Cyrix Geode GX1 */ + case 0x1078: + if (dev->device_id == 0x0104) + driverList[0] = "cyrix"; + break; + case 0x1142: driverList[0] = "apm"; break; + case 0xedd8: driverList[0] = "ark"; break; + case 0x1a03: driverList[0] = "ast"; break; + case 0x1002: driverList[0] = "ati"; break; + case 0x102c: driverList[0] = "chips"; break; + case 0x1013: driverList[0] = "cirrus"; break; + case 0x3d3d: driverList[0] = "glint"; break; + case 0x105d: driverList[0] = "i128"; break; + case 0x8086: + if ((dev->device_id == 0x00d1) || (dev->device_id == 0x7800)) { + driverList[0] = "i740"; + } else if (dev->device_id == 0x8108) { + break; /* "hooray" for poulsbo */ + } else { + driverList[0] = "intel"; + } + break; + case 0x102b: driverList[0] = "mga"; break; + case 0x10c8: driverList[0] = "neomagic"; break; + case 0x10de: case 0x12d2: driverList[0] = "nv"; break; + case 0x1106: driverList[0] = "openchrome"; break; + case 0x1b36: driverList[0] = "qxl"; break; + case 0x1163: driverList[0] = "rendition"; break; + case 0x5333: + switch (dev->device_id) + { + case 0x88d0: case 0x88d1: case 0x88f0: case 0x8811: + case 0x8812: case 0x8814: case 0x8901: + driverList[0] = "s3"; break; + case 0x5631: case 0x883d: case 0x8a01: case 0x8a10: + case 0x8c01: case 0x8c03: case 0x8904: case 0x8a13: + driverList[0] = "s3virge"; break; + default: + driverList[0] = "savage"; break; + } + break; + case 0x1039: driverList[0] = "sis"; break; + case 0x126f: driverList[0] = "siliconmotion"; break; + case 0x121a: + if (dev->device_id < 0x0003) + driverList[0] = "voodoo"; + else + driverList[0] = "tdfx"; + break; + case 0x1011: driverList[0] = "tga"; break; + case 0x1023: driverList[0] = "trident"; break; + case 0x100c: driverList[0] = "tseng"; break; + case 0x80ee: driverList[0] = "vboxvideo"; break; + case 0x15ad: driverList[0] = "vmware"; break; + case 0x18ca: + if (dev->device_id == 0x47) + driverList[0] = "xgixp"; + else + driverList[0] = "xgi"; + break; + default: break; + } + for (i = 0; (i < returnListMax) && (driverList[i] != NULL); i++) { + returnList[i] = xnfstrdup(driverList[i]); + } + return i; /* Number of entries added */ +} + +Bool +xf86AutoConfig(void) +{ + char *deviceList[20]; + char **p; + const char **cp; + char buf[1024]; + ConfigStatus ret; + + listPossibleVideoDrivers(deviceList, 20); + + for (p = deviceList; *p; p++) { + snprintf(buf, sizeof(buf), BUILTIN_DEVICE_SECTION, *p, 0, *p); + AppendToConfig(buf); + snprintf(buf, sizeof(buf), BUILTIN_SCREEN_SECTION, *p, 0, *p, 0); + AppendToConfig(buf); + } + + AppendToConfig(BUILTIN_LAYOUT_SECTION_PRE); + for (p = deviceList; *p; p++) { + snprintf(buf, sizeof(buf), BUILTIN_LAYOUT_SCREEN_LINE, *p, 0); + AppendToConfig(buf); + } + AppendToConfig(BUILTIN_LAYOUT_SECTION_POST); + + for (p = deviceList; *p; p++) { + free(*p); + } + + xf86MsgVerb(X_DEFAULT, 0, + "Using default built-in configuration (%d lines)\n", + builtinLines); + + xf86MsgVerb(X_DEFAULT, 3, "--- Start of built-in configuration ---\n"); + for (cp = builtinConfig; *cp; cp++) + xf86ErrorFVerb(3, "\t%s", *cp); + xf86MsgVerb(X_DEFAULT, 3, "--- End of built-in configuration ---\n"); + + xf86initConfigFiles(); + xf86setBuiltinConfig(builtinConfig); + ret = xf86HandleConfigFile(TRUE); + FreeConfig(); + + if (ret != CONFIG_OK) + xf86Msg(X_ERROR, "Error parsing the built-in default configuration.\n"); + + return (ret == CONFIG_OK); +} + +static int +xchomp(char *line) +{ + size_t len = 0; + + if (!line) { + return 1; + } + + len = strlen(line); + if (line[len - 1] == '\n' && len > 0) { + line[len - 1] = '\0'; + } + return 0; +} + +#ifdef __linux__ +/* This function is used to provide a workaround for binary drivers that + * don't export their PCI ID's properly. If distros don't end up using this + * feature it can and should be removed because the symbol-based resolution + * scheme should be the primary one */ +static void +matchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip) +{ + DIR *idsdir; + FILE *fp; + struct dirent *direntry; + char *line = NULL; + size_t len; + ssize_t read; + char path_name[256], vendor_str[5], chip_str[5]; + uint16_t vendor, chip; + int i, j; + + idsdir = opendir(PCI_TXT_IDS_PATH); + if (!idsdir) + return; + + xf86Msg(X_INFO, "Scanning %s directory for additional PCI ID's supported by the drivers\n", PCI_TXT_IDS_PATH); + direntry = readdir(idsdir); + /* Read the directory */ + while (direntry) { + if (direntry->d_name[0] == '.') { + direntry = readdir(idsdir); + continue; + } + len = strlen(direntry->d_name); + /* A tiny bit of sanity checking. We should probably do better */ + if (strncmp(&(direntry->d_name[len-4]), ".ids", 4) == 0) { + /* We need the full path name to open the file */ + strncpy(path_name, PCI_TXT_IDS_PATH, 256); + strncat(path_name, "/", 1); + strncat(path_name, direntry->d_name, (256 - strlen(path_name) - 1)); + fp = fopen(path_name, "r"); + if (fp == NULL) { + xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n", path_name); + goto end; + } + /* Read the file */ +#ifdef __GLIBC__ + while ((read = getline(&line, &len, fp)) != -1) { +#else + while ((line = fgetln(fp, &len)) != (char *)NULL) { +#endif /* __GLIBC __ */ + xchomp(line); + if (isdigit(line[0])) { + strncpy(vendor_str, line, 4); + vendor_str[4] = '\0'; + vendor = (int)strtol(vendor_str, NULL, 16); + if ((strlen(&line[4])) == 0) { + chip_str[0] = '\0'; + chip = -1; + } else { + /* Handle trailing whitespace */ + if (isspace(line[4])) { + chip_str[0] = '\0'; + chip = -1; + } else { + /* Ok, it's a real ID */ + strncpy(chip_str, &line[4], 4); + chip_str[4] = '\0'; + chip = (int)strtol(chip_str, NULL, 16); + } + } + if (vendor == match_vendor && chip == match_chip ) { + i = 0; + while (matches[i]) { + i++; + } + matches[i] = (char*)malloc(sizeof(char) * strlen(direntry->d_name) - 3); + if (!matches[i]) { + xf86Msg(X_ERROR, "Could not allocate space for the module name. Exiting.\n"); + goto end; + } + /* hack off the .ids suffix. This should guard + * against other problems, but it will end up + * taking off anything after the first '.' */ + for (j = 0; j < (strlen(direntry->d_name) - 3) ; j++) { + if (direntry->d_name[j] == '.') { + matches[i][j] = '\0'; + break; + } else { + matches[i][j] = direntry->d_name[j]; + } + } + xf86Msg(X_INFO, "Matched %s from file name %s\n", matches[i], direntry->d_name); + } + } else { + /* TODO Handle driver overrides here */ + } + } + fclose(fp); + } + direntry = readdir(idsdir); + } + end: + free(line); + closedir(idsdir); +} +#endif /* __linux__ */ + +static void +listPossibleVideoDrivers(char *matches[], int nmatches) +{ + struct pci_device * info = NULL; + struct pci_device_iterator *iter; + int i; + + for (i = 0 ; i < nmatches ; i++) { + matches[i] = NULL; + } + i = 0; + +#ifdef sun + /* Check for driver type based on /dev/fb type and if valid, use + it instead of PCI bus probe results */ + if (xf86Info.consoleFd >= 0) { + struct vis_identifier visid; + const char *cp; + extern char xf86SolarisFbDev[PATH_MAX]; + int iret; + + SYSCALL(iret = ioctl(xf86Info.consoleFd, VIS_GETIDENTIFIER, &visid)); + if (iret < 0) { + int fbfd; + + fbfd = open(xf86SolarisFbDev, O_RDONLY); + if (fbfd >= 0) { + SYSCALL(iret = ioctl(fbfd, VIS_GETIDENTIFIER, &visid)); + close(fbfd); + } + } + + if (iret < 0) { + xf86Msg(X_WARNING, + "could not get frame buffer identifier from %s\n", + xf86SolarisFbDev); + } else { + xf86Msg(X_PROBED, "console driver: %s\n", visid.name); + + /* Special case from before the general case was set */ + if (strcmp(visid.name, "NVDAnvda") == 0) { + matches[i++] = xnfstrdup("nvidia"); + } + + /* General case - split into vendor name (initial all-caps + prefix) & driver name (rest of the string). */ + if (strcmp(visid.name, "SUNWtext") != 0) { + for (cp = visid.name; (*cp != '\0') && isupper(*cp); cp++) { + /* find end of all uppercase vendor section */ + } + if ((cp != visid.name) && (*cp != '\0')) { + char *driverName = xnfstrdup(cp); + char *vendorName = xnfstrdup(visid.name); + vendorName[cp - visid.name] = '\0'; + + matches[i++] = vendorName; + matches[i++] = driverName; + } + } + } + } +#endif +#ifdef __sparc__ + { + char *sbusDriver = sparcDriverName(); + if (sbusDriver) + matches[i++] = xnfstrdup(sbusDriver); + } +#endif + + /* Find the primary device, and get some information about it. */ + iter = pci_slot_match_iterator_create(NULL); + while ((info = pci_device_next(iter)) != NULL) { + if (xf86IsPrimaryPci(info)) { + break; + } + } + + pci_iterator_destroy(iter); + + if (!info) { + ErrorF("Primary device is not PCI\n"); + } +#ifdef __linux__ + else { + matchDriverFromFiles(matches, info->vendor_id, info->device_id); + } +#endif /* __linux__ */ + + for (i = 0; (i < nmatches) && (matches[i]); i++) { + /* find end of matches list */ + } + + if ((info != NULL) && (i < nmatches)) { + i += videoPtrToDriverList(info, &(matches[i]), nmatches - i); + } + + /* Fallback to platform default hardware */ + if (i < (nmatches - 1)) { +#if defined(__i386__) || defined(__amd64__) || defined(__hurd__) + matches[i++] = xnfstrdup("vesa"); +#elif defined(__sparc__) && !defined(sun) + matches[i++] = xnfstrdup("sunffb"); +#endif + } + + /* Fallback to platform default frame buffer driver */ + if (i < (nmatches - 1)) { +#if !defined(__linux__) && defined(__sparc__) + matches[i++] = xnfstrdup("wsfb"); +#else + matches[i++] = xnfstrdup("fbdev"); +#endif + } +} + +/* copy a screen section and enter the desired driver + * and insert it at i in the list of screens */ +static Bool +copyScreen(confScreenPtr oscreen, GDevPtr odev, int i, char *driver) +{ + GDevPtr cptr = NULL; + + xf86ConfigLayout.screens[i].screen = xnfcalloc(1, sizeof(confScreenRec)); + if(!xf86ConfigLayout.screens[i].screen) + return FALSE; + memcpy(xf86ConfigLayout.screens[i].screen, oscreen, sizeof(confScreenRec)); + + cptr = calloc(1, sizeof(GDevRec)); + if (!cptr) + return FALSE; + memcpy(cptr, odev, sizeof(GDevRec)); + + cptr->identifier = Xprintf("Autoconfigured Video Device %s", driver); + cptr->driver = driver; + + /* now associate the new driver entry with the new screen entry */ + xf86ConfigLayout.screens[i].screen->device = cptr; + cptr->myScreenSection = xf86ConfigLayout.screens[i].screen; + + return TRUE; +} + +GDevPtr +autoConfigDevice(GDevPtr preconf_device) +{ + GDevPtr ptr = NULL; + char *matches[20]; /* If we have more than 20 drivers we're in trouble */ + int num_matches = 0, num_screens = 0, i; + screenLayoutPtr slp; + + if (!xf86configptr) { + return NULL; + } + + /* If there's a configured section with no driver chosen, use it */ + if (preconf_device) { + ptr = preconf_device; + } else { + ptr = calloc(1, sizeof(GDevRec)); + if (!ptr) { + return NULL; + } + ptr->chipID = -1; + ptr->chipRev = -1; + ptr->irq = -1; + + ptr->active = TRUE; + ptr->claimed = FALSE; + ptr->identifier = "Autoconfigured Video Device"; + ptr->driver = NULL; + } + if (!ptr->driver) { + /* get all possible video drivers and count them */ + listPossibleVideoDrivers(matches, 20); + for (; matches[num_matches]; num_matches++) { + xf86Msg(X_DEFAULT, "Matched %s as autoconfigured driver %d\n", + matches[num_matches], num_matches); + } + + slp = xf86ConfigLayout.screens; + if (slp) { + /* count the number of screens and make space for + * a new screen for each additional possible driver + * minus one for the already existing first one + * plus one for the terminating NULL */ + for (; slp[num_screens].screen; num_screens++); + xf86ConfigLayout.screens = xnfcalloc(num_screens + num_matches, + sizeof(screenLayoutRec)); + xf86ConfigLayout.screens[0] = slp[0]; + + /* do the first match and set that for the original first screen */ + ptr->driver = matches[0]; + if (!xf86ConfigLayout.screens[0].screen->device) { + xf86ConfigLayout.screens[0].screen->device = ptr; + ptr->myScreenSection = xf86ConfigLayout.screens[0].screen; + } + + /* for each other driver found, copy the first screen, insert it + * into the list of screens and set the driver */ + i = 0; + while (i++ < num_matches) { + if (!copyScreen(slp[0].screen, ptr, i, matches[i])) + return NULL; + } + + /* shift the rest of the original screen list + * to the end of the current screen list + * + * TODO Handle rest of multiple screen sections */ + for (i = 1; i < num_screens; i++) { + xf86ConfigLayout.screens[i+num_matches] = slp[i]; + } + xf86ConfigLayout.screens[num_screens+num_matches-1].screen = NULL; + free(slp); + } else { + /* layout does not have any screens, not much to do */ + ptr->driver = matches[0]; + for (i = 1; matches[i] ; i++) { + if (matches[i] != matches[0]) { + free(matches[i]); + } + } + } + } + + xf86Msg(X_DEFAULT, "Assigned the driver to the xf86ConfigLayout\n"); + + return ptr; +} diff --git a/xorg-server/hw/xfree86/common/xf86Bus.c b/xorg-server/hw/xfree86/common/xf86Bus.c index 9d243c172..5c1668644 100644 --- a/xorg-server/hw/xfree86/common/xf86Bus.c +++ b/xorg-server/hw/xfree86/common/xf86Bus.c @@ -1,683 +1,683 @@ -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * This file contains the interfaces to the bus-specific code - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <ctype.h> -#include <stdlib.h> -#include <unistd.h> -#include <X11/X.h> -#include "os.h" -#include "xf86.h" -#include "xf86Priv.h" - -/* Bus-specific headers */ - -#include "xf86Bus.h" - -#define XF86_OS_PRIVS -#include "xf86_OSproc.h" -#include "xf86VGAarbiter.h" - -#include "Pci.h" - -/* Entity data */ -EntityPtr *xf86Entities = NULL; /* Bus slots claimed by drivers */ -int xf86NumEntities = 0; -static int xf86EntityPrivateCount = 0; - -BusRec primaryBus = { BUS_NONE, { 0 } }; - -static Bool xf86ResAccessEnter = FALSE; - -static Bool doFramebufferMode = FALSE; - -/* - * Call the bus probes relevant to the architecture. - * - * The only one available so far is for PCI and SBUS. - */ - -void -xf86BusProbe(void) -{ - xf86PciProbe(); -#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) - xf86SbusProbe(); -#endif -} - -/* - * Determine what bus type the busID string represents. The start of the - * bus-dependent part of the string is returned as retID. - */ - -BusType -StringToBusType(const char* busID, const char **retID) -{ - char *p, *s; - BusType ret = BUS_NONE; - - /* If no type field, Default to PCI */ - if (isdigit(busID[0])) { - if (retID) - *retID = busID; - return BUS_PCI; - } - - s = xstrdup(busID); - p = strtok(s, ":"); - if (p == NULL || *p == 0) { - xfree(s); - return BUS_NONE; - } - if (!xf86NameCmp(p, "pci") || !xf86NameCmp(p, "agp")) - ret = BUS_PCI; - if (!xf86NameCmp(p, "sbus")) - ret = BUS_SBUS; - if (ret != BUS_NONE) - if (retID) - *retID = busID + strlen(p) + 1; - xfree(s); - return ret; -} - -/* - * Entity related code. - */ - -void -xf86EntityInit(void) -{ - int i; - - for (i = 0; i < xf86NumEntities; i++) - if (xf86Entities[i]->entityInit) { - xf86Entities[i]->entityInit(i,xf86Entities[i]->private); - } -} - -int -xf86AllocateEntity(void) -{ - xf86NumEntities++; - xf86Entities = xnfrealloc(xf86Entities, - sizeof(EntityPtr) * xf86NumEntities); - xf86Entities[xf86NumEntities - 1] = xnfcalloc(1,sizeof(EntityRec)); - xf86Entities[xf86NumEntities - 1]->entityPrivates = - xnfcalloc(sizeof(DevUnion) * xf86EntityPrivateCount, 1); - return (xf86NumEntities - 1); -} - -static void -EntityEnter(void) -{ - int i; - - for (i = 0; i < xf86NumEntities; i++) - if (xf86Entities[i]->entityEnter) { - xf86Entities[i]->entityEnter(i,xf86Entities[i]->private); - } -} - -static void -EntityLeave(void) -{ - int i; - - for (i = 0; i < xf86NumEntities; i++) - if (xf86Entities[i]->entityLeave) { - xf86Entities[i]->entityLeave(i,xf86Entities[i]->private); - } -} - -Bool -xf86IsEntityPrimary(int entityIndex) -{ - EntityPtr pEnt = xf86Entities[entityIndex]; - - if (primaryBus.type != pEnt->bus.type) return FALSE; - - switch (pEnt->bus.type) { - case BUS_PCI: - return (pEnt->bus.id.pci == primaryBus.id.pci); - case BUS_SBUS: - return (pEnt->bus.id.sbus.fbNum == primaryBus.id.sbus.fbNum); - default: - return FALSE; - } -} - -Bool -xf86SetEntityFuncs(int entityIndex, EntityProc init, EntityProc enter, - EntityProc leave, pointer private) -{ - if (entityIndex >= xf86NumEntities) - return FALSE; - xf86Entities[entityIndex]->entityInit = init; - xf86Entities[entityIndex]->entityEnter = enter; - xf86Entities[entityIndex]->entityLeave = leave; - xf86Entities[entityIndex]->private = private; - return TRUE; -} - -Bool -xf86DriverHasEntities(DriverPtr drvp) -{ - int i; - for (i = 0; i < xf86NumEntities; i++) { - if (xf86Entities[i]->driver == drvp) - return TRUE; - } - return FALSE; -} - -void -xf86AddEntityToScreen(ScrnInfoPtr pScrn, int entityIndex) -{ - if (entityIndex == -1) - return; - if (xf86Entities[entityIndex]->inUse && - !(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL)) { - ErrorF("Requested Entity already in use!\n"); - return; - } - - pScrn->numEntities++; - pScrn->entityList = xnfrealloc(pScrn->entityList, - pScrn->numEntities * sizeof(int)); - pScrn->entityList[pScrn->numEntities - 1] = entityIndex; - xf86Entities[entityIndex]->inUse = TRUE; - pScrn->entityInstanceList = xnfrealloc(pScrn->entityInstanceList, - pScrn->numEntities * sizeof(int)); - pScrn->entityInstanceList[pScrn->numEntities - 1] = 0; - pScrn->domainIOBase = xf86Entities[entityIndex]->domainIO; -} - -void -xf86SetEntityInstanceForScreen(ScrnInfoPtr pScrn, int entityIndex, int instance) -{ - int i; - - if (entityIndex == -1 || entityIndex >= xf86NumEntities) - return; - - for (i = 0; i < pScrn->numEntities; i++) { - if (pScrn->entityList[i] == entityIndex) { - pScrn->entityInstanceList[i] = instance; - break; - } - } -} - -/* - * XXX This needs to be updated for the case where a single entity may have - * instances associated with more than one screen. - */ -ScrnInfoPtr -xf86FindScreenForEntity(int entityIndex) -{ - int i,j; - - if (entityIndex == -1) return NULL; - - if (xf86Screens) { - for (i = 0; i < xf86NumScreens; i++) { - for (j = 0; j < xf86Screens[i]->numEntities; j++) { - if ( xf86Screens[i]->entityList[j] == entityIndex ) - return (xf86Screens[i]); - } - } - } - return NULL; -} - -void -xf86RemoveEntityFromScreen(ScrnInfoPtr pScrn, int entityIndex) -{ - int i; - - for (i = 0; i < pScrn->numEntities; i++) { - if (pScrn->entityList[i] == entityIndex) { - for (i++; i < pScrn->numEntities; i++) - pScrn->entityList[i-1] = pScrn->entityList[i]; - pScrn->numEntities--; - xf86Entities[entityIndex]->inUse = FALSE; - break; - } - } -} - -/* - * xf86ClearEntitiesForScreen() - called when a screen is deleted - * to mark it's entities unused. Called by xf86DeleteScreen(). - */ -void -xf86ClearEntityListForScreen(int scrnIndex) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - int i, entityIndex; - - if (pScrn->entityList == NULL || pScrn->numEntities == 0) return; - - for (i = 0; i < pScrn->numEntities; i++) { - entityIndex = pScrn->entityList[i]; - xf86Entities[entityIndex]->inUse = FALSE; - /* disable resource: call the disable function */ - } - xfree(pScrn->entityList); - xfree(pScrn->entityInstanceList); - pScrn->entityList = NULL; - pScrn->entityInstanceList = NULL; -} - -/* - * Add an extra device section (GDevPtr) to an entity. - */ - -void -xf86AddDevToEntity(int entityIndex, GDevPtr dev) -{ - EntityPtr pEnt; - - if (entityIndex >= xf86NumEntities) - return; - - pEnt = xf86Entities[entityIndex]; - pEnt->numInstances++; - pEnt->devices = xnfrealloc(pEnt->devices, - pEnt->numInstances * sizeof(GDevPtr)); - pEnt->devices[pEnt->numInstances - 1] = dev; - dev->claimed = TRUE; -} - -/* - * xf86GetEntityInfo() -- This function hands information from the - * EntityRec struct to the drivers. The EntityRec structure itself - * remains invisible to the driver. - */ -EntityInfoPtr -xf86GetEntityInfo(int entityIndex) -{ - EntityInfoPtr pEnt; - int i; - - if (entityIndex == -1) - return NULL; - - if (entityIndex >= xf86NumEntities) - return NULL; - - pEnt = xnfcalloc(1,sizeof(EntityInfoRec)); - pEnt->index = entityIndex; - pEnt->location = xf86Entities[entityIndex]->bus; - pEnt->active = xf86Entities[entityIndex]->active; - pEnt->chipset = xf86Entities[entityIndex]->chipset; - pEnt->driver = xf86Entities[entityIndex]->driver; - if ( (xf86Entities[entityIndex]->devices) && - (xf86Entities[entityIndex]->devices[0]) ) { - for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++) - if (xf86Entities[entityIndex]->devices[i]->screen == 0) - break; - pEnt->device = xf86Entities[entityIndex]->devices[i]; - } else - pEnt->device = NULL; - - return pEnt; -} - -int -xf86GetNumEntityInstances(int entityIndex) -{ - if (entityIndex >= xf86NumEntities) - return -1; - - return xf86Entities[entityIndex]->numInstances; -} - -GDevPtr -xf86GetDevFromEntity(int entityIndex, int instance) -{ - int i; - - /* We might not use AddDevtoEntity */ - if ( (!xf86Entities[entityIndex]->devices) || - (!xf86Entities[entityIndex]->devices[0]) ) - return NULL; - - if (entityIndex >= xf86NumEntities || - instance >= xf86Entities[entityIndex]->numInstances) - return NULL; - - for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++) - if (xf86Entities[entityIndex]->devices[i]->screen == instance) - break; - return xf86Entities[entityIndex]->devices[i]; -} - -/* - * xf86AccessInit() - set up everything needed for access control - * called only once on first server generation. - */ -void -xf86AccessInit(void) -{ - xf86ResAccessEnter = TRUE; -} - -/* - * xf86AccessEnter() -- gets called to save the text mode VGA IO - * resources when reentering the server after a VT switch. - */ -void -xf86AccessEnter(void) -{ - if (xf86ResAccessEnter) - return; - - /* - * on enter we simply disable routing of special resources - * to any bus and let the RAC code to "open" the right bridges. - */ - EntityEnter(); - xf86EnterServerState(SETUP); - xf86ResAccessEnter = TRUE; -} - -/* - * xf86AccessLeave() -- prepares access for and calls the - * entityLeave() functions. - * xf86AccessLeaveState() --- gets called to restore the - * access to the VGA IO resources when switching VT or on - * server exit. - * This was split to call xf86AccessLeaveState() from - * ddxGiveUp(). - */ -void -xf86AccessLeave(void) -{ - if (!xf86ResAccessEnter) - return; - EntityLeave(); -} - -/* - * xf86EnableAccess() -- enable access to controlled resources. - * To reduce latency when switching access the ScrnInfoRec has - * a linked list of the EntityAccPtr of all screen entities. - */ -/* - * switching access needs to be done in te following oder: - * disable - * 1. disable old entity - * 2. reroute bus - * 3. enable new entity - * Otherwise resources needed for access control might be shadowed - * by other resources! - */ - -void -xf86EnableAccess(ScrnInfoPtr pScrn) -{ - DebugF("Enable access %i\n",pScrn->scrnIndex); - - return; -} - -/* - * xf86EnterServerState() -- set state the server is in. - */ - -typedef enum { TRI_UNSET, TRI_TRUE, TRI_FALSE } TriState; - -static void -SetSIGIOForState(xf86State state) -{ - static int sigio_state; - static TriState sigio_blocked = TRI_UNSET; - - if ((state == SETUP) && (sigio_blocked != TRI_TRUE)) { - sigio_state = xf86BlockSIGIO(); - sigio_blocked = TRI_TRUE; - } else if ((state == OPERATING) && (sigio_blocked != TRI_UNSET)) { - xf86UnblockSIGIO(sigio_state); - sigio_blocked = TRI_FALSE; - } -} - -void -xf86EnterServerState(xf86State state) -{ - /* - * This is a good place to block SIGIO during SETUP state. - * SIGIO should be blocked in SETUP state otherwise (u)sleep() - * might get interrupted early. - * We take care not to call xf86BlockSIGIO() twice. - */ - SetSIGIOForState(state); - if (state == SETUP) - DebugF("Entering SETUP state\n"); - else - DebugF("Entering OPERATING state\n"); - - return; -} - -/* - * xf86PostProbe() -- Allocate all non conflicting resources - * This function gets called by xf86Init(). - */ -void -xf86PostProbe(void) -{ - if (fbSlotClaimed) { - if (pciSlotClaimed -#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) - || sbusSlotClaimed -#endif - ) { - FatalError("Cannot run in framebuffer mode. Please specify busIDs " - " for all framebuffer devices\n"); - return; - } else { - xf86Msg(X_INFO,"Running in FRAMEBUFFER Mode\n"); - doFramebufferMode = TRUE; - - return; - } - } -} - -void -xf86PostScreenInit(void) -{ - if (doFramebufferMode) { - SetSIGIOForState(OPERATING); - return; - } - - xf86VGAarbiterWrapFunctions(); - - DebugF("PostScreenInit generation: %i\n",serverGeneration); - xf86EnterServerState(OPERATING); -} - -/* - * xf86FindPrimaryDevice() - Find the display device which - * was active when the server was started. - */ -void -xf86FindPrimaryDevice(void) -{ - if (primaryBus.type != BUS_NONE) { - char *bus; - char loc[16]; - - switch (primaryBus.type) { - case BUS_PCI: - bus = "PCI"; - snprintf(loc, sizeof(loc), " %2.2x@%2.2x:%2.2x:%1.1x", - primaryBus.id.pci->bus, - primaryBus.id.pci->domain, - primaryBus.id.pci->dev, - primaryBus.id.pci->func); - break; - case BUS_SBUS: - bus = "SBUS"; - snprintf(loc, sizeof(loc), " %2.2x", primaryBus.id.sbus.fbNum); - break; - default: - bus = ""; - loc[0] = '\0'; - } - - xf86MsgVerb(X_INFO, 2, "Primary Device is: %s%s\n",bus,loc); - } -} - -int -xf86GetLastScrnFlag(int entityIndex) -{ - if(entityIndex < xf86NumEntities) { - return(xf86Entities[entityIndex]->lastScrnFlag); - } else { - return -1; - } -} - -void -xf86SetLastScrnFlag(int entityIndex, int scrnIndex) -{ - if(entityIndex < xf86NumEntities) { - xf86Entities[entityIndex]->lastScrnFlag = scrnIndex; - } -} - -Bool -xf86IsEntityShared(int entityIndex) -{ - if(entityIndex < xf86NumEntities) { - if(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL) { - return TRUE; - } - } - return FALSE; -} - -void -xf86SetEntityShared(int entityIndex) -{ - if(entityIndex < xf86NumEntities) { - xf86Entities[entityIndex]->entityProp |= IS_SHARED_ACCEL; - } -} - -Bool -xf86IsEntitySharable(int entityIndex) -{ - if(entityIndex < xf86NumEntities) { - if(xf86Entities[entityIndex]->entityProp & ACCEL_IS_SHARABLE) { - return TRUE; - } - } - return FALSE; -} - -void -xf86SetEntitySharable(int entityIndex) -{ - if(entityIndex < xf86NumEntities) { - xf86Entities[entityIndex]->entityProp |= ACCEL_IS_SHARABLE; - } -} - -Bool -xf86IsPrimInitDone(int entityIndex) -{ - if(entityIndex < xf86NumEntities) { - if(xf86Entities[entityIndex]->entityProp & SA_PRIM_INIT_DONE) { - return TRUE; - } - } - return FALSE; -} - -void -xf86SetPrimInitDone(int entityIndex) -{ - if(entityIndex < xf86NumEntities) { - xf86Entities[entityIndex]->entityProp |= SA_PRIM_INIT_DONE; - } -} - -void -xf86ClearPrimInitDone(int entityIndex) -{ - if(entityIndex < xf86NumEntities) { - xf86Entities[entityIndex]->entityProp &= ~SA_PRIM_INIT_DONE; - } -} - - -/* - * Allocate a private in the entities. - */ - -int -xf86AllocateEntityPrivateIndex(void) -{ - int idx, i; - EntityPtr pEnt; - DevUnion *nprivs; - - idx = xf86EntityPrivateCount++; - for (i = 0; i < xf86NumEntities; i++) { - pEnt = xf86Entities[i]; - nprivs = xnfrealloc(pEnt->entityPrivates, - xf86EntityPrivateCount * sizeof(DevUnion)); - /* Zero the new private */ - bzero(&nprivs[idx], sizeof(DevUnion)); - pEnt->entityPrivates = nprivs; - } - return idx; -} - -DevUnion * -xf86GetEntityPrivate(int entityIndex, int privIndex) -{ - if (entityIndex >= xf86NumEntities || privIndex >= xf86EntityPrivateCount) - return NULL; - - return &(xf86Entities[entityIndex]->entityPrivates[privIndex]); -} - +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * This file contains the interfaces to the bus-specific code + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <X11/X.h> +#include "os.h" +#include "xf86.h" +#include "xf86Priv.h" + +/* Bus-specific headers */ + +#include "xf86Bus.h" + +#define XF86_OS_PRIVS +#include "xf86_OSproc.h" +#include "xf86VGAarbiter.h" + +#include "Pci.h" + +/* Entity data */ +EntityPtr *xf86Entities = NULL; /* Bus slots claimed by drivers */ +int xf86NumEntities = 0; +static int xf86EntityPrivateCount = 0; + +BusRec primaryBus = { BUS_NONE, { 0 } }; + +static Bool xf86ResAccessEnter = FALSE; + +static Bool doFramebufferMode = FALSE; + +/* + * Call the bus probes relevant to the architecture. + * + * The only one available so far is for PCI and SBUS. + */ + +void +xf86BusProbe(void) +{ + xf86PciProbe(); +#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) + xf86SbusProbe(); +#endif +} + +/* + * Determine what bus type the busID string represents. The start of the + * bus-dependent part of the string is returned as retID. + */ + +BusType +StringToBusType(const char* busID, const char **retID) +{ + char *p, *s; + BusType ret = BUS_NONE; + + /* If no type field, Default to PCI */ + if (isdigit(busID[0])) { + if (retID) + *retID = busID; + return BUS_PCI; + } + + s = xstrdup(busID); + p = strtok(s, ":"); + if (p == NULL || *p == 0) { + free(s); + return BUS_NONE; + } + if (!xf86NameCmp(p, "pci") || !xf86NameCmp(p, "agp")) + ret = BUS_PCI; + if (!xf86NameCmp(p, "sbus")) + ret = BUS_SBUS; + if (ret != BUS_NONE) + if (retID) + *retID = busID + strlen(p) + 1; + free(s); + return ret; +} + +/* + * Entity related code. + */ + +void +xf86EntityInit(void) +{ + int i; + + for (i = 0; i < xf86NumEntities; i++) + if (xf86Entities[i]->entityInit) { + xf86Entities[i]->entityInit(i,xf86Entities[i]->private); + } +} + +int +xf86AllocateEntity(void) +{ + xf86NumEntities++; + xf86Entities = xnfrealloc(xf86Entities, + sizeof(EntityPtr) * xf86NumEntities); + xf86Entities[xf86NumEntities - 1] = xnfcalloc(1,sizeof(EntityRec)); + xf86Entities[xf86NumEntities - 1]->entityPrivates = + xnfcalloc(sizeof(DevUnion) * xf86EntityPrivateCount, 1); + return (xf86NumEntities - 1); +} + +static void +EntityEnter(void) +{ + int i; + + for (i = 0; i < xf86NumEntities; i++) + if (xf86Entities[i]->entityEnter) { + xf86Entities[i]->entityEnter(i,xf86Entities[i]->private); + } +} + +static void +EntityLeave(void) +{ + int i; + + for (i = 0; i < xf86NumEntities; i++) + if (xf86Entities[i]->entityLeave) { + xf86Entities[i]->entityLeave(i,xf86Entities[i]->private); + } +} + +Bool +xf86IsEntityPrimary(int entityIndex) +{ + EntityPtr pEnt = xf86Entities[entityIndex]; + + if (primaryBus.type != pEnt->bus.type) return FALSE; + + switch (pEnt->bus.type) { + case BUS_PCI: + return (pEnt->bus.id.pci == primaryBus.id.pci); + case BUS_SBUS: + return (pEnt->bus.id.sbus.fbNum == primaryBus.id.sbus.fbNum); + default: + return FALSE; + } +} + +Bool +xf86SetEntityFuncs(int entityIndex, EntityProc init, EntityProc enter, + EntityProc leave, pointer private) +{ + if (entityIndex >= xf86NumEntities) + return FALSE; + xf86Entities[entityIndex]->entityInit = init; + xf86Entities[entityIndex]->entityEnter = enter; + xf86Entities[entityIndex]->entityLeave = leave; + xf86Entities[entityIndex]->private = private; + return TRUE; +} + +Bool +xf86DriverHasEntities(DriverPtr drvp) +{ + int i; + for (i = 0; i < xf86NumEntities; i++) { + if (xf86Entities[i]->driver == drvp) + return TRUE; + } + return FALSE; +} + +void +xf86AddEntityToScreen(ScrnInfoPtr pScrn, int entityIndex) +{ + if (entityIndex == -1) + return; + if (xf86Entities[entityIndex]->inUse && + !(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL)) { + ErrorF("Requested Entity already in use!\n"); + return; + } + + pScrn->numEntities++; + pScrn->entityList = xnfrealloc(pScrn->entityList, + pScrn->numEntities * sizeof(int)); + pScrn->entityList[pScrn->numEntities - 1] = entityIndex; + xf86Entities[entityIndex]->inUse = TRUE; + pScrn->entityInstanceList = xnfrealloc(pScrn->entityInstanceList, + pScrn->numEntities * sizeof(int)); + pScrn->entityInstanceList[pScrn->numEntities - 1] = 0; + pScrn->domainIOBase = xf86Entities[entityIndex]->domainIO; +} + +void +xf86SetEntityInstanceForScreen(ScrnInfoPtr pScrn, int entityIndex, int instance) +{ + int i; + + if (entityIndex == -1 || entityIndex >= xf86NumEntities) + return; + + for (i = 0; i < pScrn->numEntities; i++) { + if (pScrn->entityList[i] == entityIndex) { + pScrn->entityInstanceList[i] = instance; + break; + } + } +} + +/* + * XXX This needs to be updated for the case where a single entity may have + * instances associated with more than one screen. + */ +ScrnInfoPtr +xf86FindScreenForEntity(int entityIndex) +{ + int i,j; + + if (entityIndex == -1) return NULL; + + if (xf86Screens) { + for (i = 0; i < xf86NumScreens; i++) { + for (j = 0; j < xf86Screens[i]->numEntities; j++) { + if ( xf86Screens[i]->entityList[j] == entityIndex ) + return (xf86Screens[i]); + } + } + } + return NULL; +} + +void +xf86RemoveEntityFromScreen(ScrnInfoPtr pScrn, int entityIndex) +{ + int i; + + for (i = 0; i < pScrn->numEntities; i++) { + if (pScrn->entityList[i] == entityIndex) { + for (i++; i < pScrn->numEntities; i++) + pScrn->entityList[i-1] = pScrn->entityList[i]; + pScrn->numEntities--; + xf86Entities[entityIndex]->inUse = FALSE; + break; + } + } +} + +/* + * xf86ClearEntitiesForScreen() - called when a screen is deleted + * to mark it's entities unused. Called by xf86DeleteScreen(). + */ +void +xf86ClearEntityListForScreen(int scrnIndex) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + int i, entityIndex; + + if (pScrn->entityList == NULL || pScrn->numEntities == 0) return; + + for (i = 0; i < pScrn->numEntities; i++) { + entityIndex = pScrn->entityList[i]; + xf86Entities[entityIndex]->inUse = FALSE; + /* disable resource: call the disable function */ + } + free(pScrn->entityList); + free(pScrn->entityInstanceList); + pScrn->entityList = NULL; + pScrn->entityInstanceList = NULL; +} + +/* + * Add an extra device section (GDevPtr) to an entity. + */ + +void +xf86AddDevToEntity(int entityIndex, GDevPtr dev) +{ + EntityPtr pEnt; + + if (entityIndex >= xf86NumEntities) + return; + + pEnt = xf86Entities[entityIndex]; + pEnt->numInstances++; + pEnt->devices = xnfrealloc(pEnt->devices, + pEnt->numInstances * sizeof(GDevPtr)); + pEnt->devices[pEnt->numInstances - 1] = dev; + dev->claimed = TRUE; +} + +/* + * xf86GetEntityInfo() -- This function hands information from the + * EntityRec struct to the drivers. The EntityRec structure itself + * remains invisible to the driver. + */ +EntityInfoPtr +xf86GetEntityInfo(int entityIndex) +{ + EntityInfoPtr pEnt; + int i; + + if (entityIndex == -1) + return NULL; + + if (entityIndex >= xf86NumEntities) + return NULL; + + pEnt = xnfcalloc(1,sizeof(EntityInfoRec)); + pEnt->index = entityIndex; + pEnt->location = xf86Entities[entityIndex]->bus; + pEnt->active = xf86Entities[entityIndex]->active; + pEnt->chipset = xf86Entities[entityIndex]->chipset; + pEnt->driver = xf86Entities[entityIndex]->driver; + if ( (xf86Entities[entityIndex]->devices) && + (xf86Entities[entityIndex]->devices[0]) ) { + for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++) + if (xf86Entities[entityIndex]->devices[i]->screen == 0) + break; + pEnt->device = xf86Entities[entityIndex]->devices[i]; + } else + pEnt->device = NULL; + + return pEnt; +} + +int +xf86GetNumEntityInstances(int entityIndex) +{ + if (entityIndex >= xf86NumEntities) + return -1; + + return xf86Entities[entityIndex]->numInstances; +} + +GDevPtr +xf86GetDevFromEntity(int entityIndex, int instance) +{ + int i; + + /* We might not use AddDevtoEntity */ + if ( (!xf86Entities[entityIndex]->devices) || + (!xf86Entities[entityIndex]->devices[0]) ) + return NULL; + + if (entityIndex >= xf86NumEntities || + instance >= xf86Entities[entityIndex]->numInstances) + return NULL; + + for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++) + if (xf86Entities[entityIndex]->devices[i]->screen == instance) + break; + return xf86Entities[entityIndex]->devices[i]; +} + +/* + * xf86AccessInit() - set up everything needed for access control + * called only once on first server generation. + */ +void +xf86AccessInit(void) +{ + xf86ResAccessEnter = TRUE; +} + +/* + * xf86AccessEnter() -- gets called to save the text mode VGA IO + * resources when reentering the server after a VT switch. + */ +void +xf86AccessEnter(void) +{ + if (xf86ResAccessEnter) + return; + + /* + * on enter we simply disable routing of special resources + * to any bus and let the RAC code to "open" the right bridges. + */ + EntityEnter(); + xf86EnterServerState(SETUP); + xf86ResAccessEnter = TRUE; +} + +/* + * xf86AccessLeave() -- prepares access for and calls the + * entityLeave() functions. + * xf86AccessLeaveState() --- gets called to restore the + * access to the VGA IO resources when switching VT or on + * server exit. + * This was split to call xf86AccessLeaveState() from + * ddxGiveUp(). + */ +void +xf86AccessLeave(void) +{ + if (!xf86ResAccessEnter) + return; + EntityLeave(); +} + +/* + * xf86EnableAccess() -- enable access to controlled resources. + * To reduce latency when switching access the ScrnInfoRec has + * a linked list of the EntityAccPtr of all screen entities. + */ +/* + * switching access needs to be done in te following oder: + * disable + * 1. disable old entity + * 2. reroute bus + * 3. enable new entity + * Otherwise resources needed for access control might be shadowed + * by other resources! + */ + +void +xf86EnableAccess(ScrnInfoPtr pScrn) +{ + DebugF("Enable access %i\n",pScrn->scrnIndex); + + return; +} + +/* + * xf86EnterServerState() -- set state the server is in. + */ + +typedef enum { TRI_UNSET, TRI_TRUE, TRI_FALSE } TriState; + +static void +SetSIGIOForState(xf86State state) +{ + static int sigio_state; + static TriState sigio_blocked = TRI_UNSET; + + if ((state == SETUP) && (sigio_blocked != TRI_TRUE)) { + sigio_state = xf86BlockSIGIO(); + sigio_blocked = TRI_TRUE; + } else if ((state == OPERATING) && (sigio_blocked != TRI_UNSET)) { + xf86UnblockSIGIO(sigio_state); + sigio_blocked = TRI_FALSE; + } +} + +void +xf86EnterServerState(xf86State state) +{ + /* + * This is a good place to block SIGIO during SETUP state. + * SIGIO should be blocked in SETUP state otherwise (u)sleep() + * might get interrupted early. + * We take care not to call xf86BlockSIGIO() twice. + */ + SetSIGIOForState(state); + if (state == SETUP) + DebugF("Entering SETUP state\n"); + else + DebugF("Entering OPERATING state\n"); + + return; +} + +/* + * xf86PostProbe() -- Allocate all non conflicting resources + * This function gets called by xf86Init(). + */ +void +xf86PostProbe(void) +{ + if (fbSlotClaimed) { + if (pciSlotClaimed +#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) + || sbusSlotClaimed +#endif + ) { + FatalError("Cannot run in framebuffer mode. Please specify busIDs " + " for all framebuffer devices\n"); + return; + } else { + xf86Msg(X_INFO,"Running in FRAMEBUFFER Mode\n"); + doFramebufferMode = TRUE; + + return; + } + } +} + +void +xf86PostScreenInit(void) +{ + if (doFramebufferMode) { + SetSIGIOForState(OPERATING); + return; + } + + xf86VGAarbiterWrapFunctions(); + + DebugF("PostScreenInit generation: %i\n",serverGeneration); + xf86EnterServerState(OPERATING); +} + +/* + * xf86FindPrimaryDevice() - Find the display device which + * was active when the server was started. + */ +void +xf86FindPrimaryDevice(void) +{ + if (primaryBus.type != BUS_NONE) { + char *bus; + char loc[16]; + + switch (primaryBus.type) { + case BUS_PCI: + bus = "PCI"; + snprintf(loc, sizeof(loc), " %2.2x@%2.2x:%2.2x:%1.1x", + primaryBus.id.pci->bus, + primaryBus.id.pci->domain, + primaryBus.id.pci->dev, + primaryBus.id.pci->func); + break; + case BUS_SBUS: + bus = "SBUS"; + snprintf(loc, sizeof(loc), " %2.2x", primaryBus.id.sbus.fbNum); + break; + default: + bus = ""; + loc[0] = '\0'; + } + + xf86MsgVerb(X_INFO, 2, "Primary Device is: %s%s\n",bus,loc); + } +} + +int +xf86GetLastScrnFlag(int entityIndex) +{ + if(entityIndex < xf86NumEntities) { + return(xf86Entities[entityIndex]->lastScrnFlag); + } else { + return -1; + } +} + +void +xf86SetLastScrnFlag(int entityIndex, int scrnIndex) +{ + if(entityIndex < xf86NumEntities) { + xf86Entities[entityIndex]->lastScrnFlag = scrnIndex; + } +} + +Bool +xf86IsEntityShared(int entityIndex) +{ + if(entityIndex < xf86NumEntities) { + if(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL) { + return TRUE; + } + } + return FALSE; +} + +void +xf86SetEntityShared(int entityIndex) +{ + if(entityIndex < xf86NumEntities) { + xf86Entities[entityIndex]->entityProp |= IS_SHARED_ACCEL; + } +} + +Bool +xf86IsEntitySharable(int entityIndex) +{ + if(entityIndex < xf86NumEntities) { + if(xf86Entities[entityIndex]->entityProp & ACCEL_IS_SHARABLE) { + return TRUE; + } + } + return FALSE; +} + +void +xf86SetEntitySharable(int entityIndex) +{ + if(entityIndex < xf86NumEntities) { + xf86Entities[entityIndex]->entityProp |= ACCEL_IS_SHARABLE; + } +} + +Bool +xf86IsPrimInitDone(int entityIndex) +{ + if(entityIndex < xf86NumEntities) { + if(xf86Entities[entityIndex]->entityProp & SA_PRIM_INIT_DONE) { + return TRUE; + } + } + return FALSE; +} + +void +xf86SetPrimInitDone(int entityIndex) +{ + if(entityIndex < xf86NumEntities) { + xf86Entities[entityIndex]->entityProp |= SA_PRIM_INIT_DONE; + } +} + +void +xf86ClearPrimInitDone(int entityIndex) +{ + if(entityIndex < xf86NumEntities) { + xf86Entities[entityIndex]->entityProp &= ~SA_PRIM_INIT_DONE; + } +} + + +/* + * Allocate a private in the entities. + */ + +int +xf86AllocateEntityPrivateIndex(void) +{ + int idx, i; + EntityPtr pEnt; + DevUnion *nprivs; + + idx = xf86EntityPrivateCount++; + for (i = 0; i < xf86NumEntities; i++) { + pEnt = xf86Entities[i]; + nprivs = xnfrealloc(pEnt->entityPrivates, + xf86EntityPrivateCount * sizeof(DevUnion)); + /* Zero the new private */ + bzero(&nprivs[idx], sizeof(DevUnion)); + pEnt->entityPrivates = nprivs; + } + return idx; +} + +DevUnion * +xf86GetEntityPrivate(int entityIndex, int privIndex) +{ + if (entityIndex >= xf86NumEntities || privIndex >= xf86EntityPrivateCount) + return NULL; + + return &(xf86Entities[entityIndex]->entityPrivates[privIndex]); +} + diff --git a/xorg-server/hw/xfree86/common/xf86Config.c b/xorg-server/hw/xfree86/common/xf86Config.c index 9a2837e7b..33b38930f 100644 --- a/xorg-server/hw/xfree86/common/xf86Config.c +++ b/xorg-server/hw/xfree86/common/xf86Config.c @@ -1,2586 +1,2586 @@ -/* - * Loosely based on code bearing the following copyright: - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - */ - -/* - * Copyright 1992-2003 by The XFree86 Project, Inc. - * Copyright 1997 by Metro Link, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * - * Authors: - * Dirk Hohndel <hohndel@XFree86.Org> - * David Dawes <dawes@XFree86.Org> - * Marc La France <tsi@XFree86.Org> - * Egbert Eich <eich@XFree86.Org> - * ... and others - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#ifdef XF86DRI -#include <sys/types.h> -#include <grp.h> -#endif - -#include "xf86.h" -#include "xf86Parser.h" -#include "xf86tokens.h" -#include "xf86Config.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" -#include "configProcs.h" -#include "globals.h" -#include "extension.h" -#include "Pci.h" - -#include "xf86Xinput.h" -extern DeviceAssocRec mouse_assoc; - -#include "xkbsrv.h" - -#include "picture.h" - -/* - * These paths define the way the config file search is done. The escape - * sequences are documented in parser/scan.c. - */ -#ifndef ROOT_CONFIGPATH -#define ROOT_CONFIGPATH "%A," "%R," \ - "/etc/X11/%R," "%P/etc/X11/%R," \ - "%E," "%F," \ - "/etc/X11/%F," "%P/etc/X11/%F," \ - "/etc/X11/%X-%M," "/etc/X11/%X," "/etc/%X," \ - "%P/etc/X11/%X.%H," "%P/etc/X11/%X-%M," \ - "%P/etc/X11/%X," \ - "%P/lib/X11/%X.%H," "%P/lib/X11/%X-%M," \ - "%P/lib/X11/%X" -#endif -#ifndef USER_CONFIGPATH -#define USER_CONFIGPATH "/etc/X11/%S," "%P/etc/X11/%S," \ - "/etc/X11/%G," "%P/etc/X11/%G," \ - "/etc/X11/%X-%M," "/etc/X11/%X," "/etc/%X," \ - "%P/etc/X11/%X.%H," "%P/etc/X11/%X-%M," \ - "%P/etc/X11/%X," \ - "%P/lib/X11/%X.%H," "%P/lib/X11/%X-%M," \ - "%P/lib/X11/%X" -#endif -#ifndef ROOT_CONFIGDIRPATH -#define ROOT_CONFIGDIRPATH "%A," "%R," \ - "/etc/X11/%R," "%C/X11/%R," \ - "/etc/X11/%X," "%C/X11/%X" -#endif -#ifndef USER_CONFIGDIRPATH -#define USER_CONFIGDIRPATH "/etc/X11/%R," "%C/X11/%R," \ - "/etc/X11/%X," "%C/X11/%X" -#endif -#ifndef SYS_CONFIGDIRPATH -#define SYS_CONFIGDIRPATH "/usr/share/X11/%X," "%D/X11/%X" -#endif -#ifndef PROJECTROOT -#define PROJECTROOT "/usr/X11R6" -#endif - -static ModuleDefault ModuleDefaults[] = { - {.name = "extmod", .toLoad = TRUE, .load_opt=NULL}, -#ifdef DBE - {.name = "dbe", .toLoad = TRUE, .load_opt=NULL}, -#endif -#ifdef GLXEXT - {.name = "glx", .toLoad = TRUE, .load_opt=NULL}, -#endif -#ifdef XRECORD - {.name = "record", .toLoad = TRUE, .load_opt=NULL}, -#endif -#ifdef XF86DRI - {.name = "dri", .toLoad = TRUE, .load_opt=NULL}, -#endif -#ifdef DRI2 - {.name = "dri2", .toLoad = TRUE, .load_opt=NULL}, -#endif - {.name = NULL, .toLoad = FALSE, .load_opt=NULL} -}; - - -/* Forward declarations */ -static Bool configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, - int scrnum, MessageType from); -static Bool configMonitor(MonPtr monitorp, XF86ConfMonitorPtr conf_monitor); -static Bool configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device, - Bool active); -static Bool configInput(IDevPtr inputp, XF86ConfInputPtr conf_input, - MessageType from); -static Bool configDisplay(DispPtr displayp, XF86ConfDisplayPtr conf_display); -static Bool addDefaultModes(MonPtr monitorp); -#ifdef XF86DRI -static void configDRI(XF86ConfDRIPtr drip); -#endif -static void configExtensions(XF86ConfExtensionsPtr conf_ext); - -/* - * xf86GetPathElem -- - * Extract a single element from the font path string starting at - * pnt. The font path element will be returned, and pnt will be - * updated to point to the start of the next element, or set to - * NULL if there are no more. - */ -static char * -xf86GetPathElem(char **pnt) -{ - char *p1; - - p1 = *pnt; - *pnt = index(*pnt, ','); - if (*pnt != NULL) { - **pnt = '\0'; - *pnt += 1; - } - return(p1); -} - -/* - * xf86ValidateFontPath -- - * Validates the user-specified font path. Each element that - * begins with a '/' is checked to make sure the directory exists. - * If the directory exists, the existence of a file named 'fonts.dir' - * is checked. If either check fails, an error is printed and the - * element is removed from the font path. - */ - -#define DIR_FILE "/fonts.dir" -static char * -xf86ValidateFontPath(char *path) -{ - char *tmp_path, *out_pnt, *path_elem, *next, *p1, *dir_elem; - struct stat stat_buf; - int flag; - int dirlen; - - tmp_path = xcalloc(1,strlen(path)+1); - out_pnt = tmp_path; - path_elem = NULL; - next = path; - while (next != NULL) { - path_elem = xf86GetPathElem(&next); - if (*path_elem == '/') { - dir_elem = xnfcalloc(1, strlen(path_elem) + 1); - if ((p1 = strchr(path_elem, ':')) != 0) - dirlen = p1 - path_elem; - else - dirlen = strlen(path_elem); - strncpy(dir_elem, path_elem, dirlen); - dir_elem[dirlen] = '\0'; - flag = stat(dir_elem, &stat_buf); - if (flag == 0) - if (!S_ISDIR(stat_buf.st_mode)) - flag = -1; - if (flag != 0) { - xf86Msg(X_WARNING, "The directory \"%s\" does not exist.\n", dir_elem); - xf86ErrorF("\tEntry deleted from font path.\n"); - xfree(dir_elem); - continue; - } - else { - p1 = xnfalloc(strlen(dir_elem)+strlen(DIR_FILE)+1); - strcpy(p1, dir_elem); - strcat(p1, DIR_FILE); - flag = stat(p1, &stat_buf); - if (flag == 0) - if (!S_ISREG(stat_buf.st_mode)) - flag = -1; - xfree(p1); - if (flag != 0) { - xf86Msg(X_WARNING, - "`fonts.dir' not found (or not valid) in \"%s\".\n", - dir_elem); - xf86ErrorF("\tEntry deleted from font path.\n"); - xf86ErrorF("\t(Run 'mkfontdir' on \"%s\").\n", dir_elem); - xfree(dir_elem); - continue; - } - } - xfree(dir_elem); - } - - /* - * Either an OK directory, or a font server name. So add it to - * the path. - */ - if (out_pnt != tmp_path) - *out_pnt++ = ','; - strcat(out_pnt, path_elem); - out_pnt += strlen(path_elem); - } - return(tmp_path); -} - - -/* - * use the datastructure that the parser provides and pick out the parts - * that we need at this point - */ -char ** -xf86ModulelistFromConfig(pointer **optlist) -{ - int count = 0, i = 0; - char **modulearray; - char *ignore[] = { "GLcore", "speedo", "bitmap", "drm", - "freetype", "type1", - NULL }; - pointer *optarray; - XF86LoadPtr modp; - Bool found; - - /* - * make sure the config file has been parsed and that we have a - * ModulePath set; if no ModulePath was given, use the default - * ModulePath - */ - if (xf86configptr == NULL) { - xf86Msg(X_ERROR, "Cannot access global config data structure\n"); - return NULL; - } - - if (xf86configptr->conf_modules) { - /* Walk the disable list and let people know what we've parsed to - * not be loaded - */ - modp = xf86configptr->conf_modules->mod_disable_lst; - while (modp) { - xf86Msg(X_WARNING, "\"%s\" will not be loaded unless you've specified it to be loaded elsewhere.\n", modp->load_name); - modp = (XF86LoadPtr) modp->list.next; - } - /* - * Walk the default settings table. For each module listed to be - * loaded, make sure it's in the mod_load_lst. If it's not, make - * sure it's not in the mod_no_load_lst. If it's not disabled, - * append it to mod_load_lst - */ - for (i=0 ; ModuleDefaults[i].name != NULL ; i++) { - if (ModuleDefaults[i].toLoad == FALSE) { - xf86Msg(X_WARNING, "\"%s\" is not to be loaded by default. Skipping.\n", ModuleDefaults[i].name); - continue; - } - found = FALSE; - modp = xf86configptr->conf_modules->mod_load_lst; - while (modp) { - if (strcmp(modp->load_name, ModuleDefaults[i].name) == 0) { - xf86Msg(X_INFO, "\"%s\" will be loaded. This was enabled by default and also specified in the config file.\n", ModuleDefaults[i].name); - found = TRUE; - break; - } - modp = (XF86LoadPtr) modp->list.next; - } - if (found == FALSE) { - modp = xf86configptr->conf_modules->mod_disable_lst; - while (modp) { - if (strcmp(modp->load_name, ModuleDefaults[i].name) == 0) { - xf86Msg(X_INFO, "\"%s\" will be loaded even though the default is to disable it.\n", ModuleDefaults[i].name); - found = TRUE; - break; - } - modp = (XF86LoadPtr) modp->list.next; - } - } - if (found == FALSE) { - XF86LoadPtr ptr = (XF86LoadPtr)xf86configptr->conf_modules; - ptr = xf86addNewLoadDirective(ptr, ModuleDefaults[i].name, XF86_LOAD_MODULE, ModuleDefaults[i].load_opt); - xf86Msg(X_INFO, "\"%s\" will be loaded by default.\n", ModuleDefaults[i].name); - } - } - } else { - xf86configptr->conf_modules = xnfcalloc(1, sizeof(XF86ConfModuleRec)); - for (i=0 ; ModuleDefaults[i].name != NULL ; i++) { - if (ModuleDefaults[i].toLoad == TRUE) { - XF86LoadPtr ptr = (XF86LoadPtr)xf86configptr->conf_modules; - ptr = xf86addNewLoadDirective(ptr, ModuleDefaults[i].name, XF86_LOAD_MODULE, ModuleDefaults[i].load_opt); - } - } - } - - /* - * Walk the list of modules in the "Module" section to determine how - * many we have. - */ - modp = xf86configptr->conf_modules->mod_load_lst; - while (modp) { - for (i = 0; ignore[i]; i++) { - if (strcmp(modp->load_name, ignore[i]) == 0) - modp->ignore = 1; - } - if (!modp->ignore) - count++; - modp = (XF86LoadPtr) modp->list.next; - } - - /* - * allocate the memory and walk the list again to fill in the pointers - */ - modulearray = xnfalloc((count + 1) * sizeof(char*)); - optarray = xnfalloc((count + 1) * sizeof(pointer)); - count = 0; - if (xf86configptr->conf_modules) { - modp = xf86configptr->conf_modules->mod_load_lst; - while (modp) { - if (!modp->ignore) { - modulearray[count] = modp->load_name; - optarray[count] = modp->load_opt; - count++; - } - modp = (XF86LoadPtr) modp->list.next; - } - } - modulearray[count] = NULL; - optarray[count] = NULL; - if (optlist) - *optlist = optarray; - else - xfree(optarray); - return modulearray; -} - - -char ** -xf86DriverlistFromConfig(void) -{ - int count = 0; - int j; - char **modulearray; - screenLayoutPtr slp; - - /* - * make sure the config file has been parsed and that we have a - * ModulePath set; if no ModulePath was given, use the default - * ModulePath - */ - if (xf86configptr == NULL) { - xf86Msg(X_ERROR, "Cannot access global config data structure\n"); - return NULL; - } - - /* - * Walk the list of driver lines in active "Device" sections to - * determine now many implicitly loaded modules there are. - * - */ - if (xf86ConfigLayout.screens) { - slp = xf86ConfigLayout.screens; - while ((slp++)->screen) { - count++; - } - } - - /* - * Handle the set of inactive "Device" sections. - */ - j = 0; - while (xf86ConfigLayout.inactives[j++].identifier) - count++; - - if (count == 0) - return NULL; - - /* - * allocate the memory and walk the list again to fill in the pointers - */ - modulearray = xnfalloc((count + 1) * sizeof(char*)); - count = 0; - slp = xf86ConfigLayout.screens; - while (slp->screen) { - modulearray[count] = slp->screen->device->driver; - count++; - slp++; - } - - j = 0; - - while (xf86ConfigLayout.inactives[j].identifier) - modulearray[count++] = xf86ConfigLayout.inactives[j++].driver; - - modulearray[count] = NULL; - - /* Remove duplicates */ - for (count = 0; modulearray[count] != NULL; count++) { - int i; - - for (i = 0; i < count; i++) - if (xf86NameCmp(modulearray[i], modulearray[count]) == 0) { - modulearray[count] = ""; - break; - } - } - return modulearray; -} - -char ** -xf86InputDriverlistFromConfig(void) -{ - int count = 0; - char **modulearray; - IDevPtr* idp; - - /* - * make sure the config file has been parsed and that we have a - * ModulePath set; if no ModulePath was given, use the default - * ModulePath - */ - if (xf86configptr == NULL) { - xf86Msg(X_ERROR, "Cannot access global config data structure\n"); - return NULL; - } - - /* - * Walk the list of driver lines in active "InputDevice" sections to - * determine now many implicitly loaded modules there are. - */ - if (xf86ConfigLayout.inputs) { - idp = xf86ConfigLayout.inputs; - while (*idp) { - count++; - idp++; - } - } - - if (count == 0) - return NULL; - - /* - * allocate the memory and walk the list again to fill in the pointers - */ - modulearray = xnfalloc((count + 1) * sizeof(char*)); - count = 0; - idp = xf86ConfigLayout.inputs; - while (idp && *idp) { - modulearray[count] = (*idp)->driver; - count++; - idp++; - } - modulearray[count] = NULL; - - /* Remove duplicates */ - for (count = 0; modulearray[count] != NULL; count++) { - int i; - - for (i = 0; i < count; i++) - if (xf86NameCmp(modulearray[i], modulearray[count]) == 0) { - modulearray[count] = ""; - break; - } - } - return modulearray; -} - -static void -fixup_video_driver_list(char **drivers) -{ - static const char *fallback[4] = { "vesa", "fbdev", "wsfb", NULL }; - char **end, **drv; - char *x; - char **ati, **atimisc; - int i; - - /* walk to the end of the list */ - for (end = drivers; *end && **end; end++) ; - end--; - - /* - * for each of the fallback drivers, if we find it in the list, - * swap it with the last available non-fallback driver. - */ - for (i = 0; fallback[i]; i++) { - for (drv = drivers; drv != end; drv++) { - if (strstr(*drv, fallback[i])) { - x = *drv; *drv = *end; *end = x; - end--; - break; - } - } - } - /* - * since the ati wrapper driver is gross and awful, sort ati before - * atimisc, which makes sure all the ati symbols are visible in xorgcfg. - */ - for (drv = drivers; drv != end; drv++) { - if (!strcmp(*drv, "atimisc")) { - atimisc = drv; - for (drv = atimisc; drv != end; drv++) { - if (!strcmp(*drv, "ati")) { - ati = drv; - x = *ati; *ati = *atimisc; *atimisc = x; - return; - } - } - /* if we get here, ati was already ahead of atimisc */ - return; - } - } -} - -static char ** -GenerateDriverlist(char * dirname) -{ - char **ret; - const char *subdirs[] = { dirname, NULL }; - static const char *patlist[] = {"(.*)_drv\\.so", "(.*)_drv\\.o", NULL}; - ret = LoaderListDirs(subdirs, patlist); - - /* fix up the probe order for video drivers */ - if (strstr(dirname, "drivers") && ret != NULL) - fixup_video_driver_list(ret); - - return ret; -} - -char ** -xf86DriverlistFromCompile(void) -{ - static char **driverlist = NULL; - - if (!driverlist) - driverlist = GenerateDriverlist("drivers"); - - return driverlist; -} - -/* - * xf86ConfigError -- - * Print a READABLE ErrorMessage!!! All information that is - * available is printed. - */ -static void -xf86ConfigError(char *msg, ...) -{ - va_list ap; - - ErrorF("\nConfig Error:\n"); - va_start(ap, msg); - VErrorF(msg, ap); - va_end(ap); - ErrorF("\n"); - return; -} - -static void -configFiles(XF86ConfFilesPtr fileconf) -{ - MessageType pathFrom; - Bool must_copy; - int size, countDirs; - char *temp_path, *log_buf, *start, *end; - - /* FontPath */ - must_copy = TRUE; - - temp_path = defaultFontPath ? defaultFontPath : ""; - if (xf86fpFlag) - pathFrom = X_CMDLINE; - else if (fileconf && fileconf->file_fontpath) { - pathFrom = X_CONFIG; - if (xf86Info.useDefaultFontPath) { - defaultFontPath = Xprintf("%s%s%s", - fileconf->file_fontpath, - *temp_path ? "," : "", temp_path); - if (defaultFontPath != NULL) { - must_copy = FALSE; - } - } - else - defaultFontPath = fileconf->file_fontpath; - } - else - pathFrom = X_DEFAULT; - temp_path = defaultFontPath ? defaultFontPath : ""; - - /* xf86ValidateFontPath modifies its argument, but returns a copy of it. */ - temp_path = must_copy ? xnfstrdup(defaultFontPath) : defaultFontPath; - defaultFontPath = xf86ValidateFontPath(temp_path); - xfree(temp_path); - - /* make fontpath more readable in the logfiles */ - countDirs = 1; - temp_path = defaultFontPath; - while ((temp_path = index(temp_path, ',')) != NULL) { - countDirs++; - temp_path++; - } - - log_buf = xnfalloc(strlen(defaultFontPath) + (2 * countDirs) + 1); - temp_path = log_buf; - start = defaultFontPath; - while((end = index(start, ',')) != NULL) { - size = (end - start) + 1; - *(temp_path++) = '\t'; - strncpy(temp_path, start, size); - temp_path += size; - *(temp_path++) = '\n'; - start += size; - } - /* copy last entry */ - *(temp_path++) = '\t'; - strcpy(temp_path, start); - xf86Msg(pathFrom, "FontPath set to:\n%s\n", log_buf); - xfree(log_buf); - - /* ModulePath */ - - if (fileconf) { - if (xf86ModPathFrom != X_CMDLINE && fileconf->file_modulepath) { - xf86ModulePath = fileconf->file_modulepath; - xf86ModPathFrom = X_CONFIG; - } - } - - xf86Msg(xf86ModPathFrom, "ModulePath set to \"%s\"\n", xf86ModulePath); - - if (!xf86xkbdirFlag && fileconf && fileconf->file_xkbdir) { - XkbBaseDirectory = fileconf->file_xkbdir; - xf86Msg(X_CONFIG, "XKB base directory set to \"%s\"\n", - XkbBaseDirectory); - } -#if 0 - /* LogFile */ - /* - * XXX The problem with this is that the log file is already open. - * One option might be to copy the exiting contents to the new location. - * and re-open it. The down side is that the default location would - * already have been overwritten. Another option would be to start with - * unique temporary location, then copy it once the correct name is known. - * A problem with this is what happens if the server exits before that - * happens. - */ - if (xf86LogFileFrom == X_DEFAULT && fileconf->file_logfile) { - xf86LogFile = fileconf->file_logfile; - xf86LogFileFrom = X_CONFIG; - } -#endif - - return; -} - -typedef enum { - FLAG_NOTRAPSIGNALS, - FLAG_DONTVTSWITCH, - FLAG_DONTZAP, - FLAG_DONTZOOM, - FLAG_DISABLEVIDMODE, - FLAG_ALLOWNONLOCAL, - FLAG_ALLOWMOUSEOPENFAIL, - FLAG_VTSYSREQ, - FLAG_SAVER_BLANKTIME, - FLAG_DPMS_STANDBYTIME, - FLAG_DPMS_SUSPENDTIME, - FLAG_DPMS_OFFTIME, - FLAG_PIXMAP, - FLAG_PC98, - FLAG_NOPM, - FLAG_XINERAMA, - FLAG_LOG, - FLAG_RENDER_COLORMAP_MODE, - FLAG_RANDR, - FLAG_AIGLX, - FLAG_IGNORE_ABI, - FLAG_ALLOW_EMPTY_INPUT, - FLAG_USE_DEFAULT_FONT_PATH, - FLAG_AUTO_ADD_DEVICES, - FLAG_AUTO_ENABLE_DEVICES, - FLAG_GLX_VISUALS, - FLAG_DRI2, - FLAG_USE_SIGIO -} FlagValues; - -/** - * NOTE: the last value for each entry is NOT the default. It is set to TRUE - * if the parser found the option in the config file. - */ -static OptionInfoRec FlagOptions[] = { - { FLAG_NOTRAPSIGNALS, "NoTrapSignals", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_DONTVTSWITCH, "DontVTSwitch", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_DONTZAP, "DontZap", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_DONTZOOM, "DontZoom", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_DISABLEVIDMODE, "DisableVidModeExtension", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_ALLOWNONLOCAL, "AllowNonLocalXvidtune", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_ALLOWMOUSEOPENFAIL, "AllowMouseOpenFail", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_VTSYSREQ, "VTSysReq", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_SAVER_BLANKTIME, "BlankTime" , OPTV_INTEGER, - {0}, FALSE }, - { FLAG_DPMS_STANDBYTIME, "StandbyTime", OPTV_INTEGER, - {0}, FALSE }, - { FLAG_DPMS_SUSPENDTIME, "SuspendTime", OPTV_INTEGER, - {0}, FALSE }, - { FLAG_DPMS_OFFTIME, "OffTime", OPTV_INTEGER, - {0}, FALSE }, - { FLAG_PIXMAP, "Pixmap", OPTV_INTEGER, - {0}, FALSE }, - { FLAG_PC98, "PC98", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_NOPM, "NoPM", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_XINERAMA, "Xinerama", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_LOG, "Log", OPTV_STRING, - {0}, FALSE }, - { FLAG_RENDER_COLORMAP_MODE, "RenderColormapMode", OPTV_STRING, - {0}, FALSE }, - { FLAG_RANDR, "RandR", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_AIGLX, "AIGLX", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_ALLOW_EMPTY_INPUT, "AllowEmptyInput", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_IGNORE_ABI, "IgnoreABI", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_USE_DEFAULT_FONT_PATH, "UseDefaultFontPath", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_AUTO_ADD_DEVICES, "AutoAddDevices", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_AUTO_ENABLE_DEVICES, "AutoEnableDevices", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_GLX_VISUALS, "GlxVisuals", OPTV_STRING, - {0}, FALSE }, - { FLAG_DRI2, "DRI2", OPTV_BOOLEAN, - {0}, FALSE }, - { FLAG_USE_SIGIO, "UseSIGIO", OPTV_BOOLEAN, - {0}, FALSE }, - { -1, NULL, OPTV_NONE, - {0}, FALSE }, -}; - -#ifdef SUPPORT_PC98 -static Bool -detectPC98(void) -{ - unsigned char buf[2]; - - if (xf86ReadBIOS(0xf8000, 0xe80, buf, 2) != 2) - return FALSE; - if ((buf[0] == 0x98) && (buf[1] == 0x21)) - return TRUE; - else - return FALSE; -} -#endif - -static Bool -configServerFlags(XF86ConfFlagsPtr flagsconf, XF86OptionPtr layoutopts) -{ - XF86OptionPtr optp, tmp; - int i; - Pix24Flags pix24 = Pix24DontCare; - Bool value; - MessageType from; - const char *s; - XkbRMLVOSet set; - /* Default options. */ - set.rules = "base"; - set.model = "pc105"; - set.layout = "us"; - set.variant = NULL; - set.options = NULL; - - /* - * Merge the ServerLayout and ServerFlags options. The former have - * precedence over the latter. - */ - optp = NULL; - if (flagsconf && flagsconf->flg_option_lst) - optp = xf86optionListDup(flagsconf->flg_option_lst); - if (layoutopts) { - tmp = xf86optionListDup(layoutopts); - if (optp) - optp = xf86optionListMerge(optp, tmp); - else - optp = tmp; - } - - xf86ProcessOptions(-1, optp, FlagOptions); - - xf86GetOptValBool(FlagOptions, FLAG_NOTRAPSIGNALS, &xf86Info.notrapSignals); - xf86GetOptValBool(FlagOptions, FLAG_DONTVTSWITCH, &xf86Info.dontVTSwitch); - xf86GetOptValBool(FlagOptions, FLAG_DONTZAP, &xf86Info.dontZap); - xf86GetOptValBool(FlagOptions, FLAG_DONTZOOM, &xf86Info.dontZoom); - - xf86GetOptValBool(FlagOptions, FLAG_IGNORE_ABI, &xf86Info.ignoreABI); - if (xf86Info.ignoreABI) { - xf86Msg(X_CONFIG, "Ignoring ABI Version\n"); - } - - if (xf86SIGIOSupported()) { - xf86Info.useSIGIO = xf86ReturnOptValBool(FlagOptions, FLAG_USE_SIGIO, USE_SIGIO_BY_DEFAULT); - if (xf86IsOptionSet(FlagOptions, FLAG_USE_SIGIO)) { - from = X_CONFIG; - } else { - from = X_DEFAULT; - } - if (!xf86Info.useSIGIO) { - xf86Msg(from, "Disabling SIGIO handlers for input devices\n"); - } else if (from == X_CONFIG) { - xf86Msg(from, "Enabling SIGIO handlers for input devices\n"); - } - } else { - xf86Info.useSIGIO = FALSE; - } - - if (xf86IsOptionSet(FlagOptions, FLAG_AUTO_ADD_DEVICES)) { - xf86GetOptValBool(FlagOptions, FLAG_AUTO_ADD_DEVICES, - &xf86Info.autoAddDevices); - from = X_CONFIG; - } - else { - from = X_DEFAULT; - } - xf86Msg(from, "%sutomatically adding devices\n", - xf86Info.autoAddDevices ? "A" : "Not a"); - - if (xf86IsOptionSet(FlagOptions, FLAG_AUTO_ENABLE_DEVICES)) { - xf86GetOptValBool(FlagOptions, FLAG_AUTO_ENABLE_DEVICES, - &xf86Info.autoEnableDevices); - from = X_CONFIG; - } - else { - from = X_DEFAULT; - } - xf86Msg(from, "%sutomatically enabling devices\n", - xf86Info.autoEnableDevices ? "A" : "Not a"); - - /* - * Set things up based on the config file information. Some of these - * settings may be overridden later when the command line options are - * checked. - */ -#ifdef XF86VIDMODE - if (xf86GetOptValBool(FlagOptions, FLAG_DISABLEVIDMODE, &value)) - xf86Info.vidModeEnabled = !value; - if (xf86GetOptValBool(FlagOptions, FLAG_ALLOWNONLOCAL, &value)) - xf86Info.vidModeAllowNonLocal = value; -#endif - - if (xf86GetOptValBool(FlagOptions, FLAG_ALLOWMOUSEOPENFAIL, &value)) - xf86Info.allowMouseOpenFail = value; - - if (xf86GetOptValBool(FlagOptions, FLAG_VTSYSREQ, &value)) { -#ifdef USE_VT_SYSREQ - xf86Info.vtSysreq = value; - xf86Msg(X_CONFIG, "VTSysReq %s\n", value ? "enabled" : "disabled"); -#else - if (value) - xf86Msg(X_WARNING, "VTSysReq is not supported on this OS\n"); -#endif - } - - xf86Info.pmFlag = TRUE; - if (xf86GetOptValBool(FlagOptions, FLAG_NOPM, &value)) - xf86Info.pmFlag = !value; - { - if ((s = xf86GetOptValString(FlagOptions, FLAG_LOG))) { - if (!xf86NameCmp(s,"flush")) { - xf86Msg(X_CONFIG, "Flushing logfile enabled\n"); - xf86Info.log = LogFlush; - LogSetParameter(XLOG_FLUSH, TRUE); - } else if (!xf86NameCmp(s,"sync")) { - xf86Msg(X_CONFIG, "Syncing logfile enabled\n"); - xf86Info.log = LogSync; - LogSetParameter(XLOG_FLUSH, TRUE); - LogSetParameter(XLOG_SYNC, TRUE); - } else { - xf86Msg(X_WARNING,"Unknown Log option\n"); - } - } - } - - { - if ((s = xf86GetOptValString(FlagOptions, FLAG_RENDER_COLORMAP_MODE))){ - int policy = PictureParseCmapPolicy (s); - if (policy == PictureCmapPolicyInvalid) - xf86Msg(X_WARNING, "Unknown colormap policy \"%s\"\n", s); - else - { - xf86Msg(X_CONFIG, "Render colormap policy set to %s\n", s); - PictureCmapPolicy = policy; - } - } - } - -#ifdef RANDR - xf86Info.disableRandR = FALSE; - xf86Info.randRFrom = X_DEFAULT; - if (xf86GetOptValBool(FlagOptions, FLAG_RANDR, &value)) { - xf86Info.disableRandR = !value; - xf86Info.randRFrom = X_CONFIG; - } -#endif - - xf86Info.aiglx = TRUE; - xf86Info.aiglxFrom = X_DEFAULT; - if (xf86GetOptValBool(FlagOptions, FLAG_AIGLX, &value)) { - xf86Info.aiglx = value; - xf86Info.aiglxFrom = X_CONFIG; - } - -#ifdef GLXEXT - xf86Info.glxVisuals = XF86_GlxVisualsTypical; - xf86Info.glxVisualsFrom = X_DEFAULT; - if ((s = xf86GetOptValString(FlagOptions, FLAG_GLX_VISUALS))) { - if (!xf86NameCmp(s, "minimal")) { - xf86Info.glxVisuals = XF86_GlxVisualsMinimal; - } else if (!xf86NameCmp(s, "typical")) { - xf86Info.glxVisuals = XF86_GlxVisualsTypical; - } else if (!xf86NameCmp(s, "all")) { - xf86Info.glxVisuals = XF86_GlxVisualsAll; - } else { - xf86Msg(X_WARNING,"Unknown GlxVisuals option\n"); - } - } - - if (xf86GetOptValBool(FlagOptions, FLAG_AIGLX, &value)) { - xf86Info.aiglx = value; - xf86Info.aiglxFrom = X_CONFIG; - } -#endif - - /* AllowEmptyInput is automatically true if we're hotplugging */ - xf86Info.allowEmptyInput = (xf86Info.autoAddDevices && xf86Info.autoEnableDevices); - xf86GetOptValBool(FlagOptions, FLAG_ALLOW_EMPTY_INPUT, &xf86Info.allowEmptyInput); - - /* AEI on? Then we're not using kbd, so use the evdev rules set. */ -#if defined(linux) - if (xf86Info.allowEmptyInput) - set.rules = "evdev"; -#endif - XkbSetRulesDflts(&set); - - xf86Info.useDefaultFontPath = TRUE; - xf86Info.useDefaultFontPathFrom = X_DEFAULT; - if (xf86GetOptValBool(FlagOptions, FLAG_USE_DEFAULT_FONT_PATH, &value)) { - xf86Info.useDefaultFontPath = value; - xf86Info.useDefaultFontPathFrom = X_CONFIG; - } - -/* Make sure that timers don't overflow CARD32's after multiplying */ -#define MAX_TIME_IN_MIN (0x7fffffff / MILLI_PER_MIN) - - i = -1; - xf86GetOptValInteger(FlagOptions, FLAG_SAVER_BLANKTIME, &i); - if ((i >= 0) && (i < MAX_TIME_IN_MIN)) - ScreenSaverTime = defaultScreenSaverTime = i * MILLI_PER_MIN; - else if (i != -1) - xf86ConfigError("BlankTime value %d outside legal range of 0 - %d minutes", - i, MAX_TIME_IN_MIN); - -#ifdef DPMSExtension - i = -1; - xf86GetOptValInteger(FlagOptions, FLAG_DPMS_STANDBYTIME, &i); - if ((i >= 0) && (i < MAX_TIME_IN_MIN)) - DPMSStandbyTime = i * MILLI_PER_MIN; - else if (i != -1) - xf86ConfigError("StandbyTime value %d outside legal range of 0 - %d minutes", - i, MAX_TIME_IN_MIN); - i = -1; - xf86GetOptValInteger(FlagOptions, FLAG_DPMS_SUSPENDTIME, &i); - if ((i >= 0) && (i < MAX_TIME_IN_MIN)) - DPMSSuspendTime = i * MILLI_PER_MIN; - else if (i != -1) - xf86ConfigError("SuspendTime value %d outside legal range of 0 - %d minutes", - i, MAX_TIME_IN_MIN); - i = -1; - xf86GetOptValInteger(FlagOptions, FLAG_DPMS_OFFTIME, &i); - if ((i >= 0) && (i < MAX_TIME_IN_MIN)) - DPMSOffTime = i * MILLI_PER_MIN; - else if (i != -1) - xf86ConfigError("OffTime value %d outside legal range of 0 - %d minutes", - i, MAX_TIME_IN_MIN); -#endif - - i = -1; - xf86GetOptValInteger(FlagOptions, FLAG_PIXMAP, &i); - switch (i) { - case 24: - pix24 = Pix24Use24; - break; - case 32: - pix24 = Pix24Use32; - break; - case -1: - break; - default: - xf86ConfigError("Pixmap option's value (%d) must be 24 or 32\n", i); - return FALSE; - } - if (xf86Pix24 != Pix24DontCare) { - xf86Info.pixmap24 = xf86Pix24; - xf86Info.pix24From = X_CMDLINE; - } else if (pix24 != Pix24DontCare) { - xf86Info.pixmap24 = pix24; - xf86Info.pix24From = X_CONFIG; - } else { - xf86Info.pixmap24 = Pix24DontCare; - xf86Info.pix24From = X_DEFAULT; - } -#ifdef SUPPORT_PC98 - if (xf86GetOptValBool(FlagOptions, FLAG_PC98, &value)) { - xf86Info.pc98 = value; - if (value) { - xf86Msg(X_CONFIG, "Japanese PC98 architecture\n"); - } - } else - if (detectPC98()) { - xf86Info.pc98 = TRUE; - xf86Msg(X_PROBED, "Japanese PC98 architecture\n"); - } -#endif - -#ifdef PANORAMIX - from = X_DEFAULT; - if (!noPanoramiXExtension) - from = X_CMDLINE; - else if (xf86GetOptValBool(FlagOptions, FLAG_XINERAMA, &value)) { - noPanoramiXExtension = !value; - from = X_CONFIG; - } - if (!noPanoramiXExtension) - xf86Msg(from, "Xinerama: enabled\n"); -#endif - -#ifdef DRI2 - xf86Info.dri2 = FALSE; - xf86Info.dri2From = X_DEFAULT; - if (xf86GetOptValBool(FlagOptions, FLAG_DRI2, &value)) { - xf86Info.dri2 = value; - xf86Info.dri2From = X_CONFIG; - } -#endif - - return TRUE; -} - -Bool xf86DRI2Enabled(void) -{ - return xf86Info.dri2; -} - -/* - * Locate the core input devices. These can be specified/located in - * the following ways, in order of priority: - * - * 1. The InputDevices named by the -pointer and -keyboard command line - * options. - * 2. The "CorePointer" and "CoreKeyboard" InputDevices referred to by - * the active ServerLayout. - * 3. The first InputDevices marked as "CorePointer" and "CoreKeyboard". - * 4. The first InputDevices that use 'keyboard' or 'kbd' and a valid mouse - * driver (mouse, synaptics, evdev, vmmouse, void) - * 5. Default devices with an empty (default) configuration. These defaults - * will reference the 'mouse' and 'keyboard' drivers. - */ - -static Bool -checkCoreInputDevices(serverLayoutPtr servlayoutp, Bool implicitLayout) -{ - IDevPtr corePointer = NULL, coreKeyboard = NULL; - Bool foundPointer = FALSE, foundKeyboard = FALSE; - const char *pointerMsg = NULL, *keyboardMsg = NULL; - IDevPtr *devs, /* iterator */ - indp; - IDevRec Pointer, Keyboard; - XF86ConfInputPtr confInput; - XF86ConfInputRec defPtr, defKbd; - int count = 0; - MessageType from = X_DEFAULT; - int found = 0; - const char *mousedrivers[] = { "mouse", "synaptics", "evdev", "vmmouse", - "void", NULL }; - - /* - * First check if a core pointer or core keyboard have been specified - * in the active ServerLayout. If more than one is specified for either, - * remove the core attribute from the later ones. - */ - for (devs = servlayoutp->inputs; devs && *devs; devs++) { - pointer opt1 = NULL, opt2 = NULL; - indp = *devs; - if (indp->commonOptions && - xf86CheckBoolOption(indp->commonOptions, "CorePointer", FALSE)) { - opt1 = indp->commonOptions; - } - if (indp->extraOptions && - xf86CheckBoolOption(indp->extraOptions, "CorePointer", FALSE)) { - opt2 = indp->extraOptions; - } - if (opt1 || opt2) { - if (!corePointer) { - corePointer = indp; - } else { - if (opt1) - xf86ReplaceBoolOption(opt1, "CorePointer", FALSE); - if (opt2) - xf86ReplaceBoolOption(opt2, "CorePointer", FALSE); - xf86Msg(X_WARNING, "Duplicate core pointer devices. " - "Removing core pointer attribute from \"%s\"\n", - indp->identifier); - } - } - opt1 = opt2 = NULL; - if (indp->commonOptions && - xf86CheckBoolOption(indp->commonOptions, "CoreKeyboard", FALSE)) { - opt1 = indp->commonOptions; - } - if (indp->extraOptions && - xf86CheckBoolOption(indp->extraOptions, "CoreKeyboard", FALSE)) { - opt2 = indp->extraOptions; - } - if (opt1 || opt2) { - if (!coreKeyboard) { - coreKeyboard = indp; - } else { - if (opt1) - xf86ReplaceBoolOption(opt1, "CoreKeyboard", FALSE); - if (opt2) - xf86ReplaceBoolOption(opt2, "CoreKeyboard", FALSE); - xf86Msg(X_WARNING, "Duplicate core keyboard devices. " - "Removing core keyboard attribute from \"%s\"\n", - indp->identifier); - } - } - count++; - } - - confInput = NULL; - - /* 1. Check for the -pointer command line option. */ - if (xf86PointerName) { - confInput = xf86findInput(xf86PointerName, - xf86configptr->conf_input_lst); - if (!confInput) { - xf86Msg(X_ERROR, "No InputDevice section called \"%s\"\n", - xf86PointerName); - return FALSE; - } - from = X_CMDLINE; - /* - * If one was already specified in the ServerLayout, it needs to be - * removed. - */ - if (corePointer) { - for (devs = servlayoutp->inputs; devs && *devs; devs++) - if (*devs == corePointer) - { - xfree(*devs); - *devs = (IDevPtr)0x1; /* ensure we dont skip next loop*/ - break; - } - for (; devs && *devs; devs++) - devs[0] = devs[1]; - count--; - } - corePointer = NULL; - foundPointer = TRUE; - } - - /* 2. ServerLayout-specified core pointer. */ - if (corePointer) { - foundPointer = TRUE; - from = X_CONFIG; - } - - /* 3. First core pointer device. */ - if (!foundPointer && (!xf86Info.allowEmptyInput || implicitLayout)) { - XF86ConfInputPtr p; - - for (p = xf86configptr->conf_input_lst; p; p = p->list.next) { - if (p->inp_option_lst && - xf86CheckBoolOption(p->inp_option_lst, "CorePointer", FALSE)) { - confInput = p; - foundPointer = TRUE; - from = X_DEFAULT; - pointerMsg = "first core pointer device"; - break; - } - } - } - - /* 4. First pointer with an allowed mouse driver. */ - if (!foundPointer && !xf86Info.allowEmptyInput) { - const char **driver = mousedrivers; - confInput = xf86findInput(CONF_IMPLICIT_POINTER, - xf86configptr->conf_input_lst); - while (*driver && !confInput) { - confInput = xf86findInputByDriver(*driver, - xf86configptr->conf_input_lst); - driver++; - } - if (confInput) { - foundPointer = TRUE; - from = X_DEFAULT; - pointerMsg = "first mouse device"; - } - } - - /* 5. Built-in default. */ - if (!foundPointer && !xf86Info.allowEmptyInput) { - bzero(&defPtr, sizeof(defPtr)); - defPtr.inp_identifier = strdup("<default pointer>"); - defPtr.inp_driver = strdup("mouse"); - confInput = &defPtr; - foundPointer = TRUE; - from = X_DEFAULT; - pointerMsg = "default mouse configuration"; - } - - /* Add the core pointer device to the layout, and set it to Core. */ - if (foundPointer && confInput) { - foundPointer = configInput(&Pointer, confInput, from); - if (foundPointer) { - count++; - devs = xnfrealloc(servlayoutp->inputs, - (count + 1) * sizeof(IDevPtr)); - devs[count - 1] = xnfalloc(sizeof(IDevRec)); - *devs[count - 1] = Pointer; - devs[count - 1]->extraOptions = - xf86addNewOption(NULL, xnfstrdup("CorePointer"), NULL); - devs[count] = NULL; - servlayoutp->inputs = devs; - } - } - - if (!foundPointer && !xf86Info.allowEmptyInput) { - /* This shouldn't happen. */ - xf86Msg(X_ERROR, "Cannot locate a core pointer device.\n"); - return FALSE; - } - - /* - * always synthesize a 'mouse' section configured to send core - * events, unless a 'void' section is found, in which case the user - * probably wants to run footless. - * - * If you're using an evdev keyboard and expect a default mouse - * section ... deal. - */ - for (devs = servlayoutp->inputs; devs && *devs; devs++) { - const char **driver = mousedrivers; - while(*driver) { - if (!strcmp((*devs)->driver, *driver)) { - found = 1; - break; - } - driver++; - } - } - if (!found && !xf86Info.allowEmptyInput) { - xf86Msg(X_INFO, "No default mouse found, adding one\n"); - bzero(&defPtr, sizeof(defPtr)); - defPtr.inp_identifier = strdup("<default pointer>"); - defPtr.inp_driver = strdup("mouse"); - confInput = &defPtr; - foundPointer = configInput(&Pointer, confInput, from); - if (foundPointer) { - count++; - devs = xnfrealloc(servlayoutp->inputs, - (count + 1) * sizeof(IDevPtr)); - devs[count - 1] = xnfalloc(sizeof(IDevRec)); - *devs[count - 1] = Pointer; - devs[count - 1]->extraOptions = - xf86addNewOption(NULL, xnfstrdup("AlwaysCore"), NULL); - devs[count] = NULL; - servlayoutp->inputs = devs; - } - } - - confInput = NULL; - - /* 1. Check for the -keyboard command line option. */ - if (xf86KeyboardName) { - confInput = xf86findInput(xf86KeyboardName, - xf86configptr->conf_input_lst); - if (!confInput) { - xf86Msg(X_ERROR, "No InputDevice section called \"%s\"\n", - xf86KeyboardName); - return FALSE; - } - from = X_CMDLINE; - /* - * If one was already specified in the ServerLayout, it needs to be - * removed. - */ - if (coreKeyboard) { - for (devs = servlayoutp->inputs; devs && *devs; devs++) - if (*devs == coreKeyboard) - { - xfree(*devs); - *devs = (IDevPtr)0x1; /* ensure we dont skip next loop */ - break; - } - for (; devs && *devs; devs++) - devs[0] = devs[1]; - count--; - } - coreKeyboard = NULL; - foundKeyboard = TRUE; - } - - /* 2. ServerLayout-specified core keyboard. */ - if (coreKeyboard) { - foundKeyboard = TRUE; - from = X_CONFIG; - } - - /* 3. First core keyboard device. */ - if (!foundKeyboard && (!xf86Info.allowEmptyInput || implicitLayout)) { - XF86ConfInputPtr p; - - for (p = xf86configptr->conf_input_lst; p; p = p->list.next) { - if (p->inp_option_lst && - xf86CheckBoolOption(p->inp_option_lst, "CoreKeyboard", FALSE)) { - confInput = p; - foundKeyboard = TRUE; - from = X_DEFAULT; - keyboardMsg = "first core keyboard device"; - break; - } - } - } - - /* 4. First keyboard with 'keyboard' or 'kbd' as the driver. */ - if (!foundKeyboard && !xf86Info.allowEmptyInput) { - confInput = xf86findInput(CONF_IMPLICIT_KEYBOARD, - xf86configptr->conf_input_lst); - if (!confInput) { - confInput = xf86findInputByDriver("kbd", - xf86configptr->conf_input_lst); - } - if (confInput) { - foundKeyboard = TRUE; - from = X_DEFAULT; - keyboardMsg = "first keyboard device"; - } - } - - /* 5. Built-in default. */ - if (!foundKeyboard && !xf86Info.allowEmptyInput) { - bzero(&defKbd, sizeof(defKbd)); - defKbd.inp_identifier = strdup("<default keyboard>"); - defKbd.inp_driver = strdup("kbd"); - confInput = &defKbd; - foundKeyboard = TRUE; - keyboardMsg = "default keyboard configuration"; - from = X_DEFAULT; - } - - /* Add the core keyboard device to the layout, and set it to Core. */ - if (foundKeyboard && confInput) { - foundKeyboard = configInput(&Keyboard, confInput, from); - if (foundKeyboard) { - count++; - devs = xnfrealloc(servlayoutp->inputs, - (count + 1) * sizeof(IDevPtr)); - devs[count - 1] = xnfalloc(sizeof(IDevRec)); - *devs[count - 1] = Keyboard; - devs[count - 1]->extraOptions = - xf86addNewOption(NULL, xnfstrdup("CoreKeyboard"), NULL); - devs[count] = NULL; - servlayoutp->inputs = devs; - } - } - - if (!foundKeyboard && !xf86Info.allowEmptyInput) { - /* This shouldn't happen. */ - xf86Msg(X_ERROR, "Cannot locate a core keyboard device.\n"); - return FALSE; - } - - if (pointerMsg) { - if (implicitLayout) - xf86Msg(X_DEFAULT, "No Layout section. Using the %s.\n", - pointerMsg); - else - xf86Msg(X_DEFAULT, "The core pointer device wasn't specified " - "explicitly in the layout.\n" - "\tUsing the %s.\n", pointerMsg); - } - - if (keyboardMsg) { - if (implicitLayout) - xf86Msg(X_DEFAULT, "No Layout section. Using the %s.\n", - keyboardMsg); - else - xf86Msg(X_DEFAULT, "The core keyboard device wasn't specified " - "explicitly in the layout.\n" - "\tUsing the %s.\n", keyboardMsg); - } - - if (xf86Info.allowEmptyInput && !(foundPointer && foundKeyboard)) { -#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) - const char *config_backend; -#if defined(CONFIG_HAL) - config_backend = "HAL"; -#else - config_backend = "udev"; -#endif - xf86Msg(X_INFO, "The server relies on %s to provide the list of " - "input devices.\n\tIf no devices become available, " - "reconfigure %s or disable AutoAddDevices.\n", - config_backend, config_backend); -#else - xf86Msg(X_INFO, "Hotplugging is disabled and no input devices were configured.\n" - "\tTry disabling AllowEmptyInput.\n"); -#endif - } - - return TRUE; -} - -typedef enum { - LAYOUT_ISOLATEDEVICE, - LAYOUT_SINGLECARD -} LayoutValues; - -static OptionInfoRec LayoutOptions[] = { - { LAYOUT_ISOLATEDEVICE, "IsolateDevice", OPTV_STRING, - {0}, FALSE }, - { LAYOUT_SINGLECARD, "SingleCard", OPTV_BOOLEAN, - {0}, FALSE }, - { -1, NULL, OPTV_NONE, - {0}, FALSE }, -}; - -static Bool -configInputDevices(XF86ConfLayoutPtr layout, serverLayoutPtr servlayoutp) -{ - XF86ConfInputrefPtr irp; - IDevPtr *indp; - int count = 0; - - /* - * Count the number of input devices. - */ - irp = layout->lay_input_lst; - while (irp) { - count++; - irp = (XF86ConfInputrefPtr)irp->list.next; - } - DebugF("Found %d input devices in the layout section %s\n", - count, layout->lay_identifier); - indp = xnfcalloc((count + 1), sizeof(IDevPtr)); - indp[count] = NULL; - irp = layout->lay_input_lst; - count = 0; - while (irp) { - indp[count] = xnfalloc(sizeof(IDevRec)); - if (!configInput(indp[count], irp->iref_inputdev, X_CONFIG)) { - while(count--) - xfree(indp[count]); - xfree(indp); - return FALSE; - } - indp[count]->extraOptions = irp->iref_option_lst; - count++; - irp = (XF86ConfInputrefPtr)irp->list.next; - } - servlayoutp->inputs = indp; - - return TRUE; -} - - -/* - * figure out which layout is active, which screens are used in that layout, - * which drivers and monitors are used in these screens - */ -static Bool -configLayout(serverLayoutPtr servlayoutp, XF86ConfLayoutPtr conf_layout, - char *default_layout) -{ - XF86ConfAdjacencyPtr adjp; - XF86ConfInactivePtr idp; - int count = 0; - int scrnum; - XF86ConfLayoutPtr l; - MessageType from; - screenLayoutPtr slp; - GDevPtr gdp; - int i = 0, j; - - if (!servlayoutp) - return FALSE; - - /* - * which layout section is the active one? - * - * If there is a -layout command line option, use that one, otherwise - * pick the first one. - */ - from = X_DEFAULT; - if (xf86LayoutName != NULL) - from = X_CMDLINE; - else if (default_layout) { - xf86LayoutName = default_layout; - from = X_CONFIG; - } - if (xf86LayoutName != NULL) { - if ((l = xf86findLayout(xf86LayoutName, conf_layout)) == NULL) { - xf86Msg(X_ERROR, "No ServerLayout section called \"%s\"\n", - xf86LayoutName); - return FALSE; - } - conf_layout = l; - } - xf86Msg(from, "ServerLayout \"%s\"\n", conf_layout->lay_identifier); - adjp = conf_layout->lay_adjacency_lst; - - /* - * we know that each screen is referenced exactly once on the left side - * of a layout statement in the Layout section. So to allocate the right - * size for the array we do a quick walk of the list to figure out how - * many sections we have - */ - while (adjp) { - count++; - adjp = (XF86ConfAdjacencyPtr)adjp->list.next; - } - - DebugF("Found %d screens in the layout section %s", - count, conf_layout->lay_identifier); - if (!count) /* alloc enough storage even if no screen is specified */ - count = 1; - - slp = xnfcalloc(1, (count + 1) * sizeof(screenLayoutRec)); - slp[count].screen = NULL; - /* - * now that we have storage, loop over the list again and fill in our - * data structure; at this point we do not fill in the adjacency - * information as it is not clear if we need it at all - */ - adjp = conf_layout->lay_adjacency_lst; - count = 0; - while (adjp) { - slp[count].screen = xnfcalloc(1, sizeof(confScreenRec)); - if (adjp->adj_scrnum < 0) - scrnum = count; - else - scrnum = adjp->adj_scrnum; - if (!configScreen(slp[count].screen, adjp->adj_screen, scrnum, - X_CONFIG)) { - xfree(slp); - return FALSE; - } - slp[count].x = adjp->adj_x; - slp[count].y = adjp->adj_y; - slp[count].refname = adjp->adj_refscreen; - switch (adjp->adj_where) { - case CONF_ADJ_OBSOLETE: - slp[count].where = PosObsolete; - slp[count].topname = adjp->adj_top_str; - slp[count].bottomname = adjp->adj_bottom_str; - slp[count].leftname = adjp->adj_left_str; - slp[count].rightname = adjp->adj_right_str; - break; - case CONF_ADJ_ABSOLUTE: - slp[count].where = PosAbsolute; - break; - case CONF_ADJ_RIGHTOF: - slp[count].where = PosRightOf; - break; - case CONF_ADJ_LEFTOF: - slp[count].where = PosLeftOf; - break; - case CONF_ADJ_ABOVE: - slp[count].where = PosAbove; - break; - case CONF_ADJ_BELOW: - slp[count].where = PosBelow; - break; - case CONF_ADJ_RELATIVE: - slp[count].where = PosRelative; - break; - } - count++; - adjp = (XF86ConfAdjacencyPtr)adjp->list.next; - } - - /* No screen was specified in the layout. take the first one from the - * config file, or - if it is NULL - configScreen autogenerates one for - * us */ - if (!count) - { - slp[0].screen = xnfcalloc(1, sizeof(confScreenRec)); - if (!configScreen(slp[0].screen, xf86configptr->conf_screen_lst, - 0, X_CONFIG)) { - xfree(slp[0].screen); - xfree(slp); - return FALSE; - } - } - - /* XXX Need to tie down the upper left screen. */ - - /* Fill in the refscreen and top/bottom/left/right values */ - for (i = 0; i < count; i++) { - for (j = 0; j < count; j++) { - if (slp[i].refname && - strcmp(slp[i].refname, slp[j].screen->id) == 0) { - slp[i].refscreen = slp[j].screen; - } - if (slp[i].topname && - strcmp(slp[i].topname, slp[j].screen->id) == 0) { - slp[i].top = slp[j].screen; - } - if (slp[i].bottomname && - strcmp(slp[i].bottomname, slp[j].screen->id) == 0) { - slp[i].bottom = slp[j].screen; - } - if (slp[i].leftname && - strcmp(slp[i].leftname, slp[j].screen->id) == 0) { - slp[i].left = slp[j].screen; - } - if (slp[i].rightname && - strcmp(slp[i].rightname, slp[j].screen->id) == 0) { - slp[i].right = slp[j].screen; - } - } - if (slp[i].where != PosObsolete - && slp[i].where != PosAbsolute - && !slp[i].refscreen) { - xf86Msg(X_ERROR,"Screen %s doesn't exist: deleting placement\n", - slp[i].refname); - slp[i].where = PosAbsolute; - slp[i].x = 0; - slp[i].y = 0; - } - } - - /* - * Count the number of inactive devices. - */ - count = 0; - idp = conf_layout->lay_inactive_lst; - while (idp) { - count++; - idp = (XF86ConfInactivePtr)idp->list.next; - } - DebugF("Found %d inactive devices in the layout section %s\n", - count, conf_layout->lay_identifier); - gdp = xnfalloc((count + 1) * sizeof(GDevRec)); - gdp[count].identifier = NULL; - idp = conf_layout->lay_inactive_lst; - count = 0; - while (idp) { - if (!configDevice(&gdp[count], idp->inactive_device, FALSE)) { - xfree(gdp); - return FALSE; - } - count++; - idp = (XF86ConfInactivePtr)idp->list.next; - } - - if (!configInputDevices(conf_layout, servlayoutp)) - return FALSE; - - servlayoutp->id = conf_layout->lay_identifier; - servlayoutp->screens = slp; - servlayoutp->inactives = gdp; - servlayoutp->options = conf_layout->lay_option_lst; - from = X_DEFAULT; - - return TRUE; -} - -/* - * No layout section, so find the first Screen section and set that up as - * the only active screen. - */ -static Bool -configImpliedLayout(serverLayoutPtr servlayoutp, XF86ConfScreenPtr conf_screen, - XF86ConfigPtr xf86configptr) -{ - MessageType from; - XF86ConfScreenPtr s; - screenLayoutPtr slp; - IDevPtr *indp; - XF86ConfLayoutRec layout; - - if (!servlayoutp) - return FALSE; - - /* - * which screen section is the active one? - * - * If there is a -screen option, use that one, otherwise use the first - * one. - */ - - from = X_CONFIG; - if (xf86ScreenName != NULL) { - if ((s = xf86findScreen(xf86ScreenName, conf_screen)) == NULL) { - xf86Msg(X_ERROR, "No Screen section called \"%s\"\n", - xf86ScreenName); - return FALSE; - } - conf_screen = s; - from = X_CMDLINE; - } - - /* We have exactly one screen */ - - slp = xnfcalloc(1, 2 * sizeof(screenLayoutRec)); - slp[0].screen = xnfcalloc(1, sizeof(confScreenRec)); - slp[1].screen = NULL; - if (!configScreen(slp[0].screen, conf_screen, 0, from)) { - xfree(slp); - return FALSE; - } - servlayoutp->id = "(implicit)"; - servlayoutp->screens = slp; - servlayoutp->inactives = xnfcalloc(1, sizeof(GDevRec)); - servlayoutp->options = NULL; - - memset(&layout, 0, sizeof(layout)); - layout.lay_identifier = servlayoutp->id; - if (xf86layoutAddInputDevices(xf86configptr, &layout) > 0) { - if (!configInputDevices(&layout, servlayoutp)) - return FALSE; - from = X_DEFAULT; - } else { - /* Set up an empty input device list, then look for some core devices. */ - indp = xnfalloc(sizeof(IDevPtr)); - *indp = NULL; - servlayoutp->inputs = indp; - } - - return TRUE; -} - -static Bool -configXvAdaptor(confXvAdaptorPtr adaptor, XF86ConfVideoAdaptorPtr conf_adaptor) -{ - int count = 0; - XF86ConfVideoPortPtr conf_port; - - xf86Msg(X_CONFIG, "| |-->VideoAdaptor \"%s\"\n", - conf_adaptor->va_identifier); - adaptor->identifier = conf_adaptor->va_identifier; - adaptor->options = conf_adaptor->va_option_lst; - if (conf_adaptor->va_busid || conf_adaptor->va_driver) { - xf86Msg(X_CONFIG, "| | Unsupported device type, skipping entry\n"); - return FALSE; - } - - /* - * figure out how many videoport subsections there are and fill them in - */ - conf_port = conf_adaptor->va_port_lst; - while(conf_port) { - count++; - conf_port = (XF86ConfVideoPortPtr)conf_port->list.next; - } - adaptor->ports = xnfalloc((count) * sizeof(confXvPortRec)); - adaptor->numports = count; - count = 0; - conf_port = conf_adaptor->va_port_lst; - while(conf_port) { - adaptor->ports[count].identifier = conf_port->vp_identifier; - adaptor->ports[count].options = conf_port->vp_option_lst; - count++; - conf_port = (XF86ConfVideoPortPtr)conf_port->list.next; - } - - return TRUE; -} - -static Bool -configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, int scrnum, - MessageType from) -{ - int count = 0; - XF86ConfDisplayPtr dispptr; - XF86ConfAdaptorLinkPtr conf_adaptor; - Bool defaultMonitor = FALSE; - - if (!conf_screen) { - conf_screen = xnfcalloc(1, sizeof(XF86ConfScreenRec)); - conf_screen->scrn_identifier = "Default Screen Section"; - xf86Msg(X_DEFAULT, "No screen section available. Using defaults.\n"); - } - - xf86Msg(from, "|-->Screen \"%s\" (%d)\n", conf_screen->scrn_identifier, - scrnum); - /* - * now we fill in the elements of the screen - */ - screenp->id = conf_screen->scrn_identifier; - screenp->screennum = scrnum; - screenp->defaultdepth = conf_screen->scrn_defaultdepth; - screenp->defaultbpp = conf_screen->scrn_defaultbpp; - screenp->defaultfbbpp = conf_screen->scrn_defaultfbbpp; - screenp->monitor = xnfcalloc(1, sizeof(MonRec)); - /* If no monitor is specified, create a default one. */ - if (!conf_screen->scrn_monitor) { - XF86ConfMonitorRec defMon; - - bzero(&defMon, sizeof(defMon)); - defMon.mon_identifier = "<default monitor>"; - if (!configMonitor(screenp->monitor, &defMon)) - return FALSE; - defaultMonitor = TRUE; - } else { - if (!configMonitor(screenp->monitor,conf_screen->scrn_monitor)) - return FALSE; - } - /* Configure the device. If there isn't one configured, attach to the - * first inactive one that we can configure. If there's none that work, - * set it to NULL so that the section can be autoconfigured later */ - screenp->device = xnfcalloc(1, sizeof(GDevRec)); - if ((!conf_screen->scrn_device) && (xf86configptr->conf_device_lst)) { - conf_screen->scrn_device = xf86configptr->conf_device_lst; - xf86Msg(X_DEFAULT, "No device specified for screen \"%s\".\n" - "\tUsing the first device section listed.\n", screenp->id); - } - if (configDevice(screenp->device,conf_screen->scrn_device, TRUE)) { - screenp->device->myScreenSection = screenp; - } else { - screenp->device = NULL; - } - screenp->options = conf_screen->scrn_option_lst; - - /* - * figure out how many display subsections there are and fill them in - */ - dispptr = conf_screen->scrn_display_lst; - while(dispptr) { - count++; - dispptr = (XF86ConfDisplayPtr)dispptr->list.next; - } - screenp->displays = xnfalloc((count) * sizeof(DispRec)); - screenp->numdisplays = count; - - /* Fill in the default Virtual size, if any */ - if (conf_screen->scrn_virtualX && conf_screen->scrn_virtualY) { - for (count = 0, dispptr = conf_screen->scrn_display_lst; - dispptr; - dispptr = (XF86ConfDisplayPtr)dispptr->list.next, count++) { - screenp->displays[count].virtualX = conf_screen->scrn_virtualX; - screenp->displays[count].virtualY = conf_screen->scrn_virtualY; - } - } - - /* Now do the per-Display Virtual sizes */ - count = 0; - dispptr = conf_screen->scrn_display_lst; - while(dispptr) { - configDisplay(&(screenp->displays[count]),dispptr); - count++; - dispptr = (XF86ConfDisplayPtr)dispptr->list.next; - } - - /* - * figure out how many videoadaptor references there are and fill them in - */ - conf_adaptor = conf_screen->scrn_adaptor_lst; - while(conf_adaptor) { - count++; - conf_adaptor = (XF86ConfAdaptorLinkPtr)conf_adaptor->list.next; - } - screenp->xvadaptors = xnfalloc((count) * sizeof(confXvAdaptorRec)); - screenp->numxvadaptors = 0; - conf_adaptor = conf_screen->scrn_adaptor_lst; - while(conf_adaptor) { - if (configXvAdaptor(&(screenp->xvadaptors[screenp->numxvadaptors]), - conf_adaptor->al_adaptor)) - screenp->numxvadaptors++; - conf_adaptor = (XF86ConfAdaptorLinkPtr)conf_adaptor->list.next; - } - - if (defaultMonitor) { - xf86Msg(X_DEFAULT, "No monitor specified for screen \"%s\".\n" - "\tUsing a default monitor configuration.\n", screenp->id); - } - return TRUE; -} - -typedef enum { - MON_REDUCEDBLANKING, - MON_MAX_PIX_CLOCK, -} MonitorValues; - -static OptionInfoRec MonitorOptions[] = { - { MON_REDUCEDBLANKING, "ReducedBlanking", OPTV_BOOLEAN, - {0}, FALSE }, - { MON_MAX_PIX_CLOCK, "MaxPixClock", OPTV_FREQ, - {0}, FALSE }, - { -1, NULL, OPTV_NONE, - {0}, FALSE }, -}; - -static Bool -configMonitor(MonPtr monitorp, XF86ConfMonitorPtr conf_monitor) -{ - int count; - DisplayModePtr mode,last = NULL; - XF86ConfModeLinePtr cmodep; - XF86ConfModesPtr modes; - XF86ConfModesLinkPtr modeslnk = conf_monitor->mon_modes_sect_lst; - Gamma zeros = {0.0, 0.0, 0.0}; - float badgamma = 0.0; - double maxPixClock; - - xf86Msg(X_CONFIG, "| |-->Monitor \"%s\"\n", - conf_monitor->mon_identifier); - monitorp->id = conf_monitor->mon_identifier; - monitorp->vendor = conf_monitor->mon_vendor; - monitorp->model = conf_monitor->mon_modelname; - monitorp->Modes = NULL; - monitorp->Last = NULL; - monitorp->gamma = zeros; - monitorp->widthmm = conf_monitor->mon_width; - monitorp->heightmm = conf_monitor->mon_height; - monitorp->reducedblanking = FALSE; - monitorp->maxPixClock = 0; - monitorp->options = conf_monitor->mon_option_lst; - - /* - * fill in the monitor structure - */ - for( count = 0 ; - count < conf_monitor->mon_n_hsync && count < MAX_HSYNC; - count++) { - monitorp->hsync[count].hi = conf_monitor->mon_hsync[count].hi; - monitorp->hsync[count].lo = conf_monitor->mon_hsync[count].lo; - } - monitorp->nHsync = count; - for( count = 0 ; - count < conf_monitor->mon_n_vrefresh && count < MAX_VREFRESH; - count++) { - monitorp->vrefresh[count].hi = conf_monitor->mon_vrefresh[count].hi; - monitorp->vrefresh[count].lo = conf_monitor->mon_vrefresh[count].lo; - } - monitorp->nVrefresh = count; - - /* - * first we collect the mode lines from the UseModes directive - */ - while(modeslnk) - { - modes = xf86findModes (modeslnk->ml_modes_str, - xf86configptr->conf_modes_lst); - modeslnk->ml_modes = modes; - - - /* now add the modes found in the modes - section to the list of modes for this - monitor unless it has been added before - because we are reusing the same section - for another screen */ - if (xf86itemNotSublist( - (GenericListPtr)conf_monitor->mon_modeline_lst, - (GenericListPtr)modes->mon_modeline_lst)) { - conf_monitor->mon_modeline_lst = (XF86ConfModeLinePtr) - xf86addListItem( - (GenericListPtr)conf_monitor->mon_modeline_lst, - (GenericListPtr)modes->mon_modeline_lst); - } - modeslnk = modeslnk->list.next; - } - - /* - * we need to hook in the mode lines now - * here both data structures use lists, only our internal one - * is double linked - */ - cmodep = conf_monitor->mon_modeline_lst; - while( cmodep ) { - mode = xnfcalloc(1, sizeof(DisplayModeRec)); - mode->type = 0; - mode->Clock = cmodep->ml_clock; - mode->HDisplay = cmodep->ml_hdisplay; - mode->HSyncStart = cmodep->ml_hsyncstart; - mode->HSyncEnd = cmodep->ml_hsyncend; - mode->HTotal = cmodep->ml_htotal; - mode->VDisplay = cmodep->ml_vdisplay; - mode->VSyncStart = cmodep->ml_vsyncstart; - mode->VSyncEnd = cmodep->ml_vsyncend; - mode->VTotal = cmodep->ml_vtotal; - mode->Flags = cmodep->ml_flags; - mode->HSkew = cmodep->ml_hskew; - mode->VScan = cmodep->ml_vscan; - mode->name = xnfstrdup(cmodep->ml_identifier); - if( last ) { - mode->prev = last; - last->next = mode; - } - else { - /* - * this is the first mode - */ - monitorp->Modes = mode; - mode->prev = NULL; - } - last = mode; - cmodep = (XF86ConfModeLinePtr)cmodep->list.next; - } - if(last){ - last->next = NULL; - } - monitorp->Last = last; - - /* add the (VESA) default modes */ - if (! addDefaultModes(monitorp) ) - return FALSE; - - if (conf_monitor->mon_gamma_red > GAMMA_ZERO) - monitorp->gamma.red = conf_monitor->mon_gamma_red; - if (conf_monitor->mon_gamma_green > GAMMA_ZERO) - monitorp->gamma.green = conf_monitor->mon_gamma_green; - if (conf_monitor->mon_gamma_blue > GAMMA_ZERO) - monitorp->gamma.blue = conf_monitor->mon_gamma_blue; - - /* Check that the gamma values are within range */ - if (monitorp->gamma.red > GAMMA_ZERO && - (monitorp->gamma.red < GAMMA_MIN || - monitorp->gamma.red > GAMMA_MAX)) { - badgamma = monitorp->gamma.red; - } else if (monitorp->gamma.green > GAMMA_ZERO && - (monitorp->gamma.green < GAMMA_MIN || - monitorp->gamma.green > GAMMA_MAX)) { - badgamma = monitorp->gamma.green; - } else if (monitorp->gamma.blue > GAMMA_ZERO && - (monitorp->gamma.blue < GAMMA_MIN || - monitorp->gamma.blue > GAMMA_MAX)) { - badgamma = monitorp->gamma.blue; - } - if (badgamma > GAMMA_ZERO) { - xf86ConfigError("Gamma value %.f is out of range (%.2f - %.1f)\n", - badgamma, GAMMA_MIN, GAMMA_MAX); - return FALSE; - } - - xf86ProcessOptions(-1, monitorp->options, MonitorOptions); - xf86GetOptValBool(MonitorOptions, MON_REDUCEDBLANKING, - &monitorp->reducedblanking); - if (xf86GetOptValFreq(MonitorOptions, MON_MAX_PIX_CLOCK, OPTUNITS_KHZ, - &maxPixClock) == TRUE) { - monitorp->maxPixClock = (int) maxPixClock; - } - - return TRUE; -} - -static int -lookupVisual(const char *visname) -{ - int i; - - if (!visname || !*visname) - return -1; - - for (i = 0; i <= DirectColor; i++) { - if (!xf86nameCompare(visname, xf86VisualNames[i])) - break; - } - - if (i <= DirectColor) - return i; - - return -1; -} - - -static Bool -configDisplay(DispPtr displayp, XF86ConfDisplayPtr conf_display) -{ - int count = 0; - XF86ModePtr modep; - - displayp->frameX0 = conf_display->disp_frameX0; - displayp->frameY0 = conf_display->disp_frameY0; - displayp->virtualX = conf_display->disp_virtualX; - displayp->virtualY = conf_display->disp_virtualY; - displayp->depth = conf_display->disp_depth; - displayp->fbbpp = conf_display->disp_bpp; - displayp->weight.red = conf_display->disp_weight.red; - displayp->weight.green = conf_display->disp_weight.green; - displayp->weight.blue = conf_display->disp_weight.blue; - displayp->blackColour.red = conf_display->disp_black.red; - displayp->blackColour.green = conf_display->disp_black.green; - displayp->blackColour.blue = conf_display->disp_black.blue; - displayp->whiteColour.red = conf_display->disp_white.red; - displayp->whiteColour.green = conf_display->disp_white.green; - displayp->whiteColour.blue = conf_display->disp_white.blue; - displayp->options = conf_display->disp_option_lst; - if (conf_display->disp_visual) { - displayp->defaultVisual = lookupVisual(conf_display->disp_visual); - if (displayp->defaultVisual == -1) { - xf86ConfigError("Invalid visual name: \"%s\"", - conf_display->disp_visual); - return FALSE; - } - } else { - displayp->defaultVisual = -1; - } - - /* - * now hook in the modes - */ - modep = conf_display->disp_mode_lst; - while(modep) { - count++; - modep = (XF86ModePtr)modep->list.next; - } - displayp->modes = xnfalloc((count+1) * sizeof(char*)); - modep = conf_display->disp_mode_lst; - count = 0; - while(modep) { - displayp->modes[count] = modep->mode_name; - count++; - modep = (XF86ModePtr)modep->list.next; - } - displayp->modes[count] = NULL; - - return TRUE; -} - -static Bool -configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device, Bool active) -{ - int i; - - if (!conf_device) { - return FALSE; - } - - if (active) - xf86Msg(X_CONFIG, "| |-->Device \"%s\"\n", - conf_device->dev_identifier); - else - xf86Msg(X_CONFIG, "|-->Inactive Device \"%s\"\n", - conf_device->dev_identifier); - - devicep->identifier = conf_device->dev_identifier; - devicep->vendor = conf_device->dev_vendor; - devicep->board = conf_device->dev_board; - devicep->chipset = conf_device->dev_chipset; - devicep->ramdac = conf_device->dev_ramdac; - devicep->driver = conf_device->dev_driver; - devicep->active = active; - devicep->videoRam = conf_device->dev_videoram; - devicep->BiosBase = conf_device->dev_bios_base; - devicep->MemBase = conf_device->dev_mem_base; - devicep->IOBase = conf_device->dev_io_base; - devicep->clockchip = conf_device->dev_clockchip; - devicep->busID = conf_device->dev_busid; - devicep->textClockFreq = conf_device->dev_textclockfreq; - devicep->chipID = conf_device->dev_chipid; - devicep->chipRev = conf_device->dev_chiprev; - devicep->options = conf_device->dev_option_lst; - devicep->irq = conf_device->dev_irq; - devicep->screen = conf_device->dev_screen; - - for (i = 0; i < MAXDACSPEEDS; i++) { - if (i < CONF_MAXDACSPEEDS) - devicep->dacSpeeds[i] = conf_device->dev_dacSpeeds[i]; - else - devicep->dacSpeeds[i] = 0; - } - devicep->numclocks = conf_device->dev_clocks; - if (devicep->numclocks > MAXCLOCKS) - devicep->numclocks = MAXCLOCKS; - for (i = 0; i < devicep->numclocks; i++) { - devicep->clock[i] = conf_device->dev_clock[i]; - } - devicep->claimed = FALSE; - - return TRUE; -} - -#ifdef XF86DRI -static void -configDRI(XF86ConfDRIPtr drip) -{ - int count = 0; - XF86ConfBuffersPtr bufs; - int i; - struct group *grp; - - xf86ConfigDRI.group = -1; - xf86ConfigDRI.mode = 0; - xf86ConfigDRI.bufs_count = 0; - xf86ConfigDRI.bufs = NULL; - - if (drip) { - if (drip->dri_group_name) { - if ((grp = getgrnam(drip->dri_group_name))) - xf86ConfigDRI.group = grp->gr_gid; - } else { - if (drip->dri_group >= 0) - xf86ConfigDRI.group = drip->dri_group; - } - xf86ConfigDRI.mode = drip->dri_mode; - for (bufs = drip->dri_buffers_lst; bufs; bufs = bufs->list.next) - ++count; - - xf86ConfigDRI.bufs_count = count; - xf86ConfigDRI.bufs = xnfalloc(count * sizeof(*xf86ConfigDRI.bufs)); - - for (i = 0, bufs = drip->dri_buffers_lst; - i < count; - i++, bufs = bufs->list.next) { - - xf86ConfigDRI.bufs[i].count = bufs->buf_count; - xf86ConfigDRI.bufs[i].size = bufs->buf_size; - /* FIXME: Flags not implemented. These - could be used, for example, to specify a - contiguous block and/or write-combining - cache policy. */ - xf86ConfigDRI.bufs[i].flags = 0; - } - } -} -#endif - -static void -configExtensions(XF86ConfExtensionsPtr conf_ext) -{ - XF86OptionPtr o; - - if (conf_ext && conf_ext->ext_option_lst) { - for (o = conf_ext->ext_option_lst; o; o = xf86NextOption(o)) { - char *name = xf86OptionName(o); - char *val = xf86OptionValue(o); - char *n; - Bool enable = TRUE; - - /* Handle "No<ExtensionName>" */ - n = xf86NormalizeName(name); - if (strncmp(n, "no", 2) == 0) { - name += 2; - enable = FALSE; - } - - if (!val || - xf86NameCmp(val, "enable") == 0 || - xf86NameCmp(val, "enabled") == 0 || - xf86NameCmp(val, "on") == 0 || - xf86NameCmp(val, "1") == 0 || - xf86NameCmp(val, "yes") == 0 || - xf86NameCmp(val, "true") == 0) { - /* NOTHING NEEDED -- enabling is handled below */ - } else if (xf86NameCmp(val, "disable") == 0 || - xf86NameCmp(val, "disabled") == 0 || - xf86NameCmp(val, "off") == 0 || - xf86NameCmp(val, "0") == 0 || - xf86NameCmp(val, "no") == 0 || - xf86NameCmp(val, "false") == 0) { - enable = !enable; - } else { - xf86Msg(X_WARNING, "Ignoring unrecognized value \"%s\"\n", val); - xfree(n); - continue; - } - - if (EnableDisableExtension(name, enable)) { - xf86Msg(X_CONFIG, "Extension \"%s\" is %s\n", - name, enable ? "enabled" : "disabled"); - } else { - xf86Msg(X_WARNING, "Ignoring unrecognized extension \"%s\"\n", - name); - } - xfree(n); - } - } -} - -static Bool -configInput(IDevPtr inputp, XF86ConfInputPtr conf_input, MessageType from) -{ - xf86Msg(from, "|-->Input Device \"%s\"\n", conf_input->inp_identifier); - inputp->identifier = conf_input->inp_identifier; - inputp->driver = conf_input->inp_driver; - inputp->commonOptions = conf_input->inp_option_lst; - inputp->extraOptions = NULL; - - return TRUE; -} - -static Bool -modeIsPresent(DisplayModePtr mode, MonPtr monitorp) -{ - DisplayModePtr knownmodes = monitorp->Modes; - - /* all I can think of is a linear search... */ - while(knownmodes != NULL) - { - if(!strcmp(mode->name, knownmodes->name) && - !(knownmodes->type & M_T_DEFAULT)) - return TRUE; - knownmodes = knownmodes->next; - } - return FALSE; -} - -static Bool -addDefaultModes(MonPtr monitorp) -{ - DisplayModePtr mode; - DisplayModePtr last = monitorp->Last; - int i = 0; - - for (i = 0; i < xf86NumDefaultModes; i++) - { - mode = xf86DuplicateMode(&xf86DefaultModes[i]); - if (!modeIsPresent(mode, monitorp)) - { - monitorp->Modes = xf86ModesAdd(monitorp->Modes, mode); - last = mode; - } else { - xfree(mode); - } - } - monitorp->Last = last; - - return TRUE; -} - -static void -checkInput(serverLayoutPtr layout, Bool implicit_layout) { - checkCoreInputDevices(layout, implicit_layout); - - /* AllowEmptyInput and the "kbd" and "mouse" drivers are mutually - * exclusive. Trawl the list for mouse/kbd devices and disable them. - */ - if (xf86Info.allowEmptyInput && layout->inputs) - { - IDevPtr *dev = layout->inputs; - BOOL warned = FALSE; - - while(*dev) - { - if (strcmp((*dev)->driver, "kbd") == 0 || - strcmp((*dev)->driver, "mouse") == 0 || - strcmp((*dev)->driver, "vmmouse") == 0) - { - IDevPtr *current; - if (!warned) - { - xf86Msg(X_WARNING, "AllowEmptyInput is on, devices using " - "drivers 'kbd', 'mouse' or 'vmmouse' will be disabled.\n"); - warned = TRUE; - } - - xf86Msg(X_WARNING, "Disabling %s\n", (*dev)->identifier); - - current = dev; - xfree(*dev); - - do { - *current = *(current + 1); - current++; - } while(*current); - } else - dev++; - } - } -} - -/* - * load the config file and fill the global data structure - */ -ConfigStatus -xf86HandleConfigFile(Bool autoconfig) -{ - const char *filename, *dirname, *sysdirname; - char *filesearch, *dirsearch; - MessageType filefrom = X_DEFAULT; - MessageType dirfrom = X_DEFAULT; - char *scanptr; - Bool singlecard = 0; - Bool implicit_layout = FALSE; - - if (!autoconfig) { - if (getuid() == 0) { - filesearch = ROOT_CONFIGPATH; - dirsearch = ROOT_CONFIGDIRPATH; - } else { - filesearch = USER_CONFIGPATH; - dirsearch = USER_CONFIGDIRPATH; - } - - if (xf86ConfigFile) - filefrom = X_CMDLINE; - if (xf86ConfigDir) - dirfrom = X_CMDLINE; - - xf86initConfigFiles(); - sysdirname = xf86openConfigDirFiles(SYS_CONFIGDIRPATH, NULL, - PROJECTROOT); - dirname = xf86openConfigDirFiles(dirsearch, xf86ConfigDir, PROJECTROOT); - filename = xf86openConfigFile(filesearch, xf86ConfigFile, PROJECTROOT); - if (filename) { - xf86MsgVerb(filefrom, 0, "Using config file: \"%s\"\n", filename); - xf86ConfigFile = xnfstrdup(filename); - } else { - if (xf86ConfigFile) - xf86Msg(X_ERROR, "Unable to locate/open config file: \"%s\"\n", - xf86ConfigFile); - } - if (dirname) { - xf86MsgVerb(dirfrom, 0, "Using config directory: \"%s\"\n", - dirname); - xf86ConfigDir = xnfstrdup(dirname); - } else { - if (xf86ConfigDir) - xf86Msg(X_ERROR, - "Unable to locate/open config directory: \"%s\"\n", - xf86ConfigDir); - } - if (sysdirname) - xf86MsgVerb(X_DEFAULT, 0, "Using system config directory \"%s\"\n", - sysdirname); - if (!filename && !dirname && !sysdirname) - return CONFIG_NOFILE; - } - - if ((xf86configptr = xf86readConfigFile ()) == NULL) { - xf86Msg(X_ERROR, "Problem parsing the config file\n"); - return CONFIG_PARSE_ERROR; - } - xf86closeConfigFile (); - - /* Initialise a few things. */ - - /* - * now we convert part of the information contained in the parser - * structures into our own structures. - * The important part here is to figure out which Screen Sections - * in the XF86Config file are active so that we can piece together - * the modes that we need later down the road. - * And while we are at it, we'll decode the rest of the stuff as well - */ - - /* First check if a layout section is present, and if it is valid. */ - - if (xf86configptr->conf_layout_lst == NULL || xf86ScreenName != NULL) { - if (xf86ScreenName == NULL) { - xf86Msg(X_DEFAULT, - "No Layout section. Using the first Screen section.\n"); - } - if (!configImpliedLayout(&xf86ConfigLayout, - xf86configptr->conf_screen_lst, - xf86configptr)) { - xf86Msg(X_ERROR, "Unable to determine the screen layout\n"); - return CONFIG_PARSE_ERROR; - } - implicit_layout = TRUE; - } else { - if (xf86configptr->conf_flags != NULL) { - char *dfltlayout = NULL; - pointer optlist = xf86configptr->conf_flags->flg_option_lst; - - if (optlist && xf86FindOption(optlist, "defaultserverlayout")) - dfltlayout = xf86SetStrOption(optlist, "defaultserverlayout", NULL); - if (!configLayout(&xf86ConfigLayout, xf86configptr->conf_layout_lst, - dfltlayout)) { - xf86Msg(X_ERROR, "Unable to determine the screen layout\n"); - return CONFIG_PARSE_ERROR; - } - } else { - if (!configLayout(&xf86ConfigLayout, xf86configptr->conf_layout_lst, - NULL)) { - xf86Msg(X_ERROR, "Unable to determine the screen layout\n"); - return CONFIG_PARSE_ERROR; - } - } - } - - xf86ProcessOptions(-1, xf86ConfigLayout.options, LayoutOptions); - - if ((scanptr = xf86GetOptValString(LayoutOptions, LAYOUT_ISOLATEDEVICE))) { - ; /* IsolateDevice specified; overrides SingleCard */ - } else { - xf86GetOptValBool(LayoutOptions, LAYOUT_SINGLECARD, &singlecard); - if (singlecard) - scanptr = xf86ConfigLayout.screens->screen->device->busID; - } - if (scanptr) { - int bus, device, func; - if (strncmp(scanptr, "PCI:", 4) != 0) { - xf86Msg(X_WARNING, "Bus types other than PCI not yet isolable.\n" - "\tIgnoring IsolateDevice option.\n"); - } else if (sscanf(scanptr, "PCI:%d:%d:%d", &bus, &device, &func) == 3) { - xf86IsolateDevice.domain = PCI_DOM_FROM_BUS(bus); - xf86IsolateDevice.bus = PCI_BUS_NO_DOMAIN(bus); - xf86IsolateDevice.dev = device; - xf86IsolateDevice.func = func; - xf86Msg(X_INFO, - "Isolating PCI bus \"%d:%d:%d\"\n", bus, device, func); - } - } - - /* Now process everything else */ - if (!configServerFlags(xf86configptr->conf_flags,xf86ConfigLayout.options)){ - ErrorF ("Problem when converting the config data structures\n"); - return CONFIG_PARSE_ERROR; - } - - configFiles(xf86configptr->conf_files); - configExtensions(xf86configptr->conf_extensions); -#ifdef XF86DRI - configDRI(xf86configptr->conf_dri); -#endif - - checkInput(&xf86ConfigLayout, implicit_layout); - - /* - * Handle some command line options that can override some of the - * ServerFlags settings. - */ -#ifdef XF86VIDMODE - if (xf86VidModeDisabled) - xf86Info.vidModeEnabled = FALSE; - if (xf86VidModeAllowNonLocal) - xf86Info.vidModeAllowNonLocal = TRUE; -#endif - - if (xf86AllowMouseOpenFail) - xf86Info.allowMouseOpenFail = TRUE; - - return CONFIG_OK; -} - -Bool -xf86PathIsSafe(const char *path) -{ - return (xf86pathIsSafe(path) != 0); -} +/* + * Loosely based on code bearing the following copyright: + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + */ + +/* + * Copyright 1992-2003 by The XFree86 Project, Inc. + * Copyright 1997 by Metro Link, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * + * Authors: + * Dirk Hohndel <hohndel@XFree86.Org> + * David Dawes <dawes@XFree86.Org> + * Marc La France <tsi@XFree86.Org> + * Egbert Eich <eich@XFree86.Org> + * ... and others + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifdef XF86DRI +#include <sys/types.h> +#include <grp.h> +#endif + +#include "xf86.h" +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "xf86Config.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#include "configProcs.h" +#include "globals.h" +#include "extension.h" +#include "Pci.h" + +#include "xf86Xinput.h" +extern DeviceAssocRec mouse_assoc; + +#include "xkbsrv.h" + +#include "picture.h" + +/* + * These paths define the way the config file search is done. The escape + * sequences are documented in parser/scan.c. + */ +#ifndef ROOT_CONFIGPATH +#define ROOT_CONFIGPATH "%A," "%R," \ + "/etc/X11/%R," "%P/etc/X11/%R," \ + "%E," "%F," \ + "/etc/X11/%F," "%P/etc/X11/%F," \ + "/etc/X11/%X-%M," "/etc/X11/%X," "/etc/%X," \ + "%P/etc/X11/%X.%H," "%P/etc/X11/%X-%M," \ + "%P/etc/X11/%X," \ + "%P/lib/X11/%X.%H," "%P/lib/X11/%X-%M," \ + "%P/lib/X11/%X" +#endif +#ifndef USER_CONFIGPATH +#define USER_CONFIGPATH "/etc/X11/%S," "%P/etc/X11/%S," \ + "/etc/X11/%G," "%P/etc/X11/%G," \ + "/etc/X11/%X-%M," "/etc/X11/%X," "/etc/%X," \ + "%P/etc/X11/%X.%H," "%P/etc/X11/%X-%M," \ + "%P/etc/X11/%X," \ + "%P/lib/X11/%X.%H," "%P/lib/X11/%X-%M," \ + "%P/lib/X11/%X" +#endif +#ifndef ROOT_CONFIGDIRPATH +#define ROOT_CONFIGDIRPATH "%A," "%R," \ + "/etc/X11/%R," "%C/X11/%R," \ + "/etc/X11/%X," "%C/X11/%X" +#endif +#ifndef USER_CONFIGDIRPATH +#define USER_CONFIGDIRPATH "/etc/X11/%R," "%C/X11/%R," \ + "/etc/X11/%X," "%C/X11/%X" +#endif +#ifndef SYS_CONFIGDIRPATH +#define SYS_CONFIGDIRPATH "/usr/share/X11/%X," "%D/X11/%X" +#endif +#ifndef PROJECTROOT +#define PROJECTROOT "/usr/X11R6" +#endif + +static ModuleDefault ModuleDefaults[] = { + {.name = "extmod", .toLoad = TRUE, .load_opt=NULL}, +#ifdef DBE + {.name = "dbe", .toLoad = TRUE, .load_opt=NULL}, +#endif +#ifdef GLXEXT + {.name = "glx", .toLoad = TRUE, .load_opt=NULL}, +#endif +#ifdef XRECORD + {.name = "record", .toLoad = TRUE, .load_opt=NULL}, +#endif +#ifdef XF86DRI + {.name = "dri", .toLoad = TRUE, .load_opt=NULL}, +#endif +#ifdef DRI2 + {.name = "dri2", .toLoad = TRUE, .load_opt=NULL}, +#endif + {.name = NULL, .toLoad = FALSE, .load_opt=NULL} +}; + + +/* Forward declarations */ +static Bool configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, + int scrnum, MessageType from); +static Bool configMonitor(MonPtr monitorp, XF86ConfMonitorPtr conf_monitor); +static Bool configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device, + Bool active); +static Bool configInput(IDevPtr inputp, XF86ConfInputPtr conf_input, + MessageType from); +static Bool configDisplay(DispPtr displayp, XF86ConfDisplayPtr conf_display); +static Bool addDefaultModes(MonPtr monitorp); +#ifdef XF86DRI +static void configDRI(XF86ConfDRIPtr drip); +#endif +static void configExtensions(XF86ConfExtensionsPtr conf_ext); + +/* + * xf86GetPathElem -- + * Extract a single element from the font path string starting at + * pnt. The font path element will be returned, and pnt will be + * updated to point to the start of the next element, or set to + * NULL if there are no more. + */ +static char * +xf86GetPathElem(char **pnt) +{ + char *p1; + + p1 = *pnt; + *pnt = index(*pnt, ','); + if (*pnt != NULL) { + **pnt = '\0'; + *pnt += 1; + } + return(p1); +} + +/* + * xf86ValidateFontPath -- + * Validates the user-specified font path. Each element that + * begins with a '/' is checked to make sure the directory exists. + * If the directory exists, the existence of a file named 'fonts.dir' + * is checked. If either check fails, an error is printed and the + * element is removed from the font path. + */ + +#define DIR_FILE "/fonts.dir" +static char * +xf86ValidateFontPath(char *path) +{ + char *tmp_path, *out_pnt, *path_elem, *next, *p1, *dir_elem; + struct stat stat_buf; + int flag; + int dirlen; + + tmp_path = calloc(1,strlen(path)+1); + out_pnt = tmp_path; + path_elem = NULL; + next = path; + while (next != NULL) { + path_elem = xf86GetPathElem(&next); + if (*path_elem == '/') { + dir_elem = xnfcalloc(1, strlen(path_elem) + 1); + if ((p1 = strchr(path_elem, ':')) != 0) + dirlen = p1 - path_elem; + else + dirlen = strlen(path_elem); + strncpy(dir_elem, path_elem, dirlen); + dir_elem[dirlen] = '\0'; + flag = stat(dir_elem, &stat_buf); + if (flag == 0) + if (!S_ISDIR(stat_buf.st_mode)) + flag = -1; + if (flag != 0) { + xf86Msg(X_WARNING, "The directory \"%s\" does not exist.\n", dir_elem); + xf86ErrorF("\tEntry deleted from font path.\n"); + free(dir_elem); + continue; + } + else { + p1 = xnfalloc(strlen(dir_elem)+strlen(DIR_FILE)+1); + strcpy(p1, dir_elem); + strcat(p1, DIR_FILE); + flag = stat(p1, &stat_buf); + if (flag == 0) + if (!S_ISREG(stat_buf.st_mode)) + flag = -1; + free(p1); + if (flag != 0) { + xf86Msg(X_WARNING, + "`fonts.dir' not found (or not valid) in \"%s\".\n", + dir_elem); + xf86ErrorF("\tEntry deleted from font path.\n"); + xf86ErrorF("\t(Run 'mkfontdir' on \"%s\").\n", dir_elem); + free(dir_elem); + continue; + } + } + free(dir_elem); + } + + /* + * Either an OK directory, or a font server name. So add it to + * the path. + */ + if (out_pnt != tmp_path) + *out_pnt++ = ','; + strcat(out_pnt, path_elem); + out_pnt += strlen(path_elem); + } + return(tmp_path); +} + + +/* + * use the datastructure that the parser provides and pick out the parts + * that we need at this point + */ +char ** +xf86ModulelistFromConfig(pointer **optlist) +{ + int count = 0, i = 0; + char **modulearray; + char *ignore[] = { "GLcore", "speedo", "bitmap", "drm", + "freetype", "type1", + NULL }; + pointer *optarray; + XF86LoadPtr modp; + Bool found; + + /* + * make sure the config file has been parsed and that we have a + * ModulePath set; if no ModulePath was given, use the default + * ModulePath + */ + if (xf86configptr == NULL) { + xf86Msg(X_ERROR, "Cannot access global config data structure\n"); + return NULL; + } + + if (xf86configptr->conf_modules) { + /* Walk the disable list and let people know what we've parsed to + * not be loaded + */ + modp = xf86configptr->conf_modules->mod_disable_lst; + while (modp) { + xf86Msg(X_WARNING, "\"%s\" will not be loaded unless you've specified it to be loaded elsewhere.\n", modp->load_name); + modp = (XF86LoadPtr) modp->list.next; + } + /* + * Walk the default settings table. For each module listed to be + * loaded, make sure it's in the mod_load_lst. If it's not, make + * sure it's not in the mod_no_load_lst. If it's not disabled, + * append it to mod_load_lst + */ + for (i=0 ; ModuleDefaults[i].name != NULL ; i++) { + if (ModuleDefaults[i].toLoad == FALSE) { + xf86Msg(X_WARNING, "\"%s\" is not to be loaded by default. Skipping.\n", ModuleDefaults[i].name); + continue; + } + found = FALSE; + modp = xf86configptr->conf_modules->mod_load_lst; + while (modp) { + if (strcmp(modp->load_name, ModuleDefaults[i].name) == 0) { + xf86Msg(X_INFO, "\"%s\" will be loaded. This was enabled by default and also specified in the config file.\n", ModuleDefaults[i].name); + found = TRUE; + break; + } + modp = (XF86LoadPtr) modp->list.next; + } + if (found == FALSE) { + modp = xf86configptr->conf_modules->mod_disable_lst; + while (modp) { + if (strcmp(modp->load_name, ModuleDefaults[i].name) == 0) { + xf86Msg(X_INFO, "\"%s\" will be loaded even though the default is to disable it.\n", ModuleDefaults[i].name); + found = TRUE; + break; + } + modp = (XF86LoadPtr) modp->list.next; + } + } + if (found == FALSE) { + XF86LoadPtr ptr = (XF86LoadPtr)xf86configptr->conf_modules; + ptr = xf86addNewLoadDirective(ptr, ModuleDefaults[i].name, XF86_LOAD_MODULE, ModuleDefaults[i].load_opt); + xf86Msg(X_INFO, "\"%s\" will be loaded by default.\n", ModuleDefaults[i].name); + } + } + } else { + xf86configptr->conf_modules = xnfcalloc(1, sizeof(XF86ConfModuleRec)); + for (i=0 ; ModuleDefaults[i].name != NULL ; i++) { + if (ModuleDefaults[i].toLoad == TRUE) { + XF86LoadPtr ptr = (XF86LoadPtr)xf86configptr->conf_modules; + ptr = xf86addNewLoadDirective(ptr, ModuleDefaults[i].name, XF86_LOAD_MODULE, ModuleDefaults[i].load_opt); + } + } + } + + /* + * Walk the list of modules in the "Module" section to determine how + * many we have. + */ + modp = xf86configptr->conf_modules->mod_load_lst; + while (modp) { + for (i = 0; ignore[i]; i++) { + if (strcmp(modp->load_name, ignore[i]) == 0) + modp->ignore = 1; + } + if (!modp->ignore) + count++; + modp = (XF86LoadPtr) modp->list.next; + } + + /* + * allocate the memory and walk the list again to fill in the pointers + */ + modulearray = xnfalloc((count + 1) * sizeof(char*)); + optarray = xnfalloc((count + 1) * sizeof(pointer)); + count = 0; + if (xf86configptr->conf_modules) { + modp = xf86configptr->conf_modules->mod_load_lst; + while (modp) { + if (!modp->ignore) { + modulearray[count] = modp->load_name; + optarray[count] = modp->load_opt; + count++; + } + modp = (XF86LoadPtr) modp->list.next; + } + } + modulearray[count] = NULL; + optarray[count] = NULL; + if (optlist) + *optlist = optarray; + else + free(optarray); + return modulearray; +} + + +char ** +xf86DriverlistFromConfig(void) +{ + int count = 0; + int j; + char **modulearray; + screenLayoutPtr slp; + + /* + * make sure the config file has been parsed and that we have a + * ModulePath set; if no ModulePath was given, use the default + * ModulePath + */ + if (xf86configptr == NULL) { + xf86Msg(X_ERROR, "Cannot access global config data structure\n"); + return NULL; + } + + /* + * Walk the list of driver lines in active "Device" sections to + * determine now many implicitly loaded modules there are. + * + */ + if (xf86ConfigLayout.screens) { + slp = xf86ConfigLayout.screens; + while ((slp++)->screen) { + count++; + } + } + + /* + * Handle the set of inactive "Device" sections. + */ + j = 0; + while (xf86ConfigLayout.inactives[j++].identifier) + count++; + + if (count == 0) + return NULL; + + /* + * allocate the memory and walk the list again to fill in the pointers + */ + modulearray = xnfalloc((count + 1) * sizeof(char*)); + count = 0; + slp = xf86ConfigLayout.screens; + while (slp->screen) { + modulearray[count] = slp->screen->device->driver; + count++; + slp++; + } + + j = 0; + + while (xf86ConfigLayout.inactives[j].identifier) + modulearray[count++] = xf86ConfigLayout.inactives[j++].driver; + + modulearray[count] = NULL; + + /* Remove duplicates */ + for (count = 0; modulearray[count] != NULL; count++) { + int i; + + for (i = 0; i < count; i++) + if (xf86NameCmp(modulearray[i], modulearray[count]) == 0) { + modulearray[count] = ""; + break; + } + } + return modulearray; +} + +char ** +xf86InputDriverlistFromConfig(void) +{ + int count = 0; + char **modulearray; + IDevPtr* idp; + + /* + * make sure the config file has been parsed and that we have a + * ModulePath set; if no ModulePath was given, use the default + * ModulePath + */ + if (xf86configptr == NULL) { + xf86Msg(X_ERROR, "Cannot access global config data structure\n"); + return NULL; + } + + /* + * Walk the list of driver lines in active "InputDevice" sections to + * determine now many implicitly loaded modules there are. + */ + if (xf86ConfigLayout.inputs) { + idp = xf86ConfigLayout.inputs; + while (*idp) { + count++; + idp++; + } + } + + if (count == 0) + return NULL; + + /* + * allocate the memory and walk the list again to fill in the pointers + */ + modulearray = xnfalloc((count + 1) * sizeof(char*)); + count = 0; + idp = xf86ConfigLayout.inputs; + while (idp && *idp) { + modulearray[count] = (*idp)->driver; + count++; + idp++; + } + modulearray[count] = NULL; + + /* Remove duplicates */ + for (count = 0; modulearray[count] != NULL; count++) { + int i; + + for (i = 0; i < count; i++) + if (xf86NameCmp(modulearray[i], modulearray[count]) == 0) { + modulearray[count] = ""; + break; + } + } + return modulearray; +} + +static void +fixup_video_driver_list(char **drivers) +{ + static const char *fallback[4] = { "vesa", "fbdev", "wsfb", NULL }; + char **end, **drv; + char *x; + char **ati, **atimisc; + int i; + + /* walk to the end of the list */ + for (end = drivers; *end && **end; end++) ; + end--; + + /* + * for each of the fallback drivers, if we find it in the list, + * swap it with the last available non-fallback driver. + */ + for (i = 0; fallback[i]; i++) { + for (drv = drivers; drv != end; drv++) { + if (strstr(*drv, fallback[i])) { + x = *drv; *drv = *end; *end = x; + end--; + break; + } + } + } + /* + * since the ati wrapper driver is gross and awful, sort ati before + * atimisc, which makes sure all the ati symbols are visible in xorgcfg. + */ + for (drv = drivers; drv != end; drv++) { + if (!strcmp(*drv, "atimisc")) { + atimisc = drv; + for (drv = atimisc; drv != end; drv++) { + if (!strcmp(*drv, "ati")) { + ati = drv; + x = *ati; *ati = *atimisc; *atimisc = x; + return; + } + } + /* if we get here, ati was already ahead of atimisc */ + return; + } + } +} + +static char ** +GenerateDriverlist(char * dirname) +{ + char **ret; + const char *subdirs[] = { dirname, NULL }; + static const char *patlist[] = {"(.*)_drv\\.so", "(.*)_drv\\.o", NULL}; + ret = LoaderListDirs(subdirs, patlist); + + /* fix up the probe order for video drivers */ + if (strstr(dirname, "drivers") && ret != NULL) + fixup_video_driver_list(ret); + + return ret; +} + +char ** +xf86DriverlistFromCompile(void) +{ + static char **driverlist = NULL; + + if (!driverlist) + driverlist = GenerateDriverlist("drivers"); + + return driverlist; +} + +/* + * xf86ConfigError -- + * Print a READABLE ErrorMessage!!! All information that is + * available is printed. + */ +static void +xf86ConfigError(char *msg, ...) +{ + va_list ap; + + ErrorF("\nConfig Error:\n"); + va_start(ap, msg); + VErrorF(msg, ap); + va_end(ap); + ErrorF("\n"); + return; +} + +static void +configFiles(XF86ConfFilesPtr fileconf) +{ + MessageType pathFrom; + Bool must_copy; + int size, countDirs; + char *temp_path, *log_buf, *start, *end; + + /* FontPath */ + must_copy = TRUE; + + temp_path = defaultFontPath ? defaultFontPath : ""; + if (xf86fpFlag) + pathFrom = X_CMDLINE; + else if (fileconf && fileconf->file_fontpath) { + pathFrom = X_CONFIG; + if (xf86Info.useDefaultFontPath) { + defaultFontPath = Xprintf("%s%s%s", + fileconf->file_fontpath, + *temp_path ? "," : "", temp_path); + if (defaultFontPath != NULL) { + must_copy = FALSE; + } + } + else + defaultFontPath = fileconf->file_fontpath; + } + else + pathFrom = X_DEFAULT; + temp_path = defaultFontPath ? defaultFontPath : ""; + + /* xf86ValidateFontPath modifies its argument, but returns a copy of it. */ + temp_path = must_copy ? xnfstrdup(defaultFontPath) : defaultFontPath; + defaultFontPath = xf86ValidateFontPath(temp_path); + free(temp_path); + + /* make fontpath more readable in the logfiles */ + countDirs = 1; + temp_path = defaultFontPath; + while ((temp_path = index(temp_path, ',')) != NULL) { + countDirs++; + temp_path++; + } + + log_buf = xnfalloc(strlen(defaultFontPath) + (2 * countDirs) + 1); + temp_path = log_buf; + start = defaultFontPath; + while((end = index(start, ',')) != NULL) { + size = (end - start) + 1; + *(temp_path++) = '\t'; + strncpy(temp_path, start, size); + temp_path += size; + *(temp_path++) = '\n'; + start += size; + } + /* copy last entry */ + *(temp_path++) = '\t'; + strcpy(temp_path, start); + xf86Msg(pathFrom, "FontPath set to:\n%s\n", log_buf); + free(log_buf); + + /* ModulePath */ + + if (fileconf) { + if (xf86ModPathFrom != X_CMDLINE && fileconf->file_modulepath) { + xf86ModulePath = fileconf->file_modulepath; + xf86ModPathFrom = X_CONFIG; + } + } + + xf86Msg(xf86ModPathFrom, "ModulePath set to \"%s\"\n", xf86ModulePath); + + if (!xf86xkbdirFlag && fileconf && fileconf->file_xkbdir) { + XkbBaseDirectory = fileconf->file_xkbdir; + xf86Msg(X_CONFIG, "XKB base directory set to \"%s\"\n", + XkbBaseDirectory); + } +#if 0 + /* LogFile */ + /* + * XXX The problem with this is that the log file is already open. + * One option might be to copy the exiting contents to the new location. + * and re-open it. The down side is that the default location would + * already have been overwritten. Another option would be to start with + * unique temporary location, then copy it once the correct name is known. + * A problem with this is what happens if the server exits before that + * happens. + */ + if (xf86LogFileFrom == X_DEFAULT && fileconf->file_logfile) { + xf86LogFile = fileconf->file_logfile; + xf86LogFileFrom = X_CONFIG; + } +#endif + + return; +} + +typedef enum { + FLAG_NOTRAPSIGNALS, + FLAG_DONTVTSWITCH, + FLAG_DONTZAP, + FLAG_DONTZOOM, + FLAG_DISABLEVIDMODE, + FLAG_ALLOWNONLOCAL, + FLAG_ALLOWMOUSEOPENFAIL, + FLAG_VTSYSREQ, + FLAG_SAVER_BLANKTIME, + FLAG_DPMS_STANDBYTIME, + FLAG_DPMS_SUSPENDTIME, + FLAG_DPMS_OFFTIME, + FLAG_PIXMAP, + FLAG_PC98, + FLAG_NOPM, + FLAG_XINERAMA, + FLAG_LOG, + FLAG_RENDER_COLORMAP_MODE, + FLAG_RANDR, + FLAG_AIGLX, + FLAG_IGNORE_ABI, + FLAG_ALLOW_EMPTY_INPUT, + FLAG_USE_DEFAULT_FONT_PATH, + FLAG_AUTO_ADD_DEVICES, + FLAG_AUTO_ENABLE_DEVICES, + FLAG_GLX_VISUALS, + FLAG_DRI2, + FLAG_USE_SIGIO +} FlagValues; + +/** + * NOTE: the last value for each entry is NOT the default. It is set to TRUE + * if the parser found the option in the config file. + */ +static OptionInfoRec FlagOptions[] = { + { FLAG_NOTRAPSIGNALS, "NoTrapSignals", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_DONTVTSWITCH, "DontVTSwitch", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_DONTZAP, "DontZap", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_DONTZOOM, "DontZoom", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_DISABLEVIDMODE, "DisableVidModeExtension", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_ALLOWNONLOCAL, "AllowNonLocalXvidtune", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_ALLOWMOUSEOPENFAIL, "AllowMouseOpenFail", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_VTSYSREQ, "VTSysReq", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_SAVER_BLANKTIME, "BlankTime" , OPTV_INTEGER, + {0}, FALSE }, + { FLAG_DPMS_STANDBYTIME, "StandbyTime", OPTV_INTEGER, + {0}, FALSE }, + { FLAG_DPMS_SUSPENDTIME, "SuspendTime", OPTV_INTEGER, + {0}, FALSE }, + { FLAG_DPMS_OFFTIME, "OffTime", OPTV_INTEGER, + {0}, FALSE }, + { FLAG_PIXMAP, "Pixmap", OPTV_INTEGER, + {0}, FALSE }, + { FLAG_PC98, "PC98", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_NOPM, "NoPM", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_XINERAMA, "Xinerama", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_LOG, "Log", OPTV_STRING, + {0}, FALSE }, + { FLAG_RENDER_COLORMAP_MODE, "RenderColormapMode", OPTV_STRING, + {0}, FALSE }, + { FLAG_RANDR, "RandR", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_AIGLX, "AIGLX", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_ALLOW_EMPTY_INPUT, "AllowEmptyInput", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_IGNORE_ABI, "IgnoreABI", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_USE_DEFAULT_FONT_PATH, "UseDefaultFontPath", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_AUTO_ADD_DEVICES, "AutoAddDevices", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_AUTO_ENABLE_DEVICES, "AutoEnableDevices", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_GLX_VISUALS, "GlxVisuals", OPTV_STRING, + {0}, FALSE }, + { FLAG_DRI2, "DRI2", OPTV_BOOLEAN, + {0}, FALSE }, + { FLAG_USE_SIGIO, "UseSIGIO", OPTV_BOOLEAN, + {0}, FALSE }, + { -1, NULL, OPTV_NONE, + {0}, FALSE }, +}; + +#ifdef SUPPORT_PC98 +static Bool +detectPC98(void) +{ + unsigned char buf[2]; + + if (xf86ReadBIOS(0xf8000, 0xe80, buf, 2) != 2) + return FALSE; + if ((buf[0] == 0x98) && (buf[1] == 0x21)) + return TRUE; + else + return FALSE; +} +#endif + +static Bool +configServerFlags(XF86ConfFlagsPtr flagsconf, XF86OptionPtr layoutopts) +{ + XF86OptionPtr optp, tmp; + int i; + Pix24Flags pix24 = Pix24DontCare; + Bool value; + MessageType from; + const char *s; + XkbRMLVOSet set; + /* Default options. */ + set.rules = "base"; + set.model = "pc105"; + set.layout = "us"; + set.variant = NULL; + set.options = NULL; + + /* + * Merge the ServerLayout and ServerFlags options. The former have + * precedence over the latter. + */ + optp = NULL; + if (flagsconf && flagsconf->flg_option_lst) + optp = xf86optionListDup(flagsconf->flg_option_lst); + if (layoutopts) { + tmp = xf86optionListDup(layoutopts); + if (optp) + optp = xf86optionListMerge(optp, tmp); + else + optp = tmp; + } + + xf86ProcessOptions(-1, optp, FlagOptions); + + xf86GetOptValBool(FlagOptions, FLAG_NOTRAPSIGNALS, &xf86Info.notrapSignals); + xf86GetOptValBool(FlagOptions, FLAG_DONTVTSWITCH, &xf86Info.dontVTSwitch); + xf86GetOptValBool(FlagOptions, FLAG_DONTZAP, &xf86Info.dontZap); + xf86GetOptValBool(FlagOptions, FLAG_DONTZOOM, &xf86Info.dontZoom); + + xf86GetOptValBool(FlagOptions, FLAG_IGNORE_ABI, &xf86Info.ignoreABI); + if (xf86Info.ignoreABI) { + xf86Msg(X_CONFIG, "Ignoring ABI Version\n"); + } + + if (xf86SIGIOSupported()) { + xf86Info.useSIGIO = xf86ReturnOptValBool(FlagOptions, FLAG_USE_SIGIO, USE_SIGIO_BY_DEFAULT); + if (xf86IsOptionSet(FlagOptions, FLAG_USE_SIGIO)) { + from = X_CONFIG; + } else { + from = X_DEFAULT; + } + if (!xf86Info.useSIGIO) { + xf86Msg(from, "Disabling SIGIO handlers for input devices\n"); + } else if (from == X_CONFIG) { + xf86Msg(from, "Enabling SIGIO handlers for input devices\n"); + } + } else { + xf86Info.useSIGIO = FALSE; + } + + if (xf86IsOptionSet(FlagOptions, FLAG_AUTO_ADD_DEVICES)) { + xf86GetOptValBool(FlagOptions, FLAG_AUTO_ADD_DEVICES, + &xf86Info.autoAddDevices); + from = X_CONFIG; + } + else { + from = X_DEFAULT; + } + xf86Msg(from, "%sutomatically adding devices\n", + xf86Info.autoAddDevices ? "A" : "Not a"); + + if (xf86IsOptionSet(FlagOptions, FLAG_AUTO_ENABLE_DEVICES)) { + xf86GetOptValBool(FlagOptions, FLAG_AUTO_ENABLE_DEVICES, + &xf86Info.autoEnableDevices); + from = X_CONFIG; + } + else { + from = X_DEFAULT; + } + xf86Msg(from, "%sutomatically enabling devices\n", + xf86Info.autoEnableDevices ? "A" : "Not a"); + + /* + * Set things up based on the config file information. Some of these + * settings may be overridden later when the command line options are + * checked. + */ +#ifdef XF86VIDMODE + if (xf86GetOptValBool(FlagOptions, FLAG_DISABLEVIDMODE, &value)) + xf86Info.vidModeEnabled = !value; + if (xf86GetOptValBool(FlagOptions, FLAG_ALLOWNONLOCAL, &value)) + xf86Info.vidModeAllowNonLocal = value; +#endif + + if (xf86GetOptValBool(FlagOptions, FLAG_ALLOWMOUSEOPENFAIL, &value)) + xf86Info.allowMouseOpenFail = value; + + if (xf86GetOptValBool(FlagOptions, FLAG_VTSYSREQ, &value)) { +#ifdef USE_VT_SYSREQ + xf86Info.vtSysreq = value; + xf86Msg(X_CONFIG, "VTSysReq %s\n", value ? "enabled" : "disabled"); +#else + if (value) + xf86Msg(X_WARNING, "VTSysReq is not supported on this OS\n"); +#endif + } + + xf86Info.pmFlag = TRUE; + if (xf86GetOptValBool(FlagOptions, FLAG_NOPM, &value)) + xf86Info.pmFlag = !value; + { + if ((s = xf86GetOptValString(FlagOptions, FLAG_LOG))) { + if (!xf86NameCmp(s,"flush")) { + xf86Msg(X_CONFIG, "Flushing logfile enabled\n"); + xf86Info.log = LogFlush; + LogSetParameter(XLOG_FLUSH, TRUE); + } else if (!xf86NameCmp(s,"sync")) { + xf86Msg(X_CONFIG, "Syncing logfile enabled\n"); + xf86Info.log = LogSync; + LogSetParameter(XLOG_FLUSH, TRUE); + LogSetParameter(XLOG_SYNC, TRUE); + } else { + xf86Msg(X_WARNING,"Unknown Log option\n"); + } + } + } + + { + if ((s = xf86GetOptValString(FlagOptions, FLAG_RENDER_COLORMAP_MODE))){ + int policy = PictureParseCmapPolicy (s); + if (policy == PictureCmapPolicyInvalid) + xf86Msg(X_WARNING, "Unknown colormap policy \"%s\"\n", s); + else + { + xf86Msg(X_CONFIG, "Render colormap policy set to %s\n", s); + PictureCmapPolicy = policy; + } + } + } + +#ifdef RANDR + xf86Info.disableRandR = FALSE; + xf86Info.randRFrom = X_DEFAULT; + if (xf86GetOptValBool(FlagOptions, FLAG_RANDR, &value)) { + xf86Info.disableRandR = !value; + xf86Info.randRFrom = X_CONFIG; + } +#endif + + xf86Info.aiglx = TRUE; + xf86Info.aiglxFrom = X_DEFAULT; + if (xf86GetOptValBool(FlagOptions, FLAG_AIGLX, &value)) { + xf86Info.aiglx = value; + xf86Info.aiglxFrom = X_CONFIG; + } + +#ifdef GLXEXT + xf86Info.glxVisuals = XF86_GlxVisualsTypical; + xf86Info.glxVisualsFrom = X_DEFAULT; + if ((s = xf86GetOptValString(FlagOptions, FLAG_GLX_VISUALS))) { + if (!xf86NameCmp(s, "minimal")) { + xf86Info.glxVisuals = XF86_GlxVisualsMinimal; + } else if (!xf86NameCmp(s, "typical")) { + xf86Info.glxVisuals = XF86_GlxVisualsTypical; + } else if (!xf86NameCmp(s, "all")) { + xf86Info.glxVisuals = XF86_GlxVisualsAll; + } else { + xf86Msg(X_WARNING,"Unknown GlxVisuals option\n"); + } + } + + if (xf86GetOptValBool(FlagOptions, FLAG_AIGLX, &value)) { + xf86Info.aiglx = value; + xf86Info.aiglxFrom = X_CONFIG; + } +#endif + + /* AllowEmptyInput is automatically true if we're hotplugging */ + xf86Info.allowEmptyInput = (xf86Info.autoAddDevices && xf86Info.autoEnableDevices); + xf86GetOptValBool(FlagOptions, FLAG_ALLOW_EMPTY_INPUT, &xf86Info.allowEmptyInput); + + /* AEI on? Then we're not using kbd, so use the evdev rules set. */ +#if defined(linux) + if (xf86Info.allowEmptyInput) + set.rules = "evdev"; +#endif + XkbSetRulesDflts(&set); + + xf86Info.useDefaultFontPath = TRUE; + xf86Info.useDefaultFontPathFrom = X_DEFAULT; + if (xf86GetOptValBool(FlagOptions, FLAG_USE_DEFAULT_FONT_PATH, &value)) { + xf86Info.useDefaultFontPath = value; + xf86Info.useDefaultFontPathFrom = X_CONFIG; + } + +/* Make sure that timers don't overflow CARD32's after multiplying */ +#define MAX_TIME_IN_MIN (0x7fffffff / MILLI_PER_MIN) + + i = -1; + xf86GetOptValInteger(FlagOptions, FLAG_SAVER_BLANKTIME, &i); + if ((i >= 0) && (i < MAX_TIME_IN_MIN)) + ScreenSaverTime = defaultScreenSaverTime = i * MILLI_PER_MIN; + else if (i != -1) + xf86ConfigError("BlankTime value %d outside legal range of 0 - %d minutes", + i, MAX_TIME_IN_MIN); + +#ifdef DPMSExtension + i = -1; + xf86GetOptValInteger(FlagOptions, FLAG_DPMS_STANDBYTIME, &i); + if ((i >= 0) && (i < MAX_TIME_IN_MIN)) + DPMSStandbyTime = i * MILLI_PER_MIN; + else if (i != -1) + xf86ConfigError("StandbyTime value %d outside legal range of 0 - %d minutes", + i, MAX_TIME_IN_MIN); + i = -1; + xf86GetOptValInteger(FlagOptions, FLAG_DPMS_SUSPENDTIME, &i); + if ((i >= 0) && (i < MAX_TIME_IN_MIN)) + DPMSSuspendTime = i * MILLI_PER_MIN; + else if (i != -1) + xf86ConfigError("SuspendTime value %d outside legal range of 0 - %d minutes", + i, MAX_TIME_IN_MIN); + i = -1; + xf86GetOptValInteger(FlagOptions, FLAG_DPMS_OFFTIME, &i); + if ((i >= 0) && (i < MAX_TIME_IN_MIN)) + DPMSOffTime = i * MILLI_PER_MIN; + else if (i != -1) + xf86ConfigError("OffTime value %d outside legal range of 0 - %d minutes", + i, MAX_TIME_IN_MIN); +#endif + + i = -1; + xf86GetOptValInteger(FlagOptions, FLAG_PIXMAP, &i); + switch (i) { + case 24: + pix24 = Pix24Use24; + break; + case 32: + pix24 = Pix24Use32; + break; + case -1: + break; + default: + xf86ConfigError("Pixmap option's value (%d) must be 24 or 32\n", i); + return FALSE; + } + if (xf86Pix24 != Pix24DontCare) { + xf86Info.pixmap24 = xf86Pix24; + xf86Info.pix24From = X_CMDLINE; + } else if (pix24 != Pix24DontCare) { + xf86Info.pixmap24 = pix24; + xf86Info.pix24From = X_CONFIG; + } else { + xf86Info.pixmap24 = Pix24DontCare; + xf86Info.pix24From = X_DEFAULT; + } +#ifdef SUPPORT_PC98 + if (xf86GetOptValBool(FlagOptions, FLAG_PC98, &value)) { + xf86Info.pc98 = value; + if (value) { + xf86Msg(X_CONFIG, "Japanese PC98 architecture\n"); + } + } else + if (detectPC98()) { + xf86Info.pc98 = TRUE; + xf86Msg(X_PROBED, "Japanese PC98 architecture\n"); + } +#endif + +#ifdef PANORAMIX + from = X_DEFAULT; + if (!noPanoramiXExtension) + from = X_CMDLINE; + else if (xf86GetOptValBool(FlagOptions, FLAG_XINERAMA, &value)) { + noPanoramiXExtension = !value; + from = X_CONFIG; + } + if (!noPanoramiXExtension) + xf86Msg(from, "Xinerama: enabled\n"); +#endif + +#ifdef DRI2 + xf86Info.dri2 = FALSE; + xf86Info.dri2From = X_DEFAULT; + if (xf86GetOptValBool(FlagOptions, FLAG_DRI2, &value)) { + xf86Info.dri2 = value; + xf86Info.dri2From = X_CONFIG; + } +#endif + + return TRUE; +} + +Bool xf86DRI2Enabled(void) +{ + return xf86Info.dri2; +} + +/* + * Locate the core input devices. These can be specified/located in + * the following ways, in order of priority: + * + * 1. The InputDevices named by the -pointer and -keyboard command line + * options. + * 2. The "CorePointer" and "CoreKeyboard" InputDevices referred to by + * the active ServerLayout. + * 3. The first InputDevices marked as "CorePointer" and "CoreKeyboard". + * 4. The first InputDevices that use 'keyboard' or 'kbd' and a valid mouse + * driver (mouse, synaptics, evdev, vmmouse, void) + * 5. Default devices with an empty (default) configuration. These defaults + * will reference the 'mouse' and 'keyboard' drivers. + */ + +static Bool +checkCoreInputDevices(serverLayoutPtr servlayoutp, Bool implicitLayout) +{ + IDevPtr corePointer = NULL, coreKeyboard = NULL; + Bool foundPointer = FALSE, foundKeyboard = FALSE; + const char *pointerMsg = NULL, *keyboardMsg = NULL; + IDevPtr *devs, /* iterator */ + indp; + IDevRec Pointer, Keyboard; + XF86ConfInputPtr confInput; + XF86ConfInputRec defPtr, defKbd; + int count = 0; + MessageType from = X_DEFAULT; + int found = 0; + const char *mousedrivers[] = { "mouse", "synaptics", "evdev", "vmmouse", + "void", NULL }; + + /* + * First check if a core pointer or core keyboard have been specified + * in the active ServerLayout. If more than one is specified for either, + * remove the core attribute from the later ones. + */ + for (devs = servlayoutp->inputs; devs && *devs; devs++) { + pointer opt1 = NULL, opt2 = NULL; + indp = *devs; + if (indp->commonOptions && + xf86CheckBoolOption(indp->commonOptions, "CorePointer", FALSE)) { + opt1 = indp->commonOptions; + } + if (indp->extraOptions && + xf86CheckBoolOption(indp->extraOptions, "CorePointer", FALSE)) { + opt2 = indp->extraOptions; + } + if (opt1 || opt2) { + if (!corePointer) { + corePointer = indp; + } else { + if (opt1) + xf86ReplaceBoolOption(opt1, "CorePointer", FALSE); + if (opt2) + xf86ReplaceBoolOption(opt2, "CorePointer", FALSE); + xf86Msg(X_WARNING, "Duplicate core pointer devices. " + "Removing core pointer attribute from \"%s\"\n", + indp->identifier); + } + } + opt1 = opt2 = NULL; + if (indp->commonOptions && + xf86CheckBoolOption(indp->commonOptions, "CoreKeyboard", FALSE)) { + opt1 = indp->commonOptions; + } + if (indp->extraOptions && + xf86CheckBoolOption(indp->extraOptions, "CoreKeyboard", FALSE)) { + opt2 = indp->extraOptions; + } + if (opt1 || opt2) { + if (!coreKeyboard) { + coreKeyboard = indp; + } else { + if (opt1) + xf86ReplaceBoolOption(opt1, "CoreKeyboard", FALSE); + if (opt2) + xf86ReplaceBoolOption(opt2, "CoreKeyboard", FALSE); + xf86Msg(X_WARNING, "Duplicate core keyboard devices. " + "Removing core keyboard attribute from \"%s\"\n", + indp->identifier); + } + } + count++; + } + + confInput = NULL; + + /* 1. Check for the -pointer command line option. */ + if (xf86PointerName) { + confInput = xf86findInput(xf86PointerName, + xf86configptr->conf_input_lst); + if (!confInput) { + xf86Msg(X_ERROR, "No InputDevice section called \"%s\"\n", + xf86PointerName); + return FALSE; + } + from = X_CMDLINE; + /* + * If one was already specified in the ServerLayout, it needs to be + * removed. + */ + if (corePointer) { + for (devs = servlayoutp->inputs; devs && *devs; devs++) + if (*devs == corePointer) + { + free(*devs); + *devs = (IDevPtr)0x1; /* ensure we dont skip next loop*/ + break; + } + for (; devs && *devs; devs++) + devs[0] = devs[1]; + count--; + } + corePointer = NULL; + foundPointer = TRUE; + } + + /* 2. ServerLayout-specified core pointer. */ + if (corePointer) { + foundPointer = TRUE; + from = X_CONFIG; + } + + /* 3. First core pointer device. */ + if (!foundPointer && (!xf86Info.allowEmptyInput || implicitLayout)) { + XF86ConfInputPtr p; + + for (p = xf86configptr->conf_input_lst; p; p = p->list.next) { + if (p->inp_option_lst && + xf86CheckBoolOption(p->inp_option_lst, "CorePointer", FALSE)) { + confInput = p; + foundPointer = TRUE; + from = X_DEFAULT; + pointerMsg = "first core pointer device"; + break; + } + } + } + + /* 4. First pointer with an allowed mouse driver. */ + if (!foundPointer && !xf86Info.allowEmptyInput) { + const char **driver = mousedrivers; + confInput = xf86findInput(CONF_IMPLICIT_POINTER, + xf86configptr->conf_input_lst); + while (*driver && !confInput) { + confInput = xf86findInputByDriver(*driver, + xf86configptr->conf_input_lst); + driver++; + } + if (confInput) { + foundPointer = TRUE; + from = X_DEFAULT; + pointerMsg = "first mouse device"; + } + } + + /* 5. Built-in default. */ + if (!foundPointer && !xf86Info.allowEmptyInput) { + bzero(&defPtr, sizeof(defPtr)); + defPtr.inp_identifier = strdup("<default pointer>"); + defPtr.inp_driver = strdup("mouse"); + confInput = &defPtr; + foundPointer = TRUE; + from = X_DEFAULT; + pointerMsg = "default mouse configuration"; + } + + /* Add the core pointer device to the layout, and set it to Core. */ + if (foundPointer && confInput) { + foundPointer = configInput(&Pointer, confInput, from); + if (foundPointer) { + count++; + devs = xnfrealloc(servlayoutp->inputs, + (count + 1) * sizeof(IDevPtr)); + devs[count - 1] = xnfalloc(sizeof(IDevRec)); + *devs[count - 1] = Pointer; + devs[count - 1]->extraOptions = + xf86addNewOption(NULL, xnfstrdup("CorePointer"), NULL); + devs[count] = NULL; + servlayoutp->inputs = devs; + } + } + + if (!foundPointer && !xf86Info.allowEmptyInput) { + /* This shouldn't happen. */ + xf86Msg(X_ERROR, "Cannot locate a core pointer device.\n"); + return FALSE; + } + + /* + * always synthesize a 'mouse' section configured to send core + * events, unless a 'void' section is found, in which case the user + * probably wants to run footless. + * + * If you're using an evdev keyboard and expect a default mouse + * section ... deal. + */ + for (devs = servlayoutp->inputs; devs && *devs; devs++) { + const char **driver = mousedrivers; + while(*driver) { + if (!strcmp((*devs)->driver, *driver)) { + found = 1; + break; + } + driver++; + } + } + if (!found && !xf86Info.allowEmptyInput) { + xf86Msg(X_INFO, "No default mouse found, adding one\n"); + bzero(&defPtr, sizeof(defPtr)); + defPtr.inp_identifier = strdup("<default pointer>"); + defPtr.inp_driver = strdup("mouse"); + confInput = &defPtr; + foundPointer = configInput(&Pointer, confInput, from); + if (foundPointer) { + count++; + devs = xnfrealloc(servlayoutp->inputs, + (count + 1) * sizeof(IDevPtr)); + devs[count - 1] = xnfalloc(sizeof(IDevRec)); + *devs[count - 1] = Pointer; + devs[count - 1]->extraOptions = + xf86addNewOption(NULL, xnfstrdup("AlwaysCore"), NULL); + devs[count] = NULL; + servlayoutp->inputs = devs; + } + } + + confInput = NULL; + + /* 1. Check for the -keyboard command line option. */ + if (xf86KeyboardName) { + confInput = xf86findInput(xf86KeyboardName, + xf86configptr->conf_input_lst); + if (!confInput) { + xf86Msg(X_ERROR, "No InputDevice section called \"%s\"\n", + xf86KeyboardName); + return FALSE; + } + from = X_CMDLINE; + /* + * If one was already specified in the ServerLayout, it needs to be + * removed. + */ + if (coreKeyboard) { + for (devs = servlayoutp->inputs; devs && *devs; devs++) + if (*devs == coreKeyboard) + { + free(*devs); + *devs = (IDevPtr)0x1; /* ensure we dont skip next loop */ + break; + } + for (; devs && *devs; devs++) + devs[0] = devs[1]; + count--; + } + coreKeyboard = NULL; + foundKeyboard = TRUE; + } + + /* 2. ServerLayout-specified core keyboard. */ + if (coreKeyboard) { + foundKeyboard = TRUE; + from = X_CONFIG; + } + + /* 3. First core keyboard device. */ + if (!foundKeyboard && (!xf86Info.allowEmptyInput || implicitLayout)) { + XF86ConfInputPtr p; + + for (p = xf86configptr->conf_input_lst; p; p = p->list.next) { + if (p->inp_option_lst && + xf86CheckBoolOption(p->inp_option_lst, "CoreKeyboard", FALSE)) { + confInput = p; + foundKeyboard = TRUE; + from = X_DEFAULT; + keyboardMsg = "first core keyboard device"; + break; + } + } + } + + /* 4. First keyboard with 'keyboard' or 'kbd' as the driver. */ + if (!foundKeyboard && !xf86Info.allowEmptyInput) { + confInput = xf86findInput(CONF_IMPLICIT_KEYBOARD, + xf86configptr->conf_input_lst); + if (!confInput) { + confInput = xf86findInputByDriver("kbd", + xf86configptr->conf_input_lst); + } + if (confInput) { + foundKeyboard = TRUE; + from = X_DEFAULT; + keyboardMsg = "first keyboard device"; + } + } + + /* 5. Built-in default. */ + if (!foundKeyboard && !xf86Info.allowEmptyInput) { + bzero(&defKbd, sizeof(defKbd)); + defKbd.inp_identifier = strdup("<default keyboard>"); + defKbd.inp_driver = strdup("kbd"); + confInput = &defKbd; + foundKeyboard = TRUE; + keyboardMsg = "default keyboard configuration"; + from = X_DEFAULT; + } + + /* Add the core keyboard device to the layout, and set it to Core. */ + if (foundKeyboard && confInput) { + foundKeyboard = configInput(&Keyboard, confInput, from); + if (foundKeyboard) { + count++; + devs = xnfrealloc(servlayoutp->inputs, + (count + 1) * sizeof(IDevPtr)); + devs[count - 1] = xnfalloc(sizeof(IDevRec)); + *devs[count - 1] = Keyboard; + devs[count - 1]->extraOptions = + xf86addNewOption(NULL, xnfstrdup("CoreKeyboard"), NULL); + devs[count] = NULL; + servlayoutp->inputs = devs; + } + } + + if (!foundKeyboard && !xf86Info.allowEmptyInput) { + /* This shouldn't happen. */ + xf86Msg(X_ERROR, "Cannot locate a core keyboard device.\n"); + return FALSE; + } + + if (pointerMsg) { + if (implicitLayout) + xf86Msg(X_DEFAULT, "No Layout section. Using the %s.\n", + pointerMsg); + else + xf86Msg(X_DEFAULT, "The core pointer device wasn't specified " + "explicitly in the layout.\n" + "\tUsing the %s.\n", pointerMsg); + } + + if (keyboardMsg) { + if (implicitLayout) + xf86Msg(X_DEFAULT, "No Layout section. Using the %s.\n", + keyboardMsg); + else + xf86Msg(X_DEFAULT, "The core keyboard device wasn't specified " + "explicitly in the layout.\n" + "\tUsing the %s.\n", keyboardMsg); + } + + if (xf86Info.allowEmptyInput && !(foundPointer && foundKeyboard)) { +#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) + const char *config_backend; +#if defined(CONFIG_HAL) + config_backend = "HAL"; +#else + config_backend = "udev"; +#endif + xf86Msg(X_INFO, "The server relies on %s to provide the list of " + "input devices.\n\tIf no devices become available, " + "reconfigure %s or disable AutoAddDevices.\n", + config_backend, config_backend); +#else + xf86Msg(X_INFO, "Hotplugging is disabled and no input devices were configured.\n" + "\tTry disabling AllowEmptyInput.\n"); +#endif + } + + return TRUE; +} + +typedef enum { + LAYOUT_ISOLATEDEVICE, + LAYOUT_SINGLECARD +} LayoutValues; + +static OptionInfoRec LayoutOptions[] = { + { LAYOUT_ISOLATEDEVICE, "IsolateDevice", OPTV_STRING, + {0}, FALSE }, + { LAYOUT_SINGLECARD, "SingleCard", OPTV_BOOLEAN, + {0}, FALSE }, + { -1, NULL, OPTV_NONE, + {0}, FALSE }, +}; + +static Bool +configInputDevices(XF86ConfLayoutPtr layout, serverLayoutPtr servlayoutp) +{ + XF86ConfInputrefPtr irp; + IDevPtr *indp; + int count = 0; + + /* + * Count the number of input devices. + */ + irp = layout->lay_input_lst; + while (irp) { + count++; + irp = (XF86ConfInputrefPtr)irp->list.next; + } + DebugF("Found %d input devices in the layout section %s\n", + count, layout->lay_identifier); + indp = xnfcalloc((count + 1), sizeof(IDevPtr)); + indp[count] = NULL; + irp = layout->lay_input_lst; + count = 0; + while (irp) { + indp[count] = xnfalloc(sizeof(IDevRec)); + if (!configInput(indp[count], irp->iref_inputdev, X_CONFIG)) { + while(count--) + free(indp[count]); + free(indp); + return FALSE; + } + indp[count]->extraOptions = irp->iref_option_lst; + count++; + irp = (XF86ConfInputrefPtr)irp->list.next; + } + servlayoutp->inputs = indp; + + return TRUE; +} + + +/* + * figure out which layout is active, which screens are used in that layout, + * which drivers and monitors are used in these screens + */ +static Bool +configLayout(serverLayoutPtr servlayoutp, XF86ConfLayoutPtr conf_layout, + char *default_layout) +{ + XF86ConfAdjacencyPtr adjp; + XF86ConfInactivePtr idp; + int count = 0; + int scrnum; + XF86ConfLayoutPtr l; + MessageType from; + screenLayoutPtr slp; + GDevPtr gdp; + int i = 0, j; + + if (!servlayoutp) + return FALSE; + + /* + * which layout section is the active one? + * + * If there is a -layout command line option, use that one, otherwise + * pick the first one. + */ + from = X_DEFAULT; + if (xf86LayoutName != NULL) + from = X_CMDLINE; + else if (default_layout) { + xf86LayoutName = default_layout; + from = X_CONFIG; + } + if (xf86LayoutName != NULL) { + if ((l = xf86findLayout(xf86LayoutName, conf_layout)) == NULL) { + xf86Msg(X_ERROR, "No ServerLayout section called \"%s\"\n", + xf86LayoutName); + return FALSE; + } + conf_layout = l; + } + xf86Msg(from, "ServerLayout \"%s\"\n", conf_layout->lay_identifier); + adjp = conf_layout->lay_adjacency_lst; + + /* + * we know that each screen is referenced exactly once on the left side + * of a layout statement in the Layout section. So to allocate the right + * size for the array we do a quick walk of the list to figure out how + * many sections we have + */ + while (adjp) { + count++; + adjp = (XF86ConfAdjacencyPtr)adjp->list.next; + } + + DebugF("Found %d screens in the layout section %s", + count, conf_layout->lay_identifier); + if (!count) /* alloc enough storage even if no screen is specified */ + count = 1; + + slp = xnfcalloc(1, (count + 1) * sizeof(screenLayoutRec)); + slp[count].screen = NULL; + /* + * now that we have storage, loop over the list again and fill in our + * data structure; at this point we do not fill in the adjacency + * information as it is not clear if we need it at all + */ + adjp = conf_layout->lay_adjacency_lst; + count = 0; + while (adjp) { + slp[count].screen = xnfcalloc(1, sizeof(confScreenRec)); + if (adjp->adj_scrnum < 0) + scrnum = count; + else + scrnum = adjp->adj_scrnum; + if (!configScreen(slp[count].screen, adjp->adj_screen, scrnum, + X_CONFIG)) { + free(slp); + return FALSE; + } + slp[count].x = adjp->adj_x; + slp[count].y = adjp->adj_y; + slp[count].refname = adjp->adj_refscreen; + switch (adjp->adj_where) { + case CONF_ADJ_OBSOLETE: + slp[count].where = PosObsolete; + slp[count].topname = adjp->adj_top_str; + slp[count].bottomname = adjp->adj_bottom_str; + slp[count].leftname = adjp->adj_left_str; + slp[count].rightname = adjp->adj_right_str; + break; + case CONF_ADJ_ABSOLUTE: + slp[count].where = PosAbsolute; + break; + case CONF_ADJ_RIGHTOF: + slp[count].where = PosRightOf; + break; + case CONF_ADJ_LEFTOF: + slp[count].where = PosLeftOf; + break; + case CONF_ADJ_ABOVE: + slp[count].where = PosAbove; + break; + case CONF_ADJ_BELOW: + slp[count].where = PosBelow; + break; + case CONF_ADJ_RELATIVE: + slp[count].where = PosRelative; + break; + } + count++; + adjp = (XF86ConfAdjacencyPtr)adjp->list.next; + } + + /* No screen was specified in the layout. take the first one from the + * config file, or - if it is NULL - configScreen autogenerates one for + * us */ + if (!count) + { + slp[0].screen = xnfcalloc(1, sizeof(confScreenRec)); + if (!configScreen(slp[0].screen, xf86configptr->conf_screen_lst, + 0, X_CONFIG)) { + free(slp[0].screen); + free(slp); + return FALSE; + } + } + + /* XXX Need to tie down the upper left screen. */ + + /* Fill in the refscreen and top/bottom/left/right values */ + for (i = 0; i < count; i++) { + for (j = 0; j < count; j++) { + if (slp[i].refname && + strcmp(slp[i].refname, slp[j].screen->id) == 0) { + slp[i].refscreen = slp[j].screen; + } + if (slp[i].topname && + strcmp(slp[i].topname, slp[j].screen->id) == 0) { + slp[i].top = slp[j].screen; + } + if (slp[i].bottomname && + strcmp(slp[i].bottomname, slp[j].screen->id) == 0) { + slp[i].bottom = slp[j].screen; + } + if (slp[i].leftname && + strcmp(slp[i].leftname, slp[j].screen->id) == 0) { + slp[i].left = slp[j].screen; + } + if (slp[i].rightname && + strcmp(slp[i].rightname, slp[j].screen->id) == 0) { + slp[i].right = slp[j].screen; + } + } + if (slp[i].where != PosObsolete + && slp[i].where != PosAbsolute + && !slp[i].refscreen) { + xf86Msg(X_ERROR,"Screen %s doesn't exist: deleting placement\n", + slp[i].refname); + slp[i].where = PosAbsolute; + slp[i].x = 0; + slp[i].y = 0; + } + } + + /* + * Count the number of inactive devices. + */ + count = 0; + idp = conf_layout->lay_inactive_lst; + while (idp) { + count++; + idp = (XF86ConfInactivePtr)idp->list.next; + } + DebugF("Found %d inactive devices in the layout section %s\n", + count, conf_layout->lay_identifier); + gdp = xnfalloc((count + 1) * sizeof(GDevRec)); + gdp[count].identifier = NULL; + idp = conf_layout->lay_inactive_lst; + count = 0; + while (idp) { + if (!configDevice(&gdp[count], idp->inactive_device, FALSE)) { + free(gdp); + return FALSE; + } + count++; + idp = (XF86ConfInactivePtr)idp->list.next; + } + + if (!configInputDevices(conf_layout, servlayoutp)) + return FALSE; + + servlayoutp->id = conf_layout->lay_identifier; + servlayoutp->screens = slp; + servlayoutp->inactives = gdp; + servlayoutp->options = conf_layout->lay_option_lst; + from = X_DEFAULT; + + return TRUE; +} + +/* + * No layout section, so find the first Screen section and set that up as + * the only active screen. + */ +static Bool +configImpliedLayout(serverLayoutPtr servlayoutp, XF86ConfScreenPtr conf_screen, + XF86ConfigPtr xf86configptr) +{ + MessageType from; + XF86ConfScreenPtr s; + screenLayoutPtr slp; + IDevPtr *indp; + XF86ConfLayoutRec layout; + + if (!servlayoutp) + return FALSE; + + /* + * which screen section is the active one? + * + * If there is a -screen option, use that one, otherwise use the first + * one. + */ + + from = X_CONFIG; + if (xf86ScreenName != NULL) { + if ((s = xf86findScreen(xf86ScreenName, conf_screen)) == NULL) { + xf86Msg(X_ERROR, "No Screen section called \"%s\"\n", + xf86ScreenName); + return FALSE; + } + conf_screen = s; + from = X_CMDLINE; + } + + /* We have exactly one screen */ + + slp = xnfcalloc(1, 2 * sizeof(screenLayoutRec)); + slp[0].screen = xnfcalloc(1, sizeof(confScreenRec)); + slp[1].screen = NULL; + if (!configScreen(slp[0].screen, conf_screen, 0, from)) { + free(slp); + return FALSE; + } + servlayoutp->id = "(implicit)"; + servlayoutp->screens = slp; + servlayoutp->inactives = xnfcalloc(1, sizeof(GDevRec)); + servlayoutp->options = NULL; + + memset(&layout, 0, sizeof(layout)); + layout.lay_identifier = servlayoutp->id; + if (xf86layoutAddInputDevices(xf86configptr, &layout) > 0) { + if (!configInputDevices(&layout, servlayoutp)) + return FALSE; + from = X_DEFAULT; + } else { + /* Set up an empty input device list, then look for some core devices. */ + indp = xnfalloc(sizeof(IDevPtr)); + *indp = NULL; + servlayoutp->inputs = indp; + } + + return TRUE; +} + +static Bool +configXvAdaptor(confXvAdaptorPtr adaptor, XF86ConfVideoAdaptorPtr conf_adaptor) +{ + int count = 0; + XF86ConfVideoPortPtr conf_port; + + xf86Msg(X_CONFIG, "| |-->VideoAdaptor \"%s\"\n", + conf_adaptor->va_identifier); + adaptor->identifier = conf_adaptor->va_identifier; + adaptor->options = conf_adaptor->va_option_lst; + if (conf_adaptor->va_busid || conf_adaptor->va_driver) { + xf86Msg(X_CONFIG, "| | Unsupported device type, skipping entry\n"); + return FALSE; + } + + /* + * figure out how many videoport subsections there are and fill them in + */ + conf_port = conf_adaptor->va_port_lst; + while(conf_port) { + count++; + conf_port = (XF86ConfVideoPortPtr)conf_port->list.next; + } + adaptor->ports = xnfalloc((count) * sizeof(confXvPortRec)); + adaptor->numports = count; + count = 0; + conf_port = conf_adaptor->va_port_lst; + while(conf_port) { + adaptor->ports[count].identifier = conf_port->vp_identifier; + adaptor->ports[count].options = conf_port->vp_option_lst; + count++; + conf_port = (XF86ConfVideoPortPtr)conf_port->list.next; + } + + return TRUE; +} + +static Bool +configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, int scrnum, + MessageType from) +{ + int count = 0; + XF86ConfDisplayPtr dispptr; + XF86ConfAdaptorLinkPtr conf_adaptor; + Bool defaultMonitor = FALSE; + + if (!conf_screen) { + conf_screen = xnfcalloc(1, sizeof(XF86ConfScreenRec)); + conf_screen->scrn_identifier = "Default Screen Section"; + xf86Msg(X_DEFAULT, "No screen section available. Using defaults.\n"); + } + + xf86Msg(from, "|-->Screen \"%s\" (%d)\n", conf_screen->scrn_identifier, + scrnum); + /* + * now we fill in the elements of the screen + */ + screenp->id = conf_screen->scrn_identifier; + screenp->screennum = scrnum; + screenp->defaultdepth = conf_screen->scrn_defaultdepth; + screenp->defaultbpp = conf_screen->scrn_defaultbpp; + screenp->defaultfbbpp = conf_screen->scrn_defaultfbbpp; + screenp->monitor = xnfcalloc(1, sizeof(MonRec)); + /* If no monitor is specified, create a default one. */ + if (!conf_screen->scrn_monitor) { + XF86ConfMonitorRec defMon; + + bzero(&defMon, sizeof(defMon)); + defMon.mon_identifier = "<default monitor>"; + if (!configMonitor(screenp->monitor, &defMon)) + return FALSE; + defaultMonitor = TRUE; + } else { + if (!configMonitor(screenp->monitor,conf_screen->scrn_monitor)) + return FALSE; + } + /* Configure the device. If there isn't one configured, attach to the + * first inactive one that we can configure. If there's none that work, + * set it to NULL so that the section can be autoconfigured later */ + screenp->device = xnfcalloc(1, sizeof(GDevRec)); + if ((!conf_screen->scrn_device) && (xf86configptr->conf_device_lst)) { + conf_screen->scrn_device = xf86configptr->conf_device_lst; + xf86Msg(X_DEFAULT, "No device specified for screen \"%s\".\n" + "\tUsing the first device section listed.\n", screenp->id); + } + if (configDevice(screenp->device,conf_screen->scrn_device, TRUE)) { + screenp->device->myScreenSection = screenp; + } else { + screenp->device = NULL; + } + screenp->options = conf_screen->scrn_option_lst; + + /* + * figure out how many display subsections there are and fill them in + */ + dispptr = conf_screen->scrn_display_lst; + while(dispptr) { + count++; + dispptr = (XF86ConfDisplayPtr)dispptr->list.next; + } + screenp->displays = xnfalloc((count) * sizeof(DispRec)); + screenp->numdisplays = count; + + /* Fill in the default Virtual size, if any */ + if (conf_screen->scrn_virtualX && conf_screen->scrn_virtualY) { + for (count = 0, dispptr = conf_screen->scrn_display_lst; + dispptr; + dispptr = (XF86ConfDisplayPtr)dispptr->list.next, count++) { + screenp->displays[count].virtualX = conf_screen->scrn_virtualX; + screenp->displays[count].virtualY = conf_screen->scrn_virtualY; + } + } + + /* Now do the per-Display Virtual sizes */ + count = 0; + dispptr = conf_screen->scrn_display_lst; + while(dispptr) { + configDisplay(&(screenp->displays[count]),dispptr); + count++; + dispptr = (XF86ConfDisplayPtr)dispptr->list.next; + } + + /* + * figure out how many videoadaptor references there are and fill them in + */ + conf_adaptor = conf_screen->scrn_adaptor_lst; + while(conf_adaptor) { + count++; + conf_adaptor = (XF86ConfAdaptorLinkPtr)conf_adaptor->list.next; + } + screenp->xvadaptors = xnfalloc((count) * sizeof(confXvAdaptorRec)); + screenp->numxvadaptors = 0; + conf_adaptor = conf_screen->scrn_adaptor_lst; + while(conf_adaptor) { + if (configXvAdaptor(&(screenp->xvadaptors[screenp->numxvadaptors]), + conf_adaptor->al_adaptor)) + screenp->numxvadaptors++; + conf_adaptor = (XF86ConfAdaptorLinkPtr)conf_adaptor->list.next; + } + + if (defaultMonitor) { + xf86Msg(X_DEFAULT, "No monitor specified for screen \"%s\".\n" + "\tUsing a default monitor configuration.\n", screenp->id); + } + return TRUE; +} + +typedef enum { + MON_REDUCEDBLANKING, + MON_MAX_PIX_CLOCK, +} MonitorValues; + +static OptionInfoRec MonitorOptions[] = { + { MON_REDUCEDBLANKING, "ReducedBlanking", OPTV_BOOLEAN, + {0}, FALSE }, + { MON_MAX_PIX_CLOCK, "MaxPixClock", OPTV_FREQ, + {0}, FALSE }, + { -1, NULL, OPTV_NONE, + {0}, FALSE }, +}; + +static Bool +configMonitor(MonPtr monitorp, XF86ConfMonitorPtr conf_monitor) +{ + int count; + DisplayModePtr mode,last = NULL; + XF86ConfModeLinePtr cmodep; + XF86ConfModesPtr modes; + XF86ConfModesLinkPtr modeslnk = conf_monitor->mon_modes_sect_lst; + Gamma zeros = {0.0, 0.0, 0.0}; + float badgamma = 0.0; + double maxPixClock; + + xf86Msg(X_CONFIG, "| |-->Monitor \"%s\"\n", + conf_monitor->mon_identifier); + monitorp->id = conf_monitor->mon_identifier; + monitorp->vendor = conf_monitor->mon_vendor; + monitorp->model = conf_monitor->mon_modelname; + monitorp->Modes = NULL; + monitorp->Last = NULL; + monitorp->gamma = zeros; + monitorp->widthmm = conf_monitor->mon_width; + monitorp->heightmm = conf_monitor->mon_height; + monitorp->reducedblanking = FALSE; + monitorp->maxPixClock = 0; + monitorp->options = conf_monitor->mon_option_lst; + + /* + * fill in the monitor structure + */ + for( count = 0 ; + count < conf_monitor->mon_n_hsync && count < MAX_HSYNC; + count++) { + monitorp->hsync[count].hi = conf_monitor->mon_hsync[count].hi; + monitorp->hsync[count].lo = conf_monitor->mon_hsync[count].lo; + } + monitorp->nHsync = count; + for( count = 0 ; + count < conf_monitor->mon_n_vrefresh && count < MAX_VREFRESH; + count++) { + monitorp->vrefresh[count].hi = conf_monitor->mon_vrefresh[count].hi; + monitorp->vrefresh[count].lo = conf_monitor->mon_vrefresh[count].lo; + } + monitorp->nVrefresh = count; + + /* + * first we collect the mode lines from the UseModes directive + */ + while(modeslnk) + { + modes = xf86findModes (modeslnk->ml_modes_str, + xf86configptr->conf_modes_lst); + modeslnk->ml_modes = modes; + + + /* now add the modes found in the modes + section to the list of modes for this + monitor unless it has been added before + because we are reusing the same section + for another screen */ + if (xf86itemNotSublist( + (GenericListPtr)conf_monitor->mon_modeline_lst, + (GenericListPtr)modes->mon_modeline_lst)) { + conf_monitor->mon_modeline_lst = (XF86ConfModeLinePtr) + xf86addListItem( + (GenericListPtr)conf_monitor->mon_modeline_lst, + (GenericListPtr)modes->mon_modeline_lst); + } + modeslnk = modeslnk->list.next; + } + + /* + * we need to hook in the mode lines now + * here both data structures use lists, only our internal one + * is double linked + */ + cmodep = conf_monitor->mon_modeline_lst; + while( cmodep ) { + mode = xnfcalloc(1, sizeof(DisplayModeRec)); + mode->type = 0; + mode->Clock = cmodep->ml_clock; + mode->HDisplay = cmodep->ml_hdisplay; + mode->HSyncStart = cmodep->ml_hsyncstart; + mode->HSyncEnd = cmodep->ml_hsyncend; + mode->HTotal = cmodep->ml_htotal; + mode->VDisplay = cmodep->ml_vdisplay; + mode->VSyncStart = cmodep->ml_vsyncstart; + mode->VSyncEnd = cmodep->ml_vsyncend; + mode->VTotal = cmodep->ml_vtotal; + mode->Flags = cmodep->ml_flags; + mode->HSkew = cmodep->ml_hskew; + mode->VScan = cmodep->ml_vscan; + mode->name = xnfstrdup(cmodep->ml_identifier); + if( last ) { + mode->prev = last; + last->next = mode; + } + else { + /* + * this is the first mode + */ + monitorp->Modes = mode; + mode->prev = NULL; + } + last = mode; + cmodep = (XF86ConfModeLinePtr)cmodep->list.next; + } + if(last){ + last->next = NULL; + } + monitorp->Last = last; + + /* add the (VESA) default modes */ + if (! addDefaultModes(monitorp) ) + return FALSE; + + if (conf_monitor->mon_gamma_red > GAMMA_ZERO) + monitorp->gamma.red = conf_monitor->mon_gamma_red; + if (conf_monitor->mon_gamma_green > GAMMA_ZERO) + monitorp->gamma.green = conf_monitor->mon_gamma_green; + if (conf_monitor->mon_gamma_blue > GAMMA_ZERO) + monitorp->gamma.blue = conf_monitor->mon_gamma_blue; + + /* Check that the gamma values are within range */ + if (monitorp->gamma.red > GAMMA_ZERO && + (monitorp->gamma.red < GAMMA_MIN || + monitorp->gamma.red > GAMMA_MAX)) { + badgamma = monitorp->gamma.red; + } else if (monitorp->gamma.green > GAMMA_ZERO && + (monitorp->gamma.green < GAMMA_MIN || + monitorp->gamma.green > GAMMA_MAX)) { + badgamma = monitorp->gamma.green; + } else if (monitorp->gamma.blue > GAMMA_ZERO && + (monitorp->gamma.blue < GAMMA_MIN || + monitorp->gamma.blue > GAMMA_MAX)) { + badgamma = monitorp->gamma.blue; + } + if (badgamma > GAMMA_ZERO) { + xf86ConfigError("Gamma value %.f is out of range (%.2f - %.1f)\n", + badgamma, GAMMA_MIN, GAMMA_MAX); + return FALSE; + } + + xf86ProcessOptions(-1, monitorp->options, MonitorOptions); + xf86GetOptValBool(MonitorOptions, MON_REDUCEDBLANKING, + &monitorp->reducedblanking); + if (xf86GetOptValFreq(MonitorOptions, MON_MAX_PIX_CLOCK, OPTUNITS_KHZ, + &maxPixClock) == TRUE) { + monitorp->maxPixClock = (int) maxPixClock; + } + + return TRUE; +} + +static int +lookupVisual(const char *visname) +{ + int i; + + if (!visname || !*visname) + return -1; + + for (i = 0; i <= DirectColor; i++) { + if (!xf86nameCompare(visname, xf86VisualNames[i])) + break; + } + + if (i <= DirectColor) + return i; + + return -1; +} + + +static Bool +configDisplay(DispPtr displayp, XF86ConfDisplayPtr conf_display) +{ + int count = 0; + XF86ModePtr modep; + + displayp->frameX0 = conf_display->disp_frameX0; + displayp->frameY0 = conf_display->disp_frameY0; + displayp->virtualX = conf_display->disp_virtualX; + displayp->virtualY = conf_display->disp_virtualY; + displayp->depth = conf_display->disp_depth; + displayp->fbbpp = conf_display->disp_bpp; + displayp->weight.red = conf_display->disp_weight.red; + displayp->weight.green = conf_display->disp_weight.green; + displayp->weight.blue = conf_display->disp_weight.blue; + displayp->blackColour.red = conf_display->disp_black.red; + displayp->blackColour.green = conf_display->disp_black.green; + displayp->blackColour.blue = conf_display->disp_black.blue; + displayp->whiteColour.red = conf_display->disp_white.red; + displayp->whiteColour.green = conf_display->disp_white.green; + displayp->whiteColour.blue = conf_display->disp_white.blue; + displayp->options = conf_display->disp_option_lst; + if (conf_display->disp_visual) { + displayp->defaultVisual = lookupVisual(conf_display->disp_visual); + if (displayp->defaultVisual == -1) { + xf86ConfigError("Invalid visual name: \"%s\"", + conf_display->disp_visual); + return FALSE; + } + } else { + displayp->defaultVisual = -1; + } + + /* + * now hook in the modes + */ + modep = conf_display->disp_mode_lst; + while(modep) { + count++; + modep = (XF86ModePtr)modep->list.next; + } + displayp->modes = xnfalloc((count+1) * sizeof(char*)); + modep = conf_display->disp_mode_lst; + count = 0; + while(modep) { + displayp->modes[count] = modep->mode_name; + count++; + modep = (XF86ModePtr)modep->list.next; + } + displayp->modes[count] = NULL; + + return TRUE; +} + +static Bool +configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device, Bool active) +{ + int i; + + if (!conf_device) { + return FALSE; + } + + if (active) + xf86Msg(X_CONFIG, "| |-->Device \"%s\"\n", + conf_device->dev_identifier); + else + xf86Msg(X_CONFIG, "|-->Inactive Device \"%s\"\n", + conf_device->dev_identifier); + + devicep->identifier = conf_device->dev_identifier; + devicep->vendor = conf_device->dev_vendor; + devicep->board = conf_device->dev_board; + devicep->chipset = conf_device->dev_chipset; + devicep->ramdac = conf_device->dev_ramdac; + devicep->driver = conf_device->dev_driver; + devicep->active = active; + devicep->videoRam = conf_device->dev_videoram; + devicep->BiosBase = conf_device->dev_bios_base; + devicep->MemBase = conf_device->dev_mem_base; + devicep->IOBase = conf_device->dev_io_base; + devicep->clockchip = conf_device->dev_clockchip; + devicep->busID = conf_device->dev_busid; + devicep->textClockFreq = conf_device->dev_textclockfreq; + devicep->chipID = conf_device->dev_chipid; + devicep->chipRev = conf_device->dev_chiprev; + devicep->options = conf_device->dev_option_lst; + devicep->irq = conf_device->dev_irq; + devicep->screen = conf_device->dev_screen; + + for (i = 0; i < MAXDACSPEEDS; i++) { + if (i < CONF_MAXDACSPEEDS) + devicep->dacSpeeds[i] = conf_device->dev_dacSpeeds[i]; + else + devicep->dacSpeeds[i] = 0; + } + devicep->numclocks = conf_device->dev_clocks; + if (devicep->numclocks > MAXCLOCKS) + devicep->numclocks = MAXCLOCKS; + for (i = 0; i < devicep->numclocks; i++) { + devicep->clock[i] = conf_device->dev_clock[i]; + } + devicep->claimed = FALSE; + + return TRUE; +} + +#ifdef XF86DRI +static void +configDRI(XF86ConfDRIPtr drip) +{ + int count = 0; + XF86ConfBuffersPtr bufs; + int i; + struct group *grp; + + xf86ConfigDRI.group = -1; + xf86ConfigDRI.mode = 0; + xf86ConfigDRI.bufs_count = 0; + xf86ConfigDRI.bufs = NULL; + + if (drip) { + if (drip->dri_group_name) { + if ((grp = getgrnam(drip->dri_group_name))) + xf86ConfigDRI.group = grp->gr_gid; + } else { + if (drip->dri_group >= 0) + xf86ConfigDRI.group = drip->dri_group; + } + xf86ConfigDRI.mode = drip->dri_mode; + for (bufs = drip->dri_buffers_lst; bufs; bufs = bufs->list.next) + ++count; + + xf86ConfigDRI.bufs_count = count; + xf86ConfigDRI.bufs = xnfalloc(count * sizeof(*xf86ConfigDRI.bufs)); + + for (i = 0, bufs = drip->dri_buffers_lst; + i < count; + i++, bufs = bufs->list.next) { + + xf86ConfigDRI.bufs[i].count = bufs->buf_count; + xf86ConfigDRI.bufs[i].size = bufs->buf_size; + /* FIXME: Flags not implemented. These + could be used, for example, to specify a + contiguous block and/or write-combining + cache policy. */ + xf86ConfigDRI.bufs[i].flags = 0; + } + } +} +#endif + +static void +configExtensions(XF86ConfExtensionsPtr conf_ext) +{ + XF86OptionPtr o; + + if (conf_ext && conf_ext->ext_option_lst) { + for (o = conf_ext->ext_option_lst; o; o = xf86NextOption(o)) { + char *name = xf86OptionName(o); + char *val = xf86OptionValue(o); + char *n; + Bool enable = TRUE; + + /* Handle "No<ExtensionName>" */ + n = xf86NormalizeName(name); + if (strncmp(n, "no", 2) == 0) { + name += 2; + enable = FALSE; + } + + if (!val || + xf86NameCmp(val, "enable") == 0 || + xf86NameCmp(val, "enabled") == 0 || + xf86NameCmp(val, "on") == 0 || + xf86NameCmp(val, "1") == 0 || + xf86NameCmp(val, "yes") == 0 || + xf86NameCmp(val, "true") == 0) { + /* NOTHING NEEDED -- enabling is handled below */ + } else if (xf86NameCmp(val, "disable") == 0 || + xf86NameCmp(val, "disabled") == 0 || + xf86NameCmp(val, "off") == 0 || + xf86NameCmp(val, "0") == 0 || + xf86NameCmp(val, "no") == 0 || + xf86NameCmp(val, "false") == 0) { + enable = !enable; + } else { + xf86Msg(X_WARNING, "Ignoring unrecognized value \"%s\"\n", val); + free(n); + continue; + } + + if (EnableDisableExtension(name, enable)) { + xf86Msg(X_CONFIG, "Extension \"%s\" is %s\n", + name, enable ? "enabled" : "disabled"); + } else { + xf86Msg(X_WARNING, "Ignoring unrecognized extension \"%s\"\n", + name); + } + free(n); + } + } +} + +static Bool +configInput(IDevPtr inputp, XF86ConfInputPtr conf_input, MessageType from) +{ + xf86Msg(from, "|-->Input Device \"%s\"\n", conf_input->inp_identifier); + inputp->identifier = conf_input->inp_identifier; + inputp->driver = conf_input->inp_driver; + inputp->commonOptions = conf_input->inp_option_lst; + inputp->extraOptions = NULL; + + return TRUE; +} + +static Bool +modeIsPresent(DisplayModePtr mode, MonPtr monitorp) +{ + DisplayModePtr knownmodes = monitorp->Modes; + + /* all I can think of is a linear search... */ + while(knownmodes != NULL) + { + if(!strcmp(mode->name, knownmodes->name) && + !(knownmodes->type & M_T_DEFAULT)) + return TRUE; + knownmodes = knownmodes->next; + } + return FALSE; +} + +static Bool +addDefaultModes(MonPtr monitorp) +{ + DisplayModePtr mode; + DisplayModePtr last = monitorp->Last; + int i = 0; + + for (i = 0; i < xf86NumDefaultModes; i++) + { + mode = xf86DuplicateMode(&xf86DefaultModes[i]); + if (!modeIsPresent(mode, monitorp)) + { + monitorp->Modes = xf86ModesAdd(monitorp->Modes, mode); + last = mode; + } else { + free(mode); + } + } + monitorp->Last = last; + + return TRUE; +} + +static void +checkInput(serverLayoutPtr layout, Bool implicit_layout) { + checkCoreInputDevices(layout, implicit_layout); + + /* AllowEmptyInput and the "kbd" and "mouse" drivers are mutually + * exclusive. Trawl the list for mouse/kbd devices and disable them. + */ + if (xf86Info.allowEmptyInput && layout->inputs) + { + IDevPtr *dev = layout->inputs; + BOOL warned = FALSE; + + while(*dev) + { + if (strcmp((*dev)->driver, "kbd") == 0 || + strcmp((*dev)->driver, "mouse") == 0 || + strcmp((*dev)->driver, "vmmouse") == 0) + { + IDevPtr *current; + if (!warned) + { + xf86Msg(X_WARNING, "AllowEmptyInput is on, devices using " + "drivers 'kbd', 'mouse' or 'vmmouse' will be disabled.\n"); + warned = TRUE; + } + + xf86Msg(X_WARNING, "Disabling %s\n", (*dev)->identifier); + + current = dev; + free(*dev); + + do { + *current = *(current + 1); + current++; + } while(*current); + } else + dev++; + } + } +} + +/* + * load the config file and fill the global data structure + */ +ConfigStatus +xf86HandleConfigFile(Bool autoconfig) +{ + const char *filename, *dirname, *sysdirname; + char *filesearch, *dirsearch; + MessageType filefrom = X_DEFAULT; + MessageType dirfrom = X_DEFAULT; + char *scanptr; + Bool singlecard = 0; + Bool implicit_layout = FALSE; + + if (!autoconfig) { + if (getuid() == 0) { + filesearch = ROOT_CONFIGPATH; + dirsearch = ROOT_CONFIGDIRPATH; + } else { + filesearch = USER_CONFIGPATH; + dirsearch = USER_CONFIGDIRPATH; + } + + if (xf86ConfigFile) + filefrom = X_CMDLINE; + if (xf86ConfigDir) + dirfrom = X_CMDLINE; + + xf86initConfigFiles(); + sysdirname = xf86openConfigDirFiles(SYS_CONFIGDIRPATH, NULL, + PROJECTROOT); + dirname = xf86openConfigDirFiles(dirsearch, xf86ConfigDir, PROJECTROOT); + filename = xf86openConfigFile(filesearch, xf86ConfigFile, PROJECTROOT); + if (filename) { + xf86MsgVerb(filefrom, 0, "Using config file: \"%s\"\n", filename); + xf86ConfigFile = xnfstrdup(filename); + } else { + if (xf86ConfigFile) + xf86Msg(X_ERROR, "Unable to locate/open config file: \"%s\"\n", + xf86ConfigFile); + } + if (dirname) { + xf86MsgVerb(dirfrom, 0, "Using config directory: \"%s\"\n", + dirname); + xf86ConfigDir = xnfstrdup(dirname); + } else { + if (xf86ConfigDir) + xf86Msg(X_ERROR, + "Unable to locate/open config directory: \"%s\"\n", + xf86ConfigDir); + } + if (sysdirname) + xf86MsgVerb(X_DEFAULT, 0, "Using system config directory \"%s\"\n", + sysdirname); + if (!filename && !dirname && !sysdirname) + return CONFIG_NOFILE; + } + + if ((xf86configptr = xf86readConfigFile ()) == NULL) { + xf86Msg(X_ERROR, "Problem parsing the config file\n"); + return CONFIG_PARSE_ERROR; + } + xf86closeConfigFile (); + + /* Initialise a few things. */ + + /* + * now we convert part of the information contained in the parser + * structures into our own structures. + * The important part here is to figure out which Screen Sections + * in the XF86Config file are active so that we can piece together + * the modes that we need later down the road. + * And while we are at it, we'll decode the rest of the stuff as well + */ + + /* First check if a layout section is present, and if it is valid. */ + + if (xf86configptr->conf_layout_lst == NULL || xf86ScreenName != NULL) { + if (xf86ScreenName == NULL) { + xf86Msg(X_DEFAULT, + "No Layout section. Using the first Screen section.\n"); + } + if (!configImpliedLayout(&xf86ConfigLayout, + xf86configptr->conf_screen_lst, + xf86configptr)) { + xf86Msg(X_ERROR, "Unable to determine the screen layout\n"); + return CONFIG_PARSE_ERROR; + } + implicit_layout = TRUE; + } else { + if (xf86configptr->conf_flags != NULL) { + char *dfltlayout = NULL; + pointer optlist = xf86configptr->conf_flags->flg_option_lst; + + if (optlist && xf86FindOption(optlist, "defaultserverlayout")) + dfltlayout = xf86SetStrOption(optlist, "defaultserverlayout", NULL); + if (!configLayout(&xf86ConfigLayout, xf86configptr->conf_layout_lst, + dfltlayout)) { + xf86Msg(X_ERROR, "Unable to determine the screen layout\n"); + return CONFIG_PARSE_ERROR; + } + } else { + if (!configLayout(&xf86ConfigLayout, xf86configptr->conf_layout_lst, + NULL)) { + xf86Msg(X_ERROR, "Unable to determine the screen layout\n"); + return CONFIG_PARSE_ERROR; + } + } + } + + xf86ProcessOptions(-1, xf86ConfigLayout.options, LayoutOptions); + + if ((scanptr = xf86GetOptValString(LayoutOptions, LAYOUT_ISOLATEDEVICE))) { + ; /* IsolateDevice specified; overrides SingleCard */ + } else { + xf86GetOptValBool(LayoutOptions, LAYOUT_SINGLECARD, &singlecard); + if (singlecard) + scanptr = xf86ConfigLayout.screens->screen->device->busID; + } + if (scanptr) { + int bus, device, func; + if (strncmp(scanptr, "PCI:", 4) != 0) { + xf86Msg(X_WARNING, "Bus types other than PCI not yet isolable.\n" + "\tIgnoring IsolateDevice option.\n"); + } else if (sscanf(scanptr, "PCI:%d:%d:%d", &bus, &device, &func) == 3) { + xf86IsolateDevice.domain = PCI_DOM_FROM_BUS(bus); + xf86IsolateDevice.bus = PCI_BUS_NO_DOMAIN(bus); + xf86IsolateDevice.dev = device; + xf86IsolateDevice.func = func; + xf86Msg(X_INFO, + "Isolating PCI bus \"%d:%d:%d\"\n", bus, device, func); + } + } + + /* Now process everything else */ + if (!configServerFlags(xf86configptr->conf_flags,xf86ConfigLayout.options)){ + ErrorF ("Problem when converting the config data structures\n"); + return CONFIG_PARSE_ERROR; + } + + configFiles(xf86configptr->conf_files); + configExtensions(xf86configptr->conf_extensions); +#ifdef XF86DRI + configDRI(xf86configptr->conf_dri); +#endif + + checkInput(&xf86ConfigLayout, implicit_layout); + + /* + * Handle some command line options that can override some of the + * ServerFlags settings. + */ +#ifdef XF86VIDMODE + if (xf86VidModeDisabled) + xf86Info.vidModeEnabled = FALSE; + if (xf86VidModeAllowNonLocal) + xf86Info.vidModeAllowNonLocal = TRUE; +#endif + + if (xf86AllowMouseOpenFail) + xf86Info.allowMouseOpenFail = TRUE; + + return CONFIG_OK; +} + +Bool +xf86PathIsSafe(const char *path) +{ + return (xf86pathIsSafe(path) != 0); +} diff --git a/xorg-server/hw/xfree86/common/xf86Configure.c b/xorg-server/hw/xfree86/common/xf86Configure.c index 67bf08bbf..883c666a6 100644 --- a/xorg-server/hw/xfree86/common/xf86Configure.c +++ b/xorg-server/hw/xfree86/common/xf86Configure.c @@ -1,892 +1,892 @@ -/* - * Copyright 2000-2002 by Alan Hourihane, Flint Mountain, North Wales. - * - * 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 Alan Hourihane not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Alan Hourihane makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL ALAN HOURIHANE 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. - * - * Author: Alan Hourihane, alanh@fairlite.demon.co.uk - * - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86Config.h" -#include "xf86_OSlib.h" -#include "xf86Priv.h" -#define IN_XSERVER -#include "Configint.h" -#include "xf86DDC.h" -#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) -#include "xf86Bus.h" -#include "xf86Sbus.h" -#endif - -typedef struct _DevToConfig { - GDevRec GDev; - struct pci_device * pVideo; -#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) - sbusDevicePtr sVideo; -#endif - int iDriver; -} DevToConfigRec, *DevToConfigPtr; - -static DevToConfigPtr DevToConfig = NULL; -static int nDevToConfig = 0, CurrentDriver; - -xf86MonPtr ConfiguredMonitor; -Bool xf86DoConfigurePass1 = TRUE; -static Bool foundMouse = FALSE; - -#if defined(__SCO__) -static char *DFLT_MOUSE_PROTO = "OSMouse"; -#elif defined(__UNIXWARE__) -static char *DFLT_MOUSE_PROTO = "OSMouse"; -static char *DFLT_MOUSE_DEV = "/dev/mouse"; -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -static char *DFLT_MOUSE_DEV = "/dev/sysmouse"; -static char *DFLT_MOUSE_PROTO = "auto"; -#elif defined(linux) -static char DFLT_MOUSE_DEV[] = "/dev/input/mice"; -static char DFLT_MOUSE_PROTO[] = "auto"; -#else -static char *DFLT_MOUSE_DEV = "/dev/mouse"; -static char *DFLT_MOUSE_PROTO = "auto"; -#endif - -static Bool -bus_pci_configure(void *busData) -{ - int i; - struct pci_device * pVideo = NULL; - - pVideo = (struct pci_device *) busData; - for (i = 0; i < nDevToConfig; i++) - if (DevToConfig[i].pVideo && - (DevToConfig[i].pVideo->domain == pVideo->domain) && - (DevToConfig[i].pVideo->bus == pVideo->bus) && - (DevToConfig[i].pVideo->dev == pVideo->dev) && - (DevToConfig[i].pVideo->func == pVideo->func)) - return 0; - - return 1; -} - -static Bool -bus_sbus_configure(void *busData) -{ -#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) - int i; - - for (i = 0; i < nDevToConfig; i++) - if (DevToConfig[i].sVideo && - DevToConfig[i].sVideo->fbNum == ((sbusDevicePtr) busData)->fbNum) - return 0; - -#endif - return 1; -} - -static void -bus_pci_newdev_configure(void *busData, int i, int *chipset) -{ - const char *VendorName; - const char *CardName; - char busnum[8]; - struct pci_device * pVideo = NULL; - - pVideo = (struct pci_device *) busData; - - DevToConfig[i].pVideo = pVideo; - - VendorName = pci_device_get_vendor_name( pVideo ); - CardName = pci_device_get_device_name( pVideo ); - - if (!VendorName) { - VendorName = xnfalloc(15); - sprintf((char*)VendorName, "Unknown Vendor"); - } - - if (!CardName) { - CardName = xnfalloc(14); - sprintf((char*)CardName, "Unknown Board"); - } - - DevToConfig[i].GDev.identifier = - xnfalloc(strlen(VendorName) + strlen(CardName) + 2); - sprintf(DevToConfig[i].GDev.identifier, "%s %s", VendorName, CardName); - - DevToConfig[i].GDev.vendor = (char *)VendorName; - DevToConfig[i].GDev.board = (char *)CardName; - - DevToConfig[i].GDev.busID = xnfalloc(16); - xf86FormatPciBusNumber(pVideo->bus, busnum); - sprintf(DevToConfig[i].GDev.busID, "PCI:%s:%d:%d", - busnum, pVideo->dev, pVideo->func); - - DevToConfig[i].GDev.chipID = pVideo->device_id; - DevToConfig[i].GDev.chipRev = pVideo->revision; - - if (*chipset < 0) { - *chipset = (pVideo->vendor_id << 16) | pVideo->device_id; - } -} - -static void -bus_sbus_newdev_configure(void *busData, int i) -{ -#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) - char *promPath = NULL; - DevToConfig[i].sVideo = (sbusDevicePtr) busData; - DevToConfig[i].GDev.identifier = DevToConfig[i].sVideo->descr; - if (sparcPromInit() >= 0) { - promPath = sparcPromNode2Pathname(&DevToConfig[i].sVideo->node); - sparcPromClose(); - } - if (promPath) { - DevToConfig[i].GDev.busID = xnfalloc(strlen(promPath) + 6); - sprintf(DevToConfig[i].GDev.busID, "SBUS:%s", promPath); - xfree(promPath); - } else { - DevToConfig[i].GDev.busID = xnfalloc(12); - sprintf(DevToConfig[i].GDev.busID, "SBUS:fb%d", - DevToConfig[i].sVideo->fbNum); - } -#endif -} - -/* - * This is called by the driver, either through xf86Match???Instances() or - * directly. We allocate a GDevRec and fill it in as much as we can, letting - * the caller fill in the rest and/or change it as it sees fit. - */ -GDevPtr -xf86AddBusDeviceToConfigure(const char *driver, BusType bus, void *busData, int chipset) -{ - int ret, i, j; - - if (!xf86DoConfigure || !xf86DoConfigurePass1) - return NULL; - - /* Check for duplicates */ - switch (bus) { - case BUS_PCI: - ret = bus_pci_configure(busData); - break; - case BUS_SBUS: - ret = bus_sbus_configure(busData); - break; - default: - return NULL; - } - - if (ret == 0) - goto out; - - /* Allocate new structure occurrence */ - i = nDevToConfig++; - DevToConfig = - xnfrealloc(DevToConfig, nDevToConfig * sizeof(DevToConfigRec)); - memset(DevToConfig + i, 0, sizeof(DevToConfigRec)); - - DevToConfig[i].GDev.chipID = - DevToConfig[i].GDev.chipRev = DevToConfig[i].GDev.irq = -1; - - DevToConfig[i].iDriver = CurrentDriver; - - /* Fill in what we know, converting the driver name to lower case */ - DevToConfig[i].GDev.driver = xnfalloc(strlen(driver) + 1); - for (j = 0; (DevToConfig[i].GDev.driver[j] = tolower(driver[j])); j++); - - switch (bus) { - case BUS_PCI: - bus_pci_newdev_configure(busData, i, &chipset); - break; - case BUS_SBUS: - bus_sbus_newdev_configure(busData, i); - break; - default: - break; - } - - /* Get driver's available options */ - if (xf86DriverList[CurrentDriver]->AvailableOptions) - DevToConfig[i].GDev.options = (OptionInfoPtr) - (*xf86DriverList[CurrentDriver]->AvailableOptions)(chipset, - bus); - - return &DevToConfig[i].GDev; - -out: - return NULL; -} - -static XF86ConfInputPtr -configureInputSection (void) -{ - XF86ConfInputPtr mouse = NULL; - parsePrologue (XF86ConfInputPtr, XF86ConfInputRec) - - ptr->inp_identifier = "Keyboard0"; - ptr->inp_driver = "kbd"; - ptr->list.next = NULL; - - /* Crude mechanism to auto-detect mouse (os dependent) */ - { - int fd; -#ifdef WSCONS_SUPPORT - fd = open("/dev/wsmouse", 0); - if (fd >= 0) { - DFLT_MOUSE_DEV = "/dev/wsmouse"; - DFLT_MOUSE_PROTO = "wsmouse"; - close(fd); - } else { - ErrorF("cannot open /dev/wsmouse\n"); - } -#endif - -#ifndef __SCO__ - fd = open(DFLT_MOUSE_DEV, 0); - if (fd != -1) { - foundMouse = TRUE; - close(fd); - } -#else - foundMouse = TRUE; -#endif - } - - mouse = calloc(1, sizeof(XF86ConfInputRec)); - mouse->inp_identifier = "Mouse0"; - mouse->inp_driver = "mouse"; - mouse->inp_option_lst = - xf86addNewOption(mouse->inp_option_lst, xstrdup("Protocol"), - xstrdup(DFLT_MOUSE_PROTO)); -#ifndef __SCO__ - mouse->inp_option_lst = - xf86addNewOption(mouse->inp_option_lst, xstrdup("Device"), - xstrdup(DFLT_MOUSE_DEV)); -#endif - mouse->inp_option_lst = - xf86addNewOption(mouse->inp_option_lst, xstrdup("ZAxisMapping"), - xstrdup("4 5 6 7")); - ptr = (XF86ConfInputPtr)xf86addListItem((glp)ptr, (glp)mouse); - return ptr; -} - -static XF86ConfScreenPtr -configureScreenSection (int screennum) -{ - int i; - int depths[] = { 1, 4, 8, 15, 16, 24/*, 32*/ }; - parsePrologue (XF86ConfScreenPtr, XF86ConfScreenRec) - - ptr->scrn_identifier = malloc(18); - sprintf(ptr->scrn_identifier, "Screen%d", screennum); - ptr->scrn_monitor_str = malloc(19); - sprintf(ptr->scrn_monitor_str, "Monitor%d", screennum); - ptr->scrn_device_str = malloc(16); - sprintf(ptr->scrn_device_str, "Card%d", screennum); - - for (i=0; i<sizeof(depths)/sizeof(depths[0]); i++) - { - XF86ConfDisplayPtr display; - - display = calloc(1, sizeof(XF86ConfDisplayRec)); - display->disp_depth = depths[i]; - display->disp_black.red = display->disp_white.red = -1; - display->disp_black.green = display->disp_white.green = -1; - display->disp_black.blue = display->disp_white.blue = -1; - ptr->scrn_display_lst = (XF86ConfDisplayPtr)xf86addListItem( - (glp)ptr->scrn_display_lst, (glp)display); - } - - return ptr; -} - -static const char* -optionTypeToSting(OptionValueType type) -{ - switch (type) { - case OPTV_NONE: - return ""; - case OPTV_INTEGER: - return "<i>"; - case OPTV_STRING: - return "<str>"; - case OPTV_ANYSTR: - return "[<str>]"; - case OPTV_REAL: - return "<f>"; - case OPTV_BOOLEAN: - return "[<bool>]"; - case OPTV_FREQ: - return "<freq>"; - default: - return ""; - } -} - -static XF86ConfDevicePtr -configureDeviceSection (int screennum) -{ - char identifier[16]; - OptionInfoPtr p; - int i = 0; - parsePrologue (XF86ConfDevicePtr, XF86ConfDeviceRec) - - /* Move device info to parser structure */ - sprintf(identifier, "Card%d", screennum); - ptr->dev_identifier = strdup(identifier); -/* ptr->dev_identifier = DevToConfig[screennum].GDev.identifier;*/ - ptr->dev_vendor = DevToConfig[screennum].GDev.vendor; - ptr->dev_board = DevToConfig[screennum].GDev.board; - ptr->dev_chipset = DevToConfig[screennum].GDev.chipset; - ptr->dev_busid = DevToConfig[screennum].GDev.busID; - ptr->dev_driver = DevToConfig[screennum].GDev.driver; - ptr->dev_ramdac = DevToConfig[screennum].GDev.ramdac; - for (i = 0; (i < MAXDACSPEEDS) && (i < CONF_MAXDACSPEEDS); i++) - ptr->dev_dacSpeeds[i] = DevToConfig[screennum].GDev.dacSpeeds[i]; - ptr->dev_videoram = DevToConfig[screennum].GDev.videoRam; - ptr->dev_textclockfreq = DevToConfig[screennum].GDev.textClockFreq; - ptr->dev_bios_base = DevToConfig[screennum].GDev.BiosBase; - ptr->dev_mem_base = DevToConfig[screennum].GDev.MemBase; - ptr->dev_io_base = DevToConfig[screennum].GDev.IOBase; - ptr->dev_clockchip = DevToConfig[screennum].GDev.clockchip; - for (i = 0; (i < MAXCLOCKS) && (i < DevToConfig[screennum].GDev.numclocks); i++) - ptr->dev_clock[i] = DevToConfig[screennum].GDev.clock[i]; - ptr->dev_clocks = i; - ptr->dev_chipid = DevToConfig[screennum].GDev.chipID; - ptr->dev_chiprev = DevToConfig[screennum].GDev.chipRev; - ptr->dev_irq = DevToConfig[screennum].GDev.irq; - - /* Make sure older drivers don't segv */ - if (DevToConfig[screennum].GDev.options) { - /* Fill in the available driver options for people to use */ - const char *descrip = - " ### Available Driver options are:-\n" - " ### Values: <i>: integer, <f>: float, " - "<bool>: \"True\"/\"False\",\n" - " ### <string>: \"String\", <freq>: \"<f> Hz/kHz/MHz\"\n" - " ### [arg]: arg optional\n"; - ptr->dev_comment = xstrdup(descrip); - if (ptr->dev_comment) { - for (p = DevToConfig[screennum].GDev.options; - p->name != NULL; p++) { - char *p_e; - const char *prefix = " #Option "; - const char *middle = " \t# "; - const char *suffix = "\n"; - const char *opttype = optionTypeToSting(p->type); - char *optname; - int len = strlen(ptr->dev_comment) + strlen(prefix) + - strlen(middle) + strlen(suffix) + 1; - - optname = xalloc(strlen(p->name) + 2 + 1); - if (!optname) - break; - sprintf(optname, "\"%s\"", p->name); - - len += max(20, strlen(optname)); - len += strlen(opttype); - - ptr->dev_comment = xrealloc(ptr->dev_comment, len); - if (!ptr->dev_comment) - break; - p_e = ptr->dev_comment + strlen(ptr->dev_comment); - sprintf(p_e, "%s%-20s%s%s%s", prefix, optname, middle, - opttype, suffix); - xfree(optname); - } - } - } - - return ptr; -} - -static XF86ConfLayoutPtr -configureLayoutSection (void) -{ - int scrnum = 0; - parsePrologue (XF86ConfLayoutPtr, XF86ConfLayoutRec) - - ptr->lay_identifier = "X.org Configured"; - - { - XF86ConfInputrefPtr iptr; - - iptr = malloc (sizeof (XF86ConfInputrefRec)); - iptr->list.next = NULL; - iptr->iref_option_lst = NULL; - iptr->iref_inputdev_str = "Mouse0"; - iptr->iref_option_lst = - xf86addNewOption (iptr->iref_option_lst, xstrdup("CorePointer"), NULL); - ptr->lay_input_lst = (XF86ConfInputrefPtr) - xf86addListItem ((glp) ptr->lay_input_lst, (glp) iptr); - } - - { - XF86ConfInputrefPtr iptr; - - iptr = malloc (sizeof (XF86ConfInputrefRec)); - iptr->list.next = NULL; - iptr->iref_option_lst = NULL; - iptr->iref_inputdev_str = "Keyboard0"; - iptr->iref_option_lst = - xf86addNewOption (iptr->iref_option_lst, xstrdup("CoreKeyboard"), NULL); - ptr->lay_input_lst = (XF86ConfInputrefPtr) - xf86addListItem ((glp) ptr->lay_input_lst, (glp) iptr); - } - - for (scrnum = 0; scrnum < nDevToConfig; scrnum++) { - XF86ConfAdjacencyPtr aptr; - - aptr = malloc (sizeof (XF86ConfAdjacencyRec)); - aptr->list.next = NULL; - aptr->adj_x = 0; - aptr->adj_y = 0; - aptr->adj_scrnum = scrnum; - aptr->adj_screen_str = xnfalloc(18); - sprintf(aptr->adj_screen_str, "Screen%d", scrnum); - if (scrnum == 0) { - aptr->adj_where = CONF_ADJ_ABSOLUTE; - aptr->adj_refscreen = NULL; - } - else { - aptr->adj_where = CONF_ADJ_RIGHTOF; - aptr->adj_refscreen = xnfalloc(18); - sprintf(aptr->adj_refscreen, "Screen%d", scrnum - 1); - } - ptr->lay_adjacency_lst = - (XF86ConfAdjacencyPtr)xf86addListItem((glp)ptr->lay_adjacency_lst, - (glp)aptr); - } - - return ptr; -} - -static XF86ConfFlagsPtr -configureFlagsSection (void) -{ - parsePrologue (XF86ConfFlagsPtr, XF86ConfFlagsRec) - - return ptr; -} - -static XF86ConfModulePtr -configureModuleSection (void) -{ - char **elist, **el; - /* Find the list of extension & font modules. */ - const char *esubdirs[] = { - "extensions", - "fonts", - NULL - }; - parsePrologue (XF86ConfModulePtr, XF86ConfModuleRec) - - elist = LoaderListDirs(esubdirs, NULL); - if (elist) { - for (el = elist; *el; el++) { - XF86LoadPtr module; - - module = calloc(1, sizeof(XF86LoadRec)); - module->load_name = *el; - ptr->mod_load_lst = (XF86LoadPtr)xf86addListItem( - (glp)ptr->mod_load_lst, (glp)module); - } - xfree(elist); - } - - return ptr; -} - -static XF86ConfFilesPtr -configureFilesSection (void) -{ - parsePrologue (XF86ConfFilesPtr, XF86ConfFilesRec) - - if (xf86ModulePath) - ptr->file_modulepath = strdup(xf86ModulePath); - if (defaultFontPath) - ptr->file_fontpath = strdup(defaultFontPath); - - return ptr; -} - -static XF86ConfMonitorPtr -configureMonitorSection (int screennum) -{ - parsePrologue (XF86ConfMonitorPtr, XF86ConfMonitorRec) - - ptr->mon_identifier = malloc(19); - sprintf(ptr->mon_identifier, "Monitor%d", screennum); - ptr->mon_vendor = strdup("Monitor Vendor"); - ptr->mon_modelname = strdup("Monitor Model"); - - return ptr; -} - -/* Initialize Configure Monitor from Detailed Timing Block */ -static void handle_detailed_input(struct detailed_monitor_section *det_mon, - void *data) -{ - XF86ConfMonitorPtr ptr = (XF86ConfMonitorPtr) data; - - switch (det_mon->type) { - case DS_NAME: - ptr->mon_modelname = realloc(ptr->mon_modelname, - strlen((char*)(det_mon->section.name)) + - 1); - strcpy(ptr->mon_modelname, - (char*)(det_mon->section.name)); - break; - case DS_RANGES: - ptr->mon_hsync[ptr->mon_n_hsync].lo = - det_mon->section.ranges.min_h; - ptr->mon_hsync[ptr->mon_n_hsync].hi = - det_mon->section.ranges.max_h; - ptr->mon_n_vrefresh = 1; - ptr->mon_vrefresh[ptr->mon_n_hsync].lo = - det_mon->section.ranges.min_v; - ptr->mon_vrefresh[ptr->mon_n_hsync].hi = - det_mon->section.ranges.max_v; - ptr->mon_n_hsync++; - default: - break; - } -} - -static XF86ConfMonitorPtr -configureDDCMonitorSection (int screennum) -{ - int len, mon_width, mon_height; -#define displaySizeMaxLen 80 - char displaySize_string[displaySizeMaxLen]; - int displaySizeLen; - - parsePrologue (XF86ConfMonitorPtr, XF86ConfMonitorRec) - - ptr->mon_identifier = malloc(19); - sprintf(ptr->mon_identifier, "Monitor%d", screennum); - ptr->mon_vendor = strdup(ConfiguredMonitor->vendor.name); - ptr->mon_modelname = malloc(12); - sprintf(ptr->mon_modelname, "%x", ConfiguredMonitor->vendor.prod_id); - - /* features in centimetres, we want millimetres */ - mon_width = 10 * ConfiguredMonitor->features.hsize ; - mon_height = 10 * ConfiguredMonitor->features.vsize ; - -#ifdef CONFIGURE_DISPLAYSIZE - ptr->mon_width = mon_width; - ptr->mon_height = mon_height; -#else - if (mon_width && mon_height) { - /* when values available add DisplaySize option AS A COMMENT */ - - displaySizeLen = snprintf(displaySize_string, displaySizeMaxLen, - "\t#DisplaySize\t%5d %5d\t# mm\n", - mon_width, mon_height); - - if (displaySizeLen>0 && displaySizeLen<displaySizeMaxLen) { - if (ptr->mon_comment) { - len = strlen(ptr->mon_comment); - } else { - len = 0; - } - if ((ptr->mon_comment = - realloc(ptr->mon_comment, len + strlen(displaySize_string) + 1))) { - strcpy(ptr->mon_comment + len, displaySize_string); - } - } - } -#endif /* def CONFIGURE_DISPLAYSIZE */ - - xf86ForEachDetailedBlock(ConfiguredMonitor, handle_detailed_input, - ptr); - - if (ConfiguredMonitor->features.dpms) { - ptr->mon_option_lst = xf86addNewOption(ptr->mon_option_lst, xstrdup("DPMS"), NULL); - } - - return ptr; -} - -#if !defined(PATH_MAX) -# define PATH_MAX 1024 -#endif - -void -DoConfigure(void) -{ - int i,j, screennum = -1; - char *home = NULL; - char filename[PATH_MAX]; - char *addslash = ""; - XF86ConfigPtr xf86config = NULL; - char **vlist, **vl; - int *dev2screen; - - vlist = xf86DriverlistFromCompile(); - - if (!vlist) { - ErrorF("Missing output drivers. Configuration failed.\n"); - goto bail; - } - - ErrorF("List of video drivers:\n"); - for (vl = vlist; *vl; vl++) - ErrorF("\t%s\n", *vl); - - /* Load all the drivers that were found. */ - xf86LoadModules(vlist, NULL); - - xfree(vlist); - - for (i = 0; i < xf86NumDrivers; i++) { - xorgHWFlags flags; - if (!xf86DriverList[i]->driverFunc - || !xf86DriverList[i]->driverFunc(NULL, - GET_REQUIRED_HW_INTERFACES, - &flags) - || NEED_IO_ENABLED(flags)) { - xorgHWAccess = TRUE; - break; - } - } - /* Enable full I/O access */ - if (xorgHWAccess) { - if(!xf86EnableIO()) - /* oops, we have failed */ - xorgHWAccess = FALSE; - } - - xf86FindPrimaryDevice(); - - /* Create XF86Config file structure */ - xf86config = calloc(1, sizeof(XF86ConfigRec)); - - /* Call all of the probe functions, reporting the results. */ - for (CurrentDriver = 0; CurrentDriver < xf86NumDrivers; CurrentDriver++) { - xorgHWFlags flags; - Bool found_screen; - DriverRec * const drv = xf86DriverList[CurrentDriver]; - - if (!xorgHWAccess) { - if (!drv->driverFunc - || !drv->driverFunc( NULL, GET_REQUIRED_HW_INTERFACES, &flags ) - || NEED_IO_ENABLED(flags)) - continue; - } - - found_screen = xf86CallDriverProbe( drv, TRUE ); - if ( found_screen && drv->Identify ) { - (*drv->Identify)(0); - } - } - - if (nDevToConfig <= 0) { - ErrorF("No devices to configure. Configuration failed.\n"); - goto bail; - } - - /* Add device, monitor and screen sections for detected devices */ - for (screennum = 0; screennum < nDevToConfig; screennum++) { - XF86ConfDevicePtr DevicePtr; - XF86ConfMonitorPtr MonitorPtr; - XF86ConfScreenPtr ScreenPtr; - - DevicePtr = configureDeviceSection(screennum); - xf86config->conf_device_lst = (XF86ConfDevicePtr)xf86addListItem( - (glp)xf86config->conf_device_lst, (glp)DevicePtr); - MonitorPtr = configureMonitorSection(screennum); - xf86config->conf_monitor_lst = (XF86ConfMonitorPtr)xf86addListItem( - (glp)xf86config->conf_monitor_lst, (glp)MonitorPtr); - ScreenPtr = configureScreenSection(screennum); - xf86config->conf_screen_lst = (XF86ConfScreenPtr)xf86addListItem( - (glp)xf86config->conf_screen_lst, (glp)ScreenPtr); - } - - xf86config->conf_files = configureFilesSection(); - xf86config->conf_modules = configureModuleSection(); - xf86config->conf_flags = configureFlagsSection(); - xf86config->conf_videoadaptor_lst = NULL; - xf86config->conf_modes_lst = NULL; - xf86config->conf_vendor_lst = NULL; - xf86config->conf_dri = NULL; - xf86config->conf_input_lst = configureInputSection(); - xf86config->conf_layout_lst = configureLayoutSection(); - - home = getenv("HOME"); - if ((home == NULL) || (home[0] == '\0')) { - home = "/"; - } else { - /* Determine if trailing slash is present or needed */ - int l = strlen(home); - - if (home[l-1] != '/') { - addslash = "/"; - } - } - - snprintf(filename, sizeof(filename), "%s%s" XF86CONFIGFILE ".new", - home, addslash); - - if (xf86writeConfigFile(filename, xf86config) == 0) { - xf86Msg(X_ERROR, "Unable to write config file: \"%s\": %s\n", - filename, strerror(errno)); - goto bail; - } - - xf86DoConfigurePass1 = FALSE; - /* Try to get DDC information filled in */ - xf86ConfigFile = filename; - if (xf86HandleConfigFile(FALSE) != CONFIG_OK) { - goto bail; - } - - xf86DoConfigurePass1 = FALSE; - - dev2screen = xnfcalloc(1,xf86NumDrivers*sizeof(int)); - - { - Bool *driverProbed = xnfcalloc(1,xf86NumDrivers*sizeof(Bool)); - for (screennum = 0; screennum < nDevToConfig; screennum++) { - int k,l,n,oldNumScreens; - - i = DevToConfig[screennum].iDriver; - - if (driverProbed[i]) continue; - driverProbed[i] = TRUE; - - oldNumScreens = xf86NumScreens; - - xf86CallDriverProbe( xf86DriverList[i], FALSE ); - - /* reorder */ - k = screennum > 0 ? screennum : 1; - for (l = oldNumScreens; l < xf86NumScreens; l++) { - /* is screen primary? */ - Bool primary = FALSE; - for (n = 0; n<xf86Screens[l]->numEntities; n++) { - if (xf86IsEntityPrimary(xf86Screens[l]->entityList[n])) { - dev2screen[0] = l; - primary = TRUE; - break; - } - } - if (primary) continue; - /* not primary: assign it to next device of same driver */ - /* - * NOTE: we assume that devices in DevToConfig - * and xf86Screens[] have the same order except - * for the primary device which always comes first. - */ - for (; k < nDevToConfig; k++) { - if (DevToConfig[k].iDriver == i) { - dev2screen[k++] = l; - break; - } - } - } - } - xfree(driverProbed); - } - - - if (nDevToConfig != xf86NumScreens) { - ErrorF("Number of created screens does not match number of detected" - " devices.\n Configuration failed.\n"); - goto bail; - } - - xf86PostProbe(); - xf86EntityInit(); - - for (j = 0; j < xf86NumScreens; j++) { - xf86Screens[j]->scrnIndex = j; - } - - xf86freeMonitorList(xf86config->conf_monitor_lst); - xf86config->conf_monitor_lst = NULL; - xf86freeScreenList(xf86config->conf_screen_lst); - xf86config->conf_screen_lst = NULL; - for (j = 0; j < xf86NumScreens; j++) { - XF86ConfMonitorPtr MonitorPtr; - XF86ConfScreenPtr ScreenPtr; - - ConfiguredMonitor = NULL; - - xf86EnableAccess(xf86Screens[dev2screen[j]]); - if ((*xf86Screens[dev2screen[j]]->PreInit)(xf86Screens[dev2screen[j]], - PROBE_DETECT) && - ConfiguredMonitor) { - MonitorPtr = configureDDCMonitorSection(j); - } else { - MonitorPtr = configureMonitorSection(j); - } - ScreenPtr = configureScreenSection(j); - xf86config->conf_monitor_lst = (XF86ConfMonitorPtr)xf86addListItem( - (glp)xf86config->conf_monitor_lst, (glp)MonitorPtr); - xf86config->conf_screen_lst = (XF86ConfScreenPtr)xf86addListItem( - (glp)xf86config->conf_screen_lst, (glp)ScreenPtr); - } - - if (xf86writeConfigFile(filename, xf86config) == 0) { - xf86Msg(X_ERROR, "Unable to write config file: \"%s\": %s\n", - filename, strerror(errno)); - goto bail; - } - - ErrorF("\n"); - -#ifdef __SCO__ - ErrorF("\n"__XSERVERNAME__ - " is using the kernel event driver to access the mouse.\n" - "If you wish to use the internal "__XSERVERNAME__ - " mouse drivers, please\n" - "edit the file and correct the Device.\n"); -#else /* !__SCO__ */ - if (!foundMouse) { - ErrorF("\n"__XSERVERNAME__" is not able to detect your mouse.\n" - "Edit the file and correct the Device.\n"); - } else { - ErrorF("\n"__XSERVERNAME__" detected your mouse at device %s.\n" - "Please check your config if the mouse is still not\n" - "operational, as by default "__XSERVERNAME__ - " tries to autodetect\n" - "the protocol.\n",DFLT_MOUSE_DEV); - } -#endif /* !__SCO__ */ - - if (xf86NumScreens > 1) { - ErrorF("\n"__XSERVERNAME__ - " has configured a multihead system, please check your config.\n"); - } - - ErrorF("\nYour %s file is %s\n\n", XF86CONFIGFILE ,filename); - ErrorF("To test the server, run 'X -config %s'\n\n", filename); - -bail: - OsCleanup(TRUE); - AbortDDX(); - fflush(stderr); - exit(0); -} +/* + * Copyright 2000-2002 by Alan Hourihane, Flint Mountain, North Wales. + * + * 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 Alan Hourihane not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Alan Hourihane makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ALAN HOURIHANE 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. + * + * Author: Alan Hourihane, alanh@fairlite.demon.co.uk + * + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86Config.h" +#include "xf86_OSlib.h" +#include "xf86Priv.h" +#define IN_XSERVER +#include "Configint.h" +#include "xf86DDC.h" +#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) +#include "xf86Bus.h" +#include "xf86Sbus.h" +#endif + +typedef struct _DevToConfig { + GDevRec GDev; + struct pci_device * pVideo; +#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) + sbusDevicePtr sVideo; +#endif + int iDriver; +} DevToConfigRec, *DevToConfigPtr; + +static DevToConfigPtr DevToConfig = NULL; +static int nDevToConfig = 0, CurrentDriver; + +xf86MonPtr ConfiguredMonitor; +Bool xf86DoConfigurePass1 = TRUE; +static Bool foundMouse = FALSE; + +#if defined(__SCO__) +static char *DFLT_MOUSE_PROTO = "OSMouse"; +#elif defined(__UNIXWARE__) +static char *DFLT_MOUSE_PROTO = "OSMouse"; +static char *DFLT_MOUSE_DEV = "/dev/mouse"; +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +static char *DFLT_MOUSE_DEV = "/dev/sysmouse"; +static char *DFLT_MOUSE_PROTO = "auto"; +#elif defined(linux) +static char DFLT_MOUSE_DEV[] = "/dev/input/mice"; +static char DFLT_MOUSE_PROTO[] = "auto"; +#else +static char *DFLT_MOUSE_DEV = "/dev/mouse"; +static char *DFLT_MOUSE_PROTO = "auto"; +#endif + +static Bool +bus_pci_configure(void *busData) +{ + int i; + struct pci_device * pVideo = NULL; + + pVideo = (struct pci_device *) busData; + for (i = 0; i < nDevToConfig; i++) + if (DevToConfig[i].pVideo && + (DevToConfig[i].pVideo->domain == pVideo->domain) && + (DevToConfig[i].pVideo->bus == pVideo->bus) && + (DevToConfig[i].pVideo->dev == pVideo->dev) && + (DevToConfig[i].pVideo->func == pVideo->func)) + return 0; + + return 1; +} + +static Bool +bus_sbus_configure(void *busData) +{ +#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) + int i; + + for (i = 0; i < nDevToConfig; i++) + if (DevToConfig[i].sVideo && + DevToConfig[i].sVideo->fbNum == ((sbusDevicePtr) busData)->fbNum) + return 0; + +#endif + return 1; +} + +static void +bus_pci_newdev_configure(void *busData, int i, int *chipset) +{ + const char *VendorName; + const char *CardName; + char busnum[8]; + struct pci_device * pVideo = NULL; + + pVideo = (struct pci_device *) busData; + + DevToConfig[i].pVideo = pVideo; + + VendorName = pci_device_get_vendor_name( pVideo ); + CardName = pci_device_get_device_name( pVideo ); + + if (!VendorName) { + VendorName = xnfalloc(15); + sprintf((char*)VendorName, "Unknown Vendor"); + } + + if (!CardName) { + CardName = xnfalloc(14); + sprintf((char*)CardName, "Unknown Board"); + } + + DevToConfig[i].GDev.identifier = + xnfalloc(strlen(VendorName) + strlen(CardName) + 2); + sprintf(DevToConfig[i].GDev.identifier, "%s %s", VendorName, CardName); + + DevToConfig[i].GDev.vendor = (char *)VendorName; + DevToConfig[i].GDev.board = (char *)CardName; + + DevToConfig[i].GDev.busID = xnfalloc(16); + xf86FormatPciBusNumber(pVideo->bus, busnum); + sprintf(DevToConfig[i].GDev.busID, "PCI:%s:%d:%d", + busnum, pVideo->dev, pVideo->func); + + DevToConfig[i].GDev.chipID = pVideo->device_id; + DevToConfig[i].GDev.chipRev = pVideo->revision; + + if (*chipset < 0) { + *chipset = (pVideo->vendor_id << 16) | pVideo->device_id; + } +} + +static void +bus_sbus_newdev_configure(void *busData, int i) +{ +#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) + char *promPath = NULL; + DevToConfig[i].sVideo = (sbusDevicePtr) busData; + DevToConfig[i].GDev.identifier = DevToConfig[i].sVideo->descr; + if (sparcPromInit() >= 0) { + promPath = sparcPromNode2Pathname(&DevToConfig[i].sVideo->node); + sparcPromClose(); + } + if (promPath) { + DevToConfig[i].GDev.busID = xnfalloc(strlen(promPath) + 6); + sprintf(DevToConfig[i].GDev.busID, "SBUS:%s", promPath); + free(promPath); + } else { + DevToConfig[i].GDev.busID = xnfalloc(12); + sprintf(DevToConfig[i].GDev.busID, "SBUS:fb%d", + DevToConfig[i].sVideo->fbNum); + } +#endif +} + +/* + * This is called by the driver, either through xf86Match???Instances() or + * directly. We allocate a GDevRec and fill it in as much as we can, letting + * the caller fill in the rest and/or change it as it sees fit. + */ +GDevPtr +xf86AddBusDeviceToConfigure(const char *driver, BusType bus, void *busData, int chipset) +{ + int ret, i, j; + + if (!xf86DoConfigure || !xf86DoConfigurePass1) + return NULL; + + /* Check for duplicates */ + switch (bus) { + case BUS_PCI: + ret = bus_pci_configure(busData); + break; + case BUS_SBUS: + ret = bus_sbus_configure(busData); + break; + default: + return NULL; + } + + if (ret == 0) + goto out; + + /* Allocate new structure occurrence */ + i = nDevToConfig++; + DevToConfig = + xnfrealloc(DevToConfig, nDevToConfig * sizeof(DevToConfigRec)); + memset(DevToConfig + i, 0, sizeof(DevToConfigRec)); + + DevToConfig[i].GDev.chipID = + DevToConfig[i].GDev.chipRev = DevToConfig[i].GDev.irq = -1; + + DevToConfig[i].iDriver = CurrentDriver; + + /* Fill in what we know, converting the driver name to lower case */ + DevToConfig[i].GDev.driver = xnfalloc(strlen(driver) + 1); + for (j = 0; (DevToConfig[i].GDev.driver[j] = tolower(driver[j])); j++); + + switch (bus) { + case BUS_PCI: + bus_pci_newdev_configure(busData, i, &chipset); + break; + case BUS_SBUS: + bus_sbus_newdev_configure(busData, i); + break; + default: + break; + } + + /* Get driver's available options */ + if (xf86DriverList[CurrentDriver]->AvailableOptions) + DevToConfig[i].GDev.options = (OptionInfoPtr) + (*xf86DriverList[CurrentDriver]->AvailableOptions)(chipset, + bus); + + return &DevToConfig[i].GDev; + +out: + return NULL; +} + +static XF86ConfInputPtr +configureInputSection (void) +{ + XF86ConfInputPtr mouse = NULL; + parsePrologue (XF86ConfInputPtr, XF86ConfInputRec) + + ptr->inp_identifier = "Keyboard0"; + ptr->inp_driver = "kbd"; + ptr->list.next = NULL; + + /* Crude mechanism to auto-detect mouse (os dependent) */ + { + int fd; +#ifdef WSCONS_SUPPORT + fd = open("/dev/wsmouse", 0); + if (fd >= 0) { + DFLT_MOUSE_DEV = "/dev/wsmouse"; + DFLT_MOUSE_PROTO = "wsmouse"; + close(fd); + } else { + ErrorF("cannot open /dev/wsmouse\n"); + } +#endif + +#ifndef __SCO__ + fd = open(DFLT_MOUSE_DEV, 0); + if (fd != -1) { + foundMouse = TRUE; + close(fd); + } +#else + foundMouse = TRUE; +#endif + } + + mouse = calloc(1, sizeof(XF86ConfInputRec)); + mouse->inp_identifier = "Mouse0"; + mouse->inp_driver = "mouse"; + mouse->inp_option_lst = + xf86addNewOption(mouse->inp_option_lst, xstrdup("Protocol"), + xstrdup(DFLT_MOUSE_PROTO)); +#ifndef __SCO__ + mouse->inp_option_lst = + xf86addNewOption(mouse->inp_option_lst, xstrdup("Device"), + xstrdup(DFLT_MOUSE_DEV)); +#endif + mouse->inp_option_lst = + xf86addNewOption(mouse->inp_option_lst, xstrdup("ZAxisMapping"), + xstrdup("4 5 6 7")); + ptr = (XF86ConfInputPtr)xf86addListItem((glp)ptr, (glp)mouse); + return ptr; +} + +static XF86ConfScreenPtr +configureScreenSection (int screennum) +{ + int i; + int depths[] = { 1, 4, 8, 15, 16, 24/*, 32*/ }; + parsePrologue (XF86ConfScreenPtr, XF86ConfScreenRec) + + ptr->scrn_identifier = malloc(18); + sprintf(ptr->scrn_identifier, "Screen%d", screennum); + ptr->scrn_monitor_str = malloc(19); + sprintf(ptr->scrn_monitor_str, "Monitor%d", screennum); + ptr->scrn_device_str = malloc(16); + sprintf(ptr->scrn_device_str, "Card%d", screennum); + + for (i=0; i<sizeof(depths)/sizeof(depths[0]); i++) + { + XF86ConfDisplayPtr display; + + display = calloc(1, sizeof(XF86ConfDisplayRec)); + display->disp_depth = depths[i]; + display->disp_black.red = display->disp_white.red = -1; + display->disp_black.green = display->disp_white.green = -1; + display->disp_black.blue = display->disp_white.blue = -1; + ptr->scrn_display_lst = (XF86ConfDisplayPtr)xf86addListItem( + (glp)ptr->scrn_display_lst, (glp)display); + } + + return ptr; +} + +static const char* +optionTypeToSting(OptionValueType type) +{ + switch (type) { + case OPTV_NONE: + return ""; + case OPTV_INTEGER: + return "<i>"; + case OPTV_STRING: + return "<str>"; + case OPTV_ANYSTR: + return "[<str>]"; + case OPTV_REAL: + return "<f>"; + case OPTV_BOOLEAN: + return "[<bool>]"; + case OPTV_FREQ: + return "<freq>"; + default: + return ""; + } +} + +static XF86ConfDevicePtr +configureDeviceSection (int screennum) +{ + char identifier[16]; + OptionInfoPtr p; + int i = 0; + parsePrologue (XF86ConfDevicePtr, XF86ConfDeviceRec) + + /* Move device info to parser structure */ + sprintf(identifier, "Card%d", screennum); + ptr->dev_identifier = strdup(identifier); +/* ptr->dev_identifier = DevToConfig[screennum].GDev.identifier;*/ + ptr->dev_vendor = DevToConfig[screennum].GDev.vendor; + ptr->dev_board = DevToConfig[screennum].GDev.board; + ptr->dev_chipset = DevToConfig[screennum].GDev.chipset; + ptr->dev_busid = DevToConfig[screennum].GDev.busID; + ptr->dev_driver = DevToConfig[screennum].GDev.driver; + ptr->dev_ramdac = DevToConfig[screennum].GDev.ramdac; + for (i = 0; (i < MAXDACSPEEDS) && (i < CONF_MAXDACSPEEDS); i++) + ptr->dev_dacSpeeds[i] = DevToConfig[screennum].GDev.dacSpeeds[i]; + ptr->dev_videoram = DevToConfig[screennum].GDev.videoRam; + ptr->dev_textclockfreq = DevToConfig[screennum].GDev.textClockFreq; + ptr->dev_bios_base = DevToConfig[screennum].GDev.BiosBase; + ptr->dev_mem_base = DevToConfig[screennum].GDev.MemBase; + ptr->dev_io_base = DevToConfig[screennum].GDev.IOBase; + ptr->dev_clockchip = DevToConfig[screennum].GDev.clockchip; + for (i = 0; (i < MAXCLOCKS) && (i < DevToConfig[screennum].GDev.numclocks); i++) + ptr->dev_clock[i] = DevToConfig[screennum].GDev.clock[i]; + ptr->dev_clocks = i; + ptr->dev_chipid = DevToConfig[screennum].GDev.chipID; + ptr->dev_chiprev = DevToConfig[screennum].GDev.chipRev; + ptr->dev_irq = DevToConfig[screennum].GDev.irq; + + /* Make sure older drivers don't segv */ + if (DevToConfig[screennum].GDev.options) { + /* Fill in the available driver options for people to use */ + const char *descrip = + " ### Available Driver options are:-\n" + " ### Values: <i>: integer, <f>: float, " + "<bool>: \"True\"/\"False\",\n" + " ### <string>: \"String\", <freq>: \"<f> Hz/kHz/MHz\"\n" + " ### [arg]: arg optional\n"; + ptr->dev_comment = xstrdup(descrip); + if (ptr->dev_comment) { + for (p = DevToConfig[screennum].GDev.options; + p->name != NULL; p++) { + char *p_e; + const char *prefix = " #Option "; + const char *middle = " \t# "; + const char *suffix = "\n"; + const char *opttype = optionTypeToSting(p->type); + char *optname; + int len = strlen(ptr->dev_comment) + strlen(prefix) + + strlen(middle) + strlen(suffix) + 1; + + optname = malloc(strlen(p->name) + 2 + 1); + if (!optname) + break; + sprintf(optname, "\"%s\"", p->name); + + len += max(20, strlen(optname)); + len += strlen(opttype); + + ptr->dev_comment = realloc(ptr->dev_comment, len); + if (!ptr->dev_comment) + break; + p_e = ptr->dev_comment + strlen(ptr->dev_comment); + sprintf(p_e, "%s%-20s%s%s%s", prefix, optname, middle, + opttype, suffix); + free(optname); + } + } + } + + return ptr; +} + +static XF86ConfLayoutPtr +configureLayoutSection (void) +{ + int scrnum = 0; + parsePrologue (XF86ConfLayoutPtr, XF86ConfLayoutRec) + + ptr->lay_identifier = "X.org Configured"; + + { + XF86ConfInputrefPtr iptr; + + iptr = malloc (sizeof (XF86ConfInputrefRec)); + iptr->list.next = NULL; + iptr->iref_option_lst = NULL; + iptr->iref_inputdev_str = "Mouse0"; + iptr->iref_option_lst = + xf86addNewOption (iptr->iref_option_lst, xstrdup("CorePointer"), NULL); + ptr->lay_input_lst = (XF86ConfInputrefPtr) + xf86addListItem ((glp) ptr->lay_input_lst, (glp) iptr); + } + + { + XF86ConfInputrefPtr iptr; + + iptr = malloc (sizeof (XF86ConfInputrefRec)); + iptr->list.next = NULL; + iptr->iref_option_lst = NULL; + iptr->iref_inputdev_str = "Keyboard0"; + iptr->iref_option_lst = + xf86addNewOption (iptr->iref_option_lst, xstrdup("CoreKeyboard"), NULL); + ptr->lay_input_lst = (XF86ConfInputrefPtr) + xf86addListItem ((glp) ptr->lay_input_lst, (glp) iptr); + } + + for (scrnum = 0; scrnum < nDevToConfig; scrnum++) { + XF86ConfAdjacencyPtr aptr; + + aptr = malloc (sizeof (XF86ConfAdjacencyRec)); + aptr->list.next = NULL; + aptr->adj_x = 0; + aptr->adj_y = 0; + aptr->adj_scrnum = scrnum; + aptr->adj_screen_str = xnfalloc(18); + sprintf(aptr->adj_screen_str, "Screen%d", scrnum); + if (scrnum == 0) { + aptr->adj_where = CONF_ADJ_ABSOLUTE; + aptr->adj_refscreen = NULL; + } + else { + aptr->adj_where = CONF_ADJ_RIGHTOF; + aptr->adj_refscreen = xnfalloc(18); + sprintf(aptr->adj_refscreen, "Screen%d", scrnum - 1); + } + ptr->lay_adjacency_lst = + (XF86ConfAdjacencyPtr)xf86addListItem((glp)ptr->lay_adjacency_lst, + (glp)aptr); + } + + return ptr; +} + +static XF86ConfFlagsPtr +configureFlagsSection (void) +{ + parsePrologue (XF86ConfFlagsPtr, XF86ConfFlagsRec) + + return ptr; +} + +static XF86ConfModulePtr +configureModuleSection (void) +{ + char **elist, **el; + /* Find the list of extension & font modules. */ + const char *esubdirs[] = { + "extensions", + "fonts", + NULL + }; + parsePrologue (XF86ConfModulePtr, XF86ConfModuleRec) + + elist = LoaderListDirs(esubdirs, NULL); + if (elist) { + for (el = elist; *el; el++) { + XF86LoadPtr module; + + module = calloc(1, sizeof(XF86LoadRec)); + module->load_name = *el; + ptr->mod_load_lst = (XF86LoadPtr)xf86addListItem( + (glp)ptr->mod_load_lst, (glp)module); + } + free(elist); + } + + return ptr; +} + +static XF86ConfFilesPtr +configureFilesSection (void) +{ + parsePrologue (XF86ConfFilesPtr, XF86ConfFilesRec) + + if (xf86ModulePath) + ptr->file_modulepath = strdup(xf86ModulePath); + if (defaultFontPath) + ptr->file_fontpath = strdup(defaultFontPath); + + return ptr; +} + +static XF86ConfMonitorPtr +configureMonitorSection (int screennum) +{ + parsePrologue (XF86ConfMonitorPtr, XF86ConfMonitorRec) + + ptr->mon_identifier = malloc(19); + sprintf(ptr->mon_identifier, "Monitor%d", screennum); + ptr->mon_vendor = strdup("Monitor Vendor"); + ptr->mon_modelname = strdup("Monitor Model"); + + return ptr; +} + +/* Initialize Configure Monitor from Detailed Timing Block */ +static void handle_detailed_input(struct detailed_monitor_section *det_mon, + void *data) +{ + XF86ConfMonitorPtr ptr = (XF86ConfMonitorPtr) data; + + switch (det_mon->type) { + case DS_NAME: + ptr->mon_modelname = realloc(ptr->mon_modelname, + strlen((char*)(det_mon->section.name)) + + 1); + strcpy(ptr->mon_modelname, + (char*)(det_mon->section.name)); + break; + case DS_RANGES: + ptr->mon_hsync[ptr->mon_n_hsync].lo = + det_mon->section.ranges.min_h; + ptr->mon_hsync[ptr->mon_n_hsync].hi = + det_mon->section.ranges.max_h; + ptr->mon_n_vrefresh = 1; + ptr->mon_vrefresh[ptr->mon_n_hsync].lo = + det_mon->section.ranges.min_v; + ptr->mon_vrefresh[ptr->mon_n_hsync].hi = + det_mon->section.ranges.max_v; + ptr->mon_n_hsync++; + default: + break; + } +} + +static XF86ConfMonitorPtr +configureDDCMonitorSection (int screennum) +{ + int len, mon_width, mon_height; +#define displaySizeMaxLen 80 + char displaySize_string[displaySizeMaxLen]; + int displaySizeLen; + + parsePrologue (XF86ConfMonitorPtr, XF86ConfMonitorRec) + + ptr->mon_identifier = malloc(19); + sprintf(ptr->mon_identifier, "Monitor%d", screennum); + ptr->mon_vendor = strdup(ConfiguredMonitor->vendor.name); + ptr->mon_modelname = malloc(12); + sprintf(ptr->mon_modelname, "%x", ConfiguredMonitor->vendor.prod_id); + + /* features in centimetres, we want millimetres */ + mon_width = 10 * ConfiguredMonitor->features.hsize ; + mon_height = 10 * ConfiguredMonitor->features.vsize ; + +#ifdef CONFIGURE_DISPLAYSIZE + ptr->mon_width = mon_width; + ptr->mon_height = mon_height; +#else + if (mon_width && mon_height) { + /* when values available add DisplaySize option AS A COMMENT */ + + displaySizeLen = snprintf(displaySize_string, displaySizeMaxLen, + "\t#DisplaySize\t%5d %5d\t# mm\n", + mon_width, mon_height); + + if (displaySizeLen>0 && displaySizeLen<displaySizeMaxLen) { + if (ptr->mon_comment) { + len = strlen(ptr->mon_comment); + } else { + len = 0; + } + if ((ptr->mon_comment = + realloc(ptr->mon_comment, len + strlen(displaySize_string) + 1))) { + strcpy(ptr->mon_comment + len, displaySize_string); + } + } + } +#endif /* def CONFIGURE_DISPLAYSIZE */ + + xf86ForEachDetailedBlock(ConfiguredMonitor, handle_detailed_input, + ptr); + + if (ConfiguredMonitor->features.dpms) { + ptr->mon_option_lst = xf86addNewOption(ptr->mon_option_lst, xstrdup("DPMS"), NULL); + } + + return ptr; +} + +#if !defined(PATH_MAX) +# define PATH_MAX 1024 +#endif + +void +DoConfigure(void) +{ + int i,j, screennum = -1; + char *home = NULL; + char filename[PATH_MAX]; + char *addslash = ""; + XF86ConfigPtr xf86config = NULL; + char **vlist, **vl; + int *dev2screen; + + vlist = xf86DriverlistFromCompile(); + + if (!vlist) { + ErrorF("Missing output drivers. Configuration failed.\n"); + goto bail; + } + + ErrorF("List of video drivers:\n"); + for (vl = vlist; *vl; vl++) + ErrorF("\t%s\n", *vl); + + /* Load all the drivers that were found. */ + xf86LoadModules(vlist, NULL); + + free(vlist); + + for (i = 0; i < xf86NumDrivers; i++) { + xorgHWFlags flags; + if (!xf86DriverList[i]->driverFunc + || !xf86DriverList[i]->driverFunc(NULL, + GET_REQUIRED_HW_INTERFACES, + &flags) + || NEED_IO_ENABLED(flags)) { + xorgHWAccess = TRUE; + break; + } + } + /* Enable full I/O access */ + if (xorgHWAccess) { + if(!xf86EnableIO()) + /* oops, we have failed */ + xorgHWAccess = FALSE; + } + + xf86FindPrimaryDevice(); + + /* Create XF86Config file structure */ + xf86config = calloc(1, sizeof(XF86ConfigRec)); + + /* Call all of the probe functions, reporting the results. */ + for (CurrentDriver = 0; CurrentDriver < xf86NumDrivers; CurrentDriver++) { + xorgHWFlags flags; + Bool found_screen; + DriverRec * const drv = xf86DriverList[CurrentDriver]; + + if (!xorgHWAccess) { + if (!drv->driverFunc + || !drv->driverFunc( NULL, GET_REQUIRED_HW_INTERFACES, &flags ) + || NEED_IO_ENABLED(flags)) + continue; + } + + found_screen = xf86CallDriverProbe( drv, TRUE ); + if ( found_screen && drv->Identify ) { + (*drv->Identify)(0); + } + } + + if (nDevToConfig <= 0) { + ErrorF("No devices to configure. Configuration failed.\n"); + goto bail; + } + + /* Add device, monitor and screen sections for detected devices */ + for (screennum = 0; screennum < nDevToConfig; screennum++) { + XF86ConfDevicePtr DevicePtr; + XF86ConfMonitorPtr MonitorPtr; + XF86ConfScreenPtr ScreenPtr; + + DevicePtr = configureDeviceSection(screennum); + xf86config->conf_device_lst = (XF86ConfDevicePtr)xf86addListItem( + (glp)xf86config->conf_device_lst, (glp)DevicePtr); + MonitorPtr = configureMonitorSection(screennum); + xf86config->conf_monitor_lst = (XF86ConfMonitorPtr)xf86addListItem( + (glp)xf86config->conf_monitor_lst, (glp)MonitorPtr); + ScreenPtr = configureScreenSection(screennum); + xf86config->conf_screen_lst = (XF86ConfScreenPtr)xf86addListItem( + (glp)xf86config->conf_screen_lst, (glp)ScreenPtr); + } + + xf86config->conf_files = configureFilesSection(); + xf86config->conf_modules = configureModuleSection(); + xf86config->conf_flags = configureFlagsSection(); + xf86config->conf_videoadaptor_lst = NULL; + xf86config->conf_modes_lst = NULL; + xf86config->conf_vendor_lst = NULL; + xf86config->conf_dri = NULL; + xf86config->conf_input_lst = configureInputSection(); + xf86config->conf_layout_lst = configureLayoutSection(); + + home = getenv("HOME"); + if ((home == NULL) || (home[0] == '\0')) { + home = "/"; + } else { + /* Determine if trailing slash is present or needed */ + int l = strlen(home); + + if (home[l-1] != '/') { + addslash = "/"; + } + } + + snprintf(filename, sizeof(filename), "%s%s" XF86CONFIGFILE ".new", + home, addslash); + + if (xf86writeConfigFile(filename, xf86config) == 0) { + xf86Msg(X_ERROR, "Unable to write config file: \"%s\": %s\n", + filename, strerror(errno)); + goto bail; + } + + xf86DoConfigurePass1 = FALSE; + /* Try to get DDC information filled in */ + xf86ConfigFile = filename; + if (xf86HandleConfigFile(FALSE) != CONFIG_OK) { + goto bail; + } + + xf86DoConfigurePass1 = FALSE; + + dev2screen = xnfcalloc(1,xf86NumDrivers*sizeof(int)); + + { + Bool *driverProbed = xnfcalloc(1,xf86NumDrivers*sizeof(Bool)); + for (screennum = 0; screennum < nDevToConfig; screennum++) { + int k,l,n,oldNumScreens; + + i = DevToConfig[screennum].iDriver; + + if (driverProbed[i]) continue; + driverProbed[i] = TRUE; + + oldNumScreens = xf86NumScreens; + + xf86CallDriverProbe( xf86DriverList[i], FALSE ); + + /* reorder */ + k = screennum > 0 ? screennum : 1; + for (l = oldNumScreens; l < xf86NumScreens; l++) { + /* is screen primary? */ + Bool primary = FALSE; + for (n = 0; n<xf86Screens[l]->numEntities; n++) { + if (xf86IsEntityPrimary(xf86Screens[l]->entityList[n])) { + dev2screen[0] = l; + primary = TRUE; + break; + } + } + if (primary) continue; + /* not primary: assign it to next device of same driver */ + /* + * NOTE: we assume that devices in DevToConfig + * and xf86Screens[] have the same order except + * for the primary device which always comes first. + */ + for (; k < nDevToConfig; k++) { + if (DevToConfig[k].iDriver == i) { + dev2screen[k++] = l; + break; + } + } + } + } + free(driverProbed); + } + + + if (nDevToConfig != xf86NumScreens) { + ErrorF("Number of created screens does not match number of detected" + " devices.\n Configuration failed.\n"); + goto bail; + } + + xf86PostProbe(); + xf86EntityInit(); + + for (j = 0; j < xf86NumScreens; j++) { + xf86Screens[j]->scrnIndex = j; + } + + xf86freeMonitorList(xf86config->conf_monitor_lst); + xf86config->conf_monitor_lst = NULL; + xf86freeScreenList(xf86config->conf_screen_lst); + xf86config->conf_screen_lst = NULL; + for (j = 0; j < xf86NumScreens; j++) { + XF86ConfMonitorPtr MonitorPtr; + XF86ConfScreenPtr ScreenPtr; + + ConfiguredMonitor = NULL; + + xf86EnableAccess(xf86Screens[dev2screen[j]]); + if ((*xf86Screens[dev2screen[j]]->PreInit)(xf86Screens[dev2screen[j]], + PROBE_DETECT) && + ConfiguredMonitor) { + MonitorPtr = configureDDCMonitorSection(j); + } else { + MonitorPtr = configureMonitorSection(j); + } + ScreenPtr = configureScreenSection(j); + xf86config->conf_monitor_lst = (XF86ConfMonitorPtr)xf86addListItem( + (glp)xf86config->conf_monitor_lst, (glp)MonitorPtr); + xf86config->conf_screen_lst = (XF86ConfScreenPtr)xf86addListItem( + (glp)xf86config->conf_screen_lst, (glp)ScreenPtr); + } + + if (xf86writeConfigFile(filename, xf86config) == 0) { + xf86Msg(X_ERROR, "Unable to write config file: \"%s\": %s\n", + filename, strerror(errno)); + goto bail; + } + + ErrorF("\n"); + +#ifdef __SCO__ + ErrorF("\n"__XSERVERNAME__ + " is using the kernel event driver to access the mouse.\n" + "If you wish to use the internal "__XSERVERNAME__ + " mouse drivers, please\n" + "edit the file and correct the Device.\n"); +#else /* !__SCO__ */ + if (!foundMouse) { + ErrorF("\n"__XSERVERNAME__" is not able to detect your mouse.\n" + "Edit the file and correct the Device.\n"); + } else { + ErrorF("\n"__XSERVERNAME__" detected your mouse at device %s.\n" + "Please check your config if the mouse is still not\n" + "operational, as by default "__XSERVERNAME__ + " tries to autodetect\n" + "the protocol.\n",DFLT_MOUSE_DEV); + } +#endif /* !__SCO__ */ + + if (xf86NumScreens > 1) { + ErrorF("\n"__XSERVERNAME__ + " has configured a multihead system, please check your config.\n"); + } + + ErrorF("\nYour %s file is %s\n\n", XF86CONFIGFILE ,filename); + ErrorF("To test the server, run 'X -config %s'\n\n", filename); + +bail: + OsCleanup(TRUE); + AbortDDX(); + fflush(stderr); + exit(0); +} diff --git a/xorg-server/hw/xfree86/common/xf86Cursor.c b/xorg-server/hw/xfree86/common/xf86Cursor.c index 6740faf65..76490e52d 100644 --- a/xorg-server/hw/xfree86/common/xf86Cursor.c +++ b/xorg-server/hw/xfree86/common/xf86Cursor.c @@ -1,862 +1,862 @@ -/* - * Copyright (c) 1994-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xmd.h> -#include "input.h" -#include "cursor.h" -#include "mipointer.h" -#include "scrnintstr.h" -#include "globals.h" - -#include "compiler.h" - -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSproc.h" - -#include <X11/extensions/XIproto.h> -#include "xf86Xinput.h" - -#ifdef XFreeXDGA -#include "dgaproc.h" -#endif - -typedef struct _xf86EdgeRec { - short screen; - short start; - short end; - DDXPointRec offset; - struct _xf86EdgeRec *next; -} xf86EdgeRec, *xf86EdgePtr; - -typedef struct { - xf86EdgePtr left, right, up, down; -} xf86ScreenLayoutRec, *xf86ScreenLayoutPtr; - -static Bool xf86CursorOffScreen(ScreenPtr *pScreen, int *x, int *y); -static void xf86CrossScreen(ScreenPtr pScreen, Bool entering); -static void xf86WarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); - -static void xf86PointerMoved(int scrnIndex, int x, int y); - -static miPointerScreenFuncRec xf86PointerScreenFuncs = { - xf86CursorOffScreen, - xf86CrossScreen, - xf86WarpCursor, - /* let miPointerInitialize take care of these */ - NULL, - NULL -}; - -static xf86ScreenLayoutRec xf86ScreenLayout[MAXSCREENS]; - -static Bool HardEdges; - -/* - * xf86InitViewport -- - * Initialize paning & zooming parameters, so that a driver must only - * check what resolutions are possible and whether the virtual area - * is valid if specified. - */ - -void -xf86InitViewport(ScrnInfoPtr pScr) -{ - - pScr->PointerMoved = xf86PointerMoved; - - /* - * Compute the initial Viewport if necessary - */ - if (pScr->display) { - if (pScr->display->frameX0 < 0) { - pScr->frameX0 = (pScr->virtualX - pScr->modes->HDisplay) / 2; - pScr->frameY0 = (pScr->virtualY - pScr->modes->VDisplay) / 2; - } else { - pScr->frameX0 = pScr->display->frameX0; - pScr->frameY0 = pScr->display->frameY0; - } - } - - pScr->frameX1 = pScr->frameX0 + pScr->modes->HDisplay - 1; - pScr->frameY1 = pScr->frameY0 + pScr->modes->VDisplay - 1; - - /* - * Now adjust the initial Viewport, so it lies within the virtual area - */ - if (pScr->frameX1 >= pScr->virtualX) - { - pScr->frameX0 = pScr->virtualX - pScr->modes->HDisplay; - pScr->frameX1 = pScr->frameX0 + pScr->modes->HDisplay - 1; - } - - if (pScr->frameY1 >= pScr->virtualY) - { - pScr->frameY0 = pScr->virtualY - pScr->modes->VDisplay; - pScr->frameY1 = pScr->frameY0 + pScr->modes->VDisplay - 1; - } -} - - -/* - * xf86SetViewport -- - * Scroll the visual part of the screen so the pointer is visible. - */ - -void -xf86SetViewport(ScreenPtr pScreen, int x, int y) -{ - ScrnInfoPtr pScr = XF86SCRNINFO(pScreen); - - (*pScr->PointerMoved)(pScreen->myNum, x, y); -} - - -static void -xf86PointerMoved(int scrnIndex, int x, int y) -{ - Bool frameChanged = FALSE; - ScrnInfoPtr pScr = xf86Screens[scrnIndex]; - - /* - * check wether (x,y) belongs to the visual part of the screen - * if not, change the base of the displayed frame accoring - */ - if ( pScr->frameX0 > x) { - pScr->frameX0 = x; - pScr->frameX1 = x + pScr->currentMode->HDisplay - 1; - frameChanged = TRUE ; - } - - if ( pScr->frameX1 < x) { - pScr->frameX1 = x + 1; - pScr->frameX0 = x - pScr->currentMode->HDisplay + 1; - frameChanged = TRUE ; - } - - if ( pScr->frameY0 > y) { - pScr->frameY0 = y; - pScr->frameY1 = y + pScr->currentMode->VDisplay - 1; - frameChanged = TRUE; - } - - if ( pScr->frameY1 < y) { - pScr->frameY1 = y; - pScr->frameY0 = y - pScr->currentMode->VDisplay + 1; - frameChanged = TRUE; - } - - if (frameChanged && pScr->AdjustFrame != NULL) - pScr->AdjustFrame(pScr->scrnIndex, pScr->frameX0, pScr->frameY0, 0); -} - -/* - * xf86LockZoom -- - * Enable/disable ZoomViewport - */ - -void -xf86LockZoom(ScreenPtr pScreen, Bool lock) -{ - XF86SCRNINFO(pScreen)->zoomLocked = lock; -} - -/* - * xf86SwitchMode -- - * This is called by both keyboard processing and the VidMode extension to - * set a new mode. - */ - -Bool -xf86SwitchMode(ScreenPtr pScreen, DisplayModePtr mode) -{ - ScrnInfoPtr pScr = XF86SCRNINFO(pScreen); - ScreenPtr pCursorScreen; - Bool Switched; - int px, py; - DeviceIntPtr dev, it; - - if (!pScr->vtSema || !mode || !pScr->SwitchMode) - return FALSE; - -#ifdef XFreeXDGA - if (DGAActive(pScr->scrnIndex)) - return FALSE; -#endif - - if (mode == pScr->currentMode) - return TRUE; - - if (mode->HDisplay > pScr->virtualX || mode->VDisplay > pScr->virtualY) - return FALSE; - - /* Let's take an educated guess for which pointer to take here. And about as - educated as it gets is to take the first pointer we find. - */ - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (IsPointerDevice(dev) && dev->spriteInfo->spriteOwner) - break; - } - - pCursorScreen = miPointerGetScreen(dev); - if (pScreen == pCursorScreen) - miPointerGetPosition(dev, &px, &py); - - xf86EnterServerState(SETUP); - Switched = (*pScr->SwitchMode)(pScr->scrnIndex, mode, 0); - if (Switched) { - pScr->currentMode = mode; - - /* - * Adjust frame for new display size. - * Frame is centered around cursor position if cursor is on same screen. - */ - if (pScreen == pCursorScreen) - pScr->frameX0 = px - (mode->HDisplay / 2) + 1; - else - pScr->frameX0 = (pScr->frameX0 + pScr->frameX1 + 1 - mode->HDisplay) / 2; - - if (pScr->frameX0 < 0) - pScr->frameX0 = 0; - - pScr->frameX1 = pScr->frameX0 + mode->HDisplay - 1; - if (pScr->frameX1 >= pScr->virtualX) { - pScr->frameX0 = pScr->virtualX - mode->HDisplay; - pScr->frameX1 = pScr->virtualX - 1; - } - - if (pScreen == pCursorScreen) - pScr->frameY0 = py - (mode->VDisplay / 2) + 1; - else - pScr->frameY0 = (pScr->frameY0 + pScr->frameY1 + 1 - mode->VDisplay) / 2; - - if (pScr->frameY0 < 0) - pScr->frameY0 = 0; - - pScr->frameY1 = pScr->frameY0 + mode->VDisplay - 1; - if (pScr->frameY1 >= pScr->virtualY) { - pScr->frameY0 = pScr->virtualY - mode->VDisplay; - pScr->frameY1 = pScr->virtualY - 1; - } - } - xf86EnterServerState(OPERATING); - - if (pScr->AdjustFrame) - (*pScr->AdjustFrame)(pScr->scrnIndex, pScr->frameX0, pScr->frameY0, 0); - - /* The original code centered the frame around the cursor if possible. - * Since this is hard to achieve with multiple cursors, we do the following: - * - center around the first pointer - * - move all other pointers to the nearest edge on the screen (or leave - * them unmodified if they are within the boundaries). - */ - if (pScreen == pCursorScreen) - { - xf86WarpCursor(dev, pScreen, px, py); - } - - for (it = inputInfo.devices; it; it = it->next) - { - if (it == dev) - continue; - - if (IsPointerDevice(it) && it->spriteInfo->spriteOwner) - { - pCursorScreen = miPointerGetScreen(it); - if (pScreen == pCursorScreen) - { - miPointerGetPosition(it, &px, &py); - if (px < pScr->frameX0) - px = pScr->frameX0; - else if (px > pScr->frameX1) - px = pScr->frameX1; - - if(py < pScr->frameY0) - py = pScr->frameY0; - else if(py > pScr->frameY1) - py = pScr->frameY1; - - xf86WarpCursor(it, pScreen, px, py); - } - } - } - - return Switched; -} - -/* - * xf86ZoomViewport -- - * Reinitialize the visual part of the screen for another mode. - */ - -void -xf86ZoomViewport(ScreenPtr pScreen, int zoom) -{ - ScrnInfoPtr pScr = XF86SCRNINFO(pScreen); - DisplayModePtr mode; - - if (pScr->zoomLocked || !(mode = pScr->currentMode)) - return; - - do { - if (zoom > 0) - mode = mode->next; - else - mode = mode->prev; - } while (mode != pScr->currentMode && !(mode->type & M_T_USERDEF)); - - (void)xf86SwitchMode(pScreen, mode); -} - - -static xf86EdgePtr -FindEdge(xf86EdgePtr edge, int val) -{ - while(edge && (edge->end <= val)) - edge = edge->next; - - if(edge && (edge->start <= val)) - return edge; - - return NULL; -} - -/* - * xf86CursorOffScreen -- - * Check whether it is necessary to switch to another screen - */ - -static Bool -xf86CursorOffScreen(ScreenPtr *pScreen, int *x, int *y) -{ - xf86EdgePtr edge; - int tmp; - - if(screenInfo.numScreens == 1) - return FALSE; - - if(*x < 0) { - tmp = *y; - if(tmp < 0) tmp = 0; - if(tmp >= (*pScreen)->height) tmp = (*pScreen)->height - 1; - - if((edge = xf86ScreenLayout[(*pScreen)->myNum].left)) - edge = FindEdge(edge, tmp); - - if(!edge) *x = 0; - else { - *x += edge->offset.x; - *y += edge->offset.y; - *pScreen = xf86Screens[edge->screen]->pScreen; - } - } - - if(*x >= (*pScreen)->width) { - tmp = *y; - if(tmp < 0) tmp = 0; - if(tmp >= (*pScreen)->height) tmp = (*pScreen)->height - 1; - - if((edge = xf86ScreenLayout[(*pScreen)->myNum].right)) - edge = FindEdge(edge, tmp); - - if(!edge) *x = (*pScreen)->width - 1; - else { - *x += edge->offset.x; - *y += edge->offset.y; - *pScreen = xf86Screens[edge->screen]->pScreen; - } - } - - if(*y < 0) { - tmp = *x; - if(tmp < 0) tmp = 0; - if(tmp >= (*pScreen)->width) tmp = (*pScreen)->width - 1; - - if((edge = xf86ScreenLayout[(*pScreen)->myNum].up)) - edge = FindEdge(edge, tmp); - - if(!edge) *y = 0; - else { - *x += edge->offset.x; - *y += edge->offset.y; - *pScreen = xf86Screens[edge->screen]->pScreen; - } - } - - if(*y >= (*pScreen)->height) { - tmp = *x; - if(tmp < 0) tmp = 0; - if(tmp >= (*pScreen)->width) tmp = (*pScreen)->width - 1; - - if((edge = xf86ScreenLayout[(*pScreen)->myNum].down)) - edge = FindEdge(edge, tmp); - - if(!edge) *y = (*pScreen)->height - 1; - else { - *x += edge->offset.x; - *y += edge->offset.y; - (*pScreen) = xf86Screens[edge->screen]->pScreen; - } - } - - -#if 0 - /* This presents problems for overlapping screens when - HardEdges is used. Have to think about the logic more */ - if((*x < 0) || (*x >= (*pScreen)->width) || - (*y < 0) || (*y >= (*pScreen)->height)) { - /* We may have crossed more than one screen */ - xf86CursorOffScreen(pScreen, x, y); - } -#endif - - return TRUE; -} - - - -/* - * xf86CrossScreen -- - * Switch to another screen - * - * Currently nothing special happens, but mi assumes the CrossScreen - * method exists. - */ - -static void -xf86CrossScreen (ScreenPtr pScreen, Bool entering) -{ -} - - -/* - * xf86WarpCursor -- - * Warp possible to another screen - */ - -/* ARGSUSED */ -static void -xf86WarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - int sigstate; - sigstate = xf86BlockSIGIO (); - miPointerWarpCursor(pDev, pScreen, x, y); - - xf86Info.currentScreen = pScreen; - xf86UnblockSIGIO (sigstate); -} - - -void * -xf86GetPointerScreenFuncs(void) -{ - return (void *)&xf86PointerScreenFuncs; -} - - -static xf86EdgePtr -AddEdge( - xf86EdgePtr edge, - short min, - short max, - short dx, - short dy, - short screen -){ - xf86EdgePtr pEdge = edge, pPrev = NULL, pNew; - - while(1) { - while(pEdge && (min >= pEdge->end)) { - pPrev = pEdge; - pEdge = pEdge->next; - } - - if(!pEdge) { - if(!(pNew = xalloc(sizeof(xf86EdgeRec)))) - break; - - pNew->screen = screen; - pNew->start = min; - pNew->end = max; - pNew->offset.x = dx; - pNew->offset.y = dy; - pNew->next = NULL; - - if(pPrev) - pPrev->next = pNew; - else - edge = pNew; - - break; - } else if (min < pEdge->start) { - if(!(pNew = xalloc(sizeof(xf86EdgeRec)))) - break; - - pNew->screen = screen; - pNew->start = min; - pNew->offset.x = dx; - pNew->offset.y = dy; - pNew->next = pEdge; - - if(pPrev) pPrev->next = pNew; - else edge = pNew; - - if(max <= pEdge->start) { - pNew->end = max; - break; - } else { - pNew->end = pEdge->start; - min = pEdge->end; - } - } else - min = pEdge->end; - - pPrev = pEdge; - pEdge = pEdge->next; - - if(max <= min) break; - } - - return edge; -} - -static void -FillOutEdge(xf86EdgePtr pEdge, int limit) -{ - xf86EdgePtr pNext; - int diff; - - if(pEdge->start > 0) pEdge->start = 0; - - while((pNext = pEdge->next)) { - diff = pNext->start - pEdge->end; - if(diff > 0) { - pEdge->end += diff >> 1; - pNext->start -= diff - (diff >> 1); - } - pEdge = pNext; - } - - if(pEdge->end < limit) - pEdge->end = limit; -} - -/* - * xf86InitOrigins() can deal with a maximum of 32 screens - * on 32 bit architectures, 64 on 64 bit architectures. - */ - -void -xf86InitOrigins(void) -{ - unsigned long screensLeft, prevScreensLeft, mask; - screenLayoutPtr screen; - ScreenPtr pScreen; - int x1, x2, y1, y2, left, right, top, bottom; - int i, j, ref, minX, minY, min, max; - xf86ScreenLayoutPtr pLayout; - Bool OldStyleConfig = FALSE; - - /* need to have this set up with a config file option */ - HardEdges = FALSE; - - bzero(xf86ScreenLayout, MAXSCREENS * sizeof(xf86ScreenLayoutRec)); - - screensLeft = prevScreensLeft = (1 << xf86NumScreens) - 1; - - while(1) { - for(mask = screensLeft, i = 0; mask; mask >>= 1, i++) { - if(!(mask & 1L)) continue; - - screen = &xf86ConfigLayout.screens[i]; - - if (screen->refscreen != NULL && - screen->refscreen->screennum >= xf86NumScreens) { - screensLeft &= ~(1 << i); - xf86Msg(X_WARNING, "Not including screen \"%s\" in origins calculation.\n", - screen->screen->id); - continue; - } - - switch(screen->where) { - case PosObsolete: - OldStyleConfig = TRUE; - pLayout = &xf86ScreenLayout[i]; - /* force edge lists */ - if(screen->left) { - ref = screen->left->screennum; - if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { - ErrorF("Referenced uninitialized screen in Layout!\n"); - break; - } - pLayout->left = AddEdge(pLayout->left, - 0, xf86Screens[i]->pScreen->height, - xf86Screens[ref]->pScreen->width, 0, ref); - } - if(screen->right) { - ref = screen->right->screennum; - if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { - ErrorF("Referenced uninitialized screen in Layout!\n"); - break; - } - pScreen = xf86Screens[i]->pScreen; - pLayout->right = AddEdge(pLayout->right, - 0, pScreen->height, -pScreen->width, 0, ref); - } - if(screen->top) { - ref = screen->top->screennum; - if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { - ErrorF("Referenced uninitialized screen in Layout!\n"); - break; - } - pLayout->up = AddEdge(pLayout->up, - 0, xf86Screens[i]->pScreen->width, - 0, xf86Screens[ref]->pScreen->height, ref); - } - if(screen->bottom) { - ref = screen->bottom->screennum; - if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { - ErrorF("Referenced uninitialized screen in Layout!\n"); - break; - } - pScreen = xf86Screens[i]->pScreen; - pLayout->down = AddEdge(pLayout->down, - 0, pScreen->width, 0, -pScreen->height, ref); - } - /* we could also try to place it based on those - relative locations if we wanted to */ - screen->x = screen->y = 0; - /* FALLTHROUGH */ - case PosAbsolute: - dixScreenOrigins[i].x = screen->x; - dixScreenOrigins[i].y = screen->y; - screensLeft &= ~(1 << i); - break; - case PosRelative: - ref = screen->refscreen->screennum; - if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { - ErrorF("Referenced uninitialized screen in Layout!\n"); - break; - } - if(screensLeft & (1 << ref)) break; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->x; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->y; - screensLeft &= ~(1 << i); - break; - case PosRightOf: - ref = screen->refscreen->screennum; - if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { - ErrorF("Referenced uninitialized screen in Layout!\n"); - break; - } - if(screensLeft & (1 << ref)) break; - pScreen = xf86Screens[ref]->pScreen; - dixScreenOrigins[i].x = - dixScreenOrigins[ref].x + pScreen->width; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y; - screensLeft &= ~(1 << i); - break; - case PosLeftOf: - ref = screen->refscreen->screennum; - if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { - ErrorF("Referenced uninitialized screen in Layout!\n"); - break; - } - if(screensLeft & (1 << ref)) break; - pScreen = xf86Screens[i]->pScreen; - dixScreenOrigins[i].x = - dixScreenOrigins[ref].x - pScreen->width; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y; - screensLeft &= ~(1 << i); - break; - case PosBelow: - ref = screen->refscreen->screennum; - if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { - ErrorF("Referenced uninitialized screen in Layout!\n"); - break; - } - if(screensLeft & (1 << ref)) break; - pScreen = xf86Screens[ref]->pScreen; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x; - dixScreenOrigins[i].y = - dixScreenOrigins[ref].y + pScreen->height; - screensLeft &= ~(1 << i); - break; - case PosAbove: - ref = screen->refscreen->screennum; - if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { - ErrorF("Referenced uninitialized screen in Layout!\n"); - break; - } - if(screensLeft & (1 << ref)) break; - pScreen = xf86Screens[i]->pScreen; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x; - dixScreenOrigins[i].y = - dixScreenOrigins[ref].y - pScreen->height; - screensLeft &= ~(1 << i); - break; - default: - ErrorF("Illegal placement keyword in Layout!\n"); - break; - } - - } - - if(!screensLeft) break; - - if(screensLeft == prevScreensLeft) { - /* All the remaining screens are referencing each other. - Assign a value to one of them and go through again */ - i = 0; - while(!((1 << i) & screensLeft)){ i++; } - - ref = xf86ConfigLayout.screens[i].refscreen->screennum; - dixScreenOrigins[ref].x = dixScreenOrigins[ref].y = 0; - screensLeft &= ~(1 << ref); - } - - prevScreensLeft = screensLeft; - } - - /* justify the topmost and leftmost to (0,0) */ - minX = dixScreenOrigins[0].x; - minY = dixScreenOrigins[0].y; - - for(i = 1; i < xf86NumScreens; i++) { - if(dixScreenOrigins[i].x < minX) - minX = dixScreenOrigins[i].x; - if(dixScreenOrigins[i].y < minY) - minY = dixScreenOrigins[i].y; - } - - if (minX || minY) { - for(i = 0; i < xf86NumScreens; i++) { - dixScreenOrigins[i].x -= minX; - dixScreenOrigins[i].y -= minY; - } - } - - - /* Create the edge lists */ - - if(!OldStyleConfig) { - for(i = 0; i < xf86NumScreens; i++) { - pLayout = &xf86ScreenLayout[i]; - - pScreen = xf86Screens[i]->pScreen; - - left = dixScreenOrigins[i].x; - right = left + pScreen->width; - top = dixScreenOrigins[i].y; - bottom = top + pScreen->height; - - for(j = 0; j < xf86NumScreens; j++) { - if(i == j) continue; - - x1 = dixScreenOrigins[j].x; - x2 = x1 + xf86Screens[j]->pScreen->width; - y1 = dixScreenOrigins[j].y; - y2 = y1 + xf86Screens[j]->pScreen->height; - - if((bottom > y1) && (top < y2)) { - min = y1 - top; - if(min < 0) min = 0; - max = pScreen->height - (bottom - y2); - if(max > pScreen->height) max = pScreen->height; - - if(((left - 1) >= x1) && ((left - 1) < x2)) - pLayout->left = AddEdge(pLayout->left, min, max, - dixScreenOrigins[i].x - dixScreenOrigins[j].x, - dixScreenOrigins[i].y - dixScreenOrigins[j].y, j); - - if((right >= x1) && (right < x2)) - pLayout->right = AddEdge(pLayout->right, min, max, - dixScreenOrigins[i].x - dixScreenOrigins[j].x, - dixScreenOrigins[i].y - dixScreenOrigins[j].y, j); - } - - - if((left < x2) && (right > x1)) { - min = x1 - left; - if(min < 0) min = 0; - max = pScreen->width - (right - x2); - if(max > pScreen->width) max = pScreen->width; - - if(((top - 1) >= y1) && ((top - 1) < y2)) - pLayout->up = AddEdge(pLayout->up, min, max, - dixScreenOrigins[i].x - dixScreenOrigins[j].x, - dixScreenOrigins[i].y - dixScreenOrigins[j].y, j); - - if((bottom >= y1) && (bottom < y2)) - pLayout->down = AddEdge(pLayout->down, min, max, - dixScreenOrigins[i].x - dixScreenOrigins[j].x, - dixScreenOrigins[i].y - dixScreenOrigins[j].y, j); - } - } - } - } - - if(!HardEdges && !OldStyleConfig) { - for(i = 0; i < xf86NumScreens; i++) { - pLayout = &xf86ScreenLayout[i]; - pScreen = xf86Screens[i]->pScreen; - if(pLayout->left) - FillOutEdge(pLayout->left, pScreen->height); - if(pLayout->right) - FillOutEdge(pLayout->right, pScreen->height); - if(pLayout->up) - FillOutEdge(pLayout->up, pScreen->width); - if(pLayout->down) - FillOutEdge(pLayout->down, pScreen->width); - } - } -} - -void -xf86ReconfigureLayout(void) -{ - int i; - - for (i = 0; i < MAXSCREENS; i++) { - xf86ScreenLayoutPtr sl = &xf86ScreenLayout[i]; - /* we don't have to zero these, xf86InitOrigins() takes care of that */ - if (sl->left) xfree(sl->left); - if (sl->right) xfree(sl->right); - if (sl->up) xfree(sl->up); - if (sl->down) xfree(sl->down); - } - - xf86InitOrigins(); -} - - +/* + * Copyright (c) 1994-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include "input.h" +#include "cursor.h" +#include "mipointer.h" +#include "scrnintstr.h" +#include "globals.h" + +#include "compiler.h" + +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSproc.h" + +#include <X11/extensions/XIproto.h> +#include "xf86Xinput.h" + +#ifdef XFreeXDGA +#include "dgaproc.h" +#endif + +typedef struct _xf86EdgeRec { + short screen; + short start; + short end; + DDXPointRec offset; + struct _xf86EdgeRec *next; +} xf86EdgeRec, *xf86EdgePtr; + +typedef struct { + xf86EdgePtr left, right, up, down; +} xf86ScreenLayoutRec, *xf86ScreenLayoutPtr; + +static Bool xf86CursorOffScreen(ScreenPtr *pScreen, int *x, int *y); +static void xf86CrossScreen(ScreenPtr pScreen, Bool entering); +static void xf86WarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); + +static void xf86PointerMoved(int scrnIndex, int x, int y); + +static miPointerScreenFuncRec xf86PointerScreenFuncs = { + xf86CursorOffScreen, + xf86CrossScreen, + xf86WarpCursor, + /* let miPointerInitialize take care of these */ + NULL, + NULL +}; + +static xf86ScreenLayoutRec xf86ScreenLayout[MAXSCREENS]; + +static Bool HardEdges; + +/* + * xf86InitViewport -- + * Initialize paning & zooming parameters, so that a driver must only + * check what resolutions are possible and whether the virtual area + * is valid if specified. + */ + +void +xf86InitViewport(ScrnInfoPtr pScr) +{ + + pScr->PointerMoved = xf86PointerMoved; + + /* + * Compute the initial Viewport if necessary + */ + if (pScr->display) { + if (pScr->display->frameX0 < 0) { + pScr->frameX0 = (pScr->virtualX - pScr->modes->HDisplay) / 2; + pScr->frameY0 = (pScr->virtualY - pScr->modes->VDisplay) / 2; + } else { + pScr->frameX0 = pScr->display->frameX0; + pScr->frameY0 = pScr->display->frameY0; + } + } + + pScr->frameX1 = pScr->frameX0 + pScr->modes->HDisplay - 1; + pScr->frameY1 = pScr->frameY0 + pScr->modes->VDisplay - 1; + + /* + * Now adjust the initial Viewport, so it lies within the virtual area + */ + if (pScr->frameX1 >= pScr->virtualX) + { + pScr->frameX0 = pScr->virtualX - pScr->modes->HDisplay; + pScr->frameX1 = pScr->frameX0 + pScr->modes->HDisplay - 1; + } + + if (pScr->frameY1 >= pScr->virtualY) + { + pScr->frameY0 = pScr->virtualY - pScr->modes->VDisplay; + pScr->frameY1 = pScr->frameY0 + pScr->modes->VDisplay - 1; + } +} + + +/* + * xf86SetViewport -- + * Scroll the visual part of the screen so the pointer is visible. + */ + +void +xf86SetViewport(ScreenPtr pScreen, int x, int y) +{ + ScrnInfoPtr pScr = XF86SCRNINFO(pScreen); + + (*pScr->PointerMoved)(pScreen->myNum, x, y); +} + + +static void +xf86PointerMoved(int scrnIndex, int x, int y) +{ + Bool frameChanged = FALSE; + ScrnInfoPtr pScr = xf86Screens[scrnIndex]; + + /* + * check wether (x,y) belongs to the visual part of the screen + * if not, change the base of the displayed frame accoring + */ + if ( pScr->frameX0 > x) { + pScr->frameX0 = x; + pScr->frameX1 = x + pScr->currentMode->HDisplay - 1; + frameChanged = TRUE ; + } + + if ( pScr->frameX1 < x) { + pScr->frameX1 = x + 1; + pScr->frameX0 = x - pScr->currentMode->HDisplay + 1; + frameChanged = TRUE ; + } + + if ( pScr->frameY0 > y) { + pScr->frameY0 = y; + pScr->frameY1 = y + pScr->currentMode->VDisplay - 1; + frameChanged = TRUE; + } + + if ( pScr->frameY1 < y) { + pScr->frameY1 = y; + pScr->frameY0 = y - pScr->currentMode->VDisplay + 1; + frameChanged = TRUE; + } + + if (frameChanged && pScr->AdjustFrame != NULL) + pScr->AdjustFrame(pScr->scrnIndex, pScr->frameX0, pScr->frameY0, 0); +} + +/* + * xf86LockZoom -- + * Enable/disable ZoomViewport + */ + +void +xf86LockZoom(ScreenPtr pScreen, Bool lock) +{ + XF86SCRNINFO(pScreen)->zoomLocked = lock; +} + +/* + * xf86SwitchMode -- + * This is called by both keyboard processing and the VidMode extension to + * set a new mode. + */ + +Bool +xf86SwitchMode(ScreenPtr pScreen, DisplayModePtr mode) +{ + ScrnInfoPtr pScr = XF86SCRNINFO(pScreen); + ScreenPtr pCursorScreen; + Bool Switched; + int px, py; + DeviceIntPtr dev, it; + + if (!pScr->vtSema || !mode || !pScr->SwitchMode) + return FALSE; + +#ifdef XFreeXDGA + if (DGAActive(pScr->scrnIndex)) + return FALSE; +#endif + + if (mode == pScr->currentMode) + return TRUE; + + if (mode->HDisplay > pScr->virtualX || mode->VDisplay > pScr->virtualY) + return FALSE; + + /* Let's take an educated guess for which pointer to take here. And about as + educated as it gets is to take the first pointer we find. + */ + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (IsPointerDevice(dev) && dev->spriteInfo->spriteOwner) + break; + } + + pCursorScreen = miPointerGetScreen(dev); + if (pScreen == pCursorScreen) + miPointerGetPosition(dev, &px, &py); + + xf86EnterServerState(SETUP); + Switched = (*pScr->SwitchMode)(pScr->scrnIndex, mode, 0); + if (Switched) { + pScr->currentMode = mode; + + /* + * Adjust frame for new display size. + * Frame is centered around cursor position if cursor is on same screen. + */ + if (pScreen == pCursorScreen) + pScr->frameX0 = px - (mode->HDisplay / 2) + 1; + else + pScr->frameX0 = (pScr->frameX0 + pScr->frameX1 + 1 - mode->HDisplay) / 2; + + if (pScr->frameX0 < 0) + pScr->frameX0 = 0; + + pScr->frameX1 = pScr->frameX0 + mode->HDisplay - 1; + if (pScr->frameX1 >= pScr->virtualX) { + pScr->frameX0 = pScr->virtualX - mode->HDisplay; + pScr->frameX1 = pScr->virtualX - 1; + } + + if (pScreen == pCursorScreen) + pScr->frameY0 = py - (mode->VDisplay / 2) + 1; + else + pScr->frameY0 = (pScr->frameY0 + pScr->frameY1 + 1 - mode->VDisplay) / 2; + + if (pScr->frameY0 < 0) + pScr->frameY0 = 0; + + pScr->frameY1 = pScr->frameY0 + mode->VDisplay - 1; + if (pScr->frameY1 >= pScr->virtualY) { + pScr->frameY0 = pScr->virtualY - mode->VDisplay; + pScr->frameY1 = pScr->virtualY - 1; + } + } + xf86EnterServerState(OPERATING); + + if (pScr->AdjustFrame) + (*pScr->AdjustFrame)(pScr->scrnIndex, pScr->frameX0, pScr->frameY0, 0); + + /* The original code centered the frame around the cursor if possible. + * Since this is hard to achieve with multiple cursors, we do the following: + * - center around the first pointer + * - move all other pointers to the nearest edge on the screen (or leave + * them unmodified if they are within the boundaries). + */ + if (pScreen == pCursorScreen) + { + xf86WarpCursor(dev, pScreen, px, py); + } + + for (it = inputInfo.devices; it; it = it->next) + { + if (it == dev) + continue; + + if (IsPointerDevice(it) && it->spriteInfo->spriteOwner) + { + pCursorScreen = miPointerGetScreen(it); + if (pScreen == pCursorScreen) + { + miPointerGetPosition(it, &px, &py); + if (px < pScr->frameX0) + px = pScr->frameX0; + else if (px > pScr->frameX1) + px = pScr->frameX1; + + if(py < pScr->frameY0) + py = pScr->frameY0; + else if(py > pScr->frameY1) + py = pScr->frameY1; + + xf86WarpCursor(it, pScreen, px, py); + } + } + } + + return Switched; +} + +/* + * xf86ZoomViewport -- + * Reinitialize the visual part of the screen for another mode. + */ + +void +xf86ZoomViewport(ScreenPtr pScreen, int zoom) +{ + ScrnInfoPtr pScr = XF86SCRNINFO(pScreen); + DisplayModePtr mode; + + if (pScr->zoomLocked || !(mode = pScr->currentMode)) + return; + + do { + if (zoom > 0) + mode = mode->next; + else + mode = mode->prev; + } while (mode != pScr->currentMode && !(mode->type & M_T_USERDEF)); + + (void)xf86SwitchMode(pScreen, mode); +} + + +static xf86EdgePtr +FindEdge(xf86EdgePtr edge, int val) +{ + while(edge && (edge->end <= val)) + edge = edge->next; + + if(edge && (edge->start <= val)) + return edge; + + return NULL; +} + +/* + * xf86CursorOffScreen -- + * Check whether it is necessary to switch to another screen + */ + +static Bool +xf86CursorOffScreen(ScreenPtr *pScreen, int *x, int *y) +{ + xf86EdgePtr edge; + int tmp; + + if(screenInfo.numScreens == 1) + return FALSE; + + if(*x < 0) { + tmp = *y; + if(tmp < 0) tmp = 0; + if(tmp >= (*pScreen)->height) tmp = (*pScreen)->height - 1; + + if((edge = xf86ScreenLayout[(*pScreen)->myNum].left)) + edge = FindEdge(edge, tmp); + + if(!edge) *x = 0; + else { + *x += edge->offset.x; + *y += edge->offset.y; + *pScreen = xf86Screens[edge->screen]->pScreen; + } + } + + if(*x >= (*pScreen)->width) { + tmp = *y; + if(tmp < 0) tmp = 0; + if(tmp >= (*pScreen)->height) tmp = (*pScreen)->height - 1; + + if((edge = xf86ScreenLayout[(*pScreen)->myNum].right)) + edge = FindEdge(edge, tmp); + + if(!edge) *x = (*pScreen)->width - 1; + else { + *x += edge->offset.x; + *y += edge->offset.y; + *pScreen = xf86Screens[edge->screen]->pScreen; + } + } + + if(*y < 0) { + tmp = *x; + if(tmp < 0) tmp = 0; + if(tmp >= (*pScreen)->width) tmp = (*pScreen)->width - 1; + + if((edge = xf86ScreenLayout[(*pScreen)->myNum].up)) + edge = FindEdge(edge, tmp); + + if(!edge) *y = 0; + else { + *x += edge->offset.x; + *y += edge->offset.y; + *pScreen = xf86Screens[edge->screen]->pScreen; + } + } + + if(*y >= (*pScreen)->height) { + tmp = *x; + if(tmp < 0) tmp = 0; + if(tmp >= (*pScreen)->width) tmp = (*pScreen)->width - 1; + + if((edge = xf86ScreenLayout[(*pScreen)->myNum].down)) + edge = FindEdge(edge, tmp); + + if(!edge) *y = (*pScreen)->height - 1; + else { + *x += edge->offset.x; + *y += edge->offset.y; + (*pScreen) = xf86Screens[edge->screen]->pScreen; + } + } + + +#if 0 + /* This presents problems for overlapping screens when + HardEdges is used. Have to think about the logic more */ + if((*x < 0) || (*x >= (*pScreen)->width) || + (*y < 0) || (*y >= (*pScreen)->height)) { + /* We may have crossed more than one screen */ + xf86CursorOffScreen(pScreen, x, y); + } +#endif + + return TRUE; +} + + + +/* + * xf86CrossScreen -- + * Switch to another screen + * + * Currently nothing special happens, but mi assumes the CrossScreen + * method exists. + */ + +static void +xf86CrossScreen (ScreenPtr pScreen, Bool entering) +{ +} + + +/* + * xf86WarpCursor -- + * Warp possible to another screen + */ + +/* ARGSUSED */ +static void +xf86WarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + int sigstate; + sigstate = xf86BlockSIGIO (); + miPointerWarpCursor(pDev, pScreen, x, y); + + xf86Info.currentScreen = pScreen; + xf86UnblockSIGIO (sigstate); +} + + +void * +xf86GetPointerScreenFuncs(void) +{ + return (void *)&xf86PointerScreenFuncs; +} + + +static xf86EdgePtr +AddEdge( + xf86EdgePtr edge, + short min, + short max, + short dx, + short dy, + short screen +){ + xf86EdgePtr pEdge = edge, pPrev = NULL, pNew; + + while(1) { + while(pEdge && (min >= pEdge->end)) { + pPrev = pEdge; + pEdge = pEdge->next; + } + + if(!pEdge) { + if(!(pNew = malloc(sizeof(xf86EdgeRec)))) + break; + + pNew->screen = screen; + pNew->start = min; + pNew->end = max; + pNew->offset.x = dx; + pNew->offset.y = dy; + pNew->next = NULL; + + if(pPrev) + pPrev->next = pNew; + else + edge = pNew; + + break; + } else if (min < pEdge->start) { + if(!(pNew = malloc(sizeof(xf86EdgeRec)))) + break; + + pNew->screen = screen; + pNew->start = min; + pNew->offset.x = dx; + pNew->offset.y = dy; + pNew->next = pEdge; + + if(pPrev) pPrev->next = pNew; + else edge = pNew; + + if(max <= pEdge->start) { + pNew->end = max; + break; + } else { + pNew->end = pEdge->start; + min = pEdge->end; + } + } else + min = pEdge->end; + + pPrev = pEdge; + pEdge = pEdge->next; + + if(max <= min) break; + } + + return edge; +} + +static void +FillOutEdge(xf86EdgePtr pEdge, int limit) +{ + xf86EdgePtr pNext; + int diff; + + if(pEdge->start > 0) pEdge->start = 0; + + while((pNext = pEdge->next)) { + diff = pNext->start - pEdge->end; + if(diff > 0) { + pEdge->end += diff >> 1; + pNext->start -= diff - (diff >> 1); + } + pEdge = pNext; + } + + if(pEdge->end < limit) + pEdge->end = limit; +} + +/* + * xf86InitOrigins() can deal with a maximum of 32 screens + * on 32 bit architectures, 64 on 64 bit architectures. + */ + +void +xf86InitOrigins(void) +{ + unsigned long screensLeft, prevScreensLeft, mask; + screenLayoutPtr screen; + ScreenPtr pScreen; + int x1, x2, y1, y2, left, right, top, bottom; + int i, j, ref, minX, minY, min, max; + xf86ScreenLayoutPtr pLayout; + Bool OldStyleConfig = FALSE; + + /* need to have this set up with a config file option */ + HardEdges = FALSE; + + bzero(xf86ScreenLayout, MAXSCREENS * sizeof(xf86ScreenLayoutRec)); + + screensLeft = prevScreensLeft = (1 << xf86NumScreens) - 1; + + while(1) { + for(mask = screensLeft, i = 0; mask; mask >>= 1, i++) { + if(!(mask & 1L)) continue; + + screen = &xf86ConfigLayout.screens[i]; + + if (screen->refscreen != NULL && + screen->refscreen->screennum >= xf86NumScreens) { + screensLeft &= ~(1 << i); + xf86Msg(X_WARNING, "Not including screen \"%s\" in origins calculation.\n", + screen->screen->id); + continue; + } + + switch(screen->where) { + case PosObsolete: + OldStyleConfig = TRUE; + pLayout = &xf86ScreenLayout[i]; + /* force edge lists */ + if(screen->left) { + ref = screen->left->screennum; + if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { + ErrorF("Referenced uninitialized screen in Layout!\n"); + break; + } + pLayout->left = AddEdge(pLayout->left, + 0, xf86Screens[i]->pScreen->height, + xf86Screens[ref]->pScreen->width, 0, ref); + } + if(screen->right) { + ref = screen->right->screennum; + if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { + ErrorF("Referenced uninitialized screen in Layout!\n"); + break; + } + pScreen = xf86Screens[i]->pScreen; + pLayout->right = AddEdge(pLayout->right, + 0, pScreen->height, -pScreen->width, 0, ref); + } + if(screen->top) { + ref = screen->top->screennum; + if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { + ErrorF("Referenced uninitialized screen in Layout!\n"); + break; + } + pLayout->up = AddEdge(pLayout->up, + 0, xf86Screens[i]->pScreen->width, + 0, xf86Screens[ref]->pScreen->height, ref); + } + if(screen->bottom) { + ref = screen->bottom->screennum; + if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { + ErrorF("Referenced uninitialized screen in Layout!\n"); + break; + } + pScreen = xf86Screens[i]->pScreen; + pLayout->down = AddEdge(pLayout->down, + 0, pScreen->width, 0, -pScreen->height, ref); + } + /* we could also try to place it based on those + relative locations if we wanted to */ + screen->x = screen->y = 0; + /* FALLTHROUGH */ + case PosAbsolute: + dixScreenOrigins[i].x = screen->x; + dixScreenOrigins[i].y = screen->y; + screensLeft &= ~(1 << i); + break; + case PosRelative: + ref = screen->refscreen->screennum; + if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { + ErrorF("Referenced uninitialized screen in Layout!\n"); + break; + } + if(screensLeft & (1 << ref)) break; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->x; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->y; + screensLeft &= ~(1 << i); + break; + case PosRightOf: + ref = screen->refscreen->screennum; + if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { + ErrorF("Referenced uninitialized screen in Layout!\n"); + break; + } + if(screensLeft & (1 << ref)) break; + pScreen = xf86Screens[ref]->pScreen; + dixScreenOrigins[i].x = + dixScreenOrigins[ref].x + pScreen->width; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y; + screensLeft &= ~(1 << i); + break; + case PosLeftOf: + ref = screen->refscreen->screennum; + if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { + ErrorF("Referenced uninitialized screen in Layout!\n"); + break; + } + if(screensLeft & (1 << ref)) break; + pScreen = xf86Screens[i]->pScreen; + dixScreenOrigins[i].x = + dixScreenOrigins[ref].x - pScreen->width; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y; + screensLeft &= ~(1 << i); + break; + case PosBelow: + ref = screen->refscreen->screennum; + if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { + ErrorF("Referenced uninitialized screen in Layout!\n"); + break; + } + if(screensLeft & (1 << ref)) break; + pScreen = xf86Screens[ref]->pScreen; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x; + dixScreenOrigins[i].y = + dixScreenOrigins[ref].y + pScreen->height; + screensLeft &= ~(1 << i); + break; + case PosAbove: + ref = screen->refscreen->screennum; + if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) { + ErrorF("Referenced uninitialized screen in Layout!\n"); + break; + } + if(screensLeft & (1 << ref)) break; + pScreen = xf86Screens[i]->pScreen; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x; + dixScreenOrigins[i].y = + dixScreenOrigins[ref].y - pScreen->height; + screensLeft &= ~(1 << i); + break; + default: + ErrorF("Illegal placement keyword in Layout!\n"); + break; + } + + } + + if(!screensLeft) break; + + if(screensLeft == prevScreensLeft) { + /* All the remaining screens are referencing each other. + Assign a value to one of them and go through again */ + i = 0; + while(!((1 << i) & screensLeft)){ i++; } + + ref = xf86ConfigLayout.screens[i].refscreen->screennum; + dixScreenOrigins[ref].x = dixScreenOrigins[ref].y = 0; + screensLeft &= ~(1 << ref); + } + + prevScreensLeft = screensLeft; + } + + /* justify the topmost and leftmost to (0,0) */ + minX = dixScreenOrigins[0].x; + minY = dixScreenOrigins[0].y; + + for(i = 1; i < xf86NumScreens; i++) { + if(dixScreenOrigins[i].x < minX) + minX = dixScreenOrigins[i].x; + if(dixScreenOrigins[i].y < minY) + minY = dixScreenOrigins[i].y; + } + + if (minX || minY) { + for(i = 0; i < xf86NumScreens; i++) { + dixScreenOrigins[i].x -= minX; + dixScreenOrigins[i].y -= minY; + } + } + + + /* Create the edge lists */ + + if(!OldStyleConfig) { + for(i = 0; i < xf86NumScreens; i++) { + pLayout = &xf86ScreenLayout[i]; + + pScreen = xf86Screens[i]->pScreen; + + left = dixScreenOrigins[i].x; + right = left + pScreen->width; + top = dixScreenOrigins[i].y; + bottom = top + pScreen->height; + + for(j = 0; j < xf86NumScreens; j++) { + if(i == j) continue; + + x1 = dixScreenOrigins[j].x; + x2 = x1 + xf86Screens[j]->pScreen->width; + y1 = dixScreenOrigins[j].y; + y2 = y1 + xf86Screens[j]->pScreen->height; + + if((bottom > y1) && (top < y2)) { + min = y1 - top; + if(min < 0) min = 0; + max = pScreen->height - (bottom - y2); + if(max > pScreen->height) max = pScreen->height; + + if(((left - 1) >= x1) && ((left - 1) < x2)) + pLayout->left = AddEdge(pLayout->left, min, max, + dixScreenOrigins[i].x - dixScreenOrigins[j].x, + dixScreenOrigins[i].y - dixScreenOrigins[j].y, j); + + if((right >= x1) && (right < x2)) + pLayout->right = AddEdge(pLayout->right, min, max, + dixScreenOrigins[i].x - dixScreenOrigins[j].x, + dixScreenOrigins[i].y - dixScreenOrigins[j].y, j); + } + + + if((left < x2) && (right > x1)) { + min = x1 - left; + if(min < 0) min = 0; + max = pScreen->width - (right - x2); + if(max > pScreen->width) max = pScreen->width; + + if(((top - 1) >= y1) && ((top - 1) < y2)) + pLayout->up = AddEdge(pLayout->up, min, max, + dixScreenOrigins[i].x - dixScreenOrigins[j].x, + dixScreenOrigins[i].y - dixScreenOrigins[j].y, j); + + if((bottom >= y1) && (bottom < y2)) + pLayout->down = AddEdge(pLayout->down, min, max, + dixScreenOrigins[i].x - dixScreenOrigins[j].x, + dixScreenOrigins[i].y - dixScreenOrigins[j].y, j); + } + } + } + } + + if(!HardEdges && !OldStyleConfig) { + for(i = 0; i < xf86NumScreens; i++) { + pLayout = &xf86ScreenLayout[i]; + pScreen = xf86Screens[i]->pScreen; + if(pLayout->left) + FillOutEdge(pLayout->left, pScreen->height); + if(pLayout->right) + FillOutEdge(pLayout->right, pScreen->height); + if(pLayout->up) + FillOutEdge(pLayout->up, pScreen->width); + if(pLayout->down) + FillOutEdge(pLayout->down, pScreen->width); + } + } +} + +void +xf86ReconfigureLayout(void) +{ + int i; + + for (i = 0; i < MAXSCREENS; i++) { + xf86ScreenLayoutPtr sl = &xf86ScreenLayout[i]; + /* we don't have to zero these, xf86InitOrigins() takes care of that */ + if (sl->left) free(sl->left); + if (sl->right) free(sl->right); + if (sl->up) free(sl->up); + if (sl->down) free(sl->down); + } + + xf86InitOrigins(); +} + + diff --git a/xorg-server/hw/xfree86/common/xf86DGA.c b/xorg-server/hw/xfree86/common/xf86DGA.c index 794a13171..ac8302169 100644 --- a/xorg-server/hw/xfree86/common/xf86DGA.c +++ b/xorg-server/hw/xfree86/common/xf86DGA.c @@ -1,1227 +1,1227 @@ -/* - * Copyright (c) 1998-2002 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - * - * Written by Mark Vojkovich - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86str.h" -#include "xf86Priv.h" -#include "dgaproc.h" -#include <X11/extensions/xf86dgaproto.h> -#include "colormapst.h" -#include "pixmapstr.h" -#include "inputstr.h" -#include "globals.h" -#include "servermd.h" -#include "micmap.h" -#include "xkbsrv.h" -#include "xf86Xinput.h" -#include "exglobals.h" -#include "exevents.h" -#include "eventstr.h" -#include "eventconvert.h" - -#include "mi.h" - -static int DGAScreenKeyIndex; -static DevPrivateKey DGAScreenKey; -static int mieq_installed = 0; - -static Bool DGACloseScreen(int i, ScreenPtr pScreen); -static void DGADestroyColormap(ColormapPtr pmap); -static void DGAInstallColormap(ColormapPtr pmap); -static void DGAUninstallColormap(ColormapPtr pmap); -static void DGAHandleEvent(int screen_num, InternalEvent *event, - DeviceIntPtr device); - -static void -DGACopyModeInfo( - DGAModePtr mode, - XDGAModePtr xmode -); - -int *XDGAEventBase = NULL; - -#define DGA_GET_SCREEN_PRIV(pScreen) ((DGAScreenPtr) \ - dixLookupPrivate(&(pScreen)->devPrivates, DGAScreenKey)) - - -typedef struct _FakedVisualList{ - Bool free; - VisualPtr pVisual; - struct _FakedVisualList *next; -} FakedVisualList; - - -typedef struct { - ScrnInfoPtr pScrn; - int numModes; - DGAModePtr modes; - CloseScreenProcPtr CloseScreen; - DestroyColormapProcPtr DestroyColormap; - InstallColormapProcPtr InstallColormap; - UninstallColormapProcPtr UninstallColormap; - DGADevicePtr current; - DGAFunctionPtr funcs; - int input; - ClientPtr client; - int pixmapMode; - FakedVisualList *fakedVisuals; - ColormapPtr dgaColormap; - ColormapPtr savedColormap; - Bool grabMouse; - Bool grabKeyboard; -} DGAScreenRec, *DGAScreenPtr; - -Bool -DGAInit( - ScreenPtr pScreen, - DGAFunctionPtr funcs, - DGAModePtr modes, - int num -){ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - DGAScreenPtr pScreenPriv; - int i; - - if(!funcs || !funcs->SetMode || !funcs->OpenFramebuffer) - return FALSE; - - if(!modes || num <= 0) - return FALSE; - - DGAScreenKey = &DGAScreenKeyIndex; - - pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - - if (!pScreenPriv) - { - if(!(pScreenPriv = (DGAScreenPtr)xalloc(sizeof(DGAScreenRec)))) - return FALSE; - dixSetPrivate(&pScreen->devPrivates, DGAScreenKey, pScreenPriv); - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = DGACloseScreen; - pScreenPriv->DestroyColormap = pScreen->DestroyColormap; - pScreen->DestroyColormap = DGADestroyColormap; - pScreenPriv->InstallColormap = pScreen->InstallColormap; - pScreen->InstallColormap = DGAInstallColormap; - pScreenPriv->UninstallColormap = pScreen->UninstallColormap; - pScreen->UninstallColormap = DGAUninstallColormap; - } - - pScreenPriv->pScrn = pScrn; - pScreenPriv->numModes = num; - pScreenPriv->modes = modes; - pScreenPriv->current = NULL; - - pScreenPriv->funcs = funcs; - pScreenPriv->input = 0; - pScreenPriv->client = NULL; - pScreenPriv->fakedVisuals = NULL; - pScreenPriv->dgaColormap = NULL; - pScreenPriv->savedColormap = NULL; - pScreenPriv->grabMouse = FALSE; - pScreenPriv->grabKeyboard = FALSE; - - for(i = 0; i < num; i++) - modes[i].num = i + 1; - -#ifdef PANORAMIX - if(!noPanoramiXExtension) - for(i = 0; i < num; i++) - modes[i].flags &= ~DGA_PIXMAP_AVAILABLE; -#endif - - return TRUE; -} - -/* DGAReInitModes allows the driver to re-initialize - * the DGA mode list. - */ - -Bool -DGAReInitModes( - ScreenPtr pScreen, - DGAModePtr modes, - int num -){ - DGAScreenPtr pScreenPriv; - int i; - - /* No DGA? Ignore call (but don't make it look like it failed) */ - if(DGAScreenKey == NULL) - return TRUE; - - pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - - /* Same as above */ - if(!pScreenPriv) - return TRUE; - - /* Can't do this while DGA is active */ - if(pScreenPriv->current) - return FALSE; - - /* Quick sanity check */ - if(!num) - modes = NULL; - else if(!modes) - num = 0; - - pScreenPriv->numModes = num; - pScreenPriv->modes = modes; - - /* This practically disables DGA. So be it. */ - if(!num) - return TRUE; - - for(i = 0; i < num; i++) - modes[i].num = i + 1; - -#ifdef PANORAMIX - if(!noPanoramiXExtension) - for(i = 0; i < num; i++) - modes[i].flags &= ~DGA_PIXMAP_AVAILABLE; -#endif - - return TRUE; -} - -static void -FreeMarkedVisuals(ScreenPtr pScreen) -{ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - FakedVisualList *prev, *curr, *tmp; - - if(!pScreenPriv->fakedVisuals) - return; - - prev = NULL; - curr = pScreenPriv->fakedVisuals; - - while(curr) { - if(curr->free) { - tmp = curr; - curr = curr->next; - if(prev) - prev->next = curr; - else - pScreenPriv->fakedVisuals = curr; - xfree(tmp->pVisual); - xfree(tmp); - } else { - prev = curr; - curr = curr->next; - } - } -} - -static Bool -DGACloseScreen(int i, ScreenPtr pScreen) -{ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - - if (XDGAEventBase) { - mieqSetHandler(ET_DGAEvent, NULL); - } - - FreeMarkedVisuals(pScreen); - - pScreen->CloseScreen = pScreenPriv->CloseScreen; - pScreen->DestroyColormap = pScreenPriv->DestroyColormap; - pScreen->InstallColormap = pScreenPriv->InstallColormap; - pScreen->UninstallColormap = pScreenPriv->UninstallColormap; - - /* DGAShutdown() should have ensured that no DGA - screen were active by here */ - - xfree(pScreenPriv); - - return((*pScreen->CloseScreen)(i, pScreen)); -} - - -static void -DGADestroyColormap(ColormapPtr pmap) -{ - ScreenPtr pScreen = pmap->pScreen; - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - VisualPtr pVisual = pmap->pVisual; - - if(pScreenPriv->fakedVisuals) { - FakedVisualList *curr = pScreenPriv->fakedVisuals; - - while(curr) { - if(curr->pVisual == pVisual) { - /* We can't get rid of them yet since FreeColormap - still needs the pVisual during the cleanup */ - curr->free = TRUE; - break; - } - curr = curr->next; - } - } - - if(pScreenPriv->DestroyColormap) { - pScreen->DestroyColormap = pScreenPriv->DestroyColormap; - (*pScreen->DestroyColormap)(pmap); - pScreen->DestroyColormap = DGADestroyColormap; - } -} - - -static void -DGAInstallColormap(ColormapPtr pmap) -{ - ScreenPtr pScreen = pmap->pScreen; - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - - if(pScreenPriv->current && pScreenPriv->dgaColormap) { - if (pmap != pScreenPriv->dgaColormap) { - pScreenPriv->savedColormap = pmap; - pmap = pScreenPriv->dgaColormap; - } - } - - pScreen->InstallColormap = pScreenPriv->InstallColormap; - (*pScreen->InstallColormap)(pmap); - pScreen->InstallColormap = DGAInstallColormap; -} - -static void -DGAUninstallColormap(ColormapPtr pmap) -{ - ScreenPtr pScreen = pmap->pScreen; - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - - if(pScreenPriv->current && pScreenPriv->dgaColormap) { - if (pmap == pScreenPriv->dgaColormap) { - pScreenPriv->dgaColormap = NULL; - } - } - - pScreen->UninstallColormap = pScreenPriv->UninstallColormap; - (*pScreen->UninstallColormap)(pmap); - pScreen->UninstallColormap = DGAUninstallColormap; -} - -int -xf86SetDGAMode( - int index, - int num, - DGADevicePtr devRet -){ - ScreenPtr pScreen = screenInfo.screens[index]; - DGAScreenPtr pScreenPriv; - ScrnInfoPtr pScrn; - DGADevicePtr device; - PixmapPtr pPix = NULL; - DGAModePtr pMode = NULL; - - /* First check if DGAInit was successful on this screen */ - if (DGAScreenKey == NULL) - return BadValue; - pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - if (!pScreenPriv) - return BadValue; - pScrn = pScreenPriv->pScrn; - - if(!num) { - if(pScreenPriv->current) { - PixmapPtr oldPix = pScreenPriv->current->pPix; - if(oldPix) { - if(oldPix->drawable.id) - FreeResource(oldPix->drawable.id, RT_NONE); - else - (*pScreen->DestroyPixmap)(oldPix); - } - xfree(pScreenPriv->current); - pScreenPriv->current = NULL; - pScrn->vtSema = TRUE; - (*pScreenPriv->funcs->SetMode)(pScrn, NULL); - if(pScreenPriv->savedColormap) { - (*pScreen->InstallColormap)(pScreenPriv->savedColormap); - pScreenPriv->savedColormap = NULL; - } - pScreenPriv->dgaColormap = NULL; - (*pScrn->EnableDisableFBAccess)(index, TRUE); - - FreeMarkedVisuals(pScreen); - } - - pScreenPriv->grabMouse = FALSE; - pScreenPriv->grabKeyboard = FALSE; - - return Success; - } - - if(!pScrn->vtSema && !pScreenPriv->current) /* Really switched away */ - return BadAlloc; - - if((num > 0) && (num <= pScreenPriv->numModes)) - pMode = &(pScreenPriv->modes[num - 1]); - else - return BadValue; - - if(!(device = (DGADevicePtr)xalloc(sizeof(DGADeviceRec)))) - return BadAlloc; - - if(!pScreenPriv->current) { - Bool oldVTSema = pScrn->vtSema; - - pScrn->vtSema = FALSE; /* kludge until we rewrite VT switching */ - (*pScrn->EnableDisableFBAccess)(index, FALSE); - pScrn->vtSema = oldVTSema; - } - - if(!(*pScreenPriv->funcs->SetMode)(pScrn, pMode)) { - xfree(device); - return BadAlloc; - } - - pScrn->currentMode = pMode->mode; - - if(!pScreenPriv->current && !pScreenPriv->input) { - /* if it's multihead we need to warp the cursor off of - our screen so it doesn't get trapped */ - } - - pScrn->vtSema = FALSE; - - if(pScreenPriv->current) { - PixmapPtr oldPix = pScreenPriv->current->pPix; - if(oldPix) { - if(oldPix->drawable.id) - FreeResource(oldPix->drawable.id, RT_NONE); - else - (*pScreen->DestroyPixmap)(oldPix); - } - xfree(pScreenPriv->current); - pScreenPriv->current = NULL; - } - - if(pMode->flags & DGA_PIXMAP_AVAILABLE) { - if((pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pMode->depth, 0))) { - (*pScreen->ModifyPixmapHeader)(pPix, - pMode->pixmapWidth, pMode->pixmapHeight, - pMode->depth, pMode->bitsPerPixel, - pMode->bytesPerScanline, - (pointer)(pMode->address)); - } - } - - devRet->mode = device->mode = pMode; - devRet->pPix = device->pPix = pPix; - pScreenPriv->current = device; - pScreenPriv->pixmapMode = FALSE; - pScreenPriv->grabMouse = TRUE; - pScreenPriv->grabKeyboard = TRUE; - - return Success; -} - - - -/*********** exported ones ***************/ - -void -DGASetInputMode(int index, Bool keyboard, Bool mouse) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - - if (pScreenPriv) - { - pScreenPriv->grabMouse = mouse; - pScreenPriv->grabKeyboard = keyboard; - - if (!mieq_installed) { - mieqSetHandler(ET_DGAEvent, DGAHandleEvent); - mieq_installed = 1; - } - } -} - -Bool -DGAChangePixmapMode(int index, int *x, int *y, int mode) -{ - DGAScreenPtr pScreenPriv; - DGADevicePtr pDev; - DGAModePtr pMode; - PixmapPtr pPix; - - if(DGAScreenKey == NULL) - return FALSE; - - pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - if(!pScreenPriv || !pScreenPriv->current || !pScreenPriv->current->pPix) - return FALSE; - - pDev = pScreenPriv->current; - pPix = pDev->pPix; - pMode = pDev->mode; - - if(mode) { - int shift = 2; - - if(*x > (pMode->pixmapWidth - pMode->viewportWidth)) - *x = pMode->pixmapWidth - pMode->viewportWidth; - if(*y > (pMode->pixmapHeight - pMode->viewportHeight)) - *y = pMode->pixmapHeight - pMode->viewportHeight; - - switch(xf86Screens[index]->bitsPerPixel) { - case 16: shift = 1; break; - case 32: shift = 0; break; - default: break; - } - - if(BITMAP_SCANLINE_PAD == 64) - shift++; - - *x = (*x >> shift) << shift; - - pPix->drawable.x = *x; - pPix->drawable.y = *y; - pPix->drawable.width = pMode->viewportWidth; - pPix->drawable.height = pMode->viewportHeight; - } else { - pPix->drawable.x = 0; - pPix->drawable.y = 0; - pPix->drawable.width = pMode->pixmapWidth; - pPix->drawable.height = pMode->pixmapHeight; - } - pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER; - pScreenPriv->pixmapMode = mode; - - return TRUE; -} - -Bool -DGAAvailable(int index) -{ - if(DGAScreenKey == NULL) - return FALSE; - - if(DGA_GET_SCREEN_PRIV(screenInfo.screens[index])) - return TRUE; - - return FALSE; -} - -Bool -DGAActive(int index) -{ - DGAScreenPtr pScreenPriv; - - if(DGAScreenKey == NULL) - return FALSE; - - pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - if(pScreenPriv && pScreenPriv->current) - return TRUE; - - return FALSE; -} - - - -/* Called by the event code in case the server is abruptly terminated */ - -void -DGAShutdown(void) -{ - ScrnInfoPtr pScrn; - int i; - - if(DGAScreenKey == NULL) - return; - - for(i = 0; i < screenInfo.numScreens; i++) { - pScrn = xf86Screens[i]; - - (void)(*pScrn->SetDGAMode)(pScrn->scrnIndex, 0, NULL); - } -} - -/* Called by the extension to initialize a mode */ - -int -DGASetMode( - int index, - int num, - XDGAModePtr mode, - PixmapPtr *pPix -){ - ScrnInfoPtr pScrn = xf86Screens[index]; - DGADeviceRec device; - int ret; - - /* We rely on the extension to check that DGA is available */ - - ret = (*pScrn->SetDGAMode)(index, num, &device); - if((ret == Success) && num) { - DGACopyModeInfo(device.mode, mode); - *pPix = device.pPix; - } - - return ret; -} - -/* Called from the extension to let the DDX know which events are requested */ - -void -DGASelectInput( - int index, - ClientPtr client, - long mask -){ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - /* We rely on the extension to check that DGA is available */ - pScreenPriv->client = client; - pScreenPriv->input = mask; -} - -int -DGAGetViewportStatus(int index) -{ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - /* We rely on the extension to check that DGA is active */ - - if (!pScreenPriv->funcs->GetViewport) - return 0; - - return (*pScreenPriv->funcs->GetViewport)(pScreenPriv->pScrn); -} - -int -DGASetViewport( - int index, - int x, int y, - int mode -){ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - if (pScreenPriv->funcs->SetViewport) - (*pScreenPriv->funcs->SetViewport)(pScreenPriv->pScrn, x, y, mode); - return Success; -} - - -static int -BitsClear(CARD32 data) -{ - int bits = 0; - CARD32 mask; - - for(mask = 1; mask; mask <<= 1) { - if(!(data & mask)) bits++; - else break; - } - - return bits; -} - -int -DGACreateColormap(int index, ClientPtr client, int id, int mode, int alloc) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - FakedVisualList *fvlp; - VisualPtr pVisual; - DGAModePtr pMode; - ColormapPtr pmap; - - if(!mode || (mode > pScreenPriv->numModes)) - return BadValue; - - if((alloc != AllocNone) && (alloc != AllocAll)) - return BadValue; - - pMode = &(pScreenPriv->modes[mode - 1]); - - if(!(pVisual = xalloc(sizeof(VisualRec)))) - return BadAlloc; - - pVisual->vid = FakeClientID(0); - pVisual->class = pMode->visualClass; - pVisual->nplanes = pMode->depth; - pVisual->ColormapEntries = 1 << pMode->depth; - pVisual->bitsPerRGBValue = (pMode->depth + 2) / 3; - - switch (pVisual->class) { - case PseudoColor: - case GrayScale: - case StaticGray: - pVisual->bitsPerRGBValue = 8; /* not quite */ - pVisual->redMask = 0; - pVisual->greenMask = 0; - pVisual->blueMask = 0; - pVisual->offsetRed = 0; - pVisual->offsetGreen = 0; - pVisual->offsetBlue = 0; - break; - case DirectColor: - case TrueColor: - pVisual->ColormapEntries = 1 << pVisual->bitsPerRGBValue; - /* fall through */ - case StaticColor: - pVisual->redMask = pMode->red_mask; - pVisual->greenMask = pMode->green_mask; - pVisual->blueMask = pMode->blue_mask; - pVisual->offsetRed = BitsClear(pVisual->redMask); - pVisual->offsetGreen = BitsClear(pVisual->greenMask); - pVisual->offsetBlue = BitsClear(pVisual->blueMask); - } - - if(!(fvlp = xalloc(sizeof(FakedVisualList)))) { - xfree(pVisual); - return BadAlloc; - } - - fvlp->free = FALSE; - fvlp->pVisual = pVisual; - fvlp->next = pScreenPriv->fakedVisuals; - pScreenPriv->fakedVisuals = fvlp; - - LEGAL_NEW_RESOURCE(id, client); - - return CreateColormap(id, pScreen, pVisual, &pmap, alloc, client->index); -} - -/* Called by the extension to install a colormap on DGA active screens */ - -void -DGAInstallCmap(ColormapPtr cmap) -{ - ScreenPtr pScreen = cmap->pScreen; - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - - /* We rely on the extension to check that DGA is active */ - - if(!pScreenPriv->dgaColormap) - pScreenPriv->savedColormap = GetInstalledmiColormap(pScreen); - - pScreenPriv->dgaColormap = cmap; - - (*pScreen->InstallColormap)(cmap); -} - -int -DGASync(int index) -{ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - /* We rely on the extension to check that DGA is active */ - - if (pScreenPriv->funcs->Sync) - (*pScreenPriv->funcs->Sync)(pScreenPriv->pScrn); - - return Success; -} - -int -DGAFillRect( - int index, - int x, int y, int w, int h, - unsigned long color -){ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - /* We rely on the extension to check that DGA is active */ - - if(pScreenPriv->funcs->FillRect && - (pScreenPriv->current->mode->flags & DGA_FILL_RECT)) { - - (*pScreenPriv->funcs->FillRect)(pScreenPriv->pScrn, x, y, w, h, color); - return Success; - } - return BadMatch; -} - -int -DGABlitRect( - int index, - int srcx, int srcy, - int w, int h, - int dstx, int dsty -){ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - /* We rely on the extension to check that DGA is active */ - - if(pScreenPriv->funcs->BlitRect && - (pScreenPriv->current->mode->flags & DGA_BLIT_RECT)) { - - (*pScreenPriv->funcs->BlitRect)(pScreenPriv->pScrn, - srcx, srcy, w, h, dstx, dsty); - return Success; - } - return BadMatch; -} - -int -DGABlitTransRect( - int index, - int srcx, int srcy, - int w, int h, - int dstx, int dsty, - unsigned long color -){ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - /* We rely on the extension to check that DGA is active */ - - if(pScreenPriv->funcs->BlitTransRect && - (pScreenPriv->current->mode->flags & DGA_BLIT_RECT_TRANS)) { - - (*pScreenPriv->funcs->BlitTransRect)(pScreenPriv->pScrn, - srcx, srcy, w, h, dstx, dsty, color); - return Success; - } - return BadMatch; -} - - -int -DGAGetModes(int index) -{ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - /* We rely on the extension to check that DGA is available */ - - return pScreenPriv->numModes; -} - - -int -DGAGetModeInfo( - int index, - XDGAModePtr mode, - int num -){ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - /* We rely on the extension to check that DGA is available */ - - if((num <= 0) || (num > pScreenPriv->numModes)) - return BadValue; - - DGACopyModeInfo(&(pScreenPriv->modes[num - 1]), mode); - - return Success; -} - - -static void -DGACopyModeInfo( - DGAModePtr mode, - XDGAModePtr xmode -){ - DisplayModePtr dmode = mode->mode; - - xmode->num = mode->num; - xmode->name = dmode->name; - xmode->VSync_num = (int)(dmode->VRefresh * 1000.0); - xmode->VSync_den = 1000; - xmode->flags = mode->flags; - xmode->imageWidth = mode->imageWidth; - xmode->imageHeight = mode->imageHeight; - xmode->pixmapWidth = mode->pixmapWidth; - xmode->pixmapHeight = mode->pixmapHeight; - xmode->bytesPerScanline = mode->bytesPerScanline; - xmode->byteOrder = mode->byteOrder; - xmode->depth = mode->depth; - xmode->bitsPerPixel = mode->bitsPerPixel; - xmode->red_mask = mode->red_mask; - xmode->green_mask = mode->green_mask; - xmode->blue_mask = mode->blue_mask; - xmode->visualClass = mode->visualClass; - xmode->viewportWidth = mode->viewportWidth; - xmode->viewportHeight = mode->viewportHeight; - xmode->xViewportStep = mode->xViewportStep; - xmode->yViewportStep = mode->yViewportStep; - xmode->maxViewportX = mode->maxViewportX; - xmode->maxViewportY = mode->maxViewportY; - xmode->viewportFlags = mode->viewportFlags; - xmode->reserved1 = mode->reserved1; - xmode->reserved2 = mode->reserved2; - xmode->offset = mode->offset; - - if(dmode->Flags & V_INTERLACE) xmode->flags |= DGA_INTERLACED; - if(dmode->Flags & V_DBLSCAN) xmode->flags |= DGA_DOUBLESCAN; -} - - -Bool -DGAVTSwitch(void) -{ - ScreenPtr pScreen; - int i; - - for(i = 0; i < screenInfo.numScreens; i++) { - pScreen = screenInfo.screens[i]; - - /* Alternatively, this could send events to DGA clients */ - - if(DGAScreenKey) { - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - - if(pScreenPriv && pScreenPriv->current) - return FALSE; - } - } - - return TRUE; -} - -Bool -DGAStealKeyEvent(DeviceIntPtr dev, int index, int key_code, int is_down) -{ - DGAScreenPtr pScreenPriv; - DGAEvent event; - - if(DGAScreenKey == NULL) /* no DGA */ - return FALSE; - - if (key_code < 8 || key_code > 255) - return FALSE; - - pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - if(!pScreenPriv || !pScreenPriv->grabKeyboard) /* no direct mode */ - return FALSE; - - memset(&event, 0, sizeof(event)); - event.header = ET_Internal; - event.type = ET_DGAEvent; - event.length = sizeof(event); - event.time = GetTimeInMillis(); - event.subtype = (is_down ? ET_KeyPress : ET_KeyRelease); - event.detail = key_code; - event.dx = 0; - event.dy = 0; - mieqEnqueue (dev, (InternalEvent*)&event); - - return TRUE; -} - -static int DGAMouseX, DGAMouseY; - -Bool -DGAStealMotionEvent(DeviceIntPtr dev, int index, int dx, int dy) -{ - DGAScreenPtr pScreenPriv; - DGAEvent event; - - if(DGAScreenKey == NULL) /* no DGA */ - return FALSE; - - pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - if(!pScreenPriv || !pScreenPriv->grabMouse) /* no direct mode */ - return FALSE; - - DGAMouseX += dx; - if (DGAMouseX < 0) - DGAMouseX = 0; - else if (DGAMouseX > screenInfo.screens[index]->width) - DGAMouseX = screenInfo.screens[index]->width; - DGAMouseY += dy; - if (DGAMouseY < 0) - DGAMouseY = 0; - else if (DGAMouseY > screenInfo.screens[index]->height) - DGAMouseY = screenInfo.screens[index]->height; - - memset(&event, 0, sizeof(event)); - event.header = ET_Internal; - event.type = ET_DGAEvent; - event.length = sizeof(event); - event.time = GetTimeInMillis(); - event.subtype = ET_Motion; - event.detail = 0; - event.dx = dx; - event.dy = dy; - mieqEnqueue (dev, (InternalEvent*)&event); - return TRUE; -} - -Bool -DGAStealButtonEvent(DeviceIntPtr dev, int index, int button, int is_down) -{ - DGAScreenPtr pScreenPriv; - DGAEvent event; - - if (DGAScreenKey == NULL) - return FALSE; - - pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - if (!pScreenPriv || !pScreenPriv->grabMouse) - return FALSE; - - memset(&event, 0, sizeof(event)); - event.header = ET_Internal; - event.type = ET_DGAEvent; - event.length = sizeof(event); - event.time = GetTimeInMillis(); - event.subtype = (is_down ? ET_ButtonPress : ET_ButtonRelease); - event.detail = button; - event.dx = 0; - event.dy = 0; - mieqEnqueue (dev, (InternalEvent*)&event); - - return TRUE; -} - -/* We have the power to steal or modify events that are about to get queued */ - -Bool -DGAIsDgaEvent (xEvent *e) -{ - int coreEquiv; - if (DGAScreenKey == NULL || XDGAEventBase == 0) - return FALSE; - coreEquiv = e->u.u.type - *XDGAEventBase; - if (KeyPress <= coreEquiv && coreEquiv <= MotionNotify) - return TRUE; - return FALSE; -} - -#define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ -static Mask filters[] = -{ - NoSuchEvent, /* 0 */ - NoSuchEvent, /* 1 */ - KeyPressMask, /* KeyPress */ - KeyReleaseMask, /* KeyRelease */ - ButtonPressMask, /* ButtonPress */ - ButtonReleaseMask, /* ButtonRelease */ - PointerMotionMask, /* MotionNotify (initial state) */ -}; - -static void -DGAProcessKeyboardEvent (ScreenPtr pScreen, DGAEvent *event, DeviceIntPtr keybd) -{ - KeyClassPtr keyc = keybd->key; - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - DeviceIntPtr pointer = GetPairedDevice(keybd); - DeviceEvent ev; - - memset(&ev, 0, sizeof(ev)); - ev.length = sizeof(ev); - ev.detail.key = event->detail; - ev.type = event->subtype; - ev.root_x = 0; - ev.root_y = 0; - ev.corestate = XkbStateFieldFromRec(&keyc->xkbInfo->state); - ev.corestate |= pointer->button->state; - - UpdateDeviceState(keybd, &ev); - - /* - * Deliver the DGA event - */ - if (pScreenPriv->client) - { - dgaEvent de; - de.u.u.type = *XDGAEventBase + GetCoreType((InternalEvent*)&ev); - de.u.u.detail = event->detail; - de.u.event.time = event->time; - de.u.event.dx = 0; - de.u.event.dy = 0; - de.u.event.screen = pScreen->myNum; - de.u.event.state = ev.corestate; - - /* If the DGA client has selected input, then deliver based on the usual filter */ - TryClientEvents (pScreenPriv->client, keybd, (xEvent *)&de, 1, - filters[ev.type], pScreenPriv->input, 0); - } - else - { - /* If the keyboard is actively grabbed, deliver a grabbed core event */ - if (keybd->deviceGrab.grab && !keybd->deviceGrab.fromPassiveGrab) - { - ev.detail.key = event->detail; - ev.time = event->time; - ev.root_x = event->dx; - ev.root_y = event->dy; - ev.corestate = event->state; - ev.deviceid = keybd->id; - DeliverGrabbedEvent ((InternalEvent*)&ev, keybd, FALSE); - } - } -} - -static void -DGAProcessPointerEvent (ScreenPtr pScreen, DGAEvent *event, DeviceIntPtr mouse) -{ - ButtonClassPtr butc = mouse->button; - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - DeviceEvent ev; - DeviceIntPtr master = GetMaster(mouse, MASTER_KEYBOARD); - - memset(&ev, 0, sizeof(ev)); - ev.header = ET_Internal; - ev.length = sizeof(ev); - ev.type = event->subtype; - ev.corestate = butc->state; - if (master && master->key) - ev.corestate |= XkbStateFieldFromRec(&master->key->xkbInfo->state); - - UpdateDeviceState(mouse, &ev); - - /* - * Deliver the DGA event - */ - if (pScreenPriv->client) - { - dgaEvent de; - int coreEquiv; - - coreEquiv = GetCoreType((InternalEvent*)&ev); - - de.u.u.type = *XDGAEventBase + coreEquiv; - de.u.u.detail = event->detail; - de.u.event.time = event->time; - de.u.event.dx = 0; - de.u.event.dy = 0; - de.u.event.screen = pScreen->myNum; - de.u.event.state = ev.corestate; - - /* If the DGA client has selected input, then deliver based on the usual filter */ - TryClientEvents (pScreenPriv->client, mouse, (xEvent *)&de, 1, - filters[coreEquiv], pScreenPriv->input, 0); - } - else - { - /* If the pointer is actively grabbed, deliver a grabbed core event */ - if (mouse->deviceGrab.grab && !mouse->deviceGrab.fromPassiveGrab) - { - ev.detail.button = event->detail; - ev.time = event->time; - ev.root_x = event->dx; - ev.root_y = event->dy; - ev.corestate = event->state; - DeliverGrabbedEvent ((InternalEvent*)&ev, mouse, FALSE); - } - } -} - -Bool -DGAOpenFramebuffer( - int index, - char **name, - unsigned char **mem, - int *size, - int *offset, - int *flags -){ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - /* We rely on the extension to check that DGA is available */ - - return (*pScreenPriv->funcs->OpenFramebuffer)(pScreenPriv->pScrn, - name, mem, size, offset, flags); -} - -void -DGACloseFramebuffer(int index) -{ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - - /* We rely on the extension to check that DGA is available */ - if(pScreenPriv->funcs->CloseFramebuffer) - (*pScreenPriv->funcs->CloseFramebuffer)(pScreenPriv->pScrn); -} - -/* For DGA 1.0 backwards compatibility only */ - -int -DGAGetOldDGAMode(int index) -{ - DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); - ScrnInfoPtr pScrn = pScreenPriv->pScrn; - DGAModePtr mode; - int i, w, h, p; - - /* We rely on the extension to check that DGA is available */ - - w = pScrn->currentMode->HDisplay; - h = pScrn->currentMode->VDisplay; - p = pad_to_int32(pScrn->displayWidth * bits_to_bytes(pScrn->bitsPerPixel)); - - for(i = 0; i < pScreenPriv->numModes; i++) { - mode = &(pScreenPriv->modes[i]); - - if((mode->viewportWidth == w) && (mode->viewportHeight == h) && - (mode->bytesPerScanline == p) && - (mode->bitsPerPixel == pScrn->bitsPerPixel) && - (mode->depth == pScrn->depth)) { - - return mode->num; - } - } - - return 0; -} - -static void -DGAHandleEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device) -{ - DGAEvent *event= &ev->dga_event; - ScreenPtr pScreen = screenInfo.screens[screen_num]; - DGAScreenPtr pScreenPriv; - - /* no DGA */ - if (DGAScreenKey == NULL || XDGAEventBase == 0) - return; - pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); - - /* DGA not initialized on this screen */ - if (!pScreenPriv) - return; - - switch (event->subtype) { - case KeyPress: - case KeyRelease: - DGAProcessKeyboardEvent (pScreen, event, device); - break; - case MotionNotify: - case ButtonPress: - case ButtonRelease: - DGAProcessPointerEvent (pScreen, event, device); - break; - default: - break; - } -} +/* + * Copyright (c) 1998-2002 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + * + * Written by Mark Vojkovich + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86str.h" +#include "xf86Priv.h" +#include "dgaproc.h" +#include <X11/extensions/xf86dgaproto.h> +#include "colormapst.h" +#include "pixmapstr.h" +#include "inputstr.h" +#include "globals.h" +#include "servermd.h" +#include "micmap.h" +#include "xkbsrv.h" +#include "xf86Xinput.h" +#include "exglobals.h" +#include "exevents.h" +#include "eventstr.h" +#include "eventconvert.h" + +#include "mi.h" + +static int DGAScreenKeyIndex; +static DevPrivateKey DGAScreenKey; +static int mieq_installed = 0; + +static Bool DGACloseScreen(int i, ScreenPtr pScreen); +static void DGADestroyColormap(ColormapPtr pmap); +static void DGAInstallColormap(ColormapPtr pmap); +static void DGAUninstallColormap(ColormapPtr pmap); +static void DGAHandleEvent(int screen_num, InternalEvent *event, + DeviceIntPtr device); + +static void +DGACopyModeInfo( + DGAModePtr mode, + XDGAModePtr xmode +); + +int *XDGAEventBase = NULL; + +#define DGA_GET_SCREEN_PRIV(pScreen) ((DGAScreenPtr) \ + dixLookupPrivate(&(pScreen)->devPrivates, DGAScreenKey)) + + +typedef struct _FakedVisualList{ + Bool free; + VisualPtr pVisual; + struct _FakedVisualList *next; +} FakedVisualList; + + +typedef struct { + ScrnInfoPtr pScrn; + int numModes; + DGAModePtr modes; + CloseScreenProcPtr CloseScreen; + DestroyColormapProcPtr DestroyColormap; + InstallColormapProcPtr InstallColormap; + UninstallColormapProcPtr UninstallColormap; + DGADevicePtr current; + DGAFunctionPtr funcs; + int input; + ClientPtr client; + int pixmapMode; + FakedVisualList *fakedVisuals; + ColormapPtr dgaColormap; + ColormapPtr savedColormap; + Bool grabMouse; + Bool grabKeyboard; +} DGAScreenRec, *DGAScreenPtr; + +Bool +DGAInit( + ScreenPtr pScreen, + DGAFunctionPtr funcs, + DGAModePtr modes, + int num +){ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + DGAScreenPtr pScreenPriv; + int i; + + if(!funcs || !funcs->SetMode || !funcs->OpenFramebuffer) + return FALSE; + + if(!modes || num <= 0) + return FALSE; + + DGAScreenKey = &DGAScreenKeyIndex; + + pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + + if (!pScreenPriv) + { + if(!(pScreenPriv = (DGAScreenPtr)malloc(sizeof(DGAScreenRec)))) + return FALSE; + dixSetPrivate(&pScreen->devPrivates, DGAScreenKey, pScreenPriv); + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = DGACloseScreen; + pScreenPriv->DestroyColormap = pScreen->DestroyColormap; + pScreen->DestroyColormap = DGADestroyColormap; + pScreenPriv->InstallColormap = pScreen->InstallColormap; + pScreen->InstallColormap = DGAInstallColormap; + pScreenPriv->UninstallColormap = pScreen->UninstallColormap; + pScreen->UninstallColormap = DGAUninstallColormap; + } + + pScreenPriv->pScrn = pScrn; + pScreenPriv->numModes = num; + pScreenPriv->modes = modes; + pScreenPriv->current = NULL; + + pScreenPriv->funcs = funcs; + pScreenPriv->input = 0; + pScreenPriv->client = NULL; + pScreenPriv->fakedVisuals = NULL; + pScreenPriv->dgaColormap = NULL; + pScreenPriv->savedColormap = NULL; + pScreenPriv->grabMouse = FALSE; + pScreenPriv->grabKeyboard = FALSE; + + for(i = 0; i < num; i++) + modes[i].num = i + 1; + +#ifdef PANORAMIX + if(!noPanoramiXExtension) + for(i = 0; i < num; i++) + modes[i].flags &= ~DGA_PIXMAP_AVAILABLE; +#endif + + return TRUE; +} + +/* DGAReInitModes allows the driver to re-initialize + * the DGA mode list. + */ + +Bool +DGAReInitModes( + ScreenPtr pScreen, + DGAModePtr modes, + int num +){ + DGAScreenPtr pScreenPriv; + int i; + + /* No DGA? Ignore call (but don't make it look like it failed) */ + if(DGAScreenKey == NULL) + return TRUE; + + pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + + /* Same as above */ + if(!pScreenPriv) + return TRUE; + + /* Can't do this while DGA is active */ + if(pScreenPriv->current) + return FALSE; + + /* Quick sanity check */ + if(!num) + modes = NULL; + else if(!modes) + num = 0; + + pScreenPriv->numModes = num; + pScreenPriv->modes = modes; + + /* This practically disables DGA. So be it. */ + if(!num) + return TRUE; + + for(i = 0; i < num; i++) + modes[i].num = i + 1; + +#ifdef PANORAMIX + if(!noPanoramiXExtension) + for(i = 0; i < num; i++) + modes[i].flags &= ~DGA_PIXMAP_AVAILABLE; +#endif + + return TRUE; +} + +static void +FreeMarkedVisuals(ScreenPtr pScreen) +{ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + FakedVisualList *prev, *curr, *tmp; + + if(!pScreenPriv->fakedVisuals) + return; + + prev = NULL; + curr = pScreenPriv->fakedVisuals; + + while(curr) { + if(curr->free) { + tmp = curr; + curr = curr->next; + if(prev) + prev->next = curr; + else + pScreenPriv->fakedVisuals = curr; + free(tmp->pVisual); + free(tmp); + } else { + prev = curr; + curr = curr->next; + } + } +} + +static Bool +DGACloseScreen(int i, ScreenPtr pScreen) +{ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + + if (XDGAEventBase) { + mieqSetHandler(ET_DGAEvent, NULL); + } + + FreeMarkedVisuals(pScreen); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->DestroyColormap = pScreenPriv->DestroyColormap; + pScreen->InstallColormap = pScreenPriv->InstallColormap; + pScreen->UninstallColormap = pScreenPriv->UninstallColormap; + + /* DGAShutdown() should have ensured that no DGA + screen were active by here */ + + free(pScreenPriv); + + return((*pScreen->CloseScreen)(i, pScreen)); +} + + +static void +DGADestroyColormap(ColormapPtr pmap) +{ + ScreenPtr pScreen = pmap->pScreen; + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + VisualPtr pVisual = pmap->pVisual; + + if(pScreenPriv->fakedVisuals) { + FakedVisualList *curr = pScreenPriv->fakedVisuals; + + while(curr) { + if(curr->pVisual == pVisual) { + /* We can't get rid of them yet since FreeColormap + still needs the pVisual during the cleanup */ + curr->free = TRUE; + break; + } + curr = curr->next; + } + } + + if(pScreenPriv->DestroyColormap) { + pScreen->DestroyColormap = pScreenPriv->DestroyColormap; + (*pScreen->DestroyColormap)(pmap); + pScreen->DestroyColormap = DGADestroyColormap; + } +} + + +static void +DGAInstallColormap(ColormapPtr pmap) +{ + ScreenPtr pScreen = pmap->pScreen; + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + + if(pScreenPriv->current && pScreenPriv->dgaColormap) { + if (pmap != pScreenPriv->dgaColormap) { + pScreenPriv->savedColormap = pmap; + pmap = pScreenPriv->dgaColormap; + } + } + + pScreen->InstallColormap = pScreenPriv->InstallColormap; + (*pScreen->InstallColormap)(pmap); + pScreen->InstallColormap = DGAInstallColormap; +} + +static void +DGAUninstallColormap(ColormapPtr pmap) +{ + ScreenPtr pScreen = pmap->pScreen; + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + + if(pScreenPriv->current && pScreenPriv->dgaColormap) { + if (pmap == pScreenPriv->dgaColormap) { + pScreenPriv->dgaColormap = NULL; + } + } + + pScreen->UninstallColormap = pScreenPriv->UninstallColormap; + (*pScreen->UninstallColormap)(pmap); + pScreen->UninstallColormap = DGAUninstallColormap; +} + +int +xf86SetDGAMode( + int index, + int num, + DGADevicePtr devRet +){ + ScreenPtr pScreen = screenInfo.screens[index]; + DGAScreenPtr pScreenPriv; + ScrnInfoPtr pScrn; + DGADevicePtr device; + PixmapPtr pPix = NULL; + DGAModePtr pMode = NULL; + + /* First check if DGAInit was successful on this screen */ + if (DGAScreenKey == NULL) + return BadValue; + pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + if (!pScreenPriv) + return BadValue; + pScrn = pScreenPriv->pScrn; + + if(!num) { + if(pScreenPriv->current) { + PixmapPtr oldPix = pScreenPriv->current->pPix; + if(oldPix) { + if(oldPix->drawable.id) + FreeResource(oldPix->drawable.id, RT_NONE); + else + (*pScreen->DestroyPixmap)(oldPix); + } + free(pScreenPriv->current); + pScreenPriv->current = NULL; + pScrn->vtSema = TRUE; + (*pScreenPriv->funcs->SetMode)(pScrn, NULL); + if(pScreenPriv->savedColormap) { + (*pScreen->InstallColormap)(pScreenPriv->savedColormap); + pScreenPriv->savedColormap = NULL; + } + pScreenPriv->dgaColormap = NULL; + (*pScrn->EnableDisableFBAccess)(index, TRUE); + + FreeMarkedVisuals(pScreen); + } + + pScreenPriv->grabMouse = FALSE; + pScreenPriv->grabKeyboard = FALSE; + + return Success; + } + + if(!pScrn->vtSema && !pScreenPriv->current) /* Really switched away */ + return BadAlloc; + + if((num > 0) && (num <= pScreenPriv->numModes)) + pMode = &(pScreenPriv->modes[num - 1]); + else + return BadValue; + + if(!(device = (DGADevicePtr)malloc(sizeof(DGADeviceRec)))) + return BadAlloc; + + if(!pScreenPriv->current) { + Bool oldVTSema = pScrn->vtSema; + + pScrn->vtSema = FALSE; /* kludge until we rewrite VT switching */ + (*pScrn->EnableDisableFBAccess)(index, FALSE); + pScrn->vtSema = oldVTSema; + } + + if(!(*pScreenPriv->funcs->SetMode)(pScrn, pMode)) { + free(device); + return BadAlloc; + } + + pScrn->currentMode = pMode->mode; + + if(!pScreenPriv->current && !pScreenPriv->input) { + /* if it's multihead we need to warp the cursor off of + our screen so it doesn't get trapped */ + } + + pScrn->vtSema = FALSE; + + if(pScreenPriv->current) { + PixmapPtr oldPix = pScreenPriv->current->pPix; + if(oldPix) { + if(oldPix->drawable.id) + FreeResource(oldPix->drawable.id, RT_NONE); + else + (*pScreen->DestroyPixmap)(oldPix); + } + free(pScreenPriv->current); + pScreenPriv->current = NULL; + } + + if(pMode->flags & DGA_PIXMAP_AVAILABLE) { + if((pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pMode->depth, 0))) { + (*pScreen->ModifyPixmapHeader)(pPix, + pMode->pixmapWidth, pMode->pixmapHeight, + pMode->depth, pMode->bitsPerPixel, + pMode->bytesPerScanline, + (pointer)(pMode->address)); + } + } + + devRet->mode = device->mode = pMode; + devRet->pPix = device->pPix = pPix; + pScreenPriv->current = device; + pScreenPriv->pixmapMode = FALSE; + pScreenPriv->grabMouse = TRUE; + pScreenPriv->grabKeyboard = TRUE; + + return Success; +} + + + +/*********** exported ones ***************/ + +void +DGASetInputMode(int index, Bool keyboard, Bool mouse) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + + if (pScreenPriv) + { + pScreenPriv->grabMouse = mouse; + pScreenPriv->grabKeyboard = keyboard; + + if (!mieq_installed) { + mieqSetHandler(ET_DGAEvent, DGAHandleEvent); + mieq_installed = 1; + } + } +} + +Bool +DGAChangePixmapMode(int index, int *x, int *y, int mode) +{ + DGAScreenPtr pScreenPriv; + DGADevicePtr pDev; + DGAModePtr pMode; + PixmapPtr pPix; + + if(DGAScreenKey == NULL) + return FALSE; + + pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + if(!pScreenPriv || !pScreenPriv->current || !pScreenPriv->current->pPix) + return FALSE; + + pDev = pScreenPriv->current; + pPix = pDev->pPix; + pMode = pDev->mode; + + if(mode) { + int shift = 2; + + if(*x > (pMode->pixmapWidth - pMode->viewportWidth)) + *x = pMode->pixmapWidth - pMode->viewportWidth; + if(*y > (pMode->pixmapHeight - pMode->viewportHeight)) + *y = pMode->pixmapHeight - pMode->viewportHeight; + + switch(xf86Screens[index]->bitsPerPixel) { + case 16: shift = 1; break; + case 32: shift = 0; break; + default: break; + } + + if(BITMAP_SCANLINE_PAD == 64) + shift++; + + *x = (*x >> shift) << shift; + + pPix->drawable.x = *x; + pPix->drawable.y = *y; + pPix->drawable.width = pMode->viewportWidth; + pPix->drawable.height = pMode->viewportHeight; + } else { + pPix->drawable.x = 0; + pPix->drawable.y = 0; + pPix->drawable.width = pMode->pixmapWidth; + pPix->drawable.height = pMode->pixmapHeight; + } + pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pScreenPriv->pixmapMode = mode; + + return TRUE; +} + +Bool +DGAAvailable(int index) +{ + if(DGAScreenKey == NULL) + return FALSE; + + if(DGA_GET_SCREEN_PRIV(screenInfo.screens[index])) + return TRUE; + + return FALSE; +} + +Bool +DGAActive(int index) +{ + DGAScreenPtr pScreenPriv; + + if(DGAScreenKey == NULL) + return FALSE; + + pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + if(pScreenPriv && pScreenPriv->current) + return TRUE; + + return FALSE; +} + + + +/* Called by the event code in case the server is abruptly terminated */ + +void +DGAShutdown(void) +{ + ScrnInfoPtr pScrn; + int i; + + if(DGAScreenKey == NULL) + return; + + for(i = 0; i < screenInfo.numScreens; i++) { + pScrn = xf86Screens[i]; + + (void)(*pScrn->SetDGAMode)(pScrn->scrnIndex, 0, NULL); + } +} + +/* Called by the extension to initialize a mode */ + +int +DGASetMode( + int index, + int num, + XDGAModePtr mode, + PixmapPtr *pPix +){ + ScrnInfoPtr pScrn = xf86Screens[index]; + DGADeviceRec device; + int ret; + + /* We rely on the extension to check that DGA is available */ + + ret = (*pScrn->SetDGAMode)(index, num, &device); + if((ret == Success) && num) { + DGACopyModeInfo(device.mode, mode); + *pPix = device.pPix; + } + + return ret; +} + +/* Called from the extension to let the DDX know which events are requested */ + +void +DGASelectInput( + int index, + ClientPtr client, + long mask +){ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + /* We rely on the extension to check that DGA is available */ + pScreenPriv->client = client; + pScreenPriv->input = mask; +} + +int +DGAGetViewportStatus(int index) +{ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + /* We rely on the extension to check that DGA is active */ + + if (!pScreenPriv->funcs->GetViewport) + return 0; + + return (*pScreenPriv->funcs->GetViewport)(pScreenPriv->pScrn); +} + +int +DGASetViewport( + int index, + int x, int y, + int mode +){ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + if (pScreenPriv->funcs->SetViewport) + (*pScreenPriv->funcs->SetViewport)(pScreenPriv->pScrn, x, y, mode); + return Success; +} + + +static int +BitsClear(CARD32 data) +{ + int bits = 0; + CARD32 mask; + + for(mask = 1; mask; mask <<= 1) { + if(!(data & mask)) bits++; + else break; + } + + return bits; +} + +int +DGACreateColormap(int index, ClientPtr client, int id, int mode, int alloc) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + FakedVisualList *fvlp; + VisualPtr pVisual; + DGAModePtr pMode; + ColormapPtr pmap; + + if(!mode || (mode > pScreenPriv->numModes)) + return BadValue; + + if((alloc != AllocNone) && (alloc != AllocAll)) + return BadValue; + + pMode = &(pScreenPriv->modes[mode - 1]); + + if(!(pVisual = malloc(sizeof(VisualRec)))) + return BadAlloc; + + pVisual->vid = FakeClientID(0); + pVisual->class = pMode->visualClass; + pVisual->nplanes = pMode->depth; + pVisual->ColormapEntries = 1 << pMode->depth; + pVisual->bitsPerRGBValue = (pMode->depth + 2) / 3; + + switch (pVisual->class) { + case PseudoColor: + case GrayScale: + case StaticGray: + pVisual->bitsPerRGBValue = 8; /* not quite */ + pVisual->redMask = 0; + pVisual->greenMask = 0; + pVisual->blueMask = 0; + pVisual->offsetRed = 0; + pVisual->offsetGreen = 0; + pVisual->offsetBlue = 0; + break; + case DirectColor: + case TrueColor: + pVisual->ColormapEntries = 1 << pVisual->bitsPerRGBValue; + /* fall through */ + case StaticColor: + pVisual->redMask = pMode->red_mask; + pVisual->greenMask = pMode->green_mask; + pVisual->blueMask = pMode->blue_mask; + pVisual->offsetRed = BitsClear(pVisual->redMask); + pVisual->offsetGreen = BitsClear(pVisual->greenMask); + pVisual->offsetBlue = BitsClear(pVisual->blueMask); + } + + if(!(fvlp = malloc(sizeof(FakedVisualList)))) { + free(pVisual); + return BadAlloc; + } + + fvlp->free = FALSE; + fvlp->pVisual = pVisual; + fvlp->next = pScreenPriv->fakedVisuals; + pScreenPriv->fakedVisuals = fvlp; + + LEGAL_NEW_RESOURCE(id, client); + + return CreateColormap(id, pScreen, pVisual, &pmap, alloc, client->index); +} + +/* Called by the extension to install a colormap on DGA active screens */ + +void +DGAInstallCmap(ColormapPtr cmap) +{ + ScreenPtr pScreen = cmap->pScreen; + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + + /* We rely on the extension to check that DGA is active */ + + if(!pScreenPriv->dgaColormap) + pScreenPriv->savedColormap = GetInstalledmiColormap(pScreen); + + pScreenPriv->dgaColormap = cmap; + + (*pScreen->InstallColormap)(cmap); +} + +int +DGASync(int index) +{ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + /* We rely on the extension to check that DGA is active */ + + if (pScreenPriv->funcs->Sync) + (*pScreenPriv->funcs->Sync)(pScreenPriv->pScrn); + + return Success; +} + +int +DGAFillRect( + int index, + int x, int y, int w, int h, + unsigned long color +){ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + /* We rely on the extension to check that DGA is active */ + + if(pScreenPriv->funcs->FillRect && + (pScreenPriv->current->mode->flags & DGA_FILL_RECT)) { + + (*pScreenPriv->funcs->FillRect)(pScreenPriv->pScrn, x, y, w, h, color); + return Success; + } + return BadMatch; +} + +int +DGABlitRect( + int index, + int srcx, int srcy, + int w, int h, + int dstx, int dsty +){ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + /* We rely on the extension to check that DGA is active */ + + if(pScreenPriv->funcs->BlitRect && + (pScreenPriv->current->mode->flags & DGA_BLIT_RECT)) { + + (*pScreenPriv->funcs->BlitRect)(pScreenPriv->pScrn, + srcx, srcy, w, h, dstx, dsty); + return Success; + } + return BadMatch; +} + +int +DGABlitTransRect( + int index, + int srcx, int srcy, + int w, int h, + int dstx, int dsty, + unsigned long color +){ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + /* We rely on the extension to check that DGA is active */ + + if(pScreenPriv->funcs->BlitTransRect && + (pScreenPriv->current->mode->flags & DGA_BLIT_RECT_TRANS)) { + + (*pScreenPriv->funcs->BlitTransRect)(pScreenPriv->pScrn, + srcx, srcy, w, h, dstx, dsty, color); + return Success; + } + return BadMatch; +} + + +int +DGAGetModes(int index) +{ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + /* We rely on the extension to check that DGA is available */ + + return pScreenPriv->numModes; +} + + +int +DGAGetModeInfo( + int index, + XDGAModePtr mode, + int num +){ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + /* We rely on the extension to check that DGA is available */ + + if((num <= 0) || (num > pScreenPriv->numModes)) + return BadValue; + + DGACopyModeInfo(&(pScreenPriv->modes[num - 1]), mode); + + return Success; +} + + +static void +DGACopyModeInfo( + DGAModePtr mode, + XDGAModePtr xmode +){ + DisplayModePtr dmode = mode->mode; + + xmode->num = mode->num; + xmode->name = dmode->name; + xmode->VSync_num = (int)(dmode->VRefresh * 1000.0); + xmode->VSync_den = 1000; + xmode->flags = mode->flags; + xmode->imageWidth = mode->imageWidth; + xmode->imageHeight = mode->imageHeight; + xmode->pixmapWidth = mode->pixmapWidth; + xmode->pixmapHeight = mode->pixmapHeight; + xmode->bytesPerScanline = mode->bytesPerScanline; + xmode->byteOrder = mode->byteOrder; + xmode->depth = mode->depth; + xmode->bitsPerPixel = mode->bitsPerPixel; + xmode->red_mask = mode->red_mask; + xmode->green_mask = mode->green_mask; + xmode->blue_mask = mode->blue_mask; + xmode->visualClass = mode->visualClass; + xmode->viewportWidth = mode->viewportWidth; + xmode->viewportHeight = mode->viewportHeight; + xmode->xViewportStep = mode->xViewportStep; + xmode->yViewportStep = mode->yViewportStep; + xmode->maxViewportX = mode->maxViewportX; + xmode->maxViewportY = mode->maxViewportY; + xmode->viewportFlags = mode->viewportFlags; + xmode->reserved1 = mode->reserved1; + xmode->reserved2 = mode->reserved2; + xmode->offset = mode->offset; + + if(dmode->Flags & V_INTERLACE) xmode->flags |= DGA_INTERLACED; + if(dmode->Flags & V_DBLSCAN) xmode->flags |= DGA_DOUBLESCAN; +} + + +Bool +DGAVTSwitch(void) +{ + ScreenPtr pScreen; + int i; + + for(i = 0; i < screenInfo.numScreens; i++) { + pScreen = screenInfo.screens[i]; + + /* Alternatively, this could send events to DGA clients */ + + if(DGAScreenKey) { + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + + if(pScreenPriv && pScreenPriv->current) + return FALSE; + } + } + + return TRUE; +} + +Bool +DGAStealKeyEvent(DeviceIntPtr dev, int index, int key_code, int is_down) +{ + DGAScreenPtr pScreenPriv; + DGAEvent event; + + if(DGAScreenKey == NULL) /* no DGA */ + return FALSE; + + if (key_code < 8 || key_code > 255) + return FALSE; + + pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + if(!pScreenPriv || !pScreenPriv->grabKeyboard) /* no direct mode */ + return FALSE; + + memset(&event, 0, sizeof(event)); + event.header = ET_Internal; + event.type = ET_DGAEvent; + event.length = sizeof(event); + event.time = GetTimeInMillis(); + event.subtype = (is_down ? ET_KeyPress : ET_KeyRelease); + event.detail = key_code; + event.dx = 0; + event.dy = 0; + mieqEnqueue (dev, (InternalEvent*)&event); + + return TRUE; +} + +static int DGAMouseX, DGAMouseY; + +Bool +DGAStealMotionEvent(DeviceIntPtr dev, int index, int dx, int dy) +{ + DGAScreenPtr pScreenPriv; + DGAEvent event; + + if(DGAScreenKey == NULL) /* no DGA */ + return FALSE; + + pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + if(!pScreenPriv || !pScreenPriv->grabMouse) /* no direct mode */ + return FALSE; + + DGAMouseX += dx; + if (DGAMouseX < 0) + DGAMouseX = 0; + else if (DGAMouseX > screenInfo.screens[index]->width) + DGAMouseX = screenInfo.screens[index]->width; + DGAMouseY += dy; + if (DGAMouseY < 0) + DGAMouseY = 0; + else if (DGAMouseY > screenInfo.screens[index]->height) + DGAMouseY = screenInfo.screens[index]->height; + + memset(&event, 0, sizeof(event)); + event.header = ET_Internal; + event.type = ET_DGAEvent; + event.length = sizeof(event); + event.time = GetTimeInMillis(); + event.subtype = ET_Motion; + event.detail = 0; + event.dx = dx; + event.dy = dy; + mieqEnqueue (dev, (InternalEvent*)&event); + return TRUE; +} + +Bool +DGAStealButtonEvent(DeviceIntPtr dev, int index, int button, int is_down) +{ + DGAScreenPtr pScreenPriv; + DGAEvent event; + + if (DGAScreenKey == NULL) + return FALSE; + + pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + if (!pScreenPriv || !pScreenPriv->grabMouse) + return FALSE; + + memset(&event, 0, sizeof(event)); + event.header = ET_Internal; + event.type = ET_DGAEvent; + event.length = sizeof(event); + event.time = GetTimeInMillis(); + event.subtype = (is_down ? ET_ButtonPress : ET_ButtonRelease); + event.detail = button; + event.dx = 0; + event.dy = 0; + mieqEnqueue (dev, (InternalEvent*)&event); + + return TRUE; +} + +/* We have the power to steal or modify events that are about to get queued */ + +Bool +DGAIsDgaEvent (xEvent *e) +{ + int coreEquiv; + if (DGAScreenKey == NULL || XDGAEventBase == 0) + return FALSE; + coreEquiv = e->u.u.type - *XDGAEventBase; + if (KeyPress <= coreEquiv && coreEquiv <= MotionNotify) + return TRUE; + return FALSE; +} + +#define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ +static Mask filters[] = +{ + NoSuchEvent, /* 0 */ + NoSuchEvent, /* 1 */ + KeyPressMask, /* KeyPress */ + KeyReleaseMask, /* KeyRelease */ + ButtonPressMask, /* ButtonPress */ + ButtonReleaseMask, /* ButtonRelease */ + PointerMotionMask, /* MotionNotify (initial state) */ +}; + +static void +DGAProcessKeyboardEvent (ScreenPtr pScreen, DGAEvent *event, DeviceIntPtr keybd) +{ + KeyClassPtr keyc = keybd->key; + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + DeviceIntPtr pointer = GetPairedDevice(keybd); + DeviceEvent ev; + + memset(&ev, 0, sizeof(ev)); + ev.length = sizeof(ev); + ev.detail.key = event->detail; + ev.type = event->subtype; + ev.root_x = 0; + ev.root_y = 0; + ev.corestate = XkbStateFieldFromRec(&keyc->xkbInfo->state); + ev.corestate |= pointer->button->state; + + UpdateDeviceState(keybd, &ev); + + /* + * Deliver the DGA event + */ + if (pScreenPriv->client) + { + dgaEvent de; + de.u.u.type = *XDGAEventBase + GetCoreType((InternalEvent*)&ev); + de.u.u.detail = event->detail; + de.u.event.time = event->time; + de.u.event.dx = 0; + de.u.event.dy = 0; + de.u.event.screen = pScreen->myNum; + de.u.event.state = ev.corestate; + + /* If the DGA client has selected input, then deliver based on the usual filter */ + TryClientEvents (pScreenPriv->client, keybd, (xEvent *)&de, 1, + filters[ev.type], pScreenPriv->input, 0); + } + else + { + /* If the keyboard is actively grabbed, deliver a grabbed core event */ + if (keybd->deviceGrab.grab && !keybd->deviceGrab.fromPassiveGrab) + { + ev.detail.key = event->detail; + ev.time = event->time; + ev.root_x = event->dx; + ev.root_y = event->dy; + ev.corestate = event->state; + ev.deviceid = keybd->id; + DeliverGrabbedEvent ((InternalEvent*)&ev, keybd, FALSE); + } + } +} + +static void +DGAProcessPointerEvent (ScreenPtr pScreen, DGAEvent *event, DeviceIntPtr mouse) +{ + ButtonClassPtr butc = mouse->button; + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + DeviceEvent ev; + DeviceIntPtr master = GetMaster(mouse, MASTER_KEYBOARD); + + memset(&ev, 0, sizeof(ev)); + ev.header = ET_Internal; + ev.length = sizeof(ev); + ev.type = event->subtype; + ev.corestate = butc->state; + if (master && master->key) + ev.corestate |= XkbStateFieldFromRec(&master->key->xkbInfo->state); + + UpdateDeviceState(mouse, &ev); + + /* + * Deliver the DGA event + */ + if (pScreenPriv->client) + { + dgaEvent de; + int coreEquiv; + + coreEquiv = GetCoreType((InternalEvent*)&ev); + + de.u.u.type = *XDGAEventBase + coreEquiv; + de.u.u.detail = event->detail; + de.u.event.time = event->time; + de.u.event.dx = 0; + de.u.event.dy = 0; + de.u.event.screen = pScreen->myNum; + de.u.event.state = ev.corestate; + + /* If the DGA client has selected input, then deliver based on the usual filter */ + TryClientEvents (pScreenPriv->client, mouse, (xEvent *)&de, 1, + filters[coreEquiv], pScreenPriv->input, 0); + } + else + { + /* If the pointer is actively grabbed, deliver a grabbed core event */ + if (mouse->deviceGrab.grab && !mouse->deviceGrab.fromPassiveGrab) + { + ev.detail.button = event->detail; + ev.time = event->time; + ev.root_x = event->dx; + ev.root_y = event->dy; + ev.corestate = event->state; + DeliverGrabbedEvent ((InternalEvent*)&ev, mouse, FALSE); + } + } +} + +Bool +DGAOpenFramebuffer( + int index, + char **name, + unsigned char **mem, + int *size, + int *offset, + int *flags +){ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + /* We rely on the extension to check that DGA is available */ + + return (*pScreenPriv->funcs->OpenFramebuffer)(pScreenPriv->pScrn, + name, mem, size, offset, flags); +} + +void +DGACloseFramebuffer(int index) +{ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + + /* We rely on the extension to check that DGA is available */ + if(pScreenPriv->funcs->CloseFramebuffer) + (*pScreenPriv->funcs->CloseFramebuffer)(pScreenPriv->pScrn); +} + +/* For DGA 1.0 backwards compatibility only */ + +int +DGAGetOldDGAMode(int index) +{ + DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]); + ScrnInfoPtr pScrn = pScreenPriv->pScrn; + DGAModePtr mode; + int i, w, h, p; + + /* We rely on the extension to check that DGA is available */ + + w = pScrn->currentMode->HDisplay; + h = pScrn->currentMode->VDisplay; + p = pad_to_int32(pScrn->displayWidth * bits_to_bytes(pScrn->bitsPerPixel)); + + for(i = 0; i < pScreenPriv->numModes; i++) { + mode = &(pScreenPriv->modes[i]); + + if((mode->viewportWidth == w) && (mode->viewportHeight == h) && + (mode->bytesPerScanline == p) && + (mode->bitsPerPixel == pScrn->bitsPerPixel) && + (mode->depth == pScrn->depth)) { + + return mode->num; + } + } + + return 0; +} + +static void +DGAHandleEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device) +{ + DGAEvent *event= &ev->dga_event; + ScreenPtr pScreen = screenInfo.screens[screen_num]; + DGAScreenPtr pScreenPriv; + + /* no DGA */ + if (DGAScreenKey == NULL || XDGAEventBase == 0) + return; + pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen); + + /* DGA not initialized on this screen */ + if (!pScreenPriv) + return; + + switch (event->subtype) { + case KeyPress: + case KeyRelease: + DGAProcessKeyboardEvent (pScreen, event, device); + break; + case MotionNotify: + case ButtonPress: + case ButtonRelease: + DGAProcessPointerEvent (pScreen, event, device); + break; + default: + break; + } +} diff --git a/xorg-server/hw/xfree86/common/xf86DPMS.c b/xorg-server/hw/xfree86/common/xf86DPMS.c index 22174c74e..3040cb294 100644 --- a/xorg-server/hw/xfree86/common/xf86DPMS.c +++ b/xorg-server/hw/xfree86/common/xf86DPMS.c @@ -1,200 +1,200 @@ -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * This file contains the DPMS functions required by the extension. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include "os.h" -#include "globals.h" -#include "xf86.h" -#include "xf86Priv.h" -#ifdef DPMSExtension -#include <X11/extensions/dpmsconst.h> -#include "dpmsproc.h" -#endif -#include "xf86VGAarbiter.h" - - -#ifdef DPMSExtension -static int DPMSKeyIndex; -static DevPrivateKey DPMSKey; -static Bool DPMSClose(int i, ScreenPtr pScreen); -static int DPMSCount = 0; -#endif - - -Bool -xf86DPMSInit(ScreenPtr pScreen, DPMSSetProcPtr set, int flags) -{ -#ifdef DPMSExtension - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - DPMSPtr pDPMS; - pointer DPMSOpt; - MessageType enabled_from; - - DPMSKey = &DPMSKeyIndex; - - if (!dixSetPrivate(&pScreen->devPrivates, DPMSKey, - xcalloc(sizeof(DPMSRec), 1))) - return FALSE; - - pDPMS = dixLookupPrivate(&pScreen->devPrivates, DPMSKey); - pScrn->DPMSSet = set; - pDPMS->Flags = flags; - DPMSOpt = xf86FindOption(pScrn->options, "dpms"); - if (DPMSDisabledSwitch) { - enabled_from = X_CMDLINE; - DPMSEnabled = FALSE; - } - else if (DPMSOpt) { - enabled_from = X_CONFIG; - DPMSEnabled = xf86CheckBoolOption(pScrn->options, "dpms", FALSE); - xf86MarkOptionUsed(DPMSOpt); - } - else { - enabled_from = X_DEFAULT; - DPMSEnabled = TRUE; - } - if (DPMSEnabled) - xf86DrvMsg(pScreen->myNum, enabled_from, "DPMS enabled\n"); - pDPMS->Enabled = DPMSEnabled; - pDPMS->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = DPMSClose; - DPMSCount++; - return TRUE; -#else - return FALSE; -#endif -} - - -#ifdef DPMSExtension - -static Bool -DPMSClose(int i, ScreenPtr pScreen) -{ - DPMSPtr pDPMS; - - /* This shouldn't happen */ - if (DPMSKey == NULL) - return FALSE; - - pDPMS = dixLookupPrivate(&pScreen->devPrivates, DPMSKey); - - /* This shouldn't happen */ - if (!pDPMS) - return FALSE; - - pScreen->CloseScreen = pDPMS->CloseScreen; - - /* - * Turn on DPMS when shutting down. If this function can be used - * depends on the order the driver wraps things. If this is called - * after the driver has shut down everything the driver will have - * to deal with this internally. - */ - if (xf86Screens[i]->vtSema && xf86Screens[i]->DPMSSet) { - xf86Screens[i]->DPMSSet(xf86Screens[i],DPMSModeOn,0); - } - - xfree(pDPMS); - dixSetPrivate(&pScreen->devPrivates, DPMSKey, NULL); - if (--DPMSCount == 0) - DPMSKey = NULL; - return pScreen->CloseScreen(i, pScreen); -} - - -/* - * DPMSSet -- - * Device dependent DPMS mode setting hook. This is called whenever - * the DPMS mode is to be changed. - */ -int -DPMSSet(ClientPtr client, int level) -{ - int rc, i; - DPMSPtr pDPMS; - ScrnInfoPtr pScrn; - - DPMSPowerLevel = level; - - if (DPMSKey == NULL) - return Success; - - if (level != DPMSModeOn) { - rc = dixSaveScreens(client, SCREEN_SAVER_FORCER, ScreenSaverActive); - if (rc != Success) - return rc; - } - - /* For each screen, set the DPMS level */ - for (i = 0; i < xf86NumScreens; i++) { - pScrn = xf86Screens[i]; - pDPMS = dixLookupPrivate(&screenInfo.screens[i]->devPrivates, DPMSKey); - if (pDPMS && pScrn->DPMSSet && pDPMS->Enabled && pScrn->vtSema) { - xf86VGAarbiterLock(pScrn); - pScrn->DPMSSet(pScrn, level, 0); - xf86VGAarbiterUnlock(pScrn); - } - } - return Success; -} - - -/* - * DPMSSupported -- - * Return TRUE if any screen supports DPMS. - */ -Bool -DPMSSupported(void) -{ - int i; - DPMSPtr pDPMS; - ScrnInfoPtr pScrn; - - if (DPMSKey == NULL) { - return FALSE; - } - - /* For each screen, check if DPMS is supported */ - for (i = 0; i < xf86NumScreens; i++) { - pScrn = xf86Screens[i]; - pDPMS = dixLookupPrivate(&screenInfo.screens[i]->devPrivates, DPMSKey); - if (pDPMS && pScrn->DPMSSet) - return TRUE; - } - return FALSE; -} - -#endif /* DPMSExtension */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * This file contains the DPMS functions required by the extension. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "os.h" +#include "globals.h" +#include "xf86.h" +#include "xf86Priv.h" +#ifdef DPMSExtension +#include <X11/extensions/dpmsconst.h> +#include "dpmsproc.h" +#endif +#include "xf86VGAarbiter.h" + + +#ifdef DPMSExtension +static int DPMSKeyIndex; +static DevPrivateKey DPMSKey; +static Bool DPMSClose(int i, ScreenPtr pScreen); +static int DPMSCount = 0; +#endif + + +Bool +xf86DPMSInit(ScreenPtr pScreen, DPMSSetProcPtr set, int flags) +{ +#ifdef DPMSExtension + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + DPMSPtr pDPMS; + pointer DPMSOpt; + MessageType enabled_from; + + DPMSKey = &DPMSKeyIndex; + + if (!dixSetPrivate(&pScreen->devPrivates, DPMSKey, + calloc(sizeof(DPMSRec), 1))) + return FALSE; + + pDPMS = dixLookupPrivate(&pScreen->devPrivates, DPMSKey); + pScrn->DPMSSet = set; + pDPMS->Flags = flags; + DPMSOpt = xf86FindOption(pScrn->options, "dpms"); + if (DPMSDisabledSwitch) { + enabled_from = X_CMDLINE; + DPMSEnabled = FALSE; + } + else if (DPMSOpt) { + enabled_from = X_CONFIG; + DPMSEnabled = xf86CheckBoolOption(pScrn->options, "dpms", FALSE); + xf86MarkOptionUsed(DPMSOpt); + } + else { + enabled_from = X_DEFAULT; + DPMSEnabled = TRUE; + } + if (DPMSEnabled) + xf86DrvMsg(pScreen->myNum, enabled_from, "DPMS enabled\n"); + pDPMS->Enabled = DPMSEnabled; + pDPMS->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = DPMSClose; + DPMSCount++; + return TRUE; +#else + return FALSE; +#endif +} + + +#ifdef DPMSExtension + +static Bool +DPMSClose(int i, ScreenPtr pScreen) +{ + DPMSPtr pDPMS; + + /* This shouldn't happen */ + if (DPMSKey == NULL) + return FALSE; + + pDPMS = dixLookupPrivate(&pScreen->devPrivates, DPMSKey); + + /* This shouldn't happen */ + if (!pDPMS) + return FALSE; + + pScreen->CloseScreen = pDPMS->CloseScreen; + + /* + * Turn on DPMS when shutting down. If this function can be used + * depends on the order the driver wraps things. If this is called + * after the driver has shut down everything the driver will have + * to deal with this internally. + */ + if (xf86Screens[i]->vtSema && xf86Screens[i]->DPMSSet) { + xf86Screens[i]->DPMSSet(xf86Screens[i],DPMSModeOn,0); + } + + free(pDPMS); + dixSetPrivate(&pScreen->devPrivates, DPMSKey, NULL); + if (--DPMSCount == 0) + DPMSKey = NULL; + return pScreen->CloseScreen(i, pScreen); +} + + +/* + * DPMSSet -- + * Device dependent DPMS mode setting hook. This is called whenever + * the DPMS mode is to be changed. + */ +int +DPMSSet(ClientPtr client, int level) +{ + int rc, i; + DPMSPtr pDPMS; + ScrnInfoPtr pScrn; + + DPMSPowerLevel = level; + + if (DPMSKey == NULL) + return Success; + + if (level != DPMSModeOn) { + rc = dixSaveScreens(client, SCREEN_SAVER_FORCER, ScreenSaverActive); + if (rc != Success) + return rc; + } + + /* For each screen, set the DPMS level */ + for (i = 0; i < xf86NumScreens; i++) { + pScrn = xf86Screens[i]; + pDPMS = dixLookupPrivate(&screenInfo.screens[i]->devPrivates, DPMSKey); + if (pDPMS && pScrn->DPMSSet && pDPMS->Enabled && pScrn->vtSema) { + xf86VGAarbiterLock(pScrn); + pScrn->DPMSSet(pScrn, level, 0); + xf86VGAarbiterUnlock(pScrn); + } + } + return Success; +} + + +/* + * DPMSSupported -- + * Return TRUE if any screen supports DPMS. + */ +Bool +DPMSSupported(void) +{ + int i; + DPMSPtr pDPMS; + ScrnInfoPtr pScrn; + + if (DPMSKey == NULL) { + return FALSE; + } + + /* For each screen, check if DPMS is supported */ + for (i = 0; i < xf86NumScreens; i++) { + pScrn = xf86Screens[i]; + pDPMS = dixLookupPrivate(&screenInfo.screens[i]->devPrivates, DPMSKey); + if (pDPMS && pScrn->DPMSSet) + return TRUE; + } + return FALSE; +} + +#endif /* DPMSExtension */ diff --git a/xorg-server/hw/xfree86/common/xf86Events.c b/xorg-server/hw/xfree86/common/xf86Events.c index ee4835233..9d3a58f91 100644 --- a/xorg-server/hw/xfree86/common/xf86Events.c +++ b/xorg-server/hw/xfree86/common/xf86Events.c @@ -567,7 +567,7 @@ addInputHandler(int fd, InputHandlerProc proc, pointer data) if (fd < 0 || !proc) return NULL; - ih = xcalloc(sizeof(*ih), 1); + ih = calloc(sizeof(*ih), 1); if (!ih) return NULL; @@ -616,7 +616,7 @@ removeInputHandler(IHPtr ih) if (ih) p->next = ih->next; } - xfree(ih); + free(ih); } int diff --git a/xorg-server/hw/xfree86/common/xf86Helper.c b/xorg-server/hw/xfree86/common/xf86Helper.c index 1cc1526c9..4cc543fc4 100644 --- a/xorg-server/hw/xfree86/common/xf86Helper.c +++ b/xorg-server/hw/xfree86/common/xf86Helper.c @@ -1,2588 +1,2588 @@ -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * Authors: Dirk Hohndel <hohndel@XFree86.Org> - * David Dawes <dawes@XFree86.Org> - * ... and others - * - * This file includes the helper functions that the server provides for - * different drivers. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <pciaccess.h> -#include "Pci.h" - -#include <X11/X.h> -#include "os.h" -#include "servermd.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "propertyst.h" -#include "gcstruct.h" -#include "loaderProcs.h" -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" -#include "micmap.h" -#include "xf86DDC.h" -#include "xf86Xinput.h" -#include "xf86InPriv.h" -#include "mivalidate.h" -#include "xf86Bus.h" -#include "xf86Crtc.h" - -/* For xf86GetClocks */ -#if defined(CSRG_BASED) || defined(__GNU__) -#define HAS_SETPRIORITY -#include <sys/resource.h> -#endif - -static int xf86ScrnInfoPrivateCount = 0; - - -/* Add a pointer to a new DriverRec to xf86DriverList */ - -void -xf86AddDriver(DriverPtr driver, pointer module, int flags) -{ - /* Don't add null entries */ - if (!driver) - return; - - if (xf86DriverList == NULL) - xf86NumDrivers = 0; - - xf86NumDrivers++; - xf86DriverList = xnfrealloc(xf86DriverList, - xf86NumDrivers * sizeof(DriverPtr)); - xf86DriverList[xf86NumDrivers - 1] = xnfalloc(sizeof(DriverRec)); - if (flags & HaveDriverFuncs) - *xf86DriverList[xf86NumDrivers - 1] = *driver; - else { - (void) memset( xf86DriverList[xf86NumDrivers - 1], 0, - sizeof( DriverRec ) ); - (void) memcpy( xf86DriverList[xf86NumDrivers - 1], driver, - sizeof(DriverRec1)); - - } - xf86DriverList[xf86NumDrivers - 1]->module = module; - xf86DriverList[xf86NumDrivers - 1]->refCount = 0; -} - -void -xf86DeleteDriver(int drvIndex) -{ - if (xf86DriverList[drvIndex] - && (!xf86DriverHasEntities(xf86DriverList[drvIndex]))) { - if (xf86DriverList[drvIndex]->module) - UnloadModule(xf86DriverList[drvIndex]->module); - xfree(xf86DriverList[drvIndex]); - xf86DriverList[drvIndex] = NULL; - } -} - -/* Add a pointer to a new InputDriverRec to xf86InputDriverList */ - -void -xf86AddInputDriver(InputDriverPtr driver, pointer module, int flags) -{ - /* Don't add null entries */ - if (!driver) - return; - - if (xf86InputDriverList == NULL) - xf86NumInputDrivers = 0; - - xf86NumInputDrivers++; - xf86InputDriverList = xnfrealloc(xf86InputDriverList, - xf86NumInputDrivers * sizeof(InputDriverPtr)); - xf86InputDriverList[xf86NumInputDrivers - 1] = - xnfalloc(sizeof(InputDriverRec)); - *xf86InputDriverList[xf86NumInputDrivers - 1] = *driver; - xf86InputDriverList[xf86NumInputDrivers - 1]->module = module; - xf86InputDriverList[xf86NumInputDrivers - 1]->refCount = 0; -} - -void -xf86DeleteInputDriver(int drvIndex) -{ - if (xf86InputDriverList[drvIndex] && xf86InputDriverList[drvIndex]->module) - UnloadModule(xf86InputDriverList[drvIndex]->module); - xfree(xf86InputDriverList[drvIndex]); - xf86InputDriverList[drvIndex] = NULL; -} - -InputDriverPtr -xf86LookupInputDriver(const char *name) -{ - int i; - - for (i = 0; i < xf86NumInputDrivers; i++) { - if (xf86InputDriverList[i] && xf86InputDriverList[i]->driverName && - xf86NameCmp(name, xf86InputDriverList[i]->driverName) == 0) - return xf86InputDriverList[i]; - } - return NULL; -} - -InputInfoPtr -xf86LookupInput(const char *name) -{ - InputInfoPtr p; - - for (p = xf86InputDevs; p != NULL; p = p->next) { - if (strcmp(name, p->name) == 0) - return p; - } - - return NULL; -} - -/* Allocate a new ScrnInfoRec in xf86Screens */ - -ScrnInfoPtr -xf86AllocateScreen(DriverPtr drv, int flags) -{ - int i; - - if (xf86Screens == NULL) - xf86NumScreens = 0; - - i = xf86NumScreens++; - xf86Screens = xnfrealloc(xf86Screens, xf86NumScreens * sizeof(ScrnInfoPtr)); - xf86Screens[i] = xnfcalloc(sizeof(ScrnInfoRec), 1); - xf86Screens[i]->scrnIndex = i; /* Changes when a screen is removed */ - xf86Screens[i]->origIndex = i; /* This never changes */ - xf86Screens[i]->privates = xnfcalloc(sizeof(DevUnion), - xf86ScrnInfoPrivateCount); - /* - * EnableDisableFBAccess now gets initialized in InitOutput() - * xf86Screens[i]->EnableDisableFBAccess = xf86EnableDisableFBAccess; - */ - - xf86Screens[i]->drv = drv; - drv->refCount++; - xf86Screens[i]->module = DuplicateModule(drv->module, NULL); - - xf86Screens[i]->DriverFunc = drv->driverFunc; - - return xf86Screens[i]; -} - - -/* - * Remove an entry from xf86Screens. Ideally it should free all allocated - * data. To do this properly may require a driver hook. - */ - -void -xf86DeleteScreen(int scrnIndex, int flags) -{ - ScrnInfoPtr pScrn; - int i; - - /* First check if the screen is valid */ - if (xf86NumScreens == 0 || xf86Screens == NULL) - return; - - if (scrnIndex > xf86NumScreens - 1) - return; - - if (!(pScrn = xf86Screens[scrnIndex])) - return; - - /* If a FreeScreen function is defined, call it here */ - if (pScrn->FreeScreen != NULL) - pScrn->FreeScreen(scrnIndex, 0); - - while (pScrn->modes) - xf86DeleteMode(&pScrn->modes, pScrn->modes); - - while (pScrn->modePool) - xf86DeleteMode(&pScrn->modePool, pScrn->modePool); - - xf86OptionListFree(pScrn->options); - - if (pScrn->module) - UnloadModule(pScrn->module); - - if (pScrn->drv) - pScrn->drv->refCount--; - - if (pScrn->privates) - xfree(pScrn->privates); - - xf86ClearEntityListForScreen(scrnIndex); - - xfree(pScrn); - - /* Move the other entries down, updating their scrnIndex fields */ - - xf86NumScreens--; - - for (i = scrnIndex; i < xf86NumScreens; i++) { - xf86Screens[i] = xf86Screens[i + 1]; - xf86Screens[i]->scrnIndex = i; - /* Also need to take care of the screen layout settings */ - } -} - -/* - * Allocate a private in ScrnInfoRec. - */ - -int -xf86AllocateScrnInfoPrivateIndex(void) -{ - int idx, i; - ScrnInfoPtr pScr; - DevUnion *nprivs; - - idx = xf86ScrnInfoPrivateCount++; - for (i = 0; i < xf86NumScreens; i++) { - pScr = xf86Screens[i]; - nprivs = xnfrealloc(pScr->privates, - xf86ScrnInfoPrivateCount * sizeof(DevUnion)); - /* Zero the new private */ - bzero(&nprivs[idx], sizeof(DevUnion)); - pScr->privates = nprivs; - } - return idx; -} - -/* Allocate a new InputInfoRec and append it to the tail of xf86InputDevs. */ -InputInfoPtr -xf86AllocateInput(InputDriverPtr drv, int flags) -{ - InputInfoPtr new, *prev = NULL; - - if (!(new = xcalloc(sizeof(InputInfoRec), 1))) - return NULL; - - new->drv = drv; - drv->refCount++; - new->module = DuplicateModule(drv->module, NULL); - - for (prev = &xf86InputDevs; *prev; prev = &(*prev)->next) - ; - - *prev = new; - new->next = NULL; - - return new; -} - - -/* - * Remove an entry from xf86InputDevs. Ideally it should free all allocated - * data. To do this properly may require a driver hook. - */ - -void -xf86DeleteInput(InputInfoPtr pInp, int flags) -{ - InputInfoPtr p; - - /* First check if the inputdev is valid. */ - if (pInp == NULL) - return; - -#if 0 - /* If a free function is defined, call it here. */ - if (pInp->free) - pInp->free(pInp, 0); -#endif - - if (pInp->module) - UnloadModule(pInp->module); - - if (pInp->drv) - pInp->drv->refCount--; - - /* This should *really* be handled in drv->UnInit(dev) call instead, but - * if the driver forgets about it make sure we free it or at least crash - * with flying colors */ - if (pInp->private) - xfree(pInp->private); - - /* Remove the entry from the list. */ - if (pInp == xf86InputDevs) - xf86InputDevs = pInp->next; - else { - p = xf86InputDevs; - while (p && p->next != pInp) - p = p->next; - if (p) - p->next = pInp->next; - /* Else the entry wasn't in the xf86InputDevs list (ignore this). */ - } - xfree(pInp); -} - -Bool -xf86AddPixFormat(ScrnInfoPtr pScrn, int depth, int bpp, int pad) -{ - int i; - - if (pScrn->numFormats >= MAXFORMATS) - return FALSE; - - if (bpp <= 0) { - if (depth == 1) - bpp = 1; - else if (depth <= 8) - bpp = 8; - else if (depth <= 16) - bpp = 16; - else if (depth <= 32) - bpp = 32; - else - return FALSE; - } - if (pad <= 0) - pad = BITMAP_SCANLINE_PAD; - - i = pScrn->numFormats++; - pScrn->formats[i].depth = depth; - pScrn->formats[i].bitsPerPixel = bpp; - pScrn->formats[i].scanlinePad = pad; - return TRUE; -} - -/* - * Set the depth we are using based on (in the following order of preference): - * - values given on the command line - * - values given in the config file - * - values provided by the driver - * - an overall default when nothing else is given - * - * Also find a Display subsection matching the depth/bpp found. - * - * Sets the following ScrnInfoRec fields: - * bitsPerPixel, pixmap24, depth, display, imageByteOrder, - * bitmapScanlinePad, bitmapScanlineUnit, bitmapBitOrder, numFormats, - * formats, fbFormat. - */ - -/* Can the screen handle 24 bpp pixmaps */ -#define DO_PIX24(f) ((f & Support24bppFb) || \ - ((f & Support32bppFb) && (f & SupportConvert24to32))) - -/* Can the screen handle 32 bpp pixmaps */ -#define DO_PIX32(f) ((f & Support32bppFb) || \ - ((f & Support24bppFb) && (f & SupportConvert32to24))) - -/* Does the screen prefer 32bpp fb for 24bpp pixmaps */ -#define CHOOSE32FOR24(f) ((f & Support32bppFb) && (f & SupportConvert24to32) \ - && (f & PreferConvert24to32)) - -/* Does the screen prefer 24bpp fb for 32bpp pixmaps */ -#define CHOOSE24FOR32(f) ((f & Support24bppFb) && (f & SupportConvert32to24) \ - && (f & PreferConvert32to24)) - -/* Can the screen handle 32bpp pixmaps for 24bpp fb */ -#define DO_PIX32FOR24(f) ((f & Support24bppFb) && (f & SupportConvert32to24)) - -/* Can the screen handle 24bpp pixmaps for 32bpp fb */ -#define DO_PIX24FOR32(f) ((f & Support32bppFb) && (f & SupportConvert24to32)) - -#ifndef GLOBAL_DEFAULT_DEPTH -#define GLOBAL_DEFAULT_DEPTH 24 -#endif - -Bool -xf86SetDepthBpp(ScrnInfoPtr scrp, int depth, int dummy, int fbbpp, - int depth24flags) -{ - int i; - DispPtr disp; - Pix24Flags pix24 = xf86Info.pixmap24; - Bool nomatch = FALSE; - - scrp->bitsPerPixel = -1; - scrp->depth = -1; - scrp->pixmap24 = Pix24DontCare; - scrp->bitsPerPixelFrom = X_DEFAULT; - scrp->depthFrom = X_DEFAULT; - - if (xf86FbBpp > 0) { - scrp->bitsPerPixel = xf86FbBpp; - scrp->bitsPerPixelFrom = X_CMDLINE; - } - - if (xf86Depth > 0) { - scrp->depth = xf86Depth; - scrp->depthFrom = X_CMDLINE; - } - - if (xf86FbBpp < 0 && xf86Depth < 0) { - if (scrp->confScreen->defaultfbbpp > 0) { - scrp->bitsPerPixel = scrp->confScreen->defaultfbbpp; - scrp->bitsPerPixelFrom = X_CONFIG; - } - if (scrp->confScreen->defaultdepth > 0) { - scrp->depth = scrp->confScreen->defaultdepth; - scrp->depthFrom = X_CONFIG; - } - - if (scrp->confScreen->defaultfbbpp <= 0 && - scrp->confScreen->defaultdepth <= 0) { - /* - * Check for DefaultDepth and DefaultFbBpp options in the - * Device sections. - */ - int i; - GDevPtr device; - Bool found = FALSE; - - for (i = 0; i < scrp->numEntities; i++) { - device = xf86GetDevFromEntity(scrp->entityList[i], - scrp->entityInstanceList[i]); - if (device && device->options) { - if (xf86FindOption(device->options, "DefaultDepth")) { - scrp->depth = xf86SetIntOption(device->options, - "DefaultDepth", -1); - scrp->depthFrom = X_CONFIG; - found = TRUE; - } - if (xf86FindOption(device->options, "DefaultFbBpp")) { - scrp->bitsPerPixel = xf86SetIntOption(device->options, - "DefaultFbBpp", - -1); - scrp->bitsPerPixelFrom = X_CONFIG; - found = TRUE; - } - } - if (found) - break; - } - } - } - - /* If none of these is set, pick a default */ - if (scrp->bitsPerPixel < 0 && scrp->depth < 0) { - if (fbbpp > 0 || depth > 0) { - if (fbbpp > 0) - scrp->bitsPerPixel = fbbpp; - if (depth > 0) - scrp->depth = depth; - } else { - scrp->depth = GLOBAL_DEFAULT_DEPTH; - } - } - - /* If any are not given, determine a default for the others */ - - if (scrp->bitsPerPixel < 0) { - /* The depth must be set */ - if (scrp->depth > -1) { - if (scrp->depth == 1) - scrp->bitsPerPixel = 1; - else if (scrp->depth <= 4) - scrp->bitsPerPixel = 4; - else if (scrp->depth <= 8) - scrp->bitsPerPixel = 8; - else if (scrp->depth <= 16) - scrp->bitsPerPixel = 16; - else if (scrp->depth <= 24) { - /* - * Figure out if a choice is possible based on the depth24 - * and pix24 flags. - */ - /* Check pix24 first */ - if (pix24 != Pix24DontCare) { - if (pix24 == Pix24Use32) { - if (DO_PIX32(depth24flags)) { - if (CHOOSE24FOR32(depth24flags)) - scrp->bitsPerPixel = 24; - else - scrp->bitsPerPixel = 32; - } else { - nomatch = TRUE; - } - } else if (pix24 == Pix24Use24) { - if (DO_PIX24(depth24flags)) { - if (CHOOSE32FOR24(depth24flags)) - scrp->bitsPerPixel = 32; - else - scrp->bitsPerPixel = 24; - } else { - nomatch = TRUE; - } - } - } else { - if (DO_PIX32(depth24flags)) { - if (CHOOSE24FOR32(depth24flags)) - scrp->bitsPerPixel = 24; - else - scrp->bitsPerPixel = 32; - } else if (DO_PIX24(depth24flags)) { - if (CHOOSE32FOR24(depth24flags)) - scrp->bitsPerPixel = 32; - else - scrp->bitsPerPixel = 24; - } - } - } else if (scrp->depth <= 32) - scrp->bitsPerPixel = 32; - else { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Specified depth (%d) is greater than 32\n", - scrp->depth); - return FALSE; - } - } else { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "xf86SetDepthBpp: internal error: depth and fbbpp" - " are both not set\n"); - return FALSE; - } - if (scrp->bitsPerPixel < 0) { - if (nomatch) - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Driver can't support depth 24 pixmap format (%d)\n", - PIX24TOBPP(pix24)); - else if ((depth24flags & (Support24bppFb | Support32bppFb)) == - NoDepth24Support) - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Driver can't support depth 24\n"); - else - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Can't find fbbpp for depth 24\n"); - return FALSE; - } - scrp->bitsPerPixelFrom = X_PROBED; - } - - if (scrp->depth <= 0) { - /* bitsPerPixel is already set */ - switch (scrp->bitsPerPixel) { - case 32: - scrp->depth = 24; - break; - default: - /* 1, 4, 8, 16 and 24 */ - scrp->depth = scrp->bitsPerPixel; - break; - } - scrp->depthFrom = X_PROBED; - } - - /* Sanity checks */ - if (scrp->depth < 1 || scrp->depth > 32) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Specified depth (%d) is not in the range 1-32\n", - scrp->depth); - return FALSE; - } - switch (scrp->bitsPerPixel) { - case 1: - case 4: - case 8: - case 16: - case 24: - case 32: - break; - default: - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Specified fbbpp (%d) is not a permitted value\n", - scrp->bitsPerPixel); - return FALSE; - } - if (scrp->depth > scrp->bitsPerPixel) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Specified depth (%d) is greater than the fbbpp (%d)\n", - scrp->depth, scrp->bitsPerPixel); - return FALSE; - } - - /* set scrp->pixmap24 if the driver isn't flexible */ - if (scrp->bitsPerPixel == 24 && !DO_PIX32FOR24(depth24flags)) { - scrp->pixmap24 = Pix24Use24; - } - if (scrp->bitsPerPixel == 32 && !DO_PIX24FOR32(depth24flags)) { - scrp->pixmap24 = Pix24Use32; - } - - /* - * Find the Display subsection matching the depth/fbbpp and initialise - * scrp->display with it. - */ - for (i = 0, disp = scrp->confScreen->displays; - i < scrp->confScreen->numdisplays; i++, disp++) { - if ((disp->depth == scrp->depth && disp->fbbpp == scrp->bitsPerPixel) - || (disp->depth == scrp->depth && disp->fbbpp <= 0) - || (disp->fbbpp == scrp->bitsPerPixel && disp->depth <= 0)) { - scrp->display = disp; - break; - } - } - - /* - * If an exact match can't be found, see if there is one with no - * depth or fbbpp specified. - */ - if (i == scrp->confScreen->numdisplays) { - for (i = 0, disp = scrp->confScreen->displays; - i < scrp->confScreen->numdisplays; i++, disp++) { - if (disp->depth <= 0 && disp->fbbpp <= 0) { - scrp->display = disp; - break; - } - } - } - - /* - * If all else fails, create a default one. - */ - if (i == scrp->confScreen->numdisplays) { - scrp->confScreen->numdisplays++; - scrp->confScreen->displays = - xnfrealloc(scrp->confScreen->displays, - scrp->confScreen->numdisplays * sizeof(DispRec)); - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "Creating default Display subsection in Screen section\n" - "\t\"%s\" for depth/fbbpp %d/%d\n", - scrp->confScreen->id, scrp->depth, scrp->bitsPerPixel); - memset(&scrp->confScreen->displays[i], 0, sizeof(DispRec)); - scrp->confScreen->displays[i].blackColour.red = -1; - scrp->confScreen->displays[i].blackColour.green = -1; - scrp->confScreen->displays[i].blackColour.blue = -1; - scrp->confScreen->displays[i].whiteColour.red = -1; - scrp->confScreen->displays[i].whiteColour.green = -1; - scrp->confScreen->displays[i].whiteColour.blue = -1; - scrp->confScreen->displays[i].defaultVisual = -1; - scrp->confScreen->displays[i].modes = xnfalloc(sizeof(char *)); - scrp->confScreen->displays[i].modes[0] = NULL; - scrp->confScreen->displays[i].depth = depth; - scrp->confScreen->displays[i].fbbpp = fbbpp; - scrp->display = &scrp->confScreen->displays[i]; - } - - /* - * Setup defaults for the display-wide attributes the framebuffer will - * need. These defaults should eventually be set globally, and not - * dependent on the screens. - */ - scrp->imageByteOrder = IMAGE_BYTE_ORDER; - scrp->bitmapScanlinePad = BITMAP_SCANLINE_PAD; - if (scrp->depth < 8) { - /* Planar modes need these settings */ - scrp->bitmapScanlineUnit = 8; - scrp->bitmapBitOrder = MSBFirst; - } else { - scrp->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; - scrp->bitmapBitOrder = BITMAP_BIT_ORDER; - } - - /* - * If an unusual depth is required, add it to scrp->formats. The formats - * for the common depths are handled globally in InitOutput - */ - switch (scrp->depth) { - case 1: - case 4: - case 8: - case 15: - case 16: - case 24: - /* Common depths. Nothing to do for them */ - break; - default: - if (!xf86AddPixFormat(scrp, scrp->depth, 0, 0)) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Can't add pixmap format for depth %d\n", scrp->depth); - return FALSE; - } - } - - /* Initialise the framebuffer format for this screen */ - scrp->fbFormat.depth = scrp->depth; - scrp->fbFormat.bitsPerPixel = scrp->bitsPerPixel; - scrp->fbFormat.scanlinePad = BITMAP_SCANLINE_PAD; - - return TRUE; -} - -/* - * Print out the selected depth and bpp. - */ -void -xf86PrintDepthBpp(ScrnInfoPtr scrp) -{ - xf86DrvMsg(scrp->scrnIndex, scrp->depthFrom, "Depth %d, ", scrp->depth); - xf86Msg(scrp->bitsPerPixelFrom, "framebuffer bpp %d\n", scrp->bitsPerPixel); -} - -/* - * xf86SetWeight sets scrp->weight, scrp->mask, scrp->offset, and for depths - * greater than MAX_PSEUDO_DEPTH also scrp->rgbBits. - */ -Bool -xf86SetWeight(ScrnInfoPtr scrp, rgb weight, rgb mask) -{ - MessageType weightFrom = X_DEFAULT; - - scrp->weight.red = 0; - scrp->weight.green = 0; - scrp->weight.blue = 0; - - if (xf86Weight.red > 0 && xf86Weight.green > 0 && xf86Weight.blue > 0) { - scrp->weight = xf86Weight; - weightFrom = X_CMDLINE; - } else if (scrp->display->weight.red > 0 && scrp->display->weight.green > 0 - && scrp->display->weight.blue > 0) { - scrp->weight = scrp->display->weight; - weightFrom = X_CONFIG; - } else if (weight.red > 0 && weight.green > 0 && weight.blue > 0) { - scrp->weight = weight; - } else { - switch (scrp->depth) { - case 1: - case 4: - case 8: - scrp->weight.red = scrp->weight.green = - scrp->weight.blue = scrp->rgbBits; - break; - case 15: - scrp->weight.red = scrp->weight.green = scrp->weight.blue = 5; - break; - case 16: - scrp->weight.red = scrp->weight.blue = 5; - scrp->weight.green = 6; - break; - case 24: - scrp->weight.red = scrp->weight.green = scrp->weight.blue = 8; - break; - case 30: - scrp->weight.red = scrp->weight.green = scrp->weight.blue = 10; - break; - } - } - - if (scrp->weight.red) - xf86DrvMsg(scrp->scrnIndex, weightFrom, "RGB weight %d%d%d\n", - (int)scrp->weight.red, (int)scrp->weight.green, - (int)scrp->weight.blue); - - if (scrp->depth > MAX_PSEUDO_DEPTH && - (scrp->depth != scrp->weight.red + scrp->weight.green + - scrp->weight.blue)) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Weight given (%d%d%d) is inconsistent with the " - "depth (%d)\n", - (int)scrp->weight.red, (int)scrp->weight.green, - (int)scrp->weight.blue, scrp->depth); - return FALSE; - } - if (scrp->depth > MAX_PSEUDO_DEPTH && scrp->weight.red) { - /* - * XXX Does this even mean anything for TrueColor visuals? - * If not, we shouldn't even be setting it here. However, this - * matches the behaviour of 3.x versions of XFree86. - */ - scrp->rgbBits = scrp->weight.red; - if (scrp->weight.green > scrp->rgbBits) - scrp->rgbBits = scrp->weight.green; - if (scrp->weight.blue > scrp->rgbBits) - scrp->rgbBits = scrp->weight.blue; - } - - /* Set the mask and offsets */ - if (mask.red == 0 || mask.green == 0 || mask.blue == 0) { - /* Default to a setting common to PC hardware */ - scrp->offset.red = scrp->weight.green + scrp->weight.blue; - scrp->offset.green = scrp->weight.blue; - scrp->offset.blue = 0; - scrp->mask.red = ((1 << scrp->weight.red) - 1) << scrp->offset.red; - scrp->mask.green = ((1 << scrp->weight.green) - 1) - << scrp->offset.green; - scrp->mask.blue = (1 << scrp->weight.blue) - 1; - } else { - /* Initialise to the values passed */ - scrp->mask.red = mask.red; - scrp->mask.green = mask.green; - scrp->mask.blue = mask.blue; - scrp->offset.red = ffs(mask.red); - scrp->offset.green = ffs(mask.green); - scrp->offset.blue = ffs(mask.blue); - } - return TRUE; -} - -Bool -xf86SetDefaultVisual(ScrnInfoPtr scrp, int visual) -{ - MessageType visualFrom = X_DEFAULT; - - if (defaultColorVisualClass >= 0) { - scrp->defaultVisual = defaultColorVisualClass; - visualFrom = X_CMDLINE; - } else if (scrp->display->defaultVisual >= 0) { - scrp->defaultVisual = scrp->display->defaultVisual; - visualFrom = X_CONFIG; - } else if (visual >= 0) { - scrp->defaultVisual = visual; - } else { - if (scrp->depth == 1) - scrp->defaultVisual = StaticGray; - else if (scrp->depth == 4) - scrp->defaultVisual = StaticColor; - else if (scrp->depth <= MAX_PSEUDO_DEPTH) - scrp->defaultVisual = PseudoColor; - else - scrp->defaultVisual = TrueColor; - } - switch (scrp->defaultVisual) { - case StaticGray: - case GrayScale: - case StaticColor: - case PseudoColor: - case TrueColor: - case DirectColor: - xf86DrvMsg(scrp->scrnIndex, visualFrom, "Default visual is %s\n", - xf86VisualNames[scrp->defaultVisual]); - return TRUE; - default: - - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Invalid default visual class (%d)\n", scrp->defaultVisual); - return FALSE; - } -} - -#define TEST_GAMMA(g) \ - (g).red > GAMMA_ZERO || (g).green > GAMMA_ZERO || (g).blue > GAMMA_ZERO - -#define SET_GAMMA(g) \ - (g) > GAMMA_ZERO ? (g) : 1.0 - -Bool -xf86SetGamma(ScrnInfoPtr scrp, Gamma gamma) -{ - MessageType from = X_DEFAULT; -#if 0 - xf86MonPtr DDC = (xf86MonPtr)(scrp->monitor->DDC); -#endif - if (TEST_GAMMA(xf86Gamma)) { - from = X_CMDLINE; - scrp->gamma.red = SET_GAMMA(xf86Gamma.red); - scrp->gamma.green = SET_GAMMA(xf86Gamma.green); - scrp->gamma.blue = SET_GAMMA(xf86Gamma.blue); - } else if (TEST_GAMMA(scrp->monitor->gamma)) { - from = X_CONFIG; - scrp->gamma.red = SET_GAMMA(scrp->monitor->gamma.red); - scrp->gamma.green = SET_GAMMA(scrp->monitor->gamma.green); - scrp->gamma.blue = SET_GAMMA(scrp->monitor->gamma.blue); -#if 0 - } else if ( DDC && DDC->features.gamma > GAMMA_ZERO ) { - from = X_PROBED; - scrp->gamma.red = SET_GAMMA(DDC->features.gamma); - scrp->gamma.green = SET_GAMMA(DDC->features.gamma); - scrp->gamma.blue = SET_GAMMA(DDC->features.gamma); - /* EDID structure version 2 gives optional seperate red, green & blue gamma values - * in bytes 0x57-0x59 */ -#endif - } else if (TEST_GAMMA(gamma)) { - scrp->gamma.red = SET_GAMMA(gamma.red); - scrp->gamma.green = SET_GAMMA(gamma.green); - scrp->gamma.blue = SET_GAMMA(gamma.blue); - } else { - scrp->gamma.red = 1.0; - scrp->gamma.green = 1.0; - scrp->gamma.blue = 1.0; - } - /* Pretend we succeeded if we support better a gamma system. - * This avoids a confusing message. - */ - if (xf86_crtc_supports_gamma(scrp)) - return TRUE; - xf86DrvMsg(scrp->scrnIndex, from, - "Using gamma correction (%.1f, %.1f, %.1f)\n", - scrp->gamma.red, scrp->gamma.green, scrp->gamma.blue); - - return TRUE; -} - -#undef TEST_GAMMA -#undef SET_GAMMA - - -/* - * Set the DPI from the command line option. XXX should allow it to be - * calculated from the widthmm/heightmm values. - */ - -#undef MMPERINCH -#define MMPERINCH 25.4 - -void -xf86SetDpi(ScrnInfoPtr pScrn, int x, int y) -{ - MessageType from = X_DEFAULT; - xf86MonPtr DDC = (xf86MonPtr)(pScrn->monitor->DDC); - int ddcWidthmm, ddcHeightmm; - int widthErr, heightErr; - - /* XXX Maybe there is no need for widthmm/heightmm in ScrnInfoRec */ - pScrn->widthmm = pScrn->monitor->widthmm; - pScrn->heightmm = pScrn->monitor->heightmm; - - if (DDC && (DDC->features.hsize > 0 && DDC->features.vsize > 0) ) { - /* DDC gives display size in mm for individual modes, - * but cm for monitor - */ - ddcWidthmm = DDC->features.hsize * 10; /* 10mm in 1cm */ - ddcHeightmm = DDC->features.vsize * 10; /* 10mm in 1cm */ - } else { - ddcWidthmm = ddcHeightmm = 0; - } - - if (monitorResolution > 0) { - pScrn->xDpi = monitorResolution; - pScrn->yDpi = monitorResolution; - from = X_CMDLINE; - } else if (pScrn->widthmm > 0 || pScrn->heightmm > 0) { - from = X_CONFIG; - if (pScrn->widthmm > 0) { - pScrn->xDpi = - (int)((double)pScrn->virtualX * MMPERINCH / pScrn->widthmm); - } - if (pScrn->heightmm > 0) { - pScrn->yDpi = - (int)((double)pScrn->virtualY * MMPERINCH / pScrn->heightmm); - } - if (pScrn->xDpi > 0 && pScrn->yDpi <= 0) - pScrn->yDpi = pScrn->xDpi; - if (pScrn->yDpi > 0 && pScrn->xDpi <= 0) - pScrn->xDpi = pScrn->yDpi; - xf86DrvMsg(pScrn->scrnIndex, from, "Display dimensions: (%d, %d) mm\n", - pScrn->widthmm, pScrn->heightmm); - - /* Warn if config and probe disagree about display size */ - if ( ddcWidthmm && ddcHeightmm ) { - if (pScrn->widthmm > 0) { - widthErr = abs(ddcWidthmm - pScrn->widthmm); - } else { - widthErr = 0; - } - if (pScrn->heightmm > 0) { - heightErr = abs(ddcHeightmm - pScrn->heightmm); - } else { - heightErr = 0; - } - if (widthErr>10 || heightErr>10) { - /* Should include config file name for monitor here */ - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Probed monitor is %dx%d mm, using Displaysize %dx%d mm\n", - ddcWidthmm,ddcHeightmm, pScrn->widthmm,pScrn->heightmm); - } - } - } else if ( ddcWidthmm && ddcHeightmm ) { - from = X_PROBED; - xf86DrvMsg(pScrn->scrnIndex, from, "Display dimensions: (%d, %d) mm\n", - ddcWidthmm, ddcHeightmm ); - pScrn->widthmm = ddcWidthmm; - pScrn->heightmm = ddcHeightmm; - if (pScrn->widthmm > 0) { - pScrn->xDpi = - (int)((double)pScrn->virtualX * MMPERINCH / pScrn->widthmm); - } - if (pScrn->heightmm > 0) { - pScrn->yDpi = - (int)((double)pScrn->virtualY * MMPERINCH / pScrn->heightmm); - } - if (pScrn->xDpi > 0 && pScrn->yDpi <= 0) - pScrn->yDpi = pScrn->xDpi; - if (pScrn->yDpi > 0 && pScrn->xDpi <= 0) - pScrn->xDpi = pScrn->yDpi; - } else { - if (x > 0) - pScrn->xDpi = x; - else - pScrn->xDpi = DEFAULT_DPI; - if (y > 0) - pScrn->yDpi = y; - else - pScrn->yDpi = DEFAULT_DPI; - } - xf86DrvMsg(pScrn->scrnIndex, from, "DPI set to (%d, %d)\n", - pScrn->xDpi, pScrn->yDpi); -} - -#undef MMPERINCH - - -void -xf86SetBlackWhitePixels(ScreenPtr pScreen) -{ - if (xf86FlipPixels) { - pScreen->whitePixel = 0; - pScreen->blackPixel = 1; - } else { - pScreen->whitePixel = 1; - pScreen->blackPixel = 0; - } -} - -/* - * xf86SetRootClip -- - * Enable or disable rendering to the screen by - * setting the root clip list and revalidating - * all of the windows - */ - -static void -xf86SetRootClip (ScreenPtr pScreen, Bool enable) -{ - WindowPtr pWin = WindowTable[pScreen->myNum]; - WindowPtr pChild; - Bool WasViewable = (Bool)(pWin->viewable); - Bool anyMarked = FALSE; - WindowPtr pLayerWin; - BoxRec box; - - if (WasViewable) - { - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - (void) (*pScreen->MarkOverlappedWindows)(pChild, - pChild, - &pLayerWin); - } - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - if (pWin->valdata) - { - if (HasBorder (pWin)) - { - RegionPtr borderVisible; - - borderVisible = REGION_CREATE(pScreen, NullBox, 1); - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, &pWin->winSize); - pWin->valdata->before.borderVisible = borderVisible; - } - pWin->valdata->before.resized = TRUE; - } - } - - /* - * Use REGION_BREAK to avoid optimizations in ValidateTree - * that assume the root borderClip can't change well, normally - * it doesn't...) - */ - if (enable) - { - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - REGION_INIT (pScreen, &pWin->winSize, &box, 1); - REGION_INIT (pScreen, &pWin->borderSize, &box, 1); - if (WasViewable) - REGION_RESET(pScreen, &pWin->borderClip, &box); - pWin->drawable.width = pScreen->width; - pWin->drawable.height = pScreen->height; - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - else - { - REGION_EMPTY(pScreen, &pWin->borderClip); - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - - ResizeChildrenWinSize (pWin, 0, 0, 0, 0); - - if (WasViewable) - { - if (pWin->firstChild) - { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, - pWin->firstChild, - (WindowPtr *)NULL); - } - else - { - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - } - - - if (anyMarked) - (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); - } - - if (WasViewable) - { - if (anyMarked) - (*pScreen->HandleExposures)(pWin); - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); - } - if (pWin->realized) - WindowsRestructured (); - FlushAllOutput (); -} - -/* - * Function to enable/disable access to the frame buffer - * - * This is used when VT switching and when entering/leaving DGA direct mode. - * - * This has been rewritten again to eliminate the saved pixmap. The - * devPrivate field in the screen pixmap is set to NULL to catch code - * accidentally referencing the frame buffer while the X server is not - * supposed to touch it. - * - * Here, we exchange the pixmap private data, rather than the pixmaps - * themselves to avoid having to find and change any references to the screen - * pixmap such as GC's, window privates etc. This also means that this code - * does not need to know exactly how the pixmap pixels are accessed. Further, - * this exchange is >not< done through the screen's ModifyPixmapHeader() - * vector. This means the called frame buffer code layers can determine - * whether they are switched in or out by keeping track of the root pixmap's - * private data, and therefore don't need to access pScrnInfo->vtSema. - */ -void -xf86EnableDisableFBAccess(int scrnIndex, Bool enable) -{ - ScrnInfoPtr pScrnInfo = xf86Screens[scrnIndex]; - ScreenPtr pScreen = pScrnInfo->pScreen; - PixmapPtr pspix; - - pspix = (*pScreen->GetScreenPixmap) (pScreen); - if (enable) - { - /* - * Restore the screen pixmap devPrivate field - */ - pspix->devPrivate = pScrnInfo->pixmapPrivate; - /* - * Restore all of the clip lists on the screen - */ - if (!xf86Resetting) - xf86SetRootClip (pScreen, TRUE); - - } - else - { - /* - * Empty all of the clip lists on the screen - */ - xf86SetRootClip (pScreen, FALSE); - /* - * save the screen pixmap devPrivate field and - * replace it with NULL so accidental references - * to the frame buffer are caught - */ - pScrnInfo->pixmapPrivate = pspix->devPrivate; - pspix->devPrivate.ptr = NULL; - } -} - -/* Print driver messages in the standard format */ - -#undef PREFIX_SIZE -#define PREFIX_SIZE 14 - -void -xf86VDrvMsgVerb(int scrnIndex, MessageType type, int verb, const char *format, - va_list args) -{ - char *tmpFormat; - - /* Prefix the scrnIndex name to the format string. */ - if (scrnIndex >= 0 && scrnIndex < xf86NumScreens && - xf86Screens[scrnIndex]->name) { - tmpFormat = xalloc(strlen(format) + - strlen(xf86Screens[scrnIndex]->name) + - PREFIX_SIZE + 1); - if (!tmpFormat) - return; - - snprintf(tmpFormat, PREFIX_SIZE + 1, "%s(%d): ", - xf86Screens[scrnIndex]->name, scrnIndex); - - strcat(tmpFormat, format); - LogVMessageVerb(type, verb, tmpFormat, args); - xfree(tmpFormat); - } else - LogVMessageVerb(type, verb, format, args); -} -#undef PREFIX_SIZE - -/* Print driver messages, with verbose level specified directly */ -void -xf86DrvMsgVerb(int scrnIndex, MessageType type, int verb, const char *format, - ...) -{ - va_list ap; - - va_start(ap, format); - xf86VDrvMsgVerb(scrnIndex, type, verb, format, ap); - va_end(ap); -} - -/* Print driver messages, with verbose level of 1 (default) */ -void -xf86DrvMsg(int scrnIndex, MessageType type, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - xf86VDrvMsgVerb(scrnIndex, type, 1, format, ap); - va_end(ap); -} - -/* Print non-driver messages with verbose level specified directly */ -void -xf86MsgVerb(MessageType type, int verb, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - xf86VDrvMsgVerb(-1, type, verb, format, ap); - va_end(ap); -} - -/* Print non-driver messages with verbose level of 1 (default) */ -void -xf86Msg(MessageType type, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - xf86VDrvMsgVerb(-1, type, 1, format, ap); - va_end(ap); -} - -/* Just like ErrorF, but with the verbose level checked */ -void -xf86ErrorFVerb(int verb, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - if (xf86Verbose >= verb || xf86LogVerbose >= verb) - LogVWrite(verb, format, ap); - va_end(ap); -} - -/* Like xf86ErrorFVerb, but with an implied verbose level of 1 */ -void -xf86ErrorF(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - if (xf86Verbose >= 1 || xf86LogVerbose >= 1) - LogVWrite(1, format, ap); - va_end(ap); -} - - -void -xf86LogInit(void) -{ - char *lf = NULL; - -#define LOGSUFFIX ".log" -#define LOGOLDSUFFIX ".old" - - /* Get the log file name */ - if (xf86LogFileFrom == X_DEFAULT) { - /* Append the display number and ".log" */ - lf = malloc(strlen(xf86LogFile) + strlen("%s") + - strlen(LOGSUFFIX) + 1); - if (!lf) - FatalError("Cannot allocate space for the log file name\n"); - sprintf(lf, "%s%%s" LOGSUFFIX, xf86LogFile); - xf86LogFile = lf; - } - - xf86LogFile = LogInit(xf86LogFile, LOGOLDSUFFIX); - xf86LogFileWasOpened = TRUE; - - xf86SetVerbosity(xf86Verbose); - xf86SetLogVerbosity(xf86LogVerbose); - -#undef LOGSUFFIX -#undef LOGOLDSUFFIX - - free(lf); -} - -void -xf86CloseLog(void) -{ - LogClose(); -} - - -/* - * Drivers can use these for using their own SymTabRecs. - */ - -const char * -xf86TokenToString(SymTabPtr table, int token) -{ - int i; - - for (i = 0; table[i].token >= 0 && table[i].token != token; i++) - ; - - if (table[i].token < 0) - return NULL; - else - return(table[i].name); -} - -int -xf86StringToToken(SymTabPtr table, const char *string) -{ - int i; - - if (string == NULL) - return -1; - - for (i = 0; table[i].token >= 0 && xf86NameCmp(string, table[i].name); i++) - ; - - return(table[i].token); -} - -/* - * helper to display the clocks found on a card - */ -void -xf86ShowClocks(ScrnInfoPtr scrp, MessageType from) -{ - int j; - - xf86DrvMsg(scrp->scrnIndex, from, "Pixel clocks available:"); - for (j=0; j < scrp->numClocks; j++) { - if ((j % 4) == 0) { - xf86ErrorF("\n"); - xf86DrvMsg(scrp->scrnIndex, from, "pixel clocks:"); - } - xf86ErrorF(" %7.3f", (double)scrp->clock[j] / 1000.0); - } - xf86ErrorF("\n"); -} - - -/* - * This prints out the driver identify message, including the names of - * the supported chipsets. - * - * XXX This makes assumptions about the line width, etc. Maybe we could - * use a more general "pretty print" function for messages. - */ -void -xf86PrintChipsets(const char *drvname, const char *drvmsg, SymTabPtr chips) -{ - int len, i; - - len = 6 + strlen(drvname) + 2 + strlen(drvmsg) + 2; - xf86Msg(X_INFO, "%s: %s:", drvname, drvmsg); - for (i = 0; chips[i].name != NULL; i++) { - if (i != 0) { - xf86ErrorF(","); - len++; - } - if (len + 2 + strlen(chips[i].name) < 78) { - xf86ErrorF(" "); - len++; - } else { - xf86ErrorF("\n\t"); - len = 8; - } - xf86ErrorF("%s", chips[i].name); - len += strlen(chips[i].name); - } - xf86ErrorF("\n"); -} - - -int -xf86MatchDevice(const char *drivername, GDevPtr **sectlist) -{ - GDevPtr gdp, *pgdp = NULL; - confScreenPtr screensecptr; - int i,j; - - if (sectlist) - *sectlist = NULL; - - if (xf86DoConfigure && xf86DoConfigurePass1) return 1; - - /* - * This is a very important function that matches the device sections - * as they show up in the config file with the drivers that the server - * loads at run time. - * - * ChipProbe can call - * int xf86MatchDevice(char * drivername, GDevPtr ** sectlist) - * with its driver name. The function allocates an array of GDevPtr and - * returns this via sectlist and returns the number of elements in - * this list as return value. 0 means none found, -1 means fatal error. - * - * It can figure out which of the Device sections to use for which card - * (using things like the Card statement, etc). For single headed servers - * there will of course be just one such Device section. - */ - i = 0; - - /* - * first we need to loop over all the Screens sections to get to all - * 'active' device sections - */ - for (j=0; xf86ConfigLayout.screens[j].screen != NULL; j++) { - screensecptr = xf86ConfigLayout.screens[j].screen; - if ((screensecptr->device->driver != NULL) - && (xf86NameCmp( screensecptr->device->driver,drivername) == 0) - && (! screensecptr->device->claimed)) { - /* - * we have a matching driver that wasn't claimed, yet - */ - pgdp = xnfrealloc(pgdp, (i + 2) * sizeof(GDevPtr)); - pgdp[i++] = screensecptr->device; - } - } - - /* Then handle the inactive devices */ - j = 0; - while (xf86ConfigLayout.inactives[j].identifier) { - gdp = &xf86ConfigLayout.inactives[j]; - if (gdp->driver && !gdp->claimed && - !xf86NameCmp(gdp->driver,drivername)) { - /* we have a matching driver that wasn't claimed yet */ - pgdp = xnfrealloc(pgdp, (i + 2) * sizeof(GDevPtr)); - pgdp[i++] = gdp; - } - j++; - } - - /* - * make the array NULL terminated and return its address - */ - if (i) - pgdp[i] = NULL; - - if (sectlist) - *sectlist = pgdp; - else - xfree(pgdp); - return i; -} - -static Bool -pciDeviceHasBars(struct pci_device *pci) -{ - int i; - - for (i = 0; i < 6; i++) - if (pci->regions[i].size) - return TRUE; - - if (pci->rom_size) - return TRUE; - - return FALSE; -} - -struct Inst { - struct pci_device * pci; - GDevPtr dev; - Bool foundHW; /* PCIid in list of supported chipsets */ - Bool claimed; /* BusID matches with a device section */ - int chip; - int screen; -}; - - -/** - * Find set of unclaimed devices matching a given vendor ID. - * - * Used by drivers to find as yet unclaimed devices matching the specified - * vendor ID. - * - * \param driverName Name of the driver. This is used to find Device - * sections in the config file. - * \param vendorID PCI vendor ID of associated devices. If zero, then - * the true vendor ID must be encoded in the \c PCIid - * fields of the \c PCIchipsets entries. - * \param chipsets Symbol table used to associate chipset names with - * PCI IDs. - * \param devList List of Device sections parsed from the config file. - * \param numDevs Number of entries in \c devList. - * \param drvp Pointer the driver's control structure. - * \param foundEntities Returned list of entity indicies associated with the - * driver. - * - * \returns - * The number of elements in returned in \c foundEntities on success or zero - * on failure. - * - * \todo - * This function does a bit more than short description says. Fill in some - * more of the details of its operation. - * - * \todo - * The \c driverName parameter is redundant. It is the same as - * \c DriverRec::driverName. In a future version of this function, remove - * that parameter. - */ -int -xf86MatchPciInstances(const char *driverName, int vendorID, - SymTabPtr chipsets, PciChipsets *PCIchipsets, - GDevPtr *devList, int numDevs, DriverPtr drvp, - int **foundEntities) -{ - int i,j; - struct pci_device * pPci; - struct pci_device_iterator *iter; - struct Inst *instances = NULL; - int numClaimedInstances = 0; - int allocatedInstances = 0; - int numFound = 0; - SymTabRec *c; - PciChipsets *id; - int *retEntities = NULL; - - *foundEntities = NULL; - - - /* Each PCI device will contribute at least one entry. Each device - * section can contribute at most one entry. The sum of the two is - * guaranteed to be larger than the maximum possible number of entries. - * Do this calculation and memory allocation once now to eliminate the - * need for realloc calls inside the loop. - */ - if (!(xf86DoConfigure && xf86DoConfigurePass1)) { - unsigned max_entries = numDevs; - - iter = pci_slot_match_iterator_create(NULL); - while ((pPci = pci_device_next(iter)) != NULL) { - max_entries++; - } - - pci_iterator_destroy(iter); - instances = xnfalloc(max_entries * sizeof(struct Inst)); - } - - iter = pci_slot_match_iterator_create(NULL); - while ((pPci = pci_device_next(iter)) != NULL) { - unsigned device_class = pPci->device_class; - Bool foundVendor = FALSE; - - - /* Convert the pre-PCI 2.0 device class for a VGA adapter to the - * 2.0 version of the same class. - */ - if ( device_class == 0x00000101 ) { - device_class = 0x00030000; - } - - - /* Find PCI devices that match the given vendor ID. The vendor ID is - * either specified explicitly as a parameter to the function or - * implicitly encoded in the high bits of id->PCIid. - * - * The first device with a matching vendor is recorded, even if the - * device ID doesn't match. This is done because the Device section - * in the xorg.conf file can over-ride the device ID. A matching PCI - * ID might not be found now, but after the device ID over-ride is - * applied there /might/ be a match. - */ - for (id = PCIchipsets; id->PCIid != -1; id++) { - const unsigned vendor_id = ((id->PCIid & 0xFFFF0000) >> 16) - | vendorID; - const unsigned device_id = (id->PCIid & 0x0000FFFF); - const unsigned match_class = 0x00030000 | id->PCIid; - - if ((vendor_id == pPci->vendor_id) - || ((vendorID == PCI_VENDOR_GENERIC) && (match_class == device_class))) { - if (!foundVendor && (instances != NULL)) { - ++allocatedInstances; - instances[allocatedInstances - 1].pci = pPci; - instances[allocatedInstances - 1].dev = NULL; - instances[allocatedInstances - 1].claimed = FALSE; - instances[allocatedInstances - 1].foundHW = FALSE; - instances[allocatedInstances - 1].screen = 0; - } - - foundVendor = TRUE; - - if ( (device_id == pPci->device_id) - || ((vendorID == PCI_VENDOR_GENERIC) - && (match_class == device_class)) ) { - if ( instances != NULL ) { - instances[allocatedInstances - 1].foundHW = TRUE; - instances[allocatedInstances - 1].chip = id->numChipset; - } - - - if ( xf86DoConfigure && xf86DoConfigurePass1 ) { - if (xf86CheckPciSlot(pPci)) { - GDevPtr pGDev = - xf86AddBusDeviceToConfigure(drvp->driverName, - BUS_PCI, pPci, -1); - if (pGDev) { - /* After configure pass 1, chipID and chipRev - * are treated as over-rides, so clobber them - * here. - */ - pGDev->chipID = -1; - pGDev->chipRev = -1; - } - - numFound++; - } - } - else { - numFound++; - } - - break; - } - } - } - } - - pci_iterator_destroy(iter); - - - /* In "probe only" or "configure" mode (signaled by instances being NULL), - * our work is done. Return the number of detected devices. - */ - if ( instances == NULL ) { - return numFound; - } - - - /* - * This may be debatable, but if no PCI devices with a matching vendor - * type is found, return zero now. It is probably not desirable to - * allow the config file to override this. - */ - if (allocatedInstances <= 0) { - xfree(instances); - return 0; - } - - - DebugF("%s instances found: %d\n", driverName, allocatedInstances); - - /* - * Check for devices that need duplicated instances. This is required - * when there is more than one screen per entity. - * - * XXX This currently doesn't work for cases where the BusID isn't - * specified explicitly in the config file. - */ - - for (j = 0; j < numDevs; j++) { - if (devList[j]->screen > 0 && devList[j]->busID - && *devList[j]->busID) { - for (i = 0; i < allocatedInstances; i++) { - pPci = instances[i].pci; - if (xf86ComparePciBusString(devList[j]->busID, - PCI_MAKE_BUS( pPci->domain, pPci->bus ), - pPci->dev, - pPci->func)) { - allocatedInstances++; - instances[allocatedInstances - 1] = instances[i]; - instances[allocatedInstances - 1].screen = - devList[j]->screen; - numFound++; - break; - } - } - } - } - - for (i = 0; i < allocatedInstances; i++) { - GDevPtr dev = NULL; - GDevPtr devBus = NULL; - - pPci = instances[i].pci; - for (j = 0; j < numDevs; j++) { - if (devList[j]->busID && *devList[j]->busID) { - if (xf86ComparePciBusString(devList[j]->busID, - PCI_MAKE_BUS( pPci->domain, pPci->bus ), - pPci->dev, - pPci->func) && - devList[j]->screen == instances[i].screen) { - - if (devBus) - xf86MsgVerb(X_WARNING,0, - "%s: More than one matching Device section for " - "instances\n\t(BusID: %s) found: %s\n", - driverName, devList[j]->busID, - devList[j]->identifier); - else - devBus = devList[j]; - } - } else { - /* - * if device section without BusID is found - * only assign to it to the primary device. - */ - if (xf86IsPrimaryPci(pPci)) { - xf86Msg(X_PROBED, "Assigning device section with no busID" - " to primary device\n"); - if (dev || devBus) - xf86MsgVerb(X_WARNING, 0, - "%s: More than one matching Device section " - "found: %s\n", driverName, devList[j]->identifier); - else - dev = devList[j]; - } - } - } - if (devBus) dev = devBus; /* busID preferred */ - if (!dev) { - if (xf86CheckPciSlot(pPci) && pciDeviceHasBars(pPci)) { - xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section " - "for instance (BusID PCI:%u@%u:%u:%u) found\n", - driverName, pPci->domain, pPci->bus, pPci->dev, - pPci->func); - } - } else { - numClaimedInstances++; - instances[i].claimed = TRUE; - instances[i].dev = dev; - } - } - DebugF("%s instances found: %d\n", driverName, numClaimedInstances); - /* - * Now check that a chipset or chipID override in the device section - * is valid. Chipset has precedence over chipID. - * If chipset is not valid ignore BusSlot completely. - */ - for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) { - MessageType from = X_PROBED; - - if (!instances[i].claimed) { - continue; - } - if (instances[i].dev->chipset) { - for (c = chipsets; c->token >= 0; c++) { - if (xf86NameCmp(c->name, instances[i].dev->chipset) == 0) - break; - } - if (c->token == -1) { - instances[i].claimed = FALSE; - numClaimedInstances--; - xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device " - "section \"%s\" isn't valid for this driver\n", - driverName, instances[i].dev->chipset, - instances[i].dev->identifier); - } else { - instances[i].chip = c->token; - - for (id = PCIchipsets; id->numChipset >= 0; id++) { - if (id->numChipset == instances[i].chip) - break; - } - if(id->numChipset >=0){ - xf86Msg(X_CONFIG,"Chipset override: %s\n", - instances[i].dev->chipset); - from = X_CONFIG; - } else { - instances[i].claimed = FALSE; - numClaimedInstances--; - xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device " - "section \"%s\" isn't a valid PCI chipset\n", - driverName, instances[i].dev->chipset, - instances[i].dev->identifier); - } - } - } else if (instances[i].dev->chipID > 0) { - for (id = PCIchipsets; id->numChipset >= 0; id++) { - if (id->PCIid == instances[i].dev->chipID) - break; - } - if (id->numChipset == -1) { - instances[i].claimed = FALSE; - numClaimedInstances--; - xf86MsgVerb(X_WARNING, 0, "%s: ChipID 0x%04X in Device " - "section \"%s\" isn't valid for this driver\n", - driverName, instances[i].dev->chipID, - instances[i].dev->identifier); - } else { - instances[i].chip = id->numChipset; - - xf86Msg( X_CONFIG,"ChipID override: 0x%04X\n", - instances[i].dev->chipID); - from = X_CONFIG; - } - } else if (!instances[i].foundHW) { - /* - * This means that there was no override and the PCI chipType - * doesn't match one that is supported - */ - instances[i].claimed = FALSE; - numClaimedInstances--; - } - if (instances[i].claimed == TRUE){ - for (c = chipsets; c->token >= 0; c++) { - if (c->token == instances[i].chip) - break; - } - xf86Msg(from,"Chipset %s found\n", - c->name); - } - } - - /* - * Of the claimed instances, check that another driver hasn't already - * claimed its slot. - */ - numFound = 0; - for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) { - - if (!instances[i].claimed) - continue; - pPci = instances[i].pci; - - - /* - * Allow the same entity to be used more than once for devices with - * multiple screens per entity. This assumes implicitly that there - * will be a screen == 0 instance. - * - * XXX Need to make sure that two different drivers don't claim - * the same screen > 0 instance. - */ - if (instances[i].screen == 0 && !xf86CheckPciSlot( pPci )) - continue; - - DebugF("%s: card at %d:%d:%d is claimed by a Device section\n", - driverName, pPci->bus, pPci->dev, pPci->func); - - /* Allocate an entry in the lists to be returned */ - numFound++; - retEntities = xnfrealloc(retEntities, numFound * sizeof(int)); - retEntities[numFound - 1] = xf86ClaimPciSlot( pPci, drvp, - instances[i].chip, - instances[i].dev, - instances[i].dev->active); - if (retEntities[numFound - 1] == -1 && instances[i].screen > 0) { - for (j = 0; j < xf86NumEntities; j++) { - EntityPtr pEnt = xf86Entities[j]; - if (pEnt->bus.type != BUS_PCI) - continue; - if (pEnt->bus.id.pci == pPci) { - retEntities[numFound - 1] = j; - xf86AddDevToEntity(j, instances[i].dev); - break; - } - } - } - } - xfree(instances); - if (numFound > 0) { - *foundEntities = retEntities; - } - - return numFound; -} - -/* - * xf86GetClocks -- get the dot-clocks via a BIG BAD hack ... - */ -void -xf86GetClocks(ScrnInfoPtr pScrn, int num, Bool (*ClockFunc)(ScrnInfoPtr, int), - void (*ProtectRegs)(ScrnInfoPtr, Bool), - void (*BlankScreen)(ScrnInfoPtr, Bool), IOADDRESS vertsyncreg, - int maskval, int knownclkindex, int knownclkvalue) -{ - register int status = vertsyncreg; - unsigned long i, cnt, rcnt, sync; - - /* First save registers that get written on */ - (*ClockFunc)(pScrn, CLK_REG_SAVE); - - if (num > MAXCLOCKS) - num = MAXCLOCKS; - - for (i = 0; i < num; i++) - { - if (ProtectRegs) - (*ProtectRegs)(pScrn, TRUE); - if (!(*ClockFunc)(pScrn, i)) - { - pScrn->clock[i] = -1; - continue; - } - if (ProtectRegs) - (*ProtectRegs)(pScrn, FALSE); - if (BlankScreen) - (*BlankScreen)(pScrn, FALSE); - - usleep(50000); /* let VCO stabilise */ - - cnt = 0; - sync = 200000; - - while ((inb(status) & maskval) == 0x00) - if (sync-- == 0) goto finish; - /* Something appears to be happening, so reset sync count */ - sync = 200000; - while ((inb(status) & maskval) == maskval) - if (sync-- == 0) goto finish; - /* Something appears to be happening, so reset sync count */ - sync = 200000; - while ((inb(status) & maskval) == 0x00) - if (sync-- == 0) goto finish; - - for (rcnt = 0; rcnt < 5; rcnt++) - { - while (!(inb(status) & maskval)) - cnt++; - while ((inb(status) & maskval)) - cnt++; - } - -finish: - pScrn->clock[i] = cnt ? cnt : -1; - if (BlankScreen) - (*BlankScreen)(pScrn, TRUE); - } - - for (i = 0; i < num; i++) - { - if (i != knownclkindex) - { - if (pScrn->clock[i] == -1) - { - pScrn->clock[i] = 0; - } - else - { - pScrn->clock[i] = (int)(0.5 + - (((float)knownclkvalue) * pScrn->clock[knownclkindex]) / - (pScrn->clock[i])); - /* Round to nearest 10KHz */ - pScrn->clock[i] += 5; - pScrn->clock[i] /= 10; - pScrn->clock[i] *= 10; - } - } - } - - pScrn->clock[knownclkindex] = knownclkvalue; - pScrn->numClocks = num; - - /* Restore registers that were written on */ - (*ClockFunc)(pScrn, CLK_REG_RESTORE); -} - -const char * -xf86GetVisualName(int visual) -{ - if (visual < 0 || visual > DirectColor) - return NULL; - - return xf86VisualNames[visual]; -} - - -int -xf86GetVerbosity(void) -{ - return max(xf86Verbose, xf86LogVerbose); -} - -Pix24Flags -xf86GetPix24(void) -{ - return xf86Info.pixmap24; -} - - -int -xf86GetDepth(void) -{ - return xf86Depth; -} - - -rgb -xf86GetWeight(void) -{ - return xf86Weight; -} - - -Gamma -xf86GetGamma(void) -{ - return xf86Gamma; -} - - -Bool -xf86GetFlipPixels(void) -{ - return xf86FlipPixels; -} - - -const char * -xf86GetServerName(void) -{ - return xf86ServerName; -} - - -Bool -xf86ServerIsExiting(void) -{ - return (dispatchException & DE_TERMINATE) == DE_TERMINATE; -} - - -Bool -xf86ServerIsResetting(void) -{ - return xf86Resetting; -} - - -Bool -xf86ServerIsInitialising(void) -{ - return xf86Initialising; -} - - -Bool -xf86ServerIsOnlyDetecting(void) -{ - return xf86DoConfigure; -} - - -Bool -xf86CaughtSignal(void) -{ - return xf86Info.caughtSignal; -} - - -Bool -xf86GetVidModeAllowNonLocal(void) -{ - return xf86Info.vidModeAllowNonLocal; -} - - -Bool -xf86GetVidModeEnabled(void) -{ - return xf86Info.vidModeEnabled; -} - -Bool -xf86GetModInDevAllowNonLocal(void) -{ - return xf86Info.miscModInDevAllowNonLocal; -} - - -Bool -xf86GetModInDevEnabled(void) -{ - return xf86Info.miscModInDevEnabled; -} - - -Bool -xf86GetAllowMouseOpenFail(void) -{ - return xf86Info.allowMouseOpenFail; -} - - -Bool -xf86IsPc98(void) -{ -#if SUPPORT_PC98 - return xf86Info.pc98; -#else - return FALSE; -#endif -} - -void -xf86DisableRandR(void) -{ - xf86Info.disableRandR = TRUE; - xf86Info.randRFrom = X_PROBED; -} - -CARD32 -xf86GetModuleVersion(pointer module) -{ - return (CARD32)LoaderGetModuleVersion(module); -} - -pointer -xf86LoadDrvSubModule(DriverPtr drv, const char *name) -{ - pointer ret; - int errmaj = 0, errmin = 0; - - ret = LoadSubModule(drv->module, name, NULL, NULL, NULL, NULL, - &errmaj, &errmin); - if (!ret) - LoaderErrorMsg(NULL, name, errmaj, errmin); - return ret; -} - -pointer -xf86LoadSubModule(ScrnInfoPtr pScrn, const char *name) -{ - pointer ret; - int errmaj = 0, errmin = 0; - - ret = LoadSubModule(pScrn->module, name, NULL, NULL, NULL, NULL, - &errmaj, &errmin); - if (!ret) - LoaderErrorMsg(pScrn->name, name, errmaj, errmin); - return ret; -} - -/* - * xf86LoadOneModule loads a single module. - */ -pointer -xf86LoadOneModule(char *name, pointer opt) -{ - int errmaj, errmin; - char *Name; - pointer mod; - - if (!name) - return NULL; - - /* Normalise the module name */ - Name = xf86NormalizeName(name); - - /* Skip empty names */ - if (Name == NULL) - return NULL; - if (*Name == '\0') { - xfree(Name); - return NULL; - } - - mod = LoadModule(Name, NULL, NULL, NULL, opt, NULL, &errmaj, &errmin); - if (!mod) - LoaderErrorMsg(NULL, Name, errmaj, errmin); - xfree(Name); - return mod; -} - -void -xf86UnloadSubModule(pointer mod) -{ - /* - * This is disabled for now. The loader isn't smart enough yet to undo - * relocations. - */ -#if 0 - UnloadSubModule(mod); -#endif -} - -Bool -xf86LoaderCheckSymbol(const char *name) -{ - return LoaderSymbol(name) != NULL; -} - -typedef enum { - OPTION_BACKING_STORE -} BSOpts; - -static const OptionInfoRec BSOptions[] = { - { OPTION_BACKING_STORE, "BackingStore", OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, OPTV_NONE, {0}, FALSE } -}; - -void -xf86SetBackingStore(ScreenPtr pScreen) -{ - Bool useBS = FALSE; - MessageType from = X_DEFAULT; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - OptionInfoPtr options; - - options = xnfalloc(sizeof(BSOptions)); - (void)memcpy(options, BSOptions, sizeof(BSOptions)); - xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); - - /* check for commandline option here */ - if (xf86bsEnableFlag) { - from = X_CMDLINE; - useBS = TRUE; - } else if (xf86bsDisableFlag) { - from = X_CMDLINE; - useBS = FALSE; - } else { - if (xf86GetOptValBool(options, OPTION_BACKING_STORE, &useBS)) - from = X_CONFIG; - } - xfree(options); - pScreen->backingStoreSupport = useBS ? Always : NotUseful; - if (serverGeneration == 1) - xf86DrvMsg(pScreen->myNum, from, "Backing store %s\n", - useBS ? "enabled" : "disabled"); -} - - -typedef enum { - OPTION_SILKEN_MOUSE -} SMOpts; - -static const OptionInfoRec SMOptions[] = { - { OPTION_SILKEN_MOUSE, "SilkenMouse", OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, OPTV_NONE, {0}, FALSE } -}; - -void -xf86SetSilkenMouse (ScreenPtr pScreen) -{ - Bool useSM = TRUE; - MessageType from = X_DEFAULT; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - OptionInfoPtr options; - - options = xnfalloc(sizeof(SMOptions)); - (void)memcpy(options, SMOptions, sizeof(SMOptions)); - xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); - - /* check for commandline option here */ - /* disable if screen shares resources */ - /* TODO VGA arb disable silken mouse */ - if (xf86silkenMouseDisableFlag) { - from = X_CMDLINE; - useSM = FALSE; - } else { - if (xf86GetOptValBool(options, OPTION_SILKEN_MOUSE, &useSM)) - from = X_CONFIG; - } - xfree(options); - /* - * XXX quick hack to report correctly for OSs that can't do SilkenMouse - * yet. Should handle this differently so that alternate async methods - * work correctly with this too. - */ - pScrn->silkenMouse = useSM && xf86Info.useSIGIO && xf86SIGIOSupported(); - if (serverGeneration == 1) - xf86DrvMsg(pScreen->myNum, from, "Silken mouse %s\n", - pScrn->silkenMouse ? "enabled" : "disabled"); -} - -/* Wrote this function for the PM2 Xv driver, preliminary. */ - -pointer -xf86FindXvOptions(int scrnIndex, int adaptor_index, char *port_name, - char **adaptor_name, pointer *adaptor_options) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - confXvAdaptorPtr adaptor; - int i; - - if (adaptor_index >= pScrn->confScreen->numxvadaptors) { - if (adaptor_name) *adaptor_name = NULL; - if (adaptor_options) *adaptor_options = NULL; - return NULL; - } - - adaptor = &pScrn->confScreen->xvadaptors[adaptor_index]; - if (adaptor_name) *adaptor_name = adaptor->identifier; - if (adaptor_options) *adaptor_options = adaptor->options; - - for (i = 0; i < adaptor->numports; i++) - if (!xf86NameCmp(adaptor->ports[i].identifier, port_name)) - return adaptor->ports[i].options; - - return NULL; -} - -/* Rather than duplicate loader's get OS function, just include it directly */ -#define LoaderGetOS xf86GetOS -#include "loader/os.c" - -/* new RAC */ -/* - * xf86ConfigPciEntityInactive() -- This function can be used - * to configure an inactive entity as well as to reconfigure an - * previously active entity inactive. If the entity has been - * assigned to a screen before it will be removed. If p_chip is - * non-NULL all static resources listed there will be registered. - */ -static void -xf86ConfigPciEntityInactive(EntityInfoPtr pEnt, PciChipsets *p_chip, - EntityProc init, EntityProc enter, - EntityProc leave, pointer private) -{ - ScrnInfoPtr pScrn; - - if ((pScrn = xf86FindScreenForEntity(pEnt->index))) - xf86RemoveEntityFromScreen(pScrn,pEnt->index); - - /* shared resources are only needed when entity is active: remove */ - xf86SetEntityFuncs(pEnt->index,init,enter,leave,private); -} - -static void -xf86ConfigFbEntityInactive(EntityInfoPtr pEnt, EntityProc init, - EntityProc enter, EntityProc leave, pointer private) -{ - ScrnInfoPtr pScrn; - - if ((pScrn = xf86FindScreenForEntity(pEnt->index))) - xf86RemoveEntityFromScreen(pScrn,pEnt->index); - xf86SetEntityFuncs(pEnt->index,init,enter,leave,private); -} - -ScrnInfoPtr -xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex, - PciChipsets *p_chip, void *dummy, EntityProc init, - EntityProc enter, EntityProc leave, pointer private) -{ - EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); - if (!pEnt) return pScrn; - - if (!(pEnt->location.type == BUS_PCI) - || !xf86GetPciInfoForEntity(entityIndex)) { - xfree(pEnt); - return pScrn; - } - if (!pEnt->active) { - xf86ConfigPciEntityInactive(pEnt, p_chip, init, enter, - leave, private); - xfree(pEnt); - return pScrn; - } - - if (!pScrn) - pScrn = xf86AllocateScreen(pEnt->driver,scrnFlag); - if (xf86IsEntitySharable(entityIndex)) { - xf86SetEntityShared(entityIndex); - } - xf86AddEntityToScreen(pScrn,entityIndex); - if (xf86IsEntityShared(entityIndex)) { - return pScrn; - } - xfree(pEnt); - - xf86SetEntityFuncs(entityIndex,init,enter,leave,private); - - return pScrn; -} - -ScrnInfoPtr -xf86ConfigFbEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex, - EntityProc init, EntityProc enter, EntityProc leave, - pointer private) -{ - EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); - if (!pEnt) return pScrn; - - if (!(pEnt->location.type == BUS_NONE)) { - xfree(pEnt); - return pScrn; - } - - if (!pEnt->active) { - xf86ConfigFbEntityInactive(pEnt, init, enter, leave, private); - xfree(pEnt); - return pScrn; - } - - if (!pScrn) - pScrn = xf86AllocateScreen(pEnt->driver,scrnFlag); - xf86AddEntityToScreen(pScrn,entityIndex); - - xf86SetEntityFuncs(entityIndex,init,enter,leave,private); - - return pScrn; -} - -/* - * - * OBSOLETE ! xf86ConfigActivePciEntity() is an obsolete function. - * It is likely to be removed. Don't use! - */ - -Bool -xf86ConfigActivePciEntity(ScrnInfoPtr pScrn, int entityIndex, - PciChipsets *p_chip, void *dummy, EntityProc init, - EntityProc enter, EntityProc leave, pointer private) -{ - EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); - if (!pEnt) return FALSE; - - if (!pEnt->active || !(pEnt->location.type == BUS_PCI)) { - xfree(pEnt); - return FALSE; - } - xf86AddEntityToScreen(pScrn,entityIndex); - - xfree(pEnt); - if (!xf86SetEntityFuncs(entityIndex,init,enter,leave,private)) - return FALSE; - - return TRUE; -} - -Bool -xf86IsScreenPrimary(int scrnIndex) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - int i; - - for (i=0 ; i < pScrn->numEntities; i++) { - if (xf86IsEntityPrimary(i)) - return TRUE; - } - return FALSE; -} - -int -xf86RegisterRootWindowProperty(int ScrnIndex, Atom property, Atom type, - int format, unsigned long len, pointer value ) -{ - RootWinPropPtr pNewProp = NULL, pRegProp; - int i; - Bool existing = FALSE; - - DebugF("xf86RegisterRootWindowProperty(%d, %ld, %ld, %d, %ld, %p)\n", - ScrnIndex, property, type, format, len, value); - - if (ScrnIndex<0 || ScrnIndex>=xf86NumScreens) { - return(BadMatch); - } - - if (xf86RegisteredPropertiesTable && - xf86RegisteredPropertiesTable[ScrnIndex]) { - for (pNewProp = xf86RegisteredPropertiesTable[ScrnIndex]; - pNewProp; pNewProp = pNewProp->next) { - if (strcmp(pNewProp->name, NameForAtom(property)) == 0) - break; - } - } - - if (!pNewProp) { - if ((pNewProp = (RootWinPropPtr)xalloc(sizeof(RootWinProp))) == NULL) { - return(BadAlloc); - } - /* - * We will put this property at the end of the list so that - * the changes are made in the order they were requested. - */ - pNewProp->next = NULL; - } else { - if (pNewProp->name) - xfree(pNewProp->name); - existing = TRUE; - } - - pNewProp->name = xnfstrdup(NameForAtom(property)); - pNewProp->type = type; - pNewProp->format = format; - pNewProp->size = len; - pNewProp->data = value; - - DebugF("new property filled\n"); - - if (NULL==xf86RegisteredPropertiesTable) { - DebugF("creating xf86RegisteredPropertiesTable[] size %d\n", - xf86NumScreens); - if ( NULL==(xf86RegisteredPropertiesTable=(RootWinPropPtr*)xnfcalloc(sizeof(RootWinProp),xf86NumScreens) )) { - return(BadAlloc); - } - for (i=0; i<xf86NumScreens; i++) { - xf86RegisteredPropertiesTable[i] = NULL; - } - } - - DebugF("xf86RegisteredPropertiesTable %p\n", - (void *)xf86RegisteredPropertiesTable); - DebugF("xf86RegisteredPropertiesTable[%d] %p\n", - ScrnIndex, (void *)xf86RegisteredPropertiesTable[ScrnIndex]); - - if (!existing) { - if ( xf86RegisteredPropertiesTable[ScrnIndex] == NULL) { - xf86RegisteredPropertiesTable[ScrnIndex] = pNewProp; - } else { - pRegProp = xf86RegisteredPropertiesTable[ScrnIndex]; - while (pRegProp->next != NULL) { - DebugF("- next %p\n", (void *)pRegProp); - pRegProp = pRegProp->next; - } - pRegProp->next = pNewProp; - } - } - DebugF("xf86RegisterRootWindowProperty succeeded\n"); - return(Success); -} - -Bool -xf86IsUnblank(int mode) -{ - switch(mode) { - case SCREEN_SAVER_OFF: - case SCREEN_SAVER_FORCER: - return TRUE; - case SCREEN_SAVER_ON: - case SCREEN_SAVER_CYCLE: - return FALSE; - default: - xf86MsgVerb(X_WARNING, 0, "Unexpected save screen mode: %d\n", mode); - return TRUE; - } -} - -void -xf86MotionHistoryAllocate(LocalDevicePtr local) -{ - AllocateMotionHistory(local->dev); -} +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * Authors: Dirk Hohndel <hohndel@XFree86.Org> + * David Dawes <dawes@XFree86.Org> + * ... and others + * + * This file includes the helper functions that the server provides for + * different drivers. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <pciaccess.h> +#include "Pci.h" + +#include <X11/X.h> +#include "os.h" +#include "servermd.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "propertyst.h" +#include "gcstruct.h" +#include "loaderProcs.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#include "micmap.h" +#include "xf86DDC.h" +#include "xf86Xinput.h" +#include "xf86InPriv.h" +#include "mivalidate.h" +#include "xf86Bus.h" +#include "xf86Crtc.h" + +/* For xf86GetClocks */ +#if defined(CSRG_BASED) || defined(__GNU__) +#define HAS_SETPRIORITY +#include <sys/resource.h> +#endif + +static int xf86ScrnInfoPrivateCount = 0; + + +/* Add a pointer to a new DriverRec to xf86DriverList */ + +void +xf86AddDriver(DriverPtr driver, pointer module, int flags) +{ + /* Don't add null entries */ + if (!driver) + return; + + if (xf86DriverList == NULL) + xf86NumDrivers = 0; + + xf86NumDrivers++; + xf86DriverList = xnfrealloc(xf86DriverList, + xf86NumDrivers * sizeof(DriverPtr)); + xf86DriverList[xf86NumDrivers - 1] = xnfalloc(sizeof(DriverRec)); + if (flags & HaveDriverFuncs) + *xf86DriverList[xf86NumDrivers - 1] = *driver; + else { + (void) memset( xf86DriverList[xf86NumDrivers - 1], 0, + sizeof( DriverRec ) ); + (void) memcpy( xf86DriverList[xf86NumDrivers - 1], driver, + sizeof(DriverRec1)); + + } + xf86DriverList[xf86NumDrivers - 1]->module = module; + xf86DriverList[xf86NumDrivers - 1]->refCount = 0; +} + +void +xf86DeleteDriver(int drvIndex) +{ + if (xf86DriverList[drvIndex] + && (!xf86DriverHasEntities(xf86DriverList[drvIndex]))) { + if (xf86DriverList[drvIndex]->module) + UnloadModule(xf86DriverList[drvIndex]->module); + free(xf86DriverList[drvIndex]); + xf86DriverList[drvIndex] = NULL; + } +} + +/* Add a pointer to a new InputDriverRec to xf86InputDriverList */ + +void +xf86AddInputDriver(InputDriverPtr driver, pointer module, int flags) +{ + /* Don't add null entries */ + if (!driver) + return; + + if (xf86InputDriverList == NULL) + xf86NumInputDrivers = 0; + + xf86NumInputDrivers++; + xf86InputDriverList = xnfrealloc(xf86InputDriverList, + xf86NumInputDrivers * sizeof(InputDriverPtr)); + xf86InputDriverList[xf86NumInputDrivers - 1] = + xnfalloc(sizeof(InputDriverRec)); + *xf86InputDriverList[xf86NumInputDrivers - 1] = *driver; + xf86InputDriverList[xf86NumInputDrivers - 1]->module = module; + xf86InputDriverList[xf86NumInputDrivers - 1]->refCount = 0; +} + +void +xf86DeleteInputDriver(int drvIndex) +{ + if (xf86InputDriverList[drvIndex] && xf86InputDriverList[drvIndex]->module) + UnloadModule(xf86InputDriverList[drvIndex]->module); + free(xf86InputDriverList[drvIndex]); + xf86InputDriverList[drvIndex] = NULL; +} + +InputDriverPtr +xf86LookupInputDriver(const char *name) +{ + int i; + + for (i = 0; i < xf86NumInputDrivers; i++) { + if (xf86InputDriverList[i] && xf86InputDriverList[i]->driverName && + xf86NameCmp(name, xf86InputDriverList[i]->driverName) == 0) + return xf86InputDriverList[i]; + } + return NULL; +} + +InputInfoPtr +xf86LookupInput(const char *name) +{ + InputInfoPtr p; + + for (p = xf86InputDevs; p != NULL; p = p->next) { + if (strcmp(name, p->name) == 0) + return p; + } + + return NULL; +} + +/* Allocate a new ScrnInfoRec in xf86Screens */ + +ScrnInfoPtr +xf86AllocateScreen(DriverPtr drv, int flags) +{ + int i; + + if (xf86Screens == NULL) + xf86NumScreens = 0; + + i = xf86NumScreens++; + xf86Screens = xnfrealloc(xf86Screens, xf86NumScreens * sizeof(ScrnInfoPtr)); + xf86Screens[i] = xnfcalloc(sizeof(ScrnInfoRec), 1); + xf86Screens[i]->scrnIndex = i; /* Changes when a screen is removed */ + xf86Screens[i]->origIndex = i; /* This never changes */ + xf86Screens[i]->privates = xnfcalloc(sizeof(DevUnion), + xf86ScrnInfoPrivateCount); + /* + * EnableDisableFBAccess now gets initialized in InitOutput() + * xf86Screens[i]->EnableDisableFBAccess = xf86EnableDisableFBAccess; + */ + + xf86Screens[i]->drv = drv; + drv->refCount++; + xf86Screens[i]->module = DuplicateModule(drv->module, NULL); + + xf86Screens[i]->DriverFunc = drv->driverFunc; + + return xf86Screens[i]; +} + + +/* + * Remove an entry from xf86Screens. Ideally it should free all allocated + * data. To do this properly may require a driver hook. + */ + +void +xf86DeleteScreen(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn; + int i; + + /* First check if the screen is valid */ + if (xf86NumScreens == 0 || xf86Screens == NULL) + return; + + if (scrnIndex > xf86NumScreens - 1) + return; + + if (!(pScrn = xf86Screens[scrnIndex])) + return; + + /* If a FreeScreen function is defined, call it here */ + if (pScrn->FreeScreen != NULL) + pScrn->FreeScreen(scrnIndex, 0); + + while (pScrn->modes) + xf86DeleteMode(&pScrn->modes, pScrn->modes); + + while (pScrn->modePool) + xf86DeleteMode(&pScrn->modePool, pScrn->modePool); + + xf86OptionListFree(pScrn->options); + + if (pScrn->module) + UnloadModule(pScrn->module); + + if (pScrn->drv) + pScrn->drv->refCount--; + + if (pScrn->privates) + free(pScrn->privates); + + xf86ClearEntityListForScreen(scrnIndex); + + free(pScrn); + + /* Move the other entries down, updating their scrnIndex fields */ + + xf86NumScreens--; + + for (i = scrnIndex; i < xf86NumScreens; i++) { + xf86Screens[i] = xf86Screens[i + 1]; + xf86Screens[i]->scrnIndex = i; + /* Also need to take care of the screen layout settings */ + } +} + +/* + * Allocate a private in ScrnInfoRec. + */ + +int +xf86AllocateScrnInfoPrivateIndex(void) +{ + int idx, i; + ScrnInfoPtr pScr; + DevUnion *nprivs; + + idx = xf86ScrnInfoPrivateCount++; + for (i = 0; i < xf86NumScreens; i++) { + pScr = xf86Screens[i]; + nprivs = xnfrealloc(pScr->privates, + xf86ScrnInfoPrivateCount * sizeof(DevUnion)); + /* Zero the new private */ + bzero(&nprivs[idx], sizeof(DevUnion)); + pScr->privates = nprivs; + } + return idx; +} + +/* Allocate a new InputInfoRec and append it to the tail of xf86InputDevs. */ +InputInfoPtr +xf86AllocateInput(InputDriverPtr drv, int flags) +{ + InputInfoPtr new, *prev = NULL; + + if (!(new = calloc(sizeof(InputInfoRec), 1))) + return NULL; + + new->drv = drv; + drv->refCount++; + new->module = DuplicateModule(drv->module, NULL); + + for (prev = &xf86InputDevs; *prev; prev = &(*prev)->next) + ; + + *prev = new; + new->next = NULL; + + return new; +} + + +/* + * Remove an entry from xf86InputDevs. Ideally it should free all allocated + * data. To do this properly may require a driver hook. + */ + +void +xf86DeleteInput(InputInfoPtr pInp, int flags) +{ + InputInfoPtr p; + + /* First check if the inputdev is valid. */ + if (pInp == NULL) + return; + +#if 0 + /* If a free function is defined, call it here. */ + if (pInp->free) + pInp->free(pInp, 0); +#endif + + if (pInp->module) + UnloadModule(pInp->module); + + if (pInp->drv) + pInp->drv->refCount--; + + /* This should *really* be handled in drv->UnInit(dev) call instead, but + * if the driver forgets about it make sure we free it or at least crash + * with flying colors */ + if (pInp->private) + free(pInp->private); + + /* Remove the entry from the list. */ + if (pInp == xf86InputDevs) + xf86InputDevs = pInp->next; + else { + p = xf86InputDevs; + while (p && p->next != pInp) + p = p->next; + if (p) + p->next = pInp->next; + /* Else the entry wasn't in the xf86InputDevs list (ignore this). */ + } + free(pInp); +} + +Bool +xf86AddPixFormat(ScrnInfoPtr pScrn, int depth, int bpp, int pad) +{ + int i; + + if (pScrn->numFormats >= MAXFORMATS) + return FALSE; + + if (bpp <= 0) { + if (depth == 1) + bpp = 1; + else if (depth <= 8) + bpp = 8; + else if (depth <= 16) + bpp = 16; + else if (depth <= 32) + bpp = 32; + else + return FALSE; + } + if (pad <= 0) + pad = BITMAP_SCANLINE_PAD; + + i = pScrn->numFormats++; + pScrn->formats[i].depth = depth; + pScrn->formats[i].bitsPerPixel = bpp; + pScrn->formats[i].scanlinePad = pad; + return TRUE; +} + +/* + * Set the depth we are using based on (in the following order of preference): + * - values given on the command line + * - values given in the config file + * - values provided by the driver + * - an overall default when nothing else is given + * + * Also find a Display subsection matching the depth/bpp found. + * + * Sets the following ScrnInfoRec fields: + * bitsPerPixel, pixmap24, depth, display, imageByteOrder, + * bitmapScanlinePad, bitmapScanlineUnit, bitmapBitOrder, numFormats, + * formats, fbFormat. + */ + +/* Can the screen handle 24 bpp pixmaps */ +#define DO_PIX24(f) ((f & Support24bppFb) || \ + ((f & Support32bppFb) && (f & SupportConvert24to32))) + +/* Can the screen handle 32 bpp pixmaps */ +#define DO_PIX32(f) ((f & Support32bppFb) || \ + ((f & Support24bppFb) && (f & SupportConvert32to24))) + +/* Does the screen prefer 32bpp fb for 24bpp pixmaps */ +#define CHOOSE32FOR24(f) ((f & Support32bppFb) && (f & SupportConvert24to32) \ + && (f & PreferConvert24to32)) + +/* Does the screen prefer 24bpp fb for 32bpp pixmaps */ +#define CHOOSE24FOR32(f) ((f & Support24bppFb) && (f & SupportConvert32to24) \ + && (f & PreferConvert32to24)) + +/* Can the screen handle 32bpp pixmaps for 24bpp fb */ +#define DO_PIX32FOR24(f) ((f & Support24bppFb) && (f & SupportConvert32to24)) + +/* Can the screen handle 24bpp pixmaps for 32bpp fb */ +#define DO_PIX24FOR32(f) ((f & Support32bppFb) && (f & SupportConvert24to32)) + +#ifndef GLOBAL_DEFAULT_DEPTH +#define GLOBAL_DEFAULT_DEPTH 24 +#endif + +Bool +xf86SetDepthBpp(ScrnInfoPtr scrp, int depth, int dummy, int fbbpp, + int depth24flags) +{ + int i; + DispPtr disp; + Pix24Flags pix24 = xf86Info.pixmap24; + Bool nomatch = FALSE; + + scrp->bitsPerPixel = -1; + scrp->depth = -1; + scrp->pixmap24 = Pix24DontCare; + scrp->bitsPerPixelFrom = X_DEFAULT; + scrp->depthFrom = X_DEFAULT; + + if (xf86FbBpp > 0) { + scrp->bitsPerPixel = xf86FbBpp; + scrp->bitsPerPixelFrom = X_CMDLINE; + } + + if (xf86Depth > 0) { + scrp->depth = xf86Depth; + scrp->depthFrom = X_CMDLINE; + } + + if (xf86FbBpp < 0 && xf86Depth < 0) { + if (scrp->confScreen->defaultfbbpp > 0) { + scrp->bitsPerPixel = scrp->confScreen->defaultfbbpp; + scrp->bitsPerPixelFrom = X_CONFIG; + } + if (scrp->confScreen->defaultdepth > 0) { + scrp->depth = scrp->confScreen->defaultdepth; + scrp->depthFrom = X_CONFIG; + } + + if (scrp->confScreen->defaultfbbpp <= 0 && + scrp->confScreen->defaultdepth <= 0) { + /* + * Check for DefaultDepth and DefaultFbBpp options in the + * Device sections. + */ + int i; + GDevPtr device; + Bool found = FALSE; + + for (i = 0; i < scrp->numEntities; i++) { + device = xf86GetDevFromEntity(scrp->entityList[i], + scrp->entityInstanceList[i]); + if (device && device->options) { + if (xf86FindOption(device->options, "DefaultDepth")) { + scrp->depth = xf86SetIntOption(device->options, + "DefaultDepth", -1); + scrp->depthFrom = X_CONFIG; + found = TRUE; + } + if (xf86FindOption(device->options, "DefaultFbBpp")) { + scrp->bitsPerPixel = xf86SetIntOption(device->options, + "DefaultFbBpp", + -1); + scrp->bitsPerPixelFrom = X_CONFIG; + found = TRUE; + } + } + if (found) + break; + } + } + } + + /* If none of these is set, pick a default */ + if (scrp->bitsPerPixel < 0 && scrp->depth < 0) { + if (fbbpp > 0 || depth > 0) { + if (fbbpp > 0) + scrp->bitsPerPixel = fbbpp; + if (depth > 0) + scrp->depth = depth; + } else { + scrp->depth = GLOBAL_DEFAULT_DEPTH; + } + } + + /* If any are not given, determine a default for the others */ + + if (scrp->bitsPerPixel < 0) { + /* The depth must be set */ + if (scrp->depth > -1) { + if (scrp->depth == 1) + scrp->bitsPerPixel = 1; + else if (scrp->depth <= 4) + scrp->bitsPerPixel = 4; + else if (scrp->depth <= 8) + scrp->bitsPerPixel = 8; + else if (scrp->depth <= 16) + scrp->bitsPerPixel = 16; + else if (scrp->depth <= 24) { + /* + * Figure out if a choice is possible based on the depth24 + * and pix24 flags. + */ + /* Check pix24 first */ + if (pix24 != Pix24DontCare) { + if (pix24 == Pix24Use32) { + if (DO_PIX32(depth24flags)) { + if (CHOOSE24FOR32(depth24flags)) + scrp->bitsPerPixel = 24; + else + scrp->bitsPerPixel = 32; + } else { + nomatch = TRUE; + } + } else if (pix24 == Pix24Use24) { + if (DO_PIX24(depth24flags)) { + if (CHOOSE32FOR24(depth24flags)) + scrp->bitsPerPixel = 32; + else + scrp->bitsPerPixel = 24; + } else { + nomatch = TRUE; + } + } + } else { + if (DO_PIX32(depth24flags)) { + if (CHOOSE24FOR32(depth24flags)) + scrp->bitsPerPixel = 24; + else + scrp->bitsPerPixel = 32; + } else if (DO_PIX24(depth24flags)) { + if (CHOOSE32FOR24(depth24flags)) + scrp->bitsPerPixel = 32; + else + scrp->bitsPerPixel = 24; + } + } + } else if (scrp->depth <= 32) + scrp->bitsPerPixel = 32; + else { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Specified depth (%d) is greater than 32\n", + scrp->depth); + return FALSE; + } + } else { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "xf86SetDepthBpp: internal error: depth and fbbpp" + " are both not set\n"); + return FALSE; + } + if (scrp->bitsPerPixel < 0) { + if (nomatch) + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Driver can't support depth 24 pixmap format (%d)\n", + PIX24TOBPP(pix24)); + else if ((depth24flags & (Support24bppFb | Support32bppFb)) == + NoDepth24Support) + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Driver can't support depth 24\n"); + else + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Can't find fbbpp for depth 24\n"); + return FALSE; + } + scrp->bitsPerPixelFrom = X_PROBED; + } + + if (scrp->depth <= 0) { + /* bitsPerPixel is already set */ + switch (scrp->bitsPerPixel) { + case 32: + scrp->depth = 24; + break; + default: + /* 1, 4, 8, 16 and 24 */ + scrp->depth = scrp->bitsPerPixel; + break; + } + scrp->depthFrom = X_PROBED; + } + + /* Sanity checks */ + if (scrp->depth < 1 || scrp->depth > 32) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Specified depth (%d) is not in the range 1-32\n", + scrp->depth); + return FALSE; + } + switch (scrp->bitsPerPixel) { + case 1: + case 4: + case 8: + case 16: + case 24: + case 32: + break; + default: + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Specified fbbpp (%d) is not a permitted value\n", + scrp->bitsPerPixel); + return FALSE; + } + if (scrp->depth > scrp->bitsPerPixel) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Specified depth (%d) is greater than the fbbpp (%d)\n", + scrp->depth, scrp->bitsPerPixel); + return FALSE; + } + + /* set scrp->pixmap24 if the driver isn't flexible */ + if (scrp->bitsPerPixel == 24 && !DO_PIX32FOR24(depth24flags)) { + scrp->pixmap24 = Pix24Use24; + } + if (scrp->bitsPerPixel == 32 && !DO_PIX24FOR32(depth24flags)) { + scrp->pixmap24 = Pix24Use32; + } + + /* + * Find the Display subsection matching the depth/fbbpp and initialise + * scrp->display with it. + */ + for (i = 0, disp = scrp->confScreen->displays; + i < scrp->confScreen->numdisplays; i++, disp++) { + if ((disp->depth == scrp->depth && disp->fbbpp == scrp->bitsPerPixel) + || (disp->depth == scrp->depth && disp->fbbpp <= 0) + || (disp->fbbpp == scrp->bitsPerPixel && disp->depth <= 0)) { + scrp->display = disp; + break; + } + } + + /* + * If an exact match can't be found, see if there is one with no + * depth or fbbpp specified. + */ + if (i == scrp->confScreen->numdisplays) { + for (i = 0, disp = scrp->confScreen->displays; + i < scrp->confScreen->numdisplays; i++, disp++) { + if (disp->depth <= 0 && disp->fbbpp <= 0) { + scrp->display = disp; + break; + } + } + } + + /* + * If all else fails, create a default one. + */ + if (i == scrp->confScreen->numdisplays) { + scrp->confScreen->numdisplays++; + scrp->confScreen->displays = + xnfrealloc(scrp->confScreen->displays, + scrp->confScreen->numdisplays * sizeof(DispRec)); + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Creating default Display subsection in Screen section\n" + "\t\"%s\" for depth/fbbpp %d/%d\n", + scrp->confScreen->id, scrp->depth, scrp->bitsPerPixel); + memset(&scrp->confScreen->displays[i], 0, sizeof(DispRec)); + scrp->confScreen->displays[i].blackColour.red = -1; + scrp->confScreen->displays[i].blackColour.green = -1; + scrp->confScreen->displays[i].blackColour.blue = -1; + scrp->confScreen->displays[i].whiteColour.red = -1; + scrp->confScreen->displays[i].whiteColour.green = -1; + scrp->confScreen->displays[i].whiteColour.blue = -1; + scrp->confScreen->displays[i].defaultVisual = -1; + scrp->confScreen->displays[i].modes = xnfalloc(sizeof(char *)); + scrp->confScreen->displays[i].modes[0] = NULL; + scrp->confScreen->displays[i].depth = depth; + scrp->confScreen->displays[i].fbbpp = fbbpp; + scrp->display = &scrp->confScreen->displays[i]; + } + + /* + * Setup defaults for the display-wide attributes the framebuffer will + * need. These defaults should eventually be set globally, and not + * dependent on the screens. + */ + scrp->imageByteOrder = IMAGE_BYTE_ORDER; + scrp->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + if (scrp->depth < 8) { + /* Planar modes need these settings */ + scrp->bitmapScanlineUnit = 8; + scrp->bitmapBitOrder = MSBFirst; + } else { + scrp->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + scrp->bitmapBitOrder = BITMAP_BIT_ORDER; + } + + /* + * If an unusual depth is required, add it to scrp->formats. The formats + * for the common depths are handled globally in InitOutput + */ + switch (scrp->depth) { + case 1: + case 4: + case 8: + case 15: + case 16: + case 24: + /* Common depths. Nothing to do for them */ + break; + default: + if (!xf86AddPixFormat(scrp, scrp->depth, 0, 0)) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Can't add pixmap format for depth %d\n", scrp->depth); + return FALSE; + } + } + + /* Initialise the framebuffer format for this screen */ + scrp->fbFormat.depth = scrp->depth; + scrp->fbFormat.bitsPerPixel = scrp->bitsPerPixel; + scrp->fbFormat.scanlinePad = BITMAP_SCANLINE_PAD; + + return TRUE; +} + +/* + * Print out the selected depth and bpp. + */ +void +xf86PrintDepthBpp(ScrnInfoPtr scrp) +{ + xf86DrvMsg(scrp->scrnIndex, scrp->depthFrom, "Depth %d, ", scrp->depth); + xf86Msg(scrp->bitsPerPixelFrom, "framebuffer bpp %d\n", scrp->bitsPerPixel); +} + +/* + * xf86SetWeight sets scrp->weight, scrp->mask, scrp->offset, and for depths + * greater than MAX_PSEUDO_DEPTH also scrp->rgbBits. + */ +Bool +xf86SetWeight(ScrnInfoPtr scrp, rgb weight, rgb mask) +{ + MessageType weightFrom = X_DEFAULT; + + scrp->weight.red = 0; + scrp->weight.green = 0; + scrp->weight.blue = 0; + + if (xf86Weight.red > 0 && xf86Weight.green > 0 && xf86Weight.blue > 0) { + scrp->weight = xf86Weight; + weightFrom = X_CMDLINE; + } else if (scrp->display->weight.red > 0 && scrp->display->weight.green > 0 + && scrp->display->weight.blue > 0) { + scrp->weight = scrp->display->weight; + weightFrom = X_CONFIG; + } else if (weight.red > 0 && weight.green > 0 && weight.blue > 0) { + scrp->weight = weight; + } else { + switch (scrp->depth) { + case 1: + case 4: + case 8: + scrp->weight.red = scrp->weight.green = + scrp->weight.blue = scrp->rgbBits; + break; + case 15: + scrp->weight.red = scrp->weight.green = scrp->weight.blue = 5; + break; + case 16: + scrp->weight.red = scrp->weight.blue = 5; + scrp->weight.green = 6; + break; + case 24: + scrp->weight.red = scrp->weight.green = scrp->weight.blue = 8; + break; + case 30: + scrp->weight.red = scrp->weight.green = scrp->weight.blue = 10; + break; + } + } + + if (scrp->weight.red) + xf86DrvMsg(scrp->scrnIndex, weightFrom, "RGB weight %d%d%d\n", + (int)scrp->weight.red, (int)scrp->weight.green, + (int)scrp->weight.blue); + + if (scrp->depth > MAX_PSEUDO_DEPTH && + (scrp->depth != scrp->weight.red + scrp->weight.green + + scrp->weight.blue)) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Weight given (%d%d%d) is inconsistent with the " + "depth (%d)\n", + (int)scrp->weight.red, (int)scrp->weight.green, + (int)scrp->weight.blue, scrp->depth); + return FALSE; + } + if (scrp->depth > MAX_PSEUDO_DEPTH && scrp->weight.red) { + /* + * XXX Does this even mean anything for TrueColor visuals? + * If not, we shouldn't even be setting it here. However, this + * matches the behaviour of 3.x versions of XFree86. + */ + scrp->rgbBits = scrp->weight.red; + if (scrp->weight.green > scrp->rgbBits) + scrp->rgbBits = scrp->weight.green; + if (scrp->weight.blue > scrp->rgbBits) + scrp->rgbBits = scrp->weight.blue; + } + + /* Set the mask and offsets */ + if (mask.red == 0 || mask.green == 0 || mask.blue == 0) { + /* Default to a setting common to PC hardware */ + scrp->offset.red = scrp->weight.green + scrp->weight.blue; + scrp->offset.green = scrp->weight.blue; + scrp->offset.blue = 0; + scrp->mask.red = ((1 << scrp->weight.red) - 1) << scrp->offset.red; + scrp->mask.green = ((1 << scrp->weight.green) - 1) + << scrp->offset.green; + scrp->mask.blue = (1 << scrp->weight.blue) - 1; + } else { + /* Initialise to the values passed */ + scrp->mask.red = mask.red; + scrp->mask.green = mask.green; + scrp->mask.blue = mask.blue; + scrp->offset.red = ffs(mask.red); + scrp->offset.green = ffs(mask.green); + scrp->offset.blue = ffs(mask.blue); + } + return TRUE; +} + +Bool +xf86SetDefaultVisual(ScrnInfoPtr scrp, int visual) +{ + MessageType visualFrom = X_DEFAULT; + + if (defaultColorVisualClass >= 0) { + scrp->defaultVisual = defaultColorVisualClass; + visualFrom = X_CMDLINE; + } else if (scrp->display->defaultVisual >= 0) { + scrp->defaultVisual = scrp->display->defaultVisual; + visualFrom = X_CONFIG; + } else if (visual >= 0) { + scrp->defaultVisual = visual; + } else { + if (scrp->depth == 1) + scrp->defaultVisual = StaticGray; + else if (scrp->depth == 4) + scrp->defaultVisual = StaticColor; + else if (scrp->depth <= MAX_PSEUDO_DEPTH) + scrp->defaultVisual = PseudoColor; + else + scrp->defaultVisual = TrueColor; + } + switch (scrp->defaultVisual) { + case StaticGray: + case GrayScale: + case StaticColor: + case PseudoColor: + case TrueColor: + case DirectColor: + xf86DrvMsg(scrp->scrnIndex, visualFrom, "Default visual is %s\n", + xf86VisualNames[scrp->defaultVisual]); + return TRUE; + default: + + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Invalid default visual class (%d)\n", scrp->defaultVisual); + return FALSE; + } +} + +#define TEST_GAMMA(g) \ + (g).red > GAMMA_ZERO || (g).green > GAMMA_ZERO || (g).blue > GAMMA_ZERO + +#define SET_GAMMA(g) \ + (g) > GAMMA_ZERO ? (g) : 1.0 + +Bool +xf86SetGamma(ScrnInfoPtr scrp, Gamma gamma) +{ + MessageType from = X_DEFAULT; +#if 0 + xf86MonPtr DDC = (xf86MonPtr)(scrp->monitor->DDC); +#endif + if (TEST_GAMMA(xf86Gamma)) { + from = X_CMDLINE; + scrp->gamma.red = SET_GAMMA(xf86Gamma.red); + scrp->gamma.green = SET_GAMMA(xf86Gamma.green); + scrp->gamma.blue = SET_GAMMA(xf86Gamma.blue); + } else if (TEST_GAMMA(scrp->monitor->gamma)) { + from = X_CONFIG; + scrp->gamma.red = SET_GAMMA(scrp->monitor->gamma.red); + scrp->gamma.green = SET_GAMMA(scrp->monitor->gamma.green); + scrp->gamma.blue = SET_GAMMA(scrp->monitor->gamma.blue); +#if 0 + } else if ( DDC && DDC->features.gamma > GAMMA_ZERO ) { + from = X_PROBED; + scrp->gamma.red = SET_GAMMA(DDC->features.gamma); + scrp->gamma.green = SET_GAMMA(DDC->features.gamma); + scrp->gamma.blue = SET_GAMMA(DDC->features.gamma); + /* EDID structure version 2 gives optional seperate red, green & blue gamma values + * in bytes 0x57-0x59 */ +#endif + } else if (TEST_GAMMA(gamma)) { + scrp->gamma.red = SET_GAMMA(gamma.red); + scrp->gamma.green = SET_GAMMA(gamma.green); + scrp->gamma.blue = SET_GAMMA(gamma.blue); + } else { + scrp->gamma.red = 1.0; + scrp->gamma.green = 1.0; + scrp->gamma.blue = 1.0; + } + /* Pretend we succeeded if we support better a gamma system. + * This avoids a confusing message. + */ + if (xf86_crtc_supports_gamma(scrp)) + return TRUE; + xf86DrvMsg(scrp->scrnIndex, from, + "Using gamma correction (%.1f, %.1f, %.1f)\n", + scrp->gamma.red, scrp->gamma.green, scrp->gamma.blue); + + return TRUE; +} + +#undef TEST_GAMMA +#undef SET_GAMMA + + +/* + * Set the DPI from the command line option. XXX should allow it to be + * calculated from the widthmm/heightmm values. + */ + +#undef MMPERINCH +#define MMPERINCH 25.4 + +void +xf86SetDpi(ScrnInfoPtr pScrn, int x, int y) +{ + MessageType from = X_DEFAULT; + xf86MonPtr DDC = (xf86MonPtr)(pScrn->monitor->DDC); + int ddcWidthmm, ddcHeightmm; + int widthErr, heightErr; + + /* XXX Maybe there is no need for widthmm/heightmm in ScrnInfoRec */ + pScrn->widthmm = pScrn->monitor->widthmm; + pScrn->heightmm = pScrn->monitor->heightmm; + + if (DDC && (DDC->features.hsize > 0 && DDC->features.vsize > 0) ) { + /* DDC gives display size in mm for individual modes, + * but cm for monitor + */ + ddcWidthmm = DDC->features.hsize * 10; /* 10mm in 1cm */ + ddcHeightmm = DDC->features.vsize * 10; /* 10mm in 1cm */ + } else { + ddcWidthmm = ddcHeightmm = 0; + } + + if (monitorResolution > 0) { + pScrn->xDpi = monitorResolution; + pScrn->yDpi = monitorResolution; + from = X_CMDLINE; + } else if (pScrn->widthmm > 0 || pScrn->heightmm > 0) { + from = X_CONFIG; + if (pScrn->widthmm > 0) { + pScrn->xDpi = + (int)((double)pScrn->virtualX * MMPERINCH / pScrn->widthmm); + } + if (pScrn->heightmm > 0) { + pScrn->yDpi = + (int)((double)pScrn->virtualY * MMPERINCH / pScrn->heightmm); + } + if (pScrn->xDpi > 0 && pScrn->yDpi <= 0) + pScrn->yDpi = pScrn->xDpi; + if (pScrn->yDpi > 0 && pScrn->xDpi <= 0) + pScrn->xDpi = pScrn->yDpi; + xf86DrvMsg(pScrn->scrnIndex, from, "Display dimensions: (%d, %d) mm\n", + pScrn->widthmm, pScrn->heightmm); + + /* Warn if config and probe disagree about display size */ + if ( ddcWidthmm && ddcHeightmm ) { + if (pScrn->widthmm > 0) { + widthErr = abs(ddcWidthmm - pScrn->widthmm); + } else { + widthErr = 0; + } + if (pScrn->heightmm > 0) { + heightErr = abs(ddcHeightmm - pScrn->heightmm); + } else { + heightErr = 0; + } + if (widthErr>10 || heightErr>10) { + /* Should include config file name for monitor here */ + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Probed monitor is %dx%d mm, using Displaysize %dx%d mm\n", + ddcWidthmm,ddcHeightmm, pScrn->widthmm,pScrn->heightmm); + } + } + } else if ( ddcWidthmm && ddcHeightmm ) { + from = X_PROBED; + xf86DrvMsg(pScrn->scrnIndex, from, "Display dimensions: (%d, %d) mm\n", + ddcWidthmm, ddcHeightmm ); + pScrn->widthmm = ddcWidthmm; + pScrn->heightmm = ddcHeightmm; + if (pScrn->widthmm > 0) { + pScrn->xDpi = + (int)((double)pScrn->virtualX * MMPERINCH / pScrn->widthmm); + } + if (pScrn->heightmm > 0) { + pScrn->yDpi = + (int)((double)pScrn->virtualY * MMPERINCH / pScrn->heightmm); + } + if (pScrn->xDpi > 0 && pScrn->yDpi <= 0) + pScrn->yDpi = pScrn->xDpi; + if (pScrn->yDpi > 0 && pScrn->xDpi <= 0) + pScrn->xDpi = pScrn->yDpi; + } else { + if (x > 0) + pScrn->xDpi = x; + else + pScrn->xDpi = DEFAULT_DPI; + if (y > 0) + pScrn->yDpi = y; + else + pScrn->yDpi = DEFAULT_DPI; + } + xf86DrvMsg(pScrn->scrnIndex, from, "DPI set to (%d, %d)\n", + pScrn->xDpi, pScrn->yDpi); +} + +#undef MMPERINCH + + +void +xf86SetBlackWhitePixels(ScreenPtr pScreen) +{ + if (xf86FlipPixels) { + pScreen->whitePixel = 0; + pScreen->blackPixel = 1; + } else { + pScreen->whitePixel = 1; + pScreen->blackPixel = 0; + } +} + +/* + * xf86SetRootClip -- + * Enable or disable rendering to the screen by + * setting the root clip list and revalidating + * all of the windows + */ + +static void +xf86SetRootClip (ScreenPtr pScreen, Bool enable) +{ + WindowPtr pWin = WindowTable[pScreen->myNum]; + WindowPtr pChild; + Bool WasViewable = (Bool)(pWin->viewable); + Bool anyMarked = FALSE; + WindowPtr pLayerWin; + BoxRec box; + + if (WasViewable) + { + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + (void) (*pScreen->MarkOverlappedWindows)(pChild, + pChild, + &pLayerWin); + } + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + pWin->valdata->before.resized = TRUE; + } + } + + /* + * Use REGION_BREAK to avoid optimizations in ValidateTree + * that assume the root borderClip can't change well, normally + * it doesn't...) + */ + if (enable) + { + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + REGION_INIT (pScreen, &pWin->winSize, &box, 1); + REGION_INIT (pScreen, &pWin->borderSize, &box, 1); + if (WasViewable) + REGION_RESET(pScreen, &pWin->borderClip, &box); + pWin->drawable.width = pScreen->width; + pWin->drawable.height = pScreen->height; + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + else + { + REGION_EMPTY(pScreen, &pWin->borderClip); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + + ResizeChildrenWinSize (pWin, 0, 0, 0, 0); + + if (WasViewable) + { + if (pWin->firstChild) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, + pWin->firstChild, + (WindowPtr *)NULL); + } + else + { + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + } + + + if (anyMarked) + (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); + } + + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pWin); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + FlushAllOutput (); +} + +/* + * Function to enable/disable access to the frame buffer + * + * This is used when VT switching and when entering/leaving DGA direct mode. + * + * This has been rewritten again to eliminate the saved pixmap. The + * devPrivate field in the screen pixmap is set to NULL to catch code + * accidentally referencing the frame buffer while the X server is not + * supposed to touch it. + * + * Here, we exchange the pixmap private data, rather than the pixmaps + * themselves to avoid having to find and change any references to the screen + * pixmap such as GC's, window privates etc. This also means that this code + * does not need to know exactly how the pixmap pixels are accessed. Further, + * this exchange is >not< done through the screen's ModifyPixmapHeader() + * vector. This means the called frame buffer code layers can determine + * whether they are switched in or out by keeping track of the root pixmap's + * private data, and therefore don't need to access pScrnInfo->vtSema. + */ +void +xf86EnableDisableFBAccess(int scrnIndex, Bool enable) +{ + ScrnInfoPtr pScrnInfo = xf86Screens[scrnIndex]; + ScreenPtr pScreen = pScrnInfo->pScreen; + PixmapPtr pspix; + + pspix = (*pScreen->GetScreenPixmap) (pScreen); + if (enable) + { + /* + * Restore the screen pixmap devPrivate field + */ + pspix->devPrivate = pScrnInfo->pixmapPrivate; + /* + * Restore all of the clip lists on the screen + */ + if (!xf86Resetting) + xf86SetRootClip (pScreen, TRUE); + + } + else + { + /* + * Empty all of the clip lists on the screen + */ + xf86SetRootClip (pScreen, FALSE); + /* + * save the screen pixmap devPrivate field and + * replace it with NULL so accidental references + * to the frame buffer are caught + */ + pScrnInfo->pixmapPrivate = pspix->devPrivate; + pspix->devPrivate.ptr = NULL; + } +} + +/* Print driver messages in the standard format */ + +#undef PREFIX_SIZE +#define PREFIX_SIZE 14 + +void +xf86VDrvMsgVerb(int scrnIndex, MessageType type, int verb, const char *format, + va_list args) +{ + char *tmpFormat; + + /* Prefix the scrnIndex name to the format string. */ + if (scrnIndex >= 0 && scrnIndex < xf86NumScreens && + xf86Screens[scrnIndex]->name) { + tmpFormat = malloc(strlen(format) + + strlen(xf86Screens[scrnIndex]->name) + + PREFIX_SIZE + 1); + if (!tmpFormat) + return; + + snprintf(tmpFormat, PREFIX_SIZE + 1, "%s(%d): ", + xf86Screens[scrnIndex]->name, scrnIndex); + + strcat(tmpFormat, format); + LogVMessageVerb(type, verb, tmpFormat, args); + free(tmpFormat); + } else + LogVMessageVerb(type, verb, format, args); +} +#undef PREFIX_SIZE + +/* Print driver messages, with verbose level specified directly */ +void +xf86DrvMsgVerb(int scrnIndex, MessageType type, int verb, const char *format, + ...) +{ + va_list ap; + + va_start(ap, format); + xf86VDrvMsgVerb(scrnIndex, type, verb, format, ap); + va_end(ap); +} + +/* Print driver messages, with verbose level of 1 (default) */ +void +xf86DrvMsg(int scrnIndex, MessageType type, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + xf86VDrvMsgVerb(scrnIndex, type, 1, format, ap); + va_end(ap); +} + +/* Print non-driver messages with verbose level specified directly */ +void +xf86MsgVerb(MessageType type, int verb, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + xf86VDrvMsgVerb(-1, type, verb, format, ap); + va_end(ap); +} + +/* Print non-driver messages with verbose level of 1 (default) */ +void +xf86Msg(MessageType type, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + xf86VDrvMsgVerb(-1, type, 1, format, ap); + va_end(ap); +} + +/* Just like ErrorF, but with the verbose level checked */ +void +xf86ErrorFVerb(int verb, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + if (xf86Verbose >= verb || xf86LogVerbose >= verb) + LogVWrite(verb, format, ap); + va_end(ap); +} + +/* Like xf86ErrorFVerb, but with an implied verbose level of 1 */ +void +xf86ErrorF(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + if (xf86Verbose >= 1 || xf86LogVerbose >= 1) + LogVWrite(1, format, ap); + va_end(ap); +} + + +void +xf86LogInit(void) +{ + char *lf = NULL; + +#define LOGSUFFIX ".log" +#define LOGOLDSUFFIX ".old" + + /* Get the log file name */ + if (xf86LogFileFrom == X_DEFAULT) { + /* Append the display number and ".log" */ + lf = malloc(strlen(xf86LogFile) + strlen("%s") + + strlen(LOGSUFFIX) + 1); + if (!lf) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(lf, "%s%%s" LOGSUFFIX, xf86LogFile); + xf86LogFile = lf; + } + + xf86LogFile = LogInit(xf86LogFile, LOGOLDSUFFIX); + xf86LogFileWasOpened = TRUE; + + xf86SetVerbosity(xf86Verbose); + xf86SetLogVerbosity(xf86LogVerbose); + +#undef LOGSUFFIX +#undef LOGOLDSUFFIX + + free(lf); +} + +void +xf86CloseLog(void) +{ + LogClose(); +} + + +/* + * Drivers can use these for using their own SymTabRecs. + */ + +const char * +xf86TokenToString(SymTabPtr table, int token) +{ + int i; + + for (i = 0; table[i].token >= 0 && table[i].token != token; i++) + ; + + if (table[i].token < 0) + return NULL; + else + return(table[i].name); +} + +int +xf86StringToToken(SymTabPtr table, const char *string) +{ + int i; + + if (string == NULL) + return -1; + + for (i = 0; table[i].token >= 0 && xf86NameCmp(string, table[i].name); i++) + ; + + return(table[i].token); +} + +/* + * helper to display the clocks found on a card + */ +void +xf86ShowClocks(ScrnInfoPtr scrp, MessageType from) +{ + int j; + + xf86DrvMsg(scrp->scrnIndex, from, "Pixel clocks available:"); + for (j=0; j < scrp->numClocks; j++) { + if ((j % 4) == 0) { + xf86ErrorF("\n"); + xf86DrvMsg(scrp->scrnIndex, from, "pixel clocks:"); + } + xf86ErrorF(" %7.3f", (double)scrp->clock[j] / 1000.0); + } + xf86ErrorF("\n"); +} + + +/* + * This prints out the driver identify message, including the names of + * the supported chipsets. + * + * XXX This makes assumptions about the line width, etc. Maybe we could + * use a more general "pretty print" function for messages. + */ +void +xf86PrintChipsets(const char *drvname, const char *drvmsg, SymTabPtr chips) +{ + int len, i; + + len = 6 + strlen(drvname) + 2 + strlen(drvmsg) + 2; + xf86Msg(X_INFO, "%s: %s:", drvname, drvmsg); + for (i = 0; chips[i].name != NULL; i++) { + if (i != 0) { + xf86ErrorF(","); + len++; + } + if (len + 2 + strlen(chips[i].name) < 78) { + xf86ErrorF(" "); + len++; + } else { + xf86ErrorF("\n\t"); + len = 8; + } + xf86ErrorF("%s", chips[i].name); + len += strlen(chips[i].name); + } + xf86ErrorF("\n"); +} + + +int +xf86MatchDevice(const char *drivername, GDevPtr **sectlist) +{ + GDevPtr gdp, *pgdp = NULL; + confScreenPtr screensecptr; + int i,j; + + if (sectlist) + *sectlist = NULL; + + if (xf86DoConfigure && xf86DoConfigurePass1) return 1; + + /* + * This is a very important function that matches the device sections + * as they show up in the config file with the drivers that the server + * loads at run time. + * + * ChipProbe can call + * int xf86MatchDevice(char * drivername, GDevPtr ** sectlist) + * with its driver name. The function allocates an array of GDevPtr and + * returns this via sectlist and returns the number of elements in + * this list as return value. 0 means none found, -1 means fatal error. + * + * It can figure out which of the Device sections to use for which card + * (using things like the Card statement, etc). For single headed servers + * there will of course be just one such Device section. + */ + i = 0; + + /* + * first we need to loop over all the Screens sections to get to all + * 'active' device sections + */ + for (j=0; xf86ConfigLayout.screens[j].screen != NULL; j++) { + screensecptr = xf86ConfigLayout.screens[j].screen; + if ((screensecptr->device->driver != NULL) + && (xf86NameCmp( screensecptr->device->driver,drivername) == 0) + && (! screensecptr->device->claimed)) { + /* + * we have a matching driver that wasn't claimed, yet + */ + pgdp = xnfrealloc(pgdp, (i + 2) * sizeof(GDevPtr)); + pgdp[i++] = screensecptr->device; + } + } + + /* Then handle the inactive devices */ + j = 0; + while (xf86ConfigLayout.inactives[j].identifier) { + gdp = &xf86ConfigLayout.inactives[j]; + if (gdp->driver && !gdp->claimed && + !xf86NameCmp(gdp->driver,drivername)) { + /* we have a matching driver that wasn't claimed yet */ + pgdp = xnfrealloc(pgdp, (i + 2) * sizeof(GDevPtr)); + pgdp[i++] = gdp; + } + j++; + } + + /* + * make the array NULL terminated and return its address + */ + if (i) + pgdp[i] = NULL; + + if (sectlist) + *sectlist = pgdp; + else + free(pgdp); + return i; +} + +static Bool +pciDeviceHasBars(struct pci_device *pci) +{ + int i; + + for (i = 0; i < 6; i++) + if (pci->regions[i].size) + return TRUE; + + if (pci->rom_size) + return TRUE; + + return FALSE; +} + +struct Inst { + struct pci_device * pci; + GDevPtr dev; + Bool foundHW; /* PCIid in list of supported chipsets */ + Bool claimed; /* BusID matches with a device section */ + int chip; + int screen; +}; + + +/** + * Find set of unclaimed devices matching a given vendor ID. + * + * Used by drivers to find as yet unclaimed devices matching the specified + * vendor ID. + * + * \param driverName Name of the driver. This is used to find Device + * sections in the config file. + * \param vendorID PCI vendor ID of associated devices. If zero, then + * the true vendor ID must be encoded in the \c PCIid + * fields of the \c PCIchipsets entries. + * \param chipsets Symbol table used to associate chipset names with + * PCI IDs. + * \param devList List of Device sections parsed from the config file. + * \param numDevs Number of entries in \c devList. + * \param drvp Pointer the driver's control structure. + * \param foundEntities Returned list of entity indicies associated with the + * driver. + * + * \returns + * The number of elements in returned in \c foundEntities on success or zero + * on failure. + * + * \todo + * This function does a bit more than short description says. Fill in some + * more of the details of its operation. + * + * \todo + * The \c driverName parameter is redundant. It is the same as + * \c DriverRec::driverName. In a future version of this function, remove + * that parameter. + */ +int +xf86MatchPciInstances(const char *driverName, int vendorID, + SymTabPtr chipsets, PciChipsets *PCIchipsets, + GDevPtr *devList, int numDevs, DriverPtr drvp, + int **foundEntities) +{ + int i,j; + struct pci_device * pPci; + struct pci_device_iterator *iter; + struct Inst *instances = NULL; + int numClaimedInstances = 0; + int allocatedInstances = 0; + int numFound = 0; + SymTabRec *c; + PciChipsets *id; + int *retEntities = NULL; + + *foundEntities = NULL; + + + /* Each PCI device will contribute at least one entry. Each device + * section can contribute at most one entry. The sum of the two is + * guaranteed to be larger than the maximum possible number of entries. + * Do this calculation and memory allocation once now to eliminate the + * need for realloc calls inside the loop. + */ + if (!(xf86DoConfigure && xf86DoConfigurePass1)) { + unsigned max_entries = numDevs; + + iter = pci_slot_match_iterator_create(NULL); + while ((pPci = pci_device_next(iter)) != NULL) { + max_entries++; + } + + pci_iterator_destroy(iter); + instances = xnfalloc(max_entries * sizeof(struct Inst)); + } + + iter = pci_slot_match_iterator_create(NULL); + while ((pPci = pci_device_next(iter)) != NULL) { + unsigned device_class = pPci->device_class; + Bool foundVendor = FALSE; + + + /* Convert the pre-PCI 2.0 device class for a VGA adapter to the + * 2.0 version of the same class. + */ + if ( device_class == 0x00000101 ) { + device_class = 0x00030000; + } + + + /* Find PCI devices that match the given vendor ID. The vendor ID is + * either specified explicitly as a parameter to the function or + * implicitly encoded in the high bits of id->PCIid. + * + * The first device with a matching vendor is recorded, even if the + * device ID doesn't match. This is done because the Device section + * in the xorg.conf file can over-ride the device ID. A matching PCI + * ID might not be found now, but after the device ID over-ride is + * applied there /might/ be a match. + */ + for (id = PCIchipsets; id->PCIid != -1; id++) { + const unsigned vendor_id = ((id->PCIid & 0xFFFF0000) >> 16) + | vendorID; + const unsigned device_id = (id->PCIid & 0x0000FFFF); + const unsigned match_class = 0x00030000 | id->PCIid; + + if ((vendor_id == pPci->vendor_id) + || ((vendorID == PCI_VENDOR_GENERIC) && (match_class == device_class))) { + if (!foundVendor && (instances != NULL)) { + ++allocatedInstances; + instances[allocatedInstances - 1].pci = pPci; + instances[allocatedInstances - 1].dev = NULL; + instances[allocatedInstances - 1].claimed = FALSE; + instances[allocatedInstances - 1].foundHW = FALSE; + instances[allocatedInstances - 1].screen = 0; + } + + foundVendor = TRUE; + + if ( (device_id == pPci->device_id) + || ((vendorID == PCI_VENDOR_GENERIC) + && (match_class == device_class)) ) { + if ( instances != NULL ) { + instances[allocatedInstances - 1].foundHW = TRUE; + instances[allocatedInstances - 1].chip = id->numChipset; + } + + + if ( xf86DoConfigure && xf86DoConfigurePass1 ) { + if (xf86CheckPciSlot(pPci)) { + GDevPtr pGDev = + xf86AddBusDeviceToConfigure(drvp->driverName, + BUS_PCI, pPci, -1); + if (pGDev) { + /* After configure pass 1, chipID and chipRev + * are treated as over-rides, so clobber them + * here. + */ + pGDev->chipID = -1; + pGDev->chipRev = -1; + } + + numFound++; + } + } + else { + numFound++; + } + + break; + } + } + } + } + + pci_iterator_destroy(iter); + + + /* In "probe only" or "configure" mode (signaled by instances being NULL), + * our work is done. Return the number of detected devices. + */ + if ( instances == NULL ) { + return numFound; + } + + + /* + * This may be debatable, but if no PCI devices with a matching vendor + * type is found, return zero now. It is probably not desirable to + * allow the config file to override this. + */ + if (allocatedInstances <= 0) { + free(instances); + return 0; + } + + + DebugF("%s instances found: %d\n", driverName, allocatedInstances); + + /* + * Check for devices that need duplicated instances. This is required + * when there is more than one screen per entity. + * + * XXX This currently doesn't work for cases where the BusID isn't + * specified explicitly in the config file. + */ + + for (j = 0; j < numDevs; j++) { + if (devList[j]->screen > 0 && devList[j]->busID + && *devList[j]->busID) { + for (i = 0; i < allocatedInstances; i++) { + pPci = instances[i].pci; + if (xf86ComparePciBusString(devList[j]->busID, + PCI_MAKE_BUS( pPci->domain, pPci->bus ), + pPci->dev, + pPci->func)) { + allocatedInstances++; + instances[allocatedInstances - 1] = instances[i]; + instances[allocatedInstances - 1].screen = + devList[j]->screen; + numFound++; + break; + } + } + } + } + + for (i = 0; i < allocatedInstances; i++) { + GDevPtr dev = NULL; + GDevPtr devBus = NULL; + + pPci = instances[i].pci; + for (j = 0; j < numDevs; j++) { + if (devList[j]->busID && *devList[j]->busID) { + if (xf86ComparePciBusString(devList[j]->busID, + PCI_MAKE_BUS( pPci->domain, pPci->bus ), + pPci->dev, + pPci->func) && + devList[j]->screen == instances[i].screen) { + + if (devBus) + xf86MsgVerb(X_WARNING,0, + "%s: More than one matching Device section for " + "instances\n\t(BusID: %s) found: %s\n", + driverName, devList[j]->busID, + devList[j]->identifier); + else + devBus = devList[j]; + } + } else { + /* + * if device section without BusID is found + * only assign to it to the primary device. + */ + if (xf86IsPrimaryPci(pPci)) { + xf86Msg(X_PROBED, "Assigning device section with no busID" + " to primary device\n"); + if (dev || devBus) + xf86MsgVerb(X_WARNING, 0, + "%s: More than one matching Device section " + "found: %s\n", driverName, devList[j]->identifier); + else + dev = devList[j]; + } + } + } + if (devBus) dev = devBus; /* busID preferred */ + if (!dev) { + if (xf86CheckPciSlot(pPci) && pciDeviceHasBars(pPci)) { + xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section " + "for instance (BusID PCI:%u@%u:%u:%u) found\n", + driverName, pPci->domain, pPci->bus, pPci->dev, + pPci->func); + } + } else { + numClaimedInstances++; + instances[i].claimed = TRUE; + instances[i].dev = dev; + } + } + DebugF("%s instances found: %d\n", driverName, numClaimedInstances); + /* + * Now check that a chipset or chipID override in the device section + * is valid. Chipset has precedence over chipID. + * If chipset is not valid ignore BusSlot completely. + */ + for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) { + MessageType from = X_PROBED; + + if (!instances[i].claimed) { + continue; + } + if (instances[i].dev->chipset) { + for (c = chipsets; c->token >= 0; c++) { + if (xf86NameCmp(c->name, instances[i].dev->chipset) == 0) + break; + } + if (c->token == -1) { + instances[i].claimed = FALSE; + numClaimedInstances--; + xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device " + "section \"%s\" isn't valid for this driver\n", + driverName, instances[i].dev->chipset, + instances[i].dev->identifier); + } else { + instances[i].chip = c->token; + + for (id = PCIchipsets; id->numChipset >= 0; id++) { + if (id->numChipset == instances[i].chip) + break; + } + if(id->numChipset >=0){ + xf86Msg(X_CONFIG,"Chipset override: %s\n", + instances[i].dev->chipset); + from = X_CONFIG; + } else { + instances[i].claimed = FALSE; + numClaimedInstances--; + xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device " + "section \"%s\" isn't a valid PCI chipset\n", + driverName, instances[i].dev->chipset, + instances[i].dev->identifier); + } + } + } else if (instances[i].dev->chipID > 0) { + for (id = PCIchipsets; id->numChipset >= 0; id++) { + if (id->PCIid == instances[i].dev->chipID) + break; + } + if (id->numChipset == -1) { + instances[i].claimed = FALSE; + numClaimedInstances--; + xf86MsgVerb(X_WARNING, 0, "%s: ChipID 0x%04X in Device " + "section \"%s\" isn't valid for this driver\n", + driverName, instances[i].dev->chipID, + instances[i].dev->identifier); + } else { + instances[i].chip = id->numChipset; + + xf86Msg( X_CONFIG,"ChipID override: 0x%04X\n", + instances[i].dev->chipID); + from = X_CONFIG; + } + } else if (!instances[i].foundHW) { + /* + * This means that there was no override and the PCI chipType + * doesn't match one that is supported + */ + instances[i].claimed = FALSE; + numClaimedInstances--; + } + if (instances[i].claimed == TRUE){ + for (c = chipsets; c->token >= 0; c++) { + if (c->token == instances[i].chip) + break; + } + xf86Msg(from,"Chipset %s found\n", + c->name); + } + } + + /* + * Of the claimed instances, check that another driver hasn't already + * claimed its slot. + */ + numFound = 0; + for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) { + + if (!instances[i].claimed) + continue; + pPci = instances[i].pci; + + + /* + * Allow the same entity to be used more than once for devices with + * multiple screens per entity. This assumes implicitly that there + * will be a screen == 0 instance. + * + * XXX Need to make sure that two different drivers don't claim + * the same screen > 0 instance. + */ + if (instances[i].screen == 0 && !xf86CheckPciSlot( pPci )) + continue; + + DebugF("%s: card at %d:%d:%d is claimed by a Device section\n", + driverName, pPci->bus, pPci->dev, pPci->func); + + /* Allocate an entry in the lists to be returned */ + numFound++; + retEntities = xnfrealloc(retEntities, numFound * sizeof(int)); + retEntities[numFound - 1] = xf86ClaimPciSlot( pPci, drvp, + instances[i].chip, + instances[i].dev, + instances[i].dev->active); + if (retEntities[numFound - 1] == -1 && instances[i].screen > 0) { + for (j = 0; j < xf86NumEntities; j++) { + EntityPtr pEnt = xf86Entities[j]; + if (pEnt->bus.type != BUS_PCI) + continue; + if (pEnt->bus.id.pci == pPci) { + retEntities[numFound - 1] = j; + xf86AddDevToEntity(j, instances[i].dev); + break; + } + } + } + } + free(instances); + if (numFound > 0) { + *foundEntities = retEntities; + } + + return numFound; +} + +/* + * xf86GetClocks -- get the dot-clocks via a BIG BAD hack ... + */ +void +xf86GetClocks(ScrnInfoPtr pScrn, int num, Bool (*ClockFunc)(ScrnInfoPtr, int), + void (*ProtectRegs)(ScrnInfoPtr, Bool), + void (*BlankScreen)(ScrnInfoPtr, Bool), IOADDRESS vertsyncreg, + int maskval, int knownclkindex, int knownclkvalue) +{ + register int status = vertsyncreg; + unsigned long i, cnt, rcnt, sync; + + /* First save registers that get written on */ + (*ClockFunc)(pScrn, CLK_REG_SAVE); + + if (num > MAXCLOCKS) + num = MAXCLOCKS; + + for (i = 0; i < num; i++) + { + if (ProtectRegs) + (*ProtectRegs)(pScrn, TRUE); + if (!(*ClockFunc)(pScrn, i)) + { + pScrn->clock[i] = -1; + continue; + } + if (ProtectRegs) + (*ProtectRegs)(pScrn, FALSE); + if (BlankScreen) + (*BlankScreen)(pScrn, FALSE); + + usleep(50000); /* let VCO stabilise */ + + cnt = 0; + sync = 200000; + + while ((inb(status) & maskval) == 0x00) + if (sync-- == 0) goto finish; + /* Something appears to be happening, so reset sync count */ + sync = 200000; + while ((inb(status) & maskval) == maskval) + if (sync-- == 0) goto finish; + /* Something appears to be happening, so reset sync count */ + sync = 200000; + while ((inb(status) & maskval) == 0x00) + if (sync-- == 0) goto finish; + + for (rcnt = 0; rcnt < 5; rcnt++) + { + while (!(inb(status) & maskval)) + cnt++; + while ((inb(status) & maskval)) + cnt++; + } + +finish: + pScrn->clock[i] = cnt ? cnt : -1; + if (BlankScreen) + (*BlankScreen)(pScrn, TRUE); + } + + for (i = 0; i < num; i++) + { + if (i != knownclkindex) + { + if (pScrn->clock[i] == -1) + { + pScrn->clock[i] = 0; + } + else + { + pScrn->clock[i] = (int)(0.5 + + (((float)knownclkvalue) * pScrn->clock[knownclkindex]) / + (pScrn->clock[i])); + /* Round to nearest 10KHz */ + pScrn->clock[i] += 5; + pScrn->clock[i] /= 10; + pScrn->clock[i] *= 10; + } + } + } + + pScrn->clock[knownclkindex] = knownclkvalue; + pScrn->numClocks = num; + + /* Restore registers that were written on */ + (*ClockFunc)(pScrn, CLK_REG_RESTORE); +} + +const char * +xf86GetVisualName(int visual) +{ + if (visual < 0 || visual > DirectColor) + return NULL; + + return xf86VisualNames[visual]; +} + + +int +xf86GetVerbosity(void) +{ + return max(xf86Verbose, xf86LogVerbose); +} + +Pix24Flags +xf86GetPix24(void) +{ + return xf86Info.pixmap24; +} + + +int +xf86GetDepth(void) +{ + return xf86Depth; +} + + +rgb +xf86GetWeight(void) +{ + return xf86Weight; +} + + +Gamma +xf86GetGamma(void) +{ + return xf86Gamma; +} + + +Bool +xf86GetFlipPixels(void) +{ + return xf86FlipPixels; +} + + +const char * +xf86GetServerName(void) +{ + return xf86ServerName; +} + + +Bool +xf86ServerIsExiting(void) +{ + return (dispatchException & DE_TERMINATE) == DE_TERMINATE; +} + + +Bool +xf86ServerIsResetting(void) +{ + return xf86Resetting; +} + + +Bool +xf86ServerIsInitialising(void) +{ + return xf86Initialising; +} + + +Bool +xf86ServerIsOnlyDetecting(void) +{ + return xf86DoConfigure; +} + + +Bool +xf86CaughtSignal(void) +{ + return xf86Info.caughtSignal; +} + + +Bool +xf86GetVidModeAllowNonLocal(void) +{ + return xf86Info.vidModeAllowNonLocal; +} + + +Bool +xf86GetVidModeEnabled(void) +{ + return xf86Info.vidModeEnabled; +} + +Bool +xf86GetModInDevAllowNonLocal(void) +{ + return xf86Info.miscModInDevAllowNonLocal; +} + + +Bool +xf86GetModInDevEnabled(void) +{ + return xf86Info.miscModInDevEnabled; +} + + +Bool +xf86GetAllowMouseOpenFail(void) +{ + return xf86Info.allowMouseOpenFail; +} + + +Bool +xf86IsPc98(void) +{ +#if SUPPORT_PC98 + return xf86Info.pc98; +#else + return FALSE; +#endif +} + +void +xf86DisableRandR(void) +{ + xf86Info.disableRandR = TRUE; + xf86Info.randRFrom = X_PROBED; +} + +CARD32 +xf86GetModuleVersion(pointer module) +{ + return (CARD32)LoaderGetModuleVersion(module); +} + +pointer +xf86LoadDrvSubModule(DriverPtr drv, const char *name) +{ + pointer ret; + int errmaj = 0, errmin = 0; + + ret = LoadSubModule(drv->module, name, NULL, NULL, NULL, NULL, + &errmaj, &errmin); + if (!ret) + LoaderErrorMsg(NULL, name, errmaj, errmin); + return ret; +} + +pointer +xf86LoadSubModule(ScrnInfoPtr pScrn, const char *name) +{ + pointer ret; + int errmaj = 0, errmin = 0; + + ret = LoadSubModule(pScrn->module, name, NULL, NULL, NULL, NULL, + &errmaj, &errmin); + if (!ret) + LoaderErrorMsg(pScrn->name, name, errmaj, errmin); + return ret; +} + +/* + * xf86LoadOneModule loads a single module. + */ +pointer +xf86LoadOneModule(char *name, pointer opt) +{ + int errmaj, errmin; + char *Name; + pointer mod; + + if (!name) + return NULL; + + /* Normalise the module name */ + Name = xf86NormalizeName(name); + + /* Skip empty names */ + if (Name == NULL) + return NULL; + if (*Name == '\0') { + free(Name); + return NULL; + } + + mod = LoadModule(Name, NULL, NULL, NULL, opt, NULL, &errmaj, &errmin); + if (!mod) + LoaderErrorMsg(NULL, Name, errmaj, errmin); + free(Name); + return mod; +} + +void +xf86UnloadSubModule(pointer mod) +{ + /* + * This is disabled for now. The loader isn't smart enough yet to undo + * relocations. + */ +#if 0 + UnloadSubModule(mod); +#endif +} + +Bool +xf86LoaderCheckSymbol(const char *name) +{ + return LoaderSymbol(name) != NULL; +} + +typedef enum { + OPTION_BACKING_STORE +} BSOpts; + +static const OptionInfoRec BSOptions[] = { + { OPTION_BACKING_STORE, "BackingStore", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +void +xf86SetBackingStore(ScreenPtr pScreen) +{ + Bool useBS = FALSE; + MessageType from = X_DEFAULT; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + OptionInfoPtr options; + + options = xnfalloc(sizeof(BSOptions)); + (void)memcpy(options, BSOptions, sizeof(BSOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); + + /* check for commandline option here */ + if (xf86bsEnableFlag) { + from = X_CMDLINE; + useBS = TRUE; + } else if (xf86bsDisableFlag) { + from = X_CMDLINE; + useBS = FALSE; + } else { + if (xf86GetOptValBool(options, OPTION_BACKING_STORE, &useBS)) + from = X_CONFIG; + } + free(options); + pScreen->backingStoreSupport = useBS ? Always : NotUseful; + if (serverGeneration == 1) + xf86DrvMsg(pScreen->myNum, from, "Backing store %s\n", + useBS ? "enabled" : "disabled"); +} + + +typedef enum { + OPTION_SILKEN_MOUSE +} SMOpts; + +static const OptionInfoRec SMOptions[] = { + { OPTION_SILKEN_MOUSE, "SilkenMouse", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +void +xf86SetSilkenMouse (ScreenPtr pScreen) +{ + Bool useSM = TRUE; + MessageType from = X_DEFAULT; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + OptionInfoPtr options; + + options = xnfalloc(sizeof(SMOptions)); + (void)memcpy(options, SMOptions, sizeof(SMOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); + + /* check for commandline option here */ + /* disable if screen shares resources */ + /* TODO VGA arb disable silken mouse */ + if (xf86silkenMouseDisableFlag) { + from = X_CMDLINE; + useSM = FALSE; + } else { + if (xf86GetOptValBool(options, OPTION_SILKEN_MOUSE, &useSM)) + from = X_CONFIG; + } + free(options); + /* + * XXX quick hack to report correctly for OSs that can't do SilkenMouse + * yet. Should handle this differently so that alternate async methods + * work correctly with this too. + */ + pScrn->silkenMouse = useSM && xf86Info.useSIGIO && xf86SIGIOSupported(); + if (serverGeneration == 1) + xf86DrvMsg(pScreen->myNum, from, "Silken mouse %s\n", + pScrn->silkenMouse ? "enabled" : "disabled"); +} + +/* Wrote this function for the PM2 Xv driver, preliminary. */ + +pointer +xf86FindXvOptions(int scrnIndex, int adaptor_index, char *port_name, + char **adaptor_name, pointer *adaptor_options) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + confXvAdaptorPtr adaptor; + int i; + + if (adaptor_index >= pScrn->confScreen->numxvadaptors) { + if (adaptor_name) *adaptor_name = NULL; + if (adaptor_options) *adaptor_options = NULL; + return NULL; + } + + adaptor = &pScrn->confScreen->xvadaptors[adaptor_index]; + if (adaptor_name) *adaptor_name = adaptor->identifier; + if (adaptor_options) *adaptor_options = adaptor->options; + + for (i = 0; i < adaptor->numports; i++) + if (!xf86NameCmp(adaptor->ports[i].identifier, port_name)) + return adaptor->ports[i].options; + + return NULL; +} + +/* Rather than duplicate loader's get OS function, just include it directly */ +#define LoaderGetOS xf86GetOS +#include "loader/os.c" + +/* new RAC */ +/* + * xf86ConfigPciEntityInactive() -- This function can be used + * to configure an inactive entity as well as to reconfigure an + * previously active entity inactive. If the entity has been + * assigned to a screen before it will be removed. If p_chip is + * non-NULL all static resources listed there will be registered. + */ +static void +xf86ConfigPciEntityInactive(EntityInfoPtr pEnt, PciChipsets *p_chip, + EntityProc init, EntityProc enter, + EntityProc leave, pointer private) +{ + ScrnInfoPtr pScrn; + + if ((pScrn = xf86FindScreenForEntity(pEnt->index))) + xf86RemoveEntityFromScreen(pScrn,pEnt->index); + + /* shared resources are only needed when entity is active: remove */ + xf86SetEntityFuncs(pEnt->index,init,enter,leave,private); +} + +static void +xf86ConfigFbEntityInactive(EntityInfoPtr pEnt, EntityProc init, + EntityProc enter, EntityProc leave, pointer private) +{ + ScrnInfoPtr pScrn; + + if ((pScrn = xf86FindScreenForEntity(pEnt->index))) + xf86RemoveEntityFromScreen(pScrn,pEnt->index); + xf86SetEntityFuncs(pEnt->index,init,enter,leave,private); +} + +ScrnInfoPtr +xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex, + PciChipsets *p_chip, void *dummy, EntityProc init, + EntityProc enter, EntityProc leave, pointer private) +{ + EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); + if (!pEnt) return pScrn; + + if (!(pEnt->location.type == BUS_PCI) + || !xf86GetPciInfoForEntity(entityIndex)) { + free(pEnt); + return pScrn; + } + if (!pEnt->active) { + xf86ConfigPciEntityInactive(pEnt, p_chip, init, enter, + leave, private); + free(pEnt); + return pScrn; + } + + if (!pScrn) + pScrn = xf86AllocateScreen(pEnt->driver,scrnFlag); + if (xf86IsEntitySharable(entityIndex)) { + xf86SetEntityShared(entityIndex); + } + xf86AddEntityToScreen(pScrn,entityIndex); + if (xf86IsEntityShared(entityIndex)) { + return pScrn; + } + free(pEnt); + + xf86SetEntityFuncs(entityIndex,init,enter,leave,private); + + return pScrn; +} + +ScrnInfoPtr +xf86ConfigFbEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex, + EntityProc init, EntityProc enter, EntityProc leave, + pointer private) +{ + EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); + if (!pEnt) return pScrn; + + if (!(pEnt->location.type == BUS_NONE)) { + free(pEnt); + return pScrn; + } + + if (!pEnt->active) { + xf86ConfigFbEntityInactive(pEnt, init, enter, leave, private); + free(pEnt); + return pScrn; + } + + if (!pScrn) + pScrn = xf86AllocateScreen(pEnt->driver,scrnFlag); + xf86AddEntityToScreen(pScrn,entityIndex); + + xf86SetEntityFuncs(entityIndex,init,enter,leave,private); + + return pScrn; +} + +/* + * + * OBSOLETE ! xf86ConfigActivePciEntity() is an obsolete function. + * It is likely to be removed. Don't use! + */ + +Bool +xf86ConfigActivePciEntity(ScrnInfoPtr pScrn, int entityIndex, + PciChipsets *p_chip, void *dummy, EntityProc init, + EntityProc enter, EntityProc leave, pointer private) +{ + EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); + if (!pEnt) return FALSE; + + if (!pEnt->active || !(pEnt->location.type == BUS_PCI)) { + free(pEnt); + return FALSE; + } + xf86AddEntityToScreen(pScrn,entityIndex); + + free(pEnt); + if (!xf86SetEntityFuncs(entityIndex,init,enter,leave,private)) + return FALSE; + + return TRUE; +} + +Bool +xf86IsScreenPrimary(int scrnIndex) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + int i; + + for (i=0 ; i < pScrn->numEntities; i++) { + if (xf86IsEntityPrimary(i)) + return TRUE; + } + return FALSE; +} + +int +xf86RegisterRootWindowProperty(int ScrnIndex, Atom property, Atom type, + int format, unsigned long len, pointer value ) +{ + RootWinPropPtr pNewProp = NULL, pRegProp; + int i; + Bool existing = FALSE; + + DebugF("xf86RegisterRootWindowProperty(%d, %ld, %ld, %d, %ld, %p)\n", + ScrnIndex, property, type, format, len, value); + + if (ScrnIndex<0 || ScrnIndex>=xf86NumScreens) { + return(BadMatch); + } + + if (xf86RegisteredPropertiesTable && + xf86RegisteredPropertiesTable[ScrnIndex]) { + for (pNewProp = xf86RegisteredPropertiesTable[ScrnIndex]; + pNewProp; pNewProp = pNewProp->next) { + if (strcmp(pNewProp->name, NameForAtom(property)) == 0) + break; + } + } + + if (!pNewProp) { + if ((pNewProp = (RootWinPropPtr)malloc(sizeof(RootWinProp))) == NULL) { + return(BadAlloc); + } + /* + * We will put this property at the end of the list so that + * the changes are made in the order they were requested. + */ + pNewProp->next = NULL; + } else { + if (pNewProp->name) + free(pNewProp->name); + existing = TRUE; + } + + pNewProp->name = xnfstrdup(NameForAtom(property)); + pNewProp->type = type; + pNewProp->format = format; + pNewProp->size = len; + pNewProp->data = value; + + DebugF("new property filled\n"); + + if (NULL==xf86RegisteredPropertiesTable) { + DebugF("creating xf86RegisteredPropertiesTable[] size %d\n", + xf86NumScreens); + if ( NULL==(xf86RegisteredPropertiesTable=(RootWinPropPtr*)xnfcalloc(sizeof(RootWinProp),xf86NumScreens) )) { + return(BadAlloc); + } + for (i=0; i<xf86NumScreens; i++) { + xf86RegisteredPropertiesTable[i] = NULL; + } + } + + DebugF("xf86RegisteredPropertiesTable %p\n", + (void *)xf86RegisteredPropertiesTable); + DebugF("xf86RegisteredPropertiesTable[%d] %p\n", + ScrnIndex, (void *)xf86RegisteredPropertiesTable[ScrnIndex]); + + if (!existing) { + if ( xf86RegisteredPropertiesTable[ScrnIndex] == NULL) { + xf86RegisteredPropertiesTable[ScrnIndex] = pNewProp; + } else { + pRegProp = xf86RegisteredPropertiesTable[ScrnIndex]; + while (pRegProp->next != NULL) { + DebugF("- next %p\n", (void *)pRegProp); + pRegProp = pRegProp->next; + } + pRegProp->next = pNewProp; + } + } + DebugF("xf86RegisterRootWindowProperty succeeded\n"); + return(Success); +} + +Bool +xf86IsUnblank(int mode) +{ + switch(mode) { + case SCREEN_SAVER_OFF: + case SCREEN_SAVER_FORCER: + return TRUE; + case SCREEN_SAVER_ON: + case SCREEN_SAVER_CYCLE: + return FALSE; + default: + xf86MsgVerb(X_WARNING, 0, "Unexpected save screen mode: %d\n", mode); + return TRUE; + } +} + +void +xf86MotionHistoryAllocate(LocalDevicePtr local) +{ + AllocateMotionHistory(local->dev); +} diff --git a/xorg-server/hw/xfree86/common/xf86Init.c b/xorg-server/hw/xfree86/common/xf86Init.c index 55d7a6209..d78d3d1db 100644 --- a/xorg-server/hw/xfree86/common/xf86Init.c +++ b/xorg-server/hw/xfree86/common/xf86Init.c @@ -1,1822 +1,1822 @@ -/* - * Loosely based on code bearing the following copyright: - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - */ -/* - * Copyright (c) 1992-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <stdlib.h> -#include <errno.h> - -#undef HAS_UTSNAME -#if !defined(WIN32) -#define HAS_UTSNAME 1 -#include <sys/utsname.h> -#endif - -#include <X11/X.h> -#include <X11/Xmd.h> -#include <X11/Xproto.h> -#include <X11/Xatom.h> -#include "input.h" -#include "servermd.h" -#include "windowstr.h" -#include "scrnintstr.h" -#include "site.h" -#include "mi.h" - -#include "compiler.h" - -#include "loaderProcs.h" -#ifdef XFreeXDGA -#include "dgaproc.h" -#endif - -#define XF86_OS_PRIVS -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86Config.h" -#include "xf86_OSlib.h" -#include "xorgVersion.h" -#include "xf86Build.h" -#include "mipointer.h" -#include <X11/extensions/XI.h> -#include <X11/extensions/XIproto.h> -#include "xf86DDC.h" -#include "xf86Xinput.h" -#include "xf86InPriv.h" -#include "picturestr.h" - -#include "xf86VGAarbiter.h" -#include "globals.h" - -#ifdef DPMSExtension -#include <X11/extensions/dpmsconst.h> -#include "dpmsproc.h" -#endif - -#include <pciaccess.h> -#include "Pci.h" -#include "xf86Bus.h" - -#include <hotplug.h> - -/* forward declarations */ -static Bool probe_devices_from_device_sections(DriverPtr drvp); -static Bool add_matching_devices_to_configure_list(DriverPtr drvp); - -#ifdef XF86PM -void (*xf86OSPMClose)(void) = NULL; -#endif -static Bool xorgHWOpenConsole = FALSE; - -/* Common pixmap formats */ - -static PixmapFormatRec formats[MAXFORMATS] = { - { 1, 1, BITMAP_SCANLINE_PAD }, - { 4, 8, BITMAP_SCANLINE_PAD }, - { 8, 8, BITMAP_SCANLINE_PAD }, - { 15, 16, BITMAP_SCANLINE_PAD }, - { 16, 16, BITMAP_SCANLINE_PAD }, - { 24, 32, BITMAP_SCANLINE_PAD }, - { 32, 32, BITMAP_SCANLINE_PAD }, -}; -static int numFormats = 7; -static Bool formatsDone = FALSE; - -#ifndef OSNAME -#define OSNAME " unknown" -#endif -#ifndef OSVENDOR -#define OSVENDOR "" -#endif -#ifndef PRE_RELEASE -#define PRE_RELEASE XORG_VERSION_SNAP -#endif - -static void -xf86PrintBanner(void) -{ -#if PRE_RELEASE - xf86ErrorFVerb(0, "\n" - "This is a pre-release version of the X server from " XVENDORNAME ".\n" - "It is not supported in any way.\n" - "Bugs may be filed in the bugzilla at http://bugs.freedesktop.org/.\n" - "Select the \"xorg\" product for bugs you find in this release.\n" - "Before reporting bugs in pre-release versions please check the\n" - "latest version in the X.Org Foundation git repository.\n" - "See http://wiki.x.org/wiki/GitPage for git access instructions.\n"); -#endif - xf86ErrorFVerb(0, "\nX.Org X Server %d.%d.%d", - XORG_VERSION_MAJOR, - XORG_VERSION_MINOR, - XORG_VERSION_PATCH); -#if XORG_VERSION_SNAP > 0 - xf86ErrorFVerb(0, ".%d", XORG_VERSION_SNAP); -#endif - -#if XORG_VERSION_SNAP >= 900 - /* When the minor number is 99, that signifies that the we are making - * a release candidate for a major version. (X.0.0) - * When the patch number is 99, that signifies that the we are making - * a release candidate for a minor version. (X.Y.0) - * When the patch number is < 99, then we are making a release - * candidate for the next point release. (X.Y.Z) - */ -#if XORG_VERSION_MINOR >= 99 - xf86ErrorFVerb(0, " (%d.0.0 RC %d)", XORG_VERSION_MAJOR+1, - XORG_VERSION_SNAP - 900); -#elif XORG_VERSION_PATCH == 99 - xf86ErrorFVerb(0, " (%d.%d.0 RC %d)", XORG_VERSION_MAJOR, - XORG_VERSION_MINOR + 1, XORG_VERSION_SNAP - 900); -#else - xf86ErrorFVerb(0, " (%d.%d.%d RC %d)", XORG_VERSION_MAJOR, - XORG_VERSION_MINOR, XORG_VERSION_PATCH + 1, - XORG_VERSION_SNAP - 900); -#endif -#endif - -#ifdef XORG_CUSTOM_VERSION - xf86ErrorFVerb(0, " (%s)", XORG_CUSTOM_VERSION); -#endif -#ifndef XORG_DATE -# define XORG_DATE "Unknown" -#endif - xf86ErrorFVerb(0, "\nRelease Date: %s\n", XORG_DATE); - xf86ErrorFVerb(0, "X Protocol Version %d, Revision %d\n", - X_PROTOCOL, X_PROTOCOL_REVISION); - xf86ErrorFVerb(0, "Build Operating System: %s %s\n", OSNAME, OSVENDOR); -#ifdef HAS_UTSNAME - { - struct utsname name; - - /* Linux & BSD state that 0 is success, SysV (including Solaris, HP-UX, - and Irix) and Single Unix Spec 3 just say that non-negative is success. - All agree that failure is represented by a negative number. - */ - if (uname(&name) >= 0) { - xf86ErrorFVerb(0, "Current Operating System: %s %s %s %s %s\n", - name.sysname, name.nodename, name.release, name.version, name.machine); -#ifdef linux - do { - char buf[80]; - int fd = open("/proc/cmdline", O_RDONLY); - if (fd != -1) { - xf86ErrorFVerb(0, "Kernel command line: "); - memset(buf, 0, 80); - while (read(fd, buf, 80) > 0) { - xf86ErrorFVerb(0, "%.80s", buf); - memset(buf, 0, 80); - } - close(fd); - } - } while (0); -#endif - } - } -#endif -#if defined(BUILD_DATE) && (BUILD_DATE > 19000000) - { - struct tm t; - char buf[100]; - - bzero(&t, sizeof(t)); - bzero(buf, sizeof(buf)); - t.tm_mday = BUILD_DATE % 100; - t.tm_mon = (BUILD_DATE / 100) % 100 - 1; - t.tm_year = BUILD_DATE / 10000 - 1900; -#if defined(BUILD_TIME) - t.tm_sec = BUILD_TIME % 100; - t.tm_min = (BUILD_TIME / 100) % 100; - t.tm_hour = (BUILD_TIME / 10000) % 100; - if (strftime(buf, sizeof(buf), "%d %B %Y %I:%M:%S%p", &t)) - xf86ErrorFVerb(0, "Build Date: %s\n", buf); -#else - if (strftime(buf, sizeof(buf), "%d %B %Y", &t)) - xf86ErrorFVerb(0, "Build Date: %s\n", buf); -#endif - } -#endif -#if defined(BUILDERSTRING) - xf86ErrorFVerb(0, "%s \n", BUILDERSTRING); -#endif - xf86ErrorFVerb(0, "Current version of pixman: %s\n", - pixman_version_string()); - xf86ErrorFVerb(0, "\tBefore reporting problems, check " - ""__VENDORDWEBSUPPORT__"\n" - "\tto make sure that you have the latest version.\n"); -} - -static void -xf86PrintMarkers(void) -{ - LogPrintMarkers(); -} - -static Bool -xf86CreateRootWindow(WindowPtr pWin) -{ - int ret = TRUE; - int err = Success; - ScreenPtr pScreen = pWin->drawable.pScreen; - RootWinPropPtr pProp; - CreateWindowProcPtr CreateWindow = (CreateWindowProcPtr) - dixLookupPrivate(&pScreen->devPrivates, xf86CreateRootWindowKey); - - DebugF("xf86CreateRootWindow(%p)\n", pWin); - - if ( pScreen->CreateWindow != xf86CreateRootWindow ) { - /* Can't find hook we are hung on */ - xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */, - "xf86CreateRootWindow %p called when not in pScreen->CreateWindow %p n", - (void *)xf86CreateRootWindow, - (void *)pScreen->CreateWindow ); - } - - /* Unhook this function ... */ - pScreen->CreateWindow = CreateWindow; - dixSetPrivate(&pScreen->devPrivates, xf86CreateRootWindowKey, NULL); - - /* ... and call the previous CreateWindow fuction, if any */ - if (NULL!=pScreen->CreateWindow) { - ret = (*pScreen->CreateWindow)(pWin); - } - - /* Now do our stuff */ - if (xf86RegisteredPropertiesTable != NULL) { - if (pWin->parent == NULL && xf86RegisteredPropertiesTable != NULL) { - for (pProp = xf86RegisteredPropertiesTable[pScreen->myNum]; - pProp != NULL && err==Success; - pProp = pProp->next ) - { - Atom prop; - - prop = MakeAtom(pProp->name, strlen(pProp->name), TRUE); - err = dixChangeWindowProperty(serverClient, pWin, - prop, pProp->type, - pProp->format, PropModeReplace, - pProp->size, pProp->data, - FALSE); - } - - /* Look at err */ - ret &= (err==Success); - - } else { - xf86Msg(X_ERROR, "xf86CreateRootWindow unexpectedly called with " - "non-root window %p (parent %p)\n", - (void *)pWin, (void *)pWin->parent); - ret = FALSE; - } - } - - DebugF("xf86CreateRootWindow() returns %d\n", ret); - return (ret); -} - - -static void -InstallSignalHandlers(void) -{ - /* - * Install signal handler for unexpected signals - */ - xf86Info.caughtSignal=FALSE; - if (!xf86Info.notrapSignals) { - OsRegisterSigWrapper(xf86SigWrapper); - } else { - signal(SIGSEGV, SIG_DFL); - signal(SIGILL, SIG_DFL); -#ifdef SIGEMT - signal(SIGEMT, SIG_DFL); -#endif - signal(SIGFPE, SIG_DFL); -#ifdef SIGBUS - signal(SIGBUS, SIG_DFL); -#endif -#ifdef SIGSYS - signal(SIGSYS, SIG_DFL); -#endif -#ifdef SIGXCPU - signal(SIGXCPU, SIG_DFL); -#endif -#ifdef SIGXFSZ - signal(SIGXFSZ, SIG_DFL); -#endif - } -} - - -#define END_OF_MATCHES(m) \ - (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0)) - -Bool -probe_devices_from_device_sections(DriverPtr drvp) -{ - int i, j; - struct pci_device * pPci; - Bool foundScreen = FALSE; - const struct pci_id_match * const devices = drvp->supported_devices; - GDevPtr *devList; - const unsigned numDevs = xf86MatchDevice(drvp->driverName, & devList); - - - for ( i = 0 ; i < numDevs ; i++ ) { - struct pci_device_iterator *iter; - unsigned device_id; - - - /* Find the pciVideoRec associated with this device section. - */ - iter = pci_id_match_iterator_create(NULL); - while ((pPci = pci_device_next(iter)) != NULL) { - if (devList[i]->busID && *devList[i]->busID) { - if (xf86ComparePciBusString(devList[i]->busID, - ((pPci->domain << 8) - | pPci->bus), - pPci->dev, - pPci->func)) { - break; - } - } - else if (xf86IsPrimaryPci(pPci)) { - break; - } - } - - pci_iterator_destroy(iter); - - if (pPci == NULL) { - continue; - } - - device_id = (devList[i]->chipID > 0) - ? devList[i]->chipID : pPci->device_id; - - - /* Once the pciVideoRec is found, determine if the device is supported - * by the driver. If it is, probe it! - */ - for ( j = 0 ; ! END_OF_MATCHES( devices[j] ) ; j++ ) { - if ( PCI_ID_COMPARE( devices[j].vendor_id, pPci->vendor_id ) - && PCI_ID_COMPARE( devices[j].device_id, device_id ) - && ((devices[j].device_class_mask & pPci->device_class) - == devices[j].device_class) ) { - int entry; - - /* Allow the same entity to be used more than once for - * devices with multiple screens per entity. This assumes - * implicitly that there will be a screen == 0 instance. - * - * FIXME Need to make sure that two different drivers don't - * FIXME claim the same screen > 0 instance. - */ - if ( (devList[i]->screen == 0) && !xf86CheckPciSlot( pPci ) ) - continue; - - DebugF("%s: card at %d:%d:%d is claimed by a Device section\n", - drvp->driverName, pPci->bus, pPci->dev, pPci->func); - - /* Allocate an entry in the lists to be returned */ - entry = xf86ClaimPciSlot(pPci, drvp, device_id, - devList[i], devList[i]->active); - - if ((entry == -1) && (devList[i]->screen > 0)) { - unsigned k; - - for ( k = 0; k < xf86NumEntities; k++ ) { - EntityPtr pEnt = xf86Entities[k]; - if (pEnt->bus.type != BUS_PCI) - continue; - - if (pEnt->bus.id.pci == pPci) { - entry = k; - xf86AddDevToEntity(k, devList[i]); - break; - } - } - } - - if (entry != -1) { - if ((*drvp->PciProbe)(drvp, entry, pPci, - devices[j].match_data)) { - foundScreen = TRUE; - } else - xf86UnclaimPciSlot(pPci); - } - - break; - } - } - } - xfree(devList); - - return foundScreen; -} - - -Bool -add_matching_devices_to_configure_list(DriverPtr drvp) -{ - const struct pci_id_match * const devices = drvp->supported_devices; - int j; - struct pci_device *pPci; - struct pci_device_iterator *iter; - int numFound = 0; - - - iter = pci_id_match_iterator_create(NULL); - while ((pPci = pci_device_next(iter)) != NULL) { - /* Determine if this device is supported by the driver. If it is, - * add it to the list of devices to configure. - */ - for (j = 0 ; ! END_OF_MATCHES(devices[j]) ; j++) { - if ( PCI_ID_COMPARE( devices[j].vendor_id, pPci->vendor_id ) - && PCI_ID_COMPARE( devices[j].device_id, pPci->device_id ) - && ((devices[j].device_class_mask & pPci->device_class) - == devices[j].device_class) ) { - if (xf86CheckPciSlot(pPci)) { - GDevPtr pGDev = xf86AddBusDeviceToConfigure( - drvp->driverName, BUS_PCI, pPci, -1); - if (pGDev != NULL) { - /* After configure pass 1, chipID and chipRev are - * treated as over-rides, so clobber them here. - */ - pGDev->chipID = -1; - pGDev->chipRev = -1; - } - - numFound++; - } - - break; - } - } - } - - pci_iterator_destroy(iter); - - - return (numFound != 0); -} - -/** - * Call the driver's correct probe function. - * - * If the driver implements the \c DriverRec::PciProbe entry-point and an - * appropriate PCI device (with matching Device section in the xorg.conf file) - * is found, it is called. If \c DriverRec::PciProbe or no devices can be - * successfully probed with it (e.g., only non-PCI devices are available), - * the driver's \c DriverRec::Probe function is called. - * - * \param drv Driver to probe - * - * \return - * If a device can be successfully probed by the driver, \c TRUE is - * returned. Otherwise, \c FALSE is returned. - */ -Bool -xf86CallDriverProbe( DriverPtr drv, Bool detect_only ) -{ - Bool foundScreen = FALSE; - - if ( drv->PciProbe != NULL ) { - if ( xf86DoConfigure && xf86DoConfigurePass1 ) { - assert( detect_only ); - foundScreen = add_matching_devices_to_configure_list( drv ); - } - else { - assert( ! detect_only ); - foundScreen = probe_devices_from_device_sections( drv ); - } - } - - if ( ! foundScreen && (drv->Probe != NULL) ) { - xf86Msg( X_WARNING, "Falling back to old probe method for %s\n", - drv->driverName ); - foundScreen = (*drv->Probe)( drv, (detect_only) ? PROBE_DETECT - : PROBE_DEFAULT ); - } - - return foundScreen; -} - -/* - * InitOutput -- - * Initialize screenInfo for all actually accessible framebuffers. - * That includes vt-manager setup, querying all possible devices and - * collecting the pixmap formats. - */ -void -InitOutput(ScreenInfo *pScreenInfo, int argc, char **argv) -{ - int i, j, k, scr_index; - char **modulelist; - pointer *optionlist; - screenLayoutPtr layout; - Pix24Flags screenpix24, pix24; - MessageType pix24From = X_DEFAULT; - Bool pix24Fail = FALSE; - Bool autoconfig = FALSE; - GDevPtr configured_device; - - xf86Initialising = TRUE; - - if (serverGeneration == 1) { - if ((xf86ServerName = strrchr(argv[0], '/')) != 0) - xf86ServerName++; - else - xf86ServerName = argv[0]; - - xf86PrintBanner(); - xf86PrintMarkers(); - if (xf86LogFile) { - time_t t; - const char *ct; - t = time(NULL); - ct = ctime(&t); - xf86MsgVerb(xf86LogFileFrom, 0, "Log file: \"%s\", Time: %s", - xf86LogFile, ct); - } - - /* Read and parse the config file */ - if (!xf86DoConfigure && !xf86DoShowOptions) { - switch (xf86HandleConfigFile(FALSE)) { - case CONFIG_OK: - break; - case CONFIG_PARSE_ERROR: - xf86Msg(X_ERROR, "Error parsing the config file\n"); - return; - case CONFIG_NOFILE: - autoconfig = TRUE; - break; - } - } - - InstallSignalHandlers(); - - /* Initialise the loader */ - LoaderInit(); - - /* Tell the loader the default module search path */ - LoaderSetPath(xf86ModulePath); - - if (xf86Info.ignoreABI) { - LoaderSetOptions(LDR_OPT_ABI_MISMATCH_NONFATAL); - } - - if (xf86DoShowOptions) - DoShowOptions(); - - /* Do a general bus probe. This will be a PCI probe for x86 platforms */ - xf86BusProbe(); - - if (xf86DoConfigure) - DoConfigure(); - - if (autoconfig) { - if (!xf86AutoConfig()) { - xf86Msg(X_ERROR, "Auto configuration failed\n"); - return; - } - } - -#ifdef XF86PM - xf86OSPMClose = xf86OSPMOpen(); -#endif - - /* Load all modules specified explicitly in the config file */ - if ((modulelist = xf86ModulelistFromConfig(&optionlist))) { - xf86LoadModules(modulelist, optionlist); - xfree(modulelist); - xfree(optionlist); - } - - /* Load all driver modules specified in the config file */ - /* If there aren't any specified in the config file, autoconfig them */ - /* FIXME: Does not handle multiple active screen sections, but I'm not - * sure if we really want to handle that case*/ - configured_device = xf86ConfigLayout.screens->screen->device; - if ((!configured_device) || (!configured_device->driver)) { - if (!autoConfigDevice(configured_device)) { - xf86Msg(X_ERROR, "Automatic driver configuration failed\n"); - return ; - } - } - if ((modulelist = xf86DriverlistFromConfig())) { - xf86LoadModules(modulelist, NULL); - xfree(modulelist); - } - - /* Load all input driver modules specified in the config file. */ - if ((modulelist = xf86InputDriverlistFromConfig())) { - xf86LoadModules(modulelist, NULL); - xfree(modulelist); - } - - /* - * It is expected that xf86AddDriver()/xf86AddInputDriver will be - * called for each driver as it is loaded. Those functions save the - * module pointers for drivers. - * XXX Nothing keeps track of them for other modules. - */ - /* XXX What do we do if not all of these could be loaded? */ - - /* - * At this point, xf86DriverList[] is all filled in with entries for - * each of the drivers to try and xf86NumDrivers has the number of - * drivers. If there are none, return now. - */ - - if (xf86NumDrivers == 0) { - xf86Msg(X_ERROR, "No drivers available.\n"); - return; - } - - /* - * Call each of the Identify functions and call the driverFunc to check - * if HW access is required. The Identify functions print out some - * identifying information, and anything else that might be - * needed at this early stage. - */ - - for (i = 0; i < xf86NumDrivers; i++) { - if (xf86DriverList[i]->Identify != NULL) - xf86DriverList[i]->Identify(0); - - if (!xorgHWAccess || !xorgHWOpenConsole) { - xorgHWFlags flags; - if(!xf86DriverList[i]->driverFunc - || !xf86DriverList[i]->driverFunc(NULL, - GET_REQUIRED_HW_INTERFACES, - &flags)) - flags = HW_IO; - - if(NEED_IO_ENABLED(flags)) - xorgHWAccess = TRUE; - if(!(flags & HW_SKIP_CONSOLE)) - xorgHWOpenConsole = TRUE; - } - } - - if (xorgHWOpenConsole) - xf86OpenConsole(); - else - xf86Info.dontVTSwitch = TRUE; - - /* Enable full I/O access */ - if (xorgHWAccess) - xorgHWAccess = xf86EnableIO(); - - /* - * Locate bus slot that had register IO enabled at server startup - */ - if (xorgHWAccess) { - xf86AccessInit(); - xf86FindPrimaryDevice(); - } - /* - * Now call each of the Probe functions. Each successful probe will - * result in an extra entry added to the xf86Screens[] list for each - * instance of the hardware found. - */ - - for (i = 0; i < xf86NumDrivers; i++) { - xorgHWFlags flags; - if (!xorgHWAccess) { - if (!xf86DriverList[i]->driverFunc - || !xf86DriverList[i]->driverFunc(NULL, - GET_REQUIRED_HW_INTERFACES, - &flags) - || NEED_IO_ENABLED(flags)) - continue; - } - - xf86CallDriverProbe( xf86DriverList[i], FALSE ); - } - - /* - * If nothing was detected, return now. - */ - - if (xf86NumScreens == 0) { - xf86Msg(X_ERROR, "No devices detected.\n"); - return; - } - - xf86VGAarbiterInit(); - - /* - * Match up the screens found by the probes against those specified - * in the config file. Remove the ones that won't be used. Sort - * them in the order specified. - */ - - /* - * What is the best way to do this? - * - * For now, go through the screens allocated by the probes, and - * look for screen config entry which refers to the same device - * section as picked out by the probe. - * - */ - - for (i = 0; i < xf86NumScreens; i++) { - for (layout = xf86ConfigLayout.screens; layout->screen != NULL; - layout++) { - Bool found = FALSE; - for (j = 0; j < xf86Screens[i]->numEntities; j++) { - - GDevPtr dev = - xf86GetDevFromEntity(xf86Screens[i]->entityList[j], - xf86Screens[i]->entityInstanceList[j]); - - if (dev == layout->screen->device) { - /* A match has been found */ - xf86Screens[i]->confScreen = layout->screen; - found = TRUE; - break; - } - } - if (found) break; - } - if (layout->screen == NULL) { - /* No match found */ - xf86Msg(X_ERROR, - "Screen %d deleted because of no matching config section.\n", i); - xf86DeleteScreen(i--, 0); - } - } - - /* - * If no screens left, return now. - */ - - if (xf86NumScreens == 0) { - xf86Msg(X_ERROR, - "Device(s) detected, but none match those in the config file.\n"); - return; - } - - xf86PostProbe(); - xf86EntityInit(); - - /* - * Sort the drivers to match the requested ording. Using a slow - * bubble sort. - */ - for (j = 0; j < xf86NumScreens - 1; j++) { - for (i = 0; i < xf86NumScreens - j - 1; i++) { - if (xf86Screens[i + 1]->confScreen->screennum < - xf86Screens[i]->confScreen->screennum) { - ScrnInfoPtr tmpScrn = xf86Screens[i + 1]; - xf86Screens[i + 1] = xf86Screens[i]; - xf86Screens[i] = tmpScrn; - } - } - } - /* Fix up the indexes */ - for (i = 0; i < xf86NumScreens; i++) { - xf86Screens[i]->scrnIndex = i; - } - - /* - * Call the driver's PreInit()'s to complete initialisation for the first - * generation. - */ - - for (i = 0; i < xf86NumScreens; i++) { - xf86VGAarbiterScrnInit(xf86Screens[i]); - xf86VGAarbiterLock(xf86Screens[i]); - if (xf86Screens[i]->PreInit && - xf86Screens[i]->PreInit(xf86Screens[i], 0)) - xf86Screens[i]->configured = TRUE; - xf86VGAarbiterUnlock(xf86Screens[i]); - } - for (i = 0; i < xf86NumScreens; i++) - if (!xf86Screens[i]->configured) - xf86DeleteScreen(i--, 0); - - /* - * If no screens left, return now. - */ - - if (xf86NumScreens == 0) { - xf86Msg(X_ERROR, - "Screen(s) found, but none have a usable configuration.\n"); - return; - } - - for (i = 0; i < xf86NumScreens; i++) { - if (xf86Screens[i]->name == NULL) { - xf86Screens[i]->name = xnfalloc(strlen("screen") + 10 + 1); - sprintf(xf86Screens[i]->name, "screen%d", i); - xf86MsgVerb(X_WARNING, 0, - "Screen driver %d has no name set, using `%s'.\n", - i, xf86Screens[i]->name); - } - } - - /* Remove (unload) drivers that are not required */ - for (i = 0; i < xf86NumDrivers; i++) - if (xf86DriverList[i] && xf86DriverList[i]->refCount <= 0) - xf86DeleteDriver(i); - - /* - * At this stage we know how many screens there are. - */ - - for (i = 0; i < xf86NumScreens; i++) - xf86InitViewport(xf86Screens[i]); - - /* - * Collect all pixmap formats and check for conflicts at the display - * level. Should we die here? Or just delete the offending screens? - */ - screenpix24 = Pix24DontCare; - for (i = 0; i < xf86NumScreens; i++) { - if (xf86Screens[i]->imageByteOrder != - xf86Screens[0]->imageByteOrder) - FatalError("Inconsistent display bitmapBitOrder. Exiting\n"); - if (xf86Screens[i]->bitmapScanlinePad != - xf86Screens[0]->bitmapScanlinePad) - FatalError("Inconsistent display bitmapScanlinePad. Exiting\n"); - if (xf86Screens[i]->bitmapScanlineUnit != - xf86Screens[0]->bitmapScanlineUnit) - FatalError("Inconsistent display bitmapScanlineUnit. Exiting\n"); - if (xf86Screens[i]->bitmapBitOrder != - xf86Screens[0]->bitmapBitOrder) - FatalError("Inconsistent display bitmapBitOrder. Exiting\n"); - - /* Determine the depth 24 pixmap format the screens would like */ - if (xf86Screens[i]->pixmap24 != Pix24DontCare) { - if (screenpix24 == Pix24DontCare) - screenpix24 = xf86Screens[i]->pixmap24; - else if (screenpix24 != xf86Screens[i]->pixmap24) - FatalError("Inconsistent depth 24 pixmap format. Exiting\n"); - } - } - /* check if screenpix24 is consistent with the config/cmdline */ - if (xf86Info.pixmap24 != Pix24DontCare) { - pix24 = xf86Info.pixmap24; - pix24From = xf86Info.pix24From; - if (screenpix24 != Pix24DontCare && screenpix24 != xf86Info.pixmap24) - pix24Fail = TRUE; - } else if (screenpix24 != Pix24DontCare) { - pix24 = screenpix24; - pix24From = X_PROBED; - } else - pix24 = Pix24Use32; - - if (pix24Fail) - FatalError("Screen(s) can't use the required depth 24 pixmap format" - " (%d). Exiting\n", PIX24TOBPP(pix24)); - - /* Initialise the depth 24 format */ - for (j = 0; j < numFormats && formats[j].depth != 24; j++) - ; - formats[j].bitsPerPixel = PIX24TOBPP(pix24); - - /* Collect additional formats */ - for (i = 0; i < xf86NumScreens; i++) { - for (j = 0; j < xf86Screens[i]->numFormats; j++) { - for (k = 0; ; k++) { - if (k >= numFormats) { - if (k >= MAXFORMATS) - FatalError("Too many pixmap formats! Exiting\n"); - formats[k] = xf86Screens[i]->formats[j]; - numFormats++; - break; - } - if (formats[k].depth == xf86Screens[i]->formats[j].depth) { - if ((formats[k].bitsPerPixel == - xf86Screens[i]->formats[j].bitsPerPixel) && - (formats[k].scanlinePad == - xf86Screens[i]->formats[j].scanlinePad)) - break; - FatalError("Inconsistent pixmap format for depth %d." - " Exiting\n", formats[k].depth); - } - } - } - } - formatsDone = TRUE; - - if (xf86Info.vtno >= 0 ) { -#define VT_ATOM_NAME "XFree86_VT" - Atom VTAtom=-1; - CARD32 *VT = NULL; - int ret; - - /* This memory needs to stay available until the screen has been - initialized, and we can create the property for real. - */ - if ( (VT = xalloc(sizeof(CARD32)))==NULL ) { - FatalError("Unable to make VT property - out of memory. Exiting...\n"); - } - *VT = xf86Info.vtno; - - VTAtom = MakeAtom(VT_ATOM_NAME, sizeof(VT_ATOM_NAME) - 1, TRUE); - - for (i = 0, ret = Success; i < xf86NumScreens && ret == Success; i++) { - ret = xf86RegisterRootWindowProperty(xf86Screens[i]->scrnIndex, - VTAtom, XA_INTEGER, 32, - 1, VT ); - if (ret != Success) - xf86DrvMsg(xf86Screens[i]->scrnIndex, X_WARNING, - "Failed to register VT property\n"); - } - } - - /* If a screen uses depth 24, show what the pixmap format is */ - for (i = 0; i < xf86NumScreens; i++) { - if (xf86Screens[i]->depth == 24) { - xf86Msg(pix24From, "Depth 24 pixmap format is %d bpp\n", - PIX24TOBPP(pix24)); - break; - } - } - } else { - /* - * serverGeneration != 1; some OSs have to do things here, too. - */ - if (xorgHWOpenConsole) - xf86OpenConsole(); - -#ifdef XF86PM - /* - should we reopen it here? We need to deal with an already opened - device. We could leave this to the OS layer. For now we simply - close it here - */ - if (xf86OSPMClose) - xf86OSPMClose(); - if ((xf86OSPMClose = xf86OSPMOpen()) != NULL) - xf86MsgVerb(X_INFO, 3, "APM registered successfully\n"); -#endif - - /* Make sure full I/O access is enabled */ - if (xorgHWAccess) - xf86EnableIO(); - } - - /* - * Use the previously collected parts to setup pScreenInfo - */ - - pScreenInfo->imageByteOrder = xf86Screens[0]->imageByteOrder; - pScreenInfo->bitmapScanlinePad = xf86Screens[0]->bitmapScanlinePad; - pScreenInfo->bitmapScanlineUnit = xf86Screens[0]->bitmapScanlineUnit; - pScreenInfo->bitmapBitOrder = xf86Screens[0]->bitmapBitOrder; - pScreenInfo->numPixmapFormats = numFormats; - for (i = 0; i < numFormats; i++) - pScreenInfo->formats[i] = formats[i]; - - /* Make sure the server's VT is active */ - - if (serverGeneration != 1) { - xf86Resetting = TRUE; - /* All screens are in the same state, so just check the first */ - if (!xf86Screens[0]->vtSema) { -#ifdef HAS_USL_VTS - ioctl(xf86Info.consoleFd, VT_RELDISP, VT_ACKACQ); -#endif - xf86AccessEnter(); - xf86EnterServerState(SETUP); - } - } -#ifdef SCO325 - else { - /* - * Under SCO we must ack that we got the console at startup, - * I think this is the safest way to assure it. - */ - static int once = 1; - if (once) { - once = 0; - if (ioctl(xf86Info.consoleFd, VT_RELDISP, VT_ACKACQ) < 0) - xf86Msg(X_WARNING, "VT_ACKACQ failed"); - } - } -#endif /* SCO325 */ - - for (i = 0; i < xf86NumScreens; i++) { - xf86VGAarbiterLock(xf86Screens[i]); - /* - * Almost everything uses these defaults, and many of those that - * don't, will wrap them. - */ - xf86Screens[i]->EnableDisableFBAccess = xf86EnableDisableFBAccess; -#ifdef XFreeXDGA - xf86Screens[i]->SetDGAMode = xf86SetDGAMode; -#endif - xf86Screens[i]->DPMSSet = NULL; - xf86Screens[i]->LoadPalette = NULL; - xf86Screens[i]->SetOverscan = NULL; - xf86Screens[i]->DriverFunc = NULL; - xf86Screens[i]->pScreen = NULL; - scr_index = AddScreen(xf86Screens[i]->ScreenInit, argc, argv); - xf86VGAarbiterUnlock(xf86Screens[i]); - if (scr_index == i) { - /* - * Hook in our ScrnInfoRec, and initialise some other pScreen - * fields. - */ - dixSetPrivate(&screenInfo.screens[scr_index]->devPrivates, - xf86ScreenKey, xf86Screens[i]); - xf86Screens[i]->pScreen = screenInfo.screens[scr_index]; - /* The driver should set this, but make sure it is set anyway */ - xf86Screens[i]->vtSema = TRUE; - } else { - /* This shouldn't normally happen */ - FatalError("AddScreen/ScreenInit failed for driver %d\n", i); - } - - DebugF("InitOutput - xf86Screens[%d]->pScreen = %p\n", - i, xf86Screens[i]->pScreen ); - DebugF("xf86Screens[%d]->pScreen->CreateWindow = %p\n", - i, xf86Screens[i]->pScreen->CreateWindow ); - - dixSetPrivate(&screenInfo.screens[scr_index]->devPrivates, - xf86CreateRootWindowKey, - xf86Screens[i]->pScreen->CreateWindow); - xf86Screens[i]->pScreen->CreateWindow = xf86CreateRootWindow; - - if (PictureGetSubpixelOrder (xf86Screens[i]->pScreen) == SubPixelUnknown) - { - xf86MonPtr DDC = (xf86MonPtr)(xf86Screens[i]->monitor->DDC); - PictureSetSubpixelOrder (xf86Screens[i]->pScreen, - DDC ? - (DDC->features.input_type ? - SubPixelHorizontalRGB : SubPixelNone) : - SubPixelUnknown); - } -#ifdef RANDR - if (!xf86Info.disableRandR) - xf86RandRInit (screenInfo.screens[scr_index]); - xf86Msg(xf86Info.randRFrom, "RandR %s\n", - xf86Info.disableRandR ? "disabled" : "enabled"); -#endif - } - - xf86PostScreenInit(); - - xf86InitOrigins(); - - xf86Resetting = FALSE; - xf86Initialising = FALSE; - - RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, xf86Wakeup, - NULL); -} - -/* - * InitInput -- - * Initialize all supported input devices. - */ - -void -InitInput(int argc, char **argv) -{ - IDevPtr* pDev; - DeviceIntPtr dev; - - xf86Info.vtRequestsPending = FALSE; - - mieqInit(); - - GetEventList(&xf86Events); - - /* Call the PreInit function for each input device instance. */ - for (pDev = xf86ConfigLayout.inputs; pDev && *pDev; pDev++) { - /* Replace obsolete keyboard driver with kbd */ - if (!xf86NameCmp((*pDev)->driver, "keyboard")) { - strcpy((*pDev)->driver, "kbd"); - } - - /* If one fails, the others will too */ - if (xf86NewInputDevice(*pDev, &dev, TRUE) == BadAlloc) - break; - } - - config_init(); -} - -void -CloseInput (void) -{ - config_fini(); -} - -/* - * OsVendorInit -- - * OS/Vendor-specific initialisations. Called from OsInit(), which - * is called by dix before establishing the well known sockets. - */ - -void -OsVendorInit(void) -{ - static Bool beenHere = FALSE; - -#ifdef SIGCHLD - signal(SIGCHLD, SIG_DFL); /* Need to wait for child processes */ -#endif - - if (!beenHere) { - umask(022); - xf86LogInit(); - } - - /* Set stderr to non-blocking. */ -#ifndef O_NONBLOCK -#if defined(FNDELAY) -#define O_NONBLOCK FNDELAY -#elif defined(O_NDELAY) -#define O_NONBLOCK O_NDELAY -#endif - -#ifdef O_NONBLOCK - if (!beenHere) { - if (geteuid() == 0 && getuid() != geteuid()) - { - int status; - - status = fcntl(fileno(stderr), F_GETFL, 0); - if (status != -1) { - fcntl(fileno(stderr), F_SETFL, status | O_NONBLOCK); - } - } - } -#endif -#endif - - beenHere = TRUE; -} - -/* - * ddxGiveUp -- - * Device dependent cleanup. Called by by dix before normal server death. - * For SYSV386 we must switch the terminal back to normal mode. No error- - * checking here, since there should be restored as much as possible. - */ - -void -ddxGiveUp(void) -{ - int i; - - xf86VGAarbiterFini(); - -#ifdef XF86PM - if (xf86OSPMClose) - xf86OSPMClose(); - xf86OSPMClose = NULL; -#endif - - for (i = 0; i < xf86NumScreens; i++) { - /* - * zero all access functions to - * trap calls when switched away. - */ - xf86Screens[i]->vtSema = FALSE; - } - -#ifdef XFreeXDGA - DGAShutdown(); -#endif - - if (xorgHWOpenConsole) - xf86CloseConsole(); - - xf86CloseLog(); - - /* If an unexpected signal was caught, dump a core for debugging */ - if (xf86Info.caughtSignal) - OsAbort(); -} - - - -/* - * AbortDDX -- - * DDX - specific abort routine. Called by AbortServer(). The attempt is - * made to restore all original setting of the displays. Also all devices - * are closed. - */ - -void -AbortDDX(void) -{ - int i; - - /* - * try to restore the original video state - */ -#ifdef DPMSExtension /* Turn screens back on */ - if (DPMSPowerLevel != DPMSModeOn) - DPMSSet(serverClient, DPMSModeOn); -#endif - if (xf86Screens) { - if (xf86Screens[0]->vtSema) - xf86EnterServerState(SETUP); - for (i = 0; i < xf86NumScreens; i++) - if (xf86Screens[i]->vtSema) { - /* - * if we are aborting before ScreenInit() has finished - * we might not have been wrapped yet. Therefore enable - * screen explicitely. - */ - xf86VGAarbiterLock(xf86Screens[i]); - (xf86Screens[i]->LeaveVT)(i, 0); - xf86VGAarbiterUnlock(xf86Screens[i]); - } - } - - xf86AccessLeave(); - - /* - * This is needed for an abnormal server exit, since the normal exit stuff - * MUST also be performed (i.e. the vt must be left in a defined state) - */ - ddxGiveUp(); -} - -void -OsVendorFatalError(void) -{ -#ifdef VENDORSUPPORT - ErrorF("\nPlease refer to your Operating System Vendor support pages\n" - "at %s for support on this crash.\n",VENDORSUPPORT); -#else - ErrorF("\nPlease consult the "XVENDORNAME" support \n" - "\t at "__VENDORDWEBSUPPORT__"\n for help. \n"); -#endif - if (xf86LogFile && xf86LogFileWasOpened) - ErrorF("Please also check the log file at \"%s\" for additional " - "information.\n", xf86LogFile); - ErrorF("\n"); -} - -int -xf86SetVerbosity(int verb) -{ - int save = xf86Verbose; - - xf86Verbose = verb; - LogSetParameter(XLOG_VERBOSITY, verb); - return save; -} - -int -xf86SetLogVerbosity(int verb) -{ - int save = xf86LogVerbose; - - xf86LogVerbose = verb; - LogSetParameter(XLOG_FILE_VERBOSITY, verb); - return save; -} - -static void -xf86PrintDefaultModulePath(void) -{ - ErrorF("%s\n", DEFAULT_MODULE_PATH); -} - -static void -xf86PrintDefaultLibraryPath(void) -{ - ErrorF("%s\n", DEFAULT_LIBRARY_PATH); -} - -/* - * ddxProcessArgument -- - * Process device-dependent command line args. Returns 0 if argument is - * not device dependent, otherwise Count of number of elements of argv - * that are part of a device dependent commandline option. - * - */ - -/* ARGSUSED */ -int -ddxProcessArgument(int argc, char **argv, int i) -{ - /* - * Note: can't use xalloc/xfree here because OsInit() hasn't been called - * yet. Use malloc/free instead. - */ - -#define CHECK_FOR_REQUIRED_ARGUMENT() \ - if (((i + 1) >= argc) || (!argv[i + 1])) { \ - ErrorF("Required argument to %s not specified\n", argv[i]); \ - UseMsg(); \ - FatalError("Required argument to %s not specified\n", argv[i]); \ - } - - /* First the options that are only allowed for root */ - if (!strcmp(argv[i], "-modulepath") || !strcmp(argv[i], "-logfile")) { - if ( (geteuid() == 0) && (getuid() != 0) ) { - FatalError("The '%s' option can only be used by root.\n", argv[i]); - } - else if (!strcmp(argv[i], "-modulepath")) - { - char *mp; - CHECK_FOR_REQUIRED_ARGUMENT(); - mp = malloc(strlen(argv[i + 1]) + 1); - if (!mp) - FatalError("Can't allocate memory for ModulePath\n"); - strcpy(mp, argv[i + 1]); - xf86ModulePath = mp; - xf86ModPathFrom = X_CMDLINE; - return 2; - } - else if (!strcmp(argv[i], "-logfile")) - { - char *lf; - CHECK_FOR_REQUIRED_ARGUMENT(); - lf = malloc(strlen(argv[i + 1]) + 1); - if (!lf) - FatalError("Can't allocate memory for LogFile\n"); - strcpy(lf, argv[i + 1]); - xf86LogFile = lf; - xf86LogFileFrom = X_CMDLINE; - return 2; - } - } - if (!strcmp(argv[i], "-config") || !strcmp(argv[i], "-xf86config")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) { - FatalError("\nInvalid argument for %s\n" - "\tFor non-root users, the file specified with %s must be\n" - "\ta relative path and must not contain any \"..\" elements.\n" - "\tUsing default "__XCONFIGFILE__" search path.\n\n", - argv[i], argv[i]); - } - xf86ConfigFile = argv[i + 1]; - return 2; - } - if (!strcmp(argv[i], "-configdir")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) { - FatalError("\nInvalid argument for %s\n" - "\tFor non-root users, the file specified with %s must be\n" - "\ta relative path and must not contain any \"..\" elements.\n" - "\tUsing default "__XCONFIGDIR__" search path.\n\n", - argv[i], argv[i]); - } - xf86ConfigDir = argv[i + 1]; - return 2; - } - if (!strcmp(argv[i],"-flipPixels")) - { - xf86FlipPixels = TRUE; - return 1; - } -#ifdef XF86VIDMODE - if (!strcmp(argv[i],"-disableVidMode")) - { - xf86VidModeDisabled = TRUE; - return 1; - } - if (!strcmp(argv[i],"-allowNonLocalXvidtune")) - { - xf86VidModeAllowNonLocal = TRUE; - return 1; - } -#endif - if (!strcmp(argv[i],"-allowMouseOpenFail")) - { - xf86AllowMouseOpenFail = TRUE; - return 1; - } - if (!strcmp(argv[i],"-ignoreABI")) - { - LoaderSetOptions(LDR_OPT_ABI_MISMATCH_NONFATAL); - return 1; - } - if (!strcmp(argv[i],"-verbose")) - { - if (++i < argc && argv[i]) - { - char *end; - long val; - val = strtol(argv[i], &end, 0); - if (*end == '\0') - { - xf86SetVerbosity(val); - return 2; - } - } - xf86SetVerbosity(++xf86Verbose); - return 1; - } - if (!strcmp(argv[i],"-logverbose")) - { - if (++i < argc && argv[i]) - { - char *end; - long val; - val = strtol(argv[i], &end, 0); - if (*end == '\0') - { - xf86SetLogVerbosity(val); - return 2; - } - } - xf86SetLogVerbosity(++xf86LogVerbose); - return 1; - } - if (!strcmp(argv[i],"-quiet")) - { - xf86SetVerbosity(-1); - return 1; - } - if (!strcmp(argv[i],"-showconfig") || !strcmp(argv[i],"-version")) - { - xf86PrintBanner(); - exit(0); - } - if (!strcmp(argv[i],"-showDefaultModulePath")) - { - xf86PrintDefaultModulePath(); - exit(0); - } - if (!strcmp(argv[i],"-showDefaultLibPath")) - { - xf86PrintDefaultLibraryPath(); - exit(0); - } - /* Notice the -fp flag, but allow it to pass to the dix layer */ - if (!strcmp(argv[i], "-fp")) - { - xf86fpFlag = TRUE; - return 0; - } - /* Notice the -bs flag, but allow it to pass to the dix layer */ - if (!strcmp(argv[i], "-bs")) - { - xf86bsDisableFlag = TRUE; - return 0; - } - /* Notice the +bs flag, but allow it to pass to the dix layer */ - if (!strcmp(argv[i], "+bs")) - { - xf86bsEnableFlag = TRUE; - return 0; - } - /* Notice the -s flag, but allow it to pass to the dix layer */ - if (!strcmp(argv[i], "-s")) - { - xf86sFlag = TRUE; - return 0; - } - if (!strcmp(argv[i], "-pixmap24")) - { - xf86Pix24 = Pix24Use24; - return 1; - } - if (!strcmp(argv[i], "-pixmap32")) - { - xf86Pix24 = Pix24Use32; - return 1; - } - if (!strcmp(argv[i], "-fbbpp")) - { - int bpp; - CHECK_FOR_REQUIRED_ARGUMENT(); - if (sscanf(argv[++i], "%d", &bpp) == 1) - { - xf86FbBpp = bpp; - return 2; - } - else - { - ErrorF("Invalid fbbpp\n"); - return 0; - } - } - if (!strcmp(argv[i], "-depth")) - { - int depth; - CHECK_FOR_REQUIRED_ARGUMENT(); - if (sscanf(argv[++i], "%d", &depth) == 1) - { - xf86Depth = depth; - return 2; - } - else - { - ErrorF("Invalid depth\n"); - return 0; - } - } - if (!strcmp(argv[i], "-weight")) - { - int red, green, blue; - CHECK_FOR_REQUIRED_ARGUMENT(); - if (sscanf(argv[++i], "%1d%1d%1d", &red, &green, &blue) == 3) - { - xf86Weight.red = red; - xf86Weight.green = green; - xf86Weight.blue = blue; - return 2; - } - else - { - ErrorF("Invalid weighting\n"); - return 0; - } - } - if (!strcmp(argv[i], "-gamma") || !strcmp(argv[i], "-rgamma") || - !strcmp(argv[i], "-ggamma") || !strcmp(argv[i], "-bgamma")) - { - double gamma; - CHECK_FOR_REQUIRED_ARGUMENT(); - if (sscanf(argv[++i], "%lf", &gamma) == 1) { - if (gamma < GAMMA_MIN || gamma > GAMMA_MAX) { - ErrorF("gamma out of range, only %.2f <= gamma_value <= %.1f" - " is valid\n", GAMMA_MIN, GAMMA_MAX); - return 0; - } - if (!strcmp(argv[i-1], "-gamma")) - xf86Gamma.red = xf86Gamma.green = xf86Gamma.blue = gamma; - else if (!strcmp(argv[i-1], "-rgamma")) xf86Gamma.red = gamma; - else if (!strcmp(argv[i-1], "-ggamma")) xf86Gamma.green = gamma; - else if (!strcmp(argv[i-1], "-bgamma")) xf86Gamma.blue = gamma; - return 2; - } - } - if (!strcmp(argv[i], "-layout")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - xf86LayoutName = argv[++i]; - return 2; - } - if (!strcmp(argv[i], "-screen")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - xf86ScreenName = argv[++i]; - return 2; - } - if (!strcmp(argv[i], "-pointer")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - xf86PointerName = argv[++i]; - return 2; - } - if (!strcmp(argv[i], "-keyboard")) - { - CHECK_FOR_REQUIRED_ARGUMENT(); - xf86KeyboardName = argv[++i]; - return 2; - } - if (!strcmp(argv[i], "-nosilk")) - { - xf86silkenMouseDisableFlag = TRUE; - return 1; - } -#ifdef HAVE_ACPI - if (!strcmp(argv[i], "-noacpi")) - { - xf86acpiDisableFlag = TRUE; - return 1; - } -#endif - if (!strcmp(argv[i], "-configure")) - { - if (getuid() != 0 && geteuid() == 0) { - ErrorF("The '-configure' option can only be used by root.\n"); - exit(1); - } - xf86DoConfigure = TRUE; - xf86AllowMouseOpenFail = TRUE; - return 1; - } - if (!strcmp(argv[i], "-showopts")) - { - if (getuid() != 0 && geteuid() == 0) { - ErrorF("The '-showopts' option can only be used by root.\n"); - exit(1); - } - xf86DoShowOptions = TRUE; - return 1; - } - if (!strcmp(argv[i], "-isolateDevice")) - { - int bus, device, func; - CHECK_FOR_REQUIRED_ARGUMENT(); - if (strncmp(argv[++i], "PCI:", 4)) { - FatalError("Bus types other than PCI not yet isolable\n"); - } - if (sscanf(argv[i], "PCI:%d:%d:%d", &bus, &device, &func) == 3) { - xf86IsolateDevice.domain = PCI_DOM_FROM_BUS(bus); - xf86IsolateDevice.bus = PCI_BUS_NO_DOMAIN(bus); - xf86IsolateDevice.dev = device; - xf86IsolateDevice.func = func; - return 2; - } else { - FatalError("Invalid isolated device specification\n"); - } - } - /* Notice cmdline xkbdir, but pass to dix as well */ - if (!strcmp(argv[i], "-xkbdir")) - { - xf86xkbdirFlag = TRUE; - return 0; - } - - /* OS-specific processing */ - return xf86ProcessArgument(argc, argv, i); -} - -/* - * ddxUseMsg -- - * Print out correct use of device dependent commandline options. - * Maybe the user now knows what really to do ... - */ - -void -ddxUseMsg(void) -{ - ErrorF("\n"); - ErrorF("\n"); - ErrorF("Device Dependent Usage\n"); - if (getuid() == 0 || geteuid() != 0) - { - ErrorF("-modulepath paths specify the module search path\n"); - ErrorF("-logfile file specify a log file name\n"); - ErrorF("-configure probe for devices and write an "__XCONFIGFILE__"\n"); - ErrorF("-showopts print available options for all installed drivers\n"); - } - ErrorF("-config file specify a configuration file, relative to the\n"); - ErrorF(" "__XCONFIGFILE__" search path, only root can use absolute\n"); - ErrorF("-configdir dir specify a configuration directory, relative to the\n"); - ErrorF(" "__XCONFIGDIR__" search path, only root can use absolute\n"); - ErrorF("-verbose [n] verbose startup messages\n"); - ErrorF("-logverbose [n] verbose log messages\n"); - ErrorF("-quiet minimal startup messages\n"); - ErrorF("-pixmap24 use 24bpp pixmaps for depth 24\n"); - ErrorF("-pixmap32 use 32bpp pixmaps for depth 24\n"); - ErrorF("-fbbpp n set bpp for the framebuffer. Default: 8\n"); - ErrorF("-depth n set colour depth. Default: 8\n"); - ErrorF("-gamma f set gamma value (0.1 < f < 10.0) Default: 1.0\n"); - ErrorF("-rgamma f set gamma value for red phase\n"); - ErrorF("-ggamma f set gamma value for green phase\n"); - ErrorF("-bgamma f set gamma value for blue phase\n"); - ErrorF("-weight nnn set RGB weighting at 16 bpp. Default: 565\n"); - ErrorF("-layout name specify the ServerLayout section name\n"); - ErrorF("-screen name specify the Screen section name\n"); - ErrorF("-keyboard name specify the core keyboard InputDevice name\n"); - ErrorF("-pointer name specify the core pointer InputDevice name\n"); - ErrorF("-nosilk disable Silken Mouse\n"); - ErrorF("-flipPixels swap default black/white Pixel values\n"); -#ifdef XF86VIDMODE - ErrorF("-disableVidMode disable mode adjustments with xvidtune\n"); - ErrorF("-allowNonLocalXvidtune allow xvidtune to be run as a non-local client\n"); -#endif - ErrorF("-allowMouseOpenFail start server even if the mouse can't be initialized\n"); - ErrorF("-ignoreABI make module ABI mismatches non-fatal\n"); - ErrorF("-isolateDevice bus_id restrict device resets to bus_id (PCI only)\n"); - ErrorF("-version show the server version\n"); - ErrorF("-showDefaultModulePath show the server default module path\n"); - ErrorF("-showDefaultLibPath show the server default library path\n"); - /* OS-specific usage */ - xf86UseMsg(); - ErrorF("\n"); -} - - -/* - * xf86LoadModules iterates over a list that is being passed in. - */ -Bool -xf86LoadModules(char **list, pointer *optlist) -{ - int errmaj, errmin; - pointer opt; - int i; - char *name; - Bool failed = FALSE; - - if (!list) - return TRUE; - - for (i = 0; list[i] != NULL; i++) { - - /* Normalise the module name */ - name = xf86NormalizeName(list[i]); - - /* Skip empty names */ - if (name == NULL || *name == '\0') - continue; - - /* Replace obsolete keyboard driver with kbd */ - if (!xf86NameCmp(name, "keyboard")) { - strcpy(name, "kbd"); - } - - if (optlist) - opt = optlist[i]; - else - opt = NULL; - - if (!LoadModule(name, NULL, NULL, NULL, opt, NULL, &errmaj, &errmin)) { - LoaderErrorMsg(NULL, name, errmaj, errmin); - failed = TRUE; - } - xfree(name); - } - return !failed; -} - -/* Pixmap format stuff */ - -PixmapFormatPtr -xf86GetPixFormat(ScrnInfoPtr pScrn, int depth) -{ - int i; - static PixmapFormatRec format; /* XXX not reentrant */ - - /* - * When the formats[] list initialisation isn't complete, check the - * depth 24 pixmap config/cmdline options and screen-specified formats. - */ - - if (!formatsDone) { - if (depth == 24) { - Pix24Flags pix24 = Pix24DontCare; - - format.depth = 24; - format.scanlinePad = BITMAP_SCANLINE_PAD; - if (xf86Info.pixmap24 != Pix24DontCare) - pix24 = xf86Info.pixmap24; - else if (pScrn->pixmap24 != Pix24DontCare) - pix24 = pScrn->pixmap24; - if (pix24 == Pix24Use24) - format.bitsPerPixel = 24; - else - format.bitsPerPixel = 32; - return &format; - } - } - - for (i = 0; i < numFormats; i++) - if (formats[i].depth == depth) - break; - if (i != numFormats) - return &formats[i]; - else if (!formatsDone) { - /* Check for screen-specified formats */ - for (i = 0; i < pScrn->numFormats; i++) - if (pScrn->formats[i].depth == depth) - break; - if (i != pScrn->numFormats) - return &pScrn->formats[i]; - } - return NULL; -} - -int -xf86GetBppFromDepth(ScrnInfoPtr pScrn, int depth) -{ - PixmapFormatPtr format; - - - format = xf86GetPixFormat(pScrn, depth); - if (format) - return format->bitsPerPixel; - else - return 0; -} +/* + * Loosely based on code bearing the following copyright: + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + */ +/* + * Copyright (c) 1992-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <stdlib.h> +#include <errno.h> + +#undef HAS_UTSNAME +#if !defined(WIN32) +#define HAS_UTSNAME 1 +#include <sys/utsname.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include <X11/Xproto.h> +#include <X11/Xatom.h> +#include "input.h" +#include "servermd.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "site.h" +#include "mi.h" + +#include "compiler.h" + +#include "loaderProcs.h" +#ifdef XFreeXDGA +#include "dgaproc.h" +#endif + +#define XF86_OS_PRIVS +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86Config.h" +#include "xf86_OSlib.h" +#include "xorgVersion.h" +#include "xf86Build.h" +#include "mipointer.h" +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "xf86DDC.h" +#include "xf86Xinput.h" +#include "xf86InPriv.h" +#include "picturestr.h" + +#include "xf86VGAarbiter.h" +#include "globals.h" + +#ifdef DPMSExtension +#include <X11/extensions/dpmsconst.h> +#include "dpmsproc.h" +#endif + +#include <pciaccess.h> +#include "Pci.h" +#include "xf86Bus.h" + +#include <hotplug.h> + +/* forward declarations */ +static Bool probe_devices_from_device_sections(DriverPtr drvp); +static Bool add_matching_devices_to_configure_list(DriverPtr drvp); + +#ifdef XF86PM +void (*xf86OSPMClose)(void) = NULL; +#endif +static Bool xorgHWOpenConsole = FALSE; + +/* Common pixmap formats */ + +static PixmapFormatRec formats[MAXFORMATS] = { + { 1, 1, BITMAP_SCANLINE_PAD }, + { 4, 8, BITMAP_SCANLINE_PAD }, + { 8, 8, BITMAP_SCANLINE_PAD }, + { 15, 16, BITMAP_SCANLINE_PAD }, + { 16, 16, BITMAP_SCANLINE_PAD }, + { 24, 32, BITMAP_SCANLINE_PAD }, + { 32, 32, BITMAP_SCANLINE_PAD }, +}; +static int numFormats = 7; +static Bool formatsDone = FALSE; + +#ifndef OSNAME +#define OSNAME " unknown" +#endif +#ifndef OSVENDOR +#define OSVENDOR "" +#endif +#ifndef PRE_RELEASE +#define PRE_RELEASE XORG_VERSION_SNAP +#endif + +static void +xf86PrintBanner(void) +{ +#if PRE_RELEASE + xf86ErrorFVerb(0, "\n" + "This is a pre-release version of the X server from " XVENDORNAME ".\n" + "It is not supported in any way.\n" + "Bugs may be filed in the bugzilla at http://bugs.freedesktop.org/.\n" + "Select the \"xorg\" product for bugs you find in this release.\n" + "Before reporting bugs in pre-release versions please check the\n" + "latest version in the X.Org Foundation git repository.\n" + "See http://wiki.x.org/wiki/GitPage for git access instructions.\n"); +#endif + xf86ErrorFVerb(0, "\nX.Org X Server %d.%d.%d", + XORG_VERSION_MAJOR, + XORG_VERSION_MINOR, + XORG_VERSION_PATCH); +#if XORG_VERSION_SNAP > 0 + xf86ErrorFVerb(0, ".%d", XORG_VERSION_SNAP); +#endif + +#if XORG_VERSION_SNAP >= 900 + /* When the minor number is 99, that signifies that the we are making + * a release candidate for a major version. (X.0.0) + * When the patch number is 99, that signifies that the we are making + * a release candidate for a minor version. (X.Y.0) + * When the patch number is < 99, then we are making a release + * candidate for the next point release. (X.Y.Z) + */ +#if XORG_VERSION_MINOR >= 99 + xf86ErrorFVerb(0, " (%d.0.0 RC %d)", XORG_VERSION_MAJOR+1, + XORG_VERSION_SNAP - 900); +#elif XORG_VERSION_PATCH == 99 + xf86ErrorFVerb(0, " (%d.%d.0 RC %d)", XORG_VERSION_MAJOR, + XORG_VERSION_MINOR + 1, XORG_VERSION_SNAP - 900); +#else + xf86ErrorFVerb(0, " (%d.%d.%d RC %d)", XORG_VERSION_MAJOR, + XORG_VERSION_MINOR, XORG_VERSION_PATCH + 1, + XORG_VERSION_SNAP - 900); +#endif +#endif + +#ifdef XORG_CUSTOM_VERSION + xf86ErrorFVerb(0, " (%s)", XORG_CUSTOM_VERSION); +#endif +#ifndef XORG_DATE +# define XORG_DATE "Unknown" +#endif + xf86ErrorFVerb(0, "\nRelease Date: %s\n", XORG_DATE); + xf86ErrorFVerb(0, "X Protocol Version %d, Revision %d\n", + X_PROTOCOL, X_PROTOCOL_REVISION); + xf86ErrorFVerb(0, "Build Operating System: %s %s\n", OSNAME, OSVENDOR); +#ifdef HAS_UTSNAME + { + struct utsname name; + + /* Linux & BSD state that 0 is success, SysV (including Solaris, HP-UX, + and Irix) and Single Unix Spec 3 just say that non-negative is success. + All agree that failure is represented by a negative number. + */ + if (uname(&name) >= 0) { + xf86ErrorFVerb(0, "Current Operating System: %s %s %s %s %s\n", + name.sysname, name.nodename, name.release, name.version, name.machine); +#ifdef linux + do { + char buf[80]; + int fd = open("/proc/cmdline", O_RDONLY); + if (fd != -1) { + xf86ErrorFVerb(0, "Kernel command line: "); + memset(buf, 0, 80); + while (read(fd, buf, 80) > 0) { + xf86ErrorFVerb(0, "%.80s", buf); + memset(buf, 0, 80); + } + close(fd); + } + } while (0); +#endif + } + } +#endif +#if defined(BUILD_DATE) && (BUILD_DATE > 19000000) + { + struct tm t; + char buf[100]; + + bzero(&t, sizeof(t)); + bzero(buf, sizeof(buf)); + t.tm_mday = BUILD_DATE % 100; + t.tm_mon = (BUILD_DATE / 100) % 100 - 1; + t.tm_year = BUILD_DATE / 10000 - 1900; +#if defined(BUILD_TIME) + t.tm_sec = BUILD_TIME % 100; + t.tm_min = (BUILD_TIME / 100) % 100; + t.tm_hour = (BUILD_TIME / 10000) % 100; + if (strftime(buf, sizeof(buf), "%d %B %Y %I:%M:%S%p", &t)) + xf86ErrorFVerb(0, "Build Date: %s\n", buf); +#else + if (strftime(buf, sizeof(buf), "%d %B %Y", &t)) + xf86ErrorFVerb(0, "Build Date: %s\n", buf); +#endif + } +#endif +#if defined(BUILDERSTRING) + xf86ErrorFVerb(0, "%s \n", BUILDERSTRING); +#endif + xf86ErrorFVerb(0, "Current version of pixman: %s\n", + pixman_version_string()); + xf86ErrorFVerb(0, "\tBefore reporting problems, check " + ""__VENDORDWEBSUPPORT__"\n" + "\tto make sure that you have the latest version.\n"); +} + +static void +xf86PrintMarkers(void) +{ + LogPrintMarkers(); +} + +static Bool +xf86CreateRootWindow(WindowPtr pWin) +{ + int ret = TRUE; + int err = Success; + ScreenPtr pScreen = pWin->drawable.pScreen; + RootWinPropPtr pProp; + CreateWindowProcPtr CreateWindow = (CreateWindowProcPtr) + dixLookupPrivate(&pScreen->devPrivates, xf86CreateRootWindowKey); + + DebugF("xf86CreateRootWindow(%p)\n", pWin); + + if ( pScreen->CreateWindow != xf86CreateRootWindow ) { + /* Can't find hook we are hung on */ + xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */, + "xf86CreateRootWindow %p called when not in pScreen->CreateWindow %p n", + (void *)xf86CreateRootWindow, + (void *)pScreen->CreateWindow ); + } + + /* Unhook this function ... */ + pScreen->CreateWindow = CreateWindow; + dixSetPrivate(&pScreen->devPrivates, xf86CreateRootWindowKey, NULL); + + /* ... and call the previous CreateWindow fuction, if any */ + if (NULL!=pScreen->CreateWindow) { + ret = (*pScreen->CreateWindow)(pWin); + } + + /* Now do our stuff */ + if (xf86RegisteredPropertiesTable != NULL) { + if (pWin->parent == NULL && xf86RegisteredPropertiesTable != NULL) { + for (pProp = xf86RegisteredPropertiesTable[pScreen->myNum]; + pProp != NULL && err==Success; + pProp = pProp->next ) + { + Atom prop; + + prop = MakeAtom(pProp->name, strlen(pProp->name), TRUE); + err = dixChangeWindowProperty(serverClient, pWin, + prop, pProp->type, + pProp->format, PropModeReplace, + pProp->size, pProp->data, + FALSE); + } + + /* Look at err */ + ret &= (err==Success); + + } else { + xf86Msg(X_ERROR, "xf86CreateRootWindow unexpectedly called with " + "non-root window %p (parent %p)\n", + (void *)pWin, (void *)pWin->parent); + ret = FALSE; + } + } + + DebugF("xf86CreateRootWindow() returns %d\n", ret); + return (ret); +} + + +static void +InstallSignalHandlers(void) +{ + /* + * Install signal handler for unexpected signals + */ + xf86Info.caughtSignal=FALSE; + if (!xf86Info.notrapSignals) { + OsRegisterSigWrapper(xf86SigWrapper); + } else { + signal(SIGSEGV, SIG_DFL); + signal(SIGILL, SIG_DFL); +#ifdef SIGEMT + signal(SIGEMT, SIG_DFL); +#endif + signal(SIGFPE, SIG_DFL); +#ifdef SIGBUS + signal(SIGBUS, SIG_DFL); +#endif +#ifdef SIGSYS + signal(SIGSYS, SIG_DFL); +#endif +#ifdef SIGXCPU + signal(SIGXCPU, SIG_DFL); +#endif +#ifdef SIGXFSZ + signal(SIGXFSZ, SIG_DFL); +#endif + } +} + + +#define END_OF_MATCHES(m) \ + (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0)) + +Bool +probe_devices_from_device_sections(DriverPtr drvp) +{ + int i, j; + struct pci_device * pPci; + Bool foundScreen = FALSE; + const struct pci_id_match * const devices = drvp->supported_devices; + GDevPtr *devList; + const unsigned numDevs = xf86MatchDevice(drvp->driverName, & devList); + + + for ( i = 0 ; i < numDevs ; i++ ) { + struct pci_device_iterator *iter; + unsigned device_id; + + + /* Find the pciVideoRec associated with this device section. + */ + iter = pci_id_match_iterator_create(NULL); + while ((pPci = pci_device_next(iter)) != NULL) { + if (devList[i]->busID && *devList[i]->busID) { + if (xf86ComparePciBusString(devList[i]->busID, + ((pPci->domain << 8) + | pPci->bus), + pPci->dev, + pPci->func)) { + break; + } + } + else if (xf86IsPrimaryPci(pPci)) { + break; + } + } + + pci_iterator_destroy(iter); + + if (pPci == NULL) { + continue; + } + + device_id = (devList[i]->chipID > 0) + ? devList[i]->chipID : pPci->device_id; + + + /* Once the pciVideoRec is found, determine if the device is supported + * by the driver. If it is, probe it! + */ + for ( j = 0 ; ! END_OF_MATCHES( devices[j] ) ; j++ ) { + if ( PCI_ID_COMPARE( devices[j].vendor_id, pPci->vendor_id ) + && PCI_ID_COMPARE( devices[j].device_id, device_id ) + && ((devices[j].device_class_mask & pPci->device_class) + == devices[j].device_class) ) { + int entry; + + /* Allow the same entity to be used more than once for + * devices with multiple screens per entity. This assumes + * implicitly that there will be a screen == 0 instance. + * + * FIXME Need to make sure that two different drivers don't + * FIXME claim the same screen > 0 instance. + */ + if ( (devList[i]->screen == 0) && !xf86CheckPciSlot( pPci ) ) + continue; + + DebugF("%s: card at %d:%d:%d is claimed by a Device section\n", + drvp->driverName, pPci->bus, pPci->dev, pPci->func); + + /* Allocate an entry in the lists to be returned */ + entry = xf86ClaimPciSlot(pPci, drvp, device_id, + devList[i], devList[i]->active); + + if ((entry == -1) && (devList[i]->screen > 0)) { + unsigned k; + + for ( k = 0; k < xf86NumEntities; k++ ) { + EntityPtr pEnt = xf86Entities[k]; + if (pEnt->bus.type != BUS_PCI) + continue; + + if (pEnt->bus.id.pci == pPci) { + entry = k; + xf86AddDevToEntity(k, devList[i]); + break; + } + } + } + + if (entry != -1) { + if ((*drvp->PciProbe)(drvp, entry, pPci, + devices[j].match_data)) { + foundScreen = TRUE; + } else + xf86UnclaimPciSlot(pPci); + } + + break; + } + } + } + free(devList); + + return foundScreen; +} + + +Bool +add_matching_devices_to_configure_list(DriverPtr drvp) +{ + const struct pci_id_match * const devices = drvp->supported_devices; + int j; + struct pci_device *pPci; + struct pci_device_iterator *iter; + int numFound = 0; + + + iter = pci_id_match_iterator_create(NULL); + while ((pPci = pci_device_next(iter)) != NULL) { + /* Determine if this device is supported by the driver. If it is, + * add it to the list of devices to configure. + */ + for (j = 0 ; ! END_OF_MATCHES(devices[j]) ; j++) { + if ( PCI_ID_COMPARE( devices[j].vendor_id, pPci->vendor_id ) + && PCI_ID_COMPARE( devices[j].device_id, pPci->device_id ) + && ((devices[j].device_class_mask & pPci->device_class) + == devices[j].device_class) ) { + if (xf86CheckPciSlot(pPci)) { + GDevPtr pGDev = xf86AddBusDeviceToConfigure( + drvp->driverName, BUS_PCI, pPci, -1); + if (pGDev != NULL) { + /* After configure pass 1, chipID and chipRev are + * treated as over-rides, so clobber them here. + */ + pGDev->chipID = -1; + pGDev->chipRev = -1; + } + + numFound++; + } + + break; + } + } + } + + pci_iterator_destroy(iter); + + + return (numFound != 0); +} + +/** + * Call the driver's correct probe function. + * + * If the driver implements the \c DriverRec::PciProbe entry-point and an + * appropriate PCI device (with matching Device section in the xorg.conf file) + * is found, it is called. If \c DriverRec::PciProbe or no devices can be + * successfully probed with it (e.g., only non-PCI devices are available), + * the driver's \c DriverRec::Probe function is called. + * + * \param drv Driver to probe + * + * \return + * If a device can be successfully probed by the driver, \c TRUE is + * returned. Otherwise, \c FALSE is returned. + */ +Bool +xf86CallDriverProbe( DriverPtr drv, Bool detect_only ) +{ + Bool foundScreen = FALSE; + + if ( drv->PciProbe != NULL ) { + if ( xf86DoConfigure && xf86DoConfigurePass1 ) { + assert( detect_only ); + foundScreen = add_matching_devices_to_configure_list( drv ); + } + else { + assert( ! detect_only ); + foundScreen = probe_devices_from_device_sections( drv ); + } + } + + if ( ! foundScreen && (drv->Probe != NULL) ) { + xf86Msg( X_WARNING, "Falling back to old probe method for %s\n", + drv->driverName ); + foundScreen = (*drv->Probe)( drv, (detect_only) ? PROBE_DETECT + : PROBE_DEFAULT ); + } + + return foundScreen; +} + +/* + * InitOutput -- + * Initialize screenInfo for all actually accessible framebuffers. + * That includes vt-manager setup, querying all possible devices and + * collecting the pixmap formats. + */ +void +InitOutput(ScreenInfo *pScreenInfo, int argc, char **argv) +{ + int i, j, k, scr_index; + char **modulelist; + pointer *optionlist; + screenLayoutPtr layout; + Pix24Flags screenpix24, pix24; + MessageType pix24From = X_DEFAULT; + Bool pix24Fail = FALSE; + Bool autoconfig = FALSE; + GDevPtr configured_device; + + xf86Initialising = TRUE; + + if (serverGeneration == 1) { + if ((xf86ServerName = strrchr(argv[0], '/')) != 0) + xf86ServerName++; + else + xf86ServerName = argv[0]; + + xf86PrintBanner(); + xf86PrintMarkers(); + if (xf86LogFile) { + time_t t; + const char *ct; + t = time(NULL); + ct = ctime(&t); + xf86MsgVerb(xf86LogFileFrom, 0, "Log file: \"%s\", Time: %s", + xf86LogFile, ct); + } + + /* Read and parse the config file */ + if (!xf86DoConfigure && !xf86DoShowOptions) { + switch (xf86HandleConfigFile(FALSE)) { + case CONFIG_OK: + break; + case CONFIG_PARSE_ERROR: + xf86Msg(X_ERROR, "Error parsing the config file\n"); + return; + case CONFIG_NOFILE: + autoconfig = TRUE; + break; + } + } + + InstallSignalHandlers(); + + /* Initialise the loader */ + LoaderInit(); + + /* Tell the loader the default module search path */ + LoaderSetPath(xf86ModulePath); + + if (xf86Info.ignoreABI) { + LoaderSetOptions(LDR_OPT_ABI_MISMATCH_NONFATAL); + } + + if (xf86DoShowOptions) + DoShowOptions(); + + /* Do a general bus probe. This will be a PCI probe for x86 platforms */ + xf86BusProbe(); + + if (xf86DoConfigure) + DoConfigure(); + + if (autoconfig) { + if (!xf86AutoConfig()) { + xf86Msg(X_ERROR, "Auto configuration failed\n"); + return; + } + } + +#ifdef XF86PM + xf86OSPMClose = xf86OSPMOpen(); +#endif + + /* Load all modules specified explicitly in the config file */ + if ((modulelist = xf86ModulelistFromConfig(&optionlist))) { + xf86LoadModules(modulelist, optionlist); + free(modulelist); + free(optionlist); + } + + /* Load all driver modules specified in the config file */ + /* If there aren't any specified in the config file, autoconfig them */ + /* FIXME: Does not handle multiple active screen sections, but I'm not + * sure if we really want to handle that case*/ + configured_device = xf86ConfigLayout.screens->screen->device; + if ((!configured_device) || (!configured_device->driver)) { + if (!autoConfigDevice(configured_device)) { + xf86Msg(X_ERROR, "Automatic driver configuration failed\n"); + return ; + } + } + if ((modulelist = xf86DriverlistFromConfig())) { + xf86LoadModules(modulelist, NULL); + free(modulelist); + } + + /* Load all input driver modules specified in the config file. */ + if ((modulelist = xf86InputDriverlistFromConfig())) { + xf86LoadModules(modulelist, NULL); + free(modulelist); + } + + /* + * It is expected that xf86AddDriver()/xf86AddInputDriver will be + * called for each driver as it is loaded. Those functions save the + * module pointers for drivers. + * XXX Nothing keeps track of them for other modules. + */ + /* XXX What do we do if not all of these could be loaded? */ + + /* + * At this point, xf86DriverList[] is all filled in with entries for + * each of the drivers to try and xf86NumDrivers has the number of + * drivers. If there are none, return now. + */ + + if (xf86NumDrivers == 0) { + xf86Msg(X_ERROR, "No drivers available.\n"); + return; + } + + /* + * Call each of the Identify functions and call the driverFunc to check + * if HW access is required. The Identify functions print out some + * identifying information, and anything else that might be + * needed at this early stage. + */ + + for (i = 0; i < xf86NumDrivers; i++) { + if (xf86DriverList[i]->Identify != NULL) + xf86DriverList[i]->Identify(0); + + if (!xorgHWAccess || !xorgHWOpenConsole) { + xorgHWFlags flags; + if(!xf86DriverList[i]->driverFunc + || !xf86DriverList[i]->driverFunc(NULL, + GET_REQUIRED_HW_INTERFACES, + &flags)) + flags = HW_IO; + + if(NEED_IO_ENABLED(flags)) + xorgHWAccess = TRUE; + if(!(flags & HW_SKIP_CONSOLE)) + xorgHWOpenConsole = TRUE; + } + } + + if (xorgHWOpenConsole) + xf86OpenConsole(); + else + xf86Info.dontVTSwitch = TRUE; + + /* Enable full I/O access */ + if (xorgHWAccess) + xorgHWAccess = xf86EnableIO(); + + /* + * Locate bus slot that had register IO enabled at server startup + */ + if (xorgHWAccess) { + xf86AccessInit(); + xf86FindPrimaryDevice(); + } + /* + * Now call each of the Probe functions. Each successful probe will + * result in an extra entry added to the xf86Screens[] list for each + * instance of the hardware found. + */ + + for (i = 0; i < xf86NumDrivers; i++) { + xorgHWFlags flags; + if (!xorgHWAccess) { + if (!xf86DriverList[i]->driverFunc + || !xf86DriverList[i]->driverFunc(NULL, + GET_REQUIRED_HW_INTERFACES, + &flags) + || NEED_IO_ENABLED(flags)) + continue; + } + + xf86CallDriverProbe( xf86DriverList[i], FALSE ); + } + + /* + * If nothing was detected, return now. + */ + + if (xf86NumScreens == 0) { + xf86Msg(X_ERROR, "No devices detected.\n"); + return; + } + + xf86VGAarbiterInit(); + + /* + * Match up the screens found by the probes against those specified + * in the config file. Remove the ones that won't be used. Sort + * them in the order specified. + */ + + /* + * What is the best way to do this? + * + * For now, go through the screens allocated by the probes, and + * look for screen config entry which refers to the same device + * section as picked out by the probe. + * + */ + + for (i = 0; i < xf86NumScreens; i++) { + for (layout = xf86ConfigLayout.screens; layout->screen != NULL; + layout++) { + Bool found = FALSE; + for (j = 0; j < xf86Screens[i]->numEntities; j++) { + + GDevPtr dev = + xf86GetDevFromEntity(xf86Screens[i]->entityList[j], + xf86Screens[i]->entityInstanceList[j]); + + if (dev == layout->screen->device) { + /* A match has been found */ + xf86Screens[i]->confScreen = layout->screen; + found = TRUE; + break; + } + } + if (found) break; + } + if (layout->screen == NULL) { + /* No match found */ + xf86Msg(X_ERROR, + "Screen %d deleted because of no matching config section.\n", i); + xf86DeleteScreen(i--, 0); + } + } + + /* + * If no screens left, return now. + */ + + if (xf86NumScreens == 0) { + xf86Msg(X_ERROR, + "Device(s) detected, but none match those in the config file.\n"); + return; + } + + xf86PostProbe(); + xf86EntityInit(); + + /* + * Sort the drivers to match the requested ording. Using a slow + * bubble sort. + */ + for (j = 0; j < xf86NumScreens - 1; j++) { + for (i = 0; i < xf86NumScreens - j - 1; i++) { + if (xf86Screens[i + 1]->confScreen->screennum < + xf86Screens[i]->confScreen->screennum) { + ScrnInfoPtr tmpScrn = xf86Screens[i + 1]; + xf86Screens[i + 1] = xf86Screens[i]; + xf86Screens[i] = tmpScrn; + } + } + } + /* Fix up the indexes */ + for (i = 0; i < xf86NumScreens; i++) { + xf86Screens[i]->scrnIndex = i; + } + + /* + * Call the driver's PreInit()'s to complete initialisation for the first + * generation. + */ + + for (i = 0; i < xf86NumScreens; i++) { + xf86VGAarbiterScrnInit(xf86Screens[i]); + xf86VGAarbiterLock(xf86Screens[i]); + if (xf86Screens[i]->PreInit && + xf86Screens[i]->PreInit(xf86Screens[i], 0)) + xf86Screens[i]->configured = TRUE; + xf86VGAarbiterUnlock(xf86Screens[i]); + } + for (i = 0; i < xf86NumScreens; i++) + if (!xf86Screens[i]->configured) + xf86DeleteScreen(i--, 0); + + /* + * If no screens left, return now. + */ + + if (xf86NumScreens == 0) { + xf86Msg(X_ERROR, + "Screen(s) found, but none have a usable configuration.\n"); + return; + } + + for (i = 0; i < xf86NumScreens; i++) { + if (xf86Screens[i]->name == NULL) { + xf86Screens[i]->name = xnfalloc(strlen("screen") + 10 + 1); + sprintf(xf86Screens[i]->name, "screen%d", i); + xf86MsgVerb(X_WARNING, 0, + "Screen driver %d has no name set, using `%s'.\n", + i, xf86Screens[i]->name); + } + } + + /* Remove (unload) drivers that are not required */ + for (i = 0; i < xf86NumDrivers; i++) + if (xf86DriverList[i] && xf86DriverList[i]->refCount <= 0) + xf86DeleteDriver(i); + + /* + * At this stage we know how many screens there are. + */ + + for (i = 0; i < xf86NumScreens; i++) + xf86InitViewport(xf86Screens[i]); + + /* + * Collect all pixmap formats and check for conflicts at the display + * level. Should we die here? Or just delete the offending screens? + */ + screenpix24 = Pix24DontCare; + for (i = 0; i < xf86NumScreens; i++) { + if (xf86Screens[i]->imageByteOrder != + xf86Screens[0]->imageByteOrder) + FatalError("Inconsistent display bitmapBitOrder. Exiting\n"); + if (xf86Screens[i]->bitmapScanlinePad != + xf86Screens[0]->bitmapScanlinePad) + FatalError("Inconsistent display bitmapScanlinePad. Exiting\n"); + if (xf86Screens[i]->bitmapScanlineUnit != + xf86Screens[0]->bitmapScanlineUnit) + FatalError("Inconsistent display bitmapScanlineUnit. Exiting\n"); + if (xf86Screens[i]->bitmapBitOrder != + xf86Screens[0]->bitmapBitOrder) + FatalError("Inconsistent display bitmapBitOrder. Exiting\n"); + + /* Determine the depth 24 pixmap format the screens would like */ + if (xf86Screens[i]->pixmap24 != Pix24DontCare) { + if (screenpix24 == Pix24DontCare) + screenpix24 = xf86Screens[i]->pixmap24; + else if (screenpix24 != xf86Screens[i]->pixmap24) + FatalError("Inconsistent depth 24 pixmap format. Exiting\n"); + } + } + /* check if screenpix24 is consistent with the config/cmdline */ + if (xf86Info.pixmap24 != Pix24DontCare) { + pix24 = xf86Info.pixmap24; + pix24From = xf86Info.pix24From; + if (screenpix24 != Pix24DontCare && screenpix24 != xf86Info.pixmap24) + pix24Fail = TRUE; + } else if (screenpix24 != Pix24DontCare) { + pix24 = screenpix24; + pix24From = X_PROBED; + } else + pix24 = Pix24Use32; + + if (pix24Fail) + FatalError("Screen(s) can't use the required depth 24 pixmap format" + " (%d). Exiting\n", PIX24TOBPP(pix24)); + + /* Initialise the depth 24 format */ + for (j = 0; j < numFormats && formats[j].depth != 24; j++) + ; + formats[j].bitsPerPixel = PIX24TOBPP(pix24); + + /* Collect additional formats */ + for (i = 0; i < xf86NumScreens; i++) { + for (j = 0; j < xf86Screens[i]->numFormats; j++) { + for (k = 0; ; k++) { + if (k >= numFormats) { + if (k >= MAXFORMATS) + FatalError("Too many pixmap formats! Exiting\n"); + formats[k] = xf86Screens[i]->formats[j]; + numFormats++; + break; + } + if (formats[k].depth == xf86Screens[i]->formats[j].depth) { + if ((formats[k].bitsPerPixel == + xf86Screens[i]->formats[j].bitsPerPixel) && + (formats[k].scanlinePad == + xf86Screens[i]->formats[j].scanlinePad)) + break; + FatalError("Inconsistent pixmap format for depth %d." + " Exiting\n", formats[k].depth); + } + } + } + } + formatsDone = TRUE; + + if (xf86Info.vtno >= 0 ) { +#define VT_ATOM_NAME "XFree86_VT" + Atom VTAtom=-1; + CARD32 *VT = NULL; + int ret; + + /* This memory needs to stay available until the screen has been + initialized, and we can create the property for real. + */ + if ( (VT = malloc(sizeof(CARD32)))==NULL ) { + FatalError("Unable to make VT property - out of memory. Exiting...\n"); + } + *VT = xf86Info.vtno; + + VTAtom = MakeAtom(VT_ATOM_NAME, sizeof(VT_ATOM_NAME) - 1, TRUE); + + for (i = 0, ret = Success; i < xf86NumScreens && ret == Success; i++) { + ret = xf86RegisterRootWindowProperty(xf86Screens[i]->scrnIndex, + VTAtom, XA_INTEGER, 32, + 1, VT ); + if (ret != Success) + xf86DrvMsg(xf86Screens[i]->scrnIndex, X_WARNING, + "Failed to register VT property\n"); + } + } + + /* If a screen uses depth 24, show what the pixmap format is */ + for (i = 0; i < xf86NumScreens; i++) { + if (xf86Screens[i]->depth == 24) { + xf86Msg(pix24From, "Depth 24 pixmap format is %d bpp\n", + PIX24TOBPP(pix24)); + break; + } + } + } else { + /* + * serverGeneration != 1; some OSs have to do things here, too. + */ + if (xorgHWOpenConsole) + xf86OpenConsole(); + +#ifdef XF86PM + /* + should we reopen it here? We need to deal with an already opened + device. We could leave this to the OS layer. For now we simply + close it here + */ + if (xf86OSPMClose) + xf86OSPMClose(); + if ((xf86OSPMClose = xf86OSPMOpen()) != NULL) + xf86MsgVerb(X_INFO, 3, "APM registered successfully\n"); +#endif + + /* Make sure full I/O access is enabled */ + if (xorgHWAccess) + xf86EnableIO(); + } + + /* + * Use the previously collected parts to setup pScreenInfo + */ + + pScreenInfo->imageByteOrder = xf86Screens[0]->imageByteOrder; + pScreenInfo->bitmapScanlinePad = xf86Screens[0]->bitmapScanlinePad; + pScreenInfo->bitmapScanlineUnit = xf86Screens[0]->bitmapScanlineUnit; + pScreenInfo->bitmapBitOrder = xf86Screens[0]->bitmapBitOrder; + pScreenInfo->numPixmapFormats = numFormats; + for (i = 0; i < numFormats; i++) + pScreenInfo->formats[i] = formats[i]; + + /* Make sure the server's VT is active */ + + if (serverGeneration != 1) { + xf86Resetting = TRUE; + /* All screens are in the same state, so just check the first */ + if (!xf86Screens[0]->vtSema) { +#ifdef HAS_USL_VTS + ioctl(xf86Info.consoleFd, VT_RELDISP, VT_ACKACQ); +#endif + xf86AccessEnter(); + xf86EnterServerState(SETUP); + } + } +#ifdef SCO325 + else { + /* + * Under SCO we must ack that we got the console at startup, + * I think this is the safest way to assure it. + */ + static int once = 1; + if (once) { + once = 0; + if (ioctl(xf86Info.consoleFd, VT_RELDISP, VT_ACKACQ) < 0) + xf86Msg(X_WARNING, "VT_ACKACQ failed"); + } + } +#endif /* SCO325 */ + + for (i = 0; i < xf86NumScreens; i++) { + xf86VGAarbiterLock(xf86Screens[i]); + /* + * Almost everything uses these defaults, and many of those that + * don't, will wrap them. + */ + xf86Screens[i]->EnableDisableFBAccess = xf86EnableDisableFBAccess; +#ifdef XFreeXDGA + xf86Screens[i]->SetDGAMode = xf86SetDGAMode; +#endif + xf86Screens[i]->DPMSSet = NULL; + xf86Screens[i]->LoadPalette = NULL; + xf86Screens[i]->SetOverscan = NULL; + xf86Screens[i]->DriverFunc = NULL; + xf86Screens[i]->pScreen = NULL; + scr_index = AddScreen(xf86Screens[i]->ScreenInit, argc, argv); + xf86VGAarbiterUnlock(xf86Screens[i]); + if (scr_index == i) { + /* + * Hook in our ScrnInfoRec, and initialise some other pScreen + * fields. + */ + dixSetPrivate(&screenInfo.screens[scr_index]->devPrivates, + xf86ScreenKey, xf86Screens[i]); + xf86Screens[i]->pScreen = screenInfo.screens[scr_index]; + /* The driver should set this, but make sure it is set anyway */ + xf86Screens[i]->vtSema = TRUE; + } else { + /* This shouldn't normally happen */ + FatalError("AddScreen/ScreenInit failed for driver %d\n", i); + } + + DebugF("InitOutput - xf86Screens[%d]->pScreen = %p\n", + i, xf86Screens[i]->pScreen ); + DebugF("xf86Screens[%d]->pScreen->CreateWindow = %p\n", + i, xf86Screens[i]->pScreen->CreateWindow ); + + dixSetPrivate(&screenInfo.screens[scr_index]->devPrivates, + xf86CreateRootWindowKey, + xf86Screens[i]->pScreen->CreateWindow); + xf86Screens[i]->pScreen->CreateWindow = xf86CreateRootWindow; + + if (PictureGetSubpixelOrder (xf86Screens[i]->pScreen) == SubPixelUnknown) + { + xf86MonPtr DDC = (xf86MonPtr)(xf86Screens[i]->monitor->DDC); + PictureSetSubpixelOrder (xf86Screens[i]->pScreen, + DDC ? + (DDC->features.input_type ? + SubPixelHorizontalRGB : SubPixelNone) : + SubPixelUnknown); + } +#ifdef RANDR + if (!xf86Info.disableRandR) + xf86RandRInit (screenInfo.screens[scr_index]); + xf86Msg(xf86Info.randRFrom, "RandR %s\n", + xf86Info.disableRandR ? "disabled" : "enabled"); +#endif + } + + xf86PostScreenInit(); + + xf86InitOrigins(); + + xf86Resetting = FALSE; + xf86Initialising = FALSE; + + RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, xf86Wakeup, + NULL); +} + +/* + * InitInput -- + * Initialize all supported input devices. + */ + +void +InitInput(int argc, char **argv) +{ + IDevPtr* pDev; + DeviceIntPtr dev; + + xf86Info.vtRequestsPending = FALSE; + + mieqInit(); + + GetEventList(&xf86Events); + + /* Call the PreInit function for each input device instance. */ + for (pDev = xf86ConfigLayout.inputs; pDev && *pDev; pDev++) { + /* Replace obsolete keyboard driver with kbd */ + if (!xf86NameCmp((*pDev)->driver, "keyboard")) { + strcpy((*pDev)->driver, "kbd"); + } + + /* If one fails, the others will too */ + if (xf86NewInputDevice(*pDev, &dev, TRUE) == BadAlloc) + break; + } + + config_init(); +} + +void +CloseInput (void) +{ + config_fini(); +} + +/* + * OsVendorInit -- + * OS/Vendor-specific initialisations. Called from OsInit(), which + * is called by dix before establishing the well known sockets. + */ + +void +OsVendorInit(void) +{ + static Bool beenHere = FALSE; + +#ifdef SIGCHLD + signal(SIGCHLD, SIG_DFL); /* Need to wait for child processes */ +#endif + + if (!beenHere) { + umask(022); + xf86LogInit(); + } + + /* Set stderr to non-blocking. */ +#ifndef O_NONBLOCK +#if defined(FNDELAY) +#define O_NONBLOCK FNDELAY +#elif defined(O_NDELAY) +#define O_NONBLOCK O_NDELAY +#endif + +#ifdef O_NONBLOCK + if (!beenHere) { + if (geteuid() == 0 && getuid() != geteuid()) + { + int status; + + status = fcntl(fileno(stderr), F_GETFL, 0); + if (status != -1) { + fcntl(fileno(stderr), F_SETFL, status | O_NONBLOCK); + } + } + } +#endif +#endif + + beenHere = TRUE; +} + +/* + * ddxGiveUp -- + * Device dependent cleanup. Called by by dix before normal server death. + * For SYSV386 we must switch the terminal back to normal mode. No error- + * checking here, since there should be restored as much as possible. + */ + +void +ddxGiveUp(void) +{ + int i; + + xf86VGAarbiterFini(); + +#ifdef XF86PM + if (xf86OSPMClose) + xf86OSPMClose(); + xf86OSPMClose = NULL; +#endif + + for (i = 0; i < xf86NumScreens; i++) { + /* + * zero all access functions to + * trap calls when switched away. + */ + xf86Screens[i]->vtSema = FALSE; + } + +#ifdef XFreeXDGA + DGAShutdown(); +#endif + + if (xorgHWOpenConsole) + xf86CloseConsole(); + + xf86CloseLog(); + + /* If an unexpected signal was caught, dump a core for debugging */ + if (xf86Info.caughtSignal) + OsAbort(); +} + + + +/* + * AbortDDX -- + * DDX - specific abort routine. Called by AbortServer(). The attempt is + * made to restore all original setting of the displays. Also all devices + * are closed. + */ + +void +AbortDDX(void) +{ + int i; + + /* + * try to restore the original video state + */ +#ifdef DPMSExtension /* Turn screens back on */ + if (DPMSPowerLevel != DPMSModeOn) + DPMSSet(serverClient, DPMSModeOn); +#endif + if (xf86Screens) { + if (xf86Screens[0]->vtSema) + xf86EnterServerState(SETUP); + for (i = 0; i < xf86NumScreens; i++) + if (xf86Screens[i]->vtSema) { + /* + * if we are aborting before ScreenInit() has finished + * we might not have been wrapped yet. Therefore enable + * screen explicitely. + */ + xf86VGAarbiterLock(xf86Screens[i]); + (xf86Screens[i]->LeaveVT)(i, 0); + xf86VGAarbiterUnlock(xf86Screens[i]); + } + } + + xf86AccessLeave(); + + /* + * This is needed for an abnormal server exit, since the normal exit stuff + * MUST also be performed (i.e. the vt must be left in a defined state) + */ + ddxGiveUp(); +} + +void +OsVendorFatalError(void) +{ +#ifdef VENDORSUPPORT + ErrorF("\nPlease refer to your Operating System Vendor support pages\n" + "at %s for support on this crash.\n",VENDORSUPPORT); +#else + ErrorF("\nPlease consult the "XVENDORNAME" support \n" + "\t at "__VENDORDWEBSUPPORT__"\n for help. \n"); +#endif + if (xf86LogFile && xf86LogFileWasOpened) + ErrorF("Please also check the log file at \"%s\" for additional " + "information.\n", xf86LogFile); + ErrorF("\n"); +} + +int +xf86SetVerbosity(int verb) +{ + int save = xf86Verbose; + + xf86Verbose = verb; + LogSetParameter(XLOG_VERBOSITY, verb); + return save; +} + +int +xf86SetLogVerbosity(int verb) +{ + int save = xf86LogVerbose; + + xf86LogVerbose = verb; + LogSetParameter(XLOG_FILE_VERBOSITY, verb); + return save; +} + +static void +xf86PrintDefaultModulePath(void) +{ + ErrorF("%s\n", DEFAULT_MODULE_PATH); +} + +static void +xf86PrintDefaultLibraryPath(void) +{ + ErrorF("%s\n", DEFAULT_LIBRARY_PATH); +} + +/* + * ddxProcessArgument -- + * Process device-dependent command line args. Returns 0 if argument is + * not device dependent, otherwise Count of number of elements of argv + * that are part of a device dependent commandline option. + * + */ + +/* ARGSUSED */ +int +ddxProcessArgument(int argc, char **argv, int i) +{ + /* + * Note: can't use xalloc/xfree here because OsInit() hasn't been called + * yet. Use malloc/free instead. + */ + +#define CHECK_FOR_REQUIRED_ARGUMENT() \ + if (((i + 1) >= argc) || (!argv[i + 1])) { \ + ErrorF("Required argument to %s not specified\n", argv[i]); \ + UseMsg(); \ + FatalError("Required argument to %s not specified\n", argv[i]); \ + } + + /* First the options that are only allowed for root */ + if (!strcmp(argv[i], "-modulepath") || !strcmp(argv[i], "-logfile")) { + if ( (geteuid() == 0) && (getuid() != 0) ) { + FatalError("The '%s' option can only be used by root.\n", argv[i]); + } + else if (!strcmp(argv[i], "-modulepath")) + { + char *mp; + CHECK_FOR_REQUIRED_ARGUMENT(); + mp = malloc(strlen(argv[i + 1]) + 1); + if (!mp) + FatalError("Can't allocate memory for ModulePath\n"); + strcpy(mp, argv[i + 1]); + xf86ModulePath = mp; + xf86ModPathFrom = X_CMDLINE; + return 2; + } + else if (!strcmp(argv[i], "-logfile")) + { + char *lf; + CHECK_FOR_REQUIRED_ARGUMENT(); + lf = malloc(strlen(argv[i + 1]) + 1); + if (!lf) + FatalError("Can't allocate memory for LogFile\n"); + strcpy(lf, argv[i + 1]); + xf86LogFile = lf; + xf86LogFileFrom = X_CMDLINE; + return 2; + } + } + if (!strcmp(argv[i], "-config") || !strcmp(argv[i], "-xf86config")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) { + FatalError("\nInvalid argument for %s\n" + "\tFor non-root users, the file specified with %s must be\n" + "\ta relative path and must not contain any \"..\" elements.\n" + "\tUsing default "__XCONFIGFILE__" search path.\n\n", + argv[i], argv[i]); + } + xf86ConfigFile = argv[i + 1]; + return 2; + } + if (!strcmp(argv[i], "-configdir")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) { + FatalError("\nInvalid argument for %s\n" + "\tFor non-root users, the file specified with %s must be\n" + "\ta relative path and must not contain any \"..\" elements.\n" + "\tUsing default "__XCONFIGDIR__" search path.\n\n", + argv[i], argv[i]); + } + xf86ConfigDir = argv[i + 1]; + return 2; + } + if (!strcmp(argv[i],"-flipPixels")) + { + xf86FlipPixels = TRUE; + return 1; + } +#ifdef XF86VIDMODE + if (!strcmp(argv[i],"-disableVidMode")) + { + xf86VidModeDisabled = TRUE; + return 1; + } + if (!strcmp(argv[i],"-allowNonLocalXvidtune")) + { + xf86VidModeAllowNonLocal = TRUE; + return 1; + } +#endif + if (!strcmp(argv[i],"-allowMouseOpenFail")) + { + xf86AllowMouseOpenFail = TRUE; + return 1; + } + if (!strcmp(argv[i],"-ignoreABI")) + { + LoaderSetOptions(LDR_OPT_ABI_MISMATCH_NONFATAL); + return 1; + } + if (!strcmp(argv[i],"-verbose")) + { + if (++i < argc && argv[i]) + { + char *end; + long val; + val = strtol(argv[i], &end, 0); + if (*end == '\0') + { + xf86SetVerbosity(val); + return 2; + } + } + xf86SetVerbosity(++xf86Verbose); + return 1; + } + if (!strcmp(argv[i],"-logverbose")) + { + if (++i < argc && argv[i]) + { + char *end; + long val; + val = strtol(argv[i], &end, 0); + if (*end == '\0') + { + xf86SetLogVerbosity(val); + return 2; + } + } + xf86SetLogVerbosity(++xf86LogVerbose); + return 1; + } + if (!strcmp(argv[i],"-quiet")) + { + xf86SetVerbosity(-1); + return 1; + } + if (!strcmp(argv[i],"-showconfig") || !strcmp(argv[i],"-version")) + { + xf86PrintBanner(); + exit(0); + } + if (!strcmp(argv[i],"-showDefaultModulePath")) + { + xf86PrintDefaultModulePath(); + exit(0); + } + if (!strcmp(argv[i],"-showDefaultLibPath")) + { + xf86PrintDefaultLibraryPath(); + exit(0); + } + /* Notice the -fp flag, but allow it to pass to the dix layer */ + if (!strcmp(argv[i], "-fp")) + { + xf86fpFlag = TRUE; + return 0; + } + /* Notice the -bs flag, but allow it to pass to the dix layer */ + if (!strcmp(argv[i], "-bs")) + { + xf86bsDisableFlag = TRUE; + return 0; + } + /* Notice the +bs flag, but allow it to pass to the dix layer */ + if (!strcmp(argv[i], "+bs")) + { + xf86bsEnableFlag = TRUE; + return 0; + } + /* Notice the -s flag, but allow it to pass to the dix layer */ + if (!strcmp(argv[i], "-s")) + { + xf86sFlag = TRUE; + return 0; + } + if (!strcmp(argv[i], "-pixmap24")) + { + xf86Pix24 = Pix24Use24; + return 1; + } + if (!strcmp(argv[i], "-pixmap32")) + { + xf86Pix24 = Pix24Use32; + return 1; + } + if (!strcmp(argv[i], "-fbbpp")) + { + int bpp; + CHECK_FOR_REQUIRED_ARGUMENT(); + if (sscanf(argv[++i], "%d", &bpp) == 1) + { + xf86FbBpp = bpp; + return 2; + } + else + { + ErrorF("Invalid fbbpp\n"); + return 0; + } + } + if (!strcmp(argv[i], "-depth")) + { + int depth; + CHECK_FOR_REQUIRED_ARGUMENT(); + if (sscanf(argv[++i], "%d", &depth) == 1) + { + xf86Depth = depth; + return 2; + } + else + { + ErrorF("Invalid depth\n"); + return 0; + } + } + if (!strcmp(argv[i], "-weight")) + { + int red, green, blue; + CHECK_FOR_REQUIRED_ARGUMENT(); + if (sscanf(argv[++i], "%1d%1d%1d", &red, &green, &blue) == 3) + { + xf86Weight.red = red; + xf86Weight.green = green; + xf86Weight.blue = blue; + return 2; + } + else + { + ErrorF("Invalid weighting\n"); + return 0; + } + } + if (!strcmp(argv[i], "-gamma") || !strcmp(argv[i], "-rgamma") || + !strcmp(argv[i], "-ggamma") || !strcmp(argv[i], "-bgamma")) + { + double gamma; + CHECK_FOR_REQUIRED_ARGUMENT(); + if (sscanf(argv[++i], "%lf", &gamma) == 1) { + if (gamma < GAMMA_MIN || gamma > GAMMA_MAX) { + ErrorF("gamma out of range, only %.2f <= gamma_value <= %.1f" + " is valid\n", GAMMA_MIN, GAMMA_MAX); + return 0; + } + if (!strcmp(argv[i-1], "-gamma")) + xf86Gamma.red = xf86Gamma.green = xf86Gamma.blue = gamma; + else if (!strcmp(argv[i-1], "-rgamma")) xf86Gamma.red = gamma; + else if (!strcmp(argv[i-1], "-ggamma")) xf86Gamma.green = gamma; + else if (!strcmp(argv[i-1], "-bgamma")) xf86Gamma.blue = gamma; + return 2; + } + } + if (!strcmp(argv[i], "-layout")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + xf86LayoutName = argv[++i]; + return 2; + } + if (!strcmp(argv[i], "-screen")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + xf86ScreenName = argv[++i]; + return 2; + } + if (!strcmp(argv[i], "-pointer")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + xf86PointerName = argv[++i]; + return 2; + } + if (!strcmp(argv[i], "-keyboard")) + { + CHECK_FOR_REQUIRED_ARGUMENT(); + xf86KeyboardName = argv[++i]; + return 2; + } + if (!strcmp(argv[i], "-nosilk")) + { + xf86silkenMouseDisableFlag = TRUE; + return 1; + } +#ifdef HAVE_ACPI + if (!strcmp(argv[i], "-noacpi")) + { + xf86acpiDisableFlag = TRUE; + return 1; + } +#endif + if (!strcmp(argv[i], "-configure")) + { + if (getuid() != 0 && geteuid() == 0) { + ErrorF("The '-configure' option can only be used by root.\n"); + exit(1); + } + xf86DoConfigure = TRUE; + xf86AllowMouseOpenFail = TRUE; + return 1; + } + if (!strcmp(argv[i], "-showopts")) + { + if (getuid() != 0 && geteuid() == 0) { + ErrorF("The '-showopts' option can only be used by root.\n"); + exit(1); + } + xf86DoShowOptions = TRUE; + return 1; + } + if (!strcmp(argv[i], "-isolateDevice")) + { + int bus, device, func; + CHECK_FOR_REQUIRED_ARGUMENT(); + if (strncmp(argv[++i], "PCI:", 4)) { + FatalError("Bus types other than PCI not yet isolable\n"); + } + if (sscanf(argv[i], "PCI:%d:%d:%d", &bus, &device, &func) == 3) { + xf86IsolateDevice.domain = PCI_DOM_FROM_BUS(bus); + xf86IsolateDevice.bus = PCI_BUS_NO_DOMAIN(bus); + xf86IsolateDevice.dev = device; + xf86IsolateDevice.func = func; + return 2; + } else { + FatalError("Invalid isolated device specification\n"); + } + } + /* Notice cmdline xkbdir, but pass to dix as well */ + if (!strcmp(argv[i], "-xkbdir")) + { + xf86xkbdirFlag = TRUE; + return 0; + } + + /* OS-specific processing */ + return xf86ProcessArgument(argc, argv, i); +} + +/* + * ddxUseMsg -- + * Print out correct use of device dependent commandline options. + * Maybe the user now knows what really to do ... + */ + +void +ddxUseMsg(void) +{ + ErrorF("\n"); + ErrorF("\n"); + ErrorF("Device Dependent Usage\n"); + if (getuid() == 0 || geteuid() != 0) + { + ErrorF("-modulepath paths specify the module search path\n"); + ErrorF("-logfile file specify a log file name\n"); + ErrorF("-configure probe for devices and write an "__XCONFIGFILE__"\n"); + ErrorF("-showopts print available options for all installed drivers\n"); + } + ErrorF("-config file specify a configuration file, relative to the\n"); + ErrorF(" "__XCONFIGFILE__" search path, only root can use absolute\n"); + ErrorF("-configdir dir specify a configuration directory, relative to the\n"); + ErrorF(" "__XCONFIGDIR__" search path, only root can use absolute\n"); + ErrorF("-verbose [n] verbose startup messages\n"); + ErrorF("-logverbose [n] verbose log messages\n"); + ErrorF("-quiet minimal startup messages\n"); + ErrorF("-pixmap24 use 24bpp pixmaps for depth 24\n"); + ErrorF("-pixmap32 use 32bpp pixmaps for depth 24\n"); + ErrorF("-fbbpp n set bpp for the framebuffer. Default: 8\n"); + ErrorF("-depth n set colour depth. Default: 8\n"); + ErrorF("-gamma f set gamma value (0.1 < f < 10.0) Default: 1.0\n"); + ErrorF("-rgamma f set gamma value for red phase\n"); + ErrorF("-ggamma f set gamma value for green phase\n"); + ErrorF("-bgamma f set gamma value for blue phase\n"); + ErrorF("-weight nnn set RGB weighting at 16 bpp. Default: 565\n"); + ErrorF("-layout name specify the ServerLayout section name\n"); + ErrorF("-screen name specify the Screen section name\n"); + ErrorF("-keyboard name specify the core keyboard InputDevice name\n"); + ErrorF("-pointer name specify the core pointer InputDevice name\n"); + ErrorF("-nosilk disable Silken Mouse\n"); + ErrorF("-flipPixels swap default black/white Pixel values\n"); +#ifdef XF86VIDMODE + ErrorF("-disableVidMode disable mode adjustments with xvidtune\n"); + ErrorF("-allowNonLocalXvidtune allow xvidtune to be run as a non-local client\n"); +#endif + ErrorF("-allowMouseOpenFail start server even if the mouse can't be initialized\n"); + ErrorF("-ignoreABI make module ABI mismatches non-fatal\n"); + ErrorF("-isolateDevice bus_id restrict device resets to bus_id (PCI only)\n"); + ErrorF("-version show the server version\n"); + ErrorF("-showDefaultModulePath show the server default module path\n"); + ErrorF("-showDefaultLibPath show the server default library path\n"); + /* OS-specific usage */ + xf86UseMsg(); + ErrorF("\n"); +} + + +/* + * xf86LoadModules iterates over a list that is being passed in. + */ +Bool +xf86LoadModules(char **list, pointer *optlist) +{ + int errmaj, errmin; + pointer opt; + int i; + char *name; + Bool failed = FALSE; + + if (!list) + return TRUE; + + for (i = 0; list[i] != NULL; i++) { + + /* Normalise the module name */ + name = xf86NormalizeName(list[i]); + + /* Skip empty names */ + if (name == NULL || *name == '\0') + continue; + + /* Replace obsolete keyboard driver with kbd */ + if (!xf86NameCmp(name, "keyboard")) { + strcpy(name, "kbd"); + } + + if (optlist) + opt = optlist[i]; + else + opt = NULL; + + if (!LoadModule(name, NULL, NULL, NULL, opt, NULL, &errmaj, &errmin)) { + LoaderErrorMsg(NULL, name, errmaj, errmin); + failed = TRUE; + } + free(name); + } + return !failed; +} + +/* Pixmap format stuff */ + +PixmapFormatPtr +xf86GetPixFormat(ScrnInfoPtr pScrn, int depth) +{ + int i; + static PixmapFormatRec format; /* XXX not reentrant */ + + /* + * When the formats[] list initialisation isn't complete, check the + * depth 24 pixmap config/cmdline options and screen-specified formats. + */ + + if (!formatsDone) { + if (depth == 24) { + Pix24Flags pix24 = Pix24DontCare; + + format.depth = 24; + format.scanlinePad = BITMAP_SCANLINE_PAD; + if (xf86Info.pixmap24 != Pix24DontCare) + pix24 = xf86Info.pixmap24; + else if (pScrn->pixmap24 != Pix24DontCare) + pix24 = pScrn->pixmap24; + if (pix24 == Pix24Use24) + format.bitsPerPixel = 24; + else + format.bitsPerPixel = 32; + return &format; + } + } + + for (i = 0; i < numFormats; i++) + if (formats[i].depth == depth) + break; + if (i != numFormats) + return &formats[i]; + else if (!formatsDone) { + /* Check for screen-specified formats */ + for (i = 0; i < pScrn->numFormats; i++) + if (pScrn->formats[i].depth == depth) + break; + if (i != pScrn->numFormats) + return &pScrn->formats[i]; + } + return NULL; +} + +int +xf86GetBppFromDepth(ScrnInfoPtr pScrn, int depth) +{ + PixmapFormatPtr format; + + + format = xf86GetPixFormat(pScrn, depth); + if (format) + return format->bitsPerPixel; + else + return 0; +} diff --git a/xorg-server/hw/xfree86/common/xf86Mode.c b/xorg-server/hw/xfree86/common/xf86Mode.c index 5d30a782c..af738e703 100644 --- a/xorg-server/hw/xfree86/common/xf86Mode.c +++ b/xorg-server/hw/xfree86/common/xf86Mode.c @@ -1,2067 +1,2067 @@ -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * LCM() and scanLineWidth() are: - * - * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org - * - * 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 Marc Aurele La France not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. Marc Aurele La France makes no representations - * about the suitability of this software for any purpose. It is provided - * "as-is" without express or implied warranty. - * - * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO - * EVENT SHALL MARC AURELE LA FRANCE 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. - * - * Copyright 1990,91,92,93 by Thomas Roell, Germany. - * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA. - * - * 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 Thomas Roell nor - * SGCS be used in advertising or publicity pertaining to distribution - * of the software without specific, written prior permission. - * Thomas Roell nor SGCS makes no representations about the suitability - * of this software for any purpose. It is provided "as is" without - * express or implied warranty. - * - * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS 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. - */ - -/* - * Authors: Dirk Hohndel <hohndel@XFree86.Org> - * David Dawes <dawes@XFree86.Org> - * Marc La France <tsi@XFree86.Org> - * ... and others - * - * This file includes helper functions for mode related things. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include "xf86Modes.h" -#include "os.h" -#include "servermd.h" -#include "globals.h" -#include "xf86.h" -#include "xf86Priv.h" -#include "edid.h" - -static void -printModeRejectMessage(int index, DisplayModePtr p, int status) -{ - char *type; - - if (p->type & M_T_BUILTIN) - type = "built-in "; - else if (p->type & M_T_DEFAULT) - type = "default "; - else if (p->type & M_T_DRIVER) - type = "driver "; - else - type = ""; - - xf86DrvMsg(index, X_INFO, "Not using %smode \"%s\" (%s)\n", type, p->name, - xf86ModeStatusToString(status)); -} - -/* - * xf86GetNearestClock -- - * Find closest clock to given frequency (in kHz). This assumes the - * number of clocks is greater than zero. - */ -int -xf86GetNearestClock(ScrnInfoPtr scrp, int freq, Bool allowDiv2, - int DivFactor, int MulFactor, int *divider) -{ - int nearestClock = 0, nearestDiv = 1; - int minimumGap = abs(freq - scrp->clock[0]); - int i, j, k, gap; - - if (allowDiv2) - k = 2; - else - k = 1; - - /* Must set this here in case the best match is scrp->clock[0] */ - if (divider != NULL) - *divider = 0; - - for (i = 0; i < scrp->numClocks; i++) { - for (j = 1; j <= k; j++) { - gap = abs((freq * j) - ((scrp->clock[i] * DivFactor) / MulFactor)); - if ((gap < minimumGap) || - ((gap == minimumGap) && (j < nearestDiv))) { - minimumGap = gap; - nearestClock = i; - nearestDiv = j; - if (divider != NULL) - *divider = (j - 1) * V_CLKDIV2; - } - } - } - return nearestClock; -} - -/* - * xf86ModeStatusToString - * - * Convert a ModeStatus value to a printable message - */ - -const char * -xf86ModeStatusToString(ModeStatus status) -{ - switch (status) { - case MODE_OK: - return "Mode OK"; - case MODE_HSYNC: - return "hsync out of range"; - case MODE_VSYNC: - return "vrefresh out of range"; - case MODE_H_ILLEGAL: - return "illegal horizontal timings"; - case MODE_V_ILLEGAL: - return "illegal vertical timings"; - case MODE_BAD_WIDTH: - return "width requires unsupported line pitch"; - case MODE_NOMODE: - return "no mode of this name"; - case MODE_NO_INTERLACE: - return "interlace mode not supported"; - case MODE_NO_DBLESCAN: - return "doublescan mode not supported"; - case MODE_NO_VSCAN: - return "multiscan mode not supported"; - case MODE_MEM: - return "insufficient memory for mode"; - case MODE_VIRTUAL_X: - return "width too large for virtual size"; - case MODE_VIRTUAL_Y: - return "height too large for virtual size"; - case MODE_MEM_VIRT: - return "insufficient memory given virtual size"; - case MODE_NOCLOCK: - return "no clock available for mode"; - case MODE_CLOCK_HIGH: - return "mode clock too high"; - case MODE_CLOCK_LOW: - return "mode clock too low"; - case MODE_CLOCK_RANGE: - return "bad mode clock/interlace/doublescan"; - case MODE_BAD_HVALUE: - return "horizontal timing out of range"; - case MODE_BAD_VVALUE: - return "vertical timing out of range"; - case MODE_BAD_VSCAN: - return "VScan value out of range"; - case MODE_HSYNC_NARROW: - return "horizontal sync too narrow"; - case MODE_HSYNC_WIDE: - return "horizontal sync too wide"; - case MODE_HBLANK_NARROW: - return "horizontal blanking too narrow"; - case MODE_HBLANK_WIDE: - return "horizontal blanking too wide"; - case MODE_VSYNC_NARROW: - return "vertical sync too narrow"; - case MODE_VSYNC_WIDE: - return "vertical sync too wide"; - case MODE_VBLANK_NARROW: - return "vertical blanking too narrow"; - case MODE_VBLANK_WIDE: - return "vertical blanking too wide"; - case MODE_PANEL: - return "exceeds panel dimensions"; - case MODE_INTERLACE_WIDTH: - return "width too large for interlaced mode"; - case MODE_ONE_WIDTH: - return "all modes must have the same width"; - case MODE_ONE_HEIGHT: - return "all modes must have the same height"; - case MODE_ONE_SIZE: - return "all modes must have the same resolution"; - case MODE_NO_REDUCED: - return "monitor doesn't support reduced blanking"; - case MODE_BANDWIDTH: - return "mode requires too much memory bandwidth"; - case MODE_BAD: - return "unknown reason"; - case MODE_ERROR: - return "internal error"; - default: - return "unknown"; - } -} - -/* - * xf86ShowClockRanges() -- Print the clock ranges allowed - * and the clock values scaled by ClockMulFactor and ClockDivFactor - */ -void -xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges) -{ - ClockRangePtr cp; - int MulFactor = 1; - int DivFactor = 1; - int i, j; - int scaledClock; - - for (cp = clockRanges; cp != NULL; cp = cp->next) { - DivFactor = max(1, cp->ClockDivFactor); - MulFactor = max(1, cp->ClockMulFactor); - if (scrp->progClock) { - if (cp->minClock) { - if (cp->maxClock) { - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "Clock range: %6.2f to %6.2f MHz\n", - (double)cp->minClock / 1000.0, - (double)cp->maxClock / 1000.0); - } else { - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "Minimum clock: %6.2f MHz\n", - (double)cp->minClock / 1000.0); - } - } else { - if (cp->maxClock) { - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "Maximum clock: %6.2f MHz\n", - (double)cp->maxClock / 1000.0); - } - } - } else if (DivFactor > 1 || MulFactor > 1) { - j = 0; - for (i = 0; i < scrp->numClocks; i++) { - scaledClock = (scrp->clock[i] * DivFactor) / MulFactor; - if (scaledClock >= cp->minClock && scaledClock <= cp->maxClock) { - if ((j % 8) == 0) { - if (j > 0) - xf86ErrorF("\n"); - xf86DrvMsg(scrp->scrnIndex, X_INFO, "scaled clocks:"); - } - xf86ErrorF(" %6.2f", (double)scaledClock / 1000.0); - j++; - } - } - xf86ErrorF("\n"); - } - } -} - -static Bool -modeInClockRange(ClockRangePtr cp, DisplayModePtr p) -{ - return ((p->Clock >= cp->minClock) && - (p->Clock <= cp->maxClock) && - (cp->interlaceAllowed || !(p->Flags & V_INTERLACE)) && - (cp->doubleScanAllowed || - ((p->VScan <= 1) && !(p->Flags & V_DBLSCAN)))); -} - -/* - * xf86FindClockRangeForMode() [... like the name says ...] - */ -static ClockRangePtr -xf86FindClockRangeForMode(ClockRangePtr clockRanges, DisplayModePtr p) -{ - ClockRangePtr cp; - - for (cp = clockRanges; ; cp = cp->next) - if (!cp || modeInClockRange(cp, p)) - return cp; -} - - -/* - * xf86HandleBuiltinMode() - handles built-in modes - */ -static ModeStatus -xf86HandleBuiltinMode(ScrnInfoPtr scrp, - DisplayModePtr p, - DisplayModePtr modep, - ClockRangePtr clockRanges, - Bool allowDiv2) -{ - ClockRangePtr cp; - int extraFlags = 0; - int MulFactor = 1; - int DivFactor = 1; - int clockIndex; - - /* Reject previously rejected modes */ - if (p->status != MODE_OK) - return p->status; - - /* Reject previously considered modes */ - if (p->prev) - return MODE_NOMODE; - - if ((p->type & M_T_CLOCK_C) == M_T_CLOCK_C) { - /* Check clock is in range */ - cp = xf86FindClockRangeForMode(clockRanges, p); - if (cp == NULL){ - modep->type = p->type; - p->status = MODE_CLOCK_RANGE; - return MODE_CLOCK_RANGE; - } - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - if (!scrp->progClock) { - clockIndex = xf86GetNearestClock(scrp, p->Clock, allowDiv2, - cp->ClockDivFactor, - cp->ClockMulFactor, &extraFlags); - modep->Clock = (scrp->clock[clockIndex] * DivFactor) - / MulFactor; - modep->ClockIndex = clockIndex; - modep->SynthClock = scrp->clock[clockIndex]; - if (extraFlags & V_CLKDIV2) { - modep->Clock /= 2; - modep->SynthClock /= 2; - } - } else { - modep->Clock = p->Clock; - modep->ClockIndex = -1; - modep->SynthClock = (modep->Clock * MulFactor) - / DivFactor; - } - modep->PrivFlags = cp->PrivFlags; - } else { - if(!scrp->progClock) { - modep->Clock = p->Clock; - modep->ClockIndex = p->ClockIndex; - modep->SynthClock = p->SynthClock; - } else { - modep->Clock = p->Clock; - modep->ClockIndex = -1; - modep->SynthClock = p->SynthClock; - } - modep->PrivFlags = p->PrivFlags; - } - modep->type = p->type; - modep->HDisplay = p->HDisplay; - modep->HSyncStart = p->HSyncStart; - modep->HSyncEnd = p->HSyncEnd; - modep->HTotal = p->HTotal; - modep->HSkew = p->HSkew; - modep->VDisplay = p->VDisplay; - modep->VSyncStart = p->VSyncStart; - modep->VSyncEnd = p->VSyncEnd; - modep->VTotal = p->VTotal; - modep->VScan = p->VScan; - modep->Flags = p->Flags | extraFlags; - modep->CrtcHDisplay = p->CrtcHDisplay; - modep->CrtcHBlankStart = p->CrtcHBlankStart; - modep->CrtcHSyncStart = p->CrtcHSyncStart; - modep->CrtcHSyncEnd = p->CrtcHSyncEnd; - modep->CrtcHBlankEnd = p->CrtcHBlankEnd; - modep->CrtcHTotal = p->CrtcHTotal; - modep->CrtcHSkew = p->CrtcHSkew; - modep->CrtcVDisplay = p->CrtcVDisplay; - modep->CrtcVBlankStart = p->CrtcVBlankStart; - modep->CrtcVSyncStart = p->CrtcVSyncStart; - modep->CrtcVSyncEnd = p->CrtcVSyncEnd; - modep->CrtcVBlankEnd = p->CrtcVBlankEnd; - modep->CrtcVTotal = p->CrtcVTotal; - modep->CrtcHAdjusted = p->CrtcHAdjusted; - modep->CrtcVAdjusted = p->CrtcVAdjusted; - modep->HSync = p->HSync; - modep->VRefresh = p->VRefresh; - modep->Private = p->Private; - modep->PrivSize = p->PrivSize; - - p->prev = modep; - - return MODE_OK; -} - -/* - * xf86LookupMode - * - * This function returns a mode from the given list which matches the - * given name. When multiple modes with the same name are available, - * the method of picking the matching mode is determined by the - * strategy selected. - * - * This function takes the following parameters: - * scrp ScrnInfoPtr - * modep pointer to the returned mode, which must have the name - * field filled in. - * clockRanges a list of clock ranges. This is optional when all the - * modes are built-in modes. - * strategy how to decide which mode to use from multiple modes with - * the same name - * - * In addition, the following fields from the ScrnInfoRec are used: - * modePool the list of monitor modes compatible with the driver - * clocks a list of discrete clocks - * numClocks number of discrete clocks - * progClock clock is programmable - * - * If a mode was found, its values are filled in to the area pointed to - * by modep, If a mode was not found the return value indicates the - * reason. - */ - -ModeStatus -xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep, - ClockRangePtr clockRanges, LookupModeFlags strategy) -{ - DisplayModePtr p, bestMode = NULL; - ClockRangePtr cp; - int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; - double refresh, bestRefresh = 0.0; - Bool found = FALSE; - int extraFlags = 0; - int clockIndex = -1; - int MulFactor = 1; - int DivFactor = 1; - int ModePrivFlags = 0; - ModeStatus status = MODE_NOMODE; - Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; - int n; - const int types[] = { - M_T_BUILTIN | M_T_PREFERRED, - M_T_BUILTIN, - M_T_USERDEF | M_T_PREFERRED, - M_T_USERDEF, - M_T_DRIVER | M_T_PREFERRED, - M_T_DRIVER, - 0 - }; - const int ntypes = sizeof(types) / sizeof(int); - - strategy &= ~(LOOKUP_CLKDIV2 | LOOKUP_OPTIONAL_TOLERANCES); - - /* Some sanity checking */ - if (scrp == NULL || scrp->modePool == NULL || - (!scrp->progClock && scrp->numClocks == 0)) { - ErrorF("xf86LookupMode: called with invalid scrnInfoRec\n"); - return MODE_ERROR; - } - if (modep == NULL || modep->name == NULL) { - ErrorF("xf86LookupMode: called with invalid modep\n"); - return MODE_ERROR; - } - for (cp = clockRanges; cp != NULL; cp = cp->next) { - /* DivFactor and MulFactor must be > 0 */ - cp->ClockDivFactor = max(1, cp->ClockDivFactor); - cp->ClockMulFactor = max(1, cp->ClockMulFactor); - } - - /* Scan the mode pool for matching names */ - for (n = 0; n < ntypes; n++) { - int type = types[n]; - for (p = scrp->modePool; p != NULL; p = p->next) { - - /* scan through the modes in the sort order above */ - if ((p->type & type) != type) - continue; - - if (strcmp(p->name, modep->name) == 0) { - - /* Skip over previously rejected modes */ - if (p->status != MODE_OK) { - if (!found) - status = p->status; - continue; - } - - /* Skip over previously considered modes */ - if (p->prev) - continue; - - if (p->type & M_T_BUILTIN) { - return xf86HandleBuiltinMode(scrp, p,modep, clockRanges, - allowDiv2); - } - - /* Check clock is in range */ - cp = xf86FindClockRangeForMode(clockRanges, p); - if (cp == NULL) { - /* - * XXX Could do more here to provide a more detailed - * reason for not finding a mode. - */ - p->status = MODE_CLOCK_RANGE; - if (!found) - status = MODE_CLOCK_RANGE; - continue; - } - - /* - * If programmable clock and strategy is not - * LOOKUP_BEST_REFRESH, the required mode has been found, - * otherwise record the refresh and continue looking. - */ - if (scrp->progClock) { - found = TRUE; - if (strategy != LOOKUP_BEST_REFRESH) { - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - break; - } - refresh = xf86ModeVRefresh(p); - if (p->Flags & V_INTERLACE) - refresh /= INTERLACE_REFRESH_WEIGHT; - if (refresh > bestRefresh) { - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - bestRefresh = refresh; - } - continue; - } - - /* - * Clock is in range, so if it is not a programmable clock, find - * a matching clock. - */ - - i = xf86GetNearestClock(scrp, p->Clock, allowDiv2, - cp->ClockDivFactor, cp->ClockMulFactor, &k); - /* - * If the clock is too far from the requested clock, this - * mode is no good. - */ - if (k & V_CLKDIV2) - gap = abs((p->Clock * 2) - - ((scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor)); - else - gap = abs(p->Clock - - ((scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor)); - if (gap > minimumGap) { - p->status = MODE_NOCLOCK; - if (!found) - status = MODE_NOCLOCK; - continue; - } - found = TRUE; - - if (strategy == LOOKUP_BEST_REFRESH) { - refresh = xf86ModeVRefresh(p); - if (p->Flags & V_INTERLACE) - refresh /= INTERLACE_REFRESH_WEIGHT; - if (refresh > bestRefresh) { - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - extraFlags = k; - clockIndex = i; - bestRefresh = refresh; - } - continue; - } - if (strategy == LOOKUP_CLOSEST_CLOCK) { - if (gap < minimumGap) { - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - extraFlags = k; - clockIndex = i; - minimumGap = gap; - } - continue; - } - /* - * If strategy is neither LOOKUP_BEST_REFRESH or - * LOOKUP_CLOSEST_CLOCK the required mode has been found. - */ - bestMode = p; - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - extraFlags = k; - clockIndex = i; - break; - } - } - if (found) break; - } - if (!found || bestMode == NULL) - return status; - - /* Fill in the mode parameters */ - if (scrp->progClock) { - modep->Clock = bestMode->Clock; - modep->ClockIndex = -1; - modep->SynthClock = (modep->Clock * MulFactor) / DivFactor; - } else { - modep->Clock = (scrp->clock[clockIndex] * DivFactor) / - MulFactor; - modep->ClockIndex = clockIndex; - modep->SynthClock = scrp->clock[clockIndex]; - if (extraFlags & V_CLKDIV2) { - modep->Clock /= 2; - modep->SynthClock /= 2; - } - } - modep->type = bestMode->type; - modep->PrivFlags = ModePrivFlags; - modep->HDisplay = bestMode->HDisplay; - modep->HSyncStart = bestMode->HSyncStart; - modep->HSyncEnd = bestMode->HSyncEnd; - modep->HTotal = bestMode->HTotal; - modep->HSkew = bestMode->HSkew; - modep->VDisplay = bestMode->VDisplay; - modep->VSyncStart = bestMode->VSyncStart; - modep->VSyncEnd = bestMode->VSyncEnd; - modep->VTotal = bestMode->VTotal; - modep->VScan = bestMode->VScan; - modep->Flags = bestMode->Flags | extraFlags; - modep->CrtcHDisplay = bestMode->CrtcHDisplay; - modep->CrtcHBlankStart = bestMode->CrtcHBlankStart; - modep->CrtcHSyncStart = bestMode->CrtcHSyncStart; - modep->CrtcHSyncEnd = bestMode->CrtcHSyncEnd; - modep->CrtcHBlankEnd = bestMode->CrtcHBlankEnd; - modep->CrtcHTotal = bestMode->CrtcHTotal; - modep->CrtcHSkew = bestMode->CrtcHSkew; - modep->CrtcVDisplay = bestMode->CrtcVDisplay; - modep->CrtcVBlankStart = bestMode->CrtcVBlankStart; - modep->CrtcVSyncStart = bestMode->CrtcVSyncStart; - modep->CrtcVSyncEnd = bestMode->CrtcVSyncEnd; - modep->CrtcVBlankEnd = bestMode->CrtcVBlankEnd; - modep->CrtcVTotal = bestMode->CrtcVTotal; - modep->CrtcHAdjusted = bestMode->CrtcHAdjusted; - modep->CrtcVAdjusted = bestMode->CrtcVAdjusted; - modep->HSync = bestMode->HSync; - modep->VRefresh = bestMode->VRefresh; - modep->Private = bestMode->Private; - modep->PrivSize = bestMode->PrivSize; - - bestMode->prev = modep; - - return MODE_OK; -} - -/* - * xf86CheckModeForMonitor - * - * This function takes a mode and monitor description, and determines - * if the mode is valid for the monitor. - */ -ModeStatus -xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor) -{ - int i; - - /* Sanity checks */ - if (mode == NULL || monitor == NULL) { - ErrorF("xf86CheckModeForMonitor: called with invalid parameters\n"); - return MODE_ERROR; - } - - DebugF("xf86CheckModeForMonitor(%p %s, %p %s)\n", - mode, mode->name, monitor, monitor->id); - - /* Some basic mode validity checks */ - if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || - mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) - return MODE_H_ILLEGAL; - - if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || - mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) - return MODE_V_ILLEGAL; - - if (monitor->nHsync > 0) { - /* Check hsync against the allowed ranges */ - float hsync = xf86ModeHSync(mode); - for (i = 0; i < monitor->nHsync; i++) - if ((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) && - (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE))) - break; - - /* Now see whether we ran out of sync ranges without finding a match */ - if (i == monitor->nHsync) - return MODE_HSYNC; - } - - if (monitor->nVrefresh > 0) { - /* Check vrefresh against the allowed ranges */ - float vrefrsh = xf86ModeVRefresh(mode); - for (i = 0; i < monitor->nVrefresh; i++) - if ((vrefrsh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) && - (vrefrsh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE))) - break; - - /* Now see whether we ran out of refresh ranges without finding a match */ - if (i == monitor->nVrefresh) - return MODE_VSYNC; - } - - /* Force interlaced modes to have an odd VTotal */ - if (mode->Flags & V_INTERLACE) - mode->CrtcVTotal = mode->VTotal |= 1; - - /* - * This code stops cvt -r modes, and only cvt -r modes, from hitting 15y+ - * old CRTs which might, when there is a lot of solar flare activity and - * when the celestial bodies are unfavourably aligned, implode trying to - * sync to it. It's called "Protecting the user from doing anything stupid". - * -- libv - */ - - if (xf86ModeIsReduced(mode)) { - if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER)) - return MODE_NO_REDUCED; - } - - if ((monitor->maxPixClock) && (mode->Clock > monitor->maxPixClock)) - return MODE_CLOCK_HIGH; - - return MODE_OK; -} - -/* - * xf86CheckModeSize - * - * An internal routine to check if a mode fits in video memory. This tries to - * avoid overflows that would otherwise occur when video memory size is greater - * than 256MB. - */ -static Bool -xf86CheckModeSize(ScrnInfoPtr scrp, int w, int x, int y) -{ - int bpp = scrp->fbFormat.bitsPerPixel, - pad = scrp->fbFormat.scanlinePad; - int lineWidth, lastWidth; - - if (scrp->depth == 4) - pad *= 4; /* 4 planes */ - - /* Sanity check */ - if ((w < 0) || (x < 0) || (y <= 0)) - return FALSE; - - lineWidth = (((w * bpp) + pad - 1) / pad) * pad; - lastWidth = x * bpp; - - /* - * At this point, we need to compare - * - * (lineWidth * (y - 1)) + lastWidth - * - * against - * - * scrp->videoRam * (1024 * 8) - * - * These are bit quantities. To avoid overflows, do the comparison in - * terms of BITMAP_SCANLINE_PAD units. This assumes BITMAP_SCANLINE_PAD - * is a power of 2. We currently use 32, which limits us to a video - * memory size of 8GB. - */ - - lineWidth = (lineWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; - lastWidth = (lastWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; - - if ((lineWidth * (y - 1) + lastWidth) > - (scrp->videoRam * ((1024 * 8) / BITMAP_SCANLINE_PAD))) - return FALSE; - - return TRUE; -} - -/* - * xf86InitialCheckModeForDriver - * - * This function checks if a mode satisfies a driver's initial requirements: - * - mode size fits within the available pixel area (memory) - * - width lies within the range of supported line pitches - * - mode size fits within virtual size (if fixed) - * - horizontal timings are in range - * - * This function takes the following parameters: - * scrp ScrnInfoPtr - * mode mode to check - * maxPitch (optional) maximum line pitch - * virtualX (optional) virtual width requested - * virtualY (optional) virtual height requested - * - * In addition, the following fields from the ScrnInfoRec are used: - * monitor pointer to structure for monitor section - * fbFormat pixel format for the framebuffer - * videoRam video memory size (in kB) - * maxHValue maximum horizontal timing value - * maxVValue maximum vertical timing value - */ - -ModeStatus -xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, - ClockRangePtr clockRanges, - LookupModeFlags strategy, - int maxPitch, int virtualX, int virtualY) -{ - ClockRangePtr cp; - ModeStatus status; - Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; - int i, needDiv2; - - /* Sanity checks */ - if (!scrp || !mode || !clockRanges) { - ErrorF("xf86InitialCheckModeForDriver: " - "called with invalid parameters\n"); - return MODE_ERROR; - } - - DebugF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n", - scrp, mode, mode->name , clockRanges, strategy, maxPitch, virtualX, virtualY); - - /* Some basic mode validity checks */ - if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || - mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) - return MODE_H_ILLEGAL; - - if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || - mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) - return MODE_V_ILLEGAL; - - if (!xf86CheckModeSize(scrp, mode->HDisplay, mode->HDisplay, - mode->VDisplay)) - return MODE_MEM; - - if (maxPitch > 0 && mode->HDisplay > maxPitch) - return MODE_BAD_WIDTH; - - if (virtualX > 0 && mode->HDisplay > virtualX) - return MODE_VIRTUAL_X; - - if (virtualY > 0 && mode->VDisplay > virtualY) - return MODE_VIRTUAL_Y; - - if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) - return MODE_BAD_HVALUE; - - if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) - return MODE_BAD_VVALUE; - - /* - * The use of the DisplayModeRec's Crtc* and SynthClock elements below is - * provisional, in that they are later reused by the driver at mode-set - * time. Here, they are temporarily enlisted to contain the mode timings - * as seen by the CRT or panel (rather than the CRTC). The driver's - * ValidMode() is allowed to modify these so it can deal with such things - * as mode stretching and/or centering. The driver should >NOT< modify the - * user-supplied values as these are reported back when mode validation is - * said and done. - */ - /* - * NOTE: We (ab)use the mode->Crtc* values here to store timing - * information for the calculation of Hsync and Vrefresh. Before - * these values are calculated the driver is given the opportunity - * to either set these HSync and VRefresh itself or modify the timing - * values. - * The difference to the final calculation is small but imortand: - * here we pass the flag INTERLACE_HALVE_V regardless if the driver - * sets it or not. This way our calculation of VRefresh has the same - * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0 - * This dual use of the mode->Crtc* values will certainly create - * confusion and is bad software design. However since it's part of - * the driver API it's hard to change. - */ - - if (scrp->ValidMode) { - - xf86SetModeCrtc(mode, INTERLACE_HALVE_V); - - cp = xf86FindClockRangeForMode(clockRanges, mode); - if (!cp) - return MODE_CLOCK_RANGE; - - if (cp->ClockMulFactor < 1) - cp->ClockMulFactor = 1; - if (cp->ClockDivFactor < 1) - cp->ClockDivFactor = 1; - - /* - * XXX The effect of clock dividers and multipliers on the monitor's - * pixel clock needs to be verified. - */ - if (scrp->progClock) { - mode->SynthClock = mode->Clock; - } else { - i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2, - cp->ClockDivFactor, cp->ClockMulFactor, - &needDiv2); - mode->SynthClock = (scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor; - if (needDiv2 & V_CLKDIV2) - mode->SynthClock /= 2; - } - - status = (*scrp->ValidMode)(scrp->scrnIndex, mode, FALSE, - MODECHECK_INITIAL); - if (status != MODE_OK) - return status; - - if (mode->HSync <= 0.0) - mode->HSync = (float)mode->SynthClock / (float)mode->CrtcHTotal; - if (mode->VRefresh <= 0.0) - mode->VRefresh = (mode->SynthClock * 1000.0) - / (mode->CrtcHTotal * mode->CrtcVTotal); - } - - mode->HSync = xf86ModeHSync(mode); - mode->VRefresh = xf86ModeVRefresh(mode); - - /* Assume it is OK */ - return MODE_OK; -} - -/* - * xf86CheckModeForDriver - * - * This function is for checking modes while the server is running (for - * use mainly by the VidMode extension). - * - * This function checks if a mode satisfies a driver's requirements: - * - width lies within the line pitch - * - mode size fits within virtual size - * - horizontal/vertical timings are in range - * - * This function takes the following parameters: - * scrp ScrnInfoPtr - * mode mode to check - * flags not (currently) used - * - * In addition, the following fields from the ScrnInfoRec are used: - * maxHValue maximum horizontal timing value - * maxVValue maximum vertical timing value - * virtualX virtual width - * virtualY virtual height - * clockRanges allowable clock ranges - */ - -ModeStatus -xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags) -{ - ClockRangePtr cp; - int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; - int extraFlags = 0; - int clockIndex = -1; - int MulFactor = 1; - int DivFactor = 1; - int ModePrivFlags = 0; - ModeStatus status = MODE_NOMODE; - - /* Some sanity checking */ - if (scrp == NULL || (!scrp->progClock && scrp->numClocks == 0)) { - ErrorF("xf86CheckModeForDriver: called with invalid scrnInfoRec\n"); - return MODE_ERROR; - } - if (mode == NULL) { - ErrorF("xf86CheckModeForDriver: called with invalid modep\n"); - return MODE_ERROR; - } - - /* Check the mode size */ - if (mode->HDisplay > scrp->virtualX) - return MODE_VIRTUAL_X; - - if (mode->VDisplay > scrp->virtualY) - return MODE_VIRTUAL_Y; - - if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) - return MODE_BAD_HVALUE; - - if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) - return MODE_BAD_VVALUE; - - for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { - /* DivFactor and MulFactor must be > 0 */ - cp->ClockDivFactor = max(1, cp->ClockDivFactor); - cp->ClockMulFactor = max(1, cp->ClockMulFactor); - } - - if (scrp->progClock) { - /* Check clock is in range */ - for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { - if (modeInClockRange(cp, mode)) - break; - } - if (cp == NULL) { - return MODE_CLOCK_RANGE; - } - /* - * If programmable clock the required mode has been found - */ - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - } else { - status = MODE_CLOCK_RANGE; - /* Check clock is in range */ - for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { - if (modeInClockRange(cp, mode)) { - /* - * Clock is in range, so if it is not a programmable clock, - * find a matching clock. - */ - - i = xf86GetNearestClock(scrp, mode->Clock, 0, - cp->ClockDivFactor, cp->ClockMulFactor, &k); - /* - * If the clock is too far from the requested clock, this - * mode is no good. - */ - if (k & V_CLKDIV2) - gap = abs((mode->Clock * 2) - - ((scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor)); - else - gap = abs(mode->Clock - - ((scrp->clock[i] * cp->ClockDivFactor) / - cp->ClockMulFactor)); - if (gap > minimumGap) { - status = MODE_NOCLOCK; - continue; - } - - DivFactor = cp->ClockDivFactor; - MulFactor = cp->ClockMulFactor; - ModePrivFlags = cp->PrivFlags; - extraFlags = k; - clockIndex = i; - break; - } - } - if (cp == NULL) - return status; - } - - /* Fill in the mode parameters */ - if (scrp->progClock) { - mode->ClockIndex = -1; - mode->SynthClock = (mode->Clock * MulFactor) / DivFactor; - } else { - mode->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor; - mode->ClockIndex = clockIndex; - mode->SynthClock = scrp->clock[clockIndex]; - if (extraFlags & V_CLKDIV2) { - mode->Clock /= 2; - mode->SynthClock /= 2; - } - } - mode->PrivFlags = ModePrivFlags; - - return MODE_OK; -} - -static int -inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy) -{ - float aspect = 0.0; - MonPtr mon = scrp->monitor; - xf86MonPtr DDC; - int x = 0, y = 0; - DisplayModePtr mode; - - if (!mon) return 0; - DDC = mon->DDC; - - if (DDC && DDC->ver.revision >= 4) { - /* For 1.4, we might actually get native pixel format. How novel. */ - if (PREFERRED_TIMING_MODE(DDC->features.msc)) { - for (mode = modes; mode; mode = mode->next) { - if (mode->type & (M_T_DRIVER | M_T_PREFERRED)) { - x = mode->HDisplay; - y = mode->VDisplay; - goto found; - } - } - } - /* - * Even if we don't, we might get aspect ratio from extra CVT info - * or from the monitor size fields. TODO. - */ - } - - /* - * Technically this triggers if either is zero. That wasn't legal - * before EDID 1.4, but right now we'll get that wrong. TODO. - */ - if (!aspect) { - if (!mon->widthmm || !mon->heightmm) - aspect = 4.0/3.0; - else - aspect = (float)mon->widthmm / (float)mon->heightmm; - } - - /* find the largest M_T_DRIVER mode with that aspect ratio */ - for (mode = modes; mode; mode = mode->next) { - float mode_aspect, metaspect; - if (!(mode->type & (M_T_DRIVER|M_T_USERDEF))) - continue; - mode_aspect = (float)mode->HDisplay / (float)mode->VDisplay; - metaspect = aspect / mode_aspect; - /* 5% slop or so, since we only get size in centimeters */ - if (fabs(1.0 - metaspect) < 0.05) { - if ((mode->HDisplay > x) && (mode->VDisplay > y)) { - x = mode->HDisplay; - y = mode->VDisplay; - } - } - } - - if (!x || !y) { - xf86DrvMsg(scrp->scrnIndex, X_WARNING, - "Unable to estimate virtual size\n"); - return 0; - } - -found: - *vx = x; - *vy = y; - - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "Estimated virtual size for aspect ratio %.4f is %dx%d\n", - aspect, *vx, *vy); - - return 1; -} - -/* Least common multiple */ -static unsigned int -LCM(unsigned int x, unsigned int y) -{ - unsigned int m = x, n = y, o; - - while ((o = m % n)) - { - m = n; - n = o; - } - - return (x / n) * y; -} - -/* - * Given various screen attributes, determine the minimum scanline width such - * that each scanline is server and DDX padded and any pixels with imbedded - * bank boundaries are off-screen. This function returns -1 if such a width - * cannot exist. - */ -static int -scanLineWidth( - unsigned int xsize, /* pixels */ - unsigned int ysize, /* pixels */ - unsigned int width, /* pixels */ - unsigned long BankSize, /* char's */ - PixmapFormatRec *pBankFormat, - unsigned int nWidthUnit /* bits */ -) -{ - unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit; - unsigned long minBitsPerScanline, maxBitsPerScanline; - - /* Sanity checks */ - - if (!nWidthUnit || !pBankFormat) - return -1; - - nBitsPerBank = BankSize * 8; - if (nBitsPerBank % pBankFormat->scanlinePad) - return -1; - - if (xsize > width) - width = xsize; - nBitsPerScanlinePadUnit = LCM(pBankFormat->scanlinePad, nWidthUnit); - nBitsPerScanline = - (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) / - nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit; - width = nBitsPerScanline / pBankFormat->bitsPerPixel; - - if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel)) - return (int)width; - - /* - * Scanlines will be server-pad aligned at this point. They will also be - * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded - * bank boundaries are off-screen. - * - * It seems reasonable to limit total frame buffer size to 1/16 of the - * theoretical maximum address space size. On a machine with 32-bit - * addresses (to 8-bit quantities) this turns out to be 256MB. Not only - * does this provide a simple limiting condition for the loops below, but - * it also prevents unsigned long wraparounds. - */ - if (!ysize) - return -1; - - minBitsPerScanline = xsize * pBankFormat->bitsPerPixel; - if (minBitsPerScanline > nBitsPerBank) - return -1; - - if (ysize == 1) - return (int)width; - - maxBitsPerScanline = - (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1); - while (nBitsPerScanline <= maxBitsPerScanline) - { - unsigned long BankBase, BankUnit; - - BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) * - nBitsPerBank; - if (!(BankUnit % nBitsPerScanline)) - return (int)width; - - for (BankBase = BankUnit; ; BankBase += nBitsPerBank) - { - unsigned long x, y; - - y = BankBase / nBitsPerScanline; - if (y >= ysize) - return (int)width; - - x = BankBase % nBitsPerScanline; - if (!(x % pBankFormat->bitsPerPixel)) - continue; - - if (x < minBitsPerScanline) - { - /* - * Skip ahead certain widths by dividing the excess scanline - * amongst the y's. - */ - y *= nBitsPerScanlinePadUnit; - nBitsPerScanline += - ((x + y - 1) / y) * nBitsPerScanlinePadUnit; - width = nBitsPerScanline / pBankFormat->bitsPerPixel; - break; - } - - if (BankBase != BankUnit) - continue; - - if (!(nBitsPerScanline % x)) - return (int)width; - - BankBase = ((nBitsPerScanline - minBitsPerScanline) / - (nBitsPerScanline - x)) * BankUnit; - } - } - - return -1; -} - -/* - * xf86ValidateModes - * - * This function takes a set of mode names, modes and limiting conditions, - * and selects a set of modes and parameters based on those conditions. - * - * This function takes the following parameters: - * scrp ScrnInfoPtr - * availModes the list of modes available for the monitor - * modeNames (optional) list of mode names that the screen is requesting - * clockRanges a list of clock ranges - * linePitches (optional) a list of line pitches - * minPitch (optional) minimum line pitch (in pixels) - * maxPitch (optional) maximum line pitch (in pixels) - * pitchInc (mandatory) pitch increment (in bits) - * minHeight (optional) minimum virtual height (in pixels) - * maxHeight (optional) maximum virtual height (in pixels) - * virtualX (optional) virtual width requested (in pixels) - * virtualY (optional) virtual height requested (in pixels) - * apertureSize size of video aperture (in bytes) - * strategy how to decide which mode to use from multiple modes with - * the same name - * - * In addition, the following fields from the ScrnInfoRec are used: - * clocks a list of discrete clocks - * numClocks number of discrete clocks - * progClock clock is programmable - * monitor pointer to structure for monitor section - * fbFormat format of the framebuffer - * videoRam video memory size - * maxHValue maximum horizontal timing value - * maxVValue maximum vertical timing value - * xInc horizontal timing increment (defaults to 8 pixels) - * - * The function fills in the following ScrnInfoRec fields: - * modePool A subset of the modes available to the monitor which - * are compatible with the driver. - * modes one mode entry for each of the requested modes, with the - * status field filled in to indicate if the mode has been - * accepted or not. - * virtualX the resulting virtual width - * virtualY the resulting virtual height - * displayWidth the resulting line pitch - * - * The function's return value is the number of matching modes found, or -1 - * if an unrecoverable error was encountered. - */ - -int -xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, - char **modeNames, ClockRangePtr clockRanges, - int *linePitches, int minPitch, int maxPitch, int pitchInc, - int minHeight, int maxHeight, int virtualX, int virtualY, - int apertureSize, LookupModeFlags strategy) -{ - DisplayModePtr p, q, r, new, last, *endp; - int i, numModes = 0; - ModeStatus status; - int linePitch = -1, virtX = 0, virtY = 0; - int newLinePitch, newVirtX, newVirtY; - int modeSize; /* in pixels */ - Bool validateAllDefaultModes = FALSE; - Bool userModes = FALSE; - int saveType; - PixmapFormatRec *BankFormat; - ClockRangePtr cp; - ClockRangePtr storeClockRanges; - int numTimings = 0; - range hsync[MAX_HSYNC]; - range vrefresh[MAX_VREFRESH]; - Bool inferred_virtual = FALSE; - - DebugF("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n", - scrp, availModes, modeNames, clockRanges, - linePitches, minPitch, maxPitch, pitchInc, - minHeight, maxHeight, virtualX, virtualY, - apertureSize, strategy - ); - - /* Some sanity checking */ - if (scrp == NULL || scrp->name == NULL || !scrp->monitor || - (!scrp->progClock && scrp->numClocks == 0)) { - ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n"); - return -1; - } - if (linePitches != NULL && linePitches[0] <= 0) { - ErrorF("xf86ValidateModes: called with invalid linePitches\n"); - return -1; - } - if (pitchInc <= 0) { - ErrorF("xf86ValidateModes: called with invalid pitchInc\n"); - return -1; - } - if ((virtualX > 0) != (virtualY > 0)) { - ErrorF("xf86ValidateModes: called with invalid virtual resolution\n"); - return -1; - } - - /* - * If requested by the driver, allow missing hsync and/or vrefresh ranges - * in the monitor section. - */ - if (strategy & LOOKUP_OPTIONAL_TOLERANCES) { - strategy &= ~LOOKUP_OPTIONAL_TOLERANCES; - } else { - const char *type = ""; - - if (scrp->monitor->nHsync <= 0) { - if (numTimings > 0) { - scrp->monitor->nHsync = numTimings; - for (i = 0; i < numTimings; i++) { - scrp->monitor->hsync[i].lo = hsync[i].lo; - scrp->monitor->hsync[i].hi = hsync[i].hi; - } - } else { - scrp->monitor->hsync[0].lo = 31.5; - scrp->monitor->hsync[0].hi = 37.9; - scrp->monitor->nHsync = 1; - } - type = "default "; - } - for (i = 0; i < scrp->monitor->nHsync; i++) { - if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi) - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using %shsync value of %.2f kHz\n", - scrp->monitor->id, type, - scrp->monitor->hsync[i].lo); - else - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using %shsync range of %.2f-%.2f kHz\n", - scrp->monitor->id, type, - scrp->monitor->hsync[i].lo, - scrp->monitor->hsync[i].hi); - } - - type = ""; - if (scrp->monitor->nVrefresh <= 0) { - if (numTimings > 0) { - scrp->monitor->nVrefresh = numTimings; - for (i = 0; i < numTimings; i++) { - scrp->monitor->vrefresh[i].lo = vrefresh[i].lo; - scrp->monitor->vrefresh[i].hi = vrefresh[i].hi; - } - } else { - scrp->monitor->vrefresh[0].lo = 50; - scrp->monitor->vrefresh[0].hi = 70; - scrp->monitor->nVrefresh = 1; - } - type = "default "; - } - for (i = 0; i < scrp->monitor->nVrefresh; i++) { - if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi) - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using %svrefresh value of %.2f Hz\n", - scrp->monitor->id, type, - scrp->monitor->vrefresh[i].lo); - else - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using %svrefresh range of %.2f-%.2f Hz\n", - scrp->monitor->id, type, - scrp->monitor->vrefresh[i].lo, - scrp->monitor->vrefresh[i].hi); - } - if (scrp->monitor->maxPixClock) { - xf86DrvMsg(scrp->scrnIndex, X_INFO, - "%s: Using maximum pixel clock of %.2f MHz\n", - scrp->monitor->id, - (float)scrp->monitor->maxPixClock / 1000.0); - } - } - - /* - * Store the clockRanges for later use by the VidMode extension. - */ - storeClockRanges = scrp->clockRanges; - while (storeClockRanges != NULL) { - storeClockRanges = storeClockRanges->next; - } - for (cp = clockRanges; cp != NULL; cp = cp->next, - storeClockRanges = storeClockRanges->next) { - storeClockRanges = xnfalloc(sizeof(ClockRange)); - if (scrp->clockRanges == NULL) - scrp->clockRanges = storeClockRanges; - memcpy(storeClockRanges, cp, sizeof(ClockRange)); - } - - /* Determine which pixmap format to pass to scanLineWidth() */ - if (scrp->depth > 4) - BankFormat = &scrp->fbFormat; - else - BankFormat = xf86GetPixFormat(scrp, 1); /* >not< scrp->depth! */ - - if (scrp->xInc <= 0) - scrp->xInc = 8; /* Suitable for VGA and others */ - -#define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc) - - /* - * Determine maxPitch if it wasn't given explicitly. Note linePitches - * always takes precedence if is non-NULL. In that case the minPitch and - * maxPitch values passed are ignored. - */ - if (linePitches) { - minPitch = maxPitch = linePitches[0]; - for (i = 1; linePitches[i] > 0; i++) { - if (linePitches[i] > maxPitch) - maxPitch = linePitches[i]; - if (linePitches[i] < minPitch) - minPitch = linePitches[i]; - } - } - - /* Initial check of virtual size against other constraints */ - scrp->virtualFrom = X_PROBED; - /* - * Initialise virtX and virtY if the values are fixed. - */ - if (virtualY > 0) { - if (maxHeight > 0 && virtualY > maxHeight) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual height (%d) is too large for the hardware " - "(max %d)\n", virtualY, maxHeight); - return -1; - } - - if (minHeight > 0 && virtualY < minHeight) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual height (%d) is too small for the hardware " - "(min %d)\n", virtualY, minHeight); - return -1; - } - - virtualX = _VIRTUALX(virtualX); - if (linePitches != NULL) { - for (i = 0; linePitches[i] != 0; i++) { - if ((linePitches[i] >= virtualX) && - (linePitches[i] == - scanLineWidth(virtualX, virtualY, linePitches[i], - apertureSize, BankFormat, pitchInc))) { - linePitch = linePitches[i]; - break; - } - } - } else { - linePitch = scanLineWidth(virtualX, virtualY, minPitch, - apertureSize, BankFormat, pitchInc); - } - - if ((linePitch < minPitch) || (linePitch > maxPitch)) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual width (%d) is too large for the hardware " - "(max %d)\n", virtualX, maxPitch); - return -1; - } - - if (!xf86CheckModeSize(scrp, linePitch, virtualX, virtualY)) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual size (%dx%d) (pitch %d) exceeds video memory\n", - virtualX, virtualY, linePitch); - return -1; - } - - virtX = virtualX; - virtY = virtualY; - scrp->virtualFrom = X_CONFIG; - } else if (!modeNames || !*modeNames) { - /* No virtual size given in the config, try to infer */ - /* XXX this doesn't take m{in,ax}Pitch into account; oh well */ - inferred_virtual = inferVirtualSize(scrp, availModes, &virtX, &virtY); - if (inferred_virtual) - linePitch = scanLineWidth(virtX, virtY, minPitch, apertureSize, - BankFormat, pitchInc); - } - - /* Print clock ranges and scaled clocks */ - xf86ShowClockRanges(scrp, clockRanges); - - /* - * If scrp->modePool hasn't been setup yet, set it up now. This allows the - * modes that the driver definitely can't use to be weeded out early. Note - * that a modePool mode's prev field is used to hold a pointer to the - * member of the scrp->modes list for which a match was considered. - */ - if (scrp->modePool == NULL) { - q = NULL; - for (p = availModes; p != NULL; p = p->next) { - status = xf86InitialCheckModeForDriver(scrp, p, clockRanges, - strategy, maxPitch, - virtX, virtY); - - if (status == MODE_OK) { - status = xf86CheckModeForMonitor(p, scrp->monitor); - } - - if (status == MODE_OK) { - new = xnfalloc(sizeof(DisplayModeRec)); - *new = *p; - new->next = NULL; - if (!q) { - scrp->modePool = new; - } else { - q->next = new; - } - new->prev = NULL; - q = new; - q->name = xnfstrdup(p->name); - q->status = MODE_OK; - } else { - printModeRejectMessage(scrp->scrnIndex, p, status); - } - } - - if (scrp->modePool == NULL) { - xf86DrvMsg(scrp->scrnIndex, X_WARNING, "Mode pool is empty\n"); - return 0; - } - } else { - for (p = scrp->modePool; p != NULL; p = p->next) { - p->prev = NULL; - p->status = MODE_OK; - } - } - - /* - * Allocate one entry in scrp->modes for each named mode. - */ - while (scrp->modes) - xf86DeleteMode(&scrp->modes, scrp->modes); - endp = &scrp->modes; - last = NULL; - if (modeNames != NULL) { - for (i = 0; modeNames[i] != NULL; i++) { - userModes = TRUE; - new = xnfcalloc(1, sizeof(DisplayModeRec)); - new->prev = last; - new->type = M_T_USERDEF; - new->name = xnfalloc(strlen(modeNames[i]) + 1); - strcpy(new->name, modeNames[i]); - if (new->prev) - new->prev->next = new; - *endp = last = new; - endp = &new->next; - } - } - - /* Lookup each mode */ -#ifdef RANDR - if (!xf86Info.disableRandR -#ifdef PANORAMIX - && noPanoramiXExtension -#endif - ) - validateAllDefaultModes = TRUE; -#endif - - for (p = scrp->modes; ; p = p->next) { - Bool repeat; - - /* - * If the supplied mode names don't produce a valid mode, scan through - * unconsidered modePool members until one survives validation. This - * is done in decreasing order by mode pixel area. - */ - - if (p == NULL) { - if ((numModes > 0) && !validateAllDefaultModes) - break; - - validateAllDefaultModes = TRUE; - r = NULL; - modeSize = 0; - for (q = scrp->modePool; q != NULL; q = q->next) { - if ((q->prev == NULL) && (q->status == MODE_OK)) { - /* - * Deal with the case where this mode wasn't considered - * because of a builtin mode of the same name. - */ - for (p = scrp->modes; p != NULL; p = p->next) { - if ((p->status != MODE_OK) && - !strcmp(p->name, q->name)) - break; - } - - if (p != NULL) - q->prev = p; - else { - /* - * A quick check to not allow default modes with - * horizontal timing parameters that CRTs may have - * problems with. - */ - if (!scrp->monitor->reducedblanking && - (q->type & M_T_DEFAULT) && - ((double)q->HTotal / (double)q->HDisplay) < 1.15) - continue; - - if (modeSize < (q->HDisplay * q->VDisplay)) { - r = q; - modeSize = q->HDisplay * q->VDisplay; - } - } - } - } - - if (r == NULL) - break; - - p = xnfcalloc(1, sizeof(DisplayModeRec)); - p->prev = last; - p->name = xnfalloc(strlen(r->name) + 1); - if (!userModes) - p->type = M_T_USERDEF; - strcpy(p->name, r->name); - if (p->prev) - p->prev->next = p; - *endp = last = p; - endp = &p->next; - } - - repeat = FALSE; - lookupNext: - if (repeat && ((status = p->status) != MODE_OK)) - printModeRejectMessage(scrp->scrnIndex, p, status); - saveType = p->type; - status = xf86LookupMode(scrp, p, clockRanges, strategy); - if (repeat && status == MODE_NOMODE) - continue; - if (status != MODE_OK) - printModeRejectMessage(scrp->scrnIndex, p, status); - if (status == MODE_ERROR) { - ErrorF("xf86ValidateModes: " - "unexpected result from xf86LookupMode()\n"); - return -1; - } - if (status != MODE_OK) { - if (p->status == MODE_OK) - p->status = status; - continue; - } - p->type |= saveType; - repeat = TRUE; - - newLinePitch = linePitch; - newVirtX = virtX; - newVirtY = virtY; - - /* - * Don't let non-user defined modes increase the virtual size - */ - if (!(p->type & M_T_USERDEF) && (numModes > 0)) { - if (p->HDisplay > virtX) { - p->status = MODE_VIRTUAL_X; - goto lookupNext; - } - if (p->VDisplay > virtY) { - p->status = MODE_VIRTUAL_Y; - goto lookupNext; - } - } - /* - * Adjust virtual width and height if the mode is too large for the - * current values and if they are not fixed. - */ - if (virtualX <= 0 && p->HDisplay > newVirtX) - newVirtX = _VIRTUALX(p->HDisplay); - if (virtualY <= 0 && p->VDisplay > newVirtY) { - if (maxHeight > 0 && p->VDisplay > maxHeight) { - p->status = MODE_VIRTUAL_Y; /* ? */ - goto lookupNext; - } - newVirtY = p->VDisplay; - } - - /* - * If virtual resolution is to be increased, revalidate it. - */ - if ((virtX != newVirtX) || (virtY != newVirtY)) { - if (linePitches != NULL) { - newLinePitch = -1; - for (i = 0; linePitches[i] != 0; i++) { - if ((linePitches[i] >= newVirtX) && - (linePitches[i] >= linePitch) && - (linePitches[i] == - scanLineWidth(newVirtX, newVirtY, linePitches[i], - apertureSize, BankFormat, pitchInc))) { - newLinePitch = linePitches[i]; - break; - } - } - } else { - if (linePitch < minPitch) - linePitch = minPitch; - newLinePitch = scanLineWidth(newVirtX, newVirtY, linePitch, - apertureSize, BankFormat, - pitchInc); - } - if ((newLinePitch < minPitch) || (newLinePitch > maxPitch)) { - p->status = MODE_BAD_WIDTH; - goto lookupNext; - } - - /* - * Check that the pixel area required by the new virtual height - * and line pitch isn't too large. - */ - if (!xf86CheckModeSize(scrp, newLinePitch, newVirtX, newVirtY)) { - p->status = MODE_MEM_VIRT; - goto lookupNext; - } - } - - if (scrp->ValidMode) { - /* - * Give the driver a final say, passing it the proposed virtual - * geometry. - */ - scrp->virtualX = newVirtX; - scrp->virtualY = newVirtY; - scrp->displayWidth = newLinePitch; - p->status = (scrp->ValidMode)(scrp->scrnIndex, p, FALSE, - MODECHECK_FINAL); - - if (p->status != MODE_OK) { - goto lookupNext; - } - } - - /* Mode has passed all the tests */ - virtX = newVirtX; - virtY = newVirtY; - linePitch = newLinePitch; - p->status = MODE_OK; - numModes++; - } - -#undef _VIRTUALX - - /* - * If we estimated the virtual size above, we may have filtered away all - * the modes that maximally match that size; scan again to find out and - * fix up if so. - */ - if (inferred_virtual) { - int vx = 0, vy = 0; - for (p = scrp->modes; p; p = p->next) { - if (p->HDisplay > vx && p->VDisplay > vy) { - vx = p->HDisplay; - vy = p->VDisplay; - } - } - if (vx < virtX || vy < virtY) { - xf86DrvMsg(scrp->scrnIndex, X_WARNING, - "Shrinking virtual size estimate from %dx%d to %dx%d\n", - virtX, virtY, vx, vy); - virtX = vx; - virtY = vy; - linePitch = scanLineWidth(vx, vy, minPitch, apertureSize, - BankFormat, pitchInc); - } - } - - /* Update the ScrnInfoRec parameters */ - - scrp->virtualX = virtX; - scrp->virtualY = virtY; - scrp->displayWidth = linePitch; - - if (numModes <= 0) - return 0; - - /* Make the mode list into a circular list by joining up the ends */ - p = scrp->modes; - while (p->next != NULL) - p = p->next; - /* p is now the last mode on the list */ - p->next = scrp->modes; - scrp->modes->prev = p; - - if (minHeight > 0 && virtY < minHeight) { - xf86DrvMsg(scrp->scrnIndex, X_ERROR, - "Virtual height (%d) is too small for the hardware " - "(min %d)\n", virtY, minHeight); - return -1; - } - - return numModes; -} - -/* - * xf86DeleteMode - * - * This function removes a mode from a list of modes. - * - * There are different types of mode lists: - * - * - singly linked linear lists, ending in NULL - * - doubly linked linear lists, starting and ending in NULL - * - doubly linked circular lists - * - */ - -void -xf86DeleteMode(DisplayModePtr *modeList, DisplayModePtr mode) -{ - /* Catch the easy/insane cases */ - if (modeList == NULL || *modeList == NULL || mode == NULL) - return; - - /* If the mode is at the start of the list, move the start of the list */ - if (*modeList == mode) - *modeList = mode->next; - - /* If mode is the only one on the list, set the list to NULL */ - if ((mode == mode->prev) && (mode == mode->next)) { - *modeList = NULL; - } else { - if ((mode->prev != NULL) && (mode->prev->next == mode)) - mode->prev->next = mode->next; - if ((mode->next != NULL) && (mode->next->prev == mode)) - mode->next->prev = mode->prev; - } - - xfree(mode->name); - xfree(mode); -} - -/* - * xf86PruneDriverModes - * - * Remove modes from the driver's mode list which have been marked as - * invalid. - */ - -void -xf86PruneDriverModes(ScrnInfoPtr scrp) -{ - DisplayModePtr first, p, n; - - p = scrp->modes; - if (p == NULL) - return; - - do { - if (!(first = scrp->modes)) - return; - n = p->next; - if (p->status != MODE_OK) { - xf86DeleteMode(&(scrp->modes), p); - } - p = n; - } while (p != NULL && p != first); - - /* modePool is no longer needed, turf it */ - while (scrp->modePool) { - /* - * A modePool mode's prev field is used to hold a pointer to the - * member of the scrp->modes list for which a match was considered. - * Clear that pointer first, otherwise xf86DeleteMode might get - * confused - */ - scrp->modePool->prev = NULL; - xf86DeleteMode(&scrp->modePool, scrp->modePool); - } -} - - -/* - * xf86SetCrtcForModes - * - * Goes through the screen's mode list, and initialises the Crtc - * parameters for each mode. The initialisation includes adjustments - * for interlaced and double scan modes. - */ -void -xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags) -{ - DisplayModePtr p; - - /* - * Store adjustFlags for use with the VidMode extension. There is an - * implicit assumption here that SetCrtcForModes is called once. - */ - scrp->adjustFlags = adjustFlags; - - p = scrp->modes; - if (p == NULL) - return; - - do { - xf86SetModeCrtc(p, adjustFlags); - DebugF("%sMode %s: %d (%d) %d %d (%d) %d %d (%d) %d %d (%d) %d\n", - (p->type & M_T_DEFAULT) ? "Default " : "", - p->name, p->CrtcHDisplay, p->CrtcHBlankStart, - p->CrtcHSyncStart, p->CrtcHSyncEnd, p->CrtcHBlankEnd, - p->CrtcHTotal, p->CrtcVDisplay, p->CrtcVBlankStart, - p->CrtcVSyncStart, p->CrtcVSyncEnd, p->CrtcVBlankEnd, - p->CrtcVTotal); - p = p->next; - } while (p != NULL && p != scrp->modes); -} - -void -xf86PrintModes(ScrnInfoPtr scrp) -{ - DisplayModePtr p; - float hsync, refresh = 0; - char *desc, *desc2, *prefix, *uprefix; - - if (scrp == NULL) - return; - - xf86DrvMsg(scrp->scrnIndex, scrp->virtualFrom, "Virtual size is %dx%d " - "(pitch %d)\n", scrp->virtualX, scrp->virtualY, - scrp->displayWidth); - - p = scrp->modes; - if (p == NULL) - return; - - do { - desc = desc2 = ""; - hsync = xf86ModeHSync(p); - refresh = xf86ModeVRefresh(p); - if (p->Flags & V_INTERLACE) { - desc = " (I)"; - } - if (p->Flags & V_DBLSCAN) { - desc = " (D)"; - } - if (p->VScan > 1) { - desc2 = " (VScan)"; - } - if (p->type & M_T_BUILTIN) - prefix = "Built-in mode"; - else if (p->type & M_T_DEFAULT) - prefix = "Default mode"; - else if (p->type & M_T_DRIVER) - prefix = "Driver mode"; - else - prefix = "Mode"; - if (p->type & M_T_USERDEF) - uprefix = "*"; - else - uprefix = " "; - if (hsync == 0 || refresh == 0) { - if (p->name) - xf86DrvMsg(scrp->scrnIndex, X_CONFIG, - "%s%s \"%s\"\n", uprefix, prefix, p->name); - else - xf86DrvMsg(scrp->scrnIndex, X_PROBED, - "%s%s %dx%d (unnamed)\n", - uprefix, prefix, p->HDisplay, p->VDisplay); - } else if (p->Clock == p->SynthClock) { - xf86DrvMsg(scrp->scrnIndex, X_CONFIG, - "%s%s \"%s\": %.1f MHz, %.1f kHz, %.1f Hz%s%s\n", - uprefix, prefix, p->name, p->Clock / 1000.0, - hsync, refresh, desc, desc2); - } else { - xf86DrvMsg(scrp->scrnIndex, X_CONFIG, - "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), " - "%.1f kHz, %.1f Hz%s%s\n", - uprefix, prefix, p->name, p->Clock / 1000.0, - p->SynthClock / 1000.0, hsync, refresh, desc, desc2); - } - if (hsync != 0 && refresh != 0) - xf86PrintModeline(scrp->scrnIndex,p); - p = p->next; - } while (p != NULL && p != scrp->modes); -} +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * LCM() and scanLineWidth() are: + * + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + * + * Copyright 1990,91,92,93 by Thomas Roell, Germany. + * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA. + * + * 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 Thomas Roell nor + * SGCS be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Thomas Roell nor SGCS makes no representations about the suitability + * of this software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS 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. + */ + +/* + * Authors: Dirk Hohndel <hohndel@XFree86.Org> + * David Dawes <dawes@XFree86.Org> + * Marc La France <tsi@XFree86.Org> + * ... and others + * + * This file includes helper functions for mode related things. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "xf86Modes.h" +#include "os.h" +#include "servermd.h" +#include "globals.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "edid.h" + +static void +printModeRejectMessage(int index, DisplayModePtr p, int status) +{ + char *type; + + if (p->type & M_T_BUILTIN) + type = "built-in "; + else if (p->type & M_T_DEFAULT) + type = "default "; + else if (p->type & M_T_DRIVER) + type = "driver "; + else + type = ""; + + xf86DrvMsg(index, X_INFO, "Not using %smode \"%s\" (%s)\n", type, p->name, + xf86ModeStatusToString(status)); +} + +/* + * xf86GetNearestClock -- + * Find closest clock to given frequency (in kHz). This assumes the + * number of clocks is greater than zero. + */ +int +xf86GetNearestClock(ScrnInfoPtr scrp, int freq, Bool allowDiv2, + int DivFactor, int MulFactor, int *divider) +{ + int nearestClock = 0, nearestDiv = 1; + int minimumGap = abs(freq - scrp->clock[0]); + int i, j, k, gap; + + if (allowDiv2) + k = 2; + else + k = 1; + + /* Must set this here in case the best match is scrp->clock[0] */ + if (divider != NULL) + *divider = 0; + + for (i = 0; i < scrp->numClocks; i++) { + for (j = 1; j <= k; j++) { + gap = abs((freq * j) - ((scrp->clock[i] * DivFactor) / MulFactor)); + if ((gap < minimumGap) || + ((gap == minimumGap) && (j < nearestDiv))) { + minimumGap = gap; + nearestClock = i; + nearestDiv = j; + if (divider != NULL) + *divider = (j - 1) * V_CLKDIV2; + } + } + } + return nearestClock; +} + +/* + * xf86ModeStatusToString + * + * Convert a ModeStatus value to a printable message + */ + +const char * +xf86ModeStatusToString(ModeStatus status) +{ + switch (status) { + case MODE_OK: + return "Mode OK"; + case MODE_HSYNC: + return "hsync out of range"; + case MODE_VSYNC: + return "vrefresh out of range"; + case MODE_H_ILLEGAL: + return "illegal horizontal timings"; + case MODE_V_ILLEGAL: + return "illegal vertical timings"; + case MODE_BAD_WIDTH: + return "width requires unsupported line pitch"; + case MODE_NOMODE: + return "no mode of this name"; + case MODE_NO_INTERLACE: + return "interlace mode not supported"; + case MODE_NO_DBLESCAN: + return "doublescan mode not supported"; + case MODE_NO_VSCAN: + return "multiscan mode not supported"; + case MODE_MEM: + return "insufficient memory for mode"; + case MODE_VIRTUAL_X: + return "width too large for virtual size"; + case MODE_VIRTUAL_Y: + return "height too large for virtual size"; + case MODE_MEM_VIRT: + return "insufficient memory given virtual size"; + case MODE_NOCLOCK: + return "no clock available for mode"; + case MODE_CLOCK_HIGH: + return "mode clock too high"; + case MODE_CLOCK_LOW: + return "mode clock too low"; + case MODE_CLOCK_RANGE: + return "bad mode clock/interlace/doublescan"; + case MODE_BAD_HVALUE: + return "horizontal timing out of range"; + case MODE_BAD_VVALUE: + return "vertical timing out of range"; + case MODE_BAD_VSCAN: + return "VScan value out of range"; + case MODE_HSYNC_NARROW: + return "horizontal sync too narrow"; + case MODE_HSYNC_WIDE: + return "horizontal sync too wide"; + case MODE_HBLANK_NARROW: + return "horizontal blanking too narrow"; + case MODE_HBLANK_WIDE: + return "horizontal blanking too wide"; + case MODE_VSYNC_NARROW: + return "vertical sync too narrow"; + case MODE_VSYNC_WIDE: + return "vertical sync too wide"; + case MODE_VBLANK_NARROW: + return "vertical blanking too narrow"; + case MODE_VBLANK_WIDE: + return "vertical blanking too wide"; + case MODE_PANEL: + return "exceeds panel dimensions"; + case MODE_INTERLACE_WIDTH: + return "width too large for interlaced mode"; + case MODE_ONE_WIDTH: + return "all modes must have the same width"; + case MODE_ONE_HEIGHT: + return "all modes must have the same height"; + case MODE_ONE_SIZE: + return "all modes must have the same resolution"; + case MODE_NO_REDUCED: + return "monitor doesn't support reduced blanking"; + case MODE_BANDWIDTH: + return "mode requires too much memory bandwidth"; + case MODE_BAD: + return "unknown reason"; + case MODE_ERROR: + return "internal error"; + default: + return "unknown"; + } +} + +/* + * xf86ShowClockRanges() -- Print the clock ranges allowed + * and the clock values scaled by ClockMulFactor and ClockDivFactor + */ +void +xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges) +{ + ClockRangePtr cp; + int MulFactor = 1; + int DivFactor = 1; + int i, j; + int scaledClock; + + for (cp = clockRanges; cp != NULL; cp = cp->next) { + DivFactor = max(1, cp->ClockDivFactor); + MulFactor = max(1, cp->ClockMulFactor); + if (scrp->progClock) { + if (cp->minClock) { + if (cp->maxClock) { + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Clock range: %6.2f to %6.2f MHz\n", + (double)cp->minClock / 1000.0, + (double)cp->maxClock / 1000.0); + } else { + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Minimum clock: %6.2f MHz\n", + (double)cp->minClock / 1000.0); + } + } else { + if (cp->maxClock) { + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Maximum clock: %6.2f MHz\n", + (double)cp->maxClock / 1000.0); + } + } + } else if (DivFactor > 1 || MulFactor > 1) { + j = 0; + for (i = 0; i < scrp->numClocks; i++) { + scaledClock = (scrp->clock[i] * DivFactor) / MulFactor; + if (scaledClock >= cp->minClock && scaledClock <= cp->maxClock) { + if ((j % 8) == 0) { + if (j > 0) + xf86ErrorF("\n"); + xf86DrvMsg(scrp->scrnIndex, X_INFO, "scaled clocks:"); + } + xf86ErrorF(" %6.2f", (double)scaledClock / 1000.0); + j++; + } + } + xf86ErrorF("\n"); + } + } +} + +static Bool +modeInClockRange(ClockRangePtr cp, DisplayModePtr p) +{ + return ((p->Clock >= cp->minClock) && + (p->Clock <= cp->maxClock) && + (cp->interlaceAllowed || !(p->Flags & V_INTERLACE)) && + (cp->doubleScanAllowed || + ((p->VScan <= 1) && !(p->Flags & V_DBLSCAN)))); +} + +/* + * xf86FindClockRangeForMode() [... like the name says ...] + */ +static ClockRangePtr +xf86FindClockRangeForMode(ClockRangePtr clockRanges, DisplayModePtr p) +{ + ClockRangePtr cp; + + for (cp = clockRanges; ; cp = cp->next) + if (!cp || modeInClockRange(cp, p)) + return cp; +} + + +/* + * xf86HandleBuiltinMode() - handles built-in modes + */ +static ModeStatus +xf86HandleBuiltinMode(ScrnInfoPtr scrp, + DisplayModePtr p, + DisplayModePtr modep, + ClockRangePtr clockRanges, + Bool allowDiv2) +{ + ClockRangePtr cp; + int extraFlags = 0; + int MulFactor = 1; + int DivFactor = 1; + int clockIndex; + + /* Reject previously rejected modes */ + if (p->status != MODE_OK) + return p->status; + + /* Reject previously considered modes */ + if (p->prev) + return MODE_NOMODE; + + if ((p->type & M_T_CLOCK_C) == M_T_CLOCK_C) { + /* Check clock is in range */ + cp = xf86FindClockRangeForMode(clockRanges, p); + if (cp == NULL){ + modep->type = p->type; + p->status = MODE_CLOCK_RANGE; + return MODE_CLOCK_RANGE; + } + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + if (!scrp->progClock) { + clockIndex = xf86GetNearestClock(scrp, p->Clock, allowDiv2, + cp->ClockDivFactor, + cp->ClockMulFactor, &extraFlags); + modep->Clock = (scrp->clock[clockIndex] * DivFactor) + / MulFactor; + modep->ClockIndex = clockIndex; + modep->SynthClock = scrp->clock[clockIndex]; + if (extraFlags & V_CLKDIV2) { + modep->Clock /= 2; + modep->SynthClock /= 2; + } + } else { + modep->Clock = p->Clock; + modep->ClockIndex = -1; + modep->SynthClock = (modep->Clock * MulFactor) + / DivFactor; + } + modep->PrivFlags = cp->PrivFlags; + } else { + if(!scrp->progClock) { + modep->Clock = p->Clock; + modep->ClockIndex = p->ClockIndex; + modep->SynthClock = p->SynthClock; + } else { + modep->Clock = p->Clock; + modep->ClockIndex = -1; + modep->SynthClock = p->SynthClock; + } + modep->PrivFlags = p->PrivFlags; + } + modep->type = p->type; + modep->HDisplay = p->HDisplay; + modep->HSyncStart = p->HSyncStart; + modep->HSyncEnd = p->HSyncEnd; + modep->HTotal = p->HTotal; + modep->HSkew = p->HSkew; + modep->VDisplay = p->VDisplay; + modep->VSyncStart = p->VSyncStart; + modep->VSyncEnd = p->VSyncEnd; + modep->VTotal = p->VTotal; + modep->VScan = p->VScan; + modep->Flags = p->Flags | extraFlags; + modep->CrtcHDisplay = p->CrtcHDisplay; + modep->CrtcHBlankStart = p->CrtcHBlankStart; + modep->CrtcHSyncStart = p->CrtcHSyncStart; + modep->CrtcHSyncEnd = p->CrtcHSyncEnd; + modep->CrtcHBlankEnd = p->CrtcHBlankEnd; + modep->CrtcHTotal = p->CrtcHTotal; + modep->CrtcHSkew = p->CrtcHSkew; + modep->CrtcVDisplay = p->CrtcVDisplay; + modep->CrtcVBlankStart = p->CrtcVBlankStart; + modep->CrtcVSyncStart = p->CrtcVSyncStart; + modep->CrtcVSyncEnd = p->CrtcVSyncEnd; + modep->CrtcVBlankEnd = p->CrtcVBlankEnd; + modep->CrtcVTotal = p->CrtcVTotal; + modep->CrtcHAdjusted = p->CrtcHAdjusted; + modep->CrtcVAdjusted = p->CrtcVAdjusted; + modep->HSync = p->HSync; + modep->VRefresh = p->VRefresh; + modep->Private = p->Private; + modep->PrivSize = p->PrivSize; + + p->prev = modep; + + return MODE_OK; +} + +/* + * xf86LookupMode + * + * This function returns a mode from the given list which matches the + * given name. When multiple modes with the same name are available, + * the method of picking the matching mode is determined by the + * strategy selected. + * + * This function takes the following parameters: + * scrp ScrnInfoPtr + * modep pointer to the returned mode, which must have the name + * field filled in. + * clockRanges a list of clock ranges. This is optional when all the + * modes are built-in modes. + * strategy how to decide which mode to use from multiple modes with + * the same name + * + * In addition, the following fields from the ScrnInfoRec are used: + * modePool the list of monitor modes compatible with the driver + * clocks a list of discrete clocks + * numClocks number of discrete clocks + * progClock clock is programmable + * + * If a mode was found, its values are filled in to the area pointed to + * by modep, If a mode was not found the return value indicates the + * reason. + */ + +ModeStatus +xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep, + ClockRangePtr clockRanges, LookupModeFlags strategy) +{ + DisplayModePtr p, bestMode = NULL; + ClockRangePtr cp; + int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; + double refresh, bestRefresh = 0.0; + Bool found = FALSE; + int extraFlags = 0; + int clockIndex = -1; + int MulFactor = 1; + int DivFactor = 1; + int ModePrivFlags = 0; + ModeStatus status = MODE_NOMODE; + Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; + int n; + const int types[] = { + M_T_BUILTIN | M_T_PREFERRED, + M_T_BUILTIN, + M_T_USERDEF | M_T_PREFERRED, + M_T_USERDEF, + M_T_DRIVER | M_T_PREFERRED, + M_T_DRIVER, + 0 + }; + const int ntypes = sizeof(types) / sizeof(int); + + strategy &= ~(LOOKUP_CLKDIV2 | LOOKUP_OPTIONAL_TOLERANCES); + + /* Some sanity checking */ + if (scrp == NULL || scrp->modePool == NULL || + (!scrp->progClock && scrp->numClocks == 0)) { + ErrorF("xf86LookupMode: called with invalid scrnInfoRec\n"); + return MODE_ERROR; + } + if (modep == NULL || modep->name == NULL) { + ErrorF("xf86LookupMode: called with invalid modep\n"); + return MODE_ERROR; + } + for (cp = clockRanges; cp != NULL; cp = cp->next) { + /* DivFactor and MulFactor must be > 0 */ + cp->ClockDivFactor = max(1, cp->ClockDivFactor); + cp->ClockMulFactor = max(1, cp->ClockMulFactor); + } + + /* Scan the mode pool for matching names */ + for (n = 0; n < ntypes; n++) { + int type = types[n]; + for (p = scrp->modePool; p != NULL; p = p->next) { + + /* scan through the modes in the sort order above */ + if ((p->type & type) != type) + continue; + + if (strcmp(p->name, modep->name) == 0) { + + /* Skip over previously rejected modes */ + if (p->status != MODE_OK) { + if (!found) + status = p->status; + continue; + } + + /* Skip over previously considered modes */ + if (p->prev) + continue; + + if (p->type & M_T_BUILTIN) { + return xf86HandleBuiltinMode(scrp, p,modep, clockRanges, + allowDiv2); + } + + /* Check clock is in range */ + cp = xf86FindClockRangeForMode(clockRanges, p); + if (cp == NULL) { + /* + * XXX Could do more here to provide a more detailed + * reason for not finding a mode. + */ + p->status = MODE_CLOCK_RANGE; + if (!found) + status = MODE_CLOCK_RANGE; + continue; + } + + /* + * If programmable clock and strategy is not + * LOOKUP_BEST_REFRESH, the required mode has been found, + * otherwise record the refresh and continue looking. + */ + if (scrp->progClock) { + found = TRUE; + if (strategy != LOOKUP_BEST_REFRESH) { + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + break; + } + refresh = xf86ModeVRefresh(p); + if (p->Flags & V_INTERLACE) + refresh /= INTERLACE_REFRESH_WEIGHT; + if (refresh > bestRefresh) { + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + bestRefresh = refresh; + } + continue; + } + + /* + * Clock is in range, so if it is not a programmable clock, find + * a matching clock. + */ + + i = xf86GetNearestClock(scrp, p->Clock, allowDiv2, + cp->ClockDivFactor, cp->ClockMulFactor, &k); + /* + * If the clock is too far from the requested clock, this + * mode is no good. + */ + if (k & V_CLKDIV2) + gap = abs((p->Clock * 2) - + ((scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor)); + else + gap = abs(p->Clock - + ((scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor)); + if (gap > minimumGap) { + p->status = MODE_NOCLOCK; + if (!found) + status = MODE_NOCLOCK; + continue; + } + found = TRUE; + + if (strategy == LOOKUP_BEST_REFRESH) { + refresh = xf86ModeVRefresh(p); + if (p->Flags & V_INTERLACE) + refresh /= INTERLACE_REFRESH_WEIGHT; + if (refresh > bestRefresh) { + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + extraFlags = k; + clockIndex = i; + bestRefresh = refresh; + } + continue; + } + if (strategy == LOOKUP_CLOSEST_CLOCK) { + if (gap < minimumGap) { + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + extraFlags = k; + clockIndex = i; + minimumGap = gap; + } + continue; + } + /* + * If strategy is neither LOOKUP_BEST_REFRESH or + * LOOKUP_CLOSEST_CLOCK the required mode has been found. + */ + bestMode = p; + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + extraFlags = k; + clockIndex = i; + break; + } + } + if (found) break; + } + if (!found || bestMode == NULL) + return status; + + /* Fill in the mode parameters */ + if (scrp->progClock) { + modep->Clock = bestMode->Clock; + modep->ClockIndex = -1; + modep->SynthClock = (modep->Clock * MulFactor) / DivFactor; + } else { + modep->Clock = (scrp->clock[clockIndex] * DivFactor) / + MulFactor; + modep->ClockIndex = clockIndex; + modep->SynthClock = scrp->clock[clockIndex]; + if (extraFlags & V_CLKDIV2) { + modep->Clock /= 2; + modep->SynthClock /= 2; + } + } + modep->type = bestMode->type; + modep->PrivFlags = ModePrivFlags; + modep->HDisplay = bestMode->HDisplay; + modep->HSyncStart = bestMode->HSyncStart; + modep->HSyncEnd = bestMode->HSyncEnd; + modep->HTotal = bestMode->HTotal; + modep->HSkew = bestMode->HSkew; + modep->VDisplay = bestMode->VDisplay; + modep->VSyncStart = bestMode->VSyncStart; + modep->VSyncEnd = bestMode->VSyncEnd; + modep->VTotal = bestMode->VTotal; + modep->VScan = bestMode->VScan; + modep->Flags = bestMode->Flags | extraFlags; + modep->CrtcHDisplay = bestMode->CrtcHDisplay; + modep->CrtcHBlankStart = bestMode->CrtcHBlankStart; + modep->CrtcHSyncStart = bestMode->CrtcHSyncStart; + modep->CrtcHSyncEnd = bestMode->CrtcHSyncEnd; + modep->CrtcHBlankEnd = bestMode->CrtcHBlankEnd; + modep->CrtcHTotal = bestMode->CrtcHTotal; + modep->CrtcHSkew = bestMode->CrtcHSkew; + modep->CrtcVDisplay = bestMode->CrtcVDisplay; + modep->CrtcVBlankStart = bestMode->CrtcVBlankStart; + modep->CrtcVSyncStart = bestMode->CrtcVSyncStart; + modep->CrtcVSyncEnd = bestMode->CrtcVSyncEnd; + modep->CrtcVBlankEnd = bestMode->CrtcVBlankEnd; + modep->CrtcVTotal = bestMode->CrtcVTotal; + modep->CrtcHAdjusted = bestMode->CrtcHAdjusted; + modep->CrtcVAdjusted = bestMode->CrtcVAdjusted; + modep->HSync = bestMode->HSync; + modep->VRefresh = bestMode->VRefresh; + modep->Private = bestMode->Private; + modep->PrivSize = bestMode->PrivSize; + + bestMode->prev = modep; + + return MODE_OK; +} + +/* + * xf86CheckModeForMonitor + * + * This function takes a mode and monitor description, and determines + * if the mode is valid for the monitor. + */ +ModeStatus +xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor) +{ + int i; + + /* Sanity checks */ + if (mode == NULL || monitor == NULL) { + ErrorF("xf86CheckModeForMonitor: called with invalid parameters\n"); + return MODE_ERROR; + } + + DebugF("xf86CheckModeForMonitor(%p %s, %p %s)\n", + mode, mode->name, monitor, monitor->id); + + /* Some basic mode validity checks */ + if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || + mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) + return MODE_H_ILLEGAL; + + if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || + mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) + return MODE_V_ILLEGAL; + + if (monitor->nHsync > 0) { + /* Check hsync against the allowed ranges */ + float hsync = xf86ModeHSync(mode); + for (i = 0; i < monitor->nHsync; i++) + if ((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) && + (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE))) + break; + + /* Now see whether we ran out of sync ranges without finding a match */ + if (i == monitor->nHsync) + return MODE_HSYNC; + } + + if (monitor->nVrefresh > 0) { + /* Check vrefresh against the allowed ranges */ + float vrefrsh = xf86ModeVRefresh(mode); + for (i = 0; i < monitor->nVrefresh; i++) + if ((vrefrsh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) && + (vrefrsh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE))) + break; + + /* Now see whether we ran out of refresh ranges without finding a match */ + if (i == monitor->nVrefresh) + return MODE_VSYNC; + } + + /* Force interlaced modes to have an odd VTotal */ + if (mode->Flags & V_INTERLACE) + mode->CrtcVTotal = mode->VTotal |= 1; + + /* + * This code stops cvt -r modes, and only cvt -r modes, from hitting 15y+ + * old CRTs which might, when there is a lot of solar flare activity and + * when the celestial bodies are unfavourably aligned, implode trying to + * sync to it. It's called "Protecting the user from doing anything stupid". + * -- libv + */ + + if (xf86ModeIsReduced(mode)) { + if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER)) + return MODE_NO_REDUCED; + } + + if ((monitor->maxPixClock) && (mode->Clock > monitor->maxPixClock)) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +/* + * xf86CheckModeSize + * + * An internal routine to check if a mode fits in video memory. This tries to + * avoid overflows that would otherwise occur when video memory size is greater + * than 256MB. + */ +static Bool +xf86CheckModeSize(ScrnInfoPtr scrp, int w, int x, int y) +{ + int bpp = scrp->fbFormat.bitsPerPixel, + pad = scrp->fbFormat.scanlinePad; + int lineWidth, lastWidth; + + if (scrp->depth == 4) + pad *= 4; /* 4 planes */ + + /* Sanity check */ + if ((w < 0) || (x < 0) || (y <= 0)) + return FALSE; + + lineWidth = (((w * bpp) + pad - 1) / pad) * pad; + lastWidth = x * bpp; + + /* + * At this point, we need to compare + * + * (lineWidth * (y - 1)) + lastWidth + * + * against + * + * scrp->videoRam * (1024 * 8) + * + * These are bit quantities. To avoid overflows, do the comparison in + * terms of BITMAP_SCANLINE_PAD units. This assumes BITMAP_SCANLINE_PAD + * is a power of 2. We currently use 32, which limits us to a video + * memory size of 8GB. + */ + + lineWidth = (lineWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; + lastWidth = (lastWidth + (BITMAP_SCANLINE_PAD - 1)) / BITMAP_SCANLINE_PAD; + + if ((lineWidth * (y - 1) + lastWidth) > + (scrp->videoRam * ((1024 * 8) / BITMAP_SCANLINE_PAD))) + return FALSE; + + return TRUE; +} + +/* + * xf86InitialCheckModeForDriver + * + * This function checks if a mode satisfies a driver's initial requirements: + * - mode size fits within the available pixel area (memory) + * - width lies within the range of supported line pitches + * - mode size fits within virtual size (if fixed) + * - horizontal timings are in range + * + * This function takes the following parameters: + * scrp ScrnInfoPtr + * mode mode to check + * maxPitch (optional) maximum line pitch + * virtualX (optional) virtual width requested + * virtualY (optional) virtual height requested + * + * In addition, the following fields from the ScrnInfoRec are used: + * monitor pointer to structure for monitor section + * fbFormat pixel format for the framebuffer + * videoRam video memory size (in kB) + * maxHValue maximum horizontal timing value + * maxVValue maximum vertical timing value + */ + +ModeStatus +xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, + ClockRangePtr clockRanges, + LookupModeFlags strategy, + int maxPitch, int virtualX, int virtualY) +{ + ClockRangePtr cp; + ModeStatus status; + Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; + int i, needDiv2; + + /* Sanity checks */ + if (!scrp || !mode || !clockRanges) { + ErrorF("xf86InitialCheckModeForDriver: " + "called with invalid parameters\n"); + return MODE_ERROR; + } + + DebugF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n", + scrp, mode, mode->name , clockRanges, strategy, maxPitch, virtualX, virtualY); + + /* Some basic mode validity checks */ + if (0 >= mode->HDisplay || mode->HDisplay > mode->HSyncStart || + mode->HSyncStart >= mode->HSyncEnd || mode->HSyncEnd >= mode->HTotal) + return MODE_H_ILLEGAL; + + if (0 >= mode->VDisplay || mode->VDisplay > mode->VSyncStart || + mode->VSyncStart >= mode->VSyncEnd || mode->VSyncEnd >= mode->VTotal) + return MODE_V_ILLEGAL; + + if (!xf86CheckModeSize(scrp, mode->HDisplay, mode->HDisplay, + mode->VDisplay)) + return MODE_MEM; + + if (maxPitch > 0 && mode->HDisplay > maxPitch) + return MODE_BAD_WIDTH; + + if (virtualX > 0 && mode->HDisplay > virtualX) + return MODE_VIRTUAL_X; + + if (virtualY > 0 && mode->VDisplay > virtualY) + return MODE_VIRTUAL_Y; + + if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) + return MODE_BAD_HVALUE; + + if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) + return MODE_BAD_VVALUE; + + /* + * The use of the DisplayModeRec's Crtc* and SynthClock elements below is + * provisional, in that they are later reused by the driver at mode-set + * time. Here, they are temporarily enlisted to contain the mode timings + * as seen by the CRT or panel (rather than the CRTC). The driver's + * ValidMode() is allowed to modify these so it can deal with such things + * as mode stretching and/or centering. The driver should >NOT< modify the + * user-supplied values as these are reported back when mode validation is + * said and done. + */ + /* + * NOTE: We (ab)use the mode->Crtc* values here to store timing + * information for the calculation of Hsync and Vrefresh. Before + * these values are calculated the driver is given the opportunity + * to either set these HSync and VRefresh itself or modify the timing + * values. + * The difference to the final calculation is small but imortand: + * here we pass the flag INTERLACE_HALVE_V regardless if the driver + * sets it or not. This way our calculation of VRefresh has the same + * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0 + * This dual use of the mode->Crtc* values will certainly create + * confusion and is bad software design. However since it's part of + * the driver API it's hard to change. + */ + + if (scrp->ValidMode) { + + xf86SetModeCrtc(mode, INTERLACE_HALVE_V); + + cp = xf86FindClockRangeForMode(clockRanges, mode); + if (!cp) + return MODE_CLOCK_RANGE; + + if (cp->ClockMulFactor < 1) + cp->ClockMulFactor = 1; + if (cp->ClockDivFactor < 1) + cp->ClockDivFactor = 1; + + /* + * XXX The effect of clock dividers and multipliers on the monitor's + * pixel clock needs to be verified. + */ + if (scrp->progClock) { + mode->SynthClock = mode->Clock; + } else { + i = xf86GetNearestClock(scrp, mode->Clock, allowDiv2, + cp->ClockDivFactor, cp->ClockMulFactor, + &needDiv2); + mode->SynthClock = (scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor; + if (needDiv2 & V_CLKDIV2) + mode->SynthClock /= 2; + } + + status = (*scrp->ValidMode)(scrp->scrnIndex, mode, FALSE, + MODECHECK_INITIAL); + if (status != MODE_OK) + return status; + + if (mode->HSync <= 0.0) + mode->HSync = (float)mode->SynthClock / (float)mode->CrtcHTotal; + if (mode->VRefresh <= 0.0) + mode->VRefresh = (mode->SynthClock * 1000.0) + / (mode->CrtcHTotal * mode->CrtcVTotal); + } + + mode->HSync = xf86ModeHSync(mode); + mode->VRefresh = xf86ModeVRefresh(mode); + + /* Assume it is OK */ + return MODE_OK; +} + +/* + * xf86CheckModeForDriver + * + * This function is for checking modes while the server is running (for + * use mainly by the VidMode extension). + * + * This function checks if a mode satisfies a driver's requirements: + * - width lies within the line pitch + * - mode size fits within virtual size + * - horizontal/vertical timings are in range + * + * This function takes the following parameters: + * scrp ScrnInfoPtr + * mode mode to check + * flags not (currently) used + * + * In addition, the following fields from the ScrnInfoRec are used: + * maxHValue maximum horizontal timing value + * maxVValue maximum vertical timing value + * virtualX virtual width + * virtualY virtual height + * clockRanges allowable clock ranges + */ + +ModeStatus +xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags) +{ + ClockRangePtr cp; + int i, k, gap, minimumGap = CLOCK_TOLERANCE + 1; + int extraFlags = 0; + int clockIndex = -1; + int MulFactor = 1; + int DivFactor = 1; + int ModePrivFlags = 0; + ModeStatus status = MODE_NOMODE; + + /* Some sanity checking */ + if (scrp == NULL || (!scrp->progClock && scrp->numClocks == 0)) { + ErrorF("xf86CheckModeForDriver: called with invalid scrnInfoRec\n"); + return MODE_ERROR; + } + if (mode == NULL) { + ErrorF("xf86CheckModeForDriver: called with invalid modep\n"); + return MODE_ERROR; + } + + /* Check the mode size */ + if (mode->HDisplay > scrp->virtualX) + return MODE_VIRTUAL_X; + + if (mode->VDisplay > scrp->virtualY) + return MODE_VIRTUAL_Y; + + if (scrp->maxHValue > 0 && mode->HTotal > scrp->maxHValue) + return MODE_BAD_HVALUE; + + if (scrp->maxVValue > 0 && mode->VTotal > scrp->maxVValue) + return MODE_BAD_VVALUE; + + for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { + /* DivFactor and MulFactor must be > 0 */ + cp->ClockDivFactor = max(1, cp->ClockDivFactor); + cp->ClockMulFactor = max(1, cp->ClockMulFactor); + } + + if (scrp->progClock) { + /* Check clock is in range */ + for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { + if (modeInClockRange(cp, mode)) + break; + } + if (cp == NULL) { + return MODE_CLOCK_RANGE; + } + /* + * If programmable clock the required mode has been found + */ + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + } else { + status = MODE_CLOCK_RANGE; + /* Check clock is in range */ + for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) { + if (modeInClockRange(cp, mode)) { + /* + * Clock is in range, so if it is not a programmable clock, + * find a matching clock. + */ + + i = xf86GetNearestClock(scrp, mode->Clock, 0, + cp->ClockDivFactor, cp->ClockMulFactor, &k); + /* + * If the clock is too far from the requested clock, this + * mode is no good. + */ + if (k & V_CLKDIV2) + gap = abs((mode->Clock * 2) - + ((scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor)); + else + gap = abs(mode->Clock - + ((scrp->clock[i] * cp->ClockDivFactor) / + cp->ClockMulFactor)); + if (gap > minimumGap) { + status = MODE_NOCLOCK; + continue; + } + + DivFactor = cp->ClockDivFactor; + MulFactor = cp->ClockMulFactor; + ModePrivFlags = cp->PrivFlags; + extraFlags = k; + clockIndex = i; + break; + } + } + if (cp == NULL) + return status; + } + + /* Fill in the mode parameters */ + if (scrp->progClock) { + mode->ClockIndex = -1; + mode->SynthClock = (mode->Clock * MulFactor) / DivFactor; + } else { + mode->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor; + mode->ClockIndex = clockIndex; + mode->SynthClock = scrp->clock[clockIndex]; + if (extraFlags & V_CLKDIV2) { + mode->Clock /= 2; + mode->SynthClock /= 2; + } + } + mode->PrivFlags = ModePrivFlags; + + return MODE_OK; +} + +static int +inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy) +{ + float aspect = 0.0; + MonPtr mon = scrp->monitor; + xf86MonPtr DDC; + int x = 0, y = 0; + DisplayModePtr mode; + + if (!mon) return 0; + DDC = mon->DDC; + + if (DDC && DDC->ver.revision >= 4) { + /* For 1.4, we might actually get native pixel format. How novel. */ + if (PREFERRED_TIMING_MODE(DDC->features.msc)) { + for (mode = modes; mode; mode = mode->next) { + if (mode->type & (M_T_DRIVER | M_T_PREFERRED)) { + x = mode->HDisplay; + y = mode->VDisplay; + goto found; + } + } + } + /* + * Even if we don't, we might get aspect ratio from extra CVT info + * or from the monitor size fields. TODO. + */ + } + + /* + * Technically this triggers if either is zero. That wasn't legal + * before EDID 1.4, but right now we'll get that wrong. TODO. + */ + if (!aspect) { + if (!mon->widthmm || !mon->heightmm) + aspect = 4.0/3.0; + else + aspect = (float)mon->widthmm / (float)mon->heightmm; + } + + /* find the largest M_T_DRIVER mode with that aspect ratio */ + for (mode = modes; mode; mode = mode->next) { + float mode_aspect, metaspect; + if (!(mode->type & (M_T_DRIVER|M_T_USERDEF))) + continue; + mode_aspect = (float)mode->HDisplay / (float)mode->VDisplay; + metaspect = aspect / mode_aspect; + /* 5% slop or so, since we only get size in centimeters */ + if (fabs(1.0 - metaspect) < 0.05) { + if ((mode->HDisplay > x) && (mode->VDisplay > y)) { + x = mode->HDisplay; + y = mode->VDisplay; + } + } + } + + if (!x || !y) { + xf86DrvMsg(scrp->scrnIndex, X_WARNING, + "Unable to estimate virtual size\n"); + return 0; + } + +found: + *vx = x; + *vy = y; + + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Estimated virtual size for aspect ratio %.4f is %dx%d\n", + aspect, *vx, *vy); + + return 1; +} + +/* Least common multiple */ +static unsigned int +LCM(unsigned int x, unsigned int y) +{ + unsigned int m = x, n = y, o; + + while ((o = m % n)) + { + m = n; + n = o; + } + + return (x / n) * y; +} + +/* + * Given various screen attributes, determine the minimum scanline width such + * that each scanline is server and DDX padded and any pixels with imbedded + * bank boundaries are off-screen. This function returns -1 if such a width + * cannot exist. + */ +static int +scanLineWidth( + unsigned int xsize, /* pixels */ + unsigned int ysize, /* pixels */ + unsigned int width, /* pixels */ + unsigned long BankSize, /* char's */ + PixmapFormatRec *pBankFormat, + unsigned int nWidthUnit /* bits */ +) +{ + unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit; + unsigned long minBitsPerScanline, maxBitsPerScanline; + + /* Sanity checks */ + + if (!nWidthUnit || !pBankFormat) + return -1; + + nBitsPerBank = BankSize * 8; + if (nBitsPerBank % pBankFormat->scanlinePad) + return -1; + + if (xsize > width) + width = xsize; + nBitsPerScanlinePadUnit = LCM(pBankFormat->scanlinePad, nWidthUnit); + nBitsPerScanline = + (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) / + nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit; + width = nBitsPerScanline / pBankFormat->bitsPerPixel; + + if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel)) + return (int)width; + + /* + * Scanlines will be server-pad aligned at this point. They will also be + * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded + * bank boundaries are off-screen. + * + * It seems reasonable to limit total frame buffer size to 1/16 of the + * theoretical maximum address space size. On a machine with 32-bit + * addresses (to 8-bit quantities) this turns out to be 256MB. Not only + * does this provide a simple limiting condition for the loops below, but + * it also prevents unsigned long wraparounds. + */ + if (!ysize) + return -1; + + minBitsPerScanline = xsize * pBankFormat->bitsPerPixel; + if (minBitsPerScanline > nBitsPerBank) + return -1; + + if (ysize == 1) + return (int)width; + + maxBitsPerScanline = + (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1); + while (nBitsPerScanline <= maxBitsPerScanline) + { + unsigned long BankBase, BankUnit; + + BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) * + nBitsPerBank; + if (!(BankUnit % nBitsPerScanline)) + return (int)width; + + for (BankBase = BankUnit; ; BankBase += nBitsPerBank) + { + unsigned long x, y; + + y = BankBase / nBitsPerScanline; + if (y >= ysize) + return (int)width; + + x = BankBase % nBitsPerScanline; + if (!(x % pBankFormat->bitsPerPixel)) + continue; + + if (x < minBitsPerScanline) + { + /* + * Skip ahead certain widths by dividing the excess scanline + * amongst the y's. + */ + y *= nBitsPerScanlinePadUnit; + nBitsPerScanline += + ((x + y - 1) / y) * nBitsPerScanlinePadUnit; + width = nBitsPerScanline / pBankFormat->bitsPerPixel; + break; + } + + if (BankBase != BankUnit) + continue; + + if (!(nBitsPerScanline % x)) + return (int)width; + + BankBase = ((nBitsPerScanline - minBitsPerScanline) / + (nBitsPerScanline - x)) * BankUnit; + } + } + + return -1; +} + +/* + * xf86ValidateModes + * + * This function takes a set of mode names, modes and limiting conditions, + * and selects a set of modes and parameters based on those conditions. + * + * This function takes the following parameters: + * scrp ScrnInfoPtr + * availModes the list of modes available for the monitor + * modeNames (optional) list of mode names that the screen is requesting + * clockRanges a list of clock ranges + * linePitches (optional) a list of line pitches + * minPitch (optional) minimum line pitch (in pixels) + * maxPitch (optional) maximum line pitch (in pixels) + * pitchInc (mandatory) pitch increment (in bits) + * minHeight (optional) minimum virtual height (in pixels) + * maxHeight (optional) maximum virtual height (in pixels) + * virtualX (optional) virtual width requested (in pixels) + * virtualY (optional) virtual height requested (in pixels) + * apertureSize size of video aperture (in bytes) + * strategy how to decide which mode to use from multiple modes with + * the same name + * + * In addition, the following fields from the ScrnInfoRec are used: + * clocks a list of discrete clocks + * numClocks number of discrete clocks + * progClock clock is programmable + * monitor pointer to structure for monitor section + * fbFormat format of the framebuffer + * videoRam video memory size + * maxHValue maximum horizontal timing value + * maxVValue maximum vertical timing value + * xInc horizontal timing increment (defaults to 8 pixels) + * + * The function fills in the following ScrnInfoRec fields: + * modePool A subset of the modes available to the monitor which + * are compatible with the driver. + * modes one mode entry for each of the requested modes, with the + * status field filled in to indicate if the mode has been + * accepted or not. + * virtualX the resulting virtual width + * virtualY the resulting virtual height + * displayWidth the resulting line pitch + * + * The function's return value is the number of matching modes found, or -1 + * if an unrecoverable error was encountered. + */ + +int +xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, + char **modeNames, ClockRangePtr clockRanges, + int *linePitches, int minPitch, int maxPitch, int pitchInc, + int minHeight, int maxHeight, int virtualX, int virtualY, + int apertureSize, LookupModeFlags strategy) +{ + DisplayModePtr p, q, r, new, last, *endp; + int i, numModes = 0; + ModeStatus status; + int linePitch = -1, virtX = 0, virtY = 0; + int newLinePitch, newVirtX, newVirtY; + int modeSize; /* in pixels */ + Bool validateAllDefaultModes = FALSE; + Bool userModes = FALSE; + int saveType; + PixmapFormatRec *BankFormat; + ClockRangePtr cp; + ClockRangePtr storeClockRanges; + int numTimings = 0; + range hsync[MAX_HSYNC]; + range vrefresh[MAX_VREFRESH]; + Bool inferred_virtual = FALSE; + + DebugF("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n", + scrp, availModes, modeNames, clockRanges, + linePitches, minPitch, maxPitch, pitchInc, + minHeight, maxHeight, virtualX, virtualY, + apertureSize, strategy + ); + + /* Some sanity checking */ + if (scrp == NULL || scrp->name == NULL || !scrp->monitor || + (!scrp->progClock && scrp->numClocks == 0)) { + ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n"); + return -1; + } + if (linePitches != NULL && linePitches[0] <= 0) { + ErrorF("xf86ValidateModes: called with invalid linePitches\n"); + return -1; + } + if (pitchInc <= 0) { + ErrorF("xf86ValidateModes: called with invalid pitchInc\n"); + return -1; + } + if ((virtualX > 0) != (virtualY > 0)) { + ErrorF("xf86ValidateModes: called with invalid virtual resolution\n"); + return -1; + } + + /* + * If requested by the driver, allow missing hsync and/or vrefresh ranges + * in the monitor section. + */ + if (strategy & LOOKUP_OPTIONAL_TOLERANCES) { + strategy &= ~LOOKUP_OPTIONAL_TOLERANCES; + } else { + const char *type = ""; + + if (scrp->monitor->nHsync <= 0) { + if (numTimings > 0) { + scrp->monitor->nHsync = numTimings; + for (i = 0; i < numTimings; i++) { + scrp->monitor->hsync[i].lo = hsync[i].lo; + scrp->monitor->hsync[i].hi = hsync[i].hi; + } + } else { + scrp->monitor->hsync[0].lo = 31.5; + scrp->monitor->hsync[0].hi = 37.9; + scrp->monitor->nHsync = 1; + } + type = "default "; + } + for (i = 0; i < scrp->monitor->nHsync; i++) { + if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi) + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using %shsync value of %.2f kHz\n", + scrp->monitor->id, type, + scrp->monitor->hsync[i].lo); + else + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using %shsync range of %.2f-%.2f kHz\n", + scrp->monitor->id, type, + scrp->monitor->hsync[i].lo, + scrp->monitor->hsync[i].hi); + } + + type = ""; + if (scrp->monitor->nVrefresh <= 0) { + if (numTimings > 0) { + scrp->monitor->nVrefresh = numTimings; + for (i = 0; i < numTimings; i++) { + scrp->monitor->vrefresh[i].lo = vrefresh[i].lo; + scrp->monitor->vrefresh[i].hi = vrefresh[i].hi; + } + } else { + scrp->monitor->vrefresh[0].lo = 50; + scrp->monitor->vrefresh[0].hi = 70; + scrp->monitor->nVrefresh = 1; + } + type = "default "; + } + for (i = 0; i < scrp->monitor->nVrefresh; i++) { + if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi) + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using %svrefresh value of %.2f Hz\n", + scrp->monitor->id, type, + scrp->monitor->vrefresh[i].lo); + else + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using %svrefresh range of %.2f-%.2f Hz\n", + scrp->monitor->id, type, + scrp->monitor->vrefresh[i].lo, + scrp->monitor->vrefresh[i].hi); + } + if (scrp->monitor->maxPixClock) { + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "%s: Using maximum pixel clock of %.2f MHz\n", + scrp->monitor->id, + (float)scrp->monitor->maxPixClock / 1000.0); + } + } + + /* + * Store the clockRanges for later use by the VidMode extension. + */ + storeClockRanges = scrp->clockRanges; + while (storeClockRanges != NULL) { + storeClockRanges = storeClockRanges->next; + } + for (cp = clockRanges; cp != NULL; cp = cp->next, + storeClockRanges = storeClockRanges->next) { + storeClockRanges = xnfalloc(sizeof(ClockRange)); + if (scrp->clockRanges == NULL) + scrp->clockRanges = storeClockRanges; + memcpy(storeClockRanges, cp, sizeof(ClockRange)); + } + + /* Determine which pixmap format to pass to scanLineWidth() */ + if (scrp->depth > 4) + BankFormat = &scrp->fbFormat; + else + BankFormat = xf86GetPixFormat(scrp, 1); /* >not< scrp->depth! */ + + if (scrp->xInc <= 0) + scrp->xInc = 8; /* Suitable for VGA and others */ + +#define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc) + + /* + * Determine maxPitch if it wasn't given explicitly. Note linePitches + * always takes precedence if is non-NULL. In that case the minPitch and + * maxPitch values passed are ignored. + */ + if (linePitches) { + minPitch = maxPitch = linePitches[0]; + for (i = 1; linePitches[i] > 0; i++) { + if (linePitches[i] > maxPitch) + maxPitch = linePitches[i]; + if (linePitches[i] < minPitch) + minPitch = linePitches[i]; + } + } + + /* Initial check of virtual size against other constraints */ + scrp->virtualFrom = X_PROBED; + /* + * Initialise virtX and virtY if the values are fixed. + */ + if (virtualY > 0) { + if (maxHeight > 0 && virtualY > maxHeight) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual height (%d) is too large for the hardware " + "(max %d)\n", virtualY, maxHeight); + return -1; + } + + if (minHeight > 0 && virtualY < minHeight) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual height (%d) is too small for the hardware " + "(min %d)\n", virtualY, minHeight); + return -1; + } + + virtualX = _VIRTUALX(virtualX); + if (linePitches != NULL) { + for (i = 0; linePitches[i] != 0; i++) { + if ((linePitches[i] >= virtualX) && + (linePitches[i] == + scanLineWidth(virtualX, virtualY, linePitches[i], + apertureSize, BankFormat, pitchInc))) { + linePitch = linePitches[i]; + break; + } + } + } else { + linePitch = scanLineWidth(virtualX, virtualY, minPitch, + apertureSize, BankFormat, pitchInc); + } + + if ((linePitch < minPitch) || (linePitch > maxPitch)) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual width (%d) is too large for the hardware " + "(max %d)\n", virtualX, maxPitch); + return -1; + } + + if (!xf86CheckModeSize(scrp, linePitch, virtualX, virtualY)) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual size (%dx%d) (pitch %d) exceeds video memory\n", + virtualX, virtualY, linePitch); + return -1; + } + + virtX = virtualX; + virtY = virtualY; + scrp->virtualFrom = X_CONFIG; + } else if (!modeNames || !*modeNames) { + /* No virtual size given in the config, try to infer */ + /* XXX this doesn't take m{in,ax}Pitch into account; oh well */ + inferred_virtual = inferVirtualSize(scrp, availModes, &virtX, &virtY); + if (inferred_virtual) + linePitch = scanLineWidth(virtX, virtY, minPitch, apertureSize, + BankFormat, pitchInc); + } + + /* Print clock ranges and scaled clocks */ + xf86ShowClockRanges(scrp, clockRanges); + + /* + * If scrp->modePool hasn't been setup yet, set it up now. This allows the + * modes that the driver definitely can't use to be weeded out early. Note + * that a modePool mode's prev field is used to hold a pointer to the + * member of the scrp->modes list for which a match was considered. + */ + if (scrp->modePool == NULL) { + q = NULL; + for (p = availModes; p != NULL; p = p->next) { + status = xf86InitialCheckModeForDriver(scrp, p, clockRanges, + strategy, maxPitch, + virtX, virtY); + + if (status == MODE_OK) { + status = xf86CheckModeForMonitor(p, scrp->monitor); + } + + if (status == MODE_OK) { + new = xnfalloc(sizeof(DisplayModeRec)); + *new = *p; + new->next = NULL; + if (!q) { + scrp->modePool = new; + } else { + q->next = new; + } + new->prev = NULL; + q = new; + q->name = xnfstrdup(p->name); + q->status = MODE_OK; + } else { + printModeRejectMessage(scrp->scrnIndex, p, status); + } + } + + if (scrp->modePool == NULL) { + xf86DrvMsg(scrp->scrnIndex, X_WARNING, "Mode pool is empty\n"); + return 0; + } + } else { + for (p = scrp->modePool; p != NULL; p = p->next) { + p->prev = NULL; + p->status = MODE_OK; + } + } + + /* + * Allocate one entry in scrp->modes for each named mode. + */ + while (scrp->modes) + xf86DeleteMode(&scrp->modes, scrp->modes); + endp = &scrp->modes; + last = NULL; + if (modeNames != NULL) { + for (i = 0; modeNames[i] != NULL; i++) { + userModes = TRUE; + new = xnfcalloc(1, sizeof(DisplayModeRec)); + new->prev = last; + new->type = M_T_USERDEF; + new->name = xnfalloc(strlen(modeNames[i]) + 1); + strcpy(new->name, modeNames[i]); + if (new->prev) + new->prev->next = new; + *endp = last = new; + endp = &new->next; + } + } + + /* Lookup each mode */ +#ifdef RANDR + if (!xf86Info.disableRandR +#ifdef PANORAMIX + && noPanoramiXExtension +#endif + ) + validateAllDefaultModes = TRUE; +#endif + + for (p = scrp->modes; ; p = p->next) { + Bool repeat; + + /* + * If the supplied mode names don't produce a valid mode, scan through + * unconsidered modePool members until one survives validation. This + * is done in decreasing order by mode pixel area. + */ + + if (p == NULL) { + if ((numModes > 0) && !validateAllDefaultModes) + break; + + validateAllDefaultModes = TRUE; + r = NULL; + modeSize = 0; + for (q = scrp->modePool; q != NULL; q = q->next) { + if ((q->prev == NULL) && (q->status == MODE_OK)) { + /* + * Deal with the case where this mode wasn't considered + * because of a builtin mode of the same name. + */ + for (p = scrp->modes; p != NULL; p = p->next) { + if ((p->status != MODE_OK) && + !strcmp(p->name, q->name)) + break; + } + + if (p != NULL) + q->prev = p; + else { + /* + * A quick check to not allow default modes with + * horizontal timing parameters that CRTs may have + * problems with. + */ + if (!scrp->monitor->reducedblanking && + (q->type & M_T_DEFAULT) && + ((double)q->HTotal / (double)q->HDisplay) < 1.15) + continue; + + if (modeSize < (q->HDisplay * q->VDisplay)) { + r = q; + modeSize = q->HDisplay * q->VDisplay; + } + } + } + } + + if (r == NULL) + break; + + p = xnfcalloc(1, sizeof(DisplayModeRec)); + p->prev = last; + p->name = xnfalloc(strlen(r->name) + 1); + if (!userModes) + p->type = M_T_USERDEF; + strcpy(p->name, r->name); + if (p->prev) + p->prev->next = p; + *endp = last = p; + endp = &p->next; + } + + repeat = FALSE; + lookupNext: + if (repeat && ((status = p->status) != MODE_OK)) + printModeRejectMessage(scrp->scrnIndex, p, status); + saveType = p->type; + status = xf86LookupMode(scrp, p, clockRanges, strategy); + if (repeat && status == MODE_NOMODE) + continue; + if (status != MODE_OK) + printModeRejectMessage(scrp->scrnIndex, p, status); + if (status == MODE_ERROR) { + ErrorF("xf86ValidateModes: " + "unexpected result from xf86LookupMode()\n"); + return -1; + } + if (status != MODE_OK) { + if (p->status == MODE_OK) + p->status = status; + continue; + } + p->type |= saveType; + repeat = TRUE; + + newLinePitch = linePitch; + newVirtX = virtX; + newVirtY = virtY; + + /* + * Don't let non-user defined modes increase the virtual size + */ + if (!(p->type & M_T_USERDEF) && (numModes > 0)) { + if (p->HDisplay > virtX) { + p->status = MODE_VIRTUAL_X; + goto lookupNext; + } + if (p->VDisplay > virtY) { + p->status = MODE_VIRTUAL_Y; + goto lookupNext; + } + } + /* + * Adjust virtual width and height if the mode is too large for the + * current values and if they are not fixed. + */ + if (virtualX <= 0 && p->HDisplay > newVirtX) + newVirtX = _VIRTUALX(p->HDisplay); + if (virtualY <= 0 && p->VDisplay > newVirtY) { + if (maxHeight > 0 && p->VDisplay > maxHeight) { + p->status = MODE_VIRTUAL_Y; /* ? */ + goto lookupNext; + } + newVirtY = p->VDisplay; + } + + /* + * If virtual resolution is to be increased, revalidate it. + */ + if ((virtX != newVirtX) || (virtY != newVirtY)) { + if (linePitches != NULL) { + newLinePitch = -1; + for (i = 0; linePitches[i] != 0; i++) { + if ((linePitches[i] >= newVirtX) && + (linePitches[i] >= linePitch) && + (linePitches[i] == + scanLineWidth(newVirtX, newVirtY, linePitches[i], + apertureSize, BankFormat, pitchInc))) { + newLinePitch = linePitches[i]; + break; + } + } + } else { + if (linePitch < minPitch) + linePitch = minPitch; + newLinePitch = scanLineWidth(newVirtX, newVirtY, linePitch, + apertureSize, BankFormat, + pitchInc); + } + if ((newLinePitch < minPitch) || (newLinePitch > maxPitch)) { + p->status = MODE_BAD_WIDTH; + goto lookupNext; + } + + /* + * Check that the pixel area required by the new virtual height + * and line pitch isn't too large. + */ + if (!xf86CheckModeSize(scrp, newLinePitch, newVirtX, newVirtY)) { + p->status = MODE_MEM_VIRT; + goto lookupNext; + } + } + + if (scrp->ValidMode) { + /* + * Give the driver a final say, passing it the proposed virtual + * geometry. + */ + scrp->virtualX = newVirtX; + scrp->virtualY = newVirtY; + scrp->displayWidth = newLinePitch; + p->status = (scrp->ValidMode)(scrp->scrnIndex, p, FALSE, + MODECHECK_FINAL); + + if (p->status != MODE_OK) { + goto lookupNext; + } + } + + /* Mode has passed all the tests */ + virtX = newVirtX; + virtY = newVirtY; + linePitch = newLinePitch; + p->status = MODE_OK; + numModes++; + } + +#undef _VIRTUALX + + /* + * If we estimated the virtual size above, we may have filtered away all + * the modes that maximally match that size; scan again to find out and + * fix up if so. + */ + if (inferred_virtual) { + int vx = 0, vy = 0; + for (p = scrp->modes; p; p = p->next) { + if (p->HDisplay > vx && p->VDisplay > vy) { + vx = p->HDisplay; + vy = p->VDisplay; + } + } + if (vx < virtX || vy < virtY) { + xf86DrvMsg(scrp->scrnIndex, X_WARNING, + "Shrinking virtual size estimate from %dx%d to %dx%d\n", + virtX, virtY, vx, vy); + virtX = vx; + virtY = vy; + linePitch = scanLineWidth(vx, vy, minPitch, apertureSize, + BankFormat, pitchInc); + } + } + + /* Update the ScrnInfoRec parameters */ + + scrp->virtualX = virtX; + scrp->virtualY = virtY; + scrp->displayWidth = linePitch; + + if (numModes <= 0) + return 0; + + /* Make the mode list into a circular list by joining up the ends */ + p = scrp->modes; + while (p->next != NULL) + p = p->next; + /* p is now the last mode on the list */ + p->next = scrp->modes; + scrp->modes->prev = p; + + if (minHeight > 0 && virtY < minHeight) { + xf86DrvMsg(scrp->scrnIndex, X_ERROR, + "Virtual height (%d) is too small for the hardware " + "(min %d)\n", virtY, minHeight); + return -1; + } + + return numModes; +} + +/* + * xf86DeleteMode + * + * This function removes a mode from a list of modes. + * + * There are different types of mode lists: + * + * - singly linked linear lists, ending in NULL + * - doubly linked linear lists, starting and ending in NULL + * - doubly linked circular lists + * + */ + +void +xf86DeleteMode(DisplayModePtr *modeList, DisplayModePtr mode) +{ + /* Catch the easy/insane cases */ + if (modeList == NULL || *modeList == NULL || mode == NULL) + return; + + /* If the mode is at the start of the list, move the start of the list */ + if (*modeList == mode) + *modeList = mode->next; + + /* If mode is the only one on the list, set the list to NULL */ + if ((mode == mode->prev) && (mode == mode->next)) { + *modeList = NULL; + } else { + if ((mode->prev != NULL) && (mode->prev->next == mode)) + mode->prev->next = mode->next; + if ((mode->next != NULL) && (mode->next->prev == mode)) + mode->next->prev = mode->prev; + } + + free(mode->name); + free(mode); +} + +/* + * xf86PruneDriverModes + * + * Remove modes from the driver's mode list which have been marked as + * invalid. + */ + +void +xf86PruneDriverModes(ScrnInfoPtr scrp) +{ + DisplayModePtr first, p, n; + + p = scrp->modes; + if (p == NULL) + return; + + do { + if (!(first = scrp->modes)) + return; + n = p->next; + if (p->status != MODE_OK) { + xf86DeleteMode(&(scrp->modes), p); + } + p = n; + } while (p != NULL && p != first); + + /* modePool is no longer needed, turf it */ + while (scrp->modePool) { + /* + * A modePool mode's prev field is used to hold a pointer to the + * member of the scrp->modes list for which a match was considered. + * Clear that pointer first, otherwise xf86DeleteMode might get + * confused + */ + scrp->modePool->prev = NULL; + xf86DeleteMode(&scrp->modePool, scrp->modePool); + } +} + + +/* + * xf86SetCrtcForModes + * + * Goes through the screen's mode list, and initialises the Crtc + * parameters for each mode. The initialisation includes adjustments + * for interlaced and double scan modes. + */ +void +xf86SetCrtcForModes(ScrnInfoPtr scrp, int adjustFlags) +{ + DisplayModePtr p; + + /* + * Store adjustFlags for use with the VidMode extension. There is an + * implicit assumption here that SetCrtcForModes is called once. + */ + scrp->adjustFlags = adjustFlags; + + p = scrp->modes; + if (p == NULL) + return; + + do { + xf86SetModeCrtc(p, adjustFlags); + DebugF("%sMode %s: %d (%d) %d %d (%d) %d %d (%d) %d %d (%d) %d\n", + (p->type & M_T_DEFAULT) ? "Default " : "", + p->name, p->CrtcHDisplay, p->CrtcHBlankStart, + p->CrtcHSyncStart, p->CrtcHSyncEnd, p->CrtcHBlankEnd, + p->CrtcHTotal, p->CrtcVDisplay, p->CrtcVBlankStart, + p->CrtcVSyncStart, p->CrtcVSyncEnd, p->CrtcVBlankEnd, + p->CrtcVTotal); + p = p->next; + } while (p != NULL && p != scrp->modes); +} + +void +xf86PrintModes(ScrnInfoPtr scrp) +{ + DisplayModePtr p; + float hsync, refresh = 0; + char *desc, *desc2, *prefix, *uprefix; + + if (scrp == NULL) + return; + + xf86DrvMsg(scrp->scrnIndex, scrp->virtualFrom, "Virtual size is %dx%d " + "(pitch %d)\n", scrp->virtualX, scrp->virtualY, + scrp->displayWidth); + + p = scrp->modes; + if (p == NULL) + return; + + do { + desc = desc2 = ""; + hsync = xf86ModeHSync(p); + refresh = xf86ModeVRefresh(p); + if (p->Flags & V_INTERLACE) { + desc = " (I)"; + } + if (p->Flags & V_DBLSCAN) { + desc = " (D)"; + } + if (p->VScan > 1) { + desc2 = " (VScan)"; + } + if (p->type & M_T_BUILTIN) + prefix = "Built-in mode"; + else if (p->type & M_T_DEFAULT) + prefix = "Default mode"; + else if (p->type & M_T_DRIVER) + prefix = "Driver mode"; + else + prefix = "Mode"; + if (p->type & M_T_USERDEF) + uprefix = "*"; + else + uprefix = " "; + if (hsync == 0 || refresh == 0) { + if (p->name) + xf86DrvMsg(scrp->scrnIndex, X_CONFIG, + "%s%s \"%s\"\n", uprefix, prefix, p->name); + else + xf86DrvMsg(scrp->scrnIndex, X_PROBED, + "%s%s %dx%d (unnamed)\n", + uprefix, prefix, p->HDisplay, p->VDisplay); + } else if (p->Clock == p->SynthClock) { + xf86DrvMsg(scrp->scrnIndex, X_CONFIG, + "%s%s \"%s\": %.1f MHz, %.1f kHz, %.1f Hz%s%s\n", + uprefix, prefix, p->name, p->Clock / 1000.0, + hsync, refresh, desc, desc2); + } else { + xf86DrvMsg(scrp->scrnIndex, X_CONFIG, + "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), " + "%.1f kHz, %.1f Hz%s%s\n", + uprefix, prefix, p->name, p->Clock / 1000.0, + p->SynthClock / 1000.0, hsync, refresh, desc, desc2); + } + if (hsync != 0 && refresh != 0) + xf86PrintModeline(scrp->scrnIndex,p); + p = p->next; + } while (p != NULL && p != scrp->modes); +} diff --git a/xorg-server/hw/xfree86/common/xf86Option.c b/xorg-server/hw/xfree86/common/xf86Option.c index a2868bf21..965ce4c7d 100644 --- a/xorg-server/hw/xfree86/common/xf86Option.c +++ b/xorg-server/hw/xfree86/common/xf86Option.c @@ -1,862 +1,862 @@ -/* - * Copyright (c) 1998-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * Author: David Dawes <dawes@xfree86.org> - * - * This file includes public option handling functions. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <stdlib.h> -#include <ctype.h> -#include <X11/X.h> -#include "os.h" -#include "xf86.h" -#include "xf86Xinput.h" -#include "xf86Optrec.h" -#include "xf86Parser.h" - -static Bool ParseOptionValue(int scrnIndex, pointer options, OptionInfoPtr p, - Bool markUsed); - -/* - * xf86CollectOptions collects the options from each of the config file - * sections used by the screen and puts the combined list in pScrn->options. - * This function requires that the following have been initialised: - * - * pScrn->confScreen - * pScrn->Entities[i]->device - * pScrn->display - * pScrn->monitor - * - * The extraOpts parameter may optionally contain a list of additional options - * to include. - * - * The order of precedence for options is: - * - * extraOpts, display, confScreen, monitor, device - */ - -void -xf86CollectOptions(ScrnInfoPtr pScrn, pointer extraOpts) -{ - XF86OptionPtr tmp; - XF86OptionPtr extras = (XF86OptionPtr)extraOpts; - GDevPtr device; - - int i; - - pScrn->options = NULL; - - for (i=pScrn->numEntities - 1; i >= 0; i--) { - device = xf86GetDevFromEntity(pScrn->entityList[i], - pScrn->entityInstanceList[i]); - if (device && device->options) { - tmp = xf86optionListDup(device->options); - if (pScrn->options) - xf86optionListMerge(pScrn->options,tmp); - else - pScrn->options = tmp; - } - } - if (pScrn->monitor->options) { - tmp = xf86optionListDup(pScrn->monitor->options); - if (pScrn->options) - pScrn->options = xf86optionListMerge(pScrn->options, tmp); - else - pScrn->options = tmp; - } - if (pScrn->confScreen->options) { - tmp = xf86optionListDup(pScrn->confScreen->options); - if (pScrn->options) - pScrn->options = xf86optionListMerge(pScrn->options, tmp); - else - pScrn->options = tmp; - } - if (pScrn->display->options) { - tmp = xf86optionListDup(pScrn->display->options); - if (pScrn->options) - pScrn->options = xf86optionListMerge(pScrn->options, tmp); - else - pScrn->options = tmp; - } - if (extras) { - tmp = xf86optionListDup(extras); - if (pScrn->options) - pScrn->options = xf86optionListMerge(pScrn->options, tmp); - else - pScrn->options = tmp; - } -} - -/* - * xf86CollectInputOptions collects the options for an InputDevice. - * This function requires that the following has been initialised: - * - * pInfo->conf_idev - * - * The extraOpts parameter may optionally contain a list of additional options - * to include. - * - * The order of precedence for options is: - * - * extraOpts, pInfo->conf_idev->extraOptions, - * pInfo->conf_idev->commonOptions, defaultOpts - */ - -void -xf86CollectInputOptions(InputInfoPtr pInfo, const char **defaultOpts, - pointer extraOpts) -{ - XF86OptionPtr tmp; - XF86OptionPtr extras = (XF86OptionPtr)extraOpts; - - pInfo->options = NULL; - if (defaultOpts) { - pInfo->options = xf86OptionListCreate(defaultOpts, -1, 0); - } - if (pInfo->conf_idev && pInfo->conf_idev->commonOptions) { - tmp = xf86optionListDup(pInfo->conf_idev->commonOptions); - if (pInfo->options) - pInfo->options = xf86optionListMerge(pInfo->options, tmp); - else - pInfo->options = tmp; - } - if (pInfo->conf_idev && pInfo->conf_idev->extraOptions) { - tmp = xf86optionListDup(pInfo->conf_idev->extraOptions); - if (pInfo->options) - pInfo->options = xf86optionListMerge(pInfo->options, tmp); - else - pInfo->options = tmp; - } - if (extras) { - tmp = xf86optionListDup(extras); - if (pInfo->options) - pInfo->options = xf86optionListMerge(pInfo->options, tmp); - else - pInfo->options = tmp; - } -} - -/* Created for new XInput stuff -- essentially extensions to the parser */ - -static int -LookupIntOption(pointer optlist, const char *name, int deflt, Bool markUsed) -{ - OptionInfoRec o; - - o.name = name; - o.type = OPTV_INTEGER; - if (ParseOptionValue(-1, optlist, &o, markUsed)) - deflt = o.value.num; - return deflt; -} - - -static double -LookupRealOption(pointer optlist, const char *name, double deflt, - Bool markUsed) -{ - OptionInfoRec o; - - o.name = name; - o.type = OPTV_REAL; - if (ParseOptionValue(-1, optlist, &o, markUsed)) - deflt = o.value.realnum; - return deflt; -} - - -static char * -LookupStrOption(pointer optlist, const char *name, char *deflt, Bool markUsed) -{ - OptionInfoRec o; - - o.name = name; - o.type = OPTV_STRING; - if (ParseOptionValue(-1, optlist, &o, markUsed)) - deflt = o.value.str; - if (deflt) - return xstrdup(deflt); - else - return NULL; -} - - -static int -LookupBoolOption(pointer optlist, const char *name, int deflt, Bool markUsed) -{ - OptionInfoRec o; - - o.name = name; - o.type = OPTV_BOOLEAN; - if (ParseOptionValue(-1, optlist, &o, markUsed)) - deflt = o.value.bool; - return deflt; -} - -/* These xf86Set* functions are intended for use by non-screen specific code */ - -int -xf86SetIntOption(pointer optlist, const char *name, int deflt) -{ - return LookupIntOption(optlist, name, deflt, TRUE); -} - - -double -xf86SetRealOption(pointer optlist, const char *name, double deflt) -{ - return LookupRealOption(optlist, name, deflt, TRUE); -} - - -char * -xf86SetStrOption(pointer optlist, const char *name, char *deflt) -{ - return LookupStrOption(optlist, name, deflt, TRUE); -} - - -int -xf86SetBoolOption(pointer optlist, const char *name, int deflt) -{ - return LookupBoolOption(optlist, name, deflt, TRUE); -} - -/* - * These are like the Set*Option functions, but they don't mark the options - * as used. - */ -int -xf86CheckIntOption(pointer optlist, const char *name, int deflt) -{ - return LookupIntOption(optlist, name, deflt, FALSE); -} - - -double -xf86CheckRealOption(pointer optlist, const char *name, double deflt) -{ - return LookupRealOption(optlist, name, deflt, FALSE); -} - - -char * -xf86CheckStrOption(pointer optlist, const char *name, char *deflt) -{ - return LookupStrOption(optlist, name, deflt, FALSE); -} - - -int -xf86CheckBoolOption(pointer optlist, const char *name, int deflt) -{ - return LookupBoolOption(optlist, name, deflt, FALSE); -} - -/* - * addNewOption() has the required property of replacing the option value - * if the option is already present. - */ -pointer -xf86ReplaceIntOption(pointer optlist, const char *name, const int val) -{ - char tmp[16]; - sprintf(tmp,"%i",val); - return xf86AddNewOption(optlist,name,tmp); -} - -pointer -xf86ReplaceRealOption(pointer optlist, const char *name, const double val) -{ - char tmp[32]; - snprintf(tmp,32,"%f",val); - return xf86AddNewOption(optlist,name,tmp); -} - -pointer -xf86ReplaceBoolOption(pointer optlist, const char *name, const Bool val) -{ - return xf86AddNewOption(optlist,name,val?"True":"False"); -} - -pointer -xf86ReplaceStrOption(pointer optlist, const char *name, const char* val) -{ - return xf86AddNewOption(optlist,name,val); -} - -pointer -xf86AddNewOption(pointer head, const char *name, const char *val) -{ - /* XXX These should actually be allocated in the parser library. */ - char *tmp = strdup(val); - char *tmp_name = strdup(name); - - return xf86addNewOption(head, tmp_name, tmp); -} - - -pointer -xf86NewOption(char *name, char *value) -{ - return xf86newOption(name, value); -} - - -pointer -xf86NextOption(pointer list) -{ - return xf86nextOption(list); -} - -pointer -xf86OptionListCreate(const char **options, int count, int used) -{ - return xf86optionListCreate(options, count, used); -} - -pointer -xf86OptionListMerge(pointer head, pointer tail) -{ - return xf86optionListMerge(head, tail); -} - -void -xf86OptionListFree(pointer opt) -{ - xf86optionListFree(opt); -} - -char * -xf86OptionName(pointer opt) -{ - return xf86optionName(opt); -} - -char * -xf86OptionValue(pointer opt) -{ - return xf86optionValue(opt); -} - -void -xf86OptionListReport(pointer parm) -{ - XF86OptionPtr opts = parm; - - while(opts) { - if (xf86optionValue(opts)) - xf86ErrorFVerb(5, "\tOption \"%s\" \"%s\"\n", - xf86optionName(opts), xf86optionValue(opts)); - else - xf86ErrorFVerb( 5, "\tOption \"%s\"\n", xf86optionName(opts)); - opts = xf86nextOption(opts); - } -} - -/* End of XInput-caused section */ - -pointer -xf86FindOption(pointer options, const char *name) -{ - return xf86findOption(options, name); -} - - -char * -xf86FindOptionValue(pointer options, const char *name) -{ - return xf86findOptionValue(options, name); -} - - -void -xf86MarkOptionUsed(pointer option) -{ - if (option != NULL) - ((XF86OptionPtr)option)->opt_used = TRUE; -} - - -void -xf86MarkOptionUsedByName(pointer options, const char *name) -{ - XF86OptionPtr opt; - - opt = xf86findOption(options, name); - if (opt != NULL) - opt->opt_used = TRUE; -} - -Bool -xf86CheckIfOptionUsed(pointer option) -{ - if (option != NULL) - return ((XF86OptionPtr)option)->opt_used; - else - return FALSE; -} - -Bool -xf86CheckIfOptionUsedByName(pointer options, const char *name) -{ - XF86OptionPtr opt; - - opt = xf86findOption(options, name); - if (opt != NULL) - return opt->opt_used; - else - return FALSE; -} - -void -xf86ShowUnusedOptions(int scrnIndex, pointer options) -{ - XF86OptionPtr opt = options; - - while (opt) { - if (opt->opt_name && !opt->opt_used) { - xf86DrvMsg(scrnIndex, X_WARNING, "Option \"%s\" is not used\n", - opt->opt_name); - } - opt = opt->list.next; - } -} - - -static Bool -GetBoolValue(OptionInfoPtr p, const char *s) -{ - return xf86getBoolValue(&p->value.bool, s); -} - -static Bool -ParseOptionValue(int scrnIndex, pointer options, OptionInfoPtr p, - Bool markUsed) -{ - char *s, *end; - Bool wasUsed = FALSE; - - if ((s = xf86findOptionValue(options, p->name)) != NULL) { - if (markUsed) { - wasUsed = xf86CheckIfOptionUsedByName(options, p->name); - xf86MarkOptionUsedByName(options, p->name); - } - switch (p->type) { - case OPTV_INTEGER: - if (*s == '\0') { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires an integer value\n", - p->name); - p->found = FALSE; - } else { - p->value.num = strtoul(s, &end, 0); - if (*end == '\0') { - p->found = TRUE; - } else { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires an integer value\n", - p->name); - p->found = FALSE; - } - } - break; - case OPTV_STRING: - if (*s == '\0') { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires an string value\n", - p->name); - p->found = FALSE; - } else { - p->value.str = s; - p->found = TRUE; - } - break; - case OPTV_ANYSTR: - p->value.str = s; - p->found = TRUE; - break; - case OPTV_REAL: - if (*s == '\0') { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires a floating point value\n", - p->name); - p->found = FALSE; - } else { - p->value.realnum = strtod(s, &end); - if (*end == '\0') { - p->found = TRUE; - } else { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires a floating point value\n", - p->name); - p->found = FALSE; - } - } - break; - case OPTV_BOOLEAN: - if (GetBoolValue(p, s)) { - p->found = TRUE; - } else { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires a boolean value\n", p->name); - p->found = FALSE; - } - break; - case OPTV_FREQ: - if (*s == '\0') { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires a frequency value\n", - p->name); - p->found = FALSE; - } else { - double freq = strtod(s, &end); - int units = 0; - - if (end != s) { - p->found = TRUE; - if (!xf86NameCmp(end, "Hz")) - units = 1; - else if (!xf86NameCmp(end, "kHz") || - !xf86NameCmp(end, "k")) - units = 1000; - else if (!xf86NameCmp(end, "MHz") || - !xf86NameCmp(end, "M")) - units = 1000000; - else { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires a frequency value\n", - p->name); - p->found = FALSE; - } - if (p->found) - freq *= (double)units; - } else { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires a frequency value\n", - p->name); - p->found = FALSE; - } - if (p->found) { - p->value.freq.freq = freq; - p->value.freq.units = units; - } - } - break; - case OPTV_NONE: - /* Should never get here */ - p->found = FALSE; - break; - } - if (p->found && markUsed) { - int verb = 2; - if (wasUsed) - verb = 4; - xf86DrvMsgVerb(scrnIndex, X_CONFIG, verb, "Option \"%s\"", p->name); - if (!(p->type == OPTV_BOOLEAN && *s == 0)) { - xf86ErrorFVerb(verb, " \"%s\"", s); - } - xf86ErrorFVerb(verb, "\n"); - } - } else if (p->type == OPTV_BOOLEAN) { - /* Look for matches with options with or without a "No" prefix. */ - char *n, *newn; - OptionInfoRec opt; - - n = xf86NormalizeName(p->name); - if (!n) { - p->found = FALSE; - return FALSE; - } - if (strncmp(n, "no", 2) == 0) { - newn = n + 2; - } else { - xfree(n); - n = xalloc(strlen(p->name) + 2 + 1); - if (!n) { - p->found = FALSE; - return FALSE; - } - strcpy(n, "No"); - strcat(n, p->name); - newn = n; - } - if ((s = xf86findOptionValue(options, newn)) != NULL) { - if (markUsed) - xf86MarkOptionUsedByName(options, newn); - if (GetBoolValue(&opt, s)) { - p->value.bool = !opt.value.bool; - p->found = TRUE; - } else { - xf86DrvMsg(scrnIndex, X_WARNING, - "Option \"%s\" requires a boolean value\n", newn); - p->found = FALSE; - } - } else { - p->found = FALSE; - } - if (p->found && markUsed) { - xf86DrvMsgVerb(scrnIndex, X_CONFIG, 2, "Option \"%s\"", newn); - if (*s != 0) { - xf86ErrorFVerb(2, " \"%s\"", s); - } - xf86ErrorFVerb(2, "\n"); - } - xfree(n); - } else { - p->found = FALSE; - } - return p->found; -} - - -void -xf86ProcessOptions(int scrnIndex, pointer options, OptionInfoPtr optinfo) -{ - OptionInfoPtr p; - - for (p = optinfo; p->name != NULL; p++) { - ParseOptionValue(scrnIndex, options, p, TRUE); - } -} - - -OptionInfoPtr -xf86TokenToOptinfo(const OptionInfoRec *table, int token) -{ - const OptionInfoRec *p, *match = NULL, *set = NULL; - - if (!table) { - ErrorF("xf86TokenToOptinfo: table is NULL\n"); - return NULL; - } - - for (p = table; p->token >= 0; p++) { - if (p->token == token) { - match = p; - if (p->found) - set = p; - } - } - - if (set) - return (OptionInfoPtr)set; - else if (match) - return (OptionInfoPtr)match; - else - return NULL; -} - - -const char * -xf86TokenToOptName(const OptionInfoRec *table, int token) -{ - const OptionInfoRec *p; - - p = xf86TokenToOptinfo(table, token); - return p->name; -} - - -Bool -xf86IsOptionSet(const OptionInfoRec *table, int token) -{ - OptionInfoPtr p; - - p = xf86TokenToOptinfo(table, token); - return (p && p->found); -} - - -char * -xf86GetOptValString(const OptionInfoRec *table, int token) -{ - OptionInfoPtr p; - - p = xf86TokenToOptinfo(table, token); - if (p && p->found) - return p->value.str; - else - return NULL; -} - - -Bool -xf86GetOptValInteger(const OptionInfoRec *table, int token, int *value) -{ - OptionInfoPtr p; - - p = xf86TokenToOptinfo(table, token); - if (p && p->found) { - *value = p->value.num; - return TRUE; - } else - return FALSE; -} - - -Bool -xf86GetOptValULong(const OptionInfoRec *table, int token, unsigned long *value) -{ - OptionInfoPtr p; - - p = xf86TokenToOptinfo(table, token); - if (p && p->found) { - *value = p->value.num; - return TRUE; - } else - return FALSE; -} - - -Bool -xf86GetOptValReal(const OptionInfoRec *table, int token, double *value) -{ - OptionInfoPtr p; - - p = xf86TokenToOptinfo(table, token); - if (p && p->found) { - *value = p->value.realnum; - return TRUE; - } else - return FALSE; -} - - -Bool -xf86GetOptValFreq(const OptionInfoRec *table, int token, - OptFreqUnits expectedUnits, double *value) -{ - OptionInfoPtr p; - - p = xf86TokenToOptinfo(table, token); - if (p && p->found) { - if (p->value.freq.units > 0) { - /* Units give, so the scaling is known. */ - switch (expectedUnits) { - case OPTUNITS_HZ: - *value = p->value.freq.freq; - break; - case OPTUNITS_KHZ: - *value = p->value.freq.freq / 1000.0; - break; - case OPTUNITS_MHZ: - *value = p->value.freq.freq / 1000000.0; - break; - } - } else { - /* No units given, so try to guess the scaling. */ - switch (expectedUnits) { - case OPTUNITS_HZ: - *value = p->value.freq.freq; - break; - case OPTUNITS_KHZ: - if (p->value.freq.freq > 1000.0) - *value = p->value.freq.freq / 1000.0; - else - *value = p->value.freq.freq; - break; - case OPTUNITS_MHZ: - if (p->value.freq.freq > 1000000.0) - *value = p->value.freq.freq / 1000000.0; - else if (p->value.freq.freq > 1000.0) - *value = p->value.freq.freq / 1000.0; - else - *value = p->value.freq.freq; - } - } - return TRUE; - } else - return FALSE; -} - - -Bool -xf86GetOptValBool(const OptionInfoRec *table, int token, Bool *value) -{ - OptionInfoPtr p; - - p = xf86TokenToOptinfo(table, token); - if (p && p->found) { - *value = p->value.bool; - return TRUE; - } else - return FALSE; -} - - -Bool -xf86ReturnOptValBool(const OptionInfoRec *table, int token, Bool def) -{ - OptionInfoPtr p; - - p = xf86TokenToOptinfo(table, token); - if (p && p->found) { - return p->value.bool; - } else - return def; -} - - -int -xf86NameCmp(const char *s1, const char *s2) -{ - return xf86nameCompare(s1, s2); -} - -char * -xf86NormalizeName(const char *s) -{ - char *ret, *q; - const char *p; - - if (s == NULL) - return NULL; - - ret = xalloc(strlen(s) + 1); - for (p = s, q = ret; *p != 0; p++) { - switch (*p) { - case '_': - case ' ': - case '\t': - continue; - default: - if (isupper(*p)) - *q++ = tolower(*p); - else - *q++ = *p; - } - } - *q = '\0'; - return ret; -} +/* + * Copyright (c) 1998-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * Author: David Dawes <dawes@xfree86.org> + * + * This file includes public option handling functions. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <stdlib.h> +#include <ctype.h> +#include <X11/X.h> +#include "os.h" +#include "xf86.h" +#include "xf86Xinput.h" +#include "xf86Optrec.h" +#include "xf86Parser.h" + +static Bool ParseOptionValue(int scrnIndex, pointer options, OptionInfoPtr p, + Bool markUsed); + +/* + * xf86CollectOptions collects the options from each of the config file + * sections used by the screen and puts the combined list in pScrn->options. + * This function requires that the following have been initialised: + * + * pScrn->confScreen + * pScrn->Entities[i]->device + * pScrn->display + * pScrn->monitor + * + * The extraOpts parameter may optionally contain a list of additional options + * to include. + * + * The order of precedence for options is: + * + * extraOpts, display, confScreen, monitor, device + */ + +void +xf86CollectOptions(ScrnInfoPtr pScrn, pointer extraOpts) +{ + XF86OptionPtr tmp; + XF86OptionPtr extras = (XF86OptionPtr)extraOpts; + GDevPtr device; + + int i; + + pScrn->options = NULL; + + for (i=pScrn->numEntities - 1; i >= 0; i--) { + device = xf86GetDevFromEntity(pScrn->entityList[i], + pScrn->entityInstanceList[i]); + if (device && device->options) { + tmp = xf86optionListDup(device->options); + if (pScrn->options) + xf86optionListMerge(pScrn->options,tmp); + else + pScrn->options = tmp; + } + } + if (pScrn->monitor->options) { + tmp = xf86optionListDup(pScrn->monitor->options); + if (pScrn->options) + pScrn->options = xf86optionListMerge(pScrn->options, tmp); + else + pScrn->options = tmp; + } + if (pScrn->confScreen->options) { + tmp = xf86optionListDup(pScrn->confScreen->options); + if (pScrn->options) + pScrn->options = xf86optionListMerge(pScrn->options, tmp); + else + pScrn->options = tmp; + } + if (pScrn->display->options) { + tmp = xf86optionListDup(pScrn->display->options); + if (pScrn->options) + pScrn->options = xf86optionListMerge(pScrn->options, tmp); + else + pScrn->options = tmp; + } + if (extras) { + tmp = xf86optionListDup(extras); + if (pScrn->options) + pScrn->options = xf86optionListMerge(pScrn->options, tmp); + else + pScrn->options = tmp; + } +} + +/* + * xf86CollectInputOptions collects the options for an InputDevice. + * This function requires that the following has been initialised: + * + * pInfo->conf_idev + * + * The extraOpts parameter may optionally contain a list of additional options + * to include. + * + * The order of precedence for options is: + * + * extraOpts, pInfo->conf_idev->extraOptions, + * pInfo->conf_idev->commonOptions, defaultOpts + */ + +void +xf86CollectInputOptions(InputInfoPtr pInfo, const char **defaultOpts, + pointer extraOpts) +{ + XF86OptionPtr tmp; + XF86OptionPtr extras = (XF86OptionPtr)extraOpts; + + pInfo->options = NULL; + if (defaultOpts) { + pInfo->options = xf86OptionListCreate(defaultOpts, -1, 0); + } + if (pInfo->conf_idev && pInfo->conf_idev->commonOptions) { + tmp = xf86optionListDup(pInfo->conf_idev->commonOptions); + if (pInfo->options) + pInfo->options = xf86optionListMerge(pInfo->options, tmp); + else + pInfo->options = tmp; + } + if (pInfo->conf_idev && pInfo->conf_idev->extraOptions) { + tmp = xf86optionListDup(pInfo->conf_idev->extraOptions); + if (pInfo->options) + pInfo->options = xf86optionListMerge(pInfo->options, tmp); + else + pInfo->options = tmp; + } + if (extras) { + tmp = xf86optionListDup(extras); + if (pInfo->options) + pInfo->options = xf86optionListMerge(pInfo->options, tmp); + else + pInfo->options = tmp; + } +} + +/* Created for new XInput stuff -- essentially extensions to the parser */ + +static int +LookupIntOption(pointer optlist, const char *name, int deflt, Bool markUsed) +{ + OptionInfoRec o; + + o.name = name; + o.type = OPTV_INTEGER; + if (ParseOptionValue(-1, optlist, &o, markUsed)) + deflt = o.value.num; + return deflt; +} + + +static double +LookupRealOption(pointer optlist, const char *name, double deflt, + Bool markUsed) +{ + OptionInfoRec o; + + o.name = name; + o.type = OPTV_REAL; + if (ParseOptionValue(-1, optlist, &o, markUsed)) + deflt = o.value.realnum; + return deflt; +} + + +static char * +LookupStrOption(pointer optlist, const char *name, char *deflt, Bool markUsed) +{ + OptionInfoRec o; + + o.name = name; + o.type = OPTV_STRING; + if (ParseOptionValue(-1, optlist, &o, markUsed)) + deflt = o.value.str; + if (deflt) + return xstrdup(deflt); + else + return NULL; +} + + +static int +LookupBoolOption(pointer optlist, const char *name, int deflt, Bool markUsed) +{ + OptionInfoRec o; + + o.name = name; + o.type = OPTV_BOOLEAN; + if (ParseOptionValue(-1, optlist, &o, markUsed)) + deflt = o.value.bool; + return deflt; +} + +/* These xf86Set* functions are intended for use by non-screen specific code */ + +int +xf86SetIntOption(pointer optlist, const char *name, int deflt) +{ + return LookupIntOption(optlist, name, deflt, TRUE); +} + + +double +xf86SetRealOption(pointer optlist, const char *name, double deflt) +{ + return LookupRealOption(optlist, name, deflt, TRUE); +} + + +char * +xf86SetStrOption(pointer optlist, const char *name, char *deflt) +{ + return LookupStrOption(optlist, name, deflt, TRUE); +} + + +int +xf86SetBoolOption(pointer optlist, const char *name, int deflt) +{ + return LookupBoolOption(optlist, name, deflt, TRUE); +} + +/* + * These are like the Set*Option functions, but they don't mark the options + * as used. + */ +int +xf86CheckIntOption(pointer optlist, const char *name, int deflt) +{ + return LookupIntOption(optlist, name, deflt, FALSE); +} + + +double +xf86CheckRealOption(pointer optlist, const char *name, double deflt) +{ + return LookupRealOption(optlist, name, deflt, FALSE); +} + + +char * +xf86CheckStrOption(pointer optlist, const char *name, char *deflt) +{ + return LookupStrOption(optlist, name, deflt, FALSE); +} + + +int +xf86CheckBoolOption(pointer optlist, const char *name, int deflt) +{ + return LookupBoolOption(optlist, name, deflt, FALSE); +} + +/* + * addNewOption() has the required property of replacing the option value + * if the option is already present. + */ +pointer +xf86ReplaceIntOption(pointer optlist, const char *name, const int val) +{ + char tmp[16]; + sprintf(tmp,"%i",val); + return xf86AddNewOption(optlist,name,tmp); +} + +pointer +xf86ReplaceRealOption(pointer optlist, const char *name, const double val) +{ + char tmp[32]; + snprintf(tmp,32,"%f",val); + return xf86AddNewOption(optlist,name,tmp); +} + +pointer +xf86ReplaceBoolOption(pointer optlist, const char *name, const Bool val) +{ + return xf86AddNewOption(optlist,name,val?"True":"False"); +} + +pointer +xf86ReplaceStrOption(pointer optlist, const char *name, const char* val) +{ + return xf86AddNewOption(optlist,name,val); +} + +pointer +xf86AddNewOption(pointer head, const char *name, const char *val) +{ + /* XXX These should actually be allocated in the parser library. */ + char *tmp = strdup(val); + char *tmp_name = strdup(name); + + return xf86addNewOption(head, tmp_name, tmp); +} + + +pointer +xf86NewOption(char *name, char *value) +{ + return xf86newOption(name, value); +} + + +pointer +xf86NextOption(pointer list) +{ + return xf86nextOption(list); +} + +pointer +xf86OptionListCreate(const char **options, int count, int used) +{ + return xf86optionListCreate(options, count, used); +} + +pointer +xf86OptionListMerge(pointer head, pointer tail) +{ + return xf86optionListMerge(head, tail); +} + +void +xf86OptionListFree(pointer opt) +{ + xf86optionListFree(opt); +} + +char * +xf86OptionName(pointer opt) +{ + return xf86optionName(opt); +} + +char * +xf86OptionValue(pointer opt) +{ + return xf86optionValue(opt); +} + +void +xf86OptionListReport(pointer parm) +{ + XF86OptionPtr opts = parm; + + while(opts) { + if (xf86optionValue(opts)) + xf86ErrorFVerb(5, "\tOption \"%s\" \"%s\"\n", + xf86optionName(opts), xf86optionValue(opts)); + else + xf86ErrorFVerb( 5, "\tOption \"%s\"\n", xf86optionName(opts)); + opts = xf86nextOption(opts); + } +} + +/* End of XInput-caused section */ + +pointer +xf86FindOption(pointer options, const char *name) +{ + return xf86findOption(options, name); +} + + +char * +xf86FindOptionValue(pointer options, const char *name) +{ + return xf86findOptionValue(options, name); +} + + +void +xf86MarkOptionUsed(pointer option) +{ + if (option != NULL) + ((XF86OptionPtr)option)->opt_used = TRUE; +} + + +void +xf86MarkOptionUsedByName(pointer options, const char *name) +{ + XF86OptionPtr opt; + + opt = xf86findOption(options, name); + if (opt != NULL) + opt->opt_used = TRUE; +} + +Bool +xf86CheckIfOptionUsed(pointer option) +{ + if (option != NULL) + return ((XF86OptionPtr)option)->opt_used; + else + return FALSE; +} + +Bool +xf86CheckIfOptionUsedByName(pointer options, const char *name) +{ + XF86OptionPtr opt; + + opt = xf86findOption(options, name); + if (opt != NULL) + return opt->opt_used; + else + return FALSE; +} + +void +xf86ShowUnusedOptions(int scrnIndex, pointer options) +{ + XF86OptionPtr opt = options; + + while (opt) { + if (opt->opt_name && !opt->opt_used) { + xf86DrvMsg(scrnIndex, X_WARNING, "Option \"%s\" is not used\n", + opt->opt_name); + } + opt = opt->list.next; + } +} + + +static Bool +GetBoolValue(OptionInfoPtr p, const char *s) +{ + return xf86getBoolValue(&p->value.bool, s); +} + +static Bool +ParseOptionValue(int scrnIndex, pointer options, OptionInfoPtr p, + Bool markUsed) +{ + char *s, *end; + Bool wasUsed = FALSE; + + if ((s = xf86findOptionValue(options, p->name)) != NULL) { + if (markUsed) { + wasUsed = xf86CheckIfOptionUsedByName(options, p->name); + xf86MarkOptionUsedByName(options, p->name); + } + switch (p->type) { + case OPTV_INTEGER: + if (*s == '\0') { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires an integer value\n", + p->name); + p->found = FALSE; + } else { + p->value.num = strtoul(s, &end, 0); + if (*end == '\0') { + p->found = TRUE; + } else { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires an integer value\n", + p->name); + p->found = FALSE; + } + } + break; + case OPTV_STRING: + if (*s == '\0') { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires an string value\n", + p->name); + p->found = FALSE; + } else { + p->value.str = s; + p->found = TRUE; + } + break; + case OPTV_ANYSTR: + p->value.str = s; + p->found = TRUE; + break; + case OPTV_REAL: + if (*s == '\0') { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires a floating point value\n", + p->name); + p->found = FALSE; + } else { + p->value.realnum = strtod(s, &end); + if (*end == '\0') { + p->found = TRUE; + } else { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires a floating point value\n", + p->name); + p->found = FALSE; + } + } + break; + case OPTV_BOOLEAN: + if (GetBoolValue(p, s)) { + p->found = TRUE; + } else { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires a boolean value\n", p->name); + p->found = FALSE; + } + break; + case OPTV_FREQ: + if (*s == '\0') { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires a frequency value\n", + p->name); + p->found = FALSE; + } else { + double freq = strtod(s, &end); + int units = 0; + + if (end != s) { + p->found = TRUE; + if (!xf86NameCmp(end, "Hz")) + units = 1; + else if (!xf86NameCmp(end, "kHz") || + !xf86NameCmp(end, "k")) + units = 1000; + else if (!xf86NameCmp(end, "MHz") || + !xf86NameCmp(end, "M")) + units = 1000000; + else { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires a frequency value\n", + p->name); + p->found = FALSE; + } + if (p->found) + freq *= (double)units; + } else { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires a frequency value\n", + p->name); + p->found = FALSE; + } + if (p->found) { + p->value.freq.freq = freq; + p->value.freq.units = units; + } + } + break; + case OPTV_NONE: + /* Should never get here */ + p->found = FALSE; + break; + } + if (p->found && markUsed) { + int verb = 2; + if (wasUsed) + verb = 4; + xf86DrvMsgVerb(scrnIndex, X_CONFIG, verb, "Option \"%s\"", p->name); + if (!(p->type == OPTV_BOOLEAN && *s == 0)) { + xf86ErrorFVerb(verb, " \"%s\"", s); + } + xf86ErrorFVerb(verb, "\n"); + } + } else if (p->type == OPTV_BOOLEAN) { + /* Look for matches with options with or without a "No" prefix. */ + char *n, *newn; + OptionInfoRec opt; + + n = xf86NormalizeName(p->name); + if (!n) { + p->found = FALSE; + return FALSE; + } + if (strncmp(n, "no", 2) == 0) { + newn = n + 2; + } else { + free(n); + n = malloc(strlen(p->name) + 2 + 1); + if (!n) { + p->found = FALSE; + return FALSE; + } + strcpy(n, "No"); + strcat(n, p->name); + newn = n; + } + if ((s = xf86findOptionValue(options, newn)) != NULL) { + if (markUsed) + xf86MarkOptionUsedByName(options, newn); + if (GetBoolValue(&opt, s)) { + p->value.bool = !opt.value.bool; + p->found = TRUE; + } else { + xf86DrvMsg(scrnIndex, X_WARNING, + "Option \"%s\" requires a boolean value\n", newn); + p->found = FALSE; + } + } else { + p->found = FALSE; + } + if (p->found && markUsed) { + xf86DrvMsgVerb(scrnIndex, X_CONFIG, 2, "Option \"%s\"", newn); + if (*s != 0) { + xf86ErrorFVerb(2, " \"%s\"", s); + } + xf86ErrorFVerb(2, "\n"); + } + free(n); + } else { + p->found = FALSE; + } + return p->found; +} + + +void +xf86ProcessOptions(int scrnIndex, pointer options, OptionInfoPtr optinfo) +{ + OptionInfoPtr p; + + for (p = optinfo; p->name != NULL; p++) { + ParseOptionValue(scrnIndex, options, p, TRUE); + } +} + + +OptionInfoPtr +xf86TokenToOptinfo(const OptionInfoRec *table, int token) +{ + const OptionInfoRec *p, *match = NULL, *set = NULL; + + if (!table) { + ErrorF("xf86TokenToOptinfo: table is NULL\n"); + return NULL; + } + + for (p = table; p->token >= 0; p++) { + if (p->token == token) { + match = p; + if (p->found) + set = p; + } + } + + if (set) + return (OptionInfoPtr)set; + else if (match) + return (OptionInfoPtr)match; + else + return NULL; +} + + +const char * +xf86TokenToOptName(const OptionInfoRec *table, int token) +{ + const OptionInfoRec *p; + + p = xf86TokenToOptinfo(table, token); + return p->name; +} + + +Bool +xf86IsOptionSet(const OptionInfoRec *table, int token) +{ + OptionInfoPtr p; + + p = xf86TokenToOptinfo(table, token); + return (p && p->found); +} + + +char * +xf86GetOptValString(const OptionInfoRec *table, int token) +{ + OptionInfoPtr p; + + p = xf86TokenToOptinfo(table, token); + if (p && p->found) + return p->value.str; + else + return NULL; +} + + +Bool +xf86GetOptValInteger(const OptionInfoRec *table, int token, int *value) +{ + OptionInfoPtr p; + + p = xf86TokenToOptinfo(table, token); + if (p && p->found) { + *value = p->value.num; + return TRUE; + } else + return FALSE; +} + + +Bool +xf86GetOptValULong(const OptionInfoRec *table, int token, unsigned long *value) +{ + OptionInfoPtr p; + + p = xf86TokenToOptinfo(table, token); + if (p && p->found) { + *value = p->value.num; + return TRUE; + } else + return FALSE; +} + + +Bool +xf86GetOptValReal(const OptionInfoRec *table, int token, double *value) +{ + OptionInfoPtr p; + + p = xf86TokenToOptinfo(table, token); + if (p && p->found) { + *value = p->value.realnum; + return TRUE; + } else + return FALSE; +} + + +Bool +xf86GetOptValFreq(const OptionInfoRec *table, int token, + OptFreqUnits expectedUnits, double *value) +{ + OptionInfoPtr p; + + p = xf86TokenToOptinfo(table, token); + if (p && p->found) { + if (p->value.freq.units > 0) { + /* Units give, so the scaling is known. */ + switch (expectedUnits) { + case OPTUNITS_HZ: + *value = p->value.freq.freq; + break; + case OPTUNITS_KHZ: + *value = p->value.freq.freq / 1000.0; + break; + case OPTUNITS_MHZ: + *value = p->value.freq.freq / 1000000.0; + break; + } + } else { + /* No units given, so try to guess the scaling. */ + switch (expectedUnits) { + case OPTUNITS_HZ: + *value = p->value.freq.freq; + break; + case OPTUNITS_KHZ: + if (p->value.freq.freq > 1000.0) + *value = p->value.freq.freq / 1000.0; + else + *value = p->value.freq.freq; + break; + case OPTUNITS_MHZ: + if (p->value.freq.freq > 1000000.0) + *value = p->value.freq.freq / 1000000.0; + else if (p->value.freq.freq > 1000.0) + *value = p->value.freq.freq / 1000.0; + else + *value = p->value.freq.freq; + } + } + return TRUE; + } else + return FALSE; +} + + +Bool +xf86GetOptValBool(const OptionInfoRec *table, int token, Bool *value) +{ + OptionInfoPtr p; + + p = xf86TokenToOptinfo(table, token); + if (p && p->found) { + *value = p->value.bool; + return TRUE; + } else + return FALSE; +} + + +Bool +xf86ReturnOptValBool(const OptionInfoRec *table, int token, Bool def) +{ + OptionInfoPtr p; + + p = xf86TokenToOptinfo(table, token); + if (p && p->found) { + return p->value.bool; + } else + return def; +} + + +int +xf86NameCmp(const char *s1, const char *s2) +{ + return xf86nameCompare(s1, s2); +} + +char * +xf86NormalizeName(const char *s) +{ + char *ret, *q; + const char *p; + + if (s == NULL) + return NULL; + + ret = malloc(strlen(s) + 1); + for (p = s, q = ret; *p != 0; p++) { + switch (*p) { + case '_': + case ' ': + case '\t': + continue; + default: + if (isupper(*p)) + *q++ = tolower(*p); + else + *q++ = *p; + } + } + *q = '\0'; + return ret; +} diff --git a/xorg-server/hw/xfree86/common/xf86Privstr.h b/xorg-server/hw/xfree86/common/xf86Privstr.h index b2095aab1..6138b6bec 100644 --- a/xorg-server/hw/xfree86/common/xf86Privstr.h +++ b/xorg-server/hw/xfree86/common/xf86Privstr.h @@ -1,173 +1,170 @@ - -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * This file contains definitions of the private XFree86 data structures/types. - * None of the data structures here should be used by video drivers. - */ - -#ifndef _XF86PRIVSTR_H -#define _XF86PRIVSTR_H - -#include "xf86str.h" - -typedef enum { - LogNone, - LogFlush, - LogSync -} Log; - -typedef enum { - XF86_GlxVisualsMinimal, - XF86_GlxVisualsTypical, - XF86_GlxVisualsAll, -} XF86_GlxVisuals; - -/* - * xf86InfoRec contains global parameters which the video drivers never - * need to access. Global parameters which the video drivers do need - * should be individual globals. - */ - -typedef struct { - int consoleFd; - int vtno; - Bool vtSysreq; - - /* event handler part */ - int lastEventTime; - Bool vtRequestsPending; -#ifdef sun - int vtPendingNum; -#endif - Bool dontVTSwitch; - Bool dontZap; - Bool dontZoom; - Bool notrapSignals; /* don't exit cleanly - die at fault */ - Bool caughtSignal; - - /* graphics part */ - ScreenPtr currentScreen; -#if defined(CSRG_BASED) || defined(__FreeBSD_kernel__) - int screenFd; /* fd for memory mapped access to - * vga card */ - int consType; /* Which console driver? */ -#endif - - /* Other things */ - Bool allowMouseOpenFail; - Bool vidModeEnabled; /* VidMode extension enabled */ - Bool vidModeAllowNonLocal; /* allow non-local VidMode - * connections */ - Bool miscModInDevEnabled; /* Allow input devices to be - * changed */ - Bool miscModInDevAllowNonLocal; - Bool useSIGIO; /* Use SIGIO for handling - input device events */ - Pix24Flags pixmap24; - MessageType pix24From; -#ifdef SUPPORT_PC98 - Bool pc98; -#endif - Bool pmFlag; - Log log; - Bool kbdCustomKeycodes; - Bool disableRandR; - MessageType randRFrom; - Bool aiglx; - MessageType aiglxFrom; - XF86_GlxVisuals glxVisuals; - MessageType glxVisualsFrom; - - Bool useDefaultFontPath; - MessageType useDefaultFontPathFrom; - Bool ignoreABI; - - Bool allowEmptyInput; /* Allow the server to start with no input - * devices. */ - Bool autoAddDevices; /* Whether to succeed NIDR, or ignore. */ - Bool autoEnableDevices; /* Whether to enable, or let the client - * control. */ - - Bool dri2; - MessageType dri2From; -} xf86InfoRec, *xf86InfoPtr; - -#ifdef DPMSExtension -/* Private info for DPMS */ -typedef struct { - CloseScreenProcPtr CloseScreen; - Bool Enabled; - int Flags; -} DPMSRec, *DPMSPtr; -#endif - -#ifdef XF86VIDMODE -/* Private info for Video Mode Extentsion */ -typedef struct { - DisplayModePtr First; - DisplayModePtr Next; - int Flags; - CloseScreenProcPtr CloseScreen; -} VidModeRec, *VidModePtr; -#endif - -/* Information for root window properties. */ -typedef struct _RootWinProp { - struct _RootWinProp * next; - char * name; - Atom type; - short format; - long size; - pointer data; -} RootWinProp, *RootWinPropPtr; - -/* private resource types */ -#define ResNoAvoid ResBios - -/* ISC's cc can't handle ~ of UL constants, so explicitly type cast them. */ -#define XLED1 ((unsigned long) 0x00000001) -#define XLED2 ((unsigned long) 0x00000002) -#define XLED3 ((unsigned long) 0x00000004) -#define XLED4 ((unsigned long) 0x00000008) -#define XCAPS ((unsigned long) 0x20000000) -#define XNUM ((unsigned long) 0x40000000) -#define XSCR ((unsigned long) 0x80000000) -#define XCOMP ((unsigned long) 0x00008000) - -/* BSD console driver types (consType) */ -#if defined(CSRG_BASED) || defined(__FreeBSD_kernel__) -#define PCCONS 0 -#define CODRV011 1 -#define CODRV01X 2 -#define SYSCONS 8 -#define PCVT 16 -#define WSCONS 32 -#endif - -#endif /* _XF86PRIVSTR_H */ + +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * This file contains definitions of the private XFree86 data structures/types. + * None of the data structures here should be used by video drivers. + */ + +#ifndef _XF86PRIVSTR_H +#define _XF86PRIVSTR_H + +#include "xf86str.h" + +typedef enum { + LogNone, + LogFlush, + LogSync +} Log; + +typedef enum { + XF86_GlxVisualsMinimal, + XF86_GlxVisualsTypical, + XF86_GlxVisualsAll, +} XF86_GlxVisuals; + +/* + * xf86InfoRec contains global parameters which the video drivers never + * need to access. Global parameters which the video drivers do need + * should be individual globals. + */ + +typedef struct { + int consoleFd; + int vtno; + Bool vtSysreq; + + /* event handler part */ + int lastEventTime; + Bool vtRequestsPending; +#ifdef sun + int vtPendingNum; +#endif + Bool dontVTSwitch; + Bool dontZap; + Bool dontZoom; + Bool notrapSignals; /* don't exit cleanly - die at fault */ + Bool caughtSignal; + + /* graphics part */ + ScreenPtr currentScreen; +#if defined(CSRG_BASED) || defined(__FreeBSD_kernel__) + int screenFd; /* fd for memory mapped access to + * vga card */ + int consType; /* Which console driver? */ +#endif + + /* Other things */ + Bool allowMouseOpenFail; + Bool vidModeEnabled; /* VidMode extension enabled */ + Bool vidModeAllowNonLocal; /* allow non-local VidMode + * connections */ + Bool miscModInDevEnabled; /* Allow input devices to be + * changed */ + Bool miscModInDevAllowNonLocal; + Bool useSIGIO; /* Use SIGIO for handling + input device events */ + Pix24Flags pixmap24; + MessageType pix24From; +#ifdef SUPPORT_PC98 + Bool pc98; +#endif + Bool pmFlag; + Log log; + Bool kbdCustomKeycodes; + Bool disableRandR; + MessageType randRFrom; + Bool aiglx; + MessageType aiglxFrom; + XF86_GlxVisuals glxVisuals; + MessageType glxVisualsFrom; + + Bool useDefaultFontPath; + MessageType useDefaultFontPathFrom; + Bool ignoreABI; + + Bool allowEmptyInput; /* Allow the server to start with no input + * devices. */ + Bool autoAddDevices; /* Whether to succeed NIDR, or ignore. */ + Bool autoEnableDevices; /* Whether to enable, or let the client + * control. */ + + Bool dri2; + MessageType dri2From; +} xf86InfoRec, *xf86InfoPtr; + +#ifdef DPMSExtension +/* Private info for DPMS */ +typedef struct { + CloseScreenProcPtr CloseScreen; + Bool Enabled; + int Flags; +} DPMSRec, *DPMSPtr; +#endif + +#ifdef XF86VIDMODE +/* Private info for Video Mode Extentsion */ +typedef struct { + DisplayModePtr First; + DisplayModePtr Next; + int Flags; + CloseScreenProcPtr CloseScreen; +} VidModeRec, *VidModePtr; +#endif + +/* Information for root window properties. */ +typedef struct _RootWinProp { + struct _RootWinProp * next; + char * name; + Atom type; + short format; + long size; + pointer data; +} RootWinProp, *RootWinPropPtr; + +/* ISC's cc can't handle ~ of UL constants, so explicitly type cast them. */ +#define XLED1 ((unsigned long) 0x00000001) +#define XLED2 ((unsigned long) 0x00000002) +#define XLED3 ((unsigned long) 0x00000004) +#define XLED4 ((unsigned long) 0x00000008) +#define XCAPS ((unsigned long) 0x20000000) +#define XNUM ((unsigned long) 0x40000000) +#define XSCR ((unsigned long) 0x80000000) +#define XCOMP ((unsigned long) 0x00008000) + +/* BSD console driver types (consType) */ +#if defined(CSRG_BASED) || defined(__FreeBSD_kernel__) +#define PCCONS 0 +#define CODRV011 1 +#define CODRV01X 2 +#define SYSCONS 8 +#define PCVT 16 +#define WSCONS 32 +#endif + +#endif /* _XF86PRIVSTR_H */ diff --git a/xorg-server/hw/xfree86/common/xf86RandR.c b/xorg-server/hw/xfree86/common/xf86RandR.c index 86c7bde79..1893974e2 100644 --- a/xorg-server/hw/xfree86/common/xf86RandR.c +++ b/xorg-server/hw/xfree86/common/xf86RandR.c @@ -1,459 +1,459 @@ -/* - * - * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. - * - * 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_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include "os.h" -#include "globals.h" -#include "xf86.h" -#include "xf86str.h" -#include "xf86Priv.h" -#include "xf86DDC.h" -#include "mipointer.h" -#include <randrstr.h> -#include "inputstr.h" - -typedef struct _xf86RandRInfo { - CreateScreenResourcesProcPtr CreateScreenResources; - CloseScreenProcPtr CloseScreen; - int virtualX; - int virtualY; - int mmWidth; - int mmHeight; - Rotation rotation; -} XF86RandRInfoRec, *XF86RandRInfoPtr; - -static int xf86RandRKeyIndex; -static DevPrivateKey xf86RandRKey; - -#define XF86RANDRINFO(p) ((XF86RandRInfoPtr)dixLookupPrivate(&(p)->devPrivates, xf86RandRKey)) - -static int -xf86RandRModeRefresh (DisplayModePtr mode) -{ - if (mode->VRefresh) - return (int) (mode->VRefresh + 0.5); - else if (mode->Clock == 0) - return 0; - else - return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); -} - -static Bool -xf86RandRGetInfo (ScreenPtr pScreen, Rotation *rotations) -{ - RRScreenSizePtr pSize; - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - DisplayModePtr mode; - int refresh0 = 60; - xorgRRModeMM RRModeMM; - - *rotations = RR_Rotate_0; - - for (mode = scrp->modes; mode != NULL ; mode = mode->next) - { - int refresh = xf86RandRModeRefresh (mode); - - if (mode == scrp->modes) - refresh0 = refresh; - - RRModeMM.mode = mode; - RRModeMM.virtX = randrp->virtualX; - RRModeMM.virtY = randrp->virtualY; - RRModeMM.mmWidth = randrp->mmWidth; - RRModeMM.mmHeight = randrp->mmHeight; - - if(scrp->DriverFunc) { - (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); - } - - pSize = RRRegisterSize (pScreen, - mode->HDisplay, mode->VDisplay, - RRModeMM.mmWidth, RRModeMM.mmHeight); - if (!pSize) - return FALSE; - RRRegisterRate (pScreen, pSize, refresh); - if (mode == scrp->currentMode && - mode->HDisplay == scrp->virtualX && mode->VDisplay == scrp->virtualY) - RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); - if (mode->next == scrp->modes) - break; - } - if (scrp->currentMode->HDisplay != randrp->virtualX || - scrp->currentMode->VDisplay != randrp->virtualY) - { - mode = scrp->modes; - - RRModeMM.mode = NULL; - RRModeMM.virtX = randrp->virtualX; - RRModeMM.virtY = randrp->virtualY; - RRModeMM.mmWidth = randrp->mmWidth; - RRModeMM.mmHeight = randrp->mmHeight; - - if(scrp->DriverFunc) { - (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); - } - - pSize = RRRegisterSize (pScreen, - randrp->virtualX, randrp->virtualY, - RRModeMM.mmWidth, RRModeMM.mmHeight); - if (!pSize) - return FALSE; - RRRegisterRate (pScreen, pSize, refresh0); - if (scrp->virtualX == randrp->virtualX && - scrp->virtualY == randrp->virtualY) - { - RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize); - } - } - - /* If there is driver support for randr, let it set our supported rotations */ - if(scrp->DriverFunc) { - xorgRRRotation RRRotation; - - RRRotation.RRRotations = *rotations; - if (!(*scrp->DriverFunc)(scrp, RR_GET_INFO, &RRRotation)) - return TRUE; - *rotations = RRRotation.RRRotations; - } - - return TRUE; -} - -static Bool -xf86RandRSetMode (ScreenPtr pScreen, - DisplayModePtr mode, - Bool useVirtual, - int mmWidth, - int mmHeight) -{ - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - int oldWidth = pScreen->width; - int oldHeight = pScreen->height; - int oldmmWidth = pScreen->mmWidth; - int oldmmHeight = pScreen->mmHeight; - int oldVirtualX = scrp->virtualX; - int oldVirtualY = scrp->virtualY; - WindowPtr pRoot = WindowTable[pScreen->myNum]; - Bool ret = TRUE; - - if (pRoot && scrp->vtSema) - (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); - if (useVirtual) - { - scrp->virtualX = randrp->virtualX; - scrp->virtualY = randrp->virtualY; - } - else - { - scrp->virtualX = mode->HDisplay; - scrp->virtualY = mode->VDisplay; - } - - /* - * The DIX forgets the physical dimensions we passed into RRRegisterSize, so - * reconstruct them if possible. - */ - if(scrp->DriverFunc) { - xorgRRModeMM RRModeMM; - - RRModeMM.mode = mode; - RRModeMM.virtX = scrp->virtualX; - RRModeMM.virtY = scrp->virtualY; - RRModeMM.mmWidth = mmWidth; - RRModeMM.mmHeight = mmHeight; - - (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); - - mmWidth = RRModeMM.mmWidth; - mmHeight = RRModeMM.mmHeight; - } - if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) - { - /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ - pScreen->width = scrp->virtualY; - pScreen->height = scrp->virtualX; - pScreen->mmWidth = mmHeight; - pScreen->mmHeight = mmWidth; - } - else - { - pScreen->width = scrp->virtualX; - pScreen->height = scrp->virtualY; - pScreen->mmWidth = mmWidth; - pScreen->mmHeight = mmHeight; - } - if (!xf86SwitchMode (pScreen, mode)) - { - pScreen->width = oldWidth; - pScreen->height = oldHeight; - pScreen->mmWidth = oldmmWidth; - pScreen->mmHeight = oldmmHeight; - scrp->virtualX = oldVirtualX; - scrp->virtualY = oldVirtualY; - ret = FALSE; - } - /* - * Make sure the layout is correct - */ - xf86ReconfigureLayout(); - - /* - * Make sure the whole screen is visible - */ - xf86SetViewport (pScreen, pScreen->width, pScreen->height); - xf86SetViewport (pScreen, 0, 0); - if (pRoot && scrp->vtSema) - (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); - return ret; -} - -static Bool -xf86RandRSetConfig (ScreenPtr pScreen, - Rotation rotation, - int rate, - RRScreenSizePtr pSize) -{ - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - DisplayModePtr mode; - int px, py; - Bool useVirtual = FALSE; - Rotation oldRotation = randrp->rotation; - - miPointerGetPosition(inputInfo.pointer, &px, &py); - for (mode = scrp->modes; ; mode = mode->next) - { - if (mode->HDisplay == pSize->width && - mode->VDisplay == pSize->height && - (rate == 0 || xf86RandRModeRefresh (mode) == rate)) - break; - if (mode->next == scrp->modes) - { - if (pSize->width == randrp->virtualX && - pSize->height == randrp->virtualY) - { - mode = scrp->modes; - useVirtual = TRUE; - break; - } - return FALSE; - } - } - - if (randrp->rotation != rotation) { - - /* Have the driver do its thing. */ - if (scrp->DriverFunc) { - xorgRRRotation RRRotation; - RRRotation.RRConfig.rotation = rotation; - RRRotation.RRConfig.rate = rate; - RRRotation.RRConfig.width = pSize->width; - RRRotation.RRConfig.height = pSize->height; - - /* - * Currently we need to rely on HW support for rotation. - */ - if (!(*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation)) - return FALSE; - } else - return FALSE; - - randrp->rotation = rotation; - } - - if (!xf86RandRSetMode (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) { - if(randrp->rotation != oldRotation) { - /* Have the driver undo its thing. */ - if (scrp->DriverFunc) { - xorgRRRotation RRRotation; - RRRotation.RRConfig.rotation = oldRotation; - RRRotation.RRConfig.rate = xf86RandRModeRefresh (scrp->currentMode); - RRRotation.RRConfig.width = scrp->virtualX; - RRRotation.RRConfig.height = scrp->virtualY; - (*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation); - } - - randrp->rotation = oldRotation; - } - return FALSE; - } - /* - * Move the cursor back where it belongs; SwitchMode repositions it - */ - if (pScreen == miPointerCurrentScreen ()) - { - px = (px >= pScreen->width ? (pScreen->width - 1) : px); - py = (py >= pScreen->height ? (pScreen->height - 1) : py); - - xf86SetViewport(pScreen, px, py); - - (*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE); - } - - return TRUE; -} - -/* - * Wait until the screen is initialized before whacking the - * sizes around; otherwise the screen pixmap will be allocated - * at the current mode size rather than the maximum size - */ -static Bool -xf86RandRCreateScreenResources (ScreenPtr pScreen) -{ - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); -#if 0 - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - DisplayModePtr mode; -#endif - - pScreen->CreateScreenResources = randrp->CreateScreenResources; - if (!(*pScreen->CreateScreenResources) (pScreen)) - return FALSE; - -#if 0 - mode = scrp->currentMode; - if (mode) - xf86RandRSetMode (pScreen, mode, TRUE); -#endif - - return TRUE; -} - -/* - * Reset size back to original - */ -static Bool -xf86RandRCloseScreen (int index, ScreenPtr pScreen) -{ - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - - scrp->virtualX = pScreen->width = randrp->virtualX; - scrp->virtualY = pScreen->height = randrp->virtualY; - scrp->currentMode = scrp->modes; - pScreen->CloseScreen = randrp->CloseScreen; - xfree (randrp); - dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, NULL); - return (*pScreen->CloseScreen) (index, pScreen); -} - -Rotation -xf86GetRotation(ScreenPtr pScreen) -{ - if (xf86RandRKey == NULL) - return RR_Rotate_0; - - return XF86RANDRINFO(pScreen)->rotation; -} - -/* Function to change RandR's idea of the virtual screen size */ -Bool -xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen, - int newvirtX, int newvirtY, int newmmWidth, int newmmHeight, - Bool resetMode) -{ - XF86RandRInfoPtr randrp; - - if (xf86RandRKey == NULL) - return FALSE; - - randrp = XF86RANDRINFO(pScreen); - if (randrp == NULL) - return FALSE; - - if (newvirtX > 0) - randrp->virtualX = newvirtX; - - if (newvirtY > 0) - randrp->virtualY = newvirtY; - - if (newmmWidth > 0) - randrp->mmWidth = newmmWidth; - - if (newmmHeight > 0) - randrp->mmHeight = newmmHeight; - - /* This is only for during server start */ - if (resetMode) { - return (xf86RandRSetMode(pScreen, - XF86SCRNINFO(pScreen)->currentMode, - TRUE, - pScreen->mmWidth, pScreen->mmHeight)); - } - - return TRUE; -} - -Bool -xf86RandRInit (ScreenPtr pScreen) -{ - rrScrPrivPtr rp; - XF86RandRInfoPtr randrp; - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - -#ifdef PANORAMIX - /* XXX disable RandR when using Xinerama */ - if (!noPanoramiXExtension) - return TRUE; -#endif - - xf86RandRKey = &xf86RandRKeyIndex; - - randrp = xalloc (sizeof (XF86RandRInfoRec)); - if (!randrp) - return FALSE; - - if (!RRScreenInit (pScreen)) - { - xfree (randrp); - return FALSE; - } - rp = rrGetScrPriv(pScreen); - rp->rrGetInfo = xf86RandRGetInfo; - rp->rrSetConfig = xf86RandRSetConfig; - - randrp->virtualX = scrp->virtualX; - randrp->virtualY = scrp->virtualY; - randrp->mmWidth = pScreen->mmWidth; - randrp->mmHeight = pScreen->mmHeight; - - randrp->CreateScreenResources = pScreen->CreateScreenResources; - pScreen->CreateScreenResources = xf86RandRCreateScreenResources; - - randrp->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = xf86RandRCloseScreen; - - randrp->rotation = RR_Rotate_0; - - dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, randrp); - return TRUE; -} - - +/* + * + * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. + * + * 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_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "os.h" +#include "globals.h" +#include "xf86.h" +#include "xf86str.h" +#include "xf86Priv.h" +#include "xf86DDC.h" +#include "mipointer.h" +#include <randrstr.h> +#include "inputstr.h" + +typedef struct _xf86RandRInfo { + CreateScreenResourcesProcPtr CreateScreenResources; + CloseScreenProcPtr CloseScreen; + int virtualX; + int virtualY; + int mmWidth; + int mmHeight; + Rotation rotation; +} XF86RandRInfoRec, *XF86RandRInfoPtr; + +static int xf86RandRKeyIndex; +static DevPrivateKey xf86RandRKey; + +#define XF86RANDRINFO(p) ((XF86RandRInfoPtr)dixLookupPrivate(&(p)->devPrivates, xf86RandRKey)) + +static int +xf86RandRModeRefresh (DisplayModePtr mode) +{ + if (mode->VRefresh) + return (int) (mode->VRefresh + 0.5); + else if (mode->Clock == 0) + return 0; + else + return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); +} + +static Bool +xf86RandRGetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + RRScreenSizePtr pSize; + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int refresh0 = 60; + xorgRRModeMM RRModeMM; + + *rotations = RR_Rotate_0; + + for (mode = scrp->modes; mode != NULL ; mode = mode->next) + { + int refresh = xf86RandRModeRefresh (mode); + + if (mode == scrp->modes) + refresh0 = refresh; + + RRModeMM.mode = mode; + RRModeMM.virtX = randrp->virtualX; + RRModeMM.virtY = randrp->virtualY; + RRModeMM.mmWidth = randrp->mmWidth; + RRModeMM.mmHeight = randrp->mmHeight; + + if(scrp->DriverFunc) { + (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); + } + + pSize = RRRegisterSize (pScreen, + mode->HDisplay, mode->VDisplay, + RRModeMM.mmWidth, RRModeMM.mmHeight); + if (!pSize) + return FALSE; + RRRegisterRate (pScreen, pSize, refresh); + if (mode == scrp->currentMode && + mode->HDisplay == scrp->virtualX && mode->VDisplay == scrp->virtualY) + RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); + if (mode->next == scrp->modes) + break; + } + if (scrp->currentMode->HDisplay != randrp->virtualX || + scrp->currentMode->VDisplay != randrp->virtualY) + { + mode = scrp->modes; + + RRModeMM.mode = NULL; + RRModeMM.virtX = randrp->virtualX; + RRModeMM.virtY = randrp->virtualY; + RRModeMM.mmWidth = randrp->mmWidth; + RRModeMM.mmHeight = randrp->mmHeight; + + if(scrp->DriverFunc) { + (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); + } + + pSize = RRRegisterSize (pScreen, + randrp->virtualX, randrp->virtualY, + RRModeMM.mmWidth, RRModeMM.mmHeight); + if (!pSize) + return FALSE; + RRRegisterRate (pScreen, pSize, refresh0); + if (scrp->virtualX == randrp->virtualX && + scrp->virtualY == randrp->virtualY) + { + RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize); + } + } + + /* If there is driver support for randr, let it set our supported rotations */ + if(scrp->DriverFunc) { + xorgRRRotation RRRotation; + + RRRotation.RRRotations = *rotations; + if (!(*scrp->DriverFunc)(scrp, RR_GET_INFO, &RRRotation)) + return TRUE; + *rotations = RRRotation.RRRotations; + } + + return TRUE; +} + +static Bool +xf86RandRSetMode (ScreenPtr pScreen, + DisplayModePtr mode, + Bool useVirtual, + int mmWidth, + int mmHeight) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int oldWidth = pScreen->width; + int oldHeight = pScreen->height; + int oldmmWidth = pScreen->mmWidth; + int oldmmHeight = pScreen->mmHeight; + int oldVirtualX = scrp->virtualX; + int oldVirtualY = scrp->virtualY; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + Bool ret = TRUE; + + if (pRoot && scrp->vtSema) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); + if (useVirtual) + { + scrp->virtualX = randrp->virtualX; + scrp->virtualY = randrp->virtualY; + } + else + { + scrp->virtualX = mode->HDisplay; + scrp->virtualY = mode->VDisplay; + } + + /* + * The DIX forgets the physical dimensions we passed into RRRegisterSize, so + * reconstruct them if possible. + */ + if(scrp->DriverFunc) { + xorgRRModeMM RRModeMM; + + RRModeMM.mode = mode; + RRModeMM.virtX = scrp->virtualX; + RRModeMM.virtY = scrp->virtualY; + RRModeMM.mmWidth = mmWidth; + RRModeMM.mmHeight = mmHeight; + + (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); + + mmWidth = RRModeMM.mmWidth; + mmHeight = RRModeMM.mmHeight; + } + if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) + { + /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ + pScreen->width = scrp->virtualY; + pScreen->height = scrp->virtualX; + pScreen->mmWidth = mmHeight; + pScreen->mmHeight = mmWidth; + } + else + { + pScreen->width = scrp->virtualX; + pScreen->height = scrp->virtualY; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + } + if (!xf86SwitchMode (pScreen, mode)) + { + pScreen->width = oldWidth; + pScreen->height = oldHeight; + pScreen->mmWidth = oldmmWidth; + pScreen->mmHeight = oldmmHeight; + scrp->virtualX = oldVirtualX; + scrp->virtualY = oldVirtualY; + ret = FALSE; + } + /* + * Make sure the layout is correct + */ + xf86ReconfigureLayout(); + + /* + * Make sure the whole screen is visible + */ + xf86SetViewport (pScreen, pScreen->width, pScreen->height); + xf86SetViewport (pScreen, 0, 0); + if (pRoot && scrp->vtSema) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); + return ret; +} + +static Bool +xf86RandRSetConfig (ScreenPtr pScreen, + Rotation rotation, + int rate, + RRScreenSizePtr pSize) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int px, py; + Bool useVirtual = FALSE; + Rotation oldRotation = randrp->rotation; + + miPointerGetPosition(inputInfo.pointer, &px, &py); + for (mode = scrp->modes; ; mode = mode->next) + { + if (mode->HDisplay == pSize->width && + mode->VDisplay == pSize->height && + (rate == 0 || xf86RandRModeRefresh (mode) == rate)) + break; + if (mode->next == scrp->modes) + { + if (pSize->width == randrp->virtualX && + pSize->height == randrp->virtualY) + { + mode = scrp->modes; + useVirtual = TRUE; + break; + } + return FALSE; + } + } + + if (randrp->rotation != rotation) { + + /* Have the driver do its thing. */ + if (scrp->DriverFunc) { + xorgRRRotation RRRotation; + RRRotation.RRConfig.rotation = rotation; + RRRotation.RRConfig.rate = rate; + RRRotation.RRConfig.width = pSize->width; + RRRotation.RRConfig.height = pSize->height; + + /* + * Currently we need to rely on HW support for rotation. + */ + if (!(*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation)) + return FALSE; + } else + return FALSE; + + randrp->rotation = rotation; + } + + if (!xf86RandRSetMode (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) { + if(randrp->rotation != oldRotation) { + /* Have the driver undo its thing. */ + if (scrp->DriverFunc) { + xorgRRRotation RRRotation; + RRRotation.RRConfig.rotation = oldRotation; + RRRotation.RRConfig.rate = xf86RandRModeRefresh (scrp->currentMode); + RRRotation.RRConfig.width = scrp->virtualX; + RRRotation.RRConfig.height = scrp->virtualY; + (*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation); + } + + randrp->rotation = oldRotation; + } + return FALSE; + } + /* + * Move the cursor back where it belongs; SwitchMode repositions it + */ + if (pScreen == miPointerCurrentScreen ()) + { + px = (px >= pScreen->width ? (pScreen->width - 1) : px); + py = (py >= pScreen->height ? (pScreen->height - 1) : py); + + xf86SetViewport(pScreen, px, py); + + (*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE); + } + + return TRUE; +} + +/* + * Wait until the screen is initialized before whacking the + * sizes around; otherwise the screen pixmap will be allocated + * at the current mode size rather than the maximum size + */ +static Bool +xf86RandRCreateScreenResources (ScreenPtr pScreen) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); +#if 0 + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + DisplayModePtr mode; +#endif + + pScreen->CreateScreenResources = randrp->CreateScreenResources; + if (!(*pScreen->CreateScreenResources) (pScreen)) + return FALSE; + +#if 0 + mode = scrp->currentMode; + if (mode) + xf86RandRSetMode (pScreen, mode, TRUE); +#endif + + return TRUE; +} + +/* + * Reset size back to original + */ +static Bool +xf86RandRCloseScreen (int index, ScreenPtr pScreen) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + scrp->virtualX = pScreen->width = randrp->virtualX; + scrp->virtualY = pScreen->height = randrp->virtualY; + scrp->currentMode = scrp->modes; + pScreen->CloseScreen = randrp->CloseScreen; + free(randrp); + dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, NULL); + return (*pScreen->CloseScreen) (index, pScreen); +} + +Rotation +xf86GetRotation(ScreenPtr pScreen) +{ + if (xf86RandRKey == NULL) + return RR_Rotate_0; + + return XF86RANDRINFO(pScreen)->rotation; +} + +/* Function to change RandR's idea of the virtual screen size */ +Bool +xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen, + int newvirtX, int newvirtY, int newmmWidth, int newmmHeight, + Bool resetMode) +{ + XF86RandRInfoPtr randrp; + + if (xf86RandRKey == NULL) + return FALSE; + + randrp = XF86RANDRINFO(pScreen); + if (randrp == NULL) + return FALSE; + + if (newvirtX > 0) + randrp->virtualX = newvirtX; + + if (newvirtY > 0) + randrp->virtualY = newvirtY; + + if (newmmWidth > 0) + randrp->mmWidth = newmmWidth; + + if (newmmHeight > 0) + randrp->mmHeight = newmmHeight; + + /* This is only for during server start */ + if (resetMode) { + return (xf86RandRSetMode(pScreen, + XF86SCRNINFO(pScreen)->currentMode, + TRUE, + pScreen->mmWidth, pScreen->mmHeight)); + } + + return TRUE; +} + +Bool +xf86RandRInit (ScreenPtr pScreen) +{ + rrScrPrivPtr rp; + XF86RandRInfoPtr randrp; + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + +#ifdef PANORAMIX + /* XXX disable RandR when using Xinerama */ + if (!noPanoramiXExtension) + return TRUE; +#endif + + xf86RandRKey = &xf86RandRKeyIndex; + + randrp = malloc(sizeof (XF86RandRInfoRec)); + if (!randrp) + return FALSE; + + if (!RRScreenInit (pScreen)) + { + free(randrp); + return FALSE; + } + rp = rrGetScrPriv(pScreen); + rp->rrGetInfo = xf86RandRGetInfo; + rp->rrSetConfig = xf86RandRSetConfig; + + randrp->virtualX = scrp->virtualX; + randrp->virtualY = scrp->virtualY; + randrp->mmWidth = pScreen->mmWidth; + randrp->mmHeight = pScreen->mmHeight; + + randrp->CreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = xf86RandRCreateScreenResources; + + randrp->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = xf86RandRCloseScreen; + + randrp->rotation = RR_Rotate_0; + + dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, randrp); + return TRUE; +} + + diff --git a/xorg-server/hw/xfree86/common/xf86ShowOpts.c b/xorg-server/hw/xfree86/common/xf86ShowOpts.c index 04a9a8b1c..77f156486 100644 --- a/xorg-server/hw/xfree86/common/xf86ShowOpts.c +++ b/xorg-server/hw/xfree86/common/xf86ShowOpts.c @@ -1,128 +1,128 @@ -/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86ShopwOpts.c,v 3.80 2003/10/08 14:58:27 dawes Exp $ */ -/* - * Copyright 2000-2002 by Alan Hourihane, Flint Mountain, North Wales. - * - * 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 Alan Hourihane not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Alan Hourihane makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL ALAN HOURIHANE 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. - * - * Author: Marcus Schaefer, ms@suse.de - * - */ - -#include <ctype.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <X11/X.h> -#include <X11/Xmd.h> -#include "os.h" -#ifdef XFree86LOADER -#include "loaderProcs.h" -#endif -#include "xf86.h" -#include "xf86Config.h" -#include "xf86_OSlib.h" -#include "xf86Priv.h" -/* #include "xf86PciData.h" */ -#define IN_XSERVER -#include "xf86Parser.h" -#include "xf86tokens.h" -#include "Configint.h" -#include "xf86DDC.h" -#if defined(__sparc__) && !defined(__OpenBSD__) -#include "xf86Bus.h" -#include "xf86Sbus.h" -#endif -#include "globals.h" - -static const char* -optionTypeToSting(OptionValueType type) -{ - switch (type) { - case OPTV_NONE: - return ""; - case OPTV_INTEGER: - return "<int>"; - case OPTV_STRING: - return "<str>"; - case OPTV_ANYSTR: - return "<str>"; - case OPTV_REAL: - return "<real>"; - case OPTV_BOOLEAN: - return "<bool>"; - case OPTV_FREQ: - return "<freq>"; - default: - return "<undef>"; - } -} - -void DoShowOptions (void) { - int i = 0; - char **vlist = 0; - char *pSymbol = 0; - XF86ModuleData *initData = 0; - if (! (vlist = xf86DriverlistFromCompile())) { - ErrorF("Missing output drivers\n"); - goto bail; - } - xf86LoadModules (vlist,0); - xfree (vlist); - for (i = 0; i < xf86NumDrivers; i++) { - if (xf86DriverList[i]->AvailableOptions) { - OptionInfoPtr pOption = (OptionInfoPtr)(*xf86DriverList[i]->AvailableOptions)(0,0); - if (! pOption) { - ErrorF ("(EE) Couldn't read option table for %s driver\n", - xf86DriverList[i]->driverName - ); - continue; - } - pSymbol = xalloc ( - strlen(xf86DriverList[i]->driverName) + strlen("ModuleData") + 1 - ); - strcpy (pSymbol, xf86DriverList[i]->driverName); - strcat (pSymbol, "ModuleData"); - initData = LoaderSymbol (pSymbol); - if (initData) { - XF86ModuleVersionInfo *vers = initData->vers; - OptionInfoPtr p; - ErrorF ("Driver[%d]:%s[%s] {\n", - i,xf86DriverList[i]->driverName,vers->vendor - ); - for (p = pOption; p->name != NULL; p++) { - const char *opttype = optionTypeToSting(p->type); - char *optname = xalloc(strlen(p->name) + 2 + 1); - if (!optname) { - continue; - } - sprintf(optname, "%s", p->name); - ErrorF ("\t%s:%s\n", optname,opttype); - } - ErrorF ("}\n"); - } - } - } - bail: - OsCleanup (TRUE); - AbortDDX (); - fflush (stderr); - exit (0); -} +/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86ShopwOpts.c,v 3.80 2003/10/08 14:58:27 dawes Exp $ */ +/* + * Copyright 2000-2002 by Alan Hourihane, Flint Mountain, North Wales. + * + * 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 Alan Hourihane not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Alan Hourihane makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ALAN HOURIHANE 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. + * + * Author: Marcus Schaefer, ms@suse.de + * + */ + +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <X11/X.h> +#include <X11/Xmd.h> +#include "os.h" +#ifdef XFree86LOADER +#include "loaderProcs.h" +#endif +#include "xf86.h" +#include "xf86Config.h" +#include "xf86_OSlib.h" +#include "xf86Priv.h" +/* #include "xf86PciData.h" */ +#define IN_XSERVER +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" +#include "xf86DDC.h" +#if defined(__sparc__) && !defined(__OpenBSD__) +#include "xf86Bus.h" +#include "xf86Sbus.h" +#endif +#include "globals.h" + +static const char* +optionTypeToSting(OptionValueType type) +{ + switch (type) { + case OPTV_NONE: + return ""; + case OPTV_INTEGER: + return "<int>"; + case OPTV_STRING: + return "<str>"; + case OPTV_ANYSTR: + return "<str>"; + case OPTV_REAL: + return "<real>"; + case OPTV_BOOLEAN: + return "<bool>"; + case OPTV_FREQ: + return "<freq>"; + default: + return "<undef>"; + } +} + +void DoShowOptions (void) { + int i = 0; + char **vlist = 0; + char *pSymbol = 0; + XF86ModuleData *initData = 0; + if (! (vlist = xf86DriverlistFromCompile())) { + ErrorF("Missing output drivers\n"); + goto bail; + } + xf86LoadModules (vlist,0); + free(vlist); + for (i = 0; i < xf86NumDrivers; i++) { + if (xf86DriverList[i]->AvailableOptions) { + OptionInfoPtr pOption = (OptionInfoPtr)(*xf86DriverList[i]->AvailableOptions)(0,0); + if (! pOption) { + ErrorF ("(EE) Couldn't read option table for %s driver\n", + xf86DriverList[i]->driverName + ); + continue; + } + pSymbol = malloc( + strlen(xf86DriverList[i]->driverName) + strlen("ModuleData") + 1 + ); + strcpy (pSymbol, xf86DriverList[i]->driverName); + strcat (pSymbol, "ModuleData"); + initData = LoaderSymbol (pSymbol); + if (initData) { + XF86ModuleVersionInfo *vers = initData->vers; + OptionInfoPtr p; + ErrorF ("Driver[%d]:%s[%s] {\n", + i,xf86DriverList[i]->driverName,vers->vendor + ); + for (p = pOption; p->name != NULL; p++) { + const char *opttype = optionTypeToSting(p->type); + char *optname = malloc(strlen(p->name) + 2 + 1); + if (!optname) { + continue; + } + sprintf(optname, "%s", p->name); + ErrorF ("\t%s:%s\n", optname,opttype); + } + ErrorF ("}\n"); + } + } + } + bail: + OsCleanup (TRUE); + AbortDDX (); + fflush (stderr); + exit (0); +} diff --git a/xorg-server/hw/xfree86/common/xf86VGAarbiter.c b/xorg-server/hw/xfree86/common/xf86VGAarbiter.c index 52a8b9a60..ac44c5e67 100644 --- a/xorg-server/hw/xfree86/common/xf86VGAarbiter.c +++ b/xorg-server/hw/xfree86/common/xf86VGAarbiter.c @@ -1,1101 +1,1101 @@ -/* - * This code was stolen from RAC and adapted to control the legacy vga - * interface. - * - * - * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti - * - * 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 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. - * - */ - -#include "xorg-config.h" - -#include "xf86VGAarbiter.h" - -#ifdef HAVE_PCI_DEVICE_VGAARB_INIT -#include "xf86VGAarbiterPriv.h" -#include "xf86Bus.h" -#include "xf86Priv.h" -#include "pciaccess.h" - - -static GCFuncs VGAarbiterGCFuncs = { - VGAarbiterValidateGC, VGAarbiterChangeGC, VGAarbiterCopyGC, - VGAarbiterDestroyGC, VGAarbiterChangeClip, VGAarbiterDestroyClip, - VGAarbiterCopyClip -}; - -static GCOps VGAarbiterGCOps = { - VGAarbiterFillSpans, VGAarbiterSetSpans, VGAarbiterPutImage, - VGAarbiterCopyArea, VGAarbiterCopyPlane, VGAarbiterPolyPoint, - VGAarbiterPolylines, VGAarbiterPolySegment, VGAarbiterPolyRectangle, - VGAarbiterPolyArc, VGAarbiterFillPolygon, VGAarbiterPolyFillRect, - VGAarbiterPolyFillArc, VGAarbiterPolyText8, VGAarbiterPolyText16, - VGAarbiterImageText8, VGAarbiterImageText16, VGAarbiterImageGlyphBlt, - VGAarbiterPolyGlyphBlt, VGAarbiterPushPixels, - {NULL} /* devPrivate */ -}; - -static miPointerSpriteFuncRec VGAarbiterSpriteFuncs = { - VGAarbiterSpriteRealizeCursor, VGAarbiterSpriteUnrealizeCursor, - VGAarbiterSpriteSetCursor, VGAarbiterSpriteMoveCursor, - VGAarbiterDeviceCursorInitialize, VGAarbiterDeviceCursorCleanup -}; - -static int VGAarbiterKeyIndex; -static DevPrivateKey VGAarbiterScreenKey = &VGAarbiterKeyIndex; -static int VGAarbiterGCIndex; -static DevPrivateKey VGAarbiterGCKey = &VGAarbiterGCIndex; - -static int vga_no_arb = 0; -void -xf86VGAarbiterInit(void) -{ - if (pci_device_vgaarb_init() != 0) { - vga_no_arb = 1; - xf86Msg(X_WARNING, "VGA arbiter: cannot open kernel arbiter, no multi-card support\n"); - } -} - -void -xf86VGAarbiterFini(void) -{ - if (vga_no_arb) - return; - pci_device_vgaarb_fini(); -} - -void -xf86VGAarbiterLock(ScrnInfoPtr pScrn) -{ - if (vga_no_arb) - return; - pci_device_vgaarb_set_target(pScrn->vgaDev); - pci_device_vgaarb_lock(); -} - -void -xf86VGAarbiterUnlock(ScrnInfoPtr pScrn) -{ - if (vga_no_arb) - return; - pci_device_vgaarb_unlock(); -} - -Bool xf86VGAarbiterAllowDRI(ScreenPtr pScreen) -{ - int vga_count; - int rsrc_decodes; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - - if (vga_no_arb) - return TRUE; - - pci_device_vgaarb_get_info(pScrn->vgaDev, &vga_count, &rsrc_decodes); - if (vga_count > 1) { - if (rsrc_decodes) { - return FALSE; - } - } - return TRUE; -} - -void -xf86VGAarbiterScrnInit(ScrnInfoPtr pScrn) -{ - struct pci_device *dev; - EntityPtr pEnt; - - if (vga_no_arb) - return; - - pEnt = xf86Entities[pScrn->entityList[0]]; - if (pEnt->bus.type != BUS_PCI) - return; - - dev = pEnt->bus.id.pci; - pScrn->vgaDev = dev; -} - -void -xf86VGAarbiterDeviceDecodes(ScrnInfoPtr pScrn) -{ - if (vga_no_arb) - return; - pci_device_vgaarb_decodes(VGA_ARB_RSRC_LEGACY_MEM | VGA_ARB_RSRC_LEGACY_IO); -} - -Bool -xf86VGAarbiterWrapFunctions(void) -{ - ScrnInfoPtr pScrn; - VGAarbiterScreenPtr pScreenPriv; - miPointerScreenPtr PointPriv; - PictureScreenPtr ps; - ScreenPtr pScreen; - int vga_count, i; - - if (vga_no_arb) - return FALSE; - - /* - * we need to wrap the arbiter if we have more than - * one VGA card - hotplug cries. - */ - pci_device_vgaarb_get_info(NULL, &vga_count, NULL); - if (vga_count < 2 || !xf86Screens) - return FALSE; - - xf86Msg(X_INFO,"Found %d VGA devices: arbiter wrapping enabled\n", - vga_count); - - for (i = 0; i < xf86NumScreens; i++) { - pScreen = xf86Screens[i]->pScreen; - ps = GetPictureScreenIfSet(pScreen); - pScrn = xf86Screens[pScreen->myNum]; - PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); - - if (!dixRequestPrivate(VGAarbiterGCKey, sizeof(VGAarbiterGCRec))) - return FALSE; - - if (!(pScreenPriv = xalloc(sizeof(VGAarbiterScreenRec)))) - return FALSE; - - dixSetPrivate(&pScreen->devPrivates, VGAarbiterScreenKey, pScreenPriv); - - WRAP_SCREEN(CloseScreen, VGAarbiterCloseScreen); - WRAP_SCREEN(SaveScreen, VGAarbiterSaveScreen); - WRAP_SCREEN(WakeupHandler, VGAarbiterWakeupHandler); - WRAP_SCREEN(BlockHandler, VGAarbiterBlockHandler); - WRAP_SCREEN(CreateGC, VGAarbiterCreateGC); - WRAP_SCREEN(GetImage, VGAarbiterGetImage); - WRAP_SCREEN(GetSpans, VGAarbiterGetSpans); - WRAP_SCREEN(SourceValidate, VGAarbiterSourceValidate); - WRAP_SCREEN(CopyWindow, VGAarbiterCopyWindow); - WRAP_SCREEN(ClearToBackground, VGAarbiterClearToBackground); - WRAP_SCREEN(CreatePixmap, VGAarbiterCreatePixmap); - WRAP_SCREEN(StoreColors, VGAarbiterStoreColors); - WRAP_SCREEN(DisplayCursor, VGAarbiterDisplayCursor); - WRAP_SCREEN(RealizeCursor, VGAarbiterRealizeCursor); - WRAP_SCREEN(UnrealizeCursor, VGAarbiterUnrealizeCursor); - WRAP_SCREEN(RecolorCursor, VGAarbiterRecolorCursor); - WRAP_SCREEN(SetCursorPosition, VGAarbiterSetCursorPosition); - WRAP_PICT(Composite,VGAarbiterComposite); - WRAP_PICT(Glyphs,VGAarbiterGlyphs); - WRAP_PICT(CompositeRects,VGAarbiterCompositeRects); - WRAP_SCREEN_INFO(AdjustFrame, VGAarbiterAdjustFrame); - WRAP_SCREEN_INFO(SwitchMode, VGAarbiterSwitchMode); - WRAP_SCREEN_INFO(EnterVT, VGAarbiterEnterVT); - WRAP_SCREEN_INFO(LeaveVT, VGAarbiterLeaveVT); - WRAP_SCREEN_INFO(FreeScreen, VGAarbiterFreeScreen); - WRAP_SPRITE; - } - - return TRUE; -} - -/* Screen funcs */ -static Bool -VGAarbiterCloseScreen (int i, ScreenPtr pScreen) -{ - Bool val; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, VGAarbiterScreenKey); - miPointerScreenPtr PointPriv = (miPointerScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, miPointerScreenKey); - PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); - - UNWRAP_SCREEN(CreateGC); - UNWRAP_SCREEN(CloseScreen); - UNWRAP_SCREEN(GetImage); - UNWRAP_SCREEN(GetSpans); - UNWRAP_SCREEN(SourceValidate); - UNWRAP_SCREEN(CopyWindow); - UNWRAP_SCREEN(ClearToBackground); - UNWRAP_SCREEN(SaveScreen); - UNWRAP_SCREEN(StoreColors); - UNWRAP_SCREEN(DisplayCursor); - UNWRAP_SCREEN(RealizeCursor); - UNWRAP_SCREEN(UnrealizeCursor); - UNWRAP_SCREEN(RecolorCursor); - UNWRAP_SCREEN(SetCursorPosition); - UNWRAP_PICT(Composite); - UNWRAP_PICT(Glyphs); - UNWRAP_PICT(CompositeRects); - UNWRAP_SCREEN_INFO(AdjustFrame); - UNWRAP_SCREEN_INFO(SwitchMode); - UNWRAP_SCREEN_INFO(EnterVT); - UNWRAP_SCREEN_INFO(LeaveVT); - UNWRAP_SCREEN_INFO(FreeScreen); - UNWRAP_SPRITE; - - xfree ((pointer) pScreenPriv); - xf86VGAarbiterLock(xf86Screens[i]); - val = (*pScreen->CloseScreen) (i, pScreen); - xf86VGAarbiterUnlock(xf86Screens[i]); - return val; -} - -static void -VGAarbiterBlockHandler(int i, - pointer blockData, pointer pTimeout, pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[i]; - SCREEN_PROLOG(BlockHandler); - VGAGet(); - pScreen->BlockHandler(i, blockData, pTimeout, pReadmask); - VGAPut(); - SCREEN_EPILOG(BlockHandler, VGAarbiterBlockHandler); -} - -static void -VGAarbiterWakeupHandler(int i, pointer blockData, unsigned long result, pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[i]; - SCREEN_PROLOG(WakeupHandler); - VGAGet(); - pScreen->WakeupHandler(i, blockData, result, pReadmask); - VGAPut(); - SCREEN_EPILOG(WakeupHandler, VGAarbiterWakeupHandler); -} - -static void -VGAarbiterGetImage ( - DrawablePtr pDrawable, - int sx, int sy, int w, int h, - unsigned int format, - unsigned long planemask, - char *pdstLine - ) -{ - ScreenPtr pScreen = pDrawable->pScreen; - SCREEN_PROLOG(GetImage); -// if (xf86Screens[pScreen->myNum]->vtSema) { - VGAGet(); -// } - (*pScreen->GetImage) (pDrawable, sx, sy, w, h, - format, planemask, pdstLine); - VGAPut(); - SCREEN_EPILOG (GetImage, VGAarbiterGetImage); -} - -static void -VGAarbiterGetSpans ( - DrawablePtr pDrawable, - int wMax, - DDXPointPtr ppt, - int *pwidth, - int nspans, - char *pdstStart - ) -{ - ScreenPtr pScreen = pDrawable->pScreen; - - SCREEN_PROLOG (GetSpans); - VGAGet(); - (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); - VGAPut(); - SCREEN_EPILOG (GetSpans, VGAarbiterGetSpans); -} - -static void -VGAarbiterSourceValidate ( - DrawablePtr pDrawable, - int x, int y, int width, int height ) -{ - ScreenPtr pScreen = pDrawable->pScreen; - SCREEN_PROLOG (SourceValidate); - VGAGet(); - if (pScreen->SourceValidate) - (*pScreen->SourceValidate) (pDrawable, x, y, width, height); - VGAPut(); - SCREEN_EPILOG (SourceValidate, VGAarbiterSourceValidate); -} - -static void -VGAarbiterCopyWindow( - WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc ) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - SCREEN_PROLOG (CopyWindow); - VGAGet(); - (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc); - VGAPut(); - SCREEN_EPILOG (CopyWindow, VGAarbiterCopyWindow); -} - -static void -VGAarbiterClearToBackground ( - WindowPtr pWin, - int x, int y, - int w, int h, - Bool generateExposures ) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - SCREEN_PROLOG ( ClearToBackground); - VGAGet(); - (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); - VGAPut(); - SCREEN_EPILOG (ClearToBackground, VGAarbiterClearToBackground); -} - -static PixmapPtr -VGAarbiterCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, unsigned usage_hint) -{ - PixmapPtr pPix; - - SCREEN_PROLOG ( CreatePixmap); - VGAGet(); - pPix = (*pScreen->CreatePixmap) (pScreen, w, h, depth, usage_hint); - VGAPut(); - SCREEN_EPILOG (CreatePixmap, VGAarbiterCreatePixmap); - - return pPix; -} - -static Bool -VGAarbiterSaveScreen(ScreenPtr pScreen, Bool unblank) -{ - Bool val; - - SCREEN_PROLOG (SaveScreen); - VGAGet(); - val = (*pScreen->SaveScreen) (pScreen, unblank); - VGAPut(); - SCREEN_EPILOG (SaveScreen, VGAarbiterSaveScreen); - - return val; -} - -static void -VGAarbiterStoreColors ( - ColormapPtr pmap, - int ndef, - xColorItem *pdefs) -{ - ScreenPtr pScreen = pmap->pScreen; - - SCREEN_PROLOG (StoreColors); - VGAGet(); - (*pScreen->StoreColors) (pmap,ndef,pdefs); - VGAPut(); - SCREEN_EPILOG ( StoreColors, VGAarbiterStoreColors); -} - -static void -VGAarbiterRecolorCursor ( - DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCurs, - Bool displayed - ) -{ - SCREEN_PROLOG (RecolorCursor); - VGAGet(); - (*pScreen->RecolorCursor) (pDev, pScreen, pCurs, displayed); - VGAPut(); - SCREEN_EPILOG ( RecolorCursor, VGAarbiterRecolorCursor); -} - -static Bool -VGAarbiterRealizeCursor ( - DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor - ) -{ - Bool val; - - SCREEN_PROLOG (RealizeCursor); - VGAGet(); - val = (*pScreen->RealizeCursor) (pDev, pScreen,pCursor); - VGAPut(); - SCREEN_EPILOG ( RealizeCursor, VGAarbiterRealizeCursor); - return val; -} - -static Bool -VGAarbiterUnrealizeCursor ( - DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor - ) -{ - Bool val; - - SCREEN_PROLOG (UnrealizeCursor); - VGAGet(); - val = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); - VGAPut(); - SCREEN_EPILOG ( UnrealizeCursor, VGAarbiterUnrealizeCursor); - return val; -} - -static Bool -VGAarbiterDisplayCursor ( - DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor - ) -{ - Bool val; - - SCREEN_PROLOG (DisplayCursor); - VGAGet(); - val = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); - VGAPut(); - SCREEN_EPILOG ( DisplayCursor, VGAarbiterDisplayCursor); - return val; -} - -static Bool -VGAarbiterSetCursorPosition ( - DeviceIntPtr pDev, - ScreenPtr pScreen, - int x, int y, - Bool generateEvent) -{ - Bool val; - - SCREEN_PROLOG (SetCursorPosition); - VGAGet(); - val = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent); - VGAPut(); - SCREEN_EPILOG ( SetCursorPosition, VGAarbiterSetCursorPosition); - return val; -} - -static void -VGAarbiterAdjustFrame(int index, int x, int y, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, VGAarbiterScreenKey); - - VGAGet(); - (*pScreenPriv->AdjustFrame)(index, x, y, flags); - VGAPut(); -} - -static Bool -VGAarbiterSwitchMode(int index, DisplayModePtr mode, int flags) -{ - Bool val; - ScreenPtr pScreen = screenInfo.screens[index]; - VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, VGAarbiterScreenKey); - - VGAGet(); - val = (*pScreenPriv->SwitchMode)(index, mode, flags); - VGAPut(); - return val; -} - -static Bool -VGAarbiterEnterVT(int index, int flags) -{ - Bool val; - ScreenPtr pScreen = screenInfo.screens[index]; - VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, VGAarbiterScreenKey); - - VGAGet(); - val = (*pScreenPriv->EnterVT)(index, flags); - VGAPut(); - return val; -} - -static void -VGAarbiterLeaveVT(int index, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, VGAarbiterScreenKey); - - VGAGet(); - (*pScreenPriv->LeaveVT)(index, flags); - VGAPut(); -} - -static void -VGAarbiterFreeScreen(int index, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, VGAarbiterScreenKey); - - VGAGet(); - (*pScreenPriv->FreeScreen)(index, flags); - VGAPut(); -} - -static Bool -VGAarbiterCreateGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - VGAarbiterGCPtr pGCPriv = (VGAarbiterGCPtr)dixLookupPrivate(&pGC->devPrivates, VGAarbiterGCKey); - Bool ret; - - SCREEN_PROLOG(CreateGC); - VGAGet(); - ret = (*pScreen->CreateGC)(pGC); - VGAPut(); - GC_WRAP(pGC); - SCREEN_EPILOG(CreateGC,VGAarbiterCreateGC); - - return ret; -} - -/* GC funcs */ -static void -VGAarbiterValidateGC( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw ) -{ - GC_UNWRAP(pGC); - (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); - GC_WRAP(pGC); -} - - -static void -VGAarbiterDestroyGC(GCPtr pGC) -{ - GC_UNWRAP (pGC); - (*pGC->funcs->DestroyGC)(pGC); - GC_WRAP (pGC); -} - -static void -VGAarbiterChangeGC ( - GCPtr pGC, - unsigned long mask) -{ - GC_UNWRAP (pGC); - (*pGC->funcs->ChangeGC) (pGC, mask); - GC_WRAP (pGC); -} - -static void -VGAarbiterCopyGC ( - GCPtr pGCSrc, - unsigned long mask, - GCPtr pGCDst) -{ - GC_UNWRAP (pGCDst); - (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); - GC_WRAP (pGCDst); -} - -static void -VGAarbiterChangeClip ( - GCPtr pGC, - int type, - pointer pvalue, - int nrects ) -{ - GC_UNWRAP (pGC); - (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); - GC_WRAP (pGC); -} - -static void -VGAarbiterCopyClip(GCPtr pgcDst, GCPtr pgcSrc) -{ - GC_UNWRAP (pgcDst); - (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); - GC_WRAP (pgcDst); -} - -static void -VGAarbiterDestroyClip(GCPtr pGC) -{ - GC_UNWRAP (pGC); - (* pGC->funcs->DestroyClip)(pGC); - GC_WRAP (pGC); -} - -/* GC Ops */ -static void -VGAarbiterFillSpans( - DrawablePtr pDraw, - GC *pGC, - int nInit, - DDXPointPtr pptInit, - int *pwidthInit, - int fSorted ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterSetSpans( - DrawablePtr pDraw, - GCPtr pGC, - char *pcharsrc, - register DDXPointPtr ppt, - int *pwidth, - int nspans, - int fSorted ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, ppt, pwidth, nspans, fSorted); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterPutImage( - DrawablePtr pDraw, - GCPtr pGC, - int depth, - int x, int y, int w, int h, - int leftPad, - int format, - char *pImage ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h, - leftPad, format, pImage); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static RegionPtr -VGAarbiterCopyArea( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty ) -{ - RegionPtr ret; - - GC_UNWRAP(pGC); - VGAGet_GC(); - ret = (*pGC->ops->CopyArea)(pSrc, pDst, - pGC, srcx, srcy, width, height, dstx, dsty); - VGAPut_GC(); - GC_WRAP(pGC); - return ret; -} - -static RegionPtr -VGAarbiterCopyPlane( - DrawablePtr pSrc, - DrawablePtr pDst, - GCPtr pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty, - unsigned long bitPlane ) -{ - RegionPtr ret; - - GC_UNWRAP(pGC); - VGAGet_GC(); - ret = (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, srcx, srcy, - width, height, dstx, dsty, bitPlane); - VGAPut_GC(); - GC_WRAP(pGC); - return ret; -} - -static void -VGAarbiterPolyPoint( - DrawablePtr pDraw, - GCPtr pGC, - int mode, - int npt, - xPoint *pptInit ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->PolyPoint)(pDraw, pGC, mode, npt, pptInit); - VGAPut_GC(); - GC_WRAP(pGC); -} - - -static void -VGAarbiterPolylines( - DrawablePtr pDraw, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr pptInit ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->Polylines)(pDraw, pGC, mode, npt, pptInit); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterPolySegment( - DrawablePtr pDraw, - GCPtr pGC, - int nseg, - xSegment *pSeg ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->PolySegment)(pDraw, pGC, nseg, pSeg); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterPolyRectangle( - DrawablePtr pDraw, - GCPtr pGC, - int nRectsInit, - xRectangle *pRectsInit ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->PolyRectangle)(pDraw, pGC, nRectsInit, pRectsInit); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterPolyArc( - DrawablePtr pDraw, - GCPtr pGC, - int narcs, - xArc *parcs ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->PolyArc)(pDraw, pGC, narcs, parcs); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterFillPolygon( - DrawablePtr pDraw, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr ptsIn ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, ptsIn); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterPolyFillRect( - DrawablePtr pDraw, - GCPtr pGC, - int nrectFill, - xRectangle *prectInit) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->PolyFillRect)(pDraw, pGC, nrectFill, prectInit); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterPolyFillArc( - DrawablePtr pDraw, - GCPtr pGC, - int narcs, - xArc *parcs ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->PolyFillArc)(pDraw, pGC, narcs, parcs); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static int -VGAarbiterPolyText8( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - char *chars ) -{ - int ret; - - GC_UNWRAP(pGC); - VGAGet_GC(); - ret = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars); - VGAPut_GC(); - GC_WRAP(pGC); - return ret; -} - -static int -VGAarbiterPolyText16( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars ) -{ - int ret; - - GC_UNWRAP(pGC); - VGAGet_GC(); - ret = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars); - VGAPut_GC(); - GC_WRAP(pGC); - return ret; -} - -static void -VGAarbiterImageText8( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - char *chars ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterImageText16( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars); - VGAPut_GC(); - GC_WRAP(pGC); -} - - -static void -VGAarbiterImageGlyphBlt( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, xInit, yInit, - nglyph, ppci, pglyphBase); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterPolyGlyphBlt( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, xInit, yInit, - nglyph, ppci, pglyphBase); - VGAPut_GC(); - GC_WRAP(pGC); -} - -static void -VGAarbiterPushPixels( - GCPtr pGC, - PixmapPtr pBitMap, - DrawablePtr pDraw, - int dx, int dy, int xOrg, int yOrg ) -{ - GC_UNWRAP(pGC); - VGAGet_GC(); - (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); - VGAPut_GC(); - GC_WRAP(pGC); -} - - -/* miSpriteFuncs */ -static Bool -VGAarbiterSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCur) -{ - Bool val; - SPRITE_PROLOG; - VGAGet(); - val = PointPriv->spriteFuncs->RealizeCursor(pDev, pScreen, pCur); - VGAPut(); - SPRITE_EPILOG; - return val; -} - -static Bool -VGAarbiterSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCur) -{ - Bool val; - SPRITE_PROLOG; - VGAGet(); - val = PointPriv->spriteFuncs->UnrealizeCursor(pDev, pScreen, pCur); - VGAPut(); - SPRITE_EPILOG; - return val; -} - -static void -VGAarbiterSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCur, int x, int y) -{ - SPRITE_PROLOG; - VGAGet(); - PointPriv->spriteFuncs->SetCursor(pDev, pScreen, pCur, x, y); - VGAPut(); - SPRITE_EPILOG; -} - -static void -VGAarbiterSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - SPRITE_PROLOG; - VGAGet(); - PointPriv->spriteFuncs->MoveCursor(pDev, pScreen, x, y); - VGAPut(); - SPRITE_EPILOG; -} - -static Bool -VGAarbiterDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - Bool val; - SPRITE_PROLOG; - VGAGet(); - val = PointPriv->spriteFuncs->DeviceCursorInitialize(pDev, pScreen); - VGAPut(); - SPRITE_EPILOG; - return val; -} - -static void -VGAarbiterDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - SPRITE_PROLOG; - VGAGet(); - PointPriv->spriteFuncs->DeviceCursorCleanup(pDev, pScreen); - VGAPut(); - SPRITE_EPILOG; -} - -static void -VGAarbiterComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, - PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, - INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, - CARD16 height) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - - PICTURE_PROLOGUE(Composite); - - VGAGet(); - (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, - yDst, width, height); - VGAPut(); - PICTURE_EPILOGUE(Composite, VGAarbiterComposite); -} - -static void -VGAarbiterGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, - GlyphListPtr list, GlyphPtr *glyphs) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - - PICTURE_PROLOGUE(Glyphs); - - VGAGet(); - (*ps->Glyphs)(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); - VGAPut(); - PICTURE_EPILOGUE (Glyphs, VGAarbiterGlyphs); -} - -static void -VGAarbiterCompositeRects(CARD8 op, PicturePtr pDst, xRenderColor *color, int nRect, - xRectangle *rects) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - - PICTURE_PROLOGUE(CompositeRects); - - VGAGet(); - (*ps->CompositeRects)(op, pDst, color, nRect, rects); - VGAPut(); - PICTURE_EPILOGUE (CompositeRects, VGAarbiterCompositeRects); -} -#else -/* dummy functions */ -void xf86VGAarbiterInit(void) {} -void xf86VGAarbiterFini(void) {} - -void xf86VGAarbiterLock(ScrnInfoPtr pScrn) {} -void xf86VGAarbiterUnlock(ScrnInfoPtr pScrn) {} -Bool xf86VGAarbiterAllowDRI(ScreenPtr pScreen) { return TRUE; } -void xf86VGAarbiterScrnInit(ScrnInfoPtr pScrn) {} -void xf86VGAarbiterDeviceDecodes(ScrnInfoPtr pScrn) {} -Bool xf86VGAarbiterWrapFunctions(void) { return FALSE; } - -#endif +/* + * This code was stolen from RAC and adapted to control the legacy vga + * interface. + * + * + * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti + * + * 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 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. + * + */ + +#include "xorg-config.h" + +#include "xf86VGAarbiter.h" + +#ifdef HAVE_PCI_DEVICE_VGAARB_INIT +#include "xf86VGAarbiterPriv.h" +#include "xf86Bus.h" +#include "xf86Priv.h" +#include "pciaccess.h" + + +static GCFuncs VGAarbiterGCFuncs = { + VGAarbiterValidateGC, VGAarbiterChangeGC, VGAarbiterCopyGC, + VGAarbiterDestroyGC, VGAarbiterChangeClip, VGAarbiterDestroyClip, + VGAarbiterCopyClip +}; + +static GCOps VGAarbiterGCOps = { + VGAarbiterFillSpans, VGAarbiterSetSpans, VGAarbiterPutImage, + VGAarbiterCopyArea, VGAarbiterCopyPlane, VGAarbiterPolyPoint, + VGAarbiterPolylines, VGAarbiterPolySegment, VGAarbiterPolyRectangle, + VGAarbiterPolyArc, VGAarbiterFillPolygon, VGAarbiterPolyFillRect, + VGAarbiterPolyFillArc, VGAarbiterPolyText8, VGAarbiterPolyText16, + VGAarbiterImageText8, VGAarbiterImageText16, VGAarbiterImageGlyphBlt, + VGAarbiterPolyGlyphBlt, VGAarbiterPushPixels, + {NULL} /* devPrivate */ +}; + +static miPointerSpriteFuncRec VGAarbiterSpriteFuncs = { + VGAarbiterSpriteRealizeCursor, VGAarbiterSpriteUnrealizeCursor, + VGAarbiterSpriteSetCursor, VGAarbiterSpriteMoveCursor, + VGAarbiterDeviceCursorInitialize, VGAarbiterDeviceCursorCleanup +}; + +static int VGAarbiterKeyIndex; +static DevPrivateKey VGAarbiterScreenKey = &VGAarbiterKeyIndex; +static int VGAarbiterGCIndex; +static DevPrivateKey VGAarbiterGCKey = &VGAarbiterGCIndex; + +static int vga_no_arb = 0; +void +xf86VGAarbiterInit(void) +{ + if (pci_device_vgaarb_init() != 0) { + vga_no_arb = 1; + xf86Msg(X_WARNING, "VGA arbiter: cannot open kernel arbiter, no multi-card support\n"); + } +} + +void +xf86VGAarbiterFini(void) +{ + if (vga_no_arb) + return; + pci_device_vgaarb_fini(); +} + +void +xf86VGAarbiterLock(ScrnInfoPtr pScrn) +{ + if (vga_no_arb) + return; + pci_device_vgaarb_set_target(pScrn->vgaDev); + pci_device_vgaarb_lock(); +} + +void +xf86VGAarbiterUnlock(ScrnInfoPtr pScrn) +{ + if (vga_no_arb) + return; + pci_device_vgaarb_unlock(); +} + +Bool xf86VGAarbiterAllowDRI(ScreenPtr pScreen) +{ + int vga_count; + int rsrc_decodes; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (vga_no_arb) + return TRUE; + + pci_device_vgaarb_get_info(pScrn->vgaDev, &vga_count, &rsrc_decodes); + if (vga_count > 1) { + if (rsrc_decodes) { + return FALSE; + } + } + return TRUE; +} + +void +xf86VGAarbiterScrnInit(ScrnInfoPtr pScrn) +{ + struct pci_device *dev; + EntityPtr pEnt; + + if (vga_no_arb) + return; + + pEnt = xf86Entities[pScrn->entityList[0]]; + if (pEnt->bus.type != BUS_PCI) + return; + + dev = pEnt->bus.id.pci; + pScrn->vgaDev = dev; +} + +void +xf86VGAarbiterDeviceDecodes(ScrnInfoPtr pScrn) +{ + if (vga_no_arb) + return; + pci_device_vgaarb_decodes(VGA_ARB_RSRC_LEGACY_MEM | VGA_ARB_RSRC_LEGACY_IO); +} + +Bool +xf86VGAarbiterWrapFunctions(void) +{ + ScrnInfoPtr pScrn; + VGAarbiterScreenPtr pScreenPriv; + miPointerScreenPtr PointPriv; + PictureScreenPtr ps; + ScreenPtr pScreen; + int vga_count, i; + + if (vga_no_arb) + return FALSE; + + /* + * we need to wrap the arbiter if we have more than + * one VGA card - hotplug cries. + */ + pci_device_vgaarb_get_info(NULL, &vga_count, NULL); + if (vga_count < 2 || !xf86Screens) + return FALSE; + + xf86Msg(X_INFO,"Found %d VGA devices: arbiter wrapping enabled\n", + vga_count); + + for (i = 0; i < xf86NumScreens; i++) { + pScreen = xf86Screens[i]->pScreen; + ps = GetPictureScreenIfSet(pScreen); + pScrn = xf86Screens[pScreen->myNum]; + PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); + + if (!dixRequestPrivate(VGAarbiterGCKey, sizeof(VGAarbiterGCRec))) + return FALSE; + + if (!(pScreenPriv = malloc(sizeof(VGAarbiterScreenRec)))) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, VGAarbiterScreenKey, pScreenPriv); + + WRAP_SCREEN(CloseScreen, VGAarbiterCloseScreen); + WRAP_SCREEN(SaveScreen, VGAarbiterSaveScreen); + WRAP_SCREEN(WakeupHandler, VGAarbiterWakeupHandler); + WRAP_SCREEN(BlockHandler, VGAarbiterBlockHandler); + WRAP_SCREEN(CreateGC, VGAarbiterCreateGC); + WRAP_SCREEN(GetImage, VGAarbiterGetImage); + WRAP_SCREEN(GetSpans, VGAarbiterGetSpans); + WRAP_SCREEN(SourceValidate, VGAarbiterSourceValidate); + WRAP_SCREEN(CopyWindow, VGAarbiterCopyWindow); + WRAP_SCREEN(ClearToBackground, VGAarbiterClearToBackground); + WRAP_SCREEN(CreatePixmap, VGAarbiterCreatePixmap); + WRAP_SCREEN(StoreColors, VGAarbiterStoreColors); + WRAP_SCREEN(DisplayCursor, VGAarbiterDisplayCursor); + WRAP_SCREEN(RealizeCursor, VGAarbiterRealizeCursor); + WRAP_SCREEN(UnrealizeCursor, VGAarbiterUnrealizeCursor); + WRAP_SCREEN(RecolorCursor, VGAarbiterRecolorCursor); + WRAP_SCREEN(SetCursorPosition, VGAarbiterSetCursorPosition); + WRAP_PICT(Composite,VGAarbiterComposite); + WRAP_PICT(Glyphs,VGAarbiterGlyphs); + WRAP_PICT(CompositeRects,VGAarbiterCompositeRects); + WRAP_SCREEN_INFO(AdjustFrame, VGAarbiterAdjustFrame); + WRAP_SCREEN_INFO(SwitchMode, VGAarbiterSwitchMode); + WRAP_SCREEN_INFO(EnterVT, VGAarbiterEnterVT); + WRAP_SCREEN_INFO(LeaveVT, VGAarbiterLeaveVT); + WRAP_SCREEN_INFO(FreeScreen, VGAarbiterFreeScreen); + WRAP_SPRITE; + } + + return TRUE; +} + +/* Screen funcs */ +static Bool +VGAarbiterCloseScreen (int i, ScreenPtr pScreen) +{ + Bool val; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, VGAarbiterScreenKey); + miPointerScreenPtr PointPriv = (miPointerScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, miPointerScreenKey); + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + + UNWRAP_SCREEN(CreateGC); + UNWRAP_SCREEN(CloseScreen); + UNWRAP_SCREEN(GetImage); + UNWRAP_SCREEN(GetSpans); + UNWRAP_SCREEN(SourceValidate); + UNWRAP_SCREEN(CopyWindow); + UNWRAP_SCREEN(ClearToBackground); + UNWRAP_SCREEN(SaveScreen); + UNWRAP_SCREEN(StoreColors); + UNWRAP_SCREEN(DisplayCursor); + UNWRAP_SCREEN(RealizeCursor); + UNWRAP_SCREEN(UnrealizeCursor); + UNWRAP_SCREEN(RecolorCursor); + UNWRAP_SCREEN(SetCursorPosition); + UNWRAP_PICT(Composite); + UNWRAP_PICT(Glyphs); + UNWRAP_PICT(CompositeRects); + UNWRAP_SCREEN_INFO(AdjustFrame); + UNWRAP_SCREEN_INFO(SwitchMode); + UNWRAP_SCREEN_INFO(EnterVT); + UNWRAP_SCREEN_INFO(LeaveVT); + UNWRAP_SCREEN_INFO(FreeScreen); + UNWRAP_SPRITE; + + free((pointer) pScreenPriv); + xf86VGAarbiterLock(xf86Screens[i]); + val = (*pScreen->CloseScreen) (i, pScreen); + xf86VGAarbiterUnlock(xf86Screens[i]); + return val; +} + +static void +VGAarbiterBlockHandler(int i, + pointer blockData, pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + SCREEN_PROLOG(BlockHandler); + VGAGet(); + pScreen->BlockHandler(i, blockData, pTimeout, pReadmask); + VGAPut(); + SCREEN_EPILOG(BlockHandler, VGAarbiterBlockHandler); +} + +static void +VGAarbiterWakeupHandler(int i, pointer blockData, unsigned long result, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + SCREEN_PROLOG(WakeupHandler); + VGAGet(); + pScreen->WakeupHandler(i, blockData, result, pReadmask); + VGAPut(); + SCREEN_EPILOG(WakeupHandler, VGAarbiterWakeupHandler); +} + +static void +VGAarbiterGetImage ( + DrawablePtr pDrawable, + int sx, int sy, int w, int h, + unsigned int format, + unsigned long planemask, + char *pdstLine + ) +{ + ScreenPtr pScreen = pDrawable->pScreen; + SCREEN_PROLOG(GetImage); +// if (xf86Screens[pScreen->myNum]->vtSema) { + VGAGet(); +// } + (*pScreen->GetImage) (pDrawable, sx, sy, w, h, + format, planemask, pdstLine); + VGAPut(); + SCREEN_EPILOG (GetImage, VGAarbiterGetImage); +} + +static void +VGAarbiterGetSpans ( + DrawablePtr pDrawable, + int wMax, + DDXPointPtr ppt, + int *pwidth, + int nspans, + char *pdstStart + ) +{ + ScreenPtr pScreen = pDrawable->pScreen; + + SCREEN_PROLOG (GetSpans); + VGAGet(); + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + VGAPut(); + SCREEN_EPILOG (GetSpans, VGAarbiterGetSpans); +} + +static void +VGAarbiterSourceValidate ( + DrawablePtr pDrawable, + int x, int y, int width, int height ) +{ + ScreenPtr pScreen = pDrawable->pScreen; + SCREEN_PROLOG (SourceValidate); + VGAGet(); + if (pScreen->SourceValidate) + (*pScreen->SourceValidate) (pDrawable, x, y, width, height); + VGAPut(); + SCREEN_EPILOG (SourceValidate, VGAarbiterSourceValidate); +} + +static void +VGAarbiterCopyWindow( + WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc ) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOG (CopyWindow); + VGAGet(); + (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc); + VGAPut(); + SCREEN_EPILOG (CopyWindow, VGAarbiterCopyWindow); +} + +static void +VGAarbiterClearToBackground ( + WindowPtr pWin, + int x, int y, + int w, int h, + Bool generateExposures ) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOG ( ClearToBackground); + VGAGet(); + (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); + VGAPut(); + SCREEN_EPILOG (ClearToBackground, VGAarbiterClearToBackground); +} + +static PixmapPtr +VGAarbiterCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, unsigned usage_hint) +{ + PixmapPtr pPix; + + SCREEN_PROLOG ( CreatePixmap); + VGAGet(); + pPix = (*pScreen->CreatePixmap) (pScreen, w, h, depth, usage_hint); + VGAPut(); + SCREEN_EPILOG (CreatePixmap, VGAarbiterCreatePixmap); + + return pPix; +} + +static Bool +VGAarbiterSaveScreen(ScreenPtr pScreen, Bool unblank) +{ + Bool val; + + SCREEN_PROLOG (SaveScreen); + VGAGet(); + val = (*pScreen->SaveScreen) (pScreen, unblank); + VGAPut(); + SCREEN_EPILOG (SaveScreen, VGAarbiterSaveScreen); + + return val; +} + +static void +VGAarbiterStoreColors ( + ColormapPtr pmap, + int ndef, + xColorItem *pdefs) +{ + ScreenPtr pScreen = pmap->pScreen; + + SCREEN_PROLOG (StoreColors); + VGAGet(); + (*pScreen->StoreColors) (pmap,ndef,pdefs); + VGAPut(); + SCREEN_EPILOG ( StoreColors, VGAarbiterStoreColors); +} + +static void +VGAarbiterRecolorCursor ( + DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCurs, + Bool displayed + ) +{ + SCREEN_PROLOG (RecolorCursor); + VGAGet(); + (*pScreen->RecolorCursor) (pDev, pScreen, pCurs, displayed); + VGAPut(); + SCREEN_EPILOG ( RecolorCursor, VGAarbiterRecolorCursor); +} + +static Bool +VGAarbiterRealizeCursor ( + DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor + ) +{ + Bool val; + + SCREEN_PROLOG (RealizeCursor); + VGAGet(); + val = (*pScreen->RealizeCursor) (pDev, pScreen,pCursor); + VGAPut(); + SCREEN_EPILOG ( RealizeCursor, VGAarbiterRealizeCursor); + return val; +} + +static Bool +VGAarbiterUnrealizeCursor ( + DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor + ) +{ + Bool val; + + SCREEN_PROLOG (UnrealizeCursor); + VGAGet(); + val = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); + VGAPut(); + SCREEN_EPILOG ( UnrealizeCursor, VGAarbiterUnrealizeCursor); + return val; +} + +static Bool +VGAarbiterDisplayCursor ( + DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor + ) +{ + Bool val; + + SCREEN_PROLOG (DisplayCursor); + VGAGet(); + val = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); + VGAPut(); + SCREEN_EPILOG ( DisplayCursor, VGAarbiterDisplayCursor); + return val; +} + +static Bool +VGAarbiterSetCursorPosition ( + DeviceIntPtr pDev, + ScreenPtr pScreen, + int x, int y, + Bool generateEvent) +{ + Bool val; + + SCREEN_PROLOG (SetCursorPosition); + VGAGet(); + val = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent); + VGAPut(); + SCREEN_EPILOG ( SetCursorPosition, VGAarbiterSetCursorPosition); + return val; +} + +static void +VGAarbiterAdjustFrame(int index, int x, int y, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, VGAarbiterScreenKey); + + VGAGet(); + (*pScreenPriv->AdjustFrame)(index, x, y, flags); + VGAPut(); +} + +static Bool +VGAarbiterSwitchMode(int index, DisplayModePtr mode, int flags) +{ + Bool val; + ScreenPtr pScreen = screenInfo.screens[index]; + VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, VGAarbiterScreenKey); + + VGAGet(); + val = (*pScreenPriv->SwitchMode)(index, mode, flags); + VGAPut(); + return val; +} + +static Bool +VGAarbiterEnterVT(int index, int flags) +{ + Bool val; + ScreenPtr pScreen = screenInfo.screens[index]; + VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, VGAarbiterScreenKey); + + VGAGet(); + val = (*pScreenPriv->EnterVT)(index, flags); + VGAPut(); + return val; +} + +static void +VGAarbiterLeaveVT(int index, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, VGAarbiterScreenKey); + + VGAGet(); + (*pScreenPriv->LeaveVT)(index, flags); + VGAPut(); +} + +static void +VGAarbiterFreeScreen(int index, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + VGAarbiterScreenPtr pScreenPriv = (VGAarbiterScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, VGAarbiterScreenKey); + + VGAGet(); + (*pScreenPriv->FreeScreen)(index, flags); + VGAPut(); +} + +static Bool +VGAarbiterCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + VGAarbiterGCPtr pGCPriv = (VGAarbiterGCPtr)dixLookupPrivate(&pGC->devPrivates, VGAarbiterGCKey); + Bool ret; + + SCREEN_PROLOG(CreateGC); + VGAGet(); + ret = (*pScreen->CreateGC)(pGC); + VGAPut(); + GC_WRAP(pGC); + SCREEN_EPILOG(CreateGC,VGAarbiterCreateGC); + + return ret; +} + +/* GC funcs */ +static void +VGAarbiterValidateGC( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw ) +{ + GC_UNWRAP(pGC); + (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); + GC_WRAP(pGC); +} + + +static void +VGAarbiterDestroyGC(GCPtr pGC) +{ + GC_UNWRAP (pGC); + (*pGC->funcs->DestroyGC)(pGC); + GC_WRAP (pGC); +} + +static void +VGAarbiterChangeGC ( + GCPtr pGC, + unsigned long mask) +{ + GC_UNWRAP (pGC); + (*pGC->funcs->ChangeGC) (pGC, mask); + GC_WRAP (pGC); +} + +static void +VGAarbiterCopyGC ( + GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst) +{ + GC_UNWRAP (pGCDst); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + GC_WRAP (pGCDst); +} + +static void +VGAarbiterChangeClip ( + GCPtr pGC, + int type, + pointer pvalue, + int nrects ) +{ + GC_UNWRAP (pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + GC_WRAP (pGC); +} + +static void +VGAarbiterCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + GC_UNWRAP (pgcDst); + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + GC_WRAP (pgcDst); +} + +static void +VGAarbiterDestroyClip(GCPtr pGC) +{ + GC_UNWRAP (pGC); + (* pGC->funcs->DestroyClip)(pGC); + GC_WRAP (pGC); +} + +/* GC Ops */ +static void +VGAarbiterFillSpans( + DrawablePtr pDraw, + GC *pGC, + int nInit, + DDXPointPtr pptInit, + int *pwidthInit, + int fSorted ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterSetSpans( + DrawablePtr pDraw, + GCPtr pGC, + char *pcharsrc, + register DDXPointPtr ppt, + int *pwidth, + int nspans, + int fSorted ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, ppt, pwidth, nspans, fSorted); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterPutImage( + DrawablePtr pDraw, + GCPtr pGC, + int depth, + int x, int y, int w, int h, + int leftPad, + int format, + char *pImage ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h, + leftPad, format, pImage); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static RegionPtr +VGAarbiterCopyArea( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty ) +{ + RegionPtr ret; + + GC_UNWRAP(pGC); + VGAGet_GC(); + ret = (*pGC->ops->CopyArea)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty); + VGAPut_GC(); + GC_WRAP(pGC); + return ret; +} + +static RegionPtr +VGAarbiterCopyPlane( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty, + unsigned long bitPlane ) +{ + RegionPtr ret; + + GC_UNWRAP(pGC); + VGAGet_GC(); + ret = (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, srcx, srcy, + width, height, dstx, dsty, bitPlane); + VGAPut_GC(); + GC_WRAP(pGC); + return ret; +} + +static void +VGAarbiterPolyPoint( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + xPoint *pptInit ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->PolyPoint)(pDraw, pGC, mode, npt, pptInit); + VGAPut_GC(); + GC_WRAP(pGC); +} + + +static void +VGAarbiterPolylines( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pptInit ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->Polylines)(pDraw, pGC, mode, npt, pptInit); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterPolySegment( + DrawablePtr pDraw, + GCPtr pGC, + int nseg, + xSegment *pSeg ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->PolySegment)(pDraw, pGC, nseg, pSeg); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterPolyRectangle( + DrawablePtr pDraw, + GCPtr pGC, + int nRectsInit, + xRectangle *pRectsInit ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->PolyRectangle)(pDraw, pGC, nRectsInit, pRectsInit); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterPolyArc( + DrawablePtr pDraw, + GCPtr pGC, + int narcs, + xArc *parcs ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->PolyArc)(pDraw, pGC, narcs, parcs); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterFillPolygon( + DrawablePtr pDraw, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr ptsIn ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, ptsIn); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterPolyFillRect( + DrawablePtr pDraw, + GCPtr pGC, + int nrectFill, + xRectangle *prectInit) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->PolyFillRect)(pDraw, pGC, nrectFill, prectInit); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterPolyFillArc( + DrawablePtr pDraw, + GCPtr pGC, + int narcs, + xArc *parcs ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->PolyFillArc)(pDraw, pGC, narcs, parcs); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static int +VGAarbiterPolyText8( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars ) +{ + int ret; + + GC_UNWRAP(pGC); + VGAGet_GC(); + ret = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars); + VGAPut_GC(); + GC_WRAP(pGC); + return ret; +} + +static int +VGAarbiterPolyText16( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars ) +{ + int ret; + + GC_UNWRAP(pGC); + VGAGet_GC(); + ret = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars); + VGAPut_GC(); + GC_WRAP(pGC); + return ret; +} + +static void +VGAarbiterImageText8( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterImageText16( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars); + VGAPut_GC(); + GC_WRAP(pGC); +} + + +static void +VGAarbiterImageGlyphBlt( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, xInit, yInit, + nglyph, ppci, pglyphBase); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterPolyGlyphBlt( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, xInit, yInit, + nglyph, ppci, pglyphBase); + VGAPut_GC(); + GC_WRAP(pGC); +} + +static void +VGAarbiterPushPixels( + GCPtr pGC, + PixmapPtr pBitMap, + DrawablePtr pDraw, + int dx, int dy, int xOrg, int yOrg ) +{ + GC_UNWRAP(pGC); + VGAGet_GC(); + (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); + VGAPut_GC(); + GC_WRAP(pGC); +} + + +/* miSpriteFuncs */ +static Bool +VGAarbiterSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCur) +{ + Bool val; + SPRITE_PROLOG; + VGAGet(); + val = PointPriv->spriteFuncs->RealizeCursor(pDev, pScreen, pCur); + VGAPut(); + SPRITE_EPILOG; + return val; +} + +static Bool +VGAarbiterSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCur) +{ + Bool val; + SPRITE_PROLOG; + VGAGet(); + val = PointPriv->spriteFuncs->UnrealizeCursor(pDev, pScreen, pCur); + VGAPut(); + SPRITE_EPILOG; + return val; +} + +static void +VGAarbiterSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCur, int x, int y) +{ + SPRITE_PROLOG; + VGAGet(); + PointPriv->spriteFuncs->SetCursor(pDev, pScreen, pCur, x, y); + VGAPut(); + SPRITE_EPILOG; +} + +static void +VGAarbiterSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + SPRITE_PROLOG; + VGAGet(); + PointPriv->spriteFuncs->MoveCursor(pDev, pScreen, x, y); + VGAPut(); + SPRITE_EPILOG; +} + +static Bool +VGAarbiterDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + Bool val; + SPRITE_PROLOG; + VGAGet(); + val = PointPriv->spriteFuncs->DeviceCursorInitialize(pDev, pScreen); + VGAPut(); + SPRITE_EPILOG; + return val; +} + +static void +VGAarbiterDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + SPRITE_PROLOG; + VGAGet(); + PointPriv->spriteFuncs->DeviceCursorCleanup(pDev, pScreen); + VGAPut(); + SPRITE_EPILOG; +} + +static void +VGAarbiterComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, + PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, + INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, + CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + + PICTURE_PROLOGUE(Composite); + + VGAGet(); + (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, + yDst, width, height); + VGAPut(); + PICTURE_EPILOGUE(Composite, VGAarbiterComposite); +} + +static void +VGAarbiterGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, + GlyphListPtr list, GlyphPtr *glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + + PICTURE_PROLOGUE(Glyphs); + + VGAGet(); + (*ps->Glyphs)(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); + VGAPut(); + PICTURE_EPILOGUE (Glyphs, VGAarbiterGlyphs); +} + +static void +VGAarbiterCompositeRects(CARD8 op, PicturePtr pDst, xRenderColor *color, int nRect, + xRectangle *rects) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + + PICTURE_PROLOGUE(CompositeRects); + + VGAGet(); + (*ps->CompositeRects)(op, pDst, color, nRect, rects); + VGAPut(); + PICTURE_EPILOGUE (CompositeRects, VGAarbiterCompositeRects); +} +#else +/* dummy functions */ +void xf86VGAarbiterInit(void) {} +void xf86VGAarbiterFini(void) {} + +void xf86VGAarbiterLock(ScrnInfoPtr pScrn) {} +void xf86VGAarbiterUnlock(ScrnInfoPtr pScrn) {} +Bool xf86VGAarbiterAllowDRI(ScreenPtr pScreen) { return TRUE; } +void xf86VGAarbiterScrnInit(ScrnInfoPtr pScrn) {} +void xf86VGAarbiterDeviceDecodes(ScrnInfoPtr pScrn) {} +Bool xf86VGAarbiterWrapFunctions(void) { return FALSE; } + +#endif diff --git a/xorg-server/hw/xfree86/common/xf86VidMode.c b/xorg-server/hw/xfree86/common/xf86VidMode.c index 49b86e73a..08f27b8e4 100644 --- a/xorg-server/hw/xfree86/common/xf86VidMode.c +++ b/xorg-server/hw/xfree86/common/xf86VidMode.c @@ -1,667 +1,667 @@ -/* - * Copyright (c) 1999-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * This file contains the VidMode functions required by the extension. - * These have been added to avoid the need for the higher level extension - * code to access the private XFree86 data structures directly. Wherever - * possible this code uses the functions in xf86Mode.c to do the work, - * so that two version of code that do similar things don't have to be - * maintained. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include "os.h" -#include "xf86.h" -#include "xf86Priv.h" - -#ifdef XF86VIDMODE -#include "vidmodeproc.h" -#include "xf86cmap.h" - -static int VidModeKeyIndex; -static DevPrivateKey VidModeKey; -static int VidModeCount = 0; -static Bool VidModeClose(int i, ScreenPtr pScreen); - -#define VMPTR(p) ((VidModePtr)dixLookupPrivate(&(p)->devPrivates, VidModeKey)) - -#endif - -Bool -VidModeExtensionInit(ScreenPtr pScreen) -{ -#ifdef XF86VIDMODE - VidModePtr pVidMode; - - if (!xf86GetVidModeEnabled()) { - DebugF("!xf86GetVidModeEnabled()\n"); - return FALSE; - } - - VidModeKey = &VidModeKeyIndex; - - if (!dixSetPrivate(&pScreen->devPrivates, VidModeKey, - xcalloc(sizeof(VidModeRec), 1))) { - DebugF("xcalloc failed\n"); - return FALSE; - } - - pVidMode = VMPTR(pScreen); - pVidMode->Flags = 0; - pVidMode->Next = NULL; - pVidMode->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = VidModeClose; - VidModeCount++; - return TRUE; -#else - DebugF("no vidmode extension\n"); - return FALSE; -#endif -} - - -#ifdef XF86VIDMODE - -static Bool -VidModeClose(int i, ScreenPtr pScreen) -{ - VidModePtr pVidMode = VMPTR(pScreen); - - /* This shouldn't happen */ - if (!pVidMode) - return FALSE; - - pScreen->CloseScreen = pVidMode->CloseScreen; - - if (--VidModeCount == 0) { - xfree(dixLookupPrivate(&pScreen->devPrivates, VidModeKey)); - dixSetPrivate(&pScreen->devPrivates, VidModeKey, NULL); - VidModeKey = NULL; - } - return pScreen->CloseScreen(i, pScreen); -} - -Bool -VidModeAvailable(int scrnIndex) -{ - ScrnInfoPtr pScrn; - VidModePtr pVidMode; - - if (VidModeKey == NULL) { - DebugF("VidModeKey == NULL\n"); - return FALSE; - } - - pScrn = xf86Screens[scrnIndex]; - if (pScrn == NULL) { - DebugF("pScrn == NULL\n"); - return FALSE; - } - - pVidMode = VMPTR(pScrn->pScreen); - if (pVidMode) - return TRUE; - else { - DebugF("pVidMode == NULL\n"); - return FALSE; - } -} - -Bool -VidModeGetCurrentModeline(int scrnIndex, pointer *mode, int *dotClock) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - - if (pScrn->currentMode) { - *mode = (pointer)(pScrn->currentMode); - *dotClock = pScrn->currentMode->Clock; - - return TRUE; - } - return FALSE; -} - -int -VidModeGetDotClock(int scrnIndex, int Clock) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return 0; - - pScrn = xf86Screens[scrnIndex]; - if ((pScrn->progClock) || (Clock >= MAXCLOCKS)) - return Clock; - else - return pScrn->clock[Clock]; -} - -int -VidModeGetNumOfClocks(int scrnIndex, Bool *progClock) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return 0; - - pScrn = xf86Screens[scrnIndex]; - if (pScrn->progClock){ - *progClock = TRUE; - return 0; - } else { - *progClock = FALSE; - return pScrn->numClocks; - } -} - -Bool -VidModeGetClocks(int scrnIndex, int *Clocks) -{ - ScrnInfoPtr pScrn; - int i; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - - if (pScrn->progClock) - return FALSE; - - for (i = 0; i < pScrn->numClocks; i++) - *Clocks++ = pScrn->clock[i]; - - return TRUE; -} - - -Bool -VidModeGetFirstModeline(int scrnIndex, pointer *mode, int *dotClock) -{ - ScrnInfoPtr pScrn; - VidModePtr pVidMode; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - pVidMode = VMPTR(pScrn->pScreen); - pVidMode->First = pScrn->modes; - pVidMode->Next = pVidMode->First->next; - - if (pVidMode->First->status == MODE_OK) { - *mode = (pointer)(pVidMode->First); - *dotClock = VidModeGetDotClock(scrnIndex, pVidMode->First->Clock); - return TRUE; - } - - return VidModeGetNextModeline(scrnIndex, mode, dotClock); -} - -Bool -VidModeGetNextModeline(int scrnIndex, pointer *mode, int *dotClock) -{ - ScrnInfoPtr pScrn; - VidModePtr pVidMode; - DisplayModePtr p; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - pVidMode = VMPTR(pScrn->pScreen); - - for (p = pVidMode->Next; p != NULL && p != pVidMode->First; p = p->next) { - if (p->status == MODE_OK) { - pVidMode->Next = p->next; - *mode = (pointer)p; - *dotClock = VidModeGetDotClock(scrnIndex, p->Clock); - return TRUE; - } - } - - return FALSE; -} - -Bool -VidModeDeleteModeline(int scrnIndex, pointer mode) -{ - ScrnInfoPtr pScrn; - - if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - xf86DeleteMode(&(pScrn->modes), (DisplayModePtr)mode); - return TRUE; -} - -Bool -VidModeZoomViewport(int scrnIndex, int zoom) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - xf86ZoomViewport(pScrn->pScreen, zoom); - return TRUE; -} - -Bool -VidModeSetViewPort(int scrnIndex, int x, int y) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - pScrn->frameX0 = min( max(x, 0), - pScrn->virtualX - pScrn->currentMode->HDisplay ); - pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay - 1; - pScrn->frameY0 = min( max(y, 0), - pScrn->virtualY - pScrn->currentMode->VDisplay ); - pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay - 1; - if (pScrn->AdjustFrame != NULL) - (pScrn->AdjustFrame)(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); - - return TRUE; -} - -Bool -VidModeGetViewPort(int scrnIndex, int *x, int *y) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - *x = pScrn->frameX0; - *y = pScrn->frameY0; - return TRUE; -} - -Bool -VidModeSwitchMode(int scrnIndex, pointer mode) -{ - ScrnInfoPtr pScrn; - DisplayModePtr pTmpMode; - Bool retval; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - /* save in case we fail */ - pTmpMode = pScrn->currentMode; - /* Force a mode switch */ - pScrn->currentMode = NULL; - retval = xf86SwitchMode(pScrn->pScreen, mode); - /* we failed: restore it */ - if (retval == FALSE) - pScrn->currentMode = pTmpMode; - return retval; -} - -Bool -VidModeLockZoom(int scrnIndex, Bool lock) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - - if (xf86Info.dontZoom) - return FALSE; - - xf86LockZoom(pScrn->pScreen, lock); - return TRUE; -} - -Bool -VidModeGetMonitor(int scrnIndex, pointer *monitor) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - *monitor = (pointer)(pScrn->monitor); - - return TRUE; -} - -ModeStatus -VidModeCheckModeForMonitor(int scrnIndex, pointer mode) -{ - ScrnInfoPtr pScrn; - - if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) - return MODE_ERROR; - - pScrn = xf86Screens[scrnIndex]; - - return xf86CheckModeForMonitor((DisplayModePtr)mode, pScrn->monitor); -} - -ModeStatus -VidModeCheckModeForDriver(int scrnIndex, pointer mode) -{ - ScrnInfoPtr pScrn; - - if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) - return MODE_ERROR; - - pScrn = xf86Screens[scrnIndex]; - - return xf86CheckModeForDriver(pScrn, (DisplayModePtr)mode, 0); -} - -void -VidModeSetCrtcForMode(int scrnIndex, pointer mode) -{ - ScrnInfoPtr pScrn; - DisplayModePtr ScreenModes; - - if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) - return; - - /* Ugly hack so that the xf86Mode.c function can be used without change */ - pScrn = xf86Screens[scrnIndex]; - ScreenModes = pScrn->modes; - pScrn->modes = (DisplayModePtr)mode; - - xf86SetCrtcForModes(pScrn, pScrn->adjustFlags); - pScrn->modes = ScreenModes; - return; -} - -Bool -VidModeAddModeline(int scrnIndex, pointer mode) -{ - ScrnInfoPtr pScrn; - - if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - - ((DisplayModePtr)mode)->name = strdup(""); /* freed by deletemode */ - ((DisplayModePtr)mode)->status = MODE_OK; - ((DisplayModePtr)mode)->next = pScrn->modes->next; - ((DisplayModePtr)mode)->prev = pScrn->modes; - pScrn->modes->next = (DisplayModePtr)mode; - if( ((DisplayModePtr)mode)->next != NULL ) - ((DisplayModePtr)mode)->next->prev = (DisplayModePtr)mode; - - return TRUE; -} - -int -VidModeGetNumOfModes(int scrnIndex) -{ - pointer mode = NULL; - int dotClock= 0, nummodes = 0; - - if (!VidModeGetFirstModeline(scrnIndex, &mode, &dotClock)) - return nummodes; - - do { - nummodes++; - if (!VidModeGetNextModeline(scrnIndex, &mode, &dotClock)) - return nummodes; - } while (TRUE); -} - -Bool -VidModeSetGamma(int scrnIndex, float red, float green, float blue) -{ - ScrnInfoPtr pScrn; - Gamma gamma; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - gamma.red = red; - gamma.green = green; - gamma.blue = blue; - if (xf86ChangeGamma(pScrn->pScreen, gamma) != Success) - return FALSE; - else - return TRUE; -} - -Bool -VidModeGetGamma(int scrnIndex, float *red, float *green, float *blue) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - *red = pScrn->gamma.red; - *green = pScrn->gamma.green; - *blue = pScrn->gamma.blue; - return TRUE; -} - -Bool -VidModeSetGammaRamp(int scrnIndex, int size, CARD16 *r, CARD16 *g, CARD16 *b) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - xf86ChangeGammaRamp(pScrn->pScreen, size, r, g, b); - return TRUE; -} - -Bool -VidModeGetGammaRamp(int scrnIndex, int size, CARD16 *r, CARD16 *g, CARD16 *b) -{ - ScrnInfoPtr pScrn; - - if (!VidModeAvailable(scrnIndex)) - return FALSE; - - pScrn = xf86Screens[scrnIndex]; - xf86GetGammaRamp(pScrn->pScreen, size, r, g, b); - return TRUE; -} - -int -VidModeGetGammaRampSize(int scrnIndex) -{ - if (!VidModeAvailable(scrnIndex)) - return 0; - - return xf86GetGammaRampSize(xf86Screens[scrnIndex]->pScreen); -} - -pointer -VidModeCreateMode(void) -{ - DisplayModePtr mode; - - mode = xalloc(sizeof(DisplayModeRec)); - if (mode != NULL) { - mode->name = ""; - mode->VScan = 1; /* divides refresh rate. default = 1 */ - mode->Private = NULL; - mode->next = mode; - mode->prev = mode; - } - return mode; -} - -void -VidModeCopyMode(pointer modefrom, pointer modeto) -{ - memcpy(modeto, modefrom, sizeof(DisplayModeRec)); -} - - -int -VidModeGetModeValue(pointer mode, int valtyp) -{ - int ret = 0; - - switch (valtyp) { - case VIDMODE_H_DISPLAY: - ret = ((DisplayModePtr) mode)->HDisplay; - break; - case VIDMODE_H_SYNCSTART: - ret = ((DisplayModePtr)mode)->HSyncStart; - break; - case VIDMODE_H_SYNCEND: - ret = ((DisplayModePtr)mode)->HSyncEnd; - break; - case VIDMODE_H_TOTAL: - ret = ((DisplayModePtr)mode)->HTotal; - break; - case VIDMODE_H_SKEW: - ret = ((DisplayModePtr)mode)->HSkew; - break; - case VIDMODE_V_DISPLAY: - ret = ((DisplayModePtr)mode)->VDisplay; - break; - case VIDMODE_V_SYNCSTART: - ret = ((DisplayModePtr)mode)->VSyncStart; - break; - case VIDMODE_V_SYNCEND: - ret = ((DisplayModePtr)mode)->VSyncEnd; - break; - case VIDMODE_V_TOTAL: - ret = ((DisplayModePtr)mode)->VTotal; - break; - case VIDMODE_FLAGS: - ret = ((DisplayModePtr)mode)->Flags; - break; - case VIDMODE_CLOCK: - ret = ((DisplayModePtr)mode)->Clock; - break; - } - return ret; -} - -void -VidModeSetModeValue(pointer mode, int valtyp, int val) -{ - switch (valtyp) { - case VIDMODE_H_DISPLAY: - ((DisplayModePtr)mode)->HDisplay = val; - break; - case VIDMODE_H_SYNCSTART: - ((DisplayModePtr)mode)->HSyncStart = val; - break; - case VIDMODE_H_SYNCEND: - ((DisplayModePtr)mode)->HSyncEnd = val; - break; - case VIDMODE_H_TOTAL: - ((DisplayModePtr)mode)->HTotal = val; - break; - case VIDMODE_H_SKEW: - ((DisplayModePtr)mode)->HSkew = val; - break; - case VIDMODE_V_DISPLAY: - ((DisplayModePtr)mode)->VDisplay = val; - break; - case VIDMODE_V_SYNCSTART: - ((DisplayModePtr)mode)->VSyncStart = val; - break; - case VIDMODE_V_SYNCEND: - ((DisplayModePtr)mode)->VSyncEnd = val; - break; - case VIDMODE_V_TOTAL: - ((DisplayModePtr)mode)->VTotal = val; - break; - case VIDMODE_FLAGS: - ((DisplayModePtr)mode)->Flags = val; - break; - case VIDMODE_CLOCK: - ((DisplayModePtr)mode)->Clock = val; - break; - } - return; -} - -vidMonitorValue -VidModeGetMonitorValue(pointer monitor, int valtyp, int indx) -{ - vidMonitorValue ret; - - switch (valtyp) { - case VIDMODE_MON_VENDOR: - ret.ptr = (((MonPtr)monitor)->vendor); - break; - case VIDMODE_MON_MODEL: - ret.ptr = (((MonPtr)monitor)->model); - break; - case VIDMODE_MON_NHSYNC: - ret.i = ((MonPtr)monitor)->nHsync; - break; - case VIDMODE_MON_NVREFRESH: - ret.i = ((MonPtr)monitor)->nVrefresh; - break; - case VIDMODE_MON_HSYNC_LO: - ret.f = (100.0 * ((MonPtr)monitor)->hsync[indx].lo); - break; - case VIDMODE_MON_HSYNC_HI: - ret.f = (100.0 * ((MonPtr)monitor)->hsync[indx].hi); - break; - case VIDMODE_MON_VREFRESH_LO: - ret.f = (100.0 * ((MonPtr)monitor)->vrefresh[indx].lo); - break; - case VIDMODE_MON_VREFRESH_HI: - ret.f = (100.0 * ((MonPtr)monitor)->vrefresh[indx].hi); - break; - } - return ret; -} - - -#endif /* XF86VIDMODE */ +/* + * Copyright (c) 1999-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * This file contains the VidMode functions required by the extension. + * These have been added to avoid the need for the higher level extension + * code to access the private XFree86 data structures directly. Wherever + * possible this code uses the functions in xf86Mode.c to do the work, + * so that two version of code that do similar things don't have to be + * maintained. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "os.h" +#include "xf86.h" +#include "xf86Priv.h" + +#ifdef XF86VIDMODE +#include "vidmodeproc.h" +#include "xf86cmap.h" + +static int VidModeKeyIndex; +static DevPrivateKey VidModeKey; +static int VidModeCount = 0; +static Bool VidModeClose(int i, ScreenPtr pScreen); + +#define VMPTR(p) ((VidModePtr)dixLookupPrivate(&(p)->devPrivates, VidModeKey)) + +#endif + +Bool +VidModeExtensionInit(ScreenPtr pScreen) +{ +#ifdef XF86VIDMODE + VidModePtr pVidMode; + + if (!xf86GetVidModeEnabled()) { + DebugF("!xf86GetVidModeEnabled()\n"); + return FALSE; + } + + VidModeKey = &VidModeKeyIndex; + + if (!dixSetPrivate(&pScreen->devPrivates, VidModeKey, + calloc(sizeof(VidModeRec), 1))) { + DebugF("xcalloc failed\n"); + return FALSE; + } + + pVidMode = VMPTR(pScreen); + pVidMode->Flags = 0; + pVidMode->Next = NULL; + pVidMode->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = VidModeClose; + VidModeCount++; + return TRUE; +#else + DebugF("no vidmode extension\n"); + return FALSE; +#endif +} + + +#ifdef XF86VIDMODE + +static Bool +VidModeClose(int i, ScreenPtr pScreen) +{ + VidModePtr pVidMode = VMPTR(pScreen); + + /* This shouldn't happen */ + if (!pVidMode) + return FALSE; + + pScreen->CloseScreen = pVidMode->CloseScreen; + + if (--VidModeCount == 0) { + free(dixLookupPrivate(&pScreen->devPrivates, VidModeKey)); + dixSetPrivate(&pScreen->devPrivates, VidModeKey, NULL); + VidModeKey = NULL; + } + return pScreen->CloseScreen(i, pScreen); +} + +Bool +VidModeAvailable(int scrnIndex) +{ + ScrnInfoPtr pScrn; + VidModePtr pVidMode; + + if (VidModeKey == NULL) { + DebugF("VidModeKey == NULL\n"); + return FALSE; + } + + pScrn = xf86Screens[scrnIndex]; + if (pScrn == NULL) { + DebugF("pScrn == NULL\n"); + return FALSE; + } + + pVidMode = VMPTR(pScrn->pScreen); + if (pVidMode) + return TRUE; + else { + DebugF("pVidMode == NULL\n"); + return FALSE; + } +} + +Bool +VidModeGetCurrentModeline(int scrnIndex, pointer *mode, int *dotClock) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + + if (pScrn->currentMode) { + *mode = (pointer)(pScrn->currentMode); + *dotClock = pScrn->currentMode->Clock; + + return TRUE; + } + return FALSE; +} + +int +VidModeGetDotClock(int scrnIndex, int Clock) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return 0; + + pScrn = xf86Screens[scrnIndex]; + if ((pScrn->progClock) || (Clock >= MAXCLOCKS)) + return Clock; + else + return pScrn->clock[Clock]; +} + +int +VidModeGetNumOfClocks(int scrnIndex, Bool *progClock) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return 0; + + pScrn = xf86Screens[scrnIndex]; + if (pScrn->progClock){ + *progClock = TRUE; + return 0; + } else { + *progClock = FALSE; + return pScrn->numClocks; + } +} + +Bool +VidModeGetClocks(int scrnIndex, int *Clocks) +{ + ScrnInfoPtr pScrn; + int i; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + + if (pScrn->progClock) + return FALSE; + + for (i = 0; i < pScrn->numClocks; i++) + *Clocks++ = pScrn->clock[i]; + + return TRUE; +} + + +Bool +VidModeGetFirstModeline(int scrnIndex, pointer *mode, int *dotClock) +{ + ScrnInfoPtr pScrn; + VidModePtr pVidMode; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + pVidMode = VMPTR(pScrn->pScreen); + pVidMode->First = pScrn->modes; + pVidMode->Next = pVidMode->First->next; + + if (pVidMode->First->status == MODE_OK) { + *mode = (pointer)(pVidMode->First); + *dotClock = VidModeGetDotClock(scrnIndex, pVidMode->First->Clock); + return TRUE; + } + + return VidModeGetNextModeline(scrnIndex, mode, dotClock); +} + +Bool +VidModeGetNextModeline(int scrnIndex, pointer *mode, int *dotClock) +{ + ScrnInfoPtr pScrn; + VidModePtr pVidMode; + DisplayModePtr p; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + pVidMode = VMPTR(pScrn->pScreen); + + for (p = pVidMode->Next; p != NULL && p != pVidMode->First; p = p->next) { + if (p->status == MODE_OK) { + pVidMode->Next = p->next; + *mode = (pointer)p; + *dotClock = VidModeGetDotClock(scrnIndex, p->Clock); + return TRUE; + } + } + + return FALSE; +} + +Bool +VidModeDeleteModeline(int scrnIndex, pointer mode) +{ + ScrnInfoPtr pScrn; + + if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + xf86DeleteMode(&(pScrn->modes), (DisplayModePtr)mode); + return TRUE; +} + +Bool +VidModeZoomViewport(int scrnIndex, int zoom) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + xf86ZoomViewport(pScrn->pScreen, zoom); + return TRUE; +} + +Bool +VidModeSetViewPort(int scrnIndex, int x, int y) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + pScrn->frameX0 = min( max(x, 0), + pScrn->virtualX - pScrn->currentMode->HDisplay ); + pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay - 1; + pScrn->frameY0 = min( max(y, 0), + pScrn->virtualY - pScrn->currentMode->VDisplay ); + pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay - 1; + if (pScrn->AdjustFrame != NULL) + (pScrn->AdjustFrame)(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + return TRUE; +} + +Bool +VidModeGetViewPort(int scrnIndex, int *x, int *y) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + *x = pScrn->frameX0; + *y = pScrn->frameY0; + return TRUE; +} + +Bool +VidModeSwitchMode(int scrnIndex, pointer mode) +{ + ScrnInfoPtr pScrn; + DisplayModePtr pTmpMode; + Bool retval; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + /* save in case we fail */ + pTmpMode = pScrn->currentMode; + /* Force a mode switch */ + pScrn->currentMode = NULL; + retval = xf86SwitchMode(pScrn->pScreen, mode); + /* we failed: restore it */ + if (retval == FALSE) + pScrn->currentMode = pTmpMode; + return retval; +} + +Bool +VidModeLockZoom(int scrnIndex, Bool lock) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + + if (xf86Info.dontZoom) + return FALSE; + + xf86LockZoom(pScrn->pScreen, lock); + return TRUE; +} + +Bool +VidModeGetMonitor(int scrnIndex, pointer *monitor) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + *monitor = (pointer)(pScrn->monitor); + + return TRUE; +} + +ModeStatus +VidModeCheckModeForMonitor(int scrnIndex, pointer mode) +{ + ScrnInfoPtr pScrn; + + if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) + return MODE_ERROR; + + pScrn = xf86Screens[scrnIndex]; + + return xf86CheckModeForMonitor((DisplayModePtr)mode, pScrn->monitor); +} + +ModeStatus +VidModeCheckModeForDriver(int scrnIndex, pointer mode) +{ + ScrnInfoPtr pScrn; + + if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) + return MODE_ERROR; + + pScrn = xf86Screens[scrnIndex]; + + return xf86CheckModeForDriver(pScrn, (DisplayModePtr)mode, 0); +} + +void +VidModeSetCrtcForMode(int scrnIndex, pointer mode) +{ + ScrnInfoPtr pScrn; + DisplayModePtr ScreenModes; + + if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) + return; + + /* Ugly hack so that the xf86Mode.c function can be used without change */ + pScrn = xf86Screens[scrnIndex]; + ScreenModes = pScrn->modes; + pScrn->modes = (DisplayModePtr)mode; + + xf86SetCrtcForModes(pScrn, pScrn->adjustFlags); + pScrn->modes = ScreenModes; + return; +} + +Bool +VidModeAddModeline(int scrnIndex, pointer mode) +{ + ScrnInfoPtr pScrn; + + if ((mode == NULL) || (!VidModeAvailable(scrnIndex))) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + + ((DisplayModePtr)mode)->name = strdup(""); /* freed by deletemode */ + ((DisplayModePtr)mode)->status = MODE_OK; + ((DisplayModePtr)mode)->next = pScrn->modes->next; + ((DisplayModePtr)mode)->prev = pScrn->modes; + pScrn->modes->next = (DisplayModePtr)mode; + if( ((DisplayModePtr)mode)->next != NULL ) + ((DisplayModePtr)mode)->next->prev = (DisplayModePtr)mode; + + return TRUE; +} + +int +VidModeGetNumOfModes(int scrnIndex) +{ + pointer mode = NULL; + int dotClock= 0, nummodes = 0; + + if (!VidModeGetFirstModeline(scrnIndex, &mode, &dotClock)) + return nummodes; + + do { + nummodes++; + if (!VidModeGetNextModeline(scrnIndex, &mode, &dotClock)) + return nummodes; + } while (TRUE); +} + +Bool +VidModeSetGamma(int scrnIndex, float red, float green, float blue) +{ + ScrnInfoPtr pScrn; + Gamma gamma; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + gamma.red = red; + gamma.green = green; + gamma.blue = blue; + if (xf86ChangeGamma(pScrn->pScreen, gamma) != Success) + return FALSE; + else + return TRUE; +} + +Bool +VidModeGetGamma(int scrnIndex, float *red, float *green, float *blue) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + *red = pScrn->gamma.red; + *green = pScrn->gamma.green; + *blue = pScrn->gamma.blue; + return TRUE; +} + +Bool +VidModeSetGammaRamp(int scrnIndex, int size, CARD16 *r, CARD16 *g, CARD16 *b) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + xf86ChangeGammaRamp(pScrn->pScreen, size, r, g, b); + return TRUE; +} + +Bool +VidModeGetGammaRamp(int scrnIndex, int size, CARD16 *r, CARD16 *g, CARD16 *b) +{ + ScrnInfoPtr pScrn; + + if (!VidModeAvailable(scrnIndex)) + return FALSE; + + pScrn = xf86Screens[scrnIndex]; + xf86GetGammaRamp(pScrn->pScreen, size, r, g, b); + return TRUE; +} + +int +VidModeGetGammaRampSize(int scrnIndex) +{ + if (!VidModeAvailable(scrnIndex)) + return 0; + + return xf86GetGammaRampSize(xf86Screens[scrnIndex]->pScreen); +} + +pointer +VidModeCreateMode(void) +{ + DisplayModePtr mode; + + mode = malloc(sizeof(DisplayModeRec)); + if (mode != NULL) { + mode->name = ""; + mode->VScan = 1; /* divides refresh rate. default = 1 */ + mode->Private = NULL; + mode->next = mode; + mode->prev = mode; + } + return mode; +} + +void +VidModeCopyMode(pointer modefrom, pointer modeto) +{ + memcpy(modeto, modefrom, sizeof(DisplayModeRec)); +} + + +int +VidModeGetModeValue(pointer mode, int valtyp) +{ + int ret = 0; + + switch (valtyp) { + case VIDMODE_H_DISPLAY: + ret = ((DisplayModePtr) mode)->HDisplay; + break; + case VIDMODE_H_SYNCSTART: + ret = ((DisplayModePtr)mode)->HSyncStart; + break; + case VIDMODE_H_SYNCEND: + ret = ((DisplayModePtr)mode)->HSyncEnd; + break; + case VIDMODE_H_TOTAL: + ret = ((DisplayModePtr)mode)->HTotal; + break; + case VIDMODE_H_SKEW: + ret = ((DisplayModePtr)mode)->HSkew; + break; + case VIDMODE_V_DISPLAY: + ret = ((DisplayModePtr)mode)->VDisplay; + break; + case VIDMODE_V_SYNCSTART: + ret = ((DisplayModePtr)mode)->VSyncStart; + break; + case VIDMODE_V_SYNCEND: + ret = ((DisplayModePtr)mode)->VSyncEnd; + break; + case VIDMODE_V_TOTAL: + ret = ((DisplayModePtr)mode)->VTotal; + break; + case VIDMODE_FLAGS: + ret = ((DisplayModePtr)mode)->Flags; + break; + case VIDMODE_CLOCK: + ret = ((DisplayModePtr)mode)->Clock; + break; + } + return ret; +} + +void +VidModeSetModeValue(pointer mode, int valtyp, int val) +{ + switch (valtyp) { + case VIDMODE_H_DISPLAY: + ((DisplayModePtr)mode)->HDisplay = val; + break; + case VIDMODE_H_SYNCSTART: + ((DisplayModePtr)mode)->HSyncStart = val; + break; + case VIDMODE_H_SYNCEND: + ((DisplayModePtr)mode)->HSyncEnd = val; + break; + case VIDMODE_H_TOTAL: + ((DisplayModePtr)mode)->HTotal = val; + break; + case VIDMODE_H_SKEW: + ((DisplayModePtr)mode)->HSkew = val; + break; + case VIDMODE_V_DISPLAY: + ((DisplayModePtr)mode)->VDisplay = val; + break; + case VIDMODE_V_SYNCSTART: + ((DisplayModePtr)mode)->VSyncStart = val; + break; + case VIDMODE_V_SYNCEND: + ((DisplayModePtr)mode)->VSyncEnd = val; + break; + case VIDMODE_V_TOTAL: + ((DisplayModePtr)mode)->VTotal = val; + break; + case VIDMODE_FLAGS: + ((DisplayModePtr)mode)->Flags = val; + break; + case VIDMODE_CLOCK: + ((DisplayModePtr)mode)->Clock = val; + break; + } + return; +} + +vidMonitorValue +VidModeGetMonitorValue(pointer monitor, int valtyp, int indx) +{ + vidMonitorValue ret; + + switch (valtyp) { + case VIDMODE_MON_VENDOR: + ret.ptr = (((MonPtr)monitor)->vendor); + break; + case VIDMODE_MON_MODEL: + ret.ptr = (((MonPtr)monitor)->model); + break; + case VIDMODE_MON_NHSYNC: + ret.i = ((MonPtr)monitor)->nHsync; + break; + case VIDMODE_MON_NVREFRESH: + ret.i = ((MonPtr)monitor)->nVrefresh; + break; + case VIDMODE_MON_HSYNC_LO: + ret.f = (100.0 * ((MonPtr)monitor)->hsync[indx].lo); + break; + case VIDMODE_MON_HSYNC_HI: + ret.f = (100.0 * ((MonPtr)monitor)->hsync[indx].hi); + break; + case VIDMODE_MON_VREFRESH_LO: + ret.f = (100.0 * ((MonPtr)monitor)->vrefresh[indx].lo); + break; + case VIDMODE_MON_VREFRESH_HI: + ret.f = (100.0 * ((MonPtr)monitor)->vrefresh[indx].hi); + break; + } + return ret; +} + + +#endif /* XF86VIDMODE */ diff --git a/xorg-server/hw/xfree86/common/xf86Xinput.c b/xorg-server/hw/xfree86/common/xf86Xinput.c index a1a5527f4..f1096f1a5 100644 --- a/xorg-server/hw/xfree86/common/xf86Xinput.c +++ b/xorg-server/hw/xfree86/common/xf86Xinput.c @@ -1,1284 +1,1284 @@ -/* - * Copyright 1995-1999 by Frederic Lepied, France. <Lepied@XFree86.org> - * - * 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 Frederic Lepied not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Frederic Lepied makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * FREDERIC LEPIED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL FREDERIC LEPIED 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. - * - */ -/* - * Copyright (c) 2000-2002 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of the copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/Xfuncproto.h> -#include <X11/Xmd.h> -#include <X11/extensions/XI.h> -#include <X11/extensions/XIproto.h> -#include <X11/Xatom.h> -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86Config.h" -#include "xf86Xinput.h" -#include "XIstubs.h" -#include "xf86Optrec.h" -#include "xf86Parser.h" -#include "mipointer.h" -#include "xf86InPriv.h" -#include "compiler.h" -#include "extinit.h" - -#ifdef DPMSExtension -#include <X11/extensions/dpmsconst.h> -#include "dpmsproc.h" -#endif - -#include "exevents.h" /* AddInputDevice */ -#include "exglobals.h" -#include "eventstr.h" - -#include <string.h> /* InputClassMatches */ -#ifdef HAVE_FNMATCH_H -#include <fnmatch.h> -#endif - -#include "extnsionst.h" - -#include "windowstr.h" /* screenIsSaved */ - -#include <stdarg.h> -#include <stdint.h> /* for int64_t */ - -#include <X11/Xpoll.h> - -#include "mi.h" - -#include <ptrveloc.h> /* dix pointer acceleration */ -#include <xserver-properties.h> - -#ifdef XFreeXDGA -#include "dgaproc.h" -#endif - -#include "xkbsrv.h" - -#include "os.h" - -EventListPtr xf86Events = NULL; - -/** - * Eval config and modify DeviceVelocityRec accordingly - */ -static void -ProcessVelocityConfiguration(DeviceIntPtr pDev, char* devname, pointer list, - DeviceVelocityPtr s) -{ - int tempi; - float tempf; - Atom float_prop = XIGetKnownProperty(XATOM_FLOAT); - Atom prop; - - if(!s) - return; - - /* common settings (available via device properties) */ - tempf = xf86SetRealOption(list, "ConstantDeceleration", 1.0); - if (tempf > 1.0) { - xf86Msg(X_CONFIG, "%s: (accel) constant deceleration by %.1f\n", - devname, tempf); - prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); - XIChangeDeviceProperty(pDev, prop, float_prop, 32, - PropModeReplace, 1, &tempf, FALSE); - } - - tempf = xf86SetRealOption(list, "AdaptiveDeceleration", 1.0); - if (tempf > 1.0) { - xf86Msg(X_CONFIG, "%s: (accel) adaptive deceleration by %.1f\n", - devname, tempf); - prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); - XIChangeDeviceProperty(pDev, prop, float_prop, 32, - PropModeReplace, 1, &tempf, FALSE); - } - - /* select profile by number */ - tempi = xf86SetIntOption(list, "AccelerationProfile", - s->statistics.profile_number); - - prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); - if (XIChangeDeviceProperty(pDev, prop, XA_INTEGER, 32, - PropModeReplace, 1, &tempi, FALSE) == Success) { - xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i\n", devname, - tempi); - } else { - xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i is unknown\n", - devname, tempi); - } - - /* set scaling */ - tempf = xf86SetRealOption(list, "ExpectedRate", 0); - prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); - if (tempf > 0) { - tempf = 1000.0 / tempf; - XIChangeDeviceProperty(pDev, prop, float_prop, 32, - PropModeReplace, 1, &tempf, FALSE); - } else { - tempf = xf86SetRealOption(list, "VelocityScale", s->corr_mul); - XIChangeDeviceProperty(pDev, prop, float_prop, 32, - PropModeReplace, 1, &tempf, FALSE); - } - - tempi = xf86SetIntOption(list, "VelocityTrackerCount", -1); - if (tempi > 1) - InitTrackers(s, tempi); - - s->initial_range = xf86SetIntOption(list, "VelocityInitialRange", - s->initial_range); - - s->max_diff = xf86SetRealOption(list, "VelocityAbsDiff", s->max_diff); - - tempf = xf86SetRealOption(list, "VelocityRelDiff", -1); - if (tempf >= 0) { - xf86Msg(X_CONFIG, "%s: (accel) max rel. velocity difference: %.1f%%\n", - devname, tempf*100.0); - s->max_rel_diff = tempf; - } - - /* Configure softening. If const deceleration is used, this is expected - * to provide better subpixel information so we enable - * softening by default only if ConstantDeceleration is not used - */ - s->use_softening = xf86SetBoolOption(list, "Softening", - s->const_acceleration == 1.0); - - s->average_accel = xf86SetBoolOption(list, "AccelerationProfileAveraging", - s->average_accel); - - s->reset_time = xf86SetIntOption(list, "VelocityReset", s->reset_time); -} - -static void -ApplyAccelerationSettings(DeviceIntPtr dev){ - int scheme, i; - DeviceVelocityPtr pVel; - LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate; - char* schemeStr; - - if (dev->valuator && dev->ptrfeed) { - schemeStr = xf86SetStrOption(local->options, "AccelerationScheme", ""); - - scheme = dev->valuator->accelScheme.number; - - if (!xf86NameCmp(schemeStr, "predictable")) - scheme = PtrAccelPredictable; - - if (!xf86NameCmp(schemeStr, "lightweight")) - scheme = PtrAccelLightweight; - - if (!xf86NameCmp(schemeStr, "none")) - scheme = PtrAccelNoOp; - - /* reinit scheme if needed */ - if (dev->valuator->accelScheme.number != scheme) { - if (dev->valuator->accelScheme.AccelCleanupProc) { - dev->valuator->accelScheme.AccelCleanupProc(dev); - } - - if (InitPointerAccelerationScheme(dev, scheme)) { - xf86Msg(X_CONFIG, "%s: (accel) selected scheme %s/%i\n", - local->name, schemeStr, scheme); - } else { - xf86Msg(X_CONFIG, "%s: (accel) could not init scheme %s\n", - local->name, schemeStr); - scheme = dev->valuator->accelScheme.number; - } - } else { - xf86Msg(X_CONFIG, "%s: (accel) keeping acceleration scheme %i\n", - local->name, scheme); - } - - xfree(schemeStr); - - /* process special configuration */ - switch (scheme) { - case PtrAccelPredictable: - pVel = GetDevicePredictableAccelData(dev); - ProcessVelocityConfiguration (dev, local->name, local->options, - pVel); - break; - } - - i = xf86SetIntOption(local->options, "AccelerationNumerator", - dev->ptrfeed->ctrl.num); - if (i >= 0) - dev->ptrfeed->ctrl.num = i; - - i = xf86SetIntOption(local->options, "AccelerationDenominator", - dev->ptrfeed->ctrl.den); - if (i > 0) - dev->ptrfeed->ctrl.den = i; - - i = xf86SetIntOption(local->options, "AccelerationThreshold", - dev->ptrfeed->ctrl.threshold); - if (i >= 0) - dev->ptrfeed->ctrl.threshold = i; - - /* mostly a no-op anyway */ - (*dev->ptrfeed->CtrlProc)(dev, &dev->ptrfeed->ctrl); - - xf86Msg(X_CONFIG, "%s: (accel) acceleration factor: %.3f\n", - local->name, ((float)dev->ptrfeed->ctrl.num)/ - ((float)dev->ptrfeed->ctrl.den)); - xf86Msg(X_CONFIG, "%s: (accel) acceleration threshold: %i\n", - local->name, dev->ptrfeed->ctrl.threshold); - } -} - -static Bool -xf86SendDragEvents(DeviceIntPtr device) -{ - LocalDevicePtr local = (LocalDevicePtr) device->public.devicePrivate; - - if (device->button && device->button->buttonsDown > 0) - return (local->flags & XI86_SEND_DRAG_EVENTS); - else - return (TRUE); -} - -/*********************************************************************** - * - * xf86ProcessCommonOptions -- - * - * Process global options. - * - *********************************************************************** - */ -void -xf86ProcessCommonOptions(LocalDevicePtr local, - pointer list) -{ - if (!xf86SetBoolOption(list, "AlwaysCore", 1) || - !xf86SetBoolOption(list, "SendCoreEvents", 1) || - !xf86SetBoolOption(list, "CorePointer", 1) || - !xf86SetBoolOption(list, "CoreKeyboard", 1)) { - xf86Msg(X_CONFIG, "%s: doesn't report core events\n", local->name); - } else { - local->flags |= XI86_ALWAYS_CORE; - xf86Msg(X_CONFIG, "%s: always reports core events\n", local->name); - } - - if (xf86SetBoolOption(list, "SendDragEvents", 1)) { - local->flags |= XI86_SEND_DRAG_EVENTS; - } else { - xf86Msg(X_CONFIG, "%s: doesn't report drag events\n", local->name); - } - - /* Backwards compatibility. */ - local->history_size = GetMotionHistorySize(); -} - -/*********************************************************************** - * - * xf86ActivateDevice -- - * - * Initialize an input device. - * - * Returns TRUE on success, or FALSE otherwise. - *********************************************************************** - */ -int -xf86ActivateDevice(LocalDevicePtr local) -{ - DeviceIntPtr dev; - - if (local->flags & XI86_CONFIGURED) { - dev = AddInputDevice(serverClient, local->device_control, TRUE); - - if (dev == NULL) - { - xf86Msg(X_ERROR, "Too many input devices. Ignoring %s\n", - local->name); - local->dev = NULL; - return FALSE; - } - - local->atom = MakeAtom(local->type_name, - strlen(local->type_name), - TRUE); - AssignTypeAndName(dev, local->atom, local->name); - dev->public.devicePrivate = (pointer) local; - local->dev = dev; - - dev->coreEvents = local->flags & XI86_ALWAYS_CORE; - dev->type = SLAVE; - dev->spriteInfo->spriteOwner = FALSE; - - dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; - dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; - - RegisterOtherDevice(dev); - XkbSetExtension(dev, ProcessKeyboardEvent); - - if (serverGeneration == 1) - xf86Msg(X_INFO, "XINPUT: Adding extended input device \"%s\" (type: %s)\n", - local->name, local->type_name); - } - - return TRUE; -} - - -/*********************************************************************** - * - * Caller: ProcXOpenDevice - * - * This is the implementation-dependent routine to open an input device. - * Some implementations open all input devices when the server is first - * initialized, and never close them. Other implementations open only - * the X pointer and keyboard devices during server initialization, - * and only open other input devices when some client makes an - * XOpenDevice request. This entry point is for the latter type of - * implementation. - * - * If the physical device is not already open, do it here. In this case, - * you need to keep track of the fact that one or more clients has the - * device open, and physically close it when the last client that has - * it open does an XCloseDevice. - * - * The default implementation is to do nothing (assume all input devices - * are opened during X server initialization and kept open). - * - *********************************************************************** - */ - -void -OpenInputDevice(DeviceIntPtr dev, - ClientPtr client, - int *status) -{ - if (!dev->inited) - ActivateDevice(dev, TRUE); - - *status = Success; -} - -void -CloseInputDevice(DeviceIntPtr dev, - ClientPtr client) -{ -} - -/**************************************************************************** - * - * Caller: ProcXSetDeviceMode - * - * Change the mode of an extension device. - * This function is used to change the mode of a device from reporting - * relative motion to reporting absolute positional information, and - * vice versa. - * The default implementation below is that no such devices are supported. - * - *********************************************************************** - */ - -int -SetDeviceMode (ClientPtr client, DeviceIntPtr dev, int mode) -{ - LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate; - - if (local->switch_mode) { - return (*local->switch_mode)(client, dev, mode); - } - else - return BadMatch; -} - - -/*********************************************************************** - * - * Caller: ProcXSetDeviceValuators - * - * Set the value of valuators on an extension input device. - * This function is used to set the initial value of valuators on - * those input devices that are capable of reporting either relative - * motion or an absolute position, and allow an initial position to be set. - * The default implementation below is that no such devices are supported. - * - *********************************************************************** - */ - -int -SetDeviceValuators (ClientPtr client, DeviceIntPtr dev, int *valuators, - int first_valuator, int num_valuators) -{ - LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate; - - if (local->set_device_valuators) - return (*local->set_device_valuators)(local, valuators, first_valuator, - num_valuators); - - return BadMatch; -} - - -/*********************************************************************** - * - * Caller: ProcXChangeDeviceControl - * - * Change the specified device controls on an extension input device. - * - *********************************************************************** - */ - -int -ChangeDeviceControl (ClientPtr client, DeviceIntPtr dev, xDeviceCtl *control) -{ - LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate; - - if (!local->control_proc) { - switch (control->control) { - case DEVICE_CORE: - return BadMatch; - case DEVICE_RESOLUTION: - case DEVICE_ABS_CALIB: - case DEVICE_ABS_AREA: - case DEVICE_ENABLE: - return Success; - default: - return BadMatch; - } - } - else { - return (*local->control_proc)(local, control); - } -} - -void -AddOtherInputDevices(void) -{ -} - -/* - * Classes without any Match statements match all devices. Otherwise, all - * statements must match. - */ -static Bool -InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs) -{ - char **cur; - Bool match; - - if (iclass->match_product) { - if (!attrs->product) - return FALSE; - /* see if any of the values match */ - for (cur = iclass->match_product, match = FALSE; *cur; cur++) - if (strstr(attrs->product, *cur)) { - match = TRUE; - break; - } - if (!match) - return FALSE; - } - if (iclass->match_vendor) { - if (!attrs->vendor) - return FALSE; - /* see if any of the values match */ - for (cur = iclass->match_vendor, match = FALSE; *cur; cur++) - if (strstr(attrs->vendor, *cur)) { - match = TRUE; - break; - } - if (!match) - return FALSE; - } - if (iclass->match_device) { - if (!attrs->device) - return FALSE; - /* see if any of the values match */ - for (cur = iclass->match_device, match = FALSE; *cur; cur++) -#ifdef HAVE_FNMATCH_H - if (fnmatch(*cur, attrs->device, FNM_PATHNAME) == 0) { -#else - if (strstr(attrs->device, *cur)) { -#endif - match = TRUE; - break; - } - if (!match) - return FALSE; - } - if (iclass->match_tag) { - if (!attrs->tags) - return FALSE; - - for (cur = iclass->match_tag, match = FALSE; *cur && !match; cur++) { - const char *tag; - for(tag = *attrs->tags; *tag; tag++) { - if (!strcmp(tag, *cur)) { - match = TRUE; - break; - } - } - } - - if (!match) - return FALSE; - } - - if (iclass->is_keyboard.set && - iclass->is_keyboard.val != !!(attrs->flags & ATTR_KEYBOARD)) - return FALSE; - if (iclass->is_pointer.set && - iclass->is_pointer.val != !!(attrs->flags & ATTR_POINTER)) - return FALSE; - if (iclass->is_joystick.set && - iclass->is_joystick.val != !!(attrs->flags & ATTR_JOYSTICK)) - return FALSE; - if (iclass->is_tablet.set && - iclass->is_tablet.val != !!(attrs->flags & ATTR_TABLET)) - return FALSE; - if (iclass->is_touchpad.set && - iclass->is_touchpad.val != !!(attrs->flags & ATTR_TOUCHPAD)) - return FALSE; - if (iclass->is_touchscreen.set && - iclass->is_touchscreen.val != !!(attrs->flags & ATTR_TOUCHSCREEN)) - return FALSE; - return TRUE; -} - -/* - * Merge in any InputClass configurations. Options in each InputClass - * section have more priority than the original device configuration as - * well as any previous InputClass sections. - */ -static int -MergeInputClasses(IDevPtr idev, InputAttributes *attrs) -{ - XF86ConfInputClassPtr cl; - XF86OptionPtr classopts, mergedopts = NULL; - char *classdriver = NULL; - - for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) { - if (!InputClassMatches(cl, attrs)) - continue; - - /* Collect class options and merge over previous classes */ - xf86Msg(X_CONFIG, "%s: Applying InputClass \"%s\"\n", - idev->identifier, cl->identifier); - if (cl->driver) - classdriver = cl->driver; - classopts = xf86optionListDup(cl->option_lst); - mergedopts = xf86optionListMerge(mergedopts, classopts); - } - - /* Apply options to device with InputClass settings preferred. */ - if (classdriver) { - xfree(idev->driver); - idev->driver = xstrdup(classdriver); - if (!idev->driver) { - xf86Msg(X_ERROR, "Failed to allocate memory while merging " - "InputClass configuration"); - return BadAlloc; - } - mergedopts = xf86ReplaceStrOption(mergedopts, "driver", idev->driver); - } - idev->commonOptions = xf86optionListMerge(idev->commonOptions, mergedopts); - - return Success; -} - -/* - * Iterate the list of classes and look for Option "Ignore". Return the - * value of the last matching class and holler when returning TRUE. - */ -static Bool -IgnoreInputClass(IDevPtr idev, InputAttributes *attrs) -{ - XF86ConfInputClassPtr cl; - Bool ignore = FALSE; - const char *ignore_class; - - for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) { - if (!InputClassMatches(cl, attrs)) - continue; - if (xf86findOption(cl->option_lst, "Ignore")) { - ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE); - ignore_class = cl->identifier; - } - } - - if (ignore) - xf86Msg(X_CONFIG, "%s: Ignoring device from InputClass \"%s\"\n", - idev->identifier, ignore_class); - return ignore; -} - -/** - * Create a new input device, activate and enable it. - * - * Possible return codes: - * BadName .. a bad driver name was supplied. - * BadImplementation ... The driver does not have a PreInit function. This - * is a driver bug. - * BadMatch .. device initialization failed. - * BadAlloc .. too many input devices - * - * @param idev The device, already set up with identifier, driver, and the - * options. - * @param pdev Pointer to the new device, if Success was reported. - * @param enable Enable the device after activating it. - * - * @return Success or an error code - */ -_X_INTERNAL int -xf86NewInputDevice(IDevPtr idev, DeviceIntPtr *pdev, BOOL enable) -{ - InputDriverPtr drv = NULL; - InputInfoPtr pInfo = NULL; - DeviceIntPtr dev = NULL; - int rval; - - /* Memory leak for every attached device if we don't - * test if the module is already loaded first */ - drv = xf86LookupInputDriver(idev->driver); - if (!drv) - if (xf86LoadOneModule(idev->driver, NULL)) - drv = xf86LookupInputDriver(idev->driver); - if (!drv) { - xf86Msg(X_ERROR, "No input driver matching `%s'\n", idev->driver); - rval = BadName; - goto unwind; - } - - if (!drv->PreInit) { - xf86Msg(X_ERROR, - "Input driver `%s' has no PreInit function (ignoring)\n", - drv->driverName); - rval = BadImplementation; - goto unwind; - } - - pInfo = drv->PreInit(drv, idev, 0); - - if (!pInfo) { - xf86Msg(X_ERROR, "PreInit returned NULL for \"%s\"\n", idev->identifier); - rval = BadMatch; - goto unwind; - } - else if (!(pInfo->flags & XI86_CONFIGURED)) { - xf86Msg(X_ERROR, "PreInit failed for input device \"%s\"\n", - idev->identifier); - rval = BadMatch; - goto unwind; - } - - if (!xf86ActivateDevice(pInfo)) - { - rval = BadAlloc; - goto unwind; - } - - dev = pInfo->dev; - rval = ActivateDevice(dev, TRUE); - if (rval != Success) - { - xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", idev->identifier); - RemoveDevice(dev, TRUE); - goto unwind; - } - - /* Enable it if it's properly initialised and we're currently in the VT */ - if (enable && dev->inited && dev->startup && xf86Screens[0]->vtSema) - { - EnableDevice(dev, TRUE); - if (!dev->enabled) - { - xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", idev->identifier); - rval = BadMatch; - goto unwind; - } - /* send enter/leave event, update sprite window */ - CheckMotion(NULL, dev); - } - - *pdev = dev; - return Success; - -unwind: - if(pInfo) { - if(drv->UnInit) - drv->UnInit(drv, pInfo, 0); - else - xf86DeleteInput(pInfo, 0); - } - return rval; -} - -int -NewInputDeviceRequest (InputOption *options, InputAttributes *attrs, - DeviceIntPtr *pdev) -{ - IDevRec *idev = NULL; - InputOption *option = NULL; - int rval = Success; - int is_auto = 0; - - idev = xcalloc(sizeof(*idev), 1); - if (!idev) - return BadAlloc; - - for (option = options; option; option = option->next) { - if (strcasecmp(option->key, "driver") == 0) { - if (idev->driver) { - rval = BadRequest; - goto unwind; - } - idev->driver = xstrdup(option->value); - if (!idev->driver) { - rval = BadAlloc; - goto unwind; - } - } - - if (strcasecmp(option->key, "name") == 0 || - strcasecmp(option->key, "identifier") == 0) { - if (idev->identifier) { - rval = BadRequest; - goto unwind; - } - idev->identifier = xstrdup(option->value); - if (!idev->identifier) { - rval = BadAlloc; - goto unwind; - } - } - - if (strcmp(option->key, "_source") == 0 && - (strcmp(option->value, "server/hal") == 0 || - strcmp(option->value, "server/udev") == 0)) { - is_auto = 1; - if (!xf86Info.autoAddDevices) { - rval = BadMatch; - goto unwind; - } - } - } - - for (option = options; option; option = option->next) { - /* Steal option key/value strings from the provided list. - * We need those strings, the InputOption list doesn't. */ - idev->commonOptions = xf86addNewOption(idev->commonOptions, - option->key, option->value); - option->key = NULL; - option->value = NULL; - } - - /* Apply InputClass settings */ - if (attrs) { - if (IgnoreInputClass(idev, attrs)) { - rval = BadIDChoice; - goto unwind; - } - - rval = MergeInputClasses(idev, attrs); - if (rval != Success) - goto unwind; - } - - if (!idev->driver || !idev->identifier) { - xf86Msg(X_INFO, "No input driver/identifier specified (ignoring)\n"); - rval = BadRequest; - goto unwind; - } - - if (!idev->identifier) { - xf86Msg(X_ERROR, "No device identifier specified (ignoring)\n"); - return BadMatch; - } - - rval = xf86NewInputDevice(idev, pdev, - (!is_auto || (is_auto && xf86Info.autoEnableDevices))); - if (rval == Success) - return Success; - -unwind: - if (is_auto && !xf86Info.autoAddDevices) - xf86Msg(X_INFO, "AutoAddDevices is off - not adding device.\n"); - if(idev->driver) - xfree(idev->driver); - if(idev->identifier) - xfree(idev->identifier); - xf86optionListFree(idev->commonOptions); - xfree(idev); - return rval; -} - -void -DeleteInputDeviceRequest(DeviceIntPtr pDev) -{ - LocalDevicePtr pInfo = (LocalDevicePtr) pDev->public.devicePrivate; - InputDriverPtr drv = NULL; - IDevRec *idev = NULL; - IDevPtr *it; - Bool isMaster = IsMaster(pDev); - - if (pInfo) /* need to get these before RemoveDevice */ - { - drv = pInfo->drv; - idev = pInfo->conf_idev; - } - - OsBlockSignals(); - RemoveDevice(pDev, TRUE); - - if (!isMaster && pInfo != NULL) - { - if(drv->UnInit) - drv->UnInit(drv, pInfo, 0); - else - xf86DeleteInput(pInfo, 0); - - /* devices added through HAL aren't in the config layout */ - it = xf86ConfigLayout.inputs; - while(*it && *it != idev) - it++; - - if (!(*it)) /* end of list, not in the layout */ - { - xfree(idev->driver); - xfree(idev->identifier); - xf86optionListFree(idev->commonOptions); - xfree(idev); - } - } - OsReleaseSignals(); -} - -/* - * convenient functions to post events - */ - -void -xf86PostMotionEvent(DeviceIntPtr device, - int is_absolute, - int first_valuator, - int num_valuators, - ...) -{ - va_list var; - int i = 0; - static int valuators[MAX_VALUATORS]; - - XI_VERIFY_VALUATORS(num_valuators); - - va_start(var, num_valuators); - for (i = 0; i < num_valuators; i++) - valuators[i] = va_arg(var, int); - va_end(var); - - xf86PostMotionEventP(device, is_absolute, first_valuator, num_valuators, valuators); -} - -void -xf86PostMotionEventP(DeviceIntPtr device, - int is_absolute, - int first_valuator, - int num_valuators, - int *valuators) -{ - int i = 0, nevents = 0; - Bool drag = xf86SendDragEvents(device); - DeviceEvent *event; - int flags = 0; - -#if XFreeXDGA - int index; - int dx = 0, dy = 0; -#endif - - XI_VERIFY_VALUATORS(num_valuators); - - if (is_absolute) - flags = POINTER_ABSOLUTE; - else - flags = POINTER_RELATIVE | POINTER_ACCELERATE; - -#if XFreeXDGA - /* The evdev driver may not always send all axes across. */ - if (num_valuators >= 1 && first_valuator <= 1) { - if (miPointerGetScreen(device)) { - index = miPointerGetScreen(device)->myNum; - if (first_valuator == 0) - { - dx = valuators[0]; - if (is_absolute) - dx -= device->last.valuators[0]; - } - - if (first_valuator == 1 || num_valuators >= 2) - { - dy = valuators[1 - first_valuator]; - if (is_absolute) - dy -= device->last.valuators[1]; - } - - if (DGAStealMotionEvent(device, index, dx, dy)) - return; - } - } -#endif - - nevents = GetPointerEvents(xf86Events, device, MotionNotify, 0, - flags, first_valuator, num_valuators, - valuators); - - for (i = 0; i < nevents; i++) { - event = (DeviceEvent*)((xf86Events + i)->event); - /* Don't post core motion events for devices not registered to send - * drag events. */ - if (event->header == ET_Internal && - (event->type != ET_Motion || drag)) { - mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event)); - } - } -} - -void -xf86PostProximityEvent(DeviceIntPtr device, - int is_in, - int first_valuator, - int num_valuators, - ...) -{ - va_list var; - int i; - int valuators[MAX_VALUATORS]; - - XI_VERIFY_VALUATORS(num_valuators); - - va_start(var, num_valuators); - for (i = 0; i < num_valuators; i++) - valuators[i] = va_arg(var, int); - va_end(var); - - xf86PostProximityEventP(device, is_in, first_valuator, num_valuators, - valuators); - -} - -void -xf86PostProximityEventP(DeviceIntPtr device, - int is_in, - int first_valuator, - int num_valuators, - int *valuators) -{ - int i, nevents; - - XI_VERIFY_VALUATORS(num_valuators); - - nevents = GetProximityEvents(xf86Events, device, - is_in ? ProximityIn : ProximityOut, - first_valuator, num_valuators, valuators); - for (i = 0; i < nevents; i++) - mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event)); - -} - -void -xf86PostButtonEvent(DeviceIntPtr device, - int is_absolute, - int button, - int is_down, - int first_valuator, - int num_valuators, - ...) -{ - va_list var; - int valuators[MAX_VALUATORS]; - int i = 0; - - XI_VERIFY_VALUATORS(num_valuators); - - va_start(var, num_valuators); - for (i = 0; i < num_valuators; i++) - valuators[i] = va_arg(var, int); - va_end(var); - - xf86PostButtonEventP(device, is_absolute, button, is_down, first_valuator, - num_valuators, valuators); - -} - -void -xf86PostButtonEventP(DeviceIntPtr device, - int is_absolute, - int button, - int is_down, - int first_valuator, - int num_valuators, - int *valuators) -{ - int i = 0, nevents = 0; - int flags = 0; - -#if XFreeXDGA - int index; -#endif - - XI_VERIFY_VALUATORS(num_valuators); - - if (is_absolute) - flags = POINTER_ABSOLUTE; - else - flags = POINTER_RELATIVE | POINTER_ACCELERATE; - -#if XFreeXDGA - if (miPointerGetScreen(device)) { - index = miPointerGetScreen(device)->myNum; - if (DGAStealButtonEvent(device, index, button, is_down)) - return; - } -#endif - - nevents = GetPointerEvents(xf86Events, device, - is_down ? ButtonPress : ButtonRelease, button, - flags, first_valuator, num_valuators, valuators); - - for (i = 0; i < nevents; i++) - mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event)); - -} - -void -xf86PostKeyEvent(DeviceIntPtr device, - unsigned int key_code, - int is_down, - int is_absolute, - int first_valuator, - int num_valuators, - ...) -{ - va_list var; - int i = 0; - static int valuators[MAX_VALUATORS]; - - XI_VERIFY_VALUATORS(num_valuators); - - va_start(var, num_valuators); - for (i = 0; i < num_valuators; i++) - valuators[i] = va_arg(var, int); - va_end(var); - - xf86PostKeyEventP(device, key_code, is_down, is_absolute, first_valuator, - num_valuators, valuators); - -} - -void -xf86PostKeyEventP(DeviceIntPtr device, - unsigned int key_code, - int is_down, - int is_absolute, - int first_valuator, - int num_valuators, - int *valuators) -{ - int i = 0, nevents = 0; - - XI_VERIFY_VALUATORS(num_valuators); - - if (is_absolute) { - nevents = GetKeyboardValuatorEvents(xf86Events, device, - is_down ? KeyPress : KeyRelease, - key_code, first_valuator, - num_valuators, valuators); - } - else { - nevents = GetKeyboardEvents(xf86Events, device, - is_down ? KeyPress : KeyRelease, - key_code); - } - - for (i = 0; i < nevents; i++) - mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event)); -} - -void -xf86PostKeyboardEvent(DeviceIntPtr device, - unsigned int key_code, - int is_down) -{ - xf86PostKeyEventP(device, key_code, is_down, 0, 0, 0, NULL); -} - -LocalDevicePtr -xf86FirstLocalDevice(void) -{ - return xf86InputDevs; -} - -/* - * Cx - raw data from touch screen - * Sxhigh - scaled highest dimension - * (remember, this is of rows - 1 because of 0 origin) - * Sxlow - scaled lowest dimension - * Rxhigh - highest raw value from touch screen calibration - * Rxlow - lowest raw value from touch screen calibration - * - * This function is the same for X or Y coordinates. - * You may have to reverse the high and low values to compensate for - * different orgins on the touch screen vs X. - */ - -int -xf86ScaleAxis(int Cx, - int Sxhigh, - int Sxlow, - int Rxhigh, - int Rxlow ) -{ - int X; - int64_t dSx = Sxhigh - Sxlow; - int64_t dRx = Rxhigh - Rxlow; - - if (dRx) { - X = (int)(((dSx * (Cx - Rxlow)) / dRx) + Sxlow); - } - else { - X = 0; - ErrorF ("Divide by Zero in xf86ScaleAxis"); - } - - if (X > Sxhigh) - X = Sxhigh; - if (X < Sxlow) - X = Sxlow; - - return (X); -} - -/* - * This function checks the given screen against the current screen and - * makes changes if appropriate. It should be called from an XInput driver's - * ReadInput function before any events are posted, if the device is screen - * specific like a touch screen. - */ -void -xf86XInputSetScreen(LocalDevicePtr local, - int screen_number, - int x, - int y) -{ - if (miPointerGetScreen(local->dev) != - screenInfo.screens[screen_number]) { - miPointerSetScreen(local->dev, screen_number, x, y); - } -} - - -void -xf86InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int maxval, - int resolution, int min_res, int max_res) -{ - if (!dev || !dev->valuator) - return; - - InitValuatorAxisStruct(dev, axnum, label, minval, maxval, resolution, min_res, - max_res); -} - -/* - * Set the valuator values to be in synch with dix/event.c - * DefineInitialRootWindow(). - */ -void -xf86InitValuatorDefaults(DeviceIntPtr dev, int axnum) -{ - if (axnum == 0) { - dev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; - dev->last.valuators[0] = dev->valuator->axisVal[0]; - } - else if (axnum == 1) { - dev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; - dev->last.valuators[1] = dev->valuator->axisVal[1]; - } - - if(axnum == 0) /* to prevent double invocation */ - ApplyAccelerationSettings(dev); -} - - -/** - * Deactivate a device. Call this function from the driver if you receive a - * read error or something else that spoils your day. - * Device will be moved to the off_devices list, but it will still be there - * until you really clean up after it. - * Notifies the client about an inactive device. - * - * @param panic True if device is unrecoverable and needs to be removed. - */ -void -xf86DisableDevice(DeviceIntPtr dev, Bool panic) -{ - if(!panic) - { - DisableDevice(dev, TRUE); - } else - { - SendDevicePresenceEvent(dev->id, DeviceUnrecoverable); - DeleteInputDeviceRequest(dev); - } -} - -/** - * Reactivate a device. Call this function from the driver if you just found - * out that the read error wasn't quite that bad after all. - * Device will be re-activated, and an event sent to the client. - */ -void -xf86EnableDevice(DeviceIntPtr dev) -{ - EnableDevice(dev, TRUE); -} - -/* end of xf86Xinput.c */ +/* + * Copyright 1995-1999 by Frederic Lepied, France. <Lepied@XFree86.org> + * + * 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 Frederic Lepied not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Frederic Lepied makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * FREDERIC LEPIED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL FREDERIC LEPIED 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. + * + */ +/* + * Copyright (c) 2000-2002 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/Xfuncproto.h> +#include <X11/Xmd.h> +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include <X11/Xatom.h> +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86Config.h" +#include "xf86Xinput.h" +#include "XIstubs.h" +#include "xf86Optrec.h" +#include "xf86Parser.h" +#include "mipointer.h" +#include "xf86InPriv.h" +#include "compiler.h" +#include "extinit.h" + +#ifdef DPMSExtension +#include <X11/extensions/dpmsconst.h> +#include "dpmsproc.h" +#endif + +#include "exevents.h" /* AddInputDevice */ +#include "exglobals.h" +#include "eventstr.h" + +#include <string.h> /* InputClassMatches */ +#ifdef HAVE_FNMATCH_H +#include <fnmatch.h> +#endif + +#include "extnsionst.h" + +#include "windowstr.h" /* screenIsSaved */ + +#include <stdarg.h> +#include <stdint.h> /* for int64_t */ + +#include <X11/Xpoll.h> + +#include "mi.h" + +#include <ptrveloc.h> /* dix pointer acceleration */ +#include <xserver-properties.h> + +#ifdef XFreeXDGA +#include "dgaproc.h" +#endif + +#include "xkbsrv.h" + +#include "os.h" + +EventListPtr xf86Events = NULL; + +/** + * Eval config and modify DeviceVelocityRec accordingly + */ +static void +ProcessVelocityConfiguration(DeviceIntPtr pDev, char* devname, pointer list, + DeviceVelocityPtr s) +{ + int tempi; + float tempf; + Atom float_prop = XIGetKnownProperty(XATOM_FLOAT); + Atom prop; + + if(!s) + return; + + /* common settings (available via device properties) */ + tempf = xf86SetRealOption(list, "ConstantDeceleration", 1.0); + if (tempf > 1.0) { + xf86Msg(X_CONFIG, "%s: (accel) constant deceleration by %.1f\n", + devname, tempf); + prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); + XIChangeDeviceProperty(pDev, prop, float_prop, 32, + PropModeReplace, 1, &tempf, FALSE); + } + + tempf = xf86SetRealOption(list, "AdaptiveDeceleration", 1.0); + if (tempf > 1.0) { + xf86Msg(X_CONFIG, "%s: (accel) adaptive deceleration by %.1f\n", + devname, tempf); + prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); + XIChangeDeviceProperty(pDev, prop, float_prop, 32, + PropModeReplace, 1, &tempf, FALSE); + } + + /* select profile by number */ + tempi = xf86SetIntOption(list, "AccelerationProfile", + s->statistics.profile_number); + + prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); + if (XIChangeDeviceProperty(pDev, prop, XA_INTEGER, 32, + PropModeReplace, 1, &tempi, FALSE) == Success) { + xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i\n", devname, + tempi); + } else { + xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i is unknown\n", + devname, tempi); + } + + /* set scaling */ + tempf = xf86SetRealOption(list, "ExpectedRate", 0); + prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); + if (tempf > 0) { + tempf = 1000.0 / tempf; + XIChangeDeviceProperty(pDev, prop, float_prop, 32, + PropModeReplace, 1, &tempf, FALSE); + } else { + tempf = xf86SetRealOption(list, "VelocityScale", s->corr_mul); + XIChangeDeviceProperty(pDev, prop, float_prop, 32, + PropModeReplace, 1, &tempf, FALSE); + } + + tempi = xf86SetIntOption(list, "VelocityTrackerCount", -1); + if (tempi > 1) + InitTrackers(s, tempi); + + s->initial_range = xf86SetIntOption(list, "VelocityInitialRange", + s->initial_range); + + s->max_diff = xf86SetRealOption(list, "VelocityAbsDiff", s->max_diff); + + tempf = xf86SetRealOption(list, "VelocityRelDiff", -1); + if (tempf >= 0) { + xf86Msg(X_CONFIG, "%s: (accel) max rel. velocity difference: %.1f%%\n", + devname, tempf*100.0); + s->max_rel_diff = tempf; + } + + /* Configure softening. If const deceleration is used, this is expected + * to provide better subpixel information so we enable + * softening by default only if ConstantDeceleration is not used + */ + s->use_softening = xf86SetBoolOption(list, "Softening", + s->const_acceleration == 1.0); + + s->average_accel = xf86SetBoolOption(list, "AccelerationProfileAveraging", + s->average_accel); + + s->reset_time = xf86SetIntOption(list, "VelocityReset", s->reset_time); +} + +static void +ApplyAccelerationSettings(DeviceIntPtr dev){ + int scheme, i; + DeviceVelocityPtr pVel; + LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate; + char* schemeStr; + + if (dev->valuator && dev->ptrfeed) { + schemeStr = xf86SetStrOption(local->options, "AccelerationScheme", ""); + + scheme = dev->valuator->accelScheme.number; + + if (!xf86NameCmp(schemeStr, "predictable")) + scheme = PtrAccelPredictable; + + if (!xf86NameCmp(schemeStr, "lightweight")) + scheme = PtrAccelLightweight; + + if (!xf86NameCmp(schemeStr, "none")) + scheme = PtrAccelNoOp; + + /* reinit scheme if needed */ + if (dev->valuator->accelScheme.number != scheme) { + if (dev->valuator->accelScheme.AccelCleanupProc) { + dev->valuator->accelScheme.AccelCleanupProc(dev); + } + + if (InitPointerAccelerationScheme(dev, scheme)) { + xf86Msg(X_CONFIG, "%s: (accel) selected scheme %s/%i\n", + local->name, schemeStr, scheme); + } else { + xf86Msg(X_CONFIG, "%s: (accel) could not init scheme %s\n", + local->name, schemeStr); + scheme = dev->valuator->accelScheme.number; + } + } else { + xf86Msg(X_CONFIG, "%s: (accel) keeping acceleration scheme %i\n", + local->name, scheme); + } + + free(schemeStr); + + /* process special configuration */ + switch (scheme) { + case PtrAccelPredictable: + pVel = GetDevicePredictableAccelData(dev); + ProcessVelocityConfiguration (dev, local->name, local->options, + pVel); + break; + } + + i = xf86SetIntOption(local->options, "AccelerationNumerator", + dev->ptrfeed->ctrl.num); + if (i >= 0) + dev->ptrfeed->ctrl.num = i; + + i = xf86SetIntOption(local->options, "AccelerationDenominator", + dev->ptrfeed->ctrl.den); + if (i > 0) + dev->ptrfeed->ctrl.den = i; + + i = xf86SetIntOption(local->options, "AccelerationThreshold", + dev->ptrfeed->ctrl.threshold); + if (i >= 0) + dev->ptrfeed->ctrl.threshold = i; + + /* mostly a no-op anyway */ + (*dev->ptrfeed->CtrlProc)(dev, &dev->ptrfeed->ctrl); + + xf86Msg(X_CONFIG, "%s: (accel) acceleration factor: %.3f\n", + local->name, ((float)dev->ptrfeed->ctrl.num)/ + ((float)dev->ptrfeed->ctrl.den)); + xf86Msg(X_CONFIG, "%s: (accel) acceleration threshold: %i\n", + local->name, dev->ptrfeed->ctrl.threshold); + } +} + +static Bool +xf86SendDragEvents(DeviceIntPtr device) +{ + LocalDevicePtr local = (LocalDevicePtr) device->public.devicePrivate; + + if (device->button && device->button->buttonsDown > 0) + return (local->flags & XI86_SEND_DRAG_EVENTS); + else + return (TRUE); +} + +/*********************************************************************** + * + * xf86ProcessCommonOptions -- + * + * Process global options. + * + *********************************************************************** + */ +void +xf86ProcessCommonOptions(LocalDevicePtr local, + pointer list) +{ + if (!xf86SetBoolOption(list, "AlwaysCore", 1) || + !xf86SetBoolOption(list, "SendCoreEvents", 1) || + !xf86SetBoolOption(list, "CorePointer", 1) || + !xf86SetBoolOption(list, "CoreKeyboard", 1)) { + xf86Msg(X_CONFIG, "%s: doesn't report core events\n", local->name); + } else { + local->flags |= XI86_ALWAYS_CORE; + xf86Msg(X_CONFIG, "%s: always reports core events\n", local->name); + } + + if (xf86SetBoolOption(list, "SendDragEvents", 1)) { + local->flags |= XI86_SEND_DRAG_EVENTS; + } else { + xf86Msg(X_CONFIG, "%s: doesn't report drag events\n", local->name); + } + + /* Backwards compatibility. */ + local->history_size = GetMotionHistorySize(); +} + +/*********************************************************************** + * + * xf86ActivateDevice -- + * + * Initialize an input device. + * + * Returns TRUE on success, or FALSE otherwise. + *********************************************************************** + */ +int +xf86ActivateDevice(LocalDevicePtr local) +{ + DeviceIntPtr dev; + + if (local->flags & XI86_CONFIGURED) { + dev = AddInputDevice(serverClient, local->device_control, TRUE); + + if (dev == NULL) + { + xf86Msg(X_ERROR, "Too many input devices. Ignoring %s\n", + local->name); + local->dev = NULL; + return FALSE; + } + + local->atom = MakeAtom(local->type_name, + strlen(local->type_name), + TRUE); + AssignTypeAndName(dev, local->atom, local->name); + dev->public.devicePrivate = (pointer) local; + local->dev = dev; + + dev->coreEvents = local->flags & XI86_ALWAYS_CORE; + dev->type = SLAVE; + dev->spriteInfo->spriteOwner = FALSE; + + dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; + dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; + + RegisterOtherDevice(dev); + XkbSetExtension(dev, ProcessKeyboardEvent); + + if (serverGeneration == 1) + xf86Msg(X_INFO, "XINPUT: Adding extended input device \"%s\" (type: %s)\n", + local->name, local->type_name); + } + + return TRUE; +} + + +/*********************************************************************** + * + * Caller: ProcXOpenDevice + * + * This is the implementation-dependent routine to open an input device. + * Some implementations open all input devices when the server is first + * initialized, and never close them. Other implementations open only + * the X pointer and keyboard devices during server initialization, + * and only open other input devices when some client makes an + * XOpenDevice request. This entry point is for the latter type of + * implementation. + * + * If the physical device is not already open, do it here. In this case, + * you need to keep track of the fact that one or more clients has the + * device open, and physically close it when the last client that has + * it open does an XCloseDevice. + * + * The default implementation is to do nothing (assume all input devices + * are opened during X server initialization and kept open). + * + *********************************************************************** + */ + +void +OpenInputDevice(DeviceIntPtr dev, + ClientPtr client, + int *status) +{ + if (!dev->inited) + ActivateDevice(dev, TRUE); + + *status = Success; +} + +void +CloseInputDevice(DeviceIntPtr dev, + ClientPtr client) +{ +} + +/**************************************************************************** + * + * Caller: ProcXSetDeviceMode + * + * Change the mode of an extension device. + * This function is used to change the mode of a device from reporting + * relative motion to reporting absolute positional information, and + * vice versa. + * The default implementation below is that no such devices are supported. + * + *********************************************************************** + */ + +int +SetDeviceMode (ClientPtr client, DeviceIntPtr dev, int mode) +{ + LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate; + + if (local->switch_mode) { + return (*local->switch_mode)(client, dev, mode); + } + else + return BadMatch; +} + + +/*********************************************************************** + * + * Caller: ProcXSetDeviceValuators + * + * Set the value of valuators on an extension input device. + * This function is used to set the initial value of valuators on + * those input devices that are capable of reporting either relative + * motion or an absolute position, and allow an initial position to be set. + * The default implementation below is that no such devices are supported. + * + *********************************************************************** + */ + +int +SetDeviceValuators (ClientPtr client, DeviceIntPtr dev, int *valuators, + int first_valuator, int num_valuators) +{ + LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate; + + if (local->set_device_valuators) + return (*local->set_device_valuators)(local, valuators, first_valuator, + num_valuators); + + return BadMatch; +} + + +/*********************************************************************** + * + * Caller: ProcXChangeDeviceControl + * + * Change the specified device controls on an extension input device. + * + *********************************************************************** + */ + +int +ChangeDeviceControl (ClientPtr client, DeviceIntPtr dev, xDeviceCtl *control) +{ + LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate; + + if (!local->control_proc) { + switch (control->control) { + case DEVICE_CORE: + return BadMatch; + case DEVICE_RESOLUTION: + case DEVICE_ABS_CALIB: + case DEVICE_ABS_AREA: + case DEVICE_ENABLE: + return Success; + default: + return BadMatch; + } + } + else { + return (*local->control_proc)(local, control); + } +} + +void +AddOtherInputDevices(void) +{ +} + +/* + * Classes without any Match statements match all devices. Otherwise, all + * statements must match. + */ +static Bool +InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs) +{ + char **cur; + Bool match; + + if (iclass->match_product) { + if (!attrs->product) + return FALSE; + /* see if any of the values match */ + for (cur = iclass->match_product, match = FALSE; *cur; cur++) + if (strstr(attrs->product, *cur)) { + match = TRUE; + break; + } + if (!match) + return FALSE; + } + if (iclass->match_vendor) { + if (!attrs->vendor) + return FALSE; + /* see if any of the values match */ + for (cur = iclass->match_vendor, match = FALSE; *cur; cur++) + if (strstr(attrs->vendor, *cur)) { + match = TRUE; + break; + } + if (!match) + return FALSE; + } + if (iclass->match_device) { + if (!attrs->device) + return FALSE; + /* see if any of the values match */ + for (cur = iclass->match_device, match = FALSE; *cur; cur++) +#ifdef HAVE_FNMATCH_H + if (fnmatch(*cur, attrs->device, FNM_PATHNAME) == 0) { +#else + if (strstr(attrs->device, *cur)) { +#endif + match = TRUE; + break; + } + if (!match) + return FALSE; + } + if (iclass->match_tag) { + if (!attrs->tags) + return FALSE; + + for (cur = iclass->match_tag, match = FALSE; *cur && !match; cur++) { + const char *tag; + for(tag = *attrs->tags; *tag; tag++) { + if (!strcmp(tag, *cur)) { + match = TRUE; + break; + } + } + } + + if (!match) + return FALSE; + } + + if (iclass->is_keyboard.set && + iclass->is_keyboard.val != !!(attrs->flags & ATTR_KEYBOARD)) + return FALSE; + if (iclass->is_pointer.set && + iclass->is_pointer.val != !!(attrs->flags & ATTR_POINTER)) + return FALSE; + if (iclass->is_joystick.set && + iclass->is_joystick.val != !!(attrs->flags & ATTR_JOYSTICK)) + return FALSE; + if (iclass->is_tablet.set && + iclass->is_tablet.val != !!(attrs->flags & ATTR_TABLET)) + return FALSE; + if (iclass->is_touchpad.set && + iclass->is_touchpad.val != !!(attrs->flags & ATTR_TOUCHPAD)) + return FALSE; + if (iclass->is_touchscreen.set && + iclass->is_touchscreen.val != !!(attrs->flags & ATTR_TOUCHSCREEN)) + return FALSE; + return TRUE; +} + +/* + * Merge in any InputClass configurations. Options in each InputClass + * section have more priority than the original device configuration as + * well as any previous InputClass sections. + */ +static int +MergeInputClasses(IDevPtr idev, InputAttributes *attrs) +{ + XF86ConfInputClassPtr cl; + XF86OptionPtr classopts, mergedopts = NULL; + char *classdriver = NULL; + + for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) { + if (!InputClassMatches(cl, attrs)) + continue; + + /* Collect class options and merge over previous classes */ + xf86Msg(X_CONFIG, "%s: Applying InputClass \"%s\"\n", + idev->identifier, cl->identifier); + if (cl->driver) + classdriver = cl->driver; + classopts = xf86optionListDup(cl->option_lst); + mergedopts = xf86optionListMerge(mergedopts, classopts); + } + + /* Apply options to device with InputClass settings preferred. */ + if (classdriver) { + free(idev->driver); + idev->driver = xstrdup(classdriver); + if (!idev->driver) { + xf86Msg(X_ERROR, "Failed to allocate memory while merging " + "InputClass configuration"); + return BadAlloc; + } + mergedopts = xf86ReplaceStrOption(mergedopts, "driver", idev->driver); + } + idev->commonOptions = xf86optionListMerge(idev->commonOptions, mergedopts); + + return Success; +} + +/* + * Iterate the list of classes and look for Option "Ignore". Return the + * value of the last matching class and holler when returning TRUE. + */ +static Bool +IgnoreInputClass(IDevPtr idev, InputAttributes *attrs) +{ + XF86ConfInputClassPtr cl; + Bool ignore = FALSE; + const char *ignore_class; + + for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) { + if (!InputClassMatches(cl, attrs)) + continue; + if (xf86findOption(cl->option_lst, "Ignore")) { + ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE); + ignore_class = cl->identifier; + } + } + + if (ignore) + xf86Msg(X_CONFIG, "%s: Ignoring device from InputClass \"%s\"\n", + idev->identifier, ignore_class); + return ignore; +} + +/** + * Create a new input device, activate and enable it. + * + * Possible return codes: + * BadName .. a bad driver name was supplied. + * BadImplementation ... The driver does not have a PreInit function. This + * is a driver bug. + * BadMatch .. device initialization failed. + * BadAlloc .. too many input devices + * + * @param idev The device, already set up with identifier, driver, and the + * options. + * @param pdev Pointer to the new device, if Success was reported. + * @param enable Enable the device after activating it. + * + * @return Success or an error code + */ +_X_INTERNAL int +xf86NewInputDevice(IDevPtr idev, DeviceIntPtr *pdev, BOOL enable) +{ + InputDriverPtr drv = NULL; + InputInfoPtr pInfo = NULL; + DeviceIntPtr dev = NULL; + int rval; + + /* Memory leak for every attached device if we don't + * test if the module is already loaded first */ + drv = xf86LookupInputDriver(idev->driver); + if (!drv) + if (xf86LoadOneModule(idev->driver, NULL)) + drv = xf86LookupInputDriver(idev->driver); + if (!drv) { + xf86Msg(X_ERROR, "No input driver matching `%s'\n", idev->driver); + rval = BadName; + goto unwind; + } + + if (!drv->PreInit) { + xf86Msg(X_ERROR, + "Input driver `%s' has no PreInit function (ignoring)\n", + drv->driverName); + rval = BadImplementation; + goto unwind; + } + + pInfo = drv->PreInit(drv, idev, 0); + + if (!pInfo) { + xf86Msg(X_ERROR, "PreInit returned NULL for \"%s\"\n", idev->identifier); + rval = BadMatch; + goto unwind; + } + else if (!(pInfo->flags & XI86_CONFIGURED)) { + xf86Msg(X_ERROR, "PreInit failed for input device \"%s\"\n", + idev->identifier); + rval = BadMatch; + goto unwind; + } + + if (!xf86ActivateDevice(pInfo)) + { + rval = BadAlloc; + goto unwind; + } + + dev = pInfo->dev; + rval = ActivateDevice(dev, TRUE); + if (rval != Success) + { + xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", idev->identifier); + RemoveDevice(dev, TRUE); + goto unwind; + } + + /* Enable it if it's properly initialised and we're currently in the VT */ + if (enable && dev->inited && dev->startup && xf86Screens[0]->vtSema) + { + EnableDevice(dev, TRUE); + if (!dev->enabled) + { + xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", idev->identifier); + rval = BadMatch; + goto unwind; + } + /* send enter/leave event, update sprite window */ + CheckMotion(NULL, dev); + } + + *pdev = dev; + return Success; + +unwind: + if(pInfo) { + if(drv->UnInit) + drv->UnInit(drv, pInfo, 0); + else + xf86DeleteInput(pInfo, 0); + } + return rval; +} + +int +NewInputDeviceRequest (InputOption *options, InputAttributes *attrs, + DeviceIntPtr *pdev) +{ + IDevRec *idev = NULL; + InputOption *option = NULL; + int rval = Success; + int is_auto = 0; + + idev = calloc(sizeof(*idev), 1); + if (!idev) + return BadAlloc; + + for (option = options; option; option = option->next) { + if (strcasecmp(option->key, "driver") == 0) { + if (idev->driver) { + rval = BadRequest; + goto unwind; + } + idev->driver = xstrdup(option->value); + if (!idev->driver) { + rval = BadAlloc; + goto unwind; + } + } + + if (strcasecmp(option->key, "name") == 0 || + strcasecmp(option->key, "identifier") == 0) { + if (idev->identifier) { + rval = BadRequest; + goto unwind; + } + idev->identifier = xstrdup(option->value); + if (!idev->identifier) { + rval = BadAlloc; + goto unwind; + } + } + + if (strcmp(option->key, "_source") == 0 && + (strcmp(option->value, "server/hal") == 0 || + strcmp(option->value, "server/udev") == 0)) { + is_auto = 1; + if (!xf86Info.autoAddDevices) { + rval = BadMatch; + goto unwind; + } + } + } + + for (option = options; option; option = option->next) { + /* Steal option key/value strings from the provided list. + * We need those strings, the InputOption list doesn't. */ + idev->commonOptions = xf86addNewOption(idev->commonOptions, + option->key, option->value); + option->key = NULL; + option->value = NULL; + } + + /* Apply InputClass settings */ + if (attrs) { + if (IgnoreInputClass(idev, attrs)) { + rval = BadIDChoice; + goto unwind; + } + + rval = MergeInputClasses(idev, attrs); + if (rval != Success) + goto unwind; + } + + if (!idev->driver || !idev->identifier) { + xf86Msg(X_INFO, "No input driver/identifier specified (ignoring)\n"); + rval = BadRequest; + goto unwind; + } + + if (!idev->identifier) { + xf86Msg(X_ERROR, "No device identifier specified (ignoring)\n"); + return BadMatch; + } + + rval = xf86NewInputDevice(idev, pdev, + (!is_auto || (is_auto && xf86Info.autoEnableDevices))); + if (rval == Success) + return Success; + +unwind: + if (is_auto && !xf86Info.autoAddDevices) + xf86Msg(X_INFO, "AutoAddDevices is off - not adding device.\n"); + if(idev->driver) + free(idev->driver); + if(idev->identifier) + free(idev->identifier); + xf86optionListFree(idev->commonOptions); + free(idev); + return rval; +} + +void +DeleteInputDeviceRequest(DeviceIntPtr pDev) +{ + LocalDevicePtr pInfo = (LocalDevicePtr) pDev->public.devicePrivate; + InputDriverPtr drv = NULL; + IDevRec *idev = NULL; + IDevPtr *it; + Bool isMaster = IsMaster(pDev); + + if (pInfo) /* need to get these before RemoveDevice */ + { + drv = pInfo->drv; + idev = pInfo->conf_idev; + } + + OsBlockSignals(); + RemoveDevice(pDev, TRUE); + + if (!isMaster && pInfo != NULL) + { + if(drv->UnInit) + drv->UnInit(drv, pInfo, 0); + else + xf86DeleteInput(pInfo, 0); + + /* devices added through HAL aren't in the config layout */ + it = xf86ConfigLayout.inputs; + while(*it && *it != idev) + it++; + + if (!(*it)) /* end of list, not in the layout */ + { + free(idev->driver); + free(idev->identifier); + xf86optionListFree(idev->commonOptions); + free(idev); + } + } + OsReleaseSignals(); +} + +/* + * convenient functions to post events + */ + +void +xf86PostMotionEvent(DeviceIntPtr device, + int is_absolute, + int first_valuator, + int num_valuators, + ...) +{ + va_list var; + int i = 0; + static int valuators[MAX_VALUATORS]; + + XI_VERIFY_VALUATORS(num_valuators); + + va_start(var, num_valuators); + for (i = 0; i < num_valuators; i++) + valuators[i] = va_arg(var, int); + va_end(var); + + xf86PostMotionEventP(device, is_absolute, first_valuator, num_valuators, valuators); +} + +void +xf86PostMotionEventP(DeviceIntPtr device, + int is_absolute, + int first_valuator, + int num_valuators, + int *valuators) +{ + int i = 0, nevents = 0; + Bool drag = xf86SendDragEvents(device); + DeviceEvent *event; + int flags = 0; + +#if XFreeXDGA + int index; + int dx = 0, dy = 0; +#endif + + XI_VERIFY_VALUATORS(num_valuators); + + if (is_absolute) + flags = POINTER_ABSOLUTE; + else + flags = POINTER_RELATIVE | POINTER_ACCELERATE; + +#if XFreeXDGA + /* The evdev driver may not always send all axes across. */ + if (num_valuators >= 1 && first_valuator <= 1) { + if (miPointerGetScreen(device)) { + index = miPointerGetScreen(device)->myNum; + if (first_valuator == 0) + { + dx = valuators[0]; + if (is_absolute) + dx -= device->last.valuators[0]; + } + + if (first_valuator == 1 || num_valuators >= 2) + { + dy = valuators[1 - first_valuator]; + if (is_absolute) + dy -= device->last.valuators[1]; + } + + if (DGAStealMotionEvent(device, index, dx, dy)) + return; + } + } +#endif + + nevents = GetPointerEvents(xf86Events, device, MotionNotify, 0, + flags, first_valuator, num_valuators, + valuators); + + for (i = 0; i < nevents; i++) { + event = (DeviceEvent*)((xf86Events + i)->event); + /* Don't post core motion events for devices not registered to send + * drag events. */ + if (event->header == ET_Internal && + (event->type != ET_Motion || drag)) { + mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event)); + } + } +} + +void +xf86PostProximityEvent(DeviceIntPtr device, + int is_in, + int first_valuator, + int num_valuators, + ...) +{ + va_list var; + int i; + int valuators[MAX_VALUATORS]; + + XI_VERIFY_VALUATORS(num_valuators); + + va_start(var, num_valuators); + for (i = 0; i < num_valuators; i++) + valuators[i] = va_arg(var, int); + va_end(var); + + xf86PostProximityEventP(device, is_in, first_valuator, num_valuators, + valuators); + +} + +void +xf86PostProximityEventP(DeviceIntPtr device, + int is_in, + int first_valuator, + int num_valuators, + int *valuators) +{ + int i, nevents; + + XI_VERIFY_VALUATORS(num_valuators); + + nevents = GetProximityEvents(xf86Events, device, + is_in ? ProximityIn : ProximityOut, + first_valuator, num_valuators, valuators); + for (i = 0; i < nevents; i++) + mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event)); + +} + +void +xf86PostButtonEvent(DeviceIntPtr device, + int is_absolute, + int button, + int is_down, + int first_valuator, + int num_valuators, + ...) +{ + va_list var; + int valuators[MAX_VALUATORS]; + int i = 0; + + XI_VERIFY_VALUATORS(num_valuators); + + va_start(var, num_valuators); + for (i = 0; i < num_valuators; i++) + valuators[i] = va_arg(var, int); + va_end(var); + + xf86PostButtonEventP(device, is_absolute, button, is_down, first_valuator, + num_valuators, valuators); + +} + +void +xf86PostButtonEventP(DeviceIntPtr device, + int is_absolute, + int button, + int is_down, + int first_valuator, + int num_valuators, + int *valuators) +{ + int i = 0, nevents = 0; + int flags = 0; + +#if XFreeXDGA + int index; +#endif + + XI_VERIFY_VALUATORS(num_valuators); + + if (is_absolute) + flags = POINTER_ABSOLUTE; + else + flags = POINTER_RELATIVE | POINTER_ACCELERATE; + +#if XFreeXDGA + if (miPointerGetScreen(device)) { + index = miPointerGetScreen(device)->myNum; + if (DGAStealButtonEvent(device, index, button, is_down)) + return; + } +#endif + + nevents = GetPointerEvents(xf86Events, device, + is_down ? ButtonPress : ButtonRelease, button, + flags, first_valuator, num_valuators, valuators); + + for (i = 0; i < nevents; i++) + mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event)); + +} + +void +xf86PostKeyEvent(DeviceIntPtr device, + unsigned int key_code, + int is_down, + int is_absolute, + int first_valuator, + int num_valuators, + ...) +{ + va_list var; + int i = 0; + static int valuators[MAX_VALUATORS]; + + XI_VERIFY_VALUATORS(num_valuators); + + va_start(var, num_valuators); + for (i = 0; i < num_valuators; i++) + valuators[i] = va_arg(var, int); + va_end(var); + + xf86PostKeyEventP(device, key_code, is_down, is_absolute, first_valuator, + num_valuators, valuators); + +} + +void +xf86PostKeyEventP(DeviceIntPtr device, + unsigned int key_code, + int is_down, + int is_absolute, + int first_valuator, + int num_valuators, + int *valuators) +{ + int i = 0, nevents = 0; + + XI_VERIFY_VALUATORS(num_valuators); + + if (is_absolute) { + nevents = GetKeyboardValuatorEvents(xf86Events, device, + is_down ? KeyPress : KeyRelease, + key_code, first_valuator, + num_valuators, valuators); + } + else { + nevents = GetKeyboardEvents(xf86Events, device, + is_down ? KeyPress : KeyRelease, + key_code); + } + + for (i = 0; i < nevents; i++) + mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event)); +} + +void +xf86PostKeyboardEvent(DeviceIntPtr device, + unsigned int key_code, + int is_down) +{ + xf86PostKeyEventP(device, key_code, is_down, 0, 0, 0, NULL); +} + +LocalDevicePtr +xf86FirstLocalDevice(void) +{ + return xf86InputDevs; +} + +/* + * Cx - raw data from touch screen + * Sxhigh - scaled highest dimension + * (remember, this is of rows - 1 because of 0 origin) + * Sxlow - scaled lowest dimension + * Rxhigh - highest raw value from touch screen calibration + * Rxlow - lowest raw value from touch screen calibration + * + * This function is the same for X or Y coordinates. + * You may have to reverse the high and low values to compensate for + * different orgins on the touch screen vs X. + */ + +int +xf86ScaleAxis(int Cx, + int Sxhigh, + int Sxlow, + int Rxhigh, + int Rxlow ) +{ + int X; + int64_t dSx = Sxhigh - Sxlow; + int64_t dRx = Rxhigh - Rxlow; + + if (dRx) { + X = (int)(((dSx * (Cx - Rxlow)) / dRx) + Sxlow); + } + else { + X = 0; + ErrorF ("Divide by Zero in xf86ScaleAxis"); + } + + if (X > Sxhigh) + X = Sxhigh; + if (X < Sxlow) + X = Sxlow; + + return (X); +} + +/* + * This function checks the given screen against the current screen and + * makes changes if appropriate. It should be called from an XInput driver's + * ReadInput function before any events are posted, if the device is screen + * specific like a touch screen. + */ +void +xf86XInputSetScreen(LocalDevicePtr local, + int screen_number, + int x, + int y) +{ + if (miPointerGetScreen(local->dev) != + screenInfo.screens[screen_number]) { + miPointerSetScreen(local->dev, screen_number, x, y); + } +} + + +void +xf86InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int maxval, + int resolution, int min_res, int max_res) +{ + if (!dev || !dev->valuator) + return; + + InitValuatorAxisStruct(dev, axnum, label, minval, maxval, resolution, min_res, + max_res); +} + +/* + * Set the valuator values to be in synch with dix/event.c + * DefineInitialRootWindow(). + */ +void +xf86InitValuatorDefaults(DeviceIntPtr dev, int axnum) +{ + if (axnum == 0) { + dev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; + dev->last.valuators[0] = dev->valuator->axisVal[0]; + } + else if (axnum == 1) { + dev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; + dev->last.valuators[1] = dev->valuator->axisVal[1]; + } + + if(axnum == 0) /* to prevent double invocation */ + ApplyAccelerationSettings(dev); +} + + +/** + * Deactivate a device. Call this function from the driver if you receive a + * read error or something else that spoils your day. + * Device will be moved to the off_devices list, but it will still be there + * until you really clean up after it. + * Notifies the client about an inactive device. + * + * @param panic True if device is unrecoverable and needs to be removed. + */ +void +xf86DisableDevice(DeviceIntPtr dev, Bool panic) +{ + if(!panic) + { + DisableDevice(dev, TRUE); + } else + { + SendDevicePresenceEvent(dev->id, DeviceUnrecoverable); + DeleteInputDeviceRequest(dev); + } +} + +/** + * Reactivate a device. Call this function from the driver if you just found + * out that the read error wasn't quite that bad after all. + * Device will be re-activated, and an event sent to the client. + */ +void +xf86EnableDevice(DeviceIntPtr dev) +{ + EnableDevice(dev, TRUE); +} + +/* end of xf86Xinput.c */ diff --git a/xorg-server/hw/xfree86/common/xf86cmap.c b/xorg-server/hw/xfree86/common/xf86cmap.c index e266ffb6d..fa0ebc8eb 100644 --- a/xorg-server/hw/xfree86/common/xf86cmap.c +++ b/xorg-server/hw/xfree86/common/xf86cmap.c @@ -1,1166 +1,1166 @@ -/* - * Copyright (c) 1998-2001 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#if defined(_XOPEN_SOURCE) || defined(sun) && defined(__SVR4) -#include <math.h> -#else -#define _XOPEN_SOURCE /* to get prototype for pow on some systems */ -#include <math.h> -#undef _XOPEN_SOURCE -#endif - -#include <X11/X.h> -#include "misc.h" -#include <X11/Xproto.h> -#include "colormapst.h" -#include "scrnintstr.h" - -#include "resource.h" - -#include "xf86.h" -#include "xf86_OSproc.h" -#include "xf86str.h" -#include "micmap.h" -#include "xf86Crtc.h" - -#ifdef XFreeXDGA -#include <X11/extensions/xf86dgaproto.h> -#include "dgaproc.h" -#endif - -#include "xf86cmap.h" - -#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \ - ((CMapScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, CMapScreenKey))->field) -#define SCREEN_EPILOGUE(pScreen, field, wrapper)\ - ((pScreen)->field = wrapper) - -#define LOAD_PALETTE(pmap) \ - ((pmap == GetInstalledmiColormap(pmap->pScreen)) && \ - ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || \ - xf86Screens[pmap->pScreen->myNum]->vtSema || pScreenPriv->isDGAmode)) - - -typedef struct _CMapLink { - ColormapPtr cmap; - struct _CMapLink *next; -} CMapLink, *CMapLinkPtr; - -typedef struct { - ScrnInfoPtr pScrn; - CloseScreenProcPtr CloseScreen; - CreateColormapProcPtr CreateColormap; - DestroyColormapProcPtr DestroyColormap; - InstallColormapProcPtr InstallColormap; - StoreColorsProcPtr StoreColors; - Bool (*EnterVT)(int, int); - Bool (*SwitchMode)(int, DisplayModePtr, int); - int (*SetDGAMode)(int, int, DGADevicePtr); - xf86ChangeGammaProc *ChangeGamma; - int maxColors; - int sigRGBbits; - int gammaElements; - LOCO *gamma; - int *PreAllocIndices; - CMapLinkPtr maps; - unsigned int flags; - Bool isDGAmode; -} CMapScreenRec, *CMapScreenPtr; - -typedef struct { - int numColors; - LOCO *colors; - Bool recalculate; - int overscan; -} CMapColormapRec, *CMapColormapPtr; - -static int CMapScreenKeyIndex; -static DevPrivateKey CMapScreenKey; -static int CMapColormapKeyIndex; -static DevPrivateKey CMapColormapKey = &CMapColormapKeyIndex; - -static void CMapInstallColormap(ColormapPtr); -static void CMapStoreColors(ColormapPtr, int, xColorItem *); -static Bool CMapCloseScreen (int, ScreenPtr); -static Bool CMapCreateColormap (ColormapPtr); -static void CMapDestroyColormap (ColormapPtr); - -static Bool CMapEnterVT(int, int); -static Bool CMapSwitchMode(int, DisplayModePtr, int); -#ifdef XFreeXDGA -static int CMapSetDGAMode(int, int, DGADevicePtr); -#endif -static int CMapChangeGamma(int, Gamma); - -static void ComputeGamma(CMapScreenPtr); -static Bool CMapAllocateColormapPrivate(ColormapPtr); -static void CMapRefreshColors(ColormapPtr, int, int*); -static void CMapSetOverscan(ColormapPtr, int, int *); -static void CMapReinstallMap(ColormapPtr); -static void CMapUnwrapScreen(ScreenPtr pScreen); - - - -Bool xf86HandleColormaps( - ScreenPtr pScreen, - int maxColors, - int sigRGBbits, - xf86LoadPaletteProc *loadPalette, - xf86SetOverscanProc *setOverscan, - unsigned int flags -){ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - ColormapPtr pDefMap = NULL; - CMapScreenPtr pScreenPriv; - LOCO *gamma; - int *indices; - int elements; - - /* If we support a better colormap system, then pretend we succeeded. */ - if (xf86_crtc_supports_gamma(pScrn)) - return TRUE; - - if(!maxColors || !sigRGBbits || !loadPalette) - return FALSE; - - CMapScreenKey = &CMapScreenKeyIndex; - - elements = 1 << sigRGBbits; - - if(!(gamma = xalloc(elements * sizeof(LOCO)))) - return FALSE; - - if(!(indices = xalloc(maxColors * sizeof(int)))) { - xfree(gamma); - return FALSE; - } - - if(!(pScreenPriv = xalloc(sizeof(CMapScreenRec)))) { - xfree(gamma); - xfree(indices); - return FALSE; - } - - dixSetPrivate(&pScreen->devPrivates, CMapScreenKey, pScreenPriv); - - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreenPriv->CreateColormap = pScreen->CreateColormap; - pScreenPriv->DestroyColormap = pScreen->DestroyColormap; - pScreenPriv->InstallColormap = pScreen->InstallColormap; - pScreenPriv->StoreColors = pScreen->StoreColors; - pScreen->CloseScreen = CMapCloseScreen; - pScreen->CreateColormap = CMapCreateColormap; - pScreen->DestroyColormap = CMapDestroyColormap; - pScreen->InstallColormap = CMapInstallColormap; - pScreen->StoreColors = CMapStoreColors; - - pScreenPriv->pScrn = pScrn; - pScrn->LoadPalette = loadPalette; - pScrn->SetOverscan = setOverscan; - pScreenPriv->maxColors = maxColors; - pScreenPriv->sigRGBbits = sigRGBbits; - pScreenPriv->gammaElements = elements; - pScreenPriv->gamma = gamma; - pScreenPriv->PreAllocIndices = indices; - pScreenPriv->maps = NULL; - pScreenPriv->flags = flags; - pScreenPriv->isDGAmode = FALSE; - - pScreenPriv->EnterVT = pScrn->EnterVT; - pScreenPriv->SwitchMode = pScrn->SwitchMode; - pScreenPriv->SetDGAMode = pScrn->SetDGAMode; - pScreenPriv->ChangeGamma = pScrn->ChangeGamma; - - if (!(flags & CMAP_LOAD_EVEN_IF_OFFSCREEN)) { - pScrn->EnterVT = CMapEnterVT; - if ((flags & CMAP_RELOAD_ON_MODE_SWITCH) && pScrn->SwitchMode) - pScrn->SwitchMode = CMapSwitchMode; - } -#ifdef XFreeXDGA - pScrn->SetDGAMode = CMapSetDGAMode; -#endif - pScrn->ChangeGamma = CMapChangeGamma; - - ComputeGamma(pScreenPriv); - - /* get the default map */ - dixLookupResourceByType((pointer *)&pDefMap, pScreen->defColormap, - RT_COLORMAP, serverClient, DixInstallAccess); - - if(!CMapAllocateColormapPrivate(pDefMap)) { - CMapUnwrapScreen(pScreen); - return FALSE; - } - - /* Force the initial map to be loaded */ - SetInstalledmiColormap(pScreen, NULL); - CMapInstallColormap(pDefMap); - return TRUE; -} - - -/**** Screen functions ****/ - - -static Bool -CMapCloseScreen (int i, ScreenPtr pScreen) -{ - CMapUnwrapScreen(pScreen); - - return (*pScreen->CloseScreen) (i, pScreen); -} - -static Bool -CMapColormapUseMax(VisualPtr pVisual, CMapScreenPtr pScreenPriv) -{ - if (pVisual->nplanes > 16) - return TRUE; - return ((1 << pVisual->nplanes) > pScreenPriv->maxColors); -} - -static Bool -CMapAllocateColormapPrivate(ColormapPtr pmap) -{ - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pmap->pScreen->devPrivates, CMapScreenKey); - CMapColormapPtr pColPriv; - CMapLinkPtr pLink; - int numColors; - LOCO *colors; - - if (CMapColormapUseMax(pmap->pVisual, pScreenPriv)) - numColors = pmap->pVisual->ColormapEntries; - else - numColors = 1 << pmap->pVisual->nplanes; - - if(!(colors = xalloc(numColors * sizeof(LOCO)))) - return FALSE; - - if(!(pColPriv = xalloc(sizeof(CMapColormapRec)))) { - xfree(colors); - return FALSE; - } - - dixSetPrivate(&pmap->devPrivates, CMapColormapKey, pColPriv); - - pColPriv->numColors = numColors; - pColPriv->colors = colors; - pColPriv->recalculate = TRUE; - pColPriv->overscan = -1; - - /* add map to list */ - pLink = xalloc(sizeof(CMapLink)); - if(pLink) { - pLink->cmap = pmap; - pLink->next = pScreenPriv->maps; - pScreenPriv->maps = pLink; - } - - return TRUE; -} - -static Bool -CMapCreateColormap (ColormapPtr pmap) -{ - ScreenPtr pScreen = pmap->pScreen; - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, CMapScreenKey); - Bool ret = FALSE; - - pScreen->CreateColormap = pScreenPriv->CreateColormap; - if((*pScreen->CreateColormap)(pmap)) { - if(CMapAllocateColormapPrivate(pmap)) - ret = TRUE; - } - pScreen->CreateColormap = CMapCreateColormap; - - return ret; -} - -static void -CMapDestroyColormap (ColormapPtr cmap) -{ - ScreenPtr pScreen = cmap->pScreen; - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, CMapScreenKey); - CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate( - &cmap->devPrivates, CMapColormapKey); - CMapLinkPtr prevLink = NULL, pLink = pScreenPriv->maps; - - if(pColPriv) { - if(pColPriv->colors) xfree(pColPriv->colors); - xfree(pColPriv); - } - - /* remove map from list */ - while(pLink) { - if(pLink->cmap == cmap) { - if(prevLink) - prevLink->next = pLink->next; - else - pScreenPriv->maps = pLink->next; - xfree(pLink); - break; - } - prevLink = pLink; - pLink = pLink->next; - } - - if(pScreenPriv->DestroyColormap) { - pScreen->DestroyColormap = pScreenPriv->DestroyColormap; - (*pScreen->DestroyColormap)(cmap); - pScreen->DestroyColormap = CMapDestroyColormap; - } -} - - - -static void -CMapStoreColors( - ColormapPtr pmap, - int ndef, - xColorItem *pdefs -){ - ScreenPtr pScreen = pmap->pScreen; - VisualPtr pVisual = pmap->pVisual; - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, CMapScreenKey); - int *indices = pScreenPriv->PreAllocIndices; - int num = ndef; - - /* At the moment this isn't necessary since there's nobody below us */ - pScreen->StoreColors = pScreenPriv->StoreColors; - (*pScreen->StoreColors)(pmap, ndef, pdefs); - pScreen->StoreColors = CMapStoreColors; - - /* should never get here for these */ - if( (pVisual->class == TrueColor) || - (pVisual->class == StaticColor) || - (pVisual->class == StaticGray)) - return; - - if(pVisual->class == DirectColor) { - CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate( - &pmap->devPrivates, CMapColormapKey); - int i; - - if (CMapColormapUseMax(pVisual, pScreenPriv)) { - int index; - - num = 0; - while(ndef--) { - if(pdefs[ndef].flags & DoRed) { - index = (pdefs[ndef].pixel & pVisual->redMask) >> - pVisual->offsetRed; - i = num; - while(i--) - if(indices[i] == index) break; - if(i == -1) - indices[num++] = index; - } - if(pdefs[ndef].flags & DoGreen) { - index = (pdefs[ndef].pixel & pVisual->greenMask) >> - pVisual->offsetGreen; - i = num; - while(i--) - if(indices[i] == index) break; - if(i == -1) - indices[num++] = index; - } - if(pdefs[ndef].flags & DoBlue) { - index = (pdefs[ndef].pixel & pVisual->blueMask) >> - pVisual->offsetBlue; - i = num; - while(i--) - if(indices[i] == index) break; - if(i == -1) - indices[num++] = index; - } - } - - } else { - /* not really as overkill as it seems */ - num = pColPriv->numColors; - for(i = 0; i < pColPriv->numColors; i++) - indices[i] = i; - } - } else { - while(ndef--) - indices[ndef] = pdefs[ndef].pixel; - } - - CMapRefreshColors(pmap, num, indices); -} - - -static void -CMapInstallColormap(ColormapPtr pmap) -{ - ScreenPtr pScreen = pmap->pScreen; - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, CMapScreenKey); - - if (pmap == GetInstalledmiColormap(pmap->pScreen)) - return; - - pScreen->InstallColormap = pScreenPriv->InstallColormap; - (*pScreen->InstallColormap)(pmap); - pScreen->InstallColormap = CMapInstallColormap; - - /* Important. We let the lower layers, namely DGA, - overwrite the choice of Colormap to install */ - if (GetInstalledmiColormap(pmap->pScreen)) - pmap = GetInstalledmiColormap(pmap->pScreen); - - if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && - (pmap->pVisual->class == TrueColor) && - CMapColormapUseMax(pmap->pVisual, pScreenPriv)) - return; - - if(LOAD_PALETTE(pmap)) - CMapReinstallMap(pmap); -} - - -/**** ScrnInfoRec functions ****/ - -static Bool -CMapEnterVT(int index, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, CMapScreenKey); - - if((*pScreenPriv->EnterVT)(index, flags)) { - if(GetInstalledmiColormap(pScreen)) - CMapReinstallMap(GetInstalledmiColormap(pScreen)); - return TRUE; - } - return FALSE; -} - - -static Bool -CMapSwitchMode(int index, DisplayModePtr mode, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, CMapScreenKey); - - if((*pScreenPriv->SwitchMode)(index, mode, flags)) { - if(GetInstalledmiColormap(pScreen)) - CMapReinstallMap(GetInstalledmiColormap(pScreen)); - return TRUE; - } - return FALSE; -} - -#ifdef XFreeXDGA -static int -CMapSetDGAMode(int index, int num, DGADevicePtr dev) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, CMapScreenKey); - int ret; - - ret = (*pScreenPriv->SetDGAMode)(index, num, dev); - - pScreenPriv->isDGAmode = DGAActive(index); - - if(!pScreenPriv->isDGAmode && GetInstalledmiColormap(pScreen) - && xf86Screens[pScreen->myNum]->vtSema) - CMapReinstallMap(GetInstalledmiColormap(pScreen)); - - return ret; -} -#endif - - -/**** Utilities ****/ - -static void -CMapReinstallMap(ColormapPtr pmap) -{ - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pmap->pScreen->devPrivates, CMapScreenKey); - CMapColormapPtr cmapPriv = (CMapColormapPtr)dixLookupPrivate( - &pmap->devPrivates, CMapColormapKey); - ScrnInfoPtr pScrn = xf86Screens[pmap->pScreen->myNum]; - int i = cmapPriv->numColors; - int *indices = pScreenPriv->PreAllocIndices; - - while(i--) - indices[i] = i; - - if(cmapPriv->recalculate) - CMapRefreshColors(pmap, cmapPriv->numColors, indices); - else { - (*pScrn->LoadPalette)(pScrn, cmapPriv->numColors, - indices, cmapPriv->colors, pmap->pVisual); - if (pScrn->SetOverscan) { -#ifdef DEBUGOVERSCAN - ErrorF("SetOverscan() called from CMapReinstallMap\n"); -#endif - pScrn->SetOverscan(pScrn, cmapPriv->overscan); - } - } - - cmapPriv->recalculate = FALSE; -} - - -static void -CMapRefreshColors(ColormapPtr pmap, int defs, int* indices) -{ - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pmap->pScreen->devPrivates, CMapScreenKey); - CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate( - &pmap->devPrivates, CMapColormapKey); - VisualPtr pVisual = pmap->pVisual; - ScrnInfoPtr pScrn = xf86Screens[pmap->pScreen->myNum]; - int numColors, i; - LOCO *gamma, *colors; - EntryPtr entry; - int reds, greens, blues, maxValue, index, shift; - - numColors = pColPriv->numColors; - shift = 16 - pScreenPriv->sigRGBbits; - maxValue = (1 << pScreenPriv->sigRGBbits) - 1; - gamma = pScreenPriv->gamma; - colors = pColPriv->colors; - - reds = pVisual->redMask >> pVisual->offsetRed; - greens = pVisual->greenMask >> pVisual->offsetGreen; - blues = pVisual->blueMask >> pVisual->offsetBlue; - - switch(pVisual->class) { - case StaticGray: - for(i = 0; i < numColors; i++) { - index = (i+1) * maxValue / numColors; - colors[i].red = gamma[index].red; - colors[i].green = gamma[index].green; - colors[i].blue = gamma[index].blue; - } - break; - case TrueColor: - if (CMapColormapUseMax(pVisual, pScreenPriv)) { - for(i = 0; i <= reds; i++) - colors[i].red = gamma[i * maxValue / reds].red; - for(i = 0; i <= greens; i++) - colors[i].green = gamma[i * maxValue / greens].green; - for(i = 0; i <= blues; i++) - colors[i].blue = gamma[i * maxValue / blues].blue; - break; - } - for(i = 0; i < numColors; i++) { - colors[i].red = gamma[((i >> pVisual->offsetRed) & reds) * - maxValue / reds].red; - colors[i].green = gamma[((i >> pVisual->offsetGreen) & greens) * - maxValue / greens].green; - colors[i].blue = gamma[((i >> pVisual->offsetBlue) & blues) * - maxValue / blues].blue; - } - break; - case StaticColor: - case PseudoColor: - case GrayScale: - for(i = 0; i < defs; i++) { - index = indices[i]; - entry = (EntryPtr)&pmap->red[index]; - - if(entry->fShared) { - colors[index].red = - gamma[entry->co.shco.red->color >> shift].red; - colors[index].green = - gamma[entry->co.shco.green->color >> shift].green; - colors[index].blue = - gamma[entry->co.shco.blue->color >> shift].blue; - } else { - colors[index].red = - gamma[entry->co.local.red >> shift].red; - colors[index].green = - gamma[entry->co.local.green >> shift].green; - colors[index].blue = - gamma[entry->co.local.blue >> shift].blue; - } - } - break; - case DirectColor: - if (CMapColormapUseMax(pVisual, pScreenPriv)) { - for(i = 0; i < defs; i++) { - index = indices[i]; - if(index <= reds) - colors[index].red = - gamma[pmap->red[index].co.local.red >> shift].red; - if(index <= greens) - colors[index].green = - gamma[pmap->green[index].co.local.green >> shift].green; - if(index <= blues) - colors[index].blue = - gamma[pmap->blue[index].co.local.blue >> shift].blue; - - } - break; - } - for(i = 0; i < defs; i++) { - index = indices[i]; - - colors[index].red = gamma[pmap->red[ - (index >> pVisual->offsetRed) & reds - ].co.local.red >> shift].red; - colors[index].green = gamma[pmap->green[ - (index >> pVisual->offsetGreen) & greens - ].co.local.green >> shift].green; - colors[index].blue = gamma[pmap->blue[ - (index >> pVisual->offsetBlue) & blues - ].co.local.blue >> shift].blue; - } - break; - } - - - if(LOAD_PALETTE(pmap)) - (*pScrn->LoadPalette)(pScreenPriv->pScrn, defs, indices, - colors, pmap->pVisual); - - if (pScrn->SetOverscan) - CMapSetOverscan(pmap, defs, indices); - -} - -static Bool -CMapCompareColors(LOCO *color1, LOCO *color2) -{ - /* return TRUE if the color1 is "closer" to black than color2 */ -#ifdef DEBUGOVERSCAN - ErrorF("#%02x%02x%02x vs #%02x%02x%02x (%d vs %d)\n", - color1->red, color1->green, color1->blue, - color2->red, color2->green, color2->blue, - color1->red + color1->green + color1->blue, - color2->red + color2->green + color2->blue); -#endif - return (color1->red + color1->green + color1->blue < - color2->red + color2->green + color2->blue); -} - -static void -CMapSetOverscan(ColormapPtr pmap, int defs, int *indices) -{ - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pmap->pScreen->devPrivates, CMapScreenKey); - CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate( - &pmap->devPrivates, CMapColormapKey); - ScrnInfoPtr pScrn = xf86Screens[pmap->pScreen->myNum]; - VisualPtr pVisual = pmap->pVisual; - int i; - LOCO *colors; - int index; - Bool newOverscan = FALSE; - int overscan, tmpOverscan; - - colors = pColPriv->colors; - overscan = pColPriv->overscan; - - /* - * Search for a new overscan index in the following cases: - * - * - The index hasn't yet been initialised.  In this case search - * for an index that is black or a close match to black. - * - * - The colour of the old index is changed. In this case search - * all indices for a black or close match to black. - * - * - The colour of the old index wasn't black. In this case only - * search the indices that were changed for a better match to black. - */ - - switch (pVisual->class) { - case StaticGray: - case TrueColor: - /* Should only come here once. Initialise the overscan index to 0 */ - overscan = 0; - newOverscan = TRUE; - break; - case StaticColor: - /* - * Only come here once, but search for the overscan in the same way - * as for the other cases. - */ - case DirectColor: - case PseudoColor: - case GrayScale: - if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) { - /* Uninitialised */ - newOverscan = TRUE; - } else { - /* Check if the overscan was changed */ - for (i = 0; i < defs; i++) { - index = indices[i]; - if (index == overscan) { - newOverscan = TRUE; - break; - } - } - } - if (newOverscan) { - /* The overscan is either uninitialised or it has been changed */ - - if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) - tmpOverscan = pScreenPriv->maxColors - 1; - else - tmpOverscan = overscan; - - /* search all entries for a close match to black */ - for (i = pScreenPriv->maxColors - 1; i >= 0; i--) { - if (colors[i].red == 0 && colors[i].green == 0 && - colors[i].blue == 0) { - overscan = i; -#ifdef DEBUGOVERSCAN - ErrorF("Black found at index 0x%02x\n", i); -#endif - break; - } else { -#ifdef DEBUGOVERSCAN - ErrorF("0x%02x: ", i); -#endif - if (CMapCompareColors(&colors[i], &colors[tmpOverscan])) { - tmpOverscan = i; -#ifdef DEBUGOVERSCAN - ErrorF("possible \"Black\" at index 0x%02x\n", i); -#endif - } - } - } - if (i < 0) - overscan = tmpOverscan; - } else { - /* Check of the old overscan wasn't black */ - if (colors[overscan].red != 0 || colors[overscan].green != 0 || - colors[overscan].blue != 0) { - int oldOverscan = tmpOverscan = overscan; - /* See of there is now a better match */ - for (i = 0; i < defs; i++) { - index = indices[i]; - if (colors[index].red == 0 && colors[index].green == 0 && - colors[index].blue == 0) { - overscan = index; -#ifdef DEBUGOVERSCAN - ErrorF("Black found at index 0x%02x\n", index); -#endif - break; - } else { -#ifdef DEBUGOVERSCAN - ErrorF("0x%02x: ", index); -#endif - if (CMapCompareColors(&colors[index], - &colors[tmpOverscan])) { - tmpOverscan = index; -#ifdef DEBUGOVERSCAN - ErrorF("possible \"Black\" at index 0x%02x\n", - index); -#endif - } - } - } - if (i == defs) - overscan = tmpOverscan; - if (overscan != oldOverscan) - newOverscan = TRUE; - } - } - break; - } - if (newOverscan) { - pColPriv->overscan = overscan; - if (LOAD_PALETTE(pmap)) { -#ifdef DEBUGOVERSCAN - ErrorF("SetOverscan() called from CmapSetOverscan\n"); -#endif - pScrn->SetOverscan(pScreenPriv->pScrn, overscan); - } - } -} - -static void -CMapUnwrapScreen(ScreenPtr pScreen) -{ - CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, CMapScreenKey); - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - - pScreen->CloseScreen = pScreenPriv->CloseScreen; - pScreen->CreateColormap = pScreenPriv->CreateColormap; - pScreen->DestroyColormap = pScreenPriv->DestroyColormap; - pScreen->InstallColormap = pScreenPriv->InstallColormap; - pScreen->StoreColors = pScreenPriv->StoreColors; - - pScrn->EnterVT = pScreenPriv->EnterVT; - pScrn->SwitchMode = pScreenPriv->SwitchMode; - pScrn->SetDGAMode = pScreenPriv->SetDGAMode; - pScrn->ChangeGamma = pScreenPriv->ChangeGamma; - - xfree(pScreenPriv->gamma); - xfree(pScreenPriv->PreAllocIndices); - xfree(pScreenPriv); -} - - -static void -ComputeGamma(CMapScreenPtr priv) -{ - int elements = priv->gammaElements - 1; - double RedGamma, GreenGamma, BlueGamma; - int i; - -#ifndef DONT_CHECK_GAMMA - /* This check is to catch drivers that are not initialising pScrn->gamma */ - if (priv->pScrn->gamma.red < GAMMA_MIN || - priv->pScrn->gamma.red > GAMMA_MAX || - priv->pScrn->gamma.green < GAMMA_MIN || - priv->pScrn->gamma.green > GAMMA_MAX || - priv->pScrn->gamma.blue < GAMMA_MIN || - priv->pScrn->gamma.blue > GAMMA_MAX) { - - xf86DrvMsgVerb(priv->pScrn->scrnIndex, X_WARNING, 0, - "The %s driver didn't call xf86SetGamma() to initialise\n" - "\tthe gamma values.\n", priv->pScrn->driverName); - xf86DrvMsgVerb(priv->pScrn->scrnIndex, X_WARNING, 0, - "PLEASE FIX THE `%s' DRIVER!\n", priv->pScrn->driverName); - priv->pScrn->gamma.red = 1.0; - priv->pScrn->gamma.green = 1.0; - priv->pScrn->gamma.blue = 1.0; - } -#endif - - RedGamma = 1.0 / (double)priv->pScrn->gamma.red; - GreenGamma = 1.0 / (double)priv->pScrn->gamma.green; - BlueGamma = 1.0 / (double)priv->pScrn->gamma.blue; - - for(i = 0; i <= elements; i++) { - if(RedGamma == 1.0) - priv->gamma[i].red = i; - else - priv->gamma[i].red = (CARD16)(pow((double)i/(double)elements, - RedGamma) * (double)elements + 0.5); - - if(GreenGamma == 1.0) - priv->gamma[i].green = i; - else - priv->gamma[i].green = (CARD16)(pow((double)i/(double)elements, - GreenGamma) * (double)elements + 0.5); - - if(BlueGamma == 1.0) - priv->gamma[i].blue = i; - else - priv->gamma[i].blue = (CARD16)(pow((double)i/(double)elements, - BlueGamma) * (double)elements + 0.5); - } -} - - -int -CMapChangeGamma( - int index, - Gamma gamma -){ - int ret = Success; - ScrnInfoPtr pScrn = xf86Screens[index]; - ScreenPtr pScreen = pScrn->pScreen; - CMapColormapPtr pColPriv; - CMapScreenPtr pScreenPriv; - CMapLinkPtr pLink; - - /* Is this sufficient checking ? */ - if(CMapScreenKey == NULL) - return BadImplementation; - - pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - CMapScreenKey); - if(!pScreenPriv) - return BadImplementation; - - if (gamma.red < GAMMA_MIN || gamma.red > GAMMA_MAX || - gamma.green < GAMMA_MIN || gamma.green > GAMMA_MAX || - gamma.blue < GAMMA_MIN || gamma.blue > GAMMA_MAX) - return BadValue; - - pScrn->gamma.red = gamma.red; - pScrn->gamma.green = gamma.green; - pScrn->gamma.blue = gamma.blue; - - ComputeGamma(pScreenPriv); - - /* mark all colormaps on this screen */ - pLink = pScreenPriv->maps; - while(pLink) { - pColPriv = (CMapColormapPtr)dixLookupPrivate(&pLink->cmap->devPrivates, - CMapColormapKey); - pColPriv->recalculate = TRUE; - pLink = pLink->next; - } - - if(GetInstalledmiColormap(pScreen) && - ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || - pScrn->vtSema || pScreenPriv->isDGAmode)) { - ColormapPtr pMap = GetInstalledmiColormap(pScreen); - - if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && - (pMap->pVisual->class == TrueColor) && - CMapColormapUseMax(pMap->pVisual, pScreenPriv)) { - - /* if the current map doesn't have a palette look - for another map to change the gamma on. */ - - pLink = pScreenPriv->maps; - while(pLink) { - if(pLink->cmap->pVisual->class == PseudoColor) - break; - pLink = pLink->next; - } - - if(pLink) { - /* need to trick CMapRefreshColors() into thinking - this is the currently installed map */ - SetInstalledmiColormap(pScreen, pLink->cmap); - CMapReinstallMap(pLink->cmap); - SetInstalledmiColormap(pScreen, pMap); - } - } else - CMapReinstallMap(pMap); - } - - pScrn->ChangeGamma = pScreenPriv->ChangeGamma; - if (pScrn->ChangeGamma) - ret = pScrn->ChangeGamma(index, gamma); - pScrn->ChangeGamma = CMapChangeGamma; - - return ret; -} - - -static void -ComputeGammaRamp ( - CMapScreenPtr priv, - unsigned short *red, - unsigned short *green, - unsigned short *blue -){ - int elements = priv->gammaElements; - LOCO *entry = priv->gamma; - int shift = 16 - priv->sigRGBbits; - - while(elements--) { - entry->red = *(red++) >> shift; - entry->green = *(green++) >> shift; - entry->blue = *(blue++) >> shift; - entry++; - } -} - -int -xf86ChangeGammaRamp( - ScreenPtr pScreen, - int size, - unsigned short *red, - unsigned short *green, - unsigned short *blue -){ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - CMapColormapPtr pColPriv; - CMapScreenPtr pScreenPriv; - CMapLinkPtr pLink; - - if (xf86_crtc_supports_gamma(pScrn)) { - RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn); - - if (crtc) { - if (crtc->gammaSize != size) - return BadValue; - - RRCrtcGammaSet(crtc, red, green, blue); - - return Success; - } - } - - if(CMapScreenKey == NULL) - return BadImplementation; - - pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - CMapScreenKey); - if(!pScreenPriv) - return BadImplementation; - - if(pScreenPriv->gammaElements != size) - return BadValue; - - ComputeGammaRamp(pScreenPriv, red, green, blue); - - /* mark all colormaps on this screen */ - pLink = pScreenPriv->maps; - while(pLink) { - pColPriv = (CMapColormapPtr)dixLookupPrivate(&pLink->cmap->devPrivates, - CMapColormapKey); - pColPriv->recalculate = TRUE; - pLink = pLink->next; - } - - if(GetInstalledmiColormap(pScreen) && - ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || - pScrn->vtSema || pScreenPriv->isDGAmode)) { - ColormapPtr pMap = GetInstalledmiColormap(pScreen); - - if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && - (pMap->pVisual->class == TrueColor) && - CMapColormapUseMax(pMap->pVisual, pScreenPriv)) { - - /* if the current map doesn't have a palette look - for another map to change the gamma on. */ - - pLink = pScreenPriv->maps; - while(pLink) { - if(pLink->cmap->pVisual->class == PseudoColor) - break; - pLink = pLink->next; - } - - if(pLink) { - /* need to trick CMapRefreshColors() into thinking - this is the currently installed map */ - SetInstalledmiColormap(pScreen, pLink->cmap); - CMapReinstallMap(pLink->cmap); - SetInstalledmiColormap(pScreen, pMap); - } - } else - CMapReinstallMap(pMap); - } - - return Success; -} - -int -xf86GetGammaRampSize(ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - CMapScreenPtr pScreenPriv; - - if (xf86_crtc_supports_gamma(pScrn)) { - RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn); - - if (crtc) - return crtc->gammaSize; - } - - if(CMapScreenKey == NULL) return 0; - - pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - CMapScreenKey); - if(!pScreenPriv) return 0; - - return pScreenPriv->gammaElements; -} - -int -xf86GetGammaRamp( - ScreenPtr pScreen, - int size, - unsigned short *red, - unsigned short *green, - unsigned short *blue -){ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - CMapScreenPtr pScreenPriv; - LOCO *entry; - int shift, sigbits; - - if (xf86_crtc_supports_gamma(pScrn)) { - RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn); - - if (crtc) { - if (crtc->gammaSize < size) - return BadValue; - - if (!RRCrtcGammaGet(crtc)) - return BadImplementation; - - memcpy(red, crtc->gammaRed, size * sizeof(*red)); - memcpy(green, crtc->gammaGreen, size * sizeof(*green)); - memcpy(blue, crtc->gammaBlue, size * sizeof(*blue)); - - return Success; - } - } - - if(CMapScreenKey == NULL) - return BadImplementation; - - pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - CMapScreenKey); - if(!pScreenPriv) - return BadImplementation; - - if(size > pScreenPriv->gammaElements) - return BadValue; - - entry = pScreenPriv->gamma; - sigbits = pScreenPriv->sigRGBbits; - - while(size--) { - *red = entry->red << (16 - sigbits); - *green = entry->green << (16 - sigbits); - *blue = entry->blue << (16 - sigbits); - shift = sigbits; - while(shift < 16) { - *red |= *red >> shift; - *green |= *green >> shift; - *blue |= *blue >> shift; - shift += sigbits; - } - red++; green++; blue++; - entry++; - } - - return Success; -} - -int -xf86ChangeGamma( - ScreenPtr pScreen, - Gamma gamma -){ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - - if(pScrn->ChangeGamma) - return (*pScrn->ChangeGamma)(pScreen->myNum, gamma); - - return BadImplementation; -} +/* + * Copyright (c) 1998-2001 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#if defined(_XOPEN_SOURCE) || defined(sun) && defined(__SVR4) +#include <math.h> +#else +#define _XOPEN_SOURCE /* to get prototype for pow on some systems */ +#include <math.h> +#undef _XOPEN_SOURCE +#endif + +#include <X11/X.h> +#include "misc.h" +#include <X11/Xproto.h> +#include "colormapst.h" +#include "scrnintstr.h" + +#include "resource.h" + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86str.h" +#include "micmap.h" +#include "xf86Crtc.h" + +#ifdef XFreeXDGA +#include <X11/extensions/xf86dgaproto.h> +#include "dgaproc.h" +#endif + +#include "xf86cmap.h" + +#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \ + ((CMapScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, CMapScreenKey))->field) +#define SCREEN_EPILOGUE(pScreen, field, wrapper)\ + ((pScreen)->field = wrapper) + +#define LOAD_PALETTE(pmap) \ + ((pmap == GetInstalledmiColormap(pmap->pScreen)) && \ + ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || \ + xf86Screens[pmap->pScreen->myNum]->vtSema || pScreenPriv->isDGAmode)) + + +typedef struct _CMapLink { + ColormapPtr cmap; + struct _CMapLink *next; +} CMapLink, *CMapLinkPtr; + +typedef struct { + ScrnInfoPtr pScrn; + CloseScreenProcPtr CloseScreen; + CreateColormapProcPtr CreateColormap; + DestroyColormapProcPtr DestroyColormap; + InstallColormapProcPtr InstallColormap; + StoreColorsProcPtr StoreColors; + Bool (*EnterVT)(int, int); + Bool (*SwitchMode)(int, DisplayModePtr, int); + int (*SetDGAMode)(int, int, DGADevicePtr); + xf86ChangeGammaProc *ChangeGamma; + int maxColors; + int sigRGBbits; + int gammaElements; + LOCO *gamma; + int *PreAllocIndices; + CMapLinkPtr maps; + unsigned int flags; + Bool isDGAmode; +} CMapScreenRec, *CMapScreenPtr; + +typedef struct { + int numColors; + LOCO *colors; + Bool recalculate; + int overscan; +} CMapColormapRec, *CMapColormapPtr; + +static int CMapScreenKeyIndex; +static DevPrivateKey CMapScreenKey; +static int CMapColormapKeyIndex; +static DevPrivateKey CMapColormapKey = &CMapColormapKeyIndex; + +static void CMapInstallColormap(ColormapPtr); +static void CMapStoreColors(ColormapPtr, int, xColorItem *); +static Bool CMapCloseScreen (int, ScreenPtr); +static Bool CMapCreateColormap (ColormapPtr); +static void CMapDestroyColormap (ColormapPtr); + +static Bool CMapEnterVT(int, int); +static Bool CMapSwitchMode(int, DisplayModePtr, int); +#ifdef XFreeXDGA +static int CMapSetDGAMode(int, int, DGADevicePtr); +#endif +static int CMapChangeGamma(int, Gamma); + +static void ComputeGamma(CMapScreenPtr); +static Bool CMapAllocateColormapPrivate(ColormapPtr); +static void CMapRefreshColors(ColormapPtr, int, int*); +static void CMapSetOverscan(ColormapPtr, int, int *); +static void CMapReinstallMap(ColormapPtr); +static void CMapUnwrapScreen(ScreenPtr pScreen); + + + +Bool xf86HandleColormaps( + ScreenPtr pScreen, + int maxColors, + int sigRGBbits, + xf86LoadPaletteProc *loadPalette, + xf86SetOverscanProc *setOverscan, + unsigned int flags +){ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + ColormapPtr pDefMap = NULL; + CMapScreenPtr pScreenPriv; + LOCO *gamma; + int *indices; + int elements; + + /* If we support a better colormap system, then pretend we succeeded. */ + if (xf86_crtc_supports_gamma(pScrn)) + return TRUE; + + if(!maxColors || !sigRGBbits || !loadPalette) + return FALSE; + + CMapScreenKey = &CMapScreenKeyIndex; + + elements = 1 << sigRGBbits; + + if(!(gamma = malloc(elements * sizeof(LOCO)))) + return FALSE; + + if(!(indices = malloc(maxColors * sizeof(int)))) { + free(gamma); + return FALSE; + } + + if(!(pScreenPriv = malloc(sizeof(CMapScreenRec)))) { + free(gamma); + free(indices); + return FALSE; + } + + dixSetPrivate(&pScreen->devPrivates, CMapScreenKey, pScreenPriv); + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreenPriv->CreateColormap = pScreen->CreateColormap; + pScreenPriv->DestroyColormap = pScreen->DestroyColormap; + pScreenPriv->InstallColormap = pScreen->InstallColormap; + pScreenPriv->StoreColors = pScreen->StoreColors; + pScreen->CloseScreen = CMapCloseScreen; + pScreen->CreateColormap = CMapCreateColormap; + pScreen->DestroyColormap = CMapDestroyColormap; + pScreen->InstallColormap = CMapInstallColormap; + pScreen->StoreColors = CMapStoreColors; + + pScreenPriv->pScrn = pScrn; + pScrn->LoadPalette = loadPalette; + pScrn->SetOverscan = setOverscan; + pScreenPriv->maxColors = maxColors; + pScreenPriv->sigRGBbits = sigRGBbits; + pScreenPriv->gammaElements = elements; + pScreenPriv->gamma = gamma; + pScreenPriv->PreAllocIndices = indices; + pScreenPriv->maps = NULL; + pScreenPriv->flags = flags; + pScreenPriv->isDGAmode = FALSE; + + pScreenPriv->EnterVT = pScrn->EnterVT; + pScreenPriv->SwitchMode = pScrn->SwitchMode; + pScreenPriv->SetDGAMode = pScrn->SetDGAMode; + pScreenPriv->ChangeGamma = pScrn->ChangeGamma; + + if (!(flags & CMAP_LOAD_EVEN_IF_OFFSCREEN)) { + pScrn->EnterVT = CMapEnterVT; + if ((flags & CMAP_RELOAD_ON_MODE_SWITCH) && pScrn->SwitchMode) + pScrn->SwitchMode = CMapSwitchMode; + } +#ifdef XFreeXDGA + pScrn->SetDGAMode = CMapSetDGAMode; +#endif + pScrn->ChangeGamma = CMapChangeGamma; + + ComputeGamma(pScreenPriv); + + /* get the default map */ + dixLookupResourceByType((pointer *)&pDefMap, pScreen->defColormap, + RT_COLORMAP, serverClient, DixInstallAccess); + + if(!CMapAllocateColormapPrivate(pDefMap)) { + CMapUnwrapScreen(pScreen); + return FALSE; + } + + /* Force the initial map to be loaded */ + SetInstalledmiColormap(pScreen, NULL); + CMapInstallColormap(pDefMap); + return TRUE; +} + + +/**** Screen functions ****/ + + +static Bool +CMapCloseScreen (int i, ScreenPtr pScreen) +{ + CMapUnwrapScreen(pScreen); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static Bool +CMapColormapUseMax(VisualPtr pVisual, CMapScreenPtr pScreenPriv) +{ + if (pVisual->nplanes > 16) + return TRUE; + return ((1 << pVisual->nplanes) > pScreenPriv->maxColors); +} + +static Bool +CMapAllocateColormapPrivate(ColormapPtr pmap) +{ + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pmap->pScreen->devPrivates, CMapScreenKey); + CMapColormapPtr pColPriv; + CMapLinkPtr pLink; + int numColors; + LOCO *colors; + + if (CMapColormapUseMax(pmap->pVisual, pScreenPriv)) + numColors = pmap->pVisual->ColormapEntries; + else + numColors = 1 << pmap->pVisual->nplanes; + + if(!(colors = malloc(numColors * sizeof(LOCO)))) + return FALSE; + + if(!(pColPriv = malloc(sizeof(CMapColormapRec)))) { + free(colors); + return FALSE; + } + + dixSetPrivate(&pmap->devPrivates, CMapColormapKey, pColPriv); + + pColPriv->numColors = numColors; + pColPriv->colors = colors; + pColPriv->recalculate = TRUE; + pColPriv->overscan = -1; + + /* add map to list */ + pLink = malloc(sizeof(CMapLink)); + if(pLink) { + pLink->cmap = pmap; + pLink->next = pScreenPriv->maps; + pScreenPriv->maps = pLink; + } + + return TRUE; +} + +static Bool +CMapCreateColormap (ColormapPtr pmap) +{ + ScreenPtr pScreen = pmap->pScreen; + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, CMapScreenKey); + Bool ret = FALSE; + + pScreen->CreateColormap = pScreenPriv->CreateColormap; + if((*pScreen->CreateColormap)(pmap)) { + if(CMapAllocateColormapPrivate(pmap)) + ret = TRUE; + } + pScreen->CreateColormap = CMapCreateColormap; + + return ret; +} + +static void +CMapDestroyColormap (ColormapPtr cmap) +{ + ScreenPtr pScreen = cmap->pScreen; + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, CMapScreenKey); + CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate( + &cmap->devPrivates, CMapColormapKey); + CMapLinkPtr prevLink = NULL, pLink = pScreenPriv->maps; + + if(pColPriv) { + if(pColPriv->colors) free(pColPriv->colors); + free(pColPriv); + } + + /* remove map from list */ + while(pLink) { + if(pLink->cmap == cmap) { + if(prevLink) + prevLink->next = pLink->next; + else + pScreenPriv->maps = pLink->next; + free(pLink); + break; + } + prevLink = pLink; + pLink = pLink->next; + } + + if(pScreenPriv->DestroyColormap) { + pScreen->DestroyColormap = pScreenPriv->DestroyColormap; + (*pScreen->DestroyColormap)(cmap); + pScreen->DestroyColormap = CMapDestroyColormap; + } +} + + + +static void +CMapStoreColors( + ColormapPtr pmap, + int ndef, + xColorItem *pdefs +){ + ScreenPtr pScreen = pmap->pScreen; + VisualPtr pVisual = pmap->pVisual; + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, CMapScreenKey); + int *indices = pScreenPriv->PreAllocIndices; + int num = ndef; + + /* At the moment this isn't necessary since there's nobody below us */ + pScreen->StoreColors = pScreenPriv->StoreColors; + (*pScreen->StoreColors)(pmap, ndef, pdefs); + pScreen->StoreColors = CMapStoreColors; + + /* should never get here for these */ + if( (pVisual->class == TrueColor) || + (pVisual->class == StaticColor) || + (pVisual->class == StaticGray)) + return; + + if(pVisual->class == DirectColor) { + CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate( + &pmap->devPrivates, CMapColormapKey); + int i; + + if (CMapColormapUseMax(pVisual, pScreenPriv)) { + int index; + + num = 0; + while(ndef--) { + if(pdefs[ndef].flags & DoRed) { + index = (pdefs[ndef].pixel & pVisual->redMask) >> + pVisual->offsetRed; + i = num; + while(i--) + if(indices[i] == index) break; + if(i == -1) + indices[num++] = index; + } + if(pdefs[ndef].flags & DoGreen) { + index = (pdefs[ndef].pixel & pVisual->greenMask) >> + pVisual->offsetGreen; + i = num; + while(i--) + if(indices[i] == index) break; + if(i == -1) + indices[num++] = index; + } + if(pdefs[ndef].flags & DoBlue) { + index = (pdefs[ndef].pixel & pVisual->blueMask) >> + pVisual->offsetBlue; + i = num; + while(i--) + if(indices[i] == index) break; + if(i == -1) + indices[num++] = index; + } + } + + } else { + /* not really as overkill as it seems */ + num = pColPriv->numColors; + for(i = 0; i < pColPriv->numColors; i++) + indices[i] = i; + } + } else { + while(ndef--) + indices[ndef] = pdefs[ndef].pixel; + } + + CMapRefreshColors(pmap, num, indices); +} + + +static void +CMapInstallColormap(ColormapPtr pmap) +{ + ScreenPtr pScreen = pmap->pScreen; + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, CMapScreenKey); + + if (pmap == GetInstalledmiColormap(pmap->pScreen)) + return; + + pScreen->InstallColormap = pScreenPriv->InstallColormap; + (*pScreen->InstallColormap)(pmap); + pScreen->InstallColormap = CMapInstallColormap; + + /* Important. We let the lower layers, namely DGA, + overwrite the choice of Colormap to install */ + if (GetInstalledmiColormap(pmap->pScreen)) + pmap = GetInstalledmiColormap(pmap->pScreen); + + if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && + (pmap->pVisual->class == TrueColor) && + CMapColormapUseMax(pmap->pVisual, pScreenPriv)) + return; + + if(LOAD_PALETTE(pmap)) + CMapReinstallMap(pmap); +} + + +/**** ScrnInfoRec functions ****/ + +static Bool +CMapEnterVT(int index, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, CMapScreenKey); + + if((*pScreenPriv->EnterVT)(index, flags)) { + if(GetInstalledmiColormap(pScreen)) + CMapReinstallMap(GetInstalledmiColormap(pScreen)); + return TRUE; + } + return FALSE; +} + + +static Bool +CMapSwitchMode(int index, DisplayModePtr mode, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, CMapScreenKey); + + if((*pScreenPriv->SwitchMode)(index, mode, flags)) { + if(GetInstalledmiColormap(pScreen)) + CMapReinstallMap(GetInstalledmiColormap(pScreen)); + return TRUE; + } + return FALSE; +} + +#ifdef XFreeXDGA +static int +CMapSetDGAMode(int index, int num, DGADevicePtr dev) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, CMapScreenKey); + int ret; + + ret = (*pScreenPriv->SetDGAMode)(index, num, dev); + + pScreenPriv->isDGAmode = DGAActive(index); + + if(!pScreenPriv->isDGAmode && GetInstalledmiColormap(pScreen) + && xf86Screens[pScreen->myNum]->vtSema) + CMapReinstallMap(GetInstalledmiColormap(pScreen)); + + return ret; +} +#endif + + +/**** Utilities ****/ + +static void +CMapReinstallMap(ColormapPtr pmap) +{ + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pmap->pScreen->devPrivates, CMapScreenKey); + CMapColormapPtr cmapPriv = (CMapColormapPtr)dixLookupPrivate( + &pmap->devPrivates, CMapColormapKey); + ScrnInfoPtr pScrn = xf86Screens[pmap->pScreen->myNum]; + int i = cmapPriv->numColors; + int *indices = pScreenPriv->PreAllocIndices; + + while(i--) + indices[i] = i; + + if(cmapPriv->recalculate) + CMapRefreshColors(pmap, cmapPriv->numColors, indices); + else { + (*pScrn->LoadPalette)(pScrn, cmapPriv->numColors, + indices, cmapPriv->colors, pmap->pVisual); + if (pScrn->SetOverscan) { +#ifdef DEBUGOVERSCAN + ErrorF("SetOverscan() called from CMapReinstallMap\n"); +#endif + pScrn->SetOverscan(pScrn, cmapPriv->overscan); + } + } + + cmapPriv->recalculate = FALSE; +} + + +static void +CMapRefreshColors(ColormapPtr pmap, int defs, int* indices) +{ + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pmap->pScreen->devPrivates, CMapScreenKey); + CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate( + &pmap->devPrivates, CMapColormapKey); + VisualPtr pVisual = pmap->pVisual; + ScrnInfoPtr pScrn = xf86Screens[pmap->pScreen->myNum]; + int numColors, i; + LOCO *gamma, *colors; + EntryPtr entry; + int reds, greens, blues, maxValue, index, shift; + + numColors = pColPriv->numColors; + shift = 16 - pScreenPriv->sigRGBbits; + maxValue = (1 << pScreenPriv->sigRGBbits) - 1; + gamma = pScreenPriv->gamma; + colors = pColPriv->colors; + + reds = pVisual->redMask >> pVisual->offsetRed; + greens = pVisual->greenMask >> pVisual->offsetGreen; + blues = pVisual->blueMask >> pVisual->offsetBlue; + + switch(pVisual->class) { + case StaticGray: + for(i = 0; i < numColors; i++) { + index = (i+1) * maxValue / numColors; + colors[i].red = gamma[index].red; + colors[i].green = gamma[index].green; + colors[i].blue = gamma[index].blue; + } + break; + case TrueColor: + if (CMapColormapUseMax(pVisual, pScreenPriv)) { + for(i = 0; i <= reds; i++) + colors[i].red = gamma[i * maxValue / reds].red; + for(i = 0; i <= greens; i++) + colors[i].green = gamma[i * maxValue / greens].green; + for(i = 0; i <= blues; i++) + colors[i].blue = gamma[i * maxValue / blues].blue; + break; + } + for(i = 0; i < numColors; i++) { + colors[i].red = gamma[((i >> pVisual->offsetRed) & reds) * + maxValue / reds].red; + colors[i].green = gamma[((i >> pVisual->offsetGreen) & greens) * + maxValue / greens].green; + colors[i].blue = gamma[((i >> pVisual->offsetBlue) & blues) * + maxValue / blues].blue; + } + break; + case StaticColor: + case PseudoColor: + case GrayScale: + for(i = 0; i < defs; i++) { + index = indices[i]; + entry = (EntryPtr)&pmap->red[index]; + + if(entry->fShared) { + colors[index].red = + gamma[entry->co.shco.red->color >> shift].red; + colors[index].green = + gamma[entry->co.shco.green->color >> shift].green; + colors[index].blue = + gamma[entry->co.shco.blue->color >> shift].blue; + } else { + colors[index].red = + gamma[entry->co.local.red >> shift].red; + colors[index].green = + gamma[entry->co.local.green >> shift].green; + colors[index].blue = + gamma[entry->co.local.blue >> shift].blue; + } + } + break; + case DirectColor: + if (CMapColormapUseMax(pVisual, pScreenPriv)) { + for(i = 0; i < defs; i++) { + index = indices[i]; + if(index <= reds) + colors[index].red = + gamma[pmap->red[index].co.local.red >> shift].red; + if(index <= greens) + colors[index].green = + gamma[pmap->green[index].co.local.green >> shift].green; + if(index <= blues) + colors[index].blue = + gamma[pmap->blue[index].co.local.blue >> shift].blue; + + } + break; + } + for(i = 0; i < defs; i++) { + index = indices[i]; + + colors[index].red = gamma[pmap->red[ + (index >> pVisual->offsetRed) & reds + ].co.local.red >> shift].red; + colors[index].green = gamma[pmap->green[ + (index >> pVisual->offsetGreen) & greens + ].co.local.green >> shift].green; + colors[index].blue = gamma[pmap->blue[ + (index >> pVisual->offsetBlue) & blues + ].co.local.blue >> shift].blue; + } + break; + } + + + if(LOAD_PALETTE(pmap)) + (*pScrn->LoadPalette)(pScreenPriv->pScrn, defs, indices, + colors, pmap->pVisual); + + if (pScrn->SetOverscan) + CMapSetOverscan(pmap, defs, indices); + +} + +static Bool +CMapCompareColors(LOCO *color1, LOCO *color2) +{ + /* return TRUE if the color1 is "closer" to black than color2 */ +#ifdef DEBUGOVERSCAN + ErrorF("#%02x%02x%02x vs #%02x%02x%02x (%d vs %d)\n", + color1->red, color1->green, color1->blue, + color2->red, color2->green, color2->blue, + color1->red + color1->green + color1->blue, + color2->red + color2->green + color2->blue); +#endif + return (color1->red + color1->green + color1->blue < + color2->red + color2->green + color2->blue); +} + +static void +CMapSetOverscan(ColormapPtr pmap, int defs, int *indices) +{ + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pmap->pScreen->devPrivates, CMapScreenKey); + CMapColormapPtr pColPriv = (CMapColormapPtr)dixLookupPrivate( + &pmap->devPrivates, CMapColormapKey); + ScrnInfoPtr pScrn = xf86Screens[pmap->pScreen->myNum]; + VisualPtr pVisual = pmap->pVisual; + int i; + LOCO *colors; + int index; + Bool newOverscan = FALSE; + int overscan, tmpOverscan; + + colors = pColPriv->colors; + overscan = pColPriv->overscan; + + /* + * Search for a new overscan index in the following cases: + * + * - The index hasn't yet been initialised.  In this case search + * for an index that is black or a close match to black. + * + * - The colour of the old index is changed. In this case search + * all indices for a black or close match to black. + * + * - The colour of the old index wasn't black. In this case only + * search the indices that were changed for a better match to black. + */ + + switch (pVisual->class) { + case StaticGray: + case TrueColor: + /* Should only come here once. Initialise the overscan index to 0 */ + overscan = 0; + newOverscan = TRUE; + break; + case StaticColor: + /* + * Only come here once, but search for the overscan in the same way + * as for the other cases. + */ + case DirectColor: + case PseudoColor: + case GrayScale: + if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) { + /* Uninitialised */ + newOverscan = TRUE; + } else { + /* Check if the overscan was changed */ + for (i = 0; i < defs; i++) { + index = indices[i]; + if (index == overscan) { + newOverscan = TRUE; + break; + } + } + } + if (newOverscan) { + /* The overscan is either uninitialised or it has been changed */ + + if (overscan < 0 || overscan > pScreenPriv->maxColors - 1) + tmpOverscan = pScreenPriv->maxColors - 1; + else + tmpOverscan = overscan; + + /* search all entries for a close match to black */ + for (i = pScreenPriv->maxColors - 1; i >= 0; i--) { + if (colors[i].red == 0 && colors[i].green == 0 && + colors[i].blue == 0) { + overscan = i; +#ifdef DEBUGOVERSCAN + ErrorF("Black found at index 0x%02x\n", i); +#endif + break; + } else { +#ifdef DEBUGOVERSCAN + ErrorF("0x%02x: ", i); +#endif + if (CMapCompareColors(&colors[i], &colors[tmpOverscan])) { + tmpOverscan = i; +#ifdef DEBUGOVERSCAN + ErrorF("possible \"Black\" at index 0x%02x\n", i); +#endif + } + } + } + if (i < 0) + overscan = tmpOverscan; + } else { + /* Check of the old overscan wasn't black */ + if (colors[overscan].red != 0 || colors[overscan].green != 0 || + colors[overscan].blue != 0) { + int oldOverscan = tmpOverscan = overscan; + /* See of there is now a better match */ + for (i = 0; i < defs; i++) { + index = indices[i]; + if (colors[index].red == 0 && colors[index].green == 0 && + colors[index].blue == 0) { + overscan = index; +#ifdef DEBUGOVERSCAN + ErrorF("Black found at index 0x%02x\n", index); +#endif + break; + } else { +#ifdef DEBUGOVERSCAN + ErrorF("0x%02x: ", index); +#endif + if (CMapCompareColors(&colors[index], + &colors[tmpOverscan])) { + tmpOverscan = index; +#ifdef DEBUGOVERSCAN + ErrorF("possible \"Black\" at index 0x%02x\n", + index); +#endif + } + } + } + if (i == defs) + overscan = tmpOverscan; + if (overscan != oldOverscan) + newOverscan = TRUE; + } + } + break; + } + if (newOverscan) { + pColPriv->overscan = overscan; + if (LOAD_PALETTE(pmap)) { +#ifdef DEBUGOVERSCAN + ErrorF("SetOverscan() called from CmapSetOverscan\n"); +#endif + pScrn->SetOverscan(pScreenPriv->pScrn, overscan); + } + } +} + +static void +CMapUnwrapScreen(ScreenPtr pScreen) +{ + CMapScreenPtr pScreenPriv = (CMapScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, CMapScreenKey); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->CreateColormap = pScreenPriv->CreateColormap; + pScreen->DestroyColormap = pScreenPriv->DestroyColormap; + pScreen->InstallColormap = pScreenPriv->InstallColormap; + pScreen->StoreColors = pScreenPriv->StoreColors; + + pScrn->EnterVT = pScreenPriv->EnterVT; + pScrn->SwitchMode = pScreenPriv->SwitchMode; + pScrn->SetDGAMode = pScreenPriv->SetDGAMode; + pScrn->ChangeGamma = pScreenPriv->ChangeGamma; + + free(pScreenPriv->gamma); + free(pScreenPriv->PreAllocIndices); + free(pScreenPriv); +} + + +static void +ComputeGamma(CMapScreenPtr priv) +{ + int elements = priv->gammaElements - 1; + double RedGamma, GreenGamma, BlueGamma; + int i; + +#ifndef DONT_CHECK_GAMMA + /* This check is to catch drivers that are not initialising pScrn->gamma */ + if (priv->pScrn->gamma.red < GAMMA_MIN || + priv->pScrn->gamma.red > GAMMA_MAX || + priv->pScrn->gamma.green < GAMMA_MIN || + priv->pScrn->gamma.green > GAMMA_MAX || + priv->pScrn->gamma.blue < GAMMA_MIN || + priv->pScrn->gamma.blue > GAMMA_MAX) { + + xf86DrvMsgVerb(priv->pScrn->scrnIndex, X_WARNING, 0, + "The %s driver didn't call xf86SetGamma() to initialise\n" + "\tthe gamma values.\n", priv->pScrn->driverName); + xf86DrvMsgVerb(priv->pScrn->scrnIndex, X_WARNING, 0, + "PLEASE FIX THE `%s' DRIVER!\n", priv->pScrn->driverName); + priv->pScrn->gamma.red = 1.0; + priv->pScrn->gamma.green = 1.0; + priv->pScrn->gamma.blue = 1.0; + } +#endif + + RedGamma = 1.0 / (double)priv->pScrn->gamma.red; + GreenGamma = 1.0 / (double)priv->pScrn->gamma.green; + BlueGamma = 1.0 / (double)priv->pScrn->gamma.blue; + + for(i = 0; i <= elements; i++) { + if(RedGamma == 1.0) + priv->gamma[i].red = i; + else + priv->gamma[i].red = (CARD16)(pow((double)i/(double)elements, + RedGamma) * (double)elements + 0.5); + + if(GreenGamma == 1.0) + priv->gamma[i].green = i; + else + priv->gamma[i].green = (CARD16)(pow((double)i/(double)elements, + GreenGamma) * (double)elements + 0.5); + + if(BlueGamma == 1.0) + priv->gamma[i].blue = i; + else + priv->gamma[i].blue = (CARD16)(pow((double)i/(double)elements, + BlueGamma) * (double)elements + 0.5); + } +} + + +int +CMapChangeGamma( + int index, + Gamma gamma +){ + int ret = Success; + ScrnInfoPtr pScrn = xf86Screens[index]; + ScreenPtr pScreen = pScrn->pScreen; + CMapColormapPtr pColPriv; + CMapScreenPtr pScreenPriv; + CMapLinkPtr pLink; + + /* Is this sufficient checking ? */ + if(CMapScreenKey == NULL) + return BadImplementation; + + pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + CMapScreenKey); + if(!pScreenPriv) + return BadImplementation; + + if (gamma.red < GAMMA_MIN || gamma.red > GAMMA_MAX || + gamma.green < GAMMA_MIN || gamma.green > GAMMA_MAX || + gamma.blue < GAMMA_MIN || gamma.blue > GAMMA_MAX) + return BadValue; + + pScrn->gamma.red = gamma.red; + pScrn->gamma.green = gamma.green; + pScrn->gamma.blue = gamma.blue; + + ComputeGamma(pScreenPriv); + + /* mark all colormaps on this screen */ + pLink = pScreenPriv->maps; + while(pLink) { + pColPriv = (CMapColormapPtr)dixLookupPrivate(&pLink->cmap->devPrivates, + CMapColormapKey); + pColPriv->recalculate = TRUE; + pLink = pLink->next; + } + + if(GetInstalledmiColormap(pScreen) && + ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || + pScrn->vtSema || pScreenPriv->isDGAmode)) { + ColormapPtr pMap = GetInstalledmiColormap(pScreen); + + if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && + (pMap->pVisual->class == TrueColor) && + CMapColormapUseMax(pMap->pVisual, pScreenPriv)) { + + /* if the current map doesn't have a palette look + for another map to change the gamma on. */ + + pLink = pScreenPriv->maps; + while(pLink) { + if(pLink->cmap->pVisual->class == PseudoColor) + break; + pLink = pLink->next; + } + + if(pLink) { + /* need to trick CMapRefreshColors() into thinking + this is the currently installed map */ + SetInstalledmiColormap(pScreen, pLink->cmap); + CMapReinstallMap(pLink->cmap); + SetInstalledmiColormap(pScreen, pMap); + } + } else + CMapReinstallMap(pMap); + } + + pScrn->ChangeGamma = pScreenPriv->ChangeGamma; + if (pScrn->ChangeGamma) + ret = pScrn->ChangeGamma(index, gamma); + pScrn->ChangeGamma = CMapChangeGamma; + + return ret; +} + + +static void +ComputeGammaRamp ( + CMapScreenPtr priv, + unsigned short *red, + unsigned short *green, + unsigned short *blue +){ + int elements = priv->gammaElements; + LOCO *entry = priv->gamma; + int shift = 16 - priv->sigRGBbits; + + while(elements--) { + entry->red = *(red++) >> shift; + entry->green = *(green++) >> shift; + entry->blue = *(blue++) >> shift; + entry++; + } +} + +int +xf86ChangeGammaRamp( + ScreenPtr pScreen, + int size, + unsigned short *red, + unsigned short *green, + unsigned short *blue +){ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + CMapColormapPtr pColPriv; + CMapScreenPtr pScreenPriv; + CMapLinkPtr pLink; + + if (xf86_crtc_supports_gamma(pScrn)) { + RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn); + + if (crtc) { + if (crtc->gammaSize != size) + return BadValue; + + RRCrtcGammaSet(crtc, red, green, blue); + + return Success; + } + } + + if(CMapScreenKey == NULL) + return BadImplementation; + + pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + CMapScreenKey); + if(!pScreenPriv) + return BadImplementation; + + if(pScreenPriv->gammaElements != size) + return BadValue; + + ComputeGammaRamp(pScreenPriv, red, green, blue); + + /* mark all colormaps on this screen */ + pLink = pScreenPriv->maps; + while(pLink) { + pColPriv = (CMapColormapPtr)dixLookupPrivate(&pLink->cmap->devPrivates, + CMapColormapKey); + pColPriv->recalculate = TRUE; + pLink = pLink->next; + } + + if(GetInstalledmiColormap(pScreen) && + ((pScreenPriv->flags & CMAP_LOAD_EVEN_IF_OFFSCREEN) || + pScrn->vtSema || pScreenPriv->isDGAmode)) { + ColormapPtr pMap = GetInstalledmiColormap(pScreen); + + if (!(pScreenPriv->flags & CMAP_PALETTED_TRUECOLOR) && + (pMap->pVisual->class == TrueColor) && + CMapColormapUseMax(pMap->pVisual, pScreenPriv)) { + + /* if the current map doesn't have a palette look + for another map to change the gamma on. */ + + pLink = pScreenPriv->maps; + while(pLink) { + if(pLink->cmap->pVisual->class == PseudoColor) + break; + pLink = pLink->next; + } + + if(pLink) { + /* need to trick CMapRefreshColors() into thinking + this is the currently installed map */ + SetInstalledmiColormap(pScreen, pLink->cmap); + CMapReinstallMap(pLink->cmap); + SetInstalledmiColormap(pScreen, pMap); + } + } else + CMapReinstallMap(pMap); + } + + return Success; +} + +int +xf86GetGammaRampSize(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + CMapScreenPtr pScreenPriv; + + if (xf86_crtc_supports_gamma(pScrn)) { + RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn); + + if (crtc) + return crtc->gammaSize; + } + + if(CMapScreenKey == NULL) return 0; + + pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + CMapScreenKey); + if(!pScreenPriv) return 0; + + return pScreenPriv->gammaElements; +} + +int +xf86GetGammaRamp( + ScreenPtr pScreen, + int size, + unsigned short *red, + unsigned short *green, + unsigned short *blue +){ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + CMapScreenPtr pScreenPriv; + LOCO *entry; + int shift, sigbits; + + if (xf86_crtc_supports_gamma(pScrn)) { + RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn); + + if (crtc) { + if (crtc->gammaSize < size) + return BadValue; + + if (!RRCrtcGammaGet(crtc)) + return BadImplementation; + + memcpy(red, crtc->gammaRed, size * sizeof(*red)); + memcpy(green, crtc->gammaGreen, size * sizeof(*green)); + memcpy(blue, crtc->gammaBlue, size * sizeof(*blue)); + + return Success; + } + } + + if(CMapScreenKey == NULL) + return BadImplementation; + + pScreenPriv = (CMapScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + CMapScreenKey); + if(!pScreenPriv) + return BadImplementation; + + if(size > pScreenPriv->gammaElements) + return BadValue; + + entry = pScreenPriv->gamma; + sigbits = pScreenPriv->sigRGBbits; + + while(size--) { + *red = entry->red << (16 - sigbits); + *green = entry->green << (16 - sigbits); + *blue = entry->blue << (16 - sigbits); + shift = sigbits; + while(shift < 16) { + *red |= *red >> shift; + *green |= *green >> shift; + *blue |= *blue >> shift; + shift += sigbits; + } + red++; green++; blue++; + entry++; + } + + return Success; +} + +int +xf86ChangeGamma( + ScreenPtr pScreen, + Gamma gamma +){ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if(pScrn->ChangeGamma) + return (*pScrn->ChangeGamma)(pScreen->myNum, gamma); + + return BadImplementation; +} diff --git a/xorg-server/hw/xfree86/common/xf86fbman.c b/xorg-server/hw/xfree86/common/xf86fbman.c index 5b8871723..1ca27015f 100644 --- a/xorg-server/hw/xfree86/common/xf86fbman.c +++ b/xorg-server/hw/xfree86/common/xf86fbman.c @@ -1,1438 +1,1438 @@ - -/* - * Copyright (c) 1998-2001 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "regionstr.h" -#include "xf86fbman.h" - -/* -#define DEBUG -*/ - -static int xf86FBManagerKeyIndex; -static DevPrivateKey xf86FBManagerKey; - -Bool xf86RegisterOffscreenManager( - ScreenPtr pScreen, - FBManagerFuncsPtr funcs -){ - - xf86FBManagerKey = &xf86FBManagerKeyIndex; - dixSetPrivate(&pScreen->devPrivates, xf86FBManagerKey, funcs); - - return TRUE; -} - - -Bool -xf86FBManagerRunning(ScreenPtr pScreen) -{ - if(xf86FBManagerKey == NULL) - return FALSE; - if(!dixLookupPrivate(&pScreen->devPrivates, xf86FBManagerKey)) - return FALSE; - - return TRUE; -} - -Bool -xf86RegisterFreeBoxCallback( - ScreenPtr pScreen, - FreeBoxCallbackProcPtr FreeBoxCallback, - pointer devPriv -){ - FBManagerFuncsPtr funcs; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return FALSE; - - return (*funcs->RegisterFreeBoxCallback)(pScreen, FreeBoxCallback, devPriv); -} - - -FBAreaPtr -xf86AllocateOffscreenArea( - ScreenPtr pScreen, - int w, int h, - int gran, - MoveAreaCallbackProcPtr moveCB, - RemoveAreaCallbackProcPtr removeCB, - pointer privData -){ - FBManagerFuncsPtr funcs; - - if(xf86FBManagerKey == NULL) - return NULL; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return NULL; - - return (*funcs->AllocateOffscreenArea)( - pScreen, w, h, gran, moveCB, removeCB, privData); -} - - -FBLinearPtr -xf86AllocateOffscreenLinear( - ScreenPtr pScreen, - int length, - int gran, - MoveLinearCallbackProcPtr moveCB, - RemoveLinearCallbackProcPtr removeCB, - pointer privData -){ - FBManagerFuncsPtr funcs; - - if(xf86FBManagerKey == NULL) - return NULL; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return NULL; - - return (*funcs->AllocateOffscreenLinear)( - pScreen, length, gran, moveCB, removeCB, privData); -} - - -void -xf86FreeOffscreenArea(FBAreaPtr area) -{ - FBManagerFuncsPtr funcs; - - if(!area) return; - - if(xf86FBManagerKey == NULL) - return; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( - &area->pScreen->devPrivates, xf86FBManagerKey))) - return; - - (*funcs->FreeOffscreenArea)(area); - - return; -} - - -void -xf86FreeOffscreenLinear(FBLinearPtr linear) -{ - FBManagerFuncsPtr funcs; - - if(!linear) return; - - if(xf86FBManagerKey == NULL) - return; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( - &linear->pScreen->devPrivates, xf86FBManagerKey))) - return; - - (*funcs->FreeOffscreenLinear)(linear); - - return; -} - - -Bool -xf86ResizeOffscreenArea( - FBAreaPtr resize, - int w, int h -){ - FBManagerFuncsPtr funcs; - - if(!resize) return FALSE; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( - &resize->pScreen->devPrivates, xf86FBManagerKey))) - return FALSE; - - return (*funcs->ResizeOffscreenArea)(resize, w, h); -} - -Bool -xf86ResizeOffscreenLinear( - FBLinearPtr resize, - int size -){ - FBManagerFuncsPtr funcs; - - if(!resize) return FALSE; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( - &resize->pScreen->devPrivates, xf86FBManagerKey))) - return FALSE; - - return (*funcs->ResizeOffscreenLinear)(resize, size); -} - - -Bool -xf86QueryLargestOffscreenArea( - ScreenPtr pScreen, - int *w, int *h, - int gran, - int preferences, - int severity -){ - FBManagerFuncsPtr funcs; - - *w = 0; - *h = 0; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return FALSE; - - return (*funcs->QueryLargestOffscreenArea)( - pScreen, w, h, gran, preferences, severity); -} - -Bool -xf86QueryLargestOffscreenLinear( - ScreenPtr pScreen, - int *size, - int gran, - int severity -){ - FBManagerFuncsPtr funcs; - - *size = 0; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return FALSE; - - return (*funcs->QueryLargestOffscreenLinear)( - pScreen, size, gran, severity); -} - - -Bool -xf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen) -{ - FBManagerFuncsPtr funcs; - - if(xf86FBManagerKey == NULL) - return FALSE; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return FALSE; - - return (*funcs->PurgeOffscreenAreas)(pScreen); -} - -/************************************************************\ - - Below is a specific implementation of an offscreen manager. - -\************************************************************/ - -static int xf86FBScreenKeyIndex; -static DevPrivateKey xf86FBScreenKey = &xf86FBScreenKeyIndex; - -typedef struct _FBLink { - FBArea area; - struct _FBLink *next; -} FBLink, *FBLinkPtr; - -typedef struct _FBLinearLink { - FBLinear linear; - int free; /* need to add free here as FBLinear is publicly accessible */ - FBAreaPtr area; /* only used if allocation came from XY area */ - struct _FBLinearLink *next; -} FBLinearLink, *FBLinearLinkPtr; - - -typedef struct { - ScreenPtr pScreen; - RegionPtr InitialBoxes; - RegionPtr FreeBoxes; - FBLinkPtr UsedAreas; - int NumUsedAreas; - FBLinearLinkPtr LinearAreas; - CloseScreenProcPtr CloseScreen; - int NumCallbacks; - FreeBoxCallbackProcPtr *FreeBoxesUpdateCallback; - DevUnion *devPrivates; -} FBManager, *FBManagerPtr; - - -static void -SendCallFreeBoxCallbacks(FBManagerPtr offman) -{ - int i = offman->NumCallbacks; - - while(i--) { - (*offman->FreeBoxesUpdateCallback[i])( - offman->pScreen, offman->FreeBoxes, offman->devPrivates[i].ptr); - } -} - -static Bool -localRegisterFreeBoxCallback( - ScreenPtr pScreen, - FreeBoxCallbackProcPtr FreeBoxCallback, - pointer devPriv -){ - FBManagerPtr offman; - FreeBoxCallbackProcPtr *newCallbacks; - DevUnion *newPrivates; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - newCallbacks = xrealloc( offman->FreeBoxesUpdateCallback, - sizeof(FreeBoxCallbackProcPtr) * (offman->NumCallbacks + 1)); - - newPrivates = xrealloc(offman->devPrivates, - sizeof(DevUnion) * (offman->NumCallbacks + 1)); - - if(!newCallbacks || !newPrivates) - return FALSE; - - offman->FreeBoxesUpdateCallback = newCallbacks; - offman->devPrivates = newPrivates; - - offman->FreeBoxesUpdateCallback[offman->NumCallbacks] = FreeBoxCallback; - offman->devPrivates[offman->NumCallbacks].ptr = devPriv; - offman->NumCallbacks++; - - SendCallFreeBoxCallbacks(offman); - - return TRUE; -} - - -static FBAreaPtr -AllocateArea( - FBManagerPtr offman, - int w, int h, - int granularity, - MoveAreaCallbackProcPtr moveCB, - RemoveAreaCallbackProcPtr removeCB, - pointer privData -){ - ScreenPtr pScreen = offman->pScreen; - FBLinkPtr link = NULL; - FBAreaPtr area = NULL; - RegionRec NewReg; - int i, x = 0, num; - BoxPtr boxp; - - if(granularity <= 1) granularity = 0; - - boxp = REGION_RECTS(offman->FreeBoxes); - num = REGION_NUM_RECTS(offman->FreeBoxes); - - /* look through the free boxes */ - for(i = 0; i < num; i++, boxp++) { - x = boxp->x1; - if (granularity > 1) - x = ((x + granularity - 1) / granularity) * granularity; - - if(((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) - continue; - - link = xalloc(sizeof(FBLink)); - if(!link) return NULL; - - area = &(link->area); - link->next = offman->UsedAreas; - offman->UsedAreas = link; - offman->NumUsedAreas++; - break; - } - - /* try to boot a removeable one out if we are not expendable ourselves */ - if(!area && !removeCB) { - link = offman->UsedAreas; - - while(link) { - if(!link->area.RemoveAreaCallback) { - link = link->next; - continue; - } - - boxp = &(link->area.box); - x = boxp->x1; - if (granularity > 1) - x = ((x + granularity - 1) / granularity) * granularity; - - if(((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) { - link = link->next; - continue; - } - - /* bye, bye */ - (*link->area.RemoveAreaCallback)(&link->area); - REGION_INIT(pScreen, &NewReg, &(link->area.box), 1); - REGION_UNION(pScreen, offman->FreeBoxes, offman->FreeBoxes, &NewReg); - REGION_UNINIT(pScreen, &NewReg); - - area = &(link->area); - break; - } - } - - if(area) { - area->pScreen = pScreen; - area->granularity = granularity; - area->box.x1 = x; - area->box.x2 = x + w; - area->box.y1 = boxp->y1; - area->box.y2 = boxp->y1 + h; - area->MoveAreaCallback = moveCB; - area->RemoveAreaCallback = removeCB; - area->devPrivate.ptr = privData; - - REGION_INIT(pScreen, &NewReg, &(area->box), 1); - REGION_SUBTRACT(pScreen, offman->FreeBoxes, offman->FreeBoxes, &NewReg); - REGION_UNINIT(pScreen, &NewReg); - } - - return area; -} - -static FBAreaPtr -localAllocateOffscreenArea( - ScreenPtr pScreen, - int w, int h, - int gran, - MoveAreaCallbackProcPtr moveCB, - RemoveAreaCallbackProcPtr removeCB, - pointer privData -){ - FBManagerPtr offman; - FBAreaPtr area = NULL; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - if((area = AllocateArea(offman, w, h, gran, moveCB, removeCB, privData))) - SendCallFreeBoxCallbacks(offman); - - return area; -} - - -static void -localFreeOffscreenArea(FBAreaPtr area) -{ - FBManagerPtr offman; - FBLinkPtr pLink, pLinkPrev = NULL; - RegionRec FreedRegion; - ScreenPtr pScreen; - - pScreen = area->pScreen; - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->UsedAreas; - if(!pLink) return; - - while(&(pLink->area) != area) { - pLinkPrev = pLink; - pLink = pLink->next; - if(!pLink) return; - } - - /* put the area back into the pool */ - REGION_INIT(pScreen, &FreedRegion, &(pLink->area.box), 1); - REGION_UNION(pScreen, offman->FreeBoxes, offman->FreeBoxes, &FreedRegion); - REGION_UNINIT(pScreen, &FreedRegion); - - if(pLinkPrev) - pLinkPrev->next = pLink->next; - else offman->UsedAreas = pLink->next; - - xfree(pLink); - offman->NumUsedAreas--; - - SendCallFreeBoxCallbacks(offman); -} - - - -static Bool -localResizeOffscreenArea( - FBAreaPtr resize, - int w, int h -){ - FBManagerPtr offman; - ScreenPtr pScreen; - BoxRec OrigArea; - RegionRec FreedReg; - FBAreaPtr area = NULL; - FBLinkPtr pLink, newLink, pLinkPrev = NULL; - - pScreen = resize->pScreen; - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - /* find this link */ - if(!(pLink = offman->UsedAreas)) - return FALSE; - - while(&(pLink->area) != resize) { - pLinkPrev = pLink; - pLink = pLink->next; - if(!pLink) return FALSE; - } - - OrigArea.x1 = resize->box.x1; - OrigArea.x2 = resize->box.x2; - OrigArea.y1 = resize->box.y1; - OrigArea.y2 = resize->box.y2; - - /* if it's smaller, this is easy */ - - if((w <= (resize->box.x2 - resize->box.x1)) && - (h <= (resize->box.y2 - resize->box.y1))) { - RegionRec NewReg; - - resize->box.x2 = resize->box.x1 + w; - resize->box.y2 = resize->box.y1 + h; - - if((resize->box.y2 == OrigArea.y2) && - (resize->box.x2 == OrigArea.x2)) - return TRUE; - - REGION_INIT(pScreen, &FreedReg, &OrigArea, 1); - REGION_INIT(pScreen, &NewReg, &(resize->box), 1); - REGION_SUBTRACT(pScreen, &FreedReg, &FreedReg, &NewReg); - REGION_UNION(pScreen, offman->FreeBoxes, offman->FreeBoxes, &FreedReg); - REGION_UNINIT(pScreen, &FreedReg); - REGION_UNINIT(pScreen, &NewReg); - - SendCallFreeBoxCallbacks(offman); - - return TRUE; - } - - - /* otherwise we remove the old region */ - - REGION_INIT(pScreen, &FreedReg, &OrigArea, 1); - REGION_UNION(pScreen, offman->FreeBoxes, offman->FreeBoxes, &FreedReg); - - /* remove the old link */ - if(pLinkPrev) - pLinkPrev->next = pLink->next; - else offman->UsedAreas = pLink->next; - - /* and try to add a new one */ - - if((area = AllocateArea(offman, w, h, resize->granularity, - resize->MoveAreaCallback, resize->RemoveAreaCallback, - resize->devPrivate.ptr))) { - - /* copy data over to our link and replace the new with old */ - memcpy(resize, area, sizeof(FBArea)); - - pLinkPrev = NULL; - newLink = offman->UsedAreas; - - while(&(newLink->area) != area) { - pLinkPrev = newLink; - newLink = newLink->next; - } - - if(pLinkPrev) - pLinkPrev->next = newLink->next; - else offman->UsedAreas = newLink->next; - - pLink->next = offman->UsedAreas; - offman->UsedAreas = pLink; - - xfree(newLink); - - /* AllocateArea added one but we really only exchanged one */ - offman->NumUsedAreas--; - } else { - /* reinstate the old region */ - REGION_SUBTRACT(pScreen, offman->FreeBoxes, offman->FreeBoxes, &FreedReg); - REGION_UNINIT(pScreen, &FreedReg); - - pLink->next = offman->UsedAreas; - offman->UsedAreas = pLink; - return FALSE; - } - - - REGION_UNINIT(pScreen, &FreedReg); - - SendCallFreeBoxCallbacks(offman); - - return TRUE; -} - -static Bool -localQueryLargestOffscreenArea( - ScreenPtr pScreen, - int *width, int *height, - int granularity, - int preferences, - int severity -){ - FBManagerPtr offman; - RegionPtr newRegion = NULL; - BoxPtr pbox; - int nbox; - int x, w, h, area, oldArea; - - *width = *height = oldArea = 0; - - if(granularity <= 1) granularity = 0; - - if((preferences < 0) || (preferences > 3)) - return FALSE; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - if(severity < 0) severity = 0; - if(severity > 2) severity = 2; - - switch(severity) { - case 2: - if(offman->NumUsedAreas) { - FBLinkPtr pLink; - RegionRec tmpRegion; - newRegion = REGION_CREATE(pScreen, NULL, 1); - REGION_COPY(pScreen, newRegion, offman->InitialBoxes); - pLink = offman->UsedAreas; - - while(pLink) { - if(!pLink->area.RemoveAreaCallback) { - REGION_INIT(pScreen, &tmpRegion, &(pLink->area.box), 1); - REGION_SUBTRACT(pScreen, newRegion, newRegion, &tmpRegion); - REGION_UNINIT(pScreen, &tmpRegion); - } - pLink = pLink->next; - } - - nbox = REGION_NUM_RECTS(newRegion); - pbox = REGION_RECTS(newRegion); - break; - } - case 1: - if(offman->NumUsedAreas) { - FBLinkPtr pLink; - RegionRec tmpRegion; - newRegion = REGION_CREATE(pScreen, NULL, 1); - REGION_COPY(pScreen, newRegion, offman->FreeBoxes); - pLink = offman->UsedAreas; - - while(pLink) { - if(pLink->area.RemoveAreaCallback) { - REGION_INIT(pScreen, &tmpRegion, &(pLink->area.box), 1); - REGION_APPEND(pScreen, newRegion, &tmpRegion); - REGION_UNINIT(pScreen, &tmpRegion); - } - pLink = pLink->next; - } - - nbox = REGION_NUM_RECTS(newRegion); - pbox = REGION_RECTS(newRegion); - break; - } - default: - nbox = REGION_NUM_RECTS(offman->FreeBoxes); - pbox = REGION_RECTS(offman->FreeBoxes); - break; - } - - while(nbox--) { - x = pbox->x1; - if (granularity > 1) - x = ((x + granularity - 1) / granularity) * granularity; - - w = pbox->x2 - x; - h = pbox->y2 - pbox->y1; - area = w * h; - - if(w > 0) { - Bool gotIt = FALSE; - switch(preferences) { - case FAVOR_AREA_THEN_WIDTH: - if((area > oldArea) || ((area == oldArea) && (w > *width))) - gotIt = TRUE; - break; - case FAVOR_AREA_THEN_HEIGHT: - if((area > oldArea) || ((area == oldArea) && (h > *height))) - gotIt = TRUE; - break; - case FAVOR_WIDTH_THEN_AREA: - if((w > *width) || ((w == *width) && (area > oldArea))) - gotIt = TRUE; - break; - case FAVOR_HEIGHT_THEN_AREA: - if((h > *height) || ((h == *height) && (area > oldArea))) - gotIt = TRUE; - break; - } - if(gotIt) { - *width = w; - *height = h; - oldArea = area; - } - } - pbox++; - } - - if(newRegion) - REGION_DESTROY(pScreen, newRegion); - - return TRUE; -} - -static Bool -localPurgeUnlockedOffscreenAreas(ScreenPtr pScreen) -{ - FBManagerPtr offman; - FBLinkPtr pLink, tmp, pPrev = NULL; - RegionRec FreedRegion; - Bool anyUsed = FALSE; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->UsedAreas; - if(!pLink) return TRUE; - - while(pLink) { - if(pLink->area.RemoveAreaCallback) { - (*pLink->area.RemoveAreaCallback)(&pLink->area); - - REGION_INIT(pScreen, &FreedRegion, &(pLink->area.box), 1); - REGION_APPEND(pScreen, offman->FreeBoxes, &FreedRegion); - REGION_UNINIT(pScreen, &FreedRegion); - - if(pPrev) - pPrev->next = pLink->next; - else offman->UsedAreas = pLink->next; - - tmp = pLink; - pLink = pLink->next; - xfree(tmp); - offman->NumUsedAreas--; - anyUsed = TRUE; - } else { - pPrev = pLink; - pLink = pLink->next; - } - } - - if(anyUsed) { - REGION_VALIDATE(pScreen, offman->FreeBoxes, &anyUsed); - SendCallFreeBoxCallbacks(offman); - } - - return TRUE; -} - -static void -LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to) -{ - /* this will never get called */ -} - -static void -LinearRemoveCBWrapper(FBAreaPtr area) -{ - FBManagerPtr offman; - FBLinearLinkPtr pLink, pLinkPrev = NULL; - ScreenPtr pScreen = area->pScreen; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->LinearAreas; - if(!pLink) return; - - while(pLink->area != area) { - pLinkPrev = pLink; - pLink = pLink->next; - if(!pLink) return; - } - - /* give the user the callback it is expecting */ - (*pLink->linear.RemoveLinearCallback)(&(pLink->linear)); - - if(pLinkPrev) - pLinkPrev->next = pLink->next; - else offman->LinearAreas = pLink->next; - - xfree(pLink); -} - -static void -DumpDebug(FBLinearLinkPtr pLink) -{ -#ifdef DEBUG - if (!pLink) ErrorF("MMmm, PLINK IS NULL!\n"); - - while (pLink) { - ErrorF(" Offset:%08x, Size:%08x, %s,%s\n", - pLink->linear.offset, - pLink->linear.size, - pLink->free ? "Free" : "Used", - pLink->area ? "Area" : "Linear"); - - pLink = pLink->next; - } -#endif -} - -static FBLinearPtr -AllocateLinear( - FBManagerPtr offman, - int size, - int granularity, - pointer privData -){ - ScreenPtr pScreen = offman->pScreen; - FBLinearLinkPtr linear = NULL; - FBLinearLinkPtr newlink = NULL; - int offset, end; - - if(size <= 0) return NULL; - - if (!offman->LinearAreas) return NULL; - - linear = offman->LinearAreas; - while (linear) { - /* Make sure we get a free area that's not an XY fallback case */ - if (!linear->area && linear->free) { - offset = linear->linear.offset; - if (granularity > 1) - offset = ((offset + granularity - 1) / granularity) * granularity; - end = offset+size; - if (end <= (linear->linear.offset + linear->linear.size)) - break; - } - linear = linear->next; - } - if (!linear) - return NULL; - - /* break left */ - if (offset > linear->linear.offset) { - newlink = xalloc(sizeof(FBLinearLink)); - if (!newlink) - return NULL; - newlink->area = NULL; - newlink->linear.offset = offset; - newlink->linear.size = linear->linear.size - (offset - linear->linear.offset); - newlink->free = 1; - newlink->next = linear->next; - linear->linear.size -= newlink->linear.size; - linear->next = newlink; - linear = newlink; - } - - /* break right */ - if (size < linear->linear.size) { - newlink = xalloc(sizeof(FBLinearLink)); - if (!newlink) - return NULL; - newlink->area = NULL; - newlink->linear.offset = offset + size; - newlink->linear.size = linear->linear.size - size; - newlink->free = 1; - newlink->next = linear->next; - linear->linear.size = size; - linear->next = newlink; - } - - /* p = middle block */ - linear->linear.granularity = granularity; - linear->free = 0; - linear->linear.pScreen = pScreen; - linear->linear.MoveLinearCallback = NULL; - linear->linear.RemoveLinearCallback = NULL; - linear->linear.devPrivate.ptr = NULL; - - DumpDebug(offman->LinearAreas); - - return &(linear->linear); -} - -static FBLinearPtr -localAllocateOffscreenLinear( - ScreenPtr pScreen, - int length, - int gran, - MoveLinearCallbackProcPtr moveCB, - RemoveLinearCallbackProcPtr removeCB, - pointer privData -){ - FBManagerPtr offman; - FBLinearLinkPtr link; - FBAreaPtr area; - FBLinearPtr linear = NULL; - BoxPtr extents; - int w, h, pitch; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - - /* Try to allocate from linear memory first...... */ - DebugF("ALLOCATING LINEAR\n"); - if ((linear = AllocateLinear(offman, length, gran, privData))) - return linear; - - DebugF("NOPE, ALLOCATING AREA\n"); - - if(!(link = xalloc(sizeof(FBLinearLink)))) - return NULL; - - /* No linear available, so try and pinch some from the XY areas */ - extents = REGION_EXTENTS(pScreen, offman->InitialBoxes); - pitch = extents->x2 - extents->x1; - - if (gran > 1) { - if (gran > pitch) { - /* we can't match the specified alignment with XY allocations */ - xfree(link); - return NULL; - } - - if (pitch % gran) { - /* pitch and granularity aren't a perfect match, let's allocate - * a bit more so we can align later on - */ - length += gran - 1; - } - } - - if(length < pitch) { /* special case */ - w = length; - h = 1; - } else { - w = pitch; - h = (length + pitch - 1) / pitch; - } - - if((area = localAllocateOffscreenArea(pScreen, w, h, gran, - moveCB ? LinearMoveCBWrapper : NULL, - removeCB ? LinearRemoveCBWrapper : NULL, - privData))) - { - link->area = area; - link->free = 0; - link->next = offman->LinearAreas; - offman->LinearAreas = link; - linear = &(link->linear); - linear->pScreen = pScreen; - linear->size = h * w; - linear->offset = (pitch * area->box.y1) + area->box.x1; - if (gran > 1) - linear->offset = ((linear->offset + gran - 1) / gran) * gran; - linear->granularity = gran; - linear->MoveLinearCallback = moveCB; - linear->RemoveLinearCallback = removeCB; - linear->devPrivate.ptr = privData; - } else - xfree(link); - - DumpDebug(offman->LinearAreas); - - return linear; -} - - -static void -localFreeOffscreenLinear(FBLinearPtr linear) -{ - FBManagerPtr offman; - FBLinearLinkPtr pLink, pLinkPrev = NULL; - ScreenPtr pScreen = linear->pScreen; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->LinearAreas; - if(!pLink) return; - - while(&(pLink->linear) != linear) { - pLinkPrev = pLink; - pLink = pLink->next; - if(!pLink) return; - } - - if(pLink->area) { /* really an XY area */ - DebugF("FREEING AREA\n"); - localFreeOffscreenArea(pLink->area); - if(pLinkPrev) - pLinkPrev->next = pLink->next; - else offman->LinearAreas = pLink->next; - xfree(pLink); - DumpDebug(offman->LinearAreas); - return; - } - - pLink->free = 1; - - if (pLink->next && pLink->next->free) { - FBLinearLinkPtr p = pLink->next; - pLink->linear.size += p->linear.size; - pLink->next = p->next; - free(p); - } - - if(pLinkPrev) { - if (pLinkPrev->next && pLinkPrev->next->free && !pLinkPrev->area) { - FBLinearLinkPtr p = pLinkPrev->next; - pLinkPrev->linear.size += p->linear.size; - pLinkPrev->next = p->next; - free(p); - } - } - - DebugF("FREEING LINEAR\n"); - DumpDebug(offman->LinearAreas); -} - - -static Bool -localResizeOffscreenLinear(FBLinearPtr resize, int length) -{ - FBManagerPtr offman; - FBLinearLinkPtr pLink; - ScreenPtr pScreen = resize->pScreen; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - pLink = offman->LinearAreas; - if(!pLink) return FALSE; - - while(&(pLink->linear) != resize) { - pLink = pLink->next; - if(!pLink) return FALSE; - } - - /* This could actually be alot smarter and try to move allocations - from XY to linear when available. For now if it was XY, we keep - it XY */ - - if(pLink->area) { /* really an XY area */ - BoxPtr extents; - int pitch, w, h; - - extents = REGION_EXTENTS(pScreen, offman->InitialBoxes); - pitch = extents->x2 - extents->x1; - - if(length < pitch) { /* special case */ - w = length; - h = 1; - } else { - w = pitch; - h = (length + pitch - 1) / pitch; - } - - if(localResizeOffscreenArea(pLink->area, w, h)) { - resize->size = h * w; - resize->offset = (pitch * pLink->area->box.y1) + pLink->area->box.x1; - return TRUE; - } - } else { - /* TODO!!!! resize the linear area */ - } - - return FALSE; -} - - -static Bool -localQueryLargestOffscreenLinear( - ScreenPtr pScreen, - int *size, - int gran, - int priority -) -{ - FBManagerPtr offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - FBLinearLinkPtr pLink; - FBLinearLinkPtr pLinkRet; - - *size = 0; - - pLink = offman->LinearAreas; - - if (pLink && !pLink->area) { - pLinkRet = pLink; - while (pLink) { - if (pLink->free) { - if (pLink->linear.size > pLinkRet->linear.size) - pLinkRet = pLink; - } - pLink = pLink->next; - } - - if (pLinkRet->free) { - *size = pLinkRet->linear.size; - return TRUE; - } - } else { - int w, h; - - if(localQueryLargestOffscreenArea(pScreen, &w, &h, gran, - FAVOR_WIDTH_THEN_AREA, priority)) - { - FBManagerPtr offman; - BoxPtr extents; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - extents = REGION_EXTENTS(pScreen, offman->InitialBoxes); - if((extents->x2 - extents->x1) == w) - *size = w * h; - return TRUE; - } - } - - return FALSE; -} - - - -static FBManagerFuncs xf86FBManFuncs = { - localAllocateOffscreenArea, - localFreeOffscreenArea, - localResizeOffscreenArea, - localQueryLargestOffscreenArea, - localRegisterFreeBoxCallback, - localAllocateOffscreenLinear, - localFreeOffscreenLinear, - localResizeOffscreenLinear, - localQueryLargestOffscreenLinear, - localPurgeUnlockedOffscreenAreas - }; - - -static Bool -xf86FBCloseScreen (int i, ScreenPtr pScreen) -{ - FBLinkPtr pLink, tmp; - FBLinearLinkPtr pLinearLink, tmp2; - FBManagerPtr offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - - pScreen->CloseScreen = offman->CloseScreen; - - pLink = offman->UsedAreas; - while(pLink) { - tmp = pLink; - pLink = pLink->next; - xfree(tmp); - } - - pLinearLink = offman->LinearAreas; - while(pLinearLink) { - tmp2 = pLinearLink; - pLinearLink = pLinearLink->next; - xfree(tmp2); - } - - REGION_DESTROY(pScreen, offman->InitialBoxes); - REGION_DESTROY(pScreen, offman->FreeBoxes); - - xfree(offman->FreeBoxesUpdateCallback); - xfree(offman->devPrivates); - xfree(offman); - dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, NULL); - - return (*pScreen->CloseScreen) (i, pScreen); -} - -Bool -xf86InitFBManager( - ScreenPtr pScreen, - BoxPtr FullBox -){ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - RegionRec ScreenRegion; - RegionRec FullRegion; - BoxRec ScreenBox; - Bool ret; - - ScreenBox.x1 = 0; - ScreenBox.y1 = 0; - ScreenBox.x2 = pScrn->virtualX; - ScreenBox.y2 = pScrn->virtualY; - - if((FullBox->x1 > ScreenBox.x1) || (FullBox->y1 > ScreenBox.y1) || - (FullBox->x2 < ScreenBox.x2) || (FullBox->y2 < ScreenBox.y2)) { - return FALSE; - } - - if (FullBox->y2 < FullBox->y1) return FALSE; - if (FullBox->x2 < FullBox->x1) return FALSE; - - REGION_INIT(pScreen, &ScreenRegion, &ScreenBox, 1); - REGION_INIT(pScreen, &FullRegion, FullBox, 1); - - REGION_SUBTRACT(pScreen, &FullRegion, &FullRegion, &ScreenRegion); - - ret = xf86InitFBManagerRegion(pScreen, &FullRegion); - - REGION_UNINIT(pScreen, &ScreenRegion); - REGION_UNINIT(pScreen, &FullRegion); - - return ret; -} - -Bool -xf86InitFBManagerArea( - ScreenPtr pScreen, - int PixelArea, - int Verbosity -) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xRectangle Rect[3]; - RegionPtr pRegion, pScreenRegion; - int nRect; - Bool ret = FALSE; - - if (PixelArea < (pScrn->displayWidth * pScrn->virtualY)) - return FALSE; - - Rect[0].x = Rect[0].y = 0; - Rect[0].width = pScrn->displayWidth; - Rect[0].height = PixelArea / pScrn->displayWidth; - nRect = 1; - - /* Add a possible partial scanline */ - if ((Rect[1].height = Rect[1].width = PixelArea % pScrn->displayWidth)) { - Rect[1].x = 0; - Rect[1].y = Rect[0].height; - Rect[1].height = 1; - nRect++; - } - - /* Factor out virtual resolution */ - pRegion = RECTS_TO_REGION(pScreen, nRect, Rect, 0); - if (pRegion) { - if (!REGION_NAR(pRegion)) { - Rect[2].x = Rect[2].y = 0; - Rect[2].width = pScrn->virtualX; - Rect[2].height = pScrn->virtualY; - - pScreenRegion = RECTS_TO_REGION(pScreen, 1, &Rect[2], 0); - if (pScreenRegion) { - if (!REGION_NAR(pScreenRegion)) { - REGION_SUBTRACT(pScreen, pRegion, pRegion, pScreenRegion); - - ret = xf86InitFBManagerRegion(pScreen, pRegion); - - if (ret && xf86GetVerbosity() >= Verbosity) { - int scrnIndex = pScrn->scrnIndex; - - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "Largest offscreen areas (with overlaps):\n"); - - if (Rect[2].width < Rect[0].width) { - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "\t%d x %d rectangle at %d,0\n", - Rect[0].width - Rect[2].width, - Rect[0].height, - Rect[2].width); - } - if (Rect[2].width < Rect[1].width) { - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "\t%d x %d rectangle at %d,0\n", - Rect[1].width - Rect[2].width, - Rect[0].height + Rect[1].height, - Rect[2].width); - } - if (Rect[2].height < Rect[0].height) { - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "\t%d x %d rectangle at 0,%d\n", - Rect[0].width, - Rect[0].height - Rect[2].height, - Rect[2].height); - } - if (Rect[1].height) { - xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, - "\t%d x %d rectangle at 0,%d\n", - Rect[1].width, - Rect[0].height - Rect[2].height + - Rect[1].height, - Rect[2].height); - } - } - } - - REGION_DESTROY(pScreen, pScreenRegion); - } - } - - REGION_DESTROY(pScreen, pRegion); - } - - return ret; -} - -Bool -xf86InitFBManagerRegion( - ScreenPtr pScreen, - RegionPtr FullRegion -){ - FBManagerPtr offman; - - if(REGION_NIL(FullRegion)) - return FALSE; - - if(!xf86RegisterOffscreenManager(pScreen, &xf86FBManFuncs)) - return FALSE; - - offman = xalloc(sizeof(FBManager)); - if(!offman) return FALSE; - - dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, offman); - - offman->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = xf86FBCloseScreen; - - offman->InitialBoxes = REGION_CREATE(pScreen, NULL, 1); - offman->FreeBoxes = REGION_CREATE(pScreen, NULL, 1); - - REGION_COPY(pScreen, offman->InitialBoxes, FullRegion); - REGION_COPY(pScreen, offman->FreeBoxes, FullRegion); - - offman->pScreen = pScreen; - offman->UsedAreas = NULL; - offman->LinearAreas = NULL; - offman->NumUsedAreas = 0; - offman->NumCallbacks = 0; - offman->FreeBoxesUpdateCallback = NULL; - offman->devPrivates = NULL; - - return TRUE; -} - -Bool -xf86InitFBManagerLinear( - ScreenPtr pScreen, - int offset, - int size -){ - FBManagerPtr offman; - FBLinearLinkPtr link; - FBLinearPtr linear; - - if (size <= 0) - return FALSE; - - /* we expect people to have called the Area setup first for pixmap cache */ - if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBScreenKey)) - return FALSE; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - offman->LinearAreas = xalloc(sizeof(FBLinearLink)); - if (!offman->LinearAreas) - return FALSE; - - link = offman->LinearAreas; - link->area = NULL; - link->next = NULL; - link->free = 1; - linear = &(link->linear); - linear->pScreen = pScreen; - linear->size = size; - linear->offset = offset; - linear->granularity = 0; - linear->MoveLinearCallback = NULL; - linear->RemoveLinearCallback = NULL; - linear->devPrivate.ptr = NULL; - - return TRUE; -} - - -/* This is an implementation specific function and should - disappear after the next release. People should use the - real linear functions instead */ - -FBAreaPtr -xf86AllocateLinearOffscreenArea ( - ScreenPtr pScreen, - int length, - int gran, - MoveAreaCallbackProcPtr moveCB, - RemoveAreaCallbackProcPtr removeCB, - pointer privData -){ - FBManagerFuncsPtr funcs; - FBManagerPtr offman; - BoxPtr extents; - int w, h; - - if(xf86FBManagerKey == NULL) - return NULL; - if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBManagerKey))) - return NULL; - - offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, - xf86FBScreenKey); - extents = REGION_EXTENTS(pScreen, offman->InitialBoxes); - w = extents->x2 - extents->x1; - - if (gran > 1) { - if (gran > w) - return NULL; - - if (w % gran) - length += gran - 1; - } - - if(length <= w) { /* special case */ - h = 1; - w = length; - } else { - h = (length + w - 1) / w; - } - - return (*funcs->AllocateOffscreenArea)( - pScreen, w, h, gran, moveCB, removeCB, privData); -} + +/* + * Copyright (c) 1998-2001 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "regionstr.h" +#include "xf86fbman.h" + +/* +#define DEBUG +*/ + +static int xf86FBManagerKeyIndex; +static DevPrivateKey xf86FBManagerKey; + +Bool xf86RegisterOffscreenManager( + ScreenPtr pScreen, + FBManagerFuncsPtr funcs +){ + + xf86FBManagerKey = &xf86FBManagerKeyIndex; + dixSetPrivate(&pScreen->devPrivates, xf86FBManagerKey, funcs); + + return TRUE; +} + + +Bool +xf86FBManagerRunning(ScreenPtr pScreen) +{ + if(xf86FBManagerKey == NULL) + return FALSE; + if(!dixLookupPrivate(&pScreen->devPrivates, xf86FBManagerKey)) + return FALSE; + + return TRUE; +} + +Bool +xf86RegisterFreeBoxCallback( + ScreenPtr pScreen, + FreeBoxCallbackProcPtr FreeBoxCallback, + pointer devPriv +){ + FBManagerFuncsPtr funcs; + + if(xf86FBManagerKey == NULL) + return FALSE; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->RegisterFreeBoxCallback)(pScreen, FreeBoxCallback, devPriv); +} + + +FBAreaPtr +xf86AllocateOffscreenArea( + ScreenPtr pScreen, + int w, int h, + int gran, + MoveAreaCallbackProcPtr moveCB, + RemoveAreaCallbackProcPtr removeCB, + pointer privData +){ + FBManagerFuncsPtr funcs; + + if(xf86FBManagerKey == NULL) + return NULL; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return NULL; + + return (*funcs->AllocateOffscreenArea)( + pScreen, w, h, gran, moveCB, removeCB, privData); +} + + +FBLinearPtr +xf86AllocateOffscreenLinear( + ScreenPtr pScreen, + int length, + int gran, + MoveLinearCallbackProcPtr moveCB, + RemoveLinearCallbackProcPtr removeCB, + pointer privData +){ + FBManagerFuncsPtr funcs; + + if(xf86FBManagerKey == NULL) + return NULL; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return NULL; + + return (*funcs->AllocateOffscreenLinear)( + pScreen, length, gran, moveCB, removeCB, privData); +} + + +void +xf86FreeOffscreenArea(FBAreaPtr area) +{ + FBManagerFuncsPtr funcs; + + if(!area) return; + + if(xf86FBManagerKey == NULL) + return; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( + &area->pScreen->devPrivates, xf86FBManagerKey))) + return; + + (*funcs->FreeOffscreenArea)(area); + + return; +} + + +void +xf86FreeOffscreenLinear(FBLinearPtr linear) +{ + FBManagerFuncsPtr funcs; + + if(!linear) return; + + if(xf86FBManagerKey == NULL) + return; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( + &linear->pScreen->devPrivates, xf86FBManagerKey))) + return; + + (*funcs->FreeOffscreenLinear)(linear); + + return; +} + + +Bool +xf86ResizeOffscreenArea( + FBAreaPtr resize, + int w, int h +){ + FBManagerFuncsPtr funcs; + + if(!resize) return FALSE; + + if(xf86FBManagerKey == NULL) + return FALSE; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( + &resize->pScreen->devPrivates, xf86FBManagerKey))) + return FALSE; + + return (*funcs->ResizeOffscreenArea)(resize, w, h); +} + +Bool +xf86ResizeOffscreenLinear( + FBLinearPtr resize, + int size +){ + FBManagerFuncsPtr funcs; + + if(!resize) return FALSE; + + if(xf86FBManagerKey == NULL) + return FALSE; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate( + &resize->pScreen->devPrivates, xf86FBManagerKey))) + return FALSE; + + return (*funcs->ResizeOffscreenLinear)(resize, size); +} + + +Bool +xf86QueryLargestOffscreenArea( + ScreenPtr pScreen, + int *w, int *h, + int gran, + int preferences, + int severity +){ + FBManagerFuncsPtr funcs; + + *w = 0; + *h = 0; + + if(xf86FBManagerKey == NULL) + return FALSE; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->QueryLargestOffscreenArea)( + pScreen, w, h, gran, preferences, severity); +} + +Bool +xf86QueryLargestOffscreenLinear( + ScreenPtr pScreen, + int *size, + int gran, + int severity +){ + FBManagerFuncsPtr funcs; + + *size = 0; + + if(xf86FBManagerKey == NULL) + return FALSE; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->QueryLargestOffscreenLinear)( + pScreen, size, gran, severity); +} + + +Bool +xf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen) +{ + FBManagerFuncsPtr funcs; + + if(xf86FBManagerKey == NULL) + return FALSE; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return FALSE; + + return (*funcs->PurgeOffscreenAreas)(pScreen); +} + +/************************************************************\ + + Below is a specific implementation of an offscreen manager. + +\************************************************************/ + +static int xf86FBScreenKeyIndex; +static DevPrivateKey xf86FBScreenKey = &xf86FBScreenKeyIndex; + +typedef struct _FBLink { + FBArea area; + struct _FBLink *next; +} FBLink, *FBLinkPtr; + +typedef struct _FBLinearLink { + FBLinear linear; + int free; /* need to add free here as FBLinear is publicly accessible */ + FBAreaPtr area; /* only used if allocation came from XY area */ + struct _FBLinearLink *next; +} FBLinearLink, *FBLinearLinkPtr; + + +typedef struct { + ScreenPtr pScreen; + RegionPtr InitialBoxes; + RegionPtr FreeBoxes; + FBLinkPtr UsedAreas; + int NumUsedAreas; + FBLinearLinkPtr LinearAreas; + CloseScreenProcPtr CloseScreen; + int NumCallbacks; + FreeBoxCallbackProcPtr *FreeBoxesUpdateCallback; + DevUnion *devPrivates; +} FBManager, *FBManagerPtr; + + +static void +SendCallFreeBoxCallbacks(FBManagerPtr offman) +{ + int i = offman->NumCallbacks; + + while(i--) { + (*offman->FreeBoxesUpdateCallback[i])( + offman->pScreen, offman->FreeBoxes, offman->devPrivates[i].ptr); + } +} + +static Bool +localRegisterFreeBoxCallback( + ScreenPtr pScreen, + FreeBoxCallbackProcPtr FreeBoxCallback, + pointer devPriv +){ + FBManagerPtr offman; + FreeBoxCallbackProcPtr *newCallbacks; + DevUnion *newPrivates; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + newCallbacks = realloc( offman->FreeBoxesUpdateCallback, + sizeof(FreeBoxCallbackProcPtr) * (offman->NumCallbacks + 1)); + + newPrivates = realloc(offman->devPrivates, + sizeof(DevUnion) * (offman->NumCallbacks + 1)); + + if(!newCallbacks || !newPrivates) + return FALSE; + + offman->FreeBoxesUpdateCallback = newCallbacks; + offman->devPrivates = newPrivates; + + offman->FreeBoxesUpdateCallback[offman->NumCallbacks] = FreeBoxCallback; + offman->devPrivates[offman->NumCallbacks].ptr = devPriv; + offman->NumCallbacks++; + + SendCallFreeBoxCallbacks(offman); + + return TRUE; +} + + +static FBAreaPtr +AllocateArea( + FBManagerPtr offman, + int w, int h, + int granularity, + MoveAreaCallbackProcPtr moveCB, + RemoveAreaCallbackProcPtr removeCB, + pointer privData +){ + ScreenPtr pScreen = offman->pScreen; + FBLinkPtr link = NULL; + FBAreaPtr area = NULL; + RegionRec NewReg; + int i, x = 0, num; + BoxPtr boxp; + + if(granularity <= 1) granularity = 0; + + boxp = REGION_RECTS(offman->FreeBoxes); + num = REGION_NUM_RECTS(offman->FreeBoxes); + + /* look through the free boxes */ + for(i = 0; i < num; i++, boxp++) { + x = boxp->x1; + if (granularity > 1) + x = ((x + granularity - 1) / granularity) * granularity; + + if(((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) + continue; + + link = malloc(sizeof(FBLink)); + if(!link) return NULL; + + area = &(link->area); + link->next = offman->UsedAreas; + offman->UsedAreas = link; + offman->NumUsedAreas++; + break; + } + + /* try to boot a removeable one out if we are not expendable ourselves */ + if(!area && !removeCB) { + link = offman->UsedAreas; + + while(link) { + if(!link->area.RemoveAreaCallback) { + link = link->next; + continue; + } + + boxp = &(link->area.box); + x = boxp->x1; + if (granularity > 1) + x = ((x + granularity - 1) / granularity) * granularity; + + if(((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) { + link = link->next; + continue; + } + + /* bye, bye */ + (*link->area.RemoveAreaCallback)(&link->area); + REGION_INIT(pScreen, &NewReg, &(link->area.box), 1); + REGION_UNION(pScreen, offman->FreeBoxes, offman->FreeBoxes, &NewReg); + REGION_UNINIT(pScreen, &NewReg); + + area = &(link->area); + break; + } + } + + if(area) { + area->pScreen = pScreen; + area->granularity = granularity; + area->box.x1 = x; + area->box.x2 = x + w; + area->box.y1 = boxp->y1; + area->box.y2 = boxp->y1 + h; + area->MoveAreaCallback = moveCB; + area->RemoveAreaCallback = removeCB; + area->devPrivate.ptr = privData; + + REGION_INIT(pScreen, &NewReg, &(area->box), 1); + REGION_SUBTRACT(pScreen, offman->FreeBoxes, offman->FreeBoxes, &NewReg); + REGION_UNINIT(pScreen, &NewReg); + } + + return area; +} + +static FBAreaPtr +localAllocateOffscreenArea( + ScreenPtr pScreen, + int w, int h, + int gran, + MoveAreaCallbackProcPtr moveCB, + RemoveAreaCallbackProcPtr removeCB, + pointer privData +){ + FBManagerPtr offman; + FBAreaPtr area = NULL; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + if((area = AllocateArea(offman, w, h, gran, moveCB, removeCB, privData))) + SendCallFreeBoxCallbacks(offman); + + return area; +} + + +static void +localFreeOffscreenArea(FBAreaPtr area) +{ + FBManagerPtr offman; + FBLinkPtr pLink, pLinkPrev = NULL; + RegionRec FreedRegion; + ScreenPtr pScreen; + + pScreen = area->pScreen; + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->UsedAreas; + if(!pLink) return; + + while(&(pLink->area) != area) { + pLinkPrev = pLink; + pLink = pLink->next; + if(!pLink) return; + } + + /* put the area back into the pool */ + REGION_INIT(pScreen, &FreedRegion, &(pLink->area.box), 1); + REGION_UNION(pScreen, offman->FreeBoxes, offman->FreeBoxes, &FreedRegion); + REGION_UNINIT(pScreen, &FreedRegion); + + if(pLinkPrev) + pLinkPrev->next = pLink->next; + else offman->UsedAreas = pLink->next; + + free(pLink); + offman->NumUsedAreas--; + + SendCallFreeBoxCallbacks(offman); +} + + + +static Bool +localResizeOffscreenArea( + FBAreaPtr resize, + int w, int h +){ + FBManagerPtr offman; + ScreenPtr pScreen; + BoxRec OrigArea; + RegionRec FreedReg; + FBAreaPtr area = NULL; + FBLinkPtr pLink, newLink, pLinkPrev = NULL; + + pScreen = resize->pScreen; + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + /* find this link */ + if(!(pLink = offman->UsedAreas)) + return FALSE; + + while(&(pLink->area) != resize) { + pLinkPrev = pLink; + pLink = pLink->next; + if(!pLink) return FALSE; + } + + OrigArea.x1 = resize->box.x1; + OrigArea.x2 = resize->box.x2; + OrigArea.y1 = resize->box.y1; + OrigArea.y2 = resize->box.y2; + + /* if it's smaller, this is easy */ + + if((w <= (resize->box.x2 - resize->box.x1)) && + (h <= (resize->box.y2 - resize->box.y1))) { + RegionRec NewReg; + + resize->box.x2 = resize->box.x1 + w; + resize->box.y2 = resize->box.y1 + h; + + if((resize->box.y2 == OrigArea.y2) && + (resize->box.x2 == OrigArea.x2)) + return TRUE; + + REGION_INIT(pScreen, &FreedReg, &OrigArea, 1); + REGION_INIT(pScreen, &NewReg, &(resize->box), 1); + REGION_SUBTRACT(pScreen, &FreedReg, &FreedReg, &NewReg); + REGION_UNION(pScreen, offman->FreeBoxes, offman->FreeBoxes, &FreedReg); + REGION_UNINIT(pScreen, &FreedReg); + REGION_UNINIT(pScreen, &NewReg); + + SendCallFreeBoxCallbacks(offman); + + return TRUE; + } + + + /* otherwise we remove the old region */ + + REGION_INIT(pScreen, &FreedReg, &OrigArea, 1); + REGION_UNION(pScreen, offman->FreeBoxes, offman->FreeBoxes, &FreedReg); + + /* remove the old link */ + if(pLinkPrev) + pLinkPrev->next = pLink->next; + else offman->UsedAreas = pLink->next; + + /* and try to add a new one */ + + if((area = AllocateArea(offman, w, h, resize->granularity, + resize->MoveAreaCallback, resize->RemoveAreaCallback, + resize->devPrivate.ptr))) { + + /* copy data over to our link and replace the new with old */ + memcpy(resize, area, sizeof(FBArea)); + + pLinkPrev = NULL; + newLink = offman->UsedAreas; + + while(&(newLink->area) != area) { + pLinkPrev = newLink; + newLink = newLink->next; + } + + if(pLinkPrev) + pLinkPrev->next = newLink->next; + else offman->UsedAreas = newLink->next; + + pLink->next = offman->UsedAreas; + offman->UsedAreas = pLink; + + free(newLink); + + /* AllocateArea added one but we really only exchanged one */ + offman->NumUsedAreas--; + } else { + /* reinstate the old region */ + REGION_SUBTRACT(pScreen, offman->FreeBoxes, offman->FreeBoxes, &FreedReg); + REGION_UNINIT(pScreen, &FreedReg); + + pLink->next = offman->UsedAreas; + offman->UsedAreas = pLink; + return FALSE; + } + + + REGION_UNINIT(pScreen, &FreedReg); + + SendCallFreeBoxCallbacks(offman); + + return TRUE; +} + +static Bool +localQueryLargestOffscreenArea( + ScreenPtr pScreen, + int *width, int *height, + int granularity, + int preferences, + int severity +){ + FBManagerPtr offman; + RegionPtr newRegion = NULL; + BoxPtr pbox; + int nbox; + int x, w, h, area, oldArea; + + *width = *height = oldArea = 0; + + if(granularity <= 1) granularity = 0; + + if((preferences < 0) || (preferences > 3)) + return FALSE; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + if(severity < 0) severity = 0; + if(severity > 2) severity = 2; + + switch(severity) { + case 2: + if(offman->NumUsedAreas) { + FBLinkPtr pLink; + RegionRec tmpRegion; + newRegion = REGION_CREATE(pScreen, NULL, 1); + REGION_COPY(pScreen, newRegion, offman->InitialBoxes); + pLink = offman->UsedAreas; + + while(pLink) { + if(!pLink->area.RemoveAreaCallback) { + REGION_INIT(pScreen, &tmpRegion, &(pLink->area.box), 1); + REGION_SUBTRACT(pScreen, newRegion, newRegion, &tmpRegion); + REGION_UNINIT(pScreen, &tmpRegion); + } + pLink = pLink->next; + } + + nbox = REGION_NUM_RECTS(newRegion); + pbox = REGION_RECTS(newRegion); + break; + } + case 1: + if(offman->NumUsedAreas) { + FBLinkPtr pLink; + RegionRec tmpRegion; + newRegion = REGION_CREATE(pScreen, NULL, 1); + REGION_COPY(pScreen, newRegion, offman->FreeBoxes); + pLink = offman->UsedAreas; + + while(pLink) { + if(pLink->area.RemoveAreaCallback) { + REGION_INIT(pScreen, &tmpRegion, &(pLink->area.box), 1); + REGION_APPEND(pScreen, newRegion, &tmpRegion); + REGION_UNINIT(pScreen, &tmpRegion); + } + pLink = pLink->next; + } + + nbox = REGION_NUM_RECTS(newRegion); + pbox = REGION_RECTS(newRegion); + break; + } + default: + nbox = REGION_NUM_RECTS(offman->FreeBoxes); + pbox = REGION_RECTS(offman->FreeBoxes); + break; + } + + while(nbox--) { + x = pbox->x1; + if (granularity > 1) + x = ((x + granularity - 1) / granularity) * granularity; + + w = pbox->x2 - x; + h = pbox->y2 - pbox->y1; + area = w * h; + + if(w > 0) { + Bool gotIt = FALSE; + switch(preferences) { + case FAVOR_AREA_THEN_WIDTH: + if((area > oldArea) || ((area == oldArea) && (w > *width))) + gotIt = TRUE; + break; + case FAVOR_AREA_THEN_HEIGHT: + if((area > oldArea) || ((area == oldArea) && (h > *height))) + gotIt = TRUE; + break; + case FAVOR_WIDTH_THEN_AREA: + if((w > *width) || ((w == *width) && (area > oldArea))) + gotIt = TRUE; + break; + case FAVOR_HEIGHT_THEN_AREA: + if((h > *height) || ((h == *height) && (area > oldArea))) + gotIt = TRUE; + break; + } + if(gotIt) { + *width = w; + *height = h; + oldArea = area; + } + } + pbox++; + } + + if(newRegion) + REGION_DESTROY(pScreen, newRegion); + + return TRUE; +} + +static Bool +localPurgeUnlockedOffscreenAreas(ScreenPtr pScreen) +{ + FBManagerPtr offman; + FBLinkPtr pLink, tmp, pPrev = NULL; + RegionRec FreedRegion; + Bool anyUsed = FALSE; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->UsedAreas; + if(!pLink) return TRUE; + + while(pLink) { + if(pLink->area.RemoveAreaCallback) { + (*pLink->area.RemoveAreaCallback)(&pLink->area); + + REGION_INIT(pScreen, &FreedRegion, &(pLink->area.box), 1); + REGION_APPEND(pScreen, offman->FreeBoxes, &FreedRegion); + REGION_UNINIT(pScreen, &FreedRegion); + + if(pPrev) + pPrev->next = pLink->next; + else offman->UsedAreas = pLink->next; + + tmp = pLink; + pLink = pLink->next; + free(tmp); + offman->NumUsedAreas--; + anyUsed = TRUE; + } else { + pPrev = pLink; + pLink = pLink->next; + } + } + + if(anyUsed) { + REGION_VALIDATE(pScreen, offman->FreeBoxes, &anyUsed); + SendCallFreeBoxCallbacks(offman); + } + + return TRUE; +} + +static void +LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to) +{ + /* this will never get called */ +} + +static void +LinearRemoveCBWrapper(FBAreaPtr area) +{ + FBManagerPtr offman; + FBLinearLinkPtr pLink, pLinkPrev = NULL; + ScreenPtr pScreen = area->pScreen; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->LinearAreas; + if(!pLink) return; + + while(pLink->area != area) { + pLinkPrev = pLink; + pLink = pLink->next; + if(!pLink) return; + } + + /* give the user the callback it is expecting */ + (*pLink->linear.RemoveLinearCallback)(&(pLink->linear)); + + if(pLinkPrev) + pLinkPrev->next = pLink->next; + else offman->LinearAreas = pLink->next; + + free(pLink); +} + +static void +DumpDebug(FBLinearLinkPtr pLink) +{ +#ifdef DEBUG + if (!pLink) ErrorF("MMmm, PLINK IS NULL!\n"); + + while (pLink) { + ErrorF(" Offset:%08x, Size:%08x, %s,%s\n", + pLink->linear.offset, + pLink->linear.size, + pLink->free ? "Free" : "Used", + pLink->area ? "Area" : "Linear"); + + pLink = pLink->next; + } +#endif +} + +static FBLinearPtr +AllocateLinear( + FBManagerPtr offman, + int size, + int granularity, + pointer privData +){ + ScreenPtr pScreen = offman->pScreen; + FBLinearLinkPtr linear = NULL; + FBLinearLinkPtr newlink = NULL; + int offset, end; + + if(size <= 0) return NULL; + + if (!offman->LinearAreas) return NULL; + + linear = offman->LinearAreas; + while (linear) { + /* Make sure we get a free area that's not an XY fallback case */ + if (!linear->area && linear->free) { + offset = linear->linear.offset; + if (granularity > 1) + offset = ((offset + granularity - 1) / granularity) * granularity; + end = offset+size; + if (end <= (linear->linear.offset + linear->linear.size)) + break; + } + linear = linear->next; + } + if (!linear) + return NULL; + + /* break left */ + if (offset > linear->linear.offset) { + newlink = malloc(sizeof(FBLinearLink)); + if (!newlink) + return NULL; + newlink->area = NULL; + newlink->linear.offset = offset; + newlink->linear.size = linear->linear.size - (offset - linear->linear.offset); + newlink->free = 1; + newlink->next = linear->next; + linear->linear.size -= newlink->linear.size; + linear->next = newlink; + linear = newlink; + } + + /* break right */ + if (size < linear->linear.size) { + newlink = malloc(sizeof(FBLinearLink)); + if (!newlink) + return NULL; + newlink->area = NULL; + newlink->linear.offset = offset + size; + newlink->linear.size = linear->linear.size - size; + newlink->free = 1; + newlink->next = linear->next; + linear->linear.size = size; + linear->next = newlink; + } + + /* p = middle block */ + linear->linear.granularity = granularity; + linear->free = 0; + linear->linear.pScreen = pScreen; + linear->linear.MoveLinearCallback = NULL; + linear->linear.RemoveLinearCallback = NULL; + linear->linear.devPrivate.ptr = NULL; + + DumpDebug(offman->LinearAreas); + + return &(linear->linear); +} + +static FBLinearPtr +localAllocateOffscreenLinear( + ScreenPtr pScreen, + int length, + int gran, + MoveLinearCallbackProcPtr moveCB, + RemoveLinearCallbackProcPtr removeCB, + pointer privData +){ + FBManagerPtr offman; + FBLinearLinkPtr link; + FBAreaPtr area; + FBLinearPtr linear = NULL; + BoxPtr extents; + int w, h, pitch; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + + /* Try to allocate from linear memory first...... */ + DebugF("ALLOCATING LINEAR\n"); + if ((linear = AllocateLinear(offman, length, gran, privData))) + return linear; + + DebugF("NOPE, ALLOCATING AREA\n"); + + if(!(link = malloc(sizeof(FBLinearLink)))) + return NULL; + + /* No linear available, so try and pinch some from the XY areas */ + extents = REGION_EXTENTS(pScreen, offman->InitialBoxes); + pitch = extents->x2 - extents->x1; + + if (gran > 1) { + if (gran > pitch) { + /* we can't match the specified alignment with XY allocations */ + free(link); + return NULL; + } + + if (pitch % gran) { + /* pitch and granularity aren't a perfect match, let's allocate + * a bit more so we can align later on + */ + length += gran - 1; + } + } + + if(length < pitch) { /* special case */ + w = length; + h = 1; + } else { + w = pitch; + h = (length + pitch - 1) / pitch; + } + + if((area = localAllocateOffscreenArea(pScreen, w, h, gran, + moveCB ? LinearMoveCBWrapper : NULL, + removeCB ? LinearRemoveCBWrapper : NULL, + privData))) + { + link->area = area; + link->free = 0; + link->next = offman->LinearAreas; + offman->LinearAreas = link; + linear = &(link->linear); + linear->pScreen = pScreen; + linear->size = h * w; + linear->offset = (pitch * area->box.y1) + area->box.x1; + if (gran > 1) + linear->offset = ((linear->offset + gran - 1) / gran) * gran; + linear->granularity = gran; + linear->MoveLinearCallback = moveCB; + linear->RemoveLinearCallback = removeCB; + linear->devPrivate.ptr = privData; + } else + free(link); + + DumpDebug(offman->LinearAreas); + + return linear; +} + + +static void +localFreeOffscreenLinear(FBLinearPtr linear) +{ + FBManagerPtr offman; + FBLinearLinkPtr pLink, pLinkPrev = NULL; + ScreenPtr pScreen = linear->pScreen; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->LinearAreas; + if(!pLink) return; + + while(&(pLink->linear) != linear) { + pLinkPrev = pLink; + pLink = pLink->next; + if(!pLink) return; + } + + if(pLink->area) { /* really an XY area */ + DebugF("FREEING AREA\n"); + localFreeOffscreenArea(pLink->area); + if(pLinkPrev) + pLinkPrev->next = pLink->next; + else offman->LinearAreas = pLink->next; + free(pLink); + DumpDebug(offman->LinearAreas); + return; + } + + pLink->free = 1; + + if (pLink->next && pLink->next->free) { + FBLinearLinkPtr p = pLink->next; + pLink->linear.size += p->linear.size; + pLink->next = p->next; + free(p); + } + + if(pLinkPrev) { + if (pLinkPrev->next && pLinkPrev->next->free && !pLinkPrev->area) { + FBLinearLinkPtr p = pLinkPrev->next; + pLinkPrev->linear.size += p->linear.size; + pLinkPrev->next = p->next; + free(p); + } + } + + DebugF("FREEING LINEAR\n"); + DumpDebug(offman->LinearAreas); +} + + +static Bool +localResizeOffscreenLinear(FBLinearPtr resize, int length) +{ + FBManagerPtr offman; + FBLinearLinkPtr pLink; + ScreenPtr pScreen = resize->pScreen; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + pLink = offman->LinearAreas; + if(!pLink) return FALSE; + + while(&(pLink->linear) != resize) { + pLink = pLink->next; + if(!pLink) return FALSE; + } + + /* This could actually be alot smarter and try to move allocations + from XY to linear when available. For now if it was XY, we keep + it XY */ + + if(pLink->area) { /* really an XY area */ + BoxPtr extents; + int pitch, w, h; + + extents = REGION_EXTENTS(pScreen, offman->InitialBoxes); + pitch = extents->x2 - extents->x1; + + if(length < pitch) { /* special case */ + w = length; + h = 1; + } else { + w = pitch; + h = (length + pitch - 1) / pitch; + } + + if(localResizeOffscreenArea(pLink->area, w, h)) { + resize->size = h * w; + resize->offset = (pitch * pLink->area->box.y1) + pLink->area->box.x1; + return TRUE; + } + } else { + /* TODO!!!! resize the linear area */ + } + + return FALSE; +} + + +static Bool +localQueryLargestOffscreenLinear( + ScreenPtr pScreen, + int *size, + int gran, + int priority +) +{ + FBManagerPtr offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + FBLinearLinkPtr pLink; + FBLinearLinkPtr pLinkRet; + + *size = 0; + + pLink = offman->LinearAreas; + + if (pLink && !pLink->area) { + pLinkRet = pLink; + while (pLink) { + if (pLink->free) { + if (pLink->linear.size > pLinkRet->linear.size) + pLinkRet = pLink; + } + pLink = pLink->next; + } + + if (pLinkRet->free) { + *size = pLinkRet->linear.size; + return TRUE; + } + } else { + int w, h; + + if(localQueryLargestOffscreenArea(pScreen, &w, &h, gran, + FAVOR_WIDTH_THEN_AREA, priority)) + { + FBManagerPtr offman; + BoxPtr extents; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + extents = REGION_EXTENTS(pScreen, offman->InitialBoxes); + if((extents->x2 - extents->x1) == w) + *size = w * h; + return TRUE; + } + } + + return FALSE; +} + + + +static FBManagerFuncs xf86FBManFuncs = { + localAllocateOffscreenArea, + localFreeOffscreenArea, + localResizeOffscreenArea, + localQueryLargestOffscreenArea, + localRegisterFreeBoxCallback, + localAllocateOffscreenLinear, + localFreeOffscreenLinear, + localResizeOffscreenLinear, + localQueryLargestOffscreenLinear, + localPurgeUnlockedOffscreenAreas + }; + + +static Bool +xf86FBCloseScreen (int i, ScreenPtr pScreen) +{ + FBLinkPtr pLink, tmp; + FBLinearLinkPtr pLinearLink, tmp2; + FBManagerPtr offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + + pScreen->CloseScreen = offman->CloseScreen; + + pLink = offman->UsedAreas; + while(pLink) { + tmp = pLink; + pLink = pLink->next; + free(tmp); + } + + pLinearLink = offman->LinearAreas; + while(pLinearLink) { + tmp2 = pLinearLink; + pLinearLink = pLinearLink->next; + free(tmp2); + } + + REGION_DESTROY(pScreen, offman->InitialBoxes); + REGION_DESTROY(pScreen, offman->FreeBoxes); + + free(offman->FreeBoxesUpdateCallback); + free(offman->devPrivates); + free(offman); + dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, NULL); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +Bool +xf86InitFBManager( + ScreenPtr pScreen, + BoxPtr FullBox +){ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RegionRec ScreenRegion; + RegionRec FullRegion; + BoxRec ScreenBox; + Bool ret; + + ScreenBox.x1 = 0; + ScreenBox.y1 = 0; + ScreenBox.x2 = pScrn->virtualX; + ScreenBox.y2 = pScrn->virtualY; + + if((FullBox->x1 > ScreenBox.x1) || (FullBox->y1 > ScreenBox.y1) || + (FullBox->x2 < ScreenBox.x2) || (FullBox->y2 < ScreenBox.y2)) { + return FALSE; + } + + if (FullBox->y2 < FullBox->y1) return FALSE; + if (FullBox->x2 < FullBox->x1) return FALSE; + + REGION_INIT(pScreen, &ScreenRegion, &ScreenBox, 1); + REGION_INIT(pScreen, &FullRegion, FullBox, 1); + + REGION_SUBTRACT(pScreen, &FullRegion, &FullRegion, &ScreenRegion); + + ret = xf86InitFBManagerRegion(pScreen, &FullRegion); + + REGION_UNINIT(pScreen, &ScreenRegion); + REGION_UNINIT(pScreen, &FullRegion); + + return ret; +} + +Bool +xf86InitFBManagerArea( + ScreenPtr pScreen, + int PixelArea, + int Verbosity +) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xRectangle Rect[3]; + RegionPtr pRegion, pScreenRegion; + int nRect; + Bool ret = FALSE; + + if (PixelArea < (pScrn->displayWidth * pScrn->virtualY)) + return FALSE; + + Rect[0].x = Rect[0].y = 0; + Rect[0].width = pScrn->displayWidth; + Rect[0].height = PixelArea / pScrn->displayWidth; + nRect = 1; + + /* Add a possible partial scanline */ + if ((Rect[1].height = Rect[1].width = PixelArea % pScrn->displayWidth)) { + Rect[1].x = 0; + Rect[1].y = Rect[0].height; + Rect[1].height = 1; + nRect++; + } + + /* Factor out virtual resolution */ + pRegion = RECTS_TO_REGION(pScreen, nRect, Rect, 0); + if (pRegion) { + if (!REGION_NAR(pRegion)) { + Rect[2].x = Rect[2].y = 0; + Rect[2].width = pScrn->virtualX; + Rect[2].height = pScrn->virtualY; + + pScreenRegion = RECTS_TO_REGION(pScreen, 1, &Rect[2], 0); + if (pScreenRegion) { + if (!REGION_NAR(pScreenRegion)) { + REGION_SUBTRACT(pScreen, pRegion, pRegion, pScreenRegion); + + ret = xf86InitFBManagerRegion(pScreen, pRegion); + + if (ret && xf86GetVerbosity() >= Verbosity) { + int scrnIndex = pScrn->scrnIndex; + + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "Largest offscreen areas (with overlaps):\n"); + + if (Rect[2].width < Rect[0].width) { + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "\t%d x %d rectangle at %d,0\n", + Rect[0].width - Rect[2].width, + Rect[0].height, + Rect[2].width); + } + if (Rect[2].width < Rect[1].width) { + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "\t%d x %d rectangle at %d,0\n", + Rect[1].width - Rect[2].width, + Rect[0].height + Rect[1].height, + Rect[2].width); + } + if (Rect[2].height < Rect[0].height) { + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "\t%d x %d rectangle at 0,%d\n", + Rect[0].width, + Rect[0].height - Rect[2].height, + Rect[2].height); + } + if (Rect[1].height) { + xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity, + "\t%d x %d rectangle at 0,%d\n", + Rect[1].width, + Rect[0].height - Rect[2].height + + Rect[1].height, + Rect[2].height); + } + } + } + + REGION_DESTROY(pScreen, pScreenRegion); + } + } + + REGION_DESTROY(pScreen, pRegion); + } + + return ret; +} + +Bool +xf86InitFBManagerRegion( + ScreenPtr pScreen, + RegionPtr FullRegion +){ + FBManagerPtr offman; + + if(REGION_NIL(FullRegion)) + return FALSE; + + if(!xf86RegisterOffscreenManager(pScreen, &xf86FBManFuncs)) + return FALSE; + + offman = malloc(sizeof(FBManager)); + if(!offman) return FALSE; + + dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, offman); + + offman->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = xf86FBCloseScreen; + + offman->InitialBoxes = REGION_CREATE(pScreen, NULL, 1); + offman->FreeBoxes = REGION_CREATE(pScreen, NULL, 1); + + REGION_COPY(pScreen, offman->InitialBoxes, FullRegion); + REGION_COPY(pScreen, offman->FreeBoxes, FullRegion); + + offman->pScreen = pScreen; + offman->UsedAreas = NULL; + offman->LinearAreas = NULL; + offman->NumUsedAreas = 0; + offman->NumCallbacks = 0; + offman->FreeBoxesUpdateCallback = NULL; + offman->devPrivates = NULL; + + return TRUE; +} + +Bool +xf86InitFBManagerLinear( + ScreenPtr pScreen, + int offset, + int size +){ + FBManagerPtr offman; + FBLinearLinkPtr link; + FBLinearPtr linear; + + if (size <= 0) + return FALSE; + + /* we expect people to have called the Area setup first for pixmap cache */ + if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBScreenKey)) + return FALSE; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + offman->LinearAreas = malloc(sizeof(FBLinearLink)); + if (!offman->LinearAreas) + return FALSE; + + link = offman->LinearAreas; + link->area = NULL; + link->next = NULL; + link->free = 1; + linear = &(link->linear); + linear->pScreen = pScreen; + linear->size = size; + linear->offset = offset; + linear->granularity = 0; + linear->MoveLinearCallback = NULL; + linear->RemoveLinearCallback = NULL; + linear->devPrivate.ptr = NULL; + + return TRUE; +} + + +/* This is an implementation specific function and should + disappear after the next release. People should use the + real linear functions instead */ + +FBAreaPtr +xf86AllocateLinearOffscreenArea ( + ScreenPtr pScreen, + int length, + int gran, + MoveAreaCallbackProcPtr moveCB, + RemoveAreaCallbackProcPtr removeCB, + pointer privData +){ + FBManagerFuncsPtr funcs; + FBManagerPtr offman; + BoxPtr extents; + int w, h; + + if(xf86FBManagerKey == NULL) + return NULL; + if(!(funcs = (FBManagerFuncsPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBManagerKey))) + return NULL; + + offman = (FBManagerPtr)dixLookupPrivate(&pScreen->devPrivates, + xf86FBScreenKey); + extents = REGION_EXTENTS(pScreen, offman->InitialBoxes); + w = extents->x2 - extents->x1; + + if (gran > 1) { + if (gran > w) + return NULL; + + if (w % gran) + length += gran - 1; + } + + if(length <= w) { /* special case */ + h = 1; + w = length; + } else { + h = (length + w - 1) / w; + } + + return (*funcs->AllocateOffscreenArea)( + pScreen, w, h, gran, moveCB, removeCB, privData); +} diff --git a/xorg-server/hw/xfree86/common/xf86pciBus.c b/xorg-server/hw/xfree86/common/xf86pciBus.c index ac018e739..b3164730c 100644 --- a/xorg-server/hw/xfree86/common/xf86pciBus.c +++ b/xorg-server/hw/xfree86/common/xf86pciBus.c @@ -1,423 +1,423 @@ -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* - * This file contains the interfaces to the bus-specific code - */ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <ctype.h> -#include <stdlib.h> -#include <unistd.h> -#include <X11/X.h> -#include <pciaccess.h> -#include "os.h" -#include "Pci.h" -#include "xf86.h" -#include "xf86Priv.h" - -/* Bus-specific headers */ -#include "xf86Bus.h" - -#define XF86_OS_PRIVS -#include "xf86_OSproc.h" - - -/* Bus-specific globals */ -Bool pciSlotClaimed = FALSE; - -#define PCIINFOCLASSES(c) \ - ( (((c) & 0x00ff0000) == (PCI_CLASS_PREHISTORIC << 16)) \ - || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \ - || ((((c) & 0x00ffff00) \ - == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) \ - || ((((c) & 0x00ffff00) \ - == ((PCI_CLASS_PROCESSOR << 16) | (PCI_SUBCLASS_PROCESSOR_COPROC << 8)))) ) - -/* - * PCI classes that have messages printed always. The others are only - * have a message printed when the vendor/dev IDs are recognised. - */ -#define PCIALWAYSPRINTCLASSES(c) \ - ( (((c) & 0x00ffff00) \ - == ((PCI_CLASS_PREHISTORIC << 16) | (PCI_SUBCLASS_PREHISTORIC_VGA << 8))) \ - || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \ - || ((((c) & 0x00ffff00) \ - == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) ) - -#define IS_VGA(c) \ - (((c) & 0x00ffff00) \ - == ((PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8))) - -void -xf86FormatPciBusNumber(int busnum, char *buffer) -{ - /* 'buffer' should be at least 8 characters long */ - if (busnum < 256) - sprintf(buffer, "%d", busnum); - else - sprintf(buffer, "%d@%d", busnum & 0x00ff, busnum >> 8); -} - -/* - * xf86Bus.c interface - */ - -void -xf86PciProbe(void) -{ - int i = 0, k; - int num = 0; - struct pci_device *info; - struct pci_device_iterator *iter; - struct pci_device ** xf86PciVideoInfo = NULL; - - - if (!xf86scanpci()) { - xf86PciVideoInfo = NULL; - return; - } - - iter = pci_slot_match_iterator_create(& xf86IsolateDevice); - while ((info = pci_device_next(iter)) != NULL) { - if (PCIINFOCLASSES(info->device_class)) { - num++; - xf86PciVideoInfo = xnfrealloc(xf86PciVideoInfo, - (sizeof(struct pci_device *) - * (num + 1))); - xf86PciVideoInfo[num] = NULL; - xf86PciVideoInfo[num - 1] = info; - - pci_device_probe(info); -#ifdef HAVE_PCI_DEVICE_IS_BOOT_VGA - if (pci_device_is_boot_vga(info)) { - primaryBus.type = BUS_PCI; - primaryBus.id.pci = info; - } -#endif - info->user_data = 0; - } - } - free(iter); - - /* If we haven't found a primary device try a different heuristic */ - if (primaryBus.type == BUS_NONE && num) { - for (i = 0; i < num; i++) { - uint16_t command; - - info = xf86PciVideoInfo[i]; - pci_device_cfg_read_u16(info, & command, 4); - - if ((command & PCI_CMD_MEM_ENABLE) - && ((num == 1) || IS_VGA(info->device_class))) { - if (primaryBus.type == BUS_NONE) { - primaryBus.type = BUS_PCI; - primaryBus.id.pci = info; - } else { - xf86Msg(X_NOTICE, - "More than one possible primary device found\n"); - primaryBus.type ^= (BusType)(-1); - } - } - } - } - - /* Print a summary of the video devices found */ - for (k = 0; k < num; k++) { - const char *vendorname = NULL, *chipname = NULL; - const char *prim = " "; - Bool memdone = FALSE, iodone = FALSE; - - - info = xf86PciVideoInfo[k]; - - vendorname = pci_device_get_vendor_name( info ); - chipname = pci_device_get_device_name( info ); - - if ((!vendorname || !chipname) && - !PCIALWAYSPRINTCLASSES(info->device_class)) - continue; - - if (xf86IsPrimaryPci(info)) - prim = "*"; - - xf86Msg(X_PROBED, "PCI:%s(%u:%u:%u:%u) %04x:%04x:%04x:%04x ", prim, - info->domain, info->bus, info->dev, info->func, - info->vendor_id, info->device_id, - info->subvendor_id, info->subdevice_id); - - if (vendorname) - xf86ErrorF("%s ", vendorname); - - if (chipname) - xf86ErrorF("%s ", chipname); - - xf86ErrorF("rev %d", info->revision); - - for (i = 0; i < 6; i++) { - struct pci_mem_region * r = & info->regions[i]; - - if ( r->size && ! r->is_IO ) { - if (!memdone) { - xf86ErrorF(", Mem @ "); - memdone = TRUE; - } else - xf86ErrorF(", "); - xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size); - } - } - - for (i = 0; i < 6; i++) { - struct pci_mem_region * r = & info->regions[i]; - - if ( r->size && r->is_IO ) { - if (!iodone) { - xf86ErrorF(", I/O @ "); - iodone = TRUE; - } else - xf86ErrorF(", "); - xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size); - } - } - - if ( info->rom_size ) { - xf86ErrorF(", BIOS @ 0x\?\?\?\?\?\?\?\?/%ld", (long)info->rom_size); - } - - xf86ErrorF("\n"); - } - xfree(xf86PciVideoInfo); -} - -/* - * If the slot requested is already in use, return -1. - * Otherwise, claim the slot for the screen requesting it. - */ - -int -xf86ClaimPciSlot(struct pci_device * d, DriverPtr drvp, - int chipset, GDevPtr dev, Bool active) -{ - EntityPtr p = NULL; - int num; - - if (xf86CheckPciSlot(d)) { - num = xf86AllocateEntity(); - p = xf86Entities[num]; - p->driver = drvp; - p->chipset = chipset; - p->bus.type = BUS_PCI; - p->bus.id.pci = d; - p->active = active; - p->inUse = FALSE; - if (dev) - xf86AddDevToEntity(num, dev); - pciSlotClaimed = TRUE; - - if (active) { - /* Map in this domain's I/O space */ - p->domainIO = xf86MapLegacyIO(d); - } - - return num; - } else - return -1; -} - -/* - * Unclaim PCI slot, e.g. if probing failed, so that a different driver can claim. - */ -void -xf86UnclaimPciSlot(struct pci_device *d) -{ - int i; - - for (i = 0; i < xf86NumEntities; i++) { - const EntityPtr p = xf86Entities[i]; - - if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) { - /* Probably the slot should be deallocated? */ - p->bus.type = BUS_NONE; - return; - } - } -} - -/* - * Parse a BUS ID string, and return the PCI bus parameters if it was - * in the correct format for a PCI bus id. - */ - -Bool -xf86ParsePciBusString(const char *busID, int *bus, int *device, int *func) -{ - /* - * The format is assumed to be "bus[@domain]:device[:func]", where domain, - * bus, device and func are decimal integers. domain and func may be - * omitted and assumed to be zero, although doing this isn't encouraged. - */ - - char *p, *s, *d; - const char *id; - int i; - - if (StringToBusType(busID, &id) != BUS_PCI) - return FALSE; - - s = xstrdup(id); - p = strtok(s, ":"); - if (p == NULL || *p == 0) { - xfree(s); - return FALSE; - } - d = strpbrk(p, "@"); - if (d != NULL) { - *(d++) = 0; - for (i = 0; d[i] != 0; i++) { - if (!isdigit(d[i])) { - xfree(s); - return FALSE; - } - } - } - for (i = 0; p[i] != 0; i++) { - if (!isdigit(p[i])) { - xfree(s); - return FALSE; - } - } - *bus = atoi(p); - if (d != NULL && *d != 0) - *bus += atoi(d) << 8; - p = strtok(NULL, ":"); - if (p == NULL || *p == 0) { - xfree(s); - return FALSE; - } - for (i = 0; p[i] != 0; i++) { - if (!isdigit(p[i])) { - xfree(s); - return FALSE; - } - } - *device = atoi(p); - *func = 0; - p = strtok(NULL, ":"); - if (p == NULL || *p == 0) { - xfree(s); - return TRUE; - } - for (i = 0; p[i] != 0; i++) { - if (!isdigit(p[i])) { - xfree(s); - return FALSE; - } - } - *func = atoi(p); - xfree(s); - return TRUE; -} - -/* - * Compare a BUS ID string with a PCI bus id. Return TRUE if they match. - */ - -Bool -xf86ComparePciBusString(const char *busID, int bus, int device, int func) -{ - int ibus, idevice, ifunc; - - if (xf86ParsePciBusString(busID, &ibus, &idevice, &ifunc)) { - return bus == ibus && device == idevice && func == ifunc; - } else { - return FALSE; - } -} - -/* - * xf86IsPrimaryPci() -- return TRUE if primary device - * is PCI and bus, dev and func numbers match. - */ - -Bool -xf86IsPrimaryPci(struct pci_device *pPci) -{ - return ((primaryBus.type == BUS_PCI) && (pPci == primaryBus.id.pci)); -} - -/* - * xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity. - */ -struct pci_device * -xf86GetPciInfoForEntity(int entityIndex) -{ - EntityPtr p; - - if (entityIndex >= xf86NumEntities) - return NULL; - - p = xf86Entities[entityIndex]; - return (p->bus.type == BUS_PCI) ? p->bus.id.pci : NULL; -} - -/* - * xf86CheckPciMemBase() checks that the memory base value matches one of the - * PCI base address register values for the given PCI device. - */ -Bool -xf86CheckPciMemBase( struct pci_device * pPci, memType base ) -{ - int i; - - for (i = 0; i < 6; i++) - if (base == pPci->regions[i].base_addr) - return TRUE; - return FALSE; -} - -/* - * Check if the slot requested is free. If it is already in use, return FALSE. - */ - -Bool -xf86CheckPciSlot(const struct pci_device *d) -{ - int i; - - for (i = 0; i < xf86NumEntities; i++) { - const EntityPtr p = xf86Entities[i]; - - if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) { - return FALSE; - } - } - return TRUE; -} - - +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* + * This file contains the interfaces to the bus-specific code + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <X11/X.h> +#include <pciaccess.h> +#include "os.h" +#include "Pci.h" +#include "xf86.h" +#include "xf86Priv.h" + +/* Bus-specific headers */ +#include "xf86Bus.h" + +#define XF86_OS_PRIVS +#include "xf86_OSproc.h" + + +/* Bus-specific globals */ +Bool pciSlotClaimed = FALSE; + +#define PCIINFOCLASSES(c) \ + ( (((c) & 0x00ff0000) == (PCI_CLASS_PREHISTORIC << 16)) \ + || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \ + || ((((c) & 0x00ffff00) \ + == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) \ + || ((((c) & 0x00ffff00) \ + == ((PCI_CLASS_PROCESSOR << 16) | (PCI_SUBCLASS_PROCESSOR_COPROC << 8)))) ) + +/* + * PCI classes that have messages printed always. The others are only + * have a message printed when the vendor/dev IDs are recognised. + */ +#define PCIALWAYSPRINTCLASSES(c) \ + ( (((c) & 0x00ffff00) \ + == ((PCI_CLASS_PREHISTORIC << 16) | (PCI_SUBCLASS_PREHISTORIC_VGA << 8))) \ + || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \ + || ((((c) & 0x00ffff00) \ + == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) ) + +#define IS_VGA(c) \ + (((c) & 0x00ffff00) \ + == ((PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8))) + +void +xf86FormatPciBusNumber(int busnum, char *buffer) +{ + /* 'buffer' should be at least 8 characters long */ + if (busnum < 256) + sprintf(buffer, "%d", busnum); + else + sprintf(buffer, "%d@%d", busnum & 0x00ff, busnum >> 8); +} + +/* + * xf86Bus.c interface + */ + +void +xf86PciProbe(void) +{ + int i = 0, k; + int num = 0; + struct pci_device *info; + struct pci_device_iterator *iter; + struct pci_device ** xf86PciVideoInfo = NULL; + + + if (!xf86scanpci()) { + xf86PciVideoInfo = NULL; + return; + } + + iter = pci_slot_match_iterator_create(& xf86IsolateDevice); + while ((info = pci_device_next(iter)) != NULL) { + if (PCIINFOCLASSES(info->device_class)) { + num++; + xf86PciVideoInfo = xnfrealloc(xf86PciVideoInfo, + (sizeof(struct pci_device *) + * (num + 1))); + xf86PciVideoInfo[num] = NULL; + xf86PciVideoInfo[num - 1] = info; + + pci_device_probe(info); +#ifdef HAVE_PCI_DEVICE_IS_BOOT_VGA + if (pci_device_is_boot_vga(info)) { + primaryBus.type = BUS_PCI; + primaryBus.id.pci = info; + } +#endif + info->user_data = 0; + } + } + free(iter); + + /* If we haven't found a primary device try a different heuristic */ + if (primaryBus.type == BUS_NONE && num) { + for (i = 0; i < num; i++) { + uint16_t command; + + info = xf86PciVideoInfo[i]; + pci_device_cfg_read_u16(info, & command, 4); + + if ((command & PCI_CMD_MEM_ENABLE) + && ((num == 1) || IS_VGA(info->device_class))) { + if (primaryBus.type == BUS_NONE) { + primaryBus.type = BUS_PCI; + primaryBus.id.pci = info; + } else { + xf86Msg(X_NOTICE, + "More than one possible primary device found\n"); + primaryBus.type ^= (BusType)(-1); + } + } + } + } + + /* Print a summary of the video devices found */ + for (k = 0; k < num; k++) { + const char *vendorname = NULL, *chipname = NULL; + const char *prim = " "; + Bool memdone = FALSE, iodone = FALSE; + + + info = xf86PciVideoInfo[k]; + + vendorname = pci_device_get_vendor_name( info ); + chipname = pci_device_get_device_name( info ); + + if ((!vendorname || !chipname) && + !PCIALWAYSPRINTCLASSES(info->device_class)) + continue; + + if (xf86IsPrimaryPci(info)) + prim = "*"; + + xf86Msg(X_PROBED, "PCI:%s(%u:%u:%u:%u) %04x:%04x:%04x:%04x ", prim, + info->domain, info->bus, info->dev, info->func, + info->vendor_id, info->device_id, + info->subvendor_id, info->subdevice_id); + + if (vendorname) + xf86ErrorF("%s ", vendorname); + + if (chipname) + xf86ErrorF("%s ", chipname); + + xf86ErrorF("rev %d", info->revision); + + for (i = 0; i < 6; i++) { + struct pci_mem_region * r = & info->regions[i]; + + if ( r->size && ! r->is_IO ) { + if (!memdone) { + xf86ErrorF(", Mem @ "); + memdone = TRUE; + } else + xf86ErrorF(", "); + xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size); + } + } + + for (i = 0; i < 6; i++) { + struct pci_mem_region * r = & info->regions[i]; + + if ( r->size && r->is_IO ) { + if (!iodone) { + xf86ErrorF(", I/O @ "); + iodone = TRUE; + } else + xf86ErrorF(", "); + xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size); + } + } + + if ( info->rom_size ) { + xf86ErrorF(", BIOS @ 0x\?\?\?\?\?\?\?\?/%ld", (long)info->rom_size); + } + + xf86ErrorF("\n"); + } + free(xf86PciVideoInfo); +} + +/* + * If the slot requested is already in use, return -1. + * Otherwise, claim the slot for the screen requesting it. + */ + +int +xf86ClaimPciSlot(struct pci_device * d, DriverPtr drvp, + int chipset, GDevPtr dev, Bool active) +{ + EntityPtr p = NULL; + int num; + + if (xf86CheckPciSlot(d)) { + num = xf86AllocateEntity(); + p = xf86Entities[num]; + p->driver = drvp; + p->chipset = chipset; + p->bus.type = BUS_PCI; + p->bus.id.pci = d; + p->active = active; + p->inUse = FALSE; + if (dev) + xf86AddDevToEntity(num, dev); + pciSlotClaimed = TRUE; + + if (active) { + /* Map in this domain's I/O space */ + p->domainIO = xf86MapLegacyIO(d); + } + + return num; + } else + return -1; +} + +/* + * Unclaim PCI slot, e.g. if probing failed, so that a different driver can claim. + */ +void +xf86UnclaimPciSlot(struct pci_device *d) +{ + int i; + + for (i = 0; i < xf86NumEntities; i++) { + const EntityPtr p = xf86Entities[i]; + + if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) { + /* Probably the slot should be deallocated? */ + p->bus.type = BUS_NONE; + return; + } + } +} + +/* + * Parse a BUS ID string, and return the PCI bus parameters if it was + * in the correct format for a PCI bus id. + */ + +Bool +xf86ParsePciBusString(const char *busID, int *bus, int *device, int *func) +{ + /* + * The format is assumed to be "bus[@domain]:device[:func]", where domain, + * bus, device and func are decimal integers. domain and func may be + * omitted and assumed to be zero, although doing this isn't encouraged. + */ + + char *p, *s, *d; + const char *id; + int i; + + if (StringToBusType(busID, &id) != BUS_PCI) + return FALSE; + + s = xstrdup(id); + p = strtok(s, ":"); + if (p == NULL || *p == 0) { + free(s); + return FALSE; + } + d = strpbrk(p, "@"); + if (d != NULL) { + *(d++) = 0; + for (i = 0; d[i] != 0; i++) { + if (!isdigit(d[i])) { + free(s); + return FALSE; + } + } + } + for (i = 0; p[i] != 0; i++) { + if (!isdigit(p[i])) { + free(s); + return FALSE; + } + } + *bus = atoi(p); + if (d != NULL && *d != 0) + *bus += atoi(d) << 8; + p = strtok(NULL, ":"); + if (p == NULL || *p == 0) { + free(s); + return FALSE; + } + for (i = 0; p[i] != 0; i++) { + if (!isdigit(p[i])) { + free(s); + return FALSE; + } + } + *device = atoi(p); + *func = 0; + p = strtok(NULL, ":"); + if (p == NULL || *p == 0) { + free(s); + return TRUE; + } + for (i = 0; p[i] != 0; i++) { + if (!isdigit(p[i])) { + free(s); + return FALSE; + } + } + *func = atoi(p); + free(s); + return TRUE; +} + +/* + * Compare a BUS ID string with a PCI bus id. Return TRUE if they match. + */ + +Bool +xf86ComparePciBusString(const char *busID, int bus, int device, int func) +{ + int ibus, idevice, ifunc; + + if (xf86ParsePciBusString(busID, &ibus, &idevice, &ifunc)) { + return bus == ibus && device == idevice && func == ifunc; + } else { + return FALSE; + } +} + +/* + * xf86IsPrimaryPci() -- return TRUE if primary device + * is PCI and bus, dev and func numbers match. + */ + +Bool +xf86IsPrimaryPci(struct pci_device *pPci) +{ + return ((primaryBus.type == BUS_PCI) && (pPci == primaryBus.id.pci)); +} + +/* + * xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity. + */ +struct pci_device * +xf86GetPciInfoForEntity(int entityIndex) +{ + EntityPtr p; + + if (entityIndex >= xf86NumEntities) + return NULL; + + p = xf86Entities[entityIndex]; + return (p->bus.type == BUS_PCI) ? p->bus.id.pci : NULL; +} + +/* + * xf86CheckPciMemBase() checks that the memory base value matches one of the + * PCI base address register values for the given PCI device. + */ +Bool +xf86CheckPciMemBase( struct pci_device * pPci, memType base ) +{ + int i; + + for (i = 0; i < 6; i++) + if (base == pPci->regions[i].base_addr) + return TRUE; + return FALSE; +} + +/* + * Check if the slot requested is free. If it is already in use, return FALSE. + */ + +Bool +xf86CheckPciSlot(const struct pci_device *d) +{ + int i; + + for (i = 0; i < xf86NumEntities; i++) { + const EntityPtr p = xf86Entities[i]; + + if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) { + return FALSE; + } + } + return TRUE; +} + + diff --git a/xorg-server/hw/xfree86/common/xf86sbusBus.c b/xorg-server/hw/xfree86/common/xf86sbusBus.c index 7b23233aa..8df3a6c7a 100644 --- a/xorg-server/hw/xfree86/common/xf86sbusBus.c +++ b/xorg-server/hw/xfree86/common/xf86sbusBus.c @@ -1,688 +1,688 @@ -/* - * SBUS bus-specific code. - * - * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com) - * - * 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 - * JAKUB JELINEK 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. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <ctype.h> -#include <stdio.h> -#include <unistd.h> -#include <X11/X.h> -#include "os.h" -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" -#include "xf86cmap.h" - -#include "xf86Bus.h" - -#include "xf86sbusBus.h" -#include "xf86Sbus.h" - -Bool sbusSlotClaimed = FALSE; - -static int xf86nSbusInfo; - -static void -CheckSbusDevice(const char *device, int fbNum) -{ - int fd, i; - struct fbgattr fbattr; - sbusDevicePtr psdp; - - fd = open(device, O_RDONLY, 0); - if (fd < 0) - return; - memset(&fbattr, 0, sizeof(fbattr)); - if (ioctl(fd, FBIOGATTR, &fbattr) < 0) { - if (ioctl(fd, FBIOGTYPE, &fbattr.fbtype) < 0) { - close(fd); - return; - } - } - close(fd); - for (i = 0; sbusDeviceTable[i].devId; i++) - if (sbusDeviceTable[i].fbType == fbattr.fbtype.fb_type) - break; - if (! sbusDeviceTable[i].devId) - return; - xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (++xf86nSbusInfo + 1)); - xf86SbusInfo[xf86nSbusInfo] = NULL; - xf86SbusInfo[xf86nSbusInfo - 1] = psdp = xnfcalloc(sizeof (sbusDevice), 1); - psdp->devId = sbusDeviceTable[i].devId; - psdp->fbNum = fbNum; - psdp->device = xnfstrdup(device); - psdp->width = fbattr.fbtype.fb_width; - psdp->height = fbattr.fbtype.fb_height; - psdp->fd = -1; -} - -void -xf86SbusProbe(void) -{ - int i, useProm = 0; - char fbDevName[32]; - sbusDevicePtr psdp, *psdpp; - - xf86SbusInfo = xalloc(sizeof(psdp)); - *xf86SbusInfo = NULL; - for (i = 0; i < 32; i++) { - sprintf(fbDevName, "/dev/fb%d", i); - CheckSbusDevice(fbDevName, i); - } - if (sparcPromInit() >= 0) { - useProm = 1; - sparcPromAssignNodes(); - } - for (psdpp = xf86SbusInfo; (psdp = *psdpp); psdpp++) { - for (i = 0; sbusDeviceTable[i].devId; i++) - if (sbusDeviceTable[i].devId == psdp->devId) - psdp->descr = sbusDeviceTable[i].descr; - /* - * If we can use PROM information and found the PROM node for this - * device, we can tell more about the card. - */ - if (useProm && psdp->node.node) { - char *prop, *promPath; - int len, chiprev, vmsize; - - switch (psdp->devId) { - case SBUS_DEVICE_MGX: - prop = sparcPromGetProperty(&psdp->node, "fb_size", &len); - if (prop && len == 4 && *(int *)prop == 0x400000) - psdp->descr = "Quantum 3D MGXplus with 4M VRAM"; - break; - case SBUS_DEVICE_CG6: - chiprev = 0; - vmsize = 0; - prop = sparcPromGetProperty(&psdp->node, "chiprev", &len); - if (prop && len == 4) - chiprev = *(int *)prop; - prop = sparcPromGetProperty(&psdp->node, "vmsize", &len); - if (prop && len == 4) - vmsize = *(int *)prop; - switch (chiprev) { - case 1: - case 2: - case 3: - case 4: - psdp->descr = "Sun Double width GX"; break; - case 5: - case 6: - case 7: - case 8: - case 9: - psdp->descr = "Sun Single width GX"; break; - case 11: - switch (vmsize) { - case 2: - psdp->descr = "Sun Turbo GX with 1M VSIMM"; break; - case 4: - psdp->descr = "Sun Turbo GX Plus"; break; - default: - psdp->descr = "Sun Turbo GX"; break; - } - } - break; - case SBUS_DEVICE_CG14: - prop = sparcPromGetProperty(&psdp->node, "reg", &len); - vmsize = 0; - if (prop && !(len % 12) && len > 0) - vmsize = *(int *)(prop + len - 4); - switch (vmsize) { - case 0x400000: - psdp->descr = "Sun SX with 4M VSIMM"; break; - case 0x800000: - psdp->descr = "Sun SX with 8M VSIMM"; break; - } - break; - case SBUS_DEVICE_LEO: - prop = sparcPromGetProperty(&psdp->node, "model", &len); - if (prop && len > 0 && !strstr(prop, "501-2503")) - psdp->descr = "Sun Turbo ZX"; - break; - case SBUS_DEVICE_TCX: - if (sparcPromGetBool(&psdp->node, "tcx-8-bit")) - psdp->descr = "Sun TCX (8bit)"; - else - psdp->descr = "Sun TCX (S24)"; - break; - case SBUS_DEVICE_FFB: - prop = sparcPromGetProperty(&psdp->node, "name", &len); - chiprev = 0; - prop = sparcPromGetProperty(&psdp->node, "board_type", &len); - if (prop && len == 4) - chiprev = *(int *)prop; - if (strstr (prop, "afb")) { - if (chiprev == 3) - psdp->descr = "Sun|Elite3D-M6 Horizontal"; - } else { - switch (chiprev) { - case 0x08: - psdp->descr = "Sun FFB 67MHz Creator"; break; - case 0x0b: - psdp->descr = "Sun FFB 67MHz Creator 3D"; break; - case 0x1b: - psdp->descr = "Sun FFB 75MHz Creator 3D"; break; - case 0x20: - case 0x28: - psdp->descr = "Sun FFB2 Vertical Creator"; break; - case 0x23: - case 0x2b: - psdp->descr = "Sun FFB2 Vertical Creator 3D"; break; - case 0x30: - psdp->descr = "Sun FFB2+ Vertical Creator"; break; - case 0x33: - psdp->descr = "Sun FFB2+ Vertical Creator 3D"; break; - case 0x40: - case 0x48: - psdp->descr = "Sun FFB2 Horizontal Creator"; break; - case 0x43: - case 0x4b: - psdp->descr = "Sun FFB2 Horizontal Creator 3D"; break; - } - } - break; - } - - xf86Msg(X_PROBED, "SBUS:(0x%08x) %s", psdp->node.node, psdp->descr); - promPath = sparcPromNode2Pathname (&psdp->node); - if (promPath) { - xf86ErrorF(" at %s", promPath); - xfree(promPath); - } - } else - xf86Msg(X_PROBED, "SBUS: %s", psdp->descr); - xf86ErrorF("\n"); - } - if (useProm) - sparcPromClose(); -} - -/* - * Parse a BUS ID string, and return the SBUS bus parameters if it was - * in the correct format for a SBUS bus id. - */ - -Bool -xf86ParseSbusBusString(const char *busID, int *fbNum) -{ - /* - * The format is assumed to be one of: - * "fbN", e.g. "fb1", which means the device corresponding to /dev/fbN - * "nameN", e.g. "cgsix0", which means Nth instance of card NAME - * "/prompath", e.g. "/sbus@0,10001000/cgsix@3,0" which is PROM pathname - * to the device. - */ - - const char *id; - int i, len; - - if (StringToBusType(busID, &id) != BUS_SBUS) - return FALSE; - - if (*id != '/') { - if (!strncmp (id, "fb", 2)) { - if (!isdigit(id[2])) - return FALSE; - *fbNum = atoi(id + 2); - return TRUE; - } else { - sbusDevicePtr *psdpp; - int devId; - - for (i = 0, len = 0; sbusDeviceTable[i].devId; i++) { - len = strlen(sbusDeviceTable[i].promName); - if (!strncmp (sbusDeviceTable[i].promName, id, len) - && isdigit(id[len])) - break; - } - devId = sbusDeviceTable[i].devId; - if (!devId) return FALSE; - i = atoi(id + len); - for (psdpp = xf86SbusInfo; *psdpp; ++psdpp) { - if ((*psdpp)->devId != devId) - continue; - if (!i) { - *fbNum = (*psdpp)->fbNum; - return TRUE; - } - i--; - } - } - return FALSE; - } - - if (sparcPromInit() >= 0) { - i = sparcPromPathname2Node(id); - sparcPromClose(); - if (i) { - sbusDevicePtr *psdpp; - for (psdpp = xf86SbusInfo; *psdpp; ++psdpp) { - if ((*psdpp)->node.node == i) { - *fbNum = (*psdpp)->fbNum; - return TRUE; - } - } - } - } - return FALSE; -} - -/* - * Compare a BUS ID string with a SBUS bus id. Return TRUE if they match. - */ - -Bool -xf86CompareSbusBusString(const char *busID, int fbNum) -{ - int iFbNum; - - if (xf86ParseSbusBusString(busID, &iFbNum)) { - return fbNum == iFbNum; - } else { - return FALSE; - } -} - -/* - * Check if the slot requested is free. If it is already in use, return FALSE. - */ - -Bool -xf86CheckSbusSlot(int fbNum) -{ - int i; - EntityPtr p; - - for (i = 0; i < xf86NumEntities; i++) { - p = xf86Entities[i]; - /* Check if this SBUS slot is taken */ - if (p->bus.type == BUS_SBUS && p->bus.id.sbus.fbNum == fbNum) - return FALSE; - } - - return TRUE; -} - -/* - * If the slot requested is already in use, return -1. - * Otherwise, claim the slot for the screen requesting it. - */ - -int -xf86ClaimSbusSlot(sbusDevicePtr psdp, DriverPtr drvp, - GDevPtr dev, Bool active) -{ - EntityPtr p = NULL; - - int num; - - if (xf86CheckSbusSlot(psdp->fbNum)) { - num = xf86AllocateEntity(); - p = xf86Entities[num]; - p->driver = drvp; - p->chipset = -1; - p->bus.type = BUS_SBUS; - xf86AddDevToEntity(num, dev); - p->bus.id.sbus.fbNum = psdp->fbNum; - p->active = active; - p->inUse = FALSE; - sbusSlotClaimed = TRUE; - return num; - } else - return -1; -} - -int -xf86MatchSbusInstances(const char *driverName, int sbusDevId, - GDevPtr *devList, int numDevs, DriverPtr drvp, - int **foundEntities) -{ - int i,j; - sbusDevicePtr psdp, *psdpp; - int numClaimedInstances = 0; - int allocatedInstances = 0; - int numFound = 0; - GDevPtr devBus = NULL; - GDevPtr dev = NULL; - int *retEntities = NULL; - int useProm = 0; - - struct Inst { - sbusDevicePtr sbus; - GDevPtr dev; - Bool claimed; /* BusID matches with a device section */ - } *instances = NULL; - - *foundEntities = NULL; - for (psdpp = xf86SbusInfo, psdp = *psdpp; psdp; psdp = *++psdpp) { - if (psdp->devId != sbusDevId) - continue; - if (psdp->fd == -2) - continue; - ++allocatedInstances; - instances = xnfrealloc(instances, - allocatedInstances * sizeof(struct Inst)); - instances[allocatedInstances - 1].sbus = psdp; - instances[allocatedInstances - 1].dev = NULL; - instances[allocatedInstances - 1].claimed = FALSE; - numFound++; - } - - /* - * This may be debatable, but if no SBUS devices with a matching vendor - * type is found, return zero now. It is probably not desirable to - * allow the config file to override this. - */ - if (allocatedInstances <= 0) { - xfree(instances); - return 0; - } - - if (sparcPromInit() >= 0) - useProm = 1; - - if (xf86DoConfigure && xf86DoConfigurePass1) { - GDevPtr pGDev; - int actualcards = 0; - for (i = 0; i < allocatedInstances; i++) { - actualcards++; - pGDev = xf86AddBusDeviceToConfigure(drvp->driverName, BUS_SBUS, - instances[i].sbus, -1); - if (pGDev) { - /* - * XF86Match???Instances() treat chipID and chipRev as - * overrides, so clobber them here. - */ - pGDev->chipID = pGDev->chipRev = -1; - } - } - xfree(instances); - if (useProm) - sparcPromClose(); - return actualcards; - } - - DebugF("%s instances found: %d\n", driverName, allocatedInstances); - - for (i = 0; i < allocatedInstances; i++) { - char *promPath = NULL; - - psdp = instances[i].sbus; - devBus = NULL; - dev = NULL; - if (useProm && psdp->node.node) - promPath = sparcPromNode2Pathname(&psdp->node); - - for (j = 0; j < numDevs; j++) { - if (devList[j]->busID && *devList[j]->busID) { - if (xf86CompareSbusBusString(devList[j]->busID, psdp->fbNum)) { - if (devBus) - xf86MsgVerb(X_WARNING,0, - "%s: More than one matching Device section for " - "instance (BusID: %s) found: %s\n", - driverName,devList[j]->identifier, - devList[j]->busID); - else - devBus = devList[j]; - } - } else { - if (!dev && !devBus) { - if (promPath) - xf86Msg(X_PROBED, "Assigning device section with no busID to SBUS:%s\n", - promPath); - else - xf86Msg(X_PROBED, "Assigning device section with no busID to SBUS:fb%d\n", - psdp->fbNum); - dev = devList[j]; - } else - xf86MsgVerb(X_WARNING, 0, - "%s: More than one matching Device section " - "found: %s\n", driverName, devList[j]->identifier); - } - } - if (devBus) dev = devBus; /* busID preferred */ - if (!dev && psdp->fd != -2) { - if (promPath) { - xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section " - "for instance (BusID SBUS:%s) found\n", - driverName, promPath); - } else - xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section " - "for instance (BusID SBUS:fb%d) found\n", - driverName, psdp->fbNum); - } else if (dev) { - numClaimedInstances++; - instances[i].claimed = TRUE; - instances[i].dev = dev; - } - if (promPath) - xfree(promPath); - } - - DebugF("%s instances found: %d\n", driverName, numClaimedInstances); - - /* - * Of the claimed instances, check that another driver hasn't already - * claimed its slot. - */ - numFound = 0; - for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) { - if (!instances[i].claimed) - continue; - psdp = instances[i].sbus; - if (!xf86CheckSbusSlot(psdp->fbNum)) - continue; - - DebugF("%s: card at fb%d %08x is claimed by a Device section\n", - driverName, psdp->fbNum, psdp->node.node); - - /* Allocate an entry in the lists to be returned */ - numFound++; - retEntities = xnfrealloc(retEntities, numFound * sizeof(int)); - retEntities[numFound - 1] - = xf86ClaimSbusSlot(psdp, drvp, instances[i].dev,instances[i].dev->active ? - TRUE : FALSE); - } - xfree(instances); - if (numFound > 0) { - *foundEntities = retEntities; - } - - if (useProm) - sparcPromClose(); - - return numFound; -} - -/* - * xf86GetSbusInfoForEntity() -- Get the sbusDevicePtr of entity. - */ -sbusDevicePtr -xf86GetSbusInfoForEntity(int entityIndex) -{ - sbusDevicePtr *psdpp; - EntityPtr p = xf86Entities[entityIndex]; - - if (entityIndex >= xf86NumEntities - || p->bus.type != BUS_SBUS) return NULL; - - for (psdpp = xf86SbusInfo; *psdpp != NULL; psdpp++) { - if (p->bus.id.sbus.fbNum == (*psdpp)->fbNum) - return (*psdpp); - } - return NULL; -} - -int -xf86GetEntityForSbusInfo(sbusDevicePtr psdp) -{ - int i; - - for (i = 0; i < xf86NumEntities; i++) { - EntityPtr p = xf86Entities[i]; - if (p->bus.type != BUS_SBUS) continue; - - if (p->bus.id.sbus.fbNum == psdp->fbNum) - return i; - } - return -1; -} - -void -xf86SbusUseBuiltinMode(ScrnInfoPtr pScrn, sbusDevicePtr psdp) -{ - DisplayModePtr mode; - - mode = xnfcalloc(sizeof(DisplayModeRec), 1); - mode->name = "current"; - mode->next = mode; - mode->prev = mode; - mode->type = M_T_BUILTIN; - mode->Clock = 100000000; - mode->HDisplay = psdp->width; - mode->HSyncStart = psdp->width; - mode->HSyncEnd = psdp->width; - mode->HTotal = psdp->width; - mode->VDisplay = psdp->height; - mode->VSyncStart = psdp->height; - mode->VSyncEnd = psdp->height; - mode->VTotal = psdp->height; - mode->SynthClock = mode->Clock; - mode->CrtcHDisplay = mode->HDisplay; - mode->CrtcHSyncStart = mode->HSyncStart; - mode->CrtcHSyncEnd = mode->HSyncEnd; - mode->CrtcHTotal = mode->HTotal; - mode->CrtcVDisplay = mode->VDisplay; - mode->CrtcVSyncStart = mode->VSyncStart; - mode->CrtcVSyncEnd = mode->VSyncEnd; - mode->CrtcVTotal = mode->VTotal; - mode->CrtcHAdjusted = FALSE; - mode->CrtcVAdjusted = FALSE; - pScrn->modes = mode; - pScrn->virtualX = psdp->width; - pScrn->virtualY = psdp->height; -} - -static sbusPaletteKeyIndex; -static DevPrivateKey sbusPaletteKey = &sbusPaletteKeyIndex; -typedef struct _sbusCmap { - sbusDevicePtr psdp; - CloseScreenProcPtr CloseScreen; - Bool origCmapValid; - unsigned char origRed[16]; - unsigned char origGreen[16]; - unsigned char origBlue[16]; -} sbusCmapRec, *sbusCmapPtr; - -#define SBUSCMAPPTR(pScreen) ((sbusCmapPtr) \ - dixLookupPrivate(&(pScreen)->devPrivates, sbusPaletteKey)) - -static void -xf86SbusCmapLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, - LOCO *colors, VisualPtr pVisual) -{ - int i, index; - sbusCmapPtr cmap; - struct fbcmap fbcmap; - unsigned char *data = xalloc(numColors*3); - - cmap = SBUSCMAPPTR(pScrn->pScreen); - if (!cmap) return; - fbcmap.count = 0; - fbcmap.index = indices[0]; - fbcmap.red = data; - fbcmap.green = data + numColors; - fbcmap.blue = fbcmap.green + numColors; - for (i = 0; i < numColors; i++) { - index = indices[i]; - if (fbcmap.count && index != fbcmap.index + fbcmap.count) { - ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap); - fbcmap.count = 0; - fbcmap.index = index; - } - fbcmap.red[fbcmap.count] = colors[index].red; - fbcmap.green[fbcmap.count] = colors[index].green; - fbcmap.blue[fbcmap.count++] = colors[index].blue; - } - ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap); - xfree(data); -} - -static Bool -xf86SbusCmapCloseScreen(int i, ScreenPtr pScreen) -{ - sbusCmapPtr cmap; - struct fbcmap fbcmap; - - cmap = SBUSCMAPPTR(pScreen); - if (cmap->origCmapValid) { - fbcmap.index = 0; - fbcmap.count = 16; - fbcmap.red = cmap->origRed; - fbcmap.green = cmap->origGreen; - fbcmap.blue = cmap->origBlue; - ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap); - } - pScreen->CloseScreen = cmap->CloseScreen; - xfree (cmap); - return (*pScreen->CloseScreen) (i, pScreen); -} - -Bool -xf86SbusHandleColormaps(ScreenPtr pScreen, sbusDevicePtr psdp) -{ - sbusCmapPtr cmap; - struct fbcmap fbcmap; - unsigned char data[2]; - - cmap = xnfcalloc(1, sizeof(sbusCmapRec)); - dixSetPrivate(&pScreen->devPrivates, sbusPaletteKey, cmap); - cmap->psdp = psdp; - fbcmap.index = 0; - fbcmap.count = 16; - fbcmap.red = cmap->origRed; - fbcmap.green = cmap->origGreen; - fbcmap.blue = cmap->origBlue; - if (ioctl (psdp->fd, FBIOGETCMAP, &fbcmap) >= 0) - cmap->origCmapValid = TRUE; - fbcmap.index = 0; - fbcmap.count = 2; - fbcmap.red = data; - fbcmap.green = data; - fbcmap.blue = data; - if (pScreen->whitePixel == 0) { - data[0] = 255; - data[1] = 0; - } else { - data[0] = 0; - data[1] = 255; - } - ioctl (psdp->fd, FBIOPUTCMAP, &fbcmap); - cmap->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = xf86SbusCmapCloseScreen; - return xf86HandleColormaps(pScreen, 256, 8, - xf86SbusCmapLoadPalette, NULL, 0); -} +/* + * SBUS bus-specific code. + * + * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com) + * + * 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 + * JAKUB JELINEK 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <ctype.h> +#include <stdio.h> +#include <unistd.h> +#include <X11/X.h> +#include "os.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#include "xf86cmap.h" + +#include "xf86Bus.h" + +#include "xf86sbusBus.h" +#include "xf86Sbus.h" + +Bool sbusSlotClaimed = FALSE; + +static int xf86nSbusInfo; + +static void +CheckSbusDevice(const char *device, int fbNum) +{ + int fd, i; + struct fbgattr fbattr; + sbusDevicePtr psdp; + + fd = open(device, O_RDONLY, 0); + if (fd < 0) + return; + memset(&fbattr, 0, sizeof(fbattr)); + if (ioctl(fd, FBIOGATTR, &fbattr) < 0) { + if (ioctl(fd, FBIOGTYPE, &fbattr.fbtype) < 0) { + close(fd); + return; + } + } + close(fd); + for (i = 0; sbusDeviceTable[i].devId; i++) + if (sbusDeviceTable[i].fbType == fbattr.fbtype.fb_type) + break; + if (! sbusDeviceTable[i].devId) + return; + xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (++xf86nSbusInfo + 1)); + xf86SbusInfo[xf86nSbusInfo] = NULL; + xf86SbusInfo[xf86nSbusInfo - 1] = psdp = xnfcalloc(sizeof (sbusDevice), 1); + psdp->devId = sbusDeviceTable[i].devId; + psdp->fbNum = fbNum; + psdp->device = xnfstrdup(device); + psdp->width = fbattr.fbtype.fb_width; + psdp->height = fbattr.fbtype.fb_height; + psdp->fd = -1; +} + +void +xf86SbusProbe(void) +{ + int i, useProm = 0; + char fbDevName[32]; + sbusDevicePtr psdp, *psdpp; + + xf86SbusInfo = malloc(sizeof(psdp)); + *xf86SbusInfo = NULL; + for (i = 0; i < 32; i++) { + sprintf(fbDevName, "/dev/fb%d", i); + CheckSbusDevice(fbDevName, i); + } + if (sparcPromInit() >= 0) { + useProm = 1; + sparcPromAssignNodes(); + } + for (psdpp = xf86SbusInfo; (psdp = *psdpp); psdpp++) { + for (i = 0; sbusDeviceTable[i].devId; i++) + if (sbusDeviceTable[i].devId == psdp->devId) + psdp->descr = sbusDeviceTable[i].descr; + /* + * If we can use PROM information and found the PROM node for this + * device, we can tell more about the card. + */ + if (useProm && psdp->node.node) { + char *prop, *promPath; + int len, chiprev, vmsize; + + switch (psdp->devId) { + case SBUS_DEVICE_MGX: + prop = sparcPromGetProperty(&psdp->node, "fb_size", &len); + if (prop && len == 4 && *(int *)prop == 0x400000) + psdp->descr = "Quantum 3D MGXplus with 4M VRAM"; + break; + case SBUS_DEVICE_CG6: + chiprev = 0; + vmsize = 0; + prop = sparcPromGetProperty(&psdp->node, "chiprev", &len); + if (prop && len == 4) + chiprev = *(int *)prop; + prop = sparcPromGetProperty(&psdp->node, "vmsize", &len); + if (prop && len == 4) + vmsize = *(int *)prop; + switch (chiprev) { + case 1: + case 2: + case 3: + case 4: + psdp->descr = "Sun Double width GX"; break; + case 5: + case 6: + case 7: + case 8: + case 9: + psdp->descr = "Sun Single width GX"; break; + case 11: + switch (vmsize) { + case 2: + psdp->descr = "Sun Turbo GX with 1M VSIMM"; break; + case 4: + psdp->descr = "Sun Turbo GX Plus"; break; + default: + psdp->descr = "Sun Turbo GX"; break; + } + } + break; + case SBUS_DEVICE_CG14: + prop = sparcPromGetProperty(&psdp->node, "reg", &len); + vmsize = 0; + if (prop && !(len % 12) && len > 0) + vmsize = *(int *)(prop + len - 4); + switch (vmsize) { + case 0x400000: + psdp->descr = "Sun SX with 4M VSIMM"; break; + case 0x800000: + psdp->descr = "Sun SX with 8M VSIMM"; break; + } + break; + case SBUS_DEVICE_LEO: + prop = sparcPromGetProperty(&psdp->node, "model", &len); + if (prop && len > 0 && !strstr(prop, "501-2503")) + psdp->descr = "Sun Turbo ZX"; + break; + case SBUS_DEVICE_TCX: + if (sparcPromGetBool(&psdp->node, "tcx-8-bit")) + psdp->descr = "Sun TCX (8bit)"; + else + psdp->descr = "Sun TCX (S24)"; + break; + case SBUS_DEVICE_FFB: + prop = sparcPromGetProperty(&psdp->node, "name", &len); + chiprev = 0; + prop = sparcPromGetProperty(&psdp->node, "board_type", &len); + if (prop && len == 4) + chiprev = *(int *)prop; + if (strstr (prop, "afb")) { + if (chiprev == 3) + psdp->descr = "Sun|Elite3D-M6 Horizontal"; + } else { + switch (chiprev) { + case 0x08: + psdp->descr = "Sun FFB 67MHz Creator"; break; + case 0x0b: + psdp->descr = "Sun FFB 67MHz Creator 3D"; break; + case 0x1b: + psdp->descr = "Sun FFB 75MHz Creator 3D"; break; + case 0x20: + case 0x28: + psdp->descr = "Sun FFB2 Vertical Creator"; break; + case 0x23: + case 0x2b: + psdp->descr = "Sun FFB2 Vertical Creator 3D"; break; + case 0x30: + psdp->descr = "Sun FFB2+ Vertical Creator"; break; + case 0x33: + psdp->descr = "Sun FFB2+ Vertical Creator 3D"; break; + case 0x40: + case 0x48: + psdp->descr = "Sun FFB2 Horizontal Creator"; break; + case 0x43: + case 0x4b: + psdp->descr = "Sun FFB2 Horizontal Creator 3D"; break; + } + } + break; + } + + xf86Msg(X_PROBED, "SBUS:(0x%08x) %s", psdp->node.node, psdp->descr); + promPath = sparcPromNode2Pathname (&psdp->node); + if (promPath) { + xf86ErrorF(" at %s", promPath); + free(promPath); + } + } else + xf86Msg(X_PROBED, "SBUS: %s", psdp->descr); + xf86ErrorF("\n"); + } + if (useProm) + sparcPromClose(); +} + +/* + * Parse a BUS ID string, and return the SBUS bus parameters if it was + * in the correct format for a SBUS bus id. + */ + +Bool +xf86ParseSbusBusString(const char *busID, int *fbNum) +{ + /* + * The format is assumed to be one of: + * "fbN", e.g. "fb1", which means the device corresponding to /dev/fbN + * "nameN", e.g. "cgsix0", which means Nth instance of card NAME + * "/prompath", e.g. "/sbus@0,10001000/cgsix@3,0" which is PROM pathname + * to the device. + */ + + const char *id; + int i, len; + + if (StringToBusType(busID, &id) != BUS_SBUS) + return FALSE; + + if (*id != '/') { + if (!strncmp (id, "fb", 2)) { + if (!isdigit(id[2])) + return FALSE; + *fbNum = atoi(id + 2); + return TRUE; + } else { + sbusDevicePtr *psdpp; + int devId; + + for (i = 0, len = 0; sbusDeviceTable[i].devId; i++) { + len = strlen(sbusDeviceTable[i].promName); + if (!strncmp (sbusDeviceTable[i].promName, id, len) + && isdigit(id[len])) + break; + } + devId = sbusDeviceTable[i].devId; + if (!devId) return FALSE; + i = atoi(id + len); + for (psdpp = xf86SbusInfo; *psdpp; ++psdpp) { + if ((*psdpp)->devId != devId) + continue; + if (!i) { + *fbNum = (*psdpp)->fbNum; + return TRUE; + } + i--; + } + } + return FALSE; + } + + if (sparcPromInit() >= 0) { + i = sparcPromPathname2Node(id); + sparcPromClose(); + if (i) { + sbusDevicePtr *psdpp; + for (psdpp = xf86SbusInfo; *psdpp; ++psdpp) { + if ((*psdpp)->node.node == i) { + *fbNum = (*psdpp)->fbNum; + return TRUE; + } + } + } + } + return FALSE; +} + +/* + * Compare a BUS ID string with a SBUS bus id. Return TRUE if they match. + */ + +Bool +xf86CompareSbusBusString(const char *busID, int fbNum) +{ + int iFbNum; + + if (xf86ParseSbusBusString(busID, &iFbNum)) { + return fbNum == iFbNum; + } else { + return FALSE; + } +} + +/* + * Check if the slot requested is free. If it is already in use, return FALSE. + */ + +Bool +xf86CheckSbusSlot(int fbNum) +{ + int i; + EntityPtr p; + + for (i = 0; i < xf86NumEntities; i++) { + p = xf86Entities[i]; + /* Check if this SBUS slot is taken */ + if (p->bus.type == BUS_SBUS && p->bus.id.sbus.fbNum == fbNum) + return FALSE; + } + + return TRUE; +} + +/* + * If the slot requested is already in use, return -1. + * Otherwise, claim the slot for the screen requesting it. + */ + +int +xf86ClaimSbusSlot(sbusDevicePtr psdp, DriverPtr drvp, + GDevPtr dev, Bool active) +{ + EntityPtr p = NULL; + + int num; + + if (xf86CheckSbusSlot(psdp->fbNum)) { + num = xf86AllocateEntity(); + p = xf86Entities[num]; + p->driver = drvp; + p->chipset = -1; + p->bus.type = BUS_SBUS; + xf86AddDevToEntity(num, dev); + p->bus.id.sbus.fbNum = psdp->fbNum; + p->active = active; + p->inUse = FALSE; + sbusSlotClaimed = TRUE; + return num; + } else + return -1; +} + +int +xf86MatchSbusInstances(const char *driverName, int sbusDevId, + GDevPtr *devList, int numDevs, DriverPtr drvp, + int **foundEntities) +{ + int i,j; + sbusDevicePtr psdp, *psdpp; + int numClaimedInstances = 0; + int allocatedInstances = 0; + int numFound = 0; + GDevPtr devBus = NULL; + GDevPtr dev = NULL; + int *retEntities = NULL; + int useProm = 0; + + struct Inst { + sbusDevicePtr sbus; + GDevPtr dev; + Bool claimed; /* BusID matches with a device section */ + } *instances = NULL; + + *foundEntities = NULL; + for (psdpp = xf86SbusInfo, psdp = *psdpp; psdp; psdp = *++psdpp) { + if (psdp->devId != sbusDevId) + continue; + if (psdp->fd == -2) + continue; + ++allocatedInstances; + instances = xnfrealloc(instances, + allocatedInstances * sizeof(struct Inst)); + instances[allocatedInstances - 1].sbus = psdp; + instances[allocatedInstances - 1].dev = NULL; + instances[allocatedInstances - 1].claimed = FALSE; + numFound++; + } + + /* + * This may be debatable, but if no SBUS devices with a matching vendor + * type is found, return zero now. It is probably not desirable to + * allow the config file to override this. + */ + if (allocatedInstances <= 0) { + free(instances); + return 0; + } + + if (sparcPromInit() >= 0) + useProm = 1; + + if (xf86DoConfigure && xf86DoConfigurePass1) { + GDevPtr pGDev; + int actualcards = 0; + for (i = 0; i < allocatedInstances; i++) { + actualcards++; + pGDev = xf86AddBusDeviceToConfigure(drvp->driverName, BUS_SBUS, + instances[i].sbus, -1); + if (pGDev) { + /* + * XF86Match???Instances() treat chipID and chipRev as + * overrides, so clobber them here. + */ + pGDev->chipID = pGDev->chipRev = -1; + } + } + free(instances); + if (useProm) + sparcPromClose(); + return actualcards; + } + + DebugF("%s instances found: %d\n", driverName, allocatedInstances); + + for (i = 0; i < allocatedInstances; i++) { + char *promPath = NULL; + + psdp = instances[i].sbus; + devBus = NULL; + dev = NULL; + if (useProm && psdp->node.node) + promPath = sparcPromNode2Pathname(&psdp->node); + + for (j = 0; j < numDevs; j++) { + if (devList[j]->busID && *devList[j]->busID) { + if (xf86CompareSbusBusString(devList[j]->busID, psdp->fbNum)) { + if (devBus) + xf86MsgVerb(X_WARNING,0, + "%s: More than one matching Device section for " + "instance (BusID: %s) found: %s\n", + driverName,devList[j]->identifier, + devList[j]->busID); + else + devBus = devList[j]; + } + } else { + if (!dev && !devBus) { + if (promPath) + xf86Msg(X_PROBED, "Assigning device section with no busID to SBUS:%s\n", + promPath); + else + xf86Msg(X_PROBED, "Assigning device section with no busID to SBUS:fb%d\n", + psdp->fbNum); + dev = devList[j]; + } else + xf86MsgVerb(X_WARNING, 0, + "%s: More than one matching Device section " + "found: %s\n", driverName, devList[j]->identifier); + } + } + if (devBus) dev = devBus; /* busID preferred */ + if (!dev && psdp->fd != -2) { + if (promPath) { + xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section " + "for instance (BusID SBUS:%s) found\n", + driverName, promPath); + } else + xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section " + "for instance (BusID SBUS:fb%d) found\n", + driverName, psdp->fbNum); + } else if (dev) { + numClaimedInstances++; + instances[i].claimed = TRUE; + instances[i].dev = dev; + } + if (promPath) + free(promPath); + } + + DebugF("%s instances found: %d\n", driverName, numClaimedInstances); + + /* + * Of the claimed instances, check that another driver hasn't already + * claimed its slot. + */ + numFound = 0; + for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) { + if (!instances[i].claimed) + continue; + psdp = instances[i].sbus; + if (!xf86CheckSbusSlot(psdp->fbNum)) + continue; + + DebugF("%s: card at fb%d %08x is claimed by a Device section\n", + driverName, psdp->fbNum, psdp->node.node); + + /* Allocate an entry in the lists to be returned */ + numFound++; + retEntities = xnfrealloc(retEntities, numFound * sizeof(int)); + retEntities[numFound - 1] + = xf86ClaimSbusSlot(psdp, drvp, instances[i].dev,instances[i].dev->active ? + TRUE : FALSE); + } + free(instances); + if (numFound > 0) { + *foundEntities = retEntities; + } + + if (useProm) + sparcPromClose(); + + return numFound; +} + +/* + * xf86GetSbusInfoForEntity() -- Get the sbusDevicePtr of entity. + */ +sbusDevicePtr +xf86GetSbusInfoForEntity(int entityIndex) +{ + sbusDevicePtr *psdpp; + EntityPtr p = xf86Entities[entityIndex]; + + if (entityIndex >= xf86NumEntities + || p->bus.type != BUS_SBUS) return NULL; + + for (psdpp = xf86SbusInfo; *psdpp != NULL; psdpp++) { + if (p->bus.id.sbus.fbNum == (*psdpp)->fbNum) + return (*psdpp); + } + return NULL; +} + +int +xf86GetEntityForSbusInfo(sbusDevicePtr psdp) +{ + int i; + + for (i = 0; i < xf86NumEntities; i++) { + EntityPtr p = xf86Entities[i]; + if (p->bus.type != BUS_SBUS) continue; + + if (p->bus.id.sbus.fbNum == psdp->fbNum) + return i; + } + return -1; +} + +void +xf86SbusUseBuiltinMode(ScrnInfoPtr pScrn, sbusDevicePtr psdp) +{ + DisplayModePtr mode; + + mode = xnfcalloc(sizeof(DisplayModeRec), 1); + mode->name = "current"; + mode->next = mode; + mode->prev = mode; + mode->type = M_T_BUILTIN; + mode->Clock = 100000000; + mode->HDisplay = psdp->width; + mode->HSyncStart = psdp->width; + mode->HSyncEnd = psdp->width; + mode->HTotal = psdp->width; + mode->VDisplay = psdp->height; + mode->VSyncStart = psdp->height; + mode->VSyncEnd = psdp->height; + mode->VTotal = psdp->height; + mode->SynthClock = mode->Clock; + mode->CrtcHDisplay = mode->HDisplay; + mode->CrtcHSyncStart = mode->HSyncStart; + mode->CrtcHSyncEnd = mode->HSyncEnd; + mode->CrtcHTotal = mode->HTotal; + mode->CrtcVDisplay = mode->VDisplay; + mode->CrtcVSyncStart = mode->VSyncStart; + mode->CrtcVSyncEnd = mode->VSyncEnd; + mode->CrtcVTotal = mode->VTotal; + mode->CrtcHAdjusted = FALSE; + mode->CrtcVAdjusted = FALSE; + pScrn->modes = mode; + pScrn->virtualX = psdp->width; + pScrn->virtualY = psdp->height; +} + +static sbusPaletteKeyIndex; +static DevPrivateKey sbusPaletteKey = &sbusPaletteKeyIndex; +typedef struct _sbusCmap { + sbusDevicePtr psdp; + CloseScreenProcPtr CloseScreen; + Bool origCmapValid; + unsigned char origRed[16]; + unsigned char origGreen[16]; + unsigned char origBlue[16]; +} sbusCmapRec, *sbusCmapPtr; + +#define SBUSCMAPPTR(pScreen) ((sbusCmapPtr) \ + dixLookupPrivate(&(pScreen)->devPrivates, sbusPaletteKey)) + +static void +xf86SbusCmapLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO *colors, VisualPtr pVisual) +{ + int i, index; + sbusCmapPtr cmap; + struct fbcmap fbcmap; + unsigned char *data = malloc(numColors*3); + + cmap = SBUSCMAPPTR(pScrn->pScreen); + if (!cmap) return; + fbcmap.count = 0; + fbcmap.index = indices[0]; + fbcmap.red = data; + fbcmap.green = data + numColors; + fbcmap.blue = fbcmap.green + numColors; + for (i = 0; i < numColors; i++) { + index = indices[i]; + if (fbcmap.count && index != fbcmap.index + fbcmap.count) { + ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap); + fbcmap.count = 0; + fbcmap.index = index; + } + fbcmap.red[fbcmap.count] = colors[index].red; + fbcmap.green[fbcmap.count] = colors[index].green; + fbcmap.blue[fbcmap.count++] = colors[index].blue; + } + ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap); + free(data); +} + +static Bool +xf86SbusCmapCloseScreen(int i, ScreenPtr pScreen) +{ + sbusCmapPtr cmap; + struct fbcmap fbcmap; + + cmap = SBUSCMAPPTR(pScreen); + if (cmap->origCmapValid) { + fbcmap.index = 0; + fbcmap.count = 16; + fbcmap.red = cmap->origRed; + fbcmap.green = cmap->origGreen; + fbcmap.blue = cmap->origBlue; + ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap); + } + pScreen->CloseScreen = cmap->CloseScreen; + free(cmap); + return (*pScreen->CloseScreen) (i, pScreen); +} + +Bool +xf86SbusHandleColormaps(ScreenPtr pScreen, sbusDevicePtr psdp) +{ + sbusCmapPtr cmap; + struct fbcmap fbcmap; + unsigned char data[2]; + + cmap = xnfcalloc(1, sizeof(sbusCmapRec)); + dixSetPrivate(&pScreen->devPrivates, sbusPaletteKey, cmap); + cmap->psdp = psdp; + fbcmap.index = 0; + fbcmap.count = 16; + fbcmap.red = cmap->origRed; + fbcmap.green = cmap->origGreen; + fbcmap.blue = cmap->origBlue; + if (ioctl (psdp->fd, FBIOGETCMAP, &fbcmap) >= 0) + cmap->origCmapValid = TRUE; + fbcmap.index = 0; + fbcmap.count = 2; + fbcmap.red = data; + fbcmap.green = data; + fbcmap.blue = data; + if (pScreen->whitePixel == 0) { + data[0] = 255; + data[1] = 0; + } else { + data[0] = 0; + data[1] = 255; + } + ioctl (psdp->fd, FBIOPUTCMAP, &fbcmap); + cmap->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = xf86SbusCmapCloseScreen; + return xf86HandleColormaps(pScreen, 256, 8, + xf86SbusCmapLoadPalette, NULL, 0); +} diff --git a/xorg-server/hw/xfree86/common/xf86xv.c b/xorg-server/hw/xfree86/common/xf86xv.c index 2cc2f6093..e35b8d667 100644 --- a/xorg-server/hw/xfree86/common/xf86xv.c +++ b/xorg-server/hw/xfree86/common/xf86xv.c @@ -1,2101 +1,2102 @@ -/* - * XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com) - */ -/* - * Copyright (c) 1998-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "scrnintstr.h" -#include "regionstr.h" -#include "windowstr.h" -#include "pixmapstr.h" -#include "mivalidate.h" -#include "validate.h" -#include "resource.h" -#include "gcstruct.h" -#include "dixstruct.h" - -#include <X11/extensions/Xv.h> -#include <X11/extensions/Xvproto.h> -#include "xvdix.h" -#include "xvmodproc.h" - -#include "xf86xvpriv.h" - - -/* XvScreenRec fields */ - -static Bool xf86XVCloseScreen(int, ScreenPtr); -static int xf86XVQueryAdaptors(ScreenPtr, XvAdaptorPtr *, int *); - -/* XvAdaptorRec fields */ - -static int xf86XVAllocatePort(unsigned long, XvPortPtr, XvPortPtr*); -static int xf86XVFreePort(XvPortPtr); -static int xf86XVPutVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int xf86XVPutStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int xf86XVGetVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int xf86XVGetStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int xf86XVStopVideo(ClientPtr, XvPortPtr, DrawablePtr); -static int xf86XVSetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32); -static int xf86XVGetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32*); -static int xf86XVQueryBestSize(ClientPtr, XvPortPtr, CARD8, - CARD16, CARD16,CARD16, CARD16, - unsigned int*, unsigned int*); -static int xf86XVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16, - XvImagePtr, unsigned char*, Bool, - CARD16, CARD16); -static int xf86XVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr, - CARD16*, CARD16*, int*, int*); - - -/* ScreenRec fields */ - -static Bool xf86XVDestroyWindow(WindowPtr pWin); -static void xf86XVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2); -static void xf86XVClipNotify(WindowPtr pWin, int dx, int dy); - -/* ScrnInfoRec functions */ - -static Bool xf86XVEnterVT(int, int); -static void xf86XVLeaveVT(int, int); -static void xf86XVAdjustFrame(int index, int x, int y, int flags); - -/* misc */ - -static Bool xf86XVInitAdaptors(ScreenPtr, XF86VideoAdaptorPtr*, int); - - -static int XF86XVWindowKeyIndex; -static DevPrivateKey XF86XVWindowKey = &XF86XVWindowKeyIndex; -static int XF86XvScreenKeyIndex; -DevPrivateKey XF86XvScreenKey = &XF86XvScreenKeyIndex; -static unsigned long PortResource = 0; - -DevPrivateKey (*XvGetScreenKeyProc)(void) = NULL; -unsigned long (*XvGetRTPortProc)(void) = NULL; -int (*XvScreenInitProc)(ScreenPtr) = NULL; - -#define GET_XV_SCREEN(pScreen) \ - ((XvScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, XF86XvScreenKey)) - -#define GET_XF86XV_SCREEN(pScreen) \ - ((XF86XVScreenPtr)(GET_XV_SCREEN(pScreen)->devPriv.ptr)) - -#define GET_XF86XV_WINDOW(pWin) \ - ((XF86XVWindowPtr)dixLookupPrivate(&(pWin)->devPrivates, XF86XVWindowKey)) - -static xf86XVInitGenericAdaptorPtr *GenDrivers = NULL; -static int NumGenDrivers = 0; - -int -xf86XVRegisterGenericAdaptorDriver( - xf86XVInitGenericAdaptorPtr InitFunc -){ - xf86XVInitGenericAdaptorPtr *newdrivers; - - newdrivers = xrealloc(GenDrivers, sizeof(xf86XVInitGenericAdaptorPtr) * - (1 + NumGenDrivers)); - if (!newdrivers) - return 0; - GenDrivers = newdrivers; - - GenDrivers[NumGenDrivers++] = InitFunc; - - return 1; -} - -int -xf86XVListGenericAdaptors( - ScrnInfoPtr pScrn, - XF86VideoAdaptorPtr **adaptors -){ - int i,j,n,num; - XF86VideoAdaptorPtr *DrivAdap,*new; - - num = 0; - *adaptors = NULL; - /* - * The v4l driver registers itself first, but can use surfaces registered - * by other drivers. So, call the v4l driver last. - */ - for (i = NumGenDrivers; --i >= 0; ) { - DrivAdap = NULL; - n = (*GenDrivers[i])(pScrn, &DrivAdap); - if (0 == n) - continue; - new = xrealloc(*adaptors, sizeof(XF86VideoAdaptorPtr) * (num+n)); - if (NULL == new) - continue; - *adaptors = new; - for (j = 0; j < n; j++, num++) - (*adaptors)[num] = DrivAdap[j]; - } - return num; -} - - -/**************** Offscreen surface stuff *******************/ - -typedef struct { - XF86OffscreenImagePtr images; - int num; -} OffscreenImageRec; - -static int OffscreenPrivateKeyIndex; -static DevPrivateKey OffscreenPrivateKey = &OffscreenPrivateKeyIndex; -#define GetOffscreenImage(pScreen) ((OffscreenImageRec *) dixLookupPrivate(&(pScreen)->devPrivates, OffscreenPrivateKey)) - -Bool -xf86XVRegisterOffscreenImages( - ScreenPtr pScreen, - XF86OffscreenImagePtr images, - int num -){ - OffscreenImageRec *OffscreenImage; - /* This function may be called before xf86XVScreenInit, so there's - * no better place than this to call dixRequestPrivate to ensure we - * have space reserved. After the first call it is a no-op. */ - if(!dixRequestPrivate(OffscreenPrivateKey, sizeof(OffscreenImageRec)) || - !(OffscreenImage = GetOffscreenImage(pScreen))) - /* Every X.org driver assumes this function always succeeds, so - * just die on allocation failure. */ - FatalError("Could not allocate private storage for XV offscreen images.\n"); - - OffscreenImage->num = num; - OffscreenImage->images = images; - return TRUE; -} - -XF86OffscreenImagePtr -xf86XVQueryOffscreenImages( - ScreenPtr pScreen, - int *num -){ - OffscreenImageRec *OffscreenImage = GetOffscreenImage(pScreen); - *num = OffscreenImage->num; - return OffscreenImage->images; -} - - -XF86VideoAdaptorPtr -xf86XVAllocateVideoAdaptorRec(ScrnInfoPtr pScrn) -{ - return xcalloc(1, sizeof(XF86VideoAdaptorRec)); -} - -void -xf86XVFreeVideoAdaptorRec(XF86VideoAdaptorPtr ptr) -{ - xfree(ptr); -} - - -Bool -xf86XVScreenInit( - ScreenPtr pScreen, - XF86VideoAdaptorPtr *adaptors, - int num -){ - ScrnInfoPtr pScrn; - XF86XVScreenPtr ScreenPriv; - XvScreenPtr pxvs; - - if(num <= 0 || - !XvGetScreenKeyProc || !XvGetRTPortProc || !XvScreenInitProc) - return FALSE; - - if(Success != (*XvScreenInitProc)(pScreen)) return FALSE; - - XF86XvScreenKey = (*XvGetScreenKeyProc)(); - PortResource = (*XvGetRTPortProc)(); - - pxvs = GET_XV_SCREEN(pScreen); - - /* Anyone initializing the Xv layer must provide these two. - The Xv di layer calls them without even checking if they exist! */ - - pxvs->ddCloseScreen = xf86XVCloseScreen; - pxvs->ddQueryAdaptors = xf86XVQueryAdaptors; - - /* The Xv di layer provides us with a private hook so that we don't - have to allocate our own screen private. They also provide - a CloseScreen hook so that we don't have to wrap it. I'm not - sure that I appreciate that. */ - - ScreenPriv = xalloc(sizeof(XF86XVScreenRec)); - pxvs->devPriv.ptr = (pointer)ScreenPriv; - - if(!ScreenPriv) return FALSE; - - pScrn = xf86Screens[pScreen->myNum]; - - ScreenPriv->videoGC = NULL; /* for the helper */ - - ScreenPriv->DestroyWindow = pScreen->DestroyWindow; - ScreenPriv->WindowExposures = pScreen->WindowExposures; - ScreenPriv->ClipNotify = pScreen->ClipNotify; - ScreenPriv->EnterVT = pScrn->EnterVT; - ScreenPriv->LeaveVT = pScrn->LeaveVT; - ScreenPriv->AdjustFrame = pScrn->AdjustFrame; - - pScreen->DestroyWindow = xf86XVDestroyWindow; - pScreen->WindowExposures = xf86XVWindowExposures; - pScreen->ClipNotify = xf86XVClipNotify; - pScrn->EnterVT = xf86XVEnterVT; - pScrn->LeaveVT = xf86XVLeaveVT; - if(pScrn->AdjustFrame) - pScrn->AdjustFrame = xf86XVAdjustFrame; - - if(!xf86XVInitAdaptors(pScreen, adaptors, num)) - return FALSE; - - return TRUE; -} - -static void -xf86XVFreeAdaptor(XvAdaptorPtr pAdaptor) -{ - int i; - - xfree(pAdaptor->name); - - if(pAdaptor->pEncodings) { - XvEncodingPtr pEncode = pAdaptor->pEncodings; - - for(i = 0; i < pAdaptor->nEncodings; i++, pEncode++) - xfree(pEncode->name); - xfree(pAdaptor->pEncodings); - } - - xfree(pAdaptor->pFormats); - - if(pAdaptor->pPorts) { - XvPortPtr pPort = pAdaptor->pPorts; - XvPortRecPrivatePtr pPriv; - - for(i = 0; i < pAdaptor->nPorts; i++, pPort++) { - pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; - if(pPriv) { - if(pPriv->clientClip) - REGION_DESTROY(pAdaptor->pScreen, pPriv->clientClip); - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pAdaptor->pScreen, pPriv->pCompositeClip); - xfree(pPriv); - } - } - xfree(pAdaptor->pPorts); - } - - if(pAdaptor->nAttributes) { - XvAttributePtr pAttribute = pAdaptor->pAttributes; - - for(i = 0; i < pAdaptor->nAttributes; i++, pAttribute++) - xfree(pAttribute->name); - xfree(pAdaptor->pAttributes); - } - - xfree(pAdaptor->pImages); - xfree(pAdaptor->devPriv.ptr); -} - -static Bool -xf86XVInitAdaptors( - ScreenPtr pScreen, - XF86VideoAdaptorPtr *infoPtr, - int number -) { - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - XF86VideoAdaptorPtr adaptorPtr; - XvAdaptorPtr pAdaptor, pa; - XvAdaptorRecPrivatePtr adaptorPriv; - int na, numAdaptor; - XvPortRecPrivatePtr portPriv; - XvPortPtr pPort, pp; - int numPort; - XF86AttributePtr attributePtr; - XvAttributePtr pAttribute, pat; - XF86VideoFormatPtr formatPtr; - XvFormatPtr pFormat, pf; - int numFormat, totFormat; - XF86VideoEncodingPtr encodingPtr; - XvEncodingPtr pEncode, pe; - XF86ImagePtr imagePtr; - XvImagePtr pImage, pi; - int numVisuals; - VisualPtr pVisual; - int i; - - pxvs->nAdaptors = 0; - pxvs->pAdaptors = NULL; - - if(!(pAdaptor = xcalloc(number, sizeof(XvAdaptorRec)))) - return FALSE; - - for(pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) { - adaptorPtr = infoPtr[na]; - - if(!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute || - !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize) - continue; - - /* client libs expect at least one encoding */ - if(!adaptorPtr->nEncodings || !adaptorPtr->pEncodings) - continue; - - pa->type = adaptorPtr->type; - - if(!adaptorPtr->PutVideo && !adaptorPtr->GetVideo) - pa->type &= ~XvVideoMask; - - if(!adaptorPtr->PutStill && !adaptorPtr->GetStill) - pa->type &= ~XvStillMask; - - if(!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes) - pa->type &= ~XvImageMask; - - if(!adaptorPtr->PutVideo && !adaptorPtr->PutImage && - !adaptorPtr->PutStill) - pa->type &= ~XvInputMask; - - if(!adaptorPtr->GetVideo && !adaptorPtr->GetStill) - pa->type &= ~XvOutputMask; - - if(!(adaptorPtr->type & (XvPixmapMask | XvWindowMask))) - continue; - if(!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask))) - continue; - - pa->pScreen = pScreen; - pa->ddAllocatePort = xf86XVAllocatePort; - pa->ddFreePort = xf86XVFreePort; - pa->ddPutVideo = xf86XVPutVideo; - pa->ddPutStill = xf86XVPutStill; - pa->ddGetVideo = xf86XVGetVideo; - pa->ddGetStill = xf86XVGetStill; - pa->ddStopVideo = xf86XVStopVideo; - pa->ddPutImage = xf86XVPutImage; - pa->ddSetPortAttribute = xf86XVSetPortAttribute; - pa->ddGetPortAttribute = xf86XVGetPortAttribute; - pa->ddQueryBestSize = xf86XVQueryBestSize; - pa->ddQueryImageAttributes = xf86XVQueryImageAttributes; - if((pa->name = xalloc(strlen(adaptorPtr->name) + 1))) - strcpy(pa->name, adaptorPtr->name); - - if(adaptorPtr->nEncodings && - (pEncode = xcalloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) { - - for(pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0; - i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) - { - pe->id = encodingPtr->id; - pe->pScreen = pScreen; - if((pe->name = xalloc(strlen(encodingPtr->name) + 1))) - strcpy(pe->name, encodingPtr->name); - pe->width = encodingPtr->width; - pe->height = encodingPtr->height; - pe->rate.numerator = encodingPtr->rate.numerator; - pe->rate.denominator = encodingPtr->rate.denominator; - } - pa->nEncodings = adaptorPtr->nEncodings; - pa->pEncodings = pEncode; - } - - if(adaptorPtr->nImages && - (pImage = xcalloc(adaptorPtr->nImages, sizeof(XvImageRec)))) { - - for(i = 0, pi = pImage, imagePtr = adaptorPtr->pImages; - i < adaptorPtr->nImages; i++, pi++, imagePtr++) - { - pi->id = imagePtr->id; - pi->type = imagePtr->type; - pi->byte_order = imagePtr->byte_order; - memcpy(pi->guid, imagePtr->guid, 16); - pi->bits_per_pixel = imagePtr->bits_per_pixel; - pi->format = imagePtr->format; - pi->num_planes = imagePtr->num_planes; - pi->depth = imagePtr->depth; - pi->red_mask = imagePtr->red_mask; - pi->green_mask = imagePtr->green_mask; - pi->blue_mask = imagePtr->blue_mask; - pi->y_sample_bits = imagePtr->y_sample_bits; - pi->u_sample_bits = imagePtr->u_sample_bits; - pi->v_sample_bits = imagePtr->v_sample_bits; - pi->horz_y_period = imagePtr->horz_y_period; - pi->horz_u_period = imagePtr->horz_u_period; - pi->horz_v_period = imagePtr->horz_v_period; - pi->vert_y_period = imagePtr->vert_y_period; - pi->vert_u_period = imagePtr->vert_u_period; - pi->vert_v_period = imagePtr->vert_v_period; - memcpy(pi->component_order, imagePtr->component_order, 32); - pi->scanline_order = imagePtr->scanline_order; - } - pa->nImages = adaptorPtr->nImages; - pa->pImages = pImage; - } - - if(adaptorPtr->nAttributes && - (pAttribute = xcalloc(adaptorPtr->nAttributes, sizeof(XvAttributeRec)))) - { - for(pat = pAttribute, attributePtr = adaptorPtr->pAttributes, i = 0; - i < adaptorPtr->nAttributes; pat++, i++, attributePtr++) - { - pat->flags = attributePtr->flags; - pat->min_value = attributePtr->min_value; - pat->max_value = attributePtr->max_value; - if((pat->name = xalloc(strlen(attributePtr->name) + 1))) - strcpy(pat->name, attributePtr->name); - } - pa->nAttributes = adaptorPtr->nAttributes; - pa->pAttributes = pAttribute; - } - - - totFormat = adaptorPtr->nFormats; - - if(!(pFormat = xcalloc(totFormat, sizeof(XvFormatRec)))) { - xf86XVFreeAdaptor(pa); - continue; - } - for(pf = pFormat, i = 0, numFormat = 0, formatPtr = adaptorPtr->pFormats; - i < adaptorPtr->nFormats; i++, formatPtr++) - { - numVisuals = pScreen->numVisuals; - pVisual = pScreen->visuals; - - while(numVisuals--) { - if((pVisual->class == formatPtr->class) && - (pVisual->nplanes == formatPtr->depth)) { - - if(numFormat >= totFormat) { - void *moreSpace; - totFormat *= 2; - moreSpace = xrealloc(pFormat, - totFormat * sizeof(XvFormatRec)); - if(!moreSpace) break; - pFormat = moreSpace; - pf = pFormat + numFormat; - } - - pf->visual = pVisual->vid; - pf->depth = formatPtr->depth; - - pf++; - numFormat++; - } - pVisual++; - } - } - pa->nFormats = numFormat; - pa->pFormats = pFormat; - if(!numFormat) { - xf86XVFreeAdaptor(pa); - continue; - } - - if(!(adaptorPriv = xcalloc(1, sizeof(XvAdaptorRecPrivate)))) { - xf86XVFreeAdaptor(pa); - continue; - } - - adaptorPriv->flags = adaptorPtr->flags; - adaptorPriv->PutVideo = adaptorPtr->PutVideo; - adaptorPriv->PutStill = adaptorPtr->PutStill; - adaptorPriv->GetVideo = adaptorPtr->GetVideo; - adaptorPriv->GetStill = adaptorPtr->GetStill; - adaptorPriv->StopVideo = adaptorPtr->StopVideo; - adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute; - adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute; - adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize; - adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes; - adaptorPriv->PutImage = adaptorPtr->PutImage; - adaptorPriv->ReputImage = adaptorPtr->ReputImage; - - pa->devPriv.ptr = (pointer)adaptorPriv; - - if(!(pPort = xcalloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) { - xf86XVFreeAdaptor(pa); - continue; - } - for(pp = pPort, i = 0, numPort = 0; - i < adaptorPtr->nPorts; i++) { - - if(!(pp->id = FakeClientID(0))) - continue; - - if(!(portPriv = xcalloc(1, sizeof(XvPortRecPrivate)))) - continue; - - if(!AddResource(pp->id, PortResource, pp)) { - xfree(portPriv); - continue; - } - - pp->pAdaptor = pa; - pp->pNotify = (XvPortNotifyPtr)NULL; - pp->pDraw = (DrawablePtr)NULL; - pp->client = (ClientPtr)NULL; - pp->grab.client = (ClientPtr)NULL; - pp->time = currentTime; - pp->devPriv.ptr = portPriv; - - portPriv->pScrn = pScrn; - portPriv->AdaptorRec = adaptorPriv; - portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr; - - pp++; - numPort++; - } - pa->nPorts = numPort; - pa->pPorts = pPort; - if(!numPort) { - xf86XVFreeAdaptor(pa); - continue; - } - - pa->base_id = pPort->id; - - pa++; - numAdaptor++; - } - - if(numAdaptor) { - pxvs->nAdaptors = numAdaptor; - pxvs->pAdaptors = pAdaptor; - } else { - xfree(pAdaptor); - return FALSE; - } - - return TRUE; -} - -/* Video should be clipped to the intersection of the window cliplist - and the client cliplist specified in the GC for which the video was - initialized. When we need to reclip a window, the GC that started - the video may not even be around anymore. That's why we save the - client clip from the GC when the video is initialized. We then - use xf86XVUpdateCompositeClip to calculate the new composite clip - when we need it. This is different from what DEC did. They saved - the GC and used it's clip list when they needed to reclip the window, - even if the client clip was different from the one the video was - initialized with. If the original GC was destroyed, they had to stop - the video. I like the new method better (MArk). - - This function only works for windows. Will need to rewrite when - (if) we support pixmap rendering. -*/ - -static void -xf86XVUpdateCompositeClip(XvPortRecPrivatePtr portPriv) -{ - RegionPtr pregWin, pCompositeClip; - WindowPtr pWin; - ScreenPtr pScreen; - Bool freeCompClip = FALSE; - - if(portPriv->pCompositeClip) - return; - - pWin = (WindowPtr)portPriv->pDraw; - pScreen = pWin->drawable.pScreen; - - /* get window clip list */ - if(portPriv->subWindowMode == IncludeInferiors) { - pregWin = NotClippedByChildren(pWin); - freeCompClip = TRUE; - } else - pregWin = &pWin->clipList; - - if(!portPriv->clientClip) { - portPriv->pCompositeClip = pregWin; - portPriv->FreeCompositeClip = freeCompClip; - return; - } - - pCompositeClip = REGION_CREATE(pScreen, NullBox, 1); - REGION_COPY(pScreen, pCompositeClip, portPriv->clientClip); - REGION_TRANSLATE(pScreen, pCompositeClip, - portPriv->pDraw->x + portPriv->clipOrg.x, - portPriv->pDraw->y + portPriv->clipOrg.y); - REGION_INTERSECT(pScreen, pCompositeClip, pregWin, pCompositeClip); - - portPriv->pCompositeClip = pCompositeClip; - portPriv->FreeCompositeClip = TRUE; - - if(freeCompClip) { - REGION_DESTROY(pScreen, pregWin); - } -} - -/* Save the current clientClip and update the CompositeClip whenever - we have a fresh GC */ - -static void -xf86XVCopyClip( - XvPortRecPrivatePtr portPriv, - GCPtr pGC -){ - /* copy the new clip if it exists */ - if((pGC->clientClipType == CT_REGION) && pGC->clientClip) { - if(!portPriv->clientClip) - portPriv->clientClip = REGION_CREATE(pScreen, NullBox, 1); - /* Note: this is in window coordinates */ - REGION_COPY(pScreen, portPriv->clientClip, pGC->clientClip); - } else if(portPriv->clientClip) { /* free the old clientClip */ - REGION_DESTROY(pScreen, portPriv->clientClip); - portPriv->clientClip = NULL; - } - - /* get rid of the old clip list */ - if(portPriv->pCompositeClip && portPriv->FreeCompositeClip) { - REGION_DESTROY(pScreen, portPriv->pCompositeClip); - } - - portPriv->clipOrg = pGC->clipOrg; - portPriv->pCompositeClip = pGC->pCompositeClip; - portPriv->FreeCompositeClip = FALSE; - portPriv->subWindowMode = pGC->subWindowMode; -} - -static int -xf86XVRegetVideo(XvPortRecPrivatePtr portPriv) -{ - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - ScreenPtr pScreen; - int ret = Success; - Bool clippedAway = FALSE; - - pScreen = portPriv->pDraw->pScreen; - xf86XVUpdateCompositeClip(portPriv); - - /* translate the video region to the screen */ - WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; - WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; - WinBox.x2 = WinBox.x1 + portPriv->drw_w; - WinBox.y2 = WinBox.y1 + portPriv->drw_h; - - /* clip to the window composite clip */ - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_NULL(pScreen, &ClipRegion); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); - - /* that's all if it's totally obscured */ - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->GetVideo)(portPriv->pScrn, - portPriv->vid_x, portPriv->vid_y, - WinBox.x1, WinBox.y1, - portPriv->vid_w, portPriv->vid_h, - portPriv->drw_w, portPriv->drw_h, - &ClipRegion, portPriv->DevPriv.ptr, - portPriv->pDraw); - - if(ret == Success) - portPriv->isOn = XV_ON; - -CLIP_VIDEO_BAILOUT: - - if((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - /* This clip was copied and only good for one shot */ - if(!portPriv->FreeCompositeClip) - portPriv->pCompositeClip = NULL; - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - -static int -xf86XVReputVideo(XvPortRecPrivatePtr portPriv) -{ - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - ScreenPtr pScreen; - int ret = Success; - Bool clippedAway = FALSE; - - pScreen = portPriv->pDraw->pScreen; - - xf86XVUpdateCompositeClip(portPriv); - - /* translate the video region to the screen */ - WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; - WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; - WinBox.x2 = WinBox.x1 + portPriv->drw_w; - WinBox.y2 = WinBox.y1 + portPriv->drw_h; - - /* clip to the window composite clip */ - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_NULL(pScreen, &ClipRegion); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); - - /* clip and translate to the viewport */ - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = portPriv->pScrn->frameX0; - VPBox.y1 = portPriv->pScrn->frameY0; - VPBox.x2 = portPriv->pScrn->frameX1 + 1; - VPBox.y2 = portPriv->pScrn->frameY1 + 1; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - /* that's all if it's totally obscured */ - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - - /* bailout if we have to clip but the hardware doesn't support it */ - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->PutVideo)(portPriv->pScrn, - portPriv->vid_x, portPriv->vid_y, - WinBox.x1, WinBox.y1, - portPriv->vid_w, portPriv->vid_h, - portPriv->drw_w, portPriv->drw_h, - &ClipRegion, portPriv->DevPriv.ptr, - portPriv->pDraw); - - if(ret == Success) portPriv->isOn = XV_ON; - -CLIP_VIDEO_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - /* This clip was copied and only good for one shot */ - if(!portPriv->FreeCompositeClip) - portPriv->pCompositeClip = NULL; - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - -static int -xf86XVReputImage(XvPortRecPrivatePtr portPriv) -{ - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - ScreenPtr pScreen; - int ret = Success; - Bool clippedAway = FALSE; - - pScreen = portPriv->pDraw->pScreen; - - xf86XVUpdateCompositeClip(portPriv); - - /* translate the video region to the screen */ - WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; - WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; - WinBox.x2 = WinBox.x1 + portPriv->drw_w; - WinBox.y2 = WinBox.y1 + portPriv->drw_h; - - /* clip to the window composite clip */ - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_NULL(pScreen, &ClipRegion); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); - - /* clip and translate to the viewport */ - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = portPriv->pScrn->frameX0; - VPBox.y1 = portPriv->pScrn->frameY0; - VPBox.x2 = portPriv->pScrn->frameX1 + 1; - VPBox.y2 = portPriv->pScrn->frameY1 + 1; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - /* that's all if it's totally obscured */ - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - - /* bailout if we have to clip but the hardware doesn't support it */ - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->ReputImage)(portPriv->pScrn, - WinBox.x1, WinBox.y1, - &ClipRegion, portPriv->DevPriv.ptr, - portPriv->pDraw); - - portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF; - -CLIP_VIDEO_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - /* This clip was copied and only good for one shot */ - if(!portPriv->FreeCompositeClip) - portPriv->pCompositeClip = NULL; - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - -static int -xf86XVReputAllVideo(WindowPtr pWin, pointer data) -{ - XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); - - while(WinPriv) { - if(WinPriv->PortRec->type == XvInputMask) - xf86XVReputVideo(WinPriv->PortRec); - else - xf86XVRegetVideo(WinPriv->PortRec); - WinPriv = WinPriv->next; - } - - return WT_WALKCHILDREN; -} - -static int -xf86XVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) -{ - XF86XVWindowPtr winPriv, PrivRoot; - - winPriv = PrivRoot = GET_XF86XV_WINDOW(pWin); - - /* Enlist our port in the window private */ - while(winPriv) { - if(winPriv->PortRec == portPriv) /* we're already listed */ - break; - winPriv = winPriv->next; - } - - if(!winPriv) { - winPriv = xcalloc(1, sizeof(XF86XVWindowRec)); - if(!winPriv) return BadAlloc; - winPriv->PortRec = portPriv; - winPriv->next = PrivRoot; - dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, winPriv); - } - - portPriv->pDraw = (DrawablePtr)pWin; - - return Success; -} - - -static void -xf86XVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) -{ - XF86XVWindowPtr winPriv, prevPriv = NULL; - - winPriv = GET_XF86XV_WINDOW(pWin); - - while(winPriv) { - if(winPriv->PortRec == portPriv) { - if(prevPriv) - prevPriv->next = winPriv->next; - else - dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, - winPriv->next); - xfree(winPriv); - break; - } - prevPriv = winPriv; - winPriv = winPriv->next; - } - portPriv->pDraw = NULL; -} - -/**** ScreenRec fields ****/ - -static Bool -xf86XVDestroyWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); - XF86XVWindowPtr tmp, WinPriv = GET_XF86XV_WINDOW(pWin); - int ret; - - while(WinPriv) { - XvPortRecPrivatePtr pPriv = WinPriv->PortRec; - - if(pPriv->isOn > XV_OFF) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->pScrn, pPriv->DevPriv.ptr, TRUE); - pPriv->isOn = XV_OFF; - } - - pPriv->pDraw = NULL; - tmp = WinPriv; - if(WinPriv->pGC) { - FreeGC(WinPriv->pGC, 0); - } - WinPriv = WinPriv->next; - xfree(tmp); - } - - dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, NULL); - - pScreen->DestroyWindow = ScreenPriv->DestroyWindow; - ret = (*pScreen->DestroyWindow)(pWin); - pScreen->DestroyWindow = xf86XVDestroyWindow; - - return ret; -} - - -static void -xf86XVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); - XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); - XF86XVWindowPtr pPrev; - XvPortRecPrivatePtr pPriv; - Bool AreasExposed; - - AreasExposed = (WinPriv && reg1 && REGION_NOTEMPTY(pScreen, reg1)); - - pScreen->WindowExposures = ScreenPriv->WindowExposures; - (*pScreen->WindowExposures)(pWin, reg1, reg2); - pScreen->WindowExposures = xf86XVWindowExposures; - - /* filter out XClearWindow/Area */ - if (!pWin->valdata) return; - - pPrev = NULL; - - while(WinPriv) { - pPriv = WinPriv->PortRec; - - /* Reput anyone with a reput function */ - - switch(pPriv->type) { - case XvInputMask: - xf86XVReputVideo(pPriv); - break; - case XvOutputMask: - xf86XVRegetVideo(pPriv); - break; - default: /* overlaid still/image*/ - if (pPriv->AdaptorRec->ReputImage) - xf86XVReputImage(pPriv); - else if(AreasExposed) { - XF86XVWindowPtr tmp; - - if (pPriv->isOn == XV_ON) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->pScrn, pPriv->DevPriv.ptr, FALSE); - pPriv->isOn = XV_PENDING; - } - pPriv->pDraw = NULL; - - if(!pPrev) - dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, - WinPriv->next); - else - pPrev->next = WinPriv->next; - tmp = WinPriv; - WinPriv = WinPriv->next; - xfree(tmp); - continue; - } - break; - } - pPrev = WinPriv; - WinPriv = WinPriv->next; - } -} - - -static void -xf86XVClipNotify(WindowPtr pWin, int dx, int dy) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); - XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); - XF86XVWindowPtr tmp, pPrev = NULL; - XvPortRecPrivatePtr pPriv; - Bool visible = (pWin->visibility == VisibilityUnobscured) || - (pWin->visibility == VisibilityPartiallyObscured); - - while(WinPriv) { - pPriv = WinPriv->PortRec; - - if(!pPriv) goto next; - - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pScreen, pPriv->pCompositeClip); - - pPriv->pCompositeClip = NULL; - - if (pPriv->AdaptorRec->ClipNotify) - (*pPriv->AdaptorRec->ClipNotify)(pPriv->pScrn, pPriv->DevPriv.ptr, - pWin, dx, dy); - - /* Stop everything except images, but stop them too if the - window isn't visible. But we only remove the images. */ - - if(pPriv->type || !visible) { - if(pPriv->isOn == XV_ON) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->pScrn, pPriv->DevPriv.ptr, FALSE); - pPriv->isOn = XV_PENDING; - } - - if(!pPriv->type) { /* overlaid still/image */ - pPriv->pDraw = NULL; - - if(!pPrev) - dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, - WinPriv->next); - else - pPrev->next = WinPriv->next; - tmp = WinPriv; - WinPriv = WinPriv->next; - xfree(tmp); - continue; - } - } - -next: - pPrev = WinPriv; - WinPriv = WinPriv->next; - } - - if(ScreenPriv->ClipNotify) { - pScreen->ClipNotify = ScreenPriv->ClipNotify; - (*pScreen->ClipNotify)(pWin, dx, dy); - pScreen->ClipNotify = xf86XVClipNotify; - } -} - - - -/**** Required XvScreenRec fields ****/ - -static Bool -xf86XVCloseScreen(int i, ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); - XvAdaptorPtr pa; - int c; - - if(!ScreenPriv) return TRUE; - - if(ScreenPriv->videoGC) { - FreeGC(ScreenPriv->videoGC, 0); - ScreenPriv->videoGC = NULL; - } - - pScreen->DestroyWindow = ScreenPriv->DestroyWindow; - pScreen->WindowExposures = ScreenPriv->WindowExposures; - pScreen->ClipNotify = ScreenPriv->ClipNotify; - - pScrn->EnterVT = ScreenPriv->EnterVT; - pScrn->LeaveVT = ScreenPriv->LeaveVT; - pScrn->AdjustFrame = ScreenPriv->AdjustFrame; - - for(c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) { - xf86XVFreeAdaptor(pa); - } - - xfree(pxvs->pAdaptors); - xfree(ScreenPriv); - return TRUE; -} - - -static int -xf86XVQueryAdaptors( - ScreenPtr pScreen, - XvAdaptorPtr *p_pAdaptors, - int *p_nAdaptors -){ - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - - *p_nAdaptors = pxvs->nAdaptors; - *p_pAdaptors = pxvs->pAdaptors; - - return (Success); -} - - -/**** ScrnInfoRec fields ****/ - -static Bool -xf86XVEnterVT(int index, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); - Bool ret; - - ret = (*ScreenPriv->EnterVT)(index, flags); - - if(ret) WalkTree(pScreen, xf86XVReputAllVideo, 0); - - return ret; -} - -static void -xf86XVLeaveVT(int index, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); - XvAdaptorPtr pAdaptor; - XvPortPtr pPort; - XvPortRecPrivatePtr pPriv; - int i, j; - - for(i = 0; i < pxvs->nAdaptors; i++) { - pAdaptor = &pxvs->pAdaptors[i]; - for(j = 0; j < pAdaptor->nPorts; j++) { - pPort = &pAdaptor->pPorts[j]; - pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; - if(pPriv->isOn > XV_OFF) { - - (*pPriv->AdaptorRec->StopVideo)( - pPriv->pScrn, pPriv->DevPriv.ptr, TRUE); - pPriv->isOn = XV_OFF; - - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pScreen, pPriv->pCompositeClip); - - pPriv->pCompositeClip = NULL; - - if(!pPriv->type && pPriv->pDraw) { /* still */ - xf86XVRemovePortFromWindow((WindowPtr)pPriv->pDraw, pPriv); - } - } - } - } - - (*ScreenPriv->LeaveVT)(index, flags); -} - -static void -xf86XVAdjustFrame(int index, int x, int y, int flags) -{ - ScrnInfoPtr pScrn = xf86Screens[index]; - ScreenPtr pScreen = pScrn->pScreen; - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); - WindowPtr pWin; - XvAdaptorPtr pa; - int c, i; - - if(ScreenPriv->AdjustFrame) { - pScrn->AdjustFrame = ScreenPriv->AdjustFrame; - (*pScrn->AdjustFrame)(index, x, y, flags); - pScrn->AdjustFrame = xf86XVAdjustFrame; - } - - for(c = pxvs->nAdaptors, pa = pxvs->pAdaptors; c > 0; c--, pa++) { - XvPortPtr pPort = pa->pPorts; - XvPortRecPrivatePtr pPriv; - - for(i = pa->nPorts; i > 0; i--, pPort++) { - pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; - - if(!pPriv->type && (pPriv->isOn != XV_OFF)) { /* overlaid still/image */ - - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pScreen, pPriv->pCompositeClip); - - pPriv->pCompositeClip = NULL; - - pWin = (WindowPtr)pPriv->pDraw; - - if ((pPriv->AdaptorRec->ReputImage) && - ((pWin->visibility == VisibilityUnobscured) || - (pWin->visibility == VisibilityPartiallyObscured))) - { - xf86XVReputImage(pPriv); - } else if (pPriv->isOn == XV_ON) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->pScrn, pPriv->DevPriv.ptr, FALSE); - xf86XVRemovePortFromWindow(pWin, pPriv); - pPriv->isOn = XV_PENDING; - continue; - } - } - } - } -} - - -/**** XvAdaptorRec fields ****/ - -static int -xf86XVAllocatePort( - unsigned long port, - XvPortPtr pPort, - XvPortPtr *ppPort -){ - *ppPort = pPort; - return Success; -} - - - -static int -xf86XVFreePort(XvPortPtr pPort) -{ - return Success; -} - - -static int -xf86XVPutVideo( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - int result; - - /* No dumping video to pixmaps... For now anyhow */ - if(pDraw->type != DRAWABLE_WINDOW) { - pPort->pDraw = (DrawablePtr)NULL; - return BadAlloc; - } - - /* If we are changing windows, unregister our port in the old window */ - if(portPriv->pDraw && (portPriv->pDraw != pDraw)) - xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - - /* Register our port with the new window */ - result = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - if(result != Success) return result; - - portPriv->type = XvInputMask; - - /* save a copy of these parameters */ - portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; - portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - - /* make sure we have the most recent copy of the clientClip */ - xf86XVCopyClip(portPriv, pGC); - - /* To indicate to the DI layer that we were successful */ - pPort->pDraw = pDraw; - - if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ - - return(xf86XVReputVideo(portPriv)); -} - -static int -xf86XVPutStill( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - ScreenPtr pScreen; - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - if (pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ - - pScreen = pDraw->pScreen; - - WinBox.x1 = pDraw->x + drw_x; - WinBox.y1 = pDraw->y + drw_y; - WinBox.x2 = WinBox.x1 + drw_w; - WinBox.y2 = WinBox.y1 + drw_h; - - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_NULL(pScreen, &ClipRegion); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); - - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = portPriv->pScrn->frameX0; - VPBox.y1 = portPriv->pScrn->frameY0; - VPBox.x2 = portPriv->pScrn->frameX1 + 1; - VPBox.y2 = portPriv->pScrn->frameY1 + 1; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - if(portPriv->pDraw) { - xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - } - - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto PUT_STILL_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto PUT_STILL_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->PutStill)(portPriv->pScrn, - vid_x, vid_y, WinBox.x1, WinBox.y1, - vid_w, vid_h, drw_w, drw_h, - &ClipRegion, portPriv->DevPriv.ptr, - pDraw); - - if((ret == Success) && - (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) { - - xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - portPriv->isOn = XV_ON; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - portPriv->type = 0; /* no mask means it's transient and should - not be reput once it's removed */ - pPort->pDraw = pDraw; /* make sure we can get stop requests */ - } - -PUT_STILL_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - -static int -xf86XVGetVideo( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - int result; - - /* No pixmaps... For now anyhow */ - if(pDraw->type != DRAWABLE_WINDOW) { - pPort->pDraw = (DrawablePtr)NULL; - return BadAlloc; - } - - /* If we are changing windows, unregister our port in the old window */ - if(portPriv->pDraw && (portPriv->pDraw != pDraw)) - xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - - /* Register our port with the new window */ - result = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - if(result != Success) return result; - - portPriv->type = XvOutputMask; - - /* save a copy of these parameters */ - portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; - portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - - /* make sure we have the most recent copy of the clientClip */ - xf86XVCopyClip(portPriv, pGC); - - /* To indicate to the DI layer that we were successful */ - pPort->pDraw = pDraw; - - if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ - - return(xf86XVRegetVideo(portPriv)); -} - -static int -xf86XVGetStill( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - ScreenPtr pScreen; - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - if (pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ - - pScreen = pDraw->pScreen; - - WinBox.x1 = pDraw->x + drw_x; - WinBox.y1 = pDraw->y + drw_y; - WinBox.x2 = WinBox.x1 + drw_w; - WinBox.y2 = WinBox.y1 + drw_h; - - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_NULL(pScreen, &ClipRegion); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); - - if(portPriv->pDraw) { - xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - } - - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto GET_STILL_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->GetStill)(portPriv->pScrn, - vid_x, vid_y, WinBox.x1, WinBox.y1, - vid_w, vid_h, drw_w, drw_h, - &ClipRegion, portPriv->DevPriv.ptr, - pDraw); - -GET_STILL_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - - -static int -xf86XVStopVideo( - ClientPtr client, - XvPortPtr pPort, - DrawablePtr pDraw -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - if(pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - xf86XVRemovePortFromWindow((WindowPtr)pDraw, portPriv); - - if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ - - /* Must free resources. */ - - if(portPriv->isOn > XV_OFF) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->pScrn, portPriv->DevPriv.ptr, TRUE); - portPriv->isOn = XV_OFF; - } - - return Success; -} - -static int -xf86XVSetPortAttribute( - ClientPtr client, - XvPortPtr pPort, - Atom attribute, - INT32 value -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return((*portPriv->AdaptorRec->SetPortAttribute)(portPriv->pScrn, - attribute, value, portPriv->DevPriv.ptr)); -} - - -static int -xf86XVGetPortAttribute( - ClientPtr client, - XvPortPtr pPort, - Atom attribute, - INT32 *p_value -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return((*portPriv->AdaptorRec->GetPortAttribute)(portPriv->pScrn, - attribute, p_value, portPriv->DevPriv.ptr)); -} - - - -static int -xf86XVQueryBestSize( - ClientPtr client, - XvPortPtr pPort, - CARD8 motion, - CARD16 vid_w, CARD16 vid_h, - CARD16 drw_w, CARD16 drw_h, - unsigned int *p_w, unsigned int *p_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - (*portPriv->AdaptorRec->QueryBestSize)(portPriv->pScrn, - (Bool)motion, vid_w, vid_h, drw_w, drw_h, - p_w, p_h, portPriv->DevPriv.ptr); - - return Success; -} - - -static int -xf86XVPutImage( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 src_x, INT16 src_y, - CARD16 src_w, CARD16 src_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h, - XvImagePtr format, - unsigned char* data, - Bool sync, - CARD16 width, CARD16 height -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - ScreenPtr pScreen; - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - if (pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ - - pScreen = pDraw->pScreen; - - WinBox.x1 = pDraw->x + drw_x; - WinBox.y1 = pDraw->y + drw_y; - WinBox.x2 = WinBox.x1 + drw_w; - WinBox.y2 = WinBox.y1 + drw_h; - - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_NULL(pScreen, &ClipRegion); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); - - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = portPriv->pScrn->frameX0; - VPBox.y1 = portPriv->pScrn->frameY0; - VPBox.x2 = portPriv->pScrn->frameX1 + 1; - VPBox.y2 = portPriv->pScrn->frameY1 + 1; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - /* If we are changing windows, unregister our port in the old window */ - if(portPriv->pDraw && (portPriv->pDraw != pDraw)) - xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - - /* Register our port with the new window */ - ret = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - if(ret != Success) goto PUT_IMAGE_BAILOUT; - - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto PUT_IMAGE_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto PUT_IMAGE_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->PutImage)(portPriv->pScrn, - src_x, src_y, WinBox.x1, WinBox.y1, - src_w, src_h, drw_w, drw_h, format->id, data, width, height, - sync, &ClipRegion, portPriv->DevPriv.ptr, - pDraw); - - if((ret == Success) && - (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) { - - portPriv->isOn = XV_ON; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - portPriv->type = 0; /* no mask means it's transient and should - not be reput once it's removed */ - pPort->pDraw = pDraw; /* make sure we can get stop requests */ - } - -PUT_IMAGE_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - -static int -xf86XVQueryImageAttributes( - ClientPtr client, - XvPortPtr pPort, - XvImagePtr format, - CARD16 *width, - CARD16 *height, - int *pitches, - int *offsets -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return (*portPriv->AdaptorRec->QueryImageAttributes)(portPriv->pScrn, - format->id, width, height, pitches, offsets); -} - - -void -xf86XVFillKeyHelperDrawable (DrawablePtr pDraw, CARD32 key, RegionPtr clipboxes) -{ - ScreenPtr pScreen = pDraw->pScreen; - WindowPtr pWin = (WindowPtr)pDraw; - XF86XVWindowPtr pPriv = GET_XF86XV_WINDOW(pWin); - GCPtr pGC = NULL; - XID pval[2]; - BoxPtr pbox = REGION_RECTS(clipboxes); - int i, nbox = REGION_NUM_RECTS(clipboxes); - xRectangle *rects; - - if(!xf86Screens[pScreen->myNum]->vtSema) return; - - if(pPriv) - pGC = pPriv->pGC; - - if(!pGC) { - int status; - pval[0] = key; - pval[1] = IncludeInferiors; - pGC = CreateGC(pDraw, GCForeground | GCSubwindowMode, pval, &status, - (XID)0, serverClient); - if(!pGC) return; - ValidateGC(pDraw, pGC); - if (pPriv) pPriv->pGC = pGC; - } else if (key != pGC->fgPixel){ - pval[0] = key; - ChangeGC(pGC, GCForeground, pval); - ValidateGC(pDraw, pGC); - } - - REGION_TRANSLATE(pDraw->pScreen, clipboxes, -pDraw->x, -pDraw->y); - - rects = xalloc(nbox * sizeof(xRectangle)); - - for(i = 0; i < nbox; i++, pbox++) { - rects[i].x = pbox->x1; - rects[i].y = pbox->y1; - rects[i].width = pbox->x2 - pbox->x1; - rects[i].height = pbox->y2 - pbox->y1; - } - - (*pGC->ops->PolyFillRect)(pDraw, pGC, nbox, rects); - - if (!pPriv) FreeGC(pGC, 0); - - xfree(rects); -} - -void -xf86XVFillKeyHelper (ScreenPtr pScreen, CARD32 key, RegionPtr clipboxes) -{ - DrawablePtr root = &WindowTable[pScreen->myNum]->drawable; - XID pval[2]; - BoxPtr pbox = REGION_RECTS(clipboxes); - int i, nbox = REGION_NUM_RECTS(clipboxes); - xRectangle *rects; - GCPtr gc; - - if(!xf86Screens[pScreen->myNum]->vtSema) return; - - gc = GetScratchGC(root->depth, pScreen); - pval[0] = key; - pval[1] = IncludeInferiors; - (void) ChangeGC(gc, GCForeground|GCSubwindowMode, pval); - ValidateGC(root, gc); - - rects = xalloc (nbox * sizeof(xRectangle)); - - for(i = 0; i < nbox; i++, pbox++) - { - rects[i].x = pbox->x1; - rects[i].y = pbox->y1; - rects[i].width = pbox->x2 - pbox->x1; - rects[i].height = pbox->y2 - pbox->y1; - } - - (*gc->ops->PolyFillRect)(root, gc, nbox, rects); - - xfree (rects); - FreeScratchGC (gc); -} - -/* xf86XVClipVideoHelper - - - Takes the dst box in standard X BoxRec form (top and left - edges inclusive, bottom and right exclusive). The new dst - box is returned. The source boundaries are given (x1, y1 - inclusive, x2, y2 exclusive) and returned are the new source - boundaries in 16.16 fixed point. -*/ - -#define DummyScreen screenInfo.screens[0] - -Bool -xf86XVClipVideoHelper( - BoxPtr dst, - INT32 *xa, - INT32 *xb, - INT32 *ya, - INT32 *yb, - RegionPtr reg, - INT32 width, - INT32 height -){ - double xsw, xdw, ysw, ydw; - INT32 delta; - BoxPtr extents = REGION_EXTENTS(DummyScreen, reg); - int diff; - - xsw = (*xb - *xa) << 16; - xdw = dst->x2 - dst->x1; - ysw = (*yb - *ya) << 16; - ydw = dst->y2 - dst->y1; - - *xa <<= 16; *xb <<= 16; - *ya <<= 16; *yb <<= 16; - - diff = extents->x1 - dst->x1; - if (diff > 0) { - dst->x1 = extents->x1; - *xa += (diff * xsw) / xdw; - } - diff = dst->x2 - extents->x2; - if (diff > 0) { - dst->x2 = extents->x2; - *xb -= (diff * xsw) / xdw; - } - diff = extents->y1 - dst->y1; - if (diff > 0) { - dst->y1 = extents->y1; - *ya += (diff * ysw) / ydw; - } - diff = dst->y2 - extents->y2; - if (diff > 0) { - dst->y2 = extents->y2; - *yb -= (diff * ysw) / ydw; - } - - if (*xa < 0) { - diff = (((-*xa) * xdw) + xsw - 1) / xsw; - dst->x1 += diff; - *xa += (diff * xsw) / xdw; - } - delta = *xb - (width << 16); - if (delta > 0) { - diff = ((delta * xdw) + xsw - 1) / xsw; - dst->x2 -= diff; - *xb -= (diff * xsw) / xdw; - } - if (*xa >= *xb) return FALSE; - - if (*ya < 0) { - diff = (((-*ya) * ydw) + ysw - 1) / ysw; - dst->y1 += diff; - *ya += (diff * ysw) / ydw; - } - delta = *yb - (height << 16); - if (delta > 0) { - diff = ((delta * ydw) + ysw - 1) / ysw; - dst->y2 -= diff; - *yb -= (diff * ysw) / ydw; - } - if (*ya >= *yb) return FALSE; - - if ((dst->x1 > extents->x1) || (dst->x2 < extents->x2) || - (dst->y1 > extents->y1) || (dst->y2 < extents->y2)) - { - RegionRec clipReg; - REGION_INIT(DummyScreen, &clipReg, dst, 1); - REGION_INTERSECT(DummyScreen, reg, reg, &clipReg); - REGION_UNINIT(DummyScreen, &clipReg); - } - return TRUE; -} - -void -xf86XVCopyYUV12ToPacked( - const void *srcy, - const void *srcv, - const void *srcu, - void *dst, - int srcPitchy, - int srcPitchuv, - int dstPitch, - int h, - int w -){ - CARD32 *Dst; - const CARD8 *Y, *U, *V; - int i, j; - - w >>= 1; - - for (j = 0; j < h; j++) { - Dst = dst; - Y = srcy; V = srcv; U = srcu; - i = w; - while (i >= 4) { -#if X_BYTE_ORDER == X_LITTLE_ENDIAN - Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24); - Dst[1] = Y[2] | (Y[3] << 16) | (U[1] << 8) | (V[1] << 24); - Dst[2] = Y[4] | (Y[5] << 16) | (U[2] << 8) | (V[2] << 24); - Dst[3] = Y[6] | (Y[7] << 16) | (U[3] << 8) | (V[3] << 24); -#else - /* This assumes a little-endian framebuffer */ - Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0]; - Dst[1] = (Y[2] << 24) | (Y[3] << 8) | (U[1] << 16) | V[1]; - Dst[2] = (Y[4] << 24) | (Y[5] << 8) | (U[2] << 16) | V[2]; - Dst[3] = (Y[6] << 24) | (Y[7] << 8) | (U[3] << 16) | V[3]; -#endif - Dst += 4; Y += 8; V += 4; U += 4; - i -= 4; - } - - while (i--) { -#if X_BYTE_ORDER == X_LITTLE_ENDIAN - Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24); -#else - /* This assumes a little-endian framebuffer */ - Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0]; -#endif - Dst++; Y += 2; V++; U++; - } - - dst = (CARD8 *)dst + dstPitch; - srcy = (const CARD8 *)srcy + srcPitchy; - if (j & 1) { - srcu = (const CARD8 *)srcu + srcPitchuv; - srcv = (const CARD8 *)srcv + srcPitchuv; - } - } -} - -void -xf86XVCopyPacked( - const void *src, - void *dst, - int srcPitch, - int dstPitch, - int h, - int w -){ - const CARD32 *Src; - CARD32 *Dst; - int i; - - w >>= 1; - while (--h >= 0) { - do { - Dst = dst; Src = src; - i = w; - while (i >= 4) { - Dst[0] = Src[0]; - Dst[1] = Src[1]; - Dst[2] = Src[2]; - Dst[3] = Src[3]; - Dst += 4; Src += 4; i -= 4; - } - if (!i) break; - Dst[0] = Src[0]; - if (i == 1) break; - Dst[1] = Src[1]; - if (i == 2) break; - Dst[2] = Src[2]; - } while (0); - - src = (const CARD8 *)src + srcPitch; - dst = (CARD8 *)dst + dstPitch; - } -} +/* + * XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com) + */ +/* + * Copyright (c) 1998-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "regionstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "mivalidate.h" +#include "validate.h" +#include "resource.h" +#include "gcstruct.h" +#include "dixstruct.h" + +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvproto.h> +#include "xvdix.h" +#include "xvmodproc.h" + +#include "xf86xvpriv.h" + + +/* XvScreenRec fields */ + +static Bool xf86XVCloseScreen(int, ScreenPtr); +static int xf86XVQueryAdaptors(ScreenPtr, XvAdaptorPtr *, int *); + +/* XvAdaptorRec fields */ + +static int xf86XVAllocatePort(unsigned long, XvPortPtr, XvPortPtr*); +static int xf86XVFreePort(XvPortPtr); +static int xf86XVPutVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int xf86XVPutStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int xf86XVGetVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int xf86XVGetStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int xf86XVStopVideo(ClientPtr, XvPortPtr, DrawablePtr); +static int xf86XVSetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32); +static int xf86XVGetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32*); +static int xf86XVQueryBestSize(ClientPtr, XvPortPtr, CARD8, + CARD16, CARD16,CARD16, CARD16, + unsigned int*, unsigned int*); +static int xf86XVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16, + XvImagePtr, unsigned char*, Bool, + CARD16, CARD16); +static int xf86XVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr, + CARD16*, CARD16*, int*, int*); + + +/* ScreenRec fields */ + +static Bool xf86XVDestroyWindow(WindowPtr pWin); +static void xf86XVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2); +static void xf86XVClipNotify(WindowPtr pWin, int dx, int dy); + +/* ScrnInfoRec functions */ + +static Bool xf86XVEnterVT(int, int); +static void xf86XVLeaveVT(int, int); +static void xf86XVAdjustFrame(int index, int x, int y, int flags); + +/* misc */ + +static Bool xf86XVInitAdaptors(ScreenPtr, XF86VideoAdaptorPtr*, int); + + +static int XF86XVWindowKeyIndex; +static DevPrivateKey XF86XVWindowKey = &XF86XVWindowKeyIndex; +static int XF86XvScreenKeyIndex; +DevPrivateKey XF86XvScreenKey = &XF86XvScreenKeyIndex; +static unsigned long PortResource = 0; + +DevPrivateKey (*XvGetScreenKeyProc)(void) = NULL; +unsigned long (*XvGetRTPortProc)(void) = NULL; +int (*XvScreenInitProc)(ScreenPtr) = NULL; + +#define GET_XV_SCREEN(pScreen) \ + ((XvScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, XF86XvScreenKey)) + +#define GET_XF86XV_SCREEN(pScreen) \ + ((XF86XVScreenPtr)(GET_XV_SCREEN(pScreen)->devPriv.ptr)) + +#define GET_XF86XV_WINDOW(pWin) \ + ((XF86XVWindowPtr)dixLookupPrivate(&(pWin)->devPrivates, XF86XVWindowKey)) + +static xf86XVInitGenericAdaptorPtr *GenDrivers = NULL; +static int NumGenDrivers = 0; + +int +xf86XVRegisterGenericAdaptorDriver( + xf86XVInitGenericAdaptorPtr InitFunc +){ + xf86XVInitGenericAdaptorPtr *newdrivers; + + newdrivers = realloc(GenDrivers, sizeof(xf86XVInitGenericAdaptorPtr) * + (1 + NumGenDrivers)); + if (!newdrivers) + return 0; + GenDrivers = newdrivers; + + GenDrivers[NumGenDrivers++] = InitFunc; + + return 1; +} + +int +xf86XVListGenericAdaptors( + ScrnInfoPtr pScrn, + XF86VideoAdaptorPtr **adaptors +){ + int i,j,n,num; + XF86VideoAdaptorPtr *DrivAdap,*new; + + num = 0; + *adaptors = NULL; + /* + * The v4l driver registers itself first, but can use surfaces registered + * by other drivers. So, call the v4l driver last. + */ + for (i = NumGenDrivers; --i >= 0; ) { + DrivAdap = NULL; + n = (*GenDrivers[i])(pScrn, &DrivAdap); + if (0 == n) + continue; + new = realloc(*adaptors, sizeof(XF86VideoAdaptorPtr) * (num+n)); + if (NULL == new) + continue; + *adaptors = new; + for (j = 0; j < n; j++, num++) + (*adaptors)[num] = DrivAdap[j]; + } + return num; +} + + +/**************** Offscreen surface stuff *******************/ + +typedef struct { + XF86OffscreenImagePtr images; + int num; +} OffscreenImageRec; + +static int OffscreenPrivateKeyIndex; +static DevPrivateKey OffscreenPrivateKey = &OffscreenPrivateKeyIndex; +#define GetOffscreenImage(pScreen) ((OffscreenImageRec *) dixLookupPrivate(&(pScreen)->devPrivates, OffscreenPrivateKey)) + +Bool +xf86XVRegisterOffscreenImages( + ScreenPtr pScreen, + XF86OffscreenImagePtr images, + int num +){ + OffscreenImageRec *OffscreenImage; + /* This function may be called before xf86XVScreenInit, so there's + * no better place than this to call dixRequestPrivate to ensure we + * have space reserved. After the first call it is a no-op. */ + if(!dixRequestPrivate(OffscreenPrivateKey, sizeof(OffscreenImageRec)) || + !(OffscreenImage = GetOffscreenImage(pScreen))) + /* Every X.org driver assumes this function always succeeds, so + * just die on allocation failure. */ + FatalError("Could not allocate private storage for XV offscreen images.\n"); + + OffscreenImage->num = num; + OffscreenImage->images = images; + return TRUE; +} + +XF86OffscreenImagePtr +xf86XVQueryOffscreenImages( + ScreenPtr pScreen, + int *num +){ + OffscreenImageRec *OffscreenImage = GetOffscreenImage(pScreen); + *num = OffscreenImage->num; + return OffscreenImage->images; +} + + +XF86VideoAdaptorPtr +xf86XVAllocateVideoAdaptorRec(ScrnInfoPtr pScrn) +{ + return calloc(1, sizeof(XF86VideoAdaptorRec)); +} + +void +xf86XVFreeVideoAdaptorRec(XF86VideoAdaptorPtr ptr) +{ + free(ptr); +} + + +Bool +xf86XVScreenInit( + ScreenPtr pScreen, + XF86VideoAdaptorPtr *adaptors, + int num +){ + ScrnInfoPtr pScrn; + XF86XVScreenPtr ScreenPriv; + XvScreenPtr pxvs; + + if(num <= 0 || + !XvGetScreenKeyProc || !XvGetRTPortProc || !XvScreenInitProc) + return FALSE; + + if(Success != (*XvScreenInitProc)(pScreen)) return FALSE; + + XF86XvScreenKey = (*XvGetScreenKeyProc)(); + PortResource = (*XvGetRTPortProc)(); + + pxvs = GET_XV_SCREEN(pScreen); + + /* Anyone initializing the Xv layer must provide these two. + The Xv di layer calls them without even checking if they exist! */ + + pxvs->ddCloseScreen = xf86XVCloseScreen; + pxvs->ddQueryAdaptors = xf86XVQueryAdaptors; + + /* The Xv di layer provides us with a private hook so that we don't + have to allocate our own screen private. They also provide + a CloseScreen hook so that we don't have to wrap it. I'm not + sure that I appreciate that. */ + + ScreenPriv = malloc(sizeof(XF86XVScreenRec)); + pxvs->devPriv.ptr = (pointer)ScreenPriv; + + if(!ScreenPriv) return FALSE; + + pScrn = xf86Screens[pScreen->myNum]; + + ScreenPriv->videoGC = NULL; /* for the helper */ + + ScreenPriv->DestroyWindow = pScreen->DestroyWindow; + ScreenPriv->WindowExposures = pScreen->WindowExposures; + ScreenPriv->ClipNotify = pScreen->ClipNotify; + ScreenPriv->EnterVT = pScrn->EnterVT; + ScreenPriv->LeaveVT = pScrn->LeaveVT; + ScreenPriv->AdjustFrame = pScrn->AdjustFrame; + + pScreen->DestroyWindow = xf86XVDestroyWindow; + pScreen->WindowExposures = xf86XVWindowExposures; + pScreen->ClipNotify = xf86XVClipNotify; + pScrn->EnterVT = xf86XVEnterVT; + pScrn->LeaveVT = xf86XVLeaveVT; + if(pScrn->AdjustFrame) + pScrn->AdjustFrame = xf86XVAdjustFrame; + + if(!xf86XVInitAdaptors(pScreen, adaptors, num)) + return FALSE; + + return TRUE; +} + +static void +xf86XVFreeAdaptor(XvAdaptorPtr pAdaptor) +{ + int i; + + free(pAdaptor->name); + + if(pAdaptor->pEncodings) { + XvEncodingPtr pEncode = pAdaptor->pEncodings; + + for(i = 0; i < pAdaptor->nEncodings; i++, pEncode++) + free(pEncode->name); + free(pAdaptor->pEncodings); + } + + free(pAdaptor->pFormats); + + if(pAdaptor->pPorts) { + XvPortPtr pPort = pAdaptor->pPorts; + XvPortRecPrivatePtr pPriv; + + for(i = 0; i < pAdaptor->nPorts; i++, pPort++) { + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv) { + if(pPriv->clientClip) + REGION_DESTROY(pAdaptor->pScreen, pPriv->clientClip); + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pAdaptor->pScreen, pPriv->pCompositeClip); + free(pPriv); + } + } + free(pAdaptor->pPorts); + } + + if(pAdaptor->nAttributes) { + XvAttributePtr pAttribute = pAdaptor->pAttributes; + + for(i = 0; i < pAdaptor->nAttributes; i++, pAttribute++) + free(pAttribute->name); + free(pAdaptor->pAttributes); + } + + free(pAdaptor->pImages); + free(pAdaptor->devPriv.ptr); +} + +static Bool +xf86XVInitAdaptors( + ScreenPtr pScreen, + XF86VideoAdaptorPtr *infoPtr, + int number +) { + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XF86VideoAdaptorPtr adaptorPtr; + XvAdaptorPtr pAdaptor, pa; + XvAdaptorRecPrivatePtr adaptorPriv; + int na, numAdaptor; + XvPortRecPrivatePtr portPriv; + XvPortPtr pPort, pp; + int numPort; + XF86AttributePtr attributePtr; + XvAttributePtr pAttribute, pat; + XF86VideoFormatPtr formatPtr; + XvFormatPtr pFormat, pf; + int numFormat, totFormat; + XF86VideoEncodingPtr encodingPtr; + XvEncodingPtr pEncode, pe; + XF86ImagePtr imagePtr; + XvImagePtr pImage, pi; + int numVisuals; + VisualPtr pVisual; + int i; + + pxvs->nAdaptors = 0; + pxvs->pAdaptors = NULL; + + if(!(pAdaptor = calloc(number, sizeof(XvAdaptorRec)))) + return FALSE; + + for(pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) { + adaptorPtr = infoPtr[na]; + + if(!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute || + !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize) + continue; + + /* client libs expect at least one encoding */ + if(!adaptorPtr->nEncodings || !adaptorPtr->pEncodings) + continue; + + pa->type = adaptorPtr->type; + + if(!adaptorPtr->PutVideo && !adaptorPtr->GetVideo) + pa->type &= ~XvVideoMask; + + if(!adaptorPtr->PutStill && !adaptorPtr->GetStill) + pa->type &= ~XvStillMask; + + if(!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes) + pa->type &= ~XvImageMask; + + if(!adaptorPtr->PutVideo && !adaptorPtr->PutImage && + !adaptorPtr->PutStill) + pa->type &= ~XvInputMask; + + if(!adaptorPtr->GetVideo && !adaptorPtr->GetStill) + pa->type &= ~XvOutputMask; + + if(!(adaptorPtr->type & (XvPixmapMask | XvWindowMask))) + continue; + if(!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask))) + continue; + + pa->pScreen = pScreen; + pa->ddAllocatePort = xf86XVAllocatePort; + pa->ddFreePort = xf86XVFreePort; + pa->ddPutVideo = xf86XVPutVideo; + pa->ddPutStill = xf86XVPutStill; + pa->ddGetVideo = xf86XVGetVideo; + pa->ddGetStill = xf86XVGetStill; + pa->ddStopVideo = xf86XVStopVideo; + pa->ddPutImage = xf86XVPutImage; + pa->ddSetPortAttribute = xf86XVSetPortAttribute; + pa->ddGetPortAttribute = xf86XVGetPortAttribute; + pa->ddQueryBestSize = xf86XVQueryBestSize; + pa->ddQueryImageAttributes = xf86XVQueryImageAttributes; + if((pa->name = malloc(strlen(adaptorPtr->name) + 1))) + strcpy(pa->name, adaptorPtr->name); + + if(adaptorPtr->nEncodings && + (pEncode = calloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) { + + for(pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0; + i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) + { + pe->id = encodingPtr->id; + pe->pScreen = pScreen; + if((pe->name = malloc(strlen(encodingPtr->name) + 1))) + strcpy(pe->name, encodingPtr->name); + pe->width = encodingPtr->width; + pe->height = encodingPtr->height; + pe->rate.numerator = encodingPtr->rate.numerator; + pe->rate.denominator = encodingPtr->rate.denominator; + } + pa->nEncodings = adaptorPtr->nEncodings; + pa->pEncodings = pEncode; + } + + if(adaptorPtr->nImages && + (pImage = calloc(adaptorPtr->nImages, sizeof(XvImageRec)))) { + + for(i = 0, pi = pImage, imagePtr = adaptorPtr->pImages; + i < adaptorPtr->nImages; i++, pi++, imagePtr++) + { + pi->id = imagePtr->id; + pi->type = imagePtr->type; + pi->byte_order = imagePtr->byte_order; + memcpy(pi->guid, imagePtr->guid, 16); + pi->bits_per_pixel = imagePtr->bits_per_pixel; + pi->format = imagePtr->format; + pi->num_planes = imagePtr->num_planes; + pi->depth = imagePtr->depth; + pi->red_mask = imagePtr->red_mask; + pi->green_mask = imagePtr->green_mask; + pi->blue_mask = imagePtr->blue_mask; + pi->y_sample_bits = imagePtr->y_sample_bits; + pi->u_sample_bits = imagePtr->u_sample_bits; + pi->v_sample_bits = imagePtr->v_sample_bits; + pi->horz_y_period = imagePtr->horz_y_period; + pi->horz_u_period = imagePtr->horz_u_period; + pi->horz_v_period = imagePtr->horz_v_period; + pi->vert_y_period = imagePtr->vert_y_period; + pi->vert_u_period = imagePtr->vert_u_period; + pi->vert_v_period = imagePtr->vert_v_period; + memcpy(pi->component_order, imagePtr->component_order, 32); + pi->scanline_order = imagePtr->scanline_order; + } + pa->nImages = adaptorPtr->nImages; + pa->pImages = pImage; + } + + if(adaptorPtr->nAttributes && + (pAttribute = calloc(adaptorPtr->nAttributes, sizeof(XvAttributeRec)))) + { + for(pat = pAttribute, attributePtr = adaptorPtr->pAttributes, i = 0; + i < adaptorPtr->nAttributes; pat++, i++, attributePtr++) + { + pat->flags = attributePtr->flags; + pat->min_value = attributePtr->min_value; + pat->max_value = attributePtr->max_value; + if((pat->name = malloc(strlen(attributePtr->name) + 1))) + strcpy(pat->name, attributePtr->name); + } + pa->nAttributes = adaptorPtr->nAttributes; + pa->pAttributes = pAttribute; + } + + + totFormat = adaptorPtr->nFormats; + + if(!(pFormat = calloc(totFormat, sizeof(XvFormatRec)))) { + xf86XVFreeAdaptor(pa); + continue; + } + for(pf = pFormat, i = 0, numFormat = 0, formatPtr = adaptorPtr->pFormats; + i < adaptorPtr->nFormats; i++, formatPtr++) + { + numVisuals = pScreen->numVisuals; + pVisual = pScreen->visuals; + + while(numVisuals--) { + if((pVisual->class == formatPtr->class) && + (pVisual->nplanes == formatPtr->depth)) { + + if(numFormat >= totFormat) { + void *moreSpace; + totFormat *= 2; + moreSpace = realloc(pFormat, + totFormat * sizeof(XvFormatRec)); + if(!moreSpace) break; + pFormat = moreSpace; + pf = pFormat + numFormat; + } + + pf->visual = pVisual->vid; + pf->depth = formatPtr->depth; + + pf++; + numFormat++; + } + pVisual++; + } + } + pa->nFormats = numFormat; + pa->pFormats = pFormat; + if(!numFormat) { + xf86XVFreeAdaptor(pa); + continue; + } + + if(!(adaptorPriv = calloc(1, sizeof(XvAdaptorRecPrivate)))) { + xf86XVFreeAdaptor(pa); + continue; + } + + adaptorPriv->flags = adaptorPtr->flags; + adaptorPriv->PutVideo = adaptorPtr->PutVideo; + adaptorPriv->PutStill = adaptorPtr->PutStill; + adaptorPriv->GetVideo = adaptorPtr->GetVideo; + adaptorPriv->GetStill = adaptorPtr->GetStill; + adaptorPriv->StopVideo = adaptorPtr->StopVideo; + adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute; + adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute; + adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize; + adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes; + adaptorPriv->PutImage = adaptorPtr->PutImage; + adaptorPriv->ReputImage = adaptorPtr->ReputImage; + + pa->devPriv.ptr = (pointer)adaptorPriv; + + if(!(pPort = calloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) { + xf86XVFreeAdaptor(pa); + continue; + } + for(pp = pPort, i = 0, numPort = 0; + i < adaptorPtr->nPorts; i++) { + + if(!(pp->id = FakeClientID(0))) + continue; + + if(!(portPriv = calloc(1, sizeof(XvPortRecPrivate)))) + continue; + + if(!AddResource(pp->id, PortResource, pp)) { + free(portPriv); + continue; + } + + pp->pAdaptor = pa; + pp->pNotify = (XvPortNotifyPtr)NULL; + pp->pDraw = (DrawablePtr)NULL; + pp->client = (ClientPtr)NULL; + pp->grab.client = (ClientPtr)NULL; + pp->time = currentTime; + pp->devPriv.ptr = portPriv; + + portPriv->pScrn = pScrn; + portPriv->AdaptorRec = adaptorPriv; + portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr; + + pp++; + numPort++; + } + pa->nPorts = numPort; + pa->pPorts = pPort; + if(!numPort) { + xf86XVFreeAdaptor(pa); + continue; + } + + pa->base_id = pPort->id; + + pa++; + numAdaptor++; + } + + if(numAdaptor) { + pxvs->nAdaptors = numAdaptor; + pxvs->pAdaptors = pAdaptor; + } else { + free(pAdaptor); + return FALSE; + } + + return TRUE; +} + +/* Video should be clipped to the intersection of the window cliplist + and the client cliplist specified in the GC for which the video was + initialized. When we need to reclip a window, the GC that started + the video may not even be around anymore. That's why we save the + client clip from the GC when the video is initialized. We then + use xf86XVUpdateCompositeClip to calculate the new composite clip + when we need it. This is different from what DEC did. They saved + the GC and used it's clip list when they needed to reclip the window, + even if the client clip was different from the one the video was + initialized with. If the original GC was destroyed, they had to stop + the video. I like the new method better (MArk). + + This function only works for windows. Will need to rewrite when + (if) we support pixmap rendering. +*/ + +static void +xf86XVUpdateCompositeClip(XvPortRecPrivatePtr portPriv) +{ + RegionPtr pregWin, pCompositeClip; + WindowPtr pWin; + ScreenPtr pScreen; + Bool freeCompClip = FALSE; + + if(portPriv->pCompositeClip) + return; + + pWin = (WindowPtr)portPriv->pDraw; + pScreen = pWin->drawable.pScreen; + + /* get window clip list */ + if(portPriv->subWindowMode == IncludeInferiors) { + pregWin = NotClippedByChildren(pWin); + freeCompClip = TRUE; + } else + pregWin = &pWin->clipList; + + if(!portPriv->clientClip) { + portPriv->pCompositeClip = pregWin; + portPriv->FreeCompositeClip = freeCompClip; + return; + } + + pCompositeClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, pCompositeClip, portPriv->clientClip); + REGION_TRANSLATE(pScreen, pCompositeClip, + portPriv->pDraw->x + portPriv->clipOrg.x, + portPriv->pDraw->y + portPriv->clipOrg.y); + REGION_INTERSECT(pScreen, pCompositeClip, pregWin, pCompositeClip); + + portPriv->pCompositeClip = pCompositeClip; + portPriv->FreeCompositeClip = TRUE; + + if(freeCompClip) { + REGION_DESTROY(pScreen, pregWin); + } +} + +/* Save the current clientClip and update the CompositeClip whenever + we have a fresh GC */ + +static void +xf86XVCopyClip( + XvPortRecPrivatePtr portPriv, + GCPtr pGC +){ + /* copy the new clip if it exists */ + if((pGC->clientClipType == CT_REGION) && pGC->clientClip) { + if(!portPriv->clientClip) + portPriv->clientClip = REGION_CREATE(pScreen, NullBox, 1); + /* Note: this is in window coordinates */ + REGION_COPY(pScreen, portPriv->clientClip, pGC->clientClip); + } else if(portPriv->clientClip) { /* free the old clientClip */ + REGION_DESTROY(pScreen, portPriv->clientClip); + portPriv->clientClip = NULL; + } + + /* get rid of the old clip list */ + if(portPriv->pCompositeClip && portPriv->FreeCompositeClip) { + REGION_DESTROY(pScreen, portPriv->pCompositeClip); + } + + portPriv->clipOrg = pGC->clipOrg; + portPriv->pCompositeClip = pGC->pCompositeClip; + portPriv->FreeCompositeClip = FALSE; + portPriv->subWindowMode = pGC->subWindowMode; +} + +static int +xf86XVRegetVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen; + int ret = Success; + Bool clippedAway = FALSE; + + pScreen = portPriv->pDraw->pScreen; + xf86XVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_NULL(pScreen, &ClipRegion); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetVideo)(portPriv->pScrn, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr, + portPriv->pDraw); + + if(ret == Success) + portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +xf86XVReputVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen; + int ret = Success; + Bool clippedAway = FALSE; + + pScreen = portPriv->pDraw->pScreen; + + xf86XVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_NULL(pScreen, &ClipRegion); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = portPriv->pScrn->frameX0; + VPBox.y1 = portPriv->pScrn->frameY0; + VPBox.x2 = portPriv->pScrn->frameX1 + 1; + VPBox.y2 = portPriv->pScrn->frameY1 + 1; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutVideo)(portPriv->pScrn, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr, + portPriv->pDraw); + + if(ret == Success) portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + +static int +xf86XVReputImage(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen; + int ret = Success; + Bool clippedAway = FALSE; + + pScreen = portPriv->pDraw->pScreen; + + xf86XVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_NULL(pScreen, &ClipRegion); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = portPriv->pScrn->frameX0; + VPBox.y1 = portPriv->pScrn->frameY0; + VPBox.x2 = portPriv->pScrn->frameX1 + 1; + VPBox.y2 = portPriv->pScrn->frameY1 + 1; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->ReputImage)(portPriv->pScrn, + WinBox.x1, WinBox.y1, + &ClipRegion, portPriv->DevPriv.ptr, + portPriv->pDraw); + + portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +xf86XVReputAllVideo(WindowPtr pWin, pointer data) +{ + XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); + + while(WinPriv) { + if(WinPriv->PortRec->type == XvInputMask) + xf86XVReputVideo(WinPriv->PortRec); + else + xf86XVRegetVideo(WinPriv->PortRec); + WinPriv = WinPriv->next; + } + + return WT_WALKCHILDREN; +} + +static int +xf86XVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + XF86XVWindowPtr winPriv, PrivRoot; + + winPriv = PrivRoot = GET_XF86XV_WINDOW(pWin); + + /* Enlist our port in the window private */ + while(winPriv) { + if(winPriv->PortRec == portPriv) /* we're already listed */ + break; + winPriv = winPriv->next; + } + + if(!winPriv) { + winPriv = calloc(1, sizeof(XF86XVWindowRec)); + if(!winPriv) return BadAlloc; + winPriv->PortRec = portPriv; + winPriv->next = PrivRoot; + dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, winPriv); + } + + portPriv->pDraw = (DrawablePtr)pWin; + + return Success; +} + + +static void +xf86XVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + XF86XVWindowPtr winPriv, prevPriv = NULL; + + winPriv = GET_XF86XV_WINDOW(pWin); + + while(winPriv) { + if(winPriv->PortRec == portPriv) { + if(prevPriv) + prevPriv->next = winPriv->next; + else + dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, + winPriv->next); + free(winPriv); + break; + } + prevPriv = winPriv; + winPriv = winPriv->next; + } + portPriv->pDraw = NULL; +} + +/**** ScreenRec fields ****/ + +static Bool +xf86XVDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XF86XVWindowPtr tmp, WinPriv = GET_XF86XV_WINDOW(pWin); + int ret; + + while(WinPriv) { + XvPortRecPrivatePtr pPriv = WinPriv->PortRec; + + if(pPriv->isOn > XV_OFF) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->pScrn, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + } + + pPriv->pDraw = NULL; + tmp = WinPriv; + if(WinPriv->pGC) { + FreeGC(WinPriv->pGC, 0); + } + WinPriv = WinPriv->next; + free(tmp); + } + + dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, NULL); + + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + ret = (*pScreen->DestroyWindow)(pWin); + pScreen->DestroyWindow = xf86XVDestroyWindow; + + return ret; +} + + +static void +xf86XVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); + XF86XVWindowPtr pPrev; + XvPortRecPrivatePtr pPriv; + Bool AreasExposed; + + AreasExposed = (WinPriv && reg1 && REGION_NOTEMPTY(pScreen, reg1)); + + pScreen->WindowExposures = ScreenPriv->WindowExposures; + (*pScreen->WindowExposures)(pWin, reg1, reg2); + pScreen->WindowExposures = xf86XVWindowExposures; + + /* filter out XClearWindow/Area */ + if (!pWin->valdata) return; + + pPrev = NULL; + + while(WinPriv) { + pPriv = WinPriv->PortRec; + + /* Reput anyone with a reput function */ + + switch(pPriv->type) { + case XvInputMask: + xf86XVReputVideo(pPriv); + break; + case XvOutputMask: + xf86XVRegetVideo(pPriv); + break; + default: /* overlaid still/image*/ + if (pPriv->AdaptorRec->ReputImage) + xf86XVReputImage(pPriv); + else if(AreasExposed) { + XF86XVWindowPtr tmp; + + if (pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->pScrn, pPriv->DevPriv.ptr, FALSE); + pPriv->isOn = XV_PENDING; + } + pPriv->pDraw = NULL; + + if(!pPrev) + dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, + WinPriv->next); + else + pPrev->next = WinPriv->next; + tmp = WinPriv; + WinPriv = WinPriv->next; + free(tmp); + continue; + } + break; + } + pPrev = WinPriv; + WinPriv = WinPriv->next; + } +} + + +static void +xf86XVClipNotify(WindowPtr pWin, int dx, int dy) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); + XF86XVWindowPtr tmp, pPrev = NULL; + XvPortRecPrivatePtr pPriv; + Bool visible = (pWin->visibility == VisibilityUnobscured) || + (pWin->visibility == VisibilityPartiallyObscured); + + while(WinPriv) { + pPriv = WinPriv->PortRec; + + if(!pPriv) goto next; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pScreen, pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + if (pPriv->AdaptorRec->ClipNotify) + (*pPriv->AdaptorRec->ClipNotify)(pPriv->pScrn, pPriv->DevPriv.ptr, + pWin, dx, dy); + + /* Stop everything except images, but stop them too if the + window isn't visible. But we only remove the images. */ + + if(pPriv->type || !visible) { + if(pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->pScrn, pPriv->DevPriv.ptr, FALSE); + pPriv->isOn = XV_PENDING; + } + + if(!pPriv->type) { /* overlaid still/image */ + pPriv->pDraw = NULL; + + if(!pPrev) + dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, + WinPriv->next); + else + pPrev->next = WinPriv->next; + tmp = WinPriv; + WinPriv = WinPriv->next; + free(tmp); + continue; + } + } + +next: + pPrev = WinPriv; + WinPriv = WinPriv->next; + } + + if(ScreenPriv->ClipNotify) { + pScreen->ClipNotify = ScreenPriv->ClipNotify; + (*pScreen->ClipNotify)(pWin, dx, dy); + pScreen->ClipNotify = xf86XVClipNotify; + } +} + + + +/**** Required XvScreenRec fields ****/ + +static Bool +xf86XVCloseScreen(int i, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XvAdaptorPtr pa; + int c; + + if(!ScreenPriv) return TRUE; + + if(ScreenPriv->videoGC) { + FreeGC(ScreenPriv->videoGC, 0); + ScreenPriv->videoGC = NULL; + } + + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + pScreen->WindowExposures = ScreenPriv->WindowExposures; + pScreen->ClipNotify = ScreenPriv->ClipNotify; + + pScrn->EnterVT = ScreenPriv->EnterVT; + pScrn->LeaveVT = ScreenPriv->LeaveVT; + pScrn->AdjustFrame = ScreenPriv->AdjustFrame; + + for(c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) { + xf86XVFreeAdaptor(pa); + } + + free(pxvs->pAdaptors); + free(ScreenPriv); + return TRUE; +} + + +static int +xf86XVQueryAdaptors( + ScreenPtr pScreen, + XvAdaptorPtr *p_pAdaptors, + int *p_nAdaptors +){ + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + + *p_nAdaptors = pxvs->nAdaptors; + *p_pAdaptors = pxvs->pAdaptors; + + return (Success); +} + + +/**** ScrnInfoRec fields ****/ + +static Bool +xf86XVEnterVT(int index, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + Bool ret; + + ret = (*ScreenPriv->EnterVT)(index, flags); + + if(ret) WalkTree(pScreen, xf86XVReputAllVideo, 0); + + return ret; +} + +static void +xf86XVLeaveVT(int index, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XvAdaptorPtr pAdaptor; + XvPortPtr pPort; + XvPortRecPrivatePtr pPriv; + int i, j; + + for(i = 0; i < pxvs->nAdaptors; i++) { + pAdaptor = &pxvs->pAdaptors[i]; + for(j = 0; j < pAdaptor->nPorts; j++) { + pPort = &pAdaptor->pPorts[j]; + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv->isOn > XV_OFF) { + + (*pPriv->AdaptorRec->StopVideo)( + pPriv->pScrn, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pScreen, pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + if(!pPriv->type && pPriv->pDraw) { /* still */ + xf86XVRemovePortFromWindow((WindowPtr)pPriv->pDraw, pPriv); + } + } + } + } + + (*ScreenPriv->LeaveVT)(index, flags); +} + +static void +xf86XVAdjustFrame(int index, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[index]; + ScreenPtr pScreen = pScrn->pScreen; + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + WindowPtr pWin; + XvAdaptorPtr pa; + int c, i; + + if(ScreenPriv->AdjustFrame) { + pScrn->AdjustFrame = ScreenPriv->AdjustFrame; + (*pScrn->AdjustFrame)(index, x, y, flags); + pScrn->AdjustFrame = xf86XVAdjustFrame; + } + + for(c = pxvs->nAdaptors, pa = pxvs->pAdaptors; c > 0; c--, pa++) { + XvPortPtr pPort = pa->pPorts; + XvPortRecPrivatePtr pPriv; + + for(i = pa->nPorts; i > 0; i--, pPort++) { + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + + if(!pPriv->type && (pPriv->isOn != XV_OFF)) { /* overlaid still/image */ + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pScreen, pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + pWin = (WindowPtr)pPriv->pDraw; + + if ((pPriv->AdaptorRec->ReputImage) && + ((pWin->visibility == VisibilityUnobscured) || + (pWin->visibility == VisibilityPartiallyObscured))) + { + xf86XVReputImage(pPriv); + } else if (pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->pScrn, pPriv->DevPriv.ptr, FALSE); + xf86XVRemovePortFromWindow(pWin, pPriv); + pPriv->isOn = XV_PENDING; + continue; + } + } + } + } +} + + +/**** XvAdaptorRec fields ****/ + +static int +xf86XVAllocatePort( + unsigned long port, + XvPortPtr pPort, + XvPortPtr *ppPort +){ + *ppPort = pPort; + return Success; +} + + + +static int +xf86XVFreePort(XvPortPtr pPort) +{ + return Success; +} + + +static int +xf86XVPutVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + int result; + + /* No dumping video to pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->type = XvInputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + xf86XVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + return(xf86XVReputVideo(portPriv)); +} + +static int +xf86XVPutStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen; + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + pScreen = pDraw->pScreen; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_NULL(pScreen, &ClipRegion); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = portPriv->pScrn->frameX0; + VPBox.y1 = portPriv->pScrn->frameY0; + VPBox.x2 = portPriv->pScrn->frameX1 + 1; + VPBox.y2 = portPriv->pScrn->frameY1 + 1; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + if(portPriv->pDraw) { + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutStill)(portPriv->pScrn, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr, + pDraw); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) { + + xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + portPriv->isOn = XV_ON; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + +static int +xf86XVGetVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + int result; + + /* No pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->type = XvOutputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + xf86XVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + return(xf86XVRegetVideo(portPriv)); +} + +static int +xf86XVGetStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen; + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + pScreen = pDraw->pScreen; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_NULL(pScreen, &ClipRegion); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->pDraw) { + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto GET_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetStill)(portPriv->pScrn, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr, + pDraw); + +GET_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + + +static int +xf86XVStopVideo( + ClientPtr client, + XvPortPtr pPort, + DrawablePtr pDraw +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + if(pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + xf86XVRemovePortFromWindow((WindowPtr)pDraw, portPriv); + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + /* Must free resources. */ + + if(portPriv->isOn > XV_OFF) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, TRUE); + portPriv->isOn = XV_OFF; + } + + return Success; +} + +static int +xf86XVSetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->SetPortAttribute)(portPriv->pScrn, + attribute, value, portPriv->DevPriv.ptr)); +} + + +static int +xf86XVGetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 *p_value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->GetPortAttribute)(portPriv->pScrn, + attribute, p_value, portPriv->DevPriv.ptr)); +} + + + +static int +xf86XVQueryBestSize( + ClientPtr client, + XvPortPtr pPort, + CARD8 motion, + CARD16 vid_w, CARD16 vid_h, + CARD16 drw_w, CARD16 drw_h, + unsigned int *p_w, unsigned int *p_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + (*portPriv->AdaptorRec->QueryBestSize)(portPriv->pScrn, + (Bool)motion, vid_w, vid_h, drw_w, drw_h, + p_w, p_h, portPriv->DevPriv.ptr); + + return Success; +} + + +static int +xf86XVPutImage( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 src_x, INT16 src_y, + CARD16 src_w, CARD16 src_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h, + XvImagePtr format, + unsigned char* data, + Bool sync, + CARD16 width, CARD16 height +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen; + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + pScreen = pDraw->pScreen; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_NULL(pScreen, &ClipRegion); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = portPriv->pScrn->frameX0; + VPBox.y1 = portPriv->pScrn->frameY0; + VPBox.x2 = portPriv->pScrn->frameX1 + 1; + VPBox.y2 = portPriv->pScrn->frameY1 + 1; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + ret = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(ret != Success) goto PUT_IMAGE_BAILOUT; + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutImage)(portPriv->pScrn, + src_x, src_y, WinBox.x1, WinBox.y1, + src_w, src_h, drw_w, drw_h, format->id, data, width, height, + sync, &ClipRegion, portPriv->DevPriv.ptr, + pDraw); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) { + + portPriv->isOn = XV_ON; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_IMAGE_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +xf86XVQueryImageAttributes( + ClientPtr client, + XvPortPtr pPort, + XvImagePtr format, + CARD16 *width, + CARD16 *height, + int *pitches, + int *offsets +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return (*portPriv->AdaptorRec->QueryImageAttributes)(portPriv->pScrn, + format->id, width, height, pitches, offsets); +} + + +void +xf86XVFillKeyHelperDrawable (DrawablePtr pDraw, CARD32 key, RegionPtr clipboxes) +{ + ScreenPtr pScreen = pDraw->pScreen; + WindowPtr pWin = (WindowPtr)pDraw; + XF86XVWindowPtr pPriv = GET_XF86XV_WINDOW(pWin); + GCPtr pGC = NULL; + BoxPtr pbox = REGION_RECTS(clipboxes); + int i, nbox = REGION_NUM_RECTS(clipboxes); + xRectangle *rects; + + if(!xf86Screens[pScreen->myNum]->vtSema) return; + + if(pPriv) + pGC = pPriv->pGC; + + if(!pGC) { + int status; + XID pval[2]; + pval[0] = key; + pval[1] = IncludeInferiors; + pGC = CreateGC(pDraw, GCForeground | GCSubwindowMode, pval, &status, + (XID)0, serverClient); + if(!pGC) return; + ValidateGC(pDraw, pGC); + if (pPriv) pPriv->pGC = pGC; + } else if (key != pGC->fgPixel){ + ChangeGCVal val; + val.val = key; + ChangeGC(NullClient, pGC, GCForeground, &val); + ValidateGC(pDraw, pGC); + } + + REGION_TRANSLATE(pDraw->pScreen, clipboxes, -pDraw->x, -pDraw->y); + + rects = malloc(nbox * sizeof(xRectangle)); + + for(i = 0; i < nbox; i++, pbox++) { + rects[i].x = pbox->x1; + rects[i].y = pbox->y1; + rects[i].width = pbox->x2 - pbox->x1; + rects[i].height = pbox->y2 - pbox->y1; + } + + (*pGC->ops->PolyFillRect)(pDraw, pGC, nbox, rects); + + if (!pPriv) FreeGC(pGC, 0); + + free(rects); +} + +void +xf86XVFillKeyHelper (ScreenPtr pScreen, CARD32 key, RegionPtr clipboxes) +{ + DrawablePtr root = &WindowTable[pScreen->myNum]->drawable; + ChangeGCVal pval[2]; + BoxPtr pbox = REGION_RECTS(clipboxes); + int i, nbox = REGION_NUM_RECTS(clipboxes); + xRectangle *rects; + GCPtr gc; + + if(!xf86Screens[pScreen->myNum]->vtSema) return; + + gc = GetScratchGC(root->depth, pScreen); + pval[0].val = key; + pval[1].val = IncludeInferiors; + (void) ChangeGC(NullClient, gc, GCForeground|GCSubwindowMode, pval); + ValidateGC(root, gc); + + rects = malloc(nbox * sizeof(xRectangle)); + + for(i = 0; i < nbox; i++, pbox++) + { + rects[i].x = pbox->x1; + rects[i].y = pbox->y1; + rects[i].width = pbox->x2 - pbox->x1; + rects[i].height = pbox->y2 - pbox->y1; + } + + (*gc->ops->PolyFillRect)(root, gc, nbox, rects); + + free(rects); + FreeScratchGC (gc); +} + +/* xf86XVClipVideoHelper - + + Takes the dst box in standard X BoxRec form (top and left + edges inclusive, bottom and right exclusive). The new dst + box is returned. The source boundaries are given (x1, y1 + inclusive, x2, y2 exclusive) and returned are the new source + boundaries in 16.16 fixed point. +*/ + +#define DummyScreen screenInfo.screens[0] + +Bool +xf86XVClipVideoHelper( + BoxPtr dst, + INT32 *xa, + INT32 *xb, + INT32 *ya, + INT32 *yb, + RegionPtr reg, + INT32 width, + INT32 height +){ + double xsw, xdw, ysw, ydw; + INT32 delta; + BoxPtr extents = REGION_EXTENTS(DummyScreen, reg); + int diff; + + xsw = (*xb - *xa) << 16; + xdw = dst->x2 - dst->x1; + ysw = (*yb - *ya) << 16; + ydw = dst->y2 - dst->y1; + + *xa <<= 16; *xb <<= 16; + *ya <<= 16; *yb <<= 16; + + diff = extents->x1 - dst->x1; + if (diff > 0) { + dst->x1 = extents->x1; + *xa += (diff * xsw) / xdw; + } + diff = dst->x2 - extents->x2; + if (diff > 0) { + dst->x2 = extents->x2; + *xb -= (diff * xsw) / xdw; + } + diff = extents->y1 - dst->y1; + if (diff > 0) { + dst->y1 = extents->y1; + *ya += (diff * ysw) / ydw; + } + diff = dst->y2 - extents->y2; + if (diff > 0) { + dst->y2 = extents->y2; + *yb -= (diff * ysw) / ydw; + } + + if (*xa < 0) { + diff = (((-*xa) * xdw) + xsw - 1) / xsw; + dst->x1 += diff; + *xa += (diff * xsw) / xdw; + } + delta = *xb - (width << 16); + if (delta > 0) { + diff = ((delta * xdw) + xsw - 1) / xsw; + dst->x2 -= diff; + *xb -= (diff * xsw) / xdw; + } + if (*xa >= *xb) return FALSE; + + if (*ya < 0) { + diff = (((-*ya) * ydw) + ysw - 1) / ysw; + dst->y1 += diff; + *ya += (diff * ysw) / ydw; + } + delta = *yb - (height << 16); + if (delta > 0) { + diff = ((delta * ydw) + ysw - 1) / ysw; + dst->y2 -= diff; + *yb -= (diff * ysw) / ydw; + } + if (*ya >= *yb) return FALSE; + + if ((dst->x1 > extents->x1) || (dst->x2 < extents->x2) || + (dst->y1 > extents->y1) || (dst->y2 < extents->y2)) + { + RegionRec clipReg; + REGION_INIT(DummyScreen, &clipReg, dst, 1); + REGION_INTERSECT(DummyScreen, reg, reg, &clipReg); + REGION_UNINIT(DummyScreen, &clipReg); + } + return TRUE; +} + +void +xf86XVCopyYUV12ToPacked( + const void *srcy, + const void *srcv, + const void *srcu, + void *dst, + int srcPitchy, + int srcPitchuv, + int dstPitch, + int h, + int w +){ + CARD32 *Dst; + const CARD8 *Y, *U, *V; + int i, j; + + w >>= 1; + + for (j = 0; j < h; j++) { + Dst = dst; + Y = srcy; V = srcv; U = srcu; + i = w; + while (i >= 4) { +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24); + Dst[1] = Y[2] | (Y[3] << 16) | (U[1] << 8) | (V[1] << 24); + Dst[2] = Y[4] | (Y[5] << 16) | (U[2] << 8) | (V[2] << 24); + Dst[3] = Y[6] | (Y[7] << 16) | (U[3] << 8) | (V[3] << 24); +#else + /* This assumes a little-endian framebuffer */ + Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0]; + Dst[1] = (Y[2] << 24) | (Y[3] << 8) | (U[1] << 16) | V[1]; + Dst[2] = (Y[4] << 24) | (Y[5] << 8) | (U[2] << 16) | V[2]; + Dst[3] = (Y[6] << 24) | (Y[7] << 8) | (U[3] << 16) | V[3]; +#endif + Dst += 4; Y += 8; V += 4; U += 4; + i -= 4; + } + + while (i--) { +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24); +#else + /* This assumes a little-endian framebuffer */ + Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0]; +#endif + Dst++; Y += 2; V++; U++; + } + + dst = (CARD8 *)dst + dstPitch; + srcy = (const CARD8 *)srcy + srcPitchy; + if (j & 1) { + srcu = (const CARD8 *)srcu + srcPitchuv; + srcv = (const CARD8 *)srcv + srcPitchuv; + } + } +} + +void +xf86XVCopyPacked( + const void *src, + void *dst, + int srcPitch, + int dstPitch, + int h, + int w +){ + const CARD32 *Src; + CARD32 *Dst; + int i; + + w >>= 1; + while (--h >= 0) { + do { + Dst = dst; Src = src; + i = w; + while (i >= 4) { + Dst[0] = Src[0]; + Dst[1] = Src[1]; + Dst[2] = Src[2]; + Dst[3] = Src[3]; + Dst += 4; Src += 4; i -= 4; + } + if (!i) break; + Dst[0] = Src[0]; + if (i == 1) break; + Dst[1] = Src[1]; + if (i == 2) break; + Dst[2] = Src[2]; + } while (0); + + src = (const CARD8 *)src + srcPitch; + dst = (CARD8 *)dst + dstPitch; + } +} diff --git a/xorg-server/hw/xfree86/common/xf86xvmc.c b/xorg-server/hw/xfree86/common/xf86xvmc.c index 39d33da08..9cf36f526 100644 --- a/xorg-server/hw/xfree86/common/xf86xvmc.c +++ b/xorg-server/hw/xfree86/common/xf86xvmc.c @@ -1,229 +1,229 @@ - -/* - * Copyright (c) 2001-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "scrnintstr.h" -#include "resource.h" -#include "dixstruct.h" - -#include "xvmodproc.h" - -#include "xf86xvpriv.h" -#include "xf86xvmc.h" - -XvMCScreenInitProcPtr XvMCScreenInitProc = NULL; - - -typedef struct { - CloseScreenProcPtr CloseScreen; - int num_adaptors; - XF86MCAdaptorPtr *adaptors; - XvMCAdaptorPtr dixinfo; -} xf86XvMCScreenRec, *xf86XvMCScreenPtr; - -static int XF86XvMCScreenKeyIndex; -static DevPrivateKey XF86XvMCScreenKey = &XF86XvMCScreenKeyIndex; - -#define XF86XVMC_GET_PRIVATE(pScreen) (xf86XvMCScreenPtr) \ - dixLookupPrivate(&(pScreen)->devPrivates, XF86XvMCScreenKey) - - -static int -xf86XvMCCreateContext ( - XvPortPtr pPort, - XvMCContextPtr pContext, - int *num_priv, - CARD32 **priv -) -{ - xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); - ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; - - pContext->port_priv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return (*pScreenPriv->adaptors[pContext->adapt_num]->CreateContext)( - pScrn, pContext, num_priv, priv); -} - -static void -xf86XvMCDestroyContext ( XvMCContextPtr pContext) -{ - xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); - ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; - - (*pScreenPriv->adaptors[pContext->adapt_num]->DestroyContext)( - pScrn, pContext); -} - -static int -xf86XvMCCreateSurface ( - XvMCSurfacePtr pSurface, - int *num_priv, - CARD32 **priv -) -{ - XvMCContextPtr pContext = pSurface->context; - xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); - ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; - - return (*pScreenPriv->adaptors[pContext->adapt_num]->CreateSurface)( - pScrn, pSurface, num_priv, priv); -} - -static void -xf86XvMCDestroySurface (XvMCSurfacePtr pSurface) -{ - XvMCContextPtr pContext = pSurface->context; - xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); - ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; - - (*pScreenPriv->adaptors[pContext->adapt_num]->DestroySurface)( - pScrn, pSurface); -} - -static int -xf86XvMCCreateSubpicture ( - XvMCSubpicturePtr pSubpicture, - int *num_priv, - CARD32 **priv -) -{ - XvMCContextPtr pContext = pSubpicture->context; - xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); - ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; - - return (*pScreenPriv->adaptors[pContext->adapt_num]->CreateSubpicture)( - pScrn, pSubpicture, num_priv, priv); -} - -static void -xf86XvMCDestroySubpicture (XvMCSubpicturePtr pSubpicture) -{ - XvMCContextPtr pContext = pSubpicture->context; - xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); - ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; - - (*pScreenPriv->adaptors[pContext->adapt_num]->DestroySubpicture)( - pScrn, pSubpicture); -} - - -static Bool -xf86XvMCCloseScreen (int i, ScreenPtr pScreen) -{ - xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pScreen); - - pScreen->CloseScreen = pScreenPriv->CloseScreen; - - xfree(pScreenPriv->dixinfo); - xfree(pScreenPriv); - - return (*pScreen->CloseScreen)(i, pScreen); -} - -Bool xf86XvMCScreenInit( - ScreenPtr pScreen, - int num_adaptors, - XF86MCAdaptorPtr *adaptors -) -{ - XvMCAdaptorPtr pAdapt; - xf86XvMCScreenPtr pScreenPriv; - XvScreenPtr pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - XF86XvScreenKey); - int i, j; - - if(!XvMCScreenInitProc) return FALSE; - - if(!(pAdapt = xalloc(sizeof(XvMCAdaptorRec) * num_adaptors))) - return FALSE; - - if(!(pScreenPriv = xalloc(sizeof(xf86XvMCScreenRec)))) { - xfree(pAdapt); - return FALSE; - } - - dixSetPrivate(&pScreen->devPrivates, XF86XvMCScreenKey, pScreenPriv); - - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = xf86XvMCCloseScreen; - - pScreenPriv->num_adaptors = num_adaptors; - pScreenPriv->adaptors = adaptors; - pScreenPriv->dixinfo = pAdapt; - - for(i = 0; i < num_adaptors; i++) { - pAdapt[i].xv_adaptor = NULL; - for(j = 0; j < pxvs->nAdaptors; j++) { - if(!strcmp((*adaptors)->name, pxvs->pAdaptors[j].name)) { - pAdapt[i].xv_adaptor = &(pxvs->pAdaptors[j]); - break; - } - } - if(!pAdapt[i].xv_adaptor) { - /* no adaptor by that name */ - xfree(pAdapt); - return FALSE; - } - pAdapt[i].num_surfaces = (*adaptors)->num_surfaces; - pAdapt[i].surfaces = (XvMCSurfaceInfoPtr*)((*adaptors)->surfaces); - pAdapt[i].num_subpictures = (*adaptors)->num_subpictures; - pAdapt[i].subpictures = (XvImagePtr*)((*adaptors)->subpictures); - pAdapt[i].CreateContext = xf86XvMCCreateContext; - pAdapt[i].DestroyContext = xf86XvMCDestroyContext; - pAdapt[i].CreateSurface = xf86XvMCCreateSurface; - pAdapt[i].DestroySurface = xf86XvMCDestroySurface; - pAdapt[i].CreateSubpicture = xf86XvMCCreateSubpicture; - pAdapt[i].DestroySubpicture = xf86XvMCDestroySubpicture; - adaptors++; - } - - if(Success != (*XvMCScreenInitProc)(pScreen, num_adaptors, pAdapt)) - return FALSE; - - return TRUE; -} - -XF86MCAdaptorPtr xf86XvMCCreateAdaptorRec (void) -{ - return xcalloc(1, sizeof(XF86MCAdaptorRec)); -} - -void xf86XvMCDestroyAdaptorRec(XF86MCAdaptorPtr adaptor) -{ - xfree(adaptor); -} + +/* + * Copyright (c) 2001-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "resource.h" +#include "dixstruct.h" + +#include "xvmodproc.h" + +#include "xf86xvpriv.h" +#include "xf86xvmc.h" + +XvMCScreenInitProcPtr XvMCScreenInitProc = NULL; + + +typedef struct { + CloseScreenProcPtr CloseScreen; + int num_adaptors; + XF86MCAdaptorPtr *adaptors; + XvMCAdaptorPtr dixinfo; +} xf86XvMCScreenRec, *xf86XvMCScreenPtr; + +static int XF86XvMCScreenKeyIndex; +static DevPrivateKey XF86XvMCScreenKey = &XF86XvMCScreenKeyIndex; + +#define XF86XVMC_GET_PRIVATE(pScreen) (xf86XvMCScreenPtr) \ + dixLookupPrivate(&(pScreen)->devPrivates, XF86XvMCScreenKey) + + +static int +xf86XvMCCreateContext ( + XvPortPtr pPort, + XvMCContextPtr pContext, + int *num_priv, + CARD32 **priv +) +{ + xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); + ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; + + pContext->port_priv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return (*pScreenPriv->adaptors[pContext->adapt_num]->CreateContext)( + pScrn, pContext, num_priv, priv); +} + +static void +xf86XvMCDestroyContext ( XvMCContextPtr pContext) +{ + xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); + ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; + + (*pScreenPriv->adaptors[pContext->adapt_num]->DestroyContext)( + pScrn, pContext); +} + +static int +xf86XvMCCreateSurface ( + XvMCSurfacePtr pSurface, + int *num_priv, + CARD32 **priv +) +{ + XvMCContextPtr pContext = pSurface->context; + xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); + ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; + + return (*pScreenPriv->adaptors[pContext->adapt_num]->CreateSurface)( + pScrn, pSurface, num_priv, priv); +} + +static void +xf86XvMCDestroySurface (XvMCSurfacePtr pSurface) +{ + XvMCContextPtr pContext = pSurface->context; + xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); + ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; + + (*pScreenPriv->adaptors[pContext->adapt_num]->DestroySurface)( + pScrn, pSurface); +} + +static int +xf86XvMCCreateSubpicture ( + XvMCSubpicturePtr pSubpicture, + int *num_priv, + CARD32 **priv +) +{ + XvMCContextPtr pContext = pSubpicture->context; + xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); + ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; + + return (*pScreenPriv->adaptors[pContext->adapt_num]->CreateSubpicture)( + pScrn, pSubpicture, num_priv, priv); +} + +static void +xf86XvMCDestroySubpicture (XvMCSubpicturePtr pSubpicture) +{ + XvMCContextPtr pContext = pSubpicture->context; + xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pContext->pScreen); + ScrnInfoPtr pScrn = xf86Screens[pContext->pScreen->myNum]; + + (*pScreenPriv->adaptors[pContext->adapt_num]->DestroySubpicture)( + pScrn, pSubpicture); +} + + +static Bool +xf86XvMCCloseScreen (int i, ScreenPtr pScreen) +{ + xf86XvMCScreenPtr pScreenPriv = XF86XVMC_GET_PRIVATE(pScreen); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + + free(pScreenPriv->dixinfo); + free(pScreenPriv); + + return (*pScreen->CloseScreen)(i, pScreen); +} + +Bool xf86XvMCScreenInit( + ScreenPtr pScreen, + int num_adaptors, + XF86MCAdaptorPtr *adaptors +) +{ + XvMCAdaptorPtr pAdapt; + xf86XvMCScreenPtr pScreenPriv; + XvScreenPtr pxvs = (XvScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + XF86XvScreenKey); + int i, j; + + if(!XvMCScreenInitProc) return FALSE; + + if(!(pAdapt = malloc(sizeof(XvMCAdaptorRec) * num_adaptors))) + return FALSE; + + if(!(pScreenPriv = malloc(sizeof(xf86XvMCScreenRec)))) { + free(pAdapt); + return FALSE; + } + + dixSetPrivate(&pScreen->devPrivates, XF86XvMCScreenKey, pScreenPriv); + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = xf86XvMCCloseScreen; + + pScreenPriv->num_adaptors = num_adaptors; + pScreenPriv->adaptors = adaptors; + pScreenPriv->dixinfo = pAdapt; + + for(i = 0; i < num_adaptors; i++) { + pAdapt[i].xv_adaptor = NULL; + for(j = 0; j < pxvs->nAdaptors; j++) { + if(!strcmp((*adaptors)->name, pxvs->pAdaptors[j].name)) { + pAdapt[i].xv_adaptor = &(pxvs->pAdaptors[j]); + break; + } + } + if(!pAdapt[i].xv_adaptor) { + /* no adaptor by that name */ + free(pAdapt); + return FALSE; + } + pAdapt[i].num_surfaces = (*adaptors)->num_surfaces; + pAdapt[i].surfaces = (XvMCSurfaceInfoPtr*)((*adaptors)->surfaces); + pAdapt[i].num_subpictures = (*adaptors)->num_subpictures; + pAdapt[i].subpictures = (XvImagePtr*)((*adaptors)->subpictures); + pAdapt[i].CreateContext = xf86XvMCCreateContext; + pAdapt[i].DestroyContext = xf86XvMCDestroyContext; + pAdapt[i].CreateSurface = xf86XvMCCreateSurface; + pAdapt[i].DestroySurface = xf86XvMCDestroySurface; + pAdapt[i].CreateSubpicture = xf86XvMCCreateSubpicture; + pAdapt[i].DestroySubpicture = xf86XvMCDestroySubpicture; + adaptors++; + } + + if(Success != (*XvMCScreenInitProc)(pScreen, num_adaptors, pAdapt)) + return FALSE; + + return TRUE; +} + +XF86MCAdaptorPtr xf86XvMCCreateAdaptorRec (void) +{ + return calloc(1, sizeof(XF86MCAdaptorRec)); +} + +void xf86XvMCDestroyAdaptorRec(XF86MCAdaptorPtr adaptor) +{ + free(adaptor); +} diff --git a/xorg-server/hw/xfree86/common/xisb.c b/xorg-server/hw/xfree86/common/xisb.c index 1cb9e4854..f08327fb3 100644 --- a/xorg-server/hw/xfree86/common/xisb.c +++ b/xorg-server/hw/xfree86/common/xisb.c @@ -1,174 +1,174 @@ -/* - * Copyright (c) 1997 Metro Link Incorporated - * - * 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 Metro Link shall not be - * used in advertising or otherwise to promote the sale, use or other dealings - * in this Software without prior written authorization from Metro Link. - * - */ - -/* - X Input Serial Buffer routines for use in any XInput driver that accesses - a serial device. -*/ - - -/***************************************************************************** - * Standard Headers - ****************************************************************************/ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <misc.h> -#include <xf86.h> -#include <xf86_OSproc.h> -#include <xf86_OSlib.h> -#include <xf86Xinput.h> -#include "xisb.h" - -/***************************************************************************** - * Local Headers - ****************************************************************************/ - -/***************************************************************************** - * Variables without includable headers - ****************************************************************************/ - -/***************************************************************************** - * Local Variables - ****************************************************************************/ - -/***************************************************************************** - * Function Definitions - ****************************************************************************/ - -XISBuffer * -XisbNew (int fd, ssize_t size) -{ - XISBuffer *b; - - b = xalloc (sizeof (XISBuffer)); - if (!b) - return (NULL); - b->buf = xalloc ((sizeof (unsigned char) * size)); - if (!b->buf) - { - xfree (b); - return (NULL); - } - - b->fd = fd; - b->trace = 0; - b->block_duration = 0; - b->current = 1; /* force it to be past the end to trigger initial read */ - b->end = 0; - b->buffer_size = size; - return (b); -} - -void -XisbFree (XISBuffer *b) -{ - xfree (b->buf); - xfree (b); -} - -int -XisbRead (XISBuffer *b) -{ - int ret; - - if (b->current >= b->end) - { - if (b->block_duration >= 0) - { - if (xf86WaitForInput (b->fd, b->block_duration) < 1) - return (-1); - } - else - { - /* - * automatically clear it so if XisbRead is called in a loop - * the next call will make sure there is data with select and - * thus prevent a blocking read - */ - b->block_duration = 0; - } - - ret = xf86ReadSerial (b->fd, b->buf, b->buffer_size); - switch (ret) - { - case 0: - return (-1); /* timeout */ - case -1: - return (-2); /* error */ - default: - b->end = ret; - b->current = 0; - break; - } - } - if (b->trace) - ErrorF ("read 0x%02x (%c)\n", b->buf[b->current], - isprint(b->buf[b->current])?b->buf[b->current]:'.'); - - return (b->buf[b->current++]); -} - -/* the only purpose of this function is to provide output tracing */ -ssize_t -XisbWrite (XISBuffer *b, unsigned char *msg, ssize_t len) -{ - if (b->trace) - { - int i = 0; - for (i = 0; i < len; i++) - ErrorF ("\t\twrote 0x%02x (%c)\n", msg[i], msg[i]); - } - return (xf86WriteSerial (b->fd, msg, len)); -} - -/* turn tracing of this buffer on (1) or off (0) */ -void -XisbTrace (XISBuffer *b, int trace) -{ - b->trace = trace; -} - -/* - * specify a block_duration of -1 when you know the buffer's fd is ready to - * read. After a read, it is automatically set to 0 so that the next read - * will use check to select for data and prevent a block. - * It is the caller's responsibility to set the block_duration to -1 if it - * knows that there is data to read (because the main select loop triggered - * the read) and want's to avoid the unnecessary overhead of the select call - * - * a zero or positive block duration will cause the select to block for the - * give duration in usecs. - */ - -void -XisbBlockDuration (XISBuffer *b, int block_duration) -{ - b->block_duration = block_duration; -} +/* + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ + +/* + X Input Serial Buffer routines for use in any XInput driver that accesses + a serial device. +*/ + + +/***************************************************************************** + * Standard Headers + ****************************************************************************/ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <misc.h> +#include <xf86.h> +#include <xf86_OSproc.h> +#include <xf86_OSlib.h> +#include <xf86Xinput.h> +#include "xisb.h" + +/***************************************************************************** + * Local Headers + ****************************************************************************/ + +/***************************************************************************** + * Variables without includable headers + ****************************************************************************/ + +/***************************************************************************** + * Local Variables + ****************************************************************************/ + +/***************************************************************************** + * Function Definitions + ****************************************************************************/ + +XISBuffer * +XisbNew (int fd, ssize_t size) +{ + XISBuffer *b; + + b = malloc(sizeof (XISBuffer)); + if (!b) + return (NULL); + b->buf = malloc((sizeof (unsigned char) * size)); + if (!b->buf) + { + free(b); + return (NULL); + } + + b->fd = fd; + b->trace = 0; + b->block_duration = 0; + b->current = 1; /* force it to be past the end to trigger initial read */ + b->end = 0; + b->buffer_size = size; + return (b); +} + +void +XisbFree (XISBuffer *b) +{ + free(b->buf); + free(b); +} + +int +XisbRead (XISBuffer *b) +{ + int ret; + + if (b->current >= b->end) + { + if (b->block_duration >= 0) + { + if (xf86WaitForInput (b->fd, b->block_duration) < 1) + return (-1); + } + else + { + /* + * automatically clear it so if XisbRead is called in a loop + * the next call will make sure there is data with select and + * thus prevent a blocking read + */ + b->block_duration = 0; + } + + ret = xf86ReadSerial (b->fd, b->buf, b->buffer_size); + switch (ret) + { + case 0: + return (-1); /* timeout */ + case -1: + return (-2); /* error */ + default: + b->end = ret; + b->current = 0; + break; + } + } + if (b->trace) + ErrorF ("read 0x%02x (%c)\n", b->buf[b->current], + isprint(b->buf[b->current])?b->buf[b->current]:'.'); + + return (b->buf[b->current++]); +} + +/* the only purpose of this function is to provide output tracing */ +ssize_t +XisbWrite (XISBuffer *b, unsigned char *msg, ssize_t len) +{ + if (b->trace) + { + int i = 0; + for (i = 0; i < len; i++) + ErrorF ("\t\twrote 0x%02x (%c)\n", msg[i], msg[i]); + } + return (xf86WriteSerial (b->fd, msg, len)); +} + +/* turn tracing of this buffer on (1) or off (0) */ +void +XisbTrace (XISBuffer *b, int trace) +{ + b->trace = trace; +} + +/* + * specify a block_duration of -1 when you know the buffer's fd is ready to + * read. After a read, it is automatically set to 0 so that the next read + * will use check to select for data and prevent a block. + * It is the caller's responsibility to set the block_duration to -1 if it + * knows that there is data to read (because the main select loop triggered + * the read) and want's to avoid the unnecessary overhead of the select call + * + * a zero or positive block duration will cause the select to block for the + * give duration in usecs. + */ + +void +XisbBlockDuration (XISBuffer *b, int block_duration) +{ + b->block_duration = block_duration; +} diff --git a/xorg-server/hw/xfree86/ddc/ddc.c b/xorg-server/hw/xfree86/ddc/ddc.c index 6fad9fbbc..ec6465818 100644 --- a/xorg-server/hw/xfree86/ddc/ddc.c +++ b/xorg-server/hw/xfree86/ddc/ddc.c @@ -1,507 +1,507 @@ -/* xf86DDC.c - * - * Copyright 1998,1999 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> - */ - -/* - * A note on terminology. DDC1 is the original dumb serial protocol, and - * can only do up to 128 bytes of EDID. DDC2 is I2C-encapsulated and - * introduces extension blocks. EDID is the old display identification - * block, DisplayID is the new one. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" -#include "xf86DDC.h" -#include <string.h> - -#define RETRIES 4 - -typedef enum { - DDCOPT_NODDC1, - DDCOPT_NODDC2, - DDCOPT_NODDC -} DDCOpts; - -static const OptionInfoRec DDCOptions[] = { - { DDCOPT_NODDC1, "NoDDC1", OPTV_BOOLEAN, {0}, FALSE }, - { DDCOPT_NODDC2, "NoDDC2", OPTV_BOOLEAN, {0}, FALSE }, - { DDCOPT_NODDC, "NoDDC", OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, OPTV_NONE, {0}, FALSE }, -}; - -/* DDC1 */ - -static int -find_start(unsigned int *ptr) -{ - unsigned int comp[9], test[9]; - int i,j; - - for (i=0;i<9;i++){ - comp[i] = *(ptr++); - test[i] = 1; - } - for (i=0;i<127;i++){ - for (j=0;j<9;j++){ - test[j] = test[j] & !(comp[j] ^ *(ptr++)); - } - } - for (i=0;i<9;i++) - if (test[i]) return (i+1); - return (-1); -} - -static unsigned char * -find_header(unsigned char *block) -{ - unsigned char *ptr, *head_ptr, *end; - unsigned char header[]={0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}; - - ptr = block; - end = block + EDID1_LEN; - while (ptr<end) { - int i; - head_ptr = ptr; - for (i=0;i<8;i++){ - if (header[i] != *(head_ptr++)) break; - if (head_ptr == end) head_ptr = block; - } - if (i==8) break; - ptr++; - } - if (ptr == end) return (NULL); - return (ptr); -} - -static unsigned char * -resort(unsigned char *s_block) -{ - unsigned char *d_new, *d_ptr, *d_end, *s_ptr, *s_end; - unsigned char tmp; - - s_end = s_block + EDID1_LEN; - d_new = xalloc(EDID1_LEN); - if (!d_new) return NULL; - d_end = d_new + EDID1_LEN; - - s_ptr = find_header(s_block); - if (!s_ptr) return NULL; - for (d_ptr=d_new;d_ptr<d_end;d_ptr++){ - tmp = *(s_ptr++); - *d_ptr = tmp; - if (s_ptr == s_end) s_ptr = s_block; - } - xfree(s_block); - return (d_new); -} - -static int -DDC_checksum(unsigned char *block, int len) -{ - int i, result = 0; - int not_null = 0; - - for (i=0;i<len;i++) { - not_null |= block[i]; - result += block[i]; - } - -#ifdef DEBUG - if (result & 0xFF) ErrorF("DDC checksum not correct\n"); - if (!not_null) ErrorF("DDC read all Null\n"); -#endif - - /* catch the trivial case where all bytes are 0 */ - if (!not_null) return 1; - - return (result&0xFF); -} - -static unsigned char * -GetEDID_DDC1(unsigned int *s_ptr) -{ - unsigned char *d_block, *d_pos; - unsigned int *s_pos, *s_end; - int s_start; - int i,j; - s_start = find_start(s_ptr); - if (s_start==-1) return NULL; - s_end = s_ptr + NUM; - s_pos = s_ptr + s_start; - d_block=xalloc(EDID1_LEN); - if (!d_block) return NULL; - d_pos = d_block; - for (i=0;i<EDID1_LEN;i++) { - for (j=0;j<8;j++) { - *d_pos <<= 1; - if (*s_pos) { - *d_pos |= 0x01; - } - s_pos++; if (s_pos == s_end) s_pos=s_ptr; - }; - s_pos++; if (s_pos == s_end) s_pos=s_ptr; - d_pos++; - } - xfree(s_ptr); - if (d_block && DDC_checksum(d_block,EDID1_LEN)) return NULL; - return (resort(d_block)); -} - -/* fetch entire EDID record; DDC bit needs to be masked */ -static unsigned int * -FetchEDID_DDC1(register ScrnInfoPtr pScrn, - register unsigned int (*read_DDC)(ScrnInfoPtr)) -{ - int count = NUM; - unsigned int *ptr, *xp; - - ptr=xp=xalloc(sizeof(int)*NUM); - - if (!ptr) return NULL; - do { - /* wait for next retrace */ - *xp = read_DDC(pScrn); - xp++; - } while(--count); - return (ptr); -} - -/* test if DDC1 return 0 if not */ -static Bool -TestDDC1(ScrnInfoPtr pScrn, unsigned int (*read_DDC)(ScrnInfoPtr)) -{ - int old, count; - - old = read_DDC(pScrn); - count = HEADER * BITS_PER_BYTE; - do { - /* wait for next retrace */ - if (old != read_DDC(pScrn)) break; - } while(count--); - return (count); -} - -/* - * read EDID record , pass it to callback function to interpret. - * callback function will store it for further use by calling - * function; it will also decide if we need to reread it - */ -static unsigned char * -EDIDRead_DDC1(ScrnInfoPtr pScrn, DDC1SetSpeedProc DDCSpeed, - unsigned int (*read_DDC)(ScrnInfoPtr)) -{ - unsigned char *EDID_block = NULL; - int count = RETRIES; - - if (!read_DDC) { - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, - "chipset doesn't support DDC1\n"); - return NULL; - }; - - if (TestDDC1(pScrn,read_DDC)==-1) { - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "No DDC signal\n"); - return NULL; - }; - - if (DDCSpeed) DDCSpeed(pScrn,DDC_FAST); - do { - EDID_block = GetEDID_DDC1(FetchEDID_DDC1(pScrn,read_DDC)); - count --; - } while (!EDID_block && count); - if (DDCSpeed) DDCSpeed(pScrn,DDC_SLOW); - - return EDID_block; -} - -/** - * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC1 are - * unset. EDID information blocks are interpreted and the results returned in - * an xf86MonPtr. - * - * This function does not affect the list of modes used by drivers -- it is up - * to the driver to decide policy on what to do with EDID information. - * - * @return pointer to a new xf86MonPtr containing the EDID information. - * @return NULL if no monitor attached or failure to interpret the EDID. - */ -xf86MonPtr -xf86DoEDID_DDC1( - int scrnIndex, DDC1SetSpeedProc DDC1SetSpeed, - unsigned int (*DDC1Read)(ScrnInfoPtr) -) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - unsigned char *EDID_block = NULL; - xf86MonPtr tmp = NULL; - int sigio; - /* Default DDC and DDC1 to enabled. */ - Bool noddc = FALSE, noddc1 = FALSE; - OptionInfoPtr options; - - options = xnfalloc(sizeof(DDCOptions)); - (void)memcpy(options, DDCOptions, sizeof(DDCOptions)); - xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); - - xf86GetOptValBool(options, DDCOPT_NODDC, &noddc); - xf86GetOptValBool(options, DDCOPT_NODDC1, &noddc1); - xfree(options); - - if (noddc || noddc1) - return NULL; - - sigio = xf86BlockSIGIO(); - EDID_block = EDIDRead_DDC1(pScrn,DDC1SetSpeed,DDC1Read); - xf86UnblockSIGIO(sigio); - - if (EDID_block){ - tmp = xf86InterpretEDID(scrnIndex,EDID_block); - } -#ifdef DEBUG - else ErrorF("No EDID block returned\n"); - if (!tmp) - ErrorF("Cannot interpret EDID block\n"); -#endif - return tmp; -} - -/* DDC2 */ - -static I2CDevPtr -DDC2MakeDevice(I2CBusPtr pBus, int address, char *name) -{ - I2CDevPtr dev = NULL; - - if (!(dev = xf86I2CFindDev(pBus, address))) { - dev = xf86CreateI2CDevRec(); - dev->DevName = name; - dev->SlaveAddr = address; - dev->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ - dev->StartTimeout = 550; - dev->BitTimeout = 40; - dev->AcknTimeout = 40; - - dev->pI2CBus = pBus; - if (!xf86I2CDevInit(dev)) { - xf86DrvMsg(pBus->scrnIndex, X_PROBED, "No DDC2 device\n"); - return NULL; - } - } - - return dev; -} - -static I2CDevPtr -DDC2Init(int scrnIndex, I2CBusPtr pBus) -{ - I2CDevPtr dev = NULL; - - /* - * Slow down the bus so that older monitors don't - * miss things. - */ - pBus->RiseFallTime = 20; - - dev = DDC2MakeDevice(pBus, 0x00A0, "ddc2"); - if (xf86I2CProbeAddress(pBus, 0x0060)) - DDC2MakeDevice(pBus, 0x0060, "E-EDID segment register"); - if (xf86I2CProbeAddress(pBus, 0x0062)) - DDC2MakeDevice(pBus, 0x0062, "EDID EEPROM interface"); - if (xf86I2CProbeAddress(pBus, 0x006E)) - DDC2MakeDevice(pBus, 0x006E, "DDC control interface"); - - return dev; -} - -/* Mmmm, smell the hacks */ -static void -EEDIDStop(I2CDevPtr d) -{ -} - -/* block is the EDID block number. a segment is two blocks. */ -static Bool -DDC2Read(I2CDevPtr dev, int block, unsigned char *R_Buffer) -{ - unsigned char W_Buffer[1]; - int i, segment; - I2CDevPtr seg; - void (*stop)(I2CDevPtr); - - for (i = 0; i < RETRIES; i++) { - /* Stop bits reset the segment pointer to 0, so be careful here. */ - segment = block >> 1; - if (segment) { - Bool b; - - if (!(seg = xf86I2CFindDev(dev->pI2CBus, 0x0060))) - return FALSE; - - W_Buffer[0] = segment; - - stop = dev->pI2CBus->I2CStop; - dev->pI2CBus->I2CStop = EEDIDStop; - - b = xf86I2CWriteRead(seg, W_Buffer, 1, NULL, 0); - - dev->pI2CBus->I2CStop = stop; - if (!b) { - dev->pI2CBus->I2CStop(dev); - continue; - } - } - - W_Buffer[0] = (block & 0x01) * EDID1_LEN; - - if (xf86I2CWriteRead(dev, W_Buffer, 1, R_Buffer, EDID1_LEN)) { - if (!DDC_checksum(R_Buffer, EDID1_LEN)) - return TRUE; - } - } - - return FALSE; -} - -/** - * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC2 are - * unset. EDID information blocks are interpreted and the results returned in - * an xf86MonPtr. Unlike xf86DoEDID_DDC[12](), this function will return - * the complete EDID data, including all extension blocks, if the 'complete' - * parameter is TRUE; - * - * This function does not affect the list of modes used by drivers -- it is up - * to the driver to decide policy on what to do with EDID information. - * - * @return pointer to a new xf86MonPtr containing the EDID information. - * @return NULL if no monitor attached or failure to interpret the EDID. - */ -xf86MonPtr -xf86DoEEDID(int scrnIndex, I2CBusPtr pBus, Bool complete) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - unsigned char *EDID_block = NULL; - xf86MonPtr tmp = NULL; - I2CDevPtr dev = NULL; - /* Default DDC and DDC2 to enabled. */ - Bool noddc = FALSE, noddc2 = FALSE; - OptionInfoPtr options; - - options = xalloc(sizeof(DDCOptions)); - if (!options) - return NULL; - memcpy(options, DDCOptions, sizeof(DDCOptions)); - xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); - - xf86GetOptValBool(options, DDCOPT_NODDC, &noddc); - xf86GetOptValBool(options, DDCOPT_NODDC2, &noddc2); - xfree(options); - - if (noddc || noddc2) - return NULL; - - if (!(dev = DDC2Init(scrnIndex, pBus))) - return NULL; - - EDID_block = xcalloc(1, EDID1_LEN); - if (!EDID_block) - return NULL; - - if (DDC2Read(dev, 0, EDID_block)) { - int i, n = EDID_block[0x7e]; - - if (complete && n) { - EDID_block = xrealloc(EDID_block, EDID1_LEN * (1+n)); - - for (i = 0; i < n; i++) - DDC2Read(dev, i+1, EDID_block + (EDID1_LEN * (1+i))); - } - - tmp = xf86InterpretEEDID(scrnIndex, EDID_block); - } - - if (tmp && complete) - tmp->flags |= MONITOR_EDID_COMPLETE_RAWDATA; - - return tmp; -} - -/** - * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC2 are - * unset. EDID information blocks are interpreted and the results returned in - * an xf86MonPtr. - * - * This function does not affect the list of modes used by drivers -- it is up - * to the driver to decide policy on what to do with EDID information. - * - * @return pointer to a new xf86MonPtr containing the EDID information. - * @return NULL if no monitor attached or failure to interpret the EDID. - */ -xf86MonPtr -xf86DoEDID_DDC2(int scrnIndex, I2CBusPtr pBus) -{ - return xf86DoEEDID(scrnIndex, pBus, FALSE); -} - -/* XXX write me */ -static void * -DDC2ReadDisplayID(void) -{ - return FALSE; -} - -/** - * Attempts to probe the monitor for DisplayID information, if NoDDC and - * NoDDC2 are unset. DisplayID blocks are interpreted and the results - * returned in an xf86MonPtr. - * - * This function does not affect the list of modes used by drivers -- it is up - * to the driver to decide policy on what to do with DisplayID information. - * - * @return pointer to a new xf86MonPtr containing the DisplayID information. - * @return NULL if no monitor attached or failure to interpret the DisplayID. - */ -xf86MonPtr -xf86DoDisplayID(int scrnIndex, I2CBusPtr pBus) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - unsigned char *did = NULL; - xf86MonPtr tmp = NULL; - I2CDevPtr dev = NULL; - /* Default DDC and DDC2 to enabled. */ - Bool noddc = FALSE, noddc2 = FALSE; - OptionInfoPtr options; - - options = xalloc(sizeof(DDCOptions)); - if (!options) - return NULL; - memcpy(options, DDCOptions, sizeof(DDCOptions)); - xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); - - xf86GetOptValBool(options, DDCOPT_NODDC, &noddc); - xf86GetOptValBool(options, DDCOPT_NODDC2, &noddc2); - xfree(options); - - if (noddc || noddc2) - return NULL; - - if (!(dev = DDC2Init(scrnIndex, pBus))) - return NULL; - - if ((did = DDC2ReadDisplayID())) { - tmp = xcalloc(1, sizeof(*tmp)); - if (!tmp) - return NULL; - - tmp->scrnIndex = scrnIndex; - tmp->flags |= MONITOR_DISPLAYID; - tmp->rawData = did; - } - - return tmp; -} +/* xf86DDC.c + * + * Copyright 1998,1999 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> + */ + +/* + * A note on terminology. DDC1 is the original dumb serial protocol, and + * can only do up to 128 bytes of EDID. DDC2 is I2C-encapsulated and + * introduces extension blocks. EDID is the old display identification + * block, DisplayID is the new one. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86DDC.h" +#include <string.h> + +#define RETRIES 4 + +typedef enum { + DDCOPT_NODDC1, + DDCOPT_NODDC2, + DDCOPT_NODDC +} DDCOpts; + +static const OptionInfoRec DDCOptions[] = { + { DDCOPT_NODDC1, "NoDDC1", OPTV_BOOLEAN, {0}, FALSE }, + { DDCOPT_NODDC2, "NoDDC2", OPTV_BOOLEAN, {0}, FALSE }, + { DDCOPT_NODDC, "NoDDC", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +/* DDC1 */ + +static int +find_start(unsigned int *ptr) +{ + unsigned int comp[9], test[9]; + int i,j; + + for (i=0;i<9;i++){ + comp[i] = *(ptr++); + test[i] = 1; + } + for (i=0;i<127;i++){ + for (j=0;j<9;j++){ + test[j] = test[j] & !(comp[j] ^ *(ptr++)); + } + } + for (i=0;i<9;i++) + if (test[i]) return (i+1); + return (-1); +} + +static unsigned char * +find_header(unsigned char *block) +{ + unsigned char *ptr, *head_ptr, *end; + unsigned char header[]={0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}; + + ptr = block; + end = block + EDID1_LEN; + while (ptr<end) { + int i; + head_ptr = ptr; + for (i=0;i<8;i++){ + if (header[i] != *(head_ptr++)) break; + if (head_ptr == end) head_ptr = block; + } + if (i==8) break; + ptr++; + } + if (ptr == end) return (NULL); + return (ptr); +} + +static unsigned char * +resort(unsigned char *s_block) +{ + unsigned char *d_new, *d_ptr, *d_end, *s_ptr, *s_end; + unsigned char tmp; + + s_end = s_block + EDID1_LEN; + d_new = malloc(EDID1_LEN); + if (!d_new) return NULL; + d_end = d_new + EDID1_LEN; + + s_ptr = find_header(s_block); + if (!s_ptr) return NULL; + for (d_ptr=d_new;d_ptr<d_end;d_ptr++){ + tmp = *(s_ptr++); + *d_ptr = tmp; + if (s_ptr == s_end) s_ptr = s_block; + } + free(s_block); + return (d_new); +} + +static int +DDC_checksum(unsigned char *block, int len) +{ + int i, result = 0; + int not_null = 0; + + for (i=0;i<len;i++) { + not_null |= block[i]; + result += block[i]; + } + +#ifdef DEBUG + if (result & 0xFF) ErrorF("DDC checksum not correct\n"); + if (!not_null) ErrorF("DDC read all Null\n"); +#endif + + /* catch the trivial case where all bytes are 0 */ + if (!not_null) return 1; + + return (result&0xFF); +} + +static unsigned char * +GetEDID_DDC1(unsigned int *s_ptr) +{ + unsigned char *d_block, *d_pos; + unsigned int *s_pos, *s_end; + int s_start; + int i,j; + s_start = find_start(s_ptr); + if (s_start==-1) return NULL; + s_end = s_ptr + NUM; + s_pos = s_ptr + s_start; + d_block=malloc(EDID1_LEN); + if (!d_block) return NULL; + d_pos = d_block; + for (i=0;i<EDID1_LEN;i++) { + for (j=0;j<8;j++) { + *d_pos <<= 1; + if (*s_pos) { + *d_pos |= 0x01; + } + s_pos++; if (s_pos == s_end) s_pos=s_ptr; + }; + s_pos++; if (s_pos == s_end) s_pos=s_ptr; + d_pos++; + } + free(s_ptr); + if (d_block && DDC_checksum(d_block,EDID1_LEN)) return NULL; + return (resort(d_block)); +} + +/* fetch entire EDID record; DDC bit needs to be masked */ +static unsigned int * +FetchEDID_DDC1(register ScrnInfoPtr pScrn, + register unsigned int (*read_DDC)(ScrnInfoPtr)) +{ + int count = NUM; + unsigned int *ptr, *xp; + + ptr=xp=malloc(sizeof(int)*NUM); + + if (!ptr) return NULL; + do { + /* wait for next retrace */ + *xp = read_DDC(pScrn); + xp++; + } while(--count); + return (ptr); +} + +/* test if DDC1 return 0 if not */ +static Bool +TestDDC1(ScrnInfoPtr pScrn, unsigned int (*read_DDC)(ScrnInfoPtr)) +{ + int old, count; + + old = read_DDC(pScrn); + count = HEADER * BITS_PER_BYTE; + do { + /* wait for next retrace */ + if (old != read_DDC(pScrn)) break; + } while(count--); + return (count); +} + +/* + * read EDID record , pass it to callback function to interpret. + * callback function will store it for further use by calling + * function; it will also decide if we need to reread it + */ +static unsigned char * +EDIDRead_DDC1(ScrnInfoPtr pScrn, DDC1SetSpeedProc DDCSpeed, + unsigned int (*read_DDC)(ScrnInfoPtr)) +{ + unsigned char *EDID_block = NULL; + int count = RETRIES; + + if (!read_DDC) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "chipset doesn't support DDC1\n"); + return NULL; + }; + + if (TestDDC1(pScrn,read_DDC)==-1) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "No DDC signal\n"); + return NULL; + }; + + if (DDCSpeed) DDCSpeed(pScrn,DDC_FAST); + do { + EDID_block = GetEDID_DDC1(FetchEDID_DDC1(pScrn,read_DDC)); + count --; + } while (!EDID_block && count); + if (DDCSpeed) DDCSpeed(pScrn,DDC_SLOW); + + return EDID_block; +} + +/** + * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC1 are + * unset. EDID information blocks are interpreted and the results returned in + * an xf86MonPtr. + * + * This function does not affect the list of modes used by drivers -- it is up + * to the driver to decide policy on what to do with EDID information. + * + * @return pointer to a new xf86MonPtr containing the EDID information. + * @return NULL if no monitor attached or failure to interpret the EDID. + */ +xf86MonPtr +xf86DoEDID_DDC1( + int scrnIndex, DDC1SetSpeedProc DDC1SetSpeed, + unsigned int (*DDC1Read)(ScrnInfoPtr) +) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + unsigned char *EDID_block = NULL; + xf86MonPtr tmp = NULL; + int sigio; + /* Default DDC and DDC1 to enabled. */ + Bool noddc = FALSE, noddc1 = FALSE; + OptionInfoPtr options; + + options = xnfalloc(sizeof(DDCOptions)); + (void)memcpy(options, DDCOptions, sizeof(DDCOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); + + xf86GetOptValBool(options, DDCOPT_NODDC, &noddc); + xf86GetOptValBool(options, DDCOPT_NODDC1, &noddc1); + free(options); + + if (noddc || noddc1) + return NULL; + + sigio = xf86BlockSIGIO(); + EDID_block = EDIDRead_DDC1(pScrn,DDC1SetSpeed,DDC1Read); + xf86UnblockSIGIO(sigio); + + if (EDID_block){ + tmp = xf86InterpretEDID(scrnIndex,EDID_block); + } +#ifdef DEBUG + else ErrorF("No EDID block returned\n"); + if (!tmp) + ErrorF("Cannot interpret EDID block\n"); +#endif + return tmp; +} + +/* DDC2 */ + +static I2CDevPtr +DDC2MakeDevice(I2CBusPtr pBus, int address, char *name) +{ + I2CDevPtr dev = NULL; + + if (!(dev = xf86I2CFindDev(pBus, address))) { + dev = xf86CreateI2CDevRec(); + dev->DevName = name; + dev->SlaveAddr = address; + dev->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ + dev->StartTimeout = 550; + dev->BitTimeout = 40; + dev->AcknTimeout = 40; + + dev->pI2CBus = pBus; + if (!xf86I2CDevInit(dev)) { + xf86DrvMsg(pBus->scrnIndex, X_PROBED, "No DDC2 device\n"); + return NULL; + } + } + + return dev; +} + +static I2CDevPtr +DDC2Init(int scrnIndex, I2CBusPtr pBus) +{ + I2CDevPtr dev = NULL; + + /* + * Slow down the bus so that older monitors don't + * miss things. + */ + pBus->RiseFallTime = 20; + + dev = DDC2MakeDevice(pBus, 0x00A0, "ddc2"); + if (xf86I2CProbeAddress(pBus, 0x0060)) + DDC2MakeDevice(pBus, 0x0060, "E-EDID segment register"); + if (xf86I2CProbeAddress(pBus, 0x0062)) + DDC2MakeDevice(pBus, 0x0062, "EDID EEPROM interface"); + if (xf86I2CProbeAddress(pBus, 0x006E)) + DDC2MakeDevice(pBus, 0x006E, "DDC control interface"); + + return dev; +} + +/* Mmmm, smell the hacks */ +static void +EEDIDStop(I2CDevPtr d) +{ +} + +/* block is the EDID block number. a segment is two blocks. */ +static Bool +DDC2Read(I2CDevPtr dev, int block, unsigned char *R_Buffer) +{ + unsigned char W_Buffer[1]; + int i, segment; + I2CDevPtr seg; + void (*stop)(I2CDevPtr); + + for (i = 0; i < RETRIES; i++) { + /* Stop bits reset the segment pointer to 0, so be careful here. */ + segment = block >> 1; + if (segment) { + Bool b; + + if (!(seg = xf86I2CFindDev(dev->pI2CBus, 0x0060))) + return FALSE; + + W_Buffer[0] = segment; + + stop = dev->pI2CBus->I2CStop; + dev->pI2CBus->I2CStop = EEDIDStop; + + b = xf86I2CWriteRead(seg, W_Buffer, 1, NULL, 0); + + dev->pI2CBus->I2CStop = stop; + if (!b) { + dev->pI2CBus->I2CStop(dev); + continue; + } + } + + W_Buffer[0] = (block & 0x01) * EDID1_LEN; + + if (xf86I2CWriteRead(dev, W_Buffer, 1, R_Buffer, EDID1_LEN)) { + if (!DDC_checksum(R_Buffer, EDID1_LEN)) + return TRUE; + } + } + + return FALSE; +} + +/** + * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC2 are + * unset. EDID information blocks are interpreted and the results returned in + * an xf86MonPtr. Unlike xf86DoEDID_DDC[12](), this function will return + * the complete EDID data, including all extension blocks, if the 'complete' + * parameter is TRUE; + * + * This function does not affect the list of modes used by drivers -- it is up + * to the driver to decide policy on what to do with EDID information. + * + * @return pointer to a new xf86MonPtr containing the EDID information. + * @return NULL if no monitor attached or failure to interpret the EDID. + */ +xf86MonPtr +xf86DoEEDID(int scrnIndex, I2CBusPtr pBus, Bool complete) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + unsigned char *EDID_block = NULL; + xf86MonPtr tmp = NULL; + I2CDevPtr dev = NULL; + /* Default DDC and DDC2 to enabled. */ + Bool noddc = FALSE, noddc2 = FALSE; + OptionInfoPtr options; + + options = malloc(sizeof(DDCOptions)); + if (!options) + return NULL; + memcpy(options, DDCOptions, sizeof(DDCOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); + + xf86GetOptValBool(options, DDCOPT_NODDC, &noddc); + xf86GetOptValBool(options, DDCOPT_NODDC2, &noddc2); + free(options); + + if (noddc || noddc2) + return NULL; + + if (!(dev = DDC2Init(scrnIndex, pBus))) + return NULL; + + EDID_block = calloc(1, EDID1_LEN); + if (!EDID_block) + return NULL; + + if (DDC2Read(dev, 0, EDID_block)) { + int i, n = EDID_block[0x7e]; + + if (complete && n) { + EDID_block = realloc(EDID_block, EDID1_LEN * (1+n)); + + for (i = 0; i < n; i++) + DDC2Read(dev, i+1, EDID_block + (EDID1_LEN * (1+i))); + } + + tmp = xf86InterpretEEDID(scrnIndex, EDID_block); + } + + if (tmp && complete) + tmp->flags |= MONITOR_EDID_COMPLETE_RAWDATA; + + return tmp; +} + +/** + * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC2 are + * unset. EDID information blocks are interpreted and the results returned in + * an xf86MonPtr. + * + * This function does not affect the list of modes used by drivers -- it is up + * to the driver to decide policy on what to do with EDID information. + * + * @return pointer to a new xf86MonPtr containing the EDID information. + * @return NULL if no monitor attached or failure to interpret the EDID. + */ +xf86MonPtr +xf86DoEDID_DDC2(int scrnIndex, I2CBusPtr pBus) +{ + return xf86DoEEDID(scrnIndex, pBus, FALSE); +} + +/* XXX write me */ +static void * +DDC2ReadDisplayID(void) +{ + return FALSE; +} + +/** + * Attempts to probe the monitor for DisplayID information, if NoDDC and + * NoDDC2 are unset. DisplayID blocks are interpreted and the results + * returned in an xf86MonPtr. + * + * This function does not affect the list of modes used by drivers -- it is up + * to the driver to decide policy on what to do with DisplayID information. + * + * @return pointer to a new xf86MonPtr containing the DisplayID information. + * @return NULL if no monitor attached or failure to interpret the DisplayID. + */ +xf86MonPtr +xf86DoDisplayID(int scrnIndex, I2CBusPtr pBus) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + unsigned char *did = NULL; + xf86MonPtr tmp = NULL; + I2CDevPtr dev = NULL; + /* Default DDC and DDC2 to enabled. */ + Bool noddc = FALSE, noddc2 = FALSE; + OptionInfoPtr options; + + options = malloc(sizeof(DDCOptions)); + if (!options) + return NULL; + memcpy(options, DDCOptions, sizeof(DDCOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); + + xf86GetOptValBool(options, DDCOPT_NODDC, &noddc); + xf86GetOptValBool(options, DDCOPT_NODDC2, &noddc2); + free(options); + + if (noddc || noddc2) + return NULL; + + if (!(dev = DDC2Init(scrnIndex, pBus))) + return NULL; + + if ((did = DDC2ReadDisplayID())) { + tmp = calloc(1, sizeof(*tmp)); + if (!tmp) + return NULL; + + tmp->scrnIndex = scrnIndex; + tmp->flags |= MONITOR_DISPLAYID; + tmp->rawData = did; + } + + return tmp; +} diff --git a/xorg-server/hw/xfree86/ddc/ddcProperty.c b/xorg-server/hw/xfree86/ddc/ddcProperty.c index 329a63964..d4ae1006d 100644 --- a/xorg-server/hw/xfree86/ddc/ddcProperty.c +++ b/xorg-server/hw/xfree86/ddc/ddcProperty.c @@ -1,125 +1,125 @@ -/* - * Copyright 2006 Luc Verhaegen. - * - * 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, sub license, - * 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 NON-INFRINGEMENT. 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. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86DDC.h" -#include <X11/Xatom.h> -#include "property.h" -#include "propertyst.h" -#include "xf86DDC.h" -#include <string.h> - -#define EDID1_ATOM_NAME "XFree86_DDC_EDID1_RAWDATA" -#define EDID2_ATOM_NAME "XFree86_DDC_EDID2_RAWDATA" - -static void -edidMakeAtom(int i, const char *name, CARD8 *data, int size) -{ - Atom atom; - unsigned char *atom_data; - - if (!(atom_data = xalloc(size*sizeof(CARD8)))) - return; - - atom = MakeAtom(name, strlen(name), TRUE); - memcpy(atom_data, data, size); - xf86RegisterRootWindowProperty(i, atom, XA_INTEGER, 8, size, atom_data); -} - -static void -addRootWindowProperties(ScrnInfoPtr pScrn, xf86MonPtr DDC) -{ - int i, scrnIndex = pScrn->scrnIndex; - Bool makeEDID1prop = FALSE; - Bool makeEDID2prop = FALSE; - - if (DDC->flags & MONITOR_DISPLAYID) { - /* Don't bother, use RANDR already */ - return; - } else if (DDC->ver.version == 1) { - makeEDID1prop = TRUE; - } else if (DDC->ver.version == 2) { - int checksum1; - int checksum2; - makeEDID2prop = TRUE; - - /* Some monitors (eg Panasonic PanaSync4) - * report version==2 because they used EDID v2 spec document, - * although they use EDID v1 data structure :-( - * - * Try using checksum to determine when we have such a monitor. - */ - checksum2 = 0; - for (i = 0; i < 256; i++) - checksum2 += DDC->rawData[i]; - if (checksum2 % 256) { - xf86DrvMsg(scrnIndex, X_INFO, "Monitor EDID v2 checksum failed\n"); - xf86DrvMsg(scrnIndex, X_INFO, - "XFree86_DDC_EDID2_RAWDATA property may be bad\n"); - checksum1 = 0; - for (i = 0; i < 128; i++) - checksum1 += DDC->rawData[i]; - if (!(checksum1 % 256)) { - xf86DrvMsg(scrnIndex, X_INFO, - "Monitor EDID v1 checksum passed,\n"); - xf86DrvMsg(scrnIndex, X_INFO, - "XFree86_DDC_EDID1_RAWDATA property created\n"); - makeEDID1prop = TRUE; - } - } - } else { - xf86DrvMsg(scrnIndex, X_PROBED, "unexpected EDID version %d.%d\n", - DDC->ver.version, DDC->ver.revision); - return; - } - - if (makeEDID1prop) { - int size = 128 + - (DDC->flags & EDID_COMPLETE_RAWDATA ? DDC->no_sections * 128 : 0); - - edidMakeAtom(scrnIndex, EDID1_ATOM_NAME, DDC->rawData, size); - } - - if (makeEDID2prop) - edidMakeAtom(scrnIndex, EDID2_ATOM_NAME, DDC->rawData, 256); -} - -Bool -xf86SetDDCproperties(ScrnInfoPtr pScrn, xf86MonPtr DDC) -{ - if (!pScrn || !pScrn->monitor || !DDC) - return FALSE; - - if (DDC->flags & MONITOR_DISPLAYID) - ; - else - xf86EdidMonitorSet(pScrn->scrnIndex, pScrn->monitor, DDC); - - addRootWindowProperties(pScrn, DDC); - - return TRUE; -} +/* + * Copyright 2006 Luc Verhaegen. + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86DDC.h" +#include <X11/Xatom.h> +#include "property.h" +#include "propertyst.h" +#include "xf86DDC.h" +#include <string.h> + +#define EDID1_ATOM_NAME "XFree86_DDC_EDID1_RAWDATA" +#define EDID2_ATOM_NAME "XFree86_DDC_EDID2_RAWDATA" + +static void +edidMakeAtom(int i, const char *name, CARD8 *data, int size) +{ + Atom atom; + unsigned char *atom_data; + + if (!(atom_data = malloc(size*sizeof(CARD8)))) + return; + + atom = MakeAtom(name, strlen(name), TRUE); + memcpy(atom_data, data, size); + xf86RegisterRootWindowProperty(i, atom, XA_INTEGER, 8, size, atom_data); +} + +static void +addRootWindowProperties(ScrnInfoPtr pScrn, xf86MonPtr DDC) +{ + int i, scrnIndex = pScrn->scrnIndex; + Bool makeEDID1prop = FALSE; + Bool makeEDID2prop = FALSE; + + if (DDC->flags & MONITOR_DISPLAYID) { + /* Don't bother, use RANDR already */ + return; + } else if (DDC->ver.version == 1) { + makeEDID1prop = TRUE; + } else if (DDC->ver.version == 2) { + int checksum1; + int checksum2; + makeEDID2prop = TRUE; + + /* Some monitors (eg Panasonic PanaSync4) + * report version==2 because they used EDID v2 spec document, + * although they use EDID v1 data structure :-( + * + * Try using checksum to determine when we have such a monitor. + */ + checksum2 = 0; + for (i = 0; i < 256; i++) + checksum2 += DDC->rawData[i]; + if (checksum2 % 256) { + xf86DrvMsg(scrnIndex, X_INFO, "Monitor EDID v2 checksum failed\n"); + xf86DrvMsg(scrnIndex, X_INFO, + "XFree86_DDC_EDID2_RAWDATA property may be bad\n"); + checksum1 = 0; + for (i = 0; i < 128; i++) + checksum1 += DDC->rawData[i]; + if (!(checksum1 % 256)) { + xf86DrvMsg(scrnIndex, X_INFO, + "Monitor EDID v1 checksum passed,\n"); + xf86DrvMsg(scrnIndex, X_INFO, + "XFree86_DDC_EDID1_RAWDATA property created\n"); + makeEDID1prop = TRUE; + } + } + } else { + xf86DrvMsg(scrnIndex, X_PROBED, "unexpected EDID version %d.%d\n", + DDC->ver.version, DDC->ver.revision); + return; + } + + if (makeEDID1prop) { + int size = 128 + + (DDC->flags & EDID_COMPLETE_RAWDATA ? DDC->no_sections * 128 : 0); + + edidMakeAtom(scrnIndex, EDID1_ATOM_NAME, DDC->rawData, size); + } + + if (makeEDID2prop) + edidMakeAtom(scrnIndex, EDID2_ATOM_NAME, DDC->rawData, 256); +} + +Bool +xf86SetDDCproperties(ScrnInfoPtr pScrn, xf86MonPtr DDC) +{ + if (!pScrn || !pScrn->monitor || !DDC) + return FALSE; + + if (DDC->flags & MONITOR_DISPLAYID) + ; + else + xf86EdidMonitorSet(pScrn->scrnIndex, pScrn->monitor, DDC); + + addRootWindowProperties(pScrn, DDC); + + return TRUE; +} diff --git a/xorg-server/hw/xfree86/ddc/interpret_edid.c b/xorg-server/hw/xfree86/ddc/interpret_edid.c index f3e593aec..1a2d2f487 100644 --- a/xorg-server/hw/xfree86/ddc/interpret_edid.c +++ b/xorg-server/hw/xfree86/ddc/interpret_edid.c @@ -1,685 +1,685 @@ -/* - * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> - * Copyright 2007 Red Hat, Inc. - * - * 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. - * - * interpret_edid.c: interpret a primary EDID block - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" -#define _PARSE_EDID_ -#include "xf86DDC.h" -#include <string.h> - -static void get_vendor_section(Uchar*, struct vendor *); -static void get_version_section(Uchar*, struct edid_version *); -static void get_display_section(Uchar*, struct disp_features *, - struct edid_version *); -static void get_established_timing_section(Uchar*, struct established_timings *); -static void get_std_timing_section(Uchar*, struct std_timings *, - struct edid_version *); -static void fetch_detailed_block(Uchar *c, struct edid_version *ver, - struct detailed_monitor_section *det_mon); -static void get_dt_md_section(Uchar *, struct edid_version *, - struct detailed_monitor_section *det_mon); -static void copy_string(Uchar *, Uchar *); -static void get_dst_timing_section(Uchar *, struct std_timings *, - struct edid_version *); -static void get_monitor_ranges(Uchar *, struct monitor_ranges *); -static void get_whitepoint_section(Uchar *, struct whitePoints *); -static void get_detailed_timing_section(Uchar*, struct detailed_timings *); -static Bool validate_version(int scrnIndex, struct edid_version *); - -static void -find_ranges_section(struct detailed_monitor_section *det, void *ranges) -{ - if (det->type == DS_RANGES && det->section.ranges.max_clock) - *(struct monitor_ranges **)ranges = &det->section.ranges; -} - -static void -find_max_detailed_clock(struct detailed_monitor_section *det, void *ret) -{ - if (det->type == DT) { - *(int *)ret = max(*((int *)ret), - det->section.d_timings.clock); - } -} - -static void -handle_edid_quirks(xf86MonPtr m) -{ - struct monitor_ranges *ranges = NULL; - - /* - * max_clock is only encoded in EDID in tens of MHz, so occasionally we - * find a monitor claiming a max of 160 with a mode requiring 162, or - * similar. Strictly we should refuse to round up too far, but let's - * see how well this works. - */ - - /* Try to find Monitor Range and max clock, then re-set range value*/ - xf86ForEachDetailedBlock(m, find_ranges_section, &ranges); - if (ranges && ranges->max_clock) { - int clock = 0; - xf86ForEachDetailedBlock(m, find_max_detailed_clock, &clock); - if (clock && (ranges->max_clock * 1e6 < clock)) { - xf86Msg(X_WARNING, "EDID timing clock %.2f exceeds claimed max " - "%dMHz, fixing\n", clock / 1.0e6, ranges->max_clock); - ranges->max_clock = (clock+999999)/1e6; - } - } -} - -struct det_hv_parameter { - int real_hsize; - int real_vsize; - float target_aspect; -}; - -static void handle_detailed_hvsize(struct detailed_monitor_section *det_mon, - void *data) -{ - struct det_hv_parameter *p = (struct det_hv_parameter *)data; - float timing_aspect; - - if (det_mon->type == DT) { - struct detailed_timings *timing; - timing = &det_mon->section.d_timings; - - if (!timing->v_size) - return; - - timing_aspect = (float)timing->h_size / timing->v_size; - if (fabs(1 - (timing_aspect / p->target_aspect)) < 0.05) { - p->real_hsize = max(p->real_hsize, timing->h_size); - p->real_vsize = max(p->real_vsize, timing->v_size); - } - } -} - -static void encode_aspect_ratio(xf86MonPtr m) -{ - /* - * some monitors encode the aspect ratio instead of the physical size. - * try to find the largest detailed timing that matches that aspect - * ratio and use that to fill in the feature section. - */ - if ((m->features.hsize == 16 && m->features.vsize == 9) || - (m->features.hsize == 16 && m->features.vsize == 10) || - (m->features.hsize == 4 && m->features.vsize == 3) || - (m->features.hsize == 5 && m->features.vsize == 4)) { - - struct det_hv_parameter p; - p.real_hsize = 0; - p.real_vsize = 0; - p.target_aspect = (float)m->features.hsize /m->features.vsize; - - xf86ForEachDetailedBlock(m, handle_detailed_hvsize, &p); - - if (!p.real_hsize || !p.real_vsize) { - m->features.hsize = m->features.vsize = 0; - } else if ((m->features.hsize * 10 == p.real_hsize) && - (m->features.vsize * 10 == p.real_vsize)) { - /* exact match is just unlikely, should do a better check though */ - m->features.hsize = m->features.vsize = 0; - } else { - /* convert mm to cm */ - m->features.hsize = (p.real_hsize + 5) / 10; - m->features.vsize = (p.real_vsize + 5) / 10; - } - - xf86Msg(X_INFO, "Quirked EDID physical size to %dx%d cm\n", - m->features.hsize, m->features.vsize); - } -} - -xf86MonPtr -xf86InterpretEDID(int scrnIndex, Uchar *block) -{ - xf86MonPtr m; - - if (!block) return NULL; - if (! (m = xnfcalloc(sizeof(xf86Monitor),1))) return NULL; - m->scrnIndex = scrnIndex; - m->rawData = block; - - get_vendor_section(SECTION(VENDOR_SECTION,block),&m->vendor); - get_version_section(SECTION(VERSION_SECTION,block),&m->ver); - if (!validate_version(scrnIndex, &m->ver)) goto error; - get_display_section(SECTION(DISPLAY_SECTION,block),&m->features, - &m->ver); - get_established_timing_section(SECTION(ESTABLISHED_TIMING_SECTION,block), - &m->timings1); - get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2, - &m->ver); - get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon); - m->no_sections = (int)*(char *)SECTION(NO_EDID,block); - - handle_edid_quirks(m); - encode_aspect_ratio(m); - - return (m); - - error: - xfree(m); - return NULL; -} - -static int get_cea_detail_timing(Uchar *blk, xf86MonPtr mon, - struct detailed_monitor_section *det_mon) -{ - int dt_num; - int dt_offset = ((struct cea_ext_body *)blk)->dt_offset; - - dt_num = 0; - - if (dt_offset < CEA_EXT_MIN_DATA_OFFSET) - return dt_num; - - for (; dt_offset < (CEA_EXT_MAX_DATA_OFFSET - DET_TIMING_INFO_LEN) && - dt_num < CEA_EXT_DET_TIMING_NUM; - _NEXT_DT_MD_SECTION(dt_offset)) { - - fetch_detailed_block(blk + dt_offset, &mon->ver, det_mon + dt_num); - dt_num = dt_num + 1 ; - } - - return dt_num; -} - -static void handle_cea_detail_block(Uchar *ext, xf86MonPtr mon, - handle_detailed_fn fn, - void *data) -{ - int i; - struct detailed_monitor_section det_mon[CEA_EXT_DET_TIMING_NUM]; - int det_mon_num; - - det_mon_num = get_cea_detail_timing(ext, mon, det_mon); - - for (i = 0; i < det_mon_num; i++) - fn(det_mon + i, data); -} - -void xf86ForEachDetailedBlock(xf86MonPtr mon, - handle_detailed_fn fn, - void *data) -{ - int i; - Uchar *ext; - - if (mon == NULL) - return; - - for (i = 0; i < DET_TIMINGS; i++) - fn(mon->det_mon + i, data); - - for (i = 0; i < mon->no_sections; i++) { - ext = mon->rawData + EDID1_LEN * (i + 1); - switch (ext[EXT_TAG]){ - case CEA_EXT: - handle_cea_detail_block(ext, mon, fn, data); - break; - case VTB_EXT: - case DI_EXT: - case LS_EXT: - case MI_EXT: - break; - } - } -} - -static struct cea_data_block * -extract_cea_data_block(Uchar *ext, int data_type) -{ - struct cea_ext_body *cea; - struct cea_data_block *data_collection; - struct cea_data_block *data_end; - - cea = (struct cea_ext_body *)ext; - - if (cea->dt_offset <= CEA_EXT_MIN_DATA_OFFSET) - return NULL; - - data_collection = &cea->data_collection; - data_end = (struct cea_data_block *)(cea->dt_offset + ext); - - for ( ;data_collection < data_end;) { - - if (data_type == data_collection->tag) { - return data_collection; - } - data_collection = (void *)((unsigned char *)data_collection + - data_collection->len + 1); - } - - return NULL; -} - -static void handle_cea_video_block(Uchar *ext, handle_video_fn fn, void *data) -{ - struct cea_video_block *video; - struct cea_video_block *video_end; - struct cea_data_block *data_collection; - - data_collection = extract_cea_data_block(ext, CEA_VIDEO_BLK); - if (data_collection == NULL) - return; - - video = &data_collection->u.video; - video_end = (struct cea_video_block *) - ((Uchar *)video + data_collection->len); - - for (; video < video_end; video = video + 1) { - fn(video, data); - } -} - -void xf86ForEachVideoBlock(xf86MonPtr mon, - handle_video_fn fn, - void *data) -{ - int i; - Uchar *ext; - - if (mon == NULL) - return; - - for (i = 0; i < mon->no_sections; i++) { - ext = mon->rawData + EDID1_LEN * (i + 1); - switch (ext[EXT_TAG]) { - case CEA_EXT: - handle_cea_video_block(ext, fn, data); - break; - case VTB_EXT: - case DI_EXT: - case LS_EXT: - case MI_EXT: - break; - } - } -} - -xf86MonPtr -xf86InterpretEEDID(int scrnIndex, Uchar *block) -{ - xf86MonPtr m; - - m = xf86InterpretEDID(scrnIndex, block); - if (!m) - return NULL; - - /* extension parse */ - - return m; -} - -static void -get_vendor_section(Uchar *c, struct vendor *r) -{ - r->name[0] = L1; - r->name[1] = L2; - r->name[2] = L3; - r->name[3] = '\0'; - - r->prod_id = PROD_ID; - r->serial = SERIAL_NO; - r->week = WEEK; - r->year = YEAR; -} - -static void -get_version_section(Uchar *c, struct edid_version *r) -{ - r->version = VERSION; - r->revision = REVISION; -} - -static void -get_display_section(Uchar *c, struct disp_features *r, - struct edid_version *v) -{ - r->input_type = INPUT_TYPE; - if (!DIGITAL(r->input_type)) { - r->input_voltage = INPUT_VOLTAGE; - r->input_setup = SETUP; - r->input_sync = SYNC; - } else if (v->revision == 2 || v->revision == 3) { - r->input_dfp = DFP; - } else if (v->revision >= 4) { - r->input_bpc = BPC; - r->input_interface = DIGITAL_INTERFACE; - } - r->hsize = HSIZE_MAX; - r->vsize = VSIZE_MAX; - r->gamma = GAMMA; - r->dpms = DPMS; - r->display_type = DISPLAY_TYPE; - r->msc = MSC; - r->redx = REDX; - r->redy = REDY; - r->greenx = GREENX; - r->greeny = GREENY; - r->bluex = BLUEX; - r->bluey = BLUEY; - r->whitex = WHITEX; - r->whitey = WHITEY; -} - -static void -get_established_timing_section(Uchar *c, struct established_timings *r) -{ - r->t1 = T1; - r->t2 = T2; - r->t_manu = T_MANU; -} - -static void -get_cvt_timing_section(Uchar *c, struct cvt_timings *r) -{ - int i; - - for (i = 0; i < 4; i++) { - if (c[0] && c[1] && c[2]) { - r[i].height = (c[0] + ((c[1] & 0xF0) << 8) + 1) * 2; - switch (c[1] & 0xc0) { - case 0x00: r[i].width = r[i].height * 4 / 3; break; - case 0x40: r[i].width = r[i].height * 16 / 9; break; - case 0x80: r[i].width = r[i].height * 16 / 10; break; - case 0xc0: r[i].width = r[i].height * 15 / 9; break; - } - switch (c[2] & 0x60) { - case 0x00: r[i].rate = 50; break; - case 0x20: r[i].rate = 60; break; - case 0x40: r[i].rate = 75; break; - case 0x60: r[i].rate = 85; break; - } - r[i].rates = c[2] & 0x1f; - } else { - return; - } - c += 3; - } -} - -static void -get_std_timing_section(Uchar *c, struct std_timings *r, - struct edid_version *v) -{ - int i; - - for (i=0;i<STD_TIMINGS;i++){ - if (VALID_TIMING) { - r[i].hsize = HSIZE1; - VSIZE1(r[i].vsize); - r[i].refresh = REFRESH_R; - r[i].id = STD_TIMING_ID; - } else { - r[i].hsize = r[i].vsize = r[i].refresh = r[i].id = 0; - } - NEXT_STD_TIMING; - } -} - -static const unsigned char empty_block[18]; - -static void -fetch_detailed_block(Uchar *c, struct edid_version *ver, - struct detailed_monitor_section *det_mon) -{ - if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) { - switch (MONITOR_DESC_TYPE) { - case SERIAL_NUMBER: - det_mon->type = DS_SERIAL; - copy_string(c,det_mon->section.serial); - break; - case ASCII_STR: - det_mon->type = DS_ASCII_STR; - copy_string(c,det_mon->section.ascii_data); - break; - case MONITOR_RANGES: - det_mon->type = DS_RANGES; - get_monitor_ranges(c,&det_mon->section.ranges); - break; - case MONITOR_NAME: - det_mon->type = DS_NAME; - copy_string(c,det_mon->section.name); - break; - case ADD_COLOR_POINT: - det_mon->type = DS_WHITE_P; - get_whitepoint_section(c,det_mon->section.wp); - break; - case ADD_STD_TIMINGS: - det_mon->type = DS_STD_TIMINGS; - get_dst_timing_section(c,det_mon->section.std_t, ver); - break; - case COLOR_MANAGEMENT_DATA: - det_mon->type = DS_CMD; - break; - case CVT_3BYTE_DATA: - det_mon->type = DS_CVT; - get_cvt_timing_section(c, det_mon->section.cvt); - break; - case ADD_EST_TIMINGS: - det_mon->type = DS_EST_III; - memcpy(det_mon->section.est_iii, c + 6, 6); - break; - case ADD_DUMMY: - det_mon->type = DS_DUMMY; - break; - default: - det_mon->type = DS_UNKOWN; - break; - } - if (c[3] <= 0x0F && memcmp(c, empty_block, sizeof(empty_block))) { - det_mon->type = DS_VENDOR + c[3]; - } - } else { - det_mon->type = DT; - get_detailed_timing_section(c, &det_mon->section.d_timings); - } -} - -static void -get_dt_md_section(Uchar *c, struct edid_version *ver, - struct detailed_monitor_section *det_mon) -{ - int i; - - for (i=0; i < DET_TIMINGS; i++) { - fetch_detailed_block(c, ver, det_mon + i); - NEXT_DT_MD_SECTION; - } -} - -static void -copy_string(Uchar *c, Uchar *s) -{ - int i; - c = c + 5; - for (i = 0; (i < 13 && *c != 0x0A); i++) - *(s++) = *(c++); - *s = 0; - while (i-- && (*--s == 0x20)) *s = 0; -} - -static void -get_dst_timing_section(Uchar *c, struct std_timings *t, - struct edid_version *v) -{ - int j; - c = c + 5; - for (j = 0; j < 5; j++) { - t[j].hsize = HSIZE1; - VSIZE1(t[j].vsize); - t[j].refresh = REFRESH_R; - t[j].id = STD_TIMING_ID; - NEXT_STD_TIMING; - } -} - -static void -get_monitor_ranges(Uchar *c, struct monitor_ranges *r) -{ - r->min_v = MIN_V; - r->max_v = MAX_V; - r->min_h = MIN_H; - r->max_h = MAX_H; - r->max_clock = 0; - if(MAX_CLOCK != 0xff) /* is specified? */ - r->max_clock = MAX_CLOCK * 10; - if (HAVE_2ND_GTF) { - r->gtf_2nd_f = F_2ND_GTF; - r->gtf_2nd_c = C_2ND_GTF; - r->gtf_2nd_m = M_2ND_GTF; - r->gtf_2nd_k = K_2ND_GTF; - r->gtf_2nd_j = J_2ND_GTF; - } else { - r->gtf_2nd_f = 0; - } - if (HAVE_CVT) { - r->max_clock_khz = MAX_CLOCK_KHZ; - r->max_clock = r->max_clock_khz / 1000; - r->maxwidth = MAXWIDTH; - r->supported_aspect = SUPPORTED_ASPECT; - r->preferred_aspect = PREFERRED_ASPECT; - r->supported_blanking = SUPPORTED_BLANKING; - r->supported_scaling = SUPPORTED_SCALING; - r->preferred_refresh = PREFERRED_REFRESH; - } else { - r->max_clock_khz = 0; - } -} - -static void -get_whitepoint_section(Uchar *c, struct whitePoints *wp) -{ - wp[0].white_x = WHITEX1; - wp[0].white_y = WHITEY1; - wp[1].white_x = WHITEX2; - wp[1].white_y = WHITEY2; - wp[0].index = WHITE_INDEX1; - wp[1].index = WHITE_INDEX2; - wp[0].white_gamma = WHITE_GAMMA1; - wp[1].white_gamma = WHITE_GAMMA2; -} - -static void -get_detailed_timing_section(Uchar *c, struct detailed_timings *r) -{ - r->clock = PIXEL_CLOCK; - r->h_active = H_ACTIVE; - r->h_blanking = H_BLANK; - r->v_active = V_ACTIVE; - r->v_blanking = V_BLANK; - r->h_sync_off = H_SYNC_OFF; - r->h_sync_width = H_SYNC_WIDTH; - r->v_sync_off = V_SYNC_OFF; - r->v_sync_width = V_SYNC_WIDTH; - r->h_size = H_SIZE; - r->v_size = V_SIZE; - r->h_border = H_BORDER; - r->v_border = V_BORDER; - r->interlaced = INTERLACED; - r->stereo = STEREO; - r->stereo_1 = STEREO1; - r->sync = SYNC_T; - r->misc = MISC; -} - -#define MAX_EDID_MINOR 4 - -static Bool -validate_version(int scrnIndex, struct edid_version *r) -{ - if (r->version != 1) { - xf86DrvMsg(scrnIndex, X_ERROR, "Unknown EDID version %d\n", - r->version); - return FALSE; - } - - if (r->revision > MAX_EDID_MINOR) - xf86DrvMsg(scrnIndex, X_WARNING, - "Assuming version 1.%d is compatible with 1.%d\n", - r->revision, MAX_EDID_MINOR); - - return TRUE; -} - -/* - * Returns true if HDMI, false if definitely not or unknown. - */ -Bool -xf86MonitorIsHDMI(xf86MonPtr mon) -{ - int i = 0, version, offset; - char *edid = NULL; - - if (!mon) - return FALSE; - - if (!(mon->flags & EDID_COMPLETE_RAWDATA)) - return FALSE; - - if (!mon->no_sections) - return FALSE; - - edid = (char *)mon->rawData; - if (!edid) - return FALSE; - - /* find the CEA extension block */ - for (i = 1; i <= mon->no_sections; i++) - if (edid[i * 128] == 0x02) - break; - if (i == mon->no_sections + 1) - return FALSE; - edid += (i * 128); - - version = edid[1]; - offset = edid[2]; - if (version < 3 || offset < 4) - return FALSE; - - /* walk the cea data blocks */ - for (i = 4; i < offset; i += (edid[i] & 0x1f) + 1) { - char *x = edid + i; - - /* find a vendor specific block */ - if ((x[0] & 0xe0) >> 5 == 0x03) { - int oui = (x[3] << 16) + (x[2] << 8) + x[1]; - - /* find the HDMI vendor OUI */ - if (oui == 0x000c03) - return TRUE; - } - } - - /* guess it's not HDMI after all */ - return FALSE; -} +/* + * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> + * Copyright 2007 Red Hat, Inc. + * + * 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. + * + * interpret_edid.c: interpret a primary EDID block + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#define _PARSE_EDID_ +#include "xf86DDC.h" +#include <string.h> + +static void get_vendor_section(Uchar*, struct vendor *); +static void get_version_section(Uchar*, struct edid_version *); +static void get_display_section(Uchar*, struct disp_features *, + struct edid_version *); +static void get_established_timing_section(Uchar*, struct established_timings *); +static void get_std_timing_section(Uchar*, struct std_timings *, + struct edid_version *); +static void fetch_detailed_block(Uchar *c, struct edid_version *ver, + struct detailed_monitor_section *det_mon); +static void get_dt_md_section(Uchar *, struct edid_version *, + struct detailed_monitor_section *det_mon); +static void copy_string(Uchar *, Uchar *); +static void get_dst_timing_section(Uchar *, struct std_timings *, + struct edid_version *); +static void get_monitor_ranges(Uchar *, struct monitor_ranges *); +static void get_whitepoint_section(Uchar *, struct whitePoints *); +static void get_detailed_timing_section(Uchar*, struct detailed_timings *); +static Bool validate_version(int scrnIndex, struct edid_version *); + +static void +find_ranges_section(struct detailed_monitor_section *det, void *ranges) +{ + if (det->type == DS_RANGES && det->section.ranges.max_clock) + *(struct monitor_ranges **)ranges = &det->section.ranges; +} + +static void +find_max_detailed_clock(struct detailed_monitor_section *det, void *ret) +{ + if (det->type == DT) { + *(int *)ret = max(*((int *)ret), + det->section.d_timings.clock); + } +} + +static void +handle_edid_quirks(xf86MonPtr m) +{ + struct monitor_ranges *ranges = NULL; + + /* + * max_clock is only encoded in EDID in tens of MHz, so occasionally we + * find a monitor claiming a max of 160 with a mode requiring 162, or + * similar. Strictly we should refuse to round up too far, but let's + * see how well this works. + */ + + /* Try to find Monitor Range and max clock, then re-set range value*/ + xf86ForEachDetailedBlock(m, find_ranges_section, &ranges); + if (ranges && ranges->max_clock) { + int clock = 0; + xf86ForEachDetailedBlock(m, find_max_detailed_clock, &clock); + if (clock && (ranges->max_clock * 1e6 < clock)) { + xf86Msg(X_WARNING, "EDID timing clock %.2f exceeds claimed max " + "%dMHz, fixing\n", clock / 1.0e6, ranges->max_clock); + ranges->max_clock = (clock+999999)/1e6; + } + } +} + +struct det_hv_parameter { + int real_hsize; + int real_vsize; + float target_aspect; +}; + +static void handle_detailed_hvsize(struct detailed_monitor_section *det_mon, + void *data) +{ + struct det_hv_parameter *p = (struct det_hv_parameter *)data; + float timing_aspect; + + if (det_mon->type == DT) { + struct detailed_timings *timing; + timing = &det_mon->section.d_timings; + + if (!timing->v_size) + return; + + timing_aspect = (float)timing->h_size / timing->v_size; + if (fabs(1 - (timing_aspect / p->target_aspect)) < 0.05) { + p->real_hsize = max(p->real_hsize, timing->h_size); + p->real_vsize = max(p->real_vsize, timing->v_size); + } + } +} + +static void encode_aspect_ratio(xf86MonPtr m) +{ + /* + * some monitors encode the aspect ratio instead of the physical size. + * try to find the largest detailed timing that matches that aspect + * ratio and use that to fill in the feature section. + */ + if ((m->features.hsize == 16 && m->features.vsize == 9) || + (m->features.hsize == 16 && m->features.vsize == 10) || + (m->features.hsize == 4 && m->features.vsize == 3) || + (m->features.hsize == 5 && m->features.vsize == 4)) { + + struct det_hv_parameter p; + p.real_hsize = 0; + p.real_vsize = 0; + p.target_aspect = (float)m->features.hsize /m->features.vsize; + + xf86ForEachDetailedBlock(m, handle_detailed_hvsize, &p); + + if (!p.real_hsize || !p.real_vsize) { + m->features.hsize = m->features.vsize = 0; + } else if ((m->features.hsize * 10 == p.real_hsize) && + (m->features.vsize * 10 == p.real_vsize)) { + /* exact match is just unlikely, should do a better check though */ + m->features.hsize = m->features.vsize = 0; + } else { + /* convert mm to cm */ + m->features.hsize = (p.real_hsize + 5) / 10; + m->features.vsize = (p.real_vsize + 5) / 10; + } + + xf86Msg(X_INFO, "Quirked EDID physical size to %dx%d cm\n", + m->features.hsize, m->features.vsize); + } +} + +xf86MonPtr +xf86InterpretEDID(int scrnIndex, Uchar *block) +{ + xf86MonPtr m; + + if (!block) return NULL; + if (! (m = xnfcalloc(sizeof(xf86Monitor),1))) return NULL; + m->scrnIndex = scrnIndex; + m->rawData = block; + + get_vendor_section(SECTION(VENDOR_SECTION,block),&m->vendor); + get_version_section(SECTION(VERSION_SECTION,block),&m->ver); + if (!validate_version(scrnIndex, &m->ver)) goto error; + get_display_section(SECTION(DISPLAY_SECTION,block),&m->features, + &m->ver); + get_established_timing_section(SECTION(ESTABLISHED_TIMING_SECTION,block), + &m->timings1); + get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2, + &m->ver); + get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon); + m->no_sections = (int)*(char *)SECTION(NO_EDID,block); + + handle_edid_quirks(m); + encode_aspect_ratio(m); + + return (m); + + error: + free(m); + return NULL; +} + +static int get_cea_detail_timing(Uchar *blk, xf86MonPtr mon, + struct detailed_monitor_section *det_mon) +{ + int dt_num; + int dt_offset = ((struct cea_ext_body *)blk)->dt_offset; + + dt_num = 0; + + if (dt_offset < CEA_EXT_MIN_DATA_OFFSET) + return dt_num; + + for (; dt_offset < (CEA_EXT_MAX_DATA_OFFSET - DET_TIMING_INFO_LEN) && + dt_num < CEA_EXT_DET_TIMING_NUM; + _NEXT_DT_MD_SECTION(dt_offset)) { + + fetch_detailed_block(blk + dt_offset, &mon->ver, det_mon + dt_num); + dt_num = dt_num + 1 ; + } + + return dt_num; +} + +static void handle_cea_detail_block(Uchar *ext, xf86MonPtr mon, + handle_detailed_fn fn, + void *data) +{ + int i; + struct detailed_monitor_section det_mon[CEA_EXT_DET_TIMING_NUM]; + int det_mon_num; + + det_mon_num = get_cea_detail_timing(ext, mon, det_mon); + + for (i = 0; i < det_mon_num; i++) + fn(det_mon + i, data); +} + +void xf86ForEachDetailedBlock(xf86MonPtr mon, + handle_detailed_fn fn, + void *data) +{ + int i; + Uchar *ext; + + if (mon == NULL) + return; + + for (i = 0; i < DET_TIMINGS; i++) + fn(mon->det_mon + i, data); + + for (i = 0; i < mon->no_sections; i++) { + ext = mon->rawData + EDID1_LEN * (i + 1); + switch (ext[EXT_TAG]){ + case CEA_EXT: + handle_cea_detail_block(ext, mon, fn, data); + break; + case VTB_EXT: + case DI_EXT: + case LS_EXT: + case MI_EXT: + break; + } + } +} + +static struct cea_data_block * +extract_cea_data_block(Uchar *ext, int data_type) +{ + struct cea_ext_body *cea; + struct cea_data_block *data_collection; + struct cea_data_block *data_end; + + cea = (struct cea_ext_body *)ext; + + if (cea->dt_offset <= CEA_EXT_MIN_DATA_OFFSET) + return NULL; + + data_collection = &cea->data_collection; + data_end = (struct cea_data_block *)(cea->dt_offset + ext); + + for ( ;data_collection < data_end;) { + + if (data_type == data_collection->tag) { + return data_collection; + } + data_collection = (void *)((unsigned char *)data_collection + + data_collection->len + 1); + } + + return NULL; +} + +static void handle_cea_video_block(Uchar *ext, handle_video_fn fn, void *data) +{ + struct cea_video_block *video; + struct cea_video_block *video_end; + struct cea_data_block *data_collection; + + data_collection = extract_cea_data_block(ext, CEA_VIDEO_BLK); + if (data_collection == NULL) + return; + + video = &data_collection->u.video; + video_end = (struct cea_video_block *) + ((Uchar *)video + data_collection->len); + + for (; video < video_end; video = video + 1) { + fn(video, data); + } +} + +void xf86ForEachVideoBlock(xf86MonPtr mon, + handle_video_fn fn, + void *data) +{ + int i; + Uchar *ext; + + if (mon == NULL) + return; + + for (i = 0; i < mon->no_sections; i++) { + ext = mon->rawData + EDID1_LEN * (i + 1); + switch (ext[EXT_TAG]) { + case CEA_EXT: + handle_cea_video_block(ext, fn, data); + break; + case VTB_EXT: + case DI_EXT: + case LS_EXT: + case MI_EXT: + break; + } + } +} + +xf86MonPtr +xf86InterpretEEDID(int scrnIndex, Uchar *block) +{ + xf86MonPtr m; + + m = xf86InterpretEDID(scrnIndex, block); + if (!m) + return NULL; + + /* extension parse */ + + return m; +} + +static void +get_vendor_section(Uchar *c, struct vendor *r) +{ + r->name[0] = L1; + r->name[1] = L2; + r->name[2] = L3; + r->name[3] = '\0'; + + r->prod_id = PROD_ID; + r->serial = SERIAL_NO; + r->week = WEEK; + r->year = YEAR; +} + +static void +get_version_section(Uchar *c, struct edid_version *r) +{ + r->version = VERSION; + r->revision = REVISION; +} + +static void +get_display_section(Uchar *c, struct disp_features *r, + struct edid_version *v) +{ + r->input_type = INPUT_TYPE; + if (!DIGITAL(r->input_type)) { + r->input_voltage = INPUT_VOLTAGE; + r->input_setup = SETUP; + r->input_sync = SYNC; + } else if (v->revision == 2 || v->revision == 3) { + r->input_dfp = DFP; + } else if (v->revision >= 4) { + r->input_bpc = BPC; + r->input_interface = DIGITAL_INTERFACE; + } + r->hsize = HSIZE_MAX; + r->vsize = VSIZE_MAX; + r->gamma = GAMMA; + r->dpms = DPMS; + r->display_type = DISPLAY_TYPE; + r->msc = MSC; + r->redx = REDX; + r->redy = REDY; + r->greenx = GREENX; + r->greeny = GREENY; + r->bluex = BLUEX; + r->bluey = BLUEY; + r->whitex = WHITEX; + r->whitey = WHITEY; +} + +static void +get_established_timing_section(Uchar *c, struct established_timings *r) +{ + r->t1 = T1; + r->t2 = T2; + r->t_manu = T_MANU; +} + +static void +get_cvt_timing_section(Uchar *c, struct cvt_timings *r) +{ + int i; + + for (i = 0; i < 4; i++) { + if (c[0] && c[1] && c[2]) { + r[i].height = (c[0] + ((c[1] & 0xF0) << 8) + 1) * 2; + switch (c[1] & 0xc0) { + case 0x00: r[i].width = r[i].height * 4 / 3; break; + case 0x40: r[i].width = r[i].height * 16 / 9; break; + case 0x80: r[i].width = r[i].height * 16 / 10; break; + case 0xc0: r[i].width = r[i].height * 15 / 9; break; + } + switch (c[2] & 0x60) { + case 0x00: r[i].rate = 50; break; + case 0x20: r[i].rate = 60; break; + case 0x40: r[i].rate = 75; break; + case 0x60: r[i].rate = 85; break; + } + r[i].rates = c[2] & 0x1f; + } else { + return; + } + c += 3; + } +} + +static void +get_std_timing_section(Uchar *c, struct std_timings *r, + struct edid_version *v) +{ + int i; + + for (i=0;i<STD_TIMINGS;i++){ + if (VALID_TIMING) { + r[i].hsize = HSIZE1; + VSIZE1(r[i].vsize); + r[i].refresh = REFRESH_R; + r[i].id = STD_TIMING_ID; + } else { + r[i].hsize = r[i].vsize = r[i].refresh = r[i].id = 0; + } + NEXT_STD_TIMING; + } +} + +static const unsigned char empty_block[18]; + +static void +fetch_detailed_block(Uchar *c, struct edid_version *ver, + struct detailed_monitor_section *det_mon) +{ + if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) { + switch (MONITOR_DESC_TYPE) { + case SERIAL_NUMBER: + det_mon->type = DS_SERIAL; + copy_string(c,det_mon->section.serial); + break; + case ASCII_STR: + det_mon->type = DS_ASCII_STR; + copy_string(c,det_mon->section.ascii_data); + break; + case MONITOR_RANGES: + det_mon->type = DS_RANGES; + get_monitor_ranges(c,&det_mon->section.ranges); + break; + case MONITOR_NAME: + det_mon->type = DS_NAME; + copy_string(c,det_mon->section.name); + break; + case ADD_COLOR_POINT: + det_mon->type = DS_WHITE_P; + get_whitepoint_section(c,det_mon->section.wp); + break; + case ADD_STD_TIMINGS: + det_mon->type = DS_STD_TIMINGS; + get_dst_timing_section(c,det_mon->section.std_t, ver); + break; + case COLOR_MANAGEMENT_DATA: + det_mon->type = DS_CMD; + break; + case CVT_3BYTE_DATA: + det_mon->type = DS_CVT; + get_cvt_timing_section(c, det_mon->section.cvt); + break; + case ADD_EST_TIMINGS: + det_mon->type = DS_EST_III; + memcpy(det_mon->section.est_iii, c + 6, 6); + break; + case ADD_DUMMY: + det_mon->type = DS_DUMMY; + break; + default: + det_mon->type = DS_UNKOWN; + break; + } + if (c[3] <= 0x0F && memcmp(c, empty_block, sizeof(empty_block))) { + det_mon->type = DS_VENDOR + c[3]; + } + } else { + det_mon->type = DT; + get_detailed_timing_section(c, &det_mon->section.d_timings); + } +} + +static void +get_dt_md_section(Uchar *c, struct edid_version *ver, + struct detailed_monitor_section *det_mon) +{ + int i; + + for (i=0; i < DET_TIMINGS; i++) { + fetch_detailed_block(c, ver, det_mon + i); + NEXT_DT_MD_SECTION; + } +} + +static void +copy_string(Uchar *c, Uchar *s) +{ + int i; + c = c + 5; + for (i = 0; (i < 13 && *c != 0x0A); i++) + *(s++) = *(c++); + *s = 0; + while (i-- && (*--s == 0x20)) *s = 0; +} + +static void +get_dst_timing_section(Uchar *c, struct std_timings *t, + struct edid_version *v) +{ + int j; + c = c + 5; + for (j = 0; j < 5; j++) { + t[j].hsize = HSIZE1; + VSIZE1(t[j].vsize); + t[j].refresh = REFRESH_R; + t[j].id = STD_TIMING_ID; + NEXT_STD_TIMING; + } +} + +static void +get_monitor_ranges(Uchar *c, struct monitor_ranges *r) +{ + r->min_v = MIN_V; + r->max_v = MAX_V; + r->min_h = MIN_H; + r->max_h = MAX_H; + r->max_clock = 0; + if(MAX_CLOCK != 0xff) /* is specified? */ + r->max_clock = MAX_CLOCK * 10; + if (HAVE_2ND_GTF) { + r->gtf_2nd_f = F_2ND_GTF; + r->gtf_2nd_c = C_2ND_GTF; + r->gtf_2nd_m = M_2ND_GTF; + r->gtf_2nd_k = K_2ND_GTF; + r->gtf_2nd_j = J_2ND_GTF; + } else { + r->gtf_2nd_f = 0; + } + if (HAVE_CVT) { + r->max_clock_khz = MAX_CLOCK_KHZ; + r->max_clock = r->max_clock_khz / 1000; + r->maxwidth = MAXWIDTH; + r->supported_aspect = SUPPORTED_ASPECT; + r->preferred_aspect = PREFERRED_ASPECT; + r->supported_blanking = SUPPORTED_BLANKING; + r->supported_scaling = SUPPORTED_SCALING; + r->preferred_refresh = PREFERRED_REFRESH; + } else { + r->max_clock_khz = 0; + } +} + +static void +get_whitepoint_section(Uchar *c, struct whitePoints *wp) +{ + wp[0].white_x = WHITEX1; + wp[0].white_y = WHITEY1; + wp[1].white_x = WHITEX2; + wp[1].white_y = WHITEY2; + wp[0].index = WHITE_INDEX1; + wp[1].index = WHITE_INDEX2; + wp[0].white_gamma = WHITE_GAMMA1; + wp[1].white_gamma = WHITE_GAMMA2; +} + +static void +get_detailed_timing_section(Uchar *c, struct detailed_timings *r) +{ + r->clock = PIXEL_CLOCK; + r->h_active = H_ACTIVE; + r->h_blanking = H_BLANK; + r->v_active = V_ACTIVE; + r->v_blanking = V_BLANK; + r->h_sync_off = H_SYNC_OFF; + r->h_sync_width = H_SYNC_WIDTH; + r->v_sync_off = V_SYNC_OFF; + r->v_sync_width = V_SYNC_WIDTH; + r->h_size = H_SIZE; + r->v_size = V_SIZE; + r->h_border = H_BORDER; + r->v_border = V_BORDER; + r->interlaced = INTERLACED; + r->stereo = STEREO; + r->stereo_1 = STEREO1; + r->sync = SYNC_T; + r->misc = MISC; +} + +#define MAX_EDID_MINOR 4 + +static Bool +validate_version(int scrnIndex, struct edid_version *r) +{ + if (r->version != 1) { + xf86DrvMsg(scrnIndex, X_ERROR, "Unknown EDID version %d\n", + r->version); + return FALSE; + } + + if (r->revision > MAX_EDID_MINOR) + xf86DrvMsg(scrnIndex, X_WARNING, + "Assuming version 1.%d is compatible with 1.%d\n", + r->revision, MAX_EDID_MINOR); + + return TRUE; +} + +/* + * Returns true if HDMI, false if definitely not or unknown. + */ +Bool +xf86MonitorIsHDMI(xf86MonPtr mon) +{ + int i = 0, version, offset; + char *edid = NULL; + + if (!mon) + return FALSE; + + if (!(mon->flags & EDID_COMPLETE_RAWDATA)) + return FALSE; + + if (!mon->no_sections) + return FALSE; + + edid = (char *)mon->rawData; + if (!edid) + return FALSE; + + /* find the CEA extension block */ + for (i = 1; i <= mon->no_sections; i++) + if (edid[i * 128] == 0x02) + break; + if (i == mon->no_sections + 1) + return FALSE; + edid += (i * 128); + + version = edid[1]; + offset = edid[2]; + if (version < 3 || offset < 4) + return FALSE; + + /* walk the cea data blocks */ + for (i = 4; i < offset; i += (edid[i] & 0x1f) + 1) { + char *x = edid + i; + + /* find a vendor specific block */ + if ((x[0] & 0xe0) >> 5 == 0x03) { + int oui = (x[3] << 16) + (x[2] << 8) + x[1]; + + /* find the HDMI vendor OUI */ + if (oui == 0x000c03) + return TRUE; + } + } + + /* guess it's not HDMI after all */ + return FALSE; +} diff --git a/xorg-server/hw/xfree86/dixmods/extmod/modinit.c b/xorg-server/hw/xfree86/dixmods/extmod/modinit.c index 7d2086802..c0c17d722 100644 --- a/xorg-server/hw/xfree86/dixmods/extmod/modinit.c +++ b/xorg-server/hw/xfree86/dixmods/extmod/modinit.c @@ -1,187 +1,187 @@ -/* - * Copyright (c) 1997 Matthieu Herrb - * - * 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 Matthieu Herrb not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Matthieu Herrb makes no - * representations about the suitability of this software for any purpose. - * It is provided "as is" without express or implied warranty. - * - * MATTHIEU HERRB DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL MATTHIEU HERRB 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_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86Module.h" -#include "xf86Opt.h" - -#include <X11/Xproto.h> - -#include "modinit.h" -#include "globals.h" - -static MODULESETUPPROTO(extmodSetup); - -/* - * Array describing extensions to be initialized - */ -static ExtensionModule extensionModules[] = { -#ifdef XSELINUX - { - SELinuxExtensionInit, - SELINUX_EXTENSION_NAME, - &noSELinuxExtension, - NULL, - NULL - }, -#endif -#ifdef SCREENSAVER - { - ScreenSaverExtensionInit, - ScreenSaverName, - &noScreenSaverExtension, - NULL, - NULL - }, -#endif -#ifdef XF86VIDMODE - { - XFree86VidModeExtensionInit, - XF86VIDMODENAME, - &noXFree86VidModeExtension, - NULL, - NULL - }, -#endif -#ifdef XFreeXDGA - { - XFree86DGAExtensionInit, - XF86DGANAME, - &noXFree86DGAExtension, - XFree86DGARegister, - NULL - }, -#endif -#ifdef DPMSExtension - { - DPMSExtensionInit, - DPMSExtensionName, - &noDPMSExtension, - NULL, - NULL - }, -#endif -#ifdef XV - { - XvExtensionInit, - XvName, - &noXvExtension, - XvRegister, - NULL - }, - { - XvMCExtensionInit, - XvMCName, - &noXvExtension, - NULL, - NULL - }, -#endif -#ifdef RES - { - ResExtensionInit, - XRES_NAME, - &noResExtension, - NULL, - NULL - }, -#endif - { /* DON'T delete this entry ! */ - NULL, - NULL, - NULL, - NULL, - NULL - } -}; - -static XF86ModuleVersionInfo VersRec = -{ - "extmod", - MODULEVENDORSTRING, - MODINFOSTRING1, - MODINFOSTRING2, - XORG_VERSION_CURRENT, - 1, 0, 0, - ABI_CLASS_EXTENSION, - ABI_EXTENSION_VERSION, - MOD_CLASS_EXTENSION, - {0,0,0,0} -}; - -/* - * Data for the loader - */ -_X_EXPORT XF86ModuleData extmodModuleData = { &VersRec, extmodSetup, NULL }; - -static pointer -extmodSetup(pointer module, pointer opts, int *errmaj, int *errmin) -{ - int i; - - /* XXX the option stuff here is largely a sample/test case */ - - for (i = 0; extensionModules[i].name != NULL; i++) { - if (opts) { - char *s; - s = (char *)xalloc(strlen(extensionModules[i].name) + 5); - if (s) { - pointer o; - strcpy(s, "omit"); - strcat(s, extensionModules[i].name); - o = xf86FindOption(opts, s); - xfree(s); - if (o) { - xf86MarkOptionUsed(o); - continue; - } - } - } - -#ifdef XSELINUX - if (! strcmp(SELINUX_EXTENSION_NAME, extensionModules[i].name)) { - pointer o; - selinuxEnforcingState = SELINUX_MODE_DEFAULT; - - if ((o = xf86FindOption(opts, "SELinux mode disabled"))) { - xf86MarkOptionUsed(o); - selinuxEnforcingState = SELINUX_MODE_DISABLED; - } - if ((o = xf86FindOption(opts, "SELinux mode permissive"))) { - xf86MarkOptionUsed(o); - selinuxEnforcingState = SELINUX_MODE_PERMISSIVE; - } - if ((o = xf86FindOption(opts, "SELinux mode enforcing"))) { - xf86MarkOptionUsed(o); - selinuxEnforcingState = SELINUX_MODE_ENFORCING; - } - } -#endif - - LoadExtension(&extensionModules[i], FALSE); - } - /* Need a non-NULL return */ - return (pointer)1; -} +/* + * Copyright (c) 1997 Matthieu Herrb + * + * 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 Matthieu Herrb not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Matthieu Herrb makes no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * MATTHIEU HERRB DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL MATTHIEU HERRB 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_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86Module.h" +#include "xf86Opt.h" + +#include <X11/Xproto.h> + +#include "modinit.h" +#include "globals.h" + +static MODULESETUPPROTO(extmodSetup); + +/* + * Array describing extensions to be initialized + */ +static ExtensionModule extensionModules[] = { +#ifdef XSELINUX + { + SELinuxExtensionInit, + SELINUX_EXTENSION_NAME, + &noSELinuxExtension, + NULL, + NULL + }, +#endif +#ifdef SCREENSAVER + { + ScreenSaverExtensionInit, + ScreenSaverName, + &noScreenSaverExtension, + NULL, + NULL + }, +#endif +#ifdef XF86VIDMODE + { + XFree86VidModeExtensionInit, + XF86VIDMODENAME, + &noXFree86VidModeExtension, + NULL, + NULL + }, +#endif +#ifdef XFreeXDGA + { + XFree86DGAExtensionInit, + XF86DGANAME, + &noXFree86DGAExtension, + XFree86DGARegister, + NULL + }, +#endif +#ifdef DPMSExtension + { + DPMSExtensionInit, + DPMSExtensionName, + &noDPMSExtension, + NULL, + NULL + }, +#endif +#ifdef XV + { + XvExtensionInit, + XvName, + &noXvExtension, + XvRegister, + NULL + }, + { + XvMCExtensionInit, + XvMCName, + &noXvExtension, + NULL, + NULL + }, +#endif +#ifdef RES + { + ResExtensionInit, + XRES_NAME, + &noResExtension, + NULL, + NULL + }, +#endif + { /* DON'T delete this entry ! */ + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +static XF86ModuleVersionInfo VersRec = +{ + "extmod", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_EXTENSION, + ABI_EXTENSION_VERSION, + MOD_CLASS_EXTENSION, + {0,0,0,0} +}; + +/* + * Data for the loader + */ +_X_EXPORT XF86ModuleData extmodModuleData = { &VersRec, extmodSetup, NULL }; + +static pointer +extmodSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + int i; + + /* XXX the option stuff here is largely a sample/test case */ + + for (i = 0; extensionModules[i].name != NULL; i++) { + if (opts) { + char *s; + s = (char *)malloc(strlen(extensionModules[i].name) + 5); + if (s) { + pointer o; + strcpy(s, "omit"); + strcat(s, extensionModules[i].name); + o = xf86FindOption(opts, s); + free(s); + if (o) { + xf86MarkOptionUsed(o); + continue; + } + } + } + +#ifdef XSELINUX + if (! strcmp(SELINUX_EXTENSION_NAME, extensionModules[i].name)) { + pointer o; + selinuxEnforcingState = SELINUX_MODE_DEFAULT; + + if ((o = xf86FindOption(opts, "SELinux mode disabled"))) { + xf86MarkOptionUsed(o); + selinuxEnforcingState = SELINUX_MODE_DISABLED; + } + if ((o = xf86FindOption(opts, "SELinux mode permissive"))) { + xf86MarkOptionUsed(o); + selinuxEnforcingState = SELINUX_MODE_PERMISSIVE; + } + if ((o = xf86FindOption(opts, "SELinux mode enforcing"))) { + xf86MarkOptionUsed(o); + selinuxEnforcingState = SELINUX_MODE_ENFORCING; + } + } +#endif + + LoadExtension(&extensionModules[i], FALSE); + } + /* Need a non-NULL return */ + return (pointer)1; +} diff --git a/xorg-server/hw/xfree86/dixmods/extmod/xf86dga2.c b/xorg-server/hw/xfree86/dixmods/extmod/xf86dga2.c index 038551467..fae8d8b5d 100644 --- a/xorg-server/hw/xfree86/dixmods/extmod/xf86dga2.c +++ b/xorg-server/hw/xfree86/dixmods/extmod/xf86dga2.c @@ -1,1062 +1,1058 @@ -/* - * Copyright (c) 1995 Jon Tombs - * Copyright (c) 1995, 1996, 1999 XFree86 Inc - * Copyright (c) 1999 - The XFree86 Project Inc. - * - * Written by Mark Vojkovich - */ - - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "dixstruct.h" -#include "dixevents.h" -#include "pixmapstr.h" -#include "extnsionst.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "servermd.h" -#include <X11/extensions/xf86dgaproto.h> -#include "swaprep.h" -#include "dgaproc.h" -#include "xf86dgaext.h" -#include "protocol-versions.h" - -#include <string.h> - -#include "modinit.h" - -#define DGA_PROTOCOL_OLD_SUPPORT 1 - -static DISPATCH_PROC(ProcXDGADispatch); -static DISPATCH_PROC(SProcXDGADispatch); -static DISPATCH_PROC(ProcXDGAQueryVersion); -static DISPATCH_PROC(ProcXDGAQueryModes); -static DISPATCH_PROC(ProcXDGASetMode); -static DISPATCH_PROC(ProcXDGAOpenFramebuffer); -static DISPATCH_PROC(ProcXDGACloseFramebuffer); -static DISPATCH_PROC(ProcXDGASetViewport); -static DISPATCH_PROC(ProcXDGAInstallColormap); -static DISPATCH_PROC(ProcXDGASelectInput); -static DISPATCH_PROC(ProcXDGAFillRectangle); -static DISPATCH_PROC(ProcXDGACopyArea); -static DISPATCH_PROC(ProcXDGACopyTransparentArea); -static DISPATCH_PROC(ProcXDGAGetViewportStatus); -static DISPATCH_PROC(ProcXDGASync); -static DISPATCH_PROC(ProcXDGASetClientVersion); -static DISPATCH_PROC(ProcXDGAChangePixmapMode); -static DISPATCH_PROC(ProcXDGACreateColormap); - -static void XDGAResetProc(ExtensionEntry *extEntry); - -static void DGAClientStateChange (CallbackListPtr*, pointer, pointer); - -unsigned char DGAReqCode = 0; -int DGAErrorBase; -int DGAEventBase; - -static int DGAScreenPrivateKeyIndex; -static DevPrivateKey DGAScreenPrivateKey = &DGAScreenPrivateKeyIndex; -static int DGAClientPrivateKeyIndex; -static DevPrivateKey DGAClientPrivateKey = &DGAClientPrivateKeyIndex; -static int DGACallbackRefCount = 0; - -/* This holds the client's version information */ -typedef struct { - int major; - int minor; -} DGAPrivRec, *DGAPrivPtr; - -#define DGA_GETCLIENT(idx) ((ClientPtr) \ - dixLookupPrivate(&screenInfo.screens[idx]->devPrivates, DGAScreenPrivateKey)) -#define DGA_SETCLIENT(idx,p) \ - dixSetPrivate(&screenInfo.screens[idx]->devPrivates, DGAScreenPrivateKey, p) - -#define DGA_GETPRIV(c) ((DGAPrivPtr) \ - dixLookupPrivate(&(c)->devPrivates, DGAClientPrivateKey)) -#define DGA_SETPRIV(c,p) \ - dixSetPrivate(&(c)->devPrivates, DGAClientPrivateKey, p) - - -void -XFree86DGAExtensionInit(INITARGS) -{ - ExtensionEntry* extEntry; - - if ((extEntry = AddExtension(XF86DGANAME, - XF86DGANumberEvents, - XF86DGANumberErrors, - ProcXDGADispatch, - SProcXDGADispatch, - XDGAResetProc, - StandardMinorOpcode))) { - int i; - - DGAReqCode = (unsigned char)extEntry->base; - DGAErrorBase = extEntry->errorBase; - DGAEventBase = extEntry->eventBase; - for (i = KeyPress; i <= MotionNotify; i++) - SetCriticalEvent (DGAEventBase + i); - } -} - - - -static void -XDGAResetProc (ExtensionEntry *extEntry) -{ - DeleteCallback (&ClientStateCallback, DGAClientStateChange, NULL); - DGACallbackRefCount = 0; -} - - -static int -ProcXDGAQueryVersion(ClientPtr client) -{ - xXDGAQueryVersionReply rep; - - REQUEST_SIZE_MATCH(xXDGAQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_XDGA_MAJOR_VERSION; - rep.minorVersion = SERVER_XDGA_MINOR_VERSION; - - WriteToClient(client, sizeof(xXDGAQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - - -static int -ProcXDGAOpenFramebuffer(ClientPtr client) -{ - REQUEST(xXDGAOpenFramebufferReq); - xXDGAOpenFramebufferReply rep; - char *deviceName; - int nameSize; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if (!DGAAvailable(stuff->screen)) - return DGAErrorBase + XF86DGANoDirectVideoMode; - - REQUEST_SIZE_MATCH(xXDGAOpenFramebufferReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if(!DGAOpenFramebuffer(stuff->screen, &deviceName, - (unsigned char**)(&rep.mem1), - (int*)&rep.size, (int*)&rep.offset, (int*)&rep.extra)) - { - return BadAlloc; - } - - nameSize = deviceName ? (strlen(deviceName) + 1) : 0; - rep.length = bytes_to_int32(nameSize); - - WriteToClient(client, sizeof(xXDGAOpenFramebufferReply), (char *)&rep); - if(rep.length) - WriteToClient(client, nameSize, deviceName); - - return (client->noClientException); -} - - -static int -ProcXDGACloseFramebuffer(ClientPtr client) -{ - REQUEST(xXDGACloseFramebufferReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if (!DGAAvailable(stuff->screen)) - return DGAErrorBase + XF86DGANoDirectVideoMode; - - REQUEST_SIZE_MATCH(xXDGACloseFramebufferReq); - - DGACloseFramebuffer(stuff->screen); - - return (client->noClientException); -} - -static int -ProcXDGAQueryModes(ClientPtr client) -{ - int i, num, size; - REQUEST(xXDGAQueryModesReq); - xXDGAQueryModesReply rep; - xXDGAModeInfo info; - XDGAModePtr mode; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - REQUEST_SIZE_MATCH(xXDGAQueryModesReq); - rep.type = X_Reply; - rep.length = 0; - rep.number = 0; - rep.sequenceNumber = client->sequence; - - if (!DGAAvailable(stuff->screen)) { - rep.number = 0; - rep.length = 0; - WriteToClient(client, sz_xXDGAQueryModesReply, (char*)&rep); - return (client->noClientException); - } - - if(!(num = DGAGetModes(stuff->screen))) { - WriteToClient(client, sz_xXDGAQueryModesReply, (char*)&rep); - return (client->noClientException); - } - - if(!(mode = (XDGAModePtr)xalloc(num * sizeof(XDGAModeRec)))) - return BadAlloc; - - for(i = 0; i < num; i++) - DGAGetModeInfo(stuff->screen, mode + i, i + 1); - - size = num * sz_xXDGAModeInfo; - for(i = 0; i < num; i++) - size += pad_to_int32(strlen(mode[i].name) + 1); /* plus NULL */ - - rep.number = num; - rep.length = bytes_to_int32(size); - - WriteToClient(client, sz_xXDGAQueryModesReply, (char*)&rep); - - for(i = 0; i < num; i++) { - size = strlen(mode[i].name) + 1; - - info.byte_order = mode[i].byteOrder; - info.depth = mode[i].depth; - info.num = mode[i].num; - info.bpp = mode[i].bitsPerPixel; - info.name_size = (size + 3) & ~3L; - info.vsync_num = mode[i].VSync_num; - info.vsync_den = mode[i].VSync_den; - info.flags = mode[i].flags; - info.image_width = mode[i].imageWidth; - info.image_height = mode[i].imageHeight; - info.pixmap_width = mode[i].pixmapWidth; - info.pixmap_height = mode[i].pixmapHeight; - info.bytes_per_scanline = mode[i].bytesPerScanline; - info.red_mask = mode[i].red_mask; - info.green_mask = mode[i].green_mask; - info.blue_mask = mode[i].blue_mask; - info.visual_class = mode[i].visualClass; - info.viewport_width = mode[i].viewportWidth; - info.viewport_height = mode[i].viewportHeight; - info.viewport_xstep = mode[i].xViewportStep; - info.viewport_ystep = mode[i].yViewportStep; - info.viewport_xmax = mode[i].maxViewportX; - info.viewport_ymax = mode[i].maxViewportY; - info.viewport_flags = mode[i].viewportFlags; - info.reserved1 = mode[i].reserved1; - info.reserved2 = mode[i].reserved2; - - WriteToClient(client, sz_xXDGAModeInfo, (char*)(&info)); - WriteToClient(client, size, mode[i].name); - } - - xfree(mode); - - return (client->noClientException); -} - - -static void -DGAClientStateChange ( - CallbackListPtr* pcbl, - pointer nulldata, - pointer calldata -){ - NewClientInfoRec* pci = (NewClientInfoRec*) calldata; - ClientPtr client = NULL; - int i; - - for(i = 0; i < screenInfo.numScreens; i++) { - if(DGA_GETCLIENT(i) == pci->client) { - client = pci->client; - break; - } - } - - if(client && - ((client->clientState == ClientStateGone) || - (client->clientState == ClientStateRetained))) { - XDGAModeRec mode; - PixmapPtr pPix; - - DGA_SETCLIENT(i, NULL); - DGASelectInput(i, NULL, 0); - DGASetMode(i, 0, &mode, &pPix); - - if(--DGACallbackRefCount == 0) - DeleteCallback(&ClientStateCallback, DGAClientStateChange, NULL); - } -} - -static int -ProcXDGASetMode(ClientPtr client) -{ - REQUEST(xXDGASetModeReq); - xXDGASetModeReply rep; - XDGAModeRec mode; - xXDGAModeInfo info; - PixmapPtr pPix; - ClientPtr owner; - int size; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - owner = DGA_GETCLIENT(stuff->screen); - - REQUEST_SIZE_MATCH(xXDGASetModeReq); - rep.type = X_Reply; - rep.length = 0; - rep.offset = 0; - rep.flags = 0; - rep.sequenceNumber = client->sequence; - - if (!DGAAvailable(stuff->screen)) - return DGAErrorBase + XF86DGANoDirectVideoMode; - - if(owner && owner != client) - return DGAErrorBase + XF86DGANoDirectVideoMode; - - if(!stuff->mode) { - if(owner) { - if(--DGACallbackRefCount == 0) - DeleteCallback(&ClientStateCallback, DGAClientStateChange, NULL); - } - DGA_SETCLIENT(stuff->screen, NULL); - DGASelectInput(stuff->screen, NULL, 0); - DGASetMode(stuff->screen, 0, &mode, &pPix); - WriteToClient(client, sz_xXDGASetModeReply, (char*)&rep); - return (client->noClientException); - } - - if(Success != DGASetMode(stuff->screen, stuff->mode, &mode, &pPix)) - return BadValue; - - if(!owner) { - if(DGACallbackRefCount++ == 0) - AddCallback (&ClientStateCallback, DGAClientStateChange, NULL); - } - - DGA_SETCLIENT(stuff->screen, client); - - if(pPix) { - if(AddResource(stuff->pid, RT_PIXMAP, (pointer)(pPix))) { - pPix->drawable.id = (int)stuff->pid; - rep.flags = DGA_PIXMAP_AVAILABLE; - } - } - - size = strlen(mode.name) + 1; - - info.byte_order = mode.byteOrder; - info.depth = mode.depth; - info.num = mode.num; - info.bpp = mode.bitsPerPixel; - info.name_size = (size + 3) & ~3L; - info.vsync_num = mode.VSync_num; - info.vsync_den = mode.VSync_den; - info.flags = mode.flags; - info.image_width = mode.imageWidth; - info.image_height = mode.imageHeight; - info.pixmap_width = mode.pixmapWidth; - info.pixmap_height = mode.pixmapHeight; - info.bytes_per_scanline = mode.bytesPerScanline; - info.red_mask = mode.red_mask; - info.green_mask = mode.green_mask; - info.blue_mask = mode.blue_mask; - info.visual_class = mode.visualClass; - info.viewport_width = mode.viewportWidth; - info.viewport_height = mode.viewportHeight; - info.viewport_xstep = mode.xViewportStep; - info.viewport_ystep = mode.yViewportStep; - info.viewport_xmax = mode.maxViewportX; - info.viewport_ymax = mode.maxViewportY; - info.viewport_flags = mode.viewportFlags; - info.reserved1 = mode.reserved1; - info.reserved2 = mode.reserved2; - - rep.length = bytes_to_int32(sz_xXDGAModeInfo + info.name_size); - - WriteToClient(client, sz_xXDGASetModeReply, (char*)&rep); - WriteToClient(client, sz_xXDGAModeInfo, (char*)(&info)); - WriteToClient(client, size, mode.name); - - return (client->noClientException); -} - -static int -ProcXDGASetViewport(ClientPtr client) -{ - REQUEST(xXDGASetViewportReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGASetViewportReq); - - DGASetViewport(stuff->screen, stuff->x, stuff->y, stuff->flags); - - return (client->noClientException); -} - -static int -ProcXDGAInstallColormap(ClientPtr client) -{ - ColormapPtr cmap; - int rc; - REQUEST(xXDGAInstallColormapReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGAInstallColormapReq); - - rc = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, RT_COLORMAP, - client, DixInstallAccess); - if (rc == Success) { - DGAInstallCmap(cmap); - return (client->noClientException); - } else { - return (rc == BadValue) ? BadColor : rc; - } - - return (client->noClientException); -} - - -static int -ProcXDGASelectInput(ClientPtr client) -{ - REQUEST(xXDGASelectInputReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGASelectInputReq); - - if(DGA_GETCLIENT(stuff->screen) == client) - DGASelectInput(stuff->screen, client, stuff->mask); - - return (client->noClientException); -} - - -static int -ProcXDGAFillRectangle(ClientPtr client) -{ - REQUEST(xXDGAFillRectangleReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGAFillRectangleReq); - - if(Success != DGAFillRect(stuff->screen, stuff->x, stuff->y, - stuff->width, stuff->height, stuff->color)) - return BadMatch; - - return (client->noClientException); -} - -static int -ProcXDGACopyArea(ClientPtr client) -{ - REQUEST(xXDGACopyAreaReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGACopyAreaReq); - - if(Success != DGABlitRect(stuff->screen, stuff->srcx, stuff->srcy, - stuff->width, stuff->height, stuff->dstx, stuff->dsty)) - return BadMatch; - - return (client->noClientException); -} - - -static int -ProcXDGACopyTransparentArea(ClientPtr client) -{ - REQUEST(xXDGACopyTransparentAreaReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGACopyTransparentAreaReq); - - if(Success != DGABlitTransRect(stuff->screen, stuff->srcx, stuff->srcy, - stuff->width, stuff->height, stuff->dstx, stuff->dsty, stuff->key)) - return BadMatch; - - return (client->noClientException); -} - - -static int -ProcXDGAGetViewportStatus(ClientPtr client) -{ - REQUEST(xXDGAGetViewportStatusReq); - xXDGAGetViewportStatusReply rep; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGAGetViewportStatusReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rep.status = DGAGetViewportStatus(stuff->screen); - - WriteToClient(client, sizeof(xXDGAGetViewportStatusReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXDGASync(ClientPtr client) -{ - REQUEST(xXDGASyncReq); - xXDGASyncReply rep; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGASyncReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - DGASync(stuff->screen); - - WriteToClient(client, sizeof(xXDGASyncReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXDGASetClientVersion(ClientPtr client) -{ - REQUEST(xXDGASetClientVersionReq); - - DGAPrivPtr pPriv; - - REQUEST_SIZE_MATCH(xXDGASetClientVersionReq); - if ((pPriv = DGA_GETPRIV(client)) == NULL) { - pPriv = xalloc(sizeof(DGAPrivRec)); - /* XXX Need to look into freeing this */ - if (!pPriv) - return BadAlloc; - DGA_SETPRIV(client, pPriv); - } - pPriv->major = stuff->major; - pPriv->minor = stuff->minor; - - return (client->noClientException); -} - -static int -ProcXDGAChangePixmapMode(ClientPtr client) -{ - REQUEST(xXDGAChangePixmapModeReq); - xXDGAChangePixmapModeReply rep; - int x, y; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGAChangePixmapModeReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - x = stuff->x; - y = stuff->y; - - if(!DGAChangePixmapMode(stuff->screen, &x, &y, stuff->flags)) - return BadMatch; - - rep.x = x; - rep.y = y; - WriteToClient(client, sizeof(xXDGAChangePixmapModeReply), (char *)&rep); - - return (client->noClientException); -} - - -static int -ProcXDGACreateColormap(ClientPtr client) -{ - REQUEST(xXDGACreateColormapReq); - int result; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if(DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXDGACreateColormapReq); - - if(!stuff->mode) - return BadValue; - - result = DGACreateColormap(stuff->screen, client, stuff->id, - stuff->mode, stuff->alloc); - if(result != Success) - return result; - - return (client->noClientException); -} - -/* - * - * Support for the old DGA protocol, used to live in xf86dga.c - * - */ - -#ifdef DGA_PROTOCOL_OLD_SUPPORT - -static DISPATCH_PROC(ProcXF86DGADirectVideo); -static DISPATCH_PROC(ProcXF86DGAGetVidPage); -static DISPATCH_PROC(ProcXF86DGAGetVideoLL); -static DISPATCH_PROC(ProcXF86DGAGetViewPortSize); -static DISPATCH_PROC(ProcXF86DGASetVidPage); -static DISPATCH_PROC(ProcXF86DGASetViewPort); -static DISPATCH_PROC(ProcXF86DGAInstallColormap); -static DISPATCH_PROC(ProcXF86DGAQueryDirectVideo); -static DISPATCH_PROC(ProcXF86DGAViewPortChanged); - - -static int -ProcXF86DGAGetVideoLL(ClientPtr client) -{ - REQUEST(xXF86DGAGetVideoLLReq); - xXF86DGAGetVideoLLReply rep; - XDGAModeRec mode; - int num, offset, flags; - char *name; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - REQUEST_SIZE_MATCH(xXF86DGAGetVideoLLReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if(!DGAAvailable(stuff->screen)) - return (DGAErrorBase + XF86DGANoDirectVideoMode); - - if(!(num = DGAGetOldDGAMode(stuff->screen))) - return (DGAErrorBase + XF86DGANoDirectVideoMode); - - /* get the parameters for the mode that best matches */ - DGAGetModeInfo(stuff->screen, &mode, num); - - if(!DGAOpenFramebuffer(stuff->screen, &name, - (unsigned char**)(&rep.offset), - (int*)(&rep.bank_size), &offset, &flags)) - return BadAlloc; - - rep.offset += mode.offset; - rep.width = mode.bytesPerScanline / (mode.bitsPerPixel >> 3); - rep.ram_size = rep.bank_size >> 10; - - WriteToClient(client, SIZEOF(xXF86DGAGetVideoLLReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86DGADirectVideo(ClientPtr client) -{ - int num; - PixmapPtr pix; - XDGAModeRec mode; - ClientPtr owner; - REQUEST(xXF86DGADirectVideoReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - owner = DGA_GETCLIENT(stuff->screen); - - REQUEST_SIZE_MATCH(xXF86DGADirectVideoReq); - - if (!DGAAvailable(stuff->screen)) - return DGAErrorBase + XF86DGANoDirectVideoMode; - - if (owner && owner != client) - return DGAErrorBase + XF86DGANoDirectVideoMode; - - if (stuff->enable & XF86DGADirectGraphics) { - if(!(num = DGAGetOldDGAMode(stuff->screen))) - return (DGAErrorBase + XF86DGANoDirectVideoMode); - } else - num = 0; - - if(Success != DGASetMode(stuff->screen, num, &mode, &pix)) - return (DGAErrorBase + XF86DGAScreenNotActive); - - DGASetInputMode (stuff->screen, - (stuff->enable & XF86DGADirectKeyb) != 0, - (stuff->enable & XF86DGADirectMouse) != 0); - - /* We need to track the client and attach the teardown callback */ - if (stuff->enable & - (XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse)) { - if (!owner) { - if (DGACallbackRefCount++ == 0) - AddCallback (&ClientStateCallback, DGAClientStateChange, NULL); - } - - DGA_SETCLIENT(stuff->screen, client); - } else { - if (owner) { - if (--DGACallbackRefCount == 0) - DeleteCallback(&ClientStateCallback, DGAClientStateChange, NULL); - } - - DGA_SETCLIENT(stuff->screen, NULL); - } - - return (client->noClientException); -} - -static int -ProcXF86DGAGetViewPortSize(ClientPtr client) -{ - int num; - XDGAModeRec mode; - REQUEST(xXF86DGAGetViewPortSizeReq); - xXF86DGAGetViewPortSizeReply rep; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - REQUEST_SIZE_MATCH(xXF86DGAGetViewPortSizeReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if (!DGAAvailable(stuff->screen)) - return (DGAErrorBase + XF86DGANoDirectVideoMode); - - if(!(num = DGAGetOldDGAMode(stuff->screen))) - return (DGAErrorBase + XF86DGANoDirectVideoMode); - - DGAGetModeInfo(stuff->screen, &mode, num); - - rep.width = mode.viewportWidth; - rep.height = mode.viewportHeight; - - WriteToClient(client, SIZEOF(xXF86DGAGetViewPortSizeReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86DGASetViewPort(ClientPtr client) -{ - REQUEST(xXF86DGASetViewPortReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if (DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXF86DGASetViewPortReq); - - if (!DGAAvailable(stuff->screen)) - return (DGAErrorBase + XF86DGANoDirectVideoMode); - - if (!DGAActive(stuff->screen)) - return DGAErrorBase + XF86DGADirectNotActivated; - - if (DGASetViewport(stuff->screen, stuff->x, stuff->y, DGA_FLIP_RETRACE) - != Success) - return DGAErrorBase + XF86DGADirectNotActivated; - - return (client->noClientException); -} - -static int -ProcXF86DGAGetVidPage(ClientPtr client) -{ - REQUEST(xXF86DGAGetVidPageReq); - xXF86DGAGetVidPageReply rep; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - REQUEST_SIZE_MATCH(xXF86DGAGetVidPageReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.vpage = 0; /* silently fail */ - - WriteToClient(client, SIZEOF(xXF86DGAGetVidPageReply), (char *)&rep); - return (client->noClientException); -} - - -static int -ProcXF86DGASetVidPage(ClientPtr client) -{ - REQUEST(xXF86DGASetVidPageReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - REQUEST_SIZE_MATCH(xXF86DGASetVidPageReq); - - /* silently fail */ - - return (client->noClientException); -} - - -static int -ProcXF86DGAInstallColormap(ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xXF86DGAInstallColormapReq); - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if (DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXF86DGAInstallColormapReq); - - if (!DGAActive(stuff->screen)) - return (DGAErrorBase + XF86DGADirectNotActivated); - - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->id, RT_COLORMAP, - client, DixInstallAccess); - if (rc == Success) { - DGAInstallCmap(pcmp); - return (client->noClientException); - } else { - return (rc == BadValue) ? BadColor : rc; - } -} - -static int -ProcXF86DGAQueryDirectVideo(ClientPtr client) -{ - REQUEST(xXF86DGAQueryDirectVideoReq); - xXF86DGAQueryDirectVideoReply rep; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - REQUEST_SIZE_MATCH(xXF86DGAQueryDirectVideoReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.flags = 0; - - if (DGAAvailable(stuff->screen)) - rep.flags = XF86DGADirectPresent; - - WriteToClient(client, SIZEOF(xXF86DGAQueryDirectVideoReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86DGAViewPortChanged(ClientPtr client) -{ - REQUEST(xXF86DGAViewPortChangedReq); - xXF86DGAViewPortChangedReply rep; - - if (stuff->screen > screenInfo.numScreens) - return BadValue; - - if (DGA_GETCLIENT(stuff->screen) != client) - return DGAErrorBase + XF86DGADirectNotActivated; - - REQUEST_SIZE_MATCH(xXF86DGAViewPortChangedReq); - - if (!DGAActive(stuff->screen)) - return (DGAErrorBase + XF86DGADirectNotActivated); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.result = 1; - - WriteToClient(client, SIZEOF(xXF86DGAViewPortChangedReply), (char *)&rep); - return (client->noClientException); -} - -#endif /* DGA_PROTOCOL_OLD_SUPPORT */ - -static int -SProcXDGADispatch (ClientPtr client) -{ - return DGAErrorBase + XF86DGAClientNotLocal; -} - -#if 0 -#define DGA_REQ_DEBUG -#endif - -#ifdef DGA_REQ_DEBUG -static char *dgaMinor[] = { - "QueryVersion", - "GetVideoLL", - "DirectVideo", - "GetViewPortSize", - "SetViewPort", - "GetVidPage", - "SetVidPage", - "InstallColormap", - "QueryDirectVideo", - "ViewPortChanged", - "10", - "11", - "QueryModes", - "SetMode", - "SetViewport", - "InstallColormap", - "SelectInput", - "FillRectangle", - "CopyArea", - "CopyTransparentArea", - "GetViewportStatus", - "Sync", - "OpenFramebuffer", - "CloseFramebuffer", - "SetClientVersion", - "ChangePixmapMode", - "CreateColormap", -}; -#endif - -static int -ProcXDGADispatch (ClientPtr client) -{ - REQUEST(xReq); - - if (!LocalClient(client)) - return DGAErrorBase + XF86DGAClientNotLocal; - -#ifdef DGA_REQ_DEBUG - if (stuff->data <= X_XDGACreateColormap) - fprintf (stderr, " DGA %s\n", dgaMinor[stuff->data]); -#endif - - switch (stuff->data){ - /* - * DGA2 Protocol - */ - case X_XDGAQueryVersion: - return ProcXDGAQueryVersion(client); - case X_XDGAQueryModes: - return ProcXDGAQueryModes(client); - case X_XDGASetMode: - return ProcXDGASetMode(client); - case X_XDGAOpenFramebuffer: - return ProcXDGAOpenFramebuffer(client); - case X_XDGACloseFramebuffer: - return ProcXDGACloseFramebuffer(client); - case X_XDGASetViewport: - return ProcXDGASetViewport(client); - case X_XDGAInstallColormap: - return ProcXDGAInstallColormap(client); - case X_XDGASelectInput: - return ProcXDGASelectInput(client); - case X_XDGAFillRectangle: - return ProcXDGAFillRectangle(client); - case X_XDGACopyArea: - return ProcXDGACopyArea(client); - case X_XDGACopyTransparentArea: - return ProcXDGACopyTransparentArea(client); - case X_XDGAGetViewportStatus: - return ProcXDGAGetViewportStatus(client); - case X_XDGASync: - return ProcXDGASync(client); - case X_XDGASetClientVersion: - return ProcXDGASetClientVersion(client); - case X_XDGAChangePixmapMode: - return ProcXDGAChangePixmapMode(client); - case X_XDGACreateColormap: - return ProcXDGACreateColormap(client); - /* - * Old DGA Protocol - */ -#ifdef DGA_PROTOCOL_OLD_SUPPORT - case X_XF86DGAGetVideoLL: - return ProcXF86DGAGetVideoLL(client); - case X_XF86DGADirectVideo: - return ProcXF86DGADirectVideo(client); - case X_XF86DGAGetViewPortSize: - return ProcXF86DGAGetViewPortSize(client); - case X_XF86DGASetViewPort: - return ProcXF86DGASetViewPort(client); - case X_XF86DGAGetVidPage: - return ProcXF86DGAGetVidPage(client); - case X_XF86DGASetVidPage: - return ProcXF86DGASetVidPage(client); - case X_XF86DGAInstallColormap: - return ProcXF86DGAInstallColormap(client); - case X_XF86DGAQueryDirectVideo: - return ProcXF86DGAQueryDirectVideo(client); - case X_XF86DGAViewPortChanged: - return ProcXF86DGAViewPortChanged(client); -#endif /* DGA_PROTOCOL_OLD_SUPPORT */ - default: - return BadRequest; - } -} - -void -XFree86DGARegister(INITARGS) -{ - XDGAEventBase = &DGAEventBase; -} +/* + * Copyright (c) 1995 Jon Tombs + * Copyright (c) 1995, 1996, 1999 XFree86 Inc + * Copyright (c) 1999 - The XFree86 Project Inc. + * + * Written by Mark Vojkovich + */ + + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "dixstruct.h" +#include "dixevents.h" +#include "pixmapstr.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "servermd.h" +#include <X11/extensions/xf86dgaproto.h> +#include "swaprep.h" +#include "dgaproc.h" +#include "xf86dgaext.h" +#include "protocol-versions.h" + +#include <string.h> + +#include "modinit.h" + +#define DGA_PROTOCOL_OLD_SUPPORT 1 + +static DISPATCH_PROC(ProcXDGADispatch); +static DISPATCH_PROC(SProcXDGADispatch); +static DISPATCH_PROC(ProcXDGAQueryVersion); +static DISPATCH_PROC(ProcXDGAQueryModes); +static DISPATCH_PROC(ProcXDGASetMode); +static DISPATCH_PROC(ProcXDGAOpenFramebuffer); +static DISPATCH_PROC(ProcXDGACloseFramebuffer); +static DISPATCH_PROC(ProcXDGASetViewport); +static DISPATCH_PROC(ProcXDGAInstallColormap); +static DISPATCH_PROC(ProcXDGASelectInput); +static DISPATCH_PROC(ProcXDGAFillRectangle); +static DISPATCH_PROC(ProcXDGACopyArea); +static DISPATCH_PROC(ProcXDGACopyTransparentArea); +static DISPATCH_PROC(ProcXDGAGetViewportStatus); +static DISPATCH_PROC(ProcXDGASync); +static DISPATCH_PROC(ProcXDGASetClientVersion); +static DISPATCH_PROC(ProcXDGAChangePixmapMode); +static DISPATCH_PROC(ProcXDGACreateColormap); + +static void XDGAResetProc(ExtensionEntry *extEntry); + +static void DGAClientStateChange (CallbackListPtr*, pointer, pointer); + +unsigned char DGAReqCode = 0; +int DGAErrorBase; +int DGAEventBase; + +static int DGAScreenPrivateKeyIndex; +static DevPrivateKey DGAScreenPrivateKey = &DGAScreenPrivateKeyIndex; +static int DGAClientPrivateKeyIndex; +static DevPrivateKey DGAClientPrivateKey = &DGAClientPrivateKeyIndex; +static int DGACallbackRefCount = 0; + +/* This holds the client's version information */ +typedef struct { + int major; + int minor; +} DGAPrivRec, *DGAPrivPtr; + +#define DGA_GETCLIENT(idx) ((ClientPtr) \ + dixLookupPrivate(&screenInfo.screens[idx]->devPrivates, DGAScreenPrivateKey)) +#define DGA_SETCLIENT(idx,p) \ + dixSetPrivate(&screenInfo.screens[idx]->devPrivates, DGAScreenPrivateKey, p) + +#define DGA_GETPRIV(c) ((DGAPrivPtr) \ + dixLookupPrivate(&(c)->devPrivates, DGAClientPrivateKey)) +#define DGA_SETPRIV(c,p) \ + dixSetPrivate(&(c)->devPrivates, DGAClientPrivateKey, p) + + +void +XFree86DGAExtensionInit(INITARGS) +{ + ExtensionEntry* extEntry; + + if ((extEntry = AddExtension(XF86DGANAME, + XF86DGANumberEvents, + XF86DGANumberErrors, + ProcXDGADispatch, + SProcXDGADispatch, + XDGAResetProc, + StandardMinorOpcode))) { + int i; + + DGAReqCode = (unsigned char)extEntry->base; + DGAErrorBase = extEntry->errorBase; + DGAEventBase = extEntry->eventBase; + for (i = KeyPress; i <= MotionNotify; i++) + SetCriticalEvent (DGAEventBase + i); + } +} + + + +static void +XDGAResetProc (ExtensionEntry *extEntry) +{ + DeleteCallback (&ClientStateCallback, DGAClientStateChange, NULL); + DGACallbackRefCount = 0; +} + + +static int +ProcXDGAQueryVersion(ClientPtr client) +{ + xXDGAQueryVersionReply rep; + + REQUEST_SIZE_MATCH(xXDGAQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_XDGA_MAJOR_VERSION; + rep.minorVersion = SERVER_XDGA_MINOR_VERSION; + + WriteToClient(client, sizeof(xXDGAQueryVersionReply), (char *)&rep); + return Success; +} + + +static int +ProcXDGAOpenFramebuffer(ClientPtr client) +{ + REQUEST(xXDGAOpenFramebufferReq); + xXDGAOpenFramebufferReply rep; + char *deviceName; + int nameSize; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if (!DGAAvailable(stuff->screen)) + return DGAErrorBase + XF86DGANoDirectVideoMode; + + REQUEST_SIZE_MATCH(xXDGAOpenFramebufferReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if(!DGAOpenFramebuffer(stuff->screen, &deviceName, + (unsigned char**)(&rep.mem1), + (int*)&rep.size, (int*)&rep.offset, (int*)&rep.extra)) + { + return BadAlloc; + } + + nameSize = deviceName ? (strlen(deviceName) + 1) : 0; + rep.length = bytes_to_int32(nameSize); + + WriteToClient(client, sizeof(xXDGAOpenFramebufferReply), (char *)&rep); + if(rep.length) + WriteToClient(client, nameSize, deviceName); + + return Success; +} + + +static int +ProcXDGACloseFramebuffer(ClientPtr client) +{ + REQUEST(xXDGACloseFramebufferReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if (!DGAAvailable(stuff->screen)) + return DGAErrorBase + XF86DGANoDirectVideoMode; + + REQUEST_SIZE_MATCH(xXDGACloseFramebufferReq); + + DGACloseFramebuffer(stuff->screen); + + return Success; +} + +static int +ProcXDGAQueryModes(ClientPtr client) +{ + int i, num, size; + REQUEST(xXDGAQueryModesReq); + xXDGAQueryModesReply rep; + xXDGAModeInfo info; + XDGAModePtr mode; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + REQUEST_SIZE_MATCH(xXDGAQueryModesReq); + rep.type = X_Reply; + rep.length = 0; + rep.number = 0; + rep.sequenceNumber = client->sequence; + + if (!DGAAvailable(stuff->screen)) { + rep.number = 0; + rep.length = 0; + WriteToClient(client, sz_xXDGAQueryModesReply, (char*)&rep); + return Success; + } + + if(!(num = DGAGetModes(stuff->screen))) { + WriteToClient(client, sz_xXDGAQueryModesReply, (char*)&rep); + return Success; + } + + if(!(mode = (XDGAModePtr)malloc(num * sizeof(XDGAModeRec)))) + return BadAlloc; + + for(i = 0; i < num; i++) + DGAGetModeInfo(stuff->screen, mode + i, i + 1); + + size = num * sz_xXDGAModeInfo; + for(i = 0; i < num; i++) + size += pad_to_int32(strlen(mode[i].name) + 1); /* plus NULL */ + + rep.number = num; + rep.length = bytes_to_int32(size); + + WriteToClient(client, sz_xXDGAQueryModesReply, (char*)&rep); + + for(i = 0; i < num; i++) { + size = strlen(mode[i].name) + 1; + + info.byte_order = mode[i].byteOrder; + info.depth = mode[i].depth; + info.num = mode[i].num; + info.bpp = mode[i].bitsPerPixel; + info.name_size = (size + 3) & ~3L; + info.vsync_num = mode[i].VSync_num; + info.vsync_den = mode[i].VSync_den; + info.flags = mode[i].flags; + info.image_width = mode[i].imageWidth; + info.image_height = mode[i].imageHeight; + info.pixmap_width = mode[i].pixmapWidth; + info.pixmap_height = mode[i].pixmapHeight; + info.bytes_per_scanline = mode[i].bytesPerScanline; + info.red_mask = mode[i].red_mask; + info.green_mask = mode[i].green_mask; + info.blue_mask = mode[i].blue_mask; + info.visual_class = mode[i].visualClass; + info.viewport_width = mode[i].viewportWidth; + info.viewport_height = mode[i].viewportHeight; + info.viewport_xstep = mode[i].xViewportStep; + info.viewport_ystep = mode[i].yViewportStep; + info.viewport_xmax = mode[i].maxViewportX; + info.viewport_ymax = mode[i].maxViewportY; + info.viewport_flags = mode[i].viewportFlags; + info.reserved1 = mode[i].reserved1; + info.reserved2 = mode[i].reserved2; + + WriteToClient(client, sz_xXDGAModeInfo, (char*)(&info)); + WriteToClient(client, size, mode[i].name); + } + + free(mode); + + return Success; +} + + +static void +DGAClientStateChange ( + CallbackListPtr* pcbl, + pointer nulldata, + pointer calldata +){ + NewClientInfoRec* pci = (NewClientInfoRec*) calldata; + ClientPtr client = NULL; + int i; + + for(i = 0; i < screenInfo.numScreens; i++) { + if(DGA_GETCLIENT(i) == pci->client) { + client = pci->client; + break; + } + } + + if(client && + ((client->clientState == ClientStateGone) || + (client->clientState == ClientStateRetained))) { + XDGAModeRec mode; + PixmapPtr pPix; + + DGA_SETCLIENT(i, NULL); + DGASelectInput(i, NULL, 0); + DGASetMode(i, 0, &mode, &pPix); + + if(--DGACallbackRefCount == 0) + DeleteCallback(&ClientStateCallback, DGAClientStateChange, NULL); + } +} + +static int +ProcXDGASetMode(ClientPtr client) +{ + REQUEST(xXDGASetModeReq); + xXDGASetModeReply rep; + XDGAModeRec mode; + xXDGAModeInfo info; + PixmapPtr pPix; + ClientPtr owner; + int size; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + owner = DGA_GETCLIENT(stuff->screen); + + REQUEST_SIZE_MATCH(xXDGASetModeReq); + rep.type = X_Reply; + rep.length = 0; + rep.offset = 0; + rep.flags = 0; + rep.sequenceNumber = client->sequence; + + if (!DGAAvailable(stuff->screen)) + return DGAErrorBase + XF86DGANoDirectVideoMode; + + if(owner && owner != client) + return DGAErrorBase + XF86DGANoDirectVideoMode; + + if(!stuff->mode) { + if(owner) { + if(--DGACallbackRefCount == 0) + DeleteCallback(&ClientStateCallback, DGAClientStateChange, NULL); + } + DGA_SETCLIENT(stuff->screen, NULL); + DGASelectInput(stuff->screen, NULL, 0); + DGASetMode(stuff->screen, 0, &mode, &pPix); + WriteToClient(client, sz_xXDGASetModeReply, (char*)&rep); + return Success; + } + + if(Success != DGASetMode(stuff->screen, stuff->mode, &mode, &pPix)) + return BadValue; + + if(!owner) { + if(DGACallbackRefCount++ == 0) + AddCallback (&ClientStateCallback, DGAClientStateChange, NULL); + } + + DGA_SETCLIENT(stuff->screen, client); + + if(pPix) { + if(AddResource(stuff->pid, RT_PIXMAP, (pointer)(pPix))) { + pPix->drawable.id = (int)stuff->pid; + rep.flags = DGA_PIXMAP_AVAILABLE; + } + } + + size = strlen(mode.name) + 1; + + info.byte_order = mode.byteOrder; + info.depth = mode.depth; + info.num = mode.num; + info.bpp = mode.bitsPerPixel; + info.name_size = (size + 3) & ~3L; + info.vsync_num = mode.VSync_num; + info.vsync_den = mode.VSync_den; + info.flags = mode.flags; + info.image_width = mode.imageWidth; + info.image_height = mode.imageHeight; + info.pixmap_width = mode.pixmapWidth; + info.pixmap_height = mode.pixmapHeight; + info.bytes_per_scanline = mode.bytesPerScanline; + info.red_mask = mode.red_mask; + info.green_mask = mode.green_mask; + info.blue_mask = mode.blue_mask; + info.visual_class = mode.visualClass; + info.viewport_width = mode.viewportWidth; + info.viewport_height = mode.viewportHeight; + info.viewport_xstep = mode.xViewportStep; + info.viewport_ystep = mode.yViewportStep; + info.viewport_xmax = mode.maxViewportX; + info.viewport_ymax = mode.maxViewportY; + info.viewport_flags = mode.viewportFlags; + info.reserved1 = mode.reserved1; + info.reserved2 = mode.reserved2; + + rep.length = bytes_to_int32(sz_xXDGAModeInfo + info.name_size); + + WriteToClient(client, sz_xXDGASetModeReply, (char*)&rep); + WriteToClient(client, sz_xXDGAModeInfo, (char*)(&info)); + WriteToClient(client, size, mode.name); + + return Success; +} + +static int +ProcXDGASetViewport(ClientPtr client) +{ + REQUEST(xXDGASetViewportReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGASetViewportReq); + + DGASetViewport(stuff->screen, stuff->x, stuff->y, stuff->flags); + + return Success; +} + +static int +ProcXDGAInstallColormap(ClientPtr client) +{ + ColormapPtr cmap; + int rc; + REQUEST(xXDGAInstallColormapReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGAInstallColormapReq); + + rc = dixLookupResourceByType((pointer *)&cmap, stuff->cmap, RT_COLORMAP, + client, DixInstallAccess); + if (rc != Success) + return (rc == BadValue) ? BadColor : rc; + DGAInstallCmap(cmap); + return Success; +} + + +static int +ProcXDGASelectInput(ClientPtr client) +{ + REQUEST(xXDGASelectInputReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGASelectInputReq); + + if(DGA_GETCLIENT(stuff->screen) == client) + DGASelectInput(stuff->screen, client, stuff->mask); + + return Success; +} + + +static int +ProcXDGAFillRectangle(ClientPtr client) +{ + REQUEST(xXDGAFillRectangleReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGAFillRectangleReq); + + if(Success != DGAFillRect(stuff->screen, stuff->x, stuff->y, + stuff->width, stuff->height, stuff->color)) + return BadMatch; + + return Success; +} + +static int +ProcXDGACopyArea(ClientPtr client) +{ + REQUEST(xXDGACopyAreaReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGACopyAreaReq); + + if(Success != DGABlitRect(stuff->screen, stuff->srcx, stuff->srcy, + stuff->width, stuff->height, stuff->dstx, stuff->dsty)) + return BadMatch; + + return Success; +} + + +static int +ProcXDGACopyTransparentArea(ClientPtr client) +{ + REQUEST(xXDGACopyTransparentAreaReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGACopyTransparentAreaReq); + + if(Success != DGABlitTransRect(stuff->screen, stuff->srcx, stuff->srcy, + stuff->width, stuff->height, stuff->dstx, stuff->dsty, stuff->key)) + return BadMatch; + + return Success; +} + + +static int +ProcXDGAGetViewportStatus(ClientPtr client) +{ + REQUEST(xXDGAGetViewportStatusReq); + xXDGAGetViewportStatusReply rep; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGAGetViewportStatusReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rep.status = DGAGetViewportStatus(stuff->screen); + + WriteToClient(client, sizeof(xXDGAGetViewportStatusReply), (char *)&rep); + return Success; +} + +static int +ProcXDGASync(ClientPtr client) +{ + REQUEST(xXDGASyncReq); + xXDGASyncReply rep; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGASyncReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + DGASync(stuff->screen); + + WriteToClient(client, sizeof(xXDGASyncReply), (char *)&rep); + return Success; +} + +static int +ProcXDGASetClientVersion(ClientPtr client) +{ + REQUEST(xXDGASetClientVersionReq); + + DGAPrivPtr pPriv; + + REQUEST_SIZE_MATCH(xXDGASetClientVersionReq); + if ((pPriv = DGA_GETPRIV(client)) == NULL) { + pPriv = malloc(sizeof(DGAPrivRec)); + /* XXX Need to look into freeing this */ + if (!pPriv) + return BadAlloc; + DGA_SETPRIV(client, pPriv); + } + pPriv->major = stuff->major; + pPriv->minor = stuff->minor; + + return Success; +} + +static int +ProcXDGAChangePixmapMode(ClientPtr client) +{ + REQUEST(xXDGAChangePixmapModeReq); + xXDGAChangePixmapModeReply rep; + int x, y; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGAChangePixmapModeReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + x = stuff->x; + y = stuff->y; + + if(!DGAChangePixmapMode(stuff->screen, &x, &y, stuff->flags)) + return BadMatch; + + rep.x = x; + rep.y = y; + WriteToClient(client, sizeof(xXDGAChangePixmapModeReply), (char *)&rep); + + return Success; +} + + +static int +ProcXDGACreateColormap(ClientPtr client) +{ + REQUEST(xXDGACreateColormapReq); + int result; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if(DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXDGACreateColormapReq); + + if(!stuff->mode) + return BadValue; + + result = DGACreateColormap(stuff->screen, client, stuff->id, + stuff->mode, stuff->alloc); + if(result != Success) + return result; + + return Success; +} + +/* + * + * Support for the old DGA protocol, used to live in xf86dga.c + * + */ + +#ifdef DGA_PROTOCOL_OLD_SUPPORT + +static DISPATCH_PROC(ProcXF86DGADirectVideo); +static DISPATCH_PROC(ProcXF86DGAGetVidPage); +static DISPATCH_PROC(ProcXF86DGAGetVideoLL); +static DISPATCH_PROC(ProcXF86DGAGetViewPortSize); +static DISPATCH_PROC(ProcXF86DGASetVidPage); +static DISPATCH_PROC(ProcXF86DGASetViewPort); +static DISPATCH_PROC(ProcXF86DGAInstallColormap); +static DISPATCH_PROC(ProcXF86DGAQueryDirectVideo); +static DISPATCH_PROC(ProcXF86DGAViewPortChanged); + + +static int +ProcXF86DGAGetVideoLL(ClientPtr client) +{ + REQUEST(xXF86DGAGetVideoLLReq); + xXF86DGAGetVideoLLReply rep; + XDGAModeRec mode; + int num, offset, flags; + char *name; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + REQUEST_SIZE_MATCH(xXF86DGAGetVideoLLReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if(!DGAAvailable(stuff->screen)) + return (DGAErrorBase + XF86DGANoDirectVideoMode); + + if(!(num = DGAGetOldDGAMode(stuff->screen))) + return (DGAErrorBase + XF86DGANoDirectVideoMode); + + /* get the parameters for the mode that best matches */ + DGAGetModeInfo(stuff->screen, &mode, num); + + if(!DGAOpenFramebuffer(stuff->screen, &name, + (unsigned char**)(&rep.offset), + (int*)(&rep.bank_size), &offset, &flags)) + return BadAlloc; + + rep.offset += mode.offset; + rep.width = mode.bytesPerScanline / (mode.bitsPerPixel >> 3); + rep.ram_size = rep.bank_size >> 10; + + WriteToClient(client, SIZEOF(xXF86DGAGetVideoLLReply), (char *)&rep); + return Success; +} + +static int +ProcXF86DGADirectVideo(ClientPtr client) +{ + int num; + PixmapPtr pix; + XDGAModeRec mode; + ClientPtr owner; + REQUEST(xXF86DGADirectVideoReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + owner = DGA_GETCLIENT(stuff->screen); + + REQUEST_SIZE_MATCH(xXF86DGADirectVideoReq); + + if (!DGAAvailable(stuff->screen)) + return DGAErrorBase + XF86DGANoDirectVideoMode; + + if (owner && owner != client) + return DGAErrorBase + XF86DGANoDirectVideoMode; + + if (stuff->enable & XF86DGADirectGraphics) { + if(!(num = DGAGetOldDGAMode(stuff->screen))) + return (DGAErrorBase + XF86DGANoDirectVideoMode); + } else + num = 0; + + if(Success != DGASetMode(stuff->screen, num, &mode, &pix)) + return (DGAErrorBase + XF86DGAScreenNotActive); + + DGASetInputMode (stuff->screen, + (stuff->enable & XF86DGADirectKeyb) != 0, + (stuff->enable & XF86DGADirectMouse) != 0); + + /* We need to track the client and attach the teardown callback */ + if (stuff->enable & + (XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse)) { + if (!owner) { + if (DGACallbackRefCount++ == 0) + AddCallback (&ClientStateCallback, DGAClientStateChange, NULL); + } + + DGA_SETCLIENT(stuff->screen, client); + } else { + if (owner) { + if (--DGACallbackRefCount == 0) + DeleteCallback(&ClientStateCallback, DGAClientStateChange, NULL); + } + + DGA_SETCLIENT(stuff->screen, NULL); + } + + return Success; +} + +static int +ProcXF86DGAGetViewPortSize(ClientPtr client) +{ + int num; + XDGAModeRec mode; + REQUEST(xXF86DGAGetViewPortSizeReq); + xXF86DGAGetViewPortSizeReply rep; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + REQUEST_SIZE_MATCH(xXF86DGAGetViewPortSizeReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!DGAAvailable(stuff->screen)) + return (DGAErrorBase + XF86DGANoDirectVideoMode); + + if(!(num = DGAGetOldDGAMode(stuff->screen))) + return (DGAErrorBase + XF86DGANoDirectVideoMode); + + DGAGetModeInfo(stuff->screen, &mode, num); + + rep.width = mode.viewportWidth; + rep.height = mode.viewportHeight; + + WriteToClient(client, SIZEOF(xXF86DGAGetViewPortSizeReply), (char *)&rep); + return Success; +} + +static int +ProcXF86DGASetViewPort(ClientPtr client) +{ + REQUEST(xXF86DGASetViewPortReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if (DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXF86DGASetViewPortReq); + + if (!DGAAvailable(stuff->screen)) + return (DGAErrorBase + XF86DGANoDirectVideoMode); + + if (!DGAActive(stuff->screen)) + return DGAErrorBase + XF86DGADirectNotActivated; + + if (DGASetViewport(stuff->screen, stuff->x, stuff->y, DGA_FLIP_RETRACE) + != Success) + return DGAErrorBase + XF86DGADirectNotActivated; + + return Success; +} + +static int +ProcXF86DGAGetVidPage(ClientPtr client) +{ + REQUEST(xXF86DGAGetVidPageReq); + xXF86DGAGetVidPageReply rep; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + REQUEST_SIZE_MATCH(xXF86DGAGetVidPageReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.vpage = 0; /* silently fail */ + + WriteToClient(client, SIZEOF(xXF86DGAGetVidPageReply), (char *)&rep); + return Success; +} + + +static int +ProcXF86DGASetVidPage(ClientPtr client) +{ + REQUEST(xXF86DGASetVidPageReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + REQUEST_SIZE_MATCH(xXF86DGASetVidPageReq); + + /* silently fail */ + + return Success; +} + + +static int +ProcXF86DGAInstallColormap(ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xXF86DGAInstallColormapReq); + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if (DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXF86DGAInstallColormapReq); + + if (!DGAActive(stuff->screen)) + return (DGAErrorBase + XF86DGADirectNotActivated); + + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->id, RT_COLORMAP, + client, DixInstallAccess); + if (rc == Success) { + DGAInstallCmap(pcmp); + return Success; + } else { + return (rc == BadValue) ? BadColor : rc; + } +} + +static int +ProcXF86DGAQueryDirectVideo(ClientPtr client) +{ + REQUEST(xXF86DGAQueryDirectVideoReq); + xXF86DGAQueryDirectVideoReply rep; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + REQUEST_SIZE_MATCH(xXF86DGAQueryDirectVideoReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.flags = 0; + + if (DGAAvailable(stuff->screen)) + rep.flags = XF86DGADirectPresent; + + WriteToClient(client, SIZEOF(xXF86DGAQueryDirectVideoReply), (char *)&rep); + return Success; +} + +static int +ProcXF86DGAViewPortChanged(ClientPtr client) +{ + REQUEST(xXF86DGAViewPortChangedReq); + xXF86DGAViewPortChangedReply rep; + + if (stuff->screen > screenInfo.numScreens) + return BadValue; + + if (DGA_GETCLIENT(stuff->screen) != client) + return DGAErrorBase + XF86DGADirectNotActivated; + + REQUEST_SIZE_MATCH(xXF86DGAViewPortChangedReq); + + if (!DGAActive(stuff->screen)) + return (DGAErrorBase + XF86DGADirectNotActivated); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.result = 1; + + WriteToClient(client, SIZEOF(xXF86DGAViewPortChangedReply), (char *)&rep); + return Success; +} + +#endif /* DGA_PROTOCOL_OLD_SUPPORT */ + +static int +SProcXDGADispatch (ClientPtr client) +{ + return DGAErrorBase + XF86DGAClientNotLocal; +} + +#if 0 +#define DGA_REQ_DEBUG +#endif + +#ifdef DGA_REQ_DEBUG +static char *dgaMinor[] = { + "QueryVersion", + "GetVideoLL", + "DirectVideo", + "GetViewPortSize", + "SetViewPort", + "GetVidPage", + "SetVidPage", + "InstallColormap", + "QueryDirectVideo", + "ViewPortChanged", + "10", + "11", + "QueryModes", + "SetMode", + "SetViewport", + "InstallColormap", + "SelectInput", + "FillRectangle", + "CopyArea", + "CopyTransparentArea", + "GetViewportStatus", + "Sync", + "OpenFramebuffer", + "CloseFramebuffer", + "SetClientVersion", + "ChangePixmapMode", + "CreateColormap", +}; +#endif + +static int +ProcXDGADispatch (ClientPtr client) +{ + REQUEST(xReq); + + if (!LocalClient(client)) + return DGAErrorBase + XF86DGAClientNotLocal; + +#ifdef DGA_REQ_DEBUG + if (stuff->data <= X_XDGACreateColormap) + fprintf (stderr, " DGA %s\n", dgaMinor[stuff->data]); +#endif + + switch (stuff->data){ + /* + * DGA2 Protocol + */ + case X_XDGAQueryVersion: + return ProcXDGAQueryVersion(client); + case X_XDGAQueryModes: + return ProcXDGAQueryModes(client); + case X_XDGASetMode: + return ProcXDGASetMode(client); + case X_XDGAOpenFramebuffer: + return ProcXDGAOpenFramebuffer(client); + case X_XDGACloseFramebuffer: + return ProcXDGACloseFramebuffer(client); + case X_XDGASetViewport: + return ProcXDGASetViewport(client); + case X_XDGAInstallColormap: + return ProcXDGAInstallColormap(client); + case X_XDGASelectInput: + return ProcXDGASelectInput(client); + case X_XDGAFillRectangle: + return ProcXDGAFillRectangle(client); + case X_XDGACopyArea: + return ProcXDGACopyArea(client); + case X_XDGACopyTransparentArea: + return ProcXDGACopyTransparentArea(client); + case X_XDGAGetViewportStatus: + return ProcXDGAGetViewportStatus(client); + case X_XDGASync: + return ProcXDGASync(client); + case X_XDGASetClientVersion: + return ProcXDGASetClientVersion(client); + case X_XDGAChangePixmapMode: + return ProcXDGAChangePixmapMode(client); + case X_XDGACreateColormap: + return ProcXDGACreateColormap(client); + /* + * Old DGA Protocol + */ +#ifdef DGA_PROTOCOL_OLD_SUPPORT + case X_XF86DGAGetVideoLL: + return ProcXF86DGAGetVideoLL(client); + case X_XF86DGADirectVideo: + return ProcXF86DGADirectVideo(client); + case X_XF86DGAGetViewPortSize: + return ProcXF86DGAGetViewPortSize(client); + case X_XF86DGASetViewPort: + return ProcXF86DGASetViewPort(client); + case X_XF86DGAGetVidPage: + return ProcXF86DGAGetVidPage(client); + case X_XF86DGASetVidPage: + return ProcXF86DGASetVidPage(client); + case X_XF86DGAInstallColormap: + return ProcXF86DGAInstallColormap(client); + case X_XF86DGAQueryDirectVideo: + return ProcXF86DGAQueryDirectVideo(client); + case X_XF86DGAViewPortChanged: + return ProcXF86DGAViewPortChanged(client); +#endif /* DGA_PROTOCOL_OLD_SUPPORT */ + default: + return BadRequest; + } +} + +void +XFree86DGARegister(INITARGS) +{ + XDGAEventBase = &DGAEventBase; +} diff --git a/xorg-server/hw/xfree86/dixmods/extmod/xf86vmode.c b/xorg-server/hw/xfree86/dixmods/extmod/xf86vmode.c index a304a42d4..483b92ab1 100644 --- a/xorg-server/hw/xfree86/dixmods/extmod/xf86vmode.c +++ b/xorg-server/hw/xfree86/dixmods/extmod/xf86vmode.c @@ -1,2170 +1,2170 @@ - -/* - -Copyright 1995 Kaleb S. KEITHLEY - -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 Kaleb S. KEITHLEY 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 Kaleb S. KEITHLEY -shall not be used in advertising or otherwise to promote the sale, use -or other dealings in this Software without prior written authorization -from Kaleb S. KEITHLEY - -*/ -/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "scrnintstr.h" -#include "servermd.h" -#include <X11/extensions/xf86vmproto.h> -#include "swaprep.h" -#include "xf86.h" -#include "vidmodeproc.h" -#include "globals.h" -#include "protocol-versions.h" - -#define DEFAULT_XF86VIDMODE_VERBOSITY 3 - -static int VidModeErrorBase; -static int VidModeClientPrivateKeyIndex; -static DevPrivateKey VidModeClientPrivateKey = &VidModeClientPrivateKeyIndex; - -/* This holds the client's version information */ -typedef struct { - int major; - int minor; -} VidModePrivRec, *VidModePrivPtr; - -#define VM_GETPRIV(c) ((VidModePrivPtr) \ - dixLookupPrivate(&(c)->devPrivates, VidModeClientPrivateKey)) -#define VM_SETPRIV(c,p) \ - dixSetPrivate(&(c)->devPrivates, VidModeClientPrivateKey, p) - -static DISPATCH_PROC(ProcXF86VidModeDispatch); -static DISPATCH_PROC(ProcXF86VidModeGetAllModeLines); -static DISPATCH_PROC(ProcXF86VidModeGetModeLine); -static DISPATCH_PROC(ProcXF86VidModeGetMonitor); -static DISPATCH_PROC(ProcXF86VidModeLockModeSwitch); -static DISPATCH_PROC(ProcXF86VidModeAddModeLine); -static DISPATCH_PROC(ProcXF86VidModeDeleteModeLine); -static DISPATCH_PROC(ProcXF86VidModeModModeLine); -static DISPATCH_PROC(ProcXF86VidModeValidateModeLine); -static DISPATCH_PROC(ProcXF86VidModeQueryVersion); -static DISPATCH_PROC(ProcXF86VidModeSwitchMode); -static DISPATCH_PROC(ProcXF86VidModeSwitchToMode); -static DISPATCH_PROC(ProcXF86VidModeGetViewPort); -static DISPATCH_PROC(ProcXF86VidModeSetViewPort); -static DISPATCH_PROC(ProcXF86VidModeGetDotClocks); -static DISPATCH_PROC(ProcXF86VidModeSetGamma); -static DISPATCH_PROC(ProcXF86VidModeGetGamma); -static DISPATCH_PROC(ProcXF86VidModeSetClientVersion); -static DISPATCH_PROC(ProcXF86VidModeGetGammaRamp); -static DISPATCH_PROC(ProcXF86VidModeSetGammaRamp); -static DISPATCH_PROC(ProcXF86VidModeGetGammaRampSize); -static DISPATCH_PROC(SProcXF86VidModeDispatch); -static DISPATCH_PROC(SProcXF86VidModeGetAllModeLines); -static DISPATCH_PROC(SProcXF86VidModeGetModeLine); -static DISPATCH_PROC(SProcXF86VidModeGetMonitor); -static DISPATCH_PROC(SProcXF86VidModeLockModeSwitch); -static DISPATCH_PROC(SProcXF86VidModeAddModeLine); -static DISPATCH_PROC(SProcXF86VidModeDeleteModeLine); -static DISPATCH_PROC(SProcXF86VidModeModModeLine); -static DISPATCH_PROC(SProcXF86VidModeValidateModeLine); -static DISPATCH_PROC(SProcXF86VidModeQueryVersion); -static DISPATCH_PROC(SProcXF86VidModeSwitchMode); -static DISPATCH_PROC(SProcXF86VidModeSwitchToMode); -static DISPATCH_PROC(SProcXF86VidModeGetViewPort); -static DISPATCH_PROC(SProcXF86VidModeSetViewPort); -static DISPATCH_PROC(SProcXF86VidModeGetDotClocks); -static DISPATCH_PROC(SProcXF86VidModeSetGamma); -static DISPATCH_PROC(SProcXF86VidModeGetGamma); -static DISPATCH_PROC(SProcXF86VidModeSetClientVersion); -static DISPATCH_PROC(SProcXF86VidModeGetGammaRamp); -static DISPATCH_PROC(SProcXF86VidModeSetGammaRamp); -static DISPATCH_PROC(SProcXF86VidModeGetGammaRampSize); - -#if 0 -static unsigned char XF86VidModeReqCode = 0; -#endif - -/* The XF86VIDMODE_EVENTS code is far from complete */ - -#ifdef XF86VIDMODE_EVENTS -static int XF86VidModeEventBase = 0; - -static void SXF86VidModeNotifyEvent(); - xXF86VidModeNotifyEvent * /* from */, - xXF86VidModeNotifyEvent * /* to */ -); - -static RESTYPE EventType; /* resource type for event masks */ - -typedef struct _XF86VidModeEvent *XF86VidModeEventPtr; - -typedef struct _XF86VidModeEvent { - XF86VidModeEventPtr next; - ClientPtr client; - ScreenPtr screen; - XID resource; - CARD32 mask; -} XF86VidModeEventRec; - -static int XF86VidModeFreeEvents(); - -typedef struct _XF86VidModeScreenPrivate { - XF86VidModeEventPtr events; - Bool hasWindow; -} XF86VidModeScreenPrivateRec, *XF86VidModeScreenPrivatePtr; - -static int ScreenPrivateKeyIndex; -static DevPrivateKey ScreenPrivateKey = &ScreenPrivateKeyIndex; - -#define GetScreenPrivate(s) ((ScreenSaverScreenPrivatePtr) \ - dixLookupPrivate(&(s)->devPrivates, ScreenPrivateKey)) -#define SetScreenPrivate(s,v) \ - dixSetPrivate(&(s)->devPrivates, ScreenPrivateKey, v) -#define SetupScreen(s) ScreenSaverScreenPrivatePtr pPriv = GetScreenPrivate(s) - -#define New(t) (xalloc (sizeof (t))) -#endif - -#ifdef DEBUG -# define DEBUG_P(x) ErrorF(x"\n"); -#else -# define DEBUG_P(x) /**/ -#endif - -void -XFree86VidModeExtensionInit(void) -{ - ExtensionEntry* extEntry; - ScreenPtr pScreen; - int i; - Bool enabled = FALSE; - - DEBUG_P("XFree86VidModeExtensionInit"); - -#ifdef XF86VIDMODE_EVENTS - EventType = CreateNewResourceType(XF86VidModeFreeEvents, "VidModeEvent"); -#endif - - for(i = 0; i < screenInfo.numScreens; i++) { - pScreen = screenInfo.screens[i]; - if (VidModeExtensionInit(pScreen)) - enabled = TRUE; -#ifdef XF86VIDMODE_EVENTS - SetScreenPrivate (pScreen, NULL); -#endif - } - /* This means that the DDX doesn't want the vidmode extension enabled */ - if (!enabled) - return; - - if ( -#ifdef XF86VIDMODE_EVENTS - EventType && -#endif - (extEntry = AddExtension(XF86VIDMODENAME, - XF86VidModeNumberEvents, - XF86VidModeNumberErrors, - ProcXF86VidModeDispatch, - SProcXF86VidModeDispatch, - NULL, - StandardMinorOpcode))) { -#if 0 - XF86VidModeReqCode = (unsigned char)extEntry->base; -#endif - VidModeErrorBase = extEntry->errorBase; -#ifdef XF86VIDMODE_EVENTS - XF86VidModeEventBase = extEntry->eventBase; - EventSwapVector[XF86VidModeEventBase] = (EventSwapPtr)SXF86VidModeNotifyEvent; -#endif - } -} - -static int -ClientMajorVersion(ClientPtr client) -{ - VidModePrivPtr pPriv; - - pPriv = VM_GETPRIV(client); - if (!pPriv) - return 0; - else - return pPriv->major; -} - -#ifdef XF86VIDMODE_EVENTS -static void -CheckScreenPrivate (pScreen) - ScreenPtr pScreen; -{ - SetupScreen (pScreen); - - if (!pPriv) - return; - if (!pPriv->events && !pPriv->hasWindow) { - xfree (pPriv); - SetScreenPrivate (pScreen, NULL); - } -} - -static XF86VidModeScreenPrivatePtr -MakeScreenPrivate (pScreen) - ScreenPtr pScreen; -{ - SetupScreen (pScreen); - - if (pPriv) - return pPriv; - pPriv = New (XF86VidModeScreenPrivateRec); - if (!pPriv) - return 0; - pPriv->events = 0; - pPriv->hasWindow = FALSE; - SetScreenPrivate (pScreen, pPriv); - return pPriv; -} - -static unsigned long -getEventMask (ScreenPtr pScreen, ClientPtr client) -{ - SetupScreen(pScreen); - XF86VidModeEventPtr 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 (ScreenPtr pScreen, ClientPtr client, unsigned long mask) -{ - SetupScreen(pScreen); - XF86VidModeEventPtr pEv, *pPrev; - - if (getEventMask (pScreen, client) == mask) - return TRUE; - if (!pPriv) { - pPriv = MakeScreenPrivate (pScreen); - if (!pPriv) - return FALSE; - } - for (pPrev = &pPriv->events; pEv = *pPrev; pPrev = &pEv->next) - if (pEv->client == client) - break; - if (mask == 0) { - *pPrev = pEv->next; - xfree (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); - } - pEv->mask = mask; - } - return TRUE; -} - -static int -XF86VidModeFreeEvents(pointer value, XID id) -{ - XF86VidModeEventPtr pOld = (XF86VidModeEventPtr)value; - ScreenPtr pScreen = pOld->screen; - SetupScreen (pScreen); - XF86VidModeEventPtr pEv, *pPrev; - - if (!pPriv) - return TRUE; - for (pPrev = &pPriv->events; pEv = *pPrev; pPrev = &pEv->next) - if (pEv == pOld) - break; - if (!pEv) - return TRUE; - *pPrev = pEv->next; - xfree (pEv); - CheckScreenPrivate (pScreen); - return TRUE; -} - -static void -SendXF86VidModeNotify(ScreenPtr pScreen, int state, Bool forced) -{ - XF86VidModeScreenPrivatePtr pPriv; - XF86VidModeEventPtr pEv; - unsigned long mask; - xXF86VidModeNotifyEvent ev; - ClientPtr client; - int kind; - - UpdateCurrentTimeIf (); - mask = XF86VidModeNotifyMask; - pScreen = screenInfo.screens[pScreen->myNum]; - pPriv = GetScreenPrivate(pScreen); - if (!pPriv) - return; - kind = XF86VidModeModeChange; - for (pEv = pPriv->events; pEv; pEv = pEv->next) - { - client = pEv->client; - if (client->clientGone) - continue; - if (!(pEv->mask & mask)) - continue; - ev.type = XF86VidModeNotify + XF86VidModeEventBase; - ev.state = state; - ev.sequenceNumber = client->sequence; - ev.timestamp = currentTime.milliseconds; - ev.root = WindowTable[pScreen->myNum]->drawable.id; - ev.kind = kind; - ev.forced = forced; - WriteEventsToClient (client, 1, (xEvent *) &ev); - } -} - -static void -SXF86VidModeNotifyEvent(xXF86VidModeNotifyEvent *from, - xXF86VidModeNotifyEvent *to) -{ - to->type = from->type; - to->state = from->state; - cpswaps (from->sequenceNumber, to->sequenceNumber); - cpswapl (from->timestamp, to->timestamp); - cpswapl (from->root, to->root); - to->kind = from->kind; - to->forced = from->forced; -} -#endif - -static int -ProcXF86VidModeQueryVersion(ClientPtr client) -{ - xXF86VidModeQueryVersionReply rep; - register int n; - - DEBUG_P("XF86VidModeQueryVersion"); - - REQUEST_SIZE_MATCH(xXF86VidModeQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_XF86VIDMODE_MAJOR_VERSION; - rep.minorVersion = SERVER_XF86VIDMODE_MINOR_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xXF86VidModeQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86VidModeGetModeLine(ClientPtr client) -{ - REQUEST(xXF86VidModeGetModeLineReq); - xXF86VidModeGetModeLineReply rep; - xXF86OldVidModeGetModeLineReply oldrep; - pointer mode; - register int n; - int dotClock; - int ver; - - DEBUG_P("XF86VidModeGetModeline"); - - ver = ClientMajorVersion(client); - REQUEST_SIZE_MATCH(xXF86VidModeGetModeLineReq); - rep.type = X_Reply; - if (ver < 2) { - rep.length = bytes_to_int32(SIZEOF(xXF86OldVidModeGetModeLineReply) - - SIZEOF(xGenericReply)); - } else { - rep.length = bytes_to_int32(SIZEOF(xXF86VidModeGetModeLineReply) - - SIZEOF(xGenericReply)); - } - rep.sequenceNumber = client->sequence; - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) - return BadValue; - - rep.dotclock = dotClock; - rep.hdisplay = VidModeGetModeValue(mode, VIDMODE_H_DISPLAY); - rep.hsyncstart = VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART); - rep.hsyncend = VidModeGetModeValue(mode, VIDMODE_H_SYNCEND); - rep.htotal = VidModeGetModeValue(mode, VIDMODE_H_TOTAL); - rep.hskew = VidModeGetModeValue(mode, VIDMODE_H_SKEW); - rep.vdisplay = VidModeGetModeValue(mode, VIDMODE_V_DISPLAY); - rep.vsyncstart = VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART); - rep.vsyncend = VidModeGetModeValue(mode, VIDMODE_V_SYNCEND); - rep.vtotal = VidModeGetModeValue(mode, VIDMODE_V_TOTAL); - rep.flags = VidModeGetModeValue(mode, VIDMODE_FLAGS); - - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("GetModeLine - scrn: %d clock: %ld\n", - stuff->screen, (unsigned long)rep.dotclock); - ErrorF("GetModeLine - hdsp: %d hbeg: %d hend: %d httl: %d\n", - rep.hdisplay, rep.hsyncstart, - rep.hsyncend, rep.htotal); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", - rep.vdisplay, rep.vsyncstart, rep.vsyncend, - rep.vtotal, (unsigned long)rep.flags); - } - - /* - * Older servers sometimes had server privates that the VidMode - * extention made available. So to be compatiable pretend that - * there are no server privates to pass to the client - */ - rep.privsize = 0; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.dotclock, n); - swaps(&rep.hdisplay, n); - swaps(&rep.hsyncstart, n); - swaps(&rep.hsyncend, n); - swaps(&rep.htotal, n); - swaps(&rep.hskew, n); - swaps(&rep.vdisplay, n); - swaps(&rep.vsyncstart, n); - swaps(&rep.vsyncend, n); - swaps(&rep.vtotal, n); - swapl(&rep.flags, n); - swapl(&rep.privsize, n); - } - if (ver < 2) { - oldrep.type = rep.type; - oldrep.sequenceNumber = rep.sequenceNumber; - oldrep.length = rep.length; - oldrep.dotclock = rep.dotclock; - oldrep.hdisplay = rep.hdisplay; - oldrep.hsyncstart = rep.hsyncstart; - oldrep.hsyncend = rep.hsyncend; - oldrep.htotal = rep.htotal; - oldrep.vdisplay = rep.vdisplay; - oldrep.vsyncstart = rep.vsyncstart; - oldrep.vsyncend = rep.vsyncend; - oldrep.vtotal = rep.vtotal; - oldrep.flags = rep.flags; - oldrep.privsize = rep.privsize; - WriteToClient(client, sizeof(xXF86OldVidModeGetModeLineReply), - (char *)&oldrep); - } else { - WriteToClient(client, sizeof(xXF86VidModeGetModeLineReply), - (char *)&rep); - } - return (client->noClientException); -} - -static int -ProcXF86VidModeGetAllModeLines(ClientPtr client) -{ - REQUEST(xXF86VidModeGetAllModeLinesReq); - xXF86VidModeGetAllModeLinesReply rep; - xXF86VidModeModeInfo mdinf; - xXF86OldVidModeModeInfo oldmdinf; - pointer mode; - int modecount, dotClock; - register int n; - int ver; - - DEBUG_P("XF86VidModeGetAllModelines"); - - REQUEST_SIZE_MATCH(xXF86VidModeGetAllModeLinesReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - ver = ClientMajorVersion(client); - - modecount = VidModeGetNumOfModes(stuff->screen); - if (modecount < 1) - return (VidModeErrorBase + XF86VidModeExtensionDisabled); - - if (!VidModeGetFirstModeline(stuff->screen, &mode, &dotClock)) - return BadValue; - - rep.type = X_Reply; - rep.length = SIZEOF(xXF86VidModeGetAllModeLinesReply) - - SIZEOF(xGenericReply); - if (ver < 2) - rep.length += modecount * sizeof(xXF86OldVidModeModeInfo); - else - rep.length += modecount * sizeof(xXF86VidModeModeInfo); - rep.length >>= 2; - rep.sequenceNumber = client->sequence; - rep.modecount = modecount; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.modecount, n); - } - WriteToClient(client, sizeof(xXF86VidModeGetAllModeLinesReply), (char *)&rep); - - do { - mdinf.dotclock = dotClock; - mdinf.hdisplay = VidModeGetModeValue(mode, VIDMODE_H_DISPLAY); - mdinf.hsyncstart = VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART); - mdinf.hsyncend = VidModeGetModeValue(mode, VIDMODE_H_SYNCEND); - mdinf.htotal = VidModeGetModeValue(mode, VIDMODE_H_TOTAL); - mdinf.hskew = VidModeGetModeValue(mode, VIDMODE_H_SKEW); - mdinf.vdisplay = VidModeGetModeValue(mode, VIDMODE_V_DISPLAY); - mdinf.vsyncstart = VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART); - mdinf.vsyncend = VidModeGetModeValue(mode, VIDMODE_V_SYNCEND); - mdinf.vtotal = VidModeGetModeValue(mode, VIDMODE_V_TOTAL); - mdinf.flags = VidModeGetModeValue(mode, VIDMODE_FLAGS); - mdinf.privsize = 0; - if (client->swapped) { - swapl(&mdinf.dotclock, n); - swaps(&mdinf.hdisplay, n); - swaps(&mdinf.hsyncstart, n); - swaps(&mdinf.hsyncend, n); - swaps(&mdinf.htotal, n); - swaps(&mdinf.hskew, n); - swaps(&mdinf.vdisplay, n); - swaps(&mdinf.vsyncstart, n); - swaps(&mdinf.vsyncend, n); - swaps(&mdinf.vtotal, n); - swapl(&mdinf.flags, n); - swapl(&mdinf.privsize, n); - } - if (ver < 2) { - oldmdinf.dotclock = mdinf.dotclock; - oldmdinf.hdisplay = mdinf.hdisplay; - oldmdinf.hsyncstart = mdinf.hsyncstart; - oldmdinf.hsyncend = mdinf.hsyncend; - oldmdinf.htotal = mdinf.htotal; - oldmdinf.vdisplay = mdinf.vdisplay; - oldmdinf.vsyncstart = mdinf.vsyncstart; - oldmdinf.vsyncend = mdinf.vsyncend; - oldmdinf.vtotal = mdinf.vtotal; - oldmdinf.flags = mdinf.flags; - oldmdinf.privsize = mdinf.privsize; - WriteToClient(client, sizeof(xXF86OldVidModeModeInfo), - (char *)&oldmdinf); - } else { - WriteToClient(client, sizeof(xXF86VidModeModeInfo), (char *)&mdinf); - } - - } while (VidModeGetNextModeline(stuff->screen, &mode, &dotClock)); - - return (client->noClientException); -} - -#define MODEMATCH(mode,stuff) \ - (VidModeGetModeValue(mode, VIDMODE_H_DISPLAY) == stuff->hdisplay \ - && VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART) == stuff->hsyncstart \ - && VidModeGetModeValue(mode, VIDMODE_H_SYNCEND) == stuff->hsyncend \ - && VidModeGetModeValue(mode, VIDMODE_H_TOTAL) == stuff->htotal \ - && VidModeGetModeValue(mode, VIDMODE_V_DISPLAY) == stuff->vdisplay \ - && VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART) == stuff->vsyncstart \ - && VidModeGetModeValue(mode, VIDMODE_V_SYNCEND) == stuff->vsyncend \ - && VidModeGetModeValue(mode, VIDMODE_V_TOTAL) == stuff->vtotal \ - && VidModeGetModeValue(mode, VIDMODE_FLAGS) == stuff->flags ) - -static int -ProcXF86VidModeAddModeLine(ClientPtr client) -{ - REQUEST(xXF86VidModeAddModeLineReq); - xXF86OldVidModeAddModeLineReq *oldstuff = - (xXF86OldVidModeAddModeLineReq *)client->requestBuffer; - xXF86VidModeAddModeLineReq newstuff; - pointer mode; - int len; - int dotClock; - int ver; - - DEBUG_P("XF86VidModeAddModeline"); - - ver = ClientMajorVersion(client); - if (ver < 2) { - /* convert from old format */ - stuff = &newstuff; - stuff->length = oldstuff->length; - stuff->screen = oldstuff->screen; - stuff->dotclock = oldstuff->dotclock; - stuff->hdisplay = oldstuff->hdisplay; - stuff->hsyncstart = oldstuff->hsyncstart; - stuff->hsyncend = oldstuff->hsyncend; - stuff->htotal = oldstuff->htotal; - stuff->hskew = 0; - stuff->vdisplay = oldstuff->vdisplay; - stuff->vsyncstart = oldstuff->vsyncstart; - stuff->vsyncend = oldstuff->vsyncend; - stuff->vtotal = oldstuff->vtotal; - stuff->flags = oldstuff->flags; - stuff->privsize = oldstuff->privsize; - stuff->after_dotclock = oldstuff->after_dotclock; - stuff->after_hdisplay = oldstuff->after_hdisplay; - stuff->after_hsyncstart = oldstuff->after_hsyncstart; - stuff->after_hsyncend = oldstuff->after_hsyncend; - stuff->after_htotal = oldstuff->after_htotal; - stuff->after_hskew = 0; - stuff->after_vdisplay = oldstuff->after_vdisplay; - stuff->after_vsyncstart = oldstuff->after_vsyncstart; - stuff->after_vsyncend = oldstuff->after_vsyncend; - stuff->after_vtotal = oldstuff->after_vtotal; - stuff->after_flags = oldstuff->after_flags; - } - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("AddModeLine - scrn: %d clock: %ld\n", - (int)stuff->screen, (unsigned long)stuff->dotclock); - ErrorF("AddModeLine - hdsp: %d hbeg: %d hend: %d httl: %d\n", - stuff->hdisplay, stuff->hsyncstart, - stuff->hsyncend, stuff->htotal); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", - stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, - stuff->vtotal, (unsigned long)stuff->flags); - ErrorF(" after - scrn: %d clock: %ld\n", - (int)stuff->screen, (unsigned long)stuff->after_dotclock); - ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", - stuff->after_hdisplay, stuff->after_hsyncstart, - stuff->after_hsyncend, stuff->after_htotal); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", - stuff->after_vdisplay, stuff->after_vsyncstart, - stuff->after_vsyncend, stuff->after_vtotal, - (unsigned long)stuff->after_flags); - } - - if (ver < 2) { - REQUEST_AT_LEAST_SIZE(xXF86OldVidModeAddModeLineReq); - len = client->req_len - bytes_to_int32(sizeof(xXF86OldVidModeAddModeLineReq)); - } else { - REQUEST_AT_LEAST_SIZE(xXF86VidModeAddModeLineReq); - len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeAddModeLineReq)); - } - if (len != stuff->privsize) - return BadLength; - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if (stuff->hsyncstart < stuff->hdisplay || - stuff->hsyncend < stuff->hsyncstart || - stuff->htotal < stuff->hsyncend || - stuff->vsyncstart < stuff->vdisplay || - stuff->vsyncend < stuff->vsyncstart || - stuff->vtotal < stuff->vsyncend) - return BadValue; - - if (stuff->after_hsyncstart < stuff->after_hdisplay || - stuff->after_hsyncend < stuff->after_hsyncstart || - stuff->after_htotal < stuff->after_hsyncend || - stuff->after_vsyncstart < stuff->after_vdisplay || - stuff->after_vsyncend < stuff->after_vsyncstart || - stuff->after_vtotal < stuff->after_vsyncend) - return BadValue; - - if (stuff->after_htotal != 0 || stuff->after_vtotal != 0) { - Bool found = FALSE; - if (VidModeGetFirstModeline(stuff->screen, &mode, &dotClock)) { - do { - if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) - == dotClock) && MODEMATCH(mode, stuff)) { - found = TRUE; - break; - } - } while (VidModeGetNextModeline(stuff->screen, &mode, &dotClock)); - } - if (!found) - return BadValue; - } - - - mode = VidModeCreateMode(); - if (mode == NULL) - return BadValue; - - VidModeSetModeValue(mode, VIDMODE_CLOCK, stuff->dotclock); - VidModeSetModeValue(mode, VIDMODE_H_DISPLAY, stuff->hdisplay); - VidModeSetModeValue(mode, VIDMODE_H_SYNCSTART, stuff->hsyncstart); - VidModeSetModeValue(mode, VIDMODE_H_SYNCEND, stuff->hsyncend); - VidModeSetModeValue(mode, VIDMODE_H_TOTAL, stuff->htotal); - VidModeSetModeValue(mode, VIDMODE_H_SKEW, stuff->hskew); - VidModeSetModeValue(mode, VIDMODE_V_DISPLAY, stuff->vdisplay); - VidModeSetModeValue(mode, VIDMODE_V_SYNCSTART, stuff->vsyncstart); - VidModeSetModeValue(mode, VIDMODE_V_SYNCEND, stuff->vsyncend); - VidModeSetModeValue(mode, VIDMODE_V_TOTAL, stuff->vtotal); - VidModeSetModeValue(mode, VIDMODE_FLAGS, stuff->flags); - - if (stuff->privsize) - ErrorF("AddModeLine - Privates in request have been ignored\n"); - - /* Check that the mode is consistent with the monitor specs */ - switch (VidModeCheckModeForMonitor(stuff->screen, mode)) { - case MODE_OK: - break; - case MODE_HSYNC: - case MODE_H_ILLEGAL: - xfree(mode); - return VidModeErrorBase + XF86VidModeBadHTimings; - case MODE_VSYNC: - case MODE_V_ILLEGAL: - xfree(mode); - return VidModeErrorBase + XF86VidModeBadVTimings; - default: - xfree(mode); - return VidModeErrorBase + XF86VidModeModeUnsuitable; - } - - /* Check that the driver is happy with the mode */ - if (VidModeCheckModeForDriver(stuff->screen, mode) != MODE_OK) { - xfree(mode); - return VidModeErrorBase + XF86VidModeModeUnsuitable; - } - - VidModeSetCrtcForMode(stuff->screen, mode); - - VidModeAddModeline(stuff->screen, mode); - - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) - ErrorF("AddModeLine - Succeeded\n"); - return client->noClientException; -} - -static int -ProcXF86VidModeDeleteModeLine(ClientPtr client) -{ - REQUEST(xXF86VidModeDeleteModeLineReq); - xXF86OldVidModeDeleteModeLineReq *oldstuff = - (xXF86OldVidModeDeleteModeLineReq *)client->requestBuffer; - xXF86VidModeDeleteModeLineReq newstuff; - pointer mode; - int len, dotClock; - int ver; - - DEBUG_P("XF86VidModeDeleteModeline"); - - ver = ClientMajorVersion(client); - if (ver < 2) { - /* convert from old format */ - stuff = &newstuff; - stuff->length = oldstuff->length; - stuff->screen = oldstuff->screen; - stuff->dotclock = oldstuff->dotclock; - stuff->hdisplay = oldstuff->hdisplay; - stuff->hsyncstart = oldstuff->hsyncstart; - stuff->hsyncend = oldstuff->hsyncend; - stuff->htotal = oldstuff->htotal; - stuff->hskew = 0; - stuff->vdisplay = oldstuff->vdisplay; - stuff->vsyncstart = oldstuff->vsyncstart; - stuff->vsyncend = oldstuff->vsyncend; - stuff->vtotal = oldstuff->vtotal; - stuff->flags = oldstuff->flags; - stuff->privsize = oldstuff->privsize; - } - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("DeleteModeLine - scrn: %d clock: %ld\n", - (int)stuff->screen, (unsigned long)stuff->dotclock); - ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", - stuff->hdisplay, stuff->hsyncstart, - stuff->hsyncend, stuff->htotal); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", - stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, - stuff->vtotal, (unsigned long)stuff->flags); - } - - if (ver < 2) { - REQUEST_AT_LEAST_SIZE(xXF86OldVidModeDeleteModeLineReq); - len = client->req_len - bytes_to_int32(sizeof(xXF86OldVidModeDeleteModeLineReq)); - } else { - REQUEST_AT_LEAST_SIZE(xXF86VidModeDeleteModeLineReq); - len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeDeleteModeLineReq)); - } - if (len != stuff->privsize) { - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("req_len = %ld, sizeof(Req) = %d, privsize = %ld, " - "len = %d, length = %d\n", - (unsigned long)client->req_len, - (int)sizeof(xXF86VidModeDeleteModeLineReq)>>2, - (unsigned long)stuff->privsize, len, stuff->length); - } - return BadLength; - } - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) - return BadValue; - - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("Checking against clock: %d (%d)\n", - VidModeGetModeValue(mode, VIDMODE_CLOCK), dotClock); - ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", - VidModeGetModeValue(mode, VIDMODE_H_DISPLAY), - VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART), - VidModeGetModeValue(mode, VIDMODE_H_SYNCEND), - VidModeGetModeValue(mode, VIDMODE_H_TOTAL)); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %d\n", - VidModeGetModeValue(mode, VIDMODE_V_DISPLAY), - VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART), - VidModeGetModeValue(mode, VIDMODE_V_SYNCEND), - VidModeGetModeValue(mode, VIDMODE_V_TOTAL), - VidModeGetModeValue(mode, VIDMODE_FLAGS)); - } - if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) == dotClock) && - MODEMATCH(mode, stuff)) - return BadValue; - - if (!VidModeGetFirstModeline(stuff->screen, &mode, &dotClock)) - return BadValue; - - do { - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("Checking against clock: %d (%d)\n", - VidModeGetModeValue(mode, VIDMODE_CLOCK), dotClock); - ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", - VidModeGetModeValue(mode, VIDMODE_H_DISPLAY), - VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART), - VidModeGetModeValue(mode, VIDMODE_H_SYNCEND), - VidModeGetModeValue(mode, VIDMODE_H_TOTAL)); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %d\n", - VidModeGetModeValue(mode, VIDMODE_V_DISPLAY), - VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART), - VidModeGetModeValue(mode, VIDMODE_V_SYNCEND), - VidModeGetModeValue(mode, VIDMODE_V_TOTAL), - VidModeGetModeValue(mode, VIDMODE_FLAGS)); - } - if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) == dotClock) && - MODEMATCH(mode, stuff)) { - VidModeDeleteModeline(stuff->screen, mode); - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) - ErrorF("DeleteModeLine - Succeeded\n"); - return(client->noClientException); - } - } while (VidModeGetNextModeline(stuff->screen, &mode, &dotClock)); - - return BadValue; -} - -static int -ProcXF86VidModeModModeLine(ClientPtr client) -{ - REQUEST(xXF86VidModeModModeLineReq); - xXF86OldVidModeModModeLineReq *oldstuff = - (xXF86OldVidModeModModeLineReq *)client->requestBuffer; - xXF86VidModeModModeLineReq newstuff; - pointer mode, modetmp; - int len, dotClock; - int ver; - - DEBUG_P("XF86VidModeModModeline"); - - ver = ClientMajorVersion(client); - if (ver < 2 ) { - /* convert from old format */ - stuff = &newstuff; - stuff->length = oldstuff->length; - stuff->screen = oldstuff->screen; - stuff->hdisplay = oldstuff->hdisplay; - stuff->hsyncstart = oldstuff->hsyncstart; - stuff->hsyncend = oldstuff->hsyncend; - stuff->htotal = oldstuff->htotal; - stuff->hskew = 0; - stuff->vdisplay = oldstuff->vdisplay; - stuff->vsyncstart = oldstuff->vsyncstart; - stuff->vsyncend = oldstuff->vsyncend; - stuff->vtotal = oldstuff->vtotal; - stuff->flags = oldstuff->flags; - stuff->privsize = oldstuff->privsize; - } - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("ModModeLine - scrn: %d hdsp: %d hbeg: %d hend: %d httl: %d\n", - (int)stuff->screen, stuff->hdisplay, stuff->hsyncstart, - stuff->hsyncend, stuff->htotal); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", - stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, - stuff->vtotal, (unsigned long)stuff->flags); - } - - if (ver < 2) { - REQUEST_AT_LEAST_SIZE(xXF86OldVidModeModModeLineReq); - len = client->req_len - bytes_to_int32(sizeof(xXF86OldVidModeModModeLineReq)); - } else { - REQUEST_AT_LEAST_SIZE(xXF86VidModeModModeLineReq); - len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeModModeLineReq)); - } - if (len != stuff->privsize) - return BadLength; - - if (stuff->hsyncstart < stuff->hdisplay || - stuff->hsyncend < stuff->hsyncstart || - stuff->htotal < stuff->hsyncend || - stuff->vsyncstart < stuff->vdisplay || - stuff->vsyncend < stuff->vsyncstart || - stuff->vtotal < stuff->vsyncend) - return BadValue; - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) - return BadValue; - - modetmp = VidModeCreateMode(); - VidModeCopyMode(mode, modetmp); - - VidModeSetModeValue(modetmp, VIDMODE_H_DISPLAY, stuff->hdisplay); - VidModeSetModeValue(modetmp, VIDMODE_H_SYNCSTART, stuff->hsyncstart); - VidModeSetModeValue(modetmp, VIDMODE_H_SYNCEND, stuff->hsyncend); - VidModeSetModeValue(modetmp, VIDMODE_H_TOTAL, stuff->htotal); - VidModeSetModeValue(modetmp, VIDMODE_H_SKEW, stuff->hskew); - VidModeSetModeValue(modetmp, VIDMODE_V_DISPLAY, stuff->vdisplay); - VidModeSetModeValue(modetmp, VIDMODE_V_SYNCSTART, stuff->vsyncstart); - VidModeSetModeValue(modetmp, VIDMODE_V_SYNCEND, stuff->vsyncend); - VidModeSetModeValue(modetmp, VIDMODE_V_TOTAL, stuff->vtotal); - VidModeSetModeValue(modetmp, VIDMODE_FLAGS, stuff->flags); - - if (stuff->privsize) - ErrorF("ModModeLine - Privates in request have been ignored\n"); - - /* Check that the mode is consistent with the monitor specs */ - switch (VidModeCheckModeForMonitor(stuff->screen, modetmp)) { - case MODE_OK: - break; - case MODE_HSYNC: - case MODE_H_ILLEGAL: - xfree(modetmp); - return VidModeErrorBase + XF86VidModeBadHTimings; - case MODE_VSYNC: - case MODE_V_ILLEGAL: - xfree(modetmp); - return VidModeErrorBase + XF86VidModeBadVTimings; - default: - xfree(modetmp); - return VidModeErrorBase + XF86VidModeModeUnsuitable; - } - - /* Check that the driver is happy with the mode */ - if (VidModeCheckModeForDriver(stuff->screen, modetmp) != MODE_OK) { - xfree(modetmp); - return VidModeErrorBase + XF86VidModeModeUnsuitable; - } - xfree(modetmp); - - VidModeSetModeValue(mode, VIDMODE_H_DISPLAY, stuff->hdisplay); - VidModeSetModeValue(mode, VIDMODE_H_SYNCSTART, stuff->hsyncstart); - VidModeSetModeValue(mode, VIDMODE_H_SYNCEND, stuff->hsyncend); - VidModeSetModeValue(mode, VIDMODE_H_TOTAL, stuff->htotal); - VidModeSetModeValue(mode, VIDMODE_H_SKEW, stuff->hskew); - VidModeSetModeValue(mode, VIDMODE_V_DISPLAY, stuff->vdisplay); - VidModeSetModeValue(mode, VIDMODE_V_SYNCSTART, stuff->vsyncstart); - VidModeSetModeValue(mode, VIDMODE_V_SYNCEND, stuff->vsyncend); - VidModeSetModeValue(mode, VIDMODE_V_TOTAL, stuff->vtotal); - VidModeSetModeValue(mode, VIDMODE_FLAGS, stuff->flags); - - VidModeSetCrtcForMode(stuff->screen, mode); - VidModeSwitchMode(stuff->screen, mode); - - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) - ErrorF("ModModeLine - Succeeded\n"); - return(client->noClientException); -} - -static int -ProcXF86VidModeValidateModeLine(ClientPtr client) -{ - REQUEST(xXF86VidModeValidateModeLineReq); - xXF86OldVidModeValidateModeLineReq *oldstuff = - (xXF86OldVidModeValidateModeLineReq *)client->requestBuffer; - xXF86VidModeValidateModeLineReq newstuff; - xXF86VidModeValidateModeLineReply rep; - pointer mode, modetmp = NULL; - int len, status, dotClock; - int ver; - - DEBUG_P("XF86VidModeValidateModeline"); - - ver = ClientMajorVersion(client); - if (ver < 2) { - /* convert from old format */ - stuff = &newstuff; - stuff->length = oldstuff->length; - stuff->screen = oldstuff->screen; - stuff->dotclock = oldstuff->dotclock; - stuff->hdisplay = oldstuff->hdisplay; - stuff->hsyncstart = oldstuff->hsyncstart; - stuff->hsyncend = oldstuff->hsyncend; - stuff->htotal = oldstuff->htotal; - stuff->hskew = 0; - stuff->vdisplay = oldstuff->vdisplay; - stuff->vsyncstart = oldstuff->vsyncstart; - stuff->vsyncend = oldstuff->vsyncend; - stuff->vtotal = oldstuff->vtotal; - stuff->flags = oldstuff->flags; - stuff->privsize = oldstuff->privsize; - } - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("ValidateModeLine - scrn: %d clock: %ld\n", - (int)stuff->screen, (unsigned long)stuff->dotclock); - ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", - stuff->hdisplay, stuff->hsyncstart, - stuff->hsyncend, stuff->htotal); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", - stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, - stuff->vtotal, (unsigned long)stuff->flags); - } - - if (ver < 2) { - REQUEST_AT_LEAST_SIZE(xXF86OldVidModeValidateModeLineReq); - len = client->req_len - - bytes_to_int32(sizeof(xXF86OldVidModeValidateModeLineReq)); - } else { - REQUEST_AT_LEAST_SIZE(xXF86VidModeValidateModeLineReq); - len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeValidateModeLineReq)); - } - if (len != stuff->privsize) - return BadLength; - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - status = MODE_OK; - - if (stuff->hsyncstart < stuff->hdisplay || - stuff->hsyncend < stuff->hsyncstart || - stuff->htotal < stuff->hsyncend || - stuff->vsyncstart < stuff->vdisplay || - stuff->vsyncend < stuff->vsyncstart || - stuff->vtotal < stuff->vsyncend) - { - status = MODE_BAD; - goto status_reply; - } - - if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) - return BadValue; - - modetmp = VidModeCreateMode(); - VidModeCopyMode(mode, modetmp); - - VidModeSetModeValue(modetmp, VIDMODE_H_DISPLAY, stuff->hdisplay); - VidModeSetModeValue(modetmp, VIDMODE_H_SYNCSTART, stuff->hsyncstart); - VidModeSetModeValue(modetmp, VIDMODE_H_SYNCEND, stuff->hsyncend); - VidModeSetModeValue(modetmp, VIDMODE_H_TOTAL, stuff->htotal); - VidModeSetModeValue(modetmp, VIDMODE_H_SKEW, stuff->hskew); - VidModeSetModeValue(modetmp, VIDMODE_V_DISPLAY, stuff->vdisplay); - VidModeSetModeValue(modetmp, VIDMODE_V_SYNCSTART, stuff->vsyncstart); - VidModeSetModeValue(modetmp, VIDMODE_V_SYNCEND, stuff->vsyncend); - VidModeSetModeValue(modetmp, VIDMODE_V_TOTAL, stuff->vtotal); - VidModeSetModeValue(modetmp, VIDMODE_FLAGS, stuff->flags); - if (stuff->privsize) - ErrorF("ValidateModeLine - Privates in request have been ignored\n"); - - /* Check that the mode is consistent with the monitor specs */ - if ((status = VidModeCheckModeForMonitor(stuff->screen, modetmp)) != MODE_OK) - goto status_reply; - - /* Check that the driver is happy with the mode */ - status = VidModeCheckModeForDriver(stuff->screen, modetmp); - -status_reply: - if(modetmp) - xfree(modetmp); - - rep.type = X_Reply; - rep.length = bytes_to_int32(SIZEOF(xXF86VidModeValidateModeLineReply) - - SIZEOF(xGenericReply)); - rep.sequenceNumber = client->sequence; - rep.status = status; - if (client->swapped) { - register int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, sizeof(xXF86VidModeValidateModeLineReply), (char *)&rep); - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) - ErrorF("ValidateModeLine - Succeeded (status = %d)\n", status); - return(client->noClientException); -} - -static int -ProcXF86VidModeSwitchMode(ClientPtr client) -{ - REQUEST(xXF86VidModeSwitchModeReq); - - DEBUG_P("XF86VidModeSwitchMode"); - - REQUEST_SIZE_MATCH(xXF86VidModeSwitchModeReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - VidModeZoomViewport(stuff->screen, (short)stuff->zoom); - - return (client->noClientException); -} - -static int -ProcXF86VidModeSwitchToMode(ClientPtr client) -{ - REQUEST(xXF86VidModeSwitchToModeReq); - xXF86OldVidModeSwitchToModeReq *oldstuff = - (xXF86OldVidModeSwitchToModeReq *)client->requestBuffer; - xXF86VidModeSwitchToModeReq newstuff; - pointer mode; - int len, dotClock; - int ver; - - DEBUG_P("XF86VidModeSwitchToMode"); - - ver = ClientMajorVersion(client); - if (ver < 2) { - /* convert from old format */ - stuff = &newstuff; - stuff->length = oldstuff->length; - stuff->screen = oldstuff->screen; - stuff->dotclock = oldstuff->dotclock; - stuff->hdisplay = oldstuff->hdisplay; - stuff->hsyncstart = oldstuff->hsyncstart; - stuff->hsyncend = oldstuff->hsyncend; - stuff->htotal = oldstuff->htotal; - stuff->hskew = 0; - stuff->vdisplay = oldstuff->vdisplay; - stuff->vsyncstart = oldstuff->vsyncstart; - stuff->vsyncend = oldstuff->vsyncend; - stuff->vtotal = oldstuff->vtotal; - stuff->flags = oldstuff->flags; - stuff->privsize = oldstuff->privsize; - } - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("SwitchToMode - scrn: %d clock: %ld\n", - (int)stuff->screen, (unsigned long)stuff->dotclock); - ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", - stuff->hdisplay, stuff->hsyncstart, - stuff->hsyncend, stuff->htotal); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", - stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, - stuff->vtotal, (unsigned long)stuff->flags); - } - - if (ver < 2) { - REQUEST_AT_LEAST_SIZE(xXF86OldVidModeSwitchToModeReq); - len = client->req_len - bytes_to_int32(sizeof(xXF86OldVidModeSwitchToModeReq)); - } else { - REQUEST_AT_LEAST_SIZE(xXF86VidModeSwitchToModeReq); - len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeSwitchToModeReq)); - } - if (len != stuff->privsize) - return BadLength; - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) - return BadValue; - - if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) == dotClock) - && MODEMATCH(mode, stuff)) - return (client->noClientException); - - if (!VidModeGetFirstModeline(stuff->screen, &mode, &dotClock)) - return BadValue; - - do { - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { - ErrorF("Checking against clock: %d (%d)\n", - VidModeGetModeValue(mode, VIDMODE_CLOCK), dotClock); - ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", - VidModeGetModeValue(mode, VIDMODE_H_DISPLAY), - VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART), - VidModeGetModeValue(mode, VIDMODE_H_SYNCEND), - VidModeGetModeValue(mode, VIDMODE_H_TOTAL)); - ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %d\n", - VidModeGetModeValue(mode, VIDMODE_V_DISPLAY), - VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART), - VidModeGetModeValue(mode, VIDMODE_V_SYNCEND), - VidModeGetModeValue(mode, VIDMODE_V_TOTAL), - VidModeGetModeValue(mode, VIDMODE_FLAGS)); - } - if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) == dotClock) && - MODEMATCH(mode, stuff)) { - - if (!VidModeSwitchMode(stuff->screen, mode)) - return BadValue; - - if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) - ErrorF("SwitchToMode - Succeeded\n"); - return(client->noClientException); - } - } while (VidModeGetNextModeline(stuff->screen, &mode, &dotClock)); - - return BadValue; -} - -static int -ProcXF86VidModeLockModeSwitch(ClientPtr client) -{ - REQUEST(xXF86VidModeLockModeSwitchReq); - - REQUEST_SIZE_MATCH(xXF86VidModeLockModeSwitchReq); - - DEBUG_P("XF86VidModeLockModeSwitch"); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if (!VidModeLockZoom(stuff->screen, (short)stuff->lock)) - return VidModeErrorBase + XF86VidModeZoomLocked; - - return (client->noClientException); -} - -static int -ProcXF86VidModeGetMonitor(ClientPtr client) -{ - REQUEST(xXF86VidModeGetMonitorReq); - xXF86VidModeGetMonitorReply rep; - register int n; - CARD32 *hsyncdata, *vsyncdata; - int i, nHsync, nVrefresh; - pointer monitor; - - DEBUG_P("XF86VidModeGetMonitor"); - - REQUEST_SIZE_MATCH(xXF86VidModeGetMonitorReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if (!VidModeGetMonitor(stuff->screen, &monitor)) - return BadValue; - - nHsync = VidModeGetMonitorValue(monitor, VIDMODE_MON_NHSYNC, 0).i; - nVrefresh = VidModeGetMonitorValue(monitor, VIDMODE_MON_NVREFRESH, 0).i; - - rep.type = X_Reply; - if ((char *)(VidModeGetMonitorValue(monitor, VIDMODE_MON_VENDOR, 0)).ptr) - rep.vendorLength = strlen((char *)(VidModeGetMonitorValue(monitor, - VIDMODE_MON_VENDOR, 0)).ptr); - else - rep.vendorLength = 0; - if ((char *)(VidModeGetMonitorValue(monitor, VIDMODE_MON_MODEL, 0)).ptr) - rep.modelLength = strlen((char *)(VidModeGetMonitorValue(monitor, - VIDMODE_MON_MODEL, 0)).ptr); - else - rep.modelLength = 0; - rep.length = bytes_to_int32(SIZEOF(xXF86VidModeGetMonitorReply) - SIZEOF(xGenericReply) + - (nHsync + nVrefresh) * sizeof(CARD32) + - pad_to_int32(rep.vendorLength) + - pad_to_int32(rep.modelLength)); - rep.sequenceNumber = client->sequence; - rep.nhsync = nHsync; - rep.nvsync = nVrefresh; - hsyncdata = xalloc(nHsync * sizeof(CARD32)); - if (!hsyncdata) { - return BadAlloc; - } - - vsyncdata = xalloc(nVrefresh * sizeof(CARD32)); - if (!vsyncdata) { - xfree(hsyncdata); - return BadAlloc; - } - - for (i = 0; i < nHsync; i++) { - hsyncdata[i] = (unsigned short)(VidModeGetMonitorValue(monitor, - VIDMODE_MON_HSYNC_LO, i)).f | - (unsigned short)(VidModeGetMonitorValue(monitor, - VIDMODE_MON_HSYNC_HI, i)).f << 16; - } - for (i = 0; i < nVrefresh; i++) { - vsyncdata[i] = (unsigned short)(VidModeGetMonitorValue(monitor, - VIDMODE_MON_VREFRESH_LO, i)).f | - (unsigned short)(VidModeGetMonitorValue(monitor, - VIDMODE_MON_VREFRESH_HI, i)).f << 16; - } - - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - } - WriteToClient(client, SIZEOF(xXF86VidModeGetMonitorReply), (char *)&rep); - client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; - WriteSwappedDataToClient(client, nHsync * sizeof(CARD32), - hsyncdata); - WriteSwappedDataToClient(client, nVrefresh * sizeof(CARD32), - vsyncdata); - if (rep.vendorLength) - WriteToClient(client, rep.vendorLength, (char *)(VidModeGetMonitorValue(monitor, VIDMODE_MON_VENDOR, 0)).ptr); - if (rep.modelLength) - WriteToClient(client, rep.modelLength, (char *)(VidModeGetMonitorValue(monitor, VIDMODE_MON_MODEL, 0)).ptr); - - xfree(hsyncdata); - xfree(vsyncdata); - - return (client->noClientException); -} - -static int -ProcXF86VidModeGetViewPort(ClientPtr client) -{ - REQUEST(xXF86VidModeGetViewPortReq); - xXF86VidModeGetViewPortReply rep; - int x, y, n; - - DEBUG_P("XF86VidModeGetViewPort"); - - REQUEST_SIZE_MATCH(xXF86VidModeGetViewPortReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - VidModeGetViewPort(stuff->screen, &x, &y); - rep.x = x; - rep.y = y; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.x, n); - swapl(&rep.y, n); - } - WriteToClient(client, SIZEOF(xXF86VidModeGetViewPortReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86VidModeSetViewPort(ClientPtr client) -{ - REQUEST(xXF86VidModeSetViewPortReq); - - DEBUG_P("XF86VidModeSetViewPort"); - - REQUEST_SIZE_MATCH(xXF86VidModeSetViewPortReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if (!VidModeSetViewPort(stuff->screen, stuff->x, stuff->y)) - return BadValue; - - return (client->noClientException); -} - -static int -ProcXF86VidModeGetDotClocks(ClientPtr client) -{ - REQUEST(xXF86VidModeGetDotClocksReq); - xXF86VidModeGetDotClocksReply rep; - register int n; - int numClocks; - CARD32 dotclock; - int *Clocks = NULL; - Bool ClockProg; - - DEBUG_P("XF86VidModeGetDotClocks"); - - REQUEST_SIZE_MATCH(xXF86VidModeGetDotClocksReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - numClocks = VidModeGetNumOfClocks(stuff->screen, &ClockProg); - - rep.type = X_Reply; - rep.length = bytes_to_int32(SIZEOF(xXF86VidModeGetDotClocksReply) - - SIZEOF(xGenericReply) + numClocks); - rep.sequenceNumber = client->sequence; - rep.clocks = numClocks; - rep.maxclocks = MAXCLOCKS; - rep.flags = 0; - - if (!ClockProg) { - Clocks = xalloc(numClocks * sizeof(int)); - if (!Clocks) - return BadValue; - if (!VidModeGetClocks(stuff->screen, Clocks)) { - xfree(Clocks); - return BadValue; - } - } - - if (ClockProg) { - rep.flags |= CLKFLAG_PROGRAMABLE; - } - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.clocks, n); - swapl(&rep.maxclocks, n); - swapl(&rep.flags, n); - } - WriteToClient(client, sizeof(xXF86VidModeGetDotClocksReply), (char *)&rep); - if (!ClockProg) { - for (n = 0; n < numClocks; n++) { - dotclock = *Clocks++; - if (client->swapped) { - WriteSwappedDataToClient(client, 4, (char *)&dotclock); - } else { - WriteToClient(client, 4, (char *)&dotclock); - } - } - } - - xfree(Clocks); - return (client->noClientException); -} - -static int -ProcXF86VidModeSetGamma(ClientPtr client) -{ - REQUEST(xXF86VidModeSetGammaReq); - - DEBUG_P("XF86VidModeSetGamma"); - - REQUEST_SIZE_MATCH(xXF86VidModeSetGammaReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if (!VidModeSetGamma(stuff->screen, ((float)stuff->red)/10000., - ((float)stuff->green)/10000., ((float)stuff->blue)/10000.)) - return BadValue; - - return (client->noClientException); -} - -static int -ProcXF86VidModeGetGamma(ClientPtr client) -{ - REQUEST(xXF86VidModeGetGammaReq); - xXF86VidModeGetGammaReply rep; - register int n; - float red, green, blue; - - DEBUG_P("XF86VidModeGetGamma"); - - REQUEST_SIZE_MATCH(xXF86VidModeGetGammaReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - if (!VidModeGetGamma(stuff->screen, &red, &green, &blue)) - return BadValue; - rep.red = (CARD32)(red * 10000.); - rep.green = (CARD32)(green * 10000.); - rep.blue = (CARD32)(blue * 10000.); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.red, n); - swapl(&rep.green, n); - swapl(&rep.blue, n); - } - WriteToClient(client, sizeof(xXF86VidModeGetGammaReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86VidModeSetGammaRamp(ClientPtr client) -{ - CARD16 *r, *g, *b; - int length; - REQUEST(xXF86VidModeSetGammaRampReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if(stuff->size != VidModeGetGammaRampSize(stuff->screen)) - return BadValue; - - length = (stuff->size + 1) & ~1; - - REQUEST_FIXED_SIZE(xXF86VidModeSetGammaRampReq, length * 6); - - r = (CARD16*)&stuff[1]; - g = r + length; - b = g + length; - - if (!VidModeSetGammaRamp(stuff->screen, stuff->size, r, g, b)) - return BadValue; - - return (client->noClientException); -} - -static int -ProcXF86VidModeGetGammaRamp(ClientPtr client) -{ - CARD16 *ramp = NULL; - int n, length; - size_t ramplen = 0; - xXF86VidModeGetGammaRampReply rep; - REQUEST(xXF86VidModeGetGammaRampReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - if(stuff->size != VidModeGetGammaRampSize(stuff->screen)) - return BadValue; - - REQUEST_SIZE_MATCH(xXF86VidModeGetGammaRampReq); - - length = (stuff->size + 1) & ~1; - - if(stuff->size) { - ramplen = length * 3 * sizeof(CARD16); - if (!(ramp = xalloc(ramplen))) - return BadAlloc; - - if (!VidModeGetGammaRamp(stuff->screen, stuff->size, - ramp, ramp + length, ramp + (length * 2))) { - xfree(ramp); - return BadValue; - } - } - - rep.type = X_Reply; - rep.length = (length >> 1) * 3; - rep.sequenceNumber = client->sequence; - rep.size = stuff->size; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.size, n); - SwapShorts((short*)ramp, length * 3); - } - WriteToClient(client, sizeof(xXF86VidModeGetGammaRampReply), (char *)&rep); - - if(stuff->size) { - WriteToClient(client, ramplen, (char*)ramp); - xfree(ramp); - } - - return (client->noClientException); -} - - -static int -ProcXF86VidModeGetGammaRampSize(ClientPtr client) -{ - xXF86VidModeGetGammaRampSizeReply rep; - int n; - REQUEST(xXF86VidModeGetGammaRampSizeReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - REQUEST_SIZE_MATCH(xXF86VidModeGetGammaRampSizeReq); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.size = VidModeGetGammaRampSize(stuff->screen); - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.size, n); - } - WriteToClient(client,sizeof(xXF86VidModeGetGammaRampSizeReply),(char*)&rep); - - return (client->noClientException); -} - -static int -ProcXF86VidModeGetPermissions(ClientPtr client) -{ - xXF86VidModeGetPermissionsReply rep; - int n; - REQUEST(xXF86VidModeGetPermissionsReq); - - if(stuff->screen >= screenInfo.numScreens) - return BadValue; - - REQUEST_SIZE_MATCH(xXF86VidModeGetPermissionsReq); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.permissions = XF86VM_READ_PERMISSION; - if (xf86GetVidModeEnabled() && - (xf86GetVidModeAllowNonLocal() || LocalClient (client))) { - rep.permissions |= XF86VM_WRITE_PERMISSION; - } - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.permissions, n); - } - WriteToClient(client,sizeof(xXF86VidModeGetPermissionsReply),(char*)&rep); - - return (client->noClientException); -} - - -static int -ProcXF86VidModeSetClientVersion(ClientPtr client) -{ - REQUEST(xXF86VidModeSetClientVersionReq); - - VidModePrivPtr pPriv; - - DEBUG_P("XF86VidModeSetClientVersion"); - - REQUEST_SIZE_MATCH(xXF86VidModeSetClientVersionReq); - - if ((pPriv = VM_GETPRIV(client)) == NULL) { - pPriv = xalloc(sizeof(VidModePrivRec)); - if (!pPriv) - return BadAlloc; - VM_SETPRIV(client, pPriv); - } - pPriv->major = stuff->major; - pPriv->minor = stuff->minor; - - return (client->noClientException); -} - -static int -ProcXF86VidModeDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) - { - case X_XF86VidModeQueryVersion: - return ProcXF86VidModeQueryVersion(client); - case X_XF86VidModeGetModeLine: - return ProcXF86VidModeGetModeLine(client); - case X_XF86VidModeGetMonitor: - return ProcXF86VidModeGetMonitor(client); - case X_XF86VidModeGetAllModeLines: - return ProcXF86VidModeGetAllModeLines(client); - case X_XF86VidModeValidateModeLine: - return ProcXF86VidModeValidateModeLine(client); - case X_XF86VidModeGetViewPort: - return ProcXF86VidModeGetViewPort(client); - case X_XF86VidModeGetDotClocks: - return ProcXF86VidModeGetDotClocks(client); - case X_XF86VidModeSetClientVersion: - return ProcXF86VidModeSetClientVersion(client); - case X_XF86VidModeGetGamma: - return ProcXF86VidModeGetGamma(client); - case X_XF86VidModeGetGammaRamp: - return ProcXF86VidModeGetGammaRamp(client); - case X_XF86VidModeGetGammaRampSize: - return ProcXF86VidModeGetGammaRampSize(client); - case X_XF86VidModeGetPermissions: - return ProcXF86VidModeGetPermissions(client); - default: - if (!xf86GetVidModeEnabled()) - return VidModeErrorBase + XF86VidModeExtensionDisabled; - if (xf86GetVidModeAllowNonLocal() || LocalClient (client)) { - switch (stuff->data) { - case X_XF86VidModeAddModeLine: - return ProcXF86VidModeAddModeLine(client); - case X_XF86VidModeDeleteModeLine: - return ProcXF86VidModeDeleteModeLine(client); - case X_XF86VidModeModModeLine: - return ProcXF86VidModeModModeLine(client); - case X_XF86VidModeSwitchMode: - return ProcXF86VidModeSwitchMode(client); - case X_XF86VidModeSwitchToMode: - return ProcXF86VidModeSwitchToMode(client); - case X_XF86VidModeLockModeSwitch: - return ProcXF86VidModeLockModeSwitch(client); - case X_XF86VidModeSetViewPort: - return ProcXF86VidModeSetViewPort(client); - case X_XF86VidModeSetGamma: - return ProcXF86VidModeSetGamma(client); - case X_XF86VidModeSetGammaRamp: - return ProcXF86VidModeSetGammaRamp(client); - default: - return BadRequest; - } - } else - return VidModeErrorBase + XF86VidModeClientNotLocal; - } -} - -static int -SProcXF86VidModeQueryVersion(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeQueryVersionReq); - swaps(&stuff->length, n); - return ProcXF86VidModeQueryVersion(client); -} - -static int -SProcXF86VidModeGetModeLine(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeGetModeLineReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeGetModeLineReq); - swaps(&stuff->screen, n); - return ProcXF86VidModeGetModeLine(client); -} - -static int -SProcXF86VidModeGetAllModeLines(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeGetAllModeLinesReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeGetAllModeLinesReq); - swaps(&stuff->screen, n); - return ProcXF86VidModeGetAllModeLines(client); -} - -static int -SProcXF86VidModeAddModeLine(ClientPtr client) -{ - xXF86OldVidModeAddModeLineReq *oldstuff = - (xXF86OldVidModeAddModeLineReq *)client->requestBuffer; - int ver; - register int n; - - REQUEST(xXF86VidModeAddModeLineReq); - ver = ClientMajorVersion(client); - if (ver < 2) { - swaps(&oldstuff->length, n); - REQUEST_AT_LEAST_SIZE(xXF86OldVidModeAddModeLineReq); - swapl(&oldstuff->screen, n); - swaps(&oldstuff->hdisplay, n); - swaps(&oldstuff->hsyncstart, n); - swaps(&oldstuff->hsyncend, n); - swaps(&oldstuff->htotal, n); - swaps(&oldstuff->vdisplay, n); - swaps(&oldstuff->vsyncstart, n); - swaps(&oldstuff->vsyncend, n); - swaps(&oldstuff->vtotal, n); - swapl(&oldstuff->flags, n); - swapl(&oldstuff->privsize, n); - SwapRestL(oldstuff); - } else { - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xXF86VidModeAddModeLineReq); - swapl(&stuff->screen, n); - swaps(&stuff->hdisplay, n); - swaps(&stuff->hsyncstart, n); - swaps(&stuff->hsyncend, n); - swaps(&stuff->htotal, n); - swaps(&stuff->hskew, n); - swaps(&stuff->vdisplay, n); - swaps(&stuff->vsyncstart, n); - swaps(&stuff->vsyncend, n); - swaps(&stuff->vtotal, n); - swapl(&stuff->flags, n); - swapl(&stuff->privsize, n); - SwapRestL(stuff); - } - return ProcXF86VidModeAddModeLine(client); -} - -static int -SProcXF86VidModeDeleteModeLine(ClientPtr client) -{ - xXF86OldVidModeDeleteModeLineReq *oldstuff = - (xXF86OldVidModeDeleteModeLineReq *)client->requestBuffer; - int ver; - register int n; - - REQUEST(xXF86VidModeDeleteModeLineReq); - ver = ClientMajorVersion(client); - if (ver < 2) { - swaps(&oldstuff->length, n); - REQUEST_AT_LEAST_SIZE(xXF86OldVidModeDeleteModeLineReq); - swapl(&oldstuff->screen, n); - swaps(&oldstuff->hdisplay, n); - swaps(&oldstuff->hsyncstart, n); - swaps(&oldstuff->hsyncend, n); - swaps(&oldstuff->htotal, n); - swaps(&oldstuff->vdisplay, n); - swaps(&oldstuff->vsyncstart, n); - swaps(&oldstuff->vsyncend, n); - swaps(&oldstuff->vtotal, n); - swapl(&oldstuff->flags, n); - swapl(&oldstuff->privsize, n); - SwapRestL(oldstuff); - } else { - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xXF86VidModeDeleteModeLineReq); - swapl(&stuff->screen, n); - swaps(&stuff->hdisplay, n); - swaps(&stuff->hsyncstart, n); - swaps(&stuff->hsyncend, n); - swaps(&stuff->htotal, n); - swaps(&stuff->hskew, n); - swaps(&stuff->vdisplay, n); - swaps(&stuff->vsyncstart, n); - swaps(&stuff->vsyncend, n); - swaps(&stuff->vtotal, n); - swapl(&stuff->flags, n); - swapl(&stuff->privsize, n); - SwapRestL(stuff); - } - return ProcXF86VidModeDeleteModeLine(client); -} - -static int -SProcXF86VidModeModModeLine(ClientPtr client) -{ - xXF86OldVidModeModModeLineReq *oldstuff = - (xXF86OldVidModeModModeLineReq *)client->requestBuffer; - int ver; - register int n; - - REQUEST(xXF86VidModeModModeLineReq); - ver = ClientMajorVersion(client); - if (ver < 2) { - swaps(&oldstuff->length, n); - REQUEST_AT_LEAST_SIZE(xXF86OldVidModeModModeLineReq); - swapl(&oldstuff->screen, n); - swaps(&oldstuff->hdisplay, n); - swaps(&oldstuff->hsyncstart, n); - swaps(&oldstuff->hsyncend, n); - swaps(&oldstuff->htotal, n); - swaps(&oldstuff->vdisplay, n); - swaps(&oldstuff->vsyncstart, n); - swaps(&oldstuff->vsyncend, n); - swaps(&oldstuff->vtotal, n); - swapl(&oldstuff->flags, n); - swapl(&oldstuff->privsize, n); - SwapRestL(oldstuff); - } else { - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xXF86VidModeModModeLineReq); - swapl(&stuff->screen, n); - swaps(&stuff->hdisplay, n); - swaps(&stuff->hsyncstart, n); - swaps(&stuff->hsyncend, n); - swaps(&stuff->htotal, n); - swaps(&stuff->hskew, n); - swaps(&stuff->vdisplay, n); - swaps(&stuff->vsyncstart, n); - swaps(&stuff->vsyncend, n); - swaps(&stuff->vtotal, n); - swapl(&stuff->flags, n); - swapl(&stuff->privsize, n); - SwapRestL(stuff); - } - return ProcXF86VidModeModModeLine(client); -} - -static int -SProcXF86VidModeValidateModeLine(ClientPtr client) -{ - xXF86OldVidModeValidateModeLineReq *oldstuff = - (xXF86OldVidModeValidateModeLineReq *)client->requestBuffer; - int ver; - register int n; - - REQUEST(xXF86VidModeValidateModeLineReq); - ver = ClientMajorVersion(client); - if (ver < 2) { - swaps(&oldstuff->length, n); - REQUEST_AT_LEAST_SIZE(xXF86OldVidModeValidateModeLineReq); - swapl(&oldstuff->screen, n); - swaps(&oldstuff->hdisplay, n); - swaps(&oldstuff->hsyncstart, n); - swaps(&oldstuff->hsyncend, n); - swaps(&oldstuff->htotal, n); - swaps(&oldstuff->vdisplay, n); - swaps(&oldstuff->vsyncstart, n); - swaps(&oldstuff->vsyncend, n); - swaps(&oldstuff->vtotal, n); - swapl(&oldstuff->flags, n); - swapl(&oldstuff->privsize, n); - SwapRestL(oldstuff); - } else { - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xXF86VidModeValidateModeLineReq); - swapl(&stuff->screen, n); - swaps(&stuff->hdisplay, n); - swaps(&stuff->hsyncstart, n); - swaps(&stuff->hsyncend, n); - swaps(&stuff->htotal, n); - swaps(&stuff->hskew, n); - swaps(&stuff->vdisplay, n); - swaps(&stuff->vsyncstart, n); - swaps(&stuff->vsyncend, n); - swaps(&stuff->vtotal, n); - swapl(&stuff->flags, n); - swapl(&stuff->privsize, n); - SwapRestL(stuff); - } - return ProcXF86VidModeValidateModeLine(client); -} - -static int -SProcXF86VidModeSwitchMode(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeSwitchModeReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeSwitchModeReq); - swaps(&stuff->screen, n); - swaps(&stuff->zoom, n); - return ProcXF86VidModeSwitchMode(client); -} - -static int -SProcXF86VidModeSwitchToMode(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeSwitchToModeReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeSwitchToModeReq); - swaps(&stuff->screen, n); - return ProcXF86VidModeSwitchToMode(client); -} - -static int -SProcXF86VidModeLockModeSwitch(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeLockModeSwitchReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeLockModeSwitchReq); - swaps(&stuff->screen, n); - swaps(&stuff->lock, n); - return ProcXF86VidModeLockModeSwitch(client); -} - -static int -SProcXF86VidModeGetMonitor(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeGetMonitorReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeGetMonitorReq); - swaps(&stuff->screen, n); - return ProcXF86VidModeGetMonitor(client); -} - -static int -SProcXF86VidModeGetViewPort(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeGetViewPortReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeGetViewPortReq); - swaps(&stuff->screen, n); - return ProcXF86VidModeGetViewPort(client); -} - -static int -SProcXF86VidModeSetViewPort(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeSetViewPortReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeSetViewPortReq); - swaps(&stuff->screen, n); - swapl(&stuff->x, n); - swapl(&stuff->y, n); - return ProcXF86VidModeSetViewPort(client); -} - -static int -SProcXF86VidModeGetDotClocks(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeGetDotClocksReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeGetDotClocksReq); - swaps(&stuff->screen, n); - return ProcXF86VidModeGetDotClocks(client); -} - -static int -SProcXF86VidModeSetClientVersion(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeSetClientVersionReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeSetClientVersionReq); - swaps(&stuff->major, n); - swaps(&stuff->minor, n); - return ProcXF86VidModeSetClientVersion(client); -} - -static int -SProcXF86VidModeSetGamma(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeSetGammaReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeSetGammaReq); - swaps(&stuff->screen, n); - swapl(&stuff->red, n); - swapl(&stuff->green, n); - swapl(&stuff->blue, n); - return ProcXF86VidModeSetGamma(client); -} - -static int -SProcXF86VidModeGetGamma(ClientPtr client) -{ - register int n; - REQUEST(xXF86VidModeGetGammaReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeGetGammaReq); - swaps(&stuff->screen, n); - return ProcXF86VidModeGetGamma(client); -} - -static int -SProcXF86VidModeSetGammaRamp(ClientPtr client) -{ - int length, n; - REQUEST(xXF86VidModeSetGammaRampReq); - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xXF86VidModeSetGammaRampReq); - swaps(&stuff->size, n); - swaps(&stuff->screen, n); - length = ((stuff->size + 1) & ~1) * 6; - REQUEST_FIXED_SIZE(xXF86VidModeSetGammaRampReq, length); - SwapRestS(stuff); - return ProcXF86VidModeSetGammaRamp(client); -} - -static int -SProcXF86VidModeGetGammaRamp(ClientPtr client) -{ - int n; - REQUEST(xXF86VidModeGetGammaRampReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeGetGammaRampReq); - swaps(&stuff->size, n); - swaps(&stuff->screen, n); - return ProcXF86VidModeGetGammaRamp(client); -} - -static int -SProcXF86VidModeGetGammaRampSize(ClientPtr client) -{ - int n; - REQUEST(xXF86VidModeGetGammaRampSizeReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeGetGammaRampSizeReq); - swaps(&stuff->screen, n); - return ProcXF86VidModeGetGammaRampSize(client); -} - -static int -SProcXF86VidModeGetPermissions(ClientPtr client) -{ - int n; - REQUEST(xXF86VidModeGetPermissionsReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xXF86VidModeGetPermissionsReq); - swaps(&stuff->screen, n); - return ProcXF86VidModeGetPermissions(client); -} - - -static int -SProcXF86VidModeDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) - { - case X_XF86VidModeQueryVersion: - return SProcXF86VidModeQueryVersion(client); - case X_XF86VidModeGetModeLine: - return SProcXF86VidModeGetModeLine(client); - case X_XF86VidModeGetMonitor: - return SProcXF86VidModeGetMonitor(client); - case X_XF86VidModeGetAllModeLines: - return SProcXF86VidModeGetAllModeLines(client); - case X_XF86VidModeGetViewPort: - return SProcXF86VidModeGetViewPort(client); - case X_XF86VidModeValidateModeLine: - return SProcXF86VidModeValidateModeLine(client); - case X_XF86VidModeGetDotClocks: - return SProcXF86VidModeGetDotClocks(client); - case X_XF86VidModeSetClientVersion: - return SProcXF86VidModeSetClientVersion(client); - case X_XF86VidModeGetGamma: - return SProcXF86VidModeGetGamma(client); - case X_XF86VidModeGetGammaRamp: - return SProcXF86VidModeGetGammaRamp(client); - case X_XF86VidModeGetGammaRampSize: - return SProcXF86VidModeGetGammaRampSize(client); - case X_XF86VidModeGetPermissions: - return SProcXF86VidModeGetPermissions(client); - default: - if (!xf86GetVidModeEnabled()) - return VidModeErrorBase + XF86VidModeExtensionDisabled; - if (xf86GetVidModeAllowNonLocal() || LocalClient(client)) { - switch (stuff->data) { - case X_XF86VidModeAddModeLine: - return SProcXF86VidModeAddModeLine(client); - case X_XF86VidModeDeleteModeLine: - return SProcXF86VidModeDeleteModeLine(client); - case X_XF86VidModeModModeLine: - return SProcXF86VidModeModModeLine(client); - case X_XF86VidModeSwitchMode: - return SProcXF86VidModeSwitchMode(client); - case X_XF86VidModeSwitchToMode: - return SProcXF86VidModeSwitchToMode(client); - case X_XF86VidModeLockModeSwitch: - return SProcXF86VidModeLockModeSwitch(client); - case X_XF86VidModeSetViewPort: - return SProcXF86VidModeSetViewPort(client); - case X_XF86VidModeSetGamma: - return SProcXF86VidModeSetGamma(client); - case X_XF86VidModeSetGammaRamp: - return SProcXF86VidModeSetGammaRamp(client); - default: - return BadRequest; - } - } else - return VidModeErrorBase + XF86VidModeClientNotLocal; - } -} + +/* + +Copyright 1995 Kaleb S. KEITHLEY + +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 Kaleb S. KEITHLEY 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 Kaleb S. KEITHLEY +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +from Kaleb S. KEITHLEY + +*/ +/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "scrnintstr.h" +#include "servermd.h" +#include <X11/extensions/xf86vmproto.h> +#include "swaprep.h" +#include "xf86.h" +#include "vidmodeproc.h" +#include "globals.h" +#include "protocol-versions.h" + +#define DEFAULT_XF86VIDMODE_VERBOSITY 3 + +static int VidModeErrorBase; +static int VidModeClientPrivateKeyIndex; +static DevPrivateKey VidModeClientPrivateKey = &VidModeClientPrivateKeyIndex; + +/* This holds the client's version information */ +typedef struct { + int major; + int minor; +} VidModePrivRec, *VidModePrivPtr; + +#define VM_GETPRIV(c) ((VidModePrivPtr) \ + dixLookupPrivate(&(c)->devPrivates, VidModeClientPrivateKey)) +#define VM_SETPRIV(c,p) \ + dixSetPrivate(&(c)->devPrivates, VidModeClientPrivateKey, p) + +static DISPATCH_PROC(ProcXF86VidModeDispatch); +static DISPATCH_PROC(ProcXF86VidModeGetAllModeLines); +static DISPATCH_PROC(ProcXF86VidModeGetModeLine); +static DISPATCH_PROC(ProcXF86VidModeGetMonitor); +static DISPATCH_PROC(ProcXF86VidModeLockModeSwitch); +static DISPATCH_PROC(ProcXF86VidModeAddModeLine); +static DISPATCH_PROC(ProcXF86VidModeDeleteModeLine); +static DISPATCH_PROC(ProcXF86VidModeModModeLine); +static DISPATCH_PROC(ProcXF86VidModeValidateModeLine); +static DISPATCH_PROC(ProcXF86VidModeQueryVersion); +static DISPATCH_PROC(ProcXF86VidModeSwitchMode); +static DISPATCH_PROC(ProcXF86VidModeSwitchToMode); +static DISPATCH_PROC(ProcXF86VidModeGetViewPort); +static DISPATCH_PROC(ProcXF86VidModeSetViewPort); +static DISPATCH_PROC(ProcXF86VidModeGetDotClocks); +static DISPATCH_PROC(ProcXF86VidModeSetGamma); +static DISPATCH_PROC(ProcXF86VidModeGetGamma); +static DISPATCH_PROC(ProcXF86VidModeSetClientVersion); +static DISPATCH_PROC(ProcXF86VidModeGetGammaRamp); +static DISPATCH_PROC(ProcXF86VidModeSetGammaRamp); +static DISPATCH_PROC(ProcXF86VidModeGetGammaRampSize); +static DISPATCH_PROC(SProcXF86VidModeDispatch); +static DISPATCH_PROC(SProcXF86VidModeGetAllModeLines); +static DISPATCH_PROC(SProcXF86VidModeGetModeLine); +static DISPATCH_PROC(SProcXF86VidModeGetMonitor); +static DISPATCH_PROC(SProcXF86VidModeLockModeSwitch); +static DISPATCH_PROC(SProcXF86VidModeAddModeLine); +static DISPATCH_PROC(SProcXF86VidModeDeleteModeLine); +static DISPATCH_PROC(SProcXF86VidModeModModeLine); +static DISPATCH_PROC(SProcXF86VidModeValidateModeLine); +static DISPATCH_PROC(SProcXF86VidModeQueryVersion); +static DISPATCH_PROC(SProcXF86VidModeSwitchMode); +static DISPATCH_PROC(SProcXF86VidModeSwitchToMode); +static DISPATCH_PROC(SProcXF86VidModeGetViewPort); +static DISPATCH_PROC(SProcXF86VidModeSetViewPort); +static DISPATCH_PROC(SProcXF86VidModeGetDotClocks); +static DISPATCH_PROC(SProcXF86VidModeSetGamma); +static DISPATCH_PROC(SProcXF86VidModeGetGamma); +static DISPATCH_PROC(SProcXF86VidModeSetClientVersion); +static DISPATCH_PROC(SProcXF86VidModeGetGammaRamp); +static DISPATCH_PROC(SProcXF86VidModeSetGammaRamp); +static DISPATCH_PROC(SProcXF86VidModeGetGammaRampSize); + +#if 0 +static unsigned char XF86VidModeReqCode = 0; +#endif + +/* The XF86VIDMODE_EVENTS code is far from complete */ + +#ifdef XF86VIDMODE_EVENTS +static int XF86VidModeEventBase = 0; + +static void SXF86VidModeNotifyEvent(); + xXF86VidModeNotifyEvent * /* from */, + xXF86VidModeNotifyEvent * /* to */ +); + +static RESTYPE EventType; /* resource type for event masks */ + +typedef struct _XF86VidModeEvent *XF86VidModeEventPtr; + +typedef struct _XF86VidModeEvent { + XF86VidModeEventPtr next; + ClientPtr client; + ScreenPtr screen; + XID resource; + CARD32 mask; +} XF86VidModeEventRec; + +static int XF86VidModeFreeEvents(); + +typedef struct _XF86VidModeScreenPrivate { + XF86VidModeEventPtr events; + Bool hasWindow; +} XF86VidModeScreenPrivateRec, *XF86VidModeScreenPrivatePtr; + +static int ScreenPrivateKeyIndex; +static DevPrivateKey ScreenPrivateKey = &ScreenPrivateKeyIndex; + +#define GetScreenPrivate(s) ((ScreenSaverScreenPrivatePtr) \ + dixLookupPrivate(&(s)->devPrivates, ScreenPrivateKey)) +#define SetScreenPrivate(s,v) \ + dixSetPrivate(&(s)->devPrivates, ScreenPrivateKey, v) +#define SetupScreen(s) ScreenSaverScreenPrivatePtr pPriv = GetScreenPrivate(s) + +#define New(t) (malloc(sizeof (t))) +#endif + +#ifdef DEBUG +# define DEBUG_P(x) ErrorF(x"\n"); +#else +# define DEBUG_P(x) /**/ +#endif + +void +XFree86VidModeExtensionInit(void) +{ + ExtensionEntry* extEntry; + ScreenPtr pScreen; + int i; + Bool enabled = FALSE; + + DEBUG_P("XFree86VidModeExtensionInit"); + +#ifdef XF86VIDMODE_EVENTS + EventType = CreateNewResourceType(XF86VidModeFreeEvents, "VidModeEvent"); +#endif + + for(i = 0; i < screenInfo.numScreens; i++) { + pScreen = screenInfo.screens[i]; + if (VidModeExtensionInit(pScreen)) + enabled = TRUE; +#ifdef XF86VIDMODE_EVENTS + SetScreenPrivate (pScreen, NULL); +#endif + } + /* This means that the DDX doesn't want the vidmode extension enabled */ + if (!enabled) + return; + + if ( +#ifdef XF86VIDMODE_EVENTS + EventType && +#endif + (extEntry = AddExtension(XF86VIDMODENAME, + XF86VidModeNumberEvents, + XF86VidModeNumberErrors, + ProcXF86VidModeDispatch, + SProcXF86VidModeDispatch, + NULL, + StandardMinorOpcode))) { +#if 0 + XF86VidModeReqCode = (unsigned char)extEntry->base; +#endif + VidModeErrorBase = extEntry->errorBase; +#ifdef XF86VIDMODE_EVENTS + XF86VidModeEventBase = extEntry->eventBase; + EventSwapVector[XF86VidModeEventBase] = (EventSwapPtr)SXF86VidModeNotifyEvent; +#endif + } +} + +static int +ClientMajorVersion(ClientPtr client) +{ + VidModePrivPtr pPriv; + + pPriv = VM_GETPRIV(client); + if (!pPriv) + return 0; + else + return pPriv->major; +} + +#ifdef XF86VIDMODE_EVENTS +static void +CheckScreenPrivate (pScreen) + ScreenPtr pScreen; +{ + SetupScreen (pScreen); + + if (!pPriv) + return; + if (!pPriv->events && !pPriv->hasWindow) { + free(pPriv); + SetScreenPrivate (pScreen, NULL); + } +} + +static XF86VidModeScreenPrivatePtr +MakeScreenPrivate (pScreen) + ScreenPtr pScreen; +{ + SetupScreen (pScreen); + + if (pPriv) + return pPriv; + pPriv = New (XF86VidModeScreenPrivateRec); + if (!pPriv) + return 0; + pPriv->events = 0; + pPriv->hasWindow = FALSE; + SetScreenPrivate (pScreen, pPriv); + return pPriv; +} + +static unsigned long +getEventMask (ScreenPtr pScreen, ClientPtr client) +{ + SetupScreen(pScreen); + XF86VidModeEventPtr 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 (ScreenPtr pScreen, ClientPtr client, unsigned long mask) +{ + SetupScreen(pScreen); + XF86VidModeEventPtr pEv, *pPrev; + + if (getEventMask (pScreen, client) == mask) + return TRUE; + if (!pPriv) { + pPriv = MakeScreenPrivate (pScreen); + if (!pPriv) + return FALSE; + } + for (pPrev = &pPriv->events; pEv = *pPrev; pPrev = &pEv->next) + if (pEv->client == client) + break; + if (mask == 0) { + *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); + } + pEv->mask = mask; + } + return TRUE; +} + +static int +XF86VidModeFreeEvents(pointer value, XID id) +{ + XF86VidModeEventPtr pOld = (XF86VidModeEventPtr)value; + ScreenPtr pScreen = pOld->screen; + SetupScreen (pScreen); + XF86VidModeEventPtr pEv, *pPrev; + + if (!pPriv) + return TRUE; + for (pPrev = &pPriv->events; pEv = *pPrev; pPrev = &pEv->next) + if (pEv == pOld) + break; + if (!pEv) + return TRUE; + *pPrev = pEv->next; + free(pEv); + CheckScreenPrivate (pScreen); + return TRUE; +} + +static void +SendXF86VidModeNotify(ScreenPtr pScreen, int state, Bool forced) +{ + XF86VidModeScreenPrivatePtr pPriv; + XF86VidModeEventPtr pEv; + unsigned long mask; + xXF86VidModeNotifyEvent ev; + ClientPtr client; + int kind; + + UpdateCurrentTimeIf (); + mask = XF86VidModeNotifyMask; + pScreen = screenInfo.screens[pScreen->myNum]; + pPriv = GetScreenPrivate(pScreen); + if (!pPriv) + return; + kind = XF86VidModeModeChange; + for (pEv = pPriv->events; pEv; pEv = pEv->next) + { + client = pEv->client; + if (client->clientGone) + continue; + if (!(pEv->mask & mask)) + continue; + ev.type = XF86VidModeNotify + XF86VidModeEventBase; + ev.state = state; + ev.sequenceNumber = client->sequence; + ev.timestamp = currentTime.milliseconds; + ev.root = WindowTable[pScreen->myNum]->drawable.id; + ev.kind = kind; + ev.forced = forced; + WriteEventsToClient (client, 1, (xEvent *) &ev); + } +} + +static void +SXF86VidModeNotifyEvent(xXF86VidModeNotifyEvent *from, + xXF86VidModeNotifyEvent *to) +{ + to->type = from->type; + to->state = from->state; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->timestamp, to->timestamp); + cpswapl (from->root, to->root); + to->kind = from->kind; + to->forced = from->forced; +} +#endif + +static int +ProcXF86VidModeQueryVersion(ClientPtr client) +{ + xXF86VidModeQueryVersionReply rep; + register int n; + + DEBUG_P("XF86VidModeQueryVersion"); + + REQUEST_SIZE_MATCH(xXF86VidModeQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_XF86VIDMODE_MAJOR_VERSION; + rep.minorVersion = SERVER_XF86VIDMODE_MINOR_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xXF86VidModeQueryVersionReply), (char *)&rep); + return Success; +} + +static int +ProcXF86VidModeGetModeLine(ClientPtr client) +{ + REQUEST(xXF86VidModeGetModeLineReq); + xXF86VidModeGetModeLineReply rep; + xXF86OldVidModeGetModeLineReply oldrep; + pointer mode; + register int n; + int dotClock; + int ver; + + DEBUG_P("XF86VidModeGetModeline"); + + ver = ClientMajorVersion(client); + REQUEST_SIZE_MATCH(xXF86VidModeGetModeLineReq); + rep.type = X_Reply; + if (ver < 2) { + rep.length = bytes_to_int32(SIZEOF(xXF86OldVidModeGetModeLineReply) - + SIZEOF(xGenericReply)); + } else { + rep.length = bytes_to_int32(SIZEOF(xXF86VidModeGetModeLineReply) - + SIZEOF(xGenericReply)); + } + rep.sequenceNumber = client->sequence; + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) + return BadValue; + + rep.dotclock = dotClock; + rep.hdisplay = VidModeGetModeValue(mode, VIDMODE_H_DISPLAY); + rep.hsyncstart = VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART); + rep.hsyncend = VidModeGetModeValue(mode, VIDMODE_H_SYNCEND); + rep.htotal = VidModeGetModeValue(mode, VIDMODE_H_TOTAL); + rep.hskew = VidModeGetModeValue(mode, VIDMODE_H_SKEW); + rep.vdisplay = VidModeGetModeValue(mode, VIDMODE_V_DISPLAY); + rep.vsyncstart = VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART); + rep.vsyncend = VidModeGetModeValue(mode, VIDMODE_V_SYNCEND); + rep.vtotal = VidModeGetModeValue(mode, VIDMODE_V_TOTAL); + rep.flags = VidModeGetModeValue(mode, VIDMODE_FLAGS); + + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("GetModeLine - scrn: %d clock: %ld\n", + stuff->screen, (unsigned long)rep.dotclock); + ErrorF("GetModeLine - hdsp: %d hbeg: %d hend: %d httl: %d\n", + rep.hdisplay, rep.hsyncstart, + rep.hsyncend, rep.htotal); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", + rep.vdisplay, rep.vsyncstart, rep.vsyncend, + rep.vtotal, (unsigned long)rep.flags); + } + + /* + * Older servers sometimes had server privates that the VidMode + * extention made available. So to be compatiable pretend that + * there are no server privates to pass to the client + */ + rep.privsize = 0; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.dotclock, n); + swaps(&rep.hdisplay, n); + swaps(&rep.hsyncstart, n); + swaps(&rep.hsyncend, n); + swaps(&rep.htotal, n); + swaps(&rep.hskew, n); + swaps(&rep.vdisplay, n); + swaps(&rep.vsyncstart, n); + swaps(&rep.vsyncend, n); + swaps(&rep.vtotal, n); + swapl(&rep.flags, n); + swapl(&rep.privsize, n); + } + if (ver < 2) { + oldrep.type = rep.type; + oldrep.sequenceNumber = rep.sequenceNumber; + oldrep.length = rep.length; + oldrep.dotclock = rep.dotclock; + oldrep.hdisplay = rep.hdisplay; + oldrep.hsyncstart = rep.hsyncstart; + oldrep.hsyncend = rep.hsyncend; + oldrep.htotal = rep.htotal; + oldrep.vdisplay = rep.vdisplay; + oldrep.vsyncstart = rep.vsyncstart; + oldrep.vsyncend = rep.vsyncend; + oldrep.vtotal = rep.vtotal; + oldrep.flags = rep.flags; + oldrep.privsize = rep.privsize; + WriteToClient(client, sizeof(xXF86OldVidModeGetModeLineReply), + (char *)&oldrep); + } else { + WriteToClient(client, sizeof(xXF86VidModeGetModeLineReply), + (char *)&rep); + } + return Success; +} + +static int +ProcXF86VidModeGetAllModeLines(ClientPtr client) +{ + REQUEST(xXF86VidModeGetAllModeLinesReq); + xXF86VidModeGetAllModeLinesReply rep; + xXF86VidModeModeInfo mdinf; + xXF86OldVidModeModeInfo oldmdinf; + pointer mode; + int modecount, dotClock; + register int n; + int ver; + + DEBUG_P("XF86VidModeGetAllModelines"); + + REQUEST_SIZE_MATCH(xXF86VidModeGetAllModeLinesReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + ver = ClientMajorVersion(client); + + modecount = VidModeGetNumOfModes(stuff->screen); + if (modecount < 1) + return (VidModeErrorBase + XF86VidModeExtensionDisabled); + + if (!VidModeGetFirstModeline(stuff->screen, &mode, &dotClock)) + return BadValue; + + rep.type = X_Reply; + rep.length = SIZEOF(xXF86VidModeGetAllModeLinesReply) - + SIZEOF(xGenericReply); + if (ver < 2) + rep.length += modecount * sizeof(xXF86OldVidModeModeInfo); + else + rep.length += modecount * sizeof(xXF86VidModeModeInfo); + rep.length >>= 2; + rep.sequenceNumber = client->sequence; + rep.modecount = modecount; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.modecount, n); + } + WriteToClient(client, sizeof(xXF86VidModeGetAllModeLinesReply), (char *)&rep); + + do { + mdinf.dotclock = dotClock; + mdinf.hdisplay = VidModeGetModeValue(mode, VIDMODE_H_DISPLAY); + mdinf.hsyncstart = VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART); + mdinf.hsyncend = VidModeGetModeValue(mode, VIDMODE_H_SYNCEND); + mdinf.htotal = VidModeGetModeValue(mode, VIDMODE_H_TOTAL); + mdinf.hskew = VidModeGetModeValue(mode, VIDMODE_H_SKEW); + mdinf.vdisplay = VidModeGetModeValue(mode, VIDMODE_V_DISPLAY); + mdinf.vsyncstart = VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART); + mdinf.vsyncend = VidModeGetModeValue(mode, VIDMODE_V_SYNCEND); + mdinf.vtotal = VidModeGetModeValue(mode, VIDMODE_V_TOTAL); + mdinf.flags = VidModeGetModeValue(mode, VIDMODE_FLAGS); + mdinf.privsize = 0; + if (client->swapped) { + swapl(&mdinf.dotclock, n); + swaps(&mdinf.hdisplay, n); + swaps(&mdinf.hsyncstart, n); + swaps(&mdinf.hsyncend, n); + swaps(&mdinf.htotal, n); + swaps(&mdinf.hskew, n); + swaps(&mdinf.vdisplay, n); + swaps(&mdinf.vsyncstart, n); + swaps(&mdinf.vsyncend, n); + swaps(&mdinf.vtotal, n); + swapl(&mdinf.flags, n); + swapl(&mdinf.privsize, n); + } + if (ver < 2) { + oldmdinf.dotclock = mdinf.dotclock; + oldmdinf.hdisplay = mdinf.hdisplay; + oldmdinf.hsyncstart = mdinf.hsyncstart; + oldmdinf.hsyncend = mdinf.hsyncend; + oldmdinf.htotal = mdinf.htotal; + oldmdinf.vdisplay = mdinf.vdisplay; + oldmdinf.vsyncstart = mdinf.vsyncstart; + oldmdinf.vsyncend = mdinf.vsyncend; + oldmdinf.vtotal = mdinf.vtotal; + oldmdinf.flags = mdinf.flags; + oldmdinf.privsize = mdinf.privsize; + WriteToClient(client, sizeof(xXF86OldVidModeModeInfo), + (char *)&oldmdinf); + } else { + WriteToClient(client, sizeof(xXF86VidModeModeInfo), (char *)&mdinf); + } + + } while (VidModeGetNextModeline(stuff->screen, &mode, &dotClock)); + + return Success; +} + +#define MODEMATCH(mode,stuff) \ + (VidModeGetModeValue(mode, VIDMODE_H_DISPLAY) == stuff->hdisplay \ + && VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART) == stuff->hsyncstart \ + && VidModeGetModeValue(mode, VIDMODE_H_SYNCEND) == stuff->hsyncend \ + && VidModeGetModeValue(mode, VIDMODE_H_TOTAL) == stuff->htotal \ + && VidModeGetModeValue(mode, VIDMODE_V_DISPLAY) == stuff->vdisplay \ + && VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART) == stuff->vsyncstart \ + && VidModeGetModeValue(mode, VIDMODE_V_SYNCEND) == stuff->vsyncend \ + && VidModeGetModeValue(mode, VIDMODE_V_TOTAL) == stuff->vtotal \ + && VidModeGetModeValue(mode, VIDMODE_FLAGS) == stuff->flags ) + +static int +ProcXF86VidModeAddModeLine(ClientPtr client) +{ + REQUEST(xXF86VidModeAddModeLineReq); + xXF86OldVidModeAddModeLineReq *oldstuff = + (xXF86OldVidModeAddModeLineReq *)client->requestBuffer; + xXF86VidModeAddModeLineReq newstuff; + pointer mode; + int len; + int dotClock; + int ver; + + DEBUG_P("XF86VidModeAddModeline"); + + ver = ClientMajorVersion(client); + if (ver < 2) { + /* convert from old format */ + stuff = &newstuff; + stuff->length = oldstuff->length; + stuff->screen = oldstuff->screen; + stuff->dotclock = oldstuff->dotclock; + stuff->hdisplay = oldstuff->hdisplay; + stuff->hsyncstart = oldstuff->hsyncstart; + stuff->hsyncend = oldstuff->hsyncend; + stuff->htotal = oldstuff->htotal; + stuff->hskew = 0; + stuff->vdisplay = oldstuff->vdisplay; + stuff->vsyncstart = oldstuff->vsyncstart; + stuff->vsyncend = oldstuff->vsyncend; + stuff->vtotal = oldstuff->vtotal; + stuff->flags = oldstuff->flags; + stuff->privsize = oldstuff->privsize; + stuff->after_dotclock = oldstuff->after_dotclock; + stuff->after_hdisplay = oldstuff->after_hdisplay; + stuff->after_hsyncstart = oldstuff->after_hsyncstart; + stuff->after_hsyncend = oldstuff->after_hsyncend; + stuff->after_htotal = oldstuff->after_htotal; + stuff->after_hskew = 0; + stuff->after_vdisplay = oldstuff->after_vdisplay; + stuff->after_vsyncstart = oldstuff->after_vsyncstart; + stuff->after_vsyncend = oldstuff->after_vsyncend; + stuff->after_vtotal = oldstuff->after_vtotal; + stuff->after_flags = oldstuff->after_flags; + } + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("AddModeLine - scrn: %d clock: %ld\n", + (int)stuff->screen, (unsigned long)stuff->dotclock); + ErrorF("AddModeLine - hdsp: %d hbeg: %d hend: %d httl: %d\n", + stuff->hdisplay, stuff->hsyncstart, + stuff->hsyncend, stuff->htotal); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", + stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, + stuff->vtotal, (unsigned long)stuff->flags); + ErrorF(" after - scrn: %d clock: %ld\n", + (int)stuff->screen, (unsigned long)stuff->after_dotclock); + ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", + stuff->after_hdisplay, stuff->after_hsyncstart, + stuff->after_hsyncend, stuff->after_htotal); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", + stuff->after_vdisplay, stuff->after_vsyncstart, + stuff->after_vsyncend, stuff->after_vtotal, + (unsigned long)stuff->after_flags); + } + + if (ver < 2) { + REQUEST_AT_LEAST_SIZE(xXF86OldVidModeAddModeLineReq); + len = client->req_len - bytes_to_int32(sizeof(xXF86OldVidModeAddModeLineReq)); + } else { + REQUEST_AT_LEAST_SIZE(xXF86VidModeAddModeLineReq); + len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeAddModeLineReq)); + } + if (len != stuff->privsize) + return BadLength; + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if (stuff->hsyncstart < stuff->hdisplay || + stuff->hsyncend < stuff->hsyncstart || + stuff->htotal < stuff->hsyncend || + stuff->vsyncstart < stuff->vdisplay || + stuff->vsyncend < stuff->vsyncstart || + stuff->vtotal < stuff->vsyncend) + return BadValue; + + if (stuff->after_hsyncstart < stuff->after_hdisplay || + stuff->after_hsyncend < stuff->after_hsyncstart || + stuff->after_htotal < stuff->after_hsyncend || + stuff->after_vsyncstart < stuff->after_vdisplay || + stuff->after_vsyncend < stuff->after_vsyncstart || + stuff->after_vtotal < stuff->after_vsyncend) + return BadValue; + + if (stuff->after_htotal != 0 || stuff->after_vtotal != 0) { + Bool found = FALSE; + if (VidModeGetFirstModeline(stuff->screen, &mode, &dotClock)) { + do { + if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) + == dotClock) && MODEMATCH(mode, stuff)) { + found = TRUE; + break; + } + } while (VidModeGetNextModeline(stuff->screen, &mode, &dotClock)); + } + if (!found) + return BadValue; + } + + + mode = VidModeCreateMode(); + if (mode == NULL) + return BadValue; + + VidModeSetModeValue(mode, VIDMODE_CLOCK, stuff->dotclock); + VidModeSetModeValue(mode, VIDMODE_H_DISPLAY, stuff->hdisplay); + VidModeSetModeValue(mode, VIDMODE_H_SYNCSTART, stuff->hsyncstart); + VidModeSetModeValue(mode, VIDMODE_H_SYNCEND, stuff->hsyncend); + VidModeSetModeValue(mode, VIDMODE_H_TOTAL, stuff->htotal); + VidModeSetModeValue(mode, VIDMODE_H_SKEW, stuff->hskew); + VidModeSetModeValue(mode, VIDMODE_V_DISPLAY, stuff->vdisplay); + VidModeSetModeValue(mode, VIDMODE_V_SYNCSTART, stuff->vsyncstart); + VidModeSetModeValue(mode, VIDMODE_V_SYNCEND, stuff->vsyncend); + VidModeSetModeValue(mode, VIDMODE_V_TOTAL, stuff->vtotal); + VidModeSetModeValue(mode, VIDMODE_FLAGS, stuff->flags); + + if (stuff->privsize) + ErrorF("AddModeLine - Privates in request have been ignored\n"); + + /* Check that the mode is consistent with the monitor specs */ + switch (VidModeCheckModeForMonitor(stuff->screen, mode)) { + case MODE_OK: + break; + case MODE_HSYNC: + case MODE_H_ILLEGAL: + free(mode); + return VidModeErrorBase + XF86VidModeBadHTimings; + case MODE_VSYNC: + case MODE_V_ILLEGAL: + free(mode); + return VidModeErrorBase + XF86VidModeBadVTimings; + default: + free(mode); + return VidModeErrorBase + XF86VidModeModeUnsuitable; + } + + /* Check that the driver is happy with the mode */ + if (VidModeCheckModeForDriver(stuff->screen, mode) != MODE_OK) { + free(mode); + return VidModeErrorBase + XF86VidModeModeUnsuitable; + } + + VidModeSetCrtcForMode(stuff->screen, mode); + + VidModeAddModeline(stuff->screen, mode); + + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) + ErrorF("AddModeLine - Succeeded\n"); + return Success; +} + +static int +ProcXF86VidModeDeleteModeLine(ClientPtr client) +{ + REQUEST(xXF86VidModeDeleteModeLineReq); + xXF86OldVidModeDeleteModeLineReq *oldstuff = + (xXF86OldVidModeDeleteModeLineReq *)client->requestBuffer; + xXF86VidModeDeleteModeLineReq newstuff; + pointer mode; + int len, dotClock; + int ver; + + DEBUG_P("XF86VidModeDeleteModeline"); + + ver = ClientMajorVersion(client); + if (ver < 2) { + /* convert from old format */ + stuff = &newstuff; + stuff->length = oldstuff->length; + stuff->screen = oldstuff->screen; + stuff->dotclock = oldstuff->dotclock; + stuff->hdisplay = oldstuff->hdisplay; + stuff->hsyncstart = oldstuff->hsyncstart; + stuff->hsyncend = oldstuff->hsyncend; + stuff->htotal = oldstuff->htotal; + stuff->hskew = 0; + stuff->vdisplay = oldstuff->vdisplay; + stuff->vsyncstart = oldstuff->vsyncstart; + stuff->vsyncend = oldstuff->vsyncend; + stuff->vtotal = oldstuff->vtotal; + stuff->flags = oldstuff->flags; + stuff->privsize = oldstuff->privsize; + } + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("DeleteModeLine - scrn: %d clock: %ld\n", + (int)stuff->screen, (unsigned long)stuff->dotclock); + ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", + stuff->hdisplay, stuff->hsyncstart, + stuff->hsyncend, stuff->htotal); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", + stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, + stuff->vtotal, (unsigned long)stuff->flags); + } + + if (ver < 2) { + REQUEST_AT_LEAST_SIZE(xXF86OldVidModeDeleteModeLineReq); + len = client->req_len - bytes_to_int32(sizeof(xXF86OldVidModeDeleteModeLineReq)); + } else { + REQUEST_AT_LEAST_SIZE(xXF86VidModeDeleteModeLineReq); + len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeDeleteModeLineReq)); + } + if (len != stuff->privsize) { + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("req_len = %ld, sizeof(Req) = %d, privsize = %ld, " + "len = %d, length = %d\n", + (unsigned long)client->req_len, + (int)sizeof(xXF86VidModeDeleteModeLineReq)>>2, + (unsigned long)stuff->privsize, len, stuff->length); + } + return BadLength; + } + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) + return BadValue; + + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("Checking against clock: %d (%d)\n", + VidModeGetModeValue(mode, VIDMODE_CLOCK), dotClock); + ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", + VidModeGetModeValue(mode, VIDMODE_H_DISPLAY), + VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART), + VidModeGetModeValue(mode, VIDMODE_H_SYNCEND), + VidModeGetModeValue(mode, VIDMODE_H_TOTAL)); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %d\n", + VidModeGetModeValue(mode, VIDMODE_V_DISPLAY), + VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART), + VidModeGetModeValue(mode, VIDMODE_V_SYNCEND), + VidModeGetModeValue(mode, VIDMODE_V_TOTAL), + VidModeGetModeValue(mode, VIDMODE_FLAGS)); + } + if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) == dotClock) && + MODEMATCH(mode, stuff)) + return BadValue; + + if (!VidModeGetFirstModeline(stuff->screen, &mode, &dotClock)) + return BadValue; + + do { + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("Checking against clock: %d (%d)\n", + VidModeGetModeValue(mode, VIDMODE_CLOCK), dotClock); + ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", + VidModeGetModeValue(mode, VIDMODE_H_DISPLAY), + VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART), + VidModeGetModeValue(mode, VIDMODE_H_SYNCEND), + VidModeGetModeValue(mode, VIDMODE_H_TOTAL)); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %d\n", + VidModeGetModeValue(mode, VIDMODE_V_DISPLAY), + VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART), + VidModeGetModeValue(mode, VIDMODE_V_SYNCEND), + VidModeGetModeValue(mode, VIDMODE_V_TOTAL), + VidModeGetModeValue(mode, VIDMODE_FLAGS)); + } + if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) == dotClock) && + MODEMATCH(mode, stuff)) { + VidModeDeleteModeline(stuff->screen, mode); + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) + ErrorF("DeleteModeLine - Succeeded\n"); + return Success; + } + } while (VidModeGetNextModeline(stuff->screen, &mode, &dotClock)); + + return BadValue; +} + +static int +ProcXF86VidModeModModeLine(ClientPtr client) +{ + REQUEST(xXF86VidModeModModeLineReq); + xXF86OldVidModeModModeLineReq *oldstuff = + (xXF86OldVidModeModModeLineReq *)client->requestBuffer; + xXF86VidModeModModeLineReq newstuff; + pointer mode, modetmp; + int len, dotClock; + int ver; + + DEBUG_P("XF86VidModeModModeline"); + + ver = ClientMajorVersion(client); + if (ver < 2 ) { + /* convert from old format */ + stuff = &newstuff; + stuff->length = oldstuff->length; + stuff->screen = oldstuff->screen; + stuff->hdisplay = oldstuff->hdisplay; + stuff->hsyncstart = oldstuff->hsyncstart; + stuff->hsyncend = oldstuff->hsyncend; + stuff->htotal = oldstuff->htotal; + stuff->hskew = 0; + stuff->vdisplay = oldstuff->vdisplay; + stuff->vsyncstart = oldstuff->vsyncstart; + stuff->vsyncend = oldstuff->vsyncend; + stuff->vtotal = oldstuff->vtotal; + stuff->flags = oldstuff->flags; + stuff->privsize = oldstuff->privsize; + } + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("ModModeLine - scrn: %d hdsp: %d hbeg: %d hend: %d httl: %d\n", + (int)stuff->screen, stuff->hdisplay, stuff->hsyncstart, + stuff->hsyncend, stuff->htotal); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", + stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, + stuff->vtotal, (unsigned long)stuff->flags); + } + + if (ver < 2) { + REQUEST_AT_LEAST_SIZE(xXF86OldVidModeModModeLineReq); + len = client->req_len - bytes_to_int32(sizeof(xXF86OldVidModeModModeLineReq)); + } else { + REQUEST_AT_LEAST_SIZE(xXF86VidModeModModeLineReq); + len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeModModeLineReq)); + } + if (len != stuff->privsize) + return BadLength; + + if (stuff->hsyncstart < stuff->hdisplay || + stuff->hsyncend < stuff->hsyncstart || + stuff->htotal < stuff->hsyncend || + stuff->vsyncstart < stuff->vdisplay || + stuff->vsyncend < stuff->vsyncstart || + stuff->vtotal < stuff->vsyncend) + return BadValue; + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) + return BadValue; + + modetmp = VidModeCreateMode(); + VidModeCopyMode(mode, modetmp); + + VidModeSetModeValue(modetmp, VIDMODE_H_DISPLAY, stuff->hdisplay); + VidModeSetModeValue(modetmp, VIDMODE_H_SYNCSTART, stuff->hsyncstart); + VidModeSetModeValue(modetmp, VIDMODE_H_SYNCEND, stuff->hsyncend); + VidModeSetModeValue(modetmp, VIDMODE_H_TOTAL, stuff->htotal); + VidModeSetModeValue(modetmp, VIDMODE_H_SKEW, stuff->hskew); + VidModeSetModeValue(modetmp, VIDMODE_V_DISPLAY, stuff->vdisplay); + VidModeSetModeValue(modetmp, VIDMODE_V_SYNCSTART, stuff->vsyncstart); + VidModeSetModeValue(modetmp, VIDMODE_V_SYNCEND, stuff->vsyncend); + VidModeSetModeValue(modetmp, VIDMODE_V_TOTAL, stuff->vtotal); + VidModeSetModeValue(modetmp, VIDMODE_FLAGS, stuff->flags); + + if (stuff->privsize) + ErrorF("ModModeLine - Privates in request have been ignored\n"); + + /* Check that the mode is consistent with the monitor specs */ + switch (VidModeCheckModeForMonitor(stuff->screen, modetmp)) { + case MODE_OK: + break; + case MODE_HSYNC: + case MODE_H_ILLEGAL: + free(modetmp); + return VidModeErrorBase + XF86VidModeBadHTimings; + case MODE_VSYNC: + case MODE_V_ILLEGAL: + free(modetmp); + return VidModeErrorBase + XF86VidModeBadVTimings; + default: + free(modetmp); + return VidModeErrorBase + XF86VidModeModeUnsuitable; + } + + /* Check that the driver is happy with the mode */ + if (VidModeCheckModeForDriver(stuff->screen, modetmp) != MODE_OK) { + free(modetmp); + return VidModeErrorBase + XF86VidModeModeUnsuitable; + } + free(modetmp); + + VidModeSetModeValue(mode, VIDMODE_H_DISPLAY, stuff->hdisplay); + VidModeSetModeValue(mode, VIDMODE_H_SYNCSTART, stuff->hsyncstart); + VidModeSetModeValue(mode, VIDMODE_H_SYNCEND, stuff->hsyncend); + VidModeSetModeValue(mode, VIDMODE_H_TOTAL, stuff->htotal); + VidModeSetModeValue(mode, VIDMODE_H_SKEW, stuff->hskew); + VidModeSetModeValue(mode, VIDMODE_V_DISPLAY, stuff->vdisplay); + VidModeSetModeValue(mode, VIDMODE_V_SYNCSTART, stuff->vsyncstart); + VidModeSetModeValue(mode, VIDMODE_V_SYNCEND, stuff->vsyncend); + VidModeSetModeValue(mode, VIDMODE_V_TOTAL, stuff->vtotal); + VidModeSetModeValue(mode, VIDMODE_FLAGS, stuff->flags); + + VidModeSetCrtcForMode(stuff->screen, mode); + VidModeSwitchMode(stuff->screen, mode); + + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) + ErrorF("ModModeLine - Succeeded\n"); + return Success; +} + +static int +ProcXF86VidModeValidateModeLine(ClientPtr client) +{ + REQUEST(xXF86VidModeValidateModeLineReq); + xXF86OldVidModeValidateModeLineReq *oldstuff = + (xXF86OldVidModeValidateModeLineReq *)client->requestBuffer; + xXF86VidModeValidateModeLineReq newstuff; + xXF86VidModeValidateModeLineReply rep; + pointer mode, modetmp = NULL; + int len, status, dotClock; + int ver; + + DEBUG_P("XF86VidModeValidateModeline"); + + ver = ClientMajorVersion(client); + if (ver < 2) { + /* convert from old format */ + stuff = &newstuff; + stuff->length = oldstuff->length; + stuff->screen = oldstuff->screen; + stuff->dotclock = oldstuff->dotclock; + stuff->hdisplay = oldstuff->hdisplay; + stuff->hsyncstart = oldstuff->hsyncstart; + stuff->hsyncend = oldstuff->hsyncend; + stuff->htotal = oldstuff->htotal; + stuff->hskew = 0; + stuff->vdisplay = oldstuff->vdisplay; + stuff->vsyncstart = oldstuff->vsyncstart; + stuff->vsyncend = oldstuff->vsyncend; + stuff->vtotal = oldstuff->vtotal; + stuff->flags = oldstuff->flags; + stuff->privsize = oldstuff->privsize; + } + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("ValidateModeLine - scrn: %d clock: %ld\n", + (int)stuff->screen, (unsigned long)stuff->dotclock); + ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", + stuff->hdisplay, stuff->hsyncstart, + stuff->hsyncend, stuff->htotal); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", + stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, + stuff->vtotal, (unsigned long)stuff->flags); + } + + if (ver < 2) { + REQUEST_AT_LEAST_SIZE(xXF86OldVidModeValidateModeLineReq); + len = client->req_len - + bytes_to_int32(sizeof(xXF86OldVidModeValidateModeLineReq)); + } else { + REQUEST_AT_LEAST_SIZE(xXF86VidModeValidateModeLineReq); + len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeValidateModeLineReq)); + } + if (len != stuff->privsize) + return BadLength; + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + status = MODE_OK; + + if (stuff->hsyncstart < stuff->hdisplay || + stuff->hsyncend < stuff->hsyncstart || + stuff->htotal < stuff->hsyncend || + stuff->vsyncstart < stuff->vdisplay || + stuff->vsyncend < stuff->vsyncstart || + stuff->vtotal < stuff->vsyncend) + { + status = MODE_BAD; + goto status_reply; + } + + if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) + return BadValue; + + modetmp = VidModeCreateMode(); + VidModeCopyMode(mode, modetmp); + + VidModeSetModeValue(modetmp, VIDMODE_H_DISPLAY, stuff->hdisplay); + VidModeSetModeValue(modetmp, VIDMODE_H_SYNCSTART, stuff->hsyncstart); + VidModeSetModeValue(modetmp, VIDMODE_H_SYNCEND, stuff->hsyncend); + VidModeSetModeValue(modetmp, VIDMODE_H_TOTAL, stuff->htotal); + VidModeSetModeValue(modetmp, VIDMODE_H_SKEW, stuff->hskew); + VidModeSetModeValue(modetmp, VIDMODE_V_DISPLAY, stuff->vdisplay); + VidModeSetModeValue(modetmp, VIDMODE_V_SYNCSTART, stuff->vsyncstart); + VidModeSetModeValue(modetmp, VIDMODE_V_SYNCEND, stuff->vsyncend); + VidModeSetModeValue(modetmp, VIDMODE_V_TOTAL, stuff->vtotal); + VidModeSetModeValue(modetmp, VIDMODE_FLAGS, stuff->flags); + if (stuff->privsize) + ErrorF("ValidateModeLine - Privates in request have been ignored\n"); + + /* Check that the mode is consistent with the monitor specs */ + if ((status = VidModeCheckModeForMonitor(stuff->screen, modetmp)) != MODE_OK) + goto status_reply; + + /* Check that the driver is happy with the mode */ + status = VidModeCheckModeForDriver(stuff->screen, modetmp); + +status_reply: + if(modetmp) + free(modetmp); + + rep.type = X_Reply; + rep.length = bytes_to_int32(SIZEOF(xXF86VidModeValidateModeLineReply) + - SIZEOF(xGenericReply)); + rep.sequenceNumber = client->sequence; + rep.status = status; + if (client->swapped) { + register int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, sizeof(xXF86VidModeValidateModeLineReply), (char *)&rep); + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) + ErrorF("ValidateModeLine - Succeeded (status = %d)\n", status); + return Success; +} + +static int +ProcXF86VidModeSwitchMode(ClientPtr client) +{ + REQUEST(xXF86VidModeSwitchModeReq); + + DEBUG_P("XF86VidModeSwitchMode"); + + REQUEST_SIZE_MATCH(xXF86VidModeSwitchModeReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + VidModeZoomViewport(stuff->screen, (short)stuff->zoom); + + return Success; +} + +static int +ProcXF86VidModeSwitchToMode(ClientPtr client) +{ + REQUEST(xXF86VidModeSwitchToModeReq); + xXF86OldVidModeSwitchToModeReq *oldstuff = + (xXF86OldVidModeSwitchToModeReq *)client->requestBuffer; + xXF86VidModeSwitchToModeReq newstuff; + pointer mode; + int len, dotClock; + int ver; + + DEBUG_P("XF86VidModeSwitchToMode"); + + ver = ClientMajorVersion(client); + if (ver < 2) { + /* convert from old format */ + stuff = &newstuff; + stuff->length = oldstuff->length; + stuff->screen = oldstuff->screen; + stuff->dotclock = oldstuff->dotclock; + stuff->hdisplay = oldstuff->hdisplay; + stuff->hsyncstart = oldstuff->hsyncstart; + stuff->hsyncend = oldstuff->hsyncend; + stuff->htotal = oldstuff->htotal; + stuff->hskew = 0; + stuff->vdisplay = oldstuff->vdisplay; + stuff->vsyncstart = oldstuff->vsyncstart; + stuff->vsyncend = oldstuff->vsyncend; + stuff->vtotal = oldstuff->vtotal; + stuff->flags = oldstuff->flags; + stuff->privsize = oldstuff->privsize; + } + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("SwitchToMode - scrn: %d clock: %ld\n", + (int)stuff->screen, (unsigned long)stuff->dotclock); + ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", + stuff->hdisplay, stuff->hsyncstart, + stuff->hsyncend, stuff->htotal); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %ld\n", + stuff->vdisplay, stuff->vsyncstart, stuff->vsyncend, + stuff->vtotal, (unsigned long)stuff->flags); + } + + if (ver < 2) { + REQUEST_AT_LEAST_SIZE(xXF86OldVidModeSwitchToModeReq); + len = client->req_len - bytes_to_int32(sizeof(xXF86OldVidModeSwitchToModeReq)); + } else { + REQUEST_AT_LEAST_SIZE(xXF86VidModeSwitchToModeReq); + len = client->req_len - bytes_to_int32(sizeof(xXF86VidModeSwitchToModeReq)); + } + if (len != stuff->privsize) + return BadLength; + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if (!VidModeGetCurrentModeline(stuff->screen, &mode, &dotClock)) + return BadValue; + + if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) == dotClock) + && MODEMATCH(mode, stuff)) + return Success; + + if (!VidModeGetFirstModeline(stuff->screen, &mode, &dotClock)) + return BadValue; + + do { + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) { + ErrorF("Checking against clock: %d (%d)\n", + VidModeGetModeValue(mode, VIDMODE_CLOCK), dotClock); + ErrorF(" hdsp: %d hbeg: %d hend: %d httl: %d\n", + VidModeGetModeValue(mode, VIDMODE_H_DISPLAY), + VidModeGetModeValue(mode, VIDMODE_H_SYNCSTART), + VidModeGetModeValue(mode, VIDMODE_H_SYNCEND), + VidModeGetModeValue(mode, VIDMODE_H_TOTAL)); + ErrorF(" vdsp: %d vbeg: %d vend: %d vttl: %d flags: %d\n", + VidModeGetModeValue(mode, VIDMODE_V_DISPLAY), + VidModeGetModeValue(mode, VIDMODE_V_SYNCSTART), + VidModeGetModeValue(mode, VIDMODE_V_SYNCEND), + VidModeGetModeValue(mode, VIDMODE_V_TOTAL), + VidModeGetModeValue(mode, VIDMODE_FLAGS)); + } + if ((VidModeGetDotClock(stuff->screen, stuff->dotclock) == dotClock) && + MODEMATCH(mode, stuff)) { + + if (!VidModeSwitchMode(stuff->screen, mode)) + return BadValue; + + if (xf86GetVerbosity() > DEFAULT_XF86VIDMODE_VERBOSITY) + ErrorF("SwitchToMode - Succeeded\n"); + return Success; + } + } while (VidModeGetNextModeline(stuff->screen, &mode, &dotClock)); + + return BadValue; +} + +static int +ProcXF86VidModeLockModeSwitch(ClientPtr client) +{ + REQUEST(xXF86VidModeLockModeSwitchReq); + + REQUEST_SIZE_MATCH(xXF86VidModeLockModeSwitchReq); + + DEBUG_P("XF86VidModeLockModeSwitch"); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if (!VidModeLockZoom(stuff->screen, (short)stuff->lock)) + return VidModeErrorBase + XF86VidModeZoomLocked; + + return Success; +} + +static int +ProcXF86VidModeGetMonitor(ClientPtr client) +{ + REQUEST(xXF86VidModeGetMonitorReq); + xXF86VidModeGetMonitorReply rep; + register int n; + CARD32 *hsyncdata, *vsyncdata; + int i, nHsync, nVrefresh; + pointer monitor; + + DEBUG_P("XF86VidModeGetMonitor"); + + REQUEST_SIZE_MATCH(xXF86VidModeGetMonitorReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if (!VidModeGetMonitor(stuff->screen, &monitor)) + return BadValue; + + nHsync = VidModeGetMonitorValue(monitor, VIDMODE_MON_NHSYNC, 0).i; + nVrefresh = VidModeGetMonitorValue(monitor, VIDMODE_MON_NVREFRESH, 0).i; + + rep.type = X_Reply; + if ((char *)(VidModeGetMonitorValue(monitor, VIDMODE_MON_VENDOR, 0)).ptr) + rep.vendorLength = strlen((char *)(VidModeGetMonitorValue(monitor, + VIDMODE_MON_VENDOR, 0)).ptr); + else + rep.vendorLength = 0; + if ((char *)(VidModeGetMonitorValue(monitor, VIDMODE_MON_MODEL, 0)).ptr) + rep.modelLength = strlen((char *)(VidModeGetMonitorValue(monitor, + VIDMODE_MON_MODEL, 0)).ptr); + else + rep.modelLength = 0; + rep.length = bytes_to_int32(SIZEOF(xXF86VidModeGetMonitorReply) - SIZEOF(xGenericReply) + + (nHsync + nVrefresh) * sizeof(CARD32) + + pad_to_int32(rep.vendorLength) + + pad_to_int32(rep.modelLength)); + rep.sequenceNumber = client->sequence; + rep.nhsync = nHsync; + rep.nvsync = nVrefresh; + hsyncdata = malloc(nHsync * sizeof(CARD32)); + if (!hsyncdata) { + return BadAlloc; + } + + vsyncdata = malloc(nVrefresh * sizeof(CARD32)); + if (!vsyncdata) { + free(hsyncdata); + return BadAlloc; + } + + for (i = 0; i < nHsync; i++) { + hsyncdata[i] = (unsigned short)(VidModeGetMonitorValue(monitor, + VIDMODE_MON_HSYNC_LO, i)).f | + (unsigned short)(VidModeGetMonitorValue(monitor, + VIDMODE_MON_HSYNC_HI, i)).f << 16; + } + for (i = 0; i < nVrefresh; i++) { + vsyncdata[i] = (unsigned short)(VidModeGetMonitorValue(monitor, + VIDMODE_MON_VREFRESH_LO, i)).f | + (unsigned short)(VidModeGetMonitorValue(monitor, + VIDMODE_MON_VREFRESH_HI, i)).f << 16; + } + + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + WriteToClient(client, SIZEOF(xXF86VidModeGetMonitorReply), (char *)&rep); + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, nHsync * sizeof(CARD32), + hsyncdata); + WriteSwappedDataToClient(client, nVrefresh * sizeof(CARD32), + vsyncdata); + if (rep.vendorLength) + WriteToClient(client, rep.vendorLength, (char *)(VidModeGetMonitorValue(monitor, VIDMODE_MON_VENDOR, 0)).ptr); + if (rep.modelLength) + WriteToClient(client, rep.modelLength, (char *)(VidModeGetMonitorValue(monitor, VIDMODE_MON_MODEL, 0)).ptr); + + free(hsyncdata); + free(vsyncdata); + + return Success; +} + +static int +ProcXF86VidModeGetViewPort(ClientPtr client) +{ + REQUEST(xXF86VidModeGetViewPortReq); + xXF86VidModeGetViewPortReply rep; + int x, y, n; + + DEBUG_P("XF86VidModeGetViewPort"); + + REQUEST_SIZE_MATCH(xXF86VidModeGetViewPortReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + VidModeGetViewPort(stuff->screen, &x, &y); + rep.x = x; + rep.y = y; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.x, n); + swapl(&rep.y, n); + } + WriteToClient(client, SIZEOF(xXF86VidModeGetViewPortReply), (char *)&rep); + return Success; +} + +static int +ProcXF86VidModeSetViewPort(ClientPtr client) +{ + REQUEST(xXF86VidModeSetViewPortReq); + + DEBUG_P("XF86VidModeSetViewPort"); + + REQUEST_SIZE_MATCH(xXF86VidModeSetViewPortReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if (!VidModeSetViewPort(stuff->screen, stuff->x, stuff->y)) + return BadValue; + + return Success; +} + +static int +ProcXF86VidModeGetDotClocks(ClientPtr client) +{ + REQUEST(xXF86VidModeGetDotClocksReq); + xXF86VidModeGetDotClocksReply rep; + register int n; + int numClocks; + CARD32 dotclock; + int *Clocks = NULL; + Bool ClockProg; + + DEBUG_P("XF86VidModeGetDotClocks"); + + REQUEST_SIZE_MATCH(xXF86VidModeGetDotClocksReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + numClocks = VidModeGetNumOfClocks(stuff->screen, &ClockProg); + + rep.type = X_Reply; + rep.length = bytes_to_int32(SIZEOF(xXF86VidModeGetDotClocksReply) + - SIZEOF(xGenericReply) + numClocks); + rep.sequenceNumber = client->sequence; + rep.clocks = numClocks; + rep.maxclocks = MAXCLOCKS; + rep.flags = 0; + + if (!ClockProg) { + Clocks = malloc(numClocks * sizeof(int)); + if (!Clocks) + return BadValue; + if (!VidModeGetClocks(stuff->screen, Clocks)) { + free(Clocks); + return BadValue; + } + } + + if (ClockProg) { + rep.flags |= CLKFLAG_PROGRAMABLE; + } + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.clocks, n); + swapl(&rep.maxclocks, n); + swapl(&rep.flags, n); + } + WriteToClient(client, sizeof(xXF86VidModeGetDotClocksReply), (char *)&rep); + if (!ClockProg) { + for (n = 0; n < numClocks; n++) { + dotclock = *Clocks++; + if (client->swapped) { + WriteSwappedDataToClient(client, 4, (char *)&dotclock); + } else { + WriteToClient(client, 4, (char *)&dotclock); + } + } + } + + free(Clocks); + return Success; +} + +static int +ProcXF86VidModeSetGamma(ClientPtr client) +{ + REQUEST(xXF86VidModeSetGammaReq); + + DEBUG_P("XF86VidModeSetGamma"); + + REQUEST_SIZE_MATCH(xXF86VidModeSetGammaReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if (!VidModeSetGamma(stuff->screen, ((float)stuff->red)/10000., + ((float)stuff->green)/10000., ((float)stuff->blue)/10000.)) + return BadValue; + + return Success; +} + +static int +ProcXF86VidModeGetGamma(ClientPtr client) +{ + REQUEST(xXF86VidModeGetGammaReq); + xXF86VidModeGetGammaReply rep; + register int n; + float red, green, blue; + + DEBUG_P("XF86VidModeGetGamma"); + + REQUEST_SIZE_MATCH(xXF86VidModeGetGammaReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (!VidModeGetGamma(stuff->screen, &red, &green, &blue)) + return BadValue; + rep.red = (CARD32)(red * 10000.); + rep.green = (CARD32)(green * 10000.); + rep.blue = (CARD32)(blue * 10000.); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.red, n); + swapl(&rep.green, n); + swapl(&rep.blue, n); + } + WriteToClient(client, sizeof(xXF86VidModeGetGammaReply), (char *)&rep); + return Success; +} + +static int +ProcXF86VidModeSetGammaRamp(ClientPtr client) +{ + CARD16 *r, *g, *b; + int length; + REQUEST(xXF86VidModeSetGammaRampReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if(stuff->size != VidModeGetGammaRampSize(stuff->screen)) + return BadValue; + + length = (stuff->size + 1) & ~1; + + REQUEST_FIXED_SIZE(xXF86VidModeSetGammaRampReq, length * 6); + + r = (CARD16*)&stuff[1]; + g = r + length; + b = g + length; + + if (!VidModeSetGammaRamp(stuff->screen, stuff->size, r, g, b)) + return BadValue; + + return Success; +} + +static int +ProcXF86VidModeGetGammaRamp(ClientPtr client) +{ + CARD16 *ramp = NULL; + int n, length; + size_t ramplen = 0; + xXF86VidModeGetGammaRampReply rep; + REQUEST(xXF86VidModeGetGammaRampReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + if(stuff->size != VidModeGetGammaRampSize(stuff->screen)) + return BadValue; + + REQUEST_SIZE_MATCH(xXF86VidModeGetGammaRampReq); + + length = (stuff->size + 1) & ~1; + + if(stuff->size) { + ramplen = length * 3 * sizeof(CARD16); + if (!(ramp = malloc(ramplen))) + return BadAlloc; + + if (!VidModeGetGammaRamp(stuff->screen, stuff->size, + ramp, ramp + length, ramp + (length * 2))) { + free(ramp); + return BadValue; + } + } + + rep.type = X_Reply; + rep.length = (length >> 1) * 3; + rep.sequenceNumber = client->sequence; + rep.size = stuff->size; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.size, n); + SwapShorts((short*)ramp, length * 3); + } + WriteToClient(client, sizeof(xXF86VidModeGetGammaRampReply), (char *)&rep); + + if(stuff->size) { + WriteToClient(client, ramplen, (char*)ramp); + free(ramp); + } + + return Success; +} + + +static int +ProcXF86VidModeGetGammaRampSize(ClientPtr client) +{ + xXF86VidModeGetGammaRampSizeReply rep; + int n; + REQUEST(xXF86VidModeGetGammaRampSizeReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + REQUEST_SIZE_MATCH(xXF86VidModeGetGammaRampSizeReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.size = VidModeGetGammaRampSize(stuff->screen); + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.size, n); + } + WriteToClient(client,sizeof(xXF86VidModeGetGammaRampSizeReply),(char*)&rep); + + return Success; +} + +static int +ProcXF86VidModeGetPermissions(ClientPtr client) +{ + xXF86VidModeGetPermissionsReply rep; + int n; + REQUEST(xXF86VidModeGetPermissionsReq); + + if(stuff->screen >= screenInfo.numScreens) + return BadValue; + + REQUEST_SIZE_MATCH(xXF86VidModeGetPermissionsReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.permissions = XF86VM_READ_PERMISSION; + if (xf86GetVidModeEnabled() && + (xf86GetVidModeAllowNonLocal() || LocalClient (client))) { + rep.permissions |= XF86VM_WRITE_PERMISSION; + } + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.permissions, n); + } + WriteToClient(client,sizeof(xXF86VidModeGetPermissionsReply),(char*)&rep); + + return Success; +} + + +static int +ProcXF86VidModeSetClientVersion(ClientPtr client) +{ + REQUEST(xXF86VidModeSetClientVersionReq); + + VidModePrivPtr pPriv; + + DEBUG_P("XF86VidModeSetClientVersion"); + + REQUEST_SIZE_MATCH(xXF86VidModeSetClientVersionReq); + + if ((pPriv = VM_GETPRIV(client)) == NULL) { + pPriv = malloc(sizeof(VidModePrivRec)); + if (!pPriv) + return BadAlloc; + VM_SETPRIV(client, pPriv); + } + pPriv->major = stuff->major; + pPriv->minor = stuff->minor; + + return Success; +} + +static int +ProcXF86VidModeDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_XF86VidModeQueryVersion: + return ProcXF86VidModeQueryVersion(client); + case X_XF86VidModeGetModeLine: + return ProcXF86VidModeGetModeLine(client); + case X_XF86VidModeGetMonitor: + return ProcXF86VidModeGetMonitor(client); + case X_XF86VidModeGetAllModeLines: + return ProcXF86VidModeGetAllModeLines(client); + case X_XF86VidModeValidateModeLine: + return ProcXF86VidModeValidateModeLine(client); + case X_XF86VidModeGetViewPort: + return ProcXF86VidModeGetViewPort(client); + case X_XF86VidModeGetDotClocks: + return ProcXF86VidModeGetDotClocks(client); + case X_XF86VidModeSetClientVersion: + return ProcXF86VidModeSetClientVersion(client); + case X_XF86VidModeGetGamma: + return ProcXF86VidModeGetGamma(client); + case X_XF86VidModeGetGammaRamp: + return ProcXF86VidModeGetGammaRamp(client); + case X_XF86VidModeGetGammaRampSize: + return ProcXF86VidModeGetGammaRampSize(client); + case X_XF86VidModeGetPermissions: + return ProcXF86VidModeGetPermissions(client); + default: + if (!xf86GetVidModeEnabled()) + return VidModeErrorBase + XF86VidModeExtensionDisabled; + if (xf86GetVidModeAllowNonLocal() || LocalClient (client)) { + switch (stuff->data) { + case X_XF86VidModeAddModeLine: + return ProcXF86VidModeAddModeLine(client); + case X_XF86VidModeDeleteModeLine: + return ProcXF86VidModeDeleteModeLine(client); + case X_XF86VidModeModModeLine: + return ProcXF86VidModeModModeLine(client); + case X_XF86VidModeSwitchMode: + return ProcXF86VidModeSwitchMode(client); + case X_XF86VidModeSwitchToMode: + return ProcXF86VidModeSwitchToMode(client); + case X_XF86VidModeLockModeSwitch: + return ProcXF86VidModeLockModeSwitch(client); + case X_XF86VidModeSetViewPort: + return ProcXF86VidModeSetViewPort(client); + case X_XF86VidModeSetGamma: + return ProcXF86VidModeSetGamma(client); + case X_XF86VidModeSetGammaRamp: + return ProcXF86VidModeSetGammaRamp(client); + default: + return BadRequest; + } + } else + return VidModeErrorBase + XF86VidModeClientNotLocal; + } +} + +static int +SProcXF86VidModeQueryVersion(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeQueryVersionReq); + swaps(&stuff->length, n); + return ProcXF86VidModeQueryVersion(client); +} + +static int +SProcXF86VidModeGetModeLine(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeGetModeLineReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeGetModeLineReq); + swaps(&stuff->screen, n); + return ProcXF86VidModeGetModeLine(client); +} + +static int +SProcXF86VidModeGetAllModeLines(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeGetAllModeLinesReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeGetAllModeLinesReq); + swaps(&stuff->screen, n); + return ProcXF86VidModeGetAllModeLines(client); +} + +static int +SProcXF86VidModeAddModeLine(ClientPtr client) +{ + xXF86OldVidModeAddModeLineReq *oldstuff = + (xXF86OldVidModeAddModeLineReq *)client->requestBuffer; + int ver; + register int n; + + REQUEST(xXF86VidModeAddModeLineReq); + ver = ClientMajorVersion(client); + if (ver < 2) { + swaps(&oldstuff->length, n); + REQUEST_AT_LEAST_SIZE(xXF86OldVidModeAddModeLineReq); + swapl(&oldstuff->screen, n); + swaps(&oldstuff->hdisplay, n); + swaps(&oldstuff->hsyncstart, n); + swaps(&oldstuff->hsyncend, n); + swaps(&oldstuff->htotal, n); + swaps(&oldstuff->vdisplay, n); + swaps(&oldstuff->vsyncstart, n); + swaps(&oldstuff->vsyncend, n); + swaps(&oldstuff->vtotal, n); + swapl(&oldstuff->flags, n); + swapl(&oldstuff->privsize, n); + SwapRestL(oldstuff); + } else { + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXF86VidModeAddModeLineReq); + swapl(&stuff->screen, n); + swaps(&stuff->hdisplay, n); + swaps(&stuff->hsyncstart, n); + swaps(&stuff->hsyncend, n); + swaps(&stuff->htotal, n); + swaps(&stuff->hskew, n); + swaps(&stuff->vdisplay, n); + swaps(&stuff->vsyncstart, n); + swaps(&stuff->vsyncend, n); + swaps(&stuff->vtotal, n); + swapl(&stuff->flags, n); + swapl(&stuff->privsize, n); + SwapRestL(stuff); + } + return ProcXF86VidModeAddModeLine(client); +} + +static int +SProcXF86VidModeDeleteModeLine(ClientPtr client) +{ + xXF86OldVidModeDeleteModeLineReq *oldstuff = + (xXF86OldVidModeDeleteModeLineReq *)client->requestBuffer; + int ver; + register int n; + + REQUEST(xXF86VidModeDeleteModeLineReq); + ver = ClientMajorVersion(client); + if (ver < 2) { + swaps(&oldstuff->length, n); + REQUEST_AT_LEAST_SIZE(xXF86OldVidModeDeleteModeLineReq); + swapl(&oldstuff->screen, n); + swaps(&oldstuff->hdisplay, n); + swaps(&oldstuff->hsyncstart, n); + swaps(&oldstuff->hsyncend, n); + swaps(&oldstuff->htotal, n); + swaps(&oldstuff->vdisplay, n); + swaps(&oldstuff->vsyncstart, n); + swaps(&oldstuff->vsyncend, n); + swaps(&oldstuff->vtotal, n); + swapl(&oldstuff->flags, n); + swapl(&oldstuff->privsize, n); + SwapRestL(oldstuff); + } else { + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXF86VidModeDeleteModeLineReq); + swapl(&stuff->screen, n); + swaps(&stuff->hdisplay, n); + swaps(&stuff->hsyncstart, n); + swaps(&stuff->hsyncend, n); + swaps(&stuff->htotal, n); + swaps(&stuff->hskew, n); + swaps(&stuff->vdisplay, n); + swaps(&stuff->vsyncstart, n); + swaps(&stuff->vsyncend, n); + swaps(&stuff->vtotal, n); + swapl(&stuff->flags, n); + swapl(&stuff->privsize, n); + SwapRestL(stuff); + } + return ProcXF86VidModeDeleteModeLine(client); +} + +static int +SProcXF86VidModeModModeLine(ClientPtr client) +{ + xXF86OldVidModeModModeLineReq *oldstuff = + (xXF86OldVidModeModModeLineReq *)client->requestBuffer; + int ver; + register int n; + + REQUEST(xXF86VidModeModModeLineReq); + ver = ClientMajorVersion(client); + if (ver < 2) { + swaps(&oldstuff->length, n); + REQUEST_AT_LEAST_SIZE(xXF86OldVidModeModModeLineReq); + swapl(&oldstuff->screen, n); + swaps(&oldstuff->hdisplay, n); + swaps(&oldstuff->hsyncstart, n); + swaps(&oldstuff->hsyncend, n); + swaps(&oldstuff->htotal, n); + swaps(&oldstuff->vdisplay, n); + swaps(&oldstuff->vsyncstart, n); + swaps(&oldstuff->vsyncend, n); + swaps(&oldstuff->vtotal, n); + swapl(&oldstuff->flags, n); + swapl(&oldstuff->privsize, n); + SwapRestL(oldstuff); + } else { + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXF86VidModeModModeLineReq); + swapl(&stuff->screen, n); + swaps(&stuff->hdisplay, n); + swaps(&stuff->hsyncstart, n); + swaps(&stuff->hsyncend, n); + swaps(&stuff->htotal, n); + swaps(&stuff->hskew, n); + swaps(&stuff->vdisplay, n); + swaps(&stuff->vsyncstart, n); + swaps(&stuff->vsyncend, n); + swaps(&stuff->vtotal, n); + swapl(&stuff->flags, n); + swapl(&stuff->privsize, n); + SwapRestL(stuff); + } + return ProcXF86VidModeModModeLine(client); +} + +static int +SProcXF86VidModeValidateModeLine(ClientPtr client) +{ + xXF86OldVidModeValidateModeLineReq *oldstuff = + (xXF86OldVidModeValidateModeLineReq *)client->requestBuffer; + int ver; + register int n; + + REQUEST(xXF86VidModeValidateModeLineReq); + ver = ClientMajorVersion(client); + if (ver < 2) { + swaps(&oldstuff->length, n); + REQUEST_AT_LEAST_SIZE(xXF86OldVidModeValidateModeLineReq); + swapl(&oldstuff->screen, n); + swaps(&oldstuff->hdisplay, n); + swaps(&oldstuff->hsyncstart, n); + swaps(&oldstuff->hsyncend, n); + swaps(&oldstuff->htotal, n); + swaps(&oldstuff->vdisplay, n); + swaps(&oldstuff->vsyncstart, n); + swaps(&oldstuff->vsyncend, n); + swaps(&oldstuff->vtotal, n); + swapl(&oldstuff->flags, n); + swapl(&oldstuff->privsize, n); + SwapRestL(oldstuff); + } else { + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXF86VidModeValidateModeLineReq); + swapl(&stuff->screen, n); + swaps(&stuff->hdisplay, n); + swaps(&stuff->hsyncstart, n); + swaps(&stuff->hsyncend, n); + swaps(&stuff->htotal, n); + swaps(&stuff->hskew, n); + swaps(&stuff->vdisplay, n); + swaps(&stuff->vsyncstart, n); + swaps(&stuff->vsyncend, n); + swaps(&stuff->vtotal, n); + swapl(&stuff->flags, n); + swapl(&stuff->privsize, n); + SwapRestL(stuff); + } + return ProcXF86VidModeValidateModeLine(client); +} + +static int +SProcXF86VidModeSwitchMode(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeSwitchModeReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeSwitchModeReq); + swaps(&stuff->screen, n); + swaps(&stuff->zoom, n); + return ProcXF86VidModeSwitchMode(client); +} + +static int +SProcXF86VidModeSwitchToMode(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeSwitchToModeReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeSwitchToModeReq); + swaps(&stuff->screen, n); + return ProcXF86VidModeSwitchToMode(client); +} + +static int +SProcXF86VidModeLockModeSwitch(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeLockModeSwitchReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeLockModeSwitchReq); + swaps(&stuff->screen, n); + swaps(&stuff->lock, n); + return ProcXF86VidModeLockModeSwitch(client); +} + +static int +SProcXF86VidModeGetMonitor(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeGetMonitorReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeGetMonitorReq); + swaps(&stuff->screen, n); + return ProcXF86VidModeGetMonitor(client); +} + +static int +SProcXF86VidModeGetViewPort(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeGetViewPortReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeGetViewPortReq); + swaps(&stuff->screen, n); + return ProcXF86VidModeGetViewPort(client); +} + +static int +SProcXF86VidModeSetViewPort(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeSetViewPortReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeSetViewPortReq); + swaps(&stuff->screen, n); + swapl(&stuff->x, n); + swapl(&stuff->y, n); + return ProcXF86VidModeSetViewPort(client); +} + +static int +SProcXF86VidModeGetDotClocks(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeGetDotClocksReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeGetDotClocksReq); + swaps(&stuff->screen, n); + return ProcXF86VidModeGetDotClocks(client); +} + +static int +SProcXF86VidModeSetClientVersion(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeSetClientVersionReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeSetClientVersionReq); + swaps(&stuff->major, n); + swaps(&stuff->minor, n); + return ProcXF86VidModeSetClientVersion(client); +} + +static int +SProcXF86VidModeSetGamma(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeSetGammaReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeSetGammaReq); + swaps(&stuff->screen, n); + swapl(&stuff->red, n); + swapl(&stuff->green, n); + swapl(&stuff->blue, n); + return ProcXF86VidModeSetGamma(client); +} + +static int +SProcXF86VidModeGetGamma(ClientPtr client) +{ + register int n; + REQUEST(xXF86VidModeGetGammaReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeGetGammaReq); + swaps(&stuff->screen, n); + return ProcXF86VidModeGetGamma(client); +} + +static int +SProcXF86VidModeSetGammaRamp(ClientPtr client) +{ + int length, n; + REQUEST(xXF86VidModeSetGammaRampReq); + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXF86VidModeSetGammaRampReq); + swaps(&stuff->size, n); + swaps(&stuff->screen, n); + length = ((stuff->size + 1) & ~1) * 6; + REQUEST_FIXED_SIZE(xXF86VidModeSetGammaRampReq, length); + SwapRestS(stuff); + return ProcXF86VidModeSetGammaRamp(client); +} + +static int +SProcXF86VidModeGetGammaRamp(ClientPtr client) +{ + int n; + REQUEST(xXF86VidModeGetGammaRampReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeGetGammaRampReq); + swaps(&stuff->size, n); + swaps(&stuff->screen, n); + return ProcXF86VidModeGetGammaRamp(client); +} + +static int +SProcXF86VidModeGetGammaRampSize(ClientPtr client) +{ + int n; + REQUEST(xXF86VidModeGetGammaRampSizeReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeGetGammaRampSizeReq); + swaps(&stuff->screen, n); + return ProcXF86VidModeGetGammaRampSize(client); +} + +static int +SProcXF86VidModeGetPermissions(ClientPtr client) +{ + int n; + REQUEST(xXF86VidModeGetPermissionsReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xXF86VidModeGetPermissionsReq); + swaps(&stuff->screen, n); + return ProcXF86VidModeGetPermissions(client); +} + + +static int +SProcXF86VidModeDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_XF86VidModeQueryVersion: + return SProcXF86VidModeQueryVersion(client); + case X_XF86VidModeGetModeLine: + return SProcXF86VidModeGetModeLine(client); + case X_XF86VidModeGetMonitor: + return SProcXF86VidModeGetMonitor(client); + case X_XF86VidModeGetAllModeLines: + return SProcXF86VidModeGetAllModeLines(client); + case X_XF86VidModeGetViewPort: + return SProcXF86VidModeGetViewPort(client); + case X_XF86VidModeValidateModeLine: + return SProcXF86VidModeValidateModeLine(client); + case X_XF86VidModeGetDotClocks: + return SProcXF86VidModeGetDotClocks(client); + case X_XF86VidModeSetClientVersion: + return SProcXF86VidModeSetClientVersion(client); + case X_XF86VidModeGetGamma: + return SProcXF86VidModeGetGamma(client); + case X_XF86VidModeGetGammaRamp: + return SProcXF86VidModeGetGammaRamp(client); + case X_XF86VidModeGetGammaRampSize: + return SProcXF86VidModeGetGammaRampSize(client); + case X_XF86VidModeGetPermissions: + return SProcXF86VidModeGetPermissions(client); + default: + if (!xf86GetVidModeEnabled()) + return VidModeErrorBase + XF86VidModeExtensionDisabled; + if (xf86GetVidModeAllowNonLocal() || LocalClient(client)) { + switch (stuff->data) { + case X_XF86VidModeAddModeLine: + return SProcXF86VidModeAddModeLine(client); + case X_XF86VidModeDeleteModeLine: + return SProcXF86VidModeDeleteModeLine(client); + case X_XF86VidModeModModeLine: + return SProcXF86VidModeModModeLine(client); + case X_XF86VidModeSwitchMode: + return SProcXF86VidModeSwitchMode(client); + case X_XF86VidModeSwitchToMode: + return SProcXF86VidModeSwitchToMode(client); + case X_XF86VidModeLockModeSwitch: + return SProcXF86VidModeLockModeSwitch(client); + case X_XF86VidModeSetViewPort: + return SProcXF86VidModeSetViewPort(client); + case X_XF86VidModeSetGamma: + return SProcXF86VidModeSetGamma(client); + case X_XF86VidModeSetGammaRamp: + return SProcXF86VidModeSetGammaRamp(client); + default: + return BadRequest; + } + } else + return VidModeErrorBase + XF86VidModeClientNotLocal; + } +} diff --git a/xorg-server/hw/xfree86/dri/dri.c b/xorg-server/hw/xfree86/dri/dri.c index 836967c73..a8b050a94 100644 --- a/xorg-server/hw/xfree86/dri/dri.c +++ b/xorg-server/hw/xfree86/dri/dri.c @@ -1,2504 +1,2504 @@ -/************************************************************************** - -Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. -Copyright 2000 VA Linux Systems, 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, sub license, 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 NON-INFRINGEMENT. -IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. - -**************************************************************************/ - -/* - * Authors: - * Jens Owen <jens@tungstengraphics.com> - * Rickard E. (Rik) Faith <faith@valinux.com> - * - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include <sys/time.h> -#include <unistd.h> -#include <string.h> -#include <stdio.h> -#include <sys/ioctl.h> -#include <errno.h> - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "xf86drm.h" -#include "misc.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "windowstr.h" -#include "servermd.h" -#define _XF86DRI_SERVER_ -#include <X11/dri/xf86driproto.h> -#include "swaprep.h" -#include "xf86str.h" -#include "dri.h" -#include "sarea.h" -#include "dristruct.h" -#include "xf86.h" -#include "xf86drm.h" -#include "mi.h" -#include "mipointer.h" -#include "xf86_OSproc.h" -#include "inputstr.h" -#include "xf86VGAarbiter.h" - -#define PCI_BUS_NO_DOMAIN(bus) ((bus) & 0xffu) - -static int DRIEntPrivIndex = -1; -static int DRIScreenPrivKeyIndex; -static DevPrivateKey DRIScreenPrivKey = &DRIScreenPrivKeyIndex; -static int DRIWindowPrivKeyIndex; -static DevPrivateKey DRIWindowPrivKey = &DRIWindowPrivKeyIndex; -static unsigned long DRIGeneration = 0; -static unsigned int DRIDrawableValidationStamp = 0; - -static RESTYPE DRIDrawablePrivResType; -static RESTYPE DRIContextPrivResType; -static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv); - -drmServerInfo DRIDRMServerInfo; - - /* Wrapper just like xf86DrvMsg, but - without the verbosity level checking. - This will make it easy to turn off some - messages later, based on verbosity - level. */ - -/* - * Since we're already referencing things from the XFree86 common layer in - * this file, we'd might as well just call xf86VDrvMsgVerb, and have - * consistent message formatting. The verbosity of these messages can be - * easily changed here. - */ -#define DRI_MSG_VERBOSITY 1 -static void -DRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - xf86VDrvMsgVerb(scrnIndex, type, DRI_MSG_VERBOSITY, format, ap); - va_end(ap); -} - - -static void -DRIOpenDRMCleanup(DRIEntPrivPtr pDRIEntPriv) -{ - if (pDRIEntPriv->pLSAREA != NULL) { - drmUnmap(pDRIEntPriv->pLSAREA, pDRIEntPriv->sAreaSize); - pDRIEntPriv->pLSAREA = NULL; - } - if (pDRIEntPriv->hLSAREA != 0) { - drmRmMap(pDRIEntPriv->drmFD, pDRIEntPriv->hLSAREA); - } - if (pDRIEntPriv->drmFD >= 0) { - drmClose(pDRIEntPriv->drmFD); - pDRIEntPriv->drmFD = 0; - } -} - -int -DRIMasterFD(ScrnInfoPtr pScrn) -{ - return DRI_ENT_PRIV(pScrn)->drmFD; -} - -void * -DRIMasterSareaPointer(ScrnInfoPtr pScrn) -{ - return DRI_ENT_PRIV(pScrn)->pLSAREA; -} - -drm_handle_t -DRIMasterSareaHandle(ScrnInfoPtr pScrn) -{ - return DRI_ENT_PRIV(pScrn)->hLSAREA; -} - - -Bool -DRIOpenDRMMaster(ScrnInfoPtr pScrn, - unsigned long sAreaSize, - const char *busID, - const char *drmDriverName) -{ - drmSetVersion saveSv, sv; - Bool drmWasAvailable; - DRIEntPrivPtr pDRIEntPriv; - DRIEntPrivRec tmp; - drmVersionPtr drmlibv; - int drmlibmajor, drmlibminor; - const char *openBusID; - int count; - int err; - - if (DRIEntPrivIndex == -1) - DRIEntPrivIndex = xf86AllocateEntityPrivateIndex(); - - pDRIEntPriv = DRI_ENT_PRIV(pScrn); - - if (pDRIEntPriv && pDRIEntPriv->drmFD != -1) - return TRUE; - - drmWasAvailable = drmAvailable(); - - memset(&tmp, 0, sizeof(tmp)); - - /* Check the DRM lib version. - * drmGetLibVersion was not supported in version 1.0, so check for - * symbol first to avoid possible crash or hang. - */ - - drmlibmajor = 1; - drmlibminor = 0; - if (xf86LoaderCheckSymbol("drmGetLibVersion")) { - drmlibv = drmGetLibVersion(-1); - if (drmlibv != NULL) { - drmlibmajor = drmlibv->version_major; - drmlibminor = drmlibv->version_minor; - drmFreeVersion(drmlibv); - } - } - - /* Check if the libdrm can handle falling back to loading based on name - * if a busid string is passed. - */ - openBusID = (drmlibmajor == 1 && drmlibminor >= 2) ? busID : NULL; - - tmp.drmFD = -1; - sv.drm_di_major = 1; - sv.drm_di_minor = 1; - sv.drm_dd_major = -1; - - saveSv = sv; - count = 10; - while (count--) { - tmp.drmFD = drmOpen(drmDriverName, openBusID); - - if (tmp.drmFD < 0) { - DRIDrvMsg(-1, X_ERROR, "[drm] drmOpen failed.\n"); - goto out_err; - } - - err = drmSetInterfaceVersion(tmp.drmFD, &sv); - - if (err != -EPERM) - break; - - sv = saveSv; - drmClose(tmp.drmFD); - tmp.drmFD = -1; - usleep(100000); - } - - if (tmp.drmFD <= 0) { - DRIDrvMsg(-1, X_ERROR, "[drm] DRM was busy with another master.\n"); - goto out_err; - } - - if (!drmWasAvailable) { - DRIDrvMsg(-1, X_INFO, - "[drm] loaded kernel module for \"%s\" driver.\n", - drmDriverName); - } - - if (err != 0) { - sv.drm_di_major = 1; - sv.drm_di_minor = 0; - } - - DRIDrvMsg(-1, X_INFO, "[drm] DRM interface version %d.%d\n", - sv.drm_di_major, sv.drm_di_minor); - - if (sv.drm_di_major == 1 && sv.drm_di_minor >= 1) - err = 0; - else - err = drmSetBusid(tmp.drmFD, busID); - - if (err) { - DRIDrvMsg(-1, X_ERROR, "[drm] Could not set DRM device bus ID.\n"); - goto out_err; - } - - /* - * Create a lock-containing sarea. - */ - - if (drmAddMap( tmp.drmFD, 0, sAreaSize, DRM_SHM, - DRM_CONTAINS_LOCK, &tmp.hLSAREA) < 0) { - DRIDrvMsg(-1, X_INFO, "[drm] Could not create SAREA for DRM lock.\n"); - tmp.hLSAREA = 0; - goto out_err; - } - - if (drmMap( tmp.drmFD, tmp.hLSAREA, sAreaSize, - (drmAddressPtr)(&tmp.pLSAREA)) < 0) { - DRIDrvMsg(-1, X_INFO, "[drm] Mapping SAREA for DRM lock failed.\n"); - tmp.pLSAREA = NULL; - goto out_err; - } - - memset(tmp.pLSAREA, 0, sAreaSize); - - /* - * Reserved contexts are handled by the first opened screen. - */ - - tmp.resOwner = NULL; - - if (!pDRIEntPriv) - pDRIEntPriv = xnfcalloc(sizeof(*pDRIEntPriv), 1); - - if (!pDRIEntPriv) { - DRIDrvMsg(-1, X_INFO, "[drm] Failed to allocate memory for " - "DRM device.\n"); - goto out_err; - } - *pDRIEntPriv = tmp; - xf86GetEntityPrivate((pScrn)->entityList[0],DRIEntPrivIndex)->ptr = - pDRIEntPriv; - - DRIDrvMsg(-1, X_INFO, "[drm] DRM open master succeeded.\n"); - return TRUE; - - out_err: - - DRIOpenDRMCleanup(&tmp); - return FALSE; -} - -static void -DRIClipNotifyAllDrawables(ScreenPtr pScreen); - -static void -dri_crtc_notify(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIClipNotifyAllDrawables(pScreen); - xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify); - xf86_crtc_notify(pScreen); - pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen, dri_crtc_notify); -} - -Bool -DRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD) -{ - DRIScreenPrivPtr pDRIPriv; - drm_context_t * reserved; - int reserved_count; - int i; - DRIEntPrivPtr pDRIEntPriv; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - DRIContextFlags flags = 0; - DRIContextPrivPtr pDRIContextPriv; - - /* If the DRI extension is disabled, do not initialize the DRI */ - if (noXFree86DRIExtension) { - DRIDrvMsg(pScreen->myNum, X_WARNING, - "Direct rendering has been disabled.\n"); - return FALSE; - } - - if (!xf86VGAarbiterAllowDRI(pScreen)) { - DRIDrvMsg(pScreen->myNum, X_WARNING, - "Direct rendering is not supported when VGA arb is necessary for the device\n"); - return FALSE; - } - -#ifdef PANORAMIX - /* - * If Xinerama is on, don't allow DRI to initialise. It won't be usable - * anyway. - */ - if (!noPanoramiXExtension) { - DRIDrvMsg(pScreen->myNum, X_WARNING, - "Direct rendering is not supported when Xinerama is enabled\n"); - return FALSE; - } -#endif - - if (!DRIOpenDRMMaster(pScrn, pDRIInfo->SAREASize, - pDRIInfo->busIdString, - pDRIInfo->drmDriverName)) - return FALSE; - - pDRIEntPriv = DRI_ENT_PRIV(pScrn); - - if (DRIGeneration != serverGeneration) - DRIGeneration = serverGeneration; - - pDRIPriv = (DRIScreenPrivPtr) xcalloc(1, sizeof(DRIScreenPrivRec)); - if (!pDRIPriv) { - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - return FALSE; - } - - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, pDRIPriv); - pDRIPriv->drmFD = pDRIEntPriv->drmFD; - pDRIPriv->directRenderingSupport = TRUE; - pDRIPriv->pDriverInfo = pDRIInfo; - pDRIPriv->nrWindows = 0; - pDRIPriv->nrWindowsVisible = 0; - pDRIPriv->fullscreen = NULL; - - pDRIPriv->createDummyCtx = pDRIInfo->createDummyCtx; - pDRIPriv->createDummyCtxPriv = pDRIInfo->createDummyCtxPriv; - - pDRIPriv->grabbedDRILock = FALSE; - pDRIPriv->drmSIGIOHandlerInstalled = FALSE; - *pDRMFD = pDRIPriv->drmFD; - - if (pDRIEntPriv->sAreaGrabbed || pDRIInfo->allocSarea) { - - if (drmAddMap( pDRIPriv->drmFD, - 0, - pDRIPriv->pDriverInfo->SAREASize, - DRM_SHM, - 0, - &pDRIPriv->hSAREA) < 0) - { - pDRIPriv->directRenderingSupport = FALSE; - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - drmClose(pDRIPriv->drmFD); - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] drmAddMap failed\n"); - return FALSE; - } - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] added %d byte SAREA at %p\n", - pDRIPriv->pDriverInfo->SAREASize, pDRIPriv->hSAREA); - - /* Backwards compat. */ - if (drmMap( pDRIPriv->drmFD, - pDRIPriv->hSAREA, - pDRIPriv->pDriverInfo->SAREASize, - (drmAddressPtr)(&pDRIPriv->pSAREA)) < 0) - { - pDRIPriv->directRenderingSupport = FALSE; - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - drmClose(pDRIPriv->drmFD); - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] drmMap failed\n"); - return FALSE; - } - DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n", - pDRIPriv->hSAREA, pDRIPriv->pSAREA); - memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize); - } else { - DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] Using the DRM lock " - "SAREA also for drawables.\n"); - pDRIPriv->hSAREA = pDRIEntPriv->hLSAREA; - pDRIPriv->pSAREA = (XF86DRISAREAPtr) pDRIEntPriv->pLSAREA; - pDRIEntPriv->sAreaGrabbed = TRUE; - } - - pDRIPriv->hLSAREA = pDRIEntPriv->hLSAREA; - pDRIPriv->pLSAREA = pDRIEntPriv->pLSAREA; - - if (!pDRIPriv->pDriverInfo->dontMapFrameBuffer) - { - if (drmAddMap( pDRIPriv->drmFD, - (drm_handle_t)pDRIPriv->pDriverInfo->frameBufferPhysicalAddress, - pDRIPriv->pDriverInfo->frameBufferSize, - DRM_FRAME_BUFFER, - 0, - &pDRIPriv->pDriverInfo->hFrameBuffer) < 0) - { - pDRIPriv->directRenderingSupport = FALSE; - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - drmUnmap(pDRIPriv->pSAREA, pDRIPriv->pDriverInfo->SAREASize); - drmClose(pDRIPriv->drmFD); - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] drmAddMap failed\n"); - return FALSE; - } - DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = %p\n", - pDRIPriv->pDriverInfo->hFrameBuffer); - } else { - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] framebuffer mapped by ddx driver\n"); - } - - if (pDRIEntPriv->resOwner == NULL) { - pDRIEntPriv->resOwner = pScreen; - - /* Add tags for reserved contexts */ - if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD, - &reserved_count))) { - int i; - void *tag; - - for (i = 0; i < reserved_count; i++) { - tag = DRICreateContextPrivFromHandle(pScreen, - reserved[i], - DRI_CONTEXT_RESERVED); - drmAddContextTag(pDRIPriv->drmFD, reserved[i], tag); - } - drmFreeReservedContextList(reserved); - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] added %d reserved context%s for kernel\n", - reserved_count, reserved_count > 1 ? "s" : ""); - } - } - - /* validate max drawable table entry set by driver */ - if ((pDRIPriv->pDriverInfo->maxDrawableTableEntry <= 0) || - (pDRIPriv->pDriverInfo->maxDrawableTableEntry > SAREA_MAX_DRAWABLES)) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "Invalid max drawable table size set by driver: %d\n", - pDRIPriv->pDriverInfo->maxDrawableTableEntry); - } - - /* Initialize drawable tables (screen private and SAREA) */ - for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) { - pDRIPriv->DRIDrawables[i] = NULL; - pDRIPriv->pSAREA->drawableTable[i].stamp = 0; - pDRIPriv->pSAREA->drawableTable[i].flags = 0; - } - - pDRIPriv->pLockRefCount = &pDRIEntPriv->lockRefCount; - pDRIPriv->pLockingContext = &pDRIEntPriv->lockingContext; - - if (!pDRIEntPriv->keepFDOpen) - pDRIEntPriv->keepFDOpen = pDRIInfo->keepFDOpen; - - pDRIEntPriv->refCount++; - - /* Set up flags for DRICreateContextPriv */ - switch (pDRIInfo->driverSwapMethod) { - case DRI_KERNEL_SWAP: - flags = DRI_CONTEXT_2DONLY; - break; - case DRI_HIDE_X_CONTEXT: - flags = DRI_CONTEXT_PRESERVED; - break; - } - - if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, - &pDRIPriv->myContext, - flags))) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "failed to create server context\n"); - return FALSE; - } - pDRIPriv->myContextPriv = pDRIContextPriv; - - DRIDrvMsg(pScreen->myNum, X_INFO, - "X context handle = %p\n", pDRIPriv->myContext); - - /* Now that we have created the X server's context, we can grab the - * hardware lock for the X server. - */ - DRILock(pScreen, 0); - pDRIPriv->grabbedDRILock = TRUE; - - /* pointers so that we can prevent memory leaks later */ - pDRIPriv->hiddenContextStore = NULL; - pDRIPriv->partial3DContextStore = NULL; - - switch(pDRIInfo->driverSwapMethod) { - case DRI_HIDE_X_CONTEXT: - /* Server will handle 3D swaps, and hide 2D swaps from kernel. - * Register server context as a preserved context. - */ - - /* allocate memory for hidden context store */ - pDRIPriv->hiddenContextStore - = (void *)xcalloc(1, pDRIInfo->contextSize); - if (!pDRIPriv->hiddenContextStore) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "failed to allocate hidden context\n"); - DRIDestroyContextPriv(pDRIContextPriv); - return FALSE; - } - - /* allocate memory for partial 3D context store */ - pDRIPriv->partial3DContextStore - = (void *)xcalloc(1, pDRIInfo->contextSize); - if (!pDRIPriv->partial3DContextStore) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[DRI] failed to allocate partial 3D context\n"); - xfree(pDRIPriv->hiddenContextStore); - DRIDestroyContextPriv(pDRIContextPriv); - return FALSE; - } - - /* save initial context store */ - if (pDRIInfo->SwapContext) { - (*pDRIInfo->SwapContext)( - pScreen, - DRI_NO_SYNC, - DRI_2D_CONTEXT, - pDRIPriv->hiddenContextStore, - DRI_NO_CONTEXT, - NULL); - } - /* fall through */ - - case DRI_SERVER_SWAP: - /* For swap methods of DRI_SERVER_SWAP and DRI_HIDE_X_CONTEXT - * setup signal handler for receiving swap requests from kernel - */ - if (!(pDRIPriv->drmSIGIOHandlerInstalled = - drmInstallSIGIOHandler(pDRIPriv->drmFD, DRISwapContext))) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[drm] failed to setup DRM signal handler\n"); - if (pDRIPriv->hiddenContextStore) - xfree(pDRIPriv->hiddenContextStore); - if (pDRIPriv->partial3DContextStore) - xfree(pDRIPriv->partial3DContextStore); - DRIDestroyContextPriv(pDRIContextPriv); - return FALSE; - } else { - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] installed DRM signal handler\n"); - } - - default: - break; - } - - return TRUE; -} - -Bool -DRIFinishScreenInit(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; - - /* Wrap DRI support */ - if (pDRIInfo->wrap.ValidateTree) { - pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; - pScreen->ValidateTree = pDRIInfo->wrap.ValidateTree; - } - if (pDRIInfo->wrap.PostValidateTree) { - pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; - pScreen->PostValidateTree = pDRIInfo->wrap.PostValidateTree; - } - if (pDRIInfo->wrap.WindowExposures) { - pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; - pScreen->WindowExposures = pDRIInfo->wrap.WindowExposures; - } - - pDRIPriv->DestroyWindow = pScreen->DestroyWindow; - pScreen->DestroyWindow = DRIDestroyWindow; - - pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen, - dri_crtc_notify); - - if (pDRIInfo->wrap.CopyWindow) { - pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; - pScreen->CopyWindow = pDRIInfo->wrap.CopyWindow; - } - if (pDRIInfo->wrap.ClipNotify) { - pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; - pScreen->ClipNotify = pDRIInfo->wrap.ClipNotify; - } - if (pDRIInfo->wrap.AdjustFrame) { - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame; - pScrn->AdjustFrame = pDRIInfo->wrap.AdjustFrame; - } - pDRIPriv->wrapped = TRUE; - - DRIDrvMsg(pScreen->myNum, X_INFO, "[DRI] installation complete\n"); - - return TRUE; -} - -void -DRICloseScreen(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIInfoPtr pDRIInfo; - drm_context_t * reserved; - int reserved_count; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - DRIEntPrivPtr pDRIEntPriv = DRI_ENT_PRIV(pScrn); - Bool closeMaster; - - if (pDRIPriv) { - - pDRIInfo = pDRIPriv->pDriverInfo; - - if (pDRIPriv->wrapped) { - /* Unwrap DRI Functions */ - if (pDRIInfo->wrap.ValidateTree) { - pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree; - pDRIPriv->wrap.ValidateTree = NULL; - } - if (pDRIInfo->wrap.PostValidateTree) { - pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree; - pDRIPriv->wrap.PostValidateTree = NULL; - } - if (pDRIInfo->wrap.WindowExposures) { - pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures; - pDRIPriv->wrap.WindowExposures = NULL; - } - if (pDRIPriv->DestroyWindow) { - pScreen->DestroyWindow = pDRIPriv->DestroyWindow; - pDRIPriv->DestroyWindow = NULL; - } - - xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify); - - if (pDRIInfo->wrap.CopyWindow) { - pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow; - pDRIPriv->wrap.CopyWindow = NULL; - } - if (pDRIInfo->wrap.ClipNotify) { - pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify; - pDRIPriv->wrap.ClipNotify = NULL; - } - if (pDRIInfo->wrap.AdjustFrame) { - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame; - pDRIPriv->wrap.AdjustFrame = NULL; - } - - pDRIPriv->wrapped = FALSE; - } - - if (pDRIPriv->drmSIGIOHandlerInstalled) { - if (!drmRemoveSIGIOHandler(pDRIPriv->drmFD)) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[drm] failed to remove DRM signal handler\n"); - } - } - - if (pDRIPriv->dummyCtxPriv && pDRIPriv->createDummyCtx) { - DRIDestroyDummyContext(pScreen, pDRIPriv->createDummyCtxPriv); - } - - if (!DRIDestroyContextPriv(pDRIPriv->myContextPriv)) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "failed to destroy server context\n"); - } - - /* Remove tags for reserved contexts */ - if (pDRIEntPriv->resOwner == pScreen) { - pDRIEntPriv->resOwner = NULL; - - if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD, - &reserved_count))) { - int i; - - for (i = 0; i < reserved_count; i++) { - DRIDestroyContextPriv(drmGetContextTag(pDRIPriv->drmFD, - reserved[i])); - } - drmFreeReservedContextList(reserved); - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] removed %d reserved context%s for kernel\n", - reserved_count, reserved_count > 1 ? "s" : ""); - } - } - - /* Make sure signals get unblocked etc. */ - drmUnlock(pDRIPriv->drmFD, pDRIPriv->myContext); - pDRIPriv->pLockRefCount = NULL; - closeMaster = (--pDRIEntPriv->refCount == 0) && - !pDRIEntPriv->keepFDOpen; - if (closeMaster || pDRIPriv->hSAREA != pDRIEntPriv->hLSAREA) { - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] unmapping %d bytes of SAREA %p at %p\n", - pDRIInfo->SAREASize, - pDRIPriv->hSAREA, - pDRIPriv->pSAREA); - if (drmUnmap(pDRIPriv->pSAREA, pDRIInfo->SAREASize)) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[drm] unable to unmap %d bytes" - " of SAREA %p at %p\n", - pDRIInfo->SAREASize, - pDRIPriv->hSAREA, - pDRIPriv->pSAREA); - } - } else { - pDRIEntPriv->sAreaGrabbed = FALSE; - } - - if (closeMaster || (pDRIEntPriv->drmFD != pDRIPriv->drmFD)) { - drmClose(pDRIPriv->drmFD); - if (pDRIEntPriv->drmFD == pDRIPriv->drmFD) { - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] Closed DRM master.\n"); - pDRIEntPriv->drmFD = -1; - } - } - - xfree(pDRIPriv); - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - } -} - -#define DRM_MSG_VERBOSITY 3 - -static int dri_drm_debug_print(const char *format, va_list ap) -{ - xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap); - return 0; -} - -static void dri_drm_get_perms(gid_t *group, mode_t *mode) -{ - *group = xf86ConfigDRI.group; - *mode = xf86ConfigDRI.mode; -} - -drmServerInfo DRIDRMServerInfo = { - dri_drm_debug_print, - xf86LoadKernelModule, - dri_drm_get_perms, -}; - -Bool -DRIExtensionInit(void) -{ - if (!DRIScreenPrivKey || DRIGeneration != serverGeneration) { - return FALSE; - } - - DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete, - "DRIDrawable"); - DRIContextPrivResType = CreateNewResourceType(DRIContextPrivDelete, - "DRIContext"); - - if (!DRIDrawablePrivResType || !DRIContextPrivResType) - return FALSE; - - RegisterBlockAndWakeupHandlers(DRIBlockHandler, DRIWakeupHandler, NULL); - - return TRUE; -} - -void -DRIReset(void) -{ - /* - * This stub routine is called when the X Server recycles, resources - * allocated by DRIExtensionInit need to be managed here. - * - * Currently this routine is a stub because all the interesting resources - * are managed via the screen init process. - */ -} - -Bool -DRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool* isCapable) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIPriv) - *isCapable = pDRIPriv->directRenderingSupport; - else - *isCapable = FALSE; - - return TRUE; -} - -Bool -DRIOpenConnection(ScreenPtr pScreen, drm_handle_t * hSAREA, char **busIdString) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - *hSAREA = pDRIPriv->hSAREA; - *busIdString = pDRIPriv->pDriverInfo->busIdString; - - return TRUE; -} - -Bool -DRIAuthConnection(ScreenPtr pScreen, drm_magic_t magic) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (drmAuthMagic(pDRIPriv->drmFD, magic)) return FALSE; - return TRUE; -} - -Bool -DRICloseConnection(ScreenPtr pScreen) -{ - return TRUE; -} - -Bool -DRIGetClientDriverName(ScreenPtr pScreen, - int *ddxDriverMajorVersion, - int *ddxDriverMinorVersion, - int *ddxDriverPatchVersion, - char **clientDriverName) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - *ddxDriverMajorVersion = pDRIPriv->pDriverInfo->ddxDriverMajorVersion; - *ddxDriverMinorVersion = pDRIPriv->pDriverInfo->ddxDriverMinorVersion; - *ddxDriverPatchVersion = pDRIPriv->pDriverInfo->ddxDriverPatchVersion; - *clientDriverName = pDRIPriv->pDriverInfo->clientDriverName; - - return TRUE; -} - -/* DRICreateContextPriv and DRICreateContextPrivFromHandle are helper - functions that layer on drmCreateContext and drmAddContextTag. - - DRICreateContextPriv always creates a kernel drm_context_t and then calls - DRICreateContextPrivFromHandle to create a DRIContextPriv structure for - DRI tracking. For the SIGIO handler, the drm_context_t is associated with - DRIContextPrivPtr. Any special flags are stored in the DRIContextPriv - area and are passed to the kernel (if necessary). - - DRICreateContextPriv returns a pointer to newly allocated - DRIContextPriv, and returns the kernel drm_context_t in pHWContext. */ - -DRIContextPrivPtr -DRICreateContextPriv(ScreenPtr pScreen, - drm_context_t * pHWContext, - DRIContextFlags flags) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (drmCreateContext(pDRIPriv->drmFD, pHWContext)) { - return NULL; - } - - return DRICreateContextPrivFromHandle(pScreen, *pHWContext, flags); -} - -DRIContextPrivPtr -DRICreateContextPrivFromHandle(ScreenPtr pScreen, - drm_context_t hHWContext, - DRIContextFlags flags) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIContextPrivPtr pDRIContextPriv; - int contextPrivSize; - - contextPrivSize = sizeof(DRIContextPrivRec) + - pDRIPriv->pDriverInfo->contextSize; - if (!(pDRIContextPriv = xcalloc(1, contextPrivSize))) { - return NULL; - } - pDRIContextPriv->pContextStore = (void *)(pDRIContextPriv + 1); - - drmAddContextTag(pDRIPriv->drmFD, hHWContext, pDRIContextPriv); - - pDRIContextPriv->hwContext = hHWContext; - pDRIContextPriv->pScreen = pScreen; - pDRIContextPriv->flags = flags; - pDRIContextPriv->valid3D = FALSE; - - if (flags & DRI_CONTEXT_2DONLY) { - if (drmSetContextFlags(pDRIPriv->drmFD, - hHWContext, - DRM_CONTEXT_2DONLY)) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[drm] failed to set 2D context flag\n"); - DRIDestroyContextPriv(pDRIContextPriv); - return NULL; - } - } - if (flags & DRI_CONTEXT_PRESERVED) { - if (drmSetContextFlags(pDRIPriv->drmFD, - hHWContext, - DRM_CONTEXT_PRESERVED)) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[drm] failed to set preserved flag\n"); - DRIDestroyContextPriv(pDRIContextPriv); - return NULL; - } - } - return pDRIContextPriv; -} - -Bool -DRIDestroyContextPriv(DRIContextPrivPtr pDRIContextPriv) -{ - DRIScreenPrivPtr pDRIPriv; - - if (!pDRIContextPriv) return TRUE; - - pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen); - - if (!(pDRIContextPriv->flags & DRI_CONTEXT_RESERVED)) { - /* Don't delete reserved contexts from - kernel area -- the kernel manages its - reserved contexts itself. */ - if (drmDestroyContext(pDRIPriv->drmFD, pDRIContextPriv->hwContext)) - return FALSE; - } - - /* Remove the tag last to prevent a race - condition where the context has pending - buffers. The context can't be re-used - while in this thread, but buffers can be - dispatched asynchronously. */ - drmDelContextTag(pDRIPriv->drmFD, pDRIContextPriv->hwContext); - xfree(pDRIContextPriv); - return TRUE; -} - -static Bool -DRICreateDummyContext(ScreenPtr pScreen, Bool needCtxPriv) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIContextPrivPtr pDRIContextPriv; - void *contextStore; - - if (!(pDRIContextPriv = - DRICreateContextPriv(pScreen, - &pDRIPriv->pSAREA->dummy_context, 0))) { - return FALSE; - } - - contextStore = DRIGetContextStore(pDRIContextPriv); - if (pDRIPriv->pDriverInfo->CreateContext && needCtxPriv) { - if (!pDRIPriv->pDriverInfo->CreateContext(pScreen, NULL, - pDRIPriv->pSAREA->dummy_context, - NULL, - (DRIContextType)(long)contextStore)) { - DRIDestroyContextPriv(pDRIContextPriv); - return FALSE; - } - } - - pDRIPriv->dummyCtxPriv = pDRIContextPriv; - return TRUE; -} - -static void -DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIContextPrivPtr pDRIContextPriv = pDRIPriv->dummyCtxPriv; - void *contextStore; - - if (!pDRIContextPriv) return; - if (pDRIPriv->pDriverInfo->DestroyContext && hasCtxPriv) { - contextStore = DRIGetContextStore(pDRIContextPriv); - pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen, - pDRIContextPriv->hwContext, - (DRIContextType)(long)contextStore); - } - - DRIDestroyContextPriv(pDRIPriv->dummyCtxPriv); - pDRIPriv->dummyCtxPriv = NULL; -} - -Bool -DRICreateContext(ScreenPtr pScreen, VisualPtr visual, - XID context, drm_context_t * pHWContext) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIContextPrivPtr pDRIContextPriv; - void *contextStore; - - if (pDRIPriv->createDummyCtx && !pDRIPriv->dummyCtxPriv) { - if (!DRICreateDummyContext(pScreen, pDRIPriv->createDummyCtxPriv)) { - DRIDrvMsg(pScreen->myNum, X_INFO, - "[drm] Could not create dummy context\n"); - return FALSE; - } - } - - if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, pHWContext, 0))) { - return FALSE; - } - - contextStore = DRIGetContextStore(pDRIContextPriv); - if (pDRIPriv->pDriverInfo->CreateContext) { - if (!((*pDRIPriv->pDriverInfo->CreateContext)(pScreen, NULL, - *pHWContext, NULL, - (DRIContextType)(long)contextStore))) { - DRIDestroyContextPriv(pDRIContextPriv); - return FALSE; - } - } - - /* track this in case the client dies before cleanup */ - AddResource(context, DRIContextPrivResType, (pointer)pDRIContextPriv); - - return TRUE; -} - -Bool -DRIDestroyContext(ScreenPtr pScreen, XID context) -{ - FreeResourceByType(context, DRIContextPrivResType, FALSE); - - return TRUE; -} - -/* DRIContextPrivDelete is called by the resource manager. */ -Bool -DRIContextPrivDelete(pointer pResource, XID id) -{ - DRIContextPrivPtr pDRIContextPriv = (DRIContextPrivPtr)pResource; - DRIScreenPrivPtr pDRIPriv; - void *contextStore; - - pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen); - if (pDRIPriv->pDriverInfo->DestroyContext) { - contextStore = DRIGetContextStore(pDRIContextPriv); - pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen, - pDRIContextPriv->hwContext, - (DRIContextType)(long)contextStore); - } - return DRIDestroyContextPriv(pDRIContextPriv); -} - - -/* This walks the drawable timestamp array and invalidates all of them - * in the case of transition from private to shared backbuffers. It's - * not necessary for correctness, because DRIClipNotify gets called in - * time to prevent any conflict, but the transition from - * shared->private is sometimes missed if we don't do this. - */ -static void -DRIClipNotifyAllDrawables(ScreenPtr pScreen) -{ - int i; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) { - pDRIPriv->pSAREA->drawableTable[i].stamp = DRIDrawableValidationStamp++; - } -} - - -static void -DRITransitionToSharedBuffers(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; - - DRIClipNotifyAllDrawables( pScreen ); - - if (pDRIInfo->TransitionSingleToMulti3D) - pDRIInfo->TransitionSingleToMulti3D( pScreen ); -} - - -static void -DRITransitionToPrivateBuffers(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; - - DRIClipNotifyAllDrawables( pScreen ); - - if (pDRIInfo->TransitionMultiToSingle3D) - pDRIInfo->TransitionMultiToSingle3D( pScreen ); -} - - -static void -DRITransitionTo3d(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; - - DRIClipNotifyAllDrawables( pScreen ); - - if (pDRIInfo->TransitionTo3d) - pDRIInfo->TransitionTo3d( pScreen ); -} - -static void -DRITransitionTo2d(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; - - DRIClipNotifyAllDrawables( pScreen ); - - if (pDRIInfo->TransitionTo2d) - pDRIInfo->TransitionTo2d( pScreen ); -} - - -static int -DRIDCNTreeTraversal(WindowPtr pWin, pointer data) -{ - DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - - if (pDRIDrawablePriv) { - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (REGION_NUM_RECTS(&pWin->clipList) > 0) { - WindowPtr *pDRIWindows = (WindowPtr*)data; - int i = 0; - - while (pDRIWindows[i]) - i++; - - pDRIWindows[i] = pWin; - - pDRIPriv->nrWalked++; - } - - if (pDRIPriv->nrWindows == pDRIPriv->nrWalked) - return WT_STOPWALKING; - } - - return WT_WALKCHILDREN; -} - -static void -DRIDriverClipNotify(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIPriv->pDriverInfo->ClipNotify) { - WindowPtr *pDRIWindows = xcalloc(sizeof(WindowPtr), pDRIPriv->nrWindows); - DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; - - if (pDRIPriv->nrWindows > 0) { - pDRIPriv->nrWalked = 0; - TraverseTree(WindowTable[pScreen->myNum], DRIDCNTreeTraversal, - (pointer)pDRIWindows); - } - - pDRIInfo->ClipNotify(pScreen, pDRIWindows, pDRIPriv->nrWindows); - - xfree(pDRIWindows); - } -} - -static void -DRIIncreaseNumberVisible(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - switch (++pDRIPriv->nrWindowsVisible) { - case 1: - DRITransitionTo3d( pScreen ); - break; - case 2: - DRITransitionToSharedBuffers( pScreen ); - break; - default: - break; - } - - DRIDriverClipNotify(pScreen); -} - -static void -DRIDecreaseNumberVisible(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - switch (--pDRIPriv->nrWindowsVisible) { - case 0: - DRITransitionTo2d( pScreen ); - break; - case 1: - DRITransitionToPrivateBuffers( pScreen ); - break; - default: - break; - } - - DRIDriverClipNotify(pScreen); -} - -Bool -DRICreateDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable, - drm_drawable_t * hHWDrawable) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIDrawablePrivPtr pDRIDrawablePriv; - WindowPtr pWin; - - if (pDrawable->type == DRAWABLE_WINDOW) { - pWin = (WindowPtr)pDrawable; - if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { - pDRIDrawablePriv->refCount++; - - if (!pDRIDrawablePriv->hwDrawable) { - drmCreateDrawable(pDRIPriv->drmFD, &pDRIDrawablePriv->hwDrawable); - } - } - else { - /* allocate a DRI Window Private record */ - if (!(pDRIDrawablePriv = xalloc(sizeof(DRIDrawablePrivRec)))) { - return FALSE; - } - - /* Only create a drm_drawable_t once */ - if (drmCreateDrawable(pDRIPriv->drmFD, - &pDRIDrawablePriv->hwDrawable)) { - xfree(pDRIDrawablePriv); - return FALSE; - } - - /* add it to the list of DRI drawables for this screen */ - pDRIDrawablePriv->pScreen = pScreen; - pDRIDrawablePriv->refCount = 1; - pDRIDrawablePriv->drawableIndex = -1; - pDRIDrawablePriv->nrects = REGION_NUM_RECTS(&pWin->clipList); - - /* save private off of preallocated index */ - dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, - pDRIDrawablePriv); - pDRIPriv->nrWindows++; - - if (pDRIDrawablePriv->nrects) - DRIIncreaseNumberVisible(pScreen); - } - - /* track this in case the client dies */ - AddResource(FakeClientID(client->index), DRIDrawablePrivResType, - (pointer)(intptr_t)pDrawable->id); - - if (pDRIDrawablePriv->hwDrawable) { - drmUpdateDrawableInfo(pDRIPriv->drmFD, - pDRIDrawablePriv->hwDrawable, - DRM_DRAWABLE_CLIPRECTS, - REGION_NUM_RECTS(&pWin->clipList), - REGION_RECTS(&pWin->clipList)); - *hHWDrawable = pDRIDrawablePriv->hwDrawable; - } - } - else if (pDrawable->type != DRAWABLE_PIXMAP) { /* PBuffer */ - /* NOT_DONE */ - return FALSE; - } - - return TRUE; -} - -static void -DRIDrawablePrivDestroy(WindowPtr pWin) -{ - DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - ScreenPtr pScreen; - DRIScreenPrivPtr pDRIPriv; - - if (!pDRIDrawablePriv) - return; - - pScreen = pWin->drawable.pScreen; - pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIDrawablePriv->drawableIndex != -1) { - /* bump stamp to force outstanding 3D requests to resync */ - pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp - = DRIDrawableValidationStamp++; - - /* release drawable table entry */ - pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL; - } - - pDRIPriv->nrWindows--; - - if (pDRIDrawablePriv->nrects) - DRIDecreaseNumberVisible(pScreen); - - drmDestroyDrawable(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable); - - xfree(pDRIDrawablePriv); - dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL); -} - -static Bool -DRIDestroyDrawableCB(pointer value, XID id, pointer data) -{ - if (value == data) { - /* This calls back DRIDrawablePrivDelete which frees private area */ - FreeResourceByType(id, DRIDrawablePrivResType, FALSE); - - return TRUE; - } - - return FALSE; -} - -Bool -DRIDestroyDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable) -{ - if (pDrawable->type == DRAWABLE_WINDOW) { - LookupClientResourceComplex(client, DRIDrawablePrivResType, - DRIDestroyDrawableCB, - (pointer)(intptr_t)pDrawable->id); - } - else { /* pixmap (or for GLX 1.3, a PBuffer) */ - /* NOT_DONE */ - return FALSE; - } - - return TRUE; -} - -Bool -DRIDrawablePrivDelete(pointer pResource, XID id) -{ - WindowPtr pWin; - int rc; - - /* For DRIDrawablePrivResType, the XID is the client's fake ID. The - * important XID is the value in pResource. */ - id = (XID)(intptr_t)pResource; - rc = dixLookupWindow(&pWin, id, serverClient, DixGetAttrAccess); - - if (rc == Success) { - DRIDrawablePrivPtr pDRIDrwPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - - if (!pDRIDrwPriv) - return FALSE; - - if (--pDRIDrwPriv->refCount == 0) - DRIDrawablePrivDestroy(pWin); - - return TRUE; - } - else { /* pixmap (or for GLX 1.3, a PBuffer) */ - /* NOT_DONE */ - return FALSE; - } -} - -Bool -DRIGetDrawableInfo(ScreenPtr pScreen, - DrawablePtr pDrawable, - unsigned int* index, - unsigned int* stamp, - int* X, - int* Y, - int* W, - int* H, - int* numClipRects, - drm_clip_rect_t ** pClipRects, - int* backX, - int* backY, - int* numBackClipRects, - drm_clip_rect_t ** pBackClipRects) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIDrawablePrivPtr pDRIDrawablePriv, pOldDrawPriv; - WindowPtr pWin, pOldWin; - int i; - -#if 0 - printf("maxDrawableTableEntry = %d\n", pDRIPriv->pDriverInfo->maxDrawableTableEntry); -#endif - - if (pDrawable->type == DRAWABLE_WINDOW) { - pWin = (WindowPtr)pDrawable; - if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { - - /* Manage drawable table */ - if (pDRIDrawablePriv->drawableIndex == -1) { /* load SAREA table */ - - /* Search table for empty entry */ - i = 0; - while (i < pDRIPriv->pDriverInfo->maxDrawableTableEntry) { - if (!(pDRIPriv->DRIDrawables[i])) { - pDRIPriv->DRIDrawables[i] = pDrawable; - pDRIDrawablePriv->drawableIndex = i; - pDRIPriv->pSAREA->drawableTable[i].stamp = - DRIDrawableValidationStamp++; - break; - } - i++; - } - - /* Search table for oldest entry */ - if (i == pDRIPriv->pDriverInfo->maxDrawableTableEntry) { - unsigned int oldestStamp = ~0; - int oldestIndex = 0; - i = pDRIPriv->pDriverInfo->maxDrawableTableEntry; - while (i--) { - if (pDRIPriv->pSAREA->drawableTable[i].stamp < - oldestStamp) { - oldestIndex = i; - oldestStamp = - pDRIPriv->pSAREA->drawableTable[i].stamp; - } - } - pDRIDrawablePriv->drawableIndex = oldestIndex; - - /* release oldest drawable table entry */ - pOldWin = (WindowPtr)pDRIPriv->DRIDrawables[oldestIndex]; - pOldDrawPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pOldWin); - pOldDrawPriv->drawableIndex = -1; - - /* claim drawable table entry */ - pDRIPriv->DRIDrawables[oldestIndex] = pDrawable; - - /* validate SAREA entry */ - pDRIPriv->pSAREA->drawableTable[oldestIndex].stamp = - DRIDrawableValidationStamp++; - - /* check for stamp wrap around */ - if (oldestStamp > DRIDrawableValidationStamp) { - - /* walk SAREA table and invalidate all drawables */ - for( i=0; - i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; - i++) { - pDRIPriv->pSAREA->drawableTable[i].stamp = - DRIDrawableValidationStamp++; - } - } - } - - /* If the driver wants to be notified when the index is - * set for a drawable, let it know now. - */ - if (pDRIPriv->pDriverInfo->SetDrawableIndex) - pDRIPriv->pDriverInfo->SetDrawableIndex(pWin, - pDRIDrawablePriv->drawableIndex); - - /* reinit drawable ID if window is visible */ - if ((pWin->viewable) && - (pDRIPriv->pDriverInfo->bufferRequests != DRI_NO_WINDOWS)) - { - (*pDRIPriv->pDriverInfo->InitBuffers)(pWin, - &pWin->clipList, pDRIDrawablePriv->drawableIndex); - } - } - - *index = pDRIDrawablePriv->drawableIndex; - *stamp = pDRIPriv->pSAREA->drawableTable[*index].stamp; - *X = (int)(pWin->drawable.x); - *Y = (int)(pWin->drawable.y); -#if 0 - *W = (int)(pWin->winSize.extents.x2 - pWin->winSize.extents.x1); - *H = (int)(pWin->winSize.extents.y2 - pWin->winSize.extents.y1); -#endif - *W = (int)(pWin->drawable.width); - *H = (int)(pWin->drawable.height); - *numClipRects = REGION_NUM_RECTS(&pWin->clipList); - *pClipRects = (drm_clip_rect_t *)REGION_RECTS(&pWin->clipList); - - if (!*numClipRects && pDRIPriv->fullscreen) { - /* use fake full-screen clip rect */ - pDRIPriv->fullscreen_rect.x1 = *X; - pDRIPriv->fullscreen_rect.y1 = *Y; - pDRIPriv->fullscreen_rect.x2 = *X + *W; - pDRIPriv->fullscreen_rect.y2 = *Y + *H; - - *numClipRects = 1; - *pClipRects = &pDRIPriv->fullscreen_rect; - } - - *backX = *X; - *backY = *Y; - - if (pDRIPriv->nrWindowsVisible == 1 && *numClipRects) { - /* Use a single cliprect. */ - - int x0 = *X; - int y0 = *Y; - int x1 = x0 + *W; - int y1 = y0 + *H; - - if (x0 < 0) x0 = 0; - if (y0 < 0) y0 = 0; - if (x1 > pScreen->width) x1 = pScreen->width; - if (y1 > pScreen->height) y1 = pScreen->height; - - if (y0 >= y1 || x0 >= x1) { - *numBackClipRects = 0; - *pBackClipRects = NULL; - } else { - pDRIPriv->private_buffer_rect.x1 = x0; - pDRIPriv->private_buffer_rect.y1 = y0; - pDRIPriv->private_buffer_rect.x2 = x1; - pDRIPriv->private_buffer_rect.y2 = y1; - - *numBackClipRects = 1; - *pBackClipRects = &(pDRIPriv->private_buffer_rect); - } - } else { - /* Use the frontbuffer cliprects for back buffers. */ - *numBackClipRects = 0; - *pBackClipRects = 0; - } - } - else { - /* Not a DRIDrawable */ - return FALSE; - } - } - else { /* pixmap (or for GLX 1.3, a PBuffer) */ - /* NOT_DONE */ - return FALSE; - } - - return TRUE; -} - -Bool -DRIGetDeviceInfo(ScreenPtr pScreen, - drm_handle_t * hFrameBuffer, - int* fbOrigin, - int* fbSize, - int* fbStride, - int* devPrivateSize, - void** pDevPrivate) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - *hFrameBuffer = pDRIPriv->pDriverInfo->hFrameBuffer; - *fbOrigin = 0; - *fbSize = pDRIPriv->pDriverInfo->frameBufferSize; - *fbStride = pDRIPriv->pDriverInfo->frameBufferStride; - *devPrivateSize = pDRIPriv->pDriverInfo->devPrivateSize; - *pDevPrivate = pDRIPriv->pDriverInfo->devPrivate; - - return TRUE; -} - -DRIInfoPtr -DRICreateInfoRec(void) -{ - DRIInfoPtr inforec = (DRIInfoPtr)xcalloc(1, sizeof(DRIInfoRec)); - if (!inforec) return NULL; - - /* Initialize defaults */ - inforec->busIdString = NULL; - - /* Wrapped function defaults */ - inforec->wrap.WakeupHandler = DRIDoWakeupHandler; - inforec->wrap.BlockHandler = DRIDoBlockHandler; - inforec->wrap.WindowExposures = DRIWindowExposures; - inforec->wrap.CopyWindow = DRICopyWindow; - inforec->wrap.ValidateTree = DRIValidateTree; - inforec->wrap.PostValidateTree = DRIPostValidateTree; - inforec->wrap.ClipNotify = DRIClipNotify; - inforec->wrap.AdjustFrame = DRIAdjustFrame; - - inforec->TransitionTo2d = 0; - inforec->TransitionTo3d = 0; - inforec->SetDrawableIndex = 0; - - return inforec; -} - -void -DRIDestroyInfoRec(DRIInfoPtr DRIInfo) -{ - if (DRIInfo->busIdString) xfree(DRIInfo->busIdString); - xfree((char*)DRIInfo); -} - - -void -DRIWakeupHandler(pointer wakeupData, int result, pointer pReadmask) -{ - int i; - - for (i = 0; i < screenInfo.numScreens; i++) { - ScreenPtr pScreen = screenInfo.screens[i]; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIPriv && - pDRIPriv->pDriverInfo->wrap.WakeupHandler) - (*pDRIPriv->pDriverInfo->wrap.WakeupHandler)(i, wakeupData, - result, pReadmask); - } -} - -void -DRIBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask) -{ - int i; - - for (i = 0; i < screenInfo.numScreens; i++) { - ScreenPtr pScreen = screenInfo.screens[i]; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIPriv && - pDRIPriv->pDriverInfo->wrap.BlockHandler) - (*pDRIPriv->pDriverInfo->wrap.BlockHandler)(i, blockData, - pTimeout, pReadmask); - } -} - -void -DRIDoWakeupHandler(int screenNum, pointer wakeupData, - unsigned long result, pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[screenNum]; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - DRILock(pScreen, 0); - if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { - /* hide X context by swapping 2D component here */ - (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, - DRI_3D_SYNC, - DRI_2D_CONTEXT, - pDRIPriv->partial3DContextStore, - DRI_2D_CONTEXT, - pDRIPriv->hiddenContextStore); - } -} - -void -DRIDoBlockHandler(int screenNum, pointer blockData, - pointer pTimeout, pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[screenNum]; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { - /* hide X context by swapping 2D component here */ - (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, - DRI_2D_SYNC, - DRI_NO_CONTEXT, - NULL, - DRI_2D_CONTEXT, - pDRIPriv->partial3DContextStore); - } - - if (pDRIPriv->windowsTouched) - DRM_SPINUNLOCK(&pDRIPriv->pSAREA->drawable_lock, 1); - pDRIPriv->windowsTouched = FALSE; - - DRIUnlock(pScreen); -} - -void -DRISwapContext(int drmFD, void *oldctx, void *newctx) -{ - DRIContextPrivPtr oldContext = (DRIContextPrivPtr)oldctx; - DRIContextPrivPtr newContext = (DRIContextPrivPtr)newctx; - ScreenPtr pScreen = newContext->pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - void* oldContextStore = NULL; - DRIContextType oldContextType; - void* newContextStore = NULL; - DRIContextType newContextType; - DRISyncType syncType; -#ifdef DEBUG - static int count = 0; - - if (!newContext) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[DRI] Context Switch Error: oldContext=%x, newContext=%x\n", - oldContext, newContext); - return; - } - - /* usefull for debugging, just print out after n context switches */ - if (!count || !(count % 1)) { - DRIDrvMsg(pScreen->myNum, X_INFO, - "[DRI] Context switch %5d from %p/0x%08x (%d)\n", - count, - oldContext, - oldContext ? oldContext->flags : 0, - oldContext ? oldContext->hwContext : -1); - DRIDrvMsg(pScreen->myNum, X_INFO, - "[DRI] Context switch %5d to %p/0x%08x (%d)\n", - count, - newContext, - newContext ? newContext->flags : 0, - newContext ? newContext->hwContext : -1); - } - ++count; -#endif - - if (!pDRIPriv->pDriverInfo->SwapContext) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[DRI] DDX driver missing context swap call back\n"); - return; - } - - if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { - - /* only 3D contexts are swapped in this case */ - if (oldContext) { - oldContextStore = DRIGetContextStore(oldContext); - oldContext->valid3D = TRUE; - oldContextType = DRI_3D_CONTEXT; - } else { - oldContextType = DRI_NO_CONTEXT; - } - newContextStore = DRIGetContextStore(newContext); - if ((newContext->valid3D) && - (newContext->hwContext != pDRIPriv->myContext)) { - newContextType = DRI_3D_CONTEXT; - } - else { - newContextType = DRI_2D_CONTEXT; - } - syncType = DRI_3D_SYNC; - } - else /* default: driverSwapMethod == DRI_SERVER_SWAP */ { - - /* optimize 2D context swaps */ - - if (newContext->flags & DRI_CONTEXT_2DONLY) { - /* go from 3D context to 2D context and only save 2D - * subset of 3D state - */ - oldContextStore = DRIGetContextStore(oldContext); - oldContextType = DRI_2D_CONTEXT; - newContextStore = DRIGetContextStore(newContext); - newContextType = DRI_2D_CONTEXT; - syncType = DRI_3D_SYNC; - pDRIPriv->lastPartial3DContext = oldContext; - } - else if (oldContext->flags & DRI_CONTEXT_2DONLY) { - if (pDRIPriv->lastPartial3DContext == newContext) { - /* go from 2D context back to previous 3D context and - * only restore 2D subset of previous 3D state - */ - oldContextStore = DRIGetContextStore(oldContext); - oldContextType = DRI_2D_CONTEXT; - newContextStore = DRIGetContextStore(newContext); - newContextType = DRI_2D_CONTEXT; - syncType = DRI_2D_SYNC; - } - else { - /* go from 2D context to a different 3D context */ - - /* call DDX driver to do partial restore */ - oldContextStore = DRIGetContextStore(oldContext); - newContextStore = - DRIGetContextStore(pDRIPriv->lastPartial3DContext); - (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, - DRI_2D_SYNC, - DRI_2D_CONTEXT, - oldContextStore, - DRI_2D_CONTEXT, - newContextStore); - - /* now setup for a complete 3D swap */ - oldContextStore = newContextStore; - oldContext->valid3D = TRUE; - oldContextType = DRI_3D_CONTEXT; - newContextStore = DRIGetContextStore(newContext); - if ((newContext->valid3D) && - (newContext->hwContext != pDRIPriv->myContext)) { - newContextType = DRI_3D_CONTEXT; - } - else { - newContextType = DRI_2D_CONTEXT; - } - syncType = DRI_NO_SYNC; - } - } - else { - /* now setup for a complete 3D swap */ - oldContextStore = newContextStore; - oldContext->valid3D = TRUE; - oldContextType = DRI_3D_CONTEXT; - newContextStore = DRIGetContextStore(newContext); - if ((newContext->valid3D) && - (newContext->hwContext != pDRIPriv->myContext)) { - newContextType = DRI_3D_CONTEXT; - } - else { - newContextType = DRI_2D_CONTEXT; - } - syncType = DRI_3D_SYNC; - } - } - - /* call DDX driver to perform the swap */ - (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, - syncType, - oldContextType, - oldContextStore, - newContextType, - newContextStore); -} - -void* -DRIGetContextStore(DRIContextPrivPtr context) -{ - return((void *)context->pContextStore); -} - -void -DRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - - if(pDRIDrawablePriv) { - (*pDRIPriv->pDriverInfo->InitBuffers)(pWin, prgn, - pDRIDrawablePriv->drawableIndex); - } - - /* call lower wrapped functions */ - if (pDRIPriv && pDRIPriv->wrap.WindowExposures) { - - /* unwrap */ - pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures; - - /* call lower layers */ - (*pScreen->WindowExposures)(pWin, prgn, bsreg); - - /* rewrap */ - pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; - pScreen->WindowExposures = DRIWindowExposures; - } -} - - -static int -DRITreeTraversal(WindowPtr pWin, pointer data) -{ - DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - - if(pDRIDrawablePriv) { - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if(REGION_NUM_RECTS(&(pWin->clipList)) > 0) { - RegionPtr reg = (RegionPtr)data; - - REGION_UNION(pScreen, reg, reg, &(pWin->clipList)); - pDRIPriv->nrWalked++; - } - - if(pDRIPriv->nrWindows == pDRIPriv->nrWalked) - return WT_STOPWALKING; - } - return WT_WALKCHILDREN; -} - -Bool -DRIDestroyWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - Bool retval = TRUE; - - DRIDrawablePrivDestroy(pWin); - - /* call lower wrapped functions */ - if(pDRIPriv->DestroyWindow) { - /* unwrap */ - pScreen->DestroyWindow = pDRIPriv->DestroyWindow; - - /* call lower layers */ - retval = (*pScreen->DestroyWindow)(pWin); - - /* rewrap */ - pDRIPriv->DestroyWindow = pScreen->DestroyWindow; - pScreen->DestroyWindow = DRIDestroyWindow; - } - - return retval; -} - -void -DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if(!pDRIPriv) return; - - if(pDRIPriv->nrWindowsVisible > 0) { - RegionRec reg; - - REGION_NULL(pScreen, ®); - pDRIPriv->nrWalked = 0; - TraverseTree(pWin, DRITreeTraversal, (pointer)(®)); - - if(REGION_NOTEMPTY(pScreen, ®)) { - REGION_TRANSLATE(pScreen, ®, ptOldOrg.x - pWin->drawable.x, - ptOldOrg.y - pWin->drawable.y); - REGION_INTERSECT(pScreen, ®, ®, prgnSrc); - - /* The MoveBuffers interface is not ideal */ - (*pDRIPriv->pDriverInfo->MoveBuffers)(pWin, ptOldOrg, ®, - pDRIPriv->pDriverInfo->ddxDrawableTableEntry); - } - - REGION_UNINIT(pScreen, ®); - } - - /* call lower wrapped functions */ - if(pDRIPriv->wrap.CopyWindow) { - /* unwrap */ - pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow; - - /* call lower layers */ - (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); - - /* rewrap */ - pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; - pScreen->CopyWindow = DRICopyWindow; - } -} - -static void -DRIGetSecs(long *secs, long *usecs) -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - - *secs = tv.tv_sec; - *usecs = tv.tv_usec; -} - -static unsigned long -DRIComputeMilliSeconds(unsigned long s_secs, unsigned long s_usecs, - unsigned long f_secs, unsigned long f_usecs) -{ - if (f_usecs < s_usecs) { - --f_secs; - f_usecs += 1000000; - } - return (f_secs - s_secs) * 1000 + (f_usecs - s_usecs) / 1000; -} - -static void -DRISpinLockTimeout(drmLock *lock, int val, unsigned long timeout /* in mS */) -{ - int count = 10000; -#if !defined(__alpha__) && !defined(__powerpc__) - char ret; -#else - int ret; -#endif - long s_secs, s_usecs; - long f_secs, f_usecs; - long msecs; - long prev = 0; - - DRIGetSecs(&s_secs, &s_usecs); - - do { - DRM_SPINLOCK_COUNT(lock, val, count, ret); - if (!ret) return; /* Got lock */ - DRIGetSecs(&f_secs, &f_usecs); - msecs = DRIComputeMilliSeconds(s_secs, s_usecs, f_secs, f_usecs); - if (msecs - prev < 250) count *= 2; /* Not more than 0.5S */ - } while (msecs < timeout); - - /* Didn't get lock, so take it. The worst - that can happen is that there is some - garbage written to the wrong part of the - framebuffer that a refresh will repair. - That's undesirable, but better than - locking the server. This should be a - very rare event. */ - DRM_SPINLOCK_TAKE(lock, val); -} - -static void -DRILockTree(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if(!pDRIPriv) return; - - /* Restore the last known 3D context if the X context is hidden */ - if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { - (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, - DRI_2D_SYNC, - DRI_NO_CONTEXT, - NULL, - DRI_2D_CONTEXT, - pDRIPriv->partial3DContextStore); - } - - /* Call kernel to release lock */ - DRIUnlock(pScreen); - - /* Grab drawable spin lock: a time out between 10 and 30 seconds is - appropriate, since this should never time out except in the case of - client death while the lock is being held. The timeout must be - greater than any reasonable rendering time. */ - DRISpinLockTimeout(&pDRIPriv->pSAREA->drawable_lock, 1, 10000); /*10 secs*/ - - /* Call kernel flush outstanding buffers and relock */ - DRILock(pScreen, DRM_LOCK_QUIESCENT|DRM_LOCK_FLUSH_ALL); - - /* Switch back to our 2D context if the X context is hidden */ - if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { - /* hide X context by swapping 2D component here */ - (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, - DRI_3D_SYNC, - DRI_2D_CONTEXT, - pDRIPriv->partial3DContextStore, - DRI_2D_CONTEXT, - pDRIPriv->hiddenContextStore); - } -} - -int -DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) -{ - ScreenPtr pScreen = pParent->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - int returnValue = 1; /* always return 1, not checked by dix/window.c */ - - if(!pDRIPriv) return returnValue; - - /* call lower wrapped functions */ - if(pDRIPriv->wrap.ValidateTree) { - /* unwrap */ - pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree; - - /* call lower layers */ - returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind); - - /* rewrap */ - pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; - pScreen->ValidateTree = DRIValidateTree; - } - - return returnValue; -} - -void -DRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) -{ - ScreenPtr pScreen; - DRIScreenPrivPtr pDRIPriv; - - if (pParent) { - pScreen = pParent->drawable.pScreen; - } else { - pScreen = pChild->drawable.pScreen; - } - if(!(pDRIPriv = DRI_SCREEN_PRIV(pScreen))) return; - - if (pDRIPriv->wrap.PostValidateTree) { - /* unwrap */ - pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree; - - /* call lower layers */ - (*pScreen->PostValidateTree)(pParent, pChild, kind); - - /* rewrap */ - pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; - pScreen->PostValidateTree = DRIPostValidateTree; - } -} - -void -DRIClipNotify(WindowPtr pWin, int dx, int dy) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIDrawablePrivPtr pDRIDrawablePriv; - - if(!pDRIPriv) return; - - if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { - int nrects = REGION_NUM_RECTS(&pWin->clipList); - - if(!pDRIPriv->windowsTouched) { - DRILockTree(pScreen); - pDRIPriv->windowsTouched = TRUE; - } - - if (nrects && !pDRIDrawablePriv->nrects) - DRIIncreaseNumberVisible(pScreen); - else if (!nrects && pDRIDrawablePriv->nrects) - DRIDecreaseNumberVisible(pScreen); - else - DRIDriverClipNotify(pScreen); - - pDRIDrawablePriv->nrects = nrects; - - pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp - = DRIDrawableValidationStamp++; - - drmUpdateDrawableInfo(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable, - DRM_DRAWABLE_CLIPRECTS, - nrects, REGION_RECTS(&pWin->clipList)); - } - - /* call lower wrapped functions */ - if(pDRIPriv->wrap.ClipNotify) { - - /* unwrap */ - pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify; - - /* call lower layers */ - (*pScreen->ClipNotify)(pWin, dx, dy); - - /* rewrap */ - pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; - pScreen->ClipNotify = DRIClipNotify; - } -} - -CARD32 -DRIGetDrawableIndex(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - CARD32 index; - - if (pDRIDrawablePriv) { - index = pDRIDrawablePriv->drawableIndex; - } - else { - index = pDRIPriv->pDriverInfo->ddxDrawableTableEntry; - } - - return index; -} - -unsigned int -DRIGetDrawableStamp(ScreenPtr pScreen, CARD32 drawable_index) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - return pDRIPriv->pSAREA->drawableTable[drawable_index].stamp; -} - - -void -DRIPrintDrawableLock(ScreenPtr pScreen, char *msg) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - ErrorF("%s: %d\n", msg, pDRIPriv->pSAREA->drawable_lock.lock); -} - -void -DRILock(ScreenPtr pScreen, int flags) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if(!pDRIPriv || !pDRIPriv->pLockRefCount) return; - - if (!*pDRIPriv->pLockRefCount) { - DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext, flags); - *pDRIPriv->pLockingContext = pDRIPriv->myContext; - } else if (*pDRIPriv->pLockingContext != pDRIPriv->myContext) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[DRI] Locking deadlock.\n" - "\tAlready locked with context %d,\n" - "\ttrying to lock with context %d.\n", - pDRIPriv->pLockingContext, - pDRIPriv->myContext); - } - (*pDRIPriv->pLockRefCount)++; -} - -void -DRIUnlock(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if(!pDRIPriv || !pDRIPriv->pLockRefCount) return; - - if (*pDRIPriv->pLockRefCount > 0) { - if (pDRIPriv->myContext != *pDRIPriv->pLockingContext) { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "[DRI] Unlocking inconsistency:\n" - "\tContext %d trying to unlock lock held by context %d\n", - pDRIPriv->pLockingContext, - pDRIPriv->myContext); - } - (*pDRIPriv->pLockRefCount)--; - } else { - DRIDrvMsg(pScreen->myNum, X_ERROR, - "DRIUnlock called when not locked.\n"); - return; - } - if (! *pDRIPriv->pLockRefCount) - DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext); -} - -void * -DRIGetSAREAPrivate(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - if (!pDRIPriv) return 0; - - return (void *)(((char*)pDRIPriv->pSAREA)+sizeof(XF86DRISAREARec)); -} - -drm_context_t -DRIGetContext(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - if (!pDRIPriv) return 0; - - return pDRIPriv->myContext; -} - -void -DRIGetTexOffsetFuncs(ScreenPtr pScreen, - DRITexOffsetStartProcPtr *texOffsetStartFunc, - DRITexOffsetFinishProcPtr *texOffsetFinishFunc) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (!pDRIPriv) return; - - *texOffsetStartFunc = pDRIPriv->pDriverInfo->texOffsetStart; - *texOffsetFinishFunc = pDRIPriv->pDriverInfo->texOffsetFinish; -} - -/* This lets get at the unwrapped functions so that they can correctly - * call the lowerlevel functions, and choose whether they will be - * called at every level of recursion (eg in validatetree). - */ -DRIWrappedFuncsRec * -DRIGetWrappedFuncs(ScreenPtr pScreen) -{ - return &(DRI_SCREEN_PRIV(pScreen)->wrap); -} - -/* note that this returns the library version, not the protocol version */ -void -DRIQueryVersion(int *majorVersion, - int *minorVersion, - int *patchVersion) -{ - *majorVersion = DRIINFO_MAJOR_VERSION; - *minorVersion = DRIINFO_MINOR_VERSION; - *patchVersion = DRIINFO_PATCH_VERSION; -} - -static void -_DRIAdjustFrame(ScrnInfoPtr pScrn, DRIScreenPrivPtr pDRIPriv, int x, int y) -{ - pDRIPriv->pSAREA->frame.x = x; - pDRIPriv->pSAREA->frame.y = y; - pDRIPriv->pSAREA->frame.width = pScrn->frameX1 - x + 1; - pDRIPriv->pSAREA->frame.height = pScrn->frameY1 - y + 1; -} - -void -DRIAdjustFrame(int scrnIndex, int x, int y, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[scrnIndex]; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - int px, py; - - if (!pDRIPriv || !pDRIPriv->pSAREA) { - DRIDrvMsg(scrnIndex, X_ERROR, "[DRI] No SAREA (%p %p)\n", - pDRIPriv, pDRIPriv ? pDRIPriv->pSAREA : NULL); - return; - } - - if (pDRIPriv->fullscreen) { - /* Fix up frame */ - pScrn->frameX0 = pDRIPriv->pSAREA->frame.x; - pScrn->frameY0 = pDRIPriv->pSAREA->frame.y; - pScrn->frameX1 = pScrn->frameX0 + pDRIPriv->pSAREA->frame.width - 1; - pScrn->frameY1 = pScrn->frameY0 + pDRIPriv->pSAREA->frame.height - 1; - - /* Fix up cursor */ - miPointerGetPosition(inputInfo.pointer, &px, &py); - if (px < pScrn->frameX0) px = pScrn->frameX0; - if (px > pScrn->frameX1) px = pScrn->frameX1; - if (py < pScrn->frameY0) py = pScrn->frameY0; - if (py > pScrn->frameY1) py = pScrn->frameY1; - pScreen->SetCursorPosition(inputInfo.pointer, pScreen, px, py, TRUE); - return; - } - - if (pDRIPriv->wrap.AdjustFrame) { - /* unwrap */ - pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame; - /* call lower layers */ - (*pScrn->AdjustFrame)(scrnIndex, x, y, flags); - /* rewrap */ - pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame; - pScrn->AdjustFrame = DRIAdjustFrame; - } - - _DRIAdjustFrame(pScrn, pDRIPriv, x, y); -} - -/* - * DRIMoveBuffersHelper swaps the regions rects in place leaving you - * a region with the rects in the order that you need to blit them, - * but it is possibly (likely) an invalid region afterwards. If you - * need to use the region again for anything you have to call - * REGION_VALIDATE on it, or better yet, save a copy first. - */ - -void -DRIMoveBuffersHelper( - ScreenPtr pScreen, - int dx, - int dy, - int *xdir, - int *ydir, - RegionPtr reg -) -{ - BoxPtr extents, pbox, firstBox, lastBox; - BoxRec tmpBox; - int y, nbox; - - extents = REGION_EXTENTS(pScreen, reg); - nbox = REGION_NUM_RECTS(reg); - pbox = REGION_RECTS(reg); - - if((dy > 0) && (dy < (extents->y2 - extents->y1))) { - *ydir = -1; - if(nbox > 1) { - firstBox = pbox; - lastBox = pbox + nbox - 1; - while((unsigned long)firstBox < (unsigned long)lastBox) { - tmpBox = *firstBox; - *firstBox = *lastBox; - *lastBox = tmpBox; - firstBox++; - lastBox--; - } - } - } else *ydir = 1; - - if((dx > 0) && (dx < (extents->x2 - extents->x1))) { - *xdir = -1; - if(nbox > 1) { - firstBox = lastBox = pbox; - y = pbox->y1; - while(--nbox) { - pbox++; - if(pbox->y1 == y) lastBox++; - else { - while((unsigned long)firstBox < (unsigned long)lastBox) { - tmpBox = *firstBox; - *firstBox = *lastBox; - *lastBox = tmpBox; - firstBox++; - lastBox--; - } - - firstBox = lastBox = pbox; - y = pbox->y1; - } - } - while((unsigned long)firstBox < (unsigned long)lastBox) { - tmpBox = *firstBox; - *firstBox = *lastBox; - *lastBox = tmpBox; - firstBox++; - lastBox--; - } - } - } else *xdir = 1; - -} - -char * -DRICreatePCIBusID(const struct pci_device * dev) -{ - char *busID; - - busID = xalloc(20); - if (busID == NULL) - return NULL; - - snprintf(busID, 20, "pci:%04x:%02x:%02x.%d", dev->domain, dev->bus, - dev->dev, dev->func); - - return busID; -} - -static void drmSIGIOHandler(int interrupt, void *closure) -{ - unsigned long key; - void *value; - ssize_t count; - drm_ctx_t ctx; - typedef void (*_drmCallback)(int, void *, void *); - char buf[256]; - drm_context_t old; - drm_context_t new; - void *oldctx; - void *newctx; - char *pt; - drmHashEntry *entry; - void *hash_table; - - hash_table = drmGetHashTable(); - - if (!hash_table) return; - if (drmHashFirst(hash_table, &key, &value)) { - entry = value; - do { -#if 0 - fprintf(stderr, "Trying %d\n", entry->fd); -#endif - if ((count = read(entry->fd, buf, sizeof(buf) - 1)) > 0) { - buf[count] = '\0'; -#if 0 - fprintf(stderr, "Got %s\n", buf); -#endif - - for (pt = buf; *pt != ' '; ++pt); /* Find first space */ - ++pt; - old = strtol(pt, &pt, 0); - new = strtol(pt, NULL, 0); - oldctx = drmGetContextTag(entry->fd, old); - newctx = drmGetContextTag(entry->fd, new); -#if 0 - fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx); -#endif - ((_drmCallback)entry->f)(entry->fd, oldctx, newctx); - ctx.handle = new; - ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx); - } - } while (drmHashNext(hash_table, &key, &value)); - } -} - - -int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *)) -{ - drmHashEntry *entry; - - entry = drmGetEntry(fd); - entry->f = f; - - return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0); -} - -int drmRemoveSIGIOHandler(int fd) -{ - drmHashEntry *entry = drmGetEntry(fd); - - entry->f = NULL; - - return xf86RemoveSIGIOHandler(fd); -} +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, 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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/* + * Authors: + * Jens Owen <jens@tungstengraphics.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include <sys/time.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <errno.h> + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "xf86drm.h" +#include "misc.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "servermd.h" +#define _XF86DRI_SERVER_ +#include <X11/dri/xf86driproto.h> +#include "swaprep.h" +#include "xf86str.h" +#include "dri.h" +#include "sarea.h" +#include "dristruct.h" +#include "xf86.h" +#include "xf86drm.h" +#include "mi.h" +#include "mipointer.h" +#include "xf86_OSproc.h" +#include "inputstr.h" +#include "xf86VGAarbiter.h" + +#define PCI_BUS_NO_DOMAIN(bus) ((bus) & 0xffu) + +static int DRIEntPrivIndex = -1; +static int DRIScreenPrivKeyIndex; +static DevPrivateKey DRIScreenPrivKey = &DRIScreenPrivKeyIndex; +static int DRIWindowPrivKeyIndex; +static DevPrivateKey DRIWindowPrivKey = &DRIWindowPrivKeyIndex; +static unsigned long DRIGeneration = 0; +static unsigned int DRIDrawableValidationStamp = 0; + +static RESTYPE DRIDrawablePrivResType; +static RESTYPE DRIContextPrivResType; +static void DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv); + +drmServerInfo DRIDRMServerInfo; + + /* Wrapper just like xf86DrvMsg, but + without the verbosity level checking. + This will make it easy to turn off some + messages later, based on verbosity + level. */ + +/* + * Since we're already referencing things from the XFree86 common layer in + * this file, we'd might as well just call xf86VDrvMsgVerb, and have + * consistent message formatting. The verbosity of these messages can be + * easily changed here. + */ +#define DRI_MSG_VERBOSITY 1 +static void +DRIDrvMsg(int scrnIndex, MessageType type, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + xf86VDrvMsgVerb(scrnIndex, type, DRI_MSG_VERBOSITY, format, ap); + va_end(ap); +} + + +static void +DRIOpenDRMCleanup(DRIEntPrivPtr pDRIEntPriv) +{ + if (pDRIEntPriv->pLSAREA != NULL) { + drmUnmap(pDRIEntPriv->pLSAREA, pDRIEntPriv->sAreaSize); + pDRIEntPriv->pLSAREA = NULL; + } + if (pDRIEntPriv->hLSAREA != 0) { + drmRmMap(pDRIEntPriv->drmFD, pDRIEntPriv->hLSAREA); + } + if (pDRIEntPriv->drmFD >= 0) { + drmClose(pDRIEntPriv->drmFD); + pDRIEntPriv->drmFD = 0; + } +} + +int +DRIMasterFD(ScrnInfoPtr pScrn) +{ + return DRI_ENT_PRIV(pScrn)->drmFD; +} + +void * +DRIMasterSareaPointer(ScrnInfoPtr pScrn) +{ + return DRI_ENT_PRIV(pScrn)->pLSAREA; +} + +drm_handle_t +DRIMasterSareaHandle(ScrnInfoPtr pScrn) +{ + return DRI_ENT_PRIV(pScrn)->hLSAREA; +} + + +Bool +DRIOpenDRMMaster(ScrnInfoPtr pScrn, + unsigned long sAreaSize, + const char *busID, + const char *drmDriverName) +{ + drmSetVersion saveSv, sv; + Bool drmWasAvailable; + DRIEntPrivPtr pDRIEntPriv; + DRIEntPrivRec tmp; + drmVersionPtr drmlibv; + int drmlibmajor, drmlibminor; + const char *openBusID; + int count; + int err; + + if (DRIEntPrivIndex == -1) + DRIEntPrivIndex = xf86AllocateEntityPrivateIndex(); + + pDRIEntPriv = DRI_ENT_PRIV(pScrn); + + if (pDRIEntPriv && pDRIEntPriv->drmFD != -1) + return TRUE; + + drmWasAvailable = drmAvailable(); + + memset(&tmp, 0, sizeof(tmp)); + + /* Check the DRM lib version. + * drmGetLibVersion was not supported in version 1.0, so check for + * symbol first to avoid possible crash or hang. + */ + + drmlibmajor = 1; + drmlibminor = 0; + if (xf86LoaderCheckSymbol("drmGetLibVersion")) { + drmlibv = drmGetLibVersion(-1); + if (drmlibv != NULL) { + drmlibmajor = drmlibv->version_major; + drmlibminor = drmlibv->version_minor; + drmFreeVersion(drmlibv); + } + } + + /* Check if the libdrm can handle falling back to loading based on name + * if a busid string is passed. + */ + openBusID = (drmlibmajor == 1 && drmlibminor >= 2) ? busID : NULL; + + tmp.drmFD = -1; + sv.drm_di_major = 1; + sv.drm_di_minor = 1; + sv.drm_dd_major = -1; + + saveSv = sv; + count = 10; + while (count--) { + tmp.drmFD = drmOpen(drmDriverName, openBusID); + + if (tmp.drmFD < 0) { + DRIDrvMsg(-1, X_ERROR, "[drm] drmOpen failed.\n"); + goto out_err; + } + + err = drmSetInterfaceVersion(tmp.drmFD, &sv); + + if (err != -EPERM) + break; + + sv = saveSv; + drmClose(tmp.drmFD); + tmp.drmFD = -1; + usleep(100000); + } + + if (tmp.drmFD <= 0) { + DRIDrvMsg(-1, X_ERROR, "[drm] DRM was busy with another master.\n"); + goto out_err; + } + + if (!drmWasAvailable) { + DRIDrvMsg(-1, X_INFO, + "[drm] loaded kernel module for \"%s\" driver.\n", + drmDriverName); + } + + if (err != 0) { + sv.drm_di_major = 1; + sv.drm_di_minor = 0; + } + + DRIDrvMsg(-1, X_INFO, "[drm] DRM interface version %d.%d\n", + sv.drm_di_major, sv.drm_di_minor); + + if (sv.drm_di_major == 1 && sv.drm_di_minor >= 1) + err = 0; + else + err = drmSetBusid(tmp.drmFD, busID); + + if (err) { + DRIDrvMsg(-1, X_ERROR, "[drm] Could not set DRM device bus ID.\n"); + goto out_err; + } + + /* + * Create a lock-containing sarea. + */ + + if (drmAddMap( tmp.drmFD, 0, sAreaSize, DRM_SHM, + DRM_CONTAINS_LOCK, &tmp.hLSAREA) < 0) { + DRIDrvMsg(-1, X_INFO, "[drm] Could not create SAREA for DRM lock.\n"); + tmp.hLSAREA = 0; + goto out_err; + } + + if (drmMap( tmp.drmFD, tmp.hLSAREA, sAreaSize, + (drmAddressPtr)(&tmp.pLSAREA)) < 0) { + DRIDrvMsg(-1, X_INFO, "[drm] Mapping SAREA for DRM lock failed.\n"); + tmp.pLSAREA = NULL; + goto out_err; + } + + memset(tmp.pLSAREA, 0, sAreaSize); + + /* + * Reserved contexts are handled by the first opened screen. + */ + + tmp.resOwner = NULL; + + if (!pDRIEntPriv) + pDRIEntPriv = xnfcalloc(sizeof(*pDRIEntPriv), 1); + + if (!pDRIEntPriv) { + DRIDrvMsg(-1, X_INFO, "[drm] Failed to allocate memory for " + "DRM device.\n"); + goto out_err; + } + *pDRIEntPriv = tmp; + xf86GetEntityPrivate((pScrn)->entityList[0],DRIEntPrivIndex)->ptr = + pDRIEntPriv; + + DRIDrvMsg(-1, X_INFO, "[drm] DRM open master succeeded.\n"); + return TRUE; + + out_err: + + DRIOpenDRMCleanup(&tmp); + return FALSE; +} + +static void +DRIClipNotifyAllDrawables(ScreenPtr pScreen); + +static void +dri_crtc_notify(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIClipNotifyAllDrawables(pScreen); + xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify); + xf86_crtc_notify(pScreen); + pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen, dri_crtc_notify); +} + +Bool +DRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD) +{ + DRIScreenPrivPtr pDRIPriv; + drm_context_t * reserved; + int reserved_count; + int i; + DRIEntPrivPtr pDRIEntPriv; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + DRIContextFlags flags = 0; + DRIContextPrivPtr pDRIContextPriv; + + /* If the DRI extension is disabled, do not initialize the DRI */ + if (noXFree86DRIExtension) { + DRIDrvMsg(pScreen->myNum, X_WARNING, + "Direct rendering has been disabled.\n"); + return FALSE; + } + + if (!xf86VGAarbiterAllowDRI(pScreen)) { + DRIDrvMsg(pScreen->myNum, X_WARNING, + "Direct rendering is not supported when VGA arb is necessary for the device\n"); + return FALSE; + } + +#ifdef PANORAMIX + /* + * If Xinerama is on, don't allow DRI to initialise. It won't be usable + * anyway. + */ + if (!noPanoramiXExtension) { + DRIDrvMsg(pScreen->myNum, X_WARNING, + "Direct rendering is not supported when Xinerama is enabled\n"); + return FALSE; + } +#endif + + if (!DRIOpenDRMMaster(pScrn, pDRIInfo->SAREASize, + pDRIInfo->busIdString, + pDRIInfo->drmDriverName)) + return FALSE; + + pDRIEntPriv = DRI_ENT_PRIV(pScrn); + + if (DRIGeneration != serverGeneration) + DRIGeneration = serverGeneration; + + pDRIPriv = (DRIScreenPrivPtr) calloc(1, sizeof(DRIScreenPrivRec)); + if (!pDRIPriv) { + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + return FALSE; + } + + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, pDRIPriv); + pDRIPriv->drmFD = pDRIEntPriv->drmFD; + pDRIPriv->directRenderingSupport = TRUE; + pDRIPriv->pDriverInfo = pDRIInfo; + pDRIPriv->nrWindows = 0; + pDRIPriv->nrWindowsVisible = 0; + pDRIPriv->fullscreen = NULL; + + pDRIPriv->createDummyCtx = pDRIInfo->createDummyCtx; + pDRIPriv->createDummyCtxPriv = pDRIInfo->createDummyCtxPriv; + + pDRIPriv->grabbedDRILock = FALSE; + pDRIPriv->drmSIGIOHandlerInstalled = FALSE; + *pDRMFD = pDRIPriv->drmFD; + + if (pDRIEntPriv->sAreaGrabbed || pDRIInfo->allocSarea) { + + if (drmAddMap( pDRIPriv->drmFD, + 0, + pDRIPriv->pDriverInfo->SAREASize, + DRM_SHM, + 0, + &pDRIPriv->hSAREA) < 0) + { + pDRIPriv->directRenderingSupport = FALSE; + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + drmClose(pDRIPriv->drmFD); + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] drmAddMap failed\n"); + return FALSE; + } + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] added %d byte SAREA at %p\n", + pDRIPriv->pDriverInfo->SAREASize, pDRIPriv->hSAREA); + + /* Backwards compat. */ + if (drmMap( pDRIPriv->drmFD, + pDRIPriv->hSAREA, + pDRIPriv->pDriverInfo->SAREASize, + (drmAddressPtr)(&pDRIPriv->pSAREA)) < 0) + { + pDRIPriv->directRenderingSupport = FALSE; + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + drmClose(pDRIPriv->drmFD); + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] drmMap failed\n"); + return FALSE; + } + DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n", + pDRIPriv->hSAREA, pDRIPriv->pSAREA); + memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize); + } else { + DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] Using the DRM lock " + "SAREA also for drawables.\n"); + pDRIPriv->hSAREA = pDRIEntPriv->hLSAREA; + pDRIPriv->pSAREA = (XF86DRISAREAPtr) pDRIEntPriv->pLSAREA; + pDRIEntPriv->sAreaGrabbed = TRUE; + } + + pDRIPriv->hLSAREA = pDRIEntPriv->hLSAREA; + pDRIPriv->pLSAREA = pDRIEntPriv->pLSAREA; + + if (!pDRIPriv->pDriverInfo->dontMapFrameBuffer) + { + if (drmAddMap( pDRIPriv->drmFD, + (drm_handle_t)pDRIPriv->pDriverInfo->frameBufferPhysicalAddress, + pDRIPriv->pDriverInfo->frameBufferSize, + DRM_FRAME_BUFFER, + 0, + &pDRIPriv->pDriverInfo->hFrameBuffer) < 0) + { + pDRIPriv->directRenderingSupport = FALSE; + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + drmUnmap(pDRIPriv->pSAREA, pDRIPriv->pDriverInfo->SAREASize); + drmClose(pDRIPriv->drmFD); + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] drmAddMap failed\n"); + return FALSE; + } + DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = %p\n", + pDRIPriv->pDriverInfo->hFrameBuffer); + } else { + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] framebuffer mapped by ddx driver\n"); + } + + if (pDRIEntPriv->resOwner == NULL) { + pDRIEntPriv->resOwner = pScreen; + + /* Add tags for reserved contexts */ + if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD, + &reserved_count))) { + int i; + void *tag; + + for (i = 0; i < reserved_count; i++) { + tag = DRICreateContextPrivFromHandle(pScreen, + reserved[i], + DRI_CONTEXT_RESERVED); + drmAddContextTag(pDRIPriv->drmFD, reserved[i], tag); + } + drmFreeReservedContextList(reserved); + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] added %d reserved context%s for kernel\n", + reserved_count, reserved_count > 1 ? "s" : ""); + } + } + + /* validate max drawable table entry set by driver */ + if ((pDRIPriv->pDriverInfo->maxDrawableTableEntry <= 0) || + (pDRIPriv->pDriverInfo->maxDrawableTableEntry > SAREA_MAX_DRAWABLES)) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "Invalid max drawable table size set by driver: %d\n", + pDRIPriv->pDriverInfo->maxDrawableTableEntry); + } + + /* Initialize drawable tables (screen private and SAREA) */ + for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) { + pDRIPriv->DRIDrawables[i] = NULL; + pDRIPriv->pSAREA->drawableTable[i].stamp = 0; + pDRIPriv->pSAREA->drawableTable[i].flags = 0; + } + + pDRIPriv->pLockRefCount = &pDRIEntPriv->lockRefCount; + pDRIPriv->pLockingContext = &pDRIEntPriv->lockingContext; + + if (!pDRIEntPriv->keepFDOpen) + pDRIEntPriv->keepFDOpen = pDRIInfo->keepFDOpen; + + pDRIEntPriv->refCount++; + + /* Set up flags for DRICreateContextPriv */ + switch (pDRIInfo->driverSwapMethod) { + case DRI_KERNEL_SWAP: + flags = DRI_CONTEXT_2DONLY; + break; + case DRI_HIDE_X_CONTEXT: + flags = DRI_CONTEXT_PRESERVED; + break; + } + + if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, + &pDRIPriv->myContext, + flags))) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "failed to create server context\n"); + return FALSE; + } + pDRIPriv->myContextPriv = pDRIContextPriv; + + DRIDrvMsg(pScreen->myNum, X_INFO, + "X context handle = %p\n", pDRIPriv->myContext); + + /* Now that we have created the X server's context, we can grab the + * hardware lock for the X server. + */ + DRILock(pScreen, 0); + pDRIPriv->grabbedDRILock = TRUE; + + /* pointers so that we can prevent memory leaks later */ + pDRIPriv->hiddenContextStore = NULL; + pDRIPriv->partial3DContextStore = NULL; + + switch(pDRIInfo->driverSwapMethod) { + case DRI_HIDE_X_CONTEXT: + /* Server will handle 3D swaps, and hide 2D swaps from kernel. + * Register server context as a preserved context. + */ + + /* allocate memory for hidden context store */ + pDRIPriv->hiddenContextStore + = (void *)calloc(1, pDRIInfo->contextSize); + if (!pDRIPriv->hiddenContextStore) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "failed to allocate hidden context\n"); + DRIDestroyContextPriv(pDRIContextPriv); + return FALSE; + } + + /* allocate memory for partial 3D context store */ + pDRIPriv->partial3DContextStore + = (void *)calloc(1, pDRIInfo->contextSize); + if (!pDRIPriv->partial3DContextStore) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[DRI] failed to allocate partial 3D context\n"); + free(pDRIPriv->hiddenContextStore); + DRIDestroyContextPriv(pDRIContextPriv); + return FALSE; + } + + /* save initial context store */ + if (pDRIInfo->SwapContext) { + (*pDRIInfo->SwapContext)( + pScreen, + DRI_NO_SYNC, + DRI_2D_CONTEXT, + pDRIPriv->hiddenContextStore, + DRI_NO_CONTEXT, + NULL); + } + /* fall through */ + + case DRI_SERVER_SWAP: + /* For swap methods of DRI_SERVER_SWAP and DRI_HIDE_X_CONTEXT + * setup signal handler for receiving swap requests from kernel + */ + if (!(pDRIPriv->drmSIGIOHandlerInstalled = + drmInstallSIGIOHandler(pDRIPriv->drmFD, DRISwapContext))) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[drm] failed to setup DRM signal handler\n"); + if (pDRIPriv->hiddenContextStore) + free(pDRIPriv->hiddenContextStore); + if (pDRIPriv->partial3DContextStore) + free(pDRIPriv->partial3DContextStore); + DRIDestroyContextPriv(pDRIContextPriv); + return FALSE; + } else { + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] installed DRM signal handler\n"); + } + + default: + break; + } + + return TRUE; +} + +Bool +DRIFinishScreenInit(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; + + /* Wrap DRI support */ + if (pDRIInfo->wrap.ValidateTree) { + pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; + pScreen->ValidateTree = pDRIInfo->wrap.ValidateTree; + } + if (pDRIInfo->wrap.PostValidateTree) { + pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; + pScreen->PostValidateTree = pDRIInfo->wrap.PostValidateTree; + } + if (pDRIInfo->wrap.WindowExposures) { + pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; + pScreen->WindowExposures = pDRIInfo->wrap.WindowExposures; + } + + pDRIPriv->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = DRIDestroyWindow; + + pDRIPriv->xf86_crtc_notify = xf86_wrap_crtc_notify(pScreen, + dri_crtc_notify); + + if (pDRIInfo->wrap.CopyWindow) { + pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; + pScreen->CopyWindow = pDRIInfo->wrap.CopyWindow; + } + if (pDRIInfo->wrap.ClipNotify) { + pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; + pScreen->ClipNotify = pDRIInfo->wrap.ClipNotify; + } + if (pDRIInfo->wrap.AdjustFrame) { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame; + pScrn->AdjustFrame = pDRIInfo->wrap.AdjustFrame; + } + pDRIPriv->wrapped = TRUE; + + DRIDrvMsg(pScreen->myNum, X_INFO, "[DRI] installation complete\n"); + + return TRUE; +} + +void +DRICloseScreen(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIInfoPtr pDRIInfo; + drm_context_t * reserved; + int reserved_count; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + DRIEntPrivPtr pDRIEntPriv = DRI_ENT_PRIV(pScrn); + Bool closeMaster; + + if (pDRIPriv) { + + pDRIInfo = pDRIPriv->pDriverInfo; + + if (pDRIPriv->wrapped) { + /* Unwrap DRI Functions */ + if (pDRIInfo->wrap.ValidateTree) { + pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree; + pDRIPriv->wrap.ValidateTree = NULL; + } + if (pDRIInfo->wrap.PostValidateTree) { + pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree; + pDRIPriv->wrap.PostValidateTree = NULL; + } + if (pDRIInfo->wrap.WindowExposures) { + pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures; + pDRIPriv->wrap.WindowExposures = NULL; + } + if (pDRIPriv->DestroyWindow) { + pScreen->DestroyWindow = pDRIPriv->DestroyWindow; + pDRIPriv->DestroyWindow = NULL; + } + + xf86_unwrap_crtc_notify(pScreen, pDRIPriv->xf86_crtc_notify); + + if (pDRIInfo->wrap.CopyWindow) { + pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow; + pDRIPriv->wrap.CopyWindow = NULL; + } + if (pDRIInfo->wrap.ClipNotify) { + pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify; + pDRIPriv->wrap.ClipNotify = NULL; + } + if (pDRIInfo->wrap.AdjustFrame) { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame; + pDRIPriv->wrap.AdjustFrame = NULL; + } + + pDRIPriv->wrapped = FALSE; + } + + if (pDRIPriv->drmSIGIOHandlerInstalled) { + if (!drmRemoveSIGIOHandler(pDRIPriv->drmFD)) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[drm] failed to remove DRM signal handler\n"); + } + } + + if (pDRIPriv->dummyCtxPriv && pDRIPriv->createDummyCtx) { + DRIDestroyDummyContext(pScreen, pDRIPriv->createDummyCtxPriv); + } + + if (!DRIDestroyContextPriv(pDRIPriv->myContextPriv)) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "failed to destroy server context\n"); + } + + /* Remove tags for reserved contexts */ + if (pDRIEntPriv->resOwner == pScreen) { + pDRIEntPriv->resOwner = NULL; + + if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD, + &reserved_count))) { + int i; + + for (i = 0; i < reserved_count; i++) { + DRIDestroyContextPriv(drmGetContextTag(pDRIPriv->drmFD, + reserved[i])); + } + drmFreeReservedContextList(reserved); + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] removed %d reserved context%s for kernel\n", + reserved_count, reserved_count > 1 ? "s" : ""); + } + } + + /* Make sure signals get unblocked etc. */ + drmUnlock(pDRIPriv->drmFD, pDRIPriv->myContext); + pDRIPriv->pLockRefCount = NULL; + closeMaster = (--pDRIEntPriv->refCount == 0) && + !pDRIEntPriv->keepFDOpen; + if (closeMaster || pDRIPriv->hSAREA != pDRIEntPriv->hLSAREA) { + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] unmapping %d bytes of SAREA %p at %p\n", + pDRIInfo->SAREASize, + pDRIPriv->hSAREA, + pDRIPriv->pSAREA); + if (drmUnmap(pDRIPriv->pSAREA, pDRIInfo->SAREASize)) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[drm] unable to unmap %d bytes" + " of SAREA %p at %p\n", + pDRIInfo->SAREASize, + pDRIPriv->hSAREA, + pDRIPriv->pSAREA); + } + } else { + pDRIEntPriv->sAreaGrabbed = FALSE; + } + + if (closeMaster || (pDRIEntPriv->drmFD != pDRIPriv->drmFD)) { + drmClose(pDRIPriv->drmFD); + if (pDRIEntPriv->drmFD == pDRIPriv->drmFD) { + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] Closed DRM master.\n"); + pDRIEntPriv->drmFD = -1; + } + } + + free(pDRIPriv); + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + } +} + +#define DRM_MSG_VERBOSITY 3 + +static int dri_drm_debug_print(const char *format, va_list ap) +{ + xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap); + return 0; +} + +static void dri_drm_get_perms(gid_t *group, mode_t *mode) +{ + *group = xf86ConfigDRI.group; + *mode = xf86ConfigDRI.mode; +} + +drmServerInfo DRIDRMServerInfo = { + dri_drm_debug_print, + xf86LoadKernelModule, + dri_drm_get_perms, +}; + +Bool +DRIExtensionInit(void) +{ + if (!DRIScreenPrivKey || DRIGeneration != serverGeneration) { + return FALSE; + } + + DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete, + "DRIDrawable"); + DRIContextPrivResType = CreateNewResourceType(DRIContextPrivDelete, + "DRIContext"); + + if (!DRIDrawablePrivResType || !DRIContextPrivResType) + return FALSE; + + RegisterBlockAndWakeupHandlers(DRIBlockHandler, DRIWakeupHandler, NULL); + + return TRUE; +} + +void +DRIReset(void) +{ + /* + * This stub routine is called when the X Server recycles, resources + * allocated by DRIExtensionInit need to be managed here. + * + * Currently this routine is a stub because all the interesting resources + * are managed via the screen init process. + */ +} + +Bool +DRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool* isCapable) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv) + *isCapable = pDRIPriv->directRenderingSupport; + else + *isCapable = FALSE; + + return TRUE; +} + +Bool +DRIOpenConnection(ScreenPtr pScreen, drm_handle_t * hSAREA, char **busIdString) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + *hSAREA = pDRIPriv->hSAREA; + *busIdString = pDRIPriv->pDriverInfo->busIdString; + + return TRUE; +} + +Bool +DRIAuthConnection(ScreenPtr pScreen, drm_magic_t magic) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (drmAuthMagic(pDRIPriv->drmFD, magic)) return FALSE; + return TRUE; +} + +Bool +DRICloseConnection(ScreenPtr pScreen) +{ + return TRUE; +} + +Bool +DRIGetClientDriverName(ScreenPtr pScreen, + int *ddxDriverMajorVersion, + int *ddxDriverMinorVersion, + int *ddxDriverPatchVersion, + char **clientDriverName) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + *ddxDriverMajorVersion = pDRIPriv->pDriverInfo->ddxDriverMajorVersion; + *ddxDriverMinorVersion = pDRIPriv->pDriverInfo->ddxDriverMinorVersion; + *ddxDriverPatchVersion = pDRIPriv->pDriverInfo->ddxDriverPatchVersion; + *clientDriverName = pDRIPriv->pDriverInfo->clientDriverName; + + return TRUE; +} + +/* DRICreateContextPriv and DRICreateContextPrivFromHandle are helper + functions that layer on drmCreateContext and drmAddContextTag. + + DRICreateContextPriv always creates a kernel drm_context_t and then calls + DRICreateContextPrivFromHandle to create a DRIContextPriv structure for + DRI tracking. For the SIGIO handler, the drm_context_t is associated with + DRIContextPrivPtr. Any special flags are stored in the DRIContextPriv + area and are passed to the kernel (if necessary). + + DRICreateContextPriv returns a pointer to newly allocated + DRIContextPriv, and returns the kernel drm_context_t in pHWContext. */ + +DRIContextPrivPtr +DRICreateContextPriv(ScreenPtr pScreen, + drm_context_t * pHWContext, + DRIContextFlags flags) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (drmCreateContext(pDRIPriv->drmFD, pHWContext)) { + return NULL; + } + + return DRICreateContextPrivFromHandle(pScreen, *pHWContext, flags); +} + +DRIContextPrivPtr +DRICreateContextPrivFromHandle(ScreenPtr pScreen, + drm_context_t hHWContext, + DRIContextFlags flags) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIContextPrivPtr pDRIContextPriv; + int contextPrivSize; + + contextPrivSize = sizeof(DRIContextPrivRec) + + pDRIPriv->pDriverInfo->contextSize; + if (!(pDRIContextPriv = calloc(1, contextPrivSize))) { + return NULL; + } + pDRIContextPriv->pContextStore = (void *)(pDRIContextPriv + 1); + + drmAddContextTag(pDRIPriv->drmFD, hHWContext, pDRIContextPriv); + + pDRIContextPriv->hwContext = hHWContext; + pDRIContextPriv->pScreen = pScreen; + pDRIContextPriv->flags = flags; + pDRIContextPriv->valid3D = FALSE; + + if (flags & DRI_CONTEXT_2DONLY) { + if (drmSetContextFlags(pDRIPriv->drmFD, + hHWContext, + DRM_CONTEXT_2DONLY)) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[drm] failed to set 2D context flag\n"); + DRIDestroyContextPriv(pDRIContextPriv); + return NULL; + } + } + if (flags & DRI_CONTEXT_PRESERVED) { + if (drmSetContextFlags(pDRIPriv->drmFD, + hHWContext, + DRM_CONTEXT_PRESERVED)) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[drm] failed to set preserved flag\n"); + DRIDestroyContextPriv(pDRIContextPriv); + return NULL; + } + } + return pDRIContextPriv; +} + +Bool +DRIDestroyContextPriv(DRIContextPrivPtr pDRIContextPriv) +{ + DRIScreenPrivPtr pDRIPriv; + + if (!pDRIContextPriv) return TRUE; + + pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen); + + if (!(pDRIContextPriv->flags & DRI_CONTEXT_RESERVED)) { + /* Don't delete reserved contexts from + kernel area -- the kernel manages its + reserved contexts itself. */ + if (drmDestroyContext(pDRIPriv->drmFD, pDRIContextPriv->hwContext)) + return FALSE; + } + + /* Remove the tag last to prevent a race + condition where the context has pending + buffers. The context can't be re-used + while in this thread, but buffers can be + dispatched asynchronously. */ + drmDelContextTag(pDRIPriv->drmFD, pDRIContextPriv->hwContext); + free(pDRIContextPriv); + return TRUE; +} + +static Bool +DRICreateDummyContext(ScreenPtr pScreen, Bool needCtxPriv) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIContextPrivPtr pDRIContextPriv; + void *contextStore; + + if (!(pDRIContextPriv = + DRICreateContextPriv(pScreen, + &pDRIPriv->pSAREA->dummy_context, 0))) { + return FALSE; + } + + contextStore = DRIGetContextStore(pDRIContextPriv); + if (pDRIPriv->pDriverInfo->CreateContext && needCtxPriv) { + if (!pDRIPriv->pDriverInfo->CreateContext(pScreen, NULL, + pDRIPriv->pSAREA->dummy_context, + NULL, + (DRIContextType)(long)contextStore)) { + DRIDestroyContextPriv(pDRIContextPriv); + return FALSE; + } + } + + pDRIPriv->dummyCtxPriv = pDRIContextPriv; + return TRUE; +} + +static void +DRIDestroyDummyContext(ScreenPtr pScreen, Bool hasCtxPriv) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIContextPrivPtr pDRIContextPriv = pDRIPriv->dummyCtxPriv; + void *contextStore; + + if (!pDRIContextPriv) return; + if (pDRIPriv->pDriverInfo->DestroyContext && hasCtxPriv) { + contextStore = DRIGetContextStore(pDRIContextPriv); + pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen, + pDRIContextPriv->hwContext, + (DRIContextType)(long)contextStore); + } + + DRIDestroyContextPriv(pDRIPriv->dummyCtxPriv); + pDRIPriv->dummyCtxPriv = NULL; +} + +Bool +DRICreateContext(ScreenPtr pScreen, VisualPtr visual, + XID context, drm_context_t * pHWContext) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIContextPrivPtr pDRIContextPriv; + void *contextStore; + + if (pDRIPriv->createDummyCtx && !pDRIPriv->dummyCtxPriv) { + if (!DRICreateDummyContext(pScreen, pDRIPriv->createDummyCtxPriv)) { + DRIDrvMsg(pScreen->myNum, X_INFO, + "[drm] Could not create dummy context\n"); + return FALSE; + } + } + + if (!(pDRIContextPriv = DRICreateContextPriv(pScreen, pHWContext, 0))) { + return FALSE; + } + + contextStore = DRIGetContextStore(pDRIContextPriv); + if (pDRIPriv->pDriverInfo->CreateContext) { + if (!((*pDRIPriv->pDriverInfo->CreateContext)(pScreen, NULL, + *pHWContext, NULL, + (DRIContextType)(long)contextStore))) { + DRIDestroyContextPriv(pDRIContextPriv); + return FALSE; + } + } + + /* track this in case the client dies before cleanup */ + AddResource(context, DRIContextPrivResType, (pointer)pDRIContextPriv); + + return TRUE; +} + +Bool +DRIDestroyContext(ScreenPtr pScreen, XID context) +{ + FreeResourceByType(context, DRIContextPrivResType, FALSE); + + return TRUE; +} + +/* DRIContextPrivDelete is called by the resource manager. */ +Bool +DRIContextPrivDelete(pointer pResource, XID id) +{ + DRIContextPrivPtr pDRIContextPriv = (DRIContextPrivPtr)pResource; + DRIScreenPrivPtr pDRIPriv; + void *contextStore; + + pDRIPriv = DRI_SCREEN_PRIV(pDRIContextPriv->pScreen); + if (pDRIPriv->pDriverInfo->DestroyContext) { + contextStore = DRIGetContextStore(pDRIContextPriv); + pDRIPriv->pDriverInfo->DestroyContext(pDRIContextPriv->pScreen, + pDRIContextPriv->hwContext, + (DRIContextType)(long)contextStore); + } + return DRIDestroyContextPriv(pDRIContextPriv); +} + + +/* This walks the drawable timestamp array and invalidates all of them + * in the case of transition from private to shared backbuffers. It's + * not necessary for correctness, because DRIClipNotify gets called in + * time to prevent any conflict, but the transition from + * shared->private is sometimes missed if we don't do this. + */ +static void +DRIClipNotifyAllDrawables(ScreenPtr pScreen) +{ + int i; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + for( i=0; i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; i++) { + pDRIPriv->pSAREA->drawableTable[i].stamp = DRIDrawableValidationStamp++; + } +} + + +static void +DRITransitionToSharedBuffers(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; + + DRIClipNotifyAllDrawables( pScreen ); + + if (pDRIInfo->TransitionSingleToMulti3D) + pDRIInfo->TransitionSingleToMulti3D( pScreen ); +} + + +static void +DRITransitionToPrivateBuffers(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; + + DRIClipNotifyAllDrawables( pScreen ); + + if (pDRIInfo->TransitionMultiToSingle3D) + pDRIInfo->TransitionMultiToSingle3D( pScreen ); +} + + +static void +DRITransitionTo3d(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; + + DRIClipNotifyAllDrawables( pScreen ); + + if (pDRIInfo->TransitionTo3d) + pDRIInfo->TransitionTo3d( pScreen ); +} + +static void +DRITransitionTo2d(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; + + DRIClipNotifyAllDrawables( pScreen ); + + if (pDRIInfo->TransitionTo2d) + pDRIInfo->TransitionTo2d( pScreen ); +} + + +static int +DRIDCNTreeTraversal(WindowPtr pWin, pointer data) +{ + DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + + if (pDRIDrawablePriv) { + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (REGION_NUM_RECTS(&pWin->clipList) > 0) { + WindowPtr *pDRIWindows = (WindowPtr*)data; + int i = 0; + + while (pDRIWindows[i]) + i++; + + pDRIWindows[i] = pWin; + + pDRIPriv->nrWalked++; + } + + if (pDRIPriv->nrWindows == pDRIPriv->nrWalked) + return WT_STOPWALKING; + } + + return WT_WALKCHILDREN; +} + +static void +DRIDriverClipNotify(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv->pDriverInfo->ClipNotify) { + WindowPtr *pDRIWindows = calloc(sizeof(WindowPtr), pDRIPriv->nrWindows); + DRIInfoPtr pDRIInfo = pDRIPriv->pDriverInfo; + + if (pDRIPriv->nrWindows > 0) { + pDRIPriv->nrWalked = 0; + TraverseTree(WindowTable[pScreen->myNum], DRIDCNTreeTraversal, + (pointer)pDRIWindows); + } + + pDRIInfo->ClipNotify(pScreen, pDRIWindows, pDRIPriv->nrWindows); + + free(pDRIWindows); + } +} + +static void +DRIIncreaseNumberVisible(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + switch (++pDRIPriv->nrWindowsVisible) { + case 1: + DRITransitionTo3d( pScreen ); + break; + case 2: + DRITransitionToSharedBuffers( pScreen ); + break; + default: + break; + } + + DRIDriverClipNotify(pScreen); +} + +static void +DRIDecreaseNumberVisible(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + switch (--pDRIPriv->nrWindowsVisible) { + case 0: + DRITransitionTo2d( pScreen ); + break; + case 1: + DRITransitionToPrivateBuffers( pScreen ); + break; + default: + break; + } + + DRIDriverClipNotify(pScreen); +} + +Bool +DRICreateDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable, + drm_drawable_t * hHWDrawable) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv; + WindowPtr pWin; + + if (pDrawable->type == DRAWABLE_WINDOW) { + pWin = (WindowPtr)pDrawable; + if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { + pDRIDrawablePriv->refCount++; + + if (!pDRIDrawablePriv->hwDrawable) { + drmCreateDrawable(pDRIPriv->drmFD, &pDRIDrawablePriv->hwDrawable); + } + } + else { + /* allocate a DRI Window Private record */ + if (!(pDRIDrawablePriv = malloc(sizeof(DRIDrawablePrivRec)))) { + return FALSE; + } + + /* Only create a drm_drawable_t once */ + if (drmCreateDrawable(pDRIPriv->drmFD, + &pDRIDrawablePriv->hwDrawable)) { + free(pDRIDrawablePriv); + return FALSE; + } + + /* add it to the list of DRI drawables for this screen */ + pDRIDrawablePriv->pScreen = pScreen; + pDRIDrawablePriv->refCount = 1; + pDRIDrawablePriv->drawableIndex = -1; + pDRIDrawablePriv->nrects = REGION_NUM_RECTS(&pWin->clipList); + + /* save private off of preallocated index */ + dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, + pDRIDrawablePriv); + pDRIPriv->nrWindows++; + + if (pDRIDrawablePriv->nrects) + DRIIncreaseNumberVisible(pScreen); + } + + /* track this in case the client dies */ + AddResource(FakeClientID(client->index), DRIDrawablePrivResType, + (pointer)(intptr_t)pDrawable->id); + + if (pDRIDrawablePriv->hwDrawable) { + drmUpdateDrawableInfo(pDRIPriv->drmFD, + pDRIDrawablePriv->hwDrawable, + DRM_DRAWABLE_CLIPRECTS, + REGION_NUM_RECTS(&pWin->clipList), + REGION_RECTS(&pWin->clipList)); + *hHWDrawable = pDRIDrawablePriv->hwDrawable; + } + } + else if (pDrawable->type != DRAWABLE_PIXMAP) { /* PBuffer */ + /* NOT_DONE */ + return FALSE; + } + + return TRUE; +} + +static void +DRIDrawablePrivDestroy(WindowPtr pWin) +{ + DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + ScreenPtr pScreen; + DRIScreenPrivPtr pDRIPriv; + + if (!pDRIDrawablePriv) + return; + + pScreen = pWin->drawable.pScreen; + pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIDrawablePriv->drawableIndex != -1) { + /* bump stamp to force outstanding 3D requests to resync */ + pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp + = DRIDrawableValidationStamp++; + + /* release drawable table entry */ + pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL; + } + + pDRIPriv->nrWindows--; + + if (pDRIDrawablePriv->nrects) + DRIDecreaseNumberVisible(pScreen); + + drmDestroyDrawable(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable); + + free(pDRIDrawablePriv); + dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL); +} + +static Bool +DRIDestroyDrawableCB(pointer value, XID id, pointer data) +{ + if (value == data) { + /* This calls back DRIDrawablePrivDelete which frees private area */ + FreeResourceByType(id, DRIDrawablePrivResType, FALSE); + + return TRUE; + } + + return FALSE; +} + +Bool +DRIDestroyDrawable(ScreenPtr pScreen, ClientPtr client, DrawablePtr pDrawable) +{ + if (pDrawable->type == DRAWABLE_WINDOW) { + LookupClientResourceComplex(client, DRIDrawablePrivResType, + DRIDestroyDrawableCB, + (pointer)(intptr_t)pDrawable->id); + } + else { /* pixmap (or for GLX 1.3, a PBuffer) */ + /* NOT_DONE */ + return FALSE; + } + + return TRUE; +} + +Bool +DRIDrawablePrivDelete(pointer pResource, XID id) +{ + WindowPtr pWin; + int rc; + + /* For DRIDrawablePrivResType, the XID is the client's fake ID. The + * important XID is the value in pResource. */ + id = (XID)(intptr_t)pResource; + rc = dixLookupWindow(&pWin, id, serverClient, DixGetAttrAccess); + + if (rc == Success) { + DRIDrawablePrivPtr pDRIDrwPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + + if (!pDRIDrwPriv) + return FALSE; + + if (--pDRIDrwPriv->refCount == 0) + DRIDrawablePrivDestroy(pWin); + + return TRUE; + } + else { /* pixmap (or for GLX 1.3, a PBuffer) */ + /* NOT_DONE */ + return FALSE; + } +} + +Bool +DRIGetDrawableInfo(ScreenPtr pScreen, + DrawablePtr pDrawable, + unsigned int* index, + unsigned int* stamp, + int* X, + int* Y, + int* W, + int* H, + int* numClipRects, + drm_clip_rect_t ** pClipRects, + int* backX, + int* backY, + int* numBackClipRects, + drm_clip_rect_t ** pBackClipRects) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv, pOldDrawPriv; + WindowPtr pWin, pOldWin; + int i; + +#if 0 + printf("maxDrawableTableEntry = %d\n", pDRIPriv->pDriverInfo->maxDrawableTableEntry); +#endif + + if (pDrawable->type == DRAWABLE_WINDOW) { + pWin = (WindowPtr)pDrawable; + if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { + + /* Manage drawable table */ + if (pDRIDrawablePriv->drawableIndex == -1) { /* load SAREA table */ + + /* Search table for empty entry */ + i = 0; + while (i < pDRIPriv->pDriverInfo->maxDrawableTableEntry) { + if (!(pDRIPriv->DRIDrawables[i])) { + pDRIPriv->DRIDrawables[i] = pDrawable; + pDRIDrawablePriv->drawableIndex = i; + pDRIPriv->pSAREA->drawableTable[i].stamp = + DRIDrawableValidationStamp++; + break; + } + i++; + } + + /* Search table for oldest entry */ + if (i == pDRIPriv->pDriverInfo->maxDrawableTableEntry) { + unsigned int oldestStamp = ~0; + int oldestIndex = 0; + i = pDRIPriv->pDriverInfo->maxDrawableTableEntry; + while (i--) { + if (pDRIPriv->pSAREA->drawableTable[i].stamp < + oldestStamp) { + oldestIndex = i; + oldestStamp = + pDRIPriv->pSAREA->drawableTable[i].stamp; + } + } + pDRIDrawablePriv->drawableIndex = oldestIndex; + + /* release oldest drawable table entry */ + pOldWin = (WindowPtr)pDRIPriv->DRIDrawables[oldestIndex]; + pOldDrawPriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pOldWin); + pOldDrawPriv->drawableIndex = -1; + + /* claim drawable table entry */ + pDRIPriv->DRIDrawables[oldestIndex] = pDrawable; + + /* validate SAREA entry */ + pDRIPriv->pSAREA->drawableTable[oldestIndex].stamp = + DRIDrawableValidationStamp++; + + /* check for stamp wrap around */ + if (oldestStamp > DRIDrawableValidationStamp) { + + /* walk SAREA table and invalidate all drawables */ + for( i=0; + i < pDRIPriv->pDriverInfo->maxDrawableTableEntry; + i++) { + pDRIPriv->pSAREA->drawableTable[i].stamp = + DRIDrawableValidationStamp++; + } + } + } + + /* If the driver wants to be notified when the index is + * set for a drawable, let it know now. + */ + if (pDRIPriv->pDriverInfo->SetDrawableIndex) + pDRIPriv->pDriverInfo->SetDrawableIndex(pWin, + pDRIDrawablePriv->drawableIndex); + + /* reinit drawable ID if window is visible */ + if ((pWin->viewable) && + (pDRIPriv->pDriverInfo->bufferRequests != DRI_NO_WINDOWS)) + { + (*pDRIPriv->pDriverInfo->InitBuffers)(pWin, + &pWin->clipList, pDRIDrawablePriv->drawableIndex); + } + } + + *index = pDRIDrawablePriv->drawableIndex; + *stamp = pDRIPriv->pSAREA->drawableTable[*index].stamp; + *X = (int)(pWin->drawable.x); + *Y = (int)(pWin->drawable.y); +#if 0 + *W = (int)(pWin->winSize.extents.x2 - pWin->winSize.extents.x1); + *H = (int)(pWin->winSize.extents.y2 - pWin->winSize.extents.y1); +#endif + *W = (int)(pWin->drawable.width); + *H = (int)(pWin->drawable.height); + *numClipRects = REGION_NUM_RECTS(&pWin->clipList); + *pClipRects = (drm_clip_rect_t *)REGION_RECTS(&pWin->clipList); + + if (!*numClipRects && pDRIPriv->fullscreen) { + /* use fake full-screen clip rect */ + pDRIPriv->fullscreen_rect.x1 = *X; + pDRIPriv->fullscreen_rect.y1 = *Y; + pDRIPriv->fullscreen_rect.x2 = *X + *W; + pDRIPriv->fullscreen_rect.y2 = *Y + *H; + + *numClipRects = 1; + *pClipRects = &pDRIPriv->fullscreen_rect; + } + + *backX = *X; + *backY = *Y; + + if (pDRIPriv->nrWindowsVisible == 1 && *numClipRects) { + /* Use a single cliprect. */ + + int x0 = *X; + int y0 = *Y; + int x1 = x0 + *W; + int y1 = y0 + *H; + + if (x0 < 0) x0 = 0; + if (y0 < 0) y0 = 0; + if (x1 > pScreen->width) x1 = pScreen->width; + if (y1 > pScreen->height) y1 = pScreen->height; + + if (y0 >= y1 || x0 >= x1) { + *numBackClipRects = 0; + *pBackClipRects = NULL; + } else { + pDRIPriv->private_buffer_rect.x1 = x0; + pDRIPriv->private_buffer_rect.y1 = y0; + pDRIPriv->private_buffer_rect.x2 = x1; + pDRIPriv->private_buffer_rect.y2 = y1; + + *numBackClipRects = 1; + *pBackClipRects = &(pDRIPriv->private_buffer_rect); + } + } else { + /* Use the frontbuffer cliprects for back buffers. */ + *numBackClipRects = 0; + *pBackClipRects = 0; + } + } + else { + /* Not a DRIDrawable */ + return FALSE; + } + } + else { /* pixmap (or for GLX 1.3, a PBuffer) */ + /* NOT_DONE */ + return FALSE; + } + + return TRUE; +} + +Bool +DRIGetDeviceInfo(ScreenPtr pScreen, + drm_handle_t * hFrameBuffer, + int* fbOrigin, + int* fbSize, + int* fbStride, + int* devPrivateSize, + void** pDevPrivate) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + *hFrameBuffer = pDRIPriv->pDriverInfo->hFrameBuffer; + *fbOrigin = 0; + *fbSize = pDRIPriv->pDriverInfo->frameBufferSize; + *fbStride = pDRIPriv->pDriverInfo->frameBufferStride; + *devPrivateSize = pDRIPriv->pDriverInfo->devPrivateSize; + *pDevPrivate = pDRIPriv->pDriverInfo->devPrivate; + + return TRUE; +} + +DRIInfoPtr +DRICreateInfoRec(void) +{ + DRIInfoPtr inforec = (DRIInfoPtr)calloc(1, sizeof(DRIInfoRec)); + if (!inforec) return NULL; + + /* Initialize defaults */ + inforec->busIdString = NULL; + + /* Wrapped function defaults */ + inforec->wrap.WakeupHandler = DRIDoWakeupHandler; + inforec->wrap.BlockHandler = DRIDoBlockHandler; + inforec->wrap.WindowExposures = DRIWindowExposures; + inforec->wrap.CopyWindow = DRICopyWindow; + inforec->wrap.ValidateTree = DRIValidateTree; + inforec->wrap.PostValidateTree = DRIPostValidateTree; + inforec->wrap.ClipNotify = DRIClipNotify; + inforec->wrap.AdjustFrame = DRIAdjustFrame; + + inforec->TransitionTo2d = 0; + inforec->TransitionTo3d = 0; + inforec->SetDrawableIndex = 0; + + return inforec; +} + +void +DRIDestroyInfoRec(DRIInfoPtr DRIInfo) +{ + if (DRIInfo->busIdString) free(DRIInfo->busIdString); + free((char*)DRIInfo); +} + + +void +DRIWakeupHandler(pointer wakeupData, int result, pointer pReadmask) +{ + int i; + + for (i = 0; i < screenInfo.numScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv && + pDRIPriv->pDriverInfo->wrap.WakeupHandler) + (*pDRIPriv->pDriverInfo->wrap.WakeupHandler)(i, wakeupData, + result, pReadmask); + } +} + +void +DRIBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask) +{ + int i; + + for (i = 0; i < screenInfo.numScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv && + pDRIPriv->pDriverInfo->wrap.BlockHandler) + (*pDRIPriv->pDriverInfo->wrap.BlockHandler)(i, blockData, + pTimeout, pReadmask); + } +} + +void +DRIDoWakeupHandler(int screenNum, pointer wakeupData, + unsigned long result, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + DRILock(pScreen, 0); + if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { + /* hide X context by swapping 2D component here */ + (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, + DRI_3D_SYNC, + DRI_2D_CONTEXT, + pDRIPriv->partial3DContextStore, + DRI_2D_CONTEXT, + pDRIPriv->hiddenContextStore); + } +} + +void +DRIDoBlockHandler(int screenNum, pointer blockData, + pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { + /* hide X context by swapping 2D component here */ + (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, + DRI_2D_SYNC, + DRI_NO_CONTEXT, + NULL, + DRI_2D_CONTEXT, + pDRIPriv->partial3DContextStore); + } + + if (pDRIPriv->windowsTouched) + DRM_SPINUNLOCK(&pDRIPriv->pSAREA->drawable_lock, 1); + pDRIPriv->windowsTouched = FALSE; + + DRIUnlock(pScreen); +} + +void +DRISwapContext(int drmFD, void *oldctx, void *newctx) +{ + DRIContextPrivPtr oldContext = (DRIContextPrivPtr)oldctx; + DRIContextPrivPtr newContext = (DRIContextPrivPtr)newctx; + ScreenPtr pScreen = newContext->pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + void* oldContextStore = NULL; + DRIContextType oldContextType; + void* newContextStore = NULL; + DRIContextType newContextType; + DRISyncType syncType; +#ifdef DEBUG + static int count = 0; + + if (!newContext) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[DRI] Context Switch Error: oldContext=%x, newContext=%x\n", + oldContext, newContext); + return; + } + + /* usefull for debugging, just print out after n context switches */ + if (!count || !(count % 1)) { + DRIDrvMsg(pScreen->myNum, X_INFO, + "[DRI] Context switch %5d from %p/0x%08x (%d)\n", + count, + oldContext, + oldContext ? oldContext->flags : 0, + oldContext ? oldContext->hwContext : -1); + DRIDrvMsg(pScreen->myNum, X_INFO, + "[DRI] Context switch %5d to %p/0x%08x (%d)\n", + count, + newContext, + newContext ? newContext->flags : 0, + newContext ? newContext->hwContext : -1); + } + ++count; +#endif + + if (!pDRIPriv->pDriverInfo->SwapContext) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[DRI] DDX driver missing context swap call back\n"); + return; + } + + if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { + + /* only 3D contexts are swapped in this case */ + if (oldContext) { + oldContextStore = DRIGetContextStore(oldContext); + oldContext->valid3D = TRUE; + oldContextType = DRI_3D_CONTEXT; + } else { + oldContextType = DRI_NO_CONTEXT; + } + newContextStore = DRIGetContextStore(newContext); + if ((newContext->valid3D) && + (newContext->hwContext != pDRIPriv->myContext)) { + newContextType = DRI_3D_CONTEXT; + } + else { + newContextType = DRI_2D_CONTEXT; + } + syncType = DRI_3D_SYNC; + } + else /* default: driverSwapMethod == DRI_SERVER_SWAP */ { + + /* optimize 2D context swaps */ + + if (newContext->flags & DRI_CONTEXT_2DONLY) { + /* go from 3D context to 2D context and only save 2D + * subset of 3D state + */ + oldContextStore = DRIGetContextStore(oldContext); + oldContextType = DRI_2D_CONTEXT; + newContextStore = DRIGetContextStore(newContext); + newContextType = DRI_2D_CONTEXT; + syncType = DRI_3D_SYNC; + pDRIPriv->lastPartial3DContext = oldContext; + } + else if (oldContext->flags & DRI_CONTEXT_2DONLY) { + if (pDRIPriv->lastPartial3DContext == newContext) { + /* go from 2D context back to previous 3D context and + * only restore 2D subset of previous 3D state + */ + oldContextStore = DRIGetContextStore(oldContext); + oldContextType = DRI_2D_CONTEXT; + newContextStore = DRIGetContextStore(newContext); + newContextType = DRI_2D_CONTEXT; + syncType = DRI_2D_SYNC; + } + else { + /* go from 2D context to a different 3D context */ + + /* call DDX driver to do partial restore */ + oldContextStore = DRIGetContextStore(oldContext); + newContextStore = + DRIGetContextStore(pDRIPriv->lastPartial3DContext); + (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, + DRI_2D_SYNC, + DRI_2D_CONTEXT, + oldContextStore, + DRI_2D_CONTEXT, + newContextStore); + + /* now setup for a complete 3D swap */ + oldContextStore = newContextStore; + oldContext->valid3D = TRUE; + oldContextType = DRI_3D_CONTEXT; + newContextStore = DRIGetContextStore(newContext); + if ((newContext->valid3D) && + (newContext->hwContext != pDRIPriv->myContext)) { + newContextType = DRI_3D_CONTEXT; + } + else { + newContextType = DRI_2D_CONTEXT; + } + syncType = DRI_NO_SYNC; + } + } + else { + /* now setup for a complete 3D swap */ + oldContextStore = newContextStore; + oldContext->valid3D = TRUE; + oldContextType = DRI_3D_CONTEXT; + newContextStore = DRIGetContextStore(newContext); + if ((newContext->valid3D) && + (newContext->hwContext != pDRIPriv->myContext)) { + newContextType = DRI_3D_CONTEXT; + } + else { + newContextType = DRI_2D_CONTEXT; + } + syncType = DRI_3D_SYNC; + } + } + + /* call DDX driver to perform the swap */ + (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, + syncType, + oldContextType, + oldContextStore, + newContextType, + newContextStore); +} + +void* +DRIGetContextStore(DRIContextPrivPtr context) +{ + return((void *)context->pContextStore); +} + +void +DRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + + if(pDRIDrawablePriv) { + (*pDRIPriv->pDriverInfo->InitBuffers)(pWin, prgn, + pDRIDrawablePriv->drawableIndex); + } + + /* call lower wrapped functions */ + if (pDRIPriv && pDRIPriv->wrap.WindowExposures) { + + /* unwrap */ + pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures; + + /* call lower layers */ + (*pScreen->WindowExposures)(pWin, prgn, bsreg); + + /* rewrap */ + pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; + pScreen->WindowExposures = DRIWindowExposures; + } +} + + +static int +DRITreeTraversal(WindowPtr pWin, pointer data) +{ + DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + + if(pDRIDrawablePriv) { + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if(REGION_NUM_RECTS(&(pWin->clipList)) > 0) { + RegionPtr reg = (RegionPtr)data; + + REGION_UNION(pScreen, reg, reg, &(pWin->clipList)); + pDRIPriv->nrWalked++; + } + + if(pDRIPriv->nrWindows == pDRIPriv->nrWalked) + return WT_STOPWALKING; + } + return WT_WALKCHILDREN; +} + +Bool +DRIDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + Bool retval = TRUE; + + DRIDrawablePrivDestroy(pWin); + + /* call lower wrapped functions */ + if(pDRIPriv->DestroyWindow) { + /* unwrap */ + pScreen->DestroyWindow = pDRIPriv->DestroyWindow; + + /* call lower layers */ + retval = (*pScreen->DestroyWindow)(pWin); + + /* rewrap */ + pDRIPriv->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = DRIDestroyWindow; + } + + return retval; +} + +void +DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if(!pDRIPriv) return; + + if(pDRIPriv->nrWindowsVisible > 0) { + RegionRec reg; + + REGION_NULL(pScreen, ®); + pDRIPriv->nrWalked = 0; + TraverseTree(pWin, DRITreeTraversal, (pointer)(®)); + + if(REGION_NOTEMPTY(pScreen, ®)) { + REGION_TRANSLATE(pScreen, ®, ptOldOrg.x - pWin->drawable.x, + ptOldOrg.y - pWin->drawable.y); + REGION_INTERSECT(pScreen, ®, ®, prgnSrc); + + /* The MoveBuffers interface is not ideal */ + (*pDRIPriv->pDriverInfo->MoveBuffers)(pWin, ptOldOrg, ®, + pDRIPriv->pDriverInfo->ddxDrawableTableEntry); + } + + REGION_UNINIT(pScreen, ®); + } + + /* call lower wrapped functions */ + if(pDRIPriv->wrap.CopyWindow) { + /* unwrap */ + pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow; + + /* call lower layers */ + (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); + + /* rewrap */ + pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; + pScreen->CopyWindow = DRICopyWindow; + } +} + +static void +DRIGetSecs(long *secs, long *usecs) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + *secs = tv.tv_sec; + *usecs = tv.tv_usec; +} + +static unsigned long +DRIComputeMilliSeconds(unsigned long s_secs, unsigned long s_usecs, + unsigned long f_secs, unsigned long f_usecs) +{ + if (f_usecs < s_usecs) { + --f_secs; + f_usecs += 1000000; + } + return (f_secs - s_secs) * 1000 + (f_usecs - s_usecs) / 1000; +} + +static void +DRISpinLockTimeout(drmLock *lock, int val, unsigned long timeout /* in mS */) +{ + int count = 10000; +#if !defined(__alpha__) && !defined(__powerpc__) + char ret; +#else + int ret; +#endif + long s_secs, s_usecs; + long f_secs, f_usecs; + long msecs; + long prev = 0; + + DRIGetSecs(&s_secs, &s_usecs); + + do { + DRM_SPINLOCK_COUNT(lock, val, count, ret); + if (!ret) return; /* Got lock */ + DRIGetSecs(&f_secs, &f_usecs); + msecs = DRIComputeMilliSeconds(s_secs, s_usecs, f_secs, f_usecs); + if (msecs - prev < 250) count *= 2; /* Not more than 0.5S */ + } while (msecs < timeout); + + /* Didn't get lock, so take it. The worst + that can happen is that there is some + garbage written to the wrong part of the + framebuffer that a refresh will repair. + That's undesirable, but better than + locking the server. This should be a + very rare event. */ + DRM_SPINLOCK_TAKE(lock, val); +} + +static void +DRILockTree(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if(!pDRIPriv) return; + + /* Restore the last known 3D context if the X context is hidden */ + if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { + (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, + DRI_2D_SYNC, + DRI_NO_CONTEXT, + NULL, + DRI_2D_CONTEXT, + pDRIPriv->partial3DContextStore); + } + + /* Call kernel to release lock */ + DRIUnlock(pScreen); + + /* Grab drawable spin lock: a time out between 10 and 30 seconds is + appropriate, since this should never time out except in the case of + client death while the lock is being held. The timeout must be + greater than any reasonable rendering time. */ + DRISpinLockTimeout(&pDRIPriv->pSAREA->drawable_lock, 1, 10000); /*10 secs*/ + + /* Call kernel flush outstanding buffers and relock */ + DRILock(pScreen, DRM_LOCK_QUIESCENT|DRM_LOCK_FLUSH_ALL); + + /* Switch back to our 2D context if the X context is hidden */ + if (pDRIPriv->pDriverInfo->driverSwapMethod == DRI_HIDE_X_CONTEXT) { + /* hide X context by swapping 2D component here */ + (*pDRIPriv->pDriverInfo->SwapContext)(pScreen, + DRI_3D_SYNC, + DRI_2D_CONTEXT, + pDRIPriv->partial3DContextStore, + DRI_2D_CONTEXT, + pDRIPriv->hiddenContextStore); + } +} + +int +DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + ScreenPtr pScreen = pParent->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + int returnValue = 1; /* always return 1, not checked by dix/window.c */ + + if(!pDRIPriv) return returnValue; + + /* call lower wrapped functions */ + if(pDRIPriv->wrap.ValidateTree) { + /* unwrap */ + pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree; + + /* call lower layers */ + returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind); + + /* rewrap */ + pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; + pScreen->ValidateTree = DRIValidateTree; + } + + return returnValue; +} + +void +DRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + ScreenPtr pScreen; + DRIScreenPrivPtr pDRIPriv; + + if (pParent) { + pScreen = pParent->drawable.pScreen; + } else { + pScreen = pChild->drawable.pScreen; + } + if(!(pDRIPriv = DRI_SCREEN_PRIV(pScreen))) return; + + if (pDRIPriv->wrap.PostValidateTree) { + /* unwrap */ + pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree; + + /* call lower layers */ + (*pScreen->PostValidateTree)(pParent, pChild, kind); + + /* rewrap */ + pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; + pScreen->PostValidateTree = DRIPostValidateTree; + } +} + +void +DRIClipNotify(WindowPtr pWin, int dx, int dy) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv; + + if(!pDRIPriv) return; + + if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { + int nrects = REGION_NUM_RECTS(&pWin->clipList); + + if(!pDRIPriv->windowsTouched) { + DRILockTree(pScreen); + pDRIPriv->windowsTouched = TRUE; + } + + if (nrects && !pDRIDrawablePriv->nrects) + DRIIncreaseNumberVisible(pScreen); + else if (!nrects && pDRIDrawablePriv->nrects) + DRIDecreaseNumberVisible(pScreen); + else + DRIDriverClipNotify(pScreen); + + pDRIDrawablePriv->nrects = nrects; + + pDRIPriv->pSAREA->drawableTable[pDRIDrawablePriv->drawableIndex].stamp + = DRIDrawableValidationStamp++; + + drmUpdateDrawableInfo(pDRIPriv->drmFD, pDRIDrawablePriv->hwDrawable, + DRM_DRAWABLE_CLIPRECTS, + nrects, REGION_RECTS(&pWin->clipList)); + } + + /* call lower wrapped functions */ + if(pDRIPriv->wrap.ClipNotify) { + + /* unwrap */ + pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify; + + /* call lower layers */ + (*pScreen->ClipNotify)(pWin, dx, dy); + + /* rewrap */ + pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; + pScreen->ClipNotify = DRIClipNotify; + } +} + +CARD32 +DRIGetDrawableIndex(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + CARD32 index; + + if (pDRIDrawablePriv) { + index = pDRIDrawablePriv->drawableIndex; + } + else { + index = pDRIPriv->pDriverInfo->ddxDrawableTableEntry; + } + + return index; +} + +unsigned int +DRIGetDrawableStamp(ScreenPtr pScreen, CARD32 drawable_index) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + return pDRIPriv->pSAREA->drawableTable[drawable_index].stamp; +} + + +void +DRIPrintDrawableLock(ScreenPtr pScreen, char *msg) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + ErrorF("%s: %d\n", msg, pDRIPriv->pSAREA->drawable_lock.lock); +} + +void +DRILock(ScreenPtr pScreen, int flags) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if(!pDRIPriv || !pDRIPriv->pLockRefCount) return; + + if (!*pDRIPriv->pLockRefCount) { + DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext, flags); + *pDRIPriv->pLockingContext = pDRIPriv->myContext; + } else if (*pDRIPriv->pLockingContext != pDRIPriv->myContext) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[DRI] Locking deadlock.\n" + "\tAlready locked with context %d,\n" + "\ttrying to lock with context %d.\n", + pDRIPriv->pLockingContext, + pDRIPriv->myContext); + } + (*pDRIPriv->pLockRefCount)++; +} + +void +DRIUnlock(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if(!pDRIPriv || !pDRIPriv->pLockRefCount) return; + + if (*pDRIPriv->pLockRefCount > 0) { + if (pDRIPriv->myContext != *pDRIPriv->pLockingContext) { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "[DRI] Unlocking inconsistency:\n" + "\tContext %d trying to unlock lock held by context %d\n", + pDRIPriv->pLockingContext, + pDRIPriv->myContext); + } + (*pDRIPriv->pLockRefCount)--; + } else { + DRIDrvMsg(pScreen->myNum, X_ERROR, + "DRIUnlock called when not locked.\n"); + return; + } + if (! *pDRIPriv->pLockRefCount) + DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext); +} + +void * +DRIGetSAREAPrivate(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + if (!pDRIPriv) return 0; + + return (void *)(((char*)pDRIPriv->pSAREA)+sizeof(XF86DRISAREARec)); +} + +drm_context_t +DRIGetContext(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + if (!pDRIPriv) return 0; + + return pDRIPriv->myContext; +} + +void +DRIGetTexOffsetFuncs(ScreenPtr pScreen, + DRITexOffsetStartProcPtr *texOffsetStartFunc, + DRITexOffsetFinishProcPtr *texOffsetFinishFunc) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (!pDRIPriv) return; + + *texOffsetStartFunc = pDRIPriv->pDriverInfo->texOffsetStart; + *texOffsetFinishFunc = pDRIPriv->pDriverInfo->texOffsetFinish; +} + +/* This lets get at the unwrapped functions so that they can correctly + * call the lowerlevel functions, and choose whether they will be + * called at every level of recursion (eg in validatetree). + */ +DRIWrappedFuncsRec * +DRIGetWrappedFuncs(ScreenPtr pScreen) +{ + return &(DRI_SCREEN_PRIV(pScreen)->wrap); +} + +/* note that this returns the library version, not the protocol version */ +void +DRIQueryVersion(int *majorVersion, + int *minorVersion, + int *patchVersion) +{ + *majorVersion = DRIINFO_MAJOR_VERSION; + *minorVersion = DRIINFO_MINOR_VERSION; + *patchVersion = DRIINFO_PATCH_VERSION; +} + +static void +_DRIAdjustFrame(ScrnInfoPtr pScrn, DRIScreenPrivPtr pDRIPriv, int x, int y) +{ + pDRIPriv->pSAREA->frame.x = x; + pDRIPriv->pSAREA->frame.y = y; + pDRIPriv->pSAREA->frame.width = pScrn->frameX1 - x + 1; + pDRIPriv->pSAREA->frame.height = pScrn->frameY1 - y + 1; +} + +void +DRIAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[scrnIndex]; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + int px, py; + + if (!pDRIPriv || !pDRIPriv->pSAREA) { + DRIDrvMsg(scrnIndex, X_ERROR, "[DRI] No SAREA (%p %p)\n", + pDRIPriv, pDRIPriv ? pDRIPriv->pSAREA : NULL); + return; + } + + if (pDRIPriv->fullscreen) { + /* Fix up frame */ + pScrn->frameX0 = pDRIPriv->pSAREA->frame.x; + pScrn->frameY0 = pDRIPriv->pSAREA->frame.y; + pScrn->frameX1 = pScrn->frameX0 + pDRIPriv->pSAREA->frame.width - 1; + pScrn->frameY1 = pScrn->frameY0 + pDRIPriv->pSAREA->frame.height - 1; + + /* Fix up cursor */ + miPointerGetPosition(inputInfo.pointer, &px, &py); + if (px < pScrn->frameX0) px = pScrn->frameX0; + if (px > pScrn->frameX1) px = pScrn->frameX1; + if (py < pScrn->frameY0) py = pScrn->frameY0; + if (py > pScrn->frameY1) py = pScrn->frameY1; + pScreen->SetCursorPosition(inputInfo.pointer, pScreen, px, py, TRUE); + return; + } + + if (pDRIPriv->wrap.AdjustFrame) { + /* unwrap */ + pScrn->AdjustFrame = pDRIPriv->wrap.AdjustFrame; + /* call lower layers */ + (*pScrn->AdjustFrame)(scrnIndex, x, y, flags); + /* rewrap */ + pDRIPriv->wrap.AdjustFrame = pScrn->AdjustFrame; + pScrn->AdjustFrame = DRIAdjustFrame; + } + + _DRIAdjustFrame(pScrn, pDRIPriv, x, y); +} + +/* + * DRIMoveBuffersHelper swaps the regions rects in place leaving you + * a region with the rects in the order that you need to blit them, + * but it is possibly (likely) an invalid region afterwards. If you + * need to use the region again for anything you have to call + * REGION_VALIDATE on it, or better yet, save a copy first. + */ + +void +DRIMoveBuffersHelper( + ScreenPtr pScreen, + int dx, + int dy, + int *xdir, + int *ydir, + RegionPtr reg +) +{ + BoxPtr extents, pbox, firstBox, lastBox; + BoxRec tmpBox; + int y, nbox; + + extents = REGION_EXTENTS(pScreen, reg); + nbox = REGION_NUM_RECTS(reg); + pbox = REGION_RECTS(reg); + + if((dy > 0) && (dy < (extents->y2 - extents->y1))) { + *ydir = -1; + if(nbox > 1) { + firstBox = pbox; + lastBox = pbox + nbox - 1; + while((unsigned long)firstBox < (unsigned long)lastBox) { + tmpBox = *firstBox; + *firstBox = *lastBox; + *lastBox = tmpBox; + firstBox++; + lastBox--; + } + } + } else *ydir = 1; + + if((dx > 0) && (dx < (extents->x2 - extents->x1))) { + *xdir = -1; + if(nbox > 1) { + firstBox = lastBox = pbox; + y = pbox->y1; + while(--nbox) { + pbox++; + if(pbox->y1 == y) lastBox++; + else { + while((unsigned long)firstBox < (unsigned long)lastBox) { + tmpBox = *firstBox; + *firstBox = *lastBox; + *lastBox = tmpBox; + firstBox++; + lastBox--; + } + + firstBox = lastBox = pbox; + y = pbox->y1; + } + } + while((unsigned long)firstBox < (unsigned long)lastBox) { + tmpBox = *firstBox; + *firstBox = *lastBox; + *lastBox = tmpBox; + firstBox++; + lastBox--; + } + } + } else *xdir = 1; + +} + +char * +DRICreatePCIBusID(const struct pci_device * dev) +{ + char *busID; + + busID = malloc(20); + if (busID == NULL) + return NULL; + + snprintf(busID, 20, "pci:%04x:%02x:%02x.%d", dev->domain, dev->bus, + dev->dev, dev->func); + + return busID; +} + +static void drmSIGIOHandler(int interrupt, void *closure) +{ + unsigned long key; + void *value; + ssize_t count; + drm_ctx_t ctx; + typedef void (*_drmCallback)(int, void *, void *); + char buf[256]; + drm_context_t old; + drm_context_t new; + void *oldctx; + void *newctx; + char *pt; + drmHashEntry *entry; + void *hash_table; + + hash_table = drmGetHashTable(); + + if (!hash_table) return; + if (drmHashFirst(hash_table, &key, &value)) { + entry = value; + do { +#if 0 + fprintf(stderr, "Trying %d\n", entry->fd); +#endif + if ((count = read(entry->fd, buf, sizeof(buf) - 1)) > 0) { + buf[count] = '\0'; +#if 0 + fprintf(stderr, "Got %s\n", buf); +#endif + + for (pt = buf; *pt != ' '; ++pt); /* Find first space */ + ++pt; + old = strtol(pt, &pt, 0); + new = strtol(pt, NULL, 0); + oldctx = drmGetContextTag(entry->fd, old); + newctx = drmGetContextTag(entry->fd, new); +#if 0 + fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx); +#endif + ((_drmCallback)entry->f)(entry->fd, oldctx, newctx); + ctx.handle = new; + ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx); + } + } while (drmHashNext(hash_table, &key, &value)); + } +} + + +int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *)) +{ + drmHashEntry *entry; + + entry = drmGetEntry(fd); + entry->f = f; + + return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0); +} + +int drmRemoveSIGIOHandler(int fd) +{ + drmHashEntry *entry = drmGetEntry(fd); + + entry->f = NULL; + + return xf86RemoveSIGIOHandler(fd); +} diff --git a/xorg-server/hw/xfree86/dri/xf86dri.c b/xorg-server/hw/xfree86/dri/xf86dri.c index 78003991b..40914ed19 100644 --- a/xorg-server/hw/xfree86/dri/xf86dri.c +++ b/xorg-server/hw/xfree86/dri/xf86dri.c @@ -1,679 +1,679 @@ -/************************************************************************** - -Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. -Copyright 2000 VA Linux Systems, 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, sub license, 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 NON-INFRINGEMENT. -IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. - -**************************************************************************/ - -/* - * Authors: - * Kevin E. Martin <martin@valinux.com> - * Jens Owen <jens@tungstengraphics.com> - * Rickard E. (Rik) Faith <faith@valinux.com> - * - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "xf86.h" - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "servermd.h" -#define _XF86DRI_SERVER_ -#include <X11/dri/xf86driproto.h> -#include "swaprep.h" -#include "xf86str.h" -#include "dri.h" -#include "sarea.h" -#include "dristruct.h" -#include "xf86.h" -#include "xf86drm.h" -#include "protocol-versions.h" - -static int DRIErrorBase; - -static DISPATCH_PROC(ProcXF86DRIQueryVersion); -static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable); -static DISPATCH_PROC(ProcXF86DRIOpenConnection); -static DISPATCH_PROC(ProcXF86DRICloseConnection); -static DISPATCH_PROC(ProcXF86DRIGetClientDriverName); -static DISPATCH_PROC(ProcXF86DRICreateContext); -static DISPATCH_PROC(ProcXF86DRIDestroyContext); -static DISPATCH_PROC(ProcXF86DRICreateDrawable); -static DISPATCH_PROC(ProcXF86DRIDestroyDrawable); -static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo); -static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo); -static DISPATCH_PROC(ProcXF86DRIDispatch); -static DISPATCH_PROC(ProcXF86DRIAuthConnection); - -static DISPATCH_PROC(SProcXF86DRIQueryVersion); -static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable); -static DISPATCH_PROC(SProcXF86DRIDispatch); - -static void XF86DRIResetProc(ExtensionEntry* extEntry); - -static unsigned char DRIReqCode = 0; - -extern void XFree86DRIExtensionInit(void); - -void -XFree86DRIExtensionInit(void) -{ - ExtensionEntry* extEntry; - -#ifdef XF86DRI_EVENTS - EventType = CreateNewResourceType(XF86DRIFreeEvents, "DRIEvent"); -#endif - - if ( - DRIExtensionInit() && -#ifdef XF86DRI_EVENTS - EventType && ScreenPrivateIndex != -1 && -#endif - (extEntry = AddExtension(XF86DRINAME, - XF86DRINumberEvents, - XF86DRINumberErrors, - ProcXF86DRIDispatch, - SProcXF86DRIDispatch, - XF86DRIResetProc, - StandardMinorOpcode))) { - DRIReqCode = (unsigned char)extEntry->base; - DRIErrorBase = extEntry->errorBase; - } -} - -/*ARGSUSED*/ -static void -XF86DRIResetProc ( - ExtensionEntry* extEntry -) -{ - DRIReset(); -} - -static int -ProcXF86DRIQueryVersion( - register ClientPtr client -) -{ - xXF86DRIQueryVersionReply rep; - register int n; - - REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_XF86DRI_MAJOR_VERSION; - rep.minorVersion = SERVER_XF86DRI_MINOR_VERSION; - rep.patchVersion = SERVER_XF86DRI_PATCH_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - swapl(&rep.patchVersion, n); - } - WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86DRIQueryDirectRenderingCapable( - register ClientPtr client -) -{ - xXF86DRIQueryDirectRenderingCapableReply rep; - Bool isCapable; - register int n; - - REQUEST(xXF86DRIQueryDirectRenderingCapableReq); - REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if (!DRIQueryDirectRenderingCapable( screenInfo.screens[stuff->screen], - &isCapable)) { - return BadValue; - } - rep.isCapable = isCapable; - - if (!LocalClient(client) || client->swapped) - rep.isCapable = 0; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - } - - WriteToClient(client, - sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86DRIOpenConnection( - register ClientPtr client -) -{ - xXF86DRIOpenConnectionReply rep; - drm_handle_t hSAREA; - char* busIdString; - - REQUEST(xXF86DRIOpenConnectionReq); - REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - if (!DRIOpenConnection( screenInfo.screens[stuff->screen], - &hSAREA, - &busIdString)) { - return BadValue; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.busIdStringLength = 0; - if (busIdString) - rep.busIdStringLength = strlen(busIdString); - rep.length = bytes_to_int32(SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) + - pad_to_int32(rep.busIdStringLength)); - - rep.hSAREALow = (CARD32)(hSAREA & 0xffffffff); -#if defined(LONG64) && !defined(__linux__) - rep.hSAREAHigh = (CARD32)(hSAREA >> 32); -#else - rep.hSAREAHigh = 0; -#endif - - WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep); - if (rep.busIdStringLength) - WriteToClient(client, rep.busIdStringLength, busIdString); - return (client->noClientException); -} - -static int -ProcXF86DRIAuthConnection( - register ClientPtr client -) -{ - xXF86DRIAuthConnectionReply rep; - - REQUEST(xXF86DRIAuthConnectionReq); - REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.authenticated = 1; - - if (!DRIAuthConnection( screenInfo.screens[stuff->screen], stuff->magic)) { - ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic); - rep.authenticated = 0; - } - WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86DRICloseConnection( - register ClientPtr client -) -{ - REQUEST(xXF86DRICloseConnectionReq); - REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - DRICloseConnection( screenInfo.screens[stuff->screen]); - - return (client->noClientException); -} - -static int -ProcXF86DRIGetClientDriverName( - register ClientPtr client -) -{ - xXF86DRIGetClientDriverNameReply rep; - char* clientDriverName; - - REQUEST(xXF86DRIGetClientDriverNameReq); - REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - DRIGetClientDriverName( screenInfo.screens[stuff->screen], - (int *)&rep.ddxDriverMajorVersion, - (int *)&rep.ddxDriverMinorVersion, - (int *)&rep.ddxDriverPatchVersion, - &clientDriverName); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.clientDriverNameLength = 0; - if (clientDriverName) - rep.clientDriverNameLength = strlen(clientDriverName); - rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetClientDriverNameReply) - - SIZEOF(xGenericReply) + - pad_to_int32(rep.clientDriverNameLength)); - - WriteToClient(client, - sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep); - if (rep.clientDriverNameLength) - WriteToClient(client, - rep.clientDriverNameLength, - clientDriverName); - return (client->noClientException); -} - -static int -ProcXF86DRICreateContext( - register ClientPtr client -) -{ - xXF86DRICreateContextReply rep; - ScreenPtr pScreen; - - REQUEST(xXF86DRICreateContextReq); - REQUEST_SIZE_MATCH(xXF86DRICreateContextReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - pScreen = screenInfo.screens[stuff->screen]; - - if (!DRICreateContext( pScreen, - NULL, - stuff->context, - (drm_context_t *)&rep.hHWContext)) { - return BadValue; - } - - WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86DRIDestroyContext( - register ClientPtr client -) -{ - REQUEST(xXF86DRIDestroyContextReq); - REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - if (!DRIDestroyContext( screenInfo.screens[stuff->screen], - stuff->context)) { - return BadValue; - } - - return (client->noClientException); -} - -static int -ProcXF86DRICreateDrawable( - ClientPtr client -) -{ - xXF86DRICreateDrawableReply rep; - DrawablePtr pDrawable; - int rc; - - REQUEST(xXF86DRICreateDrawableReq); - REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - if (!DRICreateDrawable(screenInfo.screens[stuff->screen], client, - pDrawable, (drm_drawable_t *)&rep.hHWDrawable)) { - return BadValue; - } - - WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcXF86DRIDestroyDrawable( - register ClientPtr client -) -{ - REQUEST(xXF86DRIDestroyDrawableReq); - DrawablePtr pDrawable; - int rc; - REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq); - - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - if (!DRIDestroyDrawable(screenInfo.screens[stuff->screen], client, - pDrawable)) { - return BadValue; - } - - return (client->noClientException); -} - -static int -ProcXF86DRIGetDrawableInfo( - register ClientPtr client -) -{ - xXF86DRIGetDrawableInfoReply rep; - DrawablePtr pDrawable; - int X, Y, W, H; - drm_clip_rect_t * pClipRects, *pClippedRects; - drm_clip_rect_t * pBackClipRects; - int backX, backY, rc; - - REQUEST(xXF86DRIGetDrawableInfoReq); - REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - if (!DRIGetDrawableInfo( screenInfo.screens[stuff->screen], - pDrawable, - (unsigned int*)&rep.drawableTableIndex, - (unsigned int*)&rep.drawableTableStamp, - (int*)&X, - (int*)&Y, - (int*)&W, - (int*)&H, - (int*)&rep.numClipRects, - &pClipRects, - &backX, - &backY, - (int*)&rep.numBackClipRects, - &pBackClipRects)) { - return BadValue; - } - - rep.drawableX = X; - rep.drawableY = Y; - rep.drawableWidth = W; - rep.drawableHeight = H; - rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) - - SIZEOF(xGenericReply)); - - rep.backX = backX; - rep.backY = backY; - - if (rep.numBackClipRects) - rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects; - - pClippedRects = pClipRects; - - if (rep.numClipRects) { - /* Clip cliprects to screen dimensions (redirected windows) */ - pClippedRects = xalloc(rep.numClipRects * sizeof(drm_clip_rect_t)); - - if (pClippedRects) { - ScreenPtr pScreen = screenInfo.screens[stuff->screen]; - int i, j; - - for (i = 0, j = 0; i < rep.numClipRects; i++) { - pClippedRects[j].x1 = max(pClipRects[i].x1, 0); - pClippedRects[j].y1 = max(pClipRects[i].y1, 0); - pClippedRects[j].x2 = min(pClipRects[i].x2, pScreen->width); - pClippedRects[j].y2 = min(pClipRects[i].y2, pScreen->height); - - if (pClippedRects[j].x1 < pClippedRects[j].x2 && - pClippedRects[j].y1 < pClippedRects[j].y2) { - j++; - } - } - - rep.numClipRects = j; - } else { - rep.numClipRects = 0; - } - - rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects; - } - - rep.length = bytes_to_int32(rep.length); - - WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep); - - if (rep.numClipRects) { - WriteToClient(client, - sizeof(drm_clip_rect_t) * rep.numClipRects, - (char *)pClippedRects); - xfree(pClippedRects); - } - - if (rep.numBackClipRects) { - WriteToClient(client, - sizeof(drm_clip_rect_t) * rep.numBackClipRects, - (char *)pBackClipRects); - } - - return (client->noClientException); -} - -static int -ProcXF86DRIGetDeviceInfo( - register ClientPtr client -) -{ - xXF86DRIGetDeviceInfoReply rep; - drm_handle_t hFrameBuffer; - void *pDevPrivate; - - REQUEST(xXF86DRIGetDeviceInfoReq); - REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq); - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if (!DRIGetDeviceInfo( screenInfo.screens[stuff->screen], - &hFrameBuffer, - (int*)&rep.framebufferOrigin, - (int*)&rep.framebufferSize, - (int*)&rep.framebufferStride, - (int*)&rep.devPrivateSize, - &pDevPrivate)) { - return BadValue; - } - - rep.hFrameBufferLow = (CARD32)(hFrameBuffer & 0xffffffff); -#if defined(LONG64) && !defined(__linux__) - rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32); -#else - rep.hFrameBufferHigh = 0; -#endif - - rep.length = 0; - if (rep.devPrivateSize) { - rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetDeviceInfoReply) - - SIZEOF(xGenericReply) + - pad_to_int32(rep.devPrivateSize)); - } - - WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep); - if (rep.length) { - WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate); - } - return (client->noClientException); -} - -static int -ProcXF86DRIDispatch ( - register ClientPtr client -) -{ - REQUEST(xReq); - - switch (stuff->data) - { - case X_XF86DRIQueryVersion: - return ProcXF86DRIQueryVersion(client); - case X_XF86DRIQueryDirectRenderingCapable: - return ProcXF86DRIQueryDirectRenderingCapable(client); - } - - if (!LocalClient(client)) - return DRIErrorBase + XF86DRIClientNotLocal; - - switch (stuff->data) - { - case X_XF86DRIOpenConnection: - return ProcXF86DRIOpenConnection(client); - case X_XF86DRICloseConnection: - return ProcXF86DRICloseConnection(client); - case X_XF86DRIGetClientDriverName: - return ProcXF86DRIGetClientDriverName(client); - case X_XF86DRICreateContext: - return ProcXF86DRICreateContext(client); - case X_XF86DRIDestroyContext: - return ProcXF86DRIDestroyContext(client); - case X_XF86DRICreateDrawable: - return ProcXF86DRICreateDrawable(client); - case X_XF86DRIDestroyDrawable: - return ProcXF86DRIDestroyDrawable(client); - case X_XF86DRIGetDrawableInfo: - return ProcXF86DRIGetDrawableInfo(client); - case X_XF86DRIGetDeviceInfo: - return ProcXF86DRIGetDeviceInfo(client); - case X_XF86DRIAuthConnection: - return ProcXF86DRIAuthConnection(client); - /* {Open,Close}FullScreen are deprecated now */ - default: - return BadRequest; - } -} - -static int -SProcXF86DRIQueryVersion( - register ClientPtr client -) -{ - register int n; - REQUEST(xXF86DRIQueryVersionReq); - swaps(&stuff->length, n); - return ProcXF86DRIQueryVersion(client); -} - -static int -SProcXF86DRIQueryDirectRenderingCapable( - register ClientPtr client -) -{ - register int n; - REQUEST(xXF86DRIQueryDirectRenderingCapableReq); - swaps(&stuff->length, n); - swapl(&stuff->screen, n); - return ProcXF86DRIQueryDirectRenderingCapable(client); -} - -static int -SProcXF86DRIDispatch ( - register ClientPtr client -) -{ - REQUEST(xReq); - - /* - * Only local clients are allowed DRI access, but remote clients still need - * these requests to find out cleanly. - */ - switch (stuff->data) - { - case X_XF86DRIQueryVersion: - return SProcXF86DRIQueryVersion(client); - case X_XF86DRIQueryDirectRenderingCapable: - return SProcXF86DRIQueryDirectRenderingCapable(client); - default: - return DRIErrorBase + XF86DRIClientNotLocal; - } -} +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, 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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Jens Owen <jens@tungstengraphics.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "xf86.h" + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "servermd.h" +#define _XF86DRI_SERVER_ +#include <X11/dri/xf86driproto.h> +#include "swaprep.h" +#include "xf86str.h" +#include "dri.h" +#include "sarea.h" +#include "dristruct.h" +#include "xf86.h" +#include "xf86drm.h" +#include "protocol-versions.h" + +static int DRIErrorBase; + +static DISPATCH_PROC(ProcXF86DRIQueryVersion); +static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable); +static DISPATCH_PROC(ProcXF86DRIOpenConnection); +static DISPATCH_PROC(ProcXF86DRICloseConnection); +static DISPATCH_PROC(ProcXF86DRIGetClientDriverName); +static DISPATCH_PROC(ProcXF86DRICreateContext); +static DISPATCH_PROC(ProcXF86DRIDestroyContext); +static DISPATCH_PROC(ProcXF86DRICreateDrawable); +static DISPATCH_PROC(ProcXF86DRIDestroyDrawable); +static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo); +static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo); +static DISPATCH_PROC(ProcXF86DRIDispatch); +static DISPATCH_PROC(ProcXF86DRIAuthConnection); + +static DISPATCH_PROC(SProcXF86DRIQueryVersion); +static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable); +static DISPATCH_PROC(SProcXF86DRIDispatch); + +static void XF86DRIResetProc(ExtensionEntry* extEntry); + +static unsigned char DRIReqCode = 0; + +extern void XFree86DRIExtensionInit(void); + +void +XFree86DRIExtensionInit(void) +{ + ExtensionEntry* extEntry; + +#ifdef XF86DRI_EVENTS + EventType = CreateNewResourceType(XF86DRIFreeEvents, "DRIEvent"); +#endif + + if ( + DRIExtensionInit() && +#ifdef XF86DRI_EVENTS + EventType && ScreenPrivateIndex != -1 && +#endif + (extEntry = AddExtension(XF86DRINAME, + XF86DRINumberEvents, + XF86DRINumberErrors, + ProcXF86DRIDispatch, + SProcXF86DRIDispatch, + XF86DRIResetProc, + StandardMinorOpcode))) { + DRIReqCode = (unsigned char)extEntry->base; + DRIErrorBase = extEntry->errorBase; + } +} + +/*ARGSUSED*/ +static void +XF86DRIResetProc ( + ExtensionEntry* extEntry +) +{ + DRIReset(); +} + +static int +ProcXF86DRIQueryVersion( + register ClientPtr client +) +{ + xXF86DRIQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_XF86DRI_MAJOR_VERSION; + rep.minorVersion = SERVER_XF86DRI_MINOR_VERSION; + rep.patchVersion = SERVER_XF86DRI_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + swapl(&rep.patchVersion, n); + } + WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep); + return Success; +} + +static int +ProcXF86DRIQueryDirectRenderingCapable( + register ClientPtr client +) +{ + xXF86DRIQueryDirectRenderingCapableReply rep; + Bool isCapable; + register int n; + + REQUEST(xXF86DRIQueryDirectRenderingCapableReq); + REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!DRIQueryDirectRenderingCapable( screenInfo.screens[stuff->screen], + &isCapable)) { + return BadValue; + } + rep.isCapable = isCapable; + + if (!LocalClient(client) || client->swapped) + rep.isCapable = 0; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + + WriteToClient(client, + sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep); + return Success; +} + +static int +ProcXF86DRIOpenConnection( + register ClientPtr client +) +{ + xXF86DRIOpenConnectionReply rep; + drm_handle_t hSAREA; + char* busIdString; + + REQUEST(xXF86DRIOpenConnectionReq); + REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + if (!DRIOpenConnection( screenInfo.screens[stuff->screen], + &hSAREA, + &busIdString)) { + return BadValue; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.busIdStringLength = 0; + if (busIdString) + rep.busIdStringLength = strlen(busIdString); + rep.length = bytes_to_int32(SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) + + pad_to_int32(rep.busIdStringLength)); + + rep.hSAREALow = (CARD32)(hSAREA & 0xffffffff); +#if defined(LONG64) && !defined(__linux__) + rep.hSAREAHigh = (CARD32)(hSAREA >> 32); +#else + rep.hSAREAHigh = 0; +#endif + + WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep); + if (rep.busIdStringLength) + WriteToClient(client, rep.busIdStringLength, busIdString); + return Success; +} + +static int +ProcXF86DRIAuthConnection( + register ClientPtr client +) +{ + xXF86DRIAuthConnectionReply rep; + + REQUEST(xXF86DRIAuthConnectionReq); + REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.authenticated = 1; + + if (!DRIAuthConnection( screenInfo.screens[stuff->screen], stuff->magic)) { + ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic); + rep.authenticated = 0; + } + WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep); + return Success; +} + +static int +ProcXF86DRICloseConnection( + register ClientPtr client +) +{ + REQUEST(xXF86DRICloseConnectionReq); + REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + DRICloseConnection( screenInfo.screens[stuff->screen]); + + return Success; +} + +static int +ProcXF86DRIGetClientDriverName( + register ClientPtr client +) +{ + xXF86DRIGetClientDriverNameReply rep; + char* clientDriverName; + + REQUEST(xXF86DRIGetClientDriverNameReq); + REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + DRIGetClientDriverName( screenInfo.screens[stuff->screen], + (int *)&rep.ddxDriverMajorVersion, + (int *)&rep.ddxDriverMinorVersion, + (int *)&rep.ddxDriverPatchVersion, + &clientDriverName); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.clientDriverNameLength = 0; + if (clientDriverName) + rep.clientDriverNameLength = strlen(clientDriverName); + rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetClientDriverNameReply) - + SIZEOF(xGenericReply) + + pad_to_int32(rep.clientDriverNameLength)); + + WriteToClient(client, + sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep); + if (rep.clientDriverNameLength) + WriteToClient(client, + rep.clientDriverNameLength, + clientDriverName); + return Success; +} + +static int +ProcXF86DRICreateContext( + register ClientPtr client +) +{ + xXF86DRICreateContextReply rep; + ScreenPtr pScreen; + + REQUEST(xXF86DRICreateContextReq); + REQUEST_SIZE_MATCH(xXF86DRICreateContextReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + pScreen = screenInfo.screens[stuff->screen]; + + if (!DRICreateContext( pScreen, + NULL, + stuff->context, + (drm_context_t *)&rep.hHWContext)) { + return BadValue; + } + + WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep); + return Success; +} + +static int +ProcXF86DRIDestroyContext( + register ClientPtr client +) +{ + REQUEST(xXF86DRIDestroyContextReq); + REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + if (!DRIDestroyContext( screenInfo.screens[stuff->screen], + stuff->context)) { + return BadValue; + } + + return Success; +} + +static int +ProcXF86DRICreateDrawable( + ClientPtr client +) +{ + xXF86DRICreateDrawableReply rep; + DrawablePtr pDrawable; + int rc; + + REQUEST(xXF86DRICreateDrawableReq); + REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + if (!DRICreateDrawable(screenInfo.screens[stuff->screen], client, + pDrawable, (drm_drawable_t *)&rep.hHWDrawable)) { + return BadValue; + } + + WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep); + return Success; +} + +static int +ProcXF86DRIDestroyDrawable( + register ClientPtr client +) +{ + REQUEST(xXF86DRIDestroyDrawableReq); + DrawablePtr pDrawable; + int rc; + REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq); + + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + if (!DRIDestroyDrawable(screenInfo.screens[stuff->screen], client, + pDrawable)) { + return BadValue; + } + + return Success; +} + +static int +ProcXF86DRIGetDrawableInfo( + register ClientPtr client +) +{ + xXF86DRIGetDrawableInfoReply rep; + DrawablePtr pDrawable; + int X, Y, W, H; + drm_clip_rect_t * pClipRects, *pClippedRects; + drm_clip_rect_t * pBackClipRects; + int backX, backY, rc; + + REQUEST(xXF86DRIGetDrawableInfoReq); + REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + if (!DRIGetDrawableInfo( screenInfo.screens[stuff->screen], + pDrawable, + (unsigned int*)&rep.drawableTableIndex, + (unsigned int*)&rep.drawableTableStamp, + (int*)&X, + (int*)&Y, + (int*)&W, + (int*)&H, + (int*)&rep.numClipRects, + &pClipRects, + &backX, + &backY, + (int*)&rep.numBackClipRects, + &pBackClipRects)) { + return BadValue; + } + + rep.drawableX = X; + rep.drawableY = Y; + rep.drawableWidth = W; + rep.drawableHeight = H; + rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) - + SIZEOF(xGenericReply)); + + rep.backX = backX; + rep.backY = backY; + + if (rep.numBackClipRects) + rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects; + + pClippedRects = pClipRects; + + if (rep.numClipRects) { + /* Clip cliprects to screen dimensions (redirected windows) */ + pClippedRects = malloc(rep.numClipRects * sizeof(drm_clip_rect_t)); + + if (pClippedRects) { + ScreenPtr pScreen = screenInfo.screens[stuff->screen]; + int i, j; + + for (i = 0, j = 0; i < rep.numClipRects; i++) { + pClippedRects[j].x1 = max(pClipRects[i].x1, 0); + pClippedRects[j].y1 = max(pClipRects[i].y1, 0); + pClippedRects[j].x2 = min(pClipRects[i].x2, pScreen->width); + pClippedRects[j].y2 = min(pClipRects[i].y2, pScreen->height); + + if (pClippedRects[j].x1 < pClippedRects[j].x2 && + pClippedRects[j].y1 < pClippedRects[j].y2) { + j++; + } + } + + rep.numClipRects = j; + } else { + rep.numClipRects = 0; + } + + rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects; + } + + rep.length = bytes_to_int32(rep.length); + + WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep); + + if (rep.numClipRects) { + WriteToClient(client, + sizeof(drm_clip_rect_t) * rep.numClipRects, + (char *)pClippedRects); + free(pClippedRects); + } + + if (rep.numBackClipRects) { + WriteToClient(client, + sizeof(drm_clip_rect_t) * rep.numBackClipRects, + (char *)pBackClipRects); + } + + return Success; +} + +static int +ProcXF86DRIGetDeviceInfo( + register ClientPtr client +) +{ + xXF86DRIGetDeviceInfoReply rep; + drm_handle_t hFrameBuffer; + void *pDevPrivate; + + REQUEST(xXF86DRIGetDeviceInfoReq); + REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq); + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!DRIGetDeviceInfo( screenInfo.screens[stuff->screen], + &hFrameBuffer, + (int*)&rep.framebufferOrigin, + (int*)&rep.framebufferSize, + (int*)&rep.framebufferStride, + (int*)&rep.devPrivateSize, + &pDevPrivate)) { + return BadValue; + } + + rep.hFrameBufferLow = (CARD32)(hFrameBuffer & 0xffffffff); +#if defined(LONG64) && !defined(__linux__) + rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32); +#else + rep.hFrameBufferHigh = 0; +#endif + + rep.length = 0; + if (rep.devPrivateSize) { + rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetDeviceInfoReply) - + SIZEOF(xGenericReply) + + pad_to_int32(rep.devPrivateSize)); + } + + WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep); + if (rep.length) { + WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate); + } + return Success; +} + +static int +ProcXF86DRIDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_XF86DRIQueryVersion: + return ProcXF86DRIQueryVersion(client); + case X_XF86DRIQueryDirectRenderingCapable: + return ProcXF86DRIQueryDirectRenderingCapable(client); + } + + if (!LocalClient(client)) + return DRIErrorBase + XF86DRIClientNotLocal; + + switch (stuff->data) + { + case X_XF86DRIOpenConnection: + return ProcXF86DRIOpenConnection(client); + case X_XF86DRICloseConnection: + return ProcXF86DRICloseConnection(client); + case X_XF86DRIGetClientDriverName: + return ProcXF86DRIGetClientDriverName(client); + case X_XF86DRICreateContext: + return ProcXF86DRICreateContext(client); + case X_XF86DRIDestroyContext: + return ProcXF86DRIDestroyContext(client); + case X_XF86DRICreateDrawable: + return ProcXF86DRICreateDrawable(client); + case X_XF86DRIDestroyDrawable: + return ProcXF86DRIDestroyDrawable(client); + case X_XF86DRIGetDrawableInfo: + return ProcXF86DRIGetDrawableInfo(client); + case X_XF86DRIGetDeviceInfo: + return ProcXF86DRIGetDeviceInfo(client); + case X_XF86DRIAuthConnection: + return ProcXF86DRIAuthConnection(client); + /* {Open,Close}FullScreen are deprecated now */ + default: + return BadRequest; + } +} + +static int +SProcXF86DRIQueryVersion( + register ClientPtr client +) +{ + register int n; + REQUEST(xXF86DRIQueryVersionReq); + swaps(&stuff->length, n); + return ProcXF86DRIQueryVersion(client); +} + +static int +SProcXF86DRIQueryDirectRenderingCapable( + register ClientPtr client +) +{ + register int n; + REQUEST(xXF86DRIQueryDirectRenderingCapableReq); + swaps(&stuff->length, n); + swapl(&stuff->screen, n); + return ProcXF86DRIQueryDirectRenderingCapable(client); +} + +static int +SProcXF86DRIDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + /* + * Only local clients are allowed DRI access, but remote clients still need + * these requests to find out cleanly. + */ + switch (stuff->data) + { + case X_XF86DRIQueryVersion: + return SProcXF86DRIQueryVersion(client); + case X_XF86DRIQueryDirectRenderingCapable: + return SProcXF86DRIQueryDirectRenderingCapable(client); + default: + return DRIErrorBase + XF86DRIClientNotLocal; + } +} diff --git a/xorg-server/hw/xfree86/dri2/dri2.c b/xorg-server/hw/xfree86/dri2/dri2.c index abcb96668..64be079ca 100644 --- a/xorg-server/hw/xfree86/dri2/dri2.c +++ b/xorg-server/hw/xfree86/dri2/dri2.c @@ -96,6 +96,8 @@ typedef struct _DRI2Screen { DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC; HandleExposuresProcPtr HandleExposures; + + ConfigNotifyProcPtr ConfigNotify; } DRI2ScreenRec; static DRI2ScreenPtr @@ -128,7 +130,7 @@ DRI2AllocateDrawable(DrawablePtr pDraw) WindowPtr pWin; PixmapPtr pPixmap; - pPriv = xalloc(sizeof *pPriv); + pPriv = malloc(sizeof *pPriv); if (pPriv == NULL) return NULL; @@ -165,9 +167,11 @@ DRI2AllocateDrawable(DrawablePtr pDraw) } typedef struct DRI2DrawableRefRec { - XID id; - XID dri2_id; - struct list link; + XID id; + XID dri2_id; + DRI2InvalidateProcPtr invalidate; + void *priv; + struct list link; } DRI2DrawableRefRec, *DRI2DrawableRefPtr; static DRI2DrawableRefPtr @@ -184,7 +188,8 @@ DRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id) } static int -DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id) +DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id, + DRI2InvalidateProcPtr invalidate, void *priv) { DRI2DrawableRefPtr ref; @@ -200,13 +205,16 @@ DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id) ref->id = id; ref->dri2_id = dri2_id; + ref->invalidate = invalidate; + ref->priv = priv; list_add(&ref->link, &pPriv->reference_list); return Success; } int -DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id) +DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id, + DRI2InvalidateProcPtr invalidate, void *priv) { DRI2DrawablePtr pPriv; XID dri2_id; @@ -219,7 +227,7 @@ DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id) return BadAlloc; dri2_id = FakeClientID(client->index); - rc = DRI2AddDrawableRef(pPriv, id, dri2_id); + rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv); if (rc != Success) return rc; @@ -270,10 +278,10 @@ static int DRI2DrawableGone(pointer p, XID id) for (i = 0; i < pPriv->bufferCount; i++) (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); - xfree(pPriv->buffers); + free(pPriv->buffers); } - xfree(pPriv); + free(pPriv); return Success; } @@ -318,6 +326,31 @@ allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds, } } +static void +update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw, + DRI2BufferPtr *buffers, int *out_count, int *width, int *height) +{ + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); + int i; + + if (pPriv->buffers != NULL) { + for (i = 0; i < pPriv->bufferCount; i++) { + if (pPriv->buffers[i] != NULL) { + (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); + } + } + + free(pPriv->buffers); + } + + pPriv->buffers = buffers; + pPriv->bufferCount = *out_count; + pPriv->width = pDraw->width; + pPriv->height = pDraw->height; + *width = pPriv->width; + *height = pPriv->height; +} + static DRI2BufferPtr * do_get_buffers(DrawablePtr pDraw, int *width, int *height, unsigned int *attachments, int count, int *out_count, @@ -344,7 +377,7 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, dimensions_match = (pDraw->width == pPriv->width) && (pDraw->height == pPriv->height); - buffers = xalloc((count + 1) * sizeof(buffers[0])); + buffers = malloc((count + 1) * sizeof(buffers[0])); for (i = 0; i < count; i++) { const unsigned attachment = *(attachments++); @@ -355,6 +388,9 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, &buffers[i])) buffers_changed = 1; + if (buffers[i] == NULL) + goto err_out; + /* If the drawable is a window and the front-buffer is requested, * silently add the fake front-buffer to the list of requested * attachments. The counting logic in the loop accounts for the case @@ -387,6 +423,9 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, front_format, dimensions_match, &buffers[i++])) buffers_changed = 1; + + if (buffers[i] == NULL) + goto err_out; } if (need_fake_front > 0) { @@ -395,29 +434,15 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, &buffers[i++])) buffers_changed = 1; + if (buffers[i] == NULL) + goto err_out; + have_fake_front = 1; } *out_count = i; - - if (pPriv->buffers != NULL) { - for (i = 0; i < pPriv->bufferCount; i++) { - if (pPriv->buffers[i] != NULL) { - (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); - } - } - - xfree(pPriv->buffers); - } - - pPriv->buffers = buffers; - pPriv->bufferCount = *out_count; - pPriv->width = pDraw->width; - pPriv->height = pDraw->height; - *width = pPriv->width; - *height = pPriv->height; - + update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height); /* If the client is getting a fake front-buffer, pre-fill it with the * contents of the real front-buffer. This ensures correct operation of @@ -438,6 +463,22 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, } return pPriv->buffers; + +err_out: + + *out_count = 0; + + for (i = 0; i < count; i++) { + if (buffers[i] != NULL) + (*ds->DestroyBuffer)(pDraw, buffers[i]); + } + + free(buffers); + buffers = NULL; + + update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height); + + return buffers; } DRI2BufferPtr * @@ -456,6 +497,19 @@ DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, out_count, TRUE); } +static void +DRI2InvalidateDrawable(DrawablePtr pDraw) +{ + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); + DRI2DrawableRefPtr ref; + + if (!pPriv) + return; + + list_for_each_entry(ref, &pPriv->reference_list, link) + ref->invalidate(pDraw, ref->priv); +} + /* * In the direct rendered case, we throttle the clients that have more * than their share of outstanding swaps (and thus busy buffers) when a @@ -634,6 +688,8 @@ DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, ScreenPtr pScreen = pDraw->pScreen; DRI2DrawablePtr pPriv; CARD64 ust = 0; + BoxRec box; + RegionRec region; pPriv = DRI2GetDrawable(pDraw); if (pPriv == NULL) { @@ -645,6 +701,14 @@ DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, pPriv->swapsPending--; pPriv->swap_count++; + box.x1 = 0; + box.y1 = 0; + box.x2 = pDraw->width; + box.y2 = pDraw->height; + REGION_INIT(pScreen, ®ion, &box, 0); + DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, + DRI2BufferFrontLeft); + ust = ((CARD64)tv_sec * 1000000) + tv_usec; if (swap_complete) swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); @@ -756,6 +820,8 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, */ *swap_target = pPriv->swap_count + pPriv->swapsPending; + DRI2InvalidateDrawable(pDraw); + return Success; } @@ -906,6 +972,30 @@ DRI2Authenticate(ScreenPtr pScreen, drm_magic_t magic) return TRUE; } +static void +DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw, + WindowPtr pSib) +{ + DrawablePtr pDraw = (DrawablePtr)pWin; + ScreenPtr pScreen = pDraw->pScreen; + DRI2ScreenPtr ds = DRI2GetScreen(pScreen); + DRI2DrawablePtr dd = DRI2GetDrawable(pDraw); + + if (ds->ConfigNotify) { + pScreen->ConfigNotify = ds->ConfigNotify; + + (*pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib); + + ds->ConfigNotify = pScreen->ConfigNotify; + pScreen->ConfigNotify = DRI2ConfigNotify; + } + + if (!dd || (dd->width == w && dd->height == h)) + return; + + DRI2InvalidateDrawable(pDraw); +} + Bool DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) { @@ -926,7 +1016,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) return FALSE; } - ds = xcalloc(1, sizeof *ds); + ds = calloc(1, sizeof *ds); if (!ds) return FALSE; @@ -943,7 +1033,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) ds->ScheduleSwap = info->ScheduleSwap; ds->ScheduleWaitMSC = info->ScheduleWaitMSC; ds->GetMSC = info->GetMSC; - cur_minor = 2; + cur_minor = 3; } else { cur_minor = 1; } @@ -955,17 +1045,17 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) if (info->version == 3 || info->numDrivers == 0) { /* Driver too old: use the old-style driverName field */ ds->numDrivers = 1; - ds->driverNames = xalloc(sizeof(*ds->driverNames)); + ds->driverNames = malloc(sizeof(*ds->driverNames)); if (!ds->driverNames) { - xfree(ds); + free(ds); return FALSE; } ds->driverNames[0] = info->driverName; } else { ds->numDrivers = info->numDrivers; - ds->driverNames = xalloc(info->numDrivers * sizeof(*ds->driverNames)); + ds->driverNames = malloc(info->numDrivers * sizeof(*ds->driverNames)); if (!ds->driverNames) { - xfree(ds); + free(ds); return FALSE; } memcpy(ds->driverNames, info->driverNames, @@ -974,6 +1064,9 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); + ds->ConfigNotify = pScreen->ConfigNotify; + pScreen->ConfigNotify = DRI2ConfigNotify; + xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n"); for (i = 0; i < sizeof(driverTypeNames) / sizeof(driverTypeNames[0]); i++) { if (i < ds->numDrivers && ds->driverNames[i]) { @@ -990,8 +1083,8 @@ DRI2CloseScreen(ScreenPtr pScreen) { DRI2ScreenPtr ds = DRI2GetScreen(pScreen); - xfree(ds->driverNames); - xfree(ds); + free(ds->driverNames); + free(ds); dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL); } diff --git a/xorg-server/hw/xfree86/dri2/dri2.h b/xorg-server/hw/xfree86/dri2/dri2.h index cc15f120d..c43aa6a04 100644 --- a/xorg-server/hw/xfree86/dri2/dri2.h +++ b/xorg-server/hw/xfree86/dri2/dri2.h @@ -152,6 +152,10 @@ typedef int (*DRI2ScheduleWaitMSCProcPtr)(ClientPtr client, CARD64 target_msc, CARD64 divisor, CARD64 remainder); + +typedef void (*DRI2InvalidateProcPtr)(DrawablePtr pDraw, + void *data); + /** * Version of the DRI2InfoRec structure defined in this header */ @@ -199,7 +203,10 @@ extern _X_EXPORT Bool DRI2Connect(ScreenPtr pScreen, extern _X_EXPORT Bool DRI2Authenticate(ScreenPtr pScreen, drm_magic_t magic); extern _X_EXPORT int DRI2CreateDrawable(ClientPtr client, - DrawablePtr pDraw, XID id); + DrawablePtr pDraw, + XID id, + DRI2InvalidateProcPtr invalidate, + void *priv); extern _X_EXPORT void DRI2DestroyDrawable(DrawablePtr pDraw); diff --git a/xorg-server/hw/xfree86/dri2/dri2ext.c b/xorg-server/hw/xfree86/dri2/dri2ext.c index 8bed02055..38efc86e0 100644 --- a/xorg-server/hw/xfree86/dri2/dri2ext.c +++ b/xorg-server/hw/xfree86/dri2/dri2ext.c @@ -91,7 +91,7 @@ ProcDRI2QueryVersion(ClientPtr client) WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep); - return client->noClientException; + return Success; } static int @@ -129,7 +129,7 @@ ProcDRI2Connect(ClientPtr client) WriteToClient(client, rep.driverNameLength, driverName); WriteToClient(client, rep.deviceNameLength, deviceName); - return client->noClientException; + return Success; } static int @@ -151,7 +151,23 @@ ProcDRI2Authenticate(ClientPtr client) rep.authenticated = DRI2Authenticate(pDraw->pScreen, stuff->magic); WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep); - return client->noClientException; + return Success; +} + +static void +DRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv) +{ + xDRI2InvalidateBuffers event; + ClientPtr client = priv; + + if (client->clientGone) + return; + + event.type = DRI2EventBase + DRI2_InvalidateBuffers; + event.sequenceNumber = client->sequence; + event.drawable = pDraw->id; + + WriteEventsToClient(client, 1, (xEvent *)&event); } static int @@ -167,11 +183,12 @@ ProcDRI2CreateDrawable(ClientPtr client) &pDrawable, &status)) return status; - status = DRI2CreateDrawable(client, pDrawable, stuff->drawable); + status = DRI2CreateDrawable(client, pDrawable, stuff->drawable, + DRI2InvalidateBuffersEvent, client); if (status != Success) return status; - return client->noClientException; + return Success; } static int @@ -186,11 +203,11 @@ ProcDRI2DestroyDrawable(ClientPtr client) &pDrawable, &status)) return status; - return client->noClientException; + return Success; } -static void +static int send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, DRI2BufferPtr *buffers, int count, int width, int height) { @@ -198,6 +215,9 @@ send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, int skip = 0; int i; + if (buffers == NULL) + return BadAlloc; + if (pDrawable->type == DRAWABLE_WINDOW) { for (i = 0; i < count; i++) { /* Do not send the real front buffer of a window to the client. @@ -234,6 +254,7 @@ send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, buffer.flags = buffers[i]->flags; WriteToClient(client, sizeof(xDRI2Buffer), &buffer); } + return Success; } @@ -252,16 +273,15 @@ ProcDRI2GetBuffers(ClientPtr client) return status; if (DRI2ThrottleClient(client, pDrawable)) - return client->noClientException; + return Success; attachments = (unsigned int *) &stuff[1]; buffers = DRI2GetBuffers(pDrawable, &width, &height, attachments, stuff->count, &count); - send_buffers_reply(client, pDrawable, buffers, count, width, height); + return send_buffers_reply(client, pDrawable, buffers, count, width, height); - return client->noClientException; } static int @@ -279,15 +299,13 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client) return status; if (DRI2ThrottleClient(client, pDrawable)) - return client->noClientException; + return Success; attachments = (unsigned int *) &stuff[1]; buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height, attachments, stuff->count, &count); - send_buffers_reply(client, pDrawable, buffers, count, width, height); - - return client->noClientException; + return send_buffers_reply(client, pDrawable, buffers, count, width, height); } static int @@ -324,7 +342,7 @@ ProcDRI2CopyRegion(ClientPtr client) WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep); - return client->noClientException; + return Success; } static void @@ -381,7 +399,7 @@ ProcDRI2SwapBuffers(ClientPtr client) * also orders swaps. */ if (DRI2ThrottleClient(client, pDrawable)) - return client->noClientException; + return Success; target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi); divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi); @@ -399,7 +417,7 @@ ProcDRI2SwapBuffers(ClientPtr client) WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep); - return client->noClientException; + return Success; } static void @@ -439,7 +457,7 @@ ProcDRI2GetMSC(ClientPtr client) WriteToClient(client, sizeof(xDRI2MSCReply), &rep); - return client->noClientException; + return Success; } static int @@ -466,7 +484,7 @@ ProcDRI2WaitMSC(ClientPtr client) if (status != Success) return status; - return client->noClientException; + return Success; } int @@ -481,7 +499,7 @@ ProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, CARD64 msc, CARD64 sbc) WriteToClient(client, sizeof(xDRI2MSCReply), &rep); - return client->noClientException; + return Success; } static int @@ -501,7 +519,7 @@ ProcDRI2SwapInterval(ClientPtr client) DRI2SwapInterval(pDrawable, stuff->interval); - return client->noClientException; + return Success; } static int @@ -531,7 +549,7 @@ ProcDRI2WaitSBC(ClientPtr client) WriteToClient(client, sizeof(xDRI2MSCReply), &rep); - return client->noClientException; + return Success; } static int @@ -596,7 +614,7 @@ SProcDRI2Connect(ClientPtr client) rep.driverNameLength = 0; rep.deviceNameLength = 0; - return client->noClientException; + return Success; } static int diff --git a/xorg-server/hw/xfree86/exa/examodule.c b/xorg-server/hw/xfree86/exa/examodule.c index bcb6a405c..6238582c0 100644 --- a/xorg-server/hw/xfree86/exa/examodule.c +++ b/xorg-server/hw/xfree86/exa/examodule.c @@ -1,198 +1,198 @@ -/* - * Copyright © 2006 Intel Corporation - * - * 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. - * - * Authors: - * Eric Anholt <anholt@FreeBSD.org> - * - */ - -#ifdef HAVE_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "exa_priv.h" - -#include "xf86str.h" -#include "xf86.h" - -typedef struct _ExaXorgScreenPrivRec { - CloseScreenProcPtr SavedCloseScreen; - EnableDisableFBAccessProcPtr SavedEnableDisableFBAccess; - OptionInfoPtr options; -} ExaXorgScreenPrivRec, *ExaXorgScreenPrivPtr; - -static int exaXorgScreenPrivateKeyIndex; -static DevPrivateKey exaXorgScreenPrivateKey = &exaXorgScreenPrivateKeyIndex; - -typedef enum { - EXAOPT_MIGRATION_HEURISTIC, - EXAOPT_NO_COMPOSITE, - EXAOPT_NO_UTS, - EXAOPT_NO_DFS, - EXAOPT_OPTIMIZE_MIGRATION -} EXAOpts; - -static const OptionInfoRec EXAOptions[] = { - { EXAOPT_MIGRATION_HEURISTIC, "MigrationHeuristic", - OPTV_ANYSTR, {0}, FALSE }, - { EXAOPT_NO_COMPOSITE, "EXANoComposite", - OPTV_BOOLEAN, {0}, FALSE }, - { EXAOPT_NO_UTS, "EXANoUploadToScreen", - OPTV_BOOLEAN, {0}, FALSE }, - { EXAOPT_NO_DFS, "EXANoDownloadFromScreen", - OPTV_BOOLEAN, {0}, FALSE }, - { EXAOPT_OPTIMIZE_MIGRATION, "EXAOptimizeMigration", - OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, - OPTV_NONE, {0}, FALSE } -}; - -static Bool -exaXorgCloseScreen (int i, ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); - ExaXorgScreenPrivPtr pScreenPriv = (ExaXorgScreenPrivPtr) - dixLookupPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey); - - pScreen->CloseScreen = pScreenPriv->SavedCloseScreen; - - pScrn->EnableDisableFBAccess = pScreenPriv->SavedEnableDisableFBAccess; - - xfree (pScreenPriv->options); - xfree (pScreenPriv); - - return pScreen->CloseScreen (i, pScreen); -} - -static void -exaXorgEnableDisableFBAccess (int index, Bool enable) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - ExaXorgScreenPrivPtr pScreenPriv = (ExaXorgScreenPrivPtr) - dixLookupPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey); - - if (!enable) - exaEnableDisableFBAccess (index, enable); - - if (pScreenPriv->SavedEnableDisableFBAccess) - pScreenPriv->SavedEnableDisableFBAccess (index, enable); - - if (enable) - exaEnableDisableFBAccess (index, enable); -} - -/** - * This will be called during exaDriverInit, giving us the chance to set options - * and hook in our EnableDisableFBAccess. - */ -void -exaDDXDriverInit(ScreenPtr pScreen) -{ - ExaScreenPriv(pScreen); - /* Do NOT use XF86SCRNINFO macro here!! */ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - ExaXorgScreenPrivPtr pScreenPriv; - - pScreenPriv = xcalloc (1, sizeof(ExaXorgScreenPrivRec)); - if (pScreenPriv == NULL) - return; - - pScreenPriv->options = xnfalloc (sizeof(EXAOptions)); - memcpy(pScreenPriv->options, EXAOptions, sizeof(EXAOptions)); - xf86ProcessOptions (pScrn->scrnIndex, pScrn->options, pScreenPriv->options); - - if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) { - if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && - pExaScr->info->offScreenBase < pExaScr->info->memorySize) { - char *heuristicName; - - heuristicName = xf86GetOptValString (pScreenPriv->options, - EXAOPT_MIGRATION_HEURISTIC); - if (heuristicName != NULL) { - if (strcmp(heuristicName, "greedy") == 0) - pExaScr->migration = ExaMigrationGreedy; - else if (strcmp(heuristicName, "always") == 0) - pExaScr->migration = ExaMigrationAlways; - else if (strcmp(heuristicName, "smart") == 0) - pExaScr->migration = ExaMigrationSmart; - else { - xf86DrvMsg (pScreen->myNum, X_WARNING, - "EXA: unknown migration heuristic %s\n", - heuristicName); - } - } - } - - pExaScr->optimize_migration = - xf86ReturnOptValBool(pScreenPriv->options, - EXAOPT_OPTIMIZE_MIGRATION, - TRUE); - } - - if (xf86ReturnOptValBool(pScreenPriv->options, - EXAOPT_NO_COMPOSITE, FALSE)) { - xf86DrvMsg(pScreen->myNum, X_CONFIG, - "EXA: Disabling Composite operation " - "(RENDER acceleration)\n"); - pExaScr->info->CheckComposite = NULL; - pExaScr->info->PrepareComposite = NULL; - } - - if (xf86ReturnOptValBool(pScreenPriv->options, EXAOPT_NO_UTS, FALSE)) { - xf86DrvMsg(pScreen->myNum, X_CONFIG, - "EXA: Disabling UploadToScreen\n"); - pExaScr->info->UploadToScreen = NULL; - } - - if (xf86ReturnOptValBool(pScreenPriv->options, EXAOPT_NO_DFS, FALSE)) { - xf86DrvMsg(pScreen->myNum, X_CONFIG, - "EXA: Disabling DownloadFromScreen\n"); - pExaScr->info->DownloadFromScreen = NULL; - } - - dixSetPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey, pScreenPriv); - - pScreenPriv->SavedEnableDisableFBAccess = pScrn->EnableDisableFBAccess; - pScrn->EnableDisableFBAccess = exaXorgEnableDisableFBAccess; - - pScreenPriv->SavedCloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = exaXorgCloseScreen; - -} - -static XF86ModuleVersionInfo exaVersRec = -{ - "exa", - MODULEVENDORSTRING, - MODINFOSTRING1, - MODINFOSTRING2, - XORG_VERSION_CURRENT, - EXA_VERSION_MAJOR, EXA_VERSION_MINOR, EXA_VERSION_RELEASE, - ABI_CLASS_VIDEODRV, /* requires the video driver ABI */ - ABI_VIDEODRV_VERSION, - MOD_CLASS_NONE, - {0,0,0,0} -}; - -_X_EXPORT XF86ModuleData exaModuleData = { &exaVersRec, NULL, NULL }; +/* + * Copyright © 2006 Intel Corporation + * + * 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. + * + * Authors: + * Eric Anholt <anholt@FreeBSD.org> + * + */ + +#ifdef HAVE_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" + +#include "xf86str.h" +#include "xf86.h" + +typedef struct _ExaXorgScreenPrivRec { + CloseScreenProcPtr SavedCloseScreen; + EnableDisableFBAccessProcPtr SavedEnableDisableFBAccess; + OptionInfoPtr options; +} ExaXorgScreenPrivRec, *ExaXorgScreenPrivPtr; + +static int exaXorgScreenPrivateKeyIndex; +static DevPrivateKey exaXorgScreenPrivateKey = &exaXorgScreenPrivateKeyIndex; + +typedef enum { + EXAOPT_MIGRATION_HEURISTIC, + EXAOPT_NO_COMPOSITE, + EXAOPT_NO_UTS, + EXAOPT_NO_DFS, + EXAOPT_OPTIMIZE_MIGRATION +} EXAOpts; + +static const OptionInfoRec EXAOptions[] = { + { EXAOPT_MIGRATION_HEURISTIC, "MigrationHeuristic", + OPTV_ANYSTR, {0}, FALSE }, + { EXAOPT_NO_COMPOSITE, "EXANoComposite", + OPTV_BOOLEAN, {0}, FALSE }, + { EXAOPT_NO_UTS, "EXANoUploadToScreen", + OPTV_BOOLEAN, {0}, FALSE }, + { EXAOPT_NO_DFS, "EXANoDownloadFromScreen", + OPTV_BOOLEAN, {0}, FALSE }, + { EXAOPT_OPTIMIZE_MIGRATION, "EXAOptimizeMigration", + OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, + OPTV_NONE, {0}, FALSE } +}; + +static Bool +exaXorgCloseScreen (int i, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); + ExaXorgScreenPrivPtr pScreenPriv = (ExaXorgScreenPrivPtr) + dixLookupPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey); + + pScreen->CloseScreen = pScreenPriv->SavedCloseScreen; + + pScrn->EnableDisableFBAccess = pScreenPriv->SavedEnableDisableFBAccess; + + free(pScreenPriv->options); + free(pScreenPriv); + + return pScreen->CloseScreen (i, pScreen); +} + +static void +exaXorgEnableDisableFBAccess (int index, Bool enable) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + ExaXorgScreenPrivPtr pScreenPriv = (ExaXorgScreenPrivPtr) + dixLookupPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey); + + if (!enable) + exaEnableDisableFBAccess (index, enable); + + if (pScreenPriv->SavedEnableDisableFBAccess) + pScreenPriv->SavedEnableDisableFBAccess (index, enable); + + if (enable) + exaEnableDisableFBAccess (index, enable); +} + +/** + * This will be called during exaDriverInit, giving us the chance to set options + * and hook in our EnableDisableFBAccess. + */ +void +exaDDXDriverInit(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + /* Do NOT use XF86SCRNINFO macro here!! */ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + ExaXorgScreenPrivPtr pScreenPriv; + + pScreenPriv = calloc(1, sizeof(ExaXorgScreenPrivRec)); + if (pScreenPriv == NULL) + return; + + pScreenPriv->options = xnfalloc (sizeof(EXAOptions)); + memcpy(pScreenPriv->options, EXAOptions, sizeof(EXAOptions)); + xf86ProcessOptions (pScrn->scrnIndex, pScrn->options, pScreenPriv->options); + + if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) { + if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && + pExaScr->info->offScreenBase < pExaScr->info->memorySize) { + char *heuristicName; + + heuristicName = xf86GetOptValString (pScreenPriv->options, + EXAOPT_MIGRATION_HEURISTIC); + if (heuristicName != NULL) { + if (strcmp(heuristicName, "greedy") == 0) + pExaScr->migration = ExaMigrationGreedy; + else if (strcmp(heuristicName, "always") == 0) + pExaScr->migration = ExaMigrationAlways; + else if (strcmp(heuristicName, "smart") == 0) + pExaScr->migration = ExaMigrationSmart; + else { + xf86DrvMsg (pScreen->myNum, X_WARNING, + "EXA: unknown migration heuristic %s\n", + heuristicName); + } + } + } + + pExaScr->optimize_migration = + xf86ReturnOptValBool(pScreenPriv->options, + EXAOPT_OPTIMIZE_MIGRATION, + TRUE); + } + + if (xf86ReturnOptValBool(pScreenPriv->options, + EXAOPT_NO_COMPOSITE, FALSE)) { + xf86DrvMsg(pScreen->myNum, X_CONFIG, + "EXA: Disabling Composite operation " + "(RENDER acceleration)\n"); + pExaScr->info->CheckComposite = NULL; + pExaScr->info->PrepareComposite = NULL; + } + + if (xf86ReturnOptValBool(pScreenPriv->options, EXAOPT_NO_UTS, FALSE)) { + xf86DrvMsg(pScreen->myNum, X_CONFIG, + "EXA: Disabling UploadToScreen\n"); + pExaScr->info->UploadToScreen = NULL; + } + + if (xf86ReturnOptValBool(pScreenPriv->options, EXAOPT_NO_DFS, FALSE)) { + xf86DrvMsg(pScreen->myNum, X_CONFIG, + "EXA: Disabling DownloadFromScreen\n"); + pExaScr->info->DownloadFromScreen = NULL; + } + + dixSetPrivate(&pScreen->devPrivates, exaXorgScreenPrivateKey, pScreenPriv); + + pScreenPriv->SavedEnableDisableFBAccess = pScrn->EnableDisableFBAccess; + pScrn->EnableDisableFBAccess = exaXorgEnableDisableFBAccess; + + pScreenPriv->SavedCloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = exaXorgCloseScreen; + +} + +static XF86ModuleVersionInfo exaVersRec = +{ + "exa", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + EXA_VERSION_MAJOR, EXA_VERSION_MINOR, EXA_VERSION_RELEASE, + ABI_CLASS_VIDEODRV, /* requires the video driver ABI */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + {0,0,0,0} +}; + +_X_EXPORT XF86ModuleData exaModuleData = { &exaVersRec, NULL, NULL }; diff --git a/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c b/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c index 880f0a20e..3f7391d50 100644 --- a/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c +++ b/xorg-server/hw/xfree86/fbdevhw/fbdevhw.c @@ -1,1009 +1,1009 @@ -/* all driver need this */ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "xf86.h" -#include "xf86_OSproc.h" - -/* pci stuff */ -#include "xf86PciInfo.h" -#include "xf86Pci.h" - -#include "xf86cmap.h" - -#include "fbdevhw.h" -#include "fbpriv.h" - -#define PAGE_MASK (~(getpagesize() - 1)) - -#include "globals.h" -#include <X11/extensions/dpmsconst.h> - -#define DEBUG 0 - -#define PAGE_MASK (~(getpagesize() - 1)) - -#if DEBUG -# define TRACE_ENTER(str) ErrorF("fbdevHW: " str " %d\n",pScrn->scrnIndex) -#else -# define TRACE_ENTER(str) -#endif - -/* -------------------------------------------------------------------- */ - -static MODULESETUPPROTO(fbdevhwSetup); - -static XF86ModuleVersionInfo fbdevHWVersRec = -{ - "fbdevhw", - MODULEVENDORSTRING, - MODINFOSTRING1, - MODINFOSTRING2, - XORG_VERSION_CURRENT, - 0, 0, 2, - ABI_CLASS_VIDEODRV, - ABI_VIDEODRV_VERSION, - MOD_CLASS_NONE, - {0,0,0,0} -}; - -_X_EXPORT XF86ModuleData fbdevhwModuleData = { - &fbdevHWVersRec, - fbdevhwSetup, - NULL -}; - -static pointer -fbdevhwSetup(pointer module, pointer opts, int *errmaj, int *errmin) -{ - return (pointer)1; -} - -#include <fcntl.h> -#include <errno.h> -#include <sys/mman.h> -#include <sys/ioctl.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> - -/* -------------------------------------------------------------------- */ -/* our private data, and two functions to allocate/free this */ - -#define FBDEVHWPTRLVAL(p) (p)->privates[fbdevHWPrivateIndex].ptr -#define FBDEVHWPTR(p) ((fbdevHWPtr)(FBDEVHWPTRLVAL(p))) - -static int fbdevHWPrivateIndex = -1; - -typedef struct { - /* framebuffer device: filename (/dev/fb*), handle, more */ - char* device; - int fd; - void* fbmem; - unsigned int fbmem_len; - unsigned int fboff; - char* mmio; - unsigned int mmio_len; - - /* current hardware state */ - struct fb_fix_screeninfo fix; - struct fb_var_screeninfo var; - - /* saved video mode */ - struct fb_var_screeninfo saved_var; - - /* FIXME: unused??? [geert] */ - struct fb_cmap saved_cmap; - unsigned short *saved_red; - unsigned short *saved_green; - unsigned short *saved_blue; - - /* buildin video mode */ - DisplayModeRec buildin; - -} fbdevHWRec, *fbdevHWPtr; - -Bool -fbdevHWGetRec(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr; - - if (fbdevHWPrivateIndex < 0) - fbdevHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); - - if (FBDEVHWPTR(pScrn) != NULL) - return TRUE; - - fPtr = FBDEVHWPTRLVAL(pScrn) = xnfcalloc(sizeof(fbdevHWRec), 1); - return TRUE; -} - -void -fbdevHWFreeRec(ScrnInfoPtr pScrn) -{ - if (fbdevHWPrivateIndex < 0) - return; - if (FBDEVHWPTR(pScrn) == NULL) - return; - xfree(FBDEVHWPTR(pScrn)); - FBDEVHWPTRLVAL(pScrn) = NULL; -} - -int -fbdevHWGetFD(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr; - - fbdevHWGetRec(pScrn); - fPtr = FBDEVHWPTR(pScrn); - - return fPtr->fd; -} - -/* -------------------------------------------------------------------- */ -/* some helpers for printing debug informations */ - -#if DEBUG -static void -print_fbdev_mode(char *txt, struct fb_var_screeninfo *var) -{ - ErrorF( "fbdev %s mode:\t%d %d %d %d %d %d %d %d %d %d %d:%d:%d\n", - txt,var->pixclock, - var->xres, var->right_margin, var->hsync_len, var->left_margin, - var->yres, var->lower_margin, var->vsync_len, var->upper_margin, - var->bits_per_pixel, - var->red.length, var->green.length, var->blue.length); -} - -static void -print_xfree_mode(char *txt, DisplayModePtr mode) -{ - ErrorF( "xfree %s mode:\t%d %d %d %d %d %d %d %d %d\n", - txt,mode->Clock, - mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal, - mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal); -} -#endif - -/* -------------------------------------------------------------------- */ -/* Convert timings between the XFree and the Frame Buffer Device */ - -static void -xfree2fbdev_fblayout(ScrnInfoPtr pScrn, struct fb_var_screeninfo *var) -{ - var->xres_virtual = pScrn->displayWidth ? pScrn->displayWidth : - pScrn->virtualX; - var->yres_virtual = pScrn->virtualY; - var->bits_per_pixel = pScrn->bitsPerPixel; - if (pScrn->defaultVisual == TrueColor || - pScrn->defaultVisual == DirectColor) { - var->red.length = pScrn->weight.red; - var->green.length = pScrn->weight.green; - var->blue.length = pScrn->weight.blue; - } else { - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - } -} - -static void -xfree2fbdev_timing(DisplayModePtr mode, struct fb_var_screeninfo *var) -{ - var->xres = mode->HDisplay; - var->yres = mode->VDisplay; - if (var->xres_virtual < var->xres) - var->xres_virtual = var->xres; - if (var->yres_virtual < var->yres) - var->yres_virtual = var->yres; - var->xoffset = var->yoffset = 0; - var->pixclock = mode->Clock ? 1000000000/mode->Clock : 0; - var->right_margin = mode->HSyncStart-mode->HDisplay; - var->hsync_len = mode->HSyncEnd-mode->HSyncStart; - var->left_margin = mode->HTotal-mode->HSyncEnd; - var->lower_margin = mode->VSyncStart-mode->VDisplay; - var->vsync_len = mode->VSyncEnd-mode->VSyncStart; - var->upper_margin = mode->VTotal-mode->VSyncEnd; - var->sync = 0; - if (mode->Flags & V_PHSYNC) - var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (mode->Flags & V_PVSYNC) - var->sync |= FB_SYNC_VERT_HIGH_ACT; - if (mode->Flags & V_PCSYNC) - var->sync |= FB_SYNC_COMP_HIGH_ACT; - if (mode->Flags & V_BCAST) - var->sync |= FB_SYNC_BROADCAST; - if (mode->Flags & V_INTERLACE) - var->vmode = FB_VMODE_INTERLACED; - else if (mode->Flags & V_DBLSCAN) - var->vmode = FB_VMODE_DOUBLE; - else - var->vmode = FB_VMODE_NONINTERLACED; -} - -static Bool -fbdev_modes_equal(struct fb_var_screeninfo *set, struct fb_var_screeninfo *req) -{ - return (set->xres_virtual >= req->xres_virtual && - set->yres_virtual >= req->yres_virtual && - set->bits_per_pixel == req->bits_per_pixel && - set->red.length == req->red.length && - set->green.length == req->green.length && - set->blue.length == req->blue.length && - set->xres == req->xres && set->yres == req->yres && - set->right_margin == req->right_margin && - set->hsync_len == req->hsync_len && - set->left_margin == req->left_margin && - set->lower_margin == req->lower_margin && - set->vsync_len == req->vsync_len && - set->upper_margin == req->upper_margin && - set->sync == req->sync && set->vmode == req->vmode); -} - -static void -fbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode) -{ - mode->Clock = var->pixclock ? 1000000000/var->pixclock : 0; - mode->HDisplay = var->xres; - mode->HSyncStart = mode->HDisplay+var->right_margin; - mode->HSyncEnd = mode->HSyncStart+var->hsync_len; - mode->HTotal = mode->HSyncEnd+var->left_margin; - mode->VDisplay = var->yres; - mode->VSyncStart = mode->VDisplay+var->lower_margin; - mode->VSyncEnd = mode->VSyncStart+var->vsync_len; - mode->VTotal = mode->VSyncEnd+var->upper_margin; - mode->Flags = 0; - mode->Flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; - mode->Flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; - mode->Flags |= var->sync & FB_SYNC_COMP_HIGH_ACT ? V_PCSYNC : V_NCSYNC; - if (var->sync & FB_SYNC_BROADCAST) - mode->Flags |= V_BCAST; - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) - mode->Flags |= V_INTERLACE; - else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) - mode->Flags |= V_DBLSCAN; - mode->SynthClock = mode->Clock; - mode->CrtcHDisplay = mode->HDisplay; - mode->CrtcHSyncStart = mode->HSyncStart; - mode->CrtcHSyncEnd = mode->HSyncEnd; - mode->CrtcHTotal = mode->HTotal; - mode->CrtcVDisplay = mode->VDisplay; - mode->CrtcVSyncStart = mode->VSyncStart; - mode->CrtcVSyncEnd = mode->VSyncEnd; - mode->CrtcVTotal = mode->VTotal; - mode->CrtcHAdjusted = FALSE; - mode->CrtcVAdjusted = FALSE; -} - - -/* -------------------------------------------------------------------- */ -/* open correct framebuffer device */ - -/** - * Try to find the framebuffer device for a given PCI device - */ -static int -fbdev_open_pci(struct pci_device * pPci, char **namep) -{ - struct fb_fix_screeninfo fix; - char filename[256]; - int fd,i,j; - - - /* There are two ways to that we can determine which fb device is - * associated with this PCI device. The more modern way is to look in - * the sysfs directory for the PCI device for a file named - * "graphics/fb*" - */ - - for (i = 0; i < 8; i++) { - sprintf(filename, - "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics/fb%d", - pPci->domain, pPci->bus, pPci->dev, pPci->func, i); - - fd = open(filename, O_RDONLY, 0); - if (fd < 0) { - sprintf(filename, - "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics:fb%d", - pPci->domain, pPci->bus, pPci->dev, pPci->func, i); - fd = open(filename, O_RDONLY, 0); - } - if (fd >= 0) { - close(fd); - sprintf(filename, "/dev/fb%d", i); - - fd = open(filename, O_RDWR, 0); - if (fd != -1) { - if (ioctl(fd, FBIOGET_FSCREENINFO, (void*) & fix) != -1) { - if (namep) { - *namep = xnfalloc(16); - strncpy(*namep,fix.id,16); - } - - return fd; - } - close(fd); - } - } - } - - - /* The other way is to examine the resources associated with each fb - * device and see if there is a match with the PCI device. This technique - * has some problems on certain mixed 64-bit / 32-bit architectures. - * There is a flaw in the fb_fix_screeninfo structure in that it only - * returns the low 32-bits of the address of the resources associated with - * a device. However, on a mixed architecture the base addresses of PCI - * devices, even for 32-bit applications, may be higher than 0x0f0000000. - */ - - for (i = 0; i < 8; i++) { - sprintf(filename,"/dev/fb%d",i); - if (-1 == (fd = open(filename,O_RDWR,0))) { - xf86DrvMsg(-1, X_WARNING, - "open %s: %s\n", filename, strerror(errno)); - continue; - } - if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)&fix)) { - close(fd); - continue; - } - for (j = 0; j < 6; j++) { - const pciaddr_t res_start = pPci->regions[j].base_addr; - const pciaddr_t res_end = res_start + pPci->regions[j].size; - - if ((0 != fix.smem_len && - (pciaddr_t) fix.smem_start >= res_start && - (pciaddr_t) fix.smem_start < res_end) || - (0 != fix.mmio_len && - (pciaddr_t) fix.mmio_start >= res_start && - (pciaddr_t) fix.mmio_start < res_end)) - break; - } - if (j == 6) { - close(fd); - continue; - } - if (namep) { - *namep = xnfalloc(16); - strncpy(*namep,fix.id,16); - } - return fd; - } - - if (namep) - *namep = NULL; - - xf86DrvMsg(-1, X_ERROR, - "Unable to find a valid framebuffer device\n"); - return -1; -} - -static int -fbdev_open(int scrnIndex, char *dev, char** namep) -{ - struct fb_fix_screeninfo fix; - int fd; - - /* try argument (from XF86Config) first */ - if (dev) { - fd = open(dev,O_RDWR,0); - } else { - /* second: environment variable */ - dev = getenv("FRAMEBUFFER"); - if ((NULL == dev) || ((fd = open(dev,O_RDWR,0)) == -1)) { - /* last try: default device */ - dev = "/dev/fb0"; - fd = open(dev,O_RDWR,0); - } - } - - if (fd == -1) { - xf86DrvMsg(scrnIndex, X_ERROR, - "open %s: %s\n", dev, strerror(errno)); - return -1; - } - - if (namep) { - if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)(&fix))) { - *namep = NULL; - xf86DrvMsg(scrnIndex, X_ERROR, - "FBIOGET_FSCREENINFO: %s\n", strerror(errno)); - return -1; - } else { - *namep = xnfalloc(16); - strncpy(*namep,fix.id,16); - } - } - return fd; -} - -/* -------------------------------------------------------------------- */ - -Bool -fbdevHWProbe(struct pci_device * pPci, char *device,char **namep) -{ - int fd; - - if (pPci) - fd = fbdev_open_pci(pPci,namep); - else - fd = fbdev_open(-1,device,namep); - - if (-1 == fd) - return FALSE; - close(fd); - return TRUE; -} - -Bool -fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device * pPci, char *device) -{ - fbdevHWPtr fPtr; - - TRACE_ENTER("Init"); - - fbdevHWGetRec(pScrn); - fPtr = FBDEVHWPTR(pScrn); - - /* open device */ - if (pPci) - fPtr->fd = fbdev_open_pci(pPci,NULL); - else - fPtr->fd = fbdev_open(pScrn->scrnIndex,device,NULL); - if (-1 == fPtr->fd) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to open framebuffer device, consult warnings" - " and/or errors above for possible reasons\n" - "\t(you may have to look at the server log to see" - " warnings)\n"); - return FALSE; - } - - /* get current fb device settings */ - if (-1 == ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "ioctl FBIOGET_FSCREENINFO: %s\n", - strerror(errno)); - return FALSE; - } - if (-1 == ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "ioctl FBIOGET_VSCREENINFO: %s\n", - strerror(errno)); - return FALSE; - } - - /* we can use the current settings as "buildin mode" */ - fbdev2xfree_timing(&fPtr->var, &fPtr->buildin); - fPtr->buildin.name = "current"; - fPtr->buildin.next = &fPtr->buildin; - fPtr->buildin.prev = &fPtr->buildin; - fPtr->buildin.type |= M_T_BUILTIN; - - return TRUE; -} - -char* -fbdevHWGetName(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - return fPtr->fix.id; -} - -int -fbdevHWGetDepth(ScrnInfoPtr pScrn, int *fbbpp) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - if (fbbpp) - *fbbpp = fPtr->var.bits_per_pixel; - - if (fPtr->fix.visual == FB_VISUAL_TRUECOLOR || - fPtr->fix.visual == FB_VISUAL_DIRECTCOLOR) - return fPtr->var.red.length+fPtr->var.green.length+ - fPtr->var.blue.length; - else - return fPtr->var.bits_per_pixel; -} - -int -fbdevHWGetLineLength(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - if (fPtr->fix.line_length) - return fPtr->fix.line_length; - else - return fPtr->var.xres_virtual*fPtr->var.bits_per_pixel/8; -} - -int -fbdevHWGetType(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - return fPtr->fix.type; -} - -int -fbdevHWGetVidmem(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - return fPtr->fix.smem_len; -} - -static Bool -fbdevHWSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool check) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - struct fb_var_screeninfo req_var = fPtr->var, set_var; - - TRACE_ENTER("SetMode"); - - xfree2fbdev_fblayout(pScrn, &req_var); - xfree2fbdev_timing(mode, &req_var); - -#if DEBUG - print_xfree_mode("init", mode); - print_fbdev_mode("init", &req_var); -#endif - - set_var = req_var; - - if (check) - set_var.activate = FB_ACTIVATE_TEST; - - if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void*)(&set_var))) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); - return FALSE; - } - - if (!fbdev_modes_equal(&set_var, &req_var)) { - if (!check) - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOPUT_VSCREENINFO succeeded but modified " - "mode\n"); -#if DEBUG - print_fbdev_mode("returned", &set_var); -#endif - return FALSE; - } - - if (!check) - fPtr->var = set_var; - - return TRUE; -} - -void -fbdevHWSetVideoModes(ScrnInfoPtr pScrn) -{ - char **modename; - DisplayModePtr mode,this,last = pScrn->modes; - - TRACE_ENTER("VerifyModes"); - if (NULL == pScrn->display->modes) - return; - - pScrn->virtualX = pScrn->display->virtualX; - pScrn->virtualY = pScrn->display->virtualY; - - for (modename = pScrn->display->modes; *modename != NULL; modename++) { - for (mode = pScrn->monitor->Modes; mode != NULL; mode = mode->next) - if (0 == strcmp(mode->name,*modename)) - break; - if (NULL == mode) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "\tmode \"%s\" not found\n", *modename); - continue; - } - - if (!fbdevHWSetMode(pScrn, mode, TRUE)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "\tmode \"%s\" test failed\n", *modename); - continue; - } - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "\tmode \"%s\" ok\n", *modename); - - if (pScrn->virtualX < mode->HDisplay) - pScrn->virtualX = mode->HDisplay; - if (pScrn->virtualY < mode->VDisplay) - pScrn->virtualY = mode->VDisplay; - - if (NULL == pScrn->modes) { - this = pScrn->modes = xf86DuplicateMode(mode); - this->next = this; - this->prev = this; - } else { - this = xf86DuplicateMode(mode); - this->next = pScrn->modes; - this->prev = last; - last->next = this; - pScrn->modes->prev = this; - } - last = this; - } -} - -DisplayModePtr -fbdevHWGetBuildinMode(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - return &fPtr->buildin; -} - -void -fbdevHWUseBuildinMode(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - TRACE_ENTER("UseBuildinMode"); - pScrn->modes = &fPtr->buildin; - pScrn->virtualX = pScrn->display->virtualX; - pScrn->virtualY = pScrn->display->virtualY; - if (pScrn->virtualX < fPtr->buildin.HDisplay) - pScrn->virtualX = fPtr->buildin.HDisplay; - if (pScrn->virtualY < fPtr->buildin.VDisplay) - pScrn->virtualY = fPtr->buildin.VDisplay; -} - -/* -------------------------------------------------------------------- */ - -static void -calculateFbmem_len(fbdevHWPtr fPtr) -{ - fPtr->fboff = (unsigned long) fPtr->fix.smem_start & ~PAGE_MASK; - fPtr->fbmem_len = (fPtr->fboff+fPtr->fix.smem_len+~PAGE_MASK) & - PAGE_MASK; -} - - -void* -fbdevHWMapVidmem(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - TRACE_ENTER("MapVidmem"); - if (NULL == fPtr->fbmem) { - calculateFbmem_len(fPtr); - fPtr->fbmem = mmap(NULL, fPtr->fbmem_len, PROT_READ | PROT_WRITE, - MAP_SHARED, fPtr->fd, 0); - if (-1 == (long)fPtr->fbmem) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "mmap fbmem: %s\n", strerror(errno)); - fPtr->fbmem = NULL; - } else { - /* Perhaps we'd better add fboff to fbmem and return 0 in - fbdevHWLinearOffset()? Of course we then need to mask - fPtr->fbmem with PAGE_MASK in fbdevHWUnmapVidmem() as - well. [geert] */ - } - } - pScrn->memPhysBase = (unsigned long)fPtr->fix.smem_start & (unsigned long)(PAGE_MASK); - pScrn->fbOffset = (unsigned long)fPtr->fix.smem_start & (unsigned long)(~PAGE_MASK); - return fPtr->fbmem; -} - -int -fbdevHWLinearOffset(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - TRACE_ENTER("LinearOffset"); - return fPtr->fboff; -} - -Bool -fbdevHWUnmapVidmem(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - TRACE_ENTER("UnmapVidmem"); - if (NULL != fPtr->fbmem) { - if (-1 == munmap(fPtr->fbmem, fPtr->fbmem_len)) - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "munmap fbmem: %s\n", strerror(errno)); - fPtr->fbmem = NULL; - } - return TRUE; -} - -void* -fbdevHWMapMMIO(ScrnInfoPtr pScrn) -{ - unsigned int mmio_off; - - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - TRACE_ENTER("MapMMIO"); - if (NULL == fPtr->mmio) { - /* tell the kernel not to use accels to speed up console scrolling */ - fPtr->var.accel_flags = 0; - if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->var))) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); - return FALSE; - } - mmio_off = (unsigned long) fPtr->fix.mmio_start & ~PAGE_MASK; - fPtr->mmio_len = (mmio_off+fPtr->fix.mmio_len+~PAGE_MASK) & - PAGE_MASK; - if (NULL == fPtr->fbmem) - calculateFbmem_len(fPtr); - fPtr->mmio = mmap(NULL, fPtr->mmio_len, PROT_READ | PROT_WRITE, - MAP_SHARED, fPtr->fd, fPtr->fbmem_len); - if (-1 == (long)fPtr->mmio) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "mmap mmio: %s\n", strerror(errno)); - fPtr->mmio = NULL; - } else - fPtr->mmio += mmio_off; - } - return fPtr->mmio; -} - -Bool -fbdevHWUnmapMMIO(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - TRACE_ENTER("UnmapMMIO"); - if (NULL != fPtr->mmio) { - if (-1 == munmap((void *)((unsigned long)fPtr->mmio & PAGE_MASK), fPtr->mmio_len)) - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "munmap mmio: %s\n", strerror(errno)); - fPtr->mmio = NULL; - /* FIXME: restore var.accel_flags [geert] */ - } - return TRUE; -} - -/* -------------------------------------------------------------------- */ - -Bool -fbdevHWModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - pScrn->vtSema = TRUE; - - /* set */ - if (!fbdevHWSetMode(pScrn, mode, FALSE)) - return FALSE; - - /* read back */ - if (0 != ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOGET_FSCREENINFO: %s\n", strerror(errno)); - return FALSE; - } - if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOGET_VSCREENINFO: %s\n", strerror(errno)); - return FALSE; - } - - if (pScrn->defaultVisual == TrueColor || - pScrn->defaultVisual == DirectColor) { - /* XXX: This is a hack, but it should be a NOP for all the setups that - * worked before and actually seems to fix some others... - */ - pScrn->offset.red = fPtr->var.red.offset; - pScrn->offset.green = fPtr->var.green.offset; - pScrn->offset.blue = fPtr->var.blue.offset; - pScrn->mask.red = ((1 << fPtr->var.red.length) - 1) << fPtr->var.red.offset; - pScrn->mask.green = ((1 << fPtr->var.green.length) - 1) << fPtr->var.green.offset; - pScrn->mask.blue = ((1 << fPtr->var.blue.length) - 1) << fPtr->var.blue.offset; - } - - return TRUE; -} - -/* -------------------------------------------------------------------- */ -/* video mode save/restore */ - -/* TODO: colormap */ -void -fbdevHWSave(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - TRACE_ENTER("Save"); - if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->saved_var))) - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOGET_VSCREENINFO: %s\n", strerror(errno)); -} - -void -fbdevHWRestore(ScrnInfoPtr pScrn) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - TRACE_ENTER("Restore"); - if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->saved_var))) - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); -} - -/* -------------------------------------------------------------------- */ -/* callback for xf86HandleColormaps */ - -void -fbdevHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, - LOCO *colors, VisualPtr pVisual) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - struct fb_cmap cmap; - unsigned short red,green,blue; - int i; - - TRACE_ENTER("LoadPalette"); - cmap.len = 1; - cmap.red = &red; - cmap.green = &green; - cmap.blue = &blue; - cmap.transp = NULL; - for (i = 0; i < numColors; i++) { - cmap.start = indices[i]; - red = (colors[indices[i]].red << 8) | - colors[indices[i]].red; - green = (colors[indices[i]].green << 8) | - colors[indices[i]].green; - blue = (colors[indices[i]].blue << 8) | - colors[indices[i]].blue; - if (-1 == ioctl(fPtr->fd,FBIOPUTCMAP,(void*)&cmap)) - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOPUTCMAP: %s\n", strerror(errno)); - } -} - -/* -------------------------------------------------------------------- */ -/* these can be hooked directly into ScrnInfoRec */ - -ModeStatus -fbdevHWValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - - TRACE_ENTER("ValidMode"); - - if (!fbdevHWSetMode(pScrn, mode, TRUE)) - return MODE_BAD; - - return MODE_OK; -} - -Bool -fbdevHWSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - - TRACE_ENTER("SwitchMode"); - - if (!fbdevHWSetMode(pScrn, mode, FALSE)) - return FALSE; - - return TRUE; -} - -void -fbdevHWAdjustFrame(int scrnIndex, int x, int y, int flags) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - - TRACE_ENTER("AdjustFrame"); - if ( x < 0 || x + fPtr->var.xres > fPtr->var.xres_virtual || - y < 0 || y + fPtr->var.yres > fPtr->var.yres_virtual ) - return; - - fPtr->var.xoffset = x; - fPtr->var.yoffset = y; - if (-1 == ioctl(fPtr->fd,FBIOPAN_DISPLAY,(void*)&fPtr->var)) - xf86DrvMsgVerb(scrnIndex, X_WARNING, 5, - "FBIOPAN_DISPLAY: %s\n", strerror(errno)); -} - -Bool -fbdevHWEnterVT(int scrnIndex, int flags) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - - TRACE_ENTER("EnterVT"); - if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) - return FALSE; - fbdevHWAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); - return TRUE; -} - -void -fbdevHWLeaveVT(int scrnIndex, int flags) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - - TRACE_ENTER("LeaveVT"); - fbdevHWRestore(pScrn); -} - -void -fbdevHWDPMSSet(ScrnInfoPtr pScrn, int mode, int flags) -{ - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - unsigned long fbmode; - - TRACE_ENTER("DPMSSet"); - if (!pScrn->vtSema) - return; - - switch (mode) { - case DPMSModeOn: - fbmode = 0; - break; - case DPMSModeStandby: - fbmode = 2; - break; - case DPMSModeSuspend: - fbmode = 3; - break; - case DPMSModeOff: - fbmode = 4; - break; - default: - return; - } - - if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)fbmode)) - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOBLANK: %s\n", strerror(errno)); -} - -Bool -fbdevHWSaveScreen(ScreenPtr pScreen, int mode) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); - unsigned long unblank; - - TRACE_ENTER("HWSaveScreen"); - if (!pScrn->vtSema) - return TRUE; - - unblank = xf86IsUnblank(mode); - - if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)(1-unblank))) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "FBIOBLANK: %s\n", strerror(errno)); - return FALSE; - } - - return TRUE; -} - -xf86SwitchModeProc * -fbdevHWSwitchModeWeak(void) { return fbdevHWSwitchMode; } - -xf86AdjustFrameProc * -fbdevHWAdjustFrameWeak(void) { return fbdevHWAdjustFrame; } - -xf86EnterVTProc * -fbdevHWEnterVTWeak(void) { return fbdevHWEnterVT; } - -xf86LeaveVTProc * -fbdevHWLeaveVTWeak(void) { return fbdevHWLeaveVT; } - -xf86ValidModeProc * -fbdevHWValidModeWeak(void) { return fbdevHWValidMode; } - -xf86DPMSSetProc * -fbdevHWDPMSSetWeak(void) { return fbdevHWDPMSSet; } - -xf86LoadPaletteProc * -fbdevHWLoadPaletteWeak(void) { return fbdevHWLoadPalette; } - -SaveScreenProcPtr -fbdevHWSaveScreenWeak(void) { return fbdevHWSaveScreen; } +/* all driver need this */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "xf86.h" +#include "xf86_OSproc.h" + +/* pci stuff */ +#include "xf86PciInfo.h" +#include "xf86Pci.h" + +#include "xf86cmap.h" + +#include "fbdevhw.h" +#include "fbpriv.h" + +#define PAGE_MASK (~(getpagesize() - 1)) + +#include "globals.h" +#include <X11/extensions/dpmsconst.h> + +#define DEBUG 0 + +#define PAGE_MASK (~(getpagesize() - 1)) + +#if DEBUG +# define TRACE_ENTER(str) ErrorF("fbdevHW: " str " %d\n",pScrn->scrnIndex) +#else +# define TRACE_ENTER(str) +#endif + +/* -------------------------------------------------------------------- */ + +static MODULESETUPPROTO(fbdevhwSetup); + +static XF86ModuleVersionInfo fbdevHWVersRec = +{ + "fbdevhw", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 0, 0, 2, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + {0,0,0,0} +}; + +_X_EXPORT XF86ModuleData fbdevhwModuleData = { + &fbdevHWVersRec, + fbdevhwSetup, + NULL +}; + +static pointer +fbdevhwSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + return (pointer)1; +} + +#include <fcntl.h> +#include <errno.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +/* -------------------------------------------------------------------- */ +/* our private data, and two functions to allocate/free this */ + +#define FBDEVHWPTRLVAL(p) (p)->privates[fbdevHWPrivateIndex].ptr +#define FBDEVHWPTR(p) ((fbdevHWPtr)(FBDEVHWPTRLVAL(p))) + +static int fbdevHWPrivateIndex = -1; + +typedef struct { + /* framebuffer device: filename (/dev/fb*), handle, more */ + char* device; + int fd; + void* fbmem; + unsigned int fbmem_len; + unsigned int fboff; + char* mmio; + unsigned int mmio_len; + + /* current hardware state */ + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + + /* saved video mode */ + struct fb_var_screeninfo saved_var; + + /* FIXME: unused??? [geert] */ + struct fb_cmap saved_cmap; + unsigned short *saved_red; + unsigned short *saved_green; + unsigned short *saved_blue; + + /* buildin video mode */ + DisplayModeRec buildin; + +} fbdevHWRec, *fbdevHWPtr; + +Bool +fbdevHWGetRec(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr; + + if (fbdevHWPrivateIndex < 0) + fbdevHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + + if (FBDEVHWPTR(pScrn) != NULL) + return TRUE; + + fPtr = FBDEVHWPTRLVAL(pScrn) = xnfcalloc(sizeof(fbdevHWRec), 1); + return TRUE; +} + +void +fbdevHWFreeRec(ScrnInfoPtr pScrn) +{ + if (fbdevHWPrivateIndex < 0) + return; + if (FBDEVHWPTR(pScrn) == NULL) + return; + free(FBDEVHWPTR(pScrn)); + FBDEVHWPTRLVAL(pScrn) = NULL; +} + +int +fbdevHWGetFD(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr; + + fbdevHWGetRec(pScrn); + fPtr = FBDEVHWPTR(pScrn); + + return fPtr->fd; +} + +/* -------------------------------------------------------------------- */ +/* some helpers for printing debug informations */ + +#if DEBUG +static void +print_fbdev_mode(char *txt, struct fb_var_screeninfo *var) +{ + ErrorF( "fbdev %s mode:\t%d %d %d %d %d %d %d %d %d %d %d:%d:%d\n", + txt,var->pixclock, + var->xres, var->right_margin, var->hsync_len, var->left_margin, + var->yres, var->lower_margin, var->vsync_len, var->upper_margin, + var->bits_per_pixel, + var->red.length, var->green.length, var->blue.length); +} + +static void +print_xfree_mode(char *txt, DisplayModePtr mode) +{ + ErrorF( "xfree %s mode:\t%d %d %d %d %d %d %d %d %d\n", + txt,mode->Clock, + mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal, + mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal); +} +#endif + +/* -------------------------------------------------------------------- */ +/* Convert timings between the XFree and the Frame Buffer Device */ + +static void +xfree2fbdev_fblayout(ScrnInfoPtr pScrn, struct fb_var_screeninfo *var) +{ + var->xres_virtual = pScrn->displayWidth ? pScrn->displayWidth : + pScrn->virtualX; + var->yres_virtual = pScrn->virtualY; + var->bits_per_pixel = pScrn->bitsPerPixel; + if (pScrn->defaultVisual == TrueColor || + pScrn->defaultVisual == DirectColor) { + var->red.length = pScrn->weight.red; + var->green.length = pScrn->weight.green; + var->blue.length = pScrn->weight.blue; + } else { + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + } +} + +static void +xfree2fbdev_timing(DisplayModePtr mode, struct fb_var_screeninfo *var) +{ + var->xres = mode->HDisplay; + var->yres = mode->VDisplay; + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + var->xoffset = var->yoffset = 0; + var->pixclock = mode->Clock ? 1000000000/mode->Clock : 0; + var->right_margin = mode->HSyncStart-mode->HDisplay; + var->hsync_len = mode->HSyncEnd-mode->HSyncStart; + var->left_margin = mode->HTotal-mode->HSyncEnd; + var->lower_margin = mode->VSyncStart-mode->VDisplay; + var->vsync_len = mode->VSyncEnd-mode->VSyncStart; + var->upper_margin = mode->VTotal-mode->VSyncEnd; + var->sync = 0; + if (mode->Flags & V_PHSYNC) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (mode->Flags & V_PVSYNC) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (mode->Flags & V_PCSYNC) + var->sync |= FB_SYNC_COMP_HIGH_ACT; + if (mode->Flags & V_BCAST) + var->sync |= FB_SYNC_BROADCAST; + if (mode->Flags & V_INTERLACE) + var->vmode = FB_VMODE_INTERLACED; + else if (mode->Flags & V_DBLSCAN) + var->vmode = FB_VMODE_DOUBLE; + else + var->vmode = FB_VMODE_NONINTERLACED; +} + +static Bool +fbdev_modes_equal(struct fb_var_screeninfo *set, struct fb_var_screeninfo *req) +{ + return (set->xres_virtual >= req->xres_virtual && + set->yres_virtual >= req->yres_virtual && + set->bits_per_pixel == req->bits_per_pixel && + set->red.length == req->red.length && + set->green.length == req->green.length && + set->blue.length == req->blue.length && + set->xres == req->xres && set->yres == req->yres && + set->right_margin == req->right_margin && + set->hsync_len == req->hsync_len && + set->left_margin == req->left_margin && + set->lower_margin == req->lower_margin && + set->vsync_len == req->vsync_len && + set->upper_margin == req->upper_margin && + set->sync == req->sync && set->vmode == req->vmode); +} + +static void +fbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode) +{ + mode->Clock = var->pixclock ? 1000000000/var->pixclock : 0; + mode->HDisplay = var->xres; + mode->HSyncStart = mode->HDisplay+var->right_margin; + mode->HSyncEnd = mode->HSyncStart+var->hsync_len; + mode->HTotal = mode->HSyncEnd+var->left_margin; + mode->VDisplay = var->yres; + mode->VSyncStart = mode->VDisplay+var->lower_margin; + mode->VSyncEnd = mode->VSyncStart+var->vsync_len; + mode->VTotal = mode->VSyncEnd+var->upper_margin; + mode->Flags = 0; + mode->Flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; + mode->Flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + mode->Flags |= var->sync & FB_SYNC_COMP_HIGH_ACT ? V_PCSYNC : V_NCSYNC; + if (var->sync & FB_SYNC_BROADCAST) + mode->Flags |= V_BCAST; + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + mode->Flags |= V_INTERLACE; + else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) + mode->Flags |= V_DBLSCAN; + mode->SynthClock = mode->Clock; + mode->CrtcHDisplay = mode->HDisplay; + mode->CrtcHSyncStart = mode->HSyncStart; + mode->CrtcHSyncEnd = mode->HSyncEnd; + mode->CrtcHTotal = mode->HTotal; + mode->CrtcVDisplay = mode->VDisplay; + mode->CrtcVSyncStart = mode->VSyncStart; + mode->CrtcVSyncEnd = mode->VSyncEnd; + mode->CrtcVTotal = mode->VTotal; + mode->CrtcHAdjusted = FALSE; + mode->CrtcVAdjusted = FALSE; +} + + +/* -------------------------------------------------------------------- */ +/* open correct framebuffer device */ + +/** + * Try to find the framebuffer device for a given PCI device + */ +static int +fbdev_open_pci(struct pci_device * pPci, char **namep) +{ + struct fb_fix_screeninfo fix; + char filename[256]; + int fd,i,j; + + + /* There are two ways to that we can determine which fb device is + * associated with this PCI device. The more modern way is to look in + * the sysfs directory for the PCI device for a file named + * "graphics/fb*" + */ + + for (i = 0; i < 8; i++) { + sprintf(filename, + "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics/fb%d", + pPci->domain, pPci->bus, pPci->dev, pPci->func, i); + + fd = open(filename, O_RDONLY, 0); + if (fd < 0) { + sprintf(filename, + "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics:fb%d", + pPci->domain, pPci->bus, pPci->dev, pPci->func, i); + fd = open(filename, O_RDONLY, 0); + } + if (fd >= 0) { + close(fd); + sprintf(filename, "/dev/fb%d", i); + + fd = open(filename, O_RDWR, 0); + if (fd != -1) { + if (ioctl(fd, FBIOGET_FSCREENINFO, (void*) & fix) != -1) { + if (namep) { + *namep = xnfalloc(16); + strncpy(*namep,fix.id,16); + } + + return fd; + } + close(fd); + } + } + } + + + /* The other way is to examine the resources associated with each fb + * device and see if there is a match with the PCI device. This technique + * has some problems on certain mixed 64-bit / 32-bit architectures. + * There is a flaw in the fb_fix_screeninfo structure in that it only + * returns the low 32-bits of the address of the resources associated with + * a device. However, on a mixed architecture the base addresses of PCI + * devices, even for 32-bit applications, may be higher than 0x0f0000000. + */ + + for (i = 0; i < 8; i++) { + sprintf(filename,"/dev/fb%d",i); + if (-1 == (fd = open(filename,O_RDWR,0))) { + xf86DrvMsg(-1, X_WARNING, + "open %s: %s\n", filename, strerror(errno)); + continue; + } + if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)&fix)) { + close(fd); + continue; + } + for (j = 0; j < 6; j++) { + const pciaddr_t res_start = pPci->regions[j].base_addr; + const pciaddr_t res_end = res_start + pPci->regions[j].size; + + if ((0 != fix.smem_len && + (pciaddr_t) fix.smem_start >= res_start && + (pciaddr_t) fix.smem_start < res_end) || + (0 != fix.mmio_len && + (pciaddr_t) fix.mmio_start >= res_start && + (pciaddr_t) fix.mmio_start < res_end)) + break; + } + if (j == 6) { + close(fd); + continue; + } + if (namep) { + *namep = xnfalloc(16); + strncpy(*namep,fix.id,16); + } + return fd; + } + + if (namep) + *namep = NULL; + + xf86DrvMsg(-1, X_ERROR, + "Unable to find a valid framebuffer device\n"); + return -1; +} + +static int +fbdev_open(int scrnIndex, char *dev, char** namep) +{ + struct fb_fix_screeninfo fix; + int fd; + + /* try argument (from XF86Config) first */ + if (dev) { + fd = open(dev,O_RDWR,0); + } else { + /* second: environment variable */ + dev = getenv("FRAMEBUFFER"); + if ((NULL == dev) || ((fd = open(dev,O_RDWR,0)) == -1)) { + /* last try: default device */ + dev = "/dev/fb0"; + fd = open(dev,O_RDWR,0); + } + } + + if (fd == -1) { + xf86DrvMsg(scrnIndex, X_ERROR, + "open %s: %s\n", dev, strerror(errno)); + return -1; + } + + if (namep) { + if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)(&fix))) { + *namep = NULL; + xf86DrvMsg(scrnIndex, X_ERROR, + "FBIOGET_FSCREENINFO: %s\n", strerror(errno)); + return -1; + } else { + *namep = xnfalloc(16); + strncpy(*namep,fix.id,16); + } + } + return fd; +} + +/* -------------------------------------------------------------------- */ + +Bool +fbdevHWProbe(struct pci_device * pPci, char *device,char **namep) +{ + int fd; + + if (pPci) + fd = fbdev_open_pci(pPci,namep); + else + fd = fbdev_open(-1,device,namep); + + if (-1 == fd) + return FALSE; + close(fd); + return TRUE; +} + +Bool +fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device * pPci, char *device) +{ + fbdevHWPtr fPtr; + + TRACE_ENTER("Init"); + + fbdevHWGetRec(pScrn); + fPtr = FBDEVHWPTR(pScrn); + + /* open device */ + if (pPci) + fPtr->fd = fbdev_open_pci(pPci,NULL); + else + fPtr->fd = fbdev_open(pScrn->scrnIndex,device,NULL); + if (-1 == fPtr->fd) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to open framebuffer device, consult warnings" + " and/or errors above for possible reasons\n" + "\t(you may have to look at the server log to see" + " warnings)\n"); + return FALSE; + } + + /* get current fb device settings */ + if (-1 == ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ioctl FBIOGET_FSCREENINFO: %s\n", + strerror(errno)); + return FALSE; + } + if (-1 == ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ioctl FBIOGET_VSCREENINFO: %s\n", + strerror(errno)); + return FALSE; + } + + /* we can use the current settings as "buildin mode" */ + fbdev2xfree_timing(&fPtr->var, &fPtr->buildin); + fPtr->buildin.name = "current"; + fPtr->buildin.next = &fPtr->buildin; + fPtr->buildin.prev = &fPtr->buildin; + fPtr->buildin.type |= M_T_BUILTIN; + + return TRUE; +} + +char* +fbdevHWGetName(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + return fPtr->fix.id; +} + +int +fbdevHWGetDepth(ScrnInfoPtr pScrn, int *fbbpp) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + if (fbbpp) + *fbbpp = fPtr->var.bits_per_pixel; + + if (fPtr->fix.visual == FB_VISUAL_TRUECOLOR || + fPtr->fix.visual == FB_VISUAL_DIRECTCOLOR) + return fPtr->var.red.length+fPtr->var.green.length+ + fPtr->var.blue.length; + else + return fPtr->var.bits_per_pixel; +} + +int +fbdevHWGetLineLength(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + if (fPtr->fix.line_length) + return fPtr->fix.line_length; + else + return fPtr->var.xres_virtual*fPtr->var.bits_per_pixel/8; +} + +int +fbdevHWGetType(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + return fPtr->fix.type; +} + +int +fbdevHWGetVidmem(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + return fPtr->fix.smem_len; +} + +static Bool +fbdevHWSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool check) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + struct fb_var_screeninfo req_var = fPtr->var, set_var; + + TRACE_ENTER("SetMode"); + + xfree2fbdev_fblayout(pScrn, &req_var); + xfree2fbdev_timing(mode, &req_var); + +#if DEBUG + print_xfree_mode("init", mode); + print_fbdev_mode("init", &req_var); +#endif + + set_var = req_var; + + if (check) + set_var.activate = FB_ACTIVATE_TEST; + + if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void*)(&set_var))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); + return FALSE; + } + + if (!fbdev_modes_equal(&set_var, &req_var)) { + if (!check) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOPUT_VSCREENINFO succeeded but modified " + "mode\n"); +#if DEBUG + print_fbdev_mode("returned", &set_var); +#endif + return FALSE; + } + + if (!check) + fPtr->var = set_var; + + return TRUE; +} + +void +fbdevHWSetVideoModes(ScrnInfoPtr pScrn) +{ + char **modename; + DisplayModePtr mode,this,last = pScrn->modes; + + TRACE_ENTER("VerifyModes"); + if (NULL == pScrn->display->modes) + return; + + pScrn->virtualX = pScrn->display->virtualX; + pScrn->virtualY = pScrn->display->virtualY; + + for (modename = pScrn->display->modes; *modename != NULL; modename++) { + for (mode = pScrn->monitor->Modes; mode != NULL; mode = mode->next) + if (0 == strcmp(mode->name,*modename)) + break; + if (NULL == mode) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "\tmode \"%s\" not found\n", *modename); + continue; + } + + if (!fbdevHWSetMode(pScrn, mode, TRUE)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "\tmode \"%s\" test failed\n", *modename); + continue; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "\tmode \"%s\" ok\n", *modename); + + if (pScrn->virtualX < mode->HDisplay) + pScrn->virtualX = mode->HDisplay; + if (pScrn->virtualY < mode->VDisplay) + pScrn->virtualY = mode->VDisplay; + + if (NULL == pScrn->modes) { + this = pScrn->modes = xf86DuplicateMode(mode); + this->next = this; + this->prev = this; + } else { + this = xf86DuplicateMode(mode); + this->next = pScrn->modes; + this->prev = last; + last->next = this; + pScrn->modes->prev = this; + } + last = this; + } +} + +DisplayModePtr +fbdevHWGetBuildinMode(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + return &fPtr->buildin; +} + +void +fbdevHWUseBuildinMode(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + TRACE_ENTER("UseBuildinMode"); + pScrn->modes = &fPtr->buildin; + pScrn->virtualX = pScrn->display->virtualX; + pScrn->virtualY = pScrn->display->virtualY; + if (pScrn->virtualX < fPtr->buildin.HDisplay) + pScrn->virtualX = fPtr->buildin.HDisplay; + if (pScrn->virtualY < fPtr->buildin.VDisplay) + pScrn->virtualY = fPtr->buildin.VDisplay; +} + +/* -------------------------------------------------------------------- */ + +static void +calculateFbmem_len(fbdevHWPtr fPtr) +{ + fPtr->fboff = (unsigned long) fPtr->fix.smem_start & ~PAGE_MASK; + fPtr->fbmem_len = (fPtr->fboff+fPtr->fix.smem_len+~PAGE_MASK) & + PAGE_MASK; +} + + +void* +fbdevHWMapVidmem(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + TRACE_ENTER("MapVidmem"); + if (NULL == fPtr->fbmem) { + calculateFbmem_len(fPtr); + fPtr->fbmem = mmap(NULL, fPtr->fbmem_len, PROT_READ | PROT_WRITE, + MAP_SHARED, fPtr->fd, 0); + if (-1 == (long)fPtr->fbmem) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "mmap fbmem: %s\n", strerror(errno)); + fPtr->fbmem = NULL; + } else { + /* Perhaps we'd better add fboff to fbmem and return 0 in + fbdevHWLinearOffset()? Of course we then need to mask + fPtr->fbmem with PAGE_MASK in fbdevHWUnmapVidmem() as + well. [geert] */ + } + } + pScrn->memPhysBase = (unsigned long)fPtr->fix.smem_start & (unsigned long)(PAGE_MASK); + pScrn->fbOffset = (unsigned long)fPtr->fix.smem_start & (unsigned long)(~PAGE_MASK); + return fPtr->fbmem; +} + +int +fbdevHWLinearOffset(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + TRACE_ENTER("LinearOffset"); + return fPtr->fboff; +} + +Bool +fbdevHWUnmapVidmem(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + TRACE_ENTER("UnmapVidmem"); + if (NULL != fPtr->fbmem) { + if (-1 == munmap(fPtr->fbmem, fPtr->fbmem_len)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "munmap fbmem: %s\n", strerror(errno)); + fPtr->fbmem = NULL; + } + return TRUE; +} + +void* +fbdevHWMapMMIO(ScrnInfoPtr pScrn) +{ + unsigned int mmio_off; + + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + TRACE_ENTER("MapMMIO"); + if (NULL == fPtr->mmio) { + /* tell the kernel not to use accels to speed up console scrolling */ + fPtr->var.accel_flags = 0; + if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->var))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); + return FALSE; + } + mmio_off = (unsigned long) fPtr->fix.mmio_start & ~PAGE_MASK; + fPtr->mmio_len = (mmio_off+fPtr->fix.mmio_len+~PAGE_MASK) & + PAGE_MASK; + if (NULL == fPtr->fbmem) + calculateFbmem_len(fPtr); + fPtr->mmio = mmap(NULL, fPtr->mmio_len, PROT_READ | PROT_WRITE, + MAP_SHARED, fPtr->fd, fPtr->fbmem_len); + if (-1 == (long)fPtr->mmio) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "mmap mmio: %s\n", strerror(errno)); + fPtr->mmio = NULL; + } else + fPtr->mmio += mmio_off; + } + return fPtr->mmio; +} + +Bool +fbdevHWUnmapMMIO(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + TRACE_ENTER("UnmapMMIO"); + if (NULL != fPtr->mmio) { + if (-1 == munmap((void *)((unsigned long)fPtr->mmio & PAGE_MASK), fPtr->mmio_len)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "munmap mmio: %s\n", strerror(errno)); + fPtr->mmio = NULL; + /* FIXME: restore var.accel_flags [geert] */ + } + return TRUE; +} + +/* -------------------------------------------------------------------- */ + +Bool +fbdevHWModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + pScrn->vtSema = TRUE; + + /* set */ + if (!fbdevHWSetMode(pScrn, mode, FALSE)) + return FALSE; + + /* read back */ + if (0 != ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOGET_FSCREENINFO: %s\n", strerror(errno)); + return FALSE; + } + if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOGET_VSCREENINFO: %s\n", strerror(errno)); + return FALSE; + } + + if (pScrn->defaultVisual == TrueColor || + pScrn->defaultVisual == DirectColor) { + /* XXX: This is a hack, but it should be a NOP for all the setups that + * worked before and actually seems to fix some others... + */ + pScrn->offset.red = fPtr->var.red.offset; + pScrn->offset.green = fPtr->var.green.offset; + pScrn->offset.blue = fPtr->var.blue.offset; + pScrn->mask.red = ((1 << fPtr->var.red.length) - 1) << fPtr->var.red.offset; + pScrn->mask.green = ((1 << fPtr->var.green.length) - 1) << fPtr->var.green.offset; + pScrn->mask.blue = ((1 << fPtr->var.blue.length) - 1) << fPtr->var.blue.offset; + } + + return TRUE; +} + +/* -------------------------------------------------------------------- */ +/* video mode save/restore */ + +/* TODO: colormap */ +void +fbdevHWSave(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + TRACE_ENTER("Save"); + if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->saved_var))) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOGET_VSCREENINFO: %s\n", strerror(errno)); +} + +void +fbdevHWRestore(ScrnInfoPtr pScrn) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + TRACE_ENTER("Restore"); + if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->saved_var))) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); +} + +/* -------------------------------------------------------------------- */ +/* callback for xf86HandleColormaps */ + +void +fbdevHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO *colors, VisualPtr pVisual) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + struct fb_cmap cmap; + unsigned short red,green,blue; + int i; + + TRACE_ENTER("LoadPalette"); + cmap.len = 1; + cmap.red = &red; + cmap.green = &green; + cmap.blue = &blue; + cmap.transp = NULL; + for (i = 0; i < numColors; i++) { + cmap.start = indices[i]; + red = (colors[indices[i]].red << 8) | + colors[indices[i]].red; + green = (colors[indices[i]].green << 8) | + colors[indices[i]].green; + blue = (colors[indices[i]].blue << 8) | + colors[indices[i]].blue; + if (-1 == ioctl(fPtr->fd,FBIOPUTCMAP,(void*)&cmap)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOPUTCMAP: %s\n", strerror(errno)); + } +} + +/* -------------------------------------------------------------------- */ +/* these can be hooked directly into ScrnInfoRec */ + +ModeStatus +fbdevHWValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + TRACE_ENTER("ValidMode"); + + if (!fbdevHWSetMode(pScrn, mode, TRUE)) + return MODE_BAD; + + return MODE_OK; +} + +Bool +fbdevHWSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + TRACE_ENTER("SwitchMode"); + + if (!fbdevHWSetMode(pScrn, mode, FALSE)) + return FALSE; + + return TRUE; +} + +void +fbdevHWAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + + TRACE_ENTER("AdjustFrame"); + if ( x < 0 || x + fPtr->var.xres > fPtr->var.xres_virtual || + y < 0 || y + fPtr->var.yres > fPtr->var.yres_virtual ) + return; + + fPtr->var.xoffset = x; + fPtr->var.yoffset = y; + if (-1 == ioctl(fPtr->fd,FBIOPAN_DISPLAY,(void*)&fPtr->var)) + xf86DrvMsgVerb(scrnIndex, X_WARNING, 5, + "FBIOPAN_DISPLAY: %s\n", strerror(errno)); +} + +Bool +fbdevHWEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + TRACE_ENTER("EnterVT"); + if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) + return FALSE; + fbdevHWAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + return TRUE; +} + +void +fbdevHWLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + TRACE_ENTER("LeaveVT"); + fbdevHWRestore(pScrn); +} + +void +fbdevHWDPMSSet(ScrnInfoPtr pScrn, int mode, int flags) +{ + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + unsigned long fbmode; + + TRACE_ENTER("DPMSSet"); + if (!pScrn->vtSema) + return; + + switch (mode) { + case DPMSModeOn: + fbmode = 0; + break; + case DPMSModeStandby: + fbmode = 2; + break; + case DPMSModeSuspend: + fbmode = 3; + break; + case DPMSModeOff: + fbmode = 4; + break; + default: + return; + } + + if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)fbmode)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOBLANK: %s\n", strerror(errno)); +} + +Bool +fbdevHWSaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); + unsigned long unblank; + + TRACE_ENTER("HWSaveScreen"); + if (!pScrn->vtSema) + return TRUE; + + unblank = xf86IsUnblank(mode); + + if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)(1-unblank))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FBIOBLANK: %s\n", strerror(errno)); + return FALSE; + } + + return TRUE; +} + +xf86SwitchModeProc * +fbdevHWSwitchModeWeak(void) { return fbdevHWSwitchMode; } + +xf86AdjustFrameProc * +fbdevHWAdjustFrameWeak(void) { return fbdevHWAdjustFrame; } + +xf86EnterVTProc * +fbdevHWEnterVTWeak(void) { return fbdevHWEnterVT; } + +xf86LeaveVTProc * +fbdevHWLeaveVTWeak(void) { return fbdevHWLeaveVT; } + +xf86ValidModeProc * +fbdevHWValidModeWeak(void) { return fbdevHWValidMode; } + +xf86DPMSSetProc * +fbdevHWDPMSSetWeak(void) { return fbdevHWDPMSSet; } + +xf86LoadPaletteProc * +fbdevHWLoadPaletteWeak(void) { return fbdevHWLoadPalette; } + +SaveScreenProcPtr +fbdevHWSaveScreenWeak(void) { return fbdevHWSaveScreen; } diff --git a/xorg-server/hw/xfree86/i2c/bt829.c b/xorg-server/hw/xfree86/i2c/bt829.c index 3963ecf47..64c711681 100644 --- a/xorg-server/hw/xfree86/i2c/bt829.c +++ b/xorg-server/hw/xfree86/i2c/bt829.c @@ -1,745 +1,745 @@ -/* TODO: clean up/fix CC code */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> - -#include "xf86.h" -#include "xf86i2c.h" -#include "bt829.h" -#include "i2c_def.h" - -/* Changing the following settings (especially VCROP) may */ -/* require modifying code that calls this driver. */ -#define HCROP 0 /* amount to crop from the left and right edges */ -#define VCROP 0 /* amount to crop from the top and bottom edges */ - -#define BTVERSION (bt->id>>4) - -#define H(X) ( ((X)>>8) & 0xFF ) -#define L(X) ( (X) & 0xFF ) - -#define LIMIT(X,A,B) (((X)<(A)) ? (A) : ((X)>(B)) ? (B) : (X) ) - -/* Bt829 family chip ID's */ -#define BT815 0x02 -#define BT817 0x06 -#define BT819 0x07 -#define BT827 0x0C -#define BT829 0x0E - -/* Bt829 registers */ -#define STATUS 0x00 /* Device Status */ -#define IFORM 0x01 /* Input Format */ -#define TDEC 0x02 /* Temporal Decimation */ -#define CROP 0x03 /* MSB Cropping */ -#define VDELAY_LO 0x04 /* Vertical Delay */ -#define VACTIVE_LO 0x05 /* Vertical Active */ -#define HDELAY_LO 0x06 /* Horizontal Delay */ -#define HACTIVE_LO 0x07 /* Horizontal Active */ -#define HSCALE_HI 0x08 /* Horizontal Scaling */ -#define HSCALE_LO 0x09 /* Horizontal Scaling */ -#define BRIGHT 0x0A /* Brightness Control */ -#define CONTROL 0x0B /* Miscellaneous Control */ -#define CONTRAST_LO 0x0C /* Luma Gain (Contrast) */ -#define SAT_U_LO 0x0D /* Chroma (U) Gain (Saturation) */ -#define SAT_V_LO 0x0E /* Chroma (V) Gain (Saturation) */ -#define HUE 0x0F /* Hue Control */ -#define SCLOOP 0x10 /* SC Loop Control */ -#define WC_UP 0x11 /* White Crush Up Count */ -#define OFORM 0x12 /* Output Format */ -#define VSCALE_HI 0x13 /* Vertical Scaling */ -#define VSCALE_LO 0x14 /* Vertical Scaling */ -#define TEST 0x15 /* Test Control */ -#define VPOLE 0x16 /* Video Timing Polarity */ -#define IDCODE 0x17 /* ID Code */ -#define ADELAY 0x18 /* AGC Delay */ -#define BDELAY 0x19 /* Burst Gate Delay */ -#define ADC 0x1A /* ADC Interface */ -#define VTC 0x1B /* Video Timing Control */ -#define CC_STATUS 0x1C /* Extended Data Services/Closed Capt Status */ -#define CC_DATA 0x1D /* Extended Data Services/Closed Capt Data */ -#define WC_DN 0x1E /* White Crush Down Count */ -#define SRESET 0x1F /* Software Reset */ -#define P_IO 0x3F /* Programmable I/O */ - -static CARD8 btread(BT829Ptr bt, CARD8 reg) -{ - CARD8 v; - - I2C_WriteRead(&(bt->d), ®, 1, &v, 1); - - return v; -} - -static void btwrite(BT829Ptr bt, CARD8 reg, CARD8 val) -{ - CARD8 data[2]; - - data[0] = reg; - data[1] = val; - I2C_WriteRead(&(bt->d), data, 2, NULL, 0); -} - -/* - * Register access - */ -static void btwrite_status(BT829Ptr bt) /* STATUS */ -{ - btwrite(bt, STATUS, 0x00); /* clear */ -} - -static void btwrite_iform(BT829Ptr bt) /* IFORM */ -{ - int xtsel; - - switch (bt->format) { - case BT829_NTSC: - case BT829_NTSC_JAPAN: - case BT829_PAL_M: - case BT829_PAL_N_COMB: /* gatos says xtsel = 2 */ - xtsel = 1; - break; - case BT829_PAL: - case BT829_PAL_N: - case BT829_SECAM: - xtsel = 2; - break; - default: /* shouldn't get here */ - xtsel = 3; /* hardware default */ - break; - } - - btwrite(bt, IFORM, (bt->mux<<5) | (xtsel<<3) | bt->format); -} - -static void btwrite_tdec(BT829Ptr bt) /* TDEC */ -{ - /* use default */ -} - -static void btwrite_crop(BT829Ptr bt) /* CROP */ -{ - btwrite(bt, CROP, (H(bt->vdelay)<<6) | (H(bt->vactive)<<4) | - (H(bt->hdelay)<<2) | H(bt->width)); -} - -static void btwrite_vdelay_lo(BT829Ptr bt) /* VDELAY_LO */ -{ - btwrite(bt, VDELAY_LO, L(bt->vdelay)); -} - -static void btwrite_vactive_lo(BT829Ptr bt) /* VACTIVE_LO */ -{ - btwrite(bt, VACTIVE_LO, L(bt->vactive)); -} - -static void btwrite_hdelay_lo(BT829Ptr bt) /* HDELAY_LO */ -{ - btwrite(bt, HDELAY_LO, L(bt->hdelay)); -} - -static void btwrite_hactive_lo(BT829Ptr bt) /* HACTIVE_LO */ -{ - btwrite(bt, HACTIVE_LO, L(bt->width)); -} - -static void btwrite_hscale_hi(BT829Ptr bt) /* HSCALE_HI */ -{ - btwrite(bt, HSCALE_HI, H(bt->hscale)); -} - -static void btwrite_hscale_lo(BT829Ptr bt) /* HSCALE_LO */ -{ - btwrite(bt, HSCALE_LO, L(bt->hscale)); -} - -static void btwrite_bright(BT829Ptr bt) /* BRIGHT */ -{ - btwrite(bt, BRIGHT, bt->brightness); -} - -static void btwrite_control(BT829Ptr bt) /* CONTROL */ -{ - int ldec; - - /* The data sheet says ldec should always be 0 for SECAM */ - /* but the picture quality is better with ldec = 1 */ - ldec = (bt->width > 360); /* gatos says 384 */ - - btwrite(bt, CONTROL, - ((bt->mux==bt->svideo_mux) ? 0xC0:0x00) | /* LNOTCH and COMP */ - (ldec<<5) | (H(bt->contrast)<<2) | (H(bt->sat_u)<<1) | H(bt->sat_v)); -} - -static void btwrite_contrast_lo(BT829Ptr bt) /* CONTRAST_LO */ -{ - btwrite(bt, CONTRAST_LO, L(bt->contrast)); -} - -static void btwrite_sat_u_lo(BT829Ptr bt) /* SAT_U_LO */ -{ - btwrite(bt, SAT_U_LO, L(bt->sat_u)); -} - -static void btwrite_sat_v_lo(BT829Ptr bt) /* SAT_V_LO */ -{ - btwrite(bt, SAT_V_LO, L(bt->sat_v)); -} - -static void btwrite_hue(BT829Ptr bt) /* HUE */ -{ - btwrite(bt, HUE, bt->hue); -} - -static void btwrite_scloop(BT829Ptr bt) /* SCLOOP */ -{ - if (BTVERSION >= BT827) { - btwrite(bt, SCLOOP, - (bt->format==BT829_SECAM) ? 0x10:0x00 /* QCIF or AUTO */ - ); - } -} - -static void btwrite_wc_up(BT829Ptr bt) /* WC_UP */ -{ - if (BTVERSION >= BT827) { - /* use default */ - } -} - -static void btwrite_oform(BT829Ptr bt) /* OFORM */ -{ - btwrite(bt, OFORM, (bt->code<<3) | (bt->len<<2) | - 0x02 /* RANGE = 0, CORE = 0, VBI_FRAME = 0, OES = 2 (default) */ - ); -} - -static void btwrite_vscale_hi(BT829Ptr bt) /* VSCALE_HI */ -{ - btwrite(bt, VSCALE_HI, H(bt->vscale) | - 0x60 /* YCOMB = 0, COMB = 1, INT = 1 (default) */ - ); -} - -static void btwrite_vscale_lo(BT829Ptr bt) /* VSCALE_LO */ -{ - btwrite(bt, VSCALE_LO, L(bt->vscale)); -} - -/* TEST should not be written to */ - -static void btwrite_vpole(BT829Ptr bt) /* VPOLE */ -{ - btwrite(bt, VPOLE, (bt->out_en<<7)); -} - -/* IDCODE is read only */ - -static void btwrite_adelay(BT829Ptr bt) /* ADELAY */ -{ - switch (bt->format) { - case BT829_NTSC: - case BT829_NTSC_JAPAN: - case BT829_PAL_M: - btwrite(bt, ADELAY, 104); - break; - case BT829_PAL: - case BT829_PAL_N: - case BT829_SECAM: - case BT829_PAL_N_COMB: - btwrite(bt, ADELAY, 127); - break; - default: /* shouldn't get here */ - btwrite(bt, ADELAY, 104); /* hardware default */ - break; - } -} - -static void btwrite_bdelay(BT829Ptr bt) /* BDELAY */ -{ - switch (bt->format) { - case BT829_NTSC: - case BT829_NTSC_JAPAN: - case BT829_PAL_M: - btwrite(bt, BDELAY, 93); - break; - case BT829_PAL: - case BT829_PAL_N: - case BT829_PAL_N_COMB: - btwrite(bt, BDELAY, 114); - break; - case BT829_SECAM: - btwrite(bt, BDELAY, 160); - break; - default: /* shouldn't get here */ - btwrite(bt, BDELAY, 93); /* hardware default */ - break; - } -} - -static void btwrite_adc(BT829Ptr bt) /* ADC */ -{ - btwrite(bt, ADC, bt->mux==bt->svideo_mux ? 0x80:0x82); /* CSLEEP = 0 or 1 */ -} - -static void btwrite_vtc(BT829Ptr bt) /* VTC */ -{ - int vfilt = 0; /* hardware default */ - - if (BTVERSION > BT827) { /* gatos says >= BT827 */ - switch (bt->format) { - case BT829_NTSC: - case BT829_NTSC_JAPAN: - case BT829_PAL_M: - case BT829_PAL_N_COMB: /* gatos groups with BT829_PAL */ - if (bt->width <= 360) vfilt = 1; /* gatos says <= 240 */ - if (bt->width <= 180) vfilt = 2; /* gatos says <= 120 */ - if (bt->width <= 90) vfilt = 3; /* gatos says <= 60 */ - break; - case BT829_PAL: - case BT829_PAL_N: - case BT829_SECAM: - if (bt->width <= 384) vfilt = 1; - if (bt->width <= 192) vfilt = 2; - if (bt->width<= 96) vfilt = 3; - break; - default: /* shouldn't get here */ - break; /* use hardware default */ - } - btwrite(bt, VTC, (bt->vbien<<4) | (bt->vbifmt<<3) | vfilt); - } -} - -static void btwrite_cc_status(BT829Ptr bt) /* CC_STATUS */ -{ /* FIXME: ATI specific */ - if (BTVERSION >= BT827) { - if (bt->ccmode == 0) btwrite(bt, CC_STATUS, 0x00); - /* 0x40 is activate to set the CCVALID line. Not required yet */ - else btwrite(bt, CC_STATUS, (bt->ccmode<<4) | 0x40); - } -} - -/* CC_DATA is read only */ - -static void btwrite_wc_dn(BT829Ptr bt) /* WC_DN */ -{ - if (BTVERSION >= BT827) { - /* use default */ - } -} - -static void bt_reset(BT829Ptr bt) { /* SRESET */ - btwrite(bt, SRESET, 0x0); /* Reset all registers */ -} - -static void btwrite_p_io(BT829Ptr bt) /* P_IO */ -{ - if (BTVERSION >= BT827) { - btwrite(bt, P_IO, bt->p_io); - } -} - -/* - * Deal with dependencies - */ -static void propagate_changes(BT829Ptr bt) -{ - CARD16 hdelay, unscaled_hdelay, vdelay, hscale, vscale; - int htotal, vactive; - - switch (bt->format) { - case BT829_NTSC: - case BT829_NTSC_JAPAN: - case BT829_PAL_M: - vdelay = 22; - htotal = 754; - vactive = 480; - unscaled_hdelay = 135; - break; - case BT829_PAL: - case BT829_PAL_N: - vdelay = (bt->tunertype==5) ? 34 : 22; - htotal = 922; - vactive = 576; - unscaled_hdelay = 186; - break; - case BT829_SECAM: - vdelay = 34; - htotal = 922; - vactive = 576; - unscaled_hdelay = 186; - break; - case BT829_PAL_N_COMB: - vdelay = (bt->tunertype==5) ? 34 : 22; /* windows says 22 */ - htotal = 754; /* gatos and windows say 922 */ - vactive = 576; - unscaled_hdelay = 135; /* gatos and windows say 186 */ - break; - default: /* shouldn't get here */ - vdelay = 22; /* hardware default */ - htotal = 754; - vactive = 480; /* hardware default */ - unscaled_hdelay = 135; - break; - } - - bt->htotal = htotal; /* Used for error checking in bt829_SetCaptSize */ - - hscale = 4096 * htotal / (bt->width + 2 * HCROP)-4096; - hdelay = ( - HCROP + (bt->width + 2 * HCROP) * unscaled_hdelay / htotal - ) & 0x3FE; - - vactive = vactive - 2 * VCROP; - vdelay = vdelay + VCROP; - vscale = (0x10000 - (512*vactive/bt->height-512)) & 0x1FFF; - - if ((hdelay != bt->hdelay) || (vdelay != bt->vdelay) || - (vactive != bt->vactive) || (hscale != bt->hscale) || - (vscale != bt->vscale)) { - bt->hdelay = hdelay; - bt->vdelay = vdelay; - bt->vactive = vactive; - bt->hscale = hscale; - bt->vscale = vscale; - btwrite_crop(bt); - btwrite_vdelay_lo(bt); - btwrite_vactive_lo(bt); - btwrite_hdelay_lo(bt); - btwrite_hscale_hi(bt); - btwrite_hscale_lo(bt); - btwrite_control(bt); - btwrite_vscale_hi(bt); - btwrite_vscale_lo(bt); - } -} - -static void write_all(BT829Ptr bt) -{ - bt_reset(bt); - propagate_changes(bt); /* ensure consistency */ - btwrite_iform(bt); - btwrite_tdec(bt); - btwrite_crop(bt); - btwrite_vdelay_lo(bt); - btwrite_vactive_lo(bt); - btwrite_hdelay_lo(bt); - btwrite_hactive_lo(bt); - btwrite_hscale_hi(bt); - btwrite_hscale_lo(bt); - btwrite_bright(bt); - btwrite_control(bt); - btwrite_contrast_lo(bt); - btwrite_sat_u_lo(bt); - btwrite_sat_v_lo(bt); - btwrite_hue(bt); - btwrite_scloop(bt); - btwrite_wc_up(bt); - btwrite_oform(bt); - btwrite_vscale_hi(bt); - btwrite_vscale_lo(bt); - btwrite_vpole(bt); - btwrite_adelay(bt); - btwrite_bdelay(bt); - btwrite_adc(bt); - btwrite_vtc(bt); -/* btwrite_cc_status(bt); */ /* FIXME: CC code needs cleaning */ - btwrite_wc_dn(bt); - btwrite_p_io(bt); -} - -/* - * Public functions - */ -BT829Ptr bt829_Detect(I2CBusPtr b, I2CSlaveAddr addr) -{ - BT829Ptr bt; - I2CByte a; - - bt = xcalloc(1, sizeof(BT829Rec)); - if(bt == NULL) return NULL; - bt->d.DevName = strdup("BT829 video decoder"); - bt->d.SlaveAddr = addr; - bt->d.pI2CBus = b; - bt->d.NextDev = NULL; - bt->d.StartTimeout = b->StartTimeout; - bt->d.BitTimeout = b->BitTimeout; - bt->d.AcknTimeout = b->AcknTimeout; - bt->d.ByteTimeout = b->ByteTimeout; - - - if(!I2C_WriteRead(&(bt->d), NULL, 0, &a, 1)) - { - free(bt); - return NULL; - } - - bt->id = btread(bt,IDCODE); - - free(bt->d.DevName); - bt->d.DevName = xcalloc(200, sizeof(char)); - switch(BTVERSION){ - case BT815: - sprintf(bt->d.DevName, "bt815a video decoder, revision %d",bt->id & 0xf); - break; - case BT817: - sprintf(bt->d.DevName, "bt817a video decoder, revision %d",bt->id & 0xf); - break; - case BT819: - sprintf(bt->d.DevName, "bt819a video decoder, revision %d",bt->id & 0xf); - break; - case BT827: - sprintf(bt->d.DevName, "bt827a/b video decoder, revision %d",bt->id & 0xf); - break; - case BT829: - sprintf(bt->d.DevName, "bt829a/b video decoder, revision %d",bt->id & 0xf); - break; - default: - sprintf(bt->d.DevName, "bt8xx/unknown video decoder version %d, revision %d",bt->id >> 4,bt->id & 0xf); - break; - } - - /* set default parameters */ - if(!I2CDevInit(&(bt->d))) - { - free(bt); - return NULL; - } - - bt->tunertype = 1; - - bt->brightness = 0; /* hardware default */ - bt->ccmode = 0; - bt->code = 0; /* hardware default */ - bt->contrast = 216; /* hardware default */ - bt->format = BT829_NTSC; - bt->height = 480; /* hardware default for vactive */ - bt->hue = 0; /* hardware default */ - bt->len = 1; /* hardware default */ - bt->mux = BT829_MUX0; /* hardware default */ - bt->out_en = 0; /* hardware default */ - bt->p_io = 0; /* hardware default */ - bt->sat_u = 254; /* hardware default */ - bt->sat_v = 180; /* hardware default */ - bt->vbien = 0; /* hardware default */ - bt->vbifmt = 0; /* hardware default */ - bt->width = 640; /* hardware default for hactive */ - - bt->hdelay = 120; /* hardware default */ - bt->hscale = 684; /* hardware default */ - bt->vactive = 480; /* hardware default */ - bt->vdelay = 22; /* hardware default */ - bt->vscale = 0; /* hardware default */ - - bt->htotal = 754; /* NTSC */ - bt->svideo_mux = 0; /* no s-video */ - - return bt; -} - -int bt829_ATIInit(BT829Ptr bt) -{ - bt->code = 1; - bt->len = 0; - bt->vbien = 1; - bt->vbifmt = 1; - bt->svideo_mux = BT829_MUX1; - - write_all (bt); - - return 0; -} - -int bt829_SetFormat(BT829Ptr bt, CARD8 format) -{ - if ((format < 1) || (format > 7)) return -1; - if ((BTVERSION <= BT819) && - (format != BT829_NTSC) && (format != BT829_PAL)) return -1; - if (format == bt->format) return 0; - bt->format = format; - propagate_changes(bt); - btwrite_iform(bt); - btwrite_scloop(bt); - btwrite_adelay(bt); - btwrite_bdelay(bt); - btwrite_vtc(bt); - return 0; -} - -int bt829_SetMux(BT829Ptr bt, CARD8 mux) -{ - if ((mux < 1) || (mux > 3)) return -1; - if (mux == bt->mux) return 0; - bt->mux = mux; - /* propagate_changes(bt); */ /* no dependencies */ - btwrite_iform(bt); - btwrite_control(bt); - btwrite_adc(bt); - return 0; -} - -void bt829_SetBrightness(BT829Ptr bt, int brightness) -{ - brightness = LIMIT(brightness,-1000,999); /* ensure -128 <= brightness <= 127 below */ - brightness = (128*brightness)/1000; - if (brightness == bt->brightness) return; - bt->brightness = brightness; - /* propagate_changes(bt); */ /* no dependencies */ - btwrite_bright(bt); -} - -void bt829_SetContrast(BT829Ptr bt, int contrast) -{ - contrast = LIMIT(contrast,-1000,1000); - contrast = (216*(contrast+1000))/1000; - if (contrast == bt->contrast) return; - bt->contrast = contrast; - /* propagate_changes(bt); */ /* no dependencies */ - btwrite_control(bt); - btwrite_contrast_lo(bt); -} - -void bt829_SetSaturation(BT829Ptr bt, int saturation) -{ - CARD16 sat_u, sat_v; - - saturation = LIMIT(saturation,-1000,1000); - sat_u = (254*(saturation+1000))/1000; - sat_v = (180*(saturation+1000))/1000; - if ((sat_u == bt->sat_u) && (sat_v == bt->sat_v)) return; - bt->sat_u = sat_u; - bt->sat_v = sat_v; - /* propagate_changes(bt); */ /* no dependencies */ - btwrite_control(bt); - btwrite_sat_u_lo(bt); - btwrite_sat_v_lo(bt); -} - -void bt829_SetTint(BT829Ptr bt, int hue) -{ - hue = LIMIT(hue,-1000,999); /* ensure -128 <= hue <= 127 below */ - hue = (128*hue)/1000; - if (hue == bt->hue) return; - bt->hue = hue; - /* propagate_changes(bt); */ /* no dependencies */ - btwrite_hue(bt); -} - -int bt829_SetCaptSize(BT829Ptr bt, int width, int height) -{ - if ((width > bt->htotal - 2 * HCROP) || - (16 * width < bt->htotal - 32 * HCROP)) return -1; - if ((height > bt->vactive) || (16 * height < bt->vactive)) return -1; - if ((width == bt->width) && (height == bt->height)) return 0; - bt->width = width; - bt->height = height; - propagate_changes(bt); - btwrite_crop(bt); - btwrite_hactive_lo(bt); - btwrite_control(bt); - btwrite_vtc(bt); - return 0; -} - -int bt829_SetCC(BT829Ptr bt) /* FIXME: should take ccmode as a parameter */ -{ - if (BTVERSION < BT827) return -1; /* can't do it */ - /* propagate_changes(bt); */ /* no dependencies */ - btwrite_cc_status(bt); - /* we write to STATUS to reset the CCVALID flag */ - if (bt->ccmode != 0) btwrite_status(bt); - return 0; -} - -void bt829_SetOUT_EN(BT829Ptr bt, BOOL out_en) -{ - out_en = (out_en != 0); - if (out_en == bt->out_en) return; - bt->out_en = out_en; - /* propagate_changes(bt); */ /* no dependencies */ - btwrite_vpole(bt); -} - -void bt829_SetP_IO(BT829Ptr bt, CARD8 p_io) -{ - if (p_io == bt->p_io) return; - bt->p_io = p_io; - /* propagate_changes(bt); */ /* no dependencies */ - btwrite_p_io(bt); -} - -#define BTREAD(R) btread(bt,(R)) - -#if 0 - -void bt829_getCCdata(BT829Ptr bt,struct CCdata *data) -{ - CARD8 status; - data->num_valid=0; - /* wait for buffer to be half full (means 8/16 bytes) - * either 4 (one of CC/EDS) or 2 (both CC/EDS) frames */ - if(!(BTREAD(STATUS)&0x04)) return; /* could comment this line */ - for(;data->num_valid<CC_FIFO_SIZE;data->num_valid++) { - status=BTREAD(CC_STATUS); - if(!(status&0x04)) break; - data->data[data->num_valid]= BTREAD(CC_DATA)&0x7f; - /* stripped high bit (parity) */ - data->status[data->num_valid]= (CCS_EDS*((status&0x02)>>1)) | - (CCS_HIGH*(status&0x01)) | - (CCS_OVER*((status&0x08)>>3)) | - (CCS_PAR*((status&0x80)>>7)) ; } - btwrite(bt,STATUS,0x00); /* Reset CCVALID status bit */ - return; -} - -#endif - -/* ------------------------------------------------------------------------ */ -/* Debug and report routines */ - -#define DUMPREG(REG) \ - xf86DrvMsg(bt->d.pI2CBus->scrnIndex,X_INFO," %-12s (0x%02X) = 0x%02X\n", \ - #REG,REG,BTREAD(REG)) - -/*static void bt829_dumpregs(BT829Ptr bt) -{ - DUMPREG(STATUS); - DUMPREG(IFORM); - DUMPREG(TDEC); - DUMPREG(CROP); - DUMPREG(VDELAY_LO); - DUMPREG(VACTIVE_LO); - DUMPREG(HDELAY_LO); - DUMPREG(HACTIVE_LO); - DUMPREG(HSCALE_HI); - DUMPREG(HSCALE_LO); - DUMPREG(BRIGHT); - DUMPREG(CONTROL); - DUMPREG(CONTRAST_LO); - DUMPREG(SAT_U_LO); - DUMPREG(SAT_V_LO); - DUMPREG(HUE); - if (BTVERSION >= BT827) { - DUMPREG(SCLOOP); - DUMPREG(WC_UP) ; } - DUMPREG(OFORM); - DUMPREG(VSCALE_HI); - DUMPREG(VSCALE_LO); - DUMPREG(TEST); - DUMPREG(VPOLE); - DUMPREG(IDCODE); - DUMPREG(ADELAY); - DUMPREG(BDELAY); - DUMPREG(ADC); - if (BTVERSION >= BT827) { - DUMPREG(VTC); - DUMPREG(CC_STATUS); - DUMPREG(CC_DATA); - DUMPREG(WC_DN); - DUMPREG(P_IO) ; } -}*/ +/* TODO: clean up/fix CC code */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xf86i2c.h" +#include "bt829.h" +#include "i2c_def.h" + +/* Changing the following settings (especially VCROP) may */ +/* require modifying code that calls this driver. */ +#define HCROP 0 /* amount to crop from the left and right edges */ +#define VCROP 0 /* amount to crop from the top and bottom edges */ + +#define BTVERSION (bt->id>>4) + +#define H(X) ( ((X)>>8) & 0xFF ) +#define L(X) ( (X) & 0xFF ) + +#define LIMIT(X,A,B) (((X)<(A)) ? (A) : ((X)>(B)) ? (B) : (X) ) + +/* Bt829 family chip ID's */ +#define BT815 0x02 +#define BT817 0x06 +#define BT819 0x07 +#define BT827 0x0C +#define BT829 0x0E + +/* Bt829 registers */ +#define STATUS 0x00 /* Device Status */ +#define IFORM 0x01 /* Input Format */ +#define TDEC 0x02 /* Temporal Decimation */ +#define CROP 0x03 /* MSB Cropping */ +#define VDELAY_LO 0x04 /* Vertical Delay */ +#define VACTIVE_LO 0x05 /* Vertical Active */ +#define HDELAY_LO 0x06 /* Horizontal Delay */ +#define HACTIVE_LO 0x07 /* Horizontal Active */ +#define HSCALE_HI 0x08 /* Horizontal Scaling */ +#define HSCALE_LO 0x09 /* Horizontal Scaling */ +#define BRIGHT 0x0A /* Brightness Control */ +#define CONTROL 0x0B /* Miscellaneous Control */ +#define CONTRAST_LO 0x0C /* Luma Gain (Contrast) */ +#define SAT_U_LO 0x0D /* Chroma (U) Gain (Saturation) */ +#define SAT_V_LO 0x0E /* Chroma (V) Gain (Saturation) */ +#define HUE 0x0F /* Hue Control */ +#define SCLOOP 0x10 /* SC Loop Control */ +#define WC_UP 0x11 /* White Crush Up Count */ +#define OFORM 0x12 /* Output Format */ +#define VSCALE_HI 0x13 /* Vertical Scaling */ +#define VSCALE_LO 0x14 /* Vertical Scaling */ +#define TEST 0x15 /* Test Control */ +#define VPOLE 0x16 /* Video Timing Polarity */ +#define IDCODE 0x17 /* ID Code */ +#define ADELAY 0x18 /* AGC Delay */ +#define BDELAY 0x19 /* Burst Gate Delay */ +#define ADC 0x1A /* ADC Interface */ +#define VTC 0x1B /* Video Timing Control */ +#define CC_STATUS 0x1C /* Extended Data Services/Closed Capt Status */ +#define CC_DATA 0x1D /* Extended Data Services/Closed Capt Data */ +#define WC_DN 0x1E /* White Crush Down Count */ +#define SRESET 0x1F /* Software Reset */ +#define P_IO 0x3F /* Programmable I/O */ + +static CARD8 btread(BT829Ptr bt, CARD8 reg) +{ + CARD8 v; + + I2C_WriteRead(&(bt->d), ®, 1, &v, 1); + + return v; +} + +static void btwrite(BT829Ptr bt, CARD8 reg, CARD8 val) +{ + CARD8 data[2]; + + data[0] = reg; + data[1] = val; + I2C_WriteRead(&(bt->d), data, 2, NULL, 0); +} + +/* + * Register access + */ +static void btwrite_status(BT829Ptr bt) /* STATUS */ +{ + btwrite(bt, STATUS, 0x00); /* clear */ +} + +static void btwrite_iform(BT829Ptr bt) /* IFORM */ +{ + int xtsel; + + switch (bt->format) { + case BT829_NTSC: + case BT829_NTSC_JAPAN: + case BT829_PAL_M: + case BT829_PAL_N_COMB: /* gatos says xtsel = 2 */ + xtsel = 1; + break; + case BT829_PAL: + case BT829_PAL_N: + case BT829_SECAM: + xtsel = 2; + break; + default: /* shouldn't get here */ + xtsel = 3; /* hardware default */ + break; + } + + btwrite(bt, IFORM, (bt->mux<<5) | (xtsel<<3) | bt->format); +} + +static void btwrite_tdec(BT829Ptr bt) /* TDEC */ +{ + /* use default */ +} + +static void btwrite_crop(BT829Ptr bt) /* CROP */ +{ + btwrite(bt, CROP, (H(bt->vdelay)<<6) | (H(bt->vactive)<<4) | + (H(bt->hdelay)<<2) | H(bt->width)); +} + +static void btwrite_vdelay_lo(BT829Ptr bt) /* VDELAY_LO */ +{ + btwrite(bt, VDELAY_LO, L(bt->vdelay)); +} + +static void btwrite_vactive_lo(BT829Ptr bt) /* VACTIVE_LO */ +{ + btwrite(bt, VACTIVE_LO, L(bt->vactive)); +} + +static void btwrite_hdelay_lo(BT829Ptr bt) /* HDELAY_LO */ +{ + btwrite(bt, HDELAY_LO, L(bt->hdelay)); +} + +static void btwrite_hactive_lo(BT829Ptr bt) /* HACTIVE_LO */ +{ + btwrite(bt, HACTIVE_LO, L(bt->width)); +} + +static void btwrite_hscale_hi(BT829Ptr bt) /* HSCALE_HI */ +{ + btwrite(bt, HSCALE_HI, H(bt->hscale)); +} + +static void btwrite_hscale_lo(BT829Ptr bt) /* HSCALE_LO */ +{ + btwrite(bt, HSCALE_LO, L(bt->hscale)); +} + +static void btwrite_bright(BT829Ptr bt) /* BRIGHT */ +{ + btwrite(bt, BRIGHT, bt->brightness); +} + +static void btwrite_control(BT829Ptr bt) /* CONTROL */ +{ + int ldec; + + /* The data sheet says ldec should always be 0 for SECAM */ + /* but the picture quality is better with ldec = 1 */ + ldec = (bt->width > 360); /* gatos says 384 */ + + btwrite(bt, CONTROL, + ((bt->mux==bt->svideo_mux) ? 0xC0:0x00) | /* LNOTCH and COMP */ + (ldec<<5) | (H(bt->contrast)<<2) | (H(bt->sat_u)<<1) | H(bt->sat_v)); +} + +static void btwrite_contrast_lo(BT829Ptr bt) /* CONTRAST_LO */ +{ + btwrite(bt, CONTRAST_LO, L(bt->contrast)); +} + +static void btwrite_sat_u_lo(BT829Ptr bt) /* SAT_U_LO */ +{ + btwrite(bt, SAT_U_LO, L(bt->sat_u)); +} + +static void btwrite_sat_v_lo(BT829Ptr bt) /* SAT_V_LO */ +{ + btwrite(bt, SAT_V_LO, L(bt->sat_v)); +} + +static void btwrite_hue(BT829Ptr bt) /* HUE */ +{ + btwrite(bt, HUE, bt->hue); +} + +static void btwrite_scloop(BT829Ptr bt) /* SCLOOP */ +{ + if (BTVERSION >= BT827) { + btwrite(bt, SCLOOP, + (bt->format==BT829_SECAM) ? 0x10:0x00 /* QCIF or AUTO */ + ); + } +} + +static void btwrite_wc_up(BT829Ptr bt) /* WC_UP */ +{ + if (BTVERSION >= BT827) { + /* use default */ + } +} + +static void btwrite_oform(BT829Ptr bt) /* OFORM */ +{ + btwrite(bt, OFORM, (bt->code<<3) | (bt->len<<2) | + 0x02 /* RANGE = 0, CORE = 0, VBI_FRAME = 0, OES = 2 (default) */ + ); +} + +static void btwrite_vscale_hi(BT829Ptr bt) /* VSCALE_HI */ +{ + btwrite(bt, VSCALE_HI, H(bt->vscale) | + 0x60 /* YCOMB = 0, COMB = 1, INT = 1 (default) */ + ); +} + +static void btwrite_vscale_lo(BT829Ptr bt) /* VSCALE_LO */ +{ + btwrite(bt, VSCALE_LO, L(bt->vscale)); +} + +/* TEST should not be written to */ + +static void btwrite_vpole(BT829Ptr bt) /* VPOLE */ +{ + btwrite(bt, VPOLE, (bt->out_en<<7)); +} + +/* IDCODE is read only */ + +static void btwrite_adelay(BT829Ptr bt) /* ADELAY */ +{ + switch (bt->format) { + case BT829_NTSC: + case BT829_NTSC_JAPAN: + case BT829_PAL_M: + btwrite(bt, ADELAY, 104); + break; + case BT829_PAL: + case BT829_PAL_N: + case BT829_SECAM: + case BT829_PAL_N_COMB: + btwrite(bt, ADELAY, 127); + break; + default: /* shouldn't get here */ + btwrite(bt, ADELAY, 104); /* hardware default */ + break; + } +} + +static void btwrite_bdelay(BT829Ptr bt) /* BDELAY */ +{ + switch (bt->format) { + case BT829_NTSC: + case BT829_NTSC_JAPAN: + case BT829_PAL_M: + btwrite(bt, BDELAY, 93); + break; + case BT829_PAL: + case BT829_PAL_N: + case BT829_PAL_N_COMB: + btwrite(bt, BDELAY, 114); + break; + case BT829_SECAM: + btwrite(bt, BDELAY, 160); + break; + default: /* shouldn't get here */ + btwrite(bt, BDELAY, 93); /* hardware default */ + break; + } +} + +static void btwrite_adc(BT829Ptr bt) /* ADC */ +{ + btwrite(bt, ADC, bt->mux==bt->svideo_mux ? 0x80:0x82); /* CSLEEP = 0 or 1 */ +} + +static void btwrite_vtc(BT829Ptr bt) /* VTC */ +{ + int vfilt = 0; /* hardware default */ + + if (BTVERSION > BT827) { /* gatos says >= BT827 */ + switch (bt->format) { + case BT829_NTSC: + case BT829_NTSC_JAPAN: + case BT829_PAL_M: + case BT829_PAL_N_COMB: /* gatos groups with BT829_PAL */ + if (bt->width <= 360) vfilt = 1; /* gatos says <= 240 */ + if (bt->width <= 180) vfilt = 2; /* gatos says <= 120 */ + if (bt->width <= 90) vfilt = 3; /* gatos says <= 60 */ + break; + case BT829_PAL: + case BT829_PAL_N: + case BT829_SECAM: + if (bt->width <= 384) vfilt = 1; + if (bt->width <= 192) vfilt = 2; + if (bt->width<= 96) vfilt = 3; + break; + default: /* shouldn't get here */ + break; /* use hardware default */ + } + btwrite(bt, VTC, (bt->vbien<<4) | (bt->vbifmt<<3) | vfilt); + } +} + +static void btwrite_cc_status(BT829Ptr bt) /* CC_STATUS */ +{ /* FIXME: ATI specific */ + if (BTVERSION >= BT827) { + if (bt->ccmode == 0) btwrite(bt, CC_STATUS, 0x00); + /* 0x40 is activate to set the CCVALID line. Not required yet */ + else btwrite(bt, CC_STATUS, (bt->ccmode<<4) | 0x40); + } +} + +/* CC_DATA is read only */ + +static void btwrite_wc_dn(BT829Ptr bt) /* WC_DN */ +{ + if (BTVERSION >= BT827) { + /* use default */ + } +} + +static void bt_reset(BT829Ptr bt) { /* SRESET */ + btwrite(bt, SRESET, 0x0); /* Reset all registers */ +} + +static void btwrite_p_io(BT829Ptr bt) /* P_IO */ +{ + if (BTVERSION >= BT827) { + btwrite(bt, P_IO, bt->p_io); + } +} + +/* + * Deal with dependencies + */ +static void propagate_changes(BT829Ptr bt) +{ + CARD16 hdelay, unscaled_hdelay, vdelay, hscale, vscale; + int htotal, vactive; + + switch (bt->format) { + case BT829_NTSC: + case BT829_NTSC_JAPAN: + case BT829_PAL_M: + vdelay = 22; + htotal = 754; + vactive = 480; + unscaled_hdelay = 135; + break; + case BT829_PAL: + case BT829_PAL_N: + vdelay = (bt->tunertype==5) ? 34 : 22; + htotal = 922; + vactive = 576; + unscaled_hdelay = 186; + break; + case BT829_SECAM: + vdelay = 34; + htotal = 922; + vactive = 576; + unscaled_hdelay = 186; + break; + case BT829_PAL_N_COMB: + vdelay = (bt->tunertype==5) ? 34 : 22; /* windows says 22 */ + htotal = 754; /* gatos and windows say 922 */ + vactive = 576; + unscaled_hdelay = 135; /* gatos and windows say 186 */ + break; + default: /* shouldn't get here */ + vdelay = 22; /* hardware default */ + htotal = 754; + vactive = 480; /* hardware default */ + unscaled_hdelay = 135; + break; + } + + bt->htotal = htotal; /* Used for error checking in bt829_SetCaptSize */ + + hscale = 4096 * htotal / (bt->width + 2 * HCROP)-4096; + hdelay = ( + HCROP + (bt->width + 2 * HCROP) * unscaled_hdelay / htotal + ) & 0x3FE; + + vactive = vactive - 2 * VCROP; + vdelay = vdelay + VCROP; + vscale = (0x10000 - (512*vactive/bt->height-512)) & 0x1FFF; + + if ((hdelay != bt->hdelay) || (vdelay != bt->vdelay) || + (vactive != bt->vactive) || (hscale != bt->hscale) || + (vscale != bt->vscale)) { + bt->hdelay = hdelay; + bt->vdelay = vdelay; + bt->vactive = vactive; + bt->hscale = hscale; + bt->vscale = vscale; + btwrite_crop(bt); + btwrite_vdelay_lo(bt); + btwrite_vactive_lo(bt); + btwrite_hdelay_lo(bt); + btwrite_hscale_hi(bt); + btwrite_hscale_lo(bt); + btwrite_control(bt); + btwrite_vscale_hi(bt); + btwrite_vscale_lo(bt); + } +} + +static void write_all(BT829Ptr bt) +{ + bt_reset(bt); + propagate_changes(bt); /* ensure consistency */ + btwrite_iform(bt); + btwrite_tdec(bt); + btwrite_crop(bt); + btwrite_vdelay_lo(bt); + btwrite_vactive_lo(bt); + btwrite_hdelay_lo(bt); + btwrite_hactive_lo(bt); + btwrite_hscale_hi(bt); + btwrite_hscale_lo(bt); + btwrite_bright(bt); + btwrite_control(bt); + btwrite_contrast_lo(bt); + btwrite_sat_u_lo(bt); + btwrite_sat_v_lo(bt); + btwrite_hue(bt); + btwrite_scloop(bt); + btwrite_wc_up(bt); + btwrite_oform(bt); + btwrite_vscale_hi(bt); + btwrite_vscale_lo(bt); + btwrite_vpole(bt); + btwrite_adelay(bt); + btwrite_bdelay(bt); + btwrite_adc(bt); + btwrite_vtc(bt); +/* btwrite_cc_status(bt); */ /* FIXME: CC code needs cleaning */ + btwrite_wc_dn(bt); + btwrite_p_io(bt); +} + +/* + * Public functions + */ +BT829Ptr bt829_Detect(I2CBusPtr b, I2CSlaveAddr addr) +{ + BT829Ptr bt; + I2CByte a; + + bt = calloc(1, sizeof(BT829Rec)); + if(bt == NULL) return NULL; + bt->d.DevName = strdup("BT829 video decoder"); + bt->d.SlaveAddr = addr; + bt->d.pI2CBus = b; + bt->d.NextDev = NULL; + bt->d.StartTimeout = b->StartTimeout; + bt->d.BitTimeout = b->BitTimeout; + bt->d.AcknTimeout = b->AcknTimeout; + bt->d.ByteTimeout = b->ByteTimeout; + + + if(!I2C_WriteRead(&(bt->d), NULL, 0, &a, 1)) + { + free(bt); + return NULL; + } + + bt->id = btread(bt,IDCODE); + + free(bt->d.DevName); + bt->d.DevName = calloc(200, sizeof(char)); + switch(BTVERSION){ + case BT815: + sprintf(bt->d.DevName, "bt815a video decoder, revision %d",bt->id & 0xf); + break; + case BT817: + sprintf(bt->d.DevName, "bt817a video decoder, revision %d",bt->id & 0xf); + break; + case BT819: + sprintf(bt->d.DevName, "bt819a video decoder, revision %d",bt->id & 0xf); + break; + case BT827: + sprintf(bt->d.DevName, "bt827a/b video decoder, revision %d",bt->id & 0xf); + break; + case BT829: + sprintf(bt->d.DevName, "bt829a/b video decoder, revision %d",bt->id & 0xf); + break; + default: + sprintf(bt->d.DevName, "bt8xx/unknown video decoder version %d, revision %d",bt->id >> 4,bt->id & 0xf); + break; + } + + /* set default parameters */ + if(!I2CDevInit(&(bt->d))) + { + free(bt); + return NULL; + } + + bt->tunertype = 1; + + bt->brightness = 0; /* hardware default */ + bt->ccmode = 0; + bt->code = 0; /* hardware default */ + bt->contrast = 216; /* hardware default */ + bt->format = BT829_NTSC; + bt->height = 480; /* hardware default for vactive */ + bt->hue = 0; /* hardware default */ + bt->len = 1; /* hardware default */ + bt->mux = BT829_MUX0; /* hardware default */ + bt->out_en = 0; /* hardware default */ + bt->p_io = 0; /* hardware default */ + bt->sat_u = 254; /* hardware default */ + bt->sat_v = 180; /* hardware default */ + bt->vbien = 0; /* hardware default */ + bt->vbifmt = 0; /* hardware default */ + bt->width = 640; /* hardware default for hactive */ + + bt->hdelay = 120; /* hardware default */ + bt->hscale = 684; /* hardware default */ + bt->vactive = 480; /* hardware default */ + bt->vdelay = 22; /* hardware default */ + bt->vscale = 0; /* hardware default */ + + bt->htotal = 754; /* NTSC */ + bt->svideo_mux = 0; /* no s-video */ + + return bt; +} + +int bt829_ATIInit(BT829Ptr bt) +{ + bt->code = 1; + bt->len = 0; + bt->vbien = 1; + bt->vbifmt = 1; + bt->svideo_mux = BT829_MUX1; + + write_all (bt); + + return 0; +} + +int bt829_SetFormat(BT829Ptr bt, CARD8 format) +{ + if ((format < 1) || (format > 7)) return -1; + if ((BTVERSION <= BT819) && + (format != BT829_NTSC) && (format != BT829_PAL)) return -1; + if (format == bt->format) return 0; + bt->format = format; + propagate_changes(bt); + btwrite_iform(bt); + btwrite_scloop(bt); + btwrite_adelay(bt); + btwrite_bdelay(bt); + btwrite_vtc(bt); + return 0; +} + +int bt829_SetMux(BT829Ptr bt, CARD8 mux) +{ + if ((mux < 1) || (mux > 3)) return -1; + if (mux == bt->mux) return 0; + bt->mux = mux; + /* propagate_changes(bt); */ /* no dependencies */ + btwrite_iform(bt); + btwrite_control(bt); + btwrite_adc(bt); + return 0; +} + +void bt829_SetBrightness(BT829Ptr bt, int brightness) +{ + brightness = LIMIT(brightness,-1000,999); /* ensure -128 <= brightness <= 127 below */ + brightness = (128*brightness)/1000; + if (brightness == bt->brightness) return; + bt->brightness = brightness; + /* propagate_changes(bt); */ /* no dependencies */ + btwrite_bright(bt); +} + +void bt829_SetContrast(BT829Ptr bt, int contrast) +{ + contrast = LIMIT(contrast,-1000,1000); + contrast = (216*(contrast+1000))/1000; + if (contrast == bt->contrast) return; + bt->contrast = contrast; + /* propagate_changes(bt); */ /* no dependencies */ + btwrite_control(bt); + btwrite_contrast_lo(bt); +} + +void bt829_SetSaturation(BT829Ptr bt, int saturation) +{ + CARD16 sat_u, sat_v; + + saturation = LIMIT(saturation,-1000,1000); + sat_u = (254*(saturation+1000))/1000; + sat_v = (180*(saturation+1000))/1000; + if ((sat_u == bt->sat_u) && (sat_v == bt->sat_v)) return; + bt->sat_u = sat_u; + bt->sat_v = sat_v; + /* propagate_changes(bt); */ /* no dependencies */ + btwrite_control(bt); + btwrite_sat_u_lo(bt); + btwrite_sat_v_lo(bt); +} + +void bt829_SetTint(BT829Ptr bt, int hue) +{ + hue = LIMIT(hue,-1000,999); /* ensure -128 <= hue <= 127 below */ + hue = (128*hue)/1000; + if (hue == bt->hue) return; + bt->hue = hue; + /* propagate_changes(bt); */ /* no dependencies */ + btwrite_hue(bt); +} + +int bt829_SetCaptSize(BT829Ptr bt, int width, int height) +{ + if ((width > bt->htotal - 2 * HCROP) || + (16 * width < bt->htotal - 32 * HCROP)) return -1; + if ((height > bt->vactive) || (16 * height < bt->vactive)) return -1; + if ((width == bt->width) && (height == bt->height)) return 0; + bt->width = width; + bt->height = height; + propagate_changes(bt); + btwrite_crop(bt); + btwrite_hactive_lo(bt); + btwrite_control(bt); + btwrite_vtc(bt); + return 0; +} + +int bt829_SetCC(BT829Ptr bt) /* FIXME: should take ccmode as a parameter */ +{ + if (BTVERSION < BT827) return -1; /* can't do it */ + /* propagate_changes(bt); */ /* no dependencies */ + btwrite_cc_status(bt); + /* we write to STATUS to reset the CCVALID flag */ + if (bt->ccmode != 0) btwrite_status(bt); + return 0; +} + +void bt829_SetOUT_EN(BT829Ptr bt, BOOL out_en) +{ + out_en = (out_en != 0); + if (out_en == bt->out_en) return; + bt->out_en = out_en; + /* propagate_changes(bt); */ /* no dependencies */ + btwrite_vpole(bt); +} + +void bt829_SetP_IO(BT829Ptr bt, CARD8 p_io) +{ + if (p_io == bt->p_io) return; + bt->p_io = p_io; + /* propagate_changes(bt); */ /* no dependencies */ + btwrite_p_io(bt); +} + +#define BTREAD(R) btread(bt,(R)) + +#if 0 + +void bt829_getCCdata(BT829Ptr bt,struct CCdata *data) +{ + CARD8 status; + data->num_valid=0; + /* wait for buffer to be half full (means 8/16 bytes) + * either 4 (one of CC/EDS) or 2 (both CC/EDS) frames */ + if(!(BTREAD(STATUS)&0x04)) return; /* could comment this line */ + for(;data->num_valid<CC_FIFO_SIZE;data->num_valid++) { + status=BTREAD(CC_STATUS); + if(!(status&0x04)) break; + data->data[data->num_valid]= BTREAD(CC_DATA)&0x7f; + /* stripped high bit (parity) */ + data->status[data->num_valid]= (CCS_EDS*((status&0x02)>>1)) | + (CCS_HIGH*(status&0x01)) | + (CCS_OVER*((status&0x08)>>3)) | + (CCS_PAR*((status&0x80)>>7)) ; } + btwrite(bt,STATUS,0x00); /* Reset CCVALID status bit */ + return; +} + +#endif + +/* ------------------------------------------------------------------------ */ +/* Debug and report routines */ + +#define DUMPREG(REG) \ + xf86DrvMsg(bt->d.pI2CBus->scrnIndex,X_INFO," %-12s (0x%02X) = 0x%02X\n", \ + #REG,REG,BTREAD(REG)) + +/*static void bt829_dumpregs(BT829Ptr bt) +{ + DUMPREG(STATUS); + DUMPREG(IFORM); + DUMPREG(TDEC); + DUMPREG(CROP); + DUMPREG(VDELAY_LO); + DUMPREG(VACTIVE_LO); + DUMPREG(HDELAY_LO); + DUMPREG(HACTIVE_LO); + DUMPREG(HSCALE_HI); + DUMPREG(HSCALE_LO); + DUMPREG(BRIGHT); + DUMPREG(CONTROL); + DUMPREG(CONTRAST_LO); + DUMPREG(SAT_U_LO); + DUMPREG(SAT_V_LO); + DUMPREG(HUE); + if (BTVERSION >= BT827) { + DUMPREG(SCLOOP); + DUMPREG(WC_UP) ; } + DUMPREG(OFORM); + DUMPREG(VSCALE_HI); + DUMPREG(VSCALE_LO); + DUMPREG(TEST); + DUMPREG(VPOLE); + DUMPREG(IDCODE); + DUMPREG(ADELAY); + DUMPREG(BDELAY); + DUMPREG(ADC); + if (BTVERSION >= BT827) { + DUMPREG(VTC); + DUMPREG(CC_STATUS); + DUMPREG(CC_DATA); + DUMPREG(WC_DN); + DUMPREG(P_IO) ; } +}*/ diff --git a/xorg-server/hw/xfree86/i2c/fi1236.c b/xorg-server/hw/xfree86/i2c/fi1236.c index 61224eaa5..531b64aed 100644 --- a/xorg-server/hw/xfree86/i2c/fi1236.c +++ b/xorg-server/hw/xfree86/i2c/fi1236.c @@ -1,605 +1,605 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "xf86.h" -#include "xf86i2c.h" -#include "fi1236.h" -#include "tda9885.h" -#include "i2c_def.h" - -#define NUM_TUNERS 8 - -const FI1236_parameters tuner_parms[NUM_TUNERS] = -{ - /* 0 - FI1236 */ - { 733 ,884 ,12820 ,2516 ,7220 ,0xA2 ,0x94, 0x34, 0x8e }, - /* !!!based on documentation - it should be: - {733 ,16*55.25 ,16*801.25 ,16*160 ,16*454 ,0xA0 ,0x90, 0x30, 0x8e},*/ - - /* 1 - FI1216 */ - { 623 ,16*48.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e }, - /* 2 - TEMIC FN5AL */ - { 623 ,16*45.75 ,16*855.25 ,16*169 ,16*454 ,0xA0 ,0x90, 0x30, 0x8e }, - /* 3 - MT2032.. */ - { 733 ,768 ,13760 , 0 , 0 , 0 , 0, 0, 0 }, - /* 4 - FI1246 */ - { 623 ,16*45.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e }, - /* 5 - FI1256 */ - { 623 ,16*49.75 ,16*863.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e }, - /* 6 - FI1236W */ - /*{ 733 ,884 ,12820 ,2516 ,7220 ,0x1 ,0x2, 0x4, 0x8e },*/ - { 732, 16*55.25, 16*801.25, 16*160, 16*442, 0x1, 0x2, 0x4, 0x8e }, - /* 7 - FM1216ME */ - { 623 ,16*48.25 ,16*863.25 ,16*158.00 ,16*442.00 ,0x1 ,0x2, 0x4, 0x8e } -}; - - -FI1236Ptr Detect_FI1236(I2CBusPtr b, I2CSlaveAddr addr) -{ - FI1236Ptr f; - I2CByte a; - - f = xcalloc(1,sizeof(FI1236Rec)); - if(f == NULL) return NULL; - f->d.DevName = strdup("FI12xx Tuner"); - f->d.SlaveAddr = addr; - f->d.pI2CBus = b; - f->d.NextDev = NULL; - f->d.StartTimeout = b->StartTimeout; - f->d.BitTimeout = b->BitTimeout; - f->d.AcknTimeout = b->AcknTimeout; - f->d.ByteTimeout = b->ByteTimeout; - f->type=TUNER_TYPE_FI1236; - f->afc_timer_installed=FALSE; - f->last_afc_hint=TUNER_OFF; - f->video_if=45.7812; - - if(!I2C_WriteRead(&(f->d), NULL, 0, &a, 1)) - { - free(f); - return NULL; - } - FI1236_set_tuner_type(f, TUNER_TYPE_FI1236); - if(!I2CDevInit(&(f->d))) - { - free(f); - return NULL; - } - return f; -} - -static void MT2032_dump_parameters(FI1236Ptr f, MT2032_parameters *m) -{ -xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: input f_rf=%g f_if1=%g f_if2=%g f_ref=%g f_ifbw=%g f_step=%g\n", - m->f_rf, m->f_if1, m->f_if2, m->f_ref, m->f_ifbw, m->f_step); - -xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: computed f_lo1=%g f_lo2=%g LO1I=%d LO2I=%d SEL=%d STEP=%d NUM=%d\n", - m->f_lo1, m->f_lo2, m->LO1I, m->LO2I, m->SEL, m->STEP, m->NUM); -} - - -static void MT2032_getid(FI1236Ptr f) -{ -CARD8 out[4]; -CARD8 in; - -in=0x11; -I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 4); -xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: Company code 0x%02x%02x, part code 0x%02x, revision code 0x%02x\n", - out[0], out[1], out[2], out[3]); - -} - -/* might be buggy */ -#if 0 -static void MT2032_shutdown(FI1236Ptr f) -{ -CARD8 data[10]; - -data[0]=0x00; /* start with register 0x00 */ -data[1]=0x1A; -data[2]=0x44; -data[3]=0x20; - -I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); - -data[0]=0x05; /* now start with register 0x05 */ -data[1]=0xD7; -data[2]=0x14; -data[3]=0x05; -I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); - -data[0]=0x0B; /* now start with register 0x05 */ -data[1]=0x8F; -data[2]=0x07; -data[3]=0x43; -I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); - -usleep(15000); -} -#endif - -static void MT2032_dump_status(FI1236Ptr f); - -static void MT2032_init(FI1236Ptr f) -{ -CARD8 data[10]; -CARD8 value; -CARD8 xogc = 0x00; - -MT2032_getid(f); - -data[0]=0x02; /* start with register 0x02 */ -data[1]=0xFF; -data[2]=0x0F; -data[3]=0x1F; - -I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); - -data[0]=0x06; /* now start with register 0x06 */ -data[1]=0xE4; -data[2]=0x8F; -data[3]=0xC3; -data[4]=0x4E; -data[5]=0xEC; -I2C_WriteRead(&(f->d), (I2CByte *)data, 6, NULL, 0); - -data[0]=0x0d; /* now start with register 0x0d */ -data[1]=0x32; -I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); - -while(1) { - usleep(15000); /* wait 15 milliseconds */ - - data[0]=0x0e; /* register number 7, status */ - value=0xFF; - if(!I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1)) - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to read XOK\n"); - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: XOK=%d\n", value & 0x01); - if(value & 1) break; - - data[0]=0x07; - if(!I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1)) - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to read XOGC\n"); - - xogc=value & 0x7; - if(xogc==4){ - break; /* XOGC has reached 4.. stop */ - } - xogc--; - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: try XOGC=%d\n", xogc); - usleep(15000); - data[0]=0x07; /* register number 7, control byte 2 */ - data[1]=0x08 | xogc; - I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); - } -f->xogc=xogc; -/* wait before continuing */ -usleep(15000); /* wait 50 milliseconds */ -MT2032_dump_status(f); -} - -static int MT2032_no_spur_in_band(MT2032_parameters *m) -{ -int n_max, n1, n2; -double f_test; -n_max=5; -n1=1; -while(1){ - n2=-n1; - f_test=n1*(m->f_lo1-m->f_lo2); - while(1){ - n2--; - f_test=f_test-m->f_lo2; - xf86DrvMsg(0, X_INFO, "testing f_test=%g n1=%d n2=%d f_lo1=%g f_lo2=%g f_if2=%g\n", f_test, n1, n2, m->f_lo1, m->f_lo2, m->f_if2); - xf86DrvMsg(0, X_INFO, "d_f=%g f_ifbw=%g\n",fabs(fabs(f_test)-m->f_if2), m->f_ifbw); - if((fabs(fabs(f_test)-m->f_if2)*2.0)<=m->f_ifbw)return 0; - if(n2<=-n_max)break; - /* this line in the manual is bogus. I say it is faster - and more correct to go over all harmonics.. */ - #if 0 - if(f_test<(m->f_lo2-m->f_if2-m->f_ifbw))break; - #endif - } - n1++; - if(n1>=n_max)return 1; - } - -} - -static void MT2032_calculate_register_settings(MT2032_parameters *m, double f_rf, double f_if1, double f_if2, double f_ref, double f_ifbw, double f_step) -{ -int n; -m->f_rf=f_rf; -m->f_if1=f_if1; -m->f_if2=f_if2; -m->f_ref=f_ref; -m->f_ifbw=f_ifbw; -m->f_step=f_step; - -m->f_lo1=f_rf+f_if1; -m->LO1I=lrint(m->f_lo1/f_ref); -m->f_lo1=f_ref*m->LO1I; - -m->f_lo2=m->f_lo1-f_rf-f_if2; - -/* check for spurs */ -n=1; -while(n<3){ - if(MT2032_no_spur_in_band(m))break; - if(m->f_lo1<(f_rf+f_if1)){ - m->LO1I+=n; - } else { - m->LO1I-=n; - } - m->f_lo1=m->LO1I*f_ref; - m->f_lo2=m->f_lo1-f_rf-f_if2; - n++; - } -/* xf86DrvMsg(0, X_INFO, "MT2032: n=%d\n", n); */ -/* select VCO */ - -/* m->f_lo1>1100.0 */ -if(m->f_lo1<1370.0)m->SEL=4; - else -if(m->f_lo1<1530.0)m->SEL=3; - else -if(m->f_lo1<1720.0)m->SEL=2; - else -if(m->f_lo1<1890.0)m->SEL=1; - else /* m->f_lo1 < 1958.0 */ - m->SEL=0; - -/* calculate the rest of the registers */ -m->LO2I=floor(m->f_lo2/f_ref); -m->STEP=floor(3780.0*f_step/f_ref); -m->NUM=floor(3780.0*(m->f_lo2/f_ref-m->LO2I)); -m->NUM=m->STEP*lrint((1.0*m->NUM)/(1.0*m->STEP)); -} - -static int MT2032_wait_for_lock(FI1236Ptr f) -{ -int n; -CARD8 data[10]; -CARD8 value; - -n=12; -while(1){ - data[0]=0x0e; /* register number 7, status */ - I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1); -/* xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: LO1LK=%d LO2LK=%d\n", (value & 0x04)>>2, (value & 0x02)>>1); */ - if((value & 6)==6) break; - usleep(1500); - n--; - if(n<0)break; - } -if(n<0){ - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to set frequency\n"); - return 0; - } -return 1; -} - -static void MT2032_implement_settings(FI1236Ptr f, MT2032_parameters *m) -{ -CARD8 data[10]; -CARD8 value; - -data[0]=0x00; /* start with register 0x00 */ -data[1]=(m->LO1I>>3)-1; -data[2]=(m->SEL<<4)|(m->LO1I & 0x7); -data[3]=0x86; -I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); - -data[0]=0x05; /* start with register 0x05 */ -data[1]=((m->LO2I & 0x7)<<5)|((m->LO2I>>3)-1); -if(m->f_rf<400.0)data[2]=0xe4; - else data[2]=0xf4; -I2C_WriteRead(&(f->d), (I2CByte *)data, 3, NULL, 0); - -data[0]=0x07; /* register number 7, control byte 2 */ -I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1); -xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: using XOGC=%d\n", (value & 0x07)); -data[1]=8 | (value & 0x7); -I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); - -data[0]=0x0b; /* start with register 0x0b */ -data[1]=m->NUM & 0xff; -data[2]=(1<<7)|((m->NUM >> 8) & 0x0f); -I2C_WriteRead(&(f->d), (I2CByte *)data, 3, NULL, 0); - -MT2032_wait_for_lock(f); -} - -static void MT2032_optimize_VCO(FI1236Ptr f, MT2032_parameters *m) -{ -CARD8 data[10]; -CARD8 value; -CARD8 TAD1; - -data[0]=0x0f; /* register number 7, status */ -I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1); -TAD1=value & 0x07; -xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: TAD1=%d SEL=%d\n", TAD1, m->SEL); -if(TAD1 < 2)return; -if(TAD1==2){ - if(m->SEL==0)return; - m->SEL--; - } else { - if(m->SEL>=4)return; - m->SEL++; - } -data[0]=0x01; /* start with register 1 */ -data[1]=(m->SEL<<4)|(m->LO1I & 0x7); -I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); - -} - -static int FI1236_get_afc_hint(FI1236Ptr f) -{ - CARD8 out; - CARD8 AFC; - - if ((f->type == TUNER_TYPE_FM1216ME) || (f->type == TUNER_TYPE_FI1236W)) - { - TDA9885Ptr t = (TDA9885Ptr)f->afc_source; - if (t == NULL) - return TUNER_OFF; - - tda9885_getstatus(t); - tda9885_dumpstatus(t); - AFC = t->afc_status & 0x0f; - - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: FI1236_get_afc_hint: %i\n", AFC); - if (AFC == 0) return TUNER_TUNED; - else if (AFC <= 0x07)return TUNER_JUST_BELOW; - else if (AFC < 0x0f )return TUNER_JUST_ABOVE; - else if (AFC == 0x0f)return TUNER_TUNED; - } - else - { - I2C_WriteRead(&(f->d), NULL, 0, &out, 1); - AFC=out & 0x7; - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: FI1236_get_afc_hint: %i\n", AFC); - if(AFC==2)return TUNER_TUNED; - if(AFC==3)return TUNER_JUST_BELOW; - if(AFC==1)return TUNER_JUST_ABOVE; - return TUNER_OFF; - } - return TUNER_OFF; -} - -static int MT2032_get_afc_hint(FI1236Ptr f) -{ -CARD8 in; -CARD8 out[2]; -CARD8 AFC; -in=0x0e; -I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 2); -AFC=(out[0]>>4) & 0x7; -#if 0 -xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC=%d TAD1=%d TAD2=%d\n", AFC, out[1] & 0x7, (out[1]>>4)& 0x07); -#endif -if(AFC==2)return TUNER_TUNED; -if(AFC==3)return TUNER_JUST_BELOW; -if(AFC==1)return TUNER_JUST_ABOVE; -return TUNER_OFF; -} - -/* this function is for external use only */ -int TUNER_get_afc_hint(FI1236Ptr f) -{ -if(f->afc_timer_installed)return TUNER_STILL_TUNING; -return f->last_afc_hint; -} - -static void MT2032_dump_status(FI1236Ptr f) -{ -CARD8 in; -CARD8 out[2]; -CARD8 AFC; -CARD8 LDONrb; -CARD8 LO1LK, LO2LK, XOK; -CARD8 TAD2, TAD1; - -in=0x0e; -I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 2); -XOK=out[0] & 1; -LO1LK=(out[0]>>2) &1; -LO2LK=(out[0]>>1) &1; -LDONrb=(out[0]>>3) &1; - -AFC=(out[0]>>4) & 0x7; - -TAD1=(out[1] & 0x7); -TAD2=(out[1]>>4) & 0x7; - -xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: status: XOK=%d LO1LK=%d LO2LK=%d LDONrb=%d AFC=%d TAD1=%d TAD2=%d\n", - XOK, LO1LK, LO2LK, LDONrb, AFC, TAD1, TAD2); -xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: status: OSCILLATOR:%s PLL1:%s PLL2:%s\n", - XOK ? "ok":"off", LO1LK ? "locked" : "off" , LO2LK ? "locked" : "off"); - -} - -static void MT2032_tune(FI1236Ptr f, double freq, double step) -{ -MT2032_parameters m; -CARD8 data[10]; -int i; -/* NTSC IF is 44mhz.. but 733/16=45.8125 and all TDAXXXX docs mention - 45.75, 39, 58.75 and 30. */ -#if 0 -MT2032_calculate_register_settings(&m, freq, 1090.0, 45.125, 5.25, 6.0, step); -MT2032_calculate_register_settings(&m, freq, 1090.0, 45.74, 5.25, 6.0, step); -#endif -MT2032_calculate_register_settings(&m, freq, 1090.0, f->video_if, 5.25, 3.0, step); -MT2032_dump_parameters(f, &m); -MT2032_implement_settings(f, &m); -/* MT2032_dump_parameters(f, &m); */ -for(i=0;i<3;i++){ - MT2032_optimize_VCO(f, &m); - if(MT2032_wait_for_lock(f)){ - data[0]=0x02; /* LO Gain control register 0x02 */ - data[1]=0x20; - I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); - return; - } - data[0]=0x07; - data[1]=0x88|f->xogc; - I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); - usleep(15000); - data[1]=0x08|f->xogc; - I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); - } -xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to set frequency\n"); -} - -void FI1236_set_tuner_type(FI1236Ptr f, int type) -{ -f->type=type; -if(type>=NUM_TUNERS)type = NUM_TUNERS-1; -if(type<0)type = 0; -memcpy(&(f->parm), &(tuner_parms[type]), sizeof(FI1236_parameters)); -f->original_frequency=f->parm.min_freq; -f->afc_delta=0; -if(type==TUNER_TYPE_MT2032){ - MT2032_init(f); - return; - } -} - - -static CARD32 AFC_TimerCallback(OsTimerPtr timer, CARD32 time, pointer data){ -FI1236Ptr f=(FI1236Ptr)data; -if(FI1236_AFC(f))return 150; - else { - f->afc_timer_installed=FALSE; - f->afc_count=0; - return 0; - } -} - -void FI1236_tune(FI1236Ptr f, CARD32 frequency) -{ - CARD16 divider; - CARD8 data; - - if(frequency < f->parm.min_freq) frequency = f->parm.min_freq; - if(frequency > f->parm.max_freq) frequency = f->parm.max_freq; - - divider = (f->parm.fcar+(CARD16)frequency) & 0x7fff; - f->tuner_data.div1 = (CARD8)((divider>>8)&0x7f); - f->tuner_data.div2 = (CARD8)(divider & 0xff); - f->tuner_data.control = f->parm.control; - - if(frequency < f->parm.threshold1) - { - f->tuner_data.band = f->parm.band_low; - } - else if (frequency < f->parm.threshold2) - { - f->tuner_data.band = f->parm.band_mid; - } - else - { - f->tuner_data.band = f->parm.band_high; - } - - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Setting tuner band to %d\n", f->tuner_data.band); - - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Setting tuner frequency to %d\n", (int)frequency); - - if ((f->type == TUNER_TYPE_FM1216ME) || (f->type == TUNER_TYPE_FI1236W)) - { - f->tuner_data.aux = 0x20; - I2C_WriteRead(&(f->d), (I2CByte *)&(f->tuner_data), 5, NULL, 0); - I2C_WriteRead(&(f->d), NULL, 0, &data, 1); - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Tuner status %x\n", data); - - } - else - I2C_WriteRead(&(f->d), (I2CByte *)&(f->tuner_data), 4, NULL, 0); -} - -void TUNER_set_frequency(FI1236Ptr f, CARD32 frequency) -{ - if(frequency < f->parm.min_freq) frequency = f->parm.min_freq; - if(frequency > f->parm.max_freq) frequency = f->parm.max_freq; - - f->afc_delta=0; - f->original_frequency=frequency; - - if(f->type==TUNER_TYPE_MT2032) - { - MT2032_tune(f, (1.0*frequency)/16.0, 0.0625); - } else - { - FI1236_tune(f, frequency); - } - - if(!f->afc_timer_installed) - { - f->afc_timer_installed=TRUE; -/* RegisterBlockAndWakeupHandlers(FI1236_BlockHandler, AFCWakeup, f); */ - TimerSet(NULL, 0, 300, AFC_TimerCallback, f); - } - -} - - -int FI1236_AFC(FI1236Ptr f) -{ - #if 0 - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: f=%p f->count=%d f->original_frequency=%d f->afc_delta=%d\n", f, f->afc_count, f->original_frequency, f->afc_delta); - #endif - f->afc_count++; - if(f->type==TUNER_TYPE_MT2032) - { - f->last_afc_hint=MT2032_get_afc_hint(f); - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: afc_hint=%d\n", f->last_afc_hint); - if(f->last_afc_hint==TUNER_TUNED)return 0; - if(f->afc_count>3)f->last_afc_hint=TUNER_OFF; - if(f->last_afc_hint==TUNER_OFF) - { - f->afc_delta=0; - } else - f->afc_delta+=f->last_afc_hint; - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: Setting tuner frequency to %g\n", (0.5*(2*f->original_frequency+f->afc_delta))/16.0); - MT2032_tune(f, (1.0*f->original_frequency+0.5*f->afc_delta)/16.0, 0.03125); - if(f->last_afc_hint==TUNER_OFF)return 0; - return 1; /* call me again */ - } else - { - f->last_afc_hint=FI1236_get_afc_hint(f); - if(f->last_afc_hint==TUNER_TUNED) - { - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: TUNER_TUNNED\n"); - return 0; - } - if(f->afc_count>3)f->last_afc_hint=TUNER_OFF; - if(f->last_afc_hint==TUNER_OFF) - { - f->afc_delta=0; - } else - f->afc_delta+=f->last_afc_hint; - xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: Setting tuner frequency to %g\n", (0.5*(2*f->original_frequency+f->afc_delta))/16.0); - FI1236_tune(f, f->original_frequency+f->afc_delta); - if(f->last_afc_hint==TUNER_OFF)return 0; - return 1; /* call me again */ - } - return 0; /* done */ -} - -void fi1236_dump_status(FI1236Ptr f) -{ -if(f->type==TUNER_TYPE_MT2032){ - MT2032_dump_status(f); - } -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "xf86.h" +#include "xf86i2c.h" +#include "fi1236.h" +#include "tda9885.h" +#include "i2c_def.h" + +#define NUM_TUNERS 8 + +const FI1236_parameters tuner_parms[NUM_TUNERS] = +{ + /* 0 - FI1236 */ + { 733 ,884 ,12820 ,2516 ,7220 ,0xA2 ,0x94, 0x34, 0x8e }, + /* !!!based on documentation - it should be: + {733 ,16*55.25 ,16*801.25 ,16*160 ,16*454 ,0xA0 ,0x90, 0x30, 0x8e},*/ + + /* 1 - FI1216 */ + { 623 ,16*48.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e }, + /* 2 - TEMIC FN5AL */ + { 623 ,16*45.75 ,16*855.25 ,16*169 ,16*454 ,0xA0 ,0x90, 0x30, 0x8e }, + /* 3 - MT2032.. */ + { 733 ,768 ,13760 , 0 , 0 , 0 , 0, 0, 0 }, + /* 4 - FI1246 */ + { 623 ,16*45.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e }, + /* 5 - FI1256 */ + { 623 ,16*49.75 ,16*863.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e }, + /* 6 - FI1236W */ + /*{ 733 ,884 ,12820 ,2516 ,7220 ,0x1 ,0x2, 0x4, 0x8e },*/ + { 732, 16*55.25, 16*801.25, 16*160, 16*442, 0x1, 0x2, 0x4, 0x8e }, + /* 7 - FM1216ME */ + { 623 ,16*48.25 ,16*863.25 ,16*158.00 ,16*442.00 ,0x1 ,0x2, 0x4, 0x8e } +}; + + +FI1236Ptr Detect_FI1236(I2CBusPtr b, I2CSlaveAddr addr) +{ + FI1236Ptr f; + I2CByte a; + + f = calloc(1,sizeof(FI1236Rec)); + if(f == NULL) return NULL; + f->d.DevName = strdup("FI12xx Tuner"); + f->d.SlaveAddr = addr; + f->d.pI2CBus = b; + f->d.NextDev = NULL; + f->d.StartTimeout = b->StartTimeout; + f->d.BitTimeout = b->BitTimeout; + f->d.AcknTimeout = b->AcknTimeout; + f->d.ByteTimeout = b->ByteTimeout; + f->type=TUNER_TYPE_FI1236; + f->afc_timer_installed=FALSE; + f->last_afc_hint=TUNER_OFF; + f->video_if=45.7812; + + if(!I2C_WriteRead(&(f->d), NULL, 0, &a, 1)) + { + free(f); + return NULL; + } + FI1236_set_tuner_type(f, TUNER_TYPE_FI1236); + if(!I2CDevInit(&(f->d))) + { + free(f); + return NULL; + } + return f; +} + +static void MT2032_dump_parameters(FI1236Ptr f, MT2032_parameters *m) +{ +xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: input f_rf=%g f_if1=%g f_if2=%g f_ref=%g f_ifbw=%g f_step=%g\n", + m->f_rf, m->f_if1, m->f_if2, m->f_ref, m->f_ifbw, m->f_step); + +xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: computed f_lo1=%g f_lo2=%g LO1I=%d LO2I=%d SEL=%d STEP=%d NUM=%d\n", + m->f_lo1, m->f_lo2, m->LO1I, m->LO2I, m->SEL, m->STEP, m->NUM); +} + + +static void MT2032_getid(FI1236Ptr f) +{ +CARD8 out[4]; +CARD8 in; + +in=0x11; +I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 4); +xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: Company code 0x%02x%02x, part code 0x%02x, revision code 0x%02x\n", + out[0], out[1], out[2], out[3]); + +} + +/* might be buggy */ +#if 0 +static void MT2032_shutdown(FI1236Ptr f) +{ +CARD8 data[10]; + +data[0]=0x00; /* start with register 0x00 */ +data[1]=0x1A; +data[2]=0x44; +data[3]=0x20; + +I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); + +data[0]=0x05; /* now start with register 0x05 */ +data[1]=0xD7; +data[2]=0x14; +data[3]=0x05; +I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); + +data[0]=0x0B; /* now start with register 0x05 */ +data[1]=0x8F; +data[2]=0x07; +data[3]=0x43; +I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); + +usleep(15000); +} +#endif + +static void MT2032_dump_status(FI1236Ptr f); + +static void MT2032_init(FI1236Ptr f) +{ +CARD8 data[10]; +CARD8 value; +CARD8 xogc = 0x00; + +MT2032_getid(f); + +data[0]=0x02; /* start with register 0x02 */ +data[1]=0xFF; +data[2]=0x0F; +data[3]=0x1F; + +I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); + +data[0]=0x06; /* now start with register 0x06 */ +data[1]=0xE4; +data[2]=0x8F; +data[3]=0xC3; +data[4]=0x4E; +data[5]=0xEC; +I2C_WriteRead(&(f->d), (I2CByte *)data, 6, NULL, 0); + +data[0]=0x0d; /* now start with register 0x0d */ +data[1]=0x32; +I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); + +while(1) { + usleep(15000); /* wait 15 milliseconds */ + + data[0]=0x0e; /* register number 7, status */ + value=0xFF; + if(!I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1)) + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to read XOK\n"); + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: XOK=%d\n", value & 0x01); + if(value & 1) break; + + data[0]=0x07; + if(!I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1)) + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to read XOGC\n"); + + xogc=value & 0x7; + if(xogc==4){ + break; /* XOGC has reached 4.. stop */ + } + xogc--; + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: try XOGC=%d\n", xogc); + usleep(15000); + data[0]=0x07; /* register number 7, control byte 2 */ + data[1]=0x08 | xogc; + I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); + } +f->xogc=xogc; +/* wait before continuing */ +usleep(15000); /* wait 50 milliseconds */ +MT2032_dump_status(f); +} + +static int MT2032_no_spur_in_band(MT2032_parameters *m) +{ +int n_max, n1, n2; +double f_test; +n_max=5; +n1=1; +while(1){ + n2=-n1; + f_test=n1*(m->f_lo1-m->f_lo2); + while(1){ + n2--; + f_test=f_test-m->f_lo2; + xf86DrvMsg(0, X_INFO, "testing f_test=%g n1=%d n2=%d f_lo1=%g f_lo2=%g f_if2=%g\n", f_test, n1, n2, m->f_lo1, m->f_lo2, m->f_if2); + xf86DrvMsg(0, X_INFO, "d_f=%g f_ifbw=%g\n",fabs(fabs(f_test)-m->f_if2), m->f_ifbw); + if((fabs(fabs(f_test)-m->f_if2)*2.0)<=m->f_ifbw)return 0; + if(n2<=-n_max)break; + /* this line in the manual is bogus. I say it is faster + and more correct to go over all harmonics.. */ + #if 0 + if(f_test<(m->f_lo2-m->f_if2-m->f_ifbw))break; + #endif + } + n1++; + if(n1>=n_max)return 1; + } + +} + +static void MT2032_calculate_register_settings(MT2032_parameters *m, double f_rf, double f_if1, double f_if2, double f_ref, double f_ifbw, double f_step) +{ +int n; +m->f_rf=f_rf; +m->f_if1=f_if1; +m->f_if2=f_if2; +m->f_ref=f_ref; +m->f_ifbw=f_ifbw; +m->f_step=f_step; + +m->f_lo1=f_rf+f_if1; +m->LO1I=lrint(m->f_lo1/f_ref); +m->f_lo1=f_ref*m->LO1I; + +m->f_lo2=m->f_lo1-f_rf-f_if2; + +/* check for spurs */ +n=1; +while(n<3){ + if(MT2032_no_spur_in_band(m))break; + if(m->f_lo1<(f_rf+f_if1)){ + m->LO1I+=n; + } else { + m->LO1I-=n; + } + m->f_lo1=m->LO1I*f_ref; + m->f_lo2=m->f_lo1-f_rf-f_if2; + n++; + } +/* xf86DrvMsg(0, X_INFO, "MT2032: n=%d\n", n); */ +/* select VCO */ + +/* m->f_lo1>1100.0 */ +if(m->f_lo1<1370.0)m->SEL=4; + else +if(m->f_lo1<1530.0)m->SEL=3; + else +if(m->f_lo1<1720.0)m->SEL=2; + else +if(m->f_lo1<1890.0)m->SEL=1; + else /* m->f_lo1 < 1958.0 */ + m->SEL=0; + +/* calculate the rest of the registers */ +m->LO2I=floor(m->f_lo2/f_ref); +m->STEP=floor(3780.0*f_step/f_ref); +m->NUM=floor(3780.0*(m->f_lo2/f_ref-m->LO2I)); +m->NUM=m->STEP*lrint((1.0*m->NUM)/(1.0*m->STEP)); +} + +static int MT2032_wait_for_lock(FI1236Ptr f) +{ +int n; +CARD8 data[10]; +CARD8 value; + +n=12; +while(1){ + data[0]=0x0e; /* register number 7, status */ + I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1); +/* xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: LO1LK=%d LO2LK=%d\n", (value & 0x04)>>2, (value & 0x02)>>1); */ + if((value & 6)==6) break; + usleep(1500); + n--; + if(n<0)break; + } +if(n<0){ + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to set frequency\n"); + return 0; + } +return 1; +} + +static void MT2032_implement_settings(FI1236Ptr f, MT2032_parameters *m) +{ +CARD8 data[10]; +CARD8 value; + +data[0]=0x00; /* start with register 0x00 */ +data[1]=(m->LO1I>>3)-1; +data[2]=(m->SEL<<4)|(m->LO1I & 0x7); +data[3]=0x86; +I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0); + +data[0]=0x05; /* start with register 0x05 */ +data[1]=((m->LO2I & 0x7)<<5)|((m->LO2I>>3)-1); +if(m->f_rf<400.0)data[2]=0xe4; + else data[2]=0xf4; +I2C_WriteRead(&(f->d), (I2CByte *)data, 3, NULL, 0); + +data[0]=0x07; /* register number 7, control byte 2 */ +I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1); +xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: using XOGC=%d\n", (value & 0x07)); +data[1]=8 | (value & 0x7); +I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); + +data[0]=0x0b; /* start with register 0x0b */ +data[1]=m->NUM & 0xff; +data[2]=(1<<7)|((m->NUM >> 8) & 0x0f); +I2C_WriteRead(&(f->d), (I2CByte *)data, 3, NULL, 0); + +MT2032_wait_for_lock(f); +} + +static void MT2032_optimize_VCO(FI1236Ptr f, MT2032_parameters *m) +{ +CARD8 data[10]; +CARD8 value; +CARD8 TAD1; + +data[0]=0x0f; /* register number 7, status */ +I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1); +TAD1=value & 0x07; +xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: TAD1=%d SEL=%d\n", TAD1, m->SEL); +if(TAD1 < 2)return; +if(TAD1==2){ + if(m->SEL==0)return; + m->SEL--; + } else { + if(m->SEL>=4)return; + m->SEL++; + } +data[0]=0x01; /* start with register 1 */ +data[1]=(m->SEL<<4)|(m->LO1I & 0x7); +I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); + +} + +static int FI1236_get_afc_hint(FI1236Ptr f) +{ + CARD8 out; + CARD8 AFC; + + if ((f->type == TUNER_TYPE_FM1216ME) || (f->type == TUNER_TYPE_FI1236W)) + { + TDA9885Ptr t = (TDA9885Ptr)f->afc_source; + if (t == NULL) + return TUNER_OFF; + + tda9885_getstatus(t); + tda9885_dumpstatus(t); + AFC = t->afc_status & 0x0f; + + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: FI1236_get_afc_hint: %i\n", AFC); + if (AFC == 0) return TUNER_TUNED; + else if (AFC <= 0x07)return TUNER_JUST_BELOW; + else if (AFC < 0x0f )return TUNER_JUST_ABOVE; + else if (AFC == 0x0f)return TUNER_TUNED; + } + else + { + I2C_WriteRead(&(f->d), NULL, 0, &out, 1); + AFC=out & 0x7; + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: FI1236_get_afc_hint: %i\n", AFC); + if(AFC==2)return TUNER_TUNED; + if(AFC==3)return TUNER_JUST_BELOW; + if(AFC==1)return TUNER_JUST_ABOVE; + return TUNER_OFF; + } + return TUNER_OFF; +} + +static int MT2032_get_afc_hint(FI1236Ptr f) +{ +CARD8 in; +CARD8 out[2]; +CARD8 AFC; +in=0x0e; +I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 2); +AFC=(out[0]>>4) & 0x7; +#if 0 +xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC=%d TAD1=%d TAD2=%d\n", AFC, out[1] & 0x7, (out[1]>>4)& 0x07); +#endif +if(AFC==2)return TUNER_TUNED; +if(AFC==3)return TUNER_JUST_BELOW; +if(AFC==1)return TUNER_JUST_ABOVE; +return TUNER_OFF; +} + +/* this function is for external use only */ +int TUNER_get_afc_hint(FI1236Ptr f) +{ +if(f->afc_timer_installed)return TUNER_STILL_TUNING; +return f->last_afc_hint; +} + +static void MT2032_dump_status(FI1236Ptr f) +{ +CARD8 in; +CARD8 out[2]; +CARD8 AFC; +CARD8 LDONrb; +CARD8 LO1LK, LO2LK, XOK; +CARD8 TAD2, TAD1; + +in=0x0e; +I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 2); +XOK=out[0] & 1; +LO1LK=(out[0]>>2) &1; +LO2LK=(out[0]>>1) &1; +LDONrb=(out[0]>>3) &1; + +AFC=(out[0]>>4) & 0x7; + +TAD1=(out[1] & 0x7); +TAD2=(out[1]>>4) & 0x7; + +xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: status: XOK=%d LO1LK=%d LO2LK=%d LDONrb=%d AFC=%d TAD1=%d TAD2=%d\n", + XOK, LO1LK, LO2LK, LDONrb, AFC, TAD1, TAD2); +xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: status: OSCILLATOR:%s PLL1:%s PLL2:%s\n", + XOK ? "ok":"off", LO1LK ? "locked" : "off" , LO2LK ? "locked" : "off"); + +} + +static void MT2032_tune(FI1236Ptr f, double freq, double step) +{ +MT2032_parameters m; +CARD8 data[10]; +int i; +/* NTSC IF is 44mhz.. but 733/16=45.8125 and all TDAXXXX docs mention + 45.75, 39, 58.75 and 30. */ +#if 0 +MT2032_calculate_register_settings(&m, freq, 1090.0, 45.125, 5.25, 6.0, step); +MT2032_calculate_register_settings(&m, freq, 1090.0, 45.74, 5.25, 6.0, step); +#endif +MT2032_calculate_register_settings(&m, freq, 1090.0, f->video_if, 5.25, 3.0, step); +MT2032_dump_parameters(f, &m); +MT2032_implement_settings(f, &m); +/* MT2032_dump_parameters(f, &m); */ +for(i=0;i<3;i++){ + MT2032_optimize_VCO(f, &m); + if(MT2032_wait_for_lock(f)){ + data[0]=0x02; /* LO Gain control register 0x02 */ + data[1]=0x20; + I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); + return; + } + data[0]=0x07; + data[1]=0x88|f->xogc; + I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); + usleep(15000); + data[1]=0x08|f->xogc; + I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0); + } +xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to set frequency\n"); +} + +void FI1236_set_tuner_type(FI1236Ptr f, int type) +{ +f->type=type; +if(type>=NUM_TUNERS)type = NUM_TUNERS-1; +if(type<0)type = 0; +memcpy(&(f->parm), &(tuner_parms[type]), sizeof(FI1236_parameters)); +f->original_frequency=f->parm.min_freq; +f->afc_delta=0; +if(type==TUNER_TYPE_MT2032){ + MT2032_init(f); + return; + } +} + + +static CARD32 AFC_TimerCallback(OsTimerPtr timer, CARD32 time, pointer data){ +FI1236Ptr f=(FI1236Ptr)data; +if(FI1236_AFC(f))return 150; + else { + f->afc_timer_installed=FALSE; + f->afc_count=0; + return 0; + } +} + +void FI1236_tune(FI1236Ptr f, CARD32 frequency) +{ + CARD16 divider; + CARD8 data; + + if(frequency < f->parm.min_freq) frequency = f->parm.min_freq; + if(frequency > f->parm.max_freq) frequency = f->parm.max_freq; + + divider = (f->parm.fcar+(CARD16)frequency) & 0x7fff; + f->tuner_data.div1 = (CARD8)((divider>>8)&0x7f); + f->tuner_data.div2 = (CARD8)(divider & 0xff); + f->tuner_data.control = f->parm.control; + + if(frequency < f->parm.threshold1) + { + f->tuner_data.band = f->parm.band_low; + } + else if (frequency < f->parm.threshold2) + { + f->tuner_data.band = f->parm.band_mid; + } + else + { + f->tuner_data.band = f->parm.band_high; + } + + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Setting tuner band to %d\n", f->tuner_data.band); + + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Setting tuner frequency to %d\n", (int)frequency); + + if ((f->type == TUNER_TYPE_FM1216ME) || (f->type == TUNER_TYPE_FI1236W)) + { + f->tuner_data.aux = 0x20; + I2C_WriteRead(&(f->d), (I2CByte *)&(f->tuner_data), 5, NULL, 0); + I2C_WriteRead(&(f->d), NULL, 0, &data, 1); + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Tuner status %x\n", data); + + } + else + I2C_WriteRead(&(f->d), (I2CByte *)&(f->tuner_data), 4, NULL, 0); +} + +void TUNER_set_frequency(FI1236Ptr f, CARD32 frequency) +{ + if(frequency < f->parm.min_freq) frequency = f->parm.min_freq; + if(frequency > f->parm.max_freq) frequency = f->parm.max_freq; + + f->afc_delta=0; + f->original_frequency=frequency; + + if(f->type==TUNER_TYPE_MT2032) + { + MT2032_tune(f, (1.0*frequency)/16.0, 0.0625); + } else + { + FI1236_tune(f, frequency); + } + + if(!f->afc_timer_installed) + { + f->afc_timer_installed=TRUE; +/* RegisterBlockAndWakeupHandlers(FI1236_BlockHandler, AFCWakeup, f); */ + TimerSet(NULL, 0, 300, AFC_TimerCallback, f); + } + +} + + +int FI1236_AFC(FI1236Ptr f) +{ + #if 0 + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: f=%p f->count=%d f->original_frequency=%d f->afc_delta=%d\n", f, f->afc_count, f->original_frequency, f->afc_delta); + #endif + f->afc_count++; + if(f->type==TUNER_TYPE_MT2032) + { + f->last_afc_hint=MT2032_get_afc_hint(f); + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: afc_hint=%d\n", f->last_afc_hint); + if(f->last_afc_hint==TUNER_TUNED)return 0; + if(f->afc_count>3)f->last_afc_hint=TUNER_OFF; + if(f->last_afc_hint==TUNER_OFF) + { + f->afc_delta=0; + } else + f->afc_delta+=f->last_afc_hint; + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: Setting tuner frequency to %g\n", (0.5*(2*f->original_frequency+f->afc_delta))/16.0); + MT2032_tune(f, (1.0*f->original_frequency+0.5*f->afc_delta)/16.0, 0.03125); + if(f->last_afc_hint==TUNER_OFF)return 0; + return 1; /* call me again */ + } else + { + f->last_afc_hint=FI1236_get_afc_hint(f); + if(f->last_afc_hint==TUNER_TUNED) + { + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: TUNER_TUNNED\n"); + return 0; + } + if(f->afc_count>3)f->last_afc_hint=TUNER_OFF; + if(f->last_afc_hint==TUNER_OFF) + { + f->afc_delta=0; + } else + f->afc_delta+=f->last_afc_hint; + xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: Setting tuner frequency to %g\n", (0.5*(2*f->original_frequency+f->afc_delta))/16.0); + FI1236_tune(f, f->original_frequency+f->afc_delta); + if(f->last_afc_hint==TUNER_OFF)return 0; + return 1; /* call me again */ + } + return 0; /* done */ +} + +void fi1236_dump_status(FI1236Ptr f) +{ +if(f->type==TUNER_TYPE_MT2032){ + MT2032_dump_status(f); + } +} diff --git a/xorg-server/hw/xfree86/i2c/msp3430.c b/xorg-server/hw/xfree86/i2c/msp3430.c index 4bd3a7187..b58c3f09c 100644 --- a/xorg-server/hw/xfree86/i2c/msp3430.c +++ b/xorg-server/hw/xfree86/i2c/msp3430.c @@ -1,726 +1,726 @@ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> -#include <unistd.h> - -#include "xf86.h" -#include "xf86i2c.h" -#include "msp3430.h" -#include "i2c_def.h" - -#define CONTROL 0x00 -#define WR_DEM 0x10 -#define RD_DEM 0x11 -#define WR_DSP 0x12 -#define RD_DSP 0x13 - - -void InitMSP34xxG(MSP3430Ptr m); -void InitMSP34x5D(MSP3430Ptr m); -void CheckModeMSP34x5D(MSP3430Ptr m); -char *MSP_getProductName (CARD16 product_id); -void mpause(int milliseconds); - -#define __MSPDEBUG__ 0 - -#if __MSPDEBUG__ > 3 - -void MSPBeep(MSP3430Ptr m, CARD8 freq); -#define __MSPBEEP MSPBeep(m,0x14); - -#else - -#define __MSPBEEP -#endif - -static void SetMSP3430Control(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegValueHigh, CARD8 RegValueLow) -{ - I2CByte data[3]; - - data[0]=RegAddress; - data[1]=RegValueHigh; - data[2]=RegValueLow; - - I2C_WriteRead(&(m->d),data,3,NULL,0); -} - -static void SetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, - CARD8 RegValueHigh, CARD8 RegValueLow) -{ - I2CByte data[5]; -#ifdef MSP_DEBUG - if(!m->registers_present[RegSubAddressLow]){ - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_ERROR, "Attempt to access non-existent register in MSP34xxX: 0x%02x 0x%02x 0x%02x <- 0x%02x 0x%02x\n", - RegAddress, RegSubAddressHigh, RegSubAddressLow, RegValueHigh, RegValueLow); - } -#endif - - data[0] = RegAddress; - data[1] = RegSubAddressHigh; - data[2] = RegSubAddressLow; - data[3] = RegValueHigh; - data[4] = RegValueLow; - - I2C_WriteRead(&(m->d),data,5,NULL,0); -} - -static void GetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, - CARD8 *RegValueHigh, CARD8 *RegValueLow) -{ - I2CByte send[3]; - I2CByte receive[2]; - - send[0] = RegAddress; - send[1] = RegSubAddressHigh; - send[2] = RegSubAddressLow; - - I2C_WriteRead(&(m->d), send, 3, receive, 2); - - *RegValueHigh = receive[0]; - *RegValueLow = receive[1]; -} - -#if __MSPDEBUG__ > 2 -static void MSP3430DumpStatus(MSP3430Ptr m) -{ -CARD8 status_hi, status_lo; -CARD8 subaddr, data[2]; - -GetMSP3430Data(m, RD_DEM, 0x02, 0x00, &status_hi, &status_lo); -xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: SAP(8)=%d mono/NICAM(7)=%d stereo=%d %s O_1=%d O_0=%d 2nd car=%d 1st car=%d\n", - status_hi & 1, (status_lo>>7) & 1, (status_lo>>6)&1, - (status_lo>>5)? ( (status_hi>>1)&1? "bad NICAM reception" : "NICAM" ) : - ((status_hi>>1)&1 ? "bogus" : "ANALOG FM/AM") , - (status_lo>>4)&1, (status_lo>>3)&1,!( (status_lo>>2)&1), !((status_lo>>1)&1)); - -GetMSP3430Data(m, RD_DEM, 0x00, 0x7E, &status_hi, &status_lo); -xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: standard result=0x%02x%02x\n", - status_hi, status_lo); -subaddr=0x0; -I2C_WriteRead(&(m->d), &subaddr, 1, data, 2); -xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: control=0x%02x%02x\n", - data[1], data[0]); -} -#endif - -/* wrapper */ -void InitMSP3430(MSP3430Ptr m) -{ - #if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", - m->connector, m->standard, m->chip_family); - #endif - switch (m->chip_family) { - case MSPFAMILY_34x0G: - InitMSP34xxG(m); - break; - case MSPFAMILY_34x5G: - InitMSP34xxG(m); - break; - case MSPFAMILY_34x5D: - InitMSP34x5D(m); - break; - } -} - -/*----------------------------------------------------------------- -| common functions for all MSP34xx chips -|----------------------------------------------------------------*/ - -MSP3430Ptr DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr) -{ - MSP3430Ptr m; - I2CByte a; - CARD8 hardware_version, major_revision, product_code, rom_version; - Bool supported; - - m = xcalloc(1,sizeof(MSP3430Rec)); - if(m == NULL)return NULL; - m->d.DevName = strdup("MSP34xx"); - m->d.SlaveAddr = addr; - m->d.pI2CBus = b; - m->d.NextDev = NULL; - m->d.StartTimeout = b->StartTimeout; - m->d.BitTimeout = b->BitTimeout; - m->d.AcknTimeout = b->AcknTimeout; - m->d.ByteTimeout = b->ByteTimeout; - - if(!I2C_WriteRead(&(m->d), NULL, 0, &a, 1)) - { - xfree(m->d.DevName); - xfree(m); - return NULL; - } - - - m->standard=MSP3430_NTSC; - m->connector=MSP3430_CONNECTOR_1; - m->mode=MSPMODE_STEREO_A; /*stereo or chanel A if avail. */ - m->c_format=MSPFORMAT_UNKNOWN; - m->c_standard=MSPSTANDARD_UNKNOWN; - m->c_matrix=m->c_fmmatrix=m->c_source=0; - m->volume=0; - m->recheck=FALSE; - - GetMSP3430Data(m, RD_DSP, 0x00, 0x1E, &hardware_version, &major_revision); - GetMSP3430Data(m, RD_DSP, 0x00, 0x1F, &product_code, &rom_version); - m->hardware_version=hardware_version; - m->major_revision=major_revision; - m->product_code=product_code; - m->rom_version=rom_version; - - m->chip_id=((major_revision << 8) | product_code); - - supported=FALSE; - switch (major_revision) { - case 4: /* 34xxD */ - switch (product_code) { - case 0x05: /* 3405D */ - case 0x0A: /* 3410D */ - case 0x0F: /* 3415D */ - m->chip_family=MSPFAMILY_34x5D; - m->recheck=TRUE; - supported=TRUE; - break; - default: - m->chip_family=MSPFAMILY_34x0D; - } - break; - case 7: /* 34xxG */ - switch(product_code){ - case 0x00: - case 0x0A: - case 0x1E: - case 0x28: - case 0x32: - m->chip_family=MSPFAMILY_34x0G; - supported=TRUE; - break; - case 0x0f: - case 0x19: - case 0x2d: - case 0x37: - case 0x41: - m->chip_family=MSPFAMILY_34x5G; - supported=TRUE; - #ifdef MSP_DEBUG - memset(m->registers_present, 0, 256); - #define A(num) m->registers_present[(num)]=1; - #define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1); - A(0x20) - A(0x30) - A(0x40) - A(0x00) - B(0x01, 0x08) - B(0x0B, 0x0E) - A(0x10) - B(0x12,0x14) - A(0x16) - A(0x29) - #undef B - #undef A - #endif - break; - default: - m->chip_family=MSPFAMILY_UNKNOWN; - } - break; - default: - m->chip_family=MSPFAMILY_UNKNOWN; - } - - xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Found %s%s, rom version 0x%02x, chip_id=0x%04x\n", - MSP_getProductName(m->chip_id), supported?"":" (unsupported)", rom_version, m->chip_id); - - if (!supported) { - xfree(m->d.DevName); - xfree(m); - return NULL; - } - if(!I2CDevInit(&(m->d))) - { - xfree(m->d.DevName); - xfree(m); - return NULL; - } - - return m; -} - -void ResetMSP3430(MSP3430Ptr m) -{ - /* Reset the MSP3430 */ - SetMSP3430Control(m, 0x00, 0x80, 0x00); - /* Set it back to normal operation */ - SetMSP3430Control(m, 0x00, 0x00, 0x00); - - m->c_format=MSPFORMAT_UNKNOWN; - m->c_standard=MSPSTANDARD_UNKNOWN; - m->c_matrix=m->c_fmmatrix=m->c_source=0; - m->volume=0; -} - -void MSP3430SetVolume (MSP3430Ptr m, CARD8 value) -{ - CARD8 result; -#if 0 - CARD8 old_volume; - GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); - xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 result 0x%02x\n", result); -#endif - /* save an extra Get call */ - result=0; - - SetMSP3430Data(m, WR_DSP, 0x00, 0x00, value, result); - - SetMSP3430Data(m, WR_DSP, 0x00, 0x07, value, 0); - m->volume=value; - -#if __MSPDEBUG__ > 2 - MSP3430DumpStatus(m); - __MSPBEEP - GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); - xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 volume 0x%02x\n",value); -#endif -} - - -void MSP3430SetSAP (MSP3430Ptr m, int mode) -{ - xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Put actual code to change SAP here\n"); - - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, mode & 0xff, 0x20); -} - - -#if 0 -void MSP3430SetSource(MSP3430Ptr m, CARD8 value) -{ - /* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */ - /* This sets the source to the TV tuner, for stereo operation */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, value, 0x20); -} -#endif - - -char *MSP_getProductName (CARD16 product_id) -{ - switch (product_id) { - case 0x0400: return "MSP3400D"; - case 0x040a: return "MSP3410D"; - case 0x0405: return "MSP3405D"; - case 0x040f: return "MSP3415D"; - case 0x0700: return "MSP3400G"; - case 0x070a: return "MSP3410G"; - case 0x071e: return "MSP3430G"; - case 0x0728: return "MSP3440G"; - case 0x0732: return "MSP3450G"; - case 0x070f: return "MSP3415G"; - case 0x0719: return "MSP3425G"; - case 0x072d: return "MSP3445G"; - case 0x0737: return "MSP3455G"; - case 0x0741: return "MSP3465G"; - } - return "MSP - unknown type"; -} - -#if __MSPDEBUG__ > 2 -/*puts beep in MSP output - freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz -*/ -void MSPBeep(MSP3430Ptr m, CARD8 freq) { - SetMSP3430Data (m, WR_DSP, 0x00, freq, 0x7f, 0x40); - mpause(100); - SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x00); -} -#endif - -void mpause(int milliseconds) { - int i,m; - m=milliseconds/20; - for (i=0;i<m;i++) usleep(20000); -} - -/*----------------------------------------------------------------- -| specific functions for all MSP34xxG chips -|----------------------------------------------------------------*/ - -void InitMSP34xxG(MSP3430Ptr m) -{ - - #if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", - m->connector, m->standard, m->chip_family); - #endif - /* Reset MSP3430 */ - SetMSP3430Control(m, 0x00, 0x80, 0x00); - /* Set it back to normal operation */ - SetMSP3430Control(m, 0x00, 0x00, 0x00); - - /*set MODUS register */ - /* bits: 0 - automatic sound detection */ - /* 1 - enable STATUS change */ - /* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */ - /* 13 - detect 4.5 Mhz carrier as BTSC */ - if ( (m->standard & 0xff) == MSP3430_PAL ) - { - SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x30, 0x03|0x08); /* make O_ pins tristate */ - /* PAL standard */ - SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */ - } else { - SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x20, 0x03|0x08); - /* standard selection is M-BTSC-Stereo */ - SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x20); - } - - switch(m->connector){ - case MSP3430_CONNECTOR_1: - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x03, 0x20); - break; - case MSP3430_CONNECTOR_2: - /* this has not been checked yet.. could be bogus */ - /* SCART Input Prescale: 0 dB gain */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); - break; - case MSP3430_CONNECTOR_3: - default: - /* SCART Input Prescale: 0 dB gain */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); - - SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); - break; - } - - switch(m->standard){ - case MSP3430_PAL: - SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); - SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); - SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x03); - /* Set volume to FAST_MUTE. */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); - break; - case MSP3430_PAL_DK1: - SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); - SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); - SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x04); - /* Set volume to FAST_MUTE. */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); - break; - case MSP3430_SECAM: /* is this right ? */ - case MSP3430_NTSC: - /* Write to DSP, register 0x000E, (prescale FM/FM matrix) */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); - - /* Set volume to FAST_MUTE. */ - SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); - break; - } - -} - -/*----------------------------------------------------------------- -| specific functions for all MSP34x5D chips -|----------------------------------------------------------------*/ - -void InitMSP34x5D(MSP3430Ptr m) -{ -int count; -CARD8 high,low; -CARD16 result,standard; -CARD16 peak; - - -if (m->c_format==MSPFORMAT_UNKNOWN) ResetMSP3430(m); -else { - /*mute volume*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x00, 0x00, 0x00); -} - - - - switch(m->connector){ - case MSP3430_CONNECTOR_2: - case MSP3430_CONNECTOR_3: - if (m->c_format!=MSPFORMAT_SCART) { - /* SCART Input Prescale: 0 dB gain */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); - /* this has not been checked yet.. could be bogus */ - m->c_format=MSPFORMAT_SCART; /*stereo*/ - } - break; - case MSP3430_CONNECTOR_1: - default: - - switch ( m->standard & 0x00ff ) { - case MSP3430_PAL: - switch( m->standard ) { - case MSP3430_PAL_DK1: - standard=MSPSTANDARD_FM_DK1; - break; -/* case MSP3430_PAL_DK2: - standard=MSPSTANDARD_FM_DK2; - break; - case MSP3430_PAL_BG: - may be FM stereo (Germany) or FM NICAM (Scandinavia,spain) - standard=MSPSTANDARD_AUTO; - break; -*/ - default: - standard=MSPSTANDARD_AUTO; - } - break; - case MSP3430_SECAM: - standard=MSPSTANDARD_AUTO; - case MSP3430_NTSC: - /* Only MSP34x5 supported format - Korean NTSC-M*/ - standard=MSPSTANDARD_FM_M; - default: - standard=MSPSTANDARD_AUTO; - } - - /*no NICAM support in MSP3410D - force to autodetect*/ - if ((m->chip_id==0x405) && (standard>=MSPSTANDARD_NICAM_BG)) - standard=MSPSTANDARD_AUTO; - - if (m->c_standard != standard) { - - SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); - if (standard==MSPSTANDARD_AUTO) { - count = 50; /* time shouldn't exceed 1s, just in case */ - do { - usleep(20000); - GetMSP3430Data (m, RD_DEM, 0x00, 0x7e, &high, &low); - result = ( high << 8 ) | low; - --count; - } while( result > 0x07ff && count > 0 ); - - if ((result > MSPSTANDARD_AUTO)) - standard=result; - else standard=MSPSTANDARD_UNKNOWN; -#if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Detected audio standard: %d\n",result); -#endif - /* result = MSPSTANDARD_NICAM_L can be one of: - SECAM_L - MSPSTANDARD_NICAM_L - D/K1 - MSPSTANDARD_FM_DK1 - D/K2 - MSPSTANDARD_FM_DK2 - D/K-NICAM - MSPSTANDARD_NICAM_DK*/ - if( standard == MSPSTANDARD_NICAM_L ) { - if ((m->standard & 0x00ff)==MSP3430_PAL) { - /* force PAL D/K */ - standard=MSPSTANDARD_FM_DK1; - SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); -#if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO, "Detected 6.5MHz carrier - forced to D/K1 !!!\n" ); -#endif - } - } - } - m->c_standard=standard; - } /*end - standard changed*/ - else { - if (standard<MSPSTANDARD_NICAM_BG) { - /* get old value of ident. mode register*/ - GetMSP3430Data (m, RD_DSP, 0x00, 0x15, &high, &low); - /* reset Ident-Filter */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x3F); - /* put back old value to ident. mode register*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, low); - } - } - - if (standard<=MSPSTANDARD_AUTO) { - m->c_format=MSPFORMAT_1xFM; - } - else if (standard<MSPSTANDARD_NICAM_BG) { - /* set FM prescale */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); - /* set FM deemphasis*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, ((standard==MSPSTANDARD_FM_M)?0:1), 0); - - /* check if FM2 carrier is present */ - /*turn off FM DC Notch*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x3f); - /*matrix source for Quasi-Peak Detector - stereo: ch2->L ch1->R*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0c, 0x00, 0x20); - - mpause(250); - GetMSP3430Data (m, RD_DSP, 0x00, 0x1A, &high, &low); - peak = (high << 8) | low; -#if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Second carrier Quasi-Peak detection: %d\n",peak); -#endif - /*turn on FM DC Notch*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x00); - - if (peak<5) { - /* if second carrier not detected - only mono from first carrier*/ - m->c_format=MSPFORMAT_1xFM; - } - else { - m->c_format=MSPFORMAT_2xFM; - /*start of FM identification process - FM_WAIT - wait at least 0.5s - used 1s - gives beter resolution*/ - mpause(1000); - } - } - else { - if (standard==MSPSTANDARD_NICAM_L) { - m->c_format=MSPFORMAT_NICAM_AM; - /* set AM prescale */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x7C, 0); - } - else { - m->c_format=MSPFORMAT_NICAM_FM; - /* set FM prescale */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); - } - /* set FM deemphasis*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, 0x00, 0); - /* set NICAM prescale to 0dB */ - SetMSP3430Data (m, WR_DSP, 0x00, 0x10, 0x20, 0); - } - - break; - } /*end - case conector*/ - - CheckModeMSP34x5D(m); - - /* Set volume to FAST_MUTE. */ - /*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);*/ - /*set volume*/ - MSP3430SetVolume(m,m->volume); - - __MSPBEEP - - -} /* EnableMSP34x5D ()... */ - - - - -void CheckModeMSP34x5D(MSP3430Ptr m) { - const char stereo_on=25; - const char stereo_off=20; - const char dual_on=-stereo_on; - const char dual_off=-stereo_off; - char detect; - CARD8 matrix, fmmatrix, source, high, low; - - fmmatrix=0; /*no matrix*/ - source=0; /*FM*/ - switch (m->c_format) { - case MSPFORMAT_NICAM_FM: - case MSPFORMAT_NICAM_AM: - case MSPFORMAT_SCART: - source=( (m->c_format == MSPFORMAT_SCART)?2:1 ); - switch (m->mode) { - case MSPMODE_MONO: - matrix=0x30; /*MONO*/ - break; - case MSPMODE_A: - matrix=0x00; /*A*/ - break; - case MSPMODE_B: - matrix=0x10; /*B*/ - break; - default: - matrix=0x20; /*STEREO*/ - break; - } - break; - default: - case MSPFORMAT_1xFM: - matrix=0x00; /*A*/ - break; - case MSPFORMAT_2xFM: - switch (m->mode) { - case MSPMODE_MONO: - matrix=0x30; /*MONO*/ - break; - case MSPMODE_STEREO: - matrix=0x20; /*STEREO*/ - fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); - break; - case MSPMODE_AB: - matrix=0x20; /*STEREO*/ - break; - case MSPMODE_A: - matrix=0x00; /*A*/ - break; - case MSPMODE_B: - matrix=0x10; /*B*/ - break; - default: - /*FM_IDENT_CHECK*/ - GetMSP3430Data (m, RD_DSP, 0x00, 0x18, &high, &low); - detect=(char)high; -#if __MSPDEBUG__ > 1 - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Stereo Detection Register: %d\n",detect); -#endif - if (detect>=((m->c_mode==MSPMODE_STEREO)?stereo_off:stereo_on)) { - m->c_mode=MSPMODE_STEREO; - matrix=0x20; /*STEREO*/ - fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); - } - else if (detect<=((m->c_mode==MSPMODE_AB)?dual_off:dual_on)) { - m->c_mode=MSPMODE_AB; - switch (m->mode) { - case MSPMODE_STEREO_AB: matrix=0x20; break; - case MSPMODE_STEREO_B: matrix=0x10; break; - default: - case MSPMODE_A: matrix=0x00; break; - } - } - else { - m->c_mode=MSPMODE_MONO; - matrix=0x30; /*MONO*/ - } - break; - } /* end - case mode*/ - break; - } - - if (m->c_fmmatrix != fmmatrix) { - GetMSP3430Data (m, RD_DSP, 0x00, 0x0e, &high, &low); - SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, high, fmmatrix); - m->c_fmmatrix = fmmatrix; - } - - if ((m->c_matrix != matrix) || (m->c_source != source)) { - /*set chanel source and matrix for loudspeaker*/ - SetMSP3430Data (m, WR_DSP, 0x00, 0x08, source, matrix); - - m->c_matrix = matrix; - m->c_source = source; - } - - if ( ((m->c_format) & 0xF0) == MSPFORMAT_NICAM) - SetMSP3430Data (m, WR_DEM, 0x00, 0x21, 0, 1); - -#if __MSPDEBUG__ > 0 - char *msg; - switch (matrix) { - case 0x30: /*MONO*/ - msg="MONO"; - break; - case 0x00: /*LEFT*/ - msg="MONO/CHANNEL_1"; - break; - case 0x10: /*RIGHT*/ - msg="MONO/CHANNEL_2"; - break; - case 0x20: /*LEFT*/ - msg="STEREO"; - break; - default: - msg="unknown"; - break; - } - xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Audio mode set to: %s\n",msg); -#endif -} - +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> +#include <unistd.h> + +#include "xf86.h" +#include "xf86i2c.h" +#include "msp3430.h" +#include "i2c_def.h" + +#define CONTROL 0x00 +#define WR_DEM 0x10 +#define RD_DEM 0x11 +#define WR_DSP 0x12 +#define RD_DSP 0x13 + + +void InitMSP34xxG(MSP3430Ptr m); +void InitMSP34x5D(MSP3430Ptr m); +void CheckModeMSP34x5D(MSP3430Ptr m); +char *MSP_getProductName (CARD16 product_id); +void mpause(int milliseconds); + +#define __MSPDEBUG__ 0 + +#if __MSPDEBUG__ > 3 + +void MSPBeep(MSP3430Ptr m, CARD8 freq); +#define __MSPBEEP MSPBeep(m,0x14); + +#else + +#define __MSPBEEP +#endif + +static void SetMSP3430Control(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegValueHigh, CARD8 RegValueLow) +{ + I2CByte data[3]; + + data[0]=RegAddress; + data[1]=RegValueHigh; + data[2]=RegValueLow; + + I2C_WriteRead(&(m->d),data,3,NULL,0); +} + +static void SetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, + CARD8 RegValueHigh, CARD8 RegValueLow) +{ + I2CByte data[5]; +#ifdef MSP_DEBUG + if(!m->registers_present[RegSubAddressLow]){ + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_ERROR, "Attempt to access non-existent register in MSP34xxX: 0x%02x 0x%02x 0x%02x <- 0x%02x 0x%02x\n", + RegAddress, RegSubAddressHigh, RegSubAddressLow, RegValueHigh, RegValueLow); + } +#endif + + data[0] = RegAddress; + data[1] = RegSubAddressHigh; + data[2] = RegSubAddressLow; + data[3] = RegValueHigh; + data[4] = RegValueLow; + + I2C_WriteRead(&(m->d),data,5,NULL,0); +} + +static void GetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, + CARD8 *RegValueHigh, CARD8 *RegValueLow) +{ + I2CByte send[3]; + I2CByte receive[2]; + + send[0] = RegAddress; + send[1] = RegSubAddressHigh; + send[2] = RegSubAddressLow; + + I2C_WriteRead(&(m->d), send, 3, receive, 2); + + *RegValueHigh = receive[0]; + *RegValueLow = receive[1]; +} + +#if __MSPDEBUG__ > 2 +static void MSP3430DumpStatus(MSP3430Ptr m) +{ +CARD8 status_hi, status_lo; +CARD8 subaddr, data[2]; + +GetMSP3430Data(m, RD_DEM, 0x02, 0x00, &status_hi, &status_lo); +xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: SAP(8)=%d mono/NICAM(7)=%d stereo=%d %s O_1=%d O_0=%d 2nd car=%d 1st car=%d\n", + status_hi & 1, (status_lo>>7) & 1, (status_lo>>6)&1, + (status_lo>>5)? ( (status_hi>>1)&1? "bad NICAM reception" : "NICAM" ) : + ((status_hi>>1)&1 ? "bogus" : "ANALOG FM/AM") , + (status_lo>>4)&1, (status_lo>>3)&1,!( (status_lo>>2)&1), !((status_lo>>1)&1)); + +GetMSP3430Data(m, RD_DEM, 0x00, 0x7E, &status_hi, &status_lo); +xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: standard result=0x%02x%02x\n", + status_hi, status_lo); +subaddr=0x0; +I2C_WriteRead(&(m->d), &subaddr, 1, data, 2); +xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: control=0x%02x%02x\n", + data[1], data[0]); +} +#endif + +/* wrapper */ +void InitMSP3430(MSP3430Ptr m) +{ + #if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", + m->connector, m->standard, m->chip_family); + #endif + switch (m->chip_family) { + case MSPFAMILY_34x0G: + InitMSP34xxG(m); + break; + case MSPFAMILY_34x5G: + InitMSP34xxG(m); + break; + case MSPFAMILY_34x5D: + InitMSP34x5D(m); + break; + } +} + +/*----------------------------------------------------------------- +| common functions for all MSP34xx chips +|----------------------------------------------------------------*/ + +MSP3430Ptr DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr) +{ + MSP3430Ptr m; + I2CByte a; + CARD8 hardware_version, major_revision, product_code, rom_version; + Bool supported; + + m = calloc(1,sizeof(MSP3430Rec)); + if(m == NULL)return NULL; + m->d.DevName = strdup("MSP34xx"); + m->d.SlaveAddr = addr; + m->d.pI2CBus = b; + m->d.NextDev = NULL; + m->d.StartTimeout = b->StartTimeout; + m->d.BitTimeout = b->BitTimeout; + m->d.AcknTimeout = b->AcknTimeout; + m->d.ByteTimeout = b->ByteTimeout; + + if(!I2C_WriteRead(&(m->d), NULL, 0, &a, 1)) + { + free(m->d.DevName); + free(m); + return NULL; + } + + + m->standard=MSP3430_NTSC; + m->connector=MSP3430_CONNECTOR_1; + m->mode=MSPMODE_STEREO_A; /*stereo or chanel A if avail. */ + m->c_format=MSPFORMAT_UNKNOWN; + m->c_standard=MSPSTANDARD_UNKNOWN; + m->c_matrix=m->c_fmmatrix=m->c_source=0; + m->volume=0; + m->recheck=FALSE; + + GetMSP3430Data(m, RD_DSP, 0x00, 0x1E, &hardware_version, &major_revision); + GetMSP3430Data(m, RD_DSP, 0x00, 0x1F, &product_code, &rom_version); + m->hardware_version=hardware_version; + m->major_revision=major_revision; + m->product_code=product_code; + m->rom_version=rom_version; + + m->chip_id=((major_revision << 8) | product_code); + + supported=FALSE; + switch (major_revision) { + case 4: /* 34xxD */ + switch (product_code) { + case 0x05: /* 3405D */ + case 0x0A: /* 3410D */ + case 0x0F: /* 3415D */ + m->chip_family=MSPFAMILY_34x5D; + m->recheck=TRUE; + supported=TRUE; + break; + default: + m->chip_family=MSPFAMILY_34x0D; + } + break; + case 7: /* 34xxG */ + switch(product_code){ + case 0x00: + case 0x0A: + case 0x1E: + case 0x28: + case 0x32: + m->chip_family=MSPFAMILY_34x0G; + supported=TRUE; + break; + case 0x0f: + case 0x19: + case 0x2d: + case 0x37: + case 0x41: + m->chip_family=MSPFAMILY_34x5G; + supported=TRUE; + #ifdef MSP_DEBUG + memset(m->registers_present, 0, 256); + #define A(num) m->registers_present[(num)]=1; + #define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1); + A(0x20) + A(0x30) + A(0x40) + A(0x00) + B(0x01, 0x08) + B(0x0B, 0x0E) + A(0x10) + B(0x12,0x14) + A(0x16) + A(0x29) + #undef B + #undef A + #endif + break; + default: + m->chip_family=MSPFAMILY_UNKNOWN; + } + break; + default: + m->chip_family=MSPFAMILY_UNKNOWN; + } + + xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Found %s%s, rom version 0x%02x, chip_id=0x%04x\n", + MSP_getProductName(m->chip_id), supported?"":" (unsupported)", rom_version, m->chip_id); + + if (!supported) { + free(m->d.DevName); + free(m); + return NULL; + } + if(!I2CDevInit(&(m->d))) + { + free(m->d.DevName); + free(m); + return NULL; + } + + return m; +} + +void ResetMSP3430(MSP3430Ptr m) +{ + /* Reset the MSP3430 */ + SetMSP3430Control(m, 0x00, 0x80, 0x00); + /* Set it back to normal operation */ + SetMSP3430Control(m, 0x00, 0x00, 0x00); + + m->c_format=MSPFORMAT_UNKNOWN; + m->c_standard=MSPSTANDARD_UNKNOWN; + m->c_matrix=m->c_fmmatrix=m->c_source=0; + m->volume=0; +} + +void MSP3430SetVolume (MSP3430Ptr m, CARD8 value) +{ + CARD8 result; +#if 0 + CARD8 old_volume; + GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); + xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 result 0x%02x\n", result); +#endif + /* save an extra Get call */ + result=0; + + SetMSP3430Data(m, WR_DSP, 0x00, 0x00, value, result); + + SetMSP3430Data(m, WR_DSP, 0x00, 0x07, value, 0); + m->volume=value; + +#if __MSPDEBUG__ > 2 + MSP3430DumpStatus(m); + __MSPBEEP + GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); + xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 volume 0x%02x\n",value); +#endif +} + + +void MSP3430SetSAP (MSP3430Ptr m, int mode) +{ + xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Put actual code to change SAP here\n"); + + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, mode & 0xff, 0x20); +} + + +#if 0 +void MSP3430SetSource(MSP3430Ptr m, CARD8 value) +{ + /* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */ + /* This sets the source to the TV tuner, for stereo operation */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, value, 0x20); +} +#endif + + +char *MSP_getProductName (CARD16 product_id) +{ + switch (product_id) { + case 0x0400: return "MSP3400D"; + case 0x040a: return "MSP3410D"; + case 0x0405: return "MSP3405D"; + case 0x040f: return "MSP3415D"; + case 0x0700: return "MSP3400G"; + case 0x070a: return "MSP3410G"; + case 0x071e: return "MSP3430G"; + case 0x0728: return "MSP3440G"; + case 0x0732: return "MSP3450G"; + case 0x070f: return "MSP3415G"; + case 0x0719: return "MSP3425G"; + case 0x072d: return "MSP3445G"; + case 0x0737: return "MSP3455G"; + case 0x0741: return "MSP3465G"; + } + return "MSP - unknown type"; +} + +#if __MSPDEBUG__ > 2 +/*puts beep in MSP output + freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz +*/ +void MSPBeep(MSP3430Ptr m, CARD8 freq) { + SetMSP3430Data (m, WR_DSP, 0x00, freq, 0x7f, 0x40); + mpause(100); + SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x00); +} +#endif + +void mpause(int milliseconds) { + int i,m; + m=milliseconds/20; + for (i=0;i<m;i++) usleep(20000); +} + +/*----------------------------------------------------------------- +| specific functions for all MSP34xxG chips +|----------------------------------------------------------------*/ + +void InitMSP34xxG(MSP3430Ptr m) +{ + + #if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", + m->connector, m->standard, m->chip_family); + #endif + /* Reset MSP3430 */ + SetMSP3430Control(m, 0x00, 0x80, 0x00); + /* Set it back to normal operation */ + SetMSP3430Control(m, 0x00, 0x00, 0x00); + + /*set MODUS register */ + /* bits: 0 - automatic sound detection */ + /* 1 - enable STATUS change */ + /* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */ + /* 13 - detect 4.5 Mhz carrier as BTSC */ + if ( (m->standard & 0xff) == MSP3430_PAL ) + { + SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x30, 0x03|0x08); /* make O_ pins tristate */ + /* PAL standard */ + SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */ + } else { + SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x20, 0x03|0x08); + /* standard selection is M-BTSC-Stereo */ + SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x20); + } + + switch(m->connector){ + case MSP3430_CONNECTOR_1: + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x03, 0x20); + break; + case MSP3430_CONNECTOR_2: + /* this has not been checked yet.. could be bogus */ + /* SCART Input Prescale: 0 dB gain */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); + break; + case MSP3430_CONNECTOR_3: + default: + /* SCART Input Prescale: 0 dB gain */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); + + SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); + break; + } + + switch(m->standard){ + case MSP3430_PAL: + SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); + SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); + SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x03); + /* Set volume to FAST_MUTE. */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); + break; + case MSP3430_PAL_DK1: + SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); + SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); + SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x04); + /* Set volume to FAST_MUTE. */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); + break; + case MSP3430_SECAM: /* is this right ? */ + case MSP3430_NTSC: + /* Write to DSP, register 0x000E, (prescale FM/FM matrix) */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); + + /* Set volume to FAST_MUTE. */ + SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); + break; + } + +} + +/*----------------------------------------------------------------- +| specific functions for all MSP34x5D chips +|----------------------------------------------------------------*/ + +void InitMSP34x5D(MSP3430Ptr m) +{ +int count; +CARD8 high,low; +CARD16 result,standard; +CARD16 peak; + + +if (m->c_format==MSPFORMAT_UNKNOWN) ResetMSP3430(m); +else { + /*mute volume*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x00, 0x00, 0x00); +} + + + + switch(m->connector){ + case MSP3430_CONNECTOR_2: + case MSP3430_CONNECTOR_3: + if (m->c_format!=MSPFORMAT_SCART) { + /* SCART Input Prescale: 0 dB gain */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); + /* this has not been checked yet.. could be bogus */ + m->c_format=MSPFORMAT_SCART; /*stereo*/ + } + break; + case MSP3430_CONNECTOR_1: + default: + + switch ( m->standard & 0x00ff ) { + case MSP3430_PAL: + switch( m->standard ) { + case MSP3430_PAL_DK1: + standard=MSPSTANDARD_FM_DK1; + break; +/* case MSP3430_PAL_DK2: + standard=MSPSTANDARD_FM_DK2; + break; + case MSP3430_PAL_BG: + may be FM stereo (Germany) or FM NICAM (Scandinavia,spain) + standard=MSPSTANDARD_AUTO; + break; +*/ + default: + standard=MSPSTANDARD_AUTO; + } + break; + case MSP3430_SECAM: + standard=MSPSTANDARD_AUTO; + case MSP3430_NTSC: + /* Only MSP34x5 supported format - Korean NTSC-M*/ + standard=MSPSTANDARD_FM_M; + default: + standard=MSPSTANDARD_AUTO; + } + + /*no NICAM support in MSP3410D - force to autodetect*/ + if ((m->chip_id==0x405) && (standard>=MSPSTANDARD_NICAM_BG)) + standard=MSPSTANDARD_AUTO; + + if (m->c_standard != standard) { + + SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); + if (standard==MSPSTANDARD_AUTO) { + count = 50; /* time shouldn't exceed 1s, just in case */ + do { + usleep(20000); + GetMSP3430Data (m, RD_DEM, 0x00, 0x7e, &high, &low); + result = ( high << 8 ) | low; + --count; + } while( result > 0x07ff && count > 0 ); + + if ((result > MSPSTANDARD_AUTO)) + standard=result; + else standard=MSPSTANDARD_UNKNOWN; +#if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Detected audio standard: %d\n",result); +#endif + /* result = MSPSTANDARD_NICAM_L can be one of: + SECAM_L - MSPSTANDARD_NICAM_L + D/K1 - MSPSTANDARD_FM_DK1 + D/K2 - MSPSTANDARD_FM_DK2 + D/K-NICAM - MSPSTANDARD_NICAM_DK*/ + if( standard == MSPSTANDARD_NICAM_L ) { + if ((m->standard & 0x00ff)==MSP3430_PAL) { + /* force PAL D/K */ + standard=MSPSTANDARD_FM_DK1; + SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); +#if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO, "Detected 6.5MHz carrier - forced to D/K1 !!!\n" ); +#endif + } + } + } + m->c_standard=standard; + } /*end - standard changed*/ + else { + if (standard<MSPSTANDARD_NICAM_BG) { + /* get old value of ident. mode register*/ + GetMSP3430Data (m, RD_DSP, 0x00, 0x15, &high, &low); + /* reset Ident-Filter */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x3F); + /* put back old value to ident. mode register*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, low); + } + } + + if (standard<=MSPSTANDARD_AUTO) { + m->c_format=MSPFORMAT_1xFM; + } + else if (standard<MSPSTANDARD_NICAM_BG) { + /* set FM prescale */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); + /* set FM deemphasis*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, ((standard==MSPSTANDARD_FM_M)?0:1), 0); + + /* check if FM2 carrier is present */ + /*turn off FM DC Notch*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x3f); + /*matrix source for Quasi-Peak Detector - stereo: ch2->L ch1->R*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0c, 0x00, 0x20); + + mpause(250); + GetMSP3430Data (m, RD_DSP, 0x00, 0x1A, &high, &low); + peak = (high << 8) | low; +#if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Second carrier Quasi-Peak detection: %d\n",peak); +#endif + /*turn on FM DC Notch*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x00); + + if (peak<5) { + /* if second carrier not detected - only mono from first carrier*/ + m->c_format=MSPFORMAT_1xFM; + } + else { + m->c_format=MSPFORMAT_2xFM; + /*start of FM identification process - FM_WAIT + wait at least 0.5s - used 1s - gives beter resolution*/ + mpause(1000); + } + } + else { + if (standard==MSPSTANDARD_NICAM_L) { + m->c_format=MSPFORMAT_NICAM_AM; + /* set AM prescale */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x7C, 0); + } + else { + m->c_format=MSPFORMAT_NICAM_FM; + /* set FM prescale */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); + } + /* set FM deemphasis*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, 0x00, 0); + /* set NICAM prescale to 0dB */ + SetMSP3430Data (m, WR_DSP, 0x00, 0x10, 0x20, 0); + } + + break; + } /*end - case conector*/ + + CheckModeMSP34x5D(m); + + /* Set volume to FAST_MUTE. */ + /*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);*/ + /*set volume*/ + MSP3430SetVolume(m,m->volume); + + __MSPBEEP + + +} /* EnableMSP34x5D ()... */ + + + + +void CheckModeMSP34x5D(MSP3430Ptr m) { + const char stereo_on=25; + const char stereo_off=20; + const char dual_on=-stereo_on; + const char dual_off=-stereo_off; + char detect; + CARD8 matrix, fmmatrix, source, high, low; + + fmmatrix=0; /*no matrix*/ + source=0; /*FM*/ + switch (m->c_format) { + case MSPFORMAT_NICAM_FM: + case MSPFORMAT_NICAM_AM: + case MSPFORMAT_SCART: + source=( (m->c_format == MSPFORMAT_SCART)?2:1 ); + switch (m->mode) { + case MSPMODE_MONO: + matrix=0x30; /*MONO*/ + break; + case MSPMODE_A: + matrix=0x00; /*A*/ + break; + case MSPMODE_B: + matrix=0x10; /*B*/ + break; + default: + matrix=0x20; /*STEREO*/ + break; + } + break; + default: + case MSPFORMAT_1xFM: + matrix=0x00; /*A*/ + break; + case MSPFORMAT_2xFM: + switch (m->mode) { + case MSPMODE_MONO: + matrix=0x30; /*MONO*/ + break; + case MSPMODE_STEREO: + matrix=0x20; /*STEREO*/ + fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); + break; + case MSPMODE_AB: + matrix=0x20; /*STEREO*/ + break; + case MSPMODE_A: + matrix=0x00; /*A*/ + break; + case MSPMODE_B: + matrix=0x10; /*B*/ + break; + default: + /*FM_IDENT_CHECK*/ + GetMSP3430Data (m, RD_DSP, 0x00, 0x18, &high, &low); + detect=(char)high; +#if __MSPDEBUG__ > 1 + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Stereo Detection Register: %d\n",detect); +#endif + if (detect>=((m->c_mode==MSPMODE_STEREO)?stereo_off:stereo_on)) { + m->c_mode=MSPMODE_STEREO; + matrix=0x20; /*STEREO*/ + fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); + } + else if (detect<=((m->c_mode==MSPMODE_AB)?dual_off:dual_on)) { + m->c_mode=MSPMODE_AB; + switch (m->mode) { + case MSPMODE_STEREO_AB: matrix=0x20; break; + case MSPMODE_STEREO_B: matrix=0x10; break; + default: + case MSPMODE_A: matrix=0x00; break; + } + } + else { + m->c_mode=MSPMODE_MONO; + matrix=0x30; /*MONO*/ + } + break; + } /* end - case mode*/ + break; + } + + if (m->c_fmmatrix != fmmatrix) { + GetMSP3430Data (m, RD_DSP, 0x00, 0x0e, &high, &low); + SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, high, fmmatrix); + m->c_fmmatrix = fmmatrix; + } + + if ((m->c_matrix != matrix) || (m->c_source != source)) { + /*set chanel source and matrix for loudspeaker*/ + SetMSP3430Data (m, WR_DSP, 0x00, 0x08, source, matrix); + + m->c_matrix = matrix; + m->c_source = source; + } + + if ( ((m->c_format) & 0xF0) == MSPFORMAT_NICAM) + SetMSP3430Data (m, WR_DEM, 0x00, 0x21, 0, 1); + +#if __MSPDEBUG__ > 0 + char *msg; + switch (matrix) { + case 0x30: /*MONO*/ + msg="MONO"; + break; + case 0x00: /*LEFT*/ + msg="MONO/CHANNEL_1"; + break; + case 0x10: /*RIGHT*/ + msg="MONO/CHANNEL_2"; + break; + case 0x20: /*LEFT*/ + msg="STEREO"; + break; + default: + msg="unknown"; + break; + } + xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Audio mode set to: %s\n",msg); +#endif +} + diff --git a/xorg-server/hw/xfree86/i2c/tda8425.c b/xorg-server/hw/xfree86/i2c/tda8425.c index 7631a0863..abbbb2a03 100644 --- a/xorg-server/hw/xfree86/i2c/tda8425.c +++ b/xorg-server/hw/xfree86/i2c/tda8425.c @@ -1,78 +1,78 @@ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86i2c.h" -#include "tda8425.h" -#include "i2c_def.h" - -#define TDA8425(a,b) { \ - data[0]=a; \ - data[1]=b; \ - I2C_WriteRead(&(t->d), data, 2, NULL, 0); \ - } - -TDA8425Ptr Detect_tda8425(I2CBusPtr b, I2CSlaveAddr addr, Bool force) -{ - TDA8425Ptr t; - - t = xcalloc(1, sizeof(TDA8425Rec)); - if(t == NULL) return NULL; - t->d.DevName = "TDA8425 BTSC Stereo Audio Processor"; - t->d.SlaveAddr = addr; - t->d.pI2CBus = b; - t->d.NextDev = NULL; - t->d.StartTimeout = b->StartTimeout; - t->d.BitTimeout = b->BitTimeout; - t->d.AcknTimeout = b->AcknTimeout; - t->d.ByteTimeout = b->ByteTimeout; - - if(!force && !I2CProbeAddress(b, addr)) - { - xfree(t); - return NULL; - } - - /* set default parameters */ - if(!I2CDevInit(&(t->d))) - { - xfree(t); - return NULL; - } - - return t; -} - -Bool tda8425_init(TDA8425Ptr t) -{ - t->stereo = 3; /* 3 = Spacial 2 = Linear 1 = Pseudo 0 = Forced mono */ - t->v_left = 0xFF; /* FF - C0 */ - t->v_right = 0xFF; /* FF - C0 */ - t->bass = 0xF6; /* 0xFF - 0xF0 */ - t->treble = 0xF6; /* 0xFF - 0xF0 */ - t->src_sel = 3; /* 3 - stereo */ - t->mute = TRUE; - t->mux = 0; /* 0 - source one, 1 -source 2 */ - - tda8425_setaudio(t); - return TRUE; -} - -void tda8425_setaudio(TDA8425Ptr t) -{ - I2CByte data[2]; - - TDA8425(0x00, t->v_left ); - TDA8425(0x01, t->v_right ); - TDA8425(0x02, t->bass ); - TDA8425(0x03, t->treble ); - TDA8425(0x08, 0xC0 | (t->mute ? 0x20 : 0x0) | (t->stereo << 3) | (t->src_sel << 1) | - t->mux); -} - -void tda8425_mute(TDA8425Ptr t, Bool mute) -{ - t->mute = mute; - tda8425_setaudio(t); -} +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86i2c.h" +#include "tda8425.h" +#include "i2c_def.h" + +#define TDA8425(a,b) { \ + data[0]=a; \ + data[1]=b; \ + I2C_WriteRead(&(t->d), data, 2, NULL, 0); \ + } + +TDA8425Ptr Detect_tda8425(I2CBusPtr b, I2CSlaveAddr addr, Bool force) +{ + TDA8425Ptr t; + + t = calloc(1, sizeof(TDA8425Rec)); + if(t == NULL) return NULL; + t->d.DevName = "TDA8425 BTSC Stereo Audio Processor"; + t->d.SlaveAddr = addr; + t->d.pI2CBus = b; + t->d.NextDev = NULL; + t->d.StartTimeout = b->StartTimeout; + t->d.BitTimeout = b->BitTimeout; + t->d.AcknTimeout = b->AcknTimeout; + t->d.ByteTimeout = b->ByteTimeout; + + if(!force && !I2CProbeAddress(b, addr)) + { + free(t); + return NULL; + } + + /* set default parameters */ + if(!I2CDevInit(&(t->d))) + { + free(t); + return NULL; + } + + return t; +} + +Bool tda8425_init(TDA8425Ptr t) +{ + t->stereo = 3; /* 3 = Spacial 2 = Linear 1 = Pseudo 0 = Forced mono */ + t->v_left = 0xFF; /* FF - C0 */ + t->v_right = 0xFF; /* FF - C0 */ + t->bass = 0xF6; /* 0xFF - 0xF0 */ + t->treble = 0xF6; /* 0xFF - 0xF0 */ + t->src_sel = 3; /* 3 - stereo */ + t->mute = TRUE; + t->mux = 0; /* 0 - source one, 1 -source 2 */ + + tda8425_setaudio(t); + return TRUE; +} + +void tda8425_setaudio(TDA8425Ptr t) +{ + I2CByte data[2]; + + TDA8425(0x00, t->v_left ); + TDA8425(0x01, t->v_right ); + TDA8425(0x02, t->bass ); + TDA8425(0x03, t->treble ); + TDA8425(0x08, 0xC0 | (t->mute ? 0x20 : 0x0) | (t->stereo << 3) | (t->src_sel << 1) | + t->mux); +} + +void tda8425_mute(TDA8425Ptr t, Bool mute) +{ + t->mute = mute; + tda8425_setaudio(t); +} diff --git a/xorg-server/hw/xfree86/i2c/tda9850.c b/xorg-server/hw/xfree86/i2c/tda9850.c index 5b0c581ed..5d794dfe5 100644 --- a/xorg-server/hw/xfree86/i2c/tda9850.c +++ b/xorg-server/hw/xfree86/i2c/tda9850.c @@ -1,112 +1,112 @@ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86i2c.h" -#include "tda9850.h" -#include "i2c_def.h" - -#define TDA9850(a,b) { \ - data[0]=a; \ - data[1]=b; \ - I2C_WriteRead(&(t->d), data, 2, NULL, 0); \ - } - -TDA9850Ptr Detect_tda9850(I2CBusPtr b, I2CSlaveAddr addr) -{ - TDA9850Ptr t; - I2CByte a; - - t = xcalloc(1, sizeof(TDA9850Rec)); - if(t == NULL) return NULL; - switch(addr) - { - case TDA9850_ADDR_1: - t->d.DevName = "TDA9850 BTSC Stereo+SAP Audio Processor"; - break; - default: - t->d.DevName = "Generic TDAxxxx"; - break; - } - t->d.SlaveAddr = addr; - t->d.pI2CBus = b; - t->d.NextDev = NULL; - t->d.StartTimeout = b->StartTimeout; - t->d.BitTimeout = b->BitTimeout; - t->d.AcknTimeout = b->AcknTimeout; - t->d.ByteTimeout = b->ByteTimeout; - - if(!I2C_WriteRead(&(t->d), NULL, 0, &a, 1)) - { - xfree(t); - return NULL; - } - - /* set default parameters */ - if(!I2CDevInit(&(t->d))) - { - xfree(t); - return NULL; - } - - return t; -} - -Bool tda9850_init(TDA9850Ptr t) -{ - t->stereo = 1; - t->sap = 0; - t->mute = TRUE; - t->sap_mute = TRUE; - tda9850_setaudio(t); - return TRUE; -} - -void tda9850_setaudio(TDA9850Ptr t) -{ -CARD8 data[2]; - -if(t->mux==2) -{ - TDA9850(0x04,0x0F); TDA9850(0x05,0x0F); TDA9850(0x06, 0x58); - TDA9850(0x07,0x07); TDA9850(0x08,0x00); - TDA9850(0x09,0x00); TDA9850(0x0A,0x03); -} else -{ - TDA9850(0x04,0x07); TDA9850(0x05,0x07); - TDA9850(0x06,0x58); TDA9850(0x07,0x07); - TDA9850(0x08,0x10); TDA9850(0x09,0x10); - TDA9850(0x0A,0x03); -} - -TDA9850(0x06,(t->stereo<<6)|(t->sap<<7)|(t->mute?0x8:0)|(t->sap_mute?0x10:0x0)); -} - -void tda9850_mute(TDA9850Ptr t, Bool mute) -{ -CARD8 data[2]; - -xf86DrvMsg(t->d.pI2CBus->scrnIndex, X_INFO, "tda9850_mute %s\n", mute ? "on" : "off"); -t->mute = mute; - -TDA9850(0x06,(t->stereo<<6)|(t->sap<<7)|(t->mute?0x8:0x0)|(t->sap_mute?0x10:0x0)); -} - -void tda9850_sap_mute(TDA9850Ptr t, Bool sap_mute) -{ -CARD8 data[2]; - -xf86DrvMsg(t->d.pI2CBus->scrnIndex, X_INFO, "tda9850_sap_mute %s\n", sap_mute ? "on" : "off"); -t->sap_mute = sap_mute; - -TDA9850(0x06,(t->stereo<<6)|(t->sap<<7)|(t->mute?0x8:0x0)|(t->sap_mute?0x10:0x0)); -} - -CARD16 tda9850_getstatus(TDA9850Ptr t) -{ -CARD16 status; - -I2C_WriteRead(&(t->d), NULL, 0, (I2CByte *)&status, 2); -return status; -} +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86i2c.h" +#include "tda9850.h" +#include "i2c_def.h" + +#define TDA9850(a,b) { \ + data[0]=a; \ + data[1]=b; \ + I2C_WriteRead(&(t->d), data, 2, NULL, 0); \ + } + +TDA9850Ptr Detect_tda9850(I2CBusPtr b, I2CSlaveAddr addr) +{ + TDA9850Ptr t; + I2CByte a; + + t = calloc(1, sizeof(TDA9850Rec)); + if(t == NULL) return NULL; + switch(addr) + { + case TDA9850_ADDR_1: + t->d.DevName = "TDA9850 BTSC Stereo+SAP Audio Processor"; + break; + default: + t->d.DevName = "Generic TDAxxxx"; + break; + } + t->d.SlaveAddr = addr; + t->d.pI2CBus = b; + t->d.NextDev = NULL; + t->d.StartTimeout = b->StartTimeout; + t->d.BitTimeout = b->BitTimeout; + t->d.AcknTimeout = b->AcknTimeout; + t->d.ByteTimeout = b->ByteTimeout; + + if(!I2C_WriteRead(&(t->d), NULL, 0, &a, 1)) + { + free(t); + return NULL; + } + + /* set default parameters */ + if(!I2CDevInit(&(t->d))) + { + free(t); + return NULL; + } + + return t; +} + +Bool tda9850_init(TDA9850Ptr t) +{ + t->stereo = 1; + t->sap = 0; + t->mute = TRUE; + t->sap_mute = TRUE; + tda9850_setaudio(t); + return TRUE; +} + +void tda9850_setaudio(TDA9850Ptr t) +{ +CARD8 data[2]; + +if(t->mux==2) +{ + TDA9850(0x04,0x0F); TDA9850(0x05,0x0F); TDA9850(0x06, 0x58); + TDA9850(0x07,0x07); TDA9850(0x08,0x00); + TDA9850(0x09,0x00); TDA9850(0x0A,0x03); +} else +{ + TDA9850(0x04,0x07); TDA9850(0x05,0x07); + TDA9850(0x06,0x58); TDA9850(0x07,0x07); + TDA9850(0x08,0x10); TDA9850(0x09,0x10); + TDA9850(0x0A,0x03); +} + +TDA9850(0x06,(t->stereo<<6)|(t->sap<<7)|(t->mute?0x8:0)|(t->sap_mute?0x10:0x0)); +} + +void tda9850_mute(TDA9850Ptr t, Bool mute) +{ +CARD8 data[2]; + +xf86DrvMsg(t->d.pI2CBus->scrnIndex, X_INFO, "tda9850_mute %s\n", mute ? "on" : "off"); +t->mute = mute; + +TDA9850(0x06,(t->stereo<<6)|(t->sap<<7)|(t->mute?0x8:0x0)|(t->sap_mute?0x10:0x0)); +} + +void tda9850_sap_mute(TDA9850Ptr t, Bool sap_mute) +{ +CARD8 data[2]; + +xf86DrvMsg(t->d.pI2CBus->scrnIndex, X_INFO, "tda9850_sap_mute %s\n", sap_mute ? "on" : "off"); +t->sap_mute = sap_mute; + +TDA9850(0x06,(t->stereo<<6)|(t->sap<<7)|(t->mute?0x8:0x0)|(t->sap_mute?0x10:0x0)); +} + +CARD16 tda9850_getstatus(TDA9850Ptr t) +{ +CARD16 status; + +I2C_WriteRead(&(t->d), NULL, 0, (I2CByte *)&status, 2); +return status; +} diff --git a/xorg-server/hw/xfree86/i2c/tda9885.c b/xorg-server/hw/xfree86/i2c/tda9885.c index 4147dfdd7..f22233995 100644 --- a/xorg-server/hw/xfree86/i2c/tda9885.c +++ b/xorg-server/hw/xfree86/i2c/tda9885.c @@ -1,104 +1,104 @@ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86i2c.h" -#include "tda9885.h" -#include "i2c_def.h" - - -TDA9885Ptr Detect_tda9885(I2CBusPtr b, I2CSlaveAddr addr) -{ - TDA9885Ptr t; - I2CByte a; - - t = xcalloc(1, sizeof(TDA9885Rec)); - if(t == NULL) return NULL; - switch(addr) - { - case TDA9885_ADDR_1: - case TDA9885_ADDR_2: - case TDA9885_ADDR_3: - case TDA9885_ADDR_4: - t->d.DevName = "TDA9885 Alignment-free IF-PLL"; - break; - default: - t->d.DevName = "Generic TDAxxxx"; - break; - } - t->d.SlaveAddr = addr; - t->d.pI2CBus = b; - t->d.NextDev = NULL; - t->d.StartTimeout = b->StartTimeout; - t->d.BitTimeout = b->BitTimeout; - t->d.AcknTimeout = b->AcknTimeout; - t->d.ByteTimeout = b->ByteTimeout; - - if(!I2C_WriteRead(&(t->d), NULL, 0, &a, 1)) - { - xfree(t); - return NULL; - } - - /* set default parameters */ - if(!I2CDevInit(&(t->d))) - { - xfree(t); - return NULL; - } - - return t; -} - -Bool tda9885_init(TDA9885Ptr t) -{ - t->forced_mute_audio=1; - return TRUE; -} - -void tda9885_getstatus(TDA9885Ptr t) -{ -CARD8 value; - -I2C_WriteRead(&(t->d), NULL, 0, &value, 1); -t->after_reset=value & 1; -t->afc_status=(value >> 1) & 0xf; -t->fm_carrier=(value>>5)& 1; -t->vif_level=(value >>6) & 1; -t->afc_win=(value >> 7)&1; -} - -void tda9885_setparameters(TDA9885Ptr t) -{ -CARD8 data[4]; - -data[0]=0; /* start with subaddress 0 */ -data[1]=(t->sound_trap & 1) | - ((t->auto_mute_fm &1)<<1) | - ((t->carrier_mode &1)<<2) | - ((t->modulation &3)<<3) | - ((t->forced_mute_audio &1)<<5) | - ((t->port1 & 1)<<6) | - ((t->port2 &1)<<7); /* B data */ -data[2]=(t->top_adjustment & 0x1f) | - ((t->deemphasis & 0x3)<<5) | - ((t->audio_gain & 1) << 7); /* C data */ -data[3]=(t->standard_sound_carrier & 0x3) | - ((t->standard_video_if & 0x07)<<2) | - ((t->minimum_gain & 0x01)<<5) | - ((t->gating & 0x01)<<6) | - ((t->vif_agc & 0x01)<<7); /* E data */ - -I2C_WriteRead(&(t->d), data, 4, NULL, 0); - -xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"TDA9885 setparam: B data: %x, C data: %x, E data: %x\n", data[1], data[2], data[3]); -} - -void tda9885_dumpstatus(TDA9885Ptr t) -{ -xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"TDA9885 status: after_reset=%d afc_status=%d (%3.1f kHz off) fm_carrier=%d vif_level=%d afc_win=%d %s\n", - t->after_reset, t->afc_status, - (t->afc_status<8)?-12.5-t->afc_status*25.0:-12.5+(16-t->afc_status)*25.0, - t->fm_carrier, t->vif_level, t->afc_win, t->afc_win?"VCO in": "VCO out"); -} +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86i2c.h" +#include "tda9885.h" +#include "i2c_def.h" + + +TDA9885Ptr Detect_tda9885(I2CBusPtr b, I2CSlaveAddr addr) +{ + TDA9885Ptr t; + I2CByte a; + + t = calloc(1, sizeof(TDA9885Rec)); + if(t == NULL) return NULL; + switch(addr) + { + case TDA9885_ADDR_1: + case TDA9885_ADDR_2: + case TDA9885_ADDR_3: + case TDA9885_ADDR_4: + t->d.DevName = "TDA9885 Alignment-free IF-PLL"; + break; + default: + t->d.DevName = "Generic TDAxxxx"; + break; + } + t->d.SlaveAddr = addr; + t->d.pI2CBus = b; + t->d.NextDev = NULL; + t->d.StartTimeout = b->StartTimeout; + t->d.BitTimeout = b->BitTimeout; + t->d.AcknTimeout = b->AcknTimeout; + t->d.ByteTimeout = b->ByteTimeout; + + if(!I2C_WriteRead(&(t->d), NULL, 0, &a, 1)) + { + free(t); + return NULL; + } + + /* set default parameters */ + if(!I2CDevInit(&(t->d))) + { + free(t); + return NULL; + } + + return t; +} + +Bool tda9885_init(TDA9885Ptr t) +{ + t->forced_mute_audio=1; + return TRUE; +} + +void tda9885_getstatus(TDA9885Ptr t) +{ +CARD8 value; + +I2C_WriteRead(&(t->d), NULL, 0, &value, 1); +t->after_reset=value & 1; +t->afc_status=(value >> 1) & 0xf; +t->fm_carrier=(value>>5)& 1; +t->vif_level=(value >>6) & 1; +t->afc_win=(value >> 7)&1; +} + +void tda9885_setparameters(TDA9885Ptr t) +{ +CARD8 data[4]; + +data[0]=0; /* start with subaddress 0 */ +data[1]=(t->sound_trap & 1) | + ((t->auto_mute_fm &1)<<1) | + ((t->carrier_mode &1)<<2) | + ((t->modulation &3)<<3) | + ((t->forced_mute_audio &1)<<5) | + ((t->port1 & 1)<<6) | + ((t->port2 &1)<<7); /* B data */ +data[2]=(t->top_adjustment & 0x1f) | + ((t->deemphasis & 0x3)<<5) | + ((t->audio_gain & 1) << 7); /* C data */ +data[3]=(t->standard_sound_carrier & 0x3) | + ((t->standard_video_if & 0x07)<<2) | + ((t->minimum_gain & 0x01)<<5) | + ((t->gating & 0x01)<<6) | + ((t->vif_agc & 0x01)<<7); /* E data */ + +I2C_WriteRead(&(t->d), data, 4, NULL, 0); + +xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"TDA9885 setparam: B data: %x, C data: %x, E data: %x\n", data[1], data[2], data[3]); +} + +void tda9885_dumpstatus(TDA9885Ptr t) +{ +xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"TDA9885 status: after_reset=%d afc_status=%d (%3.1f kHz off) fm_carrier=%d vif_level=%d afc_win=%d %s\n", + t->after_reset, t->afc_status, + (t->afc_status<8)?-12.5-t->afc_status*25.0:-12.5+(16-t->afc_status)*25.0, + t->fm_carrier, t->vif_level, t->afc_win, t->afc_win?"VCO in": "VCO out"); +} diff --git a/xorg-server/hw/xfree86/i2c/uda1380.c b/xorg-server/hw/xfree86/i2c/uda1380.c index defda3cdc..eebe127ed 100644 --- a/xorg-server/hw/xfree86/i2c/uda1380.c +++ b/xorg-server/hw/xfree86/i2c/uda1380.c @@ -1,183 +1,183 @@ -/************************************************************************************* - * Copyright (C) 2005 Bogdan D. bogdand@users.sourceforge.net - * - * 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 AUTHOR 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 author 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 author. - * - ************************************************************************************/ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86i2c.h" -#include "uda1380.h" -#include "i2c_def.h" - -UDA1380Ptr Detect_uda1380(I2CBusPtr b, I2CSlaveAddr addr) -{ - UDA1380Ptr t; - I2CByte a; - - t = xcalloc(1, sizeof(UDA1380Rec)); - if(t == NULL) return NULL; - switch(addr) - { - case UDA1380_ADDR_1: - case UDA1380_ADDR_2: - t->d.DevName = "UDA1380 Stereo audion coder-decoder"; - break; - default: - t->d.DevName = "Generic UDAxxxx"; - break; - } - t->d.SlaveAddr = addr; - t->d.pI2CBus = b; - t->d.NextDev = NULL; - t->d.StartTimeout = b->StartTimeout; - t->d.BitTimeout = b->BitTimeout; - t->d.AcknTimeout = b->AcknTimeout; - t->d.ByteTimeout = b->ByteTimeout; - - if(!I2C_WriteRead(&(t->d), NULL, 0, &a, 1)) - { - xfree(t); - return NULL; - } - - /* set default parameters */ - if(!I2CDevInit(&(t->d))) - { - xfree(t); - return NULL; - } - - xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 stereo coder-decoder detected\n"); - - return t; -} - -Bool uda1380_init(UDA1380Ptr t) -{ - CARD8 data[3]; - CARD16 tmp; - Bool ret; - - /* Power control */ - data[0] = 0x02; - tmp = (1 << 13) | (1 << 10) | ( 1 << 8) | (1 << 7) | (1 << 6) | (1 << 3) | (1 << 1); - data[1] = (CARD8)((tmp >> 8) & 0xff); - data[2] = (CARD8)(tmp & 0xff); - ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); - if (ret == FALSE) - { - xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to initialize\n"); - return FALSE; - } - - /* Analog mixer (AVC) */ - data[0] = 0x03; - /* the analog mixer is muted initially */ - data[1] = 0x3f; - data[2] = 0x3f; - ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); - if (ret == FALSE) - { - xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to initialize\n"); - return FALSE; - } - - xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 initialized\n"); - - return TRUE; -} - -void uda1380_shutdown(UDA1380Ptr t) -{ - CARD8 data[3]; - Bool ret; - - /* Power control */ - data[0] = 0x02; - data[1] = 0; - data[2] = 0; - ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); - if (ret == FALSE) - xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to shutdown\n"); -} - -void uda1380_setvolume(UDA1380Ptr t, INT32 value) -{ - CARD8 data[3]; - /* - * We have to scale the value ranging from -1000 to 1000 to 0x2c to 0 - */ - CARD8 volume = 47 - (CARD8)((value + 1000) * 47 / 2000); - Bool ret; - - t->analog_mixer_settings = ((volume << 8) & 0x3f00) | (volume & 0x3f); - - /* Analog mixer (AVC) */ - data[0] = 0x03; - data[1] = volume & 0x3f; - data[2] = volume & 0x3f; - ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); - if (ret == FALSE) - xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to set volume\n"); -} - -void uda1380_mute(UDA1380Ptr t, Bool mute) -{ - CARD8 data[3]; - Bool ret; - - if (mute == TRUE) - { - /* Analog mixer (AVC) */ - data[0] = 0x03; - data[1] = 0xff; - data[2] = 0xff; - ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); - if (ret == FALSE) - xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to mute\n"); - } - else - { - /* Analog mixer (AVC) */ - data[0] = 0x03; - data[1] = (CARD8)((t->analog_mixer_settings >> 8) & 0x3f); - data[2] = (CARD8)(t->analog_mixer_settings & 0x3f); - ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); - if (ret == FALSE) - xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to unmute\n"); - } -} - -void uda1380_getstatus(UDA1380Ptr t) -{ -} - -void uda1380_setparameters(UDA1380Ptr t) -{ -} - -void uda1380_dumpstatus(UDA1380Ptr t) -{ -} +/************************************************************************************* + * Copyright (C) 2005 Bogdan D. bogdand@users.sourceforge.net + * + * 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 AUTHOR 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 author 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 author. + * + ************************************************************************************/ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86i2c.h" +#include "uda1380.h" +#include "i2c_def.h" + +UDA1380Ptr Detect_uda1380(I2CBusPtr b, I2CSlaveAddr addr) +{ + UDA1380Ptr t; + I2CByte a; + + t = calloc(1, sizeof(UDA1380Rec)); + if(t == NULL) return NULL; + switch(addr) + { + case UDA1380_ADDR_1: + case UDA1380_ADDR_2: + t->d.DevName = "UDA1380 Stereo audion coder-decoder"; + break; + default: + t->d.DevName = "Generic UDAxxxx"; + break; + } + t->d.SlaveAddr = addr; + t->d.pI2CBus = b; + t->d.NextDev = NULL; + t->d.StartTimeout = b->StartTimeout; + t->d.BitTimeout = b->BitTimeout; + t->d.AcknTimeout = b->AcknTimeout; + t->d.ByteTimeout = b->ByteTimeout; + + if(!I2C_WriteRead(&(t->d), NULL, 0, &a, 1)) + { + free(t); + return NULL; + } + + /* set default parameters */ + if(!I2CDevInit(&(t->d))) + { + free(t); + return NULL; + } + + xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 stereo coder-decoder detected\n"); + + return t; +} + +Bool uda1380_init(UDA1380Ptr t) +{ + CARD8 data[3]; + CARD16 tmp; + Bool ret; + + /* Power control */ + data[0] = 0x02; + tmp = (1 << 13) | (1 << 10) | ( 1 << 8) | (1 << 7) | (1 << 6) | (1 << 3) | (1 << 1); + data[1] = (CARD8)((tmp >> 8) & 0xff); + data[2] = (CARD8)(tmp & 0xff); + ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); + if (ret == FALSE) + { + xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to initialize\n"); + return FALSE; + } + + /* Analog mixer (AVC) */ + data[0] = 0x03; + /* the analog mixer is muted initially */ + data[1] = 0x3f; + data[2] = 0x3f; + ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); + if (ret == FALSE) + { + xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to initialize\n"); + return FALSE; + } + + xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 initialized\n"); + + return TRUE; +} + +void uda1380_shutdown(UDA1380Ptr t) +{ + CARD8 data[3]; + Bool ret; + + /* Power control */ + data[0] = 0x02; + data[1] = 0; + data[2] = 0; + ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); + if (ret == FALSE) + xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to shutdown\n"); +} + +void uda1380_setvolume(UDA1380Ptr t, INT32 value) +{ + CARD8 data[3]; + /* + * We have to scale the value ranging from -1000 to 1000 to 0x2c to 0 + */ + CARD8 volume = 47 - (CARD8)((value + 1000) * 47 / 2000); + Bool ret; + + t->analog_mixer_settings = ((volume << 8) & 0x3f00) | (volume & 0x3f); + + /* Analog mixer (AVC) */ + data[0] = 0x03; + data[1] = volume & 0x3f; + data[2] = volume & 0x3f; + ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); + if (ret == FALSE) + xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to set volume\n"); +} + +void uda1380_mute(UDA1380Ptr t, Bool mute) +{ + CARD8 data[3]; + Bool ret; + + if (mute == TRUE) + { + /* Analog mixer (AVC) */ + data[0] = 0x03; + data[1] = 0xff; + data[2] = 0xff; + ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); + if (ret == FALSE) + xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to mute\n"); + } + else + { + /* Analog mixer (AVC) */ + data[0] = 0x03; + data[1] = (CARD8)((t->analog_mixer_settings >> 8) & 0x3f); + data[2] = (CARD8)(t->analog_mixer_settings & 0x3f); + ret = I2C_WriteRead(&(t->d), data, 3, NULL, 0); + if (ret == FALSE) + xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"UDA1380 failed to unmute\n"); + } +} + +void uda1380_getstatus(UDA1380Ptr t) +{ +} + +void uda1380_setparameters(UDA1380Ptr t) +{ +} + +void uda1380_dumpstatus(UDA1380Ptr t) +{ +} diff --git a/xorg-server/hw/xfree86/i2c/xf86i2c.c b/xorg-server/hw/xfree86/i2c/xf86i2c.c index 59832d6f9..488b6815f 100644 --- a/xorg-server/hw/xfree86/i2c/xf86i2c.c +++ b/xorg-server/hw/xfree86/i2c/xf86i2c.c @@ -1,866 +1,866 @@ -/* - * Copyright (C) 1998 Itai Nahshon, Michael Schimek - * - * The original code was derived from and inspired by - * the I2C driver from the Linux kernel. - * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> - */ - - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <sys/time.h> -#include <string.h> - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include <X11/Xos.h> -#include <X11/Xproto.h> -#include "scrnintstr.h" -#include "regionstr.h" -#include "windowstr.h" -#include "pixmapstr.h" -#include "validate.h" -#include "resource.h" -#include "gcstruct.h" -#include "dixstruct.h" - -#include "xf86i2c.h" - -#define I2C_TIMEOUT(x) /*(x)*/ /* Report timeouts */ -#define I2C_TRACE(x) /*(x)*/ /* Report progress */ - -/* This is the default I2CUDelay function if not supplied by the driver. - * High level I2C interfaces implementing the bus protocol in hardware - * should supply this function too. - * - * Delay execution at least usec microseconds. - * All values 0 to 1e6 inclusive must be expected. - */ - -static void -I2CUDelay(I2CBusPtr b, int usec) -{ - struct timeval begin, cur; - long d_secs, d_usecs; - long diff; - - if (usec > 0) { - X_GETTIMEOFDAY(&begin); - do { - /* It would be nice to use {xf86}usleep, - * but usleep (1) takes >10000 usec ! - */ - X_GETTIMEOFDAY(&cur); - d_secs = (cur.tv_sec - begin.tv_sec); - d_usecs = (cur.tv_usec - begin.tv_usec); - diff = d_secs*1000000 + d_usecs; - } while (diff>=0 && diff< (usec + 1)); - } -} - -/* Most drivers will register just with GetBits/PutBits functions. - * The following functions implement a software I2C protocol - * by using the promitive functions given by the driver. - * ================================================================ - * - * It is assumed that there is just one master on the I2C bus, therefore - * there is no explicit test for conflits. - */ - -#define RISEFALLTIME 2 /* usec, actually 300 to 1000 ns according to the i2c specs */ - -/* Some devices will hold SCL low to slow down the bus or until - * ready for transmission. - * - * This condition will be noticed when the master tries to raise - * the SCL line. You can set the timeout to zero if the slave device - * does not support this clock synchronization. - */ - -static Bool -I2CRaiseSCL(I2CBusPtr b, int sda, int timeout) -{ - int i, scl; - - b->I2CPutBits(b, 1, sda); - b->I2CUDelay(b, b->RiseFallTime); - - for (i = timeout; i > 0; i -= b->RiseFallTime) { - b->I2CGetBits(b, &scl, &sda); - if (scl) break; - b->I2CUDelay(b, b->RiseFallTime); - } - - if (i <= 0) { - I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d, %d) timeout]", b->BusName, sda, timeout)); - return FALSE; - } - - return TRUE; -} - -/* Send a start signal on the I2C bus. The start signal notifies - * devices that a new transaction is initiated by the bus master. - * - * The start signal is always followed by a slave address. - * Slave addresses are 8+ bits. The first 7 bits identify the - * device and the last bit signals if this is a read (1) or - * write (0) operation. - * - * There may be more than one start signal on one transaction. - * This happens for example on some devices that allow reading - * of registers. First send a start bit followed by the device - * address (with the last bit 0) and the register number. Then send - * a new start bit with the device address (with the last bit 1) - * and then read the value from the device. - * - * Note this is function does not implement a multiple master - * arbitration procedure. - */ - -static Bool -I2CStart(I2CBusPtr b, int timeout) -{ - if (!I2CRaiseSCL(b, 1, timeout)) - return FALSE; - - b->I2CPutBits(b, 1, 0); - b->I2CUDelay(b, b->HoldTime); - b->I2CPutBits(b, 0, 0); - b->I2CUDelay(b, b->HoldTime); - - I2C_TRACE(ErrorF("\ni2c: <")); - - return TRUE; -} - -/* This is the default I2CStop function if not supplied by the driver. - * - * Signal devices on the I2C bus that a transaction on the - * bus has finished. There may be more than one start signal - * on a transaction but only one stop signal. - */ - -static void -I2CStop(I2CDevPtr d) -{ - I2CBusPtr b = d->pI2CBus; - - b->I2CPutBits(b, 0, 0); - b->I2CUDelay(b, b->RiseFallTime); - - b->I2CPutBits(b, 1, 0); - b->I2CUDelay(b, b->HoldTime); - b->I2CPutBits(b, 1, 1); - b->I2CUDelay(b, b->HoldTime); - - I2C_TRACE(ErrorF(">\n")); -} - -/* Write/Read a single bit to/from a device. - * Return FALSE if a timeout occurs. - */ - -static Bool -I2CWriteBit(I2CBusPtr b, int sda, int timeout) -{ - Bool r; - - b->I2CPutBits(b, 0, sda); - b->I2CUDelay(b, b->RiseFallTime); - - r = I2CRaiseSCL(b, sda, timeout); - b->I2CUDelay(b, b->HoldTime); - - b->I2CPutBits(b, 0, sda); - b->I2CUDelay(b, b->HoldTime); - - return r; -} - -static Bool -I2CReadBit(I2CBusPtr b, int *psda, int timeout) -{ - Bool r; - int scl; - - r = I2CRaiseSCL(b, 1, timeout); - b->I2CUDelay(b, b->HoldTime); - - b->I2CGetBits(b, &scl, psda); - - b->I2CPutBits(b, 0, 1); - b->I2CUDelay(b, b->HoldTime); - - return r; -} - -/* This is the default I2CPutByte function if not supplied by the driver. - * - * A single byte is sent to the device. - * The function returns FALSE if a timeout occurs, you should send - * a stop condition afterwards to reset the bus. - * - * A timeout occurs, - * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, - * or slows down the bus for more than BitTimeout usecs for each bit, - * or does not send an ACK bit (0) to acknowledge the transmission within - * AcknTimeout usecs, but a NACK (1) bit. - * - * AcknTimeout must be at least b->HoldTime, the other timeouts can be - * zero according to the comment on I2CRaiseSCL. - */ - -static Bool -I2CPutByte(I2CDevPtr d, I2CByte data) -{ - Bool r; - int i, scl, sda; - I2CBusPtr b = d->pI2CBus; - - if (!I2CWriteBit(b, (data >> 7) & 1, d->ByteTimeout)) - return FALSE; - - for (i = 6; i >= 0; i--) - if (!I2CWriteBit(b, (data >> i) & 1, d->BitTimeout)) - return FALSE; - - b->I2CPutBits(b, 0, 1); - b->I2CUDelay(b, b->RiseFallTime); - - r = I2CRaiseSCL(b, 1, b->HoldTime); - - if (r) { - for (i = d->AcknTimeout; i > 0; i -= b->HoldTime) { - b->I2CUDelay(b, b->HoldTime); - b->I2CGetBits(b, &scl, &sda); - if (sda == 0) break; - } - - if (i <= 0) { - I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]", - b->BusName, data, d->BitTimeout, - d->ByteTimeout, d->AcknTimeout)); - r = FALSE; - } - - I2C_TRACE(ErrorF("W%02x%c ", (int) data, sda ? '-' : '+')); - } - - b->I2CPutBits(b, 0, 1); - b->I2CUDelay(b, b->HoldTime); - - return r; -} - -/* This is the default I2CGetByte function if not supplied by the driver. - * - * A single byte is read from the device. - * The function returns FALSE if a timeout occurs, you should send - * a stop condition afterwards to reset the bus. - * - * A timeout occurs, - * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, - * or slows down the bus for more than b->BitTimeout usecs for each bit. - * - * ByteTimeout must be at least b->HoldTime, the other timeouts can be - * zero according to the comment on I2CRaiseSCL. - * - * For the <last> byte in a sequence the acknowledge bit NACK (1), - * otherwise ACK (0) will be sent. - */ - -static Bool -I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) -{ - int i, sda; - I2CBusPtr b = d->pI2CBus; - - b->I2CPutBits(b, 0, 1); - b->I2CUDelay(b, b->RiseFallTime); - - if (!I2CReadBit(b, &sda, d->ByteTimeout)) - return FALSE; - - *data = (sda > 0) << 7; - - for (i = 6; i >= 0; i--) - if (!I2CReadBit(b, &sda, d->BitTimeout)) - return FALSE; - else - *data |= (sda > 0) << i; - - if (!I2CWriteBit(b, last ? 1 : 0, d->BitTimeout)) - return FALSE; - - I2C_TRACE(ErrorF("R%02x%c ", (int) *data, last ? '+' : '-')); - - return TRUE; -} - -/* This is the default I2CAddress function if not supplied by the driver. - * - * It creates the start condition, followed by the d->SlaveAddr. - * Higher level functions must call this routine rather than - * I2CStart/PutByte because a hardware I2C master may not be able - * to send a slave address without a start condition. - * - * The same timeouts apply as with I2CPutByte and additional a - * StartTimeout, similar to the ByteTimeout but for the start - * condition. - * - * In case of a timeout, the bus is left in a clean idle condition. - * I. e. you *must not* send a Stop. If this function succeeds, you *must*. - * - * The slave address format is 16 bit, with the legacy _8_bit_ slave address - * in the least significant byte. This is, the slave address must include the - * R/_W flag as least significant bit. - * - * The most significant byte of the address will be sent _after_ the LSB, - * but only if the LSB indicates: - * a) an 11 bit address, this is LSB = 1111 0xxx. - * b) a 'general call address', this is LSB = 0000 000x - see the I2C specs - * for more. - */ - -static Bool -I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) -{ - if (I2CStart(d->pI2CBus, d->StartTimeout)) { - if (I2CPutByte(d, addr & 0xFF)) { - if ((addr & 0xF8) != 0xF0 && - (addr & 0xFE) != 0x00) - return TRUE; - - if (I2CPutByte(d, (addr >> 8) & 0xFF)) - return TRUE; - } - - I2CStop(d); - } - - return FALSE; -} - -/* These are the hardware independent I2C helper functions. - * ======================================================== - */ - -/* Function for probing. Just send the slave address - * and return true if the device responds. The slave address - * must have the lsb set to reflect a read (1) or write (0) access. - * Don't expect a read- or write-only device will respond otherwise. - */ - -Bool -xf86I2CProbeAddress(I2CBusPtr b, I2CSlaveAddr addr) -{ - int r; - I2CDevRec d; - - d.DevName = "Probing"; - d.BitTimeout = b->BitTimeout; - d.ByteTimeout = b->ByteTimeout; - d.AcknTimeout = b->AcknTimeout; - d.StartTimeout = b->StartTimeout; - d.SlaveAddr = addr; - d.pI2CBus = b; - d.NextDev = NULL; - - r = b->I2CAddress(&d, addr); - - if (r) b->I2CStop(&d); - - return r; -} - -/* All functions below are related to devices and take the - * slave address and timeout values from an I2CDevRec. They - * return FALSE in case of an error (presumably a timeout). - */ - -/* General purpose read and write function. - * - * 1st, if nWrite > 0 - * Send a start condition - * Send the slave address (1 or 2 bytes) with write flag - * Write n bytes from WriteBuffer - * 2nd, if nRead > 0 - * Send a start condition [again] - * Send the slave address (1 or 2 bytes) with read flag - * Read n bytes to ReadBuffer - * 3rd, if a Start condition has been successfully sent, - * Send a Stop condition. - * - * The functions exits immediately when an error occures, - * not proceeding any data left. However, step 3 will - * be executed anyway to leave the bus in clean idle state. - */ - -static Bool -I2CWriteRead(I2CDevPtr d, - I2CByte *WriteBuffer, int nWrite, - I2CByte *ReadBuffer, int nRead) -{ - Bool r = TRUE; - I2CBusPtr b = d->pI2CBus; - int s = 0; - - if (r && nWrite > 0) { - r = b->I2CAddress(d, d->SlaveAddr & ~1); - if (r) { - for (; nWrite > 0; WriteBuffer++, nWrite--) - if (!(r = b->I2CPutByte(d, *WriteBuffer))) - break; - s++; - } - } - - if (r && nRead > 0) { - r = b->I2CAddress(d, d->SlaveAddr | 1); - if (r) { - for (; nRead > 0; ReadBuffer++, nRead--) - if (!(r = b->I2CGetByte(d, ReadBuffer, nRead == 1))) - break; - s++; - } - } - - if (s) b->I2CStop(d); - - return r; -} - -/* wrapper - for compatibility and convinience */ - -Bool -xf86I2CWriteRead(I2CDevPtr d, - I2CByte *WriteBuffer, int nWrite, - I2CByte *ReadBuffer, int nRead) -{ - I2CBusPtr b = d->pI2CBus; - return b->I2CWriteRead(d,WriteBuffer,nWrite,ReadBuffer,nRead); -} - -/* Read a byte, the only readable register of a device. - */ - -Bool -xf86I2CReadStatus(I2CDevPtr d, I2CByte *pbyte) -{ - return xf86I2CWriteRead(d, NULL, 0, pbyte, 1); -} - -/* Read a byte from one of the registers determined by its sub-address. - */ - -Bool -xf86I2CReadByte(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte) -{ - return xf86I2CWriteRead(d, &subaddr, 1, pbyte, 1); -} - -/* Read bytes from subsequent registers determined by the - * sub-address of the first register. - */ - -Bool -xf86I2CReadBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte, int n) -{ - return xf86I2CWriteRead(d, &subaddr, 1, pbyte, n); -} - -/* Read a word (high byte, then low byte) from one of the registers - * determined by its sub-address. - */ - -Bool -xf86I2CReadWord(I2CDevPtr d, I2CByte subaddr, unsigned short *pword) -{ - I2CByte rb[2]; - - if (!xf86I2CWriteRead(d, &subaddr, 1, rb, 2)) return FALSE; - - *pword = (rb[0] << 8) | rb[1]; - - return TRUE; -} - -/* Write a byte to one of the registers determined by its sub-address. - */ - -Bool -xf86I2CWriteByte(I2CDevPtr d, I2CByte subaddr, I2CByte byte) -{ - I2CByte wb[2]; - - wb[0] = subaddr; - wb[1] = byte; - - return xf86I2CWriteRead(d, wb, 2, NULL, 0); -} - -/* Write bytes to subsequent registers determined by the - * sub-address of the first register. - */ - -Bool -xf86I2CWriteBytes(I2CDevPtr d, I2CByte subaddr, - I2CByte *WriteBuffer, int nWrite) -{ - I2CBusPtr b = d->pI2CBus; - Bool r = TRUE; - - if (nWrite > 0) { - r = b->I2CAddress(d, d->SlaveAddr & ~1); - if (r){ - if ((r = b->I2CPutByte(d, subaddr))) - for (; nWrite > 0; WriteBuffer++, nWrite--) - if (!(r = b->I2CPutByte(d, *WriteBuffer))) - break; - - b->I2CStop(d); - } - } - - return r; -} - -/* Write a word (high byte, then low byte) to one of the registers - * determined by its sub-address. - */ - -Bool -xf86I2CWriteWord(I2CDevPtr d, I2CByte subaddr, unsigned short word) -{ - I2CByte wb[3]; - - wb[0] = subaddr; - wb[1] = word >> 8; - wb[2] = word & 0xFF; - - return xf86I2CWriteRead(d, wb, 3, NULL, 0); -} - -/* Write a vector of bytes to not adjacent registers. This vector is, - * 1st byte sub-address, 2nd byte value, 3rd byte sub-address asf. - * This function is intended to initialize devices. Note this function - * exits immediately when an error occurs, some registers may - * remain uninitialized. - */ - -Bool -xf86I2CWriteVec(I2CDevPtr d, I2CByte *vec, int nValues) -{ - I2CBusPtr b = d->pI2CBus; - Bool r = TRUE; - int s = 0; - - if (nValues > 0) { - for (; nValues > 0; nValues--, vec += 2) { - if (!(r = b->I2CAddress(d, d->SlaveAddr & ~1))) - break; - - s++; - - if (!(r = b->I2CPutByte(d, vec[0]))) - break; - - if (!(r = b->I2CPutByte(d, vec[1]))) - break; - } - - if (s > 0) b->I2CStop(d); - } - - return r; -} - -/* Administrative functions. - * ========================= - */ - -/* Allocates an I2CDevRec for you and initializes with propper defaults - * you may modify before calling xf86I2CDevInit. Your I2CDevRec must - * contain at least a SlaveAddr, and a pI2CBus pointer to the bus this - * device shall be linked to. - * - * See function I2CAddress for the slave address format. Always set - * the least significant bit, indicating a read or write access, to zero. - */ - -I2CDevPtr -xf86CreateI2CDevRec(void) -{ - return xcalloc(1, sizeof(I2CDevRec)); -} - -/* Unlink an I2C device. If you got the I2CDevRec from xf86CreateI2CDevRec - * you should set <unalloc> to free it. - */ - -void -xf86DestroyI2CDevRec(I2CDevPtr d, Bool unalloc) -{ - if (d) { - I2CDevPtr *p; - - /* Remove this from the list of active I2C devices. */ - - for (p = &d->pI2CBus->FirstDev; *p != NULL; p = &(*p)->NextDev) - if (*p == d) { - *p = (*p)->NextDev; - break; - } - - xf86DrvMsg(d->pI2CBus->scrnIndex, X_INFO, - "I2C device \"%s:%s\" removed.\n", - d->pI2CBus->BusName, d->DevName); - - if (unalloc) xfree(d); - } -} - -/* I2C transmissions are related to an I2CDevRec you must link to a - * previously registered bus (see xf86I2CBusInit) before attempting - * to read and write data. You may call xf86I2CProbeAddress first to - * see if the device in question is present on this bus. - * - * xf86I2CDevInit will not allocate an I2CBusRec for you, instead you - * may enter a pointer to a statically allocated I2CDevRec or the (modified) - * result of xf86CreateI2CDevRec. - * - * If you don't specify timeouts for the device (n <= 0), it will inherit - * the bus-wide defaults. The function returns TRUE on success. - */ - -Bool -xf86I2CDevInit(I2CDevPtr d) -{ - I2CBusPtr b; - - if (d == NULL || - (b = d->pI2CBus) == NULL || - (d->SlaveAddr & 1) || - xf86I2CFindDev(b, d->SlaveAddr) != NULL) - return FALSE; - - if (d->BitTimeout <= 0) d->BitTimeout = b->BitTimeout; - if (d->ByteTimeout <= 0) d->ByteTimeout = b->ByteTimeout; - if (d->AcknTimeout <= 0) d->AcknTimeout = b->AcknTimeout; - if (d->StartTimeout <= 0) d->StartTimeout = b->StartTimeout; - - d->NextDev = b->FirstDev; - b->FirstDev = d; - - xf86DrvMsg(b->scrnIndex, X_INFO, - "I2C device \"%s:%s\" registered at address 0x%02X.\n", - b->BusName, d->DevName, d->SlaveAddr); - - return TRUE; -} - -I2CDevPtr -xf86I2CFindDev(I2CBusPtr b, I2CSlaveAddr addr) -{ - I2CDevPtr d; - - if (b) { - for (d = b->FirstDev; d != NULL; d = d->NextDev) - if (d->SlaveAddr == addr) - return d; - } - - return NULL; -} - -static I2CBusPtr I2CBusList; - -/* Allocates an I2CBusRec for you and initializes with propper defaults - * you may modify before calling xf86I2CBusInit. Your I2CBusRec must - * contain at least a BusName, a scrnIndex (or -1), and a complete set - * of either high or low level I2C function pointers. You may pass - * bus-wide timeouts, otherwise inplausible values will be replaced - * with safe defaults. - */ - -I2CBusPtr -xf86CreateI2CBusRec(void) -{ - I2CBusPtr b; - - b = (I2CBusPtr) xcalloc(1, sizeof(I2CBusRec)); - - if (b != NULL) { - b->scrnIndex = -1; - b->HoldTime = 5; /* 100 kHz bus */ - b->BitTimeout = 5; - b->ByteTimeout = 5; - b->AcknTimeout = 5; - b->StartTimeout = 5; - b->RiseFallTime = RISEFALLTIME; - } - - return b; -} - -/* Unregister an I2C bus. If you got the I2CBusRec from xf86CreateI2CBusRec - * you should set <unalloc> to free it. If you set <devs_too>, the function - * xf86DestroyI2CDevRec will be called for all devices linked to the bus - * first, passing down the <unalloc> option. - */ - -void -xf86DestroyI2CBusRec(I2CBusPtr b, Bool unalloc, Bool devs_too) -{ - if (b) { - I2CBusPtr *p; - - /* Remove this from the list of active I2C buses */ - - for (p = &I2CBusList; *p != NULL; p = &(*p)->NextBus) - if (*p == b) { - *p = (*p)->NextBus; - break; - } - - if (b->FirstDev != NULL) { - if (devs_too) { - I2CDevPtr d; - - while ((d = b->FirstDev) != NULL) { - b->FirstDev = d->NextDev; - xf86DestroyI2CDevRec(d, unalloc); - } - } else { - if (unalloc) { - xf86Msg(X_ERROR, "i2c bug: Attempt to remove I2C bus \"%s\", " - "but device list is not empty.\n", - b->BusName); - return; - } - } - } - - xf86DrvMsg(b->scrnIndex, X_INFO, "I2C bus \"%s\" removed.\n", - b->BusName); - - if (unalloc) xfree(b); - } -} - -/* I2C masters have to register themselves using this function. - * It will not allocate an I2CBusRec for you, instead you may enter - * a pointer to a statically allocated I2CBusRec or the (modified) - * result of xf86CreateI2CBusRec. Returns TRUE on success. - * - * At this point there won't be any traffic on the I2C bus. - */ - -Bool -xf86I2CBusInit(I2CBusPtr b) -{ - /* I2C buses must be identified by a unique scrnIndex - * and name. If scrnIndex is unspecified (a negative value), - * then the name must be unique throughout the server. - */ - - if (b->BusName == NULL || - xf86I2CFindBus(b->scrnIndex, b->BusName) != NULL) - return FALSE; - - /* If the high level functions are not - * supplied, use the generic functions. - * In this case we need the low-level - * function. - */ - if (b->I2CWriteRead == NULL) - { - b->I2CWriteRead=I2CWriteRead; - - if (b->I2CPutBits == NULL || - b->I2CGetBits == NULL) - { - if (b->I2CPutByte == NULL || - b->I2CGetByte == NULL || - b->I2CAddress == NULL || - b->I2CStart == NULL || - b->I2CStop == NULL) - return FALSE; - } else { - b->I2CPutByte = I2CPutByte; - b->I2CGetByte = I2CGetByte; - b->I2CAddress = I2CAddress; - b->I2CStop = I2CStop; - b->I2CStart = I2CStart; - } - } - - if (b->I2CUDelay == NULL) - b->I2CUDelay = I2CUDelay; - - if (b->HoldTime < 2) b->HoldTime = 5; - if (b->BitTimeout <= 0) b->BitTimeout = b->HoldTime; - if (b->ByteTimeout <= 0) b->ByteTimeout = b->HoldTime; - if (b->AcknTimeout <= 0) b->AcknTimeout = b->HoldTime; - if (b->StartTimeout <= 0) b->StartTimeout = b->HoldTime; - - /* Put new bus on list. */ - - b->NextBus = I2CBusList; - I2CBusList = b; - - xf86DrvMsg(b->scrnIndex, X_INFO, "I2C bus \"%s\" initialized.\n", - b->BusName); - - return TRUE; -} - -I2CBusPtr -xf86I2CFindBus(int scrnIndex, char *name) -{ - I2CBusPtr p; - - if (name != NULL) - for (p = I2CBusList; p != NULL; p = p->NextBus) - if (scrnIndex < 0 || p->scrnIndex == scrnIndex) - if (!strcmp(p->BusName, name)) - return p; - - return NULL; -} - -/* - * Return an array of I2CBusPtr's related to a screen. The caller is - * responsible for freeing the array. - */ -int -xf86I2CGetScreenBuses(int scrnIndex, I2CBusPtr **pppI2CBus) -{ - I2CBusPtr pI2CBus; - int n = 0; - - if (pppI2CBus) - *pppI2CBus = NULL; - - for (pI2CBus = I2CBusList; pI2CBus; pI2CBus = pI2CBus->NextBus) { - if ((pI2CBus->scrnIndex >= 0) && (pI2CBus->scrnIndex != scrnIndex)) - continue; - - n++; - - if (!pppI2CBus) - continue; - - *pppI2CBus = xnfrealloc(*pppI2CBus, n * sizeof(I2CBusPtr)); - (*pppI2CBus)[n - 1] = pI2CBus; - } - - return n; -} +/* + * Copyright (C) 1998 Itai Nahshon, Michael Schimek + * + * The original code was derived from and inspired by + * the I2C driver from the Linux kernel. + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + */ + + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <sys/time.h> +#include <string.h> + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include <X11/Xos.h> +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "regionstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "validate.h" +#include "resource.h" +#include "gcstruct.h" +#include "dixstruct.h" + +#include "xf86i2c.h" + +#define I2C_TIMEOUT(x) /*(x)*/ /* Report timeouts */ +#define I2C_TRACE(x) /*(x)*/ /* Report progress */ + +/* This is the default I2CUDelay function if not supplied by the driver. + * High level I2C interfaces implementing the bus protocol in hardware + * should supply this function too. + * + * Delay execution at least usec microseconds. + * All values 0 to 1e6 inclusive must be expected. + */ + +static void +I2CUDelay(I2CBusPtr b, int usec) +{ + struct timeval begin, cur; + long d_secs, d_usecs; + long diff; + + if (usec > 0) { + X_GETTIMEOFDAY(&begin); + do { + /* It would be nice to use {xf86}usleep, + * but usleep (1) takes >10000 usec ! + */ + X_GETTIMEOFDAY(&cur); + d_secs = (cur.tv_sec - begin.tv_sec); + d_usecs = (cur.tv_usec - begin.tv_usec); + diff = d_secs*1000000 + d_usecs; + } while (diff>=0 && diff< (usec + 1)); + } +} + +/* Most drivers will register just with GetBits/PutBits functions. + * The following functions implement a software I2C protocol + * by using the promitive functions given by the driver. + * ================================================================ + * + * It is assumed that there is just one master on the I2C bus, therefore + * there is no explicit test for conflits. + */ + +#define RISEFALLTIME 2 /* usec, actually 300 to 1000 ns according to the i2c specs */ + +/* Some devices will hold SCL low to slow down the bus or until + * ready for transmission. + * + * This condition will be noticed when the master tries to raise + * the SCL line. You can set the timeout to zero if the slave device + * does not support this clock synchronization. + */ + +static Bool +I2CRaiseSCL(I2CBusPtr b, int sda, int timeout) +{ + int i, scl; + + b->I2CPutBits(b, 1, sda); + b->I2CUDelay(b, b->RiseFallTime); + + for (i = timeout; i > 0; i -= b->RiseFallTime) { + b->I2CGetBits(b, &scl, &sda); + if (scl) break; + b->I2CUDelay(b, b->RiseFallTime); + } + + if (i <= 0) { + I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d, %d) timeout]", b->BusName, sda, timeout)); + return FALSE; + } + + return TRUE; +} + +/* Send a start signal on the I2C bus. The start signal notifies + * devices that a new transaction is initiated by the bus master. + * + * The start signal is always followed by a slave address. + * Slave addresses are 8+ bits. The first 7 bits identify the + * device and the last bit signals if this is a read (1) or + * write (0) operation. + * + * There may be more than one start signal on one transaction. + * This happens for example on some devices that allow reading + * of registers. First send a start bit followed by the device + * address (with the last bit 0) and the register number. Then send + * a new start bit with the device address (with the last bit 1) + * and then read the value from the device. + * + * Note this is function does not implement a multiple master + * arbitration procedure. + */ + +static Bool +I2CStart(I2CBusPtr b, int timeout) +{ + if (!I2CRaiseSCL(b, 1, timeout)) + return FALSE; + + b->I2CPutBits(b, 1, 0); + b->I2CUDelay(b, b->HoldTime); + b->I2CPutBits(b, 0, 0); + b->I2CUDelay(b, b->HoldTime); + + I2C_TRACE(ErrorF("\ni2c: <")); + + return TRUE; +} + +/* This is the default I2CStop function if not supplied by the driver. + * + * Signal devices on the I2C bus that a transaction on the + * bus has finished. There may be more than one start signal + * on a transaction but only one stop signal. + */ + +static void +I2CStop(I2CDevPtr d) +{ + I2CBusPtr b = d->pI2CBus; + + b->I2CPutBits(b, 0, 0); + b->I2CUDelay(b, b->RiseFallTime); + + b->I2CPutBits(b, 1, 0); + b->I2CUDelay(b, b->HoldTime); + b->I2CPutBits(b, 1, 1); + b->I2CUDelay(b, b->HoldTime); + + I2C_TRACE(ErrorF(">\n")); +} + +/* Write/Read a single bit to/from a device. + * Return FALSE if a timeout occurs. + */ + +static Bool +I2CWriteBit(I2CBusPtr b, int sda, int timeout) +{ + Bool r; + + b->I2CPutBits(b, 0, sda); + b->I2CUDelay(b, b->RiseFallTime); + + r = I2CRaiseSCL(b, sda, timeout); + b->I2CUDelay(b, b->HoldTime); + + b->I2CPutBits(b, 0, sda); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +static Bool +I2CReadBit(I2CBusPtr b, int *psda, int timeout) +{ + Bool r; + int scl; + + r = I2CRaiseSCL(b, 1, timeout); + b->I2CUDelay(b, b->HoldTime); + + b->I2CGetBits(b, &scl, psda); + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +/* This is the default I2CPutByte function if not supplied by the driver. + * + * A single byte is sent to the device. + * The function returns FALSE if a timeout occurs, you should send + * a stop condition afterwards to reset the bus. + * + * A timeout occurs, + * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, + * or slows down the bus for more than BitTimeout usecs for each bit, + * or does not send an ACK bit (0) to acknowledge the transmission within + * AcknTimeout usecs, but a NACK (1) bit. + * + * AcknTimeout must be at least b->HoldTime, the other timeouts can be + * zero according to the comment on I2CRaiseSCL. + */ + +static Bool +I2CPutByte(I2CDevPtr d, I2CByte data) +{ + Bool r; + int i, scl, sda; + I2CBusPtr b = d->pI2CBus; + + if (!I2CWriteBit(b, (data >> 7) & 1, d->ByteTimeout)) + return FALSE; + + for (i = 6; i >= 0; i--) + if (!I2CWriteBit(b, (data >> i) & 1, d->BitTimeout)) + return FALSE; + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->RiseFallTime); + + r = I2CRaiseSCL(b, 1, b->HoldTime); + + if (r) { + for (i = d->AcknTimeout; i > 0; i -= b->HoldTime) { + b->I2CUDelay(b, b->HoldTime); + b->I2CGetBits(b, &scl, &sda); + if (sda == 0) break; + } + + if (i <= 0) { + I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]", + b->BusName, data, d->BitTimeout, + d->ByteTimeout, d->AcknTimeout)); + r = FALSE; + } + + I2C_TRACE(ErrorF("W%02x%c ", (int) data, sda ? '-' : '+')); + } + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +/* This is the default I2CGetByte function if not supplied by the driver. + * + * A single byte is read from the device. + * The function returns FALSE if a timeout occurs, you should send + * a stop condition afterwards to reset the bus. + * + * A timeout occurs, + * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, + * or slows down the bus for more than b->BitTimeout usecs for each bit. + * + * ByteTimeout must be at least b->HoldTime, the other timeouts can be + * zero according to the comment on I2CRaiseSCL. + * + * For the <last> byte in a sequence the acknowledge bit NACK (1), + * otherwise ACK (0) will be sent. + */ + +static Bool +I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) +{ + int i, sda; + I2CBusPtr b = d->pI2CBus; + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->RiseFallTime); + + if (!I2CReadBit(b, &sda, d->ByteTimeout)) + return FALSE; + + *data = (sda > 0) << 7; + + for (i = 6; i >= 0; i--) + if (!I2CReadBit(b, &sda, d->BitTimeout)) + return FALSE; + else + *data |= (sda > 0) << i; + + if (!I2CWriteBit(b, last ? 1 : 0, d->BitTimeout)) + return FALSE; + + I2C_TRACE(ErrorF("R%02x%c ", (int) *data, last ? '+' : '-')); + + return TRUE; +} + +/* This is the default I2CAddress function if not supplied by the driver. + * + * It creates the start condition, followed by the d->SlaveAddr. + * Higher level functions must call this routine rather than + * I2CStart/PutByte because a hardware I2C master may not be able + * to send a slave address without a start condition. + * + * The same timeouts apply as with I2CPutByte and additional a + * StartTimeout, similar to the ByteTimeout but for the start + * condition. + * + * In case of a timeout, the bus is left in a clean idle condition. + * I. e. you *must not* send a Stop. If this function succeeds, you *must*. + * + * The slave address format is 16 bit, with the legacy _8_bit_ slave address + * in the least significant byte. This is, the slave address must include the + * R/_W flag as least significant bit. + * + * The most significant byte of the address will be sent _after_ the LSB, + * but only if the LSB indicates: + * a) an 11 bit address, this is LSB = 1111 0xxx. + * b) a 'general call address', this is LSB = 0000 000x - see the I2C specs + * for more. + */ + +static Bool +I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) +{ + if (I2CStart(d->pI2CBus, d->StartTimeout)) { + if (I2CPutByte(d, addr & 0xFF)) { + if ((addr & 0xF8) != 0xF0 && + (addr & 0xFE) != 0x00) + return TRUE; + + if (I2CPutByte(d, (addr >> 8) & 0xFF)) + return TRUE; + } + + I2CStop(d); + } + + return FALSE; +} + +/* These are the hardware independent I2C helper functions. + * ======================================================== + */ + +/* Function for probing. Just send the slave address + * and return true if the device responds. The slave address + * must have the lsb set to reflect a read (1) or write (0) access. + * Don't expect a read- or write-only device will respond otherwise. + */ + +Bool +xf86I2CProbeAddress(I2CBusPtr b, I2CSlaveAddr addr) +{ + int r; + I2CDevRec d; + + d.DevName = "Probing"; + d.BitTimeout = b->BitTimeout; + d.ByteTimeout = b->ByteTimeout; + d.AcknTimeout = b->AcknTimeout; + d.StartTimeout = b->StartTimeout; + d.SlaveAddr = addr; + d.pI2CBus = b; + d.NextDev = NULL; + + r = b->I2CAddress(&d, addr); + + if (r) b->I2CStop(&d); + + return r; +} + +/* All functions below are related to devices and take the + * slave address and timeout values from an I2CDevRec. They + * return FALSE in case of an error (presumably a timeout). + */ + +/* General purpose read and write function. + * + * 1st, if nWrite > 0 + * Send a start condition + * Send the slave address (1 or 2 bytes) with write flag + * Write n bytes from WriteBuffer + * 2nd, if nRead > 0 + * Send a start condition [again] + * Send the slave address (1 or 2 bytes) with read flag + * Read n bytes to ReadBuffer + * 3rd, if a Start condition has been successfully sent, + * Send a Stop condition. + * + * The functions exits immediately when an error occures, + * not proceeding any data left. However, step 3 will + * be executed anyway to leave the bus in clean idle state. + */ + +static Bool +I2CWriteRead(I2CDevPtr d, + I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead) +{ + Bool r = TRUE; + I2CBusPtr b = d->pI2CBus; + int s = 0; + + if (r && nWrite > 0) { + r = b->I2CAddress(d, d->SlaveAddr & ~1); + if (r) { + for (; nWrite > 0; WriteBuffer++, nWrite--) + if (!(r = b->I2CPutByte(d, *WriteBuffer))) + break; + s++; + } + } + + if (r && nRead > 0) { + r = b->I2CAddress(d, d->SlaveAddr | 1); + if (r) { + for (; nRead > 0; ReadBuffer++, nRead--) + if (!(r = b->I2CGetByte(d, ReadBuffer, nRead == 1))) + break; + s++; + } + } + + if (s) b->I2CStop(d); + + return r; +} + +/* wrapper - for compatibility and convinience */ + +Bool +xf86I2CWriteRead(I2CDevPtr d, + I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead) +{ + I2CBusPtr b = d->pI2CBus; + return b->I2CWriteRead(d,WriteBuffer,nWrite,ReadBuffer,nRead); +} + +/* Read a byte, the only readable register of a device. + */ + +Bool +xf86I2CReadStatus(I2CDevPtr d, I2CByte *pbyte) +{ + return xf86I2CWriteRead(d, NULL, 0, pbyte, 1); +} + +/* Read a byte from one of the registers determined by its sub-address. + */ + +Bool +xf86I2CReadByte(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte) +{ + return xf86I2CWriteRead(d, &subaddr, 1, pbyte, 1); +} + +/* Read bytes from subsequent registers determined by the + * sub-address of the first register. + */ + +Bool +xf86I2CReadBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte, int n) +{ + return xf86I2CWriteRead(d, &subaddr, 1, pbyte, n); +} + +/* Read a word (high byte, then low byte) from one of the registers + * determined by its sub-address. + */ + +Bool +xf86I2CReadWord(I2CDevPtr d, I2CByte subaddr, unsigned short *pword) +{ + I2CByte rb[2]; + + if (!xf86I2CWriteRead(d, &subaddr, 1, rb, 2)) return FALSE; + + *pword = (rb[0] << 8) | rb[1]; + + return TRUE; +} + +/* Write a byte to one of the registers determined by its sub-address. + */ + +Bool +xf86I2CWriteByte(I2CDevPtr d, I2CByte subaddr, I2CByte byte) +{ + I2CByte wb[2]; + + wb[0] = subaddr; + wb[1] = byte; + + return xf86I2CWriteRead(d, wb, 2, NULL, 0); +} + +/* Write bytes to subsequent registers determined by the + * sub-address of the first register. + */ + +Bool +xf86I2CWriteBytes(I2CDevPtr d, I2CByte subaddr, + I2CByte *WriteBuffer, int nWrite) +{ + I2CBusPtr b = d->pI2CBus; + Bool r = TRUE; + + if (nWrite > 0) { + r = b->I2CAddress(d, d->SlaveAddr & ~1); + if (r){ + if ((r = b->I2CPutByte(d, subaddr))) + for (; nWrite > 0; WriteBuffer++, nWrite--) + if (!(r = b->I2CPutByte(d, *WriteBuffer))) + break; + + b->I2CStop(d); + } + } + + return r; +} + +/* Write a word (high byte, then low byte) to one of the registers + * determined by its sub-address. + */ + +Bool +xf86I2CWriteWord(I2CDevPtr d, I2CByte subaddr, unsigned short word) +{ + I2CByte wb[3]; + + wb[0] = subaddr; + wb[1] = word >> 8; + wb[2] = word & 0xFF; + + return xf86I2CWriteRead(d, wb, 3, NULL, 0); +} + +/* Write a vector of bytes to not adjacent registers. This vector is, + * 1st byte sub-address, 2nd byte value, 3rd byte sub-address asf. + * This function is intended to initialize devices. Note this function + * exits immediately when an error occurs, some registers may + * remain uninitialized. + */ + +Bool +xf86I2CWriteVec(I2CDevPtr d, I2CByte *vec, int nValues) +{ + I2CBusPtr b = d->pI2CBus; + Bool r = TRUE; + int s = 0; + + if (nValues > 0) { + for (; nValues > 0; nValues--, vec += 2) { + if (!(r = b->I2CAddress(d, d->SlaveAddr & ~1))) + break; + + s++; + + if (!(r = b->I2CPutByte(d, vec[0]))) + break; + + if (!(r = b->I2CPutByte(d, vec[1]))) + break; + } + + if (s > 0) b->I2CStop(d); + } + + return r; +} + +/* Administrative functions. + * ========================= + */ + +/* Allocates an I2CDevRec for you and initializes with propper defaults + * you may modify before calling xf86I2CDevInit. Your I2CDevRec must + * contain at least a SlaveAddr, and a pI2CBus pointer to the bus this + * device shall be linked to. + * + * See function I2CAddress for the slave address format. Always set + * the least significant bit, indicating a read or write access, to zero. + */ + +I2CDevPtr +xf86CreateI2CDevRec(void) +{ + return calloc(1, sizeof(I2CDevRec)); +} + +/* Unlink an I2C device. If you got the I2CDevRec from xf86CreateI2CDevRec + * you should set <unalloc> to free it. + */ + +void +xf86DestroyI2CDevRec(I2CDevPtr d, Bool unalloc) +{ + if (d) { + I2CDevPtr *p; + + /* Remove this from the list of active I2C devices. */ + + for (p = &d->pI2CBus->FirstDev; *p != NULL; p = &(*p)->NextDev) + if (*p == d) { + *p = (*p)->NextDev; + break; + } + + xf86DrvMsg(d->pI2CBus->scrnIndex, X_INFO, + "I2C device \"%s:%s\" removed.\n", + d->pI2CBus->BusName, d->DevName); + + if (unalloc) free(d); + } +} + +/* I2C transmissions are related to an I2CDevRec you must link to a + * previously registered bus (see xf86I2CBusInit) before attempting + * to read and write data. You may call xf86I2CProbeAddress first to + * see if the device in question is present on this bus. + * + * xf86I2CDevInit will not allocate an I2CBusRec for you, instead you + * may enter a pointer to a statically allocated I2CDevRec or the (modified) + * result of xf86CreateI2CDevRec. + * + * If you don't specify timeouts for the device (n <= 0), it will inherit + * the bus-wide defaults. The function returns TRUE on success. + */ + +Bool +xf86I2CDevInit(I2CDevPtr d) +{ + I2CBusPtr b; + + if (d == NULL || + (b = d->pI2CBus) == NULL || + (d->SlaveAddr & 1) || + xf86I2CFindDev(b, d->SlaveAddr) != NULL) + return FALSE; + + if (d->BitTimeout <= 0) d->BitTimeout = b->BitTimeout; + if (d->ByteTimeout <= 0) d->ByteTimeout = b->ByteTimeout; + if (d->AcknTimeout <= 0) d->AcknTimeout = b->AcknTimeout; + if (d->StartTimeout <= 0) d->StartTimeout = b->StartTimeout; + + d->NextDev = b->FirstDev; + b->FirstDev = d; + + xf86DrvMsg(b->scrnIndex, X_INFO, + "I2C device \"%s:%s\" registered at address 0x%02X.\n", + b->BusName, d->DevName, d->SlaveAddr); + + return TRUE; +} + +I2CDevPtr +xf86I2CFindDev(I2CBusPtr b, I2CSlaveAddr addr) +{ + I2CDevPtr d; + + if (b) { + for (d = b->FirstDev; d != NULL; d = d->NextDev) + if (d->SlaveAddr == addr) + return d; + } + + return NULL; +} + +static I2CBusPtr I2CBusList; + +/* Allocates an I2CBusRec for you and initializes with propper defaults + * you may modify before calling xf86I2CBusInit. Your I2CBusRec must + * contain at least a BusName, a scrnIndex (or -1), and a complete set + * of either high or low level I2C function pointers. You may pass + * bus-wide timeouts, otherwise inplausible values will be replaced + * with safe defaults. + */ + +I2CBusPtr +xf86CreateI2CBusRec(void) +{ + I2CBusPtr b; + + b = (I2CBusPtr) calloc(1, sizeof(I2CBusRec)); + + if (b != NULL) { + b->scrnIndex = -1; + b->HoldTime = 5; /* 100 kHz bus */ + b->BitTimeout = 5; + b->ByteTimeout = 5; + b->AcknTimeout = 5; + b->StartTimeout = 5; + b->RiseFallTime = RISEFALLTIME; + } + + return b; +} + +/* Unregister an I2C bus. If you got the I2CBusRec from xf86CreateI2CBusRec + * you should set <unalloc> to free it. If you set <devs_too>, the function + * xf86DestroyI2CDevRec will be called for all devices linked to the bus + * first, passing down the <unalloc> option. + */ + +void +xf86DestroyI2CBusRec(I2CBusPtr b, Bool unalloc, Bool devs_too) +{ + if (b) { + I2CBusPtr *p; + + /* Remove this from the list of active I2C buses */ + + for (p = &I2CBusList; *p != NULL; p = &(*p)->NextBus) + if (*p == b) { + *p = (*p)->NextBus; + break; + } + + if (b->FirstDev != NULL) { + if (devs_too) { + I2CDevPtr d; + + while ((d = b->FirstDev) != NULL) { + b->FirstDev = d->NextDev; + xf86DestroyI2CDevRec(d, unalloc); + } + } else { + if (unalloc) { + xf86Msg(X_ERROR, "i2c bug: Attempt to remove I2C bus \"%s\", " + "but device list is not empty.\n", + b->BusName); + return; + } + } + } + + xf86DrvMsg(b->scrnIndex, X_INFO, "I2C bus \"%s\" removed.\n", + b->BusName); + + if (unalloc) free(b); + } +} + +/* I2C masters have to register themselves using this function. + * It will not allocate an I2CBusRec for you, instead you may enter + * a pointer to a statically allocated I2CBusRec or the (modified) + * result of xf86CreateI2CBusRec. Returns TRUE on success. + * + * At this point there won't be any traffic on the I2C bus. + */ + +Bool +xf86I2CBusInit(I2CBusPtr b) +{ + /* I2C buses must be identified by a unique scrnIndex + * and name. If scrnIndex is unspecified (a negative value), + * then the name must be unique throughout the server. + */ + + if (b->BusName == NULL || + xf86I2CFindBus(b->scrnIndex, b->BusName) != NULL) + return FALSE; + + /* If the high level functions are not + * supplied, use the generic functions. + * In this case we need the low-level + * function. + */ + if (b->I2CWriteRead == NULL) + { + b->I2CWriteRead=I2CWriteRead; + + if (b->I2CPutBits == NULL || + b->I2CGetBits == NULL) + { + if (b->I2CPutByte == NULL || + b->I2CGetByte == NULL || + b->I2CAddress == NULL || + b->I2CStart == NULL || + b->I2CStop == NULL) + return FALSE; + } else { + b->I2CPutByte = I2CPutByte; + b->I2CGetByte = I2CGetByte; + b->I2CAddress = I2CAddress; + b->I2CStop = I2CStop; + b->I2CStart = I2CStart; + } + } + + if (b->I2CUDelay == NULL) + b->I2CUDelay = I2CUDelay; + + if (b->HoldTime < 2) b->HoldTime = 5; + if (b->BitTimeout <= 0) b->BitTimeout = b->HoldTime; + if (b->ByteTimeout <= 0) b->ByteTimeout = b->HoldTime; + if (b->AcknTimeout <= 0) b->AcknTimeout = b->HoldTime; + if (b->StartTimeout <= 0) b->StartTimeout = b->HoldTime; + + /* Put new bus on list. */ + + b->NextBus = I2CBusList; + I2CBusList = b; + + xf86DrvMsg(b->scrnIndex, X_INFO, "I2C bus \"%s\" initialized.\n", + b->BusName); + + return TRUE; +} + +I2CBusPtr +xf86I2CFindBus(int scrnIndex, char *name) +{ + I2CBusPtr p; + + if (name != NULL) + for (p = I2CBusList; p != NULL; p = p->NextBus) + if (scrnIndex < 0 || p->scrnIndex == scrnIndex) + if (!strcmp(p->BusName, name)) + return p; + + return NULL; +} + +/* + * Return an array of I2CBusPtr's related to a screen. The caller is + * responsible for freeing the array. + */ +int +xf86I2CGetScreenBuses(int scrnIndex, I2CBusPtr **pppI2CBus) +{ + I2CBusPtr pI2CBus; + int n = 0; + + if (pppI2CBus) + *pppI2CBus = NULL; + + for (pI2CBus = I2CBusList; pI2CBus; pI2CBus = pI2CBus->NextBus) { + if ((pI2CBus->scrnIndex >= 0) && (pI2CBus->scrnIndex != scrnIndex)) + continue; + + n++; + + if (!pppI2CBus) + continue; + + *pppI2CBus = xnfrealloc(*pppI2CBus, n * sizeof(I2CBusPtr)); + (*pppI2CBus)[n - 1] = pI2CBus; + } + + return n; +} diff --git a/xorg-server/hw/xfree86/int10/generic.c b/xorg-server/hw/xfree86/int10/generic.c index 9d39e99b0..c242405cc 100644 --- a/xorg-server/hw/xfree86/int10/generic.c +++ b/xorg-server/hw/xfree86/int10/generic.c @@ -1,494 +1,494 @@ -/* - * XFree86 int10 module - * execute BIOS int 10h calls in x86 real mode environment - * Copyright 1999 Egbert Eich - */ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> -#include <unistd.h> - -#include "xf86.h" -#include "xf86_OSproc.h" -#include "compiler.h" -#define _INT10_PRIVATE -#include "xf86int10.h" -#include "int10Defines.h" -#include "Pci.h" - -#define ALLOC_ENTRIES(x) ((V_RAM / x) - 1) - -static CARD8 read_b(xf86Int10InfoPtr pInt,int addr); -static CARD16 read_w(xf86Int10InfoPtr pInt,int addr); -static CARD32 read_l(xf86Int10InfoPtr pInt,int addr); -static void write_b(xf86Int10InfoPtr pInt,int addr, CARD8 val); -static void write_w(xf86Int10InfoPtr pInt,int addr, CARD16 val); -static void write_l(xf86Int10InfoPtr pInt,int addr, CARD32 val); - -/* - * the emulator cannot pass a pointer to the current xf86Int10InfoRec - * to the memory access functions therefore store it here. - */ - -typedef struct { - int shift; - int entries; - void* base; - void* vRam; - int highMemory; - void* sysMem; - char* alloc; -} genericInt10Priv; - -#define INTPriv(x) ((genericInt10Priv*)x->private) - -int10MemRec genericMem = { - read_b, - read_w, - read_l, - write_b, - write_w, - write_l -}; - -static void MapVRam(xf86Int10InfoPtr pInt); -static void UnmapVRam(xf86Int10InfoPtr pInt); -#ifdef _PC -#define GET_HIGH_BASE(x) (((V_BIOS + (x) + getpagesize() - 1)/getpagesize()) \ - * getpagesize()) -#endif - -static void *sysMem = NULL; - -/** - * Read legacy VGA video BIOS associated with specified domain. - * - * Attempts to read up to 128KiB of legacy VGA video BIOS. - * - * \return - * The number of bytes read on success or -1 on failure. - * - * \bug - * PCI ROMs can contain multiple BIOS images (e.g., OpenFirmware, x86 VGA, - * etc.). How do we know that \c pci_device_read_rom will return the - * legacy VGA BIOS image? - */ -#ifndef _PC -static int -read_legacy_video_BIOS(struct pci_device *dev, unsigned char *Buf) -{ - const ADDRESS Base = 0xC0000; - const int Len = 0x10000 * 2; - const int pagemask = getpagesize() - 1; - const ADDRESS offset = Base & ~pagemask; - const unsigned long size = ((Base + Len + pagemask) & ~pagemask) - offset; - unsigned char *ptr, *src; - int len; - - - /* Try to use the civilized PCI interface first. - */ - if (pci_device_read_rom(dev, Buf) == 0) { - return dev->rom_size; - } - - ptr = xf86MapDomainMemory(-1, VIDMEM_READONLY, dev, offset, size); - - if (!ptr) - return -1; - - /* Using memcpy() here can hang the system */ - src = ptr + (Base - offset); - for (len = 0; len < (Len / 2); len++) { - Buf[len] = src[len]; - } - - if ((Buf[0] == 0x55) && (Buf[1] == 0xAA) && (Buf[2] > 0x80)) { - for ( /* empty */ ; len < Len; len++) { - Buf[len] = src[len]; - } - } - - xf86UnMapVidMem(-1, ptr, size); - - return Len; -} -#endif /* _PC */ - - -xf86Int10InfoPtr -xf86ExtendedInitInt10(int entityIndex, int Flags) -{ - xf86Int10InfoPtr pInt; - void* base = 0; - void* vbiosMem = 0; - void* options = NULL; - int screen; - legacyVGARec vga; - -#if 0 - CARD32 cs; -#endif - - screen = (xf86FindScreenForEntity(entityIndex))->scrnIndex; - - options = xf86HandleInt10Options(xf86Screens[screen],entityIndex); - - if (int10skip(options)) { - xfree(options); - return NULL; - } - - pInt = (xf86Int10InfoPtr)xnfcalloc(1, sizeof(xf86Int10InfoRec)); - pInt->entityIndex = entityIndex; - if (!xf86Int10ExecSetup(pInt)) - goto error0; - pInt->mem = &genericMem; - pInt->private = (pointer)xnfcalloc(1, sizeof(genericInt10Priv)); - INTPriv(pInt)->alloc = (pointer)xnfcalloc(1, ALLOC_ENTRIES(getpagesize())); - pInt->scrnIndex = screen; - base = INTPriv(pInt)->base = xnfalloc(SYS_BIOS); - - /* FIXME: Shouldn't this be a failure case? Leaving dev as NULL seems like - * FIXME: an error - */ - pInt->dev = xf86GetPciInfoForEntity(entityIndex); - - /* - * we need to map video RAM MMIO as some chipsets map mmio - * registers into this range. - */ - MapVRam(pInt); -#ifdef _PC - if (!sysMem) - sysMem = xf86MapVidMem(screen, VIDMEM_MMIO, V_BIOS, - BIOS_SIZE + SYS_BIOS - V_BIOS); - INTPriv(pInt)->sysMem = sysMem; - - if (xf86ReadBIOS(0, 0, base, LOW_PAGE_SIZE) < 0) { - xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n"); - goto error1; - } - - /* - * Retrieve everything between V_BIOS and SYS_BIOS as some system BIOSes - * have executable code there. Note that xf86ReadBIOS() can only read in - * 64kB at a time. - */ - memset((char *)base + V_BIOS, 0, SYS_BIOS - V_BIOS); -#if 0 - for (cs = V_BIOS; cs < SYS_BIOS; cs += V_BIOS_SIZE) - if (xf86ReadBIOS(cs, 0, (unsigned char *)base + cs, V_BIOS_SIZE) < - V_BIOS_SIZE) - xf86DrvMsg(screen, X_WARNING, - "Unable to retrieve all of segment 0x%06X.\n", cs); -#endif - INTPriv(pInt)->highMemory = V_BIOS; - - if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) { - if (!xf86int10GetBiosSegment(pInt, (unsigned char *)sysMem - V_BIOS)) - goto error1; - - set_return_trap(pInt); - - pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); - if (! (pInt->Flags & SET_BIOS_SCRATCH)) - pInt->Flags &= ~RESTORE_BIOS_SCRATCH; - xf86Int10SaveRestoreBIOSVars(pInt, TRUE); - - } else { - const BusType location_type = xf86int10GetBiosLocationType(pInt); - int bios_location = V_BIOS; - - reset_int_vect(pInt); - set_return_trap(pInt); - - switch (location_type) { - case BUS_PCI: { - int err; - struct pci_device *rom_device = - xf86GetPciInfoForEntity(pInt->entityIndex); - - vbiosMem = (unsigned char *)base + bios_location; - err = pci_device_read_rom(rom_device, vbiosMem); - if (err) { - xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (3) %s\n", - strerror(err)); - goto error1; - } - INTPriv(pInt)->highMemory = GET_HIGH_BASE(rom_device->rom_size); - break; - } - default: - goto error1; - } - pInt->BIOSseg = V_BIOS >> 4; - pInt->num = 0xe6; - LockLegacyVGA(pInt, &vga); - xf86ExecX86int10(pInt); - UnlockLegacyVGA(pInt, &vga); - } -#else - if (!sysMem) { - sysMem = xnfalloc(BIOS_SIZE); - setup_system_bios(sysMem); - } - INTPriv(pInt)->sysMem = sysMem; - setup_int_vect(pInt); - set_return_trap(pInt); - - /* Retrieve the entire legacy video BIOS segment. This can be upto - * 128KiB. - */ - vbiosMem = (char *)base + V_BIOS; - memset(vbiosMem, 0, 2 * V_BIOS_SIZE); - if (read_legacy_video_BIOS(pInt->dev, vbiosMem) < V_BIOS_SIZE) { - xf86DrvMsg(screen, X_WARNING, - "Unable to retrieve all of segment 0x0C0000.\n"); - } - - /* - * If this adapter is the primary, use its post-init BIOS (if we can find - * it). - */ - { - int bios_location = V_BIOS; - Bool done = FALSE; - vbiosMem = (unsigned char *)base + bios_location; - - if (xf86IsEntityPrimary(entityIndex)) { - if (int10_check_bios(screen, bios_location >> 4, vbiosMem)) - done = TRUE; - else - xf86DrvMsg(screen,X_INFO, - "No legacy BIOS found -- trying PCI\n"); - } - if (!done) { - int err; - struct pci_device *rom_device = - xf86GetPciInfoForEntity(pInt->entityIndex); - - err = pci_device_read_rom(rom_device, vbiosMem); - if (err) { - xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (5) %s\n", - strerror(err)); - goto error1; - } - } - } - - pInt->BIOSseg = V_BIOS >> 4; - pInt->num = 0xe6; - LockLegacyVGA(pInt, &vga); - xf86ExecX86int10(pInt); - UnlockLegacyVGA(pInt, &vga); -#endif - xfree(options); - return pInt; - - error1: - xfree(base); - UnmapVRam(pInt); - xfree(INTPriv(pInt)->alloc); - xfree(pInt->private); - error0: - xfree(pInt); - xfree(options); - - return NULL; -} - -static void -MapVRam(xf86Int10InfoPtr pInt) -{ - int pagesize = getpagesize(); - int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize; - - INTPriv(pInt)->vRam = xf86MapDomainMemory(pInt->scrnIndex, VIDMEM_MMIO, - pInt->dev, V_RAM, size); - - pInt->ioBase = xf86Screens[pInt->scrnIndex]->domainIOBase; -} - -static void -UnmapVRam(xf86Int10InfoPtr pInt) -{ - int screen = pInt->scrnIndex; - int pagesize = getpagesize(); - int size = ((VRAM_SIZE + pagesize - 1)/pagesize) * pagesize; - - xf86UnMapVidMem(screen, INTPriv(pInt)->vRam, size); -} - -Bool -MapCurrentInt10(xf86Int10InfoPtr pInt) -{ - /* nothing to do here */ - return TRUE; -} - -void -xf86FreeInt10(xf86Int10InfoPtr pInt) -{ - if (!pInt) - return; -#if defined (_PC) - xf86Int10SaveRestoreBIOSVars(pInt, FALSE); -#endif - if (Int10Current == pInt) - Int10Current = NULL; - xfree(INTPriv(pInt)->base); - UnmapVRam(pInt); - xfree(INTPriv(pInt)->alloc); - xfree(pInt->private); - xfree(pInt); -} - -void * -xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off) -{ - int pagesize = getpagesize(); - int num_pages = ALLOC_ENTRIES(pagesize); - int i,j; - - for (i = 0; i < (num_pages - num); i++) { - if (INTPriv(pInt)->alloc[i] == 0) { - for (j = i; j < (num + i); j++) - if (INTPriv(pInt)->alloc[j] != 0) - break; - if (j == (num + i)) - break; - i += num; - } - } - if (i == (num_pages - num)) - return NULL; - - for (j = i; j < (i + num); j++) - INTPriv(pInt)->alloc[j] = 1; - - *off = (i + 1) * pagesize; - - return (char *)INTPriv(pInt)->base + *off; -} - -void -xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) -{ - int pagesize = getpagesize(); - int first = (((char *)pbase - (char *)INTPriv(pInt)->base) / pagesize) - 1; - int i; - - for (i = first; i < (first + num); i++) - INTPriv(pInt)->alloc[i] = 0; -} - -#define OFF(addr) ((addr) & 0xffff) -#if defined _PC -# define HIGH_OFFSET (INTPriv(pInt)->highMemory) -# define HIGH_BASE V_BIOS -#else -# define HIGH_OFFSET SYS_BIOS -# define HIGH_BASE SYS_BIOS -#endif -# define SYS(addr) ((addr) >= HIGH_OFFSET) -#define V_ADDR(addr) \ - (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \ - : (((char*)(INTPriv(pInt)->base) + addr))) -#define VRAM_ADDR(addr) (addr - V_RAM) -#define VRAM_BASE (INTPriv(pInt)->vRam) - -#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE))) -#define V_ADDR_RB(addr) \ - (VRAM(addr)) ? MMIO_IN8((CARD8*)VRAM_BASE,VRAM_ADDR(addr)) \ - : *(CARD8*) V_ADDR(addr) -#define V_ADDR_RW(addr) \ - (VRAM(addr)) ? MMIO_IN16((CARD16*)VRAM_BASE,VRAM_ADDR(addr)) \ - : ldw_u((pointer)V_ADDR(addr)) -#define V_ADDR_RL(addr) \ - (VRAM(addr)) ? MMIO_IN32((CARD32*)VRAM_BASE,VRAM_ADDR(addr)) \ - : ldl_u((pointer)V_ADDR(addr)) - -#define V_ADDR_WB(addr,val) \ - if(VRAM(addr)) \ - MMIO_OUT8((CARD8*)VRAM_BASE,VRAM_ADDR(addr),val); \ - else \ - *(CARD8*) V_ADDR(addr) = val; -#define V_ADDR_WW(addr,val) \ - if(VRAM(addr)) \ - MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); \ - else \ - stw_u((val),(pointer)(V_ADDR(addr))); - -#define V_ADDR_WL(addr,val) \ - if (VRAM(addr)) \ - MMIO_OUT32((CARD32*)VRAM_BASE,VRAM_ADDR(addr),val); \ - else \ - stl_u(val,(pointer)(V_ADDR(addr))); - -static CARD8 -read_b(xf86Int10InfoPtr pInt, int addr) -{ - return V_ADDR_RB(addr); -} - -static CARD16 -read_w(xf86Int10InfoPtr pInt, int addr) -{ -#if X_BYTE_ORDER == X_LITTLE_ENDIAN - if (OFF(addr + 1) > 0) - return V_ADDR_RW(addr); -#endif - return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8); -} - -static CARD32 -read_l(xf86Int10InfoPtr pInt, int addr) -{ -#if X_BYTE_ORDER == X_LITTLE_ENDIAN - if (OFF(addr + 3) > 2) - return V_ADDR_RL(addr); -#endif - return V_ADDR_RB(addr) | - (V_ADDR_RB(addr + 1) << 8) | - (V_ADDR_RB(addr + 2) << 16) | - (V_ADDR_RB(addr + 3) << 24); -} - -static void -write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val) -{ - V_ADDR_WB(addr,val); -} - -static void -write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val) -{ -#if X_BYTE_ORDER == X_LITTLE_ENDIAN - if (OFF(addr + 1) > 0) - { V_ADDR_WW(addr, val); } -#endif - V_ADDR_WB(addr, val); - V_ADDR_WB(addr + 1, val >> 8); -} - -static void -write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val) -{ -#if X_BYTE_ORDER == X_LITTLE_ENDIAN - if (OFF(addr + 3) > 2) - { V_ADDR_WL(addr, val); } -#endif - V_ADDR_WB(addr, val); - V_ADDR_WB(addr + 1, val >> 8); - V_ADDR_WB(addr + 2, val >> 16); - V_ADDR_WB(addr + 3, val >> 24); -} - -pointer -xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr) -{ - return V_ADDR(addr); -} +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> +#include <unistd.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#define _INT10_PRIVATE +#include "xf86int10.h" +#include "int10Defines.h" +#include "Pci.h" + +#define ALLOC_ENTRIES(x) ((V_RAM / x) - 1) + +static CARD8 read_b(xf86Int10InfoPtr pInt,int addr); +static CARD16 read_w(xf86Int10InfoPtr pInt,int addr); +static CARD32 read_l(xf86Int10InfoPtr pInt,int addr); +static void write_b(xf86Int10InfoPtr pInt,int addr, CARD8 val); +static void write_w(xf86Int10InfoPtr pInt,int addr, CARD16 val); +static void write_l(xf86Int10InfoPtr pInt,int addr, CARD32 val); + +/* + * the emulator cannot pass a pointer to the current xf86Int10InfoRec + * to the memory access functions therefore store it here. + */ + +typedef struct { + int shift; + int entries; + void* base; + void* vRam; + int highMemory; + void* sysMem; + char* alloc; +} genericInt10Priv; + +#define INTPriv(x) ((genericInt10Priv*)x->private) + +int10MemRec genericMem = { + read_b, + read_w, + read_l, + write_b, + write_w, + write_l +}; + +static void MapVRam(xf86Int10InfoPtr pInt); +static void UnmapVRam(xf86Int10InfoPtr pInt); +#ifdef _PC +#define GET_HIGH_BASE(x) (((V_BIOS + (x) + getpagesize() - 1)/getpagesize()) \ + * getpagesize()) +#endif + +static void *sysMem = NULL; + +/** + * Read legacy VGA video BIOS associated with specified domain. + * + * Attempts to read up to 128KiB of legacy VGA video BIOS. + * + * \return + * The number of bytes read on success or -1 on failure. + * + * \bug + * PCI ROMs can contain multiple BIOS images (e.g., OpenFirmware, x86 VGA, + * etc.). How do we know that \c pci_device_read_rom will return the + * legacy VGA BIOS image? + */ +#ifndef _PC +static int +read_legacy_video_BIOS(struct pci_device *dev, unsigned char *Buf) +{ + const ADDRESS Base = 0xC0000; + const int Len = 0x10000 * 2; + const int pagemask = getpagesize() - 1; + const ADDRESS offset = Base & ~pagemask; + const unsigned long size = ((Base + Len + pagemask) & ~pagemask) - offset; + unsigned char *ptr, *src; + int len; + + + /* Try to use the civilized PCI interface first. + */ + if (pci_device_read_rom(dev, Buf) == 0) { + return dev->rom_size; + } + + ptr = xf86MapDomainMemory(-1, VIDMEM_READONLY, dev, offset, size); + + if (!ptr) + return -1; + + /* Using memcpy() here can hang the system */ + src = ptr + (Base - offset); + for (len = 0; len < (Len / 2); len++) { + Buf[len] = src[len]; + } + + if ((Buf[0] == 0x55) && (Buf[1] == 0xAA) && (Buf[2] > 0x80)) { + for ( /* empty */ ; len < Len; len++) { + Buf[len] = src[len]; + } + } + + xf86UnMapVidMem(-1, ptr, size); + + return Len; +} +#endif /* _PC */ + + +xf86Int10InfoPtr +xf86ExtendedInitInt10(int entityIndex, int Flags) +{ + xf86Int10InfoPtr pInt; + void* base = 0; + void* vbiosMem = 0; + void* options = NULL; + int screen; + legacyVGARec vga; + +#if 0 + CARD32 cs; +#endif + + screen = (xf86FindScreenForEntity(entityIndex))->scrnIndex; + + options = xf86HandleInt10Options(xf86Screens[screen],entityIndex); + + if (int10skip(options)) { + free(options); + return NULL; + } + + pInt = (xf86Int10InfoPtr)xnfcalloc(1, sizeof(xf86Int10InfoRec)); + pInt->entityIndex = entityIndex; + if (!xf86Int10ExecSetup(pInt)) + goto error0; + pInt->mem = &genericMem; + pInt->private = (pointer)xnfcalloc(1, sizeof(genericInt10Priv)); + INTPriv(pInt)->alloc = (pointer)xnfcalloc(1, ALLOC_ENTRIES(getpagesize())); + pInt->scrnIndex = screen; + base = INTPriv(pInt)->base = xnfalloc(SYS_BIOS); + + /* FIXME: Shouldn't this be a failure case? Leaving dev as NULL seems like + * FIXME: an error + */ + pInt->dev = xf86GetPciInfoForEntity(entityIndex); + + /* + * we need to map video RAM MMIO as some chipsets map mmio + * registers into this range. + */ + MapVRam(pInt); +#ifdef _PC + if (!sysMem) + sysMem = xf86MapVidMem(screen, VIDMEM_MMIO, V_BIOS, + BIOS_SIZE + SYS_BIOS - V_BIOS); + INTPriv(pInt)->sysMem = sysMem; + + if (xf86ReadBIOS(0, 0, base, LOW_PAGE_SIZE) < 0) { + xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n"); + goto error1; + } + + /* + * Retrieve everything between V_BIOS and SYS_BIOS as some system BIOSes + * have executable code there. Note that xf86ReadBIOS() can only read in + * 64kB at a time. + */ + memset((char *)base + V_BIOS, 0, SYS_BIOS - V_BIOS); +#if 0 + for (cs = V_BIOS; cs < SYS_BIOS; cs += V_BIOS_SIZE) + if (xf86ReadBIOS(cs, 0, (unsigned char *)base + cs, V_BIOS_SIZE) < + V_BIOS_SIZE) + xf86DrvMsg(screen, X_WARNING, + "Unable to retrieve all of segment 0x%06X.\n", cs); +#endif + INTPriv(pInt)->highMemory = V_BIOS; + + if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) { + if (!xf86int10GetBiosSegment(pInt, (unsigned char *)sysMem - V_BIOS)) + goto error1; + + set_return_trap(pInt); + + pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); + if (! (pInt->Flags & SET_BIOS_SCRATCH)) + pInt->Flags &= ~RESTORE_BIOS_SCRATCH; + xf86Int10SaveRestoreBIOSVars(pInt, TRUE); + + } else { + const BusType location_type = xf86int10GetBiosLocationType(pInt); + int bios_location = V_BIOS; + + reset_int_vect(pInt); + set_return_trap(pInt); + + switch (location_type) { + case BUS_PCI: { + int err; + struct pci_device *rom_device = + xf86GetPciInfoForEntity(pInt->entityIndex); + + vbiosMem = (unsigned char *)base + bios_location; + err = pci_device_read_rom(rom_device, vbiosMem); + if (err) { + xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (3) %s\n", + strerror(err)); + goto error1; + } + INTPriv(pInt)->highMemory = GET_HIGH_BASE(rom_device->rom_size); + break; + } + default: + goto error1; + } + pInt->BIOSseg = V_BIOS >> 4; + pInt->num = 0xe6; + LockLegacyVGA(pInt, &vga); + xf86ExecX86int10(pInt); + UnlockLegacyVGA(pInt, &vga); + } +#else + if (!sysMem) { + sysMem = xnfalloc(BIOS_SIZE); + setup_system_bios(sysMem); + } + INTPriv(pInt)->sysMem = sysMem; + setup_int_vect(pInt); + set_return_trap(pInt); + + /* Retrieve the entire legacy video BIOS segment. This can be upto + * 128KiB. + */ + vbiosMem = (char *)base + V_BIOS; + memset(vbiosMem, 0, 2 * V_BIOS_SIZE); + if (read_legacy_video_BIOS(pInt->dev, vbiosMem) < V_BIOS_SIZE) { + xf86DrvMsg(screen, X_WARNING, + "Unable to retrieve all of segment 0x0C0000.\n"); + } + + /* + * If this adapter is the primary, use its post-init BIOS (if we can find + * it). + */ + { + int bios_location = V_BIOS; + Bool done = FALSE; + vbiosMem = (unsigned char *)base + bios_location; + + if (xf86IsEntityPrimary(entityIndex)) { + if (int10_check_bios(screen, bios_location >> 4, vbiosMem)) + done = TRUE; + else + xf86DrvMsg(screen,X_INFO, + "No legacy BIOS found -- trying PCI\n"); + } + if (!done) { + int err; + struct pci_device *rom_device = + xf86GetPciInfoForEntity(pInt->entityIndex); + + err = pci_device_read_rom(rom_device, vbiosMem); + if (err) { + xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (5) %s\n", + strerror(err)); + goto error1; + } + } + } + + pInt->BIOSseg = V_BIOS >> 4; + pInt->num = 0xe6; + LockLegacyVGA(pInt, &vga); + xf86ExecX86int10(pInt); + UnlockLegacyVGA(pInt, &vga); +#endif + free(options); + return pInt; + + error1: + free(base); + UnmapVRam(pInt); + free(INTPriv(pInt)->alloc); + free(pInt->private); + error0: + free(pInt); + free(options); + + return NULL; +} + +static void +MapVRam(xf86Int10InfoPtr pInt) +{ + int pagesize = getpagesize(); + int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize; + + INTPriv(pInt)->vRam = xf86MapDomainMemory(pInt->scrnIndex, VIDMEM_MMIO, + pInt->dev, V_RAM, size); + + pInt->ioBase = xf86Screens[pInt->scrnIndex]->domainIOBase; +} + +static void +UnmapVRam(xf86Int10InfoPtr pInt) +{ + int screen = pInt->scrnIndex; + int pagesize = getpagesize(); + int size = ((VRAM_SIZE + pagesize - 1)/pagesize) * pagesize; + + xf86UnMapVidMem(screen, INTPriv(pInt)->vRam, size); +} + +Bool +MapCurrentInt10(xf86Int10InfoPtr pInt) +{ + /* nothing to do here */ + return TRUE; +} + +void +xf86FreeInt10(xf86Int10InfoPtr pInt) +{ + if (!pInt) + return; +#if defined (_PC) + xf86Int10SaveRestoreBIOSVars(pInt, FALSE); +#endif + if (Int10Current == pInt) + Int10Current = NULL; + free(INTPriv(pInt)->base); + UnmapVRam(pInt); + free(INTPriv(pInt)->alloc); + free(pInt->private); + free(pInt); +} + +void * +xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off) +{ + int pagesize = getpagesize(); + int num_pages = ALLOC_ENTRIES(pagesize); + int i,j; + + for (i = 0; i < (num_pages - num); i++) { + if (INTPriv(pInt)->alloc[i] == 0) { + for (j = i; j < (num + i); j++) + if (INTPriv(pInt)->alloc[j] != 0) + break; + if (j == (num + i)) + break; + i += num; + } + } + if (i == (num_pages - num)) + return NULL; + + for (j = i; j < (i + num); j++) + INTPriv(pInt)->alloc[j] = 1; + + *off = (i + 1) * pagesize; + + return (char *)INTPriv(pInt)->base + *off; +} + +void +xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) +{ + int pagesize = getpagesize(); + int first = (((char *)pbase - (char *)INTPriv(pInt)->base) / pagesize) - 1; + int i; + + for (i = first; i < (first + num); i++) + INTPriv(pInt)->alloc[i] = 0; +} + +#define OFF(addr) ((addr) & 0xffff) +#if defined _PC +# define HIGH_OFFSET (INTPriv(pInt)->highMemory) +# define HIGH_BASE V_BIOS +#else +# define HIGH_OFFSET SYS_BIOS +# define HIGH_BASE SYS_BIOS +#endif +# define SYS(addr) ((addr) >= HIGH_OFFSET) +#define V_ADDR(addr) \ + (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \ + : (((char*)(INTPriv(pInt)->base) + addr))) +#define VRAM_ADDR(addr) (addr - V_RAM) +#define VRAM_BASE (INTPriv(pInt)->vRam) + +#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE))) +#define V_ADDR_RB(addr) \ + (VRAM(addr)) ? MMIO_IN8((CARD8*)VRAM_BASE,VRAM_ADDR(addr)) \ + : *(CARD8*) V_ADDR(addr) +#define V_ADDR_RW(addr) \ + (VRAM(addr)) ? MMIO_IN16((CARD16*)VRAM_BASE,VRAM_ADDR(addr)) \ + : ldw_u((pointer)V_ADDR(addr)) +#define V_ADDR_RL(addr) \ + (VRAM(addr)) ? MMIO_IN32((CARD32*)VRAM_BASE,VRAM_ADDR(addr)) \ + : ldl_u((pointer)V_ADDR(addr)) + +#define V_ADDR_WB(addr,val) \ + if(VRAM(addr)) \ + MMIO_OUT8((CARD8*)VRAM_BASE,VRAM_ADDR(addr),val); \ + else \ + *(CARD8*) V_ADDR(addr) = val; +#define V_ADDR_WW(addr,val) \ + if(VRAM(addr)) \ + MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); \ + else \ + stw_u((val),(pointer)(V_ADDR(addr))); + +#define V_ADDR_WL(addr,val) \ + if (VRAM(addr)) \ + MMIO_OUT32((CARD32*)VRAM_BASE,VRAM_ADDR(addr),val); \ + else \ + stl_u(val,(pointer)(V_ADDR(addr))); + +static CARD8 +read_b(xf86Int10InfoPtr pInt, int addr) +{ + return V_ADDR_RB(addr); +} + +static CARD16 +read_w(xf86Int10InfoPtr pInt, int addr) +{ +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + if (OFF(addr + 1) > 0) + return V_ADDR_RW(addr); +#endif + return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8); +} + +static CARD32 +read_l(xf86Int10InfoPtr pInt, int addr) +{ +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + if (OFF(addr + 3) > 2) + return V_ADDR_RL(addr); +#endif + return V_ADDR_RB(addr) | + (V_ADDR_RB(addr + 1) << 8) | + (V_ADDR_RB(addr + 2) << 16) | + (V_ADDR_RB(addr + 3) << 24); +} + +static void +write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val) +{ + V_ADDR_WB(addr,val); +} + +static void +write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val) +{ +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + if (OFF(addr + 1) > 0) + { V_ADDR_WW(addr, val); } +#endif + V_ADDR_WB(addr, val); + V_ADDR_WB(addr + 1, val >> 8); +} + +static void +write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val) +{ +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + if (OFF(addr + 3) > 2) + { V_ADDR_WL(addr, val); } +#endif + V_ADDR_WB(addr, val); + V_ADDR_WB(addr + 1, val >> 8); + V_ADDR_WB(addr + 2, val >> 16); + V_ADDR_WB(addr + 3, val >> 24); +} + +pointer +xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr) +{ + return V_ADDR(addr); +} diff --git a/xorg-server/hw/xfree86/int10/helper_exec.c b/xorg-server/hw/xfree86/int10/helper_exec.c index 6ba647f89..5b6253646 100644 --- a/xorg-server/hw/xfree86/int10/helper_exec.c +++ b/xorg-server/hw/xfree86/int10/helper_exec.c @@ -1,727 +1,727 @@ -/* - * XFree86 int10 module - * execute BIOS int 10h calls in x86 real mode environment - * Copyright 1999 Egbert Eich - * - * Part of this code was inspired by the VBIOS POSTing code in DOSEMU - * developed by the "DOSEMU-Development-Team" - */ - -/* - * To debug port accesses define PRINT_PORT to 1. - * Note! You also have to comment out ioperm() - * in xf86EnableIO(). Otherwise we won't trap - * on PIO. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#define PRINT_PORT 0 - -#include <unistd.h> - -#include <X11/Xos.h> -#include "xf86.h" -#include "xf86_OSproc.h" -#include "compiler.h" -#define _INT10_PRIVATE -#include "int10Defines.h" -#include "xf86int10.h" -#include "Pci.h" -#ifdef _X86EMU -#include "x86emu/x86emui.h" -#else -#define DEBUG_IO_TRACE() 0 -#endif -#include <pciaccess.h> - -static int pciCfg1in(CARD16 addr, CARD32 *val); -static int pciCfg1out(CARD16 addr, CARD32 val); -static int pciCfg1inw(CARD16 addr, CARD16 *val); -static int pciCfg1outw(CARD16 addr, CARD16 val); -static int pciCfg1inb(CARD16 addr, CARD8 *val); -static int pciCfg1outb(CARD16 addr, CARD8 val); -#if defined (_PC) -static void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set); -#endif - -#define REG pInt - -int -setup_int(xf86Int10InfoPtr pInt) -{ - if (pInt != Int10Current) { - if (!MapCurrentInt10(pInt)) - return -1; - Int10Current = pInt; - } - X86_EAX = (CARD32) pInt->ax; - X86_EBX = (CARD32) pInt->bx; - X86_ECX = (CARD32) pInt->cx; - X86_EDX = (CARD32) pInt->dx; - X86_ESI = (CARD32) pInt->si; - X86_EDI = (CARD32) pInt->di; - X86_EBP = (CARD32) pInt->bp; - X86_ESP = 0x1000; X86_SS = pInt->stackseg >> 4; - X86_EIP = 0x0600; X86_CS = 0x0; /* address of 'hlt' */ - X86_DS = 0x40; /* standard pc ds */ - X86_ES = pInt->es; - X86_FS = 0; - X86_GS = 0; - X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK; -#if defined (_PC) - if (pInt->Flags & SET_BIOS_SCRATCH) - SetResetBIOSVars(pInt, TRUE); -#endif - return xf86BlockSIGIO(); -} - -void -finish_int(xf86Int10InfoPtr pInt, int sig) -{ - xf86UnblockSIGIO(sig); - pInt->ax = (CARD32) X86_EAX; - pInt->bx = (CARD32) X86_EBX; - pInt->cx = (CARD32) X86_ECX; - pInt->dx = (CARD32) X86_EDX; - pInt->si = (CARD32) X86_ESI; - pInt->di = (CARD32) X86_EDI; - pInt->es = (CARD16) X86_ES; - pInt->bp = (CARD32) X86_EBP; - pInt->flags = (CARD32) X86_FLAGS; -#if defined (_PC) - if (pInt->Flags & RESTORE_BIOS_SCRATCH) - SetResetBIOSVars(pInt, FALSE); -#endif -} - -/* general software interrupt handler */ -CARD32 -getIntVect(xf86Int10InfoPtr pInt,int num) -{ - return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4); -} - -void -pushw(xf86Int10InfoPtr pInt, CARD16 val) -{ - X86_ESP -= 2; - MEM_WW(pInt, ((CARD32) X86_SS << 4) + X86_SP, val); -} - -int -run_bios_int(int num, xf86Int10InfoPtr pInt) -{ - CARD32 eflags; -#ifndef _PC - /* check if bios vector is initialized */ - if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) { /* SYS_BIOS_SEG ?*/ - - if (num == 21 && X86_AH == 0x4e) { - xf86DrvMsg(pInt->scrnIndex, X_NOTICE, - "Failing Find-Matching-File on non-PC" - " (int 21, func 4e)\n"); - X86_AX = 2; - SET_FLAG(F_CF); - return 1; - } else { - xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, - "Ignoring int 0x%02x call\n", num); - if (xf86GetVerbosity() > 3) { - dump_registers(pInt); - stack_trace(pInt); - } - return 1; - } - } -#endif -#ifdef PRINT_INT - ErrorF("calling card BIOS at: "); -#endif - eflags = X86_EFLAGS; -#if 0 - eflags = eflags | IF_MASK; - X86_EFLAGS = X86_EFLAGS & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK); -#endif - pushw(pInt, eflags); - pushw(pInt, X86_CS); - pushw(pInt, X86_IP); - X86_CS = MEM_RW(pInt, (num << 2) + 2); - X86_IP = MEM_RW(pInt, num << 2); -#ifdef PRINT_INT - ErrorF("0x%x:%lx\n", X86_CS, X86_EIP); -#endif - return 1; -} - -/* Debugging stuff */ -void -dump_code(xf86Int10InfoPtr pInt) -{ - int i; - unsigned long lina = SEG_ADR((CARD32), X86_CS, IP); - - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, "code at 0x%8.8lx:\n", lina); - for (i=0; i<0x10; i++) - xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); - xf86ErrorFVerb(3, "\n"); - for (; i<0x20; i++) - xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); - xf86ErrorFVerb(3, "\n"); -} - -void -dump_registers(xf86Int10InfoPtr pInt) -{ - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, - "EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n", - (unsigned long)X86_EAX, (unsigned long)X86_EBX, - (unsigned long)X86_ECX, (unsigned long)X86_EDX); - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, - "ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n", - (unsigned long)X86_ESP, (unsigned long)X86_EBP, - (unsigned long)X86_ESI, (unsigned long)X86_EDI); - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, - "CS=0x%4.4x, SS=0x%4.4x," - " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n", - X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS); - xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, - "EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n", - (unsigned long)X86_EIP, (unsigned long)X86_EFLAGS); -} - -void -stack_trace(xf86Int10InfoPtr pInt) -{ - int i = 0; - unsigned long stack = SEG_ADR((CARD32), X86_SS, SP); - unsigned long tail = (CARD32)((X86_SS << 4) + 0x1000); - - if (stack >= tail) return; - - xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack); - for (; stack < tail; stack++) { - xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack)); - i = (i + 1) % 0x10; - if (!i) - xf86ErrorFVerb(3, "\n"); - } - if (i) - xf86ErrorFVerb(3, "\n"); -} - -int -port_rep_inb(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -1 : 1; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_insb(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - MEM_WB(pInt, dst, x_inb(port)); - dst += inc; - } - return dst - base; -} - -int -port_rep_inw(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -2 : 2; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_insw(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - MEM_WW(pInt, dst, x_inw(port)); - dst += inc; - } - return dst - base; -} - -int -port_rep_inl(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -4 : 4; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_insl(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - MEM_WL(pInt, dst, x_inl(port)); - dst += inc; - } - return dst - base; -} - -int -port_rep_outb(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -1 : 1; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_outb(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - x_outb(port, MEM_RB(pInt, dst)); - dst += inc; - } - return dst - base; -} - -int -port_rep_outw(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -2 : 2; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_outw(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - x_outw(port, MEM_RW(pInt, dst)); - dst += inc; - } - return dst - base; -} - -int -port_rep_outl(xf86Int10InfoPtr pInt, - CARD16 port, CARD32 base, int d_f, CARD32 count) -{ - register int inc = d_f ? -4 : 4; - CARD32 dst = base; - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" rep_outl(%#x) %ld bytes at %8.8lx %s\n", - port, count, base, d_f ? "up" : "down"); - while (count--) { - x_outl(port, MEM_RL(pInt, dst)); - dst += inc; - } - return dst - base; -} - -CARD8 -x_inb(CARD16 port) -{ - CARD8 val; - - if (port == 0x40) { - Int10Current->inb40time++; - val = (CARD8)(Int10Current->inb40time >> - ((Int10Current->inb40time & 1) << 3)); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inb(%#x) = %2.2x\n", port, val); -#ifdef __NOT_YET__ - } else if (port < 0x0100) { /* Don't interfere with mainboard */ - val = 0; - xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, - "inb 0x%4.4x\n", port); - if (xf86GetVerbosity() > 3) { - dump_registers(Int10Current); - stack_trace(Int10Current); - } -#endif /* __NOT_YET__ */ - } else if (!pciCfg1inb(port, &val)) { - val = inb(Int10Current->ioBase + port); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inb(%#x) = %2.2x\n", port, val); - } - return val; -} - -CARD16 -x_inw(CARD16 port) -{ - CARD16 val; - - if (port == 0x5c) { - struct timeval tv; - - /* - * Emulate a PC98's timer. Typical resolution is 3.26 usec. - * Approximate this by dividing by 3. - */ - X_GETTIMEOFDAY(&tv); - val = (CARD16)(tv.tv_usec / 3); - } else if (!pciCfg1inw(port, &val)) { - val = inw(Int10Current->ioBase + port); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inw(%#x) = %4.4x\n", port, val); - } - return val; -} - -void -x_outb(CARD16 port, CARD8 val) -{ - if ((port == 0x43) && (val == 0)) { - struct timeval tv; - /* - * Emulate a PC's timer 0. Such timers typically have a resolution of - * some .838 usec per tick, but this can only provide 1 usec per tick. - * (Not that this matters much, given inherent emulation delays.) Use - * the bottom bit as a byte select. See inb(0x40) above. - */ - X_GETTIMEOFDAY(&tv); - Int10Current->inb40time = (CARD16)(tv.tv_usec | 1); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" outb(%#x, %2.2x)\n", port, val); -#ifdef __NOT_YET__ - } else if (port < 0x0100) { /* Don't interfere with mainboard */ - xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, - "outb 0x%4.4x,0x%2.2x\n", port, val); - if (xf86GetVerbosity() > 3) { - dump_registers(Int10Current); - stack_trace(Int10Current); - } -#endif /* __NOT_YET__ */ - } else if (!pciCfg1outb(port, val)) { - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" outb(%#x, %2.2x)\n", port, val); - outb(Int10Current->ioBase + port, val); - } -} - -void -x_outw(CARD16 port, CARD16 val) -{ - - if (!pciCfg1outw(port, val)) { - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" outw(%#x, %4.4x)\n", port, val); - outw(Int10Current->ioBase + port, val); - } -} - -CARD32 -x_inl(CARD16 port) -{ - CARD32 val; - - if (!pciCfg1in(port, &val)) { - val = inl(Int10Current->ioBase + port); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inl(%#x) = %8.8lx\n", port, val); - } - return val; -} - -void -x_outl(CARD16 port, CARD32 val) -{ - if (!pciCfg1out(port, val)) { - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" outl(%#x, %8.8lx)\n", port, val); - outl(Int10Current->ioBase + port, val); - } -} - -CARD8 -Mem_rb(CARD32 addr) -{ - return (*Int10Current->mem->rb)(Int10Current, addr); -} - -CARD16 -Mem_rw(CARD32 addr) -{ - return (*Int10Current->mem->rw)(Int10Current, addr); -} - -CARD32 -Mem_rl(CARD32 addr) -{ - return (*Int10Current->mem->rl)(Int10Current, addr); -} - -void -Mem_wb(CARD32 addr, CARD8 val) -{ - (*Int10Current->mem->wb)(Int10Current, addr, val); -} - -void -Mem_ww(CARD32 addr, CARD16 val) -{ - (*Int10Current->mem->ww)(Int10Current, addr, val); -} - -void -Mem_wl(CARD32 addr, CARD32 val) -{ - (*Int10Current->mem->wl)(Int10Current, addr, val); -} - -static CARD32 PciCfg1Addr = 0; - -#define PCI_OFFSET(x) ((x) & 0x000000ff) -#define PCI_TAG(x) ((x) & 0x7fffff00) - -static struct pci_device* -pci_device_for_cfg_address (CARD32 addr) -{ - struct pci_device *dev = NULL; - PCITAG tag = PCI_TAG(addr); - struct pci_slot_match slot_match = { - .domain = PCI_DOM_FROM_TAG(tag), - .bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)), - .dev = PCI_DEV_FROM_TAG(tag), - .func = PCI_FUNC_FROM_TAG(tag), - .match_data = 0 - }; - - struct pci_device_iterator *iter = - pci_slot_match_iterator_create (&slot_match); - - if (iter) - dev = pci_device_next(iter); - - pci_iterator_destroy(iter); - - return dev; -} - -static int -pciCfg1in(CARD16 addr, CARD32 *val) -{ - if (addr == 0xCF8) { - *val = PciCfg1Addr; - return 1; - } - if (addr == 0xCFC) { - pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr)); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_inl(%#lx) = %8.8lx\n", PciCfg1Addr, *val); - return 1; - } - return 0; -} - -static int -pciCfg1out(CARD16 addr, CARD32 val) -{ - if (addr == 0xCF8) { - PciCfg1Addr = val; - return 1; - } - if (addr == 0xCFC) { - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_outl(%#lx, %8.8lx)\n", PciCfg1Addr, val); - pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr)); - return 1; - } - return 0; -} - -static int -pciCfg1inw(CARD16 addr, CARD16 *val) -{ - int shift; - - if ((addr >= 0xCF8) && (addr <= 0xCFB)) { - shift = (addr - 0xCF8) * 8; - *val = (PciCfg1Addr >> shift) & 0xffff; - return 1; - } - if ((addr >= 0xCFC) && (addr <= 0xCFF)) { - const unsigned offset = addr - 0xCFC; - - pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr) + offset); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_inw(%#lx) = %4.4x\n", PciCfg1Addr + offset, *val); - return 1; - } - return 0; -} - -static int -pciCfg1outw(CARD16 addr, CARD16 val) -{ - int shift; - - if ((addr >= 0xCF8) && (addr <= 0xCFB)) { - shift = (addr - 0xCF8) * 8; - PciCfg1Addr &= ~(0xffff << shift); - PciCfg1Addr |= ((CARD32) val) << shift; - return 1; - } - if ((addr >= 0xCFC) && (addr <= 0xCFF)) { - const unsigned offset = addr - 0xCFC; - - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_outw(%#lx, %4.4x)\n", PciCfg1Addr + offset, val); - pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr) + offset); - return 1; - } - return 0; -} - -static int -pciCfg1inb(CARD16 addr, CARD8 *val) -{ - int shift; - - if ((addr >= 0xCF8) && (addr <= 0xCFB)) { - shift = (addr - 0xCF8) * 8; - *val = (PciCfg1Addr >> shift) & 0xff; - return 1; - } - if ((addr >= 0xCFC) && (addr <= 0xCFF)) { - const unsigned offset = addr - 0xCFC; - - pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr) + offset); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_inb(%#lx) = %2.2x\n", PciCfg1Addr + offset, *val); - return 1; - } - return 0; -} - -static int -pciCfg1outb(CARD16 addr, CARD8 val) -{ - int shift; - - if ((addr >= 0xCF8) && (addr <= 0xCFB)) { - shift = (addr - 0xCF8) * 8; - PciCfg1Addr &= ~(0xff << shift); - PciCfg1Addr |= ((CARD32) val) << shift; - return 1; - } - if ((addr >= 0xCFC) && (addr <= 0xCFF)) { - const unsigned offset = addr - 0xCFC; - - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" cfg_outb(%#lx, %2.2x)\n", PciCfg1Addr + offset, val); - pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr), - val, PCI_OFFSET(PciCfg1Addr) + offset); - return 1; - } - return 0; -} - -CARD8 -bios_checksum(const CARD8 *start, int size) -{ - CARD8 sum = 0; - - while (size-- > 0) - sum += *start++; - return sum; -} - -/* - * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make - * an attempt to detect a legacy ISA card. If they find one they might - * act very strange: for example they might configure the card as a - * monochrome card. This might cause some drivers to choke. - * To avoid this we attempt legacy VGA by writing to all know VGA - * disable registers before we call the BIOS initialization and - * restore the original values afterwards. In beween we hold our - * breath. To get to a (possibly exising) ISA card need to disable - * our current PCI card. - */ -/* - * This is just for booting: we just want to catch pure - * legacy vga therefore we don't worry about mmio etc. - * This stuff should really go into vgaHW.c. However then - * the driver would have to load the vga-module prior to - * doing int10. - */ -void -LockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) -{ - vga->save_msr = inb(pInt->ioBase + 0x03CC); - vga->save_vse = inb(pInt->ioBase + 0x03C3); -#ifndef __ia64__ - vga->save_46e8 = inb(pInt->ioBase + 0x46E8); -#endif - vga->save_pos102 = inb(pInt->ioBase + 0x0102); - outb(pInt->ioBase + 0x03C2, ~(CARD8)0x03 & vga->save_msr); - outb(pInt->ioBase + 0x03C3, ~(CARD8)0x01 & vga->save_vse); -#ifndef __ia64__ - outb(pInt->ioBase + 0x46E8, ~(CARD8)0x08 & vga->save_46e8); -#endif - outb(pInt->ioBase + 0x0102, ~(CARD8)0x01 & vga->save_pos102); -} - -void -UnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) -{ - outb(pInt->ioBase + 0x0102, vga->save_pos102); -#ifndef __ia64__ - outb(pInt->ioBase + 0x46E8, vga->save_46e8); -#endif - outb(pInt->ioBase + 0x03C3, vga->save_vse); - outb(pInt->ioBase + 0x03C2, vga->save_msr); -} - -#if defined (_PC) -static void -SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set) -{ - int pagesize = getpagesize(); - unsigned char* base = xf86MapVidMem(pInt->scrnIndex, - VIDMEM_MMIO, 0, pagesize); - int i; - - if (set) { - for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) - MEM_WW(pInt, i, *(base + i)); - } else { - for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) - *(base + i) = MEM_RW(pInt, i); - } - - xf86UnMapVidMem(pInt->scrnIndex,base,pagesize); -} - -void -xf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save) -{ - int pagesize = getpagesize(); - unsigned char* base; - int i; - - if (!xf86IsEntityPrimary(pInt->entityIndex) - || (!save && !pInt->BIOSScratch)) - return; - - base = xf86MapVidMem(pInt->scrnIndex, VIDMEM_MMIO, 0, pagesize); - base += BIOS_SCRATCH_OFF; - if (save) { - if ((pInt->BIOSScratch - = xnfalloc(BIOS_SCRATCH_LEN))) - for (i = 0; i < BIOS_SCRATCH_LEN; i++) - *(((char*)pInt->BIOSScratch + i)) = *(base + i); - } else { - if (pInt->BIOSScratch) { - for (i = 0; i < BIOS_SCRATCH_LEN; i++) - *(base + i) = *(pInt->BIOSScratch + i); - xfree(pInt->BIOSScratch); - pInt->BIOSScratch = NULL; - } - } - - xf86UnMapVidMem(pInt->scrnIndex,base - BIOS_SCRATCH_OFF ,pagesize); -} -#endif - -xf86Int10InfoPtr -xf86InitInt10(int entityIndex) -{ - return xf86ExtendedInitInt10(entityIndex, 0); -} +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + * + * Part of this code was inspired by the VBIOS POSTing code in DOSEMU + * developed by the "DOSEMU-Development-Team" + */ + +/* + * To debug port accesses define PRINT_PORT to 1. + * Note! You also have to comment out ioperm() + * in xf86EnableIO(). Otherwise we won't trap + * on PIO. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#define PRINT_PORT 0 + +#include <unistd.h> + +#include <X11/Xos.h> +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#define _INT10_PRIVATE +#include "int10Defines.h" +#include "xf86int10.h" +#include "Pci.h" +#ifdef _X86EMU +#include "x86emu/x86emui.h" +#else +#define DEBUG_IO_TRACE() 0 +#endif +#include <pciaccess.h> + +static int pciCfg1in(CARD16 addr, CARD32 *val); +static int pciCfg1out(CARD16 addr, CARD32 val); +static int pciCfg1inw(CARD16 addr, CARD16 *val); +static int pciCfg1outw(CARD16 addr, CARD16 val); +static int pciCfg1inb(CARD16 addr, CARD8 *val); +static int pciCfg1outb(CARD16 addr, CARD8 val); +#if defined (_PC) +static void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set); +#endif + +#define REG pInt + +int +setup_int(xf86Int10InfoPtr pInt) +{ + if (pInt != Int10Current) { + if (!MapCurrentInt10(pInt)) + return -1; + Int10Current = pInt; + } + X86_EAX = (CARD32) pInt->ax; + X86_EBX = (CARD32) pInt->bx; + X86_ECX = (CARD32) pInt->cx; + X86_EDX = (CARD32) pInt->dx; + X86_ESI = (CARD32) pInt->si; + X86_EDI = (CARD32) pInt->di; + X86_EBP = (CARD32) pInt->bp; + X86_ESP = 0x1000; X86_SS = pInt->stackseg >> 4; + X86_EIP = 0x0600; X86_CS = 0x0; /* address of 'hlt' */ + X86_DS = 0x40; /* standard pc ds */ + X86_ES = pInt->es; + X86_FS = 0; + X86_GS = 0; + X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK; +#if defined (_PC) + if (pInt->Flags & SET_BIOS_SCRATCH) + SetResetBIOSVars(pInt, TRUE); +#endif + return xf86BlockSIGIO(); +} + +void +finish_int(xf86Int10InfoPtr pInt, int sig) +{ + xf86UnblockSIGIO(sig); + pInt->ax = (CARD32) X86_EAX; + pInt->bx = (CARD32) X86_EBX; + pInt->cx = (CARD32) X86_ECX; + pInt->dx = (CARD32) X86_EDX; + pInt->si = (CARD32) X86_ESI; + pInt->di = (CARD32) X86_EDI; + pInt->es = (CARD16) X86_ES; + pInt->bp = (CARD32) X86_EBP; + pInt->flags = (CARD32) X86_FLAGS; +#if defined (_PC) + if (pInt->Flags & RESTORE_BIOS_SCRATCH) + SetResetBIOSVars(pInt, FALSE); +#endif +} + +/* general software interrupt handler */ +CARD32 +getIntVect(xf86Int10InfoPtr pInt,int num) +{ + return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4); +} + +void +pushw(xf86Int10InfoPtr pInt, CARD16 val) +{ + X86_ESP -= 2; + MEM_WW(pInt, ((CARD32) X86_SS << 4) + X86_SP, val); +} + +int +run_bios_int(int num, xf86Int10InfoPtr pInt) +{ + CARD32 eflags; +#ifndef _PC + /* check if bios vector is initialized */ + if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) { /* SYS_BIOS_SEG ?*/ + + if (num == 21 && X86_AH == 0x4e) { + xf86DrvMsg(pInt->scrnIndex, X_NOTICE, + "Failing Find-Matching-File on non-PC" + " (int 21, func 4e)\n"); + X86_AX = 2; + SET_FLAG(F_CF); + return 1; + } else { + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "Ignoring int 0x%02x call\n", num); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + return 1; + } + } +#endif +#ifdef PRINT_INT + ErrorF("calling card BIOS at: "); +#endif + eflags = X86_EFLAGS; +#if 0 + eflags = eflags | IF_MASK; + X86_EFLAGS = X86_EFLAGS & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK); +#endif + pushw(pInt, eflags); + pushw(pInt, X86_CS); + pushw(pInt, X86_IP); + X86_CS = MEM_RW(pInt, (num << 2) + 2); + X86_IP = MEM_RW(pInt, num << 2); +#ifdef PRINT_INT + ErrorF("0x%x:%lx\n", X86_CS, X86_EIP); +#endif + return 1; +} + +/* Debugging stuff */ +void +dump_code(xf86Int10InfoPtr pInt) +{ + int i; + unsigned long lina = SEG_ADR((CARD32), X86_CS, IP); + + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, "code at 0x%8.8lx:\n", lina); + for (i=0; i<0x10; i++) + xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); + xf86ErrorFVerb(3, "\n"); + for (; i<0x20; i++) + xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); + xf86ErrorFVerb(3, "\n"); +} + +void +dump_registers(xf86Int10InfoPtr pInt) +{ + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n", + (unsigned long)X86_EAX, (unsigned long)X86_EBX, + (unsigned long)X86_ECX, (unsigned long)X86_EDX); + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n", + (unsigned long)X86_ESP, (unsigned long)X86_EBP, + (unsigned long)X86_ESI, (unsigned long)X86_EDI); + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "CS=0x%4.4x, SS=0x%4.4x," + " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n", + X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS); + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n", + (unsigned long)X86_EIP, (unsigned long)X86_EFLAGS); +} + +void +stack_trace(xf86Int10InfoPtr pInt) +{ + int i = 0; + unsigned long stack = SEG_ADR((CARD32), X86_SS, SP); + unsigned long tail = (CARD32)((X86_SS << 4) + 0x1000); + + if (stack >= tail) return; + + xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack); + for (; stack < tail; stack++) { + xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack)); + i = (i + 1) % 0x10; + if (!i) + xf86ErrorFVerb(3, "\n"); + } + if (i) + xf86ErrorFVerb(3, "\n"); +} + +int +port_rep_inb(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -1 : 1; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_insb(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + MEM_WB(pInt, dst, x_inb(port)); + dst += inc; + } + return dst - base; +} + +int +port_rep_inw(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -2 : 2; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_insw(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + MEM_WW(pInt, dst, x_inw(port)); + dst += inc; + } + return dst - base; +} + +int +port_rep_inl(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -4 : 4; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_insl(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + MEM_WL(pInt, dst, x_inl(port)); + dst += inc; + } + return dst - base; +} + +int +port_rep_outb(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -1 : 1; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_outb(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + x_outb(port, MEM_RB(pInt, dst)); + dst += inc; + } + return dst - base; +} + +int +port_rep_outw(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -2 : 2; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_outw(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + x_outw(port, MEM_RW(pInt, dst)); + dst += inc; + } + return dst - base; +} + +int +port_rep_outl(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -4 : 4; + CARD32 dst = base; + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" rep_outl(%#x) %ld bytes at %8.8lx %s\n", + port, count, base, d_f ? "up" : "down"); + while (count--) { + x_outl(port, MEM_RL(pInt, dst)); + dst += inc; + } + return dst - base; +} + +CARD8 +x_inb(CARD16 port) +{ + CARD8 val; + + if (port == 0x40) { + Int10Current->inb40time++; + val = (CARD8)(Int10Current->inb40time >> + ((Int10Current->inb40time & 1) << 3)); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inb(%#x) = %2.2x\n", port, val); +#ifdef __NOT_YET__ + } else if (port < 0x0100) { /* Don't interfere with mainboard */ + val = 0; + xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, + "inb 0x%4.4x\n", port); + if (xf86GetVerbosity() > 3) { + dump_registers(Int10Current); + stack_trace(Int10Current); + } +#endif /* __NOT_YET__ */ + } else if (!pciCfg1inb(port, &val)) { + val = inb(Int10Current->ioBase + port); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inb(%#x) = %2.2x\n", port, val); + } + return val; +} + +CARD16 +x_inw(CARD16 port) +{ + CARD16 val; + + if (port == 0x5c) { + struct timeval tv; + + /* + * Emulate a PC98's timer. Typical resolution is 3.26 usec. + * Approximate this by dividing by 3. + */ + X_GETTIMEOFDAY(&tv); + val = (CARD16)(tv.tv_usec / 3); + } else if (!pciCfg1inw(port, &val)) { + val = inw(Int10Current->ioBase + port); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inw(%#x) = %4.4x\n", port, val); + } + return val; +} + +void +x_outb(CARD16 port, CARD8 val) +{ + if ((port == 0x43) && (val == 0)) { + struct timeval tv; + /* + * Emulate a PC's timer 0. Such timers typically have a resolution of + * some .838 usec per tick, but this can only provide 1 usec per tick. + * (Not that this matters much, given inherent emulation delays.) Use + * the bottom bit as a byte select. See inb(0x40) above. + */ + X_GETTIMEOFDAY(&tv); + Int10Current->inb40time = (CARD16)(tv.tv_usec | 1); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" outb(%#x, %2.2x)\n", port, val); +#ifdef __NOT_YET__ + } else if (port < 0x0100) { /* Don't interfere with mainboard */ + xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, + "outb 0x%4.4x,0x%2.2x\n", port, val); + if (xf86GetVerbosity() > 3) { + dump_registers(Int10Current); + stack_trace(Int10Current); + } +#endif /* __NOT_YET__ */ + } else if (!pciCfg1outb(port, val)) { + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" outb(%#x, %2.2x)\n", port, val); + outb(Int10Current->ioBase + port, val); + } +} + +void +x_outw(CARD16 port, CARD16 val) +{ + + if (!pciCfg1outw(port, val)) { + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" outw(%#x, %4.4x)\n", port, val); + outw(Int10Current->ioBase + port, val); + } +} + +CARD32 +x_inl(CARD16 port) +{ + CARD32 val; + + if (!pciCfg1in(port, &val)) { + val = inl(Int10Current->ioBase + port); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inl(%#x) = %8.8lx\n", port, val); + } + return val; +} + +void +x_outl(CARD16 port, CARD32 val) +{ + if (!pciCfg1out(port, val)) { + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" outl(%#x, %8.8lx)\n", port, val); + outl(Int10Current->ioBase + port, val); + } +} + +CARD8 +Mem_rb(CARD32 addr) +{ + return (*Int10Current->mem->rb)(Int10Current, addr); +} + +CARD16 +Mem_rw(CARD32 addr) +{ + return (*Int10Current->mem->rw)(Int10Current, addr); +} + +CARD32 +Mem_rl(CARD32 addr) +{ + return (*Int10Current->mem->rl)(Int10Current, addr); +} + +void +Mem_wb(CARD32 addr, CARD8 val) +{ + (*Int10Current->mem->wb)(Int10Current, addr, val); +} + +void +Mem_ww(CARD32 addr, CARD16 val) +{ + (*Int10Current->mem->ww)(Int10Current, addr, val); +} + +void +Mem_wl(CARD32 addr, CARD32 val) +{ + (*Int10Current->mem->wl)(Int10Current, addr, val); +} + +static CARD32 PciCfg1Addr = 0; + +#define PCI_OFFSET(x) ((x) & 0x000000ff) +#define PCI_TAG(x) ((x) & 0x7fffff00) + +static struct pci_device* +pci_device_for_cfg_address (CARD32 addr) +{ + struct pci_device *dev = NULL; + PCITAG tag = PCI_TAG(addr); + struct pci_slot_match slot_match = { + .domain = PCI_DOM_FROM_TAG(tag), + .bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)), + .dev = PCI_DEV_FROM_TAG(tag), + .func = PCI_FUNC_FROM_TAG(tag), + .match_data = 0 + }; + + struct pci_device_iterator *iter = + pci_slot_match_iterator_create (&slot_match); + + if (iter) + dev = pci_device_next(iter); + + pci_iterator_destroy(iter); + + return dev; +} + +static int +pciCfg1in(CARD16 addr, CARD32 *val) +{ + if (addr == 0xCF8) { + *val = PciCfg1Addr; + return 1; + } + if (addr == 0xCFC) { + pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr)); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_inl(%#lx) = %8.8lx\n", PciCfg1Addr, *val); + return 1; + } + return 0; +} + +static int +pciCfg1out(CARD16 addr, CARD32 val) +{ + if (addr == 0xCF8) { + PciCfg1Addr = val; + return 1; + } + if (addr == 0xCFC) { + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_outl(%#lx, %8.8lx)\n", PciCfg1Addr, val); + pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr)); + return 1; + } + return 0; +} + +static int +pciCfg1inw(CARD16 addr, CARD16 *val) +{ + int shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + *val = (PciCfg1Addr >> shift) & 0xffff; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + const unsigned offset = addr - 0xCFC; + + pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_inw(%#lx) = %4.4x\n", PciCfg1Addr + offset, *val); + return 1; + } + return 0; +} + +static int +pciCfg1outw(CARD16 addr, CARD16 val) +{ + int shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + PciCfg1Addr &= ~(0xffff << shift); + PciCfg1Addr |= ((CARD32) val) << shift; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + const unsigned offset = addr - 0xCFC; + + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_outw(%#lx, %4.4x)\n", PciCfg1Addr + offset, val); + pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); + return 1; + } + return 0; +} + +static int +pciCfg1inb(CARD16 addr, CARD8 *val) +{ + int shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + *val = (PciCfg1Addr >> shift) & 0xff; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + const unsigned offset = addr - 0xCFC; + + pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_inb(%#lx) = %2.2x\n", PciCfg1Addr + offset, *val); + return 1; + } + return 0; +} + +static int +pciCfg1outb(CARD16 addr, CARD8 val) +{ + int shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + PciCfg1Addr &= ~(0xff << shift); + PciCfg1Addr |= ((CARD32) val) << shift; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + const unsigned offset = addr - 0xCFC; + + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" cfg_outb(%#lx, %2.2x)\n", PciCfg1Addr + offset, val); + pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); + return 1; + } + return 0; +} + +CARD8 +bios_checksum(const CARD8 *start, int size) +{ + CARD8 sum = 0; + + while (size-- > 0) + sum += *start++; + return sum; +} + +/* + * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make + * an attempt to detect a legacy ISA card. If they find one they might + * act very strange: for example they might configure the card as a + * monochrome card. This might cause some drivers to choke. + * To avoid this we attempt legacy VGA by writing to all know VGA + * disable registers before we call the BIOS initialization and + * restore the original values afterwards. In beween we hold our + * breath. To get to a (possibly exising) ISA card need to disable + * our current PCI card. + */ +/* + * This is just for booting: we just want to catch pure + * legacy vga therefore we don't worry about mmio etc. + * This stuff should really go into vgaHW.c. However then + * the driver would have to load the vga-module prior to + * doing int10. + */ +void +LockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) +{ + vga->save_msr = inb(pInt->ioBase + 0x03CC); + vga->save_vse = inb(pInt->ioBase + 0x03C3); +#ifndef __ia64__ + vga->save_46e8 = inb(pInt->ioBase + 0x46E8); +#endif + vga->save_pos102 = inb(pInt->ioBase + 0x0102); + outb(pInt->ioBase + 0x03C2, ~(CARD8)0x03 & vga->save_msr); + outb(pInt->ioBase + 0x03C3, ~(CARD8)0x01 & vga->save_vse); +#ifndef __ia64__ + outb(pInt->ioBase + 0x46E8, ~(CARD8)0x08 & vga->save_46e8); +#endif + outb(pInt->ioBase + 0x0102, ~(CARD8)0x01 & vga->save_pos102); +} + +void +UnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) +{ + outb(pInt->ioBase + 0x0102, vga->save_pos102); +#ifndef __ia64__ + outb(pInt->ioBase + 0x46E8, vga->save_46e8); +#endif + outb(pInt->ioBase + 0x03C3, vga->save_vse); + outb(pInt->ioBase + 0x03C2, vga->save_msr); +} + +#if defined (_PC) +static void +SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set) +{ + int pagesize = getpagesize(); + unsigned char* base = xf86MapVidMem(pInt->scrnIndex, + VIDMEM_MMIO, 0, pagesize); + int i; + + if (set) { + for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) + MEM_WW(pInt, i, *(base + i)); + } else { + for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) + *(base + i) = MEM_RW(pInt, i); + } + + xf86UnMapVidMem(pInt->scrnIndex,base,pagesize); +} + +void +xf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save) +{ + int pagesize = getpagesize(); + unsigned char* base; + int i; + + if (!xf86IsEntityPrimary(pInt->entityIndex) + || (!save && !pInt->BIOSScratch)) + return; + + base = xf86MapVidMem(pInt->scrnIndex, VIDMEM_MMIO, 0, pagesize); + base += BIOS_SCRATCH_OFF; + if (save) { + if ((pInt->BIOSScratch + = xnfalloc(BIOS_SCRATCH_LEN))) + for (i = 0; i < BIOS_SCRATCH_LEN; i++) + *(((char*)pInt->BIOSScratch + i)) = *(base + i); + } else { + if (pInt->BIOSScratch) { + for (i = 0; i < BIOS_SCRATCH_LEN; i++) + *(base + i) = *(pInt->BIOSScratch + i); + free(pInt->BIOSScratch); + pInt->BIOSScratch = NULL; + } + } + + xf86UnMapVidMem(pInt->scrnIndex,base - BIOS_SCRATCH_OFF ,pagesize); +} +#endif + +xf86Int10InfoPtr +xf86InitInt10(int entityIndex) +{ + return xf86ExtendedInitInt10(entityIndex, 0); +} diff --git a/xorg-server/hw/xfree86/int10/helper_mem.c b/xorg-server/hw/xfree86/int10/helper_mem.c index 6f6ecc2b3..b95b56a93 100644 --- a/xorg-server/hw/xfree86/int10/helper_mem.c +++ b/xorg-server/hw/xfree86/int10/helper_mem.c @@ -1,330 +1,330 @@ -/* - * XFree86 int10 module - * execute BIOS int 10h calls in x86 real mode environment - * Copyright 1999 Egbert Eich - */ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> -#include <stdlib.h> - -#include "xf86.h" -#include "xf86_OSproc.h" -#include "compiler.h" -#include "xf86Pci.h" -#define _INT10_PRIVATE -#if 0 -#include "int10Defines.h" -#endif -#include "xf86int10.h" - -#define REG pInt - -typedef enum { - OPT_NOINT10, - OPT_INIT_PRIMARY, -} INT10Opts; - -static const OptionInfoRec INT10Options[] = { - {OPT_NOINT10, "NoINT10", OPTV_BOOLEAN, {0}, FALSE }, - {OPT_INIT_PRIMARY, "InitPrimary", OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, OPTV_NONE, {0}, FALSE }, -}; - -#ifdef DEBUG -void -dprint(unsigned long start, unsigned long size) -{ - int i,j; - char *c = (char *)start; - - for (j = 0; j < (size >> 4); j++) { - char *d = c; - ErrorF("\n0x%lx: ",(unsigned long)c); - for (i = 0; i<16; i++) - ErrorF("%2.2x ",(unsigned char) (*(c++))); - c = d; - for (i = 0; i<16; i++) { - ErrorF("%c",((((CARD8)(*c)) > 32) && (((CARD8)(*c)) < 128)) ? - (unsigned char) (*(c)): '.'); - c++; - } - } - ErrorF("\n"); -} -#endif - -#ifndef _PC -/* - * here we are really paranoid about faking a "real" - * BIOS. Most of this information was pulled from - * dosemu. - */ -void -setup_int_vect(xf86Int10InfoPtr pInt) -{ - int i; - - /* let the int vects point to the SYS_BIOS seg */ - for (i = 0; i < 0x80; i++) { - MEM_WW(pInt, i << 2, 0); - MEM_WW(pInt, (i << 2) + 2, SYS_BIOS >> 4); - } - - reset_int_vect(pInt); - /* font tables default location (int 1F) */ - MEM_WW(pInt,0x1f<<2,0xfa6e); - - /* int 11 default location (Get Equipment Configuration) */ - MEM_WW(pInt, 0x11 << 2, 0xf84d); - /* int 12 default location (Get Conventional Memory Size) */ - MEM_WW(pInt, 0x12 << 2, 0xf841); - /* int 15 default location (I/O System Extensions) */ - MEM_WW(pInt, 0x15 << 2, 0xf859); - /* int 1A default location (RTC, PCI and others) */ - MEM_WW(pInt, 0x1a << 2, 0xff6e); - /* int 05 default location (Bound Exceeded) */ - MEM_WW(pInt, 0x05 << 2, 0xff54); - /* int 08 default location (Double Fault) */ - MEM_WW(pInt, 0x08 << 2, 0xfea5); - /* int 13 default location (Disk) */ - MEM_WW(pInt, 0x13 << 2, 0xec59); - /* int 0E default location (Page Fault) */ - MEM_WW(pInt, 0x0e << 2, 0xef57); - /* int 17 default location (Parallel Port) */ - MEM_WW(pInt, 0x17 << 2, 0xefd2); - /* fdd table default location (int 1e) */ - MEM_WW(pInt, 0x1e << 2, 0xefc7); - - /* Set Equipment flag to VGA */ - i = MEM_RB(pInt, 0x0410) & 0xCF; - MEM_WB(pInt, 0x0410, i); - /* XXX Perhaps setup more of the BDA here. See also int42(0x00). */ -} -#endif - -int -setup_system_bios(void *base_addr) -{ - char *base = (char *) base_addr; - - /* - * we trap the "industry standard entry points" to the BIOS - * and all other locations by filling them with "hlt" - * TODO: implement hlt-handler for these - */ - memset(base, 0xf4, 0x10000); - - /* set bios date */ - strcpy(base + 0x0FFF5, "06/11/99"); - /* set up eisa ident string */ - strcpy(base + 0x0FFD9, "PCI_ISA"); - /* write system model id for IBM-AT */ - *((unsigned char *)(base + 0x0FFFE)) = 0xfc; - - return 1; -} - -void -reset_int_vect(xf86Int10InfoPtr pInt) -{ - /* - * This table is normally located at 0xF000:0xF0A4. However, int 0x42, - * function 0 (Mode Set) expects it (or a copy) somewhere in the bottom - * 64kB. Note that because this data doesn't survive POST, int 0x42 should - * only be used during EGA/VGA BIOS initialisation. - */ - static const CARD8 VideoParms[] = { - /* Timing for modes 0x00 & 0x01 */ - 0x38, 0x28, 0x2d, 0x0a, 0x1f, 0x06, 0x19, 0x1c, - 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, - /* Timing for modes 0x02 & 0x03 */ - 0x71, 0x50, 0x5a, 0x0a, 0x1f, 0x06, 0x19, 0x1c, - 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, - /* Timing for modes 0x04, 0x05 & 0x06 */ - 0x38, 0x28, 0x2d, 0x0a, 0x7f, 0x06, 0x64, 0x70, - 0x02, 0x01, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, - /* Timing for mode 0x07 */ - 0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19, - 0x02, 0x0d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, - /* Display page lengths in little endian order */ - 0x00, 0x08, /* Modes 0x00 and 0x01 */ - 0x00, 0x10, /* Modes 0x02 and 0x03 */ - 0x00, 0x40, /* Modes 0x04 and 0x05 */ - 0x00, 0x40, /* Modes 0x06 and 0x07 */ - /* Number of columns for each mode */ - 40, 40, 80, 80, 40, 40, 80, 80, - /* CGA Mode register value for each mode */ - 0x2c, 0x28, 0x2d, 0x29, 0x2a, 0x2e, 0x1e, 0x29, - /* Padding */ - 0x00, 0x00, 0x00, 0x00 - }; - int i; - - for (i = 0; i < sizeof(VideoParms); i++) - MEM_WB(pInt, i + (0x1000 - sizeof(VideoParms)), VideoParms[i]); - MEM_WW(pInt, 0x1d << 2, 0x1000 - sizeof(VideoParms)); - MEM_WW(pInt, (0x1d << 2) + 2, 0); - - MEM_WW(pInt, 0x10 << 2, 0xf065); - MEM_WW(pInt, (0x10 << 2) + 2, SYS_BIOS >> 4); - MEM_WW(pInt, 0x42 << 2, 0xf065); - MEM_WW(pInt, (0x42 << 2) + 2, SYS_BIOS >> 4); - MEM_WW(pInt, 0x6D << 2, 0xf065); - MEM_WW(pInt, (0x6D << 2) + 2, SYS_BIOS >> 4); -} - -void -set_return_trap(xf86Int10InfoPtr pInt) -{ - /* - * Here we set the exit condition: We return when we encounter - * 'hlt' (=0xf4), which we locate at address 0x600 in x86 memory. - */ - MEM_WB(pInt, 0x0600, 0xf4); - - /* - * Allocate a segment for the stack - */ - xf86Int10AllocPages(pInt, 1, &pInt->stackseg); -} - -void * -xf86HandleInt10Options(ScrnInfoPtr pScrn, int entityIndex) -{ - EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); - OptionInfoPtr options = NULL; - - if (pEnt->device) { - pointer configOptions = NULL; - - /* Check if xf86CollectOptions() has already been called */ - if (((pEnt->index < 0) || - !pScrn || - !(configOptions = pScrn->options)) && - pEnt->device) - configOptions = pEnt->device->options; - - if (configOptions) { - if (!(options = (OptionInfoPtr) xalloc(sizeof(INT10Options)))) - return NULL; - - (void)memcpy(options, INT10Options, sizeof(INT10Options)); - xf86ProcessOptions(pScrn->scrnIndex, configOptions, options); - } - } - xfree(pEnt); - - return options; -} - -Bool -int10skip(const void* options) -{ - Bool noint10 = FALSE; - - if (!options) return FALSE; - - xf86GetOptValBool(options, OPT_NOINT10, &noint10); - return noint10; -} - -Bool -int10_check_bios(int scrnIndex, int codeSeg, const unsigned char* vbiosMem) -{ - int size; - - if ((codeSeg & 0x1f) || /* Not 512-byte aligned otherwise */ - ((codeSeg << 4) < V_BIOS) || - ((codeSeg << 4) >= SYS_SIZE)) - return FALSE; - - if (xf86IsPc98()) - return FALSE; - - if ((*vbiosMem != 0x55) || (*(vbiosMem+1) != 0xAA) || !*(vbiosMem+2)) - return FALSE; - - size = *(vbiosMem + 2) * 512; - - if ((size + (codeSeg << 4)) > SYS_SIZE) - return FALSE; - - if (bios_checksum(vbiosMem, size)) - xf86DrvMsg(scrnIndex, X_INFO, "Bad V_BIOS checksum\n"); - - return TRUE; -} - -Bool -initPrimary(const void* options) -{ - Bool initPrimary = FALSE; - - if (!options) return FALSE; - - xf86GetOptValBool(options, OPT_INIT_PRIMARY, &initPrimary); - return initPrimary; -} - -BusType -xf86int10GetBiosLocationType(const xf86Int10InfoPtr pInt) -{ - BusType location_type; - - EntityInfoPtr pEnt = xf86GetEntityInfo(pInt->entityIndex); - location_type = pEnt->location.type; - xfree(pEnt); - - return location_type; -} - - -#define CHECK_V_SEGMENT_RANGE(x) \ - if (((x) << 4) < V_BIOS) { \ - xf86DrvMsg(pInt->scrnIndex, X_ERROR, \ - "V_BIOS address 0x%lx out of range\n", \ - (unsigned long)(x) << 4); \ - return FALSE; \ - } - -Bool -xf86int10GetBiosSegment(xf86Int10InfoPtr pInt, void *base) -{ - unsigned i; - int cs = ~0; - int segments[4]; - const char * format; - - segments[0] = MEM_RW(pInt, (0x10 << 2) + 2); - segments[1] = MEM_RW(pInt, (0x42 << 2) + 2); - segments[2] = V_BIOS >> 4; - segments[3] = ~0; - - format = "No V_BIOS found\n"; - - for (i = 0; segments[i] != ~0; i++) { - unsigned char * vbiosMem; - - cs = segments[i]; - - CHECK_V_SEGMENT_RANGE(cs); - vbiosMem = (unsigned char *)base + (cs << 4); - if (int10_check_bios(pInt->scrnIndex, cs, vbiosMem)) { - break; - } - } - - if (segments[i] == ~0) { - xf86DrvMsg(pInt->scrnIndex, X_ERROR, format, (unsigned long)cs << 4); - return FALSE; - } - - xf86DrvMsg(pInt->scrnIndex, X_INFO, "Primary V_BIOS segment is: 0x%lx\n", - (unsigned long)cs); - - pInt->BIOSseg = cs; - return TRUE; -} +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> +#include <stdlib.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#include "xf86Pci.h" +#define _INT10_PRIVATE +#if 0 +#include "int10Defines.h" +#endif +#include "xf86int10.h" + +#define REG pInt + +typedef enum { + OPT_NOINT10, + OPT_INIT_PRIMARY, +} INT10Opts; + +static const OptionInfoRec INT10Options[] = { + {OPT_NOINT10, "NoINT10", OPTV_BOOLEAN, {0}, FALSE }, + {OPT_INIT_PRIMARY, "InitPrimary", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +#ifdef DEBUG +void +dprint(unsigned long start, unsigned long size) +{ + int i,j; + char *c = (char *)start; + + for (j = 0; j < (size >> 4); j++) { + char *d = c; + ErrorF("\n0x%lx: ",(unsigned long)c); + for (i = 0; i<16; i++) + ErrorF("%2.2x ",(unsigned char) (*(c++))); + c = d; + for (i = 0; i<16; i++) { + ErrorF("%c",((((CARD8)(*c)) > 32) && (((CARD8)(*c)) < 128)) ? + (unsigned char) (*(c)): '.'); + c++; + } + } + ErrorF("\n"); +} +#endif + +#ifndef _PC +/* + * here we are really paranoid about faking a "real" + * BIOS. Most of this information was pulled from + * dosemu. + */ +void +setup_int_vect(xf86Int10InfoPtr pInt) +{ + int i; + + /* let the int vects point to the SYS_BIOS seg */ + for (i = 0; i < 0x80; i++) { + MEM_WW(pInt, i << 2, 0); + MEM_WW(pInt, (i << 2) + 2, SYS_BIOS >> 4); + } + + reset_int_vect(pInt); + /* font tables default location (int 1F) */ + MEM_WW(pInt,0x1f<<2,0xfa6e); + + /* int 11 default location (Get Equipment Configuration) */ + MEM_WW(pInt, 0x11 << 2, 0xf84d); + /* int 12 default location (Get Conventional Memory Size) */ + MEM_WW(pInt, 0x12 << 2, 0xf841); + /* int 15 default location (I/O System Extensions) */ + MEM_WW(pInt, 0x15 << 2, 0xf859); + /* int 1A default location (RTC, PCI and others) */ + MEM_WW(pInt, 0x1a << 2, 0xff6e); + /* int 05 default location (Bound Exceeded) */ + MEM_WW(pInt, 0x05 << 2, 0xff54); + /* int 08 default location (Double Fault) */ + MEM_WW(pInt, 0x08 << 2, 0xfea5); + /* int 13 default location (Disk) */ + MEM_WW(pInt, 0x13 << 2, 0xec59); + /* int 0E default location (Page Fault) */ + MEM_WW(pInt, 0x0e << 2, 0xef57); + /* int 17 default location (Parallel Port) */ + MEM_WW(pInt, 0x17 << 2, 0xefd2); + /* fdd table default location (int 1e) */ + MEM_WW(pInt, 0x1e << 2, 0xefc7); + + /* Set Equipment flag to VGA */ + i = MEM_RB(pInt, 0x0410) & 0xCF; + MEM_WB(pInt, 0x0410, i); + /* XXX Perhaps setup more of the BDA here. See also int42(0x00). */ +} +#endif + +int +setup_system_bios(void *base_addr) +{ + char *base = (char *) base_addr; + + /* + * we trap the "industry standard entry points" to the BIOS + * and all other locations by filling them with "hlt" + * TODO: implement hlt-handler for these + */ + memset(base, 0xf4, 0x10000); + + /* set bios date */ + strcpy(base + 0x0FFF5, "06/11/99"); + /* set up eisa ident string */ + strcpy(base + 0x0FFD9, "PCI_ISA"); + /* write system model id for IBM-AT */ + *((unsigned char *)(base + 0x0FFFE)) = 0xfc; + + return 1; +} + +void +reset_int_vect(xf86Int10InfoPtr pInt) +{ + /* + * This table is normally located at 0xF000:0xF0A4. However, int 0x42, + * function 0 (Mode Set) expects it (or a copy) somewhere in the bottom + * 64kB. Note that because this data doesn't survive POST, int 0x42 should + * only be used during EGA/VGA BIOS initialisation. + */ + static const CARD8 VideoParms[] = { + /* Timing for modes 0x00 & 0x01 */ + 0x38, 0x28, 0x2d, 0x0a, 0x1f, 0x06, 0x19, 0x1c, + 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + /* Timing for modes 0x02 & 0x03 */ + 0x71, 0x50, 0x5a, 0x0a, 0x1f, 0x06, 0x19, 0x1c, + 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + /* Timing for modes 0x04, 0x05 & 0x06 */ + 0x38, 0x28, 0x2d, 0x0a, 0x7f, 0x06, 0x64, 0x70, + 0x02, 0x01, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + /* Timing for mode 0x07 */ + 0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19, + 0x02, 0x0d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + /* Display page lengths in little endian order */ + 0x00, 0x08, /* Modes 0x00 and 0x01 */ + 0x00, 0x10, /* Modes 0x02 and 0x03 */ + 0x00, 0x40, /* Modes 0x04 and 0x05 */ + 0x00, 0x40, /* Modes 0x06 and 0x07 */ + /* Number of columns for each mode */ + 40, 40, 80, 80, 40, 40, 80, 80, + /* CGA Mode register value for each mode */ + 0x2c, 0x28, 0x2d, 0x29, 0x2a, 0x2e, 0x1e, 0x29, + /* Padding */ + 0x00, 0x00, 0x00, 0x00 + }; + int i; + + for (i = 0; i < sizeof(VideoParms); i++) + MEM_WB(pInt, i + (0x1000 - sizeof(VideoParms)), VideoParms[i]); + MEM_WW(pInt, 0x1d << 2, 0x1000 - sizeof(VideoParms)); + MEM_WW(pInt, (0x1d << 2) + 2, 0); + + MEM_WW(pInt, 0x10 << 2, 0xf065); + MEM_WW(pInt, (0x10 << 2) + 2, SYS_BIOS >> 4); + MEM_WW(pInt, 0x42 << 2, 0xf065); + MEM_WW(pInt, (0x42 << 2) + 2, SYS_BIOS >> 4); + MEM_WW(pInt, 0x6D << 2, 0xf065); + MEM_WW(pInt, (0x6D << 2) + 2, SYS_BIOS >> 4); +} + +void +set_return_trap(xf86Int10InfoPtr pInt) +{ + /* + * Here we set the exit condition: We return when we encounter + * 'hlt' (=0xf4), which we locate at address 0x600 in x86 memory. + */ + MEM_WB(pInt, 0x0600, 0xf4); + + /* + * Allocate a segment for the stack + */ + xf86Int10AllocPages(pInt, 1, &pInt->stackseg); +} + +void * +xf86HandleInt10Options(ScrnInfoPtr pScrn, int entityIndex) +{ + EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); + OptionInfoPtr options = NULL; + + if (pEnt->device) { + pointer configOptions = NULL; + + /* Check if xf86CollectOptions() has already been called */ + if (((pEnt->index < 0) || + !pScrn || + !(configOptions = pScrn->options)) && + pEnt->device) + configOptions = pEnt->device->options; + + if (configOptions) { + if (!(options = (OptionInfoPtr) malloc(sizeof(INT10Options)))) + return NULL; + + (void)memcpy(options, INT10Options, sizeof(INT10Options)); + xf86ProcessOptions(pScrn->scrnIndex, configOptions, options); + } + } + free(pEnt); + + return options; +} + +Bool +int10skip(const void* options) +{ + Bool noint10 = FALSE; + + if (!options) return FALSE; + + xf86GetOptValBool(options, OPT_NOINT10, &noint10); + return noint10; +} + +Bool +int10_check_bios(int scrnIndex, int codeSeg, const unsigned char* vbiosMem) +{ + int size; + + if ((codeSeg & 0x1f) || /* Not 512-byte aligned otherwise */ + ((codeSeg << 4) < V_BIOS) || + ((codeSeg << 4) >= SYS_SIZE)) + return FALSE; + + if (xf86IsPc98()) + return FALSE; + + if ((*vbiosMem != 0x55) || (*(vbiosMem+1) != 0xAA) || !*(vbiosMem+2)) + return FALSE; + + size = *(vbiosMem + 2) * 512; + + if ((size + (codeSeg << 4)) > SYS_SIZE) + return FALSE; + + if (bios_checksum(vbiosMem, size)) + xf86DrvMsg(scrnIndex, X_INFO, "Bad V_BIOS checksum\n"); + + return TRUE; +} + +Bool +initPrimary(const void* options) +{ + Bool initPrimary = FALSE; + + if (!options) return FALSE; + + xf86GetOptValBool(options, OPT_INIT_PRIMARY, &initPrimary); + return initPrimary; +} + +BusType +xf86int10GetBiosLocationType(const xf86Int10InfoPtr pInt) +{ + BusType location_type; + + EntityInfoPtr pEnt = xf86GetEntityInfo(pInt->entityIndex); + location_type = pEnt->location.type; + free(pEnt); + + return location_type; +} + + +#define CHECK_V_SEGMENT_RANGE(x) \ + if (((x) << 4) < V_BIOS) { \ + xf86DrvMsg(pInt->scrnIndex, X_ERROR, \ + "V_BIOS address 0x%lx out of range\n", \ + (unsigned long)(x) << 4); \ + return FALSE; \ + } + +Bool +xf86int10GetBiosSegment(xf86Int10InfoPtr pInt, void *base) +{ + unsigned i; + int cs = ~0; + int segments[4]; + const char * format; + + segments[0] = MEM_RW(pInt, (0x10 << 2) + 2); + segments[1] = MEM_RW(pInt, (0x42 << 2) + 2); + segments[2] = V_BIOS >> 4; + segments[3] = ~0; + + format = "No V_BIOS found\n"; + + for (i = 0; segments[i] != ~0; i++) { + unsigned char * vbiosMem; + + cs = segments[i]; + + CHECK_V_SEGMENT_RANGE(cs); + vbiosMem = (unsigned char *)base + (cs << 4); + if (int10_check_bios(pInt->scrnIndex, cs, vbiosMem)) { + break; + } + } + + if (segments[i] == ~0) { + xf86DrvMsg(pInt->scrnIndex, X_ERROR, format, (unsigned long)cs << 4); + return FALSE; + } + + xf86DrvMsg(pInt->scrnIndex, X_INFO, "Primary V_BIOS segment is: 0x%lx\n", + (unsigned long)cs); + + pInt->BIOSseg = cs; + return TRUE; +} diff --git a/xorg-server/hw/xfree86/loader/loadext.c b/xorg-server/hw/xfree86/loader/loadext.c index 29cdaf1ac..26066856d 100644 --- a/xorg-server/hw/xfree86/loader/loadext.c +++ b/xorg-server/hw/xfree86/loader/loadext.c @@ -1,442 +1,442 @@ -/* - * Copyright (c) 2000 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -/* Maybe this file belongs elsewhere? */ - -#define LOADERDECLARATIONS -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "loaderProcs.h" -#include "misc.h" -#include "xf86.h" - -/* - * This should be static, but miinitext wants it. FIXME: make extension - * initialization not completely terrible. - */ -ExtensionModule *ExtensionModuleList = NULL; -static int numExtensionModules = 0; - -static ExtensionModule * -NewExtensionModule(void) -{ - ExtensionModule *save = ExtensionModuleList; - int n; - - /* Sanity check */ - if (!ExtensionModuleList) - numExtensionModules = 0; - - n = numExtensionModules + 1; - ExtensionModuleList = xrealloc(ExtensionModuleList, - (n + 1) * sizeof(ExtensionModule)); - if (ExtensionModuleList == NULL) { - ExtensionModuleList = save; - return NULL; - } else { - numExtensionModules++; - ExtensionModuleList[numExtensionModules].name = NULL; - return ExtensionModuleList + (numExtensionModules - 1); - } -} - -void -LoadExtension(ExtensionModule * e, Bool builtin) -{ - ExtensionModule *newext; - - if (e == NULL || e->name == NULL) - return; - - if (!(newext = NewExtensionModule())) - return; - - if (builtin) - xf86MsgVerb(X_INFO, 2, "Initializing built-in extension %s\n", - e->name); - else - xf86MsgVerb(X_INFO, 2, "Loading extension %s\n", e->name); - - newext->name = e->name; - newext->initFunc = e->initFunc; - newext->disablePtr = e->disablePtr; - newext->setupFunc = e->setupFunc; - newext->initDependencies = e->initDependencies; - - if (e->setupFunc != NULL) - e->setupFunc(); -} - -/* - * Sort ExtensionModuleList according to the initialisation order - * dependencies. The code for this is taken from BSD's tsort, - * and carries the following copyright/license: - * - * - * Copyright (c) 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Michael Rendell of Memorial University of Newfoundland. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define NF_MARK 0x1 /* marker for cycle detection */ -#define NF_ACYCLIC 0x2 /* this node is cycle free */ -#define NF_NODEST 0x4 /* Unreachable */ - -typedef struct node_str NODE; -struct node_str { - NODE **n_prevp; /* pointer to previous node's n_next */ - NODE *n_next; /* next node in graph */ - NODE **n_arcs; /* array of arcs to other nodes */ - int n_narcs; /* number of arcs in n_arcs[] */ - int n_arcsize; /* size of n_arcs[] array */ - int n_refcnt; /* # of arcs pointing to this node */ - int n_flags; /* NF_* */ - const char *n_name; /* name of this node */ -}; - -static NODE *graph = NULL, **cycle_buf = NULL, **longest_cycle = NULL; -static int longest = 0; -static NODE *sorted = NULL, *last = NULL; - -/* Find a node in the graph (insert if not found) and return a pointer to it. */ -static NODE * -get_node(const char *name) -{ - NODE *n; - - for (n = graph; n && n->n_name && strcmp(n->n_name, name); - n = n->n_next) ; - if (n) - return (n); - - n = xnfalloc(sizeof(NODE)); - - n->n_narcs = 0; - n->n_arcsize = 0; - n->n_arcs = NULL; - n->n_refcnt = 0; - n->n_flags = 0; - n->n_name = name; - - /* Add to linked list. */ - if ((n->n_next = graph) != NULL) - graph->n_prevp = &n->n_next; - n->n_prevp = &graph; - graph = n; - - return (n); -} - -/* - * add an arc from node s1 to node s2 in the graph. If s1 or s2 are not in - * the graph, then add them. - */ -static void -add_arc(const char *s1, const char *s2) -{ - NODE *n1; - NODE *n2; - int bsize, i; - - n1 = get_node(s1); - - if (!strcmp(s1, s2)) - return; - - n2 = get_node(s2); - - /* - * Check if this arc is already here. - */ - for (i = 0; i < n1->n_narcs; i++) - if (n1->n_arcs[i] == n2) - return; - /* - * Add it. - */ - if (n1->n_narcs == n1->n_arcsize) { - if (!n1->n_arcsize) - n1->n_arcsize = 10; - bsize = n1->n_arcsize * sizeof(*n1->n_arcs) * 2; - n1->n_arcs = xnfrealloc(n1->n_arcs, bsize); - n1->n_arcsize = bsize / sizeof(*n1->n_arcs); - } - n1->n_arcs[n1->n_narcs++] = n2; - ++n2->n_refcnt; -} - -/* - * Clear the NODEST flag from all nodes. - */ -static void -clear_cycle(void) -{ - NODE *n; - - for (n = graph; n != NULL; n = n->n_next) - n->n_flags &= ~NF_NODEST; -} - -/* print node and remove from graph (does not actually free node) */ -static void -remove_node(NODE * n) -{ - NODE **np; - NODE *newnode; - int i; - -#ifdef DEBUG - ErrorF("%s\n", n->n_name); -#endif - newnode = xnfalloc(sizeof(NODE)); - memcpy(newnode, n, sizeof(NODE)); - if (last) - last->n_next = newnode; - else - sorted = newnode; - last = newnode; - newnode->n_next = NULL; - - for (np = n->n_arcs, i = n->n_narcs; --i >= 0; np++) - --(*np)->n_refcnt; - n->n_narcs = 0; - *n->n_prevp = n->n_next; - if (n->n_next) - n->n_next->n_prevp = n->n_prevp; -} - -static void -free_nodes(NODE * nodelist) -{ - NODE *n, *nextnode; - - for (n = nodelist; n;) { - nextnode = n->n_next; - xfree(n); - n = nextnode; - } -} - -/* look for the longest? cycle from node from to node to. */ -static int -find_cycle(NODE * from, NODE * to, int longest_len, int depth) -{ - NODE **np; - int i, len; - - /* - * avoid infinite loops and ignore portions of the graph known - * to be acyclic - */ - if (from->n_flags & (NF_NODEST | NF_MARK | NF_ACYCLIC)) - return (0); - from->n_flags |= NF_MARK; - - for (np = from->n_arcs, i = from->n_narcs; --i >= 0; np++) { - cycle_buf[depth] = *np; - if (*np == to) { - if (depth + 1 > longest_len) { - longest_len = depth + 1; - memcpy((char *)longest_cycle, - (char *)cycle_buf, longest_len * sizeof(NODE *)); - } - } else { - if ((*np)->n_flags & (NF_MARK | NF_ACYCLIC | NF_NODEST)) - continue; - len = find_cycle(*np, to, longest_len, depth + 1); - -#ifdef DEBUG - ErrorF("%*s %s->%s %d\n", depth, "", - from->n_name, to->n_name, len); -#endif - - if (len == 0) - (*np)->n_flags |= NF_NODEST; - - if (len > longest_len) - longest_len = len; - - if (len > 0 && !longest) - break; - } - } - from->n_flags &= ~NF_MARK; - return (longest_len); -} - -/* do topological sort on graph */ -static void -tsort(void) -{ - NODE *n, *next; - int cnt, i; - - while (graph != NULL) { - /* - * Keep getting rid of simple cases until there are none left, - * if there are any nodes still in the graph, then there is - * a cycle in it. - */ - do { - for (cnt = 0, n = graph; n != NULL; n = next) { - next = n->n_next; - if (n->n_refcnt == 0) { - remove_node(n); - ++cnt; - } - } - } while (graph != NULL && cnt); - - if (graph == NULL) - break; - - if (!cycle_buf) { - /* - * Allocate space for two cycle logs - one to be used - * as scratch space, the other to save the longest - * cycle. - */ - for (cnt = 0, n = graph; n != NULL; n = n->n_next) - ++cnt; - cycle_buf = xnfalloc(sizeof(NODE *) * cnt); - longest_cycle = xnfalloc(sizeof(NODE *) * cnt); - if (cycle_buf == NULL || longest_cycle == NULL) - return; - } - for (n = graph; n != NULL; n = n->n_next) - if (!(n->n_flags & NF_ACYCLIC)) { - if ((cnt = find_cycle(n, n, 0, 0))) { - ErrorF("tsort: cycle in data"); - for (i = 0; i < cnt; i++) - ErrorF("%s", longest_cycle[i]->n_name); - remove_node(n); - clear_cycle(); - break; - } else { - /* to avoid further checks */ - n->n_flags |= NF_ACYCLIC; - clear_cycle(); - } - } - - if (n == NULL) - ErrorF("tsort: internal error -- could not find cycle"); - } - if (cycle_buf) - xfree(cycle_buf); - if (longest_cycle) - xfree(longest_cycle); - if (graph) - free_nodes(graph); -} - -void -LoaderSortExtensions(void) -{ - int i, j; - ExtensionModule *ext, *newList; - NODE *node; - - graph = NULL; - longest = 0; - sorted = NULL; - last = NULL; - cycle_buf = NULL; - longest_cycle = NULL; - - /* - * Parse list and build the graph. Enter them in reverse order - * because tsort() will reverse those that have no depedencies. - */ - for (i = numExtensionModules - 1; i >= 0; i--) { - ext = &ExtensionModuleList[i]; - add_arc(ext->name, ext->name); -#ifdef DEBUG - ErrorF("Extension %s:\n", ext->name); -#endif - if (ext->initDependencies) - for (j = 0; ext->initDependencies[j]; j++) { - add_arc(ext->initDependencies[j], ext->name); -#ifdef DEBUG - ErrorF("\t%s\n", ext->initDependencies[j]); -#endif - } - } - tsort(); - newList = xnfalloc((numExtensionModules + 1) * sizeof(ExtensionModule)); - i = 0; - for (node = sorted; node; node = node->n_next) { - for (j = 0; j < numExtensionModules; j++) - if (!strcmp(node->n_name, ExtensionModuleList[j].name)) - break; - if (j != numExtensionModules) - newList[i++] = ExtensionModuleList[j]; - } - if (sorted) - free_nodes(sorted); - if (graph) - free_nodes(graph); - newList[i].name = NULL; - xfree(ExtensionModuleList); - ExtensionModuleList = newList; -#ifdef DEBUG - for (i = 0; ExtensionModuleList[i].name; i++) - ErrorF("Extension %s\n", ExtensionModuleList[i].name); -#endif -} +/* + * Copyright (c) 2000 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +/* Maybe this file belongs elsewhere? */ + +#define LOADERDECLARATIONS +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "loaderProcs.h" +#include "misc.h" +#include "xf86.h" + +/* + * This should be static, but miinitext wants it. FIXME: make extension + * initialization not completely terrible. + */ +ExtensionModule *ExtensionModuleList = NULL; +static int numExtensionModules = 0; + +static ExtensionModule * +NewExtensionModule(void) +{ + ExtensionModule *save = ExtensionModuleList; + int n; + + /* Sanity check */ + if (!ExtensionModuleList) + numExtensionModules = 0; + + n = numExtensionModules + 1; + ExtensionModuleList = realloc(ExtensionModuleList, + (n + 1) * sizeof(ExtensionModule)); + if (ExtensionModuleList == NULL) { + ExtensionModuleList = save; + return NULL; + } else { + numExtensionModules++; + ExtensionModuleList[numExtensionModules].name = NULL; + return ExtensionModuleList + (numExtensionModules - 1); + } +} + +void +LoadExtension(ExtensionModule * e, Bool builtin) +{ + ExtensionModule *newext; + + if (e == NULL || e->name == NULL) + return; + + if (!(newext = NewExtensionModule())) + return; + + if (builtin) + xf86MsgVerb(X_INFO, 2, "Initializing built-in extension %s\n", + e->name); + else + xf86MsgVerb(X_INFO, 2, "Loading extension %s\n", e->name); + + newext->name = e->name; + newext->initFunc = e->initFunc; + newext->disablePtr = e->disablePtr; + newext->setupFunc = e->setupFunc; + newext->initDependencies = e->initDependencies; + + if (e->setupFunc != NULL) + e->setupFunc(); +} + +/* + * Sort ExtensionModuleList according to the initialisation order + * dependencies. The code for this is taken from BSD's tsort, + * and carries the following copyright/license: + * + * + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Rendell of Memorial University of Newfoundland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define NF_MARK 0x1 /* marker for cycle detection */ +#define NF_ACYCLIC 0x2 /* this node is cycle free */ +#define NF_NODEST 0x4 /* Unreachable */ + +typedef struct node_str NODE; +struct node_str { + NODE **n_prevp; /* pointer to previous node's n_next */ + NODE *n_next; /* next node in graph */ + NODE **n_arcs; /* array of arcs to other nodes */ + int n_narcs; /* number of arcs in n_arcs[] */ + int n_arcsize; /* size of n_arcs[] array */ + int n_refcnt; /* # of arcs pointing to this node */ + int n_flags; /* NF_* */ + const char *n_name; /* name of this node */ +}; + +static NODE *graph = NULL, **cycle_buf = NULL, **longest_cycle = NULL; +static int longest = 0; +static NODE *sorted = NULL, *last = NULL; + +/* Find a node in the graph (insert if not found) and return a pointer to it. */ +static NODE * +get_node(const char *name) +{ + NODE *n; + + for (n = graph; n && n->n_name && strcmp(n->n_name, name); + n = n->n_next) ; + if (n) + return (n); + + n = xnfalloc(sizeof(NODE)); + + n->n_narcs = 0; + n->n_arcsize = 0; + n->n_arcs = NULL; + n->n_refcnt = 0; + n->n_flags = 0; + n->n_name = name; + + /* Add to linked list. */ + if ((n->n_next = graph) != NULL) + graph->n_prevp = &n->n_next; + n->n_prevp = &graph; + graph = n; + + return (n); +} + +/* + * add an arc from node s1 to node s2 in the graph. If s1 or s2 are not in + * the graph, then add them. + */ +static void +add_arc(const char *s1, const char *s2) +{ + NODE *n1; + NODE *n2; + int bsize, i; + + n1 = get_node(s1); + + if (!strcmp(s1, s2)) + return; + + n2 = get_node(s2); + + /* + * Check if this arc is already here. + */ + for (i = 0; i < n1->n_narcs; i++) + if (n1->n_arcs[i] == n2) + return; + /* + * Add it. + */ + if (n1->n_narcs == n1->n_arcsize) { + if (!n1->n_arcsize) + n1->n_arcsize = 10; + bsize = n1->n_arcsize * sizeof(*n1->n_arcs) * 2; + n1->n_arcs = xnfrealloc(n1->n_arcs, bsize); + n1->n_arcsize = bsize / sizeof(*n1->n_arcs); + } + n1->n_arcs[n1->n_narcs++] = n2; + ++n2->n_refcnt; +} + +/* + * Clear the NODEST flag from all nodes. + */ +static void +clear_cycle(void) +{ + NODE *n; + + for (n = graph; n != NULL; n = n->n_next) + n->n_flags &= ~NF_NODEST; +} + +/* print node and remove from graph (does not actually free node) */ +static void +remove_node(NODE * n) +{ + NODE **np; + NODE *newnode; + int i; + +#ifdef DEBUG + ErrorF("%s\n", n->n_name); +#endif + newnode = xnfalloc(sizeof(NODE)); + memcpy(newnode, n, sizeof(NODE)); + if (last) + last->n_next = newnode; + else + sorted = newnode; + last = newnode; + newnode->n_next = NULL; + + for (np = n->n_arcs, i = n->n_narcs; --i >= 0; np++) + --(*np)->n_refcnt; + n->n_narcs = 0; + *n->n_prevp = n->n_next; + if (n->n_next) + n->n_next->n_prevp = n->n_prevp; +} + +static void +free_nodes(NODE * nodelist) +{ + NODE *n, *nextnode; + + for (n = nodelist; n;) { + nextnode = n->n_next; + free(n); + n = nextnode; + } +} + +/* look for the longest? cycle from node from to node to. */ +static int +find_cycle(NODE * from, NODE * to, int longest_len, int depth) +{ + NODE **np; + int i, len; + + /* + * avoid infinite loops and ignore portions of the graph known + * to be acyclic + */ + if (from->n_flags & (NF_NODEST | NF_MARK | NF_ACYCLIC)) + return (0); + from->n_flags |= NF_MARK; + + for (np = from->n_arcs, i = from->n_narcs; --i >= 0; np++) { + cycle_buf[depth] = *np; + if (*np == to) { + if (depth + 1 > longest_len) { + longest_len = depth + 1; + memcpy((char *)longest_cycle, + (char *)cycle_buf, longest_len * sizeof(NODE *)); + } + } else { + if ((*np)->n_flags & (NF_MARK | NF_ACYCLIC | NF_NODEST)) + continue; + len = find_cycle(*np, to, longest_len, depth + 1); + +#ifdef DEBUG + ErrorF("%*s %s->%s %d\n", depth, "", + from->n_name, to->n_name, len); +#endif + + if (len == 0) + (*np)->n_flags |= NF_NODEST; + + if (len > longest_len) + longest_len = len; + + if (len > 0 && !longest) + break; + } + } + from->n_flags &= ~NF_MARK; + return (longest_len); +} + +/* do topological sort on graph */ +static void +tsort(void) +{ + NODE *n, *next; + int cnt, i; + + while (graph != NULL) { + /* + * Keep getting rid of simple cases until there are none left, + * if there are any nodes still in the graph, then there is + * a cycle in it. + */ + do { + for (cnt = 0, n = graph; n != NULL; n = next) { + next = n->n_next; + if (n->n_refcnt == 0) { + remove_node(n); + ++cnt; + } + } + } while (graph != NULL && cnt); + + if (graph == NULL) + break; + + if (!cycle_buf) { + /* + * Allocate space for two cycle logs - one to be used + * as scratch space, the other to save the longest + * cycle. + */ + for (cnt = 0, n = graph; n != NULL; n = n->n_next) + ++cnt; + cycle_buf = xnfalloc(sizeof(NODE *) * cnt); + longest_cycle = xnfalloc(sizeof(NODE *) * cnt); + if (cycle_buf == NULL || longest_cycle == NULL) + return; + } + for (n = graph; n != NULL; n = n->n_next) + if (!(n->n_flags & NF_ACYCLIC)) { + if ((cnt = find_cycle(n, n, 0, 0))) { + ErrorF("tsort: cycle in data"); + for (i = 0; i < cnt; i++) + ErrorF("%s", longest_cycle[i]->n_name); + remove_node(n); + clear_cycle(); + break; + } else { + /* to avoid further checks */ + n->n_flags |= NF_ACYCLIC; + clear_cycle(); + } + } + + if (n == NULL) + ErrorF("tsort: internal error -- could not find cycle"); + } + if (cycle_buf) + free(cycle_buf); + if (longest_cycle) + free(longest_cycle); + if (graph) + free_nodes(graph); +} + +void +LoaderSortExtensions(void) +{ + int i, j; + ExtensionModule *ext, *newList; + NODE *node; + + graph = NULL; + longest = 0; + sorted = NULL; + last = NULL; + cycle_buf = NULL; + longest_cycle = NULL; + + /* + * Parse list and build the graph. Enter them in reverse order + * because tsort() will reverse those that have no depedencies. + */ + for (i = numExtensionModules - 1; i >= 0; i--) { + ext = &ExtensionModuleList[i]; + add_arc(ext->name, ext->name); +#ifdef DEBUG + ErrorF("Extension %s:\n", ext->name); +#endif + if (ext->initDependencies) + for (j = 0; ext->initDependencies[j]; j++) { + add_arc(ext->initDependencies[j], ext->name); +#ifdef DEBUG + ErrorF("\t%s\n", ext->initDependencies[j]); +#endif + } + } + tsort(); + newList = xnfalloc((numExtensionModules + 1) * sizeof(ExtensionModule)); + i = 0; + for (node = sorted; node; node = node->n_next) { + for (j = 0; j < numExtensionModules; j++) + if (!strcmp(node->n_name, ExtensionModuleList[j].name)) + break; + if (j != numExtensionModules) + newList[i++] = ExtensionModuleList[j]; + } + if (sorted) + free_nodes(sorted); + if (graph) + free_nodes(graph); + newList[i].name = NULL; + free(ExtensionModuleList); + ExtensionModuleList = newList; +#ifdef DEBUG + for (i = 0; ExtensionModuleList[i].name; i++) + ErrorF("Extension %s\n", ExtensionModuleList[i].name); +#endif +} diff --git a/xorg-server/hw/xfree86/loader/loadmod.c b/xorg-server/hw/xfree86/loader/loadmod.c index 5b175a546..e75ec8f69 100644 --- a/xorg-server/hw/xfree86/loader/loadmod.c +++ b/xorg-server/hw/xfree86/loader/loadmod.c @@ -1,1268 +1,1268 @@ -/* - * Copyright 1995-1998 by Metro Link, Inc. - * - * 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 Metro Link, Inc. not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Metro Link, Inc. makes no - * representations about the suitability of this software for any purpose. - * It is provided "as is" without express or implied warranty. - * - * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL METRO LINK, INC. 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. - */ -/* - * Copyright (c) 1997-2002 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "os.h" -/* For stat() and related stuff */ -#define NO_OSLIB_PROTOTYPES -#include "xf86_OSlib.h" -#define LOADERDECLARATIONS -#include "loaderProcs.h" -#include "misc.h" -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86Xinput.h" -#include "loader.h" -#include "xf86Optrec.h" - -#include <sys/types.h> -#include <regex.h> -#include <dirent.h> -#include <limits.h> - -typedef struct _pattern { - const char *pattern; - regex_t rex; -} PatternRec, *PatternPtr; - -/* Prototypes for static functions */ -static char *FindModule(const char *, const char *, const char **, - PatternPtr); -static Bool CheckVersion(const char *, XF86ModuleVersionInfo *, - const XF86ModReqInfo *); -static void UnloadModuleOrDriver(ModuleDescPtr mod); -static char *LoaderGetCanonicalName(const char *, PatternPtr); -static void RemoveChild(ModuleDescPtr); -static ModuleDescPtr doLoadModule(const char *, const char *, const char **, - const char **, pointer, - const XF86ModReqInfo *, int *, int *, - int flags); - -const ModuleVersions LoaderVersionInfo = { - XORG_VERSION_CURRENT, - ABI_ANSIC_VERSION, - ABI_VIDEODRV_VERSION, - ABI_XINPUT_VERSION, - ABI_EXTENSION_VERSION, - ABI_FONT_VERSION -}; - -static void -FreeStringList(char **paths) -{ - char **p; - - if (!paths) - return; - - for (p = paths; *p; p++) - xfree(*p); - - xfree(paths); -} - -static char **defaultPathList = NULL; - -static Bool -PathIsAbsolute(const char *path) -{ - return (*path == '/'); -} - -/* - * Convert a comma-separated path into a NULL-terminated array of path - * elements, rejecting any that are not full absolute paths, and appending - * a '/' when it isn't already present. - */ -static char ** -InitPathList(const char *path) -{ - char *fullpath = NULL; - char *elem = NULL; - char **list = NULL, **save = NULL; - int len; - int addslash; - int n = 0; - - if (!path) - return defaultPathList; - - fullpath = xstrdup(path); - if (!fullpath) - return NULL; - elem = strtok(fullpath, ","); - while (elem) { - if (PathIsAbsolute(elem)) - { - len = strlen(elem); - addslash = (elem[len - 1] != '/'); - if (addslash) - len++; - save = list; - list = xrealloc(list, (n + 2) * sizeof(char *)); - if (!list) { - if (save) { - save[n] = NULL; - FreeStringList(save); - } - xfree(fullpath); - return NULL; - } - list[n] = xalloc(len + 1); - if (!list[n]) { - FreeStringList(list); - xfree(fullpath); - return NULL; - } - strcpy(list[n], elem); - if (addslash) { - list[n][len - 1] = '/'; - list[n][len] = '\0'; - } - n++; - } - elem = strtok(NULL, ","); - } - if (list) - list[n] = NULL; - xfree(fullpath); - return list; -} - -static void -FreePathList(char **pathlist) -{ - if (pathlist && pathlist != defaultPathList) - FreeStringList(pathlist); -} - -void -LoaderSetPath(const char *path) -{ - if (!path) - return; - - defaultPathList = InitPathList(path); -} - -/* Standard set of module subdirectories to search, in order of preference */ -static const char *stdSubdirs[] = { - "", - "input/", - "drivers/", - "multimedia/", - "extensions/", - "internal/", - NULL -}; - -/* - * Standard set of module name patterns to check, in order of preference - * These are regular expressions (suitable for use with POSIX regex(3)). - * - * This list assumes that you're an ELFish platform and therefore your - * shared libraries are named something.so. If we're ever nuts enough - * to port this DDX to, say, Darwin, we'll need to fix this. - */ -static PatternRec stdPatterns[] = { - {"^lib(.*)\\.so$",}, - {"(.*)_drv\\.so$",}, - {"(.*)\\.so$",}, - {NULL,} -}; - -static PatternPtr -InitPatterns(const char **patternlist) -{ - char errmsg[80]; - int i, e; - PatternPtr patterns = NULL; - PatternPtr p = NULL; - static int firstTime = 1; - const char **s; - - if (firstTime) { - /* precompile stdPatterns */ - firstTime = 0; - for (p = stdPatterns; p->pattern; p++) - if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { - regerror(e, &p->rex, errmsg, sizeof(errmsg)); - FatalError("InitPatterns: regcomp error for `%s': %s\n", - p->pattern, errmsg); - } - } - - if (patternlist) { - for (i = 0, s = patternlist; *s; i++, s++) - if (*s == DEFAULT_LIST) - i += sizeof(stdPatterns) / sizeof(stdPatterns[0]) - 1 - 1; - patterns = xalloc((i + 1) * sizeof(PatternRec)); - if (!patterns) { - return NULL; - } - for (i = 0, s = patternlist; *s; i++, s++) - if (*s != DEFAULT_LIST) { - p = patterns + i; - p->pattern = *s; - if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { - regerror(e, &p->rex, errmsg, sizeof(errmsg)); - ErrorF("InitPatterns: regcomp error for `%s': %s\n", - p->pattern, errmsg); - i--; - } - } else { - for (p = stdPatterns; p->pattern; p++, i++) - patterns[i] = *p; - if (p != stdPatterns) - i--; - } - patterns[i].pattern = NULL; - } else - patterns = stdPatterns; - return patterns; -} - -static void -FreePatterns(PatternPtr patterns) -{ - if (patterns && patterns != stdPatterns) - xfree(patterns); -} - -static const char ** -InitSubdirs(const char **subdirlist) -{ - int i; - const char **tmp_subdirlist = NULL; - char **subdirs = NULL; - const char **s, **stmp = NULL; - const char *osname; - const char *slash; - int oslen = 0, len; - Bool indefault; - - if (subdirlist == NULL) { - subdirlist = tmp_subdirlist = xalloc(2 * sizeof(char *)); - if (subdirlist == NULL) - return NULL; - subdirlist[0] = DEFAULT_LIST; - subdirlist[1] = NULL; - } - - LoaderGetOS(&osname, NULL, NULL, NULL); - oslen = strlen(osname); - - { - /* Count number of entries and check for invalid paths */ - for (i = 0, s = subdirlist; *s; i++, s++) { - if (*s == DEFAULT_LIST) { - i += sizeof(stdSubdirs) / sizeof(stdSubdirs[0]) - 1 - 1; - } else { - /* - * Path validity check. Don't allow absolute paths, or - * paths containing "..". To catch absolute paths on - * platforms that use driver letters, don't allow the ':' - * character to appear at all. - */ - if (**s == '/' || **s == '\\' || strchr(*s, ':') || - strstr(*s, "..")) { - xf86Msg(X_ERROR, "InitSubdirs: Bad subdir: \"%s\"\n", *s); - if (tmp_subdirlist) - xfree(tmp_subdirlist); - return NULL; - } - } - } - subdirs = xalloc((i * 2 + 1) * sizeof(char *)); - if (!subdirs) { - if (tmp_subdirlist) - xfree(tmp_subdirlist); - return NULL; - } - i = 0; - s = subdirlist; - indefault = FALSE; - while (*s) { - if (*s == DEFAULT_LIST) { - /* Divert to the default list */ - indefault = TRUE; - stmp = ++s; - s = stdSubdirs; - } - len = strlen(*s); - if (**s && (*s)[len - 1] != '/') { - slash = "/"; - len++; - } else - slash = ""; - len += oslen + 2; - if (!(subdirs[i] = xalloc(len))) { - while (--i >= 0) - xfree(subdirs[i]); - xfree(subdirs); - if (tmp_subdirlist) - xfree(tmp_subdirlist); - return NULL; - } - /* tack on the OS name */ - sprintf(subdirs[i], "%s%s%s/", *s, slash, osname); - i++; - /* path as given */ - subdirs[i] = xstrdup(*s); - i++; - s++; - if (indefault && !s) { - /* revert back to the main list */ - indefault = FALSE; - s = stmp; - } - } - subdirs[i] = NULL; - } - if (tmp_subdirlist) - xfree(tmp_subdirlist); - return (const char **)subdirs; -} - -static void -FreeSubdirs(const char **subdirs) -{ - const char **s; - - if (subdirs) { - for (s = subdirs; *s; s++) - xfree(*s); - xfree(subdirs); - } -} - -static char * -FindModuleInSubdir(const char *dirpath, const char *module) -{ - struct dirent *direntry = NULL; - DIR *dir = NULL; - char *ret = NULL, tmpBuf[PATH_MAX]; - struct stat stat_buf; - - dir = opendir(dirpath); - if (!dir) - return NULL; - - while ((direntry = readdir(dir))) { - if (direntry->d_name[0] == '.') - continue; - snprintf(tmpBuf, PATH_MAX, "%s%s/", dirpath, direntry->d_name); - /* the stat with the appended / fails for normal files, - and works for sub dirs fine, looks a bit strange in strace - but does seem to work */ - if ((stat(tmpBuf, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) { - if ((ret = FindModuleInSubdir(tmpBuf, module))) - break; - continue; - } - - snprintf(tmpBuf, PATH_MAX, "lib%s.so", module); - if (strcmp(direntry->d_name, tmpBuf) == 0) { - ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); - sprintf(ret, "%s%s", dirpath, tmpBuf); - break; - } - - snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module); - if (strcmp(direntry->d_name, tmpBuf) == 0) { - ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); - sprintf(ret, "%s%s", dirpath, tmpBuf); - break; - } - - snprintf(tmpBuf, PATH_MAX, "%s.so", module); - if (strcmp(direntry->d_name, tmpBuf) == 0) { - ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); - sprintf(ret, "%s%s", dirpath, tmpBuf); - break; - } - } - - closedir(dir); - return ret; -} - -static char * -FindModule(const char *module, const char *dirname, const char **subdirlist, - PatternPtr patterns) -{ - char buf[PATH_MAX + 1]; - char *dirpath = NULL; - char *name = NULL; - int dirlen; - const char **subdirs = NULL; - const char **s; - - dirpath = (char *)dirname; - if (strlen(dirpath) > PATH_MAX) - return NULL; - - subdirs = InitSubdirs(subdirlist); - if (!subdirs) - return NULL; - - for (s = subdirs; *s; s++) { - if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX) - continue; - strcpy(buf, dirpath); - strcat(buf, *s); - if ((name = FindModuleInSubdir(buf, module))) - break; - } - - FreeSubdirs(subdirs); - if (dirpath != dirname) - xfree(dirpath); - - return name; -} - -char ** -LoaderListDirs(const char **subdirlist, const char **patternlist) -{ - char buf[PATH_MAX + 1]; - char **pathlist; - char **elem; - const char **subdirs; - const char **s; - PatternPtr patterns; - PatternPtr p; - DIR *d; - struct dirent *dp; - regmatch_t match[2]; - struct stat stat_buf; - int len, dirlen; - char *fp; - char **listing = NULL; - char **save; - int n = 0; - - if (!(pathlist = InitPathList(NULL))) - return NULL; - if (!(subdirs = InitSubdirs(subdirlist))) { - FreePathList(pathlist); - return NULL; - } - if (!(patterns = InitPatterns(patternlist))) { - FreePathList(pathlist); - FreeSubdirs(subdirs); - return NULL; - } - - for (elem = pathlist; *elem; elem++) { - for (s = subdirs; *s; s++) { - if ((dirlen = strlen(*elem) + strlen(*s)) > PATH_MAX) - continue; - strcpy(buf, *elem); - strcat(buf, *s); - fp = buf + dirlen; - if (stat(buf, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode) && - (d = opendir(buf))) { - if (buf[dirlen - 1] != '/') { - buf[dirlen++] = '/'; - fp++; - } - while ((dp = readdir(d))) { - if (dirlen + strlen(dp->d_name) > PATH_MAX) - continue; - strcpy(fp, dp->d_name); - if (!(stat(buf, &stat_buf) == 0 && - S_ISREG(stat_buf.st_mode))) - continue; - for (p = patterns; p->pattern; p++) { - if (regexec(&p->rex, dp->d_name, 2, match, 0) == 0 && - match[1].rm_so != -1) { - len = match[1].rm_eo - match[1].rm_so; - save = listing; - listing = xrealloc(listing, - (n + 2) * sizeof(char *)); - if (!listing) { - if (save) { - save[n] = NULL; - FreeStringList(save); - } - FreePathList(pathlist); - FreeSubdirs(subdirs); - FreePatterns(patterns); - return NULL; - } - listing[n] = xalloc(len + 1); - if (!listing[n]) { - FreeStringList(listing); - FreePathList(pathlist); - FreeSubdirs(subdirs); - FreePatterns(patterns); - return NULL; - } - strncpy(listing[n], dp->d_name + match[1].rm_so, - len); - listing[n][len] = '\0'; - n++; - break; - } - } - } - closedir(d); - } - } - } - if (listing) - listing[n] = NULL; - return listing; -} - -void -LoaderFreeDirList(char **list) -{ - FreeStringList(list); -} - -static Bool -CheckVersion(const char *module, XF86ModuleVersionInfo * data, - const XF86ModReqInfo * req) -{ - int vercode[4]; - char verstr[4]; - long ver = data->xf86version; - MessageType errtype; - - xf86Msg(X_INFO, "Module %s: vendor=\"%s\"\n", - data->modname ? data->modname : "UNKNOWN!", - data->vendor ? data->vendor : "UNKNOWN!"); - - /* Check for the different scheme used in XFree86 4.0.x releases: - * ((((((((major << 7) | minor) << 7) | subminor) << 5) | beta) << 5) | alpha) - * Since it wasn't used in 4.1.0 or later, limit to versions in the 4.0.x - * range, which limits the overlap with the new version scheme to conflicts - * with 6.71.8.764 through 6.72.39.934. - */ - if ((ver > (4 << 24)) && (ver < ( (4 << 24) + (1 << 17)))) { - /* 4.0.x and earlier */ - verstr[1] = verstr[3] = 0; - verstr[2] = (ver & 0x1f) ? (ver & 0x1f) + 'a' - 1 : 0; - ver >>= 5; - verstr[0] = (ver & 0x1f) ? (ver & 0x1f) + 'A' - 1 : 0; - ver >>= 5; - vercode[2] = ver & 0x7f; - ver >>= 7; - vercode[1] = ver & 0x7f; - ver >>= 7; - vercode[0] = ver; - xf86ErrorF("\tcompiled for %d.%d", vercode[0], vercode[1]); - if (vercode[2] != 0) - xf86ErrorF(".%d", vercode[2]); - xf86ErrorF("%s%s, module version = %d.%d.%d\n", verstr, verstr + 2, - data->majorversion, data->minorversion, data->patchlevel); - } else { - vercode[0] = ver / 10000000; - vercode[1] = (ver / 100000) % 100; - vercode[2] = (ver / 1000) % 100; - vercode[3] = ver % 1000; - xf86ErrorF("\tcompiled for %d.%d.%d", vercode[0], vercode[1], - vercode[2]); - if (vercode[3] != 0) - xf86ErrorF(".%d", vercode[3]); - xf86ErrorF(", module version = %d.%d.%d\n", data->majorversion, - data->minorversion, data->patchlevel); - } - - if (data->moduleclass) - xf86ErrorFVerb(2, "\tModule class: %s\n", data->moduleclass); - - ver = -1; - if (data->abiclass) { - int abimaj, abimin; - int vermaj, vermin; - - if (!strcmp(data->abiclass, ABI_CLASS_ANSIC)) - ver = LoaderVersionInfo.ansicVersion; - else if (!strcmp(data->abiclass, ABI_CLASS_VIDEODRV)) - ver = LoaderVersionInfo.videodrvVersion; - else if (!strcmp(data->abiclass, ABI_CLASS_XINPUT)) - ver = LoaderVersionInfo.xinputVersion; - else if (!strcmp(data->abiclass, ABI_CLASS_EXTENSION)) - ver = LoaderVersionInfo.extensionVersion; - else if (!strcmp(data->abiclass, ABI_CLASS_FONT)) - ver = LoaderVersionInfo.fontVersion; - - abimaj = GET_ABI_MAJOR(data->abiversion); - abimin = GET_ABI_MINOR(data->abiversion); - xf86ErrorFVerb(2, "\tABI class: %s, version %d.%d\n", - data->abiclass, abimaj, abimin); - if (ver != -1) { - vermaj = GET_ABI_MAJOR(ver); - vermin = GET_ABI_MINOR(ver); - if (abimaj != vermaj) { - if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) - errtype = X_WARNING; - else - errtype = X_ERROR; - xf86MsgVerb(errtype, 0, - "module ABI major version (%d) doesn't" - " match the server's version (%d)\n", - abimaj, vermaj); - if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) - return FALSE; - } else if (abimin > vermin) { - if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) - errtype = X_WARNING; - else - errtype = X_ERROR; - xf86MsgVerb(errtype, 0, - "module ABI minor version (%d) is " - "newer than the server's version " - "(%d)\n", abimin, vermin); - if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) - return FALSE; - } - } - } - - /* Check against requirements that the caller has specified */ - if (req) { - if (req->majorversion != MAJOR_UNSPEC) { - if (data->majorversion != req->majorversion) { - xf86MsgVerb(X_WARNING, 2, "module major version (%d) " - "doesn't match required major version (%d)\n", - data->majorversion, req->majorversion); - return FALSE; - } else if (req->minorversion != MINOR_UNSPEC) { - if (data->minorversion < req->minorversion) { - xf86MsgVerb(X_WARNING, 2, "module minor version (%d) " - "is less than the required minor version (%d)\n", - data->minorversion, req->minorversion); - return FALSE; - } else if (data->minorversion == req->minorversion && - req->patchlevel != PATCH_UNSPEC) { - if (data->patchlevel < req->patchlevel) { - xf86MsgVerb(X_WARNING, 2, "module patch level (%d) " - "is less than the required patch level (%d)\n", - data->patchlevel, req->patchlevel); - return FALSE; - } - } - } - } - if (req->moduleclass) { - if (!data->moduleclass || - strcmp(req->moduleclass, data->moduleclass)) { - xf86MsgVerb(X_WARNING, 2, "Module class (%s) doesn't match " - "the required class (%s)\n", - data->moduleclass ? data->moduleclass : "<NONE>", - req->moduleclass); - return FALSE; - } - } else if (req->abiclass != ABI_CLASS_NONE) { - if (!data->abiclass || strcmp(req->abiclass, data->abiclass)) { - xf86MsgVerb(X_WARNING, 2, "ABI class (%s) doesn't match the " - "required ABI class (%s)\n", - data->abiclass ? data->abiclass : "<NONE>", - req->abiclass); - return FALSE; - } - } - if ((req->abiclass != ABI_CLASS_NONE) && - req->abiversion != ABI_VERS_UNSPEC) { - int reqmaj, reqmin, maj, min; - - reqmaj = GET_ABI_MAJOR(req->abiversion); - reqmin = GET_ABI_MINOR(req->abiversion); - maj = GET_ABI_MAJOR(data->abiversion); - min = GET_ABI_MINOR(data->abiversion); - if (maj != reqmaj) { - xf86MsgVerb(X_WARNING, 2, "ABI major version (%d) doesn't " - "match the required ABI major version (%d)\n", - maj, reqmaj); - return FALSE; - } - /* XXX Maybe this should be the other way around? */ - if (min > reqmin) { - xf86MsgVerb(X_WARNING, 2, "module ABI minor version (%d) " - "is newer than that available (%d)\n", min, reqmin); - return FALSE; - } - } - } - return TRUE; -} - -static ModuleDescPtr -AddSibling(ModuleDescPtr head, ModuleDescPtr new) -{ - new->sib = head; - return (new); -} - -pointer -LoadSubModule(pointer _parent, const char *module, - const char **subdirlist, const char **patternlist, - pointer options, const XF86ModReqInfo * modreq, - int *errmaj, int *errmin) -{ - ModuleDescPtr submod; - ModuleDescPtr parent = (ModuleDescPtr)_parent; - - xf86MsgVerb(X_INFO, 3, "Loading sub module \"%s\"\n", module); - - if (PathIsAbsolute(module)) { - xf86Msg(X_ERROR, - "LoadSubModule: Absolute module path not permitted: \"%s\"\n", - module); - if (errmaj) - *errmaj = LDR_BADUSAGE; - if (errmin) - *errmin = 0; - return NULL; - } - - submod = doLoadModule(module, NULL, subdirlist, patternlist, options, - modreq, errmaj, errmin, LD_FLAG_GLOBAL); - if (submod && submod != (ModuleDescPtr) 1) { - parent->child = AddSibling(parent->child, submod); - submod->parent = parent; - } - return submod; -} - -static ModuleDescPtr -NewModuleDesc(const char *name) -{ - ModuleDescPtr mdp = xalloc(sizeof(ModuleDesc)); - - if (mdp) { - mdp->child = NULL; - mdp->sib = NULL; - mdp->parent = NULL; - mdp->name = xstrdup(name); - mdp->handle = -1; - mdp->SetupProc = NULL; - mdp->TearDownProc = NULL; - mdp->TearDownData = NULL; - } - - return (mdp); -} - -ModuleDescPtr -DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) -{ - ModuleDescPtr ret; - - if (!mod) - return NULL; - - ret = NewModuleDesc(mod->name); - if (ret == NULL) - return NULL; - - if (LoaderHandleOpen(mod->handle) == -1) - return NULL; - - ret->handle = mod->handle; - ret->SetupProc = mod->SetupProc; - ret->TearDownProc = mod->TearDownProc; - ret->TearDownData = NULL; - ret->child = DuplicateModule(mod->child, ret); - ret->sib = DuplicateModule(mod->sib, parent); - ret->parent = parent; - ret->VersionInfo = mod->VersionInfo; - - return ret; -} - -static const char *compiled_in_modules[] = { - "ddc", - "i2c", - "ramdac", - NULL -}; - -static ModuleDescPtr -doLoadModule(const char *module, const char *path, const char **subdirlist, - const char **patternlist, pointer options, - const XF86ModReqInfo * modreq, - int *errmaj, int *errmin, int flags) -{ - XF86ModuleData *initdata = NULL; - char **pathlist = NULL; - char *found = NULL; - char *name = NULL; - char **path_elem = NULL; - char *p = NULL; - ModuleDescPtr ret = NULL; - int wasLoaded = 0; - PatternPtr patterns = NULL; - int noncanonical = 0; - char *m = NULL; - const char **cim; - - xf86MsgVerb(X_INFO, 3, "LoadModule: \"%s\"", module); - - patterns = InitPatterns(patternlist); - name = LoaderGetCanonicalName(module, patterns); - noncanonical = (name && strcmp(module, name) != 0); - if (noncanonical) { - xf86ErrorFVerb(3, " (%s)\n", name); - xf86MsgVerb(X_WARNING, 1, - "LoadModule: given non-canonical module name \"%s\"\n", - module); - m = name; - } else { - xf86ErrorFVerb(3, "\n"); - m = (char *)module; - } - - for (cim = compiled_in_modules; *cim; cim++) - if (!strcmp (m, *cim)) - { - xf86MsgVerb(X_INFO, 3, "Module \"%s\" already built-in\n", m); - ret = (ModuleDescPtr) 1; - goto LoadModule_exit; - } - - if (!name) { - if (errmaj) - *errmaj = LDR_BADUSAGE; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - ret = NewModuleDesc(name); - if (!ret) { - if (errmaj) - *errmaj = LDR_NOMEM; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - - pathlist = InitPathList(path); - if (!pathlist) { - /* This could be a malloc failure too */ - if (errmaj) - *errmaj = LDR_BADUSAGE; - if (errmin) - *errmin = 1; - goto LoadModule_fail; - } - - /* - * if the module name is not a full pathname, we need to - * check the elements in the path - */ - if (PathIsAbsolute(module)) - found = xstrdup(module); - path_elem = pathlist; - while (!found && *path_elem != NULL) { - found = FindModule(m, *path_elem, subdirlist, patterns); - path_elem++; - /* - * When the module name isn't the canonical name, search for the - * former if no match was found for the latter. - */ - if (!*path_elem && m == name) { - path_elem = pathlist; - m = (char *)module; - } - } - - /* - * did we find the module? - */ - if (!found) { - xf86Msg(X_WARNING, "Warning, couldn't open module %s\n", module); - if (errmaj) - *errmaj = LDR_NOENT; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - ret->handle = LoaderOpen(found, name, 0, - errmaj, errmin, &wasLoaded, flags); - if (ret->handle < 0) - goto LoadModule_fail; - - /* drop any explicit suffix from the module name */ - p = strchr(name, '.'); - if (p) - *p = '\0'; - - /* - * now check if the special data object <modulename>ModuleData is - * present. - */ - p = xalloc(strlen(name) + strlen("ModuleData") + 1); - if (!p) { - if (errmaj) - *errmaj = LDR_NOMEM; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - strcpy(p, name); - strcat(p, "ModuleData"); - initdata = LoaderSymbol(p); - if (initdata) { - ModuleSetupProc setup; - ModuleTearDownProc teardown; - XF86ModuleVersionInfo *vers; - - vers = initdata->vers; - setup = initdata->setup; - teardown = initdata->teardown; - - if (!wasLoaded) { - if (vers) { - if (!CheckVersion(module, vers, modreq)) { - if (errmaj) - *errmaj = LDR_MISMATCH; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - } else { - xf86Msg(X_ERROR, - "LoadModule: Module %s does not supply" - " version information\n", module); - if (errmaj) - *errmaj = LDR_INVALID; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - } - if (setup) - ret->SetupProc = setup; - if (teardown) - ret->TearDownProc = teardown; - ret->VersionInfo = vers; - } else { - /* No initdata is OK for external modules */ - if (options == EXTERN_MODULE) - goto LoadModule_exit; - - /* no initdata, fail the load */ - xf86Msg(X_ERROR, "LoadModule: Module %s does not have a %s " - "data object.\n", module, p); - if (errmaj) - *errmaj = LDR_INVALID; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - if (ret->SetupProc) { - ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin); - if (!ret->TearDownData) { - goto LoadModule_fail; - } - } else if (options) { - xf86Msg(X_WARNING, "Module Options present, but no SetupProc " - "available for %s\n", module); - } - goto LoadModule_exit; - - LoadModule_fail: - UnloadModule(ret); - ret = NULL; - - LoadModule_exit: - FreePathList(pathlist); - FreePatterns(patterns); - xfree(found); - xfree(name); - xfree(p); - - return ret; -} - -/* - * LoadModule: load a module - * - * module The module name. Normally this is not a filename but the - * module's "canonical name. A full pathname is, however, - * also accepted. - * path A comma separated list of module directories. - * subdirlist A NULL terminated list of subdirectories to search. When - * NULL, the default "stdSubdirs" list is used. The default - * list is also substituted for entries with value DEFAULT_LIST. - * patternlist A NULL terminated list of regular expressions used to find - * module filenames. Each regex should contain exactly one - * subexpression that corresponds to the canonical module name. - * When NULL, the default "stdPatterns" list is used. The - * default list is also substituted for entries with value - * DEFAULT_LIST. - * options A NULL terminated list of Options that are passed to the - * module's SetupProc function. - * modreq An optional XF86ModReqInfo* containing - * version/ABI/vendor-ABI requirements to check for when - * loading the module. The following fields of the - * XF86ModReqInfo struct are checked: - * majorversion - must match the module's majorversion exactly - * minorversion - the module's minorversion must be >= this - * patchlevel - the module's minorversion.patchlevel must be - * >= this. Patchlevel is ignored when - * minorversion is not set. - * abiclass - (string) must match the module's abiclass - * abiversion - must be consistent with the module's - * abiversion (major equal, minor no older) - * moduleclass - string must match the module's moduleclass - * string - * "don't care" values are ~0 for numbers, and NULL for strings - * errmaj Major error return. - * errmin Minor error return. - * - */ -ModuleDescPtr -LoadModule(const char *module, const char *path, const char **subdirlist, - const char **patternlist, pointer options, - const XF86ModReqInfo * modreq, int *errmaj, int *errmin) -{ - return doLoadModule(module, path, subdirlist, patternlist, options, - modreq, errmaj, errmin, LD_FLAG_GLOBAL); -} - -void -UnloadModule(pointer mod) -{ - UnloadModuleOrDriver((ModuleDescPtr)mod); -} - -static void -UnloadModuleOrDriver(ModuleDescPtr mod) -{ - if (mod == (ModuleDescPtr) 1) - return; - - if (mod == NULL || mod->name == NULL) - return; - - xf86MsgVerb(X_INFO, 3, "UnloadModule: \"%s\"\n", mod->name); - - if ((mod->TearDownProc) && (mod->TearDownData)) - mod->TearDownProc(mod->TearDownData); - LoaderUnload(mod->handle); - - if (mod->child) - UnloadModuleOrDriver(mod->child); - if (mod->sib) - UnloadModuleOrDriver(mod->sib); - xfree(mod->name); - xfree(mod); -} - -void -UnloadSubModule(pointer _mod) -{ - ModuleDescPtr mod = (ModuleDescPtr)_mod; - - if (mod == NULL || mod->name == NULL) - return; - - xf86MsgVerb(X_INFO, 3, "UnloadSubModule: \"%s\"\n", mod->name); - - if ((mod->TearDownProc) && (mod->TearDownData)) - mod->TearDownProc(mod->TearDownData); - LoaderUnload(mod->handle); - - RemoveChild(mod); - - if (mod->child) - UnloadModuleOrDriver(mod->child); - - xfree(mod->name); - xfree(mod); -} - -static void -RemoveChild(ModuleDescPtr child) -{ - ModuleDescPtr mdp; - ModuleDescPtr prevsib; - ModuleDescPtr parent; - - if (!child->parent) - return; - - parent = child->parent; - if (parent->child == child) { - parent->child = child->sib; - return; - } - - prevsib = parent->child; - mdp = prevsib->sib; - while (mdp && mdp != child) { - prevsib = mdp; - mdp = mdp->sib; - } - if (mdp == child) - prevsib->sib = child->sib; - return; -} - -void -LoaderErrorMsg(const char *name, const char *modname, int errmaj, int errmin) -{ - const char *msg; - MessageType type = X_ERROR; - - switch (errmaj) { - case LDR_NOERROR: - msg = "no error"; - break; - case LDR_NOMEM: - msg = "out of memory"; - break; - case LDR_NOENT: - msg = "module does not exist"; - break; - case LDR_NOSUBENT: - msg = "a required submodule could not be loaded"; - break; - case LDR_NOSPACE: - msg = "too many modules"; - break; - case LDR_NOMODOPEN: - msg = "open failed"; - break; - case LDR_UNKTYPE: - msg = "unknown module type"; - break; - case LDR_NOLOAD: - msg = "loader failed"; - break; - case LDR_ONCEONLY: - msg = "already loaded"; - type = X_INFO; - break; - case LDR_NOPORTOPEN: - msg = "port open failed"; - break; - case LDR_NOHARDWARE: - msg = "no hardware found"; - break; - case LDR_MISMATCH: - msg = "module requirement mismatch"; - break; - case LDR_BADUSAGE: - msg = "invalid argument(s) to LoadModule()"; - break; - case LDR_INVALID: - msg = "invalid module"; - break; - case LDR_BADOS: - msg = "module doesn't support this OS"; - break; - case LDR_MODSPECIFIC: - msg = "module-specific error"; - break; - default: - msg = "unknown error"; - } - if (name) - xf86Msg(type, "%s: Failed to load module \"%s\" (%s, %d)\n", - name, modname, msg, errmin); - else - xf86Msg(type, "Failed to load module \"%s\" (%s, %d)\n", - modname, msg, errmin); -} - -/* Given a module path or file name, return the module's canonical name */ -static char * -LoaderGetCanonicalName(const char *modname, PatternPtr patterns) -{ - char *str; - const char *s; - int len; - PatternPtr p; - regmatch_t match[2]; - - /* Strip off any leading path */ - s = strrchr(modname, '/'); - if (s == NULL) - s = modname; - else - s++; - - /* Find the first regex that is matched */ - for (p = patterns; p->pattern; p++) - if (regexec(&p->rex, s, 2, match, 0) == 0 && match[1].rm_so != -1) { - len = match[1].rm_eo - match[1].rm_so; - str = xalloc(len + 1); - if (!str) - return NULL; - strncpy(str, s + match[1].rm_so, len); - str[len] = '\0'; - return str; - } - - /* If there is no match, return the whole name minus the leading path */ - return xstrdup(s); -} - -/* - * Return the module version information. - */ -unsigned long -LoaderGetModuleVersion(ModuleDescPtr mod) -{ - if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo) - return 0; - - return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion, - mod->VersionInfo->minorversion, - mod->VersionInfo->patchlevel); -} +/* + * Copyright 1995-1998 by Metro Link, Inc. + * + * 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 Metro Link, Inc. not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Metro Link, Inc. makes no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL METRO LINK, INC. 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. + */ +/* + * Copyright (c) 1997-2002 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "os.h" +/* For stat() and related stuff */ +#define NO_OSLIB_PROTOTYPES +#include "xf86_OSlib.h" +#define LOADERDECLARATIONS +#include "loaderProcs.h" +#include "misc.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86Xinput.h" +#include "loader.h" +#include "xf86Optrec.h" + +#include <sys/types.h> +#include <regex.h> +#include <dirent.h> +#include <limits.h> + +typedef struct _pattern { + const char *pattern; + regex_t rex; +} PatternRec, *PatternPtr; + +/* Prototypes for static functions */ +static char *FindModule(const char *, const char *, const char **, + PatternPtr); +static Bool CheckVersion(const char *, XF86ModuleVersionInfo *, + const XF86ModReqInfo *); +static void UnloadModuleOrDriver(ModuleDescPtr mod); +static char *LoaderGetCanonicalName(const char *, PatternPtr); +static void RemoveChild(ModuleDescPtr); +static ModuleDescPtr doLoadModule(const char *, const char *, const char **, + const char **, pointer, + const XF86ModReqInfo *, int *, int *, + int flags); + +const ModuleVersions LoaderVersionInfo = { + XORG_VERSION_CURRENT, + ABI_ANSIC_VERSION, + ABI_VIDEODRV_VERSION, + ABI_XINPUT_VERSION, + ABI_EXTENSION_VERSION, + ABI_FONT_VERSION +}; + +static void +FreeStringList(char **paths) +{ + char **p; + + if (!paths) + return; + + for (p = paths; *p; p++) + free(*p); + + free(paths); +} + +static char **defaultPathList = NULL; + +static Bool +PathIsAbsolute(const char *path) +{ + return (*path == '/'); +} + +/* + * Convert a comma-separated path into a NULL-terminated array of path + * elements, rejecting any that are not full absolute paths, and appending + * a '/' when it isn't already present. + */ +static char ** +InitPathList(const char *path) +{ + char *fullpath = NULL; + char *elem = NULL; + char **list = NULL, **save = NULL; + int len; + int addslash; + int n = 0; + + if (!path) + return defaultPathList; + + fullpath = xstrdup(path); + if (!fullpath) + return NULL; + elem = strtok(fullpath, ","); + while (elem) { + if (PathIsAbsolute(elem)) + { + len = strlen(elem); + addslash = (elem[len - 1] != '/'); + if (addslash) + len++; + save = list; + list = realloc(list, (n + 2) * sizeof(char *)); + if (!list) { + if (save) { + save[n] = NULL; + FreeStringList(save); + } + free(fullpath); + return NULL; + } + list[n] = malloc(len + 1); + if (!list[n]) { + FreeStringList(list); + free(fullpath); + return NULL; + } + strcpy(list[n], elem); + if (addslash) { + list[n][len - 1] = '/'; + list[n][len] = '\0'; + } + n++; + } + elem = strtok(NULL, ","); + } + if (list) + list[n] = NULL; + free(fullpath); + return list; +} + +static void +FreePathList(char **pathlist) +{ + if (pathlist && pathlist != defaultPathList) + FreeStringList(pathlist); +} + +void +LoaderSetPath(const char *path) +{ + if (!path) + return; + + defaultPathList = InitPathList(path); +} + +/* Standard set of module subdirectories to search, in order of preference */ +static const char *stdSubdirs[] = { + "", + "input/", + "drivers/", + "multimedia/", + "extensions/", + "internal/", + NULL +}; + +/* + * Standard set of module name patterns to check, in order of preference + * These are regular expressions (suitable for use with POSIX regex(3)). + * + * This list assumes that you're an ELFish platform and therefore your + * shared libraries are named something.so. If we're ever nuts enough + * to port this DDX to, say, Darwin, we'll need to fix this. + */ +static PatternRec stdPatterns[] = { + {"^lib(.*)\\.so$",}, + {"(.*)_drv\\.so$",}, + {"(.*)\\.so$",}, + {NULL,} +}; + +static PatternPtr +InitPatterns(const char **patternlist) +{ + char errmsg[80]; + int i, e; + PatternPtr patterns = NULL; + PatternPtr p = NULL; + static int firstTime = 1; + const char **s; + + if (firstTime) { + /* precompile stdPatterns */ + firstTime = 0; + for (p = stdPatterns; p->pattern; p++) + if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { + regerror(e, &p->rex, errmsg, sizeof(errmsg)); + FatalError("InitPatterns: regcomp error for `%s': %s\n", + p->pattern, errmsg); + } + } + + if (patternlist) { + for (i = 0, s = patternlist; *s; i++, s++) + if (*s == DEFAULT_LIST) + i += sizeof(stdPatterns) / sizeof(stdPatterns[0]) - 1 - 1; + patterns = malloc((i + 1) * sizeof(PatternRec)); + if (!patterns) { + return NULL; + } + for (i = 0, s = patternlist; *s; i++, s++) + if (*s != DEFAULT_LIST) { + p = patterns + i; + p->pattern = *s; + if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { + regerror(e, &p->rex, errmsg, sizeof(errmsg)); + ErrorF("InitPatterns: regcomp error for `%s': %s\n", + p->pattern, errmsg); + i--; + } + } else { + for (p = stdPatterns; p->pattern; p++, i++) + patterns[i] = *p; + if (p != stdPatterns) + i--; + } + patterns[i].pattern = NULL; + } else + patterns = stdPatterns; + return patterns; +} + +static void +FreePatterns(PatternPtr patterns) +{ + if (patterns && patterns != stdPatterns) + free(patterns); +} + +static const char ** +InitSubdirs(const char **subdirlist) +{ + int i; + const char **tmp_subdirlist = NULL; + char **subdirs = NULL; + const char **s, **stmp = NULL; + const char *osname; + const char *slash; + int oslen = 0, len; + Bool indefault; + + if (subdirlist == NULL) { + subdirlist = tmp_subdirlist = malloc(2 * sizeof(char *)); + if (subdirlist == NULL) + return NULL; + subdirlist[0] = DEFAULT_LIST; + subdirlist[1] = NULL; + } + + LoaderGetOS(&osname, NULL, NULL, NULL); + oslen = strlen(osname); + + { + /* Count number of entries and check for invalid paths */ + for (i = 0, s = subdirlist; *s; i++, s++) { + if (*s == DEFAULT_LIST) { + i += sizeof(stdSubdirs) / sizeof(stdSubdirs[0]) - 1 - 1; + } else { + /* + * Path validity check. Don't allow absolute paths, or + * paths containing "..". To catch absolute paths on + * platforms that use driver letters, don't allow the ':' + * character to appear at all. + */ + if (**s == '/' || **s == '\\' || strchr(*s, ':') || + strstr(*s, "..")) { + xf86Msg(X_ERROR, "InitSubdirs: Bad subdir: \"%s\"\n", *s); + if (tmp_subdirlist) + free(tmp_subdirlist); + return NULL; + } + } + } + subdirs = malloc((i * 2 + 1) * sizeof(char *)); + if (!subdirs) { + if (tmp_subdirlist) + free(tmp_subdirlist); + return NULL; + } + i = 0; + s = subdirlist; + indefault = FALSE; + while (*s) { + if (*s == DEFAULT_LIST) { + /* Divert to the default list */ + indefault = TRUE; + stmp = ++s; + s = stdSubdirs; + } + len = strlen(*s); + if (**s && (*s)[len - 1] != '/') { + slash = "/"; + len++; + } else + slash = ""; + len += oslen + 2; + if (!(subdirs[i] = malloc(len))) { + while (--i >= 0) + free(subdirs[i]); + free(subdirs); + if (tmp_subdirlist) + free(tmp_subdirlist); + return NULL; + } + /* tack on the OS name */ + sprintf(subdirs[i], "%s%s%s/", *s, slash, osname); + i++; + /* path as given */ + subdirs[i] = xstrdup(*s); + i++; + s++; + if (indefault && !s) { + /* revert back to the main list */ + indefault = FALSE; + s = stmp; + } + } + subdirs[i] = NULL; + } + if (tmp_subdirlist) + free(tmp_subdirlist); + return (const char **)subdirs; +} + +static void +FreeSubdirs(const char **subdirs) +{ + const char **s; + + if (subdirs) { + for (s = subdirs; *s; s++) + free(*s); + free(subdirs); + } +} + +static char * +FindModuleInSubdir(const char *dirpath, const char *module) +{ + struct dirent *direntry = NULL; + DIR *dir = NULL; + char *ret = NULL, tmpBuf[PATH_MAX]; + struct stat stat_buf; + + dir = opendir(dirpath); + if (!dir) + return NULL; + + while ((direntry = readdir(dir))) { + if (direntry->d_name[0] == '.') + continue; + snprintf(tmpBuf, PATH_MAX, "%s%s/", dirpath, direntry->d_name); + /* the stat with the appended / fails for normal files, + and works for sub dirs fine, looks a bit strange in strace + but does seem to work */ + if ((stat(tmpBuf, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) { + if ((ret = FindModuleInSubdir(tmpBuf, module))) + break; + continue; + } + + snprintf(tmpBuf, PATH_MAX, "lib%s.so", module); + if (strcmp(direntry->d_name, tmpBuf) == 0) { + ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); + sprintf(ret, "%s%s", dirpath, tmpBuf); + break; + } + + snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module); + if (strcmp(direntry->d_name, tmpBuf) == 0) { + ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); + sprintf(ret, "%s%s", dirpath, tmpBuf); + break; + } + + snprintf(tmpBuf, PATH_MAX, "%s.so", module); + if (strcmp(direntry->d_name, tmpBuf) == 0) { + ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); + sprintf(ret, "%s%s", dirpath, tmpBuf); + break; + } + } + + closedir(dir); + return ret; +} + +static char * +FindModule(const char *module, const char *dirname, const char **subdirlist, + PatternPtr patterns) +{ + char buf[PATH_MAX + 1]; + char *dirpath = NULL; + char *name = NULL; + int dirlen; + const char **subdirs = NULL; + const char **s; + + dirpath = (char *)dirname; + if (strlen(dirpath) > PATH_MAX) + return NULL; + + subdirs = InitSubdirs(subdirlist); + if (!subdirs) + return NULL; + + for (s = subdirs; *s; s++) { + if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX) + continue; + strcpy(buf, dirpath); + strcat(buf, *s); + if ((name = FindModuleInSubdir(buf, module))) + break; + } + + FreeSubdirs(subdirs); + if (dirpath != dirname) + free(dirpath); + + return name; +} + +char ** +LoaderListDirs(const char **subdirlist, const char **patternlist) +{ + char buf[PATH_MAX + 1]; + char **pathlist; + char **elem; + const char **subdirs; + const char **s; + PatternPtr patterns; + PatternPtr p; + DIR *d; + struct dirent *dp; + regmatch_t match[2]; + struct stat stat_buf; + int len, dirlen; + char *fp; + char **listing = NULL; + char **save; + int n = 0; + + if (!(pathlist = InitPathList(NULL))) + return NULL; + if (!(subdirs = InitSubdirs(subdirlist))) { + FreePathList(pathlist); + return NULL; + } + if (!(patterns = InitPatterns(patternlist))) { + FreePathList(pathlist); + FreeSubdirs(subdirs); + return NULL; + } + + for (elem = pathlist; *elem; elem++) { + for (s = subdirs; *s; s++) { + if ((dirlen = strlen(*elem) + strlen(*s)) > PATH_MAX) + continue; + strcpy(buf, *elem); + strcat(buf, *s); + fp = buf + dirlen; + if (stat(buf, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode) && + (d = opendir(buf))) { + if (buf[dirlen - 1] != '/') { + buf[dirlen++] = '/'; + fp++; + } + while ((dp = readdir(d))) { + if (dirlen + strlen(dp->d_name) > PATH_MAX) + continue; + strcpy(fp, dp->d_name); + if (!(stat(buf, &stat_buf) == 0 && + S_ISREG(stat_buf.st_mode))) + continue; + for (p = patterns; p->pattern; p++) { + if (regexec(&p->rex, dp->d_name, 2, match, 0) == 0 && + match[1].rm_so != -1) { + len = match[1].rm_eo - match[1].rm_so; + save = listing; + listing = realloc(listing, + (n + 2) * sizeof(char *)); + if (!listing) { + if (save) { + save[n] = NULL; + FreeStringList(save); + } + FreePathList(pathlist); + FreeSubdirs(subdirs); + FreePatterns(patterns); + return NULL; + } + listing[n] = malloc(len + 1); + if (!listing[n]) { + FreeStringList(listing); + FreePathList(pathlist); + FreeSubdirs(subdirs); + FreePatterns(patterns); + return NULL; + } + strncpy(listing[n], dp->d_name + match[1].rm_so, + len); + listing[n][len] = '\0'; + n++; + break; + } + } + } + closedir(d); + } + } + } + if (listing) + listing[n] = NULL; + return listing; +} + +void +LoaderFreeDirList(char **list) +{ + FreeStringList(list); +} + +static Bool +CheckVersion(const char *module, XF86ModuleVersionInfo * data, + const XF86ModReqInfo * req) +{ + int vercode[4]; + char verstr[4]; + long ver = data->xf86version; + MessageType errtype; + + xf86Msg(X_INFO, "Module %s: vendor=\"%s\"\n", + data->modname ? data->modname : "UNKNOWN!", + data->vendor ? data->vendor : "UNKNOWN!"); + + /* Check for the different scheme used in XFree86 4.0.x releases: + * ((((((((major << 7) | minor) << 7) | subminor) << 5) | beta) << 5) | alpha) + * Since it wasn't used in 4.1.0 or later, limit to versions in the 4.0.x + * range, which limits the overlap with the new version scheme to conflicts + * with 6.71.8.764 through 6.72.39.934. + */ + if ((ver > (4 << 24)) && (ver < ( (4 << 24) + (1 << 17)))) { + /* 4.0.x and earlier */ + verstr[1] = verstr[3] = 0; + verstr[2] = (ver & 0x1f) ? (ver & 0x1f) + 'a' - 1 : 0; + ver >>= 5; + verstr[0] = (ver & 0x1f) ? (ver & 0x1f) + 'A' - 1 : 0; + ver >>= 5; + vercode[2] = ver & 0x7f; + ver >>= 7; + vercode[1] = ver & 0x7f; + ver >>= 7; + vercode[0] = ver; + xf86ErrorF("\tcompiled for %d.%d", vercode[0], vercode[1]); + if (vercode[2] != 0) + xf86ErrorF(".%d", vercode[2]); + xf86ErrorF("%s%s, module version = %d.%d.%d\n", verstr, verstr + 2, + data->majorversion, data->minorversion, data->patchlevel); + } else { + vercode[0] = ver / 10000000; + vercode[1] = (ver / 100000) % 100; + vercode[2] = (ver / 1000) % 100; + vercode[3] = ver % 1000; + xf86ErrorF("\tcompiled for %d.%d.%d", vercode[0], vercode[1], + vercode[2]); + if (vercode[3] != 0) + xf86ErrorF(".%d", vercode[3]); + xf86ErrorF(", module version = %d.%d.%d\n", data->majorversion, + data->minorversion, data->patchlevel); + } + + if (data->moduleclass) + xf86ErrorFVerb(2, "\tModule class: %s\n", data->moduleclass); + + ver = -1; + if (data->abiclass) { + int abimaj, abimin; + int vermaj, vermin; + + if (!strcmp(data->abiclass, ABI_CLASS_ANSIC)) + ver = LoaderVersionInfo.ansicVersion; + else if (!strcmp(data->abiclass, ABI_CLASS_VIDEODRV)) + ver = LoaderVersionInfo.videodrvVersion; + else if (!strcmp(data->abiclass, ABI_CLASS_XINPUT)) + ver = LoaderVersionInfo.xinputVersion; + else if (!strcmp(data->abiclass, ABI_CLASS_EXTENSION)) + ver = LoaderVersionInfo.extensionVersion; + else if (!strcmp(data->abiclass, ABI_CLASS_FONT)) + ver = LoaderVersionInfo.fontVersion; + + abimaj = GET_ABI_MAJOR(data->abiversion); + abimin = GET_ABI_MINOR(data->abiversion); + xf86ErrorFVerb(2, "\tABI class: %s, version %d.%d\n", + data->abiclass, abimaj, abimin); + if (ver != -1) { + vermaj = GET_ABI_MAJOR(ver); + vermin = GET_ABI_MINOR(ver); + if (abimaj != vermaj) { + if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) + errtype = X_WARNING; + else + errtype = X_ERROR; + xf86MsgVerb(errtype, 0, + "module ABI major version (%d) doesn't" + " match the server's version (%d)\n", + abimaj, vermaj); + if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) + return FALSE; + } else if (abimin > vermin) { + if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) + errtype = X_WARNING; + else + errtype = X_ERROR; + xf86MsgVerb(errtype, 0, + "module ABI minor version (%d) is " + "newer than the server's version " + "(%d)\n", abimin, vermin); + if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) + return FALSE; + } + } + } + + /* Check against requirements that the caller has specified */ + if (req) { + if (req->majorversion != MAJOR_UNSPEC) { + if (data->majorversion != req->majorversion) { + xf86MsgVerb(X_WARNING, 2, "module major version (%d) " + "doesn't match required major version (%d)\n", + data->majorversion, req->majorversion); + return FALSE; + } else if (req->minorversion != MINOR_UNSPEC) { + if (data->minorversion < req->minorversion) { + xf86MsgVerb(X_WARNING, 2, "module minor version (%d) " + "is less than the required minor version (%d)\n", + data->minorversion, req->minorversion); + return FALSE; + } else if (data->minorversion == req->minorversion && + req->patchlevel != PATCH_UNSPEC) { + if (data->patchlevel < req->patchlevel) { + xf86MsgVerb(X_WARNING, 2, "module patch level (%d) " + "is less than the required patch level (%d)\n", + data->patchlevel, req->patchlevel); + return FALSE; + } + } + } + } + if (req->moduleclass) { + if (!data->moduleclass || + strcmp(req->moduleclass, data->moduleclass)) { + xf86MsgVerb(X_WARNING, 2, "Module class (%s) doesn't match " + "the required class (%s)\n", + data->moduleclass ? data->moduleclass : "<NONE>", + req->moduleclass); + return FALSE; + } + } else if (req->abiclass != ABI_CLASS_NONE) { + if (!data->abiclass || strcmp(req->abiclass, data->abiclass)) { + xf86MsgVerb(X_WARNING, 2, "ABI class (%s) doesn't match the " + "required ABI class (%s)\n", + data->abiclass ? data->abiclass : "<NONE>", + req->abiclass); + return FALSE; + } + } + if ((req->abiclass != ABI_CLASS_NONE) && + req->abiversion != ABI_VERS_UNSPEC) { + int reqmaj, reqmin, maj, min; + + reqmaj = GET_ABI_MAJOR(req->abiversion); + reqmin = GET_ABI_MINOR(req->abiversion); + maj = GET_ABI_MAJOR(data->abiversion); + min = GET_ABI_MINOR(data->abiversion); + if (maj != reqmaj) { + xf86MsgVerb(X_WARNING, 2, "ABI major version (%d) doesn't " + "match the required ABI major version (%d)\n", + maj, reqmaj); + return FALSE; + } + /* XXX Maybe this should be the other way around? */ + if (min > reqmin) { + xf86MsgVerb(X_WARNING, 2, "module ABI minor version (%d) " + "is newer than that available (%d)\n", min, reqmin); + return FALSE; + } + } + } + return TRUE; +} + +static ModuleDescPtr +AddSibling(ModuleDescPtr head, ModuleDescPtr new) +{ + new->sib = head; + return (new); +} + +pointer +LoadSubModule(pointer _parent, const char *module, + const char **subdirlist, const char **patternlist, + pointer options, const XF86ModReqInfo * modreq, + int *errmaj, int *errmin) +{ + ModuleDescPtr submod; + ModuleDescPtr parent = (ModuleDescPtr)_parent; + + xf86MsgVerb(X_INFO, 3, "Loading sub module \"%s\"\n", module); + + if (PathIsAbsolute(module)) { + xf86Msg(X_ERROR, + "LoadSubModule: Absolute module path not permitted: \"%s\"\n", + module); + if (errmaj) + *errmaj = LDR_BADUSAGE; + if (errmin) + *errmin = 0; + return NULL; + } + + submod = doLoadModule(module, NULL, subdirlist, patternlist, options, + modreq, errmaj, errmin, LD_FLAG_GLOBAL); + if (submod && submod != (ModuleDescPtr) 1) { + parent->child = AddSibling(parent->child, submod); + submod->parent = parent; + } + return submod; +} + +static ModuleDescPtr +NewModuleDesc(const char *name) +{ + ModuleDescPtr mdp = malloc(sizeof(ModuleDesc)); + + if (mdp) { + mdp->child = NULL; + mdp->sib = NULL; + mdp->parent = NULL; + mdp->name = xstrdup(name); + mdp->handle = -1; + mdp->SetupProc = NULL; + mdp->TearDownProc = NULL; + mdp->TearDownData = NULL; + } + + return (mdp); +} + +ModuleDescPtr +DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) +{ + ModuleDescPtr ret; + + if (!mod) + return NULL; + + ret = NewModuleDesc(mod->name); + if (ret == NULL) + return NULL; + + if (LoaderHandleOpen(mod->handle) == -1) + return NULL; + + ret->handle = mod->handle; + ret->SetupProc = mod->SetupProc; + ret->TearDownProc = mod->TearDownProc; + ret->TearDownData = NULL; + ret->child = DuplicateModule(mod->child, ret); + ret->sib = DuplicateModule(mod->sib, parent); + ret->parent = parent; + ret->VersionInfo = mod->VersionInfo; + + return ret; +} + +static const char *compiled_in_modules[] = { + "ddc", + "i2c", + "ramdac", + NULL +}; + +static ModuleDescPtr +doLoadModule(const char *module, const char *path, const char **subdirlist, + const char **patternlist, pointer options, + const XF86ModReqInfo * modreq, + int *errmaj, int *errmin, int flags) +{ + XF86ModuleData *initdata = NULL; + char **pathlist = NULL; + char *found = NULL; + char *name = NULL; + char **path_elem = NULL; + char *p = NULL; + ModuleDescPtr ret = NULL; + int wasLoaded = 0; + PatternPtr patterns = NULL; + int noncanonical = 0; + char *m = NULL; + const char **cim; + + xf86MsgVerb(X_INFO, 3, "LoadModule: \"%s\"", module); + + patterns = InitPatterns(patternlist); + name = LoaderGetCanonicalName(module, patterns); + noncanonical = (name && strcmp(module, name) != 0); + if (noncanonical) { + xf86ErrorFVerb(3, " (%s)\n", name); + xf86MsgVerb(X_WARNING, 1, + "LoadModule: given non-canonical module name \"%s\"\n", + module); + m = name; + } else { + xf86ErrorFVerb(3, "\n"); + m = (char *)module; + } + + for (cim = compiled_in_modules; *cim; cim++) + if (!strcmp (m, *cim)) + { + xf86MsgVerb(X_INFO, 3, "Module \"%s\" already built-in\n", m); + ret = (ModuleDescPtr) 1; + goto LoadModule_exit; + } + + if (!name) { + if (errmaj) + *errmaj = LDR_BADUSAGE; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + ret = NewModuleDesc(name); + if (!ret) { + if (errmaj) + *errmaj = LDR_NOMEM; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + + pathlist = InitPathList(path); + if (!pathlist) { + /* This could be a malloc failure too */ + if (errmaj) + *errmaj = LDR_BADUSAGE; + if (errmin) + *errmin = 1; + goto LoadModule_fail; + } + + /* + * if the module name is not a full pathname, we need to + * check the elements in the path + */ + if (PathIsAbsolute(module)) + found = xstrdup(module); + path_elem = pathlist; + while (!found && *path_elem != NULL) { + found = FindModule(m, *path_elem, subdirlist, patterns); + path_elem++; + /* + * When the module name isn't the canonical name, search for the + * former if no match was found for the latter. + */ + if (!*path_elem && m == name) { + path_elem = pathlist; + m = (char *)module; + } + } + + /* + * did we find the module? + */ + if (!found) { + xf86Msg(X_WARNING, "Warning, couldn't open module %s\n", module); + if (errmaj) + *errmaj = LDR_NOENT; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + ret->handle = LoaderOpen(found, name, 0, + errmaj, errmin, &wasLoaded, flags); + if (ret->handle < 0) + goto LoadModule_fail; + + /* drop any explicit suffix from the module name */ + p = strchr(name, '.'); + if (p) + *p = '\0'; + + /* + * now check if the special data object <modulename>ModuleData is + * present. + */ + p = malloc(strlen(name) + strlen("ModuleData") + 1); + if (!p) { + if (errmaj) + *errmaj = LDR_NOMEM; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + strcpy(p, name); + strcat(p, "ModuleData"); + initdata = LoaderSymbol(p); + if (initdata) { + ModuleSetupProc setup; + ModuleTearDownProc teardown; + XF86ModuleVersionInfo *vers; + + vers = initdata->vers; + setup = initdata->setup; + teardown = initdata->teardown; + + if (!wasLoaded) { + if (vers) { + if (!CheckVersion(module, vers, modreq)) { + if (errmaj) + *errmaj = LDR_MISMATCH; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + } else { + xf86Msg(X_ERROR, + "LoadModule: Module %s does not supply" + " version information\n", module); + if (errmaj) + *errmaj = LDR_INVALID; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + } + if (setup) + ret->SetupProc = setup; + if (teardown) + ret->TearDownProc = teardown; + ret->VersionInfo = vers; + } else { + /* No initdata is OK for external modules */ + if (options == EXTERN_MODULE) + goto LoadModule_exit; + + /* no initdata, fail the load */ + xf86Msg(X_ERROR, "LoadModule: Module %s does not have a %s " + "data object.\n", module, p); + if (errmaj) + *errmaj = LDR_INVALID; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + if (ret->SetupProc) { + ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin); + if (!ret->TearDownData) { + goto LoadModule_fail; + } + } else if (options) { + xf86Msg(X_WARNING, "Module Options present, but no SetupProc " + "available for %s\n", module); + } + goto LoadModule_exit; + + LoadModule_fail: + UnloadModule(ret); + ret = NULL; + + LoadModule_exit: + FreePathList(pathlist); + FreePatterns(patterns); + free(found); + free(name); + free(p); + + return ret; +} + +/* + * LoadModule: load a module + * + * module The module name. Normally this is not a filename but the + * module's "canonical name. A full pathname is, however, + * also accepted. + * path A comma separated list of module directories. + * subdirlist A NULL terminated list of subdirectories to search. When + * NULL, the default "stdSubdirs" list is used. The default + * list is also substituted for entries with value DEFAULT_LIST. + * patternlist A NULL terminated list of regular expressions used to find + * module filenames. Each regex should contain exactly one + * subexpression that corresponds to the canonical module name. + * When NULL, the default "stdPatterns" list is used. The + * default list is also substituted for entries with value + * DEFAULT_LIST. + * options A NULL terminated list of Options that are passed to the + * module's SetupProc function. + * modreq An optional XF86ModReqInfo* containing + * version/ABI/vendor-ABI requirements to check for when + * loading the module. The following fields of the + * XF86ModReqInfo struct are checked: + * majorversion - must match the module's majorversion exactly + * minorversion - the module's minorversion must be >= this + * patchlevel - the module's minorversion.patchlevel must be + * >= this. Patchlevel is ignored when + * minorversion is not set. + * abiclass - (string) must match the module's abiclass + * abiversion - must be consistent with the module's + * abiversion (major equal, minor no older) + * moduleclass - string must match the module's moduleclass + * string + * "don't care" values are ~0 for numbers, and NULL for strings + * errmaj Major error return. + * errmin Minor error return. + * + */ +ModuleDescPtr +LoadModule(const char *module, const char *path, const char **subdirlist, + const char **patternlist, pointer options, + const XF86ModReqInfo * modreq, int *errmaj, int *errmin) +{ + return doLoadModule(module, path, subdirlist, patternlist, options, + modreq, errmaj, errmin, LD_FLAG_GLOBAL); +} + +void +UnloadModule(pointer mod) +{ + UnloadModuleOrDriver((ModuleDescPtr)mod); +} + +static void +UnloadModuleOrDriver(ModuleDescPtr mod) +{ + if (mod == (ModuleDescPtr) 1) + return; + + if (mod == NULL || mod->name == NULL) + return; + + xf86MsgVerb(X_INFO, 3, "UnloadModule: \"%s\"\n", mod->name); + + if ((mod->TearDownProc) && (mod->TearDownData)) + mod->TearDownProc(mod->TearDownData); + LoaderUnload(mod->handle); + + if (mod->child) + UnloadModuleOrDriver(mod->child); + if (mod->sib) + UnloadModuleOrDriver(mod->sib); + free(mod->name); + free(mod); +} + +void +UnloadSubModule(pointer _mod) +{ + ModuleDescPtr mod = (ModuleDescPtr)_mod; + + if (mod == NULL || mod->name == NULL) + return; + + xf86MsgVerb(X_INFO, 3, "UnloadSubModule: \"%s\"\n", mod->name); + + if ((mod->TearDownProc) && (mod->TearDownData)) + mod->TearDownProc(mod->TearDownData); + LoaderUnload(mod->handle); + + RemoveChild(mod); + + if (mod->child) + UnloadModuleOrDriver(mod->child); + + free(mod->name); + free(mod); +} + +static void +RemoveChild(ModuleDescPtr child) +{ + ModuleDescPtr mdp; + ModuleDescPtr prevsib; + ModuleDescPtr parent; + + if (!child->parent) + return; + + parent = child->parent; + if (parent->child == child) { + parent->child = child->sib; + return; + } + + prevsib = parent->child; + mdp = prevsib->sib; + while (mdp && mdp != child) { + prevsib = mdp; + mdp = mdp->sib; + } + if (mdp == child) + prevsib->sib = child->sib; + return; +} + +void +LoaderErrorMsg(const char *name, const char *modname, int errmaj, int errmin) +{ + const char *msg; + MessageType type = X_ERROR; + + switch (errmaj) { + case LDR_NOERROR: + msg = "no error"; + break; + case LDR_NOMEM: + msg = "out of memory"; + break; + case LDR_NOENT: + msg = "module does not exist"; + break; + case LDR_NOSUBENT: + msg = "a required submodule could not be loaded"; + break; + case LDR_NOSPACE: + msg = "too many modules"; + break; + case LDR_NOMODOPEN: + msg = "open failed"; + break; + case LDR_UNKTYPE: + msg = "unknown module type"; + break; + case LDR_NOLOAD: + msg = "loader failed"; + break; + case LDR_ONCEONLY: + msg = "already loaded"; + type = X_INFO; + break; + case LDR_NOPORTOPEN: + msg = "port open failed"; + break; + case LDR_NOHARDWARE: + msg = "no hardware found"; + break; + case LDR_MISMATCH: + msg = "module requirement mismatch"; + break; + case LDR_BADUSAGE: + msg = "invalid argument(s) to LoadModule()"; + break; + case LDR_INVALID: + msg = "invalid module"; + break; + case LDR_BADOS: + msg = "module doesn't support this OS"; + break; + case LDR_MODSPECIFIC: + msg = "module-specific error"; + break; + default: + msg = "unknown error"; + } + if (name) + xf86Msg(type, "%s: Failed to load module \"%s\" (%s, %d)\n", + name, modname, msg, errmin); + else + xf86Msg(type, "Failed to load module \"%s\" (%s, %d)\n", + modname, msg, errmin); +} + +/* Given a module path or file name, return the module's canonical name */ +static char * +LoaderGetCanonicalName(const char *modname, PatternPtr patterns) +{ + char *str; + const char *s; + int len; + PatternPtr p; + regmatch_t match[2]; + + /* Strip off any leading path */ + s = strrchr(modname, '/'); + if (s == NULL) + s = modname; + else + s++; + + /* Find the first regex that is matched */ + for (p = patterns; p->pattern; p++) + if (regexec(&p->rex, s, 2, match, 0) == 0 && match[1].rm_so != -1) { + len = match[1].rm_eo - match[1].rm_so; + str = malloc(len + 1); + if (!str) + return NULL; + strncpy(str, s + match[1].rm_so, len); + str[len] = '\0'; + return str; + } + + /* If there is no match, return the whole name minus the leading path */ + return xstrdup(s); +} + +/* + * Return the module version information. + */ +unsigned long +LoaderGetModuleVersion(ModuleDescPtr mod) +{ + if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo) + return 0; + + return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion, + mod->VersionInfo->minorversion, + mod->VersionInfo->patchlevel); +} diff --git a/xorg-server/hw/xfree86/modes/xf86Crtc.c b/xorg-server/hw/xfree86/modes/xf86Crtc.c index 1ccaffc10..9dbeea8a5 100644 --- a/xorg-server/hw/xfree86/modes/xf86Crtc.c +++ b/xorg-server/hw/xfree86/modes/xf86Crtc.c @@ -1,3201 +1,3201 @@ -/* - * Copyright © 2006 Keith Packard - * Copyright © 2008 Red Hat, Inc. - * - * 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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_XORG_CONFIG_H -#include <xorg-config.h> -#else -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#endif - -#include <stddef.h> -#include <string.h> -#include <stdio.h> - -#include "xf86.h" -#include "xf86DDC.h" -#include "xf86Crtc.h" -#include "xf86Modes.h" -#include "xf86Priv.h" -#include "xf86RandR12.h" -#include "X11/extensions/render.h" -#include "X11/extensions/dpmsconst.h" -#include "X11/Xatom.h" -#include "picturestr.h" - -#include "xf86xv.h" - -/* - * Initialize xf86CrtcConfig structure - */ - -int xf86CrtcConfigPrivateIndex = -1; - -void -xf86CrtcConfigInit (ScrnInfoPtr scrn, - const xf86CrtcConfigFuncsRec *funcs) -{ - xf86CrtcConfigPtr config; - - if (xf86CrtcConfigPrivateIndex == -1) - xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); - config = xnfcalloc (1, sizeof (xf86CrtcConfigRec)); - - config->funcs = funcs; - - scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config; -} - -void -xf86CrtcSetSizeRange (ScrnInfoPtr scrn, - int minWidth, int minHeight, - int maxWidth, int maxHeight) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - - config->minWidth = minWidth; - config->minHeight = minHeight; - config->maxWidth = maxWidth; - config->maxHeight = maxHeight; -} - -/* - * Crtc functions - */ -xf86CrtcPtr -xf86CrtcCreate (ScrnInfoPtr scrn, - const xf86CrtcFuncsRec *funcs) -{ - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - xf86CrtcPtr crtc, *crtcs; - - crtc = xcalloc (sizeof (xf86CrtcRec), 1); - if (!crtc) - return NULL; - crtc->version = XF86_CRTC_VERSION; - crtc->scrn = scrn; - crtc->funcs = funcs; -#ifdef RANDR_12_INTERFACE - crtc->randr_crtc = NULL; -#endif - crtc->rotation = RR_Rotate_0; - crtc->desiredRotation = RR_Rotate_0; - pixman_transform_init_identity (&crtc->crtc_to_framebuffer); - pixman_f_transform_init_identity (&crtc->f_crtc_to_framebuffer); - pixman_f_transform_init_identity (&crtc->f_framebuffer_to_crtc); - crtc->filter = NULL; - crtc->params = NULL; - crtc->nparams = 0; - crtc->filter_width = 0; - crtc->filter_height = 0; - crtc->transform_in_use = FALSE; - crtc->transformPresent = FALSE; - crtc->desiredTransformPresent = FALSE; - memset (&crtc->bounds, '\0', sizeof (crtc->bounds)); - - /* Preallocate gamma at a sensible size. */ - crtc->gamma_size = 256; - crtc->gamma_red = malloc(3 * crtc->gamma_size * sizeof (CARD16)); - if (!crtc->gamma_red) { - xfree (crtc); - return NULL; - } - crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; - crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; - - if (xf86_config->crtc) - crtcs = xrealloc (xf86_config->crtc, - (xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); - else - crtcs = xalloc ((xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); - if (!crtcs) - { - xfree (crtc); - return NULL; - } - xf86_config->crtc = crtcs; - xf86_config->crtc[xf86_config->num_crtc++] = crtc; - return crtc; -} - -void -xf86CrtcDestroy (xf86CrtcPtr crtc) -{ - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); - int c; - - (*crtc->funcs->destroy) (crtc); - for (c = 0; c < xf86_config->num_crtc; c++) - if (xf86_config->crtc[c] == crtc) - { - memmove (&xf86_config->crtc[c], - &xf86_config->crtc[c+1], - ((xf86_config->num_crtc - (c + 1)) * sizeof(void*))); - xf86_config->num_crtc--; - break; - } - if (crtc->params) - xfree (crtc->params); - free(crtc->gamma_red); - xfree (crtc); -} - - -/** - * Return whether any outputs are connected to the specified pipe - */ - -Bool -xf86CrtcInUse (xf86CrtcPtr crtc) -{ - ScrnInfoPtr pScrn = crtc->scrn; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int o; - - for (o = 0; o < xf86_config->num_output; o++) - if (xf86_config->output[o]->crtc == crtc) - return TRUE; - return FALSE; -} - -void -xf86CrtcSetScreenSubpixelOrder (ScreenPtr pScreen) -{ - int subpixel_order = SubPixelUnknown; - Bool has_none = FALSE; - ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - int c, o; - - for (c = 0; c < xf86_config->num_crtc; c++) - { - xf86CrtcPtr crtc = xf86_config->crtc[c]; - - for (o = 0; o < xf86_config->num_output; o++) - { - xf86OutputPtr output = xf86_config->output[o]; - - if (output->crtc == crtc) - { - switch (output->subpixel_order) { - case SubPixelNone: - has_none = TRUE; - break; - case SubPixelUnknown: - break; - default: - subpixel_order = output->subpixel_order; - break; - } - } - if (subpixel_order != SubPixelUnknown) - break; - } - if (subpixel_order != SubPixelUnknown) - { - static const int circle[4] = { - SubPixelHorizontalRGB, - SubPixelVerticalRGB, - SubPixelHorizontalBGR, - SubPixelVerticalBGR, - }; - int rotate; - int c; - for (rotate = 0; rotate < 4; rotate++) - if (crtc->rotation & (1 << rotate)) - break; - for (c = 0; c < 4; c++) - if (circle[c] == subpixel_order) - break; - c = (c + rotate) & 0x3; - if ((crtc->rotation & RR_Reflect_X) && !(c & 1)) - c ^= 2; - if ((crtc->rotation & RR_Reflect_Y) && (c & 1)) - c ^= 2; - subpixel_order = circle[c]; - break; - } - } - if (subpixel_order == SubPixelUnknown && has_none) - subpixel_order = SubPixelNone; - PictureSetSubpixelOrder (pScreen, subpixel_order); -} - -/** - * Sets the given video mode on the given crtc - */ -Bool -xf86CrtcSetModeTransform (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, - RRTransformPtr transform, int x, int y) -{ - ScrnInfoPtr scrn = crtc->scrn; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - int i; - Bool ret = FALSE; - Bool didLock = FALSE; - DisplayModePtr adjusted_mode; - DisplayModeRec saved_mode; - int saved_x, saved_y; - Rotation saved_rotation; - RRTransformRec saved_transform; - Bool saved_transform_present; - - crtc->enabled = xf86CrtcInUse (crtc); - - /* We only hit this if someone explicitly sends a "disabled" modeset. */ - if (!crtc->enabled) - { - /* Check everything for stuff that should be off. */ - xf86DisableUnusedFunctions(scrn); - return TRUE; - } - - adjusted_mode = xf86DuplicateMode(mode); - - - saved_mode = crtc->mode; - saved_x = crtc->x; - saved_y = crtc->y; - saved_rotation = crtc->rotation; - if (crtc->transformPresent) { - RRTransformInit (&saved_transform); - RRTransformCopy (&saved_transform, &crtc->transform); - } - saved_transform_present = crtc->transformPresent; - - /* Update crtc values up front so the driver can rely on them for mode - * setting. - */ - crtc->mode = *mode; - crtc->x = x; - crtc->y = y; - crtc->rotation = rotation; - if (transform) { - RRTransformCopy (&crtc->transform, transform); - crtc->transformPresent = TRUE; - } else - crtc->transformPresent = FALSE; - - if (crtc->funcs->set_mode_major) { - ret = crtc->funcs->set_mode_major(crtc, mode, rotation, x, y); - goto done; - } - - didLock = crtc->funcs->lock (crtc); - /* Pass our mode to the outputs and the CRTC to give them a chance to - * adjust it according to limitations or output properties, and also - * a chance to reject the mode entirely. - */ - for (i = 0; i < xf86_config->num_output; i++) { - xf86OutputPtr output = xf86_config->output[i]; - - if (output->crtc != crtc) - continue; - - if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { - goto done; - } - } - - if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { - goto done; - } - - if (!xf86CrtcRotate (crtc)) - goto done; - - /* Prepare the outputs and CRTCs before setting the mode. */ - for (i = 0; i < xf86_config->num_output; i++) { - xf86OutputPtr output = xf86_config->output[i]; - - if (output->crtc != crtc) - continue; - - /* Disable the output as the first thing we do. */ - output->funcs->prepare(output); - } - - crtc->funcs->prepare(crtc); - - /* Set up the DPLL and any output state that needs to adjust or depend - * on the DPLL. - */ - crtc->funcs->mode_set(crtc, mode, adjusted_mode, crtc->x, crtc->y); - for (i = 0; i < xf86_config->num_output; i++) - { - xf86OutputPtr output = xf86_config->output[i]; - if (output->crtc == crtc) - output->funcs->mode_set(output, mode, adjusted_mode); - } - - /* Only upload when needed, to avoid unneeded delays. */ - if (!crtc->active && crtc->funcs->gamma_set) - crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, - crtc->gamma_blue, crtc->gamma_size); - - /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ - crtc->funcs->commit(crtc); - for (i = 0; i < xf86_config->num_output; i++) - { - xf86OutputPtr output = xf86_config->output[i]; - if (output->crtc == crtc) - output->funcs->commit(output); - } - - ret = TRUE; - -done: - if (ret) { - crtc->active = TRUE; - if (scrn->pScreen) - xf86CrtcSetScreenSubpixelOrder (scrn->pScreen); - } else { - crtc->x = saved_x; - crtc->y = saved_y; - crtc->rotation = saved_rotation; - crtc->mode = saved_mode; - if (saved_transform_present) - RRTransformCopy (&crtc->transform, &saved_transform); - crtc->transformPresent = saved_transform_present; - } - - if (adjusted_mode->name) - xfree(adjusted_mode->name); - xfree(adjusted_mode); - - if (didLock) - crtc->funcs->unlock (crtc); - - return ret; -} - -/** - * Sets the given video mode on the given crtc, but without providing - * a transform - */ -Bool -xf86CrtcSetMode (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, - int x, int y) -{ - return xf86CrtcSetModeTransform (crtc, mode, rotation, NULL, x, y); -} - -/** - * Pans the screen, does not change the mode - */ -void -xf86CrtcSetOrigin (xf86CrtcPtr crtc, int x, int y) -{ - crtc->x = x; - crtc->y = y; - if (crtc->funcs->set_origin) { - if (!xf86CrtcRotate (crtc)) - return; - crtc->funcs->set_origin (crtc, x, y); - } - else - xf86CrtcSetMode (crtc, &crtc->mode, crtc->rotation, x, y); -} - -/* - * Output functions - */ - -extern XF86ConfigPtr xf86configptr; - -typedef enum { - OPTION_PREFERRED_MODE, - OPTION_POSITION, - OPTION_BELOW, - OPTION_RIGHT_OF, - OPTION_ABOVE, - OPTION_LEFT_OF, - OPTION_ENABLE, - OPTION_DISABLE, - OPTION_MIN_CLOCK, - OPTION_MAX_CLOCK, - OPTION_IGNORE, - OPTION_ROTATE, - OPTION_PANNING, - OPTION_PRIMARY, -} OutputOpts; - -static OptionInfoRec xf86OutputOptions[] = { - {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE }, - {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE }, - {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE }, - {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE }, - {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE }, - {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE }, - {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE }, - {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE }, - {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE }, - {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE }, - {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE }, - {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE }, - {OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE }, - {OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE }, - {-1, NULL, OPTV_NONE, {0}, FALSE }, -}; - -enum { - OPTION_MODEDEBUG, -}; - -static OptionInfoRec xf86DeviceOptions[] = { - {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE }, - {-1, NULL, OPTV_NONE, {0}, FALSE }, -}; - -static void -xf86OutputSetMonitor (xf86OutputPtr output) -{ - char *option_name; - static const char monitor_prefix[] = "monitor-"; - char *monitor; - - if (!output->name) - return; - - if (output->options) - xfree (output->options); - - output->options = xnfalloc (sizeof (xf86OutputOptions)); - memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions)); - - option_name = xnfalloc (strlen (monitor_prefix) + - strlen (output->name) + 1); - strcpy (option_name, monitor_prefix); - strcat (option_name, output->name); - monitor = xf86findOptionValue (output->scrn->options, option_name); - if (!monitor) - monitor = output->name; - else - xf86MarkOptionUsedByName (output->scrn->options, option_name); - xfree (option_name); - output->conf_monitor = xf86findMonitor (monitor, - xf86configptr->conf_monitor_lst); - /* - * Find the monitor section of the screen and use that - */ - if (!output->conf_monitor && output->use_screen_monitor) - output->conf_monitor = xf86findMonitor (output->scrn->monitor->id, - xf86configptr->conf_monitor_lst); - if (output->conf_monitor) - { - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s using monitor section %s\n", - output->name, output->conf_monitor->mon_identifier); - xf86ProcessOptions (output->scrn->scrnIndex, - output->conf_monitor->mon_option_lst, - output->options); - } - else - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s has no monitor section\n", - output->name); -} - -static Bool -xf86OutputEnabled (xf86OutputPtr output, Bool strict) -{ - Bool enable, disable; - - /* check to see if this output was enabled in the config file */ - if (xf86GetOptValBool (output->options, OPTION_ENABLE, &enable) && enable) - { - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s enabled by config file\n", output->name); - return TRUE; - } - /* or if this output was disabled in the config file */ - if (xf86GetOptValBool (output->options, OPTION_DISABLE, &disable) && disable) - { - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s disabled by config file\n", output->name); - return FALSE; - } - - /* If not, try to only light up the ones we know are connected */ - if (strict) { - enable = output->status == XF86OutputStatusConnected; - } - /* But if that fails, try to light up even outputs we're unsure of */ - else { - enable = output->status != XF86OutputStatusDisconnected; - } - - xf86DrvMsg (output->scrn->scrnIndex, X_INFO, - "Output %s %sconnected\n", output->name, enable ? "" : "dis"); - return enable; -} - -static Bool -xf86OutputIgnored (xf86OutputPtr output) -{ - return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE); -} - -static char *direction[4] = { - "normal", - "left", - "inverted", - "right" -}; - -static Rotation -xf86OutputInitialRotation (xf86OutputPtr output) -{ - char *rotate_name = xf86GetOptValString (output->options, - OPTION_ROTATE); - int i; - - if (!rotate_name) - return RR_Rotate_0; - - for (i = 0; i < 4; i++) - if (xf86nameCompare (direction[i], rotate_name) == 0) - return (1 << i); - return RR_Rotate_0; -} - -xf86OutputPtr -xf86OutputCreate (ScrnInfoPtr scrn, - const xf86OutputFuncsRec *funcs, - const char *name) -{ - xf86OutputPtr output, *outputs; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - int len; - Bool primary; - - if (name) - len = strlen (name) + 1; - else - len = 0; - - output = xcalloc (sizeof (xf86OutputRec) + len, 1); - if (!output) - return NULL; - output->scrn = scrn; - output->funcs = funcs; - if (name) - { - output->name = (char *) (output + 1); - strcpy (output->name, name); - } - output->subpixel_order = SubPixelUnknown; - /* - * Use the old per-screen monitor section for the first output - */ - output->use_screen_monitor = (xf86_config->num_output == 0); -#ifdef RANDR_12_INTERFACE - output->randr_output = NULL; -#endif - if (name) - { - xf86OutputSetMonitor (output); - if (xf86OutputIgnored (output)) - { - xfree (output); - return FALSE; - } - } - - - if (xf86_config->output) - outputs = xrealloc (xf86_config->output, - (xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); - else - outputs = xalloc ((xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); - if (!outputs) - { - xfree (output); - return NULL; - } - - xf86_config->output = outputs; - - if (xf86GetOptValBool (output->options, OPTION_PRIMARY, &primary) && primary) - { - memmove(xf86_config->output + 1, xf86_config->output, - xf86_config->num_output * sizeof (xf86OutputPtr)); - xf86_config->output[0] = output; - } - else - { - xf86_config->output[xf86_config->num_output] = output; - } - - xf86_config->num_output++; - - return output; -} - -Bool -xf86OutputRename (xf86OutputPtr output, const char *name) -{ - int len = strlen(name) + 1; - char *newname = xalloc (len); - - if (!newname) - return FALSE; /* so sorry... */ - - strcpy (newname, name); - if (output->name && output->name != (char *) (output + 1)) - xfree (output->name); - output->name = newname; - xf86OutputSetMonitor (output); - if (xf86OutputIgnored (output)) - return FALSE; - return TRUE; -} - -void -xf86OutputUseScreenMonitor (xf86OutputPtr output, Bool use_screen_monitor) -{ - if (use_screen_monitor != output->use_screen_monitor) - { - output->use_screen_monitor = use_screen_monitor; - xf86OutputSetMonitor (output); - } -} - -void -xf86OutputDestroy (xf86OutputPtr output) -{ - ScrnInfoPtr scrn = output->scrn; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - - (*output->funcs->destroy) (output); - while (output->probed_modes) - xf86DeleteMode (&output->probed_modes, output->probed_modes); - for (o = 0; o < xf86_config->num_output; o++) - if (xf86_config->output[o] == output) - { - memmove (&xf86_config->output[o], - &xf86_config->output[o+1], - ((xf86_config->num_output - (o + 1)) * sizeof(void*))); - xf86_config->num_output--; - break; - } - if (output->name && output->name != (char *) (output + 1)) - xfree (output->name); - xfree (output); -} - -/* - * Called during CreateScreenResources to hook up RandR - */ -static Bool -xf86CrtcCreateScreenResources (ScreenPtr screen) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - - screen->CreateScreenResources = config->CreateScreenResources; - - if (!(*screen->CreateScreenResources)(screen)) - return FALSE; - - if (!xf86RandR12CreateScreenResources (screen)) - return FALSE; - - return TRUE; -} - -/* - * Clean up config on server reset - */ -static Bool -xf86CrtcCloseScreen (int index, ScreenPtr screen) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o, c; - - screen->CloseScreen = config->CloseScreen; - - xf86RotateCloseScreen (screen); - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - output->randr_output = NULL; - } - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - - crtc->randr_crtc = NULL; - } - return screen->CloseScreen (index, screen); -} - -/* - * Called at ScreenInit time to set up - */ -#ifdef RANDR_13_INTERFACE -int -#else -Bool -#endif -xf86CrtcScreenInit (ScreenPtr screen) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int c; - - /* Rotation */ - xf86DrvMsg(scrn->scrnIndex, X_INFO, "RandR 1.2 enabled, ignore the following RandR disabled message.\n"); - xf86DisableRandR(); /* Disable old RandR extension support */ - xf86RandR12Init (screen); - - /* support all rotations if every crtc has the shadow alloc funcs */ - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create) - break; - } - if (c == config->num_crtc) - { - xf86RandR12SetRotations (screen, RR_Rotate_0 | RR_Rotate_90 | - RR_Rotate_180 | RR_Rotate_270 | - RR_Reflect_X | RR_Reflect_Y); - xf86RandR12SetTransformSupport (screen, TRUE); - } - else - { - xf86RandR12SetRotations (screen, RR_Rotate_0); - xf86RandR12SetTransformSupport (screen, FALSE); - } - - /* Wrap CreateScreenResources so we can initialize the RandR code */ - config->CreateScreenResources = screen->CreateScreenResources; - screen->CreateScreenResources = xf86CrtcCreateScreenResources; - - config->CloseScreen = screen->CloseScreen; - screen->CloseScreen = xf86CrtcCloseScreen; - -#ifdef XFreeXDGA - _xf86_di_dga_init_internal(screen); -#endif -#ifdef RANDR_13_INTERFACE - return RANDR_INTERFACE_VERSION; -#else - return TRUE; -#endif -} - -static DisplayModePtr -xf86DefaultMode (xf86OutputPtr output, int width, int height) -{ - DisplayModePtr target_mode = NULL; - DisplayModePtr mode; - int target_diff = 0; - int target_preferred = 0; - int mm_height; - - mm_height = output->mm_height; - if (!mm_height) - mm_height = (768 * 25.4) / DEFAULT_DPI; - /* - * Pick a mode closest to DEFAULT_DPI - */ - for (mode = output->probed_modes; mode; mode = mode->next) - { - int dpi; - int preferred = (((mode->type & M_T_PREFERRED) != 0) + - ((mode->type & M_T_USERPREF) != 0)); - int diff; - - if (xf86ModeWidth (mode, output->initial_rotation) > width || - xf86ModeHeight (mode, output->initial_rotation) > height) - continue; - - /* yes, use VDisplay here, not xf86ModeHeight */ - dpi = (mode->VDisplay * 254) / (mm_height * 10); - diff = dpi - DEFAULT_DPI; - diff = diff < 0 ? -diff : diff; - if (target_mode == NULL || (preferred > target_preferred) || - (preferred == target_preferred && diff < target_diff)) - { - target_mode = mode; - target_diff = diff; - target_preferred = preferred; - } - } - return target_mode; -} - -static DisplayModePtr -xf86ClosestMode (xf86OutputPtr output, - DisplayModePtr match, Rotation match_rotation, - int width, int height) -{ - DisplayModePtr target_mode = NULL; - DisplayModePtr mode; - int target_diff = 0; - - /* - * Pick a mode closest to the specified mode - */ - for (mode = output->probed_modes; mode; mode = mode->next) - { - int dx, dy; - int diff; - - if (xf86ModeWidth (mode, output->initial_rotation) > width || - xf86ModeHeight (mode, output->initial_rotation) > height) - continue; - - /* exact matches are preferred */ - if (output->initial_rotation == match_rotation && - xf86ModesEqual (mode, match)) - return mode; - - dx = xf86ModeWidth (match, match_rotation) - xf86ModeWidth (mode, output->initial_rotation); - dy = xf86ModeHeight (match, match_rotation) - xf86ModeHeight (mode, output->initial_rotation); - diff = dx * dx + dy * dy; - if (target_mode == NULL || diff < target_diff) - { - target_mode = mode; - target_diff = diff; - } - } - return target_mode; -} - -static DisplayModePtr -xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height) -{ - DisplayModePtr mode; - - for (mode = output->probed_modes; mode; mode = mode->next) - { - if (xf86ModeWidth (mode, output->initial_rotation) > width || - xf86ModeHeight (mode, output->initial_rotation) > height) - continue; - - if (mode->type & M_T_PREFERRED) - return mode; - } - return NULL; -} - -static DisplayModePtr -xf86OutputHasUserPreferredMode (xf86OutputPtr output) -{ - DisplayModePtr mode, first = output->probed_modes; - - for (mode = first; mode && mode->next != first; mode = mode->next) - if (mode->type & M_T_USERPREF) - return mode; - - return NULL; -} - -static int -xf86PickCrtcs (ScrnInfoPtr scrn, - xf86CrtcPtr *best_crtcs, - DisplayModePtr *modes, - int n, - int width, - int height) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int c, o; - xf86OutputPtr output; - xf86CrtcPtr crtc; - xf86CrtcPtr *crtcs; - xf86CrtcPtr best_crtc; - int best_score; - int score; - int my_score; - - if (n == config->num_output) - return 0; - output = config->output[n]; - - /* - * Compute score with this output disabled - */ - best_crtcs[n] = NULL; - best_crtc = NULL; - best_score = xf86PickCrtcs (scrn, best_crtcs, modes, n+1, width, height); - if (modes[n] == NULL) - return best_score; - - crtcs = xalloc (config->num_output * sizeof (xf86CrtcPtr)); - if (!crtcs) - return best_score; - - my_score = 1; - /* Score outputs that are known to be connected higher */ - if (output->status == XF86OutputStatusConnected) - my_score++; - /* Score outputs with preferred modes higher */ - if (xf86OutputHasPreferredMode (output, width, height)) - my_score++; - /* - * Select a crtc for this output and - * then attempt to configure the remaining - * outputs - */ - for (c = 0; c < config->num_crtc; c++) - { - if ((output->possible_crtcs & (1 << c)) == 0) - continue; - - crtc = config->crtc[c]; - /* - * Check to see if some other output is - * using this crtc - */ - for (o = 0; o < n; o++) - if (best_crtcs[o] == crtc) - break; - if (o < n) - { - /* - * If the two outputs desire the same mode, - * see if they can be cloned - */ - if (xf86ModesEqual (modes[o], modes[n]) && - config->output[o]->initial_rotation == config->output[n]->initial_rotation && - config->output[o]->initial_x == config->output[n]->initial_x && - config->output[o]->initial_y == config->output[n]->initial_y) - { - if ((output->possible_clones & (1 << o)) == 0) - continue; /* nope, try next CRTC */ - } - else - continue; /* different modes, can't clone */ - } - crtcs[n] = crtc; - memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); - score = my_score + xf86PickCrtcs (scrn, crtcs, modes, n+1, width, height); - if (score > best_score) - { - best_crtc = crtc; - best_score = score; - memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr)); - } - } - xfree (crtcs); - return best_score; -} - - -/* - * Compute the virtual size necessary to place all of the available - * crtcs in the specified configuration. - * - * canGrow indicates that the driver can make the screen larger than its initial - * configuration. If FALSE, this function will enlarge the screen to include - * the largest available mode. - */ - -static void -xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp, - Bool canGrow) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int width = 0, height = 0; - int o; - int c; - int s; - - for (c = 0; c < config->num_crtc; c++) - { - int crtc_width = 0, crtc_height = 0; - xf86CrtcPtr crtc = config->crtc[c]; - - if (crtc->enabled) - { - crtc_width = crtc->x + xf86ModeWidth (&crtc->desiredMode, crtc->desiredRotation); - crtc_height = crtc->y + xf86ModeHeight (&crtc->desiredMode, crtc->desiredRotation); - } - if (!canGrow) { - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - for (s = 0; s < config->num_crtc; s++) - if (output->possible_crtcs & (1 << s)) - { - DisplayModePtr mode; - for (mode = output->probed_modes; mode; mode = mode->next) - { - if (mode->HDisplay > crtc_width) - crtc_width = mode->HDisplay; - if (mode->VDisplay > crtc_width) - crtc_width = mode->VDisplay; - if (mode->VDisplay > crtc_height) - crtc_height = mode->VDisplay; - if (mode->HDisplay > crtc_height) - crtc_height = mode->HDisplay; - } - } - } - } - if (crtc_width > width) - width = crtc_width; - if (crtc_height > height) - height = crtc_height; - } - if (config->maxWidth && width > config->maxWidth) width = config->maxWidth; - if (config->maxHeight && height > config->maxHeight) height = config->maxHeight; - if (config->minWidth && width < config->minWidth) width = config->minWidth; - if (config->minHeight && height < config->minHeight) height = config->minHeight; - *widthp = width; - *heightp = height; -} - -#define POSITION_UNSET -100000 - -/* - * check if the user configured any outputs at all - * with either a position or a relative setting or a mode. - */ -static Bool -xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr *modes) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - Bool user_conf = FALSE; - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - char *position; - char *relative_name; - OutputOpts relation; - int r; - static const OutputOpts relations[] = { - OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF - }; - - position = xf86GetOptValString (output->options, - OPTION_POSITION); - if (position) - user_conf = TRUE; - - relation = 0; - relative_name = NULL; - for (r = 0; r < 4; r++) - { - relation = relations[r]; - relative_name = xf86GetOptValString (output->options, - relation); - if (relative_name) - break; - } - if (relative_name) - user_conf = TRUE; - - modes[o] = xf86OutputHasUserPreferredMode(output); - if (modes[o]) - user_conf = TRUE; - } - - return user_conf; -} - -static Bool -xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - int min_x, min_y; - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - output->initial_x = output->initial_y = POSITION_UNSET; - } - - /* - * Loop until all outputs are set - */ - for (;;) - { - Bool any_set = FALSE; - Bool keep_going = FALSE; - - for (o = 0; o < config->num_output; o++) - { - static const OutputOpts relations[] = { - OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF - }; - xf86OutputPtr output = config->output[o]; - xf86OutputPtr relative; - char *relative_name; - char *position; - OutputOpts relation; - int r; - - if (output->initial_x != POSITION_UNSET) - continue; - position = xf86GetOptValString (output->options, - OPTION_POSITION); - /* - * Absolute position wins - */ - if (position) - { - int x, y; - if (sscanf (position, "%d %d", &x, &y) == 2) - { - output->initial_x = x; - output->initial_y = y; - } - else - { - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Output %s position not of form \"x y\"\n", - output->name); - output->initial_x = output->initial_y = 0; - } - any_set = TRUE; - continue; - } - /* - * Next comes relative positions - */ - relation = 0; - relative_name = NULL; - for (r = 0; r < 4; r++) - { - relation = relations[r]; - relative_name = xf86GetOptValString (output->options, - relation); - if (relative_name) - break; - } - if (relative_name) - { - int or; - relative = NULL; - for (or = 0; or < config->num_output; or++) - { - xf86OutputPtr out_rel = config->output[or]; - XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; - - if (rel_mon) - { - if (xf86nameCompare (rel_mon->mon_identifier, - relative_name) == 0) - { - relative = config->output[or]; - break; - } - } - if (strcmp (out_rel->name, relative_name) == 0) - { - relative = config->output[or]; - break; - } - } - if (!relative) - { - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Cannot position output %s relative to unknown output %s\n", - output->name, relative_name); - output->initial_x = 0; - output->initial_y = 0; - any_set = TRUE; - continue; - } - if (!modes[or]) - { - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Cannot position output %s relative to output %s without modes\n", - output->name, relative_name); - output->initial_x = 0; - output->initial_y = 0; - any_set = TRUE; - continue; - } - if (relative->initial_x == POSITION_UNSET) - { - keep_going = TRUE; - continue; - } - output->initial_x = relative->initial_x; - output->initial_y = relative->initial_y; - switch (relation) { - case OPTION_BELOW: - output->initial_y += xf86ModeHeight (modes[or], relative->initial_rotation); - break; - case OPTION_RIGHT_OF: - output->initial_x += xf86ModeWidth (modes[or], relative->initial_rotation); - break; - case OPTION_ABOVE: - if (modes[o]) - output->initial_y -= xf86ModeHeight (modes[o], output->initial_rotation); - break; - case OPTION_LEFT_OF: - if (modes[o]) - output->initial_x -= xf86ModeWidth (modes[o], output->initial_rotation); - break; - default: - break; - } - any_set = TRUE; - continue; - } - - /* Nothing set, just stick them at 0,0 */ - output->initial_x = 0; - output->initial_y = 0; - any_set = TRUE; - } - if (!keep_going) - break; - if (!any_set) - { - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - if (output->initial_x == POSITION_UNSET) - { - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Output position loop. Moving %s to 0,0\n", - output->name); - output->initial_x = output->initial_y = 0; - break; - } - } - } - } - - /* - * normalize positions - */ - min_x = 1000000; - min_y = 1000000; - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - if (output->initial_x < min_x) - min_x = output->initial_x; - if (output->initial_y < min_y) - min_y = output->initial_y; - } - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - output->initial_x -= min_x; - output->initial_y -= min_y; - } - return TRUE; -} - -static void -xf86InitialPanning (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - char *panning = xf86GetOptValString (output->options, OPTION_PANNING); - int width, height, left, top; - int track_width, track_height, track_left, track_top; - int brdr[4]; - - memset (&output->initialTotalArea, 0, sizeof(BoxRec)); - memset (&output->initialTrackingArea, 0, sizeof(BoxRec)); - memset (output->initialBorder, 0, 4*sizeof(INT16)); - - if (! panning) - continue; - - switch (sscanf (panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", - &width, &height, &left, &top, - &track_width, &track_height, &track_left, &track_top, - &brdr[0], &brdr[1], &brdr[2], &brdr[3])) { - case 12: - output->initialBorder[0] = brdr[0]; - output->initialBorder[1] = brdr[1]; - output->initialBorder[2] = brdr[2]; - output->initialBorder[3] = brdr[3]; - /* fall through */ - case 8: - output->initialTrackingArea.x1 = track_left; - output->initialTrackingArea.y1 = track_top; - output->initialTrackingArea.x2 = track_left + track_width; - output->initialTrackingArea.y2 = track_top + track_height; - /* fall through */ - case 4: - output->initialTotalArea.x1 = left; - output->initialTotalArea.y1 = top; - /* fall through */ - case 2: - output->initialTotalArea.x2 = output->initialTotalArea.x1 + width; - output->initialTotalArea.y2 = output->initialTotalArea.y1 + height; - break; - default: - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Broken panning specification '%s' for output %s in config file\n", - panning, output->name); - } - } -} - -/** Return - 0 + if a should be earlier, same or later than b in list - */ -static int -xf86ModeCompare (DisplayModePtr a, DisplayModePtr b) -{ - int diff; - - diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); - if (diff) - return diff; - diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; - if (diff) - return diff; - diff = b->Clock - a->Clock; - return diff; -} - -/** - * Insertion sort input in-place and return the resulting head - */ -static DisplayModePtr -xf86SortModes (DisplayModePtr input) -{ - DisplayModePtr output = NULL, i, o, n, *op, prev; - - /* sort by preferred status and pixel area */ - while (input) - { - i = input; - input = input->next; - for (op = &output; (o = *op); op = &o->next) - if (xf86ModeCompare (o, i) > 0) - break; - i->next = *op; - *op = i; - } - /* prune identical modes */ - for (o = output; o && (n = o->next); o = n) - { - if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n)) - { - o->next = n->next; - xfree (n->name); - xfree (n); - n = o; - } - } - /* hook up backward links */ - prev = NULL; - for (o = output; o; o = o->next) - { - o->prev = prev; - prev = o; - } - return output; -} - -static char * -preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output) -{ - char *preferred_mode = NULL; - - /* Check for a configured preference for a particular mode */ - preferred_mode = xf86GetOptValString (output->options, - OPTION_PREFERRED_MODE); - if (preferred_mode) - return preferred_mode; - - if (pScrn->display->modes && *pScrn->display->modes) - preferred_mode = *pScrn->display->modes; - - return preferred_mode; -} - -static void -GuessRangeFromModes(MonPtr mon, DisplayModePtr mode) -{ - if (!mon || !mode) - return; - - mon->nHsync = 1; - mon->hsync[0].lo = 1024.0; - mon->hsync[0].hi = 0.0; - - mon->nVrefresh = 1; - mon->vrefresh[0].lo = 1024.0; - mon->vrefresh[0].hi = 0.0; - - while (mode) { - if (!mode->HSync) - mode->HSync = ((float) mode->Clock ) / ((float) mode->HTotal); - - if (!mode->VRefresh) - mode->VRefresh = (1000.0 * ((float) mode->Clock)) / - ((float) (mode->HTotal * mode->VTotal)); - - if (mode->HSync < mon->hsync[0].lo) - mon->hsync[0].lo = mode->HSync; - - if (mode->HSync > mon->hsync[0].hi) - mon->hsync[0].hi = mode->HSync; - - if (mode->VRefresh < mon->vrefresh[0].lo) - mon->vrefresh[0].lo = mode->VRefresh; - - if (mode->VRefresh > mon->vrefresh[0].hi) - mon->vrefresh[0].hi = mode->VRefresh; - - mode = mode->next; - } - - /* stretch out the bottom to fit 640x480@60 */ - if (mon->hsync[0].lo > 31.0) - mon->hsync[0].lo = 31.0; - if (mon->vrefresh[0].lo > 58.0) - mon->vrefresh[0].lo = 58.0; -} - -enum det_monrec_source { - sync_config, sync_edid, sync_default -}; - -struct det_monrec_parameter { - MonRec *mon_rec; - int *max_clock; - Bool set_hsync; - Bool set_vrefresh; - enum det_monrec_source *sync_source; -}; - -static void handle_detailed_monrec(struct detailed_monitor_section *det_mon, - void *data) -{ - enum { sync_config, sync_edid, sync_default }; - struct det_monrec_parameter *p; - p = (struct det_monrec_parameter *)data; - - if (det_mon->type == DS_RANGES) { - struct monitor_ranges *ranges = &det_mon->section.ranges; - if (p->set_hsync && ranges->max_h) { - p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h; - p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h; - p->mon_rec->nHsync++; - if (*p->sync_source == sync_default) - *p->sync_source = sync_edid; - } - if (p->set_vrefresh && ranges->max_v) { - p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v; - p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v; - p->mon_rec->nVrefresh++; - if (*p->sync_source == sync_default) - *p->sync_source = sync_edid; - } - if (ranges->max_clock * 1000 > *p->max_clock) - *p->max_clock = ranges->max_clock * 1000; - } -} - -void -xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - - /* When canGrow was TRUE in the initial configuration we have to - * compare against the maximum values so that we don't drop modes. - * When canGrow was FALSE, the maximum values would have been clamped - * anyway. - */ - if (maxX == 0 || maxY == 0) { - maxX = config->maxWidth; - maxY = config->maxHeight; - } - - /* Probe the list of modes for each output. */ - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - DisplayModePtr mode; - DisplayModePtr config_modes = NULL, output_modes, default_modes = NULL; - char *preferred_mode; - xf86MonPtr edid_monitor; - XF86ConfMonitorPtr conf_monitor; - MonRec mon_rec; - int min_clock = 0; - int max_clock = 0; - double clock; - Bool add_default_modes = TRUE; - Bool debug_modes = config->debug_modes || - xf86Initialising; - enum det_monrec_source sync_source = sync_default; - - while (output->probed_modes != NULL) - xf86DeleteMode(&output->probed_modes, output->probed_modes); - - /* - * Check connection status - */ - output->status = (*output->funcs->detect)(output); - - if (output->status == XF86OutputStatusDisconnected && - !xf86ReturnOptValBool(output->options, OPTION_ENABLE, FALSE)) - { - xf86OutputSetEDID (output, NULL); - continue; - } - - memset (&mon_rec, '\0', sizeof (mon_rec)); - - conf_monitor = output->conf_monitor; - - if (conf_monitor) - { - int i; - - for (i = 0; i < conf_monitor->mon_n_hsync; i++) - { - mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo; - mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi; - mon_rec.nHsync++; - sync_source = sync_config; - } - for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) - { - mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo; - mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi; - mon_rec.nVrefresh++; - sync_source = sync_config; - } - config_modes = xf86GetMonitorModes (scrn, conf_monitor); - } - - output_modes = (*output->funcs->get_modes) (output); - - edid_monitor = output->MonInfo; - - if (edid_monitor) - { - struct det_monrec_parameter p; - struct disp_features *features = &edid_monitor->features; - - /* if display is not continuous-frequency, don't add default modes */ - if (!GTF_SUPPORTED(features->msc)) - add_default_modes = FALSE; - - p.mon_rec = &mon_rec; - p.max_clock = &max_clock; - p.set_hsync = mon_rec.nHsync == 0; - p.set_vrefresh = mon_rec.nVrefresh == 0; - p.sync_source = &sync_source; - - xf86ForEachDetailedBlock(edid_monitor, - handle_detailed_monrec, - &p); - } - - if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK, - OPTUNITS_KHZ, &clock)) - min_clock = (int) clock; - if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK, - OPTUNITS_KHZ, &clock)) - max_clock = (int) clock; - - /* If we still don't have a sync range, guess wildly */ - if (!mon_rec.nHsync || !mon_rec.nVrefresh) - GuessRangeFromModes(&mon_rec, output_modes); - - /* - * These limits will end up setting a 1024x768@60Hz mode by default, - * which seems like a fairly good mode to use when nothing else is - * specified - */ - if (mon_rec.nHsync == 0) - { - mon_rec.hsync[0].lo = 31.0; - mon_rec.hsync[0].hi = 55.0; - mon_rec.nHsync = 1; - } - if (mon_rec.nVrefresh == 0) - { - mon_rec.vrefresh[0].lo = 58.0; - mon_rec.vrefresh[0].hi = 62.0; - mon_rec.nVrefresh = 1; - } - - if (add_default_modes) - default_modes = xf86GetDefaultModes (); - - /* - * If this is not an RB monitor, remove RB modes from the default - * pool. RB modes from the config or the monitor itself are fine. - */ - if (!mon_rec.reducedblanking) - xf86ValidateModesReducedBlanking (scrn, default_modes); - - if (sync_source == sync_config) - { - /* - * Check output and config modes against sync range from config file - */ - xf86ValidateModesSync (scrn, output_modes, &mon_rec); - xf86ValidateModesSync (scrn, config_modes, &mon_rec); - } - /* - * Check default modes against sync range - */ - xf86ValidateModesSync (scrn, default_modes, &mon_rec); - /* - * Check default modes against monitor max clock - */ - if (max_clock) { - xf86ValidateModesClocks(scrn, default_modes, - &min_clock, &max_clock, 1); - xf86ValidateModesClocks(scrn, output_modes, - &min_clock, &max_clock, 1); - } - - output->probed_modes = NULL; - output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes); - output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes); - output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes); - - /* - * Check all modes against max size, interlace, and doublescan - */ - if (maxX && maxY) - xf86ValidateModesSize (scrn, output->probed_modes, - maxX, maxY, 0); - - { - int flags = (output->interlaceAllowed ? V_INTERLACE : 0) | - (output->doubleScanAllowed ? V_DBLSCAN : 0); - xf86ValidateModesFlags (scrn, output->probed_modes, flags); - } - - /* - * Check all modes against output - */ - for (mode = output->probed_modes; mode != NULL; mode = mode->next) - if (mode->status == MODE_OK) - mode->status = (*output->funcs->mode_valid)(output, mode); - - xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes); - - output->probed_modes = xf86SortModes (output->probed_modes); - - /* Check for a configured preference for a particular mode */ - preferred_mode = preferredMode(scrn, output); - - if (preferred_mode) - { - for (mode = output->probed_modes; mode; mode = mode->next) - { - if (!strcmp (preferred_mode, mode->name)) - { - if (mode != output->probed_modes) - { - if (mode->prev) - mode->prev->next = mode->next; - if (mode->next) - mode->next->prev = mode->prev; - mode->next = output->probed_modes; - output->probed_modes->prev = mode; - mode->prev = NULL; - output->probed_modes = mode; - } - mode->type |= (M_T_PREFERRED|M_T_USERPREF); - break; - } - } - } - - output->initial_rotation = xf86OutputInitialRotation (output); - - if (debug_modes) { - if (output->probed_modes != NULL) { - xf86DrvMsg(scrn->scrnIndex, X_INFO, - "Printing probed modes for output %s\n", - output->name); - } else { - xf86DrvMsg(scrn->scrnIndex, X_INFO, - "No remaining probed modes for output %s\n", - output->name); - } - } - for (mode = output->probed_modes; mode != NULL; mode = mode->next) - { - /* The code to choose the best mode per pipe later on will require - * VRefresh to be set. - */ - mode->VRefresh = xf86ModeVRefresh(mode); - xf86SetModeCrtc(mode, INTERLACE_HALVE_V); - - if (debug_modes) - xf86PrintModeline(scrn->scrnIndex, mode); - } - } -} - - -/** - * Copy one of the output mode lists to the ScrnInfo record - */ - -/* XXX where does this function belong? Here? */ -void -xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y); - -static DisplayModePtr -biggestMode(DisplayModePtr a, DisplayModePtr b) -{ - int A, B; - - if (!a) - return b; - if (!b) - return a; - - A = a->HDisplay * a->VDisplay; - B = b->HDisplay * b->VDisplay; - - if (A > B) - return a; - - return b; -} - -static xf86OutputPtr -SetCompatOutput(xf86CrtcConfigPtr config) -{ - xf86OutputPtr output = NULL, test = NULL; - DisplayModePtr maxmode = NULL, testmode, mode; - int o, compat = -1, count, mincount = 0; - - /* Look for one that's definitely connected */ - for (o = 0; o < config->num_output; o++) - { - test = config->output[o]; - if (!test->crtc) - continue; - if (test->status != XF86OutputStatusConnected) - continue; - if (!test->probed_modes) - continue; - - testmode = mode = test->probed_modes; - for (count = 0; mode; mode = mode->next, count++) - testmode = biggestMode(testmode, mode); - - if (!output) { - output = test; - compat = o; - maxmode = testmode; - mincount = count; - } else if (maxmode == biggestMode(maxmode, testmode)) { - output = test; - compat = o; - maxmode = testmode; - mincount = count; - } else if ((maxmode->HDisplay == testmode->HDisplay) && - (maxmode->VDisplay == testmode->VDisplay) && - count <= mincount) { - output = test; - compat = o; - maxmode = testmode; - mincount = count; - } - } - - /* If we didn't find one, take anything we can get */ - if (!output) - { - for (o = 0; o < config->num_output; o++) - { - test = config->output[o]; - if (!test->crtc) - continue; - if (!test->probed_modes) - continue; - - if (!output) { - output = test; - compat = o; - } else if (test->probed_modes->HDisplay < output->probed_modes->HDisplay) { - output = test; - compat = o; - } - } - } - - if (compat >= 0) { - config->compat_output = compat; - } else { - /* Don't change the compat output when no valid outputs found */ - output = config->output[config->compat_output]; - } - - return output; -} - -void -xf86SetScrnInfoModes (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - xf86OutputPtr output; - xf86CrtcPtr crtc; - DisplayModePtr last, mode = NULL; - - output = SetCompatOutput(config); - - if (!output) - return; /* punt */ - - crtc = output->crtc; - - /* Clear any existing modes from scrn->modes */ - while (scrn->modes != NULL) - xf86DeleteMode(&scrn->modes, scrn->modes); - - /* Set scrn->modes to the mode list for the 'compat' output */ - scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); - - if (crtc) { - for (mode = scrn->modes; mode; mode = mode->next) - if (xf86ModesEqual (mode, &crtc->desiredMode)) - break; - } - - if (scrn->modes != NULL) { - /* For some reason, scrn->modes is circular, unlike the other mode - * lists. How great is that? - */ - for (last = scrn->modes; last && last->next; last = last->next) - ; - last->next = scrn->modes; - scrn->modes->prev = last; - if (mode) { - while (scrn->modes != mode) - scrn->modes = scrn->modes->next; - } - } - scrn->currentMode = scrn->modes; -#ifdef XFreeXDGA - if (scrn->pScreen) - _xf86_di_dga_reinit_internal(scrn->pScreen); -#endif -} - -static void -xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - Bool *enabled) -{ - Bool any_enabled = FALSE; - int o; - - for (o = 0; o < config->num_output; o++) - any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE); - - if (!any_enabled) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "No outputs definitely connected, trying again...\n"); - - for (o = 0; o < config->num_output; o++) - enabled[o] = xf86OutputEnabled(config->output[o], FALSE); - } -} - -static Bool -nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index) -{ - int o = *index; - - for (o++; o < config->num_output; o++) { - if (enabled[o]) { - *index = o; - return TRUE; - } - } - - return FALSE; -} - -static Bool -aspectMatch(float a, float b) -{ - return fabs(1 - (a / b)) < 0.05; -} - -static DisplayModePtr -nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect) -{ - DisplayModePtr m = NULL; - - if (!o) - return NULL; - - if (!last) - m = o->probed_modes; - else - m = last->next; - - for (; m; m = m->next) - if (aspectMatch(aspect, (float)m->HDisplay / (float)m->VDisplay)) - return m; - - return NULL; -} - -static DisplayModePtr -bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect) -{ - int o = -1, p; - DisplayModePtr mode = NULL, test = NULL, match = NULL; - - if (!nextEnabledOutput(config, enabled, &o)) - return NULL; - while ((mode = nextAspectMode(config->output[o], mode, aspect))) { - test = mode; - for (p = o; nextEnabledOutput(config, enabled, &p); ) { - test = xf86OutputFindClosestMode(config->output[p], mode); - if (!test) - break; - if (test->HDisplay != mode->HDisplay || - test->VDisplay != mode->VDisplay) { - test = NULL; - break; - } - } - - /* if we didn't match it on all outputs, try the next one */ - if (!test) - continue; - - /* if it's bigger than the last one, save it */ - if (!match || (test->HDisplay > match->HDisplay)) - match = test; - } - - /* return the biggest one found */ - return match; -} - -static Bool -xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - DisplayModePtr *modes, Bool *enabled, - int width, int height) -{ - int o, p; - int max_pref_width = 0, max_pref_height = 0; - DisplayModePtr *preferred, *preferred_match; - Bool ret = FALSE; - - preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); - preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); - - /* Check if the preferred mode is available on all outputs */ - for (p = -1; nextEnabledOutput(config, enabled, &p); ) { - Rotation r = config->output[p]->initial_rotation; - DisplayModePtr mode; - if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p], - width, height))) { - int pref_width = xf86ModeWidth(preferred[p], r); - int pref_height = xf86ModeHeight(preferred[p], r); - Bool all_match = TRUE; - - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - Bool match = FALSE; - xf86OutputPtr output = config->output[o]; - if (o == p) - continue; - - for (mode = output->probed_modes; mode; mode = mode->next) { - Rotation r = output->initial_rotation; - if (xf86ModeWidth(mode, r) == pref_width && - xf86ModeHeight(mode, r) == pref_height) { - preferred[o] = mode; - match = TRUE; - } - } - - all_match &= match; - } - - if (all_match && - (pref_width*pref_height > max_pref_width*max_pref_height)) { - for (o = -1; nextEnabledOutput(config, enabled, &o); ) - preferred_match[o] = preferred[o]; - max_pref_width = pref_width; - max_pref_height = pref_height; - ret = TRUE; - } - } - } - - /* - * If there's no preferred mode, but only one monitor, pick the - * biggest mode for its aspect ratio, assuming one exists. - */ - if (!ret) do { - int i = 0; - float aspect = 0.0; - - /* count the number of enabled outputs */ - for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ; - - if (i != 1) - break; - - p = -1; - nextEnabledOutput(config, enabled, &p); - if (config->output[p]->mm_height) - aspect = (float)config->output[p]->mm_width / - (float)config->output[p]->mm_height; - - if (aspect) - preferred_match[p] = bestModeForAspect(config, enabled, aspect); - - if (preferred_match[p]) - ret = TRUE; - - } while (0); - - if (ret) { - /* oh good, there is a match. stash the selected modes and return. */ - memcpy(modes, preferred_match, - config->num_output * sizeof(DisplayModePtr)); - } - - xfree(preferred); - xfree(preferred_match); - return ret; -} - -static Bool -xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - DisplayModePtr *modes, Bool *enabled, - int width, int height) -{ - int o; - float aspect = 0.0, *aspects; - xf86OutputPtr output; - Bool ret = FALSE; - DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL; - - aspects = xnfcalloc(config->num_output, sizeof(float)); - - /* collect the aspect ratios */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - output = config->output[o]; - if (output->mm_height) - aspects[o] = (float)output->mm_width / (float)output->mm_height; - else - aspects[o] = 4.0 / 3.0; - } - - /* check that they're all the same */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - output = config->output[o]; - if (!aspect) { - aspect = aspects[o]; - } else if (!aspectMatch(aspect, aspects[o])) { - goto no_aspect_match; - } - } - - /* if they're all 4:3, just skip ahead and save effort */ - if (!aspectMatch(aspect, 4.0/3.0)) - aspect_guess = bestModeForAspect(config, enabled, aspect); - -no_aspect_match: - base_guess = bestModeForAspect(config, enabled, 4.0/3.0); - - guess = biggestMode(base_guess, aspect_guess); - - if (!guess) - goto out; - - /* found a mode that works everywhere, now apply it */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - modes[o] = xf86OutputFindClosestMode(config->output[o], guess); - } - ret = TRUE; - -out: - xfree(aspects); - return ret; -} - -static Bool -xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - DisplayModePtr *modes, Bool *enabled, - int width, int height) -{ - DisplayModePtr target_mode = NULL; - Rotation target_rotation = RR_Rotate_0; - DisplayModePtr default_mode; - int default_preferred, target_preferred = 0, o; - - /* User preferred > preferred > other modes */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - default_mode = xf86DefaultMode (config->output[o], width, height); - if (!default_mode) - continue; - - default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) + - ((default_mode->type & M_T_USERPREF) != 0)); - - if (default_preferred > target_preferred || !target_mode) { - target_mode = default_mode; - target_preferred = default_preferred; - target_rotation = config->output[o]->initial_rotation; - config->compat_output = o; - } - } - - if (target_mode) - modes[config->compat_output] = target_mode; - - /* Fill in other output modes */ - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - if (!modes[o]) - modes[o] = xf86ClosestMode(config->output[o], target_mode, - target_rotation, width, height); - } - - return (target_mode != NULL); -} - -static Bool -xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, - DisplayModePtr *modes, Bool *enabled, - int width, int height) -{ - int o; - - if (xf86UserConfiguredOutputs(scrn, modes)) - return xf86TargetFallback(scrn, config, modes, enabled, width, height); - - for (o = -1; nextEnabledOutput(config, enabled, &o); ) - if (xf86OutputHasUserPreferredMode(config->output[o])) - return - xf86TargetFallback(scrn, config, modes, enabled, width, height); - - return FALSE; -} - -static Bool -xf86CrtcSetInitialGamma(xf86CrtcPtr crtc, float gamma_red, float gamma_green, - float gamma_blue) -{ - int i, size = 256; - CARD16 *red, *green, *blue; - - red = malloc(3 * size * sizeof(CARD16)); - green = red + size; - blue = green + size; - - /* Only cause warning if user wanted gamma to be set. */ - if (!crtc->funcs->gamma_set && (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0)) { - free(red); - return FALSE; - } else if (!crtc->funcs->gamma_set) { - free(red); - return TRUE; - } - - /* At this early stage none of the randr-interface stuff is up. - * So take the default gamma size for lack of something better. - */ - for (i = 0; i < size; i++) { - if (gamma_red == 1.0) - red[i] = i << 8; - else - red[i] = (CARD16)(pow((double)i/(double)(size - 1), - 1. / (double)gamma_red) * (double)(size - 1) * 256); - - if (gamma_green == 1.0) - green[i] = i << 8; - else - green[i] = (CARD16)(pow((double)i/(double)(size - 1), - 1. / (double)gamma_green) * (double)(size - 1) * 256); - - if (gamma_blue == 1.0) - blue[i] = i << 8; - else - blue[i] = (CARD16)(pow((double)i/(double)(size - 1), - 1. / (double)gamma_blue) * (double)(size - 1) * 256); - } - - /* Default size is 256, so anything else is failure. */ - if (size != crtc->gamma_size) { - free(red); - return FALSE; - } - - crtc->gamma_size = size; - memcpy (crtc->gamma_red, red, crtc->gamma_size * sizeof (CARD16)); - memcpy (crtc->gamma_green, green, crtc->gamma_size * sizeof (CARD16)); - memcpy (crtc->gamma_blue, blue, crtc->gamma_size * sizeof (CARD16)); - - /* Do not set gamma now, delay until the crtc is activated. */ - - free(red); - - return TRUE; -} - -static Bool -xf86OutputSetInitialGamma(xf86OutputPtr output) -{ - XF86ConfMonitorPtr mon = output->conf_monitor; - float gamma_red = 1.0, gamma_green = 1.0, gamma_blue = 1.0; - - if (!mon) - return TRUE; - - if (!output->crtc) - return FALSE; - - /* Get configured values, where they exist. */ - if (mon->mon_gamma_red >= GAMMA_MIN && - mon->mon_gamma_red <= GAMMA_MAX) - gamma_red = mon->mon_gamma_red; - - if (mon->mon_gamma_green >= GAMMA_MIN && - mon->mon_gamma_green <= GAMMA_MAX) - gamma_green = mon->mon_gamma_green; - - if (mon->mon_gamma_blue >= GAMMA_MIN && - mon->mon_gamma_blue <= GAMMA_MAX) - gamma_blue = mon->mon_gamma_blue; - - /* This avoids setting gamma 1.0 in case another cloned output on this crtc has a specific gamma. */ - if (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0) { - xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Output %s wants gamma correction (%.1f, %.1f, %.1f)\n", output->name, gamma_red, gamma_green, gamma_blue); - return xf86CrtcSetInitialGamma(output->crtc, gamma_red, gamma_green, gamma_blue); - }else - return TRUE; -} - -/** - * Construct default screen configuration - * - * Given auto-detected (and, eventually, configured) values, - * construct a usable configuration for the system - * - * canGrow indicates that the driver can resize the screen to larger than its - * initially configured size via the config->funcs->resize hook. If TRUE, this - * function will set virtualX and virtualY to match the initial configuration - * and leave config->max{Width,Height} alone. If FALSE, it will bloat - * virtual[XY] to include the largest modes and set config->max{Width,Height} - * accordingly. - */ - -Bool -xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o, c; - xf86CrtcPtr *crtcs; - DisplayModePtr *modes; - Bool *enabled; - int width, height; - int i = scrn->scrnIndex; - - /* Set up the device options */ - config->options = xnfalloc (sizeof (xf86DeviceOptions)); - memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions)); - xf86ProcessOptions (scrn->scrnIndex, - scrn->options, - config->options); - config->debug_modes = xf86ReturnOptValBool (config->options, - OPTION_MODEDEBUG, FALSE); - - if (scrn->display->virtualX) - width = scrn->display->virtualX; - else - width = config->maxWidth; - if (scrn->display->virtualY) - height = scrn->display->virtualY; - else - height = config->maxHeight; - - xf86ProbeOutputModes (scrn, width, height); - - crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); - modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); - enabled = xnfcalloc (config->num_output, sizeof (Bool)); - - xf86CollectEnabledOutputs(scrn, config, enabled); - - if (xf86TargetUserpref(scrn, config, modes, enabled, width, height)) - xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n"); - else if (xf86TargetPreferred(scrn, config, modes, enabled, width, height)) - xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n"); - else if (xf86TargetAspect(scrn, config, modes, enabled, width, height)) - xf86DrvMsg(i, X_INFO, "Using fuzzy aspect match for initial modes\n"); - else if (xf86TargetFallback(scrn, config, modes, enabled, width, height)) - xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n"); - else - xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n"); - - for (o = -1; nextEnabledOutput(config, enabled, &o); ) { - if (!modes[o]) - xf86DrvMsg (scrn->scrnIndex, X_ERROR, - "Output %s enabled but has no modes\n", - config->output[o]->name); - else - xf86DrvMsg (scrn->scrnIndex, X_INFO, - "Output %s using initial mode %s\n", - config->output[o]->name, modes[o]->name); - } - - /* - * Set the position of each output - */ - if (!xf86InitialOutputPositions (scrn, modes)) - { - xfree (crtcs); - xfree (modes); - return FALSE; - } - - /* - * Set initial panning of each output - */ - xf86InitialPanning (scrn); - - /* - * Assign CRTCs to fit output configuration - */ - if (!xf86PickCrtcs (scrn, crtcs, modes, 0, width, height)) - { - xfree (crtcs); - xfree (modes); - return FALSE; - } - - /* XXX override xf86 common frame computation code */ - - scrn->display->frameX0 = 0; - scrn->display->frameY0 = 0; - - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - - crtc->enabled = FALSE; - memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); - /* Set default gamma for all crtc's. */ - /* This is done to avoid problems later on with cloned outputs. */ - xf86CrtcSetInitialGamma(crtc, 1.0, 1.0, 1.0); - } - - if (xf86_crtc_supports_gamma(scrn)) - xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using default gamma of (1.0, 1.0, 1.0) unless otherwise stated.\n"); - - /* - * Set initial configuration - */ - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - DisplayModePtr mode = modes[o]; - xf86CrtcPtr crtc = crtcs[o]; - - if (mode && crtc) - { - crtc->desiredMode = *mode; - crtc->desiredRotation = output->initial_rotation; - crtc->desiredX = output->initial_x; - crtc->desiredY = output->initial_y; - crtc->desiredTransformPresent = FALSE; - crtc->enabled = TRUE; - memcpy (&crtc->panningTotalArea, &output->initialTotalArea, sizeof(BoxRec)); - memcpy (&crtc->panningTrackingArea, &output->initialTrackingArea, sizeof(BoxRec)); - memcpy (crtc->panningBorder, output->initialBorder, 4*sizeof(INT16)); - output->crtc = crtc; - if (!xf86OutputSetInitialGamma(output)) - xf86DrvMsg (scrn->scrnIndex, X_WARNING, "Initial gamma correction for output %s: failed.\n", output->name); - } else { - output->crtc = NULL; - } - } - - if (scrn->display->virtualX == 0) - { - /* - * Expand virtual size to cover the current config and potential mode - * switches, if the driver can't enlarge the screen later. - */ - xf86DefaultScreenLimits (scrn, &width, &height, canGrow); - - scrn->display->virtualX = width; - scrn->display->virtualY = height; - } - - if (width > scrn->virtualX) - scrn->virtualX = width; - if (height > scrn->virtualY) - scrn->virtualY = height; - - /* - * Make sure the configuration isn't too small. - */ - if (width < config->minWidth || height < config->minHeight) - return FALSE; - - /* - * Limit the crtc config to virtual[XY] if the driver can't grow the - * desktop. - */ - if (!canGrow) - { - xf86CrtcSetSizeRange (scrn, config->minWidth, config->minHeight, - width, height); - } - - /* Mirror output modes to scrn mode list */ - xf86SetScrnInfoModes (scrn); - - xfree (crtcs); - xfree (modes); - return TRUE; -} - -/* - * Check the CRTC we're going to map each output to vs. it's current - * CRTC. If they don't match, we have to disable the output and the CRTC - * since the driver will have to re-route things. - */ -static void -xf86PrepareOutputs (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int o; - - for (o = 0; o < config->num_output; o++) { - xf86OutputPtr output = config->output[o]; -#if RANDR_GET_CRTC_INTERFACE - /* Disable outputs that are unused or will be re-routed */ - if (!output->funcs->get_crtc || - output->crtc != (*output->funcs->get_crtc)(output) || - output->crtc == NULL) -#endif - (*output->funcs->dpms)(output, DPMSModeOff); - } -} - -static void -xf86PrepareCrtcs (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int c; - - for (c = 0; c < config->num_crtc; c++) { -#if RANDR_GET_CRTC_INTERFACE - xf86CrtcPtr crtc = config->crtc[c]; - xf86OutputPtr output = NULL; - uint32_t desired_outputs = 0, current_outputs = 0; - int o; - - for (o = 0; o < config->num_output; o++) { - output = config->output[o]; - if (output->crtc == crtc) - desired_outputs |= (1<<o); - /* If we can't tell where it's mapped, force it off */ - if (!output->funcs->get_crtc) { - desired_outputs = 0; - break; - } - if ((*output->funcs->get_crtc)(output) == crtc) - current_outputs |= (1<<o); - } - - /* - * If mappings are different or the CRTC is unused, - * we need to disable it - */ - if (desired_outputs != current_outputs || - !desired_outputs) - (*crtc->funcs->dpms)(crtc, DPMSModeOff); -#else - (*crtc->funcs->dpms)(crtc, DPMSModeOff); -#endif - } -} - -/* - * Using the desired mode information in each crtc, set - * modes (used in EnterVT functions, or at server startup) - */ - -Bool -xf86SetDesiredModes (ScrnInfoPtr scrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - xf86CrtcPtr crtc = config->crtc[0]; - int c; - - /* A driver with this hook will take care of this */ - if (!crtc->funcs->set_mode_major) { - xf86PrepareOutputs(scrn); - xf86PrepareCrtcs(scrn); - } - - for (c = 0; c < config->num_crtc; c++) - { - xf86OutputPtr output = NULL; - int o; - RRTransformPtr transform; - - crtc = config->crtc[c]; - - /* Skip disabled CRTCs */ - if (!crtc->enabled) - continue; - - if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc) - output = xf86CompatOutput(scrn); - else - { - for (o = 0; o < config->num_output; o++) - if (config->output[o]->crtc == crtc) - { - output = config->output[o]; - break; - } - } - /* paranoia */ - if (!output) - continue; - - /* Mark that we'll need to re-set the mode for sure */ - memset(&crtc->mode, 0, sizeof(crtc->mode)); - if (!crtc->desiredMode.CrtcHDisplay) - { - DisplayModePtr mode = xf86OutputFindClosestMode (output, scrn->currentMode); - - if (!mode) - return FALSE; - crtc->desiredMode = *mode; - crtc->desiredRotation = RR_Rotate_0; - crtc->desiredTransformPresent = FALSE; - crtc->desiredX = 0; - crtc->desiredY = 0; - } - - if (crtc->desiredTransformPresent) - transform = &crtc->desiredTransform; - else - transform = NULL; - if (!xf86CrtcSetModeTransform (crtc, &crtc->desiredMode, crtc->desiredRotation, - transform, crtc->desiredX, crtc->desiredY)) - return FALSE; - } - - xf86DisableUnusedFunctions(scrn); - return TRUE; -} - -/** - * In the current world order, there are lists of modes per output, which may - * or may not include the mode that was asked to be set by XFree86's mode - * selection. Find the closest one, in the following preference order: - * - * - Equality - * - Closer in size to the requested mode, but no larger - * - Closer in refresh rate to the requested mode. - */ - -DisplayModePtr -xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired) -{ - DisplayModePtr best = NULL, scan = NULL; - - for (scan = output->probed_modes; scan != NULL; scan = scan->next) - { - /* If there's an exact match, we're done. */ - if (xf86ModesEqual(scan, desired)) { - best = desired; - break; - } - - /* Reject if it's larger than the desired mode. */ - if (scan->HDisplay > desired->HDisplay || - scan->VDisplay > desired->VDisplay) - { - continue; - } - - /* - * If we haven't picked a best mode yet, use the first - * one in the size range - */ - if (best == NULL) - { - best = scan; - continue; - } - - /* Find if it's closer to the right size than the current best - * option. - */ - if ((scan->HDisplay > best->HDisplay && - scan->VDisplay >= best->VDisplay) || - (scan->HDisplay >= best->HDisplay && - scan->VDisplay > best->VDisplay)) - { - best = scan; - continue; - } - - /* Find if it's still closer to the right refresh than the current - * best resolution. - */ - if (scan->HDisplay == best->HDisplay && - scan->VDisplay == best->VDisplay && - (fabs(scan->VRefresh - desired->VRefresh) < - fabs(best->VRefresh - desired->VRefresh))) { - best = scan; - } - } - return best; -} - -/** - * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, - * take the specified mode and apply it to the crtc connected to the compat - * output. Then, find similar modes for the other outputs, as with the - * InitialConfiguration code above. The goal is to clone the desired - * mode across all outputs that are currently active. - */ - -Bool -xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - Bool ok = TRUE; - xf86OutputPtr compat_output; - DisplayModePtr compat_mode = NULL; - int c; - - /* - * Let the compat output drive the final mode selection - */ - compat_output = xf86CompatOutput(pScrn); - if (compat_output) - compat_mode = xf86OutputFindClosestMode (compat_output, desired); - if (compat_mode) - desired = compat_mode; - - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - DisplayModePtr crtc_mode = NULL; - int o; - - if (!crtc->enabled) - continue; - - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - DisplayModePtr output_mode; - - /* skip outputs not on this crtc */ - if (output->crtc != crtc) - continue; - - if (crtc_mode) - { - output_mode = xf86OutputFindClosestMode (output, crtc_mode); - if (output_mode != crtc_mode) - output->crtc = NULL; - } - else - crtc_mode = xf86OutputFindClosestMode (output, desired); - } - if (!crtc_mode) - { - crtc->enabled = FALSE; - continue; - } - if (!xf86CrtcSetModeTransform (crtc, crtc_mode, rotation, NULL, 0, 0)) - ok = FALSE; - else - { - crtc->desiredMode = *crtc_mode; - crtc->desiredRotation = rotation; - crtc->desiredTransformPresent = FALSE; - crtc->desiredX = 0; - crtc->desiredY = 0; - } - } - xf86DisableUnusedFunctions(pScrn); -#ifdef RANDR_12_INTERFACE - xf86RandR12TellChanged (pScrn->pScreen); -#endif - return ok; -} - - -/** - * Set the DPMS power mode of all outputs and CRTCs. - * - * If the new mode is off, it will turn off outputs and then CRTCs. - * Otherwise, it will affect CRTCs before outputs. - */ -void -xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int i; - - if (!scrn->vtSema) - return; - - if (mode == DPMSModeOff) { - for (i = 0; i < config->num_output; i++) { - xf86OutputPtr output = config->output[i]; - if (output->crtc != NULL) - (*output->funcs->dpms) (output, mode); - } - } - - for (i = 0; i < config->num_crtc; i++) { - xf86CrtcPtr crtc = config->crtc[i]; - if (crtc->enabled) - (*crtc->funcs->dpms) (crtc, mode); - } - - if (mode != DPMSModeOff) { - for (i = 0; i < config->num_output; i++) { - xf86OutputPtr output = config->output[i]; - if (output->crtc != NULL) - (*output->funcs->dpms) (output, mode); - } - } -} - -/** - * Implement the screensaver by just calling down into the driver DPMS hooks. - * - * Even for monitors with no DPMS support, by the definition of our DPMS hooks, - * the outputs will still get disabled (blanked). - */ -Bool -xf86SaveScreen(ScreenPtr pScreen, int mode) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - - if (xf86IsUnblank(mode)) - xf86DPMSSet(pScrn, DPMSModeOn, 0); - else - xf86DPMSSet(pScrn, DPMSModeOff, 0); - - return TRUE; -} - -/** - * Disable all inactive crtcs and outputs - */ -void -xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) -{ - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int o, c; - - for (o = 0; o < xf86_config->num_output; o++) - { - xf86OutputPtr output = xf86_config->output[o]; - if (!output->crtc) - (*output->funcs->dpms)(output, DPMSModeOff); - } - - for (c = 0; c < xf86_config->num_crtc; c++) - { - xf86CrtcPtr crtc = xf86_config->crtc[c]; - - if (!crtc->enabled) - { - crtc->funcs->dpms(crtc, DPMSModeOff); - memset(&crtc->mode, 0, sizeof(crtc->mode)); - xf86RotateDestroy(crtc); - crtc->active = FALSE; - } - } - if (pScrn->pScreen) - xf86_crtc_notify(pScrn->pScreen); -} - -#ifdef RANDR_12_INTERFACE - -#define EDID_ATOM_NAME "EDID" - -/** - * Set the RandR EDID property - */ -static void -xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) -{ - Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); - - /* This may get called before the RandR resources have been created */ - if (output->randr_output == NULL) - return; - - if (data_len != 0) { - RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, - PropModeReplace, data_len, data, FALSE, TRUE); - } else { - RRDeleteOutputProperty(output->randr_output, edid_atom); - } -} - -#endif - -/* Pull out a phyiscal size from a detailed timing if available. */ -struct det_phySize_parameter { - xf86OutputPtr output; - ddc_quirk_t quirks; - Bool ret; -}; - -static void handle_detailed_physical_size(struct detailed_monitor_section - *det_mon, void *data) -{ - struct det_phySize_parameter *p; - p = (struct det_phySize_parameter *)data; - - if (p->ret == TRUE ) - return ; - - xf86DetTimingApplyQuirks(det_mon, p->quirks, - p->output->MonInfo->features.hsize, - p->output->MonInfo->features.vsize); - if (det_mon->type == DT && - det_mon->section.d_timings.h_size != 0 && - det_mon->section.d_timings.v_size != 0) { - - p->output->mm_width = det_mon->section.d_timings.h_size; - p->output->mm_height = det_mon->section.d_timings.v_size; - p->ret = TRUE; - } -} - -/** - * Set the EDID information for the specified output - */ -void -xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) -{ - ScrnInfoPtr scrn = output->scrn; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - Bool debug_modes = config->debug_modes || xf86Initialising; -#ifdef RANDR_12_INTERFACE - int size; -#endif - - if (output->MonInfo != NULL) - xfree(output->MonInfo); - - output->MonInfo = edid_mon; - - if (debug_modes) { - xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", - output->name); - xf86PrintEDID(edid_mon); - } - - /* Set the DDC properties for the 'compat' output */ - if (output == xf86CompatOutput(scrn)) - xf86SetDDCproperties(scrn, edid_mon); - -#ifdef RANDR_12_INTERFACE - /* Set the RandR output properties */ - size = 0; - if (edid_mon) - { - if (edid_mon->ver.version == 1) { - size = 128; - if (edid_mon->flags & EDID_COMPLETE_RAWDATA) - size += edid_mon->no_sections * 128; - } else if (edid_mon->ver.version == 2) - size = 256; - } - xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); -#endif - - if (edid_mon) { - - struct det_phySize_parameter p; - p.output = output; - p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex,edid_mon, FALSE); - p.ret = FALSE; - xf86ForEachDetailedBlock(edid_mon, - handle_detailed_physical_size, &p); - - /* if no mm size is available from a detailed timing, check the max size field */ - if ((!output->mm_width || !output->mm_height) && - (edid_mon->features.hsize && edid_mon->features.vsize)) - { - output->mm_width = edid_mon->features.hsize * 10; - output->mm_height = edid_mon->features.vsize * 10; - } - } -} - -/** - * Return the list of modes supported by the EDID information - * stored in 'output' - */ -DisplayModePtr -xf86OutputGetEDIDModes (xf86OutputPtr output) -{ - ScrnInfoPtr scrn = output->scrn; - xf86MonPtr edid_mon = output->MonInfo; - - if (!edid_mon) - return NULL; - return xf86DDCGetModes(scrn->scrnIndex, edid_mon); -} - -/* maybe we should care about DDC1? meh. */ -xf86MonPtr -xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) -{ - ScrnInfoPtr scrn = output->scrn; - xf86MonPtr mon; - - mon = xf86DoEEDID(scrn->scrnIndex, pDDCBus, TRUE); - if (mon) - xf86DDCApplyQuirks(scrn->scrnIndex, mon); - - return mon; -} - -static char *_xf86ConnectorNames[] = { - "None", "VGA", "DVI-I", "DVI-D", - "DVI-A", "Composite", "S-Video", - "Component", "LFP", "Proprietary", - "HDMI", "DisplayPort", - }; -char * -xf86ConnectorGetName(xf86ConnectorType connector) -{ - return _xf86ConnectorNames[connector]; -} - -static void -x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) -{ - dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; - dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; - dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; - dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; - - if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) - dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; -} - -static void -x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) -{ - if (crtc->enabled) { - crtc_box->x1 = crtc->x; - crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); - crtc_box->y1 = crtc->y; - crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); - } else - crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; -} - -static int -xf86_crtc_box_area(BoxPtr box) -{ - return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); -} - -/* - * Return the crtc covering 'box'. If two crtcs cover a portion of - * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc - * with greater coverage - */ - -static xf86CrtcPtr -xf86_covering_crtc(ScrnInfoPtr pScrn, - BoxPtr box, - xf86CrtcPtr desired, - BoxPtr crtc_box_ret) -{ - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - xf86CrtcPtr crtc, best_crtc; - int coverage, best_coverage; - int c; - BoxRec crtc_box, cover_box; - - best_crtc = NULL; - best_coverage = 0; - crtc_box_ret->x1 = 0; - crtc_box_ret->x2 = 0; - crtc_box_ret->y1 = 0; - crtc_box_ret->y2 = 0; - for (c = 0; c < xf86_config->num_crtc; c++) { - crtc = xf86_config->crtc[c]; - x86_crtc_box(crtc, &crtc_box); - x86_crtc_box_intersect(&cover_box, &crtc_box, box); - coverage = xf86_crtc_box_area(&cover_box); - if (coverage && crtc == desired) { - *crtc_box_ret = crtc_box; - return crtc; - } else if (coverage > best_coverage) { - *crtc_box_ret = crtc_box; - best_crtc = crtc; - best_coverage = coverage; - } - } - return best_crtc; -} - -/* - * For overlay video, compute the relevant CRTC and - * clip video to that. - * - * returning FALSE means there was a memory failure of some kind, - * not that the video shouldn't be displayed - */ - -Bool -xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, - xf86CrtcPtr *crtc_ret, - xf86CrtcPtr desired_crtc, - BoxPtr dst, - INT32 *xa, - INT32 *xb, - INT32 *ya, - INT32 *yb, - RegionPtr reg, - INT32 width, - INT32 height) -{ - Bool ret; - RegionRec crtc_region_local; - RegionPtr crtc_region = reg; - - if (crtc_ret) { - BoxRec crtc_box; - xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, - desired_crtc, - &crtc_box); - - if (crtc) { - REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1); - crtc_region = &crtc_region_local; - REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg); - } - *crtc_ret = crtc; - } - - ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, - crtc_region, width, height); - - if (crtc_region != reg) - REGION_UNINIT (pScreen, &crtc_region_local); - - return ret; -} - -xf86_crtc_notify_proc_ptr -xf86_wrap_crtc_notify (ScreenPtr screen, xf86_crtc_notify_proc_ptr new) -{ - if (xf86CrtcConfigPrivateIndex != -1) - { - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - xf86_crtc_notify_proc_ptr old; - - old = config->xf86_crtc_notify; - config->xf86_crtc_notify = new; - return old; - } - return NULL; -} - -void -xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old) -{ - if (xf86CrtcConfigPrivateIndex != -1) - { - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - - config->xf86_crtc_notify = old; - } -} - -void -xf86_crtc_notify(ScreenPtr screen) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - - if (config->xf86_crtc_notify) - config->xf86_crtc_notify(screen); -} - -Bool -xf86_crtc_supports_gamma(ScrnInfoPtr pScrn) -{ - if (xf86CrtcConfigPrivateIndex != -1) { - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - xf86CrtcPtr crtc; - - /* for multiple drivers loaded we need this */ - if (!xf86_config) - return FALSE; - if (xf86_config->num_crtc == 0) - return FALSE; - crtc = xf86_config->crtc[0]; - - return (crtc->funcs->gamma_set != NULL); - } - - return FALSE; -} +/* + * Copyright © 2006 Keith Packard + * Copyright © 2008 Red Hat, Inc. + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xf86DDC.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "xf86Priv.h" +#include "xf86RandR12.h" +#include "X11/extensions/render.h" +#include "X11/extensions/dpmsconst.h" +#include "X11/Xatom.h" +#include "picturestr.h" + +#include "xf86xv.h" + +/* + * Initialize xf86CrtcConfig structure + */ + +int xf86CrtcConfigPrivateIndex = -1; + +void +xf86CrtcConfigInit (ScrnInfoPtr scrn, + const xf86CrtcConfigFuncsRec *funcs) +{ + xf86CrtcConfigPtr config; + + if (xf86CrtcConfigPrivateIndex == -1) + xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + config = xnfcalloc (1, sizeof (xf86CrtcConfigRec)); + + config->funcs = funcs; + + scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config; +} + +void +xf86CrtcSetSizeRange (ScrnInfoPtr scrn, + int minWidth, int minHeight, + int maxWidth, int maxHeight) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + config->minWidth = minWidth; + config->minHeight = minHeight; + config->maxWidth = maxWidth; + config->maxHeight = maxHeight; +} + +/* + * Crtc functions + */ +xf86CrtcPtr +xf86CrtcCreate (ScrnInfoPtr scrn, + const xf86CrtcFuncsRec *funcs) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CrtcPtr crtc, *crtcs; + + crtc = calloc(sizeof (xf86CrtcRec), 1); + if (!crtc) + return NULL; + crtc->version = XF86_CRTC_VERSION; + crtc->scrn = scrn; + crtc->funcs = funcs; +#ifdef RANDR_12_INTERFACE + crtc->randr_crtc = NULL; +#endif + crtc->rotation = RR_Rotate_0; + crtc->desiredRotation = RR_Rotate_0; + pixman_transform_init_identity (&crtc->crtc_to_framebuffer); + pixman_f_transform_init_identity (&crtc->f_crtc_to_framebuffer); + pixman_f_transform_init_identity (&crtc->f_framebuffer_to_crtc); + crtc->filter = NULL; + crtc->params = NULL; + crtc->nparams = 0; + crtc->filter_width = 0; + crtc->filter_height = 0; + crtc->transform_in_use = FALSE; + crtc->transformPresent = FALSE; + crtc->desiredTransformPresent = FALSE; + memset (&crtc->bounds, '\0', sizeof (crtc->bounds)); + + /* Preallocate gamma at a sensible size. */ + crtc->gamma_size = 256; + crtc->gamma_red = malloc(3 * crtc->gamma_size * sizeof (CARD16)); + if (!crtc->gamma_red) { + free(crtc); + return NULL; + } + crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; + crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; + + if (xf86_config->crtc) + crtcs = realloc(xf86_config->crtc, + (xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + else + crtcs = malloc((xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + if (!crtcs) + { + free(crtc); + return NULL; + } + xf86_config->crtc = crtcs; + xf86_config->crtc[xf86_config->num_crtc++] = crtc; + return crtc; +} + +void +xf86CrtcDestroy (xf86CrtcPtr crtc) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + int c; + + (*crtc->funcs->destroy) (crtc); + for (c = 0; c < xf86_config->num_crtc; c++) + if (xf86_config->crtc[c] == crtc) + { + memmove (&xf86_config->crtc[c], + &xf86_config->crtc[c+1], + ((xf86_config->num_crtc - (c + 1)) * sizeof(void*))); + xf86_config->num_crtc--; + break; + } + if (crtc->params) + free(crtc->params); + free(crtc->gamma_red); + free(crtc); +} + + +/** + * Return whether any outputs are connected to the specified pipe + */ + +Bool +xf86CrtcInUse (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int o; + + for (o = 0; o < xf86_config->num_output; o++) + if (xf86_config->output[o]->crtc == crtc) + return TRUE; + return FALSE; +} + +void +xf86CrtcSetScreenSubpixelOrder (ScreenPtr pScreen) +{ + int subpixel_order = SubPixelUnknown; + Bool has_none = FALSE; + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + for (o = 0; o < xf86_config->num_output; o++) + { + xf86OutputPtr output = xf86_config->output[o]; + + if (output->crtc == crtc) + { + switch (output->subpixel_order) { + case SubPixelNone: + has_none = TRUE; + break; + case SubPixelUnknown: + break; + default: + subpixel_order = output->subpixel_order; + break; + } + } + if (subpixel_order != SubPixelUnknown) + break; + } + if (subpixel_order != SubPixelUnknown) + { + static const int circle[4] = { + SubPixelHorizontalRGB, + SubPixelVerticalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalBGR, + }; + int rotate; + int c; + for (rotate = 0; rotate < 4; rotate++) + if (crtc->rotation & (1 << rotate)) + break; + for (c = 0; c < 4; c++) + if (circle[c] == subpixel_order) + break; + c = (c + rotate) & 0x3; + if ((crtc->rotation & RR_Reflect_X) && !(c & 1)) + c ^= 2; + if ((crtc->rotation & RR_Reflect_Y) && (c & 1)) + c ^= 2; + subpixel_order = circle[c]; + break; + } + } + if (subpixel_order == SubPixelUnknown && has_none) + subpixel_order = SubPixelNone; + PictureSetSubpixelOrder (pScreen, subpixel_order); +} + +/** + * Sets the given video mode on the given crtc + */ +Bool +xf86CrtcSetModeTransform (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, + RRTransformPtr transform, int x, int y) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int i; + Bool ret = FALSE; + Bool didLock = FALSE; + DisplayModePtr adjusted_mode; + DisplayModeRec saved_mode; + int saved_x, saved_y; + Rotation saved_rotation; + RRTransformRec saved_transform; + Bool saved_transform_present; + + crtc->enabled = xf86CrtcInUse (crtc); + + /* We only hit this if someone explicitly sends a "disabled" modeset. */ + if (!crtc->enabled) + { + /* Check everything for stuff that should be off. */ + xf86DisableUnusedFunctions(scrn); + return TRUE; + } + + adjusted_mode = xf86DuplicateMode(mode); + + + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + saved_rotation = crtc->rotation; + if (crtc->transformPresent) { + RRTransformInit (&saved_transform); + RRTransformCopy (&saved_transform, &crtc->transform); + } + saved_transform_present = crtc->transformPresent; + + /* Update crtc values up front so the driver can rely on them for mode + * setting. + */ + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + crtc->rotation = rotation; + if (transform) { + RRTransformCopy (&crtc->transform, transform); + crtc->transformPresent = TRUE; + } else + crtc->transformPresent = FALSE; + + if (crtc->funcs->set_mode_major) { + ret = crtc->funcs->set_mode_major(crtc, mode, rotation, x, y); + goto done; + } + + didLock = crtc->funcs->lock (crtc); + /* Pass our mode to the outputs and the CRTC to give them a chance to + * adjust it according to limitations or output properties, and also + * a chance to reject the mode entirely. + */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { + goto done; + } + } + + if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { + goto done; + } + + if (!xf86CrtcRotate (crtc)) + goto done; + + /* Prepare the outputs and CRTCs before setting the mode. */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + /* Disable the output as the first thing we do. */ + output->funcs->prepare(output); + } + + crtc->funcs->prepare(crtc); + + /* Set up the DPLL and any output state that needs to adjust or depend + * on the DPLL. + */ + crtc->funcs->mode_set(crtc, mode, adjusted_mode, crtc->x, crtc->y); + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc) + output->funcs->mode_set(output, mode, adjusted_mode); + } + + /* Only upload when needed, to avoid unneeded delays. */ + if (!crtc->active && crtc->funcs->gamma_set) + crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, + crtc->gamma_blue, crtc->gamma_size); + + /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ + crtc->funcs->commit(crtc); + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc) + output->funcs->commit(output); + } + + ret = TRUE; + +done: + if (ret) { + crtc->active = TRUE; + if (scrn->pScreen) + xf86CrtcSetScreenSubpixelOrder (scrn->pScreen); + } else { + crtc->x = saved_x; + crtc->y = saved_y; + crtc->rotation = saved_rotation; + crtc->mode = saved_mode; + if (saved_transform_present) + RRTransformCopy (&crtc->transform, &saved_transform); + crtc->transformPresent = saved_transform_present; + } + + if (adjusted_mode->name) + free(adjusted_mode->name); + free(adjusted_mode); + + if (didLock) + crtc->funcs->unlock (crtc); + + return ret; +} + +/** + * Sets the given video mode on the given crtc, but without providing + * a transform + */ +Bool +xf86CrtcSetMode (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, + int x, int y) +{ + return xf86CrtcSetModeTransform (crtc, mode, rotation, NULL, x, y); +} + +/** + * Pans the screen, does not change the mode + */ +void +xf86CrtcSetOrigin (xf86CrtcPtr crtc, int x, int y) +{ + crtc->x = x; + crtc->y = y; + if (crtc->funcs->set_origin) { + if (!xf86CrtcRotate (crtc)) + return; + crtc->funcs->set_origin (crtc, x, y); + } + else + xf86CrtcSetMode (crtc, &crtc->mode, crtc->rotation, x, y); +} + +/* + * Output functions + */ + +extern XF86ConfigPtr xf86configptr; + +typedef enum { + OPTION_PREFERRED_MODE, + OPTION_POSITION, + OPTION_BELOW, + OPTION_RIGHT_OF, + OPTION_ABOVE, + OPTION_LEFT_OF, + OPTION_ENABLE, + OPTION_DISABLE, + OPTION_MIN_CLOCK, + OPTION_MAX_CLOCK, + OPTION_IGNORE, + OPTION_ROTATE, + OPTION_PANNING, + OPTION_PRIMARY, +} OutputOpts; + +static OptionInfoRec xf86OutputOptions[] = { + {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE }, + {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE }, + {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE }, + {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE }, + {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE }, + {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE }, + {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE }, + {OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE }, + {OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +enum { + OPTION_MODEDEBUG, +}; + +static OptionInfoRec xf86DeviceOptions[] = { + {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +static void +xf86OutputSetMonitor (xf86OutputPtr output) +{ + char *option_name; + static const char monitor_prefix[] = "monitor-"; + char *monitor; + + if (!output->name) + return; + + if (output->options) + free(output->options); + + output->options = xnfalloc (sizeof (xf86OutputOptions)); + memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions)); + + option_name = xnfalloc (strlen (monitor_prefix) + + strlen (output->name) + 1); + strcpy (option_name, monitor_prefix); + strcat (option_name, output->name); + monitor = xf86findOptionValue (output->scrn->options, option_name); + if (!monitor) + monitor = output->name; + else + xf86MarkOptionUsedByName (output->scrn->options, option_name); + free(option_name); + output->conf_monitor = xf86findMonitor (monitor, + xf86configptr->conf_monitor_lst); + /* + * Find the monitor section of the screen and use that + */ + if (!output->conf_monitor && output->use_screen_monitor) + output->conf_monitor = xf86findMonitor (output->scrn->monitor->id, + xf86configptr->conf_monitor_lst); + if (output->conf_monitor) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s using monitor section %s\n", + output->name, output->conf_monitor->mon_identifier); + xf86ProcessOptions (output->scrn->scrnIndex, + output->conf_monitor->mon_option_lst, + output->options); + } + else + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s has no monitor section\n", + output->name); +} + +static Bool +xf86OutputEnabled (xf86OutputPtr output, Bool strict) +{ + Bool enable, disable; + + /* check to see if this output was enabled in the config file */ + if (xf86GetOptValBool (output->options, OPTION_ENABLE, &enable) && enable) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s enabled by config file\n", output->name); + return TRUE; + } + /* or if this output was disabled in the config file */ + if (xf86GetOptValBool (output->options, OPTION_DISABLE, &disable) && disable) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s disabled by config file\n", output->name); + return FALSE; + } + + /* If not, try to only light up the ones we know are connected */ + if (strict) { + enable = output->status == XF86OutputStatusConnected; + } + /* But if that fails, try to light up even outputs we're unsure of */ + else { + enable = output->status != XF86OutputStatusDisconnected; + } + + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s %sconnected\n", output->name, enable ? "" : "dis"); + return enable; +} + +static Bool +xf86OutputIgnored (xf86OutputPtr output) +{ + return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE); +} + +static char *direction[4] = { + "normal", + "left", + "inverted", + "right" +}; + +static Rotation +xf86OutputInitialRotation (xf86OutputPtr output) +{ + char *rotate_name = xf86GetOptValString (output->options, + OPTION_ROTATE); + int i; + + if (!rotate_name) + return RR_Rotate_0; + + for (i = 0; i < 4; i++) + if (xf86nameCompare (direction[i], rotate_name) == 0) + return (1 << i); + return RR_Rotate_0; +} + +xf86OutputPtr +xf86OutputCreate (ScrnInfoPtr scrn, + const xf86OutputFuncsRec *funcs, + const char *name) +{ + xf86OutputPtr output, *outputs; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int len; + Bool primary; + + if (name) + len = strlen (name) + 1; + else + len = 0; + + output = calloc(sizeof (xf86OutputRec) + len, 1); + if (!output) + return NULL; + output->scrn = scrn; + output->funcs = funcs; + if (name) + { + output->name = (char *) (output + 1); + strcpy (output->name, name); + } + output->subpixel_order = SubPixelUnknown; + /* + * Use the old per-screen monitor section for the first output + */ + output->use_screen_monitor = (xf86_config->num_output == 0); +#ifdef RANDR_12_INTERFACE + output->randr_output = NULL; +#endif + if (name) + { + xf86OutputSetMonitor (output); + if (xf86OutputIgnored (output)) + { + free(output); + return FALSE; + } + } + + + if (xf86_config->output) + outputs = realloc(xf86_config->output, + (xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + else + outputs = malloc((xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + if (!outputs) + { + free(output); + return NULL; + } + + xf86_config->output = outputs; + + if (xf86GetOptValBool (output->options, OPTION_PRIMARY, &primary) && primary) + { + memmove(xf86_config->output + 1, xf86_config->output, + xf86_config->num_output * sizeof (xf86OutputPtr)); + xf86_config->output[0] = output; + } + else + { + xf86_config->output[xf86_config->num_output] = output; + } + + xf86_config->num_output++; + + return output; +} + +Bool +xf86OutputRename (xf86OutputPtr output, const char *name) +{ + int len = strlen(name) + 1; + char *newname = malloc(len); + + if (!newname) + return FALSE; /* so sorry... */ + + strcpy (newname, name); + if (output->name && output->name != (char *) (output + 1)) + free(output->name); + output->name = newname; + xf86OutputSetMonitor (output); + if (xf86OutputIgnored (output)) + return FALSE; + return TRUE; +} + +void +xf86OutputUseScreenMonitor (xf86OutputPtr output, Bool use_screen_monitor) +{ + if (use_screen_monitor != output->use_screen_monitor) + { + output->use_screen_monitor = use_screen_monitor; + xf86OutputSetMonitor (output); + } +} + +void +xf86OutputDestroy (xf86OutputPtr output) +{ + ScrnInfoPtr scrn = output->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + (*output->funcs->destroy) (output); + while (output->probed_modes) + xf86DeleteMode (&output->probed_modes, output->probed_modes); + for (o = 0; o < xf86_config->num_output; o++) + if (xf86_config->output[o] == output) + { + memmove (&xf86_config->output[o], + &xf86_config->output[o+1], + ((xf86_config->num_output - (o + 1)) * sizeof(void*))); + xf86_config->num_output--; + break; + } + if (output->name && output->name != (char *) (output + 1)) + free(output->name); + free(output); +} + +/* + * Called during CreateScreenResources to hook up RandR + */ +static Bool +xf86CrtcCreateScreenResources (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + screen->CreateScreenResources = config->CreateScreenResources; + + if (!(*screen->CreateScreenResources)(screen)) + return FALSE; + + if (!xf86RandR12CreateScreenResources (screen)) + return FALSE; + + return TRUE; +} + +/* + * Clean up config on server reset + */ +static Bool +xf86CrtcCloseScreen (int index, ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o, c; + + screen->CloseScreen = config->CloseScreen; + + xf86RotateCloseScreen (screen); + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->randr_output = NULL; + } + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->randr_crtc = NULL; + } + return screen->CloseScreen (index, screen); +} + +/* + * Called at ScreenInit time to set up + */ +#ifdef RANDR_13_INTERFACE +int +#else +Bool +#endif +xf86CrtcScreenInit (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + /* Rotation */ + xf86DrvMsg(scrn->scrnIndex, X_INFO, "RandR 1.2 enabled, ignore the following RandR disabled message.\n"); + xf86DisableRandR(); /* Disable old RandR extension support */ + xf86RandR12Init (screen); + + /* support all rotations if every crtc has the shadow alloc funcs */ + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create) + break; + } + if (c == config->num_crtc) + { + xf86RandR12SetRotations (screen, RR_Rotate_0 | RR_Rotate_90 | + RR_Rotate_180 | RR_Rotate_270 | + RR_Reflect_X | RR_Reflect_Y); + xf86RandR12SetTransformSupport (screen, TRUE); + } + else + { + xf86RandR12SetRotations (screen, RR_Rotate_0); + xf86RandR12SetTransformSupport (screen, FALSE); + } + + /* Wrap CreateScreenResources so we can initialize the RandR code */ + config->CreateScreenResources = screen->CreateScreenResources; + screen->CreateScreenResources = xf86CrtcCreateScreenResources; + + config->CloseScreen = screen->CloseScreen; + screen->CloseScreen = xf86CrtcCloseScreen; + +#ifdef XFreeXDGA + _xf86_di_dga_init_internal(screen); +#endif +#ifdef RANDR_13_INTERFACE + return RANDR_INTERFACE_VERSION; +#else + return TRUE; +#endif +} + +static DisplayModePtr +xf86DefaultMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + int target_preferred = 0; + int mm_height; + + mm_height = output->mm_height; + if (!mm_height) + mm_height = (768 * 25.4) / DEFAULT_DPI; + /* + * Pick a mode closest to DEFAULT_DPI + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dpi; + int preferred = (((mode->type & M_T_PREFERRED) != 0) + + ((mode->type & M_T_USERPREF) != 0)); + int diff; + + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + /* yes, use VDisplay here, not xf86ModeHeight */ + dpi = (mode->VDisplay * 254) / (mm_height * 10); + diff = dpi - DEFAULT_DPI; + diff = diff < 0 ? -diff : diff; + if (target_mode == NULL || (preferred > target_preferred) || + (preferred == target_preferred && diff < target_diff)) + { + target_mode = mode; + target_diff = diff; + target_preferred = preferred; + } + } + return target_mode; +} + +static DisplayModePtr +xf86ClosestMode (xf86OutputPtr output, + DisplayModePtr match, Rotation match_rotation, + int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + + /* + * Pick a mode closest to the specified mode + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dx, dy; + int diff; + + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + /* exact matches are preferred */ + if (output->initial_rotation == match_rotation && + xf86ModesEqual (mode, match)) + return mode; + + dx = xf86ModeWidth (match, match_rotation) - xf86ModeWidth (mode, output->initial_rotation); + dy = xf86ModeHeight (match, match_rotation) - xf86ModeHeight (mode, output->initial_rotation); + diff = dx * dx + dy * dy; + if (target_mode == NULL || diff < target_diff) + { + target_mode = mode; + target_diff = diff; + } + } + return target_mode; +} + +static DisplayModePtr +xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr mode; + + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + if (mode->type & M_T_PREFERRED) + return mode; + } + return NULL; +} + +static DisplayModePtr +xf86OutputHasUserPreferredMode (xf86OutputPtr output) +{ + DisplayModePtr mode, first = output->probed_modes; + + for (mode = first; mode && mode->next != first; mode = mode->next) + if (mode->type & M_T_USERPREF) + return mode; + + return NULL; +} + +static int +xf86PickCrtcs (ScrnInfoPtr scrn, + xf86CrtcPtr *best_crtcs, + DisplayModePtr *modes, + int n, + int width, + int height) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + xf86OutputPtr output; + xf86CrtcPtr crtc; + xf86CrtcPtr *crtcs; + xf86CrtcPtr best_crtc; + int best_score; + int score; + int my_score; + + if (n == config->num_output) + return 0; + output = config->output[n]; + + /* + * Compute score with this output disabled + */ + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = xf86PickCrtcs (scrn, best_crtcs, modes, n+1, width, height); + if (modes[n] == NULL) + return best_score; + + crtcs = malloc(config->num_output * sizeof (xf86CrtcPtr)); + if (!crtcs) + return best_score; + + my_score = 1; + /* Score outputs that are known to be connected higher */ + if (output->status == XF86OutputStatusConnected) + my_score++; + /* Score outputs with preferred modes higher */ + if (xf86OutputHasPreferredMode (output, width, height)) + my_score++; + /* + * Select a crtc for this output and + * then attempt to configure the remaining + * outputs + */ + for (c = 0; c < config->num_crtc; c++) + { + if ((output->possible_crtcs & (1 << c)) == 0) + continue; + + crtc = config->crtc[c]; + /* + * Check to see if some other output is + * using this crtc + */ + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; + if (o < n) + { + /* + * If the two outputs desire the same mode, + * see if they can be cloned + */ + if (xf86ModesEqual (modes[o], modes[n]) && + config->output[o]->initial_rotation == config->output[n]->initial_rotation && + config->output[o]->initial_x == config->output[n]->initial_x && + config->output[o]->initial_y == config->output[n]->initial_y) + { + if ((output->possible_clones & (1 << o)) == 0) + continue; /* nope, try next CRTC */ + } + else + continue; /* different modes, can't clone */ + } + crtcs[n] = crtc; + memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); + score = my_score + xf86PickCrtcs (scrn, crtcs, modes, n+1, width, height); + if (score > best_score) + { + best_crtc = crtc; + best_score = score; + memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr)); + } + } + free(crtcs); + return best_score; +} + + +/* + * Compute the virtual size necessary to place all of the available + * crtcs in the specified configuration. + * + * canGrow indicates that the driver can make the screen larger than its initial + * configuration. If FALSE, this function will enlarge the screen to include + * the largest available mode. + */ + +static void +xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp, + Bool canGrow) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int width = 0, height = 0; + int o; + int c; + int s; + + for (c = 0; c < config->num_crtc; c++) + { + int crtc_width = 0, crtc_height = 0; + xf86CrtcPtr crtc = config->crtc[c]; + + if (crtc->enabled) + { + crtc_width = crtc->x + xf86ModeWidth (&crtc->desiredMode, crtc->desiredRotation); + crtc_height = crtc->y + xf86ModeHeight (&crtc->desiredMode, crtc->desiredRotation); + } + if (!canGrow) { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + for (s = 0; s < config->num_crtc; s++) + if (output->possible_crtcs & (1 << s)) + { + DisplayModePtr mode; + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (mode->HDisplay > crtc_width) + crtc_width = mode->HDisplay; + if (mode->VDisplay > crtc_width) + crtc_width = mode->VDisplay; + if (mode->VDisplay > crtc_height) + crtc_height = mode->VDisplay; + if (mode->HDisplay > crtc_height) + crtc_height = mode->HDisplay; + } + } + } + } + if (crtc_width > width) + width = crtc_width; + if (crtc_height > height) + height = crtc_height; + } + if (config->maxWidth && width > config->maxWidth) width = config->maxWidth; + if (config->maxHeight && height > config->maxHeight) height = config->maxHeight; + if (config->minWidth && width < config->minWidth) width = config->minWidth; + if (config->minHeight && height < config->minHeight) height = config->minHeight; + *widthp = width; + *heightp = height; +} + +#define POSITION_UNSET -100000 + +/* + * check if the user configured any outputs at all + * with either a position or a relative setting or a mode. + */ +static Bool +xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr *modes) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + Bool user_conf = FALSE; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + char *position; + char *relative_name; + OutputOpts relation; + int r; + static const OutputOpts relations[] = { + OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF + }; + + position = xf86GetOptValString (output->options, + OPTION_POSITION); + if (position) + user_conf = TRUE; + + relation = 0; + relative_name = NULL; + for (r = 0; r < 4; r++) + { + relation = relations[r]; + relative_name = xf86GetOptValString (output->options, + relation); + if (relative_name) + break; + } + if (relative_name) + user_conf = TRUE; + + modes[o] = xf86OutputHasUserPreferredMode(output); + if (modes[o]) + user_conf = TRUE; + } + + return user_conf; +} + +static Bool +xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + int min_x, min_y; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x = output->initial_y = POSITION_UNSET; + } + + /* + * Loop until all outputs are set + */ + for (;;) + { + Bool any_set = FALSE; + Bool keep_going = FALSE; + + for (o = 0; o < config->num_output; o++) + { + static const OutputOpts relations[] = { + OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF + }; + xf86OutputPtr output = config->output[o]; + xf86OutputPtr relative; + char *relative_name; + char *position; + OutputOpts relation; + int r; + + if (output->initial_x != POSITION_UNSET) + continue; + position = xf86GetOptValString (output->options, + OPTION_POSITION); + /* + * Absolute position wins + */ + if (position) + { + int x, y; + if (sscanf (position, "%d %d", &x, &y) == 2) + { + output->initial_x = x; + output->initial_y = y; + } + else + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output %s position not of form \"x y\"\n", + output->name); + output->initial_x = output->initial_y = 0; + } + any_set = TRUE; + continue; + } + /* + * Next comes relative positions + */ + relation = 0; + relative_name = NULL; + for (r = 0; r < 4; r++) + { + relation = relations[r]; + relative_name = xf86GetOptValString (output->options, + relation); + if (relative_name) + break; + } + if (relative_name) + { + int or; + relative = NULL; + for (or = 0; or < config->num_output; or++) + { + xf86OutputPtr out_rel = config->output[or]; + XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; + + if (rel_mon) + { + if (xf86nameCompare (rel_mon->mon_identifier, + relative_name) == 0) + { + relative = config->output[or]; + break; + } + } + if (strcmp (out_rel->name, relative_name) == 0) + { + relative = config->output[or]; + break; + } + } + if (!relative) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Cannot position output %s relative to unknown output %s\n", + output->name, relative_name); + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + continue; + } + if (!modes[or]) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Cannot position output %s relative to output %s without modes\n", + output->name, relative_name); + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + continue; + } + if (relative->initial_x == POSITION_UNSET) + { + keep_going = TRUE; + continue; + } + output->initial_x = relative->initial_x; + output->initial_y = relative->initial_y; + switch (relation) { + case OPTION_BELOW: + output->initial_y += xf86ModeHeight (modes[or], relative->initial_rotation); + break; + case OPTION_RIGHT_OF: + output->initial_x += xf86ModeWidth (modes[or], relative->initial_rotation); + break; + case OPTION_ABOVE: + if (modes[o]) + output->initial_y -= xf86ModeHeight (modes[o], output->initial_rotation); + break; + case OPTION_LEFT_OF: + if (modes[o]) + output->initial_x -= xf86ModeWidth (modes[o], output->initial_rotation); + break; + default: + break; + } + any_set = TRUE; + continue; + } + + /* Nothing set, just stick them at 0,0 */ + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + } + if (!keep_going) + break; + if (!any_set) + { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + if (output->initial_x == POSITION_UNSET) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output position loop. Moving %s to 0,0\n", + output->name); + output->initial_x = output->initial_y = 0; + break; + } + } + } + } + + /* + * normalize positions + */ + min_x = 1000000; + min_y = 1000000; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (output->initial_x < min_x) + min_x = output->initial_x; + if (output->initial_y < min_y) + min_y = output->initial_y; + } + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x -= min_x; + output->initial_y -= min_y; + } + return TRUE; +} + +static void +xf86InitialPanning (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + char *panning = xf86GetOptValString (output->options, OPTION_PANNING); + int width, height, left, top; + int track_width, track_height, track_left, track_top; + int brdr[4]; + + memset (&output->initialTotalArea, 0, sizeof(BoxRec)); + memset (&output->initialTrackingArea, 0, sizeof(BoxRec)); + memset (output->initialBorder, 0, 4*sizeof(INT16)); + + if (! panning) + continue; + + switch (sscanf (panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", + &width, &height, &left, &top, + &track_width, &track_height, &track_left, &track_top, + &brdr[0], &brdr[1], &brdr[2], &brdr[3])) { + case 12: + output->initialBorder[0] = brdr[0]; + output->initialBorder[1] = brdr[1]; + output->initialBorder[2] = brdr[2]; + output->initialBorder[3] = brdr[3]; + /* fall through */ + case 8: + output->initialTrackingArea.x1 = track_left; + output->initialTrackingArea.y1 = track_top; + output->initialTrackingArea.x2 = track_left + track_width; + output->initialTrackingArea.y2 = track_top + track_height; + /* fall through */ + case 4: + output->initialTotalArea.x1 = left; + output->initialTotalArea.y1 = top; + /* fall through */ + case 2: + output->initialTotalArea.x2 = output->initialTotalArea.x1 + width; + output->initialTotalArea.y2 = output->initialTotalArea.y1 + height; + break; + default: + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Broken panning specification '%s' for output %s in config file\n", + panning, output->name); + } + } +} + +/** Return - 0 + if a should be earlier, same or later than b in list + */ +static int +xf86ModeCompare (DisplayModePtr a, DisplayModePtr b) +{ + int diff; + + diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); + if (diff) + return diff; + diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; + if (diff) + return diff; + diff = b->Clock - a->Clock; + return diff; +} + +/** + * Insertion sort input in-place and return the resulting head + */ +static DisplayModePtr +xf86SortModes (DisplayModePtr input) +{ + DisplayModePtr output = NULL, i, o, n, *op, prev; + + /* sort by preferred status and pixel area */ + while (input) + { + i = input; + input = input->next; + for (op = &output; (o = *op); op = &o->next) + if (xf86ModeCompare (o, i) > 0) + break; + i->next = *op; + *op = i; + } + /* prune identical modes */ + for (o = output; o && (n = o->next); o = n) + { + if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n)) + { + o->next = n->next; + free(n->name); + free(n); + n = o; + } + } + /* hook up backward links */ + prev = NULL; + for (o = output; o; o = o->next) + { + o->prev = prev; + prev = o; + } + return output; +} + +static char * +preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + char *preferred_mode = NULL; + + /* Check for a configured preference for a particular mode */ + preferred_mode = xf86GetOptValString (output->options, + OPTION_PREFERRED_MODE); + if (preferred_mode) + return preferred_mode; + + if (pScrn->display->modes && *pScrn->display->modes) + preferred_mode = *pScrn->display->modes; + + return preferred_mode; +} + +static void +GuessRangeFromModes(MonPtr mon, DisplayModePtr mode) +{ + if (!mon || !mode) + return; + + mon->nHsync = 1; + mon->hsync[0].lo = 1024.0; + mon->hsync[0].hi = 0.0; + + mon->nVrefresh = 1; + mon->vrefresh[0].lo = 1024.0; + mon->vrefresh[0].hi = 0.0; + + while (mode) { + if (!mode->HSync) + mode->HSync = ((float) mode->Clock ) / ((float) mode->HTotal); + + if (!mode->VRefresh) + mode->VRefresh = (1000.0 * ((float) mode->Clock)) / + ((float) (mode->HTotal * mode->VTotal)); + + if (mode->HSync < mon->hsync[0].lo) + mon->hsync[0].lo = mode->HSync; + + if (mode->HSync > mon->hsync[0].hi) + mon->hsync[0].hi = mode->HSync; + + if (mode->VRefresh < mon->vrefresh[0].lo) + mon->vrefresh[0].lo = mode->VRefresh; + + if (mode->VRefresh > mon->vrefresh[0].hi) + mon->vrefresh[0].hi = mode->VRefresh; + + mode = mode->next; + } + + /* stretch out the bottom to fit 640x480@60 */ + if (mon->hsync[0].lo > 31.0) + mon->hsync[0].lo = 31.0; + if (mon->vrefresh[0].lo > 58.0) + mon->vrefresh[0].lo = 58.0; +} + +enum det_monrec_source { + sync_config, sync_edid, sync_default +}; + +struct det_monrec_parameter { + MonRec *mon_rec; + int *max_clock; + Bool set_hsync; + Bool set_vrefresh; + enum det_monrec_source *sync_source; +}; + +static void handle_detailed_monrec(struct detailed_monitor_section *det_mon, + void *data) +{ + enum { sync_config, sync_edid, sync_default }; + struct det_monrec_parameter *p; + p = (struct det_monrec_parameter *)data; + + if (det_mon->type == DS_RANGES) { + struct monitor_ranges *ranges = &det_mon->section.ranges; + if (p->set_hsync && ranges->max_h) { + p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h; + p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h; + p->mon_rec->nHsync++; + if (*p->sync_source == sync_default) + *p->sync_source = sync_edid; + } + if (p->set_vrefresh && ranges->max_v) { + p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v; + p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v; + p->mon_rec->nVrefresh++; + if (*p->sync_source == sync_default) + *p->sync_source = sync_edid; + } + if (ranges->max_clock * 1000 > *p->max_clock) + *p->max_clock = ranges->max_clock * 1000; + } +} + +void +xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + /* When canGrow was TRUE in the initial configuration we have to + * compare against the maximum values so that we don't drop modes. + * When canGrow was FALSE, the maximum values would have been clamped + * anyway. + */ + if (maxX == 0 || maxY == 0) { + maxX = config->maxWidth; + maxY = config->maxHeight; + } + + /* Probe the list of modes for each output. */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode; + DisplayModePtr config_modes = NULL, output_modes, default_modes = NULL; + char *preferred_mode; + xf86MonPtr edid_monitor; + XF86ConfMonitorPtr conf_monitor; + MonRec mon_rec; + int min_clock = 0; + int max_clock = 0; + double clock; + Bool add_default_modes = TRUE; + Bool debug_modes = config->debug_modes || + xf86Initialising; + enum det_monrec_source sync_source = sync_default; + + while (output->probed_modes != NULL) + xf86DeleteMode(&output->probed_modes, output->probed_modes); + + /* + * Check connection status + */ + output->status = (*output->funcs->detect)(output); + + if (output->status == XF86OutputStatusDisconnected && + !xf86ReturnOptValBool(output->options, OPTION_ENABLE, FALSE)) + { + xf86OutputSetEDID (output, NULL); + continue; + } + + memset (&mon_rec, '\0', sizeof (mon_rec)); + + conf_monitor = output->conf_monitor; + + if (conf_monitor) + { + int i; + + for (i = 0; i < conf_monitor->mon_n_hsync; i++) + { + mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo; + mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi; + mon_rec.nHsync++; + sync_source = sync_config; + } + for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) + { + mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo; + mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi; + mon_rec.nVrefresh++; + sync_source = sync_config; + } + config_modes = xf86GetMonitorModes (scrn, conf_monitor); + } + + output_modes = (*output->funcs->get_modes) (output); + + edid_monitor = output->MonInfo; + + if (edid_monitor) + { + struct det_monrec_parameter p; + struct disp_features *features = &edid_monitor->features; + + /* if display is not continuous-frequency, don't add default modes */ + if (!GTF_SUPPORTED(features->msc)) + add_default_modes = FALSE; + + p.mon_rec = &mon_rec; + p.max_clock = &max_clock; + p.set_hsync = mon_rec.nHsync == 0; + p.set_vrefresh = mon_rec.nVrefresh == 0; + p.sync_source = &sync_source; + + xf86ForEachDetailedBlock(edid_monitor, + handle_detailed_monrec, + &p); + } + + if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK, + OPTUNITS_KHZ, &clock)) + min_clock = (int) clock; + if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK, + OPTUNITS_KHZ, &clock)) + max_clock = (int) clock; + + /* If we still don't have a sync range, guess wildly */ + if (!mon_rec.nHsync || !mon_rec.nVrefresh) + GuessRangeFromModes(&mon_rec, output_modes); + + /* + * These limits will end up setting a 1024x768@60Hz mode by default, + * which seems like a fairly good mode to use when nothing else is + * specified + */ + if (mon_rec.nHsync == 0) + { + mon_rec.hsync[0].lo = 31.0; + mon_rec.hsync[0].hi = 55.0; + mon_rec.nHsync = 1; + } + if (mon_rec.nVrefresh == 0) + { + mon_rec.vrefresh[0].lo = 58.0; + mon_rec.vrefresh[0].hi = 62.0; + mon_rec.nVrefresh = 1; + } + + if (add_default_modes) + default_modes = xf86GetDefaultModes (); + + /* + * If this is not an RB monitor, remove RB modes from the default + * pool. RB modes from the config or the monitor itself are fine. + */ + if (!mon_rec.reducedblanking) + xf86ValidateModesReducedBlanking (scrn, default_modes); + + if (sync_source == sync_config) + { + /* + * Check output and config modes against sync range from config file + */ + xf86ValidateModesSync (scrn, output_modes, &mon_rec); + xf86ValidateModesSync (scrn, config_modes, &mon_rec); + } + /* + * Check default modes against sync range + */ + xf86ValidateModesSync (scrn, default_modes, &mon_rec); + /* + * Check default modes against monitor max clock + */ + if (max_clock) { + xf86ValidateModesClocks(scrn, default_modes, + &min_clock, &max_clock, 1); + xf86ValidateModesClocks(scrn, output_modes, + &min_clock, &max_clock, 1); + } + + output->probed_modes = NULL; + output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes); + + /* + * Check all modes against max size, interlace, and doublescan + */ + if (maxX && maxY) + xf86ValidateModesSize (scrn, output->probed_modes, + maxX, maxY, 0); + + { + int flags = (output->interlaceAllowed ? V_INTERLACE : 0) | + (output->doubleScanAllowed ? V_DBLSCAN : 0); + xf86ValidateModesFlags (scrn, output->probed_modes, flags); + } + + /* + * Check all modes against output + */ + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + if (mode->status == MODE_OK) + mode->status = (*output->funcs->mode_valid)(output, mode); + + xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes); + + output->probed_modes = xf86SortModes (output->probed_modes); + + /* Check for a configured preference for a particular mode */ + preferred_mode = preferredMode(scrn, output); + + if (preferred_mode) + { + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (!strcmp (preferred_mode, mode->name)) + { + if (mode != output->probed_modes) + { + if (mode->prev) + mode->prev->next = mode->next; + if (mode->next) + mode->next->prev = mode->prev; + mode->next = output->probed_modes; + output->probed_modes->prev = mode; + mode->prev = NULL; + output->probed_modes = mode; + } + mode->type |= (M_T_PREFERRED|M_T_USERPREF); + break; + } + } + } + + output->initial_rotation = xf86OutputInitialRotation (output); + + if (debug_modes) { + if (output->probed_modes != NULL) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Printing probed modes for output %s\n", + output->name); + } else { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "No remaining probed modes for output %s\n", + output->name); + } + } + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + { + /* The code to choose the best mode per pipe later on will require + * VRefresh to be set. + */ + mode->VRefresh = xf86ModeVRefresh(mode); + xf86SetModeCrtc(mode, INTERLACE_HALVE_V); + + if (debug_modes) + xf86PrintModeline(scrn->scrnIndex, mode); + } + } +} + + +/** + * Copy one of the output mode lists to the ScrnInfo record + */ + +/* XXX where does this function belong? Here? */ +void +xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y); + +static DisplayModePtr +biggestMode(DisplayModePtr a, DisplayModePtr b) +{ + int A, B; + + if (!a) + return b; + if (!b) + return a; + + A = a->HDisplay * a->VDisplay; + B = b->HDisplay * b->VDisplay; + + if (A > B) + return a; + + return b; +} + +static xf86OutputPtr +SetCompatOutput(xf86CrtcConfigPtr config) +{ + xf86OutputPtr output = NULL, test = NULL; + DisplayModePtr maxmode = NULL, testmode, mode; + int o, compat = -1, count, mincount = 0; + + /* Look for one that's definitely connected */ + for (o = 0; o < config->num_output; o++) + { + test = config->output[o]; + if (!test->crtc) + continue; + if (test->status != XF86OutputStatusConnected) + continue; + if (!test->probed_modes) + continue; + + testmode = mode = test->probed_modes; + for (count = 0; mode; mode = mode->next, count++) + testmode = biggestMode(testmode, mode); + + if (!output) { + output = test; + compat = o; + maxmode = testmode; + mincount = count; + } else if (maxmode == biggestMode(maxmode, testmode)) { + output = test; + compat = o; + maxmode = testmode; + mincount = count; + } else if ((maxmode->HDisplay == testmode->HDisplay) && + (maxmode->VDisplay == testmode->VDisplay) && + count <= mincount) { + output = test; + compat = o; + maxmode = testmode; + mincount = count; + } + } + + /* If we didn't find one, take anything we can get */ + if (!output) + { + for (o = 0; o < config->num_output; o++) + { + test = config->output[o]; + if (!test->crtc) + continue; + if (!test->probed_modes) + continue; + + if (!output) { + output = test; + compat = o; + } else if (test->probed_modes->HDisplay < output->probed_modes->HDisplay) { + output = test; + compat = o; + } + } + } + + if (compat >= 0) { + config->compat_output = compat; + } else { + /* Don't change the compat output when no valid outputs found */ + output = config->output[config->compat_output]; + } + + return output; +} + +void +xf86SetScrnInfoModes (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + DisplayModePtr last, mode = NULL; + + output = SetCompatOutput(config); + + if (!output) + return; /* punt */ + + crtc = output->crtc; + + /* Clear any existing modes from scrn->modes */ + while (scrn->modes != NULL) + xf86DeleteMode(&scrn->modes, scrn->modes); + + /* Set scrn->modes to the mode list for the 'compat' output */ + scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); + + if (crtc) { + for (mode = scrn->modes; mode; mode = mode->next) + if (xf86ModesEqual (mode, &crtc->desiredMode)) + break; + } + + if (scrn->modes != NULL) { + /* For some reason, scrn->modes is circular, unlike the other mode + * lists. How great is that? + */ + for (last = scrn->modes; last && last->next; last = last->next) + ; + last->next = scrn->modes; + scrn->modes->prev = last; + if (mode) { + while (scrn->modes != mode) + scrn->modes = scrn->modes->next; + } + } + scrn->currentMode = scrn->modes; +#ifdef XFreeXDGA + if (scrn->pScreen) + _xf86_di_dga_reinit_internal(scrn->pScreen); +#endif +} + +static void +xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + Bool *enabled) +{ + Bool any_enabled = FALSE; + int o; + + for (o = 0; o < config->num_output; o++) + any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE); + + if (!any_enabled) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "No outputs definitely connected, trying again...\n"); + + for (o = 0; o < config->num_output; o++) + enabled[o] = xf86OutputEnabled(config->output[o], FALSE); + } +} + +static Bool +nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index) +{ + int o = *index; + + for (o++; o < config->num_output; o++) { + if (enabled[o]) { + *index = o; + return TRUE; + } + } + + return FALSE; +} + +static Bool +aspectMatch(float a, float b) +{ + return fabs(1 - (a / b)) < 0.05; +} + +static DisplayModePtr +nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect) +{ + DisplayModePtr m = NULL; + + if (!o) + return NULL; + + if (!last) + m = o->probed_modes; + else + m = last->next; + + for (; m; m = m->next) + if (aspectMatch(aspect, (float)m->HDisplay / (float)m->VDisplay)) + return m; + + return NULL; +} + +static DisplayModePtr +bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect) +{ + int o = -1, p; + DisplayModePtr mode = NULL, test = NULL, match = NULL; + + if (!nextEnabledOutput(config, enabled, &o)) + return NULL; + while ((mode = nextAspectMode(config->output[o], mode, aspect))) { + test = mode; + for (p = o; nextEnabledOutput(config, enabled, &p); ) { + test = xf86OutputFindClosestMode(config->output[p], mode); + if (!test) + break; + if (test->HDisplay != mode->HDisplay || + test->VDisplay != mode->VDisplay) { + test = NULL; + break; + } + } + + /* if we didn't match it on all outputs, try the next one */ + if (!test) + continue; + + /* if it's bigger than the last one, save it */ + if (!match || (test->HDisplay > match->HDisplay)) + match = test; + } + + /* return the biggest one found */ + return match; +} + +static Bool +xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + DisplayModePtr *modes, Bool *enabled, + int width, int height) +{ + int o, p; + int max_pref_width = 0, max_pref_height = 0; + DisplayModePtr *preferred, *preferred_match; + Bool ret = FALSE; + + preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); + preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); + + /* Check if the preferred mode is available on all outputs */ + for (p = -1; nextEnabledOutput(config, enabled, &p); ) { + Rotation r = config->output[p]->initial_rotation; + DisplayModePtr mode; + if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p], + width, height))) { + int pref_width = xf86ModeWidth(preferred[p], r); + int pref_height = xf86ModeHeight(preferred[p], r); + Bool all_match = TRUE; + + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + Bool match = FALSE; + xf86OutputPtr output = config->output[o]; + if (o == p) + continue; + + for (mode = output->probed_modes; mode; mode = mode->next) { + Rotation r = output->initial_rotation; + if (xf86ModeWidth(mode, r) == pref_width && + xf86ModeHeight(mode, r) == pref_height) { + preferred[o] = mode; + match = TRUE; + } + } + + all_match &= match; + } + + if (all_match && + (pref_width*pref_height > max_pref_width*max_pref_height)) { + for (o = -1; nextEnabledOutput(config, enabled, &o); ) + preferred_match[o] = preferred[o]; + max_pref_width = pref_width; + max_pref_height = pref_height; + ret = TRUE; + } + } + } + + /* + * If there's no preferred mode, but only one monitor, pick the + * biggest mode for its aspect ratio, assuming one exists. + */ + if (!ret) do { + int i = 0; + float aspect = 0.0; + + /* count the number of enabled outputs */ + for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ; + + if (i != 1) + break; + + p = -1; + nextEnabledOutput(config, enabled, &p); + if (config->output[p]->mm_height) + aspect = (float)config->output[p]->mm_width / + (float)config->output[p]->mm_height; + + if (aspect) + preferred_match[p] = bestModeForAspect(config, enabled, aspect); + + if (preferred_match[p]) + ret = TRUE; + + } while (0); + + if (ret) { + /* oh good, there is a match. stash the selected modes and return. */ + memcpy(modes, preferred_match, + config->num_output * sizeof(DisplayModePtr)); + } + + free(preferred); + free(preferred_match); + return ret; +} + +static Bool +xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + DisplayModePtr *modes, Bool *enabled, + int width, int height) +{ + int o; + float aspect = 0.0, *aspects; + xf86OutputPtr output; + Bool ret = FALSE; + DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL; + + aspects = xnfcalloc(config->num_output, sizeof(float)); + + /* collect the aspect ratios */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + output = config->output[o]; + if (output->mm_height) + aspects[o] = (float)output->mm_width / (float)output->mm_height; + else + aspects[o] = 4.0 / 3.0; + } + + /* check that they're all the same */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + output = config->output[o]; + if (!aspect) { + aspect = aspects[o]; + } else if (!aspectMatch(aspect, aspects[o])) { + goto no_aspect_match; + } + } + + /* if they're all 4:3, just skip ahead and save effort */ + if (!aspectMatch(aspect, 4.0/3.0)) + aspect_guess = bestModeForAspect(config, enabled, aspect); + +no_aspect_match: + base_guess = bestModeForAspect(config, enabled, 4.0/3.0); + + guess = biggestMode(base_guess, aspect_guess); + + if (!guess) + goto out; + + /* found a mode that works everywhere, now apply it */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + modes[o] = xf86OutputFindClosestMode(config->output[o], guess); + } + ret = TRUE; + +out: + free(aspects); + return ret; +} + +static Bool +xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + DisplayModePtr *modes, Bool *enabled, + int width, int height) +{ + DisplayModePtr target_mode = NULL; + Rotation target_rotation = RR_Rotate_0; + DisplayModePtr default_mode; + int default_preferred, target_preferred = 0, o; + + /* User preferred > preferred > other modes */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + default_mode = xf86DefaultMode (config->output[o], width, height); + if (!default_mode) + continue; + + default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) + + ((default_mode->type & M_T_USERPREF) != 0)); + + if (default_preferred > target_preferred || !target_mode) { + target_mode = default_mode; + target_preferred = default_preferred; + target_rotation = config->output[o]->initial_rotation; + config->compat_output = o; + } + } + + if (target_mode) + modes[config->compat_output] = target_mode; + + /* Fill in other output modes */ + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + if (!modes[o]) + modes[o] = xf86ClosestMode(config->output[o], target_mode, + target_rotation, width, height); + } + + return (target_mode != NULL); +} + +static Bool +xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, + DisplayModePtr *modes, Bool *enabled, + int width, int height) +{ + int o; + + if (xf86UserConfiguredOutputs(scrn, modes)) + return xf86TargetFallback(scrn, config, modes, enabled, width, height); + + for (o = -1; nextEnabledOutput(config, enabled, &o); ) + if (xf86OutputHasUserPreferredMode(config->output[o])) + return + xf86TargetFallback(scrn, config, modes, enabled, width, height); + + return FALSE; +} + +static Bool +xf86CrtcSetInitialGamma(xf86CrtcPtr crtc, float gamma_red, float gamma_green, + float gamma_blue) +{ + int i, size = 256; + CARD16 *red, *green, *blue; + + red = malloc(3 * size * sizeof(CARD16)); + green = red + size; + blue = green + size; + + /* Only cause warning if user wanted gamma to be set. */ + if (!crtc->funcs->gamma_set && (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0)) { + free(red); + return FALSE; + } else if (!crtc->funcs->gamma_set) { + free(red); + return TRUE; + } + + /* At this early stage none of the randr-interface stuff is up. + * So take the default gamma size for lack of something better. + */ + for (i = 0; i < size; i++) { + if (gamma_red == 1.0) + red[i] = i << 8; + else + red[i] = (CARD16)(pow((double)i/(double)(size - 1), + 1. / (double)gamma_red) * (double)(size - 1) * 256); + + if (gamma_green == 1.0) + green[i] = i << 8; + else + green[i] = (CARD16)(pow((double)i/(double)(size - 1), + 1. / (double)gamma_green) * (double)(size - 1) * 256); + + if (gamma_blue == 1.0) + blue[i] = i << 8; + else + blue[i] = (CARD16)(pow((double)i/(double)(size - 1), + 1. / (double)gamma_blue) * (double)(size - 1) * 256); + } + + /* Default size is 256, so anything else is failure. */ + if (size != crtc->gamma_size) { + free(red); + return FALSE; + } + + crtc->gamma_size = size; + memcpy (crtc->gamma_red, red, crtc->gamma_size * sizeof (CARD16)); + memcpy (crtc->gamma_green, green, crtc->gamma_size * sizeof (CARD16)); + memcpy (crtc->gamma_blue, blue, crtc->gamma_size * sizeof (CARD16)); + + /* Do not set gamma now, delay until the crtc is activated. */ + + free(red); + + return TRUE; +} + +static Bool +xf86OutputSetInitialGamma(xf86OutputPtr output) +{ + XF86ConfMonitorPtr mon = output->conf_monitor; + float gamma_red = 1.0, gamma_green = 1.0, gamma_blue = 1.0; + + if (!mon) + return TRUE; + + if (!output->crtc) + return FALSE; + + /* Get configured values, where they exist. */ + if (mon->mon_gamma_red >= GAMMA_MIN && + mon->mon_gamma_red <= GAMMA_MAX) + gamma_red = mon->mon_gamma_red; + + if (mon->mon_gamma_green >= GAMMA_MIN && + mon->mon_gamma_green <= GAMMA_MAX) + gamma_green = mon->mon_gamma_green; + + if (mon->mon_gamma_blue >= GAMMA_MIN && + mon->mon_gamma_blue <= GAMMA_MAX) + gamma_blue = mon->mon_gamma_blue; + + /* This avoids setting gamma 1.0 in case another cloned output on this crtc has a specific gamma. */ + if (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0) { + xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Output %s wants gamma correction (%.1f, %.1f, %.1f)\n", output->name, gamma_red, gamma_green, gamma_blue); + return xf86CrtcSetInitialGamma(output->crtc, gamma_red, gamma_green, gamma_blue); + }else + return TRUE; +} + +/** + * Construct default screen configuration + * + * Given auto-detected (and, eventually, configured) values, + * construct a usable configuration for the system + * + * canGrow indicates that the driver can resize the screen to larger than its + * initially configured size via the config->funcs->resize hook. If TRUE, this + * function will set virtualX and virtualY to match the initial configuration + * and leave config->max{Width,Height} alone. If FALSE, it will bloat + * virtual[XY] to include the largest modes and set config->max{Width,Height} + * accordingly. + */ + +Bool +xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o, c; + xf86CrtcPtr *crtcs; + DisplayModePtr *modes; + Bool *enabled; + int width, height; + int i = scrn->scrnIndex; + + /* Set up the device options */ + config->options = xnfalloc (sizeof (xf86DeviceOptions)); + memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions)); + xf86ProcessOptions (scrn->scrnIndex, + scrn->options, + config->options); + config->debug_modes = xf86ReturnOptValBool (config->options, + OPTION_MODEDEBUG, FALSE); + + if (scrn->display->virtualX) + width = scrn->display->virtualX; + else + width = config->maxWidth; + if (scrn->display->virtualY) + height = scrn->display->virtualY; + else + height = config->maxHeight; + + xf86ProbeOutputModes (scrn, width, height); + + crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); + modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); + enabled = xnfcalloc (config->num_output, sizeof (Bool)); + + xf86CollectEnabledOutputs(scrn, config, enabled); + + if (xf86TargetUserpref(scrn, config, modes, enabled, width, height)) + xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n"); + else if (xf86TargetPreferred(scrn, config, modes, enabled, width, height)) + xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n"); + else if (xf86TargetAspect(scrn, config, modes, enabled, width, height)) + xf86DrvMsg(i, X_INFO, "Using fuzzy aspect match for initial modes\n"); + else if (xf86TargetFallback(scrn, config, modes, enabled, width, height)) + xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n"); + else + xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n"); + + for (o = -1; nextEnabledOutput(config, enabled, &o); ) { + if (!modes[o]) + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output %s enabled but has no modes\n", + config->output[o]->name); + else + xf86DrvMsg (scrn->scrnIndex, X_INFO, + "Output %s using initial mode %s\n", + config->output[o]->name, modes[o]->name); + } + + /* + * Set the position of each output + */ + if (!xf86InitialOutputPositions (scrn, modes)) + { + free(crtcs); + free(modes); + return FALSE; + } + + /* + * Set initial panning of each output + */ + xf86InitialPanning (scrn); + + /* + * Assign CRTCs to fit output configuration + */ + if (!xf86PickCrtcs (scrn, crtcs, modes, 0, width, height)) + { + free(crtcs); + free(modes); + return FALSE; + } + + /* XXX override xf86 common frame computation code */ + + scrn->display->frameX0 = 0; + scrn->display->frameY0 = 0; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->enabled = FALSE; + memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); + /* Set default gamma for all crtc's. */ + /* This is done to avoid problems later on with cloned outputs. */ + xf86CrtcSetInitialGamma(crtc, 1.0, 1.0, 1.0); + } + + if (xf86_crtc_supports_gamma(scrn)) + xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using default gamma of (1.0, 1.0, 1.0) unless otherwise stated.\n"); + + /* + * Set initial configuration + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode = modes[o]; + xf86CrtcPtr crtc = crtcs[o]; + + if (mode && crtc) + { + crtc->desiredMode = *mode; + crtc->desiredRotation = output->initial_rotation; + crtc->desiredX = output->initial_x; + crtc->desiredY = output->initial_y; + crtc->desiredTransformPresent = FALSE; + crtc->enabled = TRUE; + memcpy (&crtc->panningTotalArea, &output->initialTotalArea, sizeof(BoxRec)); + memcpy (&crtc->panningTrackingArea, &output->initialTrackingArea, sizeof(BoxRec)); + memcpy (crtc->panningBorder, output->initialBorder, 4*sizeof(INT16)); + output->crtc = crtc; + if (!xf86OutputSetInitialGamma(output)) + xf86DrvMsg (scrn->scrnIndex, X_WARNING, "Initial gamma correction for output %s: failed.\n", output->name); + } else { + output->crtc = NULL; + } + } + + if (scrn->display->virtualX == 0) + { + /* + * Expand virtual size to cover the current config and potential mode + * switches, if the driver can't enlarge the screen later. + */ + xf86DefaultScreenLimits (scrn, &width, &height, canGrow); + + scrn->display->virtualX = width; + scrn->display->virtualY = height; + } + + if (width > scrn->virtualX) + scrn->virtualX = width; + if (height > scrn->virtualY) + scrn->virtualY = height; + + /* + * Make sure the configuration isn't too small. + */ + if (width < config->minWidth || height < config->minHeight) + return FALSE; + + /* + * Limit the crtc config to virtual[XY] if the driver can't grow the + * desktop. + */ + if (!canGrow) + { + xf86CrtcSetSizeRange (scrn, config->minWidth, config->minHeight, + width, height); + } + + /* Mirror output modes to scrn mode list */ + xf86SetScrnInfoModes (scrn); + + free(crtcs); + free(modes); + return TRUE; +} + +/* + * Check the CRTC we're going to map each output to vs. it's current + * CRTC. If they don't match, we have to disable the output and the CRTC + * since the driver will have to re-route things. + */ +static void +xf86PrepareOutputs (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + for (o = 0; o < config->num_output; o++) { + xf86OutputPtr output = config->output[o]; +#if RANDR_GET_CRTC_INTERFACE + /* Disable outputs that are unused or will be re-routed */ + if (!output->funcs->get_crtc || + output->crtc != (*output->funcs->get_crtc)(output) || + output->crtc == NULL) +#endif + (*output->funcs->dpms)(output, DPMSModeOff); + } +} + +static void +xf86PrepareCrtcs (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < config->num_crtc; c++) { +#if RANDR_GET_CRTC_INTERFACE + xf86CrtcPtr crtc = config->crtc[c]; + xf86OutputPtr output = NULL; + uint32_t desired_outputs = 0, current_outputs = 0; + int o; + + for (o = 0; o < config->num_output; o++) { + output = config->output[o]; + if (output->crtc == crtc) + desired_outputs |= (1<<o); + /* If we can't tell where it's mapped, force it off */ + if (!output->funcs->get_crtc) { + desired_outputs = 0; + break; + } + if ((*output->funcs->get_crtc)(output) == crtc) + current_outputs |= (1<<o); + } + + /* + * If mappings are different or the CRTC is unused, + * we need to disable it + */ + if (desired_outputs != current_outputs || + !desired_outputs) + (*crtc->funcs->dpms)(crtc, DPMSModeOff); +#else + (*crtc->funcs->dpms)(crtc, DPMSModeOff); +#endif + } +} + +/* + * Using the desired mode information in each crtc, set + * modes (used in EnterVT functions, or at server startup) + */ + +Bool +xf86SetDesiredModes (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CrtcPtr crtc = config->crtc[0]; + int c; + + /* A driver with this hook will take care of this */ + if (!crtc->funcs->set_mode_major) { + xf86PrepareOutputs(scrn); + xf86PrepareCrtcs(scrn); + } + + for (c = 0; c < config->num_crtc; c++) + { + xf86OutputPtr output = NULL; + int o; + RRTransformPtr transform; + + crtc = config->crtc[c]; + + /* Skip disabled CRTCs */ + if (!crtc->enabled) + continue; + + if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc) + output = xf86CompatOutput(scrn); + else + { + for (o = 0; o < config->num_output; o++) + if (config->output[o]->crtc == crtc) + { + output = config->output[o]; + break; + } + } + /* paranoia */ + if (!output) + continue; + + /* Mark that we'll need to re-set the mode for sure */ + memset(&crtc->mode, 0, sizeof(crtc->mode)); + if (!crtc->desiredMode.CrtcHDisplay) + { + DisplayModePtr mode = xf86OutputFindClosestMode (output, scrn->currentMode); + + if (!mode) + return FALSE; + crtc->desiredMode = *mode; + crtc->desiredRotation = RR_Rotate_0; + crtc->desiredTransformPresent = FALSE; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + + if (crtc->desiredTransformPresent) + transform = &crtc->desiredTransform; + else + transform = NULL; + if (!xf86CrtcSetModeTransform (crtc, &crtc->desiredMode, crtc->desiredRotation, + transform, crtc->desiredX, crtc->desiredY)) + return FALSE; + } + + xf86DisableUnusedFunctions(scrn); + return TRUE; +} + +/** + * In the current world order, there are lists of modes per output, which may + * or may not include the mode that was asked to be set by XFree86's mode + * selection. Find the closest one, in the following preference order: + * + * - Equality + * - Closer in size to the requested mode, but no larger + * - Closer in refresh rate to the requested mode. + */ + +DisplayModePtr +xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired) +{ + DisplayModePtr best = NULL, scan = NULL; + + for (scan = output->probed_modes; scan != NULL; scan = scan->next) + { + /* If there's an exact match, we're done. */ + if (xf86ModesEqual(scan, desired)) { + best = desired; + break; + } + + /* Reject if it's larger than the desired mode. */ + if (scan->HDisplay > desired->HDisplay || + scan->VDisplay > desired->VDisplay) + { + continue; + } + + /* + * If we haven't picked a best mode yet, use the first + * one in the size range + */ + if (best == NULL) + { + best = scan; + continue; + } + + /* Find if it's closer to the right size than the current best + * option. + */ + if ((scan->HDisplay > best->HDisplay && + scan->VDisplay >= best->VDisplay) || + (scan->HDisplay >= best->HDisplay && + scan->VDisplay > best->VDisplay)) + { + best = scan; + continue; + } + + /* Find if it's still closer to the right refresh than the current + * best resolution. + */ + if (scan->HDisplay == best->HDisplay && + scan->VDisplay == best->VDisplay && + (fabs(scan->VRefresh - desired->VRefresh) < + fabs(best->VRefresh - desired->VRefresh))) { + best = scan; + } + } + return best; +} + +/** + * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, + * take the specified mode and apply it to the crtc connected to the compat + * output. Then, find similar modes for the other outputs, as with the + * InitialConfiguration code above. The goal is to clone the desired + * mode across all outputs that are currently active. + */ + +Bool +xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + Bool ok = TRUE; + xf86OutputPtr compat_output; + DisplayModePtr compat_mode = NULL; + int c; + + /* + * Let the compat output drive the final mode selection + */ + compat_output = xf86CompatOutput(pScrn); + if (compat_output) + compat_mode = xf86OutputFindClosestMode (compat_output, desired); + if (compat_mode) + desired = compat_mode; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + DisplayModePtr crtc_mode = NULL; + int o; + + if (!crtc->enabled) + continue; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr output_mode; + + /* skip outputs not on this crtc */ + if (output->crtc != crtc) + continue; + + if (crtc_mode) + { + output_mode = xf86OutputFindClosestMode (output, crtc_mode); + if (output_mode != crtc_mode) + output->crtc = NULL; + } + else + crtc_mode = xf86OutputFindClosestMode (output, desired); + } + if (!crtc_mode) + { + crtc->enabled = FALSE; + continue; + } + if (!xf86CrtcSetModeTransform (crtc, crtc_mode, rotation, NULL, 0, 0)) + ok = FALSE; + else + { + crtc->desiredMode = *crtc_mode; + crtc->desiredRotation = rotation; + crtc->desiredTransformPresent = FALSE; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + } + xf86DisableUnusedFunctions(pScrn); +#ifdef RANDR_12_INTERFACE + xf86RandR12TellChanged (pScrn->pScreen); +#endif + return ok; +} + + +/** + * Set the DPMS power mode of all outputs and CRTCs. + * + * If the new mode is off, it will turn off outputs and then CRTCs. + * Otherwise, it will affect CRTCs before outputs. + */ +void +xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int i; + + if (!scrn->vtSema) + return; + + if (mode == DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } + + for (i = 0; i < config->num_crtc; i++) { + xf86CrtcPtr crtc = config->crtc[i]; + if (crtc->enabled) + (*crtc->funcs->dpms) (crtc, mode); + } + + if (mode != DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } +} + +/** + * Implement the screensaver by just calling down into the driver DPMS hooks. + * + * Even for monitors with no DPMS support, by the definition of our DPMS hooks, + * the outputs will still get disabled (blanked). + */ +Bool +xf86SaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (xf86IsUnblank(mode)) + xf86DPMSSet(pScrn, DPMSModeOn, 0); + else + xf86DPMSSet(pScrn, DPMSModeOff, 0); + + return TRUE; +} + +/** + * Disable all inactive crtcs and outputs + */ +void +xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int o, c; + + for (o = 0; o < xf86_config->num_output; o++) + { + xf86OutputPtr output = xf86_config->output[o]; + if (!output->crtc) + (*output->funcs->dpms)(output, DPMSModeOff); + } + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (!crtc->enabled) + { + crtc->funcs->dpms(crtc, DPMSModeOff); + memset(&crtc->mode, 0, sizeof(crtc->mode)); + xf86RotateDestroy(crtc); + crtc->active = FALSE; + } + } + if (pScrn->pScreen) + xf86_crtc_notify(pScrn->pScreen); +} + +#ifdef RANDR_12_INTERFACE + +#define EDID_ATOM_NAME "EDID" + +/** + * Set the RandR EDID property + */ +static void +xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) +{ + Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); + + /* This may get called before the RandR resources have been created */ + if (output->randr_output == NULL) + return; + + if (data_len != 0) { + RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, + PropModeReplace, data_len, data, FALSE, TRUE); + } else { + RRDeleteOutputProperty(output->randr_output, edid_atom); + } +} + +#endif + +/* Pull out a phyiscal size from a detailed timing if available. */ +struct det_phySize_parameter { + xf86OutputPtr output; + ddc_quirk_t quirks; + Bool ret; +}; + +static void handle_detailed_physical_size(struct detailed_monitor_section + *det_mon, void *data) +{ + struct det_phySize_parameter *p; + p = (struct det_phySize_parameter *)data; + + if (p->ret == TRUE ) + return ; + + xf86DetTimingApplyQuirks(det_mon, p->quirks, + p->output->MonInfo->features.hsize, + p->output->MonInfo->features.vsize); + if (det_mon->type == DT && + det_mon->section.d_timings.h_size != 0 && + det_mon->section.d_timings.v_size != 0) { + + p->output->mm_width = det_mon->section.d_timings.h_size; + p->output->mm_height = det_mon->section.d_timings.v_size; + p->ret = TRUE; + } +} + +/** + * Set the EDID information for the specified output + */ +void +xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) +{ + ScrnInfoPtr scrn = output->scrn; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + Bool debug_modes = config->debug_modes || xf86Initialising; +#ifdef RANDR_12_INTERFACE + int size; +#endif + + if (output->MonInfo != NULL) + free(output->MonInfo); + + output->MonInfo = edid_mon; + + if (debug_modes) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", + output->name); + xf86PrintEDID(edid_mon); + } + + /* Set the DDC properties for the 'compat' output */ + if (output == xf86CompatOutput(scrn)) + xf86SetDDCproperties(scrn, edid_mon); + +#ifdef RANDR_12_INTERFACE + /* Set the RandR output properties */ + size = 0; + if (edid_mon) + { + if (edid_mon->ver.version == 1) { + size = 128; + if (edid_mon->flags & EDID_COMPLETE_RAWDATA) + size += edid_mon->no_sections * 128; + } else if (edid_mon->ver.version == 2) + size = 256; + } + xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); +#endif + + if (edid_mon) { + + struct det_phySize_parameter p; + p.output = output; + p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex,edid_mon, FALSE); + p.ret = FALSE; + xf86ForEachDetailedBlock(edid_mon, + handle_detailed_physical_size, &p); + + /* if no mm size is available from a detailed timing, check the max size field */ + if ((!output->mm_width || !output->mm_height) && + (edid_mon->features.hsize && edid_mon->features.vsize)) + { + output->mm_width = edid_mon->features.hsize * 10; + output->mm_height = edid_mon->features.vsize * 10; + } + } +} + +/** + * Return the list of modes supported by the EDID information + * stored in 'output' + */ +DisplayModePtr +xf86OutputGetEDIDModes (xf86OutputPtr output) +{ + ScrnInfoPtr scrn = output->scrn; + xf86MonPtr edid_mon = output->MonInfo; + + if (!edid_mon) + return NULL; + return xf86DDCGetModes(scrn->scrnIndex, edid_mon); +} + +/* maybe we should care about DDC1? meh. */ +xf86MonPtr +xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) +{ + ScrnInfoPtr scrn = output->scrn; + xf86MonPtr mon; + + mon = xf86DoEEDID(scrn->scrnIndex, pDDCBus, TRUE); + if (mon) + xf86DDCApplyQuirks(scrn->scrnIndex, mon); + + return mon; +} + +static char *_xf86ConnectorNames[] = { + "None", "VGA", "DVI-I", "DVI-D", + "DVI-A", "Composite", "S-Video", + "Component", "LFP", "Proprietary", + "HDMI", "DisplayPort", + }; +char * +xf86ConnectorGetName(xf86ConnectorType connector) +{ + return _xf86ConnectorNames[connector]; +} + +static void +x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) +{ + dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; + dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; + dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; + dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; + + if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) + dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; +} + +static void +x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) +{ + if (crtc->enabled) { + crtc_box->x1 = crtc->x; + crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); + crtc_box->y1 = crtc->y; + crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); + } else + crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; +} + +static int +xf86_crtc_box_area(BoxPtr box) +{ + return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); +} + +/* + * Return the crtc covering 'box'. If two crtcs cover a portion of + * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc + * with greater coverage + */ + +static xf86CrtcPtr +xf86_covering_crtc(ScrnInfoPtr pScrn, + BoxPtr box, + xf86CrtcPtr desired, + BoxPtr crtc_box_ret) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc, best_crtc; + int coverage, best_coverage; + int c; + BoxRec crtc_box, cover_box; + + best_crtc = NULL; + best_coverage = 0; + crtc_box_ret->x1 = 0; + crtc_box_ret->x2 = 0; + crtc_box_ret->y1 = 0; + crtc_box_ret->y2 = 0; + for (c = 0; c < xf86_config->num_crtc; c++) { + crtc = xf86_config->crtc[c]; + x86_crtc_box(crtc, &crtc_box); + x86_crtc_box_intersect(&cover_box, &crtc_box, box); + coverage = xf86_crtc_box_area(&cover_box); + if (coverage && crtc == desired) { + *crtc_box_ret = crtc_box; + return crtc; + } else if (coverage > best_coverage) { + *crtc_box_ret = crtc_box; + best_crtc = crtc; + best_coverage = coverage; + } + } + return best_crtc; +} + +/* + * For overlay video, compute the relevant CRTC and + * clip video to that. + * + * returning FALSE means there was a memory failure of some kind, + * not that the video shouldn't be displayed + */ + +Bool +xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, + xf86CrtcPtr *crtc_ret, + xf86CrtcPtr desired_crtc, + BoxPtr dst, + INT32 *xa, + INT32 *xb, + INT32 *ya, + INT32 *yb, + RegionPtr reg, + INT32 width, + INT32 height) +{ + Bool ret; + RegionRec crtc_region_local; + RegionPtr crtc_region = reg; + + if (crtc_ret) { + BoxRec crtc_box; + xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, + desired_crtc, + &crtc_box); + + if (crtc) { + REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1); + crtc_region = &crtc_region_local; + REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg); + } + *crtc_ret = crtc; + } + + ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, + crtc_region, width, height); + + if (crtc_region != reg) + REGION_UNINIT (pScreen, &crtc_region_local); + + return ret; +} + +xf86_crtc_notify_proc_ptr +xf86_wrap_crtc_notify (ScreenPtr screen, xf86_crtc_notify_proc_ptr new) +{ + if (xf86CrtcConfigPrivateIndex != -1) + { + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + xf86_crtc_notify_proc_ptr old; + + old = config->xf86_crtc_notify; + config->xf86_crtc_notify = new; + return old; + } + return NULL; +} + +void +xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old) +{ + if (xf86CrtcConfigPrivateIndex != -1) + { + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + config->xf86_crtc_notify = old; + } +} + +void +xf86_crtc_notify(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + if (config->xf86_crtc_notify) + config->xf86_crtc_notify(screen); +} + +Bool +xf86_crtc_supports_gamma(ScrnInfoPtr pScrn) +{ + if (xf86CrtcConfigPrivateIndex != -1) { + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc; + + /* for multiple drivers loaded we need this */ + if (!xf86_config) + return FALSE; + if (xf86_config->num_crtc == 0) + return FALSE; + crtc = xf86_config->crtc[0]; + + return (crtc->funcs->gamma_set != NULL); + } + + return FALSE; +} diff --git a/xorg-server/hw/xfree86/modes/xf86Cursors.c b/xorg-server/hw/xfree86/modes/xf86Cursors.c index 3e765e6ff..e9770f8b9 100644 --- a/xorg-server/hw/xfree86/modes/xf86Cursors.c +++ b/xorg-server/hw/xfree86/modes/xf86Cursors.c @@ -551,7 +551,7 @@ xf86_cursors_init (ScreenPtr screen, int max_width, int max_height, int flags) if (!cursor_info) return FALSE; - xf86_config->cursor_image = xalloc (max_width * max_height * 4); + xf86_config->cursor_image = malloc(max_width * max_height * 4); if (!xf86_config->cursor_image) { @@ -661,7 +661,7 @@ xf86_cursors_fini (ScreenPtr screen) } if (xf86_config->cursor_image) { - xfree (xf86_config->cursor_image); + free(xf86_config->cursor_image); xf86_config->cursor_image = NULL; } if (xf86_config->cursor) diff --git a/xorg-server/hw/xfree86/modes/xf86DiDGA.c b/xorg-server/hw/xfree86/modes/xf86DiDGA.c index 60fbdbf05..61c779edc 100644 --- a/xorg-server/hw/xfree86/modes/xf86DiDGA.c +++ b/xorg-server/hw/xfree86/modes/xf86DiDGA.c @@ -1,218 +1,218 @@ -/* - * Copyright © 2006 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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_XORG_CONFIG_H -#include <xorg-config.h> -#else -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#endif - -#include "xf86.h" -#include "xf86DDC.h" -#include "xf86_OSproc.h" -#include "dgaproc.h" -#include "xf86Crtc.h" -#include "xf86Modes.h" -#include "gcstruct.h" -#include "scrnintstr.h" -#include "windowstr.h" - -static Bool -xf86_dga_get_modes (ScreenPtr pScreen) -{ - ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - DGAModePtr modes, mode; - DisplayModePtr display_mode; - int bpp = scrn->bitsPerPixel >> 3; - int num; - - num = 0; - display_mode = scrn->modes; - while (display_mode) - { - num++; - display_mode = display_mode->next; - if (display_mode == scrn->modes) - break; - } - - if (!num) - return FALSE; - - modes = xalloc(num * sizeof(DGAModeRec)); - if (!modes) - return FALSE; - - num = 0; - display_mode = scrn->modes; - while (display_mode) - { - mode = modes + num++; - - mode->mode = display_mode; - mode->flags = DGA_CONCURRENT_ACCESS; - if (display_mode->Flags & V_DBLSCAN) - mode->flags |= DGA_DOUBLESCAN; - if (display_mode->Flags & V_INTERLACE) - mode->flags |= DGA_INTERLACED; - mode->byteOrder = scrn->imageByteOrder; - mode->depth = scrn->depth; - mode->bitsPerPixel = scrn->bitsPerPixel; - mode->red_mask = scrn->mask.red; - mode->green_mask = scrn->mask.green; - mode->blue_mask = scrn->mask.blue; - mode->visualClass = (bpp == 1) ? PseudoColor : TrueColor; - mode->viewportWidth = display_mode->HDisplay; - mode->viewportHeight = display_mode->VDisplay; - mode->xViewportStep = (bpp == 3) ? 2 : 1; - mode->yViewportStep = 1; - mode->viewportFlags = DGA_FLIP_RETRACE; - mode->offset = 0; - mode->address = 0; - mode->imageWidth = mode->viewportWidth; - mode->imageHeight = mode->viewportHeight; - mode->bytesPerScanline = (mode->imageWidth * scrn->bitsPerPixel) >> 3; - mode->pixmapWidth = mode->imageWidth; - mode->pixmapHeight = mode->imageHeight; - mode->maxViewportX = 0; - mode->maxViewportY = 0; - - display_mode = display_mode->next; - if (display_mode == scrn->modes) - break; - } - if (xf86_config->dga_modes) - xfree (xf86_config->dga_modes); - xf86_config->dga_nmode = num; - xf86_config->dga_modes = modes; - return TRUE; -} - -static Bool -xf86_dga_set_mode(ScrnInfoPtr scrn, DGAModePtr display_mode) -{ - ScreenPtr pScreen = scrn->pScreen; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - - if (!display_mode) - { - if (xf86_config->dga_save_mode) - { - xf86SwitchMode(pScreen, xf86_config->dga_save_mode); - xf86_config->dga_save_mode = NULL; - } - } - else - { - if (!xf86_config->dga_save_mode) - { - xf86_config->dga_save_mode = scrn->currentMode; - xf86SwitchMode(pScreen, display_mode->mode); - } - } - return TRUE; -} - -static int -xf86_dga_get_viewport(ScrnInfoPtr scrn) -{ - return 0; -} - -static void -xf86_dga_set_viewport(ScrnInfoPtr scrn, int x, int y, int flags) -{ - scrn->AdjustFrame(scrn->pScreen->myNum, x, y, flags); -} - -static Bool -xf86_dga_open_framebuffer(ScrnInfoPtr scrn, - char **name, - unsigned char **mem, int *size, int *offset, int *flags) -{ - return FALSE; -} - -static void -xf86_dga_close_framebuffer(ScrnInfoPtr scrn) -{ -} - -static DGAFunctionRec xf86_dga_funcs = { - xf86_dga_open_framebuffer, - xf86_dga_close_framebuffer, - xf86_dga_set_mode, - xf86_dga_set_viewport, - xf86_dga_get_viewport, - NULL, - NULL, - NULL, - NULL -}; - -Bool -xf86DiDGAReInit (ScreenPtr pScreen) -{ - return TRUE; -} - -Bool -_xf86_di_dga_reinit_internal (ScreenPtr pScreen) -{ - ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - - if (!DGAAvailable(pScreen->myNum)) - return TRUE; - - if (!xf86_dga_get_modes (pScreen)) - return FALSE; - - return DGAReInitModes (pScreen, xf86_config->dga_modes, xf86_config->dga_nmode); -} - -Bool -xf86DiDGAInit (ScreenPtr pScreen, unsigned long dga_address) -{ - return TRUE; -} - -Bool -_xf86_di_dga_init_internal (ScreenPtr pScreen) -{ - ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - - xf86_config->dga_flags = 0; - xf86_config->dga_address = 0; - xf86_config->dga_width = 0; - xf86_config->dga_height = 0; - xf86_config->dga_stride = 0; - - if (!xf86_dga_get_modes (pScreen)) - return FALSE; - - return DGAInit(pScreen, &xf86_dga_funcs, xf86_config->dga_modes, xf86_config->dga_nmode); -} +/* + * Copyright © 2006 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "xf86DDC.h" +#include "xf86_OSproc.h" +#include "dgaproc.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "windowstr.h" + +static Bool +xf86_dga_get_modes (ScreenPtr pScreen) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + DGAModePtr modes, mode; + DisplayModePtr display_mode; + int bpp = scrn->bitsPerPixel >> 3; + int num; + + num = 0; + display_mode = scrn->modes; + while (display_mode) + { + num++; + display_mode = display_mode->next; + if (display_mode == scrn->modes) + break; + } + + if (!num) + return FALSE; + + modes = malloc(num * sizeof(DGAModeRec)); + if (!modes) + return FALSE; + + num = 0; + display_mode = scrn->modes; + while (display_mode) + { + mode = modes + num++; + + mode->mode = display_mode; + mode->flags = DGA_CONCURRENT_ACCESS; + if (display_mode->Flags & V_DBLSCAN) + mode->flags |= DGA_DOUBLESCAN; + if (display_mode->Flags & V_INTERLACE) + mode->flags |= DGA_INTERLACED; + mode->byteOrder = scrn->imageByteOrder; + mode->depth = scrn->depth; + mode->bitsPerPixel = scrn->bitsPerPixel; + mode->red_mask = scrn->mask.red; + mode->green_mask = scrn->mask.green; + mode->blue_mask = scrn->mask.blue; + mode->visualClass = (bpp == 1) ? PseudoColor : TrueColor; + mode->viewportWidth = display_mode->HDisplay; + mode->viewportHeight = display_mode->VDisplay; + mode->xViewportStep = (bpp == 3) ? 2 : 1; + mode->yViewportStep = 1; + mode->viewportFlags = DGA_FLIP_RETRACE; + mode->offset = 0; + mode->address = 0; + mode->imageWidth = mode->viewportWidth; + mode->imageHeight = mode->viewportHeight; + mode->bytesPerScanline = (mode->imageWidth * scrn->bitsPerPixel) >> 3; + mode->pixmapWidth = mode->imageWidth; + mode->pixmapHeight = mode->imageHeight; + mode->maxViewportX = 0; + mode->maxViewportY = 0; + + display_mode = display_mode->next; + if (display_mode == scrn->modes) + break; + } + if (xf86_config->dga_modes) + free(xf86_config->dga_modes); + xf86_config->dga_nmode = num; + xf86_config->dga_modes = modes; + return TRUE; +} + +static Bool +xf86_dga_set_mode(ScrnInfoPtr scrn, DGAModePtr display_mode) +{ + ScreenPtr pScreen = scrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + if (!display_mode) + { + if (xf86_config->dga_save_mode) + { + xf86SwitchMode(pScreen, xf86_config->dga_save_mode); + xf86_config->dga_save_mode = NULL; + } + } + else + { + if (!xf86_config->dga_save_mode) + { + xf86_config->dga_save_mode = scrn->currentMode; + xf86SwitchMode(pScreen, display_mode->mode); + } + } + return TRUE; +} + +static int +xf86_dga_get_viewport(ScrnInfoPtr scrn) +{ + return 0; +} + +static void +xf86_dga_set_viewport(ScrnInfoPtr scrn, int x, int y, int flags) +{ + scrn->AdjustFrame(scrn->pScreen->myNum, x, y, flags); +} + +static Bool +xf86_dga_open_framebuffer(ScrnInfoPtr scrn, + char **name, + unsigned char **mem, int *size, int *offset, int *flags) +{ + return FALSE; +} + +static void +xf86_dga_close_framebuffer(ScrnInfoPtr scrn) +{ +} + +static DGAFunctionRec xf86_dga_funcs = { + xf86_dga_open_framebuffer, + xf86_dga_close_framebuffer, + xf86_dga_set_mode, + xf86_dga_set_viewport, + xf86_dga_get_viewport, + NULL, + NULL, + NULL, + NULL +}; + +Bool +xf86DiDGAReInit (ScreenPtr pScreen) +{ + return TRUE; +} + +Bool +_xf86_di_dga_reinit_internal (ScreenPtr pScreen) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + if (!DGAAvailable(pScreen->myNum)) + return TRUE; + + if (!xf86_dga_get_modes (pScreen)) + return FALSE; + + return DGAReInitModes (pScreen, xf86_config->dga_modes, xf86_config->dga_nmode); +} + +Bool +xf86DiDGAInit (ScreenPtr pScreen, unsigned long dga_address) +{ + return TRUE; +} + +Bool +_xf86_di_dga_init_internal (ScreenPtr pScreen) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + xf86_config->dga_flags = 0; + xf86_config->dga_address = 0; + xf86_config->dga_width = 0; + xf86_config->dga_height = 0; + xf86_config->dga_stride = 0; + + if (!xf86_dga_get_modes (pScreen)) + return FALSE; + + return DGAInit(pScreen, &xf86_dga_funcs, xf86_config->dga_modes, xf86_config->dga_nmode); +} diff --git a/xorg-server/hw/xfree86/modes/xf86DisplayIDModes.c b/xorg-server/hw/xfree86/modes/xf86DisplayIDModes.c index 182d43e0e..d507e3b14 100644 --- a/xorg-server/hw/xfree86/modes/xf86DisplayIDModes.c +++ b/xorg-server/hw/xfree86/modes/xf86DisplayIDModes.c @@ -1,437 +1,437 @@ -/* - * Copyright 2009 Red Hat, Inc. - * - * 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 - * on the rights to use, copy, modify, merge, publish, distribute, sub - * license, and/or sell copies of the Software, and to permit persons to whom - * them 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 MERCHANTIBILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS 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. - * - * Authors: - * Adam Jackson <ajax@redhat.com> - */ - -#include "xorg-config.h" -#include "xf86.h" -#include "xf86str.h" -#include "edid.h" -#include "xf86DDC.h" - -typedef void (*did_proc)(int scrnIndex, unsigned char *data, void *closure); - -#define DID_PRODUCT_ID 0x00 -#define DID_DISPLAY_PARAMETERS 0x01 -#define DID_COLOR_INFO 0x02 -#define DID_TIMING_1_DETAILED 0x03 -#define DID_TIMING_2_DETAILED 0x04 -#define DID_TIMING_3_SHORT 0x05 -#define DID_TIMING_4_DMT 0x06 -#define DID_TIMING_VESA 0x07 -#define DID_TIMING_CEA 0x08 -#define DID_TIMING_RANGE_LIMITS 0x09 -#define DID_PRODUCT_SERIAL 0x0A -#define DID_ASCII_STRING 0x0B -#define DID_DISPLAY_DEVICE 0x0C -#define DID_POWER_SEQUENCING 0x0D -#define DID_TRANSFER_INFO 0x0E -#define DID_DISPLAY_INTERFACE 0x0F -#define DID_STEREO 0x10 -#define DID_VENDOR 0x7F - -#define extract_le16(x, i) ((x[i+1] << 8) + (x[i])) -#define extract_le24(x, i) ((x[i+2] << 16) + (x[i+1] << 8) + (x[i])) - -static DisplayModePtr -modeCalloc(void) -{ - return xcalloc(1, sizeof(DisplayModeRec)); -} - -/* - * How awesome is it to have two detailed timing formats, neither of which - * are compatible with the format in EDID? So awesome. - */ - -static void -didDetailedTiming1(int i, unsigned char *x, MonPtr mon) -{ - DisplayModePtr m = modeCalloc(); - - if (!m) - return; - - m->Clock = extract_le24(x, 0); - - m->HDisplay = extract_le16(x, 4); - m->HSyncStart = m->HDisplay + (extract_le16(x, 8) & 0x7f); - m->HSyncEnd = m->HSyncStart + extract_le16(x, 10); - m->HTotal = m->HDisplay + extract_le16(x, 6); - m->Flags |= (x[9] & 0x80) ? V_PHSYNC : V_NHSYNC; - - m->VDisplay = extract_le16(x, 12); - m->VSyncStart = m->VDisplay + (extract_le16(x, 16) & 0x7f); - m->VSyncEnd = m->VSyncStart + extract_le16(x, 18); - m->VTotal = m->VDisplay + extract_le16(x, 14); - m->Flags |= (x[17] & 0x80) ? V_PVSYNC : V_NVSYNC; - - m->type = M_T_DRIVER; - if (x[3] & 0x80) - m->type |= M_T_PREFERRED; - - /* XXX double check handling of this */ - if (x[3] & 0x10) - m->Flags |= V_INTERLACE; - - mon->Modes = xf86ModesAdd(mon->Modes, m); -} - -/* XXX no sync bits. what to do? */ -static void -didDetailedTiming2(int i, unsigned char *x, MonPtr mon) -{ - DisplayModePtr mode = modeCalloc(); - - if (!mode) - return; - - mode->Clock = extract_le24(x, 0); - - /* horiz sizes are in character cells, not pixels, hence * 8 */ - mode->HDisplay = ((extract_le16(x, 4) & 0x01ff) + 1) * 8; - mode->HSyncStart = mode->HDisplay + (((x[6] & 0xf0) >> 4) + 1) * 8; - mode->HSyncEnd = mode->HSyncStart + ((x[6] & 0x0f) + 1) * 8; - mode->HTotal = mode->HDisplay + ((x[5] >> 1) + 1) * 8; - - mode->VDisplay = extract_le16(x, 7) & 0x07ff; - mode->VSyncStart = mode->VDisplay + (x[10] >> 4) + 1; - mode->VSyncEnd = mode->VSyncStart + (x[10] & 0x0f) + 1; - mode->VTotal = mode->VDisplay + x[9]; - - mode->status = M_T_DRIVER; - if (x[3] & 0x80) - mode->status |= M_T_PREFERRED; - - /* XXX double check handling of this */ - if (x[3] & 0x10) - mode->Flags |= V_INTERLACE; - - mon->Modes = xf86ModesAdd(mon->Modes, mode); -} - -static void -didShortTiming(int i, unsigned char *x, MonPtr mon) -{ - DisplayModePtr m; - int w, h, r; - - w = (x[1] + 1) * 8; - switch (x[0] & 0x0f) { - case 0: - h = w; - break; - case 1: - h = (w * 4) / 5; - break; - case 2: - h = (w * 3) / 4; - break; - case 3: - h = (w * 9) / 15; - break; - case 4: - h = (w * 9) / 16; - break; - case 5: - h = (w * 10) / 16; - break; - default: - return; - } - r = (x[2] & 0x7f) + 1; - - m = xf86CVTMode(w, h, r, !!(x[0] & 0x10), !!(x[2] & 0x80)); - - m->type = M_T_DRIVER; - if (x[0] & 0x80) - m->type |= M_T_PREFERRED; - - mon->Modes = xf86ModesAdd(mon->Modes, m); -} - -static void -didDMTTiming(int i, unsigned char *x, void *closure) -{ - MonPtr mon = closure; - - mon->Modes = xf86ModesAdd(mon->Modes, - xf86DuplicateMode(DMTModes + *x)); -} - -#define RB 1 -#define INT 2 -static const struct did_dmt { - short w, h, r, f; -} did_dmt[] = { - /* byte 3 */ - { 640, 350, 85, 0 }, - { 640, 400, 85, 0 }, - { 720, 400, 85, 0 }, - { 640, 480, 60, 0 }, - { 640, 480, 72, 0 }, - { 640, 480, 75, 0 }, - { 640, 480, 85, 0 }, - { 800, 600, 56, 0 }, - /* byte 4 */ - { 800, 600, 60, 0 }, - { 800, 600, 72, 0 }, - { 800, 600, 75, 0 }, - { 800, 600, 85, 0 }, - { 800, 600, 120, RB }, - { 848, 480, 60, 0 }, - { 1024, 768, 43, INT }, - { 1024, 768, 60, 0 }, - /* byte 5 */ - { 1024, 768, 70, 0 }, - { 1024, 768, 75, 0 }, - { 1024, 768, 85, 0 }, - { 1024, 768, 120, RB }, - { 1152, 864, 75, 0 }, - { 1280, 768, 60, RB }, - { 1280, 768, 60, 0 }, - { 1280, 768, 75, 0 }, - /* byte 6 */ - { 1280, 768, 85, 0 }, - { 1280, 768, 120, RB }, - { 1280, 800, 60, RB }, - { 1280, 800, 60, 0 }, - { 1280, 800, 75, 0 }, - { 1280, 800, 85, 0 }, - { 1280, 800, 120, RB }, - { 1280, 960, 60, 0 }, - /* byte 7 */ - { 1280, 960, 85, 0 }, - { 1280, 960, 120, RB }, - { 1280, 1024, 60, 0 }, - { 1280, 1024, 75, 0 }, - { 1280, 1024, 85, 0 }, - { 1280, 1024, 120, RB }, - { 1360, 768, 60, 0 }, - { 1360, 768, 120, RB }, - /* byte 8 */ - { 1400, 1050, 60, RB }, - { 1400, 1050, 60, 0 }, - { 1400, 1050, 75, 0 }, - { 1400, 1050, 85, 0 }, - { 1400, 1050, 120, RB }, - { 1440, 900, 60, RB }, - { 1440, 900, 60, 0 }, - { 1440, 900, 75, 0 }, - /* byte 9 */ - { 1440, 900, 85, 0 }, - { 1440, 900, 120, RB }, - { 1600, 1200, 60, 0 }, - { 1600, 1200, 65, 0 }, - { 1600, 1200, 70, 0 }, - { 1600, 1200, 75, 0 }, - { 1600, 1200, 85, 0 }, - { 1600, 1200, 120, RB }, - /* byte a */ - { 1680, 1050, 60, RB }, - { 1680, 1050, 60, 0 }, - { 1680, 1050, 75, 0 }, - { 1680, 1050, 85, 0 }, - { 1680, 1050, 120, RB }, - { 1792, 1344, 60, 0 }, - { 1792, 1344, 75, 0 }, - { 1792, 1344, 120, RB }, - /* byte b */ - { 1856, 1392, 60, 0 }, - { 1856, 1392, 75, 0 }, - { 1856, 1392, 120, RB }, - { 1920, 1200, 60, RB }, - { 1920, 1200, 60, 0 }, - { 1920, 1200, 75, 0 }, - { 1920, 1200, 85, 0 }, - { 1920, 1200, 120, RB }, - /* byte c */ - { 1920, 1440, 60, 0 }, - { 1920, 1440, 75, 0 }, - { 1920, 1440, 120, RB }, - { 2560, 1600, 60, RB }, - { 2560, 1600, 60, 0 }, - { 2560, 1600, 75, 0 }, - { 2560, 1600, 85, 0 }, - { 2560, 1600, 120, RB }, -}; - -static void -didVesaTiming(int scrn, unsigned char *x, MonPtr mon) -{ - int i, j; - - x += 3; - - for (i = 0; i < 10; i++) - for (j = 0; j < 8; j++) - if (x[i] & (1 << j)) { - const struct did_dmt *d = &(did_dmt[i * 8 + j]); - if (d->f == INT) - continue; - mon->Modes = xf86ModesAdd(mon->Modes, - FindDMTMode(d->w, d->h, d->r, - d->f == RB)); - } - -} - -static void -handleDisplayIDBlock(int scrnIndex, unsigned char *x, void *closure) -{ - MonPtr mon = closure; - - switch (x[0]) { - case DID_DISPLAY_PARAMETERS: - /* w/h are in decimillimeters */ - mon->widthmm = (extract_le16(x, 3) + 5) / 10; - mon->heightmm = (extract_le16(x, 5) + 5) / 10; - /* XXX pixel count, feature flags, gamma, aspect, color depth */ - break; - - case DID_TIMING_RANGE_LIMITS: - { - int n; - - mon->maxPixClock = max(mon->maxPixClock, extract_le24(x, 6) * 10); - - n = mon->nHsync++; - if (n < MAX_HSYNC) { - mon->hsync[n].lo = x[9]; - mon->hsync[n].hi = x[10]; - } else { - n = MAX_HSYNC; - } - n = mon->nVrefresh++; - if (n < MAX_VREFRESH) { - mon->vrefresh[n].lo = x[13]; - mon->vrefresh[n].hi = x[14]; - } else { - n = MAX_VREFRESH; - } - break; - } - - case DID_TIMING_1_DETAILED: - { - int i; - for (i = 0; i < x[2]; i += 20) - didDetailedTiming1(scrnIndex, x + i + 3, mon); - break; - } - - case DID_TIMING_2_DETAILED: - { - int i; - for (i = 0; i < x[2]; i += 11) - didDetailedTiming2(scrnIndex, x + i + 3, mon); - break; - } - - case DID_TIMING_3_SHORT: - { - int i; - for (i = 0; i < x[2]; i += 3) - didShortTiming(scrnIndex, x + i + 3, mon); - break; - } - - case DID_TIMING_4_DMT: - { - int i; - for (i = 0; i < x[2]; i++) - didDMTTiming(scrnIndex, x + i + 3, mon); - break; - } - - case DID_TIMING_VESA: - didVesaTiming(scrnIndex, x, mon); - break; - - /* XXX pixel format, ar, orientation, subpixel, dot pitch, bit depth */ - case DID_DISPLAY_DEVICE: - - /* XXX interface, links, color encoding, ss, drm */ - case DID_DISPLAY_INTERFACE: - - /* XXX stereo */ - case DID_STEREO: - - /* nothing interesting in these */ - case DID_COLOR_INFO: - case DID_PRODUCT_SERIAL: - case DID_ASCII_STRING: - case DID_POWER_SEQUENCING: - case DID_TRANSFER_INFO: - case DID_VENDOR: - break; - - /* warn about anything else */ - default: - xf86DrvMsg(scrnIndex, X_WARNING, - "Unknown DisplayID block type %hx\n", x[0]); - break; - } -} - -static void -forEachDisplayIDBlock(int scrnIndex, unsigned char *did, did_proc proc, - void *closure) -{ - int num_extensions = did[3]; - int section_size = did[1]; - unsigned char *block; - - do { - if ((did[0] & 0xf0) != 0x10) /* not 1.x, abort */ - return; - /* XXX also, checksum */ - - block = did + 4; - - while (section_size > 0) { - int block_size = (block[2] + 2); - - proc(scrnIndex, block, closure); - - section_size -= block_size; - block += block_size; - } - - did += (did[1] + 5); - } while (num_extensions--); -} - -/* - * Fill out MonPtr with xf86MonPtr information. - */ -void -xf86DisplayIDMonitorSet(int scrnIndex, MonPtr mon, xf86MonPtr DDC) -{ - if (!mon || !DDC) - return; - - mon->DDC = DDC; - - forEachDisplayIDBlock(scrnIndex, DDC->rawData, handleDisplayIDBlock, mon); -} +/* + * Copyright 2009 Red Hat, Inc. + * + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * them 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 MERCHANTIBILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS 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. + * + * Authors: + * Adam Jackson <ajax@redhat.com> + */ + +#include "xorg-config.h" +#include "xf86.h" +#include "xf86str.h" +#include "edid.h" +#include "xf86DDC.h" + +typedef void (*did_proc)(int scrnIndex, unsigned char *data, void *closure); + +#define DID_PRODUCT_ID 0x00 +#define DID_DISPLAY_PARAMETERS 0x01 +#define DID_COLOR_INFO 0x02 +#define DID_TIMING_1_DETAILED 0x03 +#define DID_TIMING_2_DETAILED 0x04 +#define DID_TIMING_3_SHORT 0x05 +#define DID_TIMING_4_DMT 0x06 +#define DID_TIMING_VESA 0x07 +#define DID_TIMING_CEA 0x08 +#define DID_TIMING_RANGE_LIMITS 0x09 +#define DID_PRODUCT_SERIAL 0x0A +#define DID_ASCII_STRING 0x0B +#define DID_DISPLAY_DEVICE 0x0C +#define DID_POWER_SEQUENCING 0x0D +#define DID_TRANSFER_INFO 0x0E +#define DID_DISPLAY_INTERFACE 0x0F +#define DID_STEREO 0x10 +#define DID_VENDOR 0x7F + +#define extract_le16(x, i) ((x[i+1] << 8) + (x[i])) +#define extract_le24(x, i) ((x[i+2] << 16) + (x[i+1] << 8) + (x[i])) + +static DisplayModePtr +modeCalloc(void) +{ + return calloc(1, sizeof(DisplayModeRec)); +} + +/* + * How awesome is it to have two detailed timing formats, neither of which + * are compatible with the format in EDID? So awesome. + */ + +static void +didDetailedTiming1(int i, unsigned char *x, MonPtr mon) +{ + DisplayModePtr m = modeCalloc(); + + if (!m) + return; + + m->Clock = extract_le24(x, 0); + + m->HDisplay = extract_le16(x, 4); + m->HSyncStart = m->HDisplay + (extract_le16(x, 8) & 0x7f); + m->HSyncEnd = m->HSyncStart + extract_le16(x, 10); + m->HTotal = m->HDisplay + extract_le16(x, 6); + m->Flags |= (x[9] & 0x80) ? V_PHSYNC : V_NHSYNC; + + m->VDisplay = extract_le16(x, 12); + m->VSyncStart = m->VDisplay + (extract_le16(x, 16) & 0x7f); + m->VSyncEnd = m->VSyncStart + extract_le16(x, 18); + m->VTotal = m->VDisplay + extract_le16(x, 14); + m->Flags |= (x[17] & 0x80) ? V_PVSYNC : V_NVSYNC; + + m->type = M_T_DRIVER; + if (x[3] & 0x80) + m->type |= M_T_PREFERRED; + + /* XXX double check handling of this */ + if (x[3] & 0x10) + m->Flags |= V_INTERLACE; + + mon->Modes = xf86ModesAdd(mon->Modes, m); +} + +/* XXX no sync bits. what to do? */ +static void +didDetailedTiming2(int i, unsigned char *x, MonPtr mon) +{ + DisplayModePtr mode = modeCalloc(); + + if (!mode) + return; + + mode->Clock = extract_le24(x, 0); + + /* horiz sizes are in character cells, not pixels, hence * 8 */ + mode->HDisplay = ((extract_le16(x, 4) & 0x01ff) + 1) * 8; + mode->HSyncStart = mode->HDisplay + (((x[6] & 0xf0) >> 4) + 1) * 8; + mode->HSyncEnd = mode->HSyncStart + ((x[6] & 0x0f) + 1) * 8; + mode->HTotal = mode->HDisplay + ((x[5] >> 1) + 1) * 8; + + mode->VDisplay = extract_le16(x, 7) & 0x07ff; + mode->VSyncStart = mode->VDisplay + (x[10] >> 4) + 1; + mode->VSyncEnd = mode->VSyncStart + (x[10] & 0x0f) + 1; + mode->VTotal = mode->VDisplay + x[9]; + + mode->status = M_T_DRIVER; + if (x[3] & 0x80) + mode->status |= M_T_PREFERRED; + + /* XXX double check handling of this */ + if (x[3] & 0x10) + mode->Flags |= V_INTERLACE; + + mon->Modes = xf86ModesAdd(mon->Modes, mode); +} + +static void +didShortTiming(int i, unsigned char *x, MonPtr mon) +{ + DisplayModePtr m; + int w, h, r; + + w = (x[1] + 1) * 8; + switch (x[0] & 0x0f) { + case 0: + h = w; + break; + case 1: + h = (w * 4) / 5; + break; + case 2: + h = (w * 3) / 4; + break; + case 3: + h = (w * 9) / 15; + break; + case 4: + h = (w * 9) / 16; + break; + case 5: + h = (w * 10) / 16; + break; + default: + return; + } + r = (x[2] & 0x7f) + 1; + + m = xf86CVTMode(w, h, r, !!(x[0] & 0x10), !!(x[2] & 0x80)); + + m->type = M_T_DRIVER; + if (x[0] & 0x80) + m->type |= M_T_PREFERRED; + + mon->Modes = xf86ModesAdd(mon->Modes, m); +} + +static void +didDMTTiming(int i, unsigned char *x, void *closure) +{ + MonPtr mon = closure; + + mon->Modes = xf86ModesAdd(mon->Modes, + xf86DuplicateMode(DMTModes + *x)); +} + +#define RB 1 +#define INT 2 +static const struct did_dmt { + short w, h, r, f; +} did_dmt[] = { + /* byte 3 */ + { 640, 350, 85, 0 }, + { 640, 400, 85, 0 }, + { 720, 400, 85, 0 }, + { 640, 480, 60, 0 }, + { 640, 480, 72, 0 }, + { 640, 480, 75, 0 }, + { 640, 480, 85, 0 }, + { 800, 600, 56, 0 }, + /* byte 4 */ + { 800, 600, 60, 0 }, + { 800, 600, 72, 0 }, + { 800, 600, 75, 0 }, + { 800, 600, 85, 0 }, + { 800, 600, 120, RB }, + { 848, 480, 60, 0 }, + { 1024, 768, 43, INT }, + { 1024, 768, 60, 0 }, + /* byte 5 */ + { 1024, 768, 70, 0 }, + { 1024, 768, 75, 0 }, + { 1024, 768, 85, 0 }, + { 1024, 768, 120, RB }, + { 1152, 864, 75, 0 }, + { 1280, 768, 60, RB }, + { 1280, 768, 60, 0 }, + { 1280, 768, 75, 0 }, + /* byte 6 */ + { 1280, 768, 85, 0 }, + { 1280, 768, 120, RB }, + { 1280, 800, 60, RB }, + { 1280, 800, 60, 0 }, + { 1280, 800, 75, 0 }, + { 1280, 800, 85, 0 }, + { 1280, 800, 120, RB }, + { 1280, 960, 60, 0 }, + /* byte 7 */ + { 1280, 960, 85, 0 }, + { 1280, 960, 120, RB }, + { 1280, 1024, 60, 0 }, + { 1280, 1024, 75, 0 }, + { 1280, 1024, 85, 0 }, + { 1280, 1024, 120, RB }, + { 1360, 768, 60, 0 }, + { 1360, 768, 120, RB }, + /* byte 8 */ + { 1400, 1050, 60, RB }, + { 1400, 1050, 60, 0 }, + { 1400, 1050, 75, 0 }, + { 1400, 1050, 85, 0 }, + { 1400, 1050, 120, RB }, + { 1440, 900, 60, RB }, + { 1440, 900, 60, 0 }, + { 1440, 900, 75, 0 }, + /* byte 9 */ + { 1440, 900, 85, 0 }, + { 1440, 900, 120, RB }, + { 1600, 1200, 60, 0 }, + { 1600, 1200, 65, 0 }, + { 1600, 1200, 70, 0 }, + { 1600, 1200, 75, 0 }, + { 1600, 1200, 85, 0 }, + { 1600, 1200, 120, RB }, + /* byte a */ + { 1680, 1050, 60, RB }, + { 1680, 1050, 60, 0 }, + { 1680, 1050, 75, 0 }, + { 1680, 1050, 85, 0 }, + { 1680, 1050, 120, RB }, + { 1792, 1344, 60, 0 }, + { 1792, 1344, 75, 0 }, + { 1792, 1344, 120, RB }, + /* byte b */ + { 1856, 1392, 60, 0 }, + { 1856, 1392, 75, 0 }, + { 1856, 1392, 120, RB }, + { 1920, 1200, 60, RB }, + { 1920, 1200, 60, 0 }, + { 1920, 1200, 75, 0 }, + { 1920, 1200, 85, 0 }, + { 1920, 1200, 120, RB }, + /* byte c */ + { 1920, 1440, 60, 0 }, + { 1920, 1440, 75, 0 }, + { 1920, 1440, 120, RB }, + { 2560, 1600, 60, RB }, + { 2560, 1600, 60, 0 }, + { 2560, 1600, 75, 0 }, + { 2560, 1600, 85, 0 }, + { 2560, 1600, 120, RB }, +}; + +static void +didVesaTiming(int scrn, unsigned char *x, MonPtr mon) +{ + int i, j; + + x += 3; + + for (i = 0; i < 10; i++) + for (j = 0; j < 8; j++) + if (x[i] & (1 << j)) { + const struct did_dmt *d = &(did_dmt[i * 8 + j]); + if (d->f == INT) + continue; + mon->Modes = xf86ModesAdd(mon->Modes, + FindDMTMode(d->w, d->h, d->r, + d->f == RB)); + } + +} + +static void +handleDisplayIDBlock(int scrnIndex, unsigned char *x, void *closure) +{ + MonPtr mon = closure; + + switch (x[0]) { + case DID_DISPLAY_PARAMETERS: + /* w/h are in decimillimeters */ + mon->widthmm = (extract_le16(x, 3) + 5) / 10; + mon->heightmm = (extract_le16(x, 5) + 5) / 10; + /* XXX pixel count, feature flags, gamma, aspect, color depth */ + break; + + case DID_TIMING_RANGE_LIMITS: + { + int n; + + mon->maxPixClock = max(mon->maxPixClock, extract_le24(x, 6) * 10); + + n = mon->nHsync++; + if (n < MAX_HSYNC) { + mon->hsync[n].lo = x[9]; + mon->hsync[n].hi = x[10]; + } else { + n = MAX_HSYNC; + } + n = mon->nVrefresh++; + if (n < MAX_VREFRESH) { + mon->vrefresh[n].lo = x[13]; + mon->vrefresh[n].hi = x[14]; + } else { + n = MAX_VREFRESH; + } + break; + } + + case DID_TIMING_1_DETAILED: + { + int i; + for (i = 0; i < x[2]; i += 20) + didDetailedTiming1(scrnIndex, x + i + 3, mon); + break; + } + + case DID_TIMING_2_DETAILED: + { + int i; + for (i = 0; i < x[2]; i += 11) + didDetailedTiming2(scrnIndex, x + i + 3, mon); + break; + } + + case DID_TIMING_3_SHORT: + { + int i; + for (i = 0; i < x[2]; i += 3) + didShortTiming(scrnIndex, x + i + 3, mon); + break; + } + + case DID_TIMING_4_DMT: + { + int i; + for (i = 0; i < x[2]; i++) + didDMTTiming(scrnIndex, x + i + 3, mon); + break; + } + + case DID_TIMING_VESA: + didVesaTiming(scrnIndex, x, mon); + break; + + /* XXX pixel format, ar, orientation, subpixel, dot pitch, bit depth */ + case DID_DISPLAY_DEVICE: + + /* XXX interface, links, color encoding, ss, drm */ + case DID_DISPLAY_INTERFACE: + + /* XXX stereo */ + case DID_STEREO: + + /* nothing interesting in these */ + case DID_COLOR_INFO: + case DID_PRODUCT_SERIAL: + case DID_ASCII_STRING: + case DID_POWER_SEQUENCING: + case DID_TRANSFER_INFO: + case DID_VENDOR: + break; + + /* warn about anything else */ + default: + xf86DrvMsg(scrnIndex, X_WARNING, + "Unknown DisplayID block type %hx\n", x[0]); + break; + } +} + +static void +forEachDisplayIDBlock(int scrnIndex, unsigned char *did, did_proc proc, + void *closure) +{ + int num_extensions = did[3]; + int section_size = did[1]; + unsigned char *block; + + do { + if ((did[0] & 0xf0) != 0x10) /* not 1.x, abort */ + return; + /* XXX also, checksum */ + + block = did + 4; + + while (section_size > 0) { + int block_size = (block[2] + 2); + + proc(scrnIndex, block, closure); + + section_size -= block_size; + block += block_size; + } + + did += (did[1] + 5); + } while (num_extensions--); +} + +/* + * Fill out MonPtr with xf86MonPtr information. + */ +void +xf86DisplayIDMonitorSet(int scrnIndex, MonPtr mon, xf86MonPtr DDC) +{ + if (!mon || !DDC) + return; + + mon->DDC = DDC; + + forEachDisplayIDBlock(scrnIndex, DDC->rawData, handleDisplayIDBlock, mon); +} diff --git a/xorg-server/hw/xfree86/modes/xf86EdidModes.c b/xorg-server/hw/xfree86/modes/xf86EdidModes.c index ec6540841..fc469c6ba 100644 --- a/xorg-server/hw/xfree86/modes/xf86EdidModes.c +++ b/xorg-server/hw/xfree86/modes/xf86EdidModes.c @@ -1,1215 +1,1215 @@ -/* - * Copyright 2006 Luc Verhaegen. - * Copyright 2008 Red Hat, Inc. - * - * 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, sub license, - * 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 NON-INFRINGEMENT. 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. - */ - -/** - * @file This file covers code to convert a xf86MonPtr containing EDID-probed - * information into a list of modes, including applying monitor-specific - * quirks to fix broken EDID data. - */ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#else -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#endif - -#define _PARSE_EDID_ -#include "xf86.h" -#include "xf86DDC.h" -#include <X11/Xatom.h> -#include "property.h" -#include "propertyst.h" -#include "xf86Crtc.h" -#include <string.h> -#include <math.h> - -static void handle_detailed_rblank(struct detailed_monitor_section *det_mon, - void *data) -{ - if (det_mon->type == DS_RANGES) - if (det_mon->section.ranges.supported_blanking & CVT_REDUCED) - *(Bool*)data = TRUE; -} - -static Bool -xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC) -{ - /* EDID 1.4 explicitly defines RB support */ - if (DDC->ver.revision >= 4) { - Bool ret = FALSE; - - xf86ForEachDetailedBlock(DDC, handle_detailed_rblank, &ret); - return ret; - } - - /* For anything older, assume digital means RB support. Boo. */ - if (DDC->features.input_type) - return TRUE; - - return FALSE; -} - -static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC) -{ - /* Belinea 10 15 55 */ - if (memcmp (DDC->vendor.name, "MAX", 4) == 0 && - ((DDC->vendor.prod_id == 1516) || - (DDC->vendor.prod_id == 0x77e))) - return TRUE; - - /* Acer AL1706 */ - if (memcmp (DDC->vendor.name, "ACR", 4) == 0 && - DDC->vendor.prod_id == 44358) - return TRUE; - - /* Bug #10814: Samsung SyncMaster 225BW */ - if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && - DDC->vendor.prod_id == 596) - return TRUE; - - /* Bug #10545: Samsung SyncMaster 226BW */ - if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && - DDC->vendor.prod_id == 638) - return TRUE; - - /* Acer F51 */ - if (memcmp (DDC->vendor.name, "API", 4) == 0 && - DDC->vendor.prod_id == 0x7602) - return TRUE; - - - return FALSE; -} - -static Bool quirk_prefer_large_75 (int scrnIndex, xf86MonPtr DDC) -{ - /* Bug #11603: Funai Electronics PM36B */ - if (memcmp (DDC->vendor.name, "FCM", 4) == 0 && - DDC->vendor.prod_id == 13600) - return TRUE; - - return FALSE; -} - -static Bool quirk_detailed_h_in_cm (int scrnIndex, xf86MonPtr DDC) -{ - /* Bug #11603: Funai Electronics PM36B */ - if (memcmp (DDC->vendor.name, "FCM", 4) == 0 && - DDC->vendor.prod_id == 13600) - return TRUE; - - return FALSE; -} - -static Bool quirk_detailed_v_in_cm (int scrnIndex, xf86MonPtr DDC) -{ - /* Bug #11603: Funai Electronics PM36B */ - if (memcmp (DDC->vendor.name, "FCM", 4) == 0 && - DDC->vendor.prod_id == 13600) - return TRUE; - - /* Bug #21000: LGPhilipsLCD LP154W01-TLAJ */ - if (memcmp (DDC->vendor.name, "LPL", 4) == 0 && - DDC->vendor.prod_id == 47360) - return TRUE; - - /* Bug #10304: LGPhilipsLCD LP154W01-A5 */ - if (memcmp(DDC->vendor.name, "LPL", 4) == 0 && - DDC->vendor.prod_id == 0) - return TRUE; - - /* Bug #24482: LGPhilipsLCD LP154W01-TLA1 */ - if (memcmp(DDC->vendor.name, "LPL", 4) == 0 && - DDC->vendor.prod_id == 0x2a00) - return TRUE; - - /* Bug #21750: Samsung Syncmaster 2333HD */ - if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && - DDC->vendor.prod_id == 1157) - return TRUE; - - return FALSE; -} - -static Bool quirk_detailed_use_maximum_size (int scrnIndex, xf86MonPtr DDC) -{ - /* Bug #21324: Iiyama Vision Master 450 */ - if (memcmp (DDC->vendor.name, "IVM", 4) == 0 && - DDC->vendor.prod_id == 6400) - return TRUE; - - return FALSE; -} - -static Bool quirk_135_clock_too_high (int scrnIndex, xf86MonPtr DDC) -{ - /* Envision Peripherals, Inc. EN-7100e. See bug #9550. */ - if (memcmp (DDC->vendor.name, "EPI", 4) == 0 && - DDC->vendor.prod_id == 59264) - return TRUE; - - return FALSE; -} - -static Bool quirk_first_detailed_preferred (int scrnIndex, xf86MonPtr DDC) -{ - /* Philips 107p5 CRT. Reported on xorg@ with pastebin. */ - if (memcmp (DDC->vendor.name, "PHL", 4) == 0 && - DDC->vendor.prod_id == 57364) - return TRUE; - - /* Proview AY765C 17" LCD. See bug #15160*/ - if (memcmp (DDC->vendor.name, "PTS", 4) == 0 && - DDC->vendor.prod_id == 765) - return TRUE; - - /* ACR of some sort RH #284231 */ - if (memcmp (DDC->vendor.name, "ACR", 4) == 0 && - DDC->vendor.prod_id == 2423) - return TRUE; - - /* Peacock Ergovision 19. See rh#492359 */ - if (memcmp (DDC->vendor.name, "PEA", 4) == 0 && - DDC->vendor.prod_id == 9003) - return TRUE; - - return FALSE; -} - -static Bool quirk_detailed_sync_pp(int scrnIndex, xf86MonPtr DDC) -{ - /* Bug #12439: Samsung SyncMaster 205BW */ - if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && - DDC->vendor.prod_id == 541) - return TRUE; - return FALSE; -} - -/* This should probably be made more generic */ -static Bool quirk_dvi_single_link(int scrnIndex, xf86MonPtr DDC) -{ - /* Red Hat bug #453106: Apple 23" Cinema Display */ - if (memcmp (DDC->vendor.name, "APL", 4) == 0 && - DDC->vendor.prod_id == 0x921c) - return TRUE; - return FALSE; -} - -typedef struct { - Bool (*detect) (int scrnIndex, xf86MonPtr DDC); - ddc_quirk_t quirk; - char *description; -} ddc_quirk_map_t; - -static const ddc_quirk_map_t ddc_quirks[] = { - { - quirk_prefer_large_60, DDC_QUIRK_PREFER_LARGE_60, - "Detailed timing is not preferred, use largest mode at 60Hz" - }, - { - quirk_135_clock_too_high, DDC_QUIRK_135_CLOCK_TOO_HIGH, - "Recommended 135MHz pixel clock is too high" - }, - { - quirk_prefer_large_75, DDC_QUIRK_PREFER_LARGE_75, - "Detailed timing is not preferred, use largest mode at 75Hz" - }, - { - quirk_detailed_h_in_cm, DDC_QUIRK_DETAILED_H_IN_CM, - "Detailed timings give horizontal size in cm." - }, - { - quirk_detailed_v_in_cm, DDC_QUIRK_DETAILED_V_IN_CM, - "Detailed timings give vertical size in cm." - }, - { - quirk_detailed_use_maximum_size, DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE, - "Use maximum size instead of detailed timing sizes." - }, - { - quirk_first_detailed_preferred, DDC_QUIRK_FIRST_DETAILED_PREFERRED, - "First detailed timing was not marked as preferred." - }, - { - quirk_detailed_sync_pp, DDC_QUIRK_DETAILED_SYNC_PP, - "Use +hsync +vsync for detailed timing." - }, - { - quirk_dvi_single_link, DDC_QUIRK_DVI_SINGLE_LINK, - "Forcing maximum pixel clock to single DVI link." - }, - { - NULL, DDC_QUIRK_NONE, - "No known quirks" - }, -}; - -/* - * These more or less come from the DMT spec. The 720x400 modes are - * inferred from historical 80x25 practice. The 640x480@67 and 832x624@75 - * modes are old-school Mac modes. The EDID spec says the 1152x864@75 mode - * should be 1152x870, again for the Mac, but instead we use the x864 DMT - * mode. - * - * The DMT modes have been fact-checked; the rest are mild guesses. - */ -#define MODEPREFIX NULL, NULL, NULL, 0, M_T_DRIVER -#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 - -static const DisplayModeRec DDCEstablishedModes[17] = { - { MODEPREFIX, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */ - { MODEPREFIX, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */ - { MODEPREFIX, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */ - { MODEPREFIX, 31500, 640, 664, 704, 832, 0, 480, 489, 492, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */ - { MODEPREFIX, 30240, 640, 704, 768, 864, 0, 480, 483, 486, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@67Hz */ - { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */ - { MODEPREFIX, 35500, 720, 738, 846, 900, 0, 400, 421, 423, 449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400@88Hz */ - { MODEPREFIX, 28320, 720, 738, 846, 900, 0, 400, 412, 414, 449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@70Hz */ - { MODEPREFIX, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */ - { MODEPREFIX, 78750, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */ - { MODEPREFIX, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */ - { MODEPREFIX, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */ - { MODEPREFIX, 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 772, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */ - { MODEPREFIX, 57284, 832, 864, 928, 1152, 0, 624, 625, 628, 667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624@75Hz */ - { MODEPREFIX, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */ - { MODEPREFIX, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */ - { MODEPREFIX, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */ -}; - -static DisplayModePtr -DDCModesFromEstablished(int scrnIndex, struct established_timings *timing, - ddc_quirk_t quirks) -{ - DisplayModePtr Modes = NULL, Mode = NULL; - CARD32 bits = (timing->t1) | (timing->t2 << 8) | - ((timing->t_manu & 0x80) << 9); - int i; - - for (i = 0; i < 17; i++) { - if (bits & (0x01 << i)) { - Mode = xf86DuplicateMode(&DDCEstablishedModes[i]); - Modes = xf86ModesAdd(Modes, Mode); - } - } - - return Modes; -} - -/* Autogenerated from the DMT spec */ -const DisplayModeRec DMTModes[] = { - { MODEPREFIX, 31500, 640, 672, 736, 832, 0, 350, 382, 385, 445, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x350@85Hz */ - { MODEPREFIX, 31500, 640, 672, 736, 832, 0, 400, 401, 404, 445, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 640x400@85Hz */ - { MODEPREFIX, 35500, 720, 756, 828, 936, 0, 400, 401, 404, 446, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@85Hz */ - { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */ - { MODEPREFIX, 31500, 640, 664, 704, 832, 0, 480, 489, 492, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */ - { MODEPREFIX, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */ - { MODEPREFIX, 36000, 640, 696, 752, 832, 0, 480, 481, 484, 509, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@85Hz */ - { MODEPREFIX, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */ - { MODEPREFIX, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */ - { MODEPREFIX, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */ - { MODEPREFIX, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */ - { MODEPREFIX, 56250, 800, 832, 896, 1048, 0, 600, 601, 604, 631, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@85Hz */ - { MODEPREFIX, 73250, 800, 848, 880, 960, 0, 600, 603, 607, 636, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 800x600@120Hz RB */ - { MODEPREFIX, 33750, 848, 864, 976, 1088, 0, 480, 486, 494, 517, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 848x480@60Hz */ - { MODEPREFIX, 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 772, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz (interlaced) */ - { MODEPREFIX, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */ - { MODEPREFIX, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */ - { MODEPREFIX, 78750, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */ - { MODEPREFIX, 94500, 1024, 1072, 1168, 1376, 0, 768, 769, 772, 808, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@85Hz */ - { MODEPREFIX, 115500, 1024, 1072, 1104, 1184, 0, 768, 771, 775, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@120Hz RB */ - { MODEPREFIX, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */ - { MODEPREFIX, 68250, 1280, 1328, 1360, 1440, 0, 768, 771, 778, 790, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@60Hz RB */ - { MODEPREFIX, 79500, 1280, 1344, 1472, 1664, 0, 768, 771, 778, 798, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@60Hz */ - { MODEPREFIX, 102250, 1280, 1360, 1488, 1696, 0, 768, 771, 778, 805, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@75Hz */ - { MODEPREFIX, 117500, 1280, 1360, 1496, 1712, 0, 768, 771, 778, 809, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@85Hz */ - { MODEPREFIX, 140250, 1280, 1328, 1360, 1440, 0, 768, 771, 778, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@120Hz RB */ - { MODEPREFIX, 71000, 1280, 1328, 1360, 1440, 0, 800, 803, 809, 823, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@60Hz RB */ - { MODEPREFIX, 83500, 1280, 1352, 1480, 1680, 0, 800, 803, 809, 831, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@60Hz */ - { MODEPREFIX, 106500, 1280, 1360, 1488, 1696, 0, 800, 803, 809, 838, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@75Hz */ - { MODEPREFIX, 122500, 1280, 1360, 1496, 1712, 0, 800, 803, 809, 843, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@85Hz */ - { MODEPREFIX, 146250, 1280, 1328, 1360, 1440, 0, 800, 803, 809, 847, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@120Hz RB */ - { MODEPREFIX, 108000, 1280, 1376, 1488, 1800, 0, 960, 961, 964, 1000, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@60Hz */ - { MODEPREFIX, 148500, 1280, 1344, 1504, 1728, 0, 960, 961, 964, 1011, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@85Hz */ - { MODEPREFIX, 175500, 1280, 1328, 1360, 1440, 0, 960, 963, 967, 1017, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x960@120Hz RB */ - { MODEPREFIX, 108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@60Hz */ - { MODEPREFIX, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */ - { MODEPREFIX, 157500, 1280, 1344, 1504, 1728, 0, 1024, 1025, 1028, 1072, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@85Hz */ - { MODEPREFIX, 187250, 1280, 1328, 1360, 1440, 0, 1024, 1027, 1034, 1084, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x1024@120Hz RB */ - { MODEPREFIX, 85500, 1360, 1424, 1536, 1792, 0, 768, 771, 777, 795, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1360x768@60Hz */ - { MODEPREFIX, 148250, 1360, 1408, 1440, 1520, 0, 768, 771, 776, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1360x768@120Hz RB */ - { MODEPREFIX, 101000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@60Hz RB */ - { MODEPREFIX, 121750, 1400, 1488, 1632, 1864, 0, 1050, 1053, 1057, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@60Hz */ - { MODEPREFIX, 156000, 1400, 1504, 1648, 1896, 0, 1050, 1053, 1057, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@75Hz */ - { MODEPREFIX, 179500, 1400, 1504, 1656, 1912, 0, 1050, 1053, 1057, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@85Hz */ - { MODEPREFIX, 208000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@120Hz RB */ - { MODEPREFIX, 88750, 1440, 1488, 1520, 1600, 0, 900, 903, 909, 926, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@60Hz RB */ - { MODEPREFIX, 106500, 1440, 1520, 1672, 1904, 0, 900, 903, 909, 934, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@60Hz */ - { MODEPREFIX, 136750, 1440, 1536, 1688, 1936, 0, 900, 903, 909, 942, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@75Hz */ - { MODEPREFIX, 157000, 1440, 1544, 1696, 1952, 0, 900, 903, 909, 948, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@85Hz */ - { MODEPREFIX, 182750, 1440, 1488, 1520, 1600, 0, 900, 903, 909, 953, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@120Hz RB */ - { MODEPREFIX, 162000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@60Hz */ - { MODEPREFIX, 175500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@65Hz */ - { MODEPREFIX, 189000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@70Hz */ - { MODEPREFIX, 202500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@75Hz */ - { MODEPREFIX, 229500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@85Hz */ - { MODEPREFIX, 268250, 1600, 1648, 1680, 1760, 0, 1200, 1203, 1207, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1600x1200@120Hz RB */ - { MODEPREFIX, 119000, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@60Hz RB */ - { MODEPREFIX, 146250, 1680, 1784, 1960, 2240, 0, 1050, 1053, 1059, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@60Hz */ - { MODEPREFIX, 187000, 1680, 1800, 1976, 2272, 0, 1050, 1053, 1059, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@75Hz */ - { MODEPREFIX, 214750, 1680, 1808, 1984, 2288, 0, 1050, 1053, 1059, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@85Hz */ - { MODEPREFIX, 245500, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@120Hz RB */ - { MODEPREFIX, 204750, 1792, 1920, 2120, 2448, 0, 1344, 1345, 1348, 1394, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@60Hz */ - { MODEPREFIX, 261000, 1792, 1888, 2104, 2456, 0, 1344, 1345, 1348, 1417, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@75Hz */ - { MODEPREFIX, 333250, 1792, 1840, 1872, 1952, 0, 1344, 1347, 1351, 1423, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1792x1344@120Hz RB */ - { MODEPREFIX, 218250, 1856, 1952, 2176, 2528, 0, 1392, 1393, 1396, 1439, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@60Hz */ - { MODEPREFIX, 288000, 1856, 1984, 2208, 2560, 0, 1392, 1393, 1396, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@75Hz */ - { MODEPREFIX, 356500, 1856, 1904, 1936, 2016, 0, 1392, 1395, 1399, 1474, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1856x1392@120Hz RB */ - { MODEPREFIX, 154000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1235, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@60Hz RB */ - { MODEPREFIX, 193250, 1920, 2056, 2256, 2592, 0, 1200, 1203, 1209, 1245, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@60Hz */ - { MODEPREFIX, 245250, 1920, 2056, 2264, 2608, 0, 1200, 1203, 1209, 1255, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@75Hz */ - { MODEPREFIX, 281250, 1920, 2064, 2272, 2624, 0, 1200, 1203, 1209, 1262, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@85Hz */ - { MODEPREFIX, 317000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@120Hz RB */ - { MODEPREFIX, 234000, 1920, 2048, 2256, 2600, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@60Hz */ - { MODEPREFIX, 297000, 1920, 2064, 2288, 2640, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@75Hz */ - { MODEPREFIX, 380500, 1920, 1968, 2000, 2080, 0, 1440, 1443, 1447, 1525, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1440@120Hz RB */ - { MODEPREFIX, 268500, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1646, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@60Hz RB */ - { MODEPREFIX, 348500, 2560, 2752, 3032, 3504, 0, 1600, 1603, 1609, 1658, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@60Hz */ - { MODEPREFIX, 443250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1672, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@75Hz */ - { MODEPREFIX, 505250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@85Hz */ - { MODEPREFIX, 552750, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1694, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@120Hz RB */ -}; - -#define LEVEL_DMT 0 -#define LEVEL_GTF 1 -#define LEVEL_CVT 2 - -static int -MonitorStandardTimingLevel(xf86MonPtr DDC) -{ - if (DDC->ver.revision >= 2) { - if (DDC->ver.revision >= 4 && CVT_SUPPORTED(DDC->features.msc)) { - return LEVEL_CVT; - } - return LEVEL_GTF; - } - return LEVEL_DMT; -} - -static int -ModeRefresh(const DisplayModeRec *mode) -{ - return (int)(xf86ModeVRefresh(mode) + 0.5); -} - -/* - * If rb is not set, then we'll not consider reduced-blanking modes as - * part of the DMT pool. For the 'standard' EDID mode descriptor there's - * no way to specify whether the mode should be RB or not. - */ -DisplayModePtr -FindDMTMode(int hsize, int vsize, int refresh, Bool rb) -{ - int i; - const DisplayModeRec *ret; - - for (i = 0; i < sizeof(DMTModes) / sizeof(DisplayModeRec); i++) { - ret = &DMTModes[i]; - - if (!rb && xf86ModeIsReduced(ret)) - continue; - - if (ret->HDisplay == hsize && - ret->VDisplay == vsize && - refresh == ModeRefresh(ret)) - return xf86DuplicateMode(ret); - } - - return NULL; -} - -/* - * Appendix B of the EDID 1.4 spec defines the right thing to do here. - * If the timing given here matches a mode defined in the VESA DMT standard, - * we _must_ use that. If the device supports CVT modes, then we should - * generate a CVT timing. If both of the above fail, use GTF. - * - * There are some wrinkles here. EDID 1.1 and 1.0 sinks can't really - * "support" GTF, since it wasn't a standard yet; so if they ask for a - * timing in this section that isn't defined in DMT, returning a GTF mode - * may not actually be valid. EDID 1.3 sinks often report support for - * some CVT modes, but they are not required to support CVT timings for - * modes in the standard timing descriptor, so we should _not_ treat them - * as CVT-compliant (unless specified in an extension block I suppose). - * - * EDID 1.4 requires that all sink devices support both GTF and CVT timings - * for modes in this section, but does say that CVT is preferred. - */ -static DisplayModePtr -DDCModesFromStandardTiming(struct std_timings *timing, ddc_quirk_t quirks, - int timing_level, Bool rb) -{ - DisplayModePtr Modes = NULL, Mode = NULL; - int i, hsize, vsize, refresh; - - for (i = 0; i < STD_TIMINGS; i++) { - hsize = timing[i].hsize; - vsize = timing[i].vsize; - refresh = timing[i].refresh; - - /* HDTV hack, because you can't say 1366 */ - if (refresh == 60 && - ((hsize == 1360 && vsize == 765) || - (hsize == 1368 && vsize == 769))) { - Mode = xf86CVTMode(1366, 768, 60, FALSE, FALSE); - Mode->HDisplay = 1366; - Mode->VSyncStart--; - Mode->VSyncEnd--; - } else if (hsize && vsize && refresh) { - Mode = FindDMTMode(hsize, vsize, refresh, rb); - - if (!Mode) { - if (timing_level == LEVEL_CVT) - /* pass rb here too? */ - Mode = xf86CVTMode(hsize, vsize, refresh, FALSE, FALSE); - else if (timing_level == LEVEL_GTF) - Mode = xf86GTFMode(hsize, vsize, refresh, FALSE, FALSE); - } - - } - - if (Mode) { - Mode->type = M_T_DRIVER; - Modes = xf86ModesAdd(Modes, Mode); - } - Mode = NULL; - } - - return Modes; -} - -static void -DDCModeDoInterlaceQuirks(DisplayModePtr mode) -{ - /* - * EDID is delightfully ambiguous about how interlaced modes are to be - * encoded. X's internal representation is of frame height, but some - * HDTV detailed timings are encoded as field height. - * - * The format list here is from CEA, in frame size. Technically we - * should be checking refresh rate too. Whatever. - */ - static const struct { - int w, h; - } cea_interlaced[] = { - { 1920, 1080 }, - { 720, 480 }, - { 1440, 480 }, - { 2880, 480 }, - { 720, 576 }, - { 1440, 576 }, - { 2880, 576 }, - }; - static const int n_modes = sizeof(cea_interlaced)/sizeof(cea_interlaced[0]); - int i; - - for (i = 0; i < n_modes; i++) { - if ((mode->HDisplay == cea_interlaced[i].w) && - (mode->VDisplay == cea_interlaced[i].h / 2)) { - mode->VDisplay *= 2; - mode->VSyncStart *= 2; - mode->VSyncEnd *= 2; - mode->VTotal *= 2; - mode->VTotal |= 1; - } - } - - mode->Flags |= V_INTERLACE; -} - -/* - * - */ -static DisplayModePtr -DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing, - Bool preferred, ddc_quirk_t quirks) -{ - DisplayModePtr Mode; - - /* - * Refuse to create modes that are insufficiently large. 64 is a random - * number, maybe the spec says something about what the minimum is. In - * particular I see this frequently with _old_ EDID, 1.0 or so, so maybe - * our parser is just being too aggresive there. - */ - if (timing->h_active < 64 || timing->v_active < 64) { - xf86DrvMsg(scrnIndex, X_INFO, - "%s: Ignoring tiny %dx%d mode\n", __func__, - timing->h_active, timing->v_active); - return NULL; - } - - /* We don't do stereo */ - if (timing->stereo) { - xf86DrvMsg(scrnIndex, X_INFO, - "%s: Ignoring: We don't handle stereo.\n", __func__); - return NULL; - } - - /* We only do seperate sync currently */ - if (timing->sync != 0x03) { - xf86DrvMsg(scrnIndex, X_INFO, - "%s: %dx%d Warning: We only handle separate" - " sync.\n", __func__, timing->h_active, timing->v_active); - } - - Mode = xnfcalloc(1, sizeof(DisplayModeRec)); - - Mode->type = M_T_DRIVER; - if (preferred) - Mode->type |= M_T_PREFERRED; - - if( ( quirks & DDC_QUIRK_135_CLOCK_TOO_HIGH ) && - timing->clock == 135000000 ) - Mode->Clock = 108880; - else - Mode->Clock = timing->clock / 1000.0; - - Mode->HDisplay = timing->h_active; - Mode->HSyncStart = timing->h_active + timing->h_sync_off; - Mode->HSyncEnd = Mode->HSyncStart + timing->h_sync_width; - Mode->HTotal = timing->h_active + timing->h_blanking; - - Mode->VDisplay = timing->v_active; - Mode->VSyncStart = timing->v_active + timing->v_sync_off; - Mode->VSyncEnd = Mode->VSyncStart + timing->v_sync_width; - Mode->VTotal = timing->v_active + timing->v_blanking; - - /* perform basic check on the detail timing */ - if (Mode->HSyncEnd > Mode->HTotal || Mode->VSyncEnd > Mode->VTotal) { - xfree(Mode); - return NULL; - } - - /* We ignore h/v_size and h/v_border for now. */ - - if (timing->interlaced) - DDCModeDoInterlaceQuirks(Mode); - - if (quirks & DDC_QUIRK_DETAILED_SYNC_PP) - Mode->Flags |= V_PVSYNC | V_PHSYNC; - else { - if (timing->misc & 0x02) - Mode->Flags |= V_PVSYNC; - else - Mode->Flags |= V_NVSYNC; - - if (timing->misc & 0x01) - Mode->Flags |= V_PHSYNC; - else - Mode->Flags |= V_NHSYNC; - } - - xf86SetModeDefaultName(Mode); - - return Mode; -} - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) -static DisplayModePtr -DDCModesFromCVT(int scrnIndex, struct cvt_timings *t) -{ - DisplayModePtr modes = NULL; - int i; - - for (i = 0; i < 4; i++) { - if (t[i].height) { - if (t[i].rates & 0x10) - modes = xf86ModesAdd(modes, - xf86CVTMode(t[i].width, t[i].height, 50, 0, 0)); - if (t[i].rates & 0x08) - modes = xf86ModesAdd(modes, - xf86CVTMode(t[i].width, t[i].height, 60, 0, 0)); - if (t[i].rates & 0x04) - modes = xf86ModesAdd(modes, - xf86CVTMode(t[i].width, t[i].height, 75, 0, 0)); - if (t[i].rates & 0x02) - modes = xf86ModesAdd(modes, - xf86CVTMode(t[i].width, t[i].height, 85, 0, 0)); - if (t[i].rates & 0x01) - modes = xf86ModesAdd(modes, - xf86CVTMode(t[i].width, t[i].height, 60, 1, 0)); - } else break; - } - - return modes; -} -#endif - -static const struct { - short w; - short h; - short r; - short rb; -} EstIIIModes[] = { - /* byte 6 */ - { 640, 350, 85, 0 }, - { 640, 400, 85, 0 }, - { 720, 400, 85, 0 }, - { 640, 480, 85, 0 }, - { 848, 480, 60, 0 }, - { 800, 600, 85, 0 }, - { 1024, 768, 85, 0 }, - { 1152, 864, 75, 0 }, - /* byte 7 */ - { 1280, 768, 60, 1 }, - { 1280, 768, 60, 0 }, - { 1280, 768, 75, 0 }, - { 1280, 768, 85, 0 }, - { 1280, 960, 60, 0 }, - { 1280, 960, 85, 0 }, - { 1280, 1024, 60, 0 }, - { 1280, 1024, 85, 0 }, - /* byte 8 */ - { 1360, 768, 60, 0 }, - { 1440, 900, 60, 1 }, - { 1440, 900, 60, 0 }, - { 1440, 900, 75, 0 }, - { 1440, 900, 85, 0 }, - { 1400, 1050, 60, 1 }, - { 1400, 1050, 60, 0 }, - { 1400, 1050, 75, 0 }, - /* byte 9 */ - { 1400, 1050, 85, 0 }, - { 1680, 1050, 60, 1 }, - { 1680, 1050, 60, 0 }, - { 1680, 1050, 75, 0 }, - { 1680, 1050, 85, 0 }, - { 1600, 1200, 60, 0 }, - { 1600, 1200, 65, 0 }, - { 1600, 1200, 70, 0 }, - /* byte 10 */ - { 1600, 1200, 75, 0 }, - { 1600, 1200, 85, 0 }, - { 1792, 1344, 60, 0 }, - { 1792, 1344, 85, 0 }, - { 1856, 1392, 60, 0 }, - { 1856, 1392, 75, 0 }, - { 1920, 1200, 60, 1 }, - { 1920, 1200, 60, 0 }, - /* byte 11 */ - { 1920, 1200, 75, 0 }, - { 1920, 1200, 85, 0 }, - { 1920, 1440, 60, 0 }, - { 1920, 1440, 75, 0 }, -}; - -static DisplayModePtr -DDCModesFromEstIII(unsigned char *est) -{ - DisplayModePtr modes = NULL; - int i, j, m; - - for (i = 0; i < 6; i++) { - for (j = 7; j > 0; j--) { - if (est[i] & (1 << j)) { - m = (i * 8) + (7 - j); - modes = xf86ModesAdd(modes, - FindDMTMode(EstIIIModes[m].w, - EstIIIModes[m].h, - EstIIIModes[m].r, - EstIIIModes[m].rb)); - } - } - } - - return modes; -} - -/* - * This is only valid when the sink claims to be continuous-frequency - * but does not supply a detailed range descriptor. Such sinks are - * arguably broken. Currently the mode validation code isn't aware of - * this; the non-RANDR code even punts the decision of optional sync - * range checking to the driver. Loss. - */ -static void -DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes) -{ - DisplayModePtr Mode = Modes; - - if (!Monitor || !Modes) - return; - - /* set up the ranges for scanning through the modes */ - Monitor->nHsync = 1; - Monitor->hsync[0].lo = 1024.0; - Monitor->hsync[0].hi = 0.0; - - Monitor->nVrefresh = 1; - Monitor->vrefresh[0].lo = 1024.0; - Monitor->vrefresh[0].hi = 0.0; - - while (Mode) { - if (!Mode->HSync) - Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal); - - if (!Mode->VRefresh) - Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / - ((float) (Mode->HTotal * Mode->VTotal)); - - if (Mode->HSync < Monitor->hsync[0].lo) - Monitor->hsync[0].lo = Mode->HSync; - - if (Mode->HSync > Monitor->hsync[0].hi) - Monitor->hsync[0].hi = Mode->HSync; - - if (Mode->VRefresh < Monitor->vrefresh[0].lo) - Monitor->vrefresh[0].lo = Mode->VRefresh; - - if (Mode->VRefresh > Monitor->vrefresh[0].hi) - Monitor->vrefresh[0].hi = Mode->VRefresh; - - Mode = Mode->next; - } -} - -ddc_quirk_t -xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose) -{ - ddc_quirk_t quirks; - int i; - - quirks = DDC_QUIRK_NONE; - for (i = 0; ddc_quirks[i].detect; i++) { - if (ddc_quirks[i].detect (scrnIndex, DDC)) { - if (verbose) { - xf86DrvMsg (scrnIndex, X_INFO, " EDID quirk: %s\n", - ddc_quirks[i].description); - } - quirks |= ddc_quirks[i].quirk; - } - } - - return quirks; -} - -void xf86DetTimingApplyQuirks(struct detailed_monitor_section *det_mon, - ddc_quirk_t quirks, - int hsize, int vsize) -{ - if (det_mon->type != DT) - return; - - if (quirks & DDC_QUIRK_DETAILED_H_IN_CM) - det_mon->section.d_timings.h_size *= 10; - - if (quirks & DDC_QUIRK_DETAILED_V_IN_CM) - det_mon->section.d_timings.v_size *= 10; - - if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) { - det_mon->section.d_timings.h_size = 10 * hsize; - det_mon->section.d_timings.v_size = 10 * vsize; - } -} - -/** - * Applies monitor-specific quirks to the decoded EDID information. - * - * Note that some quirks applying to the mode list are still implemented in - * xf86DDCGetModes. - */ -void -xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC) -{ - ddc_quirk_t quirks = xf86DDCDetectQuirks (scrnIndex, DDC, FALSE); - int i; - - for (i = 0; i < DET_TIMINGS; i++) { - xf86DetTimingApplyQuirks(DDC->det_mon + i, quirks, - DDC->features.hsize, - DDC->features.vsize); - } -} - -/** - * Walks the modes list, finding the mode with the largest area which is - * closest to the target refresh rate, and marks it as the only preferred mode. -*/ -static void -xf86DDCSetPreferredRefresh(int scrnIndex, DisplayModePtr modes, - float target_refresh) -{ - DisplayModePtr mode, best = modes; - - for (mode = modes; mode; mode = mode->next) - { - mode->type &= ~M_T_PREFERRED; - - if (mode == best) continue; - - if (mode->HDisplay * mode->VDisplay > - best->HDisplay * best->VDisplay) - { - best = mode; - continue; - } - if (mode->HDisplay * mode->VDisplay == - best->HDisplay * best->VDisplay) - { - double mode_refresh = xf86ModeVRefresh (mode); - double best_refresh = xf86ModeVRefresh (best); - double mode_dist = fabs(mode_refresh - target_refresh); - double best_dist = fabs(best_refresh - target_refresh); - - if (mode_dist < best_dist) - { - best = mode; - continue; - } - } - } - if (best) - best->type |= M_T_PREFERRED; -} - -#define CEA_VIDEO_MODES_NUM 64 -static const DisplayModeRec CEAVideoModes[CEA_VIDEO_MODES_NUM] = { - { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 1:640x480@60Hz */ - { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 2:720x480@60Hz */ - { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 3:720x480@60Hz */ - { MODEPREFIX, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 4: 1280x720@60Hz */ - { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 5:1920x1080i@60Hz */ - { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 6:1440x480i@60Hz */ - { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 7:1440x480i@60Hz */ - { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 8:1440x240@60Hz */ - { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 9:1440x240@60Hz */ - { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 10:2880x480i@60Hz */ - { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 11:2880x480i@60Hz */ - { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 12:2880x240@60Hz */ - { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 13:2880x240@60Hz */ - { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 14:1440x480@60Hz */ - { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 15:1440x480@60Hz */ - { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 16:1920x1080@60Hz */ - { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 17:720x576@50Hz */ - { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 18:720x576@50Hz */ - { MODEPREFIX, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 19: 1280x720@50Hz */ - { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 20:1920x1080i@50Hz */ - { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 21:1440x576i@50Hz */ - { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 22:1440x576i@50Hz */ - { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 23:1440x288@50Hz */ - { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 24:1440x288@50Hz */ - { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 25:2880x576i@50Hz */ - { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 26:2880x576i@50Hz */ - { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 27:2880x288@50Hz */ - { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 28:2880x288@50Hz */ - { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 29:1440x576@50Hz */ - { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 30:1440x576@50Hz */ - { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 31:1920x1080@50Hz */ - { MODEPREFIX, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 32:1920x1080@24Hz */ - { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 33:1920x1080@25Hz */ - { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 34:1920x1080@30Hz */ - { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 35:2880x480@60Hz */ - { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 36:2880x480@60Hz */ - { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 37:2880x576@50Hz */ - { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 38:2880x576@50Hz */ - { MODEPREFIX, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, V_PHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 39:1920x1080i@50Hz */ - { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 40:1920x1080i@100Hz */ - { MODEPREFIX, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 41:1280x720@100Hz */ - { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 42:720x576@100Hz */ - { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 43:720x576@100Hz */ - { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 44:1440x576i@100Hz */ - { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 45:1440x576i@100Hz */ - { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 46:1920x1080i@120Hz */ - { MODEPREFIX, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 47:1280x720@120Hz */ - { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 48:720x480@120Hz */ - { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 49:720x480@120Hz */ - { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 50:1440x480i@120Hz */ - { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 51:1440x480i@120Hz */ - { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 52:720x576@200Hz */ - { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 53:720x576@200Hz */ - { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 54:1440x576i@200Hz */ - { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 55:1440x576i@200Hz */ - { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 56:720x480@240Hz */ - { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 57:720x480@240Hz */ - { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 58:1440x480i@240 */ - { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 59:1440x480i@240 */ - { MODEPREFIX, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 60: 1280x720@24Hz */ - { MODEPREFIX, 74250, 3700, 3740, 1430, 3960, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 61: 1280x720@25Hz */ - { MODEPREFIX, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 62: 1280x720@30Hz */ - { MODEPREFIX, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 63: 1920x1080@120Hz */ - { MODEPREFIX, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 64:1920x1080@100Hz */ -}; - -/* chose mode line by cea short video descriptor*/ -static void handle_cea_svd(struct cea_video_block *video, void *data) -{ - DisplayModePtr Mode; - DisplayModePtr *Modes = (DisplayModePtr *) data; - int vid; - - vid = video ->video_code & 0x7f; - if (vid < CEA_VIDEO_MODES_NUM) { - Mode = xf86DuplicateMode(CEAVideoModes + vid); - *Modes = xf86ModesAdd(*Modes, Mode); - } -} - -static DisplayModePtr -DDCModesFromCEAExtension(int scrnIndex, xf86MonPtr MonPtr) -{ - DisplayModePtr Modes = NULL; - - xf86ForEachVideoBlock(MonPtr, - handle_cea_svd, - &Modes); - - return Modes; -} - -struct det_modes_parameter { - xf86MonPtr DDC; - ddc_quirk_t quirks; - DisplayModePtr Modes; - Bool rb; - Bool preferred; - int timing_level; -}; - -static void handle_detailed_modes(struct detailed_monitor_section *det_mon, - void *data) -{ - DisplayModePtr Mode; - struct det_modes_parameter *p = (struct det_modes_parameter *)data; - - xf86DetTimingApplyQuirks(det_mon,p->quirks, - p->DDC->features.hsize, - p->DDC->features.vsize); - - switch (det_mon->type) { - case DT: - Mode = DDCModeFromDetailedTiming(p->DDC->scrnIndex, - &det_mon->section.d_timings, - p->preferred, - p->quirks); - p->preferred = FALSE; - p->Modes = xf86ModesAdd(p->Modes, Mode); - break; - case DS_STD_TIMINGS: - Mode = DDCModesFromStandardTiming(det_mon->section.std_t, - p->quirks, p->timing_level,p->rb); - p->Modes = xf86ModesAdd(p->Modes, Mode); - break; -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - case DS_CVT: - Mode = DDCModesFromCVT(p->DDC->scrnIndex, det_mon->section.cvt); - p->Modes = xf86ModesAdd(p->Modes, Mode); - break; -#endif - case DS_EST_III: - Mode = DDCModesFromEstIII(det_mon->section.est_iii); - p->Modes = xf86ModesAdd(p->Modes, Mode); - break; - default: - break; - } -} - -DisplayModePtr -xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC) -{ - DisplayModePtr Modes = NULL, Mode; - ddc_quirk_t quirks; - Bool preferred, rb; - int timing_level; - struct det_modes_parameter p; - - xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n", - DDC->vendor.name, DDC->vendor.prod_id); - - quirks = xf86DDCDetectQuirks(scrnIndex, DDC, TRUE); - - preferred = PREFERRED_TIMING_MODE(DDC->features.msc); - if (DDC->ver.revision >= 4) - preferred = TRUE; - if (quirks & DDC_QUIRK_FIRST_DETAILED_PREFERRED) - preferred = TRUE; - if (quirks & (DDC_QUIRK_PREFER_LARGE_60 | DDC_QUIRK_PREFER_LARGE_75)) - preferred = FALSE; - - rb = xf86MonitorSupportsReducedBlanking(DDC); - - timing_level = MonitorStandardTimingLevel(DDC); - - p.quirks = quirks; - p.DDC = DDC; - p.Modes = Modes; - p.rb = rb; - p.preferred = preferred; - p.timing_level = timing_level; - xf86ForEachDetailedBlock(DDC, handle_detailed_modes, &p); - Modes = p.Modes; - - /* Add established timings */ - Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks); - Modes = xf86ModesAdd(Modes, Mode); - - /* Add standard timings */ - Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb); - Modes = xf86ModesAdd(Modes, Mode); - - /* Add cea-extension mode timings */ - Mode = DDCModesFromCEAExtension(scrnIndex,DDC); - Modes = xf86ModesAdd(Modes, Mode); - - if (quirks & DDC_QUIRK_PREFER_LARGE_60) - xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60); - - if (quirks & DDC_QUIRK_PREFER_LARGE_75) - xf86DDCSetPreferredRefresh(scrnIndex, Modes, 75); - - Modes = xf86PruneDuplicateModes(Modes); - - return Modes; -} - -struct det_mon_parameter { - MonPtr Monitor; - ddc_quirk_t quirks; - Bool have_hsync; - Bool have_vrefresh; - Bool have_maxpixclock; -}; - -static void handle_detailed_monset(struct detailed_monitor_section *det_mon, - void *data) -{ - int clock; - struct det_mon_parameter *p = (struct det_mon_parameter *)data; - int scrnIndex = ((xf86MonPtr)(p->Monitor->DDC))->scrnIndex; - - switch (det_mon->type) { - case DS_RANGES: - if (!p->have_hsync) { - if (!p->Monitor->nHsync) - xf86DrvMsg(scrnIndex, X_INFO, - "Using EDID range info for horizontal sync\n"); - p->Monitor->hsync[p->Monitor->nHsync].lo = - det_mon->section.ranges.min_h; - p->Monitor->hsync[p->Monitor->nHsync].hi = - det_mon->section.ranges.max_h; - p->Monitor->nHsync++; - } else { - xf86DrvMsg(scrnIndex, X_INFO, - "Using hsync ranges from config file\n"); - } - - if (!p->have_vrefresh) { - if (!p->Monitor->nVrefresh) - xf86DrvMsg(scrnIndex, X_INFO, - "Using EDID range info for vertical refresh\n"); - p->Monitor->vrefresh[p->Monitor->nVrefresh].lo = - det_mon->section.ranges.min_v; - p->Monitor->vrefresh[p->Monitor->nVrefresh].hi = - det_mon->section.ranges.max_v; - p->Monitor->nVrefresh++; - } else { - xf86DrvMsg(scrnIndex, X_INFO, - "Using vrefresh ranges from config file\n"); - } - - clock = det_mon->section.ranges.max_clock * 1000; - if (p->quirks & DDC_QUIRK_DVI_SINGLE_LINK) - clock = min(clock, 165000); - if (!p->have_maxpixclock && clock > p->Monitor->maxPixClock) - p->Monitor->maxPixClock = clock; - - break; - default: - break; - } -} - -/* - * Fill out MonPtr with xf86MonPtr information. - */ -void -xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC) -{ - DisplayModePtr Modes = NULL, Mode; - struct det_mon_parameter p; - - if (!Monitor || !DDC) - return; - - Monitor->DDC = DDC; - - if (Monitor->widthmm <= 0 || Monitor->heightmm <= 0) { - Monitor->widthmm = 10 * DDC->features.hsize; - Monitor->heightmm = 10 * DDC->features.vsize; - } - - Monitor->reducedblanking = xf86MonitorSupportsReducedBlanking(DDC); - - Modes = xf86DDCGetModes(scrnIndex, DDC); - - /* Go through the detailed monitor sections */ - p.Monitor = Monitor; - p.quirks = xf86DDCDetectQuirks(scrnIndex, Monitor->DDC, FALSE); - p.have_hsync = (Monitor->nHsync != 0); - p.have_vrefresh = (Monitor->nVrefresh != 0); - p.have_maxpixclock = (Monitor->maxPixClock != 0); - xf86ForEachDetailedBlock(DDC, handle_detailed_monset, &p); - - if (Modes) { - /* Print Modes */ - xf86DrvMsg(scrnIndex, X_INFO, "Printing DDC gathered Modelines:\n"); - - Mode = Modes; - while (Mode) { - xf86PrintModeline(scrnIndex, Mode); - Mode = Mode->next; - } - - /* Do we still need ranges to be filled in? */ - if (!Monitor->nHsync || !Monitor->nVrefresh) - DDCGuessRangesFromModes(scrnIndex, Monitor, Modes); - - /* look for last Mode */ - Mode = Modes; - - while (Mode->next) - Mode = Mode->next; - - /* add to MonPtr */ - if (Monitor->Modes) { - Monitor->Last->next = Modes; - Modes->prev = Monitor->Last; - Monitor->Last = Mode; - } else { - Monitor->Modes = Modes; - Monitor->Last = Mode; - } - } -} +/* + * Copyright 2006 Luc Verhaegen. + * Copyright 2008 Red Hat, Inc. + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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. + */ + +/** + * @file This file covers code to convert a xf86MonPtr containing EDID-probed + * information into a list of modes, including applying monitor-specific + * quirks to fix broken EDID data. + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#define _PARSE_EDID_ +#include "xf86.h" +#include "xf86DDC.h" +#include <X11/Xatom.h> +#include "property.h" +#include "propertyst.h" +#include "xf86Crtc.h" +#include <string.h> +#include <math.h> + +static void handle_detailed_rblank(struct detailed_monitor_section *det_mon, + void *data) +{ + if (det_mon->type == DS_RANGES) + if (det_mon->section.ranges.supported_blanking & CVT_REDUCED) + *(Bool*)data = TRUE; +} + +static Bool +xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC) +{ + /* EDID 1.4 explicitly defines RB support */ + if (DDC->ver.revision >= 4) { + Bool ret = FALSE; + + xf86ForEachDetailedBlock(DDC, handle_detailed_rblank, &ret); + return ret; + } + + /* For anything older, assume digital means RB support. Boo. */ + if (DDC->features.input_type) + return TRUE; + + return FALSE; +} + +static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC) +{ + /* Belinea 10 15 55 */ + if (memcmp (DDC->vendor.name, "MAX", 4) == 0 && + ((DDC->vendor.prod_id == 1516) || + (DDC->vendor.prod_id == 0x77e))) + return TRUE; + + /* Acer AL1706 */ + if (memcmp (DDC->vendor.name, "ACR", 4) == 0 && + DDC->vendor.prod_id == 44358) + return TRUE; + + /* Bug #10814: Samsung SyncMaster 225BW */ + if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && + DDC->vendor.prod_id == 596) + return TRUE; + + /* Bug #10545: Samsung SyncMaster 226BW */ + if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && + DDC->vendor.prod_id == 638) + return TRUE; + + /* Acer F51 */ + if (memcmp (DDC->vendor.name, "API", 4) == 0 && + DDC->vendor.prod_id == 0x7602) + return TRUE; + + + return FALSE; +} + +static Bool quirk_prefer_large_75 (int scrnIndex, xf86MonPtr DDC) +{ + /* Bug #11603: Funai Electronics PM36B */ + if (memcmp (DDC->vendor.name, "FCM", 4) == 0 && + DDC->vendor.prod_id == 13600) + return TRUE; + + return FALSE; +} + +static Bool quirk_detailed_h_in_cm (int scrnIndex, xf86MonPtr DDC) +{ + /* Bug #11603: Funai Electronics PM36B */ + if (memcmp (DDC->vendor.name, "FCM", 4) == 0 && + DDC->vendor.prod_id == 13600) + return TRUE; + + return FALSE; +} + +static Bool quirk_detailed_v_in_cm (int scrnIndex, xf86MonPtr DDC) +{ + /* Bug #11603: Funai Electronics PM36B */ + if (memcmp (DDC->vendor.name, "FCM", 4) == 0 && + DDC->vendor.prod_id == 13600) + return TRUE; + + /* Bug #21000: LGPhilipsLCD LP154W01-TLAJ */ + if (memcmp (DDC->vendor.name, "LPL", 4) == 0 && + DDC->vendor.prod_id == 47360) + return TRUE; + + /* Bug #10304: LGPhilipsLCD LP154W01-A5 */ + if (memcmp(DDC->vendor.name, "LPL", 4) == 0 && + DDC->vendor.prod_id == 0) + return TRUE; + + /* Bug #24482: LGPhilipsLCD LP154W01-TLA1 */ + if (memcmp(DDC->vendor.name, "LPL", 4) == 0 && + DDC->vendor.prod_id == 0x2a00) + return TRUE; + + /* Bug #21750: Samsung Syncmaster 2333HD */ + if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && + DDC->vendor.prod_id == 1157) + return TRUE; + + return FALSE; +} + +static Bool quirk_detailed_use_maximum_size (int scrnIndex, xf86MonPtr DDC) +{ + /* Bug #21324: Iiyama Vision Master 450 */ + if (memcmp (DDC->vendor.name, "IVM", 4) == 0 && + DDC->vendor.prod_id == 6400) + return TRUE; + + return FALSE; +} + +static Bool quirk_135_clock_too_high (int scrnIndex, xf86MonPtr DDC) +{ + /* Envision Peripherals, Inc. EN-7100e. See bug #9550. */ + if (memcmp (DDC->vendor.name, "EPI", 4) == 0 && + DDC->vendor.prod_id == 59264) + return TRUE; + + return FALSE; +} + +static Bool quirk_first_detailed_preferred (int scrnIndex, xf86MonPtr DDC) +{ + /* Philips 107p5 CRT. Reported on xorg@ with pastebin. */ + if (memcmp (DDC->vendor.name, "PHL", 4) == 0 && + DDC->vendor.prod_id == 57364) + return TRUE; + + /* Proview AY765C 17" LCD. See bug #15160*/ + if (memcmp (DDC->vendor.name, "PTS", 4) == 0 && + DDC->vendor.prod_id == 765) + return TRUE; + + /* ACR of some sort RH #284231 */ + if (memcmp (DDC->vendor.name, "ACR", 4) == 0 && + DDC->vendor.prod_id == 2423) + return TRUE; + + /* Peacock Ergovision 19. See rh#492359 */ + if (memcmp (DDC->vendor.name, "PEA", 4) == 0 && + DDC->vendor.prod_id == 9003) + return TRUE; + + return FALSE; +} + +static Bool quirk_detailed_sync_pp(int scrnIndex, xf86MonPtr DDC) +{ + /* Bug #12439: Samsung SyncMaster 205BW */ + if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && + DDC->vendor.prod_id == 541) + return TRUE; + return FALSE; +} + +/* This should probably be made more generic */ +static Bool quirk_dvi_single_link(int scrnIndex, xf86MonPtr DDC) +{ + /* Red Hat bug #453106: Apple 23" Cinema Display */ + if (memcmp (DDC->vendor.name, "APL", 4) == 0 && + DDC->vendor.prod_id == 0x921c) + return TRUE; + return FALSE; +} + +typedef struct { + Bool (*detect) (int scrnIndex, xf86MonPtr DDC); + ddc_quirk_t quirk; + char *description; +} ddc_quirk_map_t; + +static const ddc_quirk_map_t ddc_quirks[] = { + { + quirk_prefer_large_60, DDC_QUIRK_PREFER_LARGE_60, + "Detailed timing is not preferred, use largest mode at 60Hz" + }, + { + quirk_135_clock_too_high, DDC_QUIRK_135_CLOCK_TOO_HIGH, + "Recommended 135MHz pixel clock is too high" + }, + { + quirk_prefer_large_75, DDC_QUIRK_PREFER_LARGE_75, + "Detailed timing is not preferred, use largest mode at 75Hz" + }, + { + quirk_detailed_h_in_cm, DDC_QUIRK_DETAILED_H_IN_CM, + "Detailed timings give horizontal size in cm." + }, + { + quirk_detailed_v_in_cm, DDC_QUIRK_DETAILED_V_IN_CM, + "Detailed timings give vertical size in cm." + }, + { + quirk_detailed_use_maximum_size, DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE, + "Use maximum size instead of detailed timing sizes." + }, + { + quirk_first_detailed_preferred, DDC_QUIRK_FIRST_DETAILED_PREFERRED, + "First detailed timing was not marked as preferred." + }, + { + quirk_detailed_sync_pp, DDC_QUIRK_DETAILED_SYNC_PP, + "Use +hsync +vsync for detailed timing." + }, + { + quirk_dvi_single_link, DDC_QUIRK_DVI_SINGLE_LINK, + "Forcing maximum pixel clock to single DVI link." + }, + { + NULL, DDC_QUIRK_NONE, + "No known quirks" + }, +}; + +/* + * These more or less come from the DMT spec. The 720x400 modes are + * inferred from historical 80x25 practice. The 640x480@67 and 832x624@75 + * modes are old-school Mac modes. The EDID spec says the 1152x864@75 mode + * should be 1152x870, again for the Mac, but instead we use the x864 DMT + * mode. + * + * The DMT modes have been fact-checked; the rest are mild guesses. + */ +#define MODEPREFIX NULL, NULL, NULL, 0, M_T_DRIVER +#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 + +static const DisplayModeRec DDCEstablishedModes[17] = { + { MODEPREFIX, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */ + { MODEPREFIX, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */ + { MODEPREFIX, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */ + { MODEPREFIX, 31500, 640, 664, 704, 832, 0, 480, 489, 492, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */ + { MODEPREFIX, 30240, 640, 704, 768, 864, 0, 480, 483, 486, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@67Hz */ + { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */ + { MODEPREFIX, 35500, 720, 738, 846, 900, 0, 400, 421, 423, 449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400@88Hz */ + { MODEPREFIX, 28320, 720, 738, 846, 900, 0, 400, 412, 414, 449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@70Hz */ + { MODEPREFIX, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */ + { MODEPREFIX, 78750, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */ + { MODEPREFIX, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */ + { MODEPREFIX, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */ + { MODEPREFIX, 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 772, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */ + { MODEPREFIX, 57284, 832, 864, 928, 1152, 0, 624, 625, 628, 667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624@75Hz */ + { MODEPREFIX, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */ + { MODEPREFIX, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */ + { MODEPREFIX, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */ +}; + +static DisplayModePtr +DDCModesFromEstablished(int scrnIndex, struct established_timings *timing, + ddc_quirk_t quirks) +{ + DisplayModePtr Modes = NULL, Mode = NULL; + CARD32 bits = (timing->t1) | (timing->t2 << 8) | + ((timing->t_manu & 0x80) << 9); + int i; + + for (i = 0; i < 17; i++) { + if (bits & (0x01 << i)) { + Mode = xf86DuplicateMode(&DDCEstablishedModes[i]); + Modes = xf86ModesAdd(Modes, Mode); + } + } + + return Modes; +} + +/* Autogenerated from the DMT spec */ +const DisplayModeRec DMTModes[] = { + { MODEPREFIX, 31500, 640, 672, 736, 832, 0, 350, 382, 385, 445, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x350@85Hz */ + { MODEPREFIX, 31500, 640, 672, 736, 832, 0, 400, 401, 404, 445, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 640x400@85Hz */ + { MODEPREFIX, 35500, 720, 756, 828, 936, 0, 400, 401, 404, 446, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@85Hz */ + { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */ + { MODEPREFIX, 31500, 640, 664, 704, 832, 0, 480, 489, 492, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */ + { MODEPREFIX, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */ + { MODEPREFIX, 36000, 640, 696, 752, 832, 0, 480, 481, 484, 509, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@85Hz */ + { MODEPREFIX, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */ + { MODEPREFIX, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */ + { MODEPREFIX, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */ + { MODEPREFIX, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */ + { MODEPREFIX, 56250, 800, 832, 896, 1048, 0, 600, 601, 604, 631, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@85Hz */ + { MODEPREFIX, 73250, 800, 848, 880, 960, 0, 600, 603, 607, 636, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 800x600@120Hz RB */ + { MODEPREFIX, 33750, 848, 864, 976, 1088, 0, 480, 486, 494, 517, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 848x480@60Hz */ + { MODEPREFIX, 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 772, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz (interlaced) */ + { MODEPREFIX, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */ + { MODEPREFIX, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */ + { MODEPREFIX, 78750, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */ + { MODEPREFIX, 94500, 1024, 1072, 1168, 1376, 0, 768, 769, 772, 808, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@85Hz */ + { MODEPREFIX, 115500, 1024, 1072, 1104, 1184, 0, 768, 771, 775, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@120Hz RB */ + { MODEPREFIX, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */ + { MODEPREFIX, 68250, 1280, 1328, 1360, 1440, 0, 768, 771, 778, 790, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@60Hz RB */ + { MODEPREFIX, 79500, 1280, 1344, 1472, 1664, 0, 768, 771, 778, 798, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@60Hz */ + { MODEPREFIX, 102250, 1280, 1360, 1488, 1696, 0, 768, 771, 778, 805, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@75Hz */ + { MODEPREFIX, 117500, 1280, 1360, 1496, 1712, 0, 768, 771, 778, 809, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@85Hz */ + { MODEPREFIX, 140250, 1280, 1328, 1360, 1440, 0, 768, 771, 778, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@120Hz RB */ + { MODEPREFIX, 71000, 1280, 1328, 1360, 1440, 0, 800, 803, 809, 823, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@60Hz RB */ + { MODEPREFIX, 83500, 1280, 1352, 1480, 1680, 0, 800, 803, 809, 831, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@60Hz */ + { MODEPREFIX, 106500, 1280, 1360, 1488, 1696, 0, 800, 803, 809, 838, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@75Hz */ + { MODEPREFIX, 122500, 1280, 1360, 1496, 1712, 0, 800, 803, 809, 843, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@85Hz */ + { MODEPREFIX, 146250, 1280, 1328, 1360, 1440, 0, 800, 803, 809, 847, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@120Hz RB */ + { MODEPREFIX, 108000, 1280, 1376, 1488, 1800, 0, 960, 961, 964, 1000, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@60Hz */ + { MODEPREFIX, 148500, 1280, 1344, 1504, 1728, 0, 960, 961, 964, 1011, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@85Hz */ + { MODEPREFIX, 175500, 1280, 1328, 1360, 1440, 0, 960, 963, 967, 1017, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x960@120Hz RB */ + { MODEPREFIX, 108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@60Hz */ + { MODEPREFIX, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */ + { MODEPREFIX, 157500, 1280, 1344, 1504, 1728, 0, 1024, 1025, 1028, 1072, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@85Hz */ + { MODEPREFIX, 187250, 1280, 1328, 1360, 1440, 0, 1024, 1027, 1034, 1084, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x1024@120Hz RB */ + { MODEPREFIX, 85500, 1360, 1424, 1536, 1792, 0, 768, 771, 777, 795, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1360x768@60Hz */ + { MODEPREFIX, 148250, 1360, 1408, 1440, 1520, 0, 768, 771, 776, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1360x768@120Hz RB */ + { MODEPREFIX, 101000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@60Hz RB */ + { MODEPREFIX, 121750, 1400, 1488, 1632, 1864, 0, 1050, 1053, 1057, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@60Hz */ + { MODEPREFIX, 156000, 1400, 1504, 1648, 1896, 0, 1050, 1053, 1057, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@75Hz */ + { MODEPREFIX, 179500, 1400, 1504, 1656, 1912, 0, 1050, 1053, 1057, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@85Hz */ + { MODEPREFIX, 208000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@120Hz RB */ + { MODEPREFIX, 88750, 1440, 1488, 1520, 1600, 0, 900, 903, 909, 926, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@60Hz RB */ + { MODEPREFIX, 106500, 1440, 1520, 1672, 1904, 0, 900, 903, 909, 934, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@60Hz */ + { MODEPREFIX, 136750, 1440, 1536, 1688, 1936, 0, 900, 903, 909, 942, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@75Hz */ + { MODEPREFIX, 157000, 1440, 1544, 1696, 1952, 0, 900, 903, 909, 948, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@85Hz */ + { MODEPREFIX, 182750, 1440, 1488, 1520, 1600, 0, 900, 903, 909, 953, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@120Hz RB */ + { MODEPREFIX, 162000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@60Hz */ + { MODEPREFIX, 175500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@65Hz */ + { MODEPREFIX, 189000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@70Hz */ + { MODEPREFIX, 202500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@75Hz */ + { MODEPREFIX, 229500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@85Hz */ + { MODEPREFIX, 268250, 1600, 1648, 1680, 1760, 0, 1200, 1203, 1207, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1600x1200@120Hz RB */ + { MODEPREFIX, 119000, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@60Hz RB */ + { MODEPREFIX, 146250, 1680, 1784, 1960, 2240, 0, 1050, 1053, 1059, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@60Hz */ + { MODEPREFIX, 187000, 1680, 1800, 1976, 2272, 0, 1050, 1053, 1059, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@75Hz */ + { MODEPREFIX, 214750, 1680, 1808, 1984, 2288, 0, 1050, 1053, 1059, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@85Hz */ + { MODEPREFIX, 245500, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@120Hz RB */ + { MODEPREFIX, 204750, 1792, 1920, 2120, 2448, 0, 1344, 1345, 1348, 1394, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@60Hz */ + { MODEPREFIX, 261000, 1792, 1888, 2104, 2456, 0, 1344, 1345, 1348, 1417, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@75Hz */ + { MODEPREFIX, 333250, 1792, 1840, 1872, 1952, 0, 1344, 1347, 1351, 1423, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1792x1344@120Hz RB */ + { MODEPREFIX, 218250, 1856, 1952, 2176, 2528, 0, 1392, 1393, 1396, 1439, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@60Hz */ + { MODEPREFIX, 288000, 1856, 1984, 2208, 2560, 0, 1392, 1393, 1396, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@75Hz */ + { MODEPREFIX, 356500, 1856, 1904, 1936, 2016, 0, 1392, 1395, 1399, 1474, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1856x1392@120Hz RB */ + { MODEPREFIX, 154000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1235, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@60Hz RB */ + { MODEPREFIX, 193250, 1920, 2056, 2256, 2592, 0, 1200, 1203, 1209, 1245, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@60Hz */ + { MODEPREFIX, 245250, 1920, 2056, 2264, 2608, 0, 1200, 1203, 1209, 1255, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@75Hz */ + { MODEPREFIX, 281250, 1920, 2064, 2272, 2624, 0, 1200, 1203, 1209, 1262, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@85Hz */ + { MODEPREFIX, 317000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@120Hz RB */ + { MODEPREFIX, 234000, 1920, 2048, 2256, 2600, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@60Hz */ + { MODEPREFIX, 297000, 1920, 2064, 2288, 2640, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@75Hz */ + { MODEPREFIX, 380500, 1920, 1968, 2000, 2080, 0, 1440, 1443, 1447, 1525, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1440@120Hz RB */ + { MODEPREFIX, 268500, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1646, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@60Hz RB */ + { MODEPREFIX, 348500, 2560, 2752, 3032, 3504, 0, 1600, 1603, 1609, 1658, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@60Hz */ + { MODEPREFIX, 443250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1672, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@75Hz */ + { MODEPREFIX, 505250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@85Hz */ + { MODEPREFIX, 552750, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1694, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@120Hz RB */ +}; + +#define LEVEL_DMT 0 +#define LEVEL_GTF 1 +#define LEVEL_CVT 2 + +static int +MonitorStandardTimingLevel(xf86MonPtr DDC) +{ + if (DDC->ver.revision >= 2) { + if (DDC->ver.revision >= 4 && CVT_SUPPORTED(DDC->features.msc)) { + return LEVEL_CVT; + } + return LEVEL_GTF; + } + return LEVEL_DMT; +} + +static int +ModeRefresh(const DisplayModeRec *mode) +{ + return (int)(xf86ModeVRefresh(mode) + 0.5); +} + +/* + * If rb is not set, then we'll not consider reduced-blanking modes as + * part of the DMT pool. For the 'standard' EDID mode descriptor there's + * no way to specify whether the mode should be RB or not. + */ +DisplayModePtr +FindDMTMode(int hsize, int vsize, int refresh, Bool rb) +{ + int i; + const DisplayModeRec *ret; + + for (i = 0; i < sizeof(DMTModes) / sizeof(DisplayModeRec); i++) { + ret = &DMTModes[i]; + + if (!rb && xf86ModeIsReduced(ret)) + continue; + + if (ret->HDisplay == hsize && + ret->VDisplay == vsize && + refresh == ModeRefresh(ret)) + return xf86DuplicateMode(ret); + } + + return NULL; +} + +/* + * Appendix B of the EDID 1.4 spec defines the right thing to do here. + * If the timing given here matches a mode defined in the VESA DMT standard, + * we _must_ use that. If the device supports CVT modes, then we should + * generate a CVT timing. If both of the above fail, use GTF. + * + * There are some wrinkles here. EDID 1.1 and 1.0 sinks can't really + * "support" GTF, since it wasn't a standard yet; so if they ask for a + * timing in this section that isn't defined in DMT, returning a GTF mode + * may not actually be valid. EDID 1.3 sinks often report support for + * some CVT modes, but they are not required to support CVT timings for + * modes in the standard timing descriptor, so we should _not_ treat them + * as CVT-compliant (unless specified in an extension block I suppose). + * + * EDID 1.4 requires that all sink devices support both GTF and CVT timings + * for modes in this section, but does say that CVT is preferred. + */ +static DisplayModePtr +DDCModesFromStandardTiming(struct std_timings *timing, ddc_quirk_t quirks, + int timing_level, Bool rb) +{ + DisplayModePtr Modes = NULL, Mode = NULL; + int i, hsize, vsize, refresh; + + for (i = 0; i < STD_TIMINGS; i++) { + hsize = timing[i].hsize; + vsize = timing[i].vsize; + refresh = timing[i].refresh; + + /* HDTV hack, because you can't say 1366 */ + if (refresh == 60 && + ((hsize == 1360 && vsize == 765) || + (hsize == 1368 && vsize == 769))) { + Mode = xf86CVTMode(1366, 768, 60, FALSE, FALSE); + Mode->HDisplay = 1366; + Mode->VSyncStart--; + Mode->VSyncEnd--; + } else if (hsize && vsize && refresh) { + Mode = FindDMTMode(hsize, vsize, refresh, rb); + + if (!Mode) { + if (timing_level == LEVEL_CVT) + /* pass rb here too? */ + Mode = xf86CVTMode(hsize, vsize, refresh, FALSE, FALSE); + else if (timing_level == LEVEL_GTF) + Mode = xf86GTFMode(hsize, vsize, refresh, FALSE, FALSE); + } + + } + + if (Mode) { + Mode->type = M_T_DRIVER; + Modes = xf86ModesAdd(Modes, Mode); + } + Mode = NULL; + } + + return Modes; +} + +static void +DDCModeDoInterlaceQuirks(DisplayModePtr mode) +{ + /* + * EDID is delightfully ambiguous about how interlaced modes are to be + * encoded. X's internal representation is of frame height, but some + * HDTV detailed timings are encoded as field height. + * + * The format list here is from CEA, in frame size. Technically we + * should be checking refresh rate too. Whatever. + */ + static const struct { + int w, h; + } cea_interlaced[] = { + { 1920, 1080 }, + { 720, 480 }, + { 1440, 480 }, + { 2880, 480 }, + { 720, 576 }, + { 1440, 576 }, + { 2880, 576 }, + }; + static const int n_modes = sizeof(cea_interlaced)/sizeof(cea_interlaced[0]); + int i; + + for (i = 0; i < n_modes; i++) { + if ((mode->HDisplay == cea_interlaced[i].w) && + (mode->VDisplay == cea_interlaced[i].h / 2)) { + mode->VDisplay *= 2; + mode->VSyncStart *= 2; + mode->VSyncEnd *= 2; + mode->VTotal *= 2; + mode->VTotal |= 1; + } + } + + mode->Flags |= V_INTERLACE; +} + +/* + * + */ +static DisplayModePtr +DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing, + Bool preferred, ddc_quirk_t quirks) +{ + DisplayModePtr Mode; + + /* + * Refuse to create modes that are insufficiently large. 64 is a random + * number, maybe the spec says something about what the minimum is. In + * particular I see this frequently with _old_ EDID, 1.0 or so, so maybe + * our parser is just being too aggresive there. + */ + if (timing->h_active < 64 || timing->v_active < 64) { + xf86DrvMsg(scrnIndex, X_INFO, + "%s: Ignoring tiny %dx%d mode\n", __func__, + timing->h_active, timing->v_active); + return NULL; + } + + /* We don't do stereo */ + if (timing->stereo) { + xf86DrvMsg(scrnIndex, X_INFO, + "%s: Ignoring: We don't handle stereo.\n", __func__); + return NULL; + } + + /* We only do seperate sync currently */ + if (timing->sync != 0x03) { + xf86DrvMsg(scrnIndex, X_INFO, + "%s: %dx%d Warning: We only handle separate" + " sync.\n", __func__, timing->h_active, timing->v_active); + } + + Mode = xnfcalloc(1, sizeof(DisplayModeRec)); + + Mode->type = M_T_DRIVER; + if (preferred) + Mode->type |= M_T_PREFERRED; + + if( ( quirks & DDC_QUIRK_135_CLOCK_TOO_HIGH ) && + timing->clock == 135000000 ) + Mode->Clock = 108880; + else + Mode->Clock = timing->clock / 1000.0; + + Mode->HDisplay = timing->h_active; + Mode->HSyncStart = timing->h_active + timing->h_sync_off; + Mode->HSyncEnd = Mode->HSyncStart + timing->h_sync_width; + Mode->HTotal = timing->h_active + timing->h_blanking; + + Mode->VDisplay = timing->v_active; + Mode->VSyncStart = timing->v_active + timing->v_sync_off; + Mode->VSyncEnd = Mode->VSyncStart + timing->v_sync_width; + Mode->VTotal = timing->v_active + timing->v_blanking; + + /* perform basic check on the detail timing */ + if (Mode->HSyncEnd > Mode->HTotal || Mode->VSyncEnd > Mode->VTotal) { + free(Mode); + return NULL; + } + + /* We ignore h/v_size and h/v_border for now. */ + + if (timing->interlaced) + DDCModeDoInterlaceQuirks(Mode); + + if (quirks & DDC_QUIRK_DETAILED_SYNC_PP) + Mode->Flags |= V_PVSYNC | V_PHSYNC; + else { + if (timing->misc & 0x02) + Mode->Flags |= V_PVSYNC; + else + Mode->Flags |= V_NVSYNC; + + if (timing->misc & 0x01) + Mode->Flags |= V_PHSYNC; + else + Mode->Flags |= V_NHSYNC; + } + + xf86SetModeDefaultName(Mode); + + return Mode; +} + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) +static DisplayModePtr +DDCModesFromCVT(int scrnIndex, struct cvt_timings *t) +{ + DisplayModePtr modes = NULL; + int i; + + for (i = 0; i < 4; i++) { + if (t[i].height) { + if (t[i].rates & 0x10) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 50, 0, 0)); + if (t[i].rates & 0x08) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 60, 0, 0)); + if (t[i].rates & 0x04) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 75, 0, 0)); + if (t[i].rates & 0x02) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 85, 0, 0)); + if (t[i].rates & 0x01) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 60, 1, 0)); + } else break; + } + + return modes; +} +#endif + +static const struct { + short w; + short h; + short r; + short rb; +} EstIIIModes[] = { + /* byte 6 */ + { 640, 350, 85, 0 }, + { 640, 400, 85, 0 }, + { 720, 400, 85, 0 }, + { 640, 480, 85, 0 }, + { 848, 480, 60, 0 }, + { 800, 600, 85, 0 }, + { 1024, 768, 85, 0 }, + { 1152, 864, 75, 0 }, + /* byte 7 */ + { 1280, 768, 60, 1 }, + { 1280, 768, 60, 0 }, + { 1280, 768, 75, 0 }, + { 1280, 768, 85, 0 }, + { 1280, 960, 60, 0 }, + { 1280, 960, 85, 0 }, + { 1280, 1024, 60, 0 }, + { 1280, 1024, 85, 0 }, + /* byte 8 */ + { 1360, 768, 60, 0 }, + { 1440, 900, 60, 1 }, + { 1440, 900, 60, 0 }, + { 1440, 900, 75, 0 }, + { 1440, 900, 85, 0 }, + { 1400, 1050, 60, 1 }, + { 1400, 1050, 60, 0 }, + { 1400, 1050, 75, 0 }, + /* byte 9 */ + { 1400, 1050, 85, 0 }, + { 1680, 1050, 60, 1 }, + { 1680, 1050, 60, 0 }, + { 1680, 1050, 75, 0 }, + { 1680, 1050, 85, 0 }, + { 1600, 1200, 60, 0 }, + { 1600, 1200, 65, 0 }, + { 1600, 1200, 70, 0 }, + /* byte 10 */ + { 1600, 1200, 75, 0 }, + { 1600, 1200, 85, 0 }, + { 1792, 1344, 60, 0 }, + { 1792, 1344, 85, 0 }, + { 1856, 1392, 60, 0 }, + { 1856, 1392, 75, 0 }, + { 1920, 1200, 60, 1 }, + { 1920, 1200, 60, 0 }, + /* byte 11 */ + { 1920, 1200, 75, 0 }, + { 1920, 1200, 85, 0 }, + { 1920, 1440, 60, 0 }, + { 1920, 1440, 75, 0 }, +}; + +static DisplayModePtr +DDCModesFromEstIII(unsigned char *est) +{ + DisplayModePtr modes = NULL; + int i, j, m; + + for (i = 0; i < 6; i++) { + for (j = 7; j > 0; j--) { + if (est[i] & (1 << j)) { + m = (i * 8) + (7 - j); + modes = xf86ModesAdd(modes, + FindDMTMode(EstIIIModes[m].w, + EstIIIModes[m].h, + EstIIIModes[m].r, + EstIIIModes[m].rb)); + } + } + } + + return modes; +} + +/* + * This is only valid when the sink claims to be continuous-frequency + * but does not supply a detailed range descriptor. Such sinks are + * arguably broken. Currently the mode validation code isn't aware of + * this; the non-RANDR code even punts the decision of optional sync + * range checking to the driver. Loss. + */ +static void +DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes) +{ + DisplayModePtr Mode = Modes; + + if (!Monitor || !Modes) + return; + + /* set up the ranges for scanning through the modes */ + Monitor->nHsync = 1; + Monitor->hsync[0].lo = 1024.0; + Monitor->hsync[0].hi = 0.0; + + Monitor->nVrefresh = 1; + Monitor->vrefresh[0].lo = 1024.0; + Monitor->vrefresh[0].hi = 0.0; + + while (Mode) { + if (!Mode->HSync) + Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal); + + if (!Mode->VRefresh) + Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / + ((float) (Mode->HTotal * Mode->VTotal)); + + if (Mode->HSync < Monitor->hsync[0].lo) + Monitor->hsync[0].lo = Mode->HSync; + + if (Mode->HSync > Monitor->hsync[0].hi) + Monitor->hsync[0].hi = Mode->HSync; + + if (Mode->VRefresh < Monitor->vrefresh[0].lo) + Monitor->vrefresh[0].lo = Mode->VRefresh; + + if (Mode->VRefresh > Monitor->vrefresh[0].hi) + Monitor->vrefresh[0].hi = Mode->VRefresh; + + Mode = Mode->next; + } +} + +ddc_quirk_t +xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose) +{ + ddc_quirk_t quirks; + int i; + + quirks = DDC_QUIRK_NONE; + for (i = 0; ddc_quirks[i].detect; i++) { + if (ddc_quirks[i].detect (scrnIndex, DDC)) { + if (verbose) { + xf86DrvMsg (scrnIndex, X_INFO, " EDID quirk: %s\n", + ddc_quirks[i].description); + } + quirks |= ddc_quirks[i].quirk; + } + } + + return quirks; +} + +void xf86DetTimingApplyQuirks(struct detailed_monitor_section *det_mon, + ddc_quirk_t quirks, + int hsize, int vsize) +{ + if (det_mon->type != DT) + return; + + if (quirks & DDC_QUIRK_DETAILED_H_IN_CM) + det_mon->section.d_timings.h_size *= 10; + + if (quirks & DDC_QUIRK_DETAILED_V_IN_CM) + det_mon->section.d_timings.v_size *= 10; + + if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) { + det_mon->section.d_timings.h_size = 10 * hsize; + det_mon->section.d_timings.v_size = 10 * vsize; + } +} + +/** + * Applies monitor-specific quirks to the decoded EDID information. + * + * Note that some quirks applying to the mode list are still implemented in + * xf86DDCGetModes. + */ +void +xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC) +{ + ddc_quirk_t quirks = xf86DDCDetectQuirks (scrnIndex, DDC, FALSE); + int i; + + for (i = 0; i < DET_TIMINGS; i++) { + xf86DetTimingApplyQuirks(DDC->det_mon + i, quirks, + DDC->features.hsize, + DDC->features.vsize); + } +} + +/** + * Walks the modes list, finding the mode with the largest area which is + * closest to the target refresh rate, and marks it as the only preferred mode. +*/ +static void +xf86DDCSetPreferredRefresh(int scrnIndex, DisplayModePtr modes, + float target_refresh) +{ + DisplayModePtr mode, best = modes; + + for (mode = modes; mode; mode = mode->next) + { + mode->type &= ~M_T_PREFERRED; + + if (mode == best) continue; + + if (mode->HDisplay * mode->VDisplay > + best->HDisplay * best->VDisplay) + { + best = mode; + continue; + } + if (mode->HDisplay * mode->VDisplay == + best->HDisplay * best->VDisplay) + { + double mode_refresh = xf86ModeVRefresh (mode); + double best_refresh = xf86ModeVRefresh (best); + double mode_dist = fabs(mode_refresh - target_refresh); + double best_dist = fabs(best_refresh - target_refresh); + + if (mode_dist < best_dist) + { + best = mode; + continue; + } + } + } + if (best) + best->type |= M_T_PREFERRED; +} + +#define CEA_VIDEO_MODES_NUM 64 +static const DisplayModeRec CEAVideoModes[CEA_VIDEO_MODES_NUM] = { + { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 1:640x480@60Hz */ + { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 2:720x480@60Hz */ + { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 3:720x480@60Hz */ + { MODEPREFIX, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 4: 1280x720@60Hz */ + { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 5:1920x1080i@60Hz */ + { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 6:1440x480i@60Hz */ + { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 7:1440x480i@60Hz */ + { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 8:1440x240@60Hz */ + { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 9:1440x240@60Hz */ + { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 10:2880x480i@60Hz */ + { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 11:2880x480i@60Hz */ + { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 12:2880x240@60Hz */ + { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 13:2880x240@60Hz */ + { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 14:1440x480@60Hz */ + { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 15:1440x480@60Hz */ + { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 16:1920x1080@60Hz */ + { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 17:720x576@50Hz */ + { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 18:720x576@50Hz */ + { MODEPREFIX, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 19: 1280x720@50Hz */ + { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 20:1920x1080i@50Hz */ + { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 21:1440x576i@50Hz */ + { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 22:1440x576i@50Hz */ + { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 23:1440x288@50Hz */ + { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 24:1440x288@50Hz */ + { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 25:2880x576i@50Hz */ + { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 26:2880x576i@50Hz */ + { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 27:2880x288@50Hz */ + { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 28:2880x288@50Hz */ + { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 29:1440x576@50Hz */ + { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 30:1440x576@50Hz */ + { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 31:1920x1080@50Hz */ + { MODEPREFIX, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 32:1920x1080@24Hz */ + { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 33:1920x1080@25Hz */ + { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 34:1920x1080@30Hz */ + { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 35:2880x480@60Hz */ + { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 36:2880x480@60Hz */ + { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 37:2880x576@50Hz */ + { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 38:2880x576@50Hz */ + { MODEPREFIX, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, V_PHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 39:1920x1080i@50Hz */ + { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 40:1920x1080i@100Hz */ + { MODEPREFIX, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 41:1280x720@100Hz */ + { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 42:720x576@100Hz */ + { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 43:720x576@100Hz */ + { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 44:1440x576i@100Hz */ + { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 45:1440x576i@100Hz */ + { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 46:1920x1080i@120Hz */ + { MODEPREFIX, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 47:1280x720@120Hz */ + { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 48:720x480@120Hz */ + { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 49:720x480@120Hz */ + { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 50:1440x480i@120Hz */ + { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 51:1440x480i@120Hz */ + { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 52:720x576@200Hz */ + { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 53:720x576@200Hz */ + { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 54:1440x576i@200Hz */ + { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 55:1440x576i@200Hz */ + { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 56:720x480@240Hz */ + { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 57:720x480@240Hz */ + { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 58:1440x480i@240 */ + { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 59:1440x480i@240 */ + { MODEPREFIX, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 60: 1280x720@24Hz */ + { MODEPREFIX, 74250, 3700, 3740, 1430, 3960, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 61: 1280x720@25Hz */ + { MODEPREFIX, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 62: 1280x720@30Hz */ + { MODEPREFIX, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 63: 1920x1080@120Hz */ + { MODEPREFIX, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 64:1920x1080@100Hz */ +}; + +/* chose mode line by cea short video descriptor*/ +static void handle_cea_svd(struct cea_video_block *video, void *data) +{ + DisplayModePtr Mode; + DisplayModePtr *Modes = (DisplayModePtr *) data; + int vid; + + vid = video ->video_code & 0x7f; + if (vid < CEA_VIDEO_MODES_NUM) { + Mode = xf86DuplicateMode(CEAVideoModes + vid); + *Modes = xf86ModesAdd(*Modes, Mode); + } +} + +static DisplayModePtr +DDCModesFromCEAExtension(int scrnIndex, xf86MonPtr MonPtr) +{ + DisplayModePtr Modes = NULL; + + xf86ForEachVideoBlock(MonPtr, + handle_cea_svd, + &Modes); + + return Modes; +} + +struct det_modes_parameter { + xf86MonPtr DDC; + ddc_quirk_t quirks; + DisplayModePtr Modes; + Bool rb; + Bool preferred; + int timing_level; +}; + +static void handle_detailed_modes(struct detailed_monitor_section *det_mon, + void *data) +{ + DisplayModePtr Mode; + struct det_modes_parameter *p = (struct det_modes_parameter *)data; + + xf86DetTimingApplyQuirks(det_mon,p->quirks, + p->DDC->features.hsize, + p->DDC->features.vsize); + + switch (det_mon->type) { + case DT: + Mode = DDCModeFromDetailedTiming(p->DDC->scrnIndex, + &det_mon->section.d_timings, + p->preferred, + p->quirks); + p->preferred = FALSE; + p->Modes = xf86ModesAdd(p->Modes, Mode); + break; + case DS_STD_TIMINGS: + Mode = DDCModesFromStandardTiming(det_mon->section.std_t, + p->quirks, p->timing_level,p->rb); + p->Modes = xf86ModesAdd(p->Modes, Mode); + break; +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + case DS_CVT: + Mode = DDCModesFromCVT(p->DDC->scrnIndex, det_mon->section.cvt); + p->Modes = xf86ModesAdd(p->Modes, Mode); + break; +#endif + case DS_EST_III: + Mode = DDCModesFromEstIII(det_mon->section.est_iii); + p->Modes = xf86ModesAdd(p->Modes, Mode); + break; + default: + break; + } +} + +DisplayModePtr +xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC) +{ + DisplayModePtr Modes = NULL, Mode; + ddc_quirk_t quirks; + Bool preferred, rb; + int timing_level; + struct det_modes_parameter p; + + xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n", + DDC->vendor.name, DDC->vendor.prod_id); + + quirks = xf86DDCDetectQuirks(scrnIndex, DDC, TRUE); + + preferred = PREFERRED_TIMING_MODE(DDC->features.msc); + if (DDC->ver.revision >= 4) + preferred = TRUE; + if (quirks & DDC_QUIRK_FIRST_DETAILED_PREFERRED) + preferred = TRUE; + if (quirks & (DDC_QUIRK_PREFER_LARGE_60 | DDC_QUIRK_PREFER_LARGE_75)) + preferred = FALSE; + + rb = xf86MonitorSupportsReducedBlanking(DDC); + + timing_level = MonitorStandardTimingLevel(DDC); + + p.quirks = quirks; + p.DDC = DDC; + p.Modes = Modes; + p.rb = rb; + p.preferred = preferred; + p.timing_level = timing_level; + xf86ForEachDetailedBlock(DDC, handle_detailed_modes, &p); + Modes = p.Modes; + + /* Add established timings */ + Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks); + Modes = xf86ModesAdd(Modes, Mode); + + /* Add standard timings */ + Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb); + Modes = xf86ModesAdd(Modes, Mode); + + /* Add cea-extension mode timings */ + Mode = DDCModesFromCEAExtension(scrnIndex,DDC); + Modes = xf86ModesAdd(Modes, Mode); + + if (quirks & DDC_QUIRK_PREFER_LARGE_60) + xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60); + + if (quirks & DDC_QUIRK_PREFER_LARGE_75) + xf86DDCSetPreferredRefresh(scrnIndex, Modes, 75); + + Modes = xf86PruneDuplicateModes(Modes); + + return Modes; +} + +struct det_mon_parameter { + MonPtr Monitor; + ddc_quirk_t quirks; + Bool have_hsync; + Bool have_vrefresh; + Bool have_maxpixclock; +}; + +static void handle_detailed_monset(struct detailed_monitor_section *det_mon, + void *data) +{ + int clock; + struct det_mon_parameter *p = (struct det_mon_parameter *)data; + int scrnIndex = ((xf86MonPtr)(p->Monitor->DDC))->scrnIndex; + + switch (det_mon->type) { + case DS_RANGES: + if (!p->have_hsync) { + if (!p->Monitor->nHsync) + xf86DrvMsg(scrnIndex, X_INFO, + "Using EDID range info for horizontal sync\n"); + p->Monitor->hsync[p->Monitor->nHsync].lo = + det_mon->section.ranges.min_h; + p->Monitor->hsync[p->Monitor->nHsync].hi = + det_mon->section.ranges.max_h; + p->Monitor->nHsync++; + } else { + xf86DrvMsg(scrnIndex, X_INFO, + "Using hsync ranges from config file\n"); + } + + if (!p->have_vrefresh) { + if (!p->Monitor->nVrefresh) + xf86DrvMsg(scrnIndex, X_INFO, + "Using EDID range info for vertical refresh\n"); + p->Monitor->vrefresh[p->Monitor->nVrefresh].lo = + det_mon->section.ranges.min_v; + p->Monitor->vrefresh[p->Monitor->nVrefresh].hi = + det_mon->section.ranges.max_v; + p->Monitor->nVrefresh++; + } else { + xf86DrvMsg(scrnIndex, X_INFO, + "Using vrefresh ranges from config file\n"); + } + + clock = det_mon->section.ranges.max_clock * 1000; + if (p->quirks & DDC_QUIRK_DVI_SINGLE_LINK) + clock = min(clock, 165000); + if (!p->have_maxpixclock && clock > p->Monitor->maxPixClock) + p->Monitor->maxPixClock = clock; + + break; + default: + break; + } +} + +/* + * Fill out MonPtr with xf86MonPtr information. + */ +void +xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC) +{ + DisplayModePtr Modes = NULL, Mode; + struct det_mon_parameter p; + + if (!Monitor || !DDC) + return; + + Monitor->DDC = DDC; + + if (Monitor->widthmm <= 0 || Monitor->heightmm <= 0) { + Monitor->widthmm = 10 * DDC->features.hsize; + Monitor->heightmm = 10 * DDC->features.vsize; + } + + Monitor->reducedblanking = xf86MonitorSupportsReducedBlanking(DDC); + + Modes = xf86DDCGetModes(scrnIndex, DDC); + + /* Go through the detailed monitor sections */ + p.Monitor = Monitor; + p.quirks = xf86DDCDetectQuirks(scrnIndex, Monitor->DDC, FALSE); + p.have_hsync = (Monitor->nHsync != 0); + p.have_vrefresh = (Monitor->nVrefresh != 0); + p.have_maxpixclock = (Monitor->maxPixClock != 0); + xf86ForEachDetailedBlock(DDC, handle_detailed_monset, &p); + + if (Modes) { + /* Print Modes */ + xf86DrvMsg(scrnIndex, X_INFO, "Printing DDC gathered Modelines:\n"); + + Mode = Modes; + while (Mode) { + xf86PrintModeline(scrnIndex, Mode); + Mode = Mode->next; + } + + /* Do we still need ranges to be filled in? */ + if (!Monitor->nHsync || !Monitor->nVrefresh) + DDCGuessRangesFromModes(scrnIndex, Monitor, Modes); + + /* look for last Mode */ + Mode = Modes; + + while (Mode->next) + Mode = Mode->next; + + /* add to MonPtr */ + if (Monitor->Modes) { + Monitor->Last->next = Modes; + Modes->prev = Monitor->Last; + Monitor->Last = Mode; + } else { + Monitor->Modes = Modes; + Monitor->Last = Mode; + } + } +} diff --git a/xorg-server/hw/xfree86/modes/xf86Modes.c b/xorg-server/hw/xfree86/modes/xf86Modes.c index 75aedaa99..0507e9812 100644 --- a/xorg-server/hw/xfree86/modes/xf86Modes.c +++ b/xorg-server/hw/xfree86/modes/xf86Modes.c @@ -1,727 +1,727 @@ -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#else -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#endif - -#include "xf86Modes.h" -#include "xf86Priv.h" - -extern XF86ConfigPtr xf86configptr; - -/* - * This is the version number where we epoched. These files get copied - * into drivers that want to use this setup infrastructure on pre-1.3 - * servers, so when that happens they need to define these symbols - * themselves. However, _in_ the server, we basically always define them now. - */ -#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) - -/** - * Calculates the horizontal sync rate of a mode. - */ -double -xf86ModeHSync(const DisplayModeRec *mode) -{ - double hsync = 0.0; - - if (mode->HSync > 0.0) - hsync = mode->HSync; - else if (mode->HTotal > 0) - hsync = (float)mode->Clock / (float)mode->HTotal; - - return hsync; -} - -/** - * Calculates the vertical refresh rate of a mode. - */ -double -xf86ModeVRefresh(const DisplayModeRec *mode) -{ - double refresh = 0.0; - - if (mode->VRefresh > 0.0) - refresh = mode->VRefresh; - else if (mode->HTotal > 0 && mode->VTotal > 0) { - refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal; - if (mode->Flags & V_INTERLACE) - refresh *= 2.0; - if (mode->Flags & V_DBLSCAN) - refresh /= 2.0; - if (mode->VScan > 1) - refresh /= (float)(mode->VScan); - } - return refresh; -} - -int -xf86ModeWidth (const DisplayModeRec *mode, Rotation rotation) -{ - switch (rotation & 0xf) { - case RR_Rotate_0: - case RR_Rotate_180: - return mode->HDisplay; - case RR_Rotate_90: - case RR_Rotate_270: - return mode->VDisplay; - default: - return 0; - } -} - -int -xf86ModeHeight (const DisplayModeRec *mode, Rotation rotation) -{ - switch (rotation & 0xf) { - case RR_Rotate_0: - case RR_Rotate_180: - return mode->VDisplay; - case RR_Rotate_90: - case RR_Rotate_270: - return mode->HDisplay; - default: - return 0; - } -} - -/** Calculates the memory bandwidth (in MiB/sec) of a mode. */ -unsigned int -xf86ModeBandwidth(DisplayModePtr mode, int depth) -{ - float a_active, a_total, active_percent, pixels_per_second; - int bytes_per_pixel = bits_to_bytes(depth); - - if (!mode->HTotal || !mode->VTotal || !mode->Clock) - return 0; - - a_active = mode->HDisplay * mode->VDisplay; - a_total = mode->HTotal * mode->VTotal; - active_percent = a_active / a_total; - pixels_per_second = active_percent * mode->Clock * 1000.0; - - return (unsigned int)(pixels_per_second * bytes_per_pixel / (1024 * 1024)); -} - -/** Sets a default mode name of <width>x<height> on a mode. */ -void -xf86SetModeDefaultName(DisplayModePtr mode) -{ - Bool interlaced = !!(mode->Flags & V_INTERLACE); - - xfree(mode->name); - - mode->name = XNFprintf("%dx%d%s", mode->HDisplay, mode->VDisplay, - interlaced ? "i" : ""); -} - -/* - * xf86SetModeCrtc - * - * Initialises the Crtc parameters for a mode. The initialisation includes - * adjustments for interlaced and double scan modes. - */ -void -xf86SetModeCrtc(DisplayModePtr p, int adjustFlags) -{ - if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN)) - return; - - p->CrtcHDisplay = p->HDisplay; - p->CrtcHSyncStart = p->HSyncStart; - p->CrtcHSyncEnd = p->HSyncEnd; - p->CrtcHTotal = p->HTotal; - p->CrtcHSkew = p->HSkew; - p->CrtcVDisplay = p->VDisplay; - p->CrtcVSyncStart = p->VSyncStart; - p->CrtcVSyncEnd = p->VSyncEnd; - p->CrtcVTotal = p->VTotal; - if (p->Flags & V_INTERLACE) { - if (adjustFlags & INTERLACE_HALVE_V) { - p->CrtcVDisplay /= 2; - p->CrtcVSyncStart /= 2; - p->CrtcVSyncEnd /= 2; - p->CrtcVTotal /= 2; - } - /* Force interlaced modes to have an odd VTotal */ - /* maybe we should only do this when INTERLACE_HALVE_V is set? */ - p->CrtcVTotal |= 1; - } - - if (p->Flags & V_DBLSCAN) { - p->CrtcVDisplay *= 2; - p->CrtcVSyncStart *= 2; - p->CrtcVSyncEnd *= 2; - p->CrtcVTotal *= 2; - } - if (p->VScan > 1) { - p->CrtcVDisplay *= p->VScan; - p->CrtcVSyncStart *= p->VScan; - p->CrtcVSyncEnd *= p->VScan; - p->CrtcVTotal *= p->VScan; - } - p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay); - p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal); - p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay); - p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal); - - p->CrtcHAdjusted = FALSE; - p->CrtcVAdjusted = FALSE; -} - -/** - * Allocates and returns a copy of pMode, including pointers within pMode. - */ -DisplayModePtr -xf86DuplicateMode(const DisplayModeRec *pMode) -{ - DisplayModePtr pNew; - - pNew = xnfalloc(sizeof(DisplayModeRec)); - *pNew = *pMode; - pNew->next = NULL; - pNew->prev = NULL; - - if (pMode->name == NULL) - xf86SetModeDefaultName(pNew); - else - pNew->name = xnfstrdup(pMode->name); - - return pNew; -} - -/** - * Duplicates every mode in the given list and returns a pointer to the first - * mode. - * - * \param modeList doubly-linked mode list - */ -DisplayModePtr -xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList) -{ - DisplayModePtr first = NULL, last = NULL; - DisplayModePtr mode; - - for (mode = modeList; mode != NULL; mode = mode->next) { - DisplayModePtr new; - - new = xf86DuplicateMode(mode); - - /* Insert pNew into modeList */ - if (last) { - last->next = new; - new->prev = last; - } else { - first = new; - new->prev = NULL; - } - new->next = NULL; - last = new; - } - - return first; -} - -/** - * Returns true if the given modes should program to the same timings. - * - * This doesn't use Crtc values, as it might be used on ModeRecs without the - * Crtc values set. So, it's assumed that the other numbers are enough. - */ -Bool -xf86ModesEqual(const DisplayModeRec *pMode1, const DisplayModeRec *pMode2) -{ - if (pMode1->Clock == pMode2->Clock && - pMode1->HDisplay == pMode2->HDisplay && - pMode1->HSyncStart == pMode2->HSyncStart && - pMode1->HSyncEnd == pMode2->HSyncEnd && - pMode1->HTotal == pMode2->HTotal && - pMode1->HSkew == pMode2->HSkew && - pMode1->VDisplay == pMode2->VDisplay && - pMode1->VSyncStart == pMode2->VSyncStart && - pMode1->VSyncEnd == pMode2->VSyncEnd && - pMode1->VTotal == pMode2->VTotal && - pMode1->VScan == pMode2->VScan && - pMode1->Flags == pMode2->Flags) - { - return TRUE; - } else { - return FALSE; - } -} - -static void -add(char **p, char *new) -{ - *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2); - strcat(*p, " "); - strcat(*p, new); -} - -/** - * Print out a modeline. - */ -void -xf86PrintModeline(int scrnIndex,DisplayModePtr mode) -{ - char tmp[256]; - char *flags = xnfcalloc(1, 1); - - if (mode->HSkew) { - snprintf(tmp, 256, "hskew %i", mode->HSkew); - add(&flags, tmp); - } - if (mode->VScan) { - snprintf(tmp, 256, "vscan %i", mode->VScan); - add(&flags, tmp); - } - if (mode->Flags & V_INTERLACE) add(&flags, "interlace"); - if (mode->Flags & V_CSYNC) add(&flags, "composite"); - if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan"); - if (mode->Flags & V_BCAST) add(&flags, "bcast"); - if (mode->Flags & V_PHSYNC) add(&flags, "+hsync"); - if (mode->Flags & V_NHSYNC) add(&flags, "-hsync"); - if (mode->Flags & V_PVSYNC) add(&flags, "+vsync"); - if (mode->Flags & V_NVSYNC) add(&flags, "-vsync"); - if (mode->Flags & V_PCSYNC) add(&flags, "+csync"); - if (mode->Flags & V_NCSYNC) add(&flags, "-csync"); -#if 0 - if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2"); -#endif - xf86DrvMsg(scrnIndex, X_INFO, - "Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s " - "(%.01f kHz)\n", - mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay, - mode->HSyncStart, mode->HSyncEnd, mode->HTotal, - mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, - mode->VTotal, flags, xf86ModeHSync(mode)); - xfree(flags); -} -#endif /* XORG_VERSION_CURRENT <= 7.2.99.2 */ - -/** - * Marks as bad any modes with unsupported flags. - * - * \param modeList doubly-linked list of modes. - * \param flags flags supported by the driver. - * - * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough? - */ -void -xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, - int flags) -{ - DisplayModePtr mode; - - if (flags == (V_INTERLACE | V_DBLSCAN)) - return; - - for (mode = modeList; mode != NULL; mode = mode->next) { - if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE)) - mode->status = MODE_NO_INTERLACE; - if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN)) - mode->status = MODE_NO_DBLESCAN; - } -} - -/** - * Marks as bad any modes extending beyond the given max X, Y, or pitch. - * - * \param modeList doubly-linked list of modes. - */ -void -xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, - int maxX, int maxY, int maxPitch) -{ - DisplayModePtr mode; - - for (mode = modeList; mode != NULL; mode = mode->next) { - if (maxPitch > 0 && mode->HDisplay > maxPitch) - mode->status = MODE_BAD_WIDTH; - - if (maxX > 0 && mode->HDisplay > maxX) - mode->status = MODE_VIRTUAL_X; - - if (maxY > 0 && mode->VDisplay > maxY) - mode->status = MODE_VIRTUAL_Y; - - if (mode->next == modeList) - break; - } -} - -/** - * Marks as bad any modes that aren't supported by the given monitor's - * hsync and vrefresh ranges. - * - * \param modeList doubly-linked list of modes. - */ -void -xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList, - MonPtr mon) -{ - DisplayModePtr mode; - - for (mode = modeList; mode != NULL; mode = mode->next) { - Bool bad; - int i; - - bad = TRUE; - for (i = 0; i < mon->nHsync; i++) { - if (xf86ModeHSync(mode) >= mon->hsync[i].lo * (1-SYNC_TOLERANCE) && - xf86ModeHSync(mode) <= mon->hsync[i].hi * (1+SYNC_TOLERANCE)) - { - bad = FALSE; - } - } - if (bad) - mode->status = MODE_HSYNC; - - bad = TRUE; - for (i = 0; i < mon->nVrefresh; i++) { - if (xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo * (1-SYNC_TOLERANCE) && - xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi * (1+SYNC_TOLERANCE)) - { - bad = FALSE; - } - } - if (bad) - mode->status = MODE_VSYNC; - - if (mode->next == modeList) - break; - } -} - -/** - * Marks as bad any modes extending beyond outside of the given clock ranges. - * - * \param modeList doubly-linked list of modes. - * \param min pointer to minimums of clock ranges - * \param max pointer to maximums of clock ranges - * \param n_ranges number of ranges. - */ -void -xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, - int *min, int *max, int n_ranges) -{ - DisplayModePtr mode; - int i; - - for (mode = modeList; mode != NULL; mode = mode->next) { - Bool good = FALSE; - for (i = 0; i < n_ranges; i++) { - if (mode->Clock >= min[i] * (1-SYNC_TOLERANCE) && - mode->Clock <= max[i] * (1+SYNC_TOLERANCE)) { - good = TRUE; - break; - } - } - if (!good) - mode->status = MODE_CLOCK_RANGE; - } -} - -/** - * If the user has specified a set of mode names to use, mark as bad any modes - * not listed. - * - * The user mode names specified are prefixes to names of modes, so "1024x768" - * will match modes named "1024x768", "1024x768x75", "1024x768-good", but - * "1024x768x75" would only match "1024x768x75" from that list. - * - * MODE_BAD is used as the rejection flag, for lack of a better flag. - * - * \param modeList doubly-linked list of modes. - */ -void -xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList) -{ - DisplayModePtr mode; - - if (pScrn->display->modes[0] == NULL) - return; - - for (mode = modeList; mode != NULL; mode = mode->next) { - int i; - Bool good = FALSE; - - for (i = 0; pScrn->display->modes[i] != NULL; i++) { - if (strncmp(pScrn->display->modes[i], mode->name, - strlen(pScrn->display->modes[i])) == 0) { - good = TRUE; - break; - } - } - if (!good) - mode->status = MODE_BAD; - } -} - - -/** - * Marks as bad any modes exceeding the given bandwidth. - * - * \param modeList doubly-linked list of modes. - * \param bandwidth bandwidth in MHz. - * \param depth color depth. - */ -void -xf86ValidateModesBandwidth(ScrnInfoPtr pScrn, DisplayModePtr modeList, - unsigned int bandwidth, int depth) -{ - DisplayModePtr mode; - - for (mode = modeList; mode != NULL; mode = mode->next) { - if (xf86ModeBandwidth(mode, depth) > bandwidth) -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - mode->status = MODE_BANDWIDTH; -#else - /* MODE_BANDWIDTH didn't exist in xserver 1.2 */ - mode->status = MODE_BAD; -#endif - } -} - -Bool -xf86ModeIsReduced(const DisplayModeRec *mode) -{ - if ((((mode->HDisplay * 5 / 4) & ~0x07) > mode->HTotal) && - ((mode->HTotal - mode->HDisplay) == 160) && - ((mode->HSyncEnd - mode->HDisplay) == 80) && - ((mode->HSyncEnd - mode->HSyncStart) == 32) && - ((mode->VSyncStart - mode->VDisplay) == 3)) - return TRUE; - return FALSE; -} - -/** - * Marks as bad any reduced-blanking modes. - * - * \param modeList doubly-linked list of modes. - */ -void -xf86ValidateModesReducedBlanking(ScrnInfoPtr pScrn, DisplayModePtr modeList) -{ - for (; modeList != NULL; modeList = modeList->next) - if (xf86ModeIsReduced(modeList)) - modeList->status = MODE_NO_REDUCED; -} - -/** - * Frees any modes from the list with a status other than MODE_OK. - * - * \param modeList pointer to a doubly-linked or circular list of modes. - * \param verbose determines whether the reason for mode invalidation is - * printed. - */ -void -xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, - Bool verbose) -{ - DisplayModePtr mode; - - for (mode = *modeList; mode != NULL;) { - DisplayModePtr next = mode->next, first = *modeList; - - if (mode->status != MODE_OK) { - if (verbose) { - char *type = ""; - if (mode->type & M_T_BUILTIN) - type = "built-in "; - else if (mode->type & M_T_DEFAULT) - type = "default "; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Not using %smode \"%s\" (%s)\n", type, mode->name, - xf86ModeStatusToString(mode->status)); - } - xf86DeleteMode(modeList, mode); - } - - if (next == first) - break; - mode = next; - } -} - -/** - * Adds the new mode into the mode list, and returns the new list - * - * \param modes doubly-linked mode list. - */ -DisplayModePtr -xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new) -{ - if (modes == NULL) - return new; - - if (new) { - DisplayModePtr mode = modes; - - while (mode->next) - mode = mode->next; - - mode->next = new; - new->prev = mode; - } - - return modes; -} - -/** - * Build a mode list from a list of config file modes - */ -static DisplayModePtr -xf86GetConfigModes (XF86ConfModeLinePtr conf_mode) -{ - DisplayModePtr head = NULL, prev = NULL, mode; - - for (; conf_mode; conf_mode = (XF86ConfModeLinePtr) conf_mode->list.next) - { - mode = xcalloc(1, sizeof(DisplayModeRec)); - if (!mode) - continue; - mode->name = xstrdup(conf_mode->ml_identifier); - if (!mode->name) - { - xfree (mode); - continue; - } - mode->type = 0; - mode->Clock = conf_mode->ml_clock; - mode->HDisplay = conf_mode->ml_hdisplay; - mode->HSyncStart = conf_mode->ml_hsyncstart; - mode->HSyncEnd = conf_mode->ml_hsyncend; - mode->HTotal = conf_mode->ml_htotal; - mode->VDisplay = conf_mode->ml_vdisplay; - mode->VSyncStart = conf_mode->ml_vsyncstart; - mode->VSyncEnd = conf_mode->ml_vsyncend; - mode->VTotal = conf_mode->ml_vtotal; - mode->Flags = conf_mode->ml_flags; - mode->HSkew = conf_mode->ml_hskew; - mode->VScan = conf_mode->ml_vscan; - - mode->prev = prev; - mode->next = NULL; - if (prev) - prev->next = mode; - else - head = mode; - prev = mode; - } - return head; -} - -/** - * Build a mode list from a monitor configuration - */ -DisplayModePtr -xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor) -{ - DisplayModePtr modes = NULL; - XF86ConfModesLinkPtr modes_link; - - if (!conf_monitor) - return NULL; - - /* - * first we collect the mode lines from the UseModes directive - */ - for (modes_link = conf_monitor->mon_modes_sect_lst; - modes_link; - modes_link = modes_link->list.next) - { - /* If this modes link hasn't been resolved, go look it up now */ - if (!modes_link->ml_modes) - modes_link->ml_modes = xf86findModes (modes_link->ml_modes_str, - xf86configptr->conf_modes_lst); - if (modes_link->ml_modes) - modes = xf86ModesAdd (modes, - xf86GetConfigModes (modes_link->ml_modes->mon_modeline_lst)); - } - - return xf86ModesAdd (modes, - xf86GetConfigModes (conf_monitor->mon_modeline_lst)); -} - -/** - * Build a mode list containing all of the default modes - */ -DisplayModePtr -xf86GetDefaultModes (void) -{ - DisplayModePtr head = NULL, mode; - int i; - - for (i = 0; i < xf86NumDefaultModes; i++) - { - const DisplayModeRec *defMode = &xf86DefaultModes[i]; - - mode = xf86DuplicateMode(defMode); - head = xf86ModesAdd(head, mode); - } - return head; -} - -/* - * Walk a mode list and prune out duplicates. Will preserve the preferred - * mode of an otherwise-duplicate pair. - * - * Probably best to call this on lists that are all of a single class - * (driver, default, user, etc.), otherwise, which mode gets deleted is - * not especially well defined. - * - * Returns the new list. - */ - -DisplayModePtr -xf86PruneDuplicateModes(DisplayModePtr modes) -{ - DisplayModePtr m, n, o; - -top: - for (m = modes; m; m = m->next) { - for (n = m->next; n; n = o) { - o = n->next; - if (xf86ModesEqual(m, n)) { - if (n->type & M_T_PREFERRED) { - xf86DeleteMode(&modes, m); - goto top; - } - else - xf86DeleteMode(&modes, n); - } - } - } - - return modes; -} +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86Modes.h" +#include "xf86Priv.h" + +extern XF86ConfigPtr xf86configptr; + +/* + * This is the version number where we epoched. These files get copied + * into drivers that want to use this setup infrastructure on pre-1.3 + * servers, so when that happens they need to define these symbols + * themselves. However, _in_ the server, we basically always define them now. + */ +#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) + +/** + * Calculates the horizontal sync rate of a mode. + */ +double +xf86ModeHSync(const DisplayModeRec *mode) +{ + double hsync = 0.0; + + if (mode->HSync > 0.0) + hsync = mode->HSync; + else if (mode->HTotal > 0) + hsync = (float)mode->Clock / (float)mode->HTotal; + + return hsync; +} + +/** + * Calculates the vertical refresh rate of a mode. + */ +double +xf86ModeVRefresh(const DisplayModeRec *mode) +{ + double refresh = 0.0; + + if (mode->VRefresh > 0.0) + refresh = mode->VRefresh; + else if (mode->HTotal > 0 && mode->VTotal > 0) { + refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal; + if (mode->Flags & V_INTERLACE) + refresh *= 2.0; + if (mode->Flags & V_DBLSCAN) + refresh /= 2.0; + if (mode->VScan > 1) + refresh /= (float)(mode->VScan); + } + return refresh; +} + +int +xf86ModeWidth (const DisplayModeRec *mode, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode->HDisplay; + case RR_Rotate_90: + case RR_Rotate_270: + return mode->VDisplay; + default: + return 0; + } +} + +int +xf86ModeHeight (const DisplayModeRec *mode, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode->VDisplay; + case RR_Rotate_90: + case RR_Rotate_270: + return mode->HDisplay; + default: + return 0; + } +} + +/** Calculates the memory bandwidth (in MiB/sec) of a mode. */ +unsigned int +xf86ModeBandwidth(DisplayModePtr mode, int depth) +{ + float a_active, a_total, active_percent, pixels_per_second; + int bytes_per_pixel = bits_to_bytes(depth); + + if (!mode->HTotal || !mode->VTotal || !mode->Clock) + return 0; + + a_active = mode->HDisplay * mode->VDisplay; + a_total = mode->HTotal * mode->VTotal; + active_percent = a_active / a_total; + pixels_per_second = active_percent * mode->Clock * 1000.0; + + return (unsigned int)(pixels_per_second * bytes_per_pixel / (1024 * 1024)); +} + +/** Sets a default mode name of <width>x<height> on a mode. */ +void +xf86SetModeDefaultName(DisplayModePtr mode) +{ + Bool interlaced = !!(mode->Flags & V_INTERLACE); + + free(mode->name); + + mode->name = XNFprintf("%dx%d%s", mode->HDisplay, mode->VDisplay, + interlaced ? "i" : ""); +} + +/* + * xf86SetModeCrtc + * + * Initialises the Crtc parameters for a mode. The initialisation includes + * adjustments for interlaced and double scan modes. + */ +void +xf86SetModeCrtc(DisplayModePtr p, int adjustFlags) +{ + if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN)) + return; + + p->CrtcHDisplay = p->HDisplay; + p->CrtcHSyncStart = p->HSyncStart; + p->CrtcHSyncEnd = p->HSyncEnd; + p->CrtcHTotal = p->HTotal; + p->CrtcHSkew = p->HSkew; + p->CrtcVDisplay = p->VDisplay; + p->CrtcVSyncStart = p->VSyncStart; + p->CrtcVSyncEnd = p->VSyncEnd; + p->CrtcVTotal = p->VTotal; + if (p->Flags & V_INTERLACE) { + if (adjustFlags & INTERLACE_HALVE_V) { + p->CrtcVDisplay /= 2; + p->CrtcVSyncStart /= 2; + p->CrtcVSyncEnd /= 2; + p->CrtcVTotal /= 2; + } + /* Force interlaced modes to have an odd VTotal */ + /* maybe we should only do this when INTERLACE_HALVE_V is set? */ + p->CrtcVTotal |= 1; + } + + if (p->Flags & V_DBLSCAN) { + p->CrtcVDisplay *= 2; + p->CrtcVSyncStart *= 2; + p->CrtcVSyncEnd *= 2; + p->CrtcVTotal *= 2; + } + if (p->VScan > 1) { + p->CrtcVDisplay *= p->VScan; + p->CrtcVSyncStart *= p->VScan; + p->CrtcVSyncEnd *= p->VScan; + p->CrtcVTotal *= p->VScan; + } + p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay); + p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal); + p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay); + p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal); + + p->CrtcHAdjusted = FALSE; + p->CrtcVAdjusted = FALSE; +} + +/** + * Allocates and returns a copy of pMode, including pointers within pMode. + */ +DisplayModePtr +xf86DuplicateMode(const DisplayModeRec *pMode) +{ + DisplayModePtr pNew; + + pNew = xnfalloc(sizeof(DisplayModeRec)); + *pNew = *pMode; + pNew->next = NULL; + pNew->prev = NULL; + + if (pMode->name == NULL) + xf86SetModeDefaultName(pNew); + else + pNew->name = xnfstrdup(pMode->name); + + return pNew; +} + +/** + * Duplicates every mode in the given list and returns a pointer to the first + * mode. + * + * \param modeList doubly-linked mode list + */ +DisplayModePtr +xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList) +{ + DisplayModePtr first = NULL, last = NULL; + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + DisplayModePtr new; + + new = xf86DuplicateMode(mode); + + /* Insert pNew into modeList */ + if (last) { + last->next = new; + new->prev = last; + } else { + first = new; + new->prev = NULL; + } + new->next = NULL; + last = new; + } + + return first; +} + +/** + * Returns true if the given modes should program to the same timings. + * + * This doesn't use Crtc values, as it might be used on ModeRecs without the + * Crtc values set. So, it's assumed that the other numbers are enough. + */ +Bool +xf86ModesEqual(const DisplayModeRec *pMode1, const DisplayModeRec *pMode2) +{ + if (pMode1->Clock == pMode2->Clock && + pMode1->HDisplay == pMode2->HDisplay && + pMode1->HSyncStart == pMode2->HSyncStart && + pMode1->HSyncEnd == pMode2->HSyncEnd && + pMode1->HTotal == pMode2->HTotal && + pMode1->HSkew == pMode2->HSkew && + pMode1->VDisplay == pMode2->VDisplay && + pMode1->VSyncStart == pMode2->VSyncStart && + pMode1->VSyncEnd == pMode2->VSyncEnd && + pMode1->VTotal == pMode2->VTotal && + pMode1->VScan == pMode2->VScan && + pMode1->Flags == pMode2->Flags) + { + return TRUE; + } else { + return FALSE; + } +} + +static void +add(char **p, char *new) +{ + *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2); + strcat(*p, " "); + strcat(*p, new); +} + +/** + * Print out a modeline. + */ +void +xf86PrintModeline(int scrnIndex,DisplayModePtr mode) +{ + char tmp[256]; + char *flags = xnfcalloc(1, 1); + + if (mode->HSkew) { + snprintf(tmp, 256, "hskew %i", mode->HSkew); + add(&flags, tmp); + } + if (mode->VScan) { + snprintf(tmp, 256, "vscan %i", mode->VScan); + add(&flags, tmp); + } + if (mode->Flags & V_INTERLACE) add(&flags, "interlace"); + if (mode->Flags & V_CSYNC) add(&flags, "composite"); + if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan"); + if (mode->Flags & V_BCAST) add(&flags, "bcast"); + if (mode->Flags & V_PHSYNC) add(&flags, "+hsync"); + if (mode->Flags & V_NHSYNC) add(&flags, "-hsync"); + if (mode->Flags & V_PVSYNC) add(&flags, "+vsync"); + if (mode->Flags & V_NVSYNC) add(&flags, "-vsync"); + if (mode->Flags & V_PCSYNC) add(&flags, "+csync"); + if (mode->Flags & V_NCSYNC) add(&flags, "-csync"); +#if 0 + if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2"); +#endif + xf86DrvMsg(scrnIndex, X_INFO, + "Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s " + "(%.01f kHz)\n", + mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay, + mode->HSyncStart, mode->HSyncEnd, mode->HTotal, + mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, + mode->VTotal, flags, xf86ModeHSync(mode)); + free(flags); +} +#endif /* XORG_VERSION_CURRENT <= 7.2.99.2 */ + +/** + * Marks as bad any modes with unsupported flags. + * + * \param modeList doubly-linked list of modes. + * \param flags flags supported by the driver. + * + * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough? + */ +void +xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int flags) +{ + DisplayModePtr mode; + + if (flags == (V_INTERLACE | V_DBLSCAN)) + return; + + for (mode = modeList; mode != NULL; mode = mode->next) { + if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE)) + mode->status = MODE_NO_INTERLACE; + if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN)) + mode->status = MODE_NO_DBLESCAN; + } +} + +/** + * Marks as bad any modes extending beyond the given max X, Y, or pitch. + * + * \param modeList doubly-linked list of modes. + */ +void +xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int maxX, int maxY, int maxPitch) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + if (maxPitch > 0 && mode->HDisplay > maxPitch) + mode->status = MODE_BAD_WIDTH; + + if (maxX > 0 && mode->HDisplay > maxX) + mode->status = MODE_VIRTUAL_X; + + if (maxY > 0 && mode->VDisplay > maxY) + mode->status = MODE_VIRTUAL_Y; + + if (mode->next == modeList) + break; + } +} + +/** + * Marks as bad any modes that aren't supported by the given monitor's + * hsync and vrefresh ranges. + * + * \param modeList doubly-linked list of modes. + */ +void +xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList, + MonPtr mon) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + Bool bad; + int i; + + bad = TRUE; + for (i = 0; i < mon->nHsync; i++) { + if (xf86ModeHSync(mode) >= mon->hsync[i].lo * (1-SYNC_TOLERANCE) && + xf86ModeHSync(mode) <= mon->hsync[i].hi * (1+SYNC_TOLERANCE)) + { + bad = FALSE; + } + } + if (bad) + mode->status = MODE_HSYNC; + + bad = TRUE; + for (i = 0; i < mon->nVrefresh; i++) { + if (xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo * (1-SYNC_TOLERANCE) && + xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi * (1+SYNC_TOLERANCE)) + { + bad = FALSE; + } + } + if (bad) + mode->status = MODE_VSYNC; + + if (mode->next == modeList) + break; + } +} + +/** + * Marks as bad any modes extending beyond outside of the given clock ranges. + * + * \param modeList doubly-linked list of modes. + * \param min pointer to minimums of clock ranges + * \param max pointer to maximums of clock ranges + * \param n_ranges number of ranges. + */ +void +xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int *min, int *max, int n_ranges) +{ + DisplayModePtr mode; + int i; + + for (mode = modeList; mode != NULL; mode = mode->next) { + Bool good = FALSE; + for (i = 0; i < n_ranges; i++) { + if (mode->Clock >= min[i] * (1-SYNC_TOLERANCE) && + mode->Clock <= max[i] * (1+SYNC_TOLERANCE)) { + good = TRUE; + break; + } + } + if (!good) + mode->status = MODE_CLOCK_RANGE; + } +} + +/** + * If the user has specified a set of mode names to use, mark as bad any modes + * not listed. + * + * The user mode names specified are prefixes to names of modes, so "1024x768" + * will match modes named "1024x768", "1024x768x75", "1024x768-good", but + * "1024x768x75" would only match "1024x768x75" from that list. + * + * MODE_BAD is used as the rejection flag, for lack of a better flag. + * + * \param modeList doubly-linked list of modes. + */ +void +xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList) +{ + DisplayModePtr mode; + + if (pScrn->display->modes[0] == NULL) + return; + + for (mode = modeList; mode != NULL; mode = mode->next) { + int i; + Bool good = FALSE; + + for (i = 0; pScrn->display->modes[i] != NULL; i++) { + if (strncmp(pScrn->display->modes[i], mode->name, + strlen(pScrn->display->modes[i])) == 0) { + good = TRUE; + break; + } + } + if (!good) + mode->status = MODE_BAD; + } +} + + +/** + * Marks as bad any modes exceeding the given bandwidth. + * + * \param modeList doubly-linked list of modes. + * \param bandwidth bandwidth in MHz. + * \param depth color depth. + */ +void +xf86ValidateModesBandwidth(ScrnInfoPtr pScrn, DisplayModePtr modeList, + unsigned int bandwidth, int depth) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + if (xf86ModeBandwidth(mode, depth) > bandwidth) +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + mode->status = MODE_BANDWIDTH; +#else + /* MODE_BANDWIDTH didn't exist in xserver 1.2 */ + mode->status = MODE_BAD; +#endif + } +} + +Bool +xf86ModeIsReduced(const DisplayModeRec *mode) +{ + if ((((mode->HDisplay * 5 / 4) & ~0x07) > mode->HTotal) && + ((mode->HTotal - mode->HDisplay) == 160) && + ((mode->HSyncEnd - mode->HDisplay) == 80) && + ((mode->HSyncEnd - mode->HSyncStart) == 32) && + ((mode->VSyncStart - mode->VDisplay) == 3)) + return TRUE; + return FALSE; +} + +/** + * Marks as bad any reduced-blanking modes. + * + * \param modeList doubly-linked list of modes. + */ +void +xf86ValidateModesReducedBlanking(ScrnInfoPtr pScrn, DisplayModePtr modeList) +{ + for (; modeList != NULL; modeList = modeList->next) + if (xf86ModeIsReduced(modeList)) + modeList->status = MODE_NO_REDUCED; +} + +/** + * Frees any modes from the list with a status other than MODE_OK. + * + * \param modeList pointer to a doubly-linked or circular list of modes. + * \param verbose determines whether the reason for mode invalidation is + * printed. + */ +void +xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, + Bool verbose) +{ + DisplayModePtr mode; + + for (mode = *modeList; mode != NULL;) { + DisplayModePtr next = mode->next, first = *modeList; + + if (mode->status != MODE_OK) { + if (verbose) { + char *type = ""; + if (mode->type & M_T_BUILTIN) + type = "built-in "; + else if (mode->type & M_T_DEFAULT) + type = "default "; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Not using %smode \"%s\" (%s)\n", type, mode->name, + xf86ModeStatusToString(mode->status)); + } + xf86DeleteMode(modeList, mode); + } + + if (next == first) + break; + mode = next; + } +} + +/** + * Adds the new mode into the mode list, and returns the new list + * + * \param modes doubly-linked mode list. + */ +DisplayModePtr +xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new) +{ + if (modes == NULL) + return new; + + if (new) { + DisplayModePtr mode = modes; + + while (mode->next) + mode = mode->next; + + mode->next = new; + new->prev = mode; + } + + return modes; +} + +/** + * Build a mode list from a list of config file modes + */ +static DisplayModePtr +xf86GetConfigModes (XF86ConfModeLinePtr conf_mode) +{ + DisplayModePtr head = NULL, prev = NULL, mode; + + for (; conf_mode; conf_mode = (XF86ConfModeLinePtr) conf_mode->list.next) + { + mode = calloc(1, sizeof(DisplayModeRec)); + if (!mode) + continue; + mode->name = xstrdup(conf_mode->ml_identifier); + if (!mode->name) + { + free(mode); + continue; + } + mode->type = 0; + mode->Clock = conf_mode->ml_clock; + mode->HDisplay = conf_mode->ml_hdisplay; + mode->HSyncStart = conf_mode->ml_hsyncstart; + mode->HSyncEnd = conf_mode->ml_hsyncend; + mode->HTotal = conf_mode->ml_htotal; + mode->VDisplay = conf_mode->ml_vdisplay; + mode->VSyncStart = conf_mode->ml_vsyncstart; + mode->VSyncEnd = conf_mode->ml_vsyncend; + mode->VTotal = conf_mode->ml_vtotal; + mode->Flags = conf_mode->ml_flags; + mode->HSkew = conf_mode->ml_hskew; + mode->VScan = conf_mode->ml_vscan; + + mode->prev = prev; + mode->next = NULL; + if (prev) + prev->next = mode; + else + head = mode; + prev = mode; + } + return head; +} + +/** + * Build a mode list from a monitor configuration + */ +DisplayModePtr +xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor) +{ + DisplayModePtr modes = NULL; + XF86ConfModesLinkPtr modes_link; + + if (!conf_monitor) + return NULL; + + /* + * first we collect the mode lines from the UseModes directive + */ + for (modes_link = conf_monitor->mon_modes_sect_lst; + modes_link; + modes_link = modes_link->list.next) + { + /* If this modes link hasn't been resolved, go look it up now */ + if (!modes_link->ml_modes) + modes_link->ml_modes = xf86findModes (modes_link->ml_modes_str, + xf86configptr->conf_modes_lst); + if (modes_link->ml_modes) + modes = xf86ModesAdd (modes, + xf86GetConfigModes (modes_link->ml_modes->mon_modeline_lst)); + } + + return xf86ModesAdd (modes, + xf86GetConfigModes (conf_monitor->mon_modeline_lst)); +} + +/** + * Build a mode list containing all of the default modes + */ +DisplayModePtr +xf86GetDefaultModes (void) +{ + DisplayModePtr head = NULL, mode; + int i; + + for (i = 0; i < xf86NumDefaultModes; i++) + { + const DisplayModeRec *defMode = &xf86DefaultModes[i]; + + mode = xf86DuplicateMode(defMode); + head = xf86ModesAdd(head, mode); + } + return head; +} + +/* + * Walk a mode list and prune out duplicates. Will preserve the preferred + * mode of an otherwise-duplicate pair. + * + * Probably best to call this on lists that are all of a single class + * (driver, default, user, etc.), otherwise, which mode gets deleted is + * not especially well defined. + * + * Returns the new list. + */ + +DisplayModePtr +xf86PruneDuplicateModes(DisplayModePtr modes) +{ + DisplayModePtr m, n, o; + +top: + for (m = modes; m; m = m->next) { + for (n = m->next; n; n = o) { + o = n->next; + if (xf86ModesEqual(m, n)) { + if (n->type & M_T_PREFERRED) { + xf86DeleteMode(&modes, m); + goto top; + } + else + xf86DeleteMode(&modes, n); + } + } + } + + return modes; +} diff --git a/xorg-server/hw/xfree86/modes/xf86RandR12.c b/xorg-server/hw/xfree86/modes/xf86RandR12.c index 8898f4dad..8a4d72bd6 100644 --- a/xorg-server/hw/xfree86/modes/xf86RandR12.c +++ b/xorg-server/hw/xfree86/modes/xf86RandR12.c @@ -1,1810 +1,1810 @@ -/* - * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. - * - * 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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_XORG_CONFIG_H -#include <xorg-config.h> -#else -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#endif - -#include "xf86.h" -#include "os.h" -#include "globals.h" -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86DDC.h" -#include "mipointer.h" -#include "windowstr.h" -#include "inputstr.h" -#include <randrstr.h> -#include <X11/extensions/render.h> - -#include "xf86Crtc.h" -#include "xf86RandR12.h" - -typedef struct _xf86RandR12Info { - int virtualX; - int virtualY; - int mmWidth; - int mmHeight; - int maxX; - int maxY; - int pointerX; - int pointerY; - Rotation rotation; /* current mode */ - Rotation supported_rotations; /* driver supported */ - - /* Used to wrap EnterVT so we can re-probe the outputs when a laptop unsuspends - * (actually, any time that we switch back into our VT). - * - * See https://bugs.freedesktop.org/show_bug.cgi?id=21554 - */ - xf86EnterVTProc *orig_EnterVT; -} XF86RandRInfoRec, *XF86RandRInfoPtr; - -#ifdef RANDR_12_INTERFACE -static Bool xf86RandR12Init12 (ScreenPtr pScreen); -static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen); -#endif - -static int xf86RandR12Generation; -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - -static int xf86RandR12KeyIndex; -static DevPrivateKey xf86RandR12Key; -#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) \ - dixLookupPrivate(&(p)->devPrivates, xf86RandR12Key)) - -#else /* XORG_VERSION_CURRENT < 7.0 */ - -static int xf86RandR12Index; -#define XF86RANDRINFO(p) \ - ((XF86RandRInfoPtr)(p)->devPrivates[xf86RandR12Index].ptr) - -#endif /* XORG_VERSION_CURRENT < 7.0 */ - - -static int -xf86RandR12ModeRefresh (DisplayModePtr mode) -{ - if (mode->VRefresh) - return (int) (mode->VRefresh + 0.5); - else - return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); -} - -/* Adapt panning area; return TRUE if panning area was valid without adaption */ -static int -xf86RandR13VerifyPanningArea (xf86CrtcPtr crtc, int screenWidth, int screenHeight) -{ - int ret = TRUE; - - if (crtc->version < 2) - return FALSE; - - if (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1) { - /* Panning in X is disabled */ - if (crtc->panningTotalArea.x1 || crtc->panningTotalArea.x2) - /* Illegal configuration -> fail/disable */ - ret = FALSE; - crtc->panningTotalArea.x1 = crtc->panningTotalArea.x2 = 0; - crtc->panningTrackingArea.x1 = crtc->panningTrackingArea.x2 = 0; - crtc->panningBorder[0] = crtc->panningBorder[2] = 0; - } else { - /* Panning in X is enabled */ - if (crtc->panningTotalArea.x1 < 0) { - /* Panning region outside screen -> move inside */ - crtc->panningTotalArea.x2 -= crtc->panningTotalArea.x1; - crtc->panningTotalArea.x1 = 0; - ret = FALSE; - } - if (crtc->panningTotalArea.x2 < crtc->panningTotalArea.x1 + crtc->mode.HDisplay) { - /* Panning region smaller than displayed area -> crop to displayed area */ - crtc->panningTotalArea.x2 = crtc->panningTotalArea.x1 + crtc->mode.HDisplay; - ret = FALSE; - } - if (crtc->panningTotalArea.x2 > screenWidth) { - /* Panning region larger than screen -> move inside, then crop to screen */ - crtc->panningTotalArea.x1 -= crtc->panningTotalArea.x2 - screenWidth; - crtc->panningTotalArea.x2 = screenWidth; - ret = FALSE; - if (crtc->panningTotalArea.x1 < 0) - crtc->panningTotalArea.x1 = 0; - } - if (crtc->panningBorder[0] + crtc->panningBorder[2] > crtc->mode.HDisplay) { - /* Borders too large -> set to 0 */ - crtc->panningBorder[0] = crtc->panningBorder[2] = 0; - ret = FALSE; - } - } - - if (crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1) { - /* Panning in Y is disabled */ - if (crtc->panningTotalArea.y1 || crtc->panningTotalArea.y2) - /* Illegal configuration -> fail/disable */ - ret = FALSE; - crtc->panningTotalArea.y1 = crtc->panningTotalArea.y2 = 0; - crtc->panningTrackingArea.y1 = crtc->panningTrackingArea.y2 = 0; - crtc->panningBorder[1] = crtc->panningBorder[3] = 0; - } else { - /* Panning in Y is enabled */ - if (crtc->panningTotalArea.y1 < 0) { - /* Panning region outside screen -> move inside */ - crtc->panningTotalArea.y2 -= crtc->panningTotalArea.y1; - crtc->panningTotalArea.y1 = 0; - ret = FALSE; - } - if (crtc->panningTotalArea.y2 < crtc->panningTotalArea.y1 + crtc->mode.VDisplay) { - /* Panning region smaller than displayed area -> crop to displayed area */ - crtc->panningTotalArea.y2 = crtc->panningTotalArea.y1 + crtc->mode.VDisplay; - ret = FALSE; - } - if (crtc->panningTotalArea.y2 > screenHeight) { - /* Panning region larger than screen -> move inside, then crop to screen */ - crtc->panningTotalArea.y1 -= crtc->panningTotalArea.y2 - screenHeight; - crtc->panningTotalArea.y2 = screenHeight; - ret = FALSE; - if (crtc->panningTotalArea.y1 < 0) - crtc->panningTotalArea.y1 = 0; - } - if (crtc->panningBorder[1] + crtc->panningBorder[3] > crtc->mode.VDisplay) { - /* Borders too large -> set to 0 */ - crtc->panningBorder[1] = crtc->panningBorder[3] = 0; - ret = FALSE; - } - } - - return ret; -} - -/* - * The heart of the panning operation: - * - * Given a frame buffer position (fb_x, fb_y), - * and a crtc position (crtc_x, crtc_y), - * and a transform matrix which maps frame buffer to crtc, - * compute a panning position (pan_x, pan_y) that - * makes the resulting transform line those two up - */ - -static void -xf86ComputeCrtcPan (Bool transform_in_use, - struct pixman_f_transform *m, - double screen_x, double screen_y, - double crtc_x, double crtc_y, - int old_pan_x, int old_pan_y, - int *new_pan_x, int *new_pan_y) -{ - if (transform_in_use) { - /* - * Given the current transform, M, the current position - * on the Screen, S, and the desired position on the CRTC, - * C, compute a translation, T, such that: - * - * M T S = C - * - * where T is of the form - * - * | 1 0 dx | - * | 0 1 dy | - * | 0 0 1 | - * - * M T S = - * | M00 Sx + M01 Sy + M00 dx + M01 dy + M02 | | Cx F | - * | M10 Sx + M11 Sy + M10 dx + M11 dy + M12 | = | Cy F | - * | M20 Sx + M21 Sy + M20 dx + M21 dy + M22 | | F | - * - * R = M S - * - * Cx F = M00 dx + M01 dy + R0 - * Cy F = M10 dx + M11 dy + R1 - * F = M20 dx + M21 dy + R2 - * - * Zero out dx, then dy - * - * F (Cx M10 - Cy M00) = - * (M10 M01 - M00 M11) dy + M10 R0 - M00 R1 - * F (M10 - Cy M20) = - * (M10 M21 - M20 M11) dy + M10 R2 - M20 R1 - * - * F (Cx M11 - Cy M01) = - * (M11 M00 - M01 M10) dx + M11 R0 - M01 R1 - * F (M11 - Cy M21) = - * (M11 M20 - M21 M10) dx + M11 R2 - M21 R1 - * - * Make some temporaries - * - * T = | Cx M10 - Cy M00 | - * | Cx M11 - Cy M01 | - * - * U = | M10 M01 - M00 M11 | - * | M11 M00 - M01 M10 | - * - * Q = | M10 R0 - M00 R1 | - * | M11 R0 - M01 R1 | - * - * P = | M10 - Cy M20 | - * | M11 - Cy M21 | - * - * W = | M10 M21 - M20 M11 | - * | M11 M20 - M21 M10 | - * - * V = | M10 R2 - M20 R1 | - * | M11 R2 - M21 R1 | - * - * Rewrite: - * - * F T0 = U0 dy + Q0 - * F P0 = W0 dy + V0 - * F T1 = U1 dx + Q1 - * F P1 = W1 dx + V1 - * - * Solve for F (two ways) - * - * F (W0 T0 - U0 P0) = W0 Q0 - U0 V0 - * - * W0 Q0 - U0 V0 - * F = ------------- - * W0 T0 - U0 P0 - * - * F (W1 T1 - U1 P1) = W1 Q1 - U1 V1 - * - * W1 Q1 - U1 V1 - * F = ------------- - * W1 T1 - U1 P1 - * - * We'll use which ever solution works (denominator != 0) - * - * Finally, solve for dx and dy: - * - * dx = (F T1 - Q1) / U1 - * dx = (F P1 - V1) / W1 - * - * dy = (F T0 - Q0) / U0 - * dy = (F P0 - V0) / W0 - */ - double r[3]; - double q[2], u[2], t[2], v[2], w[2], p[2]; - double f; - struct pict_f_vector d; - int i; - - /* Get the un-normalized crtc coordinates again */ - for (i = 0; i < 3; i++) - r[i] = m->m[i][0] * screen_x + m->m[i][1] * screen_y + m->m[i][2]; - - /* Combine values into temporaries */ - for (i = 0; i < 2; i++) { - q[i] = m->m[1][i] * r[0] - m->m[0][i] * r[1]; - u[i] = m->m[1][i] * m->m[0][1-i] - m->m[0][i] * m->m[1][1-i]; - t[i] = m->m[1][i] * crtc_x - m->m[0][i] * crtc_y; - - v[i] = m->m[1][i] * r[2] - m->m[2][i] * r[1]; - w[i] = m->m[1][i] * m->m[2][1-i] - m->m[2][i] * m->m[1][1-i]; - p[i] = m->m[1][i] - m->m[2][i] * crtc_y; - } - - /* Find a way to compute f */ - f = 0; - for (i = 0; i < 2; i++) { - double a = w[i] * q[i] - u[i] * v[i]; - double b = w[i] * t[i] - u[i] * p[i]; - if (b != 0) { - f = a/b; - break; - } - } - - /* Solve for the resulting transform vector */ - for (i = 0; i < 2; i++) { - if (u[i]) - d.v[1-i] = (t[i] * f - q[i]) / u[i]; - else if (w[1]) - d.v[1-i] = (p[i] * f - v[i]) / w[i]; - else - d.v[1-i] = 0; - } - *new_pan_x = old_pan_x - floor (d.v[0] + 0.5); - *new_pan_y = old_pan_y - floor (d.v[1] + 0.5); - } else { - *new_pan_x = screen_x - crtc_x; - *new_pan_y = screen_y - crtc_y; - } -} - -static void -xf86RandR13Pan (xf86CrtcPtr crtc, int x, int y) -{ - int newX, newY; - int width, height; - Bool panned = FALSE; - - if (crtc->version < 2) - return; - - if (! crtc->enabled || - (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1 && - crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1)) - return; - - newX = crtc->x; - newY = crtc->y; - width = crtc->mode.HDisplay; - height = crtc->mode.VDisplay; - - if ((crtc->panningTrackingArea.x2 <= crtc->panningTrackingArea.x1 || - (x >= crtc->panningTrackingArea.x1 && x < crtc->panningTrackingArea.x2)) && - (crtc->panningTrackingArea.y2 <= crtc->panningTrackingArea.y1 || - (y >= crtc->panningTrackingArea.y1 && y < crtc->panningTrackingArea.y2))) - { - struct pict_f_vector c; - - /* - * Pre-clip the mouse position to the panning area so that we don't - * push the crtc outside. This doesn't deal with changes to the - * panning values, only mouse position changes. - */ - if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) - { - if (x < crtc->panningTotalArea.x1) - x = crtc->panningTotalArea.x1; - if (x >= crtc->panningTotalArea.x2) - x = crtc->panningTotalArea.x2 - 1; - } - if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) - { - if (y < crtc->panningTotalArea.y1) - y = crtc->panningTotalArea.y1; - if (y >= crtc->panningTotalArea.y2) - y = crtc->panningTotalArea.y2 - 1; - } - - c.v[0] = x; - c.v[1] = y; - c.v[2] = 1.0; - if (crtc->transform_in_use) { - pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &c); - } else { - c.v[0] -= crtc->x; - c.v[1] -= crtc->y; - } - - if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) { - if (c.v[0] < crtc->panningBorder[0]) { - c.v[0] = crtc->panningBorder[0]; - panned = TRUE; - } - if (c.v[0] >= width - crtc->panningBorder[2]) { - c.v[0] = width - crtc->panningBorder[2] - 1; - panned = TRUE; - } - } - if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { - if (c.v[1] < crtc->panningBorder[1]) { - c.v[1] = crtc->panningBorder[1]; - panned = TRUE; - } - if (c.v[1] >= height - crtc->panningBorder[3]) { - c.v[1] = height - crtc->panningBorder[3] - 1; - panned = TRUE; - } - } - if (panned) - xf86ComputeCrtcPan (crtc->transform_in_use, - &crtc->f_framebuffer_to_crtc, - x, y, c.v[0], c.v[1], - newX, newY, &newX, &newY); - } - - /* - * Ensure that the crtc is within the panning region. - * - * XXX This computation only works when we do not have a transform - * in use. - */ - if (!crtc->transform_in_use) - { - /* Validate against [xy]1 after [xy]2, to be sure that results are > 0 for [xy]1 > 0 */ - if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) { - if (newX > crtc->panningTotalArea.x2 - width) - newX = crtc->panningTotalArea.x2 - width; - if (newX < crtc->panningTotalArea.x1) - newX = crtc->panningTotalArea.x1; - } - if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { - if (newY > crtc->panningTotalArea.y2 - height) - newY = crtc->panningTotalArea.y2 - height; - if (newY < crtc->panningTotalArea.y1) - newY = crtc->panningTotalArea.y1; - } - } - if (newX != crtc->x || newY != crtc->y) - xf86CrtcSetOrigin (crtc, newX, newY); -} - -static Bool -xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations) -{ - RRScreenSizePtr pSize; - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - DisplayModePtr mode; - int refresh0 = 60; - int maxX = 0, maxY = 0; - - *rotations = randrp->supported_rotations; - - if (randrp->virtualX == -1 || randrp->virtualY == -1) - { - randrp->virtualX = scrp->virtualX; - randrp->virtualY = scrp->virtualY; - } - - /* Re-probe the outputs for new monitors or modes */ - if (scrp->vtSema) - { - xf86ProbeOutputModes (scrp, 0, 0); - xf86SetScrnInfoModes (scrp); - } - - for (mode = scrp->modes; ; mode = mode->next) - { - int refresh = xf86RandR12ModeRefresh (mode); - if (randrp->maxX == 0 || randrp->maxY == 0) - { - if (maxX < mode->HDisplay) - maxX = mode->HDisplay; - if (maxY < mode->VDisplay) - maxY = mode->VDisplay; - } - if (mode == scrp->modes) - refresh0 = refresh; - pSize = RRRegisterSize (pScreen, - mode->HDisplay, mode->VDisplay, - randrp->mmWidth, randrp->mmHeight); - if (!pSize) - return FALSE; - RRRegisterRate (pScreen, pSize, refresh); - - if (xf86ModesEqual(mode, scrp->currentMode)) - { - RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); - } - if (mode->next == scrp->modes) - break; - } - - if (randrp->maxX == 0 || randrp->maxY == 0) - { - randrp->maxX = maxX; - randrp->maxY = maxY; - } - - return TRUE; -} - -static Bool -xf86RandR12SetMode (ScreenPtr pScreen, - DisplayModePtr mode, - Bool useVirtual, - int mmWidth, - int mmHeight) -{ - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - int oldWidth = pScreen->width; - int oldHeight = pScreen->height; - int oldmmWidth = pScreen->mmWidth; - int oldmmHeight = pScreen->mmHeight; - WindowPtr pRoot = WindowTable[pScreen->myNum]; - DisplayModePtr currentMode = NULL; - Bool ret = TRUE; - PixmapPtr pspix = NULL; - - if (pRoot) - (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); - if (useVirtual) - { - scrp->virtualX = randrp->virtualX; - scrp->virtualY = randrp->virtualY; - } - else - { - scrp->virtualX = mode->HDisplay; - scrp->virtualY = mode->VDisplay; - } - - if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) - { - /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ - pScreen->width = scrp->virtualY; - pScreen->height = scrp->virtualX; - pScreen->mmWidth = mmHeight; - pScreen->mmHeight = mmWidth; - } - else - { - pScreen->width = scrp->virtualX; - pScreen->height = scrp->virtualY; - pScreen->mmWidth = mmWidth; - pScreen->mmHeight = mmHeight; - } - if (scrp->currentMode == mode) { - /* Save current mode */ - currentMode = scrp->currentMode; - /* Reset, just so we ensure the drivers SwitchMode is called */ - scrp->currentMode = NULL; - } - /* - * We know that if the driver failed to SwitchMode to the rotated - * version, then it should revert back to it's prior mode. - */ - if (!xf86SwitchMode (pScreen, mode)) - { - ret = FALSE; - scrp->virtualX = pScreen->width = oldWidth; - scrp->virtualY = pScreen->height = oldHeight; - pScreen->mmWidth = oldmmWidth; - pScreen->mmHeight = oldmmHeight; - scrp->currentMode = currentMode; - } - /* - * Get the new Screen pixmap ptr as SwitchMode might have called - * ModifyPixmapHeader and xf86EnableDisableFBAccess will put it back... - * Unfortunately. - */ - pspix = (*pScreen->GetScreenPixmap) (pScreen); - if (pspix->devPrivate.ptr) - scrp->pixmapPrivate = pspix->devPrivate; - - /* - * Make sure the layout is correct - */ - xf86ReconfigureLayout(); - - /* - * Make sure the whole screen is visible - */ - xf86SetViewport (pScreen, pScreen->width, pScreen->height); - xf86SetViewport (pScreen, 0, 0); - if (pRoot) - (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); - return ret; -} - -Bool -xf86RandR12SetConfig (ScreenPtr pScreen, - Rotation rotation, - int rate, - RRScreenSizePtr pSize) -{ - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - DisplayModePtr mode; - int px, py; - Bool useVirtual = FALSE; - int maxX = 0, maxY = 0; - Rotation oldRotation = randrp->rotation; - - randrp->rotation = rotation; - - if (randrp->virtualX == -1 || randrp->virtualY == -1) - { - randrp->virtualX = scrp->virtualX; - randrp->virtualY = scrp->virtualY; - } - - miPointerGetPosition (inputInfo.pointer, &px, &py); - for (mode = scrp->modes; ; mode = mode->next) - { - if (randrp->maxX == 0 || randrp->maxY == 0) - { - if (maxX < mode->HDisplay) - maxX = mode->HDisplay; - if (maxY < mode->VDisplay) - maxY = mode->VDisplay; - } - if (mode->HDisplay == pSize->width && - mode->VDisplay == pSize->height && - (rate == 0 || xf86RandR12ModeRefresh (mode) == rate)) - break; - if (mode->next == scrp->modes) - { - if (pSize->width == randrp->virtualX && - pSize->height == randrp->virtualY) - { - mode = scrp->modes; - useVirtual = TRUE; - break; - } - if (randrp->maxX == 0 || randrp->maxY == 0) - { - randrp->maxX = maxX; - randrp->maxY = maxY; - } - return FALSE; - } - } - - if (randrp->maxX == 0 || randrp->maxY == 0) - { - randrp->maxX = maxX; - randrp->maxY = maxY; - } - - if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth, - pSize->mmHeight)) { - randrp->rotation = oldRotation; - return FALSE; - } - - /* - * Move the cursor back where it belongs; SwitchMode repositions it - */ - if (pScreen == miPointerGetScreen(inputInfo.pointer)) - { - px = (px >= pScreen->width ? (pScreen->width - 1) : px); - py = (py >= pScreen->height ? (pScreen->height - 1) : py); - - xf86SetViewport(pScreen, px, py); - - (*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE); - } - - return TRUE; -} - -static Bool -xf86RandR12ScreenSetSize (ScreenPtr pScreen, - CARD16 width, - CARD16 height, - CARD32 mmWidth, - CARD32 mmHeight) -{ - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - WindowPtr pRoot = WindowTable[pScreen->myNum]; - PixmapPtr pScrnPix = (*pScreen->GetScreenPixmap)(pScreen); - Bool ret = FALSE; - int c; - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - if (xf86RandR12Key) { -#endif - if (randrp->virtualX == -1 || randrp->virtualY == -1) - { - randrp->virtualX = pScrn->virtualX; - randrp->virtualY = pScrn->virtualY; - } -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - } -#endif - if (pRoot && pScrn->vtSema) - (*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE); - - /* Let the driver update virtualX and virtualY */ - if (!(*config->funcs->resize)(pScrn, width, height)) - goto finish; - - ret = TRUE; - /* Update panning information */ - for (c = 0; c < config->num_crtc; c++) { - xf86CrtcPtr crtc = config->crtc[c]; - if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1 || - crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { - if (crtc->panningTotalArea.x2 > crtc->panningTrackingArea.x1) - crtc->panningTotalArea.x2 += width - pScreen->width; - if (crtc->panningTotalArea.y2 > crtc->panningTrackingArea.y1) - crtc->panningTotalArea.y2 += height - pScreen->height; - if (crtc->panningTrackingArea.x2 > crtc->panningTrackingArea.x1) - crtc->panningTrackingArea.x2 += width - pScreen->width; - if (crtc->panningTrackingArea.y2 > crtc->panningTrackingArea.y1) - crtc->panningTrackingArea.y2 += height - pScreen->height; - xf86RandR13VerifyPanningArea (crtc, width, height); - xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY); - } - } - - pScreen->width = pScrnPix->drawable.width = width; - pScreen->height = pScrnPix->drawable.height = height; - randrp->mmWidth = pScreen->mmWidth = mmWidth; - randrp->mmHeight = pScreen->mmHeight = mmHeight; - - xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1); - xf86SetViewport (pScreen, 0, 0); - -finish: - if (pRoot && pScrn->vtSema) - (*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE); -#if RANDR_12_INTERFACE - if (xf86RandR12Key && WindowTable[pScreen->myNum] && ret) - RRScreenSizeNotify (pScreen); -#endif - return ret; -} - -Rotation -xf86RandR12GetRotation(ScreenPtr pScreen) -{ - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - - return randrp->rotation; -} - -Bool -xf86RandR12CreateScreenResources (ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr config; - XF86RandRInfoPtr randrp; - int c; - int width, height; - int mmWidth, mmHeight; -#ifdef PANORAMIX - /* XXX disable RandR when using Xinerama */ - if (!noPanoramiXExtension) - return TRUE; -#endif - - config = XF86_CRTC_CONFIG_PTR(pScrn); - randrp = XF86RANDRINFO(pScreen); - /* - * Compute size of screen - */ - width = 0; height = 0; - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - int crtc_width = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); - int crtc_height = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); - - if (crtc->enabled) { - if (crtc_width > width) - width = crtc_width; - if (crtc_height > height) - height = crtc_height; - if (crtc->panningTotalArea.x2 > width) - width = crtc->panningTotalArea.x2; - if (crtc->panningTotalArea.y2 > height) - height = crtc->panningTotalArea.y2; - } - } - - if (width && height) - { - /* - * Compute physical size of screen - */ - if (monitorResolution) - { - mmWidth = width * 25.4 / monitorResolution; - mmHeight = height * 25.4 / monitorResolution; - } - else - { - xf86OutputPtr output = xf86CompatOutput(pScrn); - - if (output && - output->conf_monitor && - (output->conf_monitor->mon_width > 0 && - output->conf_monitor->mon_height > 0)) - { - /* - * Prefer user configured DisplaySize - */ - mmWidth = output->conf_monitor->mon_width; - mmHeight = output->conf_monitor->mon_height; - } - else - { - /* - * Otherwise, just set the screen to DEFAULT_DPI - */ - mmWidth = width * 25.4 / DEFAULT_DPI; - mmHeight = height * 25.4 / DEFAULT_DPI; - } - } - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Setting screen physical size to %d x %d\n", - mmWidth, mmHeight); - /* - * This is the initial setting of the screen size. - * We have to pre-set it here, otherwise panning would be adapted - * to the new screen size. - */ - pScreen->width = width; - pScreen->height = height; - xf86RandR12ScreenSetSize (pScreen, - width, - height, - mmWidth, - mmHeight); - } - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - if (xf86RandR12Key == NULL) - return TRUE; -#endif - - if (randrp->virtualX == -1 || randrp->virtualY == -1) - { - randrp->virtualX = pScrn->virtualX; - randrp->virtualY = pScrn->virtualY; - } - xf86CrtcSetScreenSubpixelOrder (pScreen); -#if RANDR_12_INTERFACE - if (xf86RandR12CreateScreenResources12 (pScreen)) - return TRUE; -#endif - return TRUE; -} - - -Bool -xf86RandR12Init (ScreenPtr pScreen) -{ - rrScrPrivPtr rp; - XF86RandRInfoPtr randrp; - -#ifdef PANORAMIX - /* XXX disable RandR when using Xinerama */ - if (!noPanoramiXExtension) - { - if (xf86NumScreens == 1) - noPanoramiXExtension = TRUE; - else - return TRUE; - } -#endif - - if (xf86RandR12Generation != serverGeneration) - xf86RandR12Generation = serverGeneration; - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - xf86RandR12Key = &xf86RandR12KeyIndex; -#else - xf86RandR12Index = AllocateScreenPrivateIndex(); -#endif - - randrp = xalloc (sizeof (XF86RandRInfoRec)); - if (!randrp) - return FALSE; - - if (!RRScreenInit(pScreen)) - { - xfree (randrp); - return FALSE; - } - rp = rrGetScrPriv(pScreen); - rp->rrGetInfo = xf86RandR12GetInfo; - rp->rrSetConfig = xf86RandR12SetConfig; - - randrp->virtualX = -1; - randrp->virtualY = -1; - randrp->mmWidth = pScreen->mmWidth; - randrp->mmHeight = pScreen->mmHeight; - - randrp->rotation = RR_Rotate_0; /* initial rotated mode */ - - randrp->supported_rotations = RR_Rotate_0; - - randrp->maxX = randrp->maxY = 0; - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - dixSetPrivate(&pScreen->devPrivates, xf86RandR12Key, randrp); -#else - pScreen->devPrivates[xf86RandR12Index].ptr = randrp; -#endif - -#if RANDR_12_INTERFACE - if (!xf86RandR12Init12 (pScreen)) - return FALSE; -#endif - return TRUE; -} - -void -xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations) -{ - XF86RandRInfoPtr randrp; -#if RANDR_12_INTERFACE - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - int c; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); -#endif - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - if (xf86RandR12Key == NULL) - return; -#endif - - randrp = XF86RANDRINFO(pScreen); -#if RANDR_12_INTERFACE - for (c = 0; c < config->num_crtc; c++) { - xf86CrtcPtr crtc = config->crtc[c]; - - RRCrtcSetRotations (crtc->randr_crtc, rotations); - } -#endif - randrp->supported_rotations = rotations; -} - -void -xf86RandR12SetTransformSupport (ScreenPtr pScreen, Bool transforms) -{ - XF86RandRInfoPtr randrp; -#if RANDR_13_INTERFACE - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - int c; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); -#endif - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - if (xf86RandR12Key == NULL) - return; -#endif - - randrp = XF86RANDRINFO(pScreen); -#if RANDR_13_INTERFACE - for (c = 0; c < config->num_crtc; c++) { - xf86CrtcPtr crtc = config->crtc[c]; - - RRCrtcSetTransformSupport (crtc->randr_crtc, transforms); - } -#endif -} - -void -xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y) -{ - ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; - - if (xf86RandR12Generation != serverGeneration || - XF86RANDRINFO(pScreen)->virtualX == -1) - { - *x = pScrn->virtualX; - *y = pScrn->virtualY; - } else { - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - - *x = randrp->virtualX; - *y = randrp->virtualY; - } -} - -#if RANDR_12_INTERFACE - -#define FLAG_BITS (RR_HSyncPositive | \ - RR_HSyncNegative | \ - RR_VSyncPositive | \ - RR_VSyncNegative | \ - RR_Interlace | \ - RR_DoubleScan | \ - RR_CSync | \ - RR_CSyncPositive | \ - RR_CSyncNegative | \ - RR_HSkewPresent | \ - RR_BCast | \ - RR_PixelMultiplex | \ - RR_DoubleClock | \ - RR_ClockDivideBy2) - -static Bool -xf86RandRModeMatches (RRModePtr randr_mode, - DisplayModePtr mode) -{ -#if 0 - if (match_name) - { - /* check for same name */ - int len = strlen (mode->name); - if (randr_mode->mode.nameLength != len) return FALSE; - if (memcmp (randr_mode->name, mode->name, len) != 0) return FALSE; - } -#endif - - /* check for same timings */ - if (randr_mode->mode.dotClock / 1000 != mode->Clock) return FALSE; - if (randr_mode->mode.width != mode->HDisplay) return FALSE; - if (randr_mode->mode.hSyncStart != mode->HSyncStart) return FALSE; - if (randr_mode->mode.hSyncEnd != mode->HSyncEnd) return FALSE; - if (randr_mode->mode.hTotal != mode->HTotal) return FALSE; - if (randr_mode->mode.hSkew != mode->HSkew) return FALSE; - if (randr_mode->mode.height != mode->VDisplay) return FALSE; - if (randr_mode->mode.vSyncStart != mode->VSyncStart) return FALSE; - if (randr_mode->mode.vSyncEnd != mode->VSyncEnd) return FALSE; - if (randr_mode->mode.vTotal != mode->VTotal) return FALSE; - - /* check for same flags (using only the XF86 valid flag bits) */ - if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS)) - return FALSE; - - /* everything matches */ - return TRUE; -} - -static Bool -xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) -{ - ScreenPtr pScreen = randr_crtc->pScreen; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - RRModePtr randr_mode = NULL; - int x; - int y; - Rotation rotation; - int numOutputs; - RROutputPtr *randr_outputs; - RROutputPtr randr_output; - xf86CrtcPtr crtc = randr_crtc->devPrivate; - xf86OutputPtr output; - int i, j; - DisplayModePtr mode = &crtc->mode; - Bool ret; - - randr_outputs = xalloc(config->num_output * sizeof (RROutputPtr)); - if (!randr_outputs) - return FALSE; - x = crtc->x; - y = crtc->y; - rotation = crtc->rotation; - numOutputs = 0; - randr_mode = NULL; - for (i = 0; i < config->num_output; i++) - { - output = config->output[i]; - if (output->crtc == crtc) - { - randr_output = output->randr_output; - randr_outputs[numOutputs++] = randr_output; - /* - * We make copies of modes, so pointer equality - * isn't sufficient - */ - for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++) - { - RRModePtr m = (j < randr_output->numModes ? - randr_output->modes[j] : - randr_output->userModes[j-randr_output->numModes]); - - if (xf86RandRModeMatches (m, mode)) - { - randr_mode = m; - break; - } - } - } - } - ret = RRCrtcNotify (randr_crtc, randr_mode, x, y, - rotation, - crtc->transformPresent ? &crtc->transform : NULL, - numOutputs, randr_outputs); - xfree(randr_outputs); - return ret; -} - -/* - * Convert a RandR mode to a DisplayMode - */ -static void -xf86RandRModeConvert (ScrnInfoPtr scrn, - RRModePtr randr_mode, - DisplayModePtr mode) -{ - memset(mode, 0, sizeof(DisplayModeRec)); - mode->status = MODE_OK; - - mode->Clock = randr_mode->mode.dotClock / 1000; - - mode->HDisplay = randr_mode->mode.width; - mode->HSyncStart = randr_mode->mode.hSyncStart; - mode->HSyncEnd = randr_mode->mode.hSyncEnd; - mode->HTotal = randr_mode->mode.hTotal; - mode->HSkew = randr_mode->mode.hSkew; - - mode->VDisplay = randr_mode->mode.height; - mode->VSyncStart = randr_mode->mode.vSyncStart; - mode->VSyncEnd = randr_mode->mode.vSyncEnd; - mode->VTotal = randr_mode->mode.vTotal; - mode->VScan = 0; - - mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS; - - xf86SetModeCrtc (mode, scrn->adjustFlags); -} - -static Bool -xf86RandR12CrtcSet (ScreenPtr pScreen, - RRCrtcPtr randr_crtc, - RRModePtr randr_mode, - int x, - int y, - Rotation rotation, - int num_randr_outputs, - RROutputPtr *randr_outputs) -{ - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - xf86CrtcPtr crtc = randr_crtc->devPrivate; - RRTransformPtr transform; - Bool changed = FALSE; - int o, ro; - xf86CrtcPtr *save_crtcs; - Bool save_enabled = crtc->enabled; - - if (!crtc->scrn->vtSema) - return FALSE; - - save_crtcs = xalloc(config->num_output * sizeof (xf86CrtcPtr)); - if ((randr_mode != NULL) != crtc->enabled) - changed = TRUE; - else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode)) - changed = TRUE; - - if (rotation != crtc->rotation) - changed = TRUE; - - transform = RRCrtcGetTransform (randr_crtc); - if ((transform != NULL) != crtc->transformPresent) - changed = TRUE; - else if (transform && memcmp (&transform->transform, &crtc->transform.transform, - sizeof (transform->transform)) != 0) - changed = TRUE; - - if (x != crtc->x || y != crtc->y) - changed = TRUE; - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - xf86CrtcPtr new_crtc; - - save_crtcs[o] = output->crtc; - - if (output->crtc == crtc) - new_crtc = NULL; - else - new_crtc = output->crtc; - for (ro = 0; ro < num_randr_outputs; ro++) - if (output->randr_output == randr_outputs[ro]) - { - new_crtc = crtc; - break; - } - if (new_crtc != output->crtc) - { - changed = TRUE; - output->crtc = new_crtc; - } - } - for (ro = 0; ro < num_randr_outputs; ro++) - if (randr_outputs[ro]->pendingProperties) - changed = TRUE; - - /* XXX need device-independent mode setting code through an API */ - if (changed) - { - crtc->enabled = randr_mode != NULL; - - if (randr_mode) - { - DisplayModeRec mode; - RRTransformPtr transform = RRCrtcGetTransform (randr_crtc); - - xf86RandRModeConvert (pScrn, randr_mode, &mode); - if (!xf86CrtcSetModeTransform (crtc, &mode, rotation, transform, x, y)) - { - crtc->enabled = save_enabled; - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - output->crtc = save_crtcs[o]; - } - xfree(save_crtcs); - return FALSE; - } - xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height); - xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY); - /* - * Save the last successful setting for EnterVT - */ - crtc->desiredMode = mode; - crtc->desiredRotation = rotation; - if (transform) { - crtc->desiredTransform = *transform; - crtc->desiredTransformPresent = TRUE; - } else - crtc->desiredTransformPresent = FALSE; - - crtc->desiredX = x; - crtc->desiredY = y; - } - xf86DisableUnusedFunctions (pScrn); - } - xfree(save_crtcs); - return xf86RandR12CrtcNotify (randr_crtc); -} - -static Bool -xf86RandR12CrtcSetGamma (ScreenPtr pScreen, - RRCrtcPtr randr_crtc) -{ - xf86CrtcPtr crtc = randr_crtc->devPrivate; - - if (crtc->funcs->gamma_set == NULL) - return FALSE; - - if (!crtc->scrn->vtSema) - return TRUE; - - /* Realloc local gamma if needed. */ - if (randr_crtc->gammaSize != crtc->gamma_size) { - CARD16 *tmp_ptr; - tmp_ptr = realloc(crtc->gamma_red, 3 * crtc->gamma_size * sizeof (CARD16)); - if (!tmp_ptr) - return FALSE; - crtc->gamma_red = tmp_ptr; - crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; - crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; - } - - crtc->gamma_size = randr_crtc->gammaSize; - memcpy (crtc->gamma_red, randr_crtc->gammaRed, crtc->gamma_size * sizeof (CARD16)); - memcpy (crtc->gamma_green, randr_crtc->gammaGreen, crtc->gamma_size * sizeof (CARD16)); - memcpy (crtc->gamma_blue, randr_crtc->gammaBlue, crtc->gamma_size * sizeof (CARD16)); - - /* Only set it when the crtc is actually running. - * Otherwise it will be set when it's activated. - */ - if (crtc->active) - crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, - crtc->gamma_blue, crtc->gamma_size); - - return TRUE; -} - -static Bool -xf86RandR12CrtcGetGamma (ScreenPtr pScreen, - RRCrtcPtr randr_crtc) -{ - xf86CrtcPtr crtc = randr_crtc->devPrivate; - - if (!crtc->gamma_size) - return FALSE; - - if (!crtc->gamma_red || !crtc->gamma_green || !crtc->gamma_blue) - return FALSE; - - /* Realloc randr gamma if needed. */ - if (randr_crtc->gammaSize != crtc->gamma_size) { - CARD16 *tmp_ptr; - tmp_ptr = realloc(randr_crtc->gammaRed, 3 * crtc->gamma_size * sizeof (CARD16)); - if (!tmp_ptr) - return FALSE; - randr_crtc->gammaRed = tmp_ptr; - randr_crtc->gammaGreen = randr_crtc->gammaRed + crtc->gamma_size; - randr_crtc->gammaBlue = randr_crtc->gammaGreen + crtc->gamma_size; - } - randr_crtc->gammaSize = crtc->gamma_size; - memcpy (randr_crtc->gammaRed, crtc->gamma_red, crtc->gamma_size * sizeof (CARD16)); - memcpy (randr_crtc->gammaGreen, crtc->gamma_green, crtc->gamma_size * sizeof (CARD16)); - memcpy (randr_crtc->gammaBlue, crtc->gamma_blue, crtc->gamma_size * sizeof (CARD16)); - - return TRUE; -} - -static Bool -xf86RandR12OutputSetProperty (ScreenPtr pScreen, - RROutputPtr randr_output, - Atom property, - RRPropertyValuePtr value) -{ - xf86OutputPtr output = randr_output->devPrivate; - - /* If we don't have any property handler, then we don't care what the - * user is setting properties to. - */ - if (output->funcs->set_property == NULL) - return TRUE; - - /* - * This function gets called even when vtSema is FALSE, as - * drivers will need to remember the correct value to apply - * when the VT switch occurs - */ - return output->funcs->set_property(output, property, value); -} - -static Bool -xf86RandR13OutputGetProperty (ScreenPtr pScreen, - RROutputPtr randr_output, - Atom property) -{ - xf86OutputPtr output = randr_output->devPrivate; - - if (output->funcs->get_property == NULL) - return TRUE; - - /* Should be safe even w/o vtSema */ - return output->funcs->get_property(output, property); -} - -static Bool -xf86RandR12OutputValidateMode (ScreenPtr pScreen, - RROutputPtr randr_output, - RRModePtr randr_mode) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86OutputPtr output = randr_output->devPrivate; - DisplayModeRec mode; - - xf86RandRModeConvert (pScrn, randr_mode, &mode); - /* - * This function may be called when vtSema is FALSE, so - * the underlying function must either avoid touching the hardware - * or return FALSE when vtSema is FALSE - */ - if (output->funcs->mode_valid (output, &mode) != MODE_OK) - return FALSE; - return TRUE; -} - -static void -xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode) -{ -} - -/** - * Given a list of xf86 modes and a RandR Output object, construct - * RandR modes and assign them to the output - */ -static Bool -xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) -{ - DisplayModePtr mode; - RRModePtr *rrmodes = NULL; - int nmode = 0; - int npreferred = 0; - Bool ret = TRUE; - int pref; - - for (mode = modes; mode; mode = mode->next) - nmode++; - - if (nmode) { - rrmodes = xalloc (nmode * sizeof (RRModePtr)); - - if (!rrmodes) - return FALSE; - nmode = 0; - - for (pref = 1; pref >= 0; pref--) { - for (mode = modes; mode; mode = mode->next) { - if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) { - xRRModeInfo modeInfo; - RRModePtr rrmode; - - modeInfo.nameLength = strlen (mode->name); - modeInfo.width = mode->HDisplay; - modeInfo.dotClock = mode->Clock * 1000; - modeInfo.hSyncStart = mode->HSyncStart; - modeInfo.hSyncEnd = mode->HSyncEnd; - modeInfo.hTotal = mode->HTotal; - modeInfo.hSkew = mode->HSkew; - - modeInfo.height = mode->VDisplay; - modeInfo.vSyncStart = mode->VSyncStart; - modeInfo.vSyncEnd = mode->VSyncEnd; - modeInfo.vTotal = mode->VTotal; - modeInfo.modeFlags = mode->Flags; - - rrmode = RRModeGet (&modeInfo, mode->name); - if (rrmode) { - rrmodes[nmode++] = rrmode; - npreferred += pref; - } - } - } - } - } - - ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred); - xfree (rrmodes); - return ret; -} - -/* - * Mirror the current mode configuration to RandR - */ -static Bool -xf86RandR12SetInfo12 (ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - RROutputPtr *clones; - RRCrtcPtr *crtcs; - int ncrtc; - int o, c, l; - RRCrtcPtr randr_crtc; - int nclone; - - clones = xalloc(config->num_output * sizeof (RROutputPtr)); - crtcs = xalloc (config->num_crtc * sizeof (RRCrtcPtr)); - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - ncrtc = 0; - for (c = 0; c < config->num_crtc; c++) - if (output->possible_crtcs & (1 << c)) - crtcs[ncrtc++] = config->crtc[c]->randr_crtc; - - if (output->crtc) - randr_crtc = output->crtc->randr_crtc; - else - randr_crtc = NULL; - - if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc)) - { - xfree (crtcs); - xfree (clones); - return FALSE; - } - - RROutputSetPhysicalSize(output->randr_output, - output->mm_width, - output->mm_height); - xf86RROutputSetModes (output->randr_output, output->probed_modes); - - switch (output->status) { - case XF86OutputStatusConnected: - RROutputSetConnection (output->randr_output, RR_Connected); - break; - case XF86OutputStatusDisconnected: - RROutputSetConnection (output->randr_output, RR_Disconnected); - break; - case XF86OutputStatusUnknown: - RROutputSetConnection (output->randr_output, RR_UnknownConnection); - break; - } - - RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order); - - /* - * Valid clones - */ - nclone = 0; - for (l = 0; l < config->num_output; l++) - { - xf86OutputPtr clone = config->output[l]; - - if (l != o && (output->possible_clones & (1 << l))) - clones[nclone++] = clone->randr_output; - } - if (!RROutputSetClones (output->randr_output, clones, nclone)) - { - xfree (crtcs); - xfree (clones); - return FALSE; - } - } - xfree (crtcs); - xfree (clones); - return TRUE; -} - - - -/* - * Query the hardware for the current state, then mirror - * that to RandR - */ -static Bool -xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - - if (!pScrn->vtSema) - return TRUE; - xf86ProbeOutputModes (pScrn, 0, 0); - xf86SetScrnInfoModes (pScrn); - return xf86RandR12SetInfo12 (pScreen); -} - -static Bool -xf86RandR12CreateObjects12 (ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - int c; - int o; - - if (!RRInit ()) - return FALSE; - - /* - * Configure crtcs - */ - for (c = 0; c < config->num_crtc; c++) - { - xf86CrtcPtr crtc = config->crtc[c]; - - crtc->randr_crtc = RRCrtcCreate (pScreen, crtc); - RRCrtcGammaSetSize (crtc->randr_crtc, 256); - } - /* - * Configure outputs - */ - for (o = 0; o < config->num_output; o++) - { - xf86OutputPtr output = config->output[o]; - - output->randr_output = RROutputCreate (pScreen, output->name, - strlen (output->name), - output); - - if (output->funcs->create_resources != NULL) - output->funcs->create_resources(output); - RRPostPendingProperties (output->randr_output); - } - return TRUE; -} - -static Bool -xf86RandR12CreateScreenResources12 (ScreenPtr pScreen) -{ - int c; - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - if (xf86RandR12Key == NULL) - return TRUE; -#endif - - for (c = 0; c < config->num_crtc; c++) - xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); - - RRScreenSetSizeRange (pScreen, config->minWidth, config->minHeight, - config->maxWidth, config->maxHeight); - return TRUE; -} - -/* - * Something happened within the screen configuration due - * to DGA, VidMode or hot key. Tell RandR - */ - -void -xf86RandR12TellChanged (ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - int c; - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) - if (xf86RandR12Key == NULL) - return; -#else - if (!XF86RANDRINFO(pScreen)) - return; -#endif - - xf86RandR12SetInfo12 (pScreen); - for (c = 0; c < config->num_crtc; c++) - xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); - - RRTellChanged (pScreen); -} - -static void -xf86RandR12PointerMoved (int scrnIndex, int x, int y) -{ - ScreenPtr pScreen = screenInfo.screens[scrnIndex]; - ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - int c; - - randrp->pointerX = x; - randrp->pointerY = y; - for (c = 0; c < config->num_crtc; c++) - xf86RandR13Pan (config->crtc[c], x, y); -} - -static Bool -xf86RandR13GetPanning (ScreenPtr pScreen, - RRCrtcPtr randr_crtc, - BoxPtr totalArea, - BoxPtr trackingArea, - INT16 *border) -{ - xf86CrtcPtr crtc = randr_crtc->devPrivate; - - if (crtc->version < 2) - return FALSE; - if (totalArea) - memcpy (totalArea, &crtc->panningTotalArea, sizeof(BoxRec)); - if (trackingArea) - memcpy (trackingArea, &crtc->panningTrackingArea, sizeof(BoxRec)); - if (border) - memcpy (border, crtc->panningBorder, 4*sizeof(INT16)); - - return TRUE; -} - -static Bool -xf86RandR13SetPanning (ScreenPtr pScreen, - RRCrtcPtr randr_crtc, - BoxPtr totalArea, - BoxPtr trackingArea, - INT16 *border) -{ - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - xf86CrtcPtr crtc = randr_crtc->devPrivate; - BoxRec oldTotalArea; - BoxRec oldTrackingArea; - INT16 oldBorder[4]; - - - if (crtc->version < 2) - return FALSE; - - memcpy (&oldTotalArea, &crtc->panningTotalArea, sizeof(BoxRec)); - memcpy (&oldTrackingArea, &crtc->panningTrackingArea, sizeof(BoxRec)); - memcpy (oldBorder, crtc->panningBorder, 4*sizeof(INT16)); - - if (totalArea) - memcpy (&crtc->panningTotalArea, totalArea, sizeof(BoxRec)); - if (trackingArea) - memcpy (&crtc->panningTrackingArea, trackingArea, sizeof(BoxRec)); - if (border) - memcpy (crtc->panningBorder, border, 4*sizeof(INT16)); - - if (xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height)) { - xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY); - return TRUE; - } else { - /* Restore old settings */ - memcpy (&crtc->panningTotalArea, &oldTotalArea, sizeof(BoxRec)); - memcpy (&crtc->panningTrackingArea, &oldTrackingArea, sizeof(BoxRec)); - memcpy (crtc->panningBorder, oldBorder, 4*sizeof(INT16)); - return FALSE; - } -} - -/* - * Compatibility with XF86VidMode's gamma changer. This necessarily clobbers - * any per-crtc setup. You asked for it... - */ - -static void -gamma_to_ramp(float gamma, CARD16 *ramp, int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (gamma == 1.0) - ramp[i] = i << 8; - else - ramp[i] = (CARD16)(pow((double)i / (double)(size - 1), 1. / gamma) - * (double)(size - 1) * 256); - } -} - -static int -xf86RandR12ChangeGamma(int scrnIndex, Gamma gamma) -{ - CARD16 *points, *red, *green, *blue; - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn); - int size; - - if (!crtc) - return Success; - - size = max(0, crtc->gammaSize); - if (!size) - return Success; - - points = xcalloc(size, 3 * sizeof(CARD16)); - if (!points) - return BadAlloc; - - red = points; - green = points + size; - blue = points + 2 * size; - - gamma_to_ramp(gamma.red, red, size); - gamma_to_ramp(gamma.green, green, size); - gamma_to_ramp(gamma.blue, blue, size); - RRCrtcGammaSet(crtc, red, green, blue); - - xfree(points); - - pScrn->gamma = gamma; - - return Success; -} - -static Bool -xf86RandR12EnterVT (int screen_index, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[screen_index]; - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - - if (randrp->orig_EnterVT) { - if (!randrp->orig_EnterVT (screen_index, flags)) - return FALSE; - } - - return RRGetInfo (pScreen, TRUE); /* force a re-probe of outputs and notify clients about changes */ -} - -static Bool -xf86RandR12Init12 (ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - rrScrPrivPtr rp = rrGetScrPriv(pScreen); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - - rp->rrGetInfo = xf86RandR12GetInfo12; - rp->rrScreenSetSize = xf86RandR12ScreenSetSize; - rp->rrCrtcSet = xf86RandR12CrtcSet; - rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; - rp->rrCrtcGetGamma = xf86RandR12CrtcGetGamma; - rp->rrOutputSetProperty = xf86RandR12OutputSetProperty; - rp->rrOutputValidateMode = xf86RandR12OutputValidateMode; -#if RANDR_13_INTERFACE - rp->rrOutputGetProperty = xf86RandR13OutputGetProperty; - rp->rrGetPanning = xf86RandR13GetPanning; - rp->rrSetPanning = xf86RandR13SetPanning; -#endif - rp->rrModeDestroy = xf86RandR12ModeDestroy; - rp->rrSetConfig = NULL; - pScrn->PointerMoved = xf86RandR12PointerMoved; - pScrn->ChangeGamma = xf86RandR12ChangeGamma; - - randrp->orig_EnterVT = pScrn->EnterVT; - pScrn->EnterVT = xf86RandR12EnterVT; - - if (!xf86RandR12CreateObjects12 (pScreen)) - return FALSE; - - /* - * Configure output modes - */ - if (!xf86RandR12SetInfo12 (pScreen)) - return FALSE; - return TRUE; -} - -#endif - -Bool -xf86RandR12PreInit (ScrnInfoPtr pScrn) -{ - return TRUE; -} +/* + * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "os.h" +#include "globals.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86DDC.h" +#include "mipointer.h" +#include "windowstr.h" +#include "inputstr.h" +#include <randrstr.h> +#include <X11/extensions/render.h> + +#include "xf86Crtc.h" +#include "xf86RandR12.h" + +typedef struct _xf86RandR12Info { + int virtualX; + int virtualY; + int mmWidth; + int mmHeight; + int maxX; + int maxY; + int pointerX; + int pointerY; + Rotation rotation; /* current mode */ + Rotation supported_rotations; /* driver supported */ + + /* Used to wrap EnterVT so we can re-probe the outputs when a laptop unsuspends + * (actually, any time that we switch back into our VT). + * + * See https://bugs.freedesktop.org/show_bug.cgi?id=21554 + */ + xf86EnterVTProc *orig_EnterVT; +} XF86RandRInfoRec, *XF86RandRInfoPtr; + +#ifdef RANDR_12_INTERFACE +static Bool xf86RandR12Init12 (ScreenPtr pScreen); +static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen); +#endif + +static int xf86RandR12Generation; +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + +static int xf86RandR12KeyIndex; +static DevPrivateKey xf86RandR12Key; +#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) \ + dixLookupPrivate(&(p)->devPrivates, xf86RandR12Key)) + +#else /* XORG_VERSION_CURRENT < 7.0 */ + +static int xf86RandR12Index; +#define XF86RANDRINFO(p) \ + ((XF86RandRInfoPtr)(p)->devPrivates[xf86RandR12Index].ptr) + +#endif /* XORG_VERSION_CURRENT < 7.0 */ + + +static int +xf86RandR12ModeRefresh (DisplayModePtr mode) +{ + if (mode->VRefresh) + return (int) (mode->VRefresh + 0.5); + else + return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); +} + +/* Adapt panning area; return TRUE if panning area was valid without adaption */ +static int +xf86RandR13VerifyPanningArea (xf86CrtcPtr crtc, int screenWidth, int screenHeight) +{ + int ret = TRUE; + + if (crtc->version < 2) + return FALSE; + + if (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1) { + /* Panning in X is disabled */ + if (crtc->panningTotalArea.x1 || crtc->panningTotalArea.x2) + /* Illegal configuration -> fail/disable */ + ret = FALSE; + crtc->panningTotalArea.x1 = crtc->panningTotalArea.x2 = 0; + crtc->panningTrackingArea.x1 = crtc->panningTrackingArea.x2 = 0; + crtc->panningBorder[0] = crtc->panningBorder[2] = 0; + } else { + /* Panning in X is enabled */ + if (crtc->panningTotalArea.x1 < 0) { + /* Panning region outside screen -> move inside */ + crtc->panningTotalArea.x2 -= crtc->panningTotalArea.x1; + crtc->panningTotalArea.x1 = 0; + ret = FALSE; + } + if (crtc->panningTotalArea.x2 < crtc->panningTotalArea.x1 + crtc->mode.HDisplay) { + /* Panning region smaller than displayed area -> crop to displayed area */ + crtc->panningTotalArea.x2 = crtc->panningTotalArea.x1 + crtc->mode.HDisplay; + ret = FALSE; + } + if (crtc->panningTotalArea.x2 > screenWidth) { + /* Panning region larger than screen -> move inside, then crop to screen */ + crtc->panningTotalArea.x1 -= crtc->panningTotalArea.x2 - screenWidth; + crtc->panningTotalArea.x2 = screenWidth; + ret = FALSE; + if (crtc->panningTotalArea.x1 < 0) + crtc->panningTotalArea.x1 = 0; + } + if (crtc->panningBorder[0] + crtc->panningBorder[2] > crtc->mode.HDisplay) { + /* Borders too large -> set to 0 */ + crtc->panningBorder[0] = crtc->panningBorder[2] = 0; + ret = FALSE; + } + } + + if (crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1) { + /* Panning in Y is disabled */ + if (crtc->panningTotalArea.y1 || crtc->panningTotalArea.y2) + /* Illegal configuration -> fail/disable */ + ret = FALSE; + crtc->panningTotalArea.y1 = crtc->panningTotalArea.y2 = 0; + crtc->panningTrackingArea.y1 = crtc->panningTrackingArea.y2 = 0; + crtc->panningBorder[1] = crtc->panningBorder[3] = 0; + } else { + /* Panning in Y is enabled */ + if (crtc->panningTotalArea.y1 < 0) { + /* Panning region outside screen -> move inside */ + crtc->panningTotalArea.y2 -= crtc->panningTotalArea.y1; + crtc->panningTotalArea.y1 = 0; + ret = FALSE; + } + if (crtc->panningTotalArea.y2 < crtc->panningTotalArea.y1 + crtc->mode.VDisplay) { + /* Panning region smaller than displayed area -> crop to displayed area */ + crtc->panningTotalArea.y2 = crtc->panningTotalArea.y1 + crtc->mode.VDisplay; + ret = FALSE; + } + if (crtc->panningTotalArea.y2 > screenHeight) { + /* Panning region larger than screen -> move inside, then crop to screen */ + crtc->panningTotalArea.y1 -= crtc->panningTotalArea.y2 - screenHeight; + crtc->panningTotalArea.y2 = screenHeight; + ret = FALSE; + if (crtc->panningTotalArea.y1 < 0) + crtc->panningTotalArea.y1 = 0; + } + if (crtc->panningBorder[1] + crtc->panningBorder[3] > crtc->mode.VDisplay) { + /* Borders too large -> set to 0 */ + crtc->panningBorder[1] = crtc->panningBorder[3] = 0; + ret = FALSE; + } + } + + return ret; +} + +/* + * The heart of the panning operation: + * + * Given a frame buffer position (fb_x, fb_y), + * and a crtc position (crtc_x, crtc_y), + * and a transform matrix which maps frame buffer to crtc, + * compute a panning position (pan_x, pan_y) that + * makes the resulting transform line those two up + */ + +static void +xf86ComputeCrtcPan (Bool transform_in_use, + struct pixman_f_transform *m, + double screen_x, double screen_y, + double crtc_x, double crtc_y, + int old_pan_x, int old_pan_y, + int *new_pan_x, int *new_pan_y) +{ + if (transform_in_use) { + /* + * Given the current transform, M, the current position + * on the Screen, S, and the desired position on the CRTC, + * C, compute a translation, T, such that: + * + * M T S = C + * + * where T is of the form + * + * | 1 0 dx | + * | 0 1 dy | + * | 0 0 1 | + * + * M T S = + * | M00 Sx + M01 Sy + M00 dx + M01 dy + M02 | | Cx F | + * | M10 Sx + M11 Sy + M10 dx + M11 dy + M12 | = | Cy F | + * | M20 Sx + M21 Sy + M20 dx + M21 dy + M22 | | F | + * + * R = M S + * + * Cx F = M00 dx + M01 dy + R0 + * Cy F = M10 dx + M11 dy + R1 + * F = M20 dx + M21 dy + R2 + * + * Zero out dx, then dy + * + * F (Cx M10 - Cy M00) = + * (M10 M01 - M00 M11) dy + M10 R0 - M00 R1 + * F (M10 - Cy M20) = + * (M10 M21 - M20 M11) dy + M10 R2 - M20 R1 + * + * F (Cx M11 - Cy M01) = + * (M11 M00 - M01 M10) dx + M11 R0 - M01 R1 + * F (M11 - Cy M21) = + * (M11 M20 - M21 M10) dx + M11 R2 - M21 R1 + * + * Make some temporaries + * + * T = | Cx M10 - Cy M00 | + * | Cx M11 - Cy M01 | + * + * U = | M10 M01 - M00 M11 | + * | M11 M00 - M01 M10 | + * + * Q = | M10 R0 - M00 R1 | + * | M11 R0 - M01 R1 | + * + * P = | M10 - Cy M20 | + * | M11 - Cy M21 | + * + * W = | M10 M21 - M20 M11 | + * | M11 M20 - M21 M10 | + * + * V = | M10 R2 - M20 R1 | + * | M11 R2 - M21 R1 | + * + * Rewrite: + * + * F T0 = U0 dy + Q0 + * F P0 = W0 dy + V0 + * F T1 = U1 dx + Q1 + * F P1 = W1 dx + V1 + * + * Solve for F (two ways) + * + * F (W0 T0 - U0 P0) = W0 Q0 - U0 V0 + * + * W0 Q0 - U0 V0 + * F = ------------- + * W0 T0 - U0 P0 + * + * F (W1 T1 - U1 P1) = W1 Q1 - U1 V1 + * + * W1 Q1 - U1 V1 + * F = ------------- + * W1 T1 - U1 P1 + * + * We'll use which ever solution works (denominator != 0) + * + * Finally, solve for dx and dy: + * + * dx = (F T1 - Q1) / U1 + * dx = (F P1 - V1) / W1 + * + * dy = (F T0 - Q0) / U0 + * dy = (F P0 - V0) / W0 + */ + double r[3]; + double q[2], u[2], t[2], v[2], w[2], p[2]; + double f; + struct pict_f_vector d; + int i; + + /* Get the un-normalized crtc coordinates again */ + for (i = 0; i < 3; i++) + r[i] = m->m[i][0] * screen_x + m->m[i][1] * screen_y + m->m[i][2]; + + /* Combine values into temporaries */ + for (i = 0; i < 2; i++) { + q[i] = m->m[1][i] * r[0] - m->m[0][i] * r[1]; + u[i] = m->m[1][i] * m->m[0][1-i] - m->m[0][i] * m->m[1][1-i]; + t[i] = m->m[1][i] * crtc_x - m->m[0][i] * crtc_y; + + v[i] = m->m[1][i] * r[2] - m->m[2][i] * r[1]; + w[i] = m->m[1][i] * m->m[2][1-i] - m->m[2][i] * m->m[1][1-i]; + p[i] = m->m[1][i] - m->m[2][i] * crtc_y; + } + + /* Find a way to compute f */ + f = 0; + for (i = 0; i < 2; i++) { + double a = w[i] * q[i] - u[i] * v[i]; + double b = w[i] * t[i] - u[i] * p[i]; + if (b != 0) { + f = a/b; + break; + } + } + + /* Solve for the resulting transform vector */ + for (i = 0; i < 2; i++) { + if (u[i]) + d.v[1-i] = (t[i] * f - q[i]) / u[i]; + else if (w[1]) + d.v[1-i] = (p[i] * f - v[i]) / w[i]; + else + d.v[1-i] = 0; + } + *new_pan_x = old_pan_x - floor (d.v[0] + 0.5); + *new_pan_y = old_pan_y - floor (d.v[1] + 0.5); + } else { + *new_pan_x = screen_x - crtc_x; + *new_pan_y = screen_y - crtc_y; + } +} + +static void +xf86RandR13Pan (xf86CrtcPtr crtc, int x, int y) +{ + int newX, newY; + int width, height; + Bool panned = FALSE; + + if (crtc->version < 2) + return; + + if (! crtc->enabled || + (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1 && + crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1)) + return; + + newX = crtc->x; + newY = crtc->y; + width = crtc->mode.HDisplay; + height = crtc->mode.VDisplay; + + if ((crtc->panningTrackingArea.x2 <= crtc->panningTrackingArea.x1 || + (x >= crtc->panningTrackingArea.x1 && x < crtc->panningTrackingArea.x2)) && + (crtc->panningTrackingArea.y2 <= crtc->panningTrackingArea.y1 || + (y >= crtc->panningTrackingArea.y1 && y < crtc->panningTrackingArea.y2))) + { + struct pict_f_vector c; + + /* + * Pre-clip the mouse position to the panning area so that we don't + * push the crtc outside. This doesn't deal with changes to the + * panning values, only mouse position changes. + */ + if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) + { + if (x < crtc->panningTotalArea.x1) + x = crtc->panningTotalArea.x1; + if (x >= crtc->panningTotalArea.x2) + x = crtc->panningTotalArea.x2 - 1; + } + if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) + { + if (y < crtc->panningTotalArea.y1) + y = crtc->panningTotalArea.y1; + if (y >= crtc->panningTotalArea.y2) + y = crtc->panningTotalArea.y2 - 1; + } + + c.v[0] = x; + c.v[1] = y; + c.v[2] = 1.0; + if (crtc->transform_in_use) { + pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &c); + } else { + c.v[0] -= crtc->x; + c.v[1] -= crtc->y; + } + + if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) { + if (c.v[0] < crtc->panningBorder[0]) { + c.v[0] = crtc->panningBorder[0]; + panned = TRUE; + } + if (c.v[0] >= width - crtc->panningBorder[2]) { + c.v[0] = width - crtc->panningBorder[2] - 1; + panned = TRUE; + } + } + if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { + if (c.v[1] < crtc->panningBorder[1]) { + c.v[1] = crtc->panningBorder[1]; + panned = TRUE; + } + if (c.v[1] >= height - crtc->panningBorder[3]) { + c.v[1] = height - crtc->panningBorder[3] - 1; + panned = TRUE; + } + } + if (panned) + xf86ComputeCrtcPan (crtc->transform_in_use, + &crtc->f_framebuffer_to_crtc, + x, y, c.v[0], c.v[1], + newX, newY, &newX, &newY); + } + + /* + * Ensure that the crtc is within the panning region. + * + * XXX This computation only works when we do not have a transform + * in use. + */ + if (!crtc->transform_in_use) + { + /* Validate against [xy]1 after [xy]2, to be sure that results are > 0 for [xy]1 > 0 */ + if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) { + if (newX > crtc->panningTotalArea.x2 - width) + newX = crtc->panningTotalArea.x2 - width; + if (newX < crtc->panningTotalArea.x1) + newX = crtc->panningTotalArea.x1; + } + if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { + if (newY > crtc->panningTotalArea.y2 - height) + newY = crtc->panningTotalArea.y2 - height; + if (newY < crtc->panningTotalArea.y1) + newY = crtc->panningTotalArea.y1; + } + } + if (newX != crtc->x || newY != crtc->y) + xf86CrtcSetOrigin (crtc, newX, newY); +} + +static Bool +xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + RRScreenSizePtr pSize; + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int refresh0 = 60; + int maxX = 0, maxY = 0; + + *rotations = randrp->supported_rotations; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = scrp->virtualX; + randrp->virtualY = scrp->virtualY; + } + + /* Re-probe the outputs for new monitors or modes */ + if (scrp->vtSema) + { + xf86ProbeOutputModes (scrp, 0, 0); + xf86SetScrnInfoModes (scrp); + } + + for (mode = scrp->modes; ; mode = mode->next) + { + int refresh = xf86RandR12ModeRefresh (mode); + if (randrp->maxX == 0 || randrp->maxY == 0) + { + if (maxX < mode->HDisplay) + maxX = mode->HDisplay; + if (maxY < mode->VDisplay) + maxY = mode->VDisplay; + } + if (mode == scrp->modes) + refresh0 = refresh; + pSize = RRRegisterSize (pScreen, + mode->HDisplay, mode->VDisplay, + randrp->mmWidth, randrp->mmHeight); + if (!pSize) + return FALSE; + RRRegisterRate (pScreen, pSize, refresh); + + if (xf86ModesEqual(mode, scrp->currentMode)) + { + RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); + } + if (mode->next == scrp->modes) + break; + } + + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + + return TRUE; +} + +static Bool +xf86RandR12SetMode (ScreenPtr pScreen, + DisplayModePtr mode, + Bool useVirtual, + int mmWidth, + int mmHeight) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int oldWidth = pScreen->width; + int oldHeight = pScreen->height; + int oldmmWidth = pScreen->mmWidth; + int oldmmHeight = pScreen->mmHeight; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + DisplayModePtr currentMode = NULL; + Bool ret = TRUE; + PixmapPtr pspix = NULL; + + if (pRoot) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); + if (useVirtual) + { + scrp->virtualX = randrp->virtualX; + scrp->virtualY = randrp->virtualY; + } + else + { + scrp->virtualX = mode->HDisplay; + scrp->virtualY = mode->VDisplay; + } + + if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) + { + /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ + pScreen->width = scrp->virtualY; + pScreen->height = scrp->virtualX; + pScreen->mmWidth = mmHeight; + pScreen->mmHeight = mmWidth; + } + else + { + pScreen->width = scrp->virtualX; + pScreen->height = scrp->virtualY; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + } + if (scrp->currentMode == mode) { + /* Save current mode */ + currentMode = scrp->currentMode; + /* Reset, just so we ensure the drivers SwitchMode is called */ + scrp->currentMode = NULL; + } + /* + * We know that if the driver failed to SwitchMode to the rotated + * version, then it should revert back to it's prior mode. + */ + if (!xf86SwitchMode (pScreen, mode)) + { + ret = FALSE; + scrp->virtualX = pScreen->width = oldWidth; + scrp->virtualY = pScreen->height = oldHeight; + pScreen->mmWidth = oldmmWidth; + pScreen->mmHeight = oldmmHeight; + scrp->currentMode = currentMode; + } + /* + * Get the new Screen pixmap ptr as SwitchMode might have called + * ModifyPixmapHeader and xf86EnableDisableFBAccess will put it back... + * Unfortunately. + */ + pspix = (*pScreen->GetScreenPixmap) (pScreen); + if (pspix->devPrivate.ptr) + scrp->pixmapPrivate = pspix->devPrivate; + + /* + * Make sure the layout is correct + */ + xf86ReconfigureLayout(); + + /* + * Make sure the whole screen is visible + */ + xf86SetViewport (pScreen, pScreen->width, pScreen->height); + xf86SetViewport (pScreen, 0, 0); + if (pRoot) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); + return ret; +} + +Bool +xf86RandR12SetConfig (ScreenPtr pScreen, + Rotation rotation, + int rate, + RRScreenSizePtr pSize) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int px, py; + Bool useVirtual = FALSE; + int maxX = 0, maxY = 0; + Rotation oldRotation = randrp->rotation; + + randrp->rotation = rotation; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = scrp->virtualX; + randrp->virtualY = scrp->virtualY; + } + + miPointerGetPosition (inputInfo.pointer, &px, &py); + for (mode = scrp->modes; ; mode = mode->next) + { + if (randrp->maxX == 0 || randrp->maxY == 0) + { + if (maxX < mode->HDisplay) + maxX = mode->HDisplay; + if (maxY < mode->VDisplay) + maxY = mode->VDisplay; + } + if (mode->HDisplay == pSize->width && + mode->VDisplay == pSize->height && + (rate == 0 || xf86RandR12ModeRefresh (mode) == rate)) + break; + if (mode->next == scrp->modes) + { + if (pSize->width == randrp->virtualX && + pSize->height == randrp->virtualY) + { + mode = scrp->modes; + useVirtual = TRUE; + break; + } + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + return FALSE; + } + } + + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + + if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth, + pSize->mmHeight)) { + randrp->rotation = oldRotation; + return FALSE; + } + + /* + * Move the cursor back where it belongs; SwitchMode repositions it + */ + if (pScreen == miPointerGetScreen(inputInfo.pointer)) + { + px = (px >= pScreen->width ? (pScreen->width - 1) : px); + py = (py >= pScreen->height ? (pScreen->height - 1) : py); + + xf86SetViewport(pScreen, px, py); + + (*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE); + } + + return TRUE; +} + +static Bool +xf86RandR12ScreenSetSize (ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD32 mmWidth, + CARD32 mmHeight) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + WindowPtr pRoot = WindowTable[pScreen->myNum]; + PixmapPtr pScrnPix = (*pScreen->GetScreenPixmap)(pScreen); + Bool ret = FALSE; + int c; + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + if (xf86RandR12Key) { +#endif + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = pScrn->virtualX; + randrp->virtualY = pScrn->virtualY; + } +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + } +#endif + if (pRoot && pScrn->vtSema) + (*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE); + + /* Let the driver update virtualX and virtualY */ + if (!(*config->funcs->resize)(pScrn, width, height)) + goto finish; + + ret = TRUE; + /* Update panning information */ + for (c = 0; c < config->num_crtc; c++) { + xf86CrtcPtr crtc = config->crtc[c]; + if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1 || + crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { + if (crtc->panningTotalArea.x2 > crtc->panningTrackingArea.x1) + crtc->panningTotalArea.x2 += width - pScreen->width; + if (crtc->panningTotalArea.y2 > crtc->panningTrackingArea.y1) + crtc->panningTotalArea.y2 += height - pScreen->height; + if (crtc->panningTrackingArea.x2 > crtc->panningTrackingArea.x1) + crtc->panningTrackingArea.x2 += width - pScreen->width; + if (crtc->panningTrackingArea.y2 > crtc->panningTrackingArea.y1) + crtc->panningTrackingArea.y2 += height - pScreen->height; + xf86RandR13VerifyPanningArea (crtc, width, height); + xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY); + } + } + + pScreen->width = pScrnPix->drawable.width = width; + pScreen->height = pScrnPix->drawable.height = height; + randrp->mmWidth = pScreen->mmWidth = mmWidth; + randrp->mmHeight = pScreen->mmHeight = mmHeight; + + xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1); + xf86SetViewport (pScreen, 0, 0); + +finish: + if (pRoot && pScrn->vtSema) + (*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE); +#if RANDR_12_INTERFACE + if (xf86RandR12Key && WindowTable[pScreen->myNum] && ret) + RRScreenSizeNotify (pScreen); +#endif + return ret; +} + +Rotation +xf86RandR12GetRotation(ScreenPtr pScreen) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + return randrp->rotation; +} + +Bool +xf86RandR12CreateScreenResources (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config; + XF86RandRInfoPtr randrp; + int c; + int width, height; + int mmWidth, mmHeight; +#ifdef PANORAMIX + /* XXX disable RandR when using Xinerama */ + if (!noPanoramiXExtension) + return TRUE; +#endif + + config = XF86_CRTC_CONFIG_PTR(pScrn); + randrp = XF86RANDRINFO(pScreen); + /* + * Compute size of screen + */ + width = 0; height = 0; + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + int crtc_width = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); + int crtc_height = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); + + if (crtc->enabled) { + if (crtc_width > width) + width = crtc_width; + if (crtc_height > height) + height = crtc_height; + if (crtc->panningTotalArea.x2 > width) + width = crtc->panningTotalArea.x2; + if (crtc->panningTotalArea.y2 > height) + height = crtc->panningTotalArea.y2; + } + } + + if (width && height) + { + /* + * Compute physical size of screen + */ + if (monitorResolution) + { + mmWidth = width * 25.4 / monitorResolution; + mmHeight = height * 25.4 / monitorResolution; + } + else + { + xf86OutputPtr output = xf86CompatOutput(pScrn); + + if (output && + output->conf_monitor && + (output->conf_monitor->mon_width > 0 && + output->conf_monitor->mon_height > 0)) + { + /* + * Prefer user configured DisplaySize + */ + mmWidth = output->conf_monitor->mon_width; + mmHeight = output->conf_monitor->mon_height; + } + else + { + /* + * Otherwise, just set the screen to DEFAULT_DPI + */ + mmWidth = width * 25.4 / DEFAULT_DPI; + mmHeight = height * 25.4 / DEFAULT_DPI; + } + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Setting screen physical size to %d x %d\n", + mmWidth, mmHeight); + /* + * This is the initial setting of the screen size. + * We have to pre-set it here, otherwise panning would be adapted + * to the new screen size. + */ + pScreen->width = width; + pScreen->height = height; + xf86RandR12ScreenSetSize (pScreen, + width, + height, + mmWidth, + mmHeight); + } + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + if (xf86RandR12Key == NULL) + return TRUE; +#endif + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = pScrn->virtualX; + randrp->virtualY = pScrn->virtualY; + } + xf86CrtcSetScreenSubpixelOrder (pScreen); +#if RANDR_12_INTERFACE + if (xf86RandR12CreateScreenResources12 (pScreen)) + return TRUE; +#endif + return TRUE; +} + + +Bool +xf86RandR12Init (ScreenPtr pScreen) +{ + rrScrPrivPtr rp; + XF86RandRInfoPtr randrp; + +#ifdef PANORAMIX + /* XXX disable RandR when using Xinerama */ + if (!noPanoramiXExtension) + { + if (xf86NumScreens == 1) + noPanoramiXExtension = TRUE; + else + return TRUE; + } +#endif + + if (xf86RandR12Generation != serverGeneration) + xf86RandR12Generation = serverGeneration; + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + xf86RandR12Key = &xf86RandR12KeyIndex; +#else + xf86RandR12Index = AllocateScreenPrivateIndex(); +#endif + + randrp = malloc(sizeof (XF86RandRInfoRec)); + if (!randrp) + return FALSE; + + if (!RRScreenInit(pScreen)) + { + free(randrp); + return FALSE; + } + rp = rrGetScrPriv(pScreen); + rp->rrGetInfo = xf86RandR12GetInfo; + rp->rrSetConfig = xf86RandR12SetConfig; + + randrp->virtualX = -1; + randrp->virtualY = -1; + randrp->mmWidth = pScreen->mmWidth; + randrp->mmHeight = pScreen->mmHeight; + + randrp->rotation = RR_Rotate_0; /* initial rotated mode */ + + randrp->supported_rotations = RR_Rotate_0; + + randrp->maxX = randrp->maxY = 0; + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + dixSetPrivate(&pScreen->devPrivates, xf86RandR12Key, randrp); +#else + pScreen->devPrivates[xf86RandR12Index].ptr = randrp; +#endif + +#if RANDR_12_INTERFACE + if (!xf86RandR12Init12 (pScreen)) + return FALSE; +#endif + return TRUE; +} + +void +xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations) +{ + XF86RandRInfoPtr randrp; +#if RANDR_12_INTERFACE + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + int c; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); +#endif + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + if (xf86RandR12Key == NULL) + return; +#endif + + randrp = XF86RANDRINFO(pScreen); +#if RANDR_12_INTERFACE + for (c = 0; c < config->num_crtc; c++) { + xf86CrtcPtr crtc = config->crtc[c]; + + RRCrtcSetRotations (crtc->randr_crtc, rotations); + } +#endif + randrp->supported_rotations = rotations; +} + +void +xf86RandR12SetTransformSupport (ScreenPtr pScreen, Bool transforms) +{ + XF86RandRInfoPtr randrp; +#if RANDR_13_INTERFACE + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + int c; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); +#endif + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + if (xf86RandR12Key == NULL) + return; +#endif + + randrp = XF86RANDRINFO(pScreen); +#if RANDR_13_INTERFACE + for (c = 0; c < config->num_crtc; c++) { + xf86CrtcPtr crtc = config->crtc[c]; + + RRCrtcSetTransformSupport (crtc->randr_crtc, transforms); + } +#endif +} + +void +xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y) +{ + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + + if (xf86RandR12Generation != serverGeneration || + XF86RANDRINFO(pScreen)->virtualX == -1) + { + *x = pScrn->virtualX; + *y = pScrn->virtualY; + } else { + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + *x = randrp->virtualX; + *y = randrp->virtualY; + } +} + +#if RANDR_12_INTERFACE + +#define FLAG_BITS (RR_HSyncPositive | \ + RR_HSyncNegative | \ + RR_VSyncPositive | \ + RR_VSyncNegative | \ + RR_Interlace | \ + RR_DoubleScan | \ + RR_CSync | \ + RR_CSyncPositive | \ + RR_CSyncNegative | \ + RR_HSkewPresent | \ + RR_BCast | \ + RR_PixelMultiplex | \ + RR_DoubleClock | \ + RR_ClockDivideBy2) + +static Bool +xf86RandRModeMatches (RRModePtr randr_mode, + DisplayModePtr mode) +{ +#if 0 + if (match_name) + { + /* check for same name */ + int len = strlen (mode->name); + if (randr_mode->mode.nameLength != len) return FALSE; + if (memcmp (randr_mode->name, mode->name, len) != 0) return FALSE; + } +#endif + + /* check for same timings */ + if (randr_mode->mode.dotClock / 1000 != mode->Clock) return FALSE; + if (randr_mode->mode.width != mode->HDisplay) return FALSE; + if (randr_mode->mode.hSyncStart != mode->HSyncStart) return FALSE; + if (randr_mode->mode.hSyncEnd != mode->HSyncEnd) return FALSE; + if (randr_mode->mode.hTotal != mode->HTotal) return FALSE; + if (randr_mode->mode.hSkew != mode->HSkew) return FALSE; + if (randr_mode->mode.height != mode->VDisplay) return FALSE; + if (randr_mode->mode.vSyncStart != mode->VSyncStart) return FALSE; + if (randr_mode->mode.vSyncEnd != mode->VSyncEnd) return FALSE; + if (randr_mode->mode.vTotal != mode->VTotal) return FALSE; + + /* check for same flags (using only the XF86 valid flag bits) */ + if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS)) + return FALSE; + + /* everything matches */ + return TRUE; +} + +static Bool +xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) +{ + ScreenPtr pScreen = randr_crtc->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + RRModePtr randr_mode = NULL; + int x; + int y; + Rotation rotation; + int numOutputs; + RROutputPtr *randr_outputs; + RROutputPtr randr_output; + xf86CrtcPtr crtc = randr_crtc->devPrivate; + xf86OutputPtr output; + int i, j; + DisplayModePtr mode = &crtc->mode; + Bool ret; + + randr_outputs = malloc(config->num_output * sizeof (RROutputPtr)); + if (!randr_outputs) + return FALSE; + x = crtc->x; + y = crtc->y; + rotation = crtc->rotation; + numOutputs = 0; + randr_mode = NULL; + for (i = 0; i < config->num_output; i++) + { + output = config->output[i]; + if (output->crtc == crtc) + { + randr_output = output->randr_output; + randr_outputs[numOutputs++] = randr_output; + /* + * We make copies of modes, so pointer equality + * isn't sufficient + */ + for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++) + { + RRModePtr m = (j < randr_output->numModes ? + randr_output->modes[j] : + randr_output->userModes[j-randr_output->numModes]); + + if (xf86RandRModeMatches (m, mode)) + { + randr_mode = m; + break; + } + } + } + } + ret = RRCrtcNotify (randr_crtc, randr_mode, x, y, + rotation, + crtc->transformPresent ? &crtc->transform : NULL, + numOutputs, randr_outputs); + free(randr_outputs); + return ret; +} + +/* + * Convert a RandR mode to a DisplayMode + */ +static void +xf86RandRModeConvert (ScrnInfoPtr scrn, + RRModePtr randr_mode, + DisplayModePtr mode) +{ + memset(mode, 0, sizeof(DisplayModeRec)); + mode->status = MODE_OK; + + mode->Clock = randr_mode->mode.dotClock / 1000; + + mode->HDisplay = randr_mode->mode.width; + mode->HSyncStart = randr_mode->mode.hSyncStart; + mode->HSyncEnd = randr_mode->mode.hSyncEnd; + mode->HTotal = randr_mode->mode.hTotal; + mode->HSkew = randr_mode->mode.hSkew; + + mode->VDisplay = randr_mode->mode.height; + mode->VSyncStart = randr_mode->mode.vSyncStart; + mode->VSyncEnd = randr_mode->mode.vSyncEnd; + mode->VTotal = randr_mode->mode.vTotal; + mode->VScan = 0; + + mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS; + + xf86SetModeCrtc (mode, scrn->adjustFlags); +} + +static Bool +xf86RandR12CrtcSet (ScreenPtr pScreen, + RRCrtcPtr randr_crtc, + RRModePtr randr_mode, + int x, + int y, + Rotation rotation, + int num_randr_outputs, + RROutputPtr *randr_outputs) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc = randr_crtc->devPrivate; + RRTransformPtr transform; + Bool changed = FALSE; + int o, ro; + xf86CrtcPtr *save_crtcs; + Bool save_enabled = crtc->enabled; + + if (!crtc->scrn->vtSema) + return FALSE; + + save_crtcs = malloc(config->num_output * sizeof (xf86CrtcPtr)); + if ((randr_mode != NULL) != crtc->enabled) + changed = TRUE; + else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode)) + changed = TRUE; + + if (rotation != crtc->rotation) + changed = TRUE; + + transform = RRCrtcGetTransform (randr_crtc); + if ((transform != NULL) != crtc->transformPresent) + changed = TRUE; + else if (transform && memcmp (&transform->transform, &crtc->transform.transform, + sizeof (transform->transform)) != 0) + changed = TRUE; + + if (x != crtc->x || y != crtc->y) + changed = TRUE; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + xf86CrtcPtr new_crtc; + + save_crtcs[o] = output->crtc; + + if (output->crtc == crtc) + new_crtc = NULL; + else + new_crtc = output->crtc; + for (ro = 0; ro < num_randr_outputs; ro++) + if (output->randr_output == randr_outputs[ro]) + { + new_crtc = crtc; + break; + } + if (new_crtc != output->crtc) + { + changed = TRUE; + output->crtc = new_crtc; + } + } + for (ro = 0; ro < num_randr_outputs; ro++) + if (randr_outputs[ro]->pendingProperties) + changed = TRUE; + + /* XXX need device-independent mode setting code through an API */ + if (changed) + { + crtc->enabled = randr_mode != NULL; + + if (randr_mode) + { + DisplayModeRec mode; + RRTransformPtr transform = RRCrtcGetTransform (randr_crtc); + + xf86RandRModeConvert (pScrn, randr_mode, &mode); + if (!xf86CrtcSetModeTransform (crtc, &mode, rotation, transform, x, y)) + { + crtc->enabled = save_enabled; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + output->crtc = save_crtcs[o]; + } + free(save_crtcs); + return FALSE; + } + xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height); + xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY); + /* + * Save the last successful setting for EnterVT + */ + crtc->desiredMode = mode; + crtc->desiredRotation = rotation; + if (transform) { + crtc->desiredTransform = *transform; + crtc->desiredTransformPresent = TRUE; + } else + crtc->desiredTransformPresent = FALSE; + + crtc->desiredX = x; + crtc->desiredY = y; + } + xf86DisableUnusedFunctions (pScrn); + } + free(save_crtcs); + return xf86RandR12CrtcNotify (randr_crtc); +} + +static Bool +xf86RandR12CrtcSetGamma (ScreenPtr pScreen, + RRCrtcPtr randr_crtc) +{ + xf86CrtcPtr crtc = randr_crtc->devPrivate; + + if (crtc->funcs->gamma_set == NULL) + return FALSE; + + if (!crtc->scrn->vtSema) + return TRUE; + + /* Realloc local gamma if needed. */ + if (randr_crtc->gammaSize != crtc->gamma_size) { + CARD16 *tmp_ptr; + tmp_ptr = realloc(crtc->gamma_red, 3 * crtc->gamma_size * sizeof (CARD16)); + if (!tmp_ptr) + return FALSE; + crtc->gamma_red = tmp_ptr; + crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; + crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; + } + + crtc->gamma_size = randr_crtc->gammaSize; + memcpy (crtc->gamma_red, randr_crtc->gammaRed, crtc->gamma_size * sizeof (CARD16)); + memcpy (crtc->gamma_green, randr_crtc->gammaGreen, crtc->gamma_size * sizeof (CARD16)); + memcpy (crtc->gamma_blue, randr_crtc->gammaBlue, crtc->gamma_size * sizeof (CARD16)); + + /* Only set it when the crtc is actually running. + * Otherwise it will be set when it's activated. + */ + if (crtc->active) + crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, + crtc->gamma_blue, crtc->gamma_size); + + return TRUE; +} + +static Bool +xf86RandR12CrtcGetGamma (ScreenPtr pScreen, + RRCrtcPtr randr_crtc) +{ + xf86CrtcPtr crtc = randr_crtc->devPrivate; + + if (!crtc->gamma_size) + return FALSE; + + if (!crtc->gamma_red || !crtc->gamma_green || !crtc->gamma_blue) + return FALSE; + + /* Realloc randr gamma if needed. */ + if (randr_crtc->gammaSize != crtc->gamma_size) { + CARD16 *tmp_ptr; + tmp_ptr = realloc(randr_crtc->gammaRed, 3 * crtc->gamma_size * sizeof (CARD16)); + if (!tmp_ptr) + return FALSE; + randr_crtc->gammaRed = tmp_ptr; + randr_crtc->gammaGreen = randr_crtc->gammaRed + crtc->gamma_size; + randr_crtc->gammaBlue = randr_crtc->gammaGreen + crtc->gamma_size; + } + randr_crtc->gammaSize = crtc->gamma_size; + memcpy (randr_crtc->gammaRed, crtc->gamma_red, crtc->gamma_size * sizeof (CARD16)); + memcpy (randr_crtc->gammaGreen, crtc->gamma_green, crtc->gamma_size * sizeof (CARD16)); + memcpy (randr_crtc->gammaBlue, crtc->gamma_blue, crtc->gamma_size * sizeof (CARD16)); + + return TRUE; +} + +static Bool +xf86RandR12OutputSetProperty (ScreenPtr pScreen, + RROutputPtr randr_output, + Atom property, + RRPropertyValuePtr value) +{ + xf86OutputPtr output = randr_output->devPrivate; + + /* If we don't have any property handler, then we don't care what the + * user is setting properties to. + */ + if (output->funcs->set_property == NULL) + return TRUE; + + /* + * This function gets called even when vtSema is FALSE, as + * drivers will need to remember the correct value to apply + * when the VT switch occurs + */ + return output->funcs->set_property(output, property, value); +} + +static Bool +xf86RandR13OutputGetProperty (ScreenPtr pScreen, + RROutputPtr randr_output, + Atom property) +{ + xf86OutputPtr output = randr_output->devPrivate; + + if (output->funcs->get_property == NULL) + return TRUE; + + /* Should be safe even w/o vtSema */ + return output->funcs->get_property(output, property); +} + +static Bool +xf86RandR12OutputValidateMode (ScreenPtr pScreen, + RROutputPtr randr_output, + RRModePtr randr_mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86OutputPtr output = randr_output->devPrivate; + DisplayModeRec mode; + + xf86RandRModeConvert (pScrn, randr_mode, &mode); + /* + * This function may be called when vtSema is FALSE, so + * the underlying function must either avoid touching the hardware + * or return FALSE when vtSema is FALSE + */ + if (output->funcs->mode_valid (output, &mode) != MODE_OK) + return FALSE; + return TRUE; +} + +static void +xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode) +{ +} + +/** + * Given a list of xf86 modes and a RandR Output object, construct + * RandR modes and assign them to the output + */ +static Bool +xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) +{ + DisplayModePtr mode; + RRModePtr *rrmodes = NULL; + int nmode = 0; + int npreferred = 0; + Bool ret = TRUE; + int pref; + + for (mode = modes; mode; mode = mode->next) + nmode++; + + if (nmode) { + rrmodes = malloc(nmode * sizeof (RRModePtr)); + + if (!rrmodes) + return FALSE; + nmode = 0; + + for (pref = 1; pref >= 0; pref--) { + for (mode = modes; mode; mode = mode->next) { + if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) { + xRRModeInfo modeInfo; + RRModePtr rrmode; + + modeInfo.nameLength = strlen (mode->name); + modeInfo.width = mode->HDisplay; + modeInfo.dotClock = mode->Clock * 1000; + modeInfo.hSyncStart = mode->HSyncStart; + modeInfo.hSyncEnd = mode->HSyncEnd; + modeInfo.hTotal = mode->HTotal; + modeInfo.hSkew = mode->HSkew; + + modeInfo.height = mode->VDisplay; + modeInfo.vSyncStart = mode->VSyncStart; + modeInfo.vSyncEnd = mode->VSyncEnd; + modeInfo.vTotal = mode->VTotal; + modeInfo.modeFlags = mode->Flags; + + rrmode = RRModeGet (&modeInfo, mode->name); + if (rrmode) { + rrmodes[nmode++] = rrmode; + npreferred += pref; + } + } + } + } + } + + ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred); + free(rrmodes); + return ret; +} + +/* + * Mirror the current mode configuration to RandR + */ +static Bool +xf86RandR12SetInfo12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + RROutputPtr *clones; + RRCrtcPtr *crtcs; + int ncrtc; + int o, c, l; + RRCrtcPtr randr_crtc; + int nclone; + + clones = malloc(config->num_output * sizeof (RROutputPtr)); + crtcs = malloc(config->num_crtc * sizeof (RRCrtcPtr)); + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + ncrtc = 0; + for (c = 0; c < config->num_crtc; c++) + if (output->possible_crtcs & (1 << c)) + crtcs[ncrtc++] = config->crtc[c]->randr_crtc; + + if (output->crtc) + randr_crtc = output->crtc->randr_crtc; + else + randr_crtc = NULL; + + if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc)) + { + free(crtcs); + free(clones); + return FALSE; + } + + RROutputSetPhysicalSize(output->randr_output, + output->mm_width, + output->mm_height); + xf86RROutputSetModes (output->randr_output, output->probed_modes); + + switch (output->status) { + case XF86OutputStatusConnected: + RROutputSetConnection (output->randr_output, RR_Connected); + break; + case XF86OutputStatusDisconnected: + RROutputSetConnection (output->randr_output, RR_Disconnected); + break; + case XF86OutputStatusUnknown: + RROutputSetConnection (output->randr_output, RR_UnknownConnection); + break; + } + + RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order); + + /* + * Valid clones + */ + nclone = 0; + for (l = 0; l < config->num_output; l++) + { + xf86OutputPtr clone = config->output[l]; + + if (l != o && (output->possible_clones & (1 << l))) + clones[nclone++] = clone->randr_output; + } + if (!RROutputSetClones (output->randr_output, clones, nclone)) + { + free(crtcs); + free(clones); + return FALSE; + } + } + free(crtcs); + free(clones); + return TRUE; +} + + + +/* + * Query the hardware for the current state, then mirror + * that to RandR + */ +static Bool +xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (!pScrn->vtSema) + return TRUE; + xf86ProbeOutputModes (pScrn, 0, 0); + xf86SetScrnInfoModes (pScrn); + return xf86RandR12SetInfo12 (pScreen); +} + +static Bool +xf86RandR12CreateObjects12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + int o; + + if (!RRInit ()) + return FALSE; + + /* + * Configure crtcs + */ + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->randr_crtc = RRCrtcCreate (pScreen, crtc); + RRCrtcGammaSetSize (crtc->randr_crtc, 256); + } + /* + * Configure outputs + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->randr_output = RROutputCreate (pScreen, output->name, + strlen (output->name), + output); + + if (output->funcs->create_resources != NULL) + output->funcs->create_resources(output); + RRPostPendingProperties (output->randr_output); + } + return TRUE; +} + +static Bool +xf86RandR12CreateScreenResources12 (ScreenPtr pScreen) +{ + int c; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + if (xf86RandR12Key == NULL) + return TRUE; +#endif + + for (c = 0; c < config->num_crtc; c++) + xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); + + RRScreenSetSizeRange (pScreen, config->minWidth, config->minHeight, + config->maxWidth, config->maxHeight); + return TRUE; +} + +/* + * Something happened within the screen configuration due + * to DGA, VidMode or hot key. Tell RandR + */ + +void +xf86RandR12TellChanged (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0) + if (xf86RandR12Key == NULL) + return; +#else + if (!XF86RANDRINFO(pScreen)) + return; +#endif + + xf86RandR12SetInfo12 (pScreen); + for (c = 0; c < config->num_crtc; c++) + xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); + + RRTellChanged (pScreen); +} + +static void +xf86RandR12PointerMoved (int scrnIndex, int x, int y) +{ + ScreenPtr pScreen = screenInfo.screens[scrnIndex]; + ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int c; + + randrp->pointerX = x; + randrp->pointerY = y; + for (c = 0; c < config->num_crtc; c++) + xf86RandR13Pan (config->crtc[c], x, y); +} + +static Bool +xf86RandR13GetPanning (ScreenPtr pScreen, + RRCrtcPtr randr_crtc, + BoxPtr totalArea, + BoxPtr trackingArea, + INT16 *border) +{ + xf86CrtcPtr crtc = randr_crtc->devPrivate; + + if (crtc->version < 2) + return FALSE; + if (totalArea) + memcpy (totalArea, &crtc->panningTotalArea, sizeof(BoxRec)); + if (trackingArea) + memcpy (trackingArea, &crtc->panningTrackingArea, sizeof(BoxRec)); + if (border) + memcpy (border, crtc->panningBorder, 4*sizeof(INT16)); + + return TRUE; +} + +static Bool +xf86RandR13SetPanning (ScreenPtr pScreen, + RRCrtcPtr randr_crtc, + BoxPtr totalArea, + BoxPtr trackingArea, + INT16 *border) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + xf86CrtcPtr crtc = randr_crtc->devPrivate; + BoxRec oldTotalArea; + BoxRec oldTrackingArea; + INT16 oldBorder[4]; + + + if (crtc->version < 2) + return FALSE; + + memcpy (&oldTotalArea, &crtc->panningTotalArea, sizeof(BoxRec)); + memcpy (&oldTrackingArea, &crtc->panningTrackingArea, sizeof(BoxRec)); + memcpy (oldBorder, crtc->panningBorder, 4*sizeof(INT16)); + + if (totalArea) + memcpy (&crtc->panningTotalArea, totalArea, sizeof(BoxRec)); + if (trackingArea) + memcpy (&crtc->panningTrackingArea, trackingArea, sizeof(BoxRec)); + if (border) + memcpy (crtc->panningBorder, border, 4*sizeof(INT16)); + + if (xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height)) { + xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY); + return TRUE; + } else { + /* Restore old settings */ + memcpy (&crtc->panningTotalArea, &oldTotalArea, sizeof(BoxRec)); + memcpy (&crtc->panningTrackingArea, &oldTrackingArea, sizeof(BoxRec)); + memcpy (crtc->panningBorder, oldBorder, 4*sizeof(INT16)); + return FALSE; + } +} + +/* + * Compatibility with XF86VidMode's gamma changer. This necessarily clobbers + * any per-crtc setup. You asked for it... + */ + +static void +gamma_to_ramp(float gamma, CARD16 *ramp, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (gamma == 1.0) + ramp[i] = i << 8; + else + ramp[i] = (CARD16)(pow((double)i / (double)(size - 1), 1. / gamma) + * (double)(size - 1) * 256); + } +} + +static int +xf86RandR12ChangeGamma(int scrnIndex, Gamma gamma) +{ + CARD16 *points, *red, *green, *blue; + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn); + int size; + + if (!crtc) + return Success; + + size = max(0, crtc->gammaSize); + if (!size) + return Success; + + points = calloc(size, 3 * sizeof(CARD16)); + if (!points) + return BadAlloc; + + red = points; + green = points + size; + blue = points + 2 * size; + + gamma_to_ramp(gamma.red, red, size); + gamma_to_ramp(gamma.green, green, size); + gamma_to_ramp(gamma.blue, blue, size); + RRCrtcGammaSet(crtc, red, green, blue); + + free(points); + + pScrn->gamma = gamma; + + return Success; +} + +static Bool +xf86RandR12EnterVT (int screen_index, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[screen_index]; + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + if (randrp->orig_EnterVT) { + if (!randrp->orig_EnterVT (screen_index, flags)) + return FALSE; + } + + return RRGetInfo (pScreen, TRUE); /* force a re-probe of outputs and notify clients about changes */ +} + +static Bool +xf86RandR12Init12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + rrScrPrivPtr rp = rrGetScrPriv(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + rp->rrGetInfo = xf86RandR12GetInfo12; + rp->rrScreenSetSize = xf86RandR12ScreenSetSize; + rp->rrCrtcSet = xf86RandR12CrtcSet; + rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; + rp->rrCrtcGetGamma = xf86RandR12CrtcGetGamma; + rp->rrOutputSetProperty = xf86RandR12OutputSetProperty; + rp->rrOutputValidateMode = xf86RandR12OutputValidateMode; +#if RANDR_13_INTERFACE + rp->rrOutputGetProperty = xf86RandR13OutputGetProperty; + rp->rrGetPanning = xf86RandR13GetPanning; + rp->rrSetPanning = xf86RandR13SetPanning; +#endif + rp->rrModeDestroy = xf86RandR12ModeDestroy; + rp->rrSetConfig = NULL; + pScrn->PointerMoved = xf86RandR12PointerMoved; + pScrn->ChangeGamma = xf86RandR12ChangeGamma; + + randrp->orig_EnterVT = pScrn->EnterVT; + pScrn->EnterVT = xf86RandR12EnterVT; + + if (!xf86RandR12CreateObjects12 (pScreen)) + return FALSE; + + /* + * Configure output modes + */ + if (!xf86RandR12SetInfo12 (pScreen)) + return FALSE; + return TRUE; +} + +#endif + +Bool +xf86RandR12PreInit (ScrnInfoPtr pScrn) +{ + return TRUE; +} diff --git a/xorg-server/hw/xfree86/modes/xf86Rotate.c b/xorg-server/hw/xfree86/modes/xf86Rotate.c index 5de6b0c00..e15c61476 100644 --- a/xorg-server/hw/xfree86/modes/xf86Rotate.c +++ b/xorg-server/hw/xfree86/modes/xf86Rotate.c @@ -1,527 +1,527 @@ -/* - * Copyright © 2006 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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_XORG_CONFIG_H -#include <xorg-config.h> -#else -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#endif - -#include <stddef.h> -#include <string.h> -#include <stdio.h> - -#include "xf86.h" -#include "xf86DDC.h" -#include "fb.h" -#include "windowstr.h" -#include "xf86Crtc.h" -#include "xf86Modes.h" -#include "xf86RandR12.h" -#include "X11/extensions/render.h" -#include "X11/extensions/dpmsconst.h" -#include "X11/Xatom.h" - -/* borrowed from composite extension, move to Render and publish? */ - -static VisualPtr -compGetWindowVisual (WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - VisualID vid = wVisual (pWin); - int i; - - for (i = 0; i < pScreen->numVisuals; i++) - if (pScreen->visuals[i].vid == vid) - return &pScreen->visuals[i]; - return 0; -} - -static PictFormatPtr -compWindowFormat (WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - return PictureMatchVisual (pScreen, pWin->drawable.depth, - compGetWindowVisual (pWin)); -} - -#define F(x) IntToxFixed(x) - -#define toF(x) ((float) (x) / 65536.0f) - -static void -xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) -{ - ScrnInfoPtr scrn = crtc->scrn; - ScreenPtr screen = scrn->pScreen; - WindowPtr root = WindowTable[screen->myNum]; - PixmapPtr dst_pixmap = crtc->rotatedPixmap; - PictFormatPtr format = compWindowFormat (WindowTable[screen->myNum]); - int error; - PicturePtr src, dst; - int n = REGION_NUM_RECTS(region); - BoxPtr b = REGION_RECTS(region); - XID include_inferiors = IncludeInferiors; - - src = CreatePicture (None, - &root->drawable, - format, - CPSubwindowMode, - &include_inferiors, - serverClient, - &error); - if (!src) - return; - - dst = CreatePicture (None, - &dst_pixmap->drawable, - format, - 0L, - NULL, - serverClient, - &error); - if (!dst) - return; - - error = SetPictureTransform (src, &crtc->crtc_to_framebuffer); - if (error) - return; - if (crtc->transform_in_use && crtc->filter) - SetPicturePictFilter (src, crtc->filter, - crtc->params, crtc->nparams); - - if (crtc->shadowClear) - { - CompositePicture (PictOpSrc, - src, NULL, dst, - 0, 0, 0, 0, 0, 0, - crtc->mode.HDisplay, crtc->mode.VDisplay); - crtc->shadowClear = FALSE; - } - else - { - while (n--) - { - BoxRec dst_box; - - dst_box = *b; - dst_box.x1 -= crtc->filter_width >> 1; - dst_box.x2 += crtc->filter_width >> 1; - dst_box.y1 -= crtc->filter_height >> 1; - dst_box.y2 += crtc->filter_height >> 1; - pixman_f_transform_bounds (&crtc->f_framebuffer_to_crtc, &dst_box); - CompositePicture (PictOpSrc, - src, NULL, dst, - dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1, - dst_box.x2 - dst_box.x1, - dst_box.y2 - dst_box.y1); - b++; - } - } - FreePicture (src, None); - FreePicture (dst, None); -} - -static void -xf86CrtcDamageShadow (xf86CrtcPtr crtc) -{ - ScrnInfoPtr pScrn = crtc->scrn; - BoxRec damage_box; - RegionRec damage_region; - ScreenPtr pScreen = pScrn->pScreen; - - damage_box.x1 = 0; - damage_box.x2 = crtc->mode.HDisplay; - damage_box.y1 = 0; - damage_box.y2 = crtc->mode.VDisplay; - if (!pixman_transform_bounds (&crtc->crtc_to_framebuffer, &damage_box)) - { - damage_box.x1 = 0; - damage_box.y1 = 0; - damage_box.x2 = pScreen->width; - damage_box.y2 = pScreen->height; - } - if (damage_box.x1 < 0) damage_box.x1 = 0; - if (damage_box.y1 < 0) damage_box.y1 = 0; - if (damage_box.x2 > pScreen->width) damage_box.x2 = pScreen->width; - if (damage_box.y2 > pScreen->height) damage_box.y2 = pScreen->height; - REGION_INIT (pScreen, &damage_region, &damage_box, 1); - DamageRegionAppend (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, - &damage_region); - REGION_UNINIT (pScreen, &damage_region); - crtc->shadowClear = TRUE; -} - -static void -xf86RotatePrepare (ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int c; - - for (c = 0; c < xf86_config->num_crtc; c++) - { - xf86CrtcPtr crtc = xf86_config->crtc[c]; - - if (crtc->rotatedData && !crtc->rotatedPixmap) - { - crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, - crtc->rotatedData, - crtc->mode.HDisplay, - crtc->mode.VDisplay); - if (!xf86_config->rotation_damage_registered) - { - /* Hook damage to screen pixmap */ - DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, - xf86_config->rotation_damage); - xf86_config->rotation_damage_registered = TRUE; - EnableLimitedSchedulingLatency(); - } - - xf86CrtcDamageShadow (crtc); - } - } -} - -static Bool -xf86RotateRedisplay(ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - DamagePtr damage = xf86_config->rotation_damage; - RegionPtr region; - - if (!damage) - return FALSE; - xf86RotatePrepare (pScreen); - region = DamageRegion(damage); - if (REGION_NOTEMPTY(pScreen, region)) - { - int c; - SourceValidateProcPtr SourceValidate; - - /* - * SourceValidate is used by the software cursor code - * to pull the cursor off of the screen when reading - * bits from the frame buffer. Bypassing this function - * leaves the software cursor in place - */ - SourceValidate = pScreen->SourceValidate; - pScreen->SourceValidate = NULL; - - for (c = 0; c < xf86_config->num_crtc; c++) - { - xf86CrtcPtr crtc = xf86_config->crtc[c]; - - if (crtc->transform_in_use && crtc->enabled) - { - RegionRec crtc_damage; - - /* compute portion of damage that overlaps crtc */ - REGION_INIT(pScreen, &crtc_damage, &crtc->bounds, 1); - REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); - - /* update damaged region */ - if (REGION_NOTEMPTY(pScreen, &crtc_damage)) - xf86RotateCrtcRedisplay (crtc, &crtc_damage); - - REGION_UNINIT (pScreen, &crtc_damage); - } - } - pScreen->SourceValidate = SourceValidate; - DamageEmpty(damage); - } - return TRUE; -} - -static void -xf86RotateBlockHandler(int screenNum, pointer blockData, - pointer pTimeout, pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[screenNum]; - ScrnInfoPtr pScrn = xf86Screens[screenNum]; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - Bool rotation_active; - - rotation_active = xf86RotateRedisplay(pScreen); - pScreen->BlockHandler = xf86_config->BlockHandler; - (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); - /* cannot avoid re-wrapping until all wrapping is audited */ - xf86_config->BlockHandler = pScreen->BlockHandler; - pScreen->BlockHandler = xf86RotateBlockHandler; -} - -void -xf86RotateDestroy (xf86CrtcPtr crtc) -{ - ScrnInfoPtr pScrn = crtc->scrn; - ScreenPtr pScreen = pScrn->pScreen; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int c; - - /* Free memory from rotation */ - if (crtc->rotatedPixmap || crtc->rotatedData) - { - crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData); - crtc->rotatedPixmap = NULL; - crtc->rotatedData = NULL; - } - - for (c = 0; c < xf86_config->num_crtc; c++) - if (xf86_config->crtc[c]->transform_in_use) - return; - - /* - * Clean up damage structures when no crtcs are rotated - */ - if (xf86_config->rotation_damage) - { - /* Free damage structure */ - if (xf86_config->rotation_damage_registered) - { - DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, - xf86_config->rotation_damage); - xf86_config->rotation_damage_registered = FALSE; - DisableLimitedSchedulingLatency(); - } - DamageDestroy (xf86_config->rotation_damage); - xf86_config->rotation_damage = NULL; - } -} - -void -xf86RotateFreeShadow(ScrnInfoPtr pScrn) -{ - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - int c; - - for (c = 0; c < config->num_crtc; c++) { - xf86CrtcPtr crtc = config->crtc[c]; - - if (crtc->rotatedPixmap || crtc->rotatedData) { - crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap, - crtc->rotatedData); - crtc->rotatedPixmap = NULL; - crtc->rotatedData = NULL; - } - } -} - -void -xf86RotateCloseScreen (ScreenPtr screen) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - int c; - - for (c = 0; c < xf86_config->num_crtc; c++) - xf86RotateDestroy (xf86_config->crtc[c]); -} - -static Bool -xf86CrtcFitsScreen (xf86CrtcPtr crtc, struct pict_f_transform *crtc_to_fb) -{ - ScrnInfoPtr pScrn = crtc->scrn; - BoxRec b; - - /* When called before PreInit, the driver is - * presumably doing load detect - */ - if (pScrn->virtualX == 0 || pScrn->virtualY == 0) - return TRUE; - - b.x1 = 0; - b.y1 = 0; - b.x2 = crtc->mode.HDisplay; - b.y2 = crtc->mode.VDisplay; - if (crtc_to_fb) - pixman_f_transform_bounds (crtc_to_fb, &b); - else { - b.x1 += crtc->x; - b.y1 += crtc->y; - b.x2 += crtc->x; - b.y2 += crtc->y; - } - - return (0 <= b.x1 && b.x2 <= pScrn->virtualX && - 0 <= b.y1 && b.y2 <= pScrn->virtualY); -} - -Bool -xf86CrtcRotate (xf86CrtcPtr crtc) -{ - ScrnInfoPtr pScrn = crtc->scrn; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - /* if this is called during ScreenInit() we don't have pScrn->pScreen yet */ - ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; - PictTransform crtc_to_fb; - struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc; - xFixed *new_params = NULL; - int new_nparams = 0; - PictFilterPtr new_filter = NULL; - int new_width = 0; - int new_height = 0; - RRTransformPtr transform = NULL; - Bool damage = FALSE; - - if (crtc->transformPresent) - transform = &crtc->transform; - - if (!RRTransformCompute (crtc->x, crtc->y, - crtc->mode.HDisplay, crtc->mode.VDisplay, - crtc->rotation, - transform, - - &crtc_to_fb, - &f_crtc_to_fb, - &f_fb_to_crtc) && - xf86CrtcFitsScreen (crtc, &f_crtc_to_fb)) - { - /* - * If the untranslated transformation is the identity, - * disable the shadow buffer - */ - xf86RotateDestroy (crtc); - crtc->transform_in_use = FALSE; - if (new_params) - xfree (new_params); - new_params = NULL; - new_nparams = 0; - new_filter = NULL; - new_width = 0; - new_height = 0; - } - else - { - /* - * these are the size of the shadow pixmap, which - * matches the mode, not the pre-rotated copy in the - * frame buffer - */ - int width = crtc->mode.HDisplay; - int height = crtc->mode.VDisplay; - void *shadowData = crtc->rotatedData; - PixmapPtr shadow = crtc->rotatedPixmap; - int old_width = shadow ? shadow->drawable.width : 0; - int old_height = shadow ? shadow->drawable.height : 0; - - /* Allocate memory for rotation */ - if (old_width != width || old_height != height) - { - if (shadow || shadowData) - { - crtc->funcs->shadow_destroy (crtc, shadow, shadowData); - crtc->rotatedPixmap = NULL; - crtc->rotatedData = NULL; - } - shadowData = crtc->funcs->shadow_allocate (crtc, width, height); - if (!shadowData) - goto bail1; - crtc->rotatedData = shadowData; - /* shadow will be damaged in xf86RotatePrepare */ - } - else - { - /* mark shadowed area as damaged so it will be repainted */ - damage = TRUE; - } - - if (!xf86_config->rotation_damage) - { - /* Create damage structure */ - xf86_config->rotation_damage = DamageCreate (NULL, NULL, - DamageReportNone, - TRUE, pScreen, pScreen); - if (!xf86_config->rotation_damage) - goto bail2; - - /* Wrap block handler */ - if (!xf86_config->BlockHandler) { - xf86_config->BlockHandler = pScreen->BlockHandler; - pScreen->BlockHandler = xf86RotateBlockHandler; - } - } -#ifdef RANDR_12_INTERFACE - if (transform) - { - if (transform->nparams) { - new_params = xalloc (transform->nparams * sizeof (xFixed)); - if (new_params) { - memcpy (new_params, transform->params, - transform->nparams * sizeof (xFixed)); - new_nparams = transform->nparams; - new_filter = transform->filter; - } - } else - new_filter = transform->filter; - if (new_filter) - { - new_width = new_filter->width; - new_height = new_filter->height; - } - } -#endif - - if (0) - { - bail2: - if (shadow || shadowData) - { - crtc->funcs->shadow_destroy (crtc, shadow, shadowData); - crtc->rotatedPixmap = NULL; - crtc->rotatedData = NULL; - } - bail1: - if (old_width && old_height) - crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, - NULL, - old_width, - old_height); - return FALSE; - } - crtc->transform_in_use = TRUE; - } - crtc->crtc_to_framebuffer = crtc_to_fb; - crtc->f_crtc_to_framebuffer = f_crtc_to_fb; - crtc->f_framebuffer_to_crtc = f_fb_to_crtc; - if (crtc->params) - xfree (crtc->params); - crtc->params = new_params; - crtc->nparams = new_nparams; - crtc->filter = new_filter; - crtc->filter_width = new_width; - crtc->filter_height = new_height; - crtc->bounds.x1 = 0; - crtc->bounds.x2 = crtc->mode.HDisplay; - crtc->bounds.y1 = 0; - crtc->bounds.y2 = crtc->mode.VDisplay; - pixman_f_transform_bounds (&f_crtc_to_fb, &crtc->bounds); - - if (damage) - xf86CrtcDamageShadow (crtc); - - /* All done */ - return TRUE; -} +/* + * Copyright © 2006 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xf86DDC.h" +#include "fb.h" +#include "windowstr.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "xf86RandR12.h" +#include "X11/extensions/render.h" +#include "X11/extensions/dpmsconst.h" +#include "X11/Xatom.h" + +/* borrowed from composite extension, move to Render and publish? */ + +static VisualPtr +compGetWindowVisual (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + VisualID vid = wVisual (pWin); + int i; + + for (i = 0; i < pScreen->numVisuals; i++) + if (pScreen->visuals[i].vid == vid) + return &pScreen->visuals[i]; + return 0; +} + +static PictFormatPtr +compWindowFormat (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + return PictureMatchVisual (pScreen, pWin->drawable.depth, + compGetWindowVisual (pWin)); +} + +#define F(x) IntToxFixed(x) + +#define toF(x) ((float) (x) / 65536.0f) + +static void +xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) +{ + ScrnInfoPtr scrn = crtc->scrn; + ScreenPtr screen = scrn->pScreen; + WindowPtr root = WindowTable[screen->myNum]; + PixmapPtr dst_pixmap = crtc->rotatedPixmap; + PictFormatPtr format = compWindowFormat (WindowTable[screen->myNum]); + int error; + PicturePtr src, dst; + int n = REGION_NUM_RECTS(region); + BoxPtr b = REGION_RECTS(region); + XID include_inferiors = IncludeInferiors; + + src = CreatePicture (None, + &root->drawable, + format, + CPSubwindowMode, + &include_inferiors, + serverClient, + &error); + if (!src) + return; + + dst = CreatePicture (None, + &dst_pixmap->drawable, + format, + 0L, + NULL, + serverClient, + &error); + if (!dst) + return; + + error = SetPictureTransform (src, &crtc->crtc_to_framebuffer); + if (error) + return; + if (crtc->transform_in_use && crtc->filter) + SetPicturePictFilter (src, crtc->filter, + crtc->params, crtc->nparams); + + if (crtc->shadowClear) + { + CompositePicture (PictOpSrc, + src, NULL, dst, + 0, 0, 0, 0, 0, 0, + crtc->mode.HDisplay, crtc->mode.VDisplay); + crtc->shadowClear = FALSE; + } + else + { + while (n--) + { + BoxRec dst_box; + + dst_box = *b; + dst_box.x1 -= crtc->filter_width >> 1; + dst_box.x2 += crtc->filter_width >> 1; + dst_box.y1 -= crtc->filter_height >> 1; + dst_box.y2 += crtc->filter_height >> 1; + pixman_f_transform_bounds (&crtc->f_framebuffer_to_crtc, &dst_box); + CompositePicture (PictOpSrc, + src, NULL, dst, + dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1, + dst_box.x2 - dst_box.x1, + dst_box.y2 - dst_box.y1); + b++; + } + } + FreePicture (src, None); + FreePicture (dst, None); +} + +static void +xf86CrtcDamageShadow (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + BoxRec damage_box; + RegionRec damage_region; + ScreenPtr pScreen = pScrn->pScreen; + + damage_box.x1 = 0; + damage_box.x2 = crtc->mode.HDisplay; + damage_box.y1 = 0; + damage_box.y2 = crtc->mode.VDisplay; + if (!pixman_transform_bounds (&crtc->crtc_to_framebuffer, &damage_box)) + { + damage_box.x1 = 0; + damage_box.y1 = 0; + damage_box.x2 = pScreen->width; + damage_box.y2 = pScreen->height; + } + if (damage_box.x1 < 0) damage_box.x1 = 0; + if (damage_box.y1 < 0) damage_box.y1 = 0; + if (damage_box.x2 > pScreen->width) damage_box.x2 = pScreen->width; + if (damage_box.y2 > pScreen->height) damage_box.y2 = pScreen->height; + REGION_INIT (pScreen, &damage_region, &damage_box, 1); + DamageRegionAppend (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + &damage_region); + REGION_UNINIT (pScreen, &damage_region); + crtc->shadowClear = TRUE; +} + +static void +xf86RotatePrepare (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->rotatedData && !crtc->rotatedPixmap) + { + crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, + crtc->rotatedData, + crtc->mode.HDisplay, + crtc->mode.VDisplay); + if (!xf86_config->rotation_damage_registered) + { + /* Hook damage to screen pixmap */ + DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + xf86_config->rotation_damage); + xf86_config->rotation_damage_registered = TRUE; + EnableLimitedSchedulingLatency(); + } + + xf86CrtcDamageShadow (crtc); + } + } +} + +static Bool +xf86RotateRedisplay(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + DamagePtr damage = xf86_config->rotation_damage; + RegionPtr region; + + if (!damage) + return FALSE; + xf86RotatePrepare (pScreen); + region = DamageRegion(damage); + if (REGION_NOTEMPTY(pScreen, region)) + { + int c; + SourceValidateProcPtr SourceValidate; + + /* + * SourceValidate is used by the software cursor code + * to pull the cursor off of the screen when reading + * bits from the frame buffer. Bypassing this function + * leaves the software cursor in place + */ + SourceValidate = pScreen->SourceValidate; + pScreen->SourceValidate = NULL; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->transform_in_use && crtc->enabled) + { + RegionRec crtc_damage; + + /* compute portion of damage that overlaps crtc */ + REGION_INIT(pScreen, &crtc_damage, &crtc->bounds, 1); + REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); + + /* update damaged region */ + if (REGION_NOTEMPTY(pScreen, &crtc_damage)) + xf86RotateCrtcRedisplay (crtc, &crtc_damage); + + REGION_UNINIT (pScreen, &crtc_damage); + } + } + pScreen->SourceValidate = SourceValidate; + DamageEmpty(damage); + } + return TRUE; +} + +static void +xf86RotateBlockHandler(int screenNum, pointer blockData, + pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + ScrnInfoPtr pScrn = xf86Screens[screenNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + Bool rotation_active; + + rotation_active = xf86RotateRedisplay(pScreen); + pScreen->BlockHandler = xf86_config->BlockHandler; + (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); + /* cannot avoid re-wrapping until all wrapping is audited */ + xf86_config->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = xf86RotateBlockHandler; +} + +void +xf86RotateDestroy (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + ScreenPtr pScreen = pScrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + + /* Free memory from rotation */ + if (crtc->rotatedPixmap || crtc->rotatedData) + { + crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + + for (c = 0; c < xf86_config->num_crtc; c++) + if (xf86_config->crtc[c]->transform_in_use) + return; + + /* + * Clean up damage structures when no crtcs are rotated + */ + if (xf86_config->rotation_damage) + { + /* Free damage structure */ + if (xf86_config->rotation_damage_registered) + { + DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + xf86_config->rotation_damage); + xf86_config->rotation_damage_registered = FALSE; + DisableLimitedSchedulingLatency(); + } + DamageDestroy (xf86_config->rotation_damage); + xf86_config->rotation_damage = NULL; + } +} + +void +xf86RotateFreeShadow(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + + for (c = 0; c < config->num_crtc; c++) { + xf86CrtcPtr crtc = config->crtc[c]; + + if (crtc->rotatedPixmap || crtc->rotatedData) { + crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap, + crtc->rotatedData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + } +} + +void +xf86RotateCloseScreen (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + xf86RotateDestroy (xf86_config->crtc[c]); +} + +static Bool +xf86CrtcFitsScreen (xf86CrtcPtr crtc, struct pict_f_transform *crtc_to_fb) +{ + ScrnInfoPtr pScrn = crtc->scrn; + BoxRec b; + + /* When called before PreInit, the driver is + * presumably doing load detect + */ + if (pScrn->virtualX == 0 || pScrn->virtualY == 0) + return TRUE; + + b.x1 = 0; + b.y1 = 0; + b.x2 = crtc->mode.HDisplay; + b.y2 = crtc->mode.VDisplay; + if (crtc_to_fb) + pixman_f_transform_bounds (crtc_to_fb, &b); + else { + b.x1 += crtc->x; + b.y1 += crtc->y; + b.x2 += crtc->x; + b.y2 += crtc->y; + } + + return (0 <= b.x1 && b.x2 <= pScrn->virtualX && + 0 <= b.y1 && b.y2 <= pScrn->virtualY); +} + +Bool +xf86CrtcRotate (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + /* if this is called during ScreenInit() we don't have pScrn->pScreen yet */ + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + PictTransform crtc_to_fb; + struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc; + xFixed *new_params = NULL; + int new_nparams = 0; + PictFilterPtr new_filter = NULL; + int new_width = 0; + int new_height = 0; + RRTransformPtr transform = NULL; + Bool damage = FALSE; + + if (crtc->transformPresent) + transform = &crtc->transform; + + if (!RRTransformCompute (crtc->x, crtc->y, + crtc->mode.HDisplay, crtc->mode.VDisplay, + crtc->rotation, + transform, + + &crtc_to_fb, + &f_crtc_to_fb, + &f_fb_to_crtc) && + xf86CrtcFitsScreen (crtc, &f_crtc_to_fb)) + { + /* + * If the untranslated transformation is the identity, + * disable the shadow buffer + */ + xf86RotateDestroy (crtc); + crtc->transform_in_use = FALSE; + if (new_params) + free(new_params); + new_params = NULL; + new_nparams = 0; + new_filter = NULL; + new_width = 0; + new_height = 0; + } + else + { + /* + * these are the size of the shadow pixmap, which + * matches the mode, not the pre-rotated copy in the + * frame buffer + */ + int width = crtc->mode.HDisplay; + int height = crtc->mode.VDisplay; + void *shadowData = crtc->rotatedData; + PixmapPtr shadow = crtc->rotatedPixmap; + int old_width = shadow ? shadow->drawable.width : 0; + int old_height = shadow ? shadow->drawable.height : 0; + + /* Allocate memory for rotation */ + if (old_width != width || old_height != height) + { + if (shadow || shadowData) + { + crtc->funcs->shadow_destroy (crtc, shadow, shadowData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + shadowData = crtc->funcs->shadow_allocate (crtc, width, height); + if (!shadowData) + goto bail1; + crtc->rotatedData = shadowData; + /* shadow will be damaged in xf86RotatePrepare */ + } + else + { + /* mark shadowed area as damaged so it will be repainted */ + damage = TRUE; + } + + if (!xf86_config->rotation_damage) + { + /* Create damage structure */ + xf86_config->rotation_damage = DamageCreate (NULL, NULL, + DamageReportNone, + TRUE, pScreen, pScreen); + if (!xf86_config->rotation_damage) + goto bail2; + + /* Wrap block handler */ + if (!xf86_config->BlockHandler) { + xf86_config->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = xf86RotateBlockHandler; + } + } +#ifdef RANDR_12_INTERFACE + if (transform) + { + if (transform->nparams) { + new_params = malloc(transform->nparams * sizeof (xFixed)); + if (new_params) { + memcpy (new_params, transform->params, + transform->nparams * sizeof (xFixed)); + new_nparams = transform->nparams; + new_filter = transform->filter; + } + } else + new_filter = transform->filter; + if (new_filter) + { + new_width = new_filter->width; + new_height = new_filter->height; + } + } +#endif + + if (0) + { + bail2: + if (shadow || shadowData) + { + crtc->funcs->shadow_destroy (crtc, shadow, shadowData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + bail1: + if (old_width && old_height) + crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, + NULL, + old_width, + old_height); + return FALSE; + } + crtc->transform_in_use = TRUE; + } + crtc->crtc_to_framebuffer = crtc_to_fb; + crtc->f_crtc_to_framebuffer = f_crtc_to_fb; + crtc->f_framebuffer_to_crtc = f_fb_to_crtc; + if (crtc->params) + free(crtc->params); + crtc->params = new_params; + crtc->nparams = new_nparams; + crtc->filter = new_filter; + crtc->filter_width = new_width; + crtc->filter_height = new_height; + crtc->bounds.x1 = 0; + crtc->bounds.x2 = crtc->mode.HDisplay; + crtc->bounds.y1 = 0; + crtc->bounds.y2 = crtc->mode.VDisplay; + pixman_f_transform_bounds (&f_crtc_to_fb, &crtc->bounds); + + if (damage) + xf86CrtcDamageShadow (crtc); + + /* All done */ + return TRUE; +} diff --git a/xorg-server/hw/xfree86/os-support/bsd/i386_video.c b/xorg-server/hw/xfree86/os-support/bsd/i386_video.c index 10db9c7b8..0d457193a 100644 --- a/xorg-server/hw/xfree86/os-support/bsd/i386_video.c +++ b/xorg-server/hw/xfree86/os-support/bsd/i386_video.c @@ -1,908 +1,908 @@ -/* - * Copyright 1992 by Rich Murphey <Rich@Rice.edu> - * Copyright 1993 by David Wexelblat <dwex@goblin.org> - * - * 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 names of Rich Murphey and David Wexelblat - * not be used in advertising or publicity pertaining to distribution of - * the software without specific, written prior permission. Rich Murphey and - * David Wexelblat make no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * RICH MURPHEY AND DAVID WEXELBLAT DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL RICH MURPHEY OR DAVID WEXELBLAT 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_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include "xf86.h" -#include "xf86Priv.h" - -#include <errno.h> -#include <sys/mman.h> - -#ifdef HAS_MTRR_SUPPORT -#ifndef __NetBSD__ -#include <sys/types.h> -#include <sys/memrange.h> -#else -#include "memrange.h" -#endif -#define X_MTRR_ID "XFree86" -#endif - -#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) -#include <machine/mtrr.h> -#include <machine/sysarch.h> -#include <sys/queue.h> -#ifdef __x86_64__ -#define i386_set_mtrr x86_64_set_mtrr -#define i386_get_mtrr x86_64_get_mtrr -#define i386_iopl x86_64_iopl -#endif -#endif - -#include "xf86_OSlib.h" -#include "xf86OSpriv.h" - -#if defined(__NetBSD__) && !defined(MAP_FILE) -#define MAP_FLAGS MAP_SHARED -#else -#define MAP_FLAGS (MAP_FILE | MAP_SHARED) -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((caddr_t)-1) -#endif - -#ifdef __OpenBSD__ -#define SYSCTL_MSG "\tCheck that you have set 'machdep.allowaperture=1'\n"\ - "\tin /etc/sysctl.conf and reboot your machine\n" \ - "\trefer to xf86(4) for details" -#define SYSCTL_MSG2 \ - "Check that you have set 'machdep.allowaperture=2'\n" \ - "\tin /etc/sysctl.conf and reboot your machine\n" \ - "\trefer to xf86(4) for details" -#endif - -/***************************************************************************/ -/* Video Memory Mapping section */ -/***************************************************************************/ - -static Bool useDevMem = FALSE; -static int devMemFd = -1; - -#ifdef HAS_APERTURE_DRV -#define DEV_APERTURE "/dev/xf86" -#endif -#define DEV_MEM "/dev/mem" - -static pointer mapVidMem(int, unsigned long, unsigned long, int); -static void unmapVidMem(int, pointer, unsigned long); - -#ifdef HAS_MTRR_SUPPORT -static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType); -static void undoWC(int, pointer); -static Bool cleanMTRR(void); -#endif -#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) -static pointer NetBSDsetWC(int, unsigned long, unsigned long, Bool, - MessageType); -static void NetBSDundoWC(int, pointer); -#endif - -/* - * Check if /dev/mem can be mmap'd. If it can't print a warning when - * "warn" is TRUE. - */ -static void -checkDevMem(Bool warn) -{ - static Bool devMemChecked = FALSE; - int fd; - pointer base; - - if (devMemChecked) - return; - devMemChecked = TRUE; - - if ((fd = open(DEV_MEM, O_RDWR)) >= 0) - { - /* Try to map a page at the VGA address */ - base = mmap((caddr_t)0, 4096, PROT_READ | PROT_WRITE, - MAP_FLAGS, fd, (off_t)0xA0000); - - if (base != MAP_FAILED) - { - munmap((caddr_t)base, 4096); - devMemFd = fd; - useDevMem = TRUE; - return; - } else { - /* This should not happen */ - if (warn) - { - xf86Msg(X_WARNING, "checkDevMem: failed to mmap %s (%s)\n", - DEV_MEM, strerror(errno)); - } - useDevMem = FALSE; - return; - } - } -#ifndef HAS_APERTURE_DRV - if (warn) - { - xf86Msg(X_WARNING, "checkDevMem: failed to open %s (%s)\n", - DEV_MEM, strerror(errno)); - } - useDevMem = FALSE; - return; -#else - /* Failed to open /dev/mem, try the aperture driver */ - if ((fd = open(DEV_APERTURE, O_RDWR)) >= 0) - { - /* Try to map a page at the VGA address */ - base = mmap((caddr_t)0, 4096, PROT_READ | PROT_WRITE, - MAP_FLAGS, fd, (off_t)0xA0000); - - if (base != MAP_FAILED) - { - munmap((caddr_t)base, 4096); - devMemFd = fd; - useDevMem = TRUE; - xf86Msg(X_INFO, "checkDevMem: using aperture driver %s\n", - DEV_APERTURE); - return; - } else { - - if (warn) - { - xf86Msg(X_WARNING, "checkDevMem: failed to mmap %s (%s)\n", - DEV_APERTURE, strerror(errno)); - } - } - } else { - if (warn) - { -#ifndef __OpenBSD__ - xf86Msg(X_WARNING, "checkDevMem: failed to open %s and %s\n" - "\t(%s)\n", DEV_MEM, DEV_APERTURE, strerror(errno)); -#else /* __OpenBSD__ */ - xf86Msg(X_WARNING, "checkDevMem: failed to open %s and %s\n" - "\t(%s)\n%s", DEV_MEM, DEV_APERTURE, strerror(errno), - SYSCTL_MSG); -#endif /* __OpenBSD__ */ - } - } - - useDevMem = FALSE; - return; - -#endif -} - -void -xf86OSInitVidMem(VidMemInfoPtr pVidMem) -{ - checkDevMem(TRUE); - pVidMem->linearSupported = useDevMem; - pVidMem->mapMem = mapVidMem; - pVidMem->unmapMem = unmapVidMem; - -#if HAVE_PCI_SYSTEM_INIT_DEV_MEM - if (useDevMem) - pci_system_init_dev_mem(devMemFd); -#endif - -#ifdef HAS_MTRR_SUPPORT - if (useDevMem) { - if (cleanMTRR()) { - pVidMem->setWC = setWC; - pVidMem->undoWC = undoWC; - } - } -#endif -#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) - pVidMem->setWC = NetBSDsetWC; - pVidMem->undoWC = NetBSDundoWC; -#endif - pVidMem->initialised = TRUE; -} - -static pointer -mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags) -{ - pointer base; - - checkDevMem(FALSE); - - if (useDevMem) - { - if (devMemFd < 0) - { - FatalError("xf86MapVidMem: failed to open %s (%s)", - DEV_MEM, strerror(errno)); - } - base = mmap((caddr_t)0, Size, - (flags & VIDMEM_READONLY) ? - PROT_READ : (PROT_READ | PROT_WRITE), - MAP_FLAGS, devMemFd, (off_t)Base); - if (base == MAP_FAILED) - { - FatalError("%s: could not mmap %s [s=%lx,a=%lx] (%s)", - "xf86MapVidMem", DEV_MEM, Size, Base, - strerror(errno)); - } - return(base); - } - - /* else, mmap /dev/vga */ - if ((unsigned long)Base < 0xA0000 || (unsigned long)Base >= 0xC0000) - { - FatalError("%s: Address 0x%lx outside allowable range", - "xf86MapVidMem", Base); - } - base = mmap(0, Size, - (flags & VIDMEM_READONLY) ? - PROT_READ : (PROT_READ | PROT_WRITE), - MAP_FLAGS, xf86Info.screenFd, - (unsigned long)Base - 0xA0000 - ); - if (base == MAP_FAILED) - { - FatalError("xf86MapVidMem: Could not mmap /dev/vga (%s)", - strerror(errno)); - } - return(base); -} - -static void -unmapVidMem(int ScreenNum, pointer Base, unsigned long Size) -{ - munmap((caddr_t)Base, Size); -} - -/* - * Read BIOS via mmap()ing DEV_MEM - */ - -int -xf86ReadBIOS(unsigned long Base, unsigned long Offset, unsigned char *Buf, - int Len) -{ - unsigned char *ptr; - int psize; - int mlen; - - checkDevMem(TRUE); - if (devMemFd == -1) { - return(-1); - } - - psize = getpagesize(); - Offset += Base & (psize - 1); - Base &= ~(psize - 1); - mlen = (Offset + Len + psize - 1) & ~(psize - 1); - ptr = (unsigned char *)mmap((caddr_t)0, mlen, PROT_READ, - MAP_SHARED, devMemFd, (off_t)Base); - if ((long)ptr == -1) - { - xf86Msg(X_WARNING, - "xf86ReadBIOS: %s mmap[s=%x,a=%lx,o=%lx] failed (%s)\n", - DEV_MEM, Len, Base, Offset, strerror(errno)); -#ifdef __OpenBSD__ - if (Base < 0xa0000) { - xf86Msg(X_WARNING, SYSCTL_MSG2); - } -#endif - return(-1); - } -#ifdef DEBUG - ErrorF("xf86ReadBIOS: BIOS at 0x%08x has signature 0x%04x\n", - Base, ptr[0] | (ptr[1] << 8)); -#endif - (void)memcpy(Buf, (void *)(ptr + Offset), Len); - (void)munmap((caddr_t)ptr, mlen); -#ifdef DEBUG - xf86MsgVerb(X_INFO, 3, "xf86ReadBIOS(%x, %x, Buf, %x)" - "-> %02x %02x %02x %02x...\n", - Base, Offset, Len, Buf[0], Buf[1], Buf[2], Buf[3]); -#endif - return(Len); -} - -#ifdef USE_I386_IOPL -/***************************************************************************/ -/* I/O Permissions section */ -/***************************************************************************/ - -static Bool ExtendedEnabled = FALSE; - -Bool -xf86EnableIO() -{ - if (ExtendedEnabled) - return TRUE; - - if (i386_iopl(TRUE) < 0) - { -#ifndef __OpenBSD__ - xf86Msg(X_WARNING,"%s: Failed to set IOPL for extended I/O", - "xf86EnableIO"); -#else - xf86Msg(X_WARNING,"%s: Failed to set IOPL for extended I/O\n%s", - "xf86EnableIO", SYSCTL_MSG); -#endif - return FALSE; - } - ExtendedEnabled = TRUE; - - return TRUE; -} - -void -xf86DisableIO() -{ - if (!ExtendedEnabled) - return; - - i386_iopl(FALSE); - ExtendedEnabled = FALSE; - - return; -} - -#endif /* USE_I386_IOPL */ - -#ifdef USE_AMD64_IOPL -/***************************************************************************/ -/* I/O Permissions section */ -/***************************************************************************/ - -static Bool ExtendedEnabled = FALSE; - -Bool -xf86EnableIO() -{ - if (ExtendedEnabled) - return TRUE; - - if (amd64_iopl(TRUE) < 0) - { -#ifndef __OpenBSD__ - xf86Msg(X_WARNING,"%s: Failed to set IOPL for extended I/O", - "xf86EnableIO"); -#else - xf86Msg(X_WARNING,"%s: Failed to set IOPL for extended I/O\n%s", - "xf86EnableIO", SYSCTL_MSG); -#endif - return FALSE; - } - ExtendedEnabled = TRUE; - - return TRUE; -} - -void -xf86DisableIO() -{ - if (!ExtendedEnabled) - return; - - if (amd64_iopl(FALSE) == 0) { - ExtendedEnabled = FALSE; - } - /* Otherwise, the X server has revoqued its root uid, - and thus cannot give up IO privileges any more */ - - return; -} - -#endif /* USE_AMD64_IOPL */ - -#ifdef USE_DEV_IO -static int IoFd = -1; - -Bool -xf86EnableIO() -{ - if (IoFd >= 0) - return TRUE; - - if ((IoFd = open("/dev/io", O_RDWR)) == -1) - { - xf86Msg(X_WARNING,"xf86EnableIO: " - "Failed to open /dev/io for extended I/O"); - return FALSE; - } - return TRUE; -} - -void -xf86DisableIO() -{ - if (IoFd < 0) - return; - - close(IoFd); - IoFd = -1; - return; -} - -#endif - -#ifdef __NetBSD__ -/***************************************************************************/ -/* Set TV output mode */ -/***************************************************************************/ -void -xf86SetTVOut(int mode) -{ - switch (xf86Info.consType) - { -#ifdef PCCONS_SUPPORT - case PCCONS:{ - - if (ioctl (xf86Info.consoleFd, CONSOLE_X_TV_ON, &mode) < 0) - { - xf86Msg(X_WARNING, - "xf86SetTVOut: Could not set console to TV output, %s\n", - strerror(errno)); - } - } - break; -#endif /* PCCONS_SUPPORT */ - - default: - FatalError("Xf86SetTVOut: Unsupported console"); - break; - } - return; -} - -void -xf86SetRGBOut() -{ - switch (xf86Info.consType) - { -#ifdef PCCONS_SUPPORT - case PCCONS:{ - - if (ioctl (xf86Info.consoleFd, CONSOLE_X_TV_OFF, 0) < 0) - { - xf86Msg(X_WARNING, - "xf86SetTVOut: Could not set console to RGB output, %s\n", - strerror(errno)); - } - } - break; -#endif /* PCCONS_SUPPORT */ - - default: - FatalError("Xf86SetTVOut: Unsupported console"); - break; - } - return; -} -#endif - -#ifdef HAS_MTRR_SUPPORT -/* memory range (MTRR) support for FreeBSD */ - -/* - * This code is experimental. Some parts may be overkill, and other parts - * may be incomplete. - */ - -/* - * getAllRanges returns the full list of memory ranges with attributes set. - */ - -static struct mem_range_desc * -getAllRanges(int *nmr) -{ - struct mem_range_desc *mrd; - struct mem_range_op mro; - - /* - * Find how many ranges there are. If this fails, then the kernel - * probably doesn't have MTRR support. - */ - mro.mo_arg[0] = 0; - if (ioctl(devMemFd, MEMRANGE_GET, &mro)) - return NULL; - *nmr = mro.mo_arg[0]; - mrd = xnfalloc(*nmr * sizeof(struct mem_range_desc)); - mro.mo_arg[0] = *nmr; - mro.mo_desc = mrd; - if (ioctl(devMemFd, MEMRANGE_GET, &mro)) { - xfree(mrd); - return NULL; - } - return mrd; -} - -/* - * cleanMTRR removes any memory attribute that may be left by a previous - * X server. Normally there won't be any, but this takes care of the - * case where a server crashed without being able finish cleaning up. - */ - -static Bool -cleanMTRR() -{ - struct mem_range_desc *mrd; - struct mem_range_op mro; - int nmr, i; - - /* This shouldn't happen */ - if (devMemFd < 0) - return FALSE; - - if (!(mrd = getAllRanges(&nmr))) - return FALSE; - - for (i = 0; i < nmr; i++) { - if (strcmp(mrd[i].mr_owner, X_MTRR_ID) == 0 && - (mrd[i].mr_flags & MDF_ACTIVE)) { -#ifdef DEBUG - ErrorF("Clean for (0x%lx,0x%lx)\n", - (unsigned long)mrd[i].mr_base, - (unsigned long)mrd[i].mr_len); -#endif - if (mrd[i].mr_flags & MDF_FIXACTIVE) { - mro.mo_arg[0] = MEMRANGE_SET_UPDATE; - mrd[i].mr_flags = MDF_UNCACHEABLE; - } else { - mro.mo_arg[0] = MEMRANGE_SET_REMOVE; - } - mro.mo_desc = mrd + i; - ioctl(devMemFd, MEMRANGE_SET, &mro); - } - } -#ifdef DEBUG - sleep(10); -#endif - xfree(mrd); - return TRUE; -} - -typedef struct x_RangeRec { - struct mem_range_desc mrd; - Bool wasWC; - struct x_RangeRec * next; -} RangeRec, *RangePtr; - -static void -freeRangeList(RangePtr range) -{ - RangePtr rp; - - while (range) { - rp = range; - range = rp->next; - xfree(rp); - } -} - -static RangePtr -dupRangeList(RangePtr list) -{ - RangePtr new = NULL, rp, p; - - rp = list; - while (rp) { - p = xnfalloc(sizeof(RangeRec)); - *p = *rp; - p->next = new; - new = p; - rp = rp->next; - } - return new; -} - -static RangePtr -sortRangeList(RangePtr list) -{ - RangePtr rp1, rp2, copy, sorted = NULL, minp, prev, minprev; - unsigned long minBase; - - /* Sort by base address */ - rp1 = copy = dupRangeList(list); - while (rp1) { - minBase = rp1->mrd.mr_base; - minp = rp1; - minprev = NULL; - prev = rp1; - rp2 = rp1->next; - while (rp2) { - if (rp2->mrd.mr_base < minBase) { - minBase = rp2->mrd.mr_base; - minp = rp2; - minprev = prev; - } - prev = rp2; - rp2 = rp2->next; - } - if (minprev) { - minprev->next = minp->next; - rp1 = copy; - } else { - rp1 = minp->next; - } - minp->next = sorted; - sorted = minp; - } - return sorted; -} - -/* - * findRanges returns a list of ranges that overlap the specified range. - */ - -static void -findRanges(unsigned long base, unsigned long size, RangePtr *ucp, RangePtr *wcp) -{ - struct mem_range_desc *mrd; - int nmr, i; - RangePtr rp, *p; - - if (!(mrd = getAllRanges(&nmr))) - return; - - for (i = 0; i < nmr; i++) { - if ((mrd[i].mr_flags & MDF_ACTIVE) && - mrd[i].mr_base < base + size && - mrd[i].mr_base + mrd[i].mr_len > base) { - if (mrd[i].mr_flags & MDF_WRITECOMBINE) - p = wcp; - else if (mrd[i].mr_flags & MDF_UNCACHEABLE) - p = ucp; - else - continue; - rp = xnfalloc(sizeof(RangeRec)); - rp->mrd = mrd[i]; - rp->next = *p; - *p = rp; - } - } - xfree(mrd); -} - -/* - * This checks if the existing overlapping ranges fully cover the requested - * range. Is this overkill? - */ - -static Bool -fullCoverage(unsigned long base, unsigned long size, RangePtr overlap) -{ - RangePtr rp1, sorted = NULL; - unsigned long end; - - sorted = sortRangeList(overlap); - /* Look for gaps */ - rp1 = sorted; - end = base + size; - while (rp1) { - if (rp1->mrd.mr_base > base) { - freeRangeList(sorted); - return FALSE; - } else { - base = rp1->mrd.mr_base + rp1->mrd.mr_len; - } - if (base >= end) { - freeRangeList(sorted); - return TRUE; - } - rp1 = rp1->next; - } - freeRangeList(sorted); - return FALSE; -} - -static pointer -addWC(int screenNum, unsigned long base, unsigned long size, MessageType from) -{ - RangePtr uc = NULL, wc = NULL, retlist = NULL; - struct mem_range_desc mrd; - struct mem_range_op mro; - - findRanges(base, size, &uc, &wc); - - /* See of the full range is already WC */ - if (!uc && fullCoverage(base, size, wc)) { - xf86DrvMsg(screenNum, from, - "Write-combining range (0x%lx,0x%lx) was already set\n", - base, size); - return NULL; - } - - /* Otherwise, try to add the new range */ - mrd.mr_base = base; - mrd.mr_len = size; - strcpy(mrd.mr_owner, X_MTRR_ID); - mrd.mr_flags = MDF_WRITECOMBINE; - mro.mo_desc = &mrd; - mro.mo_arg[0] = MEMRANGE_SET_UPDATE; - if (ioctl(devMemFd, MEMRANGE_SET, &mro)) { - xf86DrvMsg(screenNum, X_WARNING, - "Failed to set write-combining range " - "(0x%lx,0x%lx)\n", base, size); - return NULL; - } else { - xf86DrvMsg(screenNum, from, - "Write-combining range (0x%lx,0x%lx)\n", base, size); - retlist = xnfalloc(sizeof(RangeRec)); - retlist->mrd = mrd; - retlist->wasWC = FALSE; - retlist->next = NULL; - return retlist; - } -} - -static pointer -delWC(int screenNum, unsigned long base, unsigned long size, MessageType from) -{ - RangePtr uc = NULL, wc = NULL, retlist = NULL; - struct mem_range_desc mrd; - struct mem_range_op mro; - - findRanges(base, size, &uc, &wc); - - /* - * See of the full range is already not WC, or if there is full - * coverage from UC ranges. - */ - if (!wc || fullCoverage(base, size, uc)) { - xf86DrvMsg(screenNum, from, - "Write-combining range (0x%lx,0x%lx) was already clear\n", - base, size); - return NULL; - } - - /* Otherwise, try to add the new range */ - mrd.mr_base = base; - mrd.mr_len = size; - strcpy(mrd.mr_owner, X_MTRR_ID); - mrd.mr_flags = MDF_UNCACHEABLE; - mro.mo_desc = &mrd; - mro.mo_arg[0] = MEMRANGE_SET_UPDATE; - if (ioctl(devMemFd, MEMRANGE_SET, &mro)) { - xf86DrvMsg(screenNum, X_WARNING, - "Failed to remove write-combining range " - "(0x%lx,0x%lx)\n", base, size); - /* XXX Should then remove all of the overlapping WC ranges */ - return NULL; - } else { - xf86DrvMsg(screenNum, from, - "Removed Write-combining range (0x%lx,0x%lx)\n", - base, size); - retlist = xnfalloc(sizeof(RangeRec)); - retlist->mrd = mrd; - retlist->wasWC = TRUE; - retlist->next = NULL; - return retlist; - } -} - -static pointer -setWC(int screenNum, unsigned long base, unsigned long size, Bool enable, - MessageType from) -{ - if (enable) - return addWC(screenNum, base, size, from); - else - return delWC(screenNum, base, size, from); -} - -static void -undoWC(int screenNum, pointer list) -{ - RangePtr rp; - struct mem_range_op mro; - Bool failed; - - rp = list; - while (rp) { -#ifdef DEBUG - ErrorF("Undo for (0x%lx,0x%lx), %d\n", - (unsigned long)rp->mrd.mr_base, - (unsigned long)rp->mrd.mr_len, rp->wasWC); -#endif - failed = FALSE; - if (rp->wasWC) { - mro.mo_arg[0] = MEMRANGE_SET_UPDATE; - rp->mrd.mr_flags = MDF_WRITECOMBINE; - strcpy(rp->mrd.mr_owner, "unknown"); - } else { - mro.mo_arg[0] = MEMRANGE_SET_REMOVE; - } - mro.mo_desc = &rp->mrd; - - if (ioctl(devMemFd, MEMRANGE_SET, &mro)) { - if (!rp->wasWC) { - mro.mo_arg[0] = MEMRANGE_SET_UPDATE; - rp->mrd.mr_flags = MDF_UNCACHEABLE; - strcpy(rp->mrd.mr_owner, "unknown"); - if (ioctl(devMemFd, MEMRANGE_SET, &mro)) - failed = TRUE; - } else - failed = TRUE; - } - if (failed) { - xf86DrvMsg(screenNum, X_WARNING, - "Failed to restore MTRR range (0x%lx,0x%lx)\n", - (unsigned long)rp->mrd.mr_base, - (unsigned long)rp->mrd.mr_len); - } - rp = rp->next; - } -} - -#endif /* HAS_MTRR_SUPPORT */ - - -#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) -static pointer -NetBSDsetWC(int screenNum, unsigned long base, unsigned long size, Bool enable, - MessageType from) -{ - struct mtrr *mtrrp; - int n; - - xf86DrvMsg(screenNum, X_WARNING, - "%s MTRR %lx - %lx\n", enable ? "set" : "remove", - base, (base + size)); - - mtrrp = xnfalloc(sizeof (struct mtrr)); - mtrrp->base = base; - mtrrp->len = size; - mtrrp->type = MTRR_TYPE_WC; - - /* - * MTRR_PRIVATE will make this MTRR get reset automatically - * if this process exits, so we have no need for an explicit - * cleanup operation when starting a new server. - */ - - if (enable) - mtrrp->flags = MTRR_VALID | MTRR_PRIVATE; - else - mtrrp->flags = 0; - n = 1; - - if (i386_set_mtrr(mtrrp, &n) < 0) { - xfree(mtrrp); - return NULL; - } - return mtrrp; -} - -static void -NetBSDundoWC(int screenNum, pointer list) -{ - struct mtrr *mtrrp = (struct mtrr *)list; - int n; - - if (mtrrp == NULL) - return; - n = 1; - mtrrp->flags &= ~MTRR_VALID; - i386_set_mtrr(mtrrp, &n); - xfree(mtrrp); -} -#endif +/* + * Copyright 1992 by Rich Murphey <Rich@Rice.edu> + * Copyright 1993 by David Wexelblat <dwex@goblin.org> + * + * 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 names of Rich Murphey and David Wexelblat + * not be used in advertising or publicity pertaining to distribution of + * the software without specific, written prior permission. Rich Murphey and + * David Wexelblat make no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * RICH MURPHEY AND DAVID WEXELBLAT DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RICH MURPHEY OR DAVID WEXELBLAT 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_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "xf86.h" +#include "xf86Priv.h" + +#include <errno.h> +#include <sys/mman.h> + +#ifdef HAS_MTRR_SUPPORT +#ifndef __NetBSD__ +#include <sys/types.h> +#include <sys/memrange.h> +#else +#include "memrange.h" +#endif +#define X_MTRR_ID "XFree86" +#endif + +#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) +#include <machine/mtrr.h> +#include <machine/sysarch.h> +#include <sys/queue.h> +#ifdef __x86_64__ +#define i386_set_mtrr x86_64_set_mtrr +#define i386_get_mtrr x86_64_get_mtrr +#define i386_iopl x86_64_iopl +#endif +#endif + +#include "xf86_OSlib.h" +#include "xf86OSpriv.h" + +#if defined(__NetBSD__) && !defined(MAP_FILE) +#define MAP_FLAGS MAP_SHARED +#else +#define MAP_FLAGS (MAP_FILE | MAP_SHARED) +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((caddr_t)-1) +#endif + +#ifdef __OpenBSD__ +#define SYSCTL_MSG "\tCheck that you have set 'machdep.allowaperture=1'\n"\ + "\tin /etc/sysctl.conf and reboot your machine\n" \ + "\trefer to xf86(4) for details" +#define SYSCTL_MSG2 \ + "Check that you have set 'machdep.allowaperture=2'\n" \ + "\tin /etc/sysctl.conf and reboot your machine\n" \ + "\trefer to xf86(4) for details" +#endif + +/***************************************************************************/ +/* Video Memory Mapping section */ +/***************************************************************************/ + +static Bool useDevMem = FALSE; +static int devMemFd = -1; + +#ifdef HAS_APERTURE_DRV +#define DEV_APERTURE "/dev/xf86" +#endif +#define DEV_MEM "/dev/mem" + +static pointer mapVidMem(int, unsigned long, unsigned long, int); +static void unmapVidMem(int, pointer, unsigned long); + +#ifdef HAS_MTRR_SUPPORT +static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType); +static void undoWC(int, pointer); +static Bool cleanMTRR(void); +#endif +#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) +static pointer NetBSDsetWC(int, unsigned long, unsigned long, Bool, + MessageType); +static void NetBSDundoWC(int, pointer); +#endif + +/* + * Check if /dev/mem can be mmap'd. If it can't print a warning when + * "warn" is TRUE. + */ +static void +checkDevMem(Bool warn) +{ + static Bool devMemChecked = FALSE; + int fd; + pointer base; + + if (devMemChecked) + return; + devMemChecked = TRUE; + + if ((fd = open(DEV_MEM, O_RDWR)) >= 0) + { + /* Try to map a page at the VGA address */ + base = mmap((caddr_t)0, 4096, PROT_READ | PROT_WRITE, + MAP_FLAGS, fd, (off_t)0xA0000); + + if (base != MAP_FAILED) + { + munmap((caddr_t)base, 4096); + devMemFd = fd; + useDevMem = TRUE; + return; + } else { + /* This should not happen */ + if (warn) + { + xf86Msg(X_WARNING, "checkDevMem: failed to mmap %s (%s)\n", + DEV_MEM, strerror(errno)); + } + useDevMem = FALSE; + return; + } + } +#ifndef HAS_APERTURE_DRV + if (warn) + { + xf86Msg(X_WARNING, "checkDevMem: failed to open %s (%s)\n", + DEV_MEM, strerror(errno)); + } + useDevMem = FALSE; + return; +#else + /* Failed to open /dev/mem, try the aperture driver */ + if ((fd = open(DEV_APERTURE, O_RDWR)) >= 0) + { + /* Try to map a page at the VGA address */ + base = mmap((caddr_t)0, 4096, PROT_READ | PROT_WRITE, + MAP_FLAGS, fd, (off_t)0xA0000); + + if (base != MAP_FAILED) + { + munmap((caddr_t)base, 4096); + devMemFd = fd; + useDevMem = TRUE; + xf86Msg(X_INFO, "checkDevMem: using aperture driver %s\n", + DEV_APERTURE); + return; + } else { + + if (warn) + { + xf86Msg(X_WARNING, "checkDevMem: failed to mmap %s (%s)\n", + DEV_APERTURE, strerror(errno)); + } + } + } else { + if (warn) + { +#ifndef __OpenBSD__ + xf86Msg(X_WARNING, "checkDevMem: failed to open %s and %s\n" + "\t(%s)\n", DEV_MEM, DEV_APERTURE, strerror(errno)); +#else /* __OpenBSD__ */ + xf86Msg(X_WARNING, "checkDevMem: failed to open %s and %s\n" + "\t(%s)\n%s", DEV_MEM, DEV_APERTURE, strerror(errno), + SYSCTL_MSG); +#endif /* __OpenBSD__ */ + } + } + + useDevMem = FALSE; + return; + +#endif +} + +void +xf86OSInitVidMem(VidMemInfoPtr pVidMem) +{ + checkDevMem(TRUE); + pVidMem->linearSupported = useDevMem; + pVidMem->mapMem = mapVidMem; + pVidMem->unmapMem = unmapVidMem; + +#if HAVE_PCI_SYSTEM_INIT_DEV_MEM + if (useDevMem) + pci_system_init_dev_mem(devMemFd); +#endif + +#ifdef HAS_MTRR_SUPPORT + if (useDevMem) { + if (cleanMTRR()) { + pVidMem->setWC = setWC; + pVidMem->undoWC = undoWC; + } + } +#endif +#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) + pVidMem->setWC = NetBSDsetWC; + pVidMem->undoWC = NetBSDundoWC; +#endif + pVidMem->initialised = TRUE; +} + +static pointer +mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags) +{ + pointer base; + + checkDevMem(FALSE); + + if (useDevMem) + { + if (devMemFd < 0) + { + FatalError("xf86MapVidMem: failed to open %s (%s)", + DEV_MEM, strerror(errno)); + } + base = mmap((caddr_t)0, Size, + (flags & VIDMEM_READONLY) ? + PROT_READ : (PROT_READ | PROT_WRITE), + MAP_FLAGS, devMemFd, (off_t)Base); + if (base == MAP_FAILED) + { + FatalError("%s: could not mmap %s [s=%lx,a=%lx] (%s)", + "xf86MapVidMem", DEV_MEM, Size, Base, + strerror(errno)); + } + return(base); + } + + /* else, mmap /dev/vga */ + if ((unsigned long)Base < 0xA0000 || (unsigned long)Base >= 0xC0000) + { + FatalError("%s: Address 0x%lx outside allowable range", + "xf86MapVidMem", Base); + } + base = mmap(0, Size, + (flags & VIDMEM_READONLY) ? + PROT_READ : (PROT_READ | PROT_WRITE), + MAP_FLAGS, xf86Info.screenFd, + (unsigned long)Base - 0xA0000 + ); + if (base == MAP_FAILED) + { + FatalError("xf86MapVidMem: Could not mmap /dev/vga (%s)", + strerror(errno)); + } + return(base); +} + +static void +unmapVidMem(int ScreenNum, pointer Base, unsigned long Size) +{ + munmap((caddr_t)Base, Size); +} + +/* + * Read BIOS via mmap()ing DEV_MEM + */ + +int +xf86ReadBIOS(unsigned long Base, unsigned long Offset, unsigned char *Buf, + int Len) +{ + unsigned char *ptr; + int psize; + int mlen; + + checkDevMem(TRUE); + if (devMemFd == -1) { + return(-1); + } + + psize = getpagesize(); + Offset += Base & (psize - 1); + Base &= ~(psize - 1); + mlen = (Offset + Len + psize - 1) & ~(psize - 1); + ptr = (unsigned char *)mmap((caddr_t)0, mlen, PROT_READ, + MAP_SHARED, devMemFd, (off_t)Base); + if ((long)ptr == -1) + { + xf86Msg(X_WARNING, + "xf86ReadBIOS: %s mmap[s=%x,a=%lx,o=%lx] failed (%s)\n", + DEV_MEM, Len, Base, Offset, strerror(errno)); +#ifdef __OpenBSD__ + if (Base < 0xa0000) { + xf86Msg(X_WARNING, SYSCTL_MSG2); + } +#endif + return(-1); + } +#ifdef DEBUG + ErrorF("xf86ReadBIOS: BIOS at 0x%08x has signature 0x%04x\n", + Base, ptr[0] | (ptr[1] << 8)); +#endif + (void)memcpy(Buf, (void *)(ptr + Offset), Len); + (void)munmap((caddr_t)ptr, mlen); +#ifdef DEBUG + xf86MsgVerb(X_INFO, 3, "xf86ReadBIOS(%x, %x, Buf, %x)" + "-> %02x %02x %02x %02x...\n", + Base, Offset, Len, Buf[0], Buf[1], Buf[2], Buf[3]); +#endif + return(Len); +} + +#ifdef USE_I386_IOPL +/***************************************************************************/ +/* I/O Permissions section */ +/***************************************************************************/ + +static Bool ExtendedEnabled = FALSE; + +Bool +xf86EnableIO() +{ + if (ExtendedEnabled) + return TRUE; + + if (i386_iopl(TRUE) < 0) + { +#ifndef __OpenBSD__ + xf86Msg(X_WARNING,"%s: Failed to set IOPL for extended I/O", + "xf86EnableIO"); +#else + xf86Msg(X_WARNING,"%s: Failed to set IOPL for extended I/O\n%s", + "xf86EnableIO", SYSCTL_MSG); +#endif + return FALSE; + } + ExtendedEnabled = TRUE; + + return TRUE; +} + +void +xf86DisableIO() +{ + if (!ExtendedEnabled) + return; + + i386_iopl(FALSE); + ExtendedEnabled = FALSE; + + return; +} + +#endif /* USE_I386_IOPL */ + +#ifdef USE_AMD64_IOPL +/***************************************************************************/ +/* I/O Permissions section */ +/***************************************************************************/ + +static Bool ExtendedEnabled = FALSE; + +Bool +xf86EnableIO() +{ + if (ExtendedEnabled) + return TRUE; + + if (amd64_iopl(TRUE) < 0) + { +#ifndef __OpenBSD__ + xf86Msg(X_WARNING,"%s: Failed to set IOPL for extended I/O", + "xf86EnableIO"); +#else + xf86Msg(X_WARNING,"%s: Failed to set IOPL for extended I/O\n%s", + "xf86EnableIO", SYSCTL_MSG); +#endif + return FALSE; + } + ExtendedEnabled = TRUE; + + return TRUE; +} + +void +xf86DisableIO() +{ + if (!ExtendedEnabled) + return; + + if (amd64_iopl(FALSE) == 0) { + ExtendedEnabled = FALSE; + } + /* Otherwise, the X server has revoqued its root uid, + and thus cannot give up IO privileges any more */ + + return; +} + +#endif /* USE_AMD64_IOPL */ + +#ifdef USE_DEV_IO +static int IoFd = -1; + +Bool +xf86EnableIO() +{ + if (IoFd >= 0) + return TRUE; + + if ((IoFd = open("/dev/io", O_RDWR)) == -1) + { + xf86Msg(X_WARNING,"xf86EnableIO: " + "Failed to open /dev/io for extended I/O"); + return FALSE; + } + return TRUE; +} + +void +xf86DisableIO() +{ + if (IoFd < 0) + return; + + close(IoFd); + IoFd = -1; + return; +} + +#endif + +#ifdef __NetBSD__ +/***************************************************************************/ +/* Set TV output mode */ +/***************************************************************************/ +void +xf86SetTVOut(int mode) +{ + switch (xf86Info.consType) + { +#ifdef PCCONS_SUPPORT + case PCCONS:{ + + if (ioctl (xf86Info.consoleFd, CONSOLE_X_TV_ON, &mode) < 0) + { + xf86Msg(X_WARNING, + "xf86SetTVOut: Could not set console to TV output, %s\n", + strerror(errno)); + } + } + break; +#endif /* PCCONS_SUPPORT */ + + default: + FatalError("Xf86SetTVOut: Unsupported console"); + break; + } + return; +} + +void +xf86SetRGBOut() +{ + switch (xf86Info.consType) + { +#ifdef PCCONS_SUPPORT + case PCCONS:{ + + if (ioctl (xf86Info.consoleFd, CONSOLE_X_TV_OFF, 0) < 0) + { + xf86Msg(X_WARNING, + "xf86SetTVOut: Could not set console to RGB output, %s\n", + strerror(errno)); + } + } + break; +#endif /* PCCONS_SUPPORT */ + + default: + FatalError("Xf86SetTVOut: Unsupported console"); + break; + } + return; +} +#endif + +#ifdef HAS_MTRR_SUPPORT +/* memory range (MTRR) support for FreeBSD */ + +/* + * This code is experimental. Some parts may be overkill, and other parts + * may be incomplete. + */ + +/* + * getAllRanges returns the full list of memory ranges with attributes set. + */ + +static struct mem_range_desc * +getAllRanges(int *nmr) +{ + struct mem_range_desc *mrd; + struct mem_range_op mro; + + /* + * Find how many ranges there are. If this fails, then the kernel + * probably doesn't have MTRR support. + */ + mro.mo_arg[0] = 0; + if (ioctl(devMemFd, MEMRANGE_GET, &mro)) + return NULL; + *nmr = mro.mo_arg[0]; + mrd = xnfalloc(*nmr * sizeof(struct mem_range_desc)); + mro.mo_arg[0] = *nmr; + mro.mo_desc = mrd; + if (ioctl(devMemFd, MEMRANGE_GET, &mro)) { + free(mrd); + return NULL; + } + return mrd; +} + +/* + * cleanMTRR removes any memory attribute that may be left by a previous + * X server. Normally there won't be any, but this takes care of the + * case where a server crashed without being able finish cleaning up. + */ + +static Bool +cleanMTRR() +{ + struct mem_range_desc *mrd; + struct mem_range_op mro; + int nmr, i; + + /* This shouldn't happen */ + if (devMemFd < 0) + return FALSE; + + if (!(mrd = getAllRanges(&nmr))) + return FALSE; + + for (i = 0; i < nmr; i++) { + if (strcmp(mrd[i].mr_owner, X_MTRR_ID) == 0 && + (mrd[i].mr_flags & MDF_ACTIVE)) { +#ifdef DEBUG + ErrorF("Clean for (0x%lx,0x%lx)\n", + (unsigned long)mrd[i].mr_base, + (unsigned long)mrd[i].mr_len); +#endif + if (mrd[i].mr_flags & MDF_FIXACTIVE) { + mro.mo_arg[0] = MEMRANGE_SET_UPDATE; + mrd[i].mr_flags = MDF_UNCACHEABLE; + } else { + mro.mo_arg[0] = MEMRANGE_SET_REMOVE; + } + mro.mo_desc = mrd + i; + ioctl(devMemFd, MEMRANGE_SET, &mro); + } + } +#ifdef DEBUG + sleep(10); +#endif + free(mrd); + return TRUE; +} + +typedef struct x_RangeRec { + struct mem_range_desc mrd; + Bool wasWC; + struct x_RangeRec * next; +} RangeRec, *RangePtr; + +static void +freeRangeList(RangePtr range) +{ + RangePtr rp; + + while (range) { + rp = range; + range = rp->next; + free(rp); + } +} + +static RangePtr +dupRangeList(RangePtr list) +{ + RangePtr new = NULL, rp, p; + + rp = list; + while (rp) { + p = xnfalloc(sizeof(RangeRec)); + *p = *rp; + p->next = new; + new = p; + rp = rp->next; + } + return new; +} + +static RangePtr +sortRangeList(RangePtr list) +{ + RangePtr rp1, rp2, copy, sorted = NULL, minp, prev, minprev; + unsigned long minBase; + + /* Sort by base address */ + rp1 = copy = dupRangeList(list); + while (rp1) { + minBase = rp1->mrd.mr_base; + minp = rp1; + minprev = NULL; + prev = rp1; + rp2 = rp1->next; + while (rp2) { + if (rp2->mrd.mr_base < minBase) { + minBase = rp2->mrd.mr_base; + minp = rp2; + minprev = prev; + } + prev = rp2; + rp2 = rp2->next; + } + if (minprev) { + minprev->next = minp->next; + rp1 = copy; + } else { + rp1 = minp->next; + } + minp->next = sorted; + sorted = minp; + } + return sorted; +} + +/* + * findRanges returns a list of ranges that overlap the specified range. + */ + +static void +findRanges(unsigned long base, unsigned long size, RangePtr *ucp, RangePtr *wcp) +{ + struct mem_range_desc *mrd; + int nmr, i; + RangePtr rp, *p; + + if (!(mrd = getAllRanges(&nmr))) + return; + + for (i = 0; i < nmr; i++) { + if ((mrd[i].mr_flags & MDF_ACTIVE) && + mrd[i].mr_base < base + size && + mrd[i].mr_base + mrd[i].mr_len > base) { + if (mrd[i].mr_flags & MDF_WRITECOMBINE) + p = wcp; + else if (mrd[i].mr_flags & MDF_UNCACHEABLE) + p = ucp; + else + continue; + rp = xnfalloc(sizeof(RangeRec)); + rp->mrd = mrd[i]; + rp->next = *p; + *p = rp; + } + } + free(mrd); +} + +/* + * This checks if the existing overlapping ranges fully cover the requested + * range. Is this overkill? + */ + +static Bool +fullCoverage(unsigned long base, unsigned long size, RangePtr overlap) +{ + RangePtr rp1, sorted = NULL; + unsigned long end; + + sorted = sortRangeList(overlap); + /* Look for gaps */ + rp1 = sorted; + end = base + size; + while (rp1) { + if (rp1->mrd.mr_base > base) { + freeRangeList(sorted); + return FALSE; + } else { + base = rp1->mrd.mr_base + rp1->mrd.mr_len; + } + if (base >= end) { + freeRangeList(sorted); + return TRUE; + } + rp1 = rp1->next; + } + freeRangeList(sorted); + return FALSE; +} + +static pointer +addWC(int screenNum, unsigned long base, unsigned long size, MessageType from) +{ + RangePtr uc = NULL, wc = NULL, retlist = NULL; + struct mem_range_desc mrd; + struct mem_range_op mro; + + findRanges(base, size, &uc, &wc); + + /* See of the full range is already WC */ + if (!uc && fullCoverage(base, size, wc)) { + xf86DrvMsg(screenNum, from, + "Write-combining range (0x%lx,0x%lx) was already set\n", + base, size); + return NULL; + } + + /* Otherwise, try to add the new range */ + mrd.mr_base = base; + mrd.mr_len = size; + strcpy(mrd.mr_owner, X_MTRR_ID); + mrd.mr_flags = MDF_WRITECOMBINE; + mro.mo_desc = &mrd; + mro.mo_arg[0] = MEMRANGE_SET_UPDATE; + if (ioctl(devMemFd, MEMRANGE_SET, &mro)) { + xf86DrvMsg(screenNum, X_WARNING, + "Failed to set write-combining range " + "(0x%lx,0x%lx)\n", base, size); + return NULL; + } else { + xf86DrvMsg(screenNum, from, + "Write-combining range (0x%lx,0x%lx)\n", base, size); + retlist = xnfalloc(sizeof(RangeRec)); + retlist->mrd = mrd; + retlist->wasWC = FALSE; + retlist->next = NULL; + return retlist; + } +} + +static pointer +delWC(int screenNum, unsigned long base, unsigned long size, MessageType from) +{ + RangePtr uc = NULL, wc = NULL, retlist = NULL; + struct mem_range_desc mrd; + struct mem_range_op mro; + + findRanges(base, size, &uc, &wc); + + /* + * See of the full range is already not WC, or if there is full + * coverage from UC ranges. + */ + if (!wc || fullCoverage(base, size, uc)) { + xf86DrvMsg(screenNum, from, + "Write-combining range (0x%lx,0x%lx) was already clear\n", + base, size); + return NULL; + } + + /* Otherwise, try to add the new range */ + mrd.mr_base = base; + mrd.mr_len = size; + strcpy(mrd.mr_owner, X_MTRR_ID); + mrd.mr_flags = MDF_UNCACHEABLE; + mro.mo_desc = &mrd; + mro.mo_arg[0] = MEMRANGE_SET_UPDATE; + if (ioctl(devMemFd, MEMRANGE_SET, &mro)) { + xf86DrvMsg(screenNum, X_WARNING, + "Failed to remove write-combining range " + "(0x%lx,0x%lx)\n", base, size); + /* XXX Should then remove all of the overlapping WC ranges */ + return NULL; + } else { + xf86DrvMsg(screenNum, from, + "Removed Write-combining range (0x%lx,0x%lx)\n", + base, size); + retlist = xnfalloc(sizeof(RangeRec)); + retlist->mrd = mrd; + retlist->wasWC = TRUE; + retlist->next = NULL; + return retlist; + } +} + +static pointer +setWC(int screenNum, unsigned long base, unsigned long size, Bool enable, + MessageType from) +{ + if (enable) + return addWC(screenNum, base, size, from); + else + return delWC(screenNum, base, size, from); +} + +static void +undoWC(int screenNum, pointer list) +{ + RangePtr rp; + struct mem_range_op mro; + Bool failed; + + rp = list; + while (rp) { +#ifdef DEBUG + ErrorF("Undo for (0x%lx,0x%lx), %d\n", + (unsigned long)rp->mrd.mr_base, + (unsigned long)rp->mrd.mr_len, rp->wasWC); +#endif + failed = FALSE; + if (rp->wasWC) { + mro.mo_arg[0] = MEMRANGE_SET_UPDATE; + rp->mrd.mr_flags = MDF_WRITECOMBINE; + strcpy(rp->mrd.mr_owner, "unknown"); + } else { + mro.mo_arg[0] = MEMRANGE_SET_REMOVE; + } + mro.mo_desc = &rp->mrd; + + if (ioctl(devMemFd, MEMRANGE_SET, &mro)) { + if (!rp->wasWC) { + mro.mo_arg[0] = MEMRANGE_SET_UPDATE; + rp->mrd.mr_flags = MDF_UNCACHEABLE; + strcpy(rp->mrd.mr_owner, "unknown"); + if (ioctl(devMemFd, MEMRANGE_SET, &mro)) + failed = TRUE; + } else + failed = TRUE; + } + if (failed) { + xf86DrvMsg(screenNum, X_WARNING, + "Failed to restore MTRR range (0x%lx,0x%lx)\n", + (unsigned long)rp->mrd.mr_base, + (unsigned long)rp->mrd.mr_len); + } + rp = rp->next; + } +} + +#endif /* HAS_MTRR_SUPPORT */ + + +#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) +static pointer +NetBSDsetWC(int screenNum, unsigned long base, unsigned long size, Bool enable, + MessageType from) +{ + struct mtrr *mtrrp; + int n; + + xf86DrvMsg(screenNum, X_WARNING, + "%s MTRR %lx - %lx\n", enable ? "set" : "remove", + base, (base + size)); + + mtrrp = xnfalloc(sizeof (struct mtrr)); + mtrrp->base = base; + mtrrp->len = size; + mtrrp->type = MTRR_TYPE_WC; + + /* + * MTRR_PRIVATE will make this MTRR get reset automatically + * if this process exits, so we have no need for an explicit + * cleanup operation when starting a new server. + */ + + if (enable) + mtrrp->flags = MTRR_VALID | MTRR_PRIVATE; + else + mtrrp->flags = 0; + n = 1; + + if (i386_set_mtrr(mtrrp, &n) < 0) { + free(mtrrp); + return NULL; + } + return mtrrp; +} + +static void +NetBSDundoWC(int screenNum, pointer list) +{ + struct mtrr *mtrrp = (struct mtrr *)list; + int n; + + if (mtrrp == NULL) + return; + n = 1; + mtrrp->flags &= ~MTRR_VALID; + i386_set_mtrr(mtrrp, &n); + free(mtrrp); +} +#endif diff --git a/xorg-server/hw/xfree86/os-support/bus/Sbus.c b/xorg-server/hw/xfree86/os-support/bus/Sbus.c index 0b6205f0b..4560ef016 100644 --- a/xorg-server/hw/xfree86/os-support/bus/Sbus.c +++ b/xorg-server/hw/xfree86/os-support/bus/Sbus.c @@ -1,690 +1,690 @@ -/* - * SBUS and OpenPROM access functions. - * - * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com) - * - * 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 - * JAKUB JELINEK 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. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <fcntl.h> -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#ifdef sun -#include <sys/utsname.h> -#endif -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" - -#include "xf86sbusBus.h" -#include "xf86Sbus.h" - -int promRootNode; - -static int promFd = -1; -static int promCurrentNode; -static int promOpenCount = 0; -static int promP1275 = -1; -#define MAX_PROP 128 -#define MAX_VAL (4096-128-4) -static struct openpromio *promOpio; - -sbusDevicePtr *xf86SbusInfo = NULL; - -struct sbus_devtable sbusDeviceTable[] = { - { SBUS_DEVICE_BW2, FBTYPE_SUN2BW, "bwtwo", "sunbw2", "Sun Monochrome (bwtwo)" }, - { SBUS_DEVICE_CG2, FBTYPE_SUN2COLOR, "cgtwo", NULL, "Sun Color2 (cgtwo)" }, - { SBUS_DEVICE_CG3, FBTYPE_SUN3COLOR, "cgthree", "suncg3", "Sun Color3 (cgthree)" }, - { SBUS_DEVICE_CG4, FBTYPE_SUN4COLOR, "cgfour", NULL, "Sun Color4 (cgfour)" }, - { SBUS_DEVICE_CG6, FBTYPE_SUNFAST_COLOR, "cgsix", "suncg6", "Sun GX" }, - { SBUS_DEVICE_CG8, FBTYPE_MEMCOLOR, "cgeight", NULL, "Sun CG8/RasterOps" }, - { SBUS_DEVICE_CG12, FBTYPE_SUNGP3, "cgtwelve", NULL, "Sun GS (cgtwelve)" }, - { SBUS_DEVICE_CG14, FBTYPE_MDICOLOR, "cgfourteen", "suncg14", "Sun SX" }, - { SBUS_DEVICE_GT, FBTYPE_SUNGT, "gt", NULL, "Sun Graphics Tower" }, - { SBUS_DEVICE_MGX, -1, "mgx", NULL, "Quantum 3D MGXplus" }, - { SBUS_DEVICE_LEO, FBTYPE_SUNLEO, "leo", "sunleo", "Sun ZX or Turbo ZX" }, - { SBUS_DEVICE_TCX, FBTYPE_TCXCOLOR, "tcx", "suntcx", "Sun TCX" }, - { SBUS_DEVICE_FFB, FBTYPE_CREATOR, "ffb", "sunffb", "Sun FFB" }, - { SBUS_DEVICE_FFB, FBTYPE_CREATOR, "afb", "sunffb", "Sun Elite3D" }, - { 0, 0, NULL } -}; - -int -promGetSibling(int node) -{ - promOpio->oprom_size = sizeof(int); - - if (node == -1) return 0; - *(int *)promOpio->oprom_array = node; - if (ioctl(promFd, OPROMNEXT, promOpio) < 0) - return 0; - promCurrentNode = *(int *)promOpio->oprom_array; - return *(int *)promOpio->oprom_array; -} - -int -promGetChild(int node) -{ - promOpio->oprom_size = sizeof(int); - - if (!node || node == -1) return 0; - *(int *)promOpio->oprom_array = node; - if (ioctl(promFd, OPROMCHILD, promOpio) < 0) - return 0; - promCurrentNode = *(int *)promOpio->oprom_array; - return *(int *)promOpio->oprom_array; -} - -char * -promGetProperty(const char *prop, int *lenp) -{ - promOpio->oprom_size = MAX_VAL; - - strcpy(promOpio->oprom_array, prop); - if (ioctl(promFd, OPROMGETPROP, promOpio) < 0) - return 0; - if (lenp) *lenp = promOpio->oprom_size; - return promOpio->oprom_array; -} - -int -promGetBool(const char *prop) -{ - promOpio->oprom_size = 0; - - *(int *)promOpio->oprom_array = 0; - for (;;) { - promOpio->oprom_size = MAX_PROP; - if (ioctl(promFd, OPROMNXTPROP, promOpio) < 0) - return 0; - if (!promOpio->oprom_size) - return 0; - if (!strcmp(promOpio->oprom_array, prop)) - return 1; - } -} - -#define PROM_NODE_SIBLING 0x01 -#define PROM_NODE_PREF 0x02 -#define PROM_NODE_SBUS 0x04 -#define PROM_NODE_EBUS 0x08 -#define PROM_NODE_PCI 0x10 - -static int -promSetNode(sbusPromNodePtr pnode) -{ - int node; - - if (!pnode->node || pnode->node == -1) - return -1; - if (pnode->cookie[0] & PROM_NODE_SIBLING) - node = promGetSibling(pnode->cookie[1]); - else - node = promGetChild(pnode->cookie[1]); - if (pnode->node != node) - return -1; - return 0; -} - -static void -promIsP1275(void) -{ -#ifdef linux - FILE *f; - char buffer[1024]; - - if (promP1275 != -1) - return; - promP1275 = 0; - f = fopen("/proc/cpuinfo","r"); - if (!f) return; - while (fgets(buffer, 1024, f) != NULL) - if (!strncmp (buffer, "type", 4) && strstr (buffer, "sun4u")) { - promP1275 = 1; - break; - } - fclose(f); -#elif defined(sun) - struct utsname buffer; - - if ((uname(&buffer) >= 0) && !strcmp(buffer.machine, "sun4u")) - promP1275 = TRUE; - else - promP1275 = FALSE; -#elif defined(__FreeBSD__) - promP1275 = TRUE; -#else -#error Missing promIsP1275() function for this OS -#endif -} - -void -sparcPromClose(void) -{ - if (promOpenCount > 1) { - promOpenCount--; - return; - } - if (promFd != -1) { - close(promFd); - promFd = -1; - } - if (promOpio) { - xfree(promOpio); - promOpio = NULL; - } - promOpenCount = 0; -} - -int -sparcPromInit(void) -{ - if (promOpenCount) { - promOpenCount++; - return 0; - } - promFd = open("/dev/openprom", O_RDONLY, 0); - if (promFd == -1) - return -1; - promOpio = (struct openpromio *)xalloc(4096); - if (!promOpio) { - sparcPromClose(); - return -1; - } - promRootNode = promGetSibling(0); - if (!promRootNode) { - sparcPromClose(); - return -1; - } - promIsP1275(); - promOpenCount++; - - return 0; -} - -char * -sparcPromGetProperty(sbusPromNodePtr pnode, const char *prop, int *lenp) -{ - if (promSetNode(pnode)) - return NULL; - return promGetProperty(prop, lenp); -} - -int -sparcPromGetBool(sbusPromNodePtr pnode, const char *prop) -{ - if (promSetNode(pnode)) - return 0; - return promGetBool(prop); -} - -static char * -promWalkGetDriverName(int node, int oldnode) -{ - int nextnode; - int len; - char *prop; - int devId, i; - - prop = promGetProperty("device_type", &len); - if (prop && (len > 0)) do { - if (!strcmp(prop, "display")) { - prop = promGetProperty("name", &len); - if (!prop || len <= 0) - break; - while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',') - prop++; - for (i = 0; sbusDeviceTable[i].devId; i++) - if (!strcmp(prop, sbusDeviceTable[i].promName)) - break; - devId = sbusDeviceTable[i].devId; - if (!devId) - break; - if (sbusDeviceTable[i].driverName) - return sbusDeviceTable[i].driverName; - } - } while (0); - - nextnode = promGetChild(node); - if (nextnode) { - char *name; - name = promWalkGetDriverName(nextnode, node); - if (name) - return name; - } - - nextnode = promGetSibling(node); - if (nextnode) - return promWalkGetDriverName(nextnode, node); - return NULL; -} - -char * -sparcDriverName(void) -{ - char *name; - - if (sparcPromInit() < 0) - return NULL; - promGetSibling(0); - name = promWalkGetDriverName(promRootNode, 0); - sparcPromClose(); - return name; -} - -static void -promWalkAssignNodes(int node, int oldnode, int flags, sbusDevicePtr *devicePtrs) -{ - int nextnode; - int len, sbus = flags & PROM_NODE_SBUS; - char *prop; - int devId, i, j; - sbusPromNode pNode, pNode2; - - prop = promGetProperty("device_type", &len); - if (prop && (len > 0)) do { - if (!strcmp(prop, "display")) { - prop = promGetProperty("name", &len); - if (!prop || len <= 0) - break; - while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',') - prop++; - for (i = 0; sbusDeviceTable[i].devId; i++) - if (!strcmp(prop, sbusDeviceTable[i].promName)) - break; - devId = sbusDeviceTable[i].devId; - if (!devId) - break; - if (!sbus) { - if (devId == SBUS_DEVICE_FFB) { - /* - * All /SUNW,ffb outside of SBUS tree come before all - * /SUNW,afb outside of SBUS tree in Linux. - */ - if (!strcmp(prop, "afb")) - flags |= PROM_NODE_PREF; - } else if (devId != SBUS_DEVICE_CG14) - break; - } - for (i = 0; i < 32; i++) { - if (!devicePtrs[i] || devicePtrs[i]->devId != devId) - continue; - if (devicePtrs[i]->node.node) { - if ((devicePtrs[i]->node.cookie[0] & ~PROM_NODE_SIBLING) <= - (flags & ~PROM_NODE_SIBLING)) - continue; - for (j = i + 1, pNode = devicePtrs[i]->node; j < 32; j++) { - if (!devicePtrs[j] || devicePtrs[j]->devId != devId) - continue; - pNode2 = devicePtrs[j]->node; - devicePtrs[j]->node = pNode; - pNode = pNode2; - } - } - devicePtrs[i]->node.node = node; - devicePtrs[i]->node.cookie[0] = flags; - devicePtrs[i]->node.cookie[1] = oldnode; - break; - } - break; - } - } while (0); - - prop = promGetProperty("name", &len); - if (prop && len > 0) { - if (!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) - sbus = PROM_NODE_SBUS; - } - - nextnode = promGetChild(node); - if (nextnode) - promWalkAssignNodes(nextnode, node, sbus, devicePtrs); - - nextnode = promGetSibling(node); - if (nextnode) - promWalkAssignNodes(nextnode, node, PROM_NODE_SIBLING | sbus, devicePtrs); -} - -void -sparcPromAssignNodes(void) -{ - sbusDevicePtr psdp, *psdpp; - int n, holes = 0, i, j; - FILE *f; - sbusDevicePtr devicePtrs[32]; - - memset(devicePtrs, 0, sizeof(devicePtrs)); - for (psdpp = xf86SbusInfo, n = 0; (psdp = *psdpp); psdpp++, n++) { - if (psdp->fbNum != n) - holes = 1; - devicePtrs[psdp->fbNum] = psdp; - } - if (holes && (f = fopen("/proc/fb", "r")) != NULL) { - /* We could not open one of fb devices, check /proc/fb to see what - * were the types of the cards missed. */ - char buffer[64]; - int fbNum, devId; - static struct { - int devId; - char *prefix; - } procFbPrefixes[] = { - { SBUS_DEVICE_BW2, "BWtwo" }, - { SBUS_DEVICE_CG14, "CGfourteen" }, - { SBUS_DEVICE_CG6, "CGsix" }, - { SBUS_DEVICE_CG3, "CGthree" }, - { SBUS_DEVICE_FFB, "Creator" }, - { SBUS_DEVICE_FFB, "Elite 3D" }, - { SBUS_DEVICE_LEO, "Leo" }, - { SBUS_DEVICE_TCX, "TCX" }, - { 0, NULL }, - }; - - while (fscanf(f, "%d %63s\n", &fbNum, buffer) == 2) { - for (i = 0; procFbPrefixes[i].devId; i++) - if (! strncmp(procFbPrefixes[i].prefix, buffer, - strlen(procFbPrefixes[i].prefix))) - break; - devId = procFbPrefixes[i].devId; - if (! devId) continue; - if (devicePtrs[fbNum]) { - if (devicePtrs[fbNum]->devId != devId) - xf86ErrorF("Inconsistent /proc/fb with FBIOGATTR\n"); - } else if (!devicePtrs[fbNum]) { - devicePtrs[fbNum] = psdp = xnfcalloc(sizeof (sbusDevice), 1); - psdp->devId = devId; - psdp->fbNum = fbNum; - psdp->fd = -2; - } - } - fclose(f); - } - promGetSibling(0); - promWalkAssignNodes(promRootNode, 0, PROM_NODE_PREF, devicePtrs); - for (i = 0, j = 0; i < 32; i++) - if (devicePtrs[i] && devicePtrs[i]->fbNum == -1) - j++; - xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (n + j + 1)); - for (i = 0, psdpp = xf86SbusInfo; i < 32; i++) - if (devicePtrs[i]) { - if (devicePtrs[i]->fbNum == -1) { - memmove(psdpp + 1, psdpp, sizeof(psdpp) * (n + 1)); - *psdpp = devicePtrs[i]; - } else - n--; - } -} - -static char * -promGetReg(int type) -{ - char *prop; - int len; - static char regstr[40]; - - regstr[0] = 0; - prop = promGetProperty("reg", &len); - if (prop && len >= 4) { - unsigned int *reg = (unsigned int *)prop; - if (!promP1275 || (type == PROM_NODE_SBUS) || (type == PROM_NODE_EBUS)) - sprintf (regstr, "@%x,%x", reg[0], reg[1]); - else if (type == PROM_NODE_PCI) { - if ((reg[0] >> 8) & 7) - sprintf (regstr, "@%x,%x", (reg[0] >> 11) & 0x1f, (reg[0] >> 8) & 7); - else - sprintf (regstr, "@%x", (reg[0] >> 11) & 0x1f); - } else if (len == 4) - sprintf (regstr, "@%x", reg[0]); - else { - unsigned int regs[2]; - - /* Things get more complicated on UPA. If upa-portid exists, - then address is @upa-portid,second-int-in-reg, otherwise - it is @first-int-in-reg/16,second-int-in-reg (well, probably - upa-portid always exists, but just to be safe). */ - memcpy (regs, reg, sizeof(regs)); - prop = promGetProperty("upa-portid", &len); - if (prop && len == 4) { - reg = (unsigned int *)prop; - sprintf (regstr, "@%x,%x", reg[0], regs[1]); - } else - sprintf (regstr, "@%x,%x", regs[0] >> 4, regs[1]); - } - } - return regstr; -} - -static int -promWalkNode2Pathname(char *path, int parent, int node, int searchNode, int type) -{ - int nextnode; - int len, ntype = type; - char *prop, *p; - - prop = promGetProperty("name", &len); - *path = '/'; - if (!prop || len <= 0) - return 0; - if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type) - ntype = PROM_NODE_SBUS; - else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI) - ntype = PROM_NODE_EBUS; - else if (!strcmp(prop, "pci") && !type) - ntype = PROM_NODE_PCI; - strcpy (path + 1, prop); - p = promGetReg(type); - if (*p) - strcat (path, p); - if (node == searchNode) - return 1; - nextnode = promGetChild(node); - if (nextnode && - promWalkNode2Pathname(strchr(path, 0), node, nextnode, searchNode, ntype)) - return 1; - nextnode = promGetSibling(node); - if (nextnode && - promWalkNode2Pathname(path, parent, nextnode, searchNode, type)) - return 1; - return 0; -} - -char * -sparcPromNode2Pathname(sbusPromNodePtr pnode) -{ - char *ret; - - if (!pnode->node) return NULL; - ret = xalloc(4096); - if (!ret) return NULL; - if (promWalkNode2Pathname(ret, promRootNode, promGetChild(promRootNode), pnode->node, 0)) - return ret; - xfree(ret); - return NULL; -} - -static int -promWalkPathname2Node(char *name, char *regstr, int parent, int type) -{ - int len, node, ret; - char *prop, *p; - - for (;;) { - prop = promGetProperty("name", &len); - if (!prop || len <= 0) - return 0; - if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type) - type = PROM_NODE_SBUS; - else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI) - type = PROM_NODE_EBUS; - else if (!strcmp(prop, "pci") && !type) - type = PROM_NODE_PCI; - for (node = promGetChild(parent); node; node = promGetSibling(node)) { - prop = promGetProperty("name", &len); - if (!prop || len <= 0) - continue; - if (*name && strcmp(name, prop)) - continue; - if (*regstr) { - p = promGetReg(type); - if (! *p || strcmp(p + 1, regstr)) - continue; - } - break; - } - if (!node) { - for (node = promGetChild(parent); node; node = promGetSibling(node)) { - ret = promWalkPathname2Node(name, regstr, node, type); - if (ret) return ret; - } - return 0; - } - name = strchr(regstr, 0) + 1; - if (! *name) - return node; - p = strchr(name, '/'); - if (p) - *p = 0; - else - p = strchr(name, 0); - regstr = strchr(name, '@'); - if (regstr) - *regstr++ = 0; - else - regstr = p; - if (name == regstr) - return 0; - parent = node; - } -} - -int -sparcPromPathname2Node(const char *pathName) -{ - int i; - char *name, *regstr, *p; - - i = strlen(pathName); - name = xalloc(i + 2); - if (! name) return 0; - strcpy (name, pathName); - name [i + 1] = 0; - if (name[0] != '/') - return 0; - p = strchr(name + 1, '/'); - if (p) - *p = 0; - else - p = strchr(name, 0); - regstr = strchr(name, '@'); - if (regstr) - *regstr++ = 0; - else - regstr = p; - if (name + 1 == regstr) - return 0; - promGetSibling(0); - i = promWalkPathname2Node(name + 1, regstr, promRootNode, 0); - xfree(name); - return i; -} - -pointer -xf86MapSbusMem(sbusDevicePtr psdp, unsigned long offset, unsigned long size) -{ - pointer ret; - unsigned long pagemask = getpagesize() - 1; - unsigned long off = offset & ~pagemask; - unsigned long len = ((offset + size + pagemask) & ~pagemask) - off; - - if (psdp->fd == -1) { - psdp->fd = open(psdp->device, O_RDWR); - if (psdp->fd == -1) - return NULL; - } else if (psdp->fd < 0) - return NULL; - - ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, - psdp->fd, off); - if (ret == (pointer) -1) { - ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, - psdp->fd, off); - } - if (ret == (pointer) -1) - return NULL; - - return (char *)ret + (offset - off); -} - -void -xf86UnmapSbusMem(sbusDevicePtr psdp, pointer addr, unsigned long size) -{ - unsigned long mask = getpagesize() - 1; - unsigned long base = (unsigned long)addr & ~mask; - unsigned long len = (((unsigned long)addr + size + mask) & ~mask) - base; - - munmap ((pointer)base, len); -} - -/* Tell OS that we are driving the HW cursor ourselves. */ -void -xf86SbusHideOsHwCursor(sbusDevicePtr psdp) -{ - struct fbcursor fbcursor; - unsigned char zeros[8]; - - memset(&fbcursor, 0, sizeof(fbcursor)); - memset(&zeros, 0, sizeof(zeros)); - fbcursor.cmap.count = 2; - fbcursor.cmap.red = zeros; - fbcursor.cmap.green = zeros; - fbcursor.cmap.blue = zeros; - fbcursor.image = (char *)zeros; - fbcursor.mask = (char *)zeros; - fbcursor.size.x = 32; - fbcursor.size.y = 1; - fbcursor.set = FB_CUR_SETALL; - ioctl(psdp->fd, FBIOSCURSOR, &fbcursor); -} - -/* Set HW cursor colormap. */ -void -xf86SbusSetOsHwCursorCmap(sbusDevicePtr psdp, int bg, int fg) -{ - struct fbcursor fbcursor; - unsigned char red[2], green[2], blue[2]; - - memset(&fbcursor, 0, sizeof(fbcursor)); - red[0] = bg >> 16; - green[0] = bg >> 8; - blue[0] = bg; - red[1] = fg >> 16; - green[1] = fg >> 8; - blue[1] = fg; - fbcursor.cmap.count = 2; - fbcursor.cmap.red = red; - fbcursor.cmap.green = green; - fbcursor.cmap.blue = blue; - fbcursor.set = FB_CUR_SETCMAP; - ioctl(psdp->fd, FBIOSCURSOR, &fbcursor); -} +/* + * SBUS and OpenPROM access functions. + * + * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com) + * + * 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 + * JAKUB JELINEK 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#ifdef sun +#include <sys/utsname.h> +#endif +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" + +#include "xf86sbusBus.h" +#include "xf86Sbus.h" + +int promRootNode; + +static int promFd = -1; +static int promCurrentNode; +static int promOpenCount = 0; +static int promP1275 = -1; +#define MAX_PROP 128 +#define MAX_VAL (4096-128-4) +static struct openpromio *promOpio; + +sbusDevicePtr *xf86SbusInfo = NULL; + +struct sbus_devtable sbusDeviceTable[] = { + { SBUS_DEVICE_BW2, FBTYPE_SUN2BW, "bwtwo", "sunbw2", "Sun Monochrome (bwtwo)" }, + { SBUS_DEVICE_CG2, FBTYPE_SUN2COLOR, "cgtwo", NULL, "Sun Color2 (cgtwo)" }, + { SBUS_DEVICE_CG3, FBTYPE_SUN3COLOR, "cgthree", "suncg3", "Sun Color3 (cgthree)" }, + { SBUS_DEVICE_CG4, FBTYPE_SUN4COLOR, "cgfour", NULL, "Sun Color4 (cgfour)" }, + { SBUS_DEVICE_CG6, FBTYPE_SUNFAST_COLOR, "cgsix", "suncg6", "Sun GX" }, + { SBUS_DEVICE_CG8, FBTYPE_MEMCOLOR, "cgeight", NULL, "Sun CG8/RasterOps" }, + { SBUS_DEVICE_CG12, FBTYPE_SUNGP3, "cgtwelve", NULL, "Sun GS (cgtwelve)" }, + { SBUS_DEVICE_CG14, FBTYPE_MDICOLOR, "cgfourteen", "suncg14", "Sun SX" }, + { SBUS_DEVICE_GT, FBTYPE_SUNGT, "gt", NULL, "Sun Graphics Tower" }, + { SBUS_DEVICE_MGX, -1, "mgx", NULL, "Quantum 3D MGXplus" }, + { SBUS_DEVICE_LEO, FBTYPE_SUNLEO, "leo", "sunleo", "Sun ZX or Turbo ZX" }, + { SBUS_DEVICE_TCX, FBTYPE_TCXCOLOR, "tcx", "suntcx", "Sun TCX" }, + { SBUS_DEVICE_FFB, FBTYPE_CREATOR, "ffb", "sunffb", "Sun FFB" }, + { SBUS_DEVICE_FFB, FBTYPE_CREATOR, "afb", "sunffb", "Sun Elite3D" }, + { 0, 0, NULL } +}; + +int +promGetSibling(int node) +{ + promOpio->oprom_size = sizeof(int); + + if (node == -1) return 0; + *(int *)promOpio->oprom_array = node; + if (ioctl(promFd, OPROMNEXT, promOpio) < 0) + return 0; + promCurrentNode = *(int *)promOpio->oprom_array; + return *(int *)promOpio->oprom_array; +} + +int +promGetChild(int node) +{ + promOpio->oprom_size = sizeof(int); + + if (!node || node == -1) return 0; + *(int *)promOpio->oprom_array = node; + if (ioctl(promFd, OPROMCHILD, promOpio) < 0) + return 0; + promCurrentNode = *(int *)promOpio->oprom_array; + return *(int *)promOpio->oprom_array; +} + +char * +promGetProperty(const char *prop, int *lenp) +{ + promOpio->oprom_size = MAX_VAL; + + strcpy(promOpio->oprom_array, prop); + if (ioctl(promFd, OPROMGETPROP, promOpio) < 0) + return 0; + if (lenp) *lenp = promOpio->oprom_size; + return promOpio->oprom_array; +} + +int +promGetBool(const char *prop) +{ + promOpio->oprom_size = 0; + + *(int *)promOpio->oprom_array = 0; + for (;;) { + promOpio->oprom_size = MAX_PROP; + if (ioctl(promFd, OPROMNXTPROP, promOpio) < 0) + return 0; + if (!promOpio->oprom_size) + return 0; + if (!strcmp(promOpio->oprom_array, prop)) + return 1; + } +} + +#define PROM_NODE_SIBLING 0x01 +#define PROM_NODE_PREF 0x02 +#define PROM_NODE_SBUS 0x04 +#define PROM_NODE_EBUS 0x08 +#define PROM_NODE_PCI 0x10 + +static int +promSetNode(sbusPromNodePtr pnode) +{ + int node; + + if (!pnode->node || pnode->node == -1) + return -1; + if (pnode->cookie[0] & PROM_NODE_SIBLING) + node = promGetSibling(pnode->cookie[1]); + else + node = promGetChild(pnode->cookie[1]); + if (pnode->node != node) + return -1; + return 0; +} + +static void +promIsP1275(void) +{ +#ifdef linux + FILE *f; + char buffer[1024]; + + if (promP1275 != -1) + return; + promP1275 = 0; + f = fopen("/proc/cpuinfo","r"); + if (!f) return; + while (fgets(buffer, 1024, f) != NULL) + if (!strncmp (buffer, "type", 4) && strstr (buffer, "sun4u")) { + promP1275 = 1; + break; + } + fclose(f); +#elif defined(sun) + struct utsname buffer; + + if ((uname(&buffer) >= 0) && !strcmp(buffer.machine, "sun4u")) + promP1275 = TRUE; + else + promP1275 = FALSE; +#elif defined(__FreeBSD__) + promP1275 = TRUE; +#else +#error Missing promIsP1275() function for this OS +#endif +} + +void +sparcPromClose(void) +{ + if (promOpenCount > 1) { + promOpenCount--; + return; + } + if (promFd != -1) { + close(promFd); + promFd = -1; + } + if (promOpio) { + free(promOpio); + promOpio = NULL; + } + promOpenCount = 0; +} + +int +sparcPromInit(void) +{ + if (promOpenCount) { + promOpenCount++; + return 0; + } + promFd = open("/dev/openprom", O_RDONLY, 0); + if (promFd == -1) + return -1; + promOpio = (struct openpromio *)malloc(4096); + if (!promOpio) { + sparcPromClose(); + return -1; + } + promRootNode = promGetSibling(0); + if (!promRootNode) { + sparcPromClose(); + return -1; + } + promIsP1275(); + promOpenCount++; + + return 0; +} + +char * +sparcPromGetProperty(sbusPromNodePtr pnode, const char *prop, int *lenp) +{ + if (promSetNode(pnode)) + return NULL; + return promGetProperty(prop, lenp); +} + +int +sparcPromGetBool(sbusPromNodePtr pnode, const char *prop) +{ + if (promSetNode(pnode)) + return 0; + return promGetBool(prop); +} + +static char * +promWalkGetDriverName(int node, int oldnode) +{ + int nextnode; + int len; + char *prop; + int devId, i; + + prop = promGetProperty("device_type", &len); + if (prop && (len > 0)) do { + if (!strcmp(prop, "display")) { + prop = promGetProperty("name", &len); + if (!prop || len <= 0) + break; + while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',') + prop++; + for (i = 0; sbusDeviceTable[i].devId; i++) + if (!strcmp(prop, sbusDeviceTable[i].promName)) + break; + devId = sbusDeviceTable[i].devId; + if (!devId) + break; + if (sbusDeviceTable[i].driverName) + return sbusDeviceTable[i].driverName; + } + } while (0); + + nextnode = promGetChild(node); + if (nextnode) { + char *name; + name = promWalkGetDriverName(nextnode, node); + if (name) + return name; + } + + nextnode = promGetSibling(node); + if (nextnode) + return promWalkGetDriverName(nextnode, node); + return NULL; +} + +char * +sparcDriverName(void) +{ + char *name; + + if (sparcPromInit() < 0) + return NULL; + promGetSibling(0); + name = promWalkGetDriverName(promRootNode, 0); + sparcPromClose(); + return name; +} + +static void +promWalkAssignNodes(int node, int oldnode, int flags, sbusDevicePtr *devicePtrs) +{ + int nextnode; + int len, sbus = flags & PROM_NODE_SBUS; + char *prop; + int devId, i, j; + sbusPromNode pNode, pNode2; + + prop = promGetProperty("device_type", &len); + if (prop && (len > 0)) do { + if (!strcmp(prop, "display")) { + prop = promGetProperty("name", &len); + if (!prop || len <= 0) + break; + while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',') + prop++; + for (i = 0; sbusDeviceTable[i].devId; i++) + if (!strcmp(prop, sbusDeviceTable[i].promName)) + break; + devId = sbusDeviceTable[i].devId; + if (!devId) + break; + if (!sbus) { + if (devId == SBUS_DEVICE_FFB) { + /* + * All /SUNW,ffb outside of SBUS tree come before all + * /SUNW,afb outside of SBUS tree in Linux. + */ + if (!strcmp(prop, "afb")) + flags |= PROM_NODE_PREF; + } else if (devId != SBUS_DEVICE_CG14) + break; + } + for (i = 0; i < 32; i++) { + if (!devicePtrs[i] || devicePtrs[i]->devId != devId) + continue; + if (devicePtrs[i]->node.node) { + if ((devicePtrs[i]->node.cookie[0] & ~PROM_NODE_SIBLING) <= + (flags & ~PROM_NODE_SIBLING)) + continue; + for (j = i + 1, pNode = devicePtrs[i]->node; j < 32; j++) { + if (!devicePtrs[j] || devicePtrs[j]->devId != devId) + continue; + pNode2 = devicePtrs[j]->node; + devicePtrs[j]->node = pNode; + pNode = pNode2; + } + } + devicePtrs[i]->node.node = node; + devicePtrs[i]->node.cookie[0] = flags; + devicePtrs[i]->node.cookie[1] = oldnode; + break; + } + break; + } + } while (0); + + prop = promGetProperty("name", &len); + if (prop && len > 0) { + if (!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) + sbus = PROM_NODE_SBUS; + } + + nextnode = promGetChild(node); + if (nextnode) + promWalkAssignNodes(nextnode, node, sbus, devicePtrs); + + nextnode = promGetSibling(node); + if (nextnode) + promWalkAssignNodes(nextnode, node, PROM_NODE_SIBLING | sbus, devicePtrs); +} + +void +sparcPromAssignNodes(void) +{ + sbusDevicePtr psdp, *psdpp; + int n, holes = 0, i, j; + FILE *f; + sbusDevicePtr devicePtrs[32]; + + memset(devicePtrs, 0, sizeof(devicePtrs)); + for (psdpp = xf86SbusInfo, n = 0; (psdp = *psdpp); psdpp++, n++) { + if (psdp->fbNum != n) + holes = 1; + devicePtrs[psdp->fbNum] = psdp; + } + if (holes && (f = fopen("/proc/fb", "r")) != NULL) { + /* We could not open one of fb devices, check /proc/fb to see what + * were the types of the cards missed. */ + char buffer[64]; + int fbNum, devId; + static struct { + int devId; + char *prefix; + } procFbPrefixes[] = { + { SBUS_DEVICE_BW2, "BWtwo" }, + { SBUS_DEVICE_CG14, "CGfourteen" }, + { SBUS_DEVICE_CG6, "CGsix" }, + { SBUS_DEVICE_CG3, "CGthree" }, + { SBUS_DEVICE_FFB, "Creator" }, + { SBUS_DEVICE_FFB, "Elite 3D" }, + { SBUS_DEVICE_LEO, "Leo" }, + { SBUS_DEVICE_TCX, "TCX" }, + { 0, NULL }, + }; + + while (fscanf(f, "%d %63s\n", &fbNum, buffer) == 2) { + for (i = 0; procFbPrefixes[i].devId; i++) + if (! strncmp(procFbPrefixes[i].prefix, buffer, + strlen(procFbPrefixes[i].prefix))) + break; + devId = procFbPrefixes[i].devId; + if (! devId) continue; + if (devicePtrs[fbNum]) { + if (devicePtrs[fbNum]->devId != devId) + xf86ErrorF("Inconsistent /proc/fb with FBIOGATTR\n"); + } else if (!devicePtrs[fbNum]) { + devicePtrs[fbNum] = psdp = xnfcalloc(sizeof (sbusDevice), 1); + psdp->devId = devId; + psdp->fbNum = fbNum; + psdp->fd = -2; + } + } + fclose(f); + } + promGetSibling(0); + promWalkAssignNodes(promRootNode, 0, PROM_NODE_PREF, devicePtrs); + for (i = 0, j = 0; i < 32; i++) + if (devicePtrs[i] && devicePtrs[i]->fbNum == -1) + j++; + xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (n + j + 1)); + for (i = 0, psdpp = xf86SbusInfo; i < 32; i++) + if (devicePtrs[i]) { + if (devicePtrs[i]->fbNum == -1) { + memmove(psdpp + 1, psdpp, sizeof(psdpp) * (n + 1)); + *psdpp = devicePtrs[i]; + } else + n--; + } +} + +static char * +promGetReg(int type) +{ + char *prop; + int len; + static char regstr[40]; + + regstr[0] = 0; + prop = promGetProperty("reg", &len); + if (prop && len >= 4) { + unsigned int *reg = (unsigned int *)prop; + if (!promP1275 || (type == PROM_NODE_SBUS) || (type == PROM_NODE_EBUS)) + sprintf (regstr, "@%x,%x", reg[0], reg[1]); + else if (type == PROM_NODE_PCI) { + if ((reg[0] >> 8) & 7) + sprintf (regstr, "@%x,%x", (reg[0] >> 11) & 0x1f, (reg[0] >> 8) & 7); + else + sprintf (regstr, "@%x", (reg[0] >> 11) & 0x1f); + } else if (len == 4) + sprintf (regstr, "@%x", reg[0]); + else { + unsigned int regs[2]; + + /* Things get more complicated on UPA. If upa-portid exists, + then address is @upa-portid,second-int-in-reg, otherwise + it is @first-int-in-reg/16,second-int-in-reg (well, probably + upa-portid always exists, but just to be safe). */ + memcpy (regs, reg, sizeof(regs)); + prop = promGetProperty("upa-portid", &len); + if (prop && len == 4) { + reg = (unsigned int *)prop; + sprintf (regstr, "@%x,%x", reg[0], regs[1]); + } else + sprintf (regstr, "@%x,%x", regs[0] >> 4, regs[1]); + } + } + return regstr; +} + +static int +promWalkNode2Pathname(char *path, int parent, int node, int searchNode, int type) +{ + int nextnode; + int len, ntype = type; + char *prop, *p; + + prop = promGetProperty("name", &len); + *path = '/'; + if (!prop || len <= 0) + return 0; + if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type) + ntype = PROM_NODE_SBUS; + else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI) + ntype = PROM_NODE_EBUS; + else if (!strcmp(prop, "pci") && !type) + ntype = PROM_NODE_PCI; + strcpy (path + 1, prop); + p = promGetReg(type); + if (*p) + strcat (path, p); + if (node == searchNode) + return 1; + nextnode = promGetChild(node); + if (nextnode && + promWalkNode2Pathname(strchr(path, 0), node, nextnode, searchNode, ntype)) + return 1; + nextnode = promGetSibling(node); + if (nextnode && + promWalkNode2Pathname(path, parent, nextnode, searchNode, type)) + return 1; + return 0; +} + +char * +sparcPromNode2Pathname(sbusPromNodePtr pnode) +{ + char *ret; + + if (!pnode->node) return NULL; + ret = malloc(4096); + if (!ret) return NULL; + if (promWalkNode2Pathname(ret, promRootNode, promGetChild(promRootNode), pnode->node, 0)) + return ret; + free(ret); + return NULL; +} + +static int +promWalkPathname2Node(char *name, char *regstr, int parent, int type) +{ + int len, node, ret; + char *prop, *p; + + for (;;) { + prop = promGetProperty("name", &len); + if (!prop || len <= 0) + return 0; + if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type) + type = PROM_NODE_SBUS; + else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI) + type = PROM_NODE_EBUS; + else if (!strcmp(prop, "pci") && !type) + type = PROM_NODE_PCI; + for (node = promGetChild(parent); node; node = promGetSibling(node)) { + prop = promGetProperty("name", &len); + if (!prop || len <= 0) + continue; + if (*name && strcmp(name, prop)) + continue; + if (*regstr) { + p = promGetReg(type); + if (! *p || strcmp(p + 1, regstr)) + continue; + } + break; + } + if (!node) { + for (node = promGetChild(parent); node; node = promGetSibling(node)) { + ret = promWalkPathname2Node(name, regstr, node, type); + if (ret) return ret; + } + return 0; + } + name = strchr(regstr, 0) + 1; + if (! *name) + return node; + p = strchr(name, '/'); + if (p) + *p = 0; + else + p = strchr(name, 0); + regstr = strchr(name, '@'); + if (regstr) + *regstr++ = 0; + else + regstr = p; + if (name == regstr) + return 0; + parent = node; + } +} + +int +sparcPromPathname2Node(const char *pathName) +{ + int i; + char *name, *regstr, *p; + + i = strlen(pathName); + name = malloc(i + 2); + if (! name) return 0; + strcpy (name, pathName); + name [i + 1] = 0; + if (name[0] != '/') + return 0; + p = strchr(name + 1, '/'); + if (p) + *p = 0; + else + p = strchr(name, 0); + regstr = strchr(name, '@'); + if (regstr) + *regstr++ = 0; + else + regstr = p; + if (name + 1 == regstr) + return 0; + promGetSibling(0); + i = promWalkPathname2Node(name + 1, regstr, promRootNode, 0); + free(name); + return i; +} + +pointer +xf86MapSbusMem(sbusDevicePtr psdp, unsigned long offset, unsigned long size) +{ + pointer ret; + unsigned long pagemask = getpagesize() - 1; + unsigned long off = offset & ~pagemask; + unsigned long len = ((offset + size + pagemask) & ~pagemask) - off; + + if (psdp->fd == -1) { + psdp->fd = open(psdp->device, O_RDWR); + if (psdp->fd == -1) + return NULL; + } else if (psdp->fd < 0) + return NULL; + + ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, + psdp->fd, off); + if (ret == (pointer) -1) { + ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, + psdp->fd, off); + } + if (ret == (pointer) -1) + return NULL; + + return (char *)ret + (offset - off); +} + +void +xf86UnmapSbusMem(sbusDevicePtr psdp, pointer addr, unsigned long size) +{ + unsigned long mask = getpagesize() - 1; + unsigned long base = (unsigned long)addr & ~mask; + unsigned long len = (((unsigned long)addr + size + mask) & ~mask) - base; + + munmap ((pointer)base, len); +} + +/* Tell OS that we are driving the HW cursor ourselves. */ +void +xf86SbusHideOsHwCursor(sbusDevicePtr psdp) +{ + struct fbcursor fbcursor; + unsigned char zeros[8]; + + memset(&fbcursor, 0, sizeof(fbcursor)); + memset(&zeros, 0, sizeof(zeros)); + fbcursor.cmap.count = 2; + fbcursor.cmap.red = zeros; + fbcursor.cmap.green = zeros; + fbcursor.cmap.blue = zeros; + fbcursor.image = (char *)zeros; + fbcursor.mask = (char *)zeros; + fbcursor.size.x = 32; + fbcursor.size.y = 1; + fbcursor.set = FB_CUR_SETALL; + ioctl(psdp->fd, FBIOSCURSOR, &fbcursor); +} + +/* Set HW cursor colormap. */ +void +xf86SbusSetOsHwCursorCmap(sbusDevicePtr psdp, int bg, int fg) +{ + struct fbcursor fbcursor; + unsigned char red[2], green[2], blue[2]; + + memset(&fbcursor, 0, sizeof(fbcursor)); + red[0] = bg >> 16; + green[0] = bg >> 8; + blue[0] = bg; + red[1] = fg >> 16; + green[1] = fg >> 8; + blue[1] = fg; + fbcursor.cmap.count = 2; + fbcursor.cmap.red = red; + fbcursor.cmap.green = green; + fbcursor.cmap.blue = blue; + fbcursor.set = FB_CUR_SETCMAP; + ioctl(psdp->fd, FBIOSCURSOR, &fbcursor); +} diff --git a/xorg-server/hw/xfree86/os-support/linux/int10/linux.c b/xorg-server/hw/xfree86/os-support/linux/int10/linux.c index 0cf3507c3..e3c8a984d 100644 --- a/xorg-server/hw/xfree86/os-support/linux/int10/linux.c +++ b/xorg-server/hw/xfree86/os-support/linux/int10/linux.c @@ -1,544 +1,544 @@ -/* - * linux specific part of the int10 module - * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2008 Egbert Eich - */ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86_OSproc.h" -#include "xf86Pci.h" -#include "compiler.h" -#define _INT10_PRIVATE -#include "xf86int10.h" -#ifdef __sparc__ -#define DEV_MEM "/dev/fb" -#else -#define DEV_MEM "/dev/mem" -#endif -#define ALLOC_ENTRIES(x) ((V_RAM / x) - 1) -#define SHMERRORPTR (pointer)(-1) - -#include <fcntl.h> -#include <errno.h> -#include <sys/mman.h> -#include <sys/ipc.h> -#include <sys/shm.h> -#include <unistd.h> -#include <string.h> - -static int counter = 0; -static unsigned long int10Generation = 0; - -static CARD8 read_b(xf86Int10InfoPtr pInt, int addr); -static CARD16 read_w(xf86Int10InfoPtr pInt, int addr); -static CARD32 read_l(xf86Int10InfoPtr pInt, int addr); -static void write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val); -static void write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val); -static void write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val); - -int10MemRec linuxMem = { - read_b, - read_w, - read_l, - write_b, - write_w, - write_l -}; - -typedef struct { - int lowMem; - int highMem; - char* base; - char* base_high; - int screen; - char* alloc; -} linuxInt10Priv; - -#if defined DoSubModules - -typedef enum { - INT10_NOT_LOADED, - INT10_LOADED_VM86, - INT10_LOADED_X86EMU, - INT10_LOAD_FAILED -} Int10LinuxSubModuleState; - -static Int10LinuxSubModuleState loadedSubModule = INT10_NOT_LOADED; - -static Int10LinuxSubModuleState int10LinuxLoadSubModule(ScrnInfoPtr pScrn); - -#endif /* DoSubModules */ - -xf86Int10InfoPtr -xf86ExtendedInitInt10(int entityIndex, int Flags) -{ - xf86Int10InfoPtr pInt = NULL; - int screen; - int fd; - static void* vidMem = NULL; - static void* sysMem = NULL; - void* vMem = NULL; - void *options = NULL; - int low_mem; - int high_mem = -1; - char *base = SHMERRORPTR; - char *base_high = SHMERRORPTR; - int pagesize; - memType cs; - legacyVGARec vga; - Bool videoBiosMapped = FALSE; - - if (int10Generation != serverGeneration) { - counter = 0; - int10Generation = serverGeneration; - } - - screen = (xf86FindScreenForEntity(entityIndex))->scrnIndex; - - options = xf86HandleInt10Options(xf86Screens[screen],entityIndex); - - if (int10skip(options)) { - xfree(options); - return NULL; - } - -#if defined DoSubModules - if (loadedSubModule == INT10_NOT_LOADED) - loadedSubModule = int10LinuxLoadSubModule(xf86Screens[screen]); - - if (loadedSubModule == INT10_LOAD_FAILED) - return NULL; -#endif - - if ((!vidMem) || (!sysMem)) { - if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) { - if (!sysMem) { - DebugF("Mapping sys bios area\n"); - if ((sysMem = mmap((void *)(SYS_BIOS), BIOS_SIZE, - PROT_READ | PROT_EXEC, - MAP_SHARED | MAP_FIXED, fd, SYS_BIOS)) - == MAP_FAILED) { - xf86DrvMsg(screen, X_ERROR, "Cannot map SYS BIOS\n"); - close(fd); - goto error0; - } - } - if (!vidMem) { - DebugF("Mapping VRAM area\n"); - if ((vidMem = mmap((void *)(V_RAM), VRAM_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_SHARED | MAP_FIXED, fd, V_RAM)) - == MAP_FAILED) { - xf86DrvMsg(screen, X_ERROR, "Cannot map V_RAM\n"); - close(fd); - goto error0; - } - } - close(fd); - } else { - xf86DrvMsg(screen, X_ERROR, "Cannot open %s\n", DEV_MEM); - goto error0; - } - } - - pInt = (xf86Int10InfoPtr)xnfcalloc(1, sizeof(xf86Int10InfoRec)); - pInt->scrnIndex = screen; - pInt->entityIndex = entityIndex; - pInt->dev = xf86GetPciInfoForEntity(entityIndex); - - if (!xf86Int10ExecSetup(pInt)) - goto error0; - pInt->mem = &linuxMem; - pagesize = getpagesize(); - pInt->private = (pointer)xnfcalloc(1, sizeof(linuxInt10Priv)); - ((linuxInt10Priv*)pInt->private)->screen = screen; - ((linuxInt10Priv*)pInt->private)->alloc = - (pointer)xnfcalloc(1, ALLOC_ENTRIES(pagesize)); - - if (!xf86IsEntityPrimary(entityIndex)) { - DebugF("Mapping high memory area\n"); - if ((high_mem = shmget(counter++, HIGH_MEM_SIZE, - IPC_CREAT | SHM_R | SHM_W)) == -1) { - if (errno == ENOSYS) - xf86DrvMsg(screen, X_ERROR, "shmget error\n Please reconfigure" - " your kernel to include System V IPC support\n"); - else - xf86DrvMsg(screen, X_ERROR, - "shmget(highmem) error: %s\n",strerror(errno)); - goto error1; - } - } else { - DebugF("Mapping Video BIOS\n"); - videoBiosMapped = TRUE; - if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) { - if ((vMem = mmap((void *)(V_BIOS), SYS_BIOS - V_BIOS, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_SHARED | MAP_FIXED, fd, V_BIOS)) - == MAP_FAILED) { - xf86DrvMsg(screen, X_ERROR, "Cannot map V_BIOS\n"); - close(fd); - goto error1; - } - close (fd); - } else - goto error1; - } - ((linuxInt10Priv*)pInt->private)->highMem = high_mem; - - DebugF("Mapping 640kB area\n"); - if ((low_mem = shmget(counter++, V_RAM, - IPC_CREAT | SHM_R | SHM_W)) == -1) { - xf86DrvMsg(screen, X_ERROR, - "shmget(lowmem) error: %s\n",strerror(errno)); - goto error2; - } - - ((linuxInt10Priv*)pInt->private)->lowMem = low_mem; - base = shmat(low_mem, 0, 0); - if (base == SHMERRORPTR) { - xf86DrvMsg(screen, X_ERROR, - "shmat(low_mem) error: %s\n",strerror(errno)); - goto error3; - } - ((linuxInt10Priv *)pInt->private)->base = base; - if (high_mem > -1) { - base_high = shmat(high_mem, 0, 0); - if (base_high == SHMERRORPTR) { - xf86DrvMsg(screen, X_ERROR, - "shmat(high_mem) error: %s\n",strerror(errno)); - goto error3; - } - ((linuxInt10Priv*)pInt->private)->base_high = base_high; - } else - ((linuxInt10Priv*)pInt->private)->base_high = NULL; - - if (!MapCurrentInt10(pInt)) - goto error3; - - Int10Current = pInt; - - DebugF("Mapping int area\n"); - if (xf86ReadBIOS(0, 0, (unsigned char *)0, LOW_PAGE_SIZE) < 0) { - xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n"); - goto error3; - } - DebugF("done\n"); - /* - * Read in everything between V_BIOS and SYS_BIOS as some system BIOSes - * have executable code there. Note that xf86ReadBIOS() can only bring in - * 64K bytes at a time. - */ - if (!videoBiosMapped) { - memset((pointer)V_BIOS, 0, SYS_BIOS - V_BIOS); - DebugF("Reading BIOS\n"); - for (cs = V_BIOS; cs < SYS_BIOS; cs += V_BIOS_SIZE) - if (xf86ReadBIOS(cs, 0, (pointer)cs, V_BIOS_SIZE) < V_BIOS_SIZE) - xf86DrvMsg(screen, X_WARNING, - "Unable to retrieve all of segment 0x%06lX.\n", - (long)cs); - DebugF("done\n"); - } - - if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) { - if (!xf86int10GetBiosSegment(pInt, NULL)) - goto error3; - - set_return_trap(pInt); -#ifdef _PC - pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); - if (! (pInt->Flags & SET_BIOS_SCRATCH)) - pInt->Flags &= ~RESTORE_BIOS_SCRATCH; - xf86Int10SaveRestoreBIOSVars(pInt, TRUE); -#endif - } else { - const BusType location_type = xf86int10GetBiosLocationType(pInt); - - switch (location_type) { - case BUS_PCI: { - int err; - struct pci_device *rom_device = - xf86GetPciInfoForEntity(pInt->entityIndex); - -#if HAVE_PCI_DEVICE_ENABLE - pci_device_enable(rom_device); -#endif - - err = pci_device_read_rom(rom_device, (unsigned char *)(V_BIOS)); - if (err) { - xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (%s)\n", - strerror(err)); - goto error3; - } - - pInt->BIOSseg = V_BIOS >> 4; - break; - } - default: - goto error3; - } - - pInt->num = 0xe6; - reset_int_vect(pInt); - set_return_trap(pInt); - LockLegacyVGA(pInt, &vga); - xf86ExecX86int10(pInt); - UnlockLegacyVGA(pInt, &vga); - } -#ifdef DEBUG - dprint(0xc0000, 0x20); -#endif - - xfree(options); - return pInt; - -error3: - if (base_high) - shmdt(base_high); - shmdt(base); - shmdt(0); - if (base_high) - shmdt((char*)HIGH_MEM); - shmctl(low_mem, IPC_RMID, NULL); - Int10Current = NULL; -error2: - if (high_mem > -1) - shmctl(high_mem, IPC_RMID,NULL); -error1: - if (vMem) - munmap(vMem, SYS_BIOS - V_BIOS); - xfree(((linuxInt10Priv*)pInt->private)->alloc); - xfree(pInt->private); -error0: - xfree(options); - xfree(pInt); - return NULL; -} - -Bool -MapCurrentInt10(xf86Int10InfoPtr pInt) -{ - pointer addr; - int fd = -1; - - if (Int10Current) { - shmdt(0); - if (((linuxInt10Priv*)Int10Current->private)->highMem >= 0) - shmdt((char*)HIGH_MEM); - else - munmap((pointer)V_BIOS, (SYS_BIOS - V_BIOS)); - } - addr = shmat(((linuxInt10Priv*)pInt->private)->lowMem, (char*)1, SHM_RND); - if (addr == SHMERRORPTR) { - xf86DrvMsg(pInt->scrnIndex, X_ERROR, "Cannot shmat() low memory\n"); - xf86DrvMsg(pInt->scrnIndex, X_ERROR, - "shmat(low_mem) error: %s\n",strerror(errno)); - return FALSE; - } - if (mprotect((void*)0, V_RAM, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) - xf86DrvMsg(pInt->scrnIndex, X_ERROR, - "Cannot set EXEC bit on low memory: %s\n", strerror(errno)); - - if (((linuxInt10Priv*)pInt->private)->highMem >= 0) { - addr = shmat(((linuxInt10Priv*)pInt->private)->highMem, - (char*)HIGH_MEM, 0); - if (addr == SHMERRORPTR) { - xf86DrvMsg(pInt->scrnIndex, X_ERROR, - "Cannot shmat() high memory\n"); - xf86DrvMsg(pInt->scrnIndex, X_ERROR, - "shmget error: %s\n",strerror(errno)); - return FALSE; - } - if (mprotect((void*)HIGH_MEM, HIGH_MEM_SIZE, - PROT_READ|PROT_WRITE|PROT_EXEC) != 0) - xf86DrvMsg(pInt->scrnIndex, X_ERROR, - "Cannot set EXEC bit on high memory: %s\n", - strerror(errno)); - } else { - if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) { - if (mmap((void *)(V_BIOS), SYS_BIOS - V_BIOS, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_SHARED | MAP_FIXED, fd, V_BIOS) - == MAP_FAILED) { - xf86DrvMsg(pInt->scrnIndex, X_ERROR, "Cannot map V_BIOS\n"); - close (fd); - return FALSE; - } - } else { - xf86DrvMsg(pInt->scrnIndex, X_ERROR, "Cannot open %s\n",DEV_MEM); - return FALSE; - } - close (fd); - } - - return TRUE; -} - -void -xf86FreeInt10(xf86Int10InfoPtr pInt) -{ - if (!pInt) - return; - -#ifdef _PC - xf86Int10SaveRestoreBIOSVars(pInt, FALSE); -#endif - if (Int10Current == pInt) { - shmdt(0); - if (((linuxInt10Priv*)pInt->private)->highMem >= 0) - shmdt((char*)HIGH_MEM); - else - munmap((pointer)V_BIOS, (SYS_BIOS - V_BIOS)); - Int10Current = NULL; - } - - if (((linuxInt10Priv*)pInt->private)->base_high) - shmdt(((linuxInt10Priv*)pInt->private)->base_high); - shmdt(((linuxInt10Priv*)pInt->private)->base); - shmctl(((linuxInt10Priv*)pInt->private)->lowMem, IPC_RMID, NULL); - if (((linuxInt10Priv*)pInt->private)->highMem >= 0) - shmctl(((linuxInt10Priv*)pInt->private)->highMem, IPC_RMID, NULL); - xfree(((linuxInt10Priv*)pInt->private)->alloc); - xfree(pInt->private); - xfree(pInt); -} - -void * -xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off) -{ - int pagesize = getpagesize(); - int num_pages = ALLOC_ENTRIES(pagesize); - int i, j; - - for (i = 0; i < (num_pages - num); i++) { - if (((linuxInt10Priv*)pInt->private)->alloc[i] == 0) { - for (j = i; j < (num + i); j++) - if ((((linuxInt10Priv*)pInt->private)->alloc[j] != 0)) - break; - if (j == (num + i)) - break; - else - i = i + num; - } - } - if (i == (num_pages - num)) - return NULL; - - for (j = i; j < (i + num); j++) - ((linuxInt10Priv*)pInt->private)->alloc[j] = 1; - - *off = (i + 1) * pagesize; - - return ((linuxInt10Priv*)pInt->private)->base + ((i + 1) * pagesize); -} - -void -xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) -{ - int pagesize = getpagesize(); - int first = (((unsigned long)pbase - - (unsigned long)((linuxInt10Priv*)pInt->private)->base) - / pagesize) - 1; - int i; - - for (i = first; i < (first + num); i++) - ((linuxInt10Priv*)pInt->private)->alloc[i] = 0; -} - -static CARD8 -read_b(xf86Int10InfoPtr pInt, int addr) -{ - return *((CARD8 *)(memType)addr); -} - -static CARD16 -read_w(xf86Int10InfoPtr pInt, int addr) -{ - return *((CARD16 *)(memType)addr); -} - -static CARD32 -read_l(xf86Int10InfoPtr pInt, int addr) -{ - return *((CARD32 *)(memType)addr); -} - -static void -write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val) -{ - *((CARD8 *)(memType)addr) = val; -} - -static void -write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val) -{ - *((CARD16 *)(memType)addr) = val; -} - -static -void write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val) -{ - *((CARD32 *)(memType) addr) = val; -} - -pointer -xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr) -{ - if (addr < V_RAM) - return ((linuxInt10Priv*)pInt->private)->base + addr; - else if (addr < V_BIOS) - return (pointer)(memType)addr; - else if (addr < SYS_BIOS) { - if (((linuxInt10Priv*)pInt->private)->base_high) - return (pointer)(((linuxInt10Priv*)pInt->private)->base_high - - V_BIOS + addr); - else - return (pointer) (memType)addr; - } else - return (pointer) (memType)addr; -} - -#if defined DoSubModules - -static Bool -vm86_tst(void) -{ - int __res; - -#ifdef __PIC__ - /* When compiling with -fPIC, we can't use asm constraint "b" because - %ebx is already taken by gcc. */ - __asm__ __volatile__("pushl %%ebx\n\t" - "movl %2,%%ebx\n\t" - "movl %1,%%eax\n\t" - "int $0x80\n\t" - "popl %%ebx" - :"=a" (__res) - :"n" ((int)113), "r" (NULL)); -#else - __asm__ __volatile__("int $0x80\n\t" - :"=a" (__res):"a" ((int)113), - "b" ((struct vm86_struct *)NULL)); -#endif - - if (__res < 0 && __res == -ENOSYS) - return FALSE; - - return TRUE; -} - -static Int10LinuxSubModuleState -int10LinuxLoadSubModule(ScrnInfoPtr pScrn) -{ - if (vm86_tst()) { - if (xf86LoadSubModule(pScrn,"vm86")) - return INT10_LOADED_VM86; - } - if (xf86LoadSubModule(pScrn,"x86emu")) - return INT10_LOADED_X86EMU; - - return INT10_LOAD_FAILED; -} - -#endif /* DoSubModules */ +/* + * linux specific part of the int10 module + * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2008 Egbert Eich + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Pci.h" +#include "compiler.h" +#define _INT10_PRIVATE +#include "xf86int10.h" +#ifdef __sparc__ +#define DEV_MEM "/dev/fb" +#else +#define DEV_MEM "/dev/mem" +#endif +#define ALLOC_ENTRIES(x) ((V_RAM / x) - 1) +#define SHMERRORPTR (pointer)(-1) + +#include <fcntl.h> +#include <errno.h> +#include <sys/mman.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <unistd.h> +#include <string.h> + +static int counter = 0; +static unsigned long int10Generation = 0; + +static CARD8 read_b(xf86Int10InfoPtr pInt, int addr); +static CARD16 read_w(xf86Int10InfoPtr pInt, int addr); +static CARD32 read_l(xf86Int10InfoPtr pInt, int addr); +static void write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val); +static void write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val); +static void write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val); + +int10MemRec linuxMem = { + read_b, + read_w, + read_l, + write_b, + write_w, + write_l +}; + +typedef struct { + int lowMem; + int highMem; + char* base; + char* base_high; + int screen; + char* alloc; +} linuxInt10Priv; + +#if defined DoSubModules + +typedef enum { + INT10_NOT_LOADED, + INT10_LOADED_VM86, + INT10_LOADED_X86EMU, + INT10_LOAD_FAILED +} Int10LinuxSubModuleState; + +static Int10LinuxSubModuleState loadedSubModule = INT10_NOT_LOADED; + +static Int10LinuxSubModuleState int10LinuxLoadSubModule(ScrnInfoPtr pScrn); + +#endif /* DoSubModules */ + +xf86Int10InfoPtr +xf86ExtendedInitInt10(int entityIndex, int Flags) +{ + xf86Int10InfoPtr pInt = NULL; + int screen; + int fd; + static void* vidMem = NULL; + static void* sysMem = NULL; + void* vMem = NULL; + void *options = NULL; + int low_mem; + int high_mem = -1; + char *base = SHMERRORPTR; + char *base_high = SHMERRORPTR; + int pagesize; + memType cs; + legacyVGARec vga; + Bool videoBiosMapped = FALSE; + + if (int10Generation != serverGeneration) { + counter = 0; + int10Generation = serverGeneration; + } + + screen = (xf86FindScreenForEntity(entityIndex))->scrnIndex; + + options = xf86HandleInt10Options(xf86Screens[screen],entityIndex); + + if (int10skip(options)) { + free(options); + return NULL; + } + +#if defined DoSubModules + if (loadedSubModule == INT10_NOT_LOADED) + loadedSubModule = int10LinuxLoadSubModule(xf86Screens[screen]); + + if (loadedSubModule == INT10_LOAD_FAILED) + return NULL; +#endif + + if ((!vidMem) || (!sysMem)) { + if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) { + if (!sysMem) { + DebugF("Mapping sys bios area\n"); + if ((sysMem = mmap((void *)(SYS_BIOS), BIOS_SIZE, + PROT_READ | PROT_EXEC, + MAP_SHARED | MAP_FIXED, fd, SYS_BIOS)) + == MAP_FAILED) { + xf86DrvMsg(screen, X_ERROR, "Cannot map SYS BIOS\n"); + close(fd); + goto error0; + } + } + if (!vidMem) { + DebugF("Mapping VRAM area\n"); + if ((vidMem = mmap((void *)(V_RAM), VRAM_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_SHARED | MAP_FIXED, fd, V_RAM)) + == MAP_FAILED) { + xf86DrvMsg(screen, X_ERROR, "Cannot map V_RAM\n"); + close(fd); + goto error0; + } + } + close(fd); + } else { + xf86DrvMsg(screen, X_ERROR, "Cannot open %s\n", DEV_MEM); + goto error0; + } + } + + pInt = (xf86Int10InfoPtr)xnfcalloc(1, sizeof(xf86Int10InfoRec)); + pInt->scrnIndex = screen; + pInt->entityIndex = entityIndex; + pInt->dev = xf86GetPciInfoForEntity(entityIndex); + + if (!xf86Int10ExecSetup(pInt)) + goto error0; + pInt->mem = &linuxMem; + pagesize = getpagesize(); + pInt->private = (pointer)xnfcalloc(1, sizeof(linuxInt10Priv)); + ((linuxInt10Priv*)pInt->private)->screen = screen; + ((linuxInt10Priv*)pInt->private)->alloc = + (pointer)xnfcalloc(1, ALLOC_ENTRIES(pagesize)); + + if (!xf86IsEntityPrimary(entityIndex)) { + DebugF("Mapping high memory area\n"); + if ((high_mem = shmget(counter++, HIGH_MEM_SIZE, + IPC_CREAT | SHM_R | SHM_W)) == -1) { + if (errno == ENOSYS) + xf86DrvMsg(screen, X_ERROR, "shmget error\n Please reconfigure" + " your kernel to include System V IPC support\n"); + else + xf86DrvMsg(screen, X_ERROR, + "shmget(highmem) error: %s\n",strerror(errno)); + goto error1; + } + } else { + DebugF("Mapping Video BIOS\n"); + videoBiosMapped = TRUE; + if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) { + if ((vMem = mmap((void *)(V_BIOS), SYS_BIOS - V_BIOS, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_SHARED | MAP_FIXED, fd, V_BIOS)) + == MAP_FAILED) { + xf86DrvMsg(screen, X_ERROR, "Cannot map V_BIOS\n"); + close(fd); + goto error1; + } + close (fd); + } else + goto error1; + } + ((linuxInt10Priv*)pInt->private)->highMem = high_mem; + + DebugF("Mapping 640kB area\n"); + if ((low_mem = shmget(counter++, V_RAM, + IPC_CREAT | SHM_R | SHM_W)) == -1) { + xf86DrvMsg(screen, X_ERROR, + "shmget(lowmem) error: %s\n",strerror(errno)); + goto error2; + } + + ((linuxInt10Priv*)pInt->private)->lowMem = low_mem; + base = shmat(low_mem, 0, 0); + if (base == SHMERRORPTR) { + xf86DrvMsg(screen, X_ERROR, + "shmat(low_mem) error: %s\n",strerror(errno)); + goto error3; + } + ((linuxInt10Priv *)pInt->private)->base = base; + if (high_mem > -1) { + base_high = shmat(high_mem, 0, 0); + if (base_high == SHMERRORPTR) { + xf86DrvMsg(screen, X_ERROR, + "shmat(high_mem) error: %s\n",strerror(errno)); + goto error3; + } + ((linuxInt10Priv*)pInt->private)->base_high = base_high; + } else + ((linuxInt10Priv*)pInt->private)->base_high = NULL; + + if (!MapCurrentInt10(pInt)) + goto error3; + + Int10Current = pInt; + + DebugF("Mapping int area\n"); + if (xf86ReadBIOS(0, 0, (unsigned char *)0, LOW_PAGE_SIZE) < 0) { + xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n"); + goto error3; + } + DebugF("done\n"); + /* + * Read in everything between V_BIOS and SYS_BIOS as some system BIOSes + * have executable code there. Note that xf86ReadBIOS() can only bring in + * 64K bytes at a time. + */ + if (!videoBiosMapped) { + memset((pointer)V_BIOS, 0, SYS_BIOS - V_BIOS); + DebugF("Reading BIOS\n"); + for (cs = V_BIOS; cs < SYS_BIOS; cs += V_BIOS_SIZE) + if (xf86ReadBIOS(cs, 0, (pointer)cs, V_BIOS_SIZE) < V_BIOS_SIZE) + xf86DrvMsg(screen, X_WARNING, + "Unable to retrieve all of segment 0x%06lX.\n", + (long)cs); + DebugF("done\n"); + } + + if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) { + if (!xf86int10GetBiosSegment(pInt, NULL)) + goto error3; + + set_return_trap(pInt); +#ifdef _PC + pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); + if (! (pInt->Flags & SET_BIOS_SCRATCH)) + pInt->Flags &= ~RESTORE_BIOS_SCRATCH; + xf86Int10SaveRestoreBIOSVars(pInt, TRUE); +#endif + } else { + const BusType location_type = xf86int10GetBiosLocationType(pInt); + + switch (location_type) { + case BUS_PCI: { + int err; + struct pci_device *rom_device = + xf86GetPciInfoForEntity(pInt->entityIndex); + +#if HAVE_PCI_DEVICE_ENABLE + pci_device_enable(rom_device); +#endif + + err = pci_device_read_rom(rom_device, (unsigned char *)(V_BIOS)); + if (err) { + xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (%s)\n", + strerror(err)); + goto error3; + } + + pInt->BIOSseg = V_BIOS >> 4; + break; + } + default: + goto error3; + } + + pInt->num = 0xe6; + reset_int_vect(pInt); + set_return_trap(pInt); + LockLegacyVGA(pInt, &vga); + xf86ExecX86int10(pInt); + UnlockLegacyVGA(pInt, &vga); + } +#ifdef DEBUG + dprint(0xc0000, 0x20); +#endif + + free(options); + return pInt; + +error3: + if (base_high) + shmdt(base_high); + shmdt(base); + shmdt(0); + if (base_high) + shmdt((char*)HIGH_MEM); + shmctl(low_mem, IPC_RMID, NULL); + Int10Current = NULL; +error2: + if (high_mem > -1) + shmctl(high_mem, IPC_RMID,NULL); +error1: + if (vMem) + munmap(vMem, SYS_BIOS - V_BIOS); + free(((linuxInt10Priv*)pInt->private)->alloc); + free(pInt->private); +error0: + free(options); + free(pInt); + return NULL; +} + +Bool +MapCurrentInt10(xf86Int10InfoPtr pInt) +{ + pointer addr; + int fd = -1; + + if (Int10Current) { + shmdt(0); + if (((linuxInt10Priv*)Int10Current->private)->highMem >= 0) + shmdt((char*)HIGH_MEM); + else + munmap((pointer)V_BIOS, (SYS_BIOS - V_BIOS)); + } + addr = shmat(((linuxInt10Priv*)pInt->private)->lowMem, (char*)1, SHM_RND); + if (addr == SHMERRORPTR) { + xf86DrvMsg(pInt->scrnIndex, X_ERROR, "Cannot shmat() low memory\n"); + xf86DrvMsg(pInt->scrnIndex, X_ERROR, + "shmat(low_mem) error: %s\n",strerror(errno)); + return FALSE; + } + if (mprotect((void*)0, V_RAM, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) + xf86DrvMsg(pInt->scrnIndex, X_ERROR, + "Cannot set EXEC bit on low memory: %s\n", strerror(errno)); + + if (((linuxInt10Priv*)pInt->private)->highMem >= 0) { + addr = shmat(((linuxInt10Priv*)pInt->private)->highMem, + (char*)HIGH_MEM, 0); + if (addr == SHMERRORPTR) { + xf86DrvMsg(pInt->scrnIndex, X_ERROR, + "Cannot shmat() high memory\n"); + xf86DrvMsg(pInt->scrnIndex, X_ERROR, + "shmget error: %s\n",strerror(errno)); + return FALSE; + } + if (mprotect((void*)HIGH_MEM, HIGH_MEM_SIZE, + PROT_READ|PROT_WRITE|PROT_EXEC) != 0) + xf86DrvMsg(pInt->scrnIndex, X_ERROR, + "Cannot set EXEC bit on high memory: %s\n", + strerror(errno)); + } else { + if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) { + if (mmap((void *)(V_BIOS), SYS_BIOS - V_BIOS, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_SHARED | MAP_FIXED, fd, V_BIOS) + == MAP_FAILED) { + xf86DrvMsg(pInt->scrnIndex, X_ERROR, "Cannot map V_BIOS\n"); + close (fd); + return FALSE; + } + } else { + xf86DrvMsg(pInt->scrnIndex, X_ERROR, "Cannot open %s\n",DEV_MEM); + return FALSE; + } + close (fd); + } + + return TRUE; +} + +void +xf86FreeInt10(xf86Int10InfoPtr pInt) +{ + if (!pInt) + return; + +#ifdef _PC + xf86Int10SaveRestoreBIOSVars(pInt, FALSE); +#endif + if (Int10Current == pInt) { + shmdt(0); + if (((linuxInt10Priv*)pInt->private)->highMem >= 0) + shmdt((char*)HIGH_MEM); + else + munmap((pointer)V_BIOS, (SYS_BIOS - V_BIOS)); + Int10Current = NULL; + } + + if (((linuxInt10Priv*)pInt->private)->base_high) + shmdt(((linuxInt10Priv*)pInt->private)->base_high); + shmdt(((linuxInt10Priv*)pInt->private)->base); + shmctl(((linuxInt10Priv*)pInt->private)->lowMem, IPC_RMID, NULL); + if (((linuxInt10Priv*)pInt->private)->highMem >= 0) + shmctl(((linuxInt10Priv*)pInt->private)->highMem, IPC_RMID, NULL); + free(((linuxInt10Priv*)pInt->private)->alloc); + free(pInt->private); + free(pInt); +} + +void * +xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off) +{ + int pagesize = getpagesize(); + int num_pages = ALLOC_ENTRIES(pagesize); + int i, j; + + for (i = 0; i < (num_pages - num); i++) { + if (((linuxInt10Priv*)pInt->private)->alloc[i] == 0) { + for (j = i; j < (num + i); j++) + if ((((linuxInt10Priv*)pInt->private)->alloc[j] != 0)) + break; + if (j == (num + i)) + break; + else + i = i + num; + } + } + if (i == (num_pages - num)) + return NULL; + + for (j = i; j < (i + num); j++) + ((linuxInt10Priv*)pInt->private)->alloc[j] = 1; + + *off = (i + 1) * pagesize; + + return ((linuxInt10Priv*)pInt->private)->base + ((i + 1) * pagesize); +} + +void +xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) +{ + int pagesize = getpagesize(); + int first = (((unsigned long)pbase + - (unsigned long)((linuxInt10Priv*)pInt->private)->base) + / pagesize) - 1; + int i; + + for (i = first; i < (first + num); i++) + ((linuxInt10Priv*)pInt->private)->alloc[i] = 0; +} + +static CARD8 +read_b(xf86Int10InfoPtr pInt, int addr) +{ + return *((CARD8 *)(memType)addr); +} + +static CARD16 +read_w(xf86Int10InfoPtr pInt, int addr) +{ + return *((CARD16 *)(memType)addr); +} + +static CARD32 +read_l(xf86Int10InfoPtr pInt, int addr) +{ + return *((CARD32 *)(memType)addr); +} + +static void +write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val) +{ + *((CARD8 *)(memType)addr) = val; +} + +static void +write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val) +{ + *((CARD16 *)(memType)addr) = val; +} + +static +void write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val) +{ + *((CARD32 *)(memType) addr) = val; +} + +pointer +xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr) +{ + if (addr < V_RAM) + return ((linuxInt10Priv*)pInt->private)->base + addr; + else if (addr < V_BIOS) + return (pointer)(memType)addr; + else if (addr < SYS_BIOS) { + if (((linuxInt10Priv*)pInt->private)->base_high) + return (pointer)(((linuxInt10Priv*)pInt->private)->base_high + - V_BIOS + addr); + else + return (pointer) (memType)addr; + } else + return (pointer) (memType)addr; +} + +#if defined DoSubModules + +static Bool +vm86_tst(void) +{ + int __res; + +#ifdef __PIC__ + /* When compiling with -fPIC, we can't use asm constraint "b" because + %ebx is already taken by gcc. */ + __asm__ __volatile__("pushl %%ebx\n\t" + "movl %2,%%ebx\n\t" + "movl %1,%%eax\n\t" + "int $0x80\n\t" + "popl %%ebx" + :"=a" (__res) + :"n" ((int)113), "r" (NULL)); +#else + __asm__ __volatile__("int $0x80\n\t" + :"=a" (__res):"a" ((int)113), + "b" ((struct vm86_struct *)NULL)); +#endif + + if (__res < 0 && __res == -ENOSYS) + return FALSE; + + return TRUE; +} + +static Int10LinuxSubModuleState +int10LinuxLoadSubModule(ScrnInfoPtr pScrn) +{ + if (vm86_tst()) { + if (xf86LoadSubModule(pScrn,"vm86")) + return INT10_LOADED_VM86; + } + if (xf86LoadSubModule(pScrn,"x86emu")) + return INT10_LOADED_X86EMU; + + return INT10_LOAD_FAILED; +} + +#endif /* DoSubModules */ diff --git a/xorg-server/hw/xfree86/os-support/linux/lnx_agp.c b/xorg-server/hw/xfree86/os-support/linux/lnx_agp.c index 61437406d..3fa897366 100644 --- a/xorg-server/hw/xfree86/os-support/linux/lnx_agp.c +++ b/xorg-server/hw/xfree86/os-support/linux/lnx_agp.c @@ -1,374 +1,374 @@ -/* - * Abstraction of the AGP GART interface. - * - * This version is for Linux and Free/Open/NetBSD. - * - * Copyright © 2000 VA Linux Systems, Inc. - * Copyright © 2001 The XFree86 Project, Inc. - */ - - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" -#include "xf86OSpriv.h" - -#if defined(linux) -#include <asm/ioctl.h> -#include <linux/agpgart.h> -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) -#include <sys/ioctl.h> -#include <sys/agpio.h> -#endif - -#ifndef AGP_DEVICE -#define AGP_DEVICE "/dev/agpgart" -#endif -/* AGP page size is independent of the host page size. */ -#ifndef AGP_PAGE_SIZE -#define AGP_PAGE_SIZE 4096 -#endif -#define AGPGART_MAJOR_VERSION 0 -#define AGPGART_MINOR_VERSION 99 - -static int gartFd = -1; -static int acquiredScreen = -1; -static Bool initDone = FALSE; -/* - * Close /dev/agpgart. This frees all associated memory allocated during - * this server generation. - */ -Bool -xf86GARTCloseScreen(int screenNum) -{ - if(gartFd != -1) { - close(gartFd); - acquiredScreen = -1; - gartFd = -1; - initDone = FALSE; - } - return TRUE; -} - -/* - * Open /dev/agpgart. Keep it open until xf86GARTCloseScreen is called. - */ -static Bool -GARTInit(int screenNum) -{ - struct _agp_info agpinf; - - if (initDone) - return (gartFd != -1); - - initDone = TRUE; - - if (gartFd == -1) - gartFd = open(AGP_DEVICE, O_RDWR, 0); - else - return FALSE; - - if (gartFd == -1) { - xf86DrvMsg(screenNum, X_ERROR, - "GARTInit: Unable to open " AGP_DEVICE " (%s)\n", - strerror(errno)); - return FALSE; - } - - xf86AcquireGART(-1); - /* Check the kernel driver version. */ - if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { - xf86DrvMsg(screenNum, X_ERROR, - "GARTInit: AGPIOC_INFO failed (%s)\n", strerror(errno)); - close(gartFd); - gartFd = -1; - return FALSE; - } - xf86ReleaseGART(-1); - -#if defined(linux) - /* Per Dave Jones, every effort will be made to keep the - * agpgart interface backwards compatible, so allow all - * future versions. - */ - if ( -#if (AGPGART_MAJOR_VERSION > 0) /* quiet compiler */ - agpinf.version.major < AGPGART_MAJOR_VERSION || -#endif - (agpinf.version.major == AGPGART_MAJOR_VERSION && - agpinf.version.minor < AGPGART_MINOR_VERSION)) { - xf86DrvMsg(screenNum, X_ERROR, - "GARTInit: Kernel agpgart driver version is not current" - " (%d.%d vs %d.%d)\n", - agpinf.version.major, agpinf.version.minor, - AGPGART_MAJOR_VERSION, AGPGART_MINOR_VERSION); - close(gartFd); - gartFd = -1; - return FALSE; - } -#endif - - return TRUE; -} - -Bool -xf86AgpGARTSupported(void) -{ - return GARTInit(-1); -} - -AgpInfoPtr -xf86GetAGPInfo(int screenNum) -{ - struct _agp_info agpinf; - AgpInfoPtr info; - - if (!GARTInit(screenNum)) - return NULL; - - - if ((info = xcalloc(sizeof(AgpInfo), 1)) == NULL) { - xf86DrvMsg(screenNum, X_ERROR, - "xf86GetAGPInfo: Failed to allocate AgpInfo\n"); - return NULL; - } - - memset((char*)&agpinf, 0, sizeof(agpinf)); - - if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { - xf86DrvMsg(screenNum, X_ERROR, - "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n", - strerror(errno)); - return NULL; - } - - info->bridgeId = agpinf.bridge_id; - info->agpMode = agpinf.agp_mode; - info->base = agpinf.aper_base; - info->size = agpinf.aper_size; - info->totalPages = agpinf.pg_total; - info->systemPages = agpinf.pg_system; - info->usedPages = agpinf.pg_used; - - xf86DrvMsg(screenNum, X_INFO, "Kernel reported %zu total, %zu used\n", agpinf.pg_total, agpinf.pg_used); - - return info; -} - -/* - * XXX If multiple screens can acquire the GART, should we have a reference - * count instead of using acquiredScreen? - */ - -Bool -xf86AcquireGART(int screenNum) -{ - if (screenNum != -1 && !GARTInit(screenNum)) - return FALSE; - - if (screenNum == -1 || acquiredScreen != screenNum) { - if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) { - xf86DrvMsg(screenNum, X_WARNING, - "xf86AcquireGART: AGPIOC_ACQUIRE failed (%s)\n", - strerror(errno)); - return FALSE; - } - acquiredScreen = screenNum; - } - return TRUE; -} - -Bool -xf86ReleaseGART(int screenNum) -{ - if (screenNum != -1 && !GARTInit(screenNum)) - return FALSE; - - if (acquiredScreen == screenNum) { - /* - * The FreeBSD agp driver removes allocations on release. - * The Linux driver doesn't. xf86ReleaseGART() is expected - * to give up access to the GART, but not to remove any - * allocations. - */ -#if !defined(linux) - if (screenNum == -1) -#endif - { - if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) { - xf86DrvMsg(screenNum, X_WARNING, - "xf86ReleaseGART: AGPIOC_RELEASE failed (%s)\n", - strerror(errno)); - return FALSE; - } - acquiredScreen = -1; - } - return TRUE; - } - return FALSE; -} - -int -xf86AllocateGARTMemory(int screenNum, unsigned long size, int type, - unsigned long *physical) -{ - struct _agp_allocate alloc; - int pages; - - /* - * Allocates "size" bytes of GART memory (rounds up to the next - * page multiple) or type "type". A handle (key) for the allocated - * memory is returned. On error, the return value is -1. - */ - - if (!GARTInit(screenNum) || acquiredScreen != screenNum) - return -1; - - pages = (size / AGP_PAGE_SIZE); - if (size % AGP_PAGE_SIZE != 0) - pages++; - - /* XXX check for pages == 0? */ - - alloc.pg_count = pages; - alloc.type = type; - - if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86AllocateGARTMemory: " - "allocation of %d pages failed\n\t(%s)\n", pages, - strerror(errno)); - return -1; - } - - if (physical) - *physical = alloc.physical; - - return alloc.key; -} - -Bool -xf86DeallocateGARTMemory(int screenNum, int key) -{ - if (!GARTInit(screenNum) || acquiredScreen != screenNum) - return FALSE; - - if (acquiredScreen != screenNum) { - xf86DrvMsg(screenNum, X_ERROR, - "xf86UnbindGARTMemory: AGP not acquired by this screen\n"); - return FALSE; - } - -#ifdef __linux__ - if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *)key) != 0) { -#else - if (ioctl(gartFd, AGPIOC_DEALLOCATE, &key) != 0) { -#endif - xf86DrvMsg(screenNum, X_WARNING,"xf86DeAllocateGARTMemory: " - "deallocation gart memory with key %d failed\n\t(%s)\n", - key, strerror(errno)); - return FALSE; - } - - return TRUE; -} - -/* Bind GART memory with "key" at "offset" */ -Bool -xf86BindGARTMemory(int screenNum, int key, unsigned long offset) -{ - struct _agp_bind bind; - int pageOffset; - - if (!GARTInit(screenNum) || acquiredScreen != screenNum) - return FALSE; - - if (acquiredScreen != screenNum) { - xf86DrvMsg(screenNum, X_ERROR, - "xf86BindGARTMemory: AGP not acquired by this screen\n"); - return FALSE; - } - - if (offset % AGP_PAGE_SIZE != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " - "offset (0x%lx) is not page-aligned (%d)\n", - offset, AGP_PAGE_SIZE); - return FALSE; - } - pageOffset = offset / AGP_PAGE_SIZE; - - xf86DrvMsgVerb(screenNum, X_INFO, 3, - "xf86BindGARTMemory: bind key %d at 0x%08lx " - "(pgoffset %d)\n", key, offset, pageOffset); - - bind.pg_start = pageOffset; - bind.key = key; - - if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " - "binding of gart memory with key %d\n" - "\tat offset 0x%lx failed (%s)\n", - key, offset, strerror(errno)); - return FALSE; - } - - return TRUE; -} - - -/* Unbind GART memory with "key" */ -Bool -xf86UnbindGARTMemory(int screenNum, int key) -{ - struct _agp_unbind unbind; - - if (!GARTInit(screenNum) || acquiredScreen != screenNum) - return FALSE; - - if (acquiredScreen != screenNum) { - xf86DrvMsg(screenNum, X_ERROR, - "xf86UnbindGARTMemory: AGP not acquired by this screen\n"); - return FALSE; - } - - unbind.priority = 0; - unbind.key = key; - - if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86UnbindGARTMemory: " - "unbinding of gart memory with key %d " - "failed (%s)\n", key, strerror(errno)); - return FALSE; - } - - xf86DrvMsgVerb(screenNum, X_INFO, 3, - "xf86UnbindGARTMemory: unbind key %d\n", key); - - return TRUE; -} - - -/* XXX Interface may change. */ -Bool -xf86EnableAGP(int screenNum, CARD32 mode) -{ - agp_setup setup; - - if (!GARTInit(screenNum) || acquiredScreen != screenNum) - return FALSE; - - setup.agp_mode = mode; - if (ioctl(gartFd, AGPIOC_SETUP, &setup) != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86EnableAGP: " - "AGPIOC_SETUP with mode %ld failed (%s)\n", - (unsigned long)mode, strerror(errno)); - return FALSE; - } - - return TRUE; -} - +/* + * Abstraction of the AGP GART interface. + * + * This version is for Linux and Free/Open/NetBSD. + * + * Copyright © 2000 VA Linux Systems, Inc. + * Copyright © 2001 The XFree86 Project, Inc. + */ + + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#include "xf86OSpriv.h" + +#if defined(linux) +#include <asm/ioctl.h> +#include <linux/agpgart.h> +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +#include <sys/ioctl.h> +#include <sys/agpio.h> +#endif + +#ifndef AGP_DEVICE +#define AGP_DEVICE "/dev/agpgart" +#endif +/* AGP page size is independent of the host page size. */ +#ifndef AGP_PAGE_SIZE +#define AGP_PAGE_SIZE 4096 +#endif +#define AGPGART_MAJOR_VERSION 0 +#define AGPGART_MINOR_VERSION 99 + +static int gartFd = -1; +static int acquiredScreen = -1; +static Bool initDone = FALSE; +/* + * Close /dev/agpgart. This frees all associated memory allocated during + * this server generation. + */ +Bool +xf86GARTCloseScreen(int screenNum) +{ + if(gartFd != -1) { + close(gartFd); + acquiredScreen = -1; + gartFd = -1; + initDone = FALSE; + } + return TRUE; +} + +/* + * Open /dev/agpgart. Keep it open until xf86GARTCloseScreen is called. + */ +static Bool +GARTInit(int screenNum) +{ + struct _agp_info agpinf; + + if (initDone) + return (gartFd != -1); + + initDone = TRUE; + + if (gartFd == -1) + gartFd = open(AGP_DEVICE, O_RDWR, 0); + else + return FALSE; + + if (gartFd == -1) { + xf86DrvMsg(screenNum, X_ERROR, + "GARTInit: Unable to open " AGP_DEVICE " (%s)\n", + strerror(errno)); + return FALSE; + } + + xf86AcquireGART(-1); + /* Check the kernel driver version. */ + if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { + xf86DrvMsg(screenNum, X_ERROR, + "GARTInit: AGPIOC_INFO failed (%s)\n", strerror(errno)); + close(gartFd); + gartFd = -1; + return FALSE; + } + xf86ReleaseGART(-1); + +#if defined(linux) + /* Per Dave Jones, every effort will be made to keep the + * agpgart interface backwards compatible, so allow all + * future versions. + */ + if ( +#if (AGPGART_MAJOR_VERSION > 0) /* quiet compiler */ + agpinf.version.major < AGPGART_MAJOR_VERSION || +#endif + (agpinf.version.major == AGPGART_MAJOR_VERSION && + agpinf.version.minor < AGPGART_MINOR_VERSION)) { + xf86DrvMsg(screenNum, X_ERROR, + "GARTInit: Kernel agpgart driver version is not current" + " (%d.%d vs %d.%d)\n", + agpinf.version.major, agpinf.version.minor, + AGPGART_MAJOR_VERSION, AGPGART_MINOR_VERSION); + close(gartFd); + gartFd = -1; + return FALSE; + } +#endif + + return TRUE; +} + +Bool +xf86AgpGARTSupported(void) +{ + return GARTInit(-1); +} + +AgpInfoPtr +xf86GetAGPInfo(int screenNum) +{ + struct _agp_info agpinf; + AgpInfoPtr info; + + if (!GARTInit(screenNum)) + return NULL; + + + if ((info = calloc(sizeof(AgpInfo), 1)) == NULL) { + xf86DrvMsg(screenNum, X_ERROR, + "xf86GetAGPInfo: Failed to allocate AgpInfo\n"); + return NULL; + } + + memset((char*)&agpinf, 0, sizeof(agpinf)); + + if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { + xf86DrvMsg(screenNum, X_ERROR, + "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n", + strerror(errno)); + return NULL; + } + + info->bridgeId = agpinf.bridge_id; + info->agpMode = agpinf.agp_mode; + info->base = agpinf.aper_base; + info->size = agpinf.aper_size; + info->totalPages = agpinf.pg_total; + info->systemPages = agpinf.pg_system; + info->usedPages = agpinf.pg_used; + + xf86DrvMsg(screenNum, X_INFO, "Kernel reported %zu total, %zu used\n", agpinf.pg_total, agpinf.pg_used); + + return info; +} + +/* + * XXX If multiple screens can acquire the GART, should we have a reference + * count instead of using acquiredScreen? + */ + +Bool +xf86AcquireGART(int screenNum) +{ + if (screenNum != -1 && !GARTInit(screenNum)) + return FALSE; + + if (screenNum == -1 || acquiredScreen != screenNum) { + if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) { + xf86DrvMsg(screenNum, X_WARNING, + "xf86AcquireGART: AGPIOC_ACQUIRE failed (%s)\n", + strerror(errno)); + return FALSE; + } + acquiredScreen = screenNum; + } + return TRUE; +} + +Bool +xf86ReleaseGART(int screenNum) +{ + if (screenNum != -1 && !GARTInit(screenNum)) + return FALSE; + + if (acquiredScreen == screenNum) { + /* + * The FreeBSD agp driver removes allocations on release. + * The Linux driver doesn't. xf86ReleaseGART() is expected + * to give up access to the GART, but not to remove any + * allocations. + */ +#if !defined(linux) + if (screenNum == -1) +#endif + { + if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) { + xf86DrvMsg(screenNum, X_WARNING, + "xf86ReleaseGART: AGPIOC_RELEASE failed (%s)\n", + strerror(errno)); + return FALSE; + } + acquiredScreen = -1; + } + return TRUE; + } + return FALSE; +} + +int +xf86AllocateGARTMemory(int screenNum, unsigned long size, int type, + unsigned long *physical) +{ + struct _agp_allocate alloc; + int pages; + + /* + * Allocates "size" bytes of GART memory (rounds up to the next + * page multiple) or type "type". A handle (key) for the allocated + * memory is returned. On error, the return value is -1. + */ + + if (!GARTInit(screenNum) || acquiredScreen != screenNum) + return -1; + + pages = (size / AGP_PAGE_SIZE); + if (size % AGP_PAGE_SIZE != 0) + pages++; + + /* XXX check for pages == 0? */ + + alloc.pg_count = pages; + alloc.type = type; + + if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86AllocateGARTMemory: " + "allocation of %d pages failed\n\t(%s)\n", pages, + strerror(errno)); + return -1; + } + + if (physical) + *physical = alloc.physical; + + return alloc.key; +} + +Bool +xf86DeallocateGARTMemory(int screenNum, int key) +{ + if (!GARTInit(screenNum) || acquiredScreen != screenNum) + return FALSE; + + if (acquiredScreen != screenNum) { + xf86DrvMsg(screenNum, X_ERROR, + "xf86UnbindGARTMemory: AGP not acquired by this screen\n"); + return FALSE; + } + +#ifdef __linux__ + if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *)key) != 0) { +#else + if (ioctl(gartFd, AGPIOC_DEALLOCATE, &key) != 0) { +#endif + xf86DrvMsg(screenNum, X_WARNING,"xf86DeAllocateGARTMemory: " + "deallocation gart memory with key %d failed\n\t(%s)\n", + key, strerror(errno)); + return FALSE; + } + + return TRUE; +} + +/* Bind GART memory with "key" at "offset" */ +Bool +xf86BindGARTMemory(int screenNum, int key, unsigned long offset) +{ + struct _agp_bind bind; + int pageOffset; + + if (!GARTInit(screenNum) || acquiredScreen != screenNum) + return FALSE; + + if (acquiredScreen != screenNum) { + xf86DrvMsg(screenNum, X_ERROR, + "xf86BindGARTMemory: AGP not acquired by this screen\n"); + return FALSE; + } + + if (offset % AGP_PAGE_SIZE != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " + "offset (0x%lx) is not page-aligned (%d)\n", + offset, AGP_PAGE_SIZE); + return FALSE; + } + pageOffset = offset / AGP_PAGE_SIZE; + + xf86DrvMsgVerb(screenNum, X_INFO, 3, + "xf86BindGARTMemory: bind key %d at 0x%08lx " + "(pgoffset %d)\n", key, offset, pageOffset); + + bind.pg_start = pageOffset; + bind.key = key; + + if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " + "binding of gart memory with key %d\n" + "\tat offset 0x%lx failed (%s)\n", + key, offset, strerror(errno)); + return FALSE; + } + + return TRUE; +} + + +/* Unbind GART memory with "key" */ +Bool +xf86UnbindGARTMemory(int screenNum, int key) +{ + struct _agp_unbind unbind; + + if (!GARTInit(screenNum) || acquiredScreen != screenNum) + return FALSE; + + if (acquiredScreen != screenNum) { + xf86DrvMsg(screenNum, X_ERROR, + "xf86UnbindGARTMemory: AGP not acquired by this screen\n"); + return FALSE; + } + + unbind.priority = 0; + unbind.key = key; + + if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86UnbindGARTMemory: " + "unbinding of gart memory with key %d " + "failed (%s)\n", key, strerror(errno)); + return FALSE; + } + + xf86DrvMsgVerb(screenNum, X_INFO, 3, + "xf86UnbindGARTMemory: unbind key %d\n", key); + + return TRUE; +} + + +/* XXX Interface may change. */ +Bool +xf86EnableAGP(int screenNum, CARD32 mode) +{ + agp_setup setup; + + if (!GARTInit(screenNum) || acquiredScreen != screenNum) + return FALSE; + + setup.agp_mode = mode; + if (ioctl(gartFd, AGPIOC_SETUP, &setup) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86EnableAGP: " + "AGPIOC_SETUP with mode %ld failed (%s)\n", + (unsigned long)mode, strerror(errno)); + return FALSE; + } + + return TRUE; +} + diff --git a/xorg-server/hw/xfree86/os-support/linux/lnx_video.c b/xorg-server/hw/xfree86/os-support/linux/lnx_video.c index 26a17425a..a515b4080 100644 --- a/xorg-server/hw/xfree86/os-support/linux/lnx_video.c +++ b/xorg-server/hw/xfree86/os-support/linux/lnx_video.c @@ -1,878 +1,878 @@ -/* - * Copyright 1992 by Orest Zborowski <obz@Kodak.com> - * Copyright 1993 by David Wexelblat <dwex@goblin.org> - * - * 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 names of Orest Zborowski and David Wexelblat - * not be used in advertising or publicity pertaining to distribution of - * the software without specific, written prior permission. Orest Zborowski - * and David Wexelblat make no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * OREST ZBOROWSKI AND DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID WEXELBLAT 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_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <errno.h> -#include <string.h> - -#include <X11/X.h> -#include "input.h" -#include "scrnintstr.h" - -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" -#include "xf86OSpriv.h" -#ifdef __alpha__ -#include "shared/xf86Axp.h" -#endif - -#ifdef HAS_MTRR_SUPPORT -#include <asm/mtrr.h> -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -static Bool ExtendedEnabled = FALSE; - -#ifdef __ia64__ - -#include "compiler.h" -#include <sys/io.h> - -#elif !defined(__powerpc__) && \ - !defined(__mc68000__) && \ - !defined(__sparc__) && \ - !defined(__mips__) && \ - !defined(__arm__) - -/* - * Due to conflicts with "compiler.h", don't rely on <sys/io.h> to declare - * these. - */ -extern int ioperm(unsigned long __from, unsigned long __num, int __turn_on); -extern int iopl(int __level); - -#endif - -#ifdef __alpha__ -# define BUS_BASE bus_base -#else -#define BUS_BASE (0) -#endif /* __alpha__ */ - -/***************************************************************************/ -/* Video Memory Mapping section */ -/***************************************************************************/ - -static pointer mapVidMem(int, unsigned long, unsigned long, int); -static void unmapVidMem(int, pointer, unsigned long); -#if defined (__alpha__) -extern void sethae(unsigned long hae); -extern unsigned long _bus_base __P ((void)) __attribute__ ((const)); -extern unsigned long _bus_base_sparse __P ((void)) __attribute__ ((const)); - -static pointer mapVidMemSparse(int, unsigned long, unsigned long, int); -extern axpDevice lnxGetAXP(void); -static void unmapVidMemSparse(int, pointer, unsigned long); -static axpDevice axpSystem = -1; -static Bool needSparse; -static unsigned long hae_thresh; -static unsigned long hae_mask; -static unsigned long bus_base; -#endif - -#ifdef HAS_MTRR_SUPPORT - -#define SPLIT_WC_REGIONS 1 - -static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType); -static void undoWC(int, pointer); - -/* The file desc for /proc/mtrr. Once opened, left opened, and the mtrr - driver will clean up when we exit. */ -#define MTRR_FD_UNOPENED (-1) /* We have yet to open /proc/mtrr */ -#define MTRR_FD_PROBLEM (-2) /* We tried to open /proc/mtrr, but had - a problem. */ -static int mtrr_fd = MTRR_FD_UNOPENED; - -/* Open /proc/mtrr. FALSE on failure. Will always fail on Linux 2.0, - and will fail on Linux 2.2 with MTRR support configured out, - so verbosity should be chosen appropriately. */ -static Bool -mtrr_open(int verbosity) -{ - /* Only report absence of /proc/mtrr once. */ - static Bool warned = FALSE; - - if (mtrr_fd == MTRR_FD_UNOPENED) { - mtrr_fd = open("/proc/mtrr", O_WRONLY); - - if (mtrr_fd < 0) - mtrr_fd = MTRR_FD_PROBLEM; - } - - if (mtrr_fd == MTRR_FD_PROBLEM) { - /* To make sure we only ever warn once, need to check - verbosity outside xf86MsgVerb */ - if (!warned && verbosity <= xf86GetVerbosity()) { - xf86MsgVerb(X_WARNING, verbosity, - "System lacks support for changing MTRRs\n"); - warned = TRUE; - } - - return FALSE; - } - else - return TRUE; -} - -/* - * We maintain a list of WC regions for each physical mapping so they can - * be undone when unmapping. - */ - -struct mtrr_wc_region { - struct mtrr_sentry sentry; - Bool added; /* added WC or removed it */ - struct mtrr_wc_region * next; -}; - - -static struct mtrr_wc_region * -mtrr_cull_wc_region(int screenNum, unsigned long base, unsigned long size, - MessageType from) -{ - /* Some BIOS writers thought that setting wc over the mmio - region of a graphics devices was a good idea. Try to fix - it. */ - - struct mtrr_gentry gent; - struct mtrr_wc_region *wcreturn = NULL, *wcr; - int count, ret=0; - - /* Linux 2.0 users should not get a warning without -verbose */ - if (!mtrr_open(2)) - return NULL; - - for (gent.regnum = 0; - ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; - gent.regnum++) { - if (gent.type != MTRR_TYPE_WRCOMB - || gent.base + gent.size <= base - || base + size <= gent.base) - continue; - - /* Found an overlapping region. Delete it. */ - - wcr = xalloc(sizeof(*wcr)); - if (!wcr) - return NULL; - wcr->sentry.base = gent.base; - wcr->sentry.size = gent.size; - wcr->sentry.type = MTRR_TYPE_WRCOMB; - wcr->added = FALSE; - - count = 3; - while (count-- && - (ret = ioctl(mtrr_fd, MTRRIOC_KILL_ENTRY, &(wcr->sentry))) < 0); - - if (ret >= 0) { - xf86DrvMsg(screenNum, from, - "Removed MMIO write-combining range " - "(0x%lx,0x%lx)\n", - (unsigned long) gent.base, (unsigned long) gent.size); - wcr->next = wcreturn; - wcreturn = wcr; - gent.regnum--; - } else { - xfree(wcr); - xf86DrvMsgVerb(screenNum, X_WARNING, 0, - "Failed to remove MMIO " - "write-combining range (0x%lx,0x%lx)\n", - gent.base, (unsigned long) gent.size); - } - } - return wcreturn; -} - - -static struct mtrr_wc_region * -mtrr_remove_offending(int screenNum, unsigned long base, unsigned long size, - MessageType from) -{ - struct mtrr_gentry gent; - struct mtrr_wc_region *wcreturn = NULL, **wcr; - - if (!mtrr_open(2)) - return NULL; - - wcr = &wcreturn; - for (gent.regnum = 0; - ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; gent.regnum++ ) { - if (gent.type == MTRR_TYPE_WRCOMB - && ((gent.base >= base && gent.base + gent.size < base + size) || - (gent.base > base && gent.base + gent.size <= base + size))) { - *wcr = mtrr_cull_wc_region(screenNum, gent.base, gent.size, from); - if (*wcr) gent.regnum--; - while(*wcr) { - wcr = &((*wcr)->next); - } - } - } - return wcreturn; -} - - -static struct mtrr_wc_region * -mtrr_add_wc_region(int screenNum, unsigned long base, unsigned long size, - MessageType from) -{ - struct mtrr_wc_region **wcr, *wcreturn, *curwcr; - - /* - * There can be only one.... - */ - - wcreturn = mtrr_remove_offending(screenNum, base, size, from); - wcr = &wcreturn; - while (*wcr) { - wcr = &((*wcr)->next); - } - - /* Linux 2.0 should not warn, unless the user explicitly asks for - WC. */ - - if (!mtrr_open(from == X_CONFIG ? 0 : 2)) - return wcreturn; - - *wcr = curwcr = xalloc(sizeof(**wcr)); - if (!curwcr) - return wcreturn; - - curwcr->sentry.base = base; - curwcr->sentry.size = size; - curwcr->sentry.type = MTRR_TYPE_WRCOMB; - curwcr->added = TRUE; - curwcr->next = NULL; - -#if SPLIT_WC_REGIONS - /* - * Splits up the write-combining region if it is not aligned on a - * size boundary. - */ - - { - unsigned long lbase, d_size = 1; - unsigned long n_size = size; - unsigned long n_base = base; - - for (lbase = n_base, d_size = 1; !(lbase & 1); - lbase = lbase >> 1, d_size <<= 1); - while (d_size > n_size) - d_size = d_size >> 1; - DebugF("WC_BASE: 0x%lx WC_END: 0x%lx\n",base,base+d_size-1); - n_base += d_size; - n_size -= d_size; - if (n_size) { - xf86DrvMsgVerb(screenNum,X_INFO,3,"Splitting WC range: " - "base: 0x%lx, size: 0x%lx\n",base,size); - curwcr->next = mtrr_add_wc_region(screenNum, n_base, n_size,from); - } - curwcr->sentry.size = d_size; - } - - /*****************************************************************/ -#endif /* SPLIT_WC_REGIONS */ - - if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &curwcr->sentry) >= 0) { - /* Avoid printing on every VT switch */ - if (xf86ServerIsInitialising()) { - xf86DrvMsg(screenNum, from, - "Write-combining range (0x%lx,0x%lx)\n", - base, size); - } - return wcreturn; - } - else { - *wcr = curwcr->next; - xfree(curwcr); - - /* Don't complain about the VGA region: MTRR fixed - regions aren't currently supported, but might be in - the future. */ - if ((unsigned long)base >= 0x100000) { - xf86DrvMsgVerb(screenNum, X_WARNING, 0, - "Failed to set up write-combining range " - "(0x%lx,0x%lx)\n", base, size); - } - return wcreturn; - } -} - -static void -mtrr_undo_wc_region(int screenNum, struct mtrr_wc_region *wcr) -{ - struct mtrr_wc_region *p, *prev; - - if (mtrr_fd >= 0) { - p = wcr; - while (p) { - if (p->added) - ioctl(mtrr_fd, MTRRIOC_DEL_ENTRY, &p->sentry); - prev = p; - p = p->next; - xfree(prev); - } - } -} - -static pointer -setWC(int screenNum, unsigned long base, unsigned long size, Bool enable, - MessageType from) -{ - if (enable) - return mtrr_add_wc_region(screenNum, base, size, from); - else - return mtrr_cull_wc_region(screenNum, base, size, from); -} - -static void -undoWC(int screenNum, pointer regioninfo) -{ - mtrr_undo_wc_region(screenNum, regioninfo); -} - -#endif /* HAS_MTRR_SUPPORT */ - -void -xf86OSInitVidMem(VidMemInfoPtr pVidMem) -{ - pVidMem->linearSupported = TRUE; -#ifdef __alpha__ - if (axpSystem == -1) { - axpSystem = lnxGetAXP(); - if ((needSparse = (_bus_base_sparse() > 0))) { - hae_thresh = xf86AXPParams[axpSystem].hae_thresh; - hae_mask = xf86AXPParams[axpSystem].hae_mask; - } - bus_base = _bus_base(); - } - if (needSparse) { - xf86Msg(X_INFO,"Machine needs sparse mapping\n"); - pVidMem->mapMem = mapVidMemSparse; - pVidMem->unmapMem = unmapVidMemSparse; - } else { - xf86Msg(X_INFO,"Machine type has 8/16 bit access\n"); - pVidMem->mapMem = mapVidMem; - pVidMem->unmapMem = unmapVidMem; - } -#else - pVidMem->mapMem = mapVidMem; - pVidMem->unmapMem = unmapVidMem; -#endif /* __alpha__ */ - - -#ifdef HAS_MTRR_SUPPORT - pVidMem->setWC = setWC; - pVidMem->undoWC = undoWC; -#endif - pVidMem->initialised = TRUE; -} - -#ifdef __sparc__ -/* Basically, you simply cannot do this on Sparc. You have to do something portable - * like use /dev/fb* or mmap() on /proc/bus/pci/X/Y nodes. -DaveM - */ -static pointer mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags) -{ - return NULL; -} -#else -static pointer -mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags) -{ - pointer base; - int fd; - int mapflags = MAP_SHARED; - int prot; - memType realBase, alignOff; - - realBase = Base & ~(getpagesize() - 1); - alignOff = Base - realBase; - DebugF("base: %lx, realBase: %lx, alignOff: %lx \n", - Base,realBase,alignOff); - -#if defined(__ia64__) || defined(__arm__) || defined(__s390__) -#ifndef MAP_WRITECOMBINED -#define MAP_WRITECOMBINED 0x00010000 -#endif -#ifndef MAP_NONCACHED -#define MAP_NONCACHED 0x00020000 -#endif - if(flags & VIDMEM_FRAMEBUFFER) - mapflags |= MAP_WRITECOMBINED; - else - mapflags |= MAP_NONCACHED; -#endif - -#if 0 - /* this will disappear when people upgrade their kernels */ - fd = open(DEV_MEM, - ((flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR) | O_SYNC); -#else - fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR); -#endif - if (fd < 0) - { - FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n", - strerror(errno)); - } - - if (flags & VIDMEM_READONLY) - prot = PROT_READ; - else - prot = PROT_READ | PROT_WRITE; - - /* This requires linux-0.99.pl10 or above */ - base = mmap((caddr_t)0, Size + alignOff, prot, mapflags, fd, - (off_t)realBase + BUS_BASE); - close(fd); - if (base == MAP_FAILED) { - FatalError("xf86MapVidMem: Could not mmap framebuffer" - " (0x%08lx,0x%lx) (%s)\n", Base, Size, - strerror(errno)); - } - DebugF("base: %lx aligned base: %lx\n",base, base + alignOff); - return (char *)base + alignOff; -} -#endif /* !(__sparc__) */ - -static void -unmapVidMem(int ScreenNum, pointer Base, unsigned long Size) -{ - memType alignOff = (memType)Base - - ((memType)Base & ~(getpagesize() - 1)); - - DebugF("alignment offset: %lx\n",alignOff); - munmap((caddr_t)((memType)Base - alignOff), (Size + alignOff)); -} - - -/***************************************************************************/ -/* I/O Permissions section */ -/***************************************************************************/ - -#if defined(__powerpc__) -volatile unsigned char *ioBase = NULL; - -#ifndef __NR_pciconfig_iobase -#define __NR_pciconfig_iobase 200 -#endif - -#endif - -Bool -xf86EnableIO(void) -{ -#if defined(__powerpc__) - int fd; - unsigned int ioBase_phys; -#endif - - if (ExtendedEnabled) - return TRUE; - -#if defined(__powerpc__) - ioBase_phys = syscall(__NR_pciconfig_iobase, 2, 0, 0); - - fd = open("/dev/mem", O_RDWR); - if (ioBase == NULL) { - ioBase = (volatile unsigned char *)mmap(0, 0x20000, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, - ioBase_phys); -/* Should this be fatal or just a warning? */ -#if 0 - if (ioBase == MAP_FAILED) { - xf86Msg(X_WARNING, - "xf86EnableIOPorts: Failed to map iobase (%s)\n", - strerror(errno)); - return FALSE; - } -#endif - } - close(fd); -#elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__s390__) && !defined(__arm__) && !defined(__m32r__) - if (ioperm(0, 1024, 1) || iopl(3)) { - if (errno == ENODEV) - ErrorF("xf86EnableIOPorts: no I/O ports found\n"); - else - FatalError("xf86EnableIOPorts: failed to set IOPL" - " for I/O (%s)\n", strerror(errno)); - return FALSE; - } -# if !defined(__alpha__) - ioperm(0x40,4,0); /* trap access to the timer chip */ - ioperm(0x60,4,0); /* trap access to the keyboard controller */ -# endif -#endif - ExtendedEnabled = TRUE; - - return TRUE; -} - -void -xf86DisableIO(void) -{ - if (!ExtendedEnabled) - return; -#if defined(__powerpc__) - munmap(ioBase, 0x20000); - ioBase = NULL; -#elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__arm__) && !defined(__s390__) && !defined(__m32r__) - iopl(0); - ioperm(0, 1024, 0); -#endif - ExtendedEnabled = FALSE; - - return; -} - -#if defined (__alpha__) - -#define vuip volatile unsigned int * - -extern int readDense8(pointer Base, register unsigned long Offset); -extern int readDense16(pointer Base, register unsigned long Offset); -extern int readDense32(pointer Base, register unsigned long Offset); -extern void -writeDenseNB8(int Value, pointer Base, register unsigned long Offset); -extern void -writeDenseNB16(int Value, pointer Base, register unsigned long Offset); -extern void -writeDenseNB32(int Value, pointer Base, register unsigned long Offset); -extern void -writeDense8(int Value, pointer Base, register unsigned long Offset); -extern void -writeDense16(int Value, pointer Base, register unsigned long Offset); -extern void -writeDense32(int Value, pointer Base, register unsigned long Offset); - -static int readSparse8(pointer Base, register unsigned long Offset); -static int readSparse16(pointer Base, register unsigned long Offset); -static int readSparse32(pointer Base, register unsigned long Offset); -static void -writeSparseNB8(int Value, pointer Base, register unsigned long Offset); -static void -writeSparseNB16(int Value, pointer Base, register unsigned long Offset); -static void -writeSparseNB32(int Value, pointer Base, register unsigned long Offset); -static void -writeSparse8(int Value, pointer Base, register unsigned long Offset); -static void -writeSparse16(int Value, pointer Base, register unsigned long Offset); -static void -writeSparse32(int Value, pointer Base, register unsigned long Offset); - -#define DENSE_BASE 0x2ff00000000UL -#define SPARSE_BASE 0x30000000000UL - -static unsigned long msb_set = 0; - -static pointer -mapVidMemSparse(int ScreenNum, unsigned long Base, unsigned long Size, int flags) -{ - int fd, prot; - unsigned long ret, rets = 0; - - static Bool was_here = FALSE; - - if (!was_here) { - was_here = TRUE; - - xf86WriteMmio8 = writeSparse8; - xf86WriteMmio16 = writeSparse16; - xf86WriteMmio32 = writeSparse32; - xf86WriteMmioNB8 = writeSparseNB8; - xf86WriteMmioNB16 = writeSparseNB16; - xf86WriteMmioNB32 = writeSparseNB32; - xf86ReadMmio8 = readSparse8; - xf86ReadMmio16 = readSparse16; - xf86ReadMmio32 = readSparse32; - } - - fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR); - if (fd < 0) { - FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n", - strerror(errno)); - } - -#if 0 - xf86Msg(X_INFO,"mapVidMemSparse: try Base 0x%lx size 0x%lx flags 0x%x\n", - Base, Size, flags); -#endif - - if (flags & VIDMEM_READONLY) - prot = PROT_READ; - else - prot = PROT_READ | PROT_WRITE; - - /* This requirers linux-0.99.pl10 or above */ - - /* - * Always do DENSE mmap, since read32/write32 currently require it. - */ - ret = (unsigned long)mmap((caddr_t)(DENSE_BASE + Base), Size, - prot, MAP_SHARED, fd, - (off_t) (bus_base + Base)); - - /* - * Do SPARSE mmap only when MMIO and not MMIO_32BIT, or FRAMEBUFFER - * and SPARSE (which should require the use of read/write macros). - * - * By not SPARSE mmapping an 8MB framebuffer, we can save approx. 256K - * bytes worth of pagetable (32 pages). - */ - if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) || - ((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE))) - { - rets = (unsigned long)mmap((caddr_t)(SPARSE_BASE + (Base << 5)), - Size << 5, prot, MAP_SHARED, fd, - (off_t) _bus_base_sparse() + (Base << 5)); - } - - close(fd); - - if (ret == (unsigned long)MAP_FAILED) { - FatalError("xf86MapVidMemSparse: Could not (dense) mmap fb (%s)\n", - strerror(errno)); - } - - if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) || - ((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE))) - { - if (rets == (unsigned long)MAP_FAILED || - rets != (SPARSE_BASE + (Base << 5))) - { - FatalError("mapVidMemSparse: Could not (sparse) mmap fb (%s)\n", - strerror(errno)); - } - } - -#if 1 - if (rets) - xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx" - " to DENSE at 0x%lx and SPARSE at 0x%lx\n", - Base, Size, ret, rets); - else - xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx" - " to DENSE only at 0x%lx\n", - Base, Size, ret); - -#endif - return (pointer) ret; -} - -static void -unmapVidMemSparse(int ScreenNum, pointer Base, unsigned long Size) -{ - unsigned long Offset = (unsigned long)Base - DENSE_BASE; -#if 1 - xf86Msg(X_INFO,"unmapVidMemSparse: unmapping Base 0x%lx Size 0x%lx\n", - Base, Size); -#endif - /* Unmap DENSE always. */ - munmap((caddr_t)Base, Size); - - /* Unmap SPARSE always, and ignore error in case we did not map it. */ - munmap((caddr_t)(SPARSE_BASE + (Offset << 5)), Size << 5); -} - -static int -readSparse8(pointer Base, register unsigned long Offset) -{ - register unsigned long result, shift; - register unsigned long msb; - - mem_barrier(); - Offset += (unsigned long)Base - DENSE_BASE; - shift = (Offset & 0x3) << 3; - if (Offset >= (hae_thresh)) { - msb = Offset & hae_mask; - Offset -= msb; - if (msb_set != msb) { - sethae(msb); - msb_set = msb; - } - } - - mem_barrier(); - result = *(vuip) (SPARSE_BASE + (Offset << 5)); - result >>= shift; - return 0xffUL & result; -} - -static int -readSparse16(pointer Base, register unsigned long Offset) -{ - register unsigned long result, shift; - register unsigned long msb; - - mem_barrier(); - Offset += (unsigned long)Base - DENSE_BASE; - shift = (Offset & 0x2) << 3; - if (Offset >= hae_thresh) { - msb = Offset & hae_mask; - Offset -= msb; - if (msb_set != msb) { - sethae(msb); - msb_set = msb; - } - } - - mem_barrier(); - result = *(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2))); - result >>= shift; - return 0xffffUL & result; -} - -static int -readSparse32(pointer Base, register unsigned long Offset) -{ - /* NOTE: this is really using DENSE. */ - mem_barrier(); - return *(vuip)((unsigned long)Base+(Offset)); -} - -static void -writeSparse8(int Value, pointer Base, register unsigned long Offset) -{ - register unsigned long msb; - register unsigned int b = Value & 0xffU; - - write_mem_barrier(); - Offset += (unsigned long)Base - DENSE_BASE; - if (Offset >= hae_thresh) { - msb = Offset & hae_mask; - Offset -= msb; - if (msb_set != msb) { - sethae(msb); - msb_set = msb; - } - } - - write_mem_barrier(); - *(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101; -} - -static void -writeSparse16(int Value, pointer Base, register unsigned long Offset) -{ - register unsigned long msb; - register unsigned int w = Value & 0xffffU; - - write_mem_barrier(); - Offset += (unsigned long)Base - DENSE_BASE; - if (Offset >= hae_thresh) { - msb = Offset & hae_mask; - Offset -= msb; - if (msb_set != msb) { - sethae(msb); - msb_set = msb; - } - } - - write_mem_barrier(); - *(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2))) = w * 0x00010001; -} - -static void -writeSparse32(int Value, pointer Base, register unsigned long Offset) -{ - /* NOTE: this is really using DENSE. */ - write_mem_barrier(); - *(vuip)((unsigned long)Base + (Offset)) = Value; - return; -} - -static void -writeSparseNB8(int Value, pointer Base, register unsigned long Offset) -{ - register unsigned long msb; - register unsigned int b = Value & 0xffU; - - Offset += (unsigned long)Base - DENSE_BASE; - if (Offset >= hae_thresh) { - msb = Offset & hae_mask; - Offset -= msb; - if (msb_set != msb) { - sethae(msb); - msb_set = msb; - } - } - *(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101; -} - -static void -writeSparseNB16(int Value, pointer Base, register unsigned long Offset) -{ - register unsigned long msb; - register unsigned int w = Value & 0xffffU; - - Offset += (unsigned long)Base - DENSE_BASE; - if (Offset >= hae_thresh) { - msb = Offset & hae_mask; - Offset -= msb; - if (msb_set != msb) { - sethae(msb); - msb_set = msb; - } - } - *(vuip)(SPARSE_BASE+(Offset<<5)+(1<<(5-2))) = w * 0x00010001; -} - -static void -writeSparseNB32(int Value, pointer Base, register unsigned long Offset) -{ - /* NOTE: this is really using DENSE. */ - *(vuip)((unsigned long)Base + (Offset)) = Value; - return; -} - -void (*xf86WriteMmio8)(int Value, pointer Base, unsigned long Offset) - = writeDense8; -void (*xf86WriteMmio16)(int Value, pointer Base, unsigned long Offset) - = writeDense16; -void (*xf86WriteMmio32)(int Value, pointer Base, unsigned long Offset) - = writeDense32; -void (*xf86WriteMmioNB8)(int Value, pointer Base, unsigned long Offset) - = writeDenseNB8; -void (*xf86WriteMmioNB16)(int Value, pointer Base, unsigned long Offset) - = writeDenseNB16; -void (*xf86WriteMmioNB32)(int Value, pointer Base, unsigned long Offset) - = writeDenseNB32; -int (*xf86ReadMmio8)(pointer Base, unsigned long Offset) - = readDense8; -int (*xf86ReadMmio16)(pointer Base, unsigned long Offset) - = readDense16; -int (*xf86ReadMmio32)(pointer Base, unsigned long Offset) - = readDense32; - -#endif /* __alpha__ */ +/* + * Copyright 1992 by Orest Zborowski <obz@Kodak.com> + * Copyright 1993 by David Wexelblat <dwex@goblin.org> + * + * 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 names of Orest Zborowski and David Wexelblat + * not be used in advertising or publicity pertaining to distribution of + * the software without specific, written prior permission. Orest Zborowski + * and David Wexelblat make no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * OREST ZBOROWSKI AND DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID WEXELBLAT 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_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <errno.h> +#include <string.h> + +#include <X11/X.h> +#include "input.h" +#include "scrnintstr.h" + +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#include "xf86OSpriv.h" +#ifdef __alpha__ +#include "shared/xf86Axp.h" +#endif + +#ifdef HAS_MTRR_SUPPORT +#include <asm/mtrr.h> +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +static Bool ExtendedEnabled = FALSE; + +#ifdef __ia64__ + +#include "compiler.h" +#include <sys/io.h> + +#elif !defined(__powerpc__) && \ + !defined(__mc68000__) && \ + !defined(__sparc__) && \ + !defined(__mips__) && \ + !defined(__arm__) + +/* + * Due to conflicts with "compiler.h", don't rely on <sys/io.h> to declare + * these. + */ +extern int ioperm(unsigned long __from, unsigned long __num, int __turn_on); +extern int iopl(int __level); + +#endif + +#ifdef __alpha__ +# define BUS_BASE bus_base +#else +#define BUS_BASE (0) +#endif /* __alpha__ */ + +/***************************************************************************/ +/* Video Memory Mapping section */ +/***************************************************************************/ + +static pointer mapVidMem(int, unsigned long, unsigned long, int); +static void unmapVidMem(int, pointer, unsigned long); +#if defined (__alpha__) +extern void sethae(unsigned long hae); +extern unsigned long _bus_base __P ((void)) __attribute__ ((const)); +extern unsigned long _bus_base_sparse __P ((void)) __attribute__ ((const)); + +static pointer mapVidMemSparse(int, unsigned long, unsigned long, int); +extern axpDevice lnxGetAXP(void); +static void unmapVidMemSparse(int, pointer, unsigned long); +static axpDevice axpSystem = -1; +static Bool needSparse; +static unsigned long hae_thresh; +static unsigned long hae_mask; +static unsigned long bus_base; +#endif + +#ifdef HAS_MTRR_SUPPORT + +#define SPLIT_WC_REGIONS 1 + +static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType); +static void undoWC(int, pointer); + +/* The file desc for /proc/mtrr. Once opened, left opened, and the mtrr + driver will clean up when we exit. */ +#define MTRR_FD_UNOPENED (-1) /* We have yet to open /proc/mtrr */ +#define MTRR_FD_PROBLEM (-2) /* We tried to open /proc/mtrr, but had + a problem. */ +static int mtrr_fd = MTRR_FD_UNOPENED; + +/* Open /proc/mtrr. FALSE on failure. Will always fail on Linux 2.0, + and will fail on Linux 2.2 with MTRR support configured out, + so verbosity should be chosen appropriately. */ +static Bool +mtrr_open(int verbosity) +{ + /* Only report absence of /proc/mtrr once. */ + static Bool warned = FALSE; + + if (mtrr_fd == MTRR_FD_UNOPENED) { + mtrr_fd = open("/proc/mtrr", O_WRONLY); + + if (mtrr_fd < 0) + mtrr_fd = MTRR_FD_PROBLEM; + } + + if (mtrr_fd == MTRR_FD_PROBLEM) { + /* To make sure we only ever warn once, need to check + verbosity outside xf86MsgVerb */ + if (!warned && verbosity <= xf86GetVerbosity()) { + xf86MsgVerb(X_WARNING, verbosity, + "System lacks support for changing MTRRs\n"); + warned = TRUE; + } + + return FALSE; + } + else + return TRUE; +} + +/* + * We maintain a list of WC regions for each physical mapping so they can + * be undone when unmapping. + */ + +struct mtrr_wc_region { + struct mtrr_sentry sentry; + Bool added; /* added WC or removed it */ + struct mtrr_wc_region * next; +}; + + +static struct mtrr_wc_region * +mtrr_cull_wc_region(int screenNum, unsigned long base, unsigned long size, + MessageType from) +{ + /* Some BIOS writers thought that setting wc over the mmio + region of a graphics devices was a good idea. Try to fix + it. */ + + struct mtrr_gentry gent; + struct mtrr_wc_region *wcreturn = NULL, *wcr; + int count, ret=0; + + /* Linux 2.0 users should not get a warning without -verbose */ + if (!mtrr_open(2)) + return NULL; + + for (gent.regnum = 0; + ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; + gent.regnum++) { + if (gent.type != MTRR_TYPE_WRCOMB + || gent.base + gent.size <= base + || base + size <= gent.base) + continue; + + /* Found an overlapping region. Delete it. */ + + wcr = malloc(sizeof(*wcr)); + if (!wcr) + return NULL; + wcr->sentry.base = gent.base; + wcr->sentry.size = gent.size; + wcr->sentry.type = MTRR_TYPE_WRCOMB; + wcr->added = FALSE; + + count = 3; + while (count-- && + (ret = ioctl(mtrr_fd, MTRRIOC_KILL_ENTRY, &(wcr->sentry))) < 0); + + if (ret >= 0) { + xf86DrvMsg(screenNum, from, + "Removed MMIO write-combining range " + "(0x%lx,0x%lx)\n", + (unsigned long) gent.base, (unsigned long) gent.size); + wcr->next = wcreturn; + wcreturn = wcr; + gent.regnum--; + } else { + free(wcr); + xf86DrvMsgVerb(screenNum, X_WARNING, 0, + "Failed to remove MMIO " + "write-combining range (0x%lx,0x%lx)\n", + gent.base, (unsigned long) gent.size); + } + } + return wcreturn; +} + + +static struct mtrr_wc_region * +mtrr_remove_offending(int screenNum, unsigned long base, unsigned long size, + MessageType from) +{ + struct mtrr_gentry gent; + struct mtrr_wc_region *wcreturn = NULL, **wcr; + + if (!mtrr_open(2)) + return NULL; + + wcr = &wcreturn; + for (gent.regnum = 0; + ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; gent.regnum++ ) { + if (gent.type == MTRR_TYPE_WRCOMB + && ((gent.base >= base && gent.base + gent.size < base + size) || + (gent.base > base && gent.base + gent.size <= base + size))) { + *wcr = mtrr_cull_wc_region(screenNum, gent.base, gent.size, from); + if (*wcr) gent.regnum--; + while(*wcr) { + wcr = &((*wcr)->next); + } + } + } + return wcreturn; +} + + +static struct mtrr_wc_region * +mtrr_add_wc_region(int screenNum, unsigned long base, unsigned long size, + MessageType from) +{ + struct mtrr_wc_region **wcr, *wcreturn, *curwcr; + + /* + * There can be only one.... + */ + + wcreturn = mtrr_remove_offending(screenNum, base, size, from); + wcr = &wcreturn; + while (*wcr) { + wcr = &((*wcr)->next); + } + + /* Linux 2.0 should not warn, unless the user explicitly asks for + WC. */ + + if (!mtrr_open(from == X_CONFIG ? 0 : 2)) + return wcreturn; + + *wcr = curwcr = malloc(sizeof(**wcr)); + if (!curwcr) + return wcreturn; + + curwcr->sentry.base = base; + curwcr->sentry.size = size; + curwcr->sentry.type = MTRR_TYPE_WRCOMB; + curwcr->added = TRUE; + curwcr->next = NULL; + +#if SPLIT_WC_REGIONS + /* + * Splits up the write-combining region if it is not aligned on a + * size boundary. + */ + + { + unsigned long lbase, d_size = 1; + unsigned long n_size = size; + unsigned long n_base = base; + + for (lbase = n_base, d_size = 1; !(lbase & 1); + lbase = lbase >> 1, d_size <<= 1); + while (d_size > n_size) + d_size = d_size >> 1; + DebugF("WC_BASE: 0x%lx WC_END: 0x%lx\n",base,base+d_size-1); + n_base += d_size; + n_size -= d_size; + if (n_size) { + xf86DrvMsgVerb(screenNum,X_INFO,3,"Splitting WC range: " + "base: 0x%lx, size: 0x%lx\n",base,size); + curwcr->next = mtrr_add_wc_region(screenNum, n_base, n_size,from); + } + curwcr->sentry.size = d_size; + } + + /*****************************************************************/ +#endif /* SPLIT_WC_REGIONS */ + + if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &curwcr->sentry) >= 0) { + /* Avoid printing on every VT switch */ + if (xf86ServerIsInitialising()) { + xf86DrvMsg(screenNum, from, + "Write-combining range (0x%lx,0x%lx)\n", + base, size); + } + return wcreturn; + } + else { + *wcr = curwcr->next; + free(curwcr); + + /* Don't complain about the VGA region: MTRR fixed + regions aren't currently supported, but might be in + the future. */ + if ((unsigned long)base >= 0x100000) { + xf86DrvMsgVerb(screenNum, X_WARNING, 0, + "Failed to set up write-combining range " + "(0x%lx,0x%lx)\n", base, size); + } + return wcreturn; + } +} + +static void +mtrr_undo_wc_region(int screenNum, struct mtrr_wc_region *wcr) +{ + struct mtrr_wc_region *p, *prev; + + if (mtrr_fd >= 0) { + p = wcr; + while (p) { + if (p->added) + ioctl(mtrr_fd, MTRRIOC_DEL_ENTRY, &p->sentry); + prev = p; + p = p->next; + free(prev); + } + } +} + +static pointer +setWC(int screenNum, unsigned long base, unsigned long size, Bool enable, + MessageType from) +{ + if (enable) + return mtrr_add_wc_region(screenNum, base, size, from); + else + return mtrr_cull_wc_region(screenNum, base, size, from); +} + +static void +undoWC(int screenNum, pointer regioninfo) +{ + mtrr_undo_wc_region(screenNum, regioninfo); +} + +#endif /* HAS_MTRR_SUPPORT */ + +void +xf86OSInitVidMem(VidMemInfoPtr pVidMem) +{ + pVidMem->linearSupported = TRUE; +#ifdef __alpha__ + if (axpSystem == -1) { + axpSystem = lnxGetAXP(); + if ((needSparse = (_bus_base_sparse() > 0))) { + hae_thresh = xf86AXPParams[axpSystem].hae_thresh; + hae_mask = xf86AXPParams[axpSystem].hae_mask; + } + bus_base = _bus_base(); + } + if (needSparse) { + xf86Msg(X_INFO,"Machine needs sparse mapping\n"); + pVidMem->mapMem = mapVidMemSparse; + pVidMem->unmapMem = unmapVidMemSparse; + } else { + xf86Msg(X_INFO,"Machine type has 8/16 bit access\n"); + pVidMem->mapMem = mapVidMem; + pVidMem->unmapMem = unmapVidMem; + } +#else + pVidMem->mapMem = mapVidMem; + pVidMem->unmapMem = unmapVidMem; +#endif /* __alpha__ */ + + +#ifdef HAS_MTRR_SUPPORT + pVidMem->setWC = setWC; + pVidMem->undoWC = undoWC; +#endif + pVidMem->initialised = TRUE; +} + +#ifdef __sparc__ +/* Basically, you simply cannot do this on Sparc. You have to do something portable + * like use /dev/fb* or mmap() on /proc/bus/pci/X/Y nodes. -DaveM + */ +static pointer mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags) +{ + return NULL; +} +#else +static pointer +mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags) +{ + pointer base; + int fd; + int mapflags = MAP_SHARED; + int prot; + memType realBase, alignOff; + + realBase = Base & ~(getpagesize() - 1); + alignOff = Base - realBase; + DebugF("base: %lx, realBase: %lx, alignOff: %lx \n", + Base,realBase,alignOff); + +#if defined(__ia64__) || defined(__arm__) || defined(__s390__) +#ifndef MAP_WRITECOMBINED +#define MAP_WRITECOMBINED 0x00010000 +#endif +#ifndef MAP_NONCACHED +#define MAP_NONCACHED 0x00020000 +#endif + if(flags & VIDMEM_FRAMEBUFFER) + mapflags |= MAP_WRITECOMBINED; + else + mapflags |= MAP_NONCACHED; +#endif + +#if 0 + /* this will disappear when people upgrade their kernels */ + fd = open(DEV_MEM, + ((flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR) | O_SYNC); +#else + fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR); +#endif + if (fd < 0) + { + FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n", + strerror(errno)); + } + + if (flags & VIDMEM_READONLY) + prot = PROT_READ; + else + prot = PROT_READ | PROT_WRITE; + + /* This requires linux-0.99.pl10 or above */ + base = mmap((caddr_t)0, Size + alignOff, prot, mapflags, fd, + (off_t)realBase + BUS_BASE); + close(fd); + if (base == MAP_FAILED) { + FatalError("xf86MapVidMem: Could not mmap framebuffer" + " (0x%08lx,0x%lx) (%s)\n", Base, Size, + strerror(errno)); + } + DebugF("base: %lx aligned base: %lx\n",base, base + alignOff); + return (char *)base + alignOff; +} +#endif /* !(__sparc__) */ + +static void +unmapVidMem(int ScreenNum, pointer Base, unsigned long Size) +{ + memType alignOff = (memType)Base + - ((memType)Base & ~(getpagesize() - 1)); + + DebugF("alignment offset: %lx\n",alignOff); + munmap((caddr_t)((memType)Base - alignOff), (Size + alignOff)); +} + + +/***************************************************************************/ +/* I/O Permissions section */ +/***************************************************************************/ + +#if defined(__powerpc__) +volatile unsigned char *ioBase = NULL; + +#ifndef __NR_pciconfig_iobase +#define __NR_pciconfig_iobase 200 +#endif + +#endif + +Bool +xf86EnableIO(void) +{ +#if defined(__powerpc__) + int fd; + unsigned int ioBase_phys; +#endif + + if (ExtendedEnabled) + return TRUE; + +#if defined(__powerpc__) + ioBase_phys = syscall(__NR_pciconfig_iobase, 2, 0, 0); + + fd = open("/dev/mem", O_RDWR); + if (ioBase == NULL) { + ioBase = (volatile unsigned char *)mmap(0, 0x20000, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, + ioBase_phys); +/* Should this be fatal or just a warning? */ +#if 0 + if (ioBase == MAP_FAILED) { + xf86Msg(X_WARNING, + "xf86EnableIOPorts: Failed to map iobase (%s)\n", + strerror(errno)); + return FALSE; + } +#endif + } + close(fd); +#elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__s390__) && !defined(__arm__) && !defined(__m32r__) + if (ioperm(0, 1024, 1) || iopl(3)) { + if (errno == ENODEV) + ErrorF("xf86EnableIOPorts: no I/O ports found\n"); + else + FatalError("xf86EnableIOPorts: failed to set IOPL" + " for I/O (%s)\n", strerror(errno)); + return FALSE; + } +# if !defined(__alpha__) + ioperm(0x40,4,0); /* trap access to the timer chip */ + ioperm(0x60,4,0); /* trap access to the keyboard controller */ +# endif +#endif + ExtendedEnabled = TRUE; + + return TRUE; +} + +void +xf86DisableIO(void) +{ + if (!ExtendedEnabled) + return; +#if defined(__powerpc__) + munmap(ioBase, 0x20000); + ioBase = NULL; +#elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__arm__) && !defined(__s390__) && !defined(__m32r__) + iopl(0); + ioperm(0, 1024, 0); +#endif + ExtendedEnabled = FALSE; + + return; +} + +#if defined (__alpha__) + +#define vuip volatile unsigned int * + +extern int readDense8(pointer Base, register unsigned long Offset); +extern int readDense16(pointer Base, register unsigned long Offset); +extern int readDense32(pointer Base, register unsigned long Offset); +extern void +writeDenseNB8(int Value, pointer Base, register unsigned long Offset); +extern void +writeDenseNB16(int Value, pointer Base, register unsigned long Offset); +extern void +writeDenseNB32(int Value, pointer Base, register unsigned long Offset); +extern void +writeDense8(int Value, pointer Base, register unsigned long Offset); +extern void +writeDense16(int Value, pointer Base, register unsigned long Offset); +extern void +writeDense32(int Value, pointer Base, register unsigned long Offset); + +static int readSparse8(pointer Base, register unsigned long Offset); +static int readSparse16(pointer Base, register unsigned long Offset); +static int readSparse32(pointer Base, register unsigned long Offset); +static void +writeSparseNB8(int Value, pointer Base, register unsigned long Offset); +static void +writeSparseNB16(int Value, pointer Base, register unsigned long Offset); +static void +writeSparseNB32(int Value, pointer Base, register unsigned long Offset); +static void +writeSparse8(int Value, pointer Base, register unsigned long Offset); +static void +writeSparse16(int Value, pointer Base, register unsigned long Offset); +static void +writeSparse32(int Value, pointer Base, register unsigned long Offset); + +#define DENSE_BASE 0x2ff00000000UL +#define SPARSE_BASE 0x30000000000UL + +static unsigned long msb_set = 0; + +static pointer +mapVidMemSparse(int ScreenNum, unsigned long Base, unsigned long Size, int flags) +{ + int fd, prot; + unsigned long ret, rets = 0; + + static Bool was_here = FALSE; + + if (!was_here) { + was_here = TRUE; + + xf86WriteMmio8 = writeSparse8; + xf86WriteMmio16 = writeSparse16; + xf86WriteMmio32 = writeSparse32; + xf86WriteMmioNB8 = writeSparseNB8; + xf86WriteMmioNB16 = writeSparseNB16; + xf86WriteMmioNB32 = writeSparseNB32; + xf86ReadMmio8 = readSparse8; + xf86ReadMmio16 = readSparse16; + xf86ReadMmio32 = readSparse32; + } + + fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR); + if (fd < 0) { + FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n", + strerror(errno)); + } + +#if 0 + xf86Msg(X_INFO,"mapVidMemSparse: try Base 0x%lx size 0x%lx flags 0x%x\n", + Base, Size, flags); +#endif + + if (flags & VIDMEM_READONLY) + prot = PROT_READ; + else + prot = PROT_READ | PROT_WRITE; + + /* This requirers linux-0.99.pl10 or above */ + + /* + * Always do DENSE mmap, since read32/write32 currently require it. + */ + ret = (unsigned long)mmap((caddr_t)(DENSE_BASE + Base), Size, + prot, MAP_SHARED, fd, + (off_t) (bus_base + Base)); + + /* + * Do SPARSE mmap only when MMIO and not MMIO_32BIT, or FRAMEBUFFER + * and SPARSE (which should require the use of read/write macros). + * + * By not SPARSE mmapping an 8MB framebuffer, we can save approx. 256K + * bytes worth of pagetable (32 pages). + */ + if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) || + ((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE))) + { + rets = (unsigned long)mmap((caddr_t)(SPARSE_BASE + (Base << 5)), + Size << 5, prot, MAP_SHARED, fd, + (off_t) _bus_base_sparse() + (Base << 5)); + } + + close(fd); + + if (ret == (unsigned long)MAP_FAILED) { + FatalError("xf86MapVidMemSparse: Could not (dense) mmap fb (%s)\n", + strerror(errno)); + } + + if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) || + ((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE))) + { + if (rets == (unsigned long)MAP_FAILED || + rets != (SPARSE_BASE + (Base << 5))) + { + FatalError("mapVidMemSparse: Could not (sparse) mmap fb (%s)\n", + strerror(errno)); + } + } + +#if 1 + if (rets) + xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx" + " to DENSE at 0x%lx and SPARSE at 0x%lx\n", + Base, Size, ret, rets); + else + xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx" + " to DENSE only at 0x%lx\n", + Base, Size, ret); + +#endif + return (pointer) ret; +} + +static void +unmapVidMemSparse(int ScreenNum, pointer Base, unsigned long Size) +{ + unsigned long Offset = (unsigned long)Base - DENSE_BASE; +#if 1 + xf86Msg(X_INFO,"unmapVidMemSparse: unmapping Base 0x%lx Size 0x%lx\n", + Base, Size); +#endif + /* Unmap DENSE always. */ + munmap((caddr_t)Base, Size); + + /* Unmap SPARSE always, and ignore error in case we did not map it. */ + munmap((caddr_t)(SPARSE_BASE + (Offset << 5)), Size << 5); +} + +static int +readSparse8(pointer Base, register unsigned long Offset) +{ + register unsigned long result, shift; + register unsigned long msb; + + mem_barrier(); + Offset += (unsigned long)Base - DENSE_BASE; + shift = (Offset & 0x3) << 3; + if (Offset >= (hae_thresh)) { + msb = Offset & hae_mask; + Offset -= msb; + if (msb_set != msb) { + sethae(msb); + msb_set = msb; + } + } + + mem_barrier(); + result = *(vuip) (SPARSE_BASE + (Offset << 5)); + result >>= shift; + return 0xffUL & result; +} + +static int +readSparse16(pointer Base, register unsigned long Offset) +{ + register unsigned long result, shift; + register unsigned long msb; + + mem_barrier(); + Offset += (unsigned long)Base - DENSE_BASE; + shift = (Offset & 0x2) << 3; + if (Offset >= hae_thresh) { + msb = Offset & hae_mask; + Offset -= msb; + if (msb_set != msb) { + sethae(msb); + msb_set = msb; + } + } + + mem_barrier(); + result = *(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2))); + result >>= shift; + return 0xffffUL & result; +} + +static int +readSparse32(pointer Base, register unsigned long Offset) +{ + /* NOTE: this is really using DENSE. */ + mem_barrier(); + return *(vuip)((unsigned long)Base+(Offset)); +} + +static void +writeSparse8(int Value, pointer Base, register unsigned long Offset) +{ + register unsigned long msb; + register unsigned int b = Value & 0xffU; + + write_mem_barrier(); + Offset += (unsigned long)Base - DENSE_BASE; + if (Offset >= hae_thresh) { + msb = Offset & hae_mask; + Offset -= msb; + if (msb_set != msb) { + sethae(msb); + msb_set = msb; + } + } + + write_mem_barrier(); + *(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101; +} + +static void +writeSparse16(int Value, pointer Base, register unsigned long Offset) +{ + register unsigned long msb; + register unsigned int w = Value & 0xffffU; + + write_mem_barrier(); + Offset += (unsigned long)Base - DENSE_BASE; + if (Offset >= hae_thresh) { + msb = Offset & hae_mask; + Offset -= msb; + if (msb_set != msb) { + sethae(msb); + msb_set = msb; + } + } + + write_mem_barrier(); + *(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2))) = w * 0x00010001; +} + +static void +writeSparse32(int Value, pointer Base, register unsigned long Offset) +{ + /* NOTE: this is really using DENSE. */ + write_mem_barrier(); + *(vuip)((unsigned long)Base + (Offset)) = Value; + return; +} + +static void +writeSparseNB8(int Value, pointer Base, register unsigned long Offset) +{ + register unsigned long msb; + register unsigned int b = Value & 0xffU; + + Offset += (unsigned long)Base - DENSE_BASE; + if (Offset >= hae_thresh) { + msb = Offset & hae_mask; + Offset -= msb; + if (msb_set != msb) { + sethae(msb); + msb_set = msb; + } + } + *(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101; +} + +static void +writeSparseNB16(int Value, pointer Base, register unsigned long Offset) +{ + register unsigned long msb; + register unsigned int w = Value & 0xffffU; + + Offset += (unsigned long)Base - DENSE_BASE; + if (Offset >= hae_thresh) { + msb = Offset & hae_mask; + Offset -= msb; + if (msb_set != msb) { + sethae(msb); + msb_set = msb; + } + } + *(vuip)(SPARSE_BASE+(Offset<<5)+(1<<(5-2))) = w * 0x00010001; +} + +static void +writeSparseNB32(int Value, pointer Base, register unsigned long Offset) +{ + /* NOTE: this is really using DENSE. */ + *(vuip)((unsigned long)Base + (Offset)) = Value; + return; +} + +void (*xf86WriteMmio8)(int Value, pointer Base, unsigned long Offset) + = writeDense8; +void (*xf86WriteMmio16)(int Value, pointer Base, unsigned long Offset) + = writeDense16; +void (*xf86WriteMmio32)(int Value, pointer Base, unsigned long Offset) + = writeDense32; +void (*xf86WriteMmioNB8)(int Value, pointer Base, unsigned long Offset) + = writeDenseNB8; +void (*xf86WriteMmioNB16)(int Value, pointer Base, unsigned long Offset) + = writeDenseNB16; +void (*xf86WriteMmioNB32)(int Value, pointer Base, unsigned long Offset) + = writeDenseNB32; +int (*xf86ReadMmio8)(pointer Base, unsigned long Offset) + = readDense8; +int (*xf86ReadMmio16)(pointer Base, unsigned long Offset) + = readDense16; +int (*xf86ReadMmio32)(pointer Base, unsigned long Offset) + = readDense32; + +#endif /* __alpha__ */ diff --git a/xorg-server/hw/xfree86/os-support/shared/posix_tty.c b/xorg-server/hw/xfree86/os-support/shared/posix_tty.c index da57939cf..7e2c4a181 100644 --- a/xorg-server/hw/xfree86/os-support/shared/posix_tty.c +++ b/xorg-server/hw/xfree86/os-support/shared/posix_tty.c @@ -1,655 +1,655 @@ -/* - * Copyright 1993-2003 by The XFree86 Project, Inc. - * - * 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. - */ -/* - * - * Copyright (c) 1997 Metro Link Incorporated - * - * 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 Metro Link shall not be - * used in advertising or otherwise to promote the sale, use or other dealings - * in this Software without prior written authorization from Metro Link. - * - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" - -static int -GetBaud (int baudrate) -{ -#ifdef B300 - if (baudrate == 300) - return B300; -#endif -#ifdef B1200 - if (baudrate == 1200) - return B1200; -#endif -#ifdef B2400 - if (baudrate == 2400) - return B2400; -#endif -#ifdef B4800 - if (baudrate == 4800) - return B4800; -#endif -#ifdef B9600 - if (baudrate == 9600) - return B9600; -#endif -#ifdef B19200 - if (baudrate == 19200) - return B19200; -#endif -#ifdef B38400 - if (baudrate == 38400) - return B38400; -#endif -#ifdef B57600 - if (baudrate == 57600) - return B57600; -#endif -#ifdef B115200 - if (baudrate == 115200) - return B115200; -#endif -#ifdef B230400 - if (baudrate == 230400) - return B230400; -#endif -#ifdef B460800 - if (baudrate == 460800) - return B460800; -#endif - return (0); -} - -int -xf86OpenSerial (pointer options) -{ - struct termios t; - int fd, i; - char *dev; - - dev = xf86SetStrOption (options, "Device", NULL); - if (!dev) - { - xf86Msg (X_ERROR, "xf86OpenSerial: No Device specified.\n"); - return (-1); - } - - SYSCALL (fd = open (dev, O_RDWR | O_NONBLOCK)); - if (fd == -1) - { - xf86Msg (X_ERROR, - "xf86OpenSerial: Cannot open device %s\n\t%s.\n", - dev, strerror (errno)); - xfree(dev); - return (-1); - } - - if (!isatty (fd)) - { - /* Allow non-tty devices to be opened. */ - xfree(dev); - return (fd); - } - - /* set up default port parameters */ - SYSCALL (tcgetattr (fd, &t)); - t.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR\ - |IGNCR|ICRNL|IXON); - t.c_oflag &= ~OPOST; - t.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - t.c_cflag &= ~(CSIZE|PARENB); - t.c_cflag |= CS8|CLOCAL; - - cfsetispeed (&t, B9600); - cfsetospeed (&t, B9600); - t.c_cc[VMIN] = 1; - t.c_cc[VTIME] = 0; - - SYSCALL (tcsetattr (fd, TCSANOW, &t)); - - if (xf86SetSerial (fd, options) == -1) - { - SYSCALL (close (fd)); - xfree(dev); - return (-1); - } - - SYSCALL (i = fcntl (fd, F_GETFL, 0)); - if (i == -1) - { - SYSCALL (close (fd)); - xfree(dev); - return (-1); - } - i &= ~O_NONBLOCK; - SYSCALL (i = fcntl (fd, F_SETFL, i)); - if (i == -1) - { - SYSCALL (close (fd)); - xfree(dev); - return (-1); - } - xfree(dev); - return (fd); -} - -int -xf86SetSerial (int fd, pointer options) -{ - struct termios t; - int val; - const char *s; - int baud, r; - - if (fd < 0) - return -1; - - /* Don't try to set parameters for non-tty devices. */ - if (!isatty(fd)) - return 0; - - SYSCALL (tcgetattr (fd, &t)); - - if ((val = xf86SetIntOption (options, "BaudRate", 0))) - { - if ((baud = GetBaud (val))) - { - cfsetispeed (&t, baud); - cfsetospeed (&t, baud); - } - else - { - xf86Msg (X_ERROR, - "Invalid Option BaudRate value: %d\n", val); - return (-1); - } - } - - if ((val = xf86SetIntOption (options, "StopBits", 0))) - { - switch (val) - { - case 1: - t.c_cflag &= ~(CSTOPB); - break; - case 2: - t.c_cflag |= CSTOPB; - break; - default: - xf86Msg (X_ERROR, - "Invalid Option StopBits value: %d\n", val); - return (-1); - break; - } - } - - if ((val = xf86SetIntOption (options, "DataBits", 0))) - { - switch (val) - { - case 5: - t.c_cflag &= ~(CSIZE); - t.c_cflag |= CS5; - break; - case 6: - t.c_cflag &= ~(CSIZE); - t.c_cflag |= CS6; - break; - case 7: - t.c_cflag &= ~(CSIZE); - t.c_cflag |= CS7; - break; - case 8: - t.c_cflag &= ~(CSIZE); - t.c_cflag |= CS8; - break; - default: - xf86Msg (X_ERROR, - "Invalid Option DataBits value: %d\n", val); - return (-1); - break; - } - } - - if ((s = xf86SetStrOption (options, "Parity", NULL))) - { - if (xf86NameCmp (s, "Odd") == 0) - { - t.c_cflag |= PARENB | PARODD; - } - else if (xf86NameCmp (s, "Even") == 0) - { - t.c_cflag |= PARENB; - t.c_cflag &= ~(PARODD); - } - else if (xf86NameCmp (s, "None") == 0) - { - t.c_cflag &= ~(PARENB); - } - else - { - xf86Msg (X_ERROR, "Invalid Option Parity value: %s\n", - s); - return (-1); - } - } - - if ((val = xf86SetIntOption (options, "Vmin", -1)) != -1) - { - t.c_cc[VMIN] = val; - } - if ((val = xf86SetIntOption (options, "Vtime", -1)) != -1) - { - t.c_cc[VTIME] = val; - } - - if ((s = xf86SetStrOption (options, "FlowControl", NULL))) - { - xf86MarkOptionUsedByName (options, "FlowControl"); - if (xf86NameCmp (s, "Xoff") == 0) - { - t.c_iflag |= IXOFF; - } - else if (xf86NameCmp (s, "Xon") == 0) - { - t.c_iflag |= IXON; - } - else if (xf86NameCmp (s, "XonXoff") == 0) - { - t.c_iflag |= IXON|IXOFF; - } - else if (xf86NameCmp (s, "None") == 0) - { - t.c_iflag &= ~(IXON | IXOFF); - } - else - { - xf86Msg (X_ERROR, - "Invalid Option FlowControl value: %s\n", s); - return (-1); - } - } - - if ((xf86SetBoolOption (options, "ClearDTR", FALSE))) - { -#ifdef CLEARDTR_SUPPORT -# if defined(TIOCMBIC) - val = TIOCM_DTR; - SYSCALL (ioctl(fd, TIOCMBIC, &val)); -# else - SYSCALL (ioctl(fd, TIOCCDTR, NULL)); -# endif -#else - xf86Msg (X_WARNING, - "Option ClearDTR not supported on this OS\n"); - return (-1); -#endif - xf86MarkOptionUsedByName (options, "ClearDTR"); - } - - if ((xf86SetBoolOption (options, "ClearRTS", FALSE))) - { - xf86Msg (X_WARNING, - "Option ClearRTS not supported on this OS\n"); - return (-1); - xf86MarkOptionUsedByName (options, "ClearRTS"); - } - - SYSCALL (r = tcsetattr (fd, TCSANOW, &t)); - return (r); -} - -int -xf86SetSerialSpeed (int fd, int speed) -{ - struct termios t; - int baud, r; - - if (fd < 0) - return -1; - - /* Don't try to set parameters for non-tty devices. */ - if (!isatty(fd)) - return 0; - - SYSCALL (tcgetattr (fd, &t)); - - if ((baud = GetBaud (speed))) - { - cfsetispeed (&t, baud); - cfsetospeed (&t, baud); - } - else - { - xf86Msg (X_ERROR, - "Invalid Option BaudRate value: %d\n", speed); - return (-1); - } - - SYSCALL (r = tcsetattr (fd, TCSANOW, &t)); - return (r); -} - -int -xf86ReadSerial (int fd, void *buf, int count) -{ - int r; - int i; - - SYSCALL (r = read (fd, buf, count)); - DebugF("ReadingSerial: 0x%x", - (unsigned char)*(((unsigned char *)buf))); - for (i = 1; i < r; i++) - DebugF(", 0x%x",(unsigned char)*(((unsigned char *)buf) + i)); - DebugF("\n"); - return (r); -} - -int -xf86WriteSerial (int fd, const void *buf, int count) -{ - int r; - int i; - - DebugF("WritingSerial: 0x%x",(unsigned char)*(((unsigned char *)buf))); - for (i = 1; i < count; i++) - ErrorF(", 0x%x",(unsigned char)*(((unsigned char *)buf) + i)); - DebugF("\n"); - SYSCALL (r = write (fd, buf, count)); - return (r); -} - -int -xf86CloseSerial (int fd) -{ - int r; - - SYSCALL (r = close (fd)); - return (r); -} - -int -xf86WaitForInput (int fd, int timeout) -{ - fd_set readfds; - struct timeval to; - int r; - - FD_ZERO(&readfds); - - if (fd >= 0) { - FD_SET(fd, &readfds); - } - - to.tv_sec = timeout / 1000000; - to.tv_usec = timeout % 1000000; - - if (fd >= 0) { - SYSCALL (r = select (FD_SETSIZE, &readfds, NULL, NULL, &to)); - } - else { - SYSCALL (r = select (FD_SETSIZE, NULL, NULL, NULL, &to)); - } - xf86ErrorFVerb (9,"select returned %d\n", r); - return (r); -} - -int -xf86SerialSendBreak (int fd, int duration) -{ - int r; - - SYSCALL (r = tcsendbreak (fd, duration)); - return (r); - -} - -int -xf86FlushInput(int fd) -{ - fd_set fds; - struct timeval timeout; - char c[4]; - - DebugF("FlushingSerial\n"); - if (tcflush(fd, TCIFLUSH) == 0) - return 0; - - timeout.tv_sec = 0; - timeout.tv_usec = 0; - FD_ZERO(&fds); - FD_SET(fd, &fds); - while (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { - if (read(fd, &c, sizeof(c)) < 1) - return 0; - FD_ZERO(&fds); - FD_SET(fd, &fds); - } - return 0; -} - -static struct states { - int xf; - int os; -} modemStates[] = { -#ifdef TIOCM_LE - { XF86_M_LE, TIOCM_LE }, -#endif -#ifdef TIOCM_DTR - { XF86_M_DTR, TIOCM_DTR }, -#endif -#ifdef TIOCM_RTS - { XF86_M_RTS, TIOCM_RTS }, -#endif -#ifdef TIOCM_ST - { XF86_M_ST, TIOCM_ST }, -#endif -#ifdef TIOCM_SR - { XF86_M_SR, TIOCM_SR }, -#endif -#ifdef TIOCM_CTS - { XF86_M_CTS, TIOCM_CTS }, -#endif -#ifdef TIOCM_CAR - { XF86_M_CAR, TIOCM_CAR }, -#elif defined(TIOCM_CD) - { XF86_M_CAR, TIOCM_CD }, -#endif -#ifdef TIOCM_RNG - { XF86_M_RNG, TIOCM_RNG }, -#elif defined(TIOCM_RI) - { XF86_M_CAR, TIOCM_RI }, -#endif -#ifdef TIOCM_DSR - { XF86_M_DSR, TIOCM_DSR }, -#endif -}; - -static int numStates = sizeof(modemStates) / sizeof(modemStates[0]); - -static int -xf2osState(int state) -{ - int i; - int ret = 0; - - for (i = 0; i < numStates; i++) - if (state & modemStates[i].xf) - ret |= modemStates[i].os; - return ret; -} - -static int -os2xfState(int state) -{ - int i; - int ret = 0; - - for (i = 0; i < numStates; i++) - if (state & modemStates[i].os) - ret |= modemStates[i].xf; - return ret; -} - -static int -getOsStateMask(void) -{ - int i; - int ret = 0; - for (i = 0; i < numStates; i++) - ret |= modemStates[i].os; - return ret; -} - -static int osStateMask = 0; - -int -xf86SetSerialModemState(int fd, int state) -{ - int ret; - int s; - - if (fd < 0) - return -1; - - /* Don't try to set parameters for non-tty devices. */ - if (!isatty(fd)) - return 0; - -#ifndef TIOCMGET - return -1; -#else - if (!osStateMask) - osStateMask = getOsStateMask(); - - state = xf2osState(state); - SYSCALL((ret = ioctl(fd, TIOCMGET, &s))); - if (ret < 0) - return -1; - s &= ~osStateMask; - s |= state; - SYSCALL((ret = ioctl(fd, TIOCMSET, &s))); - if (ret < 0) - return -1; - else - return 0; -#endif -} - -int -xf86GetSerialModemState(int fd) -{ - int ret; - int s; - - if (fd < 0) - return -1; - - /* Don't try to set parameters for non-tty devices. */ - if (!isatty(fd)) - return 0; - -#ifndef TIOCMGET - return -1; -#else - SYSCALL((ret = ioctl(fd, TIOCMGET, &s))); - if (ret < 0) - return -1; - return os2xfState(s); -#endif -} - -int -xf86SerialModemSetBits(int fd, int bits) -{ - int ret; - int s; - - if (fd < 0) - return -1; - - /* Don't try to set parameters for non-tty devices. */ - if (!isatty(fd)) - return 0; - -#ifndef TIOCMGET - return -1; -#else - s = xf2osState(bits); - SYSCALL((ret = ioctl(fd, TIOCMBIS, &s))); - return ret; -#endif -} - -int -xf86SerialModemClearBits(int fd, int bits) -{ - int ret; - int s; - - if (fd < 0) - return -1; - - /* Don't try to set parameters for non-tty devices. */ - if (!isatty(fd)) - return 0; - -#ifndef TIOCMGET - return -1; -#else - s = xf2osState(bits); - SYSCALL((ret = ioctl(fd, TIOCMBIC, &s))); - return ret; -#endif -} +/* + * Copyright 1993-2003 by The XFree86 Project, Inc. + * + * 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. + */ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" + +static int +GetBaud (int baudrate) +{ +#ifdef B300 + if (baudrate == 300) + return B300; +#endif +#ifdef B1200 + if (baudrate == 1200) + return B1200; +#endif +#ifdef B2400 + if (baudrate == 2400) + return B2400; +#endif +#ifdef B4800 + if (baudrate == 4800) + return B4800; +#endif +#ifdef B9600 + if (baudrate == 9600) + return B9600; +#endif +#ifdef B19200 + if (baudrate == 19200) + return B19200; +#endif +#ifdef B38400 + if (baudrate == 38400) + return B38400; +#endif +#ifdef B57600 + if (baudrate == 57600) + return B57600; +#endif +#ifdef B115200 + if (baudrate == 115200) + return B115200; +#endif +#ifdef B230400 + if (baudrate == 230400) + return B230400; +#endif +#ifdef B460800 + if (baudrate == 460800) + return B460800; +#endif + return (0); +} + +int +xf86OpenSerial (pointer options) +{ + struct termios t; + int fd, i; + char *dev; + + dev = xf86SetStrOption (options, "Device", NULL); + if (!dev) + { + xf86Msg (X_ERROR, "xf86OpenSerial: No Device specified.\n"); + return (-1); + } + + SYSCALL (fd = open (dev, O_RDWR | O_NONBLOCK)); + if (fd == -1) + { + xf86Msg (X_ERROR, + "xf86OpenSerial: Cannot open device %s\n\t%s.\n", + dev, strerror (errno)); + free(dev); + return (-1); + } + + if (!isatty (fd)) + { + /* Allow non-tty devices to be opened. */ + free(dev); + return (fd); + } + + /* set up default port parameters */ + SYSCALL (tcgetattr (fd, &t)); + t.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR\ + |IGNCR|ICRNL|IXON); + t.c_oflag &= ~OPOST; + t.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + t.c_cflag &= ~(CSIZE|PARENB); + t.c_cflag |= CS8|CLOCAL; + + cfsetispeed (&t, B9600); + cfsetospeed (&t, B9600); + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + + SYSCALL (tcsetattr (fd, TCSANOW, &t)); + + if (xf86SetSerial (fd, options) == -1) + { + SYSCALL (close (fd)); + free(dev); + return (-1); + } + + SYSCALL (i = fcntl (fd, F_GETFL, 0)); + if (i == -1) + { + SYSCALL (close (fd)); + free(dev); + return (-1); + } + i &= ~O_NONBLOCK; + SYSCALL (i = fcntl (fd, F_SETFL, i)); + if (i == -1) + { + SYSCALL (close (fd)); + free(dev); + return (-1); + } + free(dev); + return (fd); +} + +int +xf86SetSerial (int fd, pointer options) +{ + struct termios t; + int val; + const char *s; + int baud, r; + + if (fd < 0) + return -1; + + /* Don't try to set parameters for non-tty devices. */ + if (!isatty(fd)) + return 0; + + SYSCALL (tcgetattr (fd, &t)); + + if ((val = xf86SetIntOption (options, "BaudRate", 0))) + { + if ((baud = GetBaud (val))) + { + cfsetispeed (&t, baud); + cfsetospeed (&t, baud); + } + else + { + xf86Msg (X_ERROR, + "Invalid Option BaudRate value: %d\n", val); + return (-1); + } + } + + if ((val = xf86SetIntOption (options, "StopBits", 0))) + { + switch (val) + { + case 1: + t.c_cflag &= ~(CSTOPB); + break; + case 2: + t.c_cflag |= CSTOPB; + break; + default: + xf86Msg (X_ERROR, + "Invalid Option StopBits value: %d\n", val); + return (-1); + break; + } + } + + if ((val = xf86SetIntOption (options, "DataBits", 0))) + { + switch (val) + { + case 5: + t.c_cflag &= ~(CSIZE); + t.c_cflag |= CS5; + break; + case 6: + t.c_cflag &= ~(CSIZE); + t.c_cflag |= CS6; + break; + case 7: + t.c_cflag &= ~(CSIZE); + t.c_cflag |= CS7; + break; + case 8: + t.c_cflag &= ~(CSIZE); + t.c_cflag |= CS8; + break; + default: + xf86Msg (X_ERROR, + "Invalid Option DataBits value: %d\n", val); + return (-1); + break; + } + } + + if ((s = xf86SetStrOption (options, "Parity", NULL))) + { + if (xf86NameCmp (s, "Odd") == 0) + { + t.c_cflag |= PARENB | PARODD; + } + else if (xf86NameCmp (s, "Even") == 0) + { + t.c_cflag |= PARENB; + t.c_cflag &= ~(PARODD); + } + else if (xf86NameCmp (s, "None") == 0) + { + t.c_cflag &= ~(PARENB); + } + else + { + xf86Msg (X_ERROR, "Invalid Option Parity value: %s\n", + s); + return (-1); + } + } + + if ((val = xf86SetIntOption (options, "Vmin", -1)) != -1) + { + t.c_cc[VMIN] = val; + } + if ((val = xf86SetIntOption (options, "Vtime", -1)) != -1) + { + t.c_cc[VTIME] = val; + } + + if ((s = xf86SetStrOption (options, "FlowControl", NULL))) + { + xf86MarkOptionUsedByName (options, "FlowControl"); + if (xf86NameCmp (s, "Xoff") == 0) + { + t.c_iflag |= IXOFF; + } + else if (xf86NameCmp (s, "Xon") == 0) + { + t.c_iflag |= IXON; + } + else if (xf86NameCmp (s, "XonXoff") == 0) + { + t.c_iflag |= IXON|IXOFF; + } + else if (xf86NameCmp (s, "None") == 0) + { + t.c_iflag &= ~(IXON | IXOFF); + } + else + { + xf86Msg (X_ERROR, + "Invalid Option FlowControl value: %s\n", s); + return (-1); + } + } + + if ((xf86SetBoolOption (options, "ClearDTR", FALSE))) + { +#ifdef CLEARDTR_SUPPORT +# if defined(TIOCMBIC) + val = TIOCM_DTR; + SYSCALL (ioctl(fd, TIOCMBIC, &val)); +# else + SYSCALL (ioctl(fd, TIOCCDTR, NULL)); +# endif +#else + xf86Msg (X_WARNING, + "Option ClearDTR not supported on this OS\n"); + return (-1); +#endif + xf86MarkOptionUsedByName (options, "ClearDTR"); + } + + if ((xf86SetBoolOption (options, "ClearRTS", FALSE))) + { + xf86Msg (X_WARNING, + "Option ClearRTS not supported on this OS\n"); + return (-1); + xf86MarkOptionUsedByName (options, "ClearRTS"); + } + + SYSCALL (r = tcsetattr (fd, TCSANOW, &t)); + return (r); +} + +int +xf86SetSerialSpeed (int fd, int speed) +{ + struct termios t; + int baud, r; + + if (fd < 0) + return -1; + + /* Don't try to set parameters for non-tty devices. */ + if (!isatty(fd)) + return 0; + + SYSCALL (tcgetattr (fd, &t)); + + if ((baud = GetBaud (speed))) + { + cfsetispeed (&t, baud); + cfsetospeed (&t, baud); + } + else + { + xf86Msg (X_ERROR, + "Invalid Option BaudRate value: %d\n", speed); + return (-1); + } + + SYSCALL (r = tcsetattr (fd, TCSANOW, &t)); + return (r); +} + +int +xf86ReadSerial (int fd, void *buf, int count) +{ + int r; + int i; + + SYSCALL (r = read (fd, buf, count)); + DebugF("ReadingSerial: 0x%x", + (unsigned char)*(((unsigned char *)buf))); + for (i = 1; i < r; i++) + DebugF(", 0x%x",(unsigned char)*(((unsigned char *)buf) + i)); + DebugF("\n"); + return (r); +} + +int +xf86WriteSerial (int fd, const void *buf, int count) +{ + int r; + int i; + + DebugF("WritingSerial: 0x%x",(unsigned char)*(((unsigned char *)buf))); + for (i = 1; i < count; i++) + ErrorF(", 0x%x",(unsigned char)*(((unsigned char *)buf) + i)); + DebugF("\n"); + SYSCALL (r = write (fd, buf, count)); + return (r); +} + +int +xf86CloseSerial (int fd) +{ + int r; + + SYSCALL (r = close (fd)); + return (r); +} + +int +xf86WaitForInput (int fd, int timeout) +{ + fd_set readfds; + struct timeval to; + int r; + + FD_ZERO(&readfds); + + if (fd >= 0) { + FD_SET(fd, &readfds); + } + + to.tv_sec = timeout / 1000000; + to.tv_usec = timeout % 1000000; + + if (fd >= 0) { + SYSCALL (r = select (FD_SETSIZE, &readfds, NULL, NULL, &to)); + } + else { + SYSCALL (r = select (FD_SETSIZE, NULL, NULL, NULL, &to)); + } + xf86ErrorFVerb (9,"select returned %d\n", r); + return (r); +} + +int +xf86SerialSendBreak (int fd, int duration) +{ + int r; + + SYSCALL (r = tcsendbreak (fd, duration)); + return (r); + +} + +int +xf86FlushInput(int fd) +{ + fd_set fds; + struct timeval timeout; + char c[4]; + + DebugF("FlushingSerial\n"); + if (tcflush(fd, TCIFLUSH) == 0) + return 0; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(fd, &fds); + while (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { + if (read(fd, &c, sizeof(c)) < 1) + return 0; + FD_ZERO(&fds); + FD_SET(fd, &fds); + } + return 0; +} + +static struct states { + int xf; + int os; +} modemStates[] = { +#ifdef TIOCM_LE + { XF86_M_LE, TIOCM_LE }, +#endif +#ifdef TIOCM_DTR + { XF86_M_DTR, TIOCM_DTR }, +#endif +#ifdef TIOCM_RTS + { XF86_M_RTS, TIOCM_RTS }, +#endif +#ifdef TIOCM_ST + { XF86_M_ST, TIOCM_ST }, +#endif +#ifdef TIOCM_SR + { XF86_M_SR, TIOCM_SR }, +#endif +#ifdef TIOCM_CTS + { XF86_M_CTS, TIOCM_CTS }, +#endif +#ifdef TIOCM_CAR + { XF86_M_CAR, TIOCM_CAR }, +#elif defined(TIOCM_CD) + { XF86_M_CAR, TIOCM_CD }, +#endif +#ifdef TIOCM_RNG + { XF86_M_RNG, TIOCM_RNG }, +#elif defined(TIOCM_RI) + { XF86_M_CAR, TIOCM_RI }, +#endif +#ifdef TIOCM_DSR + { XF86_M_DSR, TIOCM_DSR }, +#endif +}; + +static int numStates = sizeof(modemStates) / sizeof(modemStates[0]); + +static int +xf2osState(int state) +{ + int i; + int ret = 0; + + for (i = 0; i < numStates; i++) + if (state & modemStates[i].xf) + ret |= modemStates[i].os; + return ret; +} + +static int +os2xfState(int state) +{ + int i; + int ret = 0; + + for (i = 0; i < numStates; i++) + if (state & modemStates[i].os) + ret |= modemStates[i].xf; + return ret; +} + +static int +getOsStateMask(void) +{ + int i; + int ret = 0; + for (i = 0; i < numStates; i++) + ret |= modemStates[i].os; + return ret; +} + +static int osStateMask = 0; + +int +xf86SetSerialModemState(int fd, int state) +{ + int ret; + int s; + + if (fd < 0) + return -1; + + /* Don't try to set parameters for non-tty devices. */ + if (!isatty(fd)) + return 0; + +#ifndef TIOCMGET + return -1; +#else + if (!osStateMask) + osStateMask = getOsStateMask(); + + state = xf2osState(state); + SYSCALL((ret = ioctl(fd, TIOCMGET, &s))); + if (ret < 0) + return -1; + s &= ~osStateMask; + s |= state; + SYSCALL((ret = ioctl(fd, TIOCMSET, &s))); + if (ret < 0) + return -1; + else + return 0; +#endif +} + +int +xf86GetSerialModemState(int fd) +{ + int ret; + int s; + + if (fd < 0) + return -1; + + /* Don't try to set parameters for non-tty devices. */ + if (!isatty(fd)) + return 0; + +#ifndef TIOCMGET + return -1; +#else + SYSCALL((ret = ioctl(fd, TIOCMGET, &s))); + if (ret < 0) + return -1; + return os2xfState(s); +#endif +} + +int +xf86SerialModemSetBits(int fd, int bits) +{ + int ret; + int s; + + if (fd < 0) + return -1; + + /* Don't try to set parameters for non-tty devices. */ + if (!isatty(fd)) + return 0; + +#ifndef TIOCMGET + return -1; +#else + s = xf2osState(bits); + SYSCALL((ret = ioctl(fd, TIOCMBIS, &s))); + return ret; +#endif +} + +int +xf86SerialModemClearBits(int fd, int bits) +{ + int ret; + int s; + + if (fd < 0) + return -1; + + /* Don't try to set parameters for non-tty devices. */ + if (!isatty(fd)) + return 0; + +#ifndef TIOCMGET + return -1; +#else + s = xf2osState(bits); + SYSCALL((ret = ioctl(fd, TIOCMBIC, &s))); + return ret; +#endif +} diff --git a/xorg-server/hw/xfree86/os-support/shared/vidmem.c b/xorg-server/hw/xfree86/os-support/shared/vidmem.c index 803ce09bd..6358138d8 100644 --- a/xorg-server/hw/xfree86/os-support/shared/vidmem.c +++ b/xorg-server/hw/xfree86/os-support/shared/vidmem.c @@ -1,296 +1,296 @@ -/* - * Copyright (c) 1993-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include "input.h" -#include "scrnintstr.h" - -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" -#include "xf86OSpriv.h" - -/* - * This file contains the common part of the video memory mapping functions - */ - -/* - * Get a piece of the ScrnInfoRec. At the moment, this is only used to hold - * the MTRR option information, but it is likely to be expanded if we do - * auto unmapping of memory at VT switch. - * - */ - -typedef struct { - unsigned long physBase; - unsigned long size; - pointer virtBase; - pointer mtrrInfo; - int flags; -} MappingRec, *MappingPtr; - -typedef struct { - int numMappings; - MappingPtr * mappings; - Bool mtrrEnabled; - MessageType mtrrFrom; - Bool mtrrOptChecked; - ScrnInfoPtr pScrn; -} VidMapRec, *VidMapPtr; - -static int vidMapIndex = -1; - -#define VIDMAPPTR(p) ((VidMapPtr)((p)->privates[vidMapIndex].ptr)) - -static VidMemInfo vidMemInfo = {FALSE, }; -static VidMapRec vidMapRec = {0, NULL, TRUE, X_DEFAULT, FALSE, NULL}; - -static VidMapPtr -getVidMapRec(int scrnIndex) -{ - VidMapPtr vp; - ScrnInfoPtr pScrn; - - if ((scrnIndex < 0) || - !(pScrn = xf86Screens[scrnIndex])) - return &vidMapRec; - - if (vidMapIndex < 0) - vidMapIndex = xf86AllocateScrnInfoPrivateIndex(); - - if (VIDMAPPTR(pScrn) != NULL) - return VIDMAPPTR(pScrn); - - vp = pScrn->privates[vidMapIndex].ptr = xnfcalloc(sizeof(VidMapRec), 1); - vp->mtrrEnabled = TRUE; /* default to enabled */ - vp->mtrrFrom = X_DEFAULT; - vp->mtrrOptChecked = FALSE; - vp->pScrn = pScrn; - return vp; -} - -static MappingPtr -newMapping(VidMapPtr vp) -{ - vp->mappings = xnfrealloc(vp->mappings, sizeof(MappingPtr) * - (vp->numMappings + 1)); - vp->mappings[vp->numMappings] = xnfcalloc(sizeof(MappingRec), 1); - return vp->mappings[vp->numMappings++]; -} - -static MappingPtr -findMapping(VidMapPtr vp, pointer vbase, unsigned long size) -{ - int i; - - for (i = 0; i < vp->numMappings; i++) { - if (vp->mappings[i]->virtBase == vbase && - vp->mappings[i]->size == size) - return vp->mappings[i]; - } - return NULL; -} - -static void -removeMapping(VidMapPtr vp, MappingPtr mp) -{ - int i, found = 0; - - for (i = 0; i < vp->numMappings; i++) { - if (vp->mappings[i] == mp) { - found = 1; - xfree(vp->mappings[i]); - } else if (found) { - vp->mappings[i - 1] = vp->mappings[i]; - } - } - vp->numMappings--; - vp->mappings[vp->numMappings] = NULL; -} - -enum { OPTION_MTRR }; -static const OptionInfoRec opts[] = -{ - { OPTION_MTRR, "mtrr", OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, OPTV_NONE, {0}, FALSE } -}; - -static void -checkMtrrOption(VidMapPtr vp) -{ - if (!vp->mtrrOptChecked && vp->pScrn && vp->pScrn->options != NULL) { - OptionInfoPtr options; - - options = xnfalloc(sizeof(opts)); - (void)memcpy(options, opts, sizeof(opts)); - xf86ProcessOptions(vp->pScrn->scrnIndex, vp->pScrn->options, - options); - if (xf86GetOptValBool(options, OPTION_MTRR, &vp->mtrrEnabled)) - vp->mtrrFrom = X_CONFIG; - xfree(options); - vp->mtrrOptChecked = TRUE; - } -} - -void -xf86MakeNewMapping(int ScreenNum, int Flags, unsigned long Base, unsigned long Size, pointer Vbase) -{ - VidMapPtr vp; - MappingPtr mp; - - vp = getVidMapRec(ScreenNum); - mp = newMapping(vp); - mp->physBase = Base; - mp->size = Size; - mp->virtBase = Vbase; - mp->flags = Flags; -} - -void -xf86InitVidMem(void) -{ - if (!vidMemInfo.initialised) { - memset(&vidMemInfo, 0, sizeof(VidMemInfo)); - xf86OSInitVidMem(&vidMemInfo); - } -} - -pointer -xf86MapVidMem(int ScreenNum, int Flags, unsigned long Base, unsigned long Size) -{ - pointer vbase = NULL; - VidMapPtr vp; - MappingPtr mp; - - if (((Flags & VIDMEM_FRAMEBUFFER) && - (Flags & (VIDMEM_MMIO | VIDMEM_MMIO_32BIT)))) - FatalError("Mapping memory with more than one type\n"); - - xf86InitVidMem(); - if (!vidMemInfo.initialised || !vidMemInfo.mapMem) - return NULL; - - vbase = vidMemInfo.mapMem(ScreenNum, Base, Size, Flags); - - if (!vbase || vbase == (pointer)-1) - return NULL; - - vp = getVidMapRec(ScreenNum); - mp = newMapping(vp); - mp->physBase = Base; - mp->size = Size; - mp->virtBase = vbase; - mp->flags = Flags; - - /* - * Check the "mtrr" option even when MTRR isn't supported to avoid - * warnings about unrecognised options. - */ - checkMtrrOption(vp); - - if (vp->mtrrEnabled && vidMemInfo.setWC) { - if (Flags & (VIDMEM_MMIO | VIDMEM_MMIO_32BIT)) - mp->mtrrInfo = - vidMemInfo.setWC(ScreenNum, Base, Size, FALSE, - vp->mtrrFrom); - else if (Flags & VIDMEM_FRAMEBUFFER) - mp->mtrrInfo = - vidMemInfo.setWC(ScreenNum, Base, Size, TRUE, - vp->mtrrFrom); - } - return vbase; -} - -void -xf86UnMapVidMem(int ScreenNum, pointer Base, unsigned long Size) -{ - VidMapPtr vp; - MappingPtr mp; - - if (!vidMemInfo.initialised || !vidMemInfo.unmapMem) { - xf86DrvMsg(ScreenNum, X_WARNING, - "xf86UnMapVidMem() called before xf86MapVidMem()\n"); - return; - } - - vp = getVidMapRec(ScreenNum); - mp = findMapping(vp, Base, Size); - if (!mp) { - xf86DrvMsg(ScreenNum, X_WARNING, - "xf86UnMapVidMem: cannot find region for [%p,0x%lx]\n", - Base, Size); - return; - } - if (vp->mtrrEnabled && vidMemInfo.undoWC && mp) - vidMemInfo.undoWC(ScreenNum, mp->mtrrInfo); - - vidMemInfo.unmapMem(ScreenNum, Base, Size); - removeMapping(vp, mp); -} - -Bool -xf86CheckMTRR(int ScreenNum) -{ - VidMapPtr vp = getVidMapRec(ScreenNum); - - /* - * Check the "mtrr" option even when MTRR isn't supported to avoid - * warnings about unrecognised options. - */ - checkMtrrOption(vp); - - if (vp->mtrrEnabled && vidMemInfo.setWC) - return TRUE; - - return FALSE; -} - -Bool -xf86LinearVidMem(void) -{ - xf86InitVidMem(); - return vidMemInfo.linearSupported; -} - -void -xf86MapReadSideEffects(int ScreenNum, int Flags, pointer base, - unsigned long Size) -{ - if (!(Flags & VIDMEM_READSIDEEFFECT)) - return; - - if (!vidMemInfo.initialised || !vidMemInfo.readSideEffects) - return; - - vidMemInfo.readSideEffects(ScreenNum, base, Size); -} - +/* + * Copyright (c) 1993-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "input.h" +#include "scrnintstr.h" + +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#include "xf86OSpriv.h" + +/* + * This file contains the common part of the video memory mapping functions + */ + +/* + * Get a piece of the ScrnInfoRec. At the moment, this is only used to hold + * the MTRR option information, but it is likely to be expanded if we do + * auto unmapping of memory at VT switch. + * + */ + +typedef struct { + unsigned long physBase; + unsigned long size; + pointer virtBase; + pointer mtrrInfo; + int flags; +} MappingRec, *MappingPtr; + +typedef struct { + int numMappings; + MappingPtr * mappings; + Bool mtrrEnabled; + MessageType mtrrFrom; + Bool mtrrOptChecked; + ScrnInfoPtr pScrn; +} VidMapRec, *VidMapPtr; + +static int vidMapIndex = -1; + +#define VIDMAPPTR(p) ((VidMapPtr)((p)->privates[vidMapIndex].ptr)) + +static VidMemInfo vidMemInfo = {FALSE, }; +static VidMapRec vidMapRec = {0, NULL, TRUE, X_DEFAULT, FALSE, NULL}; + +static VidMapPtr +getVidMapRec(int scrnIndex) +{ + VidMapPtr vp; + ScrnInfoPtr pScrn; + + if ((scrnIndex < 0) || + !(pScrn = xf86Screens[scrnIndex])) + return &vidMapRec; + + if (vidMapIndex < 0) + vidMapIndex = xf86AllocateScrnInfoPrivateIndex(); + + if (VIDMAPPTR(pScrn) != NULL) + return VIDMAPPTR(pScrn); + + vp = pScrn->privates[vidMapIndex].ptr = xnfcalloc(sizeof(VidMapRec), 1); + vp->mtrrEnabled = TRUE; /* default to enabled */ + vp->mtrrFrom = X_DEFAULT; + vp->mtrrOptChecked = FALSE; + vp->pScrn = pScrn; + return vp; +} + +static MappingPtr +newMapping(VidMapPtr vp) +{ + vp->mappings = xnfrealloc(vp->mappings, sizeof(MappingPtr) * + (vp->numMappings + 1)); + vp->mappings[vp->numMappings] = xnfcalloc(sizeof(MappingRec), 1); + return vp->mappings[vp->numMappings++]; +} + +static MappingPtr +findMapping(VidMapPtr vp, pointer vbase, unsigned long size) +{ + int i; + + for (i = 0; i < vp->numMappings; i++) { + if (vp->mappings[i]->virtBase == vbase && + vp->mappings[i]->size == size) + return vp->mappings[i]; + } + return NULL; +} + +static void +removeMapping(VidMapPtr vp, MappingPtr mp) +{ + int i, found = 0; + + for (i = 0; i < vp->numMappings; i++) { + if (vp->mappings[i] == mp) { + found = 1; + free(vp->mappings[i]); + } else if (found) { + vp->mappings[i - 1] = vp->mappings[i]; + } + } + vp->numMappings--; + vp->mappings[vp->numMappings] = NULL; +} + +enum { OPTION_MTRR }; +static const OptionInfoRec opts[] = +{ + { OPTION_MTRR, "mtrr", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +static void +checkMtrrOption(VidMapPtr vp) +{ + if (!vp->mtrrOptChecked && vp->pScrn && vp->pScrn->options != NULL) { + OptionInfoPtr options; + + options = xnfalloc(sizeof(opts)); + (void)memcpy(options, opts, sizeof(opts)); + xf86ProcessOptions(vp->pScrn->scrnIndex, vp->pScrn->options, + options); + if (xf86GetOptValBool(options, OPTION_MTRR, &vp->mtrrEnabled)) + vp->mtrrFrom = X_CONFIG; + free(options); + vp->mtrrOptChecked = TRUE; + } +} + +void +xf86MakeNewMapping(int ScreenNum, int Flags, unsigned long Base, unsigned long Size, pointer Vbase) +{ + VidMapPtr vp; + MappingPtr mp; + + vp = getVidMapRec(ScreenNum); + mp = newMapping(vp); + mp->physBase = Base; + mp->size = Size; + mp->virtBase = Vbase; + mp->flags = Flags; +} + +void +xf86InitVidMem(void) +{ + if (!vidMemInfo.initialised) { + memset(&vidMemInfo, 0, sizeof(VidMemInfo)); + xf86OSInitVidMem(&vidMemInfo); + } +} + +pointer +xf86MapVidMem(int ScreenNum, int Flags, unsigned long Base, unsigned long Size) +{ + pointer vbase = NULL; + VidMapPtr vp; + MappingPtr mp; + + if (((Flags & VIDMEM_FRAMEBUFFER) && + (Flags & (VIDMEM_MMIO | VIDMEM_MMIO_32BIT)))) + FatalError("Mapping memory with more than one type\n"); + + xf86InitVidMem(); + if (!vidMemInfo.initialised || !vidMemInfo.mapMem) + return NULL; + + vbase = vidMemInfo.mapMem(ScreenNum, Base, Size, Flags); + + if (!vbase || vbase == (pointer)-1) + return NULL; + + vp = getVidMapRec(ScreenNum); + mp = newMapping(vp); + mp->physBase = Base; + mp->size = Size; + mp->virtBase = vbase; + mp->flags = Flags; + + /* + * Check the "mtrr" option even when MTRR isn't supported to avoid + * warnings about unrecognised options. + */ + checkMtrrOption(vp); + + if (vp->mtrrEnabled && vidMemInfo.setWC) { + if (Flags & (VIDMEM_MMIO | VIDMEM_MMIO_32BIT)) + mp->mtrrInfo = + vidMemInfo.setWC(ScreenNum, Base, Size, FALSE, + vp->mtrrFrom); + else if (Flags & VIDMEM_FRAMEBUFFER) + mp->mtrrInfo = + vidMemInfo.setWC(ScreenNum, Base, Size, TRUE, + vp->mtrrFrom); + } + return vbase; +} + +void +xf86UnMapVidMem(int ScreenNum, pointer Base, unsigned long Size) +{ + VidMapPtr vp; + MappingPtr mp; + + if (!vidMemInfo.initialised || !vidMemInfo.unmapMem) { + xf86DrvMsg(ScreenNum, X_WARNING, + "xf86UnMapVidMem() called before xf86MapVidMem()\n"); + return; + } + + vp = getVidMapRec(ScreenNum); + mp = findMapping(vp, Base, Size); + if (!mp) { + xf86DrvMsg(ScreenNum, X_WARNING, + "xf86UnMapVidMem: cannot find region for [%p,0x%lx]\n", + Base, Size); + return; + } + if (vp->mtrrEnabled && vidMemInfo.undoWC && mp) + vidMemInfo.undoWC(ScreenNum, mp->mtrrInfo); + + vidMemInfo.unmapMem(ScreenNum, Base, Size); + removeMapping(vp, mp); +} + +Bool +xf86CheckMTRR(int ScreenNum) +{ + VidMapPtr vp = getVidMapRec(ScreenNum); + + /* + * Check the "mtrr" option even when MTRR isn't supported to avoid + * warnings about unrecognised options. + */ + checkMtrrOption(vp); + + if (vp->mtrrEnabled && vidMemInfo.setWC) + return TRUE; + + return FALSE; +} + +Bool +xf86LinearVidMem(void) +{ + xf86InitVidMem(); + return vidMemInfo.linearSupported; +} + +void +xf86MapReadSideEffects(int ScreenNum, int Flags, pointer base, + unsigned long Size) +{ + if (!(Flags & VIDMEM_READSIDEEFFECT)) + return; + + if (!vidMemInfo.initialised || !vidMemInfo.readSideEffects) + return; + + vidMemInfo.readSideEffects(ScreenNum, base, Size); +} + diff --git a/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c b/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c index e6a55a48b..a5fb5c6e6 100644 --- a/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c +++ b/xorg-server/hw/xfree86/os-support/solaris/sun_agp.c @@ -1,327 +1,327 @@ -/* - * Abstraction of the AGP GART interface. - * - * This version is for Solaris. - * - * Copyright © 2000 VA Linux Systems, Inc. - * Copyright © 2001 The XFree86 Project, Inc. - */ -/* Copyright 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, 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. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86_OSlib.h" -#include "xf86_OSproc.h" -#include <unistd.h> -#include <sys/ioccom.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/agpgart.h> - -/* AGP page size is independent of the host page size. */ -#ifndef AGP_PAGE_SIZE -#define AGP_PAGE_SIZE 4096 -#endif - -static int gartFd = -1; -static int acquiredScreen = -1; -static Bool initDone = FALSE; -/* - * Close /dev/agpgart. This frees all associated memory allocated during - * this server generation. - */ -Bool -xf86GARTCloseScreen(int screenNum) -{ - if (gartFd != -1) { - close(gartFd); - acquiredScreen = -1; - gartFd = -1; - initDone = FALSE; - - xf86DrvMsg(screenNum, X_INFO, - "xf86GARTCloseScreen: device closed successfully\n"); - - } - return TRUE; -} - -/* - * Open /dev/agpgart. Keep it open until xf86GARTCloseScreen is called. - */ -static Bool -GARTInit(int screenNum) -{ - if (initDone) - return (gartFd != -1); - - if (gartFd == -1) - gartFd = open(AGP_DEVICE, O_RDWR); - else - return FALSE; - - if (gartFd == -1) { - xf86DrvMsg(screenNum, X_ERROR, - "GARTInit: Unable to open " AGP_DEVICE " (%s)\n", - strerror(errno)); - return FALSE; - } - - initDone = TRUE; - xf86DrvMsg(screenNum, X_INFO, - "GARTInit: " AGP_DEVICE " opened successfully\n"); - - return TRUE; -} - -Bool -xf86AgpGARTSupported(void) -{ - return (GARTInit(-1)); - -} - -AgpInfoPtr -xf86GetAGPInfo(int screenNum) -{ - agp_info_t agpinf; - AgpInfoPtr info; - - if (!GARTInit(screenNum)) - return NULL; - - if ((info = xcalloc(sizeof(AgpInfo), 1)) == NULL) { - xf86DrvMsg(screenNum, X_ERROR, - "xf86GetAGPInfo: Failed to allocate AgpInfo\n"); - return NULL; - } - - if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { - xf86DrvMsg(screenNum, X_ERROR, - "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n", - strerror(errno)); - return NULL; - } - - info->bridgeId = agpinf.agpi_devid; - info->agpMode = agpinf.agpi_mode; - info->base = agpinf.agpi_aperbase; - info->size = agpinf.agpi_apersize; - info->totalPages = (unsigned long)agpinf.agpi_pgtotal; - info->systemPages = (unsigned long)agpinf.agpi_pgsystem; - info->usedPages = (unsigned long)agpinf.agpi_pgused; - - return info; -} - -Bool -xf86AcquireGART(int screenNum) -{ - - if (!GARTInit(screenNum)) - return FALSE; - - if (acquiredScreen != screenNum) { - if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) { - xf86DrvMsg(screenNum, X_WARNING, - "xf86AcquireGART: AGPIOC_ACQUIRE failed (%s)\n", - strerror(errno)); - return FALSE; - } - acquiredScreen = screenNum; - xf86DrvMsg(screenNum, X_INFO, - "xf86AcquireGART: AGPIOC_ACQUIRE succeeded\n"); - } - return TRUE; -} - -Bool -xf86ReleaseGART(int screenNum) -{ - - if (!GARTInit(screenNum)) - return FALSE; - - if (acquiredScreen == screenNum) { - /* - * The FreeBSD agp driver removes allocations on release. - * The Solaris driver doesn't. xf86ReleaseGART() is expected - * to give up access to the GART, but not to remove any - * allocations. - */ - - if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) { - xf86DrvMsg(screenNum, X_WARNING, - "xf86ReleaseGART: AGPIOC_RELEASE failed (%s)\n", - strerror(errno)); - return FALSE; - } - acquiredScreen = -1; - xf86DrvMsg(screenNum, X_INFO, - "xf86ReleaseGART: AGPIOC_RELEASE succeeded\n"); - return TRUE; - } - return FALSE; -} - -int -xf86AllocateGARTMemory(int screenNum, unsigned long size, int type, - unsigned long *physical) -{ - agp_allocate_t alloc; - int pages; - - /* - * Allocates "size" bytes of GART memory (rounds up to the next - * page multiple) or type "type". A handle (key) for the allocated - * memory is returned. On error, the return value is -1. - * "size" should be larger than 0, or AGPIOC_ALLOCATE ioctl will - * return error. - */ - - if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) - return -1; - - pages = (size / AGP_PAGE_SIZE); - if (size % AGP_PAGE_SIZE != 0) - pages++; - - alloc.agpa_pgcount = pages; - alloc.agpa_type = type; - - if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86AllocateGARTMemory: " - "allocation of %d pages failed\n\t(%s)\n", pages, - strerror(errno)); - return -1; - } - - if (physical) - *physical = (unsigned long)alloc.agpa_physical; - - return alloc.agpa_key; -} - -Bool -xf86DeallocateGARTMemory(int screenNum, int key) -{ - if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) - return FALSE; - - if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *)key) != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86DeAllocateGARTMemory: " - "deallocation of gart memory with key %d failed\n" - "\t(%s)\n", key, strerror(errno)); - return FALSE; - } - - return TRUE; -} - -/* Bind GART memory with "key" at "offset" */ -Bool -xf86BindGARTMemory(int screenNum, int key, unsigned long offset) -{ - agp_bind_t bind; - int pageOffset; - - if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) - return FALSE; - - if (offset % AGP_PAGE_SIZE != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " - "offset (0x%lx) is not page-aligned (%d)\n", - offset, AGP_PAGE_SIZE); - return FALSE; - } - pageOffset = offset / AGP_PAGE_SIZE; - - xf86DrvMsgVerb(screenNum, X_INFO, 3, - "xf86BindGARTMemory: bind key %d at 0x%08lx " - "(pgoffset %d)\n", key, offset, pageOffset); - - bind.agpb_pgstart = pageOffset; - bind.agpb_key = key; - - if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " - "binding of gart memory with key %d\n" - "\tat offset 0x%lx failed (%s)\n", - key, offset, strerror(errno)); - return FALSE; - } - - return TRUE; -} - -/* Unbind GART memory with "key" */ -Bool -xf86UnbindGARTMemory(int screenNum, int key) -{ - agp_unbind_t unbind; - - if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) - return FALSE; - - unbind.agpu_pri = 0; - unbind.agpu_key = key; - - if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86UnbindGARTMemory: " - "unbinding of gart memory with key %d " - "failed (%s)\n", key, strerror(errno)); - return FALSE; - } - - xf86DrvMsgVerb(screenNum, X_INFO, 3, - "xf86UnbindGARTMemory: unbind key %d\n", key); - - return TRUE; -} - - -/* XXX Interface may change. */ -Bool -xf86EnableAGP(int screenNum, CARD32 mode) -{ - agp_setup_t setup; - - if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) - return FALSE; - - setup.agps_mode = mode; - if (ioctl(gartFd, AGPIOC_SETUP, &setup) != 0) { - xf86DrvMsg(screenNum, X_WARNING, "xf86EnableAGP: " - "AGPIOC_SETUP with mode %x failed (%s)\n", - mode, strerror(errno)); - return FALSE; - } - - return TRUE; -} - +/* + * Abstraction of the AGP GART interface. + * + * This version is for Solaris. + * + * Copyright © 2000 VA Linux Systems, Inc. + * Copyright © 2001 The XFree86 Project, Inc. + */ +/* Copyright 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, 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#include "xf86_OSproc.h" +#include <unistd.h> +#include <sys/ioccom.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/agpgart.h> + +/* AGP page size is independent of the host page size. */ +#ifndef AGP_PAGE_SIZE +#define AGP_PAGE_SIZE 4096 +#endif + +static int gartFd = -1; +static int acquiredScreen = -1; +static Bool initDone = FALSE; +/* + * Close /dev/agpgart. This frees all associated memory allocated during + * this server generation. + */ +Bool +xf86GARTCloseScreen(int screenNum) +{ + if (gartFd != -1) { + close(gartFd); + acquiredScreen = -1; + gartFd = -1; + initDone = FALSE; + + xf86DrvMsg(screenNum, X_INFO, + "xf86GARTCloseScreen: device closed successfully\n"); + + } + return TRUE; +} + +/* + * Open /dev/agpgart. Keep it open until xf86GARTCloseScreen is called. + */ +static Bool +GARTInit(int screenNum) +{ + if (initDone) + return (gartFd != -1); + + if (gartFd == -1) + gartFd = open(AGP_DEVICE, O_RDWR); + else + return FALSE; + + if (gartFd == -1) { + xf86DrvMsg(screenNum, X_ERROR, + "GARTInit: Unable to open " AGP_DEVICE " (%s)\n", + strerror(errno)); + return FALSE; + } + + initDone = TRUE; + xf86DrvMsg(screenNum, X_INFO, + "GARTInit: " AGP_DEVICE " opened successfully\n"); + + return TRUE; +} + +Bool +xf86AgpGARTSupported(void) +{ + return (GARTInit(-1)); + +} + +AgpInfoPtr +xf86GetAGPInfo(int screenNum) +{ + agp_info_t agpinf; + AgpInfoPtr info; + + if (!GARTInit(screenNum)) + return NULL; + + if ((info = calloc(sizeof(AgpInfo), 1)) == NULL) { + xf86DrvMsg(screenNum, X_ERROR, + "xf86GetAGPInfo: Failed to allocate AgpInfo\n"); + return NULL; + } + + if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { + xf86DrvMsg(screenNum, X_ERROR, + "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n", + strerror(errno)); + return NULL; + } + + info->bridgeId = agpinf.agpi_devid; + info->agpMode = agpinf.agpi_mode; + info->base = agpinf.agpi_aperbase; + info->size = agpinf.agpi_apersize; + info->totalPages = (unsigned long)agpinf.agpi_pgtotal; + info->systemPages = (unsigned long)agpinf.agpi_pgsystem; + info->usedPages = (unsigned long)agpinf.agpi_pgused; + + return info; +} + +Bool +xf86AcquireGART(int screenNum) +{ + + if (!GARTInit(screenNum)) + return FALSE; + + if (acquiredScreen != screenNum) { + if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) { + xf86DrvMsg(screenNum, X_WARNING, + "xf86AcquireGART: AGPIOC_ACQUIRE failed (%s)\n", + strerror(errno)); + return FALSE; + } + acquiredScreen = screenNum; + xf86DrvMsg(screenNum, X_INFO, + "xf86AcquireGART: AGPIOC_ACQUIRE succeeded\n"); + } + return TRUE; +} + +Bool +xf86ReleaseGART(int screenNum) +{ + + if (!GARTInit(screenNum)) + return FALSE; + + if (acquiredScreen == screenNum) { + /* + * The FreeBSD agp driver removes allocations on release. + * The Solaris driver doesn't. xf86ReleaseGART() is expected + * to give up access to the GART, but not to remove any + * allocations. + */ + + if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) { + xf86DrvMsg(screenNum, X_WARNING, + "xf86ReleaseGART: AGPIOC_RELEASE failed (%s)\n", + strerror(errno)); + return FALSE; + } + acquiredScreen = -1; + xf86DrvMsg(screenNum, X_INFO, + "xf86ReleaseGART: AGPIOC_RELEASE succeeded\n"); + return TRUE; + } + return FALSE; +} + +int +xf86AllocateGARTMemory(int screenNum, unsigned long size, int type, + unsigned long *physical) +{ + agp_allocate_t alloc; + int pages; + + /* + * Allocates "size" bytes of GART memory (rounds up to the next + * page multiple) or type "type". A handle (key) for the allocated + * memory is returned. On error, the return value is -1. + * "size" should be larger than 0, or AGPIOC_ALLOCATE ioctl will + * return error. + */ + + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return -1; + + pages = (size / AGP_PAGE_SIZE); + if (size % AGP_PAGE_SIZE != 0) + pages++; + + alloc.agpa_pgcount = pages; + alloc.agpa_type = type; + + if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86AllocateGARTMemory: " + "allocation of %d pages failed\n\t(%s)\n", pages, + strerror(errno)); + return -1; + } + + if (physical) + *physical = (unsigned long)alloc.agpa_physical; + + return alloc.agpa_key; +} + +Bool +xf86DeallocateGARTMemory(int screenNum, int key) +{ + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return FALSE; + + if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *)key) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86DeAllocateGARTMemory: " + "deallocation of gart memory with key %d failed\n" + "\t(%s)\n", key, strerror(errno)); + return FALSE; + } + + return TRUE; +} + +/* Bind GART memory with "key" at "offset" */ +Bool +xf86BindGARTMemory(int screenNum, int key, unsigned long offset) +{ + agp_bind_t bind; + int pageOffset; + + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return FALSE; + + if (offset % AGP_PAGE_SIZE != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " + "offset (0x%lx) is not page-aligned (%d)\n", + offset, AGP_PAGE_SIZE); + return FALSE; + } + pageOffset = offset / AGP_PAGE_SIZE; + + xf86DrvMsgVerb(screenNum, X_INFO, 3, + "xf86BindGARTMemory: bind key %d at 0x%08lx " + "(pgoffset %d)\n", key, offset, pageOffset); + + bind.agpb_pgstart = pageOffset; + bind.agpb_key = key; + + if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " + "binding of gart memory with key %d\n" + "\tat offset 0x%lx failed (%s)\n", + key, offset, strerror(errno)); + return FALSE; + } + + return TRUE; +} + +/* Unbind GART memory with "key" */ +Bool +xf86UnbindGARTMemory(int screenNum, int key) +{ + agp_unbind_t unbind; + + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return FALSE; + + unbind.agpu_pri = 0; + unbind.agpu_key = key; + + if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86UnbindGARTMemory: " + "unbinding of gart memory with key %d " + "failed (%s)\n", key, strerror(errno)); + return FALSE; + } + + xf86DrvMsgVerb(screenNum, X_INFO, 3, + "xf86UnbindGARTMemory: unbind key %d\n", key); + + return TRUE; +} + + +/* XXX Interface may change. */ +Bool +xf86EnableAGP(int screenNum, CARD32 mode) +{ + agp_setup_t setup; + + if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) + return FALSE; + + setup.agps_mode = mode; + if (ioctl(gartFd, AGPIOC_SETUP, &setup) != 0) { + xf86DrvMsg(screenNum, X_WARNING, "xf86EnableAGP: " + "AGPIOC_SETUP with mode %x failed (%s)\n", + mode, strerror(errno)); + return FALSE; + } + + return TRUE; +} + diff --git a/xorg-server/hw/xfree86/ramdac/xf86Cursor.c b/xorg-server/hw/xfree86/ramdac/xf86Cursor.c index 346e99490..91b5795c3 100644 --- a/xorg-server/hw/xfree86/ramdac/xf86Cursor.c +++ b/xorg-server/hw/xfree86/ramdac/xf86Cursor.c @@ -1,479 +1,479 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86CursorPriv.h" -#include "colormapst.h" -#include "cursorstr.h" - -/* FIXME: This was added with the ABI change of the miPointerSpriteFuncs for - * MPX. - * inputInfo is needed to pass the core pointer as the default argument into - * the cursor functions. - * - * Externing inputInfo is not the nice way to do it but it works. - */ -#include "inputstr.h" -extern InputInfo inputInfo; - -static int xf86CursorScreenKeyIndex; -DevPrivateKey xf86CursorScreenKey = &xf86CursorScreenKeyIndex; - -/* sprite functions */ - -static Bool xf86CursorRealizeCursor(DeviceIntPtr, ScreenPtr, CursorPtr); -static Bool xf86CursorUnrealizeCursor(DeviceIntPtr, ScreenPtr, CursorPtr); -static void xf86CursorSetCursor(DeviceIntPtr, ScreenPtr, CursorPtr, int, int); -static void xf86CursorMoveCursor(DeviceIntPtr, ScreenPtr, int, int); -static Bool xf86DeviceCursorInitialize(DeviceIntPtr, ScreenPtr); -static void xf86DeviceCursorCleanup(DeviceIntPtr, ScreenPtr); - -static miPointerSpriteFuncRec xf86CursorSpriteFuncs = { - xf86CursorRealizeCursor, - xf86CursorUnrealizeCursor, - xf86CursorSetCursor, - xf86CursorMoveCursor, - xf86DeviceCursorInitialize, - xf86DeviceCursorCleanup -}; - -/* Screen functions */ - -static void xf86CursorInstallColormap(ColormapPtr); -static void xf86CursorRecolorCursor(DeviceIntPtr pDev, ScreenPtr, CursorPtr, Bool); -static Bool xf86CursorCloseScreen(int, ScreenPtr); -static void xf86CursorQueryBestSize(int, unsigned short*, unsigned short*, - ScreenPtr); - -/* ScrnInfoRec functions */ - -static void xf86CursorEnableDisableFBAccess(int, Bool); -static Bool xf86CursorSwitchMode(int, DisplayModePtr,int); - -Bool -xf86InitCursor( - ScreenPtr pScreen, - xf86CursorInfoPtr infoPtr -) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - xf86CursorScreenPtr ScreenPriv; - miPointerScreenPtr PointPriv; - - if (!xf86InitHardwareCursor(pScreen, infoPtr)) - return FALSE; - - ScreenPriv = xcalloc(1, sizeof(xf86CursorScreenRec)); - if (!ScreenPriv) - return FALSE; - - dixSetPrivate(&pScreen->devPrivates, xf86CursorScreenKey, ScreenPriv); - - ScreenPriv->SWCursor = TRUE; - ScreenPriv->isUp = FALSE; - ScreenPriv->CurrentCursor = NULL; - ScreenPriv->CursorInfoPtr = infoPtr; - ScreenPriv->PalettedCursor = FALSE; - ScreenPriv->pInstalledMap = NULL; - - ScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = xf86CursorCloseScreen; - ScreenPriv->QueryBestSize = pScreen->QueryBestSize; - pScreen->QueryBestSize = xf86CursorQueryBestSize; - ScreenPriv->RecolorCursor = pScreen->RecolorCursor; - pScreen->RecolorCursor = xf86CursorRecolorCursor; - - if ((infoPtr->pScrn->bitsPerPixel == 8) && - !(infoPtr->Flags & HARDWARE_CURSOR_TRUECOLOR_AT_8BPP)) { - ScreenPriv->InstallColormap = pScreen->InstallColormap; - pScreen->InstallColormap = xf86CursorInstallColormap; - ScreenPriv->PalettedCursor = TRUE; - } - - PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); - - ScreenPriv->showTransparent = PointPriv->showTransparent; - if (infoPtr->Flags & HARDWARE_CURSOR_SHOW_TRANSPARENT) - PointPriv->showTransparent = TRUE; - else - PointPriv->showTransparent = FALSE; - ScreenPriv->spriteFuncs = PointPriv->spriteFuncs; - PointPriv->spriteFuncs = &xf86CursorSpriteFuncs; - - ScreenPriv->EnableDisableFBAccess = pScrn->EnableDisableFBAccess; - ScreenPriv->SwitchMode = pScrn->SwitchMode; - - ScreenPriv->ForceHWCursorCount = 0; - ScreenPriv->HWCursorForced = FALSE; - - pScrn->EnableDisableFBAccess = xf86CursorEnableDisableFBAccess; - if (pScrn->SwitchMode) - pScrn->SwitchMode = xf86CursorSwitchMode; - - return TRUE; -} - -/***** Screen functions *****/ - -static Bool -xf86CursorCloseScreen(int i, ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - miPointerScreenPtr PointPriv = (miPointerScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, miPointerScreenKey); - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - if (ScreenPriv->isUp && pScrn->vtSema) - xf86SetCursor(pScreen, NullCursor, ScreenPriv->x, ScreenPriv->y); - - if (ScreenPriv->CurrentCursor) - FreeCursor(ScreenPriv->CurrentCursor, None); - - pScreen->CloseScreen = ScreenPriv->CloseScreen; - pScreen->QueryBestSize = ScreenPriv->QueryBestSize; - pScreen->RecolorCursor = ScreenPriv->RecolorCursor; - if (ScreenPriv->InstallColormap) - pScreen->InstallColormap = ScreenPriv->InstallColormap; - - PointPriv->spriteFuncs = ScreenPriv->spriteFuncs; - PointPriv->showTransparent = ScreenPriv->showTransparent; - - pScrn->EnableDisableFBAccess = ScreenPriv->EnableDisableFBAccess; - pScrn->SwitchMode = ScreenPriv->SwitchMode; - - xfree(ScreenPriv->transparentData); - xfree(ScreenPriv); - - return (*pScreen->CloseScreen)(i, pScreen); -} - -static void -xf86CursorQueryBestSize( - int class, - unsigned short *width, - unsigned short *height, - ScreenPtr pScreen) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - if (class == CursorShape) { - if(*width > ScreenPriv->CursorInfoPtr->MaxWidth) - *width = ScreenPriv->CursorInfoPtr->MaxWidth; - if(*height > ScreenPriv->CursorInfoPtr->MaxHeight) - *height = ScreenPriv->CursorInfoPtr->MaxHeight; - } else - (*ScreenPriv->QueryBestSize)(class, width, height, pScreen); -} - -static void -xf86CursorInstallColormap(ColormapPtr pMap) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pMap->pScreen->devPrivates, xf86CursorScreenKey); - - ScreenPriv->pInstalledMap = pMap; - - (*ScreenPriv->InstallColormap)(pMap); -} - -static void -xf86CursorRecolorCursor( - DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCurs, - Bool displayed) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - if (!displayed) - return; - - if (ScreenPriv->SWCursor) - (*ScreenPriv->RecolorCursor)(pDev, pScreen, pCurs, displayed); - else - xf86RecolorCursor(pScreen, pCurs, displayed); -} - -/***** ScrnInfoRec functions *********/ - -static void -xf86CursorEnableDisableFBAccess( - int index, - Bool enable) -{ - DeviceIntPtr pDev = inputInfo.pointer; - - ScreenPtr pScreen = screenInfo.screens[index]; - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - if (!enable && ScreenPriv->CurrentCursor != NullCursor) { - CursorPtr currentCursor = ScreenPriv->CurrentCursor; - xf86CursorSetCursor(pDev, pScreen, NullCursor, ScreenPriv->x, - ScreenPriv->y); - ScreenPriv->isUp = FALSE; - ScreenPriv->SWCursor = TRUE; - ScreenPriv->SavedCursor = currentCursor; - } - - if (ScreenPriv->EnableDisableFBAccess) - (*ScreenPriv->EnableDisableFBAccess)(index, enable); - - if (enable && ScreenPriv->SavedCursor) - { - /* - * Re-set current cursor so drivers can react to FB access having been - * temporarily disabled. - */ - xf86CursorSetCursor(pDev, pScreen, ScreenPriv->SavedCursor, - ScreenPriv->x, ScreenPriv->y); - ScreenPriv->SavedCursor = NULL; - } -} - -static Bool -xf86CursorSwitchMode(int index, DisplayModePtr mode, int flags) -{ - Bool ret; - ScreenPtr pScreen = screenInfo.screens[index]; - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - miPointerScreenPtr PointPriv = (miPointerScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, miPointerScreenKey); - - if (ScreenPriv->isUp) { - xf86SetCursor(pScreen, NullCursor, ScreenPriv->x, ScreenPriv->y); - ScreenPriv->isUp = FALSE; - } - - ret = (*ScreenPriv->SwitchMode)(index, mode, flags); - - /* - * Cannot restore cursor here because the new frame[XY][01] haven't been - * calculated yet. However, because the hardware cursor was removed above, - * ensure the cursor is repainted by miPointerWarpCursor(). - */ - ScreenPriv->CursorToRestore = ScreenPriv->CurrentCursor; - PointPriv->waitForUpdate = FALSE; /* Force cursor repaint */ - - return ret; -} - -/****** miPointerSpriteFunctions *******/ - -static Bool -xf86CursorRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - if (pCurs->refcnt <= 1) - dixSetPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen), NULL); - - return (*ScreenPriv->spriteFuncs->RealizeCursor)(pDev, pScreen, pCurs); -} - -static Bool -xf86CursorUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCurs) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - if (pCurs->refcnt <= 1) { - xfree(dixLookupPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen))); - dixSetPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen), NULL); - } - - return (*ScreenPriv->spriteFuncs->UnrealizeCursor)(pDev, pScreen, pCurs); -} - -static void -xf86CursorSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs, - int x, int y) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; - miPointerScreenPtr PointPriv = (miPointerScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, miPointerScreenKey); - - - if (pCurs == NullCursor) { /* means we're supposed to remove the cursor */ - if (ScreenPriv->SWCursor || - !(GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer)) - (*ScreenPriv->spriteFuncs->SetCursor)(pDev, pScreen, NullCursor, x, y); - else if (ScreenPriv->isUp) { - xf86SetCursor(pScreen, NullCursor, x, y); - ScreenPriv->isUp = FALSE; - } - if (ScreenPriv->CurrentCursor) - FreeCursor(ScreenPriv->CurrentCursor, None); - ScreenPriv->CurrentCursor = NullCursor; - return; - } - - /* only update for VCP, otherwise we get cursor jumps when removing a - sprite. The second cursor is never HW rendered anyway. */ - if (pDev == inputInfo.pointer || - (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer)) - { - pCurs->refcnt++; - if (ScreenPriv->CurrentCursor) - FreeCursor(ScreenPriv->CurrentCursor, None); - ScreenPriv->CurrentCursor = pCurs; - ScreenPriv->x = x; - ScreenPriv->y = y; - ScreenPriv->CursorToRestore = NULL; - ScreenPriv->HotX = pCurs->bits->xhot; - ScreenPriv->HotY = pCurs->bits->yhot; - - if (!infoPtr->pScrn->vtSema) - ScreenPriv->SavedCursor = pCurs; - - if (infoPtr->pScrn->vtSema && (ScreenPriv->ForceHWCursorCount || (( -#ifdef ARGB_CURSOR - pCurs->bits->argb && infoPtr->UseHWCursorARGB && - (*infoPtr->UseHWCursorARGB) (pScreen, pCurs) ) || ( - pCurs->bits->argb == 0 && -#endif - (pCurs->bits->height <= infoPtr->MaxHeight) && - (pCurs->bits->width <= infoPtr->MaxWidth) && - (!infoPtr->UseHWCursor || (*infoPtr->UseHWCursor)(pScreen, pCurs)))))) - { - - if (ScreenPriv->SWCursor) /* remove the SW cursor */ - (*ScreenPriv->spriteFuncs->SetCursor)(pDev, pScreen, NullCursor, x, y); - - xf86SetCursor(pScreen, pCurs, x, y); - ScreenPriv->SWCursor = FALSE; - ScreenPriv->isUp = TRUE; - PointPriv->waitForUpdate = !infoPtr->pScrn->silkenMouse; - return; - } - - PointPriv->waitForUpdate = TRUE; - - if (ScreenPriv->isUp) { - /* Remove the HW cursor, or make it transparent */ - if (infoPtr->Flags & HARDWARE_CURSOR_SHOW_TRANSPARENT) { - xf86SetTransparentCursor(pScreen); - } else { - xf86SetCursor(pScreen, NullCursor, x, y); - ScreenPriv->isUp = FALSE; - } - } - - if (!ScreenPriv->SWCursor) - ScreenPriv->SWCursor = TRUE; - - } - - if (pCurs->bits->emptyMask && !ScreenPriv->showTransparent) - pCurs = NullCursor; - - (*ScreenPriv->spriteFuncs->SetCursor)(pDev, pScreen, pCurs, x, y); -} - -static void -xf86CursorMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - /* only update coordinate state for first sprite, otherwise we get jumps - when removing a sprite. The second sprite is never HW rendered anyway */ - if (pDev == inputInfo.pointer || - (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer)) - { - ScreenPriv->x = x; - ScreenPriv->y = y; - - if (ScreenPriv->CursorToRestore) - xf86CursorSetCursor(pDev, pScreen, ScreenPriv->CursorToRestore, x, y); - else if (ScreenPriv->SWCursor) - (*ScreenPriv->spriteFuncs->MoveCursor)(pDev, pScreen, x, y); - else if (ScreenPriv->isUp) - xf86MoveCursor(pScreen, x, y); - } else - (*ScreenPriv->spriteFuncs->MoveCursor)(pDev, pScreen, x, y); -} - -void -xf86ForceHWCursor (ScreenPtr pScreen, Bool on) -{ - DeviceIntPtr pDev = inputInfo.pointer; - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - if (on) - { - if (ScreenPriv->ForceHWCursorCount++ == 0) - { - if (ScreenPriv->SWCursor && ScreenPriv->CurrentCursor) - { - ScreenPriv->HWCursorForced = TRUE; - xf86CursorSetCursor (pDev, pScreen, ScreenPriv->CurrentCursor, - ScreenPriv->x, ScreenPriv->y); - } - else - ScreenPriv->HWCursorForced = FALSE; - } - } - else - { - if (--ScreenPriv->ForceHWCursorCount == 0) - { - if (ScreenPriv->HWCursorForced && ScreenPriv->CurrentCursor) - xf86CursorSetCursor (pDev, pScreen, ScreenPriv->CurrentCursor, - ScreenPriv->x, ScreenPriv->y); - } - } -} - -xf86CursorInfoPtr -xf86CreateCursorInfoRec(void) -{ - return xcalloc(1, sizeof(xf86CursorInfoRec)); -} - -void -xf86DestroyCursorInfoRec(xf86CursorInfoPtr infoPtr) -{ - xfree(infoPtr); -} - -/** - * New cursor has been created. Do your initalizations here. - */ -static Bool -xf86DeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - int ret; - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - /* Init SW cursor */ - ret = (*ScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen); - - return ret; -} - -/** - * Cursor has been removed. Clean up after yourself. - */ -static void -xf86DeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - - /* Clean up SW cursor */ - (*ScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen); -} - + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86CursorPriv.h" +#include "colormapst.h" +#include "cursorstr.h" + +/* FIXME: This was added with the ABI change of the miPointerSpriteFuncs for + * MPX. + * inputInfo is needed to pass the core pointer as the default argument into + * the cursor functions. + * + * Externing inputInfo is not the nice way to do it but it works. + */ +#include "inputstr.h" +extern InputInfo inputInfo; + +static int xf86CursorScreenKeyIndex; +DevPrivateKey xf86CursorScreenKey = &xf86CursorScreenKeyIndex; + +/* sprite functions */ + +static Bool xf86CursorRealizeCursor(DeviceIntPtr, ScreenPtr, CursorPtr); +static Bool xf86CursorUnrealizeCursor(DeviceIntPtr, ScreenPtr, CursorPtr); +static void xf86CursorSetCursor(DeviceIntPtr, ScreenPtr, CursorPtr, int, int); +static void xf86CursorMoveCursor(DeviceIntPtr, ScreenPtr, int, int); +static Bool xf86DeviceCursorInitialize(DeviceIntPtr, ScreenPtr); +static void xf86DeviceCursorCleanup(DeviceIntPtr, ScreenPtr); + +static miPointerSpriteFuncRec xf86CursorSpriteFuncs = { + xf86CursorRealizeCursor, + xf86CursorUnrealizeCursor, + xf86CursorSetCursor, + xf86CursorMoveCursor, + xf86DeviceCursorInitialize, + xf86DeviceCursorCleanup +}; + +/* Screen functions */ + +static void xf86CursorInstallColormap(ColormapPtr); +static void xf86CursorRecolorCursor(DeviceIntPtr pDev, ScreenPtr, CursorPtr, Bool); +static Bool xf86CursorCloseScreen(int, ScreenPtr); +static void xf86CursorQueryBestSize(int, unsigned short*, unsigned short*, + ScreenPtr); + +/* ScrnInfoRec functions */ + +static void xf86CursorEnableDisableFBAccess(int, Bool); +static Bool xf86CursorSwitchMode(int, DisplayModePtr,int); + +Bool +xf86InitCursor( + ScreenPtr pScreen, + xf86CursorInfoPtr infoPtr +) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CursorScreenPtr ScreenPriv; + miPointerScreenPtr PointPriv; + + if (!xf86InitHardwareCursor(pScreen, infoPtr)) + return FALSE; + + ScreenPriv = calloc(1, sizeof(xf86CursorScreenRec)); + if (!ScreenPriv) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, xf86CursorScreenKey, ScreenPriv); + + ScreenPriv->SWCursor = TRUE; + ScreenPriv->isUp = FALSE; + ScreenPriv->CurrentCursor = NULL; + ScreenPriv->CursorInfoPtr = infoPtr; + ScreenPriv->PalettedCursor = FALSE; + ScreenPriv->pInstalledMap = NULL; + + ScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = xf86CursorCloseScreen; + ScreenPriv->QueryBestSize = pScreen->QueryBestSize; + pScreen->QueryBestSize = xf86CursorQueryBestSize; + ScreenPriv->RecolorCursor = pScreen->RecolorCursor; + pScreen->RecolorCursor = xf86CursorRecolorCursor; + + if ((infoPtr->pScrn->bitsPerPixel == 8) && + !(infoPtr->Flags & HARDWARE_CURSOR_TRUECOLOR_AT_8BPP)) { + ScreenPriv->InstallColormap = pScreen->InstallColormap; + pScreen->InstallColormap = xf86CursorInstallColormap; + ScreenPriv->PalettedCursor = TRUE; + } + + PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); + + ScreenPriv->showTransparent = PointPriv->showTransparent; + if (infoPtr->Flags & HARDWARE_CURSOR_SHOW_TRANSPARENT) + PointPriv->showTransparent = TRUE; + else + PointPriv->showTransparent = FALSE; + ScreenPriv->spriteFuncs = PointPriv->spriteFuncs; + PointPriv->spriteFuncs = &xf86CursorSpriteFuncs; + + ScreenPriv->EnableDisableFBAccess = pScrn->EnableDisableFBAccess; + ScreenPriv->SwitchMode = pScrn->SwitchMode; + + ScreenPriv->ForceHWCursorCount = 0; + ScreenPriv->HWCursorForced = FALSE; + + pScrn->EnableDisableFBAccess = xf86CursorEnableDisableFBAccess; + if (pScrn->SwitchMode) + pScrn->SwitchMode = xf86CursorSwitchMode; + + return TRUE; +} + +/***** Screen functions *****/ + +static Bool +xf86CursorCloseScreen(int i, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + miPointerScreenPtr PointPriv = (miPointerScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, miPointerScreenKey); + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + if (ScreenPriv->isUp && pScrn->vtSema) + xf86SetCursor(pScreen, NullCursor, ScreenPriv->x, ScreenPriv->y); + + if (ScreenPriv->CurrentCursor) + FreeCursor(ScreenPriv->CurrentCursor, None); + + pScreen->CloseScreen = ScreenPriv->CloseScreen; + pScreen->QueryBestSize = ScreenPriv->QueryBestSize; + pScreen->RecolorCursor = ScreenPriv->RecolorCursor; + if (ScreenPriv->InstallColormap) + pScreen->InstallColormap = ScreenPriv->InstallColormap; + + PointPriv->spriteFuncs = ScreenPriv->spriteFuncs; + PointPriv->showTransparent = ScreenPriv->showTransparent; + + pScrn->EnableDisableFBAccess = ScreenPriv->EnableDisableFBAccess; + pScrn->SwitchMode = ScreenPriv->SwitchMode; + + free(ScreenPriv->transparentData); + free(ScreenPriv); + + return (*pScreen->CloseScreen)(i, pScreen); +} + +static void +xf86CursorQueryBestSize( + int class, + unsigned short *width, + unsigned short *height, + ScreenPtr pScreen) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + if (class == CursorShape) { + if(*width > ScreenPriv->CursorInfoPtr->MaxWidth) + *width = ScreenPriv->CursorInfoPtr->MaxWidth; + if(*height > ScreenPriv->CursorInfoPtr->MaxHeight) + *height = ScreenPriv->CursorInfoPtr->MaxHeight; + } else + (*ScreenPriv->QueryBestSize)(class, width, height, pScreen); +} + +static void +xf86CursorInstallColormap(ColormapPtr pMap) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pMap->pScreen->devPrivates, xf86CursorScreenKey); + + ScreenPriv->pInstalledMap = pMap; + + (*ScreenPriv->InstallColormap)(pMap); +} + +static void +xf86CursorRecolorCursor( + DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCurs, + Bool displayed) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + if (!displayed) + return; + + if (ScreenPriv->SWCursor) + (*ScreenPriv->RecolorCursor)(pDev, pScreen, pCurs, displayed); + else + xf86RecolorCursor(pScreen, pCurs, displayed); +} + +/***** ScrnInfoRec functions *********/ + +static void +xf86CursorEnableDisableFBAccess( + int index, + Bool enable) +{ + DeviceIntPtr pDev = inputInfo.pointer; + + ScreenPtr pScreen = screenInfo.screens[index]; + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + if (!enable && ScreenPriv->CurrentCursor != NullCursor) { + CursorPtr currentCursor = ScreenPriv->CurrentCursor; + xf86CursorSetCursor(pDev, pScreen, NullCursor, ScreenPriv->x, + ScreenPriv->y); + ScreenPriv->isUp = FALSE; + ScreenPriv->SWCursor = TRUE; + ScreenPriv->SavedCursor = currentCursor; + } + + if (ScreenPriv->EnableDisableFBAccess) + (*ScreenPriv->EnableDisableFBAccess)(index, enable); + + if (enable && ScreenPriv->SavedCursor) + { + /* + * Re-set current cursor so drivers can react to FB access having been + * temporarily disabled. + */ + xf86CursorSetCursor(pDev, pScreen, ScreenPriv->SavedCursor, + ScreenPriv->x, ScreenPriv->y); + ScreenPriv->SavedCursor = NULL; + } +} + +static Bool +xf86CursorSwitchMode(int index, DisplayModePtr mode, int flags) +{ + Bool ret; + ScreenPtr pScreen = screenInfo.screens[index]; + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + miPointerScreenPtr PointPriv = (miPointerScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, miPointerScreenKey); + + if (ScreenPriv->isUp) { + xf86SetCursor(pScreen, NullCursor, ScreenPriv->x, ScreenPriv->y); + ScreenPriv->isUp = FALSE; + } + + ret = (*ScreenPriv->SwitchMode)(index, mode, flags); + + /* + * Cannot restore cursor here because the new frame[XY][01] haven't been + * calculated yet. However, because the hardware cursor was removed above, + * ensure the cursor is repainted by miPointerWarpCursor(). + */ + ScreenPriv->CursorToRestore = ScreenPriv->CurrentCursor; + PointPriv->waitForUpdate = FALSE; /* Force cursor repaint */ + + return ret; +} + +/****** miPointerSpriteFunctions *******/ + +static Bool +xf86CursorRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + if (pCurs->refcnt <= 1) + dixSetPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen), NULL); + + return (*ScreenPriv->spriteFuncs->RealizeCursor)(pDev, pScreen, pCurs); +} + +static Bool +xf86CursorUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCurs) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + if (pCurs->refcnt <= 1) { + free(dixLookupPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen))); + dixSetPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen), NULL); + } + + return (*ScreenPriv->spriteFuncs->UnrealizeCursor)(pDev, pScreen, pCurs); +} + +static void +xf86CursorSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs, + int x, int y) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; + miPointerScreenPtr PointPriv = (miPointerScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, miPointerScreenKey); + + + if (pCurs == NullCursor) { /* means we're supposed to remove the cursor */ + if (ScreenPriv->SWCursor || + !(GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer)) + (*ScreenPriv->spriteFuncs->SetCursor)(pDev, pScreen, NullCursor, x, y); + else if (ScreenPriv->isUp) { + xf86SetCursor(pScreen, NullCursor, x, y); + ScreenPriv->isUp = FALSE; + } + if (ScreenPriv->CurrentCursor) + FreeCursor(ScreenPriv->CurrentCursor, None); + ScreenPriv->CurrentCursor = NullCursor; + return; + } + + /* only update for VCP, otherwise we get cursor jumps when removing a + sprite. The second cursor is never HW rendered anyway. */ + if (pDev == inputInfo.pointer || + (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer)) + { + pCurs->refcnt++; + if (ScreenPriv->CurrentCursor) + FreeCursor(ScreenPriv->CurrentCursor, None); + ScreenPriv->CurrentCursor = pCurs; + ScreenPriv->x = x; + ScreenPriv->y = y; + ScreenPriv->CursorToRestore = NULL; + ScreenPriv->HotX = pCurs->bits->xhot; + ScreenPriv->HotY = pCurs->bits->yhot; + + if (!infoPtr->pScrn->vtSema) + ScreenPriv->SavedCursor = pCurs; + + if (infoPtr->pScrn->vtSema && (ScreenPriv->ForceHWCursorCount || (( +#ifdef ARGB_CURSOR + pCurs->bits->argb && infoPtr->UseHWCursorARGB && + (*infoPtr->UseHWCursorARGB) (pScreen, pCurs) ) || ( + pCurs->bits->argb == 0 && +#endif + (pCurs->bits->height <= infoPtr->MaxHeight) && + (pCurs->bits->width <= infoPtr->MaxWidth) && + (!infoPtr->UseHWCursor || (*infoPtr->UseHWCursor)(pScreen, pCurs)))))) + { + + if (ScreenPriv->SWCursor) /* remove the SW cursor */ + (*ScreenPriv->spriteFuncs->SetCursor)(pDev, pScreen, NullCursor, x, y); + + xf86SetCursor(pScreen, pCurs, x, y); + ScreenPriv->SWCursor = FALSE; + ScreenPriv->isUp = TRUE; + PointPriv->waitForUpdate = !infoPtr->pScrn->silkenMouse; + return; + } + + PointPriv->waitForUpdate = TRUE; + + if (ScreenPriv->isUp) { + /* Remove the HW cursor, or make it transparent */ + if (infoPtr->Flags & HARDWARE_CURSOR_SHOW_TRANSPARENT) { + xf86SetTransparentCursor(pScreen); + } else { + xf86SetCursor(pScreen, NullCursor, x, y); + ScreenPriv->isUp = FALSE; + } + } + + if (!ScreenPriv->SWCursor) + ScreenPriv->SWCursor = TRUE; + + } + + if (pCurs->bits->emptyMask && !ScreenPriv->showTransparent) + pCurs = NullCursor; + + (*ScreenPriv->spriteFuncs->SetCursor)(pDev, pScreen, pCurs, x, y); +} + +static void +xf86CursorMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + /* only update coordinate state for first sprite, otherwise we get jumps + when removing a sprite. The second sprite is never HW rendered anyway */ + if (pDev == inputInfo.pointer || + (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer)) + { + ScreenPriv->x = x; + ScreenPriv->y = y; + + if (ScreenPriv->CursorToRestore) + xf86CursorSetCursor(pDev, pScreen, ScreenPriv->CursorToRestore, x, y); + else if (ScreenPriv->SWCursor) + (*ScreenPriv->spriteFuncs->MoveCursor)(pDev, pScreen, x, y); + else if (ScreenPriv->isUp) + xf86MoveCursor(pScreen, x, y); + } else + (*ScreenPriv->spriteFuncs->MoveCursor)(pDev, pScreen, x, y); +} + +void +xf86ForceHWCursor (ScreenPtr pScreen, Bool on) +{ + DeviceIntPtr pDev = inputInfo.pointer; + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + if (on) + { + if (ScreenPriv->ForceHWCursorCount++ == 0) + { + if (ScreenPriv->SWCursor && ScreenPriv->CurrentCursor) + { + ScreenPriv->HWCursorForced = TRUE; + xf86CursorSetCursor (pDev, pScreen, ScreenPriv->CurrentCursor, + ScreenPriv->x, ScreenPriv->y); + } + else + ScreenPriv->HWCursorForced = FALSE; + } + } + else + { + if (--ScreenPriv->ForceHWCursorCount == 0) + { + if (ScreenPriv->HWCursorForced && ScreenPriv->CurrentCursor) + xf86CursorSetCursor (pDev, pScreen, ScreenPriv->CurrentCursor, + ScreenPriv->x, ScreenPriv->y); + } + } +} + +xf86CursorInfoPtr +xf86CreateCursorInfoRec(void) +{ + return calloc(1, sizeof(xf86CursorInfoRec)); +} + +void +xf86DestroyCursorInfoRec(xf86CursorInfoPtr infoPtr) +{ + free(infoPtr); +} + +/** + * New cursor has been created. Do your initalizations here. + */ +static Bool +xf86DeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + int ret; + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + /* Init SW cursor */ + ret = (*ScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen); + + return ret; +} + +/** + * Cursor has been removed. Clean up after yourself. + */ +static void +xf86DeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + + /* Clean up SW cursor */ + (*ScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen); +} + diff --git a/xorg-server/hw/xfree86/ramdac/xf86HWCurs.c b/xorg-server/hw/xfree86/ramdac/xf86HWCurs.c index 4374e51d4..43f28ef8e 100644 --- a/xorg-server/hw/xfree86/ramdac/xf86HWCurs.c +++ b/xorg-server/hw/xfree86/ramdac/xf86HWCurs.c @@ -1,527 +1,527 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "xf86str.h" -#include "cursorstr.h" -#include "mi.h" -#include "mipointer.h" -#include "xf86CursorPriv.h" - -#include "servermd.h" - -#if BITMAP_SCANLINE_PAD == 64 - -#if 1 -/* Cursors might be only 32 wide. Give'em a chance */ -#define SCANLINE CARD32 -#define CUR_BITMAP_SCANLINE_PAD 32 -#define CUR_LOG2_BITMAP_PAD 5 -#define REVERSE_BIT_ORDER(w) xf86ReverseBitOrder(w) -#else -#define SCANLINE CARD64 -#define CUR_BITMAP_SCANLINE_PAD BITMAP_SCANLINE_PAD -#define CUR_LOG2_BITMAP_PAD LOG2_BITMAP_PAD -#define REVERSE_BIT_ORDER(w) xf86CARD64ReverseBits(w) -static CARD64 xf86CARD64ReverseBits(CARD64 w); - -static CARD64 -xf86CARD64ReverseBits(CARD64 w) -{ - unsigned char *p = (unsigned char *)&w; - - p[0] = byte_reversed[p[0]]; - p[1] = byte_reversed[p[1]]; - p[2] = byte_reversed[p[2]]; - p[3] = byte_reversed[p[3]]; - p[4] = byte_reversed[p[4]]; - p[5] = byte_reversed[p[5]]; - p[6] = byte_reversed[p[6]]; - p[7] = byte_reversed[p[7]]; - - return w; -} -#endif - -#else - -#define SCANLINE CARD32 -#define CUR_BITMAP_SCANLINE_PAD BITMAP_SCANLINE_PAD -#define CUR_LOG2_BITMAP_PAD LOG2_BITMAP_PAD -#define REVERSE_BIT_ORDER(w) xf86ReverseBitOrder(w) - -#endif /* BITMAP_SCANLINE_PAD == 64 */ - -static unsigned char* RealizeCursorInterleave0(xf86CursorInfoPtr, CursorPtr); -static unsigned char* RealizeCursorInterleave1(xf86CursorInfoPtr, CursorPtr); -static unsigned char* RealizeCursorInterleave8(xf86CursorInfoPtr, CursorPtr); -static unsigned char* RealizeCursorInterleave16(xf86CursorInfoPtr, CursorPtr); -static unsigned char* RealizeCursorInterleave32(xf86CursorInfoPtr, CursorPtr); -static unsigned char* RealizeCursorInterleave64(xf86CursorInfoPtr, CursorPtr); - -Bool -xf86InitHardwareCursor(ScreenPtr pScreen, xf86CursorInfoPtr infoPtr) -{ - if ((infoPtr->MaxWidth <= 0) || (infoPtr->MaxHeight <= 0)) - return FALSE; - - /* These are required for now */ - if (!infoPtr->SetCursorPosition || - !infoPtr->LoadCursorImage || - !infoPtr->HideCursor || - !infoPtr->ShowCursor || - !infoPtr->SetCursorColors) - return FALSE; - - if (infoPtr->RealizeCursor) { - /* Don't overwrite a driver provided Realize Cursor function */ - } else - if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 & infoPtr->Flags) { - infoPtr->RealizeCursor = RealizeCursorInterleave1; - } else - if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 & infoPtr->Flags) { - infoPtr->RealizeCursor = RealizeCursorInterleave8; - } else - if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 & infoPtr->Flags) { - infoPtr->RealizeCursor = RealizeCursorInterleave16; - } else - if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 & infoPtr->Flags) { - infoPtr->RealizeCursor = RealizeCursorInterleave32; - } else - if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 & infoPtr->Flags) { - infoPtr->RealizeCursor = RealizeCursorInterleave64; - } else { /* not interleaved */ - infoPtr->RealizeCursor = RealizeCursorInterleave0; - } - - infoPtr->pScrn = xf86Screens[pScreen->myNum]; - - return TRUE; -} - -void -xf86SetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; - unsigned char *bits; - - if (pCurs == NullCursor) { - (*infoPtr->HideCursor)(infoPtr->pScrn); - return; - } - - bits = dixLookupPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen)); - - x -= infoPtr->pScrn->frameX0 + ScreenPriv->HotX; - y -= infoPtr->pScrn->frameY0 + ScreenPriv->HotY; - -#ifdef ARGB_CURSOR - if (!pCurs->bits->argb || !infoPtr->LoadCursorARGB) -#endif - if (!bits) { - bits = (*infoPtr->RealizeCursor)(infoPtr, pCurs); - dixSetPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen), bits); - } - - if (!(infoPtr->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN)) - (*infoPtr->HideCursor)(infoPtr->pScrn); - -#ifdef ARGB_CURSOR - if (pCurs->bits->argb && infoPtr->LoadCursorARGB) - (*infoPtr->LoadCursorARGB) (infoPtr->pScrn, pCurs); - else -#endif - if (bits) - (*infoPtr->LoadCursorImage)(infoPtr->pScrn, bits); - - xf86RecolorCursor(pScreen, pCurs, 1); - - (*infoPtr->SetCursorPosition)(infoPtr->pScrn, x, y); - - (*infoPtr->ShowCursor)(infoPtr->pScrn); -} - -void -xf86SetTransparentCursor(ScreenPtr pScreen) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; - - if (!ScreenPriv->transparentData) - ScreenPriv->transparentData = - (*infoPtr->RealizeCursor)(infoPtr, NullCursor); - - if (!(infoPtr->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN)) - (*infoPtr->HideCursor)(infoPtr->pScrn); - - if (ScreenPriv->transparentData) - (*infoPtr->LoadCursorImage)(infoPtr->pScrn, - ScreenPriv->transparentData); - - (*infoPtr->ShowCursor)(infoPtr->pScrn); -} - -void -xf86MoveCursor(ScreenPtr pScreen, int x, int y) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; - - x -= infoPtr->pScrn->frameX0 + ScreenPriv->HotX; - y -= infoPtr->pScrn->frameY0 + ScreenPriv->HotY; - - (*infoPtr->SetCursorPosition)(infoPtr->pScrn, x, y); -} - -void -xf86RecolorCursor(ScreenPtr pScreen, CursorPtr pCurs, Bool displayed) -{ - xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( - &pScreen->devPrivates, xf86CursorScreenKey); - xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; - -#ifdef ARGB_CURSOR - /* recoloring isn't applicable to ARGB cursors and drivers - shouldn't have to ignore SetCursorColors requests */ - if (pCurs->bits->argb) - return; -#endif - - if (ScreenPriv->PalettedCursor) { - xColorItem sourceColor, maskColor; - ColormapPtr pmap = ScreenPriv->pInstalledMap; - - if (!pmap) - return; - - sourceColor.red = pCurs->foreRed; - sourceColor.green = pCurs->foreGreen; - sourceColor.blue = pCurs->foreBlue; - FakeAllocColor(pmap, &sourceColor); - maskColor.red = pCurs->backRed; - maskColor.green = pCurs->backGreen; - maskColor.blue = pCurs->backBlue; - FakeAllocColor(pmap, &maskColor); - FakeFreeColor(pmap, sourceColor.pixel); - FakeFreeColor(pmap, maskColor.pixel); - (*infoPtr->SetCursorColors)(infoPtr->pScrn, - maskColor.pixel, sourceColor.pixel); - } else { /* Pass colors in 8-8-8 RGB format */ - (*infoPtr->SetCursorColors)(infoPtr->pScrn, - (pCurs->backBlue >> 8) | - ((pCurs->backGreen >> 8) << 8) | - ((pCurs->backRed >> 8) << 16), - (pCurs->foreBlue >> 8) | - ((pCurs->foreGreen >> 8) << 8) | - ((pCurs->foreRed >> 8) << 16) - ); - } -} - -/* These functions assume that MaxWidth is a multiple of 32 */ -static unsigned char* -RealizeCursorInterleave0(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) -{ - - SCANLINE *SrcS, *SrcM, *DstS, *DstM; - SCANLINE *pSrc, *pMsk; - unsigned char *mem; - int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; - int SrcPitch, DstPitch, Pitch, y, x; - /* how many words are in the source or mask */ - int words = size / (CUR_BITMAP_SCANLINE_PAD / 4); - - - if (!(mem = xcalloc(1, size))) - return NULL; - - if (pCurs == NullCursor) { - if (infoPtr->Flags & HARDWARE_CURSOR_INVERT_MASK) { - DstM = (SCANLINE*)mem; - if (!(infoPtr->Flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK)) - DstM += words; - memset(DstM, -1, words * sizeof(SCANLINE)); - } - return mem; - } - - /* SrcPitch == the number of scanlines wide the cursor image is */ - SrcPitch = (pCurs->bits->width + (BITMAP_SCANLINE_PAD - 1)) >> - CUR_LOG2_BITMAP_PAD; - - /* DstPitch is the width of the hw cursor in scanlines */ - DstPitch = infoPtr->MaxWidth >> CUR_LOG2_BITMAP_PAD; - Pitch = SrcPitch < DstPitch ? SrcPitch : DstPitch; - - SrcS = (SCANLINE*)pCurs->bits->source; - SrcM = (SCANLINE*)pCurs->bits->mask; - DstS = (SCANLINE*)mem; - DstM = DstS + words; - - if (infoPtr->Flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK) { - SCANLINE *tmp; - tmp = DstS; DstS = DstM; DstM = tmp; - } - - if (infoPtr->Flags & HARDWARE_CURSOR_AND_SOURCE_WITH_MASK) { - for(y = pCurs->bits->height, pSrc = DstS, pMsk = DstM; - y--; - pSrc+=DstPitch, pMsk+=DstPitch, SrcS+=SrcPitch, SrcM+=SrcPitch) { - for(x = 0; x < Pitch; x++) { - pSrc[x] = SrcS[x] & SrcM[x]; - pMsk[x] = SrcM[x]; - } - } - } else { - for(y = pCurs->bits->height, pSrc = DstS, pMsk = DstM; - y--; - pSrc+=DstPitch, pMsk+=DstPitch, SrcS+=SrcPitch, SrcM+=SrcPitch) { - for(x = 0; x < Pitch; x++) { - pSrc[x] = SrcS[x]; - pMsk[x] = SrcM[x]; - } - } - } - - if (infoPtr->Flags & HARDWARE_CURSOR_NIBBLE_SWAPPED) { - int count = size; - unsigned char* pntr1 = (unsigned char *)DstS; - unsigned char* pntr2 = (unsigned char *)DstM; - unsigned char a, b; - while (count) { - - a = *pntr1; - b = *pntr2; - *pntr1 = ((a & 0xF0) >> 4) | ((a & 0x0F) << 4); - *pntr2 = ((b & 0xF0) >> 4) | ((b & 0x0F) << 4); - pntr1++; pntr2++; - count-=2; - } - } - - /* - * Must be _after_ HARDWARE_CURSOR_AND_SOURCE_WITH_MASK to avoid wiping - * out entire source mask. - */ - if (infoPtr->Flags & HARDWARE_CURSOR_INVERT_MASK) { - int count = words; - SCANLINE* pntr = DstM; - while (count--) { - *pntr = ~(*pntr); - pntr++; - } - } - - if (infoPtr->Flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) { - for(y = pCurs->bits->height, pSrc = DstS, pMsk = DstM; - y--; - pSrc+=DstPitch, pMsk+=DstPitch) { - for(x = 0; x < Pitch; x++) { - pSrc[x] = REVERSE_BIT_ORDER(pSrc[x]); - pMsk[x] = REVERSE_BIT_ORDER(pMsk[x]); - } - } - } - - return mem; -} - -static unsigned char* -RealizeCursorInterleave1(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) -{ - unsigned char *DstS, *DstM; - unsigned char *pntr; - unsigned char *mem, *mem2; - int count; - int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; - - /* Realize the cursor without interleaving */ - if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) - return NULL; - - if (!(mem = xcalloc(1, size))) { - xfree(mem2); - return NULL; - } - - /* 1 bit interleave */ - DstS = mem2; - DstM = DstS + (size >> 1); - pntr = mem; - count = size; - while (count) { - *pntr++ = ((*DstS&0x01) ) | ((*DstM&0x01) << 1) | - ((*DstS&0x02) << 1) | ((*DstM&0x02) << 2) | - ((*DstS&0x04) << 2) | ((*DstM&0x04) << 3) | - ((*DstS&0x08) << 3) | ((*DstM&0x08) << 4); - *pntr++ = ((*DstS&0x10) >> 4) | ((*DstM&0x10) >> 3) | - ((*DstS&0x20) >> 3) | ((*DstM&0x20) >> 2) | - ((*DstS&0x40) >> 2) | ((*DstM&0x40) >> 1) | - ((*DstS&0x80) >> 1) | ((*DstM&0x80) ); - DstS++; - DstM++; - count-=2; - } - - /* Free the uninterleaved cursor */ - xfree(mem2); - - return mem; -} - -static unsigned char* -RealizeCursorInterleave8(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) -{ - unsigned char *DstS, *DstM; - unsigned char *pntr; - unsigned char *mem, *mem2; - int count; - int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; - - /* Realize the cursor without interleaving */ - if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) - return NULL; - - if (!(mem = xcalloc(1, size))) { - xfree(mem2); - return NULL; - } - - /* 8 bit interleave */ - DstS = mem2; - DstM = DstS + (size >> 1); - pntr = mem; - count = size; - while (count) { - *pntr++ = *DstS++; - *pntr++ = *DstM++; - count-=2; - } - - /* Free the uninterleaved cursor */ - xfree(mem2); - - return mem; -} - -static unsigned char* -RealizeCursorInterleave16(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) -{ - unsigned short *DstS, *DstM; - unsigned short *pntr; - unsigned char *mem, *mem2; - int count; - int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; - - /* Realize the cursor without interleaving */ - if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) - return NULL; - - if (!(mem = xcalloc(1, size))) { - xfree(mem2); - return NULL; - } - - /* 16 bit interleave */ - DstS = (pointer)mem2; - DstM = DstS + (size >> 2); - pntr = (pointer)mem; - count = (size >> 1); - while (count) { - *pntr++ = *DstS++; - *pntr++ = *DstM++; - count-=2; - } - - /* Free the uninterleaved cursor */ - xfree(mem2); - - return mem; -} - -static unsigned char* -RealizeCursorInterleave32(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) -{ - CARD32 *DstS, *DstM; - CARD32 *pntr; - unsigned char *mem, *mem2; - int count; - int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; - - /* Realize the cursor without interleaving */ - if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) - return NULL; - - if (!(mem = xcalloc(1, size))) { - xfree(mem2); - return NULL; - } - - /* 32 bit interleave */ - DstS = (pointer)mem2; - DstM = DstS + (size >> 3); - pntr = (pointer)mem; - count = (size >> 2); - while (count) { - *pntr++ = *DstS++; - *pntr++ = *DstM++; - count-=2; - } - - /* Free the uninterleaved cursor */ - xfree(mem2); - - return mem; -} - -static unsigned char* -RealizeCursorInterleave64(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) -{ - CARD32 *DstS, *DstM; - CARD32 *pntr; - unsigned char *mem, *mem2; - int count; - int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; - - /* Realize the cursor without interleaving */ - if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) - return NULL; - - if (!(mem = xcalloc(1, size))) { - xfree(mem2); - return NULL; - } - - /* 64 bit interleave */ - DstS = (pointer)mem2; - DstM = DstS + (size >> 3); - pntr = (pointer)mem; - count = (size >> 2); - while (count) { - *pntr++ = *DstS++; - *pntr++ = *DstS++; - *pntr++ = *DstM++; - *pntr++ = *DstM++; - count-=4; - } - - /* Free the uninterleaved cursor */ - xfree(mem2); - - return mem; -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "xf86str.h" +#include "cursorstr.h" +#include "mi.h" +#include "mipointer.h" +#include "xf86CursorPriv.h" + +#include "servermd.h" + +#if BITMAP_SCANLINE_PAD == 64 + +#if 1 +/* Cursors might be only 32 wide. Give'em a chance */ +#define SCANLINE CARD32 +#define CUR_BITMAP_SCANLINE_PAD 32 +#define CUR_LOG2_BITMAP_PAD 5 +#define REVERSE_BIT_ORDER(w) xf86ReverseBitOrder(w) +#else +#define SCANLINE CARD64 +#define CUR_BITMAP_SCANLINE_PAD BITMAP_SCANLINE_PAD +#define CUR_LOG2_BITMAP_PAD LOG2_BITMAP_PAD +#define REVERSE_BIT_ORDER(w) xf86CARD64ReverseBits(w) +static CARD64 xf86CARD64ReverseBits(CARD64 w); + +static CARD64 +xf86CARD64ReverseBits(CARD64 w) +{ + unsigned char *p = (unsigned char *)&w; + + p[0] = byte_reversed[p[0]]; + p[1] = byte_reversed[p[1]]; + p[2] = byte_reversed[p[2]]; + p[3] = byte_reversed[p[3]]; + p[4] = byte_reversed[p[4]]; + p[5] = byte_reversed[p[5]]; + p[6] = byte_reversed[p[6]]; + p[7] = byte_reversed[p[7]]; + + return w; +} +#endif + +#else + +#define SCANLINE CARD32 +#define CUR_BITMAP_SCANLINE_PAD BITMAP_SCANLINE_PAD +#define CUR_LOG2_BITMAP_PAD LOG2_BITMAP_PAD +#define REVERSE_BIT_ORDER(w) xf86ReverseBitOrder(w) + +#endif /* BITMAP_SCANLINE_PAD == 64 */ + +static unsigned char* RealizeCursorInterleave0(xf86CursorInfoPtr, CursorPtr); +static unsigned char* RealizeCursorInterleave1(xf86CursorInfoPtr, CursorPtr); +static unsigned char* RealizeCursorInterleave8(xf86CursorInfoPtr, CursorPtr); +static unsigned char* RealizeCursorInterleave16(xf86CursorInfoPtr, CursorPtr); +static unsigned char* RealizeCursorInterleave32(xf86CursorInfoPtr, CursorPtr); +static unsigned char* RealizeCursorInterleave64(xf86CursorInfoPtr, CursorPtr); + +Bool +xf86InitHardwareCursor(ScreenPtr pScreen, xf86CursorInfoPtr infoPtr) +{ + if ((infoPtr->MaxWidth <= 0) || (infoPtr->MaxHeight <= 0)) + return FALSE; + + /* These are required for now */ + if (!infoPtr->SetCursorPosition || + !infoPtr->LoadCursorImage || + !infoPtr->HideCursor || + !infoPtr->ShowCursor || + !infoPtr->SetCursorColors) + return FALSE; + + if (infoPtr->RealizeCursor) { + /* Don't overwrite a driver provided Realize Cursor function */ + } else + if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 & infoPtr->Flags) { + infoPtr->RealizeCursor = RealizeCursorInterleave1; + } else + if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 & infoPtr->Flags) { + infoPtr->RealizeCursor = RealizeCursorInterleave8; + } else + if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 & infoPtr->Flags) { + infoPtr->RealizeCursor = RealizeCursorInterleave16; + } else + if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 & infoPtr->Flags) { + infoPtr->RealizeCursor = RealizeCursorInterleave32; + } else + if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 & infoPtr->Flags) { + infoPtr->RealizeCursor = RealizeCursorInterleave64; + } else { /* not interleaved */ + infoPtr->RealizeCursor = RealizeCursorInterleave0; + } + + infoPtr->pScrn = xf86Screens[pScreen->myNum]; + + return TRUE; +} + +void +xf86SetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; + unsigned char *bits; + + if (pCurs == NullCursor) { + (*infoPtr->HideCursor)(infoPtr->pScrn); + return; + } + + bits = dixLookupPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen)); + + x -= infoPtr->pScrn->frameX0 + ScreenPriv->HotX; + y -= infoPtr->pScrn->frameY0 + ScreenPriv->HotY; + +#ifdef ARGB_CURSOR + if (!pCurs->bits->argb || !infoPtr->LoadCursorARGB) +#endif + if (!bits) { + bits = (*infoPtr->RealizeCursor)(infoPtr, pCurs); + dixSetPrivate(&pCurs->devPrivates, CursorScreenKey(pScreen), bits); + } + + if (!(infoPtr->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN)) + (*infoPtr->HideCursor)(infoPtr->pScrn); + +#ifdef ARGB_CURSOR + if (pCurs->bits->argb && infoPtr->LoadCursorARGB) + (*infoPtr->LoadCursorARGB) (infoPtr->pScrn, pCurs); + else +#endif + if (bits) + (*infoPtr->LoadCursorImage)(infoPtr->pScrn, bits); + + xf86RecolorCursor(pScreen, pCurs, 1); + + (*infoPtr->SetCursorPosition)(infoPtr->pScrn, x, y); + + (*infoPtr->ShowCursor)(infoPtr->pScrn); +} + +void +xf86SetTransparentCursor(ScreenPtr pScreen) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; + + if (!ScreenPriv->transparentData) + ScreenPriv->transparentData = + (*infoPtr->RealizeCursor)(infoPtr, NullCursor); + + if (!(infoPtr->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN)) + (*infoPtr->HideCursor)(infoPtr->pScrn); + + if (ScreenPriv->transparentData) + (*infoPtr->LoadCursorImage)(infoPtr->pScrn, + ScreenPriv->transparentData); + + (*infoPtr->ShowCursor)(infoPtr->pScrn); +} + +void +xf86MoveCursor(ScreenPtr pScreen, int x, int y) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; + + x -= infoPtr->pScrn->frameX0 + ScreenPriv->HotX; + y -= infoPtr->pScrn->frameY0 + ScreenPriv->HotY; + + (*infoPtr->SetCursorPosition)(infoPtr->pScrn, x, y); +} + +void +xf86RecolorCursor(ScreenPtr pScreen, CursorPtr pCurs, Bool displayed) +{ + xf86CursorScreenPtr ScreenPriv = (xf86CursorScreenPtr)dixLookupPrivate( + &pScreen->devPrivates, xf86CursorScreenKey); + xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr; + +#ifdef ARGB_CURSOR + /* recoloring isn't applicable to ARGB cursors and drivers + shouldn't have to ignore SetCursorColors requests */ + if (pCurs->bits->argb) + return; +#endif + + if (ScreenPriv->PalettedCursor) { + xColorItem sourceColor, maskColor; + ColormapPtr pmap = ScreenPriv->pInstalledMap; + + if (!pmap) + return; + + sourceColor.red = pCurs->foreRed; + sourceColor.green = pCurs->foreGreen; + sourceColor.blue = pCurs->foreBlue; + FakeAllocColor(pmap, &sourceColor); + maskColor.red = pCurs->backRed; + maskColor.green = pCurs->backGreen; + maskColor.blue = pCurs->backBlue; + FakeAllocColor(pmap, &maskColor); + FakeFreeColor(pmap, sourceColor.pixel); + FakeFreeColor(pmap, maskColor.pixel); + (*infoPtr->SetCursorColors)(infoPtr->pScrn, + maskColor.pixel, sourceColor.pixel); + } else { /* Pass colors in 8-8-8 RGB format */ + (*infoPtr->SetCursorColors)(infoPtr->pScrn, + (pCurs->backBlue >> 8) | + ((pCurs->backGreen >> 8) << 8) | + ((pCurs->backRed >> 8) << 16), + (pCurs->foreBlue >> 8) | + ((pCurs->foreGreen >> 8) << 8) | + ((pCurs->foreRed >> 8) << 16) + ); + } +} + +/* These functions assume that MaxWidth is a multiple of 32 */ +static unsigned char* +RealizeCursorInterleave0(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) +{ + + SCANLINE *SrcS, *SrcM, *DstS, *DstM; + SCANLINE *pSrc, *pMsk; + unsigned char *mem; + int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; + int SrcPitch, DstPitch, Pitch, y, x; + /* how many words are in the source or mask */ + int words = size / (CUR_BITMAP_SCANLINE_PAD / 4); + + + if (!(mem = calloc(1, size))) + return NULL; + + if (pCurs == NullCursor) { + if (infoPtr->Flags & HARDWARE_CURSOR_INVERT_MASK) { + DstM = (SCANLINE*)mem; + if (!(infoPtr->Flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK)) + DstM += words; + memset(DstM, -1, words * sizeof(SCANLINE)); + } + return mem; + } + + /* SrcPitch == the number of scanlines wide the cursor image is */ + SrcPitch = (pCurs->bits->width + (BITMAP_SCANLINE_PAD - 1)) >> + CUR_LOG2_BITMAP_PAD; + + /* DstPitch is the width of the hw cursor in scanlines */ + DstPitch = infoPtr->MaxWidth >> CUR_LOG2_BITMAP_PAD; + Pitch = SrcPitch < DstPitch ? SrcPitch : DstPitch; + + SrcS = (SCANLINE*)pCurs->bits->source; + SrcM = (SCANLINE*)pCurs->bits->mask; + DstS = (SCANLINE*)mem; + DstM = DstS + words; + + if (infoPtr->Flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK) { + SCANLINE *tmp; + tmp = DstS; DstS = DstM; DstM = tmp; + } + + if (infoPtr->Flags & HARDWARE_CURSOR_AND_SOURCE_WITH_MASK) { + for(y = pCurs->bits->height, pSrc = DstS, pMsk = DstM; + y--; + pSrc+=DstPitch, pMsk+=DstPitch, SrcS+=SrcPitch, SrcM+=SrcPitch) { + for(x = 0; x < Pitch; x++) { + pSrc[x] = SrcS[x] & SrcM[x]; + pMsk[x] = SrcM[x]; + } + } + } else { + for(y = pCurs->bits->height, pSrc = DstS, pMsk = DstM; + y--; + pSrc+=DstPitch, pMsk+=DstPitch, SrcS+=SrcPitch, SrcM+=SrcPitch) { + for(x = 0; x < Pitch; x++) { + pSrc[x] = SrcS[x]; + pMsk[x] = SrcM[x]; + } + } + } + + if (infoPtr->Flags & HARDWARE_CURSOR_NIBBLE_SWAPPED) { + int count = size; + unsigned char* pntr1 = (unsigned char *)DstS; + unsigned char* pntr2 = (unsigned char *)DstM; + unsigned char a, b; + while (count) { + + a = *pntr1; + b = *pntr2; + *pntr1 = ((a & 0xF0) >> 4) | ((a & 0x0F) << 4); + *pntr2 = ((b & 0xF0) >> 4) | ((b & 0x0F) << 4); + pntr1++; pntr2++; + count-=2; + } + } + + /* + * Must be _after_ HARDWARE_CURSOR_AND_SOURCE_WITH_MASK to avoid wiping + * out entire source mask. + */ + if (infoPtr->Flags & HARDWARE_CURSOR_INVERT_MASK) { + int count = words; + SCANLINE* pntr = DstM; + while (count--) { + *pntr = ~(*pntr); + pntr++; + } + } + + if (infoPtr->Flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) { + for(y = pCurs->bits->height, pSrc = DstS, pMsk = DstM; + y--; + pSrc+=DstPitch, pMsk+=DstPitch) { + for(x = 0; x < Pitch; x++) { + pSrc[x] = REVERSE_BIT_ORDER(pSrc[x]); + pMsk[x] = REVERSE_BIT_ORDER(pMsk[x]); + } + } + } + + return mem; +} + +static unsigned char* +RealizeCursorInterleave1(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) +{ + unsigned char *DstS, *DstM; + unsigned char *pntr; + unsigned char *mem, *mem2; + int count; + int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; + + /* Realize the cursor without interleaving */ + if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) + return NULL; + + if (!(mem = calloc(1, size))) { + free(mem2); + return NULL; + } + + /* 1 bit interleave */ + DstS = mem2; + DstM = DstS + (size >> 1); + pntr = mem; + count = size; + while (count) { + *pntr++ = ((*DstS&0x01) ) | ((*DstM&0x01) << 1) | + ((*DstS&0x02) << 1) | ((*DstM&0x02) << 2) | + ((*DstS&0x04) << 2) | ((*DstM&0x04) << 3) | + ((*DstS&0x08) << 3) | ((*DstM&0x08) << 4); + *pntr++ = ((*DstS&0x10) >> 4) | ((*DstM&0x10) >> 3) | + ((*DstS&0x20) >> 3) | ((*DstM&0x20) >> 2) | + ((*DstS&0x40) >> 2) | ((*DstM&0x40) >> 1) | + ((*DstS&0x80) >> 1) | ((*DstM&0x80) ); + DstS++; + DstM++; + count-=2; + } + + /* Free the uninterleaved cursor */ + free(mem2); + + return mem; +} + +static unsigned char* +RealizeCursorInterleave8(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) +{ + unsigned char *DstS, *DstM; + unsigned char *pntr; + unsigned char *mem, *mem2; + int count; + int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; + + /* Realize the cursor without interleaving */ + if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) + return NULL; + + if (!(mem = calloc(1, size))) { + free(mem2); + return NULL; + } + + /* 8 bit interleave */ + DstS = mem2; + DstM = DstS + (size >> 1); + pntr = mem; + count = size; + while (count) { + *pntr++ = *DstS++; + *pntr++ = *DstM++; + count-=2; + } + + /* Free the uninterleaved cursor */ + free(mem2); + + return mem; +} + +static unsigned char* +RealizeCursorInterleave16(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) +{ + unsigned short *DstS, *DstM; + unsigned short *pntr; + unsigned char *mem, *mem2; + int count; + int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; + + /* Realize the cursor without interleaving */ + if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) + return NULL; + + if (!(mem = calloc(1, size))) { + free(mem2); + return NULL; + } + + /* 16 bit interleave */ + DstS = (pointer)mem2; + DstM = DstS + (size >> 2); + pntr = (pointer)mem; + count = (size >> 1); + while (count) { + *pntr++ = *DstS++; + *pntr++ = *DstM++; + count-=2; + } + + /* Free the uninterleaved cursor */ + free(mem2); + + return mem; +} + +static unsigned char* +RealizeCursorInterleave32(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) +{ + CARD32 *DstS, *DstM; + CARD32 *pntr; + unsigned char *mem, *mem2; + int count; + int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; + + /* Realize the cursor without interleaving */ + if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) + return NULL; + + if (!(mem = calloc(1, size))) { + free(mem2); + return NULL; + } + + /* 32 bit interleave */ + DstS = (pointer)mem2; + DstM = DstS + (size >> 3); + pntr = (pointer)mem; + count = (size >> 2); + while (count) { + *pntr++ = *DstS++; + *pntr++ = *DstM++; + count-=2; + } + + /* Free the uninterleaved cursor */ + free(mem2); + + return mem; +} + +static unsigned char* +RealizeCursorInterleave64(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) +{ + CARD32 *DstS, *DstM; + CARD32 *pntr; + unsigned char *mem, *mem2; + int count; + int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2; + + /* Realize the cursor without interleaving */ + if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs))) + return NULL; + + if (!(mem = calloc(1, size))) { + free(mem2); + return NULL; + } + + /* 64 bit interleave */ + DstS = (pointer)mem2; + DstM = DstS + (size >> 3); + pntr = (pointer)mem; + count = (size >> 2); + while (count) { + *pntr++ = *DstS++; + *pntr++ = *DstS++; + *pntr++ = *DstM++; + *pntr++ = *DstM++; + count-=4; + } + + /* Free the uninterleaved cursor */ + free(mem2); + + return mem; +} diff --git a/xorg-server/hw/xfree86/ramdac/xf86RamDac.c b/xorg-server/hw/xfree86/ramdac/xf86RamDac.c index bd4f3466a..25d450c07 100644 --- a/xorg-server/hw/xfree86/ramdac/xf86RamDac.c +++ b/xorg-server/hw/xfree86/ramdac/xf86RamDac.c @@ -1,154 +1,154 @@ -/* - * Copyright 1998 by Alan Hourihane, Wigan, England. - * - * 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 Alan Hourihane not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Alan Hourihane makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL ALAN HOURIHANE 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. - * - * Authors: Alan Hourihane, <alanh@fairlite.demon.co.uk> - * - * Generic RAMDAC access routines. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xf86.h" -#include "xf86_OSproc.h" - -#include "xf86RamDacPriv.h" - -int RamDacHWPrivateIndex = -1; -int RamDacScreenPrivateIndex = -1; - -RamDacRecPtr -RamDacCreateInfoRec(void) -{ - RamDacRecPtr infoRec; - - infoRec = xcalloc(1, sizeof(RamDacRec)); - - return infoRec; -} - -RamDacHelperRecPtr -RamDacHelperCreateInfoRec(void) -{ - RamDacHelperRecPtr infoRec; - - infoRec = xcalloc(1, sizeof(RamDacHelperRec)); - - return infoRec; -} - -void -RamDacDestroyInfoRec(RamDacRecPtr infoRec) -{ - xfree(infoRec); -} - -void -RamDacHelperDestroyInfoRec(RamDacHelperRecPtr infoRec) -{ - xfree(infoRec); -} - -Bool -RamDacInit(ScrnInfoPtr pScrn, RamDacRecPtr ramdacPriv) -{ - RamDacScreenRecPtr ramdacScrPtr; - - /* - * make sure the RamDacRec is allocated - */ - if (!RamDacGetRec(pScrn)) - return FALSE; - ramdacScrPtr = - ((RamDacScreenRecPtr) (pScrn)->privates[RamDacGetScreenIndex()].ptr); - ramdacScrPtr->RamDacRec = ramdacPriv; - - return(TRUE); -} - -void -RamDacGetRecPrivate(void) -{ - if (RamDacHWPrivateIndex < 0) - RamDacHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); - if (RamDacScreenPrivateIndex < 0) - RamDacScreenPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); - return; -} - -Bool -RamDacGetRec(ScrnInfoPtr scrp) -{ - RamDacGetRecPrivate(); - /* - * New privates are always set to NULL, so we can check if the allocation - * has already been done. - */ - if (scrp->privates[RamDacHWPrivateIndex].ptr != NULL) - return TRUE; - if (scrp->privates[RamDacScreenPrivateIndex].ptr != NULL) - return TRUE; - - scrp->privates[RamDacHWPrivateIndex].ptr = - xnfcalloc(sizeof(RamDacHWRec), 1); - scrp->privates[RamDacScreenPrivateIndex].ptr = - xnfcalloc(sizeof(RamDacScreenRec), 1); - - return TRUE; -} - -void -RamDacFreeRec(ScrnInfoPtr pScrn) -{ - RamDacHWRecPtr ramdacHWPtr; - RamDacScreenRecPtr ramdacScrPtr; - - if (RamDacHWPrivateIndex < 0) - return; - - if (RamDacScreenPrivateIndex < 0) - return; - - ramdacHWPtr = RAMDACHWPTR(pScrn); - ramdacScrPtr = ((RamDacScreenRecPtr) - (pScrn)->privates[RamDacGetScreenIndex()].ptr); - - if (ramdacHWPtr) - xfree(ramdacHWPtr); - ramdacHWPtr = NULL; - - if (ramdacScrPtr) - xfree(ramdacScrPtr); - ramdacScrPtr = NULL; -} - -int -RamDacGetHWIndex(void) -{ - return RamDacHWPrivateIndex; -} - -int -RamDacGetScreenIndex(void) -{ - return RamDacScreenPrivateIndex; -} +/* + * Copyright 1998 by Alan Hourihane, Wigan, England. + * + * 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 Alan Hourihane not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Alan Hourihane makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ALAN HOURIHANE 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. + * + * Authors: Alan Hourihane, <alanh@fairlite.demon.co.uk> + * + * Generic RAMDAC access routines. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "xf86RamDacPriv.h" + +int RamDacHWPrivateIndex = -1; +int RamDacScreenPrivateIndex = -1; + +RamDacRecPtr +RamDacCreateInfoRec(void) +{ + RamDacRecPtr infoRec; + + infoRec = calloc(1, sizeof(RamDacRec)); + + return infoRec; +} + +RamDacHelperRecPtr +RamDacHelperCreateInfoRec(void) +{ + RamDacHelperRecPtr infoRec; + + infoRec = calloc(1, sizeof(RamDacHelperRec)); + + return infoRec; +} + +void +RamDacDestroyInfoRec(RamDacRecPtr infoRec) +{ + free(infoRec); +} + +void +RamDacHelperDestroyInfoRec(RamDacHelperRecPtr infoRec) +{ + free(infoRec); +} + +Bool +RamDacInit(ScrnInfoPtr pScrn, RamDacRecPtr ramdacPriv) +{ + RamDacScreenRecPtr ramdacScrPtr; + + /* + * make sure the RamDacRec is allocated + */ + if (!RamDacGetRec(pScrn)) + return FALSE; + ramdacScrPtr = + ((RamDacScreenRecPtr) (pScrn)->privates[RamDacGetScreenIndex()].ptr); + ramdacScrPtr->RamDacRec = ramdacPriv; + + return(TRUE); +} + +void +RamDacGetRecPrivate(void) +{ + if (RamDacHWPrivateIndex < 0) + RamDacHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + if (RamDacScreenPrivateIndex < 0) + RamDacScreenPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + return; +} + +Bool +RamDacGetRec(ScrnInfoPtr scrp) +{ + RamDacGetRecPrivate(); + /* + * New privates are always set to NULL, so we can check if the allocation + * has already been done. + */ + if (scrp->privates[RamDacHWPrivateIndex].ptr != NULL) + return TRUE; + if (scrp->privates[RamDacScreenPrivateIndex].ptr != NULL) + return TRUE; + + scrp->privates[RamDacHWPrivateIndex].ptr = + xnfcalloc(sizeof(RamDacHWRec), 1); + scrp->privates[RamDacScreenPrivateIndex].ptr = + xnfcalloc(sizeof(RamDacScreenRec), 1); + + return TRUE; +} + +void +RamDacFreeRec(ScrnInfoPtr pScrn) +{ + RamDacHWRecPtr ramdacHWPtr; + RamDacScreenRecPtr ramdacScrPtr; + + if (RamDacHWPrivateIndex < 0) + return; + + if (RamDacScreenPrivateIndex < 0) + return; + + ramdacHWPtr = RAMDACHWPTR(pScrn); + ramdacScrPtr = ((RamDacScreenRecPtr) + (pScrn)->privates[RamDacGetScreenIndex()].ptr); + + if (ramdacHWPtr) + free(ramdacHWPtr); + ramdacHWPtr = NULL; + + if (ramdacScrPtr) + free(ramdacScrPtr); + ramdacScrPtr = NULL; +} + +int +RamDacGetHWIndex(void) +{ + return RamDacHWPrivateIndex; +} + +int +RamDacGetScreenIndex(void) +{ + return RamDacScreenPrivateIndex; +} diff --git a/xorg-server/hw/xfree86/shadowfb/shadow.c b/xorg-server/hw/xfree86/shadowfb/shadow.c index 1c8170104..9e847f4d2 100644 --- a/xorg-server/hw/xfree86/shadowfb/shadow.c +++ b/xorg-server/hw/xfree86/shadowfb/shadow.c @@ -1,1729 +1,1729 @@ -/* - Copyright (C) 1999. The XFree86 Project Inc. - - Written by Mark Vojkovich (mvojkovi@ucsd.edu) - - Pre-fb-write callbacks and RENDER support - Nolan Leake (nolan@vmware.com) -*/ - - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "pixmapstr.h" -#include "input.h" -#include <X11/fonts/font.h> -#include "mi.h" -#include "scrnintstr.h" -#include "windowstr.h" -#include "gcstruct.h" -#include "dixfontstr.h" -#include <X11/fonts/fontstruct.h> -#include "xf86.h" -#include "xf86str.h" -#include "shadowfb.h" - -# include "picturestr.h" - -static Bool ShadowCloseScreen (int i, ScreenPtr pScreen); -static void ShadowCopyWindow( - WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgn -); -static Bool ShadowCreateGC(GCPtr pGC); -static Bool ShadowModifyPixmapHeader( - PixmapPtr pPixmap, - int width, - int height, - int depth, - int bitsPerPixel, - int devKind, - pointer pPixData -); - -static Bool ShadowEnterVT(int index, int flags); -static void ShadowLeaveVT(int index, int flags); - -static void ShadowComposite( - CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height -); - - -typedef struct { - ScrnInfoPtr pScrn; - RefreshAreaFuncPtr preRefresh; - RefreshAreaFuncPtr postRefresh; - CloseScreenProcPtr CloseScreen; - CopyWindowProcPtr CopyWindow; - CreateGCProcPtr CreateGC; - ModifyPixmapHeaderProcPtr ModifyPixmapHeader; - CompositeProcPtr Composite; - Bool (*EnterVT)(int, int); - void (*LeaveVT)(int, int); - Bool vtSema; -} ShadowScreenRec, *ShadowScreenPtr; - -typedef struct { - GCOps *ops; - GCFuncs *funcs; -} ShadowGCRec, *ShadowGCPtr; - - -static int ShadowScreenKeyIndex; -static DevPrivateKey ShadowScreenKey = &ShadowScreenKeyIndex; -static int ShadowGCKeyIndex; -static DevPrivateKey ShadowGCKey = &ShadowGCKeyIndex; - -#define GET_SCREEN_PRIVATE(pScreen) \ - (ShadowScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, ShadowScreenKey) -#define GET_GC_PRIVATE(pGC) \ - (ShadowGCPtr)dixLookupPrivate(&(pGC)->devPrivates, ShadowGCKey) - -#define SHADOW_GC_FUNC_PROLOGUE(pGC)\ - ShadowGCPtr pGCPriv = GET_GC_PRIVATE(pGC);\ - (pGC)->funcs = pGCPriv->funcs;\ - if(pGCPriv->ops)\ - (pGC)->ops = pGCPriv->ops - -#define SHADOW_GC_FUNC_EPILOGUE(pGC)\ - pGCPriv->funcs = (pGC)->funcs;\ - (pGC)->funcs = &ShadowGCFuncs;\ - if(pGCPriv->ops) {\ - pGCPriv->ops = (pGC)->ops;\ - (pGC)->ops = &ShadowGCOps;\ - } - -#define SHADOW_GC_OP_PROLOGUE(pGC)\ - ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pGC->pScreen); \ - ShadowGCPtr pGCPriv = GET_GC_PRIVATE(pGC);\ - GCFuncs *oldFuncs = pGC->funcs;\ - pGC->funcs = pGCPriv->funcs;\ - pGC->ops = pGCPriv->ops - - -#define SHADOW_GC_OP_EPILOGUE(pGC)\ - pGCPriv->ops = pGC->ops;\ - pGC->funcs = oldFuncs;\ - pGC->ops = &ShadowGCOps - -#define IS_VISIBLE(pWin) (pPriv->vtSema && \ - (((WindowPtr)pWin)->visibility != VisibilityFullyObscured)) - -#define TRIM_BOX(box, pGC) { \ - BoxPtr extents = &pGC->pCompositeClip->extents;\ - if(box.x1 < extents->x1) box.x1 = extents->x1; \ - if(box.x2 > extents->x2) box.x2 = extents->x2; \ - if(box.y1 < extents->y1) box.y1 = extents->y1; \ - if(box.y2 > extents->y2) box.y2 = extents->y2; \ - } - -#define TRANSLATE_BOX(box, pDraw) { \ - box.x1 += pDraw->x; \ - box.x2 += pDraw->x; \ - box.y1 += pDraw->y; \ - box.y2 += pDraw->y; \ - } - -#define TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC) { \ - TRANSLATE_BOX(box, pDraw); \ - TRIM_BOX(box, pGC); \ - } - -#define BOX_NOT_EMPTY(box) \ - (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0)) - - - -Bool -ShadowFBInit2 ( - ScreenPtr pScreen, - RefreshAreaFuncPtr preRefreshArea, - RefreshAreaFuncPtr postRefreshArea -){ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - ShadowScreenPtr pPriv; - PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); - - if(!preRefreshArea && !postRefreshArea) return FALSE; - - if(!dixRequestPrivate(ShadowGCKey, sizeof(ShadowGCRec))) - return FALSE; - - if(!(pPriv = (ShadowScreenPtr)xalloc(sizeof(ShadowScreenRec)))) - return FALSE; - - dixSetPrivate(&pScreen->devPrivates, ShadowScreenKey, pPriv); - - pPriv->pScrn = pScrn; - pPriv->preRefresh = preRefreshArea; - pPriv->postRefresh = postRefreshArea; - pPriv->vtSema = TRUE; - - pPriv->CloseScreen = pScreen->CloseScreen; - pPriv->CopyWindow = pScreen->CopyWindow; - pPriv->CreateGC = pScreen->CreateGC; - pPriv->ModifyPixmapHeader = pScreen->ModifyPixmapHeader; - - pPriv->EnterVT = pScrn->EnterVT; - pPriv->LeaveVT = pScrn->LeaveVT; - - pScreen->CloseScreen = ShadowCloseScreen; - pScreen->CopyWindow = ShadowCopyWindow; - pScreen->CreateGC = ShadowCreateGC; - pScreen->ModifyPixmapHeader = ShadowModifyPixmapHeader; - - pScrn->EnterVT = ShadowEnterVT; - pScrn->LeaveVT = ShadowLeaveVT; - - if(ps) { - pPriv->Composite = ps->Composite; - ps->Composite = ShadowComposite; - } - - return TRUE; -} - -Bool -ShadowFBInit ( - ScreenPtr pScreen, - RefreshAreaFuncPtr refreshArea -){ - return ShadowFBInit2(pScreen, NULL, refreshArea); -} - -/**********************************************************/ - -static Bool -ShadowEnterVT(int index, int flags) -{ - ScrnInfoPtr pScrn = xf86Screens[index]; - ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScrn->pScreen); - - if((*pPriv->EnterVT)(index, flags)) { - pPriv->vtSema = TRUE; - return TRUE; - } - - return FALSE; -} - -static void -ShadowLeaveVT(int index, int flags) -{ - ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(xf86Screens[index]->pScreen); - - pPriv->vtSema = FALSE; - - (*pPriv->LeaveVT)(index, flags); -} - -/**********************************************************/ - - -static Bool -ShadowCloseScreen (int i, ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen); - PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); - - pScreen->CloseScreen = pPriv->CloseScreen; - pScreen->CopyWindow = pPriv->CopyWindow; - pScreen->CreateGC = pPriv->CreateGC; - pScreen->ModifyPixmapHeader = pPriv->ModifyPixmapHeader; - - pScrn->EnterVT = pPriv->EnterVT; - pScrn->LeaveVT = pPriv->LeaveVT; - - if(ps) { - ps->Composite = pPriv->Composite; - } - - xfree((pointer)pPriv); - - return (*pScreen->CloseScreen) (i, pScreen); -} - -static void -ShadowCopyWindow( - WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgn -){ - ScreenPtr pScreen = pWin->drawable.pScreen; - ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen); - int num = 0; - RegionRec rgnDst; - - if (pPriv->vtSema) { - REGION_NULL(pWin->drawable.pScreen, &rgnDst); - REGION_COPY(pWin->drawable.pScreen, &rgnDst, prgn); - - REGION_TRANSLATE(pWin->drawable.pScreen, &rgnDst, - pWin->drawable.x - ptOldOrg.x, - pWin->drawable.y - ptOldOrg.y); - REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, &rgnDst); - if ((num = REGION_NUM_RECTS(&rgnDst))) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, num, REGION_RECTS(&rgnDst)); - } else { - REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); - } - } - - pScreen->CopyWindow = pPriv->CopyWindow; - (*pScreen->CopyWindow) (pWin, ptOldOrg, prgn); - pScreen->CopyWindow = ShadowCopyWindow; - - if (num) { - if (pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, num, REGION_RECTS(&rgnDst)); - REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); - } -} - -static Bool -ShadowModifyPixmapHeader( - PixmapPtr pPixmap, - int width, - int height, - int depth, - int bitsPerPixel, - int devKind, - pointer pPixData -) -{ - ScreenPtr pScreen; - ScrnInfoPtr pScrn; - ShadowScreenPtr pPriv; - Bool retval; - PixmapPtr pScreenPix; - - if (!pPixmap) - return FALSE; - - pScreen = pPixmap->drawable.pScreen; - pScrn = xf86Screens[pScreen->myNum]; - - pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); - - if (pPixmap == pScreenPix && !pScrn->vtSema) - pScreenPix->devPrivate = pScrn->pixmapPrivate; - - pPriv = GET_SCREEN_PRIVATE(pScreen); - - pScreen->ModifyPixmapHeader = pPriv->ModifyPixmapHeader; - retval = (*pScreen->ModifyPixmapHeader)(pPixmap, - width, height, depth, bitsPerPixel, devKind, pPixData); - pScreen->ModifyPixmapHeader = ShadowModifyPixmapHeader; - - if (pPixmap == pScreenPix && !pScrn->vtSema) - { - pScrn->pixmapPrivate = pScreenPix->devPrivate; - pScreenPix->devPrivate.ptr = 0; - } - return retval; -} - -static void -ShadowComposite( - CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height -){ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen); - PictureScreenPtr ps = GetPictureScreen(pScreen); - BoxRec box; - BoxPtr extents; - Bool boxNotEmpty = FALSE; - - if (pPriv->vtSema - && pDst->pDrawable->type == DRAWABLE_WINDOW) { - - box.x1 = pDst->pDrawable->x + xDst; - box.y1 = pDst->pDrawable->y + yDst; - box.x2 = box.x1 + width; - box.y2 = box.y1 + height; - - extents = &pDst->pCompositeClip->extents; - if(box.x1 < extents->x1) box.x1 = extents->x1; - if(box.x2 > extents->x2) box.x2 = extents->x2; - if(box.y1 < extents->y1) box.y1 = extents->y1; - if(box.y2 > extents->y2) box.y2 = extents->y2; - - if (BOX_NOT_EMPTY(box)) { - if (pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - ps->Composite = pPriv->Composite; - (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, - xMask, yMask, xDst, yDst, width, height); - ps->Composite = ShadowComposite; - - if (pPriv->postRefresh && boxNotEmpty) { - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - } -} - -/**********************************************************/ - -static void ShadowValidateGC(GCPtr, unsigned long, DrawablePtr); -static void ShadowChangeGC(GCPtr, unsigned long); -static void ShadowCopyGC(GCPtr, unsigned long, GCPtr); -static void ShadowDestroyGC(GCPtr); -static void ShadowChangeClip(GCPtr, int, pointer, int); -static void ShadowDestroyClip(GCPtr); -static void ShadowCopyClip(GCPtr, GCPtr); - -GCFuncs ShadowGCFuncs = { - ShadowValidateGC, ShadowChangeGC, ShadowCopyGC, ShadowDestroyGC, - ShadowChangeClip, ShadowDestroyClip, ShadowCopyClip -}; - - -extern GCOps ShadowGCOps; - -static Bool -ShadowCreateGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen); - ShadowGCPtr pGCPriv = GET_GC_PRIVATE(pGC); - Bool ret; - - pScreen->CreateGC = pPriv->CreateGC; - if((ret = (*pScreen->CreateGC) (pGC))) { - pGCPriv->ops = NULL; - pGCPriv->funcs = pGC->funcs; - pGC->funcs = &ShadowGCFuncs; - } - pScreen->CreateGC = ShadowCreateGC; - - return ret; -} - - -static void -ShadowValidateGC( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -){ - SHADOW_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); - if(pDraw->type == DRAWABLE_WINDOW) - pGCPriv->ops = pGC->ops; /* just so it's not NULL */ - else - pGCPriv->ops = NULL; - SHADOW_GC_FUNC_EPILOGUE (pGC); -} - - -static void -ShadowDestroyGC(GCPtr pGC) -{ - SHADOW_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->DestroyGC)(pGC); - SHADOW_GC_FUNC_EPILOGUE (pGC); -} - -static void -ShadowChangeGC ( - GCPtr pGC, - unsigned long mask -){ - SHADOW_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ChangeGC) (pGC, mask); - SHADOW_GC_FUNC_EPILOGUE (pGC); -} - -static void -ShadowCopyGC ( - GCPtr pGCSrc, - unsigned long mask, - GCPtr pGCDst -){ - SHADOW_GC_FUNC_PROLOGUE (pGCDst); - (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); - SHADOW_GC_FUNC_EPILOGUE (pGCDst); -} - -static void -ShadowChangeClip ( - GCPtr pGC, - int type, - pointer pvalue, - int nrects -){ - SHADOW_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); - SHADOW_GC_FUNC_EPILOGUE (pGC); -} - -static void -ShadowCopyClip(GCPtr pgcDst, GCPtr pgcSrc) -{ - SHADOW_GC_FUNC_PROLOGUE (pgcDst); - (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); - SHADOW_GC_FUNC_EPILOGUE (pgcDst); -} - -static void -ShadowDestroyClip(GCPtr pGC) -{ - SHADOW_GC_FUNC_PROLOGUE (pGC); - (* pGC->funcs->DestroyClip)(pGC); - SHADOW_GC_FUNC_EPILOGUE (pGC); -} - - - - -/**********************************************************/ - - -static void -ShadowFillSpans( - DrawablePtr pDraw, - GC *pGC, - int nInit, - DDXPointPtr pptInit, - int *pwidthInit, - int fSorted -){ - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && nInit) { - DDXPointPtr ppt = pptInit; - int *pwidth = pwidthInit; - int i = nInit; - BoxRec box; - Bool boxNotEmpty = FALSE; - - box.x1 = ppt->x; - box.x2 = box.x1 + *pwidth; - box.y2 = box.y1 = ppt->y; - - while(--i) { - ppt++; - pwidth++; - if(box.x1 > ppt->x) box.x1 = ppt->x; - if(box.x2 < (ppt->x + *pwidth)) - box.x2 = ppt->x + *pwidth; - if(box.y1 > ppt->y) box.y1 = ppt->y; - else if(box.y2 < ppt->y) box.y2 = ppt->y; - } - - box.y2++; - - if(!pGC->miTranslate) { - TRANSLATE_BOX(box, pDraw); - } - TRIM_BOX(box, pGC); - - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - - (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - } else - (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - -static void -ShadowSetSpans( - DrawablePtr pDraw, - GCPtr pGC, - char *pcharsrc, - DDXPointPtr pptInit, - int *pwidthInit, - int nspans, - int fSorted -){ - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && nspans) { - DDXPointPtr ppt = pptInit; - int *pwidth = pwidthInit; - int i = nspans; - BoxRec box; - Bool boxNotEmpty = FALSE; - - box.x1 = ppt->x; - box.x2 = box.x1 + *pwidth; - box.y2 = box.y1 = ppt->y; - - while(--i) { - ppt++; - pwidth++; - if(box.x1 > ppt->x) box.x1 = ppt->x; - if(box.x2 < (ppt->x + *pwidth)) - box.x2 = ppt->x + *pwidth; - if(box.y1 > ppt->y) box.y1 = ppt->y; - else if(box.y2 < ppt->y) box.y2 = ppt->y; - } - - box.y2++; - - if(!pGC->miTranslate) { - TRANSLATE_BOX(box, pDraw); - } - TRIM_BOX(box, pGC); - - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - - (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit, - pwidthInit, nspans, fSorted); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - } else - (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit, - pwidthInit, nspans, fSorted); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - -static void -ShadowPutImage( - DrawablePtr pDraw, - GCPtr pGC, - int depth, - int x, int y, int w, int h, - int leftPad, - int format, - char *pImage -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw)) { - box.x1 = x + pDraw->x; - box.x2 = box.x1 + w; - box.y1 = y + pDraw->y; - box.y2 = box.y1 + h; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h, - leftPad, format, pImage); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); - -} - -static RegionPtr -ShadowCopyArea( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty -){ - RegionPtr ret; - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDst)) { - box.x1 = dstx + pDst->x; - box.x2 = box.x1 + width; - box.y1 = dsty + pDst->y; - box.y2 = box.y1 + height; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - ret = (*pGC->ops->CopyArea)(pSrc, pDst, - pGC, srcx, srcy, width, height, dstx, dsty); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); - - return ret; -} - -static RegionPtr -ShadowCopyPlane( - DrawablePtr pSrc, - DrawablePtr pDst, - GCPtr pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty, - unsigned long bitPlane -){ - RegionPtr ret; - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDst)) { - box.x1 = dstx + pDst->x; - box.x2 = box.x1 + width; - box.y1 = dsty + pDst->y; - box.y2 = box.y1 + height; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - ret = (*pGC->ops->CopyPlane)(pSrc, pDst, - pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); - - return ret; -} - -static void -ShadowPolyPoint( - DrawablePtr pDraw, - GCPtr pGC, - int mode, - int nptInit, - xPoint *pptInit -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && nptInit) { - xPoint *ppt = pptInit; - int npt = nptInit; - - box.x2 = box.x1 = pptInit->x; - box.y2 = box.y1 = pptInit->y; - - /* this could be slow if the points were spread out */ - - while(--npt) { - ppt++; - if(box.x1 > ppt->x) box.x1 = ppt->x; - else if(box.x2 < ppt->x) box.x2 = ppt->x; - if(box.y1 > ppt->y) box.y1 = ppt->y; - else if(box.y2 < ppt->y) box.y2 = ppt->y; - } - - box.x2++; - box.y2++; - - TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->PolyPoint)(pDraw, pGC, mode, nptInit, pptInit); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - -static void -ShadowPolylines( - DrawablePtr pDraw, - GCPtr pGC, - int mode, - int nptInit, - DDXPointPtr pptInit -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && nptInit) { - DDXPointPtr ppt = pptInit; - int npt = nptInit; - int extra = pGC->lineWidth >> 1; - - box.x2 = box.x1 = pptInit->x; - box.y2 = box.y1 = pptInit->y; - - if(npt > 1) { - if(pGC->joinStyle == JoinMiter) - extra = 6 * pGC->lineWidth; - else if(pGC->capStyle == CapProjecting) - extra = pGC->lineWidth; - } - - if(mode == CoordModePrevious) { - int x = box.x1; - int y = box.y1; - while(--npt) { - ppt++; - x += ppt->x; - y += ppt->y; - if(box.x1 > x) box.x1 = x; - else if(box.x2 < x) box.x2 = x; - if(box.y1 > y) box.y1 = y; - else if(box.y2 < y) box.y2 = y; - } - } else { - while(--npt) { - ppt++; - if(box.x1 > ppt->x) box.x1 = ppt->x; - else if(box.x2 < ppt->x) box.x2 = ppt->x; - if(box.y1 > ppt->y) box.y1 = ppt->y; - else if(box.y2 < ppt->y) box.y2 = ppt->y; - } - } - - box.x2++; - box.y2++; - - if(extra) { - box.x1 -= extra; - box.x2 += extra; - box.y1 -= extra; - box.y2 += extra; - } - - TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->Polylines)(pDraw, pGC, mode, nptInit, pptInit); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - -static void -ShadowPolySegment( - DrawablePtr pDraw, - GCPtr pGC, - int nsegInit, - xSegment *pSegInit -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && nsegInit) { - int extra = pGC->lineWidth; - xSegment *pSeg = pSegInit; - int nseg = nsegInit; - - if(pGC->capStyle != CapProjecting) - extra >>= 1; - - if(pSeg->x2 > pSeg->x1) { - box.x1 = pSeg->x1; - box.x2 = pSeg->x2; - } else { - box.x2 = pSeg->x1; - box.x1 = pSeg->x2; - } - - if(pSeg->y2 > pSeg->y1) { - box.y1 = pSeg->y1; - box.y2 = pSeg->y2; - } else { - box.y2 = pSeg->y1; - box.y1 = pSeg->y2; - } - - while(--nseg) { - pSeg++; - if(pSeg->x2 > pSeg->x1) { - if(pSeg->x1 < box.x1) box.x1 = pSeg->x1; - if(pSeg->x2 > box.x2) box.x2 = pSeg->x2; - } else { - if(pSeg->x2 < box.x1) box.x1 = pSeg->x2; - if(pSeg->x1 > box.x2) box.x2 = pSeg->x1; - } - if(pSeg->y2 > pSeg->y1) { - if(pSeg->y1 < box.y1) box.y1 = pSeg->y1; - if(pSeg->y2 > box.y2) box.y2 = pSeg->y2; - } else { - if(pSeg->y2 < box.y1) box.y1 = pSeg->y2; - if(pSeg->y1 > box.y2) box.y2 = pSeg->y1; - } - } - - box.x2++; - box.y2++; - - if(extra) { - box.x1 -= extra; - box.x2 += extra; - box.y1 -= extra; - box.y2 += extra; - } - - TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->PolySegment)(pDraw, pGC, nsegInit, pSegInit); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - -static void -ShadowPolyRectangle( - DrawablePtr pDraw, - GCPtr pGC, - int nRectsInit, - xRectangle *pRectsInit -){ - BoxRec box; - BoxPtr pBoxInit = NULL; - Bool boxNotEmpty = FALSE; - int num = 0; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && nRectsInit) { - xRectangle *pRects = pRectsInit; - int nRects = nRectsInit; - - if(nRects >= 32) { - int extra = pGC->lineWidth >> 1; - - box.x1 = pRects->x; - box.x2 = box.x1 + pRects->width; - box.y1 = pRects->y; - box.y2 = box.y1 + pRects->height; - - while(--nRects) { - pRects++; - if(box.x1 > pRects->x) box.x1 = pRects->x; - if(box.x2 < (pRects->x + pRects->width)) - box.x2 = pRects->x + pRects->width; - if(box.y1 > pRects->y) box.y1 = pRects->y; - if(box.y2 < (pRects->y + pRects->height)) - box.y2 = pRects->y + pRects->height; - } - - if(extra) { - box.x1 -= extra; - box.x2 += extra; - box.y1 -= extra; - box.y2 += extra; - } - - box.x2++; - box.y2++; - - TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } else { - BoxPtr pbox; - int offset1, offset2, offset3; - - offset2 = pGC->lineWidth; - if(!offset2) offset2 = 1; - offset1 = offset2 >> 1; - offset3 = offset2 - offset1; - - pBoxInit = (BoxPtr)xalloc(nRects * 4 * sizeof(BoxRec)); - pbox = pBoxInit; - - while(nRects--) { - pbox->x1 = pRects->x - offset1; - pbox->y1 = pRects->y - offset1; - pbox->x2 = pbox->x1 + pRects->width + offset2; - pbox->y2 = pbox->y1 + offset2; - TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC); - if(BOX_NOT_EMPTY((*pbox))) { - num++; - pbox++; - } - - pbox->x1 = pRects->x - offset1; - pbox->y1 = pRects->y + offset3; - pbox->x2 = pbox->x1 + offset2; - pbox->y2 = pbox->y1 + pRects->height - offset2; - TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC); - if(BOX_NOT_EMPTY((*pbox))) { - num++; - pbox++; - } - - pbox->x1 = pRects->x + pRects->width - offset1; - pbox->y1 = pRects->y + offset3; - pbox->x2 = pbox->x1 + offset2; - pbox->y2 = pbox->y1 + pRects->height - offset2; - TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC); - if(BOX_NOT_EMPTY((*pbox))) { - num++; - pbox++; - } - - pbox->x1 = pRects->x - offset1; - pbox->y1 = pRects->y + pRects->height - offset1; - pbox->x2 = pbox->x1 + pRects->width + offset2; - pbox->y2 = pbox->y1 + offset2; - TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC); - if(BOX_NOT_EMPTY((*pbox))) { - num++; - pbox++; - } - - pRects++; - } - - if(num) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, num, pBoxInit); - } else { - xfree(pBoxInit); - } - } - } - - (*pGC->ops->PolyRectangle)(pDraw, pGC, nRectsInit, pRectsInit); - - if(boxNotEmpty && pPriv->postRefresh) { - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - } else if(num) { - if(pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, num, pBoxInit); - xfree(pBoxInit); - } - - SHADOW_GC_OP_EPILOGUE(pGC); - -} - -static void -ShadowPolyArc( - DrawablePtr pDraw, - GCPtr pGC, - int narcsInit, - xArc *parcsInit -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && narcsInit) { - int narcs = narcsInit; - xArc *parcs = parcsInit; - int extra = pGC->lineWidth >> 1; - - box.x1 = parcs->x; - box.x2 = box.x1 + parcs->width; - box.y1 = parcs->y; - box.y2 = box.y1 + parcs->height; - - /* should I break these up instead ? */ - - while(--narcs) { - parcs++; - if(box.x1 > parcs->x) box.x1 = parcs->x; - if(box.x2 < (parcs->x + parcs->width)) - box.x2 = parcs->x + parcs->width; - if(box.y1 > parcs->y) box.y1 = parcs->y; - if(box.y2 < (parcs->y + parcs->height)) - box.y2 = parcs->y + parcs->height; - } - - if(extra) { - box.x1 -= extra; - box.x2 += extra; - box.y1 -= extra; - box.y2 += extra; - } - - box.x2++; - box.y2++; - - TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->PolyArc)(pDraw, pGC, narcsInit, parcsInit); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); - -} - -static void -ShadowFillPolygon( - DrawablePtr pDraw, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr pptInit -){ - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && (count > 2)) { - DDXPointPtr ppt = pptInit; - int i = count; - BoxRec box; - Bool boxNotEmpty = FALSE; - - box.x2 = box.x1 = ppt->x; - box.y2 = box.y1 = ppt->y; - - if(mode != CoordModeOrigin) { - int x = box.x1; - int y = box.y1; - while(--i) { - ppt++; - x += ppt->x; - y += ppt->y; - if(box.x1 > x) box.x1 = x; - else if(box.x2 < x) box.x2 = x; - if(box.y1 > y) box.y1 = y; - else if(box.y2 < y) box.y2 = y; - } - } else { - while(--i) { - ppt++; - if(box.x1 > ppt->x) box.x1 = ppt->x; - else if(box.x2 < ppt->x) box.x2 = ppt->x; - if(box.y1 > ppt->y) box.y1 = ppt->y; - else if(box.y2 < ppt->y) box.y2 = ppt->y; - } - } - - box.x2++; - box.y2++; - - TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - - (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - } else - (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - - -static void -ShadowPolyFillRect( - DrawablePtr pDraw, - GCPtr pGC, - int nRectsInit, - xRectangle *pRectsInit -){ - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && nRectsInit) { - BoxRec box; - Bool boxNotEmpty = FALSE; - xRectangle *pRects = pRectsInit; - int nRects = nRectsInit; - - box.x1 = pRects->x; - box.x2 = box.x1 + pRects->width; - box.y1 = pRects->y; - box.y2 = box.y1 + pRects->height; - - while(--nRects) { - pRects++; - if(box.x1 > pRects->x) box.x1 = pRects->x; - if(box.x2 < (pRects->x + pRects->width)) - box.x2 = pRects->x + pRects->width; - if(box.y1 > pRects->y) box.y1 = pRects->y; - if(box.y2 < (pRects->y + pRects->height)) - box.y2 = pRects->y + pRects->height; - } - - /* cfb messes with the pRectsInit so we have to do our - calculations first */ - - TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - - (*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - } else - (*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - - -static void -ShadowPolyFillArc( - DrawablePtr pDraw, - GCPtr pGC, - int narcsInit, - xArc *parcsInit -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && narcsInit) { - xArc *parcs = parcsInit; - int narcs = narcsInit; - - box.x1 = parcs->x; - box.x2 = box.x1 + parcs->width; - box.y1 = parcs->y; - box.y2 = box.y1 + parcs->height; - - /* should I break these up instead ? */ - - while(--narcs) { - parcs++; - if(box.x1 > parcs->x) box.x1 = parcs->x; - if(box.x2 < (parcs->x + parcs->width)) - box.x2 = parcs->x + parcs->width; - if(box.y1 > parcs->y) box.y1 = parcs->y; - if(box.y2 < (parcs->y + parcs->height)) - box.y2 = parcs->y + parcs->height; - } - - TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->PolyFillArc)(pDraw, pGC, narcsInit, parcsInit); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - -static void -ShadowTextExtent(FontPtr pFont, int count, char* chars, - FontEncoding fontEncoding, BoxPtr box) -{ - unsigned long n, i; - int w; - CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */ - - GetGlyphs(pFont, (unsigned long)count, (unsigned char *)chars, - fontEncoding, &n, charinfo); - w = 0; - for (i=0; i < n; i++) { - w += charinfo[i]->metrics.characterWidth; - } - if (i) { - w += charinfo[i - 1]->metrics.rightSideBearing; - } - - box->x1 = 0; - if (n) { - if (charinfo[0]->metrics.leftSideBearing < 0) { - box->x1 = charinfo[0]->metrics.leftSideBearing; - } - } - box->x2 = w; - box->y1 = -FONTMAXBOUNDS(pFont,ascent); - box->y2 = FONTMAXBOUNDS(pFont,descent); -} - - - -static void -ShadowFontToBox(BoxPtr BB, DrawablePtr pDrawable, GCPtr pGC, int x, int y, - int count, char *chars, int wide) -{ - FontPtr pFont; - - pFont = pGC->font; - if (pFont->info.constantWidth) { - int ascent, descent, left, right = 0; - - ascent = max(pFont->info.fontAscent, pFont->info.maxbounds.ascent); - descent = max(pFont->info.fontDescent, pFont->info.maxbounds.descent); - left = pFont->info.maxbounds.leftSideBearing; - if (count > 0) { - right = (count - 1) * pFont->info.maxbounds.characterWidth; - } - right += pFont->info.maxbounds.rightSideBearing; - BB->x1 = - max(pDrawable->x + x - left, (REGION_EXTENTS(pGC->pScreen, - &((WindowPtr) pDrawable)->winSize))->x1); - BB->y1 = - max(pDrawable->y + y - ascent, - (REGION_EXTENTS(pGC->pScreen, - &((WindowPtr) pDrawable)->winSize))->y1); - BB->x2 = - min(pDrawable->x + x + right, - (REGION_EXTENTS(pGC->pScreen, - &((WindowPtr) pDrawable)->winSize))->x2); - BB->y2 = - min(pDrawable->y + y + descent, - (REGION_EXTENTS(pGC->pScreen, - &((WindowPtr) pDrawable)->winSize))->y2); - } else { - ShadowTextExtent(pFont, count, chars, wide ? (FONTLASTROW(pFont) == 0) - ? Linear16Bit : TwoD16Bit : Linear8Bit, BB); - BB->x1 = - max(pDrawable->x + x + BB->x1, (REGION_EXTENTS(pGC->pScreen, - &((WindowPtr) pDrawable)->winSize))->x1); - BB->y1 = - max(pDrawable->y + y + BB->y1, - (REGION_EXTENTS(pGC->pScreen, - &((WindowPtr) pDrawable)->winSize))->y1); - BB->x2 = - min(pDrawable->x + x + BB->x2, - (REGION_EXTENTS(pGC->pScreen, - &((WindowPtr) pDrawable)->winSize))->x2); - BB->y2 = - min(pDrawable->y + y + BB->y2, - (REGION_EXTENTS(pGC->pScreen, - &((WindowPtr) pDrawable)->winSize))->y2); - } -} - -static int -ShadowPolyText8( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - char *chars -){ - int width; - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw)) { - ShadowFontToBox(&box, pDraw, pGC, x, y, count, chars, 0); - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - width = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); - - return width; -} - -static int -ShadowPolyText16( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars -){ - int width; - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw)) { - ShadowFontToBox(&box, pDraw, pGC, x, y, count, (char*)chars, 1); - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - width = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); - - return width; -} - -static void -ShadowImageText8( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - char *chars -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && count) { - int top, bot, Min, Max; - - top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); - bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); - - Min = count * FONTMINBOUNDS(pGC->font, characterWidth); - if(Min > 0) Min = 0; - Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); - if(Max < 0) Max = 0; - - /* ugh */ - box.x1 = pDraw->x + x + Min + - FONTMINBOUNDS(pGC->font, leftSideBearing); - box.x2 = pDraw->x + x + Max + - FONTMAXBOUNDS(pGC->font, rightSideBearing); - - box.y1 = pDraw->y + y - top; - box.y2 = pDraw->y + y + bot; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); -} -static void -ShadowImageText16( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && count) { - int top, bot, Min, Max; - - top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); - bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); - - Min = count * FONTMINBOUNDS(pGC->font, characterWidth); - if(Min > 0) Min = 0; - Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); - if(Max < 0) Max = 0; - - /* ugh */ - box.x1 = pDraw->x + x + Min + - FONTMINBOUNDS(pGC->font, leftSideBearing); - box.x2 = pDraw->x + x + Max + - FONTMAXBOUNDS(pGC->font, rightSideBearing); - - box.y1 = pDraw->y + y - top; - box.y2 = pDraw->y + y + bot; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - - -static void -ShadowImageGlyphBlt( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - unsigned int nglyphInit, - CharInfoPtr *ppciInit, - pointer pglyphBase -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && nglyphInit) { - CharInfoPtr *ppci = ppciInit; - unsigned int nglyph = nglyphInit; - int top, bot, width = 0; - - top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); - bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); - - box.x1 = ppci[0]->metrics.leftSideBearing; - if(box.x1 > 0) box.x1 = 0; - box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing - - ppci[nglyph - 1]->metrics.characterWidth; - if(box.x2 < 0) box.x2 = 0; - - box.x2 += pDraw->x + x; - box.x1 += pDraw->x + x; - - while(nglyph--) { - width += (*ppci)->metrics.characterWidth; - ppci++; - } - - if(width > 0) - box.x2 += width; - else - box.x1 += width; - - box.y1 = pDraw->y + y - top; - box.y2 = pDraw->y + y + bot; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, nglyphInit, - ppciInit, pglyphBase); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - -static void -ShadowPolyGlyphBlt( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - unsigned int nglyphInit, - CharInfoPtr *ppciInit, - pointer pglyphBase -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw) && nglyphInit) { - CharInfoPtr *ppci = ppciInit; - unsigned int nglyph = nglyphInit; - - /* ugh */ - box.x1 = pDraw->x + x + ppci[0]->metrics.leftSideBearing; - box.x2 = pDraw->x + x + ppci[nglyph - 1]->metrics.rightSideBearing; - - if(nglyph > 1) { - int width = 0; - - while(--nglyph) { - width += (*ppci)->metrics.characterWidth; - ppci++; - } - - if(width > 0) box.x2 += width; - else box.x1 += width; - } - - box.y1 = pDraw->y + y - FONTMAXBOUNDS(pGC->font, ascent); - box.y2 = pDraw->y + y + FONTMAXBOUNDS(pGC->font, descent); - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, x, y, nglyphInit, - ppciInit, pglyphBase); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - -static void -ShadowPushPixels( - GCPtr pGC, - PixmapPtr pBitMap, - DrawablePtr pDraw, - int dx, int dy, int xOrg, int yOrg -){ - BoxRec box; - Bool boxNotEmpty = FALSE; - - SHADOW_GC_OP_PROLOGUE(pGC); - - if(IS_VISIBLE(pDraw)) { - box.x1 = xOrg; - box.y1 = yOrg; - - if(!pGC->miTranslate) { - box.x1 += pDraw->x; - box.y1 += pDraw->y; - } - - box.x2 = box.x1 + dx; - box.y2 = box.y1 + dy; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) { - if(pPriv->preRefresh) - (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); - boxNotEmpty = TRUE; - } - } - - (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); - - if(boxNotEmpty && pPriv->postRefresh) - (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); - - SHADOW_GC_OP_EPILOGUE(pGC); -} - - -GCOps ShadowGCOps = { - ShadowFillSpans, ShadowSetSpans, - ShadowPutImage, ShadowCopyArea, - ShadowCopyPlane, ShadowPolyPoint, - ShadowPolylines, ShadowPolySegment, - ShadowPolyRectangle, ShadowPolyArc, - ShadowFillPolygon, ShadowPolyFillRect, - ShadowPolyFillArc, ShadowPolyText8, - ShadowPolyText16, ShadowImageText8, - ShadowImageText16, ShadowImageGlyphBlt, - ShadowPolyGlyphBlt, ShadowPushPixels, - {NULL} /* devPrivate */ -}; - +/* + Copyright (C) 1999. The XFree86 Project Inc. + + Written by Mark Vojkovich (mvojkovi@ucsd.edu) + + Pre-fb-write callbacks and RENDER support - Nolan Leake (nolan@vmware.com) +*/ + + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "pixmapstr.h" +#include "input.h" +#include <X11/fonts/font.h> +#include "mi.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "gcstruct.h" +#include "dixfontstr.h" +#include <X11/fonts/fontstruct.h> +#include "xf86.h" +#include "xf86str.h" +#include "shadowfb.h" + +# include "picturestr.h" + +static Bool ShadowCloseScreen (int i, ScreenPtr pScreen); +static void ShadowCopyWindow( + WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgn +); +static Bool ShadowCreateGC(GCPtr pGC); +static Bool ShadowModifyPixmapHeader( + PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, + int devKind, + pointer pPixData +); + +static Bool ShadowEnterVT(int index, int flags); +static void ShadowLeaveVT(int index, int flags); + +static void ShadowComposite( + CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height +); + + +typedef struct { + ScrnInfoPtr pScrn; + RefreshAreaFuncPtr preRefresh; + RefreshAreaFuncPtr postRefresh; + CloseScreenProcPtr CloseScreen; + CopyWindowProcPtr CopyWindow; + CreateGCProcPtr CreateGC; + ModifyPixmapHeaderProcPtr ModifyPixmapHeader; + CompositeProcPtr Composite; + Bool (*EnterVT)(int, int); + void (*LeaveVT)(int, int); + Bool vtSema; +} ShadowScreenRec, *ShadowScreenPtr; + +typedef struct { + GCOps *ops; + GCFuncs *funcs; +} ShadowGCRec, *ShadowGCPtr; + + +static int ShadowScreenKeyIndex; +static DevPrivateKey ShadowScreenKey = &ShadowScreenKeyIndex; +static int ShadowGCKeyIndex; +static DevPrivateKey ShadowGCKey = &ShadowGCKeyIndex; + +#define GET_SCREEN_PRIVATE(pScreen) \ + (ShadowScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, ShadowScreenKey) +#define GET_GC_PRIVATE(pGC) \ + (ShadowGCPtr)dixLookupPrivate(&(pGC)->devPrivates, ShadowGCKey) + +#define SHADOW_GC_FUNC_PROLOGUE(pGC)\ + ShadowGCPtr pGCPriv = GET_GC_PRIVATE(pGC);\ + (pGC)->funcs = pGCPriv->funcs;\ + if(pGCPriv->ops)\ + (pGC)->ops = pGCPriv->ops + +#define SHADOW_GC_FUNC_EPILOGUE(pGC)\ + pGCPriv->funcs = (pGC)->funcs;\ + (pGC)->funcs = &ShadowGCFuncs;\ + if(pGCPriv->ops) {\ + pGCPriv->ops = (pGC)->ops;\ + (pGC)->ops = &ShadowGCOps;\ + } + +#define SHADOW_GC_OP_PROLOGUE(pGC)\ + ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pGC->pScreen); \ + ShadowGCPtr pGCPriv = GET_GC_PRIVATE(pGC);\ + GCFuncs *oldFuncs = pGC->funcs;\ + pGC->funcs = pGCPriv->funcs;\ + pGC->ops = pGCPriv->ops + + +#define SHADOW_GC_OP_EPILOGUE(pGC)\ + pGCPriv->ops = pGC->ops;\ + pGC->funcs = oldFuncs;\ + pGC->ops = &ShadowGCOps + +#define IS_VISIBLE(pWin) (pPriv->vtSema && \ + (((WindowPtr)pWin)->visibility != VisibilityFullyObscured)) + +#define TRIM_BOX(box, pGC) { \ + BoxPtr extents = &pGC->pCompositeClip->extents;\ + if(box.x1 < extents->x1) box.x1 = extents->x1; \ + if(box.x2 > extents->x2) box.x2 = extents->x2; \ + if(box.y1 < extents->y1) box.y1 = extents->y1; \ + if(box.y2 > extents->y2) box.y2 = extents->y2; \ + } + +#define TRANSLATE_BOX(box, pDraw) { \ + box.x1 += pDraw->x; \ + box.x2 += pDraw->x; \ + box.y1 += pDraw->y; \ + box.y2 += pDraw->y; \ + } + +#define TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC) { \ + TRANSLATE_BOX(box, pDraw); \ + TRIM_BOX(box, pGC); \ + } + +#define BOX_NOT_EMPTY(box) \ + (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0)) + + + +Bool +ShadowFBInit2 ( + ScreenPtr pScreen, + RefreshAreaFuncPtr preRefreshArea, + RefreshAreaFuncPtr postRefreshArea +){ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + ShadowScreenPtr pPriv; + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + + if(!preRefreshArea && !postRefreshArea) return FALSE; + + if(!dixRequestPrivate(ShadowGCKey, sizeof(ShadowGCRec))) + return FALSE; + + if(!(pPriv = (ShadowScreenPtr)malloc(sizeof(ShadowScreenRec)))) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, ShadowScreenKey, pPriv); + + pPriv->pScrn = pScrn; + pPriv->preRefresh = preRefreshArea; + pPriv->postRefresh = postRefreshArea; + pPriv->vtSema = TRUE; + + pPriv->CloseScreen = pScreen->CloseScreen; + pPriv->CopyWindow = pScreen->CopyWindow; + pPriv->CreateGC = pScreen->CreateGC; + pPriv->ModifyPixmapHeader = pScreen->ModifyPixmapHeader; + + pPriv->EnterVT = pScrn->EnterVT; + pPriv->LeaveVT = pScrn->LeaveVT; + + pScreen->CloseScreen = ShadowCloseScreen; + pScreen->CopyWindow = ShadowCopyWindow; + pScreen->CreateGC = ShadowCreateGC; + pScreen->ModifyPixmapHeader = ShadowModifyPixmapHeader; + + pScrn->EnterVT = ShadowEnterVT; + pScrn->LeaveVT = ShadowLeaveVT; + + if(ps) { + pPriv->Composite = ps->Composite; + ps->Composite = ShadowComposite; + } + + return TRUE; +} + +Bool +ShadowFBInit ( + ScreenPtr pScreen, + RefreshAreaFuncPtr refreshArea +){ + return ShadowFBInit2(pScreen, NULL, refreshArea); +} + +/**********************************************************/ + +static Bool +ShadowEnterVT(int index, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[index]; + ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScrn->pScreen); + + if((*pPriv->EnterVT)(index, flags)) { + pPriv->vtSema = TRUE; + return TRUE; + } + + return FALSE; +} + +static void +ShadowLeaveVT(int index, int flags) +{ + ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(xf86Screens[index]->pScreen); + + pPriv->vtSema = FALSE; + + (*pPriv->LeaveVT)(index, flags); +} + +/**********************************************************/ + + +static Bool +ShadowCloseScreen (int i, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen); + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + + pScreen->CloseScreen = pPriv->CloseScreen; + pScreen->CopyWindow = pPriv->CopyWindow; + pScreen->CreateGC = pPriv->CreateGC; + pScreen->ModifyPixmapHeader = pPriv->ModifyPixmapHeader; + + pScrn->EnterVT = pPriv->EnterVT; + pScrn->LeaveVT = pPriv->LeaveVT; + + if(ps) { + ps->Composite = pPriv->Composite; + } + + free((pointer)pPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void +ShadowCopyWindow( + WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgn +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen); + int num = 0; + RegionRec rgnDst; + + if (pPriv->vtSema) { + REGION_NULL(pWin->drawable.pScreen, &rgnDst); + REGION_COPY(pWin->drawable.pScreen, &rgnDst, prgn); + + REGION_TRANSLATE(pWin->drawable.pScreen, &rgnDst, + pWin->drawable.x - ptOldOrg.x, + pWin->drawable.y - ptOldOrg.y); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, &rgnDst); + if ((num = REGION_NUM_RECTS(&rgnDst))) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, num, REGION_RECTS(&rgnDst)); + } else { + REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); + } + } + + pScreen->CopyWindow = pPriv->CopyWindow; + (*pScreen->CopyWindow) (pWin, ptOldOrg, prgn); + pScreen->CopyWindow = ShadowCopyWindow; + + if (num) { + if (pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, num, REGION_RECTS(&rgnDst)); + REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); + } +} + +static Bool +ShadowModifyPixmapHeader( + PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, + int devKind, + pointer pPixData +) +{ + ScreenPtr pScreen; + ScrnInfoPtr pScrn; + ShadowScreenPtr pPriv; + Bool retval; + PixmapPtr pScreenPix; + + if (!pPixmap) + return FALSE; + + pScreen = pPixmap->drawable.pScreen; + pScrn = xf86Screens[pScreen->myNum]; + + pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); + + if (pPixmap == pScreenPix && !pScrn->vtSema) + pScreenPix->devPrivate = pScrn->pixmapPrivate; + + pPriv = GET_SCREEN_PRIVATE(pScreen); + + pScreen->ModifyPixmapHeader = pPriv->ModifyPixmapHeader; + retval = (*pScreen->ModifyPixmapHeader)(pPixmap, + width, height, depth, bitsPerPixel, devKind, pPixData); + pScreen->ModifyPixmapHeader = ShadowModifyPixmapHeader; + + if (pPixmap == pScreenPix && !pScrn->vtSema) + { + pScrn->pixmapPrivate = pScreenPix->devPrivate; + pScreenPix->devPrivate.ptr = 0; + } + return retval; +} + +static void +ShadowComposite( + CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height +){ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen); + PictureScreenPtr ps = GetPictureScreen(pScreen); + BoxRec box; + BoxPtr extents; + Bool boxNotEmpty = FALSE; + + if (pPriv->vtSema + && pDst->pDrawable->type == DRAWABLE_WINDOW) { + + box.x1 = pDst->pDrawable->x + xDst; + box.y1 = pDst->pDrawable->y + yDst; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + + extents = &pDst->pCompositeClip->extents; + if(box.x1 < extents->x1) box.x1 = extents->x1; + if(box.x2 > extents->x2) box.x2 = extents->x2; + if(box.y1 < extents->y1) box.y1 = extents->y1; + if(box.y2 > extents->y2) box.y2 = extents->y2; + + if (BOX_NOT_EMPTY(box)) { + if (pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + ps->Composite = pPriv->Composite; + (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + ps->Composite = ShadowComposite; + + if (pPriv->postRefresh && boxNotEmpty) { + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + } +} + +/**********************************************************/ + +static void ShadowValidateGC(GCPtr, unsigned long, DrawablePtr); +static void ShadowChangeGC(GCPtr, unsigned long); +static void ShadowCopyGC(GCPtr, unsigned long, GCPtr); +static void ShadowDestroyGC(GCPtr); +static void ShadowChangeClip(GCPtr, int, pointer, int); +static void ShadowDestroyClip(GCPtr); +static void ShadowCopyClip(GCPtr, GCPtr); + +GCFuncs ShadowGCFuncs = { + ShadowValidateGC, ShadowChangeGC, ShadowCopyGC, ShadowDestroyGC, + ShadowChangeClip, ShadowDestroyClip, ShadowCopyClip +}; + + +extern GCOps ShadowGCOps; + +static Bool +ShadowCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen); + ShadowGCPtr pGCPriv = GET_GC_PRIVATE(pGC); + Bool ret; + + pScreen->CreateGC = pPriv->CreateGC; + if((ret = (*pScreen->CreateGC) (pGC))) { + pGCPriv->ops = NULL; + pGCPriv->funcs = pGC->funcs; + pGC->funcs = &ShadowGCFuncs; + } + pScreen->CreateGC = ShadowCreateGC; + + return ret; +} + + +static void +ShadowValidateGC( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +){ + SHADOW_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); + if(pDraw->type == DRAWABLE_WINDOW) + pGCPriv->ops = pGC->ops; /* just so it's not NULL */ + else + pGCPriv->ops = NULL; + SHADOW_GC_FUNC_EPILOGUE (pGC); +} + + +static void +ShadowDestroyGC(GCPtr pGC) +{ + SHADOW_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->DestroyGC)(pGC); + SHADOW_GC_FUNC_EPILOGUE (pGC); +} + +static void +ShadowChangeGC ( + GCPtr pGC, + unsigned long mask +){ + SHADOW_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeGC) (pGC, mask); + SHADOW_GC_FUNC_EPILOGUE (pGC); +} + +static void +ShadowCopyGC ( + GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst +){ + SHADOW_GC_FUNC_PROLOGUE (pGCDst); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + SHADOW_GC_FUNC_EPILOGUE (pGCDst); +} + +static void +ShadowChangeClip ( + GCPtr pGC, + int type, + pointer pvalue, + int nrects +){ + SHADOW_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + SHADOW_GC_FUNC_EPILOGUE (pGC); +} + +static void +ShadowCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + SHADOW_GC_FUNC_PROLOGUE (pgcDst); + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + SHADOW_GC_FUNC_EPILOGUE (pgcDst); +} + +static void +ShadowDestroyClip(GCPtr pGC) +{ + SHADOW_GC_FUNC_PROLOGUE (pGC); + (* pGC->funcs->DestroyClip)(pGC); + SHADOW_GC_FUNC_EPILOGUE (pGC); +} + + + + +/**********************************************************/ + + +static void +ShadowFillSpans( + DrawablePtr pDraw, + GC *pGC, + int nInit, + DDXPointPtr pptInit, + int *pwidthInit, + int fSorted +){ + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && nInit) { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nInit; + BoxRec box; + Bool boxNotEmpty = FALSE; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while(--i) { + ppt++; + pwidth++; + if(box.x1 > ppt->x) box.x1 = ppt->x; + if(box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if(box.y1 > ppt->y) box.y1 = ppt->y; + else if(box.y2 < ppt->y) box.y2 = ppt->y; + } + + box.y2++; + + if(!pGC->miTranslate) { + TRANSLATE_BOX(box, pDraw); + } + TRIM_BOX(box, pGC); + + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + + (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + } else + (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + +static void +ShadowSetSpans( + DrawablePtr pDraw, + GCPtr pGC, + char *pcharsrc, + DDXPointPtr pptInit, + int *pwidthInit, + int nspans, + int fSorted +){ + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && nspans) { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nspans; + BoxRec box; + Bool boxNotEmpty = FALSE; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while(--i) { + ppt++; + pwidth++; + if(box.x1 > ppt->x) box.x1 = ppt->x; + if(box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if(box.y1 > ppt->y) box.y1 = ppt->y; + else if(box.y2 < ppt->y) box.y2 = ppt->y; + } + + box.y2++; + + if(!pGC->miTranslate) { + TRANSLATE_BOX(box, pDraw); + } + TRIM_BOX(box, pGC); + + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + + (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit, + pwidthInit, nspans, fSorted); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + } else + (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit, + pwidthInit, nspans, fSorted); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + +static void +ShadowPutImage( + DrawablePtr pDraw, + GCPtr pGC, + int depth, + int x, int y, int w, int h, + int leftPad, + int format, + char *pImage +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw)) { + box.x1 = x + pDraw->x; + box.x2 = box.x1 + w; + box.y1 = y + pDraw->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h, + leftPad, format, pImage); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); + +} + +static RegionPtr +ShadowCopyArea( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty +){ + RegionPtr ret; + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDst)) { + box.x1 = dstx + pDst->x; + box.x2 = box.x1 + width; + box.y1 = dsty + pDst->y; + box.y2 = box.y1 + height; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + ret = (*pGC->ops->CopyArea)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); + + return ret; +} + +static RegionPtr +ShadowCopyPlane( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty, + unsigned long bitPlane +){ + RegionPtr ret; + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDst)) { + box.x1 = dstx + pDst->x; + box.x2 = box.x1 + width; + box.y1 = dsty + pDst->y; + box.y2 = box.y1 + height; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + ret = (*pGC->ops->CopyPlane)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); + + return ret; +} + +static void +ShadowPolyPoint( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int nptInit, + xPoint *pptInit +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && nptInit) { + xPoint *ppt = pptInit; + int npt = nptInit; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + + /* this could be slow if the points were spread out */ + + while(--npt) { + ppt++; + if(box.x1 > ppt->x) box.x1 = ppt->x; + else if(box.x2 < ppt->x) box.x2 = ppt->x; + if(box.y1 > ppt->y) box.y1 = ppt->y; + else if(box.y2 < ppt->y) box.y2 = ppt->y; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->PolyPoint)(pDraw, pGC, mode, nptInit, pptInit); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + +static void +ShadowPolylines( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int nptInit, + DDXPointPtr pptInit +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && nptInit) { + DDXPointPtr ppt = pptInit; + int npt = nptInit; + int extra = pGC->lineWidth >> 1; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + + if(npt > 1) { + if(pGC->joinStyle == JoinMiter) + extra = 6 * pGC->lineWidth; + else if(pGC->capStyle == CapProjecting) + extra = pGC->lineWidth; + } + + if(mode == CoordModePrevious) { + int x = box.x1; + int y = box.y1; + while(--npt) { + ppt++; + x += ppt->x; + y += ppt->y; + if(box.x1 > x) box.x1 = x; + else if(box.x2 < x) box.x2 = x; + if(box.y1 > y) box.y1 = y; + else if(box.y2 < y) box.y2 = y; + } + } else { + while(--npt) { + ppt++; + if(box.x1 > ppt->x) box.x1 = ppt->x; + else if(box.x2 < ppt->x) box.x2 = ppt->x; + if(box.y1 > ppt->y) box.y1 = ppt->y; + else if(box.y2 < ppt->y) box.y2 = ppt->y; + } + } + + box.x2++; + box.y2++; + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->Polylines)(pDraw, pGC, mode, nptInit, pptInit); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + +static void +ShadowPolySegment( + DrawablePtr pDraw, + GCPtr pGC, + int nsegInit, + xSegment *pSegInit +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && nsegInit) { + int extra = pGC->lineWidth; + xSegment *pSeg = pSegInit; + int nseg = nsegInit; + + if(pGC->capStyle != CapProjecting) + extra >>= 1; + + if(pSeg->x2 > pSeg->x1) { + box.x1 = pSeg->x1; + box.x2 = pSeg->x2; + } else { + box.x2 = pSeg->x1; + box.x1 = pSeg->x2; + } + + if(pSeg->y2 > pSeg->y1) { + box.y1 = pSeg->y1; + box.y2 = pSeg->y2; + } else { + box.y2 = pSeg->y1; + box.y1 = pSeg->y2; + } + + while(--nseg) { + pSeg++; + if(pSeg->x2 > pSeg->x1) { + if(pSeg->x1 < box.x1) box.x1 = pSeg->x1; + if(pSeg->x2 > box.x2) box.x2 = pSeg->x2; + } else { + if(pSeg->x2 < box.x1) box.x1 = pSeg->x2; + if(pSeg->x1 > box.x2) box.x2 = pSeg->x1; + } + if(pSeg->y2 > pSeg->y1) { + if(pSeg->y1 < box.y1) box.y1 = pSeg->y1; + if(pSeg->y2 > box.y2) box.y2 = pSeg->y2; + } else { + if(pSeg->y2 < box.y1) box.y1 = pSeg->y2; + if(pSeg->y1 > box.y2) box.y2 = pSeg->y1; + } + } + + box.x2++; + box.y2++; + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->PolySegment)(pDraw, pGC, nsegInit, pSegInit); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + +static void +ShadowPolyRectangle( + DrawablePtr pDraw, + GCPtr pGC, + int nRectsInit, + xRectangle *pRectsInit +){ + BoxRec box; + BoxPtr pBoxInit = NULL; + Bool boxNotEmpty = FALSE; + int num = 0; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && nRectsInit) { + xRectangle *pRects = pRectsInit; + int nRects = nRectsInit; + + if(nRects >= 32) { + int extra = pGC->lineWidth >> 1; + + box.x1 = pRects->x; + box.x2 = box.x1 + pRects->width; + box.y1 = pRects->y; + box.y2 = box.y1 + pRects->height; + + while(--nRects) { + pRects++; + if(box.x1 > pRects->x) box.x1 = pRects->x; + if(box.x2 < (pRects->x + pRects->width)) + box.x2 = pRects->x + pRects->width; + if(box.y1 > pRects->y) box.y1 = pRects->y; + if(box.y2 < (pRects->y + pRects->height)) + box.y2 = pRects->y + pRects->height; + } + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } else { + BoxPtr pbox; + int offset1, offset2, offset3; + + offset2 = pGC->lineWidth; + if(!offset2) offset2 = 1; + offset1 = offset2 >> 1; + offset3 = offset2 - offset1; + + pBoxInit = (BoxPtr)malloc(nRects * 4 * sizeof(BoxRec)); + pbox = pBoxInit; + + while(nRects--) { + pbox->x1 = pRects->x - offset1; + pbox->y1 = pRects->y - offset1; + pbox->x2 = pbox->x1 + pRects->width + offset2; + pbox->y2 = pbox->y1 + offset2; + TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC); + if(BOX_NOT_EMPTY((*pbox))) { + num++; + pbox++; + } + + pbox->x1 = pRects->x - offset1; + pbox->y1 = pRects->y + offset3; + pbox->x2 = pbox->x1 + offset2; + pbox->y2 = pbox->y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC); + if(BOX_NOT_EMPTY((*pbox))) { + num++; + pbox++; + } + + pbox->x1 = pRects->x + pRects->width - offset1; + pbox->y1 = pRects->y + offset3; + pbox->x2 = pbox->x1 + offset2; + pbox->y2 = pbox->y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC); + if(BOX_NOT_EMPTY((*pbox))) { + num++; + pbox++; + } + + pbox->x1 = pRects->x - offset1; + pbox->y1 = pRects->y + pRects->height - offset1; + pbox->x2 = pbox->x1 + pRects->width + offset2; + pbox->y2 = pbox->y1 + offset2; + TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC); + if(BOX_NOT_EMPTY((*pbox))) { + num++; + pbox++; + } + + pRects++; + } + + if(num) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, num, pBoxInit); + } else { + free(pBoxInit); + } + } + } + + (*pGC->ops->PolyRectangle)(pDraw, pGC, nRectsInit, pRectsInit); + + if(boxNotEmpty && pPriv->postRefresh) { + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + } else if(num) { + if(pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, num, pBoxInit); + free(pBoxInit); + } + + SHADOW_GC_OP_EPILOGUE(pGC); + +} + +static void +ShadowPolyArc( + DrawablePtr pDraw, + GCPtr pGC, + int narcsInit, + xArc *parcsInit +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && narcsInit) { + int narcs = narcsInit; + xArc *parcs = parcsInit; + int extra = pGC->lineWidth >> 1; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while(--narcs) { + parcs++; + if(box.x1 > parcs->x) box.x1 = parcs->x; + if(box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if(box.y1 > parcs->y) box.y1 = parcs->y; + if(box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->PolyArc)(pDraw, pGC, narcsInit, parcsInit); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); + +} + +static void +ShadowFillPolygon( + DrawablePtr pDraw, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr pptInit +){ + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && (count > 2)) { + DDXPointPtr ppt = pptInit; + int i = count; + BoxRec box; + Bool boxNotEmpty = FALSE; + + box.x2 = box.x1 = ppt->x; + box.y2 = box.y1 = ppt->y; + + if(mode != CoordModeOrigin) { + int x = box.x1; + int y = box.y1; + while(--i) { + ppt++; + x += ppt->x; + y += ppt->y; + if(box.x1 > x) box.x1 = x; + else if(box.x2 < x) box.x2 = x; + if(box.y1 > y) box.y1 = y; + else if(box.y2 < y) box.y2 = y; + } + } else { + while(--i) { + ppt++; + if(box.x1 > ppt->x) box.x1 = ppt->x; + else if(box.x2 < ppt->x) box.x2 = ppt->x; + if(box.y1 > ppt->y) box.y1 = ppt->y; + else if(box.y2 < ppt->y) box.y2 = ppt->y; + } + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + + (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + } else + (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + + +static void +ShadowPolyFillRect( + DrawablePtr pDraw, + GCPtr pGC, + int nRectsInit, + xRectangle *pRectsInit +){ + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && nRectsInit) { + BoxRec box; + Bool boxNotEmpty = FALSE; + xRectangle *pRects = pRectsInit; + int nRects = nRectsInit; + + box.x1 = pRects->x; + box.x2 = box.x1 + pRects->width; + box.y1 = pRects->y; + box.y2 = box.y1 + pRects->height; + + while(--nRects) { + pRects++; + if(box.x1 > pRects->x) box.x1 = pRects->x; + if(box.x2 < (pRects->x + pRects->width)) + box.x2 = pRects->x + pRects->width; + if(box.y1 > pRects->y) box.y1 = pRects->y; + if(box.y2 < (pRects->y + pRects->height)) + box.y2 = pRects->y + pRects->height; + } + + /* cfb messes with the pRectsInit so we have to do our + calculations first */ + + TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + + (*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + } else + (*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + + +static void +ShadowPolyFillArc( + DrawablePtr pDraw, + GCPtr pGC, + int narcsInit, + xArc *parcsInit +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && narcsInit) { + xArc *parcs = parcsInit; + int narcs = narcsInit; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while(--narcs) { + parcs++; + if(box.x1 > parcs->x) box.x1 = parcs->x; + if(box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if(box.y1 > parcs->y) box.y1 = parcs->y; + if(box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->PolyFillArc)(pDraw, pGC, narcsInit, parcsInit); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + +static void +ShadowTextExtent(FontPtr pFont, int count, char* chars, + FontEncoding fontEncoding, BoxPtr box) +{ + unsigned long n, i; + int w; + CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */ + + GetGlyphs(pFont, (unsigned long)count, (unsigned char *)chars, + fontEncoding, &n, charinfo); + w = 0; + for (i=0; i < n; i++) { + w += charinfo[i]->metrics.characterWidth; + } + if (i) { + w += charinfo[i - 1]->metrics.rightSideBearing; + } + + box->x1 = 0; + if (n) { + if (charinfo[0]->metrics.leftSideBearing < 0) { + box->x1 = charinfo[0]->metrics.leftSideBearing; + } + } + box->x2 = w; + box->y1 = -FONTMAXBOUNDS(pFont,ascent); + box->y2 = FONTMAXBOUNDS(pFont,descent); +} + + + +static void +ShadowFontToBox(BoxPtr BB, DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int count, char *chars, int wide) +{ + FontPtr pFont; + + pFont = pGC->font; + if (pFont->info.constantWidth) { + int ascent, descent, left, right = 0; + + ascent = max(pFont->info.fontAscent, pFont->info.maxbounds.ascent); + descent = max(pFont->info.fontDescent, pFont->info.maxbounds.descent); + left = pFont->info.maxbounds.leftSideBearing; + if (count > 0) { + right = (count - 1) * pFont->info.maxbounds.characterWidth; + } + right += pFont->info.maxbounds.rightSideBearing; + BB->x1 = + max(pDrawable->x + x - left, (REGION_EXTENTS(pGC->pScreen, + &((WindowPtr) pDrawable)->winSize))->x1); + BB->y1 = + max(pDrawable->y + y - ascent, + (REGION_EXTENTS(pGC->pScreen, + &((WindowPtr) pDrawable)->winSize))->y1); + BB->x2 = + min(pDrawable->x + x + right, + (REGION_EXTENTS(pGC->pScreen, + &((WindowPtr) pDrawable)->winSize))->x2); + BB->y2 = + min(pDrawable->y + y + descent, + (REGION_EXTENTS(pGC->pScreen, + &((WindowPtr) pDrawable)->winSize))->y2); + } else { + ShadowTextExtent(pFont, count, chars, wide ? (FONTLASTROW(pFont) == 0) + ? Linear16Bit : TwoD16Bit : Linear8Bit, BB); + BB->x1 = + max(pDrawable->x + x + BB->x1, (REGION_EXTENTS(pGC->pScreen, + &((WindowPtr) pDrawable)->winSize))->x1); + BB->y1 = + max(pDrawable->y + y + BB->y1, + (REGION_EXTENTS(pGC->pScreen, + &((WindowPtr) pDrawable)->winSize))->y1); + BB->x2 = + min(pDrawable->x + x + BB->x2, + (REGION_EXTENTS(pGC->pScreen, + &((WindowPtr) pDrawable)->winSize))->x2); + BB->y2 = + min(pDrawable->y + y + BB->y2, + (REGION_EXTENTS(pGC->pScreen, + &((WindowPtr) pDrawable)->winSize))->y2); + } +} + +static int +ShadowPolyText8( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars +){ + int width; + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw)) { + ShadowFontToBox(&box, pDraw, pGC, x, y, count, chars, 0); + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + width = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); + + return width; +} + +static int +ShadowPolyText16( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars +){ + int width; + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw)) { + ShadowFontToBox(&box, pDraw, pGC, x, y, count, (char*)chars, 1); + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + width = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); + + return width; +} + +static void +ShadowImageText8( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && count) { + int top, bot, Min, Max; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if(Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if(Max < 0) Max = 0; + + /* ugh */ + box.x1 = pDraw->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = pDraw->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = pDraw->y + y - top; + box.y2 = pDraw->y + y + bot; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); +} +static void +ShadowImageText16( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && count) { + int top, bot, Min, Max; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if(Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if(Max < 0) Max = 0; + + /* ugh */ + box.x1 = pDraw->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = pDraw->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = pDraw->y + y - top; + box.y2 = pDraw->y + y + bot; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + + +static void +ShadowImageGlyphBlt( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + unsigned int nglyphInit, + CharInfoPtr *ppciInit, + pointer pglyphBase +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && nglyphInit) { + CharInfoPtr *ppci = ppciInit; + unsigned int nglyph = nglyphInit; + int top, bot, width = 0; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + box.x1 = ppci[0]->metrics.leftSideBearing; + if(box.x1 > 0) box.x1 = 0; + box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing - + ppci[nglyph - 1]->metrics.characterWidth; + if(box.x2 < 0) box.x2 = 0; + + box.x2 += pDraw->x + x; + box.x1 += pDraw->x + x; + + while(nglyph--) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if(width > 0) + box.x2 += width; + else + box.x1 += width; + + box.y1 = pDraw->y + y - top; + box.y2 = pDraw->y + y + bot; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, nglyphInit, + ppciInit, pglyphBase); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + +static void +ShadowPolyGlyphBlt( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + unsigned int nglyphInit, + CharInfoPtr *ppciInit, + pointer pglyphBase +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw) && nglyphInit) { + CharInfoPtr *ppci = ppciInit; + unsigned int nglyph = nglyphInit; + + /* ugh */ + box.x1 = pDraw->x + x + ppci[0]->metrics.leftSideBearing; + box.x2 = pDraw->x + x + ppci[nglyph - 1]->metrics.rightSideBearing; + + if(nglyph > 1) { + int width = 0; + + while(--nglyph) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if(width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = pDraw->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = pDraw->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, x, y, nglyphInit, + ppciInit, pglyphBase); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + +static void +ShadowPushPixels( + GCPtr pGC, + PixmapPtr pBitMap, + DrawablePtr pDraw, + int dx, int dy, int xOrg, int yOrg +){ + BoxRec box; + Bool boxNotEmpty = FALSE; + + SHADOW_GC_OP_PROLOGUE(pGC); + + if(IS_VISIBLE(pDraw)) { + box.x1 = xOrg; + box.y1 = yOrg; + + if(!pGC->miTranslate) { + box.x1 += pDraw->x; + box.y1 += pDraw->y; + } + + box.x2 = box.x1 + dx; + box.y2 = box.y1 + dy; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) { + if(pPriv->preRefresh) + (*pPriv->preRefresh)(pPriv->pScrn, 1, &box); + boxNotEmpty = TRUE; + } + } + + (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); + + if(boxNotEmpty && pPriv->postRefresh) + (*pPriv->postRefresh)(pPriv->pScrn, 1, &box); + + SHADOW_GC_OP_EPILOGUE(pGC); +} + + +GCOps ShadowGCOps = { + ShadowFillSpans, ShadowSetSpans, + ShadowPutImage, ShadowCopyArea, + ShadowCopyPlane, ShadowPolyPoint, + ShadowPolylines, ShadowPolySegment, + ShadowPolyRectangle, ShadowPolyArc, + ShadowFillPolygon, ShadowPolyFillRect, + ShadowPolyFillArc, ShadowPolyText8, + ShadowPolyText16, ShadowImageText8, + ShadowImageText16, ShadowImageGlyphBlt, + ShadowPolyGlyphBlt, ShadowPushPixels, + {NULL} /* devPrivate */ +}; + diff --git a/xorg-server/hw/xfree86/vbe/vbe.c b/xorg-server/hw/xfree86/vbe/vbe.c index 26f5911d5..bb88b86cf 100644 --- a/xorg-server/hw/xfree86/vbe/vbe.c +++ b/xorg-server/hw/xfree86/vbe/vbe.c @@ -1,1145 +1,1145 @@ - -/* - * XFree86 vbe module - * Copyright 2000 Egbert Eich - * - * The mode query/save/set/restore functions from the vesa driver - * have been moved here. - * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com) - * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br> - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "xf86.h" -#include "vbe.h" -#include <X11/Xarch.h> -#include <X11/extensions/dpmsconst.h> - -#define VERSION(x) VBE_VERSION_MAJOR(x),VBE_VERSION_MINOR(x) - -#if X_BYTE_ORDER == X_LITTLE_ENDIAN -#define B_O16(x) (x) -#define B_O32(x) (x) -#else -#define B_O16(x) ((((x) & 0xff) << 8) | (((x) & 0xff) >> 8)) -#define B_O32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) \ - | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24)) -#endif -#define L_ADD(x) (B_O32(x) & 0xffff) + ((B_O32(x) >> 12) & 0xffff00) - -#define FARP(p) (((unsigned)(p & 0xffff0000) >> 12) | (p & 0xffff)) -#define R16(v) ((v) & 0xffff) - -static unsigned char * vbeReadEDID(vbeInfoPtr pVbe); -static Bool vbeProbeDDC(vbeInfoPtr pVbe); - -static const char vbeVersionString[] = "VBE2"; - -vbeInfoPtr -VBEInit(xf86Int10InfoPtr pInt, int entityIndex) -{ - return VBEExtendedInit(pInt, entityIndex, 0); -} - -vbeInfoPtr -VBEExtendedInit(xf86Int10InfoPtr pInt, int entityIndex, int Flags) -{ - int RealOff; - pointer page = NULL; - ScrnInfoPtr pScrn = xf86FindScreenForEntity(entityIndex); - vbeControllerInfoPtr vbe = NULL; - Bool init_int10 = FALSE; - vbeInfoPtr vip = NULL; - int screen; - - if (!pScrn) return NULL; - screen = pScrn->scrnIndex; - - if (!pInt) { - if (!xf86LoadSubModule(pScrn, "int10")) - goto error; - - xf86DrvMsg(screen,X_INFO,"initializing int10\n"); - pInt = xf86ExtendedInitInt10(entityIndex,Flags); - if (!pInt) - goto error; - init_int10 = TRUE; - } - - page = xf86Int10AllocPages(pInt,1,&RealOff); - if (!page) goto error; - vbe = (vbeControllerInfoPtr) page; - memcpy(vbe->VbeSignature,vbeVersionString,4); - - pInt->ax = 0x4F00; - pInt->es = SEG_ADDR(RealOff); - pInt->di = SEG_OFF(RealOff); - pInt->num = 0x10; - - xf86ExecX86int10(pInt); - - if ((pInt->ax & 0xff) != 0x4f) { - xf86DrvMsgVerb(screen,X_INFO,3,"VESA BIOS not detected\n"); - goto error; - } - - switch (pInt->ax & 0xff00) { - case 0: - xf86DrvMsg(screen,X_INFO,"VESA BIOS detected\n"); - break; - case 0x100: - xf86DrvMsg(screen,X_INFO,"VESA BIOS function failed\n"); - goto error; - case 0x200: - xf86DrvMsg(screen,X_INFO,"VESA BIOS not supported\n"); - goto error; - case 0x300: - xf86DrvMsg(screen,X_INFO,"VESA BIOS not supported in current mode\n"); - goto error; - default: - xf86DrvMsg(screen,X_INFO,"Invalid\n"); - goto error; - } - - xf86DrvMsgVerb(screen, X_INFO, 4, - "VbeVersion is %d, OemStringPtr is 0x%08lx,\n" - "\tOemVendorNamePtr is 0x%08lx, OemProductNamePtr is 0x%08lx,\n" - "\tOemProductRevPtr is 0x%08lx\n", - vbe->VbeVersion, (unsigned long)vbe->OemStringPtr, - (unsigned long)vbe->OemVendorNamePtr, - (unsigned long)vbe->OemProductNamePtr, - (unsigned long)vbe->OemProductRevPtr); - - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE Version %i.%i\n", - VERSION(vbe->VbeVersion)); - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE Total Mem: %i kB\n", - vbe->TotalMem * 64); - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM: %s\n", - (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemStringPtr))); - - if (B_O16(vbe->VbeVersion) >= 0x200) { - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Software Rev: %i.%i\n", - VERSION(vbe->OemSoftwareRev)); - if (vbe->OemVendorNamePtr) - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Vendor: %s\n", - (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemVendorNamePtr))); - if (vbe->OemProductNamePtr) - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Product: %s\n", - (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemProductNamePtr))); - if (vbe->OemProductRevPtr) - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Product Rev: %s\n", - (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemProductRevPtr))); - } - vip = (vbeInfoPtr)xnfalloc(sizeof(vbeInfoRec)); - vip->version = B_O16(vbe->VbeVersion); - vip->pInt10 = pInt; - vip->ddc = DDC_UNCHECKED; - vip->memory = page; - vip->real_mode_base = RealOff; - vip->num_pages = 1; - vip->init_int10 = init_int10; - - return vip; - - error: - if (page) - xf86Int10FreePages(pInt, page, 1); - if (init_int10) - xf86FreeInt10(pInt); - return NULL; -} - -void -vbeFree(vbeInfoPtr pVbe) -{ - if (!pVbe) - return; - - xf86Int10FreePages(pVbe->pInt10,pVbe->memory,pVbe->num_pages); - /* If we have initalized int10 we ought to free it, too */ - if (pVbe->init_int10) - xf86FreeInt10(pVbe->pInt10); - xfree(pVbe); - return; -} - -static Bool -vbeProbeDDC(vbeInfoPtr pVbe) -{ - char *ddc_level; - int screen = pVbe->pInt10->scrnIndex; - - if (pVbe->ddc == DDC_NONE) - return FALSE; - if (pVbe->ddc != DDC_UNCHECKED) - return TRUE; - - pVbe->pInt10->ax = 0x4F15; - pVbe->pInt10->bx = 0; - pVbe->pInt10->cx = 0; - pVbe->pInt10->es = 0; - pVbe->pInt10->di = 0; - pVbe->pInt10->num = 0x10; - - xf86ExecX86int10(pVbe->pInt10); - - if ((pVbe->pInt10->ax & 0xff) != 0x4f) { - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC not supported\n"); - pVbe->ddc = DDC_NONE; - return FALSE; - } - - switch ((pVbe->pInt10->ax >> 8) & 0xff) { - case 0: - xf86DrvMsg(screen,X_INFO,"VESA VBE DDC supported\n"); - switch (pVbe->pInt10->bx & 0x3) { - case 0: - ddc_level = " none"; - pVbe->ddc = DDC_NONE; - break; - case 1: - ddc_level = " 1"; - pVbe->ddc = DDC_1; - break; - case 2: - ddc_level = " 2"; - pVbe->ddc = DDC_2; - break; - case 3: - ddc_level = " 1 + 2"; - pVbe->ddc = DDC_1_2; - break; - default: - ddc_level = ""; - pVbe->ddc = DDC_NONE; - break; - } - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC Level%s\n",ddc_level); - if (pVbe->pInt10->bx & 0x4) { - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC Screen blanked" - "for data transfer\n"); - pVbe->ddc_blank = TRUE; - } else - pVbe->ddc_blank = FALSE; - - xf86DrvMsgVerb(screen,X_INFO,3, - "VESA VBE DDC transfer in appr. %x sec.\n", - (pVbe->pInt10->bx >> 8) & 0xff); - } - - return TRUE; -} - -typedef enum { - VBEOPT_NOVBE, - VBEOPT_NODDC -} VBEOpts; - -static const OptionInfoRec VBEOptions[] = { - { VBEOPT_NOVBE, "NoVBE", OPTV_BOOLEAN, {0}, FALSE }, - { VBEOPT_NODDC, "NoDDC", OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, OPTV_NONE, {0}, FALSE }, -}; - -static unsigned char * -vbeReadEDID(vbeInfoPtr pVbe) -{ - int RealOff = pVbe->real_mode_base; - pointer page = pVbe->memory; - unsigned char *tmp = NULL; - Bool novbe = FALSE; - Bool noddc = FALSE; - int screen = pVbe->pInt10->scrnIndex; - OptionInfoPtr options; - - if (!page) return NULL; - - options = xnfalloc(sizeof(VBEOptions)); - (void)memcpy(options, VBEOptions, sizeof(VBEOptions)); - xf86ProcessOptions(screen, xf86Screens[screen]->options, options); - xf86GetOptValBool(options, VBEOPT_NOVBE, &novbe); - xf86GetOptValBool(options, VBEOPT_NODDC, &noddc); - xfree(options); - if (novbe || noddc) return NULL; - - if (!vbeProbeDDC(pVbe)) goto error; - - memset(page,0,sizeof(vbeInfoPtr)); - strcpy(page,vbeVersionString); - - pVbe->pInt10->ax = 0x4F15; - pVbe->pInt10->bx = 0x01; - pVbe->pInt10->cx = 0; - pVbe->pInt10->dx = 0; - pVbe->pInt10->es = SEG_ADDR(RealOff); - pVbe->pInt10->di = SEG_OFF(RealOff); - pVbe->pInt10->num = 0x10; - - xf86ExecX86int10(pVbe->pInt10); - - if ((pVbe->pInt10->ax & 0xff) != 0x4f) { - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC invalid\n"); - goto error; - } - switch (pVbe->pInt10->ax & 0xff00) { - case 0x0: - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC read successfully\n"); - tmp = (unsigned char *)xnfalloc(128); - memcpy(tmp,page,128); - break; - case 0x100: - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC read failed\n"); - break; - default: - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC unkown failure %i\n", - pVbe->pInt10->ax & 0xff00); - break; - } - - error: - return tmp; -} - -xf86MonPtr -vbeDoEDID(vbeInfoPtr pVbe, pointer pDDCModule) -{ - xf86MonPtr pMonitor; - pointer pModule; - unsigned char *DDC_data = NULL; - - if (!pVbe) return NULL; - if (pVbe->version < 0x200) - return NULL; - - if (!(pModule = pDDCModule)) { - pModule = - xf86LoadSubModule(xf86Screens[pVbe->pInt10->scrnIndex], "ddc"); - if (!pModule) - return NULL; - } - - DDC_data = vbeReadEDID(pVbe); - - if (!DDC_data) - return NULL; - - pMonitor = xf86InterpretEDID(pVbe->pInt10->scrnIndex, DDC_data); - - if (!pDDCModule) - xf86UnloadSubModule(pModule); - return pMonitor; -} - -#define GET_UNALIGNED2(x) \ - ((*(CARD16*)(x)) | (*(((CARD16*)(x) + 1))) << 16) - -VbeInfoBlock * -VBEGetVBEInfo(vbeInfoPtr pVbe) -{ - VbeInfoBlock *block = NULL; - int i, pStr, pModes; - char *str; - CARD16 major, *modes; - - bzero(pVbe->memory, sizeof(VbeInfoBlock)); - - /* - Input: - AH := 4Fh Super VGA support - AL := 00h Return Super VGA information - ES:DI := Pointer to buffer - - Output: - AX := status - (All other registers are preserved) - */ - - ((char*)pVbe->memory)[0] = 'V'; - ((char*)pVbe->memory)[1] = 'B'; - ((char*)pVbe->memory)[2] = 'E'; - ((char*)pVbe->memory)[3] = '2'; - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f00; - pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); - pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) != 0x4f) - return (NULL); - - block = xcalloc(sizeof(VbeInfoBlock), 1); - block->VESASignature[0] = ((char*)pVbe->memory)[0]; - block->VESASignature[1] = ((char*)pVbe->memory)[1]; - block->VESASignature[2] = ((char*)pVbe->memory)[2]; - block->VESASignature[3] = ((char*)pVbe->memory)[3]; - - block->VESAVersion = *(CARD16*)(((char*)pVbe->memory) + 4); - major = (unsigned)block->VESAVersion >> 8; - - pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 6)); - str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); - block->OEMStringPtr = strdup(str); - - block->Capabilities[0] = ((char*)pVbe->memory)[10]; - block->Capabilities[1] = ((char*)pVbe->memory)[11]; - block->Capabilities[2] = ((char*)pVbe->memory)[12]; - block->Capabilities[3] = ((char*)pVbe->memory)[13]; - - pModes = GET_UNALIGNED2((((char*)pVbe->memory) + 14)); - modes = xf86int10Addr(pVbe->pInt10, FARP(pModes)); - i = 0; - while (modes[i] != 0xffff) - i++; - block->VideoModePtr = xalloc(sizeof(CARD16) * i + 1); - memcpy(block->VideoModePtr, modes, sizeof(CARD16) * i); - block->VideoModePtr[i] = 0xffff; - - block->TotalMemory = *(CARD16*)(((char*)pVbe->memory) + 18); - - if (major < 2) - memcpy(&block->OemSoftwareRev, ((char*)pVbe->memory) + 20, 236); - else { - block->OemSoftwareRev = *(CARD16*)(((char*)pVbe->memory) + 20); - pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 22)); - str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); - block->OemVendorNamePtr = strdup(str); - pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 26)); - str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); - block->OemProductNamePtr = strdup(str); - pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 30)); - str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); - block->OemProductRevPtr = strdup(str); - memcpy(&block->Reserved, ((char*)pVbe->memory) + 34, 222); - memcpy(&block->OemData, ((char*)pVbe->memory) + 256, 256); - } - - return (block); -} - -void -VBEFreeVBEInfo(VbeInfoBlock *block) -{ - xfree(block->OEMStringPtr); - xfree(block->VideoModePtr); - if (((unsigned)block->VESAVersion >> 8) >= 2) { - xfree(block->OemVendorNamePtr); - xfree(block->OemProductNamePtr); - xfree(block->OemProductRevPtr); - } - xfree(block); -} - -Bool -VBESetVBEMode(vbeInfoPtr pVbe, int mode, VbeCRTCInfoBlock *block) -{ - /* - Input: - AH := 4Fh Super VGA support - AL := 02h Set Super VGA video mode - BX := Video mode - D0-D8 := Mode number - D9-D10 := Reserved (must be 0) - D11 := 0 Use current default refresh rate - := 1 Use user specified CRTC values for refresh rate - D12-13 Reserved for VBE/AF (must be 0) - D14 := 0 Use windowed frame buffer model - := 1 Use linear/flat frame buffer model - D15 := 0 Clear video memory - := 1 Don't clear video memory - ES:DI := Pointer to VbeCRTCInfoBlock structure - - Output: AX = Status - (All other registers are preserved) - */ - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f02; - pVbe->pInt10->bx = mode; - if (block) { - pVbe->pInt10->bx |= 1 << 11; - memcpy(pVbe->memory, block, sizeof(VbeCRTCInfoBlock)); - pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); - pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); - } else - pVbe->pInt10->bx &= ~(1 << 11); - - xf86ExecX86int10(pVbe->pInt10); - - return (R16(pVbe->pInt10->ax) == 0x4f); -} - -Bool -VBEGetVBEMode(vbeInfoPtr pVbe, int *mode) -{ - /* - Input: - AH := 4Fh Super VGA support - AL := 03h Return current video mode - - Output: - AX := Status - BX := Current video mode - (All other registers are preserved) - */ - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f03; - - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) == 0x4f) { - *mode = R16(pVbe->pInt10->bx); - - return (TRUE); - } - - return (FALSE); -} - -VbeModeInfoBlock * -VBEGetModeInfo(vbeInfoPtr pVbe, int mode) -{ - VbeModeInfoBlock *block = NULL; - - bzero(pVbe->memory, sizeof(VbeModeInfoBlock)); - - /* - Input: - AH := 4Fh Super VGA support - AL := 01h Return Super VGA mode information - CX := Super VGA video mode - (mode number must be one of those returned by Function 0) - ES:DI := Pointer to buffer - - Output: - AX := status - (All other registers are preserved) - */ - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f01; - pVbe->pInt10->cx = mode; - pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); - pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); - xf86ExecX86int10(pVbe->pInt10); - if (R16(pVbe->pInt10->ax) != 0x4f) - return (NULL); - - block = xcalloc(sizeof(VbeModeInfoBlock), 1); - - block->ModeAttributes = *(CARD16*)pVbe->memory; - block->WinAAttributes = ((char*)pVbe->memory)[2]; - block->WinBAttributes = ((char*)pVbe->memory)[3]; - block->WinGranularity = *(CARD16*)(((char*)pVbe->memory) + 4); - block->WinSize = *(CARD16*)(((char*)pVbe->memory) + 6); - block->WinASegment = *(CARD16*)(((char*)pVbe->memory) + 8); - block->WinBSegment = *(CARD16*)(((char*)pVbe->memory) + 10); - block->WinFuncPtr = *(CARD32*)(((char*)pVbe->memory) + 12); - block->BytesPerScanline = *(CARD16*)(((char*)pVbe->memory) + 16); - - /* mandatory information for VBE 1.2 and above */ - block->XResolution = *(CARD16*)(((char*)pVbe->memory) + 18); - block->YResolution = *(CARD16*)(((char*)pVbe->memory) + 20); - block->XCharSize = ((char*)pVbe->memory)[22]; - block->YCharSize = ((char*)pVbe->memory)[23]; - block->NumberOfPlanes = ((char*)pVbe->memory)[24]; - block->BitsPerPixel = ((char*)pVbe->memory)[25]; - block->NumberOfBanks = ((char*)pVbe->memory)[26]; - block->MemoryModel = ((char*)pVbe->memory)[27]; - block->BankSize = ((char*)pVbe->memory)[28]; - block->NumberOfImages = ((char*)pVbe->memory)[29]; - block->Reserved = ((char*)pVbe->memory)[30]; - - /* Direct color fields (required for direct/6 and YUV/7 memory models) */ - block->RedMaskSize = ((char*)pVbe->memory)[31]; - block->RedFieldPosition = ((char*)pVbe->memory)[32]; - block->GreenMaskSize = ((char*)pVbe->memory)[33]; - block->GreenFieldPosition = ((char*)pVbe->memory)[34]; - block->BlueMaskSize = ((char*)pVbe->memory)[35]; - block->BlueFieldPosition = ((char*)pVbe->memory)[36]; - block->RsvdMaskSize = ((char*)pVbe->memory)[37]; - block->RsvdFieldPosition = ((char*)pVbe->memory)[38]; - block->DirectColorModeInfo = ((char*)pVbe->memory)[39]; - - /* Mandatory information for VBE 2.0 and above */ - if (pVbe->version >= 0x200) { - block->PhysBasePtr = *(CARD32*)(((char*)pVbe->memory) + 40); - block->Reserved32 = *(CARD32*)(((char*)pVbe->memory) + 44); - block->Reserved16 = *(CARD16*)(((char*)pVbe->memory) + 48); - - /* Mandatory information for VBE 3.0 and above */ - if (pVbe->version >= 0x300) { - block->LinBytesPerScanLine = *(CARD16*)(((char*)pVbe->memory) + 50); - block->BnkNumberOfImagePages = ((char*)pVbe->memory)[52]; - block->LinNumberOfImagePages = ((char*)pVbe->memory)[53]; - block->LinRedMaskSize = ((char*)pVbe->memory)[54]; - block->LinRedFieldPosition = ((char*)pVbe->memory)[55]; - block->LinGreenMaskSize = ((char*)pVbe->memory)[56]; - block->LinGreenFieldPosition = ((char*)pVbe->memory)[57]; - block->LinBlueMaskSize = ((char*)pVbe->memory)[58]; - block->LinBlueFieldPosition = ((char*)pVbe->memory)[59]; - block->LinRsvdMaskSize = ((char*)pVbe->memory)[60]; - block->LinRsvdFieldPosition = ((char*)pVbe->memory)[61]; - block->MaxPixelClock = *(CARD32*)(((char*)pVbe->memory) + 62); - memcpy(&block->Reserved2, ((char*)pVbe->memory) + 66, 188); - } - else - memcpy(&block->LinBytesPerScanLine, ((char*)pVbe->memory) + 50, 206); - } - else - memcpy(&block->PhysBasePtr, ((char*)pVbe->memory) + 40, 216); - - return (block); -} - -void -VBEFreeModeInfo(VbeModeInfoBlock *block) -{ - xfree(block); -} - -Bool -VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction function, - pointer *memory, int *size, int *real_mode_pages) -{ - /* - Input: - AH := 4Fh Super VGA support - AL := 04h Save/restore Super VGA video state - DL := 00h Return save/restore state buffer size - CX := Requested states - D0 = Save/restore video hardware state - D1 = Save/restore video BIOS data state - D2 = Save/restore video DAC state - D3 = Save/restore Super VGA state - - Output: - AX = Status - BX = Number of 64-byte blocks to hold the state buffer - (All other registers are preserved) - - - Input: - AH := 4Fh Super VGA support - AL := 04h Save/restore Super VGA video state - DL := 01h Save Super VGA video state - CX := Requested states (see above) - ES:BX := Pointer to buffer - - Output: - AX := Status - (All other registers are preserved) - - - Input: - AH := 4Fh Super VGA support - AL := 04h Save/restore Super VGA video state - DL := 02h Restore Super VGA video state - CX := Requested states (see above) - ES:BX := Pointer to buffer - - Output: - AX := Status - (All other registers are preserved) - */ - - if ((pVbe->version & 0xff00) > 0x100) { - int screen = pVbe->pInt10->scrnIndex; - if (function == MODE_QUERY || - (function == MODE_SAVE && !*memory)) { - /* Query amount of memory to save state */ - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f04; - pVbe->pInt10->dx = 0; - pVbe->pInt10->cx = 0x000f; - xf86ExecX86int10(pVbe->pInt10); - if (R16(pVbe->pInt10->ax) != 0x4f) - return (FALSE); - - if (function == MODE_SAVE) { - int npages = (R16(pVbe->pInt10->bx) * 64) / 4096 + 1; - if ((*memory = xf86Int10AllocPages(pVbe->pInt10, npages, - real_mode_pages)) == NULL) { - xf86DrvMsg(screen, X_ERROR, - "Cannot allocate memory to save SVGA state.\n"); - return (FALSE); - } - } - *size = pVbe->pInt10->bx * 64; - } - - /* Save/Restore Super VGA state */ - if (function != MODE_QUERY) { - - if (!*memory) return FALSE; - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f04; - switch (function) { - case MODE_SAVE: - pVbe->pInt10->dx = 1; - break; - case MODE_RESTORE: - pVbe->pInt10->dx = 2; - break; - case MODE_QUERY: - return FALSE; - } - pVbe->pInt10->cx = 0x000f; - - pVbe->pInt10->es = SEG_ADDR(*real_mode_pages); - pVbe->pInt10->bx = SEG_OFF(*real_mode_pages); - xf86ExecX86int10(pVbe->pInt10); - return (R16(pVbe->pInt10->ax) == 0x4f); - - } - } - return TRUE; -} - -Bool -VBEBankSwitch(vbeInfoPtr pVbe, unsigned int iBank, int window) -{ - /* - Input: - AH := 4Fh Super VGA support - AL := 05h - - Output: - */ - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f05; - pVbe->pInt10->bx = window; - pVbe->pInt10->dx = iBank; - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) != 0x4f) - return (FALSE); - - return (TRUE); -} - -Bool -VBESetGetLogicalScanlineLength(vbeInfoPtr pVbe, vbeScanwidthCommand command, - int width, int *pixels, int *bytes, int *max) -{ - if (command < SCANWID_SET || command > SCANWID_GET_MAX) - return (FALSE); - - /* - Input: - AX := 4F06h VBE Set/Get Logical Scan Line Length - BL := 00h Set Scan Line Length in Pixels - := 01h Get Scan Line Length - := 02h Set Scan Line Length in Bytes - := 03h Get Maximum Scan Line Length - CX := If BL=00h Desired Width in Pixels - If BL=02h Desired Width in Bytes - (Ignored for Get Functions) - - Output: - AX := VBE Return Status - BX := Bytes Per Scan Line - CX := Actual Pixels Per Scan Line - (truncated to nearest complete pixel) - DX := Maximum Number of Scan Lines - */ - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f06; - pVbe->pInt10->bx = command; - if (command == SCANWID_SET || command == SCANWID_SET_BYTES) - pVbe->pInt10->cx = width; - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) != 0x4f) - return (FALSE); - - if (command == SCANWID_GET || command == SCANWID_GET_MAX) { - if (pixels) - *pixels = R16(pVbe->pInt10->cx); - if (bytes) - *bytes = R16(pVbe->pInt10->bx); - if (max) - *max = R16(pVbe->pInt10->dx); - } - - return (TRUE); -} - -Bool -VBESetDisplayStart(vbeInfoPtr pVbe, int x, int y, Bool wait_retrace) -{ - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f07; - pVbe->pInt10->bx = wait_retrace ? 0x80 : 0x00; - pVbe->pInt10->cx = x; - pVbe->pInt10->dx = y; - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) != 0x4f) - return (FALSE); - - return (TRUE); -} - -Bool -VBEGetDisplayStart(vbeInfoPtr pVbe, int *x, int *y) -{ - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f07; - pVbe->pInt10->bx = 0x01; - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) != 0x4f) - return (FALSE); - - *x = pVbe->pInt10->cx; - *y = pVbe->pInt10->dx; - - return (TRUE); -} - -int -VBESetGetDACPaletteFormat(vbeInfoPtr pVbe, int bits) -{ - /* - Input: - AX := 4F08h VBE Set/Get Palette Format - BL := 00h Set DAC Palette Format - := 01h Get DAC Palette Format - BH := Desired bits of color per primary - (Set DAC Palette Format only) - - Output: - AX := VBE Return Status - BH := Current number of bits of color per primary - */ - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f08; - if (!bits) - pVbe->pInt10->bx = 0x01; - else - pVbe->pInt10->bx = (bits & 0x00ff) << 8; - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) != 0x4f) - return (0); - - return (bits != 0 ? bits : (pVbe->pInt10->bx >> 8) & 0x00ff); -} - -CARD32 * -VBESetGetPaletteData(vbeInfoPtr pVbe, Bool set, int first, int num, - CARD32 *data, Bool secondary, Bool wait_retrace) -{ - /* - Input: - (16-bit) - AX := 4F09h VBE Load/Unload Palette Data - BL := 00h Set Palette Data - := 01h Get Palette Data - := 02h Set Secondary Palette Data - := 03h Get Secondary Palette Data - := 80h Set Palette Data during Vertical Retrace - CX := Number of palette registers to update (to a maximum of 256) - DX := First of the palette registers to update (start) - ES:DI := Table of palette values (see below for format) - - Output: - AX := VBE Return Status - - - Input: - (32-bit) - BL := 00h Set Palette Data - := 80h Set Palette Data during Vertical Retrace - CX := Number of palette registers to update (to a maximum of 256) - DX := First of the palette registers to update (start) - ES:EDI := Table of palette values (see below for format) - DS := Selector for memory mapped registers - */ - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f09; - if (!secondary) - pVbe->pInt10->bx = set && wait_retrace ? 0x80 : set ? 0 : 1; - else - pVbe->pInt10->bx = set ? 2 : 3; - pVbe->pInt10->cx = num; - pVbe->pInt10->dx = first; - pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); - pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); - if (set) - memcpy(pVbe->memory, data, num * sizeof(CARD32)); - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) != 0x4f) - return (NULL); - - if (set) - return (data); - - data = xalloc(num * sizeof(CARD32)); - memcpy(data, pVbe->memory, num * sizeof(CARD32)); - - return (data); -} - -VBEpmi * -VBEGetVBEpmi(vbeInfoPtr pVbe) -{ - VBEpmi *pmi; - - /* - Input: - AH := 4Fh Super VGA support - AL := 0Ah Protected Mode Interface - BL := 00h Return Protected Mode Table - - Output: - AX := Status - ES := Real Mode Segment of Table - DI := Offset of Table - CX := Lenght of Table including protected mode code in bytes (for copying purposes) - (All other registers are preserved) - */ - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f0a; - pVbe->pInt10->bx = 0; - pVbe->pInt10->di = 0; - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) != 0x4f) - return (NULL); - - pmi = xalloc(sizeof(VBEpmi)); - pmi->seg_tbl = R16(pVbe->pInt10->es); - pmi->tbl_off = R16(pVbe->pInt10->di); - pmi->tbl_len = R16(pVbe->pInt10->cx); - - return (pmi); -} - -#if 0 -vbeModeInfoPtr -VBEBuildVbeModeList(vbeInfoPtr pVbe, VbeInfoBlock *vbe) -{ - vbeModeInfoPtr ModeList = NULL; - - int i = 0; - while (vbe->VideoModePtr[i] != 0xffff) { - vbeModeInfoPtr m; - VbeModeInfoBlock *mode; - int id = vbe->VideoModePtr[i++]; - int bpp; - - if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) - continue; - - bpp = mode->BitsPerPixel; - - m = xnfcalloc(sizeof(vbeModeInfoRec),1); - m->width = mode->XResolution; - m->height = mode->YResolution; - m->bpp = bpp; - m->n = id; - m->next = ModeList; - - xf86DrvMsgVerb(pVbe->pInt10->scrnIndex, X_PROBED, 3, - "BIOS reported VESA mode 0x%x: x:%i y:%i bpp:%i\n", - m->n, m->width, m->height, m->bpp); - - ModeList = m; - - VBEFreeModeInfo(mode); - } - return ModeList; -} - -unsigned short -VBECalcVbeModeIndex(vbeModeInfoPtr m, DisplayModePtr mode, int bpp) -{ - while (m) { - if (bpp == m->bpp - && mode->HDisplay == m->width - && mode->VDisplay == m->height) - return m->n; - m = m->next; - } - return 0; -} -#endif - -void -VBEVesaSaveRestore(vbeInfoPtr pVbe, vbeSaveRestorePtr vbe_sr, - vbeSaveRestoreFunction function) -{ - Bool SaveSucc = FALSE; - - if (VBE_VERSION_MAJOR(pVbe->version) > 1 - && (function == MODE_SAVE || vbe_sr->pstate)) { - if (function == MODE_RESTORE) - memcpy(vbe_sr->state, vbe_sr->pstate, vbe_sr->stateSize); - ErrorF("VBESaveRestore\n"); - if ((VBESaveRestore(pVbe,function, - (pointer)&vbe_sr->state, - &vbe_sr->stateSize,&vbe_sr->statePage))) { - if (function == MODE_SAVE) { - SaveSucc = TRUE; - vbe_sr->stateMode = -1; /* invalidate */ - /* don't rely on the memory not being touched */ - if (vbe_sr->pstate == NULL) - vbe_sr->pstate = xalloc(vbe_sr->stateSize); - memcpy(vbe_sr->pstate, vbe_sr->state, vbe_sr->stateSize); - } - ErrorF("VBESaveRestore done with success\n"); - return; - } - ErrorF("VBESaveRestore done\n"); - } - - if (function == MODE_SAVE && !SaveSucc) - (void)VBEGetVBEMode(pVbe, &vbe_sr->stateMode); - - if (function == MODE_RESTORE && vbe_sr->stateMode != -1) - VBESetVBEMode(pVbe, vbe_sr->stateMode, NULL); - -} - -int -VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int clock) -{ - /* - Input: - AX := 4F0Bh VBE Get Pixel Clock - BL := 00h Get Pixel Clock - ECX := pixel clock in units of Hz - DX := mode number - - Output: - AX := VBE Return Status - ECX := Closest pixel clock - */ - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f0b; - pVbe->pInt10->bx = 0x00; - pVbe->pInt10->cx = clock; - pVbe->pInt10->dx = mode; - xf86ExecX86int10(pVbe->pInt10); - - if (R16(pVbe->pInt10->ax) != 0x4f) - return (0); - - return (pVbe->pInt10->cx); -} - -Bool -VBEDPMSSet(vbeInfoPtr pVbe, int mode) -{ - /* - Input: - AX := 4F10h DPMS - BL := 01h Set Display Power State - BH := requested power state - - Output: - AX := VBE Return Status - */ - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f10; - pVbe->pInt10->bx = 0x01; - switch (mode) { - case DPMSModeOn: - break; - case DPMSModeStandby: - pVbe->pInt10->bx |= 0x100; - break; - case DPMSModeSuspend: - pVbe->pInt10->bx |= 0x200; - break; - case DPMSModeOff: - pVbe->pInt10->bx |= 0x400; - break; - } - xf86ExecX86int10(pVbe->pInt10); - return (R16(pVbe->pInt10->ax) == 0x4f); -} - -void -VBEInterpretPanelID(int scrnIndex, struct vbePanelID *data) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - DisplayModePtr mode; - const float PANEL_HZ = 60.0; - - if (!data) - return; - - xf86DrvMsg(scrnIndex, X_INFO, "PanelID returned panel resolution %dx%d\n", - data->hsize, data->vsize); - - if (pScrn->monitor->nHsync || pScrn->monitor->nVrefresh) - return; - - mode = xf86CVTMode(data->hsize, data->vsize, PANEL_HZ, 1, 0); - - pScrn->monitor->nHsync = 1; - pScrn->monitor->hsync[0].lo = 31.5; - pScrn->monitor->hsync[0].hi = (float)mode->Clock / (float)mode->HTotal; - pScrn->monitor->nVrefresh = 1; - pScrn->monitor->vrefresh[0].lo = 56.0; - pScrn->monitor->vrefresh[0].hi = - (float)mode->Clock*1000.0 / (float)mode->HTotal / (float)mode->VTotal; - - xfree(mode); -} - -struct vbePanelID * -VBEReadPanelID(vbeInfoPtr pVbe) -{ - int RealOff = pVbe->real_mode_base; - pointer page = pVbe->memory; - void *tmp = NULL; - int screen = pVbe->pInt10->scrnIndex; - - pVbe->pInt10->ax = 0x4F11; - pVbe->pInt10->bx = 0x01; - pVbe->pInt10->cx = 0; - pVbe->pInt10->dx = 0; - pVbe->pInt10->es = SEG_ADDR(RealOff); - pVbe->pInt10->di = SEG_OFF(RealOff); - pVbe->pInt10->num = 0x10; - - xf86ExecX86int10(pVbe->pInt10); - - if ((pVbe->pInt10->ax & 0xff) != 0x4f) { - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID invalid\n"); - goto error; - } - - switch (pVbe->pInt10->ax & 0xff00) { - case 0x0: - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read successfully\n"); - tmp = xnfalloc(32); - memcpy(tmp, page, 32); - break; - case 0x100: - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read failed\n"); - break; - default: - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID unknown failure %i\n", - pVbe->pInt10->ax & 0xff00); - break; - } - -error: - return tmp; -} + +/* + * XFree86 vbe module + * Copyright 2000 Egbert Eich + * + * The mode query/save/set/restore functions from the vesa driver + * have been moved here. + * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com) + * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br> + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "xf86.h" +#include "vbe.h" +#include <X11/Xarch.h> +#include <X11/extensions/dpmsconst.h> + +#define VERSION(x) VBE_VERSION_MAJOR(x),VBE_VERSION_MINOR(x) + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN +#define B_O16(x) (x) +#define B_O32(x) (x) +#else +#define B_O16(x) ((((x) & 0xff) << 8) | (((x) & 0xff) >> 8)) +#define B_O32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) \ + | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24)) +#endif +#define L_ADD(x) (B_O32(x) & 0xffff) + ((B_O32(x) >> 12) & 0xffff00) + +#define FARP(p) (((unsigned)(p & 0xffff0000) >> 12) | (p & 0xffff)) +#define R16(v) ((v) & 0xffff) + +static unsigned char * vbeReadEDID(vbeInfoPtr pVbe); +static Bool vbeProbeDDC(vbeInfoPtr pVbe); + +static const char vbeVersionString[] = "VBE2"; + +vbeInfoPtr +VBEInit(xf86Int10InfoPtr pInt, int entityIndex) +{ + return VBEExtendedInit(pInt, entityIndex, 0); +} + +vbeInfoPtr +VBEExtendedInit(xf86Int10InfoPtr pInt, int entityIndex, int Flags) +{ + int RealOff; + pointer page = NULL; + ScrnInfoPtr pScrn = xf86FindScreenForEntity(entityIndex); + vbeControllerInfoPtr vbe = NULL; + Bool init_int10 = FALSE; + vbeInfoPtr vip = NULL; + int screen; + + if (!pScrn) return NULL; + screen = pScrn->scrnIndex; + + if (!pInt) { + if (!xf86LoadSubModule(pScrn, "int10")) + goto error; + + xf86DrvMsg(screen,X_INFO,"initializing int10\n"); + pInt = xf86ExtendedInitInt10(entityIndex,Flags); + if (!pInt) + goto error; + init_int10 = TRUE; + } + + page = xf86Int10AllocPages(pInt,1,&RealOff); + if (!page) goto error; + vbe = (vbeControllerInfoPtr) page; + memcpy(vbe->VbeSignature,vbeVersionString,4); + + pInt->ax = 0x4F00; + pInt->es = SEG_ADDR(RealOff); + pInt->di = SEG_OFF(RealOff); + pInt->num = 0x10; + + xf86ExecX86int10(pInt); + + if ((pInt->ax & 0xff) != 0x4f) { + xf86DrvMsgVerb(screen,X_INFO,3,"VESA BIOS not detected\n"); + goto error; + } + + switch (pInt->ax & 0xff00) { + case 0: + xf86DrvMsg(screen,X_INFO,"VESA BIOS detected\n"); + break; + case 0x100: + xf86DrvMsg(screen,X_INFO,"VESA BIOS function failed\n"); + goto error; + case 0x200: + xf86DrvMsg(screen,X_INFO,"VESA BIOS not supported\n"); + goto error; + case 0x300: + xf86DrvMsg(screen,X_INFO,"VESA BIOS not supported in current mode\n"); + goto error; + default: + xf86DrvMsg(screen,X_INFO,"Invalid\n"); + goto error; + } + + xf86DrvMsgVerb(screen, X_INFO, 4, + "VbeVersion is %d, OemStringPtr is 0x%08lx,\n" + "\tOemVendorNamePtr is 0x%08lx, OemProductNamePtr is 0x%08lx,\n" + "\tOemProductRevPtr is 0x%08lx\n", + vbe->VbeVersion, (unsigned long)vbe->OemStringPtr, + (unsigned long)vbe->OemVendorNamePtr, + (unsigned long)vbe->OemProductNamePtr, + (unsigned long)vbe->OemProductRevPtr); + + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE Version %i.%i\n", + VERSION(vbe->VbeVersion)); + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE Total Mem: %i kB\n", + vbe->TotalMem * 64); + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM: %s\n", + (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemStringPtr))); + + if (B_O16(vbe->VbeVersion) >= 0x200) { + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Software Rev: %i.%i\n", + VERSION(vbe->OemSoftwareRev)); + if (vbe->OemVendorNamePtr) + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Vendor: %s\n", + (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemVendorNamePtr))); + if (vbe->OemProductNamePtr) + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Product: %s\n", + (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemProductNamePtr))); + if (vbe->OemProductRevPtr) + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Product Rev: %s\n", + (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemProductRevPtr))); + } + vip = (vbeInfoPtr)xnfalloc(sizeof(vbeInfoRec)); + vip->version = B_O16(vbe->VbeVersion); + vip->pInt10 = pInt; + vip->ddc = DDC_UNCHECKED; + vip->memory = page; + vip->real_mode_base = RealOff; + vip->num_pages = 1; + vip->init_int10 = init_int10; + + return vip; + + error: + if (page) + xf86Int10FreePages(pInt, page, 1); + if (init_int10) + xf86FreeInt10(pInt); + return NULL; +} + +void +vbeFree(vbeInfoPtr pVbe) +{ + if (!pVbe) + return; + + xf86Int10FreePages(pVbe->pInt10,pVbe->memory,pVbe->num_pages); + /* If we have initalized int10 we ought to free it, too */ + if (pVbe->init_int10) + xf86FreeInt10(pVbe->pInt10); + free(pVbe); + return; +} + +static Bool +vbeProbeDDC(vbeInfoPtr pVbe) +{ + char *ddc_level; + int screen = pVbe->pInt10->scrnIndex; + + if (pVbe->ddc == DDC_NONE) + return FALSE; + if (pVbe->ddc != DDC_UNCHECKED) + return TRUE; + + pVbe->pInt10->ax = 0x4F15; + pVbe->pInt10->bx = 0; + pVbe->pInt10->cx = 0; + pVbe->pInt10->es = 0; + pVbe->pInt10->di = 0; + pVbe->pInt10->num = 0x10; + + xf86ExecX86int10(pVbe->pInt10); + + if ((pVbe->pInt10->ax & 0xff) != 0x4f) { + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC not supported\n"); + pVbe->ddc = DDC_NONE; + return FALSE; + } + + switch ((pVbe->pInt10->ax >> 8) & 0xff) { + case 0: + xf86DrvMsg(screen,X_INFO,"VESA VBE DDC supported\n"); + switch (pVbe->pInt10->bx & 0x3) { + case 0: + ddc_level = " none"; + pVbe->ddc = DDC_NONE; + break; + case 1: + ddc_level = " 1"; + pVbe->ddc = DDC_1; + break; + case 2: + ddc_level = " 2"; + pVbe->ddc = DDC_2; + break; + case 3: + ddc_level = " 1 + 2"; + pVbe->ddc = DDC_1_2; + break; + default: + ddc_level = ""; + pVbe->ddc = DDC_NONE; + break; + } + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC Level%s\n",ddc_level); + if (pVbe->pInt10->bx & 0x4) { + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC Screen blanked" + "for data transfer\n"); + pVbe->ddc_blank = TRUE; + } else + pVbe->ddc_blank = FALSE; + + xf86DrvMsgVerb(screen,X_INFO,3, + "VESA VBE DDC transfer in appr. %x sec.\n", + (pVbe->pInt10->bx >> 8) & 0xff); + } + + return TRUE; +} + +typedef enum { + VBEOPT_NOVBE, + VBEOPT_NODDC +} VBEOpts; + +static const OptionInfoRec VBEOptions[] = { + { VBEOPT_NOVBE, "NoVBE", OPTV_BOOLEAN, {0}, FALSE }, + { VBEOPT_NODDC, "NoDDC", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +static unsigned char * +vbeReadEDID(vbeInfoPtr pVbe) +{ + int RealOff = pVbe->real_mode_base; + pointer page = pVbe->memory; + unsigned char *tmp = NULL; + Bool novbe = FALSE; + Bool noddc = FALSE; + int screen = pVbe->pInt10->scrnIndex; + OptionInfoPtr options; + + if (!page) return NULL; + + options = xnfalloc(sizeof(VBEOptions)); + (void)memcpy(options, VBEOptions, sizeof(VBEOptions)); + xf86ProcessOptions(screen, xf86Screens[screen]->options, options); + xf86GetOptValBool(options, VBEOPT_NOVBE, &novbe); + xf86GetOptValBool(options, VBEOPT_NODDC, &noddc); + free(options); + if (novbe || noddc) return NULL; + + if (!vbeProbeDDC(pVbe)) goto error; + + memset(page,0,sizeof(vbeInfoPtr)); + strcpy(page,vbeVersionString); + + pVbe->pInt10->ax = 0x4F15; + pVbe->pInt10->bx = 0x01; + pVbe->pInt10->cx = 0; + pVbe->pInt10->dx = 0; + pVbe->pInt10->es = SEG_ADDR(RealOff); + pVbe->pInt10->di = SEG_OFF(RealOff); + pVbe->pInt10->num = 0x10; + + xf86ExecX86int10(pVbe->pInt10); + + if ((pVbe->pInt10->ax & 0xff) != 0x4f) { + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC invalid\n"); + goto error; + } + switch (pVbe->pInt10->ax & 0xff00) { + case 0x0: + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC read successfully\n"); + tmp = (unsigned char *)xnfalloc(128); + memcpy(tmp,page,128); + break; + case 0x100: + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC read failed\n"); + break; + default: + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC unkown failure %i\n", + pVbe->pInt10->ax & 0xff00); + break; + } + + error: + return tmp; +} + +xf86MonPtr +vbeDoEDID(vbeInfoPtr pVbe, pointer pDDCModule) +{ + xf86MonPtr pMonitor; + pointer pModule; + unsigned char *DDC_data = NULL; + + if (!pVbe) return NULL; + if (pVbe->version < 0x200) + return NULL; + + if (!(pModule = pDDCModule)) { + pModule = + xf86LoadSubModule(xf86Screens[pVbe->pInt10->scrnIndex], "ddc"); + if (!pModule) + return NULL; + } + + DDC_data = vbeReadEDID(pVbe); + + if (!DDC_data) + return NULL; + + pMonitor = xf86InterpretEDID(pVbe->pInt10->scrnIndex, DDC_data); + + if (!pDDCModule) + xf86UnloadSubModule(pModule); + return pMonitor; +} + +#define GET_UNALIGNED2(x) \ + ((*(CARD16*)(x)) | (*(((CARD16*)(x) + 1))) << 16) + +VbeInfoBlock * +VBEGetVBEInfo(vbeInfoPtr pVbe) +{ + VbeInfoBlock *block = NULL; + int i, pStr, pModes; + char *str; + CARD16 major, *modes; + + bzero(pVbe->memory, sizeof(VbeInfoBlock)); + + /* + Input: + AH := 4Fh Super VGA support + AL := 00h Return Super VGA information + ES:DI := Pointer to buffer + + Output: + AX := status + (All other registers are preserved) + */ + + ((char*)pVbe->memory)[0] = 'V'; + ((char*)pVbe->memory)[1] = 'B'; + ((char*)pVbe->memory)[2] = 'E'; + ((char*)pVbe->memory)[3] = '2'; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f00; + pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); + pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return (NULL); + + block = calloc(sizeof(VbeInfoBlock), 1); + block->VESASignature[0] = ((char*)pVbe->memory)[0]; + block->VESASignature[1] = ((char*)pVbe->memory)[1]; + block->VESASignature[2] = ((char*)pVbe->memory)[2]; + block->VESASignature[3] = ((char*)pVbe->memory)[3]; + + block->VESAVersion = *(CARD16*)(((char*)pVbe->memory) + 4); + major = (unsigned)block->VESAVersion >> 8; + + pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 6)); + str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); + block->OEMStringPtr = strdup(str); + + block->Capabilities[0] = ((char*)pVbe->memory)[10]; + block->Capabilities[1] = ((char*)pVbe->memory)[11]; + block->Capabilities[2] = ((char*)pVbe->memory)[12]; + block->Capabilities[3] = ((char*)pVbe->memory)[13]; + + pModes = GET_UNALIGNED2((((char*)pVbe->memory) + 14)); + modes = xf86int10Addr(pVbe->pInt10, FARP(pModes)); + i = 0; + while (modes[i] != 0xffff) + i++; + block->VideoModePtr = malloc(sizeof(CARD16) * i + 1); + memcpy(block->VideoModePtr, modes, sizeof(CARD16) * i); + block->VideoModePtr[i] = 0xffff; + + block->TotalMemory = *(CARD16*)(((char*)pVbe->memory) + 18); + + if (major < 2) + memcpy(&block->OemSoftwareRev, ((char*)pVbe->memory) + 20, 236); + else { + block->OemSoftwareRev = *(CARD16*)(((char*)pVbe->memory) + 20); + pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 22)); + str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); + block->OemVendorNamePtr = strdup(str); + pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 26)); + str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); + block->OemProductNamePtr = strdup(str); + pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 30)); + str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); + block->OemProductRevPtr = strdup(str); + memcpy(&block->Reserved, ((char*)pVbe->memory) + 34, 222); + memcpy(&block->OemData, ((char*)pVbe->memory) + 256, 256); + } + + return (block); +} + +void +VBEFreeVBEInfo(VbeInfoBlock *block) +{ + free(block->OEMStringPtr); + free(block->VideoModePtr); + if (((unsigned)block->VESAVersion >> 8) >= 2) { + free(block->OemVendorNamePtr); + free(block->OemProductNamePtr); + free(block->OemProductRevPtr); + } + free(block); +} + +Bool +VBESetVBEMode(vbeInfoPtr pVbe, int mode, VbeCRTCInfoBlock *block) +{ + /* + Input: + AH := 4Fh Super VGA support + AL := 02h Set Super VGA video mode + BX := Video mode + D0-D8 := Mode number + D9-D10 := Reserved (must be 0) + D11 := 0 Use current default refresh rate + := 1 Use user specified CRTC values for refresh rate + D12-13 Reserved for VBE/AF (must be 0) + D14 := 0 Use windowed frame buffer model + := 1 Use linear/flat frame buffer model + D15 := 0 Clear video memory + := 1 Don't clear video memory + ES:DI := Pointer to VbeCRTCInfoBlock structure + + Output: AX = Status + (All other registers are preserved) + */ + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f02; + pVbe->pInt10->bx = mode; + if (block) { + pVbe->pInt10->bx |= 1 << 11; + memcpy(pVbe->memory, block, sizeof(VbeCRTCInfoBlock)); + pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); + pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); + } else + pVbe->pInt10->bx &= ~(1 << 11); + + xf86ExecX86int10(pVbe->pInt10); + + return (R16(pVbe->pInt10->ax) == 0x4f); +} + +Bool +VBEGetVBEMode(vbeInfoPtr pVbe, int *mode) +{ + /* + Input: + AH := 4Fh Super VGA support + AL := 03h Return current video mode + + Output: + AX := Status + BX := Current video mode + (All other registers are preserved) + */ + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f03; + + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) == 0x4f) { + *mode = R16(pVbe->pInt10->bx); + + return (TRUE); + } + + return (FALSE); +} + +VbeModeInfoBlock * +VBEGetModeInfo(vbeInfoPtr pVbe, int mode) +{ + VbeModeInfoBlock *block = NULL; + + bzero(pVbe->memory, sizeof(VbeModeInfoBlock)); + + /* + Input: + AH := 4Fh Super VGA support + AL := 01h Return Super VGA mode information + CX := Super VGA video mode + (mode number must be one of those returned by Function 0) + ES:DI := Pointer to buffer + + Output: + AX := status + (All other registers are preserved) + */ + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f01; + pVbe->pInt10->cx = mode; + pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); + pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); + xf86ExecX86int10(pVbe->pInt10); + if (R16(pVbe->pInt10->ax) != 0x4f) + return (NULL); + + block = calloc(sizeof(VbeModeInfoBlock), 1); + + block->ModeAttributes = *(CARD16*)pVbe->memory; + block->WinAAttributes = ((char*)pVbe->memory)[2]; + block->WinBAttributes = ((char*)pVbe->memory)[3]; + block->WinGranularity = *(CARD16*)(((char*)pVbe->memory) + 4); + block->WinSize = *(CARD16*)(((char*)pVbe->memory) + 6); + block->WinASegment = *(CARD16*)(((char*)pVbe->memory) + 8); + block->WinBSegment = *(CARD16*)(((char*)pVbe->memory) + 10); + block->WinFuncPtr = *(CARD32*)(((char*)pVbe->memory) + 12); + block->BytesPerScanline = *(CARD16*)(((char*)pVbe->memory) + 16); + + /* mandatory information for VBE 1.2 and above */ + block->XResolution = *(CARD16*)(((char*)pVbe->memory) + 18); + block->YResolution = *(CARD16*)(((char*)pVbe->memory) + 20); + block->XCharSize = ((char*)pVbe->memory)[22]; + block->YCharSize = ((char*)pVbe->memory)[23]; + block->NumberOfPlanes = ((char*)pVbe->memory)[24]; + block->BitsPerPixel = ((char*)pVbe->memory)[25]; + block->NumberOfBanks = ((char*)pVbe->memory)[26]; + block->MemoryModel = ((char*)pVbe->memory)[27]; + block->BankSize = ((char*)pVbe->memory)[28]; + block->NumberOfImages = ((char*)pVbe->memory)[29]; + block->Reserved = ((char*)pVbe->memory)[30]; + + /* Direct color fields (required for direct/6 and YUV/7 memory models) */ + block->RedMaskSize = ((char*)pVbe->memory)[31]; + block->RedFieldPosition = ((char*)pVbe->memory)[32]; + block->GreenMaskSize = ((char*)pVbe->memory)[33]; + block->GreenFieldPosition = ((char*)pVbe->memory)[34]; + block->BlueMaskSize = ((char*)pVbe->memory)[35]; + block->BlueFieldPosition = ((char*)pVbe->memory)[36]; + block->RsvdMaskSize = ((char*)pVbe->memory)[37]; + block->RsvdFieldPosition = ((char*)pVbe->memory)[38]; + block->DirectColorModeInfo = ((char*)pVbe->memory)[39]; + + /* Mandatory information for VBE 2.0 and above */ + if (pVbe->version >= 0x200) { + block->PhysBasePtr = *(CARD32*)(((char*)pVbe->memory) + 40); + block->Reserved32 = *(CARD32*)(((char*)pVbe->memory) + 44); + block->Reserved16 = *(CARD16*)(((char*)pVbe->memory) + 48); + + /* Mandatory information for VBE 3.0 and above */ + if (pVbe->version >= 0x300) { + block->LinBytesPerScanLine = *(CARD16*)(((char*)pVbe->memory) + 50); + block->BnkNumberOfImagePages = ((char*)pVbe->memory)[52]; + block->LinNumberOfImagePages = ((char*)pVbe->memory)[53]; + block->LinRedMaskSize = ((char*)pVbe->memory)[54]; + block->LinRedFieldPosition = ((char*)pVbe->memory)[55]; + block->LinGreenMaskSize = ((char*)pVbe->memory)[56]; + block->LinGreenFieldPosition = ((char*)pVbe->memory)[57]; + block->LinBlueMaskSize = ((char*)pVbe->memory)[58]; + block->LinBlueFieldPosition = ((char*)pVbe->memory)[59]; + block->LinRsvdMaskSize = ((char*)pVbe->memory)[60]; + block->LinRsvdFieldPosition = ((char*)pVbe->memory)[61]; + block->MaxPixelClock = *(CARD32*)(((char*)pVbe->memory) + 62); + memcpy(&block->Reserved2, ((char*)pVbe->memory) + 66, 188); + } + else + memcpy(&block->LinBytesPerScanLine, ((char*)pVbe->memory) + 50, 206); + } + else + memcpy(&block->PhysBasePtr, ((char*)pVbe->memory) + 40, 216); + + return (block); +} + +void +VBEFreeModeInfo(VbeModeInfoBlock *block) +{ + free(block); +} + +Bool +VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction function, + pointer *memory, int *size, int *real_mode_pages) +{ + /* + Input: + AH := 4Fh Super VGA support + AL := 04h Save/restore Super VGA video state + DL := 00h Return save/restore state buffer size + CX := Requested states + D0 = Save/restore video hardware state + D1 = Save/restore video BIOS data state + D2 = Save/restore video DAC state + D3 = Save/restore Super VGA state + + Output: + AX = Status + BX = Number of 64-byte blocks to hold the state buffer + (All other registers are preserved) + + + Input: + AH := 4Fh Super VGA support + AL := 04h Save/restore Super VGA video state + DL := 01h Save Super VGA video state + CX := Requested states (see above) + ES:BX := Pointer to buffer + + Output: + AX := Status + (All other registers are preserved) + + + Input: + AH := 4Fh Super VGA support + AL := 04h Save/restore Super VGA video state + DL := 02h Restore Super VGA video state + CX := Requested states (see above) + ES:BX := Pointer to buffer + + Output: + AX := Status + (All other registers are preserved) + */ + + if ((pVbe->version & 0xff00) > 0x100) { + int screen = pVbe->pInt10->scrnIndex; + if (function == MODE_QUERY || + (function == MODE_SAVE && !*memory)) { + /* Query amount of memory to save state */ + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f04; + pVbe->pInt10->dx = 0; + pVbe->pInt10->cx = 0x000f; + xf86ExecX86int10(pVbe->pInt10); + if (R16(pVbe->pInt10->ax) != 0x4f) + return (FALSE); + + if (function == MODE_SAVE) { + int npages = (R16(pVbe->pInt10->bx) * 64) / 4096 + 1; + if ((*memory = xf86Int10AllocPages(pVbe->pInt10, npages, + real_mode_pages)) == NULL) { + xf86DrvMsg(screen, X_ERROR, + "Cannot allocate memory to save SVGA state.\n"); + return (FALSE); + } + } + *size = pVbe->pInt10->bx * 64; + } + + /* Save/Restore Super VGA state */ + if (function != MODE_QUERY) { + + if (!*memory) return FALSE; + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f04; + switch (function) { + case MODE_SAVE: + pVbe->pInt10->dx = 1; + break; + case MODE_RESTORE: + pVbe->pInt10->dx = 2; + break; + case MODE_QUERY: + return FALSE; + } + pVbe->pInt10->cx = 0x000f; + + pVbe->pInt10->es = SEG_ADDR(*real_mode_pages); + pVbe->pInt10->bx = SEG_OFF(*real_mode_pages); + xf86ExecX86int10(pVbe->pInt10); + return (R16(pVbe->pInt10->ax) == 0x4f); + + } + } + return TRUE; +} + +Bool +VBEBankSwitch(vbeInfoPtr pVbe, unsigned int iBank, int window) +{ + /* + Input: + AH := 4Fh Super VGA support + AL := 05h + + Output: + */ + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f05; + pVbe->pInt10->bx = window; + pVbe->pInt10->dx = iBank; + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return (FALSE); + + return (TRUE); +} + +Bool +VBESetGetLogicalScanlineLength(vbeInfoPtr pVbe, vbeScanwidthCommand command, + int width, int *pixels, int *bytes, int *max) +{ + if (command < SCANWID_SET || command > SCANWID_GET_MAX) + return (FALSE); + + /* + Input: + AX := 4F06h VBE Set/Get Logical Scan Line Length + BL := 00h Set Scan Line Length in Pixels + := 01h Get Scan Line Length + := 02h Set Scan Line Length in Bytes + := 03h Get Maximum Scan Line Length + CX := If BL=00h Desired Width in Pixels + If BL=02h Desired Width in Bytes + (Ignored for Get Functions) + + Output: + AX := VBE Return Status + BX := Bytes Per Scan Line + CX := Actual Pixels Per Scan Line + (truncated to nearest complete pixel) + DX := Maximum Number of Scan Lines + */ + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f06; + pVbe->pInt10->bx = command; + if (command == SCANWID_SET || command == SCANWID_SET_BYTES) + pVbe->pInt10->cx = width; + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return (FALSE); + + if (command == SCANWID_GET || command == SCANWID_GET_MAX) { + if (pixels) + *pixels = R16(pVbe->pInt10->cx); + if (bytes) + *bytes = R16(pVbe->pInt10->bx); + if (max) + *max = R16(pVbe->pInt10->dx); + } + + return (TRUE); +} + +Bool +VBESetDisplayStart(vbeInfoPtr pVbe, int x, int y, Bool wait_retrace) +{ + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f07; + pVbe->pInt10->bx = wait_retrace ? 0x80 : 0x00; + pVbe->pInt10->cx = x; + pVbe->pInt10->dx = y; + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return (FALSE); + + return (TRUE); +} + +Bool +VBEGetDisplayStart(vbeInfoPtr pVbe, int *x, int *y) +{ + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f07; + pVbe->pInt10->bx = 0x01; + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return (FALSE); + + *x = pVbe->pInt10->cx; + *y = pVbe->pInt10->dx; + + return (TRUE); +} + +int +VBESetGetDACPaletteFormat(vbeInfoPtr pVbe, int bits) +{ + /* + Input: + AX := 4F08h VBE Set/Get Palette Format + BL := 00h Set DAC Palette Format + := 01h Get DAC Palette Format + BH := Desired bits of color per primary + (Set DAC Palette Format only) + + Output: + AX := VBE Return Status + BH := Current number of bits of color per primary + */ + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f08; + if (!bits) + pVbe->pInt10->bx = 0x01; + else + pVbe->pInt10->bx = (bits & 0x00ff) << 8; + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return (0); + + return (bits != 0 ? bits : (pVbe->pInt10->bx >> 8) & 0x00ff); +} + +CARD32 * +VBESetGetPaletteData(vbeInfoPtr pVbe, Bool set, int first, int num, + CARD32 *data, Bool secondary, Bool wait_retrace) +{ + /* + Input: + (16-bit) + AX := 4F09h VBE Load/Unload Palette Data + BL := 00h Set Palette Data + := 01h Get Palette Data + := 02h Set Secondary Palette Data + := 03h Get Secondary Palette Data + := 80h Set Palette Data during Vertical Retrace + CX := Number of palette registers to update (to a maximum of 256) + DX := First of the palette registers to update (start) + ES:DI := Table of palette values (see below for format) + + Output: + AX := VBE Return Status + + + Input: + (32-bit) + BL := 00h Set Palette Data + := 80h Set Palette Data during Vertical Retrace + CX := Number of palette registers to update (to a maximum of 256) + DX := First of the palette registers to update (start) + ES:EDI := Table of palette values (see below for format) + DS := Selector for memory mapped registers + */ + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f09; + if (!secondary) + pVbe->pInt10->bx = set && wait_retrace ? 0x80 : set ? 0 : 1; + else + pVbe->pInt10->bx = set ? 2 : 3; + pVbe->pInt10->cx = num; + pVbe->pInt10->dx = first; + pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); + pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); + if (set) + memcpy(pVbe->memory, data, num * sizeof(CARD32)); + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return (NULL); + + if (set) + return (data); + + data = malloc(num * sizeof(CARD32)); + memcpy(data, pVbe->memory, num * sizeof(CARD32)); + + return (data); +} + +VBEpmi * +VBEGetVBEpmi(vbeInfoPtr pVbe) +{ + VBEpmi *pmi; + + /* + Input: + AH := 4Fh Super VGA support + AL := 0Ah Protected Mode Interface + BL := 00h Return Protected Mode Table + + Output: + AX := Status + ES := Real Mode Segment of Table + DI := Offset of Table + CX := Lenght of Table including protected mode code in bytes (for copying purposes) + (All other registers are preserved) + */ + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f0a; + pVbe->pInt10->bx = 0; + pVbe->pInt10->di = 0; + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return (NULL); + + pmi = malloc(sizeof(VBEpmi)); + pmi->seg_tbl = R16(pVbe->pInt10->es); + pmi->tbl_off = R16(pVbe->pInt10->di); + pmi->tbl_len = R16(pVbe->pInt10->cx); + + return (pmi); +} + +#if 0 +vbeModeInfoPtr +VBEBuildVbeModeList(vbeInfoPtr pVbe, VbeInfoBlock *vbe) +{ + vbeModeInfoPtr ModeList = NULL; + + int i = 0; + while (vbe->VideoModePtr[i] != 0xffff) { + vbeModeInfoPtr m; + VbeModeInfoBlock *mode; + int id = vbe->VideoModePtr[i++]; + int bpp; + + if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) + continue; + + bpp = mode->BitsPerPixel; + + m = xnfcalloc(sizeof(vbeModeInfoRec),1); + m->width = mode->XResolution; + m->height = mode->YResolution; + m->bpp = bpp; + m->n = id; + m->next = ModeList; + + xf86DrvMsgVerb(pVbe->pInt10->scrnIndex, X_PROBED, 3, + "BIOS reported VESA mode 0x%x: x:%i y:%i bpp:%i\n", + m->n, m->width, m->height, m->bpp); + + ModeList = m; + + VBEFreeModeInfo(mode); + } + return ModeList; +} + +unsigned short +VBECalcVbeModeIndex(vbeModeInfoPtr m, DisplayModePtr mode, int bpp) +{ + while (m) { + if (bpp == m->bpp + && mode->HDisplay == m->width + && mode->VDisplay == m->height) + return m->n; + m = m->next; + } + return 0; +} +#endif + +void +VBEVesaSaveRestore(vbeInfoPtr pVbe, vbeSaveRestorePtr vbe_sr, + vbeSaveRestoreFunction function) +{ + Bool SaveSucc = FALSE; + + if (VBE_VERSION_MAJOR(pVbe->version) > 1 + && (function == MODE_SAVE || vbe_sr->pstate)) { + if (function == MODE_RESTORE) + memcpy(vbe_sr->state, vbe_sr->pstate, vbe_sr->stateSize); + ErrorF("VBESaveRestore\n"); + if ((VBESaveRestore(pVbe,function, + (pointer)&vbe_sr->state, + &vbe_sr->stateSize,&vbe_sr->statePage))) { + if (function == MODE_SAVE) { + SaveSucc = TRUE; + vbe_sr->stateMode = -1; /* invalidate */ + /* don't rely on the memory not being touched */ + if (vbe_sr->pstate == NULL) + vbe_sr->pstate = malloc(vbe_sr->stateSize); + memcpy(vbe_sr->pstate, vbe_sr->state, vbe_sr->stateSize); + } + ErrorF("VBESaveRestore done with success\n"); + return; + } + ErrorF("VBESaveRestore done\n"); + } + + if (function == MODE_SAVE && !SaveSucc) + (void)VBEGetVBEMode(pVbe, &vbe_sr->stateMode); + + if (function == MODE_RESTORE && vbe_sr->stateMode != -1) + VBESetVBEMode(pVbe, vbe_sr->stateMode, NULL); + +} + +int +VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int clock) +{ + /* + Input: + AX := 4F0Bh VBE Get Pixel Clock + BL := 00h Get Pixel Clock + ECX := pixel clock in units of Hz + DX := mode number + + Output: + AX := VBE Return Status + ECX := Closest pixel clock + */ + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f0b; + pVbe->pInt10->bx = 0x00; + pVbe->pInt10->cx = clock; + pVbe->pInt10->dx = mode; + xf86ExecX86int10(pVbe->pInt10); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return (0); + + return (pVbe->pInt10->cx); +} + +Bool +VBEDPMSSet(vbeInfoPtr pVbe, int mode) +{ + /* + Input: + AX := 4F10h DPMS + BL := 01h Set Display Power State + BH := requested power state + + Output: + AX := VBE Return Status + */ + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f10; + pVbe->pInt10->bx = 0x01; + switch (mode) { + case DPMSModeOn: + break; + case DPMSModeStandby: + pVbe->pInt10->bx |= 0x100; + break; + case DPMSModeSuspend: + pVbe->pInt10->bx |= 0x200; + break; + case DPMSModeOff: + pVbe->pInt10->bx |= 0x400; + break; + } + xf86ExecX86int10(pVbe->pInt10); + return (R16(pVbe->pInt10->ax) == 0x4f); +} + +void +VBEInterpretPanelID(int scrnIndex, struct vbePanelID *data) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + DisplayModePtr mode; + const float PANEL_HZ = 60.0; + + if (!data) + return; + + xf86DrvMsg(scrnIndex, X_INFO, "PanelID returned panel resolution %dx%d\n", + data->hsize, data->vsize); + + if (pScrn->monitor->nHsync || pScrn->monitor->nVrefresh) + return; + + mode = xf86CVTMode(data->hsize, data->vsize, PANEL_HZ, 1, 0); + + pScrn->monitor->nHsync = 1; + pScrn->monitor->hsync[0].lo = 31.5; + pScrn->monitor->hsync[0].hi = (float)mode->Clock / (float)mode->HTotal; + pScrn->monitor->nVrefresh = 1; + pScrn->monitor->vrefresh[0].lo = 56.0; + pScrn->monitor->vrefresh[0].hi = + (float)mode->Clock*1000.0 / (float)mode->HTotal / (float)mode->VTotal; + + free(mode); +} + +struct vbePanelID * +VBEReadPanelID(vbeInfoPtr pVbe) +{ + int RealOff = pVbe->real_mode_base; + pointer page = pVbe->memory; + void *tmp = NULL; + int screen = pVbe->pInt10->scrnIndex; + + pVbe->pInt10->ax = 0x4F11; + pVbe->pInt10->bx = 0x01; + pVbe->pInt10->cx = 0; + pVbe->pInt10->dx = 0; + pVbe->pInt10->es = SEG_ADDR(RealOff); + pVbe->pInt10->di = SEG_OFF(RealOff); + pVbe->pInt10->num = 0x10; + + xf86ExecX86int10(pVbe->pInt10); + + if ((pVbe->pInt10->ax & 0xff) != 0x4f) { + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID invalid\n"); + goto error; + } + + switch (pVbe->pInt10->ax & 0xff00) { + case 0x0: + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read successfully\n"); + tmp = xnfalloc(32); + memcpy(tmp, page, 32); + break; + case 0x100: + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read failed\n"); + break; + default: + xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID unknown failure %i\n", + pVbe->pInt10->ax & 0xff00); + break; + } + +error: + return tmp; +} diff --git a/xorg-server/hw/xfree86/vbe/vbe.h b/xorg-server/hw/xfree86/vbe/vbe.h index b1ec5a9fb..4786709ea 100644 --- a/xorg-server/hw/xfree86/vbe/vbe.h +++ b/xorg-server/hw/xfree86/vbe/vbe.h @@ -1,341 +1,341 @@ - -/* - * XFree86 vbe module - * Copyright 2000 Egbert Eich - * - * The mode query/save/set/restore functions from the vesa driver - * have been moved here. - * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com) - * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br> - */ - -#ifndef _VBE_H -#define _VBE_H -#include "xf86int10.h" -#include "xf86DDC.h" - -typedef enum { - DDC_UNCHECKED, - DDC_NONE, - DDC_1, - DDC_2, - DDC_1_2 -} -ddc_lvl; - -typedef struct { - xf86Int10InfoPtr pInt10; - int version; - pointer memory; - int real_mode_base; - int num_pages; - Bool init_int10; - ddc_lvl ddc; - Bool ddc_blank; -} vbeInfoRec, *vbeInfoPtr; - -#define VBE_VERSION_MAJOR(x) *((CARD8*)(&x) + 1) -#define VBE_VERSION_MINOR(x) (CARD8)(x) - -extern _X_EXPORT vbeInfoPtr VBEInit(xf86Int10InfoPtr pInt, int entityIndex); -extern _X_EXPORT vbeInfoPtr VBEExtendedInit(xf86Int10InfoPtr pInt, int entityIndex, int Flags); -extern _X_EXPORT void vbeFree(vbeInfoPtr pVbe); -extern _X_EXPORT xf86MonPtr vbeDoEDID(vbeInfoPtr pVbe, pointer pDDCModule); - -#pragma pack(1) - -typedef struct vbeControllerInfoBlock { - CARD8 VbeSignature[4]; - CARD16 VbeVersion; - CARD32 OemStringPtr; - CARD8 Capabilities[4]; - CARD32 VideoModePtr; - CARD16 TotalMem; - CARD16 OemSoftwareRev; - CARD32 OemVendorNamePtr; - CARD32 OemProductNamePtr; - CARD32 OemProductRevPtr; - CARD8 Scratch[222]; - CARD8 OemData[256]; -} vbeControllerInfoRec, *vbeControllerInfoPtr; - -#if defined(__GNUC__) || defined(__USLC__) || defined(__SUNPRO_C) -#pragma pack() /* All GCC versions recognise this syntax */ -#else -#pragma pack(0) -#endif - -#ifndef __GNUC__ -#define __attribute__(a) -#endif - -typedef struct _VbeInfoBlock VbeInfoBlock; -typedef struct _VbeModeInfoBlock VbeModeInfoBlock; -typedef struct _VbeCRTCInfoBlock VbeCRTCInfoBlock; - -/* - * INT 0 - */ - -struct _VbeInfoBlock { - /* VESA 1.2 fields */ - CARD8 VESASignature[4]; /* VESA */ - CARD16 VESAVersion; /* Higher byte major, lower byte minor */ - /*CARD32*/char *OEMStringPtr; /* Pointer to OEM string */ - CARD8 Capabilities[4]; /* Capabilities of the video environment */ - - /*CARD32*/CARD16 *VideoModePtr; /* pointer to supported Super VGA modes */ - - CARD16 TotalMemory; /* Number of 64kb memory blocks on board */ - /* if not VESA 2, 236 scratch bytes follow (256 bytes total size) */ - - /* VESA 2 fields */ - CARD16 OemSoftwareRev; /* VBE implementation Software revision */ - /*CARD32*/char *OemVendorNamePtr; /* Pointer to Vendor Name String */ - /*CARD32*/char *OemProductNamePtr; /* Pointer to Product Name String */ - /*CARD32*/char *OemProductRevPtr; /* Pointer to Product Revision String */ - CARD8 Reserved[222]; /* Reserved for VBE implementation */ - CARD8 OemData[256]; /* Data Area for OEM Strings */ -} __attribute__((packed)); - -/* Return Super VGA Information */ -extern _X_EXPORT VbeInfoBlock *VBEGetVBEInfo(vbeInfoPtr pVbe); -extern _X_EXPORT void VBEFreeVBEInfo(VbeInfoBlock *block); - -/* - * INT 1 - */ - -struct _VbeModeInfoBlock { - CARD16 ModeAttributes; /* mode attributes */ - CARD8 WinAAttributes; /* window A attributes */ - CARD8 WinBAttributes; /* window B attributes */ - CARD16 WinGranularity; /* window granularity */ - CARD16 WinSize; /* window size */ - CARD16 WinASegment; /* window A start segment */ - CARD16 WinBSegment; /* window B start segment */ - CARD32 WinFuncPtr; /* real mode pointer to window function */ - CARD16 BytesPerScanline; /* bytes per scanline */ - - /* Mandatory information for VBE 1.2 and above */ - CARD16 XResolution; /* horizontal resolution in pixels or characters */ - CARD16 YResolution; /* vertical resolution in pixels or characters */ - CARD8 XCharSize; /* character cell width in pixels */ - CARD8 YCharSize; /* character cell height in pixels */ - CARD8 NumberOfPlanes; /* number of memory planes */ - CARD8 BitsPerPixel; /* bits per pixel */ - CARD8 NumberOfBanks; /* number of banks */ - CARD8 MemoryModel; /* memory model type */ - CARD8 BankSize; /* bank size in KB */ - CARD8 NumberOfImages; /* number of images */ - CARD8 Reserved; /* 1 */ /* reserved for page function */ - - /* Direct color fields (required for direct/6 and YUV/7 memory models) */ - CARD8 RedMaskSize; /* size of direct color red mask in bits */ - CARD8 RedFieldPosition; /* bit position of lsb of red mask */ - CARD8 GreenMaskSize; /* size of direct color green mask in bits */ - CARD8 GreenFieldPosition; /* bit position of lsb of green mask */ - CARD8 BlueMaskSize; /* size of direct color blue mask in bits */ - CARD8 BlueFieldPosition; /* bit position of lsb of blue mask */ - CARD8 RsvdMaskSize; /* size of direct color reserved mask in bits */ - CARD8 RsvdFieldPosition; /* bit position of lsb of reserved mask */ - CARD8 DirectColorModeInfo; /* direct color mode attributes */ - - /* Mandatory information for VBE 2.0 and above */ - CARD32 PhysBasePtr; /* physical address for flat memory frame buffer */ - CARD32 Reserved32; /* 0 */ /* Reserved - always set to 0 */ - CARD16 Reserved16; /* 0 */ /* Reserved - always set to 0 */ - - /* Mandatory information for VBE 3.0 and above */ - CARD16 LinBytesPerScanLine; /* bytes per scan line for linear modes */ - CARD8 BnkNumberOfImagePages; /* number of images for banked modes */ - CARD8 LinNumberOfImagePages; /* number of images for linear modes */ - CARD8 LinRedMaskSize; /* size of direct color red mask (linear modes) */ - CARD8 LinRedFieldPosition; /* bit position of lsb of red mask (linear modes) */ - CARD8 LinGreenMaskSize; /* size of direct color green mask (linear modes) */ - CARD8 LinGreenFieldPosition; /* bit position of lsb of green mask (linear modes) */ - CARD8 LinBlueMaskSize; /* size of direct color blue mask (linear modes) */ - CARD8 LinBlueFieldPosition; /* bit position of lsb of blue mask (linear modes) */ - CARD8 LinRsvdMaskSize; /* size of direct color reserved mask (linear modes) */ - CARD8 LinRsvdFieldPosition; /* bit position of lsb of reserved mask (linear modes) */ - CARD32 MaxPixelClock; /* maximum pixel clock (in Hz) for graphics mode */ - CARD8 Reserved2[189]; /* remainder of VbeModeInfoBlock */ -} __attribute__((packed)); - -/* Return VBE Mode Information */ -extern _X_EXPORT VbeModeInfoBlock *VBEGetModeInfo(vbeInfoPtr pVbe, int mode); -extern _X_EXPORT void VBEFreeModeInfo(VbeModeInfoBlock *block); - -/* - * INT2 - */ - -#define CRTC_DBLSCAN (1<<0) -#define CRTC_INTERLACE (1<<1) -#define CRTC_NHSYNC (1<<2) -#define CRTC_NVSYNC (1<<3) - -struct _VbeCRTCInfoBlock { - CARD16 HorizontalTotal; /* Horizontal total in pixels */ - CARD16 HorizontalSyncStart; /* Horizontal sync start in pixels */ - CARD16 HorizontalSyncEnd; /* Horizontal sync end in pixels */ - CARD16 VerticalTotal; /* Vertical total in lines */ - CARD16 VerticalSyncStart; /* Vertical sync start in lines */ - CARD16 VerticalSyncEnd; /* Vertical sync end in lines */ - CARD8 Flags; /* Flags (Interlaced, Double Scan etc) */ - CARD32 PixelClock; /* Pixel clock in units of Hz */ - CARD16 RefreshRate; /* Refresh rate in units of 0.01 Hz */ - CARD8 Reserved[40]; /* remainder of ModeInfoBlock */ -} __attribute__((packed)); -/* VbeCRTCInfoBlock is in the VESA 3.0 specs */ - -extern _X_EXPORT Bool VBESetVBEMode(vbeInfoPtr pVbe, int mode, VbeCRTCInfoBlock *crtc); - -/* - * INT 3 - */ - -extern _X_EXPORT Bool VBEGetVBEMode(vbeInfoPtr pVbe, int *mode); - -/* - * INT 4 - */ - -/* Save/Restore Super VGA video state */ -/* function values are (values stored in VESAPtr): - * 0 := query & allocate amount of memory to save state - * 1 := save state - * 2 := restore state - * - * function 0 called automatically if function 1 called without - * a previous call to function 0. - */ - -typedef enum { - MODE_QUERY, - MODE_SAVE, - MODE_RESTORE -} vbeSaveRestoreFunction; - -extern _X_EXPORT Bool -VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction fuction, - pointer *memory, int *size, int *real_mode_pages); - -/* - * INT 5 - */ - -extern _X_EXPORT Bool -VBEBankSwitch(vbeInfoPtr pVbe, unsigned int iBank, int window); - -/* - * INT 6 - */ - -typedef enum { - SCANWID_SET, - SCANWID_GET, - SCANWID_SET_BYTES, - SCANWID_GET_MAX -} vbeScanwidthCommand; - -#define VBESetLogicalScanline(pVbe, width) \ - VBESetGetLogicalScanlineLength(pVbe, SCANWID_SET, width, \ - NULL, NULL, NULL) -#define VBESetLogicalScanlineBytes(pVbe, width) \ - VBESetGetLogicalScanlineLength(pVbe, SCANWID_SET_BYTES, width, \ - NULL, NULL, NULL) -#define VBEGetLogicalScanline(pVbe, pixels, bytes, max) \ - VBESetGetLogicalScanlineLength(pVbe, SCANWID_GET, 0, \ - pixels, bytes, max) -#define VBEGetMaxLogicalScanline(pVbe, pixels, bytes, max) \ - VBESetGetLogicalScanlineLength(pVbe, SCANWID_GET_MAX, 0, \ - pixels, bytes, max) -extern _X_EXPORT Bool VBESetGetLogicalScanlineLength(vbeInfoPtr pVbe, - vbeScanwidthCommand command, int width, - int *pixels, int *bytes, int *max); - -/* - * INT 7 - */ - -/* 16 bit code */ -extern _X_EXPORT Bool VBESetDisplayStart(vbeInfoPtr pVbe, int x, int y, Bool wait_retrace); -extern _X_EXPORT Bool VBEGetDisplayStart(vbeInfoPtr pVbe, int *x, int *y); - -/* - * INT 8 - */ - -/* if bits is 0, then it is a GET */ -extern _X_EXPORT int VBESetGetDACPaletteFormat(vbeInfoPtr pVbe, int bits); - -/* - * INT 9 - */ - -/* - * If getting a palette, the data argument is not used. It will return - * the data. - * If setting a palette, it will return the pointer received on success, - * NULL on failure. - */ -extern _X_EXPORT CARD32 *VBESetGetPaletteData(vbeInfoPtr pVbe, Bool set, int first, int num, - CARD32 *data, Bool secondary, Bool wait_retrace); -#define VBEFreePaletteData(data) xfree(data) - -/* - * INT A - */ - -typedef struct _VBEpmi { - int seg_tbl; - int tbl_off; - int tbl_len; -} VBEpmi; - -extern _X_EXPORT VBEpmi *VBEGetVBEpmi(vbeInfoPtr pVbe); -#define VESAFreeVBEpmi(pmi) xfree(pmi) - -/* high level helper functions */ - -typedef struct _vbeModeInfoRec { - int width; - int height; - int bpp; - int n; - struct _vbeModeInfoRec *next; -} vbeModeInfoRec, *vbeModeInfoPtr; - -typedef struct { - CARD8 *state; - CARD8 *pstate; - int statePage; - int stateSize; - int stateMode; -} vbeSaveRestoreRec, *vbeSaveRestorePtr; - -extern _X_EXPORT void -VBEVesaSaveRestore(vbeInfoPtr pVbe, vbeSaveRestorePtr vbe_sr, - vbeSaveRestoreFunction function); - -extern _X_EXPORT int VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int Clock); -extern _X_EXPORT Bool VBEDPMSSet(vbeInfoPtr pVbe, int mode); - -struct vbePanelID { - short hsize; - short vsize; - short fptype; - char redbpp; - char greenbpp; - char bluebpp; - char reservedbpp; - int reserved_offscreen_mem_size; - int reserved_offscreen_mem_pointer; - char reserved[14]; -}; - -extern _X_EXPORT void VBEInterpretPanelID(int scrnIndex, struct vbePanelID *data); -extern _X_EXPORT struct vbePanelID *VBEReadPanelID(vbeInfoPtr pVbe); - -#endif + +/* + * XFree86 vbe module + * Copyright 2000 Egbert Eich + * + * The mode query/save/set/restore functions from the vesa driver + * have been moved here. + * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com) + * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br> + */ + +#ifndef _VBE_H +#define _VBE_H +#include "xf86int10.h" +#include "xf86DDC.h" + +typedef enum { + DDC_UNCHECKED, + DDC_NONE, + DDC_1, + DDC_2, + DDC_1_2 +} +ddc_lvl; + +typedef struct { + xf86Int10InfoPtr pInt10; + int version; + pointer memory; + int real_mode_base; + int num_pages; + Bool init_int10; + ddc_lvl ddc; + Bool ddc_blank; +} vbeInfoRec, *vbeInfoPtr; + +#define VBE_VERSION_MAJOR(x) *((CARD8*)(&x) + 1) +#define VBE_VERSION_MINOR(x) (CARD8)(x) + +extern _X_EXPORT vbeInfoPtr VBEInit(xf86Int10InfoPtr pInt, int entityIndex); +extern _X_EXPORT vbeInfoPtr VBEExtendedInit(xf86Int10InfoPtr pInt, int entityIndex, int Flags); +extern _X_EXPORT void vbeFree(vbeInfoPtr pVbe); +extern _X_EXPORT xf86MonPtr vbeDoEDID(vbeInfoPtr pVbe, pointer pDDCModule); + +#pragma pack(1) + +typedef struct vbeControllerInfoBlock { + CARD8 VbeSignature[4]; + CARD16 VbeVersion; + CARD32 OemStringPtr; + CARD8 Capabilities[4]; + CARD32 VideoModePtr; + CARD16 TotalMem; + CARD16 OemSoftwareRev; + CARD32 OemVendorNamePtr; + CARD32 OemProductNamePtr; + CARD32 OemProductRevPtr; + CARD8 Scratch[222]; + CARD8 OemData[256]; +} vbeControllerInfoRec, *vbeControllerInfoPtr; + +#if defined(__GNUC__) || defined(__USLC__) || defined(__SUNPRO_C) +#pragma pack() /* All GCC versions recognise this syntax */ +#else +#pragma pack(0) +#endif + +#ifndef __GNUC__ +#define __attribute__(a) +#endif + +typedef struct _VbeInfoBlock VbeInfoBlock; +typedef struct _VbeModeInfoBlock VbeModeInfoBlock; +typedef struct _VbeCRTCInfoBlock VbeCRTCInfoBlock; + +/* + * INT 0 + */ + +struct _VbeInfoBlock { + /* VESA 1.2 fields */ + CARD8 VESASignature[4]; /* VESA */ + CARD16 VESAVersion; /* Higher byte major, lower byte minor */ + /*CARD32*/char *OEMStringPtr; /* Pointer to OEM string */ + CARD8 Capabilities[4]; /* Capabilities of the video environment */ + + /*CARD32*/CARD16 *VideoModePtr; /* pointer to supported Super VGA modes */ + + CARD16 TotalMemory; /* Number of 64kb memory blocks on board */ + /* if not VESA 2, 236 scratch bytes follow (256 bytes total size) */ + + /* VESA 2 fields */ + CARD16 OemSoftwareRev; /* VBE implementation Software revision */ + /*CARD32*/char *OemVendorNamePtr; /* Pointer to Vendor Name String */ + /*CARD32*/char *OemProductNamePtr; /* Pointer to Product Name String */ + /*CARD32*/char *OemProductRevPtr; /* Pointer to Product Revision String */ + CARD8 Reserved[222]; /* Reserved for VBE implementation */ + CARD8 OemData[256]; /* Data Area for OEM Strings */ +} __attribute__((packed)); + +/* Return Super VGA Information */ +extern _X_EXPORT VbeInfoBlock *VBEGetVBEInfo(vbeInfoPtr pVbe); +extern _X_EXPORT void VBEFreeVBEInfo(VbeInfoBlock *block); + +/* + * INT 1 + */ + +struct _VbeModeInfoBlock { + CARD16 ModeAttributes; /* mode attributes */ + CARD8 WinAAttributes; /* window A attributes */ + CARD8 WinBAttributes; /* window B attributes */ + CARD16 WinGranularity; /* window granularity */ + CARD16 WinSize; /* window size */ + CARD16 WinASegment; /* window A start segment */ + CARD16 WinBSegment; /* window B start segment */ + CARD32 WinFuncPtr; /* real mode pointer to window function */ + CARD16 BytesPerScanline; /* bytes per scanline */ + + /* Mandatory information for VBE 1.2 and above */ + CARD16 XResolution; /* horizontal resolution in pixels or characters */ + CARD16 YResolution; /* vertical resolution in pixels or characters */ + CARD8 XCharSize; /* character cell width in pixels */ + CARD8 YCharSize; /* character cell height in pixels */ + CARD8 NumberOfPlanes; /* number of memory planes */ + CARD8 BitsPerPixel; /* bits per pixel */ + CARD8 NumberOfBanks; /* number of banks */ + CARD8 MemoryModel; /* memory model type */ + CARD8 BankSize; /* bank size in KB */ + CARD8 NumberOfImages; /* number of images */ + CARD8 Reserved; /* 1 */ /* reserved for page function */ + + /* Direct color fields (required for direct/6 and YUV/7 memory models) */ + CARD8 RedMaskSize; /* size of direct color red mask in bits */ + CARD8 RedFieldPosition; /* bit position of lsb of red mask */ + CARD8 GreenMaskSize; /* size of direct color green mask in bits */ + CARD8 GreenFieldPosition; /* bit position of lsb of green mask */ + CARD8 BlueMaskSize; /* size of direct color blue mask in bits */ + CARD8 BlueFieldPosition; /* bit position of lsb of blue mask */ + CARD8 RsvdMaskSize; /* size of direct color reserved mask in bits */ + CARD8 RsvdFieldPosition; /* bit position of lsb of reserved mask */ + CARD8 DirectColorModeInfo; /* direct color mode attributes */ + + /* Mandatory information for VBE 2.0 and above */ + CARD32 PhysBasePtr; /* physical address for flat memory frame buffer */ + CARD32 Reserved32; /* 0 */ /* Reserved - always set to 0 */ + CARD16 Reserved16; /* 0 */ /* Reserved - always set to 0 */ + + /* Mandatory information for VBE 3.0 and above */ + CARD16 LinBytesPerScanLine; /* bytes per scan line for linear modes */ + CARD8 BnkNumberOfImagePages; /* number of images for banked modes */ + CARD8 LinNumberOfImagePages; /* number of images for linear modes */ + CARD8 LinRedMaskSize; /* size of direct color red mask (linear modes) */ + CARD8 LinRedFieldPosition; /* bit position of lsb of red mask (linear modes) */ + CARD8 LinGreenMaskSize; /* size of direct color green mask (linear modes) */ + CARD8 LinGreenFieldPosition; /* bit position of lsb of green mask (linear modes) */ + CARD8 LinBlueMaskSize; /* size of direct color blue mask (linear modes) */ + CARD8 LinBlueFieldPosition; /* bit position of lsb of blue mask (linear modes) */ + CARD8 LinRsvdMaskSize; /* size of direct color reserved mask (linear modes) */ + CARD8 LinRsvdFieldPosition; /* bit position of lsb of reserved mask (linear modes) */ + CARD32 MaxPixelClock; /* maximum pixel clock (in Hz) for graphics mode */ + CARD8 Reserved2[189]; /* remainder of VbeModeInfoBlock */ +} __attribute__((packed)); + +/* Return VBE Mode Information */ +extern _X_EXPORT VbeModeInfoBlock *VBEGetModeInfo(vbeInfoPtr pVbe, int mode); +extern _X_EXPORT void VBEFreeModeInfo(VbeModeInfoBlock *block); + +/* + * INT2 + */ + +#define CRTC_DBLSCAN (1<<0) +#define CRTC_INTERLACE (1<<1) +#define CRTC_NHSYNC (1<<2) +#define CRTC_NVSYNC (1<<3) + +struct _VbeCRTCInfoBlock { + CARD16 HorizontalTotal; /* Horizontal total in pixels */ + CARD16 HorizontalSyncStart; /* Horizontal sync start in pixels */ + CARD16 HorizontalSyncEnd; /* Horizontal sync end in pixels */ + CARD16 VerticalTotal; /* Vertical total in lines */ + CARD16 VerticalSyncStart; /* Vertical sync start in lines */ + CARD16 VerticalSyncEnd; /* Vertical sync end in lines */ + CARD8 Flags; /* Flags (Interlaced, Double Scan etc) */ + CARD32 PixelClock; /* Pixel clock in units of Hz */ + CARD16 RefreshRate; /* Refresh rate in units of 0.01 Hz */ + CARD8 Reserved[40]; /* remainder of ModeInfoBlock */ +} __attribute__((packed)); +/* VbeCRTCInfoBlock is in the VESA 3.0 specs */ + +extern _X_EXPORT Bool VBESetVBEMode(vbeInfoPtr pVbe, int mode, VbeCRTCInfoBlock *crtc); + +/* + * INT 3 + */ + +extern _X_EXPORT Bool VBEGetVBEMode(vbeInfoPtr pVbe, int *mode); + +/* + * INT 4 + */ + +/* Save/Restore Super VGA video state */ +/* function values are (values stored in VESAPtr): + * 0 := query & allocate amount of memory to save state + * 1 := save state + * 2 := restore state + * + * function 0 called automatically if function 1 called without + * a previous call to function 0. + */ + +typedef enum { + MODE_QUERY, + MODE_SAVE, + MODE_RESTORE +} vbeSaveRestoreFunction; + +extern _X_EXPORT Bool +VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction fuction, + pointer *memory, int *size, int *real_mode_pages); + +/* + * INT 5 + */ + +extern _X_EXPORT Bool +VBEBankSwitch(vbeInfoPtr pVbe, unsigned int iBank, int window); + +/* + * INT 6 + */ + +typedef enum { + SCANWID_SET, + SCANWID_GET, + SCANWID_SET_BYTES, + SCANWID_GET_MAX +} vbeScanwidthCommand; + +#define VBESetLogicalScanline(pVbe, width) \ + VBESetGetLogicalScanlineLength(pVbe, SCANWID_SET, width, \ + NULL, NULL, NULL) +#define VBESetLogicalScanlineBytes(pVbe, width) \ + VBESetGetLogicalScanlineLength(pVbe, SCANWID_SET_BYTES, width, \ + NULL, NULL, NULL) +#define VBEGetLogicalScanline(pVbe, pixels, bytes, max) \ + VBESetGetLogicalScanlineLength(pVbe, SCANWID_GET, 0, \ + pixels, bytes, max) +#define VBEGetMaxLogicalScanline(pVbe, pixels, bytes, max) \ + VBESetGetLogicalScanlineLength(pVbe, SCANWID_GET_MAX, 0, \ + pixels, bytes, max) +extern _X_EXPORT Bool VBESetGetLogicalScanlineLength(vbeInfoPtr pVbe, + vbeScanwidthCommand command, int width, + int *pixels, int *bytes, int *max); + +/* + * INT 7 + */ + +/* 16 bit code */ +extern _X_EXPORT Bool VBESetDisplayStart(vbeInfoPtr pVbe, int x, int y, Bool wait_retrace); +extern _X_EXPORT Bool VBEGetDisplayStart(vbeInfoPtr pVbe, int *x, int *y); + +/* + * INT 8 + */ + +/* if bits is 0, then it is a GET */ +extern _X_EXPORT int VBESetGetDACPaletteFormat(vbeInfoPtr pVbe, int bits); + +/* + * INT 9 + */ + +/* + * If getting a palette, the data argument is not used. It will return + * the data. + * If setting a palette, it will return the pointer received on success, + * NULL on failure. + */ +extern _X_EXPORT CARD32 *VBESetGetPaletteData(vbeInfoPtr pVbe, Bool set, int first, int num, + CARD32 *data, Bool secondary, Bool wait_retrace); +#define VBEFreePaletteData(data) free(data) + +/* + * INT A + */ + +typedef struct _VBEpmi { + int seg_tbl; + int tbl_off; + int tbl_len; +} VBEpmi; + +extern _X_EXPORT VBEpmi *VBEGetVBEpmi(vbeInfoPtr pVbe); +#define VESAFreeVBEpmi(pmi) free(pmi) + +/* high level helper functions */ + +typedef struct _vbeModeInfoRec { + int width; + int height; + int bpp; + int n; + struct _vbeModeInfoRec *next; +} vbeModeInfoRec, *vbeModeInfoPtr; + +typedef struct { + CARD8 *state; + CARD8 *pstate; + int statePage; + int stateSize; + int stateMode; +} vbeSaveRestoreRec, *vbeSaveRestorePtr; + +extern _X_EXPORT void +VBEVesaSaveRestore(vbeInfoPtr pVbe, vbeSaveRestorePtr vbe_sr, + vbeSaveRestoreFunction function); + +extern _X_EXPORT int VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int Clock); +extern _X_EXPORT Bool VBEDPMSSet(vbeInfoPtr pVbe, int mode); + +struct vbePanelID { + short hsize; + short vsize; + short fptype; + char redbpp; + char greenbpp; + char bluebpp; + char reservedbpp; + int reserved_offscreen_mem_size; + int reserved_offscreen_mem_pointer; + char reserved[14]; +}; + +extern _X_EXPORT void VBEInterpretPanelID(int scrnIndex, struct vbePanelID *data); +extern _X_EXPORT struct vbePanelID *VBEReadPanelID(vbeInfoPtr pVbe); + +#endif diff --git a/xorg-server/hw/xfree86/vbe/vbeModes.c b/xorg-server/hw/xfree86/vbe/vbeModes.c index 1a4d2407c..5b69b0096 100644 --- a/xorg-server/hw/xfree86/vbe/vbeModes.c +++ b/xorg-server/hw/xfree86/vbe/vbeModes.c @@ -1,451 +1,451 @@ -#define DEBUG_VERB 2 -/* - * Copyright © 2002 David Dawes - * - * 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 AUTHOR(S) 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 author(s) 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 author(s). - * - * Authors: David Dawes <dawes@xfree86.org> - * - */ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <stdio.h> -#include <string.h> - -#include "xf86.h" -#include "vbe.h" -#include "vbeModes.h" - -static int -GetDepthFlag(vbeInfoPtr pVbe, int id) -{ - VbeModeInfoBlock *mode; - int bpp; - - if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) - return 0; - - if (VBE_MODE_USABLE(mode, 0)) { - int depth; - - if (VBE_MODE_COLOR(mode)) { - depth = mode->RedMaskSize + mode->GreenMaskSize + - mode->BlueMaskSize; - } else { - depth = 1; - } - bpp = mode->BitsPerPixel; - VBEFreeModeInfo(mode); - mode = NULL; - switch (depth) { - case 1: - return V_DEPTH_1; - case 4: - return V_DEPTH_4; - case 8: - return V_DEPTH_8; - case 15: - return V_DEPTH_15; - case 16: - return V_DEPTH_16; - case 24: - switch (bpp) { - case 24: - return V_DEPTH_24_24; - case 32: - return V_DEPTH_24_32; - } - } - } - if (mode) - VBEFreeModeInfo(mode); - return 0; -} - -/* - * Find supported mode depths. - */ -int -VBEFindSupportedDepths(vbeInfoPtr pVbe, VbeInfoBlock *vbe, int *flags24, - int modeTypes) -{ - int i = 0; - int depths = 0; - - if (modeTypes & V_MODETYPE_VBE) { - while (vbe->VideoModePtr[i] != 0xffff) { - depths |= GetDepthFlag(pVbe, vbe->VideoModePtr[i++]); - } - } - - /* - * XXX This possibly only works with VBE 3.0 and later. - */ - if (modeTypes & V_MODETYPE_VGA) { - for (i = 0; i < 0x7F; i++) { - depths |= GetDepthFlag(pVbe, i); - } - } - - if (flags24) { - if (depths & V_DEPTH_24_24) - *flags24 |= Support24bppFb; - if (depths & V_DEPTH_24_32) - *flags24 |= Support32bppFb; - } - - return depths; -} - -static DisplayModePtr -CheckMode(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe, int id, - int flags) -{ - CARD16 major; - VbeModeInfoBlock *mode; - DisplayModePtr pMode; - VbeModeInfoData *data; - Bool modeOK = FALSE; - - major = (unsigned)(vbe->VESAVersion >> 8); - - if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) - return NULL; - - /* Does the mode match the depth/bpp? */ - /* Some BIOS's set BitsPerPixel to 15 instead of 16 for 15/16 */ - if (VBE_MODE_USABLE(mode, flags) && - ((pScrn->bitsPerPixel == 1 && !VBE_MODE_COLOR(mode)) || - (mode->BitsPerPixel > 8 && - (mode->RedMaskSize + mode->GreenMaskSize + - mode->BlueMaskSize) == pScrn->depth && - mode->BitsPerPixel == pScrn->bitsPerPixel) || - (mode->BitsPerPixel == 15 && pScrn->depth == 15) || - (mode->BitsPerPixel <= 8 && - mode->BitsPerPixel == pScrn->bitsPerPixel))) { - modeOK = TRUE; - xf86ErrorFVerb(DEBUG_VERB, "*"); - } - - xf86ErrorFVerb(DEBUG_VERB, - "Mode: %x (%dx%d)\n", id, mode->XResolution, mode->YResolution); - xf86ErrorFVerb(DEBUG_VERB, - " ModeAttributes: 0x%x\n", mode->ModeAttributes); - xf86ErrorFVerb(DEBUG_VERB, - " WinAAttributes: 0x%x\n", mode->WinAAttributes); - xf86ErrorFVerb(DEBUG_VERB, - " WinBAttributes: 0x%x\n", mode->WinBAttributes); - xf86ErrorFVerb(DEBUG_VERB, - " WinGranularity: %d\n", mode->WinGranularity); - xf86ErrorFVerb(DEBUG_VERB, - " WinSize: %d\n", mode->WinSize); - xf86ErrorFVerb(DEBUG_VERB, - " WinASegment: 0x%x\n", mode->WinASegment); - xf86ErrorFVerb(DEBUG_VERB, - " WinBSegment: 0x%x\n", mode->WinBSegment); - xf86ErrorFVerb(DEBUG_VERB, - " WinFuncPtr: 0x%lx\n", (unsigned long)mode->WinFuncPtr); - xf86ErrorFVerb(DEBUG_VERB, - " BytesPerScanline: %d\n", mode->BytesPerScanline); - xf86ErrorFVerb(DEBUG_VERB, - " XResolution: %d\n", mode->XResolution); - xf86ErrorFVerb(DEBUG_VERB, - " YResolution: %d\n", mode->YResolution); - xf86ErrorFVerb(DEBUG_VERB, - " XCharSize: %d\n", mode->XCharSize); - xf86ErrorFVerb(DEBUG_VERB, - " YCharSize: %d\n", mode->YCharSize); - xf86ErrorFVerb(DEBUG_VERB, - " NumberOfPlanes: %d\n", mode->NumberOfPlanes); - xf86ErrorFVerb(DEBUG_VERB, - " BitsPerPixel: %d\n", mode->BitsPerPixel); - xf86ErrorFVerb(DEBUG_VERB, - " NumberOfBanks: %d\n", mode->NumberOfBanks); - xf86ErrorFVerb(DEBUG_VERB, - " MemoryModel: %d\n", mode->MemoryModel); - xf86ErrorFVerb(DEBUG_VERB, - " BankSize: %d\n", mode->BankSize); - xf86ErrorFVerb(DEBUG_VERB, - " NumberOfImages: %d\n", mode->NumberOfImages); - xf86ErrorFVerb(DEBUG_VERB, - " RedMaskSize: %d\n", mode->RedMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " RedFieldPosition: %d\n", mode->RedFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " GreenMaskSize: %d\n", mode->GreenMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " GreenFieldPosition: %d\n", mode->GreenFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " BlueMaskSize: %d\n", mode->BlueMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " BlueFieldPosition: %d\n", mode->BlueFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " RsvdMaskSize: %d\n", mode->RsvdMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " RsvdFieldPosition: %d\n", mode->RsvdFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " DirectColorModeInfo: %d\n", mode->DirectColorModeInfo); - if (major >= 2) { - xf86ErrorFVerb(DEBUG_VERB, - " PhysBasePtr: 0x%lx\n", - (unsigned long)mode->PhysBasePtr); - if (major >= 3) { - xf86ErrorFVerb(DEBUG_VERB, - " LinBytesPerScanLine: %d\n", mode->LinBytesPerScanLine); - xf86ErrorFVerb(DEBUG_VERB, - " BnkNumberOfImagePages: %d\n", mode->BnkNumberOfImagePages); - xf86ErrorFVerb(DEBUG_VERB, - " LinNumberOfImagePages: %d\n", mode->LinNumberOfImagePages); - xf86ErrorFVerb(DEBUG_VERB, - " LinRedMaskSize: %d\n", mode->LinRedMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " LinRedFieldPosition: %d\n", mode->LinRedFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " LinGreenMaskSize: %d\n", mode->LinGreenMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " LinGreenFieldPosition: %d\n", mode->LinGreenFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " LinBlueMaskSize: %d\n", mode->LinBlueMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " LinBlueFieldPosition: %d\n", mode->LinBlueFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " LinRsvdMaskSize: %d\n", mode->LinRsvdMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " LinRsvdFieldPosition: %d\n", mode->LinRsvdFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " MaxPixelClock: %ld\n", (unsigned long)mode->MaxPixelClock); - } - } - - if (!modeOK) { - VBEFreeModeInfo(mode); - return NULL; - } - pMode = xnfcalloc(sizeof(DisplayModeRec), 1); - - pMode->status = MODE_OK; - pMode->type = M_T_BUILTIN; - - /* for adjust frame */ - pMode->HDisplay = mode->XResolution; - pMode->VDisplay = mode->YResolution; - - data = xnfcalloc(sizeof(VbeModeInfoData), 1); - data->mode = id; - data->data = mode; - pMode->PrivSize = sizeof(VbeModeInfoData); - pMode->Private = (INT32*)data; - pMode->next = NULL; - return pMode; -} - -/* - * Check the available BIOS modes, and extract those that match the - * requirements into the modePool. Note: modePool is a NULL-terminated - * list. - */ - -DisplayModePtr -VBEGetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe, - int modeTypes) -{ - DisplayModePtr pMode, p = NULL, modePool = NULL; - int i = 0; - - if (modeTypes & V_MODETYPE_VBE) { - while (vbe->VideoModePtr[i] != 0xffff) { - int id = vbe->VideoModePtr[i++]; - - if ((pMode = CheckMode(pScrn, pVbe, vbe, id, modeTypes)) != NULL) { - ModeStatus status = MODE_OK; - - /* Check the mode against a specified virtual size (if any) */ - if (pScrn->display->virtualX > 0 && - pMode->HDisplay > pScrn->display->virtualX) { - status = MODE_VIRTUAL_X; - } - if (pScrn->display->virtualY > 0 && - pMode->VDisplay > pScrn->display->virtualY) { - status = MODE_VIRTUAL_Y; - } - if (status != MODE_OK) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Not using mode \"%dx%d\" (%s)\n", - pMode->HDisplay, pMode->VDisplay, - xf86ModeStatusToString(status)); - } else { - if (p == NULL) { - modePool = pMode; - } else { - p->next = pMode; - } - pMode->prev = NULL; - p = pMode; - } - } - } - } - if (modeTypes & V_MODETYPE_VGA) { - for (i = 0; i < 0x7F; i++) { - if ((pMode = CheckMode(pScrn, pVbe, vbe, i, modeTypes)) != NULL) { - ModeStatus status = MODE_OK; - - /* Check the mode against a specified virtual size (if any) */ - if (pScrn->display->virtualX > 0 && - pMode->HDisplay > pScrn->display->virtualX) { - status = MODE_VIRTUAL_X; - } - if (pScrn->display->virtualY > 0 && - pMode->VDisplay > pScrn->display->virtualY) { - status = MODE_VIRTUAL_Y; - } - if (status != MODE_OK) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Not using mode \"%dx%d\" (%s)\n", - pMode->HDisplay, pMode->VDisplay, - xf86ModeStatusToString(status)); - } else { - if (p == NULL) { - modePool = pMode; - } else { - p->next = pMode; - } - pMode->prev = NULL; - p = pMode; - } - } - } - } - return modePool; -} - -void -VBESetModeNames(DisplayModePtr pMode) -{ - if (!pMode) - return; - - do { - if (!pMode->name) { - /* Catch "bad" modes. */ - if (pMode->HDisplay > 10000 || pMode->HDisplay < 0 || - pMode->VDisplay > 10000 || pMode->VDisplay < 0) { - pMode->name = strdup("BADMODE"); - } else { - pMode->name = xnfalloc(4 + 1 + 4 + 1); - sprintf(pMode->name, "%dx%d", pMode->HDisplay, pMode->VDisplay); - } - } - pMode = pMode->next; - } while (pMode); -} - -/* - * Go through the monitor modes and selecting the best set of - * parameters for each BIOS mode. Note: This is only supported in - * VBE version 3.0 or later. - */ -void -VBESetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe) -{ - DisplayModePtr pMode; - VbeModeInfoData *data; - - pMode = pScrn->modes; - do { - DisplayModePtr p, best = NULL; - ModeStatus status; - - for (p = pScrn->monitor->Modes; p != NULL; p = p->next) { - if ((p->HDisplay != pMode->HDisplay) || - (p->VDisplay != pMode->VDisplay) || - (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) - continue; - /* XXX could support the various V_ flags */ - status = xf86CheckModeForMonitor(p, pScrn->monitor); - if (status != MODE_OK) - continue; - if (!best || (p->Clock > best->Clock)) - best = p; - } - - if (best) { - int clock; - - data = (VbeModeInfoData*)pMode->Private; - pMode->HSync = (float)best->Clock * 1000.0 / best->HTotal + 0.5; - pMode->VRefresh = pMode->HSync / best->VTotal + 0.5; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Attempting to use %dHz refresh for mode \"%s\" (%x)\n", - (int)pMode->VRefresh, pMode->name, data->mode); - data->block = xcalloc(sizeof(VbeCRTCInfoBlock), 1); - data->block->HorizontalTotal = best->HTotal; - data->block->HorizontalSyncStart = best->HSyncStart; - data->block->HorizontalSyncEnd = best->HSyncEnd; - data->block->VerticalTotal = best->VTotal; - data->block->VerticalSyncStart = best->VSyncStart; - data->block->VerticalSyncEnd = best->VSyncEnd; - data->block->Flags = ((best->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) | - ((best->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0); - data->block->PixelClock = best->Clock * 1000; - /* XXX May not have this. */ - clock = VBEGetPixelClock(pVbe, data->mode, data->block->PixelClock); - DebugF("Setting clock %.2fMHz, closest is %.2fMHz\n", - (double)data->block->PixelClock / 1000000.0, - (double)clock / 1000000.0); - if (clock) - data->block->PixelClock = clock; - data->mode |= (1 << 11); - data->block->RefreshRate = ((double)(data->block->PixelClock) / - (double)(best->HTotal * best->VTotal)) * 100; - } - pMode = pMode->next; - } while (pMode != pScrn->modes); -} - -/* - * These wrappers are to allow (temporary) funtionality divergences. - */ -int -VBEValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, - char **modeNames, ClockRangePtr clockRanges, - int *linePitches, int minPitch, int maxPitch, int pitchInc, - int minHeight, int maxHeight, int virtualX, int virtualY, - int apertureSize, LookupModeFlags strategy) -{ - return xf86ValidateModes(scrp, availModes, modeNames, clockRanges, - linePitches, minPitch, maxPitch, pitchInc, - minHeight, maxHeight, virtualX, virtualY, - apertureSize, strategy); -} - -void -VBEPrintModes(ScrnInfoPtr scrp) -{ - xf86PrintModes(scrp); -} - +#define DEBUG_VERB 2 +/* + * Copyright © 2002 David Dawes + * + * 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 AUTHOR(S) 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 author(s) 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 author(s). + * + * Authors: David Dawes <dawes@xfree86.org> + * + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <stdio.h> +#include <string.h> + +#include "xf86.h" +#include "vbe.h" +#include "vbeModes.h" + +static int +GetDepthFlag(vbeInfoPtr pVbe, int id) +{ + VbeModeInfoBlock *mode; + int bpp; + + if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) + return 0; + + if (VBE_MODE_USABLE(mode, 0)) { + int depth; + + if (VBE_MODE_COLOR(mode)) { + depth = mode->RedMaskSize + mode->GreenMaskSize + + mode->BlueMaskSize; + } else { + depth = 1; + } + bpp = mode->BitsPerPixel; + VBEFreeModeInfo(mode); + mode = NULL; + switch (depth) { + case 1: + return V_DEPTH_1; + case 4: + return V_DEPTH_4; + case 8: + return V_DEPTH_8; + case 15: + return V_DEPTH_15; + case 16: + return V_DEPTH_16; + case 24: + switch (bpp) { + case 24: + return V_DEPTH_24_24; + case 32: + return V_DEPTH_24_32; + } + } + } + if (mode) + VBEFreeModeInfo(mode); + return 0; +} + +/* + * Find supported mode depths. + */ +int +VBEFindSupportedDepths(vbeInfoPtr pVbe, VbeInfoBlock *vbe, int *flags24, + int modeTypes) +{ + int i = 0; + int depths = 0; + + if (modeTypes & V_MODETYPE_VBE) { + while (vbe->VideoModePtr[i] != 0xffff) { + depths |= GetDepthFlag(pVbe, vbe->VideoModePtr[i++]); + } + } + + /* + * XXX This possibly only works with VBE 3.0 and later. + */ + if (modeTypes & V_MODETYPE_VGA) { + for (i = 0; i < 0x7F; i++) { + depths |= GetDepthFlag(pVbe, i); + } + } + + if (flags24) { + if (depths & V_DEPTH_24_24) + *flags24 |= Support24bppFb; + if (depths & V_DEPTH_24_32) + *flags24 |= Support32bppFb; + } + + return depths; +} + +static DisplayModePtr +CheckMode(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe, int id, + int flags) +{ + CARD16 major; + VbeModeInfoBlock *mode; + DisplayModePtr pMode; + VbeModeInfoData *data; + Bool modeOK = FALSE; + + major = (unsigned)(vbe->VESAVersion >> 8); + + if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) + return NULL; + + /* Does the mode match the depth/bpp? */ + /* Some BIOS's set BitsPerPixel to 15 instead of 16 for 15/16 */ + if (VBE_MODE_USABLE(mode, flags) && + ((pScrn->bitsPerPixel == 1 && !VBE_MODE_COLOR(mode)) || + (mode->BitsPerPixel > 8 && + (mode->RedMaskSize + mode->GreenMaskSize + + mode->BlueMaskSize) == pScrn->depth && + mode->BitsPerPixel == pScrn->bitsPerPixel) || + (mode->BitsPerPixel == 15 && pScrn->depth == 15) || + (mode->BitsPerPixel <= 8 && + mode->BitsPerPixel == pScrn->bitsPerPixel))) { + modeOK = TRUE; + xf86ErrorFVerb(DEBUG_VERB, "*"); + } + + xf86ErrorFVerb(DEBUG_VERB, + "Mode: %x (%dx%d)\n", id, mode->XResolution, mode->YResolution); + xf86ErrorFVerb(DEBUG_VERB, + " ModeAttributes: 0x%x\n", mode->ModeAttributes); + xf86ErrorFVerb(DEBUG_VERB, + " WinAAttributes: 0x%x\n", mode->WinAAttributes); + xf86ErrorFVerb(DEBUG_VERB, + " WinBAttributes: 0x%x\n", mode->WinBAttributes); + xf86ErrorFVerb(DEBUG_VERB, + " WinGranularity: %d\n", mode->WinGranularity); + xf86ErrorFVerb(DEBUG_VERB, + " WinSize: %d\n", mode->WinSize); + xf86ErrorFVerb(DEBUG_VERB, + " WinASegment: 0x%x\n", mode->WinASegment); + xf86ErrorFVerb(DEBUG_VERB, + " WinBSegment: 0x%x\n", mode->WinBSegment); + xf86ErrorFVerb(DEBUG_VERB, + " WinFuncPtr: 0x%lx\n", (unsigned long)mode->WinFuncPtr); + xf86ErrorFVerb(DEBUG_VERB, + " BytesPerScanline: %d\n", mode->BytesPerScanline); + xf86ErrorFVerb(DEBUG_VERB, + " XResolution: %d\n", mode->XResolution); + xf86ErrorFVerb(DEBUG_VERB, + " YResolution: %d\n", mode->YResolution); + xf86ErrorFVerb(DEBUG_VERB, + " XCharSize: %d\n", mode->XCharSize); + xf86ErrorFVerb(DEBUG_VERB, + " YCharSize: %d\n", mode->YCharSize); + xf86ErrorFVerb(DEBUG_VERB, + " NumberOfPlanes: %d\n", mode->NumberOfPlanes); + xf86ErrorFVerb(DEBUG_VERB, + " BitsPerPixel: %d\n", mode->BitsPerPixel); + xf86ErrorFVerb(DEBUG_VERB, + " NumberOfBanks: %d\n", mode->NumberOfBanks); + xf86ErrorFVerb(DEBUG_VERB, + " MemoryModel: %d\n", mode->MemoryModel); + xf86ErrorFVerb(DEBUG_VERB, + " BankSize: %d\n", mode->BankSize); + xf86ErrorFVerb(DEBUG_VERB, + " NumberOfImages: %d\n", mode->NumberOfImages); + xf86ErrorFVerb(DEBUG_VERB, + " RedMaskSize: %d\n", mode->RedMaskSize); + xf86ErrorFVerb(DEBUG_VERB, + " RedFieldPosition: %d\n", mode->RedFieldPosition); + xf86ErrorFVerb(DEBUG_VERB, + " GreenMaskSize: %d\n", mode->GreenMaskSize); + xf86ErrorFVerb(DEBUG_VERB, + " GreenFieldPosition: %d\n", mode->GreenFieldPosition); + xf86ErrorFVerb(DEBUG_VERB, + " BlueMaskSize: %d\n", mode->BlueMaskSize); + xf86ErrorFVerb(DEBUG_VERB, + " BlueFieldPosition: %d\n", mode->BlueFieldPosition); + xf86ErrorFVerb(DEBUG_VERB, + " RsvdMaskSize: %d\n", mode->RsvdMaskSize); + xf86ErrorFVerb(DEBUG_VERB, + " RsvdFieldPosition: %d\n", mode->RsvdFieldPosition); + xf86ErrorFVerb(DEBUG_VERB, + " DirectColorModeInfo: %d\n", mode->DirectColorModeInfo); + if (major >= 2) { + xf86ErrorFVerb(DEBUG_VERB, + " PhysBasePtr: 0x%lx\n", + (unsigned long)mode->PhysBasePtr); + if (major >= 3) { + xf86ErrorFVerb(DEBUG_VERB, + " LinBytesPerScanLine: %d\n", mode->LinBytesPerScanLine); + xf86ErrorFVerb(DEBUG_VERB, + " BnkNumberOfImagePages: %d\n", mode->BnkNumberOfImagePages); + xf86ErrorFVerb(DEBUG_VERB, + " LinNumberOfImagePages: %d\n", mode->LinNumberOfImagePages); + xf86ErrorFVerb(DEBUG_VERB, + " LinRedMaskSize: %d\n", mode->LinRedMaskSize); + xf86ErrorFVerb(DEBUG_VERB, + " LinRedFieldPosition: %d\n", mode->LinRedFieldPosition); + xf86ErrorFVerb(DEBUG_VERB, + " LinGreenMaskSize: %d\n", mode->LinGreenMaskSize); + xf86ErrorFVerb(DEBUG_VERB, + " LinGreenFieldPosition: %d\n", mode->LinGreenFieldPosition); + xf86ErrorFVerb(DEBUG_VERB, + " LinBlueMaskSize: %d\n", mode->LinBlueMaskSize); + xf86ErrorFVerb(DEBUG_VERB, + " LinBlueFieldPosition: %d\n", mode->LinBlueFieldPosition); + xf86ErrorFVerb(DEBUG_VERB, + " LinRsvdMaskSize: %d\n", mode->LinRsvdMaskSize); + xf86ErrorFVerb(DEBUG_VERB, + " LinRsvdFieldPosition: %d\n", mode->LinRsvdFieldPosition); + xf86ErrorFVerb(DEBUG_VERB, + " MaxPixelClock: %ld\n", (unsigned long)mode->MaxPixelClock); + } + } + + if (!modeOK) { + VBEFreeModeInfo(mode); + return NULL; + } + pMode = xnfcalloc(sizeof(DisplayModeRec), 1); + + pMode->status = MODE_OK; + pMode->type = M_T_BUILTIN; + + /* for adjust frame */ + pMode->HDisplay = mode->XResolution; + pMode->VDisplay = mode->YResolution; + + data = xnfcalloc(sizeof(VbeModeInfoData), 1); + data->mode = id; + data->data = mode; + pMode->PrivSize = sizeof(VbeModeInfoData); + pMode->Private = (INT32*)data; + pMode->next = NULL; + return pMode; +} + +/* + * Check the available BIOS modes, and extract those that match the + * requirements into the modePool. Note: modePool is a NULL-terminated + * list. + */ + +DisplayModePtr +VBEGetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe, + int modeTypes) +{ + DisplayModePtr pMode, p = NULL, modePool = NULL; + int i = 0; + + if (modeTypes & V_MODETYPE_VBE) { + while (vbe->VideoModePtr[i] != 0xffff) { + int id = vbe->VideoModePtr[i++]; + + if ((pMode = CheckMode(pScrn, pVbe, vbe, id, modeTypes)) != NULL) { + ModeStatus status = MODE_OK; + + /* Check the mode against a specified virtual size (if any) */ + if (pScrn->display->virtualX > 0 && + pMode->HDisplay > pScrn->display->virtualX) { + status = MODE_VIRTUAL_X; + } + if (pScrn->display->virtualY > 0 && + pMode->VDisplay > pScrn->display->virtualY) { + status = MODE_VIRTUAL_Y; + } + if (status != MODE_OK) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Not using mode \"%dx%d\" (%s)\n", + pMode->HDisplay, pMode->VDisplay, + xf86ModeStatusToString(status)); + } else { + if (p == NULL) { + modePool = pMode; + } else { + p->next = pMode; + } + pMode->prev = NULL; + p = pMode; + } + } + } + } + if (modeTypes & V_MODETYPE_VGA) { + for (i = 0; i < 0x7F; i++) { + if ((pMode = CheckMode(pScrn, pVbe, vbe, i, modeTypes)) != NULL) { + ModeStatus status = MODE_OK; + + /* Check the mode against a specified virtual size (if any) */ + if (pScrn->display->virtualX > 0 && + pMode->HDisplay > pScrn->display->virtualX) { + status = MODE_VIRTUAL_X; + } + if (pScrn->display->virtualY > 0 && + pMode->VDisplay > pScrn->display->virtualY) { + status = MODE_VIRTUAL_Y; + } + if (status != MODE_OK) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Not using mode \"%dx%d\" (%s)\n", + pMode->HDisplay, pMode->VDisplay, + xf86ModeStatusToString(status)); + } else { + if (p == NULL) { + modePool = pMode; + } else { + p->next = pMode; + } + pMode->prev = NULL; + p = pMode; + } + } + } + } + return modePool; +} + +void +VBESetModeNames(DisplayModePtr pMode) +{ + if (!pMode) + return; + + do { + if (!pMode->name) { + /* Catch "bad" modes. */ + if (pMode->HDisplay > 10000 || pMode->HDisplay < 0 || + pMode->VDisplay > 10000 || pMode->VDisplay < 0) { + pMode->name = strdup("BADMODE"); + } else { + pMode->name = xnfalloc(4 + 1 + 4 + 1); + sprintf(pMode->name, "%dx%d", pMode->HDisplay, pMode->VDisplay); + } + } + pMode = pMode->next; + } while (pMode); +} + +/* + * Go through the monitor modes and selecting the best set of + * parameters for each BIOS mode. Note: This is only supported in + * VBE version 3.0 or later. + */ +void +VBESetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe) +{ + DisplayModePtr pMode; + VbeModeInfoData *data; + + pMode = pScrn->modes; + do { + DisplayModePtr p, best = NULL; + ModeStatus status; + + for (p = pScrn->monitor->Modes; p != NULL; p = p->next) { + if ((p->HDisplay != pMode->HDisplay) || + (p->VDisplay != pMode->VDisplay) || + (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) + continue; + /* XXX could support the various V_ flags */ + status = xf86CheckModeForMonitor(p, pScrn->monitor); + if (status != MODE_OK) + continue; + if (!best || (p->Clock > best->Clock)) + best = p; + } + + if (best) { + int clock; + + data = (VbeModeInfoData*)pMode->Private; + pMode->HSync = (float)best->Clock * 1000.0 / best->HTotal + 0.5; + pMode->VRefresh = pMode->HSync / best->VTotal + 0.5; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Attempting to use %dHz refresh for mode \"%s\" (%x)\n", + (int)pMode->VRefresh, pMode->name, data->mode); + data->block = calloc(sizeof(VbeCRTCInfoBlock), 1); + data->block->HorizontalTotal = best->HTotal; + data->block->HorizontalSyncStart = best->HSyncStart; + data->block->HorizontalSyncEnd = best->HSyncEnd; + data->block->VerticalTotal = best->VTotal; + data->block->VerticalSyncStart = best->VSyncStart; + data->block->VerticalSyncEnd = best->VSyncEnd; + data->block->Flags = ((best->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) | + ((best->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0); + data->block->PixelClock = best->Clock * 1000; + /* XXX May not have this. */ + clock = VBEGetPixelClock(pVbe, data->mode, data->block->PixelClock); + DebugF("Setting clock %.2fMHz, closest is %.2fMHz\n", + (double)data->block->PixelClock / 1000000.0, + (double)clock / 1000000.0); + if (clock) + data->block->PixelClock = clock; + data->mode |= (1 << 11); + data->block->RefreshRate = ((double)(data->block->PixelClock) / + (double)(best->HTotal * best->VTotal)) * 100; + } + pMode = pMode->next; + } while (pMode != pScrn->modes); +} + +/* + * These wrappers are to allow (temporary) funtionality divergences. + */ +int +VBEValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, + char **modeNames, ClockRangePtr clockRanges, + int *linePitches, int minPitch, int maxPitch, int pitchInc, + int minHeight, int maxHeight, int virtualX, int virtualY, + int apertureSize, LookupModeFlags strategy) +{ + return xf86ValidateModes(scrp, availModes, modeNames, clockRanges, + linePitches, minPitch, maxPitch, pitchInc, + minHeight, maxHeight, virtualX, virtualY, + apertureSize, strategy); +} + +void +VBEPrintModes(ScrnInfoPtr scrp) +{ + xf86PrintModes(scrp); +} + diff --git a/xorg-server/hw/xfree86/vgahw/vgaCmap.c b/xorg-server/hw/xfree86/vgahw/vgaCmap.c index 06eeb4ce1..e337b42c0 100644 --- a/xorg-server/hw/xfree86/vgahw/vgaCmap.c +++ b/xorg-server/hw/xfree86/vgahw/vgaCmap.c @@ -1,301 +1,301 @@ -/* - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * - * 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 Thomas Roell not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Thomas Roell makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THOMAS ROELL 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_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "windowstr.h" -#include "compiler.h" -#include "mipointer.h" -#include "micmap.h" - -#include "xf86.h" -#include "vgaHW.h" - -#include <X11/extensions/xf86dgaproto.h> -#include "dgaproc.h" - - -#define NOMAPYET (ColormapPtr) 0 - -int -vgaListInstalledColormaps(pScreen, pmaps) - ScreenPtr pScreen; - Colormap *pmaps; -{ - /* By the time we are processing requests, we can guarantee that there - * is always a colormap installed */ - - *pmaps = GetInstalledmiColormap(pScreen)->mid; - return(1); -} - -int -vgaGetInstalledColormaps(pScreen, pmaps) - ScreenPtr pScreen; - ColormapPtr *pmaps; -{ - /* By the time we are processing requests, we can guarantee that there - * is always a colormap installed */ - - *pmaps = GetInstalledmiColormap(pScreen); - return(1); -} - -int vgaCheckColorMap(ColormapPtr pmap) -{ - return (pmap != GetInstalledmiColormap(pmap->pScreen)); -} - - -void -vgaStoreColors(pmap, ndef, pdefs) - ColormapPtr pmap; - int ndef; - xColorItem *pdefs; -{ - int i; - unsigned char *cmap, *tmp = NULL; - xColorItem directDefs[256]; - Bool new_overscan = FALSE; - Bool writeColormap; - - /* This can get called before the ScrnInfoRec is installed so we - can't rely on getting it with XF86SCRNINFO() */ - int scrnIndex = pmap->pScreen->myNum; - ScrnInfoPtr scrninfp = xf86Screens[scrnIndex]; - vgaHWPtr hwp = VGAHWPTR(scrninfp); - - unsigned char overscan = hwp->ModeReg.Attribute[OVERSCAN]; - unsigned char tmp_overscan = 0; - - if (vgaCheckColorMap(pmap)) - return; - - if ((pmap->pVisual->class | DynamicClass) == DirectColor) - { - ndef = miExpandDirectColors (pmap, ndef, pdefs, directDefs); - pdefs = directDefs; - } - - writeColormap = scrninfp->vtSema; - if (DGAAvailable(scrnIndex)) - { - writeColormap = writeColormap || - (DGAGetDirectMode(scrnIndex) && - !(DGAGetFlags(scrnIndex) & XF86DGADirectColormap)) || - (DGAGetFlags(scrnIndex) & XF86DGAHasColormap); - } - - if (writeColormap) - hwp->enablePalette(hwp); - - for(i = 0; i < ndef; i++) - { - if (pdefs[i].pixel == overscan) - { - new_overscan = TRUE; - } - cmap = &(hwp->ModeReg.DAC[pdefs[i].pixel*3]); - if (scrninfp->rgbBits == 8) { - cmap[0] = pdefs[i].red >> 8; - cmap[1] = pdefs[i].green >> 8; - cmap[2] = pdefs[i].blue >> 8; - } - else { - cmap[0] = pdefs[i].red >> 10; - cmap[1] = pdefs[i].green >> 10; - cmap[2] = pdefs[i].blue >> 10; - } -#if 0 - if (clgd6225Lcd) - { - /* The LCD doesn't like white */ - if (cmap[0] == 63) cmap[0]= 62; - if (cmap[1] == 63) cmap[1]= 62; - if (cmap[2] == 63) cmap[2]= 62; - } -#endif - - if (writeColormap) - { - if (hwp->ShowOverscan && i == 255) - continue; - hwp->writeDacWriteAddr(hwp, pdefs[i].pixel); - DACDelay(hwp); - hwp->writeDacData(hwp, cmap[0]); - DACDelay(hwp); - hwp->writeDacData(hwp, cmap[1]); - DACDelay(hwp); - hwp->writeDacData(hwp, cmap[2]); - DACDelay(hwp); - } - } - if (new_overscan && !hwp->ShowOverscan) - { - new_overscan = FALSE; - for(i = 0; i < ndef; i++) - { - if (pdefs[i].pixel == overscan) - { - if ((pdefs[i].red != 0) || - (pdefs[i].green != 0) || - (pdefs[i].blue != 0)) - { - new_overscan = TRUE; - tmp_overscan = overscan; - tmp = &(hwp->ModeReg.DAC[pdefs[i].pixel*3]); - } - break; - } - } - if (new_overscan) - { - /* - * Find a black pixel, or the nearest match. - */ - for (i=255; i >= 0; i--) - { - cmap = &(hwp->ModeReg.DAC[i*3]); - if ((cmap[0] == 0) && (cmap[1] == 0) && (cmap[2] == 0)) - { - overscan = i; - break; - } - else - { - if ((cmap[0] < tmp[0]) && - (cmap[1] < tmp[1]) && (cmap[2] < tmp[2])) - { - tmp = cmap; - tmp_overscan = i; - } - } - } - if (i < 0) - { - overscan = tmp_overscan; - } - hwp->ModeReg.Attribute[OVERSCAN] = overscan; - if (writeColormap) - { - hwp->writeAttr(hwp, OVERSCAN, overscan); - } - } - } - - if (writeColormap) - hwp->disablePalette(hwp); -} - - -void -vgaInstallColormap(pmap) - ColormapPtr pmap; -{ - ColormapPtr oldmap = GetInstalledmiColormap(pmap->pScreen); - int entries; - Pixel * ppix; - xrgb * prgb; - xColorItem *defs; - int i; - - - if (pmap == oldmap) - return; - - if ((pmap->pVisual->class | DynamicClass) == DirectColor) - entries = (pmap->pVisual->redMask | - pmap->pVisual->greenMask | - pmap->pVisual->blueMask) + 1; - else - entries = pmap->pVisual->ColormapEntries; - - ppix = (Pixel *)xalloc( entries * sizeof(Pixel)); - prgb = (xrgb *)xalloc( entries * sizeof(xrgb)); - defs = (xColorItem *)xalloc(entries * sizeof(xColorItem)); - - if ( oldmap != NOMAPYET) - WalkTree( pmap->pScreen, TellLostMap, &oldmap->mid); - - SetInstalledmiColormap(pmap->pScreen, pmap); - - for ( i=0; i<entries; i++) ppix[i] = i; - - QueryColors( pmap, entries, ppix, prgb); - - for ( i=0; i<entries; i++) /* convert xrgbs to xColorItems */ - { - defs[i].pixel = ppix[i]; - defs[i].red = prgb[i].red; - defs[i].green = prgb[i].green; - defs[i].blue = prgb[i].blue; - defs[i].flags = DoRed|DoGreen|DoBlue; - } - pmap->pScreen->StoreColors(pmap, entries, defs); - - WalkTree(pmap->pScreen, TellGainedMap, &pmap->mid); - - xfree(ppix); - xfree(prgb); - xfree(defs); -} - - -void -vgaUninstallColormap(pmap) - ColormapPtr pmap; -{ - - ColormapPtr defColormap; - - if ( pmap != GetInstalledmiColormap(pmap->pScreen)) - return; - - dixLookupResourceByType((pointer *)&defColormap, pmap->pScreen->defColormap, - RT_COLORMAP, serverClient, DixInstallAccess); - - if (defColormap == GetInstalledmiColormap(pmap->pScreen)) - return; - - (*pmap->pScreen->InstallColormap) (defColormap); -} - - -void -vgaHandleColormaps(ScreenPtr pScreen, ScrnInfoPtr scrnp) -{ - if (scrnp->bitsPerPixel > 1) { - if (scrnp->bitsPerPixel <= 8) { /* For 8bpp SVGA and VGA16 */ - pScreen->InstallColormap = vgaInstallColormap; - pScreen->UninstallColormap = vgaUninstallColormap; - pScreen->ListInstalledColormaps = vgaListInstalledColormaps; - pScreen->StoreColors = vgaStoreColors; - } - } -} - +/* + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * 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 Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL 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_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "windowstr.h" +#include "compiler.h" +#include "mipointer.h" +#include "micmap.h" + +#include "xf86.h" +#include "vgaHW.h" + +#include <X11/extensions/xf86dgaproto.h> +#include "dgaproc.h" + + +#define NOMAPYET (ColormapPtr) 0 + +int +vgaListInstalledColormaps(pScreen, pmaps) + ScreenPtr pScreen; + Colormap *pmaps; +{ + /* By the time we are processing requests, we can guarantee that there + * is always a colormap installed */ + + *pmaps = GetInstalledmiColormap(pScreen)->mid; + return(1); +} + +int +vgaGetInstalledColormaps(pScreen, pmaps) + ScreenPtr pScreen; + ColormapPtr *pmaps; +{ + /* By the time we are processing requests, we can guarantee that there + * is always a colormap installed */ + + *pmaps = GetInstalledmiColormap(pScreen); + return(1); +} + +int vgaCheckColorMap(ColormapPtr pmap) +{ + return (pmap != GetInstalledmiColormap(pmap->pScreen)); +} + + +void +vgaStoreColors(pmap, ndef, pdefs) + ColormapPtr pmap; + int ndef; + xColorItem *pdefs; +{ + int i; + unsigned char *cmap, *tmp = NULL; + xColorItem directDefs[256]; + Bool new_overscan = FALSE; + Bool writeColormap; + + /* This can get called before the ScrnInfoRec is installed so we + can't rely on getting it with XF86SCRNINFO() */ + int scrnIndex = pmap->pScreen->myNum; + ScrnInfoPtr scrninfp = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(scrninfp); + + unsigned char overscan = hwp->ModeReg.Attribute[OVERSCAN]; + unsigned char tmp_overscan = 0; + + if (vgaCheckColorMap(pmap)) + return; + + if ((pmap->pVisual->class | DynamicClass) == DirectColor) + { + ndef = miExpandDirectColors (pmap, ndef, pdefs, directDefs); + pdefs = directDefs; + } + + writeColormap = scrninfp->vtSema; + if (DGAAvailable(scrnIndex)) + { + writeColormap = writeColormap || + (DGAGetDirectMode(scrnIndex) && + !(DGAGetFlags(scrnIndex) & XF86DGADirectColormap)) || + (DGAGetFlags(scrnIndex) & XF86DGAHasColormap); + } + + if (writeColormap) + hwp->enablePalette(hwp); + + for(i = 0; i < ndef; i++) + { + if (pdefs[i].pixel == overscan) + { + new_overscan = TRUE; + } + cmap = &(hwp->ModeReg.DAC[pdefs[i].pixel*3]); + if (scrninfp->rgbBits == 8) { + cmap[0] = pdefs[i].red >> 8; + cmap[1] = pdefs[i].green >> 8; + cmap[2] = pdefs[i].blue >> 8; + } + else { + cmap[0] = pdefs[i].red >> 10; + cmap[1] = pdefs[i].green >> 10; + cmap[2] = pdefs[i].blue >> 10; + } +#if 0 + if (clgd6225Lcd) + { + /* The LCD doesn't like white */ + if (cmap[0] == 63) cmap[0]= 62; + if (cmap[1] == 63) cmap[1]= 62; + if (cmap[2] == 63) cmap[2]= 62; + } +#endif + + if (writeColormap) + { + if (hwp->ShowOverscan && i == 255) + continue; + hwp->writeDacWriteAddr(hwp, pdefs[i].pixel); + DACDelay(hwp); + hwp->writeDacData(hwp, cmap[0]); + DACDelay(hwp); + hwp->writeDacData(hwp, cmap[1]); + DACDelay(hwp); + hwp->writeDacData(hwp, cmap[2]); + DACDelay(hwp); + } + } + if (new_overscan && !hwp->ShowOverscan) + { + new_overscan = FALSE; + for(i = 0; i < ndef; i++) + { + if (pdefs[i].pixel == overscan) + { + if ((pdefs[i].red != 0) || + (pdefs[i].green != 0) || + (pdefs[i].blue != 0)) + { + new_overscan = TRUE; + tmp_overscan = overscan; + tmp = &(hwp->ModeReg.DAC[pdefs[i].pixel*3]); + } + break; + } + } + if (new_overscan) + { + /* + * Find a black pixel, or the nearest match. + */ + for (i=255; i >= 0; i--) + { + cmap = &(hwp->ModeReg.DAC[i*3]); + if ((cmap[0] == 0) && (cmap[1] == 0) && (cmap[2] == 0)) + { + overscan = i; + break; + } + else + { + if ((cmap[0] < tmp[0]) && + (cmap[1] < tmp[1]) && (cmap[2] < tmp[2])) + { + tmp = cmap; + tmp_overscan = i; + } + } + } + if (i < 0) + { + overscan = tmp_overscan; + } + hwp->ModeReg.Attribute[OVERSCAN] = overscan; + if (writeColormap) + { + hwp->writeAttr(hwp, OVERSCAN, overscan); + } + } + } + + if (writeColormap) + hwp->disablePalette(hwp); +} + + +void +vgaInstallColormap(pmap) + ColormapPtr pmap; +{ + ColormapPtr oldmap = GetInstalledmiColormap(pmap->pScreen); + int entries; + Pixel * ppix; + xrgb * prgb; + xColorItem *defs; + int i; + + + if (pmap == oldmap) + return; + + if ((pmap->pVisual->class | DynamicClass) == DirectColor) + entries = (pmap->pVisual->redMask | + pmap->pVisual->greenMask | + pmap->pVisual->blueMask) + 1; + else + entries = pmap->pVisual->ColormapEntries; + + ppix = (Pixel *)malloc( entries * sizeof(Pixel)); + prgb = (xrgb *)malloc( entries * sizeof(xrgb)); + defs = (xColorItem *)malloc(entries * sizeof(xColorItem)); + + if ( oldmap != NOMAPYET) + WalkTree( pmap->pScreen, TellLostMap, &oldmap->mid); + + SetInstalledmiColormap(pmap->pScreen, pmap); + + for ( i=0; i<entries; i++) ppix[i] = i; + + QueryColors(pmap, entries, ppix, prgb, serverClient); + + for ( i=0; i<entries; i++) /* convert xrgbs to xColorItems */ + { + defs[i].pixel = ppix[i]; + defs[i].red = prgb[i].red; + defs[i].green = prgb[i].green; + defs[i].blue = prgb[i].blue; + defs[i].flags = DoRed|DoGreen|DoBlue; + } + pmap->pScreen->StoreColors(pmap, entries, defs); + + WalkTree(pmap->pScreen, TellGainedMap, &pmap->mid); + + free(ppix); + free(prgb); + free(defs); +} + + +void +vgaUninstallColormap(pmap) + ColormapPtr pmap; +{ + + ColormapPtr defColormap; + + if ( pmap != GetInstalledmiColormap(pmap->pScreen)) + return; + + dixLookupResourceByType((pointer *)&defColormap, pmap->pScreen->defColormap, + RT_COLORMAP, serverClient, DixInstallAccess); + + if (defColormap == GetInstalledmiColormap(pmap->pScreen)) + return; + + (*pmap->pScreen->InstallColormap) (defColormap); +} + + +void +vgaHandleColormaps(ScreenPtr pScreen, ScrnInfoPtr scrnp) +{ + if (scrnp->bitsPerPixel > 1) { + if (scrnp->bitsPerPixel <= 8) { /* For 8bpp SVGA and VGA16 */ + pScreen->InstallColormap = vgaInstallColormap; + pScreen->UninstallColormap = vgaUninstallColormap; + pScreen->ListInstalledColormaps = vgaListInstalledColormaps; + pScreen->StoreColors = vgaStoreColors; + } + } +} + diff --git a/xorg-server/hw/xfree86/vgahw/vgaHW.c b/xorg-server/hw/xfree86/vgahw/vgaHW.c index 004376b75..396a3cc62 100644 --- a/xorg-server/hw/xfree86/vgahw/vgaHW.c +++ b/xorg-server/hw/xfree86/vgahw/vgaHW.c @@ -1,1995 +1,1995 @@ - -/* - * - * Copyright 1991-1999 by The XFree86 Project, Inc. - * - * Loosely based on code bearing the following copyright: - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * - */ - -#define _NEED_SYSI86 - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <X11/X.h> -#include "misc.h" - -#include "xf86.h" -#include "xf86_OSproc.h" -#include "vgaHW.h" - -#include "compiler.h" - -#include "xf86cmap.h" - -#include "Pci.h" - -#ifndef SAVE_FONT1 -#define SAVE_FONT1 1 -#endif - -/* - * These used to be OS-specific, which made this module have an undesirable - * OS dependency. Define them by default for all platforms. - */ -#ifndef NEED_SAVED_CMAP -#define NEED_SAVED_CMAP -#endif -#ifndef SAVE_TEXT -#define SAVE_TEXT 1 -#endif -#ifndef SAVE_FONT2 -#define SAVE_FONT2 1 -#endif - -/* bytes per plane to save for text */ -#define TEXT_AMOUNT 16384 - -/* bytes per plane to save for font data */ -#define FONT_AMOUNT (8*8192) - -#if 0 -/* Override all of these for now */ -#undef SAVE_FONT1 -#define SAVE_FONT1 1 -#undef SAVE_FONT2 -#define SAVE_FONT2 1 -#undef SAVE_TEST -#define SAVE_TEST 1 -#undef FONT_AMOUNT -#define FONT_AMOUNT 65536 -#undef TEXT_AMOUNT -#define TEXT_AMOUNT 65536 -#endif - -/* DAC indices for white and black */ -#define WHITE_VALUE 0x3F -#define BLACK_VALUE 0x00 -#define OVERSCAN_VALUE 0x01 - - -/* Use a private definition of this here */ -#undef VGAHWPTR -#define VGAHWPTRLVAL(p) (p)->privates[vgaHWPrivateIndex].ptr -#define VGAHWPTR(p) ((vgaHWPtr)(VGAHWPTRLVAL(p))) - -static int vgaHWPrivateIndex = -1; - -#define DAC_TEST_MASK 0x3F - -#ifdef NEED_SAVED_CMAP -/* This default colourmap is used only when it can't be read from the VGA */ - -static CARD8 defaultDAC[768] = -{ - 0, 0, 0, 0, 0, 42, 0, 42, 0, 0, 42, 42, - 42, 0, 0, 42, 0, 42, 42, 21, 0, 42, 42, 42, - 21, 21, 21, 21, 21, 63, 21, 63, 21, 21, 63, 63, - 63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63, - 0, 0, 0, 5, 5, 5, 8, 8, 8, 11, 11, 11, - 14, 14, 14, 17, 17, 17, 20, 20, 20, 24, 24, 24, - 28, 28, 28, 32, 32, 32, 36, 36, 36, 40, 40, 40, - 45, 45, 45, 50, 50, 50, 56, 56, 56, 63, 63, 63, - 0, 0, 63, 16, 0, 63, 31, 0, 63, 47, 0, 63, - 63, 0, 63, 63, 0, 47, 63, 0, 31, 63, 0, 16, - 63, 0, 0, 63, 16, 0, 63, 31, 0, 63, 47, 0, - 63, 63, 0, 47, 63, 0, 31, 63, 0, 16, 63, 0, - 0, 63, 0, 0, 63, 16, 0, 63, 31, 0, 63, 47, - 0, 63, 63, 0, 47, 63, 0, 31, 63, 0, 16, 63, - 31, 31, 63, 39, 31, 63, 47, 31, 63, 55, 31, 63, - 63, 31, 63, 63, 31, 55, 63, 31, 47, 63, 31, 39, - 63, 31, 31, 63, 39, 31, 63, 47, 31, 63, 55, 31, - 63, 63, 31, 55, 63, 31, 47, 63, 31, 39, 63, 31, - 31, 63, 31, 31, 63, 39, 31, 63, 47, 31, 63, 55, - 31, 63, 63, 31, 55, 63, 31, 47, 63, 31, 39, 63, - 45, 45, 63, 49, 45, 63, 54, 45, 63, 58, 45, 63, - 63, 45, 63, 63, 45, 58, 63, 45, 54, 63, 45, 49, - 63, 45, 45, 63, 49, 45, 63, 54, 45, 63, 58, 45, - 63, 63, 45, 58, 63, 45, 54, 63, 45, 49, 63, 45, - 45, 63, 45, 45, 63, 49, 45, 63, 54, 45, 63, 58, - 45, 63, 63, 45, 58, 63, 45, 54, 63, 45, 49, 63, - 0, 0, 28, 7, 0, 28, 14, 0, 28, 21, 0, 28, - 28, 0, 28, 28, 0, 21, 28, 0, 14, 28, 0, 7, - 28, 0, 0, 28, 7, 0, 28, 14, 0, 28, 21, 0, - 28, 28, 0, 21, 28, 0, 14, 28, 0, 7, 28, 0, - 0, 28, 0, 0, 28, 7, 0, 28, 14, 0, 28, 21, - 0, 28, 28, 0, 21, 28, 0, 14, 28, 0, 7, 28, - 14, 14, 28, 17, 14, 28, 21, 14, 28, 24, 14, 28, - 28, 14, 28, 28, 14, 24, 28, 14, 21, 28, 14, 17, - 28, 14, 14, 28, 17, 14, 28, 21, 14, 28, 24, 14, - 28, 28, 14, 24, 28, 14, 21, 28, 14, 17, 28, 14, - 14, 28, 14, 14, 28, 17, 14, 28, 21, 14, 28, 24, - 14, 28, 28, 14, 24, 28, 14, 21, 28, 14, 17, 28, - 20, 20, 28, 22, 20, 28, 24, 20, 28, 26, 20, 28, - 28, 20, 28, 28, 20, 26, 28, 20, 24, 28, 20, 22, - 28, 20, 20, 28, 22, 20, 28, 24, 20, 28, 26, 20, - 28, 28, 20, 26, 28, 20, 24, 28, 20, 22, 28, 20, - 20, 28, 20, 20, 28, 22, 20, 28, 24, 20, 28, 26, - 20, 28, 28, 20, 26, 28, 20, 24, 28, 20, 22, 28, - 0, 0, 16, 4, 0, 16, 8, 0, 16, 12, 0, 16, - 16, 0, 16, 16, 0, 12, 16, 0, 8, 16, 0, 4, - 16, 0, 0, 16, 4, 0, 16, 8, 0, 16, 12, 0, - 16, 16, 0, 12, 16, 0, 8, 16, 0, 4, 16, 0, - 0, 16, 0, 0, 16, 4, 0, 16, 8, 0, 16, 12, - 0, 16, 16, 0, 12, 16, 0, 8, 16, 0, 4, 16, - 8, 8, 16, 10, 8, 16, 12, 8, 16, 14, 8, 16, - 16, 8, 16, 16, 8, 14, 16, 8, 12, 16, 8, 10, - 16, 8, 8, 16, 10, 8, 16, 12, 8, 16, 14, 8, - 16, 16, 8, 14, 16, 8, 12, 16, 8, 10, 16, 8, - 8, 16, 8, 8, 16, 10, 8, 16, 12, 8, 16, 14, - 8, 16, 16, 8, 14, 16, 8, 12, 16, 8, 10, 16, - 11, 11, 16, 12, 11, 16, 13, 11, 16, 15, 11, 16, - 16, 11, 16, 16, 11, 15, 16, 11, 13, 16, 11, 12, - 16, 11, 11, 16, 12, 11, 16, 13, 11, 16, 15, 11, - 16, 16, 11, 15, 16, 11, 13, 16, 11, 12, 16, 11, - 11, 16, 11, 11, 16, 12, 11, 16, 13, 11, 16, 15, - 11, 16, 16, 11, 15, 16, 11, 13, 16, 11, 12, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; -#endif /* NEED_SAVED_CMAP */ - -/* - * Standard VGA versions of the register access functions. - */ -static void -stdWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value) -{ - outb(hwp->IOBase + hwp->PIOOffset + VGA_CRTC_INDEX_OFFSET, index); - outb(hwp->IOBase + hwp->PIOOffset + VGA_CRTC_DATA_OFFSET, value); -} - -static CARD8 -stdReadCrtc(vgaHWPtr hwp, CARD8 index) -{ - outb(hwp->IOBase + hwp->PIOOffset + VGA_CRTC_INDEX_OFFSET, index); - return inb(hwp->IOBase + hwp->PIOOffset + VGA_CRTC_DATA_OFFSET); -} - -static void -stdWriteGr(vgaHWPtr hwp, CARD8 index, CARD8 value) -{ - outb(hwp->PIOOffset + VGA_GRAPH_INDEX, index); - outb(hwp->PIOOffset + VGA_GRAPH_DATA, value); -} - -static CARD8 -stdReadGr(vgaHWPtr hwp, CARD8 index) -{ - outb(hwp->PIOOffset + VGA_GRAPH_INDEX, index); - return inb(hwp->PIOOffset + VGA_GRAPH_DATA); -} - -static void -stdWriteSeq(vgaHWPtr hwp, CARD8 index, CARD8 value) -{ - outb(hwp->PIOOffset + VGA_SEQ_INDEX, index); - outb(hwp->PIOOffset + VGA_SEQ_DATA, value); -} - -static CARD8 -stdReadSeq(vgaHWPtr hwp, CARD8 index) -{ - outb(hwp->PIOOffset + VGA_SEQ_INDEX, index); - return inb(hwp->PIOOffset + VGA_SEQ_DATA); -} - -static CARD8 -stdReadST00(vgaHWPtr hwp) -{ - return inb(hwp->PIOOffset + VGA_IN_STAT_0); -} - -static CARD8 -stdReadST01(vgaHWPtr hwp) -{ - return inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); -} - -static CARD8 -stdReadFCR(vgaHWPtr hwp) -{ - return inb(hwp->PIOOffset + VGA_FEATURE_R); -} - -static void -stdWriteFCR(vgaHWPtr hwp, CARD8 value) -{ - outb(hwp->IOBase + hwp->PIOOffset + VGA_FEATURE_W_OFFSET,value); -} - -static void -stdWriteAttr(vgaHWPtr hwp, CARD8 index, CARD8 value) -{ - if (hwp->paletteEnabled) - index &= ~0x20; - else - index |= 0x20; - - (void) inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); - outb(hwp->PIOOffset + VGA_ATTR_INDEX, index); - outb(hwp->PIOOffset + VGA_ATTR_DATA_W, value); -} - -static CARD8 -stdReadAttr(vgaHWPtr hwp, CARD8 index) -{ - if (hwp->paletteEnabled) - index &= ~0x20; - else - index |= 0x20; - - (void) inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); - outb(hwp->PIOOffset + VGA_ATTR_INDEX, index); - return inb(hwp->PIOOffset + VGA_ATTR_DATA_R); -} - -static void -stdWriteMiscOut(vgaHWPtr hwp, CARD8 value) -{ - outb(hwp->PIOOffset + VGA_MISC_OUT_W, value); -} - -static CARD8 -stdReadMiscOut(vgaHWPtr hwp) -{ - return inb(hwp->PIOOffset + VGA_MISC_OUT_R); -} - -static void -stdEnablePalette(vgaHWPtr hwp) -{ - (void) inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); - outb(hwp->PIOOffset + VGA_ATTR_INDEX, 0x00); - hwp->paletteEnabled = TRUE; -} - -static void -stdDisablePalette(vgaHWPtr hwp) -{ - (void) inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); - outb(hwp->PIOOffset + VGA_ATTR_INDEX, 0x20); - hwp->paletteEnabled = FALSE; -} - -static void -stdWriteDacMask(vgaHWPtr hwp, CARD8 value) -{ - outb(hwp->PIOOffset + VGA_DAC_MASK, value); -} - -static CARD8 -stdReadDacMask(vgaHWPtr hwp) -{ - return inb(hwp->PIOOffset + VGA_DAC_MASK); -} - -static void -stdWriteDacReadAddr(vgaHWPtr hwp, CARD8 value) -{ - outb(hwp->PIOOffset + VGA_DAC_READ_ADDR, value); -} - -static void -stdWriteDacWriteAddr(vgaHWPtr hwp, CARD8 value) -{ - outb(hwp->PIOOffset + VGA_DAC_WRITE_ADDR, value); -} - -static void -stdWriteDacData(vgaHWPtr hwp, CARD8 value) -{ - outb(hwp->PIOOffset + VGA_DAC_DATA, value); -} - -static CARD8 -stdReadDacData(vgaHWPtr hwp) -{ - return inb(hwp->PIOOffset + VGA_DAC_DATA); -} - -static CARD8 -stdReadEnable(vgaHWPtr hwp) -{ - return inb(hwp->PIOOffset + VGA_ENABLE); -} - -static void -stdWriteEnable(vgaHWPtr hwp, CARD8 value) -{ - outb(hwp->PIOOffset + VGA_ENABLE, value); -} - -void -vgaHWSetStdFuncs(vgaHWPtr hwp) -{ - hwp->writeCrtc = stdWriteCrtc; - hwp->readCrtc = stdReadCrtc; - hwp->writeGr = stdWriteGr; - hwp->readGr = stdReadGr; - hwp->readST00 = stdReadST00; - hwp->readST01 = stdReadST01; - hwp->readFCR = stdReadFCR; - hwp->writeFCR = stdWriteFCR; - hwp->writeAttr = stdWriteAttr; - hwp->readAttr = stdReadAttr; - hwp->writeSeq = stdWriteSeq; - hwp->readSeq = stdReadSeq; - hwp->writeMiscOut = stdWriteMiscOut; - hwp->readMiscOut = stdReadMiscOut; - hwp->enablePalette = stdEnablePalette; - hwp->disablePalette = stdDisablePalette; - hwp->writeDacMask = stdWriteDacMask; - hwp->readDacMask = stdReadDacMask; - hwp->writeDacWriteAddr = stdWriteDacWriteAddr; - hwp->writeDacReadAddr = stdWriteDacReadAddr; - hwp->writeDacData = stdWriteDacData; - hwp->readDacData = stdReadDacData; - hwp->PIOOffset = 0; - hwp->readEnable = stdReadEnable; - hwp->writeEnable = stdWriteEnable; -} - -/* - * MMIO versions of the register access functions. These require - * hwp->MemBase to be set in such a way that when the standard VGA port - * adderss is added the correct memory address results. - */ - -#define minb(p) MMIO_IN8(hwp->MMIOBase, (hwp->MMIOOffset + (p))) -#define moutb(p,v) MMIO_OUT8(hwp->MMIOBase, (hwp->MMIOOffset + (p)),(v)) - -static void -mmioWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value) -{ - moutb(hwp->IOBase + VGA_CRTC_INDEX_OFFSET, index); - moutb(hwp->IOBase + VGA_CRTC_DATA_OFFSET, value); -} - -static CARD8 -mmioReadCrtc(vgaHWPtr hwp, CARD8 index) -{ - moutb(hwp->IOBase + VGA_CRTC_INDEX_OFFSET, index); - return minb(hwp->IOBase + VGA_CRTC_DATA_OFFSET); -} - -static void -mmioWriteGr(vgaHWPtr hwp, CARD8 index, CARD8 value) -{ - moutb(VGA_GRAPH_INDEX, index); - moutb(VGA_GRAPH_DATA, value); -} - -static CARD8 -mmioReadGr(vgaHWPtr hwp, CARD8 index) -{ - moutb(VGA_GRAPH_INDEX, index); - return minb(VGA_GRAPH_DATA); -} - -static void -mmioWriteSeq(vgaHWPtr hwp, CARD8 index, CARD8 value) -{ - moutb(VGA_SEQ_INDEX, index); - moutb(VGA_SEQ_DATA, value); -} - -static CARD8 -mmioReadSeq(vgaHWPtr hwp, CARD8 index) -{ - moutb(VGA_SEQ_INDEX, index); - return minb(VGA_SEQ_DATA); -} - -static CARD8 -mmioReadST00(vgaHWPtr hwp) -{ - return minb(VGA_IN_STAT_0); -} - -static CARD8 -mmioReadST01(vgaHWPtr hwp) -{ - return minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); -} - -static CARD8 -mmioReadFCR(vgaHWPtr hwp) -{ - return minb(VGA_FEATURE_R); -} - -static void -mmioWriteFCR(vgaHWPtr hwp, CARD8 value) -{ - moutb(hwp->IOBase + VGA_FEATURE_W_OFFSET,value); -} - -static void -mmioWriteAttr(vgaHWPtr hwp, CARD8 index, CARD8 value) -{ - if (hwp->paletteEnabled) - index &= ~0x20; - else - index |= 0x20; - - (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); - moutb(VGA_ATTR_INDEX, index); - moutb(VGA_ATTR_DATA_W, value); -} - -static CARD8 -mmioReadAttr(vgaHWPtr hwp, CARD8 index) -{ - if (hwp->paletteEnabled) - index &= ~0x20; - else - index |= 0x20; - - (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); - moutb(VGA_ATTR_INDEX, index); - return minb(VGA_ATTR_DATA_R); -} - -static void -mmioWriteMiscOut(vgaHWPtr hwp, CARD8 value) -{ - moutb(VGA_MISC_OUT_W, value); -} - -static CARD8 -mmioReadMiscOut(vgaHWPtr hwp) -{ - return minb(VGA_MISC_OUT_R); -} - -static void -mmioEnablePalette(vgaHWPtr hwp) -{ - (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); - moutb(VGA_ATTR_INDEX, 0x00); - hwp->paletteEnabled = TRUE; -} - -static void -mmioDisablePalette(vgaHWPtr hwp) -{ - (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); - moutb(VGA_ATTR_INDEX, 0x20); - hwp->paletteEnabled = FALSE; -} - -static void -mmioWriteDacMask(vgaHWPtr hwp, CARD8 value) -{ - moutb(VGA_DAC_MASK, value); -} - -static CARD8 -mmioReadDacMask(vgaHWPtr hwp) -{ - return minb(VGA_DAC_MASK); -} - -static void -mmioWriteDacReadAddr(vgaHWPtr hwp, CARD8 value) -{ - moutb(VGA_DAC_READ_ADDR, value); -} - -static void -mmioWriteDacWriteAddr(vgaHWPtr hwp, CARD8 value) -{ - moutb(VGA_DAC_WRITE_ADDR, value); -} - -static void -mmioWriteDacData(vgaHWPtr hwp, CARD8 value) -{ - moutb(VGA_DAC_DATA, value); -} - -static CARD8 -mmioReadDacData(vgaHWPtr hwp) -{ - return minb(VGA_DAC_DATA); -} - -static CARD8 -mmioReadEnable(vgaHWPtr hwp) -{ - return minb(VGA_ENABLE); -} - -static void -mmioWriteEnable(vgaHWPtr hwp, CARD8 value) -{ - moutb(VGA_ENABLE, value); -} - -void -vgaHWSetMmioFuncs(vgaHWPtr hwp, CARD8 *base, int offset) -{ - hwp->writeCrtc = mmioWriteCrtc; - hwp->readCrtc = mmioReadCrtc; - hwp->writeGr = mmioWriteGr; - hwp->readGr = mmioReadGr; - hwp->readST00 = mmioReadST00; - hwp->readST01 = mmioReadST01; - hwp->readFCR = mmioReadFCR; - hwp->writeFCR = mmioWriteFCR; - hwp->writeAttr = mmioWriteAttr; - hwp->readAttr = mmioReadAttr; - hwp->writeSeq = mmioWriteSeq; - hwp->readSeq = mmioReadSeq; - hwp->writeMiscOut = mmioWriteMiscOut; - hwp->readMiscOut = mmioReadMiscOut; - hwp->enablePalette = mmioEnablePalette; - hwp->disablePalette = mmioDisablePalette; - hwp->writeDacMask = mmioWriteDacMask; - hwp->readDacMask = mmioReadDacMask; - hwp->writeDacWriteAddr = mmioWriteDacWriteAddr; - hwp->writeDacReadAddr = mmioWriteDacReadAddr; - hwp->writeDacData = mmioWriteDacData; - hwp->readDacData = mmioReadDacData; - hwp->MMIOBase = base; - hwp->MMIOOffset = offset; - hwp->readEnable = mmioReadEnable; - hwp->writeEnable = mmioWriteEnable; -} - -/* - * vgaHWProtect -- - * Protect VGA registers and memory from corruption during loads. - */ - -void -vgaHWProtect(ScrnInfoPtr pScrn, Bool on) -{ - vgaHWPtr hwp = VGAHWPTR(pScrn); - - unsigned char tmp; - - if (pScrn->vtSema) { - if (on) { - /* - * Turn off screen and disable sequencer. - */ - tmp = hwp->readSeq(hwp, 0x01); - - vgaHWSeqReset(hwp, TRUE); /* start synchronous reset */ - hwp->writeSeq(hwp, 0x01, tmp | 0x20); /* disable the display */ - - hwp->enablePalette(hwp); - } else { - /* - * Reenable sequencer, then turn on screen. - */ - - tmp = hwp->readSeq(hwp, 0x01); - - hwp->writeSeq(hwp, 0x01, tmp & ~0x20); /* reenable display */ - vgaHWSeqReset(hwp, FALSE); /* clear synchronousreset */ - - hwp->disablePalette(hwp); - } - } -} - -vgaHWProtectProc *vgaHWProtectWeak(void) { - return vgaHWProtect; -} - -/* - * vgaHWBlankScreen -- blank the screen. - */ - -void -vgaHWBlankScreen(ScrnInfoPtr pScrn, Bool on) -{ - vgaHWPtr hwp = VGAHWPTR(pScrn); - unsigned char scrn; - - scrn = hwp->readSeq(hwp, 0x01); - - if (on) { - scrn &= ~0x20; /* enable screen */ - } else { - scrn |= 0x20; /* blank screen */ - } - - vgaHWSeqReset(hwp, TRUE); - hwp->writeSeq(hwp, 0x01, scrn); /* change mode */ - vgaHWSeqReset(hwp, FALSE); -} - -vgaHWBlankScreenProc *vgaHWBlankScreenWeak(void) { - return vgaHWBlankScreen; -} - -/* - * vgaHWSaveScreen -- blank the screen. - */ - -Bool -vgaHWSaveScreen(ScreenPtr pScreen, int mode) -{ - ScrnInfoPtr pScrn = NULL; - Bool on; - - if (pScreen != NULL) - pScrn = xf86Screens[pScreen->myNum]; - - on = xf86IsUnblank(mode); - -#if 0 - if (on) - SetTimeSinceLastInputEvent(); -#endif - - if ((pScrn != NULL) && pScrn->vtSema) { - vgaHWBlankScreen(pScrn, on); - } - return (TRUE); -} - - -/* - * vgaHWDPMSSet -- Sets VESA Display Power Management Signaling (DPMS) Mode - * - * This generic VGA function can only set the Off and On modes. If the - * Standby and Suspend modes are to be supported, a chip specific replacement - * for this function must be written. - */ - -void -vgaHWDPMSSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) -{ - unsigned char seq1 = 0, crtc17 = 0; - vgaHWPtr hwp = VGAHWPTR(pScrn); - - if (!pScrn->vtSema) return; - - switch (PowerManagementMode) { - case DPMSModeOn: - /* Screen: On; HSync: On, VSync: On */ - seq1 = 0x00; - crtc17 = 0x80; - break; - case DPMSModeStandby: - /* Screen: Off; HSync: Off, VSync: On -- Not Supported */ - seq1 = 0x20; - crtc17 = 0x80; - break; - case DPMSModeSuspend: - /* Screen: Off; HSync: On, VSync: Off -- Not Supported */ - seq1 = 0x20; - crtc17 = 0x80; - break; - case DPMSModeOff: - /* Screen: Off; HSync: Off, VSync: Off */ - seq1 = 0x20; - crtc17 = 0x00; - break; - } - hwp->writeSeq(hwp, 0x00, 0x01); /* Synchronous Reset */ - seq1 |= hwp->readSeq(hwp, 0x01) & ~0x20; - hwp->writeSeq(hwp, 0x01, seq1); - crtc17 |= hwp->readCrtc(hwp, 0x17) & ~0x80; - usleep(10000); - hwp->writeCrtc(hwp, 0x17, crtc17); - hwp->writeSeq(hwp, 0x00, 0x03); /* End Reset */ -} - - -/* - * vgaHWSeqReset - * perform a sequencer reset. - */ - -void -vgaHWSeqReset(vgaHWPtr hwp, Bool start) -{ - if (start) - hwp->writeSeq(hwp, 0x00, 0x01); /* Synchronous Reset */ - else - hwp->writeSeq(hwp, 0x00, 0x03); /* End Reset */ -} - - -void -vgaHWRestoreFonts(ScrnInfoPtr scrninfp, vgaRegPtr restore) -{ -#if SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 - vgaHWPtr hwp = VGAHWPTR(scrninfp); - int savedIOBase; - unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4; - Bool doMap = FALSE; - - /* If nothing to do, return now */ - if (!hwp->FontInfo1 && !hwp->FontInfo2 && !hwp->TextInfo) - return; - - if (hwp->Base == NULL) { - doMap = TRUE; - if (!vgaHWMapMem(scrninfp)) { - xf86DrvMsg(scrninfp->scrnIndex, X_ERROR, - "vgaHWRestoreFonts: vgaHWMapMem() failed\n"); - return; - } - } - - /* save the registers that are needed here */ - miscOut = hwp->readMiscOut(hwp); - attr10 = hwp->readAttr(hwp, 0x10); - gr1 = hwp->readGr(hwp, 0x01); - gr3 = hwp->readGr(hwp, 0x03); - gr4 = hwp->readGr(hwp, 0x04); - gr5 = hwp->readGr(hwp, 0x05); - gr6 = hwp->readGr(hwp, 0x06); - gr8 = hwp->readGr(hwp, 0x08); - seq2 = hwp->readSeq(hwp, 0x02); - seq4 = hwp->readSeq(hwp, 0x04); - - /* save hwp->IOBase and temporarily set it for colour mode */ - savedIOBase = hwp->IOBase; - hwp->IOBase = VGA_IOBASE_COLOR; - - /* Force into colour mode */ - hwp->writeMiscOut(hwp, miscOut | 0x01); - - vgaHWBlankScreen(scrninfp, FALSE); - - /* - * here we temporarily switch to 16 colour planar mode, to simply - * copy the font-info and saved text. - * - * BUG ALERT: The (S)VGA's segment-select register MUST be set correctly! - */ -#if 0 - hwp->writeAttr(hwp, 0x10, 0x01); /* graphics mode */ -#endif - - hwp->writeSeq(hwp, 0x04, 0x06); /* enable plane graphics */ - hwp->writeGr(hwp, 0x05, 0x00); /* write mode 0, read mode 0 */ - hwp->writeGr(hwp, 0x06, 0x05); /* set graphics */ - - if (scrninfp->depth == 4) { - /* GJA */ - hwp->writeGr(hwp, 0x03, 0x00); /* don't rotate, write unmodified */ - hwp->writeGr(hwp, 0x08, 0xFF); /* write all bits in a byte */ - hwp->writeGr(hwp, 0x01, 0x00); /* all planes come from CPU */ - } - -#if SAVE_FONT1 - if (hwp->FontInfo1) { - hwp->writeSeq(hwp, 0x02, 0x04); /* write to plane 2 */ - hwp->writeGr(hwp, 0x04, 0x02); /* read plane 2 */ - slowbcopy_tobus(hwp->FontInfo1, hwp->Base, FONT_AMOUNT); - } -#endif - -#if SAVE_FONT2 - if (hwp->FontInfo2) { - hwp->writeSeq(hwp, 0x02, 0x08); /* write to plane 3 */ - hwp->writeGr(hwp, 0x04, 0x03); /* read plane 3 */ - slowbcopy_tobus(hwp->FontInfo2, hwp->Base, FONT_AMOUNT); - } -#endif - -#if SAVE_TEXT - if (hwp->TextInfo) { - hwp->writeSeq(hwp, 0x02, 0x01); /* write to plane 0 */ - hwp->writeGr(hwp, 0x04, 0x00); /* read plane 0 */ - slowbcopy_tobus(hwp->TextInfo, hwp->Base, TEXT_AMOUNT); - hwp->writeSeq(hwp, 0x02, 0x02); /* write to plane 1 */ - hwp->writeGr(hwp, 0x04, 0x01); /* read plane 1 */ - slowbcopy_tobus((unsigned char *)hwp->TextInfo + TEXT_AMOUNT, - hwp->Base, TEXT_AMOUNT); - } -#endif - - vgaHWBlankScreen(scrninfp, TRUE); - - /* restore the registers that were changed */ - hwp->writeMiscOut(hwp, miscOut); - hwp->writeAttr(hwp, 0x10, attr10); - hwp->writeGr(hwp, 0x01, gr1); - hwp->writeGr(hwp, 0x03, gr3); - hwp->writeGr(hwp, 0x04, gr4); - hwp->writeGr(hwp, 0x05, gr5); - hwp->writeGr(hwp, 0x06, gr6); - hwp->writeGr(hwp, 0x08, gr8); - hwp->writeSeq(hwp, 0x02, seq2); - hwp->writeSeq(hwp, 0x04, seq4); - hwp->IOBase = savedIOBase; - - if (doMap) - vgaHWUnmapMem(scrninfp); - -#endif /* SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 */ -} - - -void -vgaHWRestoreMode(ScrnInfoPtr scrninfp, vgaRegPtr restore) -{ - vgaHWPtr hwp = VGAHWPTR(scrninfp); - int i; - - if (restore->MiscOutReg & 0x01) - hwp->IOBase = VGA_IOBASE_COLOR; - else - hwp->IOBase = VGA_IOBASE_MONO; - - hwp->writeMiscOut(hwp, restore->MiscOutReg); - - for (i = 1; i < restore->numSequencer; i++) - hwp->writeSeq(hwp, i, restore->Sequencer[i]); - - /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17] */ - hwp->writeCrtc(hwp, 17, restore->CRTC[17] & ~0x80); - - for (i = 0; i < restore->numCRTC; i++) - hwp->writeCrtc(hwp, i, restore->CRTC[i]); - - for (i = 0; i < restore->numGraphics; i++) - hwp->writeGr(hwp, i, restore->Graphics[i]); - - hwp->enablePalette(hwp); - for (i = 0; i < restore->numAttribute; i++) - hwp->writeAttr(hwp, i, restore->Attribute[i]); - hwp->disablePalette(hwp); -} - - -void -vgaHWRestoreColormap(ScrnInfoPtr scrninfp, vgaRegPtr restore) -{ - vgaHWPtr hwp = VGAHWPTR(scrninfp); - int i; - -#if 0 - hwp->enablePalette(hwp); -#endif - - hwp->writeDacMask(hwp, 0xFF); - hwp->writeDacWriteAddr(hwp, 0x00); - for (i = 0; i < 768; i++) { - hwp->writeDacData(hwp, restore->DAC[i]); - DACDelay(hwp); - } - - hwp->disablePalette(hwp); -} - - -/* - * vgaHWRestore -- - * restore the VGA state - */ - -void -vgaHWRestore(ScrnInfoPtr scrninfp, vgaRegPtr restore, int flags) -{ - if (flags & VGA_SR_MODE) - vgaHWRestoreMode(scrninfp, restore); - - if (flags & VGA_SR_FONTS) - vgaHWRestoreFonts(scrninfp, restore); - - if (flags & VGA_SR_CMAP) - vgaHWRestoreColormap(scrninfp, restore); -} - -void -vgaHWSaveFonts(ScrnInfoPtr scrninfp, vgaRegPtr save) -{ -#if SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 - vgaHWPtr hwp = VGAHWPTR(scrninfp); - int savedIOBase; - unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4; - Bool doMap = FALSE; - - if (hwp->Base == NULL) { - doMap = TRUE; - if (!vgaHWMapMem(scrninfp)) { - xf86DrvMsg(scrninfp->scrnIndex, X_ERROR, - "vgaHWSaveFonts: vgaHWMapMem() failed\n"); - return; - } - } - - /* If in graphics mode, don't save anything */ - attr10 = hwp->readAttr(hwp, 0x10); - if (attr10 & 0x01) - return; - - /* save the registers that are needed here */ - miscOut = hwp->readMiscOut(hwp); - gr4 = hwp->readGr(hwp, 0x04); - gr5 = hwp->readGr(hwp, 0x05); - gr6 = hwp->readGr(hwp, 0x06); - seq2 = hwp->readSeq(hwp, 0x02); - seq4 = hwp->readSeq(hwp, 0x04); - - /* save hwp->IOBase and temporarily set it for colour mode */ - savedIOBase = hwp->IOBase; - hwp->IOBase = VGA_IOBASE_COLOR; - - /* Force into colour mode */ - hwp->writeMiscOut(hwp, miscOut | 0x01); - - vgaHWBlankScreen(scrninfp, FALSE); - - /* - * get the character sets, and text screen if required - */ - /* - * Here we temporarily switch to 16 colour planar mode, to simply - * copy the font-info - * - * BUG ALERT: The (S)VGA's segment-select register MUST be set correctly! - */ -#if 0 - hwp->writeAttr(hwp, 0x10, 0x01); /* graphics mode */ -#endif - - hwp->writeSeq(hwp, 0x04, 0x06); /* enable plane graphics */ - hwp->writeGr(hwp, 0x05, 0x00); /* write mode 0, read mode 0 */ - hwp->writeGr(hwp, 0x06, 0x05); /* set graphics */ - -#if SAVE_FONT1 - if (hwp->FontInfo1 || (hwp->FontInfo1 = xalloc(FONT_AMOUNT))) { - hwp->writeSeq(hwp, 0x02, 0x04); /* write to plane 2 */ - hwp->writeGr(hwp, 0x04, 0x02); /* read plane 2 */ - slowbcopy_frombus(hwp->Base, hwp->FontInfo1, FONT_AMOUNT); - } -#endif /* SAVE_FONT1 */ -#if SAVE_FONT2 - if (hwp->FontInfo2 || (hwp->FontInfo2 = xalloc(FONT_AMOUNT))) { - hwp->writeSeq(hwp, 0x02, 0x08); /* write to plane 3 */ - hwp->writeGr(hwp, 0x04, 0x03); /* read plane 3 */ - slowbcopy_frombus(hwp->Base, hwp->FontInfo2, FONT_AMOUNT); - } -#endif /* SAVE_FONT2 */ -#if SAVE_TEXT - if (hwp->TextInfo || (hwp->TextInfo = xalloc(2 * TEXT_AMOUNT))) { - hwp->writeSeq(hwp, 0x02, 0x01); /* write to plane 0 */ - hwp->writeGr(hwp, 0x04, 0x00); /* read plane 0 */ - slowbcopy_frombus(hwp->Base, hwp->TextInfo, TEXT_AMOUNT); - hwp->writeSeq(hwp, 0x02, 0x02); /* write to plane 1 */ - hwp->writeGr(hwp, 0x04, 0x01); /* read plane 1 */ - slowbcopy_frombus(hwp->Base, - (unsigned char *)hwp->TextInfo + TEXT_AMOUNT, TEXT_AMOUNT); - } -#endif /* SAVE_TEXT */ - - /* Restore clobbered registers */ - hwp->writeAttr(hwp, 0x10, attr10); - hwp->writeSeq(hwp, 0x02, seq2); - hwp->writeSeq(hwp, 0x04, seq4); - hwp->writeGr(hwp, 0x04, gr4); - hwp->writeGr(hwp, 0x05, gr5); - hwp->writeGr(hwp, 0x06, gr6); - hwp->writeMiscOut(hwp, miscOut); - hwp->IOBase = savedIOBase; - - vgaHWBlankScreen(scrninfp, TRUE); - - if (doMap) - vgaHWUnmapMem(scrninfp); - -#endif /* SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 */ -} - -void -vgaHWSaveMode(ScrnInfoPtr scrninfp, vgaRegPtr save) -{ - vgaHWPtr hwp = VGAHWPTR(scrninfp); - int i; - - save->MiscOutReg = hwp->readMiscOut(hwp); - if (save->MiscOutReg & 0x01) - hwp->IOBase = VGA_IOBASE_COLOR; - else - hwp->IOBase = VGA_IOBASE_MONO; - - for (i = 0; i < save->numCRTC; i++) { - save->CRTC[i] = hwp->readCrtc(hwp, i); - DebugF("CRTC[0x%02x] = 0x%02x\n", i, save->CRTC[i]); - } - - hwp->enablePalette(hwp); - for (i = 0; i < save->numAttribute; i++) { - save->Attribute[i] = hwp->readAttr(hwp, i); - DebugF("Attribute[0x%02x] = 0x%02x\n", i, save->Attribute[i]); - } - hwp->disablePalette(hwp); - - for (i = 0; i < save->numGraphics; i++) { - save->Graphics[i] = hwp->readGr(hwp, i); - DebugF("Graphics[0x%02x] = 0x%02x\n", i, save->Graphics[i]); - } - - for (i = 1; i < save->numSequencer; i++) { - save->Sequencer[i] = hwp->readSeq(hwp, i); - DebugF("Sequencer[0x%02x] = 0x%02x\n", i, save->Sequencer[i]); - } -} - - -void -vgaHWSaveColormap(ScrnInfoPtr scrninfp, vgaRegPtr save) -{ - vgaHWPtr hwp = VGAHWPTR(scrninfp); - Bool readError = FALSE; - int i; - -#ifdef NEED_SAVED_CMAP - /* - * Some ET4000 chips from 1991 have a HW bug that prevents the reading - * of the color lookup table. Mask rev 9042EAI is known to have this bug. - * - * If the colourmap is not readable, we set the saved map to a default - * map (taken from Ferraro's "Programmer's Guide to the EGA and VGA - * Cards" 2nd ed). - */ - - /* Only save it once */ - if (hwp->cmapSaved) - return; - -#if 0 - hwp->enablePalette(hwp); -#endif - - hwp->writeDacMask(hwp, 0xFF); - - /* - * check if we can read the lookup table - */ - hwp->writeDacReadAddr(hwp, 0x00); - for (i = 0; i < 6; i++) { - save->DAC[i] = hwp->readDacData(hwp); - switch (i % 3) { - case 0: - DebugF("DAC[0x%02x] = 0x%02x, ", i / 3, save->DAC[i]); - break; - case 1: - DebugF("0x%02x, ", save->DAC[i]); - break; - case 2: - DebugF("0x%02x\n", save->DAC[i]); - } - } - - /* - * Check if we can read the palette - - * use foreground color to prevent flashing. - */ - hwp->writeDacWriteAddr(hwp, 0x01); - for (i = 3; i < 6; i++) - hwp->writeDacData(hwp, ~save->DAC[i] & DAC_TEST_MASK); - hwp->writeDacReadAddr(hwp, 0x01); - for (i = 3; i < 6; i++) { - if (hwp->readDacData(hwp) != (~save->DAC[i] & DAC_TEST_MASK)) - readError = TRUE; - } - hwp->writeDacWriteAddr(hwp, 0x01); - for (i = 3; i < 6; i++) - hwp->writeDacData(hwp, save->DAC[i]); - - if (readError) { - /* - * save the default lookup table - */ - memmove(save->DAC, defaultDAC, 768); - xf86DrvMsg(scrninfp->scrnIndex, X_WARNING, - "Cannot read colourmap from VGA. Will restore with default\n"); - } else { - /* save the colourmap */ - hwp->writeDacReadAddr(hwp, 0x02); - for (i = 6; i < 768; i++) { - save->DAC[i] = hwp->readDacData(hwp); - DACDelay(hwp); - switch (i % 3) { - case 0: - DebugF("DAC[0x%02x] = 0x%02x, ", i / 3, save->DAC[i]); - break; - case 1: - DebugF("0x%02x, ", save->DAC[i]); - break; - case 2: - DebugF("0x%02x\n", save->DAC[i]); - } - } - } - - hwp->disablePalette(hwp); - hwp->cmapSaved = TRUE; -#endif -} - -/* - * vgaHWSave -- - * save the current VGA state - */ - -void -vgaHWSave(ScrnInfoPtr scrninfp, vgaRegPtr save, int flags) -{ - if (save == NULL) - return; - - if (flags & VGA_SR_CMAP) - vgaHWSaveColormap(scrninfp, save); - - if (flags & VGA_SR_MODE) - vgaHWSaveMode(scrninfp, save); - - if (flags & VGA_SR_FONTS) - vgaHWSaveFonts(scrninfp, save); -} - - -/* - * vgaHWInit -- - * Handle the initialization, etc. of a screen. - * Return FALSE on failure. - */ - -Bool -vgaHWInit(ScrnInfoPtr scrninfp, DisplayModePtr mode) -{ - unsigned int i; - vgaHWPtr hwp; - vgaRegPtr regp; - int depth = scrninfp->depth; - - /* - * make sure the vgaHWRec is allocated - */ - if (!vgaHWGetHWRec(scrninfp)) - return FALSE; - hwp = VGAHWPTR(scrninfp); - regp = &hwp->ModeReg; - - /* - * compute correct Hsync & Vsync polarity - */ - if ((mode->Flags & (V_PHSYNC | V_NHSYNC)) - && (mode->Flags & (V_PVSYNC | V_NVSYNC))) - { - regp->MiscOutReg = 0x23; - if (mode->Flags & V_NHSYNC) regp->MiscOutReg |= 0x40; - if (mode->Flags & V_NVSYNC) regp->MiscOutReg |= 0x80; - } - else - { - int VDisplay = mode->VDisplay; - if (mode->Flags & V_DBLSCAN) - VDisplay *= 2; - if (mode->VScan > 1) - VDisplay *= mode->VScan; - if (VDisplay < 400) - regp->MiscOutReg = 0xA3; /* +hsync -vsync */ - else if (VDisplay < 480) - regp->MiscOutReg = 0x63; /* -hsync +vsync */ - else if (VDisplay < 768) - regp->MiscOutReg = 0xE3; /* -hsync -vsync */ - else - regp->MiscOutReg = 0x23; /* +hsync +vsync */ - } - - regp->MiscOutReg |= (mode->ClockIndex & 0x03) << 2; - - /* - * Time Sequencer - */ - if (depth == 4) - regp->Sequencer[0] = 0x02; - else - regp->Sequencer[0] = 0x00; - if (mode->Flags & V_CLKDIV2) - regp->Sequencer[1] = 0x09; - else - regp->Sequencer[1] = 0x01; - if (depth == 1) - regp->Sequencer[2] = 1 << BIT_PLANE; - else - regp->Sequencer[2] = 0x0F; - regp->Sequencer[3] = 0x00; /* Font select */ - if (depth < 8) - regp->Sequencer[4] = 0x06; /* Misc */ - else - regp->Sequencer[4] = 0x0E; /* Misc */ - - /* - * CRTC Controller - */ - regp->CRTC[0] = (mode->CrtcHTotal >> 3) - 5; - regp->CRTC[1] = (mode->CrtcHDisplay >> 3) - 1; - regp->CRTC[2] = (mode->CrtcHBlankStart >> 3) - 1; - regp->CRTC[3] = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80; - i = (((mode->CrtcHSkew << 2) + 0x10) & ~0x1F); - if (i < 0x80) - regp->CRTC[3] |= i; - regp->CRTC[4] = (mode->CrtcHSyncStart >> 3); - regp->CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) - | (((mode->CrtcHSyncEnd >> 3)) & 0x1F); - regp->CRTC[6] = (mode->CrtcVTotal - 2) & 0xFF; - regp->CRTC[7] = (((mode->CrtcVTotal - 2) & 0x100) >> 8) - | (((mode->CrtcVDisplay - 1) & 0x100) >> 7) - | ((mode->CrtcVSyncStart & 0x100) >> 6) - | (((mode->CrtcVBlankStart - 1) & 0x100) >> 5) - | 0x10 - | (((mode->CrtcVTotal - 2) & 0x200) >> 4) - | (((mode->CrtcVDisplay - 1) & 0x200) >> 3) - | ((mode->CrtcVSyncStart & 0x200) >> 2); - regp->CRTC[8] = 0x00; - regp->CRTC[9] = (((mode->CrtcVBlankStart - 1) & 0x200) >> 4) | 0x40; - if (mode->Flags & V_DBLSCAN) - regp->CRTC[9] |= 0x80; - if (mode->VScan >= 32) - regp->CRTC[9] |= 0x1F; - else if (mode->VScan > 1) - regp->CRTC[9] |= mode->VScan - 1; - regp->CRTC[10] = 0x00; - regp->CRTC[11] = 0x00; - regp->CRTC[12] = 0x00; - regp->CRTC[13] = 0x00; - regp->CRTC[14] = 0x00; - regp->CRTC[15] = 0x00; - regp->CRTC[16] = mode->CrtcVSyncStart & 0xFF; - regp->CRTC[17] = (mode->CrtcVSyncEnd & 0x0F) | 0x20; - regp->CRTC[18] = (mode->CrtcVDisplay - 1) & 0xFF; - regp->CRTC[19] = scrninfp->displayWidth >> 4; /* just a guess */ - regp->CRTC[20] = 0x00; - regp->CRTC[21] = (mode->CrtcVBlankStart - 1) & 0xFF; - regp->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; - if (depth < 8) - regp->CRTC[23] = 0xE3; - else - regp->CRTC[23] = 0xC3; - regp->CRTC[24] = 0xFF; - - vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); - vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); - - /* - * Theory resumes here.... - */ - - /* - * Graphics Display Controller - */ - regp->Graphics[0] = 0x00; - regp->Graphics[1] = 0x00; - regp->Graphics[2] = 0x00; - regp->Graphics[3] = 0x00; - if (depth == 1) { - regp->Graphics[4] = BIT_PLANE; - regp->Graphics[5] = 0x00; - } else { - regp->Graphics[4] = 0x00; - if (depth == 4) - regp->Graphics[5] = 0x02; - else - regp->Graphics[5] = 0x40; - } - regp->Graphics[6] = 0x05; /* only map 64k VGA memory !!!! */ - regp->Graphics[7] = 0x0F; - regp->Graphics[8] = 0xFF; - - if (depth == 1) { - /* Initialise the Mono map according to which bit-plane gets used */ - - Bool flipPixels = xf86GetFlipPixels(); - - for (i=0; i<16; i++) - if (((i & (1 << BIT_PLANE)) != 0) != flipPixels) - regp->Attribute[i] = WHITE_VALUE; - else - regp->Attribute[i] = BLACK_VALUE; - - regp->Attribute[16] = 0x01; /* -VGA2- */ /* wrong for the ET4000 */ - if (!hwp->ShowOverscan) - regp->Attribute[OVERSCAN] = OVERSCAN_VALUE; /* -VGA2- */ - } else { - regp->Attribute[0] = 0x00; /* standard colormap translation */ - regp->Attribute[1] = 0x01; - regp->Attribute[2] = 0x02; - regp->Attribute[3] = 0x03; - regp->Attribute[4] = 0x04; - regp->Attribute[5] = 0x05; - regp->Attribute[6] = 0x06; - regp->Attribute[7] = 0x07; - regp->Attribute[8] = 0x08; - regp->Attribute[9] = 0x09; - regp->Attribute[10] = 0x0A; - regp->Attribute[11] = 0x0B; - regp->Attribute[12] = 0x0C; - regp->Attribute[13] = 0x0D; - regp->Attribute[14] = 0x0E; - regp->Attribute[15] = 0x0F; - if (depth == 4) - regp->Attribute[16] = 0x81; /* wrong for the ET4000 */ - else - regp->Attribute[16] = 0x41; /* wrong for the ET4000 */ - /* Attribute[17] (overscan) initialised in vgaHWGetHWRec() */ - } - regp->Attribute[18] = 0x0F; - regp->Attribute[19] = 0x00; - regp->Attribute[20] = 0x00; - - return(TRUE); -} - - /* - * OK, so much for theory. Now, let's deal with the >real< world... - * - * The above CRTC settings are precise in theory, except that many, if not - * most, VGA clones fail to reset the blanking signal when the character or - * line counter reaches [HV]Total. In this case, the signal is only - * unblanked when the counter reaches [HV]BlankEnd (mod 64, 128 or 256 as - * the case may be) at the start of the >next< scanline or frame, which - * means only part of the screen shows. This affects how null overscans - * are to be implemented on such adapters. - * - * Henceforth, VGA cores that implement this broken, but unfortunately - * common, behaviour are to be designated as KGA's, in honour of Koen - * Gadeyne, whose zeal to eliminate overscans (read: fury) set in motion - * a series of events that led to the discovery of this problem. - * - * Some VGA's are KGA's only in the horizontal, or only in the vertical, - * some in both, others in neither. Don't let anyone tell you there is - * such a thing as a VGA "standard"... And, thank the Creator for the fact - * that Hilbert spaces are not yet implemented in this industry. - * - * The following implements a trick suggested by David Dawes. This sets - * [HV]BlankEnd to zero if the blanking interval does not already contain a - * 0-point, and decrements it by one otherwise. In the latter case, this - * will produce a left and/or top overscan which the colourmap code will - * (still) need to ensure is as close to black as possible. This will make - * the behaviour consistent across all chipsets, while allowing all - * chipsets to display the entire screen. Non-KGA drivers can ignore the - * following in their own copy of this code. - * - * -- TSI @ UQV, 1998.08.21 - */ - -CARD32 -vgaHWHBlankKGA(DisplayModePtr mode, vgaRegPtr regp, int nBits, - unsigned int Flags) -{ - int nExtBits = (nBits < 6) ? 0 : nBits - 6; - CARD32 ExtBits; - CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 6; - - regp->CRTC[3] = (regp->CRTC[3] & ~0x1F) - | (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F); - regp->CRTC[5] = (regp->CRTC[5] & ~0x80) - | ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2); - ExtBits = ((mode->CrtcHBlankEnd >> 3) - 1) & ExtBitMask; - - /* First the horizontal case */ - if ((Flags & KGA_FIX_OVERSCAN) - && ((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3))) - { - int i = (regp->CRTC[3] & 0x1F) - | ((regp->CRTC[5] & 0x80) >> 2) - | ExtBits; - if (Flags & KGA_ENABLE_ON_ZERO) { - if ((i-- > (((mode->CrtcHBlankStart >> 3) - 1) - & (0x3F | ExtBitMask))) - && (mode->CrtcHBlankEnd == mode->CrtcHTotal)) - i = 0; - } else if (Flags & KGA_BE_TOT_DEC) - i--; - regp->CRTC[3] = (regp->CRTC[3] & ~0x1F) | (i & 0x1F); - regp->CRTC[5] = (regp->CRTC[5] & ~0x80) | ((i << 2) & 0x80); - ExtBits = i & ExtBitMask; - } - return ExtBits >> 6; -} - - /* - * The vertical case is a little trickier. Some VGA's ignore bit 0x80 of - * CRTC[22]. Also, in some cases, a zero CRTC[22] will still blank the - * very first scanline in a double- or multi-scanned mode. This last case - * needs further investigation. - */ -CARD32 -vgaHWVBlankKGA(DisplayModePtr mode, vgaRegPtr regp, int nBits, - unsigned int Flags) -{ - CARD32 ExtBits; - CARD32 nExtBits = (nBits < 8) ? 0 : (nBits - 8); - CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 8; - /* If width is not known nBits should be 0. In this - * case BitMask is set to 0 so we can check for it. */ - CARD32 BitMask = (nBits < 7) ? 0 : ((1 << nExtBits) - 1); - int VBlankStart = (mode->CrtcVBlankStart - 1) & 0xFF; - regp->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; - ExtBits = (mode->CrtcVBlankEnd - 1) & ExtBitMask; - - if ((Flags & KGA_FIX_OVERSCAN) - && (mode->CrtcVBlankEnd == mode->CrtcVTotal)) - /* Null top overscan */ - { - int i = regp->CRTC[22] | ExtBits; - if (Flags & KGA_ENABLE_ON_ZERO) { - if (((BitMask && ((i & BitMask) > (VBlankStart & BitMask))) - || ((i > VBlankStart) && /* 8-bit case */ - ((i & 0x7F) > (VBlankStart & 0x7F)))) && /* 7-bit case */ - !(regp->CRTC[9] & 0x9F)) /* 1 scanline/row */ - i = 0; - else - i = (i - 1); - } else if (Flags & KGA_BE_TOT_DEC) - i = (i - 1); - - regp->CRTC[22] = i & 0xFF; - ExtBits = i & 0xFF00; - } - return ExtBits >> 8; -} - -/* - * these are some more hardware specific helpers, formerly in vga.c - */ -static void -vgaHWGetHWRecPrivate(void) -{ - if (vgaHWPrivateIndex < 0) - vgaHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); - return; -} - - -static void -vgaHWFreeRegs(vgaRegPtr regp) -{ - if (regp->CRTC) - xfree (regp->CRTC); - - regp->CRTC = - regp->Sequencer = - regp->Graphics = - regp->Attribute = NULL; - - regp->numCRTC = - regp->numSequencer = - regp->numGraphics = - regp->numAttribute = 0; -} - - - -static Bool -vgaHWAllocRegs(vgaRegPtr regp) -{ - unsigned char *buf; - - if ((regp->numCRTC + regp->numSequencer + regp->numGraphics + - regp->numAttribute) == 0) - return FALSE; - - buf = xcalloc(regp->numCRTC + - regp->numSequencer + - regp->numGraphics + - regp->numAttribute, 1); - if (!buf) - return FALSE; - - regp->CRTC = buf; - regp->Sequencer = regp->CRTC + regp->numCRTC; - regp->Graphics = regp->Sequencer + regp->numSequencer; - regp->Attribute = regp->Graphics + regp->numGraphics; - - return TRUE; -} - - -Bool -vgaHWAllocDefaultRegs(vgaRegPtr regp) -{ - regp->numCRTC = VGA_NUM_CRTC; - regp->numSequencer = VGA_NUM_SEQ; - regp->numGraphics = VGA_NUM_GFX; - regp->numAttribute = VGA_NUM_ATTR; - - return vgaHWAllocRegs(regp); -} - - -Bool -vgaHWSetRegCounts(ScrnInfoPtr scrp, int numCRTC, int numSequencer, - int numGraphics, int numAttribute) -{ -#define VGAHWMINNUM(regtype) \ - ((newMode.num##regtype < regp->num##regtype) ? \ - (newMode.num##regtype) : (regp->num##regtype)) -#define VGAHWCOPYREGSET(regtype) \ - memcpy (newMode.regtype, regp->regtype, VGAHWMINNUM(regtype)) - - vgaRegRec newMode, newSaved; - vgaRegPtr regp; - - regp = &VGAHWPTR(scrp)->ModeReg; - memcpy (&newMode, regp, sizeof(vgaRegRec)); - - /* allocate space for new registers */ - - regp = &newMode; - regp->numCRTC = numCRTC; - regp->numSequencer = numSequencer; - regp->numGraphics = numGraphics; - regp->numAttribute = numAttribute; - if (!vgaHWAllocRegs(regp)) - return FALSE; - - regp = &VGAHWPTR(scrp)->SavedReg; - memcpy (&newSaved, regp, sizeof(vgaRegRec)); - - regp = &newSaved; - regp->numCRTC = numCRTC; - regp->numSequencer = numSequencer; - regp->numGraphics = numGraphics; - regp->numAttribute = numAttribute; - if (!vgaHWAllocRegs(regp)) { - vgaHWFreeRegs(&newMode); - return FALSE; - } - - /* allocations succeeded, copy register data into new space */ - - regp = &VGAHWPTR(scrp)->ModeReg; - VGAHWCOPYREGSET(CRTC); - VGAHWCOPYREGSET(Sequencer); - VGAHWCOPYREGSET(Graphics); - VGAHWCOPYREGSET(Attribute); - - regp = &VGAHWPTR(scrp)->SavedReg; - VGAHWCOPYREGSET(CRTC); - VGAHWCOPYREGSET(Sequencer); - VGAHWCOPYREGSET(Graphics); - VGAHWCOPYREGSET(Attribute); - - /* free old register arrays */ - - regp = &VGAHWPTR(scrp)->ModeReg; - vgaHWFreeRegs(regp); - memcpy(regp, &newMode, sizeof(vgaRegRec)); - - regp = &VGAHWPTR(scrp)->SavedReg; - vgaHWFreeRegs(regp); - memcpy(regp, &newSaved, sizeof(vgaRegRec)); - - return TRUE; - -#undef VGAHWMINNUM -#undef VGAHWCOPYREGSET -} - - -Bool -vgaHWCopyReg(vgaRegPtr dst, vgaRegPtr src) -{ - vgaHWFreeRegs(dst); - - memcpy(dst, src, sizeof(vgaRegRec)); - - if (!vgaHWAllocRegs(dst)) - return FALSE; - - memcpy(dst->CRTC, src->CRTC, src->numCRTC); - memcpy(dst->Sequencer, src->Sequencer, src->numSequencer); - memcpy(dst->Graphics, src->Graphics, src->numGraphics); - memcpy(dst->Attribute, src->Attribute, src->numAttribute); - - return TRUE; -} - - -Bool -vgaHWGetHWRec(ScrnInfoPtr scrp) -{ - vgaRegPtr regp; - vgaHWPtr hwp; - int i; - - /* - * Let's make sure that the private exists and allocate one. - */ - vgaHWGetHWRecPrivate(); - /* - * New privates are always set to NULL, so we can check if the allocation - * has already been done. - */ - if (VGAHWPTR(scrp)) - return TRUE; - hwp = VGAHWPTRLVAL(scrp) = xnfcalloc(sizeof(vgaHWRec), 1); - regp = &VGAHWPTR(scrp)->ModeReg; - - if ((!vgaHWAllocDefaultRegs(&VGAHWPTR(scrp)->SavedReg)) || - (!vgaHWAllocDefaultRegs(&VGAHWPTR(scrp)->ModeReg))) { - xfree(hwp); - return FALSE; - } - - if (scrp->bitsPerPixel == 1) { - rgb blackColour = scrp->display->blackColour, - whiteColour = scrp->display->whiteColour; - - if (blackColour.red > 0x3F) blackColour.red = 0x3F; - if (blackColour.green > 0x3F) blackColour.green = 0x3F; - if (blackColour.blue > 0x3F) blackColour.blue = 0x3F; - - if (whiteColour.red > 0x3F) whiteColour.red = 0x3F; - if (whiteColour.green > 0x3F) whiteColour.green = 0x3F; - if (whiteColour.blue > 0x3F) whiteColour.blue = 0x3F; - - if ((blackColour.red == whiteColour.red ) && - (blackColour.green == whiteColour.green) && - (blackColour.blue == whiteColour.blue )) { - blackColour.red ^= 0x3F; - blackColour.green ^= 0x3F; - blackColour.blue ^= 0x3F; - } - - /* - * initialize default colormap for monochrome - */ - for (i=0; i<3; i++) regp->DAC[i] = 0x00; - for (i=3; i<768; i++) regp->DAC[i] = 0x3F; - i = BLACK_VALUE * 3; - regp->DAC[i++] = blackColour.red; - regp->DAC[i++] = blackColour.green; - regp->DAC[i] = blackColour.blue; - i = WHITE_VALUE * 3; - regp->DAC[i++] = whiteColour.red; - regp->DAC[i++] = whiteColour.green; - regp->DAC[i] = whiteColour.blue; - i = OVERSCAN_VALUE * 3; - regp->DAC[i++] = 0x00; - regp->DAC[i++] = 0x00; - regp->DAC[i] = 0x00; - } else { - /* Set all colours to black */ - for (i=0; i<768; i++) regp->DAC[i] = 0x00; - /* ... and the overscan */ - if (scrp->depth >= 4) - regp->Attribute[OVERSCAN] = 0xFF; - } - if (xf86FindOption(scrp->confScreen->options, "ShowOverscan")) { - xf86MarkOptionUsedByName(scrp->confScreen->options, "ShowOverscan"); - xf86DrvMsg(scrp->scrnIndex, X_CONFIG, "Showing overscan area\n"); - regp->DAC[765] = 0x3F; - regp->DAC[766] = 0x00; - regp->DAC[767] = 0x3F; - regp->Attribute[OVERSCAN] = 0xFF; - hwp->ShowOverscan = TRUE; - } else - hwp->ShowOverscan = FALSE; - - hwp->paletteEnabled = FALSE; - hwp->cmapSaved = FALSE; - hwp->MapSize = 0; - hwp->pScrn = scrp; - - /* Initialise the function pointers with the standard VGA versions */ - vgaHWSetStdFuncs(hwp); - - hwp->PIOOffset = scrp->domainIOBase; - hwp->dev = xf86GetPciInfoForEntity(scrp->entityList[0]); - - return TRUE; -} - - -void -vgaHWFreeHWRec(ScrnInfoPtr scrp) -{ - if (vgaHWPrivateIndex >= 0) { - vgaHWPtr hwp = VGAHWPTR(scrp); - - if (!hwp) - return; - - xfree(hwp->FontInfo1); - xfree(hwp->FontInfo2); - xfree(hwp->TextInfo); - - vgaHWFreeRegs (&hwp->ModeReg); - vgaHWFreeRegs (&hwp->SavedReg); - - xfree(hwp); - VGAHWPTRLVAL(scrp) = NULL; - } -} - - -Bool -vgaHWMapMem(ScrnInfoPtr scrp) -{ - vgaHWPtr hwp = VGAHWPTR(scrp); - int scr_index = scrp->scrnIndex; - - if (hwp->Base) - return TRUE; - - /* If not set, initialise with the defaults */ - if (hwp->MapSize == 0) - hwp->MapSize = VGA_DEFAULT_MEM_SIZE; - if (hwp->MapPhys == 0) - hwp->MapPhys = VGA_DEFAULT_PHYS_ADDR; - - /* - * Map as VIDMEM_MMIO_32BIT because WC - * is bad when there is page flipping. - * XXX This is not correct but we do it - * for now. - */ - DebugF("Mapping VGAMem\n"); - hwp->Base = xf86MapDomainMemory(scr_index, VIDMEM_MMIO_32BIT, hwp->dev, - hwp->MapPhys, hwp->MapSize); - return hwp->Base != NULL; -} - - -void -vgaHWUnmapMem(ScrnInfoPtr scrp) -{ - vgaHWPtr hwp = VGAHWPTR(scrp); - int scr_index = scrp->scrnIndex; - - if (hwp->Base == NULL) - return; - - DebugF("Unmapping VGAMem\n"); - xf86UnMapVidMem(scr_index, hwp->Base, hwp->MapSize); - hwp->Base = NULL; -} - -int -vgaHWGetIndex(void) -{ - return vgaHWPrivateIndex; -} - - -void -vgaHWGetIOBase(vgaHWPtr hwp) -{ - hwp->IOBase = (hwp->readMiscOut(hwp) & 0x01) ? - VGA_IOBASE_COLOR : VGA_IOBASE_MONO; - xf86DrvMsgVerb(hwp->pScrn->scrnIndex, X_INFO, 3, - "vgaHWGetIOBase: hwp->IOBase is 0x%04x, hwp->PIOOffset is 0x%04lx\n", - hwp->IOBase, hwp->PIOOffset); -} - - -void -vgaHWLock(vgaHWPtr hwp) -{ - /* Protect CRTC[0-7] */ - hwp->writeCrtc(hwp, 0x11, hwp->readCrtc(hwp, 0x11) | 0x80); -} - -void -vgaHWUnlock(vgaHWPtr hwp) -{ - /* Unprotect CRTC[0-7] */ - hwp->writeCrtc(hwp, 0x11, hwp->readCrtc(hwp, 0x11) & ~0x80); -} - - -void -vgaHWEnable(vgaHWPtr hwp) -{ - hwp->writeEnable(hwp, hwp->readEnable(hwp) | 0x01); -} - - -void -vgaHWDisable(vgaHWPtr hwp) -{ - hwp->writeEnable(hwp, hwp->readEnable(hwp) & ~0x01); -} - - -static void -vgaHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, - VisualPtr pVisual) -{ - vgaHWPtr hwp = VGAHWPTR(pScrn); - int i, index; - - for (i = 0; i < numColors; i++) { - index = indices[i]; - hwp->writeDacWriteAddr(hwp, index); - DACDelay(hwp); - hwp->writeDacData(hwp, colors[index].red); - DACDelay(hwp); - hwp->writeDacData(hwp, colors[index].green); - DACDelay(hwp); - hwp->writeDacData(hwp, colors[index].blue); - DACDelay(hwp); - } - - /* This shouldn't be necessary, but we'll play safe. */ - hwp->disablePalette(hwp); -} - - -static void -vgaHWSetOverscan(ScrnInfoPtr pScrn, int overscan) -{ - vgaHWPtr hwp = VGAHWPTR(pScrn); - - if (overscan < 0 || overscan > 255) - return; - - hwp->enablePalette(hwp); - hwp->writeAttr(hwp, OVERSCAN, overscan); - -#ifdef DEBUGOVERSCAN - { - int ov = hwp->readAttr(hwp, OVERSCAN); - int red, green, blue; - - hwp->writeDacReadAddr(hwp, ov); - red = hwp->readDacData(hwp); - green = hwp->readDacData(hwp); - blue = hwp->readDacData(hwp); - ErrorF("Overscan index is 0x%02x, colours are #%02x%02x%02x\n", - ov, red, green, blue); - } -#endif - - hwp->disablePalette(hwp); -} - - -Bool -vgaHWHandleColormaps(ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - - if (pScrn->depth > 1 && pScrn->depth <= 8) { - return xf86HandleColormaps(pScreen, 1 << pScrn->depth, - pScrn->rgbBits, vgaHWLoadPalette, - pScrn->depth > 4 ? vgaHWSetOverscan : NULL, - CMAP_RELOAD_ON_MODE_SWITCH); - } - return TRUE; -} - -/* ----------------------- DDC support ------------------------*/ -/* - * Adjust v_active, v_blank, v_sync, v_sync_end, v_blank_end, v_total - * to read out EDID at a faster rate. Allowed maximum is 25kHz with - * 20 usec v_sync active. Set positive v_sync polarity, turn off lightpen - * readback, enable access to cr00-cr07. - */ - -/* vertical timings */ -#define DISPLAY_END 0x04 -#define BLANK_START DISPLAY_END -#define SYNC_START BLANK_START -#define SYNC_END 0x09 -#define BLANK_END SYNC_END -#define V_TOTAL BLANK_END -/* this function doesn't have to be reentrant for our purposes */ -struct _vgaDdcSave { - unsigned char cr03; - unsigned char cr06; - unsigned char cr07; - unsigned char cr09; - unsigned char cr10; - unsigned char cr11; - unsigned char cr12; - unsigned char cr15; - unsigned char cr16; - unsigned char msr; -}; - -void -vgaHWddc1SetSpeed(ScrnInfoPtr pScrn, xf86ddcSpeed speed) -{ - vgaHWPtr hwp = VGAHWPTR(pScrn); - unsigned char tmp; - struct _vgaDdcSave* save; - switch (speed) { - case DDC_FAST: - - if (hwp->ddc != NULL) break; - hwp->ddc = xnfcalloc(sizeof(struct _vgaDdcSave),1); - save = (struct _vgaDdcSave *)hwp->ddc; - /* Lightpen register disable - allow access to cr10 & 11; just in case */ - save->cr03 = hwp->readCrtc(hwp, 0x03); - hwp->writeCrtc(hwp,0x03,(save->cr03 |0x80)); - save->cr12 = hwp->readCrtc(hwp, 0x12); - hwp->writeCrtc(hwp,0x12,DISPLAY_END); - save->cr15 = hwp->readCrtc(hwp, 0x15); - hwp->writeCrtc(hwp,0x15,BLANK_START); - save->cr10 = hwp->readCrtc(hwp, 0x10); - hwp->writeCrtc(hwp,0x10,SYNC_START); - save->cr11 = hwp->readCrtc(hwp, 0x11); - /* unprotect group 1 registers; just in case ...*/ - hwp->writeCrtc(hwp,0x11,((save->cr11 & 0x70) | SYNC_END)); - save->cr16 = hwp->readCrtc(hwp, 0x16); - hwp->writeCrtc(hwp,0x16,BLANK_END); - save->cr06 = hwp->readCrtc(hwp, 0x06); - hwp->writeCrtc(hwp,0x06,V_TOTAL); - /* all values have less than 8 bit - mask out 9th and 10th bits */ - save->cr09 = hwp->readCrtc(hwp, 0x09); - hwp->writeCrtc(hwp,0x09,(save->cr09 &0xDF)); - save->cr07 = hwp->readCrtc(hwp, 0x07); - hwp->writeCrtc(hwp,0x07,(save->cr07 &0x10)); - /* vsync polarity negativ & ensure a 25MHz clock */ - save->msr = hwp->readMiscOut(hwp); - hwp->writeMiscOut(hwp,((save->msr & 0xF3) | 0x80)); - break; - case DDC_SLOW: - if (hwp->ddc == NULL) break; - save = (struct _vgaDdcSave *)hwp->ddc; - hwp->writeMiscOut(hwp,save->msr); - hwp->writeCrtc(hwp,0x07,save->cr07); - tmp = hwp->readCrtc(hwp, 0x09); - hwp->writeCrtc(hwp,0x09,((save->cr09 & 0x20) | (tmp & 0xDF))); - hwp->writeCrtc(hwp,0x06,save->cr06); - hwp->writeCrtc(hwp,0x16,save->cr16); - hwp->writeCrtc(hwp,0x11,save->cr11); - hwp->writeCrtc(hwp,0x10,save->cr10); - hwp->writeCrtc(hwp,0x15,save->cr15); - hwp->writeCrtc(hwp,0x12,save->cr12); - hwp->writeCrtc(hwp,0x03,save->cr03); - xfree(save); - hwp->ddc = NULL; - break; - default: - break; - } -} - -DDC1SetSpeedProc -vgaHWddc1SetSpeedWeak(void) -{ - return vgaHWddc1SetSpeed; -} - -SaveScreenProcPtr vgaHWSaveScreenWeak(void) -{ - return vgaHWSaveScreen; -} + +/* + * + * Copyright 1991-1999 by The XFree86 Project, Inc. + * + * Loosely based on code bearing the following copyright: + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + */ + +#define _NEED_SYSI86 + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <X11/X.h> +#include "misc.h" + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "vgaHW.h" + +#include "compiler.h" + +#include "xf86cmap.h" + +#include "Pci.h" + +#ifndef SAVE_FONT1 +#define SAVE_FONT1 1 +#endif + +/* + * These used to be OS-specific, which made this module have an undesirable + * OS dependency. Define them by default for all platforms. + */ +#ifndef NEED_SAVED_CMAP +#define NEED_SAVED_CMAP +#endif +#ifndef SAVE_TEXT +#define SAVE_TEXT 1 +#endif +#ifndef SAVE_FONT2 +#define SAVE_FONT2 1 +#endif + +/* bytes per plane to save for text */ +#define TEXT_AMOUNT 16384 + +/* bytes per plane to save for font data */ +#define FONT_AMOUNT (8*8192) + +#if 0 +/* Override all of these for now */ +#undef SAVE_FONT1 +#define SAVE_FONT1 1 +#undef SAVE_FONT2 +#define SAVE_FONT2 1 +#undef SAVE_TEST +#define SAVE_TEST 1 +#undef FONT_AMOUNT +#define FONT_AMOUNT 65536 +#undef TEXT_AMOUNT +#define TEXT_AMOUNT 65536 +#endif + +/* DAC indices for white and black */ +#define WHITE_VALUE 0x3F +#define BLACK_VALUE 0x00 +#define OVERSCAN_VALUE 0x01 + + +/* Use a private definition of this here */ +#undef VGAHWPTR +#define VGAHWPTRLVAL(p) (p)->privates[vgaHWPrivateIndex].ptr +#define VGAHWPTR(p) ((vgaHWPtr)(VGAHWPTRLVAL(p))) + +static int vgaHWPrivateIndex = -1; + +#define DAC_TEST_MASK 0x3F + +#ifdef NEED_SAVED_CMAP +/* This default colourmap is used only when it can't be read from the VGA */ + +static CARD8 defaultDAC[768] = +{ + 0, 0, 0, 0, 0, 42, 0, 42, 0, 0, 42, 42, + 42, 0, 0, 42, 0, 42, 42, 21, 0, 42, 42, 42, + 21, 21, 21, 21, 21, 63, 21, 63, 21, 21, 63, 63, + 63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63, + 0, 0, 0, 5, 5, 5, 8, 8, 8, 11, 11, 11, + 14, 14, 14, 17, 17, 17, 20, 20, 20, 24, 24, 24, + 28, 28, 28, 32, 32, 32, 36, 36, 36, 40, 40, 40, + 45, 45, 45, 50, 50, 50, 56, 56, 56, 63, 63, 63, + 0, 0, 63, 16, 0, 63, 31, 0, 63, 47, 0, 63, + 63, 0, 63, 63, 0, 47, 63, 0, 31, 63, 0, 16, + 63, 0, 0, 63, 16, 0, 63, 31, 0, 63, 47, 0, + 63, 63, 0, 47, 63, 0, 31, 63, 0, 16, 63, 0, + 0, 63, 0, 0, 63, 16, 0, 63, 31, 0, 63, 47, + 0, 63, 63, 0, 47, 63, 0, 31, 63, 0, 16, 63, + 31, 31, 63, 39, 31, 63, 47, 31, 63, 55, 31, 63, + 63, 31, 63, 63, 31, 55, 63, 31, 47, 63, 31, 39, + 63, 31, 31, 63, 39, 31, 63, 47, 31, 63, 55, 31, + 63, 63, 31, 55, 63, 31, 47, 63, 31, 39, 63, 31, + 31, 63, 31, 31, 63, 39, 31, 63, 47, 31, 63, 55, + 31, 63, 63, 31, 55, 63, 31, 47, 63, 31, 39, 63, + 45, 45, 63, 49, 45, 63, 54, 45, 63, 58, 45, 63, + 63, 45, 63, 63, 45, 58, 63, 45, 54, 63, 45, 49, + 63, 45, 45, 63, 49, 45, 63, 54, 45, 63, 58, 45, + 63, 63, 45, 58, 63, 45, 54, 63, 45, 49, 63, 45, + 45, 63, 45, 45, 63, 49, 45, 63, 54, 45, 63, 58, + 45, 63, 63, 45, 58, 63, 45, 54, 63, 45, 49, 63, + 0, 0, 28, 7, 0, 28, 14, 0, 28, 21, 0, 28, + 28, 0, 28, 28, 0, 21, 28, 0, 14, 28, 0, 7, + 28, 0, 0, 28, 7, 0, 28, 14, 0, 28, 21, 0, + 28, 28, 0, 21, 28, 0, 14, 28, 0, 7, 28, 0, + 0, 28, 0, 0, 28, 7, 0, 28, 14, 0, 28, 21, + 0, 28, 28, 0, 21, 28, 0, 14, 28, 0, 7, 28, + 14, 14, 28, 17, 14, 28, 21, 14, 28, 24, 14, 28, + 28, 14, 28, 28, 14, 24, 28, 14, 21, 28, 14, 17, + 28, 14, 14, 28, 17, 14, 28, 21, 14, 28, 24, 14, + 28, 28, 14, 24, 28, 14, 21, 28, 14, 17, 28, 14, + 14, 28, 14, 14, 28, 17, 14, 28, 21, 14, 28, 24, + 14, 28, 28, 14, 24, 28, 14, 21, 28, 14, 17, 28, + 20, 20, 28, 22, 20, 28, 24, 20, 28, 26, 20, 28, + 28, 20, 28, 28, 20, 26, 28, 20, 24, 28, 20, 22, + 28, 20, 20, 28, 22, 20, 28, 24, 20, 28, 26, 20, + 28, 28, 20, 26, 28, 20, 24, 28, 20, 22, 28, 20, + 20, 28, 20, 20, 28, 22, 20, 28, 24, 20, 28, 26, + 20, 28, 28, 20, 26, 28, 20, 24, 28, 20, 22, 28, + 0, 0, 16, 4, 0, 16, 8, 0, 16, 12, 0, 16, + 16, 0, 16, 16, 0, 12, 16, 0, 8, 16, 0, 4, + 16, 0, 0, 16, 4, 0, 16, 8, 0, 16, 12, 0, + 16, 16, 0, 12, 16, 0, 8, 16, 0, 4, 16, 0, + 0, 16, 0, 0, 16, 4, 0, 16, 8, 0, 16, 12, + 0, 16, 16, 0, 12, 16, 0, 8, 16, 0, 4, 16, + 8, 8, 16, 10, 8, 16, 12, 8, 16, 14, 8, 16, + 16, 8, 16, 16, 8, 14, 16, 8, 12, 16, 8, 10, + 16, 8, 8, 16, 10, 8, 16, 12, 8, 16, 14, 8, + 16, 16, 8, 14, 16, 8, 12, 16, 8, 10, 16, 8, + 8, 16, 8, 8, 16, 10, 8, 16, 12, 8, 16, 14, + 8, 16, 16, 8, 14, 16, 8, 12, 16, 8, 10, 16, + 11, 11, 16, 12, 11, 16, 13, 11, 16, 15, 11, 16, + 16, 11, 16, 16, 11, 15, 16, 11, 13, 16, 11, 12, + 16, 11, 11, 16, 12, 11, 16, 13, 11, 16, 15, 11, + 16, 16, 11, 15, 16, 11, 13, 16, 11, 12, 16, 11, + 11, 16, 11, 11, 16, 12, 11, 16, 13, 11, 16, 15, + 11, 16, 16, 11, 15, 16, 11, 13, 16, 11, 12, 16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#endif /* NEED_SAVED_CMAP */ + +/* + * Standard VGA versions of the register access functions. + */ +static void +stdWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value) +{ + outb(hwp->IOBase + hwp->PIOOffset + VGA_CRTC_INDEX_OFFSET, index); + outb(hwp->IOBase + hwp->PIOOffset + VGA_CRTC_DATA_OFFSET, value); +} + +static CARD8 +stdReadCrtc(vgaHWPtr hwp, CARD8 index) +{ + outb(hwp->IOBase + hwp->PIOOffset + VGA_CRTC_INDEX_OFFSET, index); + return inb(hwp->IOBase + hwp->PIOOffset + VGA_CRTC_DATA_OFFSET); +} + +static void +stdWriteGr(vgaHWPtr hwp, CARD8 index, CARD8 value) +{ + outb(hwp->PIOOffset + VGA_GRAPH_INDEX, index); + outb(hwp->PIOOffset + VGA_GRAPH_DATA, value); +} + +static CARD8 +stdReadGr(vgaHWPtr hwp, CARD8 index) +{ + outb(hwp->PIOOffset + VGA_GRAPH_INDEX, index); + return inb(hwp->PIOOffset + VGA_GRAPH_DATA); +} + +static void +stdWriteSeq(vgaHWPtr hwp, CARD8 index, CARD8 value) +{ + outb(hwp->PIOOffset + VGA_SEQ_INDEX, index); + outb(hwp->PIOOffset + VGA_SEQ_DATA, value); +} + +static CARD8 +stdReadSeq(vgaHWPtr hwp, CARD8 index) +{ + outb(hwp->PIOOffset + VGA_SEQ_INDEX, index); + return inb(hwp->PIOOffset + VGA_SEQ_DATA); +} + +static CARD8 +stdReadST00(vgaHWPtr hwp) +{ + return inb(hwp->PIOOffset + VGA_IN_STAT_0); +} + +static CARD8 +stdReadST01(vgaHWPtr hwp) +{ + return inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); +} + +static CARD8 +stdReadFCR(vgaHWPtr hwp) +{ + return inb(hwp->PIOOffset + VGA_FEATURE_R); +} + +static void +stdWriteFCR(vgaHWPtr hwp, CARD8 value) +{ + outb(hwp->IOBase + hwp->PIOOffset + VGA_FEATURE_W_OFFSET,value); +} + +static void +stdWriteAttr(vgaHWPtr hwp, CARD8 index, CARD8 value) +{ + if (hwp->paletteEnabled) + index &= ~0x20; + else + index |= 0x20; + + (void) inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); + outb(hwp->PIOOffset + VGA_ATTR_INDEX, index); + outb(hwp->PIOOffset + VGA_ATTR_DATA_W, value); +} + +static CARD8 +stdReadAttr(vgaHWPtr hwp, CARD8 index) +{ + if (hwp->paletteEnabled) + index &= ~0x20; + else + index |= 0x20; + + (void) inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); + outb(hwp->PIOOffset + VGA_ATTR_INDEX, index); + return inb(hwp->PIOOffset + VGA_ATTR_DATA_R); +} + +static void +stdWriteMiscOut(vgaHWPtr hwp, CARD8 value) +{ + outb(hwp->PIOOffset + VGA_MISC_OUT_W, value); +} + +static CARD8 +stdReadMiscOut(vgaHWPtr hwp) +{ + return inb(hwp->PIOOffset + VGA_MISC_OUT_R); +} + +static void +stdEnablePalette(vgaHWPtr hwp) +{ + (void) inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); + outb(hwp->PIOOffset + VGA_ATTR_INDEX, 0x00); + hwp->paletteEnabled = TRUE; +} + +static void +stdDisablePalette(vgaHWPtr hwp) +{ + (void) inb(hwp->IOBase + hwp->PIOOffset + VGA_IN_STAT_1_OFFSET); + outb(hwp->PIOOffset + VGA_ATTR_INDEX, 0x20); + hwp->paletteEnabled = FALSE; +} + +static void +stdWriteDacMask(vgaHWPtr hwp, CARD8 value) +{ + outb(hwp->PIOOffset + VGA_DAC_MASK, value); +} + +static CARD8 +stdReadDacMask(vgaHWPtr hwp) +{ + return inb(hwp->PIOOffset + VGA_DAC_MASK); +} + +static void +stdWriteDacReadAddr(vgaHWPtr hwp, CARD8 value) +{ + outb(hwp->PIOOffset + VGA_DAC_READ_ADDR, value); +} + +static void +stdWriteDacWriteAddr(vgaHWPtr hwp, CARD8 value) +{ + outb(hwp->PIOOffset + VGA_DAC_WRITE_ADDR, value); +} + +static void +stdWriteDacData(vgaHWPtr hwp, CARD8 value) +{ + outb(hwp->PIOOffset + VGA_DAC_DATA, value); +} + +static CARD8 +stdReadDacData(vgaHWPtr hwp) +{ + return inb(hwp->PIOOffset + VGA_DAC_DATA); +} + +static CARD8 +stdReadEnable(vgaHWPtr hwp) +{ + return inb(hwp->PIOOffset + VGA_ENABLE); +} + +static void +stdWriteEnable(vgaHWPtr hwp, CARD8 value) +{ + outb(hwp->PIOOffset + VGA_ENABLE, value); +} + +void +vgaHWSetStdFuncs(vgaHWPtr hwp) +{ + hwp->writeCrtc = stdWriteCrtc; + hwp->readCrtc = stdReadCrtc; + hwp->writeGr = stdWriteGr; + hwp->readGr = stdReadGr; + hwp->readST00 = stdReadST00; + hwp->readST01 = stdReadST01; + hwp->readFCR = stdReadFCR; + hwp->writeFCR = stdWriteFCR; + hwp->writeAttr = stdWriteAttr; + hwp->readAttr = stdReadAttr; + hwp->writeSeq = stdWriteSeq; + hwp->readSeq = stdReadSeq; + hwp->writeMiscOut = stdWriteMiscOut; + hwp->readMiscOut = stdReadMiscOut; + hwp->enablePalette = stdEnablePalette; + hwp->disablePalette = stdDisablePalette; + hwp->writeDacMask = stdWriteDacMask; + hwp->readDacMask = stdReadDacMask; + hwp->writeDacWriteAddr = stdWriteDacWriteAddr; + hwp->writeDacReadAddr = stdWriteDacReadAddr; + hwp->writeDacData = stdWriteDacData; + hwp->readDacData = stdReadDacData; + hwp->PIOOffset = 0; + hwp->readEnable = stdReadEnable; + hwp->writeEnable = stdWriteEnable; +} + +/* + * MMIO versions of the register access functions. These require + * hwp->MemBase to be set in such a way that when the standard VGA port + * adderss is added the correct memory address results. + */ + +#define minb(p) MMIO_IN8(hwp->MMIOBase, (hwp->MMIOOffset + (p))) +#define moutb(p,v) MMIO_OUT8(hwp->MMIOBase, (hwp->MMIOOffset + (p)),(v)) + +static void +mmioWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value) +{ + moutb(hwp->IOBase + VGA_CRTC_INDEX_OFFSET, index); + moutb(hwp->IOBase + VGA_CRTC_DATA_OFFSET, value); +} + +static CARD8 +mmioReadCrtc(vgaHWPtr hwp, CARD8 index) +{ + moutb(hwp->IOBase + VGA_CRTC_INDEX_OFFSET, index); + return minb(hwp->IOBase + VGA_CRTC_DATA_OFFSET); +} + +static void +mmioWriteGr(vgaHWPtr hwp, CARD8 index, CARD8 value) +{ + moutb(VGA_GRAPH_INDEX, index); + moutb(VGA_GRAPH_DATA, value); +} + +static CARD8 +mmioReadGr(vgaHWPtr hwp, CARD8 index) +{ + moutb(VGA_GRAPH_INDEX, index); + return minb(VGA_GRAPH_DATA); +} + +static void +mmioWriteSeq(vgaHWPtr hwp, CARD8 index, CARD8 value) +{ + moutb(VGA_SEQ_INDEX, index); + moutb(VGA_SEQ_DATA, value); +} + +static CARD8 +mmioReadSeq(vgaHWPtr hwp, CARD8 index) +{ + moutb(VGA_SEQ_INDEX, index); + return minb(VGA_SEQ_DATA); +} + +static CARD8 +mmioReadST00(vgaHWPtr hwp) +{ + return minb(VGA_IN_STAT_0); +} + +static CARD8 +mmioReadST01(vgaHWPtr hwp) +{ + return minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); +} + +static CARD8 +mmioReadFCR(vgaHWPtr hwp) +{ + return minb(VGA_FEATURE_R); +} + +static void +mmioWriteFCR(vgaHWPtr hwp, CARD8 value) +{ + moutb(hwp->IOBase + VGA_FEATURE_W_OFFSET,value); +} + +static void +mmioWriteAttr(vgaHWPtr hwp, CARD8 index, CARD8 value) +{ + if (hwp->paletteEnabled) + index &= ~0x20; + else + index |= 0x20; + + (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); + moutb(VGA_ATTR_INDEX, index); + moutb(VGA_ATTR_DATA_W, value); +} + +static CARD8 +mmioReadAttr(vgaHWPtr hwp, CARD8 index) +{ + if (hwp->paletteEnabled) + index &= ~0x20; + else + index |= 0x20; + + (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); + moutb(VGA_ATTR_INDEX, index); + return minb(VGA_ATTR_DATA_R); +} + +static void +mmioWriteMiscOut(vgaHWPtr hwp, CARD8 value) +{ + moutb(VGA_MISC_OUT_W, value); +} + +static CARD8 +mmioReadMiscOut(vgaHWPtr hwp) +{ + return minb(VGA_MISC_OUT_R); +} + +static void +mmioEnablePalette(vgaHWPtr hwp) +{ + (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); + moutb(VGA_ATTR_INDEX, 0x00); + hwp->paletteEnabled = TRUE; +} + +static void +mmioDisablePalette(vgaHWPtr hwp) +{ + (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); + moutb(VGA_ATTR_INDEX, 0x20); + hwp->paletteEnabled = FALSE; +} + +static void +mmioWriteDacMask(vgaHWPtr hwp, CARD8 value) +{ + moutb(VGA_DAC_MASK, value); +} + +static CARD8 +mmioReadDacMask(vgaHWPtr hwp) +{ + return minb(VGA_DAC_MASK); +} + +static void +mmioWriteDacReadAddr(vgaHWPtr hwp, CARD8 value) +{ + moutb(VGA_DAC_READ_ADDR, value); +} + +static void +mmioWriteDacWriteAddr(vgaHWPtr hwp, CARD8 value) +{ + moutb(VGA_DAC_WRITE_ADDR, value); +} + +static void +mmioWriteDacData(vgaHWPtr hwp, CARD8 value) +{ + moutb(VGA_DAC_DATA, value); +} + +static CARD8 +mmioReadDacData(vgaHWPtr hwp) +{ + return minb(VGA_DAC_DATA); +} + +static CARD8 +mmioReadEnable(vgaHWPtr hwp) +{ + return minb(VGA_ENABLE); +} + +static void +mmioWriteEnable(vgaHWPtr hwp, CARD8 value) +{ + moutb(VGA_ENABLE, value); +} + +void +vgaHWSetMmioFuncs(vgaHWPtr hwp, CARD8 *base, int offset) +{ + hwp->writeCrtc = mmioWriteCrtc; + hwp->readCrtc = mmioReadCrtc; + hwp->writeGr = mmioWriteGr; + hwp->readGr = mmioReadGr; + hwp->readST00 = mmioReadST00; + hwp->readST01 = mmioReadST01; + hwp->readFCR = mmioReadFCR; + hwp->writeFCR = mmioWriteFCR; + hwp->writeAttr = mmioWriteAttr; + hwp->readAttr = mmioReadAttr; + hwp->writeSeq = mmioWriteSeq; + hwp->readSeq = mmioReadSeq; + hwp->writeMiscOut = mmioWriteMiscOut; + hwp->readMiscOut = mmioReadMiscOut; + hwp->enablePalette = mmioEnablePalette; + hwp->disablePalette = mmioDisablePalette; + hwp->writeDacMask = mmioWriteDacMask; + hwp->readDacMask = mmioReadDacMask; + hwp->writeDacWriteAddr = mmioWriteDacWriteAddr; + hwp->writeDacReadAddr = mmioWriteDacReadAddr; + hwp->writeDacData = mmioWriteDacData; + hwp->readDacData = mmioReadDacData; + hwp->MMIOBase = base; + hwp->MMIOOffset = offset; + hwp->readEnable = mmioReadEnable; + hwp->writeEnable = mmioWriteEnable; +} + +/* + * vgaHWProtect -- + * Protect VGA registers and memory from corruption during loads. + */ + +void +vgaHWProtect(ScrnInfoPtr pScrn, Bool on) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + + unsigned char tmp; + + if (pScrn->vtSema) { + if (on) { + /* + * Turn off screen and disable sequencer. + */ + tmp = hwp->readSeq(hwp, 0x01); + + vgaHWSeqReset(hwp, TRUE); /* start synchronous reset */ + hwp->writeSeq(hwp, 0x01, tmp | 0x20); /* disable the display */ + + hwp->enablePalette(hwp); + } else { + /* + * Reenable sequencer, then turn on screen. + */ + + tmp = hwp->readSeq(hwp, 0x01); + + hwp->writeSeq(hwp, 0x01, tmp & ~0x20); /* reenable display */ + vgaHWSeqReset(hwp, FALSE); /* clear synchronousreset */ + + hwp->disablePalette(hwp); + } + } +} + +vgaHWProtectProc *vgaHWProtectWeak(void) { + return vgaHWProtect; +} + +/* + * vgaHWBlankScreen -- blank the screen. + */ + +void +vgaHWBlankScreen(ScrnInfoPtr pScrn, Bool on) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + unsigned char scrn; + + scrn = hwp->readSeq(hwp, 0x01); + + if (on) { + scrn &= ~0x20; /* enable screen */ + } else { + scrn |= 0x20; /* blank screen */ + } + + vgaHWSeqReset(hwp, TRUE); + hwp->writeSeq(hwp, 0x01, scrn); /* change mode */ + vgaHWSeqReset(hwp, FALSE); +} + +vgaHWBlankScreenProc *vgaHWBlankScreenWeak(void) { + return vgaHWBlankScreen; +} + +/* + * vgaHWSaveScreen -- blank the screen. + */ + +Bool +vgaHWSaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = NULL; + Bool on; + + if (pScreen != NULL) + pScrn = xf86Screens[pScreen->myNum]; + + on = xf86IsUnblank(mode); + +#if 0 + if (on) + SetTimeSinceLastInputEvent(); +#endif + + if ((pScrn != NULL) && pScrn->vtSema) { + vgaHWBlankScreen(pScrn, on); + } + return (TRUE); +} + + +/* + * vgaHWDPMSSet -- Sets VESA Display Power Management Signaling (DPMS) Mode + * + * This generic VGA function can only set the Off and On modes. If the + * Standby and Suspend modes are to be supported, a chip specific replacement + * for this function must be written. + */ + +void +vgaHWDPMSSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) +{ + unsigned char seq1 = 0, crtc17 = 0; + vgaHWPtr hwp = VGAHWPTR(pScrn); + + if (!pScrn->vtSema) return; + + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + seq1 = 0x00; + crtc17 = 0x80; + break; + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On -- Not Supported */ + seq1 = 0x20; + crtc17 = 0x80; + break; + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off -- Not Supported */ + seq1 = 0x20; + crtc17 = 0x80; + break; + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + seq1 = 0x20; + crtc17 = 0x00; + break; + } + hwp->writeSeq(hwp, 0x00, 0x01); /* Synchronous Reset */ + seq1 |= hwp->readSeq(hwp, 0x01) & ~0x20; + hwp->writeSeq(hwp, 0x01, seq1); + crtc17 |= hwp->readCrtc(hwp, 0x17) & ~0x80; + usleep(10000); + hwp->writeCrtc(hwp, 0x17, crtc17); + hwp->writeSeq(hwp, 0x00, 0x03); /* End Reset */ +} + + +/* + * vgaHWSeqReset + * perform a sequencer reset. + */ + +void +vgaHWSeqReset(vgaHWPtr hwp, Bool start) +{ + if (start) + hwp->writeSeq(hwp, 0x00, 0x01); /* Synchronous Reset */ + else + hwp->writeSeq(hwp, 0x00, 0x03); /* End Reset */ +} + + +void +vgaHWRestoreFonts(ScrnInfoPtr scrninfp, vgaRegPtr restore) +{ +#if SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 + vgaHWPtr hwp = VGAHWPTR(scrninfp); + int savedIOBase; + unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4; + Bool doMap = FALSE; + + /* If nothing to do, return now */ + if (!hwp->FontInfo1 && !hwp->FontInfo2 && !hwp->TextInfo) + return; + + if (hwp->Base == NULL) { + doMap = TRUE; + if (!vgaHWMapMem(scrninfp)) { + xf86DrvMsg(scrninfp->scrnIndex, X_ERROR, + "vgaHWRestoreFonts: vgaHWMapMem() failed\n"); + return; + } + } + + /* save the registers that are needed here */ + miscOut = hwp->readMiscOut(hwp); + attr10 = hwp->readAttr(hwp, 0x10); + gr1 = hwp->readGr(hwp, 0x01); + gr3 = hwp->readGr(hwp, 0x03); + gr4 = hwp->readGr(hwp, 0x04); + gr5 = hwp->readGr(hwp, 0x05); + gr6 = hwp->readGr(hwp, 0x06); + gr8 = hwp->readGr(hwp, 0x08); + seq2 = hwp->readSeq(hwp, 0x02); + seq4 = hwp->readSeq(hwp, 0x04); + + /* save hwp->IOBase and temporarily set it for colour mode */ + savedIOBase = hwp->IOBase; + hwp->IOBase = VGA_IOBASE_COLOR; + + /* Force into colour mode */ + hwp->writeMiscOut(hwp, miscOut | 0x01); + + vgaHWBlankScreen(scrninfp, FALSE); + + /* + * here we temporarily switch to 16 colour planar mode, to simply + * copy the font-info and saved text. + * + * BUG ALERT: The (S)VGA's segment-select register MUST be set correctly! + */ +#if 0 + hwp->writeAttr(hwp, 0x10, 0x01); /* graphics mode */ +#endif + + hwp->writeSeq(hwp, 0x04, 0x06); /* enable plane graphics */ + hwp->writeGr(hwp, 0x05, 0x00); /* write mode 0, read mode 0 */ + hwp->writeGr(hwp, 0x06, 0x05); /* set graphics */ + + if (scrninfp->depth == 4) { + /* GJA */ + hwp->writeGr(hwp, 0x03, 0x00); /* don't rotate, write unmodified */ + hwp->writeGr(hwp, 0x08, 0xFF); /* write all bits in a byte */ + hwp->writeGr(hwp, 0x01, 0x00); /* all planes come from CPU */ + } + +#if SAVE_FONT1 + if (hwp->FontInfo1) { + hwp->writeSeq(hwp, 0x02, 0x04); /* write to plane 2 */ + hwp->writeGr(hwp, 0x04, 0x02); /* read plane 2 */ + slowbcopy_tobus(hwp->FontInfo1, hwp->Base, FONT_AMOUNT); + } +#endif + +#if SAVE_FONT2 + if (hwp->FontInfo2) { + hwp->writeSeq(hwp, 0x02, 0x08); /* write to plane 3 */ + hwp->writeGr(hwp, 0x04, 0x03); /* read plane 3 */ + slowbcopy_tobus(hwp->FontInfo2, hwp->Base, FONT_AMOUNT); + } +#endif + +#if SAVE_TEXT + if (hwp->TextInfo) { + hwp->writeSeq(hwp, 0x02, 0x01); /* write to plane 0 */ + hwp->writeGr(hwp, 0x04, 0x00); /* read plane 0 */ + slowbcopy_tobus(hwp->TextInfo, hwp->Base, TEXT_AMOUNT); + hwp->writeSeq(hwp, 0x02, 0x02); /* write to plane 1 */ + hwp->writeGr(hwp, 0x04, 0x01); /* read plane 1 */ + slowbcopy_tobus((unsigned char *)hwp->TextInfo + TEXT_AMOUNT, + hwp->Base, TEXT_AMOUNT); + } +#endif + + vgaHWBlankScreen(scrninfp, TRUE); + + /* restore the registers that were changed */ + hwp->writeMiscOut(hwp, miscOut); + hwp->writeAttr(hwp, 0x10, attr10); + hwp->writeGr(hwp, 0x01, gr1); + hwp->writeGr(hwp, 0x03, gr3); + hwp->writeGr(hwp, 0x04, gr4); + hwp->writeGr(hwp, 0x05, gr5); + hwp->writeGr(hwp, 0x06, gr6); + hwp->writeGr(hwp, 0x08, gr8); + hwp->writeSeq(hwp, 0x02, seq2); + hwp->writeSeq(hwp, 0x04, seq4); + hwp->IOBase = savedIOBase; + + if (doMap) + vgaHWUnmapMem(scrninfp); + +#endif /* SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 */ +} + + +void +vgaHWRestoreMode(ScrnInfoPtr scrninfp, vgaRegPtr restore) +{ + vgaHWPtr hwp = VGAHWPTR(scrninfp); + int i; + + if (restore->MiscOutReg & 0x01) + hwp->IOBase = VGA_IOBASE_COLOR; + else + hwp->IOBase = VGA_IOBASE_MONO; + + hwp->writeMiscOut(hwp, restore->MiscOutReg); + + for (i = 1; i < restore->numSequencer; i++) + hwp->writeSeq(hwp, i, restore->Sequencer[i]); + + /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17] */ + hwp->writeCrtc(hwp, 17, restore->CRTC[17] & ~0x80); + + for (i = 0; i < restore->numCRTC; i++) + hwp->writeCrtc(hwp, i, restore->CRTC[i]); + + for (i = 0; i < restore->numGraphics; i++) + hwp->writeGr(hwp, i, restore->Graphics[i]); + + hwp->enablePalette(hwp); + for (i = 0; i < restore->numAttribute; i++) + hwp->writeAttr(hwp, i, restore->Attribute[i]); + hwp->disablePalette(hwp); +} + + +void +vgaHWRestoreColormap(ScrnInfoPtr scrninfp, vgaRegPtr restore) +{ + vgaHWPtr hwp = VGAHWPTR(scrninfp); + int i; + +#if 0 + hwp->enablePalette(hwp); +#endif + + hwp->writeDacMask(hwp, 0xFF); + hwp->writeDacWriteAddr(hwp, 0x00); + for (i = 0; i < 768; i++) { + hwp->writeDacData(hwp, restore->DAC[i]); + DACDelay(hwp); + } + + hwp->disablePalette(hwp); +} + + +/* + * vgaHWRestore -- + * restore the VGA state + */ + +void +vgaHWRestore(ScrnInfoPtr scrninfp, vgaRegPtr restore, int flags) +{ + if (flags & VGA_SR_MODE) + vgaHWRestoreMode(scrninfp, restore); + + if (flags & VGA_SR_FONTS) + vgaHWRestoreFonts(scrninfp, restore); + + if (flags & VGA_SR_CMAP) + vgaHWRestoreColormap(scrninfp, restore); +} + +void +vgaHWSaveFonts(ScrnInfoPtr scrninfp, vgaRegPtr save) +{ +#if SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 + vgaHWPtr hwp = VGAHWPTR(scrninfp); + int savedIOBase; + unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4; + Bool doMap = FALSE; + + if (hwp->Base == NULL) { + doMap = TRUE; + if (!vgaHWMapMem(scrninfp)) { + xf86DrvMsg(scrninfp->scrnIndex, X_ERROR, + "vgaHWSaveFonts: vgaHWMapMem() failed\n"); + return; + } + } + + /* If in graphics mode, don't save anything */ + attr10 = hwp->readAttr(hwp, 0x10); + if (attr10 & 0x01) + return; + + /* save the registers that are needed here */ + miscOut = hwp->readMiscOut(hwp); + gr4 = hwp->readGr(hwp, 0x04); + gr5 = hwp->readGr(hwp, 0x05); + gr6 = hwp->readGr(hwp, 0x06); + seq2 = hwp->readSeq(hwp, 0x02); + seq4 = hwp->readSeq(hwp, 0x04); + + /* save hwp->IOBase and temporarily set it for colour mode */ + savedIOBase = hwp->IOBase; + hwp->IOBase = VGA_IOBASE_COLOR; + + /* Force into colour mode */ + hwp->writeMiscOut(hwp, miscOut | 0x01); + + vgaHWBlankScreen(scrninfp, FALSE); + + /* + * get the character sets, and text screen if required + */ + /* + * Here we temporarily switch to 16 colour planar mode, to simply + * copy the font-info + * + * BUG ALERT: The (S)VGA's segment-select register MUST be set correctly! + */ +#if 0 + hwp->writeAttr(hwp, 0x10, 0x01); /* graphics mode */ +#endif + + hwp->writeSeq(hwp, 0x04, 0x06); /* enable plane graphics */ + hwp->writeGr(hwp, 0x05, 0x00); /* write mode 0, read mode 0 */ + hwp->writeGr(hwp, 0x06, 0x05); /* set graphics */ + +#if SAVE_FONT1 + if (hwp->FontInfo1 || (hwp->FontInfo1 = malloc(FONT_AMOUNT))) { + hwp->writeSeq(hwp, 0x02, 0x04); /* write to plane 2 */ + hwp->writeGr(hwp, 0x04, 0x02); /* read plane 2 */ + slowbcopy_frombus(hwp->Base, hwp->FontInfo1, FONT_AMOUNT); + } +#endif /* SAVE_FONT1 */ +#if SAVE_FONT2 + if (hwp->FontInfo2 || (hwp->FontInfo2 = malloc(FONT_AMOUNT))) { + hwp->writeSeq(hwp, 0x02, 0x08); /* write to plane 3 */ + hwp->writeGr(hwp, 0x04, 0x03); /* read plane 3 */ + slowbcopy_frombus(hwp->Base, hwp->FontInfo2, FONT_AMOUNT); + } +#endif /* SAVE_FONT2 */ +#if SAVE_TEXT + if (hwp->TextInfo || (hwp->TextInfo = malloc(2 * TEXT_AMOUNT))) { + hwp->writeSeq(hwp, 0x02, 0x01); /* write to plane 0 */ + hwp->writeGr(hwp, 0x04, 0x00); /* read plane 0 */ + slowbcopy_frombus(hwp->Base, hwp->TextInfo, TEXT_AMOUNT); + hwp->writeSeq(hwp, 0x02, 0x02); /* write to plane 1 */ + hwp->writeGr(hwp, 0x04, 0x01); /* read plane 1 */ + slowbcopy_frombus(hwp->Base, + (unsigned char *)hwp->TextInfo + TEXT_AMOUNT, TEXT_AMOUNT); + } +#endif /* SAVE_TEXT */ + + /* Restore clobbered registers */ + hwp->writeAttr(hwp, 0x10, attr10); + hwp->writeSeq(hwp, 0x02, seq2); + hwp->writeSeq(hwp, 0x04, seq4); + hwp->writeGr(hwp, 0x04, gr4); + hwp->writeGr(hwp, 0x05, gr5); + hwp->writeGr(hwp, 0x06, gr6); + hwp->writeMiscOut(hwp, miscOut); + hwp->IOBase = savedIOBase; + + vgaHWBlankScreen(scrninfp, TRUE); + + if (doMap) + vgaHWUnmapMem(scrninfp); + +#endif /* SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 */ +} + +void +vgaHWSaveMode(ScrnInfoPtr scrninfp, vgaRegPtr save) +{ + vgaHWPtr hwp = VGAHWPTR(scrninfp); + int i; + + save->MiscOutReg = hwp->readMiscOut(hwp); + if (save->MiscOutReg & 0x01) + hwp->IOBase = VGA_IOBASE_COLOR; + else + hwp->IOBase = VGA_IOBASE_MONO; + + for (i = 0; i < save->numCRTC; i++) { + save->CRTC[i] = hwp->readCrtc(hwp, i); + DebugF("CRTC[0x%02x] = 0x%02x\n", i, save->CRTC[i]); + } + + hwp->enablePalette(hwp); + for (i = 0; i < save->numAttribute; i++) { + save->Attribute[i] = hwp->readAttr(hwp, i); + DebugF("Attribute[0x%02x] = 0x%02x\n", i, save->Attribute[i]); + } + hwp->disablePalette(hwp); + + for (i = 0; i < save->numGraphics; i++) { + save->Graphics[i] = hwp->readGr(hwp, i); + DebugF("Graphics[0x%02x] = 0x%02x\n", i, save->Graphics[i]); + } + + for (i = 1; i < save->numSequencer; i++) { + save->Sequencer[i] = hwp->readSeq(hwp, i); + DebugF("Sequencer[0x%02x] = 0x%02x\n", i, save->Sequencer[i]); + } +} + + +void +vgaHWSaveColormap(ScrnInfoPtr scrninfp, vgaRegPtr save) +{ + vgaHWPtr hwp = VGAHWPTR(scrninfp); + Bool readError = FALSE; + int i; + +#ifdef NEED_SAVED_CMAP + /* + * Some ET4000 chips from 1991 have a HW bug that prevents the reading + * of the color lookup table. Mask rev 9042EAI is known to have this bug. + * + * If the colourmap is not readable, we set the saved map to a default + * map (taken from Ferraro's "Programmer's Guide to the EGA and VGA + * Cards" 2nd ed). + */ + + /* Only save it once */ + if (hwp->cmapSaved) + return; + +#if 0 + hwp->enablePalette(hwp); +#endif + + hwp->writeDacMask(hwp, 0xFF); + + /* + * check if we can read the lookup table + */ + hwp->writeDacReadAddr(hwp, 0x00); + for (i = 0; i < 6; i++) { + save->DAC[i] = hwp->readDacData(hwp); + switch (i % 3) { + case 0: + DebugF("DAC[0x%02x] = 0x%02x, ", i / 3, save->DAC[i]); + break; + case 1: + DebugF("0x%02x, ", save->DAC[i]); + break; + case 2: + DebugF("0x%02x\n", save->DAC[i]); + } + } + + /* + * Check if we can read the palette - + * use foreground color to prevent flashing. + */ + hwp->writeDacWriteAddr(hwp, 0x01); + for (i = 3; i < 6; i++) + hwp->writeDacData(hwp, ~save->DAC[i] & DAC_TEST_MASK); + hwp->writeDacReadAddr(hwp, 0x01); + for (i = 3; i < 6; i++) { + if (hwp->readDacData(hwp) != (~save->DAC[i] & DAC_TEST_MASK)) + readError = TRUE; + } + hwp->writeDacWriteAddr(hwp, 0x01); + for (i = 3; i < 6; i++) + hwp->writeDacData(hwp, save->DAC[i]); + + if (readError) { + /* + * save the default lookup table + */ + memmove(save->DAC, defaultDAC, 768); + xf86DrvMsg(scrninfp->scrnIndex, X_WARNING, + "Cannot read colourmap from VGA. Will restore with default\n"); + } else { + /* save the colourmap */ + hwp->writeDacReadAddr(hwp, 0x02); + for (i = 6; i < 768; i++) { + save->DAC[i] = hwp->readDacData(hwp); + DACDelay(hwp); + switch (i % 3) { + case 0: + DebugF("DAC[0x%02x] = 0x%02x, ", i / 3, save->DAC[i]); + break; + case 1: + DebugF("0x%02x, ", save->DAC[i]); + break; + case 2: + DebugF("0x%02x\n", save->DAC[i]); + } + } + } + + hwp->disablePalette(hwp); + hwp->cmapSaved = TRUE; +#endif +} + +/* + * vgaHWSave -- + * save the current VGA state + */ + +void +vgaHWSave(ScrnInfoPtr scrninfp, vgaRegPtr save, int flags) +{ + if (save == NULL) + return; + + if (flags & VGA_SR_CMAP) + vgaHWSaveColormap(scrninfp, save); + + if (flags & VGA_SR_MODE) + vgaHWSaveMode(scrninfp, save); + + if (flags & VGA_SR_FONTS) + vgaHWSaveFonts(scrninfp, save); +} + + +/* + * vgaHWInit -- + * Handle the initialization, etc. of a screen. + * Return FALSE on failure. + */ + +Bool +vgaHWInit(ScrnInfoPtr scrninfp, DisplayModePtr mode) +{ + unsigned int i; + vgaHWPtr hwp; + vgaRegPtr regp; + int depth = scrninfp->depth; + + /* + * make sure the vgaHWRec is allocated + */ + if (!vgaHWGetHWRec(scrninfp)) + return FALSE; + hwp = VGAHWPTR(scrninfp); + regp = &hwp->ModeReg; + + /* + * compute correct Hsync & Vsync polarity + */ + if ((mode->Flags & (V_PHSYNC | V_NHSYNC)) + && (mode->Flags & (V_PVSYNC | V_NVSYNC))) + { + regp->MiscOutReg = 0x23; + if (mode->Flags & V_NHSYNC) regp->MiscOutReg |= 0x40; + if (mode->Flags & V_NVSYNC) regp->MiscOutReg |= 0x80; + } + else + { + int VDisplay = mode->VDisplay; + if (mode->Flags & V_DBLSCAN) + VDisplay *= 2; + if (mode->VScan > 1) + VDisplay *= mode->VScan; + if (VDisplay < 400) + regp->MiscOutReg = 0xA3; /* +hsync -vsync */ + else if (VDisplay < 480) + regp->MiscOutReg = 0x63; /* -hsync +vsync */ + else if (VDisplay < 768) + regp->MiscOutReg = 0xE3; /* -hsync -vsync */ + else + regp->MiscOutReg = 0x23; /* +hsync +vsync */ + } + + regp->MiscOutReg |= (mode->ClockIndex & 0x03) << 2; + + /* + * Time Sequencer + */ + if (depth == 4) + regp->Sequencer[0] = 0x02; + else + regp->Sequencer[0] = 0x00; + if (mode->Flags & V_CLKDIV2) + regp->Sequencer[1] = 0x09; + else + regp->Sequencer[1] = 0x01; + if (depth == 1) + regp->Sequencer[2] = 1 << BIT_PLANE; + else + regp->Sequencer[2] = 0x0F; + regp->Sequencer[3] = 0x00; /* Font select */ + if (depth < 8) + regp->Sequencer[4] = 0x06; /* Misc */ + else + regp->Sequencer[4] = 0x0E; /* Misc */ + + /* + * CRTC Controller + */ + regp->CRTC[0] = (mode->CrtcHTotal >> 3) - 5; + regp->CRTC[1] = (mode->CrtcHDisplay >> 3) - 1; + regp->CRTC[2] = (mode->CrtcHBlankStart >> 3) - 1; + regp->CRTC[3] = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80; + i = (((mode->CrtcHSkew << 2) + 0x10) & ~0x1F); + if (i < 0x80) + regp->CRTC[3] |= i; + regp->CRTC[4] = (mode->CrtcHSyncStart >> 3); + regp->CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) + | (((mode->CrtcHSyncEnd >> 3)) & 0x1F); + regp->CRTC[6] = (mode->CrtcVTotal - 2) & 0xFF; + regp->CRTC[7] = (((mode->CrtcVTotal - 2) & 0x100) >> 8) + | (((mode->CrtcVDisplay - 1) & 0x100) >> 7) + | ((mode->CrtcVSyncStart & 0x100) >> 6) + | (((mode->CrtcVBlankStart - 1) & 0x100) >> 5) + | 0x10 + | (((mode->CrtcVTotal - 2) & 0x200) >> 4) + | (((mode->CrtcVDisplay - 1) & 0x200) >> 3) + | ((mode->CrtcVSyncStart & 0x200) >> 2); + regp->CRTC[8] = 0x00; + regp->CRTC[9] = (((mode->CrtcVBlankStart - 1) & 0x200) >> 4) | 0x40; + if (mode->Flags & V_DBLSCAN) + regp->CRTC[9] |= 0x80; + if (mode->VScan >= 32) + regp->CRTC[9] |= 0x1F; + else if (mode->VScan > 1) + regp->CRTC[9] |= mode->VScan - 1; + regp->CRTC[10] = 0x00; + regp->CRTC[11] = 0x00; + regp->CRTC[12] = 0x00; + regp->CRTC[13] = 0x00; + regp->CRTC[14] = 0x00; + regp->CRTC[15] = 0x00; + regp->CRTC[16] = mode->CrtcVSyncStart & 0xFF; + regp->CRTC[17] = (mode->CrtcVSyncEnd & 0x0F) | 0x20; + regp->CRTC[18] = (mode->CrtcVDisplay - 1) & 0xFF; + regp->CRTC[19] = scrninfp->displayWidth >> 4; /* just a guess */ + regp->CRTC[20] = 0x00; + regp->CRTC[21] = (mode->CrtcVBlankStart - 1) & 0xFF; + regp->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; + if (depth < 8) + regp->CRTC[23] = 0xE3; + else + regp->CRTC[23] = 0xC3; + regp->CRTC[24] = 0xFF; + + vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); + vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); + + /* + * Theory resumes here.... + */ + + /* + * Graphics Display Controller + */ + regp->Graphics[0] = 0x00; + regp->Graphics[1] = 0x00; + regp->Graphics[2] = 0x00; + regp->Graphics[3] = 0x00; + if (depth == 1) { + regp->Graphics[4] = BIT_PLANE; + regp->Graphics[5] = 0x00; + } else { + regp->Graphics[4] = 0x00; + if (depth == 4) + regp->Graphics[5] = 0x02; + else + regp->Graphics[5] = 0x40; + } + regp->Graphics[6] = 0x05; /* only map 64k VGA memory !!!! */ + regp->Graphics[7] = 0x0F; + regp->Graphics[8] = 0xFF; + + if (depth == 1) { + /* Initialise the Mono map according to which bit-plane gets used */ + + Bool flipPixels = xf86GetFlipPixels(); + + for (i=0; i<16; i++) + if (((i & (1 << BIT_PLANE)) != 0) != flipPixels) + regp->Attribute[i] = WHITE_VALUE; + else + regp->Attribute[i] = BLACK_VALUE; + + regp->Attribute[16] = 0x01; /* -VGA2- */ /* wrong for the ET4000 */ + if (!hwp->ShowOverscan) + regp->Attribute[OVERSCAN] = OVERSCAN_VALUE; /* -VGA2- */ + } else { + regp->Attribute[0] = 0x00; /* standard colormap translation */ + regp->Attribute[1] = 0x01; + regp->Attribute[2] = 0x02; + regp->Attribute[3] = 0x03; + regp->Attribute[4] = 0x04; + regp->Attribute[5] = 0x05; + regp->Attribute[6] = 0x06; + regp->Attribute[7] = 0x07; + regp->Attribute[8] = 0x08; + regp->Attribute[9] = 0x09; + regp->Attribute[10] = 0x0A; + regp->Attribute[11] = 0x0B; + regp->Attribute[12] = 0x0C; + regp->Attribute[13] = 0x0D; + regp->Attribute[14] = 0x0E; + regp->Attribute[15] = 0x0F; + if (depth == 4) + regp->Attribute[16] = 0x81; /* wrong for the ET4000 */ + else + regp->Attribute[16] = 0x41; /* wrong for the ET4000 */ + /* Attribute[17] (overscan) initialised in vgaHWGetHWRec() */ + } + regp->Attribute[18] = 0x0F; + regp->Attribute[19] = 0x00; + regp->Attribute[20] = 0x00; + + return(TRUE); +} + + /* + * OK, so much for theory. Now, let's deal with the >real< world... + * + * The above CRTC settings are precise in theory, except that many, if not + * most, VGA clones fail to reset the blanking signal when the character or + * line counter reaches [HV]Total. In this case, the signal is only + * unblanked when the counter reaches [HV]BlankEnd (mod 64, 128 or 256 as + * the case may be) at the start of the >next< scanline or frame, which + * means only part of the screen shows. This affects how null overscans + * are to be implemented on such adapters. + * + * Henceforth, VGA cores that implement this broken, but unfortunately + * common, behaviour are to be designated as KGA's, in honour of Koen + * Gadeyne, whose zeal to eliminate overscans (read: fury) set in motion + * a series of events that led to the discovery of this problem. + * + * Some VGA's are KGA's only in the horizontal, or only in the vertical, + * some in both, others in neither. Don't let anyone tell you there is + * such a thing as a VGA "standard"... And, thank the Creator for the fact + * that Hilbert spaces are not yet implemented in this industry. + * + * The following implements a trick suggested by David Dawes. This sets + * [HV]BlankEnd to zero if the blanking interval does not already contain a + * 0-point, and decrements it by one otherwise. In the latter case, this + * will produce a left and/or top overscan which the colourmap code will + * (still) need to ensure is as close to black as possible. This will make + * the behaviour consistent across all chipsets, while allowing all + * chipsets to display the entire screen. Non-KGA drivers can ignore the + * following in their own copy of this code. + * + * -- TSI @ UQV, 1998.08.21 + */ + +CARD32 +vgaHWHBlankKGA(DisplayModePtr mode, vgaRegPtr regp, int nBits, + unsigned int Flags) +{ + int nExtBits = (nBits < 6) ? 0 : nBits - 6; + CARD32 ExtBits; + CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 6; + + regp->CRTC[3] = (regp->CRTC[3] & ~0x1F) + | (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F); + regp->CRTC[5] = (regp->CRTC[5] & ~0x80) + | ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2); + ExtBits = ((mode->CrtcHBlankEnd >> 3) - 1) & ExtBitMask; + + /* First the horizontal case */ + if ((Flags & KGA_FIX_OVERSCAN) + && ((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3))) + { + int i = (regp->CRTC[3] & 0x1F) + | ((regp->CRTC[5] & 0x80) >> 2) + | ExtBits; + if (Flags & KGA_ENABLE_ON_ZERO) { + if ((i-- > (((mode->CrtcHBlankStart >> 3) - 1) + & (0x3F | ExtBitMask))) + && (mode->CrtcHBlankEnd == mode->CrtcHTotal)) + i = 0; + } else if (Flags & KGA_BE_TOT_DEC) + i--; + regp->CRTC[3] = (regp->CRTC[3] & ~0x1F) | (i & 0x1F); + regp->CRTC[5] = (regp->CRTC[5] & ~0x80) | ((i << 2) & 0x80); + ExtBits = i & ExtBitMask; + } + return ExtBits >> 6; +} + + /* + * The vertical case is a little trickier. Some VGA's ignore bit 0x80 of + * CRTC[22]. Also, in some cases, a zero CRTC[22] will still blank the + * very first scanline in a double- or multi-scanned mode. This last case + * needs further investigation. + */ +CARD32 +vgaHWVBlankKGA(DisplayModePtr mode, vgaRegPtr regp, int nBits, + unsigned int Flags) +{ + CARD32 ExtBits; + CARD32 nExtBits = (nBits < 8) ? 0 : (nBits - 8); + CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 8; + /* If width is not known nBits should be 0. In this + * case BitMask is set to 0 so we can check for it. */ + CARD32 BitMask = (nBits < 7) ? 0 : ((1 << nExtBits) - 1); + int VBlankStart = (mode->CrtcVBlankStart - 1) & 0xFF; + regp->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; + ExtBits = (mode->CrtcVBlankEnd - 1) & ExtBitMask; + + if ((Flags & KGA_FIX_OVERSCAN) + && (mode->CrtcVBlankEnd == mode->CrtcVTotal)) + /* Null top overscan */ + { + int i = regp->CRTC[22] | ExtBits; + if (Flags & KGA_ENABLE_ON_ZERO) { + if (((BitMask && ((i & BitMask) > (VBlankStart & BitMask))) + || ((i > VBlankStart) && /* 8-bit case */ + ((i & 0x7F) > (VBlankStart & 0x7F)))) && /* 7-bit case */ + !(regp->CRTC[9] & 0x9F)) /* 1 scanline/row */ + i = 0; + else + i = (i - 1); + } else if (Flags & KGA_BE_TOT_DEC) + i = (i - 1); + + regp->CRTC[22] = i & 0xFF; + ExtBits = i & 0xFF00; + } + return ExtBits >> 8; +} + +/* + * these are some more hardware specific helpers, formerly in vga.c + */ +static void +vgaHWGetHWRecPrivate(void) +{ + if (vgaHWPrivateIndex < 0) + vgaHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + return; +} + + +static void +vgaHWFreeRegs(vgaRegPtr regp) +{ + if (regp->CRTC) + free(regp->CRTC); + + regp->CRTC = + regp->Sequencer = + regp->Graphics = + regp->Attribute = NULL; + + regp->numCRTC = + regp->numSequencer = + regp->numGraphics = + regp->numAttribute = 0; +} + + + +static Bool +vgaHWAllocRegs(vgaRegPtr regp) +{ + unsigned char *buf; + + if ((regp->numCRTC + regp->numSequencer + regp->numGraphics + + regp->numAttribute) == 0) + return FALSE; + + buf = calloc(regp->numCRTC + + regp->numSequencer + + regp->numGraphics + + regp->numAttribute, 1); + if (!buf) + return FALSE; + + regp->CRTC = buf; + regp->Sequencer = regp->CRTC + regp->numCRTC; + regp->Graphics = regp->Sequencer + regp->numSequencer; + regp->Attribute = regp->Graphics + regp->numGraphics; + + return TRUE; +} + + +Bool +vgaHWAllocDefaultRegs(vgaRegPtr regp) +{ + regp->numCRTC = VGA_NUM_CRTC; + regp->numSequencer = VGA_NUM_SEQ; + regp->numGraphics = VGA_NUM_GFX; + regp->numAttribute = VGA_NUM_ATTR; + + return vgaHWAllocRegs(regp); +} + + +Bool +vgaHWSetRegCounts(ScrnInfoPtr scrp, int numCRTC, int numSequencer, + int numGraphics, int numAttribute) +{ +#define VGAHWMINNUM(regtype) \ + ((newMode.num##regtype < regp->num##regtype) ? \ + (newMode.num##regtype) : (regp->num##regtype)) +#define VGAHWCOPYREGSET(regtype) \ + memcpy (newMode.regtype, regp->regtype, VGAHWMINNUM(regtype)) + + vgaRegRec newMode, newSaved; + vgaRegPtr regp; + + regp = &VGAHWPTR(scrp)->ModeReg; + memcpy (&newMode, regp, sizeof(vgaRegRec)); + + /* allocate space for new registers */ + + regp = &newMode; + regp->numCRTC = numCRTC; + regp->numSequencer = numSequencer; + regp->numGraphics = numGraphics; + regp->numAttribute = numAttribute; + if (!vgaHWAllocRegs(regp)) + return FALSE; + + regp = &VGAHWPTR(scrp)->SavedReg; + memcpy (&newSaved, regp, sizeof(vgaRegRec)); + + regp = &newSaved; + regp->numCRTC = numCRTC; + regp->numSequencer = numSequencer; + regp->numGraphics = numGraphics; + regp->numAttribute = numAttribute; + if (!vgaHWAllocRegs(regp)) { + vgaHWFreeRegs(&newMode); + return FALSE; + } + + /* allocations succeeded, copy register data into new space */ + + regp = &VGAHWPTR(scrp)->ModeReg; + VGAHWCOPYREGSET(CRTC); + VGAHWCOPYREGSET(Sequencer); + VGAHWCOPYREGSET(Graphics); + VGAHWCOPYREGSET(Attribute); + + regp = &VGAHWPTR(scrp)->SavedReg; + VGAHWCOPYREGSET(CRTC); + VGAHWCOPYREGSET(Sequencer); + VGAHWCOPYREGSET(Graphics); + VGAHWCOPYREGSET(Attribute); + + /* free old register arrays */ + + regp = &VGAHWPTR(scrp)->ModeReg; + vgaHWFreeRegs(regp); + memcpy(regp, &newMode, sizeof(vgaRegRec)); + + regp = &VGAHWPTR(scrp)->SavedReg; + vgaHWFreeRegs(regp); + memcpy(regp, &newSaved, sizeof(vgaRegRec)); + + return TRUE; + +#undef VGAHWMINNUM +#undef VGAHWCOPYREGSET +} + + +Bool +vgaHWCopyReg(vgaRegPtr dst, vgaRegPtr src) +{ + vgaHWFreeRegs(dst); + + memcpy(dst, src, sizeof(vgaRegRec)); + + if (!vgaHWAllocRegs(dst)) + return FALSE; + + memcpy(dst->CRTC, src->CRTC, src->numCRTC); + memcpy(dst->Sequencer, src->Sequencer, src->numSequencer); + memcpy(dst->Graphics, src->Graphics, src->numGraphics); + memcpy(dst->Attribute, src->Attribute, src->numAttribute); + + return TRUE; +} + + +Bool +vgaHWGetHWRec(ScrnInfoPtr scrp) +{ + vgaRegPtr regp; + vgaHWPtr hwp; + int i; + + /* + * Let's make sure that the private exists and allocate one. + */ + vgaHWGetHWRecPrivate(); + /* + * New privates are always set to NULL, so we can check if the allocation + * has already been done. + */ + if (VGAHWPTR(scrp)) + return TRUE; + hwp = VGAHWPTRLVAL(scrp) = xnfcalloc(sizeof(vgaHWRec), 1); + regp = &VGAHWPTR(scrp)->ModeReg; + + if ((!vgaHWAllocDefaultRegs(&VGAHWPTR(scrp)->SavedReg)) || + (!vgaHWAllocDefaultRegs(&VGAHWPTR(scrp)->ModeReg))) { + free(hwp); + return FALSE; + } + + if (scrp->bitsPerPixel == 1) { + rgb blackColour = scrp->display->blackColour, + whiteColour = scrp->display->whiteColour; + + if (blackColour.red > 0x3F) blackColour.red = 0x3F; + if (blackColour.green > 0x3F) blackColour.green = 0x3F; + if (blackColour.blue > 0x3F) blackColour.blue = 0x3F; + + if (whiteColour.red > 0x3F) whiteColour.red = 0x3F; + if (whiteColour.green > 0x3F) whiteColour.green = 0x3F; + if (whiteColour.blue > 0x3F) whiteColour.blue = 0x3F; + + if ((blackColour.red == whiteColour.red ) && + (blackColour.green == whiteColour.green) && + (blackColour.blue == whiteColour.blue )) { + blackColour.red ^= 0x3F; + blackColour.green ^= 0x3F; + blackColour.blue ^= 0x3F; + } + + /* + * initialize default colormap for monochrome + */ + for (i=0; i<3; i++) regp->DAC[i] = 0x00; + for (i=3; i<768; i++) regp->DAC[i] = 0x3F; + i = BLACK_VALUE * 3; + regp->DAC[i++] = blackColour.red; + regp->DAC[i++] = blackColour.green; + regp->DAC[i] = blackColour.blue; + i = WHITE_VALUE * 3; + regp->DAC[i++] = whiteColour.red; + regp->DAC[i++] = whiteColour.green; + regp->DAC[i] = whiteColour.blue; + i = OVERSCAN_VALUE * 3; + regp->DAC[i++] = 0x00; + regp->DAC[i++] = 0x00; + regp->DAC[i] = 0x00; + } else { + /* Set all colours to black */ + for (i=0; i<768; i++) regp->DAC[i] = 0x00; + /* ... and the overscan */ + if (scrp->depth >= 4) + regp->Attribute[OVERSCAN] = 0xFF; + } + if (xf86FindOption(scrp->confScreen->options, "ShowOverscan")) { + xf86MarkOptionUsedByName(scrp->confScreen->options, "ShowOverscan"); + xf86DrvMsg(scrp->scrnIndex, X_CONFIG, "Showing overscan area\n"); + regp->DAC[765] = 0x3F; + regp->DAC[766] = 0x00; + regp->DAC[767] = 0x3F; + regp->Attribute[OVERSCAN] = 0xFF; + hwp->ShowOverscan = TRUE; + } else + hwp->ShowOverscan = FALSE; + + hwp->paletteEnabled = FALSE; + hwp->cmapSaved = FALSE; + hwp->MapSize = 0; + hwp->pScrn = scrp; + + /* Initialise the function pointers with the standard VGA versions */ + vgaHWSetStdFuncs(hwp); + + hwp->PIOOffset = scrp->domainIOBase; + hwp->dev = xf86GetPciInfoForEntity(scrp->entityList[0]); + + return TRUE; +} + + +void +vgaHWFreeHWRec(ScrnInfoPtr scrp) +{ + if (vgaHWPrivateIndex >= 0) { + vgaHWPtr hwp = VGAHWPTR(scrp); + + if (!hwp) + return; + + free(hwp->FontInfo1); + free(hwp->FontInfo2); + free(hwp->TextInfo); + + vgaHWFreeRegs (&hwp->ModeReg); + vgaHWFreeRegs (&hwp->SavedReg); + + free(hwp); + VGAHWPTRLVAL(scrp) = NULL; + } +} + + +Bool +vgaHWMapMem(ScrnInfoPtr scrp) +{ + vgaHWPtr hwp = VGAHWPTR(scrp); + int scr_index = scrp->scrnIndex; + + if (hwp->Base) + return TRUE; + + /* If not set, initialise with the defaults */ + if (hwp->MapSize == 0) + hwp->MapSize = VGA_DEFAULT_MEM_SIZE; + if (hwp->MapPhys == 0) + hwp->MapPhys = VGA_DEFAULT_PHYS_ADDR; + + /* + * Map as VIDMEM_MMIO_32BIT because WC + * is bad when there is page flipping. + * XXX This is not correct but we do it + * for now. + */ + DebugF("Mapping VGAMem\n"); + hwp->Base = xf86MapDomainMemory(scr_index, VIDMEM_MMIO_32BIT, hwp->dev, + hwp->MapPhys, hwp->MapSize); + return hwp->Base != NULL; +} + + +void +vgaHWUnmapMem(ScrnInfoPtr scrp) +{ + vgaHWPtr hwp = VGAHWPTR(scrp); + int scr_index = scrp->scrnIndex; + + if (hwp->Base == NULL) + return; + + DebugF("Unmapping VGAMem\n"); + xf86UnMapVidMem(scr_index, hwp->Base, hwp->MapSize); + hwp->Base = NULL; +} + +int +vgaHWGetIndex(void) +{ + return vgaHWPrivateIndex; +} + + +void +vgaHWGetIOBase(vgaHWPtr hwp) +{ + hwp->IOBase = (hwp->readMiscOut(hwp) & 0x01) ? + VGA_IOBASE_COLOR : VGA_IOBASE_MONO; + xf86DrvMsgVerb(hwp->pScrn->scrnIndex, X_INFO, 3, + "vgaHWGetIOBase: hwp->IOBase is 0x%04x, hwp->PIOOffset is 0x%04lx\n", + hwp->IOBase, hwp->PIOOffset); +} + + +void +vgaHWLock(vgaHWPtr hwp) +{ + /* Protect CRTC[0-7] */ + hwp->writeCrtc(hwp, 0x11, hwp->readCrtc(hwp, 0x11) | 0x80); +} + +void +vgaHWUnlock(vgaHWPtr hwp) +{ + /* Unprotect CRTC[0-7] */ + hwp->writeCrtc(hwp, 0x11, hwp->readCrtc(hwp, 0x11) & ~0x80); +} + + +void +vgaHWEnable(vgaHWPtr hwp) +{ + hwp->writeEnable(hwp, hwp->readEnable(hwp) | 0x01); +} + + +void +vgaHWDisable(vgaHWPtr hwp) +{ + hwp->writeEnable(hwp, hwp->readEnable(hwp) & ~0x01); +} + + +static void +vgaHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, + VisualPtr pVisual) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + int i, index; + + for (i = 0; i < numColors; i++) { + index = indices[i]; + hwp->writeDacWriteAddr(hwp, index); + DACDelay(hwp); + hwp->writeDacData(hwp, colors[index].red); + DACDelay(hwp); + hwp->writeDacData(hwp, colors[index].green); + DACDelay(hwp); + hwp->writeDacData(hwp, colors[index].blue); + DACDelay(hwp); + } + + /* This shouldn't be necessary, but we'll play safe. */ + hwp->disablePalette(hwp); +} + + +static void +vgaHWSetOverscan(ScrnInfoPtr pScrn, int overscan) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + + if (overscan < 0 || overscan > 255) + return; + + hwp->enablePalette(hwp); + hwp->writeAttr(hwp, OVERSCAN, overscan); + +#ifdef DEBUGOVERSCAN + { + int ov = hwp->readAttr(hwp, OVERSCAN); + int red, green, blue; + + hwp->writeDacReadAddr(hwp, ov); + red = hwp->readDacData(hwp); + green = hwp->readDacData(hwp); + blue = hwp->readDacData(hwp); + ErrorF("Overscan index is 0x%02x, colours are #%02x%02x%02x\n", + ov, red, green, blue); + } +#endif + + hwp->disablePalette(hwp); +} + + +Bool +vgaHWHandleColormaps(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (pScrn->depth > 1 && pScrn->depth <= 8) { + return xf86HandleColormaps(pScreen, 1 << pScrn->depth, + pScrn->rgbBits, vgaHWLoadPalette, + pScrn->depth > 4 ? vgaHWSetOverscan : NULL, + CMAP_RELOAD_ON_MODE_SWITCH); + } + return TRUE; +} + +/* ----------------------- DDC support ------------------------*/ +/* + * Adjust v_active, v_blank, v_sync, v_sync_end, v_blank_end, v_total + * to read out EDID at a faster rate. Allowed maximum is 25kHz with + * 20 usec v_sync active. Set positive v_sync polarity, turn off lightpen + * readback, enable access to cr00-cr07. + */ + +/* vertical timings */ +#define DISPLAY_END 0x04 +#define BLANK_START DISPLAY_END +#define SYNC_START BLANK_START +#define SYNC_END 0x09 +#define BLANK_END SYNC_END +#define V_TOTAL BLANK_END +/* this function doesn't have to be reentrant for our purposes */ +struct _vgaDdcSave { + unsigned char cr03; + unsigned char cr06; + unsigned char cr07; + unsigned char cr09; + unsigned char cr10; + unsigned char cr11; + unsigned char cr12; + unsigned char cr15; + unsigned char cr16; + unsigned char msr; +}; + +void +vgaHWddc1SetSpeed(ScrnInfoPtr pScrn, xf86ddcSpeed speed) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + unsigned char tmp; + struct _vgaDdcSave* save; + switch (speed) { + case DDC_FAST: + + if (hwp->ddc != NULL) break; + hwp->ddc = xnfcalloc(sizeof(struct _vgaDdcSave),1); + save = (struct _vgaDdcSave *)hwp->ddc; + /* Lightpen register disable - allow access to cr10 & 11; just in case */ + save->cr03 = hwp->readCrtc(hwp, 0x03); + hwp->writeCrtc(hwp,0x03,(save->cr03 |0x80)); + save->cr12 = hwp->readCrtc(hwp, 0x12); + hwp->writeCrtc(hwp,0x12,DISPLAY_END); + save->cr15 = hwp->readCrtc(hwp, 0x15); + hwp->writeCrtc(hwp,0x15,BLANK_START); + save->cr10 = hwp->readCrtc(hwp, 0x10); + hwp->writeCrtc(hwp,0x10,SYNC_START); + save->cr11 = hwp->readCrtc(hwp, 0x11); + /* unprotect group 1 registers; just in case ...*/ + hwp->writeCrtc(hwp,0x11,((save->cr11 & 0x70) | SYNC_END)); + save->cr16 = hwp->readCrtc(hwp, 0x16); + hwp->writeCrtc(hwp,0x16,BLANK_END); + save->cr06 = hwp->readCrtc(hwp, 0x06); + hwp->writeCrtc(hwp,0x06,V_TOTAL); + /* all values have less than 8 bit - mask out 9th and 10th bits */ + save->cr09 = hwp->readCrtc(hwp, 0x09); + hwp->writeCrtc(hwp,0x09,(save->cr09 &0xDF)); + save->cr07 = hwp->readCrtc(hwp, 0x07); + hwp->writeCrtc(hwp,0x07,(save->cr07 &0x10)); + /* vsync polarity negativ & ensure a 25MHz clock */ + save->msr = hwp->readMiscOut(hwp); + hwp->writeMiscOut(hwp,((save->msr & 0xF3) | 0x80)); + break; + case DDC_SLOW: + if (hwp->ddc == NULL) break; + save = (struct _vgaDdcSave *)hwp->ddc; + hwp->writeMiscOut(hwp,save->msr); + hwp->writeCrtc(hwp,0x07,save->cr07); + tmp = hwp->readCrtc(hwp, 0x09); + hwp->writeCrtc(hwp,0x09,((save->cr09 & 0x20) | (tmp & 0xDF))); + hwp->writeCrtc(hwp,0x06,save->cr06); + hwp->writeCrtc(hwp,0x16,save->cr16); + hwp->writeCrtc(hwp,0x11,save->cr11); + hwp->writeCrtc(hwp,0x10,save->cr10); + hwp->writeCrtc(hwp,0x15,save->cr15); + hwp->writeCrtc(hwp,0x12,save->cr12); + hwp->writeCrtc(hwp,0x03,save->cr03); + free(save); + hwp->ddc = NULL; + break; + default: + break; + } +} + +DDC1SetSpeedProc +vgaHWddc1SetSpeedWeak(void) +{ + return vgaHWddc1SetSpeed; +} + +SaveScreenProcPtr vgaHWSaveScreenWeak(void) +{ + return vgaHWSaveScreen; +} diff --git a/xorg-server/hw/xfree86/xaa/xaaBitBlt.c b/xorg-server/hw/xfree86/xaa/xaaBitBlt.c index ebba74e55..b1fda1cd6 100644 --- a/xorg-server/hw/xfree86/xaa/xaaBitBlt.c +++ b/xorg-server/hw/xfree86/xaa/xaaBitBlt.c @@ -1,221 +1,221 @@ - -/* - This is a lighter version of cfbBitBlt. We calculate the boxes - when accelerating pixmap->screen and screen->screen copies. - We also pass the GC to the doBitBlt function so that it has access - to the fg and bg so CopyPlane can use this. -*/ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "mi.h" -#include "pixmapstr.h" -#include "gcstruct.h" -#include "windowstr.h" -#include "xaalocal.h" - - -RegionPtr -XAABitBlt( - DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GC *pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty, - void (*doBitBlt)(DrawablePtr, DrawablePtr, GCPtr, RegionPtr, DDXPointPtr), - unsigned long bitPlane ) -{ - - RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */ - RegionPtr prgnExposed; - Bool freeSrcClip = FALSE; - RegionRec rgnDst; - DDXPointPtr pptSrc, ppt; - DDXPointRec origDest; - BoxPtr pbox; - BoxRec fastBox; - int i, dx, dy, numRects; - xRectangle origSource; - int fastClip = 0; /* for fast clipping with pixmap source */ - int fastExpose = 0; /* for fast exposures with pixmap source */ - - origSource.x = srcx; - origSource.y = srcy; - origSource.width = width; - origSource.height = height; - origDest.x = dstx; - origDest.y = dsty; - - if((pSrcDrawable != pDstDrawable) && - pSrcDrawable->pScreen->SourceValidate) { - (*pSrcDrawable->pScreen->SourceValidate) ( - pSrcDrawable, srcx, srcy, width, height); - } - - srcx += pSrcDrawable->x; - srcy += pSrcDrawable->y; - - /* clip the source */ - if (pSrcDrawable->type == DRAWABLE_PIXMAP) { - if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE)) - prgnSrcClip = pGC->pCompositeClip; - else - fastClip = 1; - } else { /* Window */ - if (pGC->subWindowMode == IncludeInferiors) { - if (!((WindowPtr) pSrcDrawable)->parent) { - /* - * special case bitblt from root window in - * IncludeInferiors mode; just like from a pixmap - */ - fastClip = 1; - } else if ((pSrcDrawable == pDstDrawable) && - (pGC->clientClipType == CT_NONE)) { - prgnSrcClip = pGC->pCompositeClip; - } else { - prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable); - freeSrcClip = TRUE; - } - } else { - prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; - } - } - - fastBox.x1 = srcx; - fastBox.y1 = srcy; - fastBox.x2 = srcx + width; - fastBox.y2 = srcy + height; - - /* Don't create a source region if we are doing a fast clip */ - if (fastClip) { - fastExpose = 1; - /* - * clip the source; if regions extend beyond the source size, - * make sure exposure events get sent - */ - if (fastBox.x1 < pSrcDrawable->x) { - fastBox.x1 = pSrcDrawable->x; - fastExpose = 0; - } - if (fastBox.y1 < pSrcDrawable->y) { - fastBox.y1 = pSrcDrawable->y; - fastExpose = 0; - } - if (fastBox.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) { - fastBox.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; - fastExpose = 0; - } - if (fastBox.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) { - fastBox.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; - fastExpose = 0; - } - } else { - REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1); - REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip); - } - - dstx += pDstDrawable->x; - dsty += pDstDrawable->y; - - if (pDstDrawable->type == DRAWABLE_WINDOW) { - if (!((WindowPtr)pDstDrawable)->realized) { - if (!fastClip) - REGION_UNINIT(pGC->pScreen, &rgnDst); - if (freeSrcClip) - REGION_DESTROY(pGC->pScreen, prgnSrcClip); - return NULL; - } - } - - dx = srcx - dstx; - dy = srcy - dsty; - - /* Translate and clip the dst to the destination composite clip */ - if (fastClip) { - RegionPtr cclip; - - /* Translate the region directly */ - fastBox.x1 -= dx; - fastBox.x2 -= dx; - fastBox.y1 -= dy; - fastBox.y2 -= dy; - - /* If the destination composite clip is one rectangle we can - do the clip directly. Otherwise we have to create a full - blown region and call intersect */ - - cclip = pGC->pCompositeClip; - if (REGION_NUM_RECTS(cclip) == 1) { - BoxPtr pBox = REGION_RECTS(cclip); - - if (fastBox.x1 < pBox->x1) fastBox.x1 = pBox->x1; - if (fastBox.x2 > pBox->x2) fastBox.x2 = pBox->x2; - if (fastBox.y1 < pBox->y1) fastBox.y1 = pBox->y1; - if (fastBox.y2 > pBox->y2) fastBox.y2 = pBox->y2; - - /* Check to see if the region is empty */ - if (fastBox.x1 >= fastBox.x2 || fastBox.y1 >= fastBox.y2) { - REGION_NULL(pGC->pScreen, &rgnDst); - } else { - REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1); - } - } else { - /* We must turn off fastClip now, since we must create - a full blown region. It is intersected with the - composite clip below. */ - fastClip = 0; - REGION_INIT(pGC->pScreen, &rgnDst, &fastBox,1); - } - } else { - REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy); - } - - if (!fastClip) { - REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, - pGC->pCompositeClip); - } - - /* Do bit blitting */ - numRects = REGION_NUM_RECTS(&rgnDst); - if (numRects && width && height) { - if(!(pptSrc = (DDXPointPtr)xalloc(numRects * - sizeof(DDXPointRec)))) { - REGION_UNINIT(pGC->pScreen, &rgnDst); - if (freeSrcClip) - REGION_DESTROY(pGC->pScreen, prgnSrcClip); - return NULL; - } - pbox = REGION_RECTS(&rgnDst); - ppt = pptSrc; - for (i = numRects; --i >= 0; pbox++, ppt++) { - ppt->x = pbox->x1 + dx; - ppt->y = pbox->y1 + dy; - } - - (*doBitBlt) (pSrcDrawable, pDstDrawable, pGC, &rgnDst, pptSrc); - xfree(pptSrc); - } - - prgnExposed = NULL; - if (pGC->fExpose) { - /* Pixmap sources generate a NoExposed (we return NULL to do this) */ - if (!fastExpose) - prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, - origSource.x, origSource.y, - (int)origSource.width, - (int)origSource.height, - origDest.x, origDest.y, bitPlane); - } - REGION_UNINIT(pGC->pScreen, &rgnDst); - if (freeSrcClip) - REGION_DESTROY(pGC->pScreen, prgnSrcClip); - return prgnExposed; -} + +/* + This is a lighter version of cfbBitBlt. We calculate the boxes + when accelerating pixmap->screen and screen->screen copies. + We also pass the GC to the doBitBlt function so that it has access + to the fg and bg so CopyPlane can use this. +*/ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "mi.h" +#include "pixmapstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "xaalocal.h" + + +RegionPtr +XAABitBlt( + DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GC *pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty, + void (*doBitBlt)(DrawablePtr, DrawablePtr, GCPtr, RegionPtr, DDXPointPtr), + unsigned long bitPlane ) +{ + + RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */ + RegionPtr prgnExposed; + Bool freeSrcClip = FALSE; + RegionRec rgnDst; + DDXPointPtr pptSrc, ppt; + DDXPointRec origDest; + BoxPtr pbox; + BoxRec fastBox; + int i, dx, dy, numRects; + xRectangle origSource; + int fastClip = 0; /* for fast clipping with pixmap source */ + int fastExpose = 0; /* for fast exposures with pixmap source */ + + origSource.x = srcx; + origSource.y = srcy; + origSource.width = width; + origSource.height = height; + origDest.x = dstx; + origDest.y = dsty; + + if((pSrcDrawable != pDstDrawable) && + pSrcDrawable->pScreen->SourceValidate) { + (*pSrcDrawable->pScreen->SourceValidate) ( + pSrcDrawable, srcx, srcy, width, height); + } + + srcx += pSrcDrawable->x; + srcy += pSrcDrawable->y; + + /* clip the source */ + if (pSrcDrawable->type == DRAWABLE_PIXMAP) { + if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE)) + prgnSrcClip = pGC->pCompositeClip; + else + fastClip = 1; + } else { /* Window */ + if (pGC->subWindowMode == IncludeInferiors) { + if (!((WindowPtr) pSrcDrawable)->parent) { + /* + * special case bitblt from root window in + * IncludeInferiors mode; just like from a pixmap + */ + fastClip = 1; + } else if ((pSrcDrawable == pDstDrawable) && + (pGC->clientClipType == CT_NONE)) { + prgnSrcClip = pGC->pCompositeClip; + } else { + prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable); + freeSrcClip = TRUE; + } + } else { + prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; + } + } + + fastBox.x1 = srcx; + fastBox.y1 = srcy; + fastBox.x2 = srcx + width; + fastBox.y2 = srcy + height; + + /* Don't create a source region if we are doing a fast clip */ + if (fastClip) { + fastExpose = 1; + /* + * clip the source; if regions extend beyond the source size, + * make sure exposure events get sent + */ + if (fastBox.x1 < pSrcDrawable->x) { + fastBox.x1 = pSrcDrawable->x; + fastExpose = 0; + } + if (fastBox.y1 < pSrcDrawable->y) { + fastBox.y1 = pSrcDrawable->y; + fastExpose = 0; + } + if (fastBox.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) { + fastBox.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; + fastExpose = 0; + } + if (fastBox.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) { + fastBox.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; + fastExpose = 0; + } + } else { + REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1); + REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip); + } + + dstx += pDstDrawable->x; + dsty += pDstDrawable->y; + + if (pDstDrawable->type == DRAWABLE_WINDOW) { + if (!((WindowPtr)pDstDrawable)->realized) { + if (!fastClip) + REGION_UNINIT(pGC->pScreen, &rgnDst); + if (freeSrcClip) + REGION_DESTROY(pGC->pScreen, prgnSrcClip); + return NULL; + } + } + + dx = srcx - dstx; + dy = srcy - dsty; + + /* Translate and clip the dst to the destination composite clip */ + if (fastClip) { + RegionPtr cclip; + + /* Translate the region directly */ + fastBox.x1 -= dx; + fastBox.x2 -= dx; + fastBox.y1 -= dy; + fastBox.y2 -= dy; + + /* If the destination composite clip is one rectangle we can + do the clip directly. Otherwise we have to create a full + blown region and call intersect */ + + cclip = pGC->pCompositeClip; + if (REGION_NUM_RECTS(cclip) == 1) { + BoxPtr pBox = REGION_RECTS(cclip); + + if (fastBox.x1 < pBox->x1) fastBox.x1 = pBox->x1; + if (fastBox.x2 > pBox->x2) fastBox.x2 = pBox->x2; + if (fastBox.y1 < pBox->y1) fastBox.y1 = pBox->y1; + if (fastBox.y2 > pBox->y2) fastBox.y2 = pBox->y2; + + /* Check to see if the region is empty */ + if (fastBox.x1 >= fastBox.x2 || fastBox.y1 >= fastBox.y2) { + REGION_NULL(pGC->pScreen, &rgnDst); + } else { + REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1); + } + } else { + /* We must turn off fastClip now, since we must create + a full blown region. It is intersected with the + composite clip below. */ + fastClip = 0; + REGION_INIT(pGC->pScreen, &rgnDst, &fastBox,1); + } + } else { + REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy); + } + + if (!fastClip) { + REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, + pGC->pCompositeClip); + } + + /* Do bit blitting */ + numRects = REGION_NUM_RECTS(&rgnDst); + if (numRects && width && height) { + if(!(pptSrc = (DDXPointPtr)malloc(numRects * + sizeof(DDXPointRec)))) { + REGION_UNINIT(pGC->pScreen, &rgnDst); + if (freeSrcClip) + REGION_DESTROY(pGC->pScreen, prgnSrcClip); + return NULL; + } + pbox = REGION_RECTS(&rgnDst); + ppt = pptSrc; + for (i = numRects; --i >= 0; pbox++, ppt++) { + ppt->x = pbox->x1 + dx; + ppt->y = pbox->y1 + dy; + } + + (*doBitBlt) (pSrcDrawable, pDstDrawable, pGC, &rgnDst, pptSrc); + free(pptSrc); + } + + prgnExposed = NULL; + if (pGC->fExpose) { + /* Pixmap sources generate a NoExposed (we return NULL to do this) */ + if (!fastExpose) + prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, + origSource.x, origSource.y, + (int)origSource.width, + (int)origSource.height, + origDest.x, origDest.y, bitPlane); + } + REGION_UNINIT(pGC->pScreen, &rgnDst); + if (freeSrcClip) + REGION_DESTROY(pGC->pScreen, prgnSrcClip); + return prgnExposed; +} diff --git a/xorg-server/hw/xfree86/xaa/xaaCpyArea.c b/xorg-server/hw/xfree86/xaa/xaaCpyArea.c index 6a898cd5f..eefd8d38d 100644 --- a/xorg-server/hw/xfree86/xaa/xaaCpyArea.c +++ b/xorg-server/hw/xfree86/xaa/xaaCpyArea.c @@ -1,387 +1,387 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaalocal.h" -#include "migc.h" -#include "gcstruct.h" -#include "pixmapstr.h" - -/* - Written mostly by Harm Hanemaayer (H.Hanemaayer@inter.nl.net). - */ - - -RegionPtr -XAACopyArea( - DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GC *pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - - if(pDstDrawable->type == DRAWABLE_WINDOW) { - if((pSrcDrawable->type == DRAWABLE_WINDOW) || - IS_OFFSCREEN_PIXMAP(pSrcDrawable)){ - if(infoRec->ScreenToScreenBitBlt && - CHECK_ROP(pGC,infoRec->ScreenToScreenBitBltFlags) && - CHECK_ROPSRC(pGC,infoRec->ScreenToScreenBitBltFlags) && - CHECK_PLANEMASK(pGC,infoRec->ScreenToScreenBitBltFlags)) - return (XAABitBlt( pSrcDrawable, pDstDrawable, - pGC, srcx, srcy, width, height, dstx, dsty, - XAADoBitBlt, 0L)); - } else { - if(infoRec->WritePixmap && - ((pDstDrawable->bitsPerPixel == pSrcDrawable->bitsPerPixel) || - ((pDstDrawable->bitsPerPixel == 24) && - (pSrcDrawable->bitsPerPixel == 32) && - (infoRec->WritePixmapFlags & CONVERT_32BPP_TO_24BPP))) && - CHECK_ROP(pGC,infoRec->WritePixmapFlags) && - CHECK_ROPSRC(pGC,infoRec->WritePixmapFlags) && - CHECK_PLANEMASK(pGC,infoRec->WritePixmapFlags) && - CHECK_NO_GXCOPY(pGC,infoRec->WritePixmapFlags)) - return (XAABitBlt( pSrcDrawable, pDstDrawable, - pGC, srcx, srcy, width, height, dstx, dsty, - XAADoImageWrite, 0L)); - } - } else if(IS_OFFSCREEN_PIXMAP(pDstDrawable)){ - if((pSrcDrawable->type == DRAWABLE_WINDOW) || - IS_OFFSCREEN_PIXMAP(pSrcDrawable)){ - if(infoRec->ScreenToScreenBitBlt && - CHECK_ROP(pGC,infoRec->ScreenToScreenBitBltFlags) && - CHECK_ROPSRC(pGC,infoRec->ScreenToScreenBitBltFlags) && - CHECK_PLANEMASK(pGC,infoRec->ScreenToScreenBitBltFlags)) - return (XAABitBlt( pSrcDrawable, pDstDrawable, - pGC, srcx, srcy, width, height, dstx, dsty, - XAADoBitBlt, 0L)); - } - } - - return (XAAFallbackOps.CopyArea(pSrcDrawable, pDstDrawable, pGC, - srcx, srcy, width, height, dstx, dsty)); -} - - -void -XAADoBitBlt( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - RegionPtr prgnDst, - DDXPointPtr pptSrc ) -{ - int nbox, careful; - BoxPtr pbox, pboxTmp, pboxNext, pboxBase, pboxNew1, pboxNew2; - DDXPointPtr pptTmp, pptNew1, pptNew2; - int xdir, ydir; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - - /* XXX we have to err on the side of safety when both are windows, - * because we don't know if IncludeInferiors is being used. - */ - careful = ((pSrc == pDst) || - ((pSrc->type == DRAWABLE_WINDOW) && - (pDst->type == DRAWABLE_WINDOW))); - - pbox = REGION_RECTS(prgnDst); - nbox = REGION_NUM_RECTS(prgnDst); - - pboxNew1 = NULL; - pptNew1 = NULL; - pboxNew2 = NULL; - pptNew2 = NULL; - if (careful && (pptSrc->y < pbox->y1)) { - /* walk source botttom to top */ - ydir = -1; - - if (nbox > 1) { - /* keep ordering in each band, reverse order of bands */ - pboxNew1 = (BoxPtr)xalloc(sizeof(BoxRec) * nbox); - if(!pboxNew1) - return; - pptNew1 = (DDXPointPtr)xalloc(sizeof(DDXPointRec) * nbox); - if(!pptNew1) { - xfree(pboxNew1); - return; - } - pboxBase = pboxNext = pbox+nbox-1; - while (pboxBase >= pbox) { - while ((pboxNext >= pbox) && - (pboxBase->y1 == pboxNext->y1)) - pboxNext--; - pboxTmp = pboxNext+1; - pptTmp = pptSrc + (pboxTmp - pbox); - while (pboxTmp <= pboxBase) { - *pboxNew1++ = *pboxTmp++; - *pptNew1++ = *pptTmp++; - } - pboxBase = pboxNext; - } - pboxNew1 -= nbox; - pbox = pboxNew1; - pptNew1 -= nbox; - pptSrc = pptNew1; - } - } else { - /* walk source top to bottom */ - ydir = 1; - } - - if (careful && (pptSrc->x < pbox->x1)) { - /* walk source right to left */ - xdir = -1; - - if (nbox > 1) { - /* reverse order of rects in each band */ - pboxNew2 = (BoxPtr)xalloc(sizeof(BoxRec) * nbox); - pptNew2 = (DDXPointPtr)xalloc(sizeof(DDXPointRec) * nbox); - if(!pboxNew2 || !pptNew2) { - if (pptNew2) xfree(pptNew2); - if (pboxNew2) xfree(pboxNew2); - if (pboxNew1) { - xfree(pptNew1); - xfree(pboxNew1); - } - return; - } - pboxBase = pboxNext = pbox; - while (pboxBase < pbox+nbox) { - while ((pboxNext < pbox+nbox) && - (pboxNext->y1 == pboxBase->y1)) - pboxNext++; - pboxTmp = pboxNext; - pptTmp = pptSrc + (pboxTmp - pbox); - while (pboxTmp != pboxBase) { - *pboxNew2++ = *--pboxTmp; - *pptNew2++ = *--pptTmp; - } - pboxBase = pboxNext; - } - pboxNew2 -= nbox; - pbox = pboxNew2; - pptNew2 -= nbox; - pptSrc = pptNew2; - } - } else { - /* walk source left to right */ - xdir = 1; - } - - (*infoRec->ScreenToScreenBitBlt)(infoRec->pScrn, nbox, pptSrc, pbox, - xdir, ydir, pGC->alu, pGC->planemask); - - if (pboxNew2) { - xfree(pptNew2); - xfree(pboxNew2); - } - if (pboxNew1) { - xfree(pptNew1); - xfree(pboxNew1); - } - -} - -void -XAADoImageWrite( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - RegionPtr prgnDst, - DDXPointPtr pptSrc ) -{ - int srcwidth; - unsigned char* psrcBase; /* start of image */ - unsigned char* srcPntr; /* index into the image */ - BoxPtr pbox = REGION_RECTS(prgnDst); - int nbox = REGION_NUM_RECTS(prgnDst); - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - int Bpp = pSrc->bitsPerPixel >> 3; - - psrcBase = (unsigned char *)((PixmapPtr)pSrc)->devPrivate.ptr; - srcwidth = (int)((PixmapPtr)pSrc)->devKind; - - for(; nbox; pbox++, pptSrc++, nbox--) { - srcPntr = psrcBase + (pptSrc->y * srcwidth) + (pptSrc->x * Bpp); - - (*infoRec->WritePixmap)(infoRec->pScrn, pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, srcPntr, srcwidth, - pGC->alu, pGC->planemask, -1, pSrc->bitsPerPixel, pSrc->depth); - } -} - - -void -XAADoImageRead( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - RegionPtr prgnDst, - DDXPointPtr pptSrc ) -{ - int dstwidth; - unsigned char* pdstBase; /* start of image */ - unsigned char* dstPntr; /* index into the image */ - BoxPtr pbox = REGION_RECTS(prgnDst); - int nbox = REGION_NUM_RECTS(prgnDst); - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - int Bpp = pSrc->bitsPerPixel >> 3; /* wouldn't get here unless both - src and dst have same bpp */ - - pdstBase = (unsigned char *)((PixmapPtr)pDst)->devPrivate.ptr; - dstwidth = (int)((PixmapPtr)pDst)->devKind; - - for(; nbox; pbox++, pptSrc++, nbox--) { - dstPntr = pdstBase + (pbox->y1 * dstwidth) + (pbox->x1 * Bpp); - - (*infoRec->ReadPixmap)(infoRec->pScrn, pptSrc->x, pptSrc->y, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, dstPntr, dstwidth, - pSrc->bitsPerPixel, pSrc->depth); - } -} - - -void -XAAScreenToScreenBitBlt( - ScrnInfoPtr pScrn, - int nbox, - DDXPointPtr pptSrc, - BoxPtr pbox, - int xdir, int ydir, - int alu, - unsigned int planemask ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - int dirsetup; - - if ((!(infoRec->CopyAreaFlags & ONLY_TWO_BITBLT_DIRECTIONS) - || (xdir == ydir)) && - (!(infoRec->CopyAreaFlags & ONLY_LEFT_TO_RIGHT_BITBLT) - || (xdir == 1))) { - (*infoRec->SetupForScreenToScreenCopy)(pScrn, - xdir, ydir, alu, planemask, -1); - for (; nbox; pbox++, pptSrc++, nbox--) - (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y, - pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); - SET_SYNC_FLAG(infoRec); - return; - } - - if (infoRec->CopyAreaFlags & ONLY_LEFT_TO_RIGHT_BITBLT) { - /* - * This is the case of a chip that only supports xdir = 1, - * with ydir = 1 or ydir = -1, but we have xdir = -1. - */ - (*infoRec->SetupForScreenToScreenCopy)(pScrn, - 1, ydir, alu, planemask, -1); - for (; nbox; pbox++, pptSrc++, nbox--) - if (pptSrc->y != pbox->y1 || pptSrc->x >= pbox->x1) - /* No problem. Do a xdir = 1 blit instead. */ - (*infoRec->SubsequentScreenToScreenCopy)(pScrn, - pptSrc->x, pptSrc->y, pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); - else - { - /* - * This is the difficult case. Needs striping into - * non-overlapping horizontal chunks. - */ - int stripeWidth, w, fullStripes, extra, i; - stripeWidth = 16; - w = pbox->x2 - pbox->x1; - if (pbox->x1 - pptSrc->x < stripeWidth) - stripeWidth = pbox->x1 - pptSrc->x; - fullStripes = w / stripeWidth; - extra = w % stripeWidth; - - /* First, take care of the little bit on the far right */ - if (extra) - (*infoRec->SubsequentScreenToScreenCopy)(pScrn, - pptSrc->x + fullStripes * stripeWidth, pptSrc->y, - pbox->x1 + fullStripes * stripeWidth, pbox->y1, - extra, pbox->y2 - pbox->y1); - - /* Now, take care of the rest of the blit */ - for (i = fullStripes - 1; i >= 0; i--) - (*infoRec->SubsequentScreenToScreenCopy)(pScrn, - pptSrc->x + i * stripeWidth, pptSrc->y, - pbox->x1 + i * stripeWidth, pbox->y1, - stripeWidth, pbox->y2 - pbox->y1); - } - SET_SYNC_FLAG(infoRec); - return; - } - - /* - * Now the case of a chip that only supports xdir = ydir = 1 or - * xdir = ydir = -1, but we have xdir != ydir. - */ - dirsetup = 0; /* No direction set up yet. */ - for (; nbox; pbox++, pptSrc++, nbox--) { - if (xdir == 1 && pptSrc->y != pbox->y1) { - /* Do a xdir = ydir = -1 blit instead. */ - if (dirsetup != -1) { - (*infoRec->SetupForScreenToScreenCopy)(pScrn, - -1, -1, alu, planemask, -1); - dirsetup = -1; - } - (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y, - pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); - } - else if (xdir == -1 && pptSrc->y != pbox->y1) { - /* Do a xdir = ydir = 1 blit instead. */ - if (dirsetup != 1) { - (*infoRec->SetupForScreenToScreenCopy)(pScrn, - 1, 1, alu, planemask, -1); - dirsetup = 1; - } - (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y, - pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); - } - else - if (xdir == 1) { - /* - * xdir = 1, ydir = -1. - * Perform line-by-line xdir = ydir = 1 blits, going up. - */ - int i; - if (dirsetup != 1) { - (*infoRec->SetupForScreenToScreenCopy)(pScrn, - 1, 1, alu, planemask, -1); - dirsetup = 1; - } - for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) - (*infoRec->SubsequentScreenToScreenCopy)(pScrn, - pptSrc->x, pptSrc->y + i, pbox->x1, pbox->y1 + i, - pbox->x2 - pbox->x1, 1); - } - else { - /* - * xdir = -1, ydir = 1. - * Perform line-by-line xdir = ydir = -1 blits, going down. - */ - int i; - if (dirsetup != -1) { - (*infoRec->SetupForScreenToScreenCopy)(pScrn, - -1, -1, alu, planemask, -1); - dirsetup = -1; - } - for (i = 0; i < pbox->y2 - pbox->y1; i++) - (*infoRec->SubsequentScreenToScreenCopy)(pScrn, - pptSrc->x, pptSrc->y + i, pbox->x1, pbox->y1 + i, - pbox->x2 - pbox->x1, 1); - } - } /* next box */ - SET_SYNC_FLAG(infoRec); -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaalocal.h" +#include "migc.h" +#include "gcstruct.h" +#include "pixmapstr.h" + +/* + Written mostly by Harm Hanemaayer (H.Hanemaayer@inter.nl.net). + */ + + +RegionPtr +XAACopyArea( + DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GC *pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + + if(pDstDrawable->type == DRAWABLE_WINDOW) { + if((pSrcDrawable->type == DRAWABLE_WINDOW) || + IS_OFFSCREEN_PIXMAP(pSrcDrawable)){ + if(infoRec->ScreenToScreenBitBlt && + CHECK_ROP(pGC,infoRec->ScreenToScreenBitBltFlags) && + CHECK_ROPSRC(pGC,infoRec->ScreenToScreenBitBltFlags) && + CHECK_PLANEMASK(pGC,infoRec->ScreenToScreenBitBltFlags)) + return (XAABitBlt( pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty, + XAADoBitBlt, 0L)); + } else { + if(infoRec->WritePixmap && + ((pDstDrawable->bitsPerPixel == pSrcDrawable->bitsPerPixel) || + ((pDstDrawable->bitsPerPixel == 24) && + (pSrcDrawable->bitsPerPixel == 32) && + (infoRec->WritePixmapFlags & CONVERT_32BPP_TO_24BPP))) && + CHECK_ROP(pGC,infoRec->WritePixmapFlags) && + CHECK_ROPSRC(pGC,infoRec->WritePixmapFlags) && + CHECK_PLANEMASK(pGC,infoRec->WritePixmapFlags) && + CHECK_NO_GXCOPY(pGC,infoRec->WritePixmapFlags)) + return (XAABitBlt( pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty, + XAADoImageWrite, 0L)); + } + } else if(IS_OFFSCREEN_PIXMAP(pDstDrawable)){ + if((pSrcDrawable->type == DRAWABLE_WINDOW) || + IS_OFFSCREEN_PIXMAP(pSrcDrawable)){ + if(infoRec->ScreenToScreenBitBlt && + CHECK_ROP(pGC,infoRec->ScreenToScreenBitBltFlags) && + CHECK_ROPSRC(pGC,infoRec->ScreenToScreenBitBltFlags) && + CHECK_PLANEMASK(pGC,infoRec->ScreenToScreenBitBltFlags)) + return (XAABitBlt( pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty, + XAADoBitBlt, 0L)); + } + } + + return (XAAFallbackOps.CopyArea(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty)); +} + + +void +XAADoBitBlt( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + RegionPtr prgnDst, + DDXPointPtr pptSrc ) +{ + int nbox, careful; + BoxPtr pbox, pboxTmp, pboxNext, pboxBase, pboxNew1, pboxNew2; + DDXPointPtr pptTmp, pptNew1, pptNew2; + int xdir, ydir; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + + /* XXX we have to err on the side of safety when both are windows, + * because we don't know if IncludeInferiors is being used. + */ + careful = ((pSrc == pDst) || + ((pSrc->type == DRAWABLE_WINDOW) && + (pDst->type == DRAWABLE_WINDOW))); + + pbox = REGION_RECTS(prgnDst); + nbox = REGION_NUM_RECTS(prgnDst); + + pboxNew1 = NULL; + pptNew1 = NULL; + pboxNew2 = NULL; + pptNew2 = NULL; + if (careful && (pptSrc->y < pbox->y1)) { + /* walk source botttom to top */ + ydir = -1; + + if (nbox > 1) { + /* keep ordering in each band, reverse order of bands */ + pboxNew1 = (BoxPtr)malloc(sizeof(BoxRec) * nbox); + if(!pboxNew1) + return; + pptNew1 = (DDXPointPtr)malloc(sizeof(DDXPointRec) * nbox); + if(!pptNew1) { + free(pboxNew1); + return; + } + pboxBase = pboxNext = pbox+nbox-1; + while (pboxBase >= pbox) { + while ((pboxNext >= pbox) && + (pboxBase->y1 == pboxNext->y1)) + pboxNext--; + pboxTmp = pboxNext+1; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp <= pboxBase) { + *pboxNew1++ = *pboxTmp++; + *pptNew1++ = *pptTmp++; + } + pboxBase = pboxNext; + } + pboxNew1 -= nbox; + pbox = pboxNew1; + pptNew1 -= nbox; + pptSrc = pptNew1; + } + } else { + /* walk source top to bottom */ + ydir = 1; + } + + if (careful && (pptSrc->x < pbox->x1)) { + /* walk source right to left */ + xdir = -1; + + if (nbox > 1) { + /* reverse order of rects in each band */ + pboxNew2 = (BoxPtr)malloc(sizeof(BoxRec) * nbox); + pptNew2 = (DDXPointPtr)malloc(sizeof(DDXPointRec) * nbox); + if(!pboxNew2 || !pptNew2) { + if (pptNew2) free(pptNew2); + if (pboxNew2) free(pboxNew2); + if (pboxNew1) { + free(pptNew1); + free(pboxNew1); + } + return; + } + pboxBase = pboxNext = pbox; + while (pboxBase < pbox+nbox) { + while ((pboxNext < pbox+nbox) && + (pboxNext->y1 == pboxBase->y1)) + pboxNext++; + pboxTmp = pboxNext; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp != pboxBase) { + *pboxNew2++ = *--pboxTmp; + *pptNew2++ = *--pptTmp; + } + pboxBase = pboxNext; + } + pboxNew2 -= nbox; + pbox = pboxNew2; + pptNew2 -= nbox; + pptSrc = pptNew2; + } + } else { + /* walk source left to right */ + xdir = 1; + } + + (*infoRec->ScreenToScreenBitBlt)(infoRec->pScrn, nbox, pptSrc, pbox, + xdir, ydir, pGC->alu, pGC->planemask); + + if (pboxNew2) { + free(pptNew2); + free(pboxNew2); + } + if (pboxNew1) { + free(pptNew1); + free(pboxNew1); + } + +} + +void +XAADoImageWrite( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + RegionPtr prgnDst, + DDXPointPtr pptSrc ) +{ + int srcwidth; + unsigned char* psrcBase; /* start of image */ + unsigned char* srcPntr; /* index into the image */ + BoxPtr pbox = REGION_RECTS(prgnDst); + int nbox = REGION_NUM_RECTS(prgnDst); + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + int Bpp = pSrc->bitsPerPixel >> 3; + + psrcBase = (unsigned char *)((PixmapPtr)pSrc)->devPrivate.ptr; + srcwidth = (int)((PixmapPtr)pSrc)->devKind; + + for(; nbox; pbox++, pptSrc++, nbox--) { + srcPntr = psrcBase + (pptSrc->y * srcwidth) + (pptSrc->x * Bpp); + + (*infoRec->WritePixmap)(infoRec->pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, srcPntr, srcwidth, + pGC->alu, pGC->planemask, -1, pSrc->bitsPerPixel, pSrc->depth); + } +} + + +void +XAADoImageRead( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + RegionPtr prgnDst, + DDXPointPtr pptSrc ) +{ + int dstwidth; + unsigned char* pdstBase; /* start of image */ + unsigned char* dstPntr; /* index into the image */ + BoxPtr pbox = REGION_RECTS(prgnDst); + int nbox = REGION_NUM_RECTS(prgnDst); + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + int Bpp = pSrc->bitsPerPixel >> 3; /* wouldn't get here unless both + src and dst have same bpp */ + + pdstBase = (unsigned char *)((PixmapPtr)pDst)->devPrivate.ptr; + dstwidth = (int)((PixmapPtr)pDst)->devKind; + + for(; nbox; pbox++, pptSrc++, nbox--) { + dstPntr = pdstBase + (pbox->y1 * dstwidth) + (pbox->x1 * Bpp); + + (*infoRec->ReadPixmap)(infoRec->pScrn, pptSrc->x, pptSrc->y, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, dstPntr, dstwidth, + pSrc->bitsPerPixel, pSrc->depth); + } +} + + +void +XAAScreenToScreenBitBlt( + ScrnInfoPtr pScrn, + int nbox, + DDXPointPtr pptSrc, + BoxPtr pbox, + int xdir, int ydir, + int alu, + unsigned int planemask ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + int dirsetup; + + if ((!(infoRec->CopyAreaFlags & ONLY_TWO_BITBLT_DIRECTIONS) + || (xdir == ydir)) && + (!(infoRec->CopyAreaFlags & ONLY_LEFT_TO_RIGHT_BITBLT) + || (xdir == 1))) { + (*infoRec->SetupForScreenToScreenCopy)(pScrn, + xdir, ydir, alu, planemask, -1); + for (; nbox; pbox++, pptSrc++, nbox--) + (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y, + pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + SET_SYNC_FLAG(infoRec); + return; + } + + if (infoRec->CopyAreaFlags & ONLY_LEFT_TO_RIGHT_BITBLT) { + /* + * This is the case of a chip that only supports xdir = 1, + * with ydir = 1 or ydir = -1, but we have xdir = -1. + */ + (*infoRec->SetupForScreenToScreenCopy)(pScrn, + 1, ydir, alu, planemask, -1); + for (; nbox; pbox++, pptSrc++, nbox--) + if (pptSrc->y != pbox->y1 || pptSrc->x >= pbox->x1) + /* No problem. Do a xdir = 1 blit instead. */ + (*infoRec->SubsequentScreenToScreenCopy)(pScrn, + pptSrc->x, pptSrc->y, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + else + { + /* + * This is the difficult case. Needs striping into + * non-overlapping horizontal chunks. + */ + int stripeWidth, w, fullStripes, extra, i; + stripeWidth = 16; + w = pbox->x2 - pbox->x1; + if (pbox->x1 - pptSrc->x < stripeWidth) + stripeWidth = pbox->x1 - pptSrc->x; + fullStripes = w / stripeWidth; + extra = w % stripeWidth; + + /* First, take care of the little bit on the far right */ + if (extra) + (*infoRec->SubsequentScreenToScreenCopy)(pScrn, + pptSrc->x + fullStripes * stripeWidth, pptSrc->y, + pbox->x1 + fullStripes * stripeWidth, pbox->y1, + extra, pbox->y2 - pbox->y1); + + /* Now, take care of the rest of the blit */ + for (i = fullStripes - 1; i >= 0; i--) + (*infoRec->SubsequentScreenToScreenCopy)(pScrn, + pptSrc->x + i * stripeWidth, pptSrc->y, + pbox->x1 + i * stripeWidth, pbox->y1, + stripeWidth, pbox->y2 - pbox->y1); + } + SET_SYNC_FLAG(infoRec); + return; + } + + /* + * Now the case of a chip that only supports xdir = ydir = 1 or + * xdir = ydir = -1, but we have xdir != ydir. + */ + dirsetup = 0; /* No direction set up yet. */ + for (; nbox; pbox++, pptSrc++, nbox--) { + if (xdir == 1 && pptSrc->y != pbox->y1) { + /* Do a xdir = ydir = -1 blit instead. */ + if (dirsetup != -1) { + (*infoRec->SetupForScreenToScreenCopy)(pScrn, + -1, -1, alu, planemask, -1); + dirsetup = -1; + } + (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y, + pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + } + else if (xdir == -1 && pptSrc->y != pbox->y1) { + /* Do a xdir = ydir = 1 blit instead. */ + if (dirsetup != 1) { + (*infoRec->SetupForScreenToScreenCopy)(pScrn, + 1, 1, alu, planemask, -1); + dirsetup = 1; + } + (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y, + pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + } + else + if (xdir == 1) { + /* + * xdir = 1, ydir = -1. + * Perform line-by-line xdir = ydir = 1 blits, going up. + */ + int i; + if (dirsetup != 1) { + (*infoRec->SetupForScreenToScreenCopy)(pScrn, + 1, 1, alu, planemask, -1); + dirsetup = 1; + } + for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) + (*infoRec->SubsequentScreenToScreenCopy)(pScrn, + pptSrc->x, pptSrc->y + i, pbox->x1, pbox->y1 + i, + pbox->x2 - pbox->x1, 1); + } + else { + /* + * xdir = -1, ydir = 1. + * Perform line-by-line xdir = ydir = -1 blits, going down. + */ + int i; + if (dirsetup != -1) { + (*infoRec->SetupForScreenToScreenCopy)(pScrn, + -1, -1, alu, planemask, -1); + dirsetup = -1; + } + for (i = 0; i < pbox->y2 - pbox->y1; i++) + (*infoRec->SubsequentScreenToScreenCopy)(pScrn, + pptSrc->x, pptSrc->y + i, pbox->x1, pbox->y1 + i, + pbox->x2 - pbox->x1, 1); + } + } /* next box */ + SET_SYNC_FLAG(infoRec); +} diff --git a/xorg-server/hw/xfree86/xaa/xaaCpyPlane.c b/xorg-server/hw/xfree86/xaa/xaaCpyPlane.c index aa4c0407c..358cb6fb2 100644 --- a/xorg-server/hw/xfree86/xaa/xaaCpyPlane.c +++ b/xorg-server/hw/xfree86/xaa/xaaCpyPlane.c @@ -1,208 +1,208 @@ - -/* - A CopyPlane function that handles bitmap->screen copies and - sends anything else to the Fallback. - - Also, a PushPixels for solid fill styles. - - Written by Mark Vojkovich (markv@valinux.com) - -*/ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" -#include "servermd.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "mi.h" -#include "pixmapstr.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaalocal.h" -#include "xaawrap.h" - -static void XAACopyPlane1toNColorExpand(DrawablePtr pSrc, DrawablePtr pDst, - GCPtr pGC, RegionPtr rgnDst, - DDXPointPtr pptSrc); -static void XAACopyPlaneNtoNColorExpand(DrawablePtr pSrc, DrawablePtr pDst, - GCPtr pGC, RegionPtr rgnDst, - DDXPointPtr pptSrc); - - -static unsigned long TmpBitPlane; - -RegionPtr -XAACopyPlaneColorExpansion( - DrawablePtr pSrc, - DrawablePtr pDst, - GCPtr pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty, - unsigned long bitPlane -){ - if((pSrc->type == DRAWABLE_PIXMAP) && !XAA_DEPTH_BUG(pGC)) { - if(pSrc->bitsPerPixel == 1) { - return(XAABitBlt(pSrc, pDst, pGC, srcx, srcy, - width, height, dstx, dsty, - XAACopyPlane1toNColorExpand, bitPlane)); - } else if(bitPlane < (1 << pDst->depth)){ - TmpBitPlane = bitPlane; - return(XAABitBlt(pSrc, pDst, pGC, srcx, srcy, - width, height, dstx, dsty, - XAACopyPlaneNtoNColorExpand, bitPlane)); - } - } - - return (XAAFallbackOps.CopyPlane(pSrc, pDst, pGC, srcx, srcy, - width, height, dstx, dsty, bitPlane)); -} - - -static void -XAACopyPlane1toNColorExpand( - DrawablePtr pSrc, - DrawablePtr pDst, - GCPtr pGC, - RegionPtr rgnDst, - DDXPointPtr pptSrc ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - BoxPtr pbox = REGION_RECTS(rgnDst); - int numrects = REGION_NUM_RECTS(rgnDst); - unsigned char *src = ((PixmapPtr)pSrc)->devPrivate.ptr; - int srcwidth = ((PixmapPtr)pSrc)->devKind; - - while(numrects--) { - (*infoRec->WriteBitmap)(infoRec->pScrn, pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, - src + (srcwidth * pptSrc->y) + ((pptSrc->x >> 5) << 2), - srcwidth, pptSrc->x & 31, - pGC->fgPixel, pGC->bgPixel, pGC->alu, pGC->planemask); - pbox++; pptSrc++; - } -} - - -static void -XAACopyPlaneNtoNColorExpand( - DrawablePtr pSrc, - DrawablePtr pDst, - GCPtr pGC, - RegionPtr rgnDst, - DDXPointPtr pptSrc -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - BoxPtr pbox = REGION_RECTS(rgnDst); - int numrects = REGION_NUM_RECTS(rgnDst); - unsigned char *src = ((PixmapPtr)pSrc)->devPrivate.ptr; - unsigned char *data, *srcPtr, *dataPtr; - int srcwidth = ((PixmapPtr)pSrc)->devKind; - int pitch, width, height, h, i, index, offset; - int Bpp = pSrc->bitsPerPixel >> 3; - unsigned long mask = TmpBitPlane; - - if(TmpBitPlane < (1 << 8)) { - offset = 0; - } else if(TmpBitPlane < (1 << 16)) { - offset = 1; - mask >>= 8; - } else if(TmpBitPlane < (1 << 24)) { - offset = 2; - mask >>= 16; - } else { - offset = 3; - mask >>= 24; - } - - if(IS_OFFSCREEN_PIXMAP(pSrc)) - SYNC_CHECK(pSrc); - - while(numrects--) { - width = pbox->x2 - pbox->x1; - h = height = pbox->y2 - pbox->y1; - pitch = BitmapBytePad(width); - - if(!(data = xcalloc(height, pitch))) - goto ALLOC_FAILED; - - dataPtr = data; - srcPtr = ((pptSrc->y) * srcwidth) + src + - ((pptSrc->x) * Bpp) + offset; - - while(h--) { - for(i = index = 0; i < width; i++, index += Bpp) { - if(mask & srcPtr[index]) - dataPtr[i >> 3] |= (1 << (i & 7)); - } - dataPtr += pitch; - srcPtr += srcwidth; - } - - (*infoRec->WriteBitmap)(infoRec->pScrn, - pbox->x1, pbox->y1, width, height, data, pitch, 0, - pGC->fgPixel, pGC->bgPixel, pGC->alu, pGC->planemask); - - xfree(data); - -ALLOC_FAILED: - - pbox++; pptSrc++; - } -} - -void -XAAPushPixelsSolidColorExpansion( - GCPtr pGC, - PixmapPtr pBitMap, - DrawablePtr pDraw, - int dx, int dy, - int xOrg, int yOrg ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - int MaxBoxes = REGION_NUM_RECTS(pGC->pCompositeClip); - BoxPtr pbox, pClipBoxes; - int nboxes, srcx, srcy; - xRectangle TheRect; - unsigned char *src = pBitMap->devPrivate.ptr; - int srcwidth = pBitMap->devKind; - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - TheRect.x = xOrg; - TheRect.y = yOrg; - TheRect.width = dx; - TheRect.height = dy; - - if(MaxBoxes > (infoRec->PreAllocSize/sizeof(BoxRec))) { - pClipBoxes = xalloc(MaxBoxes * sizeof(BoxRec)); - if(!pClipBoxes) return; - } else pClipBoxes = (BoxPtr)infoRec->PreAllocMem; - - nboxes = XAAGetRectClipBoxes(pGC, pClipBoxes, 1, &TheRect); - pbox = pClipBoxes; - - while(nboxes--) { - srcx = pbox->x1 - xOrg; - srcy = pbox->y1 - yOrg; - (*infoRec->WriteBitmap)(infoRec->pScrn, pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, - src + (srcwidth * srcy) + ((srcx >> 5) << 2), - srcwidth, srcx & 31, - pGC->fgPixel, -1, pGC->alu, pGC->planemask); - pbox++; - } - - if(pClipBoxes != (BoxPtr)infoRec->PreAllocMem) - xfree(pClipBoxes); -} - + +/* + A CopyPlane function that handles bitmap->screen copies and + sends anything else to the Fallback. + + Also, a PushPixels for solid fill styles. + + Written by Mark Vojkovich (markv@valinux.com) + +*/ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#include "servermd.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "mi.h" +#include "pixmapstr.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xaawrap.h" + +static void XAACopyPlane1toNColorExpand(DrawablePtr pSrc, DrawablePtr pDst, + GCPtr pGC, RegionPtr rgnDst, + DDXPointPtr pptSrc); +static void XAACopyPlaneNtoNColorExpand(DrawablePtr pSrc, DrawablePtr pDst, + GCPtr pGC, RegionPtr rgnDst, + DDXPointPtr pptSrc); + + +static unsigned long TmpBitPlane; + +RegionPtr +XAACopyPlaneColorExpansion( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty, + unsigned long bitPlane +){ + if((pSrc->type == DRAWABLE_PIXMAP) && !XAA_DEPTH_BUG(pGC)) { + if(pSrc->bitsPerPixel == 1) { + return(XAABitBlt(pSrc, pDst, pGC, srcx, srcy, + width, height, dstx, dsty, + XAACopyPlane1toNColorExpand, bitPlane)); + } else if(bitPlane < (1 << pDst->depth)){ + TmpBitPlane = bitPlane; + return(XAABitBlt(pSrc, pDst, pGC, srcx, srcy, + width, height, dstx, dsty, + XAACopyPlaneNtoNColorExpand, bitPlane)); + } + } + + return (XAAFallbackOps.CopyPlane(pSrc, pDst, pGC, srcx, srcy, + width, height, dstx, dsty, bitPlane)); +} + + +static void +XAACopyPlane1toNColorExpand( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + RegionPtr rgnDst, + DDXPointPtr pptSrc ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + BoxPtr pbox = REGION_RECTS(rgnDst); + int numrects = REGION_NUM_RECTS(rgnDst); + unsigned char *src = ((PixmapPtr)pSrc)->devPrivate.ptr; + int srcwidth = ((PixmapPtr)pSrc)->devKind; + + while(numrects--) { + (*infoRec->WriteBitmap)(infoRec->pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, + src + (srcwidth * pptSrc->y) + ((pptSrc->x >> 5) << 2), + srcwidth, pptSrc->x & 31, + pGC->fgPixel, pGC->bgPixel, pGC->alu, pGC->planemask); + pbox++; pptSrc++; + } +} + + +static void +XAACopyPlaneNtoNColorExpand( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + RegionPtr rgnDst, + DDXPointPtr pptSrc +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + BoxPtr pbox = REGION_RECTS(rgnDst); + int numrects = REGION_NUM_RECTS(rgnDst); + unsigned char *src = ((PixmapPtr)pSrc)->devPrivate.ptr; + unsigned char *data, *srcPtr, *dataPtr; + int srcwidth = ((PixmapPtr)pSrc)->devKind; + int pitch, width, height, h, i, index, offset; + int Bpp = pSrc->bitsPerPixel >> 3; + unsigned long mask = TmpBitPlane; + + if(TmpBitPlane < (1 << 8)) { + offset = 0; + } else if(TmpBitPlane < (1 << 16)) { + offset = 1; + mask >>= 8; + } else if(TmpBitPlane < (1 << 24)) { + offset = 2; + mask >>= 16; + } else { + offset = 3; + mask >>= 24; + } + + if(IS_OFFSCREEN_PIXMAP(pSrc)) + SYNC_CHECK(pSrc); + + while(numrects--) { + width = pbox->x2 - pbox->x1; + h = height = pbox->y2 - pbox->y1; + pitch = BitmapBytePad(width); + + if(!(data = calloc(height, pitch))) + goto ALLOC_FAILED; + + dataPtr = data; + srcPtr = ((pptSrc->y) * srcwidth) + src + + ((pptSrc->x) * Bpp) + offset; + + while(h--) { + for(i = index = 0; i < width; i++, index += Bpp) { + if(mask & srcPtr[index]) + dataPtr[i >> 3] |= (1 << (i & 7)); + } + dataPtr += pitch; + srcPtr += srcwidth; + } + + (*infoRec->WriteBitmap)(infoRec->pScrn, + pbox->x1, pbox->y1, width, height, data, pitch, 0, + pGC->fgPixel, pGC->bgPixel, pGC->alu, pGC->planemask); + + free(data); + +ALLOC_FAILED: + + pbox++; pptSrc++; + } +} + +void +XAAPushPixelsSolidColorExpansion( + GCPtr pGC, + PixmapPtr pBitMap, + DrawablePtr pDraw, + int dx, int dy, + int xOrg, int yOrg ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + int MaxBoxes = REGION_NUM_RECTS(pGC->pCompositeClip); + BoxPtr pbox, pClipBoxes; + int nboxes, srcx, srcy; + xRectangle TheRect; + unsigned char *src = pBitMap->devPrivate.ptr; + int srcwidth = pBitMap->devKind; + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + TheRect.x = xOrg; + TheRect.y = yOrg; + TheRect.width = dx; + TheRect.height = dy; + + if(MaxBoxes > (infoRec->PreAllocSize/sizeof(BoxRec))) { + pClipBoxes = malloc(MaxBoxes * sizeof(BoxRec)); + if(!pClipBoxes) return; + } else pClipBoxes = (BoxPtr)infoRec->PreAllocMem; + + nboxes = XAAGetRectClipBoxes(pGC, pClipBoxes, 1, &TheRect); + pbox = pClipBoxes; + + while(nboxes--) { + srcx = pbox->x1 - xOrg; + srcy = pbox->y1 - yOrg; + (*infoRec->WriteBitmap)(infoRec->pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, + src + (srcwidth * srcy) + ((srcx >> 5) << 2), + srcwidth, srcx & 31, + pGC->fgPixel, -1, pGC->alu, pGC->planemask); + pbox++; + } + + if(pClipBoxes != (BoxPtr)infoRec->PreAllocMem) + free(pClipBoxes); +} + diff --git a/xorg-server/hw/xfree86/xaa/xaaCpyWin.c b/xorg-server/hw/xfree86/xaa/xaaCpyWin.c index 31c421e65..34f460f24 100644 --- a/xorg-server/hw/xfree86/xaa/xaaCpyWin.c +++ b/xorg-server/hw/xfree86/xaa/xaaCpyWin.c @@ -1,82 +1,82 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "windowstr.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaalocal.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "xaawrap.h" - -/* - Written by Harm Hanemaayer (H.Hanemaayer@inter.nl.net). -*/ - -void -XAACopyWindow( - WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc ) -{ - DDXPointPtr pptSrc, ppt; - RegionRec rgnDst; - BoxPtr pbox; - int dx, dy, nbox; - WindowPtr pwinRoot; - ScreenPtr pScreen = pWin->drawable.pScreen; - XAAInfoRecPtr infoRec = - GET_XAAINFORECPTR_FROM_DRAWABLE((&pWin->drawable)); - - if (!infoRec->pScrn->vtSema || !infoRec->ScreenToScreenBitBlt) { - XAA_SCREEN_PROLOGUE (pScreen, CopyWindow); - if(infoRec->pScrn->vtSema && infoRec->NeedToSync) { - (*infoRec->Sync)(infoRec->pScrn); - infoRec->NeedToSync = FALSE; - } - (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc); - XAA_SCREEN_EPILOGUE (pScreen, CopyWindow, XAACopyWindow); - return; - } - - pwinRoot = WindowTable[pScreen->myNum]; - - REGION_NULL(pScreen, &rgnDst); - - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); - REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); - - pbox = REGION_RECTS(&rgnDst); - nbox = REGION_NUM_RECTS(&rgnDst); - if(!nbox || - !(pptSrc = (DDXPointPtr )xalloc(nbox * sizeof(DDXPointRec)))) { - REGION_UNINIT(pScreen, &rgnDst); - return; - } - ppt = pptSrc; - - while(nbox--) { - ppt->x = pbox->x1 + dx; - ppt->y = pbox->y1 + dy; - ppt++; pbox++; - } - - infoRec->ScratchGC.planemask = ~0L; - infoRec->ScratchGC.alu = GXcopy; - - XAADoBitBlt((DrawablePtr)pwinRoot, (DrawablePtr)pwinRoot, - &(infoRec->ScratchGC), &rgnDst, pptSrc); - - xfree(pptSrc); - REGION_UNINIT(pScreen, &rgnDst); -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "windowstr.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaalocal.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "xaawrap.h" + +/* + Written by Harm Hanemaayer (H.Hanemaayer@inter.nl.net). +*/ + +void +XAACopyWindow( + WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc ) +{ + DDXPointPtr pptSrc, ppt; + RegionRec rgnDst; + BoxPtr pbox; + int dx, dy, nbox; + WindowPtr pwinRoot; + ScreenPtr pScreen = pWin->drawable.pScreen; + XAAInfoRecPtr infoRec = + GET_XAAINFORECPTR_FROM_DRAWABLE((&pWin->drawable)); + + if (!infoRec->pScrn->vtSema || !infoRec->ScreenToScreenBitBlt) { + XAA_SCREEN_PROLOGUE (pScreen, CopyWindow); + if(infoRec->pScrn->vtSema && infoRec->NeedToSync) { + (*infoRec->Sync)(infoRec->pScrn); + infoRec->NeedToSync = FALSE; + } + (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc); + XAA_SCREEN_EPILOGUE (pScreen, CopyWindow, XAACopyWindow); + return; + } + + pwinRoot = WindowTable[pScreen->myNum]; + + REGION_NULL(pScreen, &rgnDst); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + pbox = REGION_RECTS(&rgnDst); + nbox = REGION_NUM_RECTS(&rgnDst); + if(!nbox || + !(pptSrc = (DDXPointPtr )malloc(nbox * sizeof(DDXPointRec)))) { + REGION_UNINIT(pScreen, &rgnDst); + return; + } + ppt = pptSrc; + + while(nbox--) { + ppt->x = pbox->x1 + dx; + ppt->y = pbox->y1 + dy; + ppt++; pbox++; + } + + infoRec->ScratchGC.planemask = ~0L; + infoRec->ScratchGC.alu = GXcopy; + + XAADoBitBlt((DrawablePtr)pwinRoot, (DrawablePtr)pwinRoot, + &(infoRec->ScratchGC), &rgnDst, pptSrc); + + free(pptSrc); + REGION_UNINIT(pScreen, &rgnDst); +} diff --git a/xorg-server/hw/xfree86/xaa/xaaGC.c b/xorg-server/hw/xfree86/xaa/xaaGC.c index e6083d529..d029d982b 100644 --- a/xorg-server/hw/xfree86/xaa/xaaGC.c +++ b/xorg-server/hw/xfree86/xaa/xaaGC.c @@ -1,656 +1,656 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaalocal.h" -#include "migc.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "xaawrap.h" - -static void XAAValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDraw); -static void XAAChangeGC(GCPtr pGC, unsigned long mask); -static void XAACopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); -static void XAADestroyGC(GCPtr pGC); -static void XAAChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects); -static void XAADestroyClip(GCPtr pGC); -static void XAACopyClip(GCPtr pgcDst, GCPtr pgcSrc); - -GCFuncs XAAGCFuncs = { - XAAValidateGC, XAAChangeGC, XAACopyGC, XAADestroyGC, - XAAChangeClip, XAADestroyClip, XAACopyClip -}; - -extern GCOps XAAPixmapOps; - -Bool -XAACreateGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - XAAGCPtr pGCPriv = (XAAGCPtr)dixLookupPrivate(&pGC->devPrivates, - XAAGetGCKey()); - Bool ret; - - XAA_SCREEN_PROLOGUE(pScreen,CreateGC); - - if((ret = (*pScreen->CreateGC)(pGC))) { - pGCPriv->wrapOps = NULL; - pGCPriv->wrapFuncs = pGC->funcs; - pGCPriv->XAAOps = &XAAFallbackOps; - pGCPriv->flags = 0; - pGCPriv->DashLength = 0; - pGCPriv->DashPattern = NULL; - pGCPriv->changes = 0; - /* initialize any other private fields here */ - pGC->funcs = &XAAGCFuncs; - } - - XAA_SCREEN_EPILOGUE(pScreen,CreateGC,XAACreateGC); - - return ret; -} - - -static void -XAAValidateGC( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - XAA_GC_FUNC_PROLOGUE(pGC); - - (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); - - if((changes & GCPlaneMask) && - ((pGC->planemask & infoRec->FullPlanemasks[pGC->depth - 1]) == - infoRec->FullPlanemasks[pGC->depth - 1])) - { - pGC->planemask = ~0; - } - - if(pGC->depth != 32) { - /* 0xffffffff is reserved for transparency */ - if(pGC->bgPixel == 0xffffffff) - pGC->bgPixel = 0x7fffffff; - if(pGC->fgPixel == 0xffffffff) - pGC->fgPixel = 0x7fffffff; - } - - if((pDraw->type == DRAWABLE_PIXMAP) && !IS_OFFSCREEN_PIXMAP(pDraw)){ - pGCPriv->flags = OPS_ARE_PIXMAP; - pGCPriv->changes |= changes; - - /* make sure we're not using videomemory pixmaps to render - onto system memory drawables */ - - if((pGC->fillStyle == FillTiled) && - IS_OFFSCREEN_PIXMAP(pGC->tile.pixmap) && - !OFFSCREEN_PIXMAP_LOCKED(pGC->tile.pixmap)) { - - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pGC->tile.pixmap); - FBAreaPtr area = pPriv->offscreenArea; - - XAARemoveAreaCallback(area); /* clobbers pPriv->offscreenArea */ - xf86FreeOffscreenArea(area); - } - } - else if(!infoRec->pScrn->vtSema && (pDraw->type == DRAWABLE_WINDOW)) { - pGCPriv->flags = 0; - pGCPriv->changes |= changes; - } - else { - if(!(pGCPriv->flags & OPS_ARE_ACCEL)) { - changes |= pGCPriv->changes; - pGCPriv->changes = 0; - } - pGCPriv->flags = OPS_ARE_ACCEL; - -#if 1 - /* Ugh. If we can't use the blitter on offscreen pixmaps used - as tiles, then we need to move them out as cfb can't handle - tiles with non-zero origins */ - - if((pGC->fillStyle == FillTiled) && - IS_OFFSCREEN_PIXMAP(pGC->tile.pixmap) && - (DO_PIXMAP_COPY != (*infoRec->TiledFillChooser)(pGC))) { - - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pGC->tile.pixmap); - FBAreaPtr area = pPriv->offscreenArea; - - XAARemoveAreaCallback(area); /* clobbers pPriv->offscreenArea */ - xf86FreeOffscreenArea(area); - } -#endif - } - - XAA_GC_FUNC_EPILOGUE(pGC); - - if(!(pGCPriv->flags & OPS_ARE_ACCEL)) return; - - if((changes & GCTile) && !pGC->tileIsPixel && pGC->tile.pixmap){ - XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(pGC->tile.pixmap); - - if(pixPriv->flags & DIRTY) { - pixPriv->flags &= ~(DIRTY | REDUCIBILITY_MASK); - pGC->tile.pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - } - } - if((changes & GCStipple) && pGC->stipple){ - XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(pGC->stipple); - - if(pixPriv->flags & DIRTY) { - pixPriv->flags &= ~(DIRTY | REDUCIBILITY_MASK); - pGC->stipple->drawable.serialNumber = NEXT_SERIAL_NUMBER; - } - } - - /* If our Ops are still the default ones we need to allocate new ones */ - if(pGC->ops == &XAAFallbackOps) { - if(!(pGCPriv->XAAOps = xalloc(sizeof(GCOps)))) { - pGCPriv->XAAOps = &XAAFallbackOps; - return; - } - /* make a modifiable copy of the default ops */ - memcpy(pGCPriv->XAAOps, &XAAFallbackOps, sizeof(GCOps)); - pGC->ops = pGCPriv->XAAOps; - changes = ~0; - } - - if(!changes) return; - - if((changes & GCDashList) && infoRec->ComputeDash) - infoRec->ComputeDash(pGC); - - if(changes & infoRec->FillSpansMask) - (*infoRec->ValidateFillSpans)(pGC, changes, pDraw); - - if(changes & infoRec->SetSpansMask) - (*infoRec->ValidateSetSpans)(pGC, changes, pDraw); - - if(changes & infoRec->PutImageMask) - (*infoRec->ValidatePutImage)(pGC, changes, pDraw); - - if(changes & infoRec->CopyAreaMask) - (*infoRec->ValidateCopyArea)(pGC, changes, pDraw); - - if(changes & infoRec->CopyPlaneMask) - (*infoRec->ValidateCopyPlane)(pGC, changes, pDraw); - - if(changes & infoRec->PolyPointMask) - (*infoRec->ValidatePolyPoint)(pGC, changes, pDraw); - - if(changes & infoRec->PolylinesMask) - (*infoRec->ValidatePolylines)(pGC, changes, pDraw); - - if(changes & infoRec->PolySegmentMask) - (*infoRec->ValidatePolySegment)(pGC, changes, pDraw); - - if(changes & infoRec->PolyRectangleMask) - (*infoRec->ValidatePolyRectangle)(pGC, changes, pDraw); - - if(changes & infoRec->PolyArcMask) - (*infoRec->ValidatePolyArc)(pGC, changes, pDraw); - - if(changes & infoRec->FillPolygonMask) - (*infoRec->ValidateFillPolygon)(pGC, changes, pDraw); - - if(changes & infoRec->PolyFillRectMask) - (*infoRec->ValidatePolyFillRect)(pGC, changes, pDraw); - - if(changes & infoRec->PolyFillArcMask) - (*infoRec->ValidatePolyFillArc)(pGC, changes, pDraw); - - if(changes & infoRec->PolyGlyphBltMask) - (*infoRec->ValidatePolyGlyphBlt)(pGC, changes, pDraw); - - if(changes & infoRec->ImageGlyphBltMask) - (*infoRec->ValidateImageGlyphBlt)(pGC, changes, pDraw); - - if(changes & infoRec->PolyText8Mask) - (*infoRec->ValidatePolyText8)(pGC, changes, pDraw); - - if(changes & infoRec->PolyText16Mask) - (*infoRec->ValidatePolyText16)(pGC, changes, pDraw); - - if(changes & infoRec->ImageText8Mask) - (*infoRec->ValidateImageText8)(pGC, changes, pDraw); - - if(changes & infoRec->ImageText16Mask) - (*infoRec->ValidateImageText16)(pGC, changes, pDraw); - - if(changes & infoRec->PushPixelsMask) - (*infoRec->ValidatePushPixels)(pGC, changes, pDraw); -} - - -static void -XAADestroyGC(GCPtr pGC) -{ - XAA_GC_FUNC_PROLOGUE (pGC); - - if(pGCPriv->XAAOps != &XAAFallbackOps) - xfree(pGCPriv->XAAOps); - - if(pGCPriv->DashPattern) - xfree(pGCPriv->DashPattern); - - (*pGC->funcs->DestroyGC)(pGC); - XAA_GC_FUNC_EPILOGUE (pGC); -} - -static void -XAAChangeGC ( - GCPtr pGC, - unsigned long mask -) -{ - XAA_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ChangeGC) (pGC, mask); - XAA_GC_FUNC_EPILOGUE (pGC); - - /* we have to assume that shared memory pixmaps are dirty - because we can't wrap all operations on them */ - - if((mask & GCTile) && !pGC->tileIsPixel && - PIXMAP_IS_SHARED(pGC->tile.pixmap)) - { - XAAPixmapPtr pPixPriv = XAA_GET_PIXMAP_PRIVATE(pGC->tile.pixmap); - pPixPriv->flags |= DIRTY; - } - - if((mask & GCStipple) && PIXMAP_IS_SHARED(pGC->stipple)){ - XAAPixmapPtr pPixPriv = XAA_GET_PIXMAP_PRIVATE(pGC->stipple); - pPixPriv->flags |= DIRTY; - } -} - -static void -XAACopyGC ( - GCPtr pGCSrc, - unsigned long mask, - GCPtr pGCDst) -{ - XAA_GC_FUNC_PROLOGUE (pGCDst); - (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); - XAA_GC_FUNC_EPILOGUE (pGCDst); -} -static void -XAAChangeClip ( - GCPtr pGC, - int type, - pointer pvalue, - int nrects ) -{ - XAA_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); - XAA_GC_FUNC_EPILOGUE (pGC); -} - -static void -XAACopyClip(GCPtr pgcDst, GCPtr pgcSrc) -{ - XAA_GC_FUNC_PROLOGUE (pgcDst); - (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); - XAA_GC_FUNC_EPILOGUE (pgcDst); -} - -static void -XAADestroyClip(GCPtr pGC) -{ - XAA_GC_FUNC_PROLOGUE (pGC); - (* pGC->funcs->DestroyClip)(pGC); - XAA_GC_FUNC_EPILOGUE (pGC); -} - -/**** Pixmap Wrappers ****/ - - - -static void -XAAFillSpansPixmap( - DrawablePtr pDraw, - GC *pGC, - int nInit, - DDXPointPtr pptInit, - int *pwidthInit, - int fSorted -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static void -XAASetSpansPixmap( - DrawablePtr pDraw, - GCPtr pGC, - char *pcharsrc, - register DDXPointPtr ppt, - int *pwidth, - int nspans, - int fSorted -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, ppt, pwidth, nspans, fSorted); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static void -XAAPutImagePixmap( - DrawablePtr pDraw, - GCPtr pGC, - int depth, - int x, int y, int w, int h, - int leftPad, - int format, - char *pImage -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h, - leftPad, format, pImage); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static RegionPtr -XAACopyAreaPixmap( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - RegionPtr ret; - - if(infoRec->pScrn->vtSema && - ((pSrc->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pSrc))) - { - if(infoRec->ReadPixmap && (pGC->alu == GXcopy) && - (pSrc->bitsPerPixel == pDst->bitsPerPixel) && - ((pGC->planemask & infoRec->FullPlanemasks[pSrc->depth - 1]) - == infoRec->FullPlanemasks[pSrc->depth - 1])) - { - XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pDst)); - pixPriv->flags |= DIRTY; - - return (XAABitBlt( pSrc, pDst, pGC, - srcx, srcy, width, height, dstx, dsty, - XAADoImageRead, 0L)); - } else - if(infoRec->NeedToSync) { - (*infoRec->Sync)(infoRec->pScrn); - infoRec->NeedToSync = FALSE; - } - } - - { - XAA_PIXMAP_OP_PROLOGUE(pGC, pDst); - ret = (*pGC->ops->CopyArea)(pSrc, pDst, - pGC, srcx, srcy, width, height, dstx, dsty); - XAA_PIXMAP_OP_EPILOGUE(pGC); - } - return ret; -} - -static RegionPtr -XAACopyPlanePixmap( - DrawablePtr pSrc, - DrawablePtr pDst, - GCPtr pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty, - unsigned long bitPlane -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - RegionPtr ret; - - XAA_PIXMAP_OP_PROLOGUE(pGC, pDst); - - if(infoRec->pScrn->vtSema && - ((pSrc->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pSrc))){ - if(infoRec->NeedToSync) { - (*infoRec->Sync)(infoRec->pScrn); - infoRec->NeedToSync = FALSE; - } - } - - ret = (*pGC->ops->CopyPlane)(pSrc, pDst, - pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); - XAA_PIXMAP_OP_EPILOGUE(pGC); - return ret; -} - -static void -XAAPolyPointPixmap( - DrawablePtr pDraw, - GCPtr pGC, - int mode, - int npt, - xPoint *pptInit -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->PolyPoint)(pDraw, pGC, mode, npt, pptInit); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - - -static void -XAAPolylinesPixmap( - DrawablePtr pDraw, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr pptInit -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->Polylines)(pDraw, pGC, mode, npt, pptInit); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static void -XAAPolySegmentPixmap( - DrawablePtr pDraw, - GCPtr pGC, - int nseg, - xSegment *pSeg -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->PolySegment)(pDraw, pGC, nseg, pSeg); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static void -XAAPolyRectanglePixmap( - DrawablePtr pDraw, - GCPtr pGC, - int nRectsInit, - xRectangle *pRectsInit -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->PolyRectangle)(pDraw, pGC, nRectsInit, pRectsInit); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static void -XAAPolyArcPixmap( - DrawablePtr pDraw, - GCPtr pGC, - int narcs, - xArc *parcs -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->PolyArc)(pDraw, pGC, narcs, parcs); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static void -XAAFillPolygonPixmap( - DrawablePtr pDraw, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr ptsIn -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, ptsIn); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - - -static void -XAAPolyFillRectPixmap( - DrawablePtr pDraw, - GCPtr pGC, - int nrectFill, - xRectangle *prectInit -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->PolyFillRect)(pDraw, pGC, nrectFill, prectInit); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - - -static void -XAAPolyFillArcPixmap( - DrawablePtr pDraw, - GCPtr pGC, - int narcs, - xArc *parcs -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->PolyFillArc)(pDraw, pGC, narcs, parcs); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static int -XAAPolyText8Pixmap( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - char *chars -){ - int ret; - - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - ret = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars); - XAA_PIXMAP_OP_EPILOGUE(pGC); - return ret; -} - -static int -XAAPolyText16Pixmap( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars -){ - int ret; - - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - ret = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars); - XAA_PIXMAP_OP_EPILOGUE(pGC); - return ret; -} - -static void -XAAImageText8Pixmap( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - char *chars -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} -static void -XAAImageText16Pixmap( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - - -static void -XAAImageGlyphBltPixmap( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, xInit, yInit, nglyph, - ppci, pglyphBase); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static void -XAAPolyGlyphBltPixmap( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, xInit, yInit, nglyph, - ppci, pglyphBase); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -static void -XAAPushPixelsPixmap( - GCPtr pGC, - PixmapPtr pBitMap, - DrawablePtr pDraw, - int dx, int dy, int xOrg, int yOrg -){ - XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); - (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); - XAA_PIXMAP_OP_EPILOGUE(pGC); -} - -GCOps XAAPixmapOps = { - XAAFillSpansPixmap, XAASetSpansPixmap, - XAAPutImagePixmap, XAACopyAreaPixmap, - XAACopyPlanePixmap, XAAPolyPointPixmap, - XAAPolylinesPixmap, XAAPolySegmentPixmap, - XAAPolyRectanglePixmap, XAAPolyArcPixmap, - XAAFillPolygonPixmap, XAAPolyFillRectPixmap, - XAAPolyFillArcPixmap, XAAPolyText8Pixmap, - XAAPolyText16Pixmap, XAAImageText8Pixmap, - XAAImageText16Pixmap, XAAImageGlyphBltPixmap, - XAAPolyGlyphBltPixmap, XAAPushPixelsPixmap, - {NULL} /* devPrivate */ -}; + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaalocal.h" +#include "migc.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "xaawrap.h" + +static void XAAValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDraw); +static void XAAChangeGC(GCPtr pGC, unsigned long mask); +static void XAACopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void XAADestroyGC(GCPtr pGC); +static void XAAChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects); +static void XAADestroyClip(GCPtr pGC); +static void XAACopyClip(GCPtr pgcDst, GCPtr pgcSrc); + +GCFuncs XAAGCFuncs = { + XAAValidateGC, XAAChangeGC, XAACopyGC, XAADestroyGC, + XAAChangeClip, XAADestroyClip, XAACopyClip +}; + +extern GCOps XAAPixmapOps; + +Bool +XAACreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + XAAGCPtr pGCPriv = (XAAGCPtr)dixLookupPrivate(&pGC->devPrivates, + XAAGetGCKey()); + Bool ret; + + XAA_SCREEN_PROLOGUE(pScreen,CreateGC); + + if((ret = (*pScreen->CreateGC)(pGC))) { + pGCPriv->wrapOps = NULL; + pGCPriv->wrapFuncs = pGC->funcs; + pGCPriv->XAAOps = &XAAFallbackOps; + pGCPriv->flags = 0; + pGCPriv->DashLength = 0; + pGCPriv->DashPattern = NULL; + pGCPriv->changes = 0; + /* initialize any other private fields here */ + pGC->funcs = &XAAGCFuncs; + } + + XAA_SCREEN_EPILOGUE(pScreen,CreateGC,XAACreateGC); + + return ret; +} + + +static void +XAAValidateGC( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + XAA_GC_FUNC_PROLOGUE(pGC); + + (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); + + if((changes & GCPlaneMask) && + ((pGC->planemask & infoRec->FullPlanemasks[pGC->depth - 1]) == + infoRec->FullPlanemasks[pGC->depth - 1])) + { + pGC->planemask = ~0; + } + + if(pGC->depth != 32) { + /* 0xffffffff is reserved for transparency */ + if(pGC->bgPixel == 0xffffffff) + pGC->bgPixel = 0x7fffffff; + if(pGC->fgPixel == 0xffffffff) + pGC->fgPixel = 0x7fffffff; + } + + if((pDraw->type == DRAWABLE_PIXMAP) && !IS_OFFSCREEN_PIXMAP(pDraw)){ + pGCPriv->flags = OPS_ARE_PIXMAP; + pGCPriv->changes |= changes; + + /* make sure we're not using videomemory pixmaps to render + onto system memory drawables */ + + if((pGC->fillStyle == FillTiled) && + IS_OFFSCREEN_PIXMAP(pGC->tile.pixmap) && + !OFFSCREEN_PIXMAP_LOCKED(pGC->tile.pixmap)) { + + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pGC->tile.pixmap); + FBAreaPtr area = pPriv->offscreenArea; + + XAARemoveAreaCallback(area); /* clobbers pPriv->offscreenArea */ + xf86FreeOffscreenArea(area); + } + } + else if(!infoRec->pScrn->vtSema && (pDraw->type == DRAWABLE_WINDOW)) { + pGCPriv->flags = 0; + pGCPriv->changes |= changes; + } + else { + if(!(pGCPriv->flags & OPS_ARE_ACCEL)) { + changes |= pGCPriv->changes; + pGCPriv->changes = 0; + } + pGCPriv->flags = OPS_ARE_ACCEL; + +#if 1 + /* Ugh. If we can't use the blitter on offscreen pixmaps used + as tiles, then we need to move them out as cfb can't handle + tiles with non-zero origins */ + + if((pGC->fillStyle == FillTiled) && + IS_OFFSCREEN_PIXMAP(pGC->tile.pixmap) && + (DO_PIXMAP_COPY != (*infoRec->TiledFillChooser)(pGC))) { + + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pGC->tile.pixmap); + FBAreaPtr area = pPriv->offscreenArea; + + XAARemoveAreaCallback(area); /* clobbers pPriv->offscreenArea */ + xf86FreeOffscreenArea(area); + } +#endif + } + + XAA_GC_FUNC_EPILOGUE(pGC); + + if(!(pGCPriv->flags & OPS_ARE_ACCEL)) return; + + if((changes & GCTile) && !pGC->tileIsPixel && pGC->tile.pixmap){ + XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(pGC->tile.pixmap); + + if(pixPriv->flags & DIRTY) { + pixPriv->flags &= ~(DIRTY | REDUCIBILITY_MASK); + pGC->tile.pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } + } + if((changes & GCStipple) && pGC->stipple){ + XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(pGC->stipple); + + if(pixPriv->flags & DIRTY) { + pixPriv->flags &= ~(DIRTY | REDUCIBILITY_MASK); + pGC->stipple->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } + } + + /* If our Ops are still the default ones we need to allocate new ones */ + if(pGC->ops == &XAAFallbackOps) { + if(!(pGCPriv->XAAOps = malloc(sizeof(GCOps)))) { + pGCPriv->XAAOps = &XAAFallbackOps; + return; + } + /* make a modifiable copy of the default ops */ + memcpy(pGCPriv->XAAOps, &XAAFallbackOps, sizeof(GCOps)); + pGC->ops = pGCPriv->XAAOps; + changes = ~0; + } + + if(!changes) return; + + if((changes & GCDashList) && infoRec->ComputeDash) + infoRec->ComputeDash(pGC); + + if(changes & infoRec->FillSpansMask) + (*infoRec->ValidateFillSpans)(pGC, changes, pDraw); + + if(changes & infoRec->SetSpansMask) + (*infoRec->ValidateSetSpans)(pGC, changes, pDraw); + + if(changes & infoRec->PutImageMask) + (*infoRec->ValidatePutImage)(pGC, changes, pDraw); + + if(changes & infoRec->CopyAreaMask) + (*infoRec->ValidateCopyArea)(pGC, changes, pDraw); + + if(changes & infoRec->CopyPlaneMask) + (*infoRec->ValidateCopyPlane)(pGC, changes, pDraw); + + if(changes & infoRec->PolyPointMask) + (*infoRec->ValidatePolyPoint)(pGC, changes, pDraw); + + if(changes & infoRec->PolylinesMask) + (*infoRec->ValidatePolylines)(pGC, changes, pDraw); + + if(changes & infoRec->PolySegmentMask) + (*infoRec->ValidatePolySegment)(pGC, changes, pDraw); + + if(changes & infoRec->PolyRectangleMask) + (*infoRec->ValidatePolyRectangle)(pGC, changes, pDraw); + + if(changes & infoRec->PolyArcMask) + (*infoRec->ValidatePolyArc)(pGC, changes, pDraw); + + if(changes & infoRec->FillPolygonMask) + (*infoRec->ValidateFillPolygon)(pGC, changes, pDraw); + + if(changes & infoRec->PolyFillRectMask) + (*infoRec->ValidatePolyFillRect)(pGC, changes, pDraw); + + if(changes & infoRec->PolyFillArcMask) + (*infoRec->ValidatePolyFillArc)(pGC, changes, pDraw); + + if(changes & infoRec->PolyGlyphBltMask) + (*infoRec->ValidatePolyGlyphBlt)(pGC, changes, pDraw); + + if(changes & infoRec->ImageGlyphBltMask) + (*infoRec->ValidateImageGlyphBlt)(pGC, changes, pDraw); + + if(changes & infoRec->PolyText8Mask) + (*infoRec->ValidatePolyText8)(pGC, changes, pDraw); + + if(changes & infoRec->PolyText16Mask) + (*infoRec->ValidatePolyText16)(pGC, changes, pDraw); + + if(changes & infoRec->ImageText8Mask) + (*infoRec->ValidateImageText8)(pGC, changes, pDraw); + + if(changes & infoRec->ImageText16Mask) + (*infoRec->ValidateImageText16)(pGC, changes, pDraw); + + if(changes & infoRec->PushPixelsMask) + (*infoRec->ValidatePushPixels)(pGC, changes, pDraw); +} + + +static void +XAADestroyGC(GCPtr pGC) +{ + XAA_GC_FUNC_PROLOGUE (pGC); + + if(pGCPriv->XAAOps != &XAAFallbackOps) + free(pGCPriv->XAAOps); + + if(pGCPriv->DashPattern) + free(pGCPriv->DashPattern); + + (*pGC->funcs->DestroyGC)(pGC); + XAA_GC_FUNC_EPILOGUE (pGC); +} + +static void +XAAChangeGC ( + GCPtr pGC, + unsigned long mask +) +{ + XAA_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeGC) (pGC, mask); + XAA_GC_FUNC_EPILOGUE (pGC); + + /* we have to assume that shared memory pixmaps are dirty + because we can't wrap all operations on them */ + + if((mask & GCTile) && !pGC->tileIsPixel && + PIXMAP_IS_SHARED(pGC->tile.pixmap)) + { + XAAPixmapPtr pPixPriv = XAA_GET_PIXMAP_PRIVATE(pGC->tile.pixmap); + pPixPriv->flags |= DIRTY; + } + + if((mask & GCStipple) && PIXMAP_IS_SHARED(pGC->stipple)){ + XAAPixmapPtr pPixPriv = XAA_GET_PIXMAP_PRIVATE(pGC->stipple); + pPixPriv->flags |= DIRTY; + } +} + +static void +XAACopyGC ( + GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst) +{ + XAA_GC_FUNC_PROLOGUE (pGCDst); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + XAA_GC_FUNC_EPILOGUE (pGCDst); +} +static void +XAAChangeClip ( + GCPtr pGC, + int type, + pointer pvalue, + int nrects ) +{ + XAA_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + XAA_GC_FUNC_EPILOGUE (pGC); +} + +static void +XAACopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + XAA_GC_FUNC_PROLOGUE (pgcDst); + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + XAA_GC_FUNC_EPILOGUE (pgcDst); +} + +static void +XAADestroyClip(GCPtr pGC) +{ + XAA_GC_FUNC_PROLOGUE (pGC); + (* pGC->funcs->DestroyClip)(pGC); + XAA_GC_FUNC_EPILOGUE (pGC); +} + +/**** Pixmap Wrappers ****/ + + + +static void +XAAFillSpansPixmap( + DrawablePtr pDraw, + GC *pGC, + int nInit, + DDXPointPtr pptInit, + int *pwidthInit, + int fSorted +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static void +XAASetSpansPixmap( + DrawablePtr pDraw, + GCPtr pGC, + char *pcharsrc, + register DDXPointPtr ppt, + int *pwidth, + int nspans, + int fSorted +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, ppt, pwidth, nspans, fSorted); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static void +XAAPutImagePixmap( + DrawablePtr pDraw, + GCPtr pGC, + int depth, + int x, int y, int w, int h, + int leftPad, + int format, + char *pImage +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h, + leftPad, format, pImage); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static RegionPtr +XAACopyAreaPixmap( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + RegionPtr ret; + + if(infoRec->pScrn->vtSema && + ((pSrc->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pSrc))) + { + if(infoRec->ReadPixmap && (pGC->alu == GXcopy) && + (pSrc->bitsPerPixel == pDst->bitsPerPixel) && + ((pGC->planemask & infoRec->FullPlanemasks[pSrc->depth - 1]) + == infoRec->FullPlanemasks[pSrc->depth - 1])) + { + XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pDst)); + pixPriv->flags |= DIRTY; + + return (XAABitBlt( pSrc, pDst, pGC, + srcx, srcy, width, height, dstx, dsty, + XAADoImageRead, 0L)); + } else + if(infoRec->NeedToSync) { + (*infoRec->Sync)(infoRec->pScrn); + infoRec->NeedToSync = FALSE; + } + } + + { + XAA_PIXMAP_OP_PROLOGUE(pGC, pDst); + ret = (*pGC->ops->CopyArea)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty); + XAA_PIXMAP_OP_EPILOGUE(pGC); + } + return ret; +} + +static RegionPtr +XAACopyPlanePixmap( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty, + unsigned long bitPlane +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + RegionPtr ret; + + XAA_PIXMAP_OP_PROLOGUE(pGC, pDst); + + if(infoRec->pScrn->vtSema && + ((pSrc->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pSrc))){ + if(infoRec->NeedToSync) { + (*infoRec->Sync)(infoRec->pScrn); + infoRec->NeedToSync = FALSE; + } + } + + ret = (*pGC->ops->CopyPlane)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); + XAA_PIXMAP_OP_EPILOGUE(pGC); + return ret; +} + +static void +XAAPolyPointPixmap( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + xPoint *pptInit +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyPoint)(pDraw, pGC, mode, npt, pptInit); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + + +static void +XAAPolylinesPixmap( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pptInit +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->Polylines)(pDraw, pGC, mode, npt, pptInit); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static void +XAAPolySegmentPixmap( + DrawablePtr pDraw, + GCPtr pGC, + int nseg, + xSegment *pSeg +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolySegment)(pDraw, pGC, nseg, pSeg); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static void +XAAPolyRectanglePixmap( + DrawablePtr pDraw, + GCPtr pGC, + int nRectsInit, + xRectangle *pRectsInit +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyRectangle)(pDraw, pGC, nRectsInit, pRectsInit); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static void +XAAPolyArcPixmap( + DrawablePtr pDraw, + GCPtr pGC, + int narcs, + xArc *parcs +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyArc)(pDraw, pGC, narcs, parcs); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static void +XAAFillPolygonPixmap( + DrawablePtr pDraw, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr ptsIn +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, ptsIn); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + + +static void +XAAPolyFillRectPixmap( + DrawablePtr pDraw, + GCPtr pGC, + int nrectFill, + xRectangle *prectInit +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyFillRect)(pDraw, pGC, nrectFill, prectInit); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + + +static void +XAAPolyFillArcPixmap( + DrawablePtr pDraw, + GCPtr pGC, + int narcs, + xArc *parcs +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyFillArc)(pDraw, pGC, narcs, parcs); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static int +XAAPolyText8Pixmap( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars +){ + int ret; + + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + ret = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars); + XAA_PIXMAP_OP_EPILOGUE(pGC); + return ret; +} + +static int +XAAPolyText16Pixmap( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars +){ + int ret; + + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + ret = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars); + XAA_PIXMAP_OP_EPILOGUE(pGC); + return ret; +} + +static void +XAAImageText8Pixmap( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} +static void +XAAImageText16Pixmap( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + + +static void +XAAImageGlyphBltPixmap( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, xInit, yInit, nglyph, + ppci, pglyphBase); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static void +XAAPolyGlyphBltPixmap( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, xInit, yInit, nglyph, + ppci, pglyphBase); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +static void +XAAPushPixelsPixmap( + GCPtr pGC, + PixmapPtr pBitMap, + DrawablePtr pDraw, + int dx, int dy, int xOrg, int yOrg +){ + XAA_PIXMAP_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); + XAA_PIXMAP_OP_EPILOGUE(pGC); +} + +GCOps XAAPixmapOps = { + XAAFillSpansPixmap, XAASetSpansPixmap, + XAAPutImagePixmap, XAACopyAreaPixmap, + XAACopyPlanePixmap, XAAPolyPointPixmap, + XAAPolylinesPixmap, XAAPolySegmentPixmap, + XAAPolyRectanglePixmap, XAAPolyArcPixmap, + XAAFillPolygonPixmap, XAAPolyFillRectPixmap, + XAAPolyFillArcPixmap, XAAPolyText8Pixmap, + XAAPolyText16Pixmap, XAAImageText8Pixmap, + XAAImageText16Pixmap, XAAImageGlyphBltPixmap, + XAAPolyGlyphBltPixmap, XAAPushPixelsPixmap, + {NULL} /* devPrivate */ +}; diff --git a/xorg-server/hw/xfree86/xaa/xaaImage.c b/xorg-server/hw/xfree86/xaa/xaaImage.c index 4933beea3..c8d98c7d0 100644 --- a/xorg-server/hw/xfree86/xaa/xaaImage.c +++ b/xorg-server/hw/xfree86/xaa/xaaImage.c @@ -1,521 +1,521 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" -#include "servermd.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "mi.h" -#include "pixmapstr.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaalocal.h" - -void XAAMoveDWORDS_FixedBase( - register CARD32* dest, - register CARD32* src, - register int dwords ) -{ - while(dwords & ~0x03) { - *dest = *src; - *dest = *(src + 1); - *dest = *(src + 2); - *dest = *(src + 3); - dwords -= 4; - src += 4; - } - - if(!dwords) return; - *dest = *src; - if(dwords == 1) return; - *dest = *(src + 1); - if(dwords == 2) return; - *dest = *(src + 2); -} - -void XAAMoveDWORDS( - register CARD32* dest, - register CARD32* src, - register int dwords ) -{ - while(dwords & ~0x03) { - *dest = *src; - *(dest + 1) = *(src + 1); - *(dest + 2) = *(src + 2); - *(dest + 3) = *(src + 3); - src += 4; - dest += 4; - dwords -= 4; - } - if(!dwords) return; - *dest = *src; - if(dwords == 1) return; - *(dest + 1) = *(src + 1); - if(dwords == 2) return; - *(dest + 2) = *(src + 2); -} - -void XAAMoveDWORDS_FixedSrc( - register CARD32* dest, - register CARD32* src, - register int dwords ) -{ - while(dwords & ~0x03) { - *dest = *src; - *(dest + 1) = *src; - *(dest + 2) = *src; - *(dest + 3) = *src; - dest += 4; - dwords -= 4; - } - if(!dwords) return; - *dest = *src; - if(dwords == 1) return; - *(dest + 1) = *src; - if(dwords == 2) return; - *(dest + 2) = *src; -} - -static void -XAAWritePixmap32To24( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *srcInit, - int srcwidth, /* bytes */ - int rop, - unsigned int planemask, - int trans -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - int count, dwords = bytes_to_int32(w * 3); - CARD32 *src, *dst; - Bool PlusOne = FALSE; - - if((infoRec->ImageWriteFlags & CPU_TRANSFER_PAD_QWORD) && - ((dwords * h) & 0x01)) { - PlusOne = TRUE; - } - - (*infoRec->SetupForImageWrite)(pScrn, rop, planemask, trans, 24, 24); - (*infoRec->SubsequentImageWriteRect)(pScrn, x, y, w, h, 0); - - if(dwords > infoRec->ImageWriteRange) { - dst = (CARD32*)infoRec->ImageWriteBase; - while(h--) { - src = (CARD32*)srcInit; - count = w; - - while(count >= 4) { - *dst = (src[0] & 0x00ffffff) | (src[1] << 24); - *dst = ((src[1] >> 8) & 0x0000ffff) | (src[2] << 16); - *dst = ((src[2] >> 16) & 0x000000ff) | (src[3] << 8); - src += 4; - count -= 4; - } - switch(count) { - case 0: break; - case 1: *dst = src[0]; - break; - case 2: *dst = (src[0] & 0x00ffffff) | (src[1] << 24); - *dst = src[1] >> 8; - break; - default: *dst = (src[0] & 0x00ffffff) | (src[1] << 24); - *dst = ((src[1] >> 8) & 0x0000ffff) | (src[2] << 16); - *dst = src[2] >> 16; - break; - } - srcInit += srcwidth; - } - } else { - while(h--) { - dst = (CARD32*)infoRec->ImageWriteBase; - src = (CARD32*)srcInit; - count = w; - - while(count >= 4) { - dst[0] = (src[0] & 0x00ffffff) | (src[1] << 24); - dst[1] = ((src[1] >> 8) & 0x0000ffff) | (src[2] << 16); - dst[2] = ((src[2] >> 16) & 0x000000ff) | (src[3] << 8); - dst += 3; - src += 4; - count -= 4; - } - switch(count) { - case 0: break; - case 1: dst[0] = src[0]; - break; - case 2: dst[0] = (src[0] & 0x00ffffff) | (src[1] << 24); - dst[1] = src[1] >> 8; - break; - default: dst[0] = (src[0] & 0x00ffffff) | (src[1] << 24); - dst[1] = ((src[1] >> 8) & 0x0000ffff) | (src[2] << 16); - dst[2] = src[2] >> 16; - break; - } - srcInit += srcwidth; - } - } - - if(PlusOne) { - CARD32* base = (CARD32*)infoRec->ImageWriteBase; - *base = 0x00000000; - } - - if(infoRec->ImageWriteFlags & SYNC_AFTER_IMAGE_WRITE) - (*infoRec->Sync)(pScrn); - else SET_SYNC_FLAG(infoRec); - -} - -void -XAAWritePixmap ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, /* bytes */ - int rop, - unsigned int planemask, - int trans, - int bpp, int depth -){ - XAAInfoRecPtr infoRec; - int dwords, skipleft, Bpp; - Bool beCareful, PlusOne; - - if((bpp == 32) && (pScrn->bitsPerPixel == 24)) { - XAAWritePixmap32To24(pScrn, x, y, w, h, src, srcwidth, - rop, planemask, trans); - return; - } - - infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - beCareful = PlusOne = FALSE; - Bpp = bpp >> 3; - - if((skipleft = (long)src & 0x03L)) { - if(!(infoRec->ImageWriteFlags & LEFT_EDGE_CLIPPING)) { - skipleft = 0; - beCareful = TRUE; - goto BAD_ALIGNMENT; - } - - if(Bpp == 3) - skipleft = 4 - skipleft; - else - skipleft /= Bpp; - - if((x < skipleft) && !(infoRec->ImageWriteFlags & - LEFT_EDGE_CLIPPING_NEGATIVE_X)) { - skipleft = 0; - beCareful = TRUE; - goto BAD_ALIGNMENT; - } - - x -= skipleft; - w += skipleft; - - if(Bpp == 3) - src -= 3 * skipleft; - else /* is this Alpha friendly ? */ - src = (unsigned char*)((long)src & ~0x03L); - } - -BAD_ALIGNMENT: - - dwords = bytes_to_int32(w * Bpp); - - if((infoRec->ImageWriteFlags & CPU_TRANSFER_PAD_QWORD) && - ((dwords * h) & 0x01)) { - PlusOne = TRUE; - } - - - (*infoRec->SetupForImageWrite)(pScrn, rop, planemask, trans, bpp, depth); - (*infoRec->SubsequentImageWriteRect)(pScrn, x, y, w, h, skipleft); - - if(beCareful) { - /* in cases with bad alignment we have to be careful not - to read beyond the end of the source */ - if(((x * Bpp) + (dwords << 2)) > srcwidth) h--; - else beCareful = FALSE; - } - - if(dwords > infoRec->ImageWriteRange) { - while(h--) { - XAAMoveDWORDS_FixedBase((CARD32*)infoRec->ImageWriteBase, - (CARD32*)src, dwords); - src += srcwidth; - } - if(beCareful) { - int shift = ((long)src & 0x03L) << 3; - if(--dwords) - XAAMoveDWORDS_FixedBase((CARD32*)infoRec->ImageWriteBase, - (CARD32*)src, dwords); - src = (unsigned char*)((long)(src + (dwords << 2)) & ~0x03L); - *((CARD32*)infoRec->ImageWriteBase) = *((CARD32*)src) >> shift; - } - } else { - if(srcwidth == (dwords << 2)) { - int decrement = infoRec->ImageWriteRange/dwords; - - while(h > decrement) { - XAAMoveDWORDS((CARD32*)infoRec->ImageWriteBase, - (CARD32*)src, dwords * decrement); - src += (srcwidth * decrement); - h -= decrement; - } - if(h) { - XAAMoveDWORDS((CARD32*)infoRec->ImageWriteBase, - (CARD32*)src, dwords * h); - if(beCareful) src += (srcwidth * h); - } - } else { - while(h--) { - XAAMoveDWORDS((CARD32*)infoRec->ImageWriteBase, - (CARD32*)src, dwords); - src += srcwidth; - } - } - - if(beCareful) { - int shift = ((long)src & 0x03L) << 3; - if(--dwords) - XAAMoveDWORDS((CARD32*)infoRec->ImageWriteBase, - (CARD32*)src, dwords); - src = (unsigned char*)((long)(src + (dwords << 2)) & ~0x03L); - - ((CARD32*)infoRec->ImageWriteBase)[dwords] = - *((CARD32*)src) >> shift; - } - } - - if(PlusOne) { - CARD32* base = (CARD32*)infoRec->ImageWriteBase; - *base = 0x00000000; - } - - if(infoRec->ImageWriteFlags & SYNC_AFTER_IMAGE_WRITE) - (*infoRec->Sync)(pScrn); - else SET_SYNC_FLAG(infoRec); -} - - -void -XAAWritePixmapScanline ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, /* bytes */ - int rop, - unsigned int planemask, - int trans, - int bpp, int depth -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - int dwords, skipleft, bufferNo = 0, Bpp = bpp >> 3; - Bool beCareful = FALSE; - CARD32* base; - - if((skipleft = (long)src & 0x03L)) { - if(!(infoRec->ScanlineImageWriteFlags & LEFT_EDGE_CLIPPING)) { - skipleft = 0; - beCareful = TRUE; - goto BAD_ALIGNMENT; - } - - if(Bpp == 3) - skipleft = 4 - skipleft; - else - skipleft /= Bpp; - - if((x < skipleft) && !(infoRec->ScanlineImageWriteFlags & - LEFT_EDGE_CLIPPING_NEGATIVE_X)) { - skipleft = 0; - beCareful = TRUE; - goto BAD_ALIGNMENT; - } - - x -= skipleft; - w += skipleft; - - if(Bpp == 3) - src -= 3 * skipleft; - else - src = (unsigned char*)((long)src & ~0x03L); - } - -BAD_ALIGNMENT: - - dwords = bytes_to_int32(w * Bpp); - - (*infoRec->SetupForScanlineImageWrite)( - pScrn, rop, planemask, trans, bpp, depth); - (*infoRec->SubsequentScanlineImageWriteRect)(pScrn, x, y, w, h, skipleft); - - if(beCareful) { - /* in cases with bad alignment we have to be careful not - to read beyond the end of the source */ - if(((x * Bpp) + (dwords << 2)) > srcwidth) h--; - else beCareful = FALSE; - } - - while(h--) { - base = (CARD32*)infoRec->ScanlineImageWriteBuffers[bufferNo]; - XAAMoveDWORDS(base, (CARD32*)src, dwords); - (*infoRec->SubsequentImageWriteScanline)(pScrn, bufferNo++); - src += srcwidth; - if(bufferNo >= infoRec->NumScanlineImageWriteBuffers) - bufferNo = 0; - } - - if(beCareful) { - int shift = ((long)src & 0x03L) << 3; - base = (CARD32*)infoRec->ScanlineImageWriteBuffers[bufferNo]; - if(--dwords) - XAAMoveDWORDS(base,(CARD32*)src, dwords); - src = (unsigned char*)((long)(src + (dwords << 2)) & ~0x03L); - - base[dwords] = *((CARD32*)src) >> shift; - (*infoRec->SubsequentImageWriteScanline)(pScrn, bufferNo); - } - - SET_SYNC_FLAG(infoRec); -} - - -void -XAAPutImage( - DrawablePtr pDraw, - GCPtr pGC, - int depth, - int x, - int y, - int w, - int h, - int leftPad, - int format, - char *pImage -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - int bpp = BitsPerPixel(depth); - Bool depthBug = FALSE; - if(!w || !h) return; - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - depthBug = XAA_DEPTH_BUG(pGC); - - if(((format == ZPixmap) && infoRec->WritePixmap && - ((pDraw->bitsPerPixel == bpp) || - ((pDraw->bitsPerPixel == 24) && (bpp == 32) && - (infoRec->WritePixmapFlags & CONVERT_32BPP_TO_24BPP))) && - CHECK_ROP(pGC,infoRec->WritePixmapFlags) && - CHECK_ROPSRC(pGC,infoRec->WritePixmapFlags) && - CHECK_PLANEMASK(pGC,infoRec->WritePixmapFlags) && - CHECK_NO_GXCOPY(pGC,infoRec->WritePixmapFlags)) || - ((format == XYBitmap) && !depthBug && infoRec->WriteBitmap && - CHECK_ROP(pGC,infoRec->WriteBitmapFlags) && - CHECK_ROPSRC(pGC,infoRec->WriteBitmapFlags) && - CHECK_PLANEMASK(pGC,infoRec->WriteBitmapFlags) && - CHECK_COLORS(pGC,infoRec->WriteBitmapFlags) && - !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY)) || - ((format == XYPixmap) && !depthBug && infoRec->WriteBitmap && - CHECK_ROP(pGC,infoRec->WriteBitmapFlags) && - CHECK_ROPSRC(pGC,infoRec->WriteBitmapFlags) && - !(infoRec->WriteBitmapFlags & NO_PLANEMASK) && - !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY))){ - - int MaxBoxes = REGION_NUM_RECTS(pGC->pCompositeClip); - BoxPtr pbox, pClipBoxes; - int nboxes, srcx, srcy, srcwidth; - xRectangle TheRect; - - TheRect.x = pDraw->x + x; - TheRect.y = pDraw->y + y; - TheRect.width = w; - TheRect.height = h; - - if(MaxBoxes > (infoRec->PreAllocSize/sizeof(BoxRec))) { - pClipBoxes = xalloc(MaxBoxes * sizeof(BoxRec)); - if(!pClipBoxes) return; - } else pClipBoxes = (BoxPtr)infoRec->PreAllocMem; - - nboxes = XAAGetRectClipBoxes(pGC, pClipBoxes, 1, &TheRect); - pbox = pClipBoxes; - - if(format == XYBitmap) { - srcwidth = BitmapBytePad(leftPad + w); - while(nboxes--) { - srcx = pbox->x1 - TheRect.x + leftPad; - srcy = pbox->y1 - TheRect.y; - (*infoRec->WriteBitmap)(infoRec->pScrn, pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, - (unsigned char*)pImage + - (srcwidth * srcy) + ((srcx >> 5) << 2), - srcwidth, srcx & 31, pGC->fgPixel, pGC->bgPixel, - pGC->alu, pGC->planemask); - pbox++; - } - } else if(format == ZPixmap) { - int Bpp = bpp >> 3; - srcwidth = PixmapBytePad(leftPad + w, depth); - while(nboxes--) { - srcx = pbox->x1 - TheRect.x + leftPad; - srcy = pbox->y1 - TheRect.y; - (*infoRec->WritePixmap)(infoRec->pScrn, pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, - (unsigned char*)pImage + - (srcwidth * srcy) + (srcx * Bpp), - srcwidth, pGC->alu, pGC->planemask, -1, - Bpp << 3, depth); - pbox++; - } - } else { /* XYPixmap */ - int depth = pGC->depth; - int numBox, increment; - unsigned long i, mask; - BoxPtr pntBox; - - srcwidth = BitmapBytePad(w + leftPad); - increment = h * srcwidth; - i = 1 << (depth - 1); - mask = ~0; - - if((infoRec->pScrn->overlayFlags & OVERLAY_8_32_PLANAR) && - (pGC->depth == 8)){ - i = 0x80000000; mask = 0xff000000; - } - - for(; i & mask; i >>= 1, pImage += increment) { - if(i & pGC->planemask) { - pntBox = pbox; - numBox = nboxes; - while(numBox--) { - srcx = pntBox->x1 - TheRect.x + leftPad; - srcy = pntBox->y1 - TheRect.y; - (*infoRec->WriteBitmap)(infoRec->pScrn, - pntBox->x1, pntBox->y1, - pntBox->x2 - pntBox->x1, - pntBox->y2 - pntBox->y1, - (unsigned char*)pImage + - (srcwidth * srcy) + ((srcx >> 5) << 2), - srcwidth, srcx & 31, ~0, 0, pGC->alu, i); - pntBox++; - } - } - } - - } - - if(pClipBoxes != (BoxPtr)infoRec->PreAllocMem) - xfree(pClipBoxes); - } else - XAAFallbackOps.PutImage(pDraw, pGC, depth, x, y, w, h, leftPad, - format, pImage); -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#include "servermd.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "mi.h" +#include "pixmapstr.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaalocal.h" + +void XAAMoveDWORDS_FixedBase( + register CARD32* dest, + register CARD32* src, + register int dwords ) +{ + while(dwords & ~0x03) { + *dest = *src; + *dest = *(src + 1); + *dest = *(src + 2); + *dest = *(src + 3); + dwords -= 4; + src += 4; + } + + if(!dwords) return; + *dest = *src; + if(dwords == 1) return; + *dest = *(src + 1); + if(dwords == 2) return; + *dest = *(src + 2); +} + +void XAAMoveDWORDS( + register CARD32* dest, + register CARD32* src, + register int dwords ) +{ + while(dwords & ~0x03) { + *dest = *src; + *(dest + 1) = *(src + 1); + *(dest + 2) = *(src + 2); + *(dest + 3) = *(src + 3); + src += 4; + dest += 4; + dwords -= 4; + } + if(!dwords) return; + *dest = *src; + if(dwords == 1) return; + *(dest + 1) = *(src + 1); + if(dwords == 2) return; + *(dest + 2) = *(src + 2); +} + +void XAAMoveDWORDS_FixedSrc( + register CARD32* dest, + register CARD32* src, + register int dwords ) +{ + while(dwords & ~0x03) { + *dest = *src; + *(dest + 1) = *src; + *(dest + 2) = *src; + *(dest + 3) = *src; + dest += 4; + dwords -= 4; + } + if(!dwords) return; + *dest = *src; + if(dwords == 1) return; + *(dest + 1) = *src; + if(dwords == 2) return; + *(dest + 2) = *src; +} + +static void +XAAWritePixmap32To24( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *srcInit, + int srcwidth, /* bytes */ + int rop, + unsigned int planemask, + int trans +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + int count, dwords = bytes_to_int32(w * 3); + CARD32 *src, *dst; + Bool PlusOne = FALSE; + + if((infoRec->ImageWriteFlags & CPU_TRANSFER_PAD_QWORD) && + ((dwords * h) & 0x01)) { + PlusOne = TRUE; + } + + (*infoRec->SetupForImageWrite)(pScrn, rop, planemask, trans, 24, 24); + (*infoRec->SubsequentImageWriteRect)(pScrn, x, y, w, h, 0); + + if(dwords > infoRec->ImageWriteRange) { + dst = (CARD32*)infoRec->ImageWriteBase; + while(h--) { + src = (CARD32*)srcInit; + count = w; + + while(count >= 4) { + *dst = (src[0] & 0x00ffffff) | (src[1] << 24); + *dst = ((src[1] >> 8) & 0x0000ffff) | (src[2] << 16); + *dst = ((src[2] >> 16) & 0x000000ff) | (src[3] << 8); + src += 4; + count -= 4; + } + switch(count) { + case 0: break; + case 1: *dst = src[0]; + break; + case 2: *dst = (src[0] & 0x00ffffff) | (src[1] << 24); + *dst = src[1] >> 8; + break; + default: *dst = (src[0] & 0x00ffffff) | (src[1] << 24); + *dst = ((src[1] >> 8) & 0x0000ffff) | (src[2] << 16); + *dst = src[2] >> 16; + break; + } + srcInit += srcwidth; + } + } else { + while(h--) { + dst = (CARD32*)infoRec->ImageWriteBase; + src = (CARD32*)srcInit; + count = w; + + while(count >= 4) { + dst[0] = (src[0] & 0x00ffffff) | (src[1] << 24); + dst[1] = ((src[1] >> 8) & 0x0000ffff) | (src[2] << 16); + dst[2] = ((src[2] >> 16) & 0x000000ff) | (src[3] << 8); + dst += 3; + src += 4; + count -= 4; + } + switch(count) { + case 0: break; + case 1: dst[0] = src[0]; + break; + case 2: dst[0] = (src[0] & 0x00ffffff) | (src[1] << 24); + dst[1] = src[1] >> 8; + break; + default: dst[0] = (src[0] & 0x00ffffff) | (src[1] << 24); + dst[1] = ((src[1] >> 8) & 0x0000ffff) | (src[2] << 16); + dst[2] = src[2] >> 16; + break; + } + srcInit += srcwidth; + } + } + + if(PlusOne) { + CARD32* base = (CARD32*)infoRec->ImageWriteBase; + *base = 0x00000000; + } + + if(infoRec->ImageWriteFlags & SYNC_AFTER_IMAGE_WRITE) + (*infoRec->Sync)(pScrn); + else SET_SYNC_FLAG(infoRec); + +} + +void +XAAWritePixmap ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, /* bytes */ + int rop, + unsigned int planemask, + int trans, + int bpp, int depth +){ + XAAInfoRecPtr infoRec; + int dwords, skipleft, Bpp; + Bool beCareful, PlusOne; + + if((bpp == 32) && (pScrn->bitsPerPixel == 24)) { + XAAWritePixmap32To24(pScrn, x, y, w, h, src, srcwidth, + rop, planemask, trans); + return; + } + + infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + beCareful = PlusOne = FALSE; + Bpp = bpp >> 3; + + if((skipleft = (long)src & 0x03L)) { + if(!(infoRec->ImageWriteFlags & LEFT_EDGE_CLIPPING)) { + skipleft = 0; + beCareful = TRUE; + goto BAD_ALIGNMENT; + } + + if(Bpp == 3) + skipleft = 4 - skipleft; + else + skipleft /= Bpp; + + if((x < skipleft) && !(infoRec->ImageWriteFlags & + LEFT_EDGE_CLIPPING_NEGATIVE_X)) { + skipleft = 0; + beCareful = TRUE; + goto BAD_ALIGNMENT; + } + + x -= skipleft; + w += skipleft; + + if(Bpp == 3) + src -= 3 * skipleft; + else /* is this Alpha friendly ? */ + src = (unsigned char*)((long)src & ~0x03L); + } + +BAD_ALIGNMENT: + + dwords = bytes_to_int32(w * Bpp); + + if((infoRec->ImageWriteFlags & CPU_TRANSFER_PAD_QWORD) && + ((dwords * h) & 0x01)) { + PlusOne = TRUE; + } + + + (*infoRec->SetupForImageWrite)(pScrn, rop, planemask, trans, bpp, depth); + (*infoRec->SubsequentImageWriteRect)(pScrn, x, y, w, h, skipleft); + + if(beCareful) { + /* in cases with bad alignment we have to be careful not + to read beyond the end of the source */ + if(((x * Bpp) + (dwords << 2)) > srcwidth) h--; + else beCareful = FALSE; + } + + if(dwords > infoRec->ImageWriteRange) { + while(h--) { + XAAMoveDWORDS_FixedBase((CARD32*)infoRec->ImageWriteBase, + (CARD32*)src, dwords); + src += srcwidth; + } + if(beCareful) { + int shift = ((long)src & 0x03L) << 3; + if(--dwords) + XAAMoveDWORDS_FixedBase((CARD32*)infoRec->ImageWriteBase, + (CARD32*)src, dwords); + src = (unsigned char*)((long)(src + (dwords << 2)) & ~0x03L); + *((CARD32*)infoRec->ImageWriteBase) = *((CARD32*)src) >> shift; + } + } else { + if(srcwidth == (dwords << 2)) { + int decrement = infoRec->ImageWriteRange/dwords; + + while(h > decrement) { + XAAMoveDWORDS((CARD32*)infoRec->ImageWriteBase, + (CARD32*)src, dwords * decrement); + src += (srcwidth * decrement); + h -= decrement; + } + if(h) { + XAAMoveDWORDS((CARD32*)infoRec->ImageWriteBase, + (CARD32*)src, dwords * h); + if(beCareful) src += (srcwidth * h); + } + } else { + while(h--) { + XAAMoveDWORDS((CARD32*)infoRec->ImageWriteBase, + (CARD32*)src, dwords); + src += srcwidth; + } + } + + if(beCareful) { + int shift = ((long)src & 0x03L) << 3; + if(--dwords) + XAAMoveDWORDS((CARD32*)infoRec->ImageWriteBase, + (CARD32*)src, dwords); + src = (unsigned char*)((long)(src + (dwords << 2)) & ~0x03L); + + ((CARD32*)infoRec->ImageWriteBase)[dwords] = + *((CARD32*)src) >> shift; + } + } + + if(PlusOne) { + CARD32* base = (CARD32*)infoRec->ImageWriteBase; + *base = 0x00000000; + } + + if(infoRec->ImageWriteFlags & SYNC_AFTER_IMAGE_WRITE) + (*infoRec->Sync)(pScrn); + else SET_SYNC_FLAG(infoRec); +} + + +void +XAAWritePixmapScanline ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, /* bytes */ + int rop, + unsigned int planemask, + int trans, + int bpp, int depth +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + int dwords, skipleft, bufferNo = 0, Bpp = bpp >> 3; + Bool beCareful = FALSE; + CARD32* base; + + if((skipleft = (long)src & 0x03L)) { + if(!(infoRec->ScanlineImageWriteFlags & LEFT_EDGE_CLIPPING)) { + skipleft = 0; + beCareful = TRUE; + goto BAD_ALIGNMENT; + } + + if(Bpp == 3) + skipleft = 4 - skipleft; + else + skipleft /= Bpp; + + if((x < skipleft) && !(infoRec->ScanlineImageWriteFlags & + LEFT_EDGE_CLIPPING_NEGATIVE_X)) { + skipleft = 0; + beCareful = TRUE; + goto BAD_ALIGNMENT; + } + + x -= skipleft; + w += skipleft; + + if(Bpp == 3) + src -= 3 * skipleft; + else + src = (unsigned char*)((long)src & ~0x03L); + } + +BAD_ALIGNMENT: + + dwords = bytes_to_int32(w * Bpp); + + (*infoRec->SetupForScanlineImageWrite)( + pScrn, rop, planemask, trans, bpp, depth); + (*infoRec->SubsequentScanlineImageWriteRect)(pScrn, x, y, w, h, skipleft); + + if(beCareful) { + /* in cases with bad alignment we have to be careful not + to read beyond the end of the source */ + if(((x * Bpp) + (dwords << 2)) > srcwidth) h--; + else beCareful = FALSE; + } + + while(h--) { + base = (CARD32*)infoRec->ScanlineImageWriteBuffers[bufferNo]; + XAAMoveDWORDS(base, (CARD32*)src, dwords); + (*infoRec->SubsequentImageWriteScanline)(pScrn, bufferNo++); + src += srcwidth; + if(bufferNo >= infoRec->NumScanlineImageWriteBuffers) + bufferNo = 0; + } + + if(beCareful) { + int shift = ((long)src & 0x03L) << 3; + base = (CARD32*)infoRec->ScanlineImageWriteBuffers[bufferNo]; + if(--dwords) + XAAMoveDWORDS(base,(CARD32*)src, dwords); + src = (unsigned char*)((long)(src + (dwords << 2)) & ~0x03L); + + base[dwords] = *((CARD32*)src) >> shift; + (*infoRec->SubsequentImageWriteScanline)(pScrn, bufferNo); + } + + SET_SYNC_FLAG(infoRec); +} + + +void +XAAPutImage( + DrawablePtr pDraw, + GCPtr pGC, + int depth, + int x, + int y, + int w, + int h, + int leftPad, + int format, + char *pImage +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + int bpp = BitsPerPixel(depth); + Bool depthBug = FALSE; + if(!w || !h) return; + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + depthBug = XAA_DEPTH_BUG(pGC); + + if(((format == ZPixmap) && infoRec->WritePixmap && + ((pDraw->bitsPerPixel == bpp) || + ((pDraw->bitsPerPixel == 24) && (bpp == 32) && + (infoRec->WritePixmapFlags & CONVERT_32BPP_TO_24BPP))) && + CHECK_ROP(pGC,infoRec->WritePixmapFlags) && + CHECK_ROPSRC(pGC,infoRec->WritePixmapFlags) && + CHECK_PLANEMASK(pGC,infoRec->WritePixmapFlags) && + CHECK_NO_GXCOPY(pGC,infoRec->WritePixmapFlags)) || + ((format == XYBitmap) && !depthBug && infoRec->WriteBitmap && + CHECK_ROP(pGC,infoRec->WriteBitmapFlags) && + CHECK_ROPSRC(pGC,infoRec->WriteBitmapFlags) && + CHECK_PLANEMASK(pGC,infoRec->WriteBitmapFlags) && + CHECK_COLORS(pGC,infoRec->WriteBitmapFlags) && + !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY)) || + ((format == XYPixmap) && !depthBug && infoRec->WriteBitmap && + CHECK_ROP(pGC,infoRec->WriteBitmapFlags) && + CHECK_ROPSRC(pGC,infoRec->WriteBitmapFlags) && + !(infoRec->WriteBitmapFlags & NO_PLANEMASK) && + !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY))){ + + int MaxBoxes = REGION_NUM_RECTS(pGC->pCompositeClip); + BoxPtr pbox, pClipBoxes; + int nboxes, srcx, srcy, srcwidth; + xRectangle TheRect; + + TheRect.x = pDraw->x + x; + TheRect.y = pDraw->y + y; + TheRect.width = w; + TheRect.height = h; + + if(MaxBoxes > (infoRec->PreAllocSize/sizeof(BoxRec))) { + pClipBoxes = malloc(MaxBoxes * sizeof(BoxRec)); + if(!pClipBoxes) return; + } else pClipBoxes = (BoxPtr)infoRec->PreAllocMem; + + nboxes = XAAGetRectClipBoxes(pGC, pClipBoxes, 1, &TheRect); + pbox = pClipBoxes; + + if(format == XYBitmap) { + srcwidth = BitmapBytePad(leftPad + w); + while(nboxes--) { + srcx = pbox->x1 - TheRect.x + leftPad; + srcy = pbox->y1 - TheRect.y; + (*infoRec->WriteBitmap)(infoRec->pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, + (unsigned char*)pImage + + (srcwidth * srcy) + ((srcx >> 5) << 2), + srcwidth, srcx & 31, pGC->fgPixel, pGC->bgPixel, + pGC->alu, pGC->planemask); + pbox++; + } + } else if(format == ZPixmap) { + int Bpp = bpp >> 3; + srcwidth = PixmapBytePad(leftPad + w, depth); + while(nboxes--) { + srcx = pbox->x1 - TheRect.x + leftPad; + srcy = pbox->y1 - TheRect.y; + (*infoRec->WritePixmap)(infoRec->pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, + (unsigned char*)pImage + + (srcwidth * srcy) + (srcx * Bpp), + srcwidth, pGC->alu, pGC->planemask, -1, + Bpp << 3, depth); + pbox++; + } + } else { /* XYPixmap */ + int depth = pGC->depth; + int numBox, increment; + unsigned long i, mask; + BoxPtr pntBox; + + srcwidth = BitmapBytePad(w + leftPad); + increment = h * srcwidth; + i = 1 << (depth - 1); + mask = ~0; + + if((infoRec->pScrn->overlayFlags & OVERLAY_8_32_PLANAR) && + (pGC->depth == 8)){ + i = 0x80000000; mask = 0xff000000; + } + + for(; i & mask; i >>= 1, pImage += increment) { + if(i & pGC->planemask) { + pntBox = pbox; + numBox = nboxes; + while(numBox--) { + srcx = pntBox->x1 - TheRect.x + leftPad; + srcy = pntBox->y1 - TheRect.y; + (*infoRec->WriteBitmap)(infoRec->pScrn, + pntBox->x1, pntBox->y1, + pntBox->x2 - pntBox->x1, + pntBox->y2 - pntBox->y1, + (unsigned char*)pImage + + (srcwidth * srcy) + ((srcx >> 5) << 2), + srcwidth, srcx & 31, ~0, 0, pGC->alu, i); + pntBox++; + } + } + } + + } + + if(pClipBoxes != (BoxPtr)infoRec->PreAllocMem) + free(pClipBoxes); + } else + XAAFallbackOps.PutImage(pDraw, pGC, depth, x, y, w, h, leftPad, + format, pImage); +} diff --git a/xorg-server/hw/xfree86/xaa/xaaInit.c b/xorg-server/hw/xfree86/xaa/xaaInit.c index 7d4583dc2..58efb6a82 100644 --- a/xorg-server/hw/xfree86/xaa/xaaInit.c +++ b/xorg-server/hw/xfree86/xaa/xaaInit.c @@ -1,624 +1,624 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "xf86str.h" -#include "mi.h" -#include "miline.h" -#include "xaa.h" -#include "xaalocal.h" -#include "xaawrap.h" -#include "xf86fbman.h" -#include "servermd.h" -#ifdef COMPOSITE -#include "cw.h" -#endif - -#define MAX_PREALLOC_MEM 65536 /* MUST be >= 1024 */ - -#define MIN_OFFPIX_SIZE (320*200) - -static Bool XAACloseScreen(int i, ScreenPtr pScreen); -static void XAAGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, - unsigned int format, unsigned long planemask, - char *pdstLine); -static void XAAGetSpans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, - int *pwidth, int nspans, char *pdstStart); -static PixmapPtr XAACreatePixmap(ScreenPtr pScreen, int w, int h, int depth, - unsigned usage_hint); -static Bool XAADestroyPixmap(PixmapPtr pPixmap); -static Bool XAAEnterVT (int index, int flags); -static void XAALeaveVT (int index, int flags); -static int XAASetDGAMode(int index, int num, DGADevicePtr devRet); -static void XAAEnableDisableFBAccess (int index, Bool enable); -static Bool XAAChangeWindowAttributes (WindowPtr pWin, unsigned long mask); - -static int XAAScreenKeyIndex; -static DevPrivateKey XAAScreenKey = &XAAScreenKeyIndex; -static int XAAGCKeyIndex; -static DevPrivateKey XAAGCKey = &XAAGCKeyIndex; -static int XAAPixmapKeyIndex; -static DevPrivateKey XAAPixmapKey = &XAAPixmapKeyIndex; - -DevPrivateKey XAAGetScreenKey(void) { - return XAAScreenKey; -} - -DevPrivateKey XAAGetGCKey(void) { - return XAAGCKey; -} - -DevPrivateKey XAAGetPixmapKey(void) { - return XAAPixmapKey; -} - -/* temp kludge */ -static Bool SwitchedOut = FALSE; - -XAAInfoRecPtr -XAACreateInfoRec(void) -{ - XAAInfoRecPtr infoRec; - - infoRec = xcalloc(1, sizeof(XAAInfoRec)); - if(infoRec) - infoRec->CachePixelGranularity = -1; - - return infoRec; -} - -void -XAADestroyInfoRec(XAAInfoRecPtr infoRec) -{ - if(!infoRec) return; - - if(infoRec->ClosePixmapCache) - (*infoRec->ClosePixmapCache)(infoRec->pScrn->pScreen); - - if(infoRec->PreAllocMem) - xfree(infoRec->PreAllocMem); - - if(infoRec->PixmapCachePrivate) - xfree(infoRec->PixmapCachePrivate); - - xfree(infoRec); -} - - -Bool -XAAInit(ScreenPtr pScreen, XAAInfoRecPtr infoRec) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - XAAScreenPtr pScreenPriv; - int i; - PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); - - /* Return successfully if no acceleration wanted */ - if (!infoRec) - return TRUE; - - if (!dixRequestPrivate(XAAGCKey, sizeof(XAAGCRec))) - return FALSE; - - if (!dixRequestPrivate(XAAPixmapKey, sizeof(XAAPixmapRec))) - return FALSE; - - if (!(pScreenPriv = xalloc(sizeof(XAAScreenRec)))) - return FALSE; - - dixSetPrivate(&pScreen->devPrivates, XAAScreenKey, pScreenPriv); - - if(!xf86FBManagerRunning(pScreen)) - infoRec->Flags &= ~(PIXMAP_CACHE | OFFSCREEN_PIXMAPS); - if(!(infoRec->Flags & LINEAR_FRAMEBUFFER)) - infoRec->Flags &= ~OFFSCREEN_PIXMAPS; - - if(!infoRec->FullPlanemask) { /* for backwards compatibility */ - infoRec->FullPlanemask = (1 << pScrn->depth) - 1; - infoRec->FullPlanemasks[pScrn->depth - 1] = infoRec->FullPlanemask; - } - - for(i = 0; i < 32; i++) { - if(!infoRec->FullPlanemasks[i]) /* keep any set by caller */ - infoRec->FullPlanemasks[i] = (1 << (i+1)) - 1; - } - - if(!XAAInitAccel(pScreen, infoRec)) return FALSE; - pScreenPriv->AccelInfoRec = infoRec; - infoRec->ScratchGC.pScreen = pScreen; - - - if(!infoRec->GetImage) - infoRec->GetImage = XAAGetImage; - if(!infoRec->GetSpans) - infoRec->GetSpans = XAAGetSpans; - if(!infoRec->CopyWindow) - infoRec->CopyWindow = XAACopyWindow; - - pScreenPriv->CreateGC = pScreen->CreateGC; - pScreen->CreateGC = XAACreateGC; - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = XAACloseScreen; - pScreenPriv->GetImage = pScreen->GetImage; - pScreen->GetImage = infoRec->GetImage; - pScreenPriv->GetSpans = pScreen->GetSpans; - pScreen->GetSpans = infoRec->GetSpans; - pScreenPriv->CopyWindow = pScreen->CopyWindow; - pScreen->CopyWindow = infoRec->CopyWindow; - pScreenPriv->CreatePixmap = pScreen->CreatePixmap; - pScreen->CreatePixmap = XAACreatePixmap; - pScreenPriv->DestroyPixmap = pScreen->DestroyPixmap; - pScreen->DestroyPixmap = XAADestroyPixmap; - pScreenPriv->ChangeWindowAttributes = pScreen->ChangeWindowAttributes; - pScreen->ChangeWindowAttributes = XAAChangeWindowAttributes; - - pScreenPriv->EnterVT = pScrn->EnterVT; - pScrn->EnterVT = XAAEnterVT; - pScreenPriv->LeaveVT = pScrn->LeaveVT; - pScrn->LeaveVT = XAALeaveVT; - pScreenPriv->SetDGAMode = pScrn->SetDGAMode; - pScrn->SetDGAMode = XAASetDGAMode; - pScreenPriv->EnableDisableFBAccess = pScrn->EnableDisableFBAccess; - pScrn->EnableDisableFBAccess = XAAEnableDisableFBAccess; - - pScreenPriv->WindowExposures = pScreen->WindowExposures; - if (ps) - { - pScreenPriv->Composite = ps->Composite; - ps->Composite = XAAComposite; - pScreenPriv->Glyphs = ps->Glyphs; - ps->Glyphs = XAAGlyphs; - } - if(pScrn->overlayFlags & OVERLAY_8_32_PLANAR) - XAASetupOverlay8_32Planar(pScreen); - - infoRec->PreAllocMem = xalloc(MAX_PREALLOC_MEM); - if(infoRec->PreAllocMem) - infoRec->PreAllocSize = MAX_PREALLOC_MEM; - - if(infoRec->Flags & PIXMAP_CACHE) - xf86RegisterFreeBoxCallback(pScreen, infoRec->InitPixmapCache, - (pointer)infoRec); - - if(infoRec->Flags & MICROSOFT_ZERO_LINE_BIAS) - miSetZeroLineBias(pScreen, OCTANT1 | OCTANT2 | OCTANT3 | OCTANT4); - -#ifdef COMPOSITE - /* Initialize the composite wrapper. This needs to happen after the - * wrapping above (so it comes before us), but before all other extensions, - * so it doesn't confuse them. (particularly damage). - */ - miInitializeCompositeWrapper(pScreen); -#endif - - return TRUE; -} - - - -static Bool -XAACloseScreen (int i, ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - XAAScreenPtr pScreenPriv = - (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); - - pScrn->EnterVT = pScreenPriv->EnterVT; - pScrn->LeaveVT = pScreenPriv->LeaveVT; - pScrn->EnableDisableFBAccess = pScreenPriv->EnableDisableFBAccess; - - pScreen->CreateGC = pScreenPriv->CreateGC; - pScreen->CloseScreen = pScreenPriv->CloseScreen; - pScreen->GetImage = pScreenPriv->GetImage; - pScreen->GetSpans = pScreenPriv->GetSpans; - pScreen->CopyWindow = pScreenPriv->CopyWindow; - pScreen->WindowExposures = pScreenPriv->WindowExposures; - pScreen->CreatePixmap = pScreenPriv->CreatePixmap; - pScreen->DestroyPixmap = pScreenPriv->DestroyPixmap; - pScreen->ChangeWindowAttributes = pScreenPriv->ChangeWindowAttributes; - - /* We leave it up to the client to free the XAAInfoRec */ - - xfree ((pointer) pScreenPriv); - - return (*pScreen->CloseScreen) (i, pScreen); -} - -static void -XAAGetImage ( - DrawablePtr pDraw, - int sx, int sy, int w, int h, - unsigned int format, - unsigned long planemask, - char *pdstLine -) -{ - ScreenPtr pScreen = pDraw->pScreen; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - ScrnInfoPtr pScrn = infoRec->pScrn; - - if(pScrn->vtSema && - ((pDraw->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pDraw))) - { - if(infoRec->ReadPixmap && (format == ZPixmap) && - ((planemask & infoRec->FullPlanemasks[pDraw->depth - 1]) == - infoRec->FullPlanemasks[pDraw->depth - 1]) && - (pDraw->bitsPerPixel == BitsPerPixel(pDraw->depth))) - { - (*infoRec->ReadPixmap)(pScrn, - sx + pDraw->x, sy + pDraw->y, w, h, - (unsigned char *)pdstLine, - PixmapBytePad(w, pDraw->depth), - pDraw->bitsPerPixel, pDraw->depth); - return; - } - SYNC_CHECK(pDraw); - } - - XAA_SCREEN_PROLOGUE (pScreen, GetImage); - (*pScreen->GetImage) (pDraw, sx, sy, w, h, format, planemask, pdstLine); - XAA_SCREEN_EPILOGUE (pScreen, GetImage, XAAGetImage); -} - -static void -XAAGetSpans ( - DrawablePtr pDraw, - int wMax, - DDXPointPtr ppt, - int *pwidth, - int nspans, - char *pdstStart -) -{ - ScreenPtr pScreen = pDraw->pScreen; - XAA_SCREEN_PROLOGUE (pScreen, GetSpans); - if(xf86Screens[pScreen->myNum]->vtSema && - ((pDraw->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pDraw))) { - SYNC_CHECK(pDraw); - } - (*pScreen->GetSpans) (pDraw, wMax, ppt, pwidth, nspans, pdstStart); - XAA_SCREEN_EPILOGUE (pScreen, GetSpans, XAAGetSpans); -} - - -static int -XAAPixmapBPP (ScreenPtr pScreen, int depth) -{ - PixmapPtr pPix; - int bpp; - DestroyPixmapProcPtr destroyPixmap; - - XAA_SCREEN_PROLOGUE (pScreen, CreatePixmap); - pPix = (*pScreen->CreatePixmap) (pScreen, 1, 1, depth, - CREATE_PIXMAP_USAGE_SCRATCH); - XAA_SCREEN_EPILOGUE (pScreen, CreatePixmap, XAACreatePixmap); - if (!pPix) - return 0; - bpp = pPix->drawable.bitsPerPixel; - destroyPixmap = pScreen->DestroyPixmap; - XAA_SCREEN_PROLOGUE (pScreen, DestroyPixmap); - (*pScreen->DestroyPixmap) (pPix); - XAA_SCREEN_EPILOGUE (pScreen, DestroyPixmap, destroyPixmap); - return bpp; -} - -static void -XAAInitializeOffscreenDepths (ScreenPtr pScreen) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - int d, dep; - - infoRec->offscreenDepthsInitialized = TRUE; - infoRec->offscreenDepths = 0; - if (infoRec->Flags & OFFSCREEN_PIXMAPS) { - for (d = 0; d < pScreen->numDepths; d++) { - dep = pScreen->allowedDepths[d].depth; - if (XAAPixmapBPP (pScreen, dep) == pScrn->bitsPerPixel) - infoRec->offscreenDepths |= (1 << (dep - 1)); - } - } -} - -static PixmapPtr -XAACreatePixmap(ScreenPtr pScreen, int w, int h, int depth, unsigned usage_hint) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - XAAPixmapPtr pPriv; - PixmapPtr pPix = NULL; - int size = w * h; - - if (w > 32767 || h > 32767) - return NullPixmap; - - if (!infoRec->offscreenDepthsInitialized) - XAAInitializeOffscreenDepths (pScreen); - - if(pScrn->vtSema && - (usage_hint != CREATE_PIXMAP_USAGE_GLYPH_PICTURE) && - (infoRec->offscreenDepths & (1 << (depth - 1))) && - (size >= MIN_OFFPIX_SIZE) && !SwitchedOut && - (!infoRec->maxOffPixWidth || (w <= infoRec->maxOffPixWidth)) && - (!infoRec->maxOffPixHeight || (h <= infoRec->maxOffPixHeight)) ) - { - PixmapLinkPtr pLink; - PixmapPtr pScreenPix; - FBAreaPtr area; - int gran = 0; - - switch(pScrn->bitsPerPixel) { - case 24: - case 8: gran = 4; break; - case 16: gran = 2; break; - case 32: gran = 1; break; - default: break; - } - - if(BITMAP_SCANLINE_PAD == 64) - gran *= 2; - - if(!(area = xf86AllocateOffscreenArea(pScreen, w, h, gran, 0, - XAARemoveAreaCallback, NULL))) { - goto BAILOUT; - } - - if(!(pLink = xalloc(sizeof(PixmapLink)))) { - xf86FreeOffscreenArea(area); - goto BAILOUT; - } - - XAA_SCREEN_PROLOGUE (pScreen, CreatePixmap); - pPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, usage_hint); - XAA_SCREEN_EPILOGUE (pScreen, CreatePixmap, XAACreatePixmap); - - if (!pPix) { - xfree (pLink); - xf86FreeOffscreenArea(area); - goto BAILOUT; - } - - pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); - - pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); - pPix->drawable.x = area->box.x1; - pPix->drawable.y = area->box.y1; - pPix->drawable.width = w; - pPix->drawable.height = h; - pPix->drawable.bitsPerPixel = pScrn->bitsPerPixel; - pPix->devKind = pScreenPix->devKind; - pPix->devPrivate.ptr = pScreenPix->devPrivate.ptr; - area->devPrivate.ptr = pPix; - - pPriv->flags = OFFSCREEN; - pPriv->offscreenArea = area; - pPriv->freeData = FALSE; - - pLink->next = infoRec->OffscreenPixmaps; - pLink->pPix = pPix; - infoRec->OffscreenPixmaps = pLink; - return pPix; - } -BAILOUT: - XAA_SCREEN_PROLOGUE (pScreen, CreatePixmap); - pPix = (*pScreen->CreatePixmap) (pScreen, w, h, depth, usage_hint); - XAA_SCREEN_EPILOGUE (pScreen, CreatePixmap, XAACreatePixmap); - - if(pPix) { - pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); - pPriv->flags = 0; - pPriv->offscreenArea = NULL; - pPriv->freeData = FALSE; - if(!w || !h) /* either scratch or shared memory */ - pPriv->flags |= SHARED_PIXMAP; - } - - return pPix; -} - -static Bool -XAADestroyPixmap(PixmapPtr pPix) -{ - ScreenPtr pScreen = pPix->drawable.pScreen; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); - Bool ret; - - if(pPix->refcnt == 1) { - if(pPriv->flags & OFFSCREEN) { - if(pPriv->flags & DGA_PIXMAP) - xfree(pPriv->offscreenArea); - else { - FBAreaPtr area = pPriv->offscreenArea; - PixmapLinkPtr pLink = infoRec->OffscreenPixmaps; - PixmapLinkPtr prev = NULL; - - while(pLink->pPix != pPix) { - prev = pLink; - pLink = pLink->next; - } - - if(prev) prev->next = pLink->next; - else infoRec->OffscreenPixmaps = pLink->next; - - if(!area) area = pLink->area; - - xf86FreeOffscreenArea(area); - pPriv->offscreenArea = NULL; - xfree(pLink); - } - } - - if(pPriv->freeData) { /* pixmaps that were once in video ram */ - xfree(pPix->devPrivate.ptr); - pPix->devPrivate.ptr = NULL; - } - } - - XAA_SCREEN_PROLOGUE (pScreen, DestroyPixmap); - ret = (*pScreen->DestroyPixmap) (pPix); - XAA_SCREEN_EPILOGUE (pScreen, DestroyPixmap, XAADestroyPixmap); - - return ret; -} - -static Bool -XAAChangeWindowAttributes (WindowPtr pWin, unsigned long mask) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - Bool ret; - - XAA_SCREEN_PROLOGUE (pScreen, ChangeWindowAttributes); - ret = (*pScreen->ChangeWindowAttributes) (pWin, mask); - XAA_SCREEN_EPILOGUE (pScreen, ChangeWindowAttributes, XAAChangeWindowAttributes); - - /* we have to assume that shared memory pixmaps are dirty - because we can't wrap operations on them */ - - if((mask & CWBackPixmap) && (pWin->backgroundState == BackgroundPixmap) && - PIXMAP_IS_SHARED(pWin->background.pixmap)) - { - XAAPixmapPtr pPixPriv = XAA_GET_PIXMAP_PRIVATE(pWin->background.pixmap); - pPixPriv->flags |= DIRTY; - } - if((mask & CWBorderPixmap) && !(pWin->borderIsPixel) && - PIXMAP_IS_SHARED(pWin->border.pixmap)) - { - XAAPixmapPtr pPixPriv = XAA_GET_PIXMAP_PRIVATE(pWin->border.pixmap); - pPixPriv->flags |= DIRTY; - } - - return ret; -} - - - -/* These two aren't really needed for anything */ - -static Bool -XAAEnterVT(int index, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - XAAScreenPtr pScreenPriv = - (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); - - return((*pScreenPriv->EnterVT)(index, flags)); -} - -static void -XAALeaveVT(int index, int flags) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - XAAScreenPtr pScreenPriv = - (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); - XAAInfoRecPtr infoRec = pScreenPriv->AccelInfoRec; - - if(infoRec->NeedToSync) { - (*infoRec->Sync)(infoRec->pScrn); - infoRec->NeedToSync = FALSE; - } - - (*pScreenPriv->LeaveVT)(index, flags); -} - -typedef struct { - Bool UsingPixmapCache; - Bool CanDoColor8x8; - Bool CanDoMono8x8; -} SavedCacheState, *SavedCacheStatePtr; - -static int -XAASetDGAMode(int index, int num, DGADevicePtr devRet) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - XAAScreenPtr pScreenPriv = - (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); - int ret; - - if (!num && infoRec->dgaSaves) { /* restore old pixmap cache state */ - SavedCacheStatePtr state = (SavedCacheStatePtr)infoRec->dgaSaves; - - infoRec->UsingPixmapCache = state->UsingPixmapCache; - infoRec->CanDoColor8x8 = state->CanDoColor8x8; - infoRec->CanDoMono8x8 = state->CanDoMono8x8; - xfree(infoRec->dgaSaves); - infoRec->dgaSaves = NULL; - } - - ret = (*pScreenPriv->SetDGAMode)(index, num, devRet); - if(ret != Success) return ret; - - if(num && devRet->pPix) { /* accelerate this pixmap */ - XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(devRet->pPix); - FBAreaPtr area; - - if((area = xalloc(sizeof(FBArea)))) { - area->pScreen = pScreen; - area->box.x1 = 0; - area->box.x2 = 0; - area->box.y1 = devRet->mode->pixmapWidth; - area->box.y2 = devRet->mode->pixmapHeight; - area->granularity = 0; - area->MoveAreaCallback = 0; - area->RemoveAreaCallback = 0; - area->devPrivate.ptr = 0; - - pixPriv->flags |= OFFSCREEN | DGA_PIXMAP; - pixPriv->offscreenArea = area; - - if(!infoRec->dgaSaves) { /* save pixmap cache state */ - SavedCacheStatePtr state = xalloc(sizeof(SavedCacheState)); - - state->UsingPixmapCache = infoRec->UsingPixmapCache; - state->CanDoColor8x8 = infoRec->CanDoColor8x8; - state->CanDoMono8x8 = infoRec->CanDoMono8x8; - infoRec->dgaSaves = (char*)state; - - infoRec->UsingPixmapCache = FALSE; - if(infoRec->PixmapCacheFlags & CACHE_MONO_8x8) - infoRec->CanDoMono8x8 = FALSE; - if(infoRec->PixmapCacheFlags & CACHE_COLOR_8x8) - infoRec->CanDoColor8x8 = FALSE; - } - } - } - - return ret; -} - - - -static void -XAAEnableDisableFBAccess (int index, Bool enable) -{ - ScreenPtr pScreen = screenInfo.screens[index]; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - XAAScreenPtr pScreenPriv = - (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); - - if(!enable) { - if((infoRec->Flags & OFFSCREEN_PIXMAPS) && (infoRec->OffscreenPixmaps)) - XAAMoveOutOffscreenPixmaps(pScreen); - if(infoRec->Flags & PIXMAP_CACHE) - XAAInvalidatePixmapCache(pScreen); - SwitchedOut = TRUE; - } - - (*pScreenPriv->EnableDisableFBAccess)(index, enable); - - if(enable) { - if((infoRec->Flags & OFFSCREEN_PIXMAPS) && (infoRec->OffscreenPixmaps)) - XAAMoveInOffscreenPixmaps(pScreen); - SwitchedOut = FALSE; - } -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "xf86str.h" +#include "mi.h" +#include "miline.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xaawrap.h" +#include "xf86fbman.h" +#include "servermd.h" +#ifdef COMPOSITE +#include "cw.h" +#endif + +#define MAX_PREALLOC_MEM 65536 /* MUST be >= 1024 */ + +#define MIN_OFFPIX_SIZE (320*200) + +static Bool XAACloseScreen(int i, ScreenPtr pScreen); +static void XAAGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planemask, + char *pdstLine); +static void XAAGetSpans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, + int *pwidth, int nspans, char *pdstStart); +static PixmapPtr XAACreatePixmap(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint); +static Bool XAADestroyPixmap(PixmapPtr pPixmap); +static Bool XAAEnterVT (int index, int flags); +static void XAALeaveVT (int index, int flags); +static int XAASetDGAMode(int index, int num, DGADevicePtr devRet); +static void XAAEnableDisableFBAccess (int index, Bool enable); +static Bool XAAChangeWindowAttributes (WindowPtr pWin, unsigned long mask); + +static int XAAScreenKeyIndex; +static DevPrivateKey XAAScreenKey = &XAAScreenKeyIndex; +static int XAAGCKeyIndex; +static DevPrivateKey XAAGCKey = &XAAGCKeyIndex; +static int XAAPixmapKeyIndex; +static DevPrivateKey XAAPixmapKey = &XAAPixmapKeyIndex; + +DevPrivateKey XAAGetScreenKey(void) { + return XAAScreenKey; +} + +DevPrivateKey XAAGetGCKey(void) { + return XAAGCKey; +} + +DevPrivateKey XAAGetPixmapKey(void) { + return XAAPixmapKey; +} + +/* temp kludge */ +static Bool SwitchedOut = FALSE; + +XAAInfoRecPtr +XAACreateInfoRec(void) +{ + XAAInfoRecPtr infoRec; + + infoRec = calloc(1, sizeof(XAAInfoRec)); + if(infoRec) + infoRec->CachePixelGranularity = -1; + + return infoRec; +} + +void +XAADestroyInfoRec(XAAInfoRecPtr infoRec) +{ + if(!infoRec) return; + + if(infoRec->ClosePixmapCache) + (*infoRec->ClosePixmapCache)(infoRec->pScrn->pScreen); + + if(infoRec->PreAllocMem) + free(infoRec->PreAllocMem); + + if(infoRec->PixmapCachePrivate) + free(infoRec->PixmapCachePrivate); + + free(infoRec); +} + + +Bool +XAAInit(ScreenPtr pScreen, XAAInfoRecPtr infoRec) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XAAScreenPtr pScreenPriv; + int i; + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + + /* Return successfully if no acceleration wanted */ + if (!infoRec) + return TRUE; + + if (!dixRequestPrivate(XAAGCKey, sizeof(XAAGCRec))) + return FALSE; + + if (!dixRequestPrivate(XAAPixmapKey, sizeof(XAAPixmapRec))) + return FALSE; + + if (!(pScreenPriv = malloc(sizeof(XAAScreenRec)))) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, XAAScreenKey, pScreenPriv); + + if(!xf86FBManagerRunning(pScreen)) + infoRec->Flags &= ~(PIXMAP_CACHE | OFFSCREEN_PIXMAPS); + if(!(infoRec->Flags & LINEAR_FRAMEBUFFER)) + infoRec->Flags &= ~OFFSCREEN_PIXMAPS; + + if(!infoRec->FullPlanemask) { /* for backwards compatibility */ + infoRec->FullPlanemask = (1 << pScrn->depth) - 1; + infoRec->FullPlanemasks[pScrn->depth - 1] = infoRec->FullPlanemask; + } + + for(i = 0; i < 32; i++) { + if(!infoRec->FullPlanemasks[i]) /* keep any set by caller */ + infoRec->FullPlanemasks[i] = (1 << (i+1)) - 1; + } + + if(!XAAInitAccel(pScreen, infoRec)) return FALSE; + pScreenPriv->AccelInfoRec = infoRec; + infoRec->ScratchGC.pScreen = pScreen; + + + if(!infoRec->GetImage) + infoRec->GetImage = XAAGetImage; + if(!infoRec->GetSpans) + infoRec->GetSpans = XAAGetSpans; + if(!infoRec->CopyWindow) + infoRec->CopyWindow = XAACopyWindow; + + pScreenPriv->CreateGC = pScreen->CreateGC; + pScreen->CreateGC = XAACreateGC; + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = XAACloseScreen; + pScreenPriv->GetImage = pScreen->GetImage; + pScreen->GetImage = infoRec->GetImage; + pScreenPriv->GetSpans = pScreen->GetSpans; + pScreen->GetSpans = infoRec->GetSpans; + pScreenPriv->CopyWindow = pScreen->CopyWindow; + pScreen->CopyWindow = infoRec->CopyWindow; + pScreenPriv->CreatePixmap = pScreen->CreatePixmap; + pScreen->CreatePixmap = XAACreatePixmap; + pScreenPriv->DestroyPixmap = pScreen->DestroyPixmap; + pScreen->DestroyPixmap = XAADestroyPixmap; + pScreenPriv->ChangeWindowAttributes = pScreen->ChangeWindowAttributes; + pScreen->ChangeWindowAttributes = XAAChangeWindowAttributes; + + pScreenPriv->EnterVT = pScrn->EnterVT; + pScrn->EnterVT = XAAEnterVT; + pScreenPriv->LeaveVT = pScrn->LeaveVT; + pScrn->LeaveVT = XAALeaveVT; + pScreenPriv->SetDGAMode = pScrn->SetDGAMode; + pScrn->SetDGAMode = XAASetDGAMode; + pScreenPriv->EnableDisableFBAccess = pScrn->EnableDisableFBAccess; + pScrn->EnableDisableFBAccess = XAAEnableDisableFBAccess; + + pScreenPriv->WindowExposures = pScreen->WindowExposures; + if (ps) + { + pScreenPriv->Composite = ps->Composite; + ps->Composite = XAAComposite; + pScreenPriv->Glyphs = ps->Glyphs; + ps->Glyphs = XAAGlyphs; + } + if(pScrn->overlayFlags & OVERLAY_8_32_PLANAR) + XAASetupOverlay8_32Planar(pScreen); + + infoRec->PreAllocMem = malloc(MAX_PREALLOC_MEM); + if(infoRec->PreAllocMem) + infoRec->PreAllocSize = MAX_PREALLOC_MEM; + + if(infoRec->Flags & PIXMAP_CACHE) + xf86RegisterFreeBoxCallback(pScreen, infoRec->InitPixmapCache, + (pointer)infoRec); + + if(infoRec->Flags & MICROSOFT_ZERO_LINE_BIAS) + miSetZeroLineBias(pScreen, OCTANT1 | OCTANT2 | OCTANT3 | OCTANT4); + +#ifdef COMPOSITE + /* Initialize the composite wrapper. This needs to happen after the + * wrapping above (so it comes before us), but before all other extensions, + * so it doesn't confuse them. (particularly damage). + */ + miInitializeCompositeWrapper(pScreen); +#endif + + return TRUE; +} + + + +static Bool +XAACloseScreen (int i, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XAAScreenPtr pScreenPriv = + (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); + + pScrn->EnterVT = pScreenPriv->EnterVT; + pScrn->LeaveVT = pScreenPriv->LeaveVT; + pScrn->EnableDisableFBAccess = pScreenPriv->EnableDisableFBAccess; + + pScreen->CreateGC = pScreenPriv->CreateGC; + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->GetImage = pScreenPriv->GetImage; + pScreen->GetSpans = pScreenPriv->GetSpans; + pScreen->CopyWindow = pScreenPriv->CopyWindow; + pScreen->WindowExposures = pScreenPriv->WindowExposures; + pScreen->CreatePixmap = pScreenPriv->CreatePixmap; + pScreen->DestroyPixmap = pScreenPriv->DestroyPixmap; + pScreen->ChangeWindowAttributes = pScreenPriv->ChangeWindowAttributes; + + /* We leave it up to the client to free the XAAInfoRec */ + + free((pointer) pScreenPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void +XAAGetImage ( + DrawablePtr pDraw, + int sx, int sy, int w, int h, + unsigned int format, + unsigned long planemask, + char *pdstLine +) +{ + ScreenPtr pScreen = pDraw->pScreen; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + ScrnInfoPtr pScrn = infoRec->pScrn; + + if(pScrn->vtSema && + ((pDraw->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pDraw))) + { + if(infoRec->ReadPixmap && (format == ZPixmap) && + ((planemask & infoRec->FullPlanemasks[pDraw->depth - 1]) == + infoRec->FullPlanemasks[pDraw->depth - 1]) && + (pDraw->bitsPerPixel == BitsPerPixel(pDraw->depth))) + { + (*infoRec->ReadPixmap)(pScrn, + sx + pDraw->x, sy + pDraw->y, w, h, + (unsigned char *)pdstLine, + PixmapBytePad(w, pDraw->depth), + pDraw->bitsPerPixel, pDraw->depth); + return; + } + SYNC_CHECK(pDraw); + } + + XAA_SCREEN_PROLOGUE (pScreen, GetImage); + (*pScreen->GetImage) (pDraw, sx, sy, w, h, format, planemask, pdstLine); + XAA_SCREEN_EPILOGUE (pScreen, GetImage, XAAGetImage); +} + +static void +XAAGetSpans ( + DrawablePtr pDraw, + int wMax, + DDXPointPtr ppt, + int *pwidth, + int nspans, + char *pdstStart +) +{ + ScreenPtr pScreen = pDraw->pScreen; + XAA_SCREEN_PROLOGUE (pScreen, GetSpans); + if(xf86Screens[pScreen->myNum]->vtSema && + ((pDraw->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pDraw))) { + SYNC_CHECK(pDraw); + } + (*pScreen->GetSpans) (pDraw, wMax, ppt, pwidth, nspans, pdstStart); + XAA_SCREEN_EPILOGUE (pScreen, GetSpans, XAAGetSpans); +} + + +static int +XAAPixmapBPP (ScreenPtr pScreen, int depth) +{ + PixmapPtr pPix; + int bpp; + DestroyPixmapProcPtr destroyPixmap; + + XAA_SCREEN_PROLOGUE (pScreen, CreatePixmap); + pPix = (*pScreen->CreatePixmap) (pScreen, 1, 1, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + XAA_SCREEN_EPILOGUE (pScreen, CreatePixmap, XAACreatePixmap); + if (!pPix) + return 0; + bpp = pPix->drawable.bitsPerPixel; + destroyPixmap = pScreen->DestroyPixmap; + XAA_SCREEN_PROLOGUE (pScreen, DestroyPixmap); + (*pScreen->DestroyPixmap) (pPix); + XAA_SCREEN_EPILOGUE (pScreen, DestroyPixmap, destroyPixmap); + return bpp; +} + +static void +XAAInitializeOffscreenDepths (ScreenPtr pScreen) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + int d, dep; + + infoRec->offscreenDepthsInitialized = TRUE; + infoRec->offscreenDepths = 0; + if (infoRec->Flags & OFFSCREEN_PIXMAPS) { + for (d = 0; d < pScreen->numDepths; d++) { + dep = pScreen->allowedDepths[d].depth; + if (XAAPixmapBPP (pScreen, dep) == pScrn->bitsPerPixel) + infoRec->offscreenDepths |= (1 << (dep - 1)); + } + } +} + +static PixmapPtr +XAACreatePixmap(ScreenPtr pScreen, int w, int h, int depth, unsigned usage_hint) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XAAPixmapPtr pPriv; + PixmapPtr pPix = NULL; + int size = w * h; + + if (w > 32767 || h > 32767) + return NullPixmap; + + if (!infoRec->offscreenDepthsInitialized) + XAAInitializeOffscreenDepths (pScreen); + + if(pScrn->vtSema && + (usage_hint != CREATE_PIXMAP_USAGE_GLYPH_PICTURE) && + (infoRec->offscreenDepths & (1 << (depth - 1))) && + (size >= MIN_OFFPIX_SIZE) && !SwitchedOut && + (!infoRec->maxOffPixWidth || (w <= infoRec->maxOffPixWidth)) && + (!infoRec->maxOffPixHeight || (h <= infoRec->maxOffPixHeight)) ) + { + PixmapLinkPtr pLink; + PixmapPtr pScreenPix; + FBAreaPtr area; + int gran = 0; + + switch(pScrn->bitsPerPixel) { + case 24: + case 8: gran = 4; break; + case 16: gran = 2; break; + case 32: gran = 1; break; + default: break; + } + + if(BITMAP_SCANLINE_PAD == 64) + gran *= 2; + + if(!(area = xf86AllocateOffscreenArea(pScreen, w, h, gran, 0, + XAARemoveAreaCallback, NULL))) { + goto BAILOUT; + } + + if(!(pLink = malloc(sizeof(PixmapLink)))) { + xf86FreeOffscreenArea(area); + goto BAILOUT; + } + + XAA_SCREEN_PROLOGUE (pScreen, CreatePixmap); + pPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, usage_hint); + XAA_SCREEN_EPILOGUE (pScreen, CreatePixmap, XAACreatePixmap); + + if (!pPix) { + free(pLink); + xf86FreeOffscreenArea(area); + goto BAILOUT; + } + + pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); + + pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); + pPix->drawable.x = area->box.x1; + pPix->drawable.y = area->box.y1; + pPix->drawable.width = w; + pPix->drawable.height = h; + pPix->drawable.bitsPerPixel = pScrn->bitsPerPixel; + pPix->devKind = pScreenPix->devKind; + pPix->devPrivate.ptr = pScreenPix->devPrivate.ptr; + area->devPrivate.ptr = pPix; + + pPriv->flags = OFFSCREEN; + pPriv->offscreenArea = area; + pPriv->freeData = FALSE; + + pLink->next = infoRec->OffscreenPixmaps; + pLink->pPix = pPix; + infoRec->OffscreenPixmaps = pLink; + return pPix; + } +BAILOUT: + XAA_SCREEN_PROLOGUE (pScreen, CreatePixmap); + pPix = (*pScreen->CreatePixmap) (pScreen, w, h, depth, usage_hint); + XAA_SCREEN_EPILOGUE (pScreen, CreatePixmap, XAACreatePixmap); + + if(pPix) { + pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); + pPriv->flags = 0; + pPriv->offscreenArea = NULL; + pPriv->freeData = FALSE; + if(!w || !h) /* either scratch or shared memory */ + pPriv->flags |= SHARED_PIXMAP; + } + + return pPix; +} + +static Bool +XAADestroyPixmap(PixmapPtr pPix) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); + Bool ret; + + if(pPix->refcnt == 1) { + if(pPriv->flags & OFFSCREEN) { + if(pPriv->flags & DGA_PIXMAP) + free(pPriv->offscreenArea); + else { + FBAreaPtr area = pPriv->offscreenArea; + PixmapLinkPtr pLink = infoRec->OffscreenPixmaps; + PixmapLinkPtr prev = NULL; + + while(pLink->pPix != pPix) { + prev = pLink; + pLink = pLink->next; + } + + if(prev) prev->next = pLink->next; + else infoRec->OffscreenPixmaps = pLink->next; + + if(!area) area = pLink->area; + + xf86FreeOffscreenArea(area); + pPriv->offscreenArea = NULL; + free(pLink); + } + } + + if(pPriv->freeData) { /* pixmaps that were once in video ram */ + free(pPix->devPrivate.ptr); + pPix->devPrivate.ptr = NULL; + } + } + + XAA_SCREEN_PROLOGUE (pScreen, DestroyPixmap); + ret = (*pScreen->DestroyPixmap) (pPix); + XAA_SCREEN_EPILOGUE (pScreen, DestroyPixmap, XAADestroyPixmap); + + return ret; +} + +static Bool +XAAChangeWindowAttributes (WindowPtr pWin, unsigned long mask) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + Bool ret; + + XAA_SCREEN_PROLOGUE (pScreen, ChangeWindowAttributes); + ret = (*pScreen->ChangeWindowAttributes) (pWin, mask); + XAA_SCREEN_EPILOGUE (pScreen, ChangeWindowAttributes, XAAChangeWindowAttributes); + + /* we have to assume that shared memory pixmaps are dirty + because we can't wrap operations on them */ + + if((mask & CWBackPixmap) && (pWin->backgroundState == BackgroundPixmap) && + PIXMAP_IS_SHARED(pWin->background.pixmap)) + { + XAAPixmapPtr pPixPriv = XAA_GET_PIXMAP_PRIVATE(pWin->background.pixmap); + pPixPriv->flags |= DIRTY; + } + if((mask & CWBorderPixmap) && !(pWin->borderIsPixel) && + PIXMAP_IS_SHARED(pWin->border.pixmap)) + { + XAAPixmapPtr pPixPriv = XAA_GET_PIXMAP_PRIVATE(pWin->border.pixmap); + pPixPriv->flags |= DIRTY; + } + + return ret; +} + + + +/* These two aren't really needed for anything */ + +static Bool +XAAEnterVT(int index, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + XAAScreenPtr pScreenPriv = + (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); + + return((*pScreenPriv->EnterVT)(index, flags)); +} + +static void +XAALeaveVT(int index, int flags) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + XAAScreenPtr pScreenPriv = + (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); + XAAInfoRecPtr infoRec = pScreenPriv->AccelInfoRec; + + if(infoRec->NeedToSync) { + (*infoRec->Sync)(infoRec->pScrn); + infoRec->NeedToSync = FALSE; + } + + (*pScreenPriv->LeaveVT)(index, flags); +} + +typedef struct { + Bool UsingPixmapCache; + Bool CanDoColor8x8; + Bool CanDoMono8x8; +} SavedCacheState, *SavedCacheStatePtr; + +static int +XAASetDGAMode(int index, int num, DGADevicePtr devRet) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + XAAScreenPtr pScreenPriv = + (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); + int ret; + + if (!num && infoRec->dgaSaves) { /* restore old pixmap cache state */ + SavedCacheStatePtr state = (SavedCacheStatePtr)infoRec->dgaSaves; + + infoRec->UsingPixmapCache = state->UsingPixmapCache; + infoRec->CanDoColor8x8 = state->CanDoColor8x8; + infoRec->CanDoMono8x8 = state->CanDoMono8x8; + free(infoRec->dgaSaves); + infoRec->dgaSaves = NULL; + } + + ret = (*pScreenPriv->SetDGAMode)(index, num, devRet); + if(ret != Success) return ret; + + if(num && devRet->pPix) { /* accelerate this pixmap */ + XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(devRet->pPix); + FBAreaPtr area; + + if((area = malloc(sizeof(FBArea)))) { + area->pScreen = pScreen; + area->box.x1 = 0; + area->box.x2 = 0; + area->box.y1 = devRet->mode->pixmapWidth; + area->box.y2 = devRet->mode->pixmapHeight; + area->granularity = 0; + area->MoveAreaCallback = 0; + area->RemoveAreaCallback = 0; + area->devPrivate.ptr = 0; + + pixPriv->flags |= OFFSCREEN | DGA_PIXMAP; + pixPriv->offscreenArea = area; + + if(!infoRec->dgaSaves) { /* save pixmap cache state */ + SavedCacheStatePtr state = malloc(sizeof(SavedCacheState)); + + state->UsingPixmapCache = infoRec->UsingPixmapCache; + state->CanDoColor8x8 = infoRec->CanDoColor8x8; + state->CanDoMono8x8 = infoRec->CanDoMono8x8; + infoRec->dgaSaves = (char*)state; + + infoRec->UsingPixmapCache = FALSE; + if(infoRec->PixmapCacheFlags & CACHE_MONO_8x8) + infoRec->CanDoMono8x8 = FALSE; + if(infoRec->PixmapCacheFlags & CACHE_COLOR_8x8) + infoRec->CanDoColor8x8 = FALSE; + } + } + } + + return ret; +} + + + +static void +XAAEnableDisableFBAccess (int index, Bool enable) +{ + ScreenPtr pScreen = screenInfo.screens[index]; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + XAAScreenPtr pScreenPriv = + (XAAScreenPtr)dixLookupPrivate(&pScreen->devPrivates, XAAScreenKey); + + if(!enable) { + if((infoRec->Flags & OFFSCREEN_PIXMAPS) && (infoRec->OffscreenPixmaps)) + XAAMoveOutOffscreenPixmaps(pScreen); + if(infoRec->Flags & PIXMAP_CACHE) + XAAInvalidatePixmapCache(pScreen); + SwitchedOut = TRUE; + } + + (*pScreenPriv->EnableDisableFBAccess)(index, enable); + + if(enable) { + if((infoRec->Flags & OFFSCREEN_PIXMAPS) && (infoRec->OffscreenPixmaps)) + XAAMoveInOffscreenPixmaps(pScreen); + SwitchedOut = FALSE; + } +} diff --git a/xorg-server/hw/xfree86/xaa/xaaInitAccel.c b/xorg-server/hw/xfree86/xaa/xaaInitAccel.c index 6f3d622e1..d24599d48 100644 --- a/xorg-server/hw/xfree86/xaa/xaaInitAccel.c +++ b/xorg-server/hw/xfree86/xaa/xaaInitAccel.c @@ -1,1498 +1,1498 @@ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaalocal.h" -#include "xf86fbman.h" -#include "servermd.h" - -/* - * XAA Config options - */ - -typedef enum { - XAAOPT_SCREEN_TO_SCREEN_COPY, - XAAOPT_SOLID_FILL_RECT, - XAAOPT_SOLID_FILL_TRAP, - XAAOPT_SOLID_TWO_POINT_LINE, - XAAOPT_SOLID_BRESENHAM_LINE, - XAAOPT_SOLID_HORVERT_LINE, - XAAOPT_DASHED_TWO_POINT_LINE, - XAAOPT_DASHED_BRESENHAM_LINE, - XAAOPT_MONO_8x8_PATTERN_FILL_RECT, - XAAOPT_MONO_8x8_PATTERN_FILL_TRAP, - XAAOPT_COL_8x8_PATTERN_FILL_RECT, - XAAOPT_COL_8x8_PATTERN_FILL_TRAP, - XAAOPT_CPU_TO_SCREEN_COL_EXP_FILL, - XAAOPT_SCANLINE_CPU_TO_SCREEN_COL_EXP_FILL, - XAAOPT_SCREEN_TO_SCREEN_COL_EXP_FILL, - XAAOPT_IMAGE_WRITE_RECT, - XAAOPT_SCANLINE_IMAGE_WRITE_RECT, - XAAOPT_WRITE_BITMAP, - XAAOPT_WRITE_PIXMAP, - XAAOPT_PIXMAP_CACHE, - XAAOPT_OFFSCREEN_PIXMAPS, - XAAOPT_HAS_DUMB_INVERTED_OPTION_SENSE -} XAAOpts; - -static const OptionInfoRec XAAOptions[] = { - {XAAOPT_SCREEN_TO_SCREEN_COPY, "XaaNoScreenToScreenCopy", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_SOLID_FILL_RECT, "XaaNoSolidFillRect", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_SOLID_FILL_TRAP, "XaaNoSolidFillTrap", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_SOLID_TWO_POINT_LINE, "XaaNoSolidTwoPointLine", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_SOLID_BRESENHAM_LINE, "XaaNoSolidBresenhamLine", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_SOLID_HORVERT_LINE, "XaaNoSolidHorVertLine", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_DASHED_TWO_POINT_LINE, "XaaNoDashedTwoPointLine", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_DASHED_BRESENHAM_LINE, "XaaNoDashedBresenhamLine", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_MONO_8x8_PATTERN_FILL_RECT, "XaaNoMono8x8PatternFillRect", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_MONO_8x8_PATTERN_FILL_TRAP, "XaaNoMono8x8PatternFillTrap", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_COL_8x8_PATTERN_FILL_RECT, "XaaNoColor8x8PatternFillRect", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_COL_8x8_PATTERN_FILL_TRAP, "XaaNoColor8x8PatternFillTrap", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_CPU_TO_SCREEN_COL_EXP_FILL, "XaaNoCPUToScreenColorExpandFill", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_SCANLINE_CPU_TO_SCREEN_COL_EXP_FILL,"XaaNoScanlineCPUToScreenColorExpandFill", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_SCREEN_TO_SCREEN_COL_EXP_FILL, "XaaNoScreenToScreenColorExpandFill", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_IMAGE_WRITE_RECT, "XaaNoImageWriteRect", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_SCANLINE_IMAGE_WRITE_RECT, "XaaNoScanlineImageWriteRect", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_WRITE_BITMAP, "XaaNoWriteBitmap", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_WRITE_PIXMAP, "XaaNoWritePixmap", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_PIXMAP_CACHE, "XaaNoPixmapCache", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_OFFSCREEN_PIXMAPS, "XaaNoOffscreenPixmaps", - OPTV_BOOLEAN, {0}, FALSE }, - {XAAOPT_HAS_DUMB_INVERTED_OPTION_SENSE, "XaaOffscreenPixmaps", - OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, - OPTV_NONE, {0}, FALSE } -}; - -static XF86ModuleVersionInfo xaaVersRec = -{ - "xaa", - MODULEVENDORSTRING, - MODINFOSTRING1, - MODINFOSTRING2, - XORG_VERSION_CURRENT, - XAA_VERSION_MAJOR, - XAA_VERSION_MINOR, - XAA_VERSION_RELEASE, - ABI_CLASS_VIDEODRV, /* requires the video driver ABI */ - ABI_VIDEODRV_VERSION, - MOD_CLASS_NONE, - {0,0,0,0} -}; - -_X_EXPORT XF86ModuleData xaaModuleData = { &xaaVersRec, NULL, NULL }; - -Bool -XAAInitAccel(ScreenPtr pScreen, XAAInfoRecPtr infoRec) -{ - int index = pScreen->myNum; - ScrnInfoPtr pScrn = xf86Screens[index]; - Bool HaveScreenToScreenCopy = FALSE; - Bool HaveColorExpansion = FALSE; - Bool HaveScanlineColorExpansion = FALSE; - Bool HaveSolidFillRect = FALSE; - Bool HaveMono8x8PatternFillRect = FALSE; - Bool HaveColor8x8PatternFillRect = FALSE; - Bool HaveSolidFillTrap = FALSE; - Bool HaveMono8x8PatternFillTrap = FALSE; - Bool HaveColor8x8PatternFillTrap = FALSE; - Bool HaveSolidTwoPointLine = FALSE; - Bool HaveSolidBresenhamLine = FALSE; - Bool HaveSolidHorVertLine = FALSE; - Bool HaveDashedTwoPointLine = FALSE; - Bool HaveDashedBresenhamLine = FALSE; - Bool HaveImageWriteRect = FALSE; - Bool HaveScanlineImageWriteRect = FALSE; - Bool HaveScreenToScreenColorExpandFill = FALSE; - OptionInfoPtr options; - int is_shared = 0; - int i; - - options = xnfalloc(sizeof(XAAOptions)); - (void)memcpy(options, XAAOptions, sizeof(XAAOptions)); - xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); - - infoRec->pScrn = pScrn; - infoRec->NeedToSync = FALSE; - - /* must have a Sync function */ - if(!infoRec->Sync) return FALSE; - for(i = 0; i < pScrn->numEntities; i++) { - if(xf86IsEntityShared(pScrn->entityList[i])) is_shared = 1; - } - - /* If this PCI entity has IS_SHARED_ACCEL set in entityProp - * then a RestoreAccelState function is required - */ - if(!infoRec->RestoreAccelState && is_shared) return FALSE; - - if(infoRec->RestoreAccelState) { - if(!XAAInitStateWrap(pScreen, infoRec)) return FALSE; - } - - if (serverGeneration == 1) - xf86DrvMsg(index, X_INFO, - "Using XFree86 Acceleration Architecture (XAA)\n"); - - - /************** Low Level *************/ - - if(!infoRec->SetClippingRectangle || !infoRec->DisableClipping) { - infoRec->ClippingFlags = 0; - infoRec->SetClippingRectangle = NULL; - infoRec->DisableClipping = NULL; - } - - /**** CopyArea ****/ - - if(infoRec->SetupForScreenToScreenCopy && - infoRec->SubsequentScreenToScreenCopy && - !xf86ReturnOptValBool(options, XAAOPT_SCREEN_TO_SCREEN_COPY, FALSE)) { - HaveScreenToScreenCopy = TRUE; - } else { - infoRec->ScreenToScreenCopyFlags = 0; - infoRec->SetupForScreenToScreenCopy = NULL; - infoRec->SubsequentScreenToScreenCopy = NULL; - } - - /**** Solid Filled Rects ****/ - - if(infoRec->SetupForSolidFill && infoRec->SubsequentSolidFillRect && - !xf86ReturnOptValBool(options, XAAOPT_SOLID_FILL_RECT, FALSE)) { - HaveSolidFillRect = TRUE; - if(infoRec->SubsequentSolidFillTrap && - !xf86ReturnOptValBool(options, XAAOPT_SOLID_FILL_TRAP, FALSE)) - HaveSolidFillTrap = TRUE; - else - infoRec->SubsequentSolidFillTrap = NULL; - } else { - infoRec->SolidFillFlags = 0; - infoRec->SetupForSolidFill = NULL; - infoRec->SubsequentSolidFillRect = NULL; - infoRec->SubsequentSolidFillTrap = NULL; - } - - /**** Solid lines ****/ - - if(infoRec->SetupForSolidLine) { - if(infoRec->SubsequentSolidTwoPointLine && - !xf86ReturnOptValBool(options, - XAAOPT_SOLID_TWO_POINT_LINE, FALSE)) - HaveSolidTwoPointLine = TRUE; - if(infoRec->SubsequentSolidBresenhamLine && - !xf86ReturnOptValBool(options, XAAOPT_SOLID_BRESENHAM_LINE, FALSE)) { - HaveSolidBresenhamLine = TRUE; - - if(infoRec->SolidBresenhamLineErrorTermBits) - infoRec->SolidBresenhamLineErrorTermBits = - ~((1 << infoRec->SolidBresenhamLineErrorTermBits) - 1); - } - - if(infoRec->SubsequentSolidHorVertLine && - !xf86ReturnOptValBool(options, - XAAOPT_SOLID_HORVERT_LINE, FALSE)) - HaveSolidHorVertLine = TRUE; - else if(HaveSolidTwoPointLine) { - infoRec->SubsequentSolidHorVertLine = - XAASolidHorVertLineAsTwoPoint; - HaveSolidHorVertLine = TRUE; - } else if(HaveSolidBresenhamLine) { - infoRec->SubsequentSolidHorVertLine = - XAASolidHorVertLineAsBresenham; - HaveSolidHorVertLine = TRUE; - } - } - - /* XXX Should this also check for XAAOPT_SOLID_HORVERT_LINE? */ - if (!HaveSolidTwoPointLine && - !HaveSolidBresenhamLine && - !HaveSolidHorVertLine && - HaveSolidFillRect) { - infoRec->SetupForSolidLine = infoRec->SetupForSolidFill; - infoRec->SubsequentSolidHorVertLine = XAASolidHorVertLineAsRects; - infoRec->SolidLineFlags = infoRec->SolidFillFlags; - HaveSolidHorVertLine = TRUE; - } - - if (!HaveSolidTwoPointLine) - infoRec->SubsequentSolidTwoPointLine = NULL; - if (!HaveSolidBresenhamLine) - infoRec->SubsequentSolidBresenhamLine = NULL; - if (!HaveSolidHorVertLine) - infoRec->SubsequentSolidHorVertLine = NULL; - - /* Disable all if nothing left over */ - if (!HaveSolidTwoPointLine && - !HaveSolidBresenhamLine && - !HaveSolidHorVertLine) { - infoRec->SolidLineFlags = 0; - infoRec->SetupForSolidLine = NULL; - } - - /**** 8x8 Mono Pattern Filled Rects ****/ - - if(infoRec->SetupForMono8x8PatternFill && - infoRec->SubsequentMono8x8PatternFillRect && - !xf86ReturnOptValBool(options, - XAAOPT_MONO_8x8_PATTERN_FILL_RECT, - FALSE)) { - HaveMono8x8PatternFillRect = TRUE; - if(infoRec->SubsequentMono8x8PatternFillTrap && - !xf86ReturnOptValBool(options, - XAAOPT_MONO_8x8_PATTERN_FILL_TRAP, - FALSE)) - HaveMono8x8PatternFillTrap = TRUE; - - if(infoRec->Mono8x8PatternFillFlags & - HARDWARE_PATTERN_PROGRAMMED_BITS) { - infoRec->CanDoMono8x8 = TRUE; - } else { /* others require caching */ - int min_pitch; - infoRec->PixmapCacheFlags |= CACHE_MONO_8x8; - - switch(pScrn->bitsPerPixel) { - case 32: min_pitch = 2; break; - case 24: min_pitch = 3; break; - case 16: min_pitch = 4; break; - default: min_pitch = 8; break; - } - - if(min_pitch > infoRec->MonoPatternPitch) - infoRec->MonoPatternPitch = min_pitch; - - if(infoRec->Mono8x8PatternFillFlags & - HARDWARE_PATTERN_PROGRAMMED_ORIGIN) { - if(!infoRec->CacheWidthMono8x8Pattern || - !infoRec->CacheHeightMono8x8Pattern) { - infoRec->CacheWidthMono8x8Pattern = - infoRec->MonoPatternPitch; - infoRec->CacheHeightMono8x8Pattern = 1; - } - } else { - int numPerLine = 128/infoRec->MonoPatternPitch; - - if(!infoRec->CacheWidthMono8x8Pattern || - !infoRec->CacheHeightMono8x8Pattern) { - infoRec->CacheWidthMono8x8Pattern = - numPerLine * infoRec->MonoPatternPitch; - infoRec->CacheHeightMono8x8Pattern = - (64 + numPerLine - 1)/numPerLine; - } - } - } - } else { - infoRec->Mono8x8PatternFillFlags = 0; - infoRec->SetupForMono8x8PatternFill = NULL; - infoRec->SubsequentMono8x8PatternFillRect = NULL; - } - - /**** Dashed lines ****/ - - if(infoRec->SetupForDashedLine && infoRec->DashPatternMaxLength) { - if(infoRec->SubsequentDashedTwoPointLine && - !xf86ReturnOptValBool(options, XAAOPT_DASHED_TWO_POINT_LINE, - FALSE)) - HaveDashedTwoPointLine = TRUE; - if(infoRec->SubsequentDashedBresenhamLine && - !xf86ReturnOptValBool(options, XAAOPT_DASHED_BRESENHAM_LINE, - FALSE)) { - HaveDashedBresenhamLine = TRUE; - - if(infoRec->DashedBresenhamLineErrorTermBits) - infoRec->DashedBresenhamLineErrorTermBits = - ~((1 << infoRec->DashedBresenhamLineErrorTermBits) - 1); - } - } - - if (!HaveDashedTwoPointLine) - infoRec->SubsequentDashedTwoPointLine = NULL; - if (!HaveDashedBresenhamLine) - infoRec->SubsequentDashedBresenhamLine = NULL; - - /* Disable all if nothing left over */ - if (!HaveDashedTwoPointLine && !HaveDashedBresenhamLine) { - infoRec->DashedLineFlags = 0; - infoRec->SetupForDashedLine = NULL; - } - - /**** 8x8 Color Pattern Filled Rects ****/ - - if(infoRec->SetupForColor8x8PatternFill && - infoRec->SubsequentColor8x8PatternFillRect && - !xf86ReturnOptValBool(options, XAAOPT_COL_8x8_PATTERN_FILL_RECT, FALSE)) { - HaveColor8x8PatternFillRect = TRUE; - if(infoRec->SubsequentColor8x8PatternFillTrap && - !xf86ReturnOptValBool(options, XAAOPT_COL_8x8_PATTERN_FILL_TRAP, - FALSE)) - HaveColor8x8PatternFillTrap = TRUE; - else - infoRec->SubsequentColor8x8PatternFillTrap = NULL; - - infoRec->PixmapCacheFlags |= CACHE_COLOR_8x8; - - if(infoRec->Color8x8PatternFillFlags & - HARDWARE_PATTERN_PROGRAMMED_ORIGIN) { - if(!infoRec->CacheWidthColor8x8Pattern || - !infoRec->CacheHeightColor8x8Pattern) { - infoRec->CacheWidthColor8x8Pattern = 64; - infoRec->CacheHeightColor8x8Pattern = 1; - } - } else { - if(!infoRec->CacheWidthColor8x8Pattern || - !infoRec->CacheHeightColor8x8Pattern) { - infoRec->CacheWidthColor8x8Pattern = 128; - infoRec->CacheHeightColor8x8Pattern = 8; - } - } - } else { - infoRec->Color8x8PatternFillFlags = 0; - infoRec->SetupForColor8x8PatternFill = NULL; - infoRec->SubsequentColor8x8PatternFillRect = NULL; - infoRec->SubsequentColor8x8PatternFillTrap = NULL; - } - - /**** Color Expansion ****/ - - if(infoRec->SetupForCPUToScreenColorExpandFill && - infoRec->ColorExpandBase && - infoRec->SubsequentCPUToScreenColorExpandFill && - !xf86ReturnOptValBool(options, XAAOPT_CPU_TO_SCREEN_COL_EXP_FILL, - FALSE)) { - int dwordsNeeded = pScrn->virtualX; - - infoRec->ColorExpandRange >>= 2; /* convert to DWORDS */ - HaveColorExpansion = TRUE; - - if(infoRec->CPUToScreenColorExpandFillFlags & - LEFT_EDGE_CLIPPING_NEGATIVE_X) - dwordsNeeded += 31; - dwordsNeeded = (dwordsNeeded + 31) >> 5; - if(dwordsNeeded > infoRec->ColorExpandRange) - infoRec->CPUToScreenColorExpandFillFlags |= CPU_TRANSFER_BASE_FIXED; - } else { - infoRec->CPUToScreenColorExpandFillFlags = 0; - infoRec->SetupForCPUToScreenColorExpandFill = NULL; - infoRec->SubsequentCPUToScreenColorExpandFill = NULL; - } - - /**** Scanline Color Expansion ****/ - - if(infoRec->SetupForScanlineCPUToScreenColorExpandFill && - infoRec->SubsequentScanlineCPUToScreenColorExpandFill && - infoRec->SubsequentColorExpandScanline && - infoRec->ScanlineColorExpandBuffers && - (infoRec->NumScanlineColorExpandBuffers > 0) && - !xf86ReturnOptValBool(options, - XAAOPT_SCANLINE_CPU_TO_SCREEN_COL_EXP_FILL, - FALSE)) { - HaveScanlineColorExpansion = TRUE; - } else { - infoRec->ScanlineCPUToScreenColorExpandFillFlags = 0; - infoRec->SetupForScanlineCPUToScreenColorExpandFill = NULL; - infoRec->SubsequentScanlineCPUToScreenColorExpandFill = NULL; - infoRec->SubsequentColorExpandScanline = NULL; - } - - /**** Screen to Screen Color Expansion ****/ - - if(infoRec->SetupForScreenToScreenColorExpandFill && - infoRec->SubsequentScreenToScreenColorExpandFill && - !xf86ReturnOptValBool(options, XAAOPT_SCREEN_TO_SCREEN_COL_EXP_FILL, - FALSE)) { - HaveScreenToScreenColorExpandFill = TRUE; - if (!infoRec->CacheColorExpandDensity) - infoRec->CacheColorExpandDensity = 1; - } else { - infoRec->ScreenToScreenColorExpandFillFlags = 0; - infoRec->SetupForScreenToScreenColorExpandFill = NULL; - infoRec->SubsequentScreenToScreenColorExpandFill = NULL; - } - - /**** Image Writes ****/ - - if(infoRec->SetupForImageWrite && infoRec->ImageWriteBase && - infoRec->SubsequentImageWriteRect && - !xf86ReturnOptValBool(options, XAAOPT_IMAGE_WRITE_RECT, FALSE)) { - - infoRec->ImageWriteRange >>= 2; /* convert to DWORDS */ - if(infoRec->ImageWriteFlags & CPU_TRANSFER_BASE_FIXED) - infoRec->ImageWriteRange = 0; - HaveImageWriteRect = TRUE; - } else { - infoRec->ImageWriteFlags = 0; - infoRec->SetupForImageWrite = NULL; - infoRec->SubsequentImageWriteRect = NULL; - } - - /**** Scanline Image Writes ****/ - - if(infoRec->SetupForScanlineImageWrite && - infoRec->SubsequentScanlineImageWriteRect && - infoRec->SubsequentImageWriteScanline && - infoRec->ScanlineImageWriteBuffers && - (infoRec->NumScanlineImageWriteBuffers > 0) && - !xf86ReturnOptValBool(options, XAAOPT_SCANLINE_IMAGE_WRITE_RECT, - FALSE)) { - HaveScanlineImageWriteRect = TRUE; - } else { - infoRec->ScanlineImageWriteFlags = 0; - infoRec->SetupForScanlineImageWrite = NULL; - infoRec->SubsequentScanlineImageWriteRect = NULL; - infoRec->SubsequentImageWriteScanline = NULL; - } - -#ifndef __i386__ - /* XAA makes some unaligned accesses when clipping is not available */ -# define CLIP_FLAGS (LEFT_EDGE_CLIPPING | LEFT_EDGE_CLIPPING_NEGATIVE_X) - if(HaveImageWriteRect && - ((infoRec->ImageWriteFlags & CLIP_FLAGS) != CLIP_FLAGS)) - { - HaveImageWriteRect = FALSE; - } - if(HaveScanlineImageWriteRect && - ((infoRec->ScanlineImageWriteFlags & CLIP_FLAGS) != CLIP_FLAGS)) - { - HaveScanlineImageWriteRect = FALSE; - } -#endif - - if (serverGeneration == 1) { - if(HaveScreenToScreenCopy) - xf86ErrorF("\tScreen to screen bit blits\n"); - if(HaveSolidFillRect) - xf86ErrorF("\tSolid filled rectangles\n"); - if(HaveSolidFillTrap) - xf86ErrorF("\tSolid filled trapezoids\n"); - if(HaveMono8x8PatternFillRect) - xf86ErrorF("\t8x8 mono pattern filled rectangles\n"); - if(HaveMono8x8PatternFillTrap) - xf86ErrorF("\t8x8 mono pattern filled trapezoids\n"); - if(HaveColor8x8PatternFillRect) - xf86ErrorF("\t8x8 color pattern filled rectangles\n"); - if(HaveColor8x8PatternFillTrap) - xf86ErrorF("\t8x8 color pattern filled trapezoids\n"); - - if(HaveColorExpansion) - xf86ErrorF("\tCPU to Screen color expansion\n"); - else if(HaveScanlineColorExpansion) - xf86ErrorF("\tIndirect CPU to Screen color expansion\n"); - - if(HaveScreenToScreenColorExpandFill) - xf86ErrorF("\tScreen to Screen color expansion\n"); - - if(HaveSolidTwoPointLine || HaveSolidBresenhamLine) - xf86ErrorF("\tSolid Lines\n"); - else if(HaveSolidHorVertLine) - xf86ErrorF("\tSolid Horizontal and Vertical Lines\n"); - - if(HaveDashedTwoPointLine || HaveDashedBresenhamLine) - xf86ErrorF("\tDashed Lines\n"); - - if(HaveImageWriteRect) - xf86ErrorF("\tImage Writes\n"); - else if(HaveScanlineImageWriteRect) - xf86ErrorF("\tScanline Image Writes\n"); - - } - -#define XAAMSG(s) do { if (serverGeneration == 1) xf86ErrorF(s); } while (0) - - if((infoRec->Flags & OFFSCREEN_PIXMAPS) && HaveScreenToScreenCopy && - xf86ReturnOptValBool(options, - XAAOPT_HAS_DUMB_INVERTED_OPTION_SENSE, - FALSE)) - { - XAAMSG("\tOffscreen Pixmaps\n"); - } else { - infoRec->Flags &= ~OFFSCREEN_PIXMAPS; - } - - - /************** Mid Level *************/ - - /**** ScreenToScreenBitBlt ****/ - - if(infoRec->ScreenToScreenBitBlt) { - XAAMSG("\tDriver provided ScreenToScreenBitBlt replacement\n"); - } else if(HaveScreenToScreenCopy) { - infoRec->ScreenToScreenBitBlt = XAAScreenToScreenBitBlt; - infoRec->ScreenToScreenBitBltFlags = infoRec->ScreenToScreenCopyFlags; - } - - /**** FillSolidRects ****/ - - if(infoRec->FillSolidRects) { - XAAMSG("\tDriver provided FillSolidRects replacement\n"); - } else if(HaveSolidFillRect) { - infoRec->FillSolidRects = XAAFillSolidRects; - infoRec->FillSolidRectsFlags = infoRec->SolidFillFlags; - } - - /**** FillSolidSpans ****/ - - if(infoRec->FillSolidSpans) { - XAAMSG("\tDriver provided FillSolidSpans replacement\n"); - } else if(HaveSolidFillRect) { - infoRec->FillSolidSpans = XAAFillSolidSpans; - infoRec->FillSolidSpansFlags = infoRec->SolidFillFlags; - } - - /**** FillMono8x8PatternRects ****/ - - if(infoRec->FillMono8x8PatternRects) { - XAAMSG("\tDriver provided FillMono8x8PatternRects replacement\n"); - } else if(HaveMono8x8PatternFillRect) { - infoRec->FillMono8x8PatternRects = - (infoRec->Mono8x8PatternFillFlags & HARDWARE_PATTERN_SCREEN_ORIGIN) ? - XAAFillMono8x8PatternRectsScreenOrigin : - XAAFillMono8x8PatternRects; - - infoRec->FillMono8x8PatternRectsFlags = - infoRec->Mono8x8PatternFillFlags; - } - - /**** FillMono8x8PatternSpans ****/ - - if(infoRec->FillMono8x8PatternSpans) { - XAAMSG("\tDriver provided FillMono8x8PatternSpans replacement\n"); - } else if(HaveMono8x8PatternFillRect) { - infoRec->FillMono8x8PatternSpans = - (infoRec->Mono8x8PatternFillFlags & HARDWARE_PATTERN_SCREEN_ORIGIN) ? - XAAFillMono8x8PatternSpansScreenOrigin: - XAAFillMono8x8PatternSpans; - - infoRec->FillMono8x8PatternSpansFlags = - infoRec->Mono8x8PatternFillFlags; - } - - /**** FillColor8x8Rects ****/ - - if(infoRec->FillColor8x8PatternRects) { - XAAMSG("\tDriver provided FillColor8x8PatternRects replacement\n"); - } else if(HaveColor8x8PatternFillRect) { - infoRec->FillColor8x8PatternRects = - (infoRec->Color8x8PatternFillFlags & HARDWARE_PATTERN_SCREEN_ORIGIN) ? - XAAFillColor8x8PatternRectsScreenOrigin : - XAAFillColor8x8PatternRects; - - infoRec->FillColor8x8PatternRectsFlags = - infoRec->Color8x8PatternFillFlags; - } - - /**** FillColor8x8Spans ****/ - - if(infoRec->FillColor8x8PatternSpans) { - XAAMSG("\tDriver provided FillColor8x8PatternSpans replacement\n"); - } else if(HaveColor8x8PatternFillRect) { - infoRec->FillColor8x8PatternSpans = - (infoRec->Color8x8PatternFillFlags & HARDWARE_PATTERN_SCREEN_ORIGIN) ? - XAAFillColor8x8PatternSpansScreenOrigin: - XAAFillColor8x8PatternSpans; - - infoRec->FillColor8x8PatternSpansFlags = - infoRec->Color8x8PatternFillFlags; - } - - /**** FillCacheBltRects ****/ - - if(infoRec->FillCacheBltRects) { - XAAMSG("\tDriver provided FillCacheBltRects replacement\n"); - } else if(HaveScreenToScreenCopy) { - infoRec->FillCacheBltRects = XAAFillCacheBltRects; - infoRec->FillCacheBltRectsFlags = infoRec->ScreenToScreenCopyFlags; - } - - /**** FillCacheBltSpans ****/ - - if(infoRec->FillCacheBltSpans) { - XAAMSG("\tDriver provided FillCacheBltSpans replacement\n"); - } else if(HaveScreenToScreenCopy) { - infoRec->FillCacheBltSpans = XAAFillCacheBltSpans; - infoRec->FillCacheBltSpansFlags = infoRec->ScreenToScreenCopyFlags; - } - - /**** FillCacheExpandRects ****/ - - if(infoRec->FillCacheExpandRects) { - XAAMSG("\tDriver provided FillCacheExpandRects replacement\n"); - } else if(HaveScreenToScreenColorExpandFill) { - infoRec->FillCacheExpandRects = XAAFillCacheExpandRects; - infoRec->FillCacheExpandRectsFlags = - infoRec->ScreenToScreenColorExpandFillFlags; - } - - /**** FillCacheExpandSpans ****/ - - if(infoRec->FillCacheExpandSpans) { - XAAMSG("\tDriver provided FillCacheExpandSpans replacement\n"); - } else if(HaveScreenToScreenColorExpandFill) { - infoRec->FillCacheExpandSpans = XAAFillCacheExpandSpans; - infoRec->FillCacheExpandSpansFlags = - infoRec->ScreenToScreenColorExpandFillFlags; - } - - /**** FillColorExpandRects ****/ - - if(infoRec->FillColorExpandRects) { - XAAMSG("\tDriver provided FillColorExpandRects replacement\n"); - } else if(HaveColorExpansion) { - if (infoRec->CPUToScreenColorExpandFillFlags & TRIPLE_BITS_24BPP) { - if(infoRec->CPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->FillColorExpandRects = - XAAFillColorExpandRects3MSBFirstFixedBase; - else - infoRec->FillColorExpandRects = - XAAFillColorExpandRects3MSBFirst; - } else { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->FillColorExpandRects = - XAAFillColorExpandRects3LSBFirstFixedBase; - else - infoRec->FillColorExpandRects = - XAAFillColorExpandRects3LSBFirst; - } - } else { - if(infoRec->CPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->FillColorExpandRects = - XAAFillColorExpandRectsMSBFirstFixedBase; - else - infoRec->FillColorExpandRects = - XAAFillColorExpandRectsMSBFirst; - } else { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->FillColorExpandRects = - XAAFillColorExpandRectsLSBFirstFixedBase; - else - infoRec->FillColorExpandRects = - XAAFillColorExpandRectsLSBFirst; - } - } - infoRec->FillColorExpandRectsFlags = - infoRec->CPUToScreenColorExpandFillFlags; - } else if(HaveScanlineColorExpansion) { - if (infoRec->ScanlineCPUToScreenColorExpandFillFlags & - TRIPLE_BITS_24BPP) { - if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) - infoRec->FillColorExpandRects = - XAAFillScanlineColorExpandRects3MSBFirst; - else - infoRec->FillColorExpandRects = - XAAFillScanlineColorExpandRects3LSBFirst; - } else { - if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) - infoRec->FillColorExpandRects = - XAAFillScanlineColorExpandRectsMSBFirst; - else - infoRec->FillColorExpandRects = - XAAFillScanlineColorExpandRectsLSBFirst; - } - infoRec->FillColorExpandRectsFlags = - infoRec->ScanlineCPUToScreenColorExpandFillFlags; - } - - /**** FillColorExpandSpans ****/ - - if(infoRec->FillColorExpandSpans) { - XAAMSG("\tDriver provided FillColorExpandSpans replacement\n"); - } else if(HaveColorExpansion) { - if (infoRec->CPUToScreenColorExpandFillFlags & TRIPLE_BITS_24BPP) { - if(infoRec->CPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->FillColorExpandSpans = - XAAFillColorExpandSpans3MSBFirstFixedBase; - else - infoRec->FillColorExpandSpans = - XAAFillColorExpandSpans3MSBFirst; - } else { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->FillColorExpandSpans = - XAAFillColorExpandSpans3LSBFirstFixedBase; - else - infoRec->FillColorExpandSpans = - XAAFillColorExpandSpans3LSBFirst; - } - } else { - if(infoRec->CPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->FillColorExpandSpans = - XAAFillColorExpandSpansMSBFirstFixedBase; - else - infoRec->FillColorExpandSpans = - XAAFillColorExpandSpansMSBFirst; - } else { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->FillColorExpandSpans = - XAAFillColorExpandSpansLSBFirstFixedBase; - else - infoRec->FillColorExpandSpans = - XAAFillColorExpandSpansLSBFirst; - } - } - infoRec->FillColorExpandSpansFlags = - infoRec->CPUToScreenColorExpandFillFlags; - } else if(HaveScanlineColorExpansion) { - if (infoRec->ScanlineCPUToScreenColorExpandFillFlags & - TRIPLE_BITS_24BPP) { - if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) - infoRec->FillColorExpandSpans = - XAAFillScanlineColorExpandSpans3MSBFirst; - else - infoRec->FillColorExpandSpans = - XAAFillScanlineColorExpandSpans3LSBFirst; - } else { - if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) - infoRec->FillColorExpandSpans = - XAAFillScanlineColorExpandSpansMSBFirst; - else - infoRec->FillColorExpandSpans = - XAAFillScanlineColorExpandSpansLSBFirst; - } - infoRec->FillColorExpandSpansFlags = - infoRec->ScanlineCPUToScreenColorExpandFillFlags; - } - - /**** FillImageWriteRects ****/ - - if(infoRec->FillImageWriteRects) { - XAAMSG("\tDriver provided FillImageWriteRects replacement\n"); - } else if(HaveImageWriteRect && - (infoRec->ImageWriteFlags & LEFT_EDGE_CLIPPING_NEGATIVE_X) && - (infoRec->ImageWriteFlags & LEFT_EDGE_CLIPPING)) { - infoRec->FillImageWriteRects = XAAFillImageWriteRects; - infoRec->FillImageWriteRectsFlags = infoRec->ImageWriteFlags; - } - - /**** WriteBitmap ****/ - - if(infoRec->WriteBitmap && - !xf86ReturnOptValBool(options, XAAOPT_WRITE_BITMAP, FALSE)) { - XAAMSG("\tDriver provided WriteBitmap replacement\n"); - } else if(HaveColorExpansion) { - if (infoRec->CPUToScreenColorExpandFillFlags & TRIPLE_BITS_24BPP) { - if(infoRec->CPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->WriteBitmap = - XAAWriteBitmapColorExpand3MSBFirstFixedBase; - else - infoRec->WriteBitmap = XAAWriteBitmapColorExpand3MSBFirst; - } else { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->WriteBitmap = - XAAWriteBitmapColorExpand3LSBFirstFixedBase; - else - infoRec->WriteBitmap = XAAWriteBitmapColorExpand3LSBFirst; - } - } else { - if(infoRec->CPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->WriteBitmap = - XAAWriteBitmapColorExpandMSBFirstFixedBase; - else - infoRec->WriteBitmap = XAAWriteBitmapColorExpandMSBFirst; - } else { - if(infoRec->CPUToScreenColorExpandFillFlags & - CPU_TRANSFER_BASE_FIXED) - infoRec->WriteBitmap = - XAAWriteBitmapColorExpandLSBFirstFixedBase; - else - infoRec->WriteBitmap = XAAWriteBitmapColorExpandLSBFirst; - } - } - infoRec->WriteBitmapFlags = infoRec->CPUToScreenColorExpandFillFlags; - } else if(HaveScanlineColorExpansion) { - if (infoRec->ScanlineCPUToScreenColorExpandFillFlags & - TRIPLE_BITS_24BPP) { - if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) - infoRec->WriteBitmap = - XAAWriteBitmapScanlineColorExpand3MSBFirst; - else - infoRec->WriteBitmap = - XAAWriteBitmapScanlineColorExpand3LSBFirst; - } else { - if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST) - infoRec->WriteBitmap = - XAAWriteBitmapScanlineColorExpandMSBFirst; - else - infoRec->WriteBitmap = - XAAWriteBitmapScanlineColorExpandLSBFirst; - } - infoRec->WriteBitmapFlags = - infoRec->ScanlineCPUToScreenColorExpandFillFlags; - } else - infoRec->WriteBitmap = NULL; - - /**** TE Glyphs ****/ - - if (infoRec->TEGlyphRenderer) { - XAAMSG("\tDriver provided TEGlyphRenderer replacement\n"); - } else if (HaveColorExpansion) { - infoRec->TEGlyphRendererFlags = - infoRec->CPUToScreenColorExpandFillFlags; - - if (infoRec->TEGlyphRendererFlags & TRIPLE_BITS_24BPP) { - if (infoRec->TEGlyphRendererFlags & BIT_ORDER_IN_BYTE_MSBFIRST) { - if (infoRec->TEGlyphRendererFlags & CPU_TRANSFER_BASE_FIXED) - infoRec->TEGlyphRenderer = - XAATEGlyphRenderer3MSBFirstFixedBase; - else - infoRec->TEGlyphRenderer = XAATEGlyphRenderer3MSBFirst; - } else { - if (infoRec->TEGlyphRendererFlags & CPU_TRANSFER_BASE_FIXED) - infoRec->TEGlyphRenderer = - XAATEGlyphRenderer3LSBFirstFixedBase; - else - infoRec->TEGlyphRenderer = XAATEGlyphRenderer3LSBFirst; - } - - if (!HaveSolidFillRect && - (infoRec->TEGlyphRendererFlags & RGB_EQUAL)) { - infoRec->TEGlyphRendererFlags &= ~RGB_EQUAL; - XAAMSG("WARNING: TEGlyphRenderer cannot support RGB_EQUAL" - " without solid fills\n"); - } - } else { - if (infoRec->TEGlyphRendererFlags & BIT_ORDER_IN_BYTE_MSBFIRST) { - if (infoRec->TEGlyphRendererFlags & CPU_TRANSFER_BASE_FIXED) - infoRec->TEGlyphRenderer = - XAATEGlyphRendererMSBFirstFixedBase; - else - infoRec->TEGlyphRenderer = XAATEGlyphRendererMSBFirst; - } else { - if (infoRec->TEGlyphRendererFlags & CPU_TRANSFER_BASE_FIXED) - infoRec->TEGlyphRenderer = - XAATEGlyphRendererLSBFirstFixedBase; - else - infoRec->TEGlyphRenderer = XAATEGlyphRendererLSBFirst; - } - } - - if (!HaveSolidFillRect && - (infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { - infoRec->TEGlyphRendererFlags &= ~TRANSPARENCY_ONLY; - XAAMSG("WARNING: TEGlyphRenderer cannot support TRANPARENCY_ONLY" - " without solid fills\n"); - } - - } else if (HaveScanlineColorExpansion) { - infoRec->TEGlyphRendererFlags = - infoRec->ScanlineCPUToScreenColorExpandFillFlags; - - if (infoRec->TEGlyphRendererFlags & TRIPLE_BITS_24BPP) { - if (infoRec->TEGlyphRendererFlags & BIT_ORDER_IN_BYTE_MSBFIRST) - infoRec->TEGlyphRenderer = XAATEGlyphRendererScanline3MSBFirst; - else - infoRec->TEGlyphRenderer = XAATEGlyphRendererScanline3LSBFirst; - - if (!HaveSolidFillRect && - (infoRec->TEGlyphRendererFlags & RGB_EQUAL)) { - infoRec->TEGlyphRendererFlags &= ~RGB_EQUAL; - XAAMSG("WARNING: TEGlyphRenderer cannot support RGB_EQUAL" - " without solid fills\n"); - } - } else { - if (infoRec->TEGlyphRendererFlags & BIT_ORDER_IN_BYTE_MSBFIRST) - infoRec->TEGlyphRenderer = XAATEGlyphRendererScanlineMSBFirst; - else - infoRec->TEGlyphRenderer = XAATEGlyphRendererScanlineLSBFirst; - } - - if (!HaveSolidFillRect && - (infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { - infoRec->TEGlyphRendererFlags &= ~TRANSPARENCY_ONLY; - XAAMSG("WARNING: TEGlyphRenderer cannot support TRANPARENCY_ONLY" - " without solid fills\n"); - } - } - - /**** NonTE Glyphs ****/ - - if(infoRec->NonTEGlyphRenderer) { - XAAMSG("\tDriver provided NonTEGlyphRenderer replacement\n"); - } else if(infoRec->WriteBitmap && - !(infoRec->WriteBitmapFlags & NO_TRANSPARENCY)) { - infoRec->NonTEGlyphRenderer = XAANonTEGlyphRenderer; - infoRec->NonTEGlyphRendererFlags = infoRec->WriteBitmapFlags; - } - - /**** WritePixmap ****/ - - if(infoRec->WritePixmap && - !xf86ReturnOptValBool(options, XAAOPT_WRITE_PIXMAP, FALSE)) { - XAAMSG("\tDriver provided WritePixmap replacement\n"); - } else if(HaveImageWriteRect) { - infoRec->WritePixmap = XAAWritePixmap; - infoRec->WritePixmapFlags = - infoRec->ImageWriteFlags | CONVERT_32BPP_TO_24BPP; - } else if(HaveScanlineImageWriteRect) { - infoRec->WritePixmap = XAAWritePixmapScanline; - infoRec->WritePixmapFlags = infoRec->ScanlineImageWriteFlags; - } else - infoRec->WritePixmap = NULL; - - /**** ReadPixmap ****/ - - if(infoRec->ReadPixmap) { - XAAMSG("\tDriver provided ReadPixmap replacement\n"); - } - - - /************** GC Level *************/ - - /**** CopyArea ****/ - - if(infoRec->CopyArea) { - XAAMSG("\tDriver provided GC level CopyArea replacement\n"); - } else if(infoRec->ScreenToScreenBitBlt) { - infoRec->CopyArea = XAACopyArea; - infoRec->CopyAreaFlags = infoRec->ScreenToScreenBitBltFlags; - - /* most GC level primitives use one mid-level primitive so - the GC level primitive gets the mid-level primitive flag - and we use that at GC validation time. But CopyArea uses - more than one mid-level primitive so we have to essentially - do a GC validation every time that primitive is used. - The CopyAreaFlags would only be used for filtering out the - common denominators. Here we assume that if you don't do - ScreenToScreenBitBlt you aren't going to do the others. - We also assume that ScreenToScreenBitBlt has the least - restrictions. */ - } - - if(infoRec->CopyPlane) { - XAAMSG("\tDriver provided GC level CopyPlane replacement\n"); - } else if(infoRec->WriteBitmap && - !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY)) { - infoRec->CopyPlane = XAACopyPlaneColorExpansion; - infoRec->CopyPlaneFlags = infoRec->WriteBitmapFlags; - } - - if(infoRec->PushPixelsSolid) { - XAAMSG("\tDriver provided GC level PushPixelsSolid replacement\n"); - } else if(infoRec->WriteBitmap && - !(infoRec->WriteBitmapFlags & NO_TRANSPARENCY)) { - infoRec->PushPixelsSolid = XAAPushPixelsSolidColorExpansion; - infoRec->PushPixelsFlags = infoRec->WriteBitmapFlags; - } - - if(infoRec->FillSolidRects) { - if(!infoRec->PolyFillRectSolid) { - infoRec->PolyFillRectSolid = XAAPolyFillRect; - infoRec->PolyFillRectSolidFlags = infoRec->FillSolidRectsFlags; - } - } - if(infoRec->FillSolidSpans) { - if(!infoRec->FillSpansSolid) { - infoRec->FillSpansSolid = XAAFillSpans; - infoRec->FillSpansSolidFlags = infoRec->FillSolidSpansFlags; - } - } - - if(infoRec->FillMono8x8PatternRects || infoRec->FillColor8x8PatternRects || - infoRec->FillCacheBltRects || infoRec->FillColorExpandRects || - infoRec->FillCacheExpandRects) { - if(!infoRec->PolyFillRectStippled) { - - infoRec->PolyFillRectStippled = XAAPolyFillRect; - infoRec->PolyFillRectStippledFlags = 0; - } - } - - if(infoRec->FillMono8x8PatternSpans || infoRec->FillColor8x8PatternSpans || - infoRec->FillCacheBltSpans || infoRec->FillColorExpandSpans || - infoRec->FillCacheExpandSpans) { - if(!infoRec->FillSpansStippled) { - - infoRec->FillSpansStippled = XAAFillSpans; - infoRec->FillSpansStippledFlags = 0; - } - } - - if(infoRec->FillMono8x8PatternRects || infoRec->FillColor8x8PatternRects || - infoRec->FillCacheBltRects || infoRec->FillColorExpandRects || - infoRec->FillCacheExpandRects) { - if(!infoRec->PolyFillRectOpaqueStippled) { - - infoRec->PolyFillRectOpaqueStippled = XAAPolyFillRect; - infoRec->PolyFillRectOpaqueStippledFlags = 0; - } - } - - if(infoRec->FillMono8x8PatternSpans || infoRec->FillColor8x8PatternSpans || - infoRec->FillCacheBltSpans || infoRec->FillColorExpandSpans || - infoRec->FillCacheExpandSpans) { - if(!infoRec->FillSpansOpaqueStippled) { - - infoRec->FillSpansOpaqueStippled = XAAFillSpans; - infoRec->FillSpansOpaqueStippledFlags = 0; - } - } - - if(infoRec->FillMono8x8PatternRects || infoRec->FillColor8x8PatternRects || - infoRec->FillCacheBltRects || infoRec->FillImageWriteRects) { - if(!infoRec->PolyFillRectTiled) { - - infoRec->PolyFillRectTiled = XAAPolyFillRect; - infoRec->PolyFillRectTiledFlags = 0; - } - } - - if(infoRec->FillMono8x8PatternSpans || infoRec->FillColor8x8PatternSpans || - infoRec->FillCacheBltSpans) { - if(!infoRec->FillSpansTiled) { - - infoRec->FillSpansTiled = XAAFillSpans; - infoRec->FillSpansTiledFlags = 0; - } - } - - if(infoRec->TEGlyphRenderer && - !(infoRec->TEGlyphRendererFlags & NO_TRANSPARENCY)) { - - if(!infoRec->PolyText8TE) { - infoRec->PolyText8TE = XAAPolyText8TEColorExpansion; - infoRec->PolyText8TEFlags = infoRec->TEGlyphRendererFlags; - } - - if(!infoRec->PolyText16TE) { - infoRec->PolyText16TE = XAAPolyText16TEColorExpansion; - infoRec->PolyText16TEFlags = infoRec->TEGlyphRendererFlags; - } - - if(!infoRec->PolyGlyphBltTE) { - infoRec->PolyGlyphBltTE = XAAPolyGlyphBltTEColorExpansion; - infoRec->PolyGlyphBltTEFlags = infoRec->TEGlyphRendererFlags; - } - } - - if(infoRec->TEGlyphRenderer && - !(infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { - - if(!infoRec->ImageText8TE) { - infoRec->ImageText8TE = XAAImageText8TEColorExpansion; - infoRec->ImageText8TEFlags = infoRec->TEGlyphRendererFlags; - } - - if(!infoRec->ImageText16TE) { - infoRec->ImageText16TE = XAAImageText16TEColorExpansion; - infoRec->ImageText16TEFlags = infoRec->TEGlyphRendererFlags; - } - - if(!infoRec->ImageGlyphBltTE) { - infoRec->ImageGlyphBltTE = XAAImageGlyphBltTEColorExpansion; - infoRec->ImageGlyphBltTEFlags = infoRec->TEGlyphRendererFlags; - } - } - - if(infoRec->NonTEGlyphRenderer) { - if(!infoRec->PolyText8NonTE) { - infoRec->PolyText8NonTE = XAAPolyText8NonTEColorExpansion; - infoRec->PolyText8NonTEFlags = infoRec->NonTEGlyphRendererFlags; - } - - if(!infoRec->PolyText16NonTE) { - infoRec->PolyText16NonTE = XAAPolyText16NonTEColorExpansion; - infoRec->PolyText16NonTEFlags = infoRec->NonTEGlyphRendererFlags; - } - if(!infoRec->PolyGlyphBltNonTE) { - infoRec->PolyGlyphBltNonTE = XAAPolyGlyphBltNonTEColorExpansion; - infoRec->PolyGlyphBltNonTEFlags = infoRec->NonTEGlyphRendererFlags; - } - } - - if(infoRec->NonTEGlyphRenderer && HaveSolidFillRect) { - if(!infoRec->ImageText8NonTE) { - infoRec->ImageText8NonTE = XAAImageText8NonTEColorExpansion; - infoRec->ImageText8NonTEFlags = infoRec->NonTEGlyphRendererFlags; - } - - if(!infoRec->ImageText16NonTE) { - infoRec->ImageText16NonTE = XAAImageText16NonTEColorExpansion; - infoRec->ImageText16NonTEFlags = infoRec->NonTEGlyphRendererFlags; - } - - if(!infoRec->ImageGlyphBltNonTE) { - infoRec->ImageGlyphBltNonTE = XAAImageGlyphBltNonTEColorExpansion; - infoRec->ImageGlyphBltNonTEFlags = infoRec->NonTEGlyphRendererFlags; - } - } - - if(!infoRec->PolyRectangleThinSolid && HaveSolidHorVertLine) { - infoRec->PolyRectangleThinSolid = XAAPolyRectangleThinSolid; - infoRec->PolyRectangleThinSolidFlags = infoRec->SolidLineFlags; - } - - if(!infoRec->FillPolygonSolid && HaveSolidFillRect) { - infoRec->FillPolygonSolid = XAAFillPolygonSolid; - infoRec->FillPolygonSolidFlags = infoRec->SolidFillFlags; - } - - if(!infoRec->FillPolygonStippled && (HaveMono8x8PatternFillRect || - HaveScreenToScreenColorExpandFill || HaveScreenToScreenCopy)) { - infoRec->FillPolygonStippled = XAAFillPolygonStippled; - infoRec->FillPolygonStippledFlags = infoRec->SolidFillFlags; - } - - if(!infoRec->FillPolygonOpaqueStippled && (HaveMono8x8PatternFillRect || - HaveScreenToScreenColorExpandFill || HaveScreenToScreenCopy)) { - infoRec->FillPolygonOpaqueStippled = XAAFillPolygonStippled; - infoRec->FillPolygonOpaqueStippledFlags = infoRec->SolidFillFlags; - } - - if(!infoRec->FillPolygonTiled && (HaveMono8x8PatternFillRect || - HaveScreenToScreenColorExpandFill || HaveScreenToScreenCopy)) { - infoRec->FillPolygonTiled = XAAFillPolygonTiled; - infoRec->FillPolygonTiledFlags = infoRec->SolidFillFlags; - } - - - if(!infoRec->PolyFillArcSolid && HaveSolidFillRect) { - infoRec->PolyFillArcSolid = XAAPolyFillArcSolid; - infoRec->PolyFillArcSolidFlags = infoRec->SolidFillFlags; - } - - if(!infoRec->PolylinesWideSolid && HaveSolidFillRect) { - infoRec->PolylinesWideSolid = XAAPolylinesWideSolid; - infoRec->PolylinesWideSolidFlags = - infoRec->SolidFillFlags | GXCOPY_ONLY; - } - - if(!infoRec->PutImage && (infoRec->WritePixmap || - (infoRec->WriteBitmap && - !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY)))) { - infoRec->PutImage = XAAPutImage; - - /* See comment for CopyArea above. But here we make fewer - assumptions. The driver can provide the PutImageFlags if - it wants too */ - } - - if(HaveSolidHorVertLine && - (HaveSolidBresenhamLine || (HaveSolidTwoPointLine && - (infoRec->ClippingFlags & HARDWARE_CLIP_SOLID_LINE)))){ - if(!infoRec->PolylinesThinSolid) { - infoRec->PolylinesThinSolid = XAAPolyLines; - infoRec->PolylinesThinSolidFlags = infoRec->SolidLineFlags; - } - if(!infoRec->PolySegmentThinSolid) { - infoRec->PolySegmentThinSolid = XAAPolySegment; - infoRec->PolySegmentThinSolidFlags = infoRec->SolidLineFlags; - } - } - - if(HaveDashedBresenhamLine || (HaveDashedTwoPointLine && - (infoRec->ClippingFlags & HARDWARE_CLIP_DASHED_LINE))){ - if(!infoRec->PolylinesThinDashed) { - infoRec->PolylinesThinDashed = XAAPolyLinesDashed; - infoRec->PolylinesThinDashedFlags = infoRec->DashedLineFlags; - } - if(!infoRec->PolySegmentThinDashed) { - infoRec->PolySegmentThinDashed = XAAPolySegmentDashed; - infoRec->PolySegmentThinDashedFlags = infoRec->DashedLineFlags; - } - } - - if(infoRec->PolylinesThinDashed || infoRec->PolySegmentThinDashed) { - if(!infoRec->ComputeDash) - infoRec->ComputeDash = XAAComputeDash; - } - - { - Bool haveTexture = infoRec->CPUToScreenTextureFormats && - infoRec->CPUToScreenTextureDstFormats && - infoRec->SetupForCPUToScreenTexture2 && - infoRec->SubsequentCPUToScreenTexture; - Bool haveAlphaTexture = infoRec->CPUToScreenAlphaTextureFormats && - infoRec->CPUToScreenAlphaTextureDstFormats && - infoRec->SetupForCPUToScreenAlphaTexture2 && - infoRec->SubsequentCPUToScreenAlphaTexture; - - if(!infoRec->Composite && (haveTexture || haveAlphaTexture)) - infoRec->Composite = XAADoComposite; - - if(!infoRec->Glyphs && infoRec->WriteBitmap && - !(infoRec->WriteBitmapFlags & NO_TRANSPARENCY)) - { - infoRec->Glyphs = XAADoGlyphs; - } - } - - /************ Validation Functions **************/ - - if(!infoRec->ValidateCopyArea && infoRec->CopyArea) { - infoRec->CopyAreaMask = GCWhenForced; - if((infoRec->CopyAreaFlags & GXCOPY_ONLY) || - (infoRec->CopyAreaFlags & ROP_NEEDS_SOURCE)) - infoRec->CopyAreaMask |= GCFunction; - if(infoRec->CopyAreaFlags & NO_PLANEMASK) - infoRec->CopyAreaMask |= GCPlaneMask; - infoRec->ValidateCopyArea = XAAValidateCopyArea; - } - - if(!infoRec->ValidateCopyPlane && infoRec->CopyPlane) { - infoRec->CopyPlaneMask = GCWhenForced; - if((infoRec->CopyPlaneFlags & GXCOPY_ONLY) || - (infoRec->CopyPlaneFlags & ROP_NEEDS_SOURCE)) - infoRec->CopyPlaneMask |= GCFunction; - if(infoRec->CopyPlaneFlags & NO_PLANEMASK) - infoRec->CopyPlaneMask |= GCPlaneMask; - if(infoRec->CopyPlaneFlags & RGB_EQUAL) - infoRec->CopyPlaneMask |= GCForeground | GCBackground; - infoRec->ValidateCopyPlane = XAAValidateCopyPlane; - } - - if(!infoRec->ValidatePutImage && infoRec->PutImage) { - infoRec->PutImageMask = GCWhenForced; - if((infoRec->PutImageFlags & GXCOPY_ONLY) || - (infoRec->PutImageFlags & ROP_NEEDS_SOURCE)) - infoRec->PutImageMask |= GCFunction; - if(infoRec->PutImageFlags & NO_PLANEMASK) - infoRec->PutImageMask |= GCPlaneMask; - if(infoRec->PutImageFlags & RGB_EQUAL) - infoRec->PutImageMask |= GCForeground | GCBackground; - infoRec->ValidatePutImage = XAAValidatePutImage; - } - - - if(!infoRec->ValidatePushPixels && infoRec->PushPixelsSolid) { - infoRec->PushPixelsMask = GCFillStyle; - if((infoRec->PushPixelsFlags & GXCOPY_ONLY) || - (infoRec->PushPixelsFlags & ROP_NEEDS_SOURCE) || - (infoRec->PushPixelsFlags & TRANSPARENCY_GXCOPY_ONLY)) - infoRec->PushPixelsMask |= GCFunction; - if(infoRec->PushPixelsFlags & NO_PLANEMASK) - infoRec->PushPixelsMask |= GCPlaneMask; - if(infoRec->PushPixelsFlags & RGB_EQUAL) - infoRec->PushPixelsMask |= GCForeground; - infoRec->ValidatePushPixels = XAAValidatePushPixels; - } - - /* By default XAA assumes the FillSpans, PolyFillRects, FillPolygon - and PolyFillArcs have the same restrictions. If you supply GC - level replacements for any of these and alter this relationship - you may need to supply replacement validation routines */ - - if(!infoRec->ValidateFillSpans && - (infoRec->FillSpansSolid || infoRec->FillSpansStippled || - infoRec->FillSpansOpaqueStippled || infoRec->FillSpansTiled)) { - - int compositeFlags = infoRec->FillSpansSolidFlags | - infoRec->FillSpansStippledFlags | - infoRec->FillSpansOpaqueStippledFlags | - infoRec->FillSpansTiledFlags; - - infoRec->FillSpansMask = GCFillStyle | GCTile | GCStipple; - - if((compositeFlags & GXCOPY_ONLY) || - (compositeFlags & ROP_NEEDS_SOURCE)) - infoRec->FillSpansMask |= GCFunction; - if(compositeFlags & NO_PLANEMASK) - infoRec->FillSpansMask |= GCPlaneMask; - if(compositeFlags & RGB_EQUAL) - infoRec->FillSpansMask |= GCForeground; - infoRec->ValidateFillSpans = XAAValidateFillSpans; - } - - /* By default XAA only provides Validations for the GlyphBlt - functions and not the text higher up. This is because the - Text8/16 and GlyphBlt are linked. If you break this linkage, - you may need to have the driver supply its own Validation - routines */ - - if(!infoRec->ValidatePolyGlyphBlt && - (infoRec->PolyGlyphBltTE || infoRec->PolyGlyphBltNonTE)) { - int compositeFlags = infoRec->PolyGlyphBltTEFlags | - infoRec->PolyGlyphBltNonTEFlags; - - infoRec->PolyGlyphBltMask = GCFillStyle | GCFont; - if((compositeFlags & GXCOPY_ONLY) || - (compositeFlags & ROP_NEEDS_SOURCE) || - (infoRec->PolyGlyphBltNonTEFlags & TRANSPARENCY_GXCOPY_ONLY)) - infoRec->PolyGlyphBltMask |= GCFunction; - if(compositeFlags & NO_PLANEMASK) - infoRec->PolyGlyphBltMask |= GCPlaneMask; - if(compositeFlags & RGB_EQUAL) - infoRec->PolyGlyphBltMask |= GCForeground; - infoRec->ValidatePolyGlyphBlt = XAAValidatePolyGlyphBlt; - } - - if(!infoRec->ValidateImageGlyphBlt && - (infoRec->ImageGlyphBltTE || infoRec->ImageGlyphBltNonTE)) { - int compositeFlags = infoRec->ImageGlyphBltTEFlags | - infoRec->ImageGlyphBltNonTEFlags; - - if(infoRec->ImageGlyphBltNonTE) - compositeFlags |= infoRec->SolidFillFlags; - - infoRec->ImageGlyphBltMask = GCFont; - if(compositeFlags & NO_PLANEMASK) - infoRec->ImageGlyphBltMask |= GCPlaneMask; - if(compositeFlags & RGB_EQUAL) - infoRec->ImageGlyphBltMask |= GCForeground | GCBackground; - infoRec->ValidateImageGlyphBlt = XAAValidateImageGlyphBlt; - } - - /* By default XAA only provides a Validation function for the - Polylines and does segments and polylines at the same time */ - - if(!infoRec->ValidatePolylines && infoRec->ValidateFillSpans) { - int compositeFlags = infoRec->PolyRectangleThinSolidFlags | - infoRec->PolylinesWideSolidFlags | - infoRec->PolylinesThinSolidFlags | - infoRec->PolySegmentThinSolidFlags | - infoRec->PolySegmentThinDashedFlags | - infoRec->PolylinesThinDashedFlags; - - infoRec->ValidatePolylines = XAAValidatePolylines; - infoRec->PolylinesMask = - infoRec->FillSpansMask | GCLineStyle | GCLineWidth; - - if(infoRec->PolySegmentThinDashed || infoRec->PolylinesThinDashed) - infoRec->PolylinesMask |= GCDashList; - if(compositeFlags & NO_PLANEMASK) - infoRec->PolylinesMask |= GCPlaneMask; - if((compositeFlags & GXCOPY_ONLY) || - (compositeFlags & ROP_NEEDS_SOURCE)) - infoRec->PolylinesMask |= GCFunction; - if(compositeFlags & RGB_EQUAL) - infoRec->PolylinesMask |= GCForeground; - } - - - /**** Fill choosers ****/ - - if(!infoRec->StippledFillChooser) - infoRec->StippledFillChooser = XAAStippledFillChooser; - - if(!infoRec->OpaqueStippledFillChooser) - infoRec->OpaqueStippledFillChooser = XAAOpaqueStippledFillChooser; - - if(!infoRec->TiledFillChooser) - infoRec->TiledFillChooser = XAATiledFillChooser; - - - /**** Setup the pixmap cache ****/ - - if(infoRec->WriteBitmapToCache) {} - else if(infoRec->WriteBitmap && - !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY)) - infoRec->WriteBitmapToCache = XAAWriteBitmapToCache; - else if(infoRec->Flags & LINEAR_FRAMEBUFFER) - infoRec->WriteBitmapToCache = XAAWriteBitmapToCacheLinear; - else - infoRec->PixmapCacheFlags |= DO_NOT_BLIT_STIPPLES; - - if(infoRec->WritePixmapToCache) {} - else if(infoRec->WritePixmap && !(infoRec->WritePixmapFlags & NO_GXCOPY)) - infoRec->WritePixmapToCache = XAAWritePixmapToCache; - else if(infoRec->Flags & LINEAR_FRAMEBUFFER) - infoRec->WritePixmapToCache = XAAWritePixmapToCacheLinear; - else - infoRec->Flags &= ~PIXMAP_CACHE; - - if (xf86ReturnOptValBool(options, XAAOPT_PIXMAP_CACHE, FALSE)) - infoRec->Flags &= ~PIXMAP_CACHE; - - if(infoRec->WriteMono8x8PatternToCache) {} - else if(infoRec->PixmapCacheFlags & CACHE_MONO_8x8) { - if(infoRec->WritePixmapToCache) - infoRec->WriteMono8x8PatternToCache = XAAWriteMono8x8PatternToCache; - else - infoRec->PixmapCacheFlags &= ~CACHE_MONO_8x8; - } - - if(infoRec->WriteColor8x8PatternToCache) {} - else if(infoRec->PixmapCacheFlags & CACHE_COLOR_8x8) { - if(infoRec->WritePixmapToCache && infoRec->WriteBitmapToCache) - infoRec->WriteColor8x8PatternToCache = XAAWriteColor8x8PatternToCache; - else - infoRec->PixmapCacheFlags &= ~CACHE_COLOR_8x8; - } - - if(infoRec->CachePixelGranularity < 0) { - switch(pScrn->bitsPerPixel) { - case 24: - case 8: infoRec->CachePixelGranularity = 4; break; - case 16: infoRec->CachePixelGranularity = 2; break; - case 32: infoRec->CachePixelGranularity = 1; break; - default: break; - } - - if(BITMAP_SCANLINE_PAD == 64) - infoRec->CachePixelGranularity *= 2; - } - - xfree(options); - - if(!infoRec->CacheTile && infoRec->WritePixmapToCache) - infoRec->CacheTile = XAACacheTile; - if(!infoRec->CacheMonoStipple && infoRec->WritePixmapToCache) - infoRec->CacheMonoStipple = XAACacheMonoStipple; - if(!infoRec->CacheStipple && infoRec->WriteBitmapToCache) - infoRec->CacheStipple = XAACacheStipple; - if(!infoRec->CacheMono8x8Pattern && infoRec->WriteMono8x8PatternToCache) - infoRec->CacheMono8x8Pattern = XAACacheMono8x8Pattern; - if(!infoRec->CacheColor8x8Pattern && infoRec->WriteColor8x8PatternToCache) - infoRec->CacheColor8x8Pattern = XAACacheColor8x8Pattern; - - if((infoRec->Flags & PIXMAP_CACHE) && !infoRec->InitPixmapCache) { - infoRec->InitPixmapCache = XAAInitPixmapCache; - infoRec->ClosePixmapCache = XAAClosePixmapCache; - } - - return TRUE; -} +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xf86fbman.h" +#include "servermd.h" + +/* + * XAA Config options + */ + +typedef enum { + XAAOPT_SCREEN_TO_SCREEN_COPY, + XAAOPT_SOLID_FILL_RECT, + XAAOPT_SOLID_FILL_TRAP, + XAAOPT_SOLID_TWO_POINT_LINE, + XAAOPT_SOLID_BRESENHAM_LINE, + XAAOPT_SOLID_HORVERT_LINE, + XAAOPT_DASHED_TWO_POINT_LINE, + XAAOPT_DASHED_BRESENHAM_LINE, + XAAOPT_MONO_8x8_PATTERN_FILL_RECT, + XAAOPT_MONO_8x8_PATTERN_FILL_TRAP, + XAAOPT_COL_8x8_PATTERN_FILL_RECT, + XAAOPT_COL_8x8_PATTERN_FILL_TRAP, + XAAOPT_CPU_TO_SCREEN_COL_EXP_FILL, + XAAOPT_SCANLINE_CPU_TO_SCREEN_COL_EXP_FILL, + XAAOPT_SCREEN_TO_SCREEN_COL_EXP_FILL, + XAAOPT_IMAGE_WRITE_RECT, + XAAOPT_SCANLINE_IMAGE_WRITE_RECT, + XAAOPT_WRITE_BITMAP, + XAAOPT_WRITE_PIXMAP, + XAAOPT_PIXMAP_CACHE, + XAAOPT_OFFSCREEN_PIXMAPS, + XAAOPT_HAS_DUMB_INVERTED_OPTION_SENSE +} XAAOpts; + +static const OptionInfoRec XAAOptions[] = { + {XAAOPT_SCREEN_TO_SCREEN_COPY, "XaaNoScreenToScreenCopy", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_SOLID_FILL_RECT, "XaaNoSolidFillRect", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_SOLID_FILL_TRAP, "XaaNoSolidFillTrap", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_SOLID_TWO_POINT_LINE, "XaaNoSolidTwoPointLine", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_SOLID_BRESENHAM_LINE, "XaaNoSolidBresenhamLine", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_SOLID_HORVERT_LINE, "XaaNoSolidHorVertLine", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_DASHED_TWO_POINT_LINE, "XaaNoDashedTwoPointLine", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_DASHED_BRESENHAM_LINE, "XaaNoDashedBresenhamLine", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_MONO_8x8_PATTERN_FILL_RECT, "XaaNoMono8x8PatternFillRect", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_MONO_8x8_PATTERN_FILL_TRAP, "XaaNoMono8x8PatternFillTrap", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_COL_8x8_PATTERN_FILL_RECT, "XaaNoColor8x8PatternFillRect", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_COL_8x8_PATTERN_FILL_TRAP, "XaaNoColor8x8PatternFillTrap", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_CPU_TO_SCREEN_COL_EXP_FILL, "XaaNoCPUToScreenColorExpandFill", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_SCANLINE_CPU_TO_SCREEN_COL_EXP_FILL,"XaaNoScanlineCPUToScreenColorExpandFill", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_SCREEN_TO_SCREEN_COL_EXP_FILL, "XaaNoScreenToScreenColorExpandFill", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_IMAGE_WRITE_RECT, "XaaNoImageWriteRect", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_SCANLINE_IMAGE_WRITE_RECT, "XaaNoScanlineImageWriteRect", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_WRITE_BITMAP, "XaaNoWriteBitmap", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_WRITE_PIXMAP, "XaaNoWritePixmap", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_PIXMAP_CACHE, "XaaNoPixmapCache", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_OFFSCREEN_PIXMAPS, "XaaNoOffscreenPixmaps", + OPTV_BOOLEAN, {0}, FALSE }, + {XAAOPT_HAS_DUMB_INVERTED_OPTION_SENSE, "XaaOffscreenPixmaps", + OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, + OPTV_NONE, {0}, FALSE } +}; + +static XF86ModuleVersionInfo xaaVersRec = +{ + "xaa", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + XAA_VERSION_MAJOR, + XAA_VERSION_MINOR, + XAA_VERSION_RELEASE, + ABI_CLASS_VIDEODRV, /* requires the video driver ABI */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + {0,0,0,0} +}; + +_X_EXPORT XF86ModuleData xaaModuleData = { &xaaVersRec, NULL, NULL }; + +Bool +XAAInitAccel(ScreenPtr pScreen, XAAInfoRecPtr infoRec) +{ + int index = pScreen->myNum; + ScrnInfoPtr pScrn = xf86Screens[index]; + Bool HaveScreenToScreenCopy = FALSE; + Bool HaveColorExpansion = FALSE; + Bool HaveScanlineColorExpansion = FALSE; + Bool HaveSolidFillRect = FALSE; + Bool HaveMono8x8PatternFillRect = FALSE; + Bool HaveColor8x8PatternFillRect = FALSE; + Bool HaveSolidFillTrap = FALSE; + Bool HaveMono8x8PatternFillTrap = FALSE; + Bool HaveColor8x8PatternFillTrap = FALSE; + Bool HaveSolidTwoPointLine = FALSE; + Bool HaveSolidBresenhamLine = FALSE; + Bool HaveSolidHorVertLine = FALSE; + Bool HaveDashedTwoPointLine = FALSE; + Bool HaveDashedBresenhamLine = FALSE; + Bool HaveImageWriteRect = FALSE; + Bool HaveScanlineImageWriteRect = FALSE; + Bool HaveScreenToScreenColorExpandFill = FALSE; + OptionInfoPtr options; + int is_shared = 0; + int i; + + options = xnfalloc(sizeof(XAAOptions)); + (void)memcpy(options, XAAOptions, sizeof(XAAOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); + + infoRec->pScrn = pScrn; + infoRec->NeedToSync = FALSE; + + /* must have a Sync function */ + if(!infoRec->Sync) return FALSE; + for(i = 0; i < pScrn->numEntities; i++) { + if(xf86IsEntityShared(pScrn->entityList[i])) is_shared = 1; + } + + /* If this PCI entity has IS_SHARED_ACCEL set in entityProp + * then a RestoreAccelState function is required + */ + if(!infoRec->RestoreAccelState && is_shared) return FALSE; + + if(infoRec->RestoreAccelState) { + if(!XAAInitStateWrap(pScreen, infoRec)) return FALSE; + } + + if (serverGeneration == 1) + xf86DrvMsg(index, X_INFO, + "Using XFree86 Acceleration Architecture (XAA)\n"); + + + /************** Low Level *************/ + + if(!infoRec->SetClippingRectangle || !infoRec->DisableClipping) { + infoRec->ClippingFlags = 0; + infoRec->SetClippingRectangle = NULL; + infoRec->DisableClipping = NULL; + } + + /**** CopyArea ****/ + + if(infoRec->SetupForScreenToScreenCopy && + infoRec->SubsequentScreenToScreenCopy && + !xf86ReturnOptValBool(options, XAAOPT_SCREEN_TO_SCREEN_COPY, FALSE)) { + HaveScreenToScreenCopy = TRUE; + } else { + infoRec->ScreenToScreenCopyFlags = 0; + infoRec->SetupForScreenToScreenCopy = NULL; + infoRec->SubsequentScreenToScreenCopy = NULL; + } + + /**** Solid Filled Rects ****/ + + if(infoRec->SetupForSolidFill && infoRec->SubsequentSolidFillRect && + !xf86ReturnOptValBool(options, XAAOPT_SOLID_FILL_RECT, FALSE)) { + HaveSolidFillRect = TRUE; + if(infoRec->SubsequentSolidFillTrap && + !xf86ReturnOptValBool(options, XAAOPT_SOLID_FILL_TRAP, FALSE)) + HaveSolidFillTrap = TRUE; + else + infoRec->SubsequentSolidFillTrap = NULL; + } else { + infoRec->SolidFillFlags = 0; + infoRec->SetupForSolidFill = NULL; + infoRec->SubsequentSolidFillRect = NULL; + infoRec->SubsequentSolidFillTrap = NULL; + } + + /**** Solid lines ****/ + + if(infoRec->SetupForSolidLine) { + if(infoRec->SubsequentSolidTwoPointLine && + !xf86ReturnOptValBool(options, + XAAOPT_SOLID_TWO_POINT_LINE, FALSE)) + HaveSolidTwoPointLine = TRUE; + if(infoRec->SubsequentSolidBresenhamLine && + !xf86ReturnOptValBool(options, XAAOPT_SOLID_BRESENHAM_LINE, FALSE)) { + HaveSolidBresenhamLine = TRUE; + + if(infoRec->SolidBresenhamLineErrorTermBits) + infoRec->SolidBresenhamLineErrorTermBits = + ~((1 << infoRec->SolidBresenhamLineErrorTermBits) - 1); + } + + if(infoRec->SubsequentSolidHorVertLine && + !xf86ReturnOptValBool(options, + XAAOPT_SOLID_HORVERT_LINE, FALSE)) + HaveSolidHorVertLine = TRUE; + else if(HaveSolidTwoPointLine) { + infoRec->SubsequentSolidHorVertLine = + XAASolidHorVertLineAsTwoPoint; + HaveSolidHorVertLine = TRUE; + } else if(HaveSolidBresenhamLine) { + infoRec->SubsequentSolidHorVertLine = + XAASolidHorVertLineAsBresenham; + HaveSolidHorVertLine = TRUE; + } + } + + /* XXX Should this also check for XAAOPT_SOLID_HORVERT_LINE? */ + if (!HaveSolidTwoPointLine && + !HaveSolidBresenhamLine && + !HaveSolidHorVertLine && + HaveSolidFillRect) { + infoRec->SetupForSolidLine = infoRec->SetupForSolidFill; + infoRec->SubsequentSolidHorVertLine = XAASolidHorVertLineAsRects; + infoRec->SolidLineFlags = infoRec->SolidFillFlags; + HaveSolidHorVertLine = TRUE; + } + + if (!HaveSolidTwoPointLine) + infoRec->SubsequentSolidTwoPointLine = NULL; + if (!HaveSolidBresenhamLine) + infoRec->SubsequentSolidBresenhamLine = NULL; + if (!HaveSolidHorVertLine) + infoRec->SubsequentSolidHorVertLine = NULL; + + /* Disable all if nothing left over */ + if (!HaveSolidTwoPointLine && + !HaveSolidBresenhamLine && + !HaveSolidHorVertLine) { + infoRec->SolidLineFlags = 0; + infoRec->SetupForSolidLine = NULL; + } + + /**** 8x8 Mono Pattern Filled Rects ****/ + + if(infoRec->SetupForMono8x8PatternFill && + infoRec->SubsequentMono8x8PatternFillRect && + !xf86ReturnOptValBool(options, + XAAOPT_MONO_8x8_PATTERN_FILL_RECT, + FALSE)) { + HaveMono8x8PatternFillRect = TRUE; + if(infoRec->SubsequentMono8x8PatternFillTrap && + !xf86ReturnOptValBool(options, + XAAOPT_MONO_8x8_PATTERN_FILL_TRAP, + FALSE)) + HaveMono8x8PatternFillTrap = TRUE; + + if(infoRec->Mono8x8PatternFillFlags & + HARDWARE_PATTERN_PROGRAMMED_BITS) { + infoRec->CanDoMono8x8 = TRUE; + } else { /* others require caching */ + int min_pitch; + infoRec->PixmapCacheFlags |= CACHE_MONO_8x8; + + switch(pScrn->bitsPerPixel) { + case 32: min_pitch = 2; break; + case 24: min_pitch = 3; break; + case 16: min_pitch = 4; break; + default: min_pitch = 8; break; + } + + if(min_pitch > infoRec->MonoPatternPitch) + infoRec->MonoPatternPitch = min_pitch; + + if(infoRec->Mono8x8PatternFillFlags & + HARDWARE_PATTERN_PROGRAMMED_ORIGIN) { + if(!infoRec->CacheWidthMono8x8Pattern || + !infoRec->CacheHeightMono8x8Pattern) { + infoRec->CacheWidthMono8x8Pattern = + infoRec->MonoPatternPitch; + infoRec->CacheHeightMono8x8Pattern = 1; + } + } else { + int numPerLine = 128/infoRec->MonoPatternPitch; + + if(!infoRec->CacheWidthMono8x8Pattern || + !infoRec->CacheHeightMono8x8Pattern) { + infoRec->CacheWidthMono8x8Pattern = + numPerLine * infoRec->MonoPatternPitch; + infoRec->CacheHeightMono8x8Pattern = + (64 + numPerLine - 1)/numPerLine; + } + } + } + } else { + infoRec->Mono8x8PatternFillFlags = 0; + infoRec->SetupForMono8x8PatternFill = NULL; + infoRec->SubsequentMono8x8PatternFillRect = NULL; + } + + /**** Dashed lines ****/ + + if(infoRec->SetupForDashedLine && infoRec->DashPatternMaxLength) { + if(infoRec->SubsequentDashedTwoPointLine && + !xf86ReturnOptValBool(options, XAAOPT_DASHED_TWO_POINT_LINE, + FALSE)) + HaveDashedTwoPointLine = TRUE; + if(infoRec->SubsequentDashedBresenhamLine && + !xf86ReturnOptValBool(options, XAAOPT_DASHED_BRESENHAM_LINE, + FALSE)) { + HaveDashedBresenhamLine = TRUE; + + if(infoRec->DashedBresenhamLineErrorTermBits) + infoRec->DashedBresenhamLineErrorTermBits = + ~((1 << infoRec->DashedBresenhamLineErrorTermBits) - 1); + } + } + + if (!HaveDashedTwoPointLine) + infoRec->SubsequentDashedTwoPointLine = NULL; + if (!HaveDashedBresenhamLine) + infoRec->SubsequentDashedBresenhamLine = NULL; + + /* Disable all if nothing left over */ + if (!HaveDashedTwoPointLine && !HaveDashedBresenhamLine) { + infoRec->DashedLineFlags = 0; + infoRec->SetupForDashedLine = NULL; + } + + /**** 8x8 Color Pattern Filled Rects ****/ + + if(infoRec->SetupForColor8x8PatternFill && + infoRec->SubsequentColor8x8PatternFillRect && + !xf86ReturnOptValBool(options, XAAOPT_COL_8x8_PATTERN_FILL_RECT, FALSE)) { + HaveColor8x8PatternFillRect = TRUE; + if(infoRec->SubsequentColor8x8PatternFillTrap && + !xf86ReturnOptValBool(options, XAAOPT_COL_8x8_PATTERN_FILL_TRAP, + FALSE)) + HaveColor8x8PatternFillTrap = TRUE; + else + infoRec->SubsequentColor8x8PatternFillTrap = NULL; + + infoRec->PixmapCacheFlags |= CACHE_COLOR_8x8; + + if(infoRec->Color8x8PatternFillFlags & + HARDWARE_PATTERN_PROGRAMMED_ORIGIN) { + if(!infoRec->CacheWidthColor8x8Pattern || + !infoRec->CacheHeightColor8x8Pattern) { + infoRec->CacheWidthColor8x8Pattern = 64; + infoRec->CacheHeightColor8x8Pattern = 1; + } + } else { + if(!infoRec->CacheWidthColor8x8Pattern || + !infoRec->CacheHeightColor8x8Pattern) { + infoRec->CacheWidthColor8x8Pattern = 128; + infoRec->CacheHeightColor8x8Pattern = 8; + } + } + } else { + infoRec->Color8x8PatternFillFlags = 0; + infoRec->SetupForColor8x8PatternFill = NULL; + infoRec->SubsequentColor8x8PatternFillRect = NULL; + infoRec->SubsequentColor8x8PatternFillTrap = NULL; + } + + /**** Color Expansion ****/ + + if(infoRec->SetupForCPUToScreenColorExpandFill && + infoRec->ColorExpandBase && + infoRec->SubsequentCPUToScreenColorExpandFill && + !xf86ReturnOptValBool(options, XAAOPT_CPU_TO_SCREEN_COL_EXP_FILL, + FALSE)) { + int dwordsNeeded = pScrn->virtualX; + + infoRec->ColorExpandRange >>= 2; /* convert to DWORDS */ + HaveColorExpansion = TRUE; + + if(infoRec->CPUToScreenColorExpandFillFlags & + LEFT_EDGE_CLIPPING_NEGATIVE_X) + dwordsNeeded += 31; + dwordsNeeded = (dwordsNeeded + 31) >> 5; + if(dwordsNeeded > infoRec->ColorExpandRange) + infoRec->CPUToScreenColorExpandFillFlags |= CPU_TRANSFER_BASE_FIXED; + } else { + infoRec->CPUToScreenColorExpandFillFlags = 0; + infoRec->SetupForCPUToScreenColorExpandFill = NULL; + infoRec->SubsequentCPUToScreenColorExpandFill = NULL; + } + + /**** Scanline Color Expansion ****/ + + if(infoRec->SetupForScanlineCPUToScreenColorExpandFill && + infoRec->SubsequentScanlineCPUToScreenColorExpandFill && + infoRec->SubsequentColorExpandScanline && + infoRec->ScanlineColorExpandBuffers && + (infoRec->NumScanlineColorExpandBuffers > 0) && + !xf86ReturnOptValBool(options, + XAAOPT_SCANLINE_CPU_TO_SCREEN_COL_EXP_FILL, + FALSE)) { + HaveScanlineColorExpansion = TRUE; + } else { + infoRec->ScanlineCPUToScreenColorExpandFillFlags = 0; + infoRec->SetupForScanlineCPUToScreenColorExpandFill = NULL; + infoRec->SubsequentScanlineCPUToScreenColorExpandFill = NULL; + infoRec->SubsequentColorExpandScanline = NULL; + } + + /**** Screen to Screen Color Expansion ****/ + + if(infoRec->SetupForScreenToScreenColorExpandFill && + infoRec->SubsequentScreenToScreenColorExpandFill && + !xf86ReturnOptValBool(options, XAAOPT_SCREEN_TO_SCREEN_COL_EXP_FILL, + FALSE)) { + HaveScreenToScreenColorExpandFill = TRUE; + if (!infoRec->CacheColorExpandDensity) + infoRec->CacheColorExpandDensity = 1; + } else { + infoRec->ScreenToScreenColorExpandFillFlags = 0; + infoRec->SetupForScreenToScreenColorExpandFill = NULL; + infoRec->SubsequentScreenToScreenColorExpandFill = NULL; + } + + /**** Image Writes ****/ + + if(infoRec->SetupForImageWrite && infoRec->ImageWriteBase && + infoRec->SubsequentImageWriteRect && + !xf86ReturnOptValBool(options, XAAOPT_IMAGE_WRITE_RECT, FALSE)) { + + infoRec->ImageWriteRange >>= 2; /* convert to DWORDS */ + if(infoRec->ImageWriteFlags & CPU_TRANSFER_BASE_FIXED) + infoRec->ImageWriteRange = 0; + HaveImageWriteRect = TRUE; + } else { + infoRec->ImageWriteFlags = 0; + infoRec->SetupForImageWrite = NULL; + infoRec->SubsequentImageWriteRect = NULL; + } + + /**** Scanline Image Writes ****/ + + if(infoRec->SetupForScanlineImageWrite && + infoRec->SubsequentScanlineImageWriteRect && + infoRec->SubsequentImageWriteScanline && + infoRec->ScanlineImageWriteBuffers && + (infoRec->NumScanlineImageWriteBuffers > 0) && + !xf86ReturnOptValBool(options, XAAOPT_SCANLINE_IMAGE_WRITE_RECT, + FALSE)) { + HaveScanlineImageWriteRect = TRUE; + } else { + infoRec->ScanlineImageWriteFlags = 0; + infoRec->SetupForScanlineImageWrite = NULL; + infoRec->SubsequentScanlineImageWriteRect = NULL; + infoRec->SubsequentImageWriteScanline = NULL; + } + +#ifndef __i386__ + /* XAA makes some unaligned accesses when clipping is not available */ +# define CLIP_FLAGS (LEFT_EDGE_CLIPPING | LEFT_EDGE_CLIPPING_NEGATIVE_X) + if(HaveImageWriteRect && + ((infoRec->ImageWriteFlags & CLIP_FLAGS) != CLIP_FLAGS)) + { + HaveImageWriteRect = FALSE; + } + if(HaveScanlineImageWriteRect && + ((infoRec->ScanlineImageWriteFlags & CLIP_FLAGS) != CLIP_FLAGS)) + { + HaveScanlineImageWriteRect = FALSE; + } +#endif + + if (serverGeneration == 1) { + if(HaveScreenToScreenCopy) + xf86ErrorF("\tScreen to screen bit blits\n"); + if(HaveSolidFillRect) + xf86ErrorF("\tSolid filled rectangles\n"); + if(HaveSolidFillTrap) + xf86ErrorF("\tSolid filled trapezoids\n"); + if(HaveMono8x8PatternFillRect) + xf86ErrorF("\t8x8 mono pattern filled rectangles\n"); + if(HaveMono8x8PatternFillTrap) + xf86ErrorF("\t8x8 mono pattern filled trapezoids\n"); + if(HaveColor8x8PatternFillRect) + xf86ErrorF("\t8x8 color pattern filled rectangles\n"); + if(HaveColor8x8PatternFillTrap) + xf86ErrorF("\t8x8 color pattern filled trapezoids\n"); + + if(HaveColorExpansion) + xf86ErrorF("\tCPU to Screen color expansion\n"); + else if(HaveScanlineColorExpansion) + xf86ErrorF("\tIndirect CPU to Screen color expansion\n"); + + if(HaveScreenToScreenColorExpandFill) + xf86ErrorF("\tScreen to Screen color expansion\n"); + + if(HaveSolidTwoPointLine || HaveSolidBresenhamLine) + xf86ErrorF("\tSolid Lines\n"); + else if(HaveSolidHorVertLine) + xf86ErrorF("\tSolid Horizontal and Vertical Lines\n"); + + if(HaveDashedTwoPointLine || HaveDashedBresenhamLine) + xf86ErrorF("\tDashed Lines\n"); + + if(HaveImageWriteRect) + xf86ErrorF("\tImage Writes\n"); + else if(HaveScanlineImageWriteRect) + xf86ErrorF("\tScanline Image Writes\n"); + + } + +#define XAAMSG(s) do { if (serverGeneration == 1) xf86ErrorF(s); } while (0) + + if((infoRec->Flags & OFFSCREEN_PIXMAPS) && HaveScreenToScreenCopy && + xf86ReturnOptValBool(options, + XAAOPT_HAS_DUMB_INVERTED_OPTION_SENSE, + FALSE)) + { + XAAMSG("\tOffscreen Pixmaps\n"); + } else { + infoRec->Flags &= ~OFFSCREEN_PIXMAPS; + } + + + /************** Mid Level *************/ + + /**** ScreenToScreenBitBlt ****/ + + if(infoRec->ScreenToScreenBitBlt) { + XAAMSG("\tDriver provided ScreenToScreenBitBlt replacement\n"); + } else if(HaveScreenToScreenCopy) { + infoRec->ScreenToScreenBitBlt = XAAScreenToScreenBitBlt; + infoRec->ScreenToScreenBitBltFlags = infoRec->ScreenToScreenCopyFlags; + } + + /**** FillSolidRects ****/ + + if(infoRec->FillSolidRects) { + XAAMSG("\tDriver provided FillSolidRects replacement\n"); + } else if(HaveSolidFillRect) { + infoRec->FillSolidRects = XAAFillSolidRects; + infoRec->FillSolidRectsFlags = infoRec->SolidFillFlags; + } + + /**** FillSolidSpans ****/ + + if(infoRec->FillSolidSpans) { + XAAMSG("\tDriver provided FillSolidSpans replacement\n"); + } else if(HaveSolidFillRect) { + infoRec->FillSolidSpans = XAAFillSolidSpans; + infoRec->FillSolidSpansFlags = infoRec->SolidFillFlags; + } + + /**** FillMono8x8PatternRects ****/ + + if(infoRec->FillMono8x8PatternRects) { + XAAMSG("\tDriver provided FillMono8x8PatternRects replacement\n"); + } else if(HaveMono8x8PatternFillRect) { + infoRec->FillMono8x8PatternRects = + (infoRec->Mono8x8PatternFillFlags & HARDWARE_PATTERN_SCREEN_ORIGIN) ? + XAAFillMono8x8PatternRectsScreenOrigin : + XAAFillMono8x8PatternRects; + + infoRec->FillMono8x8PatternRectsFlags = + infoRec->Mono8x8PatternFillFlags; + } + + /**** FillMono8x8PatternSpans ****/ + + if(infoRec->FillMono8x8PatternSpans) { + XAAMSG("\tDriver provided FillMono8x8PatternSpans replacement\n"); + } else if(HaveMono8x8PatternFillRect) { + infoRec->FillMono8x8PatternSpans = + (infoRec->Mono8x8PatternFillFlags & HARDWARE_PATTERN_SCREEN_ORIGIN) ? + XAAFillMono8x8PatternSpansScreenOrigin: + XAAFillMono8x8PatternSpans; + + infoRec->FillMono8x8PatternSpansFlags = + infoRec->Mono8x8PatternFillFlags; + } + + /**** FillColor8x8Rects ****/ + + if(infoRec->FillColor8x8PatternRects) { + XAAMSG("\tDriver provided FillColor8x8PatternRects replacement\n"); + } else if(HaveColor8x8PatternFillRect) { + infoRec->FillColor8x8PatternRects = + (infoRec->Color8x8PatternFillFlags & HARDWARE_PATTERN_SCREEN_ORIGIN) ? + XAAFillColor8x8PatternRectsScreenOrigin : + XAAFillColor8x8PatternRects; + + infoRec->FillColor8x8PatternRectsFlags = + infoRec->Color8x8PatternFillFlags; + } + + /**** FillColor8x8Spans ****/ + + if(infoRec->FillColor8x8PatternSpans) { + XAAMSG("\tDriver provided FillColor8x8PatternSpans replacement\n"); + } else if(HaveColor8x8PatternFillRect) { + infoRec->FillColor8x8PatternSpans = + (infoRec->Color8x8PatternFillFlags & HARDWARE_PATTERN_SCREEN_ORIGIN) ? + XAAFillColor8x8PatternSpansScreenOrigin: + XAAFillColor8x8PatternSpans; + + infoRec->FillColor8x8PatternSpansFlags = + infoRec->Color8x8PatternFillFlags; + } + + /**** FillCacheBltRects ****/ + + if(infoRec->FillCacheBltRects) { + XAAMSG("\tDriver provided FillCacheBltRects replacement\n"); + } else if(HaveScreenToScreenCopy) { + infoRec->FillCacheBltRects = XAAFillCacheBltRects; + infoRec->FillCacheBltRectsFlags = infoRec->ScreenToScreenCopyFlags; + } + + /**** FillCacheBltSpans ****/ + + if(infoRec->FillCacheBltSpans) { + XAAMSG("\tDriver provided FillCacheBltSpans replacement\n"); + } else if(HaveScreenToScreenCopy) { + infoRec->FillCacheBltSpans = XAAFillCacheBltSpans; + infoRec->FillCacheBltSpansFlags = infoRec->ScreenToScreenCopyFlags; + } + + /**** FillCacheExpandRects ****/ + + if(infoRec->FillCacheExpandRects) { + XAAMSG("\tDriver provided FillCacheExpandRects replacement\n"); + } else if(HaveScreenToScreenColorExpandFill) { + infoRec->FillCacheExpandRects = XAAFillCacheExpandRects; + infoRec->FillCacheExpandRectsFlags = + infoRec->ScreenToScreenColorExpandFillFlags; + } + + /**** FillCacheExpandSpans ****/ + + if(infoRec->FillCacheExpandSpans) { + XAAMSG("\tDriver provided FillCacheExpandSpans replacement\n"); + } else if(HaveScreenToScreenColorExpandFill) { + infoRec->FillCacheExpandSpans = XAAFillCacheExpandSpans; + infoRec->FillCacheExpandSpansFlags = + infoRec->ScreenToScreenColorExpandFillFlags; + } + + /**** FillColorExpandRects ****/ + + if(infoRec->FillColorExpandRects) { + XAAMSG("\tDriver provided FillColorExpandRects replacement\n"); + } else if(HaveColorExpansion) { + if (infoRec->CPUToScreenColorExpandFillFlags & TRIPLE_BITS_24BPP) { + if(infoRec->CPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->FillColorExpandRects = + XAAFillColorExpandRects3MSBFirstFixedBase; + else + infoRec->FillColorExpandRects = + XAAFillColorExpandRects3MSBFirst; + } else { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->FillColorExpandRects = + XAAFillColorExpandRects3LSBFirstFixedBase; + else + infoRec->FillColorExpandRects = + XAAFillColorExpandRects3LSBFirst; + } + } else { + if(infoRec->CPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->FillColorExpandRects = + XAAFillColorExpandRectsMSBFirstFixedBase; + else + infoRec->FillColorExpandRects = + XAAFillColorExpandRectsMSBFirst; + } else { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->FillColorExpandRects = + XAAFillColorExpandRectsLSBFirstFixedBase; + else + infoRec->FillColorExpandRects = + XAAFillColorExpandRectsLSBFirst; + } + } + infoRec->FillColorExpandRectsFlags = + infoRec->CPUToScreenColorExpandFillFlags; + } else if(HaveScanlineColorExpansion) { + if (infoRec->ScanlineCPUToScreenColorExpandFillFlags & + TRIPLE_BITS_24BPP) { + if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) + infoRec->FillColorExpandRects = + XAAFillScanlineColorExpandRects3MSBFirst; + else + infoRec->FillColorExpandRects = + XAAFillScanlineColorExpandRects3LSBFirst; + } else { + if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) + infoRec->FillColorExpandRects = + XAAFillScanlineColorExpandRectsMSBFirst; + else + infoRec->FillColorExpandRects = + XAAFillScanlineColorExpandRectsLSBFirst; + } + infoRec->FillColorExpandRectsFlags = + infoRec->ScanlineCPUToScreenColorExpandFillFlags; + } + + /**** FillColorExpandSpans ****/ + + if(infoRec->FillColorExpandSpans) { + XAAMSG("\tDriver provided FillColorExpandSpans replacement\n"); + } else if(HaveColorExpansion) { + if (infoRec->CPUToScreenColorExpandFillFlags & TRIPLE_BITS_24BPP) { + if(infoRec->CPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->FillColorExpandSpans = + XAAFillColorExpandSpans3MSBFirstFixedBase; + else + infoRec->FillColorExpandSpans = + XAAFillColorExpandSpans3MSBFirst; + } else { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->FillColorExpandSpans = + XAAFillColorExpandSpans3LSBFirstFixedBase; + else + infoRec->FillColorExpandSpans = + XAAFillColorExpandSpans3LSBFirst; + } + } else { + if(infoRec->CPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->FillColorExpandSpans = + XAAFillColorExpandSpansMSBFirstFixedBase; + else + infoRec->FillColorExpandSpans = + XAAFillColorExpandSpansMSBFirst; + } else { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->FillColorExpandSpans = + XAAFillColorExpandSpansLSBFirstFixedBase; + else + infoRec->FillColorExpandSpans = + XAAFillColorExpandSpansLSBFirst; + } + } + infoRec->FillColorExpandSpansFlags = + infoRec->CPUToScreenColorExpandFillFlags; + } else if(HaveScanlineColorExpansion) { + if (infoRec->ScanlineCPUToScreenColorExpandFillFlags & + TRIPLE_BITS_24BPP) { + if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) + infoRec->FillColorExpandSpans = + XAAFillScanlineColorExpandSpans3MSBFirst; + else + infoRec->FillColorExpandSpans = + XAAFillScanlineColorExpandSpans3LSBFirst; + } else { + if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) + infoRec->FillColorExpandSpans = + XAAFillScanlineColorExpandSpansMSBFirst; + else + infoRec->FillColorExpandSpans = + XAAFillScanlineColorExpandSpansLSBFirst; + } + infoRec->FillColorExpandSpansFlags = + infoRec->ScanlineCPUToScreenColorExpandFillFlags; + } + + /**** FillImageWriteRects ****/ + + if(infoRec->FillImageWriteRects) { + XAAMSG("\tDriver provided FillImageWriteRects replacement\n"); + } else if(HaveImageWriteRect && + (infoRec->ImageWriteFlags & LEFT_EDGE_CLIPPING_NEGATIVE_X) && + (infoRec->ImageWriteFlags & LEFT_EDGE_CLIPPING)) { + infoRec->FillImageWriteRects = XAAFillImageWriteRects; + infoRec->FillImageWriteRectsFlags = infoRec->ImageWriteFlags; + } + + /**** WriteBitmap ****/ + + if(infoRec->WriteBitmap && + !xf86ReturnOptValBool(options, XAAOPT_WRITE_BITMAP, FALSE)) { + XAAMSG("\tDriver provided WriteBitmap replacement\n"); + } else if(HaveColorExpansion) { + if (infoRec->CPUToScreenColorExpandFillFlags & TRIPLE_BITS_24BPP) { + if(infoRec->CPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->WriteBitmap = + XAAWriteBitmapColorExpand3MSBFirstFixedBase; + else + infoRec->WriteBitmap = XAAWriteBitmapColorExpand3MSBFirst; + } else { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->WriteBitmap = + XAAWriteBitmapColorExpand3LSBFirstFixedBase; + else + infoRec->WriteBitmap = XAAWriteBitmapColorExpand3LSBFirst; + } + } else { + if(infoRec->CPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->WriteBitmap = + XAAWriteBitmapColorExpandMSBFirstFixedBase; + else + infoRec->WriteBitmap = XAAWriteBitmapColorExpandMSBFirst; + } else { + if(infoRec->CPUToScreenColorExpandFillFlags & + CPU_TRANSFER_BASE_FIXED) + infoRec->WriteBitmap = + XAAWriteBitmapColorExpandLSBFirstFixedBase; + else + infoRec->WriteBitmap = XAAWriteBitmapColorExpandLSBFirst; + } + } + infoRec->WriteBitmapFlags = infoRec->CPUToScreenColorExpandFillFlags; + } else if(HaveScanlineColorExpansion) { + if (infoRec->ScanlineCPUToScreenColorExpandFillFlags & + TRIPLE_BITS_24BPP) { + if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) + infoRec->WriteBitmap = + XAAWriteBitmapScanlineColorExpand3MSBFirst; + else + infoRec->WriteBitmap = + XAAWriteBitmapScanlineColorExpand3LSBFirst; + } else { + if(infoRec->ScanlineCPUToScreenColorExpandFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST) + infoRec->WriteBitmap = + XAAWriteBitmapScanlineColorExpandMSBFirst; + else + infoRec->WriteBitmap = + XAAWriteBitmapScanlineColorExpandLSBFirst; + } + infoRec->WriteBitmapFlags = + infoRec->ScanlineCPUToScreenColorExpandFillFlags; + } else + infoRec->WriteBitmap = NULL; + + /**** TE Glyphs ****/ + + if (infoRec->TEGlyphRenderer) { + XAAMSG("\tDriver provided TEGlyphRenderer replacement\n"); + } else if (HaveColorExpansion) { + infoRec->TEGlyphRendererFlags = + infoRec->CPUToScreenColorExpandFillFlags; + + if (infoRec->TEGlyphRendererFlags & TRIPLE_BITS_24BPP) { + if (infoRec->TEGlyphRendererFlags & BIT_ORDER_IN_BYTE_MSBFIRST) { + if (infoRec->TEGlyphRendererFlags & CPU_TRANSFER_BASE_FIXED) + infoRec->TEGlyphRenderer = + XAATEGlyphRenderer3MSBFirstFixedBase; + else + infoRec->TEGlyphRenderer = XAATEGlyphRenderer3MSBFirst; + } else { + if (infoRec->TEGlyphRendererFlags & CPU_TRANSFER_BASE_FIXED) + infoRec->TEGlyphRenderer = + XAATEGlyphRenderer3LSBFirstFixedBase; + else + infoRec->TEGlyphRenderer = XAATEGlyphRenderer3LSBFirst; + } + + if (!HaveSolidFillRect && + (infoRec->TEGlyphRendererFlags & RGB_EQUAL)) { + infoRec->TEGlyphRendererFlags &= ~RGB_EQUAL; + XAAMSG("WARNING: TEGlyphRenderer cannot support RGB_EQUAL" + " without solid fills\n"); + } + } else { + if (infoRec->TEGlyphRendererFlags & BIT_ORDER_IN_BYTE_MSBFIRST) { + if (infoRec->TEGlyphRendererFlags & CPU_TRANSFER_BASE_FIXED) + infoRec->TEGlyphRenderer = + XAATEGlyphRendererMSBFirstFixedBase; + else + infoRec->TEGlyphRenderer = XAATEGlyphRendererMSBFirst; + } else { + if (infoRec->TEGlyphRendererFlags & CPU_TRANSFER_BASE_FIXED) + infoRec->TEGlyphRenderer = + XAATEGlyphRendererLSBFirstFixedBase; + else + infoRec->TEGlyphRenderer = XAATEGlyphRendererLSBFirst; + } + } + + if (!HaveSolidFillRect && + (infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { + infoRec->TEGlyphRendererFlags &= ~TRANSPARENCY_ONLY; + XAAMSG("WARNING: TEGlyphRenderer cannot support TRANPARENCY_ONLY" + " without solid fills\n"); + } + + } else if (HaveScanlineColorExpansion) { + infoRec->TEGlyphRendererFlags = + infoRec->ScanlineCPUToScreenColorExpandFillFlags; + + if (infoRec->TEGlyphRendererFlags & TRIPLE_BITS_24BPP) { + if (infoRec->TEGlyphRendererFlags & BIT_ORDER_IN_BYTE_MSBFIRST) + infoRec->TEGlyphRenderer = XAATEGlyphRendererScanline3MSBFirst; + else + infoRec->TEGlyphRenderer = XAATEGlyphRendererScanline3LSBFirst; + + if (!HaveSolidFillRect && + (infoRec->TEGlyphRendererFlags & RGB_EQUAL)) { + infoRec->TEGlyphRendererFlags &= ~RGB_EQUAL; + XAAMSG("WARNING: TEGlyphRenderer cannot support RGB_EQUAL" + " without solid fills\n"); + } + } else { + if (infoRec->TEGlyphRendererFlags & BIT_ORDER_IN_BYTE_MSBFIRST) + infoRec->TEGlyphRenderer = XAATEGlyphRendererScanlineMSBFirst; + else + infoRec->TEGlyphRenderer = XAATEGlyphRendererScanlineLSBFirst; + } + + if (!HaveSolidFillRect && + (infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { + infoRec->TEGlyphRendererFlags &= ~TRANSPARENCY_ONLY; + XAAMSG("WARNING: TEGlyphRenderer cannot support TRANPARENCY_ONLY" + " without solid fills\n"); + } + } + + /**** NonTE Glyphs ****/ + + if(infoRec->NonTEGlyphRenderer) { + XAAMSG("\tDriver provided NonTEGlyphRenderer replacement\n"); + } else if(infoRec->WriteBitmap && + !(infoRec->WriteBitmapFlags & NO_TRANSPARENCY)) { + infoRec->NonTEGlyphRenderer = XAANonTEGlyphRenderer; + infoRec->NonTEGlyphRendererFlags = infoRec->WriteBitmapFlags; + } + + /**** WritePixmap ****/ + + if(infoRec->WritePixmap && + !xf86ReturnOptValBool(options, XAAOPT_WRITE_PIXMAP, FALSE)) { + XAAMSG("\tDriver provided WritePixmap replacement\n"); + } else if(HaveImageWriteRect) { + infoRec->WritePixmap = XAAWritePixmap; + infoRec->WritePixmapFlags = + infoRec->ImageWriteFlags | CONVERT_32BPP_TO_24BPP; + } else if(HaveScanlineImageWriteRect) { + infoRec->WritePixmap = XAAWritePixmapScanline; + infoRec->WritePixmapFlags = infoRec->ScanlineImageWriteFlags; + } else + infoRec->WritePixmap = NULL; + + /**** ReadPixmap ****/ + + if(infoRec->ReadPixmap) { + XAAMSG("\tDriver provided ReadPixmap replacement\n"); + } + + + /************** GC Level *************/ + + /**** CopyArea ****/ + + if(infoRec->CopyArea) { + XAAMSG("\tDriver provided GC level CopyArea replacement\n"); + } else if(infoRec->ScreenToScreenBitBlt) { + infoRec->CopyArea = XAACopyArea; + infoRec->CopyAreaFlags = infoRec->ScreenToScreenBitBltFlags; + + /* most GC level primitives use one mid-level primitive so + the GC level primitive gets the mid-level primitive flag + and we use that at GC validation time. But CopyArea uses + more than one mid-level primitive so we have to essentially + do a GC validation every time that primitive is used. + The CopyAreaFlags would only be used for filtering out the + common denominators. Here we assume that if you don't do + ScreenToScreenBitBlt you aren't going to do the others. + We also assume that ScreenToScreenBitBlt has the least + restrictions. */ + } + + if(infoRec->CopyPlane) { + XAAMSG("\tDriver provided GC level CopyPlane replacement\n"); + } else if(infoRec->WriteBitmap && + !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY)) { + infoRec->CopyPlane = XAACopyPlaneColorExpansion; + infoRec->CopyPlaneFlags = infoRec->WriteBitmapFlags; + } + + if(infoRec->PushPixelsSolid) { + XAAMSG("\tDriver provided GC level PushPixelsSolid replacement\n"); + } else if(infoRec->WriteBitmap && + !(infoRec->WriteBitmapFlags & NO_TRANSPARENCY)) { + infoRec->PushPixelsSolid = XAAPushPixelsSolidColorExpansion; + infoRec->PushPixelsFlags = infoRec->WriteBitmapFlags; + } + + if(infoRec->FillSolidRects) { + if(!infoRec->PolyFillRectSolid) { + infoRec->PolyFillRectSolid = XAAPolyFillRect; + infoRec->PolyFillRectSolidFlags = infoRec->FillSolidRectsFlags; + } + } + if(infoRec->FillSolidSpans) { + if(!infoRec->FillSpansSolid) { + infoRec->FillSpansSolid = XAAFillSpans; + infoRec->FillSpansSolidFlags = infoRec->FillSolidSpansFlags; + } + } + + if(infoRec->FillMono8x8PatternRects || infoRec->FillColor8x8PatternRects || + infoRec->FillCacheBltRects || infoRec->FillColorExpandRects || + infoRec->FillCacheExpandRects) { + if(!infoRec->PolyFillRectStippled) { + + infoRec->PolyFillRectStippled = XAAPolyFillRect; + infoRec->PolyFillRectStippledFlags = 0; + } + } + + if(infoRec->FillMono8x8PatternSpans || infoRec->FillColor8x8PatternSpans || + infoRec->FillCacheBltSpans || infoRec->FillColorExpandSpans || + infoRec->FillCacheExpandSpans) { + if(!infoRec->FillSpansStippled) { + + infoRec->FillSpansStippled = XAAFillSpans; + infoRec->FillSpansStippledFlags = 0; + } + } + + if(infoRec->FillMono8x8PatternRects || infoRec->FillColor8x8PatternRects || + infoRec->FillCacheBltRects || infoRec->FillColorExpandRects || + infoRec->FillCacheExpandRects) { + if(!infoRec->PolyFillRectOpaqueStippled) { + + infoRec->PolyFillRectOpaqueStippled = XAAPolyFillRect; + infoRec->PolyFillRectOpaqueStippledFlags = 0; + } + } + + if(infoRec->FillMono8x8PatternSpans || infoRec->FillColor8x8PatternSpans || + infoRec->FillCacheBltSpans || infoRec->FillColorExpandSpans || + infoRec->FillCacheExpandSpans) { + if(!infoRec->FillSpansOpaqueStippled) { + + infoRec->FillSpansOpaqueStippled = XAAFillSpans; + infoRec->FillSpansOpaqueStippledFlags = 0; + } + } + + if(infoRec->FillMono8x8PatternRects || infoRec->FillColor8x8PatternRects || + infoRec->FillCacheBltRects || infoRec->FillImageWriteRects) { + if(!infoRec->PolyFillRectTiled) { + + infoRec->PolyFillRectTiled = XAAPolyFillRect; + infoRec->PolyFillRectTiledFlags = 0; + } + } + + if(infoRec->FillMono8x8PatternSpans || infoRec->FillColor8x8PatternSpans || + infoRec->FillCacheBltSpans) { + if(!infoRec->FillSpansTiled) { + + infoRec->FillSpansTiled = XAAFillSpans; + infoRec->FillSpansTiledFlags = 0; + } + } + + if(infoRec->TEGlyphRenderer && + !(infoRec->TEGlyphRendererFlags & NO_TRANSPARENCY)) { + + if(!infoRec->PolyText8TE) { + infoRec->PolyText8TE = XAAPolyText8TEColorExpansion; + infoRec->PolyText8TEFlags = infoRec->TEGlyphRendererFlags; + } + + if(!infoRec->PolyText16TE) { + infoRec->PolyText16TE = XAAPolyText16TEColorExpansion; + infoRec->PolyText16TEFlags = infoRec->TEGlyphRendererFlags; + } + + if(!infoRec->PolyGlyphBltTE) { + infoRec->PolyGlyphBltTE = XAAPolyGlyphBltTEColorExpansion; + infoRec->PolyGlyphBltTEFlags = infoRec->TEGlyphRendererFlags; + } + } + + if(infoRec->TEGlyphRenderer && + !(infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { + + if(!infoRec->ImageText8TE) { + infoRec->ImageText8TE = XAAImageText8TEColorExpansion; + infoRec->ImageText8TEFlags = infoRec->TEGlyphRendererFlags; + } + + if(!infoRec->ImageText16TE) { + infoRec->ImageText16TE = XAAImageText16TEColorExpansion; + infoRec->ImageText16TEFlags = infoRec->TEGlyphRendererFlags; + } + + if(!infoRec->ImageGlyphBltTE) { + infoRec->ImageGlyphBltTE = XAAImageGlyphBltTEColorExpansion; + infoRec->ImageGlyphBltTEFlags = infoRec->TEGlyphRendererFlags; + } + } + + if(infoRec->NonTEGlyphRenderer) { + if(!infoRec->PolyText8NonTE) { + infoRec->PolyText8NonTE = XAAPolyText8NonTEColorExpansion; + infoRec->PolyText8NonTEFlags = infoRec->NonTEGlyphRendererFlags; + } + + if(!infoRec->PolyText16NonTE) { + infoRec->PolyText16NonTE = XAAPolyText16NonTEColorExpansion; + infoRec->PolyText16NonTEFlags = infoRec->NonTEGlyphRendererFlags; + } + if(!infoRec->PolyGlyphBltNonTE) { + infoRec->PolyGlyphBltNonTE = XAAPolyGlyphBltNonTEColorExpansion; + infoRec->PolyGlyphBltNonTEFlags = infoRec->NonTEGlyphRendererFlags; + } + } + + if(infoRec->NonTEGlyphRenderer && HaveSolidFillRect) { + if(!infoRec->ImageText8NonTE) { + infoRec->ImageText8NonTE = XAAImageText8NonTEColorExpansion; + infoRec->ImageText8NonTEFlags = infoRec->NonTEGlyphRendererFlags; + } + + if(!infoRec->ImageText16NonTE) { + infoRec->ImageText16NonTE = XAAImageText16NonTEColorExpansion; + infoRec->ImageText16NonTEFlags = infoRec->NonTEGlyphRendererFlags; + } + + if(!infoRec->ImageGlyphBltNonTE) { + infoRec->ImageGlyphBltNonTE = XAAImageGlyphBltNonTEColorExpansion; + infoRec->ImageGlyphBltNonTEFlags = infoRec->NonTEGlyphRendererFlags; + } + } + + if(!infoRec->PolyRectangleThinSolid && HaveSolidHorVertLine) { + infoRec->PolyRectangleThinSolid = XAAPolyRectangleThinSolid; + infoRec->PolyRectangleThinSolidFlags = infoRec->SolidLineFlags; + } + + if(!infoRec->FillPolygonSolid && HaveSolidFillRect) { + infoRec->FillPolygonSolid = XAAFillPolygonSolid; + infoRec->FillPolygonSolidFlags = infoRec->SolidFillFlags; + } + + if(!infoRec->FillPolygonStippled && (HaveMono8x8PatternFillRect || + HaveScreenToScreenColorExpandFill || HaveScreenToScreenCopy)) { + infoRec->FillPolygonStippled = XAAFillPolygonStippled; + infoRec->FillPolygonStippledFlags = infoRec->SolidFillFlags; + } + + if(!infoRec->FillPolygonOpaqueStippled && (HaveMono8x8PatternFillRect || + HaveScreenToScreenColorExpandFill || HaveScreenToScreenCopy)) { + infoRec->FillPolygonOpaqueStippled = XAAFillPolygonStippled; + infoRec->FillPolygonOpaqueStippledFlags = infoRec->SolidFillFlags; + } + + if(!infoRec->FillPolygonTiled && (HaveMono8x8PatternFillRect || + HaveScreenToScreenColorExpandFill || HaveScreenToScreenCopy)) { + infoRec->FillPolygonTiled = XAAFillPolygonTiled; + infoRec->FillPolygonTiledFlags = infoRec->SolidFillFlags; + } + + + if(!infoRec->PolyFillArcSolid && HaveSolidFillRect) { + infoRec->PolyFillArcSolid = XAAPolyFillArcSolid; + infoRec->PolyFillArcSolidFlags = infoRec->SolidFillFlags; + } + + if(!infoRec->PolylinesWideSolid && HaveSolidFillRect) { + infoRec->PolylinesWideSolid = XAAPolylinesWideSolid; + infoRec->PolylinesWideSolidFlags = + infoRec->SolidFillFlags | GXCOPY_ONLY; + } + + if(!infoRec->PutImage && (infoRec->WritePixmap || + (infoRec->WriteBitmap && + !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY)))) { + infoRec->PutImage = XAAPutImage; + + /* See comment for CopyArea above. But here we make fewer + assumptions. The driver can provide the PutImageFlags if + it wants too */ + } + + if(HaveSolidHorVertLine && + (HaveSolidBresenhamLine || (HaveSolidTwoPointLine && + (infoRec->ClippingFlags & HARDWARE_CLIP_SOLID_LINE)))){ + if(!infoRec->PolylinesThinSolid) { + infoRec->PolylinesThinSolid = XAAPolyLines; + infoRec->PolylinesThinSolidFlags = infoRec->SolidLineFlags; + } + if(!infoRec->PolySegmentThinSolid) { + infoRec->PolySegmentThinSolid = XAAPolySegment; + infoRec->PolySegmentThinSolidFlags = infoRec->SolidLineFlags; + } + } + + if(HaveDashedBresenhamLine || (HaveDashedTwoPointLine && + (infoRec->ClippingFlags & HARDWARE_CLIP_DASHED_LINE))){ + if(!infoRec->PolylinesThinDashed) { + infoRec->PolylinesThinDashed = XAAPolyLinesDashed; + infoRec->PolylinesThinDashedFlags = infoRec->DashedLineFlags; + } + if(!infoRec->PolySegmentThinDashed) { + infoRec->PolySegmentThinDashed = XAAPolySegmentDashed; + infoRec->PolySegmentThinDashedFlags = infoRec->DashedLineFlags; + } + } + + if(infoRec->PolylinesThinDashed || infoRec->PolySegmentThinDashed) { + if(!infoRec->ComputeDash) + infoRec->ComputeDash = XAAComputeDash; + } + + { + Bool haveTexture = infoRec->CPUToScreenTextureFormats && + infoRec->CPUToScreenTextureDstFormats && + infoRec->SetupForCPUToScreenTexture2 && + infoRec->SubsequentCPUToScreenTexture; + Bool haveAlphaTexture = infoRec->CPUToScreenAlphaTextureFormats && + infoRec->CPUToScreenAlphaTextureDstFormats && + infoRec->SetupForCPUToScreenAlphaTexture2 && + infoRec->SubsequentCPUToScreenAlphaTexture; + + if(!infoRec->Composite && (haveTexture || haveAlphaTexture)) + infoRec->Composite = XAADoComposite; + + if(!infoRec->Glyphs && infoRec->WriteBitmap && + !(infoRec->WriteBitmapFlags & NO_TRANSPARENCY)) + { + infoRec->Glyphs = XAADoGlyphs; + } + } + + /************ Validation Functions **************/ + + if(!infoRec->ValidateCopyArea && infoRec->CopyArea) { + infoRec->CopyAreaMask = GCWhenForced; + if((infoRec->CopyAreaFlags & GXCOPY_ONLY) || + (infoRec->CopyAreaFlags & ROP_NEEDS_SOURCE)) + infoRec->CopyAreaMask |= GCFunction; + if(infoRec->CopyAreaFlags & NO_PLANEMASK) + infoRec->CopyAreaMask |= GCPlaneMask; + infoRec->ValidateCopyArea = XAAValidateCopyArea; + } + + if(!infoRec->ValidateCopyPlane && infoRec->CopyPlane) { + infoRec->CopyPlaneMask = GCWhenForced; + if((infoRec->CopyPlaneFlags & GXCOPY_ONLY) || + (infoRec->CopyPlaneFlags & ROP_NEEDS_SOURCE)) + infoRec->CopyPlaneMask |= GCFunction; + if(infoRec->CopyPlaneFlags & NO_PLANEMASK) + infoRec->CopyPlaneMask |= GCPlaneMask; + if(infoRec->CopyPlaneFlags & RGB_EQUAL) + infoRec->CopyPlaneMask |= GCForeground | GCBackground; + infoRec->ValidateCopyPlane = XAAValidateCopyPlane; + } + + if(!infoRec->ValidatePutImage && infoRec->PutImage) { + infoRec->PutImageMask = GCWhenForced; + if((infoRec->PutImageFlags & GXCOPY_ONLY) || + (infoRec->PutImageFlags & ROP_NEEDS_SOURCE)) + infoRec->PutImageMask |= GCFunction; + if(infoRec->PutImageFlags & NO_PLANEMASK) + infoRec->PutImageMask |= GCPlaneMask; + if(infoRec->PutImageFlags & RGB_EQUAL) + infoRec->PutImageMask |= GCForeground | GCBackground; + infoRec->ValidatePutImage = XAAValidatePutImage; + } + + + if(!infoRec->ValidatePushPixels && infoRec->PushPixelsSolid) { + infoRec->PushPixelsMask = GCFillStyle; + if((infoRec->PushPixelsFlags & GXCOPY_ONLY) || + (infoRec->PushPixelsFlags & ROP_NEEDS_SOURCE) || + (infoRec->PushPixelsFlags & TRANSPARENCY_GXCOPY_ONLY)) + infoRec->PushPixelsMask |= GCFunction; + if(infoRec->PushPixelsFlags & NO_PLANEMASK) + infoRec->PushPixelsMask |= GCPlaneMask; + if(infoRec->PushPixelsFlags & RGB_EQUAL) + infoRec->PushPixelsMask |= GCForeground; + infoRec->ValidatePushPixels = XAAValidatePushPixels; + } + + /* By default XAA assumes the FillSpans, PolyFillRects, FillPolygon + and PolyFillArcs have the same restrictions. If you supply GC + level replacements for any of these and alter this relationship + you may need to supply replacement validation routines */ + + if(!infoRec->ValidateFillSpans && + (infoRec->FillSpansSolid || infoRec->FillSpansStippled || + infoRec->FillSpansOpaqueStippled || infoRec->FillSpansTiled)) { + + int compositeFlags = infoRec->FillSpansSolidFlags | + infoRec->FillSpansStippledFlags | + infoRec->FillSpansOpaqueStippledFlags | + infoRec->FillSpansTiledFlags; + + infoRec->FillSpansMask = GCFillStyle | GCTile | GCStipple; + + if((compositeFlags & GXCOPY_ONLY) || + (compositeFlags & ROP_NEEDS_SOURCE)) + infoRec->FillSpansMask |= GCFunction; + if(compositeFlags & NO_PLANEMASK) + infoRec->FillSpansMask |= GCPlaneMask; + if(compositeFlags & RGB_EQUAL) + infoRec->FillSpansMask |= GCForeground; + infoRec->ValidateFillSpans = XAAValidateFillSpans; + } + + /* By default XAA only provides Validations for the GlyphBlt + functions and not the text higher up. This is because the + Text8/16 and GlyphBlt are linked. If you break this linkage, + you may need to have the driver supply its own Validation + routines */ + + if(!infoRec->ValidatePolyGlyphBlt && + (infoRec->PolyGlyphBltTE || infoRec->PolyGlyphBltNonTE)) { + int compositeFlags = infoRec->PolyGlyphBltTEFlags | + infoRec->PolyGlyphBltNonTEFlags; + + infoRec->PolyGlyphBltMask = GCFillStyle | GCFont; + if((compositeFlags & GXCOPY_ONLY) || + (compositeFlags & ROP_NEEDS_SOURCE) || + (infoRec->PolyGlyphBltNonTEFlags & TRANSPARENCY_GXCOPY_ONLY)) + infoRec->PolyGlyphBltMask |= GCFunction; + if(compositeFlags & NO_PLANEMASK) + infoRec->PolyGlyphBltMask |= GCPlaneMask; + if(compositeFlags & RGB_EQUAL) + infoRec->PolyGlyphBltMask |= GCForeground; + infoRec->ValidatePolyGlyphBlt = XAAValidatePolyGlyphBlt; + } + + if(!infoRec->ValidateImageGlyphBlt && + (infoRec->ImageGlyphBltTE || infoRec->ImageGlyphBltNonTE)) { + int compositeFlags = infoRec->ImageGlyphBltTEFlags | + infoRec->ImageGlyphBltNonTEFlags; + + if(infoRec->ImageGlyphBltNonTE) + compositeFlags |= infoRec->SolidFillFlags; + + infoRec->ImageGlyphBltMask = GCFont; + if(compositeFlags & NO_PLANEMASK) + infoRec->ImageGlyphBltMask |= GCPlaneMask; + if(compositeFlags & RGB_EQUAL) + infoRec->ImageGlyphBltMask |= GCForeground | GCBackground; + infoRec->ValidateImageGlyphBlt = XAAValidateImageGlyphBlt; + } + + /* By default XAA only provides a Validation function for the + Polylines and does segments and polylines at the same time */ + + if(!infoRec->ValidatePolylines && infoRec->ValidateFillSpans) { + int compositeFlags = infoRec->PolyRectangleThinSolidFlags | + infoRec->PolylinesWideSolidFlags | + infoRec->PolylinesThinSolidFlags | + infoRec->PolySegmentThinSolidFlags | + infoRec->PolySegmentThinDashedFlags | + infoRec->PolylinesThinDashedFlags; + + infoRec->ValidatePolylines = XAAValidatePolylines; + infoRec->PolylinesMask = + infoRec->FillSpansMask | GCLineStyle | GCLineWidth; + + if(infoRec->PolySegmentThinDashed || infoRec->PolylinesThinDashed) + infoRec->PolylinesMask |= GCDashList; + if(compositeFlags & NO_PLANEMASK) + infoRec->PolylinesMask |= GCPlaneMask; + if((compositeFlags & GXCOPY_ONLY) || + (compositeFlags & ROP_NEEDS_SOURCE)) + infoRec->PolylinesMask |= GCFunction; + if(compositeFlags & RGB_EQUAL) + infoRec->PolylinesMask |= GCForeground; + } + + + /**** Fill choosers ****/ + + if(!infoRec->StippledFillChooser) + infoRec->StippledFillChooser = XAAStippledFillChooser; + + if(!infoRec->OpaqueStippledFillChooser) + infoRec->OpaqueStippledFillChooser = XAAOpaqueStippledFillChooser; + + if(!infoRec->TiledFillChooser) + infoRec->TiledFillChooser = XAATiledFillChooser; + + + /**** Setup the pixmap cache ****/ + + if(infoRec->WriteBitmapToCache) {} + else if(infoRec->WriteBitmap && + !(infoRec->WriteBitmapFlags & TRANSPARENCY_ONLY)) + infoRec->WriteBitmapToCache = XAAWriteBitmapToCache; + else if(infoRec->Flags & LINEAR_FRAMEBUFFER) + infoRec->WriteBitmapToCache = XAAWriteBitmapToCacheLinear; + else + infoRec->PixmapCacheFlags |= DO_NOT_BLIT_STIPPLES; + + if(infoRec->WritePixmapToCache) {} + else if(infoRec->WritePixmap && !(infoRec->WritePixmapFlags & NO_GXCOPY)) + infoRec->WritePixmapToCache = XAAWritePixmapToCache; + else if(infoRec->Flags & LINEAR_FRAMEBUFFER) + infoRec->WritePixmapToCache = XAAWritePixmapToCacheLinear; + else + infoRec->Flags &= ~PIXMAP_CACHE; + + if (xf86ReturnOptValBool(options, XAAOPT_PIXMAP_CACHE, FALSE)) + infoRec->Flags &= ~PIXMAP_CACHE; + + if(infoRec->WriteMono8x8PatternToCache) {} + else if(infoRec->PixmapCacheFlags & CACHE_MONO_8x8) { + if(infoRec->WritePixmapToCache) + infoRec->WriteMono8x8PatternToCache = XAAWriteMono8x8PatternToCache; + else + infoRec->PixmapCacheFlags &= ~CACHE_MONO_8x8; + } + + if(infoRec->WriteColor8x8PatternToCache) {} + else if(infoRec->PixmapCacheFlags & CACHE_COLOR_8x8) { + if(infoRec->WritePixmapToCache && infoRec->WriteBitmapToCache) + infoRec->WriteColor8x8PatternToCache = XAAWriteColor8x8PatternToCache; + else + infoRec->PixmapCacheFlags &= ~CACHE_COLOR_8x8; + } + + if(infoRec->CachePixelGranularity < 0) { + switch(pScrn->bitsPerPixel) { + case 24: + case 8: infoRec->CachePixelGranularity = 4; break; + case 16: infoRec->CachePixelGranularity = 2; break; + case 32: infoRec->CachePixelGranularity = 1; break; + default: break; + } + + if(BITMAP_SCANLINE_PAD == 64) + infoRec->CachePixelGranularity *= 2; + } + + free(options); + + if(!infoRec->CacheTile && infoRec->WritePixmapToCache) + infoRec->CacheTile = XAACacheTile; + if(!infoRec->CacheMonoStipple && infoRec->WritePixmapToCache) + infoRec->CacheMonoStipple = XAACacheMonoStipple; + if(!infoRec->CacheStipple && infoRec->WriteBitmapToCache) + infoRec->CacheStipple = XAACacheStipple; + if(!infoRec->CacheMono8x8Pattern && infoRec->WriteMono8x8PatternToCache) + infoRec->CacheMono8x8Pattern = XAACacheMono8x8Pattern; + if(!infoRec->CacheColor8x8Pattern && infoRec->WriteColor8x8PatternToCache) + infoRec->CacheColor8x8Pattern = XAACacheColor8x8Pattern; + + if((infoRec->Flags & PIXMAP_CACHE) && !infoRec->InitPixmapCache) { + infoRec->InitPixmapCache = XAAInitPixmapCache; + infoRec->ClosePixmapCache = XAAClosePixmapCache; + } + + return TRUE; +} diff --git a/xorg-server/hw/xfree86/xaa/xaaLineMisc.c b/xorg-server/hw/xfree86/xaa/xaaLineMisc.c index 6cef4bcd5..3e5330fd3 100644 --- a/xorg-server/hw/xfree86/xaa/xaaLineMisc.c +++ b/xorg-server/hw/xfree86/xaa/xaaLineMisc.c @@ -1,151 +1,151 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "miline.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaalocal.h" - - -void -XAASolidHorVertLineAsRects( - ScrnInfoPtr pScrn, - int x, int y, int len, int dir -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - - if(dir == DEGREES_0) - (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, len, 1); - else - (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, 1, len); -} - - -void -XAASolidHorVertLineAsTwoPoint( - ScrnInfoPtr pScrn, - int x, int y, int len, int dir -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - - len--; - - if(dir == DEGREES_0) - (*infoRec->SubsequentSolidTwoPointLine)(pScrn, x, y, x + len, y, 0); - else - (*infoRec->SubsequentSolidTwoPointLine)(pScrn, x, y, x, y + len, 0); -} - -void -XAASolidHorVertLineAsBresenham( - ScrnInfoPtr pScrn, - int x, int y, int len, int dir -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - - if(dir == DEGREES_0) - (*infoRec->SubsequentSolidBresenhamLine)( - pScrn, x, y, len << 1, 0, -len, len, 0); - else - (*infoRec->SubsequentSolidBresenhamLine)( - pScrn, x, y, len << 1, 0, -len, len, YMAJOR); -} - - -void -XAAComputeDash(GCPtr pGC) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - XAAGCPtr pGCPriv = (XAAGCPtr)dixLookupPrivate(&pGC->devPrivates, - XAAGetGCKey()); - Bool EvenDash = (pGC->numInDashList & 0x01) ? FALSE : TRUE; - int PatternLength = 0; - unsigned char* DashPtr = (unsigned char*)pGC->dash; - CARD32 *ptr; - int count = pGC->numInDashList; - int shift, value, direction; - Bool set; - - if(pGCPriv->DashPattern) - xfree(pGCPriv->DashPattern); - - pGCPriv->DashPattern = NULL; - pGCPriv->DashLength = 0; - - while(count--) - PatternLength += *(DashPtr++); - - if(!EvenDash) - PatternLength <<= 1; - - if(PatternLength > infoRec->DashPatternMaxLength) - return; - - if((infoRec->DashedLineFlags & LINE_PATTERN_POWER_OF_2_ONLY) && - (PatternLength & (PatternLength - 1))) - return; - - pGCPriv->DashPattern = xcalloc((PatternLength + 31) >> 5, 4); - if(!pGCPriv->DashPattern) return; - pGCPriv->DashLength = PatternLength; - - if(infoRec->DashedLineFlags & (LINE_PATTERN_LSBFIRST_MSBJUSTIFIED | - LINE_PATTERN_LSBFIRST_LSBJUSTIFIED)) { - direction = 1; - set = TRUE; - DashPtr = (unsigned char*)pGC->dash; - } else { - direction = -1; - set = FALSE; - DashPtr = (unsigned char*)pGC->dash + pGC->numInDashList - 1; - } - - if(infoRec->DashedLineFlags & (LINE_PATTERN_LSBFIRST_MSBJUSTIFIED | - LINE_PATTERN_MSBFIRST_MSBJUSTIFIED)) - shift = 32 - (PatternLength & 31); - else - shift = 0; - - ptr = (CARD32*)(pGCPriv->DashPattern); - -CONCATENATE: - - count = pGC->numInDashList; - - while(count--) { - value = *DashPtr; - DashPtr += direction; - while(value) { - if(value < (32 - shift)) { - if(set) *ptr |= XAAShiftMasks[value] << shift; - shift += value; - break; - } else { - if(set) *ptr |= ~0L << shift; - value -= (32 - shift); - shift = 0; - ptr++; - } - } - if(set) set = FALSE; - else set = TRUE; - } - - if(!EvenDash) { - EvenDash = TRUE; - if(infoRec->DashedLineFlags & (LINE_PATTERN_LSBFIRST_MSBJUSTIFIED | - LINE_PATTERN_LSBFIRST_LSBJUSTIFIED)) - DashPtr = (unsigned char*)pGC->dash; - else - DashPtr = (unsigned char*)pGC->dash + pGC->numInDashList; - goto CONCATENATE; - } -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "miline.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaalocal.h" + + +void +XAASolidHorVertLineAsRects( + ScrnInfoPtr pScrn, + int x, int y, int len, int dir +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + + if(dir == DEGREES_0) + (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, len, 1); + else + (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, 1, len); +} + + +void +XAASolidHorVertLineAsTwoPoint( + ScrnInfoPtr pScrn, + int x, int y, int len, int dir +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + + len--; + + if(dir == DEGREES_0) + (*infoRec->SubsequentSolidTwoPointLine)(pScrn, x, y, x + len, y, 0); + else + (*infoRec->SubsequentSolidTwoPointLine)(pScrn, x, y, x, y + len, 0); +} + +void +XAASolidHorVertLineAsBresenham( + ScrnInfoPtr pScrn, + int x, int y, int len, int dir +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + + if(dir == DEGREES_0) + (*infoRec->SubsequentSolidBresenhamLine)( + pScrn, x, y, len << 1, 0, -len, len, 0); + else + (*infoRec->SubsequentSolidBresenhamLine)( + pScrn, x, y, len << 1, 0, -len, len, YMAJOR); +} + + +void +XAAComputeDash(GCPtr pGC) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + XAAGCPtr pGCPriv = (XAAGCPtr)dixLookupPrivate(&pGC->devPrivates, + XAAGetGCKey()); + Bool EvenDash = (pGC->numInDashList & 0x01) ? FALSE : TRUE; + int PatternLength = 0; + unsigned char* DashPtr = (unsigned char*)pGC->dash; + CARD32 *ptr; + int count = pGC->numInDashList; + int shift, value, direction; + Bool set; + + if(pGCPriv->DashPattern) + free(pGCPriv->DashPattern); + + pGCPriv->DashPattern = NULL; + pGCPriv->DashLength = 0; + + while(count--) + PatternLength += *(DashPtr++); + + if(!EvenDash) + PatternLength <<= 1; + + if(PatternLength > infoRec->DashPatternMaxLength) + return; + + if((infoRec->DashedLineFlags & LINE_PATTERN_POWER_OF_2_ONLY) && + (PatternLength & (PatternLength - 1))) + return; + + pGCPriv->DashPattern = calloc((PatternLength + 31) >> 5, 4); + if(!pGCPriv->DashPattern) return; + pGCPriv->DashLength = PatternLength; + + if(infoRec->DashedLineFlags & (LINE_PATTERN_LSBFIRST_MSBJUSTIFIED | + LINE_PATTERN_LSBFIRST_LSBJUSTIFIED)) { + direction = 1; + set = TRUE; + DashPtr = (unsigned char*)pGC->dash; + } else { + direction = -1; + set = FALSE; + DashPtr = (unsigned char*)pGC->dash + pGC->numInDashList - 1; + } + + if(infoRec->DashedLineFlags & (LINE_PATTERN_LSBFIRST_MSBJUSTIFIED | + LINE_PATTERN_MSBFIRST_MSBJUSTIFIED)) + shift = 32 - (PatternLength & 31); + else + shift = 0; + + ptr = (CARD32*)(pGCPriv->DashPattern); + +CONCATENATE: + + count = pGC->numInDashList; + + while(count--) { + value = *DashPtr; + DashPtr += direction; + while(value) { + if(value < (32 - shift)) { + if(set) *ptr |= XAAShiftMasks[value] << shift; + shift += value; + break; + } else { + if(set) *ptr |= ~0L << shift; + value -= (32 - shift); + shift = 0; + ptr++; + } + } + if(set) set = FALSE; + else set = TRUE; + } + + if(!EvenDash) { + EvenDash = TRUE; + if(infoRec->DashedLineFlags & (LINE_PATTERN_LSBFIRST_MSBJUSTIFIED | + LINE_PATTERN_LSBFIRST_LSBJUSTIFIED)) + DashPtr = (unsigned char*)pGC->dash; + else + DashPtr = (unsigned char*)pGC->dash + pGC->numInDashList; + goto CONCATENATE; + } +} diff --git a/xorg-server/hw/xfree86/xaa/xaaNonTEText.c b/xorg-server/hw/xfree86/xaa/xaaNonTEText.c index d32c0bbc5..eb798a82b 100644 --- a/xorg-server/hw/xfree86/xaa/xaaNonTEText.c +++ b/xorg-server/hw/xfree86/xaa/xaaNonTEText.c @@ -1,591 +1,591 @@ - -/******************************************************************** - - In this file we have GC level replacements for PolyText8/16, - ImageText8/16, ImageGlyphBlt and PolyGlyphBlt for NonTE (proportional) - fonts. The idea is that everything in this file is device independent. - The mentioned GCOps are merely wrappers for the - PolyGlyphBltNonTEColorExpansion and ImageGlyphBltNonTEColorExpansion - functions which calculate the boxes containing arbitrarily clipped - text and passes them to the NonTEGlyphRenderer which will usually - be a lower level XAA function which renders these clipped glyphs using - the basic color expansion functions exported by the chipset driver. - The NonTEGlyphRenderer itself may optionally be driver supplied to - facilitate work-arounds/optimizations at a higher level than usual. - - Written by Mark Vojkovich (mvojkovi@ucsd.edu) - -********************************************************************/ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include <X11/fonts/font.h> -#include "scrnintstr.h" -#include "dixfontstr.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaacexp.h" -#include "xaalocal.h" -#include "gcstruct.h" -#include "pixmapstr.h" - - -static void ImageGlyphBltNonTEColorExpansion(ScrnInfoPtr pScrn, - int xInit, int yInit, FontPtr font, - int fg, int bg, unsigned planemask, - RegionPtr cclip, int nglyph, - unsigned char* gBase, CharInfoPtr *ppci); -static int PolyGlyphBltNonTEColorExpansion(ScrnInfoPtr pScrn, - int xInit, int yInit, FontPtr font, - int fg, int rop, unsigned planemask, - RegionPtr cclip, int nglyph, - unsigned char* gBase, CharInfoPtr *ppci); - -/******************************************************************** - - GC level replacements for PolyText8/16 and ImageText8/16 - for NonTE fonts when using color expansion. - -********************************************************************/ - - -int -XAAPolyText8NonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - char *chars ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - unsigned long n; - int width = 0; - - (*pGC->font->get_glyphs)(pGC->font, (unsigned long)count, - (unsigned char *)chars, Linear8Bit, &n, infoRec->CharInfo); - - if(n) { - width = PolyGlyphBltNonTEColorExpansion( infoRec->pScrn, - x + pDraw->x, y + pDraw->y, pGC->font, - pGC->fgPixel, pGC->alu, pGC->planemask, - pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), - infoRec->CharInfo); - } - - return (x + width); -} - - -int -XAAPolyText16NonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - unsigned long n; - int width = 0; - - (*pGC->font->get_glyphs)( - pGC->font, (unsigned long)count, (unsigned char *)chars, - (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, - &n, infoRec->CharInfo); - - if(n) { - width = PolyGlyphBltNonTEColorExpansion( infoRec->pScrn, - x + pDraw->x, y + pDraw->y, pGC->font, - pGC->fgPixel, pGC->alu, pGC->planemask, - pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), - infoRec->CharInfo); - } - - return (x + width); -} - - -void -XAAImageText8NonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - char *chars -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - unsigned long n; - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - (*pGC->font->get_glyphs)(pGC->font, (unsigned long)count, - (unsigned char *)chars, Linear8Bit, &n, infoRec->CharInfo); - - if(n) ImageGlyphBltNonTEColorExpansion( - infoRec->pScrn, x + pDraw->x, y + pDraw->y, - pGC->font, pGC->fgPixel, pGC->bgPixel, pGC->planemask, - pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); -} - - -void -XAAImageText16NonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - unsigned long n; - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - (*pGC->font->get_glyphs)( - pGC->font, (unsigned long)count, (unsigned char *)chars, - (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, - &n, infoRec->CharInfo); - - if(n) ImageGlyphBltNonTEColorExpansion( - infoRec->pScrn, x + pDraw->x, y + pDraw->y, - pGC->font, pGC->fgPixel, pGC->bgPixel, pGC->planemask, - pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); -} - - - -/******************************************************************** - - GC level replacements for ImageGlyphBlt and PolyGlyphBlt for - NonTE fonts when using color expansion. - -********************************************************************/ - - -void -XAAImageGlyphBltNonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, /* array of character info */ - pointer pglyphBase /* start of array of glyphs */ -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - ImageGlyphBltNonTEColorExpansion( - infoRec->pScrn, xInit + pDraw->x, yInit + pDraw->y, - pGC->font, pGC->fgPixel, pGC->bgPixel, pGC->planemask, - pGC->pCompositeClip, nglyph, (unsigned char*)pglyphBase, ppci); -} - -void -XAAPolyGlyphBltNonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, /* array of character info */ - pointer pglyphBase /* start of array of glyphs */ -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - PolyGlyphBltNonTEColorExpansion( - infoRec->pScrn, xInit + pDraw->x, yInit + pDraw->y, - pGC->font, pGC->fgPixel, pGC->alu, pGC->planemask, - pGC->pCompositeClip, nglyph, (unsigned char*)pglyphBase, ppci); -} - - - - -/******************************************************************** - - ImageGlyphBltNonTEColorExpansion - - PolyGlyphBltNonTEColorExpansion - - - These guys compute the clipped pieces of text and send it to - the lower-level function which will handle acceleration of - arbitrarily clipped text. - -********************************************************************/ - - - -static int -CollectCharacterInfo( - NonTEGlyphPtr glyphs, - unsigned int nglyph, - CharInfoPtr *ppci, - FontPtr pfont -){ - int i, w = 0; - - for(i = 0; i < nglyph; i++, ppci++, glyphs++) { - glyphs->bits = (unsigned char*)((*ppci)->bits); - glyphs->start = w + (*ppci)->metrics.leftSideBearing; - glyphs->end = w + (*ppci)->metrics.rightSideBearing; - glyphs->yoff = (*ppci)->metrics.ascent; - glyphs->height = glyphs->yoff + (*ppci)->metrics.descent; - glyphs->srcwidth = PADGLYPHWIDTHBYTES(glyphs->end - glyphs->start); - w += (*ppci)->metrics.characterWidth; - } - return w; -} - - -static void -PolyGlyphBltAsSingleBitmap ( - ScrnInfoPtr pScrn, - int nglyph, - FontPtr font, - int xInit, - int yInit, - int nbox, - BoxPtr pbox, - int fg, - int rop, - unsigned planemask -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - CARD32 *block, *pntr, *bits; - int pitch, topLine, botLine, top, bot, height; - int Left, Right, Top, Bottom; - int LeftEdge, RightEdge; - int bitPitch, shift, size, i, skippix; - NonTEGlyphPtr glyphs = infoRec->GlyphInfo; - Bool extra; - - Left = xInit + infoRec->GlyphInfo[0].start; - Right = xInit + infoRec->GlyphInfo[nglyph - 1].end; - Top = yInit - FONTMAXBOUNDS(font,ascent); - Bottom = yInit + FONTMAXBOUNDS(font,descent); - - /* get into the first band that may contain part of our string */ - while(nbox && (Top >= pbox->y2)) { - pbox++; nbox--; - } - - if(!nbox) return; - - pitch = (Right - Left + 31) >> 5; - size = (pitch << 2) * (Bottom - Top); - block = xcalloc(1, size); - - topLine = 10000; botLine = -10000; - - while(nglyph--) { - top = -glyphs->yoff; - bot = top + glyphs->height; - if(top < topLine) topLine = top; - if(bot > botLine) botLine = bot; - skippix = glyphs->start - infoRec->GlyphInfo[0].start; - bits = (CARD32*)glyphs->bits; - bitPitch = glyphs->srcwidth >> 2; - pntr = block + ((FONTMAXBOUNDS(font,ascent) + top) * pitch) + - (skippix >> 5); - shift = skippix & 31; - extra = ((shift + glyphs->end - glyphs->start) > 32); - - for(i = top; i < bot; i++) { - *pntr |= SHIFT_L(*bits, shift); - if(extra) - *(pntr + 1) |= SHIFT_R(*bits,32 - shift); - pntr += pitch; - bits += bitPitch; - } - - glyphs++; - } - - pntr = block + ((FONTMAXBOUNDS(font,ascent) + topLine) * pitch); - - Top = yInit + topLine; - Bottom = yInit + botLine; - - while(nbox && (Top >= pbox->y2)) { - pbox++; nbox--; - } - - while(nbox && (Bottom > pbox->y1)) { - LeftEdge = max(Left, pbox->x1); - RightEdge = min(Right, pbox->x2); - - if(RightEdge > LeftEdge) { - skippix = LeftEdge - Left; - topLine = max(Top, pbox->y1); - botLine = min(Bottom, pbox->y2); - height = botLine - topLine; - - if(height > 0) - (*infoRec->WriteBitmap)(pScrn, LeftEdge, topLine, - RightEdge - LeftEdge, height, - (unsigned char*)(pntr + ((topLine - Top) * pitch) + - (skippix >> 5)), - pitch << 2, skippix & 31, fg, -1, rop, planemask); - } - - nbox--; pbox++; - } - - xfree(block); -} - -static void -ImageGlyphBltNonTEColorExpansion( - ScrnInfoPtr pScrn, - int xInit, int yInit, - FontPtr font, - int fg, int bg, - unsigned planemask, - RegionPtr cclip, - int nglyph, - unsigned char* gBase, - CharInfoPtr *ppci -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - int skippix, skipglyph, width, n, i; - int Left, Right, Top, Bottom; - int LeftEdge, RightEdge, ytop, ybot; - int nbox = REGION_NUM_RECTS(cclip); - BoxPtr pbox = REGION_RECTS(cclip); - Bool AlreadySetup = FALSE; - - width = CollectCharacterInfo(infoRec->GlyphInfo, nglyph, ppci, font); - - /* find our backing rectangle dimensions */ - Left = xInit; - Right = Left + width; - Top = yInit - FONTASCENT(font); - Bottom = yInit + FONTDESCENT(font); - - /* get into the first band that may contain part of our box */ - while(nbox && (Top >= pbox->y2)) { - pbox++; nbox--; - } - - while(nbox && (Bottom >= pbox->y1)) { - /* handle backing rect first */ - LeftEdge = max(Left, pbox->x1); - RightEdge = min(Right, pbox->x2); - if(RightEdge > LeftEdge) { - ytop = max(Top, pbox->y1); - ybot = min(Bottom, pbox->y2); - - if(ybot > ytop) { - if(!AlreadySetup) { - (*infoRec->SetupForSolidFill)(pScrn, bg, GXcopy, planemask); - AlreadySetup = TRUE; - } - (*infoRec->SubsequentSolidFillRect)(pScrn, - LeftEdge, ytop, RightEdge - LeftEdge, ybot - ytop); - } - } - nbox--; pbox++; - } - - nbox = REGION_NUM_RECTS(cclip); - pbox = REGION_RECTS(cclip); - - if(infoRec->WriteBitmap && (nglyph > 1) && - ((FONTMAXBOUNDS(font, rightSideBearing) - - FONTMINBOUNDS(font, leftSideBearing)) <= 32)) - { - PolyGlyphBltAsSingleBitmap(pScrn, nglyph, font, - xInit, yInit, nbox, pbox, - fg, GXcopy, planemask); - - return; - } - - /* compute an approximate but covering bounding box */ - Left = xInit + infoRec->GlyphInfo[0].start; - Right = xInit + infoRec->GlyphInfo[nglyph - 1].end; - Top = yInit - FONTMAXBOUNDS(font,ascent); - Bottom = yInit + FONTMAXBOUNDS(font,descent); - - /* get into the first band that may contain part of our box */ - while(nbox && (Top >= pbox->y2)) { - pbox++; nbox--; - } - - /* stop when the lower edge of the box is beyond our string */ - while(nbox && (Bottom >= pbox->y1)) { - LeftEdge = max(Left, pbox->x1); - RightEdge = min(Right, pbox->x2); - - if(RightEdge > LeftEdge) { /* we're possibly drawing something */ - ytop = max(Top, pbox->y1); - ybot = min(Bottom, pbox->y2); - if(ybot > ytop) { - skippix = LeftEdge - xInit; - skipglyph = 0; - while(skippix >= infoRec->GlyphInfo[skipglyph].end) - skipglyph++; - - skippix = RightEdge - xInit; - n = 0; i = skipglyph; - while((i < nglyph) && (skippix > infoRec->GlyphInfo[i].start)) { - i++; n++; - } - - if(n) (*infoRec->NonTEGlyphRenderer)(pScrn, - xInit, yInit, n, infoRec->GlyphInfo + skipglyph, - pbox, fg, GXcopy, planemask); - } - } - - nbox--; pbox++; - } -} - - -static int -PolyGlyphBltNonTEColorExpansion( - ScrnInfoPtr pScrn, - int xInit, int yInit, - FontPtr font, - int fg, int rop, - unsigned planemask, - RegionPtr cclip, - int nglyph, - unsigned char* gBase, - CharInfoPtr *ppci -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - int skippix, skipglyph, width, n, i; - int Left, Right, Top, Bottom; - int LeftEdge, RightEdge; - int nbox = REGION_NUM_RECTS(cclip); - BoxPtr pbox = REGION_RECTS(cclip); - - width = CollectCharacterInfo(infoRec->GlyphInfo, nglyph, ppci, font); - - if(!nbox) - return width; - - if((infoRec->WriteBitmap) && (rop == GXcopy) && (nglyph > 1) && - ((FONTMAXBOUNDS(font, rightSideBearing) - - FONTMINBOUNDS(font, leftSideBearing)) <= 32)) { - - PolyGlyphBltAsSingleBitmap(pScrn, nglyph, font, - xInit, yInit, nbox, pbox, - fg, rop, planemask); - - return width; - } - - /* compute an approximate but covering bounding box */ - Left = xInit + infoRec->GlyphInfo[0].start; - Right = xInit + infoRec->GlyphInfo[nglyph - 1].end; - Top = yInit - FONTMAXBOUNDS(font,ascent); - Bottom = yInit + FONTMAXBOUNDS(font,descent); - - /* get into the first band that may contain part of our string */ - while(nbox && (Top >= pbox->y2)) { - pbox++; nbox--; - } - - /* stop when the lower edge of the box is beyond our string */ - while(nbox && (Bottom >= pbox->y1)) { - LeftEdge = max(Left, pbox->x1); - RightEdge = min(Right, pbox->x2); - - if(RightEdge > LeftEdge) { /* we're possibly drawing something */ - - skippix = LeftEdge - xInit; - skipglyph = 0; - while(skippix >= infoRec->GlyphInfo[skipglyph].end) - skipglyph++; - - skippix = RightEdge - xInit; - n = 0; i = skipglyph; - while((i < nglyph) && (skippix > infoRec->GlyphInfo[i].start)) { - i++; n++; - } - - if(n) (*infoRec->NonTEGlyphRenderer)(pScrn, - xInit, yInit, n, infoRec->GlyphInfo + skipglyph, - pbox, fg, rop, planemask); - } - - nbox--; pbox++; - } - return width; -} - - -/* It is possible that the none of the glyphs passed to the - NonTEGlyphRenderer will be drawn. This function being called - indicates that part of the text string's bounding box is visible - but not necessarily that any of the characters are visible */ - -void XAANonTEGlyphRenderer( - ScrnInfoPtr pScrn, - int x, int y, int n, - NonTEGlyphPtr glyphs, - BoxPtr pbox, - int fg, int rop, - unsigned int planemask -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - int x1, x2, y1, y2, i, w, h, skipleft, skiptop; - unsigned char *src; - - for(i = 0; i < n; i++, glyphs++) { - x1 = x + glyphs->start; - x2 = x + glyphs->end; - y1 = y - glyphs->yoff; - y2 = y1 + glyphs->height; - - if(y1 < pbox->y1) { - skiptop = pbox->y1 - y1; - y1 = pbox->y1; - } else skiptop = 0; - if(y2 > pbox->y2) y2 = pbox->y2; - h = y2 - y1; - if(h <= 0) continue; - - if(x1 < pbox->x1) { - skipleft = pbox->x1 - x1; - x1 = pbox->x1; - } else skipleft = 0; - if(x2 > pbox->x2) x2 = pbox->x2; - - w = x2 - x1; - - if(w > 0) { - src = glyphs->bits + (skiptop * glyphs->srcwidth); - - if(skipleft) { - src += (skipleft >> 5) << 2; - skipleft &= 31; - } - - (*infoRec->WriteBitmap)(pScrn, x1, y1, w, h, src, - glyphs->srcwidth, skipleft, fg, -1, rop, planemask); - } - } - -} + +/******************************************************************** + + In this file we have GC level replacements for PolyText8/16, + ImageText8/16, ImageGlyphBlt and PolyGlyphBlt for NonTE (proportional) + fonts. The idea is that everything in this file is device independent. + The mentioned GCOps are merely wrappers for the + PolyGlyphBltNonTEColorExpansion and ImageGlyphBltNonTEColorExpansion + functions which calculate the boxes containing arbitrarily clipped + text and passes them to the NonTEGlyphRenderer which will usually + be a lower level XAA function which renders these clipped glyphs using + the basic color expansion functions exported by the chipset driver. + The NonTEGlyphRenderer itself may optionally be driver supplied to + facilitate work-arounds/optimizations at a higher level than usual. + + Written by Mark Vojkovich (mvojkovi@ucsd.edu) + +********************************************************************/ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include <X11/fonts/font.h> +#include "scrnintstr.h" +#include "dixfontstr.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaacexp.h" +#include "xaalocal.h" +#include "gcstruct.h" +#include "pixmapstr.h" + + +static void ImageGlyphBltNonTEColorExpansion(ScrnInfoPtr pScrn, + int xInit, int yInit, FontPtr font, + int fg, int bg, unsigned planemask, + RegionPtr cclip, int nglyph, + unsigned char* gBase, CharInfoPtr *ppci); +static int PolyGlyphBltNonTEColorExpansion(ScrnInfoPtr pScrn, + int xInit, int yInit, FontPtr font, + int fg, int rop, unsigned planemask, + RegionPtr cclip, int nglyph, + unsigned char* gBase, CharInfoPtr *ppci); + +/******************************************************************** + + GC level replacements for PolyText8/16 and ImageText8/16 + for NonTE fonts when using color expansion. + +********************************************************************/ + + +int +XAAPolyText8NonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + unsigned long n; + int width = 0; + + (*pGC->font->get_glyphs)(pGC->font, (unsigned long)count, + (unsigned char *)chars, Linear8Bit, &n, infoRec->CharInfo); + + if(n) { + width = PolyGlyphBltNonTEColorExpansion( infoRec->pScrn, + x + pDraw->x, y + pDraw->y, pGC->font, + pGC->fgPixel, pGC->alu, pGC->planemask, + pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), + infoRec->CharInfo); + } + + return (x + width); +} + + +int +XAAPolyText16NonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + unsigned long n; + int width = 0; + + (*pGC->font->get_glyphs)( + pGC->font, (unsigned long)count, (unsigned char *)chars, + (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, + &n, infoRec->CharInfo); + + if(n) { + width = PolyGlyphBltNonTEColorExpansion( infoRec->pScrn, + x + pDraw->x, y + pDraw->y, pGC->font, + pGC->fgPixel, pGC->alu, pGC->planemask, + pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), + infoRec->CharInfo); + } + + return (x + width); +} + + +void +XAAImageText8NonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + unsigned long n; + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + (*pGC->font->get_glyphs)(pGC->font, (unsigned long)count, + (unsigned char *)chars, Linear8Bit, &n, infoRec->CharInfo); + + if(n) ImageGlyphBltNonTEColorExpansion( + infoRec->pScrn, x + pDraw->x, y + pDraw->y, + pGC->font, pGC->fgPixel, pGC->bgPixel, pGC->planemask, + pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); +} + + +void +XAAImageText16NonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + unsigned long n; + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + (*pGC->font->get_glyphs)( + pGC->font, (unsigned long)count, (unsigned char *)chars, + (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, + &n, infoRec->CharInfo); + + if(n) ImageGlyphBltNonTEColorExpansion( + infoRec->pScrn, x + pDraw->x, y + pDraw->y, + pGC->font, pGC->fgPixel, pGC->bgPixel, pGC->planemask, + pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); +} + + + +/******************************************************************** + + GC level replacements for ImageGlyphBlt and PolyGlyphBlt for + NonTE fonts when using color expansion. + +********************************************************************/ + + +void +XAAImageGlyphBltNonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, /* array of character info */ + pointer pglyphBase /* start of array of glyphs */ +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + ImageGlyphBltNonTEColorExpansion( + infoRec->pScrn, xInit + pDraw->x, yInit + pDraw->y, + pGC->font, pGC->fgPixel, pGC->bgPixel, pGC->planemask, + pGC->pCompositeClip, nglyph, (unsigned char*)pglyphBase, ppci); +} + +void +XAAPolyGlyphBltNonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, /* array of character info */ + pointer pglyphBase /* start of array of glyphs */ +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + PolyGlyphBltNonTEColorExpansion( + infoRec->pScrn, xInit + pDraw->x, yInit + pDraw->y, + pGC->font, pGC->fgPixel, pGC->alu, pGC->planemask, + pGC->pCompositeClip, nglyph, (unsigned char*)pglyphBase, ppci); +} + + + + +/******************************************************************** + + ImageGlyphBltNonTEColorExpansion - + PolyGlyphBltNonTEColorExpansion - + + These guys compute the clipped pieces of text and send it to + the lower-level function which will handle acceleration of + arbitrarily clipped text. + +********************************************************************/ + + + +static int +CollectCharacterInfo( + NonTEGlyphPtr glyphs, + unsigned int nglyph, + CharInfoPtr *ppci, + FontPtr pfont +){ + int i, w = 0; + + for(i = 0; i < nglyph; i++, ppci++, glyphs++) { + glyphs->bits = (unsigned char*)((*ppci)->bits); + glyphs->start = w + (*ppci)->metrics.leftSideBearing; + glyphs->end = w + (*ppci)->metrics.rightSideBearing; + glyphs->yoff = (*ppci)->metrics.ascent; + glyphs->height = glyphs->yoff + (*ppci)->metrics.descent; + glyphs->srcwidth = PADGLYPHWIDTHBYTES(glyphs->end - glyphs->start); + w += (*ppci)->metrics.characterWidth; + } + return w; +} + + +static void +PolyGlyphBltAsSingleBitmap ( + ScrnInfoPtr pScrn, + int nglyph, + FontPtr font, + int xInit, + int yInit, + int nbox, + BoxPtr pbox, + int fg, + int rop, + unsigned planemask +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + CARD32 *block, *pntr, *bits; + int pitch, topLine, botLine, top, bot, height; + int Left, Right, Top, Bottom; + int LeftEdge, RightEdge; + int bitPitch, shift, size, i, skippix; + NonTEGlyphPtr glyphs = infoRec->GlyphInfo; + Bool extra; + + Left = xInit + infoRec->GlyphInfo[0].start; + Right = xInit + infoRec->GlyphInfo[nglyph - 1].end; + Top = yInit - FONTMAXBOUNDS(font,ascent); + Bottom = yInit + FONTMAXBOUNDS(font,descent); + + /* get into the first band that may contain part of our string */ + while(nbox && (Top >= pbox->y2)) { + pbox++; nbox--; + } + + if(!nbox) return; + + pitch = (Right - Left + 31) >> 5; + size = (pitch << 2) * (Bottom - Top); + block = calloc(1, size); + + topLine = 10000; botLine = -10000; + + while(nglyph--) { + top = -glyphs->yoff; + bot = top + glyphs->height; + if(top < topLine) topLine = top; + if(bot > botLine) botLine = bot; + skippix = glyphs->start - infoRec->GlyphInfo[0].start; + bits = (CARD32*)glyphs->bits; + bitPitch = glyphs->srcwidth >> 2; + pntr = block + ((FONTMAXBOUNDS(font,ascent) + top) * pitch) + + (skippix >> 5); + shift = skippix & 31; + extra = ((shift + glyphs->end - glyphs->start) > 32); + + for(i = top; i < bot; i++) { + *pntr |= SHIFT_L(*bits, shift); + if(extra) + *(pntr + 1) |= SHIFT_R(*bits,32 - shift); + pntr += pitch; + bits += bitPitch; + } + + glyphs++; + } + + pntr = block + ((FONTMAXBOUNDS(font,ascent) + topLine) * pitch); + + Top = yInit + topLine; + Bottom = yInit + botLine; + + while(nbox && (Top >= pbox->y2)) { + pbox++; nbox--; + } + + while(nbox && (Bottom > pbox->y1)) { + LeftEdge = max(Left, pbox->x1); + RightEdge = min(Right, pbox->x2); + + if(RightEdge > LeftEdge) { + skippix = LeftEdge - Left; + topLine = max(Top, pbox->y1); + botLine = min(Bottom, pbox->y2); + height = botLine - topLine; + + if(height > 0) + (*infoRec->WriteBitmap)(pScrn, LeftEdge, topLine, + RightEdge - LeftEdge, height, + (unsigned char*)(pntr + ((topLine - Top) * pitch) + + (skippix >> 5)), + pitch << 2, skippix & 31, fg, -1, rop, planemask); + } + + nbox--; pbox++; + } + + free(block); +} + +static void +ImageGlyphBltNonTEColorExpansion( + ScrnInfoPtr pScrn, + int xInit, int yInit, + FontPtr font, + int fg, int bg, + unsigned planemask, + RegionPtr cclip, + int nglyph, + unsigned char* gBase, + CharInfoPtr *ppci +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + int skippix, skipglyph, width, n, i; + int Left, Right, Top, Bottom; + int LeftEdge, RightEdge, ytop, ybot; + int nbox = REGION_NUM_RECTS(cclip); + BoxPtr pbox = REGION_RECTS(cclip); + Bool AlreadySetup = FALSE; + + width = CollectCharacterInfo(infoRec->GlyphInfo, nglyph, ppci, font); + + /* find our backing rectangle dimensions */ + Left = xInit; + Right = Left + width; + Top = yInit - FONTASCENT(font); + Bottom = yInit + FONTDESCENT(font); + + /* get into the first band that may contain part of our box */ + while(nbox && (Top >= pbox->y2)) { + pbox++; nbox--; + } + + while(nbox && (Bottom >= pbox->y1)) { + /* handle backing rect first */ + LeftEdge = max(Left, pbox->x1); + RightEdge = min(Right, pbox->x2); + if(RightEdge > LeftEdge) { + ytop = max(Top, pbox->y1); + ybot = min(Bottom, pbox->y2); + + if(ybot > ytop) { + if(!AlreadySetup) { + (*infoRec->SetupForSolidFill)(pScrn, bg, GXcopy, planemask); + AlreadySetup = TRUE; + } + (*infoRec->SubsequentSolidFillRect)(pScrn, + LeftEdge, ytop, RightEdge - LeftEdge, ybot - ytop); + } + } + nbox--; pbox++; + } + + nbox = REGION_NUM_RECTS(cclip); + pbox = REGION_RECTS(cclip); + + if(infoRec->WriteBitmap && (nglyph > 1) && + ((FONTMAXBOUNDS(font, rightSideBearing) - + FONTMINBOUNDS(font, leftSideBearing)) <= 32)) + { + PolyGlyphBltAsSingleBitmap(pScrn, nglyph, font, + xInit, yInit, nbox, pbox, + fg, GXcopy, planemask); + + return; + } + + /* compute an approximate but covering bounding box */ + Left = xInit + infoRec->GlyphInfo[0].start; + Right = xInit + infoRec->GlyphInfo[nglyph - 1].end; + Top = yInit - FONTMAXBOUNDS(font,ascent); + Bottom = yInit + FONTMAXBOUNDS(font,descent); + + /* get into the first band that may contain part of our box */ + while(nbox && (Top >= pbox->y2)) { + pbox++; nbox--; + } + + /* stop when the lower edge of the box is beyond our string */ + while(nbox && (Bottom >= pbox->y1)) { + LeftEdge = max(Left, pbox->x1); + RightEdge = min(Right, pbox->x2); + + if(RightEdge > LeftEdge) { /* we're possibly drawing something */ + ytop = max(Top, pbox->y1); + ybot = min(Bottom, pbox->y2); + if(ybot > ytop) { + skippix = LeftEdge - xInit; + skipglyph = 0; + while(skippix >= infoRec->GlyphInfo[skipglyph].end) + skipglyph++; + + skippix = RightEdge - xInit; + n = 0; i = skipglyph; + while((i < nglyph) && (skippix > infoRec->GlyphInfo[i].start)) { + i++; n++; + } + + if(n) (*infoRec->NonTEGlyphRenderer)(pScrn, + xInit, yInit, n, infoRec->GlyphInfo + skipglyph, + pbox, fg, GXcopy, planemask); + } + } + + nbox--; pbox++; + } +} + + +static int +PolyGlyphBltNonTEColorExpansion( + ScrnInfoPtr pScrn, + int xInit, int yInit, + FontPtr font, + int fg, int rop, + unsigned planemask, + RegionPtr cclip, + int nglyph, + unsigned char* gBase, + CharInfoPtr *ppci +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + int skippix, skipglyph, width, n, i; + int Left, Right, Top, Bottom; + int LeftEdge, RightEdge; + int nbox = REGION_NUM_RECTS(cclip); + BoxPtr pbox = REGION_RECTS(cclip); + + width = CollectCharacterInfo(infoRec->GlyphInfo, nglyph, ppci, font); + + if(!nbox) + return width; + + if((infoRec->WriteBitmap) && (rop == GXcopy) && (nglyph > 1) && + ((FONTMAXBOUNDS(font, rightSideBearing) - + FONTMINBOUNDS(font, leftSideBearing)) <= 32)) { + + PolyGlyphBltAsSingleBitmap(pScrn, nglyph, font, + xInit, yInit, nbox, pbox, + fg, rop, planemask); + + return width; + } + + /* compute an approximate but covering bounding box */ + Left = xInit + infoRec->GlyphInfo[0].start; + Right = xInit + infoRec->GlyphInfo[nglyph - 1].end; + Top = yInit - FONTMAXBOUNDS(font,ascent); + Bottom = yInit + FONTMAXBOUNDS(font,descent); + + /* get into the first band that may contain part of our string */ + while(nbox && (Top >= pbox->y2)) { + pbox++; nbox--; + } + + /* stop when the lower edge of the box is beyond our string */ + while(nbox && (Bottom >= pbox->y1)) { + LeftEdge = max(Left, pbox->x1); + RightEdge = min(Right, pbox->x2); + + if(RightEdge > LeftEdge) { /* we're possibly drawing something */ + + skippix = LeftEdge - xInit; + skipglyph = 0; + while(skippix >= infoRec->GlyphInfo[skipglyph].end) + skipglyph++; + + skippix = RightEdge - xInit; + n = 0; i = skipglyph; + while((i < nglyph) && (skippix > infoRec->GlyphInfo[i].start)) { + i++; n++; + } + + if(n) (*infoRec->NonTEGlyphRenderer)(pScrn, + xInit, yInit, n, infoRec->GlyphInfo + skipglyph, + pbox, fg, rop, planemask); + } + + nbox--; pbox++; + } + return width; +} + + +/* It is possible that the none of the glyphs passed to the + NonTEGlyphRenderer will be drawn. This function being called + indicates that part of the text string's bounding box is visible + but not necessarily that any of the characters are visible */ + +void XAANonTEGlyphRenderer( + ScrnInfoPtr pScrn, + int x, int y, int n, + NonTEGlyphPtr glyphs, + BoxPtr pbox, + int fg, int rop, + unsigned int planemask +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + int x1, x2, y1, y2, i, w, h, skipleft, skiptop; + unsigned char *src; + + for(i = 0; i < n; i++, glyphs++) { + x1 = x + glyphs->start; + x2 = x + glyphs->end; + y1 = y - glyphs->yoff; + y2 = y1 + glyphs->height; + + if(y1 < pbox->y1) { + skiptop = pbox->y1 - y1; + y1 = pbox->y1; + } else skiptop = 0; + if(y2 > pbox->y2) y2 = pbox->y2; + h = y2 - y1; + if(h <= 0) continue; + + if(x1 < pbox->x1) { + skipleft = pbox->x1 - x1; + x1 = pbox->x1; + } else skipleft = 0; + if(x2 > pbox->x2) x2 = pbox->x2; + + w = x2 - x1; + + if(w > 0) { + src = glyphs->bits + (skiptop * glyphs->srcwidth); + + if(skipleft) { + src += (skipleft >> 5) << 2; + skipleft &= 31; + } + + (*infoRec->WriteBitmap)(pScrn, x1, y1, w, h, src, + glyphs->srcwidth, skipleft, fg, -1, rop, planemask); + } + } + +} diff --git a/xorg-server/hw/xfree86/xaa/xaaOffscreen.c b/xorg-server/hw/xfree86/xaa/xaaOffscreen.c index 7c9d53270..41be2b491 100644 --- a/xorg-server/hw/xfree86/xaa/xaaOffscreen.c +++ b/xorg-server/hw/xfree86/xaa/xaaOffscreen.c @@ -1,162 +1,162 @@ - -/* - Copyright (c) 1999 - The XFree86 Project Inc. - - Written by Mark Vojkovich - -*/ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "xf86str.h" -#include "mi.h" -#include "miline.h" -#include "xaa.h" -#include "xaalocal.h" -#include "xaawrap.h" -#include "xf86fbman.h" -#include "servermd.h" - -void -XAAMoveOutOffscreenPixmaps(ScreenPtr pScreen) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - PixmapLinkPtr pLink = infoRec->OffscreenPixmaps; - XAAPixmapPtr pPriv; - - while(pLink) { - pPriv = XAA_GET_PIXMAP_PRIVATE(pLink->pPix); - pLink->area = pPriv->offscreenArea; - XAAMoveOutOffscreenPixmap(pLink->pPix); - pLink = pLink->next; - } -} - - - -void -XAAMoveInOffscreenPixmaps(ScreenPtr pScreen) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - PixmapLinkPtr pLink = infoRec->OffscreenPixmaps; - PixmapPtr pPix, pScreenPix, tmpPix; - pointer data; - XAAPixmapPtr pPriv; - GCPtr pGC; - FBAreaPtr area; - - pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); - - while(pLink) { - pPix = pLink->pPix; - pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); - area = pLink->area; - - data = pPix->devPrivate.ptr; - tmpPix = GetScratchPixmapHeader(pScreen, - pPix->drawable.width, pPix->drawable.height, - pPix->drawable.depth, pPix->drawable.bitsPerPixel, - pPix->devKind, data); - - pPriv->freeData = FALSE; - - pPix->drawable.x = area->box.x1; - pPix->drawable.y = area->box.y1; - pPix->devKind = pScreenPix->devKind; - pPix->devPrivate.ptr = pScreenPix->devPrivate.ptr; - pPix->drawable.bitsPerPixel = infoRec->pScrn->bitsPerPixel; - pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER; - - if(!tmpPix) { - pPriv->offscreenArea = area; - xfree(data); - pLink = pLink->next; - continue; - } - - pGC = GetScratchGC(pPix->drawable.depth, pScreen); - ValidateGC((DrawablePtr)pPix, pGC); - - (*pGC->ops->CopyArea)((DrawablePtr)tmpPix, (DrawablePtr)pPix, pGC, - 0, 0, pPix->drawable.width, pPix->drawable.height, 0, 0); - - xfree(data); - tmpPix->devPrivate.ptr = NULL; - - FreeScratchGC(pGC); - FreeScratchPixmapHeader(tmpPix); - - pPriv->offscreenArea = area; - pLink->area = NULL; - pLink = pLink->next; - } -} - - -void -XAARemoveAreaCallback(FBAreaPtr area) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(area->pScreen); - PixmapPtr pPix = (PixmapPtr)area->devPrivate.ptr; - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); - - XAAMoveOutOffscreenPixmap(pPix); - - pPriv->flags &= ~OFFSCREEN; - - DELIST_OFFSCREEN_PIXMAP(pPix); -} - -void -XAAMoveOutOffscreenPixmap(PixmapPtr pPix) -{ - ScreenPtr pScreen = pPix->drawable.pScreen; - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); - int width, height, devKind, bitsPerPixel; - PixmapPtr tmpPix; - unsigned char *data; - GCPtr pGC; - - width = pPix->drawable.width; - height = pPix->drawable.height; - bitsPerPixel = pPix->drawable.bitsPerPixel; - - devKind = BitmapBytePad(width * bitsPerPixel); - if(!(data = xalloc(devKind * height))) - FatalError("Out of memory\n"); - - tmpPix = GetScratchPixmapHeader(pScreen, width, height, - pPix->drawable.depth, bitsPerPixel, devKind, data); - if(!tmpPix) { - xfree(data); - FatalError("Out of memory\n"); - } - - pGC = GetScratchGC(pPix->drawable.depth, pScreen); - ValidateGC((DrawablePtr)tmpPix, pGC); - - (*pGC->ops->CopyArea)((DrawablePtr)pPix, (DrawablePtr)tmpPix, - pGC, 0, 0, width, height, 0, 0); - - FreeScratchGC(pGC); - FreeScratchPixmapHeader(tmpPix); - - pPix->drawable.x = 0; - pPix->drawable.y = 0; - pPix->devKind = devKind; - pPix->devPrivate.ptr = data; - pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER; - - pPriv->offscreenArea = NULL; - pPriv->freeData = TRUE; -} + +/* + Copyright (c) 1999 - The XFree86 Project Inc. + + Written by Mark Vojkovich + +*/ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "xf86str.h" +#include "mi.h" +#include "miline.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xaawrap.h" +#include "xf86fbman.h" +#include "servermd.h" + +void +XAAMoveOutOffscreenPixmaps(ScreenPtr pScreen) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + PixmapLinkPtr pLink = infoRec->OffscreenPixmaps; + XAAPixmapPtr pPriv; + + while(pLink) { + pPriv = XAA_GET_PIXMAP_PRIVATE(pLink->pPix); + pLink->area = pPriv->offscreenArea; + XAAMoveOutOffscreenPixmap(pLink->pPix); + pLink = pLink->next; + } +} + + + +void +XAAMoveInOffscreenPixmaps(ScreenPtr pScreen) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + PixmapLinkPtr pLink = infoRec->OffscreenPixmaps; + PixmapPtr pPix, pScreenPix, tmpPix; + pointer data; + XAAPixmapPtr pPriv; + GCPtr pGC; + FBAreaPtr area; + + pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); + + while(pLink) { + pPix = pLink->pPix; + pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); + area = pLink->area; + + data = pPix->devPrivate.ptr; + tmpPix = GetScratchPixmapHeader(pScreen, + pPix->drawable.width, pPix->drawable.height, + pPix->drawable.depth, pPix->drawable.bitsPerPixel, + pPix->devKind, data); + + pPriv->freeData = FALSE; + + pPix->drawable.x = area->box.x1; + pPix->drawable.y = area->box.y1; + pPix->devKind = pScreenPix->devKind; + pPix->devPrivate.ptr = pScreenPix->devPrivate.ptr; + pPix->drawable.bitsPerPixel = infoRec->pScrn->bitsPerPixel; + pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + if(!tmpPix) { + pPriv->offscreenArea = area; + free(data); + pLink = pLink->next; + continue; + } + + pGC = GetScratchGC(pPix->drawable.depth, pScreen); + ValidateGC((DrawablePtr)pPix, pGC); + + (*pGC->ops->CopyArea)((DrawablePtr)tmpPix, (DrawablePtr)pPix, pGC, + 0, 0, pPix->drawable.width, pPix->drawable.height, 0, 0); + + free(data); + tmpPix->devPrivate.ptr = NULL; + + FreeScratchGC(pGC); + FreeScratchPixmapHeader(tmpPix); + + pPriv->offscreenArea = area; + pLink->area = NULL; + pLink = pLink->next; + } +} + + +void +XAARemoveAreaCallback(FBAreaPtr area) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(area->pScreen); + PixmapPtr pPix = (PixmapPtr)area->devPrivate.ptr; + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); + + XAAMoveOutOffscreenPixmap(pPix); + + pPriv->flags &= ~OFFSCREEN; + + DELIST_OFFSCREEN_PIXMAP(pPix); +} + +void +XAAMoveOutOffscreenPixmap(PixmapPtr pPix) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPix); + int width, height, devKind, bitsPerPixel; + PixmapPtr tmpPix; + unsigned char *data; + GCPtr pGC; + + width = pPix->drawable.width; + height = pPix->drawable.height; + bitsPerPixel = pPix->drawable.bitsPerPixel; + + devKind = BitmapBytePad(width * bitsPerPixel); + if(!(data = malloc(devKind * height))) + FatalError("Out of memory\n"); + + tmpPix = GetScratchPixmapHeader(pScreen, width, height, + pPix->drawable.depth, bitsPerPixel, devKind, data); + if(!tmpPix) { + free(data); + FatalError("Out of memory\n"); + } + + pGC = GetScratchGC(pPix->drawable.depth, pScreen); + ValidateGC((DrawablePtr)tmpPix, pGC); + + (*pGC->ops->CopyArea)((DrawablePtr)pPix, (DrawablePtr)tmpPix, + pGC, 0, 0, width, height, 0, 0); + + FreeScratchGC(pGC); + FreeScratchPixmapHeader(tmpPix); + + pPix->drawable.x = 0; + pPix->drawable.y = 0; + pPix->devKind = devKind; + pPix->devPrivate.ptr = data; + pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + pPriv->offscreenArea = NULL; + pPriv->freeData = TRUE; +} diff --git a/xorg-server/hw/xfree86/xaa/xaaOverlay.c b/xorg-server/hw/xfree86/xaa/xaaOverlay.c index 2956a3dbf..b7122a58f 100644 --- a/xorg-server/hw/xfree86/xaa/xaaOverlay.c +++ b/xorg-server/hw/xfree86/xaa/xaaOverlay.c @@ -1,129 +1,129 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "windowstr.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaalocal.h" -#include "xaawrap.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "mioverlay.h" - -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif - -static void -XAACopyWindow8_32( - WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc -){ - DDXPointPtr pptSrc, ppt; - RegionRec rgnDst; - BoxPtr pbox; - int dx, dy, nbox; - WindowPtr pwinRoot; - ScreenPtr pScreen = pWin->drawable.pScreen; - XAAInfoRecPtr infoRec = - GET_XAAINFORECPTR_FROM_DRAWABLE((&pWin->drawable)); - Bool doUnderlay = miOverlayCopyUnderlay(pScreen); - RegionPtr borderClip = &pWin->borderClip; - Bool freeReg = FALSE; - - if (!infoRec->pScrn->vtSema || !infoRec->ScreenToScreenBitBlt || - (infoRec->ScreenToScreenBitBltFlags & NO_PLANEMASK)) - { - XAA_SCREEN_PROLOGUE (pScreen, CopyWindow); - if(infoRec->pScrn->vtSema && infoRec->NeedToSync) { - (*infoRec->Sync)(infoRec->pScrn); - infoRec->NeedToSync = FALSE; - } - (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc); - XAA_SCREEN_EPILOGUE (pScreen, CopyWindow, XAACopyWindow8_32); - return; - } - - pwinRoot = WindowTable[pScreen->myNum]; - - if(doUnderlay) - freeReg = miOverlayCollectUnderlayRegions(pWin, &borderClip); - - REGION_NULL(pScreen, &rgnDst); - - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); - REGION_INTERSECT(pScreen, &rgnDst, borderClip, prgnSrc); - - pbox = REGION_RECTS(&rgnDst); - nbox = REGION_NUM_RECTS(&rgnDst); - if(!nbox || - !(pptSrc = (DDXPointPtr )xalloc(nbox * sizeof(DDXPointRec)))) { - REGION_UNINIT(pScreen, &rgnDst); - return; - } - ppt = pptSrc; - - while(nbox--) { - ppt->x = pbox->x1 + dx; - ppt->y = pbox->y1 + dy; - ppt++; pbox++; - } - - infoRec->ScratchGC.planemask = doUnderlay ? 0x00ffffff : 0xff000000; - infoRec->ScratchGC.alu = GXcopy; - - XAADoBitBlt((DrawablePtr)pwinRoot, (DrawablePtr)pwinRoot, - &(infoRec->ScratchGC), &rgnDst, pptSrc); - - xfree(pptSrc); - REGION_UNINIT(pScreen, &rgnDst); - if(freeReg) - REGION_DESTROY(pScreen, borderClip); -} - -static void -XAASetColorKey8_32( - ScreenPtr pScreen, - int nbox, - BoxPtr pbox -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - ScrnInfoPtr pScrn = infoRec->pScrn; - - /* I'm counting on writes being clipped away while switched away. - If this isn't going to be true then I need to be wrapping instead. */ - if(!infoRec->pScrn->vtSema) return; - - (*infoRec->FillSolidRects)(pScrn, pScrn->colorKey << 24, GXcopy, - 0xff000000, nbox, pbox); - - SET_SYNC_FLAG(infoRec); -} - -void -XAASetupOverlay8_32Planar(ScreenPtr pScreen) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - int i; - - pScreen->CopyWindow = XAACopyWindow8_32; - - if(!(infoRec->FillSolidRectsFlags & NO_PLANEMASK)) - miOverlaySetTransFunction(pScreen, XAASetColorKey8_32); - - infoRec->FullPlanemask = ~0; - for(i = 0; i < 32; i++) /* haven't thought about this much */ - infoRec->FullPlanemasks[i] = ~0; -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "windowstr.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xaawrap.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "mioverlay.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +static void +XAACopyWindow8_32( + WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc +){ + DDXPointPtr pptSrc, ppt; + RegionRec rgnDst; + BoxPtr pbox; + int dx, dy, nbox; + WindowPtr pwinRoot; + ScreenPtr pScreen = pWin->drawable.pScreen; + XAAInfoRecPtr infoRec = + GET_XAAINFORECPTR_FROM_DRAWABLE((&pWin->drawable)); + Bool doUnderlay = miOverlayCopyUnderlay(pScreen); + RegionPtr borderClip = &pWin->borderClip; + Bool freeReg = FALSE; + + if (!infoRec->pScrn->vtSema || !infoRec->ScreenToScreenBitBlt || + (infoRec->ScreenToScreenBitBltFlags & NO_PLANEMASK)) + { + XAA_SCREEN_PROLOGUE (pScreen, CopyWindow); + if(infoRec->pScrn->vtSema && infoRec->NeedToSync) { + (*infoRec->Sync)(infoRec->pScrn); + infoRec->NeedToSync = FALSE; + } + (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc); + XAA_SCREEN_EPILOGUE (pScreen, CopyWindow, XAACopyWindow8_32); + return; + } + + pwinRoot = WindowTable[pScreen->myNum]; + + if(doUnderlay) + freeReg = miOverlayCollectUnderlayRegions(pWin, &borderClip); + + REGION_NULL(pScreen, &rgnDst); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + REGION_INTERSECT(pScreen, &rgnDst, borderClip, prgnSrc); + + pbox = REGION_RECTS(&rgnDst); + nbox = REGION_NUM_RECTS(&rgnDst); + if(!nbox || + !(pptSrc = (DDXPointPtr )malloc(nbox * sizeof(DDXPointRec)))) { + REGION_UNINIT(pScreen, &rgnDst); + return; + } + ppt = pptSrc; + + while(nbox--) { + ppt->x = pbox->x1 + dx; + ppt->y = pbox->y1 + dy; + ppt++; pbox++; + } + + infoRec->ScratchGC.planemask = doUnderlay ? 0x00ffffff : 0xff000000; + infoRec->ScratchGC.alu = GXcopy; + + XAADoBitBlt((DrawablePtr)pwinRoot, (DrawablePtr)pwinRoot, + &(infoRec->ScratchGC), &rgnDst, pptSrc); + + free(pptSrc); + REGION_UNINIT(pScreen, &rgnDst); + if(freeReg) + REGION_DESTROY(pScreen, borderClip); +} + +static void +XAASetColorKey8_32( + ScreenPtr pScreen, + int nbox, + BoxPtr pbox +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + ScrnInfoPtr pScrn = infoRec->pScrn; + + /* I'm counting on writes being clipped away while switched away. + If this isn't going to be true then I need to be wrapping instead. */ + if(!infoRec->pScrn->vtSema) return; + + (*infoRec->FillSolidRects)(pScrn, pScrn->colorKey << 24, GXcopy, + 0xff000000, nbox, pbox); + + SET_SYNC_FLAG(infoRec); +} + +void +XAASetupOverlay8_32Planar(ScreenPtr pScreen) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + int i; + + pScreen->CopyWindow = XAACopyWindow8_32; + + if(!(infoRec->FillSolidRectsFlags & NO_PLANEMASK)) + miOverlaySetTransFunction(pScreen, XAASetColorKey8_32); + + infoRec->FullPlanemask = ~0; + for(i = 0; i < 32; i++) /* haven't thought about this much */ + infoRec->FullPlanemasks[i] = ~0; +} diff --git a/xorg-server/hw/xfree86/xaa/xaaOverlayDF.c b/xorg-server/hw/xfree86/xaa/xaaOverlayDF.c index 8db816e1e..4548935fd 100644 --- a/xorg-server/hw/xfree86/xaa/xaaOverlayDF.c +++ b/xorg-server/hw/xfree86/xaa/xaaOverlayDF.c @@ -1,1050 +1,1050 @@ -/* - Copyright (c) 1999 - The XFree86 Project Inc. - - Written by Mark Vojkovich -*/ - - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "xf86str.h" -#include "mi.h" -#include "miline.h" -#include "xaa.h" -#include "xaalocal.h" -#include "xaawrap.h" -#include "servermd.h" - -/* Screen funcs */ - -static void XAAOverCopyWindow(WindowPtr, DDXPointRec, RegionPtr); -static void XAAOverWindowExposures(WindowPtr, RegionPtr, RegionPtr); - -static int XAAOverStippledFillChooser(GCPtr); -static int XAAOverOpaqueStippledFillChooser(GCPtr); -static int XAAOverTiledFillChooser(GCPtr); - -/* GC funcs */ - -static RegionPtr XAAOverCopyArea(DrawablePtr, DrawablePtr, GC *, - int, int, int, int, int, int); -static RegionPtr XAAOverCopyPlane(DrawablePtr, DrawablePtr, GCPtr, - int, int, int, int, int, int, unsigned long); -static void XAAOverPushPixelsSolid(GCPtr, PixmapPtr, DrawablePtr, int, - int, int, int); -static void XAAOverPolyFillRectSolid(DrawablePtr, GCPtr, int, xRectangle*); -static void XAAOverPolyFillRectStippled(DrawablePtr, GCPtr, int, xRectangle*); -static void XAAOverPolyFillRectOpaqueStippled(DrawablePtr, GCPtr, - int, xRectangle*); -static void XAAOverPolyFillRectTiled(DrawablePtr, GCPtr, int, xRectangle*); -static void XAAOverFillSpansSolid(DrawablePtr, GCPtr, int, DDXPointPtr, - int*, int); -static void XAAOverFillSpansStippled(DrawablePtr, GCPtr, int, DDXPointPtr, - int*, int); -static void XAAOverFillSpansOpaqueStippled(DrawablePtr, GCPtr, int, - DDXPointPtr, int*, int); -static void XAAOverFillSpansTiled(DrawablePtr, GCPtr, int, DDXPointPtr, - int*, int); -static int XAAOverPolyText8TE(DrawablePtr, GCPtr, int, int, int, char *); -static int XAAOverPolyText16TE(DrawablePtr, GCPtr, int, int, int, - unsigned short*); -static void XAAOverImageText8TE(DrawablePtr, GCPtr, int, int, int, char*); -static void XAAOverImageText16TE(DrawablePtr, GCPtr, int, int, int, - unsigned short*); -static void XAAOverImageGlyphBltTE(DrawablePtr, GCPtr, int, int, - unsigned int, CharInfoPtr*, pointer); -static void XAAOverPolyGlyphBltTE(DrawablePtr, GCPtr, int, int, - unsigned int, CharInfoPtr*, pointer); -static int XAAOverPolyText8NonTE(DrawablePtr, GCPtr, int, int, int, char*); -static int XAAOverPolyText16NonTE(DrawablePtr, GCPtr, int, int, int, - unsigned short*); -static void XAAOverImageText8NonTE(DrawablePtr, GCPtr, int, int, int, char*); -static void XAAOverImageText16NonTE(DrawablePtr, GCPtr, int, int, int, - unsigned short*); -static void XAAOverImageGlyphBltNonTE(DrawablePtr, GCPtr, int, int, - unsigned int, CharInfoPtr *, pointer); -static void XAAOverPolyGlyphBltNonTE(DrawablePtr, GCPtr, int, int, - unsigned int, CharInfoPtr *, pointer); -static void XAAOverPolyRectangleThinSolid(DrawablePtr, GCPtr, int, xRectangle*); -static void XAAOverPolylinesWideSolid(DrawablePtr, GCPtr, int, int, - DDXPointPtr); -static void XAAOverPolylinesThinSolid(DrawablePtr, GCPtr, int, int, - DDXPointPtr); -static void XAAOverPolySegmentThinSolid(DrawablePtr, GCPtr, int, xSegment*); -static void XAAOverPolylinesThinDashed(DrawablePtr, GCPtr, int, int, - DDXPointPtr); -static void XAAOverPolySegmentThinDashed(DrawablePtr, GCPtr, int, xSegment*); -static void XAAOverFillPolygonSolid(DrawablePtr, GCPtr, int, int, int, - DDXPointPtr); -static void XAAOverFillPolygonStippled(DrawablePtr, GCPtr, int, int, int, - DDXPointPtr); -static void XAAOverFillPolygonOpaqueStippled(DrawablePtr, GCPtr, int, int, int, - DDXPointPtr); -static void XAAOverFillPolygonTiled(DrawablePtr, GCPtr, int, int, int, - DDXPointPtr); -static void XAAOverPolyFillArcSolid(DrawablePtr, GCPtr, int, xArc*); -static void XAAOverPutImage(DrawablePtr, GCPtr, int, int, int, int, int, - int, int, char*); - - -typedef struct { - ScrnInfoPtr pScrn; - DepthChangeFuncPtr callback; - int currentDepth; -/* GC funcs */ - RegionPtr (*CopyArea)(DrawablePtr, DrawablePtr, GC *, - int, int, int, int, int, int); - RegionPtr (*CopyPlane)(DrawablePtr, DrawablePtr, GCPtr, - int, int, int, int, int, int, unsigned long); - void (*PushPixelsSolid)(GCPtr, PixmapPtr, DrawablePtr, int, int, int, int); - void (*PolyFillRectSolid)(DrawablePtr, GCPtr, int, xRectangle*); - void (*PolyFillRectStippled)(DrawablePtr, GCPtr, int, xRectangle*); - void (*PolyFillRectOpaqueStippled)(DrawablePtr, GCPtr, int, xRectangle*); - void (*PolyFillRectTiled)(DrawablePtr, GCPtr, int, xRectangle*); - void (*FillSpansSolid)(DrawablePtr, GCPtr, int, DDXPointPtr, int*, int); - void (*FillSpansStippled)(DrawablePtr, GCPtr, int, DDXPointPtr, int*, int); - void (*FillSpansOpaqueStippled)(DrawablePtr,GCPtr,int,DDXPointPtr,int*,int); - void (*FillSpansTiled)(DrawablePtr, GCPtr, int, DDXPointPtr, int*, int); - int (*PolyText8TE)(DrawablePtr, GCPtr, int, int, int, char *); - int (*PolyText16TE)(DrawablePtr, GCPtr, int, int, int, unsigned short*); - void (*ImageText8TE)(DrawablePtr, GCPtr, int, int, int, char*); - void (*ImageText16TE)(DrawablePtr, GCPtr, int, int, int, unsigned short*); - void (*ImageGlyphBltTE)(DrawablePtr, GCPtr, int, int, unsigned int, - CharInfoPtr*, pointer); - void (*PolyGlyphBltTE)(DrawablePtr, GCPtr, int, int, unsigned int, - CharInfoPtr*, pointer); - int (*PolyText8NonTE)(DrawablePtr, GCPtr, int, int, int, char*); - int (*PolyText16NonTE)(DrawablePtr, GCPtr, int, int, int, unsigned short*); - void (*ImageText8NonTE)(DrawablePtr, GCPtr, int, int, int, char*); - void (*ImageText16NonTE)(DrawablePtr, GCPtr, int, int, int, unsigned short*); - void (*ImageGlyphBltNonTE)(DrawablePtr, GCPtr, int, int, unsigned int, - CharInfoPtr *, pointer); - void (*PolyGlyphBltNonTE)(DrawablePtr, GCPtr, int, int, unsigned int, - CharInfoPtr *, pointer); - void (*PolyRectangleThinSolid)(DrawablePtr, GCPtr, int, xRectangle*); - void (*PolylinesWideSolid)(DrawablePtr, GCPtr, int, int, DDXPointPtr); - - void (*PolylinesThinSolid)(DrawablePtr, GCPtr, int, int, DDXPointPtr); - void (*PolySegmentThinSolid)(DrawablePtr, GCPtr, int, xSegment*); - void (*PolylinesThinDashed)(DrawablePtr, GCPtr, int, int, DDXPointPtr); - void (*PolySegmentThinDashed)(DrawablePtr, GCPtr, int, xSegment*); - void (*FillPolygonSolid)(DrawablePtr, GCPtr, int, int, int, DDXPointPtr); - void (*FillPolygonStippled)(DrawablePtr, GCPtr, int, int, int, DDXPointPtr); - void (*FillPolygonOpaqueStippled)(DrawablePtr, GCPtr, int, int, int, - DDXPointPtr); - void (*FillPolygonTiled)(DrawablePtr, GCPtr, int, int, int, DDXPointPtr); - void (*PolyFillArcSolid)(DrawablePtr, GCPtr, int, xArc*); - void (*PutImage)(DrawablePtr, GCPtr, int, int, int, int, int, int, - int, char*); - int (*StippledFillChooser)(GCPtr); - int (*OpaqueStippledFillChooser)(GCPtr); - int (*TiledFillChooser)(GCPtr); -} XAAOverlayRec, *XAAOverlayPtr; - -static int XAAOverlayKeyIndex; -static DevPrivateKey XAAOverlayKey = &XAAOverlayKeyIndex; - -#define GET_OVERLAY_PRIV(pScreen) \ - (XAAOverlayPtr)dixLookupPrivate(&(pScreen)->devPrivates, XAAOverlayKey) - -#define SWITCH_DEPTH(d) \ - if(pOverPriv->currentDepth != d) { \ - (*pOverPriv->callback)(pOverPriv->pScrn, d); \ - pOverPriv->currentDepth = d; \ - } - - -Bool -XAAInitDualFramebufferOverlay( - ScreenPtr pScreen, - DepthChangeFuncPtr callback -){ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - XAAOverlayPtr pOverPriv; - - if(!(pOverPriv = xalloc(sizeof(XAAOverlayRec)))) - return FALSE; - - dixSetPrivate(&pScreen->devPrivates, XAAOverlayKey, pOverPriv); - - pOverPriv->pScrn = pScrn; - pOverPriv->callback = callback; - pOverPriv->currentDepth = -1; - - /* Overwrite key screen functions. The XAA core will clean up */ - - pScreen->CopyWindow = XAAOverCopyWindow; - pScreen->WindowExposures = XAAOverWindowExposures; - - pOverPriv->StippledFillChooser = infoRec->StippledFillChooser; - pOverPriv->OpaqueStippledFillChooser = infoRec->OpaqueStippledFillChooser; - pOverPriv->TiledFillChooser = infoRec->TiledFillChooser; - - infoRec->StippledFillChooser = XAAOverStippledFillChooser; - infoRec->OpaqueStippledFillChooser = XAAOverOpaqueStippledFillChooser; - infoRec->TiledFillChooser = XAAOverTiledFillChooser; - - /* wrap all XAA GC rendering */ - - pOverPriv->CopyArea = infoRec->CopyArea; - pOverPriv->CopyPlane = infoRec->CopyPlane; - pOverPriv->PushPixelsSolid = infoRec->PushPixelsSolid; - pOverPriv->PolyFillRectSolid = infoRec->PolyFillRectSolid; - pOverPriv->PolyFillRectStippled = infoRec->PolyFillRectStippled; - pOverPriv->PolyFillRectOpaqueStippled = infoRec->PolyFillRectOpaqueStippled; - pOverPriv->PolyFillRectTiled = infoRec->PolyFillRectTiled; - pOverPriv->FillSpansSolid = infoRec->FillSpansSolid; - pOverPriv->FillSpansStippled = infoRec->FillSpansStippled; - pOverPriv->FillSpansOpaqueStippled = infoRec->FillSpansOpaqueStippled; - pOverPriv->FillSpansTiled = infoRec->FillSpansTiled; - pOverPriv->PolyText8TE = infoRec->PolyText8TE; - pOverPriv->PolyText16TE = infoRec->PolyText16TE; - pOverPriv->ImageText8TE = infoRec->ImageText8TE; - pOverPriv->ImageText16TE = infoRec->ImageText16TE; - pOverPriv->ImageGlyphBltTE = infoRec->ImageGlyphBltTE; - pOverPriv->PolyGlyphBltTE = infoRec->PolyGlyphBltTE; - pOverPriv->PolyText8NonTE = infoRec->PolyText8NonTE; - pOverPriv->PolyText16NonTE = infoRec->PolyText16NonTE; - pOverPriv->ImageText8NonTE = infoRec->ImageText8NonTE; - pOverPriv->ImageText16NonTE = infoRec->ImageText16NonTE; - pOverPriv->ImageGlyphBltNonTE = infoRec->ImageGlyphBltNonTE; - pOverPriv->PolyGlyphBltNonTE = infoRec->PolyGlyphBltNonTE; - pOverPriv->PolyRectangleThinSolid = infoRec->PolyRectangleThinSolid; - pOverPriv->PolylinesWideSolid = infoRec->PolylinesWideSolid; - pOverPriv->PolylinesThinSolid = infoRec->PolylinesThinSolid; - pOverPriv->PolySegmentThinSolid = infoRec->PolySegmentThinSolid; - pOverPriv->PolylinesThinDashed = infoRec->PolylinesThinDashed; - pOverPriv->PolySegmentThinDashed = infoRec->PolySegmentThinDashed; - pOverPriv->FillPolygonSolid = infoRec->FillPolygonSolid; - pOverPriv->FillPolygonStippled = infoRec->FillPolygonStippled; - pOverPriv->FillPolygonOpaqueStippled = infoRec->FillPolygonOpaqueStippled; - pOverPriv->FillPolygonTiled = infoRec->FillPolygonTiled; - pOverPriv->PolyFillArcSolid = infoRec->PolyFillArcSolid; - pOverPriv->PutImage = infoRec->PutImage; - - - if(infoRec->CopyArea) - infoRec->CopyArea = XAAOverCopyArea; - if(infoRec->CopyPlane) - infoRec->CopyPlane = XAAOverCopyPlane; - if(infoRec->PushPixelsSolid) - infoRec->PushPixelsSolid = XAAOverPushPixelsSolid; - if(infoRec->PolyFillRectSolid) - infoRec->PolyFillRectSolid = XAAOverPolyFillRectSolid; - if(infoRec->PolyFillRectStippled) - infoRec->PolyFillRectStippled = XAAOverPolyFillRectStippled; - if(infoRec->PolyFillRectOpaqueStippled) - infoRec->PolyFillRectOpaqueStippled = XAAOverPolyFillRectOpaqueStippled; - if(infoRec->PolyFillRectTiled) - infoRec->PolyFillRectTiled = XAAOverPolyFillRectTiled; - if(infoRec->FillSpansSolid) - infoRec->FillSpansSolid = XAAOverFillSpansSolid; - if(infoRec->FillSpansStippled) - infoRec->FillSpansStippled = XAAOverFillSpansStippled; - if(infoRec->FillSpansOpaqueStippled) - infoRec->FillSpansOpaqueStippled = XAAOverFillSpansOpaqueStippled; - if(infoRec->FillSpansTiled) - infoRec->FillSpansTiled = XAAOverFillSpansTiled; - if(infoRec->PolyText8TE) - infoRec->PolyText8TE = XAAOverPolyText8TE; - if(infoRec->PolyText16TE) - infoRec->PolyText16TE = XAAOverPolyText16TE; - if(infoRec->ImageText8TE) - infoRec->ImageText8TE = XAAOverImageText8TE; - if(infoRec->ImageText16TE) - infoRec->ImageText16TE = XAAOverImageText16TE; - if(infoRec->ImageGlyphBltTE) - infoRec->ImageGlyphBltTE = XAAOverImageGlyphBltTE; - if(infoRec->PolyGlyphBltTE) - infoRec->PolyGlyphBltTE = XAAOverPolyGlyphBltTE; - if(infoRec->PolyText8NonTE) - infoRec->PolyText8NonTE = XAAOverPolyText8NonTE; - if(infoRec->PolyText16NonTE) - infoRec->PolyText16NonTE = XAAOverPolyText16NonTE; - if(infoRec->ImageText8NonTE) - infoRec->ImageText8NonTE = XAAOverImageText8NonTE; - if(infoRec->ImageText16NonTE) - infoRec->ImageText16NonTE = XAAOverImageText16NonTE; - if(infoRec->ImageGlyphBltNonTE) - infoRec->ImageGlyphBltNonTE = XAAOverImageGlyphBltNonTE; - if(infoRec->PolyGlyphBltNonTE) - infoRec->PolyGlyphBltNonTE = XAAOverPolyGlyphBltNonTE; - if(infoRec->PolyRectangleThinSolid) - infoRec->PolyRectangleThinSolid = XAAOverPolyRectangleThinSolid; - if(infoRec->PolylinesWideSolid) - infoRec->PolylinesWideSolid = XAAOverPolylinesWideSolid; - if(infoRec->PolylinesThinSolid) - infoRec->PolylinesThinSolid = XAAOverPolylinesThinSolid; - if(infoRec->PolySegmentThinSolid) - infoRec->PolySegmentThinSolid = XAAOverPolySegmentThinSolid; - if(infoRec->PolylinesThinDashed) - infoRec->PolylinesThinDashed = XAAOverPolylinesThinDashed; - if(infoRec->PolySegmentThinDashed) - infoRec->PolySegmentThinDashed = XAAOverPolySegmentThinDashed; - if(infoRec->FillPolygonSolid) - infoRec->FillPolygonSolid = XAAOverFillPolygonSolid; - if(infoRec->FillPolygonStippled) - infoRec->FillPolygonStippled = XAAOverFillPolygonStippled; - if(infoRec->FillPolygonOpaqueStippled) - infoRec->FillPolygonOpaqueStippled = XAAOverFillPolygonOpaqueStippled; - if(infoRec->FillPolygonTiled) - infoRec->FillPolygonTiled = XAAOverFillPolygonTiled; - if(infoRec->PolyFillArcSolid) - infoRec->PolyFillArcSolid = XAAOverPolyFillArcSolid; - if(infoRec->PutImage) - infoRec->PutImage = XAAOverPutImage; - - return TRUE; -} - -/*********************** Screen functions ************************/ - -void -XAAOverCopyWindow( - WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc -){ - ScreenPtr pScreen = pWin->drawable.pScreen; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pScreen); - ScrnInfoPtr pScrn = infoRec->pScrn; - DDXPointPtr ppt, pptSrc; - RegionRec rgnDst; - BoxPtr pbox; - int i, nbox, dx, dy; - WindowPtr pRoot = WindowTable[pScreen->myNum]; - - - if (!pScrn->vtSema || !infoRec->ScreenToScreenBitBlt) { - XAA_SCREEN_PROLOGUE (pScreen, CopyWindow); - if(pScrn->vtSema && infoRec->NeedToSync) { - (*infoRec->Sync)(pScrn); - infoRec->NeedToSync = FALSE; - } - (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc); - XAA_SCREEN_EPILOGUE (pScreen, CopyWindow, XAAOverCopyWindow); - return; - } - - infoRec->ScratchGC.alu = GXcopy; - infoRec->ScratchGC.planemask = ~0; - - REGION_NULL(pScreen, &rgnDst); - - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); - REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); - - nbox = REGION_NUM_RECTS(&rgnDst); - if(nbox && - (pptSrc = (DDXPointPtr )xalloc(nbox * sizeof(DDXPointRec)))) { - - pbox = REGION_RECTS(&rgnDst); - for (i = nbox, ppt = pptSrc; i--; ppt++, pbox++) { - ppt->x = pbox->x1 + dx; - ppt->y = pbox->y1 + dy; - } - - SWITCH_DEPTH(8); - XAADoBitBlt((DrawablePtr)pRoot, (DrawablePtr)pRoot, - &(infoRec->ScratchGC), &rgnDst, pptSrc); - - if(pWin->drawable.bitsPerPixel != 8) { - SWITCH_DEPTH(pScrn->depth); - XAADoBitBlt((DrawablePtr)pRoot, (DrawablePtr)pRoot, - &(infoRec->ScratchGC), &rgnDst, pptSrc); - } - - xfree(pptSrc); - } - - REGION_UNINIT(pScreen, &rgnDst); - - if(pWin->drawable.depth == 8) { - REGION_NULL(pScreen, &rgnDst); - miSegregateChildren(pWin, &rgnDst, pScrn->depth); - if(REGION_NOTEMPTY(pScreen, &rgnDst)) { - REGION_INTERSECT(pScreen, &rgnDst, &rgnDst, prgnSrc); - nbox = REGION_NUM_RECTS(&rgnDst); - if(nbox && - (pptSrc = (DDXPointPtr )xalloc(nbox * sizeof(DDXPointRec)))){ - - pbox = REGION_RECTS(&rgnDst); - for (i = nbox, ppt = pptSrc; i--; ppt++, pbox++) { - ppt->x = pbox->x1 + dx; - ppt->y = pbox->y1 + dy; - } - - SWITCH_DEPTH(pScrn->depth); - XAADoBitBlt((DrawablePtr)pRoot, (DrawablePtr)pRoot, - &(infoRec->ScratchGC), &rgnDst, pptSrc); - xfree(pptSrc); - } - } - REGION_UNINIT(pScreen, &rgnDst); - } -} - - -void -XAAOverWindowExposures( - WindowPtr pWin, - RegionPtr pReg, - RegionPtr pOtherReg -){ - ScreenPtr pScreen = pWin->drawable.pScreen; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - - if((pWin->drawable.bitsPerPixel != 8) && infoRec->pScrn->vtSema) { - if(REGION_NUM_RECTS(pReg) && infoRec->FillSolidRects) { - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pScreen); - - SWITCH_DEPTH(8); - (*infoRec->FillSolidRects)(infoRec->pScrn, - infoRec->pScrn->colorKey, GXcopy, ~0, - REGION_NUM_RECTS(pReg), REGION_RECTS(pReg)); - miWindowExposures(pWin, pReg, pOtherReg); - return; - } else if(infoRec->NeedToSync) { - (*infoRec->Sync)(infoRec->pScrn); - infoRec->NeedToSync = FALSE; - } - } - - XAA_SCREEN_PROLOGUE (pScreen, WindowExposures); - (*pScreen->WindowExposures) (pWin, pReg, pOtherReg); - XAA_SCREEN_EPILOGUE(pScreen, WindowExposures, XAAOverWindowExposures); -} - -/********************* Choosers *************************/ - -static int -XAAOverStippledFillChooser(GCPtr pGC) -{ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - int ret; - - ret = (*pOverPriv->StippledFillChooser)(pGC); - - if((pGC->depth == 8) && - ((ret == DO_COLOR_8x8) || (ret == DO_CACHE_BLT))) { - ret = 0; - } - - return ret; -} - -static int -XAAOverOpaqueStippledFillChooser(GCPtr pGC) -{ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - int ret; - - ret = (*pOverPriv->OpaqueStippledFillChooser)(pGC); - - if((pGC->depth == 8) && - ((ret == DO_COLOR_8x8) || (ret == DO_CACHE_BLT))) { - ret = 0; - } - - return ret; -} - -static int -XAAOverTiledFillChooser(GCPtr pGC) -{ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - int ret; - - ret = (*pOverPriv->TiledFillChooser)(pGC); - - if((pGC->depth == 8) && - ((ret == DO_COLOR_8x8) || (ret == DO_CACHE_BLT))) { - ret = 0; - } - - return ret; -} - - -/**************************** GC Functions **************************/ - -static RegionPtr -XAAOverCopyArea( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - return (*pOverPriv->CopyArea)(pSrc, pDst, - pGC, srcx, srcy, width, height, dstx, dsty); -} - -static RegionPtr -XAAOverCopyPlane( - DrawablePtr pSrc, - DrawablePtr pDst, - GCPtr pGC, - int srcx, int srcy, - int width, int height, - int dstx, int dsty, - unsigned long bitPlane -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - return (*pOverPriv->CopyPlane)(pSrc, pDst, - pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); - -} - -static void -XAAOverPushPixelsSolid( - GCPtr pGC, - PixmapPtr pBitMap, - DrawablePtr pDraw, - int dx, int dy, - int xOrg, int yOrg -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PushPixelsSolid)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); -} - - - -static void -XAAOverPolyFillRectSolid( - DrawablePtr pDraw, - GCPtr pGC, - int nrectFill, - xRectangle *prectInit -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolyFillRectSolid)(pDraw, pGC, nrectFill, prectInit); -} - -static void -XAAOverPolyFillRectStippled( - DrawablePtr pDraw, - GCPtr pGC, - int nrectFill, - xRectangle *prectInit -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolyFillRectStippled)(pDraw, pGC, nrectFill, prectInit); -} - - -static void -XAAOverPolyFillRectOpaqueStippled( - DrawablePtr pDraw, - GCPtr pGC, - int nrectFill, - xRectangle *prectInit -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolyFillRectOpaqueStippled)(pDraw, pGC, nrectFill, prectInit); -} - -static void -XAAOverPolyFillRectTiled( - DrawablePtr pDraw, - GCPtr pGC, - int nrectFill, - xRectangle *prectInit -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolyFillRectTiled)(pDraw, pGC, nrectFill, prectInit); -} - - -static void -XAAOverFillSpansSolid( - DrawablePtr pDraw, - GCPtr pGC, - int nInit, - DDXPointPtr ppt, - int *pwidth, - int fSorted -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->FillSpansSolid)( - pDraw, pGC, nInit, ppt, pwidth, fSorted); -} - - -static void -XAAOverFillSpansStippled( - DrawablePtr pDraw, - GCPtr pGC, - int nInit, - DDXPointPtr ppt, - int *pwidth, - int fSorted -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->FillSpansStippled)(pDraw, pGC, nInit, ppt, pwidth, fSorted); -} - -static void -XAAOverFillSpansOpaqueStippled( - DrawablePtr pDraw, - GCPtr pGC, - int nInit, - DDXPointPtr ppt, - int *pwidth, - int fSorted -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->FillSpansOpaqueStippled)( - pDraw, pGC, nInit, ppt, pwidth, fSorted); -} - - -static void -XAAOverFillSpansTiled( - DrawablePtr pDraw, - GCPtr pGC, - int nInit, - DDXPointPtr ppt, - int *pwidth, - int fSorted -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->FillSpansTiled)(pDraw, pGC, nInit, ppt, pwidth, fSorted); -} - -static int -XAAOverPolyText8TE( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - return (*pOverPriv->PolyText8TE)(pDraw, pGC, x, y, count, chars); -} - - -static int -XAAOverPolyText16TE( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - return (*pOverPriv->PolyText16TE)(pDraw, pGC, x, y, count, chars); -} - - -static void -XAAOverImageText8TE( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->ImageText8TE)(pDraw, pGC, x, y, count, chars); -} - - -static void -XAAOverImageText16TE( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->ImageText16TE)(pDraw, pGC, x, y, count, chars); -} - -static void -XAAOverImageGlyphBltTE( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->ImageGlyphBltTE)( - pDraw, pGC, xInit, yInit, nglyph, ppci, pglyphBase); -} - -static void -XAAOverPolyGlyphBltTE( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolyGlyphBltTE)( - pDraw, pGC, xInit, yInit, nglyph, ppci, pglyphBase); -} - -static int -XAAOverPolyText8NonTE( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - return (*pOverPriv->PolyText8NonTE)(pDraw, pGC, x, y, count, chars); -} - - -static int -XAAOverPolyText16NonTE( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - return (*pOverPriv->PolyText16NonTE)(pDraw, pGC, x, y, count, chars); -} - -static void -XAAOverImageText8NonTE( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->ImageText8NonTE)(pDraw, pGC, x, y, count, chars); -} - -static void -XAAOverImageText16NonTE( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->ImageText16NonTE)(pDraw, pGC, x, y, count, chars); -} - - -static void -XAAOverImageGlyphBltNonTE( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->ImageGlyphBltNonTE)( - pDraw, pGC, xInit, yInit, nglyph, ppci, pglyphBase); -} - -static void -XAAOverPolyGlyphBltNonTE( - DrawablePtr pDraw, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolyGlyphBltNonTE)( - pDraw, pGC, xInit, yInit, nglyph, ppci, pglyphBase); -} - -static void -XAAOverPolyRectangleThinSolid( - DrawablePtr pDraw, - GCPtr pGC, - int nRectsInit, - xRectangle *pRectsInit -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolyRectangleThinSolid)(pDraw, pGC, nRectsInit, pRectsInit); -} - - - -static void -XAAOverPolylinesWideSolid( - DrawablePtr pDraw, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr pPts -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolylinesWideSolid)(pDraw, pGC, mode, npt, pPts); -} - - -static void -XAAOverPolylinesThinSolid( - DrawablePtr pDraw, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr pPts -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolylinesThinSolid)(pDraw, pGC, mode, npt, pPts); -} - -static void -XAAOverPolySegmentThinSolid( - DrawablePtr pDraw, - GCPtr pGC, - int nseg, - xSegment *pSeg -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolySegmentThinSolid)(pDraw, pGC, nseg, pSeg); -} - -static void -XAAOverPolylinesThinDashed( - DrawablePtr pDraw, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr pPts -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolylinesThinDashed)(pDraw, pGC, mode, npt, pPts); -} - -static void -XAAOverPolySegmentThinDashed( - DrawablePtr pDraw, - GCPtr pGC, - int nseg, - xSegment *pSeg -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolySegmentThinDashed)(pDraw, pGC, nseg, pSeg); -} - - -static void -XAAOverFillPolygonSolid( - DrawablePtr pDraw, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr ptsIn -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->FillPolygonSolid)(pDraw, pGC, shape, mode, count, ptsIn); -} - -static void -XAAOverFillPolygonStippled( - DrawablePtr pDraw, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr ptsIn -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->FillPolygonStippled)(pDraw, pGC, shape, mode, count, ptsIn); -} - - -static void -XAAOverFillPolygonOpaqueStippled( - DrawablePtr pDraw, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr ptsIn -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->FillPolygonOpaqueStippled)( - pDraw, pGC, shape, mode, count, ptsIn); -} - -static void -XAAOverFillPolygonTiled( - DrawablePtr pDraw, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr ptsIn -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->FillPolygonTiled)(pDraw, pGC, shape, mode, count, ptsIn); -} - - -static void -XAAOverPolyFillArcSolid( - DrawablePtr pDraw, - GCPtr pGC, - int narcs, - xArc *parcs -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PolyFillArcSolid)(pDraw, pGC, narcs, parcs); -} - - -static void -XAAOverPutImage( - DrawablePtr pDraw, - GCPtr pGC, - int depth, - int x, - int y, - int w, - int h, - int leftPad, - int format, - char *pImage -){ - XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); - - SWITCH_DEPTH(pGC->depth); - - (*pOverPriv->PutImage)(pDraw, pGC, depth, x, y, w, h, - leftPad, format, pImage); -} - +/* + Copyright (c) 1999 - The XFree86 Project Inc. + + Written by Mark Vojkovich +*/ + + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "xf86str.h" +#include "mi.h" +#include "miline.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xaawrap.h" +#include "servermd.h" + +/* Screen funcs */ + +static void XAAOverCopyWindow(WindowPtr, DDXPointRec, RegionPtr); +static void XAAOverWindowExposures(WindowPtr, RegionPtr, RegionPtr); + +static int XAAOverStippledFillChooser(GCPtr); +static int XAAOverOpaqueStippledFillChooser(GCPtr); +static int XAAOverTiledFillChooser(GCPtr); + +/* GC funcs */ + +static RegionPtr XAAOverCopyArea(DrawablePtr, DrawablePtr, GC *, + int, int, int, int, int, int); +static RegionPtr XAAOverCopyPlane(DrawablePtr, DrawablePtr, GCPtr, + int, int, int, int, int, int, unsigned long); +static void XAAOverPushPixelsSolid(GCPtr, PixmapPtr, DrawablePtr, int, + int, int, int); +static void XAAOverPolyFillRectSolid(DrawablePtr, GCPtr, int, xRectangle*); +static void XAAOverPolyFillRectStippled(DrawablePtr, GCPtr, int, xRectangle*); +static void XAAOverPolyFillRectOpaqueStippled(DrawablePtr, GCPtr, + int, xRectangle*); +static void XAAOverPolyFillRectTiled(DrawablePtr, GCPtr, int, xRectangle*); +static void XAAOverFillSpansSolid(DrawablePtr, GCPtr, int, DDXPointPtr, + int*, int); +static void XAAOverFillSpansStippled(DrawablePtr, GCPtr, int, DDXPointPtr, + int*, int); +static void XAAOverFillSpansOpaqueStippled(DrawablePtr, GCPtr, int, + DDXPointPtr, int*, int); +static void XAAOverFillSpansTiled(DrawablePtr, GCPtr, int, DDXPointPtr, + int*, int); +static int XAAOverPolyText8TE(DrawablePtr, GCPtr, int, int, int, char *); +static int XAAOverPolyText16TE(DrawablePtr, GCPtr, int, int, int, + unsigned short*); +static void XAAOverImageText8TE(DrawablePtr, GCPtr, int, int, int, char*); +static void XAAOverImageText16TE(DrawablePtr, GCPtr, int, int, int, + unsigned short*); +static void XAAOverImageGlyphBltTE(DrawablePtr, GCPtr, int, int, + unsigned int, CharInfoPtr*, pointer); +static void XAAOverPolyGlyphBltTE(DrawablePtr, GCPtr, int, int, + unsigned int, CharInfoPtr*, pointer); +static int XAAOverPolyText8NonTE(DrawablePtr, GCPtr, int, int, int, char*); +static int XAAOverPolyText16NonTE(DrawablePtr, GCPtr, int, int, int, + unsigned short*); +static void XAAOverImageText8NonTE(DrawablePtr, GCPtr, int, int, int, char*); +static void XAAOverImageText16NonTE(DrawablePtr, GCPtr, int, int, int, + unsigned short*); +static void XAAOverImageGlyphBltNonTE(DrawablePtr, GCPtr, int, int, + unsigned int, CharInfoPtr *, pointer); +static void XAAOverPolyGlyphBltNonTE(DrawablePtr, GCPtr, int, int, + unsigned int, CharInfoPtr *, pointer); +static void XAAOverPolyRectangleThinSolid(DrawablePtr, GCPtr, int, xRectangle*); +static void XAAOverPolylinesWideSolid(DrawablePtr, GCPtr, int, int, + DDXPointPtr); +static void XAAOverPolylinesThinSolid(DrawablePtr, GCPtr, int, int, + DDXPointPtr); +static void XAAOverPolySegmentThinSolid(DrawablePtr, GCPtr, int, xSegment*); +static void XAAOverPolylinesThinDashed(DrawablePtr, GCPtr, int, int, + DDXPointPtr); +static void XAAOverPolySegmentThinDashed(DrawablePtr, GCPtr, int, xSegment*); +static void XAAOverFillPolygonSolid(DrawablePtr, GCPtr, int, int, int, + DDXPointPtr); +static void XAAOverFillPolygonStippled(DrawablePtr, GCPtr, int, int, int, + DDXPointPtr); +static void XAAOverFillPolygonOpaqueStippled(DrawablePtr, GCPtr, int, int, int, + DDXPointPtr); +static void XAAOverFillPolygonTiled(DrawablePtr, GCPtr, int, int, int, + DDXPointPtr); +static void XAAOverPolyFillArcSolid(DrawablePtr, GCPtr, int, xArc*); +static void XAAOverPutImage(DrawablePtr, GCPtr, int, int, int, int, int, + int, int, char*); + + +typedef struct { + ScrnInfoPtr pScrn; + DepthChangeFuncPtr callback; + int currentDepth; +/* GC funcs */ + RegionPtr (*CopyArea)(DrawablePtr, DrawablePtr, GC *, + int, int, int, int, int, int); + RegionPtr (*CopyPlane)(DrawablePtr, DrawablePtr, GCPtr, + int, int, int, int, int, int, unsigned long); + void (*PushPixelsSolid)(GCPtr, PixmapPtr, DrawablePtr, int, int, int, int); + void (*PolyFillRectSolid)(DrawablePtr, GCPtr, int, xRectangle*); + void (*PolyFillRectStippled)(DrawablePtr, GCPtr, int, xRectangle*); + void (*PolyFillRectOpaqueStippled)(DrawablePtr, GCPtr, int, xRectangle*); + void (*PolyFillRectTiled)(DrawablePtr, GCPtr, int, xRectangle*); + void (*FillSpansSolid)(DrawablePtr, GCPtr, int, DDXPointPtr, int*, int); + void (*FillSpansStippled)(DrawablePtr, GCPtr, int, DDXPointPtr, int*, int); + void (*FillSpansOpaqueStippled)(DrawablePtr,GCPtr,int,DDXPointPtr,int*,int); + void (*FillSpansTiled)(DrawablePtr, GCPtr, int, DDXPointPtr, int*, int); + int (*PolyText8TE)(DrawablePtr, GCPtr, int, int, int, char *); + int (*PolyText16TE)(DrawablePtr, GCPtr, int, int, int, unsigned short*); + void (*ImageText8TE)(DrawablePtr, GCPtr, int, int, int, char*); + void (*ImageText16TE)(DrawablePtr, GCPtr, int, int, int, unsigned short*); + void (*ImageGlyphBltTE)(DrawablePtr, GCPtr, int, int, unsigned int, + CharInfoPtr*, pointer); + void (*PolyGlyphBltTE)(DrawablePtr, GCPtr, int, int, unsigned int, + CharInfoPtr*, pointer); + int (*PolyText8NonTE)(DrawablePtr, GCPtr, int, int, int, char*); + int (*PolyText16NonTE)(DrawablePtr, GCPtr, int, int, int, unsigned short*); + void (*ImageText8NonTE)(DrawablePtr, GCPtr, int, int, int, char*); + void (*ImageText16NonTE)(DrawablePtr, GCPtr, int, int, int, unsigned short*); + void (*ImageGlyphBltNonTE)(DrawablePtr, GCPtr, int, int, unsigned int, + CharInfoPtr *, pointer); + void (*PolyGlyphBltNonTE)(DrawablePtr, GCPtr, int, int, unsigned int, + CharInfoPtr *, pointer); + void (*PolyRectangleThinSolid)(DrawablePtr, GCPtr, int, xRectangle*); + void (*PolylinesWideSolid)(DrawablePtr, GCPtr, int, int, DDXPointPtr); + + void (*PolylinesThinSolid)(DrawablePtr, GCPtr, int, int, DDXPointPtr); + void (*PolySegmentThinSolid)(DrawablePtr, GCPtr, int, xSegment*); + void (*PolylinesThinDashed)(DrawablePtr, GCPtr, int, int, DDXPointPtr); + void (*PolySegmentThinDashed)(DrawablePtr, GCPtr, int, xSegment*); + void (*FillPolygonSolid)(DrawablePtr, GCPtr, int, int, int, DDXPointPtr); + void (*FillPolygonStippled)(DrawablePtr, GCPtr, int, int, int, DDXPointPtr); + void (*FillPolygonOpaqueStippled)(DrawablePtr, GCPtr, int, int, int, + DDXPointPtr); + void (*FillPolygonTiled)(DrawablePtr, GCPtr, int, int, int, DDXPointPtr); + void (*PolyFillArcSolid)(DrawablePtr, GCPtr, int, xArc*); + void (*PutImage)(DrawablePtr, GCPtr, int, int, int, int, int, int, + int, char*); + int (*StippledFillChooser)(GCPtr); + int (*OpaqueStippledFillChooser)(GCPtr); + int (*TiledFillChooser)(GCPtr); +} XAAOverlayRec, *XAAOverlayPtr; + +static int XAAOverlayKeyIndex; +static DevPrivateKey XAAOverlayKey = &XAAOverlayKeyIndex; + +#define GET_OVERLAY_PRIV(pScreen) \ + (XAAOverlayPtr)dixLookupPrivate(&(pScreen)->devPrivates, XAAOverlayKey) + +#define SWITCH_DEPTH(d) \ + if(pOverPriv->currentDepth != d) { \ + (*pOverPriv->callback)(pOverPriv->pScrn, d); \ + pOverPriv->currentDepth = d; \ + } + + +Bool +XAAInitDualFramebufferOverlay( + ScreenPtr pScreen, + DepthChangeFuncPtr callback +){ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + XAAOverlayPtr pOverPriv; + + if(!(pOverPriv = malloc(sizeof(XAAOverlayRec)))) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, XAAOverlayKey, pOverPriv); + + pOverPriv->pScrn = pScrn; + pOverPriv->callback = callback; + pOverPriv->currentDepth = -1; + + /* Overwrite key screen functions. The XAA core will clean up */ + + pScreen->CopyWindow = XAAOverCopyWindow; + pScreen->WindowExposures = XAAOverWindowExposures; + + pOverPriv->StippledFillChooser = infoRec->StippledFillChooser; + pOverPriv->OpaqueStippledFillChooser = infoRec->OpaqueStippledFillChooser; + pOverPriv->TiledFillChooser = infoRec->TiledFillChooser; + + infoRec->StippledFillChooser = XAAOverStippledFillChooser; + infoRec->OpaqueStippledFillChooser = XAAOverOpaqueStippledFillChooser; + infoRec->TiledFillChooser = XAAOverTiledFillChooser; + + /* wrap all XAA GC rendering */ + + pOverPriv->CopyArea = infoRec->CopyArea; + pOverPriv->CopyPlane = infoRec->CopyPlane; + pOverPriv->PushPixelsSolid = infoRec->PushPixelsSolid; + pOverPriv->PolyFillRectSolid = infoRec->PolyFillRectSolid; + pOverPriv->PolyFillRectStippled = infoRec->PolyFillRectStippled; + pOverPriv->PolyFillRectOpaqueStippled = infoRec->PolyFillRectOpaqueStippled; + pOverPriv->PolyFillRectTiled = infoRec->PolyFillRectTiled; + pOverPriv->FillSpansSolid = infoRec->FillSpansSolid; + pOverPriv->FillSpansStippled = infoRec->FillSpansStippled; + pOverPriv->FillSpansOpaqueStippled = infoRec->FillSpansOpaqueStippled; + pOverPriv->FillSpansTiled = infoRec->FillSpansTiled; + pOverPriv->PolyText8TE = infoRec->PolyText8TE; + pOverPriv->PolyText16TE = infoRec->PolyText16TE; + pOverPriv->ImageText8TE = infoRec->ImageText8TE; + pOverPriv->ImageText16TE = infoRec->ImageText16TE; + pOverPriv->ImageGlyphBltTE = infoRec->ImageGlyphBltTE; + pOverPriv->PolyGlyphBltTE = infoRec->PolyGlyphBltTE; + pOverPriv->PolyText8NonTE = infoRec->PolyText8NonTE; + pOverPriv->PolyText16NonTE = infoRec->PolyText16NonTE; + pOverPriv->ImageText8NonTE = infoRec->ImageText8NonTE; + pOverPriv->ImageText16NonTE = infoRec->ImageText16NonTE; + pOverPriv->ImageGlyphBltNonTE = infoRec->ImageGlyphBltNonTE; + pOverPriv->PolyGlyphBltNonTE = infoRec->PolyGlyphBltNonTE; + pOverPriv->PolyRectangleThinSolid = infoRec->PolyRectangleThinSolid; + pOverPriv->PolylinesWideSolid = infoRec->PolylinesWideSolid; + pOverPriv->PolylinesThinSolid = infoRec->PolylinesThinSolid; + pOverPriv->PolySegmentThinSolid = infoRec->PolySegmentThinSolid; + pOverPriv->PolylinesThinDashed = infoRec->PolylinesThinDashed; + pOverPriv->PolySegmentThinDashed = infoRec->PolySegmentThinDashed; + pOverPriv->FillPolygonSolid = infoRec->FillPolygonSolid; + pOverPriv->FillPolygonStippled = infoRec->FillPolygonStippled; + pOverPriv->FillPolygonOpaqueStippled = infoRec->FillPolygonOpaqueStippled; + pOverPriv->FillPolygonTiled = infoRec->FillPolygonTiled; + pOverPriv->PolyFillArcSolid = infoRec->PolyFillArcSolid; + pOverPriv->PutImage = infoRec->PutImage; + + + if(infoRec->CopyArea) + infoRec->CopyArea = XAAOverCopyArea; + if(infoRec->CopyPlane) + infoRec->CopyPlane = XAAOverCopyPlane; + if(infoRec->PushPixelsSolid) + infoRec->PushPixelsSolid = XAAOverPushPixelsSolid; + if(infoRec->PolyFillRectSolid) + infoRec->PolyFillRectSolid = XAAOverPolyFillRectSolid; + if(infoRec->PolyFillRectStippled) + infoRec->PolyFillRectStippled = XAAOverPolyFillRectStippled; + if(infoRec->PolyFillRectOpaqueStippled) + infoRec->PolyFillRectOpaqueStippled = XAAOverPolyFillRectOpaqueStippled; + if(infoRec->PolyFillRectTiled) + infoRec->PolyFillRectTiled = XAAOverPolyFillRectTiled; + if(infoRec->FillSpansSolid) + infoRec->FillSpansSolid = XAAOverFillSpansSolid; + if(infoRec->FillSpansStippled) + infoRec->FillSpansStippled = XAAOverFillSpansStippled; + if(infoRec->FillSpansOpaqueStippled) + infoRec->FillSpansOpaqueStippled = XAAOverFillSpansOpaqueStippled; + if(infoRec->FillSpansTiled) + infoRec->FillSpansTiled = XAAOverFillSpansTiled; + if(infoRec->PolyText8TE) + infoRec->PolyText8TE = XAAOverPolyText8TE; + if(infoRec->PolyText16TE) + infoRec->PolyText16TE = XAAOverPolyText16TE; + if(infoRec->ImageText8TE) + infoRec->ImageText8TE = XAAOverImageText8TE; + if(infoRec->ImageText16TE) + infoRec->ImageText16TE = XAAOverImageText16TE; + if(infoRec->ImageGlyphBltTE) + infoRec->ImageGlyphBltTE = XAAOverImageGlyphBltTE; + if(infoRec->PolyGlyphBltTE) + infoRec->PolyGlyphBltTE = XAAOverPolyGlyphBltTE; + if(infoRec->PolyText8NonTE) + infoRec->PolyText8NonTE = XAAOverPolyText8NonTE; + if(infoRec->PolyText16NonTE) + infoRec->PolyText16NonTE = XAAOverPolyText16NonTE; + if(infoRec->ImageText8NonTE) + infoRec->ImageText8NonTE = XAAOverImageText8NonTE; + if(infoRec->ImageText16NonTE) + infoRec->ImageText16NonTE = XAAOverImageText16NonTE; + if(infoRec->ImageGlyphBltNonTE) + infoRec->ImageGlyphBltNonTE = XAAOverImageGlyphBltNonTE; + if(infoRec->PolyGlyphBltNonTE) + infoRec->PolyGlyphBltNonTE = XAAOverPolyGlyphBltNonTE; + if(infoRec->PolyRectangleThinSolid) + infoRec->PolyRectangleThinSolid = XAAOverPolyRectangleThinSolid; + if(infoRec->PolylinesWideSolid) + infoRec->PolylinesWideSolid = XAAOverPolylinesWideSolid; + if(infoRec->PolylinesThinSolid) + infoRec->PolylinesThinSolid = XAAOverPolylinesThinSolid; + if(infoRec->PolySegmentThinSolid) + infoRec->PolySegmentThinSolid = XAAOverPolySegmentThinSolid; + if(infoRec->PolylinesThinDashed) + infoRec->PolylinesThinDashed = XAAOverPolylinesThinDashed; + if(infoRec->PolySegmentThinDashed) + infoRec->PolySegmentThinDashed = XAAOverPolySegmentThinDashed; + if(infoRec->FillPolygonSolid) + infoRec->FillPolygonSolid = XAAOverFillPolygonSolid; + if(infoRec->FillPolygonStippled) + infoRec->FillPolygonStippled = XAAOverFillPolygonStippled; + if(infoRec->FillPolygonOpaqueStippled) + infoRec->FillPolygonOpaqueStippled = XAAOverFillPolygonOpaqueStippled; + if(infoRec->FillPolygonTiled) + infoRec->FillPolygonTiled = XAAOverFillPolygonTiled; + if(infoRec->PolyFillArcSolid) + infoRec->PolyFillArcSolid = XAAOverPolyFillArcSolid; + if(infoRec->PutImage) + infoRec->PutImage = XAAOverPutImage; + + return TRUE; +} + +/*********************** Screen functions ************************/ + +void +XAAOverCopyWindow( + WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pScreen); + ScrnInfoPtr pScrn = infoRec->pScrn; + DDXPointPtr ppt, pptSrc; + RegionRec rgnDst; + BoxPtr pbox; + int i, nbox, dx, dy; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + + + if (!pScrn->vtSema || !infoRec->ScreenToScreenBitBlt) { + XAA_SCREEN_PROLOGUE (pScreen, CopyWindow); + if(pScrn->vtSema && infoRec->NeedToSync) { + (*infoRec->Sync)(pScrn); + infoRec->NeedToSync = FALSE; + } + (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc); + XAA_SCREEN_EPILOGUE (pScreen, CopyWindow, XAAOverCopyWindow); + return; + } + + infoRec->ScratchGC.alu = GXcopy; + infoRec->ScratchGC.planemask = ~0; + + REGION_NULL(pScreen, &rgnDst); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + nbox = REGION_NUM_RECTS(&rgnDst); + if(nbox && + (pptSrc = (DDXPointPtr )malloc(nbox * sizeof(DDXPointRec)))) { + + pbox = REGION_RECTS(&rgnDst); + for (i = nbox, ppt = pptSrc; i--; ppt++, pbox++) { + ppt->x = pbox->x1 + dx; + ppt->y = pbox->y1 + dy; + } + + SWITCH_DEPTH(8); + XAADoBitBlt((DrawablePtr)pRoot, (DrawablePtr)pRoot, + &(infoRec->ScratchGC), &rgnDst, pptSrc); + + if(pWin->drawable.bitsPerPixel != 8) { + SWITCH_DEPTH(pScrn->depth); + XAADoBitBlt((DrawablePtr)pRoot, (DrawablePtr)pRoot, + &(infoRec->ScratchGC), &rgnDst, pptSrc); + } + + free(pptSrc); + } + + REGION_UNINIT(pScreen, &rgnDst); + + if(pWin->drawable.depth == 8) { + REGION_NULL(pScreen, &rgnDst); + miSegregateChildren(pWin, &rgnDst, pScrn->depth); + if(REGION_NOTEMPTY(pScreen, &rgnDst)) { + REGION_INTERSECT(pScreen, &rgnDst, &rgnDst, prgnSrc); + nbox = REGION_NUM_RECTS(&rgnDst); + if(nbox && + (pptSrc = (DDXPointPtr )malloc(nbox * sizeof(DDXPointRec)))){ + + pbox = REGION_RECTS(&rgnDst); + for (i = nbox, ppt = pptSrc; i--; ppt++, pbox++) { + ppt->x = pbox->x1 + dx; + ppt->y = pbox->y1 + dy; + } + + SWITCH_DEPTH(pScrn->depth); + XAADoBitBlt((DrawablePtr)pRoot, (DrawablePtr)pRoot, + &(infoRec->ScratchGC), &rgnDst, pptSrc); + free(pptSrc); + } + } + REGION_UNINIT(pScreen, &rgnDst); + } +} + + +void +XAAOverWindowExposures( + WindowPtr pWin, + RegionPtr pReg, + RegionPtr pOtherReg +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + + if((pWin->drawable.bitsPerPixel != 8) && infoRec->pScrn->vtSema) { + if(REGION_NUM_RECTS(pReg) && infoRec->FillSolidRects) { + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pScreen); + + SWITCH_DEPTH(8); + (*infoRec->FillSolidRects)(infoRec->pScrn, + infoRec->pScrn->colorKey, GXcopy, ~0, + REGION_NUM_RECTS(pReg), REGION_RECTS(pReg)); + miWindowExposures(pWin, pReg, pOtherReg); + return; + } else if(infoRec->NeedToSync) { + (*infoRec->Sync)(infoRec->pScrn); + infoRec->NeedToSync = FALSE; + } + } + + XAA_SCREEN_PROLOGUE (pScreen, WindowExposures); + (*pScreen->WindowExposures) (pWin, pReg, pOtherReg); + XAA_SCREEN_EPILOGUE(pScreen, WindowExposures, XAAOverWindowExposures); +} + +/********************* Choosers *************************/ + +static int +XAAOverStippledFillChooser(GCPtr pGC) +{ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + int ret; + + ret = (*pOverPriv->StippledFillChooser)(pGC); + + if((pGC->depth == 8) && + ((ret == DO_COLOR_8x8) || (ret == DO_CACHE_BLT))) { + ret = 0; + } + + return ret; +} + +static int +XAAOverOpaqueStippledFillChooser(GCPtr pGC) +{ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + int ret; + + ret = (*pOverPriv->OpaqueStippledFillChooser)(pGC); + + if((pGC->depth == 8) && + ((ret == DO_COLOR_8x8) || (ret == DO_CACHE_BLT))) { + ret = 0; + } + + return ret; +} + +static int +XAAOverTiledFillChooser(GCPtr pGC) +{ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + int ret; + + ret = (*pOverPriv->TiledFillChooser)(pGC); + + if((pGC->depth == 8) && + ((ret == DO_COLOR_8x8) || (ret == DO_CACHE_BLT))) { + ret = 0; + } + + return ret; +} + + +/**************************** GC Functions **************************/ + +static RegionPtr +XAAOverCopyArea( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + return (*pOverPriv->CopyArea)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty); +} + +static RegionPtr +XAAOverCopyPlane( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty, + unsigned long bitPlane +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + return (*pOverPriv->CopyPlane)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); + +} + +static void +XAAOverPushPixelsSolid( + GCPtr pGC, + PixmapPtr pBitMap, + DrawablePtr pDraw, + int dx, int dy, + int xOrg, int yOrg +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PushPixelsSolid)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); +} + + + +static void +XAAOverPolyFillRectSolid( + DrawablePtr pDraw, + GCPtr pGC, + int nrectFill, + xRectangle *prectInit +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolyFillRectSolid)(pDraw, pGC, nrectFill, prectInit); +} + +static void +XAAOverPolyFillRectStippled( + DrawablePtr pDraw, + GCPtr pGC, + int nrectFill, + xRectangle *prectInit +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolyFillRectStippled)(pDraw, pGC, nrectFill, prectInit); +} + + +static void +XAAOverPolyFillRectOpaqueStippled( + DrawablePtr pDraw, + GCPtr pGC, + int nrectFill, + xRectangle *prectInit +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolyFillRectOpaqueStippled)(pDraw, pGC, nrectFill, prectInit); +} + +static void +XAAOverPolyFillRectTiled( + DrawablePtr pDraw, + GCPtr pGC, + int nrectFill, + xRectangle *prectInit +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolyFillRectTiled)(pDraw, pGC, nrectFill, prectInit); +} + + +static void +XAAOverFillSpansSolid( + DrawablePtr pDraw, + GCPtr pGC, + int nInit, + DDXPointPtr ppt, + int *pwidth, + int fSorted +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->FillSpansSolid)( + pDraw, pGC, nInit, ppt, pwidth, fSorted); +} + + +static void +XAAOverFillSpansStippled( + DrawablePtr pDraw, + GCPtr pGC, + int nInit, + DDXPointPtr ppt, + int *pwidth, + int fSorted +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->FillSpansStippled)(pDraw, pGC, nInit, ppt, pwidth, fSorted); +} + +static void +XAAOverFillSpansOpaqueStippled( + DrawablePtr pDraw, + GCPtr pGC, + int nInit, + DDXPointPtr ppt, + int *pwidth, + int fSorted +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->FillSpansOpaqueStippled)( + pDraw, pGC, nInit, ppt, pwidth, fSorted); +} + + +static void +XAAOverFillSpansTiled( + DrawablePtr pDraw, + GCPtr pGC, + int nInit, + DDXPointPtr ppt, + int *pwidth, + int fSorted +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->FillSpansTiled)(pDraw, pGC, nInit, ppt, pwidth, fSorted); +} + +static int +XAAOverPolyText8TE( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + return (*pOverPriv->PolyText8TE)(pDraw, pGC, x, y, count, chars); +} + + +static int +XAAOverPolyText16TE( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + return (*pOverPriv->PolyText16TE)(pDraw, pGC, x, y, count, chars); +} + + +static void +XAAOverImageText8TE( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->ImageText8TE)(pDraw, pGC, x, y, count, chars); +} + + +static void +XAAOverImageText16TE( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->ImageText16TE)(pDraw, pGC, x, y, count, chars); +} + +static void +XAAOverImageGlyphBltTE( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->ImageGlyphBltTE)( + pDraw, pGC, xInit, yInit, nglyph, ppci, pglyphBase); +} + +static void +XAAOverPolyGlyphBltTE( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolyGlyphBltTE)( + pDraw, pGC, xInit, yInit, nglyph, ppci, pglyphBase); +} + +static int +XAAOverPolyText8NonTE( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + return (*pOverPriv->PolyText8NonTE)(pDraw, pGC, x, y, count, chars); +} + + +static int +XAAOverPolyText16NonTE( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + return (*pOverPriv->PolyText16NonTE)(pDraw, pGC, x, y, count, chars); +} + +static void +XAAOverImageText8NonTE( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->ImageText8NonTE)(pDraw, pGC, x, y, count, chars); +} + +static void +XAAOverImageText16NonTE( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->ImageText16NonTE)(pDraw, pGC, x, y, count, chars); +} + + +static void +XAAOverImageGlyphBltNonTE( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->ImageGlyphBltNonTE)( + pDraw, pGC, xInit, yInit, nglyph, ppci, pglyphBase); +} + +static void +XAAOverPolyGlyphBltNonTE( + DrawablePtr pDraw, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolyGlyphBltNonTE)( + pDraw, pGC, xInit, yInit, nglyph, ppci, pglyphBase); +} + +static void +XAAOverPolyRectangleThinSolid( + DrawablePtr pDraw, + GCPtr pGC, + int nRectsInit, + xRectangle *pRectsInit +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolyRectangleThinSolid)(pDraw, pGC, nRectsInit, pRectsInit); +} + + + +static void +XAAOverPolylinesWideSolid( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pPts +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolylinesWideSolid)(pDraw, pGC, mode, npt, pPts); +} + + +static void +XAAOverPolylinesThinSolid( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pPts +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolylinesThinSolid)(pDraw, pGC, mode, npt, pPts); +} + +static void +XAAOverPolySegmentThinSolid( + DrawablePtr pDraw, + GCPtr pGC, + int nseg, + xSegment *pSeg +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolySegmentThinSolid)(pDraw, pGC, nseg, pSeg); +} + +static void +XAAOverPolylinesThinDashed( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pPts +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolylinesThinDashed)(pDraw, pGC, mode, npt, pPts); +} + +static void +XAAOverPolySegmentThinDashed( + DrawablePtr pDraw, + GCPtr pGC, + int nseg, + xSegment *pSeg +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolySegmentThinDashed)(pDraw, pGC, nseg, pSeg); +} + + +static void +XAAOverFillPolygonSolid( + DrawablePtr pDraw, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr ptsIn +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->FillPolygonSolid)(pDraw, pGC, shape, mode, count, ptsIn); +} + +static void +XAAOverFillPolygonStippled( + DrawablePtr pDraw, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr ptsIn +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->FillPolygonStippled)(pDraw, pGC, shape, mode, count, ptsIn); +} + + +static void +XAAOverFillPolygonOpaqueStippled( + DrawablePtr pDraw, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr ptsIn +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->FillPolygonOpaqueStippled)( + pDraw, pGC, shape, mode, count, ptsIn); +} + +static void +XAAOverFillPolygonTiled( + DrawablePtr pDraw, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr ptsIn +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->FillPolygonTiled)(pDraw, pGC, shape, mode, count, ptsIn); +} + + +static void +XAAOverPolyFillArcSolid( + DrawablePtr pDraw, + GCPtr pGC, + int narcs, + xArc *parcs +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PolyFillArcSolid)(pDraw, pGC, narcs, parcs); +} + + +static void +XAAOverPutImage( + DrawablePtr pDraw, + GCPtr pGC, + int depth, + int x, + int y, + int w, + int h, + int leftPad, + int format, + char *pImage +){ + XAAOverlayPtr pOverPriv = GET_OVERLAY_PRIV(pGC->pScreen); + + SWITCH_DEPTH(pGC->depth); + + (*pOverPriv->PutImage)(pDraw, pGC, depth, x, y, w, h, + leftPad, format, pImage); +} + diff --git a/xorg-server/hw/xfree86/xaa/xaaPCache.c b/xorg-server/hw/xfree86/xaa/xaaPCache.c index 7e3011bd5..62726d539 100644 --- a/xorg-server/hw/xfree86/xaa/xaaPCache.c +++ b/xorg-server/hw/xfree86/xaa/xaaPCache.c @@ -1,2380 +1,2380 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "gc.h" -#include "mi.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "regionstr.h" -#include "servermd.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaacexp.h" -#include "xaalocal.h" -#include "xaawrap.h" - -#define MAX_COLOR 32 -#define MAX_MONO 32 -#define MAX_8 32 -#define MAX_128 32 -#define MAX_256 32 -#define MAX_512 16 - -static int CacheInitIndex = -1; -#define CACHEINIT(p) ((p)->privates[CacheInitIndex].val) - - -typedef struct _CacheLink { - int x; - int y; - int w; - int h; - struct _CacheLink *next; -} CacheLink, *CacheLinkPtr; - - -static void -TransferList(CacheLinkPtr list, XAACacheInfoPtr array, int num) -{ - while(num--) { - array->x = list->x; - array->y = list->y; - array->w = list->w; - array->h = list->h; - array->serialNumber = 0; - array->fg = array->bg = -1; - list = list->next; - array++; - } -} - - - -static CacheLinkPtr -Enlist(CacheLinkPtr link, int x, int y, int w, int h) -{ - CacheLinkPtr newLink; - - newLink = xalloc(sizeof(CacheLink)); - newLink->next = link; - newLink->x = x; newLink->y = y; - newLink->w = w; newLink->h = h; - return newLink; -} - - - -static CacheLinkPtr -Delist(CacheLinkPtr link) { - CacheLinkPtr ret = NULL; - - if(link) { - ret = link->next; - xfree(link); - } - return ret; -} - - - -static void -FreeList(CacheLinkPtr link) { - CacheLinkPtr tmp; - - while(link) { - tmp = link; - link = link->next; - xfree(tmp); - } -} - - - -static CacheLinkPtr -QuadLinks(CacheLinkPtr big, CacheLinkPtr little) -{ - /* CAUTION: This doesn't free big */ - int w1, w2, h1, h2; - - while(big) { - w1 = big->w >> 1; - w2 = big->w - w1; - h1 = big->h >> 1; - h2 = big->h - h1; - - little = Enlist(little, big->x, big->y, w1, h1); - little = Enlist(little, big->x + w1, big->y, w2, h1); - little = Enlist(little, big->x, big->y + h1, w1, h2); - little = Enlist(little, big->x + w1, big->y + h1, w2, h2); - - big = big->next; - } - return little; -} - - -static void -SubdivideList(CacheLinkPtr *large, CacheLinkPtr *small) -{ - CacheLinkPtr big = *large; - CacheLinkPtr little = *small; - int size = big->w >> 1; - - little = Enlist(little, big->x, big->y, size, size); - little = Enlist(little, big->x + size, big->y, size, size); - little = Enlist(little, big->x, big->y + size, size, size); - little = Enlist(little, big->x + size, big->y + size, size, size); - *small = little; - big = Delist(big); - *large = big; -} - -static void -FreePixmapCachePrivate(XAAPixmapCachePrivatePtr pPriv) -{ - if(!pPriv) return; - - if(pPriv->Info512) - xfree(pPriv->Info512); - if(pPriv->Info256) - xfree(pPriv->Info256); - if(pPriv->Info128) - xfree(pPriv->Info128); - if(pPriv->InfoColor) - xfree(pPriv->InfoColor); - if(pPriv->InfoMono) - xfree(pPriv->InfoMono); - if(pPriv->InfoPartial) - xfree(pPriv->InfoPartial); - - xfree(pPriv); -} - -void -XAAClosePixmapCache(ScreenPtr pScreen) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - - if(infoRec->PixmapCachePrivate) - FreePixmapCachePrivate( - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate); - - infoRec->PixmapCachePrivate = NULL; -} - - - -static CacheLinkPtr -ThinOutPartials( - CacheLinkPtr ListPartial, - int *num, int *maxw, int *maxh -) { -/* This guy's job is to get at least 4 big slots out of a list of fragments */ - - CacheLinkPtr List64, List32, List16, List8, pCur, next, ListKeepers; - int Num64, Num32, Num16, Num8, NumKeepers; - int w, h; - - List64 = List32 = List16 = List8 = ListKeepers = NULL; - Num64 = Num32 = Num16 = Num8 = NumKeepers = 0; - w = h = 0; - - /* We sort partials by how large a square tile they can cache. - If a partial can't store a 64x64, 32x32, 16x16 or 8x8 tile, - we free it. */ - - pCur = ListPartial; - while(pCur) { - next = pCur->next; - if((pCur->w >= 64) && (pCur->h >= 64)) { - pCur->next = List64; List64 = pCur; - Num64++; - } else - if((pCur->w >= 32) && (pCur->h >= 32)) { - pCur->next = List32; List32 = pCur; - Num32++; - } else - if((pCur->w >= 16) && (pCur->h >= 16)) { - pCur->next = List16; List16 = pCur; - Num16++; - } else - if((pCur->w >= 8) && (pCur->h >= 8)) { - pCur->next = List8; List8 = pCur; - Num8++; - } else { - xfree(pCur); - } - - pCur = next; - } - - /* We save all the tiles from the largest bin that we can get - at least 4 of. If there are too few of a bigger slot, we - cut it in fourths to make smaller slots. */ - - if(Num64 >= 4) { - ListKeepers = List64; List64 = NULL; - NumKeepers = Num64; - goto GOT_EM; - } else if(Num64) { - List32 = QuadLinks(List64, List32); - Num32 += Num64 * 4; - Num64 = 0; - } - - if(Num32 >= 4) { - ListKeepers = List32; List32 = NULL; - NumKeepers = Num32; - goto GOT_EM; - } else if(Num32) { - List16 = QuadLinks(List32, List16); - Num16 += Num32 * 4; - Num32 = 0; - } - - if(Num16 >= 4) { - ListKeepers = List16; List16 = NULL; - NumKeepers = Num16; - goto GOT_EM; - } else if(Num16) { - List8 = QuadLinks(List16, List8); - Num8 += Num16 * 4; - Num16 = 0; - } - - if(Num8 >= 4) { - ListKeepers = List8; List8 = NULL; - NumKeepers = Num8; - goto GOT_EM; - } - -GOT_EM: - - /* Free the ones we aren't using */ - - if(List64) FreeList(List64); - if(List32) FreeList(List32); - if(List16) FreeList(List16); - if(List8) FreeList(List8); - - - /* Enlarge the slots if we can */ - - if(ListKeepers) { - CacheLinkPtr pLink = ListKeepers; - w = h = 128; - - while(pLink) { - if(pLink->w < w) w = pLink->w; - if(pLink->h < h) h = pLink->h; - pLink = pLink->next; - } - } - - *maxw = w; - *maxh = h; - *num = NumKeepers; - return ListKeepers; -} - -static void -ConvertColorToMono( - CacheLinkPtr *ColorList, - int ColorW, int ColorH, - CacheLinkPtr *MonoList, - int MonoW, int MonoH -){ - int x, y, w; - - x = (*ColorList)->x; y = (*ColorList)->y; - *ColorList = Delist(*ColorList); - - while(ColorH) { - ColorH -= MonoH; - for(w = 0; w <= (ColorW - MonoW); w += MonoW) - *MonoList = Enlist(*MonoList, x + w, y + ColorH, MonoW, MonoH); - } -} - -static void -ConvertAllPartialsTo8x8( - int *NumMono, int *NumColor, - CacheLinkPtr ListPartial, - CacheLinkPtr *ListMono, - CacheLinkPtr *ListColor, - XAAInfoRecPtr infoRec -){ -/* This guy extracts as many 8x8 slots as it can out of fragments */ - - int ColorH = infoRec->CacheHeightColor8x8Pattern; - int ColorW = infoRec->CacheWidthColor8x8Pattern; - int MonoH = infoRec->CacheHeightMono8x8Pattern; - int MonoW = infoRec->CacheWidthMono8x8Pattern; - int x, y, w, Height, Width; - Bool DoColor = (infoRec->PixmapCacheFlags & CACHE_COLOR_8x8); - Bool DoMono = (infoRec->PixmapCacheFlags & CACHE_MONO_8x8); - CacheLinkPtr pLink = ListPartial; - CacheLinkPtr MonoList = *ListMono, ColorList = *ListColor; - - if(DoColor && DoMono) { - /* we assume color patterns take more space than color ones */ - if(MonoH > ColorH) ColorH = MonoH; - if(MonoW > ColorW) ColorW = MonoW; - } - - /* Break up the area into as many Color and Mono slots as we can */ - - while(pLink) { - Height = pLink->h; - Width = pLink->w; - x = pLink->x; - y = pLink->y; - - if(DoColor) { - while(Height >= ColorH) { - Height -= ColorH; - for(w = 0; w <= (Width - ColorW); w += ColorW) { - ColorList = Enlist( - ColorList, x + w, y + Height, ColorW, ColorH); - (*NumColor)++; - } - } - } - - if(DoMono && (Height >= MonoH)) { - while(Height >= MonoH) { - Height -= MonoH; - for(w = 0; w <= (Width - MonoW); w += MonoW) { - MonoList = Enlist( - MonoList, x + w, y + Height, MonoW, MonoH); - (*NumMono)++; - } - } - } - - pLink = pLink->next; - } - - - *ListMono = MonoList; - *ListColor = ColorList; - FreeList(ListPartial); -} - - -static CacheLinkPtr -ExtractOneThatFits(CacheLinkPtr *initList, int w, int h) -{ - CacheLinkPtr list = *initList; - CacheLinkPtr prev = NULL; - - while(list) { - if((list->w >= w) && (list->h >= h)) - break; - prev = list; - list = list->next; - } - - if(list) { - if(prev) - prev->next = list->next; - else - *initList = list->next; - - list->next = NULL; - } - - return list; -} - - -static CacheLinkPtr -ConvertSomePartialsTo8x8( - int *NumMono, int *NumColor, int *NumPartial, - CacheLinkPtr ListPartial, - CacheLinkPtr *ListMono, - CacheLinkPtr *ListColor, - int *maxw, int *maxh, - XAAInfoRecPtr infoRec -){ -/* This guy tries to get 4 of each type of 8x8 slot requested out of - a list of fragments all while trying to retain some big fragments - for the cache blits */ - - int ColorH = infoRec->CacheHeightColor8x8Pattern; - int ColorW = infoRec->CacheWidthColor8x8Pattern; - int MonoH = infoRec->CacheHeightMono8x8Pattern; - int MonoW = infoRec->CacheWidthMono8x8Pattern; - Bool DoColor = (infoRec->PixmapCacheFlags & CACHE_COLOR_8x8); - Bool DoMono = (infoRec->PixmapCacheFlags & CACHE_MONO_8x8); - CacheLinkPtr List64, List32, List16, List8, pCur, next, ListKeepers; - CacheLinkPtr MonoList = *ListMono, ColorList = *ListColor; - int Num64, Num32, Num16, Num8, NumKeepers; - int w, h, Width, Height; - int MonosPerColor = 1; - - if(DoColor && DoMono) { - /* we assume color patterns take more space than color ones */ - if(MonoH > ColorH) ColorH = MonoH; - if(MonoW > ColorW) ColorW = MonoW; - MonosPerColor = (ColorH/MonoH) * (ColorW/MonoW); - } - - List64 = List32 = List16 = List8 = ListKeepers = MonoList = ColorList = NULL; - Num64 = Num32 = Num16 = Num8 = NumKeepers = 0; - Width = Height = 0; - - /* We sort partials by how large a square tile they can cache. - We make 8x8 patterns from the leftovers if we can. */ - - pCur = ListPartial; - while(pCur) { - next = pCur->next; - if((pCur->w >= 64) && (pCur->h >= 64)) { - pCur->next = List64; List64 = pCur; - Num64++; - } else - if((pCur->w >= 32) && (pCur->h >= 32)) { - pCur->next = List32; List32 = pCur; - Num32++; - } else - if((pCur->w >= 16) && (pCur->h >= 16)) { - pCur->next = List16; List16 = pCur; - Num16++; - } else - if((pCur->w >= 8) && (pCur->h >= 8)) { - pCur->next = List8; List8 = pCur; - Num8++; - } else { - h = pCur->h; - if(DoColor && (pCur->w >= ColorW) && (h >= ColorH)) { - while(h >= ColorH) { - h -= ColorH; - for(w = 0; w <= (pCur->w - ColorW); w += ColorW) { - ColorList = Enlist( ColorList, - pCur->x + w, pCur->y + h, ColorW, ColorH); - (*NumColor)++; - } - } - } - if(DoMono && (pCur->w >= MonoW) && (h >= MonoH)) { - while(h >= MonoH) { - h -= MonoH; - for(w = 0; w <= (pCur->w - MonoW); w += MonoW) { - MonoList = Enlist( MonoList, - pCur->x + w, pCur->y + h, MonoW, MonoH); - (*NumMono)++; - } - } - } - xfree(pCur); - } - - pCur = next; - } - - /* Try to extract at least 4 of each type of 8x8 slot that we need */ - - if(DoColor) { - CacheLinkPtr theOne; - while(*NumColor < 4) { - theOne = NULL; - if(Num8) { - if((theOne = ExtractOneThatFits(&List8, ColorW, ColorH))) - Num8--; - } - if(Num16 && !theOne) { - if((theOne = ExtractOneThatFits(&List16, ColorW, ColorH))) - Num16--; - } - if(Num32 && !theOne) { - if((theOne = ExtractOneThatFits(&List32, ColorW, ColorH))) - Num32--; - } - if(Num64 && !theOne) { - if((theOne = ExtractOneThatFits(&List64, ColorW, ColorH))) - Num64--; - } - - if(!theOne) break; - - - ConvertAllPartialsTo8x8(NumMono, NumColor, theOne, - &MonoList, &ColorList, infoRec); - - if(DoMono) { - while(*NumColor && (*NumMono < 4)) { - ConvertColorToMono(&ColorList, ColorW, ColorH, - &MonoList, MonoW, MonoH); - (*NumColor)--; *NumMono += MonosPerColor; - } - } - } - } - - if(DoMono) { - CacheLinkPtr theOne; - while(*NumMono < 4) { - theOne = NULL; - if(Num8) { - if((theOne = ExtractOneThatFits(&List8, MonoW, MonoH))) - Num8--; - } - if(Num16 && !theOne) { - if((theOne = ExtractOneThatFits(&List16, MonoW, MonoH))) - Num16--; - } - if(Num32 && !theOne) { - if((theOne = ExtractOneThatFits(&List32, MonoW, MonoH))) - Num32--; - } - if(Num64 && !theOne) { - if((theOne = ExtractOneThatFits(&List64, MonoW, MonoH))) - Num64--; - } - - if(!theOne) break; - - ConvertAllPartialsTo8x8(NumMono, NumColor, theOne, - &MonoList, &ColorList, infoRec); - } - } - - /* We save all the tiles from the largest bin that we can get - at least 4 of. If there are too few of a bigger slot, we - cut it in fourths to make smaller slots. */ - - if(Num64 >= 4) { - ListKeepers = List64; List64 = NULL; - NumKeepers = Num64; - goto GOT_EM; - } else if(Num64) { - List32 = QuadLinks(List64, List32); - Num32 += Num64 * 4; - Num64 = 0; - } - - if(Num32 >= 4) { - ListKeepers = List32; List32 = NULL; - NumKeepers = Num32; - goto GOT_EM; - } else if(Num32) { - List16 = QuadLinks(List32, List16); - Num16 += Num32 * 4; - Num32 = 0; - } - - if(Num16 >= 4) { - ListKeepers = List16; List16 = NULL; - NumKeepers = Num16; - goto GOT_EM; - } else if(Num16) { - List8 = QuadLinks(List16, List8); - Num8 += Num16 * 4; - Num16 = 0; - } - - if(Num8 >= 4) { - ListKeepers = List8; List8 = NULL; - NumKeepers = Num8; - goto GOT_EM; - } - -GOT_EM: - - /* Free the ones we aren't using */ - - if(List64) - ConvertAllPartialsTo8x8(NumMono, NumColor, List64, - &MonoList, &ColorList, infoRec); - if(List32) - ConvertAllPartialsTo8x8(NumMono, NumColor, List32, - &MonoList, &ColorList, infoRec); - if(List16) - ConvertAllPartialsTo8x8(NumMono, NumColor, List16, - &MonoList, &ColorList, infoRec); - if(List8) - ConvertAllPartialsTo8x8(NumMono, NumColor, List8, - &MonoList, &ColorList, infoRec); - - - /* Enlarge the slots if we can */ - - if(ListKeepers) { - CacheLinkPtr pLink = ListKeepers; - Width = Height = 128; - - while(pLink) { - if(pLink->w < Width) Width = pLink->w; - if(pLink->h < Height) Height = pLink->h; - pLink = pLink->next; - } - } - - *ListMono = MonoList; - *ListColor = ColorList; - *maxw = Width; - *maxh = Height; - *NumPartial = NumKeepers; - return ListKeepers; -} - - -void -XAAInitPixmapCache( - ScreenPtr pScreen, - RegionPtr areas, - pointer data -) { - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - XAAInfoRecPtr infoRec = (XAAInfoRecPtr)data; - XAAPixmapCachePrivatePtr pCachePriv; - BoxPtr pBox = REGION_RECTS(areas); - int nBox = REGION_NUM_RECTS(areas); - int Num512, Num256, Num128, NumPartial, NumColor, NumMono; - int Target512, Target256; - CacheLinkPtr List512, List256, List128, ListPartial, ListColor, ListMono; - int x, y, w, h, ntotal, granularity, width, height, i; - int MaxPartialWidth, MaxPartialHeight; - - infoRec->MaxCacheableTileWidth = 0; - infoRec->MaxCacheableTileHeight = 0; - infoRec->MaxCacheableStippleHeight = 0; - infoRec->MaxCacheableStippleWidth = 0; - infoRec->UsingPixmapCache = FALSE; - - - if(!nBox || !pBox || !(infoRec->Flags & PIXMAP_CACHE)) - return; - - /* Allocate a persistent per-screen init flag to control messages */ - if (CacheInitIndex < 0) - CacheInitIndex = xf86AllocateScrnInfoPrivateIndex(); - - /* free the old private data if it exists */ - if(infoRec->PixmapCachePrivate) { - FreePixmapCachePrivate( - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate); - infoRec->PixmapCachePrivate = NULL; - } - - Num512 = Num256 = Num128 = NumPartial = NumMono = NumColor = 0; - List512 = List256 = List128 = ListPartial = ListMono = ListColor = NULL; - granularity = infoRec->CachePixelGranularity; - if(granularity <= 1) granularity = 0; - - /* go through the boxes and break it into as many pieces as we can fit */ - - while(nBox--) { - x = pBox->x1; - if(granularity) { - int tmp = x % granularity; - if(tmp) x += (granularity - tmp); - } - width = pBox->x2 - x; - if(width <= 0) {pBox++; continue;} - - y = pBox->y1; - height = pBox->y2 - y; - - for(h = 0; h <= (height - 512); h += 512) { - for(w = 0; w <= (width - 512); w += 512) { - List512 = Enlist(List512, x + w, y + h, 512, 512); - Num512++; - } - for(; w <= (width - 256); w += 256) { - List256 = Enlist(List256, x + w, y + h, 256, 256); - List256 = Enlist(List256, x + w, y + h + 256, 256, 256); - Num256 += 2; - } - for(; w <= (width - 128); w += 128) { - List128 = Enlist(List128, x + w, y + h, 128, 128); - List128 = Enlist(List128, x + w, y + h + 128, 128, 128); - List128 = Enlist(List128, x + w, y + h + 256, 128, 128); - List128 = Enlist(List128, x + w, y + h + 384, 128, 128); - Num128 += 4; - } - if(w < width) { - int d = width - w; - ListPartial = Enlist(ListPartial, x + w, y + h, d, 128); - ListPartial = Enlist(ListPartial, x + w, y + h + 128, d, 128); - ListPartial = Enlist(ListPartial, x + w, y + h + 256, d, 128); - ListPartial = Enlist(ListPartial, x + w, y + h + 384, d, 128); - NumPartial += 4; - } - } - for(; h <= (height - 256); h += 256) { - for(w = 0; w <= (width - 256); w += 256) { - List256 = Enlist(List256, x + w, y + h, 256, 256); - Num256++; - } - for(; w <= (width - 128); w += 128) { - List128 = Enlist(List128, x + w, y + h, 128, 128); - List128 = Enlist(List128, x + w, y + h + 128, 128, 128); - Num128 += 2; - } - if(w < width) { - int d = width - w; - ListPartial = Enlist(ListPartial, x + w, y + h, d, 128); - ListPartial = Enlist(ListPartial, x + w, y + h + 128, d, 128); - NumPartial += 2; - } - } - for(; h <= (height - 128); h += 128) { - for(w = 0; w <= (width - 128); w += 128) { - List128 = Enlist(List128, x + w, y + h, 128, 128); - Num128++; - } - if(w < width) { - ListPartial = Enlist( - ListPartial, x + w, y + h, width - w, 128); - NumPartial++; - } - } - if(h < height) { - int d = height - h; - for(w = 0; w <= (width - 128); w += 128) { - ListPartial = Enlist(ListPartial, x + w, y + h, 128, d); - NumPartial++; - } - if(w < width) { - ListPartial = Enlist(ListPartial, x + w, y + h, width - w, d); - NumPartial++; - } - } - pBox++; - } - - -/* - by this point we've carved the space into as many 512x512, 256x256 - and 128x128 blocks as we could fit. We will then break larger - blocks into smaller ones if we need to. The rules are as follows: - - 512x512 - - 1) Don't take up more than half the memory. - 2) Don't bother if you can't get at least four. - 3) Don't make more than MAX_512. - 4) Don't have any of there are no 256x256s. - - 256x256 - - 1) Don't take up more than a quarter of the memory enless there - aren't any 512x512s. Then we can take up to half. - 2) Don't bother if you can't get at least four. - 3) Don't make more than MAX_256. - - 128x128 - - 1) Don't make more than MAX_128. - - We don't bother with the partial blocks unless we can use them - for 8x8 pattern fills or we are short on larger blocks. - -*/ - - ntotal = Num128 + (Num256<<2) + (Num512<<4); - - Target512 = ntotal >> 5; - if(Target512 < 4) Target512 = 0; - if(!Target512) Target256 = ntotal >> 3; - else Target256 = ntotal >> 4; - if(Target256 < 4) Target256 = 0; - - if(Num512 && Num256 < 4) { - while(Num512 && Num256 < Target256) { - SubdivideList(&List512, &List256); - Num256 += 4; Num512--; - } - } - - if(!Num512) { /* no room */ - } else if((Num512 < 4) || (!Target512)) { - while(Num512) { - SubdivideList(&List512, &List256); - Num256 += 4; Num512--; - } - } else if((Num512 > MAX_512) || (Num512 > Target512)){ - while(Num512 > MAX_512) { - SubdivideList(&List512, &List256); - Num256 += 4; Num512--; - } - while(Num512 > Target512) { - if(Num256 < MAX_256) { - SubdivideList(&List512, &List256); - Num256 += 4; Num512--; - } else break; - } - } - - if(!Num256) { /* no room */ - } else if((Num256 < 4) || (!Target256)) { - while(Num256) { - SubdivideList(&List256, &List128); - Num128 += 4; Num256--; - } - } else if((Num256 > MAX_256) || (Num256 > Target256)) { - while(Num256 > MAX_256) { - SubdivideList(&List256, &List128); - Num128 += 4; Num256--; - } - while(Num256 > Target256) { - if(Num128 < MAX_128) { - SubdivideList(&List256, &List128); - Num128 += 4; Num256--; - } else break; - } - } - - if(Num128 && ((Num128 < 4) || (Num128 > MAX_128))) { - CacheLinkPtr next; - int max = (Num128 > MAX_128) ? MAX_128 : 0; - - /* - * Note: next is set in this way to work around a code generation - * bug in gcc 2.7.2.3. - */ - next = List128->next; - while(Num128 > max) { - List128->next = ListPartial; - ListPartial = List128; - if((List128 = next)) - next = List128->next; - NumPartial++; Num128--; - } - } - - MaxPartialHeight = MaxPartialWidth = 0; - - /* at this point we have as many 512x512 and 256x256 slots as we - want but may have an excess of 128x128 slots. We still need - to find out if we need 8x8 slots. We take these from the - partials if we have them. Otherwise, we break some 128x128's */ - - if(!(infoRec->PixmapCacheFlags & (CACHE_MONO_8x8 | CACHE_COLOR_8x8))) { - if(NumPartial) { - if(Num128) { /* don't bother with partials */ - FreeList(ListPartial); - NumPartial = 0; ListPartial = NULL; - } else { - /* We have no big slots. Weed out the unusable partials */ - ListPartial = ThinOutPartials(ListPartial, &NumPartial, - &MaxPartialWidth, &MaxPartialHeight); - } - } - } else { - int MonosPerColor = 1; - int ColorH = infoRec->CacheHeightColor8x8Pattern; - int ColorW = infoRec->CacheWidthColor8x8Pattern; - int MonoH = infoRec->CacheHeightMono8x8Pattern; - int MonoW = infoRec->CacheWidthMono8x8Pattern; - Bool DoColor = (infoRec->PixmapCacheFlags & CACHE_COLOR_8x8); - Bool DoMono = (infoRec->PixmapCacheFlags & CACHE_MONO_8x8); - - if(DoColor) infoRec->CanDoColor8x8 = FALSE; - if(DoMono) infoRec->CanDoMono8x8 = FALSE; - - if(DoColor && DoMono) { - /* we assume color patterns take more space than color ones */ - if(MonoH > ColorH) ColorH = MonoH; - if(MonoW > ColorW) ColorW = MonoW; - MonosPerColor = (ColorH/MonoH) * (ColorW/MonoW); - } - - if(Num128) { - if(NumPartial) { /* use all for 8x8 slots */ - ConvertAllPartialsTo8x8(&NumMono, &NumColor, - ListPartial, &ListMono, &ListColor, infoRec); - NumPartial = 0; ListPartial = NULL; - } - - /* Get some 8x8 slots from the 128 slots */ - while((Num128 > 4) && - ((NumMono < MAX_MONO) && (NumColor < MAX_COLOR))) { - CacheLinkPtr tmp = NULL; - - tmp = Enlist(tmp, List128->x, List128->y, - List128->w, List128->h); - List128 = Delist(List128); - Num128--; - - ConvertAllPartialsTo8x8(&NumMono, &NumColor, - tmp, &ListMono, &ListColor, infoRec); - } - } else if(NumPartial) { - /* We have share partials between 8x8 slots and tiles. */ - ListPartial = ConvertSomePartialsTo8x8(&NumMono, &NumColor, - &NumPartial, ListPartial, &ListMono, &ListColor, - &MaxPartialWidth, &MaxPartialHeight, infoRec); - } - - - if(DoMono && DoColor) { - if(NumColor && ((NumColor > MAX_COLOR) || (NumColor < 4))) { - int max = (NumColor > MAX_COLOR) ? MAX_COLOR : 0; - - while(NumColor > max) { - ConvertColorToMono(&ListColor, ColorW, ColorH, - &ListMono, MonoW, MonoH); - NumColor--; NumMono += MonosPerColor; - } - } - - /* favor Mono slots over Color ones */ - while((NumColor > 4) && (NumMono < MAX_MONO)) { - ConvertColorToMono(&ListColor, ColorW, ColorH, - &ListMono, MonoW, MonoH); - NumColor--; NumMono += MonosPerColor; - } - } - - if(NumMono && ((NumMono > MAX_MONO) || (NumMono < 4))) { - int max = (NumMono > MAX_MONO) ? MAX_MONO : 0; - - while(NumMono > max) { - ListMono = Delist(ListMono); - NumMono--; - } - } - if(NumColor && ((NumColor > MAX_COLOR) || (NumColor < 4))) { - int max = (NumColor > MAX_COLOR) ? MAX_COLOR : 0; - - while(NumColor > max) { - ListColor = Delist(ListColor); - NumColor--; - } - } - } - - - pCachePriv = xcalloc(1,sizeof(XAAPixmapCachePrivate)); - if(!pCachePriv) { - if(Num512) FreeList(List512); - if(Num256) FreeList(List256); - if(Num128) FreeList(List128); - if(NumPartial) FreeList(ListPartial); - if(NumColor) FreeList(ListColor); - if(NumMono) FreeList(ListMono); - return; - } - - infoRec->PixmapCachePrivate = (char*)pCachePriv; - - if(Num512) { - pCachePriv->Info512 = xcalloc(Num512,sizeof(XAACacheInfoRec)); - if(!pCachePriv->Info512) Num512 = 0; - if(Num512) TransferList(List512, pCachePriv->Info512, Num512); - FreeList(List512); - pCachePriv->Num512x512 = Num512; - } - if(Num256) { - pCachePriv->Info256 = xcalloc(Num256, sizeof(XAACacheInfoRec)); - if(!pCachePriv->Info256) Num256 = 0; - if(Num256) TransferList(List256, pCachePriv->Info256, Num256); - FreeList(List256); - pCachePriv->Num256x256 = Num256; - } - if(Num128) { - pCachePriv->Info128 = xcalloc(Num128, sizeof(XAACacheInfoRec)); - if(!pCachePriv->Info128) Num128 = 0; - if(Num128) TransferList(List128, pCachePriv->Info128, Num128); - FreeList(List128); - pCachePriv->Num128x128 = Num128; - } - - if(NumPartial) { - pCachePriv->InfoPartial = xcalloc(NumPartial, sizeof(XAACacheInfoRec)); - if(!pCachePriv->InfoPartial) NumPartial = 0; - if(NumPartial) - TransferList(ListPartial, pCachePriv->InfoPartial, NumPartial); - FreeList(ListPartial); - pCachePriv->NumPartial = NumPartial; - } - - if(NumColor) { - pCachePriv->InfoColor = xcalloc(NumColor, sizeof(XAACacheInfoRec)); - if(!pCachePriv->InfoColor) NumColor = 0; - if(NumColor) TransferList(ListColor, pCachePriv->InfoColor, NumColor); - FreeList(ListColor); - pCachePriv->NumColor = NumColor; - } - - if(NumMono) { - pCachePriv->InfoMono = xcalloc(NumMono, sizeof(XAACacheInfoRec)); - if(!pCachePriv->InfoMono) NumMono = 0; - if(NumMono) TransferList(ListMono, pCachePriv->InfoMono, NumMono); - FreeList(ListMono); - pCachePriv->NumMono = NumMono; - } - - - if(NumPartial) { - infoRec->MaxCacheableTileWidth = MaxPartialWidth; - infoRec->MaxCacheableTileHeight = MaxPartialHeight; - } - if(Num128) - infoRec->MaxCacheableTileWidth = infoRec->MaxCacheableTileHeight = 128; - if(Num256) - infoRec->MaxCacheableTileWidth = infoRec->MaxCacheableTileHeight = 256; - if(Num512) - infoRec->MaxCacheableTileWidth = infoRec->MaxCacheableTileHeight = 512; - - - infoRec->MaxCacheableStippleHeight = infoRec->MaxCacheableTileHeight; - infoRec->MaxCacheableStippleWidth = - infoRec->MaxCacheableTileWidth * pScrn->bitsPerPixel; - if(infoRec->ScreenToScreenColorExpandFillFlags & TRIPLE_BITS_24BPP) - infoRec->MaxCacheableStippleWidth /= 3; - - if(NumMono) { - if(!(infoRec->Mono8x8PatternFillFlags & - (HARDWARE_PATTERN_PROGRAMMED_ORIGIN | - HARDWARE_PATTERN_PROGRAMMED_BITS))) { - int numPerLine = - infoRec->CacheWidthMono8x8Pattern/infoRec->MonoPatternPitch; - - for(i = 0; i < 64; i++) { - pCachePriv->MonoOffsets[i].y = i/numPerLine; - pCachePriv->MonoOffsets[i].x = (i % numPerLine) * - infoRec->MonoPatternPitch; - } - } - infoRec->CanDoMono8x8 = TRUE; - } - if(NumColor) { - if(!(infoRec->Color8x8PatternFillFlags & - HARDWARE_PATTERN_PROGRAMMED_ORIGIN)) { - - for(i = 0; i < 64; i++) { - pCachePriv->ColorOffsets[i].y = i & 0x07; - pCachePriv->ColorOffsets[i].x = i & ~0x07; - } - } - infoRec->CanDoColor8x8 = TRUE; - } - - if(!CACHEINIT(pScrn)) { - xf86ErrorF("\tSetting up tile and stipple cache:\n"); - if(NumPartial) - xf86ErrorF("\t\t%i %ix%i slots\n", - NumPartial, MaxPartialWidth, MaxPartialHeight); - if(Num128) xf86ErrorF("\t\t%i 128x128 slots\n", Num128); - if(Num256) xf86ErrorF("\t\t%i 256x256 slots\n", Num256); - if(Num512) xf86ErrorF("\t\t%i 512x512 slots\n", Num512); - if(NumColor) xf86ErrorF("\t\t%i 8x8 color pattern slots\n", NumColor); - if(NumMono) xf86ErrorF("\t\t%i 8x8 color expansion slots\n", NumMono); - } - - if(!(NumPartial | Num128 | Num256 | Num512 | NumColor | NumMono)) { - if(!CACHEINIT(pScrn)) - xf86ErrorF("\t\tNot enough video memory for pixmap cache\n"); - } else infoRec->UsingPixmapCache = TRUE; - - CACHEINIT(pScrn) = 1; -} - -#if X_BYTE_ORDER == X_BIG_ENDIAN -static CARD32 StippleMasks[4] = { - 0x80808080, - 0xC0C0C0C0, - 0x00000000, - 0xF0F0F0F0 -}; -#else -static CARD32 StippleMasks[4] = { - 0x01010101, - 0x03030303, - 0x00000000, - 0x0F0F0F0F -}; -#endif - -Bool -XAACheckStippleReducibility(PixmapPtr pPixmap) -{ - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_DRAWABLE(&pPixmap->drawable); - CARD32 *IntPtr = (CARD32*)pPixmap->devPrivate.ptr; - int w = pPixmap->drawable.width; - int h = pPixmap->drawable.height; - int i; - CARD32 bits[8]; - CARD32 mask = SHIFT_R(0xFFFFFFFF,24); - - pPriv->flags |= REDUCIBILITY_CHECKED | REDUCIBLE_TO_2_COLOR; - pPriv->flags &= ~REDUCIBLE_TO_8x8; - - if((w > 32) || (h > 32) || (w & (w - 1)) || (h & (h - 1))) - return FALSE; - - i = (h > 8) ? 8 : h; - - switch(w) { - case 32: - while(i--) { - bits[i] = IntPtr[i] & mask; - if( (bits[i] != SHIFT_R((IntPtr[i] & SHIFT_L(mask, 8)), 8)) || - (bits[i] != SHIFT_R((IntPtr[i] & SHIFT_L(mask,16)),16)) || - (bits[i] != SHIFT_R((IntPtr[i] & SHIFT_L(mask,24)),24))) - return FALSE; - } - break; - case 16: - while(i--) { - bits[i] = IntPtr[i] & mask; - if(bits[i] != ((IntPtr[i] & SHIFT_R(SHIFT_L(mask,8),8)))) - return FALSE; - } - break; - default: - while(i--) - bits[i] = IntPtr[i] & mask; - break; - } - - switch(h) { - case 32: - if( (IntPtr[8] != IntPtr[16]) || (IntPtr[9] != IntPtr[17]) || - (IntPtr[10] != IntPtr[18]) || (IntPtr[11] != IntPtr[19]) || - (IntPtr[12] != IntPtr[20]) || (IntPtr[13] != IntPtr[21]) || - (IntPtr[14] != IntPtr[22]) || (IntPtr[15] != IntPtr[23]) || - (IntPtr[16] != IntPtr[24]) || (IntPtr[17] != IntPtr[25]) || - (IntPtr[18] != IntPtr[26]) || (IntPtr[19] != IntPtr[27]) || - (IntPtr[20] != IntPtr[28]) || (IntPtr[21] != IntPtr[29]) || - (IntPtr[22] != IntPtr[30]) || (IntPtr[23] != IntPtr[31])) - return FALSE; - /* fall through */ - case 16: - if( (IntPtr[0] != IntPtr[8]) || (IntPtr[1] != IntPtr[9]) || - (IntPtr[2] != IntPtr[10]) || (IntPtr[3] != IntPtr[11]) || - (IntPtr[4] != IntPtr[12]) || (IntPtr[5] != IntPtr[13]) || - (IntPtr[6] != IntPtr[14]) || (IntPtr[7] != IntPtr[15])) - return FALSE; - case 8: break; - case 1: bits[1] = bits[0]; - case 2: bits[2] = bits[0]; bits[3] = bits[1]; - case 4: bits[4] = bits[0]; bits[5] = bits[1]; - bits[6] = bits[2]; bits[7] = bits[3]; - break; - } - - pPriv->flags |= REDUCIBLE_TO_8x8; - - pPriv->pattern0 = bits[0] | SHIFT_L(bits[1],8) | SHIFT_L(bits[2],16) | SHIFT_L(bits[3],24); - pPriv->pattern1 = bits[4] | SHIFT_L(bits[5],8) | SHIFT_L(bits[6],16) | SHIFT_L(bits[7],24); - - if(w < 8) { - pPriv->pattern0 &= StippleMasks[w - 1]; - pPriv->pattern1 &= StippleMasks[w - 1]; - - switch(w) { - case 1: pPriv->pattern0 |= SHIFT_L(pPriv->pattern0,1); - pPriv->pattern1 |= SHIFT_L(pPriv->pattern1,1); - case 2: pPriv->pattern0 |= SHIFT_L(pPriv->pattern0,2); - pPriv->pattern1 |= SHIFT_L(pPriv->pattern1,2); - case 4: pPriv->pattern0 |= SHIFT_L(pPriv->pattern0,4); - pPriv->pattern1 |= SHIFT_L(pPriv->pattern1,4); - } - } - - if(infoRec->Mono8x8PatternFillFlags & BIT_ORDER_IN_BYTE_MSBFIRST) { - pPriv->pattern0 = SWAP_BITS_IN_BYTES(pPriv->pattern0); - pPriv->pattern1 = SWAP_BITS_IN_BYTES(pPriv->pattern1); - } - - - return TRUE; -} - - -Bool -XAACheckTileReducibility(PixmapPtr pPixmap, Bool checkMono) -{ - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); - CARD32 *IntPtr; - int w = pPixmap->drawable.width; - int h = pPixmap->drawable.height; - int pitch = pPixmap->devKind >> 2; - int dwords, i, j; - - pPriv->flags |= REDUCIBILITY_CHECKED; - pPriv->flags &= ~(REDUCIBILITY_CHECKED | REDUCIBLE_TO_2_COLOR); - - if((w > 32) || (h > 32) || (w & (w - 1)) || (h & (h - 1))) - return FALSE; - - dwords = ((w * pPixmap->drawable.bitsPerPixel) + 31) >> 5; - i = (h > 8) ? 8 : h; - - - if(w > 8) { - IntPtr = (CARD32*)pPixmap->devPrivate.ptr; - switch(pPixmap->drawable.bitsPerPixel) { - case 8: - while(i--) { - for(j = 2; j < dwords; j++) - if(IntPtr[j] != IntPtr[j & 0x01]) - return FALSE; - IntPtr += pitch; - } - break; - case 16: - while(i--) { - for(j = 4; j < dwords; j++) - if(IntPtr[j] != IntPtr[j & 0x03]) - return FALSE; - IntPtr += pitch; - } - break; - case 24: - while(i--) { - for(j = 6; j < dwords; j++) - if(IntPtr[j] != IntPtr[j % 6]) - return FALSE; - IntPtr += pitch; - } - break; - case 32: - while(i--) { - for(j = 8; j < dwords; j++) - if(IntPtr[j] != IntPtr[j & 0x07]) - return FALSE; - IntPtr += pitch; - } - break; - default: return FALSE; - } - - } - - - if(h == 32) { - CARD32 *IntPtr2, *IntPtr3, *IntPtr4; - i = 8; - IntPtr = (CARD32*)pPixmap->devPrivate.ptr; - IntPtr2 = IntPtr + (pitch << 3); - IntPtr3 = IntPtr2 + (pitch << 3); - IntPtr4 = IntPtr3 + (pitch << 3); - while(i--) { - for(j = 0; j < dwords; j++) - if((IntPtr[j] != IntPtr2[j]) || (IntPtr[j] != IntPtr3[j]) || - (IntPtr[j] != IntPtr4[j])) - return FALSE; - IntPtr += pitch; - IntPtr2 += pitch; - IntPtr3 += pitch; - IntPtr4 += pitch; - } - } else if (h == 16) { - CARD32 *IntPtr2; - i = 8; - IntPtr = (CARD32*)pPixmap->devPrivate.ptr; - IntPtr2 = IntPtr + (pitch << 3); - while(i--) { - for(j = 0; j < dwords; j++) - if(IntPtr[j] != IntPtr2[j]) - return FALSE; - IntPtr += pitch; - IntPtr2 += pitch; - } - } - - pPriv->flags |= REDUCIBLE_TO_8x8; - - if(checkMono) { - XAAInfoRecPtr infoRec = - GET_XAAINFORECPTR_FROM_DRAWABLE(&pPixmap->drawable); - unsigned char bits[8]; - int fg, bg = -1, x, y; - - i = (h > 8) ? 8 : h; - j = (w > 8) ? 8 : w; - - if(pPixmap->drawable.bitsPerPixel == 8) { - unsigned char *srcp = pPixmap->devPrivate.ptr; - fg = srcp[0]; - pitch = pPixmap->devKind; - for(y = 0; y < i; y++) { - bits[y] = 0; - for(x = 0; x < j; x++) { - if(srcp[x] != fg) { - if(bg == -1) bg = srcp[x]; - else if(bg != srcp[x]) return TRUE; - } else bits[y] |= 1 << x; - } - srcp += pitch; - } - } else if(pPixmap->drawable.bitsPerPixel == 16) { - unsigned short *srcp = (unsigned short*)pPixmap->devPrivate.ptr; - fg = srcp[0]; - pitch = pPixmap->devKind >> 1; - for(y = 0; y < i; y++) { - bits[y] = 0; - for(x = 0; x < j; x++) { - if(srcp[x] != fg) { - if(bg == -1) bg = srcp[x]; - else if(bg != srcp[x]) return TRUE; - } else bits[y] |= 1 << x; - } - srcp += pitch; - } - } else if(pPixmap->drawable.bitsPerPixel == 24) { - CARD32 val; - unsigned char *srcp = pPixmap->devPrivate.ptr; - fg = *((CARD32*)srcp) & 0x00FFFFFF; - pitch = pPixmap->devKind; - j *= 3; - for(y = 0; y < i; y++) { - bits[y] = 0; - for(x = 0; x < j; x+=3) { - val = *((CARD32*)(srcp+x)) & 0x00FFFFFF; - if(val != fg) { - if(bg == -1) bg = val; - else if(bg != val) - return TRUE; - } else bits[y] |= 1 << (x/3); - } - srcp += pitch; - } - } else if(pPixmap->drawable.bitsPerPixel == 32) { - IntPtr = (CARD32*)pPixmap->devPrivate.ptr; - fg = IntPtr[0]; - for(y = 0; y < i; y++) { - bits[y] = 0; - for(x = 0; x < j; x++) { - if(IntPtr[x] != fg) { - if(bg == -1) bg = IntPtr[x]; - else if(bg != IntPtr[x]) return TRUE; - } else bits[y] |= 1 << x; - } - IntPtr += pitch; - } - } else return TRUE; - - pPriv->fg = fg; - if(bg == -1) pPriv->bg = fg; - else pPriv->bg = bg; - - if(h < 8) { - switch(h) { - case 1: bits[1] = bits[0]; - case 2: bits[2] = bits[0]; bits[3] = bits[1]; - case 4: bits[4] = bits[0]; bits[5] = bits[1]; - bits[6] = bits[2]; bits[7] = bits[3]; - break; - } - } - - pPriv->pattern0 = - bits[0] | (bits[1]<<8) | (bits[2]<<16) | (bits[3]<<24); - pPriv->pattern1 = - bits[4] | (bits[5]<<8) | (bits[6]<<16) | (bits[7]<<24); - - if(w < 8) { - switch(w) { - case 1: pPriv->pattern0 |= (pPriv->pattern0 << 1); - pPriv->pattern1 |= (pPriv->pattern1 << 1); - case 2: pPriv->pattern0 |= (pPriv->pattern0 << 2); - pPriv->pattern1 |= (pPriv->pattern1 << 2); - case 4: pPriv->pattern0 |= (pPriv->pattern0 << 4); - pPriv->pattern1 |= (pPriv->pattern1 << 4); - } - } - pPriv->flags |= REDUCIBLE_TO_2_COLOR; - - if(infoRec->Mono8x8PatternFillFlags & BIT_ORDER_IN_BYTE_MSBFIRST) { - pPriv->pattern0 = SWAP_BITS_IN_BYTES(pPriv->pattern0); - pPriv->pattern1 = SWAP_BITS_IN_BYTES(pPriv->pattern1); - } - - } - - return TRUE; -} - - -void XAATileCache( - ScrnInfoPtr pScrn, - XAACacheInfoPtr pCache, - int w, int h -) { - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - - (*infoRec->SetupForScreenToScreenCopy)(pScrn, 1, 1, GXcopy, ~0, -1); - - while((w << 1) <= pCache->w) { - (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pCache->x, pCache->y, - pCache->x + w, pCache->y, w, h); - w <<= 1; - } - if(w != pCache->w) { - (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pCache->x, pCache->y, - pCache->x + w, pCache->y, pCache->w - w, h); - w = pCache->w; - } - - while((h << 1) <= pCache->h) { - (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pCache->x, pCache->y, - pCache->x, pCache->y + h, w, h); - h <<= 1; - } - if(h != pCache->h) { - (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pCache->x, pCache->y, - pCache->x, pCache->y + h, w, pCache->h - h); - } - SET_SYNC_FLAG(infoRec); -} - -XAACacheInfoPtr -XAACacheTile(ScrnInfoPtr pScrn, PixmapPtr pPix) -{ - int w = pPix->drawable.width; - int h = pPix->drawable.height; - int size = max(w, h); - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - XAAPixmapCachePrivatePtr pCachePriv = - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; - XAACacheInfoPtr pCache, cacheRoot = NULL; - int i, max = 0; - int *current; - - if(size <= 128) { - if(pCachePriv->Info128) { - cacheRoot = pCachePriv->Info128; - max = pCachePriv->Num128x128; - current = &pCachePriv->Current128; - } else { - cacheRoot = pCachePriv->InfoPartial; - max = pCachePriv->NumPartial; - current = &pCachePriv->CurrentPartial; - } - } else if(size <= 256) { - cacheRoot = pCachePriv->Info256; - max = pCachePriv->Num256x256; - current = &pCachePriv->Current256; - } else if(size <= 512) { - cacheRoot = pCachePriv->Info512; - max = pCachePriv->Num512x512; - current = &pCachePriv->Current512; - } else { /* something's wrong */ - ErrorF("Something's wrong in XAACacheTile()\n"); - return pCachePriv->Info128; - } - - pCache = cacheRoot; - - /* lets look for it */ - for(i = 0; i < max; i++, pCache++) { - if(pCache->serialNumber == pPix->drawable.serialNumber) { - pCache->trans_color = -1; - return pCache; - } - } - - pCache = &cacheRoot[(*current)++]; - if(*current >= max) *current = 0; - - pCache->serialNumber = pPix->drawable.serialNumber; - pCache->trans_color = pCache->bg = pCache->fg = -1; - pCache->orig_w = w; pCache->orig_h = h; - (*infoRec->WritePixmapToCache)( - pScrn, pCache->x, pCache->y, w, h, pPix->devPrivate.ptr, - pPix->devKind, pPix->drawable.bitsPerPixel, pPix->drawable.depth); - if(!(infoRec->PixmapCacheFlags & DO_NOT_TILE_COLOR_DATA) && - ((w != pCache->w) || (h != pCache->h))) - XAATileCache(pScrn, pCache, w, h); - - return pCache; -} - -XAACacheInfoPtr -XAACacheMonoStipple(ScrnInfoPtr pScrn, PixmapPtr pPix) -{ - int w = pPix->drawable.width; - int h = pPix->drawable.height; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - XAAPixmapCachePrivatePtr pCachePriv = - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; - XAACacheInfoPtr pCache, cacheRoot = NULL; - int i, max = 0, funcNo, pad, dwords, bpp = pScrn->bitsPerPixel; - int *current; - StippleScanlineProcPtr StippleFunc; - unsigned char *data, *srcPtr, *dstPtr; - - if((h <= 128) && (w <= 128 * bpp)) { - if(pCachePriv->Info128) { - cacheRoot = pCachePriv->Info128; - max = pCachePriv->Num128x128; - current = &pCachePriv->Current128; - } else { - cacheRoot = pCachePriv->InfoPartial; - max = pCachePriv->NumPartial; - current = &pCachePriv->CurrentPartial; - } - } else if((h <= 256) && (w <= 256 * bpp)){ - cacheRoot = pCachePriv->Info256; - max = pCachePriv->Num256x256; - current = &pCachePriv->Current256; - } else if((h <= 512) && (w <= 526 * bpp)){ - cacheRoot = pCachePriv->Info512; - max = pCachePriv->Num512x512; - current = &pCachePriv->Current512; - } else { /* something's wrong */ - ErrorF("Something's wrong in XAACacheMonoStipple()\n"); - return pCachePriv->Info128; - } - - pCache = cacheRoot; - - /* lets look for it */ - for(i = 0; i < max; i++, pCache++) { - if((pCache->serialNumber == pPix->drawable.serialNumber) && - (pCache->fg == -1) && (pCache->bg == -1)) { - pCache->trans_color = -1; - return pCache; - } - } - - pCache = &cacheRoot[(*current)++]; - if(*current >= max) *current = 0; - - pCache->serialNumber = pPix->drawable.serialNumber; - pCache->trans_color = pCache->bg = pCache->fg = -1; - pCache->orig_w = w; pCache->orig_h = h; - - if(w <= 32) { - if(w & (w - 1)) funcNo = 1; - else funcNo = 0; - } else funcNo = 2; - - pad = BitmapBytePad(pCache->w * bpp); - dwords = bytes_to_int32(pad); - dstPtr = data = (unsigned char*)xalloc(pad * pCache->h); - srcPtr = (unsigned char*)pPix->devPrivate.ptr; - - if(infoRec->ScreenToScreenColorExpandFillFlags & BIT_ORDER_IN_BYTE_MSBFIRST) - StippleFunc = XAAStippleScanlineFuncMSBFirst[funcNo]; - else - StippleFunc = XAAStippleScanlineFuncLSBFirst[funcNo]; - - /* don't bother generating more than we'll ever use */ - max = ((pScrn->displayWidth + w - 1) + 31) >> 5; - if(dwords > max) - dwords = max; - - for(i = 0; i < h; i++) { - (*StippleFunc)((CARD32*)dstPtr, (CARD32*)srcPtr, 0, w, dwords); - srcPtr += pPix->devKind; - dstPtr += pad; - } - - while((h<<1) <= pCache->h) { - memcpy(data + (pad * h), data, pad * h); - h <<= 1; - } - - if(h < pCache->h) - memcpy(data + (pad * h), data, pad * (pCache->h - h)); - - (*infoRec->WritePixmapToCache)( - pScrn, pCache->x, pCache->y, pCache->w, pCache->h, data, - pad, bpp, pScrn->depth); - - xfree(data); - - return pCache; -} - -XAACacheInfoPtr -XAACachePlanarMonoStipple(ScrnInfoPtr pScrn, PixmapPtr pPix) -{ - int w = pPix->drawable.width; - int h = pPix->drawable.height; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - XAAPixmapCachePrivatePtr pCachePriv = - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; - XAACacheInfoPtr pCache, cacheRoot = NULL; - int i, max = 0; - int *current; - - if((h <= 128) && (w <= 128)) { - if(pCachePriv->Info128) { - cacheRoot = pCachePriv->Info128; - max = pCachePriv->Num128x128; - current = &pCachePriv->Current128; - } else { - cacheRoot = pCachePriv->InfoPartial; - max = pCachePriv->NumPartial; - current = &pCachePriv->CurrentPartial; - } - } else if((h <= 256) && (w <= 256)){ - cacheRoot = pCachePriv->Info256; - max = pCachePriv->Num256x256; - current = &pCachePriv->Current256; - } else if((h <= 512) && (w <= 526)){ - cacheRoot = pCachePriv->Info512; - max = pCachePriv->Num512x512; - current = &pCachePriv->Current512; - } else { /* something's wrong */ - ErrorF("Something's wrong in XAACachePlanarMonoStipple()\n"); - return pCachePriv->Info128; - } - - pCache = cacheRoot; - - /* lets look for it */ - for(i = 0; i < max; i++, pCache++) { - if((pCache->serialNumber == pPix->drawable.serialNumber) && - (pCache->fg == -1) && (pCache->bg == -1)) { - pCache->trans_color = -1; - return pCache; - } - } - - pCache = &cacheRoot[(*current)++]; - if(*current >= max) *current = 0; - - pCache->serialNumber = pPix->drawable.serialNumber; - pCache->trans_color = pCache->bg = pCache->fg = -1; - pCache->orig_w = w; pCache->orig_h = h; - - /* Plane 0 holds the stipple. Plane 1 holds the inverted stipple */ - (*infoRec->WriteBitmapToCache)(pScrn, pCache->x, pCache->y, - pPix->drawable.width, pPix->drawable.height, pPix->devPrivate.ptr, - pPix->devKind, 1, 2); - if(!(infoRec->PixmapCacheFlags & DO_NOT_TILE_MONO_DATA) && - ((w != pCache->w) || (h != pCache->h))) - XAATileCache(pScrn, pCache, w, h); - - return pCache; -} - -XAACachePlanarMonoStippleProc -XAAGetCachePlanarMonoStipple(void) -{ - return XAACachePlanarMonoStipple; -} - -XAACacheInfoPtr -XAACacheStipple(ScrnInfoPtr pScrn, PixmapPtr pPix, int fg, int bg) -{ - int w = pPix->drawable.width; - int h = pPix->drawable.height; - int size = max(w, h); - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - XAAPixmapCachePrivatePtr pCachePriv = - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; - XAACacheInfoPtr pCache, cacheRoot = NULL; - int i, max = 0; - int *current; - - if(size <= 128) { - if(pCachePriv->Info128) { - cacheRoot = pCachePriv->Info128; - max = pCachePriv->Num128x128; - current = &pCachePriv->Current128; - } else { - cacheRoot = pCachePriv->InfoPartial; - max = pCachePriv->NumPartial; - current = &pCachePriv->CurrentPartial; - } - } else if(size <= 256) { - cacheRoot = pCachePriv->Info256; - max = pCachePriv->Num256x256; - current = &pCachePriv->Current256; - } else if(size <= 512) { - cacheRoot = pCachePriv->Info512; - max = pCachePriv->Num512x512; - current = &pCachePriv->Current512; - } else { /* something's wrong */ - ErrorF("Something's wrong in XAACacheStipple()\n"); - return pCachePriv->Info128; - } - - pCache = cacheRoot; - /* lets look for it */ - if(bg == -1) - for(i = 0; i < max; i++, pCache++) { - if((pCache->serialNumber == pPix->drawable.serialNumber) && - (fg == pCache->fg) && (pCache->fg != pCache->bg)) { - pCache->trans_color = pCache->bg; - return pCache; - } - } - else - for(i = 0; i < max; i++, pCache++) { - if((pCache->serialNumber == pPix->drawable.serialNumber) && - (fg == pCache->fg) && (bg == pCache->bg)) { - pCache->trans_color = -1; - return pCache; - } - } - - pCache = &cacheRoot[(*current)++]; - if(*current >= max) *current = 0; - - pCache->serialNumber = pPix->drawable.serialNumber; - pCache->fg = fg; - if(bg == -1) - pCache->trans_color = bg = fg ^ 1; - else - pCache->trans_color = -1; - pCache->bg = bg; - - pCache->orig_w = w; pCache->orig_h = h; - (*infoRec->WriteBitmapToCache)(pScrn, pCache->x, pCache->y, - pPix->drawable.width, pPix->drawable.height, pPix->devPrivate.ptr, - pPix->devKind, fg, bg); - if(!(infoRec->PixmapCacheFlags & DO_NOT_TILE_COLOR_DATA) && - ((w != pCache->w) || (h != pCache->h))) - XAATileCache(pScrn, pCache, w, h); - - return pCache; -} - - - -XAACacheInfoPtr -XAACacheMono8x8Pattern(ScrnInfoPtr pScrn, int pat0, int pat1) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - XAAPixmapCachePrivatePtr pCachePriv = - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; - XAACacheInfoPtr pCache = pCachePriv->InfoMono; - int i; - - for(i = 0; i < pCachePriv->NumMono; i++, pCache++) { - if(pCache->serialNumber && - (pCache->pat0 == pat0) && (pCache->pat1 == pat1)) - return pCache; - } - - /* OK, let's cache it */ - pCache = &pCachePriv->InfoMono[pCachePriv->CurrentMono++]; - if(pCachePriv->CurrentMono >= pCachePriv->NumMono) - pCachePriv->CurrentMono = 0; - - pCache->serialNumber = 1; /* we don't care since we do lookups by pattern */ - pCache->pat0 = pat0; - pCache->pat1 = pat1; - - (*infoRec->WriteMono8x8PatternToCache)(pScrn, pCache); - - return pCache; -} - - - -XAACacheInfoPtr -XAACacheColor8x8Pattern(ScrnInfoPtr pScrn, PixmapPtr pPix, int fg, int bg) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - XAAPixmapCachePrivatePtr pCachePriv = - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; - XAACacheInfoPtr pCache = pCachePriv->InfoColor; - XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(pPix); - int i; - - if(!(pixPriv->flags & REDUCIBLE_TO_2_COLOR)) { - for(i = 0; i < pCachePriv->NumColor; i++, pCache++) { - if(pCache->serialNumber == pPix->drawable.serialNumber) { - pCache->trans_color = -1; - return pCache; - } - } - pCache = &pCachePriv->InfoColor[pCachePriv->CurrentColor++]; - if(pCachePriv->CurrentColor >= pCachePriv->NumColor) - pCachePriv->CurrentColor = 0; - - pCache->serialNumber = pPix->drawable.serialNumber; - pCache->trans_color = pCache->fg = pCache->bg = -1; - } else { - int pat0 = pixPriv->pattern0; - int pat1 = pixPriv->pattern1; - - if(fg == -1) { /* it's a tile */ - fg = pixPriv->fg; bg = pixPriv->bg; - } - - if(bg == -1) { /* stipple */ - for(i = 0; i < pCachePriv->NumColor; i++, pCache++) { - if(pCache->serialNumber && - (pCache->pat0 == pat0) && (pCache->pat1 == pat1) && - (pCache->fg == fg) && (pCache->bg != fg)) { - pCache->trans_color = pCache->bg; - return pCache; - } - } - } else { /* opaque stipple */ - for(i = 0; i < pCachePriv->NumColor; i++, pCache++) { - if(pCache->serialNumber && - (pCache->pat0 == pat0) && (pCache->pat1 == pat1) && - (pCache->fg == fg) && (pCache->bg == bg)) { - pCache->trans_color = -1; - return pCache; - } - } - } - pCache = &pCachePriv->InfoColor[pCachePriv->CurrentColor++]; - if(pCachePriv->CurrentColor >= pCachePriv->NumColor) - pCachePriv->CurrentColor = 0; - - if(bg == -1) - pCache->trans_color = bg = fg ^ 1; - else - pCache->trans_color = -1; - - pCache->pat0 = pat0; pCache->pat1 = pat1; - pCache->fg = fg; pCache->bg = bg; - pCache->serialNumber = 1; - } - - (*infoRec->WriteColor8x8PatternToCache)(pScrn, pPix, pCache); - - return pCache; -} - - -void -XAAWriteBitmapToCache( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int fg, int bg -) { - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - - (*infoRec->WriteBitmap)(pScrn, x, y, w, h, src, srcwidth, - 0, fg, bg, GXcopy, ~0); -} - -void -XAAWriteBitmapToCacheLinear( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int fg, int bg -){ - ScreenPtr pScreen = pScrn->pScreen; - PixmapPtr pScreenPix, pDstPix; - XID gcvals[2]; - GCPtr pGC; - - pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); - - pDstPix = GetScratchPixmapHeader(pScreen, pScreenPix->drawable.width, - y + h, pScreenPix->drawable.depth, - pScreenPix->drawable.bitsPerPixel, - pScreenPix->devKind, - pScreenPix->devPrivate.ptr); - - pGC = GetScratchGC(pScreenPix->drawable.depth, pScreen); - gcvals[0] = fg; - gcvals[1] = bg; - DoChangeGC(pGC, GCForeground | GCBackground, gcvals, 0); - ValidateGC((DrawablePtr)pDstPix, pGC); - - /* We've unwrapped already so these ops miss a sync */ - SYNC_CHECK(pScrn); - - (*pGC->ops->PutImage)((DrawablePtr)pDstPix, pGC, 1, x, y, w, h, 0, - XYBitmap, (pointer)src); - - FreeScratchGC(pGC); - FreeScratchPixmapHeader(pDstPix); -} - - -void -XAAWritePixmapToCache( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int bpp, int depth -) { - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - - (*infoRec->WritePixmap)(pScrn, x, y, w, h, src, srcwidth, - GXcopy, ~0, -1, bpp, depth); -} - - - -void -XAAWritePixmapToCacheLinear( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int bpp, int depth -){ - ScreenPtr pScreen = pScrn->pScreen; - PixmapPtr pScreenPix, pDstPix; - GCPtr pGC; - - pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); - - pDstPix = GetScratchPixmapHeader(pScreen, x + w, y + h, - depth, bpp, pScreenPix->devKind, - pScreenPix->devPrivate.ptr); - - pGC = GetScratchGC(depth, pScreen); - ValidateGC((DrawablePtr)pDstPix, pGC); - - /* We've unwrapped already so these ops miss a sync */ - SYNC_CHECK(pScrn); - - if(bpp == BitsPerPixel(depth)) - (*pGC->ops->PutImage)((DrawablePtr)pDstPix, pGC, depth, x, y, w, - h, 0, ZPixmap, (pointer)src); - else { - PixmapPtr pSrcPix; - - pSrcPix = GetScratchPixmapHeader(pScreen, w, h, depth, bpp, - srcwidth, (pointer)src); - - (*pGC->ops->CopyArea)((DrawablePtr)pSrcPix, (DrawablePtr)pDstPix, - pGC, 0, 0, w, h, x, y); - - FreeScratchPixmapHeader(pSrcPix); - } - - FreeScratchGC(pGC); - FreeScratchPixmapHeader(pDstPix); -} - - -void -XAAWriteMono8x8PatternToCache( - ScrnInfoPtr pScrn, - XAACacheInfoPtr pCache -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - XAAPixmapCachePrivatePtr pCachePriv = - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; - unsigned char *data; - int pad, Bpp = (pScrn->bitsPerPixel >> 3); - - pCache->offsets = pCachePriv->MonoOffsets; - - pad = BitmapBytePad(pCache->w * pScrn->bitsPerPixel); - - data = (unsigned char*)xalloc(pad * pCache->h); - if(!data) return; - - if(infoRec->Mono8x8PatternFillFlags & HARDWARE_PATTERN_PROGRAMMED_ORIGIN) { - CARD32* ptr = (CARD32*)data; - ptr[0] = pCache->pat0; ptr[1] = pCache->pat1; - } else { - CARD32 *ptr; - DDXPointPtr pPoint = pCache->offsets; - int patx, paty, i; - - for(i = 0; i < 64; i++, pPoint++) { - patx = pCache->pat0; paty = pCache->pat1; - XAARotateMonoPattern(&patx, &paty, i & 0x07, i >> 3, - (infoRec->Mono8x8PatternFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST)); - ptr = (CARD32*)(data + (pad * pPoint->y) + (Bpp * pPoint->x)); - ptr[0] = patx; ptr[1] = paty; - } - } - - (*infoRec->WritePixmapToCache)(pScrn, pCache->x, pCache->y, - pCache->w, pCache->h, data, pad, pScrn->bitsPerPixel, pScrn->depth); - - xfree(data); -} - -void -XAAWriteColor8x8PatternToCache( - ScrnInfoPtr pScrn, - PixmapPtr pPix, - XAACacheInfoPtr pCache -){ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(pPix); - XAAPixmapCachePrivatePtr pCachePriv = - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; - int pad, i, w, h, nw, nh, Bpp; - unsigned char *data, *srcPtr, *dstPtr; - - pCache->offsets = pCachePriv->ColorOffsets; - - if(pixPriv->flags & REDUCIBLE_TO_2_COLOR) { - CARD32* ptr; - pad = BitmapBytePad(pCache->w); - data = (unsigned char*)xalloc(pad * pCache->h); - if(!data) return; - - if(infoRec->Color8x8PatternFillFlags & - HARDWARE_PATTERN_PROGRAMMED_ORIGIN) { - ptr = (CARD32*)data; - ptr[0] = pCache->pat0; ptr[1] = pCache->pat1; - } else { - int patx, paty; - - ptr = (CARD32*)data; - ptr[0] = ptr[2] = pCache->pat0; ptr[1] = ptr[3] = pCache->pat1; - for(i = 1; i < 8; i++) { - patx = pCache->pat0; paty = pCache->pat1; - XAARotateMonoPattern(&patx, &paty, i, 0, - (infoRec->Mono8x8PatternFillFlags & - BIT_ORDER_IN_BYTE_MSBFIRST)); - ptr = (CARD32*)(data + (pad * i)); - ptr[0] = ptr[2] = patx; ptr[1] = ptr[3] = paty; - } - } - - (*infoRec->WriteBitmapToCache)(pScrn, pCache->x, pCache->y, - pCache->w, pCache->h, data, pad, pCache->fg, pCache->bg); - - xfree(data); - return; - } - - Bpp = pScrn->bitsPerPixel >> 3; - h = min(8,pPix->drawable.height); - w = min(8,pPix->drawable.width); - pad = BitmapBytePad(pCache->w * pScrn->bitsPerPixel); - - data = (unsigned char*)xalloc(pad * pCache->h); - if(!data) return; - - /* Write and expand horizontally. */ - for (i = h, dstPtr = data, srcPtr = pPix->devPrivate.ptr; i--; - srcPtr += pPix->devKind, dstPtr += pScrn->bitsPerPixel) { - nw = w; - memcpy(dstPtr, srcPtr, w * Bpp); - while (nw != 8) { - memcpy(dstPtr + (nw * Bpp), dstPtr, nw * Bpp); - nw <<= 1; - } - } - nh = h; - /* Expand vertically. */ - while (nh != 8) { - memcpy(data + (nh*pScrn->bitsPerPixel), data, nh*pScrn->bitsPerPixel); - nh <<= 1; - } - - if(!(infoRec->Color8x8PatternFillFlags & - HARDWARE_PATTERN_PROGRAMMED_ORIGIN)){ - int j; - unsigned char *ptr = data + (128 * Bpp); - - memcpy(data + (64 * Bpp), data, 64 * Bpp); - for(i = 1; i < 8; i++, ptr += (128 * Bpp)) { - for(j = 0; j < 8; j++) { - memcpy(ptr + (j * 8) * Bpp, data + (j * 8 + i) * Bpp, - (8 - i) * Bpp); - memcpy(ptr + (j * 8 + 8 - i) * Bpp, data + j * 8 * Bpp, i*Bpp); - } - memcpy(ptr + (64 * Bpp), ptr, 64 * Bpp); - } - } - - (*infoRec->WritePixmapToCache)(pScrn, pCache->x, pCache->y, - pCache->w, pCache->h, data, pad, pScrn->bitsPerPixel, pScrn->depth); - - xfree(data); -} - - - -int -XAAStippledFillChooser(GCPtr pGC) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - PixmapPtr pPixmap = pGC->stipple; - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); - - if(!(pPriv->flags & REDUCIBILITY_CHECKED) && - (infoRec->CanDoMono8x8 || infoRec->CanDoColor8x8)) { - XAACheckStippleReducibility(pPixmap); - } - - - if(pPriv->flags & REDUCIBLE_TO_8x8) { - if(infoRec->CanDoMono8x8 && - !(infoRec->FillMono8x8PatternSpansFlags & NO_TRANSPARENCY) && - ((pGC->alu == GXcopy) || !(infoRec->FillMono8x8PatternSpansFlags & - TRANSPARENCY_GXCOPY_ONLY)) && - CHECK_ROP(pGC,infoRec->FillMono8x8PatternSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillMono8x8PatternSpansFlags) && - CHECK_FG(pGC,infoRec->FillMono8x8PatternSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillMono8x8PatternSpansFlags)) { - - return DO_MONO_8x8; - } - - if(infoRec->CanDoColor8x8 && - !(infoRec->FillColor8x8PatternSpansFlags & NO_TRANSPARENCY) && - ((pGC->alu == GXcopy) || !(infoRec->FillColor8x8PatternSpansFlags & - TRANSPARENCY_GXCOPY_ONLY)) && - CHECK_ROP(pGC,infoRec->FillColor8x8PatternSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillColor8x8PatternSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillColor8x8PatternSpansFlags)) { - - return DO_COLOR_8x8; - } - } - - if(infoRec->UsingPixmapCache && infoRec->FillCacheExpandSpans && - (pPixmap->drawable.height <= infoRec->MaxCacheableStippleHeight) && - (pPixmap->drawable.width <= infoRec->MaxCacheableStippleWidth / - infoRec->CacheColorExpandDensity) && - !(infoRec->FillCacheExpandSpansFlags & NO_TRANSPARENCY) && - ((pGC->alu == GXcopy) || !(infoRec->FillCacheExpandSpansFlags & - TRANSPARENCY_GXCOPY_ONLY)) && - CHECK_ROP(pGC,infoRec->FillCacheExpandSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillCacheExpandSpansFlags) && - CHECK_FG(pGC,infoRec->FillCacheExpandSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillCacheExpandSpansFlags)) { - - return DO_CACHE_EXPAND; - } - - - if(infoRec->UsingPixmapCache && - !(infoRec->PixmapCacheFlags & DO_NOT_BLIT_STIPPLES) && - infoRec->FillCacheBltSpans && - (pPixmap->drawable.height <= infoRec->MaxCacheableTileHeight) && - (pPixmap->drawable.width <= infoRec->MaxCacheableTileWidth) && - !(infoRec->FillCacheBltSpansFlags & NO_TRANSPARENCY) && - ((pGC->alu == GXcopy) || !(infoRec->FillCacheBltSpansFlags & - TRANSPARENCY_GXCOPY_ONLY)) && - CHECK_ROP(pGC,infoRec->FillCacheBltSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillCacheBltSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillCacheBltSpansFlags)) { - - return DO_CACHE_BLT; - } - - if(infoRec->FillColorExpandSpans && - !(infoRec->FillColorExpandSpansFlags & NO_TRANSPARENCY) && - ((pGC->alu == GXcopy) || !(infoRec->FillColorExpandSpansFlags & - TRANSPARENCY_GXCOPY_ONLY)) && - CHECK_ROP(pGC,infoRec->FillColorExpandSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillColorExpandSpansFlags) && - CHECK_FG(pGC,infoRec->FillColorExpandSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillColorExpandSpansFlags)) { - - return DO_COLOR_EXPAND; - } - - return 0; -} - - -int -XAAOpaqueStippledFillChooser(GCPtr pGC) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - PixmapPtr pPixmap = pGC->stipple; - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); - - if(XAA_DEPTH_BUG(pGC)) - return 0; - - if(!(pPriv->flags & REDUCIBILITY_CHECKED) && - (infoRec->CanDoMono8x8 || infoRec->CanDoColor8x8)) { - XAACheckStippleReducibility(pPixmap); - } - - if(pPriv->flags & REDUCIBLE_TO_8x8) { - if(infoRec->CanDoMono8x8 && - !(infoRec->FillMono8x8PatternSpansFlags & TRANSPARENCY_ONLY) && - CHECK_ROP(pGC,infoRec->FillMono8x8PatternSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillMono8x8PatternSpansFlags) && - CHECK_COLORS(pGC,infoRec->FillMono8x8PatternSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillMono8x8PatternSpansFlags)) { - - return DO_MONO_8x8; - } - - if(infoRec->CanDoColor8x8 && - CHECK_ROP(pGC,infoRec->FillColor8x8PatternSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillColor8x8PatternSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillColor8x8PatternSpansFlags)) { - - return DO_COLOR_8x8; - } - } - - if(infoRec->UsingPixmapCache && infoRec->FillCacheExpandSpans && - (pPixmap->drawable.height <= infoRec->MaxCacheableStippleHeight) && - (pPixmap->drawable.width <= infoRec->MaxCacheableStippleWidth / - infoRec->CacheColorExpandDensity) && - !(infoRec->FillCacheExpandSpansFlags & TRANSPARENCY_ONLY) && - CHECK_ROP(pGC,infoRec->FillCacheExpandSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillCacheExpandSpansFlags) && - CHECK_COLORS(pGC,infoRec->FillCacheExpandSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillCacheExpandSpansFlags)) { - - return DO_CACHE_EXPAND; - } - - if(infoRec->UsingPixmapCache && - !(infoRec->PixmapCacheFlags & DO_NOT_BLIT_STIPPLES) && - infoRec->FillCacheBltSpans && - (pPixmap->drawable.height <= infoRec->MaxCacheableTileHeight) && - (pPixmap->drawable.width <= infoRec->MaxCacheableTileWidth) && - CHECK_ROP(pGC,infoRec->FillCacheBltSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillCacheBltSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillCacheBltSpansFlags)) { - - return DO_CACHE_BLT; - } - - if(infoRec->FillColorExpandSpans && - !(infoRec->FillColorExpandSpansFlags & TRANSPARENCY_ONLY) && - CHECK_ROP(pGC,infoRec->FillColorExpandSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillColorExpandSpansFlags) && - CHECK_COLORS(pGC,infoRec->FillColorExpandSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillColorExpandSpansFlags)) { - - return DO_COLOR_EXPAND; - } - - return 0; -} - - - -int -XAATiledFillChooser(GCPtr pGC) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - PixmapPtr pPixmap = pGC->tile.pixmap; - XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); - - if(IS_OFFSCREEN_PIXMAP(pPixmap) && infoRec->FillCacheBltSpans && - CHECK_ROP(pGC,infoRec->FillCacheBltSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillCacheBltSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillCacheBltSpansFlags)) { - - return DO_PIXMAP_COPY; - } - - if(!(pPriv->flags & REDUCIBILITY_CHECKED) && - (infoRec->CanDoMono8x8 || infoRec->CanDoColor8x8)) { - XAACheckTileReducibility(pPixmap,infoRec->CanDoMono8x8); - } - - if(pPriv->flags & REDUCIBLE_TO_8x8) { - if((pPriv->flags & REDUCIBLE_TO_2_COLOR) && infoRec->CanDoMono8x8 && - !(infoRec->FillMono8x8PatternSpansFlags & TRANSPARENCY_ONLY) && - CHECK_ROP(pGC,infoRec->FillMono8x8PatternSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillMono8x8PatternSpansFlags) && - (!(infoRec->FillMono8x8PatternSpansFlags & RGB_EQUAL) || - (CHECK_RGB_EQUAL(pPriv->fg) && CHECK_RGB_EQUAL(pPriv->bg))) && - CHECK_PLANEMASK(pGC,infoRec->FillMono8x8PatternSpansFlags)) { - - return DO_MONO_8x8; - } - - if(infoRec->CanDoColor8x8 && - CHECK_ROP(pGC,infoRec->FillColor8x8PatternSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillColor8x8PatternSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillColor8x8PatternSpansFlags)) { - - return DO_COLOR_8x8; - } - } - - if(infoRec->UsingPixmapCache && infoRec->FillCacheBltSpans && - (pPixmap->drawable.height <= infoRec->MaxCacheableTileHeight) && - (pPixmap->drawable.width <= infoRec->MaxCacheableTileWidth) && - CHECK_ROP(pGC,infoRec->FillCacheBltSpansFlags) && - CHECK_ROPSRC(pGC,infoRec->FillCacheBltSpansFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillCacheBltSpansFlags)) { - - return DO_CACHE_BLT; - } - - if(infoRec->FillImageWriteRects && - CHECK_NO_GXCOPY(pGC,infoRec->FillImageWriteRectsFlags) && - CHECK_ROP(pGC,infoRec->FillImageWriteRectsFlags) && - CHECK_ROPSRC(pGC,infoRec->FillImageWriteRectsFlags) && - CHECK_PLANEMASK(pGC,infoRec->FillImageWriteRectsFlags)) { - - return DO_IMAGE_WRITE; - } - - return 0; -} - - -static int RotateMasksX[8] = { - 0xFFFFFFFF, 0x7F7F7F7F, 0x3F3F3F3F, 0x1F1F1F1F, - 0x0F0F0F0F, 0x07070707, 0x03030303, 0x01010101 -}; - -static int RotateMasksY[4] = { - 0xFFFFFFFF, 0x00FFFFFF, 0x0000FFFF, 0x000000FF -}; - -void -XAARotateMonoPattern( - int *pat0, int *pat1, - int xorg, int yorg, - Bool msbfirst -){ - int tmp, mask; - - if(xorg) { - if(msbfirst) xorg = 8 - xorg; - mask = RotateMasksX[xorg]; - *pat0 = ((*pat0 >> xorg) & mask) | ((*pat0 << (8 - xorg)) & ~mask); - *pat1 = ((*pat1 >> xorg) & mask) | ((*pat1 << (8 - xorg)) & ~mask); - } - if(yorg >= 4) { - tmp = *pat0; *pat0 = *pat1; *pat1 = tmp; - yorg -= 4; - } - if(yorg) { - mask = RotateMasksY[yorg]; - yorg <<= 3; - tmp = *pat0; - *pat0 = ((*pat0 >> yorg) & mask) | ((*pat1 << (32 - yorg)) & ~mask); - *pat1 = ((*pat1 >> yorg) & mask) | ((tmp << (32 - yorg)) & ~mask); - } -} - - - -void -XAAInvalidatePixmapCache(ScreenPtr pScreen) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - XAAPixmapCachePrivatePtr pCachePriv = - (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; - int i; - - if(!pCachePriv) return; - - for(i = 0; i < pCachePriv->Num512x512; i++) - (pCachePriv->Info512)[i].serialNumber = 0; - for(i = 0; i < pCachePriv->Num256x256; i++) - (pCachePriv->Info256)[i].serialNumber = 0; - for(i = 0; i < pCachePriv->Num128x128; i++) - (pCachePriv->Info128)[i].serialNumber = 0; - for(i = 0; i < pCachePriv->NumPartial; i++) - (pCachePriv->InfoPartial)[i].serialNumber = 0; - for(i = 0; i < pCachePriv->NumMono; i++) - (pCachePriv->InfoMono)[i].serialNumber = 0; - for(i = 0; i < pCachePriv->NumColor; i++) - (pCachePriv->InfoColor)[i].serialNumber = 0; -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "gc.h" +#include "mi.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "regionstr.h" +#include "servermd.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaacexp.h" +#include "xaalocal.h" +#include "xaawrap.h" + +#define MAX_COLOR 32 +#define MAX_MONO 32 +#define MAX_8 32 +#define MAX_128 32 +#define MAX_256 32 +#define MAX_512 16 + +static int CacheInitIndex = -1; +#define CACHEINIT(p) ((p)->privates[CacheInitIndex].val) + + +typedef struct _CacheLink { + int x; + int y; + int w; + int h; + struct _CacheLink *next; +} CacheLink, *CacheLinkPtr; + + +static void +TransferList(CacheLinkPtr list, XAACacheInfoPtr array, int num) +{ + while(num--) { + array->x = list->x; + array->y = list->y; + array->w = list->w; + array->h = list->h; + array->serialNumber = 0; + array->fg = array->bg = -1; + list = list->next; + array++; + } +} + + + +static CacheLinkPtr +Enlist(CacheLinkPtr link, int x, int y, int w, int h) +{ + CacheLinkPtr newLink; + + newLink = malloc(sizeof(CacheLink)); + newLink->next = link; + newLink->x = x; newLink->y = y; + newLink->w = w; newLink->h = h; + return newLink; +} + + + +static CacheLinkPtr +Delist(CacheLinkPtr link) { + CacheLinkPtr ret = NULL; + + if(link) { + ret = link->next; + free(link); + } + return ret; +} + + + +static void +FreeList(CacheLinkPtr link) { + CacheLinkPtr tmp; + + while(link) { + tmp = link; + link = link->next; + free(tmp); + } +} + + + +static CacheLinkPtr +QuadLinks(CacheLinkPtr big, CacheLinkPtr little) +{ + /* CAUTION: This doesn't free big */ + int w1, w2, h1, h2; + + while(big) { + w1 = big->w >> 1; + w2 = big->w - w1; + h1 = big->h >> 1; + h2 = big->h - h1; + + little = Enlist(little, big->x, big->y, w1, h1); + little = Enlist(little, big->x + w1, big->y, w2, h1); + little = Enlist(little, big->x, big->y + h1, w1, h2); + little = Enlist(little, big->x + w1, big->y + h1, w2, h2); + + big = big->next; + } + return little; +} + + +static void +SubdivideList(CacheLinkPtr *large, CacheLinkPtr *small) +{ + CacheLinkPtr big = *large; + CacheLinkPtr little = *small; + int size = big->w >> 1; + + little = Enlist(little, big->x, big->y, size, size); + little = Enlist(little, big->x + size, big->y, size, size); + little = Enlist(little, big->x, big->y + size, size, size); + little = Enlist(little, big->x + size, big->y + size, size, size); + *small = little; + big = Delist(big); + *large = big; +} + +static void +FreePixmapCachePrivate(XAAPixmapCachePrivatePtr pPriv) +{ + if(!pPriv) return; + + if(pPriv->Info512) + free(pPriv->Info512); + if(pPriv->Info256) + free(pPriv->Info256); + if(pPriv->Info128) + free(pPriv->Info128); + if(pPriv->InfoColor) + free(pPriv->InfoColor); + if(pPriv->InfoMono) + free(pPriv->InfoMono); + if(pPriv->InfoPartial) + free(pPriv->InfoPartial); + + free(pPriv); +} + +void +XAAClosePixmapCache(ScreenPtr pScreen) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + + if(infoRec->PixmapCachePrivate) + FreePixmapCachePrivate( + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate); + + infoRec->PixmapCachePrivate = NULL; +} + + + +static CacheLinkPtr +ThinOutPartials( + CacheLinkPtr ListPartial, + int *num, int *maxw, int *maxh +) { +/* This guy's job is to get at least 4 big slots out of a list of fragments */ + + CacheLinkPtr List64, List32, List16, List8, pCur, next, ListKeepers; + int Num64, Num32, Num16, Num8, NumKeepers; + int w, h; + + List64 = List32 = List16 = List8 = ListKeepers = NULL; + Num64 = Num32 = Num16 = Num8 = NumKeepers = 0; + w = h = 0; + + /* We sort partials by how large a square tile they can cache. + If a partial can't store a 64x64, 32x32, 16x16 or 8x8 tile, + we free it. */ + + pCur = ListPartial; + while(pCur) { + next = pCur->next; + if((pCur->w >= 64) && (pCur->h >= 64)) { + pCur->next = List64; List64 = pCur; + Num64++; + } else + if((pCur->w >= 32) && (pCur->h >= 32)) { + pCur->next = List32; List32 = pCur; + Num32++; + } else + if((pCur->w >= 16) && (pCur->h >= 16)) { + pCur->next = List16; List16 = pCur; + Num16++; + } else + if((pCur->w >= 8) && (pCur->h >= 8)) { + pCur->next = List8; List8 = pCur; + Num8++; + } else { + free(pCur); + } + + pCur = next; + } + + /* We save all the tiles from the largest bin that we can get + at least 4 of. If there are too few of a bigger slot, we + cut it in fourths to make smaller slots. */ + + if(Num64 >= 4) { + ListKeepers = List64; List64 = NULL; + NumKeepers = Num64; + goto GOT_EM; + } else if(Num64) { + List32 = QuadLinks(List64, List32); + Num32 += Num64 * 4; + Num64 = 0; + } + + if(Num32 >= 4) { + ListKeepers = List32; List32 = NULL; + NumKeepers = Num32; + goto GOT_EM; + } else if(Num32) { + List16 = QuadLinks(List32, List16); + Num16 += Num32 * 4; + Num32 = 0; + } + + if(Num16 >= 4) { + ListKeepers = List16; List16 = NULL; + NumKeepers = Num16; + goto GOT_EM; + } else if(Num16) { + List8 = QuadLinks(List16, List8); + Num8 += Num16 * 4; + Num16 = 0; + } + + if(Num8 >= 4) { + ListKeepers = List8; List8 = NULL; + NumKeepers = Num8; + goto GOT_EM; + } + +GOT_EM: + + /* Free the ones we aren't using */ + + if(List64) FreeList(List64); + if(List32) FreeList(List32); + if(List16) FreeList(List16); + if(List8) FreeList(List8); + + + /* Enlarge the slots if we can */ + + if(ListKeepers) { + CacheLinkPtr pLink = ListKeepers; + w = h = 128; + + while(pLink) { + if(pLink->w < w) w = pLink->w; + if(pLink->h < h) h = pLink->h; + pLink = pLink->next; + } + } + + *maxw = w; + *maxh = h; + *num = NumKeepers; + return ListKeepers; +} + +static void +ConvertColorToMono( + CacheLinkPtr *ColorList, + int ColorW, int ColorH, + CacheLinkPtr *MonoList, + int MonoW, int MonoH +){ + int x, y, w; + + x = (*ColorList)->x; y = (*ColorList)->y; + *ColorList = Delist(*ColorList); + + while(ColorH) { + ColorH -= MonoH; + for(w = 0; w <= (ColorW - MonoW); w += MonoW) + *MonoList = Enlist(*MonoList, x + w, y + ColorH, MonoW, MonoH); + } +} + +static void +ConvertAllPartialsTo8x8( + int *NumMono, int *NumColor, + CacheLinkPtr ListPartial, + CacheLinkPtr *ListMono, + CacheLinkPtr *ListColor, + XAAInfoRecPtr infoRec +){ +/* This guy extracts as many 8x8 slots as it can out of fragments */ + + int ColorH = infoRec->CacheHeightColor8x8Pattern; + int ColorW = infoRec->CacheWidthColor8x8Pattern; + int MonoH = infoRec->CacheHeightMono8x8Pattern; + int MonoW = infoRec->CacheWidthMono8x8Pattern; + int x, y, w, Height, Width; + Bool DoColor = (infoRec->PixmapCacheFlags & CACHE_COLOR_8x8); + Bool DoMono = (infoRec->PixmapCacheFlags & CACHE_MONO_8x8); + CacheLinkPtr pLink = ListPartial; + CacheLinkPtr MonoList = *ListMono, ColorList = *ListColor; + + if(DoColor && DoMono) { + /* we assume color patterns take more space than color ones */ + if(MonoH > ColorH) ColorH = MonoH; + if(MonoW > ColorW) ColorW = MonoW; + } + + /* Break up the area into as many Color and Mono slots as we can */ + + while(pLink) { + Height = pLink->h; + Width = pLink->w; + x = pLink->x; + y = pLink->y; + + if(DoColor) { + while(Height >= ColorH) { + Height -= ColorH; + for(w = 0; w <= (Width - ColorW); w += ColorW) { + ColorList = Enlist( + ColorList, x + w, y + Height, ColorW, ColorH); + (*NumColor)++; + } + } + } + + if(DoMono && (Height >= MonoH)) { + while(Height >= MonoH) { + Height -= MonoH; + for(w = 0; w <= (Width - MonoW); w += MonoW) { + MonoList = Enlist( + MonoList, x + w, y + Height, MonoW, MonoH); + (*NumMono)++; + } + } + } + + pLink = pLink->next; + } + + + *ListMono = MonoList; + *ListColor = ColorList; + FreeList(ListPartial); +} + + +static CacheLinkPtr +ExtractOneThatFits(CacheLinkPtr *initList, int w, int h) +{ + CacheLinkPtr list = *initList; + CacheLinkPtr prev = NULL; + + while(list) { + if((list->w >= w) && (list->h >= h)) + break; + prev = list; + list = list->next; + } + + if(list) { + if(prev) + prev->next = list->next; + else + *initList = list->next; + + list->next = NULL; + } + + return list; +} + + +static CacheLinkPtr +ConvertSomePartialsTo8x8( + int *NumMono, int *NumColor, int *NumPartial, + CacheLinkPtr ListPartial, + CacheLinkPtr *ListMono, + CacheLinkPtr *ListColor, + int *maxw, int *maxh, + XAAInfoRecPtr infoRec +){ +/* This guy tries to get 4 of each type of 8x8 slot requested out of + a list of fragments all while trying to retain some big fragments + for the cache blits */ + + int ColorH = infoRec->CacheHeightColor8x8Pattern; + int ColorW = infoRec->CacheWidthColor8x8Pattern; + int MonoH = infoRec->CacheHeightMono8x8Pattern; + int MonoW = infoRec->CacheWidthMono8x8Pattern; + Bool DoColor = (infoRec->PixmapCacheFlags & CACHE_COLOR_8x8); + Bool DoMono = (infoRec->PixmapCacheFlags & CACHE_MONO_8x8); + CacheLinkPtr List64, List32, List16, List8, pCur, next, ListKeepers; + CacheLinkPtr MonoList = *ListMono, ColorList = *ListColor; + int Num64, Num32, Num16, Num8, NumKeepers; + int w, h, Width, Height; + int MonosPerColor = 1; + + if(DoColor && DoMono) { + /* we assume color patterns take more space than color ones */ + if(MonoH > ColorH) ColorH = MonoH; + if(MonoW > ColorW) ColorW = MonoW; + MonosPerColor = (ColorH/MonoH) * (ColorW/MonoW); + } + + List64 = List32 = List16 = List8 = ListKeepers = MonoList = ColorList = NULL; + Num64 = Num32 = Num16 = Num8 = NumKeepers = 0; + Width = Height = 0; + + /* We sort partials by how large a square tile they can cache. + We make 8x8 patterns from the leftovers if we can. */ + + pCur = ListPartial; + while(pCur) { + next = pCur->next; + if((pCur->w >= 64) && (pCur->h >= 64)) { + pCur->next = List64; List64 = pCur; + Num64++; + } else + if((pCur->w >= 32) && (pCur->h >= 32)) { + pCur->next = List32; List32 = pCur; + Num32++; + } else + if((pCur->w >= 16) && (pCur->h >= 16)) { + pCur->next = List16; List16 = pCur; + Num16++; + } else + if((pCur->w >= 8) && (pCur->h >= 8)) { + pCur->next = List8; List8 = pCur; + Num8++; + } else { + h = pCur->h; + if(DoColor && (pCur->w >= ColorW) && (h >= ColorH)) { + while(h >= ColorH) { + h -= ColorH; + for(w = 0; w <= (pCur->w - ColorW); w += ColorW) { + ColorList = Enlist( ColorList, + pCur->x + w, pCur->y + h, ColorW, ColorH); + (*NumColor)++; + } + } + } + if(DoMono && (pCur->w >= MonoW) && (h >= MonoH)) { + while(h >= MonoH) { + h -= MonoH; + for(w = 0; w <= (pCur->w - MonoW); w += MonoW) { + MonoList = Enlist( MonoList, + pCur->x + w, pCur->y + h, MonoW, MonoH); + (*NumMono)++; + } + } + } + free(pCur); + } + + pCur = next; + } + + /* Try to extract at least 4 of each type of 8x8 slot that we need */ + + if(DoColor) { + CacheLinkPtr theOne; + while(*NumColor < 4) { + theOne = NULL; + if(Num8) { + if((theOne = ExtractOneThatFits(&List8, ColorW, ColorH))) + Num8--; + } + if(Num16 && !theOne) { + if((theOne = ExtractOneThatFits(&List16, ColorW, ColorH))) + Num16--; + } + if(Num32 && !theOne) { + if((theOne = ExtractOneThatFits(&List32, ColorW, ColorH))) + Num32--; + } + if(Num64 && !theOne) { + if((theOne = ExtractOneThatFits(&List64, ColorW, ColorH))) + Num64--; + } + + if(!theOne) break; + + + ConvertAllPartialsTo8x8(NumMono, NumColor, theOne, + &MonoList, &ColorList, infoRec); + + if(DoMono) { + while(*NumColor && (*NumMono < 4)) { + ConvertColorToMono(&ColorList, ColorW, ColorH, + &MonoList, MonoW, MonoH); + (*NumColor)--; *NumMono += MonosPerColor; + } + } + } + } + + if(DoMono) { + CacheLinkPtr theOne; + while(*NumMono < 4) { + theOne = NULL; + if(Num8) { + if((theOne = ExtractOneThatFits(&List8, MonoW, MonoH))) + Num8--; + } + if(Num16 && !theOne) { + if((theOne = ExtractOneThatFits(&List16, MonoW, MonoH))) + Num16--; + } + if(Num32 && !theOne) { + if((theOne = ExtractOneThatFits(&List32, MonoW, MonoH))) + Num32--; + } + if(Num64 && !theOne) { + if((theOne = ExtractOneThatFits(&List64, MonoW, MonoH))) + Num64--; + } + + if(!theOne) break; + + ConvertAllPartialsTo8x8(NumMono, NumColor, theOne, + &MonoList, &ColorList, infoRec); + } + } + + /* We save all the tiles from the largest bin that we can get + at least 4 of. If there are too few of a bigger slot, we + cut it in fourths to make smaller slots. */ + + if(Num64 >= 4) { + ListKeepers = List64; List64 = NULL; + NumKeepers = Num64; + goto GOT_EM; + } else if(Num64) { + List32 = QuadLinks(List64, List32); + Num32 += Num64 * 4; + Num64 = 0; + } + + if(Num32 >= 4) { + ListKeepers = List32; List32 = NULL; + NumKeepers = Num32; + goto GOT_EM; + } else if(Num32) { + List16 = QuadLinks(List32, List16); + Num16 += Num32 * 4; + Num32 = 0; + } + + if(Num16 >= 4) { + ListKeepers = List16; List16 = NULL; + NumKeepers = Num16; + goto GOT_EM; + } else if(Num16) { + List8 = QuadLinks(List16, List8); + Num8 += Num16 * 4; + Num16 = 0; + } + + if(Num8 >= 4) { + ListKeepers = List8; List8 = NULL; + NumKeepers = Num8; + goto GOT_EM; + } + +GOT_EM: + + /* Free the ones we aren't using */ + + if(List64) + ConvertAllPartialsTo8x8(NumMono, NumColor, List64, + &MonoList, &ColorList, infoRec); + if(List32) + ConvertAllPartialsTo8x8(NumMono, NumColor, List32, + &MonoList, &ColorList, infoRec); + if(List16) + ConvertAllPartialsTo8x8(NumMono, NumColor, List16, + &MonoList, &ColorList, infoRec); + if(List8) + ConvertAllPartialsTo8x8(NumMono, NumColor, List8, + &MonoList, &ColorList, infoRec); + + + /* Enlarge the slots if we can */ + + if(ListKeepers) { + CacheLinkPtr pLink = ListKeepers; + Width = Height = 128; + + while(pLink) { + if(pLink->w < Width) Width = pLink->w; + if(pLink->h < Height) Height = pLink->h; + pLink = pLink->next; + } + } + + *ListMono = MonoList; + *ListColor = ColorList; + *maxw = Width; + *maxh = Height; + *NumPartial = NumKeepers; + return ListKeepers; +} + + +void +XAAInitPixmapCache( + ScreenPtr pScreen, + RegionPtr areas, + pointer data +) { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XAAInfoRecPtr infoRec = (XAAInfoRecPtr)data; + XAAPixmapCachePrivatePtr pCachePriv; + BoxPtr pBox = REGION_RECTS(areas); + int nBox = REGION_NUM_RECTS(areas); + int Num512, Num256, Num128, NumPartial, NumColor, NumMono; + int Target512, Target256; + CacheLinkPtr List512, List256, List128, ListPartial, ListColor, ListMono; + int x, y, w, h, ntotal, granularity, width, height, i; + int MaxPartialWidth, MaxPartialHeight; + + infoRec->MaxCacheableTileWidth = 0; + infoRec->MaxCacheableTileHeight = 0; + infoRec->MaxCacheableStippleHeight = 0; + infoRec->MaxCacheableStippleWidth = 0; + infoRec->UsingPixmapCache = FALSE; + + + if(!nBox || !pBox || !(infoRec->Flags & PIXMAP_CACHE)) + return; + + /* Allocate a persistent per-screen init flag to control messages */ + if (CacheInitIndex < 0) + CacheInitIndex = xf86AllocateScrnInfoPrivateIndex(); + + /* free the old private data if it exists */ + if(infoRec->PixmapCachePrivate) { + FreePixmapCachePrivate( + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate); + infoRec->PixmapCachePrivate = NULL; + } + + Num512 = Num256 = Num128 = NumPartial = NumMono = NumColor = 0; + List512 = List256 = List128 = ListPartial = ListMono = ListColor = NULL; + granularity = infoRec->CachePixelGranularity; + if(granularity <= 1) granularity = 0; + + /* go through the boxes and break it into as many pieces as we can fit */ + + while(nBox--) { + x = pBox->x1; + if(granularity) { + int tmp = x % granularity; + if(tmp) x += (granularity - tmp); + } + width = pBox->x2 - x; + if(width <= 0) {pBox++; continue;} + + y = pBox->y1; + height = pBox->y2 - y; + + for(h = 0; h <= (height - 512); h += 512) { + for(w = 0; w <= (width - 512); w += 512) { + List512 = Enlist(List512, x + w, y + h, 512, 512); + Num512++; + } + for(; w <= (width - 256); w += 256) { + List256 = Enlist(List256, x + w, y + h, 256, 256); + List256 = Enlist(List256, x + w, y + h + 256, 256, 256); + Num256 += 2; + } + for(; w <= (width - 128); w += 128) { + List128 = Enlist(List128, x + w, y + h, 128, 128); + List128 = Enlist(List128, x + w, y + h + 128, 128, 128); + List128 = Enlist(List128, x + w, y + h + 256, 128, 128); + List128 = Enlist(List128, x + w, y + h + 384, 128, 128); + Num128 += 4; + } + if(w < width) { + int d = width - w; + ListPartial = Enlist(ListPartial, x + w, y + h, d, 128); + ListPartial = Enlist(ListPartial, x + w, y + h + 128, d, 128); + ListPartial = Enlist(ListPartial, x + w, y + h + 256, d, 128); + ListPartial = Enlist(ListPartial, x + w, y + h + 384, d, 128); + NumPartial += 4; + } + } + for(; h <= (height - 256); h += 256) { + for(w = 0; w <= (width - 256); w += 256) { + List256 = Enlist(List256, x + w, y + h, 256, 256); + Num256++; + } + for(; w <= (width - 128); w += 128) { + List128 = Enlist(List128, x + w, y + h, 128, 128); + List128 = Enlist(List128, x + w, y + h + 128, 128, 128); + Num128 += 2; + } + if(w < width) { + int d = width - w; + ListPartial = Enlist(ListPartial, x + w, y + h, d, 128); + ListPartial = Enlist(ListPartial, x + w, y + h + 128, d, 128); + NumPartial += 2; + } + } + for(; h <= (height - 128); h += 128) { + for(w = 0; w <= (width - 128); w += 128) { + List128 = Enlist(List128, x + w, y + h, 128, 128); + Num128++; + } + if(w < width) { + ListPartial = Enlist( + ListPartial, x + w, y + h, width - w, 128); + NumPartial++; + } + } + if(h < height) { + int d = height - h; + for(w = 0; w <= (width - 128); w += 128) { + ListPartial = Enlist(ListPartial, x + w, y + h, 128, d); + NumPartial++; + } + if(w < width) { + ListPartial = Enlist(ListPartial, x + w, y + h, width - w, d); + NumPartial++; + } + } + pBox++; + } + + +/* + by this point we've carved the space into as many 512x512, 256x256 + and 128x128 blocks as we could fit. We will then break larger + blocks into smaller ones if we need to. The rules are as follows: + + 512x512 - + 1) Don't take up more than half the memory. + 2) Don't bother if you can't get at least four. + 3) Don't make more than MAX_512. + 4) Don't have any of there are no 256x256s. + + 256x256 - + 1) Don't take up more than a quarter of the memory enless there + aren't any 512x512s. Then we can take up to half. + 2) Don't bother if you can't get at least four. + 3) Don't make more than MAX_256. + + 128x128 - + 1) Don't make more than MAX_128. + + We don't bother with the partial blocks unless we can use them + for 8x8 pattern fills or we are short on larger blocks. + +*/ + + ntotal = Num128 + (Num256<<2) + (Num512<<4); + + Target512 = ntotal >> 5; + if(Target512 < 4) Target512 = 0; + if(!Target512) Target256 = ntotal >> 3; + else Target256 = ntotal >> 4; + if(Target256 < 4) Target256 = 0; + + if(Num512 && Num256 < 4) { + while(Num512 && Num256 < Target256) { + SubdivideList(&List512, &List256); + Num256 += 4; Num512--; + } + } + + if(!Num512) { /* no room */ + } else if((Num512 < 4) || (!Target512)) { + while(Num512) { + SubdivideList(&List512, &List256); + Num256 += 4; Num512--; + } + } else if((Num512 > MAX_512) || (Num512 > Target512)){ + while(Num512 > MAX_512) { + SubdivideList(&List512, &List256); + Num256 += 4; Num512--; + } + while(Num512 > Target512) { + if(Num256 < MAX_256) { + SubdivideList(&List512, &List256); + Num256 += 4; Num512--; + } else break; + } + } + + if(!Num256) { /* no room */ + } else if((Num256 < 4) || (!Target256)) { + while(Num256) { + SubdivideList(&List256, &List128); + Num128 += 4; Num256--; + } + } else if((Num256 > MAX_256) || (Num256 > Target256)) { + while(Num256 > MAX_256) { + SubdivideList(&List256, &List128); + Num128 += 4; Num256--; + } + while(Num256 > Target256) { + if(Num128 < MAX_128) { + SubdivideList(&List256, &List128); + Num128 += 4; Num256--; + } else break; + } + } + + if(Num128 && ((Num128 < 4) || (Num128 > MAX_128))) { + CacheLinkPtr next; + int max = (Num128 > MAX_128) ? MAX_128 : 0; + + /* + * Note: next is set in this way to work around a code generation + * bug in gcc 2.7.2.3. + */ + next = List128->next; + while(Num128 > max) { + List128->next = ListPartial; + ListPartial = List128; + if((List128 = next)) + next = List128->next; + NumPartial++; Num128--; + } + } + + MaxPartialHeight = MaxPartialWidth = 0; + + /* at this point we have as many 512x512 and 256x256 slots as we + want but may have an excess of 128x128 slots. We still need + to find out if we need 8x8 slots. We take these from the + partials if we have them. Otherwise, we break some 128x128's */ + + if(!(infoRec->PixmapCacheFlags & (CACHE_MONO_8x8 | CACHE_COLOR_8x8))) { + if(NumPartial) { + if(Num128) { /* don't bother with partials */ + FreeList(ListPartial); + NumPartial = 0; ListPartial = NULL; + } else { + /* We have no big slots. Weed out the unusable partials */ + ListPartial = ThinOutPartials(ListPartial, &NumPartial, + &MaxPartialWidth, &MaxPartialHeight); + } + } + } else { + int MonosPerColor = 1; + int ColorH = infoRec->CacheHeightColor8x8Pattern; + int ColorW = infoRec->CacheWidthColor8x8Pattern; + int MonoH = infoRec->CacheHeightMono8x8Pattern; + int MonoW = infoRec->CacheWidthMono8x8Pattern; + Bool DoColor = (infoRec->PixmapCacheFlags & CACHE_COLOR_8x8); + Bool DoMono = (infoRec->PixmapCacheFlags & CACHE_MONO_8x8); + + if(DoColor) infoRec->CanDoColor8x8 = FALSE; + if(DoMono) infoRec->CanDoMono8x8 = FALSE; + + if(DoColor && DoMono) { + /* we assume color patterns take more space than color ones */ + if(MonoH > ColorH) ColorH = MonoH; + if(MonoW > ColorW) ColorW = MonoW; + MonosPerColor = (ColorH/MonoH) * (ColorW/MonoW); + } + + if(Num128) { + if(NumPartial) { /* use all for 8x8 slots */ + ConvertAllPartialsTo8x8(&NumMono, &NumColor, + ListPartial, &ListMono, &ListColor, infoRec); + NumPartial = 0; ListPartial = NULL; + } + + /* Get some 8x8 slots from the 128 slots */ + while((Num128 > 4) && + ((NumMono < MAX_MONO) && (NumColor < MAX_COLOR))) { + CacheLinkPtr tmp = NULL; + + tmp = Enlist(tmp, List128->x, List128->y, + List128->w, List128->h); + List128 = Delist(List128); + Num128--; + + ConvertAllPartialsTo8x8(&NumMono, &NumColor, + tmp, &ListMono, &ListColor, infoRec); + } + } else if(NumPartial) { + /* We have share partials between 8x8 slots and tiles. */ + ListPartial = ConvertSomePartialsTo8x8(&NumMono, &NumColor, + &NumPartial, ListPartial, &ListMono, &ListColor, + &MaxPartialWidth, &MaxPartialHeight, infoRec); + } + + + if(DoMono && DoColor) { + if(NumColor && ((NumColor > MAX_COLOR) || (NumColor < 4))) { + int max = (NumColor > MAX_COLOR) ? MAX_COLOR : 0; + + while(NumColor > max) { + ConvertColorToMono(&ListColor, ColorW, ColorH, + &ListMono, MonoW, MonoH); + NumColor--; NumMono += MonosPerColor; + } + } + + /* favor Mono slots over Color ones */ + while((NumColor > 4) && (NumMono < MAX_MONO)) { + ConvertColorToMono(&ListColor, ColorW, ColorH, + &ListMono, MonoW, MonoH); + NumColor--; NumMono += MonosPerColor; + } + } + + if(NumMono && ((NumMono > MAX_MONO) || (NumMono < 4))) { + int max = (NumMono > MAX_MONO) ? MAX_MONO : 0; + + while(NumMono > max) { + ListMono = Delist(ListMono); + NumMono--; + } + } + if(NumColor && ((NumColor > MAX_COLOR) || (NumColor < 4))) { + int max = (NumColor > MAX_COLOR) ? MAX_COLOR : 0; + + while(NumColor > max) { + ListColor = Delist(ListColor); + NumColor--; + } + } + } + + + pCachePriv = calloc(1,sizeof(XAAPixmapCachePrivate)); + if(!pCachePriv) { + if(Num512) FreeList(List512); + if(Num256) FreeList(List256); + if(Num128) FreeList(List128); + if(NumPartial) FreeList(ListPartial); + if(NumColor) FreeList(ListColor); + if(NumMono) FreeList(ListMono); + return; + } + + infoRec->PixmapCachePrivate = (char*)pCachePriv; + + if(Num512) { + pCachePriv->Info512 = calloc(Num512,sizeof(XAACacheInfoRec)); + if(!pCachePriv->Info512) Num512 = 0; + if(Num512) TransferList(List512, pCachePriv->Info512, Num512); + FreeList(List512); + pCachePriv->Num512x512 = Num512; + } + if(Num256) { + pCachePriv->Info256 = calloc(Num256, sizeof(XAACacheInfoRec)); + if(!pCachePriv->Info256) Num256 = 0; + if(Num256) TransferList(List256, pCachePriv->Info256, Num256); + FreeList(List256); + pCachePriv->Num256x256 = Num256; + } + if(Num128) { + pCachePriv->Info128 = calloc(Num128, sizeof(XAACacheInfoRec)); + if(!pCachePriv->Info128) Num128 = 0; + if(Num128) TransferList(List128, pCachePriv->Info128, Num128); + FreeList(List128); + pCachePriv->Num128x128 = Num128; + } + + if(NumPartial) { + pCachePriv->InfoPartial = calloc(NumPartial, sizeof(XAACacheInfoRec)); + if(!pCachePriv->InfoPartial) NumPartial = 0; + if(NumPartial) + TransferList(ListPartial, pCachePriv->InfoPartial, NumPartial); + FreeList(ListPartial); + pCachePriv->NumPartial = NumPartial; + } + + if(NumColor) { + pCachePriv->InfoColor = calloc(NumColor, sizeof(XAACacheInfoRec)); + if(!pCachePriv->InfoColor) NumColor = 0; + if(NumColor) TransferList(ListColor, pCachePriv->InfoColor, NumColor); + FreeList(ListColor); + pCachePriv->NumColor = NumColor; + } + + if(NumMono) { + pCachePriv->InfoMono = calloc(NumMono, sizeof(XAACacheInfoRec)); + if(!pCachePriv->InfoMono) NumMono = 0; + if(NumMono) TransferList(ListMono, pCachePriv->InfoMono, NumMono); + FreeList(ListMono); + pCachePriv->NumMono = NumMono; + } + + + if(NumPartial) { + infoRec->MaxCacheableTileWidth = MaxPartialWidth; + infoRec->MaxCacheableTileHeight = MaxPartialHeight; + } + if(Num128) + infoRec->MaxCacheableTileWidth = infoRec->MaxCacheableTileHeight = 128; + if(Num256) + infoRec->MaxCacheableTileWidth = infoRec->MaxCacheableTileHeight = 256; + if(Num512) + infoRec->MaxCacheableTileWidth = infoRec->MaxCacheableTileHeight = 512; + + + infoRec->MaxCacheableStippleHeight = infoRec->MaxCacheableTileHeight; + infoRec->MaxCacheableStippleWidth = + infoRec->MaxCacheableTileWidth * pScrn->bitsPerPixel; + if(infoRec->ScreenToScreenColorExpandFillFlags & TRIPLE_BITS_24BPP) + infoRec->MaxCacheableStippleWidth /= 3; + + if(NumMono) { + if(!(infoRec->Mono8x8PatternFillFlags & + (HARDWARE_PATTERN_PROGRAMMED_ORIGIN | + HARDWARE_PATTERN_PROGRAMMED_BITS))) { + int numPerLine = + infoRec->CacheWidthMono8x8Pattern/infoRec->MonoPatternPitch; + + for(i = 0; i < 64; i++) { + pCachePriv->MonoOffsets[i].y = i/numPerLine; + pCachePriv->MonoOffsets[i].x = (i % numPerLine) * + infoRec->MonoPatternPitch; + } + } + infoRec->CanDoMono8x8 = TRUE; + } + if(NumColor) { + if(!(infoRec->Color8x8PatternFillFlags & + HARDWARE_PATTERN_PROGRAMMED_ORIGIN)) { + + for(i = 0; i < 64; i++) { + pCachePriv->ColorOffsets[i].y = i & 0x07; + pCachePriv->ColorOffsets[i].x = i & ~0x07; + } + } + infoRec->CanDoColor8x8 = TRUE; + } + + if(!CACHEINIT(pScrn)) { + xf86ErrorF("\tSetting up tile and stipple cache:\n"); + if(NumPartial) + xf86ErrorF("\t\t%i %ix%i slots\n", + NumPartial, MaxPartialWidth, MaxPartialHeight); + if(Num128) xf86ErrorF("\t\t%i 128x128 slots\n", Num128); + if(Num256) xf86ErrorF("\t\t%i 256x256 slots\n", Num256); + if(Num512) xf86ErrorF("\t\t%i 512x512 slots\n", Num512); + if(NumColor) xf86ErrorF("\t\t%i 8x8 color pattern slots\n", NumColor); + if(NumMono) xf86ErrorF("\t\t%i 8x8 color expansion slots\n", NumMono); + } + + if(!(NumPartial | Num128 | Num256 | Num512 | NumColor | NumMono)) { + if(!CACHEINIT(pScrn)) + xf86ErrorF("\t\tNot enough video memory for pixmap cache\n"); + } else infoRec->UsingPixmapCache = TRUE; + + CACHEINIT(pScrn) = 1; +} + +#if X_BYTE_ORDER == X_BIG_ENDIAN +static CARD32 StippleMasks[4] = { + 0x80808080, + 0xC0C0C0C0, + 0x00000000, + 0xF0F0F0F0 +}; +#else +static CARD32 StippleMasks[4] = { + 0x01010101, + 0x03030303, + 0x00000000, + 0x0F0F0F0F +}; +#endif + +Bool +XAACheckStippleReducibility(PixmapPtr pPixmap) +{ + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_DRAWABLE(&pPixmap->drawable); + CARD32 *IntPtr = (CARD32*)pPixmap->devPrivate.ptr; + int w = pPixmap->drawable.width; + int h = pPixmap->drawable.height; + int i; + CARD32 bits[8]; + CARD32 mask = SHIFT_R(0xFFFFFFFF,24); + + pPriv->flags |= REDUCIBILITY_CHECKED | REDUCIBLE_TO_2_COLOR; + pPriv->flags &= ~REDUCIBLE_TO_8x8; + + if((w > 32) || (h > 32) || (w & (w - 1)) || (h & (h - 1))) + return FALSE; + + i = (h > 8) ? 8 : h; + + switch(w) { + case 32: + while(i--) { + bits[i] = IntPtr[i] & mask; + if( (bits[i] != SHIFT_R((IntPtr[i] & SHIFT_L(mask, 8)), 8)) || + (bits[i] != SHIFT_R((IntPtr[i] & SHIFT_L(mask,16)),16)) || + (bits[i] != SHIFT_R((IntPtr[i] & SHIFT_L(mask,24)),24))) + return FALSE; + } + break; + case 16: + while(i--) { + bits[i] = IntPtr[i] & mask; + if(bits[i] != ((IntPtr[i] & SHIFT_R(SHIFT_L(mask,8),8)))) + return FALSE; + } + break; + default: + while(i--) + bits[i] = IntPtr[i] & mask; + break; + } + + switch(h) { + case 32: + if( (IntPtr[8] != IntPtr[16]) || (IntPtr[9] != IntPtr[17]) || + (IntPtr[10] != IntPtr[18]) || (IntPtr[11] != IntPtr[19]) || + (IntPtr[12] != IntPtr[20]) || (IntPtr[13] != IntPtr[21]) || + (IntPtr[14] != IntPtr[22]) || (IntPtr[15] != IntPtr[23]) || + (IntPtr[16] != IntPtr[24]) || (IntPtr[17] != IntPtr[25]) || + (IntPtr[18] != IntPtr[26]) || (IntPtr[19] != IntPtr[27]) || + (IntPtr[20] != IntPtr[28]) || (IntPtr[21] != IntPtr[29]) || + (IntPtr[22] != IntPtr[30]) || (IntPtr[23] != IntPtr[31])) + return FALSE; + /* fall through */ + case 16: + if( (IntPtr[0] != IntPtr[8]) || (IntPtr[1] != IntPtr[9]) || + (IntPtr[2] != IntPtr[10]) || (IntPtr[3] != IntPtr[11]) || + (IntPtr[4] != IntPtr[12]) || (IntPtr[5] != IntPtr[13]) || + (IntPtr[6] != IntPtr[14]) || (IntPtr[7] != IntPtr[15])) + return FALSE; + case 8: break; + case 1: bits[1] = bits[0]; + case 2: bits[2] = bits[0]; bits[3] = bits[1]; + case 4: bits[4] = bits[0]; bits[5] = bits[1]; + bits[6] = bits[2]; bits[7] = bits[3]; + break; + } + + pPriv->flags |= REDUCIBLE_TO_8x8; + + pPriv->pattern0 = bits[0] | SHIFT_L(bits[1],8) | SHIFT_L(bits[2],16) | SHIFT_L(bits[3],24); + pPriv->pattern1 = bits[4] | SHIFT_L(bits[5],8) | SHIFT_L(bits[6],16) | SHIFT_L(bits[7],24); + + if(w < 8) { + pPriv->pattern0 &= StippleMasks[w - 1]; + pPriv->pattern1 &= StippleMasks[w - 1]; + + switch(w) { + case 1: pPriv->pattern0 |= SHIFT_L(pPriv->pattern0,1); + pPriv->pattern1 |= SHIFT_L(pPriv->pattern1,1); + case 2: pPriv->pattern0 |= SHIFT_L(pPriv->pattern0,2); + pPriv->pattern1 |= SHIFT_L(pPriv->pattern1,2); + case 4: pPriv->pattern0 |= SHIFT_L(pPriv->pattern0,4); + pPriv->pattern1 |= SHIFT_L(pPriv->pattern1,4); + } + } + + if(infoRec->Mono8x8PatternFillFlags & BIT_ORDER_IN_BYTE_MSBFIRST) { + pPriv->pattern0 = SWAP_BITS_IN_BYTES(pPriv->pattern0); + pPriv->pattern1 = SWAP_BITS_IN_BYTES(pPriv->pattern1); + } + + + return TRUE; +} + + +Bool +XAACheckTileReducibility(PixmapPtr pPixmap, Bool checkMono) +{ + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); + CARD32 *IntPtr; + int w = pPixmap->drawable.width; + int h = pPixmap->drawable.height; + int pitch = pPixmap->devKind >> 2; + int dwords, i, j; + + pPriv->flags |= REDUCIBILITY_CHECKED; + pPriv->flags &= ~(REDUCIBILITY_CHECKED | REDUCIBLE_TO_2_COLOR); + + if((w > 32) || (h > 32) || (w & (w - 1)) || (h & (h - 1))) + return FALSE; + + dwords = ((w * pPixmap->drawable.bitsPerPixel) + 31) >> 5; + i = (h > 8) ? 8 : h; + + + if(w > 8) { + IntPtr = (CARD32*)pPixmap->devPrivate.ptr; + switch(pPixmap->drawable.bitsPerPixel) { + case 8: + while(i--) { + for(j = 2; j < dwords; j++) + if(IntPtr[j] != IntPtr[j & 0x01]) + return FALSE; + IntPtr += pitch; + } + break; + case 16: + while(i--) { + for(j = 4; j < dwords; j++) + if(IntPtr[j] != IntPtr[j & 0x03]) + return FALSE; + IntPtr += pitch; + } + break; + case 24: + while(i--) { + for(j = 6; j < dwords; j++) + if(IntPtr[j] != IntPtr[j % 6]) + return FALSE; + IntPtr += pitch; + } + break; + case 32: + while(i--) { + for(j = 8; j < dwords; j++) + if(IntPtr[j] != IntPtr[j & 0x07]) + return FALSE; + IntPtr += pitch; + } + break; + default: return FALSE; + } + + } + + + if(h == 32) { + CARD32 *IntPtr2, *IntPtr3, *IntPtr4; + i = 8; + IntPtr = (CARD32*)pPixmap->devPrivate.ptr; + IntPtr2 = IntPtr + (pitch << 3); + IntPtr3 = IntPtr2 + (pitch << 3); + IntPtr4 = IntPtr3 + (pitch << 3); + while(i--) { + for(j = 0; j < dwords; j++) + if((IntPtr[j] != IntPtr2[j]) || (IntPtr[j] != IntPtr3[j]) || + (IntPtr[j] != IntPtr4[j])) + return FALSE; + IntPtr += pitch; + IntPtr2 += pitch; + IntPtr3 += pitch; + IntPtr4 += pitch; + } + } else if (h == 16) { + CARD32 *IntPtr2; + i = 8; + IntPtr = (CARD32*)pPixmap->devPrivate.ptr; + IntPtr2 = IntPtr + (pitch << 3); + while(i--) { + for(j = 0; j < dwords; j++) + if(IntPtr[j] != IntPtr2[j]) + return FALSE; + IntPtr += pitch; + IntPtr2 += pitch; + } + } + + pPriv->flags |= REDUCIBLE_TO_8x8; + + if(checkMono) { + XAAInfoRecPtr infoRec = + GET_XAAINFORECPTR_FROM_DRAWABLE(&pPixmap->drawable); + unsigned char bits[8]; + int fg, bg = -1, x, y; + + i = (h > 8) ? 8 : h; + j = (w > 8) ? 8 : w; + + if(pPixmap->drawable.bitsPerPixel == 8) { + unsigned char *srcp = pPixmap->devPrivate.ptr; + fg = srcp[0]; + pitch = pPixmap->devKind; + for(y = 0; y < i; y++) { + bits[y] = 0; + for(x = 0; x < j; x++) { + if(srcp[x] != fg) { + if(bg == -1) bg = srcp[x]; + else if(bg != srcp[x]) return TRUE; + } else bits[y] |= 1 << x; + } + srcp += pitch; + } + } else if(pPixmap->drawable.bitsPerPixel == 16) { + unsigned short *srcp = (unsigned short*)pPixmap->devPrivate.ptr; + fg = srcp[0]; + pitch = pPixmap->devKind >> 1; + for(y = 0; y < i; y++) { + bits[y] = 0; + for(x = 0; x < j; x++) { + if(srcp[x] != fg) { + if(bg == -1) bg = srcp[x]; + else if(bg != srcp[x]) return TRUE; + } else bits[y] |= 1 << x; + } + srcp += pitch; + } + } else if(pPixmap->drawable.bitsPerPixel == 24) { + CARD32 val; + unsigned char *srcp = pPixmap->devPrivate.ptr; + fg = *((CARD32*)srcp) & 0x00FFFFFF; + pitch = pPixmap->devKind; + j *= 3; + for(y = 0; y < i; y++) { + bits[y] = 0; + for(x = 0; x < j; x+=3) { + val = *((CARD32*)(srcp+x)) & 0x00FFFFFF; + if(val != fg) { + if(bg == -1) bg = val; + else if(bg != val) + return TRUE; + } else bits[y] |= 1 << (x/3); + } + srcp += pitch; + } + } else if(pPixmap->drawable.bitsPerPixel == 32) { + IntPtr = (CARD32*)pPixmap->devPrivate.ptr; + fg = IntPtr[0]; + for(y = 0; y < i; y++) { + bits[y] = 0; + for(x = 0; x < j; x++) { + if(IntPtr[x] != fg) { + if(bg == -1) bg = IntPtr[x]; + else if(bg != IntPtr[x]) return TRUE; + } else bits[y] |= 1 << x; + } + IntPtr += pitch; + } + } else return TRUE; + + pPriv->fg = fg; + if(bg == -1) pPriv->bg = fg; + else pPriv->bg = bg; + + if(h < 8) { + switch(h) { + case 1: bits[1] = bits[0]; + case 2: bits[2] = bits[0]; bits[3] = bits[1]; + case 4: bits[4] = bits[0]; bits[5] = bits[1]; + bits[6] = bits[2]; bits[7] = bits[3]; + break; + } + } + + pPriv->pattern0 = + bits[0] | (bits[1]<<8) | (bits[2]<<16) | (bits[3]<<24); + pPriv->pattern1 = + bits[4] | (bits[5]<<8) | (bits[6]<<16) | (bits[7]<<24); + + if(w < 8) { + switch(w) { + case 1: pPriv->pattern0 |= (pPriv->pattern0 << 1); + pPriv->pattern1 |= (pPriv->pattern1 << 1); + case 2: pPriv->pattern0 |= (pPriv->pattern0 << 2); + pPriv->pattern1 |= (pPriv->pattern1 << 2); + case 4: pPriv->pattern0 |= (pPriv->pattern0 << 4); + pPriv->pattern1 |= (pPriv->pattern1 << 4); + } + } + pPriv->flags |= REDUCIBLE_TO_2_COLOR; + + if(infoRec->Mono8x8PatternFillFlags & BIT_ORDER_IN_BYTE_MSBFIRST) { + pPriv->pattern0 = SWAP_BITS_IN_BYTES(pPriv->pattern0); + pPriv->pattern1 = SWAP_BITS_IN_BYTES(pPriv->pattern1); + } + + } + + return TRUE; +} + + +void XAATileCache( + ScrnInfoPtr pScrn, + XAACacheInfoPtr pCache, + int w, int h +) { + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + + (*infoRec->SetupForScreenToScreenCopy)(pScrn, 1, 1, GXcopy, ~0, -1); + + while((w << 1) <= pCache->w) { + (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pCache->x, pCache->y, + pCache->x + w, pCache->y, w, h); + w <<= 1; + } + if(w != pCache->w) { + (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pCache->x, pCache->y, + pCache->x + w, pCache->y, pCache->w - w, h); + w = pCache->w; + } + + while((h << 1) <= pCache->h) { + (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pCache->x, pCache->y, + pCache->x, pCache->y + h, w, h); + h <<= 1; + } + if(h != pCache->h) { + (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pCache->x, pCache->y, + pCache->x, pCache->y + h, w, pCache->h - h); + } + SET_SYNC_FLAG(infoRec); +} + +XAACacheInfoPtr +XAACacheTile(ScrnInfoPtr pScrn, PixmapPtr pPix) +{ + int w = pPix->drawable.width; + int h = pPix->drawable.height; + int size = max(w, h); + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + XAAPixmapCachePrivatePtr pCachePriv = + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; + XAACacheInfoPtr pCache, cacheRoot = NULL; + int i, max = 0; + int *current; + + if(size <= 128) { + if(pCachePriv->Info128) { + cacheRoot = pCachePriv->Info128; + max = pCachePriv->Num128x128; + current = &pCachePriv->Current128; + } else { + cacheRoot = pCachePriv->InfoPartial; + max = pCachePriv->NumPartial; + current = &pCachePriv->CurrentPartial; + } + } else if(size <= 256) { + cacheRoot = pCachePriv->Info256; + max = pCachePriv->Num256x256; + current = &pCachePriv->Current256; + } else if(size <= 512) { + cacheRoot = pCachePriv->Info512; + max = pCachePriv->Num512x512; + current = &pCachePriv->Current512; + } else { /* something's wrong */ + ErrorF("Something's wrong in XAACacheTile()\n"); + return pCachePriv->Info128; + } + + pCache = cacheRoot; + + /* lets look for it */ + for(i = 0; i < max; i++, pCache++) { + if(pCache->serialNumber == pPix->drawable.serialNumber) { + pCache->trans_color = -1; + return pCache; + } + } + + pCache = &cacheRoot[(*current)++]; + if(*current >= max) *current = 0; + + pCache->serialNumber = pPix->drawable.serialNumber; + pCache->trans_color = pCache->bg = pCache->fg = -1; + pCache->orig_w = w; pCache->orig_h = h; + (*infoRec->WritePixmapToCache)( + pScrn, pCache->x, pCache->y, w, h, pPix->devPrivate.ptr, + pPix->devKind, pPix->drawable.bitsPerPixel, pPix->drawable.depth); + if(!(infoRec->PixmapCacheFlags & DO_NOT_TILE_COLOR_DATA) && + ((w != pCache->w) || (h != pCache->h))) + XAATileCache(pScrn, pCache, w, h); + + return pCache; +} + +XAACacheInfoPtr +XAACacheMonoStipple(ScrnInfoPtr pScrn, PixmapPtr pPix) +{ + int w = pPix->drawable.width; + int h = pPix->drawable.height; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + XAAPixmapCachePrivatePtr pCachePriv = + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; + XAACacheInfoPtr pCache, cacheRoot = NULL; + int i, max = 0, funcNo, pad, dwords, bpp = pScrn->bitsPerPixel; + int *current; + StippleScanlineProcPtr StippleFunc; + unsigned char *data, *srcPtr, *dstPtr; + + if((h <= 128) && (w <= 128 * bpp)) { + if(pCachePriv->Info128) { + cacheRoot = pCachePriv->Info128; + max = pCachePriv->Num128x128; + current = &pCachePriv->Current128; + } else { + cacheRoot = pCachePriv->InfoPartial; + max = pCachePriv->NumPartial; + current = &pCachePriv->CurrentPartial; + } + } else if((h <= 256) && (w <= 256 * bpp)){ + cacheRoot = pCachePriv->Info256; + max = pCachePriv->Num256x256; + current = &pCachePriv->Current256; + } else if((h <= 512) && (w <= 526 * bpp)){ + cacheRoot = pCachePriv->Info512; + max = pCachePriv->Num512x512; + current = &pCachePriv->Current512; + } else { /* something's wrong */ + ErrorF("Something's wrong in XAACacheMonoStipple()\n"); + return pCachePriv->Info128; + } + + pCache = cacheRoot; + + /* lets look for it */ + for(i = 0; i < max; i++, pCache++) { + if((pCache->serialNumber == pPix->drawable.serialNumber) && + (pCache->fg == -1) && (pCache->bg == -1)) { + pCache->trans_color = -1; + return pCache; + } + } + + pCache = &cacheRoot[(*current)++]; + if(*current >= max) *current = 0; + + pCache->serialNumber = pPix->drawable.serialNumber; + pCache->trans_color = pCache->bg = pCache->fg = -1; + pCache->orig_w = w; pCache->orig_h = h; + + if(w <= 32) { + if(w & (w - 1)) funcNo = 1; + else funcNo = 0; + } else funcNo = 2; + + pad = BitmapBytePad(pCache->w * bpp); + dwords = bytes_to_int32(pad); + dstPtr = data = (unsigned char*)malloc(pad * pCache->h); + srcPtr = (unsigned char*)pPix->devPrivate.ptr; + + if(infoRec->ScreenToScreenColorExpandFillFlags & BIT_ORDER_IN_BYTE_MSBFIRST) + StippleFunc = XAAStippleScanlineFuncMSBFirst[funcNo]; + else + StippleFunc = XAAStippleScanlineFuncLSBFirst[funcNo]; + + /* don't bother generating more than we'll ever use */ + max = ((pScrn->displayWidth + w - 1) + 31) >> 5; + if(dwords > max) + dwords = max; + + for(i = 0; i < h; i++) { + (*StippleFunc)((CARD32*)dstPtr, (CARD32*)srcPtr, 0, w, dwords); + srcPtr += pPix->devKind; + dstPtr += pad; + } + + while((h<<1) <= pCache->h) { + memcpy(data + (pad * h), data, pad * h); + h <<= 1; + } + + if(h < pCache->h) + memcpy(data + (pad * h), data, pad * (pCache->h - h)); + + (*infoRec->WritePixmapToCache)( + pScrn, pCache->x, pCache->y, pCache->w, pCache->h, data, + pad, bpp, pScrn->depth); + + free(data); + + return pCache; +} + +XAACacheInfoPtr +XAACachePlanarMonoStipple(ScrnInfoPtr pScrn, PixmapPtr pPix) +{ + int w = pPix->drawable.width; + int h = pPix->drawable.height; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + XAAPixmapCachePrivatePtr pCachePriv = + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; + XAACacheInfoPtr pCache, cacheRoot = NULL; + int i, max = 0; + int *current; + + if((h <= 128) && (w <= 128)) { + if(pCachePriv->Info128) { + cacheRoot = pCachePriv->Info128; + max = pCachePriv->Num128x128; + current = &pCachePriv->Current128; + } else { + cacheRoot = pCachePriv->InfoPartial; + max = pCachePriv->NumPartial; + current = &pCachePriv->CurrentPartial; + } + } else if((h <= 256) && (w <= 256)){ + cacheRoot = pCachePriv->Info256; + max = pCachePriv->Num256x256; + current = &pCachePriv->Current256; + } else if((h <= 512) && (w <= 526)){ + cacheRoot = pCachePriv->Info512; + max = pCachePriv->Num512x512; + current = &pCachePriv->Current512; + } else { /* something's wrong */ + ErrorF("Something's wrong in XAACachePlanarMonoStipple()\n"); + return pCachePriv->Info128; + } + + pCache = cacheRoot; + + /* lets look for it */ + for(i = 0; i < max; i++, pCache++) { + if((pCache->serialNumber == pPix->drawable.serialNumber) && + (pCache->fg == -1) && (pCache->bg == -1)) { + pCache->trans_color = -1; + return pCache; + } + } + + pCache = &cacheRoot[(*current)++]; + if(*current >= max) *current = 0; + + pCache->serialNumber = pPix->drawable.serialNumber; + pCache->trans_color = pCache->bg = pCache->fg = -1; + pCache->orig_w = w; pCache->orig_h = h; + + /* Plane 0 holds the stipple. Plane 1 holds the inverted stipple */ + (*infoRec->WriteBitmapToCache)(pScrn, pCache->x, pCache->y, + pPix->drawable.width, pPix->drawable.height, pPix->devPrivate.ptr, + pPix->devKind, 1, 2); + if(!(infoRec->PixmapCacheFlags & DO_NOT_TILE_MONO_DATA) && + ((w != pCache->w) || (h != pCache->h))) + XAATileCache(pScrn, pCache, w, h); + + return pCache; +} + +XAACachePlanarMonoStippleProc +XAAGetCachePlanarMonoStipple(void) +{ + return XAACachePlanarMonoStipple; +} + +XAACacheInfoPtr +XAACacheStipple(ScrnInfoPtr pScrn, PixmapPtr pPix, int fg, int bg) +{ + int w = pPix->drawable.width; + int h = pPix->drawable.height; + int size = max(w, h); + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + XAAPixmapCachePrivatePtr pCachePriv = + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; + XAACacheInfoPtr pCache, cacheRoot = NULL; + int i, max = 0; + int *current; + + if(size <= 128) { + if(pCachePriv->Info128) { + cacheRoot = pCachePriv->Info128; + max = pCachePriv->Num128x128; + current = &pCachePriv->Current128; + } else { + cacheRoot = pCachePriv->InfoPartial; + max = pCachePriv->NumPartial; + current = &pCachePriv->CurrentPartial; + } + } else if(size <= 256) { + cacheRoot = pCachePriv->Info256; + max = pCachePriv->Num256x256; + current = &pCachePriv->Current256; + } else if(size <= 512) { + cacheRoot = pCachePriv->Info512; + max = pCachePriv->Num512x512; + current = &pCachePriv->Current512; + } else { /* something's wrong */ + ErrorF("Something's wrong in XAACacheStipple()\n"); + return pCachePriv->Info128; + } + + pCache = cacheRoot; + /* lets look for it */ + if(bg == -1) + for(i = 0; i < max; i++, pCache++) { + if((pCache->serialNumber == pPix->drawable.serialNumber) && + (fg == pCache->fg) && (pCache->fg != pCache->bg)) { + pCache->trans_color = pCache->bg; + return pCache; + } + } + else + for(i = 0; i < max; i++, pCache++) { + if((pCache->serialNumber == pPix->drawable.serialNumber) && + (fg == pCache->fg) && (bg == pCache->bg)) { + pCache->trans_color = -1; + return pCache; + } + } + + pCache = &cacheRoot[(*current)++]; + if(*current >= max) *current = 0; + + pCache->serialNumber = pPix->drawable.serialNumber; + pCache->fg = fg; + if(bg == -1) + pCache->trans_color = bg = fg ^ 1; + else + pCache->trans_color = -1; + pCache->bg = bg; + + pCache->orig_w = w; pCache->orig_h = h; + (*infoRec->WriteBitmapToCache)(pScrn, pCache->x, pCache->y, + pPix->drawable.width, pPix->drawable.height, pPix->devPrivate.ptr, + pPix->devKind, fg, bg); + if(!(infoRec->PixmapCacheFlags & DO_NOT_TILE_COLOR_DATA) && + ((w != pCache->w) || (h != pCache->h))) + XAATileCache(pScrn, pCache, w, h); + + return pCache; +} + + + +XAACacheInfoPtr +XAACacheMono8x8Pattern(ScrnInfoPtr pScrn, int pat0, int pat1) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + XAAPixmapCachePrivatePtr pCachePriv = + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; + XAACacheInfoPtr pCache = pCachePriv->InfoMono; + int i; + + for(i = 0; i < pCachePriv->NumMono; i++, pCache++) { + if(pCache->serialNumber && + (pCache->pat0 == pat0) && (pCache->pat1 == pat1)) + return pCache; + } + + /* OK, let's cache it */ + pCache = &pCachePriv->InfoMono[pCachePriv->CurrentMono++]; + if(pCachePriv->CurrentMono >= pCachePriv->NumMono) + pCachePriv->CurrentMono = 0; + + pCache->serialNumber = 1; /* we don't care since we do lookups by pattern */ + pCache->pat0 = pat0; + pCache->pat1 = pat1; + + (*infoRec->WriteMono8x8PatternToCache)(pScrn, pCache); + + return pCache; +} + + + +XAACacheInfoPtr +XAACacheColor8x8Pattern(ScrnInfoPtr pScrn, PixmapPtr pPix, int fg, int bg) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + XAAPixmapCachePrivatePtr pCachePriv = + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; + XAACacheInfoPtr pCache = pCachePriv->InfoColor; + XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(pPix); + int i; + + if(!(pixPriv->flags & REDUCIBLE_TO_2_COLOR)) { + for(i = 0; i < pCachePriv->NumColor; i++, pCache++) { + if(pCache->serialNumber == pPix->drawable.serialNumber) { + pCache->trans_color = -1; + return pCache; + } + } + pCache = &pCachePriv->InfoColor[pCachePriv->CurrentColor++]; + if(pCachePriv->CurrentColor >= pCachePriv->NumColor) + pCachePriv->CurrentColor = 0; + + pCache->serialNumber = pPix->drawable.serialNumber; + pCache->trans_color = pCache->fg = pCache->bg = -1; + } else { + int pat0 = pixPriv->pattern0; + int pat1 = pixPriv->pattern1; + + if(fg == -1) { /* it's a tile */ + fg = pixPriv->fg; bg = pixPriv->bg; + } + + if(bg == -1) { /* stipple */ + for(i = 0; i < pCachePriv->NumColor; i++, pCache++) { + if(pCache->serialNumber && + (pCache->pat0 == pat0) && (pCache->pat1 == pat1) && + (pCache->fg == fg) && (pCache->bg != fg)) { + pCache->trans_color = pCache->bg; + return pCache; + } + } + } else { /* opaque stipple */ + for(i = 0; i < pCachePriv->NumColor; i++, pCache++) { + if(pCache->serialNumber && + (pCache->pat0 == pat0) && (pCache->pat1 == pat1) && + (pCache->fg == fg) && (pCache->bg == bg)) { + pCache->trans_color = -1; + return pCache; + } + } + } + pCache = &pCachePriv->InfoColor[pCachePriv->CurrentColor++]; + if(pCachePriv->CurrentColor >= pCachePriv->NumColor) + pCachePriv->CurrentColor = 0; + + if(bg == -1) + pCache->trans_color = bg = fg ^ 1; + else + pCache->trans_color = -1; + + pCache->pat0 = pat0; pCache->pat1 = pat1; + pCache->fg = fg; pCache->bg = bg; + pCache->serialNumber = 1; + } + + (*infoRec->WriteColor8x8PatternToCache)(pScrn, pPix, pCache); + + return pCache; +} + + +void +XAAWriteBitmapToCache( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int fg, int bg +) { + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + + (*infoRec->WriteBitmap)(pScrn, x, y, w, h, src, srcwidth, + 0, fg, bg, GXcopy, ~0); +} + +void +XAAWriteBitmapToCacheLinear( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int fg, int bg +){ + ScreenPtr pScreen = pScrn->pScreen; + PixmapPtr pScreenPix, pDstPix; + ChangeGCVal gcvals[2]; + GCPtr pGC; + + pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); + + pDstPix = GetScratchPixmapHeader(pScreen, pScreenPix->drawable.width, + y + h, pScreenPix->drawable.depth, + pScreenPix->drawable.bitsPerPixel, + pScreenPix->devKind, + pScreenPix->devPrivate.ptr); + + pGC = GetScratchGC(pScreenPix->drawable.depth, pScreen); + gcvals[0].val = fg; + gcvals[1].val = bg; + ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcvals); + ValidateGC((DrawablePtr)pDstPix, pGC); + + /* We've unwrapped already so these ops miss a sync */ + SYNC_CHECK(pScrn); + + (*pGC->ops->PutImage)((DrawablePtr)pDstPix, pGC, 1, x, y, w, h, 0, + XYBitmap, (pointer)src); + + FreeScratchGC(pGC); + FreeScratchPixmapHeader(pDstPix); +} + + +void +XAAWritePixmapToCache( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int bpp, int depth +) { + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + + (*infoRec->WritePixmap)(pScrn, x, y, w, h, src, srcwidth, + GXcopy, ~0, -1, bpp, depth); +} + + + +void +XAAWritePixmapToCacheLinear( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int bpp, int depth +){ + ScreenPtr pScreen = pScrn->pScreen; + PixmapPtr pScreenPix, pDstPix; + GCPtr pGC; + + pScreenPix = (*pScreen->GetScreenPixmap)(pScreen); + + pDstPix = GetScratchPixmapHeader(pScreen, x + w, y + h, + depth, bpp, pScreenPix->devKind, + pScreenPix->devPrivate.ptr); + + pGC = GetScratchGC(depth, pScreen); + ValidateGC((DrawablePtr)pDstPix, pGC); + + /* We've unwrapped already so these ops miss a sync */ + SYNC_CHECK(pScrn); + + if(bpp == BitsPerPixel(depth)) + (*pGC->ops->PutImage)((DrawablePtr)pDstPix, pGC, depth, x, y, w, + h, 0, ZPixmap, (pointer)src); + else { + PixmapPtr pSrcPix; + + pSrcPix = GetScratchPixmapHeader(pScreen, w, h, depth, bpp, + srcwidth, (pointer)src); + + (*pGC->ops->CopyArea)((DrawablePtr)pSrcPix, (DrawablePtr)pDstPix, + pGC, 0, 0, w, h, x, y); + + FreeScratchPixmapHeader(pSrcPix); + } + + FreeScratchGC(pGC); + FreeScratchPixmapHeader(pDstPix); +} + + +void +XAAWriteMono8x8PatternToCache( + ScrnInfoPtr pScrn, + XAACacheInfoPtr pCache +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + XAAPixmapCachePrivatePtr pCachePriv = + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; + unsigned char *data; + int pad, Bpp = (pScrn->bitsPerPixel >> 3); + + pCache->offsets = pCachePriv->MonoOffsets; + + pad = BitmapBytePad(pCache->w * pScrn->bitsPerPixel); + + data = (unsigned char*)malloc(pad * pCache->h); + if(!data) return; + + if(infoRec->Mono8x8PatternFillFlags & HARDWARE_PATTERN_PROGRAMMED_ORIGIN) { + CARD32* ptr = (CARD32*)data; + ptr[0] = pCache->pat0; ptr[1] = pCache->pat1; + } else { + CARD32 *ptr; + DDXPointPtr pPoint = pCache->offsets; + int patx, paty, i; + + for(i = 0; i < 64; i++, pPoint++) { + patx = pCache->pat0; paty = pCache->pat1; + XAARotateMonoPattern(&patx, &paty, i & 0x07, i >> 3, + (infoRec->Mono8x8PatternFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST)); + ptr = (CARD32*)(data + (pad * pPoint->y) + (Bpp * pPoint->x)); + ptr[0] = patx; ptr[1] = paty; + } + } + + (*infoRec->WritePixmapToCache)(pScrn, pCache->x, pCache->y, + pCache->w, pCache->h, data, pad, pScrn->bitsPerPixel, pScrn->depth); + + free(data); +} + +void +XAAWriteColor8x8PatternToCache( + ScrnInfoPtr pScrn, + PixmapPtr pPix, + XAACacheInfoPtr pCache +){ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + XAAPixmapPtr pixPriv = XAA_GET_PIXMAP_PRIVATE(pPix); + XAAPixmapCachePrivatePtr pCachePriv = + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; + int pad, i, w, h, nw, nh, Bpp; + unsigned char *data, *srcPtr, *dstPtr; + + pCache->offsets = pCachePriv->ColorOffsets; + + if(pixPriv->flags & REDUCIBLE_TO_2_COLOR) { + CARD32* ptr; + pad = BitmapBytePad(pCache->w); + data = (unsigned char*)malloc(pad * pCache->h); + if(!data) return; + + if(infoRec->Color8x8PatternFillFlags & + HARDWARE_PATTERN_PROGRAMMED_ORIGIN) { + ptr = (CARD32*)data; + ptr[0] = pCache->pat0; ptr[1] = pCache->pat1; + } else { + int patx, paty; + + ptr = (CARD32*)data; + ptr[0] = ptr[2] = pCache->pat0; ptr[1] = ptr[3] = pCache->pat1; + for(i = 1; i < 8; i++) { + patx = pCache->pat0; paty = pCache->pat1; + XAARotateMonoPattern(&patx, &paty, i, 0, + (infoRec->Mono8x8PatternFillFlags & + BIT_ORDER_IN_BYTE_MSBFIRST)); + ptr = (CARD32*)(data + (pad * i)); + ptr[0] = ptr[2] = patx; ptr[1] = ptr[3] = paty; + } + } + + (*infoRec->WriteBitmapToCache)(pScrn, pCache->x, pCache->y, + pCache->w, pCache->h, data, pad, pCache->fg, pCache->bg); + + free(data); + return; + } + + Bpp = pScrn->bitsPerPixel >> 3; + h = min(8,pPix->drawable.height); + w = min(8,pPix->drawable.width); + pad = BitmapBytePad(pCache->w * pScrn->bitsPerPixel); + + data = (unsigned char*)malloc(pad * pCache->h); + if(!data) return; + + /* Write and expand horizontally. */ + for (i = h, dstPtr = data, srcPtr = pPix->devPrivate.ptr; i--; + srcPtr += pPix->devKind, dstPtr += pScrn->bitsPerPixel) { + nw = w; + memcpy(dstPtr, srcPtr, w * Bpp); + while (nw != 8) { + memcpy(dstPtr + (nw * Bpp), dstPtr, nw * Bpp); + nw <<= 1; + } + } + nh = h; + /* Expand vertically. */ + while (nh != 8) { + memcpy(data + (nh*pScrn->bitsPerPixel), data, nh*pScrn->bitsPerPixel); + nh <<= 1; + } + + if(!(infoRec->Color8x8PatternFillFlags & + HARDWARE_PATTERN_PROGRAMMED_ORIGIN)){ + int j; + unsigned char *ptr = data + (128 * Bpp); + + memcpy(data + (64 * Bpp), data, 64 * Bpp); + for(i = 1; i < 8; i++, ptr += (128 * Bpp)) { + for(j = 0; j < 8; j++) { + memcpy(ptr + (j * 8) * Bpp, data + (j * 8 + i) * Bpp, + (8 - i) * Bpp); + memcpy(ptr + (j * 8 + 8 - i) * Bpp, data + j * 8 * Bpp, i*Bpp); + } + memcpy(ptr + (64 * Bpp), ptr, 64 * Bpp); + } + } + + (*infoRec->WritePixmapToCache)(pScrn, pCache->x, pCache->y, + pCache->w, pCache->h, data, pad, pScrn->bitsPerPixel, pScrn->depth); + + free(data); +} + + + +int +XAAStippledFillChooser(GCPtr pGC) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + PixmapPtr pPixmap = pGC->stipple; + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); + + if(!(pPriv->flags & REDUCIBILITY_CHECKED) && + (infoRec->CanDoMono8x8 || infoRec->CanDoColor8x8)) { + XAACheckStippleReducibility(pPixmap); + } + + + if(pPriv->flags & REDUCIBLE_TO_8x8) { + if(infoRec->CanDoMono8x8 && + !(infoRec->FillMono8x8PatternSpansFlags & NO_TRANSPARENCY) && + ((pGC->alu == GXcopy) || !(infoRec->FillMono8x8PatternSpansFlags & + TRANSPARENCY_GXCOPY_ONLY)) && + CHECK_ROP(pGC,infoRec->FillMono8x8PatternSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillMono8x8PatternSpansFlags) && + CHECK_FG(pGC,infoRec->FillMono8x8PatternSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillMono8x8PatternSpansFlags)) { + + return DO_MONO_8x8; + } + + if(infoRec->CanDoColor8x8 && + !(infoRec->FillColor8x8PatternSpansFlags & NO_TRANSPARENCY) && + ((pGC->alu == GXcopy) || !(infoRec->FillColor8x8PatternSpansFlags & + TRANSPARENCY_GXCOPY_ONLY)) && + CHECK_ROP(pGC,infoRec->FillColor8x8PatternSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillColor8x8PatternSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillColor8x8PatternSpansFlags)) { + + return DO_COLOR_8x8; + } + } + + if(infoRec->UsingPixmapCache && infoRec->FillCacheExpandSpans && + (pPixmap->drawable.height <= infoRec->MaxCacheableStippleHeight) && + (pPixmap->drawable.width <= infoRec->MaxCacheableStippleWidth / + infoRec->CacheColorExpandDensity) && + !(infoRec->FillCacheExpandSpansFlags & NO_TRANSPARENCY) && + ((pGC->alu == GXcopy) || !(infoRec->FillCacheExpandSpansFlags & + TRANSPARENCY_GXCOPY_ONLY)) && + CHECK_ROP(pGC,infoRec->FillCacheExpandSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillCacheExpandSpansFlags) && + CHECK_FG(pGC,infoRec->FillCacheExpandSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillCacheExpandSpansFlags)) { + + return DO_CACHE_EXPAND; + } + + + if(infoRec->UsingPixmapCache && + !(infoRec->PixmapCacheFlags & DO_NOT_BLIT_STIPPLES) && + infoRec->FillCacheBltSpans && + (pPixmap->drawable.height <= infoRec->MaxCacheableTileHeight) && + (pPixmap->drawable.width <= infoRec->MaxCacheableTileWidth) && + !(infoRec->FillCacheBltSpansFlags & NO_TRANSPARENCY) && + ((pGC->alu == GXcopy) || !(infoRec->FillCacheBltSpansFlags & + TRANSPARENCY_GXCOPY_ONLY)) && + CHECK_ROP(pGC,infoRec->FillCacheBltSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillCacheBltSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillCacheBltSpansFlags)) { + + return DO_CACHE_BLT; + } + + if(infoRec->FillColorExpandSpans && + !(infoRec->FillColorExpandSpansFlags & NO_TRANSPARENCY) && + ((pGC->alu == GXcopy) || !(infoRec->FillColorExpandSpansFlags & + TRANSPARENCY_GXCOPY_ONLY)) && + CHECK_ROP(pGC,infoRec->FillColorExpandSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillColorExpandSpansFlags) && + CHECK_FG(pGC,infoRec->FillColorExpandSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillColorExpandSpansFlags)) { + + return DO_COLOR_EXPAND; + } + + return 0; +} + + +int +XAAOpaqueStippledFillChooser(GCPtr pGC) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + PixmapPtr pPixmap = pGC->stipple; + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); + + if(XAA_DEPTH_BUG(pGC)) + return 0; + + if(!(pPriv->flags & REDUCIBILITY_CHECKED) && + (infoRec->CanDoMono8x8 || infoRec->CanDoColor8x8)) { + XAACheckStippleReducibility(pPixmap); + } + + if(pPriv->flags & REDUCIBLE_TO_8x8) { + if(infoRec->CanDoMono8x8 && + !(infoRec->FillMono8x8PatternSpansFlags & TRANSPARENCY_ONLY) && + CHECK_ROP(pGC,infoRec->FillMono8x8PatternSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillMono8x8PatternSpansFlags) && + CHECK_COLORS(pGC,infoRec->FillMono8x8PatternSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillMono8x8PatternSpansFlags)) { + + return DO_MONO_8x8; + } + + if(infoRec->CanDoColor8x8 && + CHECK_ROP(pGC,infoRec->FillColor8x8PatternSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillColor8x8PatternSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillColor8x8PatternSpansFlags)) { + + return DO_COLOR_8x8; + } + } + + if(infoRec->UsingPixmapCache && infoRec->FillCacheExpandSpans && + (pPixmap->drawable.height <= infoRec->MaxCacheableStippleHeight) && + (pPixmap->drawable.width <= infoRec->MaxCacheableStippleWidth / + infoRec->CacheColorExpandDensity) && + !(infoRec->FillCacheExpandSpansFlags & TRANSPARENCY_ONLY) && + CHECK_ROP(pGC,infoRec->FillCacheExpandSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillCacheExpandSpansFlags) && + CHECK_COLORS(pGC,infoRec->FillCacheExpandSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillCacheExpandSpansFlags)) { + + return DO_CACHE_EXPAND; + } + + if(infoRec->UsingPixmapCache && + !(infoRec->PixmapCacheFlags & DO_NOT_BLIT_STIPPLES) && + infoRec->FillCacheBltSpans && + (pPixmap->drawable.height <= infoRec->MaxCacheableTileHeight) && + (pPixmap->drawable.width <= infoRec->MaxCacheableTileWidth) && + CHECK_ROP(pGC,infoRec->FillCacheBltSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillCacheBltSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillCacheBltSpansFlags)) { + + return DO_CACHE_BLT; + } + + if(infoRec->FillColorExpandSpans && + !(infoRec->FillColorExpandSpansFlags & TRANSPARENCY_ONLY) && + CHECK_ROP(pGC,infoRec->FillColorExpandSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillColorExpandSpansFlags) && + CHECK_COLORS(pGC,infoRec->FillColorExpandSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillColorExpandSpansFlags)) { + + return DO_COLOR_EXPAND; + } + + return 0; +} + + + +int +XAATiledFillChooser(GCPtr pGC) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + PixmapPtr pPixmap = pGC->tile.pixmap; + XAAPixmapPtr pPriv = XAA_GET_PIXMAP_PRIVATE(pPixmap); + + if(IS_OFFSCREEN_PIXMAP(pPixmap) && infoRec->FillCacheBltSpans && + CHECK_ROP(pGC,infoRec->FillCacheBltSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillCacheBltSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillCacheBltSpansFlags)) { + + return DO_PIXMAP_COPY; + } + + if(!(pPriv->flags & REDUCIBILITY_CHECKED) && + (infoRec->CanDoMono8x8 || infoRec->CanDoColor8x8)) { + XAACheckTileReducibility(pPixmap,infoRec->CanDoMono8x8); + } + + if(pPriv->flags & REDUCIBLE_TO_8x8) { + if((pPriv->flags & REDUCIBLE_TO_2_COLOR) && infoRec->CanDoMono8x8 && + !(infoRec->FillMono8x8PatternSpansFlags & TRANSPARENCY_ONLY) && + CHECK_ROP(pGC,infoRec->FillMono8x8PatternSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillMono8x8PatternSpansFlags) && + (!(infoRec->FillMono8x8PatternSpansFlags & RGB_EQUAL) || + (CHECK_RGB_EQUAL(pPriv->fg) && CHECK_RGB_EQUAL(pPriv->bg))) && + CHECK_PLANEMASK(pGC,infoRec->FillMono8x8PatternSpansFlags)) { + + return DO_MONO_8x8; + } + + if(infoRec->CanDoColor8x8 && + CHECK_ROP(pGC,infoRec->FillColor8x8PatternSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillColor8x8PatternSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillColor8x8PatternSpansFlags)) { + + return DO_COLOR_8x8; + } + } + + if(infoRec->UsingPixmapCache && infoRec->FillCacheBltSpans && + (pPixmap->drawable.height <= infoRec->MaxCacheableTileHeight) && + (pPixmap->drawable.width <= infoRec->MaxCacheableTileWidth) && + CHECK_ROP(pGC,infoRec->FillCacheBltSpansFlags) && + CHECK_ROPSRC(pGC,infoRec->FillCacheBltSpansFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillCacheBltSpansFlags)) { + + return DO_CACHE_BLT; + } + + if(infoRec->FillImageWriteRects && + CHECK_NO_GXCOPY(pGC,infoRec->FillImageWriteRectsFlags) && + CHECK_ROP(pGC,infoRec->FillImageWriteRectsFlags) && + CHECK_ROPSRC(pGC,infoRec->FillImageWriteRectsFlags) && + CHECK_PLANEMASK(pGC,infoRec->FillImageWriteRectsFlags)) { + + return DO_IMAGE_WRITE; + } + + return 0; +} + + +static int RotateMasksX[8] = { + 0xFFFFFFFF, 0x7F7F7F7F, 0x3F3F3F3F, 0x1F1F1F1F, + 0x0F0F0F0F, 0x07070707, 0x03030303, 0x01010101 +}; + +static int RotateMasksY[4] = { + 0xFFFFFFFF, 0x00FFFFFF, 0x0000FFFF, 0x000000FF +}; + +void +XAARotateMonoPattern( + int *pat0, int *pat1, + int xorg, int yorg, + Bool msbfirst +){ + int tmp, mask; + + if(xorg) { + if(msbfirst) xorg = 8 - xorg; + mask = RotateMasksX[xorg]; + *pat0 = ((*pat0 >> xorg) & mask) | ((*pat0 << (8 - xorg)) & ~mask); + *pat1 = ((*pat1 >> xorg) & mask) | ((*pat1 << (8 - xorg)) & ~mask); + } + if(yorg >= 4) { + tmp = *pat0; *pat0 = *pat1; *pat1 = tmp; + yorg -= 4; + } + if(yorg) { + mask = RotateMasksY[yorg]; + yorg <<= 3; + tmp = *pat0; + *pat0 = ((*pat0 >> yorg) & mask) | ((*pat1 << (32 - yorg)) & ~mask); + *pat1 = ((*pat1 >> yorg) & mask) | ((tmp << (32 - yorg)) & ~mask); + } +} + + + +void +XAAInvalidatePixmapCache(ScreenPtr pScreen) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + XAAPixmapCachePrivatePtr pCachePriv = + (XAAPixmapCachePrivatePtr)infoRec->PixmapCachePrivate; + int i; + + if(!pCachePriv) return; + + for(i = 0; i < pCachePriv->Num512x512; i++) + (pCachePriv->Info512)[i].serialNumber = 0; + for(i = 0; i < pCachePriv->Num256x256; i++) + (pCachePriv->Info256)[i].serialNumber = 0; + for(i = 0; i < pCachePriv->Num128x128; i++) + (pCachePriv->Info128)[i].serialNumber = 0; + for(i = 0; i < pCachePriv->NumPartial; i++) + (pCachePriv->InfoPartial)[i].serialNumber = 0; + for(i = 0; i < pCachePriv->NumMono; i++) + (pCachePriv->InfoMono)[i].serialNumber = 0; + for(i = 0; i < pCachePriv->NumColor; i++) + (pCachePriv->InfoColor)[i].serialNumber = 0; +} diff --git a/xorg-server/hw/xfree86/xaa/xaaPict.c b/xorg-server/hw/xfree86/xaa/xaaPict.c index e059d3d65..b66291458 100644 --- a/xorg-server/hw/xfree86/xaa/xaaPict.c +++ b/xorg-server/hw/xfree86/xaa/xaaPict.c @@ -1,655 +1,655 @@ -/* - * - * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. - * - * 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_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <string.h> - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "xf86str.h" -#include "mi.h" -#include "picturestr.h" -#include "glyphstr.h" -#include "picture.h" -#include "mipict.h" -#include "xaa.h" -#include "xaalocal.h" -#include "xaawrap.h" -#include "xaacexp.h" -#include "xf86fbman.h" -#include "servermd.h" - -Bool -XAAGetPixelFromRGBA ( - CARD32 *pixel, - CARD16 red, - CARD16 green, - CARD16 blue, - CARD16 alpha, - CARD32 format -){ - int rbits, bbits, gbits, abits; - int rshift, bshift, gshift, ashift; - - *pixel = 0; - - if(!PICT_FORMAT_COLOR(format)) - return FALSE; - - rbits = PICT_FORMAT_R(format); - gbits = PICT_FORMAT_G(format); - bbits = PICT_FORMAT_B(format); - abits = PICT_FORMAT_A(format); - - if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { - bshift = 0; - gshift = bbits; - rshift = gshift + gbits; - ashift = rshift + rbits; - } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { - rshift = 0; - gshift = rbits; - bshift = gshift + gbits; - ashift = bshift + bbits; - } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { - bshift = PICT_FORMAT_BPP(format) - bbits; - gshift = bshift - gbits; - rshift = gshift - rbits; - ashift = 0; - } else - return FALSE; - - *pixel |= ( blue >> (16 - bbits)) << bshift; - *pixel |= ( red >> (16 - rbits)) << rshift; - *pixel |= (green >> (16 - gbits)) << gshift; - *pixel |= (alpha >> (16 - abits)) << ashift; - - return TRUE; -} - - -Bool -XAAGetRGBAFromPixel( - CARD32 pixel, - CARD16 *red, - CARD16 *green, - CARD16 *blue, - CARD16 *alpha, - CARD32 format -){ - int rbits, bbits, gbits, abits; - int rshift, bshift, gshift, ashift; - - if(!PICT_FORMAT_COLOR(format)) - return FALSE; - - rbits = PICT_FORMAT_R(format); - gbits = PICT_FORMAT_G(format); - bbits = PICT_FORMAT_B(format); - abits = PICT_FORMAT_A(format); - - if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { - bshift = 0; - gshift = bbits; - rshift = gshift + gbits; - ashift = rshift + rbits; - } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { - rshift = 0; - gshift = rbits; - bshift = gshift + gbits; - ashift = bshift + bbits; - } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { - bshift = PICT_FORMAT_BPP(format) - bbits; - gshift = bshift - gbits; - rshift = gshift - rbits; - ashift = 0; - } else - return FALSE; - - *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); - while(rbits < 16) { - *red |= *red >> rbits; - rbits <<= 1; - } - - *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); - while(gbits < 16) { - *green |= *green >> gbits; - gbits <<= 1; - } - - *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); - while(bbits < 16) { - *blue |= *blue >> bbits; - bbits <<= 1; - } - - if(abits) { - *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); - while(abits < 16) { - *alpha |= *alpha >> abits; - abits <<= 1; - } - } else *alpha = 0xffff; - - return TRUE; -} - -/* 8:8:8 + PICT_a8 -> 8:8:8:8 texture */ - -void -XAA_888_plus_PICT_a8_to_8888 ( - CARD32 color, - CARD8 *alphaPtr, /* in bytes */ - int alphaPitch, - CARD32 *dstPtr, - int dstPitch, /* in dwords */ - int width, - int height -){ - int x; - - color &= 0x00ffffff; - - while(height--) { - for(x = 0; x < width; x++) - dstPtr[x] = color | (alphaPtr[x] << 24); - dstPtr += dstPitch; - alphaPtr += alphaPitch; - } -} - -#define DRAWABLE_IS_ON_CARD(pDraw) \ - (pDraw->type == DRAWABLE_WINDOW || \ - (pDraw->type == DRAWABLE_PIXMAP && IS_OFFSCREEN_PIXMAP(pDraw))) - -Bool -XAADoComposite ( - CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height -){ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - RegionRec region; - CARD32 *formats, *dstformats; - int flags = 0; - BoxPtr pbox; - int nbox, w, h; - - if(!REGION_NUM_RECTS(pDst->pCompositeClip)) - return TRUE; - - if(!infoRec->pScrn->vtSema || !DRAWABLE_IS_ON_CARD(pDst->pDrawable)) - return FALSE; - - if(DRAWABLE_IS_ON_CARD(pSrc->pDrawable)) - return FALSE; - - if (pSrc->transform || (pMask && pMask->transform)) - return FALSE; - - if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) - return FALSE; - - if ((pSrc->repeat && pSrc->repeatType != RepeatNormal) || - (pMask && pMask->repeat && pMask->repeatType != RepeatNormal)) - { - return FALSE; - } - - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - - if(pMask) { - if(pMask->componentAlpha) - return FALSE; - - /* for now we only do it if there is a 1x1 (solid) source */ - - if((pSrc->pDrawable->width == 1) && (pSrc->pDrawable->height == 1)) { - CARD16 red, green, blue, alpha; - CARD32 pixel = - *((CARD32*)(((PixmapPtr)(pSrc->pDrawable))->devPrivate.ptr)); - - if(!XAAGetRGBAFromPixel(pixel,&red,&green,&blue,&alpha,pSrc->format)) - return FALSE; - - xMask += pMask->pDrawable->x; - yMask += pMask->pDrawable->y; - - /* pull out color expandable operations here */ - if((pMask->format == PICT_a1) && (alpha == 0xffff) && - (op == PictOpOver) && infoRec->WriteBitmap && !pMask->repeat && - !(infoRec->WriteBitmapFlags & NO_TRANSPARENCY) && - (!(infoRec->WriteBitmapFlags & RGB_EQUAL) || - ((red == green) && (green == blue)))) - { - PixmapPtr pPix = (PixmapPtr)(pMask->pDrawable); - int skipleft; - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, yDst, - width, height)) - return TRUE; - - nbox = REGION_NUM_RECTS(®ion); - pbox = REGION_RECTS(®ion); - - if(!nbox) - return TRUE; - - XAAGetPixelFromRGBA(&pixel, red, green, blue, 0, pDst->format); - - xMask -= xDst; - yMask -= yDst; - - while(nbox--) { - skipleft = pbox->x1 + xMask; - - (*infoRec->WriteBitmap)(infoRec->pScrn, - pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, - (unsigned char*)(pPix->devPrivate.ptr) + - (pPix->devKind * (pbox->y1 + yMask)) + - ((skipleft >> 3) & ~3), pPix->devKind, - skipleft & 31, pixel, -1, GXcopy, ~0); - pbox++; - } - - /* WriteBitmap sets the Sync flag */ - REGION_UNINIT(pScreen, ®ion); - return TRUE; - } - - formats = infoRec->CPUToScreenAlphaTextureFormats; - dstformats = infoRec->CPUToScreenAlphaTextureDstFormats; - if(!formats || !dstformats) - return FALSE; - - w = pMask->pDrawable->width; - h = pMask->pDrawable->height; - - if(pMask->repeat) { - if((infoRec->CPUToScreenAlphaTextureFlags & XAA_RENDER_NO_TILE) || - ((infoRec->CPUToScreenAlphaTextureFlags & - XAA_RENDER_POWER_OF_2_TILE_ONLY) && - ((h & (h - 1)) || (w & (w - 1))))) - { - return FALSE; - } - flags |= XAA_RENDER_REPEAT; - } - - if((alpha != 0xffff) && - (infoRec->CPUToScreenAlphaTextureFlags & XAA_RENDER_NO_SRC_ALPHA)) - return FALSE; - - while(*formats != pMask->format) { - if(!(*formats)) return FALSE; - formats++; - } - while(*dstformats != pDst->format) { - if(!(*dstformats)) - return FALSE; - dstformats++; - } - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, yDst, - width, height)) - return TRUE; - - nbox = REGION_NUM_RECTS(®ion); - pbox = REGION_RECTS(®ion); - - if(!nbox) { - REGION_UNINIT(pScreen, ®ion); - return TRUE; - } - - if(!(infoRec->SetupForCPUToScreenAlphaTexture2)(infoRec->pScrn, - op, red, green, blue, alpha, pMask->format, - pDst->format, - ((PixmapPtr)(pMask->pDrawable))->devPrivate.ptr, - ((PixmapPtr)(pMask->pDrawable))->devKind, - w, h, flags)) - { - REGION_UNINIT(pScreen, ®ion); - return FALSE; - } - - xMask -= xDst; - yMask -= yDst; - - while(nbox--) { - (*infoRec->SubsequentCPUToScreenAlphaTexture)(infoRec->pScrn, - pbox->x1, pbox->y1, - pbox->x1 + xMask, pbox->y1 + yMask, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); - pbox++; - } - - SET_SYNC_FLAG(infoRec); - REGION_UNINIT(pScreen, ®ion); - return TRUE; - } - } else { - formats = infoRec->CPUToScreenTextureFormats; - dstformats = infoRec->CPUToScreenTextureDstFormats; - if(!formats || !dstformats) - return FALSE; - - w = pSrc->pDrawable->width; - h = pSrc->pDrawable->height; - - if(pSrc->repeat) { - if((infoRec->CPUToScreenTextureFlags & XAA_RENDER_NO_TILE) || - ((infoRec->CPUToScreenTextureFlags & - XAA_RENDER_POWER_OF_2_TILE_ONLY) && - ((h & (h - 1)) || (w & (w - 1))))) - { - return FALSE; - } - flags |= XAA_RENDER_REPEAT; - } - - while(*formats != pSrc->format) { - if(!(*formats)) return FALSE; - formats++; - } - while(*dstformats != pDst->format) { - if(!(*dstformats)) - return FALSE; - dstformats++; - } - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, yDst, - width, height)) - return TRUE; - - nbox = REGION_NUM_RECTS(®ion); - pbox = REGION_RECTS(®ion); - - if(!nbox) { - REGION_UNINIT(pScreen, ®ion); - return TRUE; - } - - if(!(infoRec->SetupForCPUToScreenTexture2)(infoRec->pScrn, - op, pSrc->format, pDst->format, - ((PixmapPtr)(pSrc->pDrawable))->devPrivate.ptr, - ((PixmapPtr)(pSrc->pDrawable))->devKind, - w, h, flags)) - { - REGION_UNINIT(pScreen, ®ion); - return FALSE; - } - - - xSrc -= xDst; - ySrc -= yDst; - - while(nbox--) { - (*infoRec->SubsequentCPUToScreenTexture)(infoRec->pScrn, - pbox->x1, pbox->y1, - pbox->x1 + xSrc, pbox->y1 + ySrc, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); - pbox++; - } - - SET_SYNC_FLAG(infoRec); - REGION_UNINIT(pScreen, ®ion); - return TRUE; - } - - - return FALSE; -} - -static void -XAACompositeSrcCopy (PicturePtr pSrc, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - int i, nbox; - int xoff, yoff; - BoxPtr pbox; - DDXPointPtr pptSrc; - RegionRec region; - - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - - if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, - xSrc, ySrc, 0, 0, xDst, yDst, - width, height)) - return; - - nbox = REGION_NUM_RECTS(®ion); - pbox = REGION_RECTS(®ion); - - if(!nbox) { - REGION_UNINIT(pScreen, ®ion); - return; - } - pptSrc = xalloc(sizeof(DDXPointRec) * nbox); - if (!pptSrc) { - REGION_UNINIT(pScreen, ®ion); - return; - } - xoff = xSrc - xDst; - yoff = ySrc - yDst; - for (i = 0; i < nbox; i++) { - pptSrc[i].x = pbox[i].x1 + xoff; - pptSrc[i].y = pbox[i].y1 + yoff; - } - - infoRec->ScratchGC.planemask = ~0L; - infoRec->ScratchGC.alu = GXcopy; - - XAADoBitBlt(pSrc->pDrawable, pDst->pDrawable, &infoRec->ScratchGC, ®ion, - pptSrc); - - xfree(pptSrc); - REGION_UNINIT(pScreen, ®ion); - return; -} - -void -XAAComposite (CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - XAA_RENDER_PROLOGUE(pScreen, Composite); - - if(!pMask && infoRec->pScrn->vtSema && - infoRec->ScreenToScreenBitBlt && - pSrc->pDrawable && - DRAWABLE_IS_ON_CARD(pSrc->pDrawable) && - DRAWABLE_IS_ON_CARD(pDst->pDrawable) && - !pSrc->transform && - (!pSrc->repeat || (xSrc >= 0 && ySrc >= 0 && - xSrc+width<=pSrc->pDrawable->width && - ySrc+height<=pSrc->pDrawable->height)) && - ((op == PictOpSrc && - ((pSrc->format==pDst->format) || - (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) || - (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) || - (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap && - pSrc->format==pDst->format && - (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8)))) - { - XAACompositeSrcCopy(pSrc, pDst, xSrc, ySrc, xDst, yDst, width, height); - } else if(!pSrc->pDrawable || (pMask && !pMask->pDrawable) || - !infoRec->Composite || - !(*infoRec->Composite)(op, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, yDst, - width, height)) - { - if(infoRec->pScrn->vtSema && - ((pSrc->pDrawable && - (pSrc->pDrawable->type == DRAWABLE_WINDOW || IS_OFFSCREEN_PIXMAP(pSrc->pDrawable))) || - pDst->pDrawable->type == DRAWABLE_WINDOW || IS_OFFSCREEN_PIXMAP(pDst->pDrawable))) { - SYNC_CHECK(pDst->pDrawable); - } - (*GetPictureScreen(pScreen)->Composite) (op, - pSrc, - pMask, - pDst, - xSrc, - ySrc, - xMask, - yMask, - xDst, - yDst, - width, - height); - } - - if(pDst->pDrawable->type == DRAWABLE_PIXMAP) - (XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pDst->pDrawable)))->flags |= DIRTY; - - XAA_RENDER_EPILOGUE(pScreen, Composite, XAAComposite); -} - -Bool -XAADoGlyphs (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int nlist, - GlyphListPtr list, - GlyphPtr *glyphs) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - - if(!REGION_NUM_RECTS(pDst->pCompositeClip)) - return TRUE; - - if(!infoRec->pScrn->vtSema || - ((pDst->pDrawable->type != DRAWABLE_WINDOW) && - !IS_OFFSCREEN_PIXMAP(pDst->pDrawable))) - return FALSE; - - if((pSrc->pDrawable->type != DRAWABLE_PIXMAP) || - IS_OFFSCREEN_PIXMAP(pSrc->pDrawable)) - return FALSE; - - /* - * If it looks like we have a chance of being able to draw these - * glyphs with an accelerated Composite, do that now to avoid - * unneeded and costly syncs. - */ - if(maskFormat) { - if(!infoRec->CPUToScreenAlphaTextureFormats) - return FALSE; - } else { - if(!infoRec->CPUToScreenTextureFormats) - return FALSE; - } - - miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); - - return TRUE; -} - - -void -XAAGlyphs (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int nlist, - GlyphListPtr list, - GlyphPtr *glyphs) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); - XAA_RENDER_PROLOGUE(pScreen, Glyphs); - - if(!pSrc->pDrawable || !infoRec->Glyphs || - !(*infoRec->Glyphs)(op, pSrc, pDst, maskFormat, - xSrc, ySrc, nlist, list, glyphs)) - { - if(infoRec->pScrn->vtSema && - ((pSrc->pDrawable && - (pSrc->pDrawable->type == DRAWABLE_WINDOW || IS_OFFSCREEN_PIXMAP(pSrc->pDrawable))) || - pDst->pDrawable->type == DRAWABLE_WINDOW || IS_OFFSCREEN_PIXMAP(pDst->pDrawable))) { - SYNC_CHECK(pDst->pDrawable); - } - (*GetPictureScreen(pScreen)->Glyphs) (op, pSrc, pDst, maskFormat, - xSrc, ySrc, nlist, list, glyphs); - } - - if(pDst->pDrawable->type == DRAWABLE_PIXMAP) - (XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pDst->pDrawable)))->flags |= DIRTY; - - XAA_RENDER_EPILOGUE(pScreen, Glyphs, XAAGlyphs); -} +/* + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * + * 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_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <string.h> + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "xf86str.h" +#include "mi.h" +#include "picturestr.h" +#include "glyphstr.h" +#include "picture.h" +#include "mipict.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xaawrap.h" +#include "xaacexp.h" +#include "xf86fbman.h" +#include "servermd.h" + +Bool +XAAGetPixelFromRGBA ( + CARD32 *pixel, + CARD16 red, + CARD16 green, + CARD16 blue, + CARD16 alpha, + CARD32 format +){ + int rbits, bbits, gbits, abits; + int rshift, bshift, gshift, ashift; + + *pixel = 0; + + if(!PICT_FORMAT_COLOR(format)) + return FALSE; + + rbits = PICT_FORMAT_R(format); + gbits = PICT_FORMAT_G(format); + bbits = PICT_FORMAT_B(format); + abits = PICT_FORMAT_A(format); + + if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { + bshift = 0; + gshift = bbits; + rshift = gshift + gbits; + ashift = rshift + rbits; + } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { + rshift = 0; + gshift = rbits; + bshift = gshift + gbits; + ashift = bshift + bbits; + } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { + bshift = PICT_FORMAT_BPP(format) - bbits; + gshift = bshift - gbits; + rshift = gshift - rbits; + ashift = 0; + } else + return FALSE; + + *pixel |= ( blue >> (16 - bbits)) << bshift; + *pixel |= ( red >> (16 - rbits)) << rshift; + *pixel |= (green >> (16 - gbits)) << gshift; + *pixel |= (alpha >> (16 - abits)) << ashift; + + return TRUE; +} + + +Bool +XAAGetRGBAFromPixel( + CARD32 pixel, + CARD16 *red, + CARD16 *green, + CARD16 *blue, + CARD16 *alpha, + CARD32 format +){ + int rbits, bbits, gbits, abits; + int rshift, bshift, gshift, ashift; + + if(!PICT_FORMAT_COLOR(format)) + return FALSE; + + rbits = PICT_FORMAT_R(format); + gbits = PICT_FORMAT_G(format); + bbits = PICT_FORMAT_B(format); + abits = PICT_FORMAT_A(format); + + if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { + bshift = 0; + gshift = bbits; + rshift = gshift + gbits; + ashift = rshift + rbits; + } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { + rshift = 0; + gshift = rbits; + bshift = gshift + gbits; + ashift = bshift + bbits; + } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { + bshift = PICT_FORMAT_BPP(format) - bbits; + gshift = bshift - gbits; + rshift = gshift - rbits; + ashift = 0; + } else + return FALSE; + + *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); + while(rbits < 16) { + *red |= *red >> rbits; + rbits <<= 1; + } + + *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); + while(gbits < 16) { + *green |= *green >> gbits; + gbits <<= 1; + } + + *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); + while(bbits < 16) { + *blue |= *blue >> bbits; + bbits <<= 1; + } + + if(abits) { + *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); + while(abits < 16) { + *alpha |= *alpha >> abits; + abits <<= 1; + } + } else *alpha = 0xffff; + + return TRUE; +} + +/* 8:8:8 + PICT_a8 -> 8:8:8:8 texture */ + +void +XAA_888_plus_PICT_a8_to_8888 ( + CARD32 color, + CARD8 *alphaPtr, /* in bytes */ + int alphaPitch, + CARD32 *dstPtr, + int dstPitch, /* in dwords */ + int width, + int height +){ + int x; + + color &= 0x00ffffff; + + while(height--) { + for(x = 0; x < width; x++) + dstPtr[x] = color | (alphaPtr[x] << 24); + dstPtr += dstPitch; + alphaPtr += alphaPitch; + } +} + +#define DRAWABLE_IS_ON_CARD(pDraw) \ + (pDraw->type == DRAWABLE_WINDOW || \ + (pDraw->type == DRAWABLE_PIXMAP && IS_OFFSCREEN_PIXMAP(pDraw))) + +Bool +XAADoComposite ( + CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height +){ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + RegionRec region; + CARD32 *formats, *dstformats; + int flags = 0; + BoxPtr pbox; + int nbox, w, h; + + if(!REGION_NUM_RECTS(pDst->pCompositeClip)) + return TRUE; + + if(!infoRec->pScrn->vtSema || !DRAWABLE_IS_ON_CARD(pDst->pDrawable)) + return FALSE; + + if(DRAWABLE_IS_ON_CARD(pSrc->pDrawable)) + return FALSE; + + if (pSrc->transform || (pMask && pMask->transform)) + return FALSE; + + if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) + return FALSE; + + if ((pSrc->repeat && pSrc->repeatType != RepeatNormal) || + (pMask && pMask->repeat && pMask->repeatType != RepeatNormal)) + { + return FALSE; + } + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if(pMask) { + if(pMask->componentAlpha) + return FALSE; + + /* for now we only do it if there is a 1x1 (solid) source */ + + if((pSrc->pDrawable->width == 1) && (pSrc->pDrawable->height == 1)) { + CARD16 red, green, blue, alpha; + CARD32 pixel = + *((CARD32*)(((PixmapPtr)(pSrc->pDrawable))->devPrivate.ptr)); + + if(!XAAGetRGBAFromPixel(pixel,&red,&green,&blue,&alpha,pSrc->format)) + return FALSE; + + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + + /* pull out color expandable operations here */ + if((pMask->format == PICT_a1) && (alpha == 0xffff) && + (op == PictOpOver) && infoRec->WriteBitmap && !pMask->repeat && + !(infoRec->WriteBitmapFlags & NO_TRANSPARENCY) && + (!(infoRec->WriteBitmapFlags & RGB_EQUAL) || + ((red == green) && (green == blue)))) + { + PixmapPtr pPix = (PixmapPtr)(pMask->pDrawable); + int skipleft; + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height)) + return TRUE; + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + if(!nbox) + return TRUE; + + XAAGetPixelFromRGBA(&pixel, red, green, blue, 0, pDst->format); + + xMask -= xDst; + yMask -= yDst; + + while(nbox--) { + skipleft = pbox->x1 + xMask; + + (*infoRec->WriteBitmap)(infoRec->pScrn, + pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, + (unsigned char*)(pPix->devPrivate.ptr) + + (pPix->devKind * (pbox->y1 + yMask)) + + ((skipleft >> 3) & ~3), pPix->devKind, + skipleft & 31, pixel, -1, GXcopy, ~0); + pbox++; + } + + /* WriteBitmap sets the Sync flag */ + REGION_UNINIT(pScreen, ®ion); + return TRUE; + } + + formats = infoRec->CPUToScreenAlphaTextureFormats; + dstformats = infoRec->CPUToScreenAlphaTextureDstFormats; + if(!formats || !dstformats) + return FALSE; + + w = pMask->pDrawable->width; + h = pMask->pDrawable->height; + + if(pMask->repeat) { + if((infoRec->CPUToScreenAlphaTextureFlags & XAA_RENDER_NO_TILE) || + ((infoRec->CPUToScreenAlphaTextureFlags & + XAA_RENDER_POWER_OF_2_TILE_ONLY) && + ((h & (h - 1)) || (w & (w - 1))))) + { + return FALSE; + } + flags |= XAA_RENDER_REPEAT; + } + + if((alpha != 0xffff) && + (infoRec->CPUToScreenAlphaTextureFlags & XAA_RENDER_NO_SRC_ALPHA)) + return FALSE; + + while(*formats != pMask->format) { + if(!(*formats)) return FALSE; + formats++; + } + while(*dstformats != pDst->format) { + if(!(*dstformats)) + return FALSE; + dstformats++; + } + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height)) + return TRUE; + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + if(!nbox) { + REGION_UNINIT(pScreen, ®ion); + return TRUE; + } + + if(!(infoRec->SetupForCPUToScreenAlphaTexture2)(infoRec->pScrn, + op, red, green, blue, alpha, pMask->format, + pDst->format, + ((PixmapPtr)(pMask->pDrawable))->devPrivate.ptr, + ((PixmapPtr)(pMask->pDrawable))->devKind, + w, h, flags)) + { + REGION_UNINIT(pScreen, ®ion); + return FALSE; + } + + xMask -= xDst; + yMask -= yDst; + + while(nbox--) { + (*infoRec->SubsequentCPUToScreenAlphaTexture)(infoRec->pScrn, + pbox->x1, pbox->y1, + pbox->x1 + xMask, pbox->y1 + yMask, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + + SET_SYNC_FLAG(infoRec); + REGION_UNINIT(pScreen, ®ion); + return TRUE; + } + } else { + formats = infoRec->CPUToScreenTextureFormats; + dstformats = infoRec->CPUToScreenTextureDstFormats; + if(!formats || !dstformats) + return FALSE; + + w = pSrc->pDrawable->width; + h = pSrc->pDrawable->height; + + if(pSrc->repeat) { + if((infoRec->CPUToScreenTextureFlags & XAA_RENDER_NO_TILE) || + ((infoRec->CPUToScreenTextureFlags & + XAA_RENDER_POWER_OF_2_TILE_ONLY) && + ((h & (h - 1)) || (w & (w - 1))))) + { + return FALSE; + } + flags |= XAA_RENDER_REPEAT; + } + + while(*formats != pSrc->format) { + if(!(*formats)) return FALSE; + formats++; + } + while(*dstformats != pDst->format) { + if(!(*dstformats)) + return FALSE; + dstformats++; + } + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height)) + return TRUE; + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + if(!nbox) { + REGION_UNINIT(pScreen, ®ion); + return TRUE; + } + + if(!(infoRec->SetupForCPUToScreenTexture2)(infoRec->pScrn, + op, pSrc->format, pDst->format, + ((PixmapPtr)(pSrc->pDrawable))->devPrivate.ptr, + ((PixmapPtr)(pSrc->pDrawable))->devKind, + w, h, flags)) + { + REGION_UNINIT(pScreen, ®ion); + return FALSE; + } + + + xSrc -= xDst; + ySrc -= yDst; + + while(nbox--) { + (*infoRec->SubsequentCPUToScreenTexture)(infoRec->pScrn, + pbox->x1, pbox->y1, + pbox->x1 + xSrc, pbox->y1 + ySrc, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + + SET_SYNC_FLAG(infoRec); + REGION_UNINIT(pScreen, ®ion); + return TRUE; + } + + + return FALSE; +} + +static void +XAACompositeSrcCopy (PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + int i, nbox; + int xoff, yoff; + BoxPtr pbox; + DDXPointPtr pptSrc; + RegionRec region; + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + width, height)) + return; + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + if(!nbox) { + REGION_UNINIT(pScreen, ®ion); + return; + } + pptSrc = malloc(sizeof(DDXPointRec) * nbox); + if (!pptSrc) { + REGION_UNINIT(pScreen, ®ion); + return; + } + xoff = xSrc - xDst; + yoff = ySrc - yDst; + for (i = 0; i < nbox; i++) { + pptSrc[i].x = pbox[i].x1 + xoff; + pptSrc[i].y = pbox[i].y1 + yoff; + } + + infoRec->ScratchGC.planemask = ~0L; + infoRec->ScratchGC.alu = GXcopy; + + XAADoBitBlt(pSrc->pDrawable, pDst->pDrawable, &infoRec->ScratchGC, ®ion, + pptSrc); + + free(pptSrc); + REGION_UNINIT(pScreen, ®ion); + return; +} + +void +XAAComposite (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + XAA_RENDER_PROLOGUE(pScreen, Composite); + + if(!pMask && infoRec->pScrn->vtSema && + infoRec->ScreenToScreenBitBlt && + pSrc->pDrawable && + DRAWABLE_IS_ON_CARD(pSrc->pDrawable) && + DRAWABLE_IS_ON_CARD(pDst->pDrawable) && + !pSrc->transform && + (!pSrc->repeat || (xSrc >= 0 && ySrc >= 0 && + xSrc+width<=pSrc->pDrawable->width && + ySrc+height<=pSrc->pDrawable->height)) && + ((op == PictOpSrc && + ((pSrc->format==pDst->format) || + (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) || + (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) || + (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap && + pSrc->format==pDst->format && + (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8)))) + { + XAACompositeSrcCopy(pSrc, pDst, xSrc, ySrc, xDst, yDst, width, height); + } else if(!pSrc->pDrawable || (pMask && !pMask->pDrawable) || + !infoRec->Composite || + !(*infoRec->Composite)(op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height)) + { + if(infoRec->pScrn->vtSema && + ((pSrc->pDrawable && + (pSrc->pDrawable->type == DRAWABLE_WINDOW || IS_OFFSCREEN_PIXMAP(pSrc->pDrawable))) || + pDst->pDrawable->type == DRAWABLE_WINDOW || IS_OFFSCREEN_PIXMAP(pDst->pDrawable))) { + SYNC_CHECK(pDst->pDrawable); + } + (*GetPictureScreen(pScreen)->Composite) (op, + pSrc, + pMask, + pDst, + xSrc, + ySrc, + xMask, + yMask, + xDst, + yDst, + width, + height); + } + + if(pDst->pDrawable->type == DRAWABLE_PIXMAP) + (XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pDst->pDrawable)))->flags |= DIRTY; + + XAA_RENDER_EPILOGUE(pScreen, Composite, XAAComposite); +} + +Bool +XAADoGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + + if(!REGION_NUM_RECTS(pDst->pCompositeClip)) + return TRUE; + + if(!infoRec->pScrn->vtSema || + ((pDst->pDrawable->type != DRAWABLE_WINDOW) && + !IS_OFFSCREEN_PIXMAP(pDst->pDrawable))) + return FALSE; + + if((pSrc->pDrawable->type != DRAWABLE_PIXMAP) || + IS_OFFSCREEN_PIXMAP(pSrc->pDrawable)) + return FALSE; + + /* + * If it looks like we have a chance of being able to draw these + * glyphs with an accelerated Composite, do that now to avoid + * unneeded and costly syncs. + */ + if(maskFormat) { + if(!infoRec->CPUToScreenAlphaTextureFormats) + return FALSE; + } else { + if(!infoRec->CPUToScreenTextureFormats) + return FALSE; + } + + miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); + + return TRUE; +} + + +void +XAAGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCREEN(pScreen); + XAA_RENDER_PROLOGUE(pScreen, Glyphs); + + if(!pSrc->pDrawable || !infoRec->Glyphs || + !(*infoRec->Glyphs)(op, pSrc, pDst, maskFormat, + xSrc, ySrc, nlist, list, glyphs)) + { + if(infoRec->pScrn->vtSema && + ((pSrc->pDrawable && + (pSrc->pDrawable->type == DRAWABLE_WINDOW || IS_OFFSCREEN_PIXMAP(pSrc->pDrawable))) || + pDst->pDrawable->type == DRAWABLE_WINDOW || IS_OFFSCREEN_PIXMAP(pDst->pDrawable))) { + SYNC_CHECK(pDst->pDrawable); + } + (*GetPictureScreen(pScreen)->Glyphs) (op, pSrc, pDst, maskFormat, + xSrc, ySrc, nlist, list, glyphs); + } + + if(pDst->pDrawable->type == DRAWABLE_PIXMAP) + (XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pDst->pDrawable)))->flags |= DIRTY; + + XAA_RENDER_EPILOGUE(pScreen, Glyphs, XAAGlyphs); +} diff --git a/xorg-server/hw/xfree86/xaa/xaaStateChange.c b/xorg-server/hw/xfree86/xaa/xaaStateChange.c index f33261453..9c98a32f2 100644 --- a/xorg-server/hw/xfree86/xaa/xaaStateChange.c +++ b/xorg-server/hw/xfree86/xaa/xaaStateChange.c @@ -1,1626 +1,1626 @@ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "xf86str.h" -#include "mi.h" -#include "miline.h" -#include "xaa.h" -#include "xaalocal.h" -#include "xaawrap.h" -#include "servermd.h" - -#define XAA_STATE_WRAP(func) do {\ -if(infoRec->func) { \ - pStatePriv->func = infoRec->func;\ - infoRec->func = XAAStateWrap##func;\ -}} while(0) - -/* Wrap all XAA functions and allocate our private structure. - */ - -typedef struct _XAAStateWrapRec { - ScrnInfoPtr pScrn; - void (*RestoreAccelState)(ScrnInfoPtr pScrn); - void (*Sync)(ScrnInfoPtr pScrn); - void (*SetupForScreenToScreenCopy)(ScrnInfoPtr pScrn, int xdir, int ydir, - int rop, unsigned int planemask, - int trans_color); - void (*SetupForSolidFill)(ScrnInfoPtr pScrn, int color, int rop, - unsigned int planemask); - void (*SetupForSolidLine)(ScrnInfoPtr pScrn,int color,int rop, - unsigned int planemask); - void (*SetupForDashedLine)(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int length, - unsigned char *pattern); - void (*SetClippingRectangle) (ScrnInfoPtr pScrn, int left, int top, - int right, int bottom); - void (*DisableClipping)(ScrnInfoPtr pScrn); - void (*SetupForMono8x8PatternFill)(ScrnInfoPtr pScrn, int patx, int paty, - int fg, int bg, int rop, - unsigned int planemask); - void (*SetupForColor8x8PatternFill)(ScrnInfoPtr pScrn, int patx, int paty, - int rop, unsigned int planemask, - int transparency_color); - void (*SetupForCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int fg, - int bg, int rop, - unsigned int planemask); - void (*SetupForScanlineCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask); - void (*SetupForScreenToScreenColorExpandFill) (ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask); - void (*SetupForImageWrite)(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int transparency_color, - int bpp, int depth); - void (*SetupForScanlineImageWrite)(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, - int transparency_color, - int bpp, int depth); - void (*SetupForImageRead) (ScrnInfoPtr pScrn, int bpp, int depth); - void (*ScreenToScreenBitBlt)(ScrnInfoPtr pScrn, int nbox, - DDXPointPtr pptSrc, BoxPtr pbox, int xdir, - int ydir, int alu, unsigned int planmask); - void (*WriteBitmap) (ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *src, int srcwidth, int skipleft, - int fg, int bg, int rop, unsigned int planemask); - void (*FillSolidRects)(ScrnInfoPtr pScrn, int fg, int rop, - unsigned int planemask, int nBox, BoxPtr pBox); - void (*FillMono8x8PatternRects)(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int nBox, - BoxPtr pBox, int pat0, int pat1, - int xorg, int yorg); - void (*FillColor8x8PatternRects)(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int nBox, - BoxPtr pBox, int xorg, int yorg, - XAACacheInfoPtr pCache); - void (*FillCacheBltRects)(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int nBox, BoxPtr pBox, - int xorg, int yorg, XAACacheInfoPtr pCache); - void (*FillColorExpandRects)(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int nBox, - BoxPtr pBox, int xorg, int yorg, - PixmapPtr pPix); - void (*FillCacheExpandRects)(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int nBox, BoxPtr pBox, - int xorg, int yorg, PixmapPtr pPix); - void (*FillImageWriteRects)(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int nBox, BoxPtr pBox, - int xorg, int yorg, PixmapPtr pPix); - void (*FillSolidSpans)(ScrnInfoPtr pScrn, int fg, int rop, - unsigned int planemask, int n, DDXPointPtr points, - int *widths, int fSorted); - void (*FillMono8x8PatternSpans)(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int n, - DDXPointPtr points, int *widths, - int fSorted, int pat0, int pat1, - int xorg, int yorg); - void (*FillColor8x8PatternSpans)(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int n, - DDXPointPtr points, int *widths, - int fSorted, XAACacheInfoPtr pCache, - int xorg, int yorg); - void (*FillCacheBltSpans)(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int n, DDXPointPtr points, - int *widths, int fSorted, XAACacheInfoPtr pCache, - int xorg, int yorg); - void (*FillColorExpandSpans)(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int n, - DDXPointPtr points, int *widths, int fSorted, - int xorg, int yorg, PixmapPtr pPix); - void (*FillCacheExpandSpans)(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int n, DDXPointPtr ppt, - int *pwidth, int fSorted, int xorg, int yorg, - PixmapPtr pPix); - void (*TEGlyphRenderer)(ScrnInfoPtr pScrn, int x, int y, int w, int h, - int skipleft, int startline, unsigned int **glyphs, - int glyphWidth, int fg, int bg, int rop, - unsigned planemask); - void (*NonTEGlyphRenderer)(ScrnInfoPtr pScrn, int x, int y, int n, - NonTEGlyphPtr glyphs, BoxPtr pbox, - int fg, int rop, unsigned int planemask); - void (*WritePixmap) (ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *src, int srcwidth, int rop, - unsigned int planemask, int transparency_color, - int bpp, int depth); - void (*ReadPixmap) (ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *dst, int dstwidth, int bpp, int depth); - RegionPtr (*CopyArea)(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, - GC *pGC, int srcx, int srcy, int width, int height, - int dstx, int dsty); - RegionPtr (*CopyPlane)(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, - int srcx, int srcy, int width, int height, int dstx, - int dsty, unsigned long bitPlane); - void (*PushPixelsSolid) (GCPtr pGC, PixmapPtr pBitMap, - DrawablePtr pDrawable, int dx, int dy, int xOrg, - int yOrg); - void (*PolyFillRectSolid)(DrawablePtr pDraw, GCPtr pGC, int nrectFill, - xRectangle *prectInit); - void (*PolyFillRectStippled)(DrawablePtr pDraw, GCPtr pGC, int nrectFill, - xRectangle *prectInit); - void (*PolyFillRectOpaqueStippled)(DrawablePtr pDraw, GCPtr pGC, - int nrectFill, xRectangle *prectInit); - void (*PolyFillRectTiled)(DrawablePtr pDraw, GCPtr pGC, int nrectFill, - xRectangle *prectInit); - void (*FillSpansSolid)(DrawablePtr pDraw, GCPtr pGC, int nInit, - DDXPointPtr ppt, int *pwidth, int fSorted); - void (*FillSpansStippled)(DrawablePtr pDraw, GCPtr pGC, int nInit, - DDXPointPtr ppt, int *pwidth, int fSorted); - void (*FillSpansOpaqueStippled)(DrawablePtr pDraw, GCPtr pGC, int nInit, - DDXPointPtr ppt, int *pwidth, int fSorted); - void (*FillSpansTiled)(DrawablePtr pDraw, GCPtr pGC, int nInit, - DDXPointPtr ppt, int *pwidth, int fSorted); - int (*PolyText8TE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, - char *chars); - int (*PolyText16TE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, - unsigned short *chars); - void (*ImageText8TE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, - char *chars); - void (*ImageText16TE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, unsigned short *chars); - void (*ImageGlyphBltTE) (DrawablePtr pDrawable, GCPtr pGC, int xInit, - int yInit, unsigned int nglyph, CharInfoPtr *ppci, - pointer pglyphBase); - void (*PolyGlyphBltTE) (DrawablePtr pDrawable, GCPtr pGC, int xInit, - int yInit, unsigned int nglyph, CharInfoPtr *ppci, - pointer pglyphBase); - int (*PolyText8NonTE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, char *chars); - int (*PolyText16NonTE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, unsigned short *chars); - void (*ImageText8NonTE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, char *chars); - void (*ImageText16NonTE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, unsigned short *chars); - void (*ImageGlyphBltNonTE) (DrawablePtr pDrawable, GCPtr pGC, int xInit, - int yInit, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase); - void (*PolyGlyphBltNonTE) (DrawablePtr pDrawable, GCPtr pGC, int xInit, - int yInit, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase); - void (*PolyRectangleThinSolid)(DrawablePtr pDrawable,GCPtr pGC, - int nRectsInit, xRectangle *pRectsInit); - void (*PolylinesWideSolid)(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, DDXPointPtr pPts); - void (*PolylinesThinSolid)(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, DDXPointPtr pPts); - void (*PolySegmentThinSolid)(DrawablePtr pDrawable, GCPtr pGC, int nseg, - xSegment *pSeg); - void (*PolylinesThinDashed)(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, DDXPointPtr pPts); - void (*PolySegmentThinDashed)(DrawablePtr pDrawable, GCPtr pGC, int nseg, - xSegment *pSeg); - void (*FillPolygonSolid)(DrawablePtr pDrawable, GCPtr pGC, int shape, - int mode, int count, DDXPointPtr ptsIn); - void (*FillPolygonStippled)(DrawablePtr pDrawable, GCPtr pGC, int shape, - int mode, int count, DDXPointPtr ptsIn); - void (*FillPolygonOpaqueStippled)(DrawablePtr pDrawable, GCPtr pGC, - int shape, int mode, int count, - DDXPointPtr ptsIn); - void (*FillPolygonTiled)(DrawablePtr pDrawable, GCPtr pGC, int shape, - int mode, int count, DDXPointPtr ptsIn); - void (*PolyFillArcSolid)(DrawablePtr pDraw, GCPtr pGC, int narcs, - xArc *parcs); - void (*PutImage)(DrawablePtr pDraw, GCPtr pGC, int depth, int x, int y, - int w, int h, int leftPad, int format, char *pImage); - ValidateGCProcPtr ValidateFillSpans; - ValidateGCProcPtr ValidateSetSpans; - ValidateGCProcPtr ValidatePutImage; - ValidateGCProcPtr ValidateCopyArea; - ValidateGCProcPtr ValidateCopyPlane; - ValidateGCProcPtr ValidatePolyPoint; - ValidateGCProcPtr ValidatePolylines; - ValidateGCProcPtr ValidatePolySegment; - ValidateGCProcPtr ValidatePolyRectangle; - ValidateGCProcPtr ValidatePolyArc; - ValidateGCProcPtr ValidateFillPolygon; - ValidateGCProcPtr ValidatePolyFillRect; - ValidateGCProcPtr ValidatePolyFillArc; - ValidateGCProcPtr ValidatePolyText8; - ValidateGCProcPtr ValidatePolyText16; - ValidateGCProcPtr ValidateImageText8; - ValidateGCProcPtr ValidateImageText16; - ValidateGCProcPtr ValidatePolyGlyphBlt; - ValidateGCProcPtr ValidateImageGlyphBlt; - ValidateGCProcPtr ValidatePushPixels; - void (*ComputeDash)(GCPtr pGC); - void (*InitPixmapCache)(ScreenPtr pScreen, RegionPtr areas, pointer data); - void (*ClosePixmapCache)(ScreenPtr pScreen); - int (*StippledFillChooser)(GCPtr pGC); - int (*OpaqueStippledFillChooser)(GCPtr pGC); - int (*TiledFillChooser)(GCPtr pGC); - XAACacheInfoPtr (*CacheTile)(ScrnInfoPtr Scrn, PixmapPtr pPix); - XAACacheInfoPtr (*CacheStipple)(ScrnInfoPtr Scrn, PixmapPtr pPix, int fg, - int bg); - XAACacheInfoPtr (*CacheMonoStipple)(ScrnInfoPtr Scrn, PixmapPtr pPix); - XAACacheInfoPtr (*CacheMono8x8Pattern)(ScrnInfoPtr Scrn, int pat0, - int pat1); - XAACacheInfoPtr (*CacheColor8x8Pattern)(ScrnInfoPtr Scrn, PixmapPtr pPix, - int fg, int bg); - void (*WriteBitmapToCache) (ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *src, int srcwidth, int fg, - int bg); - void (*WritePixmapToCache) (ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *src, int srcwidth, int bpp, - int depth); - void (*WriteMono8x8PatternToCache)(ScrnInfoPtr pScrn, - XAACacheInfoPtr pCache); - void (*WriteColor8x8PatternToCache)(ScrnInfoPtr pScrn, PixmapPtr pPix, - XAACacheInfoPtr pCache); - GetImageProcPtr GetImage; - GetSpansProcPtr GetSpans; - CopyWindowProcPtr CopyWindow; - Bool (*SetupForCPUToScreenAlphaTexture2)(ScrnInfoPtr pScrn, int op, - CARD16 red, CARD16 green, - CARD16 blue, CARD16 alpha, - CARD32 maskFormat, CARD32 dstFormat, - CARD8 *alphaPtr, int alphaPitch, - int width, int height, int flags); - Bool (*SetupForCPUToScreenTexture2)(ScrnInfoPtr pScrn, int op, - CARD32 srcFormat, CARD32 dstFormat, - CARD8 *texPtr, int texPitch, - int width, int height, int flags); -} XAAStateWrapRec, *XAAStateWrapPtr; - -static int XAAStateKeyIndex; -static DevPrivateKey XAAStateKey = &XAAStateKeyIndex; - -/* Wrap functions start here */ -#define GET_STATEPRIV_GC(pGC) XAAStateWrapPtr pStatePriv =\ -(XAAStateWrapPtr)dixLookupPrivate(&(pGC)->pScreen->devPrivates, XAAStateKey) - -#define GET_STATEPRIV_SCREEN(pScreen) XAAStateWrapPtr pStatePriv =\ -(XAAStateWrapPtr)dixLookupPrivate(&(pScreen)->devPrivates, XAAStateKey) - -#define GET_STATEPRIV_PSCRN(pScrn) XAAStateWrapPtr pStatePriv =\ -(XAAStateWrapPtr)dixLookupPrivate(&(pScrn)->pScreen->devPrivates, XAAStateKey) - -#define STATE_CHECK_SP(pStatePriv) {\ - ScrnInfoPtr pScrn = pStatePriv->pScrn;\ - int i = 0;\ - int need_change = 0;\ - while(i < pScrn->numEntities) {\ - if(xf86IsEntityShared(pScrn->entityList[i]) &&\ - xf86GetLastScrnFlag(pScrn->entityList[i]) != pScrn->scrnIndex) {\ - need_change = 1;\ - xf86SetLastScrnFlag(pScrn->entityList[i],\ - pScrn->scrnIndex);\ - }\ - i++;\ - }\ - if(need_change == 1) (*pStatePriv->RestoreAccelState)(pScrn);\ -} - -#define STATE_CHECK_PSCRN(pScrn) {\ - int i = 0;\ - int need_change = 0;\ - while(i < pScrn->numEntities) {\ - if(xf86IsEntityShared(pScrn->entityList[i]) &&\ - xf86GetLastScrnFlag(pScrn->entityList[i]) != pScrn->scrnIndex) {\ - need_change = 1;\ - xf86SetLastScrnFlag(pScrn->entityList[i],\ - pScrn->scrnIndex);\ - }\ - i++;\ - }\ - if(need_change == 1) (*pStatePriv->RestoreAccelState)(pScrn);\ -} - -static void XAAStateWrapSync(ScrnInfoPtr pScrn) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->Sync)(pScrn); -} - -static void XAAStateWrapSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, - int rop, unsigned int planemask, - int trans_color) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForScreenToScreenCopy)(pScrn, xdir, ydir, rop, planemask, - trans_color); -} - -static void XAAStateWrapSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, - unsigned int planemask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForSolidFill)(pScrn, color, rop, planemask); -} - -static void XAAStateWrapSetupForSolidLine(ScrnInfoPtr pScrn,int color,int rop, - unsigned int planemask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForSolidLine)(pScrn, color, rop, planemask); -} - -static void XAAStateWrapSetupForDashedLine(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int length, - unsigned char *pattern) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForDashedLine)(pScrn, fg, bg, rop, planemask, length, pattern); -} - -static void XAAStateWrapSetClippingRectangle(ScrnInfoPtr pScrn, int left, int top, - int right, int bottom) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetClippingRectangle)(pScrn, left, top, right, bottom); -} - -static void XAAStateWrapDisableClipping(ScrnInfoPtr pScrn) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->DisableClipping)(pScrn); -} - -static void XAAStateWrapSetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int patx, int paty, - int fg, int bg, int rop, - unsigned int planemask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForMono8x8PatternFill)(pScrn, patx, paty, fg, bg, rop, planemask); -} - -static void XAAStateWrapSetupForColor8x8PatternFill(ScrnInfoPtr pScrn, int patx, int paty, - int rop, unsigned int planemask, - int transparency_color) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForColor8x8PatternFill)(pScrn, patx, paty, rop, planemask, - transparency_color); -} - -static void XAAStateWrapSetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int fg, - int bg, int rop, - unsigned int planemask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForCPUToScreenColorExpandFill)(pScrn, fg, bg, rop, planemask); -} - -static void XAAStateWrapSetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, - int fg, int bg, - int rop, - unsigned int planemask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForScanlineCPUToScreenColorExpandFill)(pScrn, fg, bg, rop, - planemask); -} - -static void XAAStateWrapSetupForScreenToScreenColorExpandFill(ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForScreenToScreenColorExpandFill)(pScrn, fg, bg, rop, planemask); -} - -static void XAAStateWrapSetupForImageWrite(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int transparency_color, - int bpp, int depth) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForImageWrite)(pScrn, rop, planemask, transparency_color, bpp, - depth); -} - -static void XAAStateWrapSetupForScanlineImageWrite(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, - int transparency_color, - int bpp, int depth) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForScanlineImageWrite)(pScrn, rop, planemask, transparency_color, - bpp, depth); -} - -static void XAAStateWrapSetupForImageRead(ScrnInfoPtr pScrn, int bpp, int depth) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->SetupForImageRead)(pScrn, bpp, depth); -} - -static void XAAStateWrapScreenToScreenBitBlt(ScrnInfoPtr pScrn, int nbox, - DDXPointPtr pptSrc, BoxPtr pbox, int xdir, - int ydir, int alu, unsigned int planmask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->ScreenToScreenBitBlt)(pScrn, nbox, - pptSrc, pbox, xdir, - ydir, alu, planmask); -} - -static void XAAStateWrapWriteBitmap(ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *src, int srcwidth, int skipleft, - int fg, int bg, int rop, unsigned int planemask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->WriteBitmap)(pScrn, x, y, w, h, - src, srcwidth, skipleft, - fg, bg, rop, planemask); -} - -static void XAAStateWrapFillSolidRects(ScrnInfoPtr pScrn, int fg, int rop, - unsigned int planemask, int nBox, BoxPtr pBox) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillSolidRects)(pScrn, fg, rop, - planemask, nBox, pBox); -} - -static void XAAStateWrapFillMono8x8PatternRects(ScrnInfoPtr pScrn, int fg, int bg, - int rop, unsigned int planemask, int nBox, - BoxPtr pBox, int pat0, int pat1, - int xorg, int yorg) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillMono8x8PatternRects)(pScrn, fg, bg, - rop, planemask, nBox, - pBox, pat0, pat1, - xorg, yorg); -} - -static void XAAStateWrapFillColor8x8PatternRects(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int nBox, - BoxPtr pBox, int xorg, int yorg, - XAACacheInfoPtr pCache) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillColor8x8PatternRects)(pScrn, rop, - planemask, nBox, - pBox, xorg, yorg, - pCache); -} - -static void XAAStateWrapFillCacheBltRects(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int nBox, BoxPtr pBox, - int xorg, int yorg, XAACacheInfoPtr pCache) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillCacheBltRects)(pScrn, rop, - planemask, nBox, pBox, - xorg, yorg, pCache); -} - -static void XAAStateWrapFillColorExpandRects(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int nBox, - BoxPtr pBox, int xorg, int yorg, - PixmapPtr pPix) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillColorExpandRects)(pScrn, fg, bg, rop, - planemask, nBox, - pBox, xorg, yorg, - pPix); -} - -static void XAAStateWrapFillCacheExpandRects(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int nBox, - BoxPtr pBox, int xorg, int yorg, - PixmapPtr pPix) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillCacheExpandRects)(pScrn, fg, bg, rop, - planemask, nBox, - pBox, xorg, yorg, - pPix); -} - -static void XAAStateWrapFillImageWriteRects(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int nBox, BoxPtr pBox, - int xorg, int yorg, PixmapPtr pPix) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillImageWriteRects)(pScrn, rop, - planemask, nBox, pBox, - xorg, yorg, pPix); -} - -static void XAAStateWrapFillSolidSpans(ScrnInfoPtr pScrn, int fg, int rop, - unsigned int planemask, int n, DDXPointPtr points, - int *widths, int fSorted) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillSolidSpans)(pScrn, fg, rop, - planemask, n, points, - widths, fSorted); -} - -static void XAAStateWrapFillMono8x8PatternSpans(ScrnInfoPtr pScrn, int fg, int bg, - int rop, unsigned int planemask, int n, - DDXPointPtr points, int *widths, - int fSorted, int pat0, int pat1, - int xorg, int yorg) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillMono8x8PatternSpans)(pScrn, fg, bg, - rop, planemask, n, - points, widths, - fSorted, pat0, pat1, - xorg, yorg); -} - -static void XAAStateWrapFillColor8x8PatternSpans(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int n, - DDXPointPtr points, int *widths, - int fSorted, XAACacheInfoPtr pCache, - int xorg, int yorg) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillColor8x8PatternSpans)(pScrn, rop, - planemask, n, - points, widths, - fSorted, pCache, - xorg, yorg); -} - -static void XAAStateWrapFillCacheBltSpans(ScrnInfoPtr pScrn, int rop, - unsigned int planemask, int n, - DDXPointPtr points, int *widths, - int fSorted, XAACacheInfoPtr pCache, - int xorg, int yorg) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillCacheBltSpans)(pScrn, rop, - planemask, n, - points, widths, - fSorted, pCache, - xorg, yorg); -} - -static void XAAStateWrapFillColorExpandSpans(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int n, - DDXPointPtr points, int *widths, int fSorted, - int xorg, int yorg, PixmapPtr pPix) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillColorExpandSpans)(pScrn, fg, bg, rop, - planemask, n, - points, widths, fSorted, - xorg, yorg, pPix); -} - -static void XAAStateWrapFillCacheExpandSpans(ScrnInfoPtr pScrn, int fg, int bg, int rop, - unsigned int planemask, int n, - DDXPointPtr ppt, int *pwidth, int fSorted, - int xorg, int yorg, PixmapPtr pPix) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->FillCacheExpandSpans)(pScrn, fg, bg, rop, - planemask, n, - ppt, pwidth, fSorted, - xorg, yorg, pPix); -} - -static void XAAStateWrapTEGlyphRenderer(ScrnInfoPtr pScrn, int x, int y, int w, int h, - int skipleft, int startline, - unsigned int **glyphs, - int glyphWidth, int fg, int bg, int rop, - unsigned planemask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->TEGlyphRenderer)(pScrn, x, y, w, h, - skipleft, startline, - glyphs, - glyphWidth, fg, bg, rop, - planemask); -} - -static void XAAStateWrapNonTEGlyphRenderer(ScrnInfoPtr pScrn, int x, int y, int n, - NonTEGlyphPtr glyphs, BoxPtr pbox, - int fg, int rop, unsigned int planemask) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->NonTEGlyphRenderer)(pScrn, x, y, n, - glyphs, pbox, - fg, rop, planemask); -} - -static void XAAStateWrapWritePixmap(ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *src, int srcwidth, int rop, - unsigned int planemask, int transparency_color, - int bpp, int depth) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->WritePixmap)(pScrn, x, y, w, h, - src, srcwidth, rop, - planemask, transparency_color, - bpp, depth); -} - -static void XAAStateWrapReadPixmap(ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *dst, int dstwidth, int bpp, int depth) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->ReadPixmap)(pScrn, x, y, w, h, - dst, dstwidth, bpp, depth); -} - -static RegionPtr XAAStateWrapCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, - GC *pGC, int srcx, int srcy, int width, int height, - int dstx, int dsty) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - return (*pStatePriv->CopyArea)(pSrcDrawable, pDstDrawable, - pGC, srcx, srcy, width, height, - dstx, dsty); -} - -static RegionPtr XAAStateWrapCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, - int srcx, int srcy, int width, int height, - int dstx, int dsty, unsigned long bitPlane) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - return (*pStatePriv->CopyPlane)(pSrc, pDst, pGC, - srcx, srcy, width, height, - dstx, dsty, bitPlane); -} - -static void XAAStateWrapPushPixelsSolid(GCPtr pGC, PixmapPtr pBitMap, - DrawablePtr pDrawable, int dx, int dy, int xOrg, - int yOrg) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PushPixelsSolid)(pGC, pBitMap, - pDrawable, dx, dy, xOrg, - yOrg); -} - -static void XAAStateWrapPolyFillRectSolid(DrawablePtr pDraw, GCPtr pGC, int nrectFill, - xRectangle *prectInit) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolyFillRectSolid)(pDraw, pGC, nrectFill, - prectInit); -} - -static void XAAStateWrapPolyFillRectStippled(DrawablePtr pDraw, GCPtr pGC, int nrectFill, - xRectangle *prectInit) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolyFillRectStippled)(pDraw, pGC, nrectFill, - prectInit); -} - -static void XAAStateWrapPolyFillRectOpaqueStippled(DrawablePtr pDraw, GCPtr pGC, - int nrectFill, xRectangle *prectInit) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolyFillRectOpaqueStippled)(pDraw, pGC, - nrectFill, prectInit); -} - -static void XAAStateWrapPolyFillRectTiled(DrawablePtr pDraw, GCPtr pGC, int nrectFill, - xRectangle *prectInit) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolyFillRectTiled)(pDraw, pGC, nrectFill, - prectInit); -} - -static void XAAStateWrapFillSpansSolid(DrawablePtr pDraw, GCPtr pGC, int nInit, - DDXPointPtr ppt, int *pwidth, int fSorted) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->FillSpansSolid)(pDraw, pGC, nInit, - ppt, pwidth, fSorted); -} - -static void XAAStateWrapFillSpansStippled(DrawablePtr pDraw, GCPtr pGC, int nInit, - DDXPointPtr ppt, int *pwidth, int fSorted) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->FillSpansStippled)(pDraw, pGC, nInit, - ppt, pwidth, fSorted); -} - -static void XAAStateWrapFillSpansOpaqueStippled(DrawablePtr pDraw, GCPtr pGC, int nInit, - DDXPointPtr ppt, int *pwidth, int fSorted) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->FillSpansOpaqueStippled)(pDraw, pGC, nInit, - ppt, pwidth, fSorted); -} - -static void XAAStateWrapFillSpansTiled(DrawablePtr pDraw, GCPtr pGC, int nInit, - DDXPointPtr ppt, int *pwidth, int fSorted) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->FillSpansTiled)(pDraw, pGC, nInit, - ppt, pwidth, fSorted); -} - -static int XAAStateWrapPolyText8TE(DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, - char *chars) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - return (*pStatePriv->PolyText8TE)(pDraw, pGC, x, y, count, - chars); -} - -static int XAAStateWrapPolyText16TE(DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, - unsigned short *chars) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - return (*pStatePriv->PolyText16TE)(pDraw, pGC, x, y, count, - chars); -} - -static void XAAStateWrapImageText8TE(DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, char *chars) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ImageText8TE)(pDraw, pGC, x, y, - count, chars); -} - -static void XAAStateWrapImageText16TE(DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, unsigned short *chars) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ImageText16TE)(pDraw, pGC, x, y, - count, chars); -} - -static void XAAStateWrapImageGlyphBltTE(DrawablePtr pDrawable, GCPtr pGC, int xInit, - int yInit, unsigned int nglyph, CharInfoPtr *ppci, - pointer pglyphBase) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ImageGlyphBltTE)(pDrawable, pGC, xInit, - yInit, nglyph, ppci, - pglyphBase); -} - -static void XAAStateWrapPolyGlyphBltTE(DrawablePtr pDrawable, GCPtr pGC, int xInit, - int yInit, unsigned int nglyph, CharInfoPtr *ppci, - pointer pglyphBase) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolyGlyphBltTE)(pDrawable, pGC, xInit, - yInit, nglyph, ppci, - pglyphBase); -} - -static int XAAStateWrapPolyText8NonTE(DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, char *chars) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - return (*pStatePriv->PolyText8NonTE)(pDraw, pGC, x, y, - count, chars); -} - -static int XAAStateWrapPolyText16NonTE(DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, unsigned short *chars) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - return (*pStatePriv->PolyText16NonTE)(pDraw, pGC, x, y, - count, chars); -} - -static void XAAStateWrapImageText8NonTE(DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, char *chars) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ImageText8NonTE)(pDraw, pGC, x, y, - count, chars); -} - -static void XAAStateWrapImageText16NonTE(DrawablePtr pDraw, GCPtr pGC, int x, int y, - int count, unsigned short *chars) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ImageText16NonTE)(pDraw, pGC, x, y, - count, chars); -} - -static void XAAStateWrapImageGlyphBltNonTE(DrawablePtr pDrawable, GCPtr pGC, int xInit, - int yInit, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ImageGlyphBltNonTE)(pDrawable, pGC, xInit, - yInit, nglyph, - ppci, pglyphBase); -} - -static void XAAStateWrapPolyGlyphBltNonTE(DrawablePtr pDrawable, GCPtr pGC, int xInit, - int yInit, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolyGlyphBltNonTE)(pDrawable, pGC, xInit, - yInit, nglyph, - ppci, pglyphBase); -} - -static void XAAStateWrapPolyRectangleThinSolid(DrawablePtr pDrawable,GCPtr pGC, - int nRectsInit, xRectangle *pRectsInit) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolyRectangleThinSolid)(pDrawable, pGC, - nRectsInit, pRectsInit); -} - -static void XAAStateWrapPolylinesWideSolid(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, DDXPointPtr pPts) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolylinesWideSolid)(pDrawable, pGC, mode, - npt, pPts); -} - -static void XAAStateWrapPolylinesThinSolid(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, DDXPointPtr pPts) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolylinesThinSolid)(pDrawable, pGC, mode, - npt, pPts); -} - -static void XAAStateWrapPolySegmentThinSolid(DrawablePtr pDrawable, GCPtr pGC, int nseg, - xSegment *pSeg) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolySegmentThinSolid)(pDrawable, pGC, nseg, - pSeg); -} - -static void XAAStateWrapPolylinesThinDashed(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, DDXPointPtr pPts) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolylinesThinDashed)(pDrawable, pGC, mode, - npt, pPts); -} - -static void XAAStateWrapPolySegmentThinDashed(DrawablePtr pDrawable, GCPtr pGC, int nseg, - xSegment *pSeg) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolySegmentThinDashed)(pDrawable, pGC, nseg, - pSeg); -} - -static void XAAStateWrapFillPolygonSolid(DrawablePtr pDrawable, GCPtr pGC, int shape, - int mode, int count, DDXPointPtr ptsIn) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->FillPolygonSolid)(pDrawable, pGC, shape, - mode, count, ptsIn); -} - -static void XAAStateWrapFillPolygonStippled(DrawablePtr pDrawable, GCPtr pGC, int shape, - int mode, int count, DDXPointPtr ptsIn) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->FillPolygonStippled)(pDrawable, pGC, shape, - mode, count, ptsIn); -} - -static void XAAStateWrapFillPolygonOpaqueStippled(DrawablePtr pDrawable, GCPtr pGC, - int shape, int mode, int count, - DDXPointPtr ptsIn) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->FillPolygonOpaqueStippled)(pDrawable, pGC, - shape, mode, count, - ptsIn); -} - -static void XAAStateWrapFillPolygonTiled(DrawablePtr pDrawable, GCPtr pGC, int shape, - int mode, int count, DDXPointPtr ptsIn) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->FillPolygonTiled)(pDrawable, pGC, shape, - mode, count, ptsIn); -} - -static void XAAStateWrapPolyFillArcSolid(DrawablePtr pDraw, GCPtr pGC, int narcs, - xArc *parcs) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PolyFillArcSolid)(pDraw, pGC, narcs, - parcs); -} - -static void XAAStateWrapPutImage(DrawablePtr pDraw, GCPtr pGC, int depth, int x, int y, - int w, int h, int leftPad, int format, char *pImage) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->PutImage)(pDraw, pGC, depth, x, y, - w, h, leftPad, format, pImage); -} - -static void XAAStateWrapValidateFillSpans(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidateFillSpans)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidateSetSpans(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidateSetSpans)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePutImage(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePutImage)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidateCopyArea(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidateCopyArea)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidateCopyPlane(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidateCopyPlane)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolyPoint(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolyPoint)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolylines(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolylines)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolySegment(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolySegment)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolyRectangle(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolyRectangle)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolyArc(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolyArc)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidateFillPolygon(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidateFillPolygon)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolyFillRect(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolyFillRect)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolyFillArc(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolyFillArc)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolyText8(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolyText8)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolyText16(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolyText16)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidateImageText8(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidateImageText8)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidateImageText16(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidateImageText16)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePolyGlyphBlt(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePolyGlyphBlt)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidateImageGlyphBlt(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - (*pStatePriv->ValidateImageGlyphBlt)(pGC, changes, - pDraw); -} - -static void XAAStateWrapValidatePushPixels(GCPtr pGC, unsigned long changes, - DrawablePtr pDraw) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ValidatePushPixels)(pGC, changes, - pDraw); -} - -static void XAAStateWrapComputeDash(GCPtr pGC) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ComputeDash)(pGC); -} - -static void XAAStateWrapInitPixmapCache(ScreenPtr pScreen, RegionPtr areas, - pointer data) -{ - GET_STATEPRIV_SCREEN(pScreen); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->InitPixmapCache)(pScreen, areas, - data); -} - -static void XAAStateWrapClosePixmapCache(ScreenPtr pScreen) -{ - GET_STATEPRIV_SCREEN(pScreen); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->ClosePixmapCache)(pScreen); -} - -static int XAAStateWrapStippledFillChooser(GCPtr pGC) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - return (*pStatePriv->StippledFillChooser)(pGC); -} - -static int XAAStateWrapOpaqueStippledFillChooser(GCPtr pGC) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - return (*pStatePriv->OpaqueStippledFillChooser)(pGC); -} - -static int XAAStateWrapTiledFillChooser(GCPtr pGC) -{ - GET_STATEPRIV_GC(pGC); - STATE_CHECK_SP(pStatePriv); - - return (*pStatePriv->TiledFillChooser)(pGC); -} - -static XAACacheInfoPtr XAAStateWrapCacheTile(ScrnInfoPtr pScrn, PixmapPtr pPix) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - return (*pStatePriv->CacheTile)(pScrn, pPix); -} - -static XAACacheInfoPtr XAAStateWrapCacheStipple(ScrnInfoPtr pScrn, PixmapPtr pPix, int fg, - int bg) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - return (*pStatePriv->CacheStipple)(pScrn, pPix, fg, - bg); -} - -static XAACacheInfoPtr XAAStateWrapCacheMonoStipple(ScrnInfoPtr pScrn, PixmapPtr pPix) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - return (*pStatePriv->CacheMonoStipple)(pScrn, pPix); -} - -static XAACacheInfoPtr XAAStateWrapCacheMono8x8Pattern(ScrnInfoPtr pScrn, int pat0, - int pat1) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - return (*pStatePriv->CacheMono8x8Pattern)(pScrn, pat0, - pat1); -} - -static XAACacheInfoPtr XAAStateWrapCacheColor8x8Pattern(ScrnInfoPtr pScrn, PixmapPtr pPix, - int fg, int bg) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - return (*pStatePriv->CacheColor8x8Pattern)(pScrn, pPix, - fg, bg); -} - -static void XAAStateWrapWriteBitmapToCache(ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *src, int srcwidth, int fg, - int bg) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->WriteBitmapToCache)(pScrn, x, y, w, h, - src, srcwidth, fg, - bg); -} - -static void XAAStateWrapWritePixmapToCache(ScrnInfoPtr pScrn, int x, int y, int w, int h, - unsigned char *src, int srcwidth, int bpp, - int depth) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->WritePixmapToCache)(pScrn, x, y, w, h, - src, srcwidth, bpp, - depth); -} - -static void XAAStateWrapWriteMono8x8PatternToCache(ScrnInfoPtr pScrn, - XAACacheInfoPtr pCache) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->WriteMono8x8PatternToCache)(pScrn, - pCache); -} - -static void XAAStateWrapWriteColor8x8PatternToCache(ScrnInfoPtr pScrn, PixmapPtr pPix, - XAACacheInfoPtr pCache) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - (*pStatePriv->WriteColor8x8PatternToCache)(pScrn, pPix, - pCache); -} - -static void XAAStateWrapGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, - unsigned int format,unsigned long planeMask, - char *pdstLine) -{ - GET_STATEPRIV_SCREEN(pDrawable->pScreen); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->GetImage)(pDrawable, sx, sy, w, h, - format, planeMask, - pdstLine); -} - -static void XAAStateWrapGetSpans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, - int *pwidth, int nspans, char *pdstStart) -{ - GET_STATEPRIV_SCREEN(pDrawable->pScreen); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->GetSpans)(pDrawable, wMax, ppt, - pwidth, nspans, pdstStart); -} - -static void XAAStateWrapCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, - RegionPtr prgnSrc) -{ - GET_STATEPRIV_SCREEN(pWindow->drawable.pScreen); - STATE_CHECK_SP(pStatePriv); - - (*pStatePriv->CopyWindow)(pWindow, ptOldOrg, - prgnSrc); -} - -static Bool XAAStateWrapSetupForCPUToScreenAlphaTexture2(ScrnInfoPtr pScrn, - int op, CARD16 red, - CARD16 green, - CARD16 blue, - CARD16 alpha, - CARD32 srcFormat, - CARD32 dstFormat, - CARD8 *alphaPtr, - int alphaPitch, - int width, int height, - int flags) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - return (*pStatePriv->SetupForCPUToScreenAlphaTexture2)(pScrn, op, red, green, - blue, alpha, srcFormat, - dstFormat, alphaPtr, - alphaPitch, width, - height, flags); -} - -static Bool XAAStateWrapSetupForCPUToScreenTexture2(ScrnInfoPtr pScrn, int op, - CARD32 srcFormat, - CARD32 dstFormat, - CARD8 *texPtr, int texPitch, - int width, int height, - int flags) -{ - GET_STATEPRIV_PSCRN(pScrn); - STATE_CHECK_PSCRN(pScrn); - - return (*pStatePriv->SetupForCPUToScreenTexture2)(pScrn, op, srcFormat, - dstFormat, texPtr, texPitch, - width, height, flags); -} - -/* Setup Function */ -Bool -XAAInitStateWrap(ScreenPtr pScreen, XAAInfoRecPtr infoRec) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - XAAStateWrapPtr pStatePriv; - int i = 0; - - if(!(pStatePriv = xalloc(sizeof(XAAStateWrapRec)))) return FALSE; - dixSetPrivate(&pScreen->devPrivates, XAAStateKey, pStatePriv); - pStatePriv->RestoreAccelState = infoRec->RestoreAccelState; - pStatePriv->pScrn = pScrn; - - /* Initialize the last screen to -1 so whenever an accel function - * is called the proper state is setup - */ - while(i < pScrn->numEntities) { - xf86SetLastScrnFlag(pScrn->entityList[i], -1); - i++; - } -/* Do the wrapping */ - XAA_STATE_WRAP(Sync); - XAA_STATE_WRAP(SetupForScreenToScreenCopy); - XAA_STATE_WRAP(SetupForSolidFill); - XAA_STATE_WRAP(SetupForSolidLine); - XAA_STATE_WRAP(SetupForDashedLine); - XAA_STATE_WRAP(SetClippingRectangle); - XAA_STATE_WRAP(DisableClipping); - XAA_STATE_WRAP(SetupForMono8x8PatternFill); - XAA_STATE_WRAP(SetupForColor8x8PatternFill); - XAA_STATE_WRAP(SetupForCPUToScreenColorExpandFill); - XAA_STATE_WRAP(SetupForScanlineCPUToScreenColorExpandFill); - XAA_STATE_WRAP(SetupForScreenToScreenColorExpandFill); - XAA_STATE_WRAP(SetupForImageWrite); - XAA_STATE_WRAP(SetupForScanlineImageWrite); - XAA_STATE_WRAP(SetupForImageRead); - XAA_STATE_WRAP(ScreenToScreenBitBlt); - XAA_STATE_WRAP(WriteBitmap); - XAA_STATE_WRAP(FillSolidRects); - XAA_STATE_WRAP(FillMono8x8PatternRects); - XAA_STATE_WRAP(FillColor8x8PatternRects); - XAA_STATE_WRAP(FillCacheBltRects); - XAA_STATE_WRAP(FillColorExpandRects); - XAA_STATE_WRAP(FillCacheExpandRects); - XAA_STATE_WRAP(FillImageWriteRects); - XAA_STATE_WRAP(FillSolidSpans); - XAA_STATE_WRAP(FillMono8x8PatternSpans); - XAA_STATE_WRAP(FillColor8x8PatternSpans); - XAA_STATE_WRAP(FillCacheBltSpans); - XAA_STATE_WRAP(FillColorExpandSpans); - XAA_STATE_WRAP(FillCacheExpandSpans); - XAA_STATE_WRAP(TEGlyphRenderer); - XAA_STATE_WRAP(NonTEGlyphRenderer); - XAA_STATE_WRAP(WritePixmap); - XAA_STATE_WRAP(ReadPixmap); - XAA_STATE_WRAP(CopyArea); - XAA_STATE_WRAP(CopyPlane); - XAA_STATE_WRAP(PushPixelsSolid); - XAA_STATE_WRAP(PolyFillRectSolid); - XAA_STATE_WRAP(PolyFillRectStippled); - XAA_STATE_WRAP(PolyFillRectOpaqueStippled); - XAA_STATE_WRAP(PolyFillRectTiled); - XAA_STATE_WRAP(FillSpansSolid); - XAA_STATE_WRAP(FillSpansStippled); - XAA_STATE_WRAP(FillSpansOpaqueStippled); - XAA_STATE_WRAP(FillSpansTiled); - XAA_STATE_WRAP(PolyText8TE); - XAA_STATE_WRAP(PolyText16TE); - XAA_STATE_WRAP(ImageText8TE); - XAA_STATE_WRAP(ImageText16TE); - XAA_STATE_WRAP(ImageGlyphBltTE); - XAA_STATE_WRAP(PolyGlyphBltTE); - XAA_STATE_WRAP(PolyText8NonTE); - XAA_STATE_WRAP(PolyText16NonTE); - XAA_STATE_WRAP(ImageText8NonTE); - XAA_STATE_WRAP(ImageText16NonTE); - XAA_STATE_WRAP(ImageGlyphBltNonTE); - XAA_STATE_WRAP(PolyGlyphBltNonTE); - XAA_STATE_WRAP(PolyRectangleThinSolid); - XAA_STATE_WRAP(PolylinesWideSolid); - XAA_STATE_WRAP(PolylinesThinSolid); - XAA_STATE_WRAP(PolySegmentThinSolid); - XAA_STATE_WRAP(PolylinesThinDashed); - XAA_STATE_WRAP(PolySegmentThinDashed); - XAA_STATE_WRAP(FillPolygonSolid); - XAA_STATE_WRAP(FillPolygonStippled); - XAA_STATE_WRAP(FillPolygonOpaqueStippled); - XAA_STATE_WRAP(FillPolygonTiled); - XAA_STATE_WRAP(PolyFillArcSolid); - XAA_STATE_WRAP(PutImage); - XAA_STATE_WRAP(ValidateFillSpans); - XAA_STATE_WRAP(ValidateSetSpans); - XAA_STATE_WRAP(ValidatePutImage); - XAA_STATE_WRAP(ValidateCopyArea); - XAA_STATE_WRAP(ValidateCopyPlane); - XAA_STATE_WRAP(ValidatePolyPoint); - XAA_STATE_WRAP(ValidatePolylines); - XAA_STATE_WRAP(ValidatePolySegment); - XAA_STATE_WRAP(ValidatePolyRectangle); - XAA_STATE_WRAP(ValidatePolyArc); - XAA_STATE_WRAP(ValidateFillPolygon); - XAA_STATE_WRAP(ValidatePolyFillRect); - XAA_STATE_WRAP(ValidatePolyFillArc); - XAA_STATE_WRAP(ValidatePolyText8); - XAA_STATE_WRAP(ValidatePolyText16); - XAA_STATE_WRAP(ValidateImageText8); - XAA_STATE_WRAP(ValidateImageText16); - XAA_STATE_WRAP(ValidatePolyGlyphBlt); - XAA_STATE_WRAP(ValidateImageGlyphBlt); - XAA_STATE_WRAP(ValidatePushPixels); - XAA_STATE_WRAP(ComputeDash); - XAA_STATE_WRAP(InitPixmapCache); - XAA_STATE_WRAP(ClosePixmapCache); - XAA_STATE_WRAP(StippledFillChooser); - XAA_STATE_WRAP(OpaqueStippledFillChooser); - XAA_STATE_WRAP(TiledFillChooser); - XAA_STATE_WRAP(CacheTile); - XAA_STATE_WRAP(CacheStipple); - XAA_STATE_WRAP(CacheMonoStipple); - XAA_STATE_WRAP(CacheMono8x8Pattern); - XAA_STATE_WRAP(CacheColor8x8Pattern); - XAA_STATE_WRAP(WriteBitmapToCache); - XAA_STATE_WRAP(WritePixmapToCache); - XAA_STATE_WRAP(WriteMono8x8PatternToCache); - XAA_STATE_WRAP(WriteColor8x8PatternToCache); - XAA_STATE_WRAP(GetImage); - XAA_STATE_WRAP(GetSpans); - XAA_STATE_WRAP(CopyWindow); - XAA_STATE_WRAP(SetupForCPUToScreenAlphaTexture2); - XAA_STATE_WRAP(SetupForCPUToScreenTexture2); - return TRUE; -} + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "xf86str.h" +#include "mi.h" +#include "miline.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xaawrap.h" +#include "servermd.h" + +#define XAA_STATE_WRAP(func) do {\ +if(infoRec->func) { \ + pStatePriv->func = infoRec->func;\ + infoRec->func = XAAStateWrap##func;\ +}} while(0) + +/* Wrap all XAA functions and allocate our private structure. + */ + +typedef struct _XAAStateWrapRec { + ScrnInfoPtr pScrn; + void (*RestoreAccelState)(ScrnInfoPtr pScrn); + void (*Sync)(ScrnInfoPtr pScrn); + void (*SetupForScreenToScreenCopy)(ScrnInfoPtr pScrn, int xdir, int ydir, + int rop, unsigned int planemask, + int trans_color); + void (*SetupForSolidFill)(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask); + void (*SetupForSolidLine)(ScrnInfoPtr pScrn,int color,int rop, + unsigned int planemask); + void (*SetupForDashedLine)(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int length, + unsigned char *pattern); + void (*SetClippingRectangle) (ScrnInfoPtr pScrn, int left, int top, + int right, int bottom); + void (*DisableClipping)(ScrnInfoPtr pScrn); + void (*SetupForMono8x8PatternFill)(ScrnInfoPtr pScrn, int patx, int paty, + int fg, int bg, int rop, + unsigned int planemask); + void (*SetupForColor8x8PatternFill)(ScrnInfoPtr pScrn, int patx, int paty, + int rop, unsigned int planemask, + int transparency_color); + void (*SetupForCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int fg, + int bg, int rop, + unsigned int planemask); + void (*SetupForScanlineCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask); + void (*SetupForScreenToScreenColorExpandFill) (ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask); + void (*SetupForImageWrite)(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int transparency_color, + int bpp, int depth); + void (*SetupForScanlineImageWrite)(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, + int transparency_color, + int bpp, int depth); + void (*SetupForImageRead) (ScrnInfoPtr pScrn, int bpp, int depth); + void (*ScreenToScreenBitBlt)(ScrnInfoPtr pScrn, int nbox, + DDXPointPtr pptSrc, BoxPtr pbox, int xdir, + int ydir, int alu, unsigned int planmask); + void (*WriteBitmap) (ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *src, int srcwidth, int skipleft, + int fg, int bg, int rop, unsigned int planemask); + void (*FillSolidRects)(ScrnInfoPtr pScrn, int fg, int rop, + unsigned int planemask, int nBox, BoxPtr pBox); + void (*FillMono8x8PatternRects)(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int nBox, + BoxPtr pBox, int pat0, int pat1, + int xorg, int yorg); + void (*FillColor8x8PatternRects)(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int nBox, + BoxPtr pBox, int xorg, int yorg, + XAACacheInfoPtr pCache); + void (*FillCacheBltRects)(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int nBox, BoxPtr pBox, + int xorg, int yorg, XAACacheInfoPtr pCache); + void (*FillColorExpandRects)(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int nBox, + BoxPtr pBox, int xorg, int yorg, + PixmapPtr pPix); + void (*FillCacheExpandRects)(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int nBox, BoxPtr pBox, + int xorg, int yorg, PixmapPtr pPix); + void (*FillImageWriteRects)(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int nBox, BoxPtr pBox, + int xorg, int yorg, PixmapPtr pPix); + void (*FillSolidSpans)(ScrnInfoPtr pScrn, int fg, int rop, + unsigned int planemask, int n, DDXPointPtr points, + int *widths, int fSorted); + void (*FillMono8x8PatternSpans)(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int n, + DDXPointPtr points, int *widths, + int fSorted, int pat0, int pat1, + int xorg, int yorg); + void (*FillColor8x8PatternSpans)(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int n, + DDXPointPtr points, int *widths, + int fSorted, XAACacheInfoPtr pCache, + int xorg, int yorg); + void (*FillCacheBltSpans)(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int n, DDXPointPtr points, + int *widths, int fSorted, XAACacheInfoPtr pCache, + int xorg, int yorg); + void (*FillColorExpandSpans)(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int n, + DDXPointPtr points, int *widths, int fSorted, + int xorg, int yorg, PixmapPtr pPix); + void (*FillCacheExpandSpans)(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int n, DDXPointPtr ppt, + int *pwidth, int fSorted, int xorg, int yorg, + PixmapPtr pPix); + void (*TEGlyphRenderer)(ScrnInfoPtr pScrn, int x, int y, int w, int h, + int skipleft, int startline, unsigned int **glyphs, + int glyphWidth, int fg, int bg, int rop, + unsigned planemask); + void (*NonTEGlyphRenderer)(ScrnInfoPtr pScrn, int x, int y, int n, + NonTEGlyphPtr glyphs, BoxPtr pbox, + int fg, int rop, unsigned int planemask); + void (*WritePixmap) (ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *src, int srcwidth, int rop, + unsigned int planemask, int transparency_color, + int bpp, int depth); + void (*ReadPixmap) (ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *dst, int dstwidth, int bpp, int depth); + RegionPtr (*CopyArea)(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GC *pGC, int srcx, int srcy, int width, int height, + int dstx, int dsty); + RegionPtr (*CopyPlane)(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int width, int height, int dstx, + int dsty, unsigned long bitPlane); + void (*PushPixelsSolid) (GCPtr pGC, PixmapPtr pBitMap, + DrawablePtr pDrawable, int dx, int dy, int xOrg, + int yOrg); + void (*PolyFillRectSolid)(DrawablePtr pDraw, GCPtr pGC, int nrectFill, + xRectangle *prectInit); + void (*PolyFillRectStippled)(DrawablePtr pDraw, GCPtr pGC, int nrectFill, + xRectangle *prectInit); + void (*PolyFillRectOpaqueStippled)(DrawablePtr pDraw, GCPtr pGC, + int nrectFill, xRectangle *prectInit); + void (*PolyFillRectTiled)(DrawablePtr pDraw, GCPtr pGC, int nrectFill, + xRectangle *prectInit); + void (*FillSpansSolid)(DrawablePtr pDraw, GCPtr pGC, int nInit, + DDXPointPtr ppt, int *pwidth, int fSorted); + void (*FillSpansStippled)(DrawablePtr pDraw, GCPtr pGC, int nInit, + DDXPointPtr ppt, int *pwidth, int fSorted); + void (*FillSpansOpaqueStippled)(DrawablePtr pDraw, GCPtr pGC, int nInit, + DDXPointPtr ppt, int *pwidth, int fSorted); + void (*FillSpansTiled)(DrawablePtr pDraw, GCPtr pGC, int nInit, + DDXPointPtr ppt, int *pwidth, int fSorted); + int (*PolyText8TE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, + char *chars); + int (*PolyText16TE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, + unsigned short *chars); + void (*ImageText8TE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, + char *chars); + void (*ImageText16TE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars); + void (*ImageGlyphBltTE) (DrawablePtr pDrawable, GCPtr pGC, int xInit, + int yInit, unsigned int nglyph, CharInfoPtr *ppci, + pointer pglyphBase); + void (*PolyGlyphBltTE) (DrawablePtr pDrawable, GCPtr pGC, int xInit, + int yInit, unsigned int nglyph, CharInfoPtr *ppci, + pointer pglyphBase); + int (*PolyText8NonTE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, char *chars); + int (*PolyText16NonTE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars); + void (*ImageText8NonTE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, char *chars); + void (*ImageText16NonTE) (DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars); + void (*ImageGlyphBltNonTE) (DrawablePtr pDrawable, GCPtr pGC, int xInit, + int yInit, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase); + void (*PolyGlyphBltNonTE) (DrawablePtr pDrawable, GCPtr pGC, int xInit, + int yInit, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase); + void (*PolyRectangleThinSolid)(DrawablePtr pDrawable,GCPtr pGC, + int nRectsInit, xRectangle *pRectsInit); + void (*PolylinesWideSolid)(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, DDXPointPtr pPts); + void (*PolylinesThinSolid)(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, DDXPointPtr pPts); + void (*PolySegmentThinSolid)(DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *pSeg); + void (*PolylinesThinDashed)(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, DDXPointPtr pPts); + void (*PolySegmentThinDashed)(DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *pSeg); + void (*FillPolygonSolid)(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr ptsIn); + void (*FillPolygonStippled)(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr ptsIn); + void (*FillPolygonOpaqueStippled)(DrawablePtr pDrawable, GCPtr pGC, + int shape, int mode, int count, + DDXPointPtr ptsIn); + void (*FillPolygonTiled)(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr ptsIn); + void (*PolyFillArcSolid)(DrawablePtr pDraw, GCPtr pGC, int narcs, + xArc *parcs); + void (*PutImage)(DrawablePtr pDraw, GCPtr pGC, int depth, int x, int y, + int w, int h, int leftPad, int format, char *pImage); + ValidateGCProcPtr ValidateFillSpans; + ValidateGCProcPtr ValidateSetSpans; + ValidateGCProcPtr ValidatePutImage; + ValidateGCProcPtr ValidateCopyArea; + ValidateGCProcPtr ValidateCopyPlane; + ValidateGCProcPtr ValidatePolyPoint; + ValidateGCProcPtr ValidatePolylines; + ValidateGCProcPtr ValidatePolySegment; + ValidateGCProcPtr ValidatePolyRectangle; + ValidateGCProcPtr ValidatePolyArc; + ValidateGCProcPtr ValidateFillPolygon; + ValidateGCProcPtr ValidatePolyFillRect; + ValidateGCProcPtr ValidatePolyFillArc; + ValidateGCProcPtr ValidatePolyText8; + ValidateGCProcPtr ValidatePolyText16; + ValidateGCProcPtr ValidateImageText8; + ValidateGCProcPtr ValidateImageText16; + ValidateGCProcPtr ValidatePolyGlyphBlt; + ValidateGCProcPtr ValidateImageGlyphBlt; + ValidateGCProcPtr ValidatePushPixels; + void (*ComputeDash)(GCPtr pGC); + void (*InitPixmapCache)(ScreenPtr pScreen, RegionPtr areas, pointer data); + void (*ClosePixmapCache)(ScreenPtr pScreen); + int (*StippledFillChooser)(GCPtr pGC); + int (*OpaqueStippledFillChooser)(GCPtr pGC); + int (*TiledFillChooser)(GCPtr pGC); + XAACacheInfoPtr (*CacheTile)(ScrnInfoPtr Scrn, PixmapPtr pPix); + XAACacheInfoPtr (*CacheStipple)(ScrnInfoPtr Scrn, PixmapPtr pPix, int fg, + int bg); + XAACacheInfoPtr (*CacheMonoStipple)(ScrnInfoPtr Scrn, PixmapPtr pPix); + XAACacheInfoPtr (*CacheMono8x8Pattern)(ScrnInfoPtr Scrn, int pat0, + int pat1); + XAACacheInfoPtr (*CacheColor8x8Pattern)(ScrnInfoPtr Scrn, PixmapPtr pPix, + int fg, int bg); + void (*WriteBitmapToCache) (ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *src, int srcwidth, int fg, + int bg); + void (*WritePixmapToCache) (ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *src, int srcwidth, int bpp, + int depth); + void (*WriteMono8x8PatternToCache)(ScrnInfoPtr pScrn, + XAACacheInfoPtr pCache); + void (*WriteColor8x8PatternToCache)(ScrnInfoPtr pScrn, PixmapPtr pPix, + XAACacheInfoPtr pCache); + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + CopyWindowProcPtr CopyWindow; + Bool (*SetupForCPUToScreenAlphaTexture2)(ScrnInfoPtr pScrn, int op, + CARD16 red, CARD16 green, + CARD16 blue, CARD16 alpha, + CARD32 maskFormat, CARD32 dstFormat, + CARD8 *alphaPtr, int alphaPitch, + int width, int height, int flags); + Bool (*SetupForCPUToScreenTexture2)(ScrnInfoPtr pScrn, int op, + CARD32 srcFormat, CARD32 dstFormat, + CARD8 *texPtr, int texPitch, + int width, int height, int flags); +} XAAStateWrapRec, *XAAStateWrapPtr; + +static int XAAStateKeyIndex; +static DevPrivateKey XAAStateKey = &XAAStateKeyIndex; + +/* Wrap functions start here */ +#define GET_STATEPRIV_GC(pGC) XAAStateWrapPtr pStatePriv =\ +(XAAStateWrapPtr)dixLookupPrivate(&(pGC)->pScreen->devPrivates, XAAStateKey) + +#define GET_STATEPRIV_SCREEN(pScreen) XAAStateWrapPtr pStatePriv =\ +(XAAStateWrapPtr)dixLookupPrivate(&(pScreen)->devPrivates, XAAStateKey) + +#define GET_STATEPRIV_PSCRN(pScrn) XAAStateWrapPtr pStatePriv =\ +(XAAStateWrapPtr)dixLookupPrivate(&(pScrn)->pScreen->devPrivates, XAAStateKey) + +#define STATE_CHECK_SP(pStatePriv) {\ + ScrnInfoPtr pScrn = pStatePriv->pScrn;\ + int i = 0;\ + int need_change = 0;\ + while(i < pScrn->numEntities) {\ + if(xf86IsEntityShared(pScrn->entityList[i]) &&\ + xf86GetLastScrnFlag(pScrn->entityList[i]) != pScrn->scrnIndex) {\ + need_change = 1;\ + xf86SetLastScrnFlag(pScrn->entityList[i],\ + pScrn->scrnIndex);\ + }\ + i++;\ + }\ + if(need_change == 1) (*pStatePriv->RestoreAccelState)(pScrn);\ +} + +#define STATE_CHECK_PSCRN(pScrn) {\ + int i = 0;\ + int need_change = 0;\ + while(i < pScrn->numEntities) {\ + if(xf86IsEntityShared(pScrn->entityList[i]) &&\ + xf86GetLastScrnFlag(pScrn->entityList[i]) != pScrn->scrnIndex) {\ + need_change = 1;\ + xf86SetLastScrnFlag(pScrn->entityList[i],\ + pScrn->scrnIndex);\ + }\ + i++;\ + }\ + if(need_change == 1) (*pStatePriv->RestoreAccelState)(pScrn);\ +} + +static void XAAStateWrapSync(ScrnInfoPtr pScrn) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->Sync)(pScrn); +} + +static void XAAStateWrapSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, + int rop, unsigned int planemask, + int trans_color) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForScreenToScreenCopy)(pScrn, xdir, ydir, rop, planemask, + trans_color); +} + +static void XAAStateWrapSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForSolidFill)(pScrn, color, rop, planemask); +} + +static void XAAStateWrapSetupForSolidLine(ScrnInfoPtr pScrn,int color,int rop, + unsigned int planemask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForSolidLine)(pScrn, color, rop, planemask); +} + +static void XAAStateWrapSetupForDashedLine(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int length, + unsigned char *pattern) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForDashedLine)(pScrn, fg, bg, rop, planemask, length, pattern); +} + +static void XAAStateWrapSetClippingRectangle(ScrnInfoPtr pScrn, int left, int top, + int right, int bottom) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetClippingRectangle)(pScrn, left, top, right, bottom); +} + +static void XAAStateWrapDisableClipping(ScrnInfoPtr pScrn) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->DisableClipping)(pScrn); +} + +static void XAAStateWrapSetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int patx, int paty, + int fg, int bg, int rop, + unsigned int planemask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForMono8x8PatternFill)(pScrn, patx, paty, fg, bg, rop, planemask); +} + +static void XAAStateWrapSetupForColor8x8PatternFill(ScrnInfoPtr pScrn, int patx, int paty, + int rop, unsigned int planemask, + int transparency_color) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForColor8x8PatternFill)(pScrn, patx, paty, rop, planemask, + transparency_color); +} + +static void XAAStateWrapSetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int fg, + int bg, int rop, + unsigned int planemask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForCPUToScreenColorExpandFill)(pScrn, fg, bg, rop, planemask); +} + +static void XAAStateWrapSetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, + unsigned int planemask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForScanlineCPUToScreenColorExpandFill)(pScrn, fg, bg, rop, + planemask); +} + +static void XAAStateWrapSetupForScreenToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForScreenToScreenColorExpandFill)(pScrn, fg, bg, rop, planemask); +} + +static void XAAStateWrapSetupForImageWrite(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int transparency_color, + int bpp, int depth) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForImageWrite)(pScrn, rop, planemask, transparency_color, bpp, + depth); +} + +static void XAAStateWrapSetupForScanlineImageWrite(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, + int transparency_color, + int bpp, int depth) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForScanlineImageWrite)(pScrn, rop, planemask, transparency_color, + bpp, depth); +} + +static void XAAStateWrapSetupForImageRead(ScrnInfoPtr pScrn, int bpp, int depth) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->SetupForImageRead)(pScrn, bpp, depth); +} + +static void XAAStateWrapScreenToScreenBitBlt(ScrnInfoPtr pScrn, int nbox, + DDXPointPtr pptSrc, BoxPtr pbox, int xdir, + int ydir, int alu, unsigned int planmask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->ScreenToScreenBitBlt)(pScrn, nbox, + pptSrc, pbox, xdir, + ydir, alu, planmask); +} + +static void XAAStateWrapWriteBitmap(ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *src, int srcwidth, int skipleft, + int fg, int bg, int rop, unsigned int planemask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->WriteBitmap)(pScrn, x, y, w, h, + src, srcwidth, skipleft, + fg, bg, rop, planemask); +} + +static void XAAStateWrapFillSolidRects(ScrnInfoPtr pScrn, int fg, int rop, + unsigned int planemask, int nBox, BoxPtr pBox) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillSolidRects)(pScrn, fg, rop, + planemask, nBox, pBox); +} + +static void XAAStateWrapFillMono8x8PatternRects(ScrnInfoPtr pScrn, int fg, int bg, + int rop, unsigned int planemask, int nBox, + BoxPtr pBox, int pat0, int pat1, + int xorg, int yorg) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillMono8x8PatternRects)(pScrn, fg, bg, + rop, planemask, nBox, + pBox, pat0, pat1, + xorg, yorg); +} + +static void XAAStateWrapFillColor8x8PatternRects(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int nBox, + BoxPtr pBox, int xorg, int yorg, + XAACacheInfoPtr pCache) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillColor8x8PatternRects)(pScrn, rop, + planemask, nBox, + pBox, xorg, yorg, + pCache); +} + +static void XAAStateWrapFillCacheBltRects(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int nBox, BoxPtr pBox, + int xorg, int yorg, XAACacheInfoPtr pCache) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillCacheBltRects)(pScrn, rop, + planemask, nBox, pBox, + xorg, yorg, pCache); +} + +static void XAAStateWrapFillColorExpandRects(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int nBox, + BoxPtr pBox, int xorg, int yorg, + PixmapPtr pPix) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillColorExpandRects)(pScrn, fg, bg, rop, + planemask, nBox, + pBox, xorg, yorg, + pPix); +} + +static void XAAStateWrapFillCacheExpandRects(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int nBox, + BoxPtr pBox, int xorg, int yorg, + PixmapPtr pPix) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillCacheExpandRects)(pScrn, fg, bg, rop, + planemask, nBox, + pBox, xorg, yorg, + pPix); +} + +static void XAAStateWrapFillImageWriteRects(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int nBox, BoxPtr pBox, + int xorg, int yorg, PixmapPtr pPix) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillImageWriteRects)(pScrn, rop, + planemask, nBox, pBox, + xorg, yorg, pPix); +} + +static void XAAStateWrapFillSolidSpans(ScrnInfoPtr pScrn, int fg, int rop, + unsigned int planemask, int n, DDXPointPtr points, + int *widths, int fSorted) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillSolidSpans)(pScrn, fg, rop, + planemask, n, points, + widths, fSorted); +} + +static void XAAStateWrapFillMono8x8PatternSpans(ScrnInfoPtr pScrn, int fg, int bg, + int rop, unsigned int planemask, int n, + DDXPointPtr points, int *widths, + int fSorted, int pat0, int pat1, + int xorg, int yorg) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillMono8x8PatternSpans)(pScrn, fg, bg, + rop, planemask, n, + points, widths, + fSorted, pat0, pat1, + xorg, yorg); +} + +static void XAAStateWrapFillColor8x8PatternSpans(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int n, + DDXPointPtr points, int *widths, + int fSorted, XAACacheInfoPtr pCache, + int xorg, int yorg) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillColor8x8PatternSpans)(pScrn, rop, + planemask, n, + points, widths, + fSorted, pCache, + xorg, yorg); +} + +static void XAAStateWrapFillCacheBltSpans(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int n, + DDXPointPtr points, int *widths, + int fSorted, XAACacheInfoPtr pCache, + int xorg, int yorg) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillCacheBltSpans)(pScrn, rop, + planemask, n, + points, widths, + fSorted, pCache, + xorg, yorg); +} + +static void XAAStateWrapFillColorExpandSpans(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int n, + DDXPointPtr points, int *widths, int fSorted, + int xorg, int yorg, PixmapPtr pPix) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillColorExpandSpans)(pScrn, fg, bg, rop, + planemask, n, + points, widths, fSorted, + xorg, yorg, pPix); +} + +static void XAAStateWrapFillCacheExpandSpans(ScrnInfoPtr pScrn, int fg, int bg, int rop, + unsigned int planemask, int n, + DDXPointPtr ppt, int *pwidth, int fSorted, + int xorg, int yorg, PixmapPtr pPix) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->FillCacheExpandSpans)(pScrn, fg, bg, rop, + planemask, n, + ppt, pwidth, fSorted, + xorg, yorg, pPix); +} + +static void XAAStateWrapTEGlyphRenderer(ScrnInfoPtr pScrn, int x, int y, int w, int h, + int skipleft, int startline, + unsigned int **glyphs, + int glyphWidth, int fg, int bg, int rop, + unsigned planemask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->TEGlyphRenderer)(pScrn, x, y, w, h, + skipleft, startline, + glyphs, + glyphWidth, fg, bg, rop, + planemask); +} + +static void XAAStateWrapNonTEGlyphRenderer(ScrnInfoPtr pScrn, int x, int y, int n, + NonTEGlyphPtr glyphs, BoxPtr pbox, + int fg, int rop, unsigned int planemask) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->NonTEGlyphRenderer)(pScrn, x, y, n, + glyphs, pbox, + fg, rop, planemask); +} + +static void XAAStateWrapWritePixmap(ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *src, int srcwidth, int rop, + unsigned int planemask, int transparency_color, + int bpp, int depth) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->WritePixmap)(pScrn, x, y, w, h, + src, srcwidth, rop, + planemask, transparency_color, + bpp, depth); +} + +static void XAAStateWrapReadPixmap(ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *dst, int dstwidth, int bpp, int depth) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->ReadPixmap)(pScrn, x, y, w, h, + dst, dstwidth, bpp, depth); +} + +static RegionPtr XAAStateWrapCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GC *pGC, int srcx, int srcy, int width, int height, + int dstx, int dsty) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + return (*pStatePriv->CopyArea)(pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, width, height, + dstx, dsty); +} + +static RegionPtr XAAStateWrapCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int width, int height, + int dstx, int dsty, unsigned long bitPlane) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + return (*pStatePriv->CopyPlane)(pSrc, pDst, pGC, + srcx, srcy, width, height, + dstx, dsty, bitPlane); +} + +static void XAAStateWrapPushPixelsSolid(GCPtr pGC, PixmapPtr pBitMap, + DrawablePtr pDrawable, int dx, int dy, int xOrg, + int yOrg) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PushPixelsSolid)(pGC, pBitMap, + pDrawable, dx, dy, xOrg, + yOrg); +} + +static void XAAStateWrapPolyFillRectSolid(DrawablePtr pDraw, GCPtr pGC, int nrectFill, + xRectangle *prectInit) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolyFillRectSolid)(pDraw, pGC, nrectFill, + prectInit); +} + +static void XAAStateWrapPolyFillRectStippled(DrawablePtr pDraw, GCPtr pGC, int nrectFill, + xRectangle *prectInit) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolyFillRectStippled)(pDraw, pGC, nrectFill, + prectInit); +} + +static void XAAStateWrapPolyFillRectOpaqueStippled(DrawablePtr pDraw, GCPtr pGC, + int nrectFill, xRectangle *prectInit) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolyFillRectOpaqueStippled)(pDraw, pGC, + nrectFill, prectInit); +} + +static void XAAStateWrapPolyFillRectTiled(DrawablePtr pDraw, GCPtr pGC, int nrectFill, + xRectangle *prectInit) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolyFillRectTiled)(pDraw, pGC, nrectFill, + prectInit); +} + +static void XAAStateWrapFillSpansSolid(DrawablePtr pDraw, GCPtr pGC, int nInit, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->FillSpansSolid)(pDraw, pGC, nInit, + ppt, pwidth, fSorted); +} + +static void XAAStateWrapFillSpansStippled(DrawablePtr pDraw, GCPtr pGC, int nInit, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->FillSpansStippled)(pDraw, pGC, nInit, + ppt, pwidth, fSorted); +} + +static void XAAStateWrapFillSpansOpaqueStippled(DrawablePtr pDraw, GCPtr pGC, int nInit, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->FillSpansOpaqueStippled)(pDraw, pGC, nInit, + ppt, pwidth, fSorted); +} + +static void XAAStateWrapFillSpansTiled(DrawablePtr pDraw, GCPtr pGC, int nInit, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->FillSpansTiled)(pDraw, pGC, nInit, + ppt, pwidth, fSorted); +} + +static int XAAStateWrapPolyText8TE(DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, + char *chars) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + return (*pStatePriv->PolyText8TE)(pDraw, pGC, x, y, count, + chars); +} + +static int XAAStateWrapPolyText16TE(DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, + unsigned short *chars) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + return (*pStatePriv->PolyText16TE)(pDraw, pGC, x, y, count, + chars); +} + +static void XAAStateWrapImageText8TE(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, char *chars) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ImageText8TE)(pDraw, pGC, x, y, + count, chars); +} + +static void XAAStateWrapImageText16TE(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ImageText16TE)(pDraw, pGC, x, y, + count, chars); +} + +static void XAAStateWrapImageGlyphBltTE(DrawablePtr pDrawable, GCPtr pGC, int xInit, + int yInit, unsigned int nglyph, CharInfoPtr *ppci, + pointer pglyphBase) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ImageGlyphBltTE)(pDrawable, pGC, xInit, + yInit, nglyph, ppci, + pglyphBase); +} + +static void XAAStateWrapPolyGlyphBltTE(DrawablePtr pDrawable, GCPtr pGC, int xInit, + int yInit, unsigned int nglyph, CharInfoPtr *ppci, + pointer pglyphBase) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolyGlyphBltTE)(pDrawable, pGC, xInit, + yInit, nglyph, ppci, + pglyphBase); +} + +static int XAAStateWrapPolyText8NonTE(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, char *chars) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + return (*pStatePriv->PolyText8NonTE)(pDraw, pGC, x, y, + count, chars); +} + +static int XAAStateWrapPolyText16NonTE(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + return (*pStatePriv->PolyText16NonTE)(pDraw, pGC, x, y, + count, chars); +} + +static void XAAStateWrapImageText8NonTE(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, char *chars) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ImageText8NonTE)(pDraw, pGC, x, y, + count, chars); +} + +static void XAAStateWrapImageText16NonTE(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ImageText16NonTE)(pDraw, pGC, x, y, + count, chars); +} + +static void XAAStateWrapImageGlyphBltNonTE(DrawablePtr pDrawable, GCPtr pGC, int xInit, + int yInit, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ImageGlyphBltNonTE)(pDrawable, pGC, xInit, + yInit, nglyph, + ppci, pglyphBase); +} + +static void XAAStateWrapPolyGlyphBltNonTE(DrawablePtr pDrawable, GCPtr pGC, int xInit, + int yInit, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolyGlyphBltNonTE)(pDrawable, pGC, xInit, + yInit, nglyph, + ppci, pglyphBase); +} + +static void XAAStateWrapPolyRectangleThinSolid(DrawablePtr pDrawable,GCPtr pGC, + int nRectsInit, xRectangle *pRectsInit) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolyRectangleThinSolid)(pDrawable, pGC, + nRectsInit, pRectsInit); +} + +static void XAAStateWrapPolylinesWideSolid(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, DDXPointPtr pPts) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolylinesWideSolid)(pDrawable, pGC, mode, + npt, pPts); +} + +static void XAAStateWrapPolylinesThinSolid(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, DDXPointPtr pPts) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolylinesThinSolid)(pDrawable, pGC, mode, + npt, pPts); +} + +static void XAAStateWrapPolySegmentThinSolid(DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *pSeg) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolySegmentThinSolid)(pDrawable, pGC, nseg, + pSeg); +} + +static void XAAStateWrapPolylinesThinDashed(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, DDXPointPtr pPts) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolylinesThinDashed)(pDrawable, pGC, mode, + npt, pPts); +} + +static void XAAStateWrapPolySegmentThinDashed(DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *pSeg) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolySegmentThinDashed)(pDrawable, pGC, nseg, + pSeg); +} + +static void XAAStateWrapFillPolygonSolid(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr ptsIn) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->FillPolygonSolid)(pDrawable, pGC, shape, + mode, count, ptsIn); +} + +static void XAAStateWrapFillPolygonStippled(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr ptsIn) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->FillPolygonStippled)(pDrawable, pGC, shape, + mode, count, ptsIn); +} + +static void XAAStateWrapFillPolygonOpaqueStippled(DrawablePtr pDrawable, GCPtr pGC, + int shape, int mode, int count, + DDXPointPtr ptsIn) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->FillPolygonOpaqueStippled)(pDrawable, pGC, + shape, mode, count, + ptsIn); +} + +static void XAAStateWrapFillPolygonTiled(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr ptsIn) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->FillPolygonTiled)(pDrawable, pGC, shape, + mode, count, ptsIn); +} + +static void XAAStateWrapPolyFillArcSolid(DrawablePtr pDraw, GCPtr pGC, int narcs, + xArc *parcs) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PolyFillArcSolid)(pDraw, pGC, narcs, + parcs); +} + +static void XAAStateWrapPutImage(DrawablePtr pDraw, GCPtr pGC, int depth, int x, int y, + int w, int h, int leftPad, int format, char *pImage) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->PutImage)(pDraw, pGC, depth, x, y, + w, h, leftPad, format, pImage); +} + +static void XAAStateWrapValidateFillSpans(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidateFillSpans)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidateSetSpans(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidateSetSpans)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePutImage(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePutImage)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidateCopyArea(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidateCopyArea)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidateCopyPlane(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidateCopyPlane)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolyPoint(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolyPoint)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolylines(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolylines)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolySegment(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolySegment)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolyRectangle(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolyRectangle)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolyArc(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolyArc)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidateFillPolygon(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidateFillPolygon)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolyFillRect(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolyFillRect)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolyFillArc(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolyFillArc)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolyText8(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolyText8)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolyText16(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolyText16)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidateImageText8(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidateImageText8)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidateImageText16(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidateImageText16)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePolyGlyphBlt(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePolyGlyphBlt)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidateImageGlyphBlt(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + (*pStatePriv->ValidateImageGlyphBlt)(pGC, changes, + pDraw); +} + +static void XAAStateWrapValidatePushPixels(GCPtr pGC, unsigned long changes, + DrawablePtr pDraw) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ValidatePushPixels)(pGC, changes, + pDraw); +} + +static void XAAStateWrapComputeDash(GCPtr pGC) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ComputeDash)(pGC); +} + +static void XAAStateWrapInitPixmapCache(ScreenPtr pScreen, RegionPtr areas, + pointer data) +{ + GET_STATEPRIV_SCREEN(pScreen); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->InitPixmapCache)(pScreen, areas, + data); +} + +static void XAAStateWrapClosePixmapCache(ScreenPtr pScreen) +{ + GET_STATEPRIV_SCREEN(pScreen); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->ClosePixmapCache)(pScreen); +} + +static int XAAStateWrapStippledFillChooser(GCPtr pGC) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + return (*pStatePriv->StippledFillChooser)(pGC); +} + +static int XAAStateWrapOpaqueStippledFillChooser(GCPtr pGC) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + return (*pStatePriv->OpaqueStippledFillChooser)(pGC); +} + +static int XAAStateWrapTiledFillChooser(GCPtr pGC) +{ + GET_STATEPRIV_GC(pGC); + STATE_CHECK_SP(pStatePriv); + + return (*pStatePriv->TiledFillChooser)(pGC); +} + +static XAACacheInfoPtr XAAStateWrapCacheTile(ScrnInfoPtr pScrn, PixmapPtr pPix) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + return (*pStatePriv->CacheTile)(pScrn, pPix); +} + +static XAACacheInfoPtr XAAStateWrapCacheStipple(ScrnInfoPtr pScrn, PixmapPtr pPix, int fg, + int bg) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + return (*pStatePriv->CacheStipple)(pScrn, pPix, fg, + bg); +} + +static XAACacheInfoPtr XAAStateWrapCacheMonoStipple(ScrnInfoPtr pScrn, PixmapPtr pPix) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + return (*pStatePriv->CacheMonoStipple)(pScrn, pPix); +} + +static XAACacheInfoPtr XAAStateWrapCacheMono8x8Pattern(ScrnInfoPtr pScrn, int pat0, + int pat1) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + return (*pStatePriv->CacheMono8x8Pattern)(pScrn, pat0, + pat1); +} + +static XAACacheInfoPtr XAAStateWrapCacheColor8x8Pattern(ScrnInfoPtr pScrn, PixmapPtr pPix, + int fg, int bg) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + return (*pStatePriv->CacheColor8x8Pattern)(pScrn, pPix, + fg, bg); +} + +static void XAAStateWrapWriteBitmapToCache(ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *src, int srcwidth, int fg, + int bg) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->WriteBitmapToCache)(pScrn, x, y, w, h, + src, srcwidth, fg, + bg); +} + +static void XAAStateWrapWritePixmapToCache(ScrnInfoPtr pScrn, int x, int y, int w, int h, + unsigned char *src, int srcwidth, int bpp, + int depth) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->WritePixmapToCache)(pScrn, x, y, w, h, + src, srcwidth, bpp, + depth); +} + +static void XAAStateWrapWriteMono8x8PatternToCache(ScrnInfoPtr pScrn, + XAACacheInfoPtr pCache) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->WriteMono8x8PatternToCache)(pScrn, + pCache); +} + +static void XAAStateWrapWriteColor8x8PatternToCache(ScrnInfoPtr pScrn, PixmapPtr pPix, + XAACacheInfoPtr pCache) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + (*pStatePriv->WriteColor8x8PatternToCache)(pScrn, pPix, + pCache); +} + +static void XAAStateWrapGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format,unsigned long planeMask, + char *pdstLine) +{ + GET_STATEPRIV_SCREEN(pDrawable->pScreen); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->GetImage)(pDrawable, sx, sy, w, h, + format, planeMask, + pdstLine); +} + +static void XAAStateWrapGetSpans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, + int *pwidth, int nspans, char *pdstStart) +{ + GET_STATEPRIV_SCREEN(pDrawable->pScreen); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->GetSpans)(pDrawable, wMax, ppt, + pwidth, nspans, pdstStart); +} + +static void XAAStateWrapCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + GET_STATEPRIV_SCREEN(pWindow->drawable.pScreen); + STATE_CHECK_SP(pStatePriv); + + (*pStatePriv->CopyWindow)(pWindow, ptOldOrg, + prgnSrc); +} + +static Bool XAAStateWrapSetupForCPUToScreenAlphaTexture2(ScrnInfoPtr pScrn, + int op, CARD16 red, + CARD16 green, + CARD16 blue, + CARD16 alpha, + CARD32 srcFormat, + CARD32 dstFormat, + CARD8 *alphaPtr, + int alphaPitch, + int width, int height, + int flags) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + return (*pStatePriv->SetupForCPUToScreenAlphaTexture2)(pScrn, op, red, green, + blue, alpha, srcFormat, + dstFormat, alphaPtr, + alphaPitch, width, + height, flags); +} + +static Bool XAAStateWrapSetupForCPUToScreenTexture2(ScrnInfoPtr pScrn, int op, + CARD32 srcFormat, + CARD32 dstFormat, + CARD8 *texPtr, int texPitch, + int width, int height, + int flags) +{ + GET_STATEPRIV_PSCRN(pScrn); + STATE_CHECK_PSCRN(pScrn); + + return (*pStatePriv->SetupForCPUToScreenTexture2)(pScrn, op, srcFormat, + dstFormat, texPtr, texPitch, + width, height, flags); +} + +/* Setup Function */ +Bool +XAAInitStateWrap(ScreenPtr pScreen, XAAInfoRecPtr infoRec) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XAAStateWrapPtr pStatePriv; + int i = 0; + + if(!(pStatePriv = malloc(sizeof(XAAStateWrapRec)))) return FALSE; + dixSetPrivate(&pScreen->devPrivates, XAAStateKey, pStatePriv); + pStatePriv->RestoreAccelState = infoRec->RestoreAccelState; + pStatePriv->pScrn = pScrn; + + /* Initialize the last screen to -1 so whenever an accel function + * is called the proper state is setup + */ + while(i < pScrn->numEntities) { + xf86SetLastScrnFlag(pScrn->entityList[i], -1); + i++; + } +/* Do the wrapping */ + XAA_STATE_WRAP(Sync); + XAA_STATE_WRAP(SetupForScreenToScreenCopy); + XAA_STATE_WRAP(SetupForSolidFill); + XAA_STATE_WRAP(SetupForSolidLine); + XAA_STATE_WRAP(SetupForDashedLine); + XAA_STATE_WRAP(SetClippingRectangle); + XAA_STATE_WRAP(DisableClipping); + XAA_STATE_WRAP(SetupForMono8x8PatternFill); + XAA_STATE_WRAP(SetupForColor8x8PatternFill); + XAA_STATE_WRAP(SetupForCPUToScreenColorExpandFill); + XAA_STATE_WRAP(SetupForScanlineCPUToScreenColorExpandFill); + XAA_STATE_WRAP(SetupForScreenToScreenColorExpandFill); + XAA_STATE_WRAP(SetupForImageWrite); + XAA_STATE_WRAP(SetupForScanlineImageWrite); + XAA_STATE_WRAP(SetupForImageRead); + XAA_STATE_WRAP(ScreenToScreenBitBlt); + XAA_STATE_WRAP(WriteBitmap); + XAA_STATE_WRAP(FillSolidRects); + XAA_STATE_WRAP(FillMono8x8PatternRects); + XAA_STATE_WRAP(FillColor8x8PatternRects); + XAA_STATE_WRAP(FillCacheBltRects); + XAA_STATE_WRAP(FillColorExpandRects); + XAA_STATE_WRAP(FillCacheExpandRects); + XAA_STATE_WRAP(FillImageWriteRects); + XAA_STATE_WRAP(FillSolidSpans); + XAA_STATE_WRAP(FillMono8x8PatternSpans); + XAA_STATE_WRAP(FillColor8x8PatternSpans); + XAA_STATE_WRAP(FillCacheBltSpans); + XAA_STATE_WRAP(FillColorExpandSpans); + XAA_STATE_WRAP(FillCacheExpandSpans); + XAA_STATE_WRAP(TEGlyphRenderer); + XAA_STATE_WRAP(NonTEGlyphRenderer); + XAA_STATE_WRAP(WritePixmap); + XAA_STATE_WRAP(ReadPixmap); + XAA_STATE_WRAP(CopyArea); + XAA_STATE_WRAP(CopyPlane); + XAA_STATE_WRAP(PushPixelsSolid); + XAA_STATE_WRAP(PolyFillRectSolid); + XAA_STATE_WRAP(PolyFillRectStippled); + XAA_STATE_WRAP(PolyFillRectOpaqueStippled); + XAA_STATE_WRAP(PolyFillRectTiled); + XAA_STATE_WRAP(FillSpansSolid); + XAA_STATE_WRAP(FillSpansStippled); + XAA_STATE_WRAP(FillSpansOpaqueStippled); + XAA_STATE_WRAP(FillSpansTiled); + XAA_STATE_WRAP(PolyText8TE); + XAA_STATE_WRAP(PolyText16TE); + XAA_STATE_WRAP(ImageText8TE); + XAA_STATE_WRAP(ImageText16TE); + XAA_STATE_WRAP(ImageGlyphBltTE); + XAA_STATE_WRAP(PolyGlyphBltTE); + XAA_STATE_WRAP(PolyText8NonTE); + XAA_STATE_WRAP(PolyText16NonTE); + XAA_STATE_WRAP(ImageText8NonTE); + XAA_STATE_WRAP(ImageText16NonTE); + XAA_STATE_WRAP(ImageGlyphBltNonTE); + XAA_STATE_WRAP(PolyGlyphBltNonTE); + XAA_STATE_WRAP(PolyRectangleThinSolid); + XAA_STATE_WRAP(PolylinesWideSolid); + XAA_STATE_WRAP(PolylinesThinSolid); + XAA_STATE_WRAP(PolySegmentThinSolid); + XAA_STATE_WRAP(PolylinesThinDashed); + XAA_STATE_WRAP(PolySegmentThinDashed); + XAA_STATE_WRAP(FillPolygonSolid); + XAA_STATE_WRAP(FillPolygonStippled); + XAA_STATE_WRAP(FillPolygonOpaqueStippled); + XAA_STATE_WRAP(FillPolygonTiled); + XAA_STATE_WRAP(PolyFillArcSolid); + XAA_STATE_WRAP(PutImage); + XAA_STATE_WRAP(ValidateFillSpans); + XAA_STATE_WRAP(ValidateSetSpans); + XAA_STATE_WRAP(ValidatePutImage); + XAA_STATE_WRAP(ValidateCopyArea); + XAA_STATE_WRAP(ValidateCopyPlane); + XAA_STATE_WRAP(ValidatePolyPoint); + XAA_STATE_WRAP(ValidatePolylines); + XAA_STATE_WRAP(ValidatePolySegment); + XAA_STATE_WRAP(ValidatePolyRectangle); + XAA_STATE_WRAP(ValidatePolyArc); + XAA_STATE_WRAP(ValidateFillPolygon); + XAA_STATE_WRAP(ValidatePolyFillRect); + XAA_STATE_WRAP(ValidatePolyFillArc); + XAA_STATE_WRAP(ValidatePolyText8); + XAA_STATE_WRAP(ValidatePolyText16); + XAA_STATE_WRAP(ValidateImageText8); + XAA_STATE_WRAP(ValidateImageText16); + XAA_STATE_WRAP(ValidatePolyGlyphBlt); + XAA_STATE_WRAP(ValidateImageGlyphBlt); + XAA_STATE_WRAP(ValidatePushPixels); + XAA_STATE_WRAP(ComputeDash); + XAA_STATE_WRAP(InitPixmapCache); + XAA_STATE_WRAP(ClosePixmapCache); + XAA_STATE_WRAP(StippledFillChooser); + XAA_STATE_WRAP(OpaqueStippledFillChooser); + XAA_STATE_WRAP(TiledFillChooser); + XAA_STATE_WRAP(CacheTile); + XAA_STATE_WRAP(CacheStipple); + XAA_STATE_WRAP(CacheMonoStipple); + XAA_STATE_WRAP(CacheMono8x8Pattern); + XAA_STATE_WRAP(CacheColor8x8Pattern); + XAA_STATE_WRAP(WriteBitmapToCache); + XAA_STATE_WRAP(WritePixmapToCache); + XAA_STATE_WRAP(WriteMono8x8PatternToCache); + XAA_STATE_WRAP(WriteColor8x8PatternToCache); + XAA_STATE_WRAP(GetImage); + XAA_STATE_WRAP(GetSpans); + XAA_STATE_WRAP(CopyWindow); + XAA_STATE_WRAP(SetupForCPUToScreenAlphaTexture2); + XAA_STATE_WRAP(SetupForCPUToScreenTexture2); + return TRUE; +} diff --git a/xorg-server/hw/xfree86/xaa/xaaTEGlyph.c b/xorg-server/hw/xfree86/xaa/xaaTEGlyph.c index 41e638e5c..049bb2cb3 100644 --- a/xorg-server/hw/xfree86/xaa/xaaTEGlyph.c +++ b/xorg-server/hw/xfree86/xaa/xaaTEGlyph.c @@ -1,1077 +1,1077 @@ - - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "xaa.h" -#include "xaalocal.h" -#include "xaacexp.h" -#include "xf86.h" - -/* scanline function for TRIPLE_BITS_24BPP */ -static CARD32 *DrawTextScanline3(CARD32 *base, CARD32 *mem, int width); - -/* Loop unrolled functions for common font widths */ -static CARD32 *DrawTETextScanlineGeneric(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -static CARD32 *DrawTETextScanlineWidth7(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -static CARD32 *DrawTETextScanlineWidth10(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -static CARD32 *DrawTETextScanlineWidth12(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -static CARD32 *DrawTETextScanlineWidth14(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -static CARD32 *DrawTETextScanlineWidth16(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -static CARD32 *DrawTETextScanlineWidth18(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -static CARD32 *DrawTETextScanlineWidth24(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); - - -#ifdef USEASSEMBLER -# ifdef FIXEDBASE -# ifdef MSBFIRST -CARD32 *DrawTETextScanlineWidth6PMSBFirstFixedBase(CARD32 *base, - unsigned int **glyphp, int line, int width, int glyphwidth); -CARD32 *DrawTETextScanlineWidth8PMSBFirstFixedBase(CARD32 *base, - unsigned int **glyphp, int line, int width, int glyphwidth); -CARD32 *DrawTETextScanlineWidth9PMSBFirstFixedBase(CARD32 *base, - unsigned int **glyphp, int line, int width, int glyphwidth); -# else -CARD32 *DrawTETextScanlineWidth6PLSBFirstFixedBase(CARD32 *base, - unsigned int **glyphp, int line, int width, int glyphwidth); -CARD32 *DrawTETextScanlineWidth8PLSBFirstFixedBase(CARD32 *base, - unsigned int **glyphp, int line, int width, int glyphwidth); -CARD32 *DrawTETextScanlineWidth9PLSBFirstFixedBase(CARD32 *base, - unsigned int **glyphp, int line, int width, int glyphwidth); -# endif -# else -# ifdef MSBFIRST -CARD32 *DrawTETextScanlineWidth6PMSBFirst(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -CARD32 *DrawTETextScanlineWidth8PMSBFirst(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -CARD32 *DrawTETextScanlineWidth9PMSBFirst(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -# else -CARD32 *DrawTETextScanlineWidth6PLSBFirst(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -CARD32 *DrawTETextScanlineWidth8PLSBFirst(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -CARD32 *DrawTETextScanlineWidth9PLSBFirst(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -# endif -# endif -#else -static CARD32 *DrawTETextScanlineWidth6(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -static CARD32 *DrawTETextScanlineWidth8(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -static CARD32 *DrawTETextScanlineWidth9(CARD32 *base, unsigned int **glyphp, - int line, int width, int glyphwidth); -#endif - -#define glyph_scanline_func EXPNAME(XAAGlyphScanlineFunc) -#define glyph_get_scanline_func EXPNAME(XAAGetGlyphScanlineFunc) - - -GlyphScanlineFuncPtr glyph_scanline_func[32] = { - DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, - DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, - DrawTETextScanlineGeneric, -#ifdef USEASSEMBLER -# ifdef FIXEDBASE -# ifdef MSBFIRST - DrawTETextScanlineWidth6PMSBFirstFixedBase, - DrawTETextScanlineWidth7, - DrawTETextScanlineWidth8PMSBFirstFixedBase, - DrawTETextScanlineWidth9PMSBFirstFixedBase, -# else - DrawTETextScanlineWidth6PLSBFirstFixedBase, - DrawTETextScanlineWidth7, - DrawTETextScanlineWidth8PLSBFirstFixedBase, - DrawTETextScanlineWidth9PLSBFirstFixedBase, -# endif -# else -# ifdef MSBFIRST - DrawTETextScanlineWidth6PMSBFirst, - DrawTETextScanlineWidth7, - DrawTETextScanlineWidth8PMSBFirst, - DrawTETextScanlineWidth9PMSBFirst, -# else - DrawTETextScanlineWidth6PLSBFirst, - DrawTETextScanlineWidth7, - DrawTETextScanlineWidth8PLSBFirst, - DrawTETextScanlineWidth9PLSBFirst, -# endif -# endif -#else - DrawTETextScanlineWidth6, DrawTETextScanlineWidth7, - DrawTETextScanlineWidth8, DrawTETextScanlineWidth9, -#endif - DrawTETextScanlineWidth10, - DrawTETextScanlineGeneric, DrawTETextScanlineWidth12, - DrawTETextScanlineGeneric, DrawTETextScanlineWidth14, - DrawTETextScanlineGeneric, DrawTETextScanlineWidth16, - DrawTETextScanlineGeneric, DrawTETextScanlineWidth18, - DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, - DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, - DrawTETextScanlineGeneric, DrawTETextScanlineWidth24, - DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, - DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, - DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, - DrawTETextScanlineGeneric, DrawTETextScanlineGeneric -}; - -GlyphScanlineFuncPtr *glyph_get_scanline_func(void) { - return glyph_scanline_func; -} - - -/******************************************************************** - - Here we have TEGlyphRenders for a bunch of different color - expansion types. The driver may provide its own renderer, but - this is the default one which renders using lower-level primitives - exported by the chipset driver. - -********************************************************************/ - -/* This gets built for MSBFIRST or LSBFIRST with FIXEDBASE or not. - A total of 4 versions */ - -void -EXPNAME(XAATEGlyphRenderer)( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - CARD32* base; - GlyphScanlineFuncPtr GlyphFunc = glyph_scanline_func[glyphWidth - 1]; - int dwords = 0; - - if((bg != -1) && (infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { - (*infoRec->SetupForSolidFill)(pScrn, bg, rop, planemask); - (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); - bg = -1; - } - - (*infoRec->SetupForCPUToScreenColorExpandFill)( - pScrn, fg, bg, rop, planemask); - - if(skipleft && - (!(infoRec->TEGlyphRendererFlags & LEFT_EDGE_CLIPPING) || - (!(infoRec->TEGlyphRendererFlags & LEFT_EDGE_CLIPPING_NEGATIVE_X) && - (skipleft > x)))) { - /* draw the first character only */ - - int count = h, line = startline; - int width = glyphWidth - skipleft; - - if(width > w) width = w; - - (*infoRec->SubsequentCPUToScreenColorExpandFill)( - pScrn, x, y, width, h, 0); - - base = (CARD32*)infoRec->ColorExpandBase; - - while(count--) { - register CARD32 tmp = SHIFT_R(glyphs[0][line++],skipleft); - WRITE_BITS(tmp); - } - - w -= width; - if((infoRec->TEGlyphRendererFlags & CPU_TRANSFER_PAD_QWORD) && - ((((width + 31) >> 5) * h) & 1)) { - base = (CARD32*)infoRec->ColorExpandBase; - base[0] = 0x00000000; - } - if(!w) goto THE_END; - glyphs++; - x += width; - skipleft = 0; /* nicely aligned again */ - } - - w += skipleft; - x -= skipleft; - dwords = ((w + 31) >> 5) * h; - - (*infoRec->SubsequentCPUToScreenColorExpandFill)( - pScrn, x, y, w, h, skipleft); - - base = (CARD32*)infoRec->ColorExpandBase; - -#ifndef FIXEDBASE - if((((w + 31) >> 5) * h) <= infoRec->ColorExpandRange) - while(h--) { - base = (*GlyphFunc)(base, glyphs, startline++, w, glyphWidth); - } - else -#endif - while(h--) { - (*GlyphFunc)(base, glyphs, startline++, w, glyphWidth); - } - - if((infoRec->TEGlyphRendererFlags & CPU_TRANSFER_PAD_QWORD) && - (dwords & 1)) { - base = (CARD32*)infoRec->ColorExpandBase; - base[0] = 0x00000000; - } - -THE_END: - - if(infoRec->TEGlyphRendererFlags & SYNC_AFTER_COLOR_EXPAND) - (*infoRec->Sync)(pScrn); - else SET_SYNC_FLAG(infoRec); -} - -/******************************************************************** - - This is the GlyphRenderer for TRIPLE_BITS_24BPP. It renders to a buffer - with the non FIXEDBASE LSB_FIRST code before tripling, and possibly - reversing the bits and sending them to the screen - -********************************************************************/ - -void -EXPNAME(XAATEGlyphRenderer3)( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - CARD32 *base, *mem; - GlyphScanlineFuncPtr GlyphFunc = XAAGlyphScanlineFuncLSBFirst[glyphWidth - 1]; - int dwords = 0; - - if((bg != -1) && - ((infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY) || - ((infoRec->TEGlyphRendererFlags & RGB_EQUAL) && - (!CHECK_RGB_EQUAL(bg))))) { - (*infoRec->SetupForSolidFill)(pScrn, bg, rop, planemask); - (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); - bg = -1; - } - - (*infoRec->SetupForCPUToScreenColorExpandFill)( - pScrn, fg, bg, rop, planemask); - - if(skipleft) { - /* draw the first character only */ - - int count = h, line = startline; - int width = glyphWidth - skipleft; - CARD32 bits; - - if(width > w) width = w; - (*infoRec->SubsequentCPUToScreenColorExpandFill)( - pScrn, x, y, width, h, 0); - - base = (CARD32*)infoRec->ColorExpandBase; - - while(count--) { - bits = SHIFT_R(glyphs[0][line++],skipleft); - if (width >= 22) { - WRITE_BITS3(bits); - } else if (width >= 11) { - WRITE_BITS2(bits); - } else { - WRITE_BITS1(bits); - } - } - - w -= width; - if((infoRec->TEGlyphRendererFlags & CPU_TRANSFER_PAD_QWORD) && - ((((3 * width + 31) >> 5) * h) & 1)) { - base = (CARD32*)infoRec->ColorExpandBase; - base[0] = 0x00000000; - } - if(!w) goto THE_END; - glyphs++; - x += width; - skipleft = 0; /* nicely aligned again */ - } - - dwords = ((3 * w + 31) >> 5) * h; - mem = (CARD32*)xalloc(((w + 31) >> 3) * sizeof(char)); - if (!mem) return; - - (*infoRec->SubsequentCPUToScreenColorExpandFill)(pScrn, x, y, w, h, 0); - - base = (CARD32*)infoRec->ColorExpandBase; - -# ifndef FIXEDBASE - if((((3 * w + 31) >> 5) * h) <= infoRec->ColorExpandRange) - while(h--) { - (*GlyphFunc)(mem, glyphs, startline++, w, glyphWidth); - base = DrawTextScanline3(base, mem, w); - } - else -# endif - while(h--) { - (*GlyphFunc)(mem, glyphs, startline++, w, glyphWidth); - DrawTextScanline3(base, mem, w); - } - - xfree(mem); - - if((infoRec->TEGlyphRendererFlags & CPU_TRANSFER_PAD_QWORD) && - (dwords & 1)) { - base = (CARD32*)infoRec->ColorExpandBase; - base[0] = 0x00000000; - } - -THE_END: - - if(infoRec->TEGlyphRendererFlags & SYNC_AFTER_COLOR_EXPAND) - (*infoRec->Sync)(pScrn); - else SET_SYNC_FLAG(infoRec); -} - - -#ifndef FIXEDBASE -/* Scanline version of above gets built for LSBFIRST and MSBFIRST */ - -void -EXPNAME(XAATEGlyphRendererScanline)( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - int bufferNo; - CARD32* base; - GlyphScanlineFuncPtr GlyphFunc = glyph_scanline_func[glyphWidth - 1]; - - if((bg != -1) && (infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { - (*infoRec->SetupForSolidFill)(pScrn, bg, rop, planemask); - (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); - bg = -1; - } - - (*infoRec->SetupForScanlineCPUToScreenColorExpandFill)( - pScrn, fg, bg, rop, planemask); - - if(skipleft && - (!(infoRec->TEGlyphRendererFlags & LEFT_EDGE_CLIPPING) || - (!(infoRec->TEGlyphRendererFlags & LEFT_EDGE_CLIPPING_NEGATIVE_X) && - (skipleft > x)))) { - /* draw the first character only */ - - int count = h, line = startline; - int width = glyphWidth - skipleft; - - if(width > w) width = w; - - (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)( - pScrn, x, y, width, h, 0); - - bufferNo = 0; - - while(count--) { - register CARD32 tmp = SHIFT_R(glyphs[0][line++],skipleft); - base = (CARD32*)infoRec->ScanlineColorExpandBuffers[bufferNo]; - WRITE_BITS(tmp); - (*infoRec->SubsequentColorExpandScanline)(pScrn, bufferNo++); - if(bufferNo >= infoRec->NumScanlineColorExpandBuffers) - bufferNo = 0; - } - - w -= width; - if(!w) goto THE_END; - glyphs++; - x += width; - skipleft = 0; /* nicely aligned again */ - } - - w += skipleft; - x -= skipleft; - - (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)( - pScrn, x, y, w, h, skipleft); - - bufferNo = 0; - - while(h--) { - base = (CARD32*)infoRec->ScanlineColorExpandBuffers[bufferNo]; - (*GlyphFunc)(base, glyphs, startline++, w, glyphWidth); - (*infoRec->SubsequentColorExpandScanline)(pScrn, bufferNo++); - if(bufferNo >= infoRec->NumScanlineColorExpandBuffers) - bufferNo = 0; - } - -THE_END: - - SET_SYNC_FLAG(infoRec); -} - -void -EXPNAME(XAATEGlyphRendererScanline3)( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - int bufferNo; - CARD32 *base, *mem; - GlyphScanlineFuncPtr GlyphFunc = XAAGlyphScanlineFuncLSBFirst[glyphWidth - 1]; - - if((bg != -1) && - ((infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY) || - ((infoRec->TEGlyphRendererFlags & RGB_EQUAL) && - (!CHECK_RGB_EQUAL(bg))))) { - (*infoRec->SetupForSolidFill)(pScrn, bg, rop, planemask); - (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); - bg = -1; - } - - (*infoRec->SetupForScanlineCPUToScreenColorExpandFill)( - pScrn, fg, bg, rop, planemask); - - if(skipleft) { - /* draw the first character only */ - - int count = h, line = startline; - int width = glyphWidth - skipleft; - CARD32 bits; - - if(width > w) width = w; - - (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)( - pScrn, x, y, width, h, 0); - - bufferNo = 0; - - while(count--) { - base = (CARD32*)infoRec->ScanlineColorExpandBuffers[bufferNo]; - bits = SHIFT_R(glyphs[0][line++],skipleft); - if (width >= 22) { - WRITE_BITS3(bits); - } else if (width >= 11) { - WRITE_BITS2(bits); - } else { - WRITE_BITS1(bits); - } - (*infoRec->SubsequentColorExpandScanline)(pScrn, bufferNo++); - if(bufferNo >= infoRec->NumScanlineColorExpandBuffers) - bufferNo = 0; - } - - w -= width; - if(!w) goto THE_END; - glyphs++; - x += width; - skipleft = 0; /* nicely aligned again */ - } - - w += skipleft; - x -= skipleft; - mem = (CARD32*)xalloc(((w + 31) >> 3) * sizeof(char)); - if (!mem) return; - - (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)( - pScrn, x, y, w, h, skipleft); - - bufferNo = 0; - - while(h--) { - base = (CARD32*)infoRec->ScanlineColorExpandBuffers[bufferNo]; - (*GlyphFunc)(mem, glyphs, startline++, w, glyphWidth); - DrawTextScanline3(base, mem, w); - (*infoRec->SubsequentColorExpandScanline)(pScrn, bufferNo++); - if(bufferNo >= infoRec->NumScanlineColorExpandBuffers) - bufferNo = 0; - } - - xfree(mem); - -THE_END: - - SET_SYNC_FLAG(infoRec); -} - -#endif - - - -/******************************************************************** - - TRIPLE_BITS_24BPP scanline rendering code. - -********************************************************************/ - - - -static CARD32* -DrawTextScanline3( - CARD32 *base, - CARD32 *mem, - int width ) -{ - - while(width > 32) { - WRITE_BITS3(*mem); - mem++; - width -= 32; - } - if(width) { - if (width >= 22) { - WRITE_BITS3(*mem); - } else if (width >= 11) { - WRITE_BITS2(*mem); - } else { - WRITE_BITS1(*mem); - } - } - - return base; -} - - -/******************************************************************** - - Generic TE scanline rendering code. - -********************************************************************/ - - - -static CARD32* -DrawTETextScanlineGeneric( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - CARD32 bits = (*glyphp)[line]; - int shift = glyphwidth; - - while(width > 32) { - while(shift < 32) { - glyphp++; - bits |= SHIFT_L((*glyphp)[line], shift); - shift += glyphwidth; - } - WRITE_BITS(bits); - shift &= 31; - if(shift) - bits = SHIFT_R((*glyphp)[line],(glyphwidth - shift)); - else bits = 0; - width -= 32; - } - - if(width) { - width -= shift; - while(width > 0) { - glyphp++; - bits |= SHIFT_L((*glyphp)[line],shift); - shift += glyphwidth; - width -= glyphwidth; - } - WRITE_BITS(bits); - } - - return base; -} - - -/******************************************************************** - - Loop unrolled TE font scanline rendering code - -********************************************************************/ - - -#ifndef USEASSEMBLER -static CARD32* -DrawTETextScanlineWidth6( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],6); - bits |= SHIFT_L(glyphp[2][line],12); - bits |= SHIFT_L(glyphp[3][line],18); - bits |= SHIFT_L(glyphp[4][line],24); - bits |= SHIFT_L(glyphp[5][line],30); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = SHIFT_R(glyphp[5][line],2); - bits |= SHIFT_L(glyphp[6][line],4); - bits |= SHIFT_L(glyphp[7][line],10); - bits |= SHIFT_L(glyphp[8][line],16); - bits |= SHIFT_L(glyphp[9][line],22); - bits |= SHIFT_L(glyphp[10][line],28); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); - bits = SHIFT_R(glyphp[10][line],4); - bits |= SHIFT_L(glyphp[11][line],2); - bits |= SHIFT_L(glyphp[12][line],8); - bits |= SHIFT_L(glyphp[13][line],14); - bits |= SHIFT_L(glyphp[14][line],20); - bits |= SHIFT_L(glyphp[15][line],26); - WRITE_IN_BITORDER(base, 2, bits); - CHECKRETURN(3); -#ifndef FIXEDBASE - base += 3; -#endif - width -= 96; - glyphp += 16; - } - return base; -} -#endif - -static CARD32* -DrawTETextScanlineWidth7( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],7); - bits |= SHIFT_L(glyphp[2][line],14); - bits |= SHIFT_L(glyphp[3][line],21); - bits |= SHIFT_L(glyphp[4][line],28); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = SHIFT_R(glyphp[4][line],4); - bits |= SHIFT_L(glyphp[5][line],3); - bits |= SHIFT_L(glyphp[6][line],10); - bits |= SHIFT_L(glyphp[7][line],17); - bits |= SHIFT_L(glyphp[8][line],24); - bits |= SHIFT_L(glyphp[9][line],31); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); - bits = SHIFT_R(glyphp[9][line],1); - bits |= SHIFT_L(glyphp[10][line],6); - bits |= SHIFT_L(glyphp[11][line],13); - bits |= SHIFT_L(glyphp[12][line],20); - bits |= SHIFT_L(glyphp[13][line],27); - WRITE_IN_BITORDER(base, 2, bits); - CHECKRETURN(3); - bits = SHIFT_R(glyphp[13][line],5); - bits |= SHIFT_L(glyphp[14][line],2); - bits |= SHIFT_L(glyphp[15][line],9); - bits |= SHIFT_L(glyphp[16][line],16); - bits |= SHIFT_L(glyphp[17][line],23); - bits |= SHIFT_L(glyphp[18][line],30); - WRITE_IN_BITORDER(base, 3, bits); - CHECKRETURN(4); - bits = SHIFT_R(glyphp[18][line],2); - bits |= SHIFT_L(glyphp[19][line],5); - bits |= SHIFT_L(glyphp[20][line],12); - bits |= SHIFT_L(glyphp[21][line],19); - bits |= SHIFT_L(glyphp[22][line],26); - WRITE_IN_BITORDER(base, 4, bits); - CHECKRETURN(5); - bits = SHIFT_R(glyphp[22][line],6); - bits |= SHIFT_L(glyphp[23][line],1); - bits |= SHIFT_L(glyphp[24][line],8); - bits |= SHIFT_L(glyphp[25][line],15); - bits |= SHIFT_L(glyphp[26][line],22); - bits |= SHIFT_L(glyphp[27][line],29); - WRITE_IN_BITORDER(base, 5, bits); - CHECKRETURN(6); - bits = SHIFT_R(glyphp[27][line],3); - bits |= SHIFT_L(glyphp[28][line],4); - bits |= SHIFT_L(glyphp[29][line],11); - bits |= SHIFT_L(glyphp[30][line],18); - bits |= SHIFT_L(glyphp[31][line],25); - WRITE_IN_BITORDER(base, 6, bits); - CHECKRETURN(7); -#ifndef FIXEDBASE - base += 7; -#endif - width -= 224; - glyphp += 32; - } - return base; -} - - -#ifndef USEASSEMBLER -static CARD32* -DrawTETextScanlineWidth8( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],8); - bits |= SHIFT_L(glyphp[2][line],16); - bits |= SHIFT_L(glyphp[3][line],24); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = glyphp[4][line]; - bits |= SHIFT_L(glyphp[5][line],8); - bits |= SHIFT_L(glyphp[6][line],16); - bits |= SHIFT_L(glyphp[7][line],24); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); -#ifndef FIXEDBASE - base += 2; -#endif - width -= 64; - glyphp += 8; - } - return base; -} -#endif - -#ifndef USEASSEMBLER -static CARD32* -DrawTETextScanlineWidth9( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],9); - bits |= SHIFT_L(glyphp[2][line],18); - bits |= SHIFT_L(glyphp[3][line],27); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = SHIFT_R(glyphp[3][line],5); - bits |= SHIFT_L(glyphp[4][line],4); - bits |= SHIFT_L(glyphp[5][line],13); - bits |= SHIFT_L(glyphp[6][line],22); - bits |= SHIFT_L(glyphp[7][line],31); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); - bits = SHIFT_R(glyphp[7][line],1); - bits |= SHIFT_L(glyphp[8][line],8); - bits |= SHIFT_L(glyphp[9][line],17); - bits |= SHIFT_L(glyphp[10][line],26); - WRITE_IN_BITORDER(base, 2, bits); - CHECKRETURN(3); - bits = SHIFT_R(glyphp[10][line],6); - bits |= SHIFT_L(glyphp[11][line],3); - bits |= SHIFT_L(glyphp[12][line],12); - bits |= SHIFT_L(glyphp[13][line],21); - bits |= SHIFT_L(glyphp[14][line],30); - WRITE_IN_BITORDER(base, 3, bits); - CHECKRETURN(4); - bits = SHIFT_R(glyphp[14][line],2); - bits |= SHIFT_L(glyphp[15][line],7); - bits |= SHIFT_L(glyphp[16][line],16); - bits |= SHIFT_L(glyphp[17][line],25); - WRITE_IN_BITORDER(base, 4, bits); - CHECKRETURN(5); - bits = SHIFT_R(glyphp[17][line],7); - bits |= SHIFT_L(glyphp[18][line],2); - bits |= SHIFT_L(glyphp[19][line],11); - bits |= SHIFT_L(glyphp[20][line],20); - bits |= SHIFT_L(glyphp[21][line],29); - WRITE_IN_BITORDER(base, 5, bits); - CHECKRETURN(6); - bits = SHIFT_R(glyphp[21][line],3); - bits |= SHIFT_L(glyphp[22][line],6); - bits |= SHIFT_L(glyphp[23][line],15); - bits |= SHIFT_L(glyphp[24][line],24); - WRITE_IN_BITORDER(base, 6, bits); - CHECKRETURN(7); - bits = SHIFT_R(glyphp[24][line],8); - bits |= SHIFT_L(glyphp[25][line],1); - bits |= SHIFT_L(glyphp[26][line],10); - bits |= SHIFT_L(glyphp[27][line],19); - bits |= SHIFT_L(glyphp[28][line],28); - WRITE_IN_BITORDER(base, 7, bits); - CHECKRETURN(8); - bits = SHIFT_R(glyphp[28][line],4); - bits |= SHIFT_L(glyphp[29][line],5); - bits |= SHIFT_L(glyphp[30][line],14); - bits |= SHIFT_L(glyphp[31][line],23); - WRITE_IN_BITORDER(base, 8, bits); - CHECKRETURN(9); -#ifndef FIXEDBASE - base += 9; -#endif - width -= 288; - glyphp += 32; - } - return base; -} -#endif - -static CARD32* -DrawTETextScanlineWidth10( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],10); - bits |= SHIFT_L(glyphp[2][line],20); - bits |= SHIFT_L(glyphp[3][line],30); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = SHIFT_R(glyphp[3][line],2); - bits |= SHIFT_L(glyphp[4][line],8); - bits |= SHIFT_L(glyphp[5][line],18); - bits |= SHIFT_L(glyphp[6][line],28); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); - bits = SHIFT_R(glyphp[6][line],4); - bits |= SHIFT_L(glyphp[7][line],6); - bits |= SHIFT_L(glyphp[8][line],16); - bits |= SHIFT_L(glyphp[9][line],26); - WRITE_IN_BITORDER(base, 2, bits); - CHECKRETURN(3); - bits = SHIFT_R(glyphp[9][line],6); - bits |= SHIFT_L(glyphp[10][line],4); - bits |= SHIFT_L(glyphp[11][line],14); - bits |= SHIFT_L(glyphp[12][line],24); - WRITE_IN_BITORDER(base, 3, bits); - CHECKRETURN(4); - bits = SHIFT_R(glyphp[12][line],8); - bits |= SHIFT_L(glyphp[13][line],2); - bits |= SHIFT_L(glyphp[14][line],12); - bits |= SHIFT_L(glyphp[15][line],22); - WRITE_IN_BITORDER(base, 4, bits); - CHECKRETURN(5); -#ifndef FIXEDBASE - base += 5; -#endif - width -= 160; - glyphp += 16; - } - return base; -} - -static CARD32* -DrawTETextScanlineWidth12( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],12); - bits |= SHIFT_L(glyphp[2][line],24); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = SHIFT_R(glyphp[2][line],8); - bits |= SHIFT_L(glyphp[3][line],4); - bits |= SHIFT_L(glyphp[4][line],16); - bits |= SHIFT_L(glyphp[5][line],28); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); - bits = SHIFT_R(glyphp[5][line],4); - bits |= SHIFT_L(glyphp[6][line],8); - bits |= SHIFT_L(glyphp[7][line],20); - WRITE_IN_BITORDER(base, 2, bits); - CHECKRETURN(3); -#ifndef FIXEDBASE - base += 3; -#endif - width -= 96; - glyphp += 8; - } - return base; -} - - - -static CARD32* -DrawTETextScanlineWidth14( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],14); - bits |= SHIFT_L(glyphp[2][line],28); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = SHIFT_R(glyphp[2][line],4); - bits |= SHIFT_L(glyphp[3][line],10); - bits |= SHIFT_L(glyphp[4][line],24); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); - bits = SHIFT_R(glyphp[4][line],8); - bits |= SHIFT_L(glyphp[5][line],6); - bits |= SHIFT_L(glyphp[6][line],20); - WRITE_IN_BITORDER(base, 2, bits); - CHECKRETURN(3); - bits = SHIFT_R(glyphp[6][line],12); - bits |= SHIFT_L(glyphp[7][line],2); - bits |= SHIFT_L(glyphp[8][line],16); - bits |= SHIFT_L(glyphp[9][line],30); - WRITE_IN_BITORDER(base, 3, bits); - CHECKRETURN(4); - bits = SHIFT_R(glyphp[9][line],2); - bits |= SHIFT_L(glyphp[10][line],12); - bits |= SHIFT_L(glyphp[11][line],26); - WRITE_IN_BITORDER(base, 4, bits); - CHECKRETURN(5); - bits = SHIFT_R(glyphp[11][line],6); - bits |= SHIFT_L(glyphp[12][line],8); - bits |= SHIFT_L(glyphp[13][line],22); - WRITE_IN_BITORDER(base, 5, bits); - CHECKRETURN(6); - bits = SHIFT_R(glyphp[13][line],10); - bits |= SHIFT_L(glyphp[14][line],4); - bits |= SHIFT_L(glyphp[15][line],18); - WRITE_IN_BITORDER(base, 6, bits); - CHECKRETURN(7); -#ifndef FIXEDBASE - base += 7; -#endif - width -= 224; - glyphp += 16; - } - return base; -} - - -static CARD32* -DrawTETextScanlineWidth16( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],16); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = glyphp[2][line]; - bits |= SHIFT_L(glyphp[3][line],16); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); - bits = glyphp[4][line]; - bits |= SHIFT_L(glyphp[5][line],16); - WRITE_IN_BITORDER(base, 2, bits); - CHECKRETURN(3); - bits = glyphp[6][line]; - bits |= SHIFT_L(glyphp[7][line],16); - WRITE_IN_BITORDER(base, 3, bits); - CHECKRETURN(4); -#ifndef FIXEDBASE - base += 4; -#endif - width -= 128; - glyphp += 8; - } - return base; -} - - - -static CARD32* -DrawTETextScanlineWidth18( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],18); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = SHIFT_R(glyphp[1][line],14); - bits |= SHIFT_L(glyphp[2][line],4); - bits |= SHIFT_L(glyphp[3][line],22); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); - bits = SHIFT_R(glyphp[3][line],10); - bits |= SHIFT_L(glyphp[4][line],8); - bits |= SHIFT_L(glyphp[5][line],26); - WRITE_IN_BITORDER(base, 2, bits); - CHECKRETURN(3); - bits = SHIFT_R(glyphp[5][line],6); - bits |= SHIFT_L(glyphp[6][line],12); - bits |= SHIFT_L(glyphp[7][line],30); - WRITE_IN_BITORDER(base, 3, bits); - CHECKRETURN(4); - bits = SHIFT_R(glyphp[7][line],2); - bits |= SHIFT_L(glyphp[8][line],16); - WRITE_IN_BITORDER(base, 4, bits); - CHECKRETURN(5); - bits = SHIFT_R(glyphp[8][line],16); - bits |= SHIFT_L(glyphp[9][line],2); - bits |= SHIFT_L(glyphp[10][line],20); - WRITE_IN_BITORDER(base, 5, bits); - CHECKRETURN(6); - bits = SHIFT_R(glyphp[10][line],12); - bits |= SHIFT_L(glyphp[11][line],6); - bits |= SHIFT_L(glyphp[12][line],24); - WRITE_IN_BITORDER(base, 6, bits); - CHECKRETURN(7); - bits = SHIFT_R(glyphp[12][line],8); - bits |= SHIFT_L(glyphp[13][line],10); - bits |= SHIFT_L(glyphp[14][line],28); - WRITE_IN_BITORDER(base, 7, bits); - CHECKRETURN(8); - bits = SHIFT_R(glyphp[14][line],4); - bits |= SHIFT_L(glyphp[15][line],14); - WRITE_IN_BITORDER(base, 8, bits); - CHECKRETURN(9); -#ifndef FIXEDBASE - base += 9; -#endif - width -= 288; - glyphp += 16; - } - return base; -} - - -static CARD32* -DrawTETextScanlineWidth24( - CARD32 *base, - unsigned int **glyphp, - int line, int width, int glyphwidth ) -{ - while (1) { - unsigned int bits; - bits = glyphp[0][line]; - bits |= SHIFT_L(glyphp[1][line],24); - WRITE_IN_BITORDER(base, 0, bits); - CHECKRETURN(1); - bits = SHIFT_R(glyphp[1][line],8); - bits |= SHIFT_L(glyphp[2][line],16); - WRITE_IN_BITORDER(base, 1, bits); - CHECKRETURN(2); - bits = SHIFT_R(glyphp[2][line],16); - bits |= SHIFT_L(glyphp[3][line],8); - WRITE_IN_BITORDER(base, 2, bits); - CHECKRETURN(3); -#ifndef FIXEDBASE - base += 3; -#endif - width -= 96; - glyphp += 4; - } - return base; -} - - + + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "xaa.h" +#include "xaalocal.h" +#include "xaacexp.h" +#include "xf86.h" + +/* scanline function for TRIPLE_BITS_24BPP */ +static CARD32 *DrawTextScanline3(CARD32 *base, CARD32 *mem, int width); + +/* Loop unrolled functions for common font widths */ +static CARD32 *DrawTETextScanlineGeneric(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +static CARD32 *DrawTETextScanlineWidth7(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +static CARD32 *DrawTETextScanlineWidth10(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +static CARD32 *DrawTETextScanlineWidth12(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +static CARD32 *DrawTETextScanlineWidth14(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +static CARD32 *DrawTETextScanlineWidth16(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +static CARD32 *DrawTETextScanlineWidth18(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +static CARD32 *DrawTETextScanlineWidth24(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); + + +#ifdef USEASSEMBLER +# ifdef FIXEDBASE +# ifdef MSBFIRST +CARD32 *DrawTETextScanlineWidth6PMSBFirstFixedBase(CARD32 *base, + unsigned int **glyphp, int line, int width, int glyphwidth); +CARD32 *DrawTETextScanlineWidth8PMSBFirstFixedBase(CARD32 *base, + unsigned int **glyphp, int line, int width, int glyphwidth); +CARD32 *DrawTETextScanlineWidth9PMSBFirstFixedBase(CARD32 *base, + unsigned int **glyphp, int line, int width, int glyphwidth); +# else +CARD32 *DrawTETextScanlineWidth6PLSBFirstFixedBase(CARD32 *base, + unsigned int **glyphp, int line, int width, int glyphwidth); +CARD32 *DrawTETextScanlineWidth8PLSBFirstFixedBase(CARD32 *base, + unsigned int **glyphp, int line, int width, int glyphwidth); +CARD32 *DrawTETextScanlineWidth9PLSBFirstFixedBase(CARD32 *base, + unsigned int **glyphp, int line, int width, int glyphwidth); +# endif +# else +# ifdef MSBFIRST +CARD32 *DrawTETextScanlineWidth6PMSBFirst(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +CARD32 *DrawTETextScanlineWidth8PMSBFirst(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +CARD32 *DrawTETextScanlineWidth9PMSBFirst(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +# else +CARD32 *DrawTETextScanlineWidth6PLSBFirst(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +CARD32 *DrawTETextScanlineWidth8PLSBFirst(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +CARD32 *DrawTETextScanlineWidth9PLSBFirst(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +# endif +# endif +#else +static CARD32 *DrawTETextScanlineWidth6(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +static CARD32 *DrawTETextScanlineWidth8(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +static CARD32 *DrawTETextScanlineWidth9(CARD32 *base, unsigned int **glyphp, + int line, int width, int glyphwidth); +#endif + +#define glyph_scanline_func EXPNAME(XAAGlyphScanlineFunc) +#define glyph_get_scanline_func EXPNAME(XAAGetGlyphScanlineFunc) + + +GlyphScanlineFuncPtr glyph_scanline_func[32] = { + DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, + DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, + DrawTETextScanlineGeneric, +#ifdef USEASSEMBLER +# ifdef FIXEDBASE +# ifdef MSBFIRST + DrawTETextScanlineWidth6PMSBFirstFixedBase, + DrawTETextScanlineWidth7, + DrawTETextScanlineWidth8PMSBFirstFixedBase, + DrawTETextScanlineWidth9PMSBFirstFixedBase, +# else + DrawTETextScanlineWidth6PLSBFirstFixedBase, + DrawTETextScanlineWidth7, + DrawTETextScanlineWidth8PLSBFirstFixedBase, + DrawTETextScanlineWidth9PLSBFirstFixedBase, +# endif +# else +# ifdef MSBFIRST + DrawTETextScanlineWidth6PMSBFirst, + DrawTETextScanlineWidth7, + DrawTETextScanlineWidth8PMSBFirst, + DrawTETextScanlineWidth9PMSBFirst, +# else + DrawTETextScanlineWidth6PLSBFirst, + DrawTETextScanlineWidth7, + DrawTETextScanlineWidth8PLSBFirst, + DrawTETextScanlineWidth9PLSBFirst, +# endif +# endif +#else + DrawTETextScanlineWidth6, DrawTETextScanlineWidth7, + DrawTETextScanlineWidth8, DrawTETextScanlineWidth9, +#endif + DrawTETextScanlineWidth10, + DrawTETextScanlineGeneric, DrawTETextScanlineWidth12, + DrawTETextScanlineGeneric, DrawTETextScanlineWidth14, + DrawTETextScanlineGeneric, DrawTETextScanlineWidth16, + DrawTETextScanlineGeneric, DrawTETextScanlineWidth18, + DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, + DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, + DrawTETextScanlineGeneric, DrawTETextScanlineWidth24, + DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, + DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, + DrawTETextScanlineGeneric, DrawTETextScanlineGeneric, + DrawTETextScanlineGeneric, DrawTETextScanlineGeneric +}; + +GlyphScanlineFuncPtr *glyph_get_scanline_func(void) { + return glyph_scanline_func; +} + + +/******************************************************************** + + Here we have TEGlyphRenders for a bunch of different color + expansion types. The driver may provide its own renderer, but + this is the default one which renders using lower-level primitives + exported by the chipset driver. + +********************************************************************/ + +/* This gets built for MSBFIRST or LSBFIRST with FIXEDBASE or not. + A total of 4 versions */ + +void +EXPNAME(XAATEGlyphRenderer)( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + CARD32* base; + GlyphScanlineFuncPtr GlyphFunc = glyph_scanline_func[glyphWidth - 1]; + int dwords = 0; + + if((bg != -1) && (infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { + (*infoRec->SetupForSolidFill)(pScrn, bg, rop, planemask); + (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); + bg = -1; + } + + (*infoRec->SetupForCPUToScreenColorExpandFill)( + pScrn, fg, bg, rop, planemask); + + if(skipleft && + (!(infoRec->TEGlyphRendererFlags & LEFT_EDGE_CLIPPING) || + (!(infoRec->TEGlyphRendererFlags & LEFT_EDGE_CLIPPING_NEGATIVE_X) && + (skipleft > x)))) { + /* draw the first character only */ + + int count = h, line = startline; + int width = glyphWidth - skipleft; + + if(width > w) width = w; + + (*infoRec->SubsequentCPUToScreenColorExpandFill)( + pScrn, x, y, width, h, 0); + + base = (CARD32*)infoRec->ColorExpandBase; + + while(count--) { + register CARD32 tmp = SHIFT_R(glyphs[0][line++],skipleft); + WRITE_BITS(tmp); + } + + w -= width; + if((infoRec->TEGlyphRendererFlags & CPU_TRANSFER_PAD_QWORD) && + ((((width + 31) >> 5) * h) & 1)) { + base = (CARD32*)infoRec->ColorExpandBase; + base[0] = 0x00000000; + } + if(!w) goto THE_END; + glyphs++; + x += width; + skipleft = 0; /* nicely aligned again */ + } + + w += skipleft; + x -= skipleft; + dwords = ((w + 31) >> 5) * h; + + (*infoRec->SubsequentCPUToScreenColorExpandFill)( + pScrn, x, y, w, h, skipleft); + + base = (CARD32*)infoRec->ColorExpandBase; + +#ifndef FIXEDBASE + if((((w + 31) >> 5) * h) <= infoRec->ColorExpandRange) + while(h--) { + base = (*GlyphFunc)(base, glyphs, startline++, w, glyphWidth); + } + else +#endif + while(h--) { + (*GlyphFunc)(base, glyphs, startline++, w, glyphWidth); + } + + if((infoRec->TEGlyphRendererFlags & CPU_TRANSFER_PAD_QWORD) && + (dwords & 1)) { + base = (CARD32*)infoRec->ColorExpandBase; + base[0] = 0x00000000; + } + +THE_END: + + if(infoRec->TEGlyphRendererFlags & SYNC_AFTER_COLOR_EXPAND) + (*infoRec->Sync)(pScrn); + else SET_SYNC_FLAG(infoRec); +} + +/******************************************************************** + + This is the GlyphRenderer for TRIPLE_BITS_24BPP. It renders to a buffer + with the non FIXEDBASE LSB_FIRST code before tripling, and possibly + reversing the bits and sending them to the screen + +********************************************************************/ + +void +EXPNAME(XAATEGlyphRenderer3)( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + CARD32 *base, *mem; + GlyphScanlineFuncPtr GlyphFunc = XAAGlyphScanlineFuncLSBFirst[glyphWidth - 1]; + int dwords = 0; + + if((bg != -1) && + ((infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY) || + ((infoRec->TEGlyphRendererFlags & RGB_EQUAL) && + (!CHECK_RGB_EQUAL(bg))))) { + (*infoRec->SetupForSolidFill)(pScrn, bg, rop, planemask); + (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); + bg = -1; + } + + (*infoRec->SetupForCPUToScreenColorExpandFill)( + pScrn, fg, bg, rop, planemask); + + if(skipleft) { + /* draw the first character only */ + + int count = h, line = startline; + int width = glyphWidth - skipleft; + CARD32 bits; + + if(width > w) width = w; + (*infoRec->SubsequentCPUToScreenColorExpandFill)( + pScrn, x, y, width, h, 0); + + base = (CARD32*)infoRec->ColorExpandBase; + + while(count--) { + bits = SHIFT_R(glyphs[0][line++],skipleft); + if (width >= 22) { + WRITE_BITS3(bits); + } else if (width >= 11) { + WRITE_BITS2(bits); + } else { + WRITE_BITS1(bits); + } + } + + w -= width; + if((infoRec->TEGlyphRendererFlags & CPU_TRANSFER_PAD_QWORD) && + ((((3 * width + 31) >> 5) * h) & 1)) { + base = (CARD32*)infoRec->ColorExpandBase; + base[0] = 0x00000000; + } + if(!w) goto THE_END; + glyphs++; + x += width; + skipleft = 0; /* nicely aligned again */ + } + + dwords = ((3 * w + 31) >> 5) * h; + mem = (CARD32*)malloc(((w + 31) >> 3) * sizeof(char)); + if (!mem) return; + + (*infoRec->SubsequentCPUToScreenColorExpandFill)(pScrn, x, y, w, h, 0); + + base = (CARD32*)infoRec->ColorExpandBase; + +# ifndef FIXEDBASE + if((((3 * w + 31) >> 5) * h) <= infoRec->ColorExpandRange) + while(h--) { + (*GlyphFunc)(mem, glyphs, startline++, w, glyphWidth); + base = DrawTextScanline3(base, mem, w); + } + else +# endif + while(h--) { + (*GlyphFunc)(mem, glyphs, startline++, w, glyphWidth); + DrawTextScanline3(base, mem, w); + } + + free(mem); + + if((infoRec->TEGlyphRendererFlags & CPU_TRANSFER_PAD_QWORD) && + (dwords & 1)) { + base = (CARD32*)infoRec->ColorExpandBase; + base[0] = 0x00000000; + } + +THE_END: + + if(infoRec->TEGlyphRendererFlags & SYNC_AFTER_COLOR_EXPAND) + (*infoRec->Sync)(pScrn); + else SET_SYNC_FLAG(infoRec); +} + + +#ifndef FIXEDBASE +/* Scanline version of above gets built for LSBFIRST and MSBFIRST */ + +void +EXPNAME(XAATEGlyphRendererScanline)( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + int bufferNo; + CARD32* base; + GlyphScanlineFuncPtr GlyphFunc = glyph_scanline_func[glyphWidth - 1]; + + if((bg != -1) && (infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY)) { + (*infoRec->SetupForSolidFill)(pScrn, bg, rop, planemask); + (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); + bg = -1; + } + + (*infoRec->SetupForScanlineCPUToScreenColorExpandFill)( + pScrn, fg, bg, rop, planemask); + + if(skipleft && + (!(infoRec->TEGlyphRendererFlags & LEFT_EDGE_CLIPPING) || + (!(infoRec->TEGlyphRendererFlags & LEFT_EDGE_CLIPPING_NEGATIVE_X) && + (skipleft > x)))) { + /* draw the first character only */ + + int count = h, line = startline; + int width = glyphWidth - skipleft; + + if(width > w) width = w; + + (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)( + pScrn, x, y, width, h, 0); + + bufferNo = 0; + + while(count--) { + register CARD32 tmp = SHIFT_R(glyphs[0][line++],skipleft); + base = (CARD32*)infoRec->ScanlineColorExpandBuffers[bufferNo]; + WRITE_BITS(tmp); + (*infoRec->SubsequentColorExpandScanline)(pScrn, bufferNo++); + if(bufferNo >= infoRec->NumScanlineColorExpandBuffers) + bufferNo = 0; + } + + w -= width; + if(!w) goto THE_END; + glyphs++; + x += width; + skipleft = 0; /* nicely aligned again */ + } + + w += skipleft; + x -= skipleft; + + (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)( + pScrn, x, y, w, h, skipleft); + + bufferNo = 0; + + while(h--) { + base = (CARD32*)infoRec->ScanlineColorExpandBuffers[bufferNo]; + (*GlyphFunc)(base, glyphs, startline++, w, glyphWidth); + (*infoRec->SubsequentColorExpandScanline)(pScrn, bufferNo++); + if(bufferNo >= infoRec->NumScanlineColorExpandBuffers) + bufferNo = 0; + } + +THE_END: + + SET_SYNC_FLAG(infoRec); +} + +void +EXPNAME(XAATEGlyphRendererScanline3)( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + int bufferNo; + CARD32 *base, *mem; + GlyphScanlineFuncPtr GlyphFunc = XAAGlyphScanlineFuncLSBFirst[glyphWidth - 1]; + + if((bg != -1) && + ((infoRec->TEGlyphRendererFlags & TRANSPARENCY_ONLY) || + ((infoRec->TEGlyphRendererFlags & RGB_EQUAL) && + (!CHECK_RGB_EQUAL(bg))))) { + (*infoRec->SetupForSolidFill)(pScrn, bg, rop, planemask); + (*infoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); + bg = -1; + } + + (*infoRec->SetupForScanlineCPUToScreenColorExpandFill)( + pScrn, fg, bg, rop, planemask); + + if(skipleft) { + /* draw the first character only */ + + int count = h, line = startline; + int width = glyphWidth - skipleft; + CARD32 bits; + + if(width > w) width = w; + + (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)( + pScrn, x, y, width, h, 0); + + bufferNo = 0; + + while(count--) { + base = (CARD32*)infoRec->ScanlineColorExpandBuffers[bufferNo]; + bits = SHIFT_R(glyphs[0][line++],skipleft); + if (width >= 22) { + WRITE_BITS3(bits); + } else if (width >= 11) { + WRITE_BITS2(bits); + } else { + WRITE_BITS1(bits); + } + (*infoRec->SubsequentColorExpandScanline)(pScrn, bufferNo++); + if(bufferNo >= infoRec->NumScanlineColorExpandBuffers) + bufferNo = 0; + } + + w -= width; + if(!w) goto THE_END; + glyphs++; + x += width; + skipleft = 0; /* nicely aligned again */ + } + + w += skipleft; + x -= skipleft; + mem = (CARD32*)malloc(((w + 31) >> 3) * sizeof(char)); + if (!mem) return; + + (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)( + pScrn, x, y, w, h, skipleft); + + bufferNo = 0; + + while(h--) { + base = (CARD32*)infoRec->ScanlineColorExpandBuffers[bufferNo]; + (*GlyphFunc)(mem, glyphs, startline++, w, glyphWidth); + DrawTextScanline3(base, mem, w); + (*infoRec->SubsequentColorExpandScanline)(pScrn, bufferNo++); + if(bufferNo >= infoRec->NumScanlineColorExpandBuffers) + bufferNo = 0; + } + + free(mem); + +THE_END: + + SET_SYNC_FLAG(infoRec); +} + +#endif + + + +/******************************************************************** + + TRIPLE_BITS_24BPP scanline rendering code. + +********************************************************************/ + + + +static CARD32* +DrawTextScanline3( + CARD32 *base, + CARD32 *mem, + int width ) +{ + + while(width > 32) { + WRITE_BITS3(*mem); + mem++; + width -= 32; + } + if(width) { + if (width >= 22) { + WRITE_BITS3(*mem); + } else if (width >= 11) { + WRITE_BITS2(*mem); + } else { + WRITE_BITS1(*mem); + } + } + + return base; +} + + +/******************************************************************** + + Generic TE scanline rendering code. + +********************************************************************/ + + + +static CARD32* +DrawTETextScanlineGeneric( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + CARD32 bits = (*glyphp)[line]; + int shift = glyphwidth; + + while(width > 32) { + while(shift < 32) { + glyphp++; + bits |= SHIFT_L((*glyphp)[line], shift); + shift += glyphwidth; + } + WRITE_BITS(bits); + shift &= 31; + if(shift) + bits = SHIFT_R((*glyphp)[line],(glyphwidth - shift)); + else bits = 0; + width -= 32; + } + + if(width) { + width -= shift; + while(width > 0) { + glyphp++; + bits |= SHIFT_L((*glyphp)[line],shift); + shift += glyphwidth; + width -= glyphwidth; + } + WRITE_BITS(bits); + } + + return base; +} + + +/******************************************************************** + + Loop unrolled TE font scanline rendering code + +********************************************************************/ + + +#ifndef USEASSEMBLER +static CARD32* +DrawTETextScanlineWidth6( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],6); + bits |= SHIFT_L(glyphp[2][line],12); + bits |= SHIFT_L(glyphp[3][line],18); + bits |= SHIFT_L(glyphp[4][line],24); + bits |= SHIFT_L(glyphp[5][line],30); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = SHIFT_R(glyphp[5][line],2); + bits |= SHIFT_L(glyphp[6][line],4); + bits |= SHIFT_L(glyphp[7][line],10); + bits |= SHIFT_L(glyphp[8][line],16); + bits |= SHIFT_L(glyphp[9][line],22); + bits |= SHIFT_L(glyphp[10][line],28); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); + bits = SHIFT_R(glyphp[10][line],4); + bits |= SHIFT_L(glyphp[11][line],2); + bits |= SHIFT_L(glyphp[12][line],8); + bits |= SHIFT_L(glyphp[13][line],14); + bits |= SHIFT_L(glyphp[14][line],20); + bits |= SHIFT_L(glyphp[15][line],26); + WRITE_IN_BITORDER(base, 2, bits); + CHECKRETURN(3); +#ifndef FIXEDBASE + base += 3; +#endif + width -= 96; + glyphp += 16; + } + return base; +} +#endif + +static CARD32* +DrawTETextScanlineWidth7( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],7); + bits |= SHIFT_L(glyphp[2][line],14); + bits |= SHIFT_L(glyphp[3][line],21); + bits |= SHIFT_L(glyphp[4][line],28); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = SHIFT_R(glyphp[4][line],4); + bits |= SHIFT_L(glyphp[5][line],3); + bits |= SHIFT_L(glyphp[6][line],10); + bits |= SHIFT_L(glyphp[7][line],17); + bits |= SHIFT_L(glyphp[8][line],24); + bits |= SHIFT_L(glyphp[9][line],31); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); + bits = SHIFT_R(glyphp[9][line],1); + bits |= SHIFT_L(glyphp[10][line],6); + bits |= SHIFT_L(glyphp[11][line],13); + bits |= SHIFT_L(glyphp[12][line],20); + bits |= SHIFT_L(glyphp[13][line],27); + WRITE_IN_BITORDER(base, 2, bits); + CHECKRETURN(3); + bits = SHIFT_R(glyphp[13][line],5); + bits |= SHIFT_L(glyphp[14][line],2); + bits |= SHIFT_L(glyphp[15][line],9); + bits |= SHIFT_L(glyphp[16][line],16); + bits |= SHIFT_L(glyphp[17][line],23); + bits |= SHIFT_L(glyphp[18][line],30); + WRITE_IN_BITORDER(base, 3, bits); + CHECKRETURN(4); + bits = SHIFT_R(glyphp[18][line],2); + bits |= SHIFT_L(glyphp[19][line],5); + bits |= SHIFT_L(glyphp[20][line],12); + bits |= SHIFT_L(glyphp[21][line],19); + bits |= SHIFT_L(glyphp[22][line],26); + WRITE_IN_BITORDER(base, 4, bits); + CHECKRETURN(5); + bits = SHIFT_R(glyphp[22][line],6); + bits |= SHIFT_L(glyphp[23][line],1); + bits |= SHIFT_L(glyphp[24][line],8); + bits |= SHIFT_L(glyphp[25][line],15); + bits |= SHIFT_L(glyphp[26][line],22); + bits |= SHIFT_L(glyphp[27][line],29); + WRITE_IN_BITORDER(base, 5, bits); + CHECKRETURN(6); + bits = SHIFT_R(glyphp[27][line],3); + bits |= SHIFT_L(glyphp[28][line],4); + bits |= SHIFT_L(glyphp[29][line],11); + bits |= SHIFT_L(glyphp[30][line],18); + bits |= SHIFT_L(glyphp[31][line],25); + WRITE_IN_BITORDER(base, 6, bits); + CHECKRETURN(7); +#ifndef FIXEDBASE + base += 7; +#endif + width -= 224; + glyphp += 32; + } + return base; +} + + +#ifndef USEASSEMBLER +static CARD32* +DrawTETextScanlineWidth8( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],8); + bits |= SHIFT_L(glyphp[2][line],16); + bits |= SHIFT_L(glyphp[3][line],24); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = glyphp[4][line]; + bits |= SHIFT_L(glyphp[5][line],8); + bits |= SHIFT_L(glyphp[6][line],16); + bits |= SHIFT_L(glyphp[7][line],24); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); +#ifndef FIXEDBASE + base += 2; +#endif + width -= 64; + glyphp += 8; + } + return base; +} +#endif + +#ifndef USEASSEMBLER +static CARD32* +DrawTETextScanlineWidth9( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],9); + bits |= SHIFT_L(glyphp[2][line],18); + bits |= SHIFT_L(glyphp[3][line],27); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = SHIFT_R(glyphp[3][line],5); + bits |= SHIFT_L(glyphp[4][line],4); + bits |= SHIFT_L(glyphp[5][line],13); + bits |= SHIFT_L(glyphp[6][line],22); + bits |= SHIFT_L(glyphp[7][line],31); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); + bits = SHIFT_R(glyphp[7][line],1); + bits |= SHIFT_L(glyphp[8][line],8); + bits |= SHIFT_L(glyphp[9][line],17); + bits |= SHIFT_L(glyphp[10][line],26); + WRITE_IN_BITORDER(base, 2, bits); + CHECKRETURN(3); + bits = SHIFT_R(glyphp[10][line],6); + bits |= SHIFT_L(glyphp[11][line],3); + bits |= SHIFT_L(glyphp[12][line],12); + bits |= SHIFT_L(glyphp[13][line],21); + bits |= SHIFT_L(glyphp[14][line],30); + WRITE_IN_BITORDER(base, 3, bits); + CHECKRETURN(4); + bits = SHIFT_R(glyphp[14][line],2); + bits |= SHIFT_L(glyphp[15][line],7); + bits |= SHIFT_L(glyphp[16][line],16); + bits |= SHIFT_L(glyphp[17][line],25); + WRITE_IN_BITORDER(base, 4, bits); + CHECKRETURN(5); + bits = SHIFT_R(glyphp[17][line],7); + bits |= SHIFT_L(glyphp[18][line],2); + bits |= SHIFT_L(glyphp[19][line],11); + bits |= SHIFT_L(glyphp[20][line],20); + bits |= SHIFT_L(glyphp[21][line],29); + WRITE_IN_BITORDER(base, 5, bits); + CHECKRETURN(6); + bits = SHIFT_R(glyphp[21][line],3); + bits |= SHIFT_L(glyphp[22][line],6); + bits |= SHIFT_L(glyphp[23][line],15); + bits |= SHIFT_L(glyphp[24][line],24); + WRITE_IN_BITORDER(base, 6, bits); + CHECKRETURN(7); + bits = SHIFT_R(glyphp[24][line],8); + bits |= SHIFT_L(glyphp[25][line],1); + bits |= SHIFT_L(glyphp[26][line],10); + bits |= SHIFT_L(glyphp[27][line],19); + bits |= SHIFT_L(glyphp[28][line],28); + WRITE_IN_BITORDER(base, 7, bits); + CHECKRETURN(8); + bits = SHIFT_R(glyphp[28][line],4); + bits |= SHIFT_L(glyphp[29][line],5); + bits |= SHIFT_L(glyphp[30][line],14); + bits |= SHIFT_L(glyphp[31][line],23); + WRITE_IN_BITORDER(base, 8, bits); + CHECKRETURN(9); +#ifndef FIXEDBASE + base += 9; +#endif + width -= 288; + glyphp += 32; + } + return base; +} +#endif + +static CARD32* +DrawTETextScanlineWidth10( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],10); + bits |= SHIFT_L(glyphp[2][line],20); + bits |= SHIFT_L(glyphp[3][line],30); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = SHIFT_R(glyphp[3][line],2); + bits |= SHIFT_L(glyphp[4][line],8); + bits |= SHIFT_L(glyphp[5][line],18); + bits |= SHIFT_L(glyphp[6][line],28); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); + bits = SHIFT_R(glyphp[6][line],4); + bits |= SHIFT_L(glyphp[7][line],6); + bits |= SHIFT_L(glyphp[8][line],16); + bits |= SHIFT_L(glyphp[9][line],26); + WRITE_IN_BITORDER(base, 2, bits); + CHECKRETURN(3); + bits = SHIFT_R(glyphp[9][line],6); + bits |= SHIFT_L(glyphp[10][line],4); + bits |= SHIFT_L(glyphp[11][line],14); + bits |= SHIFT_L(glyphp[12][line],24); + WRITE_IN_BITORDER(base, 3, bits); + CHECKRETURN(4); + bits = SHIFT_R(glyphp[12][line],8); + bits |= SHIFT_L(glyphp[13][line],2); + bits |= SHIFT_L(glyphp[14][line],12); + bits |= SHIFT_L(glyphp[15][line],22); + WRITE_IN_BITORDER(base, 4, bits); + CHECKRETURN(5); +#ifndef FIXEDBASE + base += 5; +#endif + width -= 160; + glyphp += 16; + } + return base; +} + +static CARD32* +DrawTETextScanlineWidth12( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],12); + bits |= SHIFT_L(glyphp[2][line],24); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = SHIFT_R(glyphp[2][line],8); + bits |= SHIFT_L(glyphp[3][line],4); + bits |= SHIFT_L(glyphp[4][line],16); + bits |= SHIFT_L(glyphp[5][line],28); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); + bits = SHIFT_R(glyphp[5][line],4); + bits |= SHIFT_L(glyphp[6][line],8); + bits |= SHIFT_L(glyphp[7][line],20); + WRITE_IN_BITORDER(base, 2, bits); + CHECKRETURN(3); +#ifndef FIXEDBASE + base += 3; +#endif + width -= 96; + glyphp += 8; + } + return base; +} + + + +static CARD32* +DrawTETextScanlineWidth14( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],14); + bits |= SHIFT_L(glyphp[2][line],28); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = SHIFT_R(glyphp[2][line],4); + bits |= SHIFT_L(glyphp[3][line],10); + bits |= SHIFT_L(glyphp[4][line],24); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); + bits = SHIFT_R(glyphp[4][line],8); + bits |= SHIFT_L(glyphp[5][line],6); + bits |= SHIFT_L(glyphp[6][line],20); + WRITE_IN_BITORDER(base, 2, bits); + CHECKRETURN(3); + bits = SHIFT_R(glyphp[6][line],12); + bits |= SHIFT_L(glyphp[7][line],2); + bits |= SHIFT_L(glyphp[8][line],16); + bits |= SHIFT_L(glyphp[9][line],30); + WRITE_IN_BITORDER(base, 3, bits); + CHECKRETURN(4); + bits = SHIFT_R(glyphp[9][line],2); + bits |= SHIFT_L(glyphp[10][line],12); + bits |= SHIFT_L(glyphp[11][line],26); + WRITE_IN_BITORDER(base, 4, bits); + CHECKRETURN(5); + bits = SHIFT_R(glyphp[11][line],6); + bits |= SHIFT_L(glyphp[12][line],8); + bits |= SHIFT_L(glyphp[13][line],22); + WRITE_IN_BITORDER(base, 5, bits); + CHECKRETURN(6); + bits = SHIFT_R(glyphp[13][line],10); + bits |= SHIFT_L(glyphp[14][line],4); + bits |= SHIFT_L(glyphp[15][line],18); + WRITE_IN_BITORDER(base, 6, bits); + CHECKRETURN(7); +#ifndef FIXEDBASE + base += 7; +#endif + width -= 224; + glyphp += 16; + } + return base; +} + + +static CARD32* +DrawTETextScanlineWidth16( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],16); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = glyphp[2][line]; + bits |= SHIFT_L(glyphp[3][line],16); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); + bits = glyphp[4][line]; + bits |= SHIFT_L(glyphp[5][line],16); + WRITE_IN_BITORDER(base, 2, bits); + CHECKRETURN(3); + bits = glyphp[6][line]; + bits |= SHIFT_L(glyphp[7][line],16); + WRITE_IN_BITORDER(base, 3, bits); + CHECKRETURN(4); +#ifndef FIXEDBASE + base += 4; +#endif + width -= 128; + glyphp += 8; + } + return base; +} + + + +static CARD32* +DrawTETextScanlineWidth18( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],18); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = SHIFT_R(glyphp[1][line],14); + bits |= SHIFT_L(glyphp[2][line],4); + bits |= SHIFT_L(glyphp[3][line],22); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); + bits = SHIFT_R(glyphp[3][line],10); + bits |= SHIFT_L(glyphp[4][line],8); + bits |= SHIFT_L(glyphp[5][line],26); + WRITE_IN_BITORDER(base, 2, bits); + CHECKRETURN(3); + bits = SHIFT_R(glyphp[5][line],6); + bits |= SHIFT_L(glyphp[6][line],12); + bits |= SHIFT_L(glyphp[7][line],30); + WRITE_IN_BITORDER(base, 3, bits); + CHECKRETURN(4); + bits = SHIFT_R(glyphp[7][line],2); + bits |= SHIFT_L(glyphp[8][line],16); + WRITE_IN_BITORDER(base, 4, bits); + CHECKRETURN(5); + bits = SHIFT_R(glyphp[8][line],16); + bits |= SHIFT_L(glyphp[9][line],2); + bits |= SHIFT_L(glyphp[10][line],20); + WRITE_IN_BITORDER(base, 5, bits); + CHECKRETURN(6); + bits = SHIFT_R(glyphp[10][line],12); + bits |= SHIFT_L(glyphp[11][line],6); + bits |= SHIFT_L(glyphp[12][line],24); + WRITE_IN_BITORDER(base, 6, bits); + CHECKRETURN(7); + bits = SHIFT_R(glyphp[12][line],8); + bits |= SHIFT_L(glyphp[13][line],10); + bits |= SHIFT_L(glyphp[14][line],28); + WRITE_IN_BITORDER(base, 7, bits); + CHECKRETURN(8); + bits = SHIFT_R(glyphp[14][line],4); + bits |= SHIFT_L(glyphp[15][line],14); + WRITE_IN_BITORDER(base, 8, bits); + CHECKRETURN(9); +#ifndef FIXEDBASE + base += 9; +#endif + width -= 288; + glyphp += 16; + } + return base; +} + + +static CARD32* +DrawTETextScanlineWidth24( + CARD32 *base, + unsigned int **glyphp, + int line, int width, int glyphwidth ) +{ + while (1) { + unsigned int bits; + bits = glyphp[0][line]; + bits |= SHIFT_L(glyphp[1][line],24); + WRITE_IN_BITORDER(base, 0, bits); + CHECKRETURN(1); + bits = SHIFT_R(glyphp[1][line],8); + bits |= SHIFT_L(glyphp[2][line],16); + WRITE_IN_BITORDER(base, 1, bits); + CHECKRETURN(2); + bits = SHIFT_R(glyphp[2][line],16); + bits |= SHIFT_L(glyphp[3][line],8); + WRITE_IN_BITORDER(base, 2, bits); + CHECKRETURN(3); +#ifndef FIXEDBASE + base += 3; +#endif + width -= 96; + glyphp += 4; + } + return base; +} + + diff --git a/xorg-server/hw/xfree86/xaa/xaaTEText.c b/xorg-server/hw/xfree86/xaa/xaaTEText.c index fc445726f..1e28d3103 100644 --- a/xorg-server/hw/xfree86/xaa/xaaTEText.c +++ b/xorg-server/hw/xfree86/xaa/xaaTEText.c @@ -1,312 +1,312 @@ - -/******************************************************************** - - In this file we have GC level replacements for PolyText8/16, - ImageText8/16, ImageGlyphBlt and PolyGlyphBlt for TE (fixed) fonts. - The idea is that everything in this file is device independent. - The mentioned GCOps are merely wrappers for XAAGlyphBltTEColorExpansion - which calculates the boxes containing arbitrarily clipped text - and passes them to the TEGlyphRenderer which will usually be a lower - level XAA function which renders these clipped glyphs using - the basic color expansion functions exported by the chipset driver. - The TEGlyphRenderer itself may optionally be driver supplied to - facilitate work-arounds/optimizations at a higher level than usual. - - v1.0 - Mark Vojkovich (mvojkovi@ucsd.edu) - - -********************************************************************/ - -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include "misc.h" -#include "xf86.h" -#include "xf86_OSproc.h" - -#include <X11/X.h> -#include <X11/fonts/font.h> -#include "scrnintstr.h" -#include "dixfontstr.h" -#include "xf86str.h" -#include "xaa.h" -#include "xaalocal.h" -#include "gcstruct.h" -#include "pixmapstr.h" - - -static void XAAGlyphBltTEColorExpansion(ScrnInfoPtr pScrn, int xInit, - int yInit, FontPtr font, int fg, int bg, int rop, - unsigned int planemask, RegionPtr cclip, int nglyph, - unsigned char* gBase, CharInfoPtr *ppci); - - -/******************************************************************** - - GC level replacements for PolyText8/16 and ImageText8/16 - for TE fonts when using color expansion. - -********************************************************************/ - - -int -XAAPolyText8TEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - unsigned long n; - - (*pGC->font->get_glyphs)(pGC->font, (unsigned long)count, - (unsigned char *)chars, Linear8Bit, &n, infoRec->CharInfo); - - /* we have divorced XAAGlyphBltTEColorExpansion from the drawable */ - if(n) XAAGlyphBltTEColorExpansion( - infoRec->pScrn, x + pDraw->x, y + pDraw->y, - pGC->font, pGC->fgPixel, -1, pGC->alu, pGC->planemask, - pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); - - return (x + (n * FONTMAXBOUNDS(pGC->font, characterWidth))); -} - - -int -XAAPolyText16TEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - unsigned long n; - - (*pGC->font->get_glyphs)( - pGC->font, (unsigned long)count, (unsigned char *)chars, - (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, - &n, infoRec->CharInfo); - - if(n) XAAGlyphBltTEColorExpansion( - infoRec->pScrn, x + pDraw->x, y + pDraw->y, - pGC->font, pGC->fgPixel, -1, pGC->alu, pGC->planemask, - pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); - - return (x + (n * FONTMAXBOUNDS(pGC->font, characterWidth))); -} - - -void -XAAImageText8TEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - unsigned long n; - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - (*pGC->font->get_glyphs)(pGC->font, (unsigned long)count, - (unsigned char *)chars, Linear8Bit, &n, infoRec->CharInfo); - - if(n) XAAGlyphBltTEColorExpansion( - infoRec->pScrn, x + pDraw->x, y + pDraw->y, - pGC->font, pGC->fgPixel, pGC->bgPixel, GXcopy, pGC->planemask, - pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); -} - - -void -XAAImageText16TEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - unsigned long n; - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - (*pGC->font->get_glyphs)( - pGC->font, (unsigned long)count, (unsigned char *)chars, - (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, - &n, infoRec->CharInfo); - - if(n) XAAGlyphBltTEColorExpansion( - infoRec->pScrn, x + pDraw->x, y + pDraw->y, - pGC->font, pGC->fgPixel, pGC->bgPixel, GXcopy, pGC->planemask, - pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); -} - - - -/******************************************************************** - - GC level replacements for ImageGlyphBlt and PolyGlyphBlt for - TE fonts when using color expansion. - -********************************************************************/ - - -void -XAAImageGlyphBltTEColorExpansion( - DrawablePtr pDrawable, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - XAAGlyphBltTEColorExpansion( - infoRec->pScrn, xInit + pDrawable->x, yInit + pDrawable->y, - pGC->font, pGC->fgPixel, pGC->bgPixel, GXcopy, pGC->planemask, - pGC->pCompositeClip, nglyph, (unsigned char*)pglyphBase, ppci); -} - -void -XAAPolyGlyphBltTEColorExpansion( - DrawablePtr pDrawable, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); - - if(!REGION_NUM_RECTS(pGC->pCompositeClip)) - return; - - XAAGlyphBltTEColorExpansion( - infoRec->pScrn, xInit + pDrawable->x, yInit + pDrawable->y, - pGC->font, pGC->fgPixel, -1, pGC->alu, pGC->planemask, - pGC->pCompositeClip, nglyph, (unsigned char*)pglyphBase, ppci); -} - - - - -/******************************************************************** - - XAAGlyphBltTEColorExpansion - - - This guy computes the clipped pieces of text and sends it to - the lower-level function which will handle acceleration of - arbitrarily clipped text. - -********************************************************************/ - - -static void -XAAGlyphBltTEColorExpansion( - ScrnInfoPtr pScrn, - int xInit, int yInit, - FontPtr font, - int fg, int bg, - int rop, - unsigned int planemask, - RegionPtr cclip, - int nglyph, - unsigned char* gBase, - CharInfoPtr *ppci ) -{ - XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); - int skippix, skipglyphs; - int Left, Right, Top, Bottom; - int LeftEdge, RightEdge, ytop, ybot; - int nbox = REGION_NUM_RECTS(cclip); - BoxPtr pbox = REGION_RECTS(cclip); - unsigned int **glyphs = NULL; - int glyphWidth = FONTMAXBOUNDS(font, characterWidth); - - /* find the size of the box */ - Left = xInit; - Right = Left + (glyphWidth * nglyph); - Top = yInit - FONTASCENT(font); - Bottom = yInit + FONTDESCENT(font); - - /* get into the first band that may contain part of our string */ - while(nbox && (Top >= pbox->y2)) { - pbox++; nbox--; - } - - /* stop when the lower edge of the box is beyond our string */ - while(nbox && (Bottom > pbox->y1)) { - LeftEdge = max(Left, pbox->x1); - RightEdge = min(Right, pbox->x2); - - if(RightEdge > LeftEdge) { /* we have something to draw */ - unsigned int *fallbackBits = NULL; - ytop = max(Top, pbox->y1); - ybot = min(Bottom, pbox->y2); - - if((skippix = LeftEdge - Left)) { - skipglyphs = skippix/glyphWidth; - skippix %= glyphWidth; - } else skipglyphs = 0; - - if(!glyphs) { - int count; - glyphs = (unsigned int**)(infoRec->PreAllocMem); - - for(count = 0; count < nglyph; count++) { - glyphs[count] = (unsigned int*) - FONTGLYPHBITS(gBase,*ppci++); - if (!glyphs[count]) { - /* Glyphs with NULL bits do exist in the wild. - Replace with blank bits in that case */ - - if (!fallbackBits) { - int fontHeight = Bottom - Top + 1; - fallbackBits = xcalloc (glyphWidth * fontHeight, 1); - if (!fallbackBits) - return; - } - glyphs[count] = fallbackBits; - } - } - - /* our new unrolled TE code only writes DWORDS at a time - so it can read up to 6 characters past the last one - we're displaying */ - glyphs[count + 0] = glyphs[0]; - glyphs[count + 1] = glyphs[0]; - glyphs[count + 2] = glyphs[0]; - glyphs[count + 3] = glyphs[0]; - glyphs[count + 4] = glyphs[0]; - glyphs[count + 5] = glyphs[0]; - } - - /* x, y, w, h, skipleft, skiptop, glyphp, glyphWidth, fg, bg, rop, pm */ - - (*infoRec->TEGlyphRenderer)( pScrn, - LeftEdge, ytop, RightEdge - LeftEdge, ybot - ytop, - skippix, ytop - Top, glyphs + skipglyphs, glyphWidth, - fg, bg, rop, planemask); - - if (fallbackBits) - xfree (fallbackBits); - } - - nbox--; pbox++; - } -} - - - - + +/******************************************************************** + + In this file we have GC level replacements for PolyText8/16, + ImageText8/16, ImageGlyphBlt and PolyGlyphBlt for TE (fixed) fonts. + The idea is that everything in this file is device independent. + The mentioned GCOps are merely wrappers for XAAGlyphBltTEColorExpansion + which calculates the boxes containing arbitrarily clipped text + and passes them to the TEGlyphRenderer which will usually be a lower + level XAA function which renders these clipped glyphs using + the basic color expansion functions exported by the chipset driver. + The TEGlyphRenderer itself may optionally be driver supplied to + facilitate work-arounds/optimizations at a higher level than usual. + + v1.0 - Mark Vojkovich (mvojkovi@ucsd.edu) + + +********************************************************************/ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include <X11/fonts/font.h> +#include "scrnintstr.h" +#include "dixfontstr.h" +#include "xf86str.h" +#include "xaa.h" +#include "xaalocal.h" +#include "gcstruct.h" +#include "pixmapstr.h" + + +static void XAAGlyphBltTEColorExpansion(ScrnInfoPtr pScrn, int xInit, + int yInit, FontPtr font, int fg, int bg, int rop, + unsigned int planemask, RegionPtr cclip, int nglyph, + unsigned char* gBase, CharInfoPtr *ppci); + + +/******************************************************************** + + GC level replacements for PolyText8/16 and ImageText8/16 + for TE fonts when using color expansion. + +********************************************************************/ + + +int +XAAPolyText8TEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + unsigned long n; + + (*pGC->font->get_glyphs)(pGC->font, (unsigned long)count, + (unsigned char *)chars, Linear8Bit, &n, infoRec->CharInfo); + + /* we have divorced XAAGlyphBltTEColorExpansion from the drawable */ + if(n) XAAGlyphBltTEColorExpansion( + infoRec->pScrn, x + pDraw->x, y + pDraw->y, + pGC->font, pGC->fgPixel, -1, pGC->alu, pGC->planemask, + pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); + + return (x + (n * FONTMAXBOUNDS(pGC->font, characterWidth))); +} + + +int +XAAPolyText16TEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + unsigned long n; + + (*pGC->font->get_glyphs)( + pGC->font, (unsigned long)count, (unsigned char *)chars, + (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, + &n, infoRec->CharInfo); + + if(n) XAAGlyphBltTEColorExpansion( + infoRec->pScrn, x + pDraw->x, y + pDraw->y, + pGC->font, pGC->fgPixel, -1, pGC->alu, pGC->planemask, + pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); + + return (x + (n * FONTMAXBOUNDS(pGC->font, characterWidth))); +} + + +void +XAAImageText8TEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + unsigned long n; + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + (*pGC->font->get_glyphs)(pGC->font, (unsigned long)count, + (unsigned char *)chars, Linear8Bit, &n, infoRec->CharInfo); + + if(n) XAAGlyphBltTEColorExpansion( + infoRec->pScrn, x + pDraw->x, y + pDraw->y, + pGC->font, pGC->fgPixel, pGC->bgPixel, GXcopy, pGC->planemask, + pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); +} + + +void +XAAImageText16TEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + unsigned long n; + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + (*pGC->font->get_glyphs)( + pGC->font, (unsigned long)count, (unsigned char *)chars, + (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, + &n, infoRec->CharInfo); + + if(n) XAAGlyphBltTEColorExpansion( + infoRec->pScrn, x + pDraw->x, y + pDraw->y, + pGC->font, pGC->fgPixel, pGC->bgPixel, GXcopy, pGC->planemask, + pGC->pCompositeClip, n, FONTGLYPHS(pGC->font), infoRec->CharInfo); +} + + + +/******************************************************************** + + GC level replacements for ImageGlyphBlt and PolyGlyphBlt for + TE fonts when using color expansion. + +********************************************************************/ + + +void +XAAImageGlyphBltTEColorExpansion( + DrawablePtr pDrawable, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + XAAGlyphBltTEColorExpansion( + infoRec->pScrn, xInit + pDrawable->x, yInit + pDrawable->y, + pGC->font, pGC->fgPixel, pGC->bgPixel, GXcopy, pGC->planemask, + pGC->pCompositeClip, nglyph, (unsigned char*)pglyphBase, ppci); +} + +void +XAAPolyGlyphBltTEColorExpansion( + DrawablePtr pDrawable, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + + if(!REGION_NUM_RECTS(pGC->pCompositeClip)) + return; + + XAAGlyphBltTEColorExpansion( + infoRec->pScrn, xInit + pDrawable->x, yInit + pDrawable->y, + pGC->font, pGC->fgPixel, -1, pGC->alu, pGC->planemask, + pGC->pCompositeClip, nglyph, (unsigned char*)pglyphBase, ppci); +} + + + + +/******************************************************************** + + XAAGlyphBltTEColorExpansion - + + This guy computes the clipped pieces of text and sends it to + the lower-level function which will handle acceleration of + arbitrarily clipped text. + +********************************************************************/ + + +static void +XAAGlyphBltTEColorExpansion( + ScrnInfoPtr pScrn, + int xInit, int yInit, + FontPtr font, + int fg, int bg, + int rop, + unsigned int planemask, + RegionPtr cclip, + int nglyph, + unsigned char* gBase, + CharInfoPtr *ppci ) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); + int skippix, skipglyphs; + int Left, Right, Top, Bottom; + int LeftEdge, RightEdge, ytop, ybot; + int nbox = REGION_NUM_RECTS(cclip); + BoxPtr pbox = REGION_RECTS(cclip); + unsigned int **glyphs = NULL; + int glyphWidth = FONTMAXBOUNDS(font, characterWidth); + + /* find the size of the box */ + Left = xInit; + Right = Left + (glyphWidth * nglyph); + Top = yInit - FONTASCENT(font); + Bottom = yInit + FONTDESCENT(font); + + /* get into the first band that may contain part of our string */ + while(nbox && (Top >= pbox->y2)) { + pbox++; nbox--; + } + + /* stop when the lower edge of the box is beyond our string */ + while(nbox && (Bottom > pbox->y1)) { + LeftEdge = max(Left, pbox->x1); + RightEdge = min(Right, pbox->x2); + + if(RightEdge > LeftEdge) { /* we have something to draw */ + unsigned int *fallbackBits = NULL; + ytop = max(Top, pbox->y1); + ybot = min(Bottom, pbox->y2); + + if((skippix = LeftEdge - Left)) { + skipglyphs = skippix/glyphWidth; + skippix %= glyphWidth; + } else skipglyphs = 0; + + if(!glyphs) { + int count; + glyphs = (unsigned int**)(infoRec->PreAllocMem); + + for(count = 0; count < nglyph; count++) { + glyphs[count] = (unsigned int*) + FONTGLYPHBITS(gBase,*ppci++); + if (!glyphs[count]) { + /* Glyphs with NULL bits do exist in the wild. + Replace with blank bits in that case */ + + if (!fallbackBits) { + int fontHeight = Bottom - Top + 1; + fallbackBits = calloc(glyphWidth * fontHeight, 1); + if (!fallbackBits) + return; + } + glyphs[count] = fallbackBits; + } + } + + /* our new unrolled TE code only writes DWORDS at a time + so it can read up to 6 characters past the last one + we're displaying */ + glyphs[count + 0] = glyphs[0]; + glyphs[count + 1] = glyphs[0]; + glyphs[count + 2] = glyphs[0]; + glyphs[count + 3] = glyphs[0]; + glyphs[count + 4] = glyphs[0]; + glyphs[count + 5] = glyphs[0]; + } + + /* x, y, w, h, skipleft, skiptop, glyphp, glyphWidth, fg, bg, rop, pm */ + + (*infoRec->TEGlyphRenderer)( pScrn, + LeftEdge, ytop, RightEdge - LeftEdge, ybot - ytop, + skippix, ytop - Top, glyphs + skipglyphs, glyphWidth, + fg, bg, rop, planemask); + + if (fallbackBits) + free(fallbackBits); + } + + nbox--; pbox++; + } +} + + + + diff --git a/xorg-server/hw/xfree86/xaa/xaaWrapper.c b/xorg-server/hw/xfree86/xaa/xaaWrapper.c index d6409887c..f709d0b35 100644 --- a/xorg-server/hw/xfree86/xaa/xaaWrapper.c +++ b/xorg-server/hw/xfree86/xaa/xaaWrapper.c @@ -1,474 +1,474 @@ -#ifdef HAVE_XORG_CONFIG_H -#include <xorg-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "scrnintstr.h" -#include "gcstruct.h" -#include "glyphstr.h" -#include "window.h" -#include "windowstr.h" -#include "picture.h" -#include "picturestr.h" -#include "colormapst.h" -#include "xaa.h" -#include "xaalocal.h" -#include "xaaWrapper.h" - -void XAASync(ScreenPtr pScreen); - -/* #include "render.h" */ - -#if 1 -#define COND(pDraw) \ - ((pDraw)->depth \ - != (xaaWrapperGetScrPriv(((DrawablePtr)(pDraw))->pScreen))->depth) -#else -#define COND(pDraw) 1 -#endif - -static Bool xaaWrapperCreateGC(GCPtr pGC); -static void xaaWrapperValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDraw); -static void xaaWrapperDestroyGC(GCPtr pGC); -static void xaaWrapperChangeGC (GCPtr pGC, unsigned long mask); -static void xaaWrapperCopyGC (GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); -static void xaaWrapperChangeClip (GCPtr pGC, int type, pointer pvalue, int nrects); - -static void xaaWrapperCopyClip(GCPtr pgcDst, GCPtr pgcSrc); -static void xaaWrapperDestroyClip(GCPtr pGC); - - -static void -xaaWrapperComposite (CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, - INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, - INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); -static void -xaaWrapperGlyphs (CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, - GlyphListPtr list, GlyphPtr *glyphs); - - -typedef struct { - CloseScreenProcPtr CloseScreen; - CreateScreenResourcesProcPtr CreateScreenResources; - CreateWindowProcPtr CreateWindow; - CopyWindowProcPtr CopyWindow; - WindowExposuresProcPtr WindowExposures; - CreateGCProcPtr CreateGC; - CreateColormapProcPtr CreateColormap; - DestroyColormapProcPtr DestroyColormap; - InstallColormapProcPtr InstallColormap; - UninstallColormapProcPtr UninstallColormap; - ListInstalledColormapsProcPtr ListInstalledColormaps; - StoreColorsProcPtr StoreColors; - CompositeProcPtr Composite; - GlyphsProcPtr Glyphs; - - CloseScreenProcPtr wrapCloseScreen; - CreateScreenResourcesProcPtr wrapCreateScreenResources; - CreateWindowProcPtr wrapCreateWindow; - CopyWindowProcPtr wrapCopyWindow; - WindowExposuresProcPtr wrapWindowExposures; - CreateGCProcPtr wrapCreateGC; - CreateColormapProcPtr wrapCreateColormap; - DestroyColormapProcPtr wrapDestroyColormap; - InstallColormapProcPtr wrapInstallColormap; - UninstallColormapProcPtr wrapUninstallColormap; - ListInstalledColormapsProcPtr wrapListInstalledColormaps; - StoreColorsProcPtr wrapStoreColors; - CompositeProcPtr wrapComposite; - GlyphsProcPtr wrapGlyphs; - int depth; -} xaaWrapperScrPrivRec, *xaaWrapperScrPrivPtr; - -#define xaaWrapperGetScrPriv(s) ((xaaWrapperScrPrivPtr) \ - dixLookupPrivate(&(s)->devPrivates, xaaWrapperScrPrivateKey)) -#define xaaWrapperScrPriv(s) xaaWrapperScrPrivPtr pScrPriv = xaaWrapperGetScrPriv(s) - -#define wrap(priv,real,mem,func) {\ - priv->mem = real->mem; \ - real->mem = func; \ -} - -#define unwrap(priv,real,mem) {\ - real->mem = priv->mem; \ -} - -#define cond_wrap(priv,cond,real,mem,wrapmem,func) {\ - if (COND(cond)) \ - priv->wrapmem = real->mem; \ - else \ - priv->mem = real->mem; \ - real->mem = func; \ -} - -#define cond_unwrap(priv,cond,real,mem,wrapmem) {\ - if (COND(cond)) \ - real->mem = priv->wrapmem; \ - else \ - real->mem = priv->mem; \ -} - -#define get(priv,real,func,wrap) \ - priv->wrap = real->func; - -typedef struct _xaaWrapperGCPriv { - GCOps *ops; - Bool wrap; - GCFuncs *funcs; - GCOps *wrapops; -} xaaWrapperGCPrivRec, *xaaWrapperGCPrivPtr; - -#define xaaWrapperGetGCPriv(pGC) ((xaaWrapperGCPrivPtr) \ - dixLookupPrivate(&(pGC)->devPrivates, xaaWrapperGCPrivateKey)) -#define xaaWrapperGCPriv(pGC) xaaWrapperGCPrivPtr pGCPriv = xaaWrapperGetGCPriv(pGC) - - -static int xaaWrapperScrPrivateKeyIndex; -static DevPrivateKey xaaWrapperScrPrivateKey = &xaaWrapperScrPrivateKeyIndex; -static int xaaWrapperGCPrivateKeyIndex; -static DevPrivateKey xaaWrapperGCPrivateKey = &xaaWrapperGCPrivateKeyIndex; - -static Bool -xaaWrapperCreateScreenResources(ScreenPtr pScreen) -{ - xaaWrapperScrPriv(pScreen); - Bool ret; - - unwrap (pScrPriv,pScreen, CreateScreenResources); - ret = pScreen->CreateScreenResources(pScreen); - wrap(pScrPriv,pScreen,CreateScreenResources,xaaWrapperCreateScreenResources); - return ret; -} - -static Bool -xaaWrapperCloseScreen (int iScreen, ScreenPtr pScreen) -{ - xaaWrapperScrPriv(pScreen); - Bool ret; - - unwrap (pScrPriv,pScreen, CloseScreen); - ret = pScreen->CloseScreen(iScreen,pScreen); - return TRUE; -} - -static Bool -xaaWrapperCreateWindow(WindowPtr pWin) -{ - xaaWrapperScrPriv(pWin->drawable.pScreen); - Bool ret; - - cond_unwrap(pScrPriv, &pWin->drawable, pWin->drawable.pScreen, - CreateWindow, wrapCreateWindow); - ret = pWin->drawable.pScreen->CreateWindow(pWin); - cond_wrap(pScrPriv, &pWin->drawable, pWin->drawable.pScreen, CreateWindow, - wrapCreateWindow, xaaWrapperCreateWindow); - - return ret; -} - -static void -xaaWrapperCopyWindow(WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - xaaWrapperScrPriv(pScreen); - - unwrap (pScrPriv, pScreen, CopyWindow); -#if 0 - if (COND(&pWin->drawable)) - pWin->drawable.pScreen->CopyWindow = pScrPriv->wrapCopyWindow; -#endif - pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc); - wrap(pScrPriv, pScreen, CopyWindow, xaaWrapperCopyWindow); -} - -static void -xaaWrapperWindowExposures (WindowPtr pWin, - RegionPtr prgn, - RegionPtr other_exposed) -{ - xaaWrapperScrPriv(pWin->drawable.pScreen); - - cond_unwrap(pScrPriv, &pWin->drawable, pWin->drawable.pScreen, - WindowExposures, wrapWindowExposures); - pWin->drawable.pScreen->WindowExposures(pWin, prgn, other_exposed); - cond_wrap(pScrPriv, &pWin->drawable, pWin->drawable.pScreen, - WindowExposures, wrapWindowExposures, xaaWrapperWindowExposures); -} - -static Bool -xaaWrapperCreateColormap(ColormapPtr pmap) -{ - xaaWrapperScrPriv(pmap->pScreen); - Bool ret; - unwrap(pScrPriv,pmap->pScreen, CreateColormap); - ret = pmap->pScreen->CreateColormap(pmap); - wrap(pScrPriv,pmap->pScreen,CreateColormap,xaaWrapperCreateColormap); - - return ret; -} - -static void -xaaWrapperDestroyColormap(ColormapPtr pmap) -{ - xaaWrapperScrPriv(pmap->pScreen); - unwrap(pScrPriv,pmap->pScreen, DestroyColormap); - pmap->pScreen->DestroyColormap(pmap); - wrap(pScrPriv,pmap->pScreen,DestroyColormap,xaaWrapperDestroyColormap); -} - -static void -xaaWrapperStoreColors(ColormapPtr pmap, int nColors, xColorItem *pColors) -{ - xaaWrapperScrPriv(pmap->pScreen); - unwrap(pScrPriv,pmap->pScreen, StoreColors); - pmap->pScreen->StoreColors(pmap,nColors,pColors); - wrap(pScrPriv,pmap->pScreen,StoreColors,xaaWrapperStoreColors); -} - -static void -xaaWrapperInstallColormap(ColormapPtr pmap) -{ - xaaWrapperScrPriv(pmap->pScreen); - - unwrap(pScrPriv,pmap->pScreen, InstallColormap); - pmap->pScreen->InstallColormap(pmap); - wrap(pScrPriv,pmap->pScreen,InstallColormap,xaaWrapperInstallColormap); -} - -static void -xaaWrapperUninstallColormap(ColormapPtr pmap) -{ - xaaWrapperScrPriv(pmap->pScreen); - - unwrap(pScrPriv,pmap->pScreen, UninstallColormap); - pmap->pScreen->UninstallColormap(pmap); - wrap(pScrPriv,pmap->pScreen,UninstallColormap,xaaWrapperUninstallColormap); -} - -static int -xaaWrapperListInstalledColormaps(ScreenPtr pScreen, Colormap *pCmapIds) -{ - int n; - xaaWrapperScrPriv(pScreen); - - unwrap(pScrPriv,pScreen, ListInstalledColormaps); - n = pScreen->ListInstalledColormaps(pScreen, pCmapIds); - wrap (pScrPriv,pScreen,ListInstalledColormaps,xaaWrapperListInstalledColormaps); - return n; -} - -Bool -xaaSetupWrapper(ScreenPtr pScreen, XAAInfoRecPtr infoPtr, int depth, SyncFunc *func) -{ - Bool ret; - xaaWrapperScrPrivPtr pScrPriv; - PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); - - if (!dixRequestPrivate(xaaWrapperGCPrivateKey, sizeof(xaaWrapperGCPrivRec))) - return FALSE; - - pScrPriv = (xaaWrapperScrPrivPtr) xalloc (sizeof (xaaWrapperScrPrivRec)); - if (!pScrPriv) - return FALSE; - - get (pScrPriv, pScreen, CloseScreen, wrapCloseScreen); - get (pScrPriv, pScreen, CreateScreenResources, wrapCreateScreenResources); - get (pScrPriv, pScreen, CreateWindow, wrapCreateWindow); - get (pScrPriv, pScreen, CopyWindow, wrapCopyWindow); - get (pScrPriv, pScreen, WindowExposures, wrapWindowExposures); - get (pScrPriv, pScreen, CreateGC, wrapCreateGC); - get (pScrPriv, pScreen, CreateColormap, wrapCreateColormap); - get (pScrPriv, pScreen, DestroyColormap, wrapDestroyColormap); - get (pScrPriv, pScreen, InstallColormap, wrapInstallColormap); - get (pScrPriv, pScreen, UninstallColormap, wrapUninstallColormap); - get (pScrPriv, pScreen, ListInstalledColormaps, wrapListInstalledColormaps); - get (pScrPriv, pScreen, StoreColors, wrapStoreColors); - if (ps) { - get (pScrPriv, ps, Glyphs, wrapGlyphs); - get (pScrPriv, ps, Composite, wrapComposite); - } - if (!(ret = XAAInit(pScreen,infoPtr))) - return FALSE; - - wrap (pScrPriv, pScreen, CloseScreen, xaaWrapperCloseScreen); - wrap (pScrPriv, pScreen, CreateScreenResources, - xaaWrapperCreateScreenResources); - wrap (pScrPriv, pScreen, CreateWindow, xaaWrapperCreateWindow); - wrap (pScrPriv, pScreen, CopyWindow, xaaWrapperCopyWindow); - wrap (pScrPriv, pScreen, WindowExposures, xaaWrapperWindowExposures); - wrap (pScrPriv, pScreen, CreateGC, xaaWrapperCreateGC); - wrap (pScrPriv, pScreen, CreateColormap, xaaWrapperCreateColormap); - wrap (pScrPriv, pScreen, DestroyColormap, xaaWrapperDestroyColormap); - wrap (pScrPriv, pScreen, InstallColormap, xaaWrapperInstallColormap); - wrap (pScrPriv, pScreen, UninstallColormap, xaaWrapperUninstallColormap); - wrap (pScrPriv, pScreen, ListInstalledColormaps, - xaaWrapperListInstalledColormaps); - wrap (pScrPriv, pScreen, StoreColors, xaaWrapperStoreColors); - - if (ps) { - wrap (pScrPriv, ps, Glyphs, xaaWrapperGlyphs); - wrap (pScrPriv, ps, Composite, xaaWrapperComposite); - } - pScrPriv->depth = depth; - dixSetPrivate(&pScreen->devPrivates, xaaWrapperScrPrivateKey, pScrPriv); - - *func = XAASync; - - return ret; -} - -GCFuncs xaaWrapperGCFuncs = { - xaaWrapperValidateGC, xaaWrapperChangeGC, xaaWrapperCopyGC, - xaaWrapperDestroyGC, xaaWrapperChangeClip, xaaWrapperDestroyClip, - xaaWrapperCopyClip -}; - -#define XAAWRAPPER_GC_FUNC_PROLOGUE(pGC) \ - xaaWrapperGCPriv(pGC); \ - unwrap(pGCPriv, pGC, funcs); \ - if (pGCPriv->wrap) unwrap(pGCPriv, pGC, ops) - -#define XAAWRAPPER_GC_FUNC_EPILOGUE(pGC) \ - wrap(pGCPriv, pGC, funcs, &xaaWrapperGCFuncs); \ - if (pGCPriv->wrap) wrap(pGCPriv, pGC, ops, pGCPriv->wrapops) - -static Bool -xaaWrapperCreateGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - xaaWrapperScrPriv(pScreen); - xaaWrapperGCPriv(pGC); - Bool ret; - - unwrap (pScrPriv, pScreen, CreateGC); - if((ret = (*pScreen->CreateGC) (pGC))) { - pGCPriv->wrap = FALSE; - pGCPriv->funcs = pGC->funcs; - pGCPriv->wrapops = pGC->ops; - pGC->funcs = &xaaWrapperGCFuncs; - } - wrap (pScrPriv, pScreen, CreateGC, xaaWrapperCreateGC); - - return ret; -} - -static void -xaaWrapperValidateGC( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -){ - XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); - - if(COND(pDraw)) - pGCPriv->wrap = TRUE; - - XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); -} - -static void -xaaWrapperDestroyGC(GCPtr pGC) -{ - XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->DestroyGC)(pGC); - XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); -} - -static void -xaaWrapperChangeGC ( - GCPtr pGC, - unsigned long mask -){ - XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ChangeGC) (pGC, mask); - XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); -} - -static void -xaaWrapperCopyGC ( - GCPtr pGCSrc, - unsigned long mask, - GCPtr pGCDst -){ - XAAWRAPPER_GC_FUNC_PROLOGUE (pGCDst); - (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); - XAAWRAPPER_GC_FUNC_EPILOGUE (pGCDst); -} - -static void -xaaWrapperChangeClip ( - GCPtr pGC, - int type, - pointer pvalue, - int nrects -){ - XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); - XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); -} - -static void -xaaWrapperCopyClip(GCPtr pgcDst, GCPtr pgcSrc) -{ - XAAWRAPPER_GC_FUNC_PROLOGUE (pgcDst); - (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); - XAAWRAPPER_GC_FUNC_EPILOGUE (pgcDst); -} - -static void -xaaWrapperDestroyClip(GCPtr pGC) -{ - XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); - (* pGC->funcs->DestroyClip)(pGC); - XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); -} - -static void -xaaWrapperComposite (CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, - INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, - INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - xaaWrapperScrPriv(pScreen); - - unwrap (pScrPriv, ps, Composite); - (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, - xDst, yDst, width, height); - wrap (pScrPriv, ps, Composite, xaaWrapperComposite); -} - - -static void -xaaWrapperGlyphs (CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, - GlyphListPtr list, GlyphPtr *glyphs) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - xaaWrapperScrPriv(pScreen); - - unwrap (pScrPriv, ps, Glyphs); - (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, - nlist, list, glyphs); - wrap (pScrPriv, ps, Glyphs, xaaWrapperGlyphs); - -} - -void -XAASync(ScreenPtr pScreen) -{ - XAAScreenPtr pScreenPriv = (XAAScreenPtr) - dixLookupPrivate(&pScreen->devPrivates, XAAGetScreenKey()); - XAAInfoRecPtr infoRec = pScreenPriv->AccelInfoRec; - - if(infoRec->NeedToSync) { - (*infoRec->Sync)(infoRec->pScrn); - infoRec->NeedToSync = FALSE; - } -} +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "gcstruct.h" +#include "glyphstr.h" +#include "window.h" +#include "windowstr.h" +#include "picture.h" +#include "picturestr.h" +#include "colormapst.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xaaWrapper.h" + +void XAASync(ScreenPtr pScreen); + +/* #include "render.h" */ + +#if 1 +#define COND(pDraw) \ + ((pDraw)->depth \ + != (xaaWrapperGetScrPriv(((DrawablePtr)(pDraw))->pScreen))->depth) +#else +#define COND(pDraw) 1 +#endif + +static Bool xaaWrapperCreateGC(GCPtr pGC); +static void xaaWrapperValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDraw); +static void xaaWrapperDestroyGC(GCPtr pGC); +static void xaaWrapperChangeGC (GCPtr pGC, unsigned long mask); +static void xaaWrapperCopyGC (GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void xaaWrapperChangeClip (GCPtr pGC, int type, pointer pvalue, int nrects); + +static void xaaWrapperCopyClip(GCPtr pgcDst, GCPtr pgcSrc); +static void xaaWrapperDestroyClip(GCPtr pGC); + + +static void +xaaWrapperComposite (CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); +static void +xaaWrapperGlyphs (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, + GlyphListPtr list, GlyphPtr *glyphs); + + +typedef struct { + CloseScreenProcPtr CloseScreen; + CreateScreenResourcesProcPtr CreateScreenResources; + CreateWindowProcPtr CreateWindow; + CopyWindowProcPtr CopyWindow; + WindowExposuresProcPtr WindowExposures; + CreateGCProcPtr CreateGC; + CreateColormapProcPtr CreateColormap; + DestroyColormapProcPtr DestroyColormap; + InstallColormapProcPtr InstallColormap; + UninstallColormapProcPtr UninstallColormap; + ListInstalledColormapsProcPtr ListInstalledColormaps; + StoreColorsProcPtr StoreColors; + CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; + + CloseScreenProcPtr wrapCloseScreen; + CreateScreenResourcesProcPtr wrapCreateScreenResources; + CreateWindowProcPtr wrapCreateWindow; + CopyWindowProcPtr wrapCopyWindow; + WindowExposuresProcPtr wrapWindowExposures; + CreateGCProcPtr wrapCreateGC; + CreateColormapProcPtr wrapCreateColormap; + DestroyColormapProcPtr wrapDestroyColormap; + InstallColormapProcPtr wrapInstallColormap; + UninstallColormapProcPtr wrapUninstallColormap; + ListInstalledColormapsProcPtr wrapListInstalledColormaps; + StoreColorsProcPtr wrapStoreColors; + CompositeProcPtr wrapComposite; + GlyphsProcPtr wrapGlyphs; + int depth; +} xaaWrapperScrPrivRec, *xaaWrapperScrPrivPtr; + +#define xaaWrapperGetScrPriv(s) ((xaaWrapperScrPrivPtr) \ + dixLookupPrivate(&(s)->devPrivates, xaaWrapperScrPrivateKey)) +#define xaaWrapperScrPriv(s) xaaWrapperScrPrivPtr pScrPriv = xaaWrapperGetScrPriv(s) + +#define wrap(priv,real,mem,func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define unwrap(priv,real,mem) {\ + real->mem = priv->mem; \ +} + +#define cond_wrap(priv,cond,real,mem,wrapmem,func) {\ + if (COND(cond)) \ + priv->wrapmem = real->mem; \ + else \ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define cond_unwrap(priv,cond,real,mem,wrapmem) {\ + if (COND(cond)) \ + real->mem = priv->wrapmem; \ + else \ + real->mem = priv->mem; \ +} + +#define get(priv,real,func,wrap) \ + priv->wrap = real->func; + +typedef struct _xaaWrapperGCPriv { + GCOps *ops; + Bool wrap; + GCFuncs *funcs; + GCOps *wrapops; +} xaaWrapperGCPrivRec, *xaaWrapperGCPrivPtr; + +#define xaaWrapperGetGCPriv(pGC) ((xaaWrapperGCPrivPtr) \ + dixLookupPrivate(&(pGC)->devPrivates, xaaWrapperGCPrivateKey)) +#define xaaWrapperGCPriv(pGC) xaaWrapperGCPrivPtr pGCPriv = xaaWrapperGetGCPriv(pGC) + + +static int xaaWrapperScrPrivateKeyIndex; +static DevPrivateKey xaaWrapperScrPrivateKey = &xaaWrapperScrPrivateKeyIndex; +static int xaaWrapperGCPrivateKeyIndex; +static DevPrivateKey xaaWrapperGCPrivateKey = &xaaWrapperGCPrivateKeyIndex; + +static Bool +xaaWrapperCreateScreenResources(ScreenPtr pScreen) +{ + xaaWrapperScrPriv(pScreen); + Bool ret; + + unwrap (pScrPriv,pScreen, CreateScreenResources); + ret = pScreen->CreateScreenResources(pScreen); + wrap(pScrPriv,pScreen,CreateScreenResources,xaaWrapperCreateScreenResources); + return ret; +} + +static Bool +xaaWrapperCloseScreen (int iScreen, ScreenPtr pScreen) +{ + xaaWrapperScrPriv(pScreen); + Bool ret; + + unwrap (pScrPriv,pScreen, CloseScreen); + ret = pScreen->CloseScreen(iScreen,pScreen); + return TRUE; +} + +static Bool +xaaWrapperCreateWindow(WindowPtr pWin) +{ + xaaWrapperScrPriv(pWin->drawable.pScreen); + Bool ret; + + cond_unwrap(pScrPriv, &pWin->drawable, pWin->drawable.pScreen, + CreateWindow, wrapCreateWindow); + ret = pWin->drawable.pScreen->CreateWindow(pWin); + cond_wrap(pScrPriv, &pWin->drawable, pWin->drawable.pScreen, CreateWindow, + wrapCreateWindow, xaaWrapperCreateWindow); + + return ret; +} + +static void +xaaWrapperCopyWindow(WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + xaaWrapperScrPriv(pScreen); + + unwrap (pScrPriv, pScreen, CopyWindow); +#if 0 + if (COND(&pWin->drawable)) + pWin->drawable.pScreen->CopyWindow = pScrPriv->wrapCopyWindow; +#endif + pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc); + wrap(pScrPriv, pScreen, CopyWindow, xaaWrapperCopyWindow); +} + +static void +xaaWrapperWindowExposures (WindowPtr pWin, + RegionPtr prgn, + RegionPtr other_exposed) +{ + xaaWrapperScrPriv(pWin->drawable.pScreen); + + cond_unwrap(pScrPriv, &pWin->drawable, pWin->drawable.pScreen, + WindowExposures, wrapWindowExposures); + pWin->drawable.pScreen->WindowExposures(pWin, prgn, other_exposed); + cond_wrap(pScrPriv, &pWin->drawable, pWin->drawable.pScreen, + WindowExposures, wrapWindowExposures, xaaWrapperWindowExposures); +} + +static Bool +xaaWrapperCreateColormap(ColormapPtr pmap) +{ + xaaWrapperScrPriv(pmap->pScreen); + Bool ret; + unwrap(pScrPriv,pmap->pScreen, CreateColormap); + ret = pmap->pScreen->CreateColormap(pmap); + wrap(pScrPriv,pmap->pScreen,CreateColormap,xaaWrapperCreateColormap); + + return ret; +} + +static void +xaaWrapperDestroyColormap(ColormapPtr pmap) +{ + xaaWrapperScrPriv(pmap->pScreen); + unwrap(pScrPriv,pmap->pScreen, DestroyColormap); + pmap->pScreen->DestroyColormap(pmap); + wrap(pScrPriv,pmap->pScreen,DestroyColormap,xaaWrapperDestroyColormap); +} + +static void +xaaWrapperStoreColors(ColormapPtr pmap, int nColors, xColorItem *pColors) +{ + xaaWrapperScrPriv(pmap->pScreen); + unwrap(pScrPriv,pmap->pScreen, StoreColors); + pmap->pScreen->StoreColors(pmap,nColors,pColors); + wrap(pScrPriv,pmap->pScreen,StoreColors,xaaWrapperStoreColors); +} + +static void +xaaWrapperInstallColormap(ColormapPtr pmap) +{ + xaaWrapperScrPriv(pmap->pScreen); + + unwrap(pScrPriv,pmap->pScreen, InstallColormap); + pmap->pScreen->InstallColormap(pmap); + wrap(pScrPriv,pmap->pScreen,InstallColormap,xaaWrapperInstallColormap); +} + +static void +xaaWrapperUninstallColormap(ColormapPtr pmap) +{ + xaaWrapperScrPriv(pmap->pScreen); + + unwrap(pScrPriv,pmap->pScreen, UninstallColormap); + pmap->pScreen->UninstallColormap(pmap); + wrap(pScrPriv,pmap->pScreen,UninstallColormap,xaaWrapperUninstallColormap); +} + +static int +xaaWrapperListInstalledColormaps(ScreenPtr pScreen, Colormap *pCmapIds) +{ + int n; + xaaWrapperScrPriv(pScreen); + + unwrap(pScrPriv,pScreen, ListInstalledColormaps); + n = pScreen->ListInstalledColormaps(pScreen, pCmapIds); + wrap (pScrPriv,pScreen,ListInstalledColormaps,xaaWrapperListInstalledColormaps); + return n; +} + +Bool +xaaSetupWrapper(ScreenPtr pScreen, XAAInfoRecPtr infoPtr, int depth, SyncFunc *func) +{ + Bool ret; + xaaWrapperScrPrivPtr pScrPriv; + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + + if (!dixRequestPrivate(xaaWrapperGCPrivateKey, sizeof(xaaWrapperGCPrivRec))) + return FALSE; + + pScrPriv = (xaaWrapperScrPrivPtr) malloc(sizeof (xaaWrapperScrPrivRec)); + if (!pScrPriv) + return FALSE; + + get (pScrPriv, pScreen, CloseScreen, wrapCloseScreen); + get (pScrPriv, pScreen, CreateScreenResources, wrapCreateScreenResources); + get (pScrPriv, pScreen, CreateWindow, wrapCreateWindow); + get (pScrPriv, pScreen, CopyWindow, wrapCopyWindow); + get (pScrPriv, pScreen, WindowExposures, wrapWindowExposures); + get (pScrPriv, pScreen, CreateGC, wrapCreateGC); + get (pScrPriv, pScreen, CreateColormap, wrapCreateColormap); + get (pScrPriv, pScreen, DestroyColormap, wrapDestroyColormap); + get (pScrPriv, pScreen, InstallColormap, wrapInstallColormap); + get (pScrPriv, pScreen, UninstallColormap, wrapUninstallColormap); + get (pScrPriv, pScreen, ListInstalledColormaps, wrapListInstalledColormaps); + get (pScrPriv, pScreen, StoreColors, wrapStoreColors); + if (ps) { + get (pScrPriv, ps, Glyphs, wrapGlyphs); + get (pScrPriv, ps, Composite, wrapComposite); + } + if (!(ret = XAAInit(pScreen,infoPtr))) + return FALSE; + + wrap (pScrPriv, pScreen, CloseScreen, xaaWrapperCloseScreen); + wrap (pScrPriv, pScreen, CreateScreenResources, + xaaWrapperCreateScreenResources); + wrap (pScrPriv, pScreen, CreateWindow, xaaWrapperCreateWindow); + wrap (pScrPriv, pScreen, CopyWindow, xaaWrapperCopyWindow); + wrap (pScrPriv, pScreen, WindowExposures, xaaWrapperWindowExposures); + wrap (pScrPriv, pScreen, CreateGC, xaaWrapperCreateGC); + wrap (pScrPriv, pScreen, CreateColormap, xaaWrapperCreateColormap); + wrap (pScrPriv, pScreen, DestroyColormap, xaaWrapperDestroyColormap); + wrap (pScrPriv, pScreen, InstallColormap, xaaWrapperInstallColormap); + wrap (pScrPriv, pScreen, UninstallColormap, xaaWrapperUninstallColormap); + wrap (pScrPriv, pScreen, ListInstalledColormaps, + xaaWrapperListInstalledColormaps); + wrap (pScrPriv, pScreen, StoreColors, xaaWrapperStoreColors); + + if (ps) { + wrap (pScrPriv, ps, Glyphs, xaaWrapperGlyphs); + wrap (pScrPriv, ps, Composite, xaaWrapperComposite); + } + pScrPriv->depth = depth; + dixSetPrivate(&pScreen->devPrivates, xaaWrapperScrPrivateKey, pScrPriv); + + *func = XAASync; + + return ret; +} + +GCFuncs xaaWrapperGCFuncs = { + xaaWrapperValidateGC, xaaWrapperChangeGC, xaaWrapperCopyGC, + xaaWrapperDestroyGC, xaaWrapperChangeClip, xaaWrapperDestroyClip, + xaaWrapperCopyClip +}; + +#define XAAWRAPPER_GC_FUNC_PROLOGUE(pGC) \ + xaaWrapperGCPriv(pGC); \ + unwrap(pGCPriv, pGC, funcs); \ + if (pGCPriv->wrap) unwrap(pGCPriv, pGC, ops) + +#define XAAWRAPPER_GC_FUNC_EPILOGUE(pGC) \ + wrap(pGCPriv, pGC, funcs, &xaaWrapperGCFuncs); \ + if (pGCPriv->wrap) wrap(pGCPriv, pGC, ops, pGCPriv->wrapops) + +static Bool +xaaWrapperCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + xaaWrapperScrPriv(pScreen); + xaaWrapperGCPriv(pGC); + Bool ret; + + unwrap (pScrPriv, pScreen, CreateGC); + if((ret = (*pScreen->CreateGC) (pGC))) { + pGCPriv->wrap = FALSE; + pGCPriv->funcs = pGC->funcs; + pGCPriv->wrapops = pGC->ops; + pGC->funcs = &xaaWrapperGCFuncs; + } + wrap (pScrPriv, pScreen, CreateGC, xaaWrapperCreateGC); + + return ret; +} + +static void +xaaWrapperValidateGC( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +){ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); + + if(COND(pDraw)) + pGCPriv->wrap = TRUE; + + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +static void +xaaWrapperDestroyGC(GCPtr pGC) +{ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->DestroyGC)(pGC); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +static void +xaaWrapperChangeGC ( + GCPtr pGC, + unsigned long mask +){ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeGC) (pGC, mask); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +static void +xaaWrapperCopyGC ( + GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst +){ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGCDst); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGCDst); +} + +static void +xaaWrapperChangeClip ( + GCPtr pGC, + int type, + pointer pvalue, + int nrects +){ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +static void +xaaWrapperCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + XAAWRAPPER_GC_FUNC_PROLOGUE (pgcDst); + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + XAAWRAPPER_GC_FUNC_EPILOGUE (pgcDst); +} + +static void +xaaWrapperDestroyClip(GCPtr pGC) +{ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (* pGC->funcs->DestroyClip)(pGC); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +static void +xaaWrapperComposite (CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + xaaWrapperScrPriv(pScreen); + + unwrap (pScrPriv, ps, Composite); + (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + wrap (pScrPriv, ps, Composite, xaaWrapperComposite); +} + + +static void +xaaWrapperGlyphs (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, + GlyphListPtr list, GlyphPtr *glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + xaaWrapperScrPriv(pScreen); + + unwrap (pScrPriv, ps, Glyphs); + (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, + nlist, list, glyphs); + wrap (pScrPriv, ps, Glyphs, xaaWrapperGlyphs); + +} + +void +XAASync(ScreenPtr pScreen) +{ + XAAScreenPtr pScreenPriv = (XAAScreenPtr) + dixLookupPrivate(&pScreen->devPrivates, XAAGetScreenKey()); + XAAInfoRecPtr infoRec = pScreenPriv->AccelInfoRec; + + if(infoRec->NeedToSync) { + (*infoRec->Sync)(infoRec->pScrn); + infoRec->NeedToSync = FALSE; + } +} diff --git a/xorg-server/hw/xfree86/xaa/xaalocal.h b/xorg-server/hw/xfree86/xaa/xaalocal.h index 129c1d6c4..6c492c013 100644 --- a/xorg-server/hw/xfree86/xaa/xaalocal.h +++ b/xorg-server/hw/xfree86/xaa/xaalocal.h @@ -1,1755 +1,1755 @@ - -#ifndef _XAALOCAL_H -#define _XAALOCAL_H - -/* This file is very unorganized ! */ - - -#include "gcstruct.h" -#include "regionstr.h" -#include "xf86fbman.h" -#include "xaa.h" -#include "mi.h" -#include "picturestr.h" - -#define GCWhenForced (GCArcMode << 1) - -#define DO_COLOR_8x8 0x00000001 -#define DO_MONO_8x8 0x00000002 -#define DO_CACHE_BLT 0x00000003 -#define DO_COLOR_EXPAND 0x00000004 -#define DO_CACHE_EXPAND 0x00000005 -#define DO_IMAGE_WRITE 0x00000006 -#define DO_PIXMAP_COPY 0x00000007 -#define DO_SOLID 0x00000008 - - -typedef CARD32 * (*GlyphScanlineFuncPtr)( - CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width -); - -typedef CARD32 *(*StippleScanlineProcPtr)(CARD32*, CARD32*, int, int, int); - -typedef void (*RectFuncPtr) (ScrnInfoPtr, int, int, int, int, int, int, - XAACacheInfoPtr); -typedef void (*TrapFuncPtr) (ScrnInfoPtr, int, int, int, int, int, int, - int, int, int, int, int, int, - XAACacheInfoPtr); - - - -typedef struct _XAAScreen { - CreateGCProcPtr CreateGC; - CloseScreenProcPtr CloseScreen; - GetImageProcPtr GetImage; - GetSpansProcPtr GetSpans; - CopyWindowProcPtr CopyWindow; - WindowExposuresProcPtr WindowExposures; - CreatePixmapProcPtr CreatePixmap; - DestroyPixmapProcPtr DestroyPixmap; - ChangeWindowAttributesProcPtr ChangeWindowAttributes; - XAAInfoRecPtr AccelInfoRec; - Bool (*EnterVT)(int, int); - void (*LeaveVT)(int, int); - int (*SetDGAMode)(int, int, DGADevicePtr); - void (*EnableDisableFBAccess)(int, Bool); - CompositeProcPtr Composite; - GlyphsProcPtr Glyphs; -} XAAScreenRec, *XAAScreenPtr; - -#define OPS_ARE_PIXMAP 0x00000001 -#define OPS_ARE_ACCEL 0x00000002 - -typedef struct _XAAGC { - GCOps *wrapOps; - GCFuncs *wrapFuncs; - GCOps *XAAOps; - int DashLength; - unsigned char* DashPattern; - unsigned long changes; - unsigned long flags; -} XAAGCRec, *XAAGCPtr; - -#define REDUCIBILITY_CHECKED 0x00000001 -#define REDUCIBLE_TO_8x8 0x00000002 -#define REDUCIBLE_TO_2_COLOR 0x00000004 -#define DIRTY 0x00010000 -#define OFFSCREEN 0x00020000 -#define DGA_PIXMAP 0x00040000 -#define SHARED_PIXMAP 0x00080000 -#define LOCKED_PIXMAP 0x00100000 - -#define REDUCIBILITY_MASK \ - (REDUCIBILITY_CHECKED | REDUCIBLE_TO_8x8 | REDUCIBLE_TO_2_COLOR) - -typedef struct _XAAPixmap { - unsigned long flags; - CARD32 pattern0; - CARD32 pattern1; - int fg; - int bg; - FBAreaPtr offscreenArea; - Bool freeData; -} XAAPixmapRec, *XAAPixmapPtr; - - -extern _X_EXPORT Bool -XAACreateGC( - GCPtr pGC -); - -extern _X_EXPORT Bool -XAAInitAccel( - ScreenPtr pScreen, - XAAInfoRecPtr infoRec -); - -extern _X_EXPORT RegionPtr -XAABitBlt( - DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GC *pGC, - int srcx, - int srcy, - int width, - int height, - int dstx, - int dsty, - void (*doBitBlt)(DrawablePtr, DrawablePtr, GCPtr, RegionPtr, DDXPointPtr), - unsigned long bitPlane -); - -extern _X_EXPORT void -XAAScreenToScreenBitBlt( - ScrnInfoPtr pScrn, - int nbox, - DDXPointPtr pptSrc, - BoxPtr pbox, - int xdir, - int ydir, - int alu, - unsigned int planemask -); - -extern _X_EXPORT void -XAADoBitBlt( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - RegionPtr prgnDst, - DDXPointPtr pptSrc -); - -extern _X_EXPORT void -XAADoImageWrite( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - RegionPtr prgnDst, - DDXPointPtr pptSrc -); - -extern _X_EXPORT void -XAADoImageRead( - DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - RegionPtr prgnDst, - DDXPointPtr pptSrc -); - -extern _X_EXPORT void -XAACopyWindow( - WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc -); - - -extern _X_EXPORT RegionPtr -XAACopyArea( - DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GC *pGC, - int srcx, - int srcy, - int width, - int height, - int dstx, - int dsty -); - -extern _X_EXPORT void -XAAValidateCopyArea( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -); - -extern _X_EXPORT void -XAAValidatePutImage( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -); - -extern _X_EXPORT void -XAAValidateCopyPlane( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -); - -extern _X_EXPORT void -XAAValidatePushPixels( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -); - -extern _X_EXPORT void -XAAValidateFillSpans( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -); - -extern _X_EXPORT void -XAAValidatePolyGlyphBlt( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -); - -extern _X_EXPORT void -XAAValidateImageGlyphBlt( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -); - -extern _X_EXPORT void -XAAValidatePolylines( - GCPtr pGC, - unsigned long changes, - DrawablePtr pDraw -); - - -extern _X_EXPORT RegionPtr -XAACopyPlaneColorExpansion( - DrawablePtr pSrc, - DrawablePtr pDst, - GCPtr pGC, - int srcx, - int srcy, - int width, - int height, - int dstx, - int dsty, - unsigned long bitPlane -); - - -extern _X_EXPORT void -XAAPushPixelsSolidColorExpansion( - GCPtr pGC, - PixmapPtr pBitMap, - DrawablePtr pDrawable, - int dx, - int dy, - int xOrg, - int yOrg -); - -extern _X_EXPORT void -XAAWriteBitmapColorExpandMSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapColorExpand3MSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapColorExpandMSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapColorExpand3MSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapColorExpandLSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapColorExpand3LSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapColorExpandLSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapColorExpand3LSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - - -extern _X_EXPORT void -XAAWriteBitmapScanlineColorExpandMSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapScanlineColorExpand3MSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapScanlineColorExpandMSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapScanlineColorExpand3MSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapScanlineColorExpandLSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapScanlineColorExpand3LSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapScanlineColorExpandLSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWriteBitmapScanlineColorExpand3LSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int skipleft, - int fg, int bg, - int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAWritePixmap ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int rop, - unsigned int planemask, - int transparency_color, - int bpp, int depth -); - -extern _X_EXPORT void -XAAWritePixmapScanline ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int rop, - unsigned int planemask, - int transparency_color, - int bpp, int depth -); - -typedef void (*ClipAndRenderRectsFunc)(GCPtr, int, BoxPtr, int, int); - - -extern _X_EXPORT void -XAAClipAndRenderRects( - GCPtr pGC, - ClipAndRenderRectsFunc func, - int nrectFill, - xRectangle *prectInit, - int xorg, int yorg -); - - -typedef void (*ClipAndRenderSpansFunc)(GCPtr, int, DDXPointPtr, int*, - int, int, int); - -extern _X_EXPORT void -XAAClipAndRenderSpans( - GCPtr pGC, - DDXPointPtr ppt, - int *pwidth, - int nspans, - int fSorted, - ClipAndRenderSpansFunc func, - int xorg, - int yorg -); - - -extern _X_EXPORT void -XAAFillSolidRects( - ScrnInfoPtr pScrn, - int fg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox -); - -extern _X_EXPORT void -XAAFillMono8x8PatternRects( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int pat0, int pat1, - int xorg, int yorg -); - -extern _X_EXPORT void -XAAFillMono8x8PatternRectsScreenOrigin( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int pat0, int pat1, - int xorg, int yorg -); - - -extern _X_EXPORT void -XAAFillColor8x8PatternRectsScreenOrigin( - ScrnInfoPtr pScrn, - int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorigin, int yorigin, - XAACacheInfoPtr pCache -); - -extern _X_EXPORT void -XAAFillColor8x8PatternRects( - ScrnInfoPtr pScrn, - int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorigin, int yorigin, - XAACacheInfoPtr pCache -); - -extern _X_EXPORT void -XAAFillCacheBltRects( - ScrnInfoPtr pScrn, - int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - XAACacheInfoPtr pCache -); - -extern _X_EXPORT void -XAAFillCacheExpandRects( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillImageWriteRects( - ScrnInfoPtr pScrn, - int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAPolyFillRect( - DrawablePtr pDraw, - GCPtr pGC, - int nrectFill, - xRectangle *prectInit -); - - -extern _X_EXPORT void -XAATEGlyphRendererMSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - -extern _X_EXPORT void -XAATEGlyphRenderer3MSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - -extern _X_EXPORT void -XAATEGlyphRendererMSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - -extern _X_EXPORT void -XAATEGlyphRenderer3MSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - -extern _X_EXPORT void -XAATEGlyphRendererLSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - - -extern _X_EXPORT void -XAATEGlyphRenderer3LSBFirstFixedBase ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - -extern _X_EXPORT void -XAATEGlyphRendererLSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - -extern _X_EXPORT void -XAATEGlyphRenderer3LSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - - -extern _X_EXPORT void -XAATEGlyphRendererScanlineMSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - -extern _X_EXPORT void -XAATEGlyphRendererScanline3MSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - -extern _X_EXPORT void -XAATEGlyphRendererScanlineLSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - -extern _X_EXPORT void -XAATEGlyphRendererScanline3LSBFirst ( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, int skipleft, int startline, - unsigned int **glyphs, int glyphWidth, - int fg, int bg, int rop, unsigned planemask -); - - -extern _X_EXPORT CARD32 *(*XAAGlyphScanlineFuncMSBFirstFixedBase[32])( - CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width -); - -extern _X_EXPORT CARD32 *(*XAAGlyphScanlineFuncMSBFirst[32])( - CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width -); - -extern _X_EXPORT CARD32 *(*XAAGlyphScanlineFuncLSBFirstFixedBase[32])( - CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width -); - -extern _X_EXPORT CARD32 *(*XAAGlyphScanlineFuncLSBFirst[32])( - CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width -); - -extern _X_EXPORT GlyphScanlineFuncPtr *XAAGetGlyphScanlineFuncMSBFirstFixedBase(void); -extern _X_EXPORT GlyphScanlineFuncPtr *XAAGetGlyphScanlineFuncMSBFirst(void); -extern _X_EXPORT GlyphScanlineFuncPtr *XAAGetGlyphScanlineFuncLSBFirstFixedBase(void); -extern _X_EXPORT GlyphScanlineFuncPtr *XAAGetGlyphScanlineFuncLSBFirst(void); - -extern _X_EXPORT void -XAAFillColorExpandRectsLSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandRects3LSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandRectsLSBFirstFixedBase( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandRects3LSBFirstFixedBase( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandRectsMSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandRects3MSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandRectsMSBFirstFixedBase( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandRects3MSBFirstFixedBase( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillScanlineColorExpandRectsLSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillScanlineColorExpandRects3LSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillScanlineColorExpandRectsMSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillScanlineColorExpandRects3MSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int nBox, - BoxPtr pBox, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandSpansLSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandSpans3LSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandSpansLSBFirstFixedBase( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandSpans3LSBFirstFixedBase( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandSpansMSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandSpans3MSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandSpansMSBFirstFixedBase( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillColorExpandSpans3MSBFirstFixedBase( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillScanlineColorExpandSpansLSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillScanlineColorExpandSpans3LSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAPutImage( - DrawablePtr pDraw, - GCPtr pGC, - int depth, - int x, - int y, - int w, - int h, - int leftPad, - int format, - char *pImage -); - -extern _X_EXPORT void -XAAFillScanlineColorExpandSpansMSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillScanlineColorExpandSpans3MSBFirst( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - - -extern _X_EXPORT CARD32 *(*XAAStippleScanlineFuncMSBFirstFixedBase[6])( - CARD32* base, CARD32* src, int offset, int width, int dwords -); - -extern _X_EXPORT CARD32 *(*XAAStippleScanlineFuncMSBFirst[6])( - CARD32* base, CARD32* src, int offset, int width, int dwords -); - -extern _X_EXPORT CARD32 *(*XAAStippleScanlineFuncLSBFirstFixedBase[6])( - CARD32* base, CARD32* src, int offset, int width, int dwords -); - -extern _X_EXPORT CARD32 *(*XAAStippleScanlineFuncLSBFirst[6])( - CARD32* base, CARD32* src, int offset, int width, int dwords -); - -extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFuncMSBFirstFixedBase(void); -extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFuncMSBFirst(void); -extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFuncLSBFirstFixedBase(void); -extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFuncLSBFirst(void); -extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFunc3MSBFirstFixedBase(void); -extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFunc3MSBFirst(void); -extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFunc3LSBFirstFixedBase(void); -extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFunc3LSBFirst(void); - -extern _X_EXPORT int -XAAPolyText8TEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars -); - -extern _X_EXPORT int -XAAPolyText16TEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars -); - -extern _X_EXPORT void -XAAImageText8TEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars -); - -extern _X_EXPORT void -XAAImageText16TEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars -); - -extern _X_EXPORT void -XAAImageGlyphBltTEColorExpansion( - DrawablePtr pDrawable, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -); - -extern _X_EXPORT void -XAAPolyGlyphBltTEColorExpansion( - DrawablePtr pDrawable, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -); - - -extern _X_EXPORT int -XAAPolyText8NonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars -); - -extern _X_EXPORT int -XAAPolyText16NonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars -); - -extern _X_EXPORT void -XAAImageText8NonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - char *chars -); - -extern _X_EXPORT void -XAAImageText16NonTEColorExpansion( - DrawablePtr pDraw, - GCPtr pGC, - int x, int y, - int count, - unsigned short *chars -); - -extern _X_EXPORT void -XAAImageGlyphBltNonTEColorExpansion( - DrawablePtr pDrawable, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -); - -extern _X_EXPORT void -XAAPolyGlyphBltNonTEColorExpansion( - DrawablePtr pDrawable, - GCPtr pGC, - int xInit, int yInit, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase -); - - -extern _X_EXPORT void XAANonTEGlyphRenderer( - ScrnInfoPtr pScrn, - int x, int y, int n, - NonTEGlyphPtr glyphs, - BoxPtr pbox, - int fg, int rop, - unsigned int planemask -); - -extern _X_EXPORT void -XAAFillSolidSpans( - ScrnInfoPtr pScrn, - int fg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, int fSorted -); - -extern _X_EXPORT void -XAAFillMono8x8PatternSpans( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, int fSorted, - int patx, int paty, - int xorg, int yorg -); - -extern _X_EXPORT void -XAAFillMono8x8PatternSpansScreenOrigin( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, int fSorted, - int patx, int paty, - int xorg, int yorg -); - -extern _X_EXPORT void -XAAFillColor8x8PatternSpansScreenOrigin( - ScrnInfoPtr pScrn, - int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, int fSorted, - XAACacheInfoPtr, - int xorigin, int yorigin -); - -extern _X_EXPORT void -XAAFillColor8x8PatternSpans( - ScrnInfoPtr pScrn, - int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, int fSorted, - XAACacheInfoPtr, - int xorigin, int yorigin -); - -extern _X_EXPORT void -XAAFillCacheBltSpans( - ScrnInfoPtr pScrn, - int rop, - unsigned int planemask, - int n, - DDXPointPtr points, - int *widths, - int fSorted, - XAACacheInfoPtr pCache, - int xorg, int yorg -); - -extern _X_EXPORT void -XAAFillCacheExpandSpans( - ScrnInfoPtr pScrn, - int fg, int bg, int rop, - unsigned int planemask, - int n, - DDXPointPtr ppt, - int *pwidth, - int fSorted, - int xorg, int yorg, - PixmapPtr pPix -); - -extern _X_EXPORT void -XAAFillSpans( - DrawablePtr pDrawable, - GC *pGC, - int nInit, - DDXPointPtr pptInit, - int *pwidth, - int fSorted -); - - -extern _X_EXPORT void -XAAInitPixmapCache( - ScreenPtr pScreen, - RegionPtr areas, - pointer data -); - -extern _X_EXPORT void -XAAWriteBitmapToCache( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int fg, int bg -); - -extern _X_EXPORT void -XAAWriteBitmapToCacheLinear( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int fg, int bg -); - -extern _X_EXPORT void -XAAWritePixmapToCache( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int bpp, int depth -); - -extern _X_EXPORT void -XAAWritePixmapToCacheLinear( - ScrnInfoPtr pScrn, - int x, int y, int w, int h, - unsigned char *src, - int srcwidth, - int bpp, int depth -); - -extern _X_EXPORT void -XAASolidHorVertLineAsRects( - ScrnInfoPtr pScrn, - int x, int y, int len, int dir -); - -extern _X_EXPORT void -XAASolidHorVertLineAsTwoPoint( - ScrnInfoPtr pScrn, - int x, int y, int len, int dir -); - -extern _X_EXPORT void -XAASolidHorVertLineAsBresenham( - ScrnInfoPtr pScrn, - int x, int y, int len, int dir -); - - -extern _X_EXPORT void -XAAPolyRectangleThinSolid( - DrawablePtr pDrawable, - GCPtr pGC, - int nRectsInit, - xRectangle *pRectsInit -); - - -extern _X_EXPORT void -XAAPolylinesWideSolid ( - DrawablePtr pDrawable, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr pPts -); - -extern _X_EXPORT void -XAAFillPolygonSolid( - DrawablePtr pDrawable, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr ptsIn -); - -extern _X_EXPORT void -XAAFillPolygonStippled( - DrawablePtr pDrawable, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr ptsIn -); - - -extern _X_EXPORT void -XAAFillPolygonTiled( - DrawablePtr pDrawable, - GCPtr pGC, - int shape, - int mode, - int count, - DDXPointPtr ptsIn -); - - -extern _X_EXPORT int -XAAIsEasyPolygon( - DDXPointPtr ptsIn, - int count, - BoxPtr extents, - int origin, - DDXPointPtr *topPoint, - int *topY, int *bottomY, - int shape -); - -extern _X_EXPORT void -XAAFillPolygonHelper( - ScrnInfoPtr pScrn, - DDXPointPtr ptsIn, - int count, - DDXPointPtr topPoint, - int y, - int maxy, - int origin, - RectFuncPtr RectFunc, - TrapFuncPtr TrapFunc, - int xorg, - int yorg, - XAACacheInfoPtr pCache -); - -extern _X_EXPORT void -XAAPolySegment( - DrawablePtr pDrawable, - GCPtr pGC, - int nseg, - xSegment *pSeg -); - -extern _X_EXPORT void -XAAPolyLines( - DrawablePtr pDrawable, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr pptInit -); - -extern _X_EXPORT void -XAAPolySegmentDashed( - DrawablePtr pDrawable, - GCPtr pGC, - int nseg, - xSegment *pSeg -); - -extern _X_EXPORT void -XAAPolyLinesDashed( - DrawablePtr pDrawable, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr pptInit -); - - -extern _X_EXPORT void -XAAWriteMono8x8PatternToCache(ScrnInfoPtr pScrn, XAACacheInfoPtr pCache); - -extern _X_EXPORT void -XAAWriteColor8x8PatternToCache( - ScrnInfoPtr pScrn, - PixmapPtr pPix, - XAACacheInfoPtr pCache -); - -extern _X_EXPORT void -XAARotateMonoPattern( - int *pat0, int *pat1, - int xoffset, int yoffset, - Bool msbfirst -); - -extern _X_EXPORT void XAAComputeDash(GCPtr pGC); - -extern _X_EXPORT void XAAMoveDWORDS_FixedBase( - register CARD32* dest, - register CARD32* src, - register int dwords -); - -extern _X_EXPORT void XAAMoveDWORDS_FixedSrc( - register CARD32* dest, - register CARD32* src, - register int dwords -); - -extern _X_EXPORT void XAAMoveDWORDS( - register CARD32* dest, - register CARD32* src, - register int dwords -); - -extern _X_EXPORT int -XAAGetRectClipBoxes( - GCPtr pGC, - BoxPtr pboxClippedBase, - int nrectFill, - xRectangle *prectInit -); - -extern _X_EXPORT void -XAASetupOverlay8_32Planar(ScreenPtr); - -extern _X_EXPORT void -XAAPolyFillArcSolid(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs); - -extern _X_EXPORT XAACacheInfoPtr -XAACacheTile(ScrnInfoPtr Scrn, PixmapPtr pPix); - -extern _X_EXPORT XAACacheInfoPtr -XAACacheMonoStipple(ScrnInfoPtr Scrn, PixmapPtr pPix); - -extern _X_EXPORT XAACacheInfoPtr -XAACachePlanarMonoStipple(ScrnInfoPtr Scrn, PixmapPtr pPix); - -typedef XAACacheInfoPtr (*XAACachePlanarMonoStippleProc)(ScrnInfoPtr, PixmapPtr); -extern _X_EXPORT XAACachePlanarMonoStippleProc XAAGetCachePlanarMonoStipple(void); - -extern _X_EXPORT XAACacheInfoPtr -XAACacheStipple(ScrnInfoPtr Scrn, PixmapPtr pPix, int fg, int bg); - -extern _X_EXPORT XAACacheInfoPtr -XAACacheMono8x8Pattern(ScrnInfoPtr Scrn, int pat0, int pat1); - -extern _X_EXPORT XAACacheInfoPtr -XAACacheColor8x8Pattern(ScrnInfoPtr Scrn, PixmapPtr pPix, int fg, int bg); - -extern _X_EXPORT void -XAATileCache(ScrnInfoPtr pScrn, XAACacheInfoPtr pCache, int w, int h); - -extern _X_EXPORT void XAAClosePixmapCache(ScreenPtr pScreen); -void XAAInvalidatePixmapCache(ScreenPtr pScreen); - -extern _X_EXPORT Bool XAACheckStippleReducibility(PixmapPtr pPixmap); -extern _X_EXPORT Bool XAACheckTileReducibility(PixmapPtr pPixmap, Bool checkMono); - -extern _X_EXPORT int XAAStippledFillChooser(GCPtr pGC); -extern _X_EXPORT int XAAOpaqueStippledFillChooser(GCPtr pGC); -extern _X_EXPORT int XAATiledFillChooser(GCPtr pGC); - -extern _X_EXPORT void XAAMoveInOffscreenPixmaps(ScreenPtr pScreen); -extern _X_EXPORT void XAAMoveOutOffscreenPixmaps(ScreenPtr pScreen); -extern _X_EXPORT void XAARemoveAreaCallback(FBAreaPtr area); -extern _X_EXPORT void XAAMoveOutOffscreenPixmap(PixmapPtr pPix); -extern _X_EXPORT Bool XAAInitStateWrap(ScreenPtr pScreen, XAAInfoRecPtr infoRec); - -extern _X_EXPORT void -XAAComposite (CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height); - - -extern _X_EXPORT Bool -XAADoComposite (CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height); - - -extern _X_EXPORT void -XAAGlyphs (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int nlist, - GlyphListPtr list, - GlyphPtr *glyphs); - -extern _X_EXPORT Bool -XAADoGlyphs (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int nlist, - GlyphListPtr list, - GlyphPtr *glyphs); - - - -/* helpers */ -extern _X_EXPORT void -XAA_888_plus_PICT_a8_to_8888 ( - CARD32 color, - CARD8 *alphaPtr, /* in bytes */ - int alphaPitch, - CARD32 *dstPtr, - int dstPitch, /* in dwords */ - int width, - int height -); - -extern _X_EXPORT Bool -XAAGetRGBAFromPixel( - CARD32 pixel, - CARD16 *red, - CARD16 *green, - CARD16 *blue, - CARD16 *alpha, - CARD32 format -); - - -extern _X_EXPORT Bool -XAAGetPixelFromRGBA ( - CARD32 *pixel, - CARD16 red, - CARD16 green, - CARD16 blue, - CARD16 alpha, - CARD32 format -); - -/* XXX should be static */ -extern _X_EXPORT GCOps XAAFallbackOps; -extern _X_EXPORT GCOps *XAAGetFallbackOps(void); -extern _X_EXPORT GCFuncs XAAGCFuncs; -extern _X_EXPORT DevPrivateKey XAAGetScreenKey(void); -extern _X_EXPORT DevPrivateKey XAAGetGCKey(void); -extern _X_EXPORT DevPrivateKey XAAGetPixmapKey(void); - -extern _X_EXPORT unsigned int XAAShiftMasks[32]; - -extern _X_EXPORT unsigned int byte_expand3[256], byte_reversed_expand3[256]; - -extern _X_EXPORT CARD32 XAAReverseBitOrder(CARD32 data); - -#define GET_XAASCREENPTR_FROM_SCREEN(pScreen)\ - dixLookupPrivate(&(pScreen)->devPrivates, XAAGetScreenKey()) - -#define GET_XAASCREENPTR_FROM_GC(pGC)\ - dixLookupPrivate(&(pGC)->pScreen->devPrivates, XAAGetScreenKey()) - -#define GET_XAASCREENPTR_FROM_DRAWABLE(pDraw)\ - dixLookupPrivate(&(pDraw)->pScreen->devPrivates, XAAGetScreenKey()) - -#define GET_XAAINFORECPTR_FROM_SCREEN(pScreen)\ -((XAAScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, XAAGetScreenKey()))->AccelInfoRec - -#define GET_XAAINFORECPTR_FROM_GC(pGC)\ -((XAAScreenPtr)dixLookupPrivate(&(pGC)->pScreen->devPrivates, XAAGetScreenKey()))->AccelInfoRec - -#define GET_XAAINFORECPTR_FROM_DRAWABLE(pDraw)\ -((XAAScreenPtr)dixLookupPrivate(&(pDraw)->pScreen->devPrivates, XAAGetScreenKey()))->AccelInfoRec - -#define GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn)\ -((XAAScreenPtr)dixLookupPrivate(&(pScrn)->pScreen->devPrivates, XAAGetScreenKey()))->AccelInfoRec - -#define XAA_GET_PIXMAP_PRIVATE(pix)\ - (XAAPixmapPtr)dixLookupPrivate(&(pix)->devPrivates, XAAGetPixmapKey()) - -#define CHECK_RGB_EQUAL(c) (!((((c) >> 8) ^ (c)) & 0xffff)) - -#define CHECK_FG(pGC, flags) \ - (!(flags & RGB_EQUAL) || CHECK_RGB_EQUAL(pGC->fgPixel)) - -#define CHECK_BG(pGC, flags) \ - (!(flags & RGB_EQUAL) || CHECK_RGB_EQUAL(pGC->bgPixel)) - -#define CHECK_ROP(pGC, flags) \ - (!(flags & GXCOPY_ONLY) || (pGC->alu == GXcopy)) - -#define CHECK_ROPSRC(pGC, flags) \ - (!(flags & ROP_NEEDS_SOURCE) || ((pGC->alu != GXclear) && \ - (pGC->alu != GXnoop) && (pGC->alu != GXinvert) && \ - (pGC->alu != GXset))) - -#define CHECK_PLANEMASK(pGC, flags) \ - (!(flags & NO_PLANEMASK) || \ - ((pGC->planemask & infoRec->FullPlanemasks[pGC->depth - 1]) == \ - infoRec->FullPlanemasks[pGC->depth - 1])) - -#define CHECK_COLORS(pGC, flags) \ - (!(flags & RGB_EQUAL) || \ - (CHECK_RGB_EQUAL(pGC->fgPixel) && CHECK_RGB_EQUAL(pGC->bgPixel))) - -#define CHECK_NO_GXCOPY(pGC, flags) \ - ((pGC->alu != GXcopy) || !(flags & NO_GXCOPY) || \ - ((pGC->planemask & infoRec->FullPlanemask) != infoRec->FullPlanemask)) - -#define IS_OFFSCREEN_PIXMAP(pPix)\ - ((XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pPix)))->offscreenArea) - -#define PIXMAP_IS_SHARED(pPix)\ - ((XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pPix)))->flags & SHARED_PIXMAP) - -#define OFFSCREEN_PIXMAP_LOCKED(pPix)\ - ((XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pPix)))->flags & LOCKED_PIXMAP) - -#define XAA_DEPTH_BUG(pGC) \ - ((pGC->depth == 32) && (pGC->bgPixel == 0xffffffff)) - -#define DELIST_OFFSCREEN_PIXMAP(pPix) { \ - PixmapLinkPtr _pLink, _prev; \ - _pLink = infoRec->OffscreenPixmaps; \ - _prev = NULL; \ - while(_pLink) { \ - if(_pLink->pPix == pPix) { \ - if(_prev) _prev->next = _pLink->next; \ - else infoRec->OffscreenPixmaps = _pLink->next; \ - xfree(_pLink); \ - break; \ - } \ - _prev = _pLink; \ - _pLink = _pLink->next; \ - }} - - -#define SWAP_BITS_IN_BYTES(v) \ - (((0x01010101 & (v)) << 7) | ((0x02020202 & (v)) << 5) | \ - ((0x04040404 & (v)) << 3) | ((0x08080808 & (v)) << 1) | \ - ((0x10101010 & (v)) >> 1) | ((0x20202020 & (v)) >> 3) | \ - ((0x40404040 & (v)) >> 5) | ((0x80808080 & (v)) >> 7)) - -/* - * Moved XAAPixmapCachePrivate here from xaaPCache.c, since driver - * replacements for CacheMonoStipple need access to it - */ - -typedef struct { - int Num512x512; - int Current512; - XAACacheInfoPtr Info512; - int Num256x256; - int Current256; - XAACacheInfoPtr Info256; - int Num128x128; - int Current128; - XAACacheInfoPtr Info128; - int NumMono; - int CurrentMono; - XAACacheInfoPtr InfoMono; - int NumColor; - int CurrentColor; - XAACacheInfoPtr InfoColor; - int NumPartial; - int CurrentPartial; - XAACacheInfoPtr InfoPartial; - DDXPointRec MonoOffsets[64]; - DDXPointRec ColorOffsets[64]; -} XAAPixmapCachePrivate, *XAAPixmapCachePrivatePtr; - - -#endif /* _XAALOCAL_H */ + +#ifndef _XAALOCAL_H +#define _XAALOCAL_H + +/* This file is very unorganized ! */ + + +#include "gcstruct.h" +#include "regionstr.h" +#include "xf86fbman.h" +#include "xaa.h" +#include "mi.h" +#include "picturestr.h" + +#define GCWhenForced (GCArcMode << 1) + +#define DO_COLOR_8x8 0x00000001 +#define DO_MONO_8x8 0x00000002 +#define DO_CACHE_BLT 0x00000003 +#define DO_COLOR_EXPAND 0x00000004 +#define DO_CACHE_EXPAND 0x00000005 +#define DO_IMAGE_WRITE 0x00000006 +#define DO_PIXMAP_COPY 0x00000007 +#define DO_SOLID 0x00000008 + + +typedef CARD32 * (*GlyphScanlineFuncPtr)( + CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width +); + +typedef CARD32 *(*StippleScanlineProcPtr)(CARD32*, CARD32*, int, int, int); + +typedef void (*RectFuncPtr) (ScrnInfoPtr, int, int, int, int, int, int, + XAACacheInfoPtr); +typedef void (*TrapFuncPtr) (ScrnInfoPtr, int, int, int, int, int, int, + int, int, int, int, int, int, + XAACacheInfoPtr); + + + +typedef struct _XAAScreen { + CreateGCProcPtr CreateGC; + CloseScreenProcPtr CloseScreen; + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + CopyWindowProcPtr CopyWindow; + WindowExposuresProcPtr WindowExposures; + CreatePixmapProcPtr CreatePixmap; + DestroyPixmapProcPtr DestroyPixmap; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + XAAInfoRecPtr AccelInfoRec; + Bool (*EnterVT)(int, int); + void (*LeaveVT)(int, int); + int (*SetDGAMode)(int, int, DGADevicePtr); + void (*EnableDisableFBAccess)(int, Bool); + CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; +} XAAScreenRec, *XAAScreenPtr; + +#define OPS_ARE_PIXMAP 0x00000001 +#define OPS_ARE_ACCEL 0x00000002 + +typedef struct _XAAGC { + GCOps *wrapOps; + GCFuncs *wrapFuncs; + GCOps *XAAOps; + int DashLength; + unsigned char* DashPattern; + unsigned long changes; + unsigned long flags; +} XAAGCRec, *XAAGCPtr; + +#define REDUCIBILITY_CHECKED 0x00000001 +#define REDUCIBLE_TO_8x8 0x00000002 +#define REDUCIBLE_TO_2_COLOR 0x00000004 +#define DIRTY 0x00010000 +#define OFFSCREEN 0x00020000 +#define DGA_PIXMAP 0x00040000 +#define SHARED_PIXMAP 0x00080000 +#define LOCKED_PIXMAP 0x00100000 + +#define REDUCIBILITY_MASK \ + (REDUCIBILITY_CHECKED | REDUCIBLE_TO_8x8 | REDUCIBLE_TO_2_COLOR) + +typedef struct _XAAPixmap { + unsigned long flags; + CARD32 pattern0; + CARD32 pattern1; + int fg; + int bg; + FBAreaPtr offscreenArea; + Bool freeData; +} XAAPixmapRec, *XAAPixmapPtr; + + +extern _X_EXPORT Bool +XAACreateGC( + GCPtr pGC +); + +extern _X_EXPORT Bool +XAAInitAccel( + ScreenPtr pScreen, + XAAInfoRecPtr infoRec +); + +extern _X_EXPORT RegionPtr +XAABitBlt( + DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GC *pGC, + int srcx, + int srcy, + int width, + int height, + int dstx, + int dsty, + void (*doBitBlt)(DrawablePtr, DrawablePtr, GCPtr, RegionPtr, DDXPointPtr), + unsigned long bitPlane +); + +extern _X_EXPORT void +XAAScreenToScreenBitBlt( + ScrnInfoPtr pScrn, + int nbox, + DDXPointPtr pptSrc, + BoxPtr pbox, + int xdir, + int ydir, + int alu, + unsigned int planemask +); + +extern _X_EXPORT void +XAADoBitBlt( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + RegionPtr prgnDst, + DDXPointPtr pptSrc +); + +extern _X_EXPORT void +XAADoImageWrite( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + RegionPtr prgnDst, + DDXPointPtr pptSrc +); + +extern _X_EXPORT void +XAADoImageRead( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + RegionPtr prgnDst, + DDXPointPtr pptSrc +); + +extern _X_EXPORT void +XAACopyWindow( + WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc +); + + +extern _X_EXPORT RegionPtr +XAACopyArea( + DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GC *pGC, + int srcx, + int srcy, + int width, + int height, + int dstx, + int dsty +); + +extern _X_EXPORT void +XAAValidateCopyArea( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +); + +extern _X_EXPORT void +XAAValidatePutImage( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +); + +extern _X_EXPORT void +XAAValidateCopyPlane( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +); + +extern _X_EXPORT void +XAAValidatePushPixels( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +); + +extern _X_EXPORT void +XAAValidateFillSpans( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +); + +extern _X_EXPORT void +XAAValidatePolyGlyphBlt( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +); + +extern _X_EXPORT void +XAAValidateImageGlyphBlt( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +); + +extern _X_EXPORT void +XAAValidatePolylines( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +); + + +extern _X_EXPORT RegionPtr +XAACopyPlaneColorExpansion( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, + int srcy, + int width, + int height, + int dstx, + int dsty, + unsigned long bitPlane +); + + +extern _X_EXPORT void +XAAPushPixelsSolidColorExpansion( + GCPtr pGC, + PixmapPtr pBitMap, + DrawablePtr pDrawable, + int dx, + int dy, + int xOrg, + int yOrg +); + +extern _X_EXPORT void +XAAWriteBitmapColorExpandMSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapColorExpand3MSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapColorExpandMSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapColorExpand3MSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapColorExpandLSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapColorExpand3LSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapColorExpandLSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapColorExpand3LSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + + +extern _X_EXPORT void +XAAWriteBitmapScanlineColorExpandMSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapScanlineColorExpand3MSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapScanlineColorExpandMSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapScanlineColorExpand3MSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapScanlineColorExpandLSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapScanlineColorExpand3LSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapScanlineColorExpandLSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWriteBitmapScanlineColorExpand3LSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int skipleft, + int fg, int bg, + int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAWritePixmap ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int rop, + unsigned int planemask, + int transparency_color, + int bpp, int depth +); + +extern _X_EXPORT void +XAAWritePixmapScanline ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int rop, + unsigned int planemask, + int transparency_color, + int bpp, int depth +); + +typedef void (*ClipAndRenderRectsFunc)(GCPtr, int, BoxPtr, int, int); + + +extern _X_EXPORT void +XAAClipAndRenderRects( + GCPtr pGC, + ClipAndRenderRectsFunc func, + int nrectFill, + xRectangle *prectInit, + int xorg, int yorg +); + + +typedef void (*ClipAndRenderSpansFunc)(GCPtr, int, DDXPointPtr, int*, + int, int, int); + +extern _X_EXPORT void +XAAClipAndRenderSpans( + GCPtr pGC, + DDXPointPtr ppt, + int *pwidth, + int nspans, + int fSorted, + ClipAndRenderSpansFunc func, + int xorg, + int yorg +); + + +extern _X_EXPORT void +XAAFillSolidRects( + ScrnInfoPtr pScrn, + int fg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox +); + +extern _X_EXPORT void +XAAFillMono8x8PatternRects( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int pat0, int pat1, + int xorg, int yorg +); + +extern _X_EXPORT void +XAAFillMono8x8PatternRectsScreenOrigin( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int pat0, int pat1, + int xorg, int yorg +); + + +extern _X_EXPORT void +XAAFillColor8x8PatternRectsScreenOrigin( + ScrnInfoPtr pScrn, + int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorigin, int yorigin, + XAACacheInfoPtr pCache +); + +extern _X_EXPORT void +XAAFillColor8x8PatternRects( + ScrnInfoPtr pScrn, + int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorigin, int yorigin, + XAACacheInfoPtr pCache +); + +extern _X_EXPORT void +XAAFillCacheBltRects( + ScrnInfoPtr pScrn, + int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + XAACacheInfoPtr pCache +); + +extern _X_EXPORT void +XAAFillCacheExpandRects( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillImageWriteRects( + ScrnInfoPtr pScrn, + int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAPolyFillRect( + DrawablePtr pDraw, + GCPtr pGC, + int nrectFill, + xRectangle *prectInit +); + + +extern _X_EXPORT void +XAATEGlyphRendererMSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + +extern _X_EXPORT void +XAATEGlyphRenderer3MSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + +extern _X_EXPORT void +XAATEGlyphRendererMSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + +extern _X_EXPORT void +XAATEGlyphRenderer3MSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + +extern _X_EXPORT void +XAATEGlyphRendererLSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + + +extern _X_EXPORT void +XAATEGlyphRenderer3LSBFirstFixedBase ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + +extern _X_EXPORT void +XAATEGlyphRendererLSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + +extern _X_EXPORT void +XAATEGlyphRenderer3LSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + + +extern _X_EXPORT void +XAATEGlyphRendererScanlineMSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + +extern _X_EXPORT void +XAATEGlyphRendererScanline3MSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + +extern _X_EXPORT void +XAATEGlyphRendererScanlineLSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + +extern _X_EXPORT void +XAATEGlyphRendererScanline3LSBFirst ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, int skipleft, int startline, + unsigned int **glyphs, int glyphWidth, + int fg, int bg, int rop, unsigned planemask +); + + +extern _X_EXPORT CARD32 *(*XAAGlyphScanlineFuncMSBFirstFixedBase[32])( + CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width +); + +extern _X_EXPORT CARD32 *(*XAAGlyphScanlineFuncMSBFirst[32])( + CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width +); + +extern _X_EXPORT CARD32 *(*XAAGlyphScanlineFuncLSBFirstFixedBase[32])( + CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width +); + +extern _X_EXPORT CARD32 *(*XAAGlyphScanlineFuncLSBFirst[32])( + CARD32 *base, unsigned int **glyphp, int line, int nglyph, int width +); + +extern _X_EXPORT GlyphScanlineFuncPtr *XAAGetGlyphScanlineFuncMSBFirstFixedBase(void); +extern _X_EXPORT GlyphScanlineFuncPtr *XAAGetGlyphScanlineFuncMSBFirst(void); +extern _X_EXPORT GlyphScanlineFuncPtr *XAAGetGlyphScanlineFuncLSBFirstFixedBase(void); +extern _X_EXPORT GlyphScanlineFuncPtr *XAAGetGlyphScanlineFuncLSBFirst(void); + +extern _X_EXPORT void +XAAFillColorExpandRectsLSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandRects3LSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandRectsLSBFirstFixedBase( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandRects3LSBFirstFixedBase( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandRectsMSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandRects3MSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandRectsMSBFirstFixedBase( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandRects3MSBFirstFixedBase( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillScanlineColorExpandRectsLSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillScanlineColorExpandRects3LSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillScanlineColorExpandRectsMSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillScanlineColorExpandRects3MSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int nBox, + BoxPtr pBox, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandSpansLSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandSpans3LSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandSpansLSBFirstFixedBase( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandSpans3LSBFirstFixedBase( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandSpansMSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandSpans3MSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandSpansMSBFirstFixedBase( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillColorExpandSpans3MSBFirstFixedBase( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillScanlineColorExpandSpansLSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillScanlineColorExpandSpans3LSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAPutImage( + DrawablePtr pDraw, + GCPtr pGC, + int depth, + int x, + int y, + int w, + int h, + int leftPad, + int format, + char *pImage +); + +extern _X_EXPORT void +XAAFillScanlineColorExpandSpansMSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillScanlineColorExpandSpans3MSBFirst( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + + +extern _X_EXPORT CARD32 *(*XAAStippleScanlineFuncMSBFirstFixedBase[6])( + CARD32* base, CARD32* src, int offset, int width, int dwords +); + +extern _X_EXPORT CARD32 *(*XAAStippleScanlineFuncMSBFirst[6])( + CARD32* base, CARD32* src, int offset, int width, int dwords +); + +extern _X_EXPORT CARD32 *(*XAAStippleScanlineFuncLSBFirstFixedBase[6])( + CARD32* base, CARD32* src, int offset, int width, int dwords +); + +extern _X_EXPORT CARD32 *(*XAAStippleScanlineFuncLSBFirst[6])( + CARD32* base, CARD32* src, int offset, int width, int dwords +); + +extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFuncMSBFirstFixedBase(void); +extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFuncMSBFirst(void); +extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFuncLSBFirstFixedBase(void); +extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFuncLSBFirst(void); +extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFunc3MSBFirstFixedBase(void); +extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFunc3MSBFirst(void); +extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFunc3LSBFirstFixedBase(void); +extern _X_EXPORT StippleScanlineProcPtr *XAAGetStippleScanlineFunc3LSBFirst(void); + +extern _X_EXPORT int +XAAPolyText8TEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars +); + +extern _X_EXPORT int +XAAPolyText16TEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars +); + +extern _X_EXPORT void +XAAImageText8TEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars +); + +extern _X_EXPORT void +XAAImageText16TEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars +); + +extern _X_EXPORT void +XAAImageGlyphBltTEColorExpansion( + DrawablePtr pDrawable, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +); + +extern _X_EXPORT void +XAAPolyGlyphBltTEColorExpansion( + DrawablePtr pDrawable, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +); + + +extern _X_EXPORT int +XAAPolyText8NonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars +); + +extern _X_EXPORT int +XAAPolyText16NonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars +); + +extern _X_EXPORT void +XAAImageText8NonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + char *chars +); + +extern _X_EXPORT void +XAAImageText16NonTEColorExpansion( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + int count, + unsigned short *chars +); + +extern _X_EXPORT void +XAAImageGlyphBltNonTEColorExpansion( + DrawablePtr pDrawable, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +); + +extern _X_EXPORT void +XAAPolyGlyphBltNonTEColorExpansion( + DrawablePtr pDrawable, + GCPtr pGC, + int xInit, int yInit, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +); + + +extern _X_EXPORT void XAANonTEGlyphRenderer( + ScrnInfoPtr pScrn, + int x, int y, int n, + NonTEGlyphPtr glyphs, + BoxPtr pbox, + int fg, int rop, + unsigned int planemask +); + +extern _X_EXPORT void +XAAFillSolidSpans( + ScrnInfoPtr pScrn, + int fg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, int fSorted +); + +extern _X_EXPORT void +XAAFillMono8x8PatternSpans( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, int fSorted, + int patx, int paty, + int xorg, int yorg +); + +extern _X_EXPORT void +XAAFillMono8x8PatternSpansScreenOrigin( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, int fSorted, + int patx, int paty, + int xorg, int yorg +); + +extern _X_EXPORT void +XAAFillColor8x8PatternSpansScreenOrigin( + ScrnInfoPtr pScrn, + int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, int fSorted, + XAACacheInfoPtr, + int xorigin, int yorigin +); + +extern _X_EXPORT void +XAAFillColor8x8PatternSpans( + ScrnInfoPtr pScrn, + int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, int fSorted, + XAACacheInfoPtr, + int xorigin, int yorigin +); + +extern _X_EXPORT void +XAAFillCacheBltSpans( + ScrnInfoPtr pScrn, + int rop, + unsigned int planemask, + int n, + DDXPointPtr points, + int *widths, + int fSorted, + XAACacheInfoPtr pCache, + int xorg, int yorg +); + +extern _X_EXPORT void +XAAFillCacheExpandSpans( + ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted, + int xorg, int yorg, + PixmapPtr pPix +); + +extern _X_EXPORT void +XAAFillSpans( + DrawablePtr pDrawable, + GC *pGC, + int nInit, + DDXPointPtr pptInit, + int *pwidth, + int fSorted +); + + +extern _X_EXPORT void +XAAInitPixmapCache( + ScreenPtr pScreen, + RegionPtr areas, + pointer data +); + +extern _X_EXPORT void +XAAWriteBitmapToCache( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int fg, int bg +); + +extern _X_EXPORT void +XAAWriteBitmapToCacheLinear( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int fg, int bg +); + +extern _X_EXPORT void +XAAWritePixmapToCache( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int bpp, int depth +); + +extern _X_EXPORT void +XAAWritePixmapToCacheLinear( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned char *src, + int srcwidth, + int bpp, int depth +); + +extern _X_EXPORT void +XAASolidHorVertLineAsRects( + ScrnInfoPtr pScrn, + int x, int y, int len, int dir +); + +extern _X_EXPORT void +XAASolidHorVertLineAsTwoPoint( + ScrnInfoPtr pScrn, + int x, int y, int len, int dir +); + +extern _X_EXPORT void +XAASolidHorVertLineAsBresenham( + ScrnInfoPtr pScrn, + int x, int y, int len, int dir +); + + +extern _X_EXPORT void +XAAPolyRectangleThinSolid( + DrawablePtr pDrawable, + GCPtr pGC, + int nRectsInit, + xRectangle *pRectsInit +); + + +extern _X_EXPORT void +XAAPolylinesWideSolid ( + DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pPts +); + +extern _X_EXPORT void +XAAFillPolygonSolid( + DrawablePtr pDrawable, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr ptsIn +); + +extern _X_EXPORT void +XAAFillPolygonStippled( + DrawablePtr pDrawable, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr ptsIn +); + + +extern _X_EXPORT void +XAAFillPolygonTiled( + DrawablePtr pDrawable, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr ptsIn +); + + +extern _X_EXPORT int +XAAIsEasyPolygon( + DDXPointPtr ptsIn, + int count, + BoxPtr extents, + int origin, + DDXPointPtr *topPoint, + int *topY, int *bottomY, + int shape +); + +extern _X_EXPORT void +XAAFillPolygonHelper( + ScrnInfoPtr pScrn, + DDXPointPtr ptsIn, + int count, + DDXPointPtr topPoint, + int y, + int maxy, + int origin, + RectFuncPtr RectFunc, + TrapFuncPtr TrapFunc, + int xorg, + int yorg, + XAACacheInfoPtr pCache +); + +extern _X_EXPORT void +XAAPolySegment( + DrawablePtr pDrawable, + GCPtr pGC, + int nseg, + xSegment *pSeg +); + +extern _X_EXPORT void +XAAPolyLines( + DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pptInit +); + +extern _X_EXPORT void +XAAPolySegmentDashed( + DrawablePtr pDrawable, + GCPtr pGC, + int nseg, + xSegment *pSeg +); + +extern _X_EXPORT void +XAAPolyLinesDashed( + DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pptInit +); + + +extern _X_EXPORT void +XAAWriteMono8x8PatternToCache(ScrnInfoPtr pScrn, XAACacheInfoPtr pCache); + +extern _X_EXPORT void +XAAWriteColor8x8PatternToCache( + ScrnInfoPtr pScrn, + PixmapPtr pPix, + XAACacheInfoPtr pCache +); + +extern _X_EXPORT void +XAARotateMonoPattern( + int *pat0, int *pat1, + int xoffset, int yoffset, + Bool msbfirst +); + +extern _X_EXPORT void XAAComputeDash(GCPtr pGC); + +extern _X_EXPORT void XAAMoveDWORDS_FixedBase( + register CARD32* dest, + register CARD32* src, + register int dwords +); + +extern _X_EXPORT void XAAMoveDWORDS_FixedSrc( + register CARD32* dest, + register CARD32* src, + register int dwords +); + +extern _X_EXPORT void XAAMoveDWORDS( + register CARD32* dest, + register CARD32* src, + register int dwords +); + +extern _X_EXPORT int +XAAGetRectClipBoxes( + GCPtr pGC, + BoxPtr pboxClippedBase, + int nrectFill, + xRectangle *prectInit +); + +extern _X_EXPORT void +XAASetupOverlay8_32Planar(ScreenPtr); + +extern _X_EXPORT void +XAAPolyFillArcSolid(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs); + +extern _X_EXPORT XAACacheInfoPtr +XAACacheTile(ScrnInfoPtr Scrn, PixmapPtr pPix); + +extern _X_EXPORT XAACacheInfoPtr +XAACacheMonoStipple(ScrnInfoPtr Scrn, PixmapPtr pPix); + +extern _X_EXPORT XAACacheInfoPtr +XAACachePlanarMonoStipple(ScrnInfoPtr Scrn, PixmapPtr pPix); + +typedef XAACacheInfoPtr (*XAACachePlanarMonoStippleProc)(ScrnInfoPtr, PixmapPtr); +extern _X_EXPORT XAACachePlanarMonoStippleProc XAAGetCachePlanarMonoStipple(void); + +extern _X_EXPORT XAACacheInfoPtr +XAACacheStipple(ScrnInfoPtr Scrn, PixmapPtr pPix, int fg, int bg); + +extern _X_EXPORT XAACacheInfoPtr +XAACacheMono8x8Pattern(ScrnInfoPtr Scrn, int pat0, int pat1); + +extern _X_EXPORT XAACacheInfoPtr +XAACacheColor8x8Pattern(ScrnInfoPtr Scrn, PixmapPtr pPix, int fg, int bg); + +extern _X_EXPORT void +XAATileCache(ScrnInfoPtr pScrn, XAACacheInfoPtr pCache, int w, int h); + +extern _X_EXPORT void XAAClosePixmapCache(ScreenPtr pScreen); +void XAAInvalidatePixmapCache(ScreenPtr pScreen); + +extern _X_EXPORT Bool XAACheckStippleReducibility(PixmapPtr pPixmap); +extern _X_EXPORT Bool XAACheckTileReducibility(PixmapPtr pPixmap, Bool checkMono); + +extern _X_EXPORT int XAAStippledFillChooser(GCPtr pGC); +extern _X_EXPORT int XAAOpaqueStippledFillChooser(GCPtr pGC); +extern _X_EXPORT int XAATiledFillChooser(GCPtr pGC); + +extern _X_EXPORT void XAAMoveInOffscreenPixmaps(ScreenPtr pScreen); +extern _X_EXPORT void XAAMoveOutOffscreenPixmaps(ScreenPtr pScreen); +extern _X_EXPORT void XAARemoveAreaCallback(FBAreaPtr area); +extern _X_EXPORT void XAAMoveOutOffscreenPixmap(PixmapPtr pPix); +extern _X_EXPORT Bool XAAInitStateWrap(ScreenPtr pScreen, XAAInfoRecPtr infoRec); + +extern _X_EXPORT void +XAAComposite (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); + + +extern _X_EXPORT Bool +XAADoComposite (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); + + +extern _X_EXPORT void +XAAGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs); + +extern _X_EXPORT Bool +XAADoGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs); + + + +/* helpers */ +extern _X_EXPORT void +XAA_888_plus_PICT_a8_to_8888 ( + CARD32 color, + CARD8 *alphaPtr, /* in bytes */ + int alphaPitch, + CARD32 *dstPtr, + int dstPitch, /* in dwords */ + int width, + int height +); + +extern _X_EXPORT Bool +XAAGetRGBAFromPixel( + CARD32 pixel, + CARD16 *red, + CARD16 *green, + CARD16 *blue, + CARD16 *alpha, + CARD32 format +); + + +extern _X_EXPORT Bool +XAAGetPixelFromRGBA ( + CARD32 *pixel, + CARD16 red, + CARD16 green, + CARD16 blue, + CARD16 alpha, + CARD32 format +); + +/* XXX should be static */ +extern _X_EXPORT GCOps XAAFallbackOps; +extern _X_EXPORT GCOps *XAAGetFallbackOps(void); +extern _X_EXPORT GCFuncs XAAGCFuncs; +extern _X_EXPORT DevPrivateKey XAAGetScreenKey(void); +extern _X_EXPORT DevPrivateKey XAAGetGCKey(void); +extern _X_EXPORT DevPrivateKey XAAGetPixmapKey(void); + +extern _X_EXPORT unsigned int XAAShiftMasks[32]; + +extern _X_EXPORT unsigned int byte_expand3[256], byte_reversed_expand3[256]; + +extern _X_EXPORT CARD32 XAAReverseBitOrder(CARD32 data); + +#define GET_XAASCREENPTR_FROM_SCREEN(pScreen)\ + dixLookupPrivate(&(pScreen)->devPrivates, XAAGetScreenKey()) + +#define GET_XAASCREENPTR_FROM_GC(pGC)\ + dixLookupPrivate(&(pGC)->pScreen->devPrivates, XAAGetScreenKey()) + +#define GET_XAASCREENPTR_FROM_DRAWABLE(pDraw)\ + dixLookupPrivate(&(pDraw)->pScreen->devPrivates, XAAGetScreenKey()) + +#define GET_XAAINFORECPTR_FROM_SCREEN(pScreen)\ +((XAAScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, XAAGetScreenKey()))->AccelInfoRec + +#define GET_XAAINFORECPTR_FROM_GC(pGC)\ +((XAAScreenPtr)dixLookupPrivate(&(pGC)->pScreen->devPrivates, XAAGetScreenKey()))->AccelInfoRec + +#define GET_XAAINFORECPTR_FROM_DRAWABLE(pDraw)\ +((XAAScreenPtr)dixLookupPrivate(&(pDraw)->pScreen->devPrivates, XAAGetScreenKey()))->AccelInfoRec + +#define GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn)\ +((XAAScreenPtr)dixLookupPrivate(&(pScrn)->pScreen->devPrivates, XAAGetScreenKey()))->AccelInfoRec + +#define XAA_GET_PIXMAP_PRIVATE(pix)\ + (XAAPixmapPtr)dixLookupPrivate(&(pix)->devPrivates, XAAGetPixmapKey()) + +#define CHECK_RGB_EQUAL(c) (!((((c) >> 8) ^ (c)) & 0xffff)) + +#define CHECK_FG(pGC, flags) \ + (!(flags & RGB_EQUAL) || CHECK_RGB_EQUAL(pGC->fgPixel)) + +#define CHECK_BG(pGC, flags) \ + (!(flags & RGB_EQUAL) || CHECK_RGB_EQUAL(pGC->bgPixel)) + +#define CHECK_ROP(pGC, flags) \ + (!(flags & GXCOPY_ONLY) || (pGC->alu == GXcopy)) + +#define CHECK_ROPSRC(pGC, flags) \ + (!(flags & ROP_NEEDS_SOURCE) || ((pGC->alu != GXclear) && \ + (pGC->alu != GXnoop) && (pGC->alu != GXinvert) && \ + (pGC->alu != GXset))) + +#define CHECK_PLANEMASK(pGC, flags) \ + (!(flags & NO_PLANEMASK) || \ + ((pGC->planemask & infoRec->FullPlanemasks[pGC->depth - 1]) == \ + infoRec->FullPlanemasks[pGC->depth - 1])) + +#define CHECK_COLORS(pGC, flags) \ + (!(flags & RGB_EQUAL) || \ + (CHECK_RGB_EQUAL(pGC->fgPixel) && CHECK_RGB_EQUAL(pGC->bgPixel))) + +#define CHECK_NO_GXCOPY(pGC, flags) \ + ((pGC->alu != GXcopy) || !(flags & NO_GXCOPY) || \ + ((pGC->planemask & infoRec->FullPlanemask) != infoRec->FullPlanemask)) + +#define IS_OFFSCREEN_PIXMAP(pPix)\ + ((XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pPix)))->offscreenArea) + +#define PIXMAP_IS_SHARED(pPix)\ + ((XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pPix)))->flags & SHARED_PIXMAP) + +#define OFFSCREEN_PIXMAP_LOCKED(pPix)\ + ((XAA_GET_PIXMAP_PRIVATE((PixmapPtr)(pPix)))->flags & LOCKED_PIXMAP) + +#define XAA_DEPTH_BUG(pGC) \ + ((pGC->depth == 32) && (pGC->bgPixel == 0xffffffff)) + +#define DELIST_OFFSCREEN_PIXMAP(pPix) { \ + PixmapLinkPtr _pLink, _prev; \ + _pLink = infoRec->OffscreenPixmaps; \ + _prev = NULL; \ + while(_pLink) { \ + if(_pLink->pPix == pPix) { \ + if(_prev) _prev->next = _pLink->next; \ + else infoRec->OffscreenPixmaps = _pLink->next; \ + free(_pLink); \ + break; \ + } \ + _prev = _pLink; \ + _pLink = _pLink->next; \ + }} + + +#define SWAP_BITS_IN_BYTES(v) \ + (((0x01010101 & (v)) << 7) | ((0x02020202 & (v)) << 5) | \ + ((0x04040404 & (v)) << 3) | ((0x08080808 & (v)) << 1) | \ + ((0x10101010 & (v)) >> 1) | ((0x20202020 & (v)) >> 3) | \ + ((0x40404040 & (v)) >> 5) | ((0x80808080 & (v)) >> 7)) + +/* + * Moved XAAPixmapCachePrivate here from xaaPCache.c, since driver + * replacements for CacheMonoStipple need access to it + */ + +typedef struct { + int Num512x512; + int Current512; + XAACacheInfoPtr Info512; + int Num256x256; + int Current256; + XAACacheInfoPtr Info256; + int Num128x128; + int Current128; + XAACacheInfoPtr Info128; + int NumMono; + int CurrentMono; + XAACacheInfoPtr InfoMono; + int NumColor; + int CurrentColor; + XAACacheInfoPtr InfoColor; + int NumPartial; + int CurrentPartial; + XAACacheInfoPtr InfoPartial; + DDXPointRec MonoOffsets[64]; + DDXPointRec ColorOffsets[64]; +} XAAPixmapCachePrivate, *XAAPixmapCachePrivatePtr; + + +#endif /* _XAALOCAL_H */ diff --git a/xorg-server/hw/xnest/Color.c b/xorg-server/hw/xnest/Color.c index 2e6de15e4..985b5ad95 100644 --- a/xorg-server/hw/xnest/Color.c +++ b/xorg-server/hw/xnest/Color.c @@ -1,495 +1,495 @@ -/* - -Copyright 1993 by Davor Matic - -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. Davor Matic makes no representations about -the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. - -*/ - -#ifdef HAVE_XNEST_CONFIG_H -#include <xnest-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "scrnintstr.h" -#include "window.h" -#include "windowstr.h" -#include "colormapst.h" -#include "resource.h" - -#include "Xnest.h" - - -#include "Display.h" -#include "Screen.h" -#include "Color.h" -#include "Visual.h" -#include "XNWindow.h" -#include "Args.h" - -static int cmapScrPrivateKeyIndex; -static DevPrivateKey cmapScrPrivateKey = &cmapScrPrivateKeyIndex; - -#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey)) -#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c)) - -Bool -xnestCreateColormap(ColormapPtr pCmap) -{ - VisualPtr pVisual; - XColor *colors; - int i, ncolors; - Pixel red, green, blue; - Pixel redInc, greenInc, blueInc; - - pVisual = pCmap->pVisual; - ncolors = pVisual->ColormapEntries; - - pCmap->devPriv = (pointer)xalloc(sizeof(xnestPrivColormap)); - - xnestColormapPriv(pCmap)->colormap = - XCreateColormap(xnestDisplay, - xnestDefaultWindows[pCmap->pScreen->myNum], - xnestVisual(pVisual), - (pVisual->class & DynamicClass) ? - AllocAll : AllocNone); - - - switch (pVisual->class) { - case StaticGray: /* read only */ - colors = (XColor *)xalloc(ncolors * sizeof(XColor)); - for (i = 0; i < ncolors; i++) - colors[i].pixel = i; - XQueryColors(xnestDisplay, xnestColormap(pCmap), colors, ncolors); - for (i = 0; i < ncolors; i++) { - pCmap->red[i].co.local.red = colors[i].red; - pCmap->red[i].co.local.green = colors[i].red; - pCmap->red[i].co.local.blue = colors[i].red; - } - xfree(colors); - break; - - case StaticColor: /* read only */ - colors = (XColor *)xalloc(ncolors * sizeof(XColor)); - for (i = 0; i < ncolors; i++) - colors[i].pixel = i; - XQueryColors(xnestDisplay, xnestColormap(pCmap), colors, ncolors); - for (i = 0; i < ncolors; i++) { - pCmap->red[i].co.local.red = colors[i].red; - pCmap->red[i].co.local.green = colors[i].green; - pCmap->red[i].co.local.blue = colors[i].blue; - } - xfree(colors); - break; - - case TrueColor: /* read only */ - colors = (XColor *)xalloc(ncolors * sizeof(XColor)); - red = green = blue = 0L; - redInc = lowbit(pVisual->redMask); - greenInc = lowbit(pVisual->greenMask); - blueInc = lowbit(pVisual->blueMask); - for (i = 0; i < ncolors; i++) { - colors[i].pixel = red | green | blue; - red += redInc; - if (red > pVisual->redMask) red = 0L; - green += greenInc; - if (green > pVisual->greenMask) green = 0L; - blue += blueInc; - if (blue > pVisual->blueMask) blue = 0L; - } - XQueryColors(xnestDisplay, xnestColormap(pCmap), colors, ncolors); - for (i = 0; i < ncolors; i++) { - pCmap->red[i].co.local.red = colors[i].red; - pCmap->green[i].co.local.green = colors[i].green; - pCmap->blue[i].co.local.blue = colors[i].blue; - } - xfree(colors); - break; - - case GrayScale: /* read and write */ - break; - - case PseudoColor: /* read and write */ - break; - - case DirectColor: /* read and write */ - break; - } - - return True; -} - -void -xnestDestroyColormap(ColormapPtr pCmap) -{ - XFreeColormap(xnestDisplay, xnestColormap(pCmap)); - xfree(pCmap->devPriv); -} - -#define SEARCH_PREDICATE \ - (xnestWindow(pWin) != None && wColormap(pWin) == icws->cmapIDs[i]) - -static int -xnestCountInstalledColormapWindows(WindowPtr pWin, pointer ptr) -{ - xnestInstalledColormapWindows *icws = (xnestInstalledColormapWindows *)ptr; - int i; - - for (i = 0; i < icws->numCmapIDs; i++) - if (SEARCH_PREDICATE) { - icws->numWindows++; - return WT_DONTWALKCHILDREN; - } - - return WT_WALKCHILDREN; -} - -static int -xnestGetInstalledColormapWindows(WindowPtr pWin, pointer ptr) -{ - xnestInstalledColormapWindows *icws = (xnestInstalledColormapWindows *)ptr; - int i; - - for (i = 0; i < icws->numCmapIDs; i++) - if (SEARCH_PREDICATE) { - icws->windows[icws->index++] = xnestWindow(pWin); - return WT_DONTWALKCHILDREN; - } - - return WT_WALKCHILDREN; -} - -static Window *xnestOldInstalledColormapWindows = NULL; -static int xnestNumOldInstalledColormapWindows = 0; - -static Bool -xnestSameInstalledColormapWindows(Window *windows, int numWindows) -{ - if (xnestNumOldInstalledColormapWindows != numWindows) - return False; - - if (xnestOldInstalledColormapWindows == windows) - return True; - - if (xnestOldInstalledColormapWindows == NULL || windows == NULL) - return False; - - if (memcmp(xnestOldInstalledColormapWindows, windows, - numWindows * sizeof(Window))) - return False; - - return True; -} - -void -xnestSetInstalledColormapWindows(ScreenPtr pScreen) -{ - xnestInstalledColormapWindows icws; - int numWindows; - - icws.cmapIDs = (Colormap *)xalloc(pScreen->maxInstalledCmaps * - sizeof(Colormap)); - icws.numCmapIDs = xnestListInstalledColormaps(pScreen, icws.cmapIDs); - icws.numWindows = 0; - WalkTree(pScreen, xnestCountInstalledColormapWindows, (pointer)&icws); - if (icws.numWindows) { - icws.windows = (Window *)xalloc((icws.numWindows + 1) * sizeof(Window)); - icws.index = 0; - WalkTree(pScreen, xnestGetInstalledColormapWindows, (pointer)&icws); - icws.windows[icws.numWindows] = xnestDefaultWindows[pScreen->myNum]; - numWindows = icws.numWindows + 1; - } - else { - icws.windows = NULL; - numWindows = 0; - } - - xfree(icws.cmapIDs); - - if (!xnestSameInstalledColormapWindows(icws.windows, icws.numWindows)) { - if (xnestOldInstalledColormapWindows) - xfree(xnestOldInstalledColormapWindows); - -#ifdef _XSERVER64 - { - int i; - Window64 *windows = (Window64 *)xalloc(numWindows * sizeof(Window64)); - - for(i = 0; i < numWindows; ++i) - windows[i] = icws.windows[i]; - XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], - windows, numWindows); - xfree(windows); - } -#else - XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], - icws.windows, numWindows); -#endif - - xnestOldInstalledColormapWindows = icws.windows; - xnestNumOldInstalledColormapWindows = icws.numWindows; - -#ifdef DUMB_WINDOW_MANAGERS - /* - This code is for dumb window managers. - This will only work with default local visual colormaps. - */ - if (icws.numWindows) - { - WindowPtr pWin; - Visual *visual; - ColormapPtr pCmap; - - pWin = xnestWindowPtr(icws.windows[0]); - visual = xnestVisualFromID(pScreen, wVisual(pWin)); - - if (visual == xnestDefaultVisual(pScreen)) - dixLookupResourceByType((pointer *)&pCmap, wColormap(pWin), - RT_COLORMAP, serverClient, DixUseAccess); - else - dixLookupResourceByType((pointer *)&pCmap, pScreen->defColormap, - RT_COLORMAP, serverClient, DixUseAccess); - - XSetWindowColormap(xnestDisplay, - xnestDefaultWindows[pScreen->myNum], - xnestColormap(pCmap)); - } -#endif /* DUMB_WINDOW_MANAGERS */ - } - else - if (icws.windows) xfree(icws.windows); -} - -void -xnestSetScreenSaverColormapWindow(ScreenPtr pScreen) -{ - if (xnestOldInstalledColormapWindows) - xfree(xnestOldInstalledColormapWindows); - -#ifdef _XSERVER64 - { - Window64 window; - - window = xnestScreenSaverWindows[pScreen->myNum]; - XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], - &window, 1); - xnestScreenSaverWindows[pScreen->myNum] = window; - } -#else - XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], - &xnestScreenSaverWindows[pScreen->myNum], 1); -#endif /* _XSERVER64 */ - - xnestOldInstalledColormapWindows = NULL; - xnestNumOldInstalledColormapWindows = 0; - - xnestDirectUninstallColormaps(pScreen); -} - -void -xnestDirectInstallColormaps(ScreenPtr pScreen) -{ - int i, n; - Colormap pCmapIDs[MAXCMAPS]; - - if (!xnestDoDirectColormaps) return; - - n = (*pScreen->ListInstalledColormaps)(pScreen, pCmapIDs); - - for (i = 0; i < n; i++) { - ColormapPtr pCmap; - - dixLookupResourceByType((pointer *)&pCmap, pCmapIDs[i], RT_COLORMAP, - serverClient, DixInstallAccess); - if (pCmap) - XInstallColormap(xnestDisplay, xnestColormap(pCmap)); - } -} - -void -xnestDirectUninstallColormaps(ScreenPtr pScreen) -{ - int i, n; - Colormap pCmapIDs[MAXCMAPS]; - - if (!xnestDoDirectColormaps) return; - - n = (*pScreen->ListInstalledColormaps)(pScreen, pCmapIDs); - - for (i = 0; i < n; i++) { - ColormapPtr pCmap; - - dixLookupResourceByType((pointer *)&pCmap, pCmapIDs[i], RT_COLORMAP, - serverClient, DixUninstallAccess); - if (pCmap) - XUninstallColormap(xnestDisplay, xnestColormap(pCmap)); - } -} - -void -xnestInstallColormap(ColormapPtr pCmap) -{ - ColormapPtr pOldCmap = GetInstalledColormap(pCmap->pScreen); - - if(pCmap != pOldCmap) - { - xnestDirectUninstallColormaps(pCmap->pScreen); - - /* Uninstall pInstalledMap. Notify all interested parties. */ - if(pOldCmap != (ColormapPtr)None) - WalkTree(pCmap->pScreen, TellLostMap, (pointer)&pOldCmap->mid); - - SetInstalledColormap(pCmap->pScreen, pCmap); - WalkTree(pCmap->pScreen, TellGainedMap, (pointer)&pCmap->mid); - - xnestSetInstalledColormapWindows(pCmap->pScreen); - xnestDirectInstallColormaps(pCmap->pScreen); - } -} - -void -xnestUninstallColormap(ColormapPtr pCmap) -{ - ColormapPtr pCurCmap = GetInstalledColormap(pCmap->pScreen); - - if(pCmap == pCurCmap) - { - if (pCmap->mid != pCmap->pScreen->defColormap) - { - dixLookupResourceByType((pointer *)&pCurCmap, - pCmap->pScreen->defColormap, - RT_COLORMAP, - serverClient, DixInstallAccess); - (*pCmap->pScreen->InstallColormap)(pCurCmap); - } - } -} - -static Bool xnestInstalledDefaultColormap = False; - -int -xnestListInstalledColormaps(ScreenPtr pScreen, Colormap *pCmapIDs) -{ - if (xnestInstalledDefaultColormap) { - *pCmapIDs = GetInstalledColormap(pScreen)->mid; - return 1; - } - else - return 0; -} - -void -xnestStoreColors(ColormapPtr pCmap, int nColors, xColorItem *pColors) -{ - if (pCmap->pVisual->class & DynamicClass) -#ifdef _XSERVER64 - { - int i; - XColor *pColors64 = (XColor *)xalloc(nColors * sizeof(XColor) ); - - for(i = 0; i < nColors; ++i) - { - pColors64[i].pixel = pColors[i].pixel; - pColors64[i].red = pColors[i].red; - pColors64[i].green = pColors[i].green; - pColors64[i].blue = pColors[i].blue; - pColors64[i].flags = pColors[i].flags; - } - XStoreColors(xnestDisplay, xnestColormap(pCmap), pColors64, nColors); - xfree(pColors64); - } -#else - XStoreColors(xnestDisplay, xnestColormap(pCmap), - (XColor *)pColors, nColors); -#endif -} - -void -xnestResolveColor(unsigned short *pRed, unsigned short *pGreen, - unsigned short *pBlue, VisualPtr pVisual) -{ - int shift; - unsigned int lim; - - shift = 16 - pVisual->bitsPerRGBValue; - lim = (1 << pVisual->bitsPerRGBValue) - 1; - - if ((pVisual->class == PseudoColor) || (pVisual->class == DirectColor)) - { - /* rescale to rgb bits */ - *pRed = ((*pRed >> shift) * 65535) / lim; - *pGreen = ((*pGreen >> shift) * 65535) / lim; - *pBlue = ((*pBlue >> shift) * 65535) / lim; - } - else if (pVisual->class == GrayScale) - { - /* rescale to gray then rgb bits */ - *pRed = (30L * *pRed + 59L * *pGreen + 11L * *pBlue) / 100; - *pBlue = *pGreen = *pRed = ((*pRed >> shift) * 65535) / lim; - } - else if (pVisual->class == StaticGray) - { - unsigned int limg; - - limg = pVisual->ColormapEntries - 1; - /* rescale to gray then [0..limg] then [0..65535] then rgb bits */ - *pRed = (30L * *pRed + 59L * *pGreen + 11L * *pBlue) / 100; - *pRed = ((((*pRed * (limg + 1))) >> 16) * 65535) / limg; - *pBlue = *pGreen = *pRed = ((*pRed >> shift) * 65535) / lim; - } - else - { - unsigned limr, limg, limb; - - limr = pVisual->redMask >> pVisual->offsetRed; - limg = pVisual->greenMask >> pVisual->offsetGreen; - limb = pVisual->blueMask >> pVisual->offsetBlue; - /* rescale to [0..limN] then [0..65535] then rgb bits */ - *pRed = ((((((*pRed * (limr + 1)) >> 16) * - 65535) / limr) >> shift) * 65535) / lim; - *pGreen = ((((((*pGreen * (limg + 1)) >> 16) * - 65535) / limg) >> shift) * 65535) / lim; - *pBlue = ((((((*pBlue * (limb + 1)) >> 16) * - 65535) / limb) >> shift) * 65535) / lim; - } -} - -Bool -xnestCreateDefaultColormap(ScreenPtr pScreen) -{ - VisualPtr pVisual; - ColormapPtr pCmap; - unsigned short zero = 0, ones = 0xFFFF; - Pixel wp, bp; - - for (pVisual = pScreen->visuals; - pVisual->vid != pScreen->rootVisual; - pVisual++); - - if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &pCmap, - (pVisual->class & DynamicClass) ? AllocNone : AllocAll, 0) - != Success) - return False; - - wp = pScreen->whitePixel; - bp = pScreen->blackPixel; - if ((AllocColor(pCmap, &ones, &ones, &ones, &wp, 0) != - Success) || - (AllocColor(pCmap, &zero, &zero, &zero, &bp, 0) != - Success)) - return FALSE; - pScreen->whitePixel = wp; - pScreen->blackPixel = bp; - (*pScreen->InstallColormap)(pCmap); - - xnestInstalledDefaultColormap = True; - - return True; -} +/* + +Copyright 1993 by Davor Matic + +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. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "window.h" +#include "windowstr.h" +#include "colormapst.h" +#include "resource.h" + +#include "Xnest.h" + + +#include "Display.h" +#include "Screen.h" +#include "Color.h" +#include "Visual.h" +#include "XNWindow.h" +#include "Args.h" + +static int cmapScrPrivateKeyIndex; +static DevPrivateKey cmapScrPrivateKey = &cmapScrPrivateKeyIndex; + +#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey)) +#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c)) + +Bool +xnestCreateColormap(ColormapPtr pCmap) +{ + VisualPtr pVisual; + XColor *colors; + int i, ncolors; + Pixel red, green, blue; + Pixel redInc, greenInc, blueInc; + + pVisual = pCmap->pVisual; + ncolors = pVisual->ColormapEntries; + + pCmap->devPriv = (pointer)malloc(sizeof(xnestPrivColormap)); + + xnestColormapPriv(pCmap)->colormap = + XCreateColormap(xnestDisplay, + xnestDefaultWindows[pCmap->pScreen->myNum], + xnestVisual(pVisual), + (pVisual->class & DynamicClass) ? + AllocAll : AllocNone); + + + switch (pVisual->class) { + case StaticGray: /* read only */ + colors = (XColor *)malloc(ncolors * sizeof(XColor)); + for (i = 0; i < ncolors; i++) + colors[i].pixel = i; + XQueryColors(xnestDisplay, xnestColormap(pCmap), colors, ncolors); + for (i = 0; i < ncolors; i++) { + pCmap->red[i].co.local.red = colors[i].red; + pCmap->red[i].co.local.green = colors[i].red; + pCmap->red[i].co.local.blue = colors[i].red; + } + free(colors); + break; + + case StaticColor: /* read only */ + colors = (XColor *)malloc(ncolors * sizeof(XColor)); + for (i = 0; i < ncolors; i++) + colors[i].pixel = i; + XQueryColors(xnestDisplay, xnestColormap(pCmap), colors, ncolors); + for (i = 0; i < ncolors; i++) { + pCmap->red[i].co.local.red = colors[i].red; + pCmap->red[i].co.local.green = colors[i].green; + pCmap->red[i].co.local.blue = colors[i].blue; + } + free(colors); + break; + + case TrueColor: /* read only */ + colors = (XColor *)malloc(ncolors * sizeof(XColor)); + red = green = blue = 0L; + redInc = lowbit(pVisual->redMask); + greenInc = lowbit(pVisual->greenMask); + blueInc = lowbit(pVisual->blueMask); + for (i = 0; i < ncolors; i++) { + colors[i].pixel = red | green | blue; + red += redInc; + if (red > pVisual->redMask) red = 0L; + green += greenInc; + if (green > pVisual->greenMask) green = 0L; + blue += blueInc; + if (blue > pVisual->blueMask) blue = 0L; + } + XQueryColors(xnestDisplay, xnestColormap(pCmap), colors, ncolors); + for (i = 0; i < ncolors; i++) { + pCmap->red[i].co.local.red = colors[i].red; + pCmap->green[i].co.local.green = colors[i].green; + pCmap->blue[i].co.local.blue = colors[i].blue; + } + free(colors); + break; + + case GrayScale: /* read and write */ + break; + + case PseudoColor: /* read and write */ + break; + + case DirectColor: /* read and write */ + break; + } + + return True; +} + +void +xnestDestroyColormap(ColormapPtr pCmap) +{ + XFreeColormap(xnestDisplay, xnestColormap(pCmap)); + free(pCmap->devPriv); +} + +#define SEARCH_PREDICATE \ + (xnestWindow(pWin) != None && wColormap(pWin) == icws->cmapIDs[i]) + +static int +xnestCountInstalledColormapWindows(WindowPtr pWin, pointer ptr) +{ + xnestInstalledColormapWindows *icws = (xnestInstalledColormapWindows *)ptr; + int i; + + for (i = 0; i < icws->numCmapIDs; i++) + if (SEARCH_PREDICATE) { + icws->numWindows++; + return WT_DONTWALKCHILDREN; + } + + return WT_WALKCHILDREN; +} + +static int +xnestGetInstalledColormapWindows(WindowPtr pWin, pointer ptr) +{ + xnestInstalledColormapWindows *icws = (xnestInstalledColormapWindows *)ptr; + int i; + + for (i = 0; i < icws->numCmapIDs; i++) + if (SEARCH_PREDICATE) { + icws->windows[icws->index++] = xnestWindow(pWin); + return WT_DONTWALKCHILDREN; + } + + return WT_WALKCHILDREN; +} + +static Window *xnestOldInstalledColormapWindows = NULL; +static int xnestNumOldInstalledColormapWindows = 0; + +static Bool +xnestSameInstalledColormapWindows(Window *windows, int numWindows) +{ + if (xnestNumOldInstalledColormapWindows != numWindows) + return False; + + if (xnestOldInstalledColormapWindows == windows) + return True; + + if (xnestOldInstalledColormapWindows == NULL || windows == NULL) + return False; + + if (memcmp(xnestOldInstalledColormapWindows, windows, + numWindows * sizeof(Window))) + return False; + + return True; +} + +void +xnestSetInstalledColormapWindows(ScreenPtr pScreen) +{ + xnestInstalledColormapWindows icws; + int numWindows; + + icws.cmapIDs = (Colormap *)malloc(pScreen->maxInstalledCmaps * + sizeof(Colormap)); + icws.numCmapIDs = xnestListInstalledColormaps(pScreen, icws.cmapIDs); + icws.numWindows = 0; + WalkTree(pScreen, xnestCountInstalledColormapWindows, (pointer)&icws); + if (icws.numWindows) { + icws.windows = (Window *)malloc((icws.numWindows + 1) * sizeof(Window)); + icws.index = 0; + WalkTree(pScreen, xnestGetInstalledColormapWindows, (pointer)&icws); + icws.windows[icws.numWindows] = xnestDefaultWindows[pScreen->myNum]; + numWindows = icws.numWindows + 1; + } + else { + icws.windows = NULL; + numWindows = 0; + } + + free(icws.cmapIDs); + + if (!xnestSameInstalledColormapWindows(icws.windows, icws.numWindows)) { + if (xnestOldInstalledColormapWindows) + free(xnestOldInstalledColormapWindows); + +#ifdef _XSERVER64 + { + int i; + Window64 *windows = (Window64 *)malloc(numWindows * sizeof(Window64)); + + for(i = 0; i < numWindows; ++i) + windows[i] = icws.windows[i]; + XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], + windows, numWindows); + free(windows); + } +#else + XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], + icws.windows, numWindows); +#endif + + xnestOldInstalledColormapWindows = icws.windows; + xnestNumOldInstalledColormapWindows = icws.numWindows; + +#ifdef DUMB_WINDOW_MANAGERS + /* + This code is for dumb window managers. + This will only work with default local visual colormaps. + */ + if (icws.numWindows) + { + WindowPtr pWin; + Visual *visual; + ColormapPtr pCmap; + + pWin = xnestWindowPtr(icws.windows[0]); + visual = xnestVisualFromID(pScreen, wVisual(pWin)); + + if (visual == xnestDefaultVisual(pScreen)) + dixLookupResourceByType((pointer *)&pCmap, wColormap(pWin), + RT_COLORMAP, serverClient, DixUseAccess); + else + dixLookupResourceByType((pointer *)&pCmap, pScreen->defColormap, + RT_COLORMAP, serverClient, DixUseAccess); + + XSetWindowColormap(xnestDisplay, + xnestDefaultWindows[pScreen->myNum], + xnestColormap(pCmap)); + } +#endif /* DUMB_WINDOW_MANAGERS */ + } + else + if (icws.windows) free(icws.windows); +} + +void +xnestSetScreenSaverColormapWindow(ScreenPtr pScreen) +{ + if (xnestOldInstalledColormapWindows) + free(xnestOldInstalledColormapWindows); + +#ifdef _XSERVER64 + { + Window64 window; + + window = xnestScreenSaverWindows[pScreen->myNum]; + XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], + &window, 1); + xnestScreenSaverWindows[pScreen->myNum] = window; + } +#else + XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], + &xnestScreenSaverWindows[pScreen->myNum], 1); +#endif /* _XSERVER64 */ + + xnestOldInstalledColormapWindows = NULL; + xnestNumOldInstalledColormapWindows = 0; + + xnestDirectUninstallColormaps(pScreen); +} + +void +xnestDirectInstallColormaps(ScreenPtr pScreen) +{ + int i, n; + Colormap pCmapIDs[MAXCMAPS]; + + if (!xnestDoDirectColormaps) return; + + n = (*pScreen->ListInstalledColormaps)(pScreen, pCmapIDs); + + for (i = 0; i < n; i++) { + ColormapPtr pCmap; + + dixLookupResourceByType((pointer *)&pCmap, pCmapIDs[i], RT_COLORMAP, + serverClient, DixInstallAccess); + if (pCmap) + XInstallColormap(xnestDisplay, xnestColormap(pCmap)); + } +} + +void +xnestDirectUninstallColormaps(ScreenPtr pScreen) +{ + int i, n; + Colormap pCmapIDs[MAXCMAPS]; + + if (!xnestDoDirectColormaps) return; + + n = (*pScreen->ListInstalledColormaps)(pScreen, pCmapIDs); + + for (i = 0; i < n; i++) { + ColormapPtr pCmap; + + dixLookupResourceByType((pointer *)&pCmap, pCmapIDs[i], RT_COLORMAP, + serverClient, DixUninstallAccess); + if (pCmap) + XUninstallColormap(xnestDisplay, xnestColormap(pCmap)); + } +} + +void +xnestInstallColormap(ColormapPtr pCmap) +{ + ColormapPtr pOldCmap = GetInstalledColormap(pCmap->pScreen); + + if(pCmap != pOldCmap) + { + xnestDirectUninstallColormaps(pCmap->pScreen); + + /* Uninstall pInstalledMap. Notify all interested parties. */ + if(pOldCmap != (ColormapPtr)None) + WalkTree(pCmap->pScreen, TellLostMap, (pointer)&pOldCmap->mid); + + SetInstalledColormap(pCmap->pScreen, pCmap); + WalkTree(pCmap->pScreen, TellGainedMap, (pointer)&pCmap->mid); + + xnestSetInstalledColormapWindows(pCmap->pScreen); + xnestDirectInstallColormaps(pCmap->pScreen); + } +} + +void +xnestUninstallColormap(ColormapPtr pCmap) +{ + ColormapPtr pCurCmap = GetInstalledColormap(pCmap->pScreen); + + if(pCmap == pCurCmap) + { + if (pCmap->mid != pCmap->pScreen->defColormap) + { + dixLookupResourceByType((pointer *)&pCurCmap, + pCmap->pScreen->defColormap, + RT_COLORMAP, + serverClient, DixInstallAccess); + (*pCmap->pScreen->InstallColormap)(pCurCmap); + } + } +} + +static Bool xnestInstalledDefaultColormap = False; + +int +xnestListInstalledColormaps(ScreenPtr pScreen, Colormap *pCmapIDs) +{ + if (xnestInstalledDefaultColormap) { + *pCmapIDs = GetInstalledColormap(pScreen)->mid; + return 1; + } + else + return 0; +} + +void +xnestStoreColors(ColormapPtr pCmap, int nColors, xColorItem *pColors) +{ + if (pCmap->pVisual->class & DynamicClass) +#ifdef _XSERVER64 + { + int i; + XColor *pColors64 = (XColor *)malloc(nColors * sizeof(XColor) ); + + for(i = 0; i < nColors; ++i) + { + pColors64[i].pixel = pColors[i].pixel; + pColors64[i].red = pColors[i].red; + pColors64[i].green = pColors[i].green; + pColors64[i].blue = pColors[i].blue; + pColors64[i].flags = pColors[i].flags; + } + XStoreColors(xnestDisplay, xnestColormap(pCmap), pColors64, nColors); + free(pColors64); + } +#else + XStoreColors(xnestDisplay, xnestColormap(pCmap), + (XColor *)pColors, nColors); +#endif +} + +void +xnestResolveColor(unsigned short *pRed, unsigned short *pGreen, + unsigned short *pBlue, VisualPtr pVisual) +{ + int shift; + unsigned int lim; + + shift = 16 - pVisual->bitsPerRGBValue; + lim = (1 << pVisual->bitsPerRGBValue) - 1; + + if ((pVisual->class == PseudoColor) || (pVisual->class == DirectColor)) + { + /* rescale to rgb bits */ + *pRed = ((*pRed >> shift) * 65535) / lim; + *pGreen = ((*pGreen >> shift) * 65535) / lim; + *pBlue = ((*pBlue >> shift) * 65535) / lim; + } + else if (pVisual->class == GrayScale) + { + /* rescale to gray then rgb bits */ + *pRed = (30L * *pRed + 59L * *pGreen + 11L * *pBlue) / 100; + *pBlue = *pGreen = *pRed = ((*pRed >> shift) * 65535) / lim; + } + else if (pVisual->class == StaticGray) + { + unsigned int limg; + + limg = pVisual->ColormapEntries - 1; + /* rescale to gray then [0..limg] then [0..65535] then rgb bits */ + *pRed = (30L * *pRed + 59L * *pGreen + 11L * *pBlue) / 100; + *pRed = ((((*pRed * (limg + 1))) >> 16) * 65535) / limg; + *pBlue = *pGreen = *pRed = ((*pRed >> shift) * 65535) / lim; + } + else + { + unsigned limr, limg, limb; + + limr = pVisual->redMask >> pVisual->offsetRed; + limg = pVisual->greenMask >> pVisual->offsetGreen; + limb = pVisual->blueMask >> pVisual->offsetBlue; + /* rescale to [0..limN] then [0..65535] then rgb bits */ + *pRed = ((((((*pRed * (limr + 1)) >> 16) * + 65535) / limr) >> shift) * 65535) / lim; + *pGreen = ((((((*pGreen * (limg + 1)) >> 16) * + 65535) / limg) >> shift) * 65535) / lim; + *pBlue = ((((((*pBlue * (limb + 1)) >> 16) * + 65535) / limb) >> shift) * 65535) / lim; + } +} + +Bool +xnestCreateDefaultColormap(ScreenPtr pScreen) +{ + VisualPtr pVisual; + ColormapPtr pCmap; + unsigned short zero = 0, ones = 0xFFFF; + Pixel wp, bp; + + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++); + + if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &pCmap, + (pVisual->class & DynamicClass) ? AllocNone : AllocAll, 0) + != Success) + return False; + + wp = pScreen->whitePixel; + bp = pScreen->blackPixel; + if ((AllocColor(pCmap, &ones, &ones, &ones, &wp, 0) != + Success) || + (AllocColor(pCmap, &zero, &zero, &zero, &bp, 0) != + Success)) + return FALSE; + pScreen->whitePixel = wp; + pScreen->blackPixel = bp; + (*pScreen->InstallColormap)(pCmap); + + xnestInstalledDefaultColormap = True; + + return True; +} diff --git a/xorg-server/hw/xnest/Cursor.c b/xorg-server/hw/xnest/Cursor.c index 12f47e725..290074d4e 100644 --- a/xorg-server/hw/xnest/Cursor.c +++ b/xorg-server/hw/xnest/Cursor.c @@ -1,183 +1,183 @@ -/* - -Copyright 1993 by Davor Matic - -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. Davor Matic makes no representations about -the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. - -*/ - -#ifdef HAVE_XNEST_CONFIG_H -#include <xnest-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "screenint.h" -#include "input.h" -#include "misc.h" -#include "cursor.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "servermd.h" -#include "mipointrst.h" - -#include "Xnest.h" - -#include "Display.h" -#include "Screen.h" -#include "XNCursor.h" -#include "Visual.h" -#include "Keyboard.h" -#include "Args.h" - -xnestCursorFuncRec xnestCursorFuncs = {NULL}; - -Bool -xnestRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - XImage *ximage; - Pixmap source, mask; - XColor fg_color, bg_color; - unsigned long valuemask; - XGCValues values; - - valuemask = GCFunction | - GCPlaneMask | - GCForeground | - GCBackground | - GCClipMask; - - values.function = GXcopy; - values.plane_mask = AllPlanes; - values.foreground = 1L; - values.background = 0L; - values.clip_mask = None; - - XChangeGC(xnestDisplay, xnestBitmapGC, valuemask, &values); - - source = XCreatePixmap(xnestDisplay, - xnestDefaultWindows[pScreen->myNum], - pCursor->bits->width, - pCursor->bits->height, - 1); - - mask = XCreatePixmap(xnestDisplay, - xnestDefaultWindows[pScreen->myNum], - pCursor->bits->width, - pCursor->bits->height, - 1); - - ximage = XCreateImage(xnestDisplay, - xnestDefaultVisual(pScreen), - 1, XYBitmap, 0, - (char *)pCursor->bits->source, - pCursor->bits->width, - pCursor->bits->height, - BitmapPad(xnestDisplay), 0); - - XPutImage(xnestDisplay, source, xnestBitmapGC, ximage, - 0, 0, 0, 0, pCursor->bits->width, pCursor->bits->height); - - XFree(ximage); - - ximage = XCreateImage(xnestDisplay, - xnestDefaultVisual(pScreen), - 1, XYBitmap, 0, - (char *)pCursor->bits->mask, - pCursor->bits->width, - pCursor->bits->height, - BitmapPad(xnestDisplay), 0); - - XPutImage(xnestDisplay, mask, xnestBitmapGC, ximage, - 0, 0, 0, 0, pCursor->bits->width, pCursor->bits->height); - - XFree(ximage); - - fg_color.red = pCursor->foreRed; - fg_color.green = pCursor->foreGreen; - fg_color.blue = pCursor->foreBlue; - - bg_color.red = pCursor->backRed; - bg_color.green = pCursor->backGreen; - bg_color.blue = pCursor->backBlue; - - xnestSetCursorPriv(pCursor, pScreen, xalloc(sizeof(xnestPrivCursor))); - xnestCursor(pCursor, pScreen) = - XCreatePixmapCursor(xnestDisplay, source, mask, &fg_color, &bg_color, - pCursor->bits->xhot, pCursor->bits->yhot); - - XFreePixmap(xnestDisplay, source); - XFreePixmap(xnestDisplay, mask); - - return True; -} - -Bool -xnestUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - XFreeCursor(xnestDisplay, xnestCursor(pCursor, pScreen)); - xfree(xnestGetCursorPriv(pCursor, pScreen)); - return True; -} - -void -xnestRecolorCursor(ScreenPtr pScreen, CursorPtr pCursor, Bool displayed) -{ - XColor fg_color, bg_color; - - fg_color.red = pCursor->foreRed; - fg_color.green = pCursor->foreGreen; - fg_color.blue = pCursor->foreBlue; - - bg_color.red = pCursor->backRed; - bg_color.green = pCursor->backGreen; - bg_color.blue = pCursor->backBlue; - - XRecolorCursor(xnestDisplay, - xnestCursor(pCursor, pScreen), - &fg_color, &bg_color); -} - -void xnestSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) -{ - if (pCursor) - { - XDefineCursor(xnestDisplay, - xnestDefaultWindows[pScreen->myNum], - xnestCursor(pCursor, pScreen)); - } -} - -void -xnestMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ -} - -Bool -xnestDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - xnestCursorFuncPtr pScreenPriv; - - pScreenPriv = (xnestCursorFuncPtr) - dixLookupPrivate(&pScreen->devPrivates, xnestCursorScreenKey); - - pScreenPriv->spriteFuncs->DeviceCursorInitialize(pDev, pScreen); - return TRUE; -} - -void -xnestDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - xnestCursorFuncPtr pScreenPriv; - - pScreenPriv = (xnestCursorFuncPtr) - dixLookupPrivate(&pScreen->devPrivates, xnestCursorScreenKey); - - pScreenPriv->spriteFuncs->DeviceCursorCleanup(pDev, pScreen); -} +/* + +Copyright 1993 by Davor Matic + +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. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "screenint.h" +#include "input.h" +#include "misc.h" +#include "cursor.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "servermd.h" +#include "mipointrst.h" + +#include "Xnest.h" + +#include "Display.h" +#include "Screen.h" +#include "XNCursor.h" +#include "Visual.h" +#include "Keyboard.h" +#include "Args.h" + +xnestCursorFuncRec xnestCursorFuncs = {NULL}; + +Bool +xnestRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + XImage *ximage; + Pixmap source, mask; + XColor fg_color, bg_color; + unsigned long valuemask; + XGCValues values; + + valuemask = GCFunction | + GCPlaneMask | + GCForeground | + GCBackground | + GCClipMask; + + values.function = GXcopy; + values.plane_mask = AllPlanes; + values.foreground = 1L; + values.background = 0L; + values.clip_mask = None; + + XChangeGC(xnestDisplay, xnestBitmapGC, valuemask, &values); + + source = XCreatePixmap(xnestDisplay, + xnestDefaultWindows[pScreen->myNum], + pCursor->bits->width, + pCursor->bits->height, + 1); + + mask = XCreatePixmap(xnestDisplay, + xnestDefaultWindows[pScreen->myNum], + pCursor->bits->width, + pCursor->bits->height, + 1); + + ximage = XCreateImage(xnestDisplay, + xnestDefaultVisual(pScreen), + 1, XYBitmap, 0, + (char *)pCursor->bits->source, + pCursor->bits->width, + pCursor->bits->height, + BitmapPad(xnestDisplay), 0); + + XPutImage(xnestDisplay, source, xnestBitmapGC, ximage, + 0, 0, 0, 0, pCursor->bits->width, pCursor->bits->height); + + XFree(ximage); + + ximage = XCreateImage(xnestDisplay, + xnestDefaultVisual(pScreen), + 1, XYBitmap, 0, + (char *)pCursor->bits->mask, + pCursor->bits->width, + pCursor->bits->height, + BitmapPad(xnestDisplay), 0); + + XPutImage(xnestDisplay, mask, xnestBitmapGC, ximage, + 0, 0, 0, 0, pCursor->bits->width, pCursor->bits->height); + + XFree(ximage); + + fg_color.red = pCursor->foreRed; + fg_color.green = pCursor->foreGreen; + fg_color.blue = pCursor->foreBlue; + + bg_color.red = pCursor->backRed; + bg_color.green = pCursor->backGreen; + bg_color.blue = pCursor->backBlue; + + xnestSetCursorPriv(pCursor, pScreen, malloc(sizeof(xnestPrivCursor))); + xnestCursor(pCursor, pScreen) = + XCreatePixmapCursor(xnestDisplay, source, mask, &fg_color, &bg_color, + pCursor->bits->xhot, pCursor->bits->yhot); + + XFreePixmap(xnestDisplay, source); + XFreePixmap(xnestDisplay, mask); + + return True; +} + +Bool +xnestUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + XFreeCursor(xnestDisplay, xnestCursor(pCursor, pScreen)); + free(xnestGetCursorPriv(pCursor, pScreen)); + return True; +} + +void +xnestRecolorCursor(ScreenPtr pScreen, CursorPtr pCursor, Bool displayed) +{ + XColor fg_color, bg_color; + + fg_color.red = pCursor->foreRed; + fg_color.green = pCursor->foreGreen; + fg_color.blue = pCursor->foreBlue; + + bg_color.red = pCursor->backRed; + bg_color.green = pCursor->backGreen; + bg_color.blue = pCursor->backBlue; + + XRecolorCursor(xnestDisplay, + xnestCursor(pCursor, pScreen), + &fg_color, &bg_color); +} + +void xnestSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ + if (pCursor) + { + XDefineCursor(xnestDisplay, + xnestDefaultWindows[pScreen->myNum], + xnestCursor(pCursor, pScreen)); + } +} + +void +xnestMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ +} + +Bool +xnestDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + xnestCursorFuncPtr pScreenPriv; + + pScreenPriv = (xnestCursorFuncPtr) + dixLookupPrivate(&pScreen->devPrivates, xnestCursorScreenKey); + + pScreenPriv->spriteFuncs->DeviceCursorInitialize(pDev, pScreen); + return TRUE; +} + +void +xnestDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + xnestCursorFuncPtr pScreenPriv; + + pScreenPriv = (xnestCursorFuncPtr) + dixLookupPrivate(&pScreen->devPrivates, xnestCursorScreenKey); + + pScreenPriv->spriteFuncs->DeviceCursorCleanup(pDev, pScreen); +} diff --git a/xorg-server/hw/xnest/Display.c b/xorg-server/hw/xnest/Display.c index 01290417c..72c640186 100644 --- a/xorg-server/hw/xnest/Display.c +++ b/xorg-server/hw/xnest/Display.c @@ -1,193 +1,193 @@ -/* - -Copyright 1993 by Davor Matic - -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. Davor Matic makes no representations about -the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. - -*/ - - -#ifdef HAVE_XNEST_CONFIG_H -#include <xnest-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "screenint.h" -#include "input.h" -#include "misc.h" -#include "scrnintstr.h" -#include "servermd.h" - -#include "Xnest.h" - -#include "Display.h" -#include "Init.h" -#include "Args.h" - -#include "icon" -#include "screensaver" - -Display *xnestDisplay = NULL; -XVisualInfo *xnestVisuals; -int xnestNumVisuals; -int xnestDefaultVisualIndex; -Colormap *xnestDefaultColormaps; -static int xnestNumDefaultColormaps; -int *xnestDepths; -int xnestNumDepths; -XPixmapFormatValues *xnestPixmapFormats; -int xnestNumPixmapFormats; -Pixel xnestBlackPixel; -Pixel xnestWhitePixel; -Drawable xnestDefaultDrawables[MAXDEPTH + 1]; -Pixmap xnestIconBitmap; -Pixmap xnestScreenSaverPixmap; -XlibGC xnestBitmapGC; -unsigned long xnestEventMask; - -void -xnestOpenDisplay(int argc, char *argv[]) -{ - XVisualInfo vi; - long mask; - int i, j; - - if (!xnestDoFullGeneration) return; - - xnestCloseDisplay(); - - xnestDisplay = XOpenDisplay(xnestDisplayName); - if (xnestDisplay == NULL) - FatalError("Unable to open display \"%s\".\n", - XDisplayName(xnestDisplayName)); - - if (xnestSynchronize) - XSynchronize(xnestDisplay, True); - - mask = VisualScreenMask; - vi.screen = DefaultScreen(xnestDisplay); - xnestVisuals = XGetVisualInfo(xnestDisplay, mask, &vi, &xnestNumVisuals); - if (xnestNumVisuals == 0 || xnestVisuals == NULL) - FatalError("Unable to find any visuals.\n"); - - if (xnestUserDefaultClass || xnestUserDefaultDepth) { - xnestDefaultVisualIndex = UNDEFINED; - for (i = 0; i < xnestNumVisuals; i++) - if ((!xnestUserDefaultClass || - xnestVisuals[i].class == xnestDefaultClass) - && - (!xnestUserDefaultDepth || - xnestVisuals[i].depth == xnestDefaultDepth)) { - xnestDefaultVisualIndex = i; - break; - } - if (xnestDefaultVisualIndex == UNDEFINED) - FatalError("Unable to find desired default visual.\n"); - } - else { - vi.visualid = XVisualIDFromVisual(DefaultVisual(xnestDisplay, - DefaultScreen(xnestDisplay))); - xnestDefaultVisualIndex = 0; - for (i = 0; i < xnestNumVisuals; i++) - if (vi.visualid == xnestVisuals[i].visualid) - xnestDefaultVisualIndex = i; - } - - xnestNumDefaultColormaps = xnestNumVisuals; - xnestDefaultColormaps = (Colormap *)xalloc(xnestNumDefaultColormaps * - sizeof(Colormap)); - for (i = 0; i < xnestNumDefaultColormaps; i++) - xnestDefaultColormaps[i] = XCreateColormap(xnestDisplay, - DefaultRootWindow(xnestDisplay), - xnestVisuals[i].visual, - AllocNone); - - xnestDepths = XListDepths(xnestDisplay, DefaultScreen(xnestDisplay), - &xnestNumDepths); - - xnestPixmapFormats = XListPixmapFormats(xnestDisplay, - &xnestNumPixmapFormats); - - xnestBlackPixel = BlackPixel(xnestDisplay, DefaultScreen(xnestDisplay)); - xnestWhitePixel = WhitePixel(xnestDisplay, DefaultScreen(xnestDisplay)); - - if (xnestParentWindow != (Window) 0) - xnestEventMask = StructureNotifyMask; - else - xnestEventMask = 0L; - - for (i = 0; i <= MAXDEPTH; i++) - xnestDefaultDrawables[i] = None; - - for (i = 0; i < xnestNumPixmapFormats; i++) - for (j = 0; j < xnestNumDepths; j++) - if (xnestPixmapFormats[i].depth == 1 || - xnestPixmapFormats[i].depth == xnestDepths[j]) { - xnestDefaultDrawables[xnestPixmapFormats[i].depth] = - XCreatePixmap(xnestDisplay, DefaultRootWindow(xnestDisplay), - 1, 1, xnestPixmapFormats[i].depth); - } - - xnestBitmapGC = XCreateGC(xnestDisplay, xnestDefaultDrawables[1], 0L, NULL); - - if (!(xnestUserGeometry & XValue)) - xnestX = 0; - - if (!(xnestUserGeometry & YValue)) - xnestY = 0; - - if (xnestParentWindow == 0) { - if (!(xnestUserGeometry & WidthValue)) - xnestWidth = 3 * DisplayWidth(xnestDisplay, - DefaultScreen(xnestDisplay)) / 4; - - if (!(xnestUserGeometry & HeightValue)) - xnestHeight = 3 * DisplayHeight(xnestDisplay, - DefaultScreen(xnestDisplay)) / 4; - } - - if (!xnestUserBorderWidth) - xnestBorderWidth = 1; - - xnestIconBitmap = - XCreateBitmapFromData(xnestDisplay, - DefaultRootWindow(xnestDisplay), - (char *)icon_bits, - icon_width, - icon_height); - - xnestScreenSaverPixmap = - XCreatePixmapFromBitmapData(xnestDisplay, - DefaultRootWindow(xnestDisplay), - (char *)screensaver_bits, - screensaver_width, - screensaver_height, - xnestWhitePixel, - xnestBlackPixel, - DefaultDepth(xnestDisplay, - DefaultScreen(xnestDisplay))); -} - -void -xnestCloseDisplay(void) -{ - if (!xnestDoFullGeneration || !xnestDisplay) return; - - /* - If xnestDoFullGeneration all x resources will be destroyed upon closing - the display connection. There is no need to generate extra protocol. - */ - - xfree(xnestDefaultColormaps); - XFree(xnestVisuals); - XFree(xnestDepths); - XFree(xnestPixmapFormats); - XCloseDisplay(xnestDisplay); -} +/* + +Copyright 1993 by Davor Matic + +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. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "screenint.h" +#include "input.h" +#include "misc.h" +#include "scrnintstr.h" +#include "servermd.h" + +#include "Xnest.h" + +#include "Display.h" +#include "Init.h" +#include "Args.h" + +#include "icon" +#include "screensaver" + +Display *xnestDisplay = NULL; +XVisualInfo *xnestVisuals; +int xnestNumVisuals; +int xnestDefaultVisualIndex; +Colormap *xnestDefaultColormaps; +static int xnestNumDefaultColormaps; +int *xnestDepths; +int xnestNumDepths; +XPixmapFormatValues *xnestPixmapFormats; +int xnestNumPixmapFormats; +Pixel xnestBlackPixel; +Pixel xnestWhitePixel; +Drawable xnestDefaultDrawables[MAXDEPTH + 1]; +Pixmap xnestIconBitmap; +Pixmap xnestScreenSaverPixmap; +XlibGC xnestBitmapGC; +unsigned long xnestEventMask; + +void +xnestOpenDisplay(int argc, char *argv[]) +{ + XVisualInfo vi; + long mask; + int i, j; + + if (!xnestDoFullGeneration) return; + + xnestCloseDisplay(); + + xnestDisplay = XOpenDisplay(xnestDisplayName); + if (xnestDisplay == NULL) + FatalError("Unable to open display \"%s\".\n", + XDisplayName(xnestDisplayName)); + + if (xnestSynchronize) + XSynchronize(xnestDisplay, True); + + mask = VisualScreenMask; + vi.screen = DefaultScreen(xnestDisplay); + xnestVisuals = XGetVisualInfo(xnestDisplay, mask, &vi, &xnestNumVisuals); + if (xnestNumVisuals == 0 || xnestVisuals == NULL) + FatalError("Unable to find any visuals.\n"); + + if (xnestUserDefaultClass || xnestUserDefaultDepth) { + xnestDefaultVisualIndex = UNDEFINED; + for (i = 0; i < xnestNumVisuals; i++) + if ((!xnestUserDefaultClass || + xnestVisuals[i].class == xnestDefaultClass) + && + (!xnestUserDefaultDepth || + xnestVisuals[i].depth == xnestDefaultDepth)) { + xnestDefaultVisualIndex = i; + break; + } + if (xnestDefaultVisualIndex == UNDEFINED) + FatalError("Unable to find desired default visual.\n"); + } + else { + vi.visualid = XVisualIDFromVisual(DefaultVisual(xnestDisplay, + DefaultScreen(xnestDisplay))); + xnestDefaultVisualIndex = 0; + for (i = 0; i < xnestNumVisuals; i++) + if (vi.visualid == xnestVisuals[i].visualid) + xnestDefaultVisualIndex = i; + } + + xnestNumDefaultColormaps = xnestNumVisuals; + xnestDefaultColormaps = (Colormap *)malloc(xnestNumDefaultColormaps * + sizeof(Colormap)); + for (i = 0; i < xnestNumDefaultColormaps; i++) + xnestDefaultColormaps[i] = XCreateColormap(xnestDisplay, + DefaultRootWindow(xnestDisplay), + xnestVisuals[i].visual, + AllocNone); + + xnestDepths = XListDepths(xnestDisplay, DefaultScreen(xnestDisplay), + &xnestNumDepths); + + xnestPixmapFormats = XListPixmapFormats(xnestDisplay, + &xnestNumPixmapFormats); + + xnestBlackPixel = BlackPixel(xnestDisplay, DefaultScreen(xnestDisplay)); + xnestWhitePixel = WhitePixel(xnestDisplay, DefaultScreen(xnestDisplay)); + + if (xnestParentWindow != (Window) 0) + xnestEventMask = StructureNotifyMask; + else + xnestEventMask = 0L; + + for (i = 0; i <= MAXDEPTH; i++) + xnestDefaultDrawables[i] = None; + + for (i = 0; i < xnestNumPixmapFormats; i++) + for (j = 0; j < xnestNumDepths; j++) + if (xnestPixmapFormats[i].depth == 1 || + xnestPixmapFormats[i].depth == xnestDepths[j]) { + xnestDefaultDrawables[xnestPixmapFormats[i].depth] = + XCreatePixmap(xnestDisplay, DefaultRootWindow(xnestDisplay), + 1, 1, xnestPixmapFormats[i].depth); + } + + xnestBitmapGC = XCreateGC(xnestDisplay, xnestDefaultDrawables[1], 0L, NULL); + + if (!(xnestUserGeometry & XValue)) + xnestX = 0; + + if (!(xnestUserGeometry & YValue)) + xnestY = 0; + + if (xnestParentWindow == 0) { + if (!(xnestUserGeometry & WidthValue)) + xnestWidth = 3 * DisplayWidth(xnestDisplay, + DefaultScreen(xnestDisplay)) / 4; + + if (!(xnestUserGeometry & HeightValue)) + xnestHeight = 3 * DisplayHeight(xnestDisplay, + DefaultScreen(xnestDisplay)) / 4; + } + + if (!xnestUserBorderWidth) + xnestBorderWidth = 1; + + xnestIconBitmap = + XCreateBitmapFromData(xnestDisplay, + DefaultRootWindow(xnestDisplay), + (char *)icon_bits, + icon_width, + icon_height); + + xnestScreenSaverPixmap = + XCreatePixmapFromBitmapData(xnestDisplay, + DefaultRootWindow(xnestDisplay), + (char *)screensaver_bits, + screensaver_width, + screensaver_height, + xnestWhitePixel, + xnestBlackPixel, + DefaultDepth(xnestDisplay, + DefaultScreen(xnestDisplay))); +} + +void +xnestCloseDisplay(void) +{ + if (!xnestDoFullGeneration || !xnestDisplay) return; + + /* + If xnestDoFullGeneration all x resources will be destroyed upon closing + the display connection. There is no need to generate extra protocol. + */ + + free(xnestDefaultColormaps); + XFree(xnestVisuals); + XFree(xnestDepths); + XFree(xnestPixmapFormats); + XCloseDisplay(xnestDisplay); +} diff --git a/xorg-server/hw/xnest/Font.c b/xorg-server/hw/xnest/Font.c index 7b388f0f4..87e622680 100644 --- a/xorg-server/hw/xnest/Font.c +++ b/xorg-server/hw/xnest/Font.c @@ -1,86 +1,86 @@ -/* - -Copyright 1993 by Davor Matic - -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. Davor Matic makes no representations about -the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. - -*/ - -#ifdef HAVE_XNEST_CONFIG_H -#include <xnest-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xatom.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "regionstr.h" -#include <X11/fonts/font.h> -#include <X11/fonts/fontstruct.h> -#include "scrnintstr.h" - -#include "Xnest.h" - -#include "Display.h" -#include "XNFont.h" - -int xnestFontPrivateIndex; - -Bool -xnestRealizeFont(ScreenPtr pScreen, FontPtr pFont) -{ - pointer priv; - Atom name_atom, value_atom; - int nprops; - FontPropPtr props; - int i; - const char *name; - - FontSetPrivate(pFont, xnestFontPrivateIndex, NULL); - - name_atom = MakeAtom("FONT", 4, True); - value_atom = 0L; - - nprops = pFont->info.nprops; - props = pFont->info.props; - - for (i = 0; i < nprops; i++) - if (props[i].name == name_atom) { - value_atom = props[i].value; - break; - } - - if (!value_atom) return False; - - name = NameForAtom(value_atom); - - if (!name) return False; - - priv = (pointer)xalloc(sizeof(xnestPrivFont)); - FontSetPrivate(pFont, xnestFontPrivateIndex, priv); - - xnestFontPriv(pFont)->font_struct = XLoadQueryFont(xnestDisplay, name); - - if (!xnestFontStruct(pFont)) return False; - - return True; -} - - -Bool -xnestUnrealizeFont(ScreenPtr pScreen, FontPtr pFont) -{ - if (xnestFontPriv(pFont)) { - if (xnestFontStruct(pFont)) - XFreeFont(xnestDisplay, xnestFontStruct(pFont)); - xfree(xnestFontPriv(pFont)); - FontSetPrivate(pFont, xnestFontPrivateIndex, NULL); - } - return True; -} +/* + +Copyright 1993 by Davor Matic + +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. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xatom.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "regionstr.h" +#include <X11/fonts/font.h> +#include <X11/fonts/fontstruct.h> +#include "scrnintstr.h" + +#include "Xnest.h" + +#include "Display.h" +#include "XNFont.h" + +int xnestFontPrivateIndex; + +Bool +xnestRealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + pointer priv; + Atom name_atom, value_atom; + int nprops; + FontPropPtr props; + int i; + const char *name; + + FontSetPrivate(pFont, xnestFontPrivateIndex, NULL); + + name_atom = MakeAtom("FONT", 4, True); + value_atom = 0L; + + nprops = pFont->info.nprops; + props = pFont->info.props; + + for (i = 0; i < nprops; i++) + if (props[i].name == name_atom) { + value_atom = props[i].value; + break; + } + + if (!value_atom) return False; + + name = NameForAtom(value_atom); + + if (!name) return False; + + priv = (pointer)malloc(sizeof(xnestPrivFont)); + FontSetPrivate(pFont, xnestFontPrivateIndex, priv); + + xnestFontPriv(pFont)->font_struct = XLoadQueryFont(xnestDisplay, name); + + if (!xnestFontStruct(pFont)) return False; + + return True; +} + + +Bool +xnestUnrealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + if (xnestFontPriv(pFont)) { + if (xnestFontStruct(pFont)) + XFreeFont(xnestDisplay, xnestFontStruct(pFont)); + free(xnestFontPriv(pFont)); + FontSetPrivate(pFont, xnestFontPrivateIndex, NULL); + } + return True; +} diff --git a/xorg-server/hw/xnest/GC.c b/xorg-server/hw/xnest/GC.c index 65425e98f..9df015728 100644 --- a/xorg-server/hw/xnest/GC.c +++ b/xorg-server/hw/xnest/GC.c @@ -1,339 +1,339 @@ -/* - -Copyright 1993 by Davor Matic - -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. Davor Matic makes no representations about -the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. - -*/ - -#ifdef HAVE_XNEST_CONFIG_H -#include <xnest-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "gcstruct.h" -#include "windowstr.h" -#include "pixmapstr.h" -#include "scrnintstr.h" -#include <X11/fonts/fontstruct.h> -#include "mistruct.h" -#include "region.h" - -#include "Xnest.h" - -#include "Display.h" -#include "XNGC.h" -#include "GCOps.h" -#include "Drawable.h" -#include "XNFont.h" -#include "Color.h" - -static int xnestGCPrivateKeyIndex; -DevPrivateKey xnestGCPrivateKey = &xnestGCPrivateKeyIndex; - -static GCFuncs xnestFuncs = { - xnestValidateGC, - xnestChangeGC, - xnestCopyGC, - xnestDestroyGC, - xnestChangeClip, - xnestDestroyClip, - xnestCopyClip, -}; - -static GCOps xnestOps = { - xnestFillSpans, - xnestSetSpans, - xnestPutImage, - xnestCopyArea, - xnestCopyPlane, - xnestPolyPoint, - xnestPolylines, - xnestPolySegment, - xnestPolyRectangle, - xnestPolyArc, - xnestFillPolygon, - xnestPolyFillRect, - xnestPolyFillArc, - xnestPolyText8, - xnestPolyText16, - xnestImageText8, - xnestImageText16, - xnestImageGlyphBlt, - xnestPolyGlyphBlt, - xnestPushPixels -}; - -Bool -xnestCreateGC(GCPtr pGC) -{ - pGC->clientClipType = CT_NONE; - pGC->clientClip = NULL; - - pGC->funcs = &xnestFuncs; - pGC->ops = &xnestOps; - - pGC->miTranslate = 1; - - xnestGCPriv(pGC)->gc = XCreateGC(xnestDisplay, - xnestDefaultDrawables[pGC->depth], - 0L, NULL); - xnestGCPriv(pGC)->nClipRects = 0; - - return True; -} - -void -xnestValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) -{ - pGC->lastWinOrg.x = pDrawable->x; - pGC->lastWinOrg.y = pDrawable->y; -} - -void -xnestChangeGC(GCPtr pGC, unsigned long mask) -{ - XGCValues values; - - if (mask & GCFunction) - values.function = pGC->alu; - - if (mask & GCPlaneMask) - values.plane_mask = pGC->planemask; - - if (mask & GCForeground) - values.foreground = xnestPixel(pGC->fgPixel); - - if (mask & GCBackground) - values.background = xnestPixel(pGC->bgPixel); - - if (mask & GCLineWidth) - values.line_width = pGC->lineWidth; - - if (mask & GCLineStyle) - values.line_style = pGC->lineStyle; - - if (mask & GCCapStyle) - values.cap_style = pGC->capStyle; - - if (mask & GCJoinStyle) - values.join_style = pGC->joinStyle; - - if (mask & GCFillStyle) - values.fill_style = pGC->fillStyle; - - if (mask & GCFillRule) - values.fill_rule = pGC->fillRule; - - if (mask & GCTile) { - if (pGC->tileIsPixel) - mask &= ~GCTile; - else - values.tile = xnestPixmap(pGC->tile.pixmap); - } - - if (mask & GCStipple) - values.stipple = xnestPixmap(pGC->stipple); - - if (mask & GCTileStipXOrigin) - values.ts_x_origin = pGC->patOrg.x; - - if (mask & GCTileStipYOrigin) - values.ts_y_origin = pGC->patOrg.y; - - if (mask & GCFont) - values.font = xnestFont(pGC->font); - - if (mask & GCSubwindowMode) - values.subwindow_mode = pGC->subWindowMode; - - if (mask & GCGraphicsExposures) - values.graphics_exposures = pGC->graphicsExposures; - - if (mask & GCClipXOrigin) - values.clip_x_origin = pGC->clipOrg.x; - - if (mask & GCClipYOrigin) - values.clip_y_origin = pGC->clipOrg.y; - - if (mask & GCClipMask) /* this is handled in change clip */ - mask &= ~GCClipMask; - - if (mask & GCDashOffset) - values.dash_offset = pGC->dashOffset; - - if (mask & GCDashList) { - mask &= ~GCDashList; - XSetDashes(xnestDisplay, xnestGC(pGC), - pGC->dashOffset, (char *)pGC->dash, pGC->numInDashList); - } - - if (mask & GCArcMode) - values.arc_mode = pGC->arcMode; - - if (mask) - XChangeGC(xnestDisplay, xnestGC(pGC), mask, &values); -} - -void -xnestCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) -{ - XCopyGC(xnestDisplay, xnestGC(pGCSrc), mask, xnestGC(pGCDst)); -} - -void -xnestDestroyGC(GCPtr pGC) -{ - XFreeGC(xnestDisplay, xnestGC(pGC)); -} - -void -xnestChangeClip(GCPtr pGC, int type, pointer pValue, int nRects) -{ - int i, size; - BoxPtr pBox; - XRectangle *pRects; - - xnestDestroyClipHelper(pGC); - - switch(type) - { - case CT_NONE: - XSetClipMask(xnestDisplay, xnestGC(pGC), None); - break; - - case CT_REGION: - nRects = REGION_NUM_RECTS((RegionPtr)pValue); - size = nRects * sizeof(*pRects); - pRects = (XRectangle *) xalloc(size); - pBox = REGION_RECTS((RegionPtr)pValue); - for (i = nRects; i-- > 0; ) { - pRects[i].x = pBox[i].x1; - pRects[i].y = pBox[i].y1; - pRects[i].width = pBox[i].x2 - pBox[i].x1; - pRects[i].height = pBox[i].y2 - pBox[i].y1; - } - XSetClipRectangles(xnestDisplay, xnestGC(pGC), 0, 0, - pRects, nRects, Unsorted); - xfree((char *) pRects); - break; - - case CT_PIXMAP: - XSetClipMask(xnestDisplay, xnestGC(pGC), - xnestPixmap((PixmapPtr)pValue)); - /* - * Need to change into region, so subsequent uses are with - * current pixmap contents. - */ - pGC->clientClip = (pointer) (*pGC->pScreen->BitmapToRegion)((PixmapPtr)pValue); - (*pGC->pScreen->DestroyPixmap)((PixmapPtr)pValue); - pValue = pGC->clientClip; - type = CT_REGION; - break; - - case CT_UNSORTED: - XSetClipRectangles(xnestDisplay, xnestGC(pGC), - pGC->clipOrg.x, pGC->clipOrg.y, - (XRectangle *)pValue, nRects, Unsorted); - break; - - case CT_YSORTED: - XSetClipRectangles(xnestDisplay, xnestGC(pGC), - pGC->clipOrg.x, pGC->clipOrg.y, - (XRectangle *)pValue, nRects, YSorted); - break; - - case CT_YXSORTED: - XSetClipRectangles(xnestDisplay, xnestGC(pGC), - pGC->clipOrg.x, pGC->clipOrg.y, - (XRectangle *)pValue, nRects, YXSorted); - break; - - case CT_YXBANDED: - XSetClipRectangles(xnestDisplay, xnestGC(pGC), - pGC->clipOrg.x, pGC->clipOrg.y, - (XRectangle *)pValue, nRects, YXBanded); - break; - } - - switch(type) - { - default: - break; - - case CT_UNSORTED: - case CT_YSORTED: - case CT_YXSORTED: - case CT_YXBANDED: - - /* - * other parts of server can only deal with CT_NONE, - * CT_PIXMAP and CT_REGION client clips. - */ - pGC->clientClip = (pointer) RECTS_TO_REGION(pGC->pScreen, nRects, - (xRectangle *)pValue, type); - xfree(pValue); - pValue = pGC->clientClip; - type = CT_REGION; - - break; - } - - pGC->clientClipType = type; - pGC->clientClip = pValue; - xnestGCPriv(pGC)->nClipRects = nRects; -} - -void -xnestDestroyClip(GCPtr pGC) -{ - xnestDestroyClipHelper(pGC); - - XSetClipMask(xnestDisplay, xnestGC(pGC), None); - - pGC->clientClipType = CT_NONE; - pGC->clientClip = NULL; - xnestGCPriv(pGC)->nClipRects = 0; -} - -void -xnestDestroyClipHelper(GCPtr pGC) -{ - switch (pGC->clientClipType) - { - default: - case CT_NONE: - break; - - case CT_REGION: - REGION_DESTROY(pGC->pScreen, pGC->clientClip); - break; - } -} - -void -xnestCopyClip(GCPtr pGCDst, GCPtr pGCSrc) -{ - RegionPtr pRgn; - - switch (pGCSrc->clientClipType) - { - default: - case CT_NONE: - xnestDestroyClip(pGCDst); - break; - - case CT_REGION: - pRgn = REGION_CREATE(pGCDst->pScreen, NULL, 1); - REGION_COPY(pGCDst->pScreen, pRgn, pGCSrc->clientClip); - xnestChangeClip(pGCDst, CT_REGION, pRgn, 0); - break; - } -} +/* + +Copyright 1993 by Davor Matic + +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. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "scrnintstr.h" +#include <X11/fonts/fontstruct.h> +#include "mistruct.h" +#include "region.h" + +#include "Xnest.h" + +#include "Display.h" +#include "XNGC.h" +#include "GCOps.h" +#include "Drawable.h" +#include "XNFont.h" +#include "Color.h" + +static int xnestGCPrivateKeyIndex; +DevPrivateKey xnestGCPrivateKey = &xnestGCPrivateKeyIndex; + +static GCFuncs xnestFuncs = { + xnestValidateGC, + xnestChangeGC, + xnestCopyGC, + xnestDestroyGC, + xnestChangeClip, + xnestDestroyClip, + xnestCopyClip, +}; + +static GCOps xnestOps = { + xnestFillSpans, + xnestSetSpans, + xnestPutImage, + xnestCopyArea, + xnestCopyPlane, + xnestPolyPoint, + xnestPolylines, + xnestPolySegment, + xnestPolyRectangle, + xnestPolyArc, + xnestFillPolygon, + xnestPolyFillRect, + xnestPolyFillArc, + xnestPolyText8, + xnestPolyText16, + xnestImageText8, + xnestImageText16, + xnestImageGlyphBlt, + xnestPolyGlyphBlt, + xnestPushPixels +}; + +Bool +xnestCreateGC(GCPtr pGC) +{ + pGC->clientClipType = CT_NONE; + pGC->clientClip = NULL; + + pGC->funcs = &xnestFuncs; + pGC->ops = &xnestOps; + + pGC->miTranslate = 1; + + xnestGCPriv(pGC)->gc = XCreateGC(xnestDisplay, + xnestDefaultDrawables[pGC->depth], + 0L, NULL); + xnestGCPriv(pGC)->nClipRects = 0; + + return True; +} + +void +xnestValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + pGC->lastWinOrg.x = pDrawable->x; + pGC->lastWinOrg.y = pDrawable->y; +} + +void +xnestChangeGC(GCPtr pGC, unsigned long mask) +{ + XGCValues values; + + if (mask & GCFunction) + values.function = pGC->alu; + + if (mask & GCPlaneMask) + values.plane_mask = pGC->planemask; + + if (mask & GCForeground) + values.foreground = xnestPixel(pGC->fgPixel); + + if (mask & GCBackground) + values.background = xnestPixel(pGC->bgPixel); + + if (mask & GCLineWidth) + values.line_width = pGC->lineWidth; + + if (mask & GCLineStyle) + values.line_style = pGC->lineStyle; + + if (mask & GCCapStyle) + values.cap_style = pGC->capStyle; + + if (mask & GCJoinStyle) + values.join_style = pGC->joinStyle; + + if (mask & GCFillStyle) + values.fill_style = pGC->fillStyle; + + if (mask & GCFillRule) + values.fill_rule = pGC->fillRule; + + if (mask & GCTile) { + if (pGC->tileIsPixel) + mask &= ~GCTile; + else + values.tile = xnestPixmap(pGC->tile.pixmap); + } + + if (mask & GCStipple) + values.stipple = xnestPixmap(pGC->stipple); + + if (mask & GCTileStipXOrigin) + values.ts_x_origin = pGC->patOrg.x; + + if (mask & GCTileStipYOrigin) + values.ts_y_origin = pGC->patOrg.y; + + if (mask & GCFont) + values.font = xnestFont(pGC->font); + + if (mask & GCSubwindowMode) + values.subwindow_mode = pGC->subWindowMode; + + if (mask & GCGraphicsExposures) + values.graphics_exposures = pGC->graphicsExposures; + + if (mask & GCClipXOrigin) + values.clip_x_origin = pGC->clipOrg.x; + + if (mask & GCClipYOrigin) + values.clip_y_origin = pGC->clipOrg.y; + + if (mask & GCClipMask) /* this is handled in change clip */ + mask &= ~GCClipMask; + + if (mask & GCDashOffset) + values.dash_offset = pGC->dashOffset; + + if (mask & GCDashList) { + mask &= ~GCDashList; + XSetDashes(xnestDisplay, xnestGC(pGC), + pGC->dashOffset, (char *)pGC->dash, pGC->numInDashList); + } + + if (mask & GCArcMode) + values.arc_mode = pGC->arcMode; + + if (mask) + XChangeGC(xnestDisplay, xnestGC(pGC), mask, &values); +} + +void +xnestCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) +{ + XCopyGC(xnestDisplay, xnestGC(pGCSrc), mask, xnestGC(pGCDst)); +} + +void +xnestDestroyGC(GCPtr pGC) +{ + XFreeGC(xnestDisplay, xnestGC(pGC)); +} + +void +xnestChangeClip(GCPtr pGC, int type, pointer pValue, int nRects) +{ + int i, size; + BoxPtr pBox; + XRectangle *pRects; + + xnestDestroyClipHelper(pGC); + + switch(type) + { + case CT_NONE: + XSetClipMask(xnestDisplay, xnestGC(pGC), None); + break; + + case CT_REGION: + nRects = REGION_NUM_RECTS((RegionPtr)pValue); + size = nRects * sizeof(*pRects); + pRects = (XRectangle *) malloc(size); + pBox = REGION_RECTS((RegionPtr)pValue); + for (i = nRects; i-- > 0; ) { + pRects[i].x = pBox[i].x1; + pRects[i].y = pBox[i].y1; + pRects[i].width = pBox[i].x2 - pBox[i].x1; + pRects[i].height = pBox[i].y2 - pBox[i].y1; + } + XSetClipRectangles(xnestDisplay, xnestGC(pGC), 0, 0, + pRects, nRects, Unsorted); + free((char *) pRects); + break; + + case CT_PIXMAP: + XSetClipMask(xnestDisplay, xnestGC(pGC), + xnestPixmap((PixmapPtr)pValue)); + /* + * Need to change into region, so subsequent uses are with + * current pixmap contents. + */ + pGC->clientClip = (pointer) (*pGC->pScreen->BitmapToRegion)((PixmapPtr)pValue); + (*pGC->pScreen->DestroyPixmap)((PixmapPtr)pValue); + pValue = pGC->clientClip; + type = CT_REGION; + break; + + case CT_UNSORTED: + XSetClipRectangles(xnestDisplay, xnestGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, Unsorted); + break; + + case CT_YSORTED: + XSetClipRectangles(xnestDisplay, xnestGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, YSorted); + break; + + case CT_YXSORTED: + XSetClipRectangles(xnestDisplay, xnestGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, YXSorted); + break; + + case CT_YXBANDED: + XSetClipRectangles(xnestDisplay, xnestGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, YXBanded); + break; + } + + switch(type) + { + default: + break; + + case CT_UNSORTED: + case CT_YSORTED: + case CT_YXSORTED: + case CT_YXBANDED: + + /* + * other parts of server can only deal with CT_NONE, + * CT_PIXMAP and CT_REGION client clips. + */ + pGC->clientClip = (pointer) RECTS_TO_REGION(pGC->pScreen, nRects, + (xRectangle *)pValue, type); + free(pValue); + pValue = pGC->clientClip; + type = CT_REGION; + + break; + } + + pGC->clientClipType = type; + pGC->clientClip = pValue; + xnestGCPriv(pGC)->nClipRects = nRects; +} + +void +xnestDestroyClip(GCPtr pGC) +{ + xnestDestroyClipHelper(pGC); + + XSetClipMask(xnestDisplay, xnestGC(pGC), None); + + pGC->clientClipType = CT_NONE; + pGC->clientClip = NULL; + xnestGCPriv(pGC)->nClipRects = 0; +} + +void +xnestDestroyClipHelper(GCPtr pGC) +{ + switch (pGC->clientClipType) + { + default: + case CT_NONE: + break; + + case CT_REGION: + REGION_DESTROY(pGC->pScreen, pGC->clientClip); + break; + } +} + +void +xnestCopyClip(GCPtr pGCDst, GCPtr pGCSrc) +{ + RegionPtr pRgn; + + switch (pGCSrc->clientClipType) + { + default: + case CT_NONE: + xnestDestroyClip(pGCDst); + break; + + case CT_REGION: + pRgn = REGION_CREATE(pGCDst->pScreen, NULL, 1); + REGION_COPY(pGCDst->pScreen, pRgn, pGCSrc->clientClip); + xnestChangeClip(pGCDst, CT_REGION, pRgn, 0); + break; + } +} diff --git a/xorg-server/hw/xnest/Keyboard.c b/xorg-server/hw/xnest/Keyboard.c index 1835c7071..473724a04 100644 --- a/xorg-server/hw/xnest/Keyboard.c +++ b/xorg-server/hw/xnest/Keyboard.c @@ -1,257 +1,257 @@ -/* - -Copyright 1993 by Davor Matic - -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. Davor Matic makes no representations about -the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. - -*/ - -#ifdef HAVE_XNEST_CONFIG_H -#include <xnest-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/keysym.h> -#include "screenint.h" -#include "inputstr.h" -#include "misc.h" -#include "scrnintstr.h" -#include "servermd.h" - -#include "Xnest.h" - -#include "Display.h" -#include "Screen.h" -#include "Keyboard.h" -#include "Args.h" -#include "Events.h" - -#include <X11/extensions/XKB.h> -#include "xkbsrv.h" -#include <X11/extensions/XKBconfig.h> - -extern Bool -XkbQueryExtension( - Display * /* dpy */, - int * /* opcodeReturn */, - int * /* eventBaseReturn */, - int * /* errorBaseReturn */, - int * /* majorRtrn */, - int * /* minorRtrn */ -); - -extern XkbDescPtr XkbGetKeyboard( - Display * /* dpy */, - unsigned int /* which */, - unsigned int /* deviceSpec */ -); - -extern Status XkbGetControls( - Display * /* dpy */, - unsigned long /* which */, - XkbDescPtr /* desc */ -); - -DeviceIntPtr xnestKeyboardDevice = NULL; - -void -xnestBell(int volume, DeviceIntPtr pDev, pointer ctrl, int cls) -{ - XBell(xnestDisplay, volume); -} - -void -DDXRingBell(int volume, int pitch, int duration) -{ - XBell(xnestDisplay, volume); -} - -void -xnestChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl *ctrl) -{ -#if 0 - unsigned long value_mask; - XKeyboardControl values; - int i; - - value_mask = KBKeyClickPercent | - KBBellPercent | - KBBellPitch | - KBBellDuration | - KBAutoRepeatMode; - - values.key_click_percent = ctrl->click; - values.bell_percent = ctrl->bell; - values.bell_pitch = ctrl->bell_pitch; - values.bell_duration = ctrl->bell_duration; - values.auto_repeat_mode = ctrl->autoRepeat ? - AutoRepeatModeOn : AutoRepeatModeOff; - - XChangeKeyboardControl(xnestDisplay, value_mask, &values); - - /* - value_mask = KBKey | KBAutoRepeatMode; - At this point, we need to walk through the vector and compare it - to the current server vector. If there are differences, report them. - */ - - value_mask = KBLed | KBLedMode; - for (i = 1; i <= 32; i++) { - values.led = i; - values.led_mode = (ctrl->leds & (1 << (i - 1))) ? LedModeOn : LedModeOff; - XChangeKeyboardControl(xnestDisplay, value_mask, &values); - } -#endif -} - -int -xnestKeyboardProc(DeviceIntPtr pDev, int onoff) -{ - KeySym *keymap; - int mapWidth; - int min_keycode, max_keycode; - KeySymsRec keySyms; - int i; - XKeyboardState values; - XkbDescPtr xkb; - int op, event, error, major, minor; - - switch (onoff) - { - case DEVICE_INIT: - XDisplayKeycodes(xnestDisplay, &min_keycode, &max_keycode); -#ifdef _XSERVER64 - { - KeySym64 *keymap64; - int i, len; - keymap64 = XGetKeyboardMapping(xnestDisplay, - min_keycode, - max_keycode - min_keycode + 1, - &mapWidth); - len = (max_keycode - min_keycode + 1) * mapWidth; - keymap = (KeySym *)xalloc(len * sizeof(KeySym)); - for(i = 0; i < len; ++i) - keymap[i] = keymap64[i]; - XFree(keymap64); - } -#else - keymap = XGetKeyboardMapping(xnestDisplay, - min_keycode, - max_keycode - min_keycode + 1, - &mapWidth); -#endif - - keySyms.minKeyCode = min_keycode; - keySyms.maxKeyCode = max_keycode; - keySyms.mapWidth = mapWidth; - keySyms.map = keymap; - - if (XkbQueryExtension(xnestDisplay, &op, &event, &error, &major, &minor) == 0) { - ErrorF("Unable to initialize XKEYBOARD extension.\n"); - goto XkbError; - } - xkb = XkbGetKeyboard(xnestDisplay, XkbGBN_AllComponentsMask, XkbUseCoreKbd); - if (xkb == NULL || xkb->geom == NULL) { - ErrorF("Couldn't get keyboard.\n"); - goto XkbError; - } - XkbGetControls(xnestDisplay, XkbAllControlsMask, xkb); - - InitKeyboardDeviceStruct(pDev, NULL, - xnestBell, xnestChangeKeyboardControl); - XkbDDXChangeControls(pDev, xkb->ctrls, xkb->ctrls); - XkbFreeKeyboard(xkb, 0, False); - xfree(keymap); - break; - case DEVICE_ON: - xnestEventMask |= XNEST_KEYBOARD_EVENT_MASK; - for (i = 0; i < xnestNumScreens; i++) - XSelectInput(xnestDisplay, xnestDefaultWindows[i], xnestEventMask); - break; - case DEVICE_OFF: - xnestEventMask &= ~XNEST_KEYBOARD_EVENT_MASK; - for (i = 0; i < xnestNumScreens; i++) - XSelectInput(xnestDisplay, xnestDefaultWindows[i], xnestEventMask); - break; - case DEVICE_CLOSE: - break; - } - return Success; - -XkbError: - XGetKeyboardControl(xnestDisplay, &values); - memmove((char *)defaultKeyboardControl.autoRepeats, - (char *)values.auto_repeats, - sizeof(values.auto_repeats)); - - InitKeyboardDeviceStruct(pDev, NULL, - xnestBell, xnestChangeKeyboardControl); - xfree(keymap); - return Success; -} - -Bool -LegalModifier(unsigned int key, DeviceIntPtr pDev) -{ - return TRUE; -} - -void -xnestUpdateModifierState(unsigned int state) -{ - DeviceIntPtr pDev = xnestKeyboardDevice; - KeyClassPtr keyc = pDev->key; - int i; - CARD8 mask; - int xkb_state; - - if (!pDev) - return; - - xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state); - state = state & 0xff; - - if (xkb_state == state) - return; - - for (i = 0, mask = 1; i < 8; i++, mask <<= 1) { - int key; - - /* Modifier is down, but shouldn't be - */ - if ((xkb_state & mask) && !(state & mask)) { - int count = keyc->modifierKeyCount[i]; - - for (key = 0; key < MAP_LENGTH; key++) - if (keyc->xkbInfo->desc->map->modmap[key] & mask) { - int bit; - BYTE *kptr; - - kptr = &keyc->down[key >> 3]; - bit = 1 << (key & 7); - - if (*kptr & bit) - xnestQueueKeyEvent(KeyRelease, key); - - if (--count == 0) - break; - } - } - - /* Modifier shoud be down, but isn't - */ - if (!(xkb_state & mask) && (state & mask)) - for (key = 0; key < MAP_LENGTH; key++) - if (keyc->xkbInfo->desc->map->modmap[key] & mask) { - xnestQueueKeyEvent(KeyPress, key); - break; - } - } -} +/* + +Copyright 1993 by Davor Matic + +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. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/keysym.h> +#include "screenint.h" +#include "inputstr.h" +#include "misc.h" +#include "scrnintstr.h" +#include "servermd.h" + +#include "Xnest.h" + +#include "Display.h" +#include "Screen.h" +#include "Keyboard.h" +#include "Args.h" +#include "Events.h" + +#include <X11/extensions/XKB.h> +#include "xkbsrv.h" +#include <X11/extensions/XKBconfig.h> + +extern Bool +XkbQueryExtension( + Display * /* dpy */, + int * /* opcodeReturn */, + int * /* eventBaseReturn */, + int * /* errorBaseReturn */, + int * /* majorRtrn */, + int * /* minorRtrn */ +); + +extern XkbDescPtr XkbGetKeyboard( + Display * /* dpy */, + unsigned int /* which */, + unsigned int /* deviceSpec */ +); + +extern Status XkbGetControls( + Display * /* dpy */, + unsigned long /* which */, + XkbDescPtr /* desc */ +); + +DeviceIntPtr xnestKeyboardDevice = NULL; + +void +xnestBell(int volume, DeviceIntPtr pDev, pointer ctrl, int cls) +{ + XBell(xnestDisplay, volume); +} + +void +DDXRingBell(int volume, int pitch, int duration) +{ + XBell(xnestDisplay, volume); +} + +void +xnestChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl *ctrl) +{ +#if 0 + unsigned long value_mask; + XKeyboardControl values; + int i; + + value_mask = KBKeyClickPercent | + KBBellPercent | + KBBellPitch | + KBBellDuration | + KBAutoRepeatMode; + + values.key_click_percent = ctrl->click; + values.bell_percent = ctrl->bell; + values.bell_pitch = ctrl->bell_pitch; + values.bell_duration = ctrl->bell_duration; + values.auto_repeat_mode = ctrl->autoRepeat ? + AutoRepeatModeOn : AutoRepeatModeOff; + + XChangeKeyboardControl(xnestDisplay, value_mask, &values); + + /* + value_mask = KBKey | KBAutoRepeatMode; + At this point, we need to walk through the vector and compare it + to the current server vector. If there are differences, report them. + */ + + value_mask = KBLed | KBLedMode; + for (i = 1; i <= 32; i++) { + values.led = i; + values.led_mode = (ctrl->leds & (1 << (i - 1))) ? LedModeOn : LedModeOff; + XChangeKeyboardControl(xnestDisplay, value_mask, &values); + } +#endif +} + +int +xnestKeyboardProc(DeviceIntPtr pDev, int onoff) +{ + KeySym *keymap; + int mapWidth; + int min_keycode, max_keycode; + KeySymsRec keySyms; + int i; + XKeyboardState values; + XkbDescPtr xkb; + int op, event, error, major, minor; + + switch (onoff) + { + case DEVICE_INIT: + XDisplayKeycodes(xnestDisplay, &min_keycode, &max_keycode); +#ifdef _XSERVER64 + { + KeySym64 *keymap64; + int i, len; + keymap64 = XGetKeyboardMapping(xnestDisplay, + min_keycode, + max_keycode - min_keycode + 1, + &mapWidth); + len = (max_keycode - min_keycode + 1) * mapWidth; + keymap = (KeySym *)malloc(len * sizeof(KeySym)); + for(i = 0; i < len; ++i) + keymap[i] = keymap64[i]; + XFree(keymap64); + } +#else + keymap = XGetKeyboardMapping(xnestDisplay, + min_keycode, + max_keycode - min_keycode + 1, + &mapWidth); +#endif + + keySyms.minKeyCode = min_keycode; + keySyms.maxKeyCode = max_keycode; + keySyms.mapWidth = mapWidth; + keySyms.map = keymap; + + if (XkbQueryExtension(xnestDisplay, &op, &event, &error, &major, &minor) == 0) { + ErrorF("Unable to initialize XKEYBOARD extension.\n"); + goto XkbError; + } + xkb = XkbGetKeyboard(xnestDisplay, XkbGBN_AllComponentsMask, XkbUseCoreKbd); + if (xkb == NULL || xkb->geom == NULL) { + ErrorF("Couldn't get keyboard.\n"); + goto XkbError; + } + XkbGetControls(xnestDisplay, XkbAllControlsMask, xkb); + + InitKeyboardDeviceStruct(pDev, NULL, + xnestBell, xnestChangeKeyboardControl); + XkbDDXChangeControls(pDev, xkb->ctrls, xkb->ctrls); + XkbFreeKeyboard(xkb, 0, False); + free(keymap); + break; + case DEVICE_ON: + xnestEventMask |= XNEST_KEYBOARD_EVENT_MASK; + for (i = 0; i < xnestNumScreens; i++) + XSelectInput(xnestDisplay, xnestDefaultWindows[i], xnestEventMask); + break; + case DEVICE_OFF: + xnestEventMask &= ~XNEST_KEYBOARD_EVENT_MASK; + for (i = 0; i < xnestNumScreens; i++) + XSelectInput(xnestDisplay, xnestDefaultWindows[i], xnestEventMask); + break; + case DEVICE_CLOSE: + break; + } + return Success; + +XkbError: + XGetKeyboardControl(xnestDisplay, &values); + memmove((char *)defaultKeyboardControl.autoRepeats, + (char *)values.auto_repeats, + sizeof(values.auto_repeats)); + + InitKeyboardDeviceStruct(pDev, NULL, + xnestBell, xnestChangeKeyboardControl); + free(keymap); + return Success; +} + +Bool +LegalModifier(unsigned int key, DeviceIntPtr pDev) +{ + return TRUE; +} + +void +xnestUpdateModifierState(unsigned int state) +{ + DeviceIntPtr pDev = xnestKeyboardDevice; + KeyClassPtr keyc = pDev->key; + int i; + CARD8 mask; + int xkb_state; + + if (!pDev) + return; + + xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state); + state = state & 0xff; + + if (xkb_state == state) + return; + + for (i = 0, mask = 1; i < 8; i++, mask <<= 1) { + int key; + + /* Modifier is down, but shouldn't be + */ + if ((xkb_state & mask) && !(state & mask)) { + int count = keyc->modifierKeyCount[i]; + + for (key = 0; key < MAP_LENGTH; key++) + if (keyc->xkbInfo->desc->map->modmap[key] & mask) { + int bit; + BYTE *kptr; + + kptr = &keyc->down[key >> 3]; + bit = 1 << (key & 7); + + if (*kptr & bit) + xnestQueueKeyEvent(KeyRelease, key); + + if (--count == 0) + break; + } + } + + /* Modifier shoud be down, but isn't + */ + if (!(xkb_state & mask) && (state & mask)) + for (key = 0; key < MAP_LENGTH; key++) + if (keyc->xkbInfo->desc->map->modmap[key] & mask) { + xnestQueueKeyEvent(KeyPress, key); + break; + } + } +} diff --git a/xorg-server/hw/xnest/Pixmap.c b/xorg-server/hw/xnest/Pixmap.c index 676a2ba95..cd2245b46 100644 --- a/xorg-server/hw/xnest/Pixmap.c +++ b/xorg-server/hw/xnest/Pixmap.c @@ -1,141 +1,141 @@ -/* - -Copyright 1993 by Davor Matic - -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. Davor Matic makes no representations about -the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. - -*/ - -#ifdef HAVE_XNEST_CONFIG_H -#include <xnest-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "regionstr.h" -#include "pixmapstr.h" -#include "scrnintstr.h" -#include "regionstr.h" -#include "gc.h" -#include "servermd.h" -#include "privates.h" -#include "mi.h" - -#include "Xnest.h" - -#include "Display.h" -#include "Screen.h" -#include "XNPixmap.h" - -static int xnestPixmapPrivateKeyIndex; -DevPrivateKey xnestPixmapPrivateKey = &xnestPixmapPrivateKeyIndex; - -PixmapPtr -xnestCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, - unsigned usage_hint) -{ - PixmapPtr pPixmap; - - pPixmap = AllocatePixmap(pScreen, sizeof(xnestPrivPixmap)); - if (!pPixmap) - return NullPixmap; - pPixmap->drawable.type = DRAWABLE_PIXMAP; - pPixmap->drawable.class = 0; - pPixmap->drawable.depth = depth; - pPixmap->drawable.bitsPerPixel = depth; - pPixmap->drawable.id = 0; - pPixmap->drawable.x = 0; - pPixmap->drawable.y = 0; - pPixmap->drawable.width = width; - pPixmap->drawable.height = height; - pPixmap->drawable.pScreen = pScreen; - pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - pPixmap->refcnt = 1; - pPixmap->devKind = PixmapBytePad(width, depth); - pPixmap->usage_hint = usage_hint; - dixSetPrivate(&pPixmap->devPrivates, xnestPixmapPrivateKey, - (char *)pPixmap + pScreen->totalPixmapSize); - if (width && height) - xnestPixmapPriv(pPixmap)->pixmap = - XCreatePixmap(xnestDisplay, - xnestDefaultWindows[pScreen->myNum], - width, height, depth); - else - xnestPixmapPriv(pPixmap)->pixmap = 0; - - return pPixmap; -} - -Bool -xnestDestroyPixmap(PixmapPtr pPixmap) -{ - if(--pPixmap->refcnt) - return TRUE; - XFreePixmap(xnestDisplay, xnestPixmap(pPixmap)); - dixFreePrivates(pPixmap->devPrivates); - xfree(pPixmap); - return TRUE; -} - -RegionPtr -xnestPixmapToRegion(PixmapPtr pPixmap) -{ - XImage *ximage; - register RegionPtr pReg, pTmpReg; - register int x, y; - unsigned long previousPixel, currentPixel; - BoxRec Box = { 0, 0, 0, 0 }; - Bool overlap; - - ximage = XGetImage(xnestDisplay, xnestPixmap(pPixmap), 0, 0, - pPixmap->drawable.width, pPixmap->drawable.height, - 1, XYPixmap); - - pReg = REGION_CREATE(pPixmap->drawable.pScreen, NULL, 1); - pTmpReg = REGION_CREATE(pPixmap->drawable.pScreen, NULL, 1); - if(!pReg || !pTmpReg) { - XDestroyImage(ximage); - return NullRegion; - } - - for (y = 0; y < pPixmap->drawable.height; y++) { - Box.y1 = y; - Box.y2 = y + 1; - previousPixel = 0L; - for (x = 0; x < pPixmap->drawable.width; x++) { - currentPixel = XGetPixel(ximage, x, y); - if (previousPixel != currentPixel) { - if (previousPixel == 0L) { - /* left edge */ - Box.x1 = x; - } - else if (currentPixel == 0L) { - /* right edge */ - Box.x2 = x; - REGION_RESET(pPixmap->drawable.pScreen, pTmpReg, &Box); - REGION_APPEND(pPixmap->drawable.pScreen, pReg, pTmpReg); - } - previousPixel = currentPixel; - } - } - if (previousPixel != 0L) { - /* right edge because of the end of pixmap */ - Box.x2 = pPixmap->drawable.width; - REGION_RESET(pPixmap->drawable.pScreen, pTmpReg, &Box); - REGION_APPEND(pPixmap->drawable.pScreen, pReg, pTmpReg); - } - } - - REGION_DESTROY(pPixmap->drawable.pScreen, pTmpReg); - XDestroyImage(ximage); - - REGION_VALIDATE(pPixmap->drawable.pScreen, pReg, &overlap); - - return(pReg); -} +/* + +Copyright 1993 by Davor Matic + +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. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "regionstr.h" +#include "pixmapstr.h" +#include "scrnintstr.h" +#include "regionstr.h" +#include "gc.h" +#include "servermd.h" +#include "privates.h" +#include "mi.h" + +#include "Xnest.h" + +#include "Display.h" +#include "Screen.h" +#include "XNPixmap.h" + +static int xnestPixmapPrivateKeyIndex; +DevPrivateKey xnestPixmapPrivateKey = &xnestPixmapPrivateKeyIndex; + +PixmapPtr +xnestCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + + pPixmap = AllocatePixmap(pScreen, sizeof(xnestPrivPixmap)); + if (!pPixmap) + return NullPixmap; + pPixmap->drawable.type = DRAWABLE_PIXMAP; + pPixmap->drawable.class = 0; + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = depth; + pPixmap->drawable.id = 0; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->drawable.pScreen = pScreen; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap->refcnt = 1; + pPixmap->devKind = PixmapBytePad(width, depth); + pPixmap->usage_hint = usage_hint; + dixSetPrivate(&pPixmap->devPrivates, xnestPixmapPrivateKey, + (char *)pPixmap + pScreen->totalPixmapSize); + if (width && height) + xnestPixmapPriv(pPixmap)->pixmap = + XCreatePixmap(xnestDisplay, + xnestDefaultWindows[pScreen->myNum], + width, height, depth); + else + xnestPixmapPriv(pPixmap)->pixmap = 0; + + return pPixmap; +} + +Bool +xnestDestroyPixmap(PixmapPtr pPixmap) +{ + if(--pPixmap->refcnt) + return TRUE; + XFreePixmap(xnestDisplay, xnestPixmap(pPixmap)); + dixFreePrivates(pPixmap->devPrivates); + free(pPixmap); + return TRUE; +} + +RegionPtr +xnestPixmapToRegion(PixmapPtr pPixmap) +{ + XImage *ximage; + register RegionPtr pReg, pTmpReg; + register int x, y; + unsigned long previousPixel, currentPixel; + BoxRec Box = { 0, 0, 0, 0 }; + Bool overlap; + + ximage = XGetImage(xnestDisplay, xnestPixmap(pPixmap), 0, 0, + pPixmap->drawable.width, pPixmap->drawable.height, + 1, XYPixmap); + + pReg = REGION_CREATE(pPixmap->drawable.pScreen, NULL, 1); + pTmpReg = REGION_CREATE(pPixmap->drawable.pScreen, NULL, 1); + if(!pReg || !pTmpReg) { + XDestroyImage(ximage); + return NullRegion; + } + + for (y = 0; y < pPixmap->drawable.height; y++) { + Box.y1 = y; + Box.y2 = y + 1; + previousPixel = 0L; + for (x = 0; x < pPixmap->drawable.width; x++) { + currentPixel = XGetPixel(ximage, x, y); + if (previousPixel != currentPixel) { + if (previousPixel == 0L) { + /* left edge */ + Box.x1 = x; + } + else if (currentPixel == 0L) { + /* right edge */ + Box.x2 = x; + REGION_RESET(pPixmap->drawable.pScreen, pTmpReg, &Box); + REGION_APPEND(pPixmap->drawable.pScreen, pReg, pTmpReg); + } + previousPixel = currentPixel; + } + } + if (previousPixel != 0L) { + /* right edge because of the end of pixmap */ + Box.x2 = pPixmap->drawable.width; + REGION_RESET(pPixmap->drawable.pScreen, pTmpReg, &Box); + REGION_APPEND(pPixmap->drawable.pScreen, pReg, pTmpReg); + } + } + + REGION_DESTROY(pPixmap->drawable.pScreen, pTmpReg); + XDestroyImage(ximage); + + REGION_VALIDATE(pPixmap->drawable.pScreen, pReg, &overlap); + + return(pReg); +} diff --git a/xorg-server/hw/xnest/Screen.c b/xorg-server/hw/xnest/Screen.c index ca903d7ac..5a035ac8f 100644 --- a/xorg-server/hw/xnest/Screen.c +++ b/xorg-server/hw/xnest/Screen.c @@ -1,421 +1,420 @@ -/* - -Copyright 1993 by Davor Matic - -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. Davor Matic makes no representations about -the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. - -*/ - -#ifdef HAVE_XNEST_CONFIG_H -#include <xnest-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "scrnintstr.h" -#include "dix.h" -#include "mi.h" -#include "mibstore.h" -#include "micmap.h" -#include "colormapst.h" -#include "resource.h" - -#include "Xnest.h" - -#include "Display.h" -#include "Screen.h" -#include "XNGC.h" -#include "GCOps.h" -#include "Drawable.h" -#include "XNFont.h" -#include "Color.h" -#include "XNCursor.h" -#include "Visual.h" -#include "Events.h" -#include "Init.h" -#include "mipointer.h" -#include "Args.h" -#include "mipointrst.h" - -Window xnestDefaultWindows[MAXSCREENS]; -Window xnestScreenSaverWindows[MAXSCREENS]; -static int xnestCursorScreenKeyIndex; -DevPrivateKey xnestCursorScreenKey = &xnestCursorScreenKeyIndex; - -ScreenPtr -xnestScreen(Window window) -{ - int i; - - for (i = 0; i < xnestNumScreens; i++) - if (xnestDefaultWindows[i] == window) - return screenInfo.screens[i]; - - return NULL; -} - -static int -offset(unsigned long mask) -{ - int count; - - for (count = 0; !(mask & 1) && count < 32; count++) - mask >>= 1; - - return count; -} - -static Bool -xnestSaveScreen(ScreenPtr pScreen, int what) -{ - if (xnestSoftwareScreenSaver) - return False; - else { - switch (what) { - case SCREEN_SAVER_ON: - XMapRaised(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]); - xnestSetScreenSaverColormapWindow(pScreen); - break; - - case SCREEN_SAVER_OFF: - XUnmapWindow(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]); - xnestSetInstalledColormapWindows(pScreen); - break; - - case SCREEN_SAVER_FORCER: - lastEventTime = GetTimeInMillis(); - XUnmapWindow(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]); - xnestSetInstalledColormapWindows(pScreen); - break; - - case SCREEN_SAVER_CYCLE: - XUnmapWindow(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]); - xnestSetInstalledColormapWindows(pScreen); - break; - } - return True; - } -} - -static Bool -xnestCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) -{ - return FALSE; -} - -static void -xnestCrossScreen(ScreenPtr pScreen, Bool entering) -{ -} - -static miPointerScreenFuncRec xnestPointerCursorFuncs = -{ - xnestCursorOffScreen, - xnestCrossScreen, - miPointerWarpCursor -}; - -static miPointerSpriteFuncRec xnestPointerSpriteFuncs = -{ - xnestRealizeCursor, - xnestUnrealizeCursor, - xnestSetCursor, - xnestMoveCursor, - xnestDeviceCursorInitialize, - xnestDeviceCursorCleanup -}; - -Bool -xnestOpenScreen(int index, ScreenPtr pScreen, int argc, char *argv[]) -{ - VisualPtr visuals; - DepthPtr depths; - int numVisuals, numDepths; - int i, j, depthIndex; - unsigned long valuemask; - XSetWindowAttributes attributes; - XWindowAttributes gattributes; - XSizeHints sizeHints; - VisualID defaultVisual; - int rootDepth; - miPointerScreenPtr PointPriv; - - if (!dixRequestPrivate(xnestWindowPrivateKey, sizeof(xnestPrivWin))) - return False; - if (!dixRequestPrivate(xnestGCPrivateKey, sizeof(xnestPrivGC))) - return False; - - visuals = (VisualPtr)xalloc(xnestNumVisuals * sizeof(VisualRec)); - numVisuals = 0; - - depths = (DepthPtr)xalloc(MAXDEPTH * sizeof(DepthRec)); - depths[0].depth = 1; - depths[0].numVids = 0; - depths[0].vids = (VisualID *)xalloc(MAXVISUALSPERDEPTH * sizeof(VisualID)); - numDepths = 1; - - for (i = 0; i < xnestNumVisuals; i++) { - visuals[numVisuals].class = xnestVisuals[i].class; - visuals[numVisuals].bitsPerRGBValue = xnestVisuals[i].bits_per_rgb; - visuals[numVisuals].ColormapEntries = xnestVisuals[i].colormap_size; - visuals[numVisuals].nplanes = xnestVisuals[i].depth; - visuals[numVisuals].redMask = xnestVisuals[i].red_mask; - visuals[numVisuals].greenMask = xnestVisuals[i].green_mask; - visuals[numVisuals].blueMask = xnestVisuals[i].blue_mask; - visuals[numVisuals].offsetRed = offset(xnestVisuals[i].red_mask); - visuals[numVisuals].offsetGreen = offset(xnestVisuals[i].green_mask); - visuals[numVisuals].offsetBlue = offset(xnestVisuals[i].blue_mask); - - /* Check for and remove duplicates. */ - for (j = 0; j < numVisuals; j++) { - if (visuals[numVisuals].class == visuals[j].class && - visuals[numVisuals].bitsPerRGBValue == visuals[j].bitsPerRGBValue && - visuals[numVisuals].ColormapEntries == visuals[j].ColormapEntries && - visuals[numVisuals].nplanes == visuals[j].nplanes && - visuals[numVisuals].redMask == visuals[j].redMask && - visuals[numVisuals].greenMask == visuals[j].greenMask && - visuals[numVisuals].blueMask == visuals[j].blueMask && - visuals[numVisuals].offsetRed == visuals[j].offsetRed && - visuals[numVisuals].offsetGreen == visuals[j].offsetGreen && - visuals[numVisuals].offsetBlue == visuals[j].offsetBlue) - break; - } - if (j < numVisuals) - break; - - visuals[numVisuals].vid = FakeClientID(0); - - depthIndex = UNDEFINED; - for (j = 0; j < numDepths; j++) - if (depths[j].depth == xnestVisuals[i].depth) { - depthIndex = j; - break; - } - - if (depthIndex == UNDEFINED) { - depthIndex = numDepths; - depths[depthIndex].depth = xnestVisuals[i].depth; - depths[depthIndex].numVids = 0; - depths[depthIndex].vids = - (VisualID *)xalloc(MAXVISUALSPERDEPTH * sizeof(VisualID)); - numDepths++; - } - if (depths[depthIndex].numVids >= MAXVISUALSPERDEPTH) { - FatalError("Visual table overflow"); - } - depths[depthIndex].vids[depths[depthIndex].numVids] = - visuals[numVisuals].vid; - depths[depthIndex].numVids++; - - numVisuals++; - } - visuals = (VisualPtr)xrealloc(visuals, numVisuals * sizeof(VisualRec)); - - defaultVisual = visuals[xnestDefaultVisualIndex].vid; - rootDepth = visuals[xnestDefaultVisualIndex].nplanes; - - if (xnestParentWindow != 0) { - XGetWindowAttributes(xnestDisplay, xnestParentWindow, &gattributes); - xnestWidth = gattributes.width; - xnestHeight = gattributes.height; - } - - /* myNum */ - /* id */ - miScreenInit(pScreen, NULL, xnestWidth, xnestHeight, 1, 1, xnestWidth, - rootDepth, - numDepths, depths, - defaultVisual, /* root visual */ - numVisuals, visuals); - -/* miInitializeBackingStore(pScreen); */ - - pScreen->defColormap = (Colormap) FakeClientID(0); - pScreen->minInstalledCmaps = MINCMAPS; - pScreen->maxInstalledCmaps = MAXCMAPS; - pScreen->backingStoreSupport = NotUseful; - pScreen->saveUnderSupport = NotUseful; - pScreen->whitePixel = xnestWhitePixel; - pScreen->blackPixel = xnestBlackPixel; - /* rgf */ - /* GCperDepth */ - /* PixmapPerDepth */ - pScreen->devPrivate = NULL; - /* WindowPrivateLen */ - /* WindowPrivateSizes */ - /* totalWindowSize */ - /* GCPrivateLen */ - /* GCPrivateSizes */ - /* totalGCSize */ - - /* Random screen procedures */ - - pScreen->QueryBestSize = xnestQueryBestSize; - pScreen->SaveScreen = xnestSaveScreen; - pScreen->GetImage = xnestGetImage; - pScreen->GetSpans = xnestGetSpans; - pScreen->PointerNonInterestBox = NULL; - pScreen->SourceValidate = NULL; - - /* Window Procedures */ - - pScreen->CreateWindow = xnestCreateWindow; - pScreen->DestroyWindow = xnestDestroyWindow; - pScreen->PositionWindow = xnestPositionWindow; - pScreen->ChangeWindowAttributes = xnestChangeWindowAttributes; - pScreen->RealizeWindow = xnestRealizeWindow; - pScreen->UnrealizeWindow = xnestUnrealizeWindow; - pScreen->PostValidateTree = NULL; - pScreen->WindowExposures = xnestWindowExposures; - pScreen->CopyWindow = xnestCopyWindow; - pScreen->ClipNotify = xnestClipNotify; - - /* Pixmap procedures */ - - pScreen->CreatePixmap = xnestCreatePixmap; - pScreen->DestroyPixmap = xnestDestroyPixmap; - - /* Font procedures */ - - pScreen->RealizeFont = xnestRealizeFont; - pScreen->UnrealizeFont = xnestUnrealizeFont; - - /* GC procedures */ - - pScreen->CreateGC = xnestCreateGC; - - /* Colormap procedures */ - - pScreen->CreateColormap = xnestCreateColormap; - pScreen->DestroyColormap = xnestDestroyColormap; - pScreen->InstallColormap = xnestInstallColormap; - pScreen->UninstallColormap = xnestUninstallColormap; - pScreen->ListInstalledColormaps = xnestListInstalledColormaps; - pScreen->StoreColors = xnestStoreColors; - pScreen->ResolveColor = xnestResolveColor; - - pScreen->BitmapToRegion = xnestPixmapToRegion; - - /* OS layer procedures */ - - pScreen->BlockHandler = (ScreenBlockHandlerProcPtr)NoopDDA; - pScreen->WakeupHandler = (ScreenWakeupHandlerProcPtr)NoopDDA; - pScreen->blockData = NULL; - pScreen->wakeupData = NULL; - - miDCInitialize(pScreen, &xnestPointerCursorFuncs); /* init SW rendering */ - PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); - xnestCursorFuncs.spriteFuncs = PointPriv->spriteFuncs; - dixSetPrivate(&pScreen->devPrivates, xnestCursorScreenKey, &xnestCursorFuncs); - PointPriv->spriteFuncs = &xnestPointerSpriteFuncs; - - pScreen->mmWidth = xnestWidth * DisplayWidthMM(xnestDisplay, - DefaultScreen(xnestDisplay)) / - DisplayWidth(xnestDisplay, - DefaultScreen(xnestDisplay)); - pScreen->mmHeight = xnestHeight * DisplayHeightMM(xnestDisplay, - DefaultScreen(xnestDisplay)) / - DisplayHeight(xnestDisplay, - DefaultScreen(xnestDisplay)); - - /* overwrite miCloseScreen with our own */ - pScreen->CloseScreen = xnestCloseScreen; - - if (!miScreenDevPrivateInit(pScreen, xnestWidth, NULL)) - return FALSE; - - /* overwrite miSetShape with our own */ - pScreen->SetShape = xnestSetShape; - - /* devPrivates */ - -#define POSITION_OFFSET (pScreen->myNum * (xnestWidth + xnestHeight) / 32) - - if (xnestDoFullGeneration) { - - valuemask = CWBackPixel | CWEventMask | CWColormap; - attributes.background_pixel = xnestWhitePixel; - attributes.event_mask = xnestEventMask; - attributes.colormap = xnestDefaultVisualColormap(xnestDefaultVisual(pScreen)); - - if (xnestParentWindow != 0) { - xnestDefaultWindows[pScreen->myNum] = xnestParentWindow; - XSelectInput (xnestDisplay, xnestDefaultWindows[pScreen->myNum], - xnestEventMask); - } else - xnestDefaultWindows[pScreen->myNum] = - XCreateWindow(xnestDisplay, - DefaultRootWindow(xnestDisplay), - xnestX + POSITION_OFFSET, - xnestY + POSITION_OFFSET, - xnestWidth, xnestHeight, - xnestBorderWidth, - pScreen->rootDepth, - InputOutput, - xnestDefaultVisual(pScreen), - valuemask, &attributes); - - if (!xnestWindowName) - xnestWindowName = argv[0]; - - sizeHints.flags = PPosition | PSize | PMaxSize; - sizeHints.x = xnestX + POSITION_OFFSET; - sizeHints.y = xnestY + POSITION_OFFSET; - sizeHints.width = sizeHints.max_width = xnestWidth; - sizeHints.height = sizeHints.max_height = xnestHeight; - if (xnestUserGeometry & XValue || xnestUserGeometry & YValue) - sizeHints.flags |= USPosition; - if (xnestUserGeometry & WidthValue || xnestUserGeometry & HeightValue) - sizeHints.flags |= USSize; - XSetStandardProperties(xnestDisplay, - xnestDefaultWindows[pScreen->myNum], - xnestWindowName, - xnestWindowName, - xnestIconBitmap, - argv, argc, &sizeHints); - - XMapWindow(xnestDisplay, xnestDefaultWindows[pScreen->myNum]); - - valuemask = CWBackPixmap | CWColormap; - attributes.background_pixmap = xnestScreenSaverPixmap; - attributes.colormap = - DefaultColormap(xnestDisplay, DefaultScreen(xnestDisplay)); - xnestScreenSaverWindows[pScreen->myNum] = - XCreateWindow(xnestDisplay, - xnestDefaultWindows[pScreen->myNum], - 0, 0, xnestWidth, xnestHeight, 0, - DefaultDepth(xnestDisplay, DefaultScreen(xnestDisplay)), - InputOutput, - DefaultVisual(xnestDisplay, DefaultScreen(xnestDisplay)), - valuemask, &attributes); - } - - if (!xnestCreateDefaultColormap(pScreen)) return False; - - return True; -} - -Bool -xnestCloseScreen(int index, ScreenPtr pScreen) -{ - int i; - - for (i = 0; i < pScreen->numDepths; i++) - xfree(pScreen->allowedDepths[i].vids); - xfree(pScreen->allowedDepths); - xfree(pScreen->visuals); - xfree(pScreen->devPrivate); - - /* - If xnestDoFullGeneration all x resources will be destroyed upon closing - the display connection. There is no need to generate extra protocol. - */ - - return True; -} +/* + +Copyright 1993 by Davor Matic + +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. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "dix.h" +#include "mi.h" +#include "mibstore.h" +#include "micmap.h" +#include "colormapst.h" +#include "resource.h" + +#include "Xnest.h" + +#include "Display.h" +#include "Screen.h" +#include "XNGC.h" +#include "GCOps.h" +#include "Drawable.h" +#include "XNFont.h" +#include "Color.h" +#include "XNCursor.h" +#include "Visual.h" +#include "Events.h" +#include "Init.h" +#include "mipointer.h" +#include "Args.h" +#include "mipointrst.h" + +Window xnestDefaultWindows[MAXSCREENS]; +Window xnestScreenSaverWindows[MAXSCREENS]; +static int xnestCursorScreenKeyIndex; +DevPrivateKey xnestCursorScreenKey = &xnestCursorScreenKeyIndex; + +ScreenPtr +xnestScreen(Window window) +{ + int i; + + for (i = 0; i < xnestNumScreens; i++) + if (xnestDefaultWindows[i] == window) + return screenInfo.screens[i]; + + return NULL; +} + +static int +offset(unsigned long mask) +{ + int count; + + for (count = 0; !(mask & 1) && count < 32; count++) + mask >>= 1; + + return count; +} + +static Bool +xnestSaveScreen(ScreenPtr pScreen, int what) +{ + if (xnestSoftwareScreenSaver) + return False; + else { + switch (what) { + case SCREEN_SAVER_ON: + XMapRaised(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]); + xnestSetScreenSaverColormapWindow(pScreen); + break; + + case SCREEN_SAVER_OFF: + XUnmapWindow(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]); + xnestSetInstalledColormapWindows(pScreen); + break; + + case SCREEN_SAVER_FORCER: + lastEventTime = GetTimeInMillis(); + XUnmapWindow(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]); + xnestSetInstalledColormapWindows(pScreen); + break; + + case SCREEN_SAVER_CYCLE: + XUnmapWindow(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]); + xnestSetInstalledColormapWindows(pScreen); + break; + } + return True; + } +} + +static Bool +xnestCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) +{ + return FALSE; +} + +static void +xnestCrossScreen(ScreenPtr pScreen, Bool entering) +{ +} + +static miPointerScreenFuncRec xnestPointerCursorFuncs = +{ + xnestCursorOffScreen, + xnestCrossScreen, + miPointerWarpCursor +}; + +static miPointerSpriteFuncRec xnestPointerSpriteFuncs = +{ + xnestRealizeCursor, + xnestUnrealizeCursor, + xnestSetCursor, + xnestMoveCursor, + xnestDeviceCursorInitialize, + xnestDeviceCursorCleanup +}; + +Bool +xnestOpenScreen(int index, ScreenPtr pScreen, int argc, char *argv[]) +{ + VisualPtr visuals; + DepthPtr depths; + int numVisuals, numDepths; + int i, j, depthIndex; + unsigned long valuemask; + XSetWindowAttributes attributes; + XWindowAttributes gattributes; + XSizeHints sizeHints; + VisualID defaultVisual; + int rootDepth; + miPointerScreenPtr PointPriv; + + if (!dixRequestPrivate(xnestWindowPrivateKey, sizeof(xnestPrivWin))) + return False; + if (!dixRequestPrivate(xnestGCPrivateKey, sizeof(xnestPrivGC))) + return False; + + visuals = (VisualPtr)malloc(xnestNumVisuals * sizeof(VisualRec)); + numVisuals = 0; + + depths = (DepthPtr)malloc(MAXDEPTH * sizeof(DepthRec)); + depths[0].depth = 1; + depths[0].numVids = 0; + depths[0].vids = (VisualID *)malloc(MAXVISUALSPERDEPTH * sizeof(VisualID)); + numDepths = 1; + + for (i = 0; i < xnestNumVisuals; i++) { + visuals[numVisuals].class = xnestVisuals[i].class; + visuals[numVisuals].bitsPerRGBValue = xnestVisuals[i].bits_per_rgb; + visuals[numVisuals].ColormapEntries = xnestVisuals[i].colormap_size; + visuals[numVisuals].nplanes = xnestVisuals[i].depth; + visuals[numVisuals].redMask = xnestVisuals[i].red_mask; + visuals[numVisuals].greenMask = xnestVisuals[i].green_mask; + visuals[numVisuals].blueMask = xnestVisuals[i].blue_mask; + visuals[numVisuals].offsetRed = offset(xnestVisuals[i].red_mask); + visuals[numVisuals].offsetGreen = offset(xnestVisuals[i].green_mask); + visuals[numVisuals].offsetBlue = offset(xnestVisuals[i].blue_mask); + + /* Check for and remove duplicates. */ + for (j = 0; j < numVisuals; j++) { + if (visuals[numVisuals].class == visuals[j].class && + visuals[numVisuals].bitsPerRGBValue == visuals[j].bitsPerRGBValue && + visuals[numVisuals].ColormapEntries == visuals[j].ColormapEntries && + visuals[numVisuals].nplanes == visuals[j].nplanes && + visuals[numVisuals].redMask == visuals[j].redMask && + visuals[numVisuals].greenMask == visuals[j].greenMask && + visuals[numVisuals].blueMask == visuals[j].blueMask && + visuals[numVisuals].offsetRed == visuals[j].offsetRed && + visuals[numVisuals].offsetGreen == visuals[j].offsetGreen && + visuals[numVisuals].offsetBlue == visuals[j].offsetBlue) + break; + } + if (j < numVisuals) + break; + + visuals[numVisuals].vid = FakeClientID(0); + + depthIndex = UNDEFINED; + for (j = 0; j < numDepths; j++) + if (depths[j].depth == xnestVisuals[i].depth) { + depthIndex = j; + break; + } + + if (depthIndex == UNDEFINED) { + depthIndex = numDepths; + depths[depthIndex].depth = xnestVisuals[i].depth; + depths[depthIndex].numVids = 0; + depths[depthIndex].vids = + (VisualID *)malloc(MAXVISUALSPERDEPTH * sizeof(VisualID)); + numDepths++; + } + if (depths[depthIndex].numVids >= MAXVISUALSPERDEPTH) { + FatalError("Visual table overflow"); + } + depths[depthIndex].vids[depths[depthIndex].numVids] = + visuals[numVisuals].vid; + depths[depthIndex].numVids++; + + numVisuals++; + } + visuals = (VisualPtr)realloc(visuals, numVisuals * sizeof(VisualRec)); + + defaultVisual = visuals[xnestDefaultVisualIndex].vid; + rootDepth = visuals[xnestDefaultVisualIndex].nplanes; + + if (xnestParentWindow != 0) { + XGetWindowAttributes(xnestDisplay, xnestParentWindow, &gattributes); + xnestWidth = gattributes.width; + xnestHeight = gattributes.height; + } + + /* myNum */ + /* id */ + miScreenInit(pScreen, NULL, xnestWidth, xnestHeight, 1, 1, xnestWidth, + rootDepth, + numDepths, depths, + defaultVisual, /* root visual */ + numVisuals, visuals); + +/* miInitializeBackingStore(pScreen); */ + + pScreen->defColormap = (Colormap) FakeClientID(0); + pScreen->minInstalledCmaps = MINCMAPS; + pScreen->maxInstalledCmaps = MAXCMAPS; + pScreen->backingStoreSupport = NotUseful; + pScreen->saveUnderSupport = NotUseful; + pScreen->whitePixel = xnestWhitePixel; + pScreen->blackPixel = xnestBlackPixel; + /* rgf */ + /* GCperDepth */ + /* PixmapPerDepth */ + pScreen->devPrivate = NULL; + /* WindowPrivateLen */ + /* WindowPrivateSizes */ + /* totalWindowSize */ + /* GCPrivateLen */ + /* GCPrivateSizes */ + /* totalGCSize */ + + /* Random screen procedures */ + + pScreen->QueryBestSize = xnestQueryBestSize; + pScreen->SaveScreen = xnestSaveScreen; + pScreen->GetImage = xnestGetImage; + pScreen->GetSpans = xnestGetSpans; + pScreen->SourceValidate = NULL; + + /* Window Procedures */ + + pScreen->CreateWindow = xnestCreateWindow; + pScreen->DestroyWindow = xnestDestroyWindow; + pScreen->PositionWindow = xnestPositionWindow; + pScreen->ChangeWindowAttributes = xnestChangeWindowAttributes; + pScreen->RealizeWindow = xnestRealizeWindow; + pScreen->UnrealizeWindow = xnestUnrealizeWindow; + pScreen->PostValidateTree = NULL; + pScreen->WindowExposures = xnestWindowExposures; + pScreen->CopyWindow = xnestCopyWindow; + pScreen->ClipNotify = xnestClipNotify; + + /* Pixmap procedures */ + + pScreen->CreatePixmap = xnestCreatePixmap; + pScreen->DestroyPixmap = xnestDestroyPixmap; + + /* Font procedures */ + + pScreen->RealizeFont = xnestRealizeFont; + pScreen->UnrealizeFont = xnestUnrealizeFont; + + /* GC procedures */ + + pScreen->CreateGC = xnestCreateGC; + + /* Colormap procedures */ + + pScreen->CreateColormap = xnestCreateColormap; + pScreen->DestroyColormap = xnestDestroyColormap; + pScreen->InstallColormap = xnestInstallColormap; + pScreen->UninstallColormap = xnestUninstallColormap; + pScreen->ListInstalledColormaps = xnestListInstalledColormaps; + pScreen->StoreColors = xnestStoreColors; + pScreen->ResolveColor = xnestResolveColor; + + pScreen->BitmapToRegion = xnestPixmapToRegion; + + /* OS layer procedures */ + + pScreen->BlockHandler = (ScreenBlockHandlerProcPtr)NoopDDA; + pScreen->WakeupHandler = (ScreenWakeupHandlerProcPtr)NoopDDA; + pScreen->blockData = NULL; + pScreen->wakeupData = NULL; + + miDCInitialize(pScreen, &xnestPointerCursorFuncs); /* init SW rendering */ + PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); + xnestCursorFuncs.spriteFuncs = PointPriv->spriteFuncs; + dixSetPrivate(&pScreen->devPrivates, xnestCursorScreenKey, &xnestCursorFuncs); + PointPriv->spriteFuncs = &xnestPointerSpriteFuncs; + + pScreen->mmWidth = xnestWidth * DisplayWidthMM(xnestDisplay, + DefaultScreen(xnestDisplay)) / + DisplayWidth(xnestDisplay, + DefaultScreen(xnestDisplay)); + pScreen->mmHeight = xnestHeight * DisplayHeightMM(xnestDisplay, + DefaultScreen(xnestDisplay)) / + DisplayHeight(xnestDisplay, + DefaultScreen(xnestDisplay)); + + /* overwrite miCloseScreen with our own */ + pScreen->CloseScreen = xnestCloseScreen; + + if (!miScreenDevPrivateInit(pScreen, xnestWidth, NULL)) + return FALSE; + + /* overwrite miSetShape with our own */ + pScreen->SetShape = xnestSetShape; + + /* devPrivates */ + +#define POSITION_OFFSET (pScreen->myNum * (xnestWidth + xnestHeight) / 32) + + if (xnestDoFullGeneration) { + + valuemask = CWBackPixel | CWEventMask | CWColormap; + attributes.background_pixel = xnestWhitePixel; + attributes.event_mask = xnestEventMask; + attributes.colormap = xnestDefaultVisualColormap(xnestDefaultVisual(pScreen)); + + if (xnestParentWindow != 0) { + xnestDefaultWindows[pScreen->myNum] = xnestParentWindow; + XSelectInput (xnestDisplay, xnestDefaultWindows[pScreen->myNum], + xnestEventMask); + } else + xnestDefaultWindows[pScreen->myNum] = + XCreateWindow(xnestDisplay, + DefaultRootWindow(xnestDisplay), + xnestX + POSITION_OFFSET, + xnestY + POSITION_OFFSET, + xnestWidth, xnestHeight, + xnestBorderWidth, + pScreen->rootDepth, + InputOutput, + xnestDefaultVisual(pScreen), + valuemask, &attributes); + + if (!xnestWindowName) + xnestWindowName = argv[0]; + + sizeHints.flags = PPosition | PSize | PMaxSize; + sizeHints.x = xnestX + POSITION_OFFSET; + sizeHints.y = xnestY + POSITION_OFFSET; + sizeHints.width = sizeHints.max_width = xnestWidth; + sizeHints.height = sizeHints.max_height = xnestHeight; + if (xnestUserGeometry & XValue || xnestUserGeometry & YValue) + sizeHints.flags |= USPosition; + if (xnestUserGeometry & WidthValue || xnestUserGeometry & HeightValue) + sizeHints.flags |= USSize; + XSetStandardProperties(xnestDisplay, + xnestDefaultWindows[pScreen->myNum], + xnestWindowName, + xnestWindowName, + xnestIconBitmap, + argv, argc, &sizeHints); + + XMapWindow(xnestDisplay, xnestDefaultWindows[pScreen->myNum]); + + valuemask = CWBackPixmap | CWColormap; + attributes.background_pixmap = xnestScreenSaverPixmap; + attributes.colormap = + DefaultColormap(xnestDisplay, DefaultScreen(xnestDisplay)); + xnestScreenSaverWindows[pScreen->myNum] = + XCreateWindow(xnestDisplay, + xnestDefaultWindows[pScreen->myNum], + 0, 0, xnestWidth, xnestHeight, 0, + DefaultDepth(xnestDisplay, DefaultScreen(xnestDisplay)), + InputOutput, + DefaultVisual(xnestDisplay, DefaultScreen(xnestDisplay)), + valuemask, &attributes); + } + + if (!xnestCreateDefaultColormap(pScreen)) return False; + + return True; +} + +Bool +xnestCloseScreen(int index, ScreenPtr pScreen) +{ + int i; + + for (i = 0; i < pScreen->numDepths; i++) + free(pScreen->allowedDepths[i].vids); + free(pScreen->allowedDepths); + free(pScreen->visuals); + free(pScreen->devPrivate); + + /* + If xnestDoFullGeneration all x resources will be destroyed upon closing + the display connection. There is no need to generate extra protocol. + */ + + return True; +} diff --git a/xorg-server/hw/xquartz/GL/glcontextmodes.c b/xorg-server/hw/xquartz/GL/glcontextmodes.c index 326c8b235..52a9ca440 100644 --- a/xorg-server/hw/xquartz/GL/glcontextmodes.c +++ b/xorg-server/hw/xquartz/GL/glcontextmodes.c @@ -1,550 +1,550 @@ -/* - * (C) Copyright IBM Corporation 2003 - * 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 - * on the rights to use, copy, modify, merge, publish, distribute, sub - * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS 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. - */ - -/** - * \file glcontextmodes.c - * Utility routines for working with \c __GLcontextModes structures. At - * some point most or all of these functions will be moved to the Mesa - * code base. - * - * \author Ian Romanick <idr@us.ibm.com> - */ - -#if defined(IN_MINI_GLX) -#include <GL/gl.h> -#else -#if defined(HAVE_DIX_CONFIG_H) -# include <dix-config.h> -#endif -#include <X11/X.h> -#include <GL/glx.h> -#include "GL/glxint.h" -#endif - -/* Memory macros */ -#if defined(IN_MINI_GLX) -# include <stdlib.h> -# include <string.h> -# define _mesa_malloc(b) malloc(b) -# define _mesa_free(m) free(m) -# define _mesa_memset memset -#else -# ifdef XFree86Server -# include <os.h> -# include <string.h> -# define _mesa_malloc(b) xalloc(b) -# define _mesa_free(m) xfree(m) -# define _mesa_memset memset -# else -# include <X11/Xlibint.h> -# define _mesa_memset memset -# define _mesa_malloc(b) Xmalloc(b) -# define _mesa_free(m) Xfree(m) -# endif /* XFree86Server */ -#endif /* !defined(IN_MINI_GLX) */ - -#include "glcontextmodes.h" - -#if !defined(IN_MINI_GLX) -#define NUM_VISUAL_TYPES 6 - -/** - * Convert an X visual type to a GLX visual type. - * - * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.) - * to be converted. - * \return If \c visualType is a valid X visual type, a GLX visual type will - * be returned. Otherwise \c GLX_NONE will be returned. - */ -GLint -_gl_convert_from_x_visual_type( int visualType ) -{ - static const int glx_visual_types[ NUM_VISUAL_TYPES ] = { - GLX_STATIC_GRAY, GLX_GRAY_SCALE, - GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, - GLX_TRUE_COLOR, GLX_DIRECT_COLOR - }; - - return ( (unsigned) visualType < NUM_VISUAL_TYPES ) - ? glx_visual_types[ visualType ] : GLX_NONE; -} - - -/** - * Convert a GLX visual type to an X visual type. - * - * \param visualType GLX visual type (i.e., \c GLX_TRUE_COLOR, - * \c GLX_STATIC_GRAY, etc.) to be converted. - * \return If \c visualType is a valid GLX visual type, an X visual type will - * be returned. Otherwise -1 will be returned. - */ -GLint -_gl_convert_to_x_visual_type( int visualType ) -{ - static const int x_visual_types[ NUM_VISUAL_TYPES ] = { - TrueColor, DirectColor, - PseudoColor, StaticColor, - GrayScale, StaticGray - }; - - return ( (unsigned) (visualType - GLX_TRUE_COLOR) < NUM_VISUAL_TYPES ) - ? x_visual_types[ visualType - GLX_TRUE_COLOR ] : -1; -} - - -/** - * Copy a GLX visual config structure to a GL context mode structure. All - * of the fields in \c config are copied to \c mode. Additional fields in - * \c mode that can be derrived from the fields of \c config (i.e., - * \c haveDepthBuffer) are also filled in. The remaining fields in \c mode - * that cannot be derived are set to default values. - * - * \param mode Destination GL context mode. - * \param config Source GLX visual config. - * - * \note - * The \c fbconfigID and \c visualID fields of the \c __GLcontextModes - * structure will be set to the \c vid of the \c __GLXvisualConfig structure. - */ -void -_gl_copy_visual_to_context_mode( __GLcontextModes * mode, - const __GLXvisualConfig * config ) -{ - __GLcontextModes * const next = mode->next; - - (void) _mesa_memset( mode, 0, sizeof( __GLcontextModes ) ); - mode->next = next; - - mode->visualID = config->vid; - mode->visualType = _gl_convert_from_x_visual_type( config->class ); - mode->xRenderable = GL_TRUE; - mode->fbconfigID = config->vid; - mode->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT; - - mode->rgbMode = (config->rgba != 0); - mode->renderType = (mode->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; - - mode->colorIndexMode = !(mode->rgbMode); - mode->doubleBufferMode = (config->doubleBuffer != 0); - mode->stereoMode = (config->stereo != 0); - - mode->haveAccumBuffer = ((config->accumRedSize + - config->accumGreenSize + - config->accumBlueSize + - config->accumAlphaSize) > 0); - mode->haveDepthBuffer = (config->depthSize > 0); - mode->haveStencilBuffer = (config->stencilSize > 0); - - mode->redBits = config->redSize; - mode->greenBits = config->greenSize; - mode->blueBits = config->blueSize; - mode->alphaBits = config->alphaSize; - mode->redMask = config->redMask; - mode->greenMask = config->greenMask; - mode->blueMask = config->blueMask; - mode->alphaMask = config->alphaMask; - mode->rgbBits = mode->rgbMode ? config->bufferSize : 0; - mode->indexBits = mode->colorIndexMode ? config->bufferSize : 0; - - mode->accumRedBits = config->accumRedSize; - mode->accumGreenBits = config->accumGreenSize; - mode->accumBlueBits = config->accumBlueSize; - mode->accumAlphaBits = config->accumAlphaSize; - mode->depthBits = config->depthSize; - mode->stencilBits = config->stencilSize; - - mode->numAuxBuffers = config->auxBuffers; - mode->level = config->level; - - mode->visualRating = config->visualRating; - mode->transparentPixel = config->transparentPixel; - mode->transparentRed = config->transparentRed; - mode->transparentGreen = config->transparentGreen; - mode->transparentBlue = config->transparentBlue; - mode->transparentAlpha = config->transparentAlpha; - mode->transparentIndex = config->transparentIndex; - mode->samples = config->multiSampleSize; - mode->sampleBuffers = config->nMultiSampleBuffers; - /* mode->visualSelectGroup = config->visualSelectGroup; ? */ - - mode->swapMethod = GLX_SWAP_UNDEFINED_OML; - - mode->bindToTextureRgb = (mode->rgbMode) ? GL_TRUE : GL_FALSE; - mode->bindToTextureRgba = (mode->rgbMode && mode->alphaBits) ? - GL_TRUE : GL_FALSE; - mode->bindToMipmapTexture = mode->rgbMode ? GL_TRUE : GL_FALSE; - mode->bindToTextureTargets = mode->rgbMode ? - GLX_TEXTURE_1D_BIT_EXT | GLX_TEXTURE_2D_BIT_EXT | - GLX_TEXTURE_RECTANGLE_BIT_EXT : 0; - mode->yInverted = GL_FALSE; -} - - -/** - * Get data from a GL context mode. - * - * \param mode GL context mode whose data is to be returned. - * \param attribute Attribute of \c mode that is to be returned. - * \param value_return Location to store the data member of \c mode. - * \return If \c attribute is a valid attribute of \c mode, zero is - * returned. Otherwise \c GLX_BAD_ATTRIBUTE is returned. - */ -int -_gl_get_context_mode_data(const __GLcontextModes *mode, int attribute, - int *value_return) -{ - switch (attribute) { - case GLX_USE_GL: - *value_return = GL_TRUE; - return 0; - case GLX_BUFFER_SIZE: - *value_return = mode->rgbBits; - return 0; - case GLX_RGBA: - *value_return = mode->rgbMode; - return 0; - case GLX_RED_SIZE: - *value_return = mode->redBits; - return 0; - case GLX_GREEN_SIZE: - *value_return = mode->greenBits; - return 0; - case GLX_BLUE_SIZE: - *value_return = mode->blueBits; - return 0; - case GLX_ALPHA_SIZE: - *value_return = mode->alphaBits; - return 0; - case GLX_DOUBLEBUFFER: - *value_return = mode->doubleBufferMode; - return 0; - case GLX_STEREO: - *value_return = mode->stereoMode; - return 0; - case GLX_AUX_BUFFERS: - *value_return = mode->numAuxBuffers; - return 0; - case GLX_DEPTH_SIZE: - *value_return = mode->depthBits; - return 0; - case GLX_STENCIL_SIZE: - *value_return = mode->stencilBits; - return 0; - case GLX_ACCUM_RED_SIZE: - *value_return = mode->accumRedBits; - return 0; - case GLX_ACCUM_GREEN_SIZE: - *value_return = mode->accumGreenBits; - return 0; - case GLX_ACCUM_BLUE_SIZE: - *value_return = mode->accumBlueBits; - return 0; - case GLX_ACCUM_ALPHA_SIZE: - *value_return = mode->accumAlphaBits; - return 0; - case GLX_LEVEL: - *value_return = mode->level; - return 0; - case GLX_TRANSPARENT_TYPE_EXT: - *value_return = mode->transparentPixel; - return 0; - case GLX_TRANSPARENT_RED_VALUE: - *value_return = mode->transparentRed; - return 0; - case GLX_TRANSPARENT_GREEN_VALUE: - *value_return = mode->transparentGreen; - return 0; - case GLX_TRANSPARENT_BLUE_VALUE: - *value_return = mode->transparentBlue; - return 0; - case GLX_TRANSPARENT_ALPHA_VALUE: - *value_return = mode->transparentAlpha; - return 0; - case GLX_TRANSPARENT_INDEX_VALUE: - *value_return = mode->transparentIndex; - return 0; - case GLX_X_VISUAL_TYPE: - *value_return = mode->visualType; - return 0; - case GLX_CONFIG_CAVEAT: - *value_return = mode->visualRating; - return 0; - case GLX_VISUAL_ID: - *value_return = mode->visualID; - return 0; - case GLX_DRAWABLE_TYPE: - *value_return = mode->drawableType; - return 0; - case GLX_RENDER_TYPE: - *value_return = mode->renderType; - return 0; - case GLX_X_RENDERABLE: - *value_return = mode->xRenderable; - return 0; - case GLX_FBCONFIG_ID: - *value_return = mode->fbconfigID; - return 0; - case GLX_MAX_PBUFFER_WIDTH: - *value_return = mode->maxPbufferWidth; - return 0; - case GLX_MAX_PBUFFER_HEIGHT: - *value_return = mode->maxPbufferHeight; - return 0; - case GLX_MAX_PBUFFER_PIXELS: - *value_return = mode->maxPbufferPixels; - return 0; - case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: - *value_return = mode->optimalPbufferWidth; - return 0; - case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: - *value_return = mode->optimalPbufferHeight; - return 0; - case GLX_SWAP_METHOD_OML: - *value_return = mode->swapMethod; - return 0; - case GLX_SAMPLE_BUFFERS_SGIS: - *value_return = mode->sampleBuffers; - return 0; - case GLX_SAMPLES_SGIS: - *value_return = mode->samples; - return 0; - case GLX_BIND_TO_TEXTURE_RGB_EXT: - *value_return = mode->bindToTextureRgb; - return 0; - case GLX_BIND_TO_TEXTURE_RGBA_EXT: - *value_return = mode->bindToTextureRgba; - return 0; - case GLX_BIND_TO_MIPMAP_TEXTURE_EXT: - *value_return = mode->bindToMipmapTexture == GL_TRUE ? GL_TRUE : - GL_FALSE; - return 0; - case GLX_BIND_TO_TEXTURE_TARGETS_EXT: - *value_return = mode->bindToTextureTargets; - return 0; - case GLX_Y_INVERTED_EXT: - *value_return = mode->yInverted; - return 0; - - /* Applications are NOT allowed to query GLX_VISUAL_SELECT_GROUP_SGIX. - * It is ONLY for communication between the GLX client and the GLX - * server. - */ - case GLX_VISUAL_SELECT_GROUP_SGIX: - default: - return GLX_BAD_ATTRIBUTE; - } -} -#endif /* !defined(IN_MINI_GLX) */ - - -/** - * Allocate a linked list of \c __GLcontextModes structures. The fields of - * each structure will be initialized to "reasonable" default values. In - * most cases this is the default value defined by table 3.4 of the GLX - * 1.3 specification. This means that most values are either initialized to - * zero or \c GLX_DONT_CARE (which is -1). As support for additional - * extensions is added, the new values will be initialized to appropriate - * values from the extension specification. - * - * \param count Number of structures to allocate. - * \param minimum_size Minimum size of a structure to allocate. This allows - * for differences in the version of the - * \c __GLcontextModes stucture used in libGL and in a - * DRI-based driver. - * \returns A pointer to the first element in a linked list of \c count - * stuctures on success, or \c NULL on failure. - * - * \warning Use of \c minimum_size does \b not guarantee binary compatibility. - * The fundamental assumption is that if the \c minimum_size - * specified by the driver and the size of the \c __GLcontextModes - * structure in libGL is the same, then the meaning of each byte in - * the structure is the same in both places. \b Be \b careful! - * Basically this means that fields have to be added in libGL and - * then propagated to drivers. Drivers should \b never arbitrarilly - * extend the \c __GLcontextModes data-structure. - */ -__GLcontextModes * -_gl_context_modes_create( unsigned count, size_t minimum_size ) -{ - const size_t size = (minimum_size > sizeof( __GLcontextModes )) - ? minimum_size : sizeof( __GLcontextModes ); - __GLcontextModes * base = NULL; - __GLcontextModes ** next; - unsigned i; - - next = & base; - for ( i = 0 ; i < count ; i++ ) { - *next = (__GLcontextModes *) _mesa_malloc( size ); - if ( *next == NULL ) { - _gl_context_modes_destroy( base ); - base = NULL; - break; - } - - (void) _mesa_memset( *next, 0, size ); - (*next)->visualID = GLX_DONT_CARE; - (*next)->visualType = GLX_DONT_CARE; - (*next)->visualRating = GLX_NONE; - (*next)->transparentPixel = GLX_NONE; - (*next)->transparentRed = GLX_DONT_CARE; - (*next)->transparentGreen = GLX_DONT_CARE; - (*next)->transparentBlue = GLX_DONT_CARE; - (*next)->transparentAlpha = GLX_DONT_CARE; - (*next)->transparentIndex = GLX_DONT_CARE; - (*next)->xRenderable = GLX_DONT_CARE; - (*next)->fbconfigID = GLX_DONT_CARE; - (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML; - (*next)->bindToTextureRgb = GLX_DONT_CARE; - (*next)->bindToTextureRgba = GLX_DONT_CARE; - (*next)->bindToMipmapTexture = GLX_DONT_CARE; - (*next)->bindToTextureTargets = GLX_DONT_CARE; - (*next)->yInverted = GLX_DONT_CARE; - - next = & ((*next)->next); - } - - return base; -} - - -/** - * Destroy a linked list of \c __GLcontextModes structures created by - * \c _gl_context_modes_create. - * - * \param modes Linked list of structures to be destroyed. All structres - * in the list will be freed. - */ -void -_gl_context_modes_destroy( __GLcontextModes * modes ) -{ - while ( modes != NULL ) { - __GLcontextModes * const next = modes->next; - - _mesa_free( modes ); - modes = next; - } -} - - -/** - * Find a context mode matching a Visual ID. - * - * \param modes List list of context-mode structures to be searched. - * \param vid Visual ID to be found. - * \returns A pointer to a context-mode in \c modes if \c vid was found in - * the list, or \c NULL if it was not. - */ - -__GLcontextModes * -_gl_context_modes_find_visual(__GLcontextModes *modes, int vid) -{ - __GLcontextModes *m; - - for (m = modes; m != NULL; m = m->next) - if (m->visualID == vid) - return m; - - return NULL; -} - -__GLcontextModes * -_gl_context_modes_find_fbconfig(__GLcontextModes *modes, int fbid) -{ - __GLcontextModes *m; - - for (m = modes; m != NULL; m = m->next) - if (m->fbconfigID == fbid) - return m; - - return NULL; -} - -/** - * Determine if two context-modes are the same. This is intended to be used - * by libGL implementations to compare to sets of driver generated FBconfigs. - * - * \param a Context-mode to be compared. - * \param b Context-mode to be compared. - * \returns \c GL_TRUE if the two context-modes are the same. \c GL_FALSE is - * returned otherwise. - */ -GLboolean -_gl_context_modes_are_same( const __GLcontextModes * a, - const __GLcontextModes * b ) -{ - return( (a->rgbMode == b->rgbMode) && - (a->floatMode == b->floatMode) && - (a->colorIndexMode == b->colorIndexMode) && - (a->doubleBufferMode == b->doubleBufferMode) && - (a->stereoMode == b->stereoMode) && - (a->redBits == b->redBits) && - (a->greenBits == b->greenBits) && - (a->blueBits == b->blueBits) && - (a->alphaBits == b->alphaBits) && -#if 0 /* For some reason these don't get set on the client-side in libGL. */ - (a->redMask == b->redMask) && - (a->greenMask == b->greenMask) && - (a->blueMask == b->blueMask) && - (a->alphaMask == b->alphaMask) && -#endif - (a->rgbBits == b->rgbBits) && - (a->indexBits == b->indexBits) && - (a->accumRedBits == b->accumRedBits) && - (a->accumGreenBits == b->accumGreenBits) && - (a->accumBlueBits == b->accumBlueBits) && - (a->accumAlphaBits == b->accumAlphaBits) && - (a->depthBits == b->depthBits) && - (a->stencilBits == b->stencilBits) && - (a->numAuxBuffers == b->numAuxBuffers) && - (a->level == b->level) && - (a->pixmapMode == b->pixmapMode) && - (a->visualRating == b->visualRating) && - - (a->transparentPixel == b->transparentPixel) && - - ((a->transparentPixel != GLX_TRANSPARENT_RGB) || - ((a->transparentRed == b->transparentRed) && - (a->transparentGreen == b->transparentGreen) && - (a->transparentBlue == b->transparentBlue) && - (a->transparentAlpha == b->transparentAlpha))) && - - ((a->transparentPixel != GLX_TRANSPARENT_INDEX) || - (a->transparentIndex == b->transparentIndex)) && - - (a->sampleBuffers == b->sampleBuffers) && - (a->samples == b->samples) && - ((a->drawableType & b->drawableType) != 0) && - (a->renderType == b->renderType) && - (a->maxPbufferWidth == b->maxPbufferWidth) && - (a->maxPbufferHeight == b->maxPbufferHeight) && - (a->maxPbufferPixels == b->maxPbufferPixels) && - (a->optimalPbufferWidth == b->optimalPbufferWidth) && - (a->optimalPbufferHeight == b->optimalPbufferHeight) && - (a->swapMethod == b->swapMethod) && - (a->bindToTextureRgb == b->bindToTextureRgb) && - (a->bindToTextureRgba == b->bindToTextureRgba) && - (a->bindToMipmapTexture == b->bindToMipmapTexture) && - (a->bindToTextureTargets == b->bindToTextureTargets) && - (a->yInverted == b->yInverted) ); -} +/* + * (C) Copyright IBM Corporation 2003 + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS 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. + */ + +/** + * \file glcontextmodes.c + * Utility routines for working with \c __GLcontextModes structures. At + * some point most or all of these functions will be moved to the Mesa + * code base. + * + * \author Ian Romanick <idr@us.ibm.com> + */ + +#if defined(IN_MINI_GLX) +#include <GL/gl.h> +#else +#if defined(HAVE_DIX_CONFIG_H) +# include <dix-config.h> +#endif +#include <X11/X.h> +#include <GL/glx.h> +#include "GL/glxint.h" +#endif + +/* Memory macros */ +#if defined(IN_MINI_GLX) +# include <stdlib.h> +# include <string.h> +# define _mesa_malloc(b) malloc(b) +# define _mesa_free(m) free(m) +# define _mesa_memset memset +#else +# ifdef XFree86Server +# include <os.h> +# include <string.h> +# define _mesa_malloc(b) malloc(b) +# define _mesa_free(m) free(m) +# define _mesa_memset memset +# else +# include <X11/Xlibint.h> +# define _mesa_memset memset +# define _mesa_malloc(b) Xmalloc(b) +# define _mesa_free(m) free(m) +# endif /* XFree86Server */ +#endif /* !defined(IN_MINI_GLX) */ + +#include "glcontextmodes.h" + +#if !defined(IN_MINI_GLX) +#define NUM_VISUAL_TYPES 6 + +/** + * Convert an X visual type to a GLX visual type. + * + * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.) + * to be converted. + * \return If \c visualType is a valid X visual type, a GLX visual type will + * be returned. Otherwise \c GLX_NONE will be returned. + */ +GLint +_gl_convert_from_x_visual_type( int visualType ) +{ + static const int glx_visual_types[ NUM_VISUAL_TYPES ] = { + GLX_STATIC_GRAY, GLX_GRAY_SCALE, + GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, + GLX_TRUE_COLOR, GLX_DIRECT_COLOR + }; + + return ( (unsigned) visualType < NUM_VISUAL_TYPES ) + ? glx_visual_types[ visualType ] : GLX_NONE; +} + + +/** + * Convert a GLX visual type to an X visual type. + * + * \param visualType GLX visual type (i.e., \c GLX_TRUE_COLOR, + * \c GLX_STATIC_GRAY, etc.) to be converted. + * \return If \c visualType is a valid GLX visual type, an X visual type will + * be returned. Otherwise -1 will be returned. + */ +GLint +_gl_convert_to_x_visual_type( int visualType ) +{ + static const int x_visual_types[ NUM_VISUAL_TYPES ] = { + TrueColor, DirectColor, + PseudoColor, StaticColor, + GrayScale, StaticGray + }; + + return ( (unsigned) (visualType - GLX_TRUE_COLOR) < NUM_VISUAL_TYPES ) + ? x_visual_types[ visualType - GLX_TRUE_COLOR ] : -1; +} + + +/** + * Copy a GLX visual config structure to a GL context mode structure. All + * of the fields in \c config are copied to \c mode. Additional fields in + * \c mode that can be derrived from the fields of \c config (i.e., + * \c haveDepthBuffer) are also filled in. The remaining fields in \c mode + * that cannot be derived are set to default values. + * + * \param mode Destination GL context mode. + * \param config Source GLX visual config. + * + * \note + * The \c fbconfigID and \c visualID fields of the \c __GLcontextModes + * structure will be set to the \c vid of the \c __GLXvisualConfig structure. + */ +void +_gl_copy_visual_to_context_mode( __GLcontextModes * mode, + const __GLXvisualConfig * config ) +{ + __GLcontextModes * const next = mode->next; + + (void) _mesa_memset( mode, 0, sizeof( __GLcontextModes ) ); + mode->next = next; + + mode->visualID = config->vid; + mode->visualType = _gl_convert_from_x_visual_type( config->class ); + mode->xRenderable = GL_TRUE; + mode->fbconfigID = config->vid; + mode->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT; + + mode->rgbMode = (config->rgba != 0); + mode->renderType = (mode->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; + + mode->colorIndexMode = !(mode->rgbMode); + mode->doubleBufferMode = (config->doubleBuffer != 0); + mode->stereoMode = (config->stereo != 0); + + mode->haveAccumBuffer = ((config->accumRedSize + + config->accumGreenSize + + config->accumBlueSize + + config->accumAlphaSize) > 0); + mode->haveDepthBuffer = (config->depthSize > 0); + mode->haveStencilBuffer = (config->stencilSize > 0); + + mode->redBits = config->redSize; + mode->greenBits = config->greenSize; + mode->blueBits = config->blueSize; + mode->alphaBits = config->alphaSize; + mode->redMask = config->redMask; + mode->greenMask = config->greenMask; + mode->blueMask = config->blueMask; + mode->alphaMask = config->alphaMask; + mode->rgbBits = mode->rgbMode ? config->bufferSize : 0; + mode->indexBits = mode->colorIndexMode ? config->bufferSize : 0; + + mode->accumRedBits = config->accumRedSize; + mode->accumGreenBits = config->accumGreenSize; + mode->accumBlueBits = config->accumBlueSize; + mode->accumAlphaBits = config->accumAlphaSize; + mode->depthBits = config->depthSize; + mode->stencilBits = config->stencilSize; + + mode->numAuxBuffers = config->auxBuffers; + mode->level = config->level; + + mode->visualRating = config->visualRating; + mode->transparentPixel = config->transparentPixel; + mode->transparentRed = config->transparentRed; + mode->transparentGreen = config->transparentGreen; + mode->transparentBlue = config->transparentBlue; + mode->transparentAlpha = config->transparentAlpha; + mode->transparentIndex = config->transparentIndex; + mode->samples = config->multiSampleSize; + mode->sampleBuffers = config->nMultiSampleBuffers; + /* mode->visualSelectGroup = config->visualSelectGroup; ? */ + + mode->swapMethod = GLX_SWAP_UNDEFINED_OML; + + mode->bindToTextureRgb = (mode->rgbMode) ? GL_TRUE : GL_FALSE; + mode->bindToTextureRgba = (mode->rgbMode && mode->alphaBits) ? + GL_TRUE : GL_FALSE; + mode->bindToMipmapTexture = mode->rgbMode ? GL_TRUE : GL_FALSE; + mode->bindToTextureTargets = mode->rgbMode ? + GLX_TEXTURE_1D_BIT_EXT | GLX_TEXTURE_2D_BIT_EXT | + GLX_TEXTURE_RECTANGLE_BIT_EXT : 0; + mode->yInverted = GL_FALSE; +} + + +/** + * Get data from a GL context mode. + * + * \param mode GL context mode whose data is to be returned. + * \param attribute Attribute of \c mode that is to be returned. + * \param value_return Location to store the data member of \c mode. + * \return If \c attribute is a valid attribute of \c mode, zero is + * returned. Otherwise \c GLX_BAD_ATTRIBUTE is returned. + */ +int +_gl_get_context_mode_data(const __GLcontextModes *mode, int attribute, + int *value_return) +{ + switch (attribute) { + case GLX_USE_GL: + *value_return = GL_TRUE; + return 0; + case GLX_BUFFER_SIZE: + *value_return = mode->rgbBits; + return 0; + case GLX_RGBA: + *value_return = mode->rgbMode; + return 0; + case GLX_RED_SIZE: + *value_return = mode->redBits; + return 0; + case GLX_GREEN_SIZE: + *value_return = mode->greenBits; + return 0; + case GLX_BLUE_SIZE: + *value_return = mode->blueBits; + return 0; + case GLX_ALPHA_SIZE: + *value_return = mode->alphaBits; + return 0; + case GLX_DOUBLEBUFFER: + *value_return = mode->doubleBufferMode; + return 0; + case GLX_STEREO: + *value_return = mode->stereoMode; + return 0; + case GLX_AUX_BUFFERS: + *value_return = mode->numAuxBuffers; + return 0; + case GLX_DEPTH_SIZE: + *value_return = mode->depthBits; + return 0; + case GLX_STENCIL_SIZE: + *value_return = mode->stencilBits; + return 0; + case GLX_ACCUM_RED_SIZE: + *value_return = mode->accumRedBits; + return 0; + case GLX_ACCUM_GREEN_SIZE: + *value_return = mode->accumGreenBits; + return 0; + case GLX_ACCUM_BLUE_SIZE: + *value_return = mode->accumBlueBits; + return 0; + case GLX_ACCUM_ALPHA_SIZE: + *value_return = mode->accumAlphaBits; + return 0; + case GLX_LEVEL: + *value_return = mode->level; + return 0; + case GLX_TRANSPARENT_TYPE_EXT: + *value_return = mode->transparentPixel; + return 0; + case GLX_TRANSPARENT_RED_VALUE: + *value_return = mode->transparentRed; + return 0; + case GLX_TRANSPARENT_GREEN_VALUE: + *value_return = mode->transparentGreen; + return 0; + case GLX_TRANSPARENT_BLUE_VALUE: + *value_return = mode->transparentBlue; + return 0; + case GLX_TRANSPARENT_ALPHA_VALUE: + *value_return = mode->transparentAlpha; + return 0; + case GLX_TRANSPARENT_INDEX_VALUE: + *value_return = mode->transparentIndex; + return 0; + case GLX_X_VISUAL_TYPE: + *value_return = mode->visualType; + return 0; + case GLX_CONFIG_CAVEAT: + *value_return = mode->visualRating; + return 0; + case GLX_VISUAL_ID: + *value_return = mode->visualID; + return 0; + case GLX_DRAWABLE_TYPE: + *value_return = mode->drawableType; + return 0; + case GLX_RENDER_TYPE: + *value_return = mode->renderType; + return 0; + case GLX_X_RENDERABLE: + *value_return = mode->xRenderable; + return 0; + case GLX_FBCONFIG_ID: + *value_return = mode->fbconfigID; + return 0; + case GLX_MAX_PBUFFER_WIDTH: + *value_return = mode->maxPbufferWidth; + return 0; + case GLX_MAX_PBUFFER_HEIGHT: + *value_return = mode->maxPbufferHeight; + return 0; + case GLX_MAX_PBUFFER_PIXELS: + *value_return = mode->maxPbufferPixels; + return 0; + case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: + *value_return = mode->optimalPbufferWidth; + return 0; + case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: + *value_return = mode->optimalPbufferHeight; + return 0; + case GLX_SWAP_METHOD_OML: + *value_return = mode->swapMethod; + return 0; + case GLX_SAMPLE_BUFFERS_SGIS: + *value_return = mode->sampleBuffers; + return 0; + case GLX_SAMPLES_SGIS: + *value_return = mode->samples; + return 0; + case GLX_BIND_TO_TEXTURE_RGB_EXT: + *value_return = mode->bindToTextureRgb; + return 0; + case GLX_BIND_TO_TEXTURE_RGBA_EXT: + *value_return = mode->bindToTextureRgba; + return 0; + case GLX_BIND_TO_MIPMAP_TEXTURE_EXT: + *value_return = mode->bindToMipmapTexture == GL_TRUE ? GL_TRUE : + GL_FALSE; + return 0; + case GLX_BIND_TO_TEXTURE_TARGETS_EXT: + *value_return = mode->bindToTextureTargets; + return 0; + case GLX_Y_INVERTED_EXT: + *value_return = mode->yInverted; + return 0; + + /* Applications are NOT allowed to query GLX_VISUAL_SELECT_GROUP_SGIX. + * It is ONLY for communication between the GLX client and the GLX + * server. + */ + case GLX_VISUAL_SELECT_GROUP_SGIX: + default: + return GLX_BAD_ATTRIBUTE; + } +} +#endif /* !defined(IN_MINI_GLX) */ + + +/** + * Allocate a linked list of \c __GLcontextModes structures. The fields of + * each structure will be initialized to "reasonable" default values. In + * most cases this is the default value defined by table 3.4 of the GLX + * 1.3 specification. This means that most values are either initialized to + * zero or \c GLX_DONT_CARE (which is -1). As support for additional + * extensions is added, the new values will be initialized to appropriate + * values from the extension specification. + * + * \param count Number of structures to allocate. + * \param minimum_size Minimum size of a structure to allocate. This allows + * for differences in the version of the + * \c __GLcontextModes stucture used in libGL and in a + * DRI-based driver. + * \returns A pointer to the first element in a linked list of \c count + * stuctures on success, or \c NULL on failure. + * + * \warning Use of \c minimum_size does \b not guarantee binary compatibility. + * The fundamental assumption is that if the \c minimum_size + * specified by the driver and the size of the \c __GLcontextModes + * structure in libGL is the same, then the meaning of each byte in + * the structure is the same in both places. \b Be \b careful! + * Basically this means that fields have to be added in libGL and + * then propagated to drivers. Drivers should \b never arbitrarilly + * extend the \c __GLcontextModes data-structure. + */ +__GLcontextModes * +_gl_context_modes_create( unsigned count, size_t minimum_size ) +{ + const size_t size = (minimum_size > sizeof( __GLcontextModes )) + ? minimum_size : sizeof( __GLcontextModes ); + __GLcontextModes * base = NULL; + __GLcontextModes ** next; + unsigned i; + + next = & base; + for ( i = 0 ; i < count ; i++ ) { + *next = (__GLcontextModes *) _mesa_malloc( size ); + if ( *next == NULL ) { + _gl_context_modes_destroy( base ); + base = NULL; + break; + } + + (void) _mesa_memset( *next, 0, size ); + (*next)->visualID = GLX_DONT_CARE; + (*next)->visualType = GLX_DONT_CARE; + (*next)->visualRating = GLX_NONE; + (*next)->transparentPixel = GLX_NONE; + (*next)->transparentRed = GLX_DONT_CARE; + (*next)->transparentGreen = GLX_DONT_CARE; + (*next)->transparentBlue = GLX_DONT_CARE; + (*next)->transparentAlpha = GLX_DONT_CARE; + (*next)->transparentIndex = GLX_DONT_CARE; + (*next)->xRenderable = GLX_DONT_CARE; + (*next)->fbconfigID = GLX_DONT_CARE; + (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML; + (*next)->bindToTextureRgb = GLX_DONT_CARE; + (*next)->bindToTextureRgba = GLX_DONT_CARE; + (*next)->bindToMipmapTexture = GLX_DONT_CARE; + (*next)->bindToTextureTargets = GLX_DONT_CARE; + (*next)->yInverted = GLX_DONT_CARE; + + next = & ((*next)->next); + } + + return base; +} + + +/** + * Destroy a linked list of \c __GLcontextModes structures created by + * \c _gl_context_modes_create. + * + * \param modes Linked list of structures to be destroyed. All structres + * in the list will be freed. + */ +void +_gl_context_modes_destroy( __GLcontextModes * modes ) +{ + while ( modes != NULL ) { + __GLcontextModes * const next = modes->next; + + _mesa_free( modes ); + modes = next; + } +} + + +/** + * Find a context mode matching a Visual ID. + * + * \param modes List list of context-mode structures to be searched. + * \param vid Visual ID to be found. + * \returns A pointer to a context-mode in \c modes if \c vid was found in + * the list, or \c NULL if it was not. + */ + +__GLcontextModes * +_gl_context_modes_find_visual(__GLcontextModes *modes, int vid) +{ + __GLcontextModes *m; + + for (m = modes; m != NULL; m = m->next) + if (m->visualID == vid) + return m; + + return NULL; +} + +__GLcontextModes * +_gl_context_modes_find_fbconfig(__GLcontextModes *modes, int fbid) +{ + __GLcontextModes *m; + + for (m = modes; m != NULL; m = m->next) + if (m->fbconfigID == fbid) + return m; + + return NULL; +} + +/** + * Determine if two context-modes are the same. This is intended to be used + * by libGL implementations to compare to sets of driver generated FBconfigs. + * + * \param a Context-mode to be compared. + * \param b Context-mode to be compared. + * \returns \c GL_TRUE if the two context-modes are the same. \c GL_FALSE is + * returned otherwise. + */ +GLboolean +_gl_context_modes_are_same( const __GLcontextModes * a, + const __GLcontextModes * b ) +{ + return( (a->rgbMode == b->rgbMode) && + (a->floatMode == b->floatMode) && + (a->colorIndexMode == b->colorIndexMode) && + (a->doubleBufferMode == b->doubleBufferMode) && + (a->stereoMode == b->stereoMode) && + (a->redBits == b->redBits) && + (a->greenBits == b->greenBits) && + (a->blueBits == b->blueBits) && + (a->alphaBits == b->alphaBits) && +#if 0 /* For some reason these don't get set on the client-side in libGL. */ + (a->redMask == b->redMask) && + (a->greenMask == b->greenMask) && + (a->blueMask == b->blueMask) && + (a->alphaMask == b->alphaMask) && +#endif + (a->rgbBits == b->rgbBits) && + (a->indexBits == b->indexBits) && + (a->accumRedBits == b->accumRedBits) && + (a->accumGreenBits == b->accumGreenBits) && + (a->accumBlueBits == b->accumBlueBits) && + (a->accumAlphaBits == b->accumAlphaBits) && + (a->depthBits == b->depthBits) && + (a->stencilBits == b->stencilBits) && + (a->numAuxBuffers == b->numAuxBuffers) && + (a->level == b->level) && + (a->pixmapMode == b->pixmapMode) && + (a->visualRating == b->visualRating) && + + (a->transparentPixel == b->transparentPixel) && + + ((a->transparentPixel != GLX_TRANSPARENT_RGB) || + ((a->transparentRed == b->transparentRed) && + (a->transparentGreen == b->transparentGreen) && + (a->transparentBlue == b->transparentBlue) && + (a->transparentAlpha == b->transparentAlpha))) && + + ((a->transparentPixel != GLX_TRANSPARENT_INDEX) || + (a->transparentIndex == b->transparentIndex)) && + + (a->sampleBuffers == b->sampleBuffers) && + (a->samples == b->samples) && + ((a->drawableType & b->drawableType) != 0) && + (a->renderType == b->renderType) && + (a->maxPbufferWidth == b->maxPbufferWidth) && + (a->maxPbufferHeight == b->maxPbufferHeight) && + (a->maxPbufferPixels == b->maxPbufferPixels) && + (a->optimalPbufferWidth == b->optimalPbufferWidth) && + (a->optimalPbufferHeight == b->optimalPbufferHeight) && + (a->swapMethod == b->swapMethod) && + (a->bindToTextureRgb == b->bindToTextureRgb) && + (a->bindToTextureRgba == b->bindToTextureRgba) && + (a->bindToMipmapTexture == b->bindToMipmapTexture) && + (a->bindToTextureTargets == b->bindToTextureTargets) && + (a->yInverted == b->yInverted) ); +} diff --git a/xorg-server/hw/xquartz/GL/indirect.c b/xorg-server/hw/xquartz/GL/indirect.c index e56dac1a1..b40f38d31 100644 --- a/xorg-server/hw/xquartz/GL/indirect.c +++ b/xorg-server/hw/xquartz/GL/indirect.c @@ -222,7 +222,7 @@ __glXAquaScreenCreateContext(__GLXscreen *screen, GLAQUA_DEBUG_MSG("glXAquaScreenCreateContext\n"); - context = xcalloc(1, sizeof (__GLXAquaContext)); + context = calloc(1, sizeof (__GLXAquaContext)); if (context == NULL) return NULL; @@ -241,7 +241,7 @@ __glXAquaScreenCreateContext(__GLXscreen *screen, context->pixelFormat = makeFormat(conf); if (!context->pixelFormat) { - xfree(context); + free(context); return NULL; } @@ -253,7 +253,7 @@ __glXAquaScreenCreateContext(__GLXscreen *screen, if (gl_err != 0) { ErrorF("CGLCreateContext error: %s\n", CGLErrorString(gl_err)); CGLDestroyPixelFormat(context->pixelFormat); - xfree(context); + free(context); return NULL; } @@ -286,7 +286,7 @@ static void __glXAquaContextDestroy(__GLXcontext *baseContext) { if (context->pixelFormat != NULL) CGLDestroyPixelFormat(context->pixelFormat); - xfree(context); + free(context); } } @@ -566,7 +566,7 @@ static void __glXAquaScreenDestroy(__GLXscreen *screen) { GLAQUA_DEBUG_MSG("glXAquaScreenDestroy(%p)\n", screen); __glXScreenDestroy(screen); - xfree(screen); + free(screen); } /* This is called by __glXInitScreens(). */ @@ -578,7 +578,7 @@ static __GLXscreen * __glXAquaScreenProbe(ScreenPtr pScreen) { if (pScreen == NULL) return NULL; - screen = xcalloc(1, sizeof *screen); + screen = calloc(1, sizeof *screen); if(NULL == screen) return NULL; @@ -635,7 +635,7 @@ static void __glXAquaDrawableDestroy(__GLXdrawable *base) { *to validate the test, beyond using gdb with print. */ - xfree(glxPriv); + free(glxPriv); } static __GLXdrawable * @@ -648,7 +648,7 @@ __glXAquaScreenCreateDrawable(ClientPtr client, __GLXconfig *conf) { __GLXAquaDrawable *glxPriv; - glxPriv = xalloc(sizeof *glxPriv); + glxPriv = malloc(sizeof *glxPriv); if(glxPriv == NULL) return NULL; @@ -656,7 +656,7 @@ __glXAquaScreenCreateDrawable(ClientPtr client, memset(glxPriv, 0, sizeof *glxPriv); if(!__glXDrawableInit(&glxPriv->base, screen, pDraw, type, glxDrawId, conf)) { - xfree(glxPriv); + free(glxPriv); return NULL; } diff --git a/xorg-server/hw/xquartz/GL/visualConfigs.c b/xorg-server/hw/xquartz/GL/visualConfigs.c index cecc90265..0d5793262 100644 --- a/xorg-server/hw/xquartz/GL/visualConfigs.c +++ b/xorg-server/hw/xquartz/GL/visualConfigs.c @@ -1,285 +1,285 @@ -/* - * Copyright (c) 2007, 2008 Apple Inc. - * Copyright (c) 2004 Torrey T. Lyons. All Rights Reserved. - * Copyright (c) 2002 Greg Parker. All Rights Reserved. - * - * Portions of this file are copied from Mesa's xf86glx.c, - * which contains the following copyright: - * - * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. - * 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "dri.h" - -#include <OpenGL/OpenGL.h> -#include <OpenGL/gl.h> -#include <OpenGL/glext.h> -#include <OpenGL/CGLContext.h> - -#include <GL/glxproto.h> -#include <windowstr.h> -#include <resource.h> -#include <GL/glxint.h> -#include <GL/glxtokens.h> -#include <scrnintstr.h> -#include <glxserver.h> -#include <glxscreens.h> -#include <glxdrawable.h> -#include <glxcontext.h> -#include <glxext.h> -#include <glxutil.h> -#include <glxscreens.h> -#include <GL/internal/glcore.h> - -#include "capabilities.h" -#include "visualConfigs.h" -#include "darwinfb.h" - -/* Based originally on code from indirect.c which was based on code from i830_dri.c. */ -__GLXconfig *__glXAquaCreateVisualConfigs(int *numConfigsPtr, int screenNumber) { - int numConfigs = 0; - __GLXconfig *visualConfigs, *c; - struct glCapabilities caps; - struct glCapabilitiesConfig *conf; - int stereo, depth, aux, buffers, stencil, accum, color, msample; - - if(getGlCapabilities(&caps)) { - ErrorF("error from getGlCapabilities()!\n"); - return NULL; - } - - /* - conf->stereo is 0 or 1, but we need at least 1 iteration of the loop, - so we treat a true conf->stereo as 2. - - The depth size is 0 or 24. Thus we do 2 iterations for that. - - conf->aux_buffers (when available/non-zero) result in 2 iterations instead of 1. - - conf->buffers indicates whether we have single or double buffering. - - conf->total_stencil_bit_depths - - conf->total_color_buffers indicates the RGB/RGBA color depths. - - conf->total_accum_buffers iterations for accum (with at least 1 if equal to 0) - - conf->total_depth_buffer_depths - - conf->multisample_buffers iterations (with at least 1 if equal to 0). We add 1 - for the 0 multisampling config. - - */ - - assert(NULL != caps.configurations); - - numConfigs = 0; - - for(conf = caps.configurations; conf; conf = conf->next) { - if(conf->total_color_buffers <= 0) - continue; - - numConfigs += (conf->stereo ? 2 : 1) - * (conf->aux_buffers ? 2 : 1) - * conf->buffers - * ((conf->total_stencil_bit_depths > 0) ? conf->total_stencil_bit_depths : 1) - * conf->total_color_buffers - * ((conf->total_accum_buffers > 0) ? conf->total_accum_buffers : 1) - * conf->total_depth_buffer_depths - * (conf->multisample_buffers + 1); - } - - if(numConfigsPtr) - *numConfigsPtr = numConfigs; - - visualConfigs = xcalloc(sizeof(*visualConfigs), numConfigs); - - if(NULL == visualConfigs) { - ErrorF("xcalloc failure when allocating visualConfigs\n"); - freeGlCapabilities(&caps); - return NULL; - } - - c = visualConfigs; /* current buffer */ - for(conf = caps.configurations; conf; conf = conf->next) { - for(stereo = 0; stereo < (conf->stereo ? 2 : 1); ++stereo) { - for(aux = 0; aux < (conf->aux_buffers ? 2 : 1); ++aux) { - for(buffers = 0; buffers < conf->buffers; ++buffers) { - for(stencil = 0; stencil < ((conf->total_stencil_bit_depths > 0) ? - conf->total_stencil_bit_depths : 1); ++stencil) { - for(color = 0; color < conf->total_color_buffers; ++color) { - for(accum = 0; accum < ((conf->total_accum_buffers > 0) ? - conf->total_accum_buffers : 1); ++accum) { - for(depth = 0; depth < conf->total_depth_buffer_depths; ++depth) { - for(msample = 0; msample < (conf->multisample_buffers + 1); ++msample) { - - // Global - c->visualID = -1; - c->visualType = GLX_TRUE_COLOR; - c->next = c + 1; - - c->screen = screenNumber; - - c->level = 0; - c->indexBits = 0; - c->pixmapMode = 0; // TODO: What should this be? - - if(conf->accelerated) { - c->visualRating = GLX_NONE; - } else { - c->visualRating = GLX_SLOW_VISUAL_EXT; - } - - c->transparentPixel = GLX_NONE; - c->transparentRed = GLX_NONE; - c->transparentGreen = GLX_NONE; - c->transparentBlue = GLX_NONE; - c->transparentAlpha = GLX_NONE; - c->transparentIndex = GLX_NONE; - - c->visualSelectGroup = 0; - - c->swapMethod = GLX_SWAP_UNDEFINED_OML; - - // Stereo - c->stereoMode = stereo ? TRUE : FALSE; - - // Aux buffers - c->numAuxBuffers = aux ? conf->aux_buffers : 0; - - // Double Buffered - c->doubleBufferMode = buffers ? TRUE : FALSE; - - // Stencil Buffer - if(conf->total_stencil_bit_depths > 0) { - c->stencilBits = conf->stencil_bit_depths[stencil]; - } else { - c->stencilBits = 0; - } - - // Color - if(GLCAPS_COLOR_BUF_INVALID_VALUE != conf->color_buffers[color].a) { - c->alphaBits = conf->color_buffers[color].a; - } else { - c->alphaBits = 0; - } - c->redBits = conf->color_buffers[color].r; - c->greenBits = conf->color_buffers[color].g; - c->blueBits = conf->color_buffers[color].b; - - c->rgbBits = c->alphaBits + c->redBits + c->greenBits + c->blueBits; - - c->alphaMask = AM_ARGB(c->alphaBits, c->redBits, c->greenBits, c->blueBits); - c->redMask = RM_ARGB(c->alphaBits, c->redBits, c->greenBits, c->blueBits); - c->greenMask = GM_ARGB(c->alphaBits, c->redBits, c->greenBits, c->blueBits); - c->blueMask = BM_ARGB(c->alphaBits, c->redBits, c->greenBits, c->blueBits); - - // Accumulation Buffers - if(conf->total_accum_buffers > 0) { - c->accumRedBits = conf->accum_buffers[accum].r; - c->accumGreenBits = conf->accum_buffers[accum].g; - c->accumBlueBits = conf->accum_buffers[accum].b; - if(GLCAPS_COLOR_BUF_INVALID_VALUE != conf->accum_buffers[accum].a) { - c->accumAlphaBits = conf->accum_buffers[accum].a; - } else { - c->accumAlphaBits = 0; - } - } else { - c->accumRedBits = 0; - c->accumGreenBits = 0; - c->accumBlueBits = 0; - c->accumAlphaBits = 0; - } - - // Depth - c->depthBits = conf->depth_buffers[depth]; - - // MultiSample - if(msample > 0) { - c->samples = conf->multisample_samples; - c->sampleBuffers = conf->multisample_buffers; - } else { - c->samples = 0; - c->sampleBuffers = 0; - } - - /* - * The Apple libGL supports GLXPixmaps and - * GLXPbuffers in direct mode. - */ - /* SGIX_fbconfig / GLX 1.3 */ - c->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; - c->renderType = GLX_RGBA_BIT; - c->xRenderable = GL_TRUE; - c->fbconfigID = -1; - - /* SGIX_pbuffer / GLX 1.3 */ - - /* - * The CGL layer provides a way of retrieving - * the maximum pbuffer width/height, but only - * if we create a context and call glGetIntegerv. - * - * The following values are from a test program - * that does so. - */ - c->maxPbufferWidth = 8192; - c->maxPbufferHeight = 8192; - c->maxPbufferPixels = /*Do we need this?*/ 0; - /* - * There is no introspection for this sort of thing - * with CGL. What should we do realistically? - */ - c->optimalPbufferWidth = 0; - c->optimalPbufferHeight = 0; - - /* EXT_texture_from_pixmap */ - c->bindToTextureRgb = 0; - c->bindToTextureRgba = 0; - c->bindToMipmapTexture = 0; - c->bindToTextureTargets = 0; - c->yInverted = 0; - - c = c->next; - } - } - } - } - } - } - } - } - } - - (c-1)->next = NULL; - - if (c - visualConfigs != numConfigs) { - FatalError("numConfigs calculation error in setVisualConfigs! numConfigs is %d i is %d\n", numConfigs, (int)(c - visualConfigs)); - } - - freeGlCapabilities(&caps); - return visualConfigs; -} +/* + * Copyright (c) 2007, 2008 Apple Inc. + * Copyright (c) 2004 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Greg Parker. All Rights Reserved. + * + * Portions of this file are copied from Mesa's xf86glx.c, + * which contains the following copyright: + * + * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. + * 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "dri.h" + +#include <OpenGL/OpenGL.h> +#include <OpenGL/gl.h> +#include <OpenGL/glext.h> +#include <OpenGL/CGLContext.h> + +#include <GL/glxproto.h> +#include <windowstr.h> +#include <resource.h> +#include <GL/glxint.h> +#include <GL/glxtokens.h> +#include <scrnintstr.h> +#include <glxserver.h> +#include <glxscreens.h> +#include <glxdrawable.h> +#include <glxcontext.h> +#include <glxext.h> +#include <glxutil.h> +#include <glxscreens.h> +#include <GL/internal/glcore.h> + +#include "capabilities.h" +#include "visualConfigs.h" +#include "darwinfb.h" + +/* Based originally on code from indirect.c which was based on code from i830_dri.c. */ +__GLXconfig *__glXAquaCreateVisualConfigs(int *numConfigsPtr, int screenNumber) { + int numConfigs = 0; + __GLXconfig *visualConfigs, *c; + struct glCapabilities caps; + struct glCapabilitiesConfig *conf; + int stereo, depth, aux, buffers, stencil, accum, color, msample; + + if(getGlCapabilities(&caps)) { + ErrorF("error from getGlCapabilities()!\n"); + return NULL; + } + + /* + conf->stereo is 0 or 1, but we need at least 1 iteration of the loop, + so we treat a true conf->stereo as 2. + + The depth size is 0 or 24. Thus we do 2 iterations for that. + + conf->aux_buffers (when available/non-zero) result in 2 iterations instead of 1. + + conf->buffers indicates whether we have single or double buffering. + + conf->total_stencil_bit_depths + + conf->total_color_buffers indicates the RGB/RGBA color depths. + + conf->total_accum_buffers iterations for accum (with at least 1 if equal to 0) + + conf->total_depth_buffer_depths + + conf->multisample_buffers iterations (with at least 1 if equal to 0). We add 1 + for the 0 multisampling config. + + */ + + assert(NULL != caps.configurations); + + numConfigs = 0; + + for(conf = caps.configurations; conf; conf = conf->next) { + if(conf->total_color_buffers <= 0) + continue; + + numConfigs += (conf->stereo ? 2 : 1) + * (conf->aux_buffers ? 2 : 1) + * conf->buffers + * ((conf->total_stencil_bit_depths > 0) ? conf->total_stencil_bit_depths : 1) + * conf->total_color_buffers + * ((conf->total_accum_buffers > 0) ? conf->total_accum_buffers : 1) + * conf->total_depth_buffer_depths + * (conf->multisample_buffers + 1); + } + + if(numConfigsPtr) + *numConfigsPtr = numConfigs; + + visualConfigs = calloc(sizeof(*visualConfigs), numConfigs); + + if(NULL == visualConfigs) { + ErrorF("xcalloc failure when allocating visualConfigs\n"); + freeGlCapabilities(&caps); + return NULL; + } + + c = visualConfigs; /* current buffer */ + for(conf = caps.configurations; conf; conf = conf->next) { + for(stereo = 0; stereo < (conf->stereo ? 2 : 1); ++stereo) { + for(aux = 0; aux < (conf->aux_buffers ? 2 : 1); ++aux) { + for(buffers = 0; buffers < conf->buffers; ++buffers) { + for(stencil = 0; stencil < ((conf->total_stencil_bit_depths > 0) ? + conf->total_stencil_bit_depths : 1); ++stencil) { + for(color = 0; color < conf->total_color_buffers; ++color) { + for(accum = 0; accum < ((conf->total_accum_buffers > 0) ? + conf->total_accum_buffers : 1); ++accum) { + for(depth = 0; depth < conf->total_depth_buffer_depths; ++depth) { + for(msample = 0; msample < (conf->multisample_buffers + 1); ++msample) { + + // Global + c->visualID = -1; + c->visualType = GLX_TRUE_COLOR; + c->next = c + 1; + + c->screen = screenNumber; + + c->level = 0; + c->indexBits = 0; + c->pixmapMode = 0; // TODO: What should this be? + + if(conf->accelerated) { + c->visualRating = GLX_NONE; + } else { + c->visualRating = GLX_SLOW_VISUAL_EXT; + } + + c->transparentPixel = GLX_NONE; + c->transparentRed = GLX_NONE; + c->transparentGreen = GLX_NONE; + c->transparentBlue = GLX_NONE; + c->transparentAlpha = GLX_NONE; + c->transparentIndex = GLX_NONE; + + c->visualSelectGroup = 0; + + c->swapMethod = GLX_SWAP_UNDEFINED_OML; + + // Stereo + c->stereoMode = stereo ? TRUE : FALSE; + + // Aux buffers + c->numAuxBuffers = aux ? conf->aux_buffers : 0; + + // Double Buffered + c->doubleBufferMode = buffers ? TRUE : FALSE; + + // Stencil Buffer + if(conf->total_stencil_bit_depths > 0) { + c->stencilBits = conf->stencil_bit_depths[stencil]; + } else { + c->stencilBits = 0; + } + + // Color + if(GLCAPS_COLOR_BUF_INVALID_VALUE != conf->color_buffers[color].a) { + c->alphaBits = conf->color_buffers[color].a; + } else { + c->alphaBits = 0; + } + c->redBits = conf->color_buffers[color].r; + c->greenBits = conf->color_buffers[color].g; + c->blueBits = conf->color_buffers[color].b; + + c->rgbBits = c->alphaBits + c->redBits + c->greenBits + c->blueBits; + + c->alphaMask = AM_ARGB(c->alphaBits, c->redBits, c->greenBits, c->blueBits); + c->redMask = RM_ARGB(c->alphaBits, c->redBits, c->greenBits, c->blueBits); + c->greenMask = GM_ARGB(c->alphaBits, c->redBits, c->greenBits, c->blueBits); + c->blueMask = BM_ARGB(c->alphaBits, c->redBits, c->greenBits, c->blueBits); + + // Accumulation Buffers + if(conf->total_accum_buffers > 0) { + c->accumRedBits = conf->accum_buffers[accum].r; + c->accumGreenBits = conf->accum_buffers[accum].g; + c->accumBlueBits = conf->accum_buffers[accum].b; + if(GLCAPS_COLOR_BUF_INVALID_VALUE != conf->accum_buffers[accum].a) { + c->accumAlphaBits = conf->accum_buffers[accum].a; + } else { + c->accumAlphaBits = 0; + } + } else { + c->accumRedBits = 0; + c->accumGreenBits = 0; + c->accumBlueBits = 0; + c->accumAlphaBits = 0; + } + + // Depth + c->depthBits = conf->depth_buffers[depth]; + + // MultiSample + if(msample > 0) { + c->samples = conf->multisample_samples; + c->sampleBuffers = conf->multisample_buffers; + } else { + c->samples = 0; + c->sampleBuffers = 0; + } + + /* + * The Apple libGL supports GLXPixmaps and + * GLXPbuffers in direct mode. + */ + /* SGIX_fbconfig / GLX 1.3 */ + c->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; + c->renderType = GLX_RGBA_BIT; + c->xRenderable = GL_TRUE; + c->fbconfigID = -1; + + /* SGIX_pbuffer / GLX 1.3 */ + + /* + * The CGL layer provides a way of retrieving + * the maximum pbuffer width/height, but only + * if we create a context and call glGetIntegerv. + * + * The following values are from a test program + * that does so. + */ + c->maxPbufferWidth = 8192; + c->maxPbufferHeight = 8192; + c->maxPbufferPixels = /*Do we need this?*/ 0; + /* + * There is no introspection for this sort of thing + * with CGL. What should we do realistically? + */ + c->optimalPbufferWidth = 0; + c->optimalPbufferHeight = 0; + + /* EXT_texture_from_pixmap */ + c->bindToTextureRgb = 0; + c->bindToTextureRgba = 0; + c->bindToMipmapTexture = 0; + c->bindToTextureTargets = 0; + c->yInverted = 0; + + c = c->next; + } + } + } + } + } + } + } + } + } + + (c-1)->next = NULL; + + if (c - visualConfigs != numConfigs) { + FatalError("numConfigs calculation error in setVisualConfigs! numConfigs is %d i is %d\n", numConfigs, (int)(c - visualConfigs)); + } + + freeGlCapabilities(&caps); + return visualConfigs; +} diff --git a/xorg-server/hw/xquartz/applewm.c b/xorg-server/hw/xquartz/applewm.c index 15c86de00..b0f811750 100644 --- a/xorg-server/hw/xquartz/applewm.c +++ b/xorg-server/hw/xquartz/applewm.c @@ -1,746 +1,746 @@ -/************************************************************************** - -Copyright (c) 2002-2007 Apple Inc. All Rights Reserved. -Copyright (c) 2003 Torrey T. Lyons. 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, sub license, 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 NON-INFRINGEMENT. -IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. - -**************************************************************************/ - -#include "sanitizedCarbon.h" - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "quartzCommon.h" - -#include "misc.h" -#include "dixstruct.h" -#include "globals.h" -#include "extnsionst.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "windowstr.h" -#include "servermd.h" -#include "swaprep.h" -#include "propertyst.h" -#include <X11/Xatom.h> -#include "darwin.h" -#define _APPLEWM_SERVER_ -#include <X11/extensions/applewmproto.h> -#include "applewmExt.h" -#include "X11Application.h" -#include "protocol-versions.h" - -#define DEFINE_ATOM_HELPER(func,atom_name) \ -static Atom func (void) { \ - static int generation; \ - static Atom atom; \ - if (generation != serverGeneration) { \ - generation = serverGeneration; \ - atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ - } \ - return atom; \ -} - -DEFINE_ATOM_HELPER(xa_native_screen_origin, "_NATIVE_SCREEN_ORIGIN") -DEFINE_ATOM_HELPER (xa_apple_no_order_in, "_APPLE_NO_ORDER_IN") - -static AppleWMProcsPtr appleWMProcs; - -static int WMErrorBase; - -static DISPATCH_PROC(ProcAppleWMDispatch); -static DISPATCH_PROC(SProcAppleWMDispatch); - -static unsigned char WMReqCode = 0; -static int WMEventBase = 0; - -static RESTYPE ClientType, EventType; /* resource types for event masks */ -static XID eventResource; - -/* Currently selected events */ -static unsigned int eventMask = 0; - -static int WMFreeClient (pointer data, XID id); -static int WMFreeEvents (pointer data, XID id); -static void SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to); - -typedef struct _WMEvent *WMEventPtr; -typedef struct _WMEvent { - WMEventPtr next; - ClientPtr client; - XID clientResource; - unsigned int mask; -} WMEventRec; - -static inline BoxRec -make_box (int x, int y, int w, int h) -{ - BoxRec r; - r.x1 = x; - r.y1 = y; - r.x2 = x + w; - r.y2 = y + h; - return r; -} - -void -AppleWMExtensionInit( - AppleWMProcsPtr procsPtr) -{ - ExtensionEntry* extEntry; - - ClientType = CreateNewResourceType(WMFreeClient, "WMClient"); - EventType = CreateNewResourceType(WMFreeEvents, "WMEvent"); - eventResource = FakeClientID(0); - - if (ClientType && EventType && - (extEntry = AddExtension(APPLEWMNAME, - AppleWMNumberEvents, - AppleWMNumberErrors, - ProcAppleWMDispatch, - SProcAppleWMDispatch, - NULL, - StandardMinorOpcode))) - { - WMReqCode = (unsigned char)extEntry->base; - WMErrorBase = extEntry->errorBase; - WMEventBase = extEntry->eventBase; - EventSwapVector[WMEventBase] = (EventSwapPtr) SNotifyEvent; - appleWMProcs = procsPtr; - } -} - -/* Updates the _NATIVE_SCREEN_ORIGIN property on the given root window. */ -void -AppleWMSetScreenOrigin( - WindowPtr pWin -) -{ - int32_t data[2]; - - data[0] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].x - + darwinMainScreenX); - data[1] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].y - + darwinMainScreenY); - - dixChangeWindowProperty(serverClient, pWin, xa_native_screen_origin(), - XA_INTEGER, 32, PropModeReplace, 2, data, TRUE); -} - -/* Window managers can set the _APPLE_NO_ORDER_IN property on windows - that are being genie-restored from the Dock. We want them to - be mapped but remain ordered-out until the animation - completes (when the Dock will order them in). */ -Bool -AppleWMDoReorderWindow( - WindowPtr pWin -) -{ - Atom atom; - PropertyPtr prop; - int rc; - - atom = xa_apple_no_order_in(); - rc = dixLookupProperty(&prop, pWin, atom, serverClient, DixReadAccess); - - if(Success == rc && prop->type == atom) - return 0; - - return 1; -} - - -static int -ProcAppleWMQueryVersion( - register ClientPtr client -) -{ - xAppleWMQueryVersionReply rep; - register int n; - - REQUEST_SIZE_MATCH(xAppleWMQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_APPLEWM_MAJOR_VERSION; - rep.minorVersion = SERVER_APPLEWM_MINOR_VERSION; - rep.patchVersion = SERVER_APPLEWM_PATCH_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - } - WriteToClient(client, sizeof(xAppleWMQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - - -/* events */ - -static inline void -updateEventMask (WMEventPtr *pHead) -{ - WMEventPtr pCur; - - eventMask = 0; - for (pCur = *pHead; pCur != NULL; pCur = pCur->next) - eventMask |= pCur->mask; -} - -/*ARGSUSED*/ -static int -WMFreeClient (pointer data, XID id) { - WMEventPtr pEvent; - WMEventPtr *pHead, pCur, pPrev; - int i; - - pEvent = (WMEventPtr) data; - i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, serverClient, DixReadAccess | DixWriteAccess | DixDestroyAccess); - if (i == Success && pHead) { - pPrev = 0; - for (pCur = *pHead; pCur && pCur != pEvent; pCur=pCur->next) - pPrev = pCur; - if (pCur) { - if (pPrev) - pPrev->next = pEvent->next; - else - *pHead = pEvent->next; - } - updateEventMask (pHead); - } - xfree ((pointer) pEvent); - return 1; -} - -/*ARGSUSED*/ -static int -WMFreeEvents (pointer data, XID id) { - WMEventPtr *pHead, pCur, pNext; - - pHead = (WMEventPtr *) data; - for (pCur = *pHead; pCur; pCur = pNext) { - pNext = pCur->next; - FreeResource (pCur->clientResource, ClientType); - xfree ((pointer) pCur); - } - xfree ((pointer) pHead); - eventMask = 0; - return 1; -} - -static int -ProcAppleWMSelectInput (register ClientPtr client) -{ - REQUEST(xAppleWMSelectInputReq); - WMEventPtr pEvent, pNewEvent, *pHead; - XID clientResource; - int i; - - REQUEST_SIZE_MATCH (xAppleWMSelectInputReq); - i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, client, DixWriteAccess); - if (stuff->mask != 0) { - if (i == Success && pHead) { - /* check for existing entry. */ - for (pEvent = *pHead; pEvent; pEvent = pEvent->next) - { - if (pEvent->client == client) - { - pEvent->mask = stuff->mask; - updateEventMask (pHead); - return Success; - } - } - } - - /* build the entry */ - pNewEvent = (WMEventPtr) xalloc (sizeof (WMEventRec)); - if (!pNewEvent) - return BadAlloc; - pNewEvent->next = 0; - pNewEvent->client = client; - pNewEvent->mask = stuff->mask; - /* - * add a resource that will be deleted when - * the client goes away - */ - clientResource = FakeClientID (client->index); - pNewEvent->clientResource = clientResource; - if (!AddResource (clientResource, ClientType, (pointer)pNewEvent)) - 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 (i != Success || !pHead) - { - pHead = (WMEventPtr *) xalloc (sizeof (WMEventPtr)); - if (!pHead || - !AddResource (eventResource, EventType, (pointer)pHead)) - { - FreeResource (clientResource, RT_NONE); - return BadAlloc; - } - *pHead = 0; - } - pNewEvent->next = *pHead; - *pHead = pNewEvent; - updateEventMask (pHead); - } else if (stuff->mask == 0) { - /* delete the interest */ - if (i == Success && pHead) { - pNewEvent = 0; - for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { - if (pEvent->client == client) - break; - pNewEvent = pEvent; - } - if (pEvent) { - FreeResource (pEvent->clientResource, ClientType); - if (pNewEvent) - pNewEvent->next = pEvent->next; - else - *pHead = pEvent->next; - xfree (pEvent); - updateEventMask (pHead); - } - } - } else { - client->errorValue = stuff->mask; - return BadValue; - } - return Success; -} - -/* - * deliver the event - */ - -void -AppleWMSendEvent (int type, unsigned int mask, int which, int arg) { - WMEventPtr *pHead, pEvent; - ClientPtr client; - xAppleWMNotifyEvent se; - int i; - - i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, serverClient, DixReadAccess); - if (i != Success || !pHead) - return; - for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { - client = pEvent->client; - if ((pEvent->mask & mask) == 0 - || client == serverClient || client->clientGone) - { - continue; - } - se.type = type + WMEventBase; - se.kind = which; - se.arg = arg; - se.sequenceNumber = client->sequence; - se.time = currentTime.milliseconds; - WriteEventsToClient (client, 1, (xEvent *) &se); - } -} - -/* Safe to call from any thread. */ -unsigned int -AppleWMSelectedEvents (void) -{ - return eventMask; -} - - -/* general utility functions */ - -static int -ProcAppleWMDisableUpdate( - register ClientPtr client -) -{ - REQUEST_SIZE_MATCH(xAppleWMDisableUpdateReq); - - appleWMProcs->DisableUpdate(); - - return (client->noClientException); -} - -static int -ProcAppleWMReenableUpdate( - register ClientPtr client -) -{ - REQUEST_SIZE_MATCH(xAppleWMReenableUpdateReq); - - appleWMProcs->EnableUpdate(); - - return (client->noClientException); -} - - -/* window functions */ - -static int -ProcAppleWMSetWindowMenu( - register ClientPtr client -) -{ - const char *bytes, **items; - char *shortcuts; - int max_len, nitems, i, j; - REQUEST(xAppleWMSetWindowMenuReq); - - REQUEST_AT_LEAST_SIZE(xAppleWMSetWindowMenuReq); - - nitems = stuff->nitems; - items = xalloc (sizeof (char *) * nitems); - shortcuts = xalloc (sizeof (char) * nitems); - - max_len = (stuff->length << 2) - sizeof(xAppleWMSetWindowMenuReq); - bytes = (char *) &stuff[1]; - - for (i = j = 0; i < max_len && j < nitems;) - { - shortcuts[j] = bytes[i++]; - items[j++] = bytes + i; - - while (i < max_len) - { - if (bytes[i++] == 0) - break; - } - } - X11ApplicationSetWindowMenu (nitems, items, shortcuts); - free(items); - free(shortcuts); - - return (client->noClientException); -} - -static int -ProcAppleWMSetWindowMenuCheck( - register ClientPtr client -) -{ - REQUEST(xAppleWMSetWindowMenuCheckReq); - - REQUEST_SIZE_MATCH(xAppleWMSetWindowMenuCheckReq); - X11ApplicationSetWindowMenuCheck(stuff->index); - return (client->noClientException); -} - -static int -ProcAppleWMSetFrontProcess( - register ClientPtr client -) -{ - REQUEST_SIZE_MATCH(xAppleWMSetFrontProcessReq); - - X11ApplicationSetFrontProcess(); - return (client->noClientException); -} - -static int -ProcAppleWMSetWindowLevel(register ClientPtr client) -{ - REQUEST(xAppleWMSetWindowLevelReq); - WindowPtr pWin; - int err; - - REQUEST_SIZE_MATCH(xAppleWMSetWindowLevelReq); - - if (Success != dixLookupWindow(&pWin, stuff->window, client, - DixReadAccess)) - return BadValue; - - if (stuff->level < 0 || stuff->level >= AppleWMNumWindowLevels) { - return BadValue; - } - - err = appleWMProcs->SetWindowLevel(pWin, stuff->level); - if (err != Success) { - return err; - } - - return (client->noClientException); -} - -static int -ProcAppleWMSendPSN(register ClientPtr client) -{ - REQUEST(xAppleWMSendPSNReq); - int err; - - REQUEST_SIZE_MATCH(xAppleWMSendPSNReq); - - if(!appleWMProcs->SendPSN) - return BadRequest; - - err = appleWMProcs->SendPSN(stuff->psn_hi, stuff->psn_lo); - if (err != Success) { - return err; - } - - return (client->noClientException); -} - -static int -ProcAppleWMAttachTransient(register ClientPtr client) -{ - WindowPtr pWinChild, pWinParent; - REQUEST(xAppleWMAttachTransientReq); - int err; - - REQUEST_SIZE_MATCH(xAppleWMAttachTransientReq); - - if(!appleWMProcs->AttachTransient) - return BadRequest; - - if (Success != dixLookupWindow(&pWinChild, stuff->child, client, DixReadAccess)) - return BadValue; - - if(stuff->parent) { - if(Success != dixLookupWindow(&pWinParent, stuff->parent, client, DixReadAccess)) - return BadValue; - } else { - pWinParent = NULL; - } - - err = appleWMProcs->AttachTransient(pWinChild, pWinParent); - if (err != Success) { - return err; - } - - return (client->noClientException); -} - -static int -ProcAppleWMSetCanQuit( - register ClientPtr client -) -{ - REQUEST(xAppleWMSetCanQuitReq); - - REQUEST_SIZE_MATCH(xAppleWMSetCanQuitReq); - - X11ApplicationSetCanQuit(stuff->state); - return (client->noClientException); -} - - -/* frame functions */ - -static int -ProcAppleWMFrameGetRect( - register ClientPtr client -) -{ - xAppleWMFrameGetRectReply rep; - BoxRec ir, or, rr; - REQUEST(xAppleWMFrameGetRectReq); - - REQUEST_SIZE_MATCH(xAppleWMFrameGetRectReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); - or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); - - if (appleWMProcs->FrameGetRect(stuff->frame_rect, - stuff->frame_class, - &or, &ir, &rr) != Success) - { - return BadValue; - } - - rep.x = rr.x1; - rep.y = rr.y1; - rep.w = rr.x2 - rr.x1; - rep.h = rr.y2 - rr.y1; - - WriteToClient(client, sizeof(xAppleWMFrameGetRectReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcAppleWMFrameHitTest( - register ClientPtr client -) -{ - xAppleWMFrameHitTestReply rep; - BoxRec ir, or; - int ret; - REQUEST(xAppleWMFrameHitTestReq); - - REQUEST_SIZE_MATCH(xAppleWMFrameHitTestReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); - or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); - - if (appleWMProcs->FrameHitTest(stuff->frame_class, stuff->px, - stuff->py, &or, &ir, &ret) != Success) - { - return BadValue; - } - - rep.ret = ret; - - WriteToClient(client, sizeof(xAppleWMFrameHitTestReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcAppleWMFrameDraw( - register ClientPtr client -) -{ - BoxRec ir, or; - unsigned int title_length, title_max; - unsigned char *title_bytes; - REQUEST(xAppleWMFrameDrawReq); - WindowPtr pWin; - - REQUEST_AT_LEAST_SIZE(xAppleWMFrameDrawReq); - - if (Success != dixLookupWindow(&pWin, stuff->window, client, - DixReadAccess)) - return BadValue; - - ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); - or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); - - title_length = stuff->title_length; - title_max = (stuff->length << 2) - sizeof(xAppleWMFrameDrawReq); - - if (title_max < title_length) - return BadValue; - - title_bytes = (unsigned char *) &stuff[1]; - - errno = appleWMProcs->FrameDraw(pWin, stuff->frame_class, - stuff->frame_attr, &or, &ir, - title_length, title_bytes); - if (errno != Success) { - return errno; - } - - return (client->noClientException); -} - - -/* dispatch */ - -static int -ProcAppleWMDispatch ( - register ClientPtr client -) -{ - REQUEST(xReq); - - switch (stuff->data) - { - case X_AppleWMQueryVersion: - return ProcAppleWMQueryVersion(client); - } - - if (!LocalClient(client)) - return WMErrorBase + AppleWMClientNotLocal; - - switch (stuff->data) - { - case X_AppleWMSelectInput: - return ProcAppleWMSelectInput(client); - case X_AppleWMDisableUpdate: - return ProcAppleWMDisableUpdate(client); - case X_AppleWMReenableUpdate: - return ProcAppleWMReenableUpdate(client); - case X_AppleWMSetWindowMenu: - return ProcAppleWMSetWindowMenu(client); - case X_AppleWMSetWindowMenuCheck: - return ProcAppleWMSetWindowMenuCheck(client); - case X_AppleWMSetFrontProcess: - return ProcAppleWMSetFrontProcess(client); - case X_AppleWMSetWindowLevel: - return ProcAppleWMSetWindowLevel(client); - case X_AppleWMSetCanQuit: - return ProcAppleWMSetCanQuit(client); - case X_AppleWMFrameGetRect: - return ProcAppleWMFrameGetRect(client); - case X_AppleWMFrameHitTest: - return ProcAppleWMFrameHitTest(client); - case X_AppleWMFrameDraw: - return ProcAppleWMFrameDraw(client); - case X_AppleWMSendPSN: - return ProcAppleWMSendPSN(client); - case X_AppleWMAttachTransient: - return ProcAppleWMAttachTransient(client); - default: - return BadRequest; - } -} - -static void -SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to) { - to->type = from->type; - to->kind = from->kind; - cpswaps (from->sequenceNumber, to->sequenceNumber); - cpswapl (from->time, to->time); - cpswapl (from->arg, to->arg); -} - -static int -SProcAppleWMQueryVersion( - register ClientPtr client -) -{ - register int n; - REQUEST(xAppleWMQueryVersionReq); - swaps(&stuff->length, n); - return ProcAppleWMQueryVersion(client); -} - -static int -SProcAppleWMDispatch ( - register ClientPtr client -) -{ - REQUEST(xReq); - - /* It is bound to be non-local when there is byte swapping */ - if (!LocalClient(client)) - return WMErrorBase + AppleWMClientNotLocal; - - /* only local clients are allowed WM access */ - switch (stuff->data) - { - case X_AppleWMQueryVersion: - return SProcAppleWMQueryVersion(client); - default: - return BadRequest; - } -} +/************************************************************************** + +Copyright (c) 2002-2007 Apple Inc. All Rights Reserved. +Copyright (c) 2003 Torrey T. Lyons. 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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +#include "sanitizedCarbon.h" + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "quartzCommon.h" + +#include "misc.h" +#include "dixstruct.h" +#include "globals.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "servermd.h" +#include "swaprep.h" +#include "propertyst.h" +#include <X11/Xatom.h> +#include "darwin.h" +#define _APPLEWM_SERVER_ +#include <X11/extensions/applewmproto.h> +#include "applewmExt.h" +#include "X11Application.h" +#include "protocol-versions.h" + +#define DEFINE_ATOM_HELPER(func,atom_name) \ +static Atom func (void) { \ + static int generation; \ + static Atom atom; \ + if (generation != serverGeneration) { \ + generation = serverGeneration; \ + atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ + } \ + return atom; \ +} + +DEFINE_ATOM_HELPER(xa_native_screen_origin, "_NATIVE_SCREEN_ORIGIN") +DEFINE_ATOM_HELPER (xa_apple_no_order_in, "_APPLE_NO_ORDER_IN") + +static AppleWMProcsPtr appleWMProcs; + +static int WMErrorBase; + +static DISPATCH_PROC(ProcAppleWMDispatch); +static DISPATCH_PROC(SProcAppleWMDispatch); + +static unsigned char WMReqCode = 0; +static int WMEventBase = 0; + +static RESTYPE ClientType, EventType; /* resource types for event masks */ +static XID eventResource; + +/* Currently selected events */ +static unsigned int eventMask = 0; + +static int WMFreeClient (pointer data, XID id); +static int WMFreeEvents (pointer data, XID id); +static void SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to); + +typedef struct _WMEvent *WMEventPtr; +typedef struct _WMEvent { + WMEventPtr next; + ClientPtr client; + XID clientResource; + unsigned int mask; +} WMEventRec; + +static inline BoxRec +make_box (int x, int y, int w, int h) +{ + BoxRec r; + r.x1 = x; + r.y1 = y; + r.x2 = x + w; + r.y2 = y + h; + return r; +} + +void +AppleWMExtensionInit( + AppleWMProcsPtr procsPtr) +{ + ExtensionEntry* extEntry; + + ClientType = CreateNewResourceType(WMFreeClient, "WMClient"); + EventType = CreateNewResourceType(WMFreeEvents, "WMEvent"); + eventResource = FakeClientID(0); + + if (ClientType && EventType && + (extEntry = AddExtension(APPLEWMNAME, + AppleWMNumberEvents, + AppleWMNumberErrors, + ProcAppleWMDispatch, + SProcAppleWMDispatch, + NULL, + StandardMinorOpcode))) + { + WMReqCode = (unsigned char)extEntry->base; + WMErrorBase = extEntry->errorBase; + WMEventBase = extEntry->eventBase; + EventSwapVector[WMEventBase] = (EventSwapPtr) SNotifyEvent; + appleWMProcs = procsPtr; + } +} + +/* Updates the _NATIVE_SCREEN_ORIGIN property on the given root window. */ +void +AppleWMSetScreenOrigin( + WindowPtr pWin +) +{ + int32_t data[2]; + + data[0] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].x + + darwinMainScreenX); + data[1] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].y + + darwinMainScreenY); + + dixChangeWindowProperty(serverClient, pWin, xa_native_screen_origin(), + XA_INTEGER, 32, PropModeReplace, 2, data, TRUE); +} + +/* Window managers can set the _APPLE_NO_ORDER_IN property on windows + that are being genie-restored from the Dock. We want them to + be mapped but remain ordered-out until the animation + completes (when the Dock will order them in). */ +Bool +AppleWMDoReorderWindow( + WindowPtr pWin +) +{ + Atom atom; + PropertyPtr prop; + int rc; + + atom = xa_apple_no_order_in(); + rc = dixLookupProperty(&prop, pWin, atom, serverClient, DixReadAccess); + + if(Success == rc && prop->type == atom) + return 0; + + return 1; +} + + +static int +ProcAppleWMQueryVersion( + register ClientPtr client +) +{ + xAppleWMQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH(xAppleWMQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_APPLEWM_MAJOR_VERSION; + rep.minorVersion = SERVER_APPLEWM_MINOR_VERSION; + rep.patchVersion = SERVER_APPLEWM_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + WriteToClient(client, sizeof(xAppleWMQueryVersionReply), (char *)&rep); + return Success; +} + + +/* events */ + +static inline void +updateEventMask (WMEventPtr *pHead) +{ + WMEventPtr pCur; + + eventMask = 0; + for (pCur = *pHead; pCur != NULL; pCur = pCur->next) + eventMask |= pCur->mask; +} + +/*ARGSUSED*/ +static int +WMFreeClient (pointer data, XID id) { + WMEventPtr pEvent; + WMEventPtr *pHead, pCur, pPrev; + int i; + + pEvent = (WMEventPtr) data; + i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, serverClient, DixReadAccess | DixWriteAccess | DixDestroyAccess); + if (i == Success && pHead) { + pPrev = 0; + for (pCur = *pHead; pCur && pCur != pEvent; pCur=pCur->next) + pPrev = pCur; + if (pCur) { + if (pPrev) + pPrev->next = pEvent->next; + else + *pHead = pEvent->next; + } + updateEventMask (pHead); + } + free((pointer) pEvent); + return 1; +} + +/*ARGSUSED*/ +static int +WMFreeEvents (pointer data, XID id) { + WMEventPtr *pHead, pCur, pNext; + + pHead = (WMEventPtr *) data; + for (pCur = *pHead; pCur; pCur = pNext) { + pNext = pCur->next; + FreeResource (pCur->clientResource, ClientType); + free((pointer) pCur); + } + free((pointer) pHead); + eventMask = 0; + return 1; +} + +static int +ProcAppleWMSelectInput (register ClientPtr client) +{ + REQUEST(xAppleWMSelectInputReq); + WMEventPtr pEvent, pNewEvent, *pHead; + XID clientResource; + int i; + + REQUEST_SIZE_MATCH (xAppleWMSelectInputReq); + i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, client, DixWriteAccess); + if (stuff->mask != 0) { + if (i == Success && pHead) { + /* check for existing entry. */ + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) + { + if (pEvent->client == client) + { + pEvent->mask = stuff->mask; + updateEventMask (pHead); + return Success; + } + } + } + + /* build the entry */ + pNewEvent = (WMEventPtr) malloc(sizeof (WMEventRec)); + if (!pNewEvent) + return BadAlloc; + pNewEvent->next = 0; + pNewEvent->client = client; + pNewEvent->mask = stuff->mask; + /* + * add a resource that will be deleted when + * the client goes away + */ + clientResource = FakeClientID (client->index); + pNewEvent->clientResource = clientResource; + if (!AddResource (clientResource, ClientType, (pointer)pNewEvent)) + 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 (i != Success || !pHead) + { + pHead = (WMEventPtr *) malloc(sizeof (WMEventPtr)); + if (!pHead || + !AddResource (eventResource, EventType, (pointer)pHead)) + { + FreeResource (clientResource, RT_NONE); + return BadAlloc; + } + *pHead = 0; + } + pNewEvent->next = *pHead; + *pHead = pNewEvent; + updateEventMask (pHead); + } else if (stuff->mask == 0) { + /* delete the interest */ + if (i == Success && pHead) { + pNewEvent = 0; + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + if (pEvent->client == client) + break; + pNewEvent = pEvent; + } + if (pEvent) { + FreeResource (pEvent->clientResource, ClientType); + if (pNewEvent) + pNewEvent->next = pEvent->next; + else + *pHead = pEvent->next; + free(pEvent); + updateEventMask (pHead); + } + } + } else { + client->errorValue = stuff->mask; + return BadValue; + } + return Success; +} + +/* + * deliver the event + */ + +void +AppleWMSendEvent (int type, unsigned int mask, int which, int arg) { + WMEventPtr *pHead, pEvent; + ClientPtr client; + xAppleWMNotifyEvent se; + int i; + + i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, serverClient, DixReadAccess); + if (i != Success || !pHead) + return; + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + client = pEvent->client; + if ((pEvent->mask & mask) == 0 + || client == serverClient || client->clientGone) + { + continue; + } + se.type = type + WMEventBase; + se.kind = which; + se.arg = arg; + se.sequenceNumber = client->sequence; + se.time = currentTime.milliseconds; + WriteEventsToClient (client, 1, (xEvent *) &se); + } +} + +/* Safe to call from any thread. */ +unsigned int +AppleWMSelectedEvents (void) +{ + return eventMask; +} + + +/* general utility functions */ + +static int +ProcAppleWMDisableUpdate( + register ClientPtr client +) +{ + REQUEST_SIZE_MATCH(xAppleWMDisableUpdateReq); + + appleWMProcs->DisableUpdate(); + + return Success; +} + +static int +ProcAppleWMReenableUpdate( + register ClientPtr client +) +{ + REQUEST_SIZE_MATCH(xAppleWMReenableUpdateReq); + + appleWMProcs->EnableUpdate(); + + return Success; +} + + +/* window functions */ + +static int +ProcAppleWMSetWindowMenu( + register ClientPtr client +) +{ + const char *bytes, **items; + char *shortcuts; + int max_len, nitems, i, j; + REQUEST(xAppleWMSetWindowMenuReq); + + REQUEST_AT_LEAST_SIZE(xAppleWMSetWindowMenuReq); + + nitems = stuff->nitems; + items = malloc(sizeof (char *) * nitems); + shortcuts = malloc(sizeof (char) * nitems); + + max_len = (stuff->length << 2) - sizeof(xAppleWMSetWindowMenuReq); + bytes = (char *) &stuff[1]; + + for (i = j = 0; i < max_len && j < nitems;) + { + shortcuts[j] = bytes[i++]; + items[j++] = bytes + i; + + while (i < max_len) + { + if (bytes[i++] == 0) + break; + } + } + X11ApplicationSetWindowMenu (nitems, items, shortcuts); + free(items); + free(shortcuts); + + return Success; +} + +static int +ProcAppleWMSetWindowMenuCheck( + register ClientPtr client +) +{ + REQUEST(xAppleWMSetWindowMenuCheckReq); + + REQUEST_SIZE_MATCH(xAppleWMSetWindowMenuCheckReq); + X11ApplicationSetWindowMenuCheck(stuff->index); + return Success; +} + +static int +ProcAppleWMSetFrontProcess( + register ClientPtr client +) +{ + REQUEST_SIZE_MATCH(xAppleWMSetFrontProcessReq); + + X11ApplicationSetFrontProcess(); + return Success; +} + +static int +ProcAppleWMSetWindowLevel(register ClientPtr client) +{ + REQUEST(xAppleWMSetWindowLevelReq); + WindowPtr pWin; + int err; + + REQUEST_SIZE_MATCH(xAppleWMSetWindowLevelReq); + + if (Success != dixLookupWindow(&pWin, stuff->window, client, + DixReadAccess)) + return BadValue; + + if (stuff->level < 0 || stuff->level >= AppleWMNumWindowLevels) { + return BadValue; + } + + err = appleWMProcs->SetWindowLevel(pWin, stuff->level); + if (err != Success) { + return err; + } + + return Success; +} + +static int +ProcAppleWMSendPSN(register ClientPtr client) +{ + REQUEST(xAppleWMSendPSNReq); + int err; + + REQUEST_SIZE_MATCH(xAppleWMSendPSNReq); + + if(!appleWMProcs->SendPSN) + return BadRequest; + + err = appleWMProcs->SendPSN(stuff->psn_hi, stuff->psn_lo); + if (err != Success) { + return err; + } + + return Success; +} + +static int +ProcAppleWMAttachTransient(register ClientPtr client) +{ + WindowPtr pWinChild, pWinParent; + REQUEST(xAppleWMAttachTransientReq); + int err; + + REQUEST_SIZE_MATCH(xAppleWMAttachTransientReq); + + if(!appleWMProcs->AttachTransient) + return BadRequest; + + if (Success != dixLookupWindow(&pWinChild, stuff->child, client, DixReadAccess)) + return BadValue; + + if(stuff->parent) { + if(Success != dixLookupWindow(&pWinParent, stuff->parent, client, DixReadAccess)) + return BadValue; + } else { + pWinParent = NULL; + } + + err = appleWMProcs->AttachTransient(pWinChild, pWinParent); + if (err != Success) { + return err; + } + + return Success; +} + +static int +ProcAppleWMSetCanQuit( + register ClientPtr client +) +{ + REQUEST(xAppleWMSetCanQuitReq); + + REQUEST_SIZE_MATCH(xAppleWMSetCanQuitReq); + + X11ApplicationSetCanQuit(stuff->state); + return Success; +} + + +/* frame functions */ + +static int +ProcAppleWMFrameGetRect( + register ClientPtr client +) +{ + xAppleWMFrameGetRectReply rep; + BoxRec ir, or, rr; + REQUEST(xAppleWMFrameGetRectReq); + + REQUEST_SIZE_MATCH(xAppleWMFrameGetRectReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); + or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); + + if (appleWMProcs->FrameGetRect(stuff->frame_rect, + stuff->frame_class, + &or, &ir, &rr) != Success) + { + return BadValue; + } + + rep.x = rr.x1; + rep.y = rr.y1; + rep.w = rr.x2 - rr.x1; + rep.h = rr.y2 - rr.y1; + + WriteToClient(client, sizeof(xAppleWMFrameGetRectReply), (char *)&rep); + return Success; +} + +static int +ProcAppleWMFrameHitTest( + register ClientPtr client +) +{ + xAppleWMFrameHitTestReply rep; + BoxRec ir, or; + int ret; + REQUEST(xAppleWMFrameHitTestReq); + + REQUEST_SIZE_MATCH(xAppleWMFrameHitTestReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); + or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); + + if (appleWMProcs->FrameHitTest(stuff->frame_class, stuff->px, + stuff->py, &or, &ir, &ret) != Success) + { + return BadValue; + } + + rep.ret = ret; + + WriteToClient(client, sizeof(xAppleWMFrameHitTestReply), (char *)&rep); + return Success; +} + +static int +ProcAppleWMFrameDraw( + register ClientPtr client +) +{ + BoxRec ir, or; + unsigned int title_length, title_max; + unsigned char *title_bytes; + REQUEST(xAppleWMFrameDrawReq); + WindowPtr pWin; + + REQUEST_AT_LEAST_SIZE(xAppleWMFrameDrawReq); + + if (Success != dixLookupWindow(&pWin, stuff->window, client, + DixReadAccess)) + return BadValue; + + ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); + or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); + + title_length = stuff->title_length; + title_max = (stuff->length << 2) - sizeof(xAppleWMFrameDrawReq); + + if (title_max < title_length) + return BadValue; + + title_bytes = (unsigned char *) &stuff[1]; + + errno = appleWMProcs->FrameDraw(pWin, stuff->frame_class, + stuff->frame_attr, &or, &ir, + title_length, title_bytes); + if (errno != Success) { + return errno; + } + + return Success; +} + + +/* dispatch */ + +static int +ProcAppleWMDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_AppleWMQueryVersion: + return ProcAppleWMQueryVersion(client); + } + + if (!LocalClient(client)) + return WMErrorBase + AppleWMClientNotLocal; + + switch (stuff->data) + { + case X_AppleWMSelectInput: + return ProcAppleWMSelectInput(client); + case X_AppleWMDisableUpdate: + return ProcAppleWMDisableUpdate(client); + case X_AppleWMReenableUpdate: + return ProcAppleWMReenableUpdate(client); + case X_AppleWMSetWindowMenu: + return ProcAppleWMSetWindowMenu(client); + case X_AppleWMSetWindowMenuCheck: + return ProcAppleWMSetWindowMenuCheck(client); + case X_AppleWMSetFrontProcess: + return ProcAppleWMSetFrontProcess(client); + case X_AppleWMSetWindowLevel: + return ProcAppleWMSetWindowLevel(client); + case X_AppleWMSetCanQuit: + return ProcAppleWMSetCanQuit(client); + case X_AppleWMFrameGetRect: + return ProcAppleWMFrameGetRect(client); + case X_AppleWMFrameHitTest: + return ProcAppleWMFrameHitTest(client); + case X_AppleWMFrameDraw: + return ProcAppleWMFrameDraw(client); + case X_AppleWMSendPSN: + return ProcAppleWMSendPSN(client); + case X_AppleWMAttachTransient: + return ProcAppleWMAttachTransient(client); + default: + return BadRequest; + } +} + +static void +SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to) { + to->type = from->type; + to->kind = from->kind; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->time, to->time); + cpswapl (from->arg, to->arg); +} + +static int +SProcAppleWMQueryVersion( + register ClientPtr client +) +{ + register int n; + REQUEST(xAppleWMQueryVersionReq); + swaps(&stuff->length, n); + return ProcAppleWMQueryVersion(client); +} + +static int +SProcAppleWMDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + /* It is bound to be non-local when there is byte swapping */ + if (!LocalClient(client)) + return WMErrorBase + AppleWMClientNotLocal; + + /* only local clients are allowed WM access */ + switch (stuff->data) + { + case X_AppleWMQueryVersion: + return SProcAppleWMQueryVersion(client); + default: + return BadRequest; + } +} diff --git a/xorg-server/hw/xquartz/darwin.c b/xorg-server/hw/xquartz/darwin.c index 1fb158b26..ed9543eb2 100644 --- a/xorg-server/hw/xquartz/darwin.c +++ b/xorg-server/hw/xquartz/darwin.c @@ -1,908 +1,908 @@ -/************************************************************** - * - * Xquartz initialization code - * - * Copyright (c) 2007-2008 Apple Inc. - * Copyright (c) 2001-2004 Torrey T. Lyons. 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright - * holders shall not be used in advertising or otherwise to promote the sale, - * use or other dealings in this Software without prior written authorization. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "os.h" -#include "servermd.h" -#include "inputstr.h" -#include "scrnintstr.h" -#include "mibstore.h" // mi backing store implementation -#include "mipointer.h" // mi software cursor -#include "micmap.h" // mi colormap code -#include "fb.h" // fb framebuffer code -#include "site.h" -#include "globals.h" -#include "dix.h" -#include "xkbsrv.h" - -#include <X11/extensions/XI.h> -#include <X11/extensions/XIproto.h> -#include "exevents.h" -#include "extinit.h" - -#include "xserver-properties.h" - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/syslimits.h> -#include <stdio.h> -#include <fcntl.h> -#include <unistd.h> - -#define HAS_UTSNAME 1 -#include <sys/utsname.h> - -#define NO_CFPLUGIN -#include <IOKit/hidsystem/IOHIDLib.h> - -#ifdef MITSHM -#include "shmint.h" -#endif - -#include "darwin.h" -#include "darwinEvents.h" -#include "quartzKeyboard.h" -#include "quartz.h" - -#ifdef ENABLE_DEBUG_LOG -FILE *debug_log_fp = NULL; -#endif - -/* - * X server shared global variables - */ -int darwinScreensFound = 0; -static int darwinScreenKeyIndex; -DevPrivateKey darwinScreenKey = &darwinScreenKeyIndex; -io_connect_t darwinParamConnect = 0; -int darwinEventReadFD = -1; -int darwinEventWriteFD = -1; -// int darwinMouseAccelChange = 1; -int darwinFakeButtons = 0; - -// location of X11's (0,0) point in global screen coordinates -int darwinMainScreenX = 0; -int darwinMainScreenY = 0; - -// parameters read from the command line or user preferences -int darwinDesiredDepth = -1; -int darwinSyncKeymap = FALSE; - -// modifier masks for faking mouse buttons - ANY of these bits trigger it (not all) -#ifdef NX_DEVICELCMDKEYMASK -int darwinFakeMouse2Mask = NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK; -int darwinFakeMouse3Mask = NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK; -#else -int darwinFakeMouse2Mask = NX_ALTERNATEMASK; -int darwinFakeMouse3Mask = NX_COMMANDMASK; -#endif - -// Modifier mask for overriding event delivery to appkit (might be useful to set this to rcommand for input menu -unsigned int darwinAppKitModMask = 0; // Any of these bits - -// Modifier mask for items in the Window menu (0 and -1 cause shortcuts to be disabled) -unsigned int windowItemModMask = NX_COMMANDMASK; - -// devices -DeviceIntPtr darwinKeyboard = NULL; -DeviceIntPtr darwinPointer = NULL; -DeviceIntPtr darwinTabletCurrent = NULL; -DeviceIntPtr darwinTabletStylus = NULL; -DeviceIntPtr darwinTabletCursor = NULL; -DeviceIntPtr darwinTabletEraser = NULL; - -// Common pixmap formats -static PixmapFormatRec formats[] = { - { 1, 1, BITMAP_SCANLINE_PAD }, - { 4, 8, BITMAP_SCANLINE_PAD }, - { 8, 8, BITMAP_SCANLINE_PAD }, - { 15, 16, BITMAP_SCANLINE_PAD }, - { 16, 16, BITMAP_SCANLINE_PAD }, - { 24, 32, BITMAP_SCANLINE_PAD }, - { 32, 32, BITMAP_SCANLINE_PAD } -}; -const int NUMFORMATS = sizeof(formats)/sizeof(formats[0]); - -#ifndef OSNAME -#define OSNAME " Darwin" -#endif -#ifndef OSVENDOR -#define OSVENDOR "" -#endif -#ifndef PRE_RELEASE -#define PRE_RELEASE XORG_VERSION_SNAP -#endif -#ifndef BUILD_DATE -#define BUILD_DATE "" -#endif -#ifndef XORG_RELEASE -#define XORG_RELEASE "?" -#endif - -void -DarwinPrintBanner(void) -{ - // this should change depending on which specific server we are building - ErrorF("Xquartz starting:\n"); - ErrorF("X.Org X Server %s\nBuild Date: %s\n", XSERVER_VERSION, BUILD_DATE ); -} - - -/* - * DarwinSaveScreen - * X screensaver support. Not implemented. - */ -static Bool DarwinSaveScreen(ScreenPtr pScreen, int on) -{ - // FIXME - if (on == SCREEN_SAVER_FORCER) { - } else if (on == SCREEN_SAVER_ON) { - } else { - } - return TRUE; -} - -/* - * DarwinScreenInit - * This is a callback from dix during AddScreen() from InitOutput(). - * Initialize the screen and communicate information about it back to dix. - */ -static Bool DarwinScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) { - int dpi; - static int foundIndex = 0; - Bool ret; - DarwinFramebufferPtr dfb; - - // reset index of found screens for each server generation - if (index == 0) { - foundIndex = 0; - - // reset the visual list - miClearVisualTypes(); - } - - // allocate space for private per screen storage - dfb = xalloc(sizeof(DarwinFramebufferRec)); - - // SCREEN_PRIV(pScreen) = dfb; - dixSetPrivate(&pScreen->devPrivates, darwinScreenKey, dfb); - - // setup hardware/mode specific details - ret = QuartzAddScreen(foundIndex, pScreen); - foundIndex++; - if (! ret) - return FALSE; - - // setup a single visual appropriate for our pixel type - if(!miSetVisualTypesAndMasks(dfb->depth, dfb->visuals, dfb->bitsPerRGB, - dfb->preferredCVC, dfb->redMask, - dfb->greenMask, dfb->blueMask)) { - return FALSE; - } - -// TODO: Make PseudoColor visuals not suck in TrueColor mode -// if(dfb->depth > 8) -// miSetVisualTypesAndMasks(8, PseudoColorMask, 8, PseudoColor, 0, 0, 0); - if(dfb->depth > 15) - miSetVisualTypesAndMasks(15, TrueColorMask, 5, TrueColor, RM_ARGB(0,5,5,5), GM_ARGB(0,5,5,5), BM_ARGB(0,5,5,5)); - if(dfb->depth > 24) - miSetVisualTypesAndMasks(24, TrueColorMask, 8, TrueColor, RM_ARGB(0,8,8,8), GM_ARGB(0,8,8,8), BM_ARGB(0,8,8,8)); - - miSetPixmapDepths(); - - // machine independent screen init - // setup _Screen structure in pScreen - if (monitorResolution) - dpi = monitorResolution; - else - dpi = 96; - - // initialize fb - if (! fbScreenInit(pScreen, - dfb->framebuffer, // pointer to screen bitmap - dfb->width, dfb->height, // screen size in pixels - dpi, dpi, // dots per inch - dfb->pitch/(dfb->bitsPerPixel/8), // pixel width of framebuffer - dfb->bitsPerPixel)) // bits per pixel for screen - { - return FALSE; - } - - if (! fbPictureInit(pScreen, 0, 0)) { - return FALSE; - } - -#ifdef MITSHM - ShmRegisterFbFuncs(pScreen); -#endif - - // this must be initialized (why doesn't X have a default?) - pScreen->SaveScreen = DarwinSaveScreen; - - // finish mode dependent screen setup including cursor support - if (!QuartzSetupScreen(index, pScreen)) { - return FALSE; - } - - // create and install the default colormap and - // set pScreen->blackPixel / pScreen->white - if (!miCreateDefColormap( pScreen )) { - return FALSE; - } - - dixScreenOrigins[index].x = dfb->x; - dixScreenOrigins[index].y = dfb->y; - - /* ErrorF("Screen %d added: %dx%d @ (%d,%d)\n", - index, dfb->width, dfb->height, dfb->x, dfb->y); */ - - return TRUE; -} - -/* - ============================================================================= - - mouse and keyboard callbacks - - ============================================================================= -*/ - -/* - * DarwinMouseProc: Handle the initialization, etc. of a mouse - */ -static int DarwinMouseProc(DeviceIntPtr pPointer, int what) { -#define NBUTTONS 7 -#define NAXES 2 - // 7 buttons: left, right, middle, then four scroll wheel "buttons" - CARD8 map[NBUTTONS + 1] = {0, 1, 2, 3, 4, 5, 6, 7}; - Atom btn_labels[NBUTTONS] = {0}; - Atom axes_labels[NAXES] = {0}; - - switch (what) { - case DEVICE_INIT: - pPointer->public.on = FALSE; - - btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); - btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); - btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); - btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); - btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); - btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); - btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); - - axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); - axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); - - - // Set button map. - InitPointerDeviceStruct((DevicePtr)pPointer, map, NBUTTONS, - btn_labels, - (PtrCtrlProcPtr)NoopDDA, - GetMotionHistorySize(), NAXES, - axes_labels); - pPointer->valuator->mode = Absolute; // Relative - InitAbsoluteClassDeviceStruct(pPointer); -// InitValuatorAxisStruct(pPointer, 0, 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); -// InitValuatorAxisStruct(pPointer, 1, 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); - break; - case DEVICE_ON: - pPointer->public.on = TRUE; - AddEnabledDevice( darwinEventReadFD ); - return Success; - case DEVICE_CLOSE: - case DEVICE_OFF: - pPointer->public.on = FALSE; - RemoveEnabledDevice(darwinEventReadFD); - return Success; - } - - return Success; -#undef NBUTTONS -#undef NAXES -} - -static int DarwinTabletProc(DeviceIntPtr pPointer, int what) { -#define NBUTTONS 3 -#define NAXES 5 - CARD8 map[NBUTTONS + 1] = {0, 1, 2, 3}; - Atom btn_labels[NBUTTONS] = {0}; - Atom axes_labels[NAXES] = {0}; - - switch (what) { - case DEVICE_INIT: - pPointer->public.on = FALSE; - - btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); - btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); - btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); - - axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X); - axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y); - axes_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_PRESSURE); - axes_labels[3] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_X); - axes_labels[4] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_Y); - - // Set button map. - InitPointerDeviceStruct((DevicePtr)pPointer, map, NBUTTONS, - btn_labels, - (PtrCtrlProcPtr)NoopDDA, - GetMotionHistorySize(), NAXES, - axes_labels); - pPointer->valuator->mode = Absolute; // Relative - InitProximityClassDeviceStruct(pPointer); - InitAbsoluteClassDeviceStruct(pPointer); - - InitValuatorAxisStruct(pPointer, 0, axes_labels[0], 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); - InitValuatorAxisStruct(pPointer, 1, axes_labels[1], 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); - InitValuatorAxisStruct(pPointer, 2, axes_labels[2], 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); - InitValuatorAxisStruct(pPointer, 3, axes_labels[3], -XQUARTZ_VALUATOR_LIMIT, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); - InitValuatorAxisStruct(pPointer, 4, axes_labels[4], -XQUARTZ_VALUATOR_LIMIT, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); -// pPointer->use = IsXExtensionDevice; - break; - case DEVICE_ON: - pPointer->public.on = TRUE; - AddEnabledDevice( darwinEventReadFD ); - return Success; - case DEVICE_CLOSE: - case DEVICE_OFF: - pPointer->public.on = FALSE; - RemoveEnabledDevice(darwinEventReadFD); - return Success; - } - return Success; -#undef NBUTTONS -#undef NAXES -} - -/* - * DarwinKeybdProc - * Callback from X - */ -static int DarwinKeybdProc( DeviceIntPtr pDev, int onoff ) -{ - switch ( onoff ) { - case DEVICE_INIT: - DarwinKeyboardInit( pDev ); - break; - case DEVICE_ON: - pDev->public.on = TRUE; - AddEnabledDevice( darwinEventReadFD ); - break; - case DEVICE_OFF: - pDev->public.on = FALSE; - RemoveEnabledDevice( darwinEventReadFD ); - break; - case DEVICE_CLOSE: - break; - } - - return Success; -} - -/* -=========================================================================== - - Utility routines - -=========================================================================== -*/ - -/* - * DarwinParseModifierList - * Parse a list of modifier names and return a corresponding modifier mask - */ -int DarwinParseModifierList(const char *constmodifiers, int separatelr) -{ - int result = 0; - - if (constmodifiers) { - char *modifiers = strdup(constmodifiers); - char *modifier; - int nxkey; - char *p = modifiers; - - while (p) { - modifier = strsep(&p, " ,+&|/"); // allow lots of separators - nxkey = DarwinModifierStringToNXMask(modifier, separatelr); - if(nxkey) - result |= nxkey; - else - ErrorF("fakebuttons: Unknown modifier \"%s\"\n", modifier); - } - free(modifiers); - } - return result; -} - -/* -=========================================================================== - - Functions needed to link against device independent X - -=========================================================================== -*/ - -/* - * InitInput - * Register the keyboard and mouse devices - */ -void InitInput( int argc, char **argv ) -{ - XkbRMLVOSet rmlvo = { .rules = "base", .model = "empty", .layout = "empty", - .variant = NULL, .options = NULL }; - /* We need to really have rules... or something... */ - XkbSetRulesDflts(&rmlvo); - - darwinKeyboard = AddInputDevice(serverClient, DarwinKeybdProc, TRUE); - RegisterKeyboardDevice( darwinKeyboard ); - darwinKeyboard->name = strdup("keyboard"); - - /* here's the snippet from the current gdk sources: - if (!strcmp (tmp_name, "pointer")) - gdkdev->info.source = GDK_SOURCE_MOUSE; - else if (!strcmp (tmp_name, "wacom") || - !strcmp (tmp_name, "pen")) - gdkdev->info.source = GDK_SOURCE_PEN; - else if (!strcmp (tmp_name, "eraser")) - gdkdev->info.source = GDK_SOURCE_ERASER; - else if (!strcmp (tmp_name, "cursor")) - gdkdev->info.source = GDK_SOURCE_CURSOR; - else - gdkdev->info.source = GDK_SOURCE_PEN; - */ - - darwinPointer = AddInputDevice(serverClient, DarwinMouseProc, TRUE); - RegisterPointerDevice( darwinPointer ); - darwinPointer->name = strdup("pointer"); - - darwinTabletStylus = AddInputDevice(serverClient, DarwinTabletProc, TRUE); - RegisterPointerDevice( darwinTabletStylus ); - darwinTabletStylus->name = strdup("pen"); - - darwinTabletCursor = AddInputDevice(serverClient, DarwinTabletProc, TRUE); - RegisterPointerDevice( darwinTabletCursor ); - darwinTabletCursor->name = strdup("cursor"); - - darwinTabletEraser = AddInputDevice(serverClient, DarwinTabletProc, TRUE); - RegisterPointerDevice( darwinTabletEraser ); - darwinTabletEraser->name = strdup("eraser"); - - darwinTabletCurrent = darwinTabletStylus; - - DarwinEQInit(); - - QuartzInitInput(argc, argv); -} - - -/* - * DarwinAdjustScreenOrigins - * Shift all screens so the X11 (0, 0) coordinate is at the top - * left of the global screen coordinates. - * - * Screens can be arranged so the top left isn't on any screen, so - * instead use the top left of the leftmost screen as (0,0). This - * may mean some screen space is in -y, but it's better that (0,0) - * be onscreen, or else default xterms disappear. It's better that - * -y be used than -x, because when popup menus are forced - * "onscreen" by dumb window managers like twm, they'll shift the - * menus down instead of left, which still looks funny but is an - * easier target to hit. - */ -void -DarwinAdjustScreenOrigins(ScreenInfo *pScreenInfo) -{ - int i, left, top; - - left = dixScreenOrigins[0].x; - top = dixScreenOrigins[0].y; - - /* Find leftmost screen. If there's a tie, take the topmost of the two. */ - for (i = 1; i < pScreenInfo->numScreens; i++) { - if (dixScreenOrigins[i].x < left || - (dixScreenOrigins[i].x == left && dixScreenOrigins[i].y < top)) - { - left = dixScreenOrigins[i].x; - top = dixScreenOrigins[i].y; - } - } - - darwinMainScreenX = left; - darwinMainScreenY = top; - - DEBUG_LOG("top = %d, left=%d\n", top, left); - - /* Shift all screens so that there is a screen whose top left - * is at X11 (0,0) and at global screen coordinate - * (darwinMainScreenX, darwinMainScreenY). - */ - - if (darwinMainScreenX != 0 || darwinMainScreenY != 0) { - for (i = 0; i < pScreenInfo->numScreens; i++) { - dixScreenOrigins[i].x -= darwinMainScreenX; - dixScreenOrigins[i].y -= darwinMainScreenY; - DEBUG_LOG("Screen %d placed at X11 coordinate (%d,%d).\n", - i, dixScreenOrigins[i].x, dixScreenOrigins[i].y); - } - } -} - - -/* - * InitOutput - * Initialize screenInfo for all actually accessible framebuffers. - * - * The display mode dependent code gets called three times. The mode - * specific InitOutput routines are expected to discover the number - * of potentially useful screens and cache routes to them internally. - * Inside DarwinScreenInit are two other mode specific calls. - * A mode specific AddScreen routine is called for each screen to - * actually initialize the screen with the ScreenPtr structure. - * After other screen setup has been done, a mode specific - * SetupScreen function can be called to finalize screen setup. - */ -void InitOutput( ScreenInfo *pScreenInfo, int argc, char **argv ) -{ - int i; - - pScreenInfo->imageByteOrder = IMAGE_BYTE_ORDER; - pScreenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; - pScreenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; - pScreenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; - - // List how we want common pixmap formats to be padded - pScreenInfo->numPixmapFormats = NUMFORMATS; - for (i = 0; i < NUMFORMATS; i++) - pScreenInfo->formats[i] = formats[i]; - - // Discover screens and do mode specific initialization - QuartzInitOutput(argc, argv); - - // Add screens - for (i = 0; i < darwinScreensFound; i++) { - AddScreen(DarwinScreenInit, argc, argv); - } - - DarwinAdjustScreenOrigins(pScreenInfo); -} - - -/* - * OsVendorFatalError - */ -void OsVendorFatalError( void ) -{ - ErrorF( " OsVendorFatalError\n" ); -} - - -/* - * OsVendorInit - * Initialization of Darwin OS support. - */ -void OsVendorInit(void) -{ - if (serverGeneration == 1) { - DarwinPrintBanner(); -#ifdef ENABLE_DEBUG_LOG - { - char *home_dir=NULL, *log_file_path=NULL; - home_dir = getenv("HOME"); - if (home_dir) asprintf(&log_file_path, "%s/%s", home_dir, DEBUG_LOG_NAME); - if (log_file_path) { - if (!access(log_file_path, F_OK)) { - debug_log_fp = fopen(log_file_path, "a"); - if (debug_log_fp) ErrorF("Debug logging enabled to %s\n", log_file_path); - } - free(log_file_path); - } - } -#endif - } -} - - -/* - * ddxProcessArgument - * Process device-dependent command line args. Returns 0 if argument is - * not device dependent, otherwise Count of number of elements of argv - * that are part of a device dependent commandline option. - */ -int ddxProcessArgument( int argc, char *argv[], int i ) -{ -// if ( !strcmp( argv[i], "-fullscreen" ) ) { -// ErrorF( "Running full screen in parallel with Mac OS X Quartz window server.\n" ); -// return 1; -// } - -// if ( !strcmp( argv[i], "-rootless" ) ) { -// ErrorF( "Running rootless inside Mac OS X window server.\n" ); -// return 1; -// } - - // This command line arg is passed when launched from the Aqua GUI. - if ( !strncmp( argv[i], "-psn_", 5 ) ) { - return 1; - } - - if ( !strcmp( argv[i], "-fakebuttons" ) ) { - darwinFakeButtons = TRUE; - ErrorF( "Faking a three button mouse\n" ); - return 1; - } - - if ( !strcmp( argv[i], "-nofakebuttons" ) ) { - darwinFakeButtons = FALSE; - ErrorF( "Not faking a three button mouse\n" ); - return 1; - } - - if (!strcmp( argv[i], "-fakemouse2" ) ) { - if ( i == argc-1 ) { - FatalError( "-fakemouse2 must be followed by a modifer list\n" ); - } - if (!strcasecmp(argv[i+1], "none") || !strcmp(argv[i+1], "")) - darwinFakeMouse2Mask = 0; - else - darwinFakeMouse2Mask = DarwinParseModifierList(argv[i+1], 1); - ErrorF("Modifier mask to fake mouse button 2 = 0x%x\n", - darwinFakeMouse2Mask); - return 2; - } - - if (!strcmp( argv[i], "-fakemouse3" ) ) { - if ( i == argc-1 ) { - FatalError( "-fakemouse3 must be followed by a modifer list\n" ); - } - if (!strcasecmp(argv[i+1], "none") || !strcmp(argv[i+1], "")) - darwinFakeMouse3Mask = 0; - else - darwinFakeMouse3Mask = DarwinParseModifierList(argv[i+1], 1); - ErrorF("Modifier mask to fake mouse button 3 = 0x%x\n", - darwinFakeMouse3Mask); - return 2; - } - - if ( !strcmp( argv[i], "+synckeymap" ) ) { - darwinSyncKeymap = TRUE; - return 1; - } - - if ( !strcmp( argv[i], "-synckeymap" ) ) { - darwinSyncKeymap = FALSE; - return 1; - } - - if ( !strcmp( argv[i], "-depth" ) ) { - if ( i == argc-1 ) { - FatalError( "-depth must be followed by a number\n" ); - } - darwinDesiredDepth = atoi( argv[i+1] ); - if(darwinDesiredDepth != -1 && - darwinDesiredDepth != 8 && - darwinDesiredDepth != 15 && - darwinDesiredDepth != 24) { - FatalError( "Unsupported pixel depth. Use 8, 15, or 24 bits\n" ); - } - - ErrorF( "Attempting to use pixel depth of %i\n", darwinDesiredDepth ); - return 2; - } - - if (!strcmp( argv[i], "-showconfig" ) || !strcmp( argv[i], "-version" )) { - DarwinPrintBanner(); - exit(0); - } - - return 0; -} - - -/* - * ddxUseMsg -- - * Print out correct use of device dependent commandline options. - * Maybe the user now knows what really to do ... - */ -void ddxUseMsg( void ) -{ - ErrorF("\n"); - ErrorF("\n"); - ErrorF("Device Dependent Usage:\n"); - ErrorF("\n"); - ErrorF("-depth <8,15,24> : use this bit depth.\n"); - ErrorF("-fakebuttons : fake a three button mouse with Command and Option keys.\n"); - ErrorF("-nofakebuttons : don't fake a three button mouse.\n"); - ErrorF("-fakemouse2 <modifiers> : fake middle mouse button with modifier keys.\n"); - ErrorF("-fakemouse3 <modifiers> : fake right mouse button with modifier keys.\n"); - ErrorF(" ex: -fakemouse2 \"option,shift\" = option-shift-click is middle button.\n"); - ErrorF("-version : show the server version.\n"); - ErrorF("\n"); -} - - -/* - * ddxGiveUp -- - * Device dependent cleanup. Called by dix before normal server death. - */ -void ddxGiveUp( void ) -{ - ErrorF( "Quitting Xquartz\n" ); -} - - -/* - * AbortDDX -- - * DDX - specific abort routine. Called by AbortServer(). The attempt is - * made to restore all original setting of the displays. Also all devices - * are closed. - */ -void AbortDDX( void ) -{ - ErrorF( " AbortDDX\n" ); - OsAbort(); -} - -#include "mivalidate.h" // for union _Validate used by windowstr.h -#include "windowstr.h" // for struct _Window -#include "scrnintstr.h" // for struct _Screen - -// This is copied from Xserver/hw/xfree86/common/xf86Helper.c. -// Quartz mode uses this when switching in and out of Quartz. -// Quartz or IOKit can use this when waking from sleep. -// Copyright (c) 1997-1998 by The XFree86 Project, Inc. - -/* - * xf86SetRootClip -- - * Enable or disable rendering to the screen by - * setting the root clip list and revalidating - * all of the windows - */ - -void -xf86SetRootClip (ScreenPtr pScreen, int enable) -{ - WindowPtr pWin = WindowTable[pScreen->myNum]; - WindowPtr pChild; - Bool WasViewable = (Bool)(pWin->viewable); - Bool anyMarked = TRUE; - RegionPtr pOldClip = NULL, bsExposed; - WindowPtr pLayerWin; - BoxRec box; - - if (WasViewable) - { - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - (void) (*pScreen->MarkOverlappedWindows)(pChild, - pChild, - &pLayerWin); - } - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - if (pWin->valdata) - { - if (HasBorder (pWin)) - { - RegionPtr borderVisible; - - borderVisible = REGION_CREATE(pScreen, NullBox, 1); - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, &pWin->winSize); - pWin->valdata->before.borderVisible = borderVisible; - } - pWin->valdata->before.resized = TRUE; - } - } - - /* - * Use REGION_BREAK to avoid optimizations in ValidateTree - * that assume the root borderClip can't change well, normally - * it doesn't...) - */ - if (enable) - { - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - REGION_RESET(pScreen, &pWin->borderClip, &box); - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - else - { - REGION_EMPTY(pScreen, &pWin->borderClip); - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - - ResizeChildrenWinSize (pWin, 0, 0, 0, 0); - - if (WasViewable) - { - if (pWin->backStorage) - { - pOldClip = REGION_CREATE(pScreen, NullBox, 1); - REGION_COPY(pScreen, pOldClip, &pWin->clipList); - } - - if (pWin->firstChild) - { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, - pWin->firstChild, - (WindowPtr *)NULL); - } - else - { - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - } - - - if (anyMarked) - (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); - } - - if (pWin->backStorage && - ((pWin->backingStore == Always) || WasViewable)) - { - if (!WasViewable) - pOldClip = &pWin->clipList; /* a convenient empty region */ - bsExposed = (*pScreen->TranslateBackingStore) - (pWin, 0, 0, pOldClip, - pWin->drawable.x, pWin->drawable.y); - if (WasViewable) - REGION_DESTROY(pScreen, pOldClip); - if (bsExposed) - { - RegionPtr valExposed = NullRegion; - - if (pWin->valdata) - valExposed = &pWin->valdata->after.exposed; - (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); - if (valExposed) - REGION_EMPTY(pScreen, valExposed); - REGION_DESTROY(pScreen, bsExposed); - } - } - if (WasViewable) - { - if (anyMarked) - (*pScreen->HandleExposures)(pWin); - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); - } - if (pWin->realized) - WindowsRestructured (); - FlushAllOutput (); -} +/************************************************************** + * + * Xquartz initialization code + * + * Copyright (c) 2007-2008 Apple Inc. + * Copyright (c) 2001-2004 Torrey T. Lyons. 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "os.h" +#include "servermd.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "mibstore.h" // mi backing store implementation +#include "mipointer.h" // mi software cursor +#include "micmap.h" // mi colormap code +#include "fb.h" // fb framebuffer code +#include "site.h" +#include "globals.h" +#include "dix.h" +#include "xkbsrv.h" + +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "exevents.h" +#include "extinit.h" + +#include "xserver-properties.h" + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/syslimits.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#define HAS_UTSNAME 1 +#include <sys/utsname.h> + +#define NO_CFPLUGIN +#include <IOKit/hidsystem/IOHIDLib.h> + +#ifdef MITSHM +#include "shmint.h" +#endif + +#include "darwin.h" +#include "darwinEvents.h" +#include "quartzKeyboard.h" +#include "quartz.h" + +#ifdef ENABLE_DEBUG_LOG +FILE *debug_log_fp = NULL; +#endif + +/* + * X server shared global variables + */ +int darwinScreensFound = 0; +static int darwinScreenKeyIndex; +DevPrivateKey darwinScreenKey = &darwinScreenKeyIndex; +io_connect_t darwinParamConnect = 0; +int darwinEventReadFD = -1; +int darwinEventWriteFD = -1; +// int darwinMouseAccelChange = 1; +int darwinFakeButtons = 0; + +// location of X11's (0,0) point in global screen coordinates +int darwinMainScreenX = 0; +int darwinMainScreenY = 0; + +// parameters read from the command line or user preferences +int darwinDesiredDepth = -1; +int darwinSyncKeymap = FALSE; + +// modifier masks for faking mouse buttons - ANY of these bits trigger it (not all) +#ifdef NX_DEVICELCMDKEYMASK +int darwinFakeMouse2Mask = NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK; +int darwinFakeMouse3Mask = NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK; +#else +int darwinFakeMouse2Mask = NX_ALTERNATEMASK; +int darwinFakeMouse3Mask = NX_COMMANDMASK; +#endif + +// Modifier mask for overriding event delivery to appkit (might be useful to set this to rcommand for input menu +unsigned int darwinAppKitModMask = 0; // Any of these bits + +// Modifier mask for items in the Window menu (0 and -1 cause shortcuts to be disabled) +unsigned int windowItemModMask = NX_COMMANDMASK; + +// devices +DeviceIntPtr darwinKeyboard = NULL; +DeviceIntPtr darwinPointer = NULL; +DeviceIntPtr darwinTabletCurrent = NULL; +DeviceIntPtr darwinTabletStylus = NULL; +DeviceIntPtr darwinTabletCursor = NULL; +DeviceIntPtr darwinTabletEraser = NULL; + +// Common pixmap formats +static PixmapFormatRec formats[] = { + { 1, 1, BITMAP_SCANLINE_PAD }, + { 4, 8, BITMAP_SCANLINE_PAD }, + { 8, 8, BITMAP_SCANLINE_PAD }, + { 15, 16, BITMAP_SCANLINE_PAD }, + { 16, 16, BITMAP_SCANLINE_PAD }, + { 24, 32, BITMAP_SCANLINE_PAD }, + { 32, 32, BITMAP_SCANLINE_PAD } +}; +const int NUMFORMATS = sizeof(formats)/sizeof(formats[0]); + +#ifndef OSNAME +#define OSNAME " Darwin" +#endif +#ifndef OSVENDOR +#define OSVENDOR "" +#endif +#ifndef PRE_RELEASE +#define PRE_RELEASE XORG_VERSION_SNAP +#endif +#ifndef BUILD_DATE +#define BUILD_DATE "" +#endif +#ifndef XORG_RELEASE +#define XORG_RELEASE "?" +#endif + +void +DarwinPrintBanner(void) +{ + // this should change depending on which specific server we are building + ErrorF("Xquartz starting:\n"); + ErrorF("X.Org X Server %s\nBuild Date: %s\n", XSERVER_VERSION, BUILD_DATE ); +} + + +/* + * DarwinSaveScreen + * X screensaver support. Not implemented. + */ +static Bool DarwinSaveScreen(ScreenPtr pScreen, int on) +{ + // FIXME + if (on == SCREEN_SAVER_FORCER) { + } else if (on == SCREEN_SAVER_ON) { + } else { + } + return TRUE; +} + +/* + * DarwinScreenInit + * This is a callback from dix during AddScreen() from InitOutput(). + * Initialize the screen and communicate information about it back to dix. + */ +static Bool DarwinScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) { + int dpi; + static int foundIndex = 0; + Bool ret; + DarwinFramebufferPtr dfb; + + // reset index of found screens for each server generation + if (index == 0) { + foundIndex = 0; + + // reset the visual list + miClearVisualTypes(); + } + + // allocate space for private per screen storage + dfb = malloc(sizeof(DarwinFramebufferRec)); + + // SCREEN_PRIV(pScreen) = dfb; + dixSetPrivate(&pScreen->devPrivates, darwinScreenKey, dfb); + + // setup hardware/mode specific details + ret = QuartzAddScreen(foundIndex, pScreen); + foundIndex++; + if (! ret) + return FALSE; + + // setup a single visual appropriate for our pixel type + if(!miSetVisualTypesAndMasks(dfb->depth, dfb->visuals, dfb->bitsPerRGB, + dfb->preferredCVC, dfb->redMask, + dfb->greenMask, dfb->blueMask)) { + return FALSE; + } + +// TODO: Make PseudoColor visuals not suck in TrueColor mode +// if(dfb->depth > 8) +// miSetVisualTypesAndMasks(8, PseudoColorMask, 8, PseudoColor, 0, 0, 0); + if(dfb->depth > 15) + miSetVisualTypesAndMasks(15, TrueColorMask, 5, TrueColor, RM_ARGB(0,5,5,5), GM_ARGB(0,5,5,5), BM_ARGB(0,5,5,5)); + if(dfb->depth > 24) + miSetVisualTypesAndMasks(24, TrueColorMask, 8, TrueColor, RM_ARGB(0,8,8,8), GM_ARGB(0,8,8,8), BM_ARGB(0,8,8,8)); + + miSetPixmapDepths(); + + // machine independent screen init + // setup _Screen structure in pScreen + if (monitorResolution) + dpi = monitorResolution; + else + dpi = 96; + + // initialize fb + if (! fbScreenInit(pScreen, + dfb->framebuffer, // pointer to screen bitmap + dfb->width, dfb->height, // screen size in pixels + dpi, dpi, // dots per inch + dfb->pitch/(dfb->bitsPerPixel/8), // pixel width of framebuffer + dfb->bitsPerPixel)) // bits per pixel for screen + { + return FALSE; + } + + if (! fbPictureInit(pScreen, 0, 0)) { + return FALSE; + } + +#ifdef MITSHM + ShmRegisterFbFuncs(pScreen); +#endif + + // this must be initialized (why doesn't X have a default?) + pScreen->SaveScreen = DarwinSaveScreen; + + // finish mode dependent screen setup including cursor support + if (!QuartzSetupScreen(index, pScreen)) { + return FALSE; + } + + // create and install the default colormap and + // set pScreen->blackPixel / pScreen->white + if (!miCreateDefColormap( pScreen )) { + return FALSE; + } + + dixScreenOrigins[index].x = dfb->x; + dixScreenOrigins[index].y = dfb->y; + + /* ErrorF("Screen %d added: %dx%d @ (%d,%d)\n", + index, dfb->width, dfb->height, dfb->x, dfb->y); */ + + return TRUE; +} + +/* + ============================================================================= + + mouse and keyboard callbacks + + ============================================================================= +*/ + +/* + * DarwinMouseProc: Handle the initialization, etc. of a mouse + */ +static int DarwinMouseProc(DeviceIntPtr pPointer, int what) { +#define NBUTTONS 7 +#define NAXES 2 + // 7 buttons: left, right, middle, then four scroll wheel "buttons" + CARD8 map[NBUTTONS + 1] = {0, 1, 2, 3, 4, 5, 6, 7}; + Atom btn_labels[NBUTTONS] = {0}; + Atom axes_labels[NAXES] = {0}; + + switch (what) { + case DEVICE_INIT: + pPointer->public.on = FALSE; + + btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); + btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); + btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); + btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); + btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); + + + // Set button map. + InitPointerDeviceStruct((DevicePtr)pPointer, map, NBUTTONS, + btn_labels, + (PtrCtrlProcPtr)NoopDDA, + GetMotionHistorySize(), NAXES, + axes_labels); + pPointer->valuator->mode = Absolute; // Relative + InitAbsoluteClassDeviceStruct(pPointer); +// InitValuatorAxisStruct(pPointer, 0, 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); +// InitValuatorAxisStruct(pPointer, 1, 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); + break; + case DEVICE_ON: + pPointer->public.on = TRUE; + AddEnabledDevice( darwinEventReadFD ); + return Success; + case DEVICE_CLOSE: + case DEVICE_OFF: + pPointer->public.on = FALSE; + RemoveEnabledDevice(darwinEventReadFD); + return Success; + } + + return Success; +#undef NBUTTONS +#undef NAXES +} + +static int DarwinTabletProc(DeviceIntPtr pPointer, int what) { +#define NBUTTONS 3 +#define NAXES 5 + CARD8 map[NBUTTONS + 1] = {0, 1, 2, 3}; + Atom btn_labels[NBUTTONS] = {0}; + Atom axes_labels[NAXES] = {0}; + + switch (what) { + case DEVICE_INIT: + pPointer->public.on = FALSE; + + btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); + btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y); + axes_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_PRESSURE); + axes_labels[3] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_X); + axes_labels[4] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_Y); + + // Set button map. + InitPointerDeviceStruct((DevicePtr)pPointer, map, NBUTTONS, + btn_labels, + (PtrCtrlProcPtr)NoopDDA, + GetMotionHistorySize(), NAXES, + axes_labels); + pPointer->valuator->mode = Absolute; // Relative + InitProximityClassDeviceStruct(pPointer); + InitAbsoluteClassDeviceStruct(pPointer); + + InitValuatorAxisStruct(pPointer, 0, axes_labels[0], 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); + InitValuatorAxisStruct(pPointer, 1, axes_labels[1], 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); + InitValuatorAxisStruct(pPointer, 2, axes_labels[2], 0, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); + InitValuatorAxisStruct(pPointer, 3, axes_labels[3], -XQUARTZ_VALUATOR_LIMIT, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); + InitValuatorAxisStruct(pPointer, 4, axes_labels[4], -XQUARTZ_VALUATOR_LIMIT, XQUARTZ_VALUATOR_LIMIT, 1, 0, 1); +// pPointer->use = IsXExtensionDevice; + break; + case DEVICE_ON: + pPointer->public.on = TRUE; + AddEnabledDevice( darwinEventReadFD ); + return Success; + case DEVICE_CLOSE: + case DEVICE_OFF: + pPointer->public.on = FALSE; + RemoveEnabledDevice(darwinEventReadFD); + return Success; + } + return Success; +#undef NBUTTONS +#undef NAXES +} + +/* + * DarwinKeybdProc + * Callback from X + */ +static int DarwinKeybdProc( DeviceIntPtr pDev, int onoff ) +{ + switch ( onoff ) { + case DEVICE_INIT: + DarwinKeyboardInit( pDev ); + break; + case DEVICE_ON: + pDev->public.on = TRUE; + AddEnabledDevice( darwinEventReadFD ); + break; + case DEVICE_OFF: + pDev->public.on = FALSE; + RemoveEnabledDevice( darwinEventReadFD ); + break; + case DEVICE_CLOSE: + break; + } + + return Success; +} + +/* +=========================================================================== + + Utility routines + +=========================================================================== +*/ + +/* + * DarwinParseModifierList + * Parse a list of modifier names and return a corresponding modifier mask + */ +int DarwinParseModifierList(const char *constmodifiers, int separatelr) +{ + int result = 0; + + if (constmodifiers) { + char *modifiers = strdup(constmodifiers); + char *modifier; + int nxkey; + char *p = modifiers; + + while (p) { + modifier = strsep(&p, " ,+&|/"); // allow lots of separators + nxkey = DarwinModifierStringToNXMask(modifier, separatelr); + if(nxkey) + result |= nxkey; + else + ErrorF("fakebuttons: Unknown modifier \"%s\"\n", modifier); + } + free(modifiers); + } + return result; +} + +/* +=========================================================================== + + Functions needed to link against device independent X + +=========================================================================== +*/ + +/* + * InitInput + * Register the keyboard and mouse devices + */ +void InitInput( int argc, char **argv ) +{ + XkbRMLVOSet rmlvo = { .rules = "base", .model = "empty", .layout = "empty", + .variant = NULL, .options = NULL }; + /* We need to really have rules... or something... */ + XkbSetRulesDflts(&rmlvo); + + darwinKeyboard = AddInputDevice(serverClient, DarwinKeybdProc, TRUE); + RegisterKeyboardDevice( darwinKeyboard ); + darwinKeyboard->name = strdup("keyboard"); + + /* here's the snippet from the current gdk sources: + if (!strcmp (tmp_name, "pointer")) + gdkdev->info.source = GDK_SOURCE_MOUSE; + else if (!strcmp (tmp_name, "wacom") || + !strcmp (tmp_name, "pen")) + gdkdev->info.source = GDK_SOURCE_PEN; + else if (!strcmp (tmp_name, "eraser")) + gdkdev->info.source = GDK_SOURCE_ERASER; + else if (!strcmp (tmp_name, "cursor")) + gdkdev->info.source = GDK_SOURCE_CURSOR; + else + gdkdev->info.source = GDK_SOURCE_PEN; + */ + + darwinPointer = AddInputDevice(serverClient, DarwinMouseProc, TRUE); + RegisterPointerDevice( darwinPointer ); + darwinPointer->name = strdup("pointer"); + + darwinTabletStylus = AddInputDevice(serverClient, DarwinTabletProc, TRUE); + RegisterPointerDevice( darwinTabletStylus ); + darwinTabletStylus->name = strdup("pen"); + + darwinTabletCursor = AddInputDevice(serverClient, DarwinTabletProc, TRUE); + RegisterPointerDevice( darwinTabletCursor ); + darwinTabletCursor->name = strdup("cursor"); + + darwinTabletEraser = AddInputDevice(serverClient, DarwinTabletProc, TRUE); + RegisterPointerDevice( darwinTabletEraser ); + darwinTabletEraser->name = strdup("eraser"); + + darwinTabletCurrent = darwinTabletStylus; + + DarwinEQInit(); + + QuartzInitInput(argc, argv); +} + + +/* + * DarwinAdjustScreenOrigins + * Shift all screens so the X11 (0, 0) coordinate is at the top + * left of the global screen coordinates. + * + * Screens can be arranged so the top left isn't on any screen, so + * instead use the top left of the leftmost screen as (0,0). This + * may mean some screen space is in -y, but it's better that (0,0) + * be onscreen, or else default xterms disappear. It's better that + * -y be used than -x, because when popup menus are forced + * "onscreen" by dumb window managers like twm, they'll shift the + * menus down instead of left, which still looks funny but is an + * easier target to hit. + */ +void +DarwinAdjustScreenOrigins(ScreenInfo *pScreenInfo) +{ + int i, left, top; + + left = dixScreenOrigins[0].x; + top = dixScreenOrigins[0].y; + + /* Find leftmost screen. If there's a tie, take the topmost of the two. */ + for (i = 1; i < pScreenInfo->numScreens; i++) { + if (dixScreenOrigins[i].x < left || + (dixScreenOrigins[i].x == left && dixScreenOrigins[i].y < top)) + { + left = dixScreenOrigins[i].x; + top = dixScreenOrigins[i].y; + } + } + + darwinMainScreenX = left; + darwinMainScreenY = top; + + DEBUG_LOG("top = %d, left=%d\n", top, left); + + /* Shift all screens so that there is a screen whose top left + * is at X11 (0,0) and at global screen coordinate + * (darwinMainScreenX, darwinMainScreenY). + */ + + if (darwinMainScreenX != 0 || darwinMainScreenY != 0) { + for (i = 0; i < pScreenInfo->numScreens; i++) { + dixScreenOrigins[i].x -= darwinMainScreenX; + dixScreenOrigins[i].y -= darwinMainScreenY; + DEBUG_LOG("Screen %d placed at X11 coordinate (%d,%d).\n", + i, dixScreenOrigins[i].x, dixScreenOrigins[i].y); + } + } +} + + +/* + * InitOutput + * Initialize screenInfo for all actually accessible framebuffers. + * + * The display mode dependent code gets called three times. The mode + * specific InitOutput routines are expected to discover the number + * of potentially useful screens and cache routes to them internally. + * Inside DarwinScreenInit are two other mode specific calls. + * A mode specific AddScreen routine is called for each screen to + * actually initialize the screen with the ScreenPtr structure. + * After other screen setup has been done, a mode specific + * SetupScreen function can be called to finalize screen setup. + */ +void InitOutput( ScreenInfo *pScreenInfo, int argc, char **argv ) +{ + int i; + + pScreenInfo->imageByteOrder = IMAGE_BYTE_ORDER; + pScreenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + pScreenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + pScreenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; + + // List how we want common pixmap formats to be padded + pScreenInfo->numPixmapFormats = NUMFORMATS; + for (i = 0; i < NUMFORMATS; i++) + pScreenInfo->formats[i] = formats[i]; + + // Discover screens and do mode specific initialization + QuartzInitOutput(argc, argv); + + // Add screens + for (i = 0; i < darwinScreensFound; i++) { + AddScreen(DarwinScreenInit, argc, argv); + } + + DarwinAdjustScreenOrigins(pScreenInfo); +} + + +/* + * OsVendorFatalError + */ +void OsVendorFatalError( void ) +{ + ErrorF( " OsVendorFatalError\n" ); +} + + +/* + * OsVendorInit + * Initialization of Darwin OS support. + */ +void OsVendorInit(void) +{ + if (serverGeneration == 1) { + DarwinPrintBanner(); +#ifdef ENABLE_DEBUG_LOG + { + char *home_dir=NULL, *log_file_path=NULL; + home_dir = getenv("HOME"); + if (home_dir) asprintf(&log_file_path, "%s/%s", home_dir, DEBUG_LOG_NAME); + if (log_file_path) { + if (!access(log_file_path, F_OK)) { + debug_log_fp = fopen(log_file_path, "a"); + if (debug_log_fp) ErrorF("Debug logging enabled to %s\n", log_file_path); + } + free(log_file_path); + } + } +#endif + } +} + + +/* + * ddxProcessArgument + * Process device-dependent command line args. Returns 0 if argument is + * not device dependent, otherwise Count of number of elements of argv + * that are part of a device dependent commandline option. + */ +int ddxProcessArgument( int argc, char *argv[], int i ) +{ +// if ( !strcmp( argv[i], "-fullscreen" ) ) { +// ErrorF( "Running full screen in parallel with Mac OS X Quartz window server.\n" ); +// return 1; +// } + +// if ( !strcmp( argv[i], "-rootless" ) ) { +// ErrorF( "Running rootless inside Mac OS X window server.\n" ); +// return 1; +// } + + // This command line arg is passed when launched from the Aqua GUI. + if ( !strncmp( argv[i], "-psn_", 5 ) ) { + return 1; + } + + if ( !strcmp( argv[i], "-fakebuttons" ) ) { + darwinFakeButtons = TRUE; + ErrorF( "Faking a three button mouse\n" ); + return 1; + } + + if ( !strcmp( argv[i], "-nofakebuttons" ) ) { + darwinFakeButtons = FALSE; + ErrorF( "Not faking a three button mouse\n" ); + return 1; + } + + if (!strcmp( argv[i], "-fakemouse2" ) ) { + if ( i == argc-1 ) { + FatalError( "-fakemouse2 must be followed by a modifer list\n" ); + } + if (!strcasecmp(argv[i+1], "none") || !strcmp(argv[i+1], "")) + darwinFakeMouse2Mask = 0; + else + darwinFakeMouse2Mask = DarwinParseModifierList(argv[i+1], 1); + ErrorF("Modifier mask to fake mouse button 2 = 0x%x\n", + darwinFakeMouse2Mask); + return 2; + } + + if (!strcmp( argv[i], "-fakemouse3" ) ) { + if ( i == argc-1 ) { + FatalError( "-fakemouse3 must be followed by a modifer list\n" ); + } + if (!strcasecmp(argv[i+1], "none") || !strcmp(argv[i+1], "")) + darwinFakeMouse3Mask = 0; + else + darwinFakeMouse3Mask = DarwinParseModifierList(argv[i+1], 1); + ErrorF("Modifier mask to fake mouse button 3 = 0x%x\n", + darwinFakeMouse3Mask); + return 2; + } + + if ( !strcmp( argv[i], "+synckeymap" ) ) { + darwinSyncKeymap = TRUE; + return 1; + } + + if ( !strcmp( argv[i], "-synckeymap" ) ) { + darwinSyncKeymap = FALSE; + return 1; + } + + if ( !strcmp( argv[i], "-depth" ) ) { + if ( i == argc-1 ) { + FatalError( "-depth must be followed by a number\n" ); + } + darwinDesiredDepth = atoi( argv[i+1] ); + if(darwinDesiredDepth != -1 && + darwinDesiredDepth != 8 && + darwinDesiredDepth != 15 && + darwinDesiredDepth != 24) { + FatalError( "Unsupported pixel depth. Use 8, 15, or 24 bits\n" ); + } + + ErrorF( "Attempting to use pixel depth of %i\n", darwinDesiredDepth ); + return 2; + } + + if (!strcmp( argv[i], "-showconfig" ) || !strcmp( argv[i], "-version" )) { + DarwinPrintBanner(); + exit(0); + } + + return 0; +} + + +/* + * ddxUseMsg -- + * Print out correct use of device dependent commandline options. + * Maybe the user now knows what really to do ... + */ +void ddxUseMsg( void ) +{ + ErrorF("\n"); + ErrorF("\n"); + ErrorF("Device Dependent Usage:\n"); + ErrorF("\n"); + ErrorF("-depth <8,15,24> : use this bit depth.\n"); + ErrorF("-fakebuttons : fake a three button mouse with Command and Option keys.\n"); + ErrorF("-nofakebuttons : don't fake a three button mouse.\n"); + ErrorF("-fakemouse2 <modifiers> : fake middle mouse button with modifier keys.\n"); + ErrorF("-fakemouse3 <modifiers> : fake right mouse button with modifier keys.\n"); + ErrorF(" ex: -fakemouse2 \"option,shift\" = option-shift-click is middle button.\n"); + ErrorF("-version : show the server version.\n"); + ErrorF("\n"); +} + + +/* + * ddxGiveUp -- + * Device dependent cleanup. Called by dix before normal server death. + */ +void ddxGiveUp( void ) +{ + ErrorF( "Quitting Xquartz\n" ); +} + + +/* + * AbortDDX -- + * DDX - specific abort routine. Called by AbortServer(). The attempt is + * made to restore all original setting of the displays. Also all devices + * are closed. + */ +void AbortDDX( void ) +{ + ErrorF( " AbortDDX\n" ); + OsAbort(); +} + +#include "mivalidate.h" // for union _Validate used by windowstr.h +#include "windowstr.h" // for struct _Window +#include "scrnintstr.h" // for struct _Screen + +// This is copied from Xserver/hw/xfree86/common/xf86Helper.c. +// Quartz mode uses this when switching in and out of Quartz. +// Quartz or IOKit can use this when waking from sleep. +// Copyright (c) 1997-1998 by The XFree86 Project, Inc. + +/* + * xf86SetRootClip -- + * Enable or disable rendering to the screen by + * setting the root clip list and revalidating + * all of the windows + */ + +void +xf86SetRootClip (ScreenPtr pScreen, int enable) +{ + WindowPtr pWin = WindowTable[pScreen->myNum]; + WindowPtr pChild; + Bool WasViewable = (Bool)(pWin->viewable); + Bool anyMarked = TRUE; + RegionPtr pOldClip = NULL, bsExposed; + WindowPtr pLayerWin; + BoxRec box; + + if (WasViewable) + { + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + (void) (*pScreen->MarkOverlappedWindows)(pChild, + pChild, + &pLayerWin); + } + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + pWin->valdata->before.resized = TRUE; + } + } + + /* + * Use REGION_BREAK to avoid optimizations in ValidateTree + * that assume the root borderClip can't change well, normally + * it doesn't...) + */ + if (enable) + { + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + REGION_RESET(pScreen, &pWin->borderClip, &box); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + else + { + REGION_EMPTY(pScreen, &pWin->borderClip); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + + ResizeChildrenWinSize (pWin, 0, 0, 0, 0); + + if (WasViewable) + { + if (pWin->backStorage) + { + pOldClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, pOldClip, &pWin->clipList); + } + + if (pWin->firstChild) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, + pWin->firstChild, + (WindowPtr *)NULL); + } + else + { + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + } + + + if (anyMarked) + (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); + } + + if (pWin->backStorage && + ((pWin->backingStore == Always) || WasViewable)) + { + if (!WasViewable) + pOldClip = &pWin->clipList; /* a convenient empty region */ + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, 0, 0, pOldClip, + pWin->drawable.x, pWin->drawable.y); + if (WasViewable) + REGION_DESTROY(pScreen, pOldClip); + if (bsExposed) + { + RegionPtr valExposed = NullRegion; + + if (pWin->valdata) + valExposed = &pWin->valdata->after.exposed; + (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); + if (valExposed) + REGION_EMPTY(pScreen, valExposed); + REGION_DESTROY(pScreen, bsExposed); + } + } + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pWin); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + FlushAllOutput (); +} diff --git a/xorg-server/hw/xquartz/pseudoramiX.c b/xorg-server/hw/xquartz/pseudoramiX.c index 1de7af6dc..1a357528c 100644 --- a/xorg-server/hw/xquartz/pseudoramiX.c +++ b/xorg-server/hw/xquartz/pseudoramiX.c @@ -1,471 +1,471 @@ -/* - * Minimal implementation of PanoramiX/Xinerama - * - * This is used in rootless mode where the underlying window server - * already provides an abstracted view of multiple screens as one - * large screen area. - * - * This code is largely based on panoramiX.c, which contains the - * following copyright 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 <dix-config.h> -#endif - -#include "darwin.h" -#include "pseudoramiX.h" -#include "extnsionst.h" -#include "dixstruct.h" -#include "window.h" -#include <X11/extensions/panoramiXproto.h> -#include "globals.h" - -Bool noPseudoramiXExtension = FALSE; - -extern int ProcPanoramiXQueryVersion (ClientPtr client); - -static void PseudoramiXResetProc(ExtensionEntry *extEntry); - -static int ProcPseudoramiXQueryVersion(ClientPtr client); -static int ProcPseudoramiXGetState(ClientPtr client); -static int ProcPseudoramiXGetScreenCount(ClientPtr client); -static int ProcPseudoramiXGetScreenSize(ClientPtr client); -static int ProcPseudoramiXIsActive(ClientPtr client); -static int ProcPseudoramiXQueryScreens(ClientPtr client); -static int ProcPseudoramiXDispatch(ClientPtr client); - -static int SProcPseudoramiXQueryVersion(ClientPtr client); -static int SProcPseudoramiXGetState(ClientPtr client); -static int SProcPseudoramiXGetScreenCount(ClientPtr client); -static int SProcPseudoramiXGetScreenSize(ClientPtr client); -static int SProcPseudoramiXIsActive(ClientPtr client); -static int SProcPseudoramiXQueryScreens(ClientPtr client); -static int SProcPseudoramiXDispatch(ClientPtr client); - - -typedef struct { - int x; - int y; - int w; - int h; -} PseudoramiXScreenRec; - -static PseudoramiXScreenRec *pseudoramiXScreens = NULL; -static int pseudoramiXScreensAllocated = 0; -static int pseudoramiXNumScreens = 0; -static unsigned long pseudoramiXGeneration = 0; - - -// Add a PseudoramiX screen. -// The rest of the X server will know nothing about this screen. -// Can be called before or after extension init. -// Screens must be re-added once per generation. -void -PseudoramiXAddScreen(int x, int y, int w, int h) -{ - PseudoramiXScreenRec *s; - - if (noPseudoramiXExtension) return; - - if (pseudoramiXNumScreens == pseudoramiXScreensAllocated) { - pseudoramiXScreensAllocated += pseudoramiXScreensAllocated + 1; - pseudoramiXScreens = xrealloc(pseudoramiXScreens, - pseudoramiXScreensAllocated * - sizeof(PseudoramiXScreenRec)); - } - - DEBUG_LOG("x: %d, y: %d, w: %d, h: %d\n", x, y, w, h); - - s = &pseudoramiXScreens[pseudoramiXNumScreens++]; - s->x = x; - s->y = y; - s->w = w; - s->h = h; -} - - -// Initialize PseudoramiX. -// Copied from PanoramiXExtensionInit -void PseudoramiXExtensionInit(int argc, char *argv[]) -{ - Bool success = FALSE; - ExtensionEntry *extEntry; - - if (noPseudoramiXExtension) return; - - TRACE(); - - /* Even with only one screen we need to enable PseudoramiX to allow - dynamic screen configuration changes. */ -#if 0 - if (pseudoramiXNumScreens == 1) { - // Only one screen - disable Xinerama extension. - noPseudoramiXExtension = TRUE; - return; - } -#endif - - if (pseudoramiXGeneration != serverGeneration) { - extEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0, 0, - ProcPseudoramiXDispatch, - SProcPseudoramiXDispatch, - PseudoramiXResetProc, - StandardMinorOpcode); - if (!extEntry) { - ErrorF("PseudoramiXExtensionInit(): AddExtension failed\n"); - } else { - pseudoramiXGeneration = serverGeneration; - success = TRUE; - } - } - - if (!success) { - ErrorF("%s Extension (PseudoramiX) failed to initialize\n", - PANORAMIX_PROTOCOL_NAME); - return; - } -} - - -void PseudoramiXResetScreens(void) -{ - TRACE(); - - pseudoramiXNumScreens = 0; -} - - -static void PseudoramiXResetProc(ExtensionEntry *extEntry) -{ - TRACE(); - - PseudoramiXResetScreens(); -} - - -// was PanoramiX -static int ProcPseudoramiXQueryVersion(ClientPtr client) -{ - TRACE(); - - return ProcPanoramiXQueryVersion(client); -} - - -// was PanoramiX -static int ProcPseudoramiXGetState(ClientPtr client) -{ - REQUEST(xPanoramiXGetStateReq); - WindowPtr pWin; - xPanoramiXGetStateReply rep; - register int n, rc; - - TRACE(); - - REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.state = !noPseudoramiXExtension; - if (client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swaps (&rep.state, n); - } - WriteToClient (client, sizeof (xPanoramiXGetStateReply), (char *) &rep); - return client->noClientException; -} - - -// was PanoramiX -static int ProcPseudoramiXGetScreenCount(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenCountReq); - WindowPtr pWin; - xPanoramiXGetScreenCountReply rep; - register int n, rc; - - TRACE(); - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.ScreenCount = pseudoramiXNumScreens; - if (client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swaps (&rep.ScreenCount, n); - } - WriteToClient (client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); - return client->noClientException; -} - - -// was PanoramiX -static int ProcPseudoramiXGetScreenSize(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenSizeReq); - WindowPtr pWin; - xPanoramiXGetScreenSizeReply rep; - register int n, rc; - - TRACE(); - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - /* screen dimensions */ - rep.width = pseudoramiXScreens[stuff->screen].w; - // was panoramiXdataPtr[stuff->screen].width; - rep.height = pseudoramiXScreens[stuff->screen].h; - // was panoramiXdataPtr[stuff->screen].height; - if (client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swaps (&rep.width, n); - swaps (&rep.height, n); - } - WriteToClient (client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); - return client->noClientException; -} - - -// was Xinerama -static int ProcPseudoramiXIsActive(ClientPtr client) -{ - /* REQUEST(xXineramaIsActiveReq); */ - xXineramaIsActiveReply rep; - - TRACE(); - - REQUEST_SIZE_MATCH(xXineramaIsActiveReq); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.state = !noPseudoramiXExtension; - if (client->swapped) { - register int n; - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.state, n); - } - WriteToClient (client, sizeof (xXineramaIsActiveReply), (char *) &rep); - return client->noClientException; -} - - -// was Xinerama -static int ProcPseudoramiXQueryScreens(ClientPtr client) -{ - /* REQUEST(xXineramaQueryScreensReq); */ - xXineramaQueryScreensReply rep; - - DEBUG_LOG("noPseudoramiXExtension=%d, pseudoramiXNumScreens=%d\n", noPseudoramiXExtension, pseudoramiXNumScreens); - - REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.number = noPseudoramiXExtension ? 0 : pseudoramiXNumScreens; - rep.length = bytes_to_int32(rep.number * sz_XineramaScreenInfo); - if (client->swapped) { - register int n; - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.number, n); - } - WriteToClient (client, sizeof (xXineramaQueryScreensReply), (char *) &rep); - - if (!noPseudoramiXExtension) { - xXineramaScreenInfo scratch; - int i; - - for(i = 0; i < pseudoramiXNumScreens; i++) { - scratch.x_org = pseudoramiXScreens[i].x; - scratch.y_org = pseudoramiXScreens[i].y; - scratch.width = pseudoramiXScreens[i].w; - scratch.height = pseudoramiXScreens[i].h; - - if(client->swapped) { - register int n; - swaps (&scratch.x_org, n); - swaps (&scratch.y_org, n); - swaps (&scratch.width, n); - swaps (&scratch.height, n); - } - WriteToClient (client, sz_XineramaScreenInfo, (char *) &scratch); - } - } - - return client->noClientException; -} - - -// was PanoramiX -static int ProcPseudoramiXDispatch (ClientPtr client) -{ REQUEST(xReq); - TRACE(); - switch (stuff->data) - { - case X_PanoramiXQueryVersion: - return ProcPseudoramiXQueryVersion(client); - case X_PanoramiXGetState: - return ProcPseudoramiXGetState(client); - case X_PanoramiXGetScreenCount: - return ProcPseudoramiXGetScreenCount(client); - case X_PanoramiXGetScreenSize: - return ProcPseudoramiXGetScreenSize(client); - case X_XineramaIsActive: - return ProcPseudoramiXIsActive(client); - case X_XineramaQueryScreens: - return ProcPseudoramiXQueryScreens(client); - } - return BadRequest; -} - - - -static int -SProcPseudoramiXQueryVersion (ClientPtr client) -{ - REQUEST(xPanoramiXQueryVersionReq); - register int n; - - TRACE(); - - swaps(&stuff->length,n); - REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); - return ProcPseudoramiXQueryVersion(client); -} - -static int -SProcPseudoramiXGetState(ClientPtr client) -{ - REQUEST(xPanoramiXGetStateReq); - register int n; - - TRACE(); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); - return ProcPseudoramiXGetState(client); -} - -static int -SProcPseudoramiXGetScreenCount(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenCountReq); - register int n; - - TRACE(); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); - return ProcPseudoramiXGetScreenCount(client); -} - -static int -SProcPseudoramiXGetScreenSize(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenSizeReq); - register int n; - - TRACE(); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); - return ProcPseudoramiXGetScreenSize(client); -} - - -static int -SProcPseudoramiXIsActive(ClientPtr client) -{ - REQUEST(xXineramaIsActiveReq); - register int n; - - TRACE(); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXineramaIsActiveReq); - return ProcPseudoramiXIsActive(client); -} - - -static int -SProcPseudoramiXQueryScreens(ClientPtr client) -{ - REQUEST(xXineramaQueryScreensReq); - register int n; - - TRACE(); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); - return ProcPseudoramiXQueryScreens(client); -} - - -static int -SProcPseudoramiXDispatch (ClientPtr client) -{ REQUEST(xReq); - - TRACE(); - - switch (stuff->data) - { - case X_PanoramiXQueryVersion: - return SProcPseudoramiXQueryVersion(client); - case X_PanoramiXGetState: - return SProcPseudoramiXGetState(client); - case X_PanoramiXGetScreenCount: - return SProcPseudoramiXGetScreenCount(client); - case X_PanoramiXGetScreenSize: - return SProcPseudoramiXGetScreenSize(client); - case X_XineramaIsActive: - return SProcPseudoramiXIsActive(client); - case X_XineramaQueryScreens: - return SProcPseudoramiXQueryScreens(client); - } - return BadRequest; -} +/* + * Minimal implementation of PanoramiX/Xinerama + * + * This is used in rootless mode where the underlying window server + * already provides an abstracted view of multiple screens as one + * large screen area. + * + * This code is largely based on panoramiX.c, which contains the + * following copyright 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 <dix-config.h> +#endif + +#include "darwin.h" +#include "pseudoramiX.h" +#include "extnsionst.h" +#include "dixstruct.h" +#include "window.h" +#include <X11/extensions/panoramiXproto.h> +#include "globals.h" + +Bool noPseudoramiXExtension = FALSE; + +extern int ProcPanoramiXQueryVersion (ClientPtr client); + +static void PseudoramiXResetProc(ExtensionEntry *extEntry); + +static int ProcPseudoramiXQueryVersion(ClientPtr client); +static int ProcPseudoramiXGetState(ClientPtr client); +static int ProcPseudoramiXGetScreenCount(ClientPtr client); +static int ProcPseudoramiXGetScreenSize(ClientPtr client); +static int ProcPseudoramiXIsActive(ClientPtr client); +static int ProcPseudoramiXQueryScreens(ClientPtr client); +static int ProcPseudoramiXDispatch(ClientPtr client); + +static int SProcPseudoramiXQueryVersion(ClientPtr client); +static int SProcPseudoramiXGetState(ClientPtr client); +static int SProcPseudoramiXGetScreenCount(ClientPtr client); +static int SProcPseudoramiXGetScreenSize(ClientPtr client); +static int SProcPseudoramiXIsActive(ClientPtr client); +static int SProcPseudoramiXQueryScreens(ClientPtr client); +static int SProcPseudoramiXDispatch(ClientPtr client); + + +typedef struct { + int x; + int y; + int w; + int h; +} PseudoramiXScreenRec; + +static PseudoramiXScreenRec *pseudoramiXScreens = NULL; +static int pseudoramiXScreensAllocated = 0; +static int pseudoramiXNumScreens = 0; +static unsigned long pseudoramiXGeneration = 0; + + +// Add a PseudoramiX screen. +// The rest of the X server will know nothing about this screen. +// Can be called before or after extension init. +// Screens must be re-added once per generation. +void +PseudoramiXAddScreen(int x, int y, int w, int h) +{ + PseudoramiXScreenRec *s; + + if (noPseudoramiXExtension) return; + + if (pseudoramiXNumScreens == pseudoramiXScreensAllocated) { + pseudoramiXScreensAllocated += pseudoramiXScreensAllocated + 1; + pseudoramiXScreens = realloc(pseudoramiXScreens, + pseudoramiXScreensAllocated * + sizeof(PseudoramiXScreenRec)); + } + + DEBUG_LOG("x: %d, y: %d, w: %d, h: %d\n", x, y, w, h); + + s = &pseudoramiXScreens[pseudoramiXNumScreens++]; + s->x = x; + s->y = y; + s->w = w; + s->h = h; +} + + +// Initialize PseudoramiX. +// Copied from PanoramiXExtensionInit +void PseudoramiXExtensionInit(int argc, char *argv[]) +{ + Bool success = FALSE; + ExtensionEntry *extEntry; + + if (noPseudoramiXExtension) return; + + TRACE(); + + /* Even with only one screen we need to enable PseudoramiX to allow + dynamic screen configuration changes. */ +#if 0 + if (pseudoramiXNumScreens == 1) { + // Only one screen - disable Xinerama extension. + noPseudoramiXExtension = TRUE; + return; + } +#endif + + if (pseudoramiXGeneration != serverGeneration) { + extEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0, 0, + ProcPseudoramiXDispatch, + SProcPseudoramiXDispatch, + PseudoramiXResetProc, + StandardMinorOpcode); + if (!extEntry) { + ErrorF("PseudoramiXExtensionInit(): AddExtension failed\n"); + } else { + pseudoramiXGeneration = serverGeneration; + success = TRUE; + } + } + + if (!success) { + ErrorF("%s Extension (PseudoramiX) failed to initialize\n", + PANORAMIX_PROTOCOL_NAME); + return; + } +} + + +void PseudoramiXResetScreens(void) +{ + TRACE(); + + pseudoramiXNumScreens = 0; +} + + +static void PseudoramiXResetProc(ExtensionEntry *extEntry) +{ + TRACE(); + + PseudoramiXResetScreens(); +} + + +// was PanoramiX +static int ProcPseudoramiXQueryVersion(ClientPtr client) +{ + TRACE(); + + return ProcPanoramiXQueryVersion(client); +} + + +// was PanoramiX +static int ProcPseudoramiXGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + WindowPtr pWin; + xPanoramiXGetStateReply rep; + register int n, rc; + + TRACE(); + + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = !noPseudoramiXExtension; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swaps (&rep.state, n); + } + WriteToClient (client, sizeof (xPanoramiXGetStateReply), (char *) &rep); + return Success; +} + + +// was PanoramiX +static int ProcPseudoramiXGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + WindowPtr pWin; + xPanoramiXGetScreenCountReply rep; + register int n, rc; + + TRACE(); + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.ScreenCount = pseudoramiXNumScreens; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swaps (&rep.ScreenCount, n); + } + WriteToClient (client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); + return Success; +} + + +// was PanoramiX +static int ProcPseudoramiXGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + WindowPtr pWin; + xPanoramiXGetScreenSizeReply rep; + register int n, rc; + + TRACE(); + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + /* screen dimensions */ + rep.width = pseudoramiXScreens[stuff->screen].w; + // was panoramiXdataPtr[stuff->screen].width; + rep.height = pseudoramiXScreens[stuff->screen].h; + // was panoramiXdataPtr[stuff->screen].height; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swaps (&rep.width, n); + swaps (&rep.height, n); + } + WriteToClient (client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); + return Success; +} + + +// was Xinerama +static int ProcPseudoramiXIsActive(ClientPtr client) +{ + /* REQUEST(xXineramaIsActiveReq); */ + xXineramaIsActiveReply rep; + + TRACE(); + + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = !noPseudoramiXExtension; + if (client->swapped) { + register int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.state, n); + } + WriteToClient (client, sizeof (xXineramaIsActiveReply), (char *) &rep); + return Success; +} + + +// was Xinerama +static int ProcPseudoramiXQueryScreens(ClientPtr client) +{ + /* REQUEST(xXineramaQueryScreensReq); */ + xXineramaQueryScreensReply rep; + + DEBUG_LOG("noPseudoramiXExtension=%d, pseudoramiXNumScreens=%d\n", noPseudoramiXExtension, pseudoramiXNumScreens); + + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.number = noPseudoramiXExtension ? 0 : pseudoramiXNumScreens; + rep.length = bytes_to_int32(rep.number * sz_XineramaScreenInfo); + if (client->swapped) { + register int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.number, n); + } + WriteToClient (client, sizeof (xXineramaQueryScreensReply), (char *) &rep); + + if (!noPseudoramiXExtension) { + xXineramaScreenInfo scratch; + int i; + + for(i = 0; i < pseudoramiXNumScreens; i++) { + scratch.x_org = pseudoramiXScreens[i].x; + scratch.y_org = pseudoramiXScreens[i].y; + scratch.width = pseudoramiXScreens[i].w; + scratch.height = pseudoramiXScreens[i].h; + + if(client->swapped) { + register int n; + swaps (&scratch.x_org, n); + swaps (&scratch.y_org, n); + swaps (&scratch.width, n); + swaps (&scratch.height, n); + } + WriteToClient (client, sz_XineramaScreenInfo, (char *) &scratch); + } + } + + return Success; +} + + +// was PanoramiX +static int ProcPseudoramiXDispatch (ClientPtr client) +{ REQUEST(xReq); + TRACE(); + switch (stuff->data) + { + case X_PanoramiXQueryVersion: + return ProcPseudoramiXQueryVersion(client); + case X_PanoramiXGetState: + return ProcPseudoramiXGetState(client); + case X_PanoramiXGetScreenCount: + return ProcPseudoramiXGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return ProcPseudoramiXGetScreenSize(client); + case X_XineramaIsActive: + return ProcPseudoramiXIsActive(client); + case X_XineramaQueryScreens: + return ProcPseudoramiXQueryScreens(client); + } + return BadRequest; +} + + + +static int +SProcPseudoramiXQueryVersion (ClientPtr client) +{ + REQUEST(xPanoramiXQueryVersionReq); + register int n; + + TRACE(); + + swaps(&stuff->length,n); + REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); + return ProcPseudoramiXQueryVersion(client); +} + +static int +SProcPseudoramiXGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + register int n; + + TRACE(); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + return ProcPseudoramiXGetState(client); +} + +static int +SProcPseudoramiXGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + register int n; + + TRACE(); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + return ProcPseudoramiXGetScreenCount(client); +} + +static int +SProcPseudoramiXGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + register int n; + + TRACE(); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + return ProcPseudoramiXGetScreenSize(client); +} + + +static int +SProcPseudoramiXIsActive(ClientPtr client) +{ + REQUEST(xXineramaIsActiveReq); + register int n; + + TRACE(); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + return ProcPseudoramiXIsActive(client); +} + + +static int +SProcPseudoramiXQueryScreens(ClientPtr client) +{ + REQUEST(xXineramaQueryScreensReq); + register int n; + + TRACE(); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + return ProcPseudoramiXQueryScreens(client); +} + + +static int +SProcPseudoramiXDispatch (ClientPtr client) +{ REQUEST(xReq); + + TRACE(); + + switch (stuff->data) + { + case X_PanoramiXQueryVersion: + return SProcPseudoramiXQueryVersion(client); + case X_PanoramiXGetState: + return SProcPseudoramiXGetState(client); + case X_PanoramiXGetScreenCount: + return SProcPseudoramiXGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return SProcPseudoramiXGetScreenSize(client); + case X_XineramaIsActive: + return SProcPseudoramiXIsActive(client); + case X_XineramaQueryScreens: + return SProcPseudoramiXQueryScreens(client); + } + return BadRequest; +} diff --git a/xorg-server/hw/xquartz/quartz.c b/xorg-server/hw/xquartz/quartz.c index a8c0d4b47..e073b0586 100644 --- a/xorg-server/hw/xquartz/quartz.c +++ b/xorg-server/hw/xquartz/quartz.c @@ -1,449 +1,448 @@ -/* - * - * Quartz-specific support for the Darwin X Server - * - * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons. - * 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright - * holders shall not be used in advertising or otherwise to promote the sale, - * use or other dealings in this Software without prior written authorization. - */ - -#include "sanitizedCarbon.h" - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "quartzCommon.h" -#include "inputstr.h" -#include "quartz.h" -#include "darwin.h" -#include "darwinEvents.h" -#include "pseudoramiX.h" -#define _APPLEWM_SERVER_ -#include "applewmExt.h" - -#include "X11Application.h" - -#include <X11/extensions/applewmconst.h> -#include <X11/extensions/randr.h> - -// X headers -#include "scrnintstr.h" -#include "windowstr.h" -#include "colormapst.h" -#include "globals.h" -#include "mi.h" - -// System headers -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <IOKit/pwr_mgt/IOPMLib.h> - -#include <rootlessCommon.h> -#include <Xplugin.h> - -#define FAKE_RANDR 1 - -// Shared global variables for Quartz modes -int quartzEventWriteFD = -1; -int quartzUseSysBeep = 0; -int quartzUseAGL = 1; -int quartzEnableKeyEquivalents = 1; -int quartzServerVisible = FALSE; -int quartzServerQuitting = FALSE; -static int quartzScreenKeyIndex; -DevPrivateKey quartzScreenKey = &quartzScreenKeyIndex; -int aquaMenuBarHeight = 0; -QuartzModeProcsPtr quartzProcs = NULL; -const char *quartzOpenGLBundle = NULL; -int quartzFullscreenDisableHotkeys = TRUE; -int quartzOptionSendsAlt = FALSE; - -#if defined(RANDR) && !defined(FAKE_RANDR) -Bool QuartzRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) { - return FALSE; -} - -Bool QuartzRandRSetConfig (ScreenPtr pScreen, - Rotation randr, - int rate, - RRScreenSizePtr pSize) { - return FALSE; -} - -Bool QuartzRandRInit (ScreenPtr pScreen) { - rrScrPrivPtr pScrPriv; - - if (!RRScreenInit (pScreen)) return FALSE; - - pScrPriv = rrGetScrPriv(pScreen); - pScrPriv->rrGetInfo = QuartzRandRGetInfo; - pScrPriv->rrSetConfig = QuartzRandRSetConfig; - return TRUE; -} -#endif - -/* -=========================================================================== - - Screen functions - -=========================================================================== -*/ - -/* - * QuartzAddScreen - * Do mode dependent initialization of each screen for Quartz. - */ -Bool QuartzAddScreen( - int index, - ScreenPtr pScreen) -{ - // allocate space for private per screen Quartz specific storage - QuartzScreenPtr displayInfo = xcalloc(sizeof(QuartzScreenRec), 1); - - // QUARTZ_PRIV(pScreen) = displayInfo; - dixSetPrivate(&pScreen->devPrivates, quartzScreenKey, displayInfo); - - // do Quartz mode specific initialization - return quartzProcs->AddScreen(index, pScreen); -} - - -/* - * QuartzSetupScreen - * Finalize mode specific setup of each screen. - */ -Bool QuartzSetupScreen( - int index, - ScreenPtr pScreen) -{ - // do Quartz mode specific setup - if (! quartzProcs->SetupScreen(index, pScreen)) - return FALSE; - - // setup cursor support - if (! quartzProcs->InitCursor(pScreen)) - return FALSE; - - return TRUE; -} - - -/* - * QuartzInitOutput - * Quartz display initialization. - */ -void QuartzInitOutput( - int argc, - char **argv ) -{ - if (!RegisterBlockAndWakeupHandlers(QuartzBlockHandler, - QuartzWakeupHandler, - NULL)) - { - FatalError("Could not register block and wakeup handlers."); - } - -#if defined(RANDR) && !defined(FAKE_RANDR) - if(!QuartzRandRInit(pScreen)) - FatalError("Failed to init RandR extension.\n"); -#endif - - // Do display mode specific initialization - quartzProcs->DisplayInit(); -} - - -/* - * QuartzInitInput - * Inform the main thread the X server is ready to handle events. - */ -void QuartzInitInput( - int argc, - char **argv ) -{ - X11ApplicationSetCanQuit(0); - X11ApplicationServerReady(); - // Do final display mode specific initialization before handling events - if (quartzProcs->InitInput) - quartzProcs->InitInput(argc, argv); -} - - -#ifdef FAKE_RANDR - -static const int padlength[4] = {0, 3, 2, 1}; - -static void -RREditConnectionInfo (ScreenPtr pScreen) -{ - xConnSetup *connSetup; - char *vendor; - xPixmapFormat *formats; - xWindowRoot *root; - xDepth *depth; - xVisualType *visual; - int screen = 0; - int d; - - connSetup = (xConnSetup *) ConnectionInfo; - vendor = (char *) connSetup + sizeof (xConnSetup); - formats = (xPixmapFormat *) ((char *) vendor + - connSetup->nbytesVendor + - padlength[connSetup->nbytesVendor & 3]); - root = (xWindowRoot *) ((char *) formats + - sizeof (xPixmapFormat) * screenInfo.numPixmapFormats); - while (screen != pScreen->myNum) - { - depth = (xDepth *) ((char *) root + - sizeof (xWindowRoot)); - for (d = 0; d < root->nDepths; d++) - { - visual = (xVisualType *) ((char *) depth + - sizeof (xDepth)); - depth = (xDepth *) ((char *) visual + - depth->nVisuals * sizeof (xVisualType)); - } - root = (xWindowRoot *) ((char *) depth); - screen++; - } - root->pixWidth = pScreen->width; - root->pixHeight = pScreen->height; - root->mmWidth = pScreen->mmWidth; - root->mmHeight = pScreen->mmHeight; -} -#endif - -void QuartzUpdateScreens(void) { - ScreenPtr pScreen; - WindowPtr pRoot; - int x, y, width, height, sx, sy; - xEvent e; - BoxRec bounds; - - if (noPseudoramiXExtension || screenInfo.numScreens != 1) - { - /* FIXME: if not using Xinerama, we have multiple screens, and - to do this properly may need to add or remove screens. Which - isn't possible. So don't do anything. Another reason why - we default to running with Xinerama. */ - - return; - } - - pScreen = screenInfo.screens[0]; - - PseudoramiXResetScreens(); - quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height); - - dixScreenOrigins[pScreen->myNum].x = x; - dixScreenOrigins[pScreen->myNum].y = y; - pScreen->mmWidth = pScreen->mmWidth * ((double) width / pScreen->width); - pScreen->mmHeight = pScreen->mmHeight * ((double) height / pScreen->height); - pScreen->width = width; - pScreen->height = height; - - DarwinAdjustScreenOrigins(&screenInfo); - quartzProcs->UpdateScreen(pScreen); - - /* DarwinAdjustScreenOrigins or UpdateScreen may change dixScreenOrigins, - * so use it rather than x/y - */ - sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; - sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; - - /* Adjust the root window. */ - pRoot = WindowTable[pScreen->myNum]; - AppleWMSetScreenOrigin(pRoot); - pScreen->ResizeWindow(pRoot, x - sx, y - sy, width, height, NULL); - //pScreen->PaintWindowBackground (pRoot, &pRoot->borderClip, PW_BACKGROUND); - miPaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); - - /* <rdar://problem/7770779> pointer events are clipped to old display region after display reconfiguration - * http://xquartz.macosforge.org/trac/ticket/346 - */ - bounds.x1 = 0; - bounds.x2 = width; - bounds.y1 = 0; - bounds.y2 = height; - pScreen->ConstrainCursor(inputInfo.pointer, pScreen, &bounds); - inputInfo.pointer->spriteInfo->sprite->physLimits = bounds; - inputInfo.pointer->spriteInfo->sprite->hotLimits = bounds; - - DEBUG_LOG("Root Window: %dx%d @ (%d, %d) darwinMainScreen (%d, %d) xy (%d, %d) dixScreenOrigins (%d, %d)\n", width, height, x - sx, y - sy, darwinMainScreenX, darwinMainScreenY, x, y, dixScreenOrigins[pScreen->myNum].x, dixScreenOrigins[pScreen->myNum].y); - - /* Send an event for the root reconfigure */ - e.u.u.type = ConfigureNotify; - e.u.configureNotify.window = pRoot->drawable.id; - e.u.configureNotify.aboveSibling = None; - e.u.configureNotify.x = x - sx; - e.u.configureNotify.y = y - sy; - e.u.configureNotify.width = width; - e.u.configureNotify.height = height; - e.u.configureNotify.borderWidth = wBorderWidth(pRoot); - e.u.configureNotify.override = pRoot->overrideRedirect; - DeliverEvents(pRoot, &e, 1, NullWindow); - -#ifdef FAKE_RANDR - RREditConnectionInfo(pScreen); -#endif -} - -void QuartzSetFullscreen(Bool state) { - - DEBUG_LOG("QuartzSetFullscreen: state=%d\n", state); - - if(quartzHasRoot == state) - return; - - quartzHasRoot = state; - - xp_disable_update (); - - if (!quartzHasRoot && !quartzEnableRootless) - RootlessHideAllWindows(); - - RootlessUpdateRooted(quartzHasRoot); - - if (quartzHasRoot && !quartzEnableRootless) - RootlessShowAllWindows (); - - if (quartzHasRoot || quartzEnableRootless) { - RootlessRepositionWindows(screenInfo.screens[0]); - } - - /* Somehow the menubar manages to interfere with our event stream - * in fullscreen mode, even though it's not visible. - */ - X11ApplicationShowHideMenubar(!quartzHasRoot); - - xp_reenable_update (); - - if (quartzFullscreenDisableHotkeys) - xp_disable_hot_keys(quartzHasRoot); -} - -void QuartzSetRootless(Bool state) { - if(quartzEnableRootless == state) - return; - - quartzEnableRootless = state; - - xp_disable_update(); - - /* When in rootless, the menubar is not part of the screen, so we need to update our screens on toggle */ - QuartzUpdateScreens(); - - if(!quartzHasRoot) { - if(!quartzEnableRootless) { - RootlessHideAllWindows(); - } else { - RootlessShowAllWindows(); - } - } - - X11ApplicationShowHideMenubar(!quartzHasRoot); - - xp_reenable_update(); - - if (!quartzEnableRootless && quartzFullscreenDisableHotkeys) - xp_disable_hot_keys(quartzHasRoot); -} - -/* - * QuartzShow - * Show the X server on screen. Does nothing if already shown. - * Calls mode specific screen resume to restore the X clip regions - * (if needed) and the X server cursor state. - */ -void QuartzShow(void) { - int i; - - if (quartzServerVisible) - return; - - quartzServerVisible = TRUE; - for (i = 0; i < screenInfo.numScreens; i++) { - if (screenInfo.screens[i]) { - quartzProcs->ResumeScreen(screenInfo.screens[i]); - } - } - - if (!quartzEnableRootless) - QuartzSetFullscreen(TRUE); -} - - -/* - * QuartzHide - * Remove the X server display from the screen. Does nothing if already - * hidden. Calls mode specific screen suspend to set X clip regions to - * prevent drawing (if needed) and restore the Aqua cursor. - */ -void QuartzHide(void) -{ - int i; - - if (quartzServerVisible) { - for (i = 0; i < screenInfo.numScreens; i++) { - if (screenInfo.screens[i]) { - quartzProcs->SuspendScreen(screenInfo.screens[i]); - } - } - } - - QuartzSetFullscreen(FALSE); - quartzServerVisible = FALSE; -} - - -/* - * QuartzSetRootClip - * Enable or disable rendering to the X screen. - */ -void QuartzSetRootClip( - BOOL enable) -{ - int i; - - if (!quartzServerVisible) - return; - - for (i = 0; i < screenInfo.numScreens; i++) { - if (screenInfo.screens[i]) { - xf86SetRootClip(screenInfo.screens[i], enable); - } - } -} - -/* - * QuartzSpaceChanged - * Unmap offscreen windows, map onscreen windows - */ -void QuartzSpaceChanged(uint32_t space_id) { - /* Do something special here, so we don't depend on quartz-wm for spaces to work... */ - DEBUG_LOG("Space Changed (%u) ... do something interesting...\n", space_id); -} +/* + * + * Quartz-specific support for the Darwin X Server + * + * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons. + * 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ + +#include "sanitizedCarbon.h" + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "quartzCommon.h" +#include "inputstr.h" +#include "quartz.h" +#include "darwin.h" +#include "darwinEvents.h" +#include "pseudoramiX.h" +#define _APPLEWM_SERVER_ +#include "applewmExt.h" + +#include "X11Application.h" + +#include <X11/extensions/applewmconst.h> +#include <X11/extensions/randr.h> + +// X headers +#include "scrnintstr.h" +#include "windowstr.h" +#include "colormapst.h" +#include "globals.h" +#include "mi.h" + +// System headers +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <IOKit/pwr_mgt/IOPMLib.h> + +#include <rootlessCommon.h> +#include <Xplugin.h> + +#define FAKE_RANDR 1 + +// Shared global variables for Quartz modes +int quartzEventWriteFD = -1; +int quartzUseSysBeep = 0; +int quartzUseAGL = 1; +int quartzEnableKeyEquivalents = 1; +int quartzServerVisible = FALSE; +int quartzServerQuitting = FALSE; +static int quartzScreenKeyIndex; +DevPrivateKey quartzScreenKey = &quartzScreenKeyIndex; +int aquaMenuBarHeight = 0; +QuartzModeProcsPtr quartzProcs = NULL; +const char *quartzOpenGLBundle = NULL; +int quartzFullscreenDisableHotkeys = TRUE; +int quartzOptionSendsAlt = FALSE; + +#if defined(RANDR) && !defined(FAKE_RANDR) +Bool QuartzRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) { + return FALSE; +} + +Bool QuartzRandRSetConfig (ScreenPtr pScreen, + Rotation randr, + int rate, + RRScreenSizePtr pSize) { + return FALSE; +} + +Bool QuartzRandRInit (ScreenPtr pScreen) { + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) return FALSE; + + pScrPriv = rrGetScrPriv(pScreen); + pScrPriv->rrGetInfo = QuartzRandRGetInfo; + pScrPriv->rrSetConfig = QuartzRandRSetConfig; + return TRUE; +} +#endif + +/* +=========================================================================== + + Screen functions + +=========================================================================== +*/ + +/* + * QuartzAddScreen + * Do mode dependent initialization of each screen for Quartz. + */ +Bool QuartzAddScreen( + int index, + ScreenPtr pScreen) +{ + // allocate space for private per screen Quartz specific storage + QuartzScreenPtr displayInfo = calloc(sizeof(QuartzScreenRec), 1); + + // QUARTZ_PRIV(pScreen) = displayInfo; + dixSetPrivate(&pScreen->devPrivates, quartzScreenKey, displayInfo); + + // do Quartz mode specific initialization + return quartzProcs->AddScreen(index, pScreen); +} + + +/* + * QuartzSetupScreen + * Finalize mode specific setup of each screen. + */ +Bool QuartzSetupScreen( + int index, + ScreenPtr pScreen) +{ + // do Quartz mode specific setup + if (! quartzProcs->SetupScreen(index, pScreen)) + return FALSE; + + // setup cursor support + if (! quartzProcs->InitCursor(pScreen)) + return FALSE; + + return TRUE; +} + + +/* + * QuartzInitOutput + * Quartz display initialization. + */ +void QuartzInitOutput( + int argc, + char **argv ) +{ + if (!RegisterBlockAndWakeupHandlers(QuartzBlockHandler, + QuartzWakeupHandler, + NULL)) + { + FatalError("Could not register block and wakeup handlers."); + } + +#if defined(RANDR) && !defined(FAKE_RANDR) + if(!QuartzRandRInit(pScreen)) + FatalError("Failed to init RandR extension.\n"); +#endif + + // Do display mode specific initialization + quartzProcs->DisplayInit(); +} + + +/* + * QuartzInitInput + * Inform the main thread the X server is ready to handle events. + */ +void QuartzInitInput( + int argc, + char **argv ) +{ + X11ApplicationSetCanQuit(0); + X11ApplicationServerReady(); + // Do final display mode specific initialization before handling events + if (quartzProcs->InitInput) + quartzProcs->InitInput(argc, argv); +} + + +#ifdef FAKE_RANDR + +static const int padlength[4] = {0, 3, 2, 1}; + +static void +RREditConnectionInfo (ScreenPtr pScreen) +{ + xConnSetup *connSetup; + char *vendor; + xPixmapFormat *formats; + xWindowRoot *root; + xDepth *depth; + xVisualType *visual; + int screen = 0; + int d; + + connSetup = (xConnSetup *) ConnectionInfo; + vendor = (char *) connSetup + sizeof (xConnSetup); + formats = (xPixmapFormat *) ((char *) vendor + + connSetup->nbytesVendor + + padlength[connSetup->nbytesVendor & 3]); + root = (xWindowRoot *) ((char *) formats + + sizeof (xPixmapFormat) * screenInfo.numPixmapFormats); + while (screen != pScreen->myNum) + { + depth = (xDepth *) ((char *) root + + sizeof (xWindowRoot)); + for (d = 0; d < root->nDepths; d++) + { + visual = (xVisualType *) ((char *) depth + + sizeof (xDepth)); + depth = (xDepth *) ((char *) visual + + depth->nVisuals * sizeof (xVisualType)); + } + root = (xWindowRoot *) ((char *) depth); + screen++; + } + root->pixWidth = pScreen->width; + root->pixHeight = pScreen->height; + root->mmWidth = pScreen->mmWidth; + root->mmHeight = pScreen->mmHeight; +} +#endif + +void QuartzUpdateScreens(void) { + ScreenPtr pScreen; + WindowPtr pRoot; + int x, y, width, height, sx, sy; + xEvent e; + BoxRec bounds; + + if (noPseudoramiXExtension || screenInfo.numScreens != 1) + { + /* FIXME: if not using Xinerama, we have multiple screens, and + to do this properly may need to add or remove screens. Which + isn't possible. So don't do anything. Another reason why + we default to running with Xinerama. */ + + return; + } + + pScreen = screenInfo.screens[0]; + + PseudoramiXResetScreens(); + quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height); + + dixScreenOrigins[pScreen->myNum].x = x; + dixScreenOrigins[pScreen->myNum].y = y; + pScreen->mmWidth = pScreen->mmWidth * ((double) width / pScreen->width); + pScreen->mmHeight = pScreen->mmHeight * ((double) height / pScreen->height); + pScreen->width = width; + pScreen->height = height; + + DarwinAdjustScreenOrigins(&screenInfo); + quartzProcs->UpdateScreen(pScreen); + + /* DarwinAdjustScreenOrigins or UpdateScreen may change dixScreenOrigins, + * so use it rather than x/y + */ + sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + /* Adjust the root window. */ + pRoot = WindowTable[pScreen->myNum]; + AppleWMSetScreenOrigin(pRoot); + pScreen->ResizeWindow(pRoot, x - sx, y - sy, width, height, NULL); + miPaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); + + /* <rdar://problem/7770779> pointer events are clipped to old display region after display reconfiguration + * http://xquartz.macosforge.org/trac/ticket/346 + */ + bounds.x1 = 0; + bounds.x2 = width; + bounds.y1 = 0; + bounds.y2 = height; + pScreen->ConstrainCursor(inputInfo.pointer, pScreen, &bounds); + inputInfo.pointer->spriteInfo->sprite->physLimits = bounds; + inputInfo.pointer->spriteInfo->sprite->hotLimits = bounds; + + DEBUG_LOG("Root Window: %dx%d @ (%d, %d) darwinMainScreen (%d, %d) xy (%d, %d) dixScreenOrigins (%d, %d)\n", width, height, x - sx, y - sy, darwinMainScreenX, darwinMainScreenY, x, y, dixScreenOrigins[pScreen->myNum].x, dixScreenOrigins[pScreen->myNum].y); + + /* Send an event for the root reconfigure */ + e.u.u.type = ConfigureNotify; + e.u.configureNotify.window = pRoot->drawable.id; + e.u.configureNotify.aboveSibling = None; + e.u.configureNotify.x = x - sx; + e.u.configureNotify.y = y - sy; + e.u.configureNotify.width = width; + e.u.configureNotify.height = height; + e.u.configureNotify.borderWidth = wBorderWidth(pRoot); + e.u.configureNotify.override = pRoot->overrideRedirect; + DeliverEvents(pRoot, &e, 1, NullWindow); + +#ifdef FAKE_RANDR + RREditConnectionInfo(pScreen); +#endif +} + +void QuartzSetFullscreen(Bool state) { + + DEBUG_LOG("QuartzSetFullscreen: state=%d\n", state); + + if(quartzHasRoot == state) + return; + + quartzHasRoot = state; + + xp_disable_update (); + + if (!quartzHasRoot && !quartzEnableRootless) + RootlessHideAllWindows(); + + RootlessUpdateRooted(quartzHasRoot); + + if (quartzHasRoot && !quartzEnableRootless) + RootlessShowAllWindows (); + + if (quartzHasRoot || quartzEnableRootless) { + RootlessRepositionWindows(screenInfo.screens[0]); + } + + /* Somehow the menubar manages to interfere with our event stream + * in fullscreen mode, even though it's not visible. + */ + X11ApplicationShowHideMenubar(!quartzHasRoot); + + xp_reenable_update (); + + if (quartzFullscreenDisableHotkeys) + xp_disable_hot_keys(quartzHasRoot); +} + +void QuartzSetRootless(Bool state) { + if(quartzEnableRootless == state) + return; + + quartzEnableRootless = state; + + xp_disable_update(); + + /* When in rootless, the menubar is not part of the screen, so we need to update our screens on toggle */ + QuartzUpdateScreens(); + + if(!quartzHasRoot) { + if(!quartzEnableRootless) { + RootlessHideAllWindows(); + } else { + RootlessShowAllWindows(); + } + } + + X11ApplicationShowHideMenubar(!quartzHasRoot); + + xp_reenable_update(); + + if (!quartzEnableRootless && quartzFullscreenDisableHotkeys) + xp_disable_hot_keys(quartzHasRoot); +} + +/* + * QuartzShow + * Show the X server on screen. Does nothing if already shown. + * Calls mode specific screen resume to restore the X clip regions + * (if needed) and the X server cursor state. + */ +void QuartzShow(void) { + int i; + + if (quartzServerVisible) + return; + + quartzServerVisible = TRUE; + for (i = 0; i < screenInfo.numScreens; i++) { + if (screenInfo.screens[i]) { + quartzProcs->ResumeScreen(screenInfo.screens[i]); + } + } + + if (!quartzEnableRootless) + QuartzSetFullscreen(TRUE); +} + + +/* + * QuartzHide + * Remove the X server display from the screen. Does nothing if already + * hidden. Calls mode specific screen suspend to set X clip regions to + * prevent drawing (if needed) and restore the Aqua cursor. + */ +void QuartzHide(void) +{ + int i; + + if (quartzServerVisible) { + for (i = 0; i < screenInfo.numScreens; i++) { + if (screenInfo.screens[i]) { + quartzProcs->SuspendScreen(screenInfo.screens[i]); + } + } + } + + QuartzSetFullscreen(FALSE); + quartzServerVisible = FALSE; +} + + +/* + * QuartzSetRootClip + * Enable or disable rendering to the X screen. + */ +void QuartzSetRootClip( + BOOL enable) +{ + int i; + + if (!quartzServerVisible) + return; + + for (i = 0; i < screenInfo.numScreens; i++) { + if (screenInfo.screens[i]) { + xf86SetRootClip(screenInfo.screens[i], enable); + } + } +} + +/* + * QuartzSpaceChanged + * Unmap offscreen windows, map onscreen windows + */ +void QuartzSpaceChanged(uint32_t space_id) { + /* Do something special here, so we don't depend on quartz-wm for spaces to work... */ + DEBUG_LOG("Space Changed (%u) ... do something interesting...\n", space_id); +} diff --git a/xorg-server/hw/xquartz/xpr/appledri.c b/xorg-server/hw/xquartz/xpr/appledri.c index 74a4ec315..87cb9016a 100644 --- a/xorg-server/hw/xquartz/xpr/appledri.c +++ b/xorg-server/hw/xquartz/xpr/appledri.c @@ -1,429 +1,429 @@ -/************************************************************************** - -Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. -Copyright 2000 VA Linux Systems, Inc. -Copyright (c) 2002, 2009 Apple Computer, 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, sub license, 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 NON-INFRINGEMENT. -IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. - -**************************************************************************/ - -/* - * Authors: - * Kevin E. Martin <martin@valinux.com> - * Jens Owen <jens@valinux.com> - * Rickard E. (Rik) Faith <faith@valinux.com> - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "servermd.h" -#define _APPLEDRI_SERVER_ -#include "appledristr.h" -#include "swaprep.h" -#include "dri.h" -#include "dristruct.h" -#include "xpr.h" -#include "x-hash.h" -#include "protocol-versions.h" - -static int DRIErrorBase = 0; - -static DISPATCH_PROC(ProcAppleDRIDispatch); -static DISPATCH_PROC(SProcAppleDRIDispatch); - -static void AppleDRIResetProc(ExtensionEntry* extEntry); -static int ProcAppleDRICreatePixmap(ClientPtr client); - -static unsigned char DRIReqCode = 0; -static int DRIEventBase = 0; - -static void SNotifyEvent(xAppleDRINotifyEvent *from, xAppleDRINotifyEvent *to); - -typedef struct _DRIEvent *DRIEventPtr; -typedef struct _DRIEvent { - DRIEventPtr next; - ClientPtr client; - XID clientResource; - unsigned int mask; -} DRIEventRec; - - -void -AppleDRIExtensionInit(void) -{ - ExtensionEntry* extEntry; - - if (DRIExtensionInit() && - (extEntry = AddExtension(APPLEDRINAME, - AppleDRINumberEvents, - AppleDRINumberErrors, - ProcAppleDRIDispatch, - SProcAppleDRIDispatch, - AppleDRIResetProc, - StandardMinorOpcode))) { - DRIReqCode = (unsigned char)extEntry->base; - DRIErrorBase = extEntry->errorBase; - DRIEventBase = extEntry->eventBase; - EventSwapVector[DRIEventBase] = (EventSwapPtr) SNotifyEvent; - } -} - -/*ARGSUSED*/ -static void -AppleDRIResetProc ( - ExtensionEntry* extEntry -) -{ - DRIReset(); -} - -static int -ProcAppleDRIQueryVersion( - register ClientPtr client -) -{ - xAppleDRIQueryVersionReply rep; - register int n; - - REQUEST_SIZE_MATCH(xAppleDRIQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_APPLEDRI_MAJOR_VERSION; - rep.minorVersion = SERVER_APPLEDRI_MINOR_VERSION; - rep.patchVersion = SERVER_APPLEDRI_PATCH_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - } - WriteToClient(client, sizeof(xAppleDRIQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - - -/* surfaces */ - -static int -ProcAppleDRIQueryDirectRenderingCapable( - register ClientPtr client -) -{ - xAppleDRIQueryDirectRenderingCapableReply rep; - Bool isCapable; - - REQUEST(xAppleDRIQueryDirectRenderingCapableReq); - REQUEST_SIZE_MATCH(xAppleDRIQueryDirectRenderingCapableReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if (!DRIQueryDirectRenderingCapable( screenInfo.screens[stuff->screen], - &isCapable)) { - return BadValue; - } - rep.isCapable = isCapable; - - if (!LocalClient(client)) - rep.isCapable = 0; - - WriteToClient(client, - sizeof(xAppleDRIQueryDirectRenderingCapableReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcAppleDRIAuthConnection( - register ClientPtr client -) -{ - xAppleDRIAuthConnectionReply rep; - - REQUEST(xAppleDRIAuthConnectionReq); - REQUEST_SIZE_MATCH(xAppleDRIAuthConnectionReq); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.authenticated = 1; - - if (!DRIAuthConnection( screenInfo.screens[stuff->screen], stuff->magic)) { - ErrorF("Failed to authenticate %u\n", (unsigned int)stuff->magic); - rep.authenticated = 0; - } - WriteToClient(client, sizeof(xAppleDRIAuthConnectionReply), (char *)&rep); - return (client->noClientException); -} - -static void surface_notify( - void *_arg, - void *data -) -{ - DRISurfaceNotifyArg *arg = _arg; - int client_index = (int) x_cvt_vptr_to_uint(data); - ClientPtr client; - xAppleDRINotifyEvent se; - - if (client_index < 0 || client_index >= currentMaxClients) - return; - - client = clients[client_index]; - if (client == NULL || client == serverClient || client->clientGone) - return; - - se.type = DRIEventBase + AppleDRISurfaceNotify; - se.kind = arg->kind; - se.arg = arg->id; - se.sequenceNumber = client->sequence; - se.time = currentTime.milliseconds; - WriteEventsToClient (client, 1, (xEvent *) &se); -} - -static int -ProcAppleDRICreateSurface( - ClientPtr client -) -{ - xAppleDRICreateSurfaceReply rep; - DrawablePtr pDrawable; - xp_surface_id sid; - unsigned int key[2]; - int rc; - - REQUEST(xAppleDRICreateSurfaceReq); - REQUEST_SIZE_MATCH(xAppleDRICreateSurfaceReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - rep.key_0 = rep.key_1 = rep.uid = 0; - - if (!DRICreateSurface( screenInfo.screens[stuff->screen], - (Drawable)stuff->drawable, pDrawable, - stuff->client_id, &sid, key, - surface_notify, - x_cvt_uint_to_vptr(client->index))) { - return BadValue; - } - - rep.key_0 = key[0]; - rep.key_1 = key[1]; - rep.uid = sid; - - WriteToClient(client, sizeof(xAppleDRICreateSurfaceReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcAppleDRIDestroySurface( - register ClientPtr client -) -{ - int rc; - REQUEST(xAppleDRIDestroySurfaceReq); - DrawablePtr pDrawable; - REQUEST_SIZE_MATCH(xAppleDRIDestroySurfaceReq); - - rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - if (!DRIDestroySurface( screenInfo.screens[stuff->screen], - (Drawable)stuff->drawable, - pDrawable, NULL, NULL)) { - return BadValue; - } - - return (client->noClientException); -} - -static int -ProcAppleDRICreatePixmap(ClientPtr client) -{ - REQUEST(xAppleDRICreatePixmapReq); - DrawablePtr pDrawable; - int rc; - char path[PATH_MAX]; - xAppleDRICreatePixmapReply rep; - int width, height, pitch, bpp; - void *ptr; - - REQUEST_SIZE_MATCH(xAppleDRICreatePixmapReq); - - rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, - DixReadAccess); - - if(rc != Success) - return rc; - - if(!DRICreatePixmap(screenInfo.screens[stuff->screen], - (Drawable)stuff->drawable, - pDrawable, - path, PATH_MAX)) { - return BadValue; - } - - if(!DRIGetPixmapData(pDrawable, &width, &height, - &pitch, &bpp, &ptr)) { - return BadValue; - } - - rep.stringLength = strlen(path) + 1; - - /* No need for swapping, because this only runs if LocalClient is true. */ - rep.type = X_Reply; - rep.length = sizeof(rep) + rep.stringLength; - rep.sequenceNumber = client->sequence; - rep.width = width; - rep.height = height; - rep.pitch = pitch; - rep.bpp = bpp; - rep.size = pitch * height; - - if(sizeof(rep) != sz_xAppleDRICreatePixmapReply) - ErrorF("error sizeof(rep) is %zu\n", sizeof(rep)); - - WriteReplyToClient(client, sizeof(rep), &rep); - (void)WriteToClient(client, rep.stringLength, path); - - return (client->noClientException); -} - -static int -ProcAppleDRIDestroyPixmap(ClientPtr client) -{ - DrawablePtr pDrawable; - int rc; - REQUEST(xAppleDRIDestroyPixmapReq); - REQUEST_SIZE_MATCH(xAppleDRIDestroyPixmapReq); - - rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, - DixReadAccess); - - if(rc != Success) - return rc; - - DRIDestroyPixmap(pDrawable); - - return (client->noClientException); -} - -/* dispatch */ - -static int -ProcAppleDRIDispatch ( - register ClientPtr client -) -{ - REQUEST(xReq); - - switch (stuff->data) - { - case X_AppleDRIQueryVersion: - return ProcAppleDRIQueryVersion(client); - case X_AppleDRIQueryDirectRenderingCapable: - return ProcAppleDRIQueryDirectRenderingCapable(client); - } - - if (!LocalClient(client)) - return DRIErrorBase + AppleDRIClientNotLocal; - - switch (stuff->data) - { - case X_AppleDRIAuthConnection: - return ProcAppleDRIAuthConnection(client); - case X_AppleDRICreateSurface: - return ProcAppleDRICreateSurface(client); - case X_AppleDRIDestroySurface: - return ProcAppleDRIDestroySurface(client); - case X_AppleDRICreatePixmap: - return ProcAppleDRICreatePixmap(client); - case X_AppleDRIDestroyPixmap: - return ProcAppleDRIDestroyPixmap(client); - - default: - return BadRequest; - } -} - -static void -SNotifyEvent( - xAppleDRINotifyEvent *from, - xAppleDRINotifyEvent *to -) -{ - to->type = from->type; - to->kind = from->kind; - cpswaps (from->sequenceNumber, to->sequenceNumber); - cpswapl (from->time, to->time); - cpswapl (from->arg, to->arg); -} - -static int -SProcAppleDRIQueryVersion( - register ClientPtr client -) -{ - register int n; - REQUEST(xAppleDRIQueryVersionReq); - swaps(&stuff->length, n); - return ProcAppleDRIQueryVersion(client); -} - -static int -SProcAppleDRIDispatch ( - register ClientPtr client -) -{ - REQUEST(xReq); - - /* It is bound to be non-local when there is byte swapping */ - if (!LocalClient(client)) - return DRIErrorBase + AppleDRIClientNotLocal; - - /* only local clients are allowed DRI access */ - switch (stuff->data) - { - case X_AppleDRIQueryVersion: - return SProcAppleDRIQueryVersion(client); - default: - return BadRequest; - } -} +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +Copyright (c) 2002, 2009 Apple Computer, 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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Jens Owen <jens@valinux.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "servermd.h" +#define _APPLEDRI_SERVER_ +#include "appledristr.h" +#include "swaprep.h" +#include "dri.h" +#include "dristruct.h" +#include "xpr.h" +#include "x-hash.h" +#include "protocol-versions.h" + +static int DRIErrorBase = 0; + +static DISPATCH_PROC(ProcAppleDRIDispatch); +static DISPATCH_PROC(SProcAppleDRIDispatch); + +static void AppleDRIResetProc(ExtensionEntry* extEntry); +static int ProcAppleDRICreatePixmap(ClientPtr client); + +static unsigned char DRIReqCode = 0; +static int DRIEventBase = 0; + +static void SNotifyEvent(xAppleDRINotifyEvent *from, xAppleDRINotifyEvent *to); + +typedef struct _DRIEvent *DRIEventPtr; +typedef struct _DRIEvent { + DRIEventPtr next; + ClientPtr client; + XID clientResource; + unsigned int mask; +} DRIEventRec; + + +void +AppleDRIExtensionInit(void) +{ + ExtensionEntry* extEntry; + + if (DRIExtensionInit() && + (extEntry = AddExtension(APPLEDRINAME, + AppleDRINumberEvents, + AppleDRINumberErrors, + ProcAppleDRIDispatch, + SProcAppleDRIDispatch, + AppleDRIResetProc, + StandardMinorOpcode))) { + DRIReqCode = (unsigned char)extEntry->base; + DRIErrorBase = extEntry->errorBase; + DRIEventBase = extEntry->eventBase; + EventSwapVector[DRIEventBase] = (EventSwapPtr) SNotifyEvent; + } +} + +/*ARGSUSED*/ +static void +AppleDRIResetProc ( + ExtensionEntry* extEntry +) +{ + DRIReset(); +} + +static int +ProcAppleDRIQueryVersion( + register ClientPtr client +) +{ + xAppleDRIQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH(xAppleDRIQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_APPLEDRI_MAJOR_VERSION; + rep.minorVersion = SERVER_APPLEDRI_MINOR_VERSION; + rep.patchVersion = SERVER_APPLEDRI_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + WriteToClient(client, sizeof(xAppleDRIQueryVersionReply), (char *)&rep); + return Success; +} + + +/* surfaces */ + +static int +ProcAppleDRIQueryDirectRenderingCapable( + register ClientPtr client +) +{ + xAppleDRIQueryDirectRenderingCapableReply rep; + Bool isCapable; + + REQUEST(xAppleDRIQueryDirectRenderingCapableReq); + REQUEST_SIZE_MATCH(xAppleDRIQueryDirectRenderingCapableReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!DRIQueryDirectRenderingCapable( screenInfo.screens[stuff->screen], + &isCapable)) { + return BadValue; + } + rep.isCapable = isCapable; + + if (!LocalClient(client)) + rep.isCapable = 0; + + WriteToClient(client, + sizeof(xAppleDRIQueryDirectRenderingCapableReply), (char *)&rep); + return Success; +} + +static int +ProcAppleDRIAuthConnection( + register ClientPtr client +) +{ + xAppleDRIAuthConnectionReply rep; + + REQUEST(xAppleDRIAuthConnectionReq); + REQUEST_SIZE_MATCH(xAppleDRIAuthConnectionReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.authenticated = 1; + + if (!DRIAuthConnection( screenInfo.screens[stuff->screen], stuff->magic)) { + ErrorF("Failed to authenticate %u\n", (unsigned int)stuff->magic); + rep.authenticated = 0; + } + WriteToClient(client, sizeof(xAppleDRIAuthConnectionReply), (char *)&rep); + return Success; +} + +static void surface_notify( + void *_arg, + void *data +) +{ + DRISurfaceNotifyArg *arg = _arg; + int client_index = (int) x_cvt_vptr_to_uint(data); + ClientPtr client; + xAppleDRINotifyEvent se; + + if (client_index < 0 || client_index >= currentMaxClients) + return; + + client = clients[client_index]; + if (client == NULL || client == serverClient || client->clientGone) + return; + + se.type = DRIEventBase + AppleDRISurfaceNotify; + se.kind = arg->kind; + se.arg = arg->id; + se.sequenceNumber = client->sequence; + se.time = currentTime.milliseconds; + WriteEventsToClient (client, 1, (xEvent *) &se); +} + +static int +ProcAppleDRICreateSurface( + ClientPtr client +) +{ + xAppleDRICreateSurfaceReply rep; + DrawablePtr pDrawable; + xp_surface_id sid; + unsigned int key[2]; + int rc; + + REQUEST(xAppleDRICreateSurfaceReq); + REQUEST_SIZE_MATCH(xAppleDRICreateSurfaceReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + rep.key_0 = rep.key_1 = rep.uid = 0; + + if (!DRICreateSurface( screenInfo.screens[stuff->screen], + (Drawable)stuff->drawable, pDrawable, + stuff->client_id, &sid, key, + surface_notify, + x_cvt_uint_to_vptr(client->index))) { + return BadValue; + } + + rep.key_0 = key[0]; + rep.key_1 = key[1]; + rep.uid = sid; + + WriteToClient(client, sizeof(xAppleDRICreateSurfaceReply), (char *)&rep); + return Success; +} + +static int +ProcAppleDRIDestroySurface( + register ClientPtr client +) +{ + int rc; + REQUEST(xAppleDRIDestroySurfaceReq); + DrawablePtr pDrawable; + REQUEST_SIZE_MATCH(xAppleDRIDestroySurfaceReq); + + rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + if (!DRIDestroySurface( screenInfo.screens[stuff->screen], + (Drawable)stuff->drawable, + pDrawable, NULL, NULL)) { + return BadValue; + } + + return Success; +} + +static int +ProcAppleDRICreatePixmap(ClientPtr client) +{ + REQUEST(xAppleDRICreatePixmapReq); + DrawablePtr pDrawable; + int rc; + char path[PATH_MAX]; + xAppleDRICreatePixmapReply rep; + int width, height, pitch, bpp; + void *ptr; + + REQUEST_SIZE_MATCH(xAppleDRICreatePixmapReq); + + rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixReadAccess); + + if(rc != Success) + return rc; + + if(!DRICreatePixmap(screenInfo.screens[stuff->screen], + (Drawable)stuff->drawable, + pDrawable, + path, PATH_MAX)) { + return BadValue; + } + + if(!DRIGetPixmapData(pDrawable, &width, &height, + &pitch, &bpp, &ptr)) { + return BadValue; + } + + rep.stringLength = strlen(path) + 1; + + /* No need for swapping, because this only runs if LocalClient is true. */ + rep.type = X_Reply; + rep.length = sizeof(rep) + rep.stringLength; + rep.sequenceNumber = client->sequence; + rep.width = width; + rep.height = height; + rep.pitch = pitch; + rep.bpp = bpp; + rep.size = pitch * height; + + if(sizeof(rep) != sz_xAppleDRICreatePixmapReply) + ErrorF("error sizeof(rep) is %zu\n", sizeof(rep)); + + WriteReplyToClient(client, sizeof(rep), &rep); + (void)WriteToClient(client, rep.stringLength, path); + + return Success; +} + +static int +ProcAppleDRIDestroyPixmap(ClientPtr client) +{ + DrawablePtr pDrawable; + int rc; + REQUEST(xAppleDRIDestroyPixmapReq); + REQUEST_SIZE_MATCH(xAppleDRIDestroyPixmapReq); + + rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixReadAccess); + + if(rc != Success) + return rc; + + DRIDestroyPixmap(pDrawable); + + return Success; +} + +/* dispatch */ + +static int +ProcAppleDRIDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_AppleDRIQueryVersion: + return ProcAppleDRIQueryVersion(client); + case X_AppleDRIQueryDirectRenderingCapable: + return ProcAppleDRIQueryDirectRenderingCapable(client); + } + + if (!LocalClient(client)) + return DRIErrorBase + AppleDRIClientNotLocal; + + switch (stuff->data) + { + case X_AppleDRIAuthConnection: + return ProcAppleDRIAuthConnection(client); + case X_AppleDRICreateSurface: + return ProcAppleDRICreateSurface(client); + case X_AppleDRIDestroySurface: + return ProcAppleDRIDestroySurface(client); + case X_AppleDRICreatePixmap: + return ProcAppleDRICreatePixmap(client); + case X_AppleDRIDestroyPixmap: + return ProcAppleDRIDestroyPixmap(client); + + default: + return BadRequest; + } +} + +static void +SNotifyEvent( + xAppleDRINotifyEvent *from, + xAppleDRINotifyEvent *to +) +{ + to->type = from->type; + to->kind = from->kind; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->time, to->time); + cpswapl (from->arg, to->arg); +} + +static int +SProcAppleDRIQueryVersion( + register ClientPtr client +) +{ + register int n; + REQUEST(xAppleDRIQueryVersionReq); + swaps(&stuff->length, n); + return ProcAppleDRIQueryVersion(client); +} + +static int +SProcAppleDRIDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + /* It is bound to be non-local when there is byte swapping */ + if (!LocalClient(client)) + return DRIErrorBase + AppleDRIClientNotLocal; + + /* only local clients are allowed DRI access */ + switch (stuff->data) + { + case X_AppleDRIQueryVersion: + return SProcAppleDRIQueryVersion(client); + default: + return BadRequest; + } +} diff --git a/xorg-server/hw/xquartz/xpr/dri.c b/xorg-server/hw/xquartz/xpr/dri.c index 0a58b29f3..363809d0d 100644 --- a/xorg-server/hw/xquartz/xpr/dri.c +++ b/xorg-server/hw/xquartz/xpr/dri.c @@ -1,953 +1,953 @@ -/************************************************************************** - -Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. -Copyright 2000 VA Linux Systems, Inc. -Copyright (c) 2002, 2009 Apple Computer, 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, sub license, 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 NON-INFRINGEMENT. -IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. - -**************************************************************************/ - -/* - * Authors: - * Jens Owen <jens@valinux.com> - * Rickard E. (Rik) Faith <faith@valinux.com> - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#ifdef XFree86LOADER -#include "xf86.h" -#include "xf86_ansic.h" -#else -#include <sys/time.h> -#include <unistd.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "misc.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "windowstr.h" -#include "servermd.h" -#define _APPLEDRI_SERVER_ -#include "appledristr.h" -#include "swaprep.h" -#include "dri.h" -#include "dristruct.h" -#include "mi.h" -#include "mipointer.h" -#include "rootless.h" -#include "x-hash.h" -#include "x-hook.h" -#include "driWrap.h" - -#include <AvailabilityMacros.h> - -static int DRIScreenPrivKeyIndex; -static DevPrivateKey DRIScreenPrivKey = &DRIScreenPrivKeyIndex; -static int DRIWindowPrivKeyIndex; -static DevPrivateKey DRIWindowPrivKey = &DRIWindowPrivKeyIndex; -static int DRIPixmapPrivKeyIndex; -static DevPrivateKey DRIPixmapPrivKey = &DRIPixmapPrivKeyIndex; -static int DRIPixmapBufferPrivKeyIndex; -static DevPrivateKey DRIPixmapBufferPrivKey = &DRIPixmapBufferPrivKeyIndex; - -static RESTYPE DRIDrawablePrivResType; - -static x_hash_table *surface_hash; /* maps surface ids -> drawablePrivs */ - -static Bool DRIFreePixmapImp(DrawablePtr pDrawable); - -/* FIXME: don't hardcode this? */ -#define CG_INFO_FILE "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/Info-macos.plist" - -/* Corresponds to SU Jaguar Green */ -#define CG_REQUIRED_MAJOR 1 -#define CG_REQUIRED_MINOR 157 -#define CG_REQUIRED_MICRO 11 - -typedef struct { - DrawablePtr pDrawable; - int refCount; - int bytesPerPixel; - int width; - int height; - char shmPath[PATH_MAX]; - int fd; /* From shm_open (for now) */ - size_t length; /* length of buffer */ - void *buffer; -} DRIPixmapBuffer, *DRIPixmapBufferPtr; - -/* Returns version as major.minor.micro in 10.10.10 fixed form */ -static unsigned int -get_cg_version (void) -{ - static unsigned int version; - - FILE *fh; - char *ptr; - - if (version != 0) - return version; - - /* I tried CFBundleGetVersion, but it returns zero, so.. */ - - fh = fopen (CG_INFO_FILE, "r"); - if (fh != NULL) - { - char buf[256]; - - while (fgets (buf, sizeof (buf), fh) != NULL) - { - unsigned char c; - - if (!strstr (buf, "<key>CFBundleShortVersionString</key>") - || fgets (buf, sizeof (buf), fh) == NULL) - { - continue; - } - - ptr = strstr (buf, "<string>"); - if (ptr == NULL) - continue; - - ptr += strlen ("<string>"); - - /* Now PTR points to "MAJOR.MINOR.MICRO". */ - - version = 0; - - again: - switch ((c = *ptr++)) - { - case '.': - version = version * 1024; - goto again; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - version = ((version & ~0x3ff) - + (version & 0x3ff) * 10 + (c - '0')); - goto again; - } - break; - } - - fclose (fh); - } - - return version; -} - -static Bool -test_cg_version (unsigned int major, unsigned int minor, unsigned int micro) -{ - unsigned int cg_ver = get_cg_version (); - - unsigned int cg_major = (cg_ver >> 20) & 0x3ff; - unsigned int cg_minor = (cg_ver >> 10) & 0x3ff; - unsigned int cg_micro = cg_ver & 0x3ff; - - if (cg_major > major) - return TRUE; - else if (cg_major < major) - return FALSE; - - /* cg_major == major */ - - if (cg_minor > minor) - return TRUE; - else if (cg_minor < minor) - return FALSE; - - /* cg_minor == minor */ - - if (cg_micro < micro) - return FALSE; - - return TRUE; -} - -Bool -DRIScreenInit(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv; - int i; - - pDRIPriv = (DRIScreenPrivPtr) xcalloc(1, sizeof(DRIScreenPrivRec)); - if (!pDRIPriv) { - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - return FALSE; - } - - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, pDRIPriv); - pDRIPriv->directRenderingSupport = TRUE; - pDRIPriv->nrWindows = 0; - - /* Need recent cg for window access update */ - if (!test_cg_version (CG_REQUIRED_MAJOR, - CG_REQUIRED_MINOR, - CG_REQUIRED_MICRO)) - { - ErrorF ("[DRI] disabled direct rendering; requires CoreGraphics %d.%d.%d\n", - CG_REQUIRED_MAJOR, CG_REQUIRED_MINOR, CG_REQUIRED_MICRO); - - pDRIPriv->directRenderingSupport = FALSE; - - /* Note we don't nuke the dri private, since we need it for - managing indirect surfaces. */ - } - - /* Initialize drawable tables */ - for (i = 0; i < DRI_MAX_DRAWABLES; i++) { - pDRIPriv->DRIDrawables[i] = NULL; - } - - return TRUE; -} - -Bool -DRIFinishScreenInit(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - /* Wrap DRI support */ - pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; - pScreen->ValidateTree = DRIValidateTree; - - pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; - pScreen->PostValidateTree = DRIPostValidateTree; - - pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; - pScreen->WindowExposures = DRIWindowExposures; - - pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; - pScreen->CopyWindow = DRICopyWindow; - - pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; - pScreen->ClipNotify = DRIClipNotify; - - // ErrorF("[DRI] screen %d installation complete\n", pScreen->myNum); - - return DRIWrapInit(pScreen); -} - -void -DRICloseScreen(ScreenPtr pScreen) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIPriv && pDRIPriv->directRenderingSupport) { - xfree(pDRIPriv); - dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); - } -} - -Bool -DRIExtensionInit(void) -{ - DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete, - "DRIDrawable"); - - return (DRIDrawablePrivResType != 0); -} - -void -DRIReset(void) -{ - /* - * This stub routine is called when the X Server recycles, resources - * allocated by DRIExtensionInit need to be managed here. - * - * Currently this routine is a stub because all the interesting resources - * are managed via the screen init process. - */ -} - -Bool -DRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool* isCapable) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIPriv) - *isCapable = pDRIPriv->directRenderingSupport; - else - *isCapable = FALSE; - - return TRUE; -} - -Bool -DRIAuthConnection(ScreenPtr pScreen, unsigned int magic) -{ -#if 0 - /* FIXME: something? */ - - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (drmAuthMagic(pDRIPriv->drmFD, magic)) return FALSE; -#endif - return TRUE; -} - -static void -DRIUpdateSurface(DRIDrawablePrivPtr pDRIDrawablePriv, DrawablePtr pDraw) -{ - xp_window_changes wc; - unsigned int flags = 0; - - if (pDRIDrawablePriv->sid == 0) - return; - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 - wc.depth = (pDraw->bitsPerPixel == 32 ? XP_DEPTH_ARGB8888 - : pDraw->bitsPerPixel == 16 ? XP_DEPTH_RGB555 : XP_DEPTH_NIL); - if (wc.depth != XP_DEPTH_NIL) - flags |= XP_DEPTH; -#endif - - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr) pDraw; - WindowPtr pTopWin = TopLevelParent(pWin); - - wc.x = pWin->drawable.x - (pTopWin->drawable.x - pTopWin->borderWidth); - wc.y = pWin->drawable.y - (pTopWin->drawable.y - pTopWin->borderWidth); - wc.width = pWin->drawable.width + 2 * pWin->borderWidth; - wc.height = pWin->drawable.height + 2 * pWin->borderWidth; - wc.bit_gravity = XP_GRAVITY_NONE; - - wc.shape_nrects = REGION_NUM_RECTS(&pWin->clipList); - wc.shape_rects = REGION_RECTS(&pWin->clipList); - wc.shape_tx = - (pTopWin->drawable.x - pTopWin->borderWidth); - wc.shape_ty = - (pTopWin->drawable.y - pTopWin->borderWidth); - - flags |= XP_BOUNDS | XP_SHAPE; - - } else if (pDraw->type == DRAWABLE_PIXMAP) { - wc.x = 0; - wc.y = 0; - wc.width = pDraw->width; - wc.height = pDraw->height; - wc.bit_gravity = XP_GRAVITY_NONE; - flags |= XP_BOUNDS; - } - - xp_configure_surface(pDRIDrawablePriv->sid, flags, &wc); -} - -/* Return NULL if an error occurs. */ -static DRIDrawablePrivPtr -CreateSurfaceForWindow(ScreenPtr pScreen, WindowPtr pWin, xp_window_id *widPtr) { - DRIDrawablePrivPtr pDRIDrawablePriv; - xp_window_id wid = 0; - - *widPtr = 0; - - pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - - if (pDRIDrawablePriv == NULL) { - xp_error err; - xp_window_changes wc; - - /* allocate a DRI Window Private record */ - if (!(pDRIDrawablePriv = xalloc(sizeof(*pDRIDrawablePriv)))) { - return NULL; - } - - pDRIDrawablePriv->pDraw = (DrawablePtr)pWin; - pDRIDrawablePriv->pScreen = pScreen; - pDRIDrawablePriv->refCount = 0; - pDRIDrawablePriv->drawableIndex = -1; - pDRIDrawablePriv->notifiers = NULL; - - /* find the physical window */ - wid = x_cvt_vptr_to_uint(RootlessFrameForWindow(pWin, TRUE)); - - if (wid == 0) { - xfree(pDRIDrawablePriv); - return NULL; - } - - /* allocate the physical surface */ - err = xp_create_surface(wid, &pDRIDrawablePriv->sid); - - if (err != Success) { - xfree(pDRIDrawablePriv); - return NULL; - } - - /* Make it visible */ - wc.stack_mode = XP_MAPPED_ABOVE; - wc.sibling = 0; - err = xp_configure_surface(pDRIDrawablePriv->sid, XP_STACKING, &wc); - - if (err != Success) { - xp_destroy_surface(pDRIDrawablePriv->sid); - xfree(pDRIDrawablePriv); - return NULL; - } - - /* save private off of preallocated index */ - dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, - pDRIDrawablePriv); - } - - *widPtr = wid; - - return pDRIDrawablePriv; -} - -/* Return NULL if an error occurs. */ -static DRIDrawablePrivPtr -CreateSurfaceForPixmap(ScreenPtr pScreen, PixmapPtr pPix) { - DRIDrawablePrivPtr pDRIDrawablePriv; - - pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_PIXMAP(pPix); - - if (pDRIDrawablePriv == NULL) { - xp_error err; - - /* allocate a DRI Window Private record */ - if (!(pDRIDrawablePriv = xcalloc(1, sizeof(*pDRIDrawablePriv)))) { - return NULL; - } - - pDRIDrawablePriv->pDraw = (DrawablePtr)pPix; - pDRIDrawablePriv->pScreen = pScreen; - pDRIDrawablePriv->refCount = 0; - pDRIDrawablePriv->drawableIndex = -1; - pDRIDrawablePriv->notifiers = NULL; - - /* Passing a null window id to Xplugin in 10.3+ asks for - an accelerated offscreen surface. */ - - err = xp_create_surface(0, &pDRIDrawablePriv->sid); - if (err != Success) { - xfree(pDRIDrawablePriv); - return NULL; - } - - /* - * The DRIUpdateSurface will be called to resize the surface - * after this function, if the export is successful. - */ - - /* save private off of preallocated index */ - dixSetPrivate(&pPix->devPrivates, DRIPixmapPrivKey, - pDRIDrawablePriv); - } - - return pDRIDrawablePriv; -} - - -Bool -DRICreateSurface(ScreenPtr pScreen, Drawable id, - DrawablePtr pDrawable, xp_client_id client_id, - xp_surface_id *surface_id, unsigned int ret_key[2], - void (*notify) (void *arg, void *data), void *notify_data) -{ - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - xp_window_id wid = 0; - DRIDrawablePrivPtr pDRIDrawablePriv; - - if (pDrawable->type == DRAWABLE_WINDOW) { - pDRIDrawablePriv = CreateSurfaceForWindow(pScreen, - (WindowPtr)pDrawable, &wid); - - if(NULL == pDRIDrawablePriv) - return FALSE; /*error*/ - } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 - else if (pDrawable->type == DRAWABLE_PIXMAP) { - pDRIDrawablePriv = CreateSurfaceForPixmap(pScreen, - (PixmapPtr)pDrawable); - - if(NULL == pDRIDrawablePriv) - return FALSE; /*error*/ - } -#endif - else { /* for GLX 1.3, a PBuffer */ - /* NOT_DONE */ - return FALSE; - } - - - /* Finish initialization of new surfaces */ - if (pDRIDrawablePriv->refCount == 0) { - unsigned int key[2] = {0}; - xp_error err; - - /* try to give the client access to the surface */ - if (client_id != 0) { - /* - * Xplugin accepts a 0 wid if the surface id is offscreen, such - * as for a pixmap. - */ - err = xp_export_surface(wid, pDRIDrawablePriv->sid, - client_id, key); - if (err != Success) { - xp_destroy_surface(pDRIDrawablePriv->sid); - xfree(pDRIDrawablePriv); - - /* - * Now set the dix privates to NULL that were previously set. - * This prevents reusing an invalid pointer. - */ - if(pDrawable->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDrawable; - - dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL); - } else if(pDrawable->type == DRAWABLE_PIXMAP) { - PixmapPtr pPix = (PixmapPtr)pDrawable; - - dixSetPrivate(&pPix->devPrivates, DRIPixmapPrivKey, NULL); - } - - return FALSE; - } - } - - pDRIDrawablePriv->key[0] = key[0]; - pDRIDrawablePriv->key[1] = key[1]; - - ++pDRIPriv->nrWindows; - - /* and stash it by surface id */ - if (surface_hash == NULL) - surface_hash = x_hash_table_new(NULL, NULL, NULL, NULL); - x_hash_table_insert(surface_hash, - x_cvt_uint_to_vptr(pDRIDrawablePriv->sid), pDRIDrawablePriv); - - /* track this in case this window is destroyed */ - AddResource(id, DRIDrawablePrivResType, (pointer)pDrawable); - - /* Initialize shape */ - DRIUpdateSurface(pDRIDrawablePriv, pDrawable); - } - - pDRIDrawablePriv->refCount++; - - *surface_id = pDRIDrawablePriv->sid; - - if (ret_key != NULL) { - ret_key[0] = pDRIDrawablePriv->key[0]; - ret_key[1] = pDRIDrawablePriv->key[1]; - } - - if (notify != NULL) { - pDRIDrawablePriv->notifiers = x_hook_add(pDRIDrawablePriv->notifiers, - notify, notify_data); - } - - return TRUE; -} - -Bool -DRIDestroySurface(ScreenPtr pScreen, Drawable id, DrawablePtr pDrawable, - void (*notify) (void *, void *), void *notify_data) -{ - DRIDrawablePrivPtr pDRIDrawablePriv; - - if (pDrawable->type == DRAWABLE_WINDOW) { - pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW((WindowPtr)pDrawable); - } else if (pDrawable->type == DRAWABLE_PIXMAP) { - pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_PIXMAP((PixmapPtr)pDrawable); - } else { - return FALSE; - } - - if (pDRIDrawablePriv != NULL) { - if (notify != NULL) { - pDRIDrawablePriv->notifiers = x_hook_remove(pDRIDrawablePriv->notifiers, - notify, notify_data); - } - if (--pDRIDrawablePriv->refCount <= 0) { - /* This calls back to DRIDrawablePrivDelete - which frees the private area */ - FreeResourceByType(id, DRIDrawablePrivResType, FALSE); - } - } - - return TRUE; -} - -Bool -DRIDrawablePrivDelete(pointer pResource, XID id) -{ - DrawablePtr pDrawable = (DrawablePtr)pResource; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pDrawable->pScreen); - DRIDrawablePrivPtr pDRIDrawablePriv = NULL; - WindowPtr pWin = NULL; - PixmapPtr pPix = NULL; - - if (pDrawable->type == DRAWABLE_WINDOW) { - pWin = (WindowPtr)pDrawable; - pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - } else if (pDrawable->type == DRAWABLE_PIXMAP) { - pPix = (PixmapPtr)pDrawable; - pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_PIXMAP(pPix); - } - - if (pDRIDrawablePriv == NULL) { - return DRIFreePixmapImp(pDrawable); - } - - if (pDRIDrawablePriv->drawableIndex != -1) { - /* release drawable table entry */ - pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL; - } - - if (pDRIDrawablePriv->sid != 0) { - xp_destroy_surface(pDRIDrawablePriv->sid); - x_hash_table_remove(surface_hash, x_cvt_uint_to_vptr(pDRIDrawablePriv->sid)); - } - - if (pDRIDrawablePriv->notifiers != NULL) - x_hook_free(pDRIDrawablePriv->notifiers); - - xfree(pDRIDrawablePriv); - - if (pDrawable->type == DRAWABLE_WINDOW) { - dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL); - } else if (pDrawable->type == DRAWABLE_PIXMAP) { - dixSetPrivate(&pPix->devPrivates, DRIPixmapPrivKey, NULL); - } - - --pDRIPriv->nrWindows; - - return TRUE; -} - -void -DRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - - if (pDRIDrawablePriv) { - /* FIXME: something? */ - } - - pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures; - - (*pScreen->WindowExposures)(pWin, prgn, bsreg); - - pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; - pScreen->WindowExposures = DRIWindowExposures; -} - -void -DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIDrawablePrivPtr pDRIDrawablePriv; - - if (pDRIPriv->nrWindows > 0) { - pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); - if (pDRIDrawablePriv != NULL) { - DRIUpdateSurface(pDRIDrawablePriv, &pWin->drawable); - } - } - - /* unwrap */ - pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow; - - /* call lower layers */ - (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); - - /* rewrap */ - pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; - pScreen->CopyWindow = DRICopyWindow; -} - -int -DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) -{ - ScreenPtr pScreen = pParent->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - int returnValue; - - /* unwrap */ - pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree; - - /* call lower layers */ - returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind); - - /* rewrap */ - pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; - pScreen->ValidateTree = DRIValidateTree; - - return returnValue; -} - -void -DRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) -{ - ScreenPtr pScreen; - DRIScreenPrivPtr pDRIPriv; - - if (pParent) { - pScreen = pParent->drawable.pScreen; - } else { - pScreen = pChild->drawable.pScreen; - } - pDRIPriv = DRI_SCREEN_PRIV(pScreen); - - if (pDRIPriv->wrap.PostValidateTree) { - /* unwrap */ - pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree; - - /* call lower layers */ - (*pScreen->PostValidateTree)(pParent, pChild, kind); - - /* rewrap */ - pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; - pScreen->PostValidateTree = DRIPostValidateTree; - } -} - -void -DRIClipNotify(WindowPtr pWin, int dx, int dy) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); - DRIDrawablePrivPtr pDRIDrawablePriv; - - if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { - DRIUpdateSurface(pDRIDrawablePriv, &pWin->drawable); - } - - if (pDRIPriv->wrap.ClipNotify) { - pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify; - - (*pScreen->ClipNotify)(pWin, dx, dy); - - pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; - pScreen->ClipNotify = DRIClipNotify; - } -} - -/* This lets us get at the unwrapped functions so that they can correctly - * call the lower level functions, and choose whether they will be - * called at every level of recursion (eg in validatetree). - */ -DRIWrappedFuncsRec * -DRIGetWrappedFuncs(ScreenPtr pScreen) -{ - return &(DRI_SCREEN_PRIV(pScreen)->wrap); -} - -void -DRIQueryVersion(int *majorVersion, - int *minorVersion, - int *patchVersion) -{ - *majorVersion = APPLE_DRI_MAJOR_VERSION; - *minorVersion = APPLE_DRI_MINOR_VERSION; - *patchVersion = APPLE_DRI_PATCH_VERSION; -} - -void -DRISurfaceNotify(xp_surface_id id, int kind) -{ - DRIDrawablePrivPtr pDRIDrawablePriv = NULL; - DRISurfaceNotifyArg arg; - - arg.id = id; - arg.kind = kind; - - if (surface_hash != NULL) - { - pDRIDrawablePriv = x_hash_table_lookup(surface_hash, - x_cvt_uint_to_vptr(id), NULL); - } - - if (pDRIDrawablePriv == NULL) - return; - - if (kind == AppleDRISurfaceNotifyDestroyed) - { - pDRIDrawablePriv->sid = 0; - x_hash_table_remove(surface_hash, x_cvt_uint_to_vptr(id)); - } - - x_hook_run(pDRIDrawablePriv->notifiers, &arg); - - if (kind == AppleDRISurfaceNotifyDestroyed) - { - /* Kill off the handle. */ - - FreeResourceByType(pDRIDrawablePriv->pDraw->id, - DRIDrawablePrivResType, FALSE); - } -} - -Bool DRICreatePixmap(ScreenPtr pScreen, Drawable id, - DrawablePtr pDrawable, char *path, - size_t pathmax) -{ - DRIPixmapBufferPtr shared; - PixmapPtr pPix; - - if(pDrawable->type != DRAWABLE_PIXMAP) - return FALSE; - - pPix = (PixmapPtr)pDrawable; - - shared = xalloc(sizeof(*shared)); - if(NULL == shared) { - FatalError("failed to allocate DRIPixmapBuffer in %s\n", __func__); - } - - shared->pDrawable = pDrawable; - shared->refCount = 1; - - if(pDrawable->bitsPerPixel >= 24) { - shared->bytesPerPixel = 4; - } else if(pDrawable->bitsPerPixel <= 16) { - shared->bytesPerPixel = 2; - } - - shared->width = pDrawable->width; - shared->height = pDrawable->height; - - if(-1 == snprintf(shared->shmPath, sizeof(shared->shmPath), - "%d_0x%lx", getpid(), - (unsigned long)id)) { - FatalError("buffer overflow in %s\n", __func__); - } - - shared->fd = shm_open(shared->shmPath, - O_RDWR | O_EXCL | O_CREAT, - S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH); - - if(-1 == shared->fd) { - xfree(shared); - return FALSE; - } - - shared->length = shared->width * shared->height * shared->bytesPerPixel; - - if(-1 == ftruncate(shared->fd, shared->length)) { - ErrorF("failed to ftruncate (extend) file."); - shm_unlink(shared->shmPath); - close(shared->fd); - xfree(shared); - return FALSE; - } - - shared->buffer = mmap(NULL, shared->length, - PROT_READ | PROT_WRITE, - MAP_FILE | MAP_SHARED, shared->fd, 0); - - if(MAP_FAILED == shared->buffer) { - ErrorF("failed to mmap shared memory."); - shm_unlink(shared->shmPath); - close(shared->fd); - xfree(shared); - return FALSE; - } - - strncpy(path, shared->shmPath, pathmax); - path[pathmax - 1] = '\0'; - - dixSetPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey, shared); - - AddResource(id, DRIDrawablePrivResType, (pointer)pDrawable); - - return TRUE; -} - - -Bool DRIGetPixmapData(DrawablePtr pDrawable, int *width, int *height, - int *pitch, int *bpp, void **ptr) { - PixmapPtr pPix; - DRIPixmapBufferPtr shared; - - if(pDrawable->type != DRAWABLE_PIXMAP) - return FALSE; - - pPix = (PixmapPtr)pDrawable; - - shared = dixLookupPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey); - - if(NULL == shared) - return FALSE; - - assert(pDrawable->width == shared->width); - assert(pDrawable->height == shared->height); - - *width = shared->width; - *height = shared->height; - *bpp = shared->bytesPerPixel; - *pitch = shared->width * shared->bytesPerPixel; - *ptr = shared->buffer; - - return TRUE; -} - -static Bool -DRIFreePixmapImp(DrawablePtr pDrawable) { - DRIPixmapBufferPtr shared; - PixmapPtr pPix; - - if(pDrawable->type != DRAWABLE_PIXMAP) - return FALSE; - - pPix = (PixmapPtr)pDrawable; - - shared = dixLookupPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey); - - if(NULL == shared) - return FALSE; - - close(shared->fd); - munmap(shared->buffer, shared->length); - shm_unlink(shared->shmPath); - xfree(shared); - - dixSetPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey, (pointer)NULL); - - return TRUE; -} - -void -DRIDestroyPixmap(DrawablePtr pDrawable) { - if(DRIFreePixmapImp(pDrawable)) - FreeResourceByType(pDrawable->id, DRIDrawablePrivResType, FALSE); - -} +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +Copyright (c) 2002, 2009 Apple Computer, 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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/* + * Authors: + * Jens Owen <jens@valinux.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef XFree86LOADER +#include "xf86.h" +#include "xf86_ansic.h" +#else +#include <sys/time.h> +#include <unistd.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "misc.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "servermd.h" +#define _APPLEDRI_SERVER_ +#include "appledristr.h" +#include "swaprep.h" +#include "dri.h" +#include "dristruct.h" +#include "mi.h" +#include "mipointer.h" +#include "rootless.h" +#include "x-hash.h" +#include "x-hook.h" +#include "driWrap.h" + +#include <AvailabilityMacros.h> + +static int DRIScreenPrivKeyIndex; +static DevPrivateKey DRIScreenPrivKey = &DRIScreenPrivKeyIndex; +static int DRIWindowPrivKeyIndex; +static DevPrivateKey DRIWindowPrivKey = &DRIWindowPrivKeyIndex; +static int DRIPixmapPrivKeyIndex; +static DevPrivateKey DRIPixmapPrivKey = &DRIPixmapPrivKeyIndex; +static int DRIPixmapBufferPrivKeyIndex; +static DevPrivateKey DRIPixmapBufferPrivKey = &DRIPixmapBufferPrivKeyIndex; + +static RESTYPE DRIDrawablePrivResType; + +static x_hash_table *surface_hash; /* maps surface ids -> drawablePrivs */ + +static Bool DRIFreePixmapImp(DrawablePtr pDrawable); + +/* FIXME: don't hardcode this? */ +#define CG_INFO_FILE "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/Info-macos.plist" + +/* Corresponds to SU Jaguar Green */ +#define CG_REQUIRED_MAJOR 1 +#define CG_REQUIRED_MINOR 157 +#define CG_REQUIRED_MICRO 11 + +typedef struct { + DrawablePtr pDrawable; + int refCount; + int bytesPerPixel; + int width; + int height; + char shmPath[PATH_MAX]; + int fd; /* From shm_open (for now) */ + size_t length; /* length of buffer */ + void *buffer; +} DRIPixmapBuffer, *DRIPixmapBufferPtr; + +/* Returns version as major.minor.micro in 10.10.10 fixed form */ +static unsigned int +get_cg_version (void) +{ + static unsigned int version; + + FILE *fh; + char *ptr; + + if (version != 0) + return version; + + /* I tried CFBundleGetVersion, but it returns zero, so.. */ + + fh = fopen (CG_INFO_FILE, "r"); + if (fh != NULL) + { + char buf[256]; + + while (fgets (buf, sizeof (buf), fh) != NULL) + { + unsigned char c; + + if (!strstr (buf, "<key>CFBundleShortVersionString</key>") + || fgets (buf, sizeof (buf), fh) == NULL) + { + continue; + } + + ptr = strstr (buf, "<string>"); + if (ptr == NULL) + continue; + + ptr += strlen ("<string>"); + + /* Now PTR points to "MAJOR.MINOR.MICRO". */ + + version = 0; + + again: + switch ((c = *ptr++)) + { + case '.': + version = version * 1024; + goto again; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + version = ((version & ~0x3ff) + + (version & 0x3ff) * 10 + (c - '0')); + goto again; + } + break; + } + + fclose (fh); + } + + return version; +} + +static Bool +test_cg_version (unsigned int major, unsigned int minor, unsigned int micro) +{ + unsigned int cg_ver = get_cg_version (); + + unsigned int cg_major = (cg_ver >> 20) & 0x3ff; + unsigned int cg_minor = (cg_ver >> 10) & 0x3ff; + unsigned int cg_micro = cg_ver & 0x3ff; + + if (cg_major > major) + return TRUE; + else if (cg_major < major) + return FALSE; + + /* cg_major == major */ + + if (cg_minor > minor) + return TRUE; + else if (cg_minor < minor) + return FALSE; + + /* cg_minor == minor */ + + if (cg_micro < micro) + return FALSE; + + return TRUE; +} + +Bool +DRIScreenInit(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv; + int i; + + pDRIPriv = (DRIScreenPrivPtr) calloc(1, sizeof(DRIScreenPrivRec)); + if (!pDRIPriv) { + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + return FALSE; + } + + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, pDRIPriv); + pDRIPriv->directRenderingSupport = TRUE; + pDRIPriv->nrWindows = 0; + + /* Need recent cg for window access update */ + if (!test_cg_version (CG_REQUIRED_MAJOR, + CG_REQUIRED_MINOR, + CG_REQUIRED_MICRO)) + { + ErrorF ("[DRI] disabled direct rendering; requires CoreGraphics %d.%d.%d\n", + CG_REQUIRED_MAJOR, CG_REQUIRED_MINOR, CG_REQUIRED_MICRO); + + pDRIPriv->directRenderingSupport = FALSE; + + /* Note we don't nuke the dri private, since we need it for + managing indirect surfaces. */ + } + + /* Initialize drawable tables */ + for (i = 0; i < DRI_MAX_DRAWABLES; i++) { + pDRIPriv->DRIDrawables[i] = NULL; + } + + return TRUE; +} + +Bool +DRIFinishScreenInit(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + /* Wrap DRI support */ + pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; + pScreen->ValidateTree = DRIValidateTree; + + pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; + pScreen->PostValidateTree = DRIPostValidateTree; + + pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; + pScreen->WindowExposures = DRIWindowExposures; + + pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; + pScreen->CopyWindow = DRICopyWindow; + + pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; + pScreen->ClipNotify = DRIClipNotify; + + // ErrorF("[DRI] screen %d installation complete\n", pScreen->myNum); + + return DRIWrapInit(pScreen); +} + +void +DRICloseScreen(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv && pDRIPriv->directRenderingSupport) { + free(pDRIPriv); + dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL); + } +} + +Bool +DRIExtensionInit(void) +{ + DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete, + "DRIDrawable"); + + return (DRIDrawablePrivResType != 0); +} + +void +DRIReset(void) +{ + /* + * This stub routine is called when the X Server recycles, resources + * allocated by DRIExtensionInit need to be managed here. + * + * Currently this routine is a stub because all the interesting resources + * are managed via the screen init process. + */ +} + +Bool +DRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool* isCapable) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv) + *isCapable = pDRIPriv->directRenderingSupport; + else + *isCapable = FALSE; + + return TRUE; +} + +Bool +DRIAuthConnection(ScreenPtr pScreen, unsigned int magic) +{ +#if 0 + /* FIXME: something? */ + + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (drmAuthMagic(pDRIPriv->drmFD, magic)) return FALSE; +#endif + return TRUE; +} + +static void +DRIUpdateSurface(DRIDrawablePrivPtr pDRIDrawablePriv, DrawablePtr pDraw) +{ + xp_window_changes wc; + unsigned int flags = 0; + + if (pDRIDrawablePriv->sid == 0) + return; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 + wc.depth = (pDraw->bitsPerPixel == 32 ? XP_DEPTH_ARGB8888 + : pDraw->bitsPerPixel == 16 ? XP_DEPTH_RGB555 : XP_DEPTH_NIL); + if (wc.depth != XP_DEPTH_NIL) + flags |= XP_DEPTH; +#endif + + if (pDraw->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr) pDraw; + WindowPtr pTopWin = TopLevelParent(pWin); + + wc.x = pWin->drawable.x - (pTopWin->drawable.x - pTopWin->borderWidth); + wc.y = pWin->drawable.y - (pTopWin->drawable.y - pTopWin->borderWidth); + wc.width = pWin->drawable.width + 2 * pWin->borderWidth; + wc.height = pWin->drawable.height + 2 * pWin->borderWidth; + wc.bit_gravity = XP_GRAVITY_NONE; + + wc.shape_nrects = REGION_NUM_RECTS(&pWin->clipList); + wc.shape_rects = REGION_RECTS(&pWin->clipList); + wc.shape_tx = - (pTopWin->drawable.x - pTopWin->borderWidth); + wc.shape_ty = - (pTopWin->drawable.y - pTopWin->borderWidth); + + flags |= XP_BOUNDS | XP_SHAPE; + + } else if (pDraw->type == DRAWABLE_PIXMAP) { + wc.x = 0; + wc.y = 0; + wc.width = pDraw->width; + wc.height = pDraw->height; + wc.bit_gravity = XP_GRAVITY_NONE; + flags |= XP_BOUNDS; + } + + xp_configure_surface(pDRIDrawablePriv->sid, flags, &wc); +} + +/* Return NULL if an error occurs. */ +static DRIDrawablePrivPtr +CreateSurfaceForWindow(ScreenPtr pScreen, WindowPtr pWin, xp_window_id *widPtr) { + DRIDrawablePrivPtr pDRIDrawablePriv; + xp_window_id wid = 0; + + *widPtr = 0; + + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + + if (pDRIDrawablePriv == NULL) { + xp_error err; + xp_window_changes wc; + + /* allocate a DRI Window Private record */ + if (!(pDRIDrawablePriv = malloc(sizeof(*pDRIDrawablePriv)))) { + return NULL; + } + + pDRIDrawablePriv->pDraw = (DrawablePtr)pWin; + pDRIDrawablePriv->pScreen = pScreen; + pDRIDrawablePriv->refCount = 0; + pDRIDrawablePriv->drawableIndex = -1; + pDRIDrawablePriv->notifiers = NULL; + + /* find the physical window */ + wid = x_cvt_vptr_to_uint(RootlessFrameForWindow(pWin, TRUE)); + + if (wid == 0) { + free(pDRIDrawablePriv); + return NULL; + } + + /* allocate the physical surface */ + err = xp_create_surface(wid, &pDRIDrawablePriv->sid); + + if (err != Success) { + free(pDRIDrawablePriv); + return NULL; + } + + /* Make it visible */ + wc.stack_mode = XP_MAPPED_ABOVE; + wc.sibling = 0; + err = xp_configure_surface(pDRIDrawablePriv->sid, XP_STACKING, &wc); + + if (err != Success) { + xp_destroy_surface(pDRIDrawablePriv->sid); + free(pDRIDrawablePriv); + return NULL; + } + + /* save private off of preallocated index */ + dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, + pDRIDrawablePriv); + } + + *widPtr = wid; + + return pDRIDrawablePriv; +} + +/* Return NULL if an error occurs. */ +static DRIDrawablePrivPtr +CreateSurfaceForPixmap(ScreenPtr pScreen, PixmapPtr pPix) { + DRIDrawablePrivPtr pDRIDrawablePriv; + + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_PIXMAP(pPix); + + if (pDRIDrawablePriv == NULL) { + xp_error err; + + /* allocate a DRI Window Private record */ + if (!(pDRIDrawablePriv = calloc(1, sizeof(*pDRIDrawablePriv)))) { + return NULL; + } + + pDRIDrawablePriv->pDraw = (DrawablePtr)pPix; + pDRIDrawablePriv->pScreen = pScreen; + pDRIDrawablePriv->refCount = 0; + pDRIDrawablePriv->drawableIndex = -1; + pDRIDrawablePriv->notifiers = NULL; + + /* Passing a null window id to Xplugin in 10.3+ asks for + an accelerated offscreen surface. */ + + err = xp_create_surface(0, &pDRIDrawablePriv->sid); + if (err != Success) { + free(pDRIDrawablePriv); + return NULL; + } + + /* + * The DRIUpdateSurface will be called to resize the surface + * after this function, if the export is successful. + */ + + /* save private off of preallocated index */ + dixSetPrivate(&pPix->devPrivates, DRIPixmapPrivKey, + pDRIDrawablePriv); + } + + return pDRIDrawablePriv; +} + + +Bool +DRICreateSurface(ScreenPtr pScreen, Drawable id, + DrawablePtr pDrawable, xp_client_id client_id, + xp_surface_id *surface_id, unsigned int ret_key[2], + void (*notify) (void *arg, void *data), void *notify_data) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + xp_window_id wid = 0; + DRIDrawablePrivPtr pDRIDrawablePriv; + + if (pDrawable->type == DRAWABLE_WINDOW) { + pDRIDrawablePriv = CreateSurfaceForWindow(pScreen, + (WindowPtr)pDrawable, &wid); + + if(NULL == pDRIDrawablePriv) + return FALSE; /*error*/ + } +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 + else if (pDrawable->type == DRAWABLE_PIXMAP) { + pDRIDrawablePriv = CreateSurfaceForPixmap(pScreen, + (PixmapPtr)pDrawable); + + if(NULL == pDRIDrawablePriv) + return FALSE; /*error*/ + } +#endif + else { /* for GLX 1.3, a PBuffer */ + /* NOT_DONE */ + return FALSE; + } + + + /* Finish initialization of new surfaces */ + if (pDRIDrawablePriv->refCount == 0) { + unsigned int key[2] = {0}; + xp_error err; + + /* try to give the client access to the surface */ + if (client_id != 0) { + /* + * Xplugin accepts a 0 wid if the surface id is offscreen, such + * as for a pixmap. + */ + err = xp_export_surface(wid, pDRIDrawablePriv->sid, + client_id, key); + if (err != Success) { + xp_destroy_surface(pDRIDrawablePriv->sid); + free(pDRIDrawablePriv); + + /* + * Now set the dix privates to NULL that were previously set. + * This prevents reusing an invalid pointer. + */ + if(pDrawable->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDrawable; + + dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL); + } else if(pDrawable->type == DRAWABLE_PIXMAP) { + PixmapPtr pPix = (PixmapPtr)pDrawable; + + dixSetPrivate(&pPix->devPrivates, DRIPixmapPrivKey, NULL); + } + + return FALSE; + } + } + + pDRIDrawablePriv->key[0] = key[0]; + pDRIDrawablePriv->key[1] = key[1]; + + ++pDRIPriv->nrWindows; + + /* and stash it by surface id */ + if (surface_hash == NULL) + surface_hash = x_hash_table_new(NULL, NULL, NULL, NULL); + x_hash_table_insert(surface_hash, + x_cvt_uint_to_vptr(pDRIDrawablePriv->sid), pDRIDrawablePriv); + + /* track this in case this window is destroyed */ + AddResource(id, DRIDrawablePrivResType, (pointer)pDrawable); + + /* Initialize shape */ + DRIUpdateSurface(pDRIDrawablePriv, pDrawable); + } + + pDRIDrawablePriv->refCount++; + + *surface_id = pDRIDrawablePriv->sid; + + if (ret_key != NULL) { + ret_key[0] = pDRIDrawablePriv->key[0]; + ret_key[1] = pDRIDrawablePriv->key[1]; + } + + if (notify != NULL) { + pDRIDrawablePriv->notifiers = x_hook_add(pDRIDrawablePriv->notifiers, + notify, notify_data); + } + + return TRUE; +} + +Bool +DRIDestroySurface(ScreenPtr pScreen, Drawable id, DrawablePtr pDrawable, + void (*notify) (void *, void *), void *notify_data) +{ + DRIDrawablePrivPtr pDRIDrawablePriv; + + if (pDrawable->type == DRAWABLE_WINDOW) { + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW((WindowPtr)pDrawable); + } else if (pDrawable->type == DRAWABLE_PIXMAP) { + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_PIXMAP((PixmapPtr)pDrawable); + } else { + return FALSE; + } + + if (pDRIDrawablePriv != NULL) { + if (notify != NULL) { + pDRIDrawablePriv->notifiers = x_hook_remove(pDRIDrawablePriv->notifiers, + notify, notify_data); + } + if (--pDRIDrawablePriv->refCount <= 0) { + /* This calls back to DRIDrawablePrivDelete + which frees the private area */ + FreeResourceByType(id, DRIDrawablePrivResType, FALSE); + } + } + + return TRUE; +} + +Bool +DRIDrawablePrivDelete(pointer pResource, XID id) +{ + DrawablePtr pDrawable = (DrawablePtr)pResource; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pDrawable->pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv = NULL; + WindowPtr pWin = NULL; + PixmapPtr pPix = NULL; + + if (pDrawable->type == DRAWABLE_WINDOW) { + pWin = (WindowPtr)pDrawable; + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + } else if (pDrawable->type == DRAWABLE_PIXMAP) { + pPix = (PixmapPtr)pDrawable; + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_PIXMAP(pPix); + } + + if (pDRIDrawablePriv == NULL) { + return DRIFreePixmapImp(pDrawable); + } + + if (pDRIDrawablePriv->drawableIndex != -1) { + /* release drawable table entry */ + pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL; + } + + if (pDRIDrawablePriv->sid != 0) { + xp_destroy_surface(pDRIDrawablePriv->sid); + x_hash_table_remove(surface_hash, x_cvt_uint_to_vptr(pDRIDrawablePriv->sid)); + } + + if (pDRIDrawablePriv->notifiers != NULL) + x_hook_free(pDRIDrawablePriv->notifiers); + + free(pDRIDrawablePriv); + + if (pDrawable->type == DRAWABLE_WINDOW) { + dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL); + } else if (pDrawable->type == DRAWABLE_PIXMAP) { + dixSetPrivate(&pPix->devPrivates, DRIPixmapPrivKey, NULL); + } + + --pDRIPriv->nrWindows; + + return TRUE; +} + +void +DRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + + if (pDRIDrawablePriv) { + /* FIXME: something? */ + } + + pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures; + + (*pScreen->WindowExposures)(pWin, prgn, bsreg); + + pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; + pScreen->WindowExposures = DRIWindowExposures; +} + +void +DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv; + + if (pDRIPriv->nrWindows > 0) { + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + if (pDRIDrawablePriv != NULL) { + DRIUpdateSurface(pDRIDrawablePriv, &pWin->drawable); + } + } + + /* unwrap */ + pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow; + + /* call lower layers */ + (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); + + /* rewrap */ + pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; + pScreen->CopyWindow = DRICopyWindow; +} + +int +DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + ScreenPtr pScreen = pParent->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + int returnValue; + + /* unwrap */ + pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree; + + /* call lower layers */ + returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind); + + /* rewrap */ + pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; + pScreen->ValidateTree = DRIValidateTree; + + return returnValue; +} + +void +DRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + ScreenPtr pScreen; + DRIScreenPrivPtr pDRIPriv; + + if (pParent) { + pScreen = pParent->drawable.pScreen; + } else { + pScreen = pChild->drawable.pScreen; + } + pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv->wrap.PostValidateTree) { + /* unwrap */ + pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree; + + /* call lower layers */ + (*pScreen->PostValidateTree)(pParent, pChild, kind); + + /* rewrap */ + pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; + pScreen->PostValidateTree = DRIPostValidateTree; + } +} + +void +DRIClipNotify(WindowPtr pWin, int dx, int dy) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv; + + if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { + DRIUpdateSurface(pDRIDrawablePriv, &pWin->drawable); + } + + if (pDRIPriv->wrap.ClipNotify) { + pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify; + + (*pScreen->ClipNotify)(pWin, dx, dy); + + pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; + pScreen->ClipNotify = DRIClipNotify; + } +} + +/* This lets us get at the unwrapped functions so that they can correctly + * call the lower level functions, and choose whether they will be + * called at every level of recursion (eg in validatetree). + */ +DRIWrappedFuncsRec * +DRIGetWrappedFuncs(ScreenPtr pScreen) +{ + return &(DRI_SCREEN_PRIV(pScreen)->wrap); +} + +void +DRIQueryVersion(int *majorVersion, + int *minorVersion, + int *patchVersion) +{ + *majorVersion = APPLE_DRI_MAJOR_VERSION; + *minorVersion = APPLE_DRI_MINOR_VERSION; + *patchVersion = APPLE_DRI_PATCH_VERSION; +} + +void +DRISurfaceNotify(xp_surface_id id, int kind) +{ + DRIDrawablePrivPtr pDRIDrawablePriv = NULL; + DRISurfaceNotifyArg arg; + + arg.id = id; + arg.kind = kind; + + if (surface_hash != NULL) + { + pDRIDrawablePriv = x_hash_table_lookup(surface_hash, + x_cvt_uint_to_vptr(id), NULL); + } + + if (pDRIDrawablePriv == NULL) + return; + + if (kind == AppleDRISurfaceNotifyDestroyed) + { + pDRIDrawablePriv->sid = 0; + x_hash_table_remove(surface_hash, x_cvt_uint_to_vptr(id)); + } + + x_hook_run(pDRIDrawablePriv->notifiers, &arg); + + if (kind == AppleDRISurfaceNotifyDestroyed) + { + /* Kill off the handle. */ + + FreeResourceByType(pDRIDrawablePriv->pDraw->id, + DRIDrawablePrivResType, FALSE); + } +} + +Bool DRICreatePixmap(ScreenPtr pScreen, Drawable id, + DrawablePtr pDrawable, char *path, + size_t pathmax) +{ + DRIPixmapBufferPtr shared; + PixmapPtr pPix; + + if(pDrawable->type != DRAWABLE_PIXMAP) + return FALSE; + + pPix = (PixmapPtr)pDrawable; + + shared = malloc(sizeof(*shared)); + if(NULL == shared) { + FatalError("failed to allocate DRIPixmapBuffer in %s\n", __func__); + } + + shared->pDrawable = pDrawable; + shared->refCount = 1; + + if(pDrawable->bitsPerPixel >= 24) { + shared->bytesPerPixel = 4; + } else if(pDrawable->bitsPerPixel <= 16) { + shared->bytesPerPixel = 2; + } + + shared->width = pDrawable->width; + shared->height = pDrawable->height; + + if(-1 == snprintf(shared->shmPath, sizeof(shared->shmPath), + "%d_0x%lx", getpid(), + (unsigned long)id)) { + FatalError("buffer overflow in %s\n", __func__); + } + + shared->fd = shm_open(shared->shmPath, + O_RDWR | O_EXCL | O_CREAT, + S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH); + + if(-1 == shared->fd) { + free(shared); + return FALSE; + } + + shared->length = shared->width * shared->height * shared->bytesPerPixel; + + if(-1 == ftruncate(shared->fd, shared->length)) { + ErrorF("failed to ftruncate (extend) file."); + shm_unlink(shared->shmPath); + close(shared->fd); + free(shared); + return FALSE; + } + + shared->buffer = mmap(NULL, shared->length, + PROT_READ | PROT_WRITE, + MAP_FILE | MAP_SHARED, shared->fd, 0); + + if(MAP_FAILED == shared->buffer) { + ErrorF("failed to mmap shared memory."); + shm_unlink(shared->shmPath); + close(shared->fd); + free(shared); + return FALSE; + } + + strncpy(path, shared->shmPath, pathmax); + path[pathmax - 1] = '\0'; + + dixSetPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey, shared); + + AddResource(id, DRIDrawablePrivResType, (pointer)pDrawable); + + return TRUE; +} + + +Bool DRIGetPixmapData(DrawablePtr pDrawable, int *width, int *height, + int *pitch, int *bpp, void **ptr) { + PixmapPtr pPix; + DRIPixmapBufferPtr shared; + + if(pDrawable->type != DRAWABLE_PIXMAP) + return FALSE; + + pPix = (PixmapPtr)pDrawable; + + shared = dixLookupPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey); + + if(NULL == shared) + return FALSE; + + assert(pDrawable->width == shared->width); + assert(pDrawable->height == shared->height); + + *width = shared->width; + *height = shared->height; + *bpp = shared->bytesPerPixel; + *pitch = shared->width * shared->bytesPerPixel; + *ptr = shared->buffer; + + return TRUE; +} + +static Bool +DRIFreePixmapImp(DrawablePtr pDrawable) { + DRIPixmapBufferPtr shared; + PixmapPtr pPix; + + if(pDrawable->type != DRAWABLE_PIXMAP) + return FALSE; + + pPix = (PixmapPtr)pDrawable; + + shared = dixLookupPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey); + + if(NULL == shared) + return FALSE; + + close(shared->fd); + munmap(shared->buffer, shared->length); + shm_unlink(shared->shmPath); + free(shared); + + dixSetPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey, (pointer)NULL); + + return TRUE; +} + +void +DRIDestroyPixmap(DrawablePtr pDrawable) { + if(DRIFreePixmapImp(pDrawable)) + FreeResourceByType(pDrawable->id, DRIDrawablePrivResType, FALSE); + +} diff --git a/xorg-server/hw/xquartz/xpr/driWrap.c b/xorg-server/hw/xquartz/xpr/driWrap.c index 8c57fd4bd..2e23cbbf5 100644 --- a/xorg-server/hw/xquartz/xpr/driWrap.c +++ b/xorg-server/hw/xquartz/xpr/driWrap.c @@ -1,547 +1,547 @@ -/* -Copyright (c) 2009 Apple Computer, 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, sub license, 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 NON-INFRINGEMENT. -IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. -*/ -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <stddef.h> -#include "mi.h" -#include "scrnintstr.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "dixfontstr.h" -#include "mivalidate.h" -#include "driWrap.h" -#include "dri.h" - -#include <OpenGL/OpenGL.h> - -typedef struct { - GCOps *originalOps; - GCOps *driOps; -} DRIGCRec; - -typedef struct { - GCOps *originalOps; - CreateGCProcPtr CreateGC; -} DRIWrapScreenRec; - -typedef struct { - Bool didSave; - int devKind; - DevUnion devPrivate; -} DRISavedDrawableState; - -static int driGCKeyIndex; -static DevPrivateKey driGCKey = &driGCKeyIndex; - -static int driWrapScreenKeyIndex; -static DevPrivateKey driWrapScreenKey = &driWrapScreenKeyIndex; - -static GCOps driGCOps; - -#define wrap(priv, real, member, func) { \ - priv->member = real->member; \ - real->member = func; \ - } - -#define unwrap(priv, real, member) { \ - real->member = priv->member; \ - } - -static DRIGCRec * -DRIGetGCPriv(GCPtr pGC) { - return dixLookupPrivate(&pGC->devPrivates, driGCKey); -} - -static void -DRIUnwrapGC(GCPtr pGC) { - DRIGCRec *pGCPriv = DRIGetGCPriv(pGC); - - pGC->ops = pGCPriv->originalOps; -} - -static void -DRIWrapGC(GCPtr pGC) { - DRIGCRec *pGCPriv = DRIGetGCPriv(pGC); - - pGC->ops = pGCPriv->driOps; -} - -static void -DRISurfaceSetDrawable(DrawablePtr pDraw, - DRISavedDrawableState *saved) { - saved->didSave = FALSE; - - if(pDraw->type == DRAWABLE_PIXMAP) { - int pitch, width, height, bpp; - void *buffer; - - if(DRIGetPixmapData(pDraw, &width, &height, &pitch, &bpp, &buffer)) { - PixmapPtr pPix = (PixmapPtr)pDraw; - - saved->devKind = pPix->devKind; - saved->devPrivate.ptr = pPix->devPrivate.ptr; - saved->didSave = TRUE; - - pPix->devKind = pitch; - pPix->devPrivate.ptr = buffer; - } - } -} - -static void -DRISurfaceRestoreDrawable(DrawablePtr pDraw, - DRISavedDrawableState *saved) { - PixmapPtr pPix = (PixmapPtr)pDraw; - - if(!saved->didSave) - return; - - pPix->devKind = saved->devKind; - pPix->devPrivate.ptr = saved->devPrivate.ptr; -} - -static void -DRIFillSpans(DrawablePtr dst, GCPtr pGC, int nInit, - DDXPointPtr pptInit, int *pwidthInit, - int sorted) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRISetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc, - DDXPointPtr pptInit, int *pwidthInit, - int nspans, int sorted) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIPutImage(DrawablePtr dst, GCPtr pGC, - int depth, int x, int y, int w, int h, - int leftPad, int format, char *pBits) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->PutImage(dst, pGC, depth, x, y, w, h, leftPad, format, pBits); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static RegionPtr -DRICopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC, - int srcx, int srcy, int w, int h, - int dstx, int dsty) { - RegionPtr pReg; - DRISavedDrawableState pSrcSaved, dstSaved; - - DRISurfaceSetDrawable(pSrc, &pSrcSaved); - DRISurfaceSetDrawable(dst, &dstSaved); - - DRIUnwrapGC(pGC); - - pReg = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(pSrc, &pSrcSaved); - DRISurfaceRestoreDrawable(dst, &dstSaved); - - return pReg; -} - -static RegionPtr -DRICopyPlane(DrawablePtr pSrc, DrawablePtr dst, - GCPtr pGC, int srcx, int srcy, - int w, int h, int dstx, int dsty, - unsigned long plane) { - RegionPtr pReg; - DRISavedDrawableState pSrcSaved, dstSaved; - - DRISurfaceSetDrawable(pSrc, &pSrcSaved); - DRISurfaceSetDrawable(dst, &dstSaved); - - - DRIUnwrapGC(pGC); - - pReg = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty, - plane); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(pSrc, &pSrcSaved); - DRISurfaceRestoreDrawable(dst, &dstSaved); - - return pReg; -} - -static void -DRIPolyPoint(DrawablePtr dst, GCPtr pGC, - int mode, int npt, DDXPointPtr pptInit) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIPolylines(DrawablePtr dst, GCPtr pGC, - int mode, int npt, DDXPointPtr pptInit) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->Polylines(dst, pGC, mode, npt, pptInit); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIPolySegment(DrawablePtr dst, GCPtr pGC, - int nseg, xSegment *pSeg) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->PolySegment(dst, pGC, nseg, pSeg); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIPolyRectangle(DrawablePtr dst, GCPtr pGC, - int nRects, xRectangle *pRects) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->PolyRectangle(dst, pGC, nRects, pRects); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} -static void -DRIPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->PolyArc(dst, pGC, narcs, parcs); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIFillPolygon(DrawablePtr dst, GCPtr pGC, - int shape, int mode, int count, - DDXPointPtr pptInit) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIPolyFillRect(DrawablePtr dst, GCPtr pGC, - int nRectsInit, xRectangle *pRectsInit) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIPolyFillArc(DrawablePtr dst, GCPtr pGC, - int narcsInit, xArc *parcsInit) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static int -DRIPolyText8(DrawablePtr dst, GCPtr pGC, - int x, int y, int count, char *chars) { - int ret; - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - ret = pGC->ops->PolyText8(dst, pGC, x, y, count, chars); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); - - return ret; -} - -static int -DRIPolyText16(DrawablePtr dst, GCPtr pGC, - int x, int y, int count, unsigned short *chars) { - int ret; - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - ret = pGC->ops->PolyText16(dst, pGC, x, y, count, chars); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); - - return ret; -} - -static void -DRIImageText8(DrawablePtr dst, GCPtr pGC, - int x, int y, int count, char *chars) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->ImageText8(dst, pGC, x, y, count, chars); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIImageText16(DrawablePtr dst, GCPtr pGC, - int x, int y, int count, unsigned short *chars) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->ImageText16(dst, pGC, x, y, count, chars); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIImageGlyphBlt(DrawablePtr dst, GCPtr pGC, - int x, int y, unsigned int nglyphInit, - CharInfoPtr *ppciInit, pointer unused) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void DRIPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, - int x, int y, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase) { - DRISavedDrawableState saved; - - DRISurfaceSetDrawable(dst, &saved); - - DRIUnwrapGC(pGC); - - pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(dst, &saved); -} - -static void -DRIPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst, - int dx, int dy, int xOrg, int yOrg) { - DRISavedDrawableState bitMapSaved, dstSaved; - - DRISurfaceSetDrawable(&pBitMap->drawable, &bitMapSaved); - DRISurfaceSetDrawable(dst, &dstSaved); - - DRIUnwrapGC(pGC); - - pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg); - - DRIWrapGC(pGC); - - DRISurfaceRestoreDrawable(&pBitMap->drawable, &bitMapSaved); - DRISurfaceRestoreDrawable(dst, &dstSaved); -} - - -static GCOps driGCOps = { - DRIFillSpans, - DRISetSpans, - DRIPutImage, - DRICopyArea, - DRICopyPlane, - DRIPolyPoint, - DRIPolylines, - DRIPolySegment, - DRIPolyRectangle, - DRIPolyArc, - DRIFillPolygon, - DRIPolyFillRect, - DRIPolyFillArc, - DRIPolyText8, - DRIPolyText16, - DRIImageText8, - DRIImageText16, - DRIImageGlyphBlt, - DRIPolyGlyphBlt, - DRIPushPixels -}; - - -static Bool -DRICreateGC(GCPtr pGC) { - ScreenPtr pScreen = pGC->pScreen; - DRIWrapScreenRec *pScreenPriv; - DRIGCRec *pGCPriv; - Bool ret; - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, driWrapScreenKey); - - pGCPriv = DRIGetGCPriv(pGC); - - unwrap(pScreenPriv, pScreen, CreateGC); - ret = pScreen->CreateGC(pGC); - - if(ret) { - pGCPriv->originalOps = pGC->ops; - pGC->ops = &driGCOps; - pGCPriv->driOps = &driGCOps; - } - - wrap(pScreenPriv, pScreen, CreateGC, DRICreateGC); - - return ret; -} - - -/* Return false if an error occurred. */ -Bool -DRIWrapInit(ScreenPtr pScreen) { - DRIWrapScreenRec *pScreenPriv; - - if(!dixRequestPrivate(driGCKey, sizeof(DRIGCRec))) - return FALSE; - - if(!dixRequestPrivate(driWrapScreenKey, sizeof(DRIWrapScreenRec))) - return FALSE; - - pScreenPriv = xalloc(sizeof(*pScreenPriv)); - - if(NULL == pScreenPriv) - return FALSE; - - pScreenPriv->CreateGC = pScreen->CreateGC; - pScreen->CreateGC = DRICreateGC; - - dixSetPrivate(&pScreen->devPrivates, driWrapScreenKey, pScreenPriv); - - return TRUE; -} +/* +Copyright (c) 2009 Apple Computer, 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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. +*/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stddef.h> +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "dixfontstr.h" +#include "mivalidate.h" +#include "driWrap.h" +#include "dri.h" + +#include <OpenGL/OpenGL.h> + +typedef struct { + GCOps *originalOps; + GCOps *driOps; +} DRIGCRec; + +typedef struct { + GCOps *originalOps; + CreateGCProcPtr CreateGC; +} DRIWrapScreenRec; + +typedef struct { + Bool didSave; + int devKind; + DevUnion devPrivate; +} DRISavedDrawableState; + +static int driGCKeyIndex; +static DevPrivateKey driGCKey = &driGCKeyIndex; + +static int driWrapScreenKeyIndex; +static DevPrivateKey driWrapScreenKey = &driWrapScreenKeyIndex; + +static GCOps driGCOps; + +#define wrap(priv, real, member, func) { \ + priv->member = real->member; \ + real->member = func; \ + } + +#define unwrap(priv, real, member) { \ + real->member = priv->member; \ + } + +static DRIGCRec * +DRIGetGCPriv(GCPtr pGC) { + return dixLookupPrivate(&pGC->devPrivates, driGCKey); +} + +static void +DRIUnwrapGC(GCPtr pGC) { + DRIGCRec *pGCPriv = DRIGetGCPriv(pGC); + + pGC->ops = pGCPriv->originalOps; +} + +static void +DRIWrapGC(GCPtr pGC) { + DRIGCRec *pGCPriv = DRIGetGCPriv(pGC); + + pGC->ops = pGCPriv->driOps; +} + +static void +DRISurfaceSetDrawable(DrawablePtr pDraw, + DRISavedDrawableState *saved) { + saved->didSave = FALSE; + + if(pDraw->type == DRAWABLE_PIXMAP) { + int pitch, width, height, bpp; + void *buffer; + + if(DRIGetPixmapData(pDraw, &width, &height, &pitch, &bpp, &buffer)) { + PixmapPtr pPix = (PixmapPtr)pDraw; + + saved->devKind = pPix->devKind; + saved->devPrivate.ptr = pPix->devPrivate.ptr; + saved->didSave = TRUE; + + pPix->devKind = pitch; + pPix->devPrivate.ptr = buffer; + } + } +} + +static void +DRISurfaceRestoreDrawable(DrawablePtr pDraw, + DRISavedDrawableState *saved) { + PixmapPtr pPix = (PixmapPtr)pDraw; + + if(!saved->didSave) + return; + + pPix->devKind = saved->devKind; + pPix->devPrivate.ptr = saved->devPrivate.ptr; +} + +static void +DRIFillSpans(DrawablePtr dst, GCPtr pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, + int sorted) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRISetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc, + DDXPointPtr pptInit, int *pwidthInit, + int nspans, int sorted) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIPutImage(DrawablePtr dst, GCPtr pGC, + int depth, int x, int y, int w, int h, + int leftPad, int format, char *pBits) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->PutImage(dst, pGC, depth, x, y, w, h, leftPad, format, pBits); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static RegionPtr +DRICopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC, + int srcx, int srcy, int w, int h, + int dstx, int dsty) { + RegionPtr pReg; + DRISavedDrawableState pSrcSaved, dstSaved; + + DRISurfaceSetDrawable(pSrc, &pSrcSaved); + DRISurfaceSetDrawable(dst, &dstSaved); + + DRIUnwrapGC(pGC); + + pReg = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(pSrc, &pSrcSaved); + DRISurfaceRestoreDrawable(dst, &dstSaved); + + return pReg; +} + +static RegionPtr +DRICopyPlane(DrawablePtr pSrc, DrawablePtr dst, + GCPtr pGC, int srcx, int srcy, + int w, int h, int dstx, int dsty, + unsigned long plane) { + RegionPtr pReg; + DRISavedDrawableState pSrcSaved, dstSaved; + + DRISurfaceSetDrawable(pSrc, &pSrcSaved); + DRISurfaceSetDrawable(dst, &dstSaved); + + + DRIUnwrapGC(pGC); + + pReg = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty, + plane); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(pSrc, &pSrcSaved); + DRISurfaceRestoreDrawable(dst, &dstSaved); + + return pReg; +} + +static void +DRIPolyPoint(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIPolylines(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->Polylines(dst, pGC, mode, npt, pptInit); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIPolySegment(DrawablePtr dst, GCPtr pGC, + int nseg, xSegment *pSeg) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->PolySegment(dst, pGC, nseg, pSeg); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIPolyRectangle(DrawablePtr dst, GCPtr pGC, + int nRects, xRectangle *pRects) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->PolyRectangle(dst, pGC, nRects, pRects); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} +static void +DRIPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->PolyArc(dst, pGC, narcs, parcs); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIFillPolygon(DrawablePtr dst, GCPtr pGC, + int shape, int mode, int count, + DDXPointPtr pptInit) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIPolyFillRect(DrawablePtr dst, GCPtr pGC, + int nRectsInit, xRectangle *pRectsInit) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIPolyFillArc(DrawablePtr dst, GCPtr pGC, + int narcsInit, xArc *parcsInit) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static int +DRIPolyText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) { + int ret; + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + ret = pGC->ops->PolyText8(dst, pGC, x, y, count, chars); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); + + return ret; +} + +static int +DRIPolyText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) { + int ret; + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + ret = pGC->ops->PolyText16(dst, pGC, x, y, count, chars); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); + + return ret; +} + +static void +DRIImageText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->ImageText8(dst, pGC, x, y, count, chars); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIImageText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->ImageText16(dst, pGC, x, y, count, chars); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIImageGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyphInit, + CharInfoPtr *ppciInit, pointer unused) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void DRIPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) { + DRISavedDrawableState saved; + + DRISurfaceSetDrawable(dst, &saved); + + DRIUnwrapGC(pGC); + + pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(dst, &saved); +} + +static void +DRIPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst, + int dx, int dy, int xOrg, int yOrg) { + DRISavedDrawableState bitMapSaved, dstSaved; + + DRISurfaceSetDrawable(&pBitMap->drawable, &bitMapSaved); + DRISurfaceSetDrawable(dst, &dstSaved); + + DRIUnwrapGC(pGC); + + pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg); + + DRIWrapGC(pGC); + + DRISurfaceRestoreDrawable(&pBitMap->drawable, &bitMapSaved); + DRISurfaceRestoreDrawable(dst, &dstSaved); +} + + +static GCOps driGCOps = { + DRIFillSpans, + DRISetSpans, + DRIPutImage, + DRICopyArea, + DRICopyPlane, + DRIPolyPoint, + DRIPolylines, + DRIPolySegment, + DRIPolyRectangle, + DRIPolyArc, + DRIFillPolygon, + DRIPolyFillRect, + DRIPolyFillArc, + DRIPolyText8, + DRIPolyText16, + DRIImageText8, + DRIImageText16, + DRIImageGlyphBlt, + DRIPolyGlyphBlt, + DRIPushPixels +}; + + +static Bool +DRICreateGC(GCPtr pGC) { + ScreenPtr pScreen = pGC->pScreen; + DRIWrapScreenRec *pScreenPriv; + DRIGCRec *pGCPriv; + Bool ret; + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, driWrapScreenKey); + + pGCPriv = DRIGetGCPriv(pGC); + + unwrap(pScreenPriv, pScreen, CreateGC); + ret = pScreen->CreateGC(pGC); + + if(ret) { + pGCPriv->originalOps = pGC->ops; + pGC->ops = &driGCOps; + pGCPriv->driOps = &driGCOps; + } + + wrap(pScreenPriv, pScreen, CreateGC, DRICreateGC); + + return ret; +} + + +/* Return false if an error occurred. */ +Bool +DRIWrapInit(ScreenPtr pScreen) { + DRIWrapScreenRec *pScreenPriv; + + if(!dixRequestPrivate(driGCKey, sizeof(DRIGCRec))) + return FALSE; + + if(!dixRequestPrivate(driWrapScreenKey, sizeof(DRIWrapScreenRec))) + return FALSE; + + pScreenPriv = malloc(sizeof(*pScreenPriv)); + + if(NULL == pScreenPriv) + return FALSE; + + pScreenPriv->CreateGC = pScreen->CreateGC; + pScreen->CreateGC = DRICreateGC; + + dixSetPrivate(&pScreen->devPrivates, driWrapScreenKey, pScreenPriv); + + return TRUE; +} diff --git a/xorg-server/hw/xquartz/xpr/x-hook.c b/xorg-server/hw/xquartz/xpr/x-hook.c index 5b850fe88..c65b6fc68 100644 --- a/xorg-server/hw/xquartz/xpr/x-hook.c +++ b/xorg-server/hw/xquartz/xpr/x-hook.c @@ -1,120 +1,120 @@ -/* x-hook.c - - Copyright (c) 2003 Apple Computer, 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 ABOVE LISTED COPYRIGHT - HOLDER(S) 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(s) of the above - copyright holders shall not be used in advertising or otherwise to - promote the sale, use or other dealings in this Software without - prior written authorization. */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "x-hook.h" -#include <stdlib.h> -#include <assert.h> -#include "os.h" - -#define CELL_NEW(f,d) X_PFX (list_prepend) ((x_list *) (f), (d)) -#define CELL_FREE(c) X_PFX (list_free_1) (c) -#define CELL_FUN(c) ((x_hook_function *) ((c)->next)) -#define CELL_DATA(c) ((c)->data) - -X_EXTERN x_list * -X_PFX (hook_add) (x_list *lst, x_hook_function *fun, void *data) -{ - return X_PFX (list_prepend) (lst, CELL_NEW (fun, data)); -} - -X_EXTERN x_list * -X_PFX (hook_remove) (x_list *lst, x_hook_function *fun, void *data) -{ - x_list *node, *cell; - x_list *to_delete = NULL; - - for (node = lst; node != NULL; node = node->next) - { - cell = node->data; - if (CELL_FUN (cell) == fun && CELL_DATA (cell) == data) - to_delete = X_PFX (list_prepend) (to_delete, cell); - } - - for (node = to_delete; node != NULL; node = node->next) - { - cell = node->data; - lst = X_PFX (list_remove) (lst, cell); - CELL_FREE (cell); - } - - X_PFX (list_free) (to_delete); - return lst; -} - -X_EXTERN void -X_PFX (hook_run) (x_list *lst, void *arg) -{ - x_list *node, *cell; - x_hook_function **fun; - void **data; - int length, i; - - if(!lst) - return; - - length = X_PFX (list_length) (lst); - fun = xalloc (sizeof (x_hook_function *) * length); - data = xalloc (sizeof (void *) * length); - - if(!fun || !data) { - FatalError("Failed to allocate memory in %s\n", __func__); - } - - for (i = 0, node = lst; node != NULL; node = node->next, i++) - { - cell = node->data; - fun[i] = CELL_FUN (cell); - data[i] = CELL_DATA (cell); - } - - for (i = 0; i < length; i++) - { - (*fun[i]) (arg, data[i]); - } - - xfree(fun); - xfree(data); -} - -X_EXTERN void -X_PFX (hook_free) (x_list *lst) -{ - x_list *node; - - for (node = lst; node != NULL; node = node->next) - { - CELL_FREE (node->data); - } - - X_PFX (list_free) (lst); -} +/* x-hook.c + + Copyright (c) 2003 Apple Computer, 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 ABOVE LISTED COPYRIGHT + HOLDER(S) 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(s) of the above + copyright holders shall not be used in advertising or otherwise to + promote the sale, use or other dealings in this Software without + prior written authorization. */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "x-hook.h" +#include <stdlib.h> +#include <assert.h> +#include "os.h" + +#define CELL_NEW(f,d) X_PFX (list_prepend) ((x_list *) (f), (d)) +#define CELL_FREE(c) X_PFX (list_free_1) (c) +#define CELL_FUN(c) ((x_hook_function *) ((c)->next)) +#define CELL_DATA(c) ((c)->data) + +X_EXTERN x_list * +X_PFX (hook_add) (x_list *lst, x_hook_function *fun, void *data) +{ + return X_PFX (list_prepend) (lst, CELL_NEW (fun, data)); +} + +X_EXTERN x_list * +X_PFX (hook_remove) (x_list *lst, x_hook_function *fun, void *data) +{ + x_list *node, *cell; + x_list *to_delete = NULL; + + for (node = lst; node != NULL; node = node->next) + { + cell = node->data; + if (CELL_FUN (cell) == fun && CELL_DATA (cell) == data) + to_delete = X_PFX (list_prepend) (to_delete, cell); + } + + for (node = to_delete; node != NULL; node = node->next) + { + cell = node->data; + lst = X_PFX (list_remove) (lst, cell); + CELL_FREE (cell); + } + + X_PFX (list_free) (to_delete); + return lst; +} + +X_EXTERN void +X_PFX (hook_run) (x_list *lst, void *arg) +{ + x_list *node, *cell; + x_hook_function **fun; + void **data; + int length, i; + + if(!lst) + return; + + length = X_PFX (list_length) (lst); + fun = malloc(sizeof (x_hook_function *) * length); + data = malloc(sizeof (void *) * length); + + if(!fun || !data) { + FatalError("Failed to allocate memory in %s\n", __func__); + } + + for (i = 0, node = lst; node != NULL; node = node->next, i++) + { + cell = node->data; + fun[i] = CELL_FUN (cell); + data[i] = CELL_DATA (cell); + } + + for (i = 0; i < length; i++) + { + (*fun[i]) (arg, data[i]); + } + + free(fun); + free(data); +} + +X_EXTERN void +X_PFX (hook_free) (x_list *lst) +{ + x_list *node; + + for (node = lst; node != NULL; node = node->next) + { + CELL_FREE (node->data); + } + + X_PFX (list_free) (lst); +} diff --git a/xorg-server/hw/xquartz/xpr/xprCursor.c b/xorg-server/hw/xquartz/xpr/xprCursor.c index fbaf825de..df9eef95e 100644 --- a/xorg-server/hw/xquartz/xpr/xprCursor.c +++ b/xorg-server/hw/xquartz/xpr/xprCursor.c @@ -1,418 +1,418 @@ -/************************************************************** - * - * Xplugin cursor support - * - * Copyright (c) 2001 Torrey T. Lyons and Greg Parker. - * Copyright (c) 2002 Apple Computer, 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright - * holders shall not be used in advertising or otherwise to promote the sale, - * use or other dealings in this Software without prior written authorization. - */ - -#include "sanitizedCarbon.h" - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "quartzCommon.h" -#include "xpr.h" -#include "darwin.h" -#include "darwinEvents.h" -#include <Xplugin.h> - -#include "mi.h" -#include "scrnintstr.h" -#include "cursorstr.h" -#include "mipointrst.h" -#include "windowstr.h" -#include "globals.h" -#include "servermd.h" -#include "dixevents.h" -#include "x-hash.h" - -typedef struct { - int cursorVisible; - QueryBestSizeProcPtr QueryBestSize; - miPointerSpriteFuncPtr spriteFuncs; -} QuartzCursorScreenRec, *QuartzCursorScreenPtr; - -static int darwinCursorScreenKeyIndex; -static DevPrivateKey darwinCursorScreenKey = &darwinCursorScreenKeyIndex; - -#define CURSOR_PRIV(pScreen) ((QuartzCursorScreenPtr) \ - dixLookupPrivate(&pScreen->devPrivates, darwinCursorScreenKey)) - - -static Bool -load_cursor(CursorPtr src, int screen) -{ - uint32_t *data; - uint32_t rowbytes; - int width, height; - int hot_x, hot_y; - - uint32_t fg_color, bg_color; - uint8_t *srow, *sptr; - uint8_t *mrow, *mptr; - uint32_t *drow, *dptr; - unsigned xcount, ycount; - - xp_error err; - - width = src->bits->width; - height = src->bits->height; - hot_x = src->bits->xhot; - hot_y = src->bits->yhot; - -#ifdef ARGB_CURSOR - if (src->bits->argb != NULL) - { -#if BITMAP_BIT_ORDER == MSBFirst - rowbytes = src->bits->width * sizeof (CARD32); - data = (uint32_t *) src->bits->argb; -#else - const uint32_t *be_data=(uint32_t *) src->bits->argb; - unsigned i; - rowbytes = src->bits->width * sizeof (CARD32); - data = xalloc(rowbytes * src->bits->height); - if(!data) { - FatalError("Failed to allocate memory in %s\n", __func__); - } - for(i=0;i<(src->bits->width*src->bits->height);i++) - data[i]=ntohl(be_data[i]); -#endif - } - else -#endif - { - fg_color = 0xFF00 | (src->foreRed >> 8); - fg_color <<= 16; - fg_color |= src->foreGreen & 0xFF00; - fg_color |= src->foreBlue >> 8; - - bg_color = 0xFF00 | (src->backRed >> 8); - bg_color <<= 16; - bg_color |= src->backGreen & 0xFF00; - bg_color |= src->backBlue >> 8; - - fg_color = htonl(fg_color); - bg_color = htonl(bg_color); - - /* round up to 8 pixel boundary so we can convert whole bytes */ - rowbytes = ((src->bits->width * 4) + 31) & ~31; - data = xalloc(rowbytes * src->bits->height); - if(!data) { - FatalError("Failed to allocate memory in %s\n", __func__); - } - - if (!src->bits->emptyMask) - { - ycount = src->bits->height; - srow = src->bits->source; mrow = src->bits->mask; - drow = data; - - while (ycount-- > 0) - { - xcount = bits_to_bytes(src->bits->width); - sptr = srow; mptr = mrow; - dptr = drow; - - while (xcount-- > 0) - { - uint8_t s, m; - int i; - - s = *sptr++; m = *mptr++; - for (i = 0; i < 8; i++) - { -#if BITMAP_BIT_ORDER == MSBFirst - if (m & 128) - *dptr++ = (s & 128) ? fg_color : bg_color; - else - *dptr++ = 0; - s <<= 1; m <<= 1; -#else - if (m & 1) - *dptr++ = (s & 1) ? fg_color : bg_color; - else - *dptr++ = 0; - s >>= 1; m >>= 1; -#endif - } - } - - srow += BitmapBytePad(src->bits->width); - mrow += BitmapBytePad(src->bits->width); - drow = (uint32_t *) ((char *) drow + rowbytes); - } - } - else - { - memset(data, 0, src->bits->height * rowbytes); - } - } - - err = xp_set_cursor(width, height, hot_x, hot_y, data, rowbytes); - xfree(data); - return err == Success; -} - - -/* -=========================================================================== - - Pointer sprite functions - -=========================================================================== -*/ - -/* - * QuartzRealizeCursor - * Convert the X cursor representation to native format if possible. - */ -static Bool -QuartzRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - if(pCursor == NULL || pCursor->bits == NULL) - return FALSE; - - /* FIXME: cache ARGB8888 representation? */ - - return TRUE; -} - - -/* - * QuartzUnrealizeCursor - * Free the storage space associated with a realized cursor. - */ -static Bool -QuartzUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - return TRUE; -} - - -/* - * QuartzSetCursor - * Set the cursor sprite and position. - */ -static void -QuartzSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) -{ - QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); - - if (!quartzServerVisible) - return; - - if (pCursor == NULL) - { - if (ScreenPriv->cursorVisible) - { - xp_hide_cursor(); - ScreenPriv->cursorVisible = FALSE; - } - } - else - { - load_cursor(pCursor, pScreen->myNum); - - if (!ScreenPriv->cursorVisible) - { - xp_show_cursor(); - ScreenPriv->cursorVisible = TRUE; - } - } -} - -/* - * QuartzMoveCursor - * Move the cursor. This is a noop for us. - */ -static void -QuartzMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ -} - -/* -=========================================================================== - - Pointer screen functions - -=========================================================================== -*/ - -/* - * QuartzCursorOffScreen - */ -static Bool -QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y) -{ - return FALSE; -} - - -/* - * QuartzCrossScreen - */ -static void -QuartzCrossScreen(ScreenPtr pScreen, Bool entering) -{ - return; -} - - -/* - * QuartzWarpCursor - * Change the cursor position without generating an event or motion history. - * The input coordinates (x,y) are in pScreen-local X11 coordinates. - * - */ -static void -QuartzWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - if (quartzServerVisible) - { - int sx, sy; - - sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; - sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; - - CGWarpMouseCursorPosition(CGPointMake(sx + x, sy + y)); - } - - miPointerWarpCursor(pDev, pScreen, x, y); - miPointerUpdateSprite(pDev); -} - - -static miPointerScreenFuncRec quartzScreenFuncsRec = { - QuartzCursorOffScreen, - QuartzCrossScreen, - QuartzWarpCursor, - NULL, - NULL -}; - - -/* -=========================================================================== - - Other screen functions - -=========================================================================== -*/ - -/* - * QuartzCursorQueryBestSize - * Handle queries for best cursor size - */ -static void -QuartzCursorQueryBestSize(int class, unsigned short *width, - unsigned short *height, ScreenPtr pScreen) -{ - QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); - - if (class == CursorShape) - { - /* FIXME: query window server? */ - *width = 32; - *height = 32; - } - else - { - (*ScreenPriv->QueryBestSize)(class, width, height, pScreen); - } -} - -/* - * QuartzInitCursor - * Initialize cursor support - */ -Bool -QuartzInitCursor(ScreenPtr pScreen) -{ - QuartzCursorScreenPtr ScreenPriv; - miPointerScreenPtr PointPriv; - - /* initialize software cursor handling (always needed as backup) */ - if (!miDCInitialize(pScreen, &quartzScreenFuncsRec)) - return FALSE; - - ScreenPriv = xcalloc(1, sizeof(QuartzCursorScreenRec)); - if (ScreenPriv == NULL) - return FALSE; - - /* CURSOR_PRIV(pScreen) = ScreenPriv; */ - dixSetPrivate(&pScreen->devPrivates, darwinCursorScreenKey, ScreenPriv); - - /* override some screen procedures */ - ScreenPriv->QueryBestSize = pScreen->QueryBestSize; - pScreen->QueryBestSize = QuartzCursorQueryBestSize; - - PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); - - ScreenPriv->spriteFuncs = PointPriv->spriteFuncs; - - PointPriv->spriteFuncs->RealizeCursor = QuartzRealizeCursor; - PointPriv->spriteFuncs->UnrealizeCursor = QuartzUnrealizeCursor; - PointPriv->spriteFuncs->SetCursor = QuartzSetCursor; - PointPriv->spriteFuncs->MoveCursor = QuartzMoveCursor; - - ScreenPriv->cursorVisible = TRUE; - return TRUE; -} - -/* - * QuartzSuspendXCursor - * X server is hiding. Restore the Aqua cursor. - */ -void -QuartzSuspendXCursor(ScreenPtr pScreen) -{ -} - - -/* - * QuartzResumeXCursor - * X server is showing. Restore the X cursor. - */ -void -QuartzResumeXCursor(ScreenPtr pScreen) -{ - WindowPtr pWin; - CursorPtr pCursor; - - /* TODO: Tablet? */ - - pWin = GetSpriteWindow(darwinPointer); - if (pWin->drawable.pScreen != pScreen) - return; - - pCursor = GetSpriteCursor(darwinPointer); - if (pCursor == NULL) - return; - - QuartzSetCursor(darwinPointer, pScreen, pCursor, /* x */ 0, /* y */ 0); -} +/************************************************************** + * + * Xplugin cursor support + * + * Copyright (c) 2001 Torrey T. Lyons and Greg Parker. + * Copyright (c) 2002 Apple Computer, 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ + +#include "sanitizedCarbon.h" + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "quartzCommon.h" +#include "xpr.h" +#include "darwin.h" +#include "darwinEvents.h" +#include <Xplugin.h> + +#include "mi.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "mipointrst.h" +#include "windowstr.h" +#include "globals.h" +#include "servermd.h" +#include "dixevents.h" +#include "x-hash.h" + +typedef struct { + int cursorVisible; + QueryBestSizeProcPtr QueryBestSize; + miPointerSpriteFuncPtr spriteFuncs; +} QuartzCursorScreenRec, *QuartzCursorScreenPtr; + +static int darwinCursorScreenKeyIndex; +static DevPrivateKey darwinCursorScreenKey = &darwinCursorScreenKeyIndex; + +#define CURSOR_PRIV(pScreen) ((QuartzCursorScreenPtr) \ + dixLookupPrivate(&pScreen->devPrivates, darwinCursorScreenKey)) + + +static Bool +load_cursor(CursorPtr src, int screen) +{ + uint32_t *data; + uint32_t rowbytes; + int width, height; + int hot_x, hot_y; + + uint32_t fg_color, bg_color; + uint8_t *srow, *sptr; + uint8_t *mrow, *mptr; + uint32_t *drow, *dptr; + unsigned xcount, ycount; + + xp_error err; + + width = src->bits->width; + height = src->bits->height; + hot_x = src->bits->xhot; + hot_y = src->bits->yhot; + +#ifdef ARGB_CURSOR + if (src->bits->argb != NULL) + { +#if BITMAP_BIT_ORDER == MSBFirst + rowbytes = src->bits->width * sizeof (CARD32); + data = (uint32_t *) src->bits->argb; +#else + const uint32_t *be_data=(uint32_t *) src->bits->argb; + unsigned i; + rowbytes = src->bits->width * sizeof (CARD32); + data = malloc(rowbytes * src->bits->height); + if(!data) { + FatalError("Failed to allocate memory in %s\n", __func__); + } + for(i=0;i<(src->bits->width*src->bits->height);i++) + data[i]=ntohl(be_data[i]); +#endif + } + else +#endif + { + fg_color = 0xFF00 | (src->foreRed >> 8); + fg_color <<= 16; + fg_color |= src->foreGreen & 0xFF00; + fg_color |= src->foreBlue >> 8; + + bg_color = 0xFF00 | (src->backRed >> 8); + bg_color <<= 16; + bg_color |= src->backGreen & 0xFF00; + bg_color |= src->backBlue >> 8; + + fg_color = htonl(fg_color); + bg_color = htonl(bg_color); + + /* round up to 8 pixel boundary so we can convert whole bytes */ + rowbytes = ((src->bits->width * 4) + 31) & ~31; + data = malloc(rowbytes * src->bits->height); + if(!data) { + FatalError("Failed to allocate memory in %s\n", __func__); + } + + if (!src->bits->emptyMask) + { + ycount = src->bits->height; + srow = src->bits->source; mrow = src->bits->mask; + drow = data; + + while (ycount-- > 0) + { + xcount = bits_to_bytes(src->bits->width); + sptr = srow; mptr = mrow; + dptr = drow; + + while (xcount-- > 0) + { + uint8_t s, m; + int i; + + s = *sptr++; m = *mptr++; + for (i = 0; i < 8; i++) + { +#if BITMAP_BIT_ORDER == MSBFirst + if (m & 128) + *dptr++ = (s & 128) ? fg_color : bg_color; + else + *dptr++ = 0; + s <<= 1; m <<= 1; +#else + if (m & 1) + *dptr++ = (s & 1) ? fg_color : bg_color; + else + *dptr++ = 0; + s >>= 1; m >>= 1; +#endif + } + } + + srow += BitmapBytePad(src->bits->width); + mrow += BitmapBytePad(src->bits->width); + drow = (uint32_t *) ((char *) drow + rowbytes); + } + } + else + { + memset(data, 0, src->bits->height * rowbytes); + } + } + + err = xp_set_cursor(width, height, hot_x, hot_y, data, rowbytes); + free(data); + return err == Success; +} + + +/* +=========================================================================== + + Pointer sprite functions + +=========================================================================== +*/ + +/* + * QuartzRealizeCursor + * Convert the X cursor representation to native format if possible. + */ +static Bool +QuartzRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + if(pCursor == NULL || pCursor->bits == NULL) + return FALSE; + + /* FIXME: cache ARGB8888 representation? */ + + return TRUE; +} + + +/* + * QuartzUnrealizeCursor + * Free the storage space associated with a realized cursor. + */ +static Bool +QuartzUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + return TRUE; +} + + +/* + * QuartzSetCursor + * Set the cursor sprite and position. + */ +static void +QuartzSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if (!quartzServerVisible) + return; + + if (pCursor == NULL) + { + if (ScreenPriv->cursorVisible) + { + xp_hide_cursor(); + ScreenPriv->cursorVisible = FALSE; + } + } + else + { + load_cursor(pCursor, pScreen->myNum); + + if (!ScreenPriv->cursorVisible) + { + xp_show_cursor(); + ScreenPriv->cursorVisible = TRUE; + } + } +} + +/* + * QuartzMoveCursor + * Move the cursor. This is a noop for us. + */ +static void +QuartzMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ +} + +/* +=========================================================================== + + Pointer screen functions + +=========================================================================== +*/ + +/* + * QuartzCursorOffScreen + */ +static Bool +QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y) +{ + return FALSE; +} + + +/* + * QuartzCrossScreen + */ +static void +QuartzCrossScreen(ScreenPtr pScreen, Bool entering) +{ + return; +} + + +/* + * QuartzWarpCursor + * Change the cursor position without generating an event or motion history. + * The input coordinates (x,y) are in pScreen-local X11 coordinates. + * + */ +static void +QuartzWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + if (quartzServerVisible) + { + int sx, sy; + + sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + CGWarpMouseCursorPosition(CGPointMake(sx + x, sy + y)); + } + + miPointerWarpCursor(pDev, pScreen, x, y); + miPointerUpdateSprite(pDev); +} + + +static miPointerScreenFuncRec quartzScreenFuncsRec = { + QuartzCursorOffScreen, + QuartzCrossScreen, + QuartzWarpCursor, + NULL, + NULL +}; + + +/* +=========================================================================== + + Other screen functions + +=========================================================================== +*/ + +/* + * QuartzCursorQueryBestSize + * Handle queries for best cursor size + */ +static void +QuartzCursorQueryBestSize(int class, unsigned short *width, + unsigned short *height, ScreenPtr pScreen) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if (class == CursorShape) + { + /* FIXME: query window server? */ + *width = 32; + *height = 32; + } + else + { + (*ScreenPriv->QueryBestSize)(class, width, height, pScreen); + } +} + +/* + * QuartzInitCursor + * Initialize cursor support + */ +Bool +QuartzInitCursor(ScreenPtr pScreen) +{ + QuartzCursorScreenPtr ScreenPriv; + miPointerScreenPtr PointPriv; + + /* initialize software cursor handling (always needed as backup) */ + if (!miDCInitialize(pScreen, &quartzScreenFuncsRec)) + return FALSE; + + ScreenPriv = calloc(1, sizeof(QuartzCursorScreenRec)); + if (ScreenPriv == NULL) + return FALSE; + + /* CURSOR_PRIV(pScreen) = ScreenPriv; */ + dixSetPrivate(&pScreen->devPrivates, darwinCursorScreenKey, ScreenPriv); + + /* override some screen procedures */ + ScreenPriv->QueryBestSize = pScreen->QueryBestSize; + pScreen->QueryBestSize = QuartzCursorQueryBestSize; + + PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); + + ScreenPriv->spriteFuncs = PointPriv->spriteFuncs; + + PointPriv->spriteFuncs->RealizeCursor = QuartzRealizeCursor; + PointPriv->spriteFuncs->UnrealizeCursor = QuartzUnrealizeCursor; + PointPriv->spriteFuncs->SetCursor = QuartzSetCursor; + PointPriv->spriteFuncs->MoveCursor = QuartzMoveCursor; + + ScreenPriv->cursorVisible = TRUE; + return TRUE; +} + +/* + * QuartzSuspendXCursor + * X server is hiding. Restore the Aqua cursor. + */ +void +QuartzSuspendXCursor(ScreenPtr pScreen) +{ +} + + +/* + * QuartzResumeXCursor + * X server is showing. Restore the X cursor. + */ +void +QuartzResumeXCursor(ScreenPtr pScreen) +{ + WindowPtr pWin; + CursorPtr pCursor; + + /* TODO: Tablet? */ + + pWin = GetSpriteWindow(darwinPointer); + if (pWin->drawable.pScreen != pScreen) + return; + + pCursor = GetSpriteCursor(darwinPointer); + if (pCursor == NULL) + return; + + QuartzSetCursor(darwinPointer, pScreen, pCursor, /* x */ 0, /* y */ 0); +} diff --git a/xorg-server/hw/xquartz/xpr/xprScreen.c b/xorg-server/hw/xquartz/xpr/xprScreen.c index 44067862f..bc68f7923 100644 --- a/xorg-server/hw/xquartz/xpr/xprScreen.c +++ b/xorg-server/hw/xquartz/xpr/xprScreen.c @@ -195,7 +195,7 @@ xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height) return; } - displayList = xalloc(displayCount * sizeof(CGDirectDisplayID)); + displayList = malloc(displayCount * sizeof(CGDirectDisplayID)); if(!displayList) FatalError("Unable to allocate memory for list of displays.\n"); CGGetActiveDisplayList(displayCount, displayList, &displayCount); @@ -232,7 +232,7 @@ xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height) frame.size.width, frame.size.height); } - xfree(displayList); + free(displayList); } /* diff --git a/xorg-server/hw/xwin/glx/indirect.c b/xorg-server/hw/xwin/glx/indirect.c index c12cd1fbf..7bcfcdc21 100644 --- a/xorg-server/hw/xwin/glx/indirect.c +++ b/xorg-server/hw/xwin/glx/indirect.c @@ -1,2316 +1,2316 @@ -/* - * File: indirect.c - * Purpose: A GLX implementation that uses Windows OpenGL library - * - * Authors: Alexander Gottwald - * Jon TURNEY - * - * Copyright (c) Jon TURNEY 2009 - * Copyright (c) Alexander Gottwald 2004 - * - * Portions of this file are copied from GL/apple/indirect.c, - * which contains the following copyright: - * - * Copyright (c) 2007, 2008, 2009 Apple Inc. - * Copyright (c) 2004 Torrey T. Lyons. All Rights Reserved. - * Copyright (c) 2002 Greg Parker. All Rights Reserved. - * - * Portions of this file are copied from Mesa's xf86glx.c, - * which contains the following copyright: - * - * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. - * 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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. - */ - -/* - TODO: - - hook up remaining unimplemented extensions - - research what guarantees glXWaitX, glXWaitGL are supposed to offer, and implement then - using GdiFlush and/or glFinish - - pbuffer clobbering: we don't get async notification, but can we arrange to emit the - event when we notice it's been clobbered? at the very least, check if it's been clobbered - before using it? - - are the __GLXConfig * we get handed back ones we are made (so we can extend the structure - with privates?) Or are they created inside the GLX core as well? -*/ - -/* - MSDN clarifications: - - It says SetPixelFormat()'s PIXELFORMATDESCRIPTOR pointer argument has no effect - except on metafiles, this seems to mean that as it's ok to supply NULL if the DC - is not for a metafile - - wglMakeCurrent ignores the hdc if hglrc is NULL, so wglMakeCurrent(NULL, NULL) - is used to make no context current - -*/ - -#ifdef HAVE_XWIN_CONFIG_H -#include <xwin-config.h> -#endif - -#include "glwindows.h" -#include <glx/glxserver.h> -#include <glx/glxutil.h> -#include <glx/extension_string.h> -#include <GL/glxtokens.h> - -#include <winpriv.h> -#include <wgl_ext_api.h> - -#define NUM_ELEMENTS(x) (sizeof(x)/ sizeof(x[1])) - -/* ---------------------------------------------------------------------- */ -/* - * structure definitions - */ - -typedef struct __GLXWinContext __GLXWinContext; -typedef struct __GLXWinDrawable __GLXWinDrawable; -typedef struct __GLXWinScreen glxWinScreen; -typedef struct __GLXWinConfig GLXWinConfig; - -struct __GLXWinContext { - __GLXcontext base; - HGLRC ctx; /* Windows GL Context */ - __GLXWinContext *shareContext; /* Context with which we will share display lists and textures */ - HWND hwnd; /* For detecting when HWND has changed */ -}; - -struct __GLXWinDrawable -{ - __GLXdrawable base; - __GLXWinContext *drawContext; - __GLXWinContext *readContext; - - /* If this drawable is GLX_DRAWABLE_PBUFFER */ - HPBUFFERARB hPbuffer; - - /* If this drawable is GLX_DRAWABLE_PIXMAP */ - HDC dibDC; - HBITMAP hDIB; - HBITMAP hOldDIB; /* original DIB for DC */ - void *pOldBits; /* original pBits for this drawable's pixmap */ -}; - -struct __GLXWinScreen -{ - __GLXscreen base; - - /* Supported GLX extensions */ - unsigned char glx_enable_bits[__GLX_EXT_BYTES]; - - Bool has_WGL_ARB_multisample; - Bool has_WGL_ARB_pixel_format; - Bool has_WGL_ARB_pbuffer; - Bool has_WGL_ARB_render_texture; - - /* wrapped screen functions */ - RealizeWindowProcPtr RealizeWindow; - UnrealizeWindowProcPtr UnrealizeWindow; - CopyWindowProcPtr CopyWindow; -}; - -struct __GLXWinConfig -{ - __GLXconfig base; - int pixelFormatIndex; -}; - -/* ---------------------------------------------------------------------- */ -/* - * Various debug helpers - */ - -#define GLWIN_DEBUG_HWND(hwnd) \ - if (glxWinDebugSettings.dumpHWND) { \ - char buffer[1024]; \ - if (GetWindowText(hwnd, buffer, sizeof(buffer))==0) *buffer=0; \ - GLWIN_DEBUG_MSG("Got HWND %p for window '%s'", hwnd, buffer); \ - } - -glxWinDebugSettingsRec glxWinDebugSettings = { 0, 0, 0, 0, 0, 0}; - -static void glxWinInitDebugSettings(void) -{ - char *envptr; - - envptr = getenv("GLWIN_ENABLE_DEBUG"); - if (envptr != NULL) - glxWinDebugSettings.enableDebug = (atoi(envptr) == 1); - - envptr = getenv("GLWIN_ENABLE_TRACE"); - if (envptr != NULL) - glxWinDebugSettings.enableTrace = (atoi(envptr) == 1); - - envptr = getenv("GLWIN_DUMP_PFD"); - if (envptr != NULL) - glxWinDebugSettings.dumpPFD = (atoi(envptr) == 1); - - envptr = getenv("GLWIN_DUMP_HWND"); - if (envptr != NULL) - glxWinDebugSettings.dumpHWND = (atoi(envptr) == 1); - - envptr = getenv("GLWIN_DUMP_DC"); - if (envptr != NULL) - glxWinDebugSettings.dumpDC = (atoi(envptr) == 1); - - envptr = getenv("GLWIN_ENABLE_GLCALL_TRACE"); - if (envptr != NULL) - glxWinDebugSettings.enableGLcallTrace = (atoi(envptr) == 1); - - envptr = getenv("GLWIN_ENABLE_WGLCALL_TRACE"); - if (envptr != NULL) - glxWinDebugSettings.enableWGLcallTrace = (atoi(envptr) == 1); - - envptr = getenv("GLWIN_DEBUG_ALL"); - if (envptr != NULL) - { - glxWinDebugSettings.enableDebug = 1; - glxWinDebugSettings.enableTrace = 1; - glxWinDebugSettings.dumpPFD = 1; - glxWinDebugSettings.dumpHWND = 1; - glxWinDebugSettings.dumpDC = 1; - glxWinDebugSettings.enableGLcallTrace = 1; - glxWinDebugSettings.enableWGLcallTrace = 1; - } -} - -static -const char *glxWinErrorMessage(void) -{ - static char errorbuffer[1024]; - - if (!FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &errorbuffer, - sizeof(errorbuffer), - NULL )) - { - snprintf(errorbuffer, sizeof(errorbuffer), "Unknown error in FormatMessage: %08x!", (unsigned)GetLastError()); - } - - if (errorbuffer[strlen(errorbuffer)-1] == '\n') - errorbuffer[strlen(errorbuffer)-1] = 0; - - return errorbuffer; -} - -static void pfdOut(const PIXELFORMATDESCRIPTOR *pfd); - -#define DUMP_PFD_FLAG(flag) \ - if (pfd->dwFlags & flag) { \ - ErrorF("%s%s", pipesym, #flag); \ - pipesym = " | "; \ - } - -static void pfdOut(const PIXELFORMATDESCRIPTOR *pfd) -{ - const char *pipesym = ""; /* will be set after first flag dump */ - ErrorF("PIXELFORMATDESCRIPTOR:\n"); - ErrorF("nSize = %u\n", pfd->nSize); - ErrorF("nVersion = %u\n", pfd->nVersion); - ErrorF("dwFlags = %lu = {", pfd->dwFlags); - DUMP_PFD_FLAG(PFD_DOUBLEBUFFER); - DUMP_PFD_FLAG(PFD_STEREO); - DUMP_PFD_FLAG(PFD_DRAW_TO_WINDOW); - DUMP_PFD_FLAG(PFD_DRAW_TO_BITMAP); - DUMP_PFD_FLAG(PFD_SUPPORT_GDI); - DUMP_PFD_FLAG(PFD_SUPPORT_OPENGL); - DUMP_PFD_FLAG(PFD_GENERIC_FORMAT); - DUMP_PFD_FLAG(PFD_NEED_PALETTE); - DUMP_PFD_FLAG(PFD_NEED_SYSTEM_PALETTE); - DUMP_PFD_FLAG(PFD_SWAP_EXCHANGE); - DUMP_PFD_FLAG(PFD_SWAP_COPY); - DUMP_PFD_FLAG(PFD_SWAP_LAYER_BUFFERS); - DUMP_PFD_FLAG(PFD_GENERIC_ACCELERATED); - DUMP_PFD_FLAG(PFD_DEPTH_DONTCARE); - DUMP_PFD_FLAG(PFD_DOUBLEBUFFER_DONTCARE); - DUMP_PFD_FLAG(PFD_STEREO_DONTCARE); - ErrorF("}\n"); - - ErrorF("iPixelType = %hu = %s\n", pfd->iPixelType, - (pfd->iPixelType == PFD_TYPE_RGBA ? "PFD_TYPE_RGBA" : "PFD_TYPE_COLORINDEX")); - ErrorF("cColorBits = %hhu\n", pfd->cColorBits); - ErrorF("cRedBits = %hhu\n", pfd->cRedBits); - ErrorF("cRedShift = %hhu\n", pfd->cRedShift); - ErrorF("cGreenBits = %hhu\n", pfd->cGreenBits); - ErrorF("cGreenShift = %hhu\n", pfd->cGreenShift); - ErrorF("cBlueBits = %hhu\n", pfd->cBlueBits); - ErrorF("cBlueShift = %hhu\n", pfd->cBlueShift); - ErrorF("cAlphaBits = %hhu\n", pfd->cAlphaBits); - ErrorF("cAlphaShift = %hhu\n", pfd->cAlphaShift); - ErrorF("cAccumBits = %hhu\n", pfd->cAccumBits); - ErrorF("cAccumRedBits = %hhu\n", pfd->cAccumRedBits); - ErrorF("cAccumGreenBits = %hhu\n", pfd->cAccumGreenBits); - ErrorF("cAccumBlueBits = %hhu\n", pfd->cAccumBlueBits); - ErrorF("cAccumAlphaBits = %hhu\n", pfd->cAccumAlphaBits); - ErrorF("cDepthBits = %hhu\n", pfd->cDepthBits); - ErrorF("cStencilBits = %hhu\n", pfd->cStencilBits); - ErrorF("cAuxBuffers = %hhu\n", pfd->cAuxBuffers); - ErrorF("iLayerType = %hhu\n", pfd->iLayerType); - ErrorF("bReserved = %hhu\n", pfd->bReserved); - ErrorF("dwLayerMask = %lu\n", pfd->dwLayerMask); - ErrorF("dwVisibleMask = %lu\n", pfd->dwVisibleMask); - ErrorF("dwDamageMask = %lu\n", pfd->dwDamageMask); - ErrorF("\n"); -} - -static const char * -visual_class_name(int cls) -{ - switch (cls) { - case GLX_STATIC_COLOR: - return "StaticColor"; - case GLX_PSEUDO_COLOR: - return "PseudoColor"; - case GLX_STATIC_GRAY: - return "StaticGray"; - case GLX_GRAY_SCALE: - return "GrayScale"; - case GLX_TRUE_COLOR: - return "TrueColor"; - case GLX_DIRECT_COLOR: - return "DirectColor"; - default: - return "-none-"; - } -} - -static const char * -swap_method_name(int mthd) -{ - switch (mthd) - { - case GLX_SWAP_EXCHANGE_OML: - return "xchg"; - case GLX_SWAP_COPY_OML: - return "copy"; - case GLX_SWAP_UNDEFINED_OML: - return " "; - default: - return "????"; - } -} - -static void -fbConfigsDump(unsigned int n, __GLXconfig *c) -{ - ErrorF("%d fbConfigs\n", n); - ErrorF("pxf vis fb render Ste aux accum MS drawable Group/\n"); - ErrorF("idx ID ID VisualType Depth Lvl RGB CI DB Swap reo R G B A Z S buf AR AG AB AA bufs num W P Pb Float Trans Caveat\n"); - ErrorF("-----------------------------------------------------------------------------------------------------------------------------\n"); - - while (c != NULL) - { - unsigned int i = ((GLXWinConfig *)c)->pixelFormatIndex; - - ErrorF("%3d %2x %2x " - "%-11s" - " %3d %3d %s %s %s %s %s " - "%2d %2d %2d %2d " - "%2d %2d " - "%2d " - "%2d %2d %2d %2d" - " %2d %2d" - " %s %s %s " - " %s " - " %s " - " %d %s" - "\n", - i, c->visualID, c->fbconfigID, - visual_class_name(c->visualType), - c->rgbBits ? c->rgbBits : c->indexBits, - c->level, - (c->renderType & GLX_RGBA_BIT) ? "y" : ".", - (c->renderType & GLX_COLOR_INDEX_BIT) ? "y" : ".", - c->doubleBufferMode ? "y" : ".", - swap_method_name(c->swapMethod), - c->stereoMode ? "y" : ".", - c->redBits, c->greenBits, c->blueBits, c->alphaBits, - c->depthBits, c->stencilBits, - c->numAuxBuffers, - c->accumRedBits, c->accumGreenBits, c->accumBlueBits, c->accumAlphaBits, - c->sampleBuffers, c->samples, - (c->drawableType & GLX_WINDOW_BIT) ? "y" : ".", - (c->drawableType & GLX_PIXMAP_BIT) ? "y" : ".", - (c->drawableType & GLX_PBUFFER_BIT) ? "y" : ".", - ".", - (c->transparentPixel != GLX_NONE_EXT) ? "y" : ".", - c->visualSelectGroup, (c->visualRating == GLX_SLOW_VISUAL_EXT) ? "*" : " "); - - c = c->next; - } -} - -/* ---------------------------------------------------------------------- */ -/* - * Forward declarations - */ - -static __GLXscreen *glxWinScreenProbe(ScreenPtr pScreen); -static __GLXcontext *glxWinCreateContext(__GLXscreen *screen, - __GLXconfig *modes, - __GLXcontext *baseShareContext); -static __GLXdrawable *glxWinCreateDrawable(__GLXscreen *screen, - DrawablePtr pDraw, - int type, - XID drawId, - __GLXconfig *conf); - -static Bool glxWinRealizeWindow(WindowPtr pWin); -static Bool glxWinUnrealizeWindow(WindowPtr pWin); -static void glxWinCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc); - -static HDC glxWinMakeDC(__GLXWinContext *gc, __GLXWinDrawable *draw, HDC *hdc, HWND *hwnd); -static void glxWinReleaseDC(HWND hwnd, HDC hdc, __GLXWinDrawable *draw); - -static void glxWinCreateConfigs(HDC dc, glxWinScreen *screen); -static void glxWinCreateConfigsExt(HDC hdc, glxWinScreen *screen); -static int fbConfigToPixelFormat(__GLXconfig *mode, PIXELFORMATDESCRIPTOR *pfdret, int drawableTypeOverride); -static int fbConfigToPixelFormatIndex(HDC hdc, __GLXconfig *mode, int drawableTypeOverride, glxWinScreen *winScreen); - -/* ---------------------------------------------------------------------- */ -/* - * The GLX provider - */ - -__GLXprovider __glXWGLProvider = { - glxWinScreenProbe, - "Win32 native WGL", - NULL -}; - -void -glxWinPushNativeProvider(void) -{ - GlxPushProvider(&__glXWGLProvider); -} - -/* ---------------------------------------------------------------------- */ -/* - * Screen functions - */ - -static void -glxWinScreenDestroy(__GLXscreen *screen) -{ - GLWIN_DEBUG_MSG("glxWinScreenDestroy(%p)", screen); - __glXScreenDestroy(screen); - xfree(screen); -} - -static int -glxWinScreenSwapInterval(__GLXdrawable *drawable, int interval) -{ - BOOL ret = wglSwapIntervalEXTWrapper(interval); - if (!ret) - { - ErrorF("wglSwapIntervalEXT interval %d failed:%s\n", interval, glxWinErrorMessage()); - } - return ret; -} - -/* - Report the extensions split and formatted to avoid overflowing a line - */ -static void -glxLogExtensions(const char *prefix, const char *extensions) -{ - int length = 0; - char *strl; - char *str = xalloc(strlen(extensions) + 1); - - if (str == NULL) - { - ErrorF("glxLogExtensions: xalloc error\n"); - return; - } - - str[strlen(extensions)] = '\0'; - strncpy (str, extensions, strlen(extensions)); - - strl = strtok(str, " "); - ErrorF("%s%s", prefix, strl); - length = strlen(prefix) + strlen(strl); - - while (1) - { - strl = strtok(NULL, " "); - if (strl == NULL) break; - - if (length + strlen(strl) + 1 > 120) - { - ErrorF("\n"); - ErrorF("%s",prefix); - length = strlen(prefix); - } - else - { - ErrorF(" "); - length++; - } - - ErrorF("%s", strl); - length = length + strlen(strl); - } - - ErrorF("\n"); - - xfree(str); -} - -/* This is called by GlxExtensionInit() asking the GLX provider if it can handle the screen... */ -static __GLXscreen * -glxWinScreenProbe(ScreenPtr pScreen) -{ - glxWinScreen *screen; - const char *gl_extensions; - const char *wgl_extensions; - HWND hwnd; - HDC hdc; - HGLRC hglrc; - - GLWIN_DEBUG_MSG("glxWinScreenProbe"); - - glxWinInitDebugSettings(); - - if (pScreen == NULL) - return NULL; - - if (!winCheckScreenAiglxIsSupported(pScreen)) - { - LogMessage(X_ERROR,"AIGLX: No native OpenGL in modes with a root window\n"); - return NULL; - } - - screen = xcalloc(1, sizeof(glxWinScreen)); - - if (NULL == screen) - return NULL; - - /* Wrap RealizeWindow, UnrealizeWindow and CopyWindow on this screen */ - screen->RealizeWindow = pScreen->RealizeWindow; - pScreen->RealizeWindow = glxWinRealizeWindow; - screen->UnrealizeWindow = pScreen->UnrealizeWindow; - pScreen->UnrealizeWindow = glxWinUnrealizeWindow; - screen->CopyWindow = pScreen->CopyWindow; - pScreen->CopyWindow = glxWinCopyWindow; - - /* Dump out some useful information about the native renderer */ - - // create window class -#define WIN_GL_TEST_WINDOW_CLASS "XWinGLTest" - { - static wATOM glTestWndClass = 0; - if (glTestWndClass == 0) - { - WNDCLASSEX wc; - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = DefWindowProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = GetModuleHandle(NULL); - wc.hIcon = 0; - wc.hCursor = 0; - wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); - wc.lpszMenuName = NULL; - wc.lpszClassName = WIN_GL_TEST_WINDOW_CLASS; - wc.hIconSm = 0; - RegisterClassEx (&wc); - } - } - - // create an invisible window for a scratch DC - hwnd = CreateWindowExA(0, - WIN_GL_TEST_WINDOW_CLASS, - "XWin GL Renderer Capabilities Test Window", - 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL); - if (hwnd == NULL) - LogMessage(X_ERROR,"AIGLX: Couldn't create a window for render capabilities testing\n"); - - hdc = GetDC(hwnd); - - // we must set a pixel format before we can create a context, just use the first one... - SetPixelFormat(hdc, 1, NULL); - hglrc = wglCreateContext(hdc); - wglMakeCurrent(hdc, hglrc); - - // initialize wgl extension proc pointers (don't call them before here...) - // (but we need to have a current context for them to be resolvable) - wglResolveExtensionProcs(); - - ErrorF("GL_VERSION: %s\n", glGetStringWrapperNonstatic(GL_VERSION)); - ErrorF("GL_VENDOR: %s\n", glGetStringWrapperNonstatic(GL_VENDOR)); - ErrorF("GL_RENDERER: %s\n", glGetStringWrapperNonstatic(GL_RENDERER)); - gl_extensions = (const char *)glGetStringWrapperNonstatic(GL_EXTENSIONS); - glxLogExtensions("GL_EXTENSIONS: ", gl_extensions); - wgl_extensions = wglGetExtensionsStringARBWrapper(hdc); - if (!wgl_extensions) wgl_extensions = ""; - glxLogExtensions("WGL_EXTENSIONS: ", wgl_extensions); - - // Can you see the problem here? The extensions string is DC specific - // Different DCs for windows on a multimonitor system driven by multiple cards - // might have completely different capabilities. Of course, good luck getting - // those screens to be accelerated in XP and earlier... - - { - // testing facility to not use any WGL extensions - char *envptr = getenv("GLWIN_NO_WGL_EXTENSIONS"); - if ((envptr != NULL) && (atoi(envptr) != 0)) - { - ErrorF("GLWIN_NO_WGL_EXTENSIONS is set, ignoring WGL_EXTENSIONS\n"); - wgl_extensions = ""; - } - } - - { - Bool glx_sgi_make_current_read = FALSE; - - // - // Based on the WGL extensions available, enable various GLX extensions - // XXX: make this table-driven ? - // - memset(screen->glx_enable_bits, 0, __GLX_EXT_BYTES); - - __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_visual_info"); - __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_visual_rating"); - __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_import_context"); - __glXEnableExtension(screen->glx_enable_bits, "GLX_OML_swap_method"); - __glXEnableExtension(screen->glx_enable_bits, "GLX_SGIX_fbconfig"); - - if (strstr(wgl_extensions, "WGL_ARB_make_current_read")) - { - __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_make_current_read"); - LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); - glx_sgi_make_current_read = TRUE; - } - - if (strstr(gl_extensions, "GL_WIN_swap_hint")) - { - __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer"); - LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); - } - - if (strstr(wgl_extensions, "WGL_EXT_swap_control")) - { - __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_swap_control"); - __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_swap_control"); - LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); - } - -/* // Hmm? screen->texOffset */ -/* if (strstr(wgl_extensions, "WGL_ARB_render_texture")) */ -/* { */ -/* __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_texture_from_pixmap"); */ -/* LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); */ -/* screen->has_WGL_ARB_render_texture = TRUE; */ -/* } */ - - if (strstr(wgl_extensions, "WGL_ARB_pbuffer")) - { - __glXEnableExtension(screen->glx_enable_bits, "GLX_SGIX_pbuffer"); - LogMessage(X_INFO, "AIGLX: enabled GLX_SGIX_pbuffer\n"); - screen->has_WGL_ARB_pbuffer = TRUE; - } - - if (strstr(wgl_extensions, "WGL_ARB_multisample")) - { - __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_multisample"); - __glXEnableExtension(screen->glx_enable_bits, "GLX_SGIS_multisample"); - LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_multisample and GLX_SGIS_multisample\n"); - screen->has_WGL_ARB_multisample = TRUE; - } - - screen->base.destroy = glxWinScreenDestroy; - screen->base.createContext = glxWinCreateContext; - screen->base.createDrawable = glxWinCreateDrawable; - screen->base.swapInterval = glxWinScreenSwapInterval; - screen->base.hyperpipeFuncs = NULL; - screen->base.swapBarrierFuncs = NULL; - screen->base.pScreen = pScreen; - - if (strstr(wgl_extensions, "WGL_ARB_pixel_format")) - { - glxWinCreateConfigsExt(hdc, screen); - screen->has_WGL_ARB_pixel_format = TRUE; - } - else - { - glxWinCreateConfigs(hdc, screen); - screen->has_WGL_ARB_pixel_format = FALSE; - } - // Initializes screen->base.fbconfigs and screen->base.numFBConfigs - - /* These will be set by __glXScreenInit */ - screen->base.visuals = NULL; - screen->base.numVisuals = 0; - - __glXScreenInit(&screen->base, pScreen); - - // dump out fbConfigs now fbConfigIds and visualIDs have been assigned - fbConfigsDump(screen->base.numFBConfigs, screen->base.fbconfigs); - - // Override the GL extensions string set by __glXScreenInit() - screen->base.GLextensions = xstrdup(gl_extensions); - - // Generate the GLX extensions string (overrides that set by __glXScreenInit()) - { - unsigned int buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); - if (buffer_size > 0) - { - if (screen->base.GLXextensions != NULL) - { - xfree(screen->base.GLXextensions); - } - - screen->base.GLXextensions = xnfalloc(buffer_size); - __glXGetExtensionString(screen->glx_enable_bits, screen->base.GLXextensions); - } - } - - // - // Override the GLX version (__glXScreenInit() sets it to "1.2") - // if we have all the needed extensionsto operate as a higher version - // - // SGIX_fbconfig && SGIX_pbuffer && SGI_make_current_read -> 1.3 - // ARB_multisample -> 1.4 - // - if (screen->has_WGL_ARB_pbuffer && glx_sgi_make_current_read) - { - xfree(screen->base.GLXversion); - - if (screen->has_WGL_ARB_multisample) - { - screen->base.GLXversion = xstrdup("1.4"); - screen->base.GLXmajor = 1; - screen->base.GLXminor = 4; - } - else - { - screen->base.GLXversion = xstrdup("1.3"); - screen->base.GLXmajor = 1; - screen->base.GLXminor = 3; - } - LogMessage(X_INFO, "AIGLX: Set GLX version to %s\n", screen->base.GLXversion); - } - } - - wglMakeCurrent(NULL, NULL); - wglDeleteContext(hglrc); - ReleaseDC(hwnd, hdc); - DestroyWindow(hwnd); - - return &screen->base; -} - -/* ---------------------------------------------------------------------- */ -/* - * Window functions - */ - -static Bool -glxWinRealizeWindow(WindowPtr pWin) -{ - Bool result; - ScreenPtr pScreen = pWin->drawable.pScreen; - glxWinScreen *screenPriv = (glxWinScreen *) glxGetScreen(pScreen); - - GLWIN_DEBUG_MSG("glxWinRealizeWindow"); - - /* Allow the window to be created (RootlessRealizeWindow is inside our wrap) */ - pScreen->RealizeWindow = screenPriv->RealizeWindow; - result = pScreen->RealizeWindow(pWin); - pScreen->RealizeWindow = glxWinRealizeWindow; - - return result; -} - - -static void -glxWinCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - __GLXWinDrawable *pGlxDraw; - ScreenPtr pScreen = pWindow->drawable.pScreen; - glxWinScreen *screenPriv = (glxWinScreen *) glxGetScreen(pScreen); - - GLWIN_TRACE_MSG("glxWinCopyWindow pWindow %p", pWindow); - - dixLookupResourceByType((pointer) &pGlxDraw, pWindow->drawable.id, __glXDrawableRes, - NullClient, DixUnknownAccess); - - - /* - Discard any CopyWindow requests if a GL drawing context is pointing at the window - - For regions which are being drawn by GL, the shadow framebuffer doesn't have the - correct bits, so we wish to avoid shadow framebuffer damage occuring, which will - cause those incorrect bits to be transferred to the display.... - */ - if (pGlxDraw && pGlxDraw->drawContext) - { - GLWIN_DEBUG_MSG("glxWinCopyWindow: discarding"); - return; - } - - GLWIN_DEBUG_MSG("glxWinCopyWindow - passing to hw layer"); - - pScreen->CopyWindow = screenPriv->CopyWindow; - pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc); - pScreen->CopyWindow = glxWinCopyWindow; -} - -static Bool -glxWinUnrealizeWindow(WindowPtr pWin) -{ - Bool result; - ScreenPtr pScreen = pWin->drawable.pScreen; - glxWinScreen *screenPriv = (glxWinScreen *)glxGetScreen(pScreen); - - GLWIN_DEBUG_MSG("glxWinUnrealizeWindow"); - - pScreen->UnrealizeWindow = screenPriv->UnrealizeWindow; - result = pScreen->UnrealizeWindow(pWin); - pScreen->UnrealizeWindow = glxWinUnrealizeWindow; - - return result; -} - -/* ---------------------------------------------------------------------- */ -/* - * Drawable functions - */ - -static GLboolean -glxWinDrawableSwapBuffers(ClientPtr client, __GLXdrawable *base) -{ - HDC dc; - HWND hwnd; - BOOL ret; - __GLXWinDrawable *draw = (__GLXWinDrawable *)base; - - /* Swap buffers on the last active context for drawing on the drawable */ - if (draw->drawContext == NULL) - { - GLWIN_TRACE_MSG("glxWinSwapBuffers - no context for drawable"); - return GL_FALSE; - } - - GLWIN_TRACE_MSG("glxWinSwapBuffers on drawable %p, last context %p (native ctx %p)", base, draw->drawContext, draw->drawContext->ctx); - - /* - draw->drawContext->base.drawPriv will not be set if the context is not current anymore, - but if it is, it should point to this drawable.... - */ - assert((draw->drawContext->base.drawPriv == NULL) || (draw->drawContext->base.drawPriv == base)); - - dc = glxWinMakeDC(draw->drawContext, draw, &dc, &hwnd); - if (dc == NULL) - return GL_FALSE; - - ret = wglSwapLayerBuffers(dc, WGL_SWAP_MAIN_PLANE); - - glxWinReleaseDC(hwnd, dc, draw); - - if (!ret) - { - ErrorF("wglSwapBuffers failed: %s\n", glxWinErrorMessage()); - return GL_FALSE; - } - - return GL_TRUE; -} - -static void -glxWinDrawableCopySubBuffer(__GLXdrawable *drawable, - int x, int y, int w, int h) -{ - glAddSwapHintRectWINWrapperNonstatic(x, y, w, h); - glxWinDrawableSwapBuffers(NULL, drawable); -} - -static void -glxWinDrawableDestroy(__GLXdrawable *base) -{ - __GLXWinDrawable *glxPriv = (__GLXWinDrawable *)base; - - if (glxPriv->drawContext && (__glXLastContext == &((glxPriv->drawContext)->base))) - { - // if this context is current and has unflushed commands, say we have flushed them - // (don't actually flush them, the window is going away anyhow, and an implict flush occurs - // on the next context change) - // (GLX core considers it an error when we try to select a new current context if the old one - // has unflushed commands, but the window has disappeared..) - __GLX_NOTE_FLUSHED_CMDS(__glXLastContext); - __glXLastContext = NULL; - } - - if (glxPriv->hPbuffer) - if (!wglDestroyPbufferARBWrapper(glxPriv->hPbuffer)) - { - ErrorF("wglDestroyPbufferARB failed: %s\n", glxWinErrorMessage()); - } - - if (glxPriv->dibDC) - { - // restore the default DIB - SelectObject(glxPriv->dibDC, glxPriv->hOldDIB); - - if (!DeleteDC(glxPriv->dibDC)) - { - ErrorF("DeleteDC failed: %s\n", glxWinErrorMessage()); - } - } - - if (glxPriv->hDIB) - { - if (!DeleteObject(glxPriv->hDIB)) - { - ErrorF("DeleteObject failed: %s\n", glxWinErrorMessage()); - } - - ((PixmapPtr)glxPriv->base.pDraw)->devPrivate.ptr = glxPriv->pOldBits; - } - - GLWIN_DEBUG_MSG("glxWinDestroyDrawable"); - xfree(glxPriv); -} - -static __GLXdrawable * -glxWinCreateDrawable(__GLXscreen *screen, - DrawablePtr pDraw, - int type, - XID drawId, - __GLXconfig *conf) -{ - __GLXWinDrawable *glxPriv; - - glxPriv = xalloc(sizeof *glxPriv); - - if (glxPriv == NULL) - return NULL; - - memset(glxPriv, 0, sizeof *glxPriv); - - if(!__glXDrawableInit(&glxPriv->base, screen, pDraw, type, drawId, conf)) { - xfree(glxPriv); - return NULL; - } - - glxPriv->base.destroy = glxWinDrawableDestroy; - glxPriv->base.swapBuffers = glxWinDrawableSwapBuffers; - glxPriv->base.copySubBuffer = glxWinDrawableCopySubBuffer; - // glxPriv->base.waitX what are these for? - // glxPriv->base.waitGL - - GLWIN_DEBUG_MSG("glxWinCreateDrawable %p", glxPriv); - - return &glxPriv->base; -} - -/* ---------------------------------------------------------------------- */ -/* - * Texture functions - */ - -static -int glxWinBindTexImage(__GLXcontext *baseContext, - int buffer, - __GLXdrawable *pixmap) -{ - ErrorF("glxWinBindTexImage: not implemented\n"); - return FALSE; -} - -static -int glxWinReleaseTexImage(__GLXcontext *baseContext, - int buffer, - __GLXdrawable *pixmap) -{ - ErrorF(" glxWinReleaseTexImage: not implemented\n"); - return FALSE; -} - -/* ---------------------------------------------------------------------- */ -/* - * Lazy update context implementation - * - * WGL contexts are created for a specific HDC, so we cannot create the WGL - * context in glxWinCreateContext(), we must defer creation until the context - * is actually used on a specifc drawable which is connected to a native window, - * pbuffer or DIB - * - * The WGL context may be used on other, compatible HDCs, so we don't need to - * recreate it for every new native window - * - * XXX: I wonder why we can't create the WGL context on the screen HDC ? - * Basically we assume all HDCs are compatible at the moment: if they are not - * we are in a muddle, there was some code in the old implementation to attempt - * to transparently migrate a context to a new DC by copying state and sharing - * lists with the old one... - */ - -static void -glxWinSetPixelFormat(__GLXWinContext *gc, HDC hdc, int bppOverride, int drawableTypeOverride) -{ - __GLXscreen *screen = gc->base.pGlxScreen; - glxWinScreen *winScreen = (glxWinScreen *)screen; - - __GLXconfig *config = gc->base.config; - GLXWinConfig *winConfig = (GLXWinConfig *)config; - - GLWIN_DEBUG_MSG("glxWinSetPixelFormat: pixelFormatIndex %d", winConfig->pixelFormatIndex); - - /* - Normally, we can just use the the pixelFormatIndex corresponding - to the fbconfig which has been specified by the client - */ - - if (!((bppOverride && (bppOverride != (config->redBits + config->greenBits + config->blueBits) )) - || ((config->drawableType & drawableTypeOverride) == 0))) - { - if (!SetPixelFormat(hdc, winConfig->pixelFormatIndex, NULL)) - { - ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage()); - return; - } - - return; - } - - /* - However, in certain special cases this pixel format will be incompatible with the - use we are going to put it to, so we need to re-evaluate the pixel format to use: - - 1) When PFD_DRAW_TO_BITMAP is set, ChoosePixelFormat() always returns a format with - the cColorBits we asked for, so we need to ensure it matches the bpp of the bitmap - - 2) Applications may assume that visuals selected with glXChooseVisual() work with - pixmap drawables (there is no attribute to explicitly query for pixmap drawable - support as there is for glXChooseFBConfig()) - (it's arguable this is an error in the application, but we try to make it work) - - pixmap rendering is always slow for us, so we don't want to choose those visuals - by default, but if the actual drawable type we're trying to select the context - on (drawableTypeOverride) isn't supported by the selected fbConfig, reconsider - and see if we can find a suitable one... - */ - ErrorF("glxWinSetPixelFormat: having second thoughts: cColorbits %d, bppOveride %d; config->drawableType %d, drawableTypeOverride %d\n", - (config->redBits + config->greenBits + config->blueBits), bppOverride, config->drawableType, drawableTypeOverride); - - if (!winScreen->has_WGL_ARB_pixel_format) - { - PIXELFORMATDESCRIPTOR pfd; - int pixelFormat; - - /* convert fbConfig to PFD */ - if (fbConfigToPixelFormat(gc->base.config, &pfd, drawableTypeOverride)) - { - ErrorF("glxWinSetPixelFormat: fbConfigToPixelFormat failed\n"); - return; - } - - if (glxWinDebugSettings.dumpPFD) - pfdOut(&pfd); - - if (bppOverride) - { - GLWIN_DEBUG_MSG("glxWinSetPixelFormat: Forcing bpp from %d to %d\n", pfd.cColorBits, bppOverride); - pfd.cColorBits = bppOverride; - } - - pixelFormat = ChoosePixelFormat(hdc, &pfd); - if (pixelFormat == 0) - { - ErrorF("ChoosePixelFormat error: %s\n", glxWinErrorMessage()); - return; - } - - GLWIN_DEBUG_MSG("ChoosePixelFormat: chose pixelFormatIndex %d", pixelFormat); - ErrorF("ChoosePixelFormat: chose pixelFormatIndex %d (rather than %d as originally planned)\n", pixelFormat, winConfig->pixelFormatIndex); - - if (!SetPixelFormat(hdc, pixelFormat, &pfd)) - { - ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage()); - return; - } - } - else - { - int pixelFormat = fbConfigToPixelFormatIndex(hdc, gc->base.config, drawableTypeOverride, winScreen); - if (pixelFormat == 0) - { - ErrorF("wglChoosePixelFormat error: %s\n", glxWinErrorMessage()); - return; - } - - GLWIN_DEBUG_MSG("wglChoosePixelFormat: chose pixelFormatIndex %d", pixelFormat); - ErrorF("wglChoosePixelFormat: chose pixelFormatIndex %d (rather than %d as originally planned)\n", pixelFormat, winConfig->pixelFormatIndex); - - if (!SetPixelFormat(hdc, pixelFormat, NULL)) - { - ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage()); - return; - } - } -} - -static HDC -glxWinMakeDC(__GLXWinContext *gc, __GLXWinDrawable *draw, HDC *hdc, HWND *hwnd) -{ - *hdc = NULL; - *hwnd = NULL; - - if (draw == NULL) - { - GLWIN_TRACE_MSG("No drawable for context %p (native ctx %p)", gc, gc->ctx); - return NULL; - } - - switch (draw->base.type) - { - case GLX_DRAWABLE_WINDOW: - { - WindowPtr pWin; - - pWin = (WindowPtr) draw->base.pDraw; - if (pWin == NULL) - { - GLWIN_TRACE_MSG("for drawable %p, no WindowPtr", pWin); - return NULL; - } - - *hwnd = winGetWindowInfo(pWin); - - if (*hwnd == NULL) - { - ErrorF("No HWND error: %s\n", glxWinErrorMessage()); - return NULL; - } - - *hdc = GetDC(*hwnd); - - if (*hdc == NULL) - ErrorF("GetDC error: %s\n", glxWinErrorMessage()); - - /* Check if the hwnd has changed... */ - if (*hwnd != gc->hwnd) - { - if (glxWinDebugSettings.enableTrace) - GLWIN_DEBUG_HWND(*hwnd); - - GLWIN_TRACE_MSG("for context %p (native ctx %p), hWnd changed from %p to %p", gc, gc->ctx, gc->hwnd, *hwnd); - gc->hwnd = *hwnd; - - /* We must select a pixelformat, but SetPixelFormat can only be called once for a window... */ - glxWinSetPixelFormat(gc, *hdc, 0, GLX_WINDOW_BIT); - } - } - break; - - case GLX_DRAWABLE_PBUFFER: - { - *hdc = wglGetPbufferDCARBWrapper(draw->hPbuffer); - - if (*hdc == NULL) - ErrorF("GetDC (pbuffer) error: %s\n", glxWinErrorMessage()); - } - break; - - case GLX_DRAWABLE_PIXMAP: - { - *hdc = draw->dibDC; - } - break; - - default: - { - ErrorF("glxWinMakeDC: tried to makeDC for unhandled drawable type %d\n", draw->base.type); - } - } - - if (glxWinDebugSettings.dumpDC) - GLWIN_DEBUG_MSG("Got HDC %p", *hdc); - - return *hdc; -} - -static void -glxWinReleaseDC(HWND hwnd, HDC hdc,__GLXWinDrawable *draw) -{ - switch (draw->base.type) - { - case GLX_DRAWABLE_WINDOW: - { - ReleaseDC(hwnd, hdc); - } - break; - - case GLX_DRAWABLE_PBUFFER: - { - if (!wglReleasePbufferDCARBWrapper(draw->hPbuffer, hdc)) - { - ErrorF("wglReleasePbufferDCARB error: %s\n", glxWinErrorMessage()); - } - } - break; - - case GLX_DRAWABLE_PIXMAP: - { - // don't release DC, the memory DC lives as long as the bitmap - - // We must ensure that all GDI drawing into the bitmap has completed - // in case we subsequently access the bits from it - GdiFlush(); - } - break; - - default: - { - ErrorF("glxWinReleaseDC: tried to releaseDC for unhandled drawable type %d\n", draw->base.type); - } - } -} - -static void -glxWinDeferredCreateContext(__GLXWinContext *gc, __GLXWinDrawable *draw) -{ - HDC dc; - HWND hwnd; - GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: attach context %p to drawable %p", gc, draw); - - switch (draw->base.type) - { - case GLX_DRAWABLE_WINDOW: - { - WindowPtr pWin = (WindowPtr) draw->base.pDraw; - - if (!(gc->base.config->drawableType & GLX_WINDOW_BIT)) - { - ErrorF("glxWinDeferredCreateContext: tried to attach a context whose fbConfig doesn't have drawableType GLX_WINDOW_BIT to a GLX_DRAWABLE_WINDOW drawable\n"); - } - - if (pWin == NULL) - { - GLWIN_DEBUG_MSG("Deferring until X window is created"); - return; - } - - GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: pWin %p", pWin); - - if (winGetWindowInfo(pWin) == NULL) - { - GLWIN_DEBUG_MSG("Deferring until native window is created"); - return; - } - } - break; - - case GLX_DRAWABLE_PBUFFER: - { - if (draw->hPbuffer == NULL) - { - __GLXscreen *screen; - glxWinScreen *winScreen; - int pixelFormat; - // XXX: which DC are supposed to use??? - HDC screenDC = GetDC(NULL); - - if (!(gc->base.config->drawableType & GLX_PBUFFER_BIT)) - { - ErrorF("glxWinDeferredCreateContext: tried to attach a context whose fbConfig doesn't have drawableType GLX_PBUFFER_BIT to a GLX_DRAWABLE_PBUFFER drawable\n"); - } - - screen = gc->base.pGlxScreen; - winScreen = (glxWinScreen *)screen; - - pixelFormat = fbConfigToPixelFormatIndex(screenDC, gc->base.config, GLX_DRAWABLE_PBUFFER, winScreen); - if (pixelFormat == 0) - { - ErrorF("wglChoosePixelFormat error: %s\n", glxWinErrorMessage()); - return; - } - - draw->hPbuffer = wglCreatePbufferARBWrapper(screenDC, pixelFormat, draw->base.pDraw->width, draw->base.pDraw->height, NULL); - ReleaseDC(NULL, screenDC); - - if (draw->hPbuffer == NULL) - { - ErrorF("wglCreatePbufferARBWrapper error: %s\n", glxWinErrorMessage()); - return; - } - - GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: pBuffer %p created for drawable %p", draw->hPbuffer, draw); - } - } - break; - - case GLX_DRAWABLE_PIXMAP: - { - if (draw->dibDC == NULL) - { - BITMAPINFOHEADER bmpHeader; - void *pBits; - - memset (&bmpHeader, 0, sizeof(BITMAPINFOHEADER)); - bmpHeader.biSize = sizeof(BITMAPINFOHEADER); - bmpHeader.biWidth = draw->base.pDraw->width; - bmpHeader.biHeight = draw->base.pDraw->height; - bmpHeader.biPlanes = 1; - bmpHeader.biBitCount = draw->base.pDraw->bitsPerPixel; - bmpHeader.biCompression = BI_RGB; - - if (!(gc->base.config->drawableType & GLX_PIXMAP_BIT)) - { - ErrorF("glxWinDeferredCreateContext: tried to attach a context whose fbConfig doesn't have drawableType GLX_PIXMAP_BIT to a GLX_DRAWABLE_PIXMAP drawable\n"); - } - - draw->dibDC = CreateCompatibleDC(NULL); - if (draw->dibDC == NULL) - { - ErrorF("CreateCompatibleDC error: %s\n", glxWinErrorMessage()); - return; - } - - draw->hDIB = CreateDIBSection(draw->dibDC, (BITMAPINFO *)&bmpHeader, DIB_RGB_COLORS, &pBits, 0, 0); - if (draw->dibDC == NULL) - { - ErrorF("CreateDIBSection error: %s\n", glxWinErrorMessage()); - return; - } - - // XXX: CreateDIBSection insists on allocating the bitmap memory for us, so we're going to - // need some jiggery pokery to point the underlying X Drawable's bitmap at the same set of bits - // so that they can be read with XGetImage as well as glReadPixels, assuming the formats are - // even compatible ... - draw->pOldBits = ((PixmapPtr)draw->base.pDraw)->devPrivate.ptr; - ((PixmapPtr)draw->base.pDraw)->devPrivate.ptr = pBits; - - // Select the DIB into the DC - draw->hOldDIB = SelectObject(draw->dibDC, draw->hDIB); - if (!draw->hOldDIB) - { - ErrorF("SelectObject error: %s\n", glxWinErrorMessage()); - } - - // Set the pixel format of the bitmap - glxWinSetPixelFormat(gc, draw->dibDC, draw->base.pDraw->bitsPerPixel, GLX_PIXMAP_BIT); - - GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: DIB bitmap %p created for drawable %p", draw->hDIB, draw); - } - } - break; - - default: - { - ErrorF("glxWinDeferredCreateContext: tried to attach unhandled drawable type %d\n", draw->base.type); - return; - } - } - - dc = glxWinMakeDC(gc, draw, &dc, &hwnd); - gc->ctx = wglCreateContext(dc); - glxWinReleaseDC(hwnd, dc, draw); - - if (gc->ctx == NULL) - { - ErrorF("wglCreateContext error: %s\n", glxWinErrorMessage()); - return; - } - - GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: attached context %p to native context %p drawable %p", gc, gc->ctx, draw); - - // if the native context was created successfully, shareLists if needed - if (gc->ctx && gc->shareContext) - { - GLWIN_DEBUG_MSG("glxWinCreateContextReal shareLists with context %p (native ctx %p)", gc->shareContext, gc->shareContext->ctx); - - if (!wglShareLists(gc->shareContext->ctx, gc->ctx)) - { - ErrorF("wglShareLists error: %s\n", glxWinErrorMessage()); - } - } -} - -/* ---------------------------------------------------------------------- */ -/* - * Context functions - */ - - -/* Context manipulation routines should return TRUE on success, FALSE on failure */ -static int -glxWinContextMakeCurrent(__GLXcontext *base) -{ - __GLXWinContext *gc = (__GLXWinContext *)base; - BOOL ret; - HDC drawDC; - HDC readDC = NULL; - __GLXdrawable *drawPriv; - __GLXdrawable *readPriv = NULL; - HWND hDrawWnd; - HWND hReadWnd; - - GLWIN_TRACE_MSG("glxWinContextMakeCurrent context %p (native ctx %p)", gc, gc->ctx); - glWinCallDelta(); - - /* Keep a note of the last active context in the drawable */ - drawPriv = gc->base.drawPriv; - ((__GLXWinDrawable *)drawPriv)->drawContext = gc; - - if (gc->ctx == NULL) - { - glxWinDeferredCreateContext(gc, (__GLXWinDrawable *)drawPriv); - } - - if (gc->ctx == NULL) - { - ErrorF("glxWinContextMakeCurrent: Native context is NULL\n"); - return FALSE; - } - - drawDC = glxWinMakeDC(gc, (__GLXWinDrawable *)drawPriv, &drawDC, &hDrawWnd); - if (drawDC == NULL) - { - ErrorF("glxWinMakeDC failed for drawDC\n"); - return FALSE; - } - - if ((gc->base.readPriv != NULL) && (gc->base.readPriv != gc->base.drawPriv)) - { - // XXX: should only occur with WGL_ARB_make_current_read - /* - If there is a separate read drawable, create a separate read DC, and - use the wglMakeContextCurrent extension to make the context current drawing - to one DC and reading from the other - */ - readPriv = gc->base.readPriv; - readDC = glxWinMakeDC(gc, (__GLXWinDrawable *)readPriv, &readDC, &hReadWnd); - if (readDC == NULL) - { - ErrorF("glxWinMakeDC failed for readDC\n"); - glxWinReleaseDC(hDrawWnd, drawDC, (__GLXWinDrawable *)drawPriv); - return FALSE; - } - - ret = wglMakeContextCurrentARBWrapper(drawDC, readDC, gc->ctx); - if (!ret) - { - ErrorF("wglMakeContextCurrentARBWrapper error: %s\n", glxWinErrorMessage()); - } - } - else - { - /* Otherwise, just use wglMakeCurrent */ - ret = wglMakeCurrent(drawDC, gc->ctx); - if (!ret) - { - ErrorF("wglMakeCurrent error: %s\n", glxWinErrorMessage()); - } - } - - // apparently make current could fail if the context is current in a different thread, - // but that shouldn't be able to happen in the current server... - - glxWinReleaseDC(hDrawWnd, drawDC, (__GLXWinDrawable *)drawPriv); - if (readDC) - glxWinReleaseDC(hReadWnd, readDC, (__GLXWinDrawable *)readPriv); - - return ret; -} - -static int -glxWinContextLoseCurrent(__GLXcontext *base) -{ - BOOL ret; - __GLXWinContext *gc = (__GLXWinContext *)base; - - GLWIN_TRACE_MSG("glxWinContextLoseCurrent context %p (native ctx %p)", gc, gc->ctx); - glWinCallDelta(); - - /* - An error seems to be reported if we try to make no context current - if there is already no current context, so avoid doing that... - */ - if (__glXLastContext != NULL) - { - ret = wglMakeCurrent(NULL, NULL); /* We don't need a DC when setting no current context */ - if (!ret) - ErrorF("glxWinContextLoseCurrent error: %s\n", glxWinErrorMessage()); - } - - return TRUE; -} - -static int -glxWinContextCopy(__GLXcontext *dst_base, __GLXcontext *src_base, unsigned long mask) -{ - __GLXWinContext *dst = (__GLXWinContext *)dst_base; - __GLXWinContext *src = (__GLXWinContext *)src_base; - BOOL ret; - - GLWIN_DEBUG_MSG("glxWinContextCopy"); - - ret = wglCopyContext(src->ctx, dst->ctx, mask); - if (!ret) - { - ErrorF("wglCopyContext error: %s\n", glxWinErrorMessage()); - } - - return ret; -} - -static int -glxWinContextForceCurrent(__GLXcontext *base) -{ - /* wglMakeCurrent always flushes the previous context, so this is equivalent to glxWinContextMakeCurrent */ - return glxWinContextMakeCurrent(base); -} - -static void -glxWinContextDestroy(__GLXcontext *base) -{ - __GLXWinContext *gc = (__GLXWinContext *)base; - - if (gc != NULL) - { - GLWIN_DEBUG_MSG("GLXcontext %p destroyed (native ctx %p)", base, gc->ctx); - - if (gc->ctx) - { - /* It's bad style to delete the context while it's still current */ - if (wglGetCurrentContext() == gc->ctx) - { - wglMakeCurrent(NULL, NULL); - } - - { - BOOL ret = wglDeleteContext(gc->ctx); - if (!ret) - ErrorF("wglDeleteContext error: %s\n", glxWinErrorMessage()); - } - - gc->ctx = NULL; - } - - xfree(gc); - } -} - -static __GLXcontext * -glxWinCreateContext(__GLXscreen *screen, - __GLXconfig *modes, - __GLXcontext *baseShareContext) -{ - __GLXWinContext *context; - __GLXWinContext *shareContext = (__GLXWinContext *)baseShareContext; - - static __GLXtextureFromPixmap glxWinTextureFromPixmap = - { - glxWinBindTexImage, - glxWinReleaseTexImage - }; - - context = (__GLXWinContext *)xcalloc(1, sizeof(__GLXWinContext)); - - if (!context) - return NULL; - - memset(context, 0, sizeof *context); - context->base.destroy = glxWinContextDestroy; - context->base.makeCurrent = glxWinContextMakeCurrent; - context->base.loseCurrent = glxWinContextLoseCurrent; - context->base.copy = glxWinContextCopy; - context->base.forceCurrent = glxWinContextForceCurrent; - context->base.textureFromPixmap = &glxWinTextureFromPixmap; - context->base.config = modes; - context->base.pGlxScreen = screen; - - // actual native GL context creation is deferred until attach() - context->ctx = NULL; - context->shareContext = shareContext; - - glWinSetupDispatchTable(); - - GLWIN_DEBUG_MSG("GLXcontext %p created", context); - - return &(context->base); -} - -/* ---------------------------------------------------------------------- */ -/* - * Utility functions - */ - -static int -fbConfigToPixelFormat(__GLXconfig *mode, PIXELFORMATDESCRIPTOR *pfdret, int drawableTypeOverride) -{ - PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), /* size of this pfd */ - 1, /* version number */ - PFD_SUPPORT_OPENGL, /* support OpenGL */ - PFD_TYPE_RGBA, /* RGBA type */ - 24, /* 24-bit color depth */ - 0, 0, 0, 0, 0, 0, /* color bits ignored */ - 0, /* no alpha buffer */ - 0, /* shift bit ignored */ - 0, /* no accumulation buffer */ - 0, 0, 0, 0, /* accum bits ignored */ - 32, /* 32-bit z-buffer */ - 0, /* no stencil buffer */ - 0, /* no auxiliary buffer */ - PFD_MAIN_PLANE, /* main layer */ - 0, /* reserved */ - 0, 0, 0 /* layer masks ignored */ - }; - - if ((mode->drawableType | drawableTypeOverride) & GLX_WINDOW_BIT) - pfd.dwFlags |= PFD_DRAW_TO_WINDOW; /* support window */ - - if ((mode->drawableType | drawableTypeOverride) & GLX_PIXMAP_BIT) - pfd.dwFlags |= (PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI); /* supports software rendering to bitmap */ - - if (mode->stereoMode) { - pfd.dwFlags |= PFD_STEREO; - } - if (mode->doubleBufferMode) { - pfd.dwFlags |= PFD_DOUBLEBUFFER; - } - - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = mode->redBits + mode->greenBits + mode->blueBits; - pfd.cRedBits = mode->redBits; - pfd.cRedShift = 0; /* FIXME */ - pfd.cGreenBits = mode->greenBits; - pfd.cGreenShift = 0; /* FIXME */ - pfd.cBlueBits = mode->blueBits; - pfd.cBlueShift = 0; /* FIXME */ - pfd.cAlphaBits = mode->alphaBits; - pfd.cAlphaShift = 0; /* FIXME */ - - pfd.cAccumBits = mode->accumRedBits + mode->accumGreenBits + mode->accumBlueBits + mode->accumAlphaBits; - pfd.cAccumRedBits = mode->accumRedBits; - pfd.cAccumGreenBits = mode->accumGreenBits; - pfd.cAccumBlueBits = mode->accumBlueBits; - pfd.cAccumAlphaBits = mode->accumAlphaBits; - - pfd.cDepthBits = mode->depthBits; - pfd.cStencilBits = mode->stencilBits; - pfd.cAuxBuffers = mode->numAuxBuffers; - - /* mode->level ? */ - /* mode->pixmapMode ? */ - - *pfdret = pfd; - - return 0; -} - -#define SET_ATTR_VALUE(attr, value) { attribList[i++] = attr; attribList[i++] = value; assert(i < NUM_ELEMENTS(attribList)); } - -static int -fbConfigToPixelFormatIndex(HDC hdc, __GLXconfig *mode, int drawableTypeOverride, glxWinScreen *winScreen) -{ - UINT numFormats; - unsigned int i = 0; - - /* convert fbConfig to attr-value list */ - int attribList[60]; - - SET_ATTR_VALUE(WGL_SUPPORT_OPENGL_ARB, TRUE); - SET_ATTR_VALUE(WGL_PIXEL_TYPE_ARB, (mode->visualType == GLX_TRUE_COLOR) ? WGL_TYPE_RGBA_ARB : WGL_TYPE_COLORINDEX_ARB); - SET_ATTR_VALUE(WGL_COLOR_BITS_ARB, (mode->visualType == GLX_TRUE_COLOR) ? mode->rgbBits : mode->indexBits); - SET_ATTR_VALUE(WGL_RED_BITS_ARB, mode->redBits); - SET_ATTR_VALUE(WGL_GREEN_BITS_ARB, mode->greenBits); - SET_ATTR_VALUE(WGL_BLUE_BITS_ARB, mode->blueBits); - SET_ATTR_VALUE(WGL_ALPHA_BITS_ARB, mode->alphaBits); - SET_ATTR_VALUE(WGL_ACCUM_RED_BITS_ARB, mode->accumRedBits); - SET_ATTR_VALUE(WGL_ACCUM_GREEN_BITS_ARB, mode->accumGreenBits); - SET_ATTR_VALUE(WGL_ACCUM_BLUE_BITS_ARB, mode->accumBlueBits); - SET_ATTR_VALUE(WGL_ACCUM_ALPHA_BITS_ARB, mode->accumAlphaBits); - SET_ATTR_VALUE(WGL_DEPTH_BITS_ARB, mode->depthBits); - SET_ATTR_VALUE(WGL_STENCIL_BITS_ARB, mode->stencilBits); - SET_ATTR_VALUE(WGL_AUX_BUFFERS_ARB, mode->numAuxBuffers); - - if (mode->doubleBufferMode) - SET_ATTR_VALUE(WGL_DOUBLE_BUFFER_ARB, TRUE); - - if (mode->stereoMode) - SET_ATTR_VALUE(WGL_STEREO_ARB, TRUE); - - // Some attributes are only added to the list if the value requested is not 'don't care', as exactly matching that is daft.. - if (mode->swapMethod == GLX_SWAP_EXCHANGE_OML) - SET_ATTR_VALUE(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB); - - if (mode->swapMethod == GLX_SWAP_COPY_OML) - SET_ATTR_VALUE(WGL_SWAP_COPY_ARB, TRUE); - - // XXX: this should probably be the other way around, but that messes up drawableTypeOverride - if (mode->visualRating == GLX_SLOW_VISUAL_EXT) - SET_ATTR_VALUE(WGL_ACCELERATION_ARB, WGL_NO_ACCELERATION_ARB); - - // must support all the drawable types the mode supports - if ((mode->drawableType | drawableTypeOverride) & GLX_WINDOW_BIT) - SET_ATTR_VALUE(WGL_DRAW_TO_WINDOW_ARB,TRUE); - - // XXX: this is a horrible hacky heuristic, in fact this whole drawableTypeOverride thing is a bad idea - // try to avoid asking for formats which don't exist (by not asking for all when adjusting the config to include the drawableTypeOverride) - if (drawableTypeOverride == GLX_WINDOW_BIT) - { - if (mode->drawableType & GLX_PIXMAP_BIT) - SET_ATTR_VALUE(WGL_DRAW_TO_BITMAP_ARB, TRUE); - - if (mode->drawableType & GLX_PBUFFER_BIT) - if (winScreen->has_WGL_ARB_pbuffer) - SET_ATTR_VALUE(WGL_DRAW_TO_PBUFFER_ARB, TRUE); - } - else - { - if (drawableTypeOverride & GLX_PIXMAP_BIT) - SET_ATTR_VALUE(WGL_DRAW_TO_BITMAP_ARB, TRUE); - - if (drawableTypeOverride & GLX_PBUFFER_BIT) - if (winScreen->has_WGL_ARB_pbuffer) - SET_ATTR_VALUE(WGL_DRAW_TO_PBUFFER_ARB, TRUE); - } - - SET_ATTR_VALUE(0, 0); // terminator - - /* choose the first match */ - { - int pixelFormatIndex; - - if (!wglChoosePixelFormatARBWrapper(hdc, attribList, NULL, 1, &pixelFormatIndex, &numFormats)) - { - ErrorF("wglChoosePixelFormat error: %s\n", glxWinErrorMessage()); - } - else - { - if (numFormats > 0) - { - GLWIN_DEBUG_MSG("wglChoosePixelFormat: chose pixelFormatIndex %d)", pixelFormatIndex); - return pixelFormatIndex; - } - else - ErrorF("wglChoosePixelFormat couldn't decide\n"); - } - } - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -#define BITS_AND_SHIFT_TO_MASK(bits,mask) (((1<<(bits))-1) << (mask)) - -// -// Create the GLXconfigs using DescribePixelFormat() -// -static void -glxWinCreateConfigs(HDC hdc, glxWinScreen *screen) -{ - GLXWinConfig *c, *result, *prev = NULL; - int numConfigs = 0; - int i = 0; - int n = 0; - PIXELFORMATDESCRIPTOR pfd; - - GLWIN_DEBUG_MSG("glxWinCreateConfigs"); - - screen->base.numFBConfigs = 0; - screen->base.fbconfigs = NULL; - - // get the number of pixelformats - numConfigs = DescribePixelFormat(hdc, 1, sizeof(PIXELFORMATDESCRIPTOR), NULL); - GLWIN_DEBUG_MSG("DescribePixelFormat says %d possible pixel formats", numConfigs); - - /* alloc */ - result = xalloc(sizeof(GLXWinConfig) * numConfigs); - - if (NULL == result) - { - return; - } - - memset(result, 0, sizeof(GLXWinConfig) * numConfigs); - n = 0; - - /* fill in configs */ - for (i = 0; i < numConfigs; i++) - { - int rc; - - c = &(result[i]); - c->base.next = NULL; - c->pixelFormatIndex = i+1; - - rc = DescribePixelFormat(hdc, i+1, sizeof(PIXELFORMATDESCRIPTOR), &pfd); - - if (!rc) - { - ErrorF("DescribePixelFormat failed for index %d, error %s\n", i+1, glxWinErrorMessage()); - break; - } - - if (glxWinDebugSettings.dumpPFD) - pfdOut(&pfd); - - if (!(pfd.dwFlags & (PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP)) || !(pfd.dwFlags & PFD_SUPPORT_OPENGL)) - { - GLWIN_DEBUG_MSG("pixelFormat %d has unsuitable flags 0x%08lx, skipping", i+1, pfd.dwFlags); - continue; - } - - c->base.doubleBufferMode = (pfd.dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE; - c->base.stereoMode = (pfd.dwFlags & PFD_STEREO) ? GL_TRUE : GL_FALSE; - - c->base.redBits = pfd.cRedBits; - c->base.greenBits = pfd.cGreenBits; - c->base.blueBits = pfd.cBlueBits; - c->base.alphaBits = pfd.cAlphaBits; - - c->base.redMask = BITS_AND_SHIFT_TO_MASK(pfd.cRedBits, pfd.cRedShift); - c->base.greenMask = BITS_AND_SHIFT_TO_MASK(pfd.cGreenBits, pfd.cGreenShift); - c->base.blueMask = BITS_AND_SHIFT_TO_MASK(pfd.cBlueBits, pfd.cBlueShift); - c->base.alphaMask = BITS_AND_SHIFT_TO_MASK(pfd.cAlphaBits, pfd.cAlphaShift); - - c->base.rgbBits = pfd.cColorBits; - - if (pfd.iPixelType == PFD_TYPE_COLORINDEX) - { - c->base.indexBits = pfd.cColorBits; - } - else - { - c->base.indexBits = 0; - } - - c->base.accumRedBits = pfd.cAccumRedBits; - c->base.accumGreenBits = pfd.cAccumGreenBits; - c->base.accumBlueBits = pfd.cAccumBlueBits; - c->base.accumAlphaBits = pfd.cAccumAlphaBits; - // pfd.cAccumBits; - - c->base.depthBits = pfd.cDepthBits; - c->base.stencilBits = pfd.cStencilBits; - c->base.numAuxBuffers = pfd.cAuxBuffers; - - // pfd.iLayerType; // ignored - c->base.level = 0; - // pfd.dwLayerMask; // ignored - // pfd.dwDamageMask; // ignored - - c->base.pixmapMode = 0; - c->base.visualID = -1; // will be set by __glXScreenInit() - - /* EXT_visual_rating / GLX 1.2 */ - if (pfd.dwFlags & PFD_GENERIC_FORMAT) - { - c->base.visualRating = GLX_SLOW_VISUAL_EXT; - } - else - { - // PFD_GENERIC_ACCELERATED is not considered, so this may be MCD or ICD acclerated... - c->base.visualRating = GLX_NONE_EXT; - } - - /* EXT_visual_info / GLX 1.2 */ - if (pfd.iPixelType == PFD_TYPE_COLORINDEX) - { - c->base.visualType = GLX_STATIC_COLOR; - - if (!getenv("GLWIN_ENABLE_COLORINDEX_FBCONFIGS")) - { - GLWIN_DEBUG_MSG("pixelFormat %d is PFD_TYPE_COLORINDEX, skipping", i+1); - continue; - } - } - else - { - c->base.visualType = GLX_TRUE_COLOR; - } - - // pfd.dwVisibleMask; ??? - c->base.transparentPixel = GLX_NONE; - c->base.transparentRed = GLX_NONE; - c->base.transparentGreen = GLX_NONE; - c->base.transparentBlue = GLX_NONE; - c->base.transparentAlpha = GLX_NONE; - c->base.transparentIndex = GLX_NONE; - - /* ARB_multisample / SGIS_multisample */ - c->base.sampleBuffers = 0; - c->base.samples = 0; - - /* SGIX_fbconfig / GLX 1.3 */ - c->base.drawableType = (((pfd.dwFlags & PFD_DRAW_TO_WINDOW) ? GLX_WINDOW_BIT : 0) - | ((pfd.dwFlags & PFD_DRAW_TO_BITMAP) ? GLX_PIXMAP_BIT : 0)); - - if (pfd.iPixelType == PFD_TYPE_COLORINDEX) - { - c->base.renderType = GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT; - } - else - { - c->base.renderType = GLX_RGBA_BIT; - } - - c->base.xRenderable = GL_TRUE; - c->base.fbconfigID = -1; // will be set by __glXScreenInit() - - /* SGIX_pbuffer / GLX 1.3 */ - // XXX: How can we find these values out ??? - c->base.maxPbufferWidth = -1; - c->base.maxPbufferHeight = -1; - c->base.maxPbufferPixels = -1; - c->base.optimalPbufferWidth = 0; // there is no optimal value - c->base.optimalPbufferHeight = 0; - - /* SGIX_visual_select_group */ - // arrange for visuals with the best acceleration to be preferred in selection - switch (pfd.dwFlags & (PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED)) - { - case 0: - c->base.visualSelectGroup = 2; - break; - - case PFD_GENERIC_ACCELERATED: - c->base.visualSelectGroup = 1; - break; - - case PFD_GENERIC_FORMAT: - c->base.visualSelectGroup = 0; - break; - - default: - ; - // "can't happen" - } - - /* OML_swap_method */ - if (pfd.dwFlags & PFD_SWAP_EXCHANGE) - c->base.swapMethod = GLX_SWAP_EXCHANGE_OML; - else if (pfd.dwFlags & PFD_SWAP_COPY) - c->base.swapMethod = GLX_SWAP_COPY_OML; - else - c->base.swapMethod = GLX_SWAP_UNDEFINED_OML; - - /* EXT_import_context */ - c->base.screen = screen->base.pScreen->myNum; - - /* EXT_texture_from_pixmap */ - c->base.bindToTextureRgb = -1; - c->base.bindToTextureRgba = -1; - c->base.bindToMipmapTexture = -1; - c->base.bindToTextureTargets = -1; - c->base.yInverted = -1; - - n++; - - // update previous config to point to this config - if (prev) - prev->base.next = &(c->base); - - prev = c; - } - - GLWIN_DEBUG_MSG("found %d pixelFormats suitable for conversion to fbConfigs", n); - - screen->base.numFBConfigs = n; - screen->base.fbconfigs = &(result->base); -} - -// helper function to access an attribute value from an attribute value array by attribute -static -int getAttrValue(const int attrs[], int values[], unsigned int num, int attr, int fallback) -{ - unsigned int i; - for (i = 0; i < num; i++) - { - if (attrs[i] == attr) - { - GLWIN_TRACE_MSG("getAttrValue attr 0x%x, value %d", attr, values[i]); - return values[i]; - } - } - - ErrorF("getAttrValue failed to find attr 0x%x, using default value %d\n", attr, fallback); - return fallback; -} - -// -// Create the GLXconfigs using wglGetPixelFormatAttribfvARB() extension -// -static void -glxWinCreateConfigsExt(HDC hdc, glxWinScreen *screen) -{ - GLXWinConfig *c, *result, *prev = NULL; - int i = 0; - int n = 0; - - const int attr = WGL_NUMBER_PIXEL_FORMATS_ARB; - int numConfigs; - - int attrs[50]; - unsigned int num_attrs = 0; - - GLWIN_DEBUG_MSG("glxWinCreateConfigsExt"); - - screen->base.numFBConfigs = 0; - screen->base.fbconfigs = NULL; - - if (!wglGetPixelFormatAttribivARBWrapper(hdc, 0, 0, 1, &attr, &numConfigs)) - { - ErrorF("wglGetPixelFormatAttribivARB failed for WGL_NUMBER_PIXEL_FORMATS_ARB: %s\n", glxWinErrorMessage()); - return; - } - - GLWIN_DEBUG_MSG("wglGetPixelFormatAttribivARB says %d possible pixel formats", numConfigs); - - /* alloc */ - result = xalloc(sizeof(GLXWinConfig) * numConfigs); - - if (NULL == result) - { - return; - } - - memset(result, 0, sizeof(GLXWinConfig) * numConfigs); - n = 0; - -#define ADD_ATTR(a) { attrs[num_attrs++] = a; assert(num_attrs < NUM_ELEMENTS(attrs)); } - - ADD_ATTR(WGL_DRAW_TO_WINDOW_ARB); - ADD_ATTR(WGL_DRAW_TO_BITMAP_ARB); - ADD_ATTR(WGL_ACCELERATION_ARB); - ADD_ATTR(WGL_SWAP_LAYER_BUFFERS_ARB); - ADD_ATTR(WGL_NUMBER_OVERLAYS_ARB); - ADD_ATTR(WGL_NUMBER_UNDERLAYS_ARB); - ADD_ATTR(WGL_TRANSPARENT_ARB); - ADD_ATTR(WGL_TRANSPARENT_RED_VALUE_ARB); - ADD_ATTR(WGL_TRANSPARENT_GREEN_VALUE_ARB); - ADD_ATTR(WGL_TRANSPARENT_GREEN_VALUE_ARB); - ADD_ATTR(WGL_TRANSPARENT_ALPHA_VALUE_ARB); - ADD_ATTR(WGL_SUPPORT_OPENGL_ARB); - ADD_ATTR(WGL_DOUBLE_BUFFER_ARB); - ADD_ATTR(WGL_STEREO_ARB); - ADD_ATTR(WGL_PIXEL_TYPE_ARB); - ADD_ATTR(WGL_COLOR_BITS_ARB); - ADD_ATTR(WGL_RED_BITS_ARB); - ADD_ATTR(WGL_RED_SHIFT_ARB); - ADD_ATTR(WGL_GREEN_BITS_ARB); - ADD_ATTR(WGL_GREEN_SHIFT_ARB); - ADD_ATTR(WGL_BLUE_BITS_ARB); - ADD_ATTR(WGL_BLUE_SHIFT_ARB); - ADD_ATTR(WGL_ALPHA_BITS_ARB); - ADD_ATTR(WGL_ALPHA_SHIFT_ARB); - ADD_ATTR(WGL_ACCUM_RED_BITS_ARB); - ADD_ATTR(WGL_ACCUM_GREEN_BITS_ARB); - ADD_ATTR(WGL_ACCUM_BLUE_BITS_ARB); - ADD_ATTR(WGL_ACCUM_ALPHA_BITS_ARB); - ADD_ATTR(WGL_DEPTH_BITS_ARB); - ADD_ATTR(WGL_STENCIL_BITS_ARB); - ADD_ATTR(WGL_AUX_BUFFERS_ARB); - ADD_ATTR(WGL_SWAP_METHOD_ARB); - - if (screen->has_WGL_ARB_multisample) - { - // we may not query these attrs if WGL_ARB_multisample is not offered - ADD_ATTR(WGL_SAMPLE_BUFFERS_ARB); - ADD_ATTR(WGL_SAMPLES_ARB); - } - - if (screen->has_WGL_ARB_render_texture) - { - // we may not query these attrs if WGL_ARB_render_texture is not offered - ADD_ATTR(WGL_BIND_TO_TEXTURE_RGB_ARB); - ADD_ATTR(WGL_BIND_TO_TEXTURE_RGBA_ARB); - } - - if (screen->has_WGL_ARB_pbuffer) - { - // we may not query these attrs if WGL_ARB_pbuffer is not offered - ADD_ATTR(WGL_DRAW_TO_PBUFFER_ARB); - ADD_ATTR(WGL_MAX_PBUFFER_PIXELS_ARB); - ADD_ATTR(WGL_MAX_PBUFFER_WIDTH_ARB); - ADD_ATTR(WGL_MAX_PBUFFER_HEIGHT_ARB); - } - - /* fill in configs */ - for (i = 0; i < numConfigs; i++) - { - int values[num_attrs]; - - c = &(result[i]); - c->base.next = NULL; - c->pixelFormatIndex = i+1; - - if (!wglGetPixelFormatAttribivARBWrapper(hdc, i+1, 0, num_attrs, attrs, values)) - { - ErrorF("wglGetPixelFormatAttribivARB failed for index %d, error %s\n", i+1, glxWinErrorMessage()); - break; - } - -#define ATTR_VALUE(a, d) getAttrValue(attrs, values, num_attrs, (a), (d)) - - if (!ATTR_VALUE(WGL_SUPPORT_OPENGL_ARB, 0)) - { - GLWIN_DEBUG_MSG("pixelFormat %d isn't WGL_SUPPORT_OPENGL_ARB, skipping", i+1); - continue; - } - - c->base.doubleBufferMode = ATTR_VALUE(WGL_DOUBLE_BUFFER_ARB, 0) ? GL_TRUE : GL_FALSE; - c->base.stereoMode = ATTR_VALUE(WGL_STEREO_ARB, 0) ? GL_TRUE : GL_FALSE; - - c->base.redBits = ATTR_VALUE(WGL_RED_BITS_ARB, 0); - c->base.greenBits = ATTR_VALUE(WGL_GREEN_BITS_ARB, 0); - c->base.blueBits = ATTR_VALUE(WGL_BLUE_BITS_ARB, 0); - c->base.alphaBits = ATTR_VALUE(WGL_ALPHA_BITS_ARB, 0); - - c->base.redMask = BITS_AND_SHIFT_TO_MASK(c->base.redBits, ATTR_VALUE(WGL_RED_SHIFT_ARB, 0)); - c->base.greenMask = BITS_AND_SHIFT_TO_MASK(c->base.greenBits, ATTR_VALUE(WGL_GREEN_SHIFT_ARB, 0)); - c->base.blueMask = BITS_AND_SHIFT_TO_MASK(c->base.blueBits, ATTR_VALUE(WGL_BLUE_SHIFT_ARB, 0)); - c->base.alphaMask = BITS_AND_SHIFT_TO_MASK(c->base.alphaBits, ATTR_VALUE(WGL_ALPHA_SHIFT_ARB, 0)); - - switch (ATTR_VALUE(WGL_PIXEL_TYPE_ARB, 0)) - { - case WGL_TYPE_COLORINDEX_ARB: - c->base.indexBits = ATTR_VALUE(WGL_COLOR_BITS_ARB, 0); - c->base.rgbBits = 0; - c->base.visualType = GLX_STATIC_COLOR; - - if (!getenv("GLWIN_ENABLE_COLORINDEX_FBCONFIGS")) - { - GLWIN_DEBUG_MSG("pixelFormat %d is WGL_TYPE_COLORINDEX_ARB, skipping", i+1); - continue; - } - - break; - - case WGL_TYPE_RGBA_FLOAT_ARB: - GLWIN_DEBUG_MSG("pixelFormat %d is WGL_TYPE_RGBA_FLOAT_ARB, skipping", i+1); - continue; - - case WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT: - GLWIN_DEBUG_MSG("pixelFormat %d is WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT, skipping", i+1); - continue; - - case WGL_TYPE_RGBA_ARB: - c->base.indexBits = 0; - c->base.rgbBits = ATTR_VALUE(WGL_COLOR_BITS_ARB, 0); - c->base.visualType = GLX_TRUE_COLOR; - break; - - default: - ErrorF("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_PIXEL_TYPE_ARB\n", ATTR_VALUE(WGL_PIXEL_TYPE_ARB, 0)); - continue; - } - - c->base.accumRedBits = ATTR_VALUE(WGL_ACCUM_RED_BITS_ARB, 0); - c->base.accumGreenBits = ATTR_VALUE(WGL_ACCUM_GREEN_BITS_ARB, 0); - c->base.accumBlueBits = ATTR_VALUE(WGL_ACCUM_BLUE_BITS_ARB, 0); - c->base.accumAlphaBits = ATTR_VALUE(WGL_ACCUM_ALPHA_BITS_ARB, 0); - - c->base.depthBits = ATTR_VALUE(WGL_DEPTH_BITS_ARB, 0); - c->base.stencilBits = ATTR_VALUE(WGL_STENCIL_BITS_ARB, 0); - c->base.numAuxBuffers = ATTR_VALUE(WGL_AUX_BUFFERS_ARB, 0); - - { - int layers = ATTR_VALUE(WGL_NUMBER_OVERLAYS_ARB,0) + ATTR_VALUE(WGL_NUMBER_UNDERLAYS_ARB, 0); - - if (layers > 0) - { - ErrorF("pixelFormat %d: has %d overlay, %d underlays which aren't currently handled", i, ATTR_VALUE(WGL_NUMBER_OVERLAYS_ARB,0), ATTR_VALUE(WGL_NUMBER_UNDERLAYS_ARB, 0)); - // XXX: need to iterate over layers? - } - } - c->base.level = 0; - - c->base.pixmapMode = 0; // ??? - c->base.visualID = -1; // will be set by __glXScreenInit() - - /* EXT_visual_rating / GLX 1.2 */ - switch (ATTR_VALUE(WGL_ACCELERATION_ARB, 0)) - { - default: - ErrorF("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_ACCELERATION_ARB\n", ATTR_VALUE(WGL_ACCELERATION_ARB, 0)); - - case WGL_NO_ACCELERATION_ARB: - c->base.visualRating = GLX_SLOW_VISUAL_EXT; - break; - - case WGL_GENERIC_ACCELERATION_ARB: - case WGL_FULL_ACCELERATION_ARB: - c->base.visualRating = GLX_NONE_EXT; - break; - } - - /* EXT_visual_info / GLX 1.2 */ - // c->base.visualType is set above - if (ATTR_VALUE(WGL_TRANSPARENT_ARB, 0)) - { - c->base.transparentPixel = (c->base.visualType == GLX_TRUE_COLOR) ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT; - c->base.transparentRed = ATTR_VALUE(WGL_TRANSPARENT_RED_VALUE_ARB, 0); - c->base.transparentGreen = ATTR_VALUE(WGL_TRANSPARENT_GREEN_VALUE_ARB, 0); - c->base.transparentBlue = ATTR_VALUE(WGL_TRANSPARENT_BLUE_VALUE_ARB, 0); - c->base.transparentAlpha = ATTR_VALUE(WGL_TRANSPARENT_ALPHA_VALUE_ARB, 0); - c->base.transparentIndex = ATTR_VALUE(WGL_TRANSPARENT_INDEX_VALUE_ARB, 0); - } - else - { - c->base.transparentPixel = GLX_NONE_EXT; - c->base.transparentRed = GLX_NONE; - c->base.transparentGreen = GLX_NONE; - c->base.transparentBlue = GLX_NONE; - c->base.transparentAlpha = GLX_NONE; - c->base.transparentIndex = GLX_NONE; - } - - /* ARB_multisample / SGIS_multisample */ - if (screen->has_WGL_ARB_multisample) - { - c->base.sampleBuffers = ATTR_VALUE(WGL_SAMPLE_BUFFERS_ARB, 0); - c->base.samples = ATTR_VALUE(WGL_SAMPLES_ARB, 0); - } - else - { - c->base.sampleBuffers = 0; - c->base.samples = 0; - } - - /* SGIX_fbconfig / GLX 1.3 */ - c->base.drawableType = ((ATTR_VALUE(WGL_DRAW_TO_WINDOW_ARB, 0) ? GLX_WINDOW_BIT : 0) - | (ATTR_VALUE(WGL_DRAW_TO_BITMAP_ARB, 0) ? GLX_PIXMAP_BIT : 0) - | (ATTR_VALUE(WGL_DRAW_TO_PBUFFER_ARB, 0) ? GLX_PBUFFER_BIT : 0)); - - /* - Assume OpenGL RGBA rendering is available on all visuals - (it is specified to render to red component in single-channel visuals, - if supported, but there doesn't seem to be any mechanism to check if it - is supported) - - Color index rendering is only supported on single-channel visuals - */ - if (c->base.visualType == GLX_STATIC_COLOR) - { - c->base.renderType = GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT; - } - else - { - c->base.renderType = GLX_RGBA_BIT; - } - - c->base.xRenderable = GL_TRUE; - c->base.fbconfigID = -1; // will be set by __glXScreenInit() - - /* SGIX_pbuffer / GLX 1.3 */ - if (screen->has_WGL_ARB_pbuffer) - { - c->base.maxPbufferWidth = ATTR_VALUE(WGL_MAX_PBUFFER_WIDTH_ARB, -1); - c->base.maxPbufferHeight = ATTR_VALUE(WGL_MAX_PBUFFER_HEIGHT_ARB, -1); - c->base.maxPbufferPixels = ATTR_VALUE(WGL_MAX_PBUFFER_PIXELS_ARB, -1); - } - else - { - c->base.maxPbufferWidth = -1; - c->base.maxPbufferHeight = -1; - c->base.maxPbufferPixels = -1; - } - c->base.optimalPbufferWidth = 0; // there is no optimal value - c->base.optimalPbufferHeight = 0; - - /* SGIX_visual_select_group */ - // arrange for visuals with the best acceleration to be preferred in selection - switch (ATTR_VALUE(WGL_ACCELERATION_ARB, 0)) - { - case WGL_FULL_ACCELERATION_ARB: - c->base.visualSelectGroup = 2; - break; - - case WGL_GENERIC_ACCELERATION_ARB: - c->base.visualSelectGroup = 1; - break; - - default: - case WGL_NO_ACCELERATION_ARB: - c->base.visualSelectGroup = 0; - break; - } - - /* OML_swap_method */ - switch (ATTR_VALUE(WGL_SWAP_METHOD_ARB, 0)) - { - case WGL_SWAP_EXCHANGE_ARB: - c->base.swapMethod = GLX_SWAP_EXCHANGE_OML; - break; - - case WGL_SWAP_COPY_ARB: - c->base.swapMethod = GLX_SWAP_COPY_OML; - break; - - default: - ErrorF("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_SWAP_METHOD_ARB\n", ATTR_VALUE(WGL_SWAP_METHOD_ARB, 0)); - - case WGL_SWAP_UNDEFINED_ARB: - c->base.swapMethod = GLX_SWAP_UNDEFINED_OML; - } - - /* EXT_import_context */ - c->base.screen = screen->base.pScreen->myNum; - - /* EXT_texture_from_pixmap */ - /* - Mesa's DRI configs always have bindToTextureRgb/Rgba TRUE (see driCreateConfigs(), so setting - bindToTextureRgb/bindToTextureRgba to FALSE means that swrast can't find any fbConfigs to use, - so setting these to 0, even if we know bindToTexture isn't available, isn't a good idea... - */ - if (screen->has_WGL_ARB_render_texture) - { - c->base.bindToTextureRgb = ATTR_VALUE(WGL_BIND_TO_TEXTURE_RGB_ARB, -1); - c->base.bindToTextureRgba = ATTR_VALUE(WGL_BIND_TO_TEXTURE_RGBA_ARB, -1); - } - else - { - c->base.bindToTextureRgb = -1; - c->base.bindToTextureRgba = -1; - } - c->base.bindToMipmapTexture = -1; - c->base.bindToTextureTargets = GLX_TEXTURE_1D_BIT_EXT | GLX_TEXTURE_2D_BIT_EXT | GLX_TEXTURE_RECTANGLE_BIT_EXT; - c->base.yInverted = -1; - - n++; - - // update previous config to point to this config - if (prev) - prev->base.next = &(c->base); - - prev = c; - } - - screen->base.numFBConfigs = n; - screen->base.fbconfigs = &(result->base); -} +/* + * File: indirect.c + * Purpose: A GLX implementation that uses Windows OpenGL library + * + * Authors: Alexander Gottwald + * Jon TURNEY + * + * Copyright (c) Jon TURNEY 2009 + * Copyright (c) Alexander Gottwald 2004 + * + * Portions of this file are copied from GL/apple/indirect.c, + * which contains the following copyright: + * + * Copyright (c) 2007, 2008, 2009 Apple Inc. + * Copyright (c) 2004 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Greg Parker. All Rights Reserved. + * + * Portions of this file are copied from Mesa's xf86glx.c, + * which contains the following copyright: + * + * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. + * 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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. + */ + +/* + TODO: + - hook up remaining unimplemented extensions + - research what guarantees glXWaitX, glXWaitGL are supposed to offer, and implement then + using GdiFlush and/or glFinish + - pbuffer clobbering: we don't get async notification, but can we arrange to emit the + event when we notice it's been clobbered? at the very least, check if it's been clobbered + before using it? + - are the __GLXConfig * we get handed back ones we are made (so we can extend the structure + with privates?) Or are they created inside the GLX core as well? +*/ + +/* + MSDN clarifications: + + It says SetPixelFormat()'s PIXELFORMATDESCRIPTOR pointer argument has no effect + except on metafiles, this seems to mean that as it's ok to supply NULL if the DC + is not for a metafile + + wglMakeCurrent ignores the hdc if hglrc is NULL, so wglMakeCurrent(NULL, NULL) + is used to make no context current + +*/ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif + +#include "glwindows.h" +#include <glx/glxserver.h> +#include <glx/glxutil.h> +#include <glx/extension_string.h> +#include <GL/glxtokens.h> + +#include <winpriv.h> +#include <wgl_ext_api.h> + +#define NUM_ELEMENTS(x) (sizeof(x)/ sizeof(x[1])) + +/* ---------------------------------------------------------------------- */ +/* + * structure definitions + */ + +typedef struct __GLXWinContext __GLXWinContext; +typedef struct __GLXWinDrawable __GLXWinDrawable; +typedef struct __GLXWinScreen glxWinScreen; +typedef struct __GLXWinConfig GLXWinConfig; + +struct __GLXWinContext { + __GLXcontext base; + HGLRC ctx; /* Windows GL Context */ + __GLXWinContext *shareContext; /* Context with which we will share display lists and textures */ + HWND hwnd; /* For detecting when HWND has changed */ +}; + +struct __GLXWinDrawable +{ + __GLXdrawable base; + __GLXWinContext *drawContext; + __GLXWinContext *readContext; + + /* If this drawable is GLX_DRAWABLE_PBUFFER */ + HPBUFFERARB hPbuffer; + + /* If this drawable is GLX_DRAWABLE_PIXMAP */ + HDC dibDC; + HBITMAP hDIB; + HBITMAP hOldDIB; /* original DIB for DC */ + void *pOldBits; /* original pBits for this drawable's pixmap */ +}; + +struct __GLXWinScreen +{ + __GLXscreen base; + + /* Supported GLX extensions */ + unsigned char glx_enable_bits[__GLX_EXT_BYTES]; + + Bool has_WGL_ARB_multisample; + Bool has_WGL_ARB_pixel_format; + Bool has_WGL_ARB_pbuffer; + Bool has_WGL_ARB_render_texture; + + /* wrapped screen functions */ + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + CopyWindowProcPtr CopyWindow; +}; + +struct __GLXWinConfig +{ + __GLXconfig base; + int pixelFormatIndex; +}; + +/* ---------------------------------------------------------------------- */ +/* + * Various debug helpers + */ + +#define GLWIN_DEBUG_HWND(hwnd) \ + if (glxWinDebugSettings.dumpHWND) { \ + char buffer[1024]; \ + if (GetWindowText(hwnd, buffer, sizeof(buffer))==0) *buffer=0; \ + GLWIN_DEBUG_MSG("Got HWND %p for window '%s'", hwnd, buffer); \ + } + +glxWinDebugSettingsRec glxWinDebugSettings = { 0, 0, 0, 0, 0, 0}; + +static void glxWinInitDebugSettings(void) +{ + char *envptr; + + envptr = getenv("GLWIN_ENABLE_DEBUG"); + if (envptr != NULL) + glxWinDebugSettings.enableDebug = (atoi(envptr) == 1); + + envptr = getenv("GLWIN_ENABLE_TRACE"); + if (envptr != NULL) + glxWinDebugSettings.enableTrace = (atoi(envptr) == 1); + + envptr = getenv("GLWIN_DUMP_PFD"); + if (envptr != NULL) + glxWinDebugSettings.dumpPFD = (atoi(envptr) == 1); + + envptr = getenv("GLWIN_DUMP_HWND"); + if (envptr != NULL) + glxWinDebugSettings.dumpHWND = (atoi(envptr) == 1); + + envptr = getenv("GLWIN_DUMP_DC"); + if (envptr != NULL) + glxWinDebugSettings.dumpDC = (atoi(envptr) == 1); + + envptr = getenv("GLWIN_ENABLE_GLCALL_TRACE"); + if (envptr != NULL) + glxWinDebugSettings.enableGLcallTrace = (atoi(envptr) == 1); + + envptr = getenv("GLWIN_ENABLE_WGLCALL_TRACE"); + if (envptr != NULL) + glxWinDebugSettings.enableWGLcallTrace = (atoi(envptr) == 1); + + envptr = getenv("GLWIN_DEBUG_ALL"); + if (envptr != NULL) + { + glxWinDebugSettings.enableDebug = 1; + glxWinDebugSettings.enableTrace = 1; + glxWinDebugSettings.dumpPFD = 1; + glxWinDebugSettings.dumpHWND = 1; + glxWinDebugSettings.dumpDC = 1; + glxWinDebugSettings.enableGLcallTrace = 1; + glxWinDebugSettings.enableWGLcallTrace = 1; + } +} + +static +const char *glxWinErrorMessage(void) +{ + static char errorbuffer[1024]; + + if (!FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &errorbuffer, + sizeof(errorbuffer), + NULL )) + { + snprintf(errorbuffer, sizeof(errorbuffer), "Unknown error in FormatMessage: %08x!", (unsigned)GetLastError()); + } + + if (errorbuffer[strlen(errorbuffer)-1] == '\n') + errorbuffer[strlen(errorbuffer)-1] = 0; + + return errorbuffer; +} + +static void pfdOut(const PIXELFORMATDESCRIPTOR *pfd); + +#define DUMP_PFD_FLAG(flag) \ + if (pfd->dwFlags & flag) { \ + ErrorF("%s%s", pipesym, #flag); \ + pipesym = " | "; \ + } + +static void pfdOut(const PIXELFORMATDESCRIPTOR *pfd) +{ + const char *pipesym = ""; /* will be set after first flag dump */ + ErrorF("PIXELFORMATDESCRIPTOR:\n"); + ErrorF("nSize = %u\n", pfd->nSize); + ErrorF("nVersion = %u\n", pfd->nVersion); + ErrorF("dwFlags = %lu = {", pfd->dwFlags); + DUMP_PFD_FLAG(PFD_DOUBLEBUFFER); + DUMP_PFD_FLAG(PFD_STEREO); + DUMP_PFD_FLAG(PFD_DRAW_TO_WINDOW); + DUMP_PFD_FLAG(PFD_DRAW_TO_BITMAP); + DUMP_PFD_FLAG(PFD_SUPPORT_GDI); + DUMP_PFD_FLAG(PFD_SUPPORT_OPENGL); + DUMP_PFD_FLAG(PFD_GENERIC_FORMAT); + DUMP_PFD_FLAG(PFD_NEED_PALETTE); + DUMP_PFD_FLAG(PFD_NEED_SYSTEM_PALETTE); + DUMP_PFD_FLAG(PFD_SWAP_EXCHANGE); + DUMP_PFD_FLAG(PFD_SWAP_COPY); + DUMP_PFD_FLAG(PFD_SWAP_LAYER_BUFFERS); + DUMP_PFD_FLAG(PFD_GENERIC_ACCELERATED); + DUMP_PFD_FLAG(PFD_DEPTH_DONTCARE); + DUMP_PFD_FLAG(PFD_DOUBLEBUFFER_DONTCARE); + DUMP_PFD_FLAG(PFD_STEREO_DONTCARE); + ErrorF("}\n"); + + ErrorF("iPixelType = %hu = %s\n", pfd->iPixelType, + (pfd->iPixelType == PFD_TYPE_RGBA ? "PFD_TYPE_RGBA" : "PFD_TYPE_COLORINDEX")); + ErrorF("cColorBits = %hhu\n", pfd->cColorBits); + ErrorF("cRedBits = %hhu\n", pfd->cRedBits); + ErrorF("cRedShift = %hhu\n", pfd->cRedShift); + ErrorF("cGreenBits = %hhu\n", pfd->cGreenBits); + ErrorF("cGreenShift = %hhu\n", pfd->cGreenShift); + ErrorF("cBlueBits = %hhu\n", pfd->cBlueBits); + ErrorF("cBlueShift = %hhu\n", pfd->cBlueShift); + ErrorF("cAlphaBits = %hhu\n", pfd->cAlphaBits); + ErrorF("cAlphaShift = %hhu\n", pfd->cAlphaShift); + ErrorF("cAccumBits = %hhu\n", pfd->cAccumBits); + ErrorF("cAccumRedBits = %hhu\n", pfd->cAccumRedBits); + ErrorF("cAccumGreenBits = %hhu\n", pfd->cAccumGreenBits); + ErrorF("cAccumBlueBits = %hhu\n", pfd->cAccumBlueBits); + ErrorF("cAccumAlphaBits = %hhu\n", pfd->cAccumAlphaBits); + ErrorF("cDepthBits = %hhu\n", pfd->cDepthBits); + ErrorF("cStencilBits = %hhu\n", pfd->cStencilBits); + ErrorF("cAuxBuffers = %hhu\n", pfd->cAuxBuffers); + ErrorF("iLayerType = %hhu\n", pfd->iLayerType); + ErrorF("bReserved = %hhu\n", pfd->bReserved); + ErrorF("dwLayerMask = %lu\n", pfd->dwLayerMask); + ErrorF("dwVisibleMask = %lu\n", pfd->dwVisibleMask); + ErrorF("dwDamageMask = %lu\n", pfd->dwDamageMask); + ErrorF("\n"); +} + +static const char * +visual_class_name(int cls) +{ + switch (cls) { + case GLX_STATIC_COLOR: + return "StaticColor"; + case GLX_PSEUDO_COLOR: + return "PseudoColor"; + case GLX_STATIC_GRAY: + return "StaticGray"; + case GLX_GRAY_SCALE: + return "GrayScale"; + case GLX_TRUE_COLOR: + return "TrueColor"; + case GLX_DIRECT_COLOR: + return "DirectColor"; + default: + return "-none-"; + } +} + +static const char * +swap_method_name(int mthd) +{ + switch (mthd) + { + case GLX_SWAP_EXCHANGE_OML: + return "xchg"; + case GLX_SWAP_COPY_OML: + return "copy"; + case GLX_SWAP_UNDEFINED_OML: + return " "; + default: + return "????"; + } +} + +static void +fbConfigsDump(unsigned int n, __GLXconfig *c) +{ + ErrorF("%d fbConfigs\n", n); + ErrorF("pxf vis fb render Ste aux accum MS drawable Group/\n"); + ErrorF("idx ID ID VisualType Depth Lvl RGB CI DB Swap reo R G B A Z S buf AR AG AB AA bufs num W P Pb Float Trans Caveat\n"); + ErrorF("-----------------------------------------------------------------------------------------------------------------------------\n"); + + while (c != NULL) + { + unsigned int i = ((GLXWinConfig *)c)->pixelFormatIndex; + + ErrorF("%3d %2x %2x " + "%-11s" + " %3d %3d %s %s %s %s %s " + "%2d %2d %2d %2d " + "%2d %2d " + "%2d " + "%2d %2d %2d %2d" + " %2d %2d" + " %s %s %s " + " %s " + " %s " + " %d %s" + "\n", + i, c->visualID, c->fbconfigID, + visual_class_name(c->visualType), + c->rgbBits ? c->rgbBits : c->indexBits, + c->level, + (c->renderType & GLX_RGBA_BIT) ? "y" : ".", + (c->renderType & GLX_COLOR_INDEX_BIT) ? "y" : ".", + c->doubleBufferMode ? "y" : ".", + swap_method_name(c->swapMethod), + c->stereoMode ? "y" : ".", + c->redBits, c->greenBits, c->blueBits, c->alphaBits, + c->depthBits, c->stencilBits, + c->numAuxBuffers, + c->accumRedBits, c->accumGreenBits, c->accumBlueBits, c->accumAlphaBits, + c->sampleBuffers, c->samples, + (c->drawableType & GLX_WINDOW_BIT) ? "y" : ".", + (c->drawableType & GLX_PIXMAP_BIT) ? "y" : ".", + (c->drawableType & GLX_PBUFFER_BIT) ? "y" : ".", + ".", + (c->transparentPixel != GLX_NONE_EXT) ? "y" : ".", + c->visualSelectGroup, (c->visualRating == GLX_SLOW_VISUAL_EXT) ? "*" : " "); + + c = c->next; + } +} + +/* ---------------------------------------------------------------------- */ +/* + * Forward declarations + */ + +static __GLXscreen *glxWinScreenProbe(ScreenPtr pScreen); +static __GLXcontext *glxWinCreateContext(__GLXscreen *screen, + __GLXconfig *modes, + __GLXcontext *baseShareContext); +static __GLXdrawable *glxWinCreateDrawable(__GLXscreen *screen, + DrawablePtr pDraw, + int type, + XID drawId, + __GLXconfig *conf); + +static Bool glxWinRealizeWindow(WindowPtr pWin); +static Bool glxWinUnrealizeWindow(WindowPtr pWin); +static void glxWinCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc); + +static HDC glxWinMakeDC(__GLXWinContext *gc, __GLXWinDrawable *draw, HDC *hdc, HWND *hwnd); +static void glxWinReleaseDC(HWND hwnd, HDC hdc, __GLXWinDrawable *draw); + +static void glxWinCreateConfigs(HDC dc, glxWinScreen *screen); +static void glxWinCreateConfigsExt(HDC hdc, glxWinScreen *screen); +static int fbConfigToPixelFormat(__GLXconfig *mode, PIXELFORMATDESCRIPTOR *pfdret, int drawableTypeOverride); +static int fbConfigToPixelFormatIndex(HDC hdc, __GLXconfig *mode, int drawableTypeOverride, glxWinScreen *winScreen); + +/* ---------------------------------------------------------------------- */ +/* + * The GLX provider + */ + +__GLXprovider __glXWGLProvider = { + glxWinScreenProbe, + "Win32 native WGL", + NULL +}; + +void +glxWinPushNativeProvider(void) +{ + GlxPushProvider(&__glXWGLProvider); +} + +/* ---------------------------------------------------------------------- */ +/* + * Screen functions + */ + +static void +glxWinScreenDestroy(__GLXscreen *screen) +{ + GLWIN_DEBUG_MSG("glxWinScreenDestroy(%p)", screen); + __glXScreenDestroy(screen); + free(screen); +} + +static int +glxWinScreenSwapInterval(__GLXdrawable *drawable, int interval) +{ + BOOL ret = wglSwapIntervalEXTWrapper(interval); + if (!ret) + { + ErrorF("wglSwapIntervalEXT interval %d failed:%s\n", interval, glxWinErrorMessage()); + } + return ret; +} + +/* + Report the extensions split and formatted to avoid overflowing a line + */ +static void +glxLogExtensions(const char *prefix, const char *extensions) +{ + int length = 0; + char *strl; + char *str = malloc(strlen(extensions) + 1); + + if (str == NULL) + { + ErrorF("glxLogExtensions: xalloc error\n"); + return; + } + + str[strlen(extensions)] = '\0'; + strncpy (str, extensions, strlen(extensions)); + + strl = strtok(str, " "); + ErrorF("%s%s", prefix, strl); + length = strlen(prefix) + strlen(strl); + + while (1) + { + strl = strtok(NULL, " "); + if (strl == NULL) break; + + if (length + strlen(strl) + 1 > 120) + { + ErrorF("\n"); + ErrorF("%s",prefix); + length = strlen(prefix); + } + else + { + ErrorF(" "); + length++; + } + + ErrorF("%s", strl); + length = length + strlen(strl); + } + + ErrorF("\n"); + + free(str); +} + +/* This is called by GlxExtensionInit() asking the GLX provider if it can handle the screen... */ +static __GLXscreen * +glxWinScreenProbe(ScreenPtr pScreen) +{ + glxWinScreen *screen; + const char *gl_extensions; + const char *wgl_extensions; + HWND hwnd; + HDC hdc; + HGLRC hglrc; + + GLWIN_DEBUG_MSG("glxWinScreenProbe"); + + glxWinInitDebugSettings(); + + if (pScreen == NULL) + return NULL; + + if (!winCheckScreenAiglxIsSupported(pScreen)) + { + LogMessage(X_ERROR,"AIGLX: No native OpenGL in modes with a root window\n"); + return NULL; + } + + screen = calloc(1, sizeof(glxWinScreen)); + + if (NULL == screen) + return NULL; + + /* Wrap RealizeWindow, UnrealizeWindow and CopyWindow on this screen */ + screen->RealizeWindow = pScreen->RealizeWindow; + pScreen->RealizeWindow = glxWinRealizeWindow; + screen->UnrealizeWindow = pScreen->UnrealizeWindow; + pScreen->UnrealizeWindow = glxWinUnrealizeWindow; + screen->CopyWindow = pScreen->CopyWindow; + pScreen->CopyWindow = glxWinCopyWindow; + + /* Dump out some useful information about the native renderer */ + + // create window class +#define WIN_GL_TEST_WINDOW_CLASS "XWinGLTest" + { + static wATOM glTestWndClass = 0; + if (glTestWndClass == 0) + { + WNDCLASSEX wc; + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = DefWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandle(NULL); + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = WIN_GL_TEST_WINDOW_CLASS; + wc.hIconSm = 0; + RegisterClassEx (&wc); + } + } + + // create an invisible window for a scratch DC + hwnd = CreateWindowExA(0, + WIN_GL_TEST_WINDOW_CLASS, + "XWin GL Renderer Capabilities Test Window", + 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL); + if (hwnd == NULL) + LogMessage(X_ERROR,"AIGLX: Couldn't create a window for render capabilities testing\n"); + + hdc = GetDC(hwnd); + + // we must set a pixel format before we can create a context, just use the first one... + SetPixelFormat(hdc, 1, NULL); + hglrc = wglCreateContext(hdc); + wglMakeCurrent(hdc, hglrc); + + // initialize wgl extension proc pointers (don't call them before here...) + // (but we need to have a current context for them to be resolvable) + wglResolveExtensionProcs(); + + ErrorF("GL_VERSION: %s\n", glGetStringWrapperNonstatic(GL_VERSION)); + ErrorF("GL_VENDOR: %s\n", glGetStringWrapperNonstatic(GL_VENDOR)); + ErrorF("GL_RENDERER: %s\n", glGetStringWrapperNonstatic(GL_RENDERER)); + gl_extensions = (const char *)glGetStringWrapperNonstatic(GL_EXTENSIONS); + glxLogExtensions("GL_EXTENSIONS: ", gl_extensions); + wgl_extensions = wglGetExtensionsStringARBWrapper(hdc); + if (!wgl_extensions) wgl_extensions = ""; + glxLogExtensions("WGL_EXTENSIONS: ", wgl_extensions); + + // Can you see the problem here? The extensions string is DC specific + // Different DCs for windows on a multimonitor system driven by multiple cards + // might have completely different capabilities. Of course, good luck getting + // those screens to be accelerated in XP and earlier... + + { + // testing facility to not use any WGL extensions + char *envptr = getenv("GLWIN_NO_WGL_EXTENSIONS"); + if ((envptr != NULL) && (atoi(envptr) != 0)) + { + ErrorF("GLWIN_NO_WGL_EXTENSIONS is set, ignoring WGL_EXTENSIONS\n"); + wgl_extensions = ""; + } + } + + { + Bool glx_sgi_make_current_read = FALSE; + + // + // Based on the WGL extensions available, enable various GLX extensions + // XXX: make this table-driven ? + // + memset(screen->glx_enable_bits, 0, __GLX_EXT_BYTES); + + __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_visual_info"); + __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_visual_rating"); + __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_import_context"); + __glXEnableExtension(screen->glx_enable_bits, "GLX_OML_swap_method"); + __glXEnableExtension(screen->glx_enable_bits, "GLX_SGIX_fbconfig"); + + if (strstr(wgl_extensions, "WGL_ARB_make_current_read")) + { + __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_make_current_read"); + LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); + glx_sgi_make_current_read = TRUE; + } + + if (strstr(gl_extensions, "GL_WIN_swap_hint")) + { + __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer"); + LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); + } + + if (strstr(wgl_extensions, "WGL_EXT_swap_control")) + { + __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_swap_control"); + __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_swap_control"); + LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); + } + +/* // Hmm? screen->texOffset */ +/* if (strstr(wgl_extensions, "WGL_ARB_render_texture")) */ +/* { */ +/* __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_texture_from_pixmap"); */ +/* LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); */ +/* screen->has_WGL_ARB_render_texture = TRUE; */ +/* } */ + + if (strstr(wgl_extensions, "WGL_ARB_pbuffer")) + { + __glXEnableExtension(screen->glx_enable_bits, "GLX_SGIX_pbuffer"); + LogMessage(X_INFO, "AIGLX: enabled GLX_SGIX_pbuffer\n"); + screen->has_WGL_ARB_pbuffer = TRUE; + } + + if (strstr(wgl_extensions, "WGL_ARB_multisample")) + { + __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_multisample"); + __glXEnableExtension(screen->glx_enable_bits, "GLX_SGIS_multisample"); + LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_multisample and GLX_SGIS_multisample\n"); + screen->has_WGL_ARB_multisample = TRUE; + } + + screen->base.destroy = glxWinScreenDestroy; + screen->base.createContext = glxWinCreateContext; + screen->base.createDrawable = glxWinCreateDrawable; + screen->base.swapInterval = glxWinScreenSwapInterval; + screen->base.hyperpipeFuncs = NULL; + screen->base.swapBarrierFuncs = NULL; + screen->base.pScreen = pScreen; + + if (strstr(wgl_extensions, "WGL_ARB_pixel_format")) + { + glxWinCreateConfigsExt(hdc, screen); + screen->has_WGL_ARB_pixel_format = TRUE; + } + else + { + glxWinCreateConfigs(hdc, screen); + screen->has_WGL_ARB_pixel_format = FALSE; + } + // Initializes screen->base.fbconfigs and screen->base.numFBConfigs + + /* These will be set by __glXScreenInit */ + screen->base.visuals = NULL; + screen->base.numVisuals = 0; + + __glXScreenInit(&screen->base, pScreen); + + // dump out fbConfigs now fbConfigIds and visualIDs have been assigned + fbConfigsDump(screen->base.numFBConfigs, screen->base.fbconfigs); + + // Override the GL extensions string set by __glXScreenInit() + screen->base.GLextensions = xstrdup(gl_extensions); + + // Generate the GLX extensions string (overrides that set by __glXScreenInit()) + { + unsigned int buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); + if (buffer_size > 0) + { + if (screen->base.GLXextensions != NULL) + { + free(screen->base.GLXextensions); + } + + screen->base.GLXextensions = xnfalloc(buffer_size); + __glXGetExtensionString(screen->glx_enable_bits, screen->base.GLXextensions); + } + } + + // + // Override the GLX version (__glXScreenInit() sets it to "1.2") + // if we have all the needed extensionsto operate as a higher version + // + // SGIX_fbconfig && SGIX_pbuffer && SGI_make_current_read -> 1.3 + // ARB_multisample -> 1.4 + // + if (screen->has_WGL_ARB_pbuffer && glx_sgi_make_current_read) + { + free(screen->base.GLXversion); + + if (screen->has_WGL_ARB_multisample) + { + screen->base.GLXversion = xstrdup("1.4"); + screen->base.GLXmajor = 1; + screen->base.GLXminor = 4; + } + else + { + screen->base.GLXversion = xstrdup("1.3"); + screen->base.GLXmajor = 1; + screen->base.GLXminor = 3; + } + LogMessage(X_INFO, "AIGLX: Set GLX version to %s\n", screen->base.GLXversion); + } + } + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hglrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + + return &screen->base; +} + +/* ---------------------------------------------------------------------- */ +/* + * Window functions + */ + +static Bool +glxWinRealizeWindow(WindowPtr pWin) +{ + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + glxWinScreen *screenPriv = (glxWinScreen *) glxGetScreen(pScreen); + + GLWIN_DEBUG_MSG("glxWinRealizeWindow"); + + /* Allow the window to be created (RootlessRealizeWindow is inside our wrap) */ + pScreen->RealizeWindow = screenPriv->RealizeWindow; + result = pScreen->RealizeWindow(pWin); + pScreen->RealizeWindow = glxWinRealizeWindow; + + return result; +} + + +static void +glxWinCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + __GLXWinDrawable *pGlxDraw; + ScreenPtr pScreen = pWindow->drawable.pScreen; + glxWinScreen *screenPriv = (glxWinScreen *) glxGetScreen(pScreen); + + GLWIN_TRACE_MSG("glxWinCopyWindow pWindow %p", pWindow); + + dixLookupResourceByType((pointer) &pGlxDraw, pWindow->drawable.id, __glXDrawableRes, + NullClient, DixUnknownAccess); + + + /* + Discard any CopyWindow requests if a GL drawing context is pointing at the window + + For regions which are being drawn by GL, the shadow framebuffer doesn't have the + correct bits, so we wish to avoid shadow framebuffer damage occuring, which will + cause those incorrect bits to be transferred to the display.... + */ + if (pGlxDraw && pGlxDraw->drawContext) + { + GLWIN_DEBUG_MSG("glxWinCopyWindow: discarding"); + return; + } + + GLWIN_DEBUG_MSG("glxWinCopyWindow - passing to hw layer"); + + pScreen->CopyWindow = screenPriv->CopyWindow; + pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc); + pScreen->CopyWindow = glxWinCopyWindow; +} + +static Bool +glxWinUnrealizeWindow(WindowPtr pWin) +{ + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + glxWinScreen *screenPriv = (glxWinScreen *)glxGetScreen(pScreen); + + GLWIN_DEBUG_MSG("glxWinUnrealizeWindow"); + + pScreen->UnrealizeWindow = screenPriv->UnrealizeWindow; + result = pScreen->UnrealizeWindow(pWin); + pScreen->UnrealizeWindow = glxWinUnrealizeWindow; + + return result; +} + +/* ---------------------------------------------------------------------- */ +/* + * Drawable functions + */ + +static GLboolean +glxWinDrawableSwapBuffers(ClientPtr client, __GLXdrawable *base) +{ + HDC dc; + HWND hwnd; + BOOL ret; + __GLXWinDrawable *draw = (__GLXWinDrawable *)base; + + /* Swap buffers on the last active context for drawing on the drawable */ + if (draw->drawContext == NULL) + { + GLWIN_TRACE_MSG("glxWinSwapBuffers - no context for drawable"); + return GL_FALSE; + } + + GLWIN_TRACE_MSG("glxWinSwapBuffers on drawable %p, last context %p (native ctx %p)", base, draw->drawContext, draw->drawContext->ctx); + + /* + draw->drawContext->base.drawPriv will not be set if the context is not current anymore, + but if it is, it should point to this drawable.... + */ + assert((draw->drawContext->base.drawPriv == NULL) || (draw->drawContext->base.drawPriv == base)); + + dc = glxWinMakeDC(draw->drawContext, draw, &dc, &hwnd); + if (dc == NULL) + return GL_FALSE; + + ret = wglSwapLayerBuffers(dc, WGL_SWAP_MAIN_PLANE); + + glxWinReleaseDC(hwnd, dc, draw); + + if (!ret) + { + ErrorF("wglSwapBuffers failed: %s\n", glxWinErrorMessage()); + return GL_FALSE; + } + + return GL_TRUE; +} + +static void +glxWinDrawableCopySubBuffer(__GLXdrawable *drawable, + int x, int y, int w, int h) +{ + glAddSwapHintRectWINWrapperNonstatic(x, y, w, h); + glxWinDrawableSwapBuffers(NULL, drawable); +} + +static void +glxWinDrawableDestroy(__GLXdrawable *base) +{ + __GLXWinDrawable *glxPriv = (__GLXWinDrawable *)base; + + if (glxPriv->drawContext && (__glXLastContext == &((glxPriv->drawContext)->base))) + { + // if this context is current and has unflushed commands, say we have flushed them + // (don't actually flush them, the window is going away anyhow, and an implict flush occurs + // on the next context change) + // (GLX core considers it an error when we try to select a new current context if the old one + // has unflushed commands, but the window has disappeared..) + __GLX_NOTE_FLUSHED_CMDS(__glXLastContext); + __glXLastContext = NULL; + } + + if (glxPriv->hPbuffer) + if (!wglDestroyPbufferARBWrapper(glxPriv->hPbuffer)) + { + ErrorF("wglDestroyPbufferARB failed: %s\n", glxWinErrorMessage()); + } + + if (glxPriv->dibDC) + { + // restore the default DIB + SelectObject(glxPriv->dibDC, glxPriv->hOldDIB); + + if (!DeleteDC(glxPriv->dibDC)) + { + ErrorF("DeleteDC failed: %s\n", glxWinErrorMessage()); + } + } + + if (glxPriv->hDIB) + { + if (!DeleteObject(glxPriv->hDIB)) + { + ErrorF("DeleteObject failed: %s\n", glxWinErrorMessage()); + } + + ((PixmapPtr)glxPriv->base.pDraw)->devPrivate.ptr = glxPriv->pOldBits; + } + + GLWIN_DEBUG_MSG("glxWinDestroyDrawable"); + free(glxPriv); +} + +static __GLXdrawable * +glxWinCreateDrawable(__GLXscreen *screen, + DrawablePtr pDraw, + int type, + XID drawId, + __GLXconfig *conf) +{ + __GLXWinDrawable *glxPriv; + + glxPriv = malloc(sizeof *glxPriv); + + if (glxPriv == NULL) + return NULL; + + memset(glxPriv, 0, sizeof *glxPriv); + + if(!__glXDrawableInit(&glxPriv->base, screen, pDraw, type, drawId, conf)) { + free(glxPriv); + return NULL; + } + + glxPriv->base.destroy = glxWinDrawableDestroy; + glxPriv->base.swapBuffers = glxWinDrawableSwapBuffers; + glxPriv->base.copySubBuffer = glxWinDrawableCopySubBuffer; + // glxPriv->base.waitX what are these for? + // glxPriv->base.waitGL + + GLWIN_DEBUG_MSG("glxWinCreateDrawable %p", glxPriv); + + return &glxPriv->base; +} + +/* ---------------------------------------------------------------------- */ +/* + * Texture functions + */ + +static +int glxWinBindTexImage(__GLXcontext *baseContext, + int buffer, + __GLXdrawable *pixmap) +{ + ErrorF("glxWinBindTexImage: not implemented\n"); + return FALSE; +} + +static +int glxWinReleaseTexImage(__GLXcontext *baseContext, + int buffer, + __GLXdrawable *pixmap) +{ + ErrorF(" glxWinReleaseTexImage: not implemented\n"); + return FALSE; +} + +/* ---------------------------------------------------------------------- */ +/* + * Lazy update context implementation + * + * WGL contexts are created for a specific HDC, so we cannot create the WGL + * context in glxWinCreateContext(), we must defer creation until the context + * is actually used on a specifc drawable which is connected to a native window, + * pbuffer or DIB + * + * The WGL context may be used on other, compatible HDCs, so we don't need to + * recreate it for every new native window + * + * XXX: I wonder why we can't create the WGL context on the screen HDC ? + * Basically we assume all HDCs are compatible at the moment: if they are not + * we are in a muddle, there was some code in the old implementation to attempt + * to transparently migrate a context to a new DC by copying state and sharing + * lists with the old one... + */ + +static void +glxWinSetPixelFormat(__GLXWinContext *gc, HDC hdc, int bppOverride, int drawableTypeOverride) +{ + __GLXscreen *screen = gc->base.pGlxScreen; + glxWinScreen *winScreen = (glxWinScreen *)screen; + + __GLXconfig *config = gc->base.config; + GLXWinConfig *winConfig = (GLXWinConfig *)config; + + GLWIN_DEBUG_MSG("glxWinSetPixelFormat: pixelFormatIndex %d", winConfig->pixelFormatIndex); + + /* + Normally, we can just use the the pixelFormatIndex corresponding + to the fbconfig which has been specified by the client + */ + + if (!((bppOverride && (bppOverride != (config->redBits + config->greenBits + config->blueBits) )) + || ((config->drawableType & drawableTypeOverride) == 0))) + { + if (!SetPixelFormat(hdc, winConfig->pixelFormatIndex, NULL)) + { + ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage()); + return; + } + + return; + } + + /* + However, in certain special cases this pixel format will be incompatible with the + use we are going to put it to, so we need to re-evaluate the pixel format to use: + + 1) When PFD_DRAW_TO_BITMAP is set, ChoosePixelFormat() always returns a format with + the cColorBits we asked for, so we need to ensure it matches the bpp of the bitmap + + 2) Applications may assume that visuals selected with glXChooseVisual() work with + pixmap drawables (there is no attribute to explicitly query for pixmap drawable + support as there is for glXChooseFBConfig()) + (it's arguable this is an error in the application, but we try to make it work) + + pixmap rendering is always slow for us, so we don't want to choose those visuals + by default, but if the actual drawable type we're trying to select the context + on (drawableTypeOverride) isn't supported by the selected fbConfig, reconsider + and see if we can find a suitable one... + */ + ErrorF("glxWinSetPixelFormat: having second thoughts: cColorbits %d, bppOveride %d; config->drawableType %d, drawableTypeOverride %d\n", + (config->redBits + config->greenBits + config->blueBits), bppOverride, config->drawableType, drawableTypeOverride); + + if (!winScreen->has_WGL_ARB_pixel_format) + { + PIXELFORMATDESCRIPTOR pfd; + int pixelFormat; + + /* convert fbConfig to PFD */ + if (fbConfigToPixelFormat(gc->base.config, &pfd, drawableTypeOverride)) + { + ErrorF("glxWinSetPixelFormat: fbConfigToPixelFormat failed\n"); + return; + } + + if (glxWinDebugSettings.dumpPFD) + pfdOut(&pfd); + + if (bppOverride) + { + GLWIN_DEBUG_MSG("glxWinSetPixelFormat: Forcing bpp from %d to %d\n", pfd.cColorBits, bppOverride); + pfd.cColorBits = bppOverride; + } + + pixelFormat = ChoosePixelFormat(hdc, &pfd); + if (pixelFormat == 0) + { + ErrorF("ChoosePixelFormat error: %s\n", glxWinErrorMessage()); + return; + } + + GLWIN_DEBUG_MSG("ChoosePixelFormat: chose pixelFormatIndex %d", pixelFormat); + ErrorF("ChoosePixelFormat: chose pixelFormatIndex %d (rather than %d as originally planned)\n", pixelFormat, winConfig->pixelFormatIndex); + + if (!SetPixelFormat(hdc, pixelFormat, &pfd)) + { + ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage()); + return; + } + } + else + { + int pixelFormat = fbConfigToPixelFormatIndex(hdc, gc->base.config, drawableTypeOverride, winScreen); + if (pixelFormat == 0) + { + ErrorF("wglChoosePixelFormat error: %s\n", glxWinErrorMessage()); + return; + } + + GLWIN_DEBUG_MSG("wglChoosePixelFormat: chose pixelFormatIndex %d", pixelFormat); + ErrorF("wglChoosePixelFormat: chose pixelFormatIndex %d (rather than %d as originally planned)\n", pixelFormat, winConfig->pixelFormatIndex); + + if (!SetPixelFormat(hdc, pixelFormat, NULL)) + { + ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage()); + return; + } + } +} + +static HDC +glxWinMakeDC(__GLXWinContext *gc, __GLXWinDrawable *draw, HDC *hdc, HWND *hwnd) +{ + *hdc = NULL; + *hwnd = NULL; + + if (draw == NULL) + { + GLWIN_TRACE_MSG("No drawable for context %p (native ctx %p)", gc, gc->ctx); + return NULL; + } + + switch (draw->base.type) + { + case GLX_DRAWABLE_WINDOW: + { + WindowPtr pWin; + + pWin = (WindowPtr) draw->base.pDraw; + if (pWin == NULL) + { + GLWIN_TRACE_MSG("for drawable %p, no WindowPtr", pWin); + return NULL; + } + + *hwnd = winGetWindowInfo(pWin); + + if (*hwnd == NULL) + { + ErrorF("No HWND error: %s\n", glxWinErrorMessage()); + return NULL; + } + + *hdc = GetDC(*hwnd); + + if (*hdc == NULL) + ErrorF("GetDC error: %s\n", glxWinErrorMessage()); + + /* Check if the hwnd has changed... */ + if (*hwnd != gc->hwnd) + { + if (glxWinDebugSettings.enableTrace) + GLWIN_DEBUG_HWND(*hwnd); + + GLWIN_TRACE_MSG("for context %p (native ctx %p), hWnd changed from %p to %p", gc, gc->ctx, gc->hwnd, *hwnd); + gc->hwnd = *hwnd; + + /* We must select a pixelformat, but SetPixelFormat can only be called once for a window... */ + glxWinSetPixelFormat(gc, *hdc, 0, GLX_WINDOW_BIT); + } + } + break; + + case GLX_DRAWABLE_PBUFFER: + { + *hdc = wglGetPbufferDCARBWrapper(draw->hPbuffer); + + if (*hdc == NULL) + ErrorF("GetDC (pbuffer) error: %s\n", glxWinErrorMessage()); + } + break; + + case GLX_DRAWABLE_PIXMAP: + { + *hdc = draw->dibDC; + } + break; + + default: + { + ErrorF("glxWinMakeDC: tried to makeDC for unhandled drawable type %d\n", draw->base.type); + } + } + + if (glxWinDebugSettings.dumpDC) + GLWIN_DEBUG_MSG("Got HDC %p", *hdc); + + return *hdc; +} + +static void +glxWinReleaseDC(HWND hwnd, HDC hdc,__GLXWinDrawable *draw) +{ + switch (draw->base.type) + { + case GLX_DRAWABLE_WINDOW: + { + ReleaseDC(hwnd, hdc); + } + break; + + case GLX_DRAWABLE_PBUFFER: + { + if (!wglReleasePbufferDCARBWrapper(draw->hPbuffer, hdc)) + { + ErrorF("wglReleasePbufferDCARB error: %s\n", glxWinErrorMessage()); + } + } + break; + + case GLX_DRAWABLE_PIXMAP: + { + // don't release DC, the memory DC lives as long as the bitmap + + // We must ensure that all GDI drawing into the bitmap has completed + // in case we subsequently access the bits from it + GdiFlush(); + } + break; + + default: + { + ErrorF("glxWinReleaseDC: tried to releaseDC for unhandled drawable type %d\n", draw->base.type); + } + } +} + +static void +glxWinDeferredCreateContext(__GLXWinContext *gc, __GLXWinDrawable *draw) +{ + HDC dc; + HWND hwnd; + GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: attach context %p to drawable %p", gc, draw); + + switch (draw->base.type) + { + case GLX_DRAWABLE_WINDOW: + { + WindowPtr pWin = (WindowPtr) draw->base.pDraw; + + if (!(gc->base.config->drawableType & GLX_WINDOW_BIT)) + { + ErrorF("glxWinDeferredCreateContext: tried to attach a context whose fbConfig doesn't have drawableType GLX_WINDOW_BIT to a GLX_DRAWABLE_WINDOW drawable\n"); + } + + if (pWin == NULL) + { + GLWIN_DEBUG_MSG("Deferring until X window is created"); + return; + } + + GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: pWin %p", pWin); + + if (winGetWindowInfo(pWin) == NULL) + { + GLWIN_DEBUG_MSG("Deferring until native window is created"); + return; + } + } + break; + + case GLX_DRAWABLE_PBUFFER: + { + if (draw->hPbuffer == NULL) + { + __GLXscreen *screen; + glxWinScreen *winScreen; + int pixelFormat; + // XXX: which DC are supposed to use??? + HDC screenDC = GetDC(NULL); + + if (!(gc->base.config->drawableType & GLX_PBUFFER_BIT)) + { + ErrorF("glxWinDeferredCreateContext: tried to attach a context whose fbConfig doesn't have drawableType GLX_PBUFFER_BIT to a GLX_DRAWABLE_PBUFFER drawable\n"); + } + + screen = gc->base.pGlxScreen; + winScreen = (glxWinScreen *)screen; + + pixelFormat = fbConfigToPixelFormatIndex(screenDC, gc->base.config, GLX_DRAWABLE_PBUFFER, winScreen); + if (pixelFormat == 0) + { + ErrorF("wglChoosePixelFormat error: %s\n", glxWinErrorMessage()); + return; + } + + draw->hPbuffer = wglCreatePbufferARBWrapper(screenDC, pixelFormat, draw->base.pDraw->width, draw->base.pDraw->height, NULL); + ReleaseDC(NULL, screenDC); + + if (draw->hPbuffer == NULL) + { + ErrorF("wglCreatePbufferARBWrapper error: %s\n", glxWinErrorMessage()); + return; + } + + GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: pBuffer %p created for drawable %p", draw->hPbuffer, draw); + } + } + break; + + case GLX_DRAWABLE_PIXMAP: + { + if (draw->dibDC == NULL) + { + BITMAPINFOHEADER bmpHeader; + void *pBits; + + memset (&bmpHeader, 0, sizeof(BITMAPINFOHEADER)); + bmpHeader.biSize = sizeof(BITMAPINFOHEADER); + bmpHeader.biWidth = draw->base.pDraw->width; + bmpHeader.biHeight = draw->base.pDraw->height; + bmpHeader.biPlanes = 1; + bmpHeader.biBitCount = draw->base.pDraw->bitsPerPixel; + bmpHeader.biCompression = BI_RGB; + + if (!(gc->base.config->drawableType & GLX_PIXMAP_BIT)) + { + ErrorF("glxWinDeferredCreateContext: tried to attach a context whose fbConfig doesn't have drawableType GLX_PIXMAP_BIT to a GLX_DRAWABLE_PIXMAP drawable\n"); + } + + draw->dibDC = CreateCompatibleDC(NULL); + if (draw->dibDC == NULL) + { + ErrorF("CreateCompatibleDC error: %s\n", glxWinErrorMessage()); + return; + } + + draw->hDIB = CreateDIBSection(draw->dibDC, (BITMAPINFO *)&bmpHeader, DIB_RGB_COLORS, &pBits, 0, 0); + if (draw->dibDC == NULL) + { + ErrorF("CreateDIBSection error: %s\n", glxWinErrorMessage()); + return; + } + + // XXX: CreateDIBSection insists on allocating the bitmap memory for us, so we're going to + // need some jiggery pokery to point the underlying X Drawable's bitmap at the same set of bits + // so that they can be read with XGetImage as well as glReadPixels, assuming the formats are + // even compatible ... + draw->pOldBits = ((PixmapPtr)draw->base.pDraw)->devPrivate.ptr; + ((PixmapPtr)draw->base.pDraw)->devPrivate.ptr = pBits; + + // Select the DIB into the DC + draw->hOldDIB = SelectObject(draw->dibDC, draw->hDIB); + if (!draw->hOldDIB) + { + ErrorF("SelectObject error: %s\n", glxWinErrorMessage()); + } + + // Set the pixel format of the bitmap + glxWinSetPixelFormat(gc, draw->dibDC, draw->base.pDraw->bitsPerPixel, GLX_PIXMAP_BIT); + + GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: DIB bitmap %p created for drawable %p", draw->hDIB, draw); + } + } + break; + + default: + { + ErrorF("glxWinDeferredCreateContext: tried to attach unhandled drawable type %d\n", draw->base.type); + return; + } + } + + dc = glxWinMakeDC(gc, draw, &dc, &hwnd); + gc->ctx = wglCreateContext(dc); + glxWinReleaseDC(hwnd, dc, draw); + + if (gc->ctx == NULL) + { + ErrorF("wglCreateContext error: %s\n", glxWinErrorMessage()); + return; + } + + GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: attached context %p to native context %p drawable %p", gc, gc->ctx, draw); + + // if the native context was created successfully, shareLists if needed + if (gc->ctx && gc->shareContext) + { + GLWIN_DEBUG_MSG("glxWinCreateContextReal shareLists with context %p (native ctx %p)", gc->shareContext, gc->shareContext->ctx); + + if (!wglShareLists(gc->shareContext->ctx, gc->ctx)) + { + ErrorF("wglShareLists error: %s\n", glxWinErrorMessage()); + } + } +} + +/* ---------------------------------------------------------------------- */ +/* + * Context functions + */ + + +/* Context manipulation routines should return TRUE on success, FALSE on failure */ +static int +glxWinContextMakeCurrent(__GLXcontext *base) +{ + __GLXWinContext *gc = (__GLXWinContext *)base; + BOOL ret; + HDC drawDC; + HDC readDC = NULL; + __GLXdrawable *drawPriv; + __GLXdrawable *readPriv = NULL; + HWND hDrawWnd; + HWND hReadWnd; + + GLWIN_TRACE_MSG("glxWinContextMakeCurrent context %p (native ctx %p)", gc, gc->ctx); + glWinCallDelta(); + + /* Keep a note of the last active context in the drawable */ + drawPriv = gc->base.drawPriv; + ((__GLXWinDrawable *)drawPriv)->drawContext = gc; + + if (gc->ctx == NULL) + { + glxWinDeferredCreateContext(gc, (__GLXWinDrawable *)drawPriv); + } + + if (gc->ctx == NULL) + { + ErrorF("glxWinContextMakeCurrent: Native context is NULL\n"); + return FALSE; + } + + drawDC = glxWinMakeDC(gc, (__GLXWinDrawable *)drawPriv, &drawDC, &hDrawWnd); + if (drawDC == NULL) + { + ErrorF("glxWinMakeDC failed for drawDC\n"); + return FALSE; + } + + if ((gc->base.readPriv != NULL) && (gc->base.readPriv != gc->base.drawPriv)) + { + // XXX: should only occur with WGL_ARB_make_current_read + /* + If there is a separate read drawable, create a separate read DC, and + use the wglMakeContextCurrent extension to make the context current drawing + to one DC and reading from the other + */ + readPriv = gc->base.readPriv; + readDC = glxWinMakeDC(gc, (__GLXWinDrawable *)readPriv, &readDC, &hReadWnd); + if (readDC == NULL) + { + ErrorF("glxWinMakeDC failed for readDC\n"); + glxWinReleaseDC(hDrawWnd, drawDC, (__GLXWinDrawable *)drawPriv); + return FALSE; + } + + ret = wglMakeContextCurrentARBWrapper(drawDC, readDC, gc->ctx); + if (!ret) + { + ErrorF("wglMakeContextCurrentARBWrapper error: %s\n", glxWinErrorMessage()); + } + } + else + { + /* Otherwise, just use wglMakeCurrent */ + ret = wglMakeCurrent(drawDC, gc->ctx); + if (!ret) + { + ErrorF("wglMakeCurrent error: %s\n", glxWinErrorMessage()); + } + } + + // apparently make current could fail if the context is current in a different thread, + // but that shouldn't be able to happen in the current server... + + glxWinReleaseDC(hDrawWnd, drawDC, (__GLXWinDrawable *)drawPriv); + if (readDC) + glxWinReleaseDC(hReadWnd, readDC, (__GLXWinDrawable *)readPriv); + + return ret; +} + +static int +glxWinContextLoseCurrent(__GLXcontext *base) +{ + BOOL ret; + __GLXWinContext *gc = (__GLXWinContext *)base; + + GLWIN_TRACE_MSG("glxWinContextLoseCurrent context %p (native ctx %p)", gc, gc->ctx); + glWinCallDelta(); + + /* + An error seems to be reported if we try to make no context current + if there is already no current context, so avoid doing that... + */ + if (__glXLastContext != NULL) + { + ret = wglMakeCurrent(NULL, NULL); /* We don't need a DC when setting no current context */ + if (!ret) + ErrorF("glxWinContextLoseCurrent error: %s\n", glxWinErrorMessage()); + } + + return TRUE; +} + +static int +glxWinContextCopy(__GLXcontext *dst_base, __GLXcontext *src_base, unsigned long mask) +{ + __GLXWinContext *dst = (__GLXWinContext *)dst_base; + __GLXWinContext *src = (__GLXWinContext *)src_base; + BOOL ret; + + GLWIN_DEBUG_MSG("glxWinContextCopy"); + + ret = wglCopyContext(src->ctx, dst->ctx, mask); + if (!ret) + { + ErrorF("wglCopyContext error: %s\n", glxWinErrorMessage()); + } + + return ret; +} + +static int +glxWinContextForceCurrent(__GLXcontext *base) +{ + /* wglMakeCurrent always flushes the previous context, so this is equivalent to glxWinContextMakeCurrent */ + return glxWinContextMakeCurrent(base); +} + +static void +glxWinContextDestroy(__GLXcontext *base) +{ + __GLXWinContext *gc = (__GLXWinContext *)base; + + if (gc != NULL) + { + GLWIN_DEBUG_MSG("GLXcontext %p destroyed (native ctx %p)", base, gc->ctx); + + if (gc->ctx) + { + /* It's bad style to delete the context while it's still current */ + if (wglGetCurrentContext() == gc->ctx) + { + wglMakeCurrent(NULL, NULL); + } + + { + BOOL ret = wglDeleteContext(gc->ctx); + if (!ret) + ErrorF("wglDeleteContext error: %s\n", glxWinErrorMessage()); + } + + gc->ctx = NULL; + } + + free(gc); + } +} + +static __GLXcontext * +glxWinCreateContext(__GLXscreen *screen, + __GLXconfig *modes, + __GLXcontext *baseShareContext) +{ + __GLXWinContext *context; + __GLXWinContext *shareContext = (__GLXWinContext *)baseShareContext; + + static __GLXtextureFromPixmap glxWinTextureFromPixmap = + { + glxWinBindTexImage, + glxWinReleaseTexImage + }; + + context = (__GLXWinContext *)calloc(1, sizeof(__GLXWinContext)); + + if (!context) + return NULL; + + memset(context, 0, sizeof *context); + context->base.destroy = glxWinContextDestroy; + context->base.makeCurrent = glxWinContextMakeCurrent; + context->base.loseCurrent = glxWinContextLoseCurrent; + context->base.copy = glxWinContextCopy; + context->base.forceCurrent = glxWinContextForceCurrent; + context->base.textureFromPixmap = &glxWinTextureFromPixmap; + context->base.config = modes; + context->base.pGlxScreen = screen; + + // actual native GL context creation is deferred until attach() + context->ctx = NULL; + context->shareContext = shareContext; + + glWinSetupDispatchTable(); + + GLWIN_DEBUG_MSG("GLXcontext %p created", context); + + return &(context->base); +} + +/* ---------------------------------------------------------------------- */ +/* + * Utility functions + */ + +static int +fbConfigToPixelFormat(__GLXconfig *mode, PIXELFORMATDESCRIPTOR *pfdret, int drawableTypeOverride) +{ + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), /* size of this pfd */ + 1, /* version number */ + PFD_SUPPORT_OPENGL, /* support OpenGL */ + PFD_TYPE_RGBA, /* RGBA type */ + 24, /* 24-bit color depth */ + 0, 0, 0, 0, 0, 0, /* color bits ignored */ + 0, /* no alpha buffer */ + 0, /* shift bit ignored */ + 0, /* no accumulation buffer */ + 0, 0, 0, 0, /* accum bits ignored */ + 32, /* 32-bit z-buffer */ + 0, /* no stencil buffer */ + 0, /* no auxiliary buffer */ + PFD_MAIN_PLANE, /* main layer */ + 0, /* reserved */ + 0, 0, 0 /* layer masks ignored */ + }; + + if ((mode->drawableType | drawableTypeOverride) & GLX_WINDOW_BIT) + pfd.dwFlags |= PFD_DRAW_TO_WINDOW; /* support window */ + + if ((mode->drawableType | drawableTypeOverride) & GLX_PIXMAP_BIT) + pfd.dwFlags |= (PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI); /* supports software rendering to bitmap */ + + if (mode->stereoMode) { + pfd.dwFlags |= PFD_STEREO; + } + if (mode->doubleBufferMode) { + pfd.dwFlags |= PFD_DOUBLEBUFFER; + } + + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = mode->redBits + mode->greenBits + mode->blueBits; + pfd.cRedBits = mode->redBits; + pfd.cRedShift = 0; /* FIXME */ + pfd.cGreenBits = mode->greenBits; + pfd.cGreenShift = 0; /* FIXME */ + pfd.cBlueBits = mode->blueBits; + pfd.cBlueShift = 0; /* FIXME */ + pfd.cAlphaBits = mode->alphaBits; + pfd.cAlphaShift = 0; /* FIXME */ + + pfd.cAccumBits = mode->accumRedBits + mode->accumGreenBits + mode->accumBlueBits + mode->accumAlphaBits; + pfd.cAccumRedBits = mode->accumRedBits; + pfd.cAccumGreenBits = mode->accumGreenBits; + pfd.cAccumBlueBits = mode->accumBlueBits; + pfd.cAccumAlphaBits = mode->accumAlphaBits; + + pfd.cDepthBits = mode->depthBits; + pfd.cStencilBits = mode->stencilBits; + pfd.cAuxBuffers = mode->numAuxBuffers; + + /* mode->level ? */ + /* mode->pixmapMode ? */ + + *pfdret = pfd; + + return 0; +} + +#define SET_ATTR_VALUE(attr, value) { attribList[i++] = attr; attribList[i++] = value; assert(i < NUM_ELEMENTS(attribList)); } + +static int +fbConfigToPixelFormatIndex(HDC hdc, __GLXconfig *mode, int drawableTypeOverride, glxWinScreen *winScreen) +{ + UINT numFormats; + unsigned int i = 0; + + /* convert fbConfig to attr-value list */ + int attribList[60]; + + SET_ATTR_VALUE(WGL_SUPPORT_OPENGL_ARB, TRUE); + SET_ATTR_VALUE(WGL_PIXEL_TYPE_ARB, (mode->visualType == GLX_TRUE_COLOR) ? WGL_TYPE_RGBA_ARB : WGL_TYPE_COLORINDEX_ARB); + SET_ATTR_VALUE(WGL_COLOR_BITS_ARB, (mode->visualType == GLX_TRUE_COLOR) ? mode->rgbBits : mode->indexBits); + SET_ATTR_VALUE(WGL_RED_BITS_ARB, mode->redBits); + SET_ATTR_VALUE(WGL_GREEN_BITS_ARB, mode->greenBits); + SET_ATTR_VALUE(WGL_BLUE_BITS_ARB, mode->blueBits); + SET_ATTR_VALUE(WGL_ALPHA_BITS_ARB, mode->alphaBits); + SET_ATTR_VALUE(WGL_ACCUM_RED_BITS_ARB, mode->accumRedBits); + SET_ATTR_VALUE(WGL_ACCUM_GREEN_BITS_ARB, mode->accumGreenBits); + SET_ATTR_VALUE(WGL_ACCUM_BLUE_BITS_ARB, mode->accumBlueBits); + SET_ATTR_VALUE(WGL_ACCUM_ALPHA_BITS_ARB, mode->accumAlphaBits); + SET_ATTR_VALUE(WGL_DEPTH_BITS_ARB, mode->depthBits); + SET_ATTR_VALUE(WGL_STENCIL_BITS_ARB, mode->stencilBits); + SET_ATTR_VALUE(WGL_AUX_BUFFERS_ARB, mode->numAuxBuffers); + + if (mode->doubleBufferMode) + SET_ATTR_VALUE(WGL_DOUBLE_BUFFER_ARB, TRUE); + + if (mode->stereoMode) + SET_ATTR_VALUE(WGL_STEREO_ARB, TRUE); + + // Some attributes are only added to the list if the value requested is not 'don't care', as exactly matching that is daft.. + if (mode->swapMethod == GLX_SWAP_EXCHANGE_OML) + SET_ATTR_VALUE(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB); + + if (mode->swapMethod == GLX_SWAP_COPY_OML) + SET_ATTR_VALUE(WGL_SWAP_COPY_ARB, TRUE); + + // XXX: this should probably be the other way around, but that messes up drawableTypeOverride + if (mode->visualRating == GLX_SLOW_VISUAL_EXT) + SET_ATTR_VALUE(WGL_ACCELERATION_ARB, WGL_NO_ACCELERATION_ARB); + + // must support all the drawable types the mode supports + if ((mode->drawableType | drawableTypeOverride) & GLX_WINDOW_BIT) + SET_ATTR_VALUE(WGL_DRAW_TO_WINDOW_ARB,TRUE); + + // XXX: this is a horrible hacky heuristic, in fact this whole drawableTypeOverride thing is a bad idea + // try to avoid asking for formats which don't exist (by not asking for all when adjusting the config to include the drawableTypeOverride) + if (drawableTypeOverride == GLX_WINDOW_BIT) + { + if (mode->drawableType & GLX_PIXMAP_BIT) + SET_ATTR_VALUE(WGL_DRAW_TO_BITMAP_ARB, TRUE); + + if (mode->drawableType & GLX_PBUFFER_BIT) + if (winScreen->has_WGL_ARB_pbuffer) + SET_ATTR_VALUE(WGL_DRAW_TO_PBUFFER_ARB, TRUE); + } + else + { + if (drawableTypeOverride & GLX_PIXMAP_BIT) + SET_ATTR_VALUE(WGL_DRAW_TO_BITMAP_ARB, TRUE); + + if (drawableTypeOverride & GLX_PBUFFER_BIT) + if (winScreen->has_WGL_ARB_pbuffer) + SET_ATTR_VALUE(WGL_DRAW_TO_PBUFFER_ARB, TRUE); + } + + SET_ATTR_VALUE(0, 0); // terminator + + /* choose the first match */ + { + int pixelFormatIndex; + + if (!wglChoosePixelFormatARBWrapper(hdc, attribList, NULL, 1, &pixelFormatIndex, &numFormats)) + { + ErrorF("wglChoosePixelFormat error: %s\n", glxWinErrorMessage()); + } + else + { + if (numFormats > 0) + { + GLWIN_DEBUG_MSG("wglChoosePixelFormat: chose pixelFormatIndex %d)", pixelFormatIndex); + return pixelFormatIndex; + } + else + ErrorF("wglChoosePixelFormat couldn't decide\n"); + } + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +#define BITS_AND_SHIFT_TO_MASK(bits,mask) (((1<<(bits))-1) << (mask)) + +// +// Create the GLXconfigs using DescribePixelFormat() +// +static void +glxWinCreateConfigs(HDC hdc, glxWinScreen *screen) +{ + GLXWinConfig *c, *result, *prev = NULL; + int numConfigs = 0; + int i = 0; + int n = 0; + PIXELFORMATDESCRIPTOR pfd; + + GLWIN_DEBUG_MSG("glxWinCreateConfigs"); + + screen->base.numFBConfigs = 0; + screen->base.fbconfigs = NULL; + + // get the number of pixelformats + numConfigs = DescribePixelFormat(hdc, 1, sizeof(PIXELFORMATDESCRIPTOR), NULL); + GLWIN_DEBUG_MSG("DescribePixelFormat says %d possible pixel formats", numConfigs); + + /* alloc */ + result = malloc(sizeof(GLXWinConfig) * numConfigs); + + if (NULL == result) + { + return; + } + + memset(result, 0, sizeof(GLXWinConfig) * numConfigs); + n = 0; + + /* fill in configs */ + for (i = 0; i < numConfigs; i++) + { + int rc; + + c = &(result[i]); + c->base.next = NULL; + c->pixelFormatIndex = i+1; + + rc = DescribePixelFormat(hdc, i+1, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + if (!rc) + { + ErrorF("DescribePixelFormat failed for index %d, error %s\n", i+1, glxWinErrorMessage()); + break; + } + + if (glxWinDebugSettings.dumpPFD) + pfdOut(&pfd); + + if (!(pfd.dwFlags & (PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP)) || !(pfd.dwFlags & PFD_SUPPORT_OPENGL)) + { + GLWIN_DEBUG_MSG("pixelFormat %d has unsuitable flags 0x%08lx, skipping", i+1, pfd.dwFlags); + continue; + } + + c->base.doubleBufferMode = (pfd.dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE; + c->base.stereoMode = (pfd.dwFlags & PFD_STEREO) ? GL_TRUE : GL_FALSE; + + c->base.redBits = pfd.cRedBits; + c->base.greenBits = pfd.cGreenBits; + c->base.blueBits = pfd.cBlueBits; + c->base.alphaBits = pfd.cAlphaBits; + + c->base.redMask = BITS_AND_SHIFT_TO_MASK(pfd.cRedBits, pfd.cRedShift); + c->base.greenMask = BITS_AND_SHIFT_TO_MASK(pfd.cGreenBits, pfd.cGreenShift); + c->base.blueMask = BITS_AND_SHIFT_TO_MASK(pfd.cBlueBits, pfd.cBlueShift); + c->base.alphaMask = BITS_AND_SHIFT_TO_MASK(pfd.cAlphaBits, pfd.cAlphaShift); + + c->base.rgbBits = pfd.cColorBits; + + if (pfd.iPixelType == PFD_TYPE_COLORINDEX) + { + c->base.indexBits = pfd.cColorBits; + } + else + { + c->base.indexBits = 0; + } + + c->base.accumRedBits = pfd.cAccumRedBits; + c->base.accumGreenBits = pfd.cAccumGreenBits; + c->base.accumBlueBits = pfd.cAccumBlueBits; + c->base.accumAlphaBits = pfd.cAccumAlphaBits; + // pfd.cAccumBits; + + c->base.depthBits = pfd.cDepthBits; + c->base.stencilBits = pfd.cStencilBits; + c->base.numAuxBuffers = pfd.cAuxBuffers; + + // pfd.iLayerType; // ignored + c->base.level = 0; + // pfd.dwLayerMask; // ignored + // pfd.dwDamageMask; // ignored + + c->base.pixmapMode = 0; + c->base.visualID = -1; // will be set by __glXScreenInit() + + /* EXT_visual_rating / GLX 1.2 */ + if (pfd.dwFlags & PFD_GENERIC_FORMAT) + { + c->base.visualRating = GLX_SLOW_VISUAL_EXT; + } + else + { + // PFD_GENERIC_ACCELERATED is not considered, so this may be MCD or ICD acclerated... + c->base.visualRating = GLX_NONE_EXT; + } + + /* EXT_visual_info / GLX 1.2 */ + if (pfd.iPixelType == PFD_TYPE_COLORINDEX) + { + c->base.visualType = GLX_STATIC_COLOR; + + if (!getenv("GLWIN_ENABLE_COLORINDEX_FBCONFIGS")) + { + GLWIN_DEBUG_MSG("pixelFormat %d is PFD_TYPE_COLORINDEX, skipping", i+1); + continue; + } + } + else + { + c->base.visualType = GLX_TRUE_COLOR; + } + + // pfd.dwVisibleMask; ??? + c->base.transparentPixel = GLX_NONE; + c->base.transparentRed = GLX_NONE; + c->base.transparentGreen = GLX_NONE; + c->base.transparentBlue = GLX_NONE; + c->base.transparentAlpha = GLX_NONE; + c->base.transparentIndex = GLX_NONE; + + /* ARB_multisample / SGIS_multisample */ + c->base.sampleBuffers = 0; + c->base.samples = 0; + + /* SGIX_fbconfig / GLX 1.3 */ + c->base.drawableType = (((pfd.dwFlags & PFD_DRAW_TO_WINDOW) ? GLX_WINDOW_BIT : 0) + | ((pfd.dwFlags & PFD_DRAW_TO_BITMAP) ? GLX_PIXMAP_BIT : 0)); + + if (pfd.iPixelType == PFD_TYPE_COLORINDEX) + { + c->base.renderType = GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT; + } + else + { + c->base.renderType = GLX_RGBA_BIT; + } + + c->base.xRenderable = GL_TRUE; + c->base.fbconfigID = -1; // will be set by __glXScreenInit() + + /* SGIX_pbuffer / GLX 1.3 */ + // XXX: How can we find these values out ??? + c->base.maxPbufferWidth = -1; + c->base.maxPbufferHeight = -1; + c->base.maxPbufferPixels = -1; + c->base.optimalPbufferWidth = 0; // there is no optimal value + c->base.optimalPbufferHeight = 0; + + /* SGIX_visual_select_group */ + // arrange for visuals with the best acceleration to be preferred in selection + switch (pfd.dwFlags & (PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED)) + { + case 0: + c->base.visualSelectGroup = 2; + break; + + case PFD_GENERIC_ACCELERATED: + c->base.visualSelectGroup = 1; + break; + + case PFD_GENERIC_FORMAT: + c->base.visualSelectGroup = 0; + break; + + default: + ; + // "can't happen" + } + + /* OML_swap_method */ + if (pfd.dwFlags & PFD_SWAP_EXCHANGE) + c->base.swapMethod = GLX_SWAP_EXCHANGE_OML; + else if (pfd.dwFlags & PFD_SWAP_COPY) + c->base.swapMethod = GLX_SWAP_COPY_OML; + else + c->base.swapMethod = GLX_SWAP_UNDEFINED_OML; + + /* EXT_import_context */ + c->base.screen = screen->base.pScreen->myNum; + + /* EXT_texture_from_pixmap */ + c->base.bindToTextureRgb = -1; + c->base.bindToTextureRgba = -1; + c->base.bindToMipmapTexture = -1; + c->base.bindToTextureTargets = -1; + c->base.yInverted = -1; + + n++; + + // update previous config to point to this config + if (prev) + prev->base.next = &(c->base); + + prev = c; + } + + GLWIN_DEBUG_MSG("found %d pixelFormats suitable for conversion to fbConfigs", n); + + screen->base.numFBConfigs = n; + screen->base.fbconfigs = &(result->base); +} + +// helper function to access an attribute value from an attribute value array by attribute +static +int getAttrValue(const int attrs[], int values[], unsigned int num, int attr, int fallback) +{ + unsigned int i; + for (i = 0; i < num; i++) + { + if (attrs[i] == attr) + { + GLWIN_TRACE_MSG("getAttrValue attr 0x%x, value %d", attr, values[i]); + return values[i]; + } + } + + ErrorF("getAttrValue failed to find attr 0x%x, using default value %d\n", attr, fallback); + return fallback; +} + +// +// Create the GLXconfigs using wglGetPixelFormatAttribfvARB() extension +// +static void +glxWinCreateConfigsExt(HDC hdc, glxWinScreen *screen) +{ + GLXWinConfig *c, *result, *prev = NULL; + int i = 0; + int n = 0; + + const int attr = WGL_NUMBER_PIXEL_FORMATS_ARB; + int numConfigs; + + int attrs[50]; + unsigned int num_attrs = 0; + + GLWIN_DEBUG_MSG("glxWinCreateConfigsExt"); + + screen->base.numFBConfigs = 0; + screen->base.fbconfigs = NULL; + + if (!wglGetPixelFormatAttribivARBWrapper(hdc, 0, 0, 1, &attr, &numConfigs)) + { + ErrorF("wglGetPixelFormatAttribivARB failed for WGL_NUMBER_PIXEL_FORMATS_ARB: %s\n", glxWinErrorMessage()); + return; + } + + GLWIN_DEBUG_MSG("wglGetPixelFormatAttribivARB says %d possible pixel formats", numConfigs); + + /* alloc */ + result = malloc(sizeof(GLXWinConfig) * numConfigs); + + if (NULL == result) + { + return; + } + + memset(result, 0, sizeof(GLXWinConfig) * numConfigs); + n = 0; + +#define ADD_ATTR(a) { attrs[num_attrs++] = a; assert(num_attrs < NUM_ELEMENTS(attrs)); } + + ADD_ATTR(WGL_DRAW_TO_WINDOW_ARB); + ADD_ATTR(WGL_DRAW_TO_BITMAP_ARB); + ADD_ATTR(WGL_ACCELERATION_ARB); + ADD_ATTR(WGL_SWAP_LAYER_BUFFERS_ARB); + ADD_ATTR(WGL_NUMBER_OVERLAYS_ARB); + ADD_ATTR(WGL_NUMBER_UNDERLAYS_ARB); + ADD_ATTR(WGL_TRANSPARENT_ARB); + ADD_ATTR(WGL_TRANSPARENT_RED_VALUE_ARB); + ADD_ATTR(WGL_TRANSPARENT_GREEN_VALUE_ARB); + ADD_ATTR(WGL_TRANSPARENT_GREEN_VALUE_ARB); + ADD_ATTR(WGL_TRANSPARENT_ALPHA_VALUE_ARB); + ADD_ATTR(WGL_SUPPORT_OPENGL_ARB); + ADD_ATTR(WGL_DOUBLE_BUFFER_ARB); + ADD_ATTR(WGL_STEREO_ARB); + ADD_ATTR(WGL_PIXEL_TYPE_ARB); + ADD_ATTR(WGL_COLOR_BITS_ARB); + ADD_ATTR(WGL_RED_BITS_ARB); + ADD_ATTR(WGL_RED_SHIFT_ARB); + ADD_ATTR(WGL_GREEN_BITS_ARB); + ADD_ATTR(WGL_GREEN_SHIFT_ARB); + ADD_ATTR(WGL_BLUE_BITS_ARB); + ADD_ATTR(WGL_BLUE_SHIFT_ARB); + ADD_ATTR(WGL_ALPHA_BITS_ARB); + ADD_ATTR(WGL_ALPHA_SHIFT_ARB); + ADD_ATTR(WGL_ACCUM_RED_BITS_ARB); + ADD_ATTR(WGL_ACCUM_GREEN_BITS_ARB); + ADD_ATTR(WGL_ACCUM_BLUE_BITS_ARB); + ADD_ATTR(WGL_ACCUM_ALPHA_BITS_ARB); + ADD_ATTR(WGL_DEPTH_BITS_ARB); + ADD_ATTR(WGL_STENCIL_BITS_ARB); + ADD_ATTR(WGL_AUX_BUFFERS_ARB); + ADD_ATTR(WGL_SWAP_METHOD_ARB); + + if (screen->has_WGL_ARB_multisample) + { + // we may not query these attrs if WGL_ARB_multisample is not offered + ADD_ATTR(WGL_SAMPLE_BUFFERS_ARB); + ADD_ATTR(WGL_SAMPLES_ARB); + } + + if (screen->has_WGL_ARB_render_texture) + { + // we may not query these attrs if WGL_ARB_render_texture is not offered + ADD_ATTR(WGL_BIND_TO_TEXTURE_RGB_ARB); + ADD_ATTR(WGL_BIND_TO_TEXTURE_RGBA_ARB); + } + + if (screen->has_WGL_ARB_pbuffer) + { + // we may not query these attrs if WGL_ARB_pbuffer is not offered + ADD_ATTR(WGL_DRAW_TO_PBUFFER_ARB); + ADD_ATTR(WGL_MAX_PBUFFER_PIXELS_ARB); + ADD_ATTR(WGL_MAX_PBUFFER_WIDTH_ARB); + ADD_ATTR(WGL_MAX_PBUFFER_HEIGHT_ARB); + } + + /* fill in configs */ + for (i = 0; i < numConfigs; i++) + { + int values[num_attrs]; + + c = &(result[i]); + c->base.next = NULL; + c->pixelFormatIndex = i+1; + + if (!wglGetPixelFormatAttribivARBWrapper(hdc, i+1, 0, num_attrs, attrs, values)) + { + ErrorF("wglGetPixelFormatAttribivARB failed for index %d, error %s\n", i+1, glxWinErrorMessage()); + break; + } + +#define ATTR_VALUE(a, d) getAttrValue(attrs, values, num_attrs, (a), (d)) + + if (!ATTR_VALUE(WGL_SUPPORT_OPENGL_ARB, 0)) + { + GLWIN_DEBUG_MSG("pixelFormat %d isn't WGL_SUPPORT_OPENGL_ARB, skipping", i+1); + continue; + } + + c->base.doubleBufferMode = ATTR_VALUE(WGL_DOUBLE_BUFFER_ARB, 0) ? GL_TRUE : GL_FALSE; + c->base.stereoMode = ATTR_VALUE(WGL_STEREO_ARB, 0) ? GL_TRUE : GL_FALSE; + + c->base.redBits = ATTR_VALUE(WGL_RED_BITS_ARB, 0); + c->base.greenBits = ATTR_VALUE(WGL_GREEN_BITS_ARB, 0); + c->base.blueBits = ATTR_VALUE(WGL_BLUE_BITS_ARB, 0); + c->base.alphaBits = ATTR_VALUE(WGL_ALPHA_BITS_ARB, 0); + + c->base.redMask = BITS_AND_SHIFT_TO_MASK(c->base.redBits, ATTR_VALUE(WGL_RED_SHIFT_ARB, 0)); + c->base.greenMask = BITS_AND_SHIFT_TO_MASK(c->base.greenBits, ATTR_VALUE(WGL_GREEN_SHIFT_ARB, 0)); + c->base.blueMask = BITS_AND_SHIFT_TO_MASK(c->base.blueBits, ATTR_VALUE(WGL_BLUE_SHIFT_ARB, 0)); + c->base.alphaMask = BITS_AND_SHIFT_TO_MASK(c->base.alphaBits, ATTR_VALUE(WGL_ALPHA_SHIFT_ARB, 0)); + + switch (ATTR_VALUE(WGL_PIXEL_TYPE_ARB, 0)) + { + case WGL_TYPE_COLORINDEX_ARB: + c->base.indexBits = ATTR_VALUE(WGL_COLOR_BITS_ARB, 0); + c->base.rgbBits = 0; + c->base.visualType = GLX_STATIC_COLOR; + + if (!getenv("GLWIN_ENABLE_COLORINDEX_FBCONFIGS")) + { + GLWIN_DEBUG_MSG("pixelFormat %d is WGL_TYPE_COLORINDEX_ARB, skipping", i+1); + continue; + } + + break; + + case WGL_TYPE_RGBA_FLOAT_ARB: + GLWIN_DEBUG_MSG("pixelFormat %d is WGL_TYPE_RGBA_FLOAT_ARB, skipping", i+1); + continue; + + case WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT: + GLWIN_DEBUG_MSG("pixelFormat %d is WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT, skipping", i+1); + continue; + + case WGL_TYPE_RGBA_ARB: + c->base.indexBits = 0; + c->base.rgbBits = ATTR_VALUE(WGL_COLOR_BITS_ARB, 0); + c->base.visualType = GLX_TRUE_COLOR; + break; + + default: + ErrorF("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_PIXEL_TYPE_ARB\n", ATTR_VALUE(WGL_PIXEL_TYPE_ARB, 0)); + continue; + } + + c->base.accumRedBits = ATTR_VALUE(WGL_ACCUM_RED_BITS_ARB, 0); + c->base.accumGreenBits = ATTR_VALUE(WGL_ACCUM_GREEN_BITS_ARB, 0); + c->base.accumBlueBits = ATTR_VALUE(WGL_ACCUM_BLUE_BITS_ARB, 0); + c->base.accumAlphaBits = ATTR_VALUE(WGL_ACCUM_ALPHA_BITS_ARB, 0); + + c->base.depthBits = ATTR_VALUE(WGL_DEPTH_BITS_ARB, 0); + c->base.stencilBits = ATTR_VALUE(WGL_STENCIL_BITS_ARB, 0); + c->base.numAuxBuffers = ATTR_VALUE(WGL_AUX_BUFFERS_ARB, 0); + + { + int layers = ATTR_VALUE(WGL_NUMBER_OVERLAYS_ARB,0) + ATTR_VALUE(WGL_NUMBER_UNDERLAYS_ARB, 0); + + if (layers > 0) + { + ErrorF("pixelFormat %d: has %d overlay, %d underlays which aren't currently handled", i, ATTR_VALUE(WGL_NUMBER_OVERLAYS_ARB,0), ATTR_VALUE(WGL_NUMBER_UNDERLAYS_ARB, 0)); + // XXX: need to iterate over layers? + } + } + c->base.level = 0; + + c->base.pixmapMode = 0; // ??? + c->base.visualID = -1; // will be set by __glXScreenInit() + + /* EXT_visual_rating / GLX 1.2 */ + switch (ATTR_VALUE(WGL_ACCELERATION_ARB, 0)) + { + default: + ErrorF("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_ACCELERATION_ARB\n", ATTR_VALUE(WGL_ACCELERATION_ARB, 0)); + + case WGL_NO_ACCELERATION_ARB: + c->base.visualRating = GLX_SLOW_VISUAL_EXT; + break; + + case WGL_GENERIC_ACCELERATION_ARB: + case WGL_FULL_ACCELERATION_ARB: + c->base.visualRating = GLX_NONE_EXT; + break; + } + + /* EXT_visual_info / GLX 1.2 */ + // c->base.visualType is set above + if (ATTR_VALUE(WGL_TRANSPARENT_ARB, 0)) + { + c->base.transparentPixel = (c->base.visualType == GLX_TRUE_COLOR) ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT; + c->base.transparentRed = ATTR_VALUE(WGL_TRANSPARENT_RED_VALUE_ARB, 0); + c->base.transparentGreen = ATTR_VALUE(WGL_TRANSPARENT_GREEN_VALUE_ARB, 0); + c->base.transparentBlue = ATTR_VALUE(WGL_TRANSPARENT_BLUE_VALUE_ARB, 0); + c->base.transparentAlpha = ATTR_VALUE(WGL_TRANSPARENT_ALPHA_VALUE_ARB, 0); + c->base.transparentIndex = ATTR_VALUE(WGL_TRANSPARENT_INDEX_VALUE_ARB, 0); + } + else + { + c->base.transparentPixel = GLX_NONE_EXT; + c->base.transparentRed = GLX_NONE; + c->base.transparentGreen = GLX_NONE; + c->base.transparentBlue = GLX_NONE; + c->base.transparentAlpha = GLX_NONE; + c->base.transparentIndex = GLX_NONE; + } + + /* ARB_multisample / SGIS_multisample */ + if (screen->has_WGL_ARB_multisample) + { + c->base.sampleBuffers = ATTR_VALUE(WGL_SAMPLE_BUFFERS_ARB, 0); + c->base.samples = ATTR_VALUE(WGL_SAMPLES_ARB, 0); + } + else + { + c->base.sampleBuffers = 0; + c->base.samples = 0; + } + + /* SGIX_fbconfig / GLX 1.3 */ + c->base.drawableType = ((ATTR_VALUE(WGL_DRAW_TO_WINDOW_ARB, 0) ? GLX_WINDOW_BIT : 0) + | (ATTR_VALUE(WGL_DRAW_TO_BITMAP_ARB, 0) ? GLX_PIXMAP_BIT : 0) + | (ATTR_VALUE(WGL_DRAW_TO_PBUFFER_ARB, 0) ? GLX_PBUFFER_BIT : 0)); + + /* + Assume OpenGL RGBA rendering is available on all visuals + (it is specified to render to red component in single-channel visuals, + if supported, but there doesn't seem to be any mechanism to check if it + is supported) + + Color index rendering is only supported on single-channel visuals + */ + if (c->base.visualType == GLX_STATIC_COLOR) + { + c->base.renderType = GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT; + } + else + { + c->base.renderType = GLX_RGBA_BIT; + } + + c->base.xRenderable = GL_TRUE; + c->base.fbconfigID = -1; // will be set by __glXScreenInit() + + /* SGIX_pbuffer / GLX 1.3 */ + if (screen->has_WGL_ARB_pbuffer) + { + c->base.maxPbufferWidth = ATTR_VALUE(WGL_MAX_PBUFFER_WIDTH_ARB, -1); + c->base.maxPbufferHeight = ATTR_VALUE(WGL_MAX_PBUFFER_HEIGHT_ARB, -1); + c->base.maxPbufferPixels = ATTR_VALUE(WGL_MAX_PBUFFER_PIXELS_ARB, -1); + } + else + { + c->base.maxPbufferWidth = -1; + c->base.maxPbufferHeight = -1; + c->base.maxPbufferPixels = -1; + } + c->base.optimalPbufferWidth = 0; // there is no optimal value + c->base.optimalPbufferHeight = 0; + + /* SGIX_visual_select_group */ + // arrange for visuals with the best acceleration to be preferred in selection + switch (ATTR_VALUE(WGL_ACCELERATION_ARB, 0)) + { + case WGL_FULL_ACCELERATION_ARB: + c->base.visualSelectGroup = 2; + break; + + case WGL_GENERIC_ACCELERATION_ARB: + c->base.visualSelectGroup = 1; + break; + + default: + case WGL_NO_ACCELERATION_ARB: + c->base.visualSelectGroup = 0; + break; + } + + /* OML_swap_method */ + switch (ATTR_VALUE(WGL_SWAP_METHOD_ARB, 0)) + { + case WGL_SWAP_EXCHANGE_ARB: + c->base.swapMethod = GLX_SWAP_EXCHANGE_OML; + break; + + case WGL_SWAP_COPY_ARB: + c->base.swapMethod = GLX_SWAP_COPY_OML; + break; + + default: + ErrorF("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_SWAP_METHOD_ARB\n", ATTR_VALUE(WGL_SWAP_METHOD_ARB, 0)); + + case WGL_SWAP_UNDEFINED_ARB: + c->base.swapMethod = GLX_SWAP_UNDEFINED_OML; + } + + /* EXT_import_context */ + c->base.screen = screen->base.pScreen->myNum; + + /* EXT_texture_from_pixmap */ + /* + Mesa's DRI configs always have bindToTextureRgb/Rgba TRUE (see driCreateConfigs(), so setting + bindToTextureRgb/bindToTextureRgba to FALSE means that swrast can't find any fbConfigs to use, + so setting these to 0, even if we know bindToTexture isn't available, isn't a good idea... + */ + if (screen->has_WGL_ARB_render_texture) + { + c->base.bindToTextureRgb = ATTR_VALUE(WGL_BIND_TO_TEXTURE_RGB_ARB, -1); + c->base.bindToTextureRgba = ATTR_VALUE(WGL_BIND_TO_TEXTURE_RGBA_ARB, -1); + } + else + { + c->base.bindToTextureRgb = -1; + c->base.bindToTextureRgba = -1; + } + c->base.bindToMipmapTexture = -1; + c->base.bindToTextureTargets = GLX_TEXTURE_1D_BIT_EXT | GLX_TEXTURE_2D_BIT_EXT | GLX_TEXTURE_RECTANGLE_BIT_EXT; + c->base.yInverted = -1; + + n++; + + // update previous config to point to this config + if (prev) + prev->base.next = &(c->base); + + prev = c; + } + + screen->base.numFBConfigs = n; + screen->base.fbconfigs = &(result->base); +} diff --git a/xorg-server/hw/xwin/win.h b/xorg-server/hw/xwin/win.h index 5abaa031c..f4392b233 100644 --- a/xorg-server/hw/xwin/win.h +++ b/xorg-server/hw/xwin/win.h @@ -1,1464 +1,1464 @@ -/* - *Copyright (C) 1994-2000 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. - * - * Authors: Dakshinamurthy Karra - * Suhaib M Siddiqi - * Peter Busch - * Harold L Hunt II - * Kensuke Matsuzaki - */ - -#ifndef _WIN_H_ -#define _WIN_H_ - -#ifndef NO -#define NO 0 -#endif -#ifndef YES -#define YES 1 -#endif - -/* Turn debug messages on or off */ -#ifndef CYGDEBUG -#define CYGDEBUG NO -#endif - -/* WM_XBUTTON Messages. They should go into w32api. */ -#ifndef WM_XBUTTONDOWN -# define WM_XBUTTONDOWN 523 -#endif -#ifndef WM_XBUTTONUP -# define WM_XBUTTONUP 524 -#endif -#ifndef WM_XBUTTONDBLCLK -# define WM_XBUTTONDBLCLK 525 -#endif - - -#define WIN_DEFAULT_BPP 0 -#define WIN_DEFAULT_WHITEPIXEL 255 -#define WIN_DEFAULT_BLACKPIXEL 0 -#define WIN_DEFAULT_LINEBIAS 0 -#define WIN_DEFAULT_E3B_TIME 50 /* milliseconds */ -#define WIN_DEFAULT_DPI 75 -#define WIN_DEFAULT_REFRESH 0 -#define WIN_DEFAULT_WIN_KILL TRUE -#define WIN_DEFAULT_UNIX_KILL FALSE -#define WIN_DEFAULT_CLIP_UPDATES_NBOXES 0 -#ifdef XWIN_EMULATEPSEUDO -#define WIN_DEFAULT_EMULATE_PSEUDO FALSE -#endif -#define WIN_DEFAULT_USER_GAVE_HEIGHT_AND_WIDTH FALSE - -#define WIN_DIB_MAXIMUM_SIZE 0x08000000 /* 16 MB on Windows 95, 98, Me */ -#define WIN_DIB_MAXIMUM_SIZE_MB (WIN_DIB_MAXIMUM_SIZE / 8 / 1024 / 1024) - -/* - * Windows only supports 256 color palettes - */ -#define WIN_NUM_PALETTE_ENTRIES 256 - -/* - * Number of times to call Restore in an attempt to restore the primary surface - */ -#define WIN_REGAIN_SURFACE_RETRIES 1 - -/* - * Build a supported display depths mask by shifting one to the left - * by the number of bits in the supported depth. - */ -#define WIN_SUPPORTED_BPPS ( (1 << (32 - 1)) | (1 << (24 - 1)) \ - | (1 << (16 - 1)) | (1 << (15 - 1)) \ - | (1 << ( 8 - 1))) -#define WIN_CHECK_DEPTH YES - -/* - * Timer IDs for WM_TIMER - */ -#define WIN_E3B_TIMER_ID 1 -#define WIN_POLLING_MOUSE_TIMER_ID 2 - -#define MOUSE_POLLING_INTERVAL 50 - -#define WIN_E3B_OFF -1 -#define WIN_FD_INVALID -1 - -#define WIN_SERVER_NONE 0x0L /* 0 */ -#define WIN_SERVER_SHADOW_GDI 0x1L /* 1 */ -#define WIN_SERVER_SHADOW_DD 0x2L /* 2 */ -#define WIN_SERVER_SHADOW_DDNL 0x4L /* 4 */ -#ifdef XWIN_PRIMARYFB -#define WIN_SERVER_PRIMARY_DD 0x8L /* 8 */ -#endif -#ifdef XWIN_NATIVEGDI -# define WIN_SERVER_NATIVE_GDI 0x10L /* 16 */ -#endif - -#define AltMapIndex Mod1MapIndex -#define NumLockMapIndex Mod2MapIndex -#define AltLangMapIndex Mod3MapIndex -#define KanaMapIndex Mod4MapIndex -#define ScrollLockMapIndex Mod5MapIndex - -#define WIN_MOD_LALT 0x00000001 -#define WIN_MOD_RALT 0x00000002 -#define WIN_MOD_LCONTROL 0x00000004 -#define WIN_MOD_RCONTROL 0x00000008 - -#define WIN_24BPP_MASK_RED 0x00FF0000 -#define WIN_24BPP_MASK_GREEN 0x0000FF00 -#define WIN_24BPP_MASK_BLUE 0x000000FF - -#define WIN_MAX_KEYS_PER_KEY 4 - -#include <sys/types.h> -#include <sys/stat.h> -#include <stdio.h> - -#include <errno.h> -#if defined(XWIN_MULTIWINDOWEXTWM) || defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) -#define HANDLE void * -#include <pthread.h> -#undef HANDLE -#endif - -#ifdef HAS_MMAP -#include <sys/mman.h> -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif /* MAP_FILE */ -#endif /* HAS_MMAP */ - -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/Xos.h> -#include <X11/Xprotostr.h> -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "pixmap.h" -#include "region.h" -#include "gcstruct.h" -#include "colormap.h" -#include "colormapst.h" -#include "miscstruct.h" -#include "servermd.h" -#include "windowstr.h" -#include "mi.h" -#include "micmap.h" -#include "mifillarc.h" -#include "mifpoly.h" -#include "mibstore.h" -#include "input.h" -#include "mipointer.h" -#include "X11/keysym.h" -#include "mibstore.h" -#include "micoord.h" -#include "dix.h" -#include "miline.h" -#include "shadow.h" -#include "fb.h" -#include "rootless.h" - -#include "mipict.h" -#include "picturestr.h" - -#ifdef RANDR -#include "randrstr.h" -#endif - -/* - * Windows headers - */ -#include "winms.h" -#include "winresource.h" - - -/* - * Define Windows constants - */ - -#define WM_TRAYICON (WM_USER + 1000) -#define WM_INIT_SYS_MENU (WM_USER + 1001) -#define WM_GIVEUP (WM_USER + 1002) - - -/* Local includes */ -#include "winwindow.h" -#include "winmsg.h" - - -/* - * Debugging macros - */ - -#if CYGDEBUG -#define DEBUG_MSG(str,...) \ -if (fDebugProcMsg) \ -{ \ - char *pszTemp; \ - int iLength; \ - pszTemp = Xprintf (str, ##__VA_ARGS__); \ - MessageBox (NULL, pszTemp, szFunctionName, MB_OK); \ - xfree (pszTemp); \ -} -#else -#define DEBUG_MSG(str,...) -#endif - -#if CYGDEBUG -#define DEBUG_FN_NAME(str) PTSTR szFunctionName = str -#else -#define DEBUG_FN_NAME(str) -#endif - -#if CYGDEBUG || YES -#define DEBUGVARS BOOL fDebugProcMsg = FALSE -#else -#define DEBUGVARS -#endif - -#if CYGDEBUG || YES -#define DEBUGPROC_MSG fDebugProcMsg = TRUE -#else -#define DEBUGPROC_MSG -#endif - -#define PROFILEPOINT(point,thresh)\ -{\ -static unsigned int PROFPT##point = 0;\ -if (++PROFPT##point % thresh == 0)\ -ErrorF (#point ": PROFILEPOINT hit %u times\n", PROFPT##point);\ -} - - -/* We use xor this macro for detecting toggle key state changes */ -#define WIN_XOR(a,b) ((!(a) && (b)) || ((a) && !(b))) - -#define DEFINE_ATOM_HELPER(func,atom_name) \ -static Atom func (void) { \ - static int generation; \ - static Atom atom; \ - if (generation != serverGeneration) { \ - generation = serverGeneration; \ - atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ - } \ - return atom; \ -} - -/* - * Typedefs for engine dependent function pointers - */ - -typedef Bool (*winAllocateFBProcPtr)(ScreenPtr); - -typedef void (*winShadowUpdateProcPtr)(ScreenPtr, shadowBufPtr); - -typedef Bool (*winCloseScreenProcPtr)(int, ScreenPtr); - -typedef Bool (*winInitVisualsProcPtr)(ScreenPtr); - -typedef Bool (*winAdjustVideoModeProcPtr)(ScreenPtr); - -typedef Bool (*winCreateBoundingWindowProcPtr)(ScreenPtr); - -typedef Bool (*winFinishScreenInitProcPtr)(int, ScreenPtr, int, char **); - -typedef Bool (*winBltExposedRegionsProcPtr)(ScreenPtr); - -typedef Bool (*winActivateAppProcPtr)(ScreenPtr); - -typedef Bool (*winRedrawScreenProcPtr)(ScreenPtr pScreen); - -typedef Bool (*winRealizeInstalledPaletteProcPtr)(ScreenPtr pScreen); - -typedef Bool (*winInstallColormapProcPtr)(ColormapPtr pColormap); - -typedef Bool (*winStoreColorsProcPtr)(ColormapPtr pmap, - int ndef, xColorItem *pdefs); - -typedef Bool (*winCreateColormapProcPtr)(ColormapPtr pColormap); - -typedef Bool (*winDestroyColormapProcPtr)(ColormapPtr pColormap); - -typedef Bool (*winHotKeyAltTabProcPtr)(ScreenPtr); - -typedef Bool (*winCreatePrimarySurfaceProcPtr)(ScreenPtr); - -typedef Bool (*winReleasePrimarySurfaceProcPtr)(ScreenPtr); - -typedef Bool (*winFinishCreateWindowsWindowProcPtr)(WindowPtr pWin); - -typedef Bool (*winCreateScreenResourcesProc)(ScreenPtr); - -/* Typedef for DIX wrapper functions */ -typedef int (*winDispatchProcPtr) (ClientPtr); - - -/* - * GC (graphics context) privates - */ - -typedef struct -{ - HDC hdc; - HDC hdcMem; -} winPrivGCRec, *winPrivGCPtr; - - -/* - * Pixmap privates - */ - -typedef struct -{ - HDC hdcSelected; - HBITMAP hBitmap; - BYTE *pbBits; - DWORD dwScanlineBytes; - BITMAPINFOHEADER *pbmih; -} winPrivPixmapRec, *winPrivPixmapPtr; - - -/* - * Colormap privates - */ - -typedef struct -{ - HPALETTE hPalette; - LPDIRECTDRAWPALETTE lpDDPalette; - RGBQUAD rgbColors[WIN_NUM_PALETTE_ENTRIES]; - PALETTEENTRY peColors[WIN_NUM_PALETTE_ENTRIES]; -} winPrivCmapRec, *winPrivCmapPtr; - -/* - * Windows Cursor handling. - */ - -typedef struct { - /* from GetSystemMetrics */ - int sm_cx; - int sm_cy; - - BOOL visible; - HCURSOR handle; - QueryBestSizeProcPtr QueryBestSize; - miPointerSpriteFuncPtr spriteFuncs; -} winCursorRec; - -/* - * Screen information structure that we need before privates are available - * in the server startup sequence. - */ - -typedef struct -{ - ScreenPtr pScreen; - - /* Did the user specify a height and width? */ - Bool fUserGaveHeightAndWidth; - - DWORD dwScreen; - DWORD dwUserWidth; - DWORD dwUserHeight; - DWORD dwWidth; - DWORD dwHeight; - DWORD dwWidth_mm; - DWORD dwHeight_mm; - DWORD dwPaddedWidth; - - /* Did the user specify a screen position? */ - Bool fUserGavePosition; - DWORD dwInitialX; - DWORD dwInitialY; - - /* - * dwStride is the number of whole pixels that occupy a scanline, - * including those pixels that are not displayed. This is basically - * a rounding up of the width. - */ - DWORD dwStride; - - /* Offset of the screen in the window when using scrollbars */ - DWORD dwXOffset; - DWORD dwYOffset; - - DWORD dwBPP; - DWORD dwDepth; - DWORD dwRefreshRate; - char *pfb; - DWORD dwEngine; - DWORD dwEnginePreferred; - DWORD dwClipUpdatesNBoxes; -#ifdef XWIN_EMULATEPSEUDO - Bool fEmulatePseudo; -#endif - Bool fFullScreen; - Bool fDecoration; -#ifdef XWIN_MULTIWINDOWEXTWM - Bool fMWExtWM; - Bool fInternalWM; - Bool fAnotherWMRunning; -#endif - Bool fRootless; -#ifdef XWIN_MULTIWINDOW - Bool fMultiWindow; -#endif -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - Bool fMultiMonitorOverride; -#endif - Bool fMultipleMonitors; - Bool fLessPointer; - Bool fScrollbars; - Bool fNoTrayIcon; - int iE3BTimeout; - /* Windows (Alt+F4) and Unix (Ctrl+Alt+Backspace) Killkey */ - Bool fUseWinKillKey; - Bool fUseUnixKillKey; - Bool fIgnoreInput; - - /* Did the user explicitly set this screen? */ - Bool fExplicitScreen; -} winScreenInfo, *winScreenInfoPtr; - - -/* - * Screen privates - */ - -typedef struct _winPrivScreenRec -{ - winScreenInfoPtr pScreenInfo; - - Bool fEnabled; - Bool fClosed; - Bool fActive; - Bool fBadDepth; - - int iDeltaZ; - - int iConnectedClients; - - CloseScreenProcPtr CloseScreen; - - DWORD dwRedMask; - DWORD dwGreenMask; - DWORD dwBlueMask; - DWORD dwBitsPerRGB; - - DWORD dwModeKeyStates; - - /* Handle to icons that must be freed */ - HICON hiconNotifyIcon; - - /* Last width, height, and depth of the Windows display */ - DWORD dwLastWindowsWidth; - DWORD dwLastWindowsHeight; - DWORD dwLastWindowsBitsPixel; - - /* Palette management */ - ColormapPtr pcmapInstalled; - - /* Pointer to the root visual so we only have to look it up once */ - VisualPtr pRootVisual; - - /* 3 button emulation variables */ - int iE3BCachedPress; - Bool fE3BFakeButton2Sent; - - /* Privates used by shadow fb GDI server */ - HBITMAP hbmpShadow; - HDC hdcScreen; - HDC hdcShadow; - HWND hwndScreen; - - /* Privates used by shadow fb and primary fb DirectDraw servers */ - LPDIRECTDRAW pdd; - LPDIRECTDRAWSURFACE2 pddsPrimary; - LPDIRECTDRAW2 pdd2; - - /* Privates used by shadow fb DirectDraw server */ - LPDIRECTDRAWSURFACE2 pddsShadow; - LPDDSURFACEDESC pddsdShadow; - - /* Privates used by primary fb DirectDraw server */ - LPDIRECTDRAWSURFACE2 pddsOffscreen; - LPDDSURFACEDESC pddsdOffscreen; - LPDDSURFACEDESC pddsdPrimary; - - /* Privates used by shadow fb DirectDraw Nonlocking server */ - LPDIRECTDRAW4 pdd4; - LPDIRECTDRAWSURFACE4 pddsShadow4; - LPDIRECTDRAWSURFACE4 pddsPrimary4; - BOOL fRetryCreateSurface; - - /* Privates used by both shadow fb DirectDraw servers */ - LPDIRECTDRAWCLIPPER pddcPrimary; - -#ifdef XWIN_MULTIWINDOWEXTWM - /* Privates used by multi-window external window manager */ - RootlessFrameID widTop; - Bool fRestacking; -#endif - -#ifdef XWIN_MULTIWINDOW - /* Privates used by multi-window */ - pthread_t ptWMProc; - pthread_t ptXMsgProc; - void *pWMInfo; -#endif - -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - /* Privates used by both multi-window and rootless */ - Bool fRootWindowShown; -#endif - -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) - /* Privates used for any module running in a seperate thread */ - pthread_mutex_t pmServerStarted; - Bool fServerStarted; -#endif - - /* Engine specific functions */ - winAllocateFBProcPtr pwinAllocateFB; - winShadowUpdateProcPtr pwinShadowUpdate; - winCloseScreenProcPtr pwinCloseScreen; - winInitVisualsProcPtr pwinInitVisuals; - winAdjustVideoModeProcPtr pwinAdjustVideoMode; - winCreateBoundingWindowProcPtr pwinCreateBoundingWindow; - winFinishScreenInitProcPtr pwinFinishScreenInit; - winBltExposedRegionsProcPtr pwinBltExposedRegions; - winActivateAppProcPtr pwinActivateApp; - winRedrawScreenProcPtr pwinRedrawScreen; - winRealizeInstalledPaletteProcPtr pwinRealizeInstalledPalette; - winInstallColormapProcPtr pwinInstallColormap; - winStoreColorsProcPtr pwinStoreColors; - winCreateColormapProcPtr pwinCreateColormap; - winDestroyColormapProcPtr pwinDestroyColormap; - winHotKeyAltTabProcPtr pwinHotKeyAltTab; - winCreatePrimarySurfaceProcPtr pwinCreatePrimarySurface; - winReleasePrimarySurfaceProcPtr pwinReleasePrimarySurface; - - winCreateScreenResourcesProc pwinCreateScreenResources; - -#ifdef XWIN_MULTIWINDOW - /* Window Procedures for MultiWindow mode */ - winFinishCreateWindowsWindowProcPtr pwinFinishCreateWindowsWindow; -#endif - - /* Window Procedures for Rootless mode */ - CreateWindowProcPtr CreateWindow; - DestroyWindowProcPtr DestroyWindow; - PositionWindowProcPtr PositionWindow; - ChangeWindowAttributesProcPtr ChangeWindowAttributes; - RealizeWindowProcPtr RealizeWindow; - UnrealizeWindowProcPtr UnrealizeWindow; - ValidateTreeProcPtr ValidateTree; - PostValidateTreeProcPtr PostValidateTree; - WindowExposuresProcPtr WindowExposures; - CopyWindowProcPtr CopyWindow; - ClearToBackgroundProcPtr ClearToBackground; - ClipNotifyProcPtr ClipNotify; - RestackWindowProcPtr RestackWindow; - ReparentWindowProcPtr ReparentWindow; - ResizeWindowProcPtr ResizeWindow; - MoveWindowProcPtr MoveWindow; - SetShapeProcPtr SetShape; - - winCursorRec cursor; -} winPrivScreenRec; - - -#ifdef XWIN_MULTIWINDOWEXTWM -typedef struct { - RootlessWindowPtr pFrame; - HWND hWnd; - int dwWidthBytes; - BITMAPINFOHEADER *pbmihShadow; - HBITMAP hbmpShadow; - HDC hdcShadow; - HDC hdcScreen; - BOOL fResized; - BOOL fRestackingNow; - BOOL fClose; - BOOL fMovingOrSizing; - BOOL fDestroyed;//for debug - char *pfb; -} win32RootlessWindowRec, *win32RootlessWindowPtr; -#endif - - -typedef struct { - pointer value; - XID id; -} WindowIDPairRec, *WindowIDPairPtr; - - -/* - * Extern declares for general global variables - */ - -extern winScreenInfo * g_ScreenInfo; -extern miPointerScreenFuncRec g_winPointerCursorFuncs; -extern DWORD g_dwEvents; -#ifdef HAS_DEVWINDOWS -extern int g_fdMessageQueue; -#endif -extern DevPrivateKey g_iScreenPrivateKey; -extern DevPrivateKey g_iCmapPrivateKey; -extern DevPrivateKey g_iGCPrivateKey; -extern DevPrivateKey g_iPixmapPrivateKey; -extern DevPrivateKey g_iWindowPrivateKey; -extern unsigned long g_ulServerGeneration; -extern DWORD g_dwEnginesSupported; -extern HINSTANCE g_hInstance; -extern int g_copyROP[]; -extern int g_patternROP[]; -extern const char * g_pszQueryHost; -extern DeviceIntPtr g_pwinPointer; -extern DeviceIntPtr g_pwinKeyboard; - - -/* - * Extern declares for dynamically loaded libraries and function pointers - */ - -extern HMODULE g_hmodDirectDraw; -extern FARPROC g_fpDirectDrawCreate; -extern FARPROC g_fpDirectDrawCreateClipper; - -extern HMODULE g_hmodCommonControls; -extern FARPROC g_fpTrackMouseEvent; - - -/* - * Screen privates macros - */ - -#define winGetScreenPriv(pScreen) ((winPrivScreenPtr) \ - dixLookupPrivate(&(pScreen)->devPrivates, g_iScreenPrivateKey)) - -#define winSetScreenPriv(pScreen,v) \ - dixSetPrivate(&(pScreen)->devPrivates, g_iScreenPrivateKey, v) - -#define winScreenPriv(pScreen) \ - winPrivScreenPtr pScreenPriv = winGetScreenPriv(pScreen) - - -/* - * Colormap privates macros - */ - -#define winGetCmapPriv(pCmap) ((winPrivCmapPtr) \ - dixLookupPrivate(&(pCmap)->devPrivates, g_iCmapPrivateKey)) - -#define winSetCmapPriv(pCmap,v) \ - dixSetPrivate(&(pCmap)->devPrivates, g_iCmapPrivateKey, v) - -#define winCmapPriv(pCmap) \ - winPrivCmapPtr pCmapPriv = winGetCmapPriv(pCmap) - - -/* - * GC privates macros - */ - -#define winGetGCPriv(pGC) ((winPrivGCPtr) \ - dixLookupPrivate(&(pGC)->devPrivates, g_iGCPrivateKey)) - -#define winSetGCPriv(pGC,v) \ - dixSetPrivate(&(pGC)->devPrivates, g_iGCPrivateKey, v) - -#define winGCPriv(pGC) \ - winPrivGCPtr pGCPriv = winGetGCPriv(pGC) - - -/* - * Pixmap privates macros - */ - -#define winGetPixmapPriv(pPixmap) ((winPrivPixmapPtr) \ - dixLookupPrivate(&(pPixmap)->devPrivates, g_iPixmapPrivateKey)) - -#define winSetPixmapPriv(pPixmap,v) \ - dixLookupPrivate(&(pPixmap)->devPrivates, g_iPixmapPrivateKey, v) - -#define winPixmapPriv(pPixmap) \ - winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap) - - -/* - * Window privates macros - */ - -#define winGetWindowPriv(pWin) ((winPrivWinPtr) \ - dixLookupPrivate(&(pWin)->devPrivates, g_iWindowPrivateKey)) - -#define winSetWindowPriv(pWin,v) \ - dixLookupPrivate(&(pWin)->devPrivates, g_iWindowPrivateKey, v) - -#define winWindowPriv(pWin) \ - winPrivWinPtr pWinPriv = winGetWindowPriv(pWin) - -/* - * wrapper macros - */ -#define _WIN_WRAP(priv, real, mem, func) {\ - priv->mem = real->mem; \ - real->mem = func; \ -} - -#define _WIN_UNWRAP(priv, real, mem) {\ - real->mem = priv->mem; \ -} - -#define WIN_WRAP(mem, func) _WIN_WRAP(pScreenPriv, pScreen, mem, func) - -#define WIN_UNWRAP(mem) _WIN_UNWRAP(pScreenPriv, pScreen, mem) - -/* - * BEGIN DDX and DIX Function Prototypes - */ - - -/* - * winallpriv.c - */ - -Bool -winAllocatePrivates (ScreenPtr pScreen); - -Bool -winInitCmapPrivates (ColormapPtr pCmap, int index); - -Bool -winAllocateCmapPrivates (ColormapPtr pCmap); - - -/* - * winauth.c - */ - -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) -Bool -winGenerateAuthorization (void); -void winSetAuthorization(void); -#endif - - -/* - * winblock.c - */ - -void -winBlockHandler (int nScreen, - pointer pBlockData, - pointer pTimeout, - pointer pReadMask); - - -#ifdef XWIN_NATIVEGDI -/* - * winclip.c - */ - -RegionPtr -winPixmapToRegionNativeGDI (PixmapPtr pPix); -#endif - - -#ifdef XWIN_CLIPBOARD -/* - * winclipboardinit.c - */ - -Bool -winInitClipboard (void); - -void -winFixClipboardChain (void); -#endif - - -/* - * wincmap.c - */ - -void -winSetColormapFunctions (ScreenPtr pScreen); - -Bool -winCreateDefColormap (ScreenPtr pScreen); - - -/* - * wincreatewnd.c - */ - -Bool -winCreateBoundingWindowFullScreen (ScreenPtr pScreen); - -Bool -winCreateBoundingWindowWindowed (ScreenPtr pScreen); - - -/* - * windialogs.c - */ - -void -winDisplayExitDialog (winPrivScreenPtr pScreenPriv); - -void -winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv); - -void -winDisplayAboutDialog (winPrivScreenPtr pScreenPriv); - - -/* - * winengine.c - */ - -void -winDetectSupportedEngines (void); - -Bool -winSetEngine (ScreenPtr pScreen); - -Bool -winGetDDProcAddresses (void); - - -/* - * winerror.c - */ - -#ifdef DDXOSVERRORF -void -OSVenderVErrorF (const char *pszFormat, va_list va_args); -#endif - -void -winMessageBoxF (const char *pszError, UINT uType, ...); - - -#ifdef XWIN_NATIVEGDI -/* - * winfillsp.c - */ - -void -winFillSpansNativeGDI (DrawablePtr pDrawable, - GCPtr pGC, - int nSpans, - DDXPointPtr pPoints, - int *pWidths, - int fSorted); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * winfont.c - */ - -Bool -winRealizeFontNativeGDI (ScreenPtr pScreen, FontPtr pFont); - -Bool -winUnrealizeFontNativeGDI (ScreenPtr pScreen, FontPtr pFont); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * wingc.c - */ - -Bool -winCreateGCNativeGDI (GCPtr pGC); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * wingetsp.c - */ - -void -winGetSpansNativeGDI (DrawablePtr pDrawable, - int wMax, - DDXPointPtr pPoints, - int *pWidths, - int nSpans, - char *pDst); -#endif - - -/* - * winglobals.c - */ - -void -winInitializeGlobals (void); - - -/* - * winkeybd.c - */ - -void -winTranslateKey (WPARAM wParam, LPARAM lParam, int *piScanCode); - -int -winKeybdProc (DeviceIntPtr pDeviceInt, int iState); - -void -winInitializeModeKeyStates (void); - -void -winRestoreModeKeyStates (void); - -Bool -winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam); - -void -winKeybdReleaseKeys (void); - -void -winSendKeyEvent (DWORD dwKey, Bool fDown); - -BOOL -winCheckKeyPressed(WPARAM wParam, LPARAM lParam); - -void -winFixShiftKeys (int iScanCode); - -/* - * winkeyhook.c - */ - -Bool -winInstallKeyboardHookLL (void); - -void -winRemoveKeyboardHookLL (void); - - -/* - * winmisc.c - */ - -#ifdef XWIN_NATIVEGDI -void -winQueryBestSizeNativeGDI (int class, unsigned short *pWidth, - unsigned short *pHeight, ScreenPtr pScreen); -#endif - -CARD8 -winCountBits (DWORD dw); - -Bool -winUpdateFBPointer (ScreenPtr pScreen, void *pbits); - -#ifdef XWIN_NATIVEGDI -BOOL -winPaintBackground (HWND hwnd, COLORREF colorref); -#endif - - -/* - * winmouse.c - */ - -int -winMouseProc (DeviceIntPtr pDeviceInt, int iState); - -int -winMouseWheel (ScreenPtr pScreen, int iDeltaZ); - -void -winMouseButtonsSendEvent (int iEventType, int iButton); - -int -winMouseButtonsHandle (ScreenPtr pScreen, - int iEventType, int iButton, - WPARAM wParam); - -void -winEnqueueMotion(int x, int y); - -#ifdef XWIN_NATIVEGDI -/* - * winnativegdi.c - */ - -HBITMAP -winCreateDIBNativeGDI (int iWidth, int iHeight, int iDepth, - BYTE **ppbBits, BITMAPINFO **ppbmi); - -Bool -winSetEngineFunctionsNativeGDI (ScreenPtr pScreen); -#endif - - -#ifdef XWIN_PRIMARYFB -/* - * winpfbddd.c - */ - -Bool -winSetEngineFunctionsPrimaryDD (ScreenPtr pScreen); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * winpixmap.c - */ - -PixmapPtr -winCreatePixmapNativeGDI (ScreenPtr pScreen, int width, int height, int depth, - unsigned usage_hint); - -Bool -winDestroyPixmapNativeGDI (PixmapPtr pPixmap); - -Bool -winModifyPixmapHeaderNativeGDI (PixmapPtr pPixmap, - int iWidth, int iHeight, - int iDepth, - int iBitsPerPixel, - int devKind, - pointer pPixData); -#endif - -#ifdef XWIN_NATIVEGDI -/* - * winpolyline.c - */ - -void -winPolyLineNativeGDI (DrawablePtr pDrawable, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr ppt); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * winpushpxl.c - */ - -void -winPushPixels (GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, - int dx, int dy, int xOrg, int yOrg); -#endif - - -/* - * winscrinit.c - */ - -Bool -winScreenInit (int index, - ScreenPtr pScreen, - int argc, char **argv); - -Bool -winFinishScreenInitFB (int index, - ScreenPtr pScreen, - int argc, char **argv); - -#if defined(XWIN_NATIVEGDI) -Bool -winFinishScreenInitNativeGDI (int index, - ScreenPtr pScreen, - int argc, char **argv); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * winsetsp.c - */ - -void -winSetSpansNativeGDI (DrawablePtr pDrawable, - GCPtr pGC, - char *pSrc, - DDXPointPtr pPoints, - int *pWidth, - int nSpans, - int fSorted); -#endif - - -/* - * winshaddd.c - */ - -Bool -winSetEngineFunctionsShadowDD (ScreenPtr pScreen); - - -/* - * winshadddnl.c - */ - -Bool -winSetEngineFunctionsShadowDDNL (ScreenPtr pScreen); - - -/* - * winshadgdi.c - */ - -Bool -winSetEngineFunctionsShadowGDI (ScreenPtr pScreen); - - -/* - * winwakeup.c - */ - -void -winWakeupHandler (int nScreen, - pointer pWakeupData, - unsigned long ulResult, - pointer pReadmask); - - -/* - * winwindow.c - */ - -#ifdef XWIN_NATIVEGDI -Bool -winCreateWindowNativeGDI (WindowPtr pWin); - -Bool -winDestroyWindowNativeGDI (WindowPtr pWin); - -Bool -winPositionWindowNativeGDI (WindowPtr pWin, int x, int y); - -void -winCopyWindowNativeGDI (WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc); - -Bool -winChangeWindowAttributesNativeGDI (WindowPtr pWin, unsigned long mask); - -Bool -winUnmapWindowNativeGDI (WindowPtr pWindow); - -Bool -winMapWindowNativeGDI (WindowPtr pWindow); -#endif - -Bool -winCreateWindowRootless (WindowPtr pWindow); - -Bool -winDestroyWindowRootless (WindowPtr pWindow); - -Bool -winPositionWindowRootless (WindowPtr pWindow, int x, int y); - -Bool -winChangeWindowAttributesRootless (WindowPtr pWindow, unsigned long mask); - -Bool -winUnmapWindowRootless (WindowPtr pWindow); - -Bool -winMapWindowRootless (WindowPtr pWindow); - -void -winSetShapeRootless (WindowPtr pWindow); - - -/* - * winmultiwindowicons.c - Used by both multi-window and Win32Rootless - */ - -HICON -winXIconToHICON (WindowPtr pWin, int iconSize); - -void -winSelectIcons(WindowPtr pWin, HICON *pIcon, HICON *pSmallIcon); - -#ifdef XWIN_MULTIWINDOW -/* - * winmultiwindowshape.c - */ - -void -winReshapeMultiWindow (WindowPtr pWin); - -void -winSetShapeMultiWindow (WindowPtr pWindow); - -void -winUpdateRgnMultiWindow (WindowPtr pWindow); -#endif - - -#ifdef XWIN_MULTIWINDOW -/* - * winmultiwindowwindow.c - */ - -Bool -winCreateWindowMultiWindow (WindowPtr pWindow); - -Bool -winDestroyWindowMultiWindow (WindowPtr pWindow); - -Bool -winPositionWindowMultiWindow (WindowPtr pWindow, int x, int y); - -Bool -winChangeWindowAttributesMultiWindow (WindowPtr pWindow, unsigned long mask); - -Bool -winUnmapWindowMultiWindow (WindowPtr pWindow); - -Bool -winMapWindowMultiWindow (WindowPtr pWindow); - -void -winReparentWindowMultiWindow (WindowPtr pWin, WindowPtr pPriorParent); - -void -winRestackWindowMultiWindow (WindowPtr pWin, WindowPtr pOldNextSib); - -void -winReorderWindowsMultiWindow (void); - -void -winResizeWindowMultiWindow (WindowPtr pWin, int x, int y, unsigned int w, - unsigned int h, WindowPtr pSib); -void -winMoveWindowMultiWindow (WindowPtr pWin, int x, int y, - WindowPtr pSib, VTKind kind); - -void -winCopyWindowMultiWindow (WindowPtr pWin, DDXPointRec oldpt, - RegionPtr oldRegion); - -XID -winGetWindowID (WindowPtr pWin); - -int -winAdjustXWindow (WindowPtr pWin, HWND hwnd); -#endif - - -#ifdef XWIN_MULTIWINDOW -/* - * winmultiwindowwndproc.c - */ - -LRESULT CALLBACK -winTopLevelWindowProc (HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam); -#endif - - -/* - * wintrayicon.c - */ - -void -winInitNotifyIcon (winPrivScreenPtr pScreenPriv); - -void -winDeleteNotifyIcon (winPrivScreenPtr pScreenPriv); - -LRESULT -winHandleIconMessage (HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam, - winPrivScreenPtr pScreenPriv); - - -/* - * winwndproc.c - */ - -LRESULT CALLBACK -winWindowProc (HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam); - - -#ifdef XWIN_MULTIWINDOWEXTWM -/* - * winwin32rootless.c - */ - -Bool -winMWExtWMCreateFrame (RootlessWindowPtr pFrame, ScreenPtr pScreen, - int newX, int newY, RegionPtr pShape); - -void -winMWExtWMDestroyFrame (RootlessFrameID wid); - -void -winMWExtWMMoveFrame (RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY); - -void -winMWExtWMResizeFrame (RootlessFrameID wid, ScreenPtr pScreen, - int newX, int newY, unsigned int newW, unsigned int newH, - unsigned int gravity); - -void -winMWExtWMRestackFrame (RootlessFrameID wid, RootlessFrameID nextWid); - -void -winMWExtWMReshapeFrame (RootlessFrameID wid, RegionPtr pShape); - -void -winMWExtWMUnmapFrame (RootlessFrameID wid); - -void -winMWExtWMStartDrawing (RootlessFrameID wid, char **pixelData, int *bytesPerRow); - -void -winMWExtWMStopDrawing (RootlessFrameID wid, Bool flush); - -void -winMWExtWMUpdateRegion (RootlessFrameID wid, RegionPtr pDamage); - -void -winMWExtWMDamageRects (RootlessFrameID wid, int count, const BoxRec *rects, - int shift_x, int shift_y); - -void -winMWExtWMRootlessSwitchWindow (RootlessWindowPtr pFrame, WindowPtr oldWin); - -void -winMWExtWMCopyBytes (unsigned int width, unsigned int height, - const void *src, unsigned int srcRowBytes, - void *dst, unsigned int dstRowBytes); - -void -winMWExtWMFillBytes (unsigned int width, unsigned int height, unsigned int value, - void *dst, unsigned int dstRowBytes); - -int -winMWExtWMCompositePixels (unsigned int width, unsigned int height, unsigned int function, - void *src[2], unsigned int srcRowBytes[2], - void *mask, unsigned int maskRowBytes, - void *dst[2], unsigned int dstRowBytes[2]); - -void -winMWExtWMCopyWindow (RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, - int dx, int dy); -#endif - - -#ifdef XWIN_MULTIWINDOWEXTWM -/* - * winwin32rootlesswindow.c - */ - -void -winMWExtWMReorderWindows (ScreenPtr pScreen); - -void -winMWExtWMMoveXWindow (WindowPtr pWin, int x, int y); - -void -winMWExtWMResizeXWindow (WindowPtr pWin, int w, int h); - -void -winMWExtWMMoveResizeXWindow (WindowPtr pWin, int x, int y, int w, int h); - -void -winMWExtWMUpdateIcon (Window id); - -void -winMWExtWMUpdateWindowDecoration (win32RootlessWindowPtr pRLWinPriv, - winScreenInfoPtr pScreenInfo); - -wBOOL CALLBACK -winMWExtWMDecorateWindow (HWND hwnd, LPARAM lParam); - -Bool -winIsInternalWMRunning (winScreenInfoPtr pScreenInfo); - -void -winMWExtWMRestackWindows (ScreenPtr pScreen); -#endif - - -#ifdef XWIN_MULTIWINDOWEXTWM -/* - * winwin32rootlesswndproc.c - */ - -LRESULT CALLBACK -winMWExtWMWindowProc (HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam); -#endif - - -/* - * winwindowswm.c - */ - -void -winWindowsWMSendEvent (int type, unsigned int mask, int which, int arg, - Window window, int x, int y, int w, int h); - -void -winWindowsWMExtensionInit (void); - -/* - * wincursor.c - */ - -Bool -winInitCursor (ScreenPtr pScreen); - -/* - * winprocarg.c - */ -void -winInitializeScreens(int maxscreens); - -/* - * END DDX and DIX Function Prototypes - */ - -#endif /* _WIN_H_ */ - +/* + *Copyright (C) 1994-2000 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. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + * Kensuke Matsuzaki + */ + +#ifndef _WIN_H_ +#define _WIN_H_ + +#ifndef NO +#define NO 0 +#endif +#ifndef YES +#define YES 1 +#endif + +/* Turn debug messages on or off */ +#ifndef CYGDEBUG +#define CYGDEBUG NO +#endif + +/* WM_XBUTTON Messages. They should go into w32api. */ +#ifndef WM_XBUTTONDOWN +# define WM_XBUTTONDOWN 523 +#endif +#ifndef WM_XBUTTONUP +# define WM_XBUTTONUP 524 +#endif +#ifndef WM_XBUTTONDBLCLK +# define WM_XBUTTONDBLCLK 525 +#endif + + +#define WIN_DEFAULT_BPP 0 +#define WIN_DEFAULT_WHITEPIXEL 255 +#define WIN_DEFAULT_BLACKPIXEL 0 +#define WIN_DEFAULT_LINEBIAS 0 +#define WIN_DEFAULT_E3B_TIME 50 /* milliseconds */ +#define WIN_DEFAULT_DPI 75 +#define WIN_DEFAULT_REFRESH 0 +#define WIN_DEFAULT_WIN_KILL TRUE +#define WIN_DEFAULT_UNIX_KILL FALSE +#define WIN_DEFAULT_CLIP_UPDATES_NBOXES 0 +#ifdef XWIN_EMULATEPSEUDO +#define WIN_DEFAULT_EMULATE_PSEUDO FALSE +#endif +#define WIN_DEFAULT_USER_GAVE_HEIGHT_AND_WIDTH FALSE + +#define WIN_DIB_MAXIMUM_SIZE 0x08000000 /* 16 MB on Windows 95, 98, Me */ +#define WIN_DIB_MAXIMUM_SIZE_MB (WIN_DIB_MAXIMUM_SIZE / 8 / 1024 / 1024) + +/* + * Windows only supports 256 color palettes + */ +#define WIN_NUM_PALETTE_ENTRIES 256 + +/* + * Number of times to call Restore in an attempt to restore the primary surface + */ +#define WIN_REGAIN_SURFACE_RETRIES 1 + +/* + * Build a supported display depths mask by shifting one to the left + * by the number of bits in the supported depth. + */ +#define WIN_SUPPORTED_BPPS ( (1 << (32 - 1)) | (1 << (24 - 1)) \ + | (1 << (16 - 1)) | (1 << (15 - 1)) \ + | (1 << ( 8 - 1))) +#define WIN_CHECK_DEPTH YES + +/* + * Timer IDs for WM_TIMER + */ +#define WIN_E3B_TIMER_ID 1 +#define WIN_POLLING_MOUSE_TIMER_ID 2 + +#define MOUSE_POLLING_INTERVAL 50 + +#define WIN_E3B_OFF -1 +#define WIN_FD_INVALID -1 + +#define WIN_SERVER_NONE 0x0L /* 0 */ +#define WIN_SERVER_SHADOW_GDI 0x1L /* 1 */ +#define WIN_SERVER_SHADOW_DD 0x2L /* 2 */ +#define WIN_SERVER_SHADOW_DDNL 0x4L /* 4 */ +#ifdef XWIN_PRIMARYFB +#define WIN_SERVER_PRIMARY_DD 0x8L /* 8 */ +#endif +#ifdef XWIN_NATIVEGDI +# define WIN_SERVER_NATIVE_GDI 0x10L /* 16 */ +#endif + +#define AltMapIndex Mod1MapIndex +#define NumLockMapIndex Mod2MapIndex +#define AltLangMapIndex Mod3MapIndex +#define KanaMapIndex Mod4MapIndex +#define ScrollLockMapIndex Mod5MapIndex + +#define WIN_MOD_LALT 0x00000001 +#define WIN_MOD_RALT 0x00000002 +#define WIN_MOD_LCONTROL 0x00000004 +#define WIN_MOD_RCONTROL 0x00000008 + +#define WIN_24BPP_MASK_RED 0x00FF0000 +#define WIN_24BPP_MASK_GREEN 0x0000FF00 +#define WIN_24BPP_MASK_BLUE 0x000000FF + +#define WIN_MAX_KEYS_PER_KEY 4 + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> + +#include <errno.h> +#if defined(XWIN_MULTIWINDOWEXTWM) || defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) +#define HANDLE void * +#include <pthread.h> +#undef HANDLE +#endif + +#ifdef HAS_MMAP +#include <sys/mman.h> +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif /* MAP_FILE */ +#endif /* HAS_MMAP */ + +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/Xos.h> +#include <X11/Xprotostr.h> +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "pixmap.h" +#include "region.h" +#include "gcstruct.h" +#include "colormap.h" +#include "colormapst.h" +#include "miscstruct.h" +#include "servermd.h" +#include "windowstr.h" +#include "mi.h" +#include "micmap.h" +#include "mifillarc.h" +#include "mifpoly.h" +#include "mibstore.h" +#include "input.h" +#include "mipointer.h" +#include "X11/keysym.h" +#include "mibstore.h" +#include "micoord.h" +#include "dix.h" +#include "miline.h" +#include "shadow.h" +#include "fb.h" +#include "rootless.h" + +#include "mipict.h" +#include "picturestr.h" + +#ifdef RANDR +#include "randrstr.h" +#endif + +/* + * Windows headers + */ +#include "winms.h" +#include "winresource.h" + + +/* + * Define Windows constants + */ + +#define WM_TRAYICON (WM_USER + 1000) +#define WM_INIT_SYS_MENU (WM_USER + 1001) +#define WM_GIVEUP (WM_USER + 1002) + + +/* Local includes */ +#include "winwindow.h" +#include "winmsg.h" + + +/* + * Debugging macros + */ + +#if CYGDEBUG +#define DEBUG_MSG(str,...) \ +if (fDebugProcMsg) \ +{ \ + char *pszTemp; \ + int iLength; \ + pszTemp = Xprintf (str, ##__VA_ARGS__); \ + MessageBox (NULL, pszTemp, szFunctionName, MB_OK); \ + free(pszTemp); \ +} +#else +#define DEBUG_MSG(str,...) +#endif + +#if CYGDEBUG +#define DEBUG_FN_NAME(str) PTSTR szFunctionName = str +#else +#define DEBUG_FN_NAME(str) +#endif + +#if CYGDEBUG || YES +#define DEBUGVARS BOOL fDebugProcMsg = FALSE +#else +#define DEBUGVARS +#endif + +#if CYGDEBUG || YES +#define DEBUGPROC_MSG fDebugProcMsg = TRUE +#else +#define DEBUGPROC_MSG +#endif + +#define PROFILEPOINT(point,thresh)\ +{\ +static unsigned int PROFPT##point = 0;\ +if (++PROFPT##point % thresh == 0)\ +ErrorF (#point ": PROFILEPOINT hit %u times\n", PROFPT##point);\ +} + + +/* We use xor this macro for detecting toggle key state changes */ +#define WIN_XOR(a,b) ((!(a) && (b)) || ((a) && !(b))) + +#define DEFINE_ATOM_HELPER(func,atom_name) \ +static Atom func (void) { \ + static int generation; \ + static Atom atom; \ + if (generation != serverGeneration) { \ + generation = serverGeneration; \ + atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ + } \ + return atom; \ +} + +/* + * Typedefs for engine dependent function pointers + */ + +typedef Bool (*winAllocateFBProcPtr)(ScreenPtr); + +typedef void (*winShadowUpdateProcPtr)(ScreenPtr, shadowBufPtr); + +typedef Bool (*winCloseScreenProcPtr)(int, ScreenPtr); + +typedef Bool (*winInitVisualsProcPtr)(ScreenPtr); + +typedef Bool (*winAdjustVideoModeProcPtr)(ScreenPtr); + +typedef Bool (*winCreateBoundingWindowProcPtr)(ScreenPtr); + +typedef Bool (*winFinishScreenInitProcPtr)(int, ScreenPtr, int, char **); + +typedef Bool (*winBltExposedRegionsProcPtr)(ScreenPtr); + +typedef Bool (*winActivateAppProcPtr)(ScreenPtr); + +typedef Bool (*winRedrawScreenProcPtr)(ScreenPtr pScreen); + +typedef Bool (*winRealizeInstalledPaletteProcPtr)(ScreenPtr pScreen); + +typedef Bool (*winInstallColormapProcPtr)(ColormapPtr pColormap); + +typedef Bool (*winStoreColorsProcPtr)(ColormapPtr pmap, + int ndef, xColorItem *pdefs); + +typedef Bool (*winCreateColormapProcPtr)(ColormapPtr pColormap); + +typedef Bool (*winDestroyColormapProcPtr)(ColormapPtr pColormap); + +typedef Bool (*winHotKeyAltTabProcPtr)(ScreenPtr); + +typedef Bool (*winCreatePrimarySurfaceProcPtr)(ScreenPtr); + +typedef Bool (*winReleasePrimarySurfaceProcPtr)(ScreenPtr); + +typedef Bool (*winFinishCreateWindowsWindowProcPtr)(WindowPtr pWin); + +typedef Bool (*winCreateScreenResourcesProc)(ScreenPtr); + +/* Typedef for DIX wrapper functions */ +typedef int (*winDispatchProcPtr) (ClientPtr); + + +/* + * GC (graphics context) privates + */ + +typedef struct +{ + HDC hdc; + HDC hdcMem; +} winPrivGCRec, *winPrivGCPtr; + + +/* + * Pixmap privates + */ + +typedef struct +{ + HDC hdcSelected; + HBITMAP hBitmap; + BYTE *pbBits; + DWORD dwScanlineBytes; + BITMAPINFOHEADER *pbmih; +} winPrivPixmapRec, *winPrivPixmapPtr; + + +/* + * Colormap privates + */ + +typedef struct +{ + HPALETTE hPalette; + LPDIRECTDRAWPALETTE lpDDPalette; + RGBQUAD rgbColors[WIN_NUM_PALETTE_ENTRIES]; + PALETTEENTRY peColors[WIN_NUM_PALETTE_ENTRIES]; +} winPrivCmapRec, *winPrivCmapPtr; + +/* + * Windows Cursor handling. + */ + +typedef struct { + /* from GetSystemMetrics */ + int sm_cx; + int sm_cy; + + BOOL visible; + HCURSOR handle; + QueryBestSizeProcPtr QueryBestSize; + miPointerSpriteFuncPtr spriteFuncs; +} winCursorRec; + +/* + * Screen information structure that we need before privates are available + * in the server startup sequence. + */ + +typedef struct +{ + ScreenPtr pScreen; + + /* Did the user specify a height and width? */ + Bool fUserGaveHeightAndWidth; + + DWORD dwScreen; + DWORD dwUserWidth; + DWORD dwUserHeight; + DWORD dwWidth; + DWORD dwHeight; + DWORD dwWidth_mm; + DWORD dwHeight_mm; + DWORD dwPaddedWidth; + + /* Did the user specify a screen position? */ + Bool fUserGavePosition; + DWORD dwInitialX; + DWORD dwInitialY; + + /* + * dwStride is the number of whole pixels that occupy a scanline, + * including those pixels that are not displayed. This is basically + * a rounding up of the width. + */ + DWORD dwStride; + + /* Offset of the screen in the window when using scrollbars */ + DWORD dwXOffset; + DWORD dwYOffset; + + DWORD dwBPP; + DWORD dwDepth; + DWORD dwRefreshRate; + char *pfb; + DWORD dwEngine; + DWORD dwEnginePreferred; + DWORD dwClipUpdatesNBoxes; +#ifdef XWIN_EMULATEPSEUDO + Bool fEmulatePseudo; +#endif + Bool fFullScreen; + Bool fDecoration; +#ifdef XWIN_MULTIWINDOWEXTWM + Bool fMWExtWM; + Bool fInternalWM; + Bool fAnotherWMRunning; +#endif + Bool fRootless; +#ifdef XWIN_MULTIWINDOW + Bool fMultiWindow; +#endif +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + Bool fMultiMonitorOverride; +#endif + Bool fMultipleMonitors; + Bool fLessPointer; + Bool fScrollbars; + Bool fNoTrayIcon; + int iE3BTimeout; + /* Windows (Alt+F4) and Unix (Ctrl+Alt+Backspace) Killkey */ + Bool fUseWinKillKey; + Bool fUseUnixKillKey; + Bool fIgnoreInput; + + /* Did the user explicitly set this screen? */ + Bool fExplicitScreen; +} winScreenInfo, *winScreenInfoPtr; + + +/* + * Screen privates + */ + +typedef struct _winPrivScreenRec +{ + winScreenInfoPtr pScreenInfo; + + Bool fEnabled; + Bool fClosed; + Bool fActive; + Bool fBadDepth; + + int iDeltaZ; + + int iConnectedClients; + + CloseScreenProcPtr CloseScreen; + + DWORD dwRedMask; + DWORD dwGreenMask; + DWORD dwBlueMask; + DWORD dwBitsPerRGB; + + DWORD dwModeKeyStates; + + /* Handle to icons that must be freed */ + HICON hiconNotifyIcon; + + /* Last width, height, and depth of the Windows display */ + DWORD dwLastWindowsWidth; + DWORD dwLastWindowsHeight; + DWORD dwLastWindowsBitsPixel; + + /* Palette management */ + ColormapPtr pcmapInstalled; + + /* Pointer to the root visual so we only have to look it up once */ + VisualPtr pRootVisual; + + /* 3 button emulation variables */ + int iE3BCachedPress; + Bool fE3BFakeButton2Sent; + + /* Privates used by shadow fb GDI server */ + HBITMAP hbmpShadow; + HDC hdcScreen; + HDC hdcShadow; + HWND hwndScreen; + + /* Privates used by shadow fb and primary fb DirectDraw servers */ + LPDIRECTDRAW pdd; + LPDIRECTDRAWSURFACE2 pddsPrimary; + LPDIRECTDRAW2 pdd2; + + /* Privates used by shadow fb DirectDraw server */ + LPDIRECTDRAWSURFACE2 pddsShadow; + LPDDSURFACEDESC pddsdShadow; + + /* Privates used by primary fb DirectDraw server */ + LPDIRECTDRAWSURFACE2 pddsOffscreen; + LPDDSURFACEDESC pddsdOffscreen; + LPDDSURFACEDESC pddsdPrimary; + + /* Privates used by shadow fb DirectDraw Nonlocking server */ + LPDIRECTDRAW4 pdd4; + LPDIRECTDRAWSURFACE4 pddsShadow4; + LPDIRECTDRAWSURFACE4 pddsPrimary4; + BOOL fRetryCreateSurface; + + /* Privates used by both shadow fb DirectDraw servers */ + LPDIRECTDRAWCLIPPER pddcPrimary; + +#ifdef XWIN_MULTIWINDOWEXTWM + /* Privates used by multi-window external window manager */ + RootlessFrameID widTop; + Bool fRestacking; +#endif + +#ifdef XWIN_MULTIWINDOW + /* Privates used by multi-window */ + pthread_t ptWMProc; + pthread_t ptXMsgProc; + void *pWMInfo; +#endif + +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + /* Privates used by both multi-window and rootless */ + Bool fRootWindowShown; +#endif + +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) + /* Privates used for any module running in a seperate thread */ + pthread_mutex_t pmServerStarted; + Bool fServerStarted; +#endif + + /* Engine specific functions */ + winAllocateFBProcPtr pwinAllocateFB; + winShadowUpdateProcPtr pwinShadowUpdate; + winCloseScreenProcPtr pwinCloseScreen; + winInitVisualsProcPtr pwinInitVisuals; + winAdjustVideoModeProcPtr pwinAdjustVideoMode; + winCreateBoundingWindowProcPtr pwinCreateBoundingWindow; + winFinishScreenInitProcPtr pwinFinishScreenInit; + winBltExposedRegionsProcPtr pwinBltExposedRegions; + winActivateAppProcPtr pwinActivateApp; + winRedrawScreenProcPtr pwinRedrawScreen; + winRealizeInstalledPaletteProcPtr pwinRealizeInstalledPalette; + winInstallColormapProcPtr pwinInstallColormap; + winStoreColorsProcPtr pwinStoreColors; + winCreateColormapProcPtr pwinCreateColormap; + winDestroyColormapProcPtr pwinDestroyColormap; + winHotKeyAltTabProcPtr pwinHotKeyAltTab; + winCreatePrimarySurfaceProcPtr pwinCreatePrimarySurface; + winReleasePrimarySurfaceProcPtr pwinReleasePrimarySurface; + + winCreateScreenResourcesProc pwinCreateScreenResources; + +#ifdef XWIN_MULTIWINDOW + /* Window Procedures for MultiWindow mode */ + winFinishCreateWindowsWindowProcPtr pwinFinishCreateWindowsWindow; +#endif + + /* Window Procedures for Rootless mode */ + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + PositionWindowProcPtr PositionWindow; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + ValidateTreeProcPtr ValidateTree; + PostValidateTreeProcPtr PostValidateTree; + WindowExposuresProcPtr WindowExposures; + CopyWindowProcPtr CopyWindow; + ClearToBackgroundProcPtr ClearToBackground; + ClipNotifyProcPtr ClipNotify; + RestackWindowProcPtr RestackWindow; + ReparentWindowProcPtr ReparentWindow; + ResizeWindowProcPtr ResizeWindow; + MoveWindowProcPtr MoveWindow; + SetShapeProcPtr SetShape; + + winCursorRec cursor; +} winPrivScreenRec; + + +#ifdef XWIN_MULTIWINDOWEXTWM +typedef struct { + RootlessWindowPtr pFrame; + HWND hWnd; + int dwWidthBytes; + BITMAPINFOHEADER *pbmihShadow; + HBITMAP hbmpShadow; + HDC hdcShadow; + HDC hdcScreen; + BOOL fResized; + BOOL fRestackingNow; + BOOL fClose; + BOOL fMovingOrSizing; + BOOL fDestroyed;//for debug + char *pfb; +} win32RootlessWindowRec, *win32RootlessWindowPtr; +#endif + + +typedef struct { + pointer value; + XID id; +} WindowIDPairRec, *WindowIDPairPtr; + + +/* + * Extern declares for general global variables + */ + +extern winScreenInfo * g_ScreenInfo; +extern miPointerScreenFuncRec g_winPointerCursorFuncs; +extern DWORD g_dwEvents; +#ifdef HAS_DEVWINDOWS +extern int g_fdMessageQueue; +#endif +extern DevPrivateKey g_iScreenPrivateKey; +extern DevPrivateKey g_iCmapPrivateKey; +extern DevPrivateKey g_iGCPrivateKey; +extern DevPrivateKey g_iPixmapPrivateKey; +extern DevPrivateKey g_iWindowPrivateKey; +extern unsigned long g_ulServerGeneration; +extern DWORD g_dwEnginesSupported; +extern HINSTANCE g_hInstance; +extern int g_copyROP[]; +extern int g_patternROP[]; +extern const char * g_pszQueryHost; +extern DeviceIntPtr g_pwinPointer; +extern DeviceIntPtr g_pwinKeyboard; + + +/* + * Extern declares for dynamically loaded libraries and function pointers + */ + +extern HMODULE g_hmodDirectDraw; +extern FARPROC g_fpDirectDrawCreate; +extern FARPROC g_fpDirectDrawCreateClipper; + +extern HMODULE g_hmodCommonControls; +extern FARPROC g_fpTrackMouseEvent; + + +/* + * Screen privates macros + */ + +#define winGetScreenPriv(pScreen) ((winPrivScreenPtr) \ + dixLookupPrivate(&(pScreen)->devPrivates, g_iScreenPrivateKey)) + +#define winSetScreenPriv(pScreen,v) \ + dixSetPrivate(&(pScreen)->devPrivates, g_iScreenPrivateKey, v) + +#define winScreenPriv(pScreen) \ + winPrivScreenPtr pScreenPriv = winGetScreenPriv(pScreen) + + +/* + * Colormap privates macros + */ + +#define winGetCmapPriv(pCmap) ((winPrivCmapPtr) \ + dixLookupPrivate(&(pCmap)->devPrivates, g_iCmapPrivateKey)) + +#define winSetCmapPriv(pCmap,v) \ + dixSetPrivate(&(pCmap)->devPrivates, g_iCmapPrivateKey, v) + +#define winCmapPriv(pCmap) \ + winPrivCmapPtr pCmapPriv = winGetCmapPriv(pCmap) + + +/* + * GC privates macros + */ + +#define winGetGCPriv(pGC) ((winPrivGCPtr) \ + dixLookupPrivate(&(pGC)->devPrivates, g_iGCPrivateKey)) + +#define winSetGCPriv(pGC,v) \ + dixSetPrivate(&(pGC)->devPrivates, g_iGCPrivateKey, v) + +#define winGCPriv(pGC) \ + winPrivGCPtr pGCPriv = winGetGCPriv(pGC) + + +/* + * Pixmap privates macros + */ + +#define winGetPixmapPriv(pPixmap) ((winPrivPixmapPtr) \ + dixLookupPrivate(&(pPixmap)->devPrivates, g_iPixmapPrivateKey)) + +#define winSetPixmapPriv(pPixmap,v) \ + dixLookupPrivate(&(pPixmap)->devPrivates, g_iPixmapPrivateKey, v) + +#define winPixmapPriv(pPixmap) \ + winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap) + + +/* + * Window privates macros + */ + +#define winGetWindowPriv(pWin) ((winPrivWinPtr) \ + dixLookupPrivate(&(pWin)->devPrivates, g_iWindowPrivateKey)) + +#define winSetWindowPriv(pWin,v) \ + dixLookupPrivate(&(pWin)->devPrivates, g_iWindowPrivateKey, v) + +#define winWindowPriv(pWin) \ + winPrivWinPtr pWinPriv = winGetWindowPriv(pWin) + +/* + * wrapper macros + */ +#define _WIN_WRAP(priv, real, mem, func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define _WIN_UNWRAP(priv, real, mem) {\ + real->mem = priv->mem; \ +} + +#define WIN_WRAP(mem, func) _WIN_WRAP(pScreenPriv, pScreen, mem, func) + +#define WIN_UNWRAP(mem) _WIN_UNWRAP(pScreenPriv, pScreen, mem) + +/* + * BEGIN DDX and DIX Function Prototypes + */ + + +/* + * winallpriv.c + */ + +Bool +winAllocatePrivates (ScreenPtr pScreen); + +Bool +winInitCmapPrivates (ColormapPtr pCmap, int index); + +Bool +winAllocateCmapPrivates (ColormapPtr pCmap); + + +/* + * winauth.c + */ + +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) +Bool +winGenerateAuthorization (void); +void winSetAuthorization(void); +#endif + + +/* + * winblock.c + */ + +void +winBlockHandler (int nScreen, + pointer pBlockData, + pointer pTimeout, + pointer pReadMask); + + +#ifdef XWIN_NATIVEGDI +/* + * winclip.c + */ + +RegionPtr +winPixmapToRegionNativeGDI (PixmapPtr pPix); +#endif + + +#ifdef XWIN_CLIPBOARD +/* + * winclipboardinit.c + */ + +Bool +winInitClipboard (void); + +void +winFixClipboardChain (void); +#endif + + +/* + * wincmap.c + */ + +void +winSetColormapFunctions (ScreenPtr pScreen); + +Bool +winCreateDefColormap (ScreenPtr pScreen); + + +/* + * wincreatewnd.c + */ + +Bool +winCreateBoundingWindowFullScreen (ScreenPtr pScreen); + +Bool +winCreateBoundingWindowWindowed (ScreenPtr pScreen); + + +/* + * windialogs.c + */ + +void +winDisplayExitDialog (winPrivScreenPtr pScreenPriv); + +void +winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv); + +void +winDisplayAboutDialog (winPrivScreenPtr pScreenPriv); + + +/* + * winengine.c + */ + +void +winDetectSupportedEngines (void); + +Bool +winSetEngine (ScreenPtr pScreen); + +Bool +winGetDDProcAddresses (void); + + +/* + * winerror.c + */ + +#ifdef DDXOSVERRORF +void +OSVenderVErrorF (const char *pszFormat, va_list va_args); +#endif + +void +winMessageBoxF (const char *pszError, UINT uType, ...); + + +#ifdef XWIN_NATIVEGDI +/* + * winfillsp.c + */ + +void +winFillSpansNativeGDI (DrawablePtr pDrawable, + GCPtr pGC, + int nSpans, + DDXPointPtr pPoints, + int *pWidths, + int fSorted); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * winfont.c + */ + +Bool +winRealizeFontNativeGDI (ScreenPtr pScreen, FontPtr pFont); + +Bool +winUnrealizeFontNativeGDI (ScreenPtr pScreen, FontPtr pFont); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * wingc.c + */ + +Bool +winCreateGCNativeGDI (GCPtr pGC); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * wingetsp.c + */ + +void +winGetSpansNativeGDI (DrawablePtr pDrawable, + int wMax, + DDXPointPtr pPoints, + int *pWidths, + int nSpans, + char *pDst); +#endif + + +/* + * winglobals.c + */ + +void +winInitializeGlobals (void); + + +/* + * winkeybd.c + */ + +void +winTranslateKey (WPARAM wParam, LPARAM lParam, int *piScanCode); + +int +winKeybdProc (DeviceIntPtr pDeviceInt, int iState); + +void +winInitializeModeKeyStates (void); + +void +winRestoreModeKeyStates (void); + +Bool +winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam); + +void +winKeybdReleaseKeys (void); + +void +winSendKeyEvent (DWORD dwKey, Bool fDown); + +BOOL +winCheckKeyPressed(WPARAM wParam, LPARAM lParam); + +void +winFixShiftKeys (int iScanCode); + +/* + * winkeyhook.c + */ + +Bool +winInstallKeyboardHookLL (void); + +void +winRemoveKeyboardHookLL (void); + + +/* + * winmisc.c + */ + +#ifdef XWIN_NATIVEGDI +void +winQueryBestSizeNativeGDI (int class, unsigned short *pWidth, + unsigned short *pHeight, ScreenPtr pScreen); +#endif + +CARD8 +winCountBits (DWORD dw); + +Bool +winUpdateFBPointer (ScreenPtr pScreen, void *pbits); + +#ifdef XWIN_NATIVEGDI +BOOL +winPaintBackground (HWND hwnd, COLORREF colorref); +#endif + + +/* + * winmouse.c + */ + +int +winMouseProc (DeviceIntPtr pDeviceInt, int iState); + +int +winMouseWheel (ScreenPtr pScreen, int iDeltaZ); + +void +winMouseButtonsSendEvent (int iEventType, int iButton); + +int +winMouseButtonsHandle (ScreenPtr pScreen, + int iEventType, int iButton, + WPARAM wParam); + +void +winEnqueueMotion(int x, int y); + +#ifdef XWIN_NATIVEGDI +/* + * winnativegdi.c + */ + +HBITMAP +winCreateDIBNativeGDI (int iWidth, int iHeight, int iDepth, + BYTE **ppbBits, BITMAPINFO **ppbmi); + +Bool +winSetEngineFunctionsNativeGDI (ScreenPtr pScreen); +#endif + + +#ifdef XWIN_PRIMARYFB +/* + * winpfbddd.c + */ + +Bool +winSetEngineFunctionsPrimaryDD (ScreenPtr pScreen); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * winpixmap.c + */ + +PixmapPtr +winCreatePixmapNativeGDI (ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint); + +Bool +winDestroyPixmapNativeGDI (PixmapPtr pPixmap); + +Bool +winModifyPixmapHeaderNativeGDI (PixmapPtr pPixmap, + int iWidth, int iHeight, + int iDepth, + int iBitsPerPixel, + int devKind, + pointer pPixData); +#endif + +#ifdef XWIN_NATIVEGDI +/* + * winpolyline.c + */ + +void +winPolyLineNativeGDI (DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr ppt); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * winpushpxl.c + */ + +void +winPushPixels (GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, + int dx, int dy, int xOrg, int yOrg); +#endif + + +/* + * winscrinit.c + */ + +Bool +winScreenInit (int index, + ScreenPtr pScreen, + int argc, char **argv); + +Bool +winFinishScreenInitFB (int index, + ScreenPtr pScreen, + int argc, char **argv); + +#if defined(XWIN_NATIVEGDI) +Bool +winFinishScreenInitNativeGDI (int index, + ScreenPtr pScreen, + int argc, char **argv); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * winsetsp.c + */ + +void +winSetSpansNativeGDI (DrawablePtr pDrawable, + GCPtr pGC, + char *pSrc, + DDXPointPtr pPoints, + int *pWidth, + int nSpans, + int fSorted); +#endif + + +/* + * winshaddd.c + */ + +Bool +winSetEngineFunctionsShadowDD (ScreenPtr pScreen); + + +/* + * winshadddnl.c + */ + +Bool +winSetEngineFunctionsShadowDDNL (ScreenPtr pScreen); + + +/* + * winshadgdi.c + */ + +Bool +winSetEngineFunctionsShadowGDI (ScreenPtr pScreen); + + +/* + * winwakeup.c + */ + +void +winWakeupHandler (int nScreen, + pointer pWakeupData, + unsigned long ulResult, + pointer pReadmask); + + +/* + * winwindow.c + */ + +#ifdef XWIN_NATIVEGDI +Bool +winCreateWindowNativeGDI (WindowPtr pWin); + +Bool +winDestroyWindowNativeGDI (WindowPtr pWin); + +Bool +winPositionWindowNativeGDI (WindowPtr pWin, int x, int y); + +void +winCopyWindowNativeGDI (WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc); + +Bool +winChangeWindowAttributesNativeGDI (WindowPtr pWin, unsigned long mask); + +Bool +winUnmapWindowNativeGDI (WindowPtr pWindow); + +Bool +winMapWindowNativeGDI (WindowPtr pWindow); +#endif + +Bool +winCreateWindowRootless (WindowPtr pWindow); + +Bool +winDestroyWindowRootless (WindowPtr pWindow); + +Bool +winPositionWindowRootless (WindowPtr pWindow, int x, int y); + +Bool +winChangeWindowAttributesRootless (WindowPtr pWindow, unsigned long mask); + +Bool +winUnmapWindowRootless (WindowPtr pWindow); + +Bool +winMapWindowRootless (WindowPtr pWindow); + +void +winSetShapeRootless (WindowPtr pWindow); + + +/* + * winmultiwindowicons.c - Used by both multi-window and Win32Rootless + */ + +HICON +winXIconToHICON (WindowPtr pWin, int iconSize); + +void +winSelectIcons(WindowPtr pWin, HICON *pIcon, HICON *pSmallIcon); + +#ifdef XWIN_MULTIWINDOW +/* + * winmultiwindowshape.c + */ + +void +winReshapeMultiWindow (WindowPtr pWin); + +void +winSetShapeMultiWindow (WindowPtr pWindow); + +void +winUpdateRgnMultiWindow (WindowPtr pWindow); +#endif + + +#ifdef XWIN_MULTIWINDOW +/* + * winmultiwindowwindow.c + */ + +Bool +winCreateWindowMultiWindow (WindowPtr pWindow); + +Bool +winDestroyWindowMultiWindow (WindowPtr pWindow); + +Bool +winPositionWindowMultiWindow (WindowPtr pWindow, int x, int y); + +Bool +winChangeWindowAttributesMultiWindow (WindowPtr pWindow, unsigned long mask); + +Bool +winUnmapWindowMultiWindow (WindowPtr pWindow); + +Bool +winMapWindowMultiWindow (WindowPtr pWindow); + +void +winReparentWindowMultiWindow (WindowPtr pWin, WindowPtr pPriorParent); + +void +winRestackWindowMultiWindow (WindowPtr pWin, WindowPtr pOldNextSib); + +void +winReorderWindowsMultiWindow (void); + +void +winResizeWindowMultiWindow (WindowPtr pWin, int x, int y, unsigned int w, + unsigned int h, WindowPtr pSib); +void +winMoveWindowMultiWindow (WindowPtr pWin, int x, int y, + WindowPtr pSib, VTKind kind); + +void +winCopyWindowMultiWindow (WindowPtr pWin, DDXPointRec oldpt, + RegionPtr oldRegion); + +XID +winGetWindowID (WindowPtr pWin); + +int +winAdjustXWindow (WindowPtr pWin, HWND hwnd); +#endif + + +#ifdef XWIN_MULTIWINDOW +/* + * winmultiwindowwndproc.c + */ + +LRESULT CALLBACK +winTopLevelWindowProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam); +#endif + + +/* + * wintrayicon.c + */ + +void +winInitNotifyIcon (winPrivScreenPtr pScreenPriv); + +void +winDeleteNotifyIcon (winPrivScreenPtr pScreenPriv); + +LRESULT +winHandleIconMessage (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam, + winPrivScreenPtr pScreenPriv); + + +/* + * winwndproc.c + */ + +LRESULT CALLBACK +winWindowProc (HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam); + + +#ifdef XWIN_MULTIWINDOWEXTWM +/* + * winwin32rootless.c + */ + +Bool +winMWExtWMCreateFrame (RootlessWindowPtr pFrame, ScreenPtr pScreen, + int newX, int newY, RegionPtr pShape); + +void +winMWExtWMDestroyFrame (RootlessFrameID wid); + +void +winMWExtWMMoveFrame (RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY); + +void +winMWExtWMResizeFrame (RootlessFrameID wid, ScreenPtr pScreen, + int newX, int newY, unsigned int newW, unsigned int newH, + unsigned int gravity); + +void +winMWExtWMRestackFrame (RootlessFrameID wid, RootlessFrameID nextWid); + +void +winMWExtWMReshapeFrame (RootlessFrameID wid, RegionPtr pShape); + +void +winMWExtWMUnmapFrame (RootlessFrameID wid); + +void +winMWExtWMStartDrawing (RootlessFrameID wid, char **pixelData, int *bytesPerRow); + +void +winMWExtWMStopDrawing (RootlessFrameID wid, Bool flush); + +void +winMWExtWMUpdateRegion (RootlessFrameID wid, RegionPtr pDamage); + +void +winMWExtWMDamageRects (RootlessFrameID wid, int count, const BoxRec *rects, + int shift_x, int shift_y); + +void +winMWExtWMRootlessSwitchWindow (RootlessWindowPtr pFrame, WindowPtr oldWin); + +void +winMWExtWMCopyBytes (unsigned int width, unsigned int height, + const void *src, unsigned int srcRowBytes, + void *dst, unsigned int dstRowBytes); + +void +winMWExtWMFillBytes (unsigned int width, unsigned int height, unsigned int value, + void *dst, unsigned int dstRowBytes); + +int +winMWExtWMCompositePixels (unsigned int width, unsigned int height, unsigned int function, + void *src[2], unsigned int srcRowBytes[2], + void *mask, unsigned int maskRowBytes, + void *dst[2], unsigned int dstRowBytes[2]); + +void +winMWExtWMCopyWindow (RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, + int dx, int dy); +#endif + + +#ifdef XWIN_MULTIWINDOWEXTWM +/* + * winwin32rootlesswindow.c + */ + +void +winMWExtWMReorderWindows (ScreenPtr pScreen); + +void +winMWExtWMMoveXWindow (WindowPtr pWin, int x, int y); + +void +winMWExtWMResizeXWindow (WindowPtr pWin, int w, int h); + +void +winMWExtWMMoveResizeXWindow (WindowPtr pWin, int x, int y, int w, int h); + +void +winMWExtWMUpdateIcon (Window id); + +void +winMWExtWMUpdateWindowDecoration (win32RootlessWindowPtr pRLWinPriv, + winScreenInfoPtr pScreenInfo); + +wBOOL CALLBACK +winMWExtWMDecorateWindow (HWND hwnd, LPARAM lParam); + +Bool +winIsInternalWMRunning (winScreenInfoPtr pScreenInfo); + +void +winMWExtWMRestackWindows (ScreenPtr pScreen); +#endif + + +#ifdef XWIN_MULTIWINDOWEXTWM +/* + * winwin32rootlesswndproc.c + */ + +LRESULT CALLBACK +winMWExtWMWindowProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam); +#endif + + +/* + * winwindowswm.c + */ + +void +winWindowsWMSendEvent (int type, unsigned int mask, int which, int arg, + Window window, int x, int y, int w, int h); + +void +winWindowsWMExtensionInit (void); + +/* + * wincursor.c + */ + +Bool +winInitCursor (ScreenPtr pScreen); + +/* + * winprocarg.c + */ +void +winInitializeScreens(int maxscreens); + +/* + * END DDX and DIX Function Prototypes + */ + +#endif /* _WIN_H_ */ + diff --git a/xorg-server/hw/xwin/winauth.c b/xorg-server/hw/xwin/winauth.c index 2780f6acd..7d4372549 100644 --- a/xorg-server/hw/xwin/winauth.c +++ b/xorg-server/hw/xwin/winauth.c @@ -150,7 +150,7 @@ winGenerateAuthorization (void) #ifdef XCSECURITY /* Allocate structure for additional auth information */ pAuth = (SecurityAuthorizationPtr) - xalloc (sizeof (SecurityAuthorizationRec)); + malloc(sizeof (SecurityAuthorizationRec)); if (!(pAuth)) { ErrorF ("winGenerateAuthorization - Failed allocating " @@ -186,7 +186,7 @@ winGenerateAuthorization (void) auth_bailout: if (fFreeAuth) - xfree (pAuth); + free(pAuth); return FALSE; } diff --git a/xorg-server/hw/xwin/winconfig.c b/xorg-server/hw/xwin/winconfig.c index 0f9126d77..c972bbcad 100644 --- a/xorg-server/hw/xwin/winconfig.c +++ b/xorg-server/hw/xwin/winconfig.c @@ -393,10 +393,10 @@ winConfigKeyboard (DeviceIntPtr pDevice) (1000 / g_winInfo.keyboard.rate) < 1) { winErrorFVerb (2, "\"%s\" is not a valid AutoRepeat value", s); - xfree(s); + free(s); return FALSE; } - xfree(s); + free(s); winMsg (X_CONFIG, "AutoRepeat: %ld %ld\n", g_winInfo.keyboard.delay, g_winInfo.keyboard.rate); } diff --git a/xorg-server/hw/xwin/windialogs.c b/xorg-server/hw/xwin/windialogs.c index a8153535f..a1e2e1709 100644 --- a/xorg-server/hw/xwin/windialogs.c +++ b/xorg-server/hw/xwin/windialogs.c @@ -1,787 +1,787 @@ -/* - *Copyright (C) 2003-2004 Harold L Hunt II 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 HAROLD L HUNT II 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 Harold L Hunt II - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from Harold L Hunt II. - * - * Authors: Harold L Hunt II - * Earle F. Philhower III - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include <xwin-config.h> -#endif -#include "win.h" -#ifdef __CYGWIN__ -#include <sys/cygwin.h> -#endif -#include <shellapi.h> -#include "winprefs.h" - - -/* - * References to external globals - */ - -extern Bool g_fCursor; -extern HWND g_hDlgDepthChange; -extern HWND g_hDlgExit; -extern HWND g_hDlgAbout; -extern WINPREFS pref; -#ifdef XWIN_CLIPBOARD -extern Bool g_fClipboardStarted; -#endif -extern Bool g_fSoftwareCursor; - -#if defined(XWIN_MULTIWINDOW) -extern HICON g_hIconX; -extern HICON g_hSmallIconX; -#endif - -/* - * Local function prototypes - */ - -static wBOOL CALLBACK -winExitDlgProc (HWND hDialog, UINT message, - WPARAM wParam, LPARAM lParam); - -static wBOOL CALLBACK -winChangeDepthDlgProc (HWND hDialog, UINT message, - WPARAM wParam, LPARAM lParam); - -static wBOOL CALLBACK -winAboutDlgProc (HWND hDialog, UINT message, - WPARAM wParam, LPARAM lParam); - - -static void -winDrawURLWindow (LPARAM lParam); - -static LRESULT CALLBACK -winURLWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - -static void -winOverrideURLButton (HWND hdlg, int id); - -static void -winUnoverrideURLButton (HWND hdlg, int id); - - -/* - * Owner-draw a button as a URL - */ - -static void -winDrawURLWindow (LPARAM lParam) -{ - DRAWITEMSTRUCT *draw; - char str[256]; - RECT rect; - HFONT font; - COLORREF crText; - - draw = (DRAWITEMSTRUCT *) lParam; - GetWindowText (draw->hwndItem, str, sizeof(str)); - str[255] = 0; - GetClientRect (draw->hwndItem, &rect); - - /* Color the button depending upon its state */ - if (draw->itemState & ODS_SELECTED) - crText = RGB(128+64,0,0); - else if (draw->itemState & ODS_FOCUS) - crText = RGB(0,128+64,0); - else - crText = RGB(0,0,128+64); - SetTextColor (draw->hDC, crText); - - /* Create font 8 high, standard dialog font */ - font = CreateFont (-8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, - 0, 0, 0, 0, 0, "MS Sans Serif"); - if (!font) - { - ErrorF ("winDrawURLWindow: Unable to create URL font, bailing.\n"); - return; - } - /* Draw it */ - SetBkMode (draw->hDC, OPAQUE); - SelectObject (draw->hDC, font); - DrawText (draw->hDC, str, strlen (str),&rect,DT_CENTER | DT_VCENTER); - /* Delete the created font, replace it with stock font */ - DeleteObject (SelectObject (draw->hDC, GetStockObject (ANSI_VAR_FONT))); -} - - -/* - * WndProc for overridden buttons - */ - -static LRESULT CALLBACK -winURLWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - WNDPROC origCB = NULL; - HCURSOR cursor; - - /* If it's a SetCursor message, tell it to the hand */ - if (msg==WM_SETCURSOR) { - cursor = LoadCursor (NULL, IDC_HAND); - if (cursor) - SetCursor (cursor); - return TRUE; - } - origCB = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); - /* Otherwise fall through to original WndProc */ - if (origCB) - return CallWindowProc (origCB, hwnd, msg, wParam, lParam); - else - return FALSE; -} - - -/* - * Register and unregister the custom WndProc - */ - -static void -winOverrideURLButton (HWND hwnd, int id) -{ - WNDPROC origCB; - origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id), - GWLP_WNDPROC, (LONG_PTR)winURLWndProc); - SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_USERDATA, (LONG_PTR)origCB); -} - -static void -winUnoverrideURLButton (HWND hwnd, int id) -{ - WNDPROC origCB; - origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id), - GWLP_USERDATA, 0); - if (origCB) - SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_WNDPROC, (LONG_PTR)origCB); -} - - -/* - * Center a dialog window in the desktop window - * and set small and large icons to X icons. - */ - -static void -winInitDialog (HWND hwndDlg) -{ - HWND hwndDesk; - RECT rc, rcDlg, rcDesk; - HICON hIcon, hIconSmall; - - hwndDesk = GetParent (hwndDlg); - if (!hwndDesk || IsIconic (hwndDesk)) - hwndDesk = GetDesktopWindow (); - - /* Remove minimize and maximize buttons */ - SetWindowLongPtr(hwndDlg, GWL_STYLE, - GetWindowLongPtr(hwndDlg, GWL_STYLE) - & ~(WS_MAXIMIZEBOX | WS_MINIMIZEBOX)); - - /* Set Window not to show in the task bar */ - SetWindowLongPtr(hwndDlg, GWL_EXSTYLE, - GetWindowLongPtr(hwndDlg, GWL_EXSTYLE) & ~WS_EX_APPWINDOW ); - - /* Center dialog window in the screen. Not done for multi-monitor systems, where - * it is likely to end up split across the screens. In that case, it appears - * near the Tray icon. - */ - if (GetSystemMetrics(SM_CMONITORS)>1) { - /* Still need to refresh the frame change. */ - SetWindowPos (hwndDlg, HWND_TOPMOST, 0,0,0,0, - SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); - } else { - GetWindowRect (hwndDesk, &rcDesk); - GetWindowRect (hwndDlg, &rcDlg); - CopyRect (&rc, &rcDesk); - - OffsetRect (&rcDlg, -rcDlg.left, -rcDlg.top); - OffsetRect (&rc, -rc.left, -rc.top); - OffsetRect (&rc, -rcDlg.right, -rcDlg.bottom); - - SetWindowPos (hwndDlg, - HWND_TOPMOST, - rcDesk.left + (rc.right / 2), - rcDesk.top + (rc.bottom / 2), - 0, 0, - SWP_NOSIZE | SWP_FRAMECHANGED); - } - -#ifdef XWIN_MULTIWINDOW - if (g_hIconX) hIcon=g_hIconX; - else -#endif - hIcon = LoadIcon (g_hInstance, MAKEINTRESOURCE(IDI_XWIN)); - -#ifdef XWIN_MULTIWINDOW - if (g_hSmallIconX) hIconSmall=g_hSmallIconX; - else -#endif - hIconSmall = LoadImage (g_hInstance, - MAKEINTRESOURCE(IDI_XWIN), IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_SHARED); - - PostMessage (hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon); - PostMessage (hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall); -} - - -/* - * Display the Exit dialog box - */ - -void -winDisplayExitDialog (winPrivScreenPtr pScreenPriv) -{ - int i; - int liveClients = 0; - - /* Count up running clients (clients[0] is serverClient) */ - for (i = 1; i < currentMaxClients; i++) - if (clients[i] != NullClient) - liveClients++; -#if defined(XWIN_MULTIWINDOW) - /* Count down server internal clients */ - if (pScreenPriv->pScreenInfo->fMultiWindow) - liveClients -= 2; /* multiwindow window manager & XMsgProc */ -#endif -#if defined(XWIN_CLIPBOARD) - if (g_fClipboardStarted) - liveClients--; /* clipboard manager */ -#endif - - /* A user reported that this sometimes drops below zero. just eye-candy. */ - if (liveClients < 0) - liveClients = 0; - - /* Don't show the exit confirmation dialog if SilentExit & no clients, - or ForceExit, is enabled */ - if ((pref.fSilentExit && liveClients <= 0) || pref.fForceExit) - { - if (g_hDlgExit != NULL) - { - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - } - PostMessage (pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); - return; - } - - pScreenPriv->iConnectedClients = liveClients; - - /* Check if dialog already exists */ - if (g_hDlgExit != NULL) - { - /* Dialog box already exists, display it */ - ShowWindow (g_hDlgExit, SW_SHOWDEFAULT); - - /* User has lost the dialog. Show them where it is. */ - SetForegroundWindow (g_hDlgExit); - - return; - } - - /* Create dialog box */ - g_hDlgExit = CreateDialogParam (g_hInstance, - "EXIT_DIALOG", - pScreenPriv->hwndScreen, - winExitDlgProc, - (int) pScreenPriv); - - /* Show the dialog box */ - ShowWindow (g_hDlgExit, SW_SHOW); - - /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */ - SetForegroundWindow (g_hDlgExit); - - /* Set focus to the Cancel button */ - PostMessage (g_hDlgExit, WM_NEXTDLGCTL, - GetDlgItem (g_hDlgExit, IDCANCEL), TRUE); -} - -#define CONNECTED_CLIENTS_FORMAT "There %s currently %d client%s connected." - - -/* - * Exit dialog window procedure - */ - -static wBOOL CALLBACK -winExitDlgProc (HWND hDialog, UINT message, - WPARAM wParam, LPARAM lParam) -{ - static winPrivScreenPtr s_pScreenPriv = NULL; - - /* Branch on message type */ - switch (message) - { - case WM_INITDIALOG: - { - char *pszConnectedClients; - - /* Store pointers to private structures for future use */ - s_pScreenPriv = (winPrivScreenPtr) lParam; - - winInitDialog (hDialog); - - /* Format the connected clients string */ - pszConnectedClients = Xprintf (CONNECTED_CLIENTS_FORMAT, - (s_pScreenPriv->iConnectedClients == 1) ? "is" : "are", - s_pScreenPriv->iConnectedClients, - (s_pScreenPriv->iConnectedClients == 1) ? "" : "s"); - if (!pszConnectedClients) - return TRUE; - - - - /* Set the number of connected clients */ - SetWindowText (GetDlgItem (hDialog, IDC_CLIENTS_CONNECTED), - pszConnectedClients); - xfree (pszConnectedClients); - } - return TRUE; - - case WM_COMMAND: - switch (LOWORD (wParam)) - { - case IDOK: - /* Send message to call the GiveUp function */ - PostMessage (s_pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - return TRUE; - - case IDCANCEL: - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - return TRUE; - } - break; - - case WM_MOUSEMOVE: - case WM_NCMOUSEMOVE: - /* Show the cursor if it is hidden */ - if (g_fSoftwareCursor && !g_fCursor) - { - g_fCursor = TRUE; - ShowCursor (TRUE); - } - return TRUE; - - case WM_CLOSE: - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - return TRUE; - } - - return FALSE; -} - - -/* - * Display the Depth Change dialog box - */ - -void -winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv) -{ - /* Check if dialog already exists */ - if (g_hDlgDepthChange != NULL) - { - /* Dialog box already exists, display it */ - ShowWindow (g_hDlgDepthChange, SW_SHOWDEFAULT); - - /* User has lost the dialog. Show them where it is. */ - SetForegroundWindow (g_hDlgDepthChange); - - return; - } - - /* - * Display a notification to the user that the visual - * will not be displayed until the Windows display depth - * is restored to the original value. - */ - g_hDlgDepthChange = CreateDialogParam (g_hInstance, - "DEPTH_CHANGE_BOX", - pScreenPriv->hwndScreen, - winChangeDepthDlgProc, - (int) pScreenPriv); - /* Show the dialog box */ - ShowWindow (g_hDlgDepthChange, SW_SHOW); - - ErrorF ("winDisplayDepthChangeDialog - DialogBox returned: %d\n", - (int) g_hDlgDepthChange); - ErrorF ("winDisplayDepthChangeDialog - GetLastError: %d\n", - (int) GetLastError ()); - - /* Minimize the display window */ - ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE); -} - - -/* - * Process messages for the dialog that is displayed for - * disruptive screen depth changes. - */ - -static wBOOL CALLBACK -winChangeDepthDlgProc (HWND hwndDialog, UINT message, - WPARAM wParam, LPARAM lParam) -{ - static winPrivScreenPtr s_pScreenPriv = NULL; - static winScreenInfo *s_pScreenInfo = NULL; - static ScreenPtr s_pScreen = NULL; - -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc\n"); -#endif - - /* Branch on message type */ - switch (message) - { - case WM_INITDIALOG: -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc - WM_INITDIALOG\n"); -#endif - - /* Store pointers to private structures for future use */ - s_pScreenPriv = (winPrivScreenPtr) lParam; - s_pScreenInfo = s_pScreenPriv->pScreenInfo; - s_pScreen = s_pScreenInfo->pScreen; - -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - s_pScreenPriv: %08x, " - "s_pScreenInfo: %08x, s_pScreen: %08x\n", - s_pScreenPriv, s_pScreenInfo, s_pScreen); -#endif - -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - orig bpp: %d, " - "last bpp: %d\n", - s_pScreenInfo->dwBPP, - s_pScreenPriv->dwLastWindowsBitsPixel); -#endif - - winInitDialog( hwndDialog ); - - return TRUE; - - case WM_DISPLAYCHANGE: -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc - WM_DISPLAYCHANGE - orig bpp: %d, " - "last bpp: %d, new bpp: %d\n", - s_pScreenInfo->dwBPP, - s_pScreenPriv->dwLastWindowsBitsPixel, - wParam); -#endif - - /* Dismiss the dialog if the display returns to the original depth */ - if (wParam == s_pScreenInfo->dwBPP) - { - ErrorF ("winChangeDelthDlgProc - wParam == s_pScreenInfo->dwBPP\n"); - - /* Depth has been restored, dismiss dialog */ - DestroyWindow (g_hDlgDepthChange); - g_hDlgDepthChange = NULL; - - /* Flag that we have a valid screen depth */ - s_pScreenPriv->fBadDepth = FALSE; - } - return TRUE; - - case WM_COMMAND: - switch (LOWORD (wParam)) - { - case IDOK: - case IDCANCEL: - ErrorF ("winChangeDepthDlgProc - WM_COMMAND - IDOK or IDCANCEL\n"); - - /* - * User dismissed the dialog, hide it until the - * display mode is restored. - */ - ShowWindow (g_hDlgDepthChange, SW_HIDE); - return TRUE; - } - break; - - case WM_CLOSE: - ErrorF ("winChangeDepthDlgProc - WM_CLOSE\n"); - - DestroyWindow (g_hDlgAbout); - g_hDlgAbout = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - return TRUE; - } - - return FALSE; -} - - -/* - * Display the About dialog box - */ - -void -winDisplayAboutDialog (winPrivScreenPtr pScreenPriv) -{ - /* Check if dialog already exists */ - if (g_hDlgAbout != NULL) - { - /* Dialog box already exists, display it */ - ShowWindow (g_hDlgAbout, SW_SHOWDEFAULT); - - /* User has lost the dialog. Show them where it is. */ - SetForegroundWindow (g_hDlgAbout); - - return; - } - - /* - * Display the about box - */ - g_hDlgAbout = CreateDialogParam (g_hInstance, - "ABOUT_BOX", - pScreenPriv->hwndScreen, - winAboutDlgProc, - (int) pScreenPriv); - - /* Show the dialog box */ - ShowWindow (g_hDlgAbout, SW_SHOW); - - /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */ - SetForegroundWindow (g_hDlgAbout); - - /* Set focus to the OK button */ - PostMessage (g_hDlgAbout, WM_NEXTDLGCTL, - GetDlgItem (g_hDlgAbout, IDOK), TRUE); -} - - -/* - * Process messages for the about dialog. - */ - -static wBOOL CALLBACK -winAboutDlgProc (HWND hwndDialog, UINT message, - WPARAM wParam, LPARAM lParam) -{ - static winPrivScreenPtr s_pScreenPriv = NULL; - static winScreenInfo *s_pScreenInfo = NULL; - static ScreenPtr s_pScreen = NULL; - -#if CYGDEBUG - winDebug ("winAboutDlgProc\n"); -#endif - - /* Branch on message type */ - switch (message) - { - case WM_INITDIALOG: -#if CYGDEBUG - winDebug ("winAboutDlgProc - WM_INITDIALOG\n"); -#endif - - /* Store pointers to private structures for future use */ - s_pScreenPriv = (winPrivScreenPtr) lParam; - s_pScreenInfo = s_pScreenPriv->pScreenInfo; - s_pScreen = s_pScreenInfo->pScreen; - - winInitDialog (hwndDialog); - - /* Override the URL buttons */ - winOverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); - winOverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); - winOverrideURLButton (hwndDialog, ID_ABOUT_UG); - winOverrideURLButton (hwndDialog, ID_ABOUT_FAQ); - - return TRUE; - - case WM_DRAWITEM: - /* Draw the URL buttons as needed */ - winDrawURLWindow (lParam); - return TRUE; - - case WM_MOUSEMOVE: - case WM_NCMOUSEMOVE: - /* Show the cursor if it is hidden */ - if (g_fSoftwareCursor && !g_fCursor) - { - g_fCursor = TRUE; - ShowCursor (TRUE); - } - return TRUE; - - case WM_COMMAND: - switch (LOWORD (wParam)) - { - case IDOK: - case IDCANCEL: - ErrorF ("winAboutDlgProc - WM_COMMAND - IDOK or IDCANCEL\n"); - - DestroyWindow (g_hDlgAbout); - g_hDlgAbout = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - - /* Restore window procedures for URL buttons */ - winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ); - - return TRUE; - - case ID_ABOUT_CHANGELOG: - { - HINSTANCE iReturn; -#ifdef __CYGWIN__ - const char * pszCygPath = "/usr/X11R6/share/doc/" - "xorg-x11-xwin/changelog.html"; - char pszWinPath[MAX_PATH + 1]; - - /* Convert the POSIX path to a Win32 path */ - cygwin_conv_to_win32_path (pszCygPath, pszWinPath); -#else - const char * pszWinPath = "http://x.cygwin.com/" - "devel/server/changelog.html"; -#endif - - iReturn = ShellExecute (NULL, - "open", - pszWinPath, - NULL, - NULL, - SW_MAXIMIZE); - if (iReturn < 32) - { - ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_CHANGELOG - " - "ShellExecute failed: %d\n", - iReturn); - } - } - return TRUE; - - case ID_ABOUT_WEBSITE: - { - const char * pszPath = __VENDORDWEBSUPPORT__; - int iReturn; - - iReturn = ShellExecute (NULL, - "open", - pszPath, - NULL, - NULL, - SW_MAXIMIZE); - if (iReturn < 32) - { - ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_WEBSITE - " - "ShellExecute failed: %d\n", - iReturn); - } - } - return TRUE; - - case ID_ABOUT_UG: - { - const char * pszPath = "http://x.cygwin.com/docs/ug/"; - int iReturn; - - iReturn = ShellExecute (NULL, - "open", - pszPath, - NULL, - NULL, - SW_MAXIMIZE); - if (iReturn < 32) - { - ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_UG - " - "ShellExecute failed: %d\n", - iReturn); - } - } - return TRUE; - - case ID_ABOUT_FAQ: - { - const char * pszPath = "http://x.cygwin.com/docs/faq/"; - int iReturn; - - iReturn = ShellExecute (NULL, - "open", - pszPath, - NULL, - NULL, - SW_MAXIMIZE); - if (iReturn < 32) - { - ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_FAQ - " - "ShellExecute failed: %d\n", - iReturn); - } - } - return TRUE; - } - break; - - case WM_CLOSE: - ErrorF ("winAboutDlgProc - WM_CLOSE\n"); - - DestroyWindow (g_hDlgAbout); - g_hDlgAbout = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - - /* Restore window procedures for URL buttons */ - winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ); - - return TRUE; - } - - return FALSE; -} +/* + *Copyright (C) 2003-2004 Harold L Hunt II 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 HAROLD L HUNT II 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 Harold L Hunt II + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from Harold L Hunt II. + * + * Authors: Harold L Hunt II + * Earle F. Philhower III + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif +#include "win.h" +#ifdef __CYGWIN__ +#include <sys/cygwin.h> +#endif +#include <shellapi.h> +#include "winprefs.h" + + +/* + * References to external globals + */ + +extern Bool g_fCursor; +extern HWND g_hDlgDepthChange; +extern HWND g_hDlgExit; +extern HWND g_hDlgAbout; +extern WINPREFS pref; +#ifdef XWIN_CLIPBOARD +extern Bool g_fClipboardStarted; +#endif +extern Bool g_fSoftwareCursor; + +#if defined(XWIN_MULTIWINDOW) +extern HICON g_hIconX; +extern HICON g_hSmallIconX; +#endif + +/* + * Local function prototypes + */ + +static wBOOL CALLBACK +winExitDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam); + +static wBOOL CALLBACK +winChangeDepthDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam); + +static wBOOL CALLBACK +winAboutDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam); + + +static void +winDrawURLWindow (LPARAM lParam); + +static LRESULT CALLBACK +winURLWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +static void +winOverrideURLButton (HWND hdlg, int id); + +static void +winUnoverrideURLButton (HWND hdlg, int id); + + +/* + * Owner-draw a button as a URL + */ + +static void +winDrawURLWindow (LPARAM lParam) +{ + DRAWITEMSTRUCT *draw; + char str[256]; + RECT rect; + HFONT font; + COLORREF crText; + + draw = (DRAWITEMSTRUCT *) lParam; + GetWindowText (draw->hwndItem, str, sizeof(str)); + str[255] = 0; + GetClientRect (draw->hwndItem, &rect); + + /* Color the button depending upon its state */ + if (draw->itemState & ODS_SELECTED) + crText = RGB(128+64,0,0); + else if (draw->itemState & ODS_FOCUS) + crText = RGB(0,128+64,0); + else + crText = RGB(0,0,128+64); + SetTextColor (draw->hDC, crText); + + /* Create font 8 high, standard dialog font */ + font = CreateFont (-8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, + 0, 0, 0, 0, 0, "MS Sans Serif"); + if (!font) + { + ErrorF ("winDrawURLWindow: Unable to create URL font, bailing.\n"); + return; + } + /* Draw it */ + SetBkMode (draw->hDC, OPAQUE); + SelectObject (draw->hDC, font); + DrawText (draw->hDC, str, strlen (str),&rect,DT_CENTER | DT_VCENTER); + /* Delete the created font, replace it with stock font */ + DeleteObject (SelectObject (draw->hDC, GetStockObject (ANSI_VAR_FONT))); +} + + +/* + * WndProc for overridden buttons + */ + +static LRESULT CALLBACK +winURLWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC origCB = NULL; + HCURSOR cursor; + + /* If it's a SetCursor message, tell it to the hand */ + if (msg==WM_SETCURSOR) { + cursor = LoadCursor (NULL, IDC_HAND); + if (cursor) + SetCursor (cursor); + return TRUE; + } + origCB = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); + /* Otherwise fall through to original WndProc */ + if (origCB) + return CallWindowProc (origCB, hwnd, msg, wParam, lParam); + else + return FALSE; +} + + +/* + * Register and unregister the custom WndProc + */ + +static void +winOverrideURLButton (HWND hwnd, int id) +{ + WNDPROC origCB; + origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id), + GWLP_WNDPROC, (LONG_PTR)winURLWndProc); + SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_USERDATA, (LONG_PTR)origCB); +} + +static void +winUnoverrideURLButton (HWND hwnd, int id) +{ + WNDPROC origCB; + origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id), + GWLP_USERDATA, 0); + if (origCB) + SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_WNDPROC, (LONG_PTR)origCB); +} + + +/* + * Center a dialog window in the desktop window + * and set small and large icons to X icons. + */ + +static void +winInitDialog (HWND hwndDlg) +{ + HWND hwndDesk; + RECT rc, rcDlg, rcDesk; + HICON hIcon, hIconSmall; + + hwndDesk = GetParent (hwndDlg); + if (!hwndDesk || IsIconic (hwndDesk)) + hwndDesk = GetDesktopWindow (); + + /* Remove minimize and maximize buttons */ + SetWindowLongPtr(hwndDlg, GWL_STYLE, + GetWindowLongPtr(hwndDlg, GWL_STYLE) + & ~(WS_MAXIMIZEBOX | WS_MINIMIZEBOX)); + + /* Set Window not to show in the task bar */ + SetWindowLongPtr(hwndDlg, GWL_EXSTYLE, + GetWindowLongPtr(hwndDlg, GWL_EXSTYLE) & ~WS_EX_APPWINDOW ); + + /* Center dialog window in the screen. Not done for multi-monitor systems, where + * it is likely to end up split across the screens. In that case, it appears + * near the Tray icon. + */ + if (GetSystemMetrics(SM_CMONITORS)>1) { + /* Still need to refresh the frame change. */ + SetWindowPos (hwndDlg, HWND_TOPMOST, 0,0,0,0, + SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + } else { + GetWindowRect (hwndDesk, &rcDesk); + GetWindowRect (hwndDlg, &rcDlg); + CopyRect (&rc, &rcDesk); + + OffsetRect (&rcDlg, -rcDlg.left, -rcDlg.top); + OffsetRect (&rc, -rc.left, -rc.top); + OffsetRect (&rc, -rcDlg.right, -rcDlg.bottom); + + SetWindowPos (hwndDlg, + HWND_TOPMOST, + rcDesk.left + (rc.right / 2), + rcDesk.top + (rc.bottom / 2), + 0, 0, + SWP_NOSIZE | SWP_FRAMECHANGED); + } + +#ifdef XWIN_MULTIWINDOW + if (g_hIconX) hIcon=g_hIconX; + else +#endif + hIcon = LoadIcon (g_hInstance, MAKEINTRESOURCE(IDI_XWIN)); + +#ifdef XWIN_MULTIWINDOW + if (g_hSmallIconX) hIconSmall=g_hSmallIconX; + else +#endif + hIconSmall = LoadImage (g_hInstance, + MAKEINTRESOURCE(IDI_XWIN), IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_SHARED); + + PostMessage (hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon); + PostMessage (hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall); +} + + +/* + * Display the Exit dialog box + */ + +void +winDisplayExitDialog (winPrivScreenPtr pScreenPriv) +{ + int i; + int liveClients = 0; + + /* Count up running clients (clients[0] is serverClient) */ + for (i = 1; i < currentMaxClients; i++) + if (clients[i] != NullClient) + liveClients++; +#if defined(XWIN_MULTIWINDOW) + /* Count down server internal clients */ + if (pScreenPriv->pScreenInfo->fMultiWindow) + liveClients -= 2; /* multiwindow window manager & XMsgProc */ +#endif +#if defined(XWIN_CLIPBOARD) + if (g_fClipboardStarted) + liveClients--; /* clipboard manager */ +#endif + + /* A user reported that this sometimes drops below zero. just eye-candy. */ + if (liveClients < 0) + liveClients = 0; + + /* Don't show the exit confirmation dialog if SilentExit & no clients, + or ForceExit, is enabled */ + if ((pref.fSilentExit && liveClients <= 0) || pref.fForceExit) + { + if (g_hDlgExit != NULL) + { + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + } + PostMessage (pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); + return; + } + + pScreenPriv->iConnectedClients = liveClients; + + /* Check if dialog already exists */ + if (g_hDlgExit != NULL) + { + /* Dialog box already exists, display it */ + ShowWindow (g_hDlgExit, SW_SHOWDEFAULT); + + /* User has lost the dialog. Show them where it is. */ + SetForegroundWindow (g_hDlgExit); + + return; + } + + /* Create dialog box */ + g_hDlgExit = CreateDialogParam (g_hInstance, + "EXIT_DIALOG", + pScreenPriv->hwndScreen, + winExitDlgProc, + (int) pScreenPriv); + + /* Show the dialog box */ + ShowWindow (g_hDlgExit, SW_SHOW); + + /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */ + SetForegroundWindow (g_hDlgExit); + + /* Set focus to the Cancel button */ + PostMessage (g_hDlgExit, WM_NEXTDLGCTL, + GetDlgItem (g_hDlgExit, IDCANCEL), TRUE); +} + +#define CONNECTED_CLIENTS_FORMAT "There %s currently %d client%s connected." + + +/* + * Exit dialog window procedure + */ + +static wBOOL CALLBACK +winExitDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam) +{ + static winPrivScreenPtr s_pScreenPriv = NULL; + + /* Branch on message type */ + switch (message) + { + case WM_INITDIALOG: + { + char *pszConnectedClients; + + /* Store pointers to private structures for future use */ + s_pScreenPriv = (winPrivScreenPtr) lParam; + + winInitDialog (hDialog); + + /* Format the connected clients string */ + pszConnectedClients = Xprintf (CONNECTED_CLIENTS_FORMAT, + (s_pScreenPriv->iConnectedClients == 1) ? "is" : "are", + s_pScreenPriv->iConnectedClients, + (s_pScreenPriv->iConnectedClients == 1) ? "" : "s"); + if (!pszConnectedClients) + return TRUE; + + + + /* Set the number of connected clients */ + SetWindowText (GetDlgItem (hDialog, IDC_CLIENTS_CONNECTED), + pszConnectedClients); + free(pszConnectedClients); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD (wParam)) + { + case IDOK: + /* Send message to call the GiveUp function */ + PostMessage (s_pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + + case IDCANCEL: + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + } + break; + + case WM_MOUSEMOVE: + case WM_NCMOUSEMOVE: + /* Show the cursor if it is hidden */ + if (g_fSoftwareCursor && !g_fCursor) + { + g_fCursor = TRUE; + ShowCursor (TRUE); + } + return TRUE; + + case WM_CLOSE: + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + } + + return FALSE; +} + + +/* + * Display the Depth Change dialog box + */ + +void +winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv) +{ + /* Check if dialog already exists */ + if (g_hDlgDepthChange != NULL) + { + /* Dialog box already exists, display it */ + ShowWindow (g_hDlgDepthChange, SW_SHOWDEFAULT); + + /* User has lost the dialog. Show them where it is. */ + SetForegroundWindow (g_hDlgDepthChange); + + return; + } + + /* + * Display a notification to the user that the visual + * will not be displayed until the Windows display depth + * is restored to the original value. + */ + g_hDlgDepthChange = CreateDialogParam (g_hInstance, + "DEPTH_CHANGE_BOX", + pScreenPriv->hwndScreen, + winChangeDepthDlgProc, + (int) pScreenPriv); + /* Show the dialog box */ + ShowWindow (g_hDlgDepthChange, SW_SHOW); + + ErrorF ("winDisplayDepthChangeDialog - DialogBox returned: %d\n", + (int) g_hDlgDepthChange); + ErrorF ("winDisplayDepthChangeDialog - GetLastError: %d\n", + (int) GetLastError ()); + + /* Minimize the display window */ + ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE); +} + + +/* + * Process messages for the dialog that is displayed for + * disruptive screen depth changes. + */ + +static wBOOL CALLBACK +winChangeDepthDlgProc (HWND hwndDialog, UINT message, + WPARAM wParam, LPARAM lParam) +{ + static winPrivScreenPtr s_pScreenPriv = NULL; + static winScreenInfo *s_pScreenInfo = NULL; + static ScreenPtr s_pScreen = NULL; + +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc\n"); +#endif + + /* Branch on message type */ + switch (message) + { + case WM_INITDIALOG: +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc - WM_INITDIALOG\n"); +#endif + + /* Store pointers to private structures for future use */ + s_pScreenPriv = (winPrivScreenPtr) lParam; + s_pScreenInfo = s_pScreenPriv->pScreenInfo; + s_pScreen = s_pScreenInfo->pScreen; + +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - s_pScreenPriv: %08x, " + "s_pScreenInfo: %08x, s_pScreen: %08x\n", + s_pScreenPriv, s_pScreenInfo, s_pScreen); +#endif + +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - orig bpp: %d, " + "last bpp: %d\n", + s_pScreenInfo->dwBPP, + s_pScreenPriv->dwLastWindowsBitsPixel); +#endif + + winInitDialog( hwndDialog ); + + return TRUE; + + case WM_DISPLAYCHANGE: +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc - WM_DISPLAYCHANGE - orig bpp: %d, " + "last bpp: %d, new bpp: %d\n", + s_pScreenInfo->dwBPP, + s_pScreenPriv->dwLastWindowsBitsPixel, + wParam); +#endif + + /* Dismiss the dialog if the display returns to the original depth */ + if (wParam == s_pScreenInfo->dwBPP) + { + ErrorF ("winChangeDelthDlgProc - wParam == s_pScreenInfo->dwBPP\n"); + + /* Depth has been restored, dismiss dialog */ + DestroyWindow (g_hDlgDepthChange); + g_hDlgDepthChange = NULL; + + /* Flag that we have a valid screen depth */ + s_pScreenPriv->fBadDepth = FALSE; + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD (wParam)) + { + case IDOK: + case IDCANCEL: + ErrorF ("winChangeDepthDlgProc - WM_COMMAND - IDOK or IDCANCEL\n"); + + /* + * User dismissed the dialog, hide it until the + * display mode is restored. + */ + ShowWindow (g_hDlgDepthChange, SW_HIDE); + return TRUE; + } + break; + + case WM_CLOSE: + ErrorF ("winChangeDepthDlgProc - WM_CLOSE\n"); + + DestroyWindow (g_hDlgAbout); + g_hDlgAbout = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + } + + return FALSE; +} + + +/* + * Display the About dialog box + */ + +void +winDisplayAboutDialog (winPrivScreenPtr pScreenPriv) +{ + /* Check if dialog already exists */ + if (g_hDlgAbout != NULL) + { + /* Dialog box already exists, display it */ + ShowWindow (g_hDlgAbout, SW_SHOWDEFAULT); + + /* User has lost the dialog. Show them where it is. */ + SetForegroundWindow (g_hDlgAbout); + + return; + } + + /* + * Display the about box + */ + g_hDlgAbout = CreateDialogParam (g_hInstance, + "ABOUT_BOX", + pScreenPriv->hwndScreen, + winAboutDlgProc, + (int) pScreenPriv); + + /* Show the dialog box */ + ShowWindow (g_hDlgAbout, SW_SHOW); + + /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */ + SetForegroundWindow (g_hDlgAbout); + + /* Set focus to the OK button */ + PostMessage (g_hDlgAbout, WM_NEXTDLGCTL, + GetDlgItem (g_hDlgAbout, IDOK), TRUE); +} + + +/* + * Process messages for the about dialog. + */ + +static wBOOL CALLBACK +winAboutDlgProc (HWND hwndDialog, UINT message, + WPARAM wParam, LPARAM lParam) +{ + static winPrivScreenPtr s_pScreenPriv = NULL; + static winScreenInfo *s_pScreenInfo = NULL; + static ScreenPtr s_pScreen = NULL; + +#if CYGDEBUG + winDebug ("winAboutDlgProc\n"); +#endif + + /* Branch on message type */ + switch (message) + { + case WM_INITDIALOG: +#if CYGDEBUG + winDebug ("winAboutDlgProc - WM_INITDIALOG\n"); +#endif + + /* Store pointers to private structures for future use */ + s_pScreenPriv = (winPrivScreenPtr) lParam; + s_pScreenInfo = s_pScreenPriv->pScreenInfo; + s_pScreen = s_pScreenInfo->pScreen; + + winInitDialog (hwndDialog); + + /* Override the URL buttons */ + winOverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); + winOverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); + winOverrideURLButton (hwndDialog, ID_ABOUT_UG); + winOverrideURLButton (hwndDialog, ID_ABOUT_FAQ); + + return TRUE; + + case WM_DRAWITEM: + /* Draw the URL buttons as needed */ + winDrawURLWindow (lParam); + return TRUE; + + case WM_MOUSEMOVE: + case WM_NCMOUSEMOVE: + /* Show the cursor if it is hidden */ + if (g_fSoftwareCursor && !g_fCursor) + { + g_fCursor = TRUE; + ShowCursor (TRUE); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD (wParam)) + { + case IDOK: + case IDCANCEL: + ErrorF ("winAboutDlgProc - WM_COMMAND - IDOK or IDCANCEL\n"); + + DestroyWindow (g_hDlgAbout); + g_hDlgAbout = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + + /* Restore window procedures for URL buttons */ + winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ); + + return TRUE; + + case ID_ABOUT_CHANGELOG: + { + HINSTANCE iReturn; +#ifdef __CYGWIN__ + const char * pszCygPath = "/usr/X11R6/share/doc/" + "xorg-x11-xwin/changelog.html"; + char pszWinPath[MAX_PATH + 1]; + + /* Convert the POSIX path to a Win32 path */ + cygwin_conv_to_win32_path (pszCygPath, pszWinPath); +#else + const char * pszWinPath = "http://x.cygwin.com/" + "devel/server/changelog.html"; +#endif + + iReturn = ShellExecute (NULL, + "open", + pszWinPath, + NULL, + NULL, + SW_MAXIMIZE); + if (iReturn < 32) + { + ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_CHANGELOG - " + "ShellExecute failed: %d\n", + iReturn); + } + } + return TRUE; + + case ID_ABOUT_WEBSITE: + { + const char * pszPath = __VENDORDWEBSUPPORT__; + int iReturn; + + iReturn = ShellExecute (NULL, + "open", + pszPath, + NULL, + NULL, + SW_MAXIMIZE); + if (iReturn < 32) + { + ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_WEBSITE - " + "ShellExecute failed: %d\n", + iReturn); + } + } + return TRUE; + + case ID_ABOUT_UG: + { + const char * pszPath = "http://x.cygwin.com/docs/ug/"; + int iReturn; + + iReturn = ShellExecute (NULL, + "open", + pszPath, + NULL, + NULL, + SW_MAXIMIZE); + if (iReturn < 32) + { + ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_UG - " + "ShellExecute failed: %d\n", + iReturn); + } + } + return TRUE; + + case ID_ABOUT_FAQ: + { + const char * pszPath = "http://x.cygwin.com/docs/faq/"; + int iReturn; + + iReturn = ShellExecute (NULL, + "open", + pszPath, + NULL, + NULL, + SW_MAXIMIZE); + if (iReturn < 32) + { + ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_FAQ - " + "ShellExecute failed: %d\n", + iReturn); + } + } + return TRUE; + } + break; + + case WM_CLOSE: + ErrorF ("winAboutDlgProc - WM_CLOSE\n"); + + DestroyWindow (g_hDlgAbout); + g_hDlgAbout = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + + /* Restore window procedures for URL buttons */ + winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ); + + return TRUE; + } + + return FALSE; +} diff --git a/xorg-server/hw/xwin/winerror.c b/xorg-server/hw/xwin/winerror.c index 191b9a921..253aea7a8 100644 --- a/xorg-server/hw/xwin/winerror.c +++ b/xorg-server/hw/xwin/winerror.c @@ -1,152 +1,152 @@ -/* - *Copyright (C) 2001-2004 Harold L Hunt II 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 HAROLD L HUNT II 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 Harold L Hunt II - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from Harold L Hunt II. - * - * Authors: Harold L Hunt II - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include <xwin-config.h> -#endif -#ifdef XVENDORNAME -#define VENDOR_STRING XVENDORNAME -#define VENDOR_CONTACT BUILDERADDR -#endif - -#include <../xfree86/common/xorgVersion.h> -#include "win.h" - -/* References to external symbols */ -extern char * g_pszCommandLine; -extern const char * g_pszLogFile; -extern Bool g_fSilentFatalError; -extern Bool g_fLogInited; - - -#ifdef DDXOSVERRORF -/* Prototype */ -void -OsVendorVErrorF (const char *pszFormat, va_list va_args); - -void -OsVendorVErrorF (const char *pszFormat, va_list va_args) -{ -#if defined(XWIN_CLIPBOARD) || defined (XWIN_MULTIWINDOW) - /* make sure the clipboard and multiwindow threads do not interfere the - * main thread */ - static pthread_mutex_t s_pmPrinting = PTHREAD_MUTEX_INITIALIZER; - - /* Lock the printing mutex */ - pthread_mutex_lock (&s_pmPrinting); -#endif - - /* Print the error message to a log file, could be stderr */ - LogVWrite (0, pszFormat, va_args); - -#if defined(XWIN_CLIPBOARD) || defined (XWIN_MULTIWINDOW) - /* Unlock the printing mutex */ - pthread_mutex_unlock (&s_pmPrinting); -#endif -} -#endif - - -/* - * os/util.c/FatalError () calls our vendor ErrorF, so the message - * from a FatalError will be logged. Thus, the message for the - * fatal error is not passed to this function. - * - * Attempt to do last-ditch, safe, important cleanup here. - */ -void -OsVendorFatalError (void) -{ - /* Don't give duplicate warning if UseMsg was called */ - if (g_fSilentFatalError) - return; - - if (!g_fLogInited) { - g_fLogInited = TRUE; - g_pszLogFile = LogInit (g_pszLogFile, NULL); - } - LogClose (); - - winMessageBoxF ( - "A fatal error has occurred and " PROJECT_NAME " will now exit.\n" \ - "Please open %s for more information.\n", - MB_ICONERROR, (g_pszLogFile?g_pszLogFile:"the logfile")); -} - - -/* - * winMessageBoxF - Print a formatted error message in a useful - * message box. - */ - -void -winMessageBoxF (const char *pszError, UINT uType, ...) -{ - char * pszErrorF = NULL; - char * pszMsgBox = NULL; - va_list args; - - va_start(args, uType); - pszErrorF = Xvprintf(pszError, args); - va_end(args); - if (!pszErrorF) - goto winMessageBoxF_Cleanup; - -#define MESSAGEBOXF \ - "%s\n" \ - "Vendor: %s\n" \ - "Release: %d.%d.%d.%d (%d)\n" \ - "Contact: %s\n" \ - "%s\n\n" \ - "XWin was started with the following command-line:\n\n" \ - "%s\n" - - pszMsgBox = Xprintf (MESSAGEBOXF, - pszErrorF, VENDOR_STRING, - XORG_VERSION_MAJOR, XORG_VERSION_MINOR, XORG_VERSION_PATCH, XORG_VERSION_SNAP, XORG_VERSION_CURRENT, - VENDOR_CONTACT, - BUILDERSTRING, - g_pszCommandLine); - if (!pszMsgBox) - goto winMessageBoxF_Cleanup; - - /* Display the message box string */ - MessageBox (NULL, - pszMsgBox, - PROJECT_NAME, - MB_OK | uType); - - winMessageBoxF_Cleanup: - if (pszErrorF) - xfree (pszErrorF); - if (pszMsgBox) - xfree (pszMsgBox); -#undef MESSAGEBOXF -} +/* + *Copyright (C) 2001-2004 Harold L Hunt II 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 HAROLD L HUNT II 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 Harold L Hunt II + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from Harold L Hunt II. + * + * Authors: Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif +#ifdef XVENDORNAME +#define VENDOR_STRING XVENDORNAME +#define VENDOR_CONTACT BUILDERADDR +#endif + +#include <../xfree86/common/xorgVersion.h> +#include "win.h" + +/* References to external symbols */ +extern char * g_pszCommandLine; +extern const char * g_pszLogFile; +extern Bool g_fSilentFatalError; +extern Bool g_fLogInited; + + +#ifdef DDXOSVERRORF +/* Prototype */ +void +OsVendorVErrorF (const char *pszFormat, va_list va_args); + +void +OsVendorVErrorF (const char *pszFormat, va_list va_args) +{ +#if defined(XWIN_CLIPBOARD) || defined (XWIN_MULTIWINDOW) + /* make sure the clipboard and multiwindow threads do not interfere the + * main thread */ + static pthread_mutex_t s_pmPrinting = PTHREAD_MUTEX_INITIALIZER; + + /* Lock the printing mutex */ + pthread_mutex_lock (&s_pmPrinting); +#endif + + /* Print the error message to a log file, could be stderr */ + LogVWrite (0, pszFormat, va_args); + +#if defined(XWIN_CLIPBOARD) || defined (XWIN_MULTIWINDOW) + /* Unlock the printing mutex */ + pthread_mutex_unlock (&s_pmPrinting); +#endif +} +#endif + + +/* + * os/util.c/FatalError () calls our vendor ErrorF, so the message + * from a FatalError will be logged. Thus, the message for the + * fatal error is not passed to this function. + * + * Attempt to do last-ditch, safe, important cleanup here. + */ +void +OsVendorFatalError (void) +{ + /* Don't give duplicate warning if UseMsg was called */ + if (g_fSilentFatalError) + return; + + if (!g_fLogInited) { + g_fLogInited = TRUE; + g_pszLogFile = LogInit (g_pszLogFile, NULL); + } + LogClose (); + + winMessageBoxF ( + "A fatal error has occurred and " PROJECT_NAME " will now exit.\n" \ + "Please open %s for more information.\n", + MB_ICONERROR, (g_pszLogFile?g_pszLogFile:"the logfile")); +} + + +/* + * winMessageBoxF - Print a formatted error message in a useful + * message box. + */ + +void +winMessageBoxF (const char *pszError, UINT uType, ...) +{ + char * pszErrorF = NULL; + char * pszMsgBox = NULL; + va_list args; + + va_start(args, uType); + pszErrorF = Xvprintf(pszError, args); + va_end(args); + if (!pszErrorF) + goto winMessageBoxF_Cleanup; + +#define MESSAGEBOXF \ + "%s\n" \ + "Vendor: %s\n" \ + "Release: %d.%d.%d.%d (%d)\n" \ + "Contact: %s\n" \ + "%s\n\n" \ + "XWin was started with the following command-line:\n\n" \ + "%s\n" + + pszMsgBox = Xprintf (MESSAGEBOXF, + pszErrorF, VENDOR_STRING, + XORG_VERSION_MAJOR, XORG_VERSION_MINOR, XORG_VERSION_PATCH, XORG_VERSION_SNAP, XORG_VERSION_CURRENT, + VENDOR_CONTACT, + BUILDERSTRING, + g_pszCommandLine); + if (!pszMsgBox) + goto winMessageBoxF_Cleanup; + + /* Display the message box string */ + MessageBox (NULL, + pszMsgBox, + PROJECT_NAME, + MB_OK | uType); + + winMessageBoxF_Cleanup: + if (pszErrorF) + free(pszErrorF); + if (pszMsgBox) + free(pszMsgBox); +#undef MESSAGEBOXF +} diff --git a/xorg-server/hw/xwin/winvideo.c b/xorg-server/hw/xwin/winvideo.c index 529ca76d3..42f46f405 100644 --- a/xorg-server/hw/xwin/winvideo.c +++ b/xorg-server/hw/xwin/winvideo.c @@ -1,210 +1,210 @@ -/* - *Copyright (C) 2003-2004 Harold L Hunt II 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 HAROLD L HUNT II 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 Harold L Hunt II - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from Harold L Hunt II. - * - * Authors: Harold L Hunt II - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include <xwin-config.h> -#endif -#include "win.h" -#include <X11/extensions/Xv.h> -#include <X11/extensions/Xvproto.h> - -void -winInitVideo (ScreenPtr pScreen); - -/* - * winInitVideo - Initialize support for the X Video (Xv) Extension. - */ - -void -winInitVideo (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - if (pScreenInfo->dwBPP > 8) - { - - } - - -} - - - - - - - -#if 0 -#include "../xfree86/common/xf86.h" -#include "../Xext/xvdix.h" -#include "../xfree86/common/xf86xv.h" -#include <X11/extensions/Xv.h> -#endif - -#include "win.h" - - - -#if 0 -/* client libraries expect an encoding */ -static XF86VideoEncodingRec DummyEncoding[1] = -{ - { - 0, - "XV_IMAGE", - IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, - {1, 1} - } -}; - -#define NUM_FORMATS 3 - -static XF86VideoFormatRec Formats[NUM_FORMATS] = -{ - {15, TrueColor}, {16, TrueColor}, {24, TrueColor} -}; - -#define NUM_ATTRIBUTES 3 - -static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = -{ - {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, - {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, - {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"} -}; - -#define NUM_IMAGES 4 - -static XF86ImageRec Images[NUM_IMAGES] = -{ - XVIMAGE_YUY2, - XVIMAGE_YV12, - XVIMAGE_I420, - XVIMAGE_UYVY -}; - - - -/* - * winInitVideo - Initialize support for the X Video (Xv) Extension. - */ - -void -winInitVideo (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - XF86VideoAdaptorPtr newAdaptor = NULL; - - if (pScreenInfo->dwBPP > 8) - { - newAdaptor = I810SetupImageVideo (pScreen); - I810InitOffscreenImages (pScreen); - } - - xf86XVScreenInit (pScreen, adaptors, 1); -} - - -static XF86VideoAdaptorPtr -winSetupImageVideo (ScreenPtr pScreen) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; -#if 0 - I810Ptr pI810 = I810PTR(pScrn); -#endif - XF86VideoAdaptorPtr adapt; - - if (!(adapt = xcalloc (1, sizeof(XF86VideoAdaptorRec)))) - return NULL; - - adapt->type = XvWindowMask | XvInputMask | XvImageMask; - adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; - adapt->name = PROJECT_NAME " Video Overlay"; - adapt->nEncodings = 1; - adapt->pEncodings = DummyEncoding; - adapt->nFormats = NUM_FORMATS; - adapt->pFormats = Formats; - adapt->nPorts = 1; - adapt->pPortPrivates = NULL; - - adapt->pPortPrivates[0].ptr = NULL; - adapt->pAttributes = Attributes; - adapt->nImages = NUM_IMAGES; - adapt->nAttributes = NUM_ATTRIBUTES; - adapt->pImages = Images; - adapt->PutVideo = NULL; - adapt->PutStill = NULL; - adapt->GetVideo = NULL; - adapt->GetStill = NULL; -#if 0 - adapt->StopVideo = I810StopVideo; - adapt->SetPortAttribute = I810SetPortAttribute; - adapt->GetPortAttribute = I810GetPortAttribute; - adapt->QueryBestSize = I810QueryBestSize; - adapt->PutImage = I810PutImage; - adapt->QueryImageAttributes = I810QueryImageAttributes; -#endif - -#if 0 - pPriv->colorKey = pI810->colorKey & ((1 << pScrn->depth) - 1); -#endif - pPriv->videoStatus = 0; - pPriv->brightness = 0; - pPriv->contrast = 64; - pPriv->linear = NULL; - pPriv->currentBuf = 0; - -#if 0 - /* gotta uninit this someplace */ - REGION_NULL(pScreen, &pPriv->clip); -#endif - -#if 0 - pI810->adaptor = adapt; - - pI810->BlockHandler = pScreen->BlockHandler; - pScreen->BlockHandler = I810BlockHandler; -#endif - -#if 0 - xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); - xvContrast = MAKE_ATOM("XV_CONTRAST"); - xvColorKey = MAKE_ATOM("XV_COLORKEY"); -#endif - -#if 0 - I810ResetVideo(pScrn); -#endif - - return adapt; -} -#endif +/* + *Copyright (C) 2003-2004 Harold L Hunt II 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 HAROLD L HUNT II 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 Harold L Hunt II + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from Harold L Hunt II. + * + * Authors: Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif +#include "win.h" +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvproto.h> + +void +winInitVideo (ScreenPtr pScreen); + +/* + * winInitVideo - Initialize support for the X Video (Xv) Extension. + */ + +void +winInitVideo (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + if (pScreenInfo->dwBPP > 8) + { + + } + + +} + + + + + + + +#if 0 +#include "../xfree86/common/xf86.h" +#include "../Xext/xvdix.h" +#include "../xfree86/common/xf86xv.h" +#include <X11/extensions/Xv.h> +#endif + +#include "win.h" + + + +#if 0 +/* client libraries expect an encoding */ +static XF86VideoEncodingRec DummyEncoding[1] = +{ + { + 0, + "XV_IMAGE", + IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, + {1, 1} + } +}; + +#define NUM_FORMATS 3 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = +{ + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +#define NUM_ATTRIBUTES 3 + +static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = +{ + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"} +}; + +#define NUM_IMAGES 4 + +static XF86ImageRec Images[NUM_IMAGES] = +{ + XVIMAGE_YUY2, + XVIMAGE_YV12, + XVIMAGE_I420, + XVIMAGE_UYVY +}; + + + +/* + * winInitVideo - Initialize support for the X Video (Xv) Extension. + */ + +void +winInitVideo (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + XF86VideoAdaptorPtr newAdaptor = NULL; + + if (pScreenInfo->dwBPP > 8) + { + newAdaptor = I810SetupImageVideo (pScreen); + I810InitOffscreenImages (pScreen); + } + + xf86XVScreenInit (pScreen, adaptors, 1); +} + + +static XF86VideoAdaptorPtr +winSetupImageVideo (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; +#if 0 + I810Ptr pI810 = I810PTR(pScrn); +#endif + XF86VideoAdaptorPtr adapt; + + if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec)))) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = PROJECT_NAME " Video Overlay"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = 1; + adapt->pPortPrivates = NULL; + + adapt->pPortPrivates[0].ptr = NULL; + adapt->pAttributes = Attributes; + adapt->nImages = NUM_IMAGES; + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; +#if 0 + adapt->StopVideo = I810StopVideo; + adapt->SetPortAttribute = I810SetPortAttribute; + adapt->GetPortAttribute = I810GetPortAttribute; + adapt->QueryBestSize = I810QueryBestSize; + adapt->PutImage = I810PutImage; + adapt->QueryImageAttributes = I810QueryImageAttributes; +#endif + +#if 0 + pPriv->colorKey = pI810->colorKey & ((1 << pScrn->depth) - 1); +#endif + pPriv->videoStatus = 0; + pPriv->brightness = 0; + pPriv->contrast = 64; + pPriv->linear = NULL; + pPriv->currentBuf = 0; + +#if 0 + /* gotta uninit this someplace */ + REGION_NULL(pScreen, &pPriv->clip); +#endif + +#if 0 + pI810->adaptor = adapt; + + pI810->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = I810BlockHandler; +#endif + +#if 0 + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvColorKey = MAKE_ATOM("XV_COLORKEY"); +#endif + +#if 0 + I810ResetVideo(pScrn); +#endif + + return adapt; +} +#endif diff --git a/xorg-server/hw/xwin/winwindow.c b/xorg-server/hw/xwin/winwindow.c index 0e75a2c6a..6f35707e7 100644 --- a/xorg-server/hw/xwin/winwindow.c +++ b/xorg-server/hw/xwin/winwindow.c @@ -1,637 +1,637 @@ -/* - *Copyright (C) 1994-2000 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. - * - * Authors: Harold L Hunt II - * Kensuke Matsuzaki - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include <xwin-config.h> -#endif -#include "win.h" - - -/* - * Prototypes for local functions - */ - -static int -winAddRgn (WindowPtr pWindow, pointer data); - -static -void -winUpdateRgnRootless (WindowPtr pWindow); - -static -void -winReshapeRootless (WindowPtr pWin); - - -#ifdef XWIN_NATIVEGDI -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbCreateWindow() */ - -Bool -winCreateWindowNativeGDI (WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winCreateWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(CreateWindow); - fResult = (*pScreen->CreateWindow) (pWin); - WIN_WRAP(CreateWindow, winCreateWindowNativeGDI); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbDestroyWindow() */ - -Bool -winDestroyWindowNativeGDI (WindowPtr pWin) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winDestroyWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(DestroyWindow); - fResult = (*pScreen->DestroyWindow)(pWin); - WIN_WRAP(DestroyWindow, winDestroyWindowNativeGDI); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbPositionWindow() */ - -Bool -winPositionWindowNativeGDI (WindowPtr pWin, int x, int y) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winPositionWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(PositionWindow); - fResult = (*pScreen->PositionWindow)(pWin, x, y); - WIN_WRAP(PositionWindow, winPositionWindowNativeGDI); - - return fResult; -} - - -/* See Porting Layer Definition - p. 39 */ -/* See mfb/mfbwindow.c - mfbCopyWindow() */ - -void -winCopyWindowNativeGDI (WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc) -{ - DDXPointPtr pptSrc; - DDXPointPtr ppt; - RegionPtr prgnDst; - BoxPtr pBox; - int dx, dy; - int i, nbox; - WindowPtr pwinRoot; - BoxPtr pBoxDst; - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - -#if 0 - ErrorF ("winCopyWindow\n"); -#endif - - /* Get a pointer to the root window */ - pwinRoot = WindowTable[pWin->drawable.pScreen->myNum]; - - /* Create a region for the destination */ - prgnDst = REGION_CREATE(pWin->drawable.pScreen, NULL, 1); - - /* Calculate the shift from the source to the destination */ - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - - /* Translate the region from the destination to the source? */ - REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); - REGION_INTERSECT(pWin->drawable.pScreen, prgnDst, &pWin->borderClip, - prgnSrc); - - /* Get a pointer to the first box in the region to be copied */ - pBox = REGION_RECTS(prgnDst); - - /* Get the number of boxes in the region */ - nbox = REGION_NUM_RECTS(prgnDst); - - /* Allocate source points for each box */ - if(!(pptSrc = (DDXPointPtr )xalloc(nbox * sizeof(DDXPointRec)))) - return; - - /* Set an iterator pointer */ - ppt = pptSrc; - - /* Calculate the source point of each box? */ - for (i = nbox; --i >= 0; ppt++, pBox++) - { - ppt->x = pBox->x1 + dx; - ppt->y = pBox->y1 + dy; - } - - /* Setup loop pointers again */ - pBoxDst = REGION_RECTS(prgnDst); - ppt = pptSrc; - -#if 0 - ErrorF ("winCopyWindow - x1\tx2\ty1\ty2\tx\ty\n"); -#endif - - /* BitBlt each source to the destination point */ - for (i = nbox; --i >= 0; pBoxDst++, ppt++) - { -#if 0 - ErrorF ("winCopyWindow - %d\t%d\t%d\t%d\t%d\t%d\n", - pBoxDst->x1, pBoxDst->x2, pBoxDst->y1, pBoxDst->y2, - ppt->x, ppt->y); -#endif - - BitBlt (pScreenPriv->hdcScreen, - pBoxDst->x1, pBoxDst->y1, - pBoxDst->x2 - pBoxDst->x1, pBoxDst->y2 - pBoxDst->y1, - pScreenPriv->hdcScreen, - ppt->x, ppt->y, - SRCCOPY); - } - - /* Cleanup the regions, etc. */ - xfree(pptSrc); - REGION_DESTROY(pWin->drawable.pScreen, prgnDst); -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbChangeWindowAttributes() */ - -Bool -winChangeWindowAttributesNativeGDI (WindowPtr pWin, unsigned long mask) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winChangeWindowAttributesNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(ChangeWindowAttributes); - fResult = (*pScreen->ChangeWindowAttributes)(pWin, mask); - WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesNativeGDI); - - /* - * NOTE: We do not currently need to do anything here. - */ - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 - * Also referred to as UnrealizeWindow - */ - -Bool -winUnmapWindowNativeGDI (WindowPtr pWin) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winUnmapWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(UnrealizeWindow); - fResult = (*pScreen->UnrealizeWindow)(pWin); - WIN_WRAP(UnrealizeWindow, winUnmapWindowNativeGDI); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 - * Also referred to as RealizeWindow - */ - -Bool -winMapWindowNativeGDI (WindowPtr pWin) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winMapWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(RealizeWindow); - fResult = (*pScreen->RealizeWindow)(pWin); - WIN_WRAP(RealizeWindow, winMapWindowMultiWindow); - - return fResult; - -} -#endif - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbCreateWindow() */ - -Bool -winCreateWindowRootless (WindowPtr pWin) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winCreateWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(CreateWindow); - fResult = (*pScreen->CreateWindow) (pWin); - WIN_WRAP(CreateWindow, winCreateWindowRootless); - - pWinPriv->hRgn = NULL; - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbDestroyWindow() */ - -Bool -winDestroyWindowRootless (WindowPtr pWin) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winDestroyWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(DestroyWindow); - fResult = (*pScreen->DestroyWindow)(pWin); - WIN_WRAP(DestroyWindow, winDestroyWindowRootless); - - if (pWinPriv->hRgn != NULL) - { - DeleteObject(pWinPriv->hRgn); - pWinPriv->hRgn = NULL; - } - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbPositionWindow() */ - -Bool -winPositionWindowRootless (WindowPtr pWin, int x, int y) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - - -#if CYGDEBUG - winTrace ("winPositionWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(PositionWindow); - fResult = (*pScreen->PositionWindow)(pWin, x, y); - WIN_WRAP(PositionWindow, winPositionWindowRootless); - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbChangeWindowAttributes() */ - -Bool -winChangeWindowAttributesRootless (WindowPtr pWin, unsigned long mask) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winChangeWindowAttributesRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(ChangeWindowAttributes); - fResult = (*pScreen->ChangeWindowAttributes)(pWin, mask); - WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesRootless); - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 - * Also referred to as UnrealizeWindow - */ - -Bool -winUnmapWindowRootless (WindowPtr pWin) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winUnmapWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(UnrealizeWindow); - fResult = (*pScreen->UnrealizeWindow)(pWin); - WIN_WRAP(UnrealizeWindow, winUnmapWindowRootless); - - if (pWinPriv->hRgn != NULL) - { - DeleteObject(pWinPriv->hRgn); - pWinPriv->hRgn = NULL; - } - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 - * Also referred to as RealizeWindow - */ - -Bool -winMapWindowRootless (WindowPtr pWin) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winMapWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(RealizeWindow); - fResult = (*pScreen->RealizeWindow)(pWin); - WIN_WRAP(RealizeWindow, winMapWindowRootless); - - winReshapeRootless (pWin); - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -void -winSetShapeRootless (WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winSetShapeRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(SetShape); - (*pScreen->SetShape)(pWin); - WIN_WRAP(SetShape, winSetShapeRootless); - - winReshapeRootless (pWin); - winUpdateRgnRootless (pWin); - - return; -} - - -/* - * Local function for adding a region to the Windows window region - */ - -static -int -winAddRgn (WindowPtr pWin, pointer data) -{ - int iX, iY, iWidth, iHeight, iBorder; - HRGN hRgn = *(HRGN*)data; - HRGN hRgnWin; - winWindowPriv(pWin); - - /* If pWin is not Root */ - if (pWin->parent != NULL) - { -#if CYGDEBUG - winDebug ("winAddRgn ()\n"); -#endif - if (pWin->mapped) - { - iBorder = wBorderWidth (pWin); - - iX = pWin->drawable.x - iBorder; - iY = pWin->drawable.y - iBorder; - - iWidth = pWin->drawable.width + iBorder * 2; - iHeight = pWin->drawable.height + iBorder * 2; - - hRgnWin = CreateRectRgn (0, 0, iWidth, iHeight); - - if (hRgnWin == NULL) - { - ErrorF ("winAddRgn - CreateRectRgn () failed\n"); - ErrorF (" Rect %d %d %d %d\n", - iX, iY, iX + iWidth, iY + iHeight); - } - - if (pWinPriv->hRgn) - { - if (CombineRgn (hRgnWin, hRgnWin, pWinPriv->hRgn, RGN_AND) - == ERROR) - { - ErrorF ("winAddRgn - CombineRgn () failed\n"); - } - } - - OffsetRgn (hRgnWin, iX, iY); - - if (CombineRgn (hRgn, hRgn, hRgnWin, RGN_OR) == ERROR) - { - ErrorF ("winAddRgn - CombineRgn () failed\n"); - } - - DeleteObject (hRgnWin); - } - return WT_DONTWALKCHILDREN; - } - else - { - return WT_WALKCHILDREN; - } -} - - -/* - * Local function to update the Windows window's region - */ - -static -void -winUpdateRgnRootless (WindowPtr pWin) -{ - HRGN hRgn = CreateRectRgn (0, 0, 0, 0); - - if (hRgn != NULL) - { - WalkTree (pWin->drawable.pScreen, winAddRgn, &hRgn); - SetWindowRgn (winGetScreenPriv(pWin->drawable.pScreen)->hwndScreen, - hRgn, TRUE); - } - else - { - ErrorF ("winUpdateRgnRootless - CreateRectRgn failed.\n"); - } -} - - -static -void -winReshapeRootless (WindowPtr pWin) -{ - int nRects; - /* ScreenPtr pScreen = pWin->drawable.pScreen;*/ - RegionRec rrNewShape; - BoxPtr pShape, pRects, pEnd; - HRGN hRgn, hRgnRect; - winWindowPriv(pWin); - -#if CYGDEBUG - winDebug ("winReshapeRootless ()\n"); -#endif - - /* Bail if the window is the root window */ - if (pWin->parent == NULL) - return; - - /* Bail if the window is not top level */ - if (pWin->parent->parent != NULL) - return; - - /* Free any existing window region stored in the window privates */ - if (pWinPriv->hRgn != NULL) - { - DeleteObject (pWinPriv->hRgn); - pWinPriv->hRgn = NULL; - } - - /* Bail if the window has no bounding region defined */ - if (!wBoundingShape (pWin)) - return; - - REGION_NULL(pScreen, &rrNewShape); - REGION_COPY(pScreen, &rrNewShape, wBoundingShape(pWin)); - REGION_TRANSLATE(pScreen, &rrNewShape, pWin->borderWidth, - pWin->borderWidth); - - nRects = REGION_NUM_RECTS(&rrNewShape); - pShape = REGION_RECTS(&rrNewShape); - - if (nRects > 0) - { - /* Create initial empty Windows region */ - hRgn = CreateRectRgn (0, 0, 0, 0); - - /* Loop through all rectangles in the X region */ - for (pRects = pShape, pEnd = pShape + nRects; pRects < pEnd; pRects++) - { - /* Create a Windows region for the X rectangle */ - hRgnRect = CreateRectRgn (pRects->x1, pRects->y1, - pRects->x2, pRects->y2); - if (hRgnRect == NULL) - { - ErrorF("winReshapeRootless - CreateRectRgn() failed\n"); - } - - /* Merge the Windows region with the accumulated region */ - if (CombineRgn (hRgn, hRgn, hRgnRect, RGN_OR) == ERROR) - { - ErrorF("winReshapeRootless - CombineRgn() failed\n"); - } - - /* Delete the temporary Windows region */ - DeleteObject (hRgnRect); - } - - /* Save a handle to the composite region in the window privates */ - pWinPriv->hRgn = hRgn; - } - - REGION_UNINIT(pScreen, &rrNewShape); - - return; -} +/* + *Copyright (C) 1994-2000 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. + * + * Authors: Harold L Hunt II + * Kensuke Matsuzaki + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif +#include "win.h" + + +/* + * Prototypes for local functions + */ + +static int +winAddRgn (WindowPtr pWindow, pointer data); + +static +void +winUpdateRgnRootless (WindowPtr pWindow); + +static +void +winReshapeRootless (WindowPtr pWin); + + +#ifdef XWIN_NATIVEGDI +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbCreateWindow() */ + +Bool +winCreateWindowNativeGDI (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winCreateWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(CreateWindow); + fResult = (*pScreen->CreateWindow) (pWin); + WIN_WRAP(CreateWindow, winCreateWindowNativeGDI); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbDestroyWindow() */ + +Bool +winDestroyWindowNativeGDI (WindowPtr pWin) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winDestroyWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(DestroyWindow); + fResult = (*pScreen->DestroyWindow)(pWin); + WIN_WRAP(DestroyWindow, winDestroyWindowNativeGDI); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbPositionWindow() */ + +Bool +winPositionWindowNativeGDI (WindowPtr pWin, int x, int y) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winPositionWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(PositionWindow); + fResult = (*pScreen->PositionWindow)(pWin, x, y); + WIN_WRAP(PositionWindow, winPositionWindowNativeGDI); + + return fResult; +} + + +/* See Porting Layer Definition - p. 39 */ +/* See mfb/mfbwindow.c - mfbCopyWindow() */ + +void +winCopyWindowNativeGDI (WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + DDXPointPtr pptSrc; + DDXPointPtr ppt; + RegionPtr prgnDst; + BoxPtr pBox; + int dx, dy; + int i, nbox; + WindowPtr pwinRoot; + BoxPtr pBoxDst; + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + +#if 0 + ErrorF ("winCopyWindow\n"); +#endif + + /* Get a pointer to the root window */ + pwinRoot = WindowTable[pWin->drawable.pScreen->myNum]; + + /* Create a region for the destination */ + prgnDst = REGION_CREATE(pWin->drawable.pScreen, NULL, 1); + + /* Calculate the shift from the source to the destination */ + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + + /* Translate the region from the destination to the source? */ + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); + REGION_INTERSECT(pWin->drawable.pScreen, prgnDst, &pWin->borderClip, + prgnSrc); + + /* Get a pointer to the first box in the region to be copied */ + pBox = REGION_RECTS(prgnDst); + + /* Get the number of boxes in the region */ + nbox = REGION_NUM_RECTS(prgnDst); + + /* Allocate source points for each box */ + if(!(pptSrc = (DDXPointPtr )malloc(nbox * sizeof(DDXPointRec)))) + return; + + /* Set an iterator pointer */ + ppt = pptSrc; + + /* Calculate the source point of each box? */ + for (i = nbox; --i >= 0; ppt++, pBox++) + { + ppt->x = pBox->x1 + dx; + ppt->y = pBox->y1 + dy; + } + + /* Setup loop pointers again */ + pBoxDst = REGION_RECTS(prgnDst); + ppt = pptSrc; + +#if 0 + ErrorF ("winCopyWindow - x1\tx2\ty1\ty2\tx\ty\n"); +#endif + + /* BitBlt each source to the destination point */ + for (i = nbox; --i >= 0; pBoxDst++, ppt++) + { +#if 0 + ErrorF ("winCopyWindow - %d\t%d\t%d\t%d\t%d\t%d\n", + pBoxDst->x1, pBoxDst->x2, pBoxDst->y1, pBoxDst->y2, + ppt->x, ppt->y); +#endif + + BitBlt (pScreenPriv->hdcScreen, + pBoxDst->x1, pBoxDst->y1, + pBoxDst->x2 - pBoxDst->x1, pBoxDst->y2 - pBoxDst->y1, + pScreenPriv->hdcScreen, + ppt->x, ppt->y, + SRCCOPY); + } + + /* Cleanup the regions, etc. */ + free(pptSrc); + REGION_DESTROY(pWin->drawable.pScreen, prgnDst); +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbChangeWindowAttributes() */ + +Bool +winChangeWindowAttributesNativeGDI (WindowPtr pWin, unsigned long mask) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winChangeWindowAttributesNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(ChangeWindowAttributes); + fResult = (*pScreen->ChangeWindowAttributes)(pWin, mask); + WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesNativeGDI); + + /* + * NOTE: We do not currently need to do anything here. + */ + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 + * Also referred to as UnrealizeWindow + */ + +Bool +winUnmapWindowNativeGDI (WindowPtr pWin) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winUnmapWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(UnrealizeWindow); + fResult = (*pScreen->UnrealizeWindow)(pWin); + WIN_WRAP(UnrealizeWindow, winUnmapWindowNativeGDI); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 + * Also referred to as RealizeWindow + */ + +Bool +winMapWindowNativeGDI (WindowPtr pWin) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winMapWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(RealizeWindow); + fResult = (*pScreen->RealizeWindow)(pWin); + WIN_WRAP(RealizeWindow, winMapWindowMultiWindow); + + return fResult; + +} +#endif + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbCreateWindow() */ + +Bool +winCreateWindowRootless (WindowPtr pWin) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winCreateWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(CreateWindow); + fResult = (*pScreen->CreateWindow) (pWin); + WIN_WRAP(CreateWindow, winCreateWindowRootless); + + pWinPriv->hRgn = NULL; + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbDestroyWindow() */ + +Bool +winDestroyWindowRootless (WindowPtr pWin) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winDestroyWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(DestroyWindow); + fResult = (*pScreen->DestroyWindow)(pWin); + WIN_WRAP(DestroyWindow, winDestroyWindowRootless); + + if (pWinPriv->hRgn != NULL) + { + DeleteObject(pWinPriv->hRgn); + pWinPriv->hRgn = NULL; + } + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbPositionWindow() */ + +Bool +winPositionWindowRootless (WindowPtr pWin, int x, int y) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + + +#if CYGDEBUG + winTrace ("winPositionWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(PositionWindow); + fResult = (*pScreen->PositionWindow)(pWin, x, y); + WIN_WRAP(PositionWindow, winPositionWindowRootless); + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbChangeWindowAttributes() */ + +Bool +winChangeWindowAttributesRootless (WindowPtr pWin, unsigned long mask) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winChangeWindowAttributesRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(ChangeWindowAttributes); + fResult = (*pScreen->ChangeWindowAttributes)(pWin, mask); + WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesRootless); + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 + * Also referred to as UnrealizeWindow + */ + +Bool +winUnmapWindowRootless (WindowPtr pWin) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winUnmapWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(UnrealizeWindow); + fResult = (*pScreen->UnrealizeWindow)(pWin); + WIN_WRAP(UnrealizeWindow, winUnmapWindowRootless); + + if (pWinPriv->hRgn != NULL) + { + DeleteObject(pWinPriv->hRgn); + pWinPriv->hRgn = NULL; + } + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 + * Also referred to as RealizeWindow + */ + +Bool +winMapWindowRootless (WindowPtr pWin) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winMapWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(RealizeWindow); + fResult = (*pScreen->RealizeWindow)(pWin); + WIN_WRAP(RealizeWindow, winMapWindowRootless); + + winReshapeRootless (pWin); + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +void +winSetShapeRootless (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winSetShapeRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(SetShape); + (*pScreen->SetShape)(pWin); + WIN_WRAP(SetShape, winSetShapeRootless); + + winReshapeRootless (pWin); + winUpdateRgnRootless (pWin); + + return; +} + + +/* + * Local function for adding a region to the Windows window region + */ + +static +int +winAddRgn (WindowPtr pWin, pointer data) +{ + int iX, iY, iWidth, iHeight, iBorder; + HRGN hRgn = *(HRGN*)data; + HRGN hRgnWin; + winWindowPriv(pWin); + + /* If pWin is not Root */ + if (pWin->parent != NULL) + { +#if CYGDEBUG + winDebug ("winAddRgn ()\n"); +#endif + if (pWin->mapped) + { + iBorder = wBorderWidth (pWin); + + iX = pWin->drawable.x - iBorder; + iY = pWin->drawable.y - iBorder; + + iWidth = pWin->drawable.width + iBorder * 2; + iHeight = pWin->drawable.height + iBorder * 2; + + hRgnWin = CreateRectRgn (0, 0, iWidth, iHeight); + + if (hRgnWin == NULL) + { + ErrorF ("winAddRgn - CreateRectRgn () failed\n"); + ErrorF (" Rect %d %d %d %d\n", + iX, iY, iX + iWidth, iY + iHeight); + } + + if (pWinPriv->hRgn) + { + if (CombineRgn (hRgnWin, hRgnWin, pWinPriv->hRgn, RGN_AND) + == ERROR) + { + ErrorF ("winAddRgn - CombineRgn () failed\n"); + } + } + + OffsetRgn (hRgnWin, iX, iY); + + if (CombineRgn (hRgn, hRgn, hRgnWin, RGN_OR) == ERROR) + { + ErrorF ("winAddRgn - CombineRgn () failed\n"); + } + + DeleteObject (hRgnWin); + } + return WT_DONTWALKCHILDREN; + } + else + { + return WT_WALKCHILDREN; + } +} + + +/* + * Local function to update the Windows window's region + */ + +static +void +winUpdateRgnRootless (WindowPtr pWin) +{ + HRGN hRgn = CreateRectRgn (0, 0, 0, 0); + + if (hRgn != NULL) + { + WalkTree (pWin->drawable.pScreen, winAddRgn, &hRgn); + SetWindowRgn (winGetScreenPriv(pWin->drawable.pScreen)->hwndScreen, + hRgn, TRUE); + } + else + { + ErrorF ("winUpdateRgnRootless - CreateRectRgn failed.\n"); + } +} + + +static +void +winReshapeRootless (WindowPtr pWin) +{ + int nRects; + /* ScreenPtr pScreen = pWin->drawable.pScreen;*/ + RegionRec rrNewShape; + BoxPtr pShape, pRects, pEnd; + HRGN hRgn, hRgnRect; + winWindowPriv(pWin); + +#if CYGDEBUG + winDebug ("winReshapeRootless ()\n"); +#endif + + /* Bail if the window is the root window */ + if (pWin->parent == NULL) + return; + + /* Bail if the window is not top level */ + if (pWin->parent->parent != NULL) + return; + + /* Free any existing window region stored in the window privates */ + if (pWinPriv->hRgn != NULL) + { + DeleteObject (pWinPriv->hRgn); + pWinPriv->hRgn = NULL; + } + + /* Bail if the window has no bounding region defined */ + if (!wBoundingShape (pWin)) + return; + + REGION_NULL(pScreen, &rrNewShape); + REGION_COPY(pScreen, &rrNewShape, wBoundingShape(pWin)); + REGION_TRANSLATE(pScreen, &rrNewShape, pWin->borderWidth, + pWin->borderWidth); + + nRects = REGION_NUM_RECTS(&rrNewShape); + pShape = REGION_RECTS(&rrNewShape); + + if (nRects > 0) + { + /* Create initial empty Windows region */ + hRgn = CreateRectRgn (0, 0, 0, 0); + + /* Loop through all rectangles in the X region */ + for (pRects = pShape, pEnd = pShape + nRects; pRects < pEnd; pRects++) + { + /* Create a Windows region for the X rectangle */ + hRgnRect = CreateRectRgn (pRects->x1, pRects->y1, + pRects->x2, pRects->y2); + if (hRgnRect == NULL) + { + ErrorF("winReshapeRootless - CreateRectRgn() failed\n"); + } + + /* Merge the Windows region with the accumulated region */ + if (CombineRgn (hRgn, hRgn, hRgnRect, RGN_OR) == ERROR) + { + ErrorF("winReshapeRootless - CombineRgn() failed\n"); + } + + /* Delete the temporary Windows region */ + DeleteObject (hRgnRect); + } + + /* Save a handle to the composite region in the window privates */ + pWinPriv->hRgn = hRgn; + } + + REGION_UNINIT(pScreen, &rrNewShape); + + return; +} diff --git a/xorg-server/hw/xwin/winwindowswm.c b/xorg-server/hw/xwin/winwindowswm.c index dffea425f..d8cacdc99 100644 --- a/xorg-server/hw/xwin/winwindowswm.c +++ b/xorg-server/hw/xwin/winwindowswm.c @@ -124,7 +124,7 @@ ProcWindowsWMQueryVersion(register ClientPtr client) swapl(&rep.length, n); } WriteToClient(client, sizeof(xWindowsWMQueryVersionReply), (char *)&rep); - return (client->noClientException); + return Success; } @@ -164,7 +164,7 @@ WMFreeClient (pointer data, XID id) } updateEventMask (pHead); } - xfree ((pointer) pEvent); + free((pointer) pEvent); return 1; } @@ -179,9 +179,9 @@ WMFreeEvents (pointer data, XID id) { pNext = pCur->next; FreeResource (pCur->clientResource, ClientType); - xfree ((pointer) pCur); + free((pointer) pCur); } - xfree ((pointer) pHead); + free((pointer) pHead); eventMask = 0; return 1; } @@ -212,7 +212,7 @@ ProcWindowsWMSelectInput (register ClientPtr client) } /* build the entry */ - pNewEvent = (WMEventPtr) xalloc (sizeof (WMEventRec)); + pNewEvent = (WMEventPtr) malloc(sizeof (WMEventRec)); if (!pNewEvent) return BadAlloc; pNewEvent->next = 0; @@ -234,7 +234,7 @@ ProcWindowsWMSelectInput (register ClientPtr client) */ if (!pHead) { - pHead = (WMEventPtr *) xalloc (sizeof (WMEventPtr)); + pHead = (WMEventPtr *) malloc(sizeof (WMEventPtr)); if (!pHead || !AddResource (eventResource, eventResourceType, (pointer)pHead)) { @@ -266,7 +266,7 @@ ProcWindowsWMSelectInput (register ClientPtr client) pNewEvent->next = pEvent->next; else *pHead = pEvent->next; - xfree (pEvent); + free(pEvent); updateEventMask (pHead); } } @@ -335,7 +335,7 @@ ProcWindowsWMDisableUpdate (register ClientPtr client) //winDisableUpdate(); - return (client->noClientException); + return Success; } static int @@ -345,7 +345,7 @@ ProcWindowsWMReenableUpdate (register ClientPtr client) //winEnableUpdate(); - return (client->noClientException); + return Success; } @@ -358,7 +358,7 @@ ProcWindowsWMSetFrontProcess (register ClientPtr client) //QuartzMessageMainThread(kWindowsSetFrontProcess, NULL, 0); - return (client->noClientException); + return Success; } @@ -414,7 +414,7 @@ ProcWindowsWMFrameGetRect (register ClientPtr client) #endif WriteToClient(client, sizeof(xWindowsWMFrameGetRectReply), (char *)&rep); - return (client->noClientException); + return Success; } @@ -507,7 +507,7 @@ ProcWindowsWMFrameDraw (register ClientPtr client) ErrorF ("ProcWindowsWMFrameDraw - done\n"); #endif - return (client->noClientException); + return Success; } static int @@ -566,7 +566,7 @@ ProcWindowsWMFrameSetTitle( ErrorF ("ProcWindowsWMFrameSetTitle - done\n"); #endif - return (client->noClientException); + return Success; } diff --git a/xorg-server/include/colormap.h b/xorg-server/include/colormap.h index de48ce8d8..db4c1c834 100644 --- a/xorg-server/include/colormap.h +++ b/xorg-server/include/colormap.h @@ -1,187 +1,189 @@ -/* - -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. - -*/ - -#ifndef CMAP_H -#define CMAP_H 1 - -#include <X11/Xproto.h> -#include "screenint.h" -#include "window.h" - -/* these follow X.h's AllocNone and AllocAll */ -#define CM_PSCREEN 2 -#define CM_PWIN 3 -/* Passed internally in colormap.c */ -#define REDMAP 0 -#define GREENMAP 1 -#define BLUEMAP 2 -#define PSEUDOMAP 3 -#define AllocPrivate (-1) -#define AllocTemporary (-2) -#define DynamicClass 1 - -/* Values for the flags field of a colormap. These should have 1 bit set - * and not overlap */ -#define IsDefault 1 -#define AllAllocated 2 -#define BeingCreated 4 - - -typedef CARD32 Pixel; -typedef struct _CMEntry *EntryPtr; -/* moved to screenint.h: typedef struct _ColormapRec *ColormapPtr */ -typedef struct _colorResource *colorResourcePtr; - -extern _X_EXPORT int CreateColormap( - Colormap /*mid*/, - ScreenPtr /*pScreen*/, - VisualPtr /*pVisual*/, - ColormapPtr* /*ppcmap*/, - int /*alloc*/, - int /*client*/); - -extern _X_EXPORT int FreeColormap( - pointer /*pmap*/, - XID /*mid*/); - -extern _X_EXPORT int TellLostMap( - WindowPtr /*pwin*/, - pointer /* Colormap *pmid */); - -extern _X_EXPORT int TellGainedMap( - WindowPtr /*pwin*/, - pointer /* Colormap *pmid */); - -extern _X_EXPORT int CopyColormapAndFree( - Colormap /*mid*/, - ColormapPtr /*pSrc*/, - int /*client*/); - -extern _X_EXPORT int AllocColor( - ColormapPtr /*pmap*/, - unsigned short* /*pred*/, - unsigned short* /*pgreen*/, - unsigned short* /*pblue*/, - Pixel* /*pPix*/, - int /*client*/); - -extern _X_EXPORT void FakeAllocColor( - ColormapPtr /*pmap*/, - xColorItem * /*item*/); - -extern _X_EXPORT void FakeFreeColor( - ColormapPtr /*pmap*/, - Pixel /*pixel*/); - -typedef int (*ColorCompareProcPtr)( - EntryPtr /*pent*/, - xrgb * /*prgb*/); - -extern _X_EXPORT int FindColor( - ColormapPtr /*pmap*/, - EntryPtr /*pentFirst*/, - int /*size*/, - xrgb* /*prgb*/, - Pixel* /*pPixel*/, - int /*channel*/, - int /*client*/, - ColorCompareProcPtr /*comp*/); - -extern _X_EXPORT int QueryColors( - ColormapPtr /*pmap*/, - int /*count*/, - Pixel* /*ppixIn*/, - xrgb* /*prgbList*/); - -extern _X_EXPORT int FreeClientPixels( - pointer /*pcr*/, - XID /*fakeid*/); - -extern _X_EXPORT int AllocColorCells( - int /*client*/, - ColormapPtr /*pmap*/, - int /*colors*/, - int /*planes*/, - Bool /*contig*/, - Pixel* /*ppix*/, - Pixel* /*masks*/); - -extern _X_EXPORT int AllocColorPlanes( - int /*client*/, - ColormapPtr /*pmap*/, - int /*colors*/, - int /*r*/, - int /*g*/, - int /*b*/, - Bool /*contig*/, - Pixel* /*pixels*/, - Pixel* /*prmask*/, - Pixel* /*pgmask*/, - Pixel* /*pbmask*/); - -extern _X_EXPORT int FreeColors( - ColormapPtr /*pmap*/, - int /*client*/, - int /*count*/, - Pixel* /*pixels*/, - Pixel /*mask*/); - -extern _X_EXPORT int StoreColors( - ColormapPtr /*pmap*/, - int /*count*/, - xColorItem* /*defs*/); - -extern _X_EXPORT int IsMapInstalled( - Colormap /*map*/, - WindowPtr /*pWin*/); - -extern _X_EXPORT Bool ResizeVisualArray( - ScreenPtr /* pScreen */, - int /* new_vis_count */, - DepthPtr /* depth */); - -#endif /* CMAP_H */ +/* + +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. + +*/ + +#ifndef CMAP_H +#define CMAP_H 1 + +#include <X11/Xproto.h> +#include "screenint.h" +#include "window.h" + +/* these follow X.h's AllocNone and AllocAll */ +#define CM_PSCREEN 2 +#define CM_PWIN 3 +/* Passed internally in colormap.c */ +#define REDMAP 0 +#define GREENMAP 1 +#define BLUEMAP 2 +#define PSEUDOMAP 3 +#define AllocPrivate (-1) +#define AllocTemporary (-2) +#define DynamicClass 1 + +/* Values for the flags field of a colormap. These should have 1 bit set + * and not overlap */ +#define IsDefault 1 +#define AllAllocated 2 +#define BeingCreated 4 + + +typedef CARD32 Pixel; +typedef struct _CMEntry *EntryPtr; +/* moved to screenint.h: typedef struct _ColormapRec *ColormapPtr */ +typedef struct _colorResource *colorResourcePtr; + +extern _X_EXPORT int CreateColormap( + Colormap /*mid*/, + ScreenPtr /*pScreen*/, + VisualPtr /*pVisual*/, + ColormapPtr* /*ppcmap*/, + int /*alloc*/, + int /*client*/); + +extern _X_EXPORT int FreeColormap( + pointer /*pmap*/, + XID /*mid*/); + +extern _X_EXPORT int TellLostMap( + WindowPtr /*pwin*/, + pointer /* Colormap *pmid */); + +extern _X_EXPORT int TellGainedMap( + WindowPtr /*pwin*/, + pointer /* Colormap *pmid */); + +extern _X_EXPORT int CopyColormapAndFree( + Colormap /*mid*/, + ColormapPtr /*pSrc*/, + int /*client*/); + +extern _X_EXPORT int AllocColor( + ColormapPtr /*pmap*/, + unsigned short* /*pred*/, + unsigned short* /*pgreen*/, + unsigned short* /*pblue*/, + Pixel* /*pPix*/, + int /*client*/); + +extern _X_EXPORT void FakeAllocColor( + ColormapPtr /*pmap*/, + xColorItem * /*item*/); + +extern _X_EXPORT void FakeFreeColor( + ColormapPtr /*pmap*/, + Pixel /*pixel*/); + +typedef int (*ColorCompareProcPtr)( + EntryPtr /*pent*/, + xrgb * /*prgb*/); + +extern _X_EXPORT int FindColor( + ColormapPtr /*pmap*/, + EntryPtr /*pentFirst*/, + int /*size*/, + xrgb* /*prgb*/, + Pixel* /*pPixel*/, + int /*channel*/, + int /*client*/, + ColorCompareProcPtr /*comp*/); + +extern _X_EXPORT int QueryColors( + ColormapPtr /*pmap*/, + int /*count*/, + Pixel* /*ppixIn*/, + xrgb* /*prgbList*/, + ClientPtr client); + +extern _X_EXPORT int FreeClientPixels( + pointer /*pcr*/, + XID /*fakeid*/); + +extern _X_EXPORT int AllocColorCells( + int /*client*/, + ColormapPtr /*pmap*/, + int /*colors*/, + int /*planes*/, + Bool /*contig*/, + Pixel* /*ppix*/, + Pixel* /*masks*/); + +extern _X_EXPORT int AllocColorPlanes( + int /*client*/, + ColormapPtr /*pmap*/, + int /*colors*/, + int /*r*/, + int /*g*/, + int /*b*/, + Bool /*contig*/, + Pixel* /*pixels*/, + Pixel* /*prmask*/, + Pixel* /*pgmask*/, + Pixel* /*pbmask*/); + +extern _X_EXPORT int FreeColors( + ColormapPtr /*pmap*/, + int /*client*/, + int /*count*/, + Pixel* /*pixels*/, + Pixel /*mask*/); + +extern _X_EXPORT int StoreColors( + ColormapPtr /*pmap*/, + int /*count*/, + xColorItem* /*defs*/, + ClientPtr client); + +extern _X_EXPORT int IsMapInstalled( + Colormap /*map*/, + WindowPtr /*pWin*/); + +extern _X_EXPORT Bool ResizeVisualArray( + ScreenPtr /* pScreen */, + int /* new_vis_count */, + DepthPtr /* depth */); + +#endif /* CMAP_H */ diff --git a/xorg-server/include/dixfont.h b/xorg-server/include/dixfont.h index e444a2024..4e23da845 100644 --- a/xorg-server/include/dixfont.h +++ b/xorg-server/include/dixfont.h @@ -1,188 +1,187 @@ -/*********************************************************** -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. - -******************************************************************/ - -#ifndef DIXFONT_H -#define DIXFONT_H 1 - -#include "dix.h" -#include <X11/fonts/font.h> -#include "closure.h" -#include <X11/fonts/fontstruct.h> - -#define NullDIXFontProp ((DIXFontPropPtr)0) - -typedef struct _DIXFontProp *DIXFontPropPtr; - -extern _X_EXPORT Bool SetDefaultFont(char * /*defaultfontname*/); - -extern _X_EXPORT void QueueFontWakeup(FontPathElementPtr /*fpe*/); - -extern _X_EXPORT void RemoveFontWakeup(FontPathElementPtr /*fpe*/); - -extern _X_EXPORT void FontWakeup(pointer /*data*/, - int /*count*/, - pointer /*LastSelectMask*/); - -extern _X_EXPORT int OpenFont(ClientPtr /*client*/, - XID /*fid*/, - Mask /*flags*/, - unsigned /*lenfname*/, - char * /*pfontname*/); - -extern _X_EXPORT int CloseFont(pointer /*pfont*/, - XID /*fid*/); - -typedef struct _xQueryFontReply *xQueryFontReplyPtr; - -extern _X_EXPORT void QueryFont(FontPtr /*pFont*/, - xQueryFontReplyPtr /*pReply*/, - int /*nProtoCCIStructs*/); - -extern _X_EXPORT int ListFonts(ClientPtr /*client*/, - unsigned char * /*pattern*/, - unsigned int /*length*/, - unsigned int /*max_names*/); - -extern _X_EXPORT int -doListFontsWithInfo(ClientPtr /*client*/, - LFWIclosurePtr /*c*/); - -extern _X_EXPORT int doPolyText(ClientPtr /*client*/, - PTclosurePtr /*c*/ -); - -extern _X_EXPORT int PolyText(ClientPtr /*client*/, - DrawablePtr /*pDraw*/, - GCPtr /*pGC*/, - unsigned char * /*pElt*/, - unsigned char * /*endReq*/, - int /*xorg*/, - int /*yorg*/, - int /*reqType*/, - XID /*did*/); - -extern _X_EXPORT int doImageText(ClientPtr /*client*/, - ITclosurePtr /*c*/); - -extern _X_EXPORT int ImageText(ClientPtr /*client*/, - DrawablePtr /*pDraw*/, - GCPtr /*pGC*/, - int /*nChars*/, - unsigned char * /*data*/, - int /*xorg*/, - int /*yorg*/, - int /*reqType*/, - XID /*did*/); - -extern _X_EXPORT int SetFontPath(ClientPtr /*client*/, - int /*npaths*/, - unsigned char * /*paths*/, - int * /*error*/); - -extern _X_EXPORT int SetDefaultFontPath(char * /*path*/); - -extern _X_EXPORT int GetFontPath(ClientPtr client, - int *count, - int *length, - unsigned char **result); - -extern _X_EXPORT void DeleteClientFontStuff(ClientPtr /*client*/); - -/* Quartz support on Mac OS X pulls in the QuickDraw - framework whose InitFonts function conflicts here. */ -#ifdef __APPLE__ -#define InitFonts Darwin_X_InitFonts -#endif -extern _X_EXPORT void InitFonts(void); - -extern _X_EXPORT void FreeFonts(void); - -extern _X_EXPORT FontPtr find_old_font(XID /*id*/); - -extern _X_EXPORT void GetGlyphs(FontPtr /*font*/, - unsigned long /*count*/, - unsigned char * /*chars*/, - FontEncoding /*fontEncoding*/, - unsigned long * /*glyphcount*/, - CharInfoPtr * /*glyphs*/); - -extern _X_EXPORT void QueryGlyphExtents(FontPtr /*pFont*/, - CharInfoPtr * /*charinfo*/, - unsigned long /*count*/, - ExtentInfoPtr /*info*/); - -extern _X_EXPORT Bool QueryTextExtents(FontPtr /*pFont*/, - unsigned long /*count*/, - unsigned char * /*chars*/, - ExtentInfoPtr /*info*/); - -extern _X_EXPORT Bool ParseGlyphCachingMode(char * /*str*/); - -extern _X_EXPORT void InitGlyphCaching(void); - -extern _X_EXPORT void SetGlyphCachingMode(int /*newmode*/); - -/* - * libXfont/src/builtins/builtin.h - */ -extern _X_EXPORT void BuiltinRegisterFpeFunctions(void); - -/* - * libXfont stubs. - */ -extern _X_EXPORT int client_auth_generation(ClientPtr client); - -extern _X_EXPORT void DeleteFontClientID(Font id); - -extern _X_EXPORT FontResolutionPtr GetClientResolutions(int *num); - -extern _X_EXPORT int GetDefaultPointSize(void); - -extern _X_EXPORT Font GetNewFontClientID(void); - -extern _X_EXPORT int init_fs_handlers(FontPathElementPtr fpe, - BlockHandlerProcPtr block_handler); - -extern _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); - -extern _X_EXPORT void remove_fs_handlers(FontPathElementPtr fpe, - BlockHandlerProcPtr blockHandler, - Bool all); - -extern _X_EXPORT int StoreFontClientFont(FontPtr pfont, Font id); - -#endif /* DIXFONT_H */ +/*********************************************************** +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. + +******************************************************************/ + +#ifndef DIXFONT_H +#define DIXFONT_H 1 + +#include "dix.h" +#include <X11/fonts/font.h> +#include "closure.h" +#include <X11/fonts/fontstruct.h> + +#define NullDIXFontProp ((DIXFontPropPtr)0) + +typedef struct _DIXFontProp *DIXFontPropPtr; + +extern _X_EXPORT Bool SetDefaultFont(char * /*defaultfontname*/); + +extern _X_EXPORT void QueueFontWakeup(FontPathElementPtr /*fpe*/); + +extern _X_EXPORT void RemoveFontWakeup(FontPathElementPtr /*fpe*/); + +extern _X_EXPORT void FontWakeup(pointer /*data*/, + int /*count*/, + pointer /*LastSelectMask*/); + +extern _X_EXPORT int OpenFont(ClientPtr /*client*/, + XID /*fid*/, + Mask /*flags*/, + unsigned /*lenfname*/, + char * /*pfontname*/); + +extern _X_EXPORT int CloseFont(pointer /*pfont*/, + XID /*fid*/); + +typedef struct _xQueryFontReply *xQueryFontReplyPtr; + +extern _X_EXPORT void QueryFont(FontPtr /*pFont*/, + xQueryFontReplyPtr /*pReply*/, + int /*nProtoCCIStructs*/); + +extern _X_EXPORT int ListFonts(ClientPtr /*client*/, + unsigned char * /*pattern*/, + unsigned int /*length*/, + unsigned int /*max_names*/); + +extern _X_EXPORT int +doListFontsWithInfo(ClientPtr /*client*/, + LFWIclosurePtr /*c*/); + +extern _X_EXPORT int doPolyText(ClientPtr /*client*/, + PTclosurePtr /*c*/ +); + +extern _X_EXPORT int PolyText(ClientPtr /*client*/, + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + unsigned char * /*pElt*/, + unsigned char * /*endReq*/, + int /*xorg*/, + int /*yorg*/, + int /*reqType*/, + XID /*did*/); + +extern _X_EXPORT int doImageText(ClientPtr /*client*/, + ITclosurePtr /*c*/); + +extern _X_EXPORT int ImageText(ClientPtr /*client*/, + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*nChars*/, + unsigned char * /*data*/, + int /*xorg*/, + int /*yorg*/, + int /*reqType*/, + XID /*did*/); + +extern _X_EXPORT int SetFontPath(ClientPtr /*client*/, + int /*npaths*/, + unsigned char * /*paths*/); + +extern _X_EXPORT int SetDefaultFontPath(char * /*path*/); + +extern _X_EXPORT int GetFontPath(ClientPtr client, + int *count, + int *length, + unsigned char **result); + +extern _X_EXPORT void DeleteClientFontStuff(ClientPtr /*client*/); + +/* Quartz support on Mac OS X pulls in the QuickDraw + framework whose InitFonts function conflicts here. */ +#ifdef __APPLE__ +#define InitFonts Darwin_X_InitFonts +#endif +extern _X_EXPORT void InitFonts(void); + +extern _X_EXPORT void FreeFonts(void); + +extern _X_EXPORT FontPtr find_old_font(XID /*id*/); + +extern _X_EXPORT void GetGlyphs(FontPtr /*font*/, + unsigned long /*count*/, + unsigned char * /*chars*/, + FontEncoding /*fontEncoding*/, + unsigned long * /*glyphcount*/, + CharInfoPtr * /*glyphs*/); + +extern _X_EXPORT void QueryGlyphExtents(FontPtr /*pFont*/, + CharInfoPtr * /*charinfo*/, + unsigned long /*count*/, + ExtentInfoPtr /*info*/); + +extern _X_EXPORT Bool QueryTextExtents(FontPtr /*pFont*/, + unsigned long /*count*/, + unsigned char * /*chars*/, + ExtentInfoPtr /*info*/); + +extern _X_EXPORT Bool ParseGlyphCachingMode(char * /*str*/); + +extern _X_EXPORT void InitGlyphCaching(void); + +extern _X_EXPORT void SetGlyphCachingMode(int /*newmode*/); + +/* + * libXfont/src/builtins/builtin.h + */ +extern _X_EXPORT void BuiltinRegisterFpeFunctions(void); + +/* + * libXfont stubs. + */ +extern _X_EXPORT int client_auth_generation(ClientPtr client); + +extern _X_EXPORT void DeleteFontClientID(Font id); + +extern _X_EXPORT FontResolutionPtr GetClientResolutions(int *num); + +extern _X_EXPORT int GetDefaultPointSize(void); + +extern _X_EXPORT Font GetNewFontClientID(void); + +extern _X_EXPORT int init_fs_handlers(FontPathElementPtr fpe, + BlockHandlerProcPtr block_handler); + +extern _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); + +extern _X_EXPORT void remove_fs_handlers(FontPathElementPtr fpe, + BlockHandlerProcPtr blockHandler, + Bool all); + +extern _X_EXPORT int StoreFontClientFont(FontPtr pfont, Font id); + +#endif /* DIXFONT_H */ diff --git a/xorg-server/include/gc.h b/xorg-server/include/gc.h index e75cc5e83..428c40441 100644 --- a/xorg-server/include/gc.h +++ b/xorg-server/include/gc.h @@ -1,173 +1,167 @@ -/*********************************************************** - -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. - -******************************************************************/ - -#ifndef GC_H -#define GC_H - -#include <X11/X.h> /* for GContext, Mask */ -#include <X11/Xdefs.h> /* for Bool */ -#include <X11/Xproto.h> -#include "screenint.h" /* for ScreenPtr */ -#include "pixmap.h" /* for DrawablePtr */ - -/* clientClipType field in GC */ -#define CT_NONE 0 -#define CT_PIXMAP 1 -#define CT_REGION 2 -#define CT_UNSORTED 6 -#define CT_YSORTED 10 -#define CT_YXSORTED 14 -#define CT_YXBANDED 18 - -#define GCQREASON_VALIDATE 1 -#define GCQREASON_CHANGE 2 -#define GCQREASON_COPY_SRC 3 -#define GCQREASON_COPY_DST 4 -#define GCQREASON_DESTROY 5 - -#define GC_CHANGE_SERIAL_BIT (((unsigned long)1)<<31) -#define GC_CALL_VALIDATE_BIT (1L<<30) -#define GCExtensionInterest (1L<<29) - -#define DRAWABLE_SERIAL_BITS (~(GC_CHANGE_SERIAL_BIT)) - -#define MAX_SERIAL_NUM (1L<<28) - -#define NEXT_SERIAL_NUMBER ((++globalSerialNumber) > MAX_SERIAL_NUM ? \ - (globalSerialNumber = 1): globalSerialNumber) - -typedef struct _GCInterest *GCInterestPtr; -typedef struct _GC *GCPtr; -typedef struct _GCOps *GCOpsPtr; - -extern _X_EXPORT void ValidateGC( - DrawablePtr /*pDraw*/, - GCPtr /*pGC*/); - -extern _X_EXPORT int ChangeGC( - GCPtr/*pGC*/, - BITS32 /*mask*/, - XID* /*pval*/); - -extern _X_EXPORT int DoChangeGC( - GCPtr/*pGC*/, - BITS32 /*mask*/, - XID* /*pval*/, - int /*fPointer*/); - -typedef union { - CARD32 val; - pointer ptr; -} ChangeGCVal, *ChangeGCValPtr; - -extern _X_EXPORT int dixChangeGC( - ClientPtr /*client*/, - GCPtr /*pGC*/, - BITS32 /*mask*/, - CARD32 * /*pval*/, - ChangeGCValPtr /*pCGCV*/); - -extern _X_EXPORT GCPtr CreateGC( - DrawablePtr /*pDrawable*/, - BITS32 /*mask*/, - XID* /*pval*/, - int* /*pStatus*/, - XID /*gcid*/, - ClientPtr /*client*/); - -extern _X_EXPORT int CopyGC( - GCPtr/*pgcSrc*/, - GCPtr/*pgcDst*/, - BITS32 /*mask*/); - -extern _X_EXPORT int FreeGC( - pointer /*pGC*/, - XID /*gid*/); - -extern _X_EXPORT GCPtr CreateScratchGC( - ScreenPtr /*pScreen*/, - unsigned /*depth*/); - -extern _X_EXPORT void FreeGCperDepth( - int /*screenNum*/); - -extern _X_EXPORT Bool CreateGCperDepth( - int /*screenNum*/); - -extern _X_EXPORT Bool CreateDefaultStipple( - int /*screenNum*/); - -extern _X_EXPORT void FreeDefaultStipple( - int /*screenNum*/); - -extern _X_EXPORT int SetDashes( - GCPtr /*pGC*/, - unsigned /*offset*/, - unsigned /*ndash*/, - unsigned char* /*pdash*/); - -extern _X_EXPORT int VerifyRectOrder( - int /*nrects*/, - xRectangle* /*prects*/, - int /*ordering*/); - -extern _X_EXPORT int SetClipRects( - GCPtr /*pGC*/, - int /*xOrigin*/, - int /*yOrigin*/, - int /*nrects*/, - xRectangle* /*prects*/, - int /*ordering*/); - -extern _X_EXPORT GCPtr GetScratchGC( - unsigned /*depth*/, - ScreenPtr /*pScreen*/); - -extern _X_EXPORT void FreeScratchGC( - GCPtr /*pGC*/); - -#endif /* GC_H */ +/*********************************************************** + +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. + +******************************************************************/ + +#ifndef GC_H +#define GC_H + +#include <X11/X.h> /* for GContext, Mask */ +#include <X11/Xdefs.h> /* for Bool */ +#include <X11/Xproto.h> +#include "screenint.h" /* for ScreenPtr */ +#include "pixmap.h" /* for DrawablePtr */ + +/* clientClipType field in GC */ +#define CT_NONE 0 +#define CT_PIXMAP 1 +#define CT_REGION 2 +#define CT_UNSORTED 6 +#define CT_YSORTED 10 +#define CT_YXSORTED 14 +#define CT_YXBANDED 18 + +#define GCQREASON_VALIDATE 1 +#define GCQREASON_CHANGE 2 +#define GCQREASON_COPY_SRC 3 +#define GCQREASON_COPY_DST 4 +#define GCQREASON_DESTROY 5 + +#define GC_CHANGE_SERIAL_BIT (((unsigned long)1)<<31) +#define GC_CALL_VALIDATE_BIT (1L<<30) +#define GCExtensionInterest (1L<<29) + +#define DRAWABLE_SERIAL_BITS (~(GC_CHANGE_SERIAL_BIT)) + +#define MAX_SERIAL_NUM (1L<<28) + +#define NEXT_SERIAL_NUMBER ((++globalSerialNumber) > MAX_SERIAL_NUM ? \ + (globalSerialNumber = 1): globalSerialNumber) + +typedef struct _GCInterest *GCInterestPtr; +typedef struct _GC *GCPtr; +typedef struct _GCOps *GCOpsPtr; + +extern _X_EXPORT void ValidateGC( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/); + +typedef union { + CARD32 val; + pointer ptr; +} ChangeGCVal, *ChangeGCValPtr; + +extern int ChangeGCXIDs( + ClientPtr /*client*/, + GCPtr /*pGC*/, + BITS32 /*mask*/, + CARD32 * /*pval*/); + +extern _X_EXPORT int ChangeGC( + ClientPtr /*client*/, + GCPtr /*pGC*/, + BITS32 /*mask*/, + ChangeGCValPtr /*pCGCV*/); + +extern _X_EXPORT GCPtr CreateGC( + DrawablePtr /*pDrawable*/, + BITS32 /*mask*/, + XID* /*pval*/, + int* /*pStatus*/, + XID /*gcid*/, + ClientPtr /*client*/); + +extern _X_EXPORT int CopyGC( + GCPtr/*pgcSrc*/, + GCPtr/*pgcDst*/, + BITS32 /*mask*/); + +extern _X_EXPORT int FreeGC( + pointer /*pGC*/, + XID /*gid*/); + +extern _X_EXPORT GCPtr CreateScratchGC( + ScreenPtr /*pScreen*/, + unsigned /*depth*/); + +extern _X_EXPORT void FreeGCperDepth( + int /*screenNum*/); + +extern _X_EXPORT Bool CreateGCperDepth( + int /*screenNum*/); + +extern _X_EXPORT Bool CreateDefaultStipple( + int /*screenNum*/); + +extern _X_EXPORT void FreeDefaultStipple( + int /*screenNum*/); + +extern _X_EXPORT int SetDashes( + GCPtr /*pGC*/, + unsigned /*offset*/, + unsigned /*ndash*/, + unsigned char* /*pdash*/); + +extern _X_EXPORT int VerifyRectOrder( + int /*nrects*/, + xRectangle* /*prects*/, + int /*ordering*/); + +extern _X_EXPORT int SetClipRects( + GCPtr /*pGC*/, + int /*xOrigin*/, + int /*yOrigin*/, + int /*nrects*/, + xRectangle* /*prects*/, + int /*ordering*/); + +extern _X_EXPORT GCPtr GetScratchGC( + unsigned /*depth*/, + ScreenPtr /*pScreen*/); + +extern _X_EXPORT void FreeScratchGC( + GCPtr /*pGC*/); + +#endif /* GC_H */ diff --git a/xorg-server/include/gcstruct.h b/xorg-server/include/gcstruct.h index 8d9b05575..c56dd9294 100644 --- a/xorg-server/include/gcstruct.h +++ b/xorg-server/include/gcstruct.h @@ -1,323 +1,325 @@ -/*********************************************************** - -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. - -******************************************************************/ - - - -#ifndef GCSTRUCT_H -#define GCSTRUCT_H - -#include "gc.h" - -#include "regionstr.h" -#include "region.h" -#include "pixmap.h" -#include "screenint.h" -#include "privates.h" -#include <X11/Xprotostr.h> - -/* - * functions which modify the state of the GC - */ - -typedef struct _GCFuncs { - void (* ValidateGC)( - GCPtr /*pGC*/, - unsigned long /*stateChanges*/, - DrawablePtr /*pDrawable*/); - - void (* ChangeGC)( - GCPtr /*pGC*/, - unsigned long /*mask*/); - - void (* CopyGC)( - GCPtr /*pGCSrc*/, - unsigned long /*mask*/, - GCPtr /*pGCDst*/); - - void (* DestroyGC)( - GCPtr /*pGC*/); - - void (* ChangeClip)( - GCPtr /*pGC*/, - int /*type*/, - pointer /*pvalue*/, - int /*nrects*/); - - void (* DestroyClip)( - GCPtr /*pGC*/); - - void (* CopyClip)( - GCPtr /*pgcDst*/, - GCPtr /*pgcSrc*/); - DevUnion devPrivate; -} GCFuncs; - -/* - * graphics operations invoked through a GC - */ - -typedef struct _GCOps { - void (* FillSpans)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*nInit*/, - DDXPointPtr /*pptInit*/, - int * /*pwidthInit*/, - int /*fSorted*/); - - void (* SetSpans)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - char * /*psrc*/, - DDXPointPtr /*ppt*/, - int * /*pwidth*/, - int /*nspans*/, - int /*fSorted*/); - - void (* PutImage)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*depth*/, - int /*x*/, - int /*y*/, - int /*w*/, - int /*h*/, - int /*leftPad*/, - int /*format*/, - char * /*pBits*/); - - RegionPtr (* CopyArea)( - DrawablePtr /*pSrc*/, - DrawablePtr /*pDst*/, - GCPtr /*pGC*/, - int /*srcx*/, - int /*srcy*/, - int /*w*/, - int /*h*/, - int /*dstx*/, - int /*dsty*/); - - RegionPtr (* CopyPlane)( - DrawablePtr /*pSrcDrawable*/, - DrawablePtr /*pDstDrawable*/, - GCPtr /*pGC*/, - int /*srcx*/, - int /*srcy*/, - int /*width*/, - int /*height*/, - int /*dstx*/, - int /*dsty*/, - unsigned long /*bitPlane*/); - void (* PolyPoint)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*mode*/, - int /*npt*/, - DDXPointPtr /*pptInit*/); - - void (* Polylines)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*mode*/, - int /*npt*/, - DDXPointPtr /*pptInit*/); - - void (* PolySegment)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*nseg*/, - xSegment * /*pSegs*/); - - void (* PolyRectangle)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*nrects*/, - xRectangle * /*pRects*/); - - void (* PolyArc)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*narcs*/, - xArc * /*parcs*/); - - void (* FillPolygon)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*shape*/, - int /*mode*/, - int /*count*/, - DDXPointPtr /*pPts*/); - - void (* PolyFillRect)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*nrectFill*/, - xRectangle * /*prectInit*/); - - void (* PolyFillArc)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*narcs*/, - xArc * /*parcs*/); - - int (* PolyText8)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*x*/, - int /*y*/, - int /*count*/, - char * /*chars*/); - - int (* PolyText16)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*x*/, - int /*y*/, - int /*count*/, - unsigned short * /*chars*/); - - void (* ImageText8)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*x*/, - int /*y*/, - int /*count*/, - char * /*chars*/); - - void (* ImageText16)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*x*/, - int /*y*/, - int /*count*/, - unsigned short * /*chars*/); - - void (* ImageGlyphBlt)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*x*/, - int /*y*/, - unsigned int /*nglyph*/, - CharInfoPtr * /*ppci*/, - pointer /*pglyphBase*/); - - void (* PolyGlyphBlt)( - DrawablePtr /*pDrawable*/, - GCPtr /*pGC*/, - int /*x*/, - int /*y*/, - unsigned int /*nglyph*/, - CharInfoPtr * /*ppci*/, - pointer /*pglyphBase*/); - - void (* PushPixels)( - GCPtr /*pGC*/, - PixmapPtr /*pBitMap*/, - DrawablePtr /*pDst*/, - int /*w*/, - int /*h*/, - int /*x*/, - int /*y*/); - - DevUnion devPrivate; -} GCOps; - -/* there is padding in the bit fields because the Sun compiler doesn't - * force alignment to 32-bit boundaries. losers. - */ -typedef struct _GC { - ScreenPtr pScreen; - unsigned char depth; - unsigned char alu; - unsigned short lineWidth; - unsigned short dashOffset; - unsigned short numInDashList; - unsigned char *dash; - unsigned int lineStyle : 2; - unsigned int capStyle : 2; - unsigned int joinStyle : 2; - unsigned int fillStyle : 2; - unsigned int fillRule : 1; - unsigned int arcMode : 1; - unsigned int subWindowMode : 1; - unsigned int graphicsExposures : 1; - unsigned int clientClipType : 2; /* CT_<kind> */ - unsigned int miTranslate:1; /* should mi things translate? */ - unsigned int tileIsPixel:1; /* tile is solid pixel */ - unsigned int fExpose:1; /* Call exposure handling */ - unsigned int freeCompClip:1; /* Free composite clip */ - unsigned int unused:14; /* see comment above */ - unsigned long planemask; - unsigned long fgPixel; - unsigned long bgPixel; - /* - * alas -- both tile and stipple must be here as they - * are independently specifiable - */ - PixUnion tile; - PixmapPtr stipple; - DDXPointRec patOrg; /* origin for (tile, stipple) */ - struct _Font *font; - DDXPointRec clipOrg; - DDXPointRec lastWinOrg; /* position of window last validated */ - pointer clientClip; - unsigned long stateChanges; /* masked with GC_<kind> */ - unsigned long serialNumber; - GCFuncs *funcs; - GCOps *ops; - PrivateRec *devPrivates; - /* - * The following were moved here from private storage to allow device- - * independent access to them from screen wrappers. - * --- 1997.11.03 Marc Aurele La France (tsi@xfree86.org) - */ - PixmapPtr pRotatedPixmap; /* tile/stipple rotated for alignment */ - RegionPtr pCompositeClip; - /* fExpose & freeCompClip defined above */ -} GC; - -#endif /* GCSTRUCT_H */ +/*********************************************************** + +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. + +******************************************************************/ + + + +#ifndef GCSTRUCT_H +#define GCSTRUCT_H + +#include "gc.h" + +#include "regionstr.h" +#include "region.h" +#include "pixmap.h" +#include "screenint.h" +#include "privates.h" +#include <X11/Xprotostr.h> + +#define GCAllBits ((1 << (GCLastBit + 1)) - 1) + +/* + * functions which modify the state of the GC + */ + +typedef struct _GCFuncs { + void (* ValidateGC)( + GCPtr /*pGC*/, + unsigned long /*stateChanges*/, + DrawablePtr /*pDrawable*/); + + void (* ChangeGC)( + GCPtr /*pGC*/, + unsigned long /*mask*/); + + void (* CopyGC)( + GCPtr /*pGCSrc*/, + unsigned long /*mask*/, + GCPtr /*pGCDst*/); + + void (* DestroyGC)( + GCPtr /*pGC*/); + + void (* ChangeClip)( + GCPtr /*pGC*/, + int /*type*/, + pointer /*pvalue*/, + int /*nrects*/); + + void (* DestroyClip)( + GCPtr /*pGC*/); + + void (* CopyClip)( + GCPtr /*pgcDst*/, + GCPtr /*pgcSrc*/); + DevUnion devPrivate; +} GCFuncs; + +/* + * graphics operations invoked through a GC + */ + +typedef struct _GCOps { + void (* FillSpans)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*nInit*/, + DDXPointPtr /*pptInit*/, + int * /*pwidthInit*/, + int /*fSorted*/); + + void (* SetSpans)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + char * /*psrc*/, + DDXPointPtr /*ppt*/, + int * /*pwidth*/, + int /*nspans*/, + int /*fSorted*/); + + void (* PutImage)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*depth*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + int /*leftPad*/, + int /*format*/, + char * /*pBits*/); + + RegionPtr (* CopyArea)( + DrawablePtr /*pSrc*/, + DrawablePtr /*pDst*/, + GCPtr /*pGC*/, + int /*srcx*/, + int /*srcy*/, + int /*w*/, + int /*h*/, + int /*dstx*/, + int /*dsty*/); + + RegionPtr (* CopyPlane)( + DrawablePtr /*pSrcDrawable*/, + DrawablePtr /*pDstDrawable*/, + GCPtr /*pGC*/, + int /*srcx*/, + int /*srcy*/, + int /*width*/, + int /*height*/, + int /*dstx*/, + int /*dsty*/, + unsigned long /*bitPlane*/); + void (* PolyPoint)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*mode*/, + int /*npt*/, + DDXPointPtr /*pptInit*/); + + void (* Polylines)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*mode*/, + int /*npt*/, + DDXPointPtr /*pptInit*/); + + void (* PolySegment)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*nseg*/, + xSegment * /*pSegs*/); + + void (* PolyRectangle)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*nrects*/, + xRectangle * /*pRects*/); + + void (* PolyArc)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*narcs*/, + xArc * /*parcs*/); + + void (* FillPolygon)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*shape*/, + int /*mode*/, + int /*count*/, + DDXPointPtr /*pPts*/); + + void (* PolyFillRect)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*nrectFill*/, + xRectangle * /*prectInit*/); + + void (* PolyFillArc)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*narcs*/, + xArc * /*parcs*/); + + int (* PolyText8)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + char * /*chars*/); + + int (* PolyText16)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + unsigned short * /*chars*/); + + void (* ImageText8)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + char * /*chars*/); + + void (* ImageText16)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + unsigned short * /*chars*/); + + void (* ImageGlyphBlt)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + unsigned int /*nglyph*/, + CharInfoPtr * /*ppci*/, + pointer /*pglyphBase*/); + + void (* PolyGlyphBlt)( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + unsigned int /*nglyph*/, + CharInfoPtr * /*ppci*/, + pointer /*pglyphBase*/); + + void (* PushPixels)( + GCPtr /*pGC*/, + PixmapPtr /*pBitMap*/, + DrawablePtr /*pDst*/, + int /*w*/, + int /*h*/, + int /*x*/, + int /*y*/); + + DevUnion devPrivate; +} GCOps; + +/* there is padding in the bit fields because the Sun compiler doesn't + * force alignment to 32-bit boundaries. losers. + */ +typedef struct _GC { + ScreenPtr pScreen; + unsigned char depth; + unsigned char alu; + unsigned short lineWidth; + unsigned short dashOffset; + unsigned short numInDashList; + unsigned char *dash; + unsigned int lineStyle : 2; + unsigned int capStyle : 2; + unsigned int joinStyle : 2; + unsigned int fillStyle : 2; + unsigned int fillRule : 1; + unsigned int arcMode : 1; + unsigned int subWindowMode : 1; + unsigned int graphicsExposures : 1; + unsigned int clientClipType : 2; /* CT_<kind> */ + unsigned int miTranslate:1; /* should mi things translate? */ + unsigned int tileIsPixel:1; /* tile is solid pixel */ + unsigned int fExpose:1; /* Call exposure handling */ + unsigned int freeCompClip:1; /* Free composite clip */ + unsigned int unused:14; /* see comment above */ + unsigned long planemask; + unsigned long fgPixel; + unsigned long bgPixel; + /* + * alas -- both tile and stipple must be here as they + * are independently specifiable + */ + PixUnion tile; + PixmapPtr stipple; + DDXPointRec patOrg; /* origin for (tile, stipple) */ + struct _Font *font; + DDXPointRec clipOrg; + DDXPointRec lastWinOrg; /* position of window last validated */ + pointer clientClip; + unsigned long stateChanges; /* masked with GC_<kind> */ + unsigned long serialNumber; + GCFuncs *funcs; + GCOps *ops; + PrivateRec *devPrivates; + /* + * The following were moved here from private storage to allow device- + * independent access to them from screen wrappers. + * --- 1997.11.03 Marc Aurele La France (tsi@xfree86.org) + */ + PixmapPtr pRotatedPixmap; /* tile/stipple rotated for alignment */ + RegionPtr pCompositeClip; + /* fExpose & freeCompClip defined above */ +} GC; + +#endif /* GCSTRUCT_H */ diff --git a/xorg-server/include/misc.h b/xorg-server/include/misc.h index c7add253e..6cc29c024 100644 --- a/xorg-server/include/misc.h +++ b/xorg-server/include/misc.h @@ -1,298 +1,292 @@ -/*********************************************************** - -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. - -Copyright 1992, 1993 Data General Corporation; -Copyright 1992, 1993 OMRON Corporation - -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 -neither the name OMRON or DATA GENERAL be used in advertising or publicity -pertaining to distribution of the software without specific, written prior -permission of the party whose name is to be used. Neither OMRON or -DATA GENERAL make any representation about the suitability of this software -for any purpose. It is provided "as is" without express or implied warranty. - -OMRON AND DATA GENERAL EACH DISCLAIM ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, -IN NO EVENT SHALL OMRON OR DATA GENERAL 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 MISC_H -#define MISC_H 1 -/* - * X internal definitions - * - */ - -#include <X11/Xosdefs.h> -#include <X11/Xfuncproto.h> -#include <X11/Xmd.h> -#include <X11/X.h> -#include <X11/Xdefs.h> - -#include <stddef.h> - -#ifndef MAXSCREENS -#define MAXSCREENS 16 -#endif -#define MAXCLIENTS 256 -#define MAXEXTENSIONS 128 -#define MAXFORMATS 8 -#define MAXDEVICES 40 /* input devices */ - -#define EXTENSION_EVENT_BASE 64 -#define EXTENSION_BASE 128 - -typedef unsigned long PIXEL; -typedef unsigned long ATOM; - - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#ifdef __GNUC__ -#define X_DEPRECATED __attribute__((deprecated)) -#else -#define X_DEPRECATED -#endif - -#ifndef _XTYPEDEF_CALLBACKLISTPTR -typedef struct _CallbackList *CallbackListPtr; /* also in dix.h */ -#define _XTYPEDEF_CALLBACKLISTPTR -#endif - -typedef struct _xReq *xReqPtr; - -#include "os.h" /* for ALLOCATE_LOCAL and DEALLOCATE_LOCAL */ -#include <X11/Xfuncs.h> /* for bcopy, bzero, and bcmp */ - -#define NullBox ((BoxPtr)0) -#define MILLI_PER_MIN (1000 * 60) -#define MILLI_PER_SECOND (1000) - - /* this next is used with None and ParentRelative to tell - PaintWin() what to use to paint the background. Also used - in the macro IS_VALID_PIXMAP */ - -#define USE_BACKGROUND_PIXEL 3 -#define USE_BORDER_PIXEL 3 - - -/* byte swap a 32-bit literal */ -#define lswapl(x) ((((x) & 0xff) << 24) |\ - (((x) & 0xff00) << 8) |\ - (((x) & 0xff0000) >> 8) |\ - (((x) >> 24) & 0xff)) - -/* byte swap a short literal */ -#define lswaps(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff)) - -#undef min -#undef max - -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#define max(a, b) (((a) > (b)) ? (a) : (b)) -/* abs() is a function, not a macro; include the file declaring - * it in case we haven't done that yet. - */ -#include <stdlib.h> -#ifndef Fabs -#define Fabs(a) ((a) > 0.0 ? (a) : -(a)) /* floating absolute value */ -#endif -#define sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) -/* this assumes b > 0 */ -#define modulus(a, b, d) if (((d) = (a) % (b)) < 0) (d) += (b) -/* - * return the least significant bit in x which is set - * - * This works on 1's complement and 2's complement machines. - * If you care about the extra instruction on 2's complement - * machines, change to ((x) & (-(x))) - */ -#define lowbit(x) ((x) & (~(x) + 1)) - -/* XXX Not for modules */ -#include <limits.h> -#if !defined(MAXSHORT) || !defined(MINSHORT) || \ - !defined(MAXINT) || !defined(MININT) -/* - * Some implementations #define these through <math.h>, so preclude - * #include'ing it later. - */ - -#include <math.h> -#undef MAXSHORT -#define MAXSHORT SHRT_MAX -#undef MINSHORT -#define MINSHORT SHRT_MIN -#undef MAXINT -#define MAXINT INT_MAX -#undef MININT -#define MININT INT_MIN - -#include <assert.h> -#include <ctype.h> -#include <stdio.h> /* for fopen, etc... */ - -#endif - -/** - * Calculate the number of bytes needed to hold bits. - * @param bits The minimum number of bits needed. - * @return The number of bytes needed to hold bits. - */ -static inline int -bits_to_bytes(const int bits) { - return ((bits + 7) >> 3); -} -/** - * Calculate the number of 4-byte units needed to hold the given number of - * bytes. - * @param bytes The minimum number of bytes needed. - * @return The number of 4-byte units needed to hold bytes. - */ -static inline int -bytes_to_int32(const int bytes) { - return (((bytes) + 3) >> 2); -} - -/** - * Calculate the number of bytes (in multiples of 4) needed to hold bytes. - * @param bytes The minimum number of bytes needed. - * @return The closest multiple of 4 that is equal or higher than bytes. - */ -static inline int -pad_to_int32(const int bytes) { - return (((bytes) + 3) & ~3); -} - -extern char** -xstrtokenize(const char *str, const char* separators); - -/* some macros to help swap requests, replies, and events */ - -#define LengthRestB(stuff) \ - ((client->req_len << 2) - sizeof(*stuff)) - -#define LengthRestS(stuff) \ - ((client->req_len << 1) - (sizeof(*stuff) >> 1)) - -#define LengthRestL(stuff) \ - (client->req_len - (sizeof(*stuff) >> 2)) - -#define SwapRestS(stuff) \ - SwapShorts((short *)(stuff + 1), LengthRestS(stuff)) - -#define SwapRestL(stuff) \ - SwapLongs((CARD32 *)(stuff + 1), LengthRestL(stuff)) - -/* byte swap a 32-bit value */ -#define swapl(x, n) { \ - n = ((char *) (x))[0];\ - ((char *) (x))[0] = ((char *) (x))[3];\ - ((char *) (x))[3] = n;\ - n = ((char *) (x))[1];\ - ((char *) (x))[1] = ((char *) (x))[2];\ - ((char *) (x))[2] = n; } - -/* byte swap a short */ -#define swaps(x, n) { \ - n = ((char *) (x))[0];\ - ((char *) (x))[0] = ((char *) (x))[1];\ - ((char *) (x))[1] = n; } - -/* copy 32-bit value from src to dst byteswapping on the way */ -#define cpswapl(src, dst) { \ - ((char *)&(dst))[0] = ((char *) &(src))[3];\ - ((char *)&(dst))[1] = ((char *) &(src))[2];\ - ((char *)&(dst))[2] = ((char *) &(src))[1];\ - ((char *)&(dst))[3] = ((char *) &(src))[0]; } - -/* copy short from src to dst byteswapping on the way */ -#define cpswaps(src, dst) { \ - ((char *) &(dst))[0] = ((char *) &(src))[1];\ - ((char *) &(dst))[1] = ((char *) &(src))[0]; } - -extern _X_EXPORT void SwapLongs( - CARD32 *list, - unsigned long count); - -extern _X_EXPORT void SwapShorts( - short *list, - unsigned long count); - -extern _X_EXPORT void MakePredeclaredAtoms(void); - -extern _X_EXPORT int Ones( - unsigned long /*mask*/); - -typedef struct _xPoint *DDXPointPtr; -typedef struct pixman_box16 *BoxPtr; -typedef struct _xEvent *xEventPtr; -typedef struct _xRectangle *xRectanglePtr; -typedef struct _GrabRec *GrabPtr; - -/* typedefs from other places - duplicated here to minimize the amount - * of unnecessary junk that one would normally have to include to get - * these symbols defined - */ - -#ifndef _XTYPEDEF_CHARINFOPTR -typedef struct _CharInfo *CharInfoPtr; /* also in fonts/include/font.h */ -#define _XTYPEDEF_CHARINFOPTR -#endif - -extern _X_EXPORT unsigned long globalSerialNumber; -extern _X_EXPORT unsigned long serverGeneration; - -#endif /* MISC_H */ +/*********************************************************** + +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. + +Copyright 1992, 1993 Data General Corporation; +Copyright 1992, 1993 OMRON Corporation + +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 +neither the name OMRON or DATA GENERAL be used in advertising or publicity +pertaining to distribution of the software without specific, written prior +permission of the party whose name is to be used. Neither OMRON or +DATA GENERAL make any representation about the suitability of this software +for any purpose. It is provided "as is" without express or implied warranty. + +OMRON AND DATA GENERAL EACH DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL OMRON OR DATA GENERAL 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 MISC_H +#define MISC_H 1 +/* + * X internal definitions + * + */ + +#include <X11/Xosdefs.h> +#include <X11/Xfuncproto.h> +#include <X11/Xmd.h> +#include <X11/X.h> +#include <X11/Xdefs.h> + +#include <stddef.h> + +#ifndef MAXSCREENS +#define MAXSCREENS 16 +#endif +#define MAXCLIENTS 256 +#define MAXEXTENSIONS 128 +#define MAXFORMATS 8 +#define MAXDEVICES 40 /* input devices */ + +#define EXTENSION_EVENT_BASE 64 +#define EXTENSION_BASE 128 + +typedef unsigned long PIXEL; +typedef unsigned long ATOM; + + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifndef _XTYPEDEF_CALLBACKLISTPTR +typedef struct _CallbackList *CallbackListPtr; /* also in dix.h */ +#define _XTYPEDEF_CALLBACKLISTPTR +#endif + +typedef struct _xReq *xReqPtr; + +#include "os.h" /* for ALLOCATE_LOCAL and DEALLOCATE_LOCAL */ +#include <X11/Xfuncs.h> /* for bcopy, bzero, and bcmp */ + +#define NullBox ((BoxPtr)0) +#define MILLI_PER_MIN (1000 * 60) +#define MILLI_PER_SECOND (1000) + + /* this next is used with None and ParentRelative to tell + PaintWin() what to use to paint the background. Also used + in the macro IS_VALID_PIXMAP */ + +#define USE_BACKGROUND_PIXEL 3 +#define USE_BORDER_PIXEL 3 + + +/* byte swap a 32-bit literal */ +#define lswapl(x) ((((x) & 0xff) << 24) |\ + (((x) & 0xff00) << 8) |\ + (((x) & 0xff0000) >> 8) |\ + (((x) >> 24) & 0xff)) + +/* byte swap a short literal */ +#define lswaps(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff)) + +#undef min +#undef max + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) +/* abs() is a function, not a macro; include the file declaring + * it in case we haven't done that yet. + */ +#include <stdlib.h> +#ifndef Fabs +#define Fabs(a) ((a) > 0.0 ? (a) : -(a)) /* floating absolute value */ +#endif +#define sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) +/* this assumes b > 0 */ +#define modulus(a, b, d) if (((d) = (a) % (b)) < 0) (d) += (b) +/* + * return the least significant bit in x which is set + * + * This works on 1's complement and 2's complement machines. + * If you care about the extra instruction on 2's complement + * machines, change to ((x) & (-(x))) + */ +#define lowbit(x) ((x) & (~(x) + 1)) + +/* XXX Not for modules */ +#include <limits.h> +#if !defined(MAXSHORT) || !defined(MINSHORT) || \ + !defined(MAXINT) || !defined(MININT) +/* + * Some implementations #define these through <math.h>, so preclude + * #include'ing it later. + */ + +#include <math.h> +#undef MAXSHORT +#define MAXSHORT SHRT_MAX +#undef MINSHORT +#define MINSHORT SHRT_MIN +#undef MAXINT +#define MAXINT INT_MAX +#undef MININT +#define MININT INT_MIN + +#include <assert.h> +#include <ctype.h> +#include <stdio.h> /* for fopen, etc... */ + +#endif + +/** + * Calculate the number of bytes needed to hold bits. + * @param bits The minimum number of bits needed. + * @return The number of bytes needed to hold bits. + */ +static inline int +bits_to_bytes(const int bits) { + return ((bits + 7) >> 3); +} +/** + * Calculate the number of 4-byte units needed to hold the given number of + * bytes. + * @param bytes The minimum number of bytes needed. + * @return The number of 4-byte units needed to hold bytes. + */ +static inline int +bytes_to_int32(const int bytes) { + return (((bytes) + 3) >> 2); +} + +/** + * Calculate the number of bytes (in multiples of 4) needed to hold bytes. + * @param bytes The minimum number of bytes needed. + * @return The closest multiple of 4 that is equal or higher than bytes. + */ +static inline int +pad_to_int32(const int bytes) { + return (((bytes) + 3) & ~3); +} + +extern char** +xstrtokenize(const char *str, const char* separators); + +/* some macros to help swap requests, replies, and events */ + +#define LengthRestB(stuff) \ + ((client->req_len << 2) - sizeof(*stuff)) + +#define LengthRestS(stuff) \ + ((client->req_len << 1) - (sizeof(*stuff) >> 1)) + +#define LengthRestL(stuff) \ + (client->req_len - (sizeof(*stuff) >> 2)) + +#define SwapRestS(stuff) \ + SwapShorts((short *)(stuff + 1), LengthRestS(stuff)) + +#define SwapRestL(stuff) \ + SwapLongs((CARD32 *)(stuff + 1), LengthRestL(stuff)) + +/* byte swap a 32-bit value */ +#define swapl(x, n) { \ + n = ((char *) (x))[0];\ + ((char *) (x))[0] = ((char *) (x))[3];\ + ((char *) (x))[3] = n;\ + n = ((char *) (x))[1];\ + ((char *) (x))[1] = ((char *) (x))[2];\ + ((char *) (x))[2] = n; } + +/* byte swap a short */ +#define swaps(x, n) { \ + n = ((char *) (x))[0];\ + ((char *) (x))[0] = ((char *) (x))[1];\ + ((char *) (x))[1] = n; } + +/* copy 32-bit value from src to dst byteswapping on the way */ +#define cpswapl(src, dst) { \ + ((char *)&(dst))[0] = ((char *) &(src))[3];\ + ((char *)&(dst))[1] = ((char *) &(src))[2];\ + ((char *)&(dst))[2] = ((char *) &(src))[1];\ + ((char *)&(dst))[3] = ((char *) &(src))[0]; } + +/* copy short from src to dst byteswapping on the way */ +#define cpswaps(src, dst) { \ + ((char *) &(dst))[0] = ((char *) &(src))[1];\ + ((char *) &(dst))[1] = ((char *) &(src))[0]; } + +extern _X_EXPORT void SwapLongs( + CARD32 *list, + unsigned long count); + +extern _X_EXPORT void SwapShorts( + short *list, + unsigned long count); + +extern _X_EXPORT void MakePredeclaredAtoms(void); + +extern _X_EXPORT int Ones( + unsigned long /*mask*/); + +typedef struct _xPoint *DDXPointPtr; +typedef struct pixman_box16 *BoxPtr; +typedef struct _xEvent *xEventPtr; +typedef struct _xRectangle *xRectanglePtr; +typedef struct _GrabRec *GrabPtr; + +/* typedefs from other places - duplicated here to minimize the amount + * of unnecessary junk that one would normally have to include to get + * these symbols defined + */ + +#ifndef _XTYPEDEF_CHARINFOPTR +typedef struct _CharInfo *CharInfoPtr; /* also in fonts/include/font.h */ +#define _XTYPEDEF_CHARINFOPTR +#endif + +extern _X_EXPORT unsigned long globalSerialNumber; +extern _X_EXPORT unsigned long serverGeneration; + +#endif /* MISC_H */ diff --git a/xorg-server/include/os.h b/xorg-server/include/os.h index 06dacd326..5b9b05c4a 100644 --- a/xorg-server/include/os.h +++ b/xorg-server/include/os.h @@ -214,21 +214,58 @@ extern _X_EXPORT int set_font_authorizations( #ifndef _HAVE_XALLOC_DECLS #define _HAVE_XALLOC_DECLS -extern _X_EXPORT pointer Xalloc(unsigned long /*amount*/); -extern _X_EXPORT pointer Xcalloc(unsigned long /*amount*/); -extern _X_EXPORT pointer Xrealloc(pointer /*ptr*/, unsigned long /*amount*/); -extern _X_EXPORT void Xfree(pointer /*ptr*/); + +/* + * Use malloc(3) instead. + */ +extern _X_EXPORT void *Xalloc(unsigned long /*amount*/) _X_DEPRECATED; +/* + * Use calloc(3) instead + */ +extern _X_EXPORT void *Xcalloc(unsigned long /*amount*/) _X_DEPRECATED; +/* + * Use realloc(3) instead + */ +extern _X_EXPORT void *Xrealloc(void * /*ptr*/, unsigned long /*amount*/) + _X_DEPRECATED; +/* + * Use free(3) instead + */ +extern _X_EXPORT void Xfree(void * /*ptr*/) _X_DEPRECATED; + #endif -extern _X_EXPORT pointer XNFalloc(unsigned long /*amount*/); -extern _X_EXPORT pointer XNFcalloc(unsigned long /*amount*/); -extern _X_EXPORT pointer XNFrealloc(pointer /*ptr*/, unsigned long /*amount*/); +/* + * This function malloc(3)s buffer, terminating the server if there is not + * enough memory. + */ +extern _X_EXPORT void *XNFalloc(unsigned long /*amount*/); +/* + * This function calloc(3)s buffer, terminating the server if there is not + * enough memory. + */ +extern _X_EXPORT void *XNFcalloc(unsigned long /*amount*/); +/* + * This function realloc(3)s passed buffer, terminating the server if there is + * not enough memory. + */ +extern _X_EXPORT void *XNFrealloc(void * /*ptr*/, unsigned long /*amount*/); +/* + * This function strdup(3)s passed string. The only difference from the library + * function that it is safe to pass NULL, as NULL will be returned. + */ extern _X_EXPORT char *Xstrdup(const char *s); + +/* + * This function strdup(3)s passed string, terminating the server if there is + * not enough memory. If NULL is passed to this function, NULL is returned. + */ extern _X_EXPORT char *XNFstrdup(const char *s); -extern _X_EXPORT char *Xprintf(const char *fmt, ...); + +extern _X_EXPORT char *Xprintf(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2); extern _X_EXPORT char *Xvprintf(const char *fmt, va_list va); -extern _X_EXPORT char *XNFprintf(const char *fmt, ...); +extern _X_EXPORT char *XNFprintf(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2); extern _X_EXPORT char *XNFvprintf(const char *fmt, va_list va); typedef void (*OsSigHandlerPtr)(int /* sig */); @@ -262,7 +299,7 @@ extern _X_EXPORT void OsBlockSignals (void); extern _X_EXPORT void OsReleaseSignals (void); -extern _X_EXPORT void OsAbort (void); +extern _X_EXPORT void OsAbort (void) _X_NORETURN; #if !defined(WIN32) extern _X_EXPORT int System(char *); @@ -488,32 +525,21 @@ typedef enum { X_UNKNOWN = -1 /* unknown -- this must always be last */ } MessageType; -/* XXX Need to check which GCC versions have the format(printf) attribute. */ -#if defined(__GNUC__) && (__GNUC__ > 2) -#define _printf_attribute(a,b) __attribute((format(__printf__,a,b))) -#else -#define _printf_attribute(a,b) /**/ -#endif - extern _X_EXPORT const char *LogInit(const char *fname, const char *backup); extern _X_EXPORT void LogClose(void); extern _X_EXPORT Bool LogSetParameter(LogParameter param, int value); extern _X_EXPORT void LogVWrite(int verb, const char *f, va_list args); -extern _X_EXPORT void LogWrite(int verb, const char *f, ...) _printf_attribute(2,3); +extern _X_EXPORT void LogWrite(int verb, const char *f, ...) _X_ATTRIBUTE_PRINTF(2,3); extern _X_EXPORT void LogVMessageVerb(MessageType type, int verb, const char *format, va_list args); extern _X_EXPORT void LogMessageVerb(MessageType type, int verb, const char *format, - ...) _printf_attribute(3,4); + ...) _X_ATTRIBUTE_PRINTF(3,4); extern _X_EXPORT void LogMessage(MessageType type, const char *format, ...) - _printf_attribute(2,3); + _X_ATTRIBUTE_PRINTF(2,3); extern _X_EXPORT void FreeAuditTimer(void); -extern _X_EXPORT void AuditF(const char *f, ...) _printf_attribute(1,2); +extern _X_EXPORT void AuditF(const char *f, ...) _X_ATTRIBUTE_PRINTF(1,2); extern _X_EXPORT void VAuditF(const char *f, va_list args); -extern _X_EXPORT void FatalError(const char *f, ...) _printf_attribute(1,2) -#if defined(__GNUC__) && (__GNUC__ > 2) -__attribute((noreturn)) -#endif -; +extern _X_EXPORT void FatalError(const char *f, ...) _X_ATTRIBUTE_PRINTF(1,2) _X_NORETURN; #ifdef DEBUG #define DebugF ErrorF @@ -522,7 +548,7 @@ __attribute((noreturn)) #endif extern _X_EXPORT void VErrorF(const char *f, va_list args); -extern _X_EXPORT void ErrorF(const char *f, ...) _printf_attribute(1,2); +extern _X_EXPORT void ErrorF(const char *f, ...) _X_ATTRIBUTE_PRINTF(1,2); extern _X_EXPORT void Error(char *str); extern _X_EXPORT void LogPrintMarkers(void); diff --git a/xorg-server/include/privates.h b/xorg-server/include/privates.h index e6f788de1..cbb08887f 100644 --- a/xorg-server/include/privates.h +++ b/xorg-server/include/privates.h @@ -1,162 +1,136 @@ -/*********************************************************** - -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 -AUTHOR 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 PRIVATES_H -#define PRIVATES_H 1 - -#include "dix.h" -#include "resource.h" - -/***************************************************************** - * STUFF FOR PRIVATES - *****************************************************************/ - -typedef int *DevPrivateKey; -struct _Private; -typedef struct _Private PrivateRec; - -/* - * Request pre-allocated private space for your driver/module. This function - * increases the amount of space allocated automatically when dixLookupPrivate - * is called on a PrivateRec that does not yet have a value associated with - * 'key'. - * - * This function will only increase the reserved size: if a size was previously - * requested, then dixRequestPrivate causes later calls to dixLookupPrivate to - * allocate the maximum of the old size and 'size'. Requested sizes are reset - * to 0 by dixResetPrivates, which is called before each server generation. - * - * If dixRequestPrivate is not called with a nonzero size for 'key', then the - * module responsible for 'key' must manage the associated pointer itself with - * dixSetPrivate. - * - * dixRequestPrivate returns FALSE if it cannot store the requested size. - */ -extern _X_EXPORT int -dixRequestPrivate(const DevPrivateKey key, unsigned size); - -/* - * Allocates space for an association of 'key' with a value in 'privates'. - * - * If a nonzero size was requested with dixRequestPrivate, then - * dixAllocatePrivate also allocates the requested amount of memory and - * associates the pointer to that memory with 'key' in 'privates'. The - * allocated memory is initialized to zero. This memory can only be freed by - * dixFreePrivates. - * - * If dixRequestPrivate was never called with a nonzero size, then - * dixAllocatePrivate associates NULL with 'key' in 'privates'. - * - * dixAllocatePrivate returns a pointer to the value associated with 'key' in - * 'privates', unless a memory allocation fails, in which case it returns NULL. - */ -extern _X_EXPORT pointer * -dixAllocatePrivate(PrivateRec **privates, const DevPrivateKey key); - -/* - * Look up a private pointer. - * - * If no value is currently associated with 'key' in 'privates', then - * dixLookupPrivate calls dixAllocatePrivate and returns the resulting - * associated value. - * - * dixLookupPrivate returns NULL if a memory allocation fails. - */ -extern _X_EXPORT pointer -dixLookupPrivate(PrivateRec **privates, const DevPrivateKey key); - -/* - * Look up the address of a private pointer. If 'key' is not associated with a - * value in 'privates', then dixLookupPrivateAddr calls dixAllocatePrivate and - * returns a pointer to the resulting associated value. - * - * dixLookupPrivateAddr returns NULL if 'key' was not previously associated in - * 'privates' and a memory allocation fails. - */ -extern _X_EXPORT pointer * -dixLookupPrivateAddr(PrivateRec **privates, const DevPrivateKey key); - -/* - * Associate 'val' with 'key' in 'privates' so that later calls to - * dixLookupPrivate(privates, key) will return 'val'. - * - * dixSetPrivate returns FALSE if a memory allocation fails. - */ -extern _X_EXPORT int -dixSetPrivate(PrivateRec **privates, const DevPrivateKey key, pointer val); - -/* - * Register callbacks to be called on private allocation/freeing. - * The calldata argument to the callbacks is a PrivateCallbackPtr. - */ -typedef struct _PrivateCallback { - DevPrivateKey key; /* private registration key */ - pointer *value; /* address of private pointer */ -} PrivateCallbackRec; - -/* - * Register a function to be called when dixAllocPrivate successfully associates - * 'key' with a new PrivateRec. - */ -extern _X_EXPORT int -dixRegisterPrivateInitFunc(const DevPrivateKey key, - CallbackProcPtr callback, pointer userdata); - -/* - * Register a function to be called when dixFreePrivates unassociates 'key' with - * a PrivateRec. - */ -extern _X_EXPORT int -dixRegisterPrivateDeleteFunc(const DevPrivateKey key, - CallbackProcPtr callback, pointer userdata); - -/* - * Unassociates all keys from 'privates', calls the callbacks registered with - * dixRegisterPrivateDeleteFunc, and frees all private data automatically - * allocated via dixRequestPrivate. - */ -extern _X_EXPORT void -dixFreePrivates(PrivateRec *privates); - -/* - * Resets the privates subsystem. dixResetPrivates is called from the main loop - * before each server generation. This function must only be called by main(). - */ -extern _X_EXPORT int -dixResetPrivates(void); - -/* - * These next two functions are necessary because the position of - * the devPrivates field varies by structure and calling code might - * only know the resource type, not the structure definition. - */ - -/* - * Looks up the offset where the devPrivates field is located. - * Returns -1 if no offset has been registered for the resource type. - */ -extern _X_EXPORT int -dixLookupPrivateOffset(RESTYPE type); - -/* - * Specifies the offset where the devPrivates field is located. - * A negative value indicates no devPrivates field is available. - */ -extern _X_EXPORT int -dixRegisterPrivateOffset(RESTYPE type, int offset); - -/* - * Convenience macro for adding an offset to an object pointer - * when making a call to one of the devPrivates functions - */ -#define DEVPRIV_AT(ptr, offset) ((PrivateRec **)((char *)ptr + offset)) - -#endif /* PRIVATES_H */ +/*********************************************************** + +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 +AUTHOR 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 PRIVATES_H +#define PRIVATES_H 1 + +#include "dix.h" +#include "resource.h" + +/***************************************************************** + * STUFF FOR PRIVATES + *****************************************************************/ + +typedef int *DevPrivateKey; +struct _Private; +typedef struct _Private PrivateRec; + +/* + * Request pre-allocated private space for your driver/module. This function + * increases the amount of space allocated automatically when dixLookupPrivate + * is called on a PrivateRec that does not yet have a value associated with + * 'key'. + * + * This function will only increase the reserved size: if a size was previously + * requested, then dixRequestPrivate causes later calls to dixLookupPrivate to + * allocate the maximum of the old size and 'size'. Requested sizes are reset + * to 0 by dixResetPrivates, which is called before each server generation. + * + * If dixRequestPrivate is not called with a nonzero size for 'key', then the + * module responsible for 'key' must manage the associated pointer itself with + * dixSetPrivate. + * + * dixRequestPrivate returns FALSE if it cannot store the requested size. + */ +extern _X_EXPORT int +dixRequestPrivate(const DevPrivateKey key, unsigned size); + +/* + * Allocates space for an association of 'key' with a value in 'privates'. + * + * If a nonzero size was requested with dixRequestPrivate, then + * dixAllocatePrivate also allocates the requested amount of memory and + * associates the pointer to that memory with 'key' in 'privates'. The + * allocated memory is initialized to zero. This memory can only be freed by + * dixFreePrivates. + * + * If dixRequestPrivate was never called with a nonzero size, then + * dixAllocatePrivate associates NULL with 'key' in 'privates'. + * + * dixAllocatePrivate returns a pointer to the value associated with 'key' in + * 'privates', unless a memory allocation fails, in which case it returns NULL. + */ +extern _X_EXPORT pointer * +dixAllocatePrivate(PrivateRec **privates, const DevPrivateKey key); + +/* + * Look up a private pointer. + * + * If no value is currently associated with 'key' in 'privates', then + * dixLookupPrivate calls dixAllocatePrivate and returns the resulting + * associated value. + * + * dixLookupPrivate returns NULL if a memory allocation fails. + */ +extern _X_EXPORT pointer +dixLookupPrivate(PrivateRec **privates, const DevPrivateKey key); + +/* + * Look up the address of a private pointer. If 'key' is not associated with a + * value in 'privates', then dixLookupPrivateAddr calls dixAllocatePrivate and + * returns a pointer to the resulting associated value. + * + * dixLookupPrivateAddr returns NULL if 'key' was not previously associated in + * 'privates' and a memory allocation fails. + */ +extern _X_EXPORT pointer * +dixLookupPrivateAddr(PrivateRec **privates, const DevPrivateKey key); + +/* + * Associate 'val' with 'key' in 'privates' so that later calls to + * dixLookupPrivate(privates, key) will return 'val'. + * + * dixSetPrivate returns FALSE if a memory allocation fails. + */ +extern _X_EXPORT int +dixSetPrivate(PrivateRec **privates, const DevPrivateKey key, pointer val); + +/* + * Unassociates all keys from 'privates' and frees all private data automatically + * allocated via dixRequestPrivate. + */ +extern _X_EXPORT void +dixFreePrivates(PrivateRec *privates); + +/* + * Resets the privates subsystem. dixResetPrivates is called from the main loop + * before each server generation. This function must only be called by main(). + */ +extern _X_EXPORT int +dixResetPrivates(void); + +/* + * These next two functions are necessary because the position of + * the devPrivates field varies by structure and calling code might + * only know the resource type, not the structure definition. + */ + +/* + * Looks up the offset where the devPrivates field is located. + * Returns -1 if no offset has been registered for the resource type. + */ +extern _X_EXPORT int +dixLookupPrivateOffset(RESTYPE type); + +/* + * Specifies the offset where the devPrivates field is located. + * A negative value indicates no devPrivates field is available. + */ +extern _X_EXPORT int +dixRegisterPrivateOffset(RESTYPE type, int offset); + +/* + * Convenience macro for adding an offset to an object pointer + * when making a call to one of the devPrivates functions + */ +#define DEVPRIV_AT(ptr, offset) ((PrivateRec **)((char *)ptr + offset)) + +#endif /* PRIVATES_H */ diff --git a/xorg-server/include/regionstr.h b/xorg-server/include/regionstr.h index eead1a1f2..d67873295 100644 --- a/xorg-server/include/regionstr.h +++ b/xorg-server/include/regionstr.h @@ -1,293 +1,293 @@ -/*********************************************************** - -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. - -******************************************************************/ - -#ifndef REGIONSTRUCT_H -#define REGIONSTRUCT_H - -typedef struct pixman_region16 RegionRec, *RegionPtr; - -#include "miscstruct.h" - -/* Return values from RectIn() */ - -#define rgnOUT 0 -#define rgnIN 1 -#define rgnPART 2 - -#define NullRegion ((RegionPtr)0) - -/* - * clip region - */ - -typedef struct pixman_region16_data RegDataRec, *RegDataPtr; - -extern _X_EXPORT BoxRec miEmptyBox; -extern _X_EXPORT RegDataRec miEmptyData; -extern _X_EXPORT RegDataRec miBrokenData; - -#define REGION_NIL(reg) ((reg)->data && !(reg)->data->numRects) -/* not a region */ -#define REGION_NAR(reg) ((reg)->data == &miBrokenData) -#define REGION_NUM_RECTS(reg) ((reg)->data ? (reg)->data->numRects : 1) -#define REGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0) -#define REGION_RECTS(reg) ((reg)->data ? (BoxPtr)((reg)->data + 1) \ - : &(reg)->extents) -#define REGION_BOXPTR(reg) ((BoxPtr)((reg)->data + 1)) -#define REGION_BOX(reg,i) (®ION_BOXPTR(reg)[i]) -#define REGION_TOP(reg) REGION_BOX(reg, (reg)->data->numRects) -#define REGION_END(reg) REGION_BOX(reg, (reg)->data->numRects - 1) -#define REGION_SZOF(n) (sizeof(RegDataRec) + ((n) * sizeof(BoxRec))) - -#define REGION_CREATE(_pScreen, _rect, _size) \ - miRegionCreate(_rect, _size) - -#define REGION_COPY(_pScreen, dst, src) \ - miRegionCopy(dst, src) - -#define REGION_DESTROY(_pScreen, _pReg) \ - miRegionDestroy(_pReg) - -#define REGION_INTERSECT(_pScreen, newReg, reg1, reg2) \ - miIntersect(newReg, reg1, reg2) - -#define REGION_UNION(_pScreen, newReg, reg1, reg2) \ - miUnion(newReg, reg1, reg2) - -#define REGION_SUBTRACT(_pScreen, newReg, reg1, reg2) \ - miSubtract(newReg, reg1, reg2) - -#define REGION_INVERSE(_pScreen, newReg, reg1, invRect) \ - miInverse(newReg, reg1, invRect) - -#define REGION_TRANSLATE(_pScreen, _pReg, _x, _y) \ - miTranslateRegion(_pReg, _x, _y) - -#define RECT_IN_REGION(_pScreen, _pReg, prect) \ - miRectIn(_pReg, prect) - -#define POINT_IN_REGION(_pScreen, _pReg, _x, _y, prect) \ - miPointInRegion(_pReg, _x, _y, prect) - -#define REGION_APPEND(_pScreen, dstrgn, rgn) \ - miRegionAppend(dstrgn, rgn) - -#define REGION_VALIDATE(_pScreen, badreg, pOverlap) \ - miRegionValidate(badreg, pOverlap) - -#define BITMAP_TO_REGION(_pScreen, pPix) \ - (*(_pScreen)->BitmapToRegion)(pPix) /* no mi version?! */ - -#define RECTS_TO_REGION(_pScreen, nrects, prect, ctype) \ - miRectsToRegion(nrects, prect, ctype) - -#define REGION_EQUAL(_pScreen, _pReg1, _pReg2) \ - miRegionEqual(_pReg1, _pReg2) - -#define REGION_BREAK(_pScreen, _pReg) \ - miRegionBreak(_pReg) - -#define REGION_INIT(_pScreen, _pReg, _rect, _size) \ -{ \ - if ((_rect) != NULL) \ - { \ - (_pReg)->extents = *(_rect); \ - (_pReg)->data = (RegDataPtr)NULL; \ - } \ - else \ - { \ - (_pReg)->extents = miEmptyBox; \ - if (((_size) > 1) && ((_pReg)->data = \ - (RegDataPtr)xalloc(REGION_SZOF(_size)))) \ - { \ - (_pReg)->data->size = (_size); \ - (_pReg)->data->numRects = 0; \ - } \ - else \ - (_pReg)->data = &miEmptyData; \ - } \ - } - - -#define REGION_UNINIT(_pScreen, _pReg) \ -{ \ - if ((_pReg)->data && (_pReg)->data->size) { \ - xfree((_pReg)->data); \ - (_pReg)->data = NULL; \ - } \ -} - -#define REGION_RESET(_pScreen, _pReg, _pBox) \ -{ \ - (_pReg)->extents = *(_pBox); \ - REGION_UNINIT(_pScreen, _pReg); \ - (_pReg)->data = (RegDataPtr)NULL; \ -} - -#define REGION_NOTEMPTY(_pScreen, _pReg) \ - !REGION_NIL(_pReg) - -#define REGION_BROKEN(_pScreen, _pReg) \ - REGION_NAR(_pReg) - -#define REGION_EMPTY(_pScreen, _pReg) \ -{ \ - REGION_UNINIT(_pScreen, _pReg); \ - (_pReg)->extents.x2 = (_pReg)->extents.x1; \ - (_pReg)->extents.y2 = (_pReg)->extents.y1; \ - (_pReg)->data = &miEmptyData; \ -} - -#define REGION_EXTENTS(_pScreen, _pReg) \ - (&(_pReg)->extents) - -#define REGION_NULL(_pScreen, _pReg) \ -{ \ - (_pReg)->extents = miEmptyBox; \ - (_pReg)->data = &miEmptyData; \ -} - -#ifndef REGION_NULL -#define REGION_NULL(_pScreen, _pReg) \ - REGION_INIT(_pScreen, _pReg, NullBox, 1) -#endif - -/* moved from mi.h */ - -extern _X_EXPORT void InitRegions (void); - -extern _X_EXPORT RegionPtr miRegionCreate( - BoxPtr /*rect*/, - int /*size*/); - -extern _X_EXPORT void miRegionInit( - RegionPtr /*pReg*/, - BoxPtr /*rect*/, - int /*size*/); - -extern _X_EXPORT void miRegionDestroy( - RegionPtr /*pReg*/); - -extern _X_EXPORT void miRegionUninit( - RegionPtr /*pReg*/); - -extern _X_EXPORT Bool miRegionCopy( - RegionPtr /*dst*/, - RegionPtr /*src*/); - -extern _X_EXPORT Bool miIntersect( - RegionPtr /*newReg*/, - RegionPtr /*reg1*/, - RegionPtr /*reg2*/); - -extern _X_EXPORT Bool miUnion( - RegionPtr /*newReg*/, - RegionPtr /*reg1*/, - RegionPtr /*reg2*/); - -extern _X_EXPORT Bool miRegionAppend( - RegionPtr /*dstrgn*/, - RegionPtr /*rgn*/); - -extern _X_EXPORT Bool miRegionValidate( - RegionPtr /*badreg*/, - Bool * /*pOverlap*/); - -extern _X_EXPORT RegionPtr miRectsToRegion( - int /*nrects*/, - xRectanglePtr /*prect*/, - int /*ctype*/); - -extern _X_EXPORT Bool miSubtract( - RegionPtr /*regD*/, - RegionPtr /*regM*/, - RegionPtr /*regS*/); - -extern _X_EXPORT Bool miInverse( - RegionPtr /*newReg*/, - RegionPtr /*reg1*/, - BoxPtr /*invRect*/); - -extern _X_EXPORT int miRectIn( - RegionPtr /*region*/, - BoxPtr /*prect*/); - -extern _X_EXPORT void miTranslateRegion( - RegionPtr /*pReg*/, - int /*x*/, - int /*y*/); - -extern _X_EXPORT void miRegionReset( - RegionPtr /*pReg*/, - BoxPtr /*pBox*/); - -extern _X_EXPORT Bool miRegionBreak( - RegionPtr /*pReg*/); - -extern _X_EXPORT Bool miPointInRegion( - RegionPtr /*pReg*/, - int /*x*/, - int /*y*/, - BoxPtr /*box*/); - -extern _X_EXPORT Bool miRegionEqual( - RegionPtr /*pReg1*/, - RegionPtr /*pReg2*/); - -extern _X_EXPORT Bool miRegionNotEmpty( - RegionPtr /*pReg*/); - -extern _X_EXPORT void miRegionEmpty( - RegionPtr /*pReg*/); - -extern _X_EXPORT BoxPtr miRegionExtents( - RegionPtr /*pReg*/); - -extern _X_EXPORT void miPrintRegion( - RegionPtr /*pReg*/); - -#endif /* REGIONSTRUCT_H */ +/*********************************************************** + +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. + +******************************************************************/ + +#ifndef REGIONSTRUCT_H +#define REGIONSTRUCT_H + +typedef struct pixman_region16 RegionRec, *RegionPtr; + +#include "miscstruct.h" + +/* Return values from RectIn() */ + +#define rgnOUT 0 +#define rgnIN 1 +#define rgnPART 2 + +#define NullRegion ((RegionPtr)0) + +/* + * clip region + */ + +typedef struct pixman_region16_data RegDataRec, *RegDataPtr; + +extern _X_EXPORT BoxRec miEmptyBox; +extern _X_EXPORT RegDataRec miEmptyData; +extern _X_EXPORT RegDataRec miBrokenData; + +#define REGION_NIL(reg) ((reg)->data && !(reg)->data->numRects) +/* not a region */ +#define REGION_NAR(reg) ((reg)->data == &miBrokenData) +#define REGION_NUM_RECTS(reg) ((reg)->data ? (reg)->data->numRects : 1) +#define REGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0) +#define REGION_RECTS(reg) ((reg)->data ? (BoxPtr)((reg)->data + 1) \ + : &(reg)->extents) +#define REGION_BOXPTR(reg) ((BoxPtr)((reg)->data + 1)) +#define REGION_BOX(reg,i) (®ION_BOXPTR(reg)[i]) +#define REGION_TOP(reg) REGION_BOX(reg, (reg)->data->numRects) +#define REGION_END(reg) REGION_BOX(reg, (reg)->data->numRects - 1) +#define REGION_SZOF(n) (sizeof(RegDataRec) + ((n) * sizeof(BoxRec))) + +#define REGION_CREATE(_pScreen, _rect, _size) \ + miRegionCreate(_rect, _size) + +#define REGION_COPY(_pScreen, dst, src) \ + miRegionCopy(dst, src) + +#define REGION_DESTROY(_pScreen, _pReg) \ + miRegionDestroy(_pReg) + +#define REGION_INTERSECT(_pScreen, newReg, reg1, reg2) \ + miIntersect(newReg, reg1, reg2) + +#define REGION_UNION(_pScreen, newReg, reg1, reg2) \ + miUnion(newReg, reg1, reg2) + +#define REGION_SUBTRACT(_pScreen, newReg, reg1, reg2) \ + miSubtract(newReg, reg1, reg2) + +#define REGION_INVERSE(_pScreen, newReg, reg1, invRect) \ + miInverse(newReg, reg1, invRect) + +#define REGION_TRANSLATE(_pScreen, _pReg, _x, _y) \ + miTranslateRegion(_pReg, _x, _y) + +#define RECT_IN_REGION(_pScreen, _pReg, prect) \ + miRectIn(_pReg, prect) + +#define POINT_IN_REGION(_pScreen, _pReg, _x, _y, prect) \ + miPointInRegion(_pReg, _x, _y, prect) + +#define REGION_APPEND(_pScreen, dstrgn, rgn) \ + miRegionAppend(dstrgn, rgn) + +#define REGION_VALIDATE(_pScreen, badreg, pOverlap) \ + miRegionValidate(badreg, pOverlap) + +#define BITMAP_TO_REGION(_pScreen, pPix) \ + (*(_pScreen)->BitmapToRegion)(pPix) /* no mi version?! */ + +#define RECTS_TO_REGION(_pScreen, nrects, prect, ctype) \ + miRectsToRegion(nrects, prect, ctype) + +#define REGION_EQUAL(_pScreen, _pReg1, _pReg2) \ + miRegionEqual(_pReg1, _pReg2) + +#define REGION_BREAK(_pScreen, _pReg) \ + miRegionBreak(_pReg) + +#define REGION_INIT(_pScreen, _pReg, _rect, _size) \ +{ \ + if ((_rect) != NULL) \ + { \ + (_pReg)->extents = *(_rect); \ + (_pReg)->data = (RegDataPtr)NULL; \ + } \ + else \ + { \ + (_pReg)->extents = miEmptyBox; \ + if (((_size) > 1) && ((_pReg)->data = \ + (RegDataPtr)malloc(REGION_SZOF(_size)))) \ + { \ + (_pReg)->data->size = (_size); \ + (_pReg)->data->numRects = 0; \ + } \ + else \ + (_pReg)->data = &miEmptyData; \ + } \ + } + + +#define REGION_UNINIT(_pScreen, _pReg) \ +{ \ + if ((_pReg)->data && (_pReg)->data->size) { \ + free((_pReg)->data); \ + (_pReg)->data = NULL; \ + } \ +} + +#define REGION_RESET(_pScreen, _pReg, _pBox) \ +{ \ + (_pReg)->extents = *(_pBox); \ + REGION_UNINIT(_pScreen, _pReg); \ + (_pReg)->data = (RegDataPtr)NULL; \ +} + +#define REGION_NOTEMPTY(_pScreen, _pReg) \ + !REGION_NIL(_pReg) + +#define REGION_BROKEN(_pScreen, _pReg) \ + REGION_NAR(_pReg) + +#define REGION_EMPTY(_pScreen, _pReg) \ +{ \ + REGION_UNINIT(_pScreen, _pReg); \ + (_pReg)->extents.x2 = (_pReg)->extents.x1; \ + (_pReg)->extents.y2 = (_pReg)->extents.y1; \ + (_pReg)->data = &miEmptyData; \ +} + +#define REGION_EXTENTS(_pScreen, _pReg) \ + (&(_pReg)->extents) + +#define REGION_NULL(_pScreen, _pReg) \ +{ \ + (_pReg)->extents = miEmptyBox; \ + (_pReg)->data = &miEmptyData; \ +} + +#ifndef REGION_NULL +#define REGION_NULL(_pScreen, _pReg) \ + REGION_INIT(_pScreen, _pReg, NullBox, 1) +#endif + +/* moved from mi.h */ + +extern _X_EXPORT void InitRegions (void); + +extern _X_EXPORT RegionPtr miRegionCreate( + BoxPtr /*rect*/, + int /*size*/); + +extern _X_EXPORT void miRegionInit( + RegionPtr /*pReg*/, + BoxPtr /*rect*/, + int /*size*/); + +extern _X_EXPORT void miRegionDestroy( + RegionPtr /*pReg*/); + +extern _X_EXPORT void miRegionUninit( + RegionPtr /*pReg*/); + +extern _X_EXPORT Bool miRegionCopy( + RegionPtr /*dst*/, + RegionPtr /*src*/); + +extern _X_EXPORT Bool miIntersect( + RegionPtr /*newReg*/, + RegionPtr /*reg1*/, + RegionPtr /*reg2*/); + +extern _X_EXPORT Bool miUnion( + RegionPtr /*newReg*/, + RegionPtr /*reg1*/, + RegionPtr /*reg2*/); + +extern _X_EXPORT Bool miRegionAppend( + RegionPtr /*dstrgn*/, + RegionPtr /*rgn*/); + +extern _X_EXPORT Bool miRegionValidate( + RegionPtr /*badreg*/, + Bool * /*pOverlap*/); + +extern _X_EXPORT RegionPtr miRectsToRegion( + int /*nrects*/, + xRectanglePtr /*prect*/, + int /*ctype*/); + +extern _X_EXPORT Bool miSubtract( + RegionPtr /*regD*/, + RegionPtr /*regM*/, + RegionPtr /*regS*/); + +extern _X_EXPORT Bool miInverse( + RegionPtr /*newReg*/, + RegionPtr /*reg1*/, + BoxPtr /*invRect*/); + +extern _X_EXPORT int miRectIn( + RegionPtr /*region*/, + BoxPtr /*prect*/); + +extern _X_EXPORT void miTranslateRegion( + RegionPtr /*pReg*/, + int /*x*/, + int /*y*/); + +extern _X_EXPORT void miRegionReset( + RegionPtr /*pReg*/, + BoxPtr /*pBox*/); + +extern _X_EXPORT Bool miRegionBreak( + RegionPtr /*pReg*/); + +extern _X_EXPORT Bool miPointInRegion( + RegionPtr /*pReg*/, + int /*x*/, + int /*y*/, + BoxPtr /*box*/); + +extern _X_EXPORT Bool miRegionEqual( + RegionPtr /*pReg1*/, + RegionPtr /*pReg2*/); + +extern _X_EXPORT Bool miRegionNotEmpty( + RegionPtr /*pReg*/); + +extern _X_EXPORT void miRegionEmpty( + RegionPtr /*pReg*/); + +extern _X_EXPORT BoxPtr miRegionExtents( + RegionPtr /*pReg*/); + +extern _X_EXPORT void miPrintRegion( + RegionPtr /*pReg*/); + +#endif /* REGIONSTRUCT_H */ diff --git a/xorg-server/include/resource.h b/xorg-server/include/resource.h index 56450d67a..d2a8422b4 100644 --- a/xorg-server/include/resource.h +++ b/xorg-server/include/resource.h @@ -1,279 +1,279 @@ -/*********************************************************** - -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. - -******************************************************************/ - -#ifndef RESOURCE_H -#define RESOURCE_H 1 -#include "misc.h" -#include "dixaccess.h" - -/***************************************************************** - * STUFF FOR RESOURCES - *****************************************************************/ - -/* classes for Resource routines */ - -typedef unsigned long RESTYPE; - -#define RC_VANILLA ((RESTYPE)0) -#define RC_CACHED ((RESTYPE)1<<31) -#define RC_DRAWABLE ((RESTYPE)1<<30) -/* Use class RC_NEVERRETAIN for resources that should not be retained - * regardless of the close down mode when the client dies. (A client's - * event selections on objects that it doesn't own are good candidates.) - * Extensions can use this too! - */ -#define RC_NEVERRETAIN ((RESTYPE)1<<29) -#define RC_LASTPREDEF RC_NEVERRETAIN -#define RC_ANY (~(RESTYPE)0) - -/* types for Resource routines */ - -#define RT_WINDOW ((RESTYPE)1|RC_DRAWABLE) -#define RT_PIXMAP ((RESTYPE)2|RC_DRAWABLE) -#define RT_GC ((RESTYPE)3) -#undef RT_FONT -#undef RT_CURSOR -#define RT_FONT ((RESTYPE)4) -#define RT_CURSOR ((RESTYPE)5) -#define RT_COLORMAP ((RESTYPE)6) -#define RT_CMAPENTRY ((RESTYPE)7) -#define RT_OTHERCLIENT ((RESTYPE)8|RC_NEVERRETAIN) -#define RT_PASSIVEGRAB ((RESTYPE)9|RC_NEVERRETAIN) -#define RT_LASTPREDEF ((RESTYPE)9) -#define RT_NONE ((RESTYPE)0) - -/* bits and fields within a resource id */ -#define RESOURCE_AND_CLIENT_COUNT 29 /* 29 bits for XIDs */ -#if MAXCLIENTS == 64 -#define RESOURCE_CLIENT_BITS 6 -#endif -#if MAXCLIENTS == 128 -#define RESOURCE_CLIENT_BITS 7 -#endif -#if MAXCLIENTS == 256 -#define RESOURCE_CLIENT_BITS 8 -#endif -#if MAXCLIENTS == 512 -#define RESOURCE_CLIENT_BITS 9 -#endif -/* client field offset */ -#define CLIENTOFFSET (RESOURCE_AND_CLIENT_COUNT - RESOURCE_CLIENT_BITS) -/* resource field */ -#define RESOURCE_ID_MASK ((1 << CLIENTOFFSET) - 1) -/* client field */ -#define RESOURCE_CLIENT_MASK (((1 << RESOURCE_CLIENT_BITS) - 1) << CLIENTOFFSET) -/* extract the client mask from an XID */ -#define CLIENT_BITS(id) ((id) & RESOURCE_CLIENT_MASK) -/* extract the client id from an XID */ -#define CLIENT_ID(id) ((int)(CLIENT_BITS(id) >> CLIENTOFFSET)) -#define SERVER_BIT (Mask)0x40000000 /* use illegal bit */ - -#ifdef INVALID -#undef INVALID /* needed on HP/UX */ -#endif - -/* Invalid resource id */ -#define INVALID (0) - -#define BAD_RESOURCE 0xe0000000 - -/* Resource state callback */ -extern _X_EXPORT CallbackListPtr ResourceStateCallback; - -typedef enum {ResourceStateAdding, - ResourceStateFreeing} ResourceState; - -typedef struct { - ResourceState state; - XID id; - RESTYPE type; - pointer value; -} ResourceStateInfoRec; - -typedef int (*DeleteType)( - pointer /*value*/, - XID /*id*/); - -typedef void (*FindResType)( - pointer /*value*/, - XID /*id*/, - pointer /*cdata*/); - -typedef void (*FindAllRes)( - pointer /*value*/, - XID /*id*/, - RESTYPE /*type*/, - pointer /*cdata*/); - -typedef Bool (*FindComplexResType)( - pointer /*value*/, - XID /*id*/, - pointer /*cdata*/); - -extern _X_EXPORT RESTYPE CreateNewResourceType( - DeleteType /*deleteFunc*/, char * /*name*/); - -extern _X_EXPORT RESTYPE CreateNewResourceClass(void); - -extern _X_EXPORT Bool InitClientResources( - ClientPtr /*client*/); - -extern _X_EXPORT XID FakeClientID( - int /*client*/); - -/* Quartz support on Mac OS X uses the CarbonCore - framework whose AddResource function conflicts here. */ -#ifdef __APPLE__ -#define AddResource Darwin_X_AddResource -#endif -extern _X_EXPORT Bool AddResource( - XID /*id*/, - RESTYPE /*type*/, - pointer /*value*/); - -extern _X_EXPORT void FreeResource( - XID /*id*/, - RESTYPE /*skipDeleteFuncType*/); - -extern _X_EXPORT void FreeResourceByType( - XID /*id*/, - RESTYPE /*type*/, - Bool /*skipFree*/); - -extern _X_EXPORT Bool ChangeResourceValue( - XID /*id*/, - RESTYPE /*rtype*/, - pointer /*value*/); - -extern _X_EXPORT void FindClientResourcesByType( - ClientPtr /*client*/, - RESTYPE /*type*/, - FindResType /*func*/, - pointer /*cdata*/); - -extern _X_EXPORT void FindAllClientResources( - ClientPtr /*client*/, - FindAllRes /*func*/, - pointer /*cdata*/); - -extern _X_EXPORT void FreeClientNeverRetainResources( - ClientPtr /*client*/); - -extern _X_EXPORT void FreeClientResources( - ClientPtr /*client*/); - -extern _X_EXPORT void FreeAllResources(void); - -extern _X_EXPORT Bool LegalNewID( - XID /*id*/, - ClientPtr /*client*/); - -extern _X_EXPORT pointer LookupClientResourceComplex( - ClientPtr client, - RESTYPE type, - FindComplexResType func, - pointer cdata); - -extern _X_EXPORT int dixLookupResourceByType( - pointer *result, - XID id, - RESTYPE rtype, - ClientPtr client, - Mask access_mode); - -extern _X_EXPORT int dixLookupResourceByClass( - pointer *result, - XID id, - RESTYPE rclass, - ClientPtr client, - Mask access_mode); - -extern _X_EXPORT void GetXIDRange( - int /*client*/, - Bool /*server*/, - XID * /*minp*/, - XID * /*maxp*/); - -extern _X_EXPORT unsigned int GetXIDList( - ClientPtr /*client*/, - unsigned int /*count*/, - XID * /*pids*/); - -extern _X_EXPORT RESTYPE lastResourceType; -extern _X_EXPORT RESTYPE TypeMask; - -/* - * These are deprecated compatibility functions and will be removed soon! - * Please use the noted replacements instead. - */ - -/* replaced by dixLookupResourceByType */ -extern _X_EXPORT pointer SecurityLookupIDByType( - ClientPtr client, - XID id, - RESTYPE rtype, - Mask access_mode) X_DEPRECATED; - -/* replaced by dixLookupResourceByClass */ -extern _X_EXPORT pointer SecurityLookupIDByClass( - ClientPtr client, - XID id, - RESTYPE classes, - Mask access_mode) X_DEPRECATED; - -/* replaced by dixLookupResourceByType */ -extern _X_EXPORT pointer LookupIDByType( - XID id, - RESTYPE rtype) X_DEPRECATED; - -/* replaced by dixLookupResourceByClass */ -extern _X_EXPORT pointer LookupIDByClass( - XID id, - RESTYPE classes) X_DEPRECATED; - -#endif /* RESOURCE_H */ - +/*********************************************************** + +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. + +******************************************************************/ + +#ifndef RESOURCE_H +#define RESOURCE_H 1 +#include "misc.h" +#include "dixaccess.h" + +/***************************************************************** + * STUFF FOR RESOURCES + *****************************************************************/ + +/* classes for Resource routines */ + +typedef unsigned long RESTYPE; + +#define RC_VANILLA ((RESTYPE)0) +#define RC_CACHED ((RESTYPE)1<<31) +#define RC_DRAWABLE ((RESTYPE)1<<30) +/* Use class RC_NEVERRETAIN for resources that should not be retained + * regardless of the close down mode when the client dies. (A client's + * event selections on objects that it doesn't own are good candidates.) + * Extensions can use this too! + */ +#define RC_NEVERRETAIN ((RESTYPE)1<<29) +#define RC_LASTPREDEF RC_NEVERRETAIN +#define RC_ANY (~(RESTYPE)0) + +/* types for Resource routines */ + +#define RT_WINDOW ((RESTYPE)1|RC_DRAWABLE) +#define RT_PIXMAP ((RESTYPE)2|RC_DRAWABLE) +#define RT_GC ((RESTYPE)3) +#undef RT_FONT +#undef RT_CURSOR +#define RT_FONT ((RESTYPE)4) +#define RT_CURSOR ((RESTYPE)5) +#define RT_COLORMAP ((RESTYPE)6) +#define RT_CMAPENTRY ((RESTYPE)7) +#define RT_OTHERCLIENT ((RESTYPE)8|RC_NEVERRETAIN) +#define RT_PASSIVEGRAB ((RESTYPE)9|RC_NEVERRETAIN) +#define RT_LASTPREDEF ((RESTYPE)9) +#define RT_NONE ((RESTYPE)0) + +/* bits and fields within a resource id */ +#define RESOURCE_AND_CLIENT_COUNT 29 /* 29 bits for XIDs */ +#if MAXCLIENTS == 64 +#define RESOURCE_CLIENT_BITS 6 +#endif +#if MAXCLIENTS == 128 +#define RESOURCE_CLIENT_BITS 7 +#endif +#if MAXCLIENTS == 256 +#define RESOURCE_CLIENT_BITS 8 +#endif +#if MAXCLIENTS == 512 +#define RESOURCE_CLIENT_BITS 9 +#endif +/* client field offset */ +#define CLIENTOFFSET (RESOURCE_AND_CLIENT_COUNT - RESOURCE_CLIENT_BITS) +/* resource field */ +#define RESOURCE_ID_MASK ((1 << CLIENTOFFSET) - 1) +/* client field */ +#define RESOURCE_CLIENT_MASK (((1 << RESOURCE_CLIENT_BITS) - 1) << CLIENTOFFSET) +/* extract the client mask from an XID */ +#define CLIENT_BITS(id) ((id) & RESOURCE_CLIENT_MASK) +/* extract the client id from an XID */ +#define CLIENT_ID(id) ((int)(CLIENT_BITS(id) >> CLIENTOFFSET)) +#define SERVER_BIT (Mask)0x40000000 /* use illegal bit */ + +#ifdef INVALID +#undef INVALID /* needed on HP/UX */ +#endif + +/* Invalid resource id */ +#define INVALID (0) + +#define BAD_RESOURCE 0xe0000000 + +/* Resource state callback */ +extern _X_EXPORT CallbackListPtr ResourceStateCallback; + +typedef enum {ResourceStateAdding, + ResourceStateFreeing} ResourceState; + +typedef struct { + ResourceState state; + XID id; + RESTYPE type; + pointer value; +} ResourceStateInfoRec; + +typedef int (*DeleteType)( + pointer /*value*/, + XID /*id*/); + +typedef void (*FindResType)( + pointer /*value*/, + XID /*id*/, + pointer /*cdata*/); + +typedef void (*FindAllRes)( + pointer /*value*/, + XID /*id*/, + RESTYPE /*type*/, + pointer /*cdata*/); + +typedef Bool (*FindComplexResType)( + pointer /*value*/, + XID /*id*/, + pointer /*cdata*/); + +extern _X_EXPORT RESTYPE CreateNewResourceType( + DeleteType /*deleteFunc*/, char * /*name*/); + +extern _X_EXPORT RESTYPE CreateNewResourceClass(void); + +extern _X_EXPORT Bool InitClientResources( + ClientPtr /*client*/); + +extern _X_EXPORT XID FakeClientID( + int /*client*/); + +/* Quartz support on Mac OS X uses the CarbonCore + framework whose AddResource function conflicts here. */ +#ifdef __APPLE__ +#define AddResource Darwin_X_AddResource +#endif +extern _X_EXPORT Bool AddResource( + XID /*id*/, + RESTYPE /*type*/, + pointer /*value*/); + +extern _X_EXPORT void FreeResource( + XID /*id*/, + RESTYPE /*skipDeleteFuncType*/); + +extern _X_EXPORT void FreeResourceByType( + XID /*id*/, + RESTYPE /*type*/, + Bool /*skipFree*/); + +extern _X_EXPORT Bool ChangeResourceValue( + XID /*id*/, + RESTYPE /*rtype*/, + pointer /*value*/); + +extern _X_EXPORT void FindClientResourcesByType( + ClientPtr /*client*/, + RESTYPE /*type*/, + FindResType /*func*/, + pointer /*cdata*/); + +extern _X_EXPORT void FindAllClientResources( + ClientPtr /*client*/, + FindAllRes /*func*/, + pointer /*cdata*/); + +extern _X_EXPORT void FreeClientNeverRetainResources( + ClientPtr /*client*/); + +extern _X_EXPORT void FreeClientResources( + ClientPtr /*client*/); + +extern _X_EXPORT void FreeAllResources(void); + +extern _X_EXPORT Bool LegalNewID( + XID /*id*/, + ClientPtr /*client*/); + +extern _X_EXPORT pointer LookupClientResourceComplex( + ClientPtr client, + RESTYPE type, + FindComplexResType func, + pointer cdata); + +extern _X_EXPORT int dixLookupResourceByType( + pointer *result, + XID id, + RESTYPE rtype, + ClientPtr client, + Mask access_mode); + +extern _X_EXPORT int dixLookupResourceByClass( + pointer *result, + XID id, + RESTYPE rclass, + ClientPtr client, + Mask access_mode); + +extern _X_EXPORT void GetXIDRange( + int /*client*/, + Bool /*server*/, + XID * /*minp*/, + XID * /*maxp*/); + +extern _X_EXPORT unsigned int GetXIDList( + ClientPtr /*client*/, + unsigned int /*count*/, + XID * /*pids*/); + +extern _X_EXPORT RESTYPE lastResourceType; +extern _X_EXPORT RESTYPE TypeMask; + +/* + * These are deprecated compatibility functions and will be removed soon! + * Please use the noted replacements instead. + */ + +/* replaced by dixLookupResourceByType */ +extern _X_EXPORT pointer SecurityLookupIDByType( + ClientPtr client, + XID id, + RESTYPE rtype, + Mask access_mode) _X_DEPRECATED; + +/* replaced by dixLookupResourceByClass */ +extern _X_EXPORT pointer SecurityLookupIDByClass( + ClientPtr client, + XID id, + RESTYPE classes, + Mask access_mode) _X_DEPRECATED; + +/* replaced by dixLookupResourceByType */ +extern _X_EXPORT pointer LookupIDByType( + XID id, + RESTYPE rtype) _X_DEPRECATED; + +/* replaced by dixLookupResourceByClass */ +extern _X_EXPORT pointer LookupIDByClass( + XID id, + RESTYPE classes) _X_DEPRECATED; + +#endif /* RESOURCE_H */ + diff --git a/xorg-server/include/scrnintstr.h b/xorg-server/include/scrnintstr.h index 553893677..e07bee3c3 100644 --- a/xorg-server/include/scrnintstr.h +++ b/xorg-server/include/scrnintstr.h @@ -1,629 +1,613 @@ -/*********************************************************** - -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. - -******************************************************************/ - -#ifndef SCREENINTSTRUCT_H -#define SCREENINTSTRUCT_H - -#include "screenint.h" -#include "regionstr.h" -#include "bstore.h" -#include "colormap.h" -#include "cursor.h" -#include "validate.h" -#include <X11/Xproto.h> -#include "dix.h" -#include "privates.h" - -typedef struct _PixmapFormat { - unsigned char depth; - unsigned char bitsPerPixel; - unsigned char scanlinePad; - } PixmapFormatRec; - -typedef struct _Visual { - VisualID vid; - short class; - short bitsPerRGBValue; - short ColormapEntries; - short nplanes;/* = log2 (ColormapEntries). This does not - * imply that the screen has this many planes. - * it may have more or fewer */ - unsigned long redMask, greenMask, blueMask; - int offsetRed, offsetGreen, offsetBlue; - } VisualRec; - -typedef struct _Depth { - unsigned char depth; - short numVids; - VisualID *vids; /* block of visual ids for this depth */ - } DepthRec; - - -/* - * There is a typedef for each screen function pointer so that code that - * needs to declare a screen function pointer (e.g. in a screen private - * or as a local variable) can easily do so and retain full type checking. - */ - -typedef Bool (* CloseScreenProcPtr)( - int /*index*/, - ScreenPtr /*pScreen*/); - -typedef void (* QueryBestSizeProcPtr)( - int /*class*/, - unsigned short * /*pwidth*/, - unsigned short * /*pheight*/, - ScreenPtr /*pScreen*/); - -typedef Bool (* SaveScreenProcPtr)( - ScreenPtr /*pScreen*/, - int /*on*/); - -typedef void (* GetImageProcPtr)( - DrawablePtr /*pDrawable*/, - int /*sx*/, - int /*sy*/, - int /*w*/, - int /*h*/, - unsigned int /*format*/, - unsigned long /*planeMask*/, - char * /*pdstLine*/); - -typedef void (* GetSpansProcPtr)( - DrawablePtr /*pDrawable*/, - int /*wMax*/, - DDXPointPtr /*ppt*/, - int* /*pwidth*/, - int /*nspans*/, - char * /*pdstStart*/); - -typedef void (* PointerNonInterestBoxProcPtr)( - DeviceIntPtr /*pDev*/, - ScreenPtr /*pScreen*/, - BoxPtr /*pBox*/); - -typedef void (* SourceValidateProcPtr)( - DrawablePtr /*pDrawable*/, - int /*x*/, - int /*y*/, - int /*width*/, - int /*height*/); - -typedef Bool (* CreateWindowProcPtr)( - WindowPtr /*pWindow*/); - -typedef Bool (* DestroyWindowProcPtr)( - WindowPtr /*pWindow*/); - -typedef Bool (* PositionWindowProcPtr)( - WindowPtr /*pWindow*/, - int /*x*/, - int /*y*/); - -typedef Bool (* ChangeWindowAttributesProcPtr)( - WindowPtr /*pWindow*/, - unsigned long /*mask*/); - -typedef Bool (* RealizeWindowProcPtr)( - WindowPtr /*pWindow*/); - -typedef Bool (* UnrealizeWindowProcPtr)( - WindowPtr /*pWindow*/); - -typedef void (* RestackWindowProcPtr)( - WindowPtr /*pWindow*/, - WindowPtr /*pOldNextSib*/); - -typedef int (* ValidateTreeProcPtr)( - WindowPtr /*pParent*/, - WindowPtr /*pChild*/, - VTKind /*kind*/); - -typedef void (* PostValidateTreeProcPtr)( - WindowPtr /*pParent*/, - WindowPtr /*pChild*/, - VTKind /*kind*/); - -typedef void (* WindowExposuresProcPtr)( - WindowPtr /*pWindow*/, - RegionPtr /*prgn*/, - RegionPtr /*other_exposed*/); - -typedef void (* PaintWindowProcPtr)( - WindowPtr /*pWindow*/, - RegionPtr /*pRegion*/, - int /*what*/); - -typedef PaintWindowProcPtr PaintWindowBackgroundProcPtr; -typedef PaintWindowProcPtr PaintWindowBorderProcPtr; - -typedef void (* CopyWindowProcPtr)( - WindowPtr /*pWindow*/, - DDXPointRec /*ptOldOrg*/, - RegionPtr /*prgnSrc*/); - -typedef void (* ClearToBackgroundProcPtr)( - WindowPtr /*pWindow*/, - int /*x*/, - int /*y*/, - int /*w*/, - int /*h*/, - Bool /*generateExposures*/); - -typedef void (* ClipNotifyProcPtr)( - WindowPtr /*pWindow*/, - int /*dx*/, - int /*dy*/); - -/* pixmap will exist only for the duration of the current rendering operation */ -#define CREATE_PIXMAP_USAGE_SCRATCH 1 -/* pixmap will be the backing pixmap for a redirected window */ -#define CREATE_PIXMAP_USAGE_BACKING_PIXMAP 2 -/* pixmap will contain a glyph */ -#define CREATE_PIXMAP_USAGE_GLYPH_PICTURE 3 - -typedef PixmapPtr (* CreatePixmapProcPtr)( - ScreenPtr /*pScreen*/, - int /*width*/, - int /*height*/, - int /*depth*/, - unsigned /*usage_hint*/); - -typedef Bool (* DestroyPixmapProcPtr)( - PixmapPtr /*pPixmap*/); - -typedef void (* SaveDoomedAreasProcPtr)( - WindowPtr /*pWindow*/, - RegionPtr /*prgnSave*/, - int /*xorg*/, - int /*yorg*/); - -typedef RegionPtr (* RestoreAreasProcPtr)( - WindowPtr /*pWindow*/, - RegionPtr /*prgnRestore*/); - -typedef void (* ExposeCopyProcPtr)( - WindowPtr /*pSrc*/, - DrawablePtr /*pDst*/, - GCPtr /*pGC*/, - RegionPtr /*prgnExposed*/, - int /*srcx*/, - int /*srcy*/, - int /*dstx*/, - int /*dsty*/, - unsigned long /*plane*/); - -typedef RegionPtr (* TranslateBackingStoreProcPtr)( - WindowPtr /*pWindow*/, - int /*windx*/, - int /*windy*/, - RegionPtr /*oldClip*/, - int /*oldx*/, - int /*oldy*/); - -typedef RegionPtr (* ClearBackingStoreProcPtr)( - WindowPtr /*pWindow*/, - int /*x*/, - int /*y*/, - int /*w*/, - int /*h*/, - Bool /*generateExposures*/); - -typedef void (* DrawGuaranteeProcPtr)( - WindowPtr /*pWindow*/, - GCPtr /*pGC*/, - int /*guarantee*/); - -typedef Bool (* RealizeFontProcPtr)( - ScreenPtr /*pScreen*/, - FontPtr /*pFont*/); - -typedef Bool (* UnrealizeFontProcPtr)( - ScreenPtr /*pScreen*/, - FontPtr /*pFont*/); - -typedef void (* ConstrainCursorProcPtr)( - DeviceIntPtr /*pDev*/, - ScreenPtr /*pScreen*/, - BoxPtr /*pBox*/); - -typedef void (* CursorLimitsProcPtr)( - DeviceIntPtr /* pDev */, - ScreenPtr /*pScreen*/, - CursorPtr /*pCursor*/, - BoxPtr /*pHotBox*/, - BoxPtr /*pTopLeftBox*/); - -typedef Bool (* DisplayCursorProcPtr)( - DeviceIntPtr /* pDev */, - ScreenPtr /*pScreen*/, - CursorPtr /*pCursor*/); - -typedef Bool (* RealizeCursorProcPtr)( - DeviceIntPtr /* pDev */, - ScreenPtr /*pScreen*/, - CursorPtr /*pCursor*/); - -typedef Bool (* UnrealizeCursorProcPtr)( - DeviceIntPtr /* pDev */, - ScreenPtr /*pScreen*/, - CursorPtr /*pCursor*/); - -typedef void (* RecolorCursorProcPtr)( - DeviceIntPtr /* pDev */, - ScreenPtr /*pScreen*/, - CursorPtr /*pCursor*/, - Bool /*displayed*/); - -typedef Bool (* SetCursorPositionProcPtr)( - DeviceIntPtr /* pDev */, - ScreenPtr /*pScreen*/, - int /*x*/, - int /*y*/, - Bool /*generateEvent*/); - -typedef Bool (* CreateGCProcPtr)( - GCPtr /*pGC*/); - -typedef Bool (* CreateColormapProcPtr)( - ColormapPtr /*pColormap*/); - -typedef void (* DestroyColormapProcPtr)( - ColormapPtr /*pColormap*/); - -typedef void (* InstallColormapProcPtr)( - ColormapPtr /*pColormap*/); - -typedef void (* UninstallColormapProcPtr)( - ColormapPtr /*pColormap*/); - -typedef int (* ListInstalledColormapsProcPtr) ( - ScreenPtr /*pScreen*/, - XID* /*pmaps */); - -typedef void (* StoreColorsProcPtr)( - ColormapPtr /*pColormap*/, - int /*ndef*/, - xColorItem * /*pdef*/); - -typedef void (* ResolveColorProcPtr)( - unsigned short* /*pred*/, - unsigned short* /*pgreen*/, - unsigned short* /*pblue*/, - VisualPtr /*pVisual*/); - -typedef RegionPtr (* BitmapToRegionProcPtr)( - PixmapPtr /*pPix*/); - -typedef void (* SendGraphicsExposeProcPtr)( - ClientPtr /*client*/, - RegionPtr /*pRgn*/, - XID /*drawable*/, - int /*major*/, - int /*minor*/); - -typedef void (* ScreenBlockHandlerProcPtr)( - int /*screenNum*/, - pointer /*blockData*/, - pointer /*pTimeout*/, - pointer /*pReadmask*/); - -typedef void (* ScreenWakeupHandlerProcPtr)( - int /*screenNum*/, - pointer /*wakeupData*/, - unsigned long /*result*/, - pointer /*pReadMask*/); - -typedef Bool (* CreateScreenResourcesProcPtr)( - ScreenPtr /*pScreen*/); - -typedef Bool (* ModifyPixmapHeaderProcPtr)( - PixmapPtr /*pPixmap*/, - int /*width*/, - int /*height*/, - int /*depth*/, - int /*bitsPerPixel*/, - int /*devKind*/, - pointer /*pPixData*/); - -typedef PixmapPtr (* GetWindowPixmapProcPtr)( - WindowPtr /*pWin*/); - -typedef void (* SetWindowPixmapProcPtr)( - WindowPtr /*pWin*/, - PixmapPtr /*pPix*/); - -typedef PixmapPtr (* GetScreenPixmapProcPtr)( - ScreenPtr /*pScreen*/); - -typedef void (* SetScreenPixmapProcPtr)( - PixmapPtr /*pPix*/); - -typedef void (* MarkWindowProcPtr)( - WindowPtr /*pWin*/); - -typedef Bool (* MarkOverlappedWindowsProcPtr)( - WindowPtr /*parent*/, - WindowPtr /*firstChild*/, - WindowPtr * /*pLayerWin*/); - -typedef Bool (* ChangeSaveUnderProcPtr)( - WindowPtr /*pLayerWin*/, - WindowPtr /*firstChild*/); - -typedef void (* PostChangeSaveUnderProcPtr)( - WindowPtr /*pLayerWin*/, - WindowPtr /*firstChild*/); - -typedef void (* ConfigNotifyProcPtr)( - WindowPtr /*pWin*/, - int /*x*/, - int /*y*/, - int /*w*/, - int /*h*/, - int /*bw*/, - WindowPtr /*pSib*/); - -typedef void (* MoveWindowProcPtr)( - WindowPtr /*pWin*/, - int /*x*/, - int /*y*/, - WindowPtr /*pSib*/, - VTKind /*kind*/); - -typedef void (* ResizeWindowProcPtr)( - WindowPtr /*pWin*/, - int /*x*/, - int /*y*/, - unsigned int /*w*/, - unsigned int /*h*/, - WindowPtr /*pSib*/ -); - -typedef WindowPtr (* GetLayerWindowProcPtr)( - WindowPtr /*pWin*/ -); - -typedef void (* HandleExposuresProcPtr)( - WindowPtr /*pWin*/); - -typedef void (* ReparentWindowProcPtr)( - WindowPtr /*pWin*/, - WindowPtr /*pPriorParent*/); - -typedef void (* SetShapeProcPtr)( - WindowPtr /*pWin*/); - -typedef void (* ChangeBorderWidthProcPtr)( - WindowPtr /*pWin*/, - unsigned int /*width*/); - -typedef void (* MarkUnrealizedWindowProcPtr)( - WindowPtr /*pChild*/, - WindowPtr /*pWin*/, - Bool /*fromConfigure*/); - -typedef Bool (* DeviceCursorInitializeProcPtr)( - DeviceIntPtr /* pDev */, - ScreenPtr /* pScreen */); - -typedef void (* DeviceCursorCleanupProcPtr)( - DeviceIntPtr /* pDev */, - ScreenPtr /* pScreen */); - -typedef struct _Screen { - int myNum; /* index of this instance in Screens[] */ - ATOM id; - short width, height; - short mmWidth, mmHeight; - short numDepths; - unsigned char rootDepth; - DepthPtr allowedDepths; - unsigned long rootVisual; - unsigned long defColormap; - short minInstalledCmaps, maxInstalledCmaps; - char backingStoreSupport, saveUnderSupport; - unsigned long whitePixel, blackPixel; - unsigned long rgf; /* array of flags; she's -- HUNGARIAN */ - GCPtr GCperDepth[MAXFORMATS+1]; - /* next field is a stipple to use as default in - a GC. we don't build default tiles of all depths - because they are likely to be of a color - different from the default fg pixel, so - we don't win anything by building - a standard one. - */ - PixmapPtr PixmapPerDepth[1]; - pointer devPrivate; - short numVisuals; - VisualPtr visuals; - - /* Random screen procedures */ - - CloseScreenProcPtr CloseScreen; - QueryBestSizeProcPtr QueryBestSize; - SaveScreenProcPtr SaveScreen; - GetImageProcPtr GetImage; - GetSpansProcPtr GetSpans; - PointerNonInterestBoxProcPtr PointerNonInterestBox; - SourceValidateProcPtr SourceValidate; - - /* Window Procedures */ - - CreateWindowProcPtr CreateWindow; - DestroyWindowProcPtr DestroyWindow; - PositionWindowProcPtr PositionWindow; - ChangeWindowAttributesProcPtr ChangeWindowAttributes; - RealizeWindowProcPtr RealizeWindow; - UnrealizeWindowProcPtr UnrealizeWindow; - ValidateTreeProcPtr ValidateTree; - PostValidateTreeProcPtr PostValidateTree; - WindowExposuresProcPtr WindowExposures; - PaintWindowBackgroundProcPtr PaintWindowBackground; /** unused */ - PaintWindowBorderProcPtr PaintWindowBorder; /** unused */ - CopyWindowProcPtr CopyWindow; - ClearToBackgroundProcPtr ClearToBackground; - ClipNotifyProcPtr ClipNotify; - RestackWindowProcPtr RestackWindow; - - /* Pixmap procedures */ - - CreatePixmapProcPtr CreatePixmap; - DestroyPixmapProcPtr DestroyPixmap; - - /* Backing store procedures */ - - SaveDoomedAreasProcPtr SaveDoomedAreas; - RestoreAreasProcPtr RestoreAreas; - ExposeCopyProcPtr ExposeCopy; - TranslateBackingStoreProcPtr TranslateBackingStore; - ClearBackingStoreProcPtr ClearBackingStore; - DrawGuaranteeProcPtr DrawGuarantee; - /* - * A read/write copy of the lower level backing store vector is needed now - * that the functions can be wrapped. - */ - BSFuncRec BackingStoreFuncs; - - /* Font procedures */ - - RealizeFontProcPtr RealizeFont; - UnrealizeFontProcPtr UnrealizeFont; - - /* Cursor Procedures */ - - ConstrainCursorProcPtr ConstrainCursor; - CursorLimitsProcPtr CursorLimits; - DisplayCursorProcPtr DisplayCursor; - RealizeCursorProcPtr RealizeCursor; - UnrealizeCursorProcPtr UnrealizeCursor; - RecolorCursorProcPtr RecolorCursor; - SetCursorPositionProcPtr SetCursorPosition; - - /* GC procedures */ - - CreateGCProcPtr CreateGC; - - /* Colormap procedures */ - - CreateColormapProcPtr CreateColormap; - DestroyColormapProcPtr DestroyColormap; - InstallColormapProcPtr InstallColormap; - UninstallColormapProcPtr UninstallColormap; - ListInstalledColormapsProcPtr ListInstalledColormaps; - StoreColorsProcPtr StoreColors; - ResolveColorProcPtr ResolveColor; - - /* Region procedures */ - - BitmapToRegionProcPtr BitmapToRegion; - SendGraphicsExposeProcPtr SendGraphicsExpose; - - /* os layer procedures */ - - ScreenBlockHandlerProcPtr BlockHandler; - ScreenWakeupHandlerProcPtr WakeupHandler; - - pointer blockData; - pointer wakeupData; - - /* anybody can get a piece of this array */ - PrivateRec *devPrivates; - - CreateScreenResourcesProcPtr CreateScreenResources; - ModifyPixmapHeaderProcPtr ModifyPixmapHeader; - - GetWindowPixmapProcPtr GetWindowPixmap; - SetWindowPixmapProcPtr SetWindowPixmap; - GetScreenPixmapProcPtr GetScreenPixmap; - SetScreenPixmapProcPtr SetScreenPixmap; - - PixmapPtr pScratchPixmap; /* scratch pixmap "pool" */ - - unsigned int totalPixmapSize; - - MarkWindowProcPtr MarkWindow; - MarkOverlappedWindowsProcPtr MarkOverlappedWindows; - ChangeSaveUnderProcPtr ChangeSaveUnder; - PostChangeSaveUnderProcPtr PostChangeSaveUnder; - ConfigNotifyProcPtr ConfigNotify; - MoveWindowProcPtr MoveWindow; - ResizeWindowProcPtr ResizeWindow; - GetLayerWindowProcPtr GetLayerWindow; - HandleExposuresProcPtr HandleExposures; - ReparentWindowProcPtr ReparentWindow; - - SetShapeProcPtr SetShape; - - ChangeBorderWidthProcPtr ChangeBorderWidth; - MarkUnrealizedWindowProcPtr MarkUnrealizedWindow; - - /* Device cursor procedures */ - DeviceCursorInitializeProcPtr DeviceCursorInitialize; - DeviceCursorCleanupProcPtr DeviceCursorCleanup; -} ScreenRec; - -typedef struct _ScreenInfo { - int imageByteOrder; - int bitmapScanlineUnit; - int bitmapScanlinePad; - int bitmapBitOrder; - int numPixmapFormats; - PixmapFormatRec - formats[MAXFORMATS]; - int numScreens; - ScreenPtr screens[MAXSCREENS]; -} ScreenInfo; - -extern _X_EXPORT ScreenInfo screenInfo; - -extern _X_EXPORT void InitOutput( - ScreenInfo * /*pScreenInfo*/, - int /*argc*/, - char ** /*argv*/); - -#endif /* SCREENINTSTRUCT_H */ +/*********************************************************** + +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. + +******************************************************************/ + +#ifndef SCREENINTSTRUCT_H +#define SCREENINTSTRUCT_H + +#include "screenint.h" +#include "regionstr.h" +#include "bstore.h" +#include "colormap.h" +#include "cursor.h" +#include "validate.h" +#include <X11/Xproto.h> +#include "dix.h" +#include "privates.h" + +typedef struct _PixmapFormat { + unsigned char depth; + unsigned char bitsPerPixel; + unsigned char scanlinePad; + } PixmapFormatRec; + +typedef struct _Visual { + VisualID vid; + short class; + short bitsPerRGBValue; + short ColormapEntries; + short nplanes;/* = log2 (ColormapEntries). This does not + * imply that the screen has this many planes. + * it may have more or fewer */ + unsigned long redMask, greenMask, blueMask; + int offsetRed, offsetGreen, offsetBlue; + } VisualRec; + +typedef struct _Depth { + unsigned char depth; + short numVids; + VisualID *vids; /* block of visual ids for this depth */ + } DepthRec; + + +/* + * There is a typedef for each screen function pointer so that code that + * needs to declare a screen function pointer (e.g. in a screen private + * or as a local variable) can easily do so and retain full type checking. + */ + +typedef Bool (* CloseScreenProcPtr)( + int /*index*/, + ScreenPtr /*pScreen*/); + +typedef void (* QueryBestSizeProcPtr)( + int /*class*/, + unsigned short * /*pwidth*/, + unsigned short * /*pheight*/, + ScreenPtr /*pScreen*/); + +typedef Bool (* SaveScreenProcPtr)( + ScreenPtr /*pScreen*/, + int /*on*/); + +typedef void (* GetImageProcPtr)( + DrawablePtr /*pDrawable*/, + int /*sx*/, + int /*sy*/, + int /*w*/, + int /*h*/, + unsigned int /*format*/, + unsigned long /*planeMask*/, + char * /*pdstLine*/); + +typedef void (* GetSpansProcPtr)( + DrawablePtr /*pDrawable*/, + int /*wMax*/, + DDXPointPtr /*ppt*/, + int* /*pwidth*/, + int /*nspans*/, + char * /*pdstStart*/); + +typedef void (* SourceValidateProcPtr)( + DrawablePtr /*pDrawable*/, + int /*x*/, + int /*y*/, + int /*width*/, + int /*height*/); + +typedef Bool (* CreateWindowProcPtr)( + WindowPtr /*pWindow*/); + +typedef Bool (* DestroyWindowProcPtr)( + WindowPtr /*pWindow*/); + +typedef Bool (* PositionWindowProcPtr)( + WindowPtr /*pWindow*/, + int /*x*/, + int /*y*/); + +typedef Bool (* ChangeWindowAttributesProcPtr)( + WindowPtr /*pWindow*/, + unsigned long /*mask*/); + +typedef Bool (* RealizeWindowProcPtr)( + WindowPtr /*pWindow*/); + +typedef Bool (* UnrealizeWindowProcPtr)( + WindowPtr /*pWindow*/); + +typedef void (* RestackWindowProcPtr)( + WindowPtr /*pWindow*/, + WindowPtr /*pOldNextSib*/); + +typedef int (* ValidateTreeProcPtr)( + WindowPtr /*pParent*/, + WindowPtr /*pChild*/, + VTKind /*kind*/); + +typedef void (* PostValidateTreeProcPtr)( + WindowPtr /*pParent*/, + WindowPtr /*pChild*/, + VTKind /*kind*/); + +typedef void (* WindowExposuresProcPtr)( + WindowPtr /*pWindow*/, + RegionPtr /*prgn*/, + RegionPtr /*other_exposed*/); + +typedef void (* CopyWindowProcPtr)( + WindowPtr /*pWindow*/, + DDXPointRec /*ptOldOrg*/, + RegionPtr /*prgnSrc*/); + +typedef void (* ClearToBackgroundProcPtr)( + WindowPtr /*pWindow*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + Bool /*generateExposures*/); + +typedef void (* ClipNotifyProcPtr)( + WindowPtr /*pWindow*/, + int /*dx*/, + int /*dy*/); + +/* pixmap will exist only for the duration of the current rendering operation */ +#define CREATE_PIXMAP_USAGE_SCRATCH 1 +/* pixmap will be the backing pixmap for a redirected window */ +#define CREATE_PIXMAP_USAGE_BACKING_PIXMAP 2 +/* pixmap will contain a glyph */ +#define CREATE_PIXMAP_USAGE_GLYPH_PICTURE 3 + +typedef PixmapPtr (* CreatePixmapProcPtr)( + ScreenPtr /*pScreen*/, + int /*width*/, + int /*height*/, + int /*depth*/, + unsigned /*usage_hint*/); + +typedef Bool (* DestroyPixmapProcPtr)( + PixmapPtr /*pPixmap*/); + +typedef void (* SaveDoomedAreasProcPtr)( + WindowPtr /*pWindow*/, + RegionPtr /*prgnSave*/, + int /*xorg*/, + int /*yorg*/); + +typedef RegionPtr (* RestoreAreasProcPtr)( + WindowPtr /*pWindow*/, + RegionPtr /*prgnRestore*/); + +typedef void (* ExposeCopyProcPtr)( + WindowPtr /*pSrc*/, + DrawablePtr /*pDst*/, + GCPtr /*pGC*/, + RegionPtr /*prgnExposed*/, + int /*srcx*/, + int /*srcy*/, + int /*dstx*/, + int /*dsty*/, + unsigned long /*plane*/); + +typedef RegionPtr (* TranslateBackingStoreProcPtr)( + WindowPtr /*pWindow*/, + int /*windx*/, + int /*windy*/, + RegionPtr /*oldClip*/, + int /*oldx*/, + int /*oldy*/); + +typedef RegionPtr (* ClearBackingStoreProcPtr)( + WindowPtr /*pWindow*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + Bool /*generateExposures*/); + +typedef void (* DrawGuaranteeProcPtr)( + WindowPtr /*pWindow*/, + GCPtr /*pGC*/, + int /*guarantee*/); + +typedef Bool (* RealizeFontProcPtr)( + ScreenPtr /*pScreen*/, + FontPtr /*pFont*/); + +typedef Bool (* UnrealizeFontProcPtr)( + ScreenPtr /*pScreen*/, + FontPtr /*pFont*/); + +typedef void (* ConstrainCursorProcPtr)( + DeviceIntPtr /*pDev*/, + ScreenPtr /*pScreen*/, + BoxPtr /*pBox*/); + +typedef void (* CursorLimitsProcPtr)( + DeviceIntPtr /* pDev */, + ScreenPtr /*pScreen*/, + CursorPtr /*pCursor*/, + BoxPtr /*pHotBox*/, + BoxPtr /*pTopLeftBox*/); + +typedef Bool (* DisplayCursorProcPtr)( + DeviceIntPtr /* pDev */, + ScreenPtr /*pScreen*/, + CursorPtr /*pCursor*/); + +typedef Bool (* RealizeCursorProcPtr)( + DeviceIntPtr /* pDev */, + ScreenPtr /*pScreen*/, + CursorPtr /*pCursor*/); + +typedef Bool (* UnrealizeCursorProcPtr)( + DeviceIntPtr /* pDev */, + ScreenPtr /*pScreen*/, + CursorPtr /*pCursor*/); + +typedef void (* RecolorCursorProcPtr)( + DeviceIntPtr /* pDev */, + ScreenPtr /*pScreen*/, + CursorPtr /*pCursor*/, + Bool /*displayed*/); + +typedef Bool (* SetCursorPositionProcPtr)( + DeviceIntPtr /* pDev */, + ScreenPtr /*pScreen*/, + int /*x*/, + int /*y*/, + Bool /*generateEvent*/); + +typedef Bool (* CreateGCProcPtr)( + GCPtr /*pGC*/); + +typedef Bool (* CreateColormapProcPtr)( + ColormapPtr /*pColormap*/); + +typedef void (* DestroyColormapProcPtr)( + ColormapPtr /*pColormap*/); + +typedef void (* InstallColormapProcPtr)( + ColormapPtr /*pColormap*/); + +typedef void (* UninstallColormapProcPtr)( + ColormapPtr /*pColormap*/); + +typedef int (* ListInstalledColormapsProcPtr) ( + ScreenPtr /*pScreen*/, + XID* /*pmaps */); + +typedef void (* StoreColorsProcPtr)( + ColormapPtr /*pColormap*/, + int /*ndef*/, + xColorItem * /*pdef*/); + +typedef void (* ResolveColorProcPtr)( + unsigned short* /*pred*/, + unsigned short* /*pgreen*/, + unsigned short* /*pblue*/, + VisualPtr /*pVisual*/); + +typedef RegionPtr (* BitmapToRegionProcPtr)( + PixmapPtr /*pPix*/); + +typedef void (* SendGraphicsExposeProcPtr)( + ClientPtr /*client*/, + RegionPtr /*pRgn*/, + XID /*drawable*/, + int /*major*/, + int /*minor*/); + +typedef void (* ScreenBlockHandlerProcPtr)( + int /*screenNum*/, + pointer /*blockData*/, + pointer /*pTimeout*/, + pointer /*pReadmask*/); + +typedef void (* ScreenWakeupHandlerProcPtr)( + int /*screenNum*/, + pointer /*wakeupData*/, + unsigned long /*result*/, + pointer /*pReadMask*/); + +typedef Bool (* CreateScreenResourcesProcPtr)( + ScreenPtr /*pScreen*/); + +typedef Bool (* ModifyPixmapHeaderProcPtr)( + PixmapPtr /*pPixmap*/, + int /*width*/, + int /*height*/, + int /*depth*/, + int /*bitsPerPixel*/, + int /*devKind*/, + pointer /*pPixData*/); + +typedef PixmapPtr (* GetWindowPixmapProcPtr)( + WindowPtr /*pWin*/); + +typedef void (* SetWindowPixmapProcPtr)( + WindowPtr /*pWin*/, + PixmapPtr /*pPix*/); + +typedef PixmapPtr (* GetScreenPixmapProcPtr)( + ScreenPtr /*pScreen*/); + +typedef void (* SetScreenPixmapProcPtr)( + PixmapPtr /*pPix*/); + +typedef void (* MarkWindowProcPtr)( + WindowPtr /*pWin*/); + +typedef Bool (* MarkOverlappedWindowsProcPtr)( + WindowPtr /*parent*/, + WindowPtr /*firstChild*/, + WindowPtr * /*pLayerWin*/); + +typedef Bool (* ChangeSaveUnderProcPtr)( + WindowPtr /*pLayerWin*/, + WindowPtr /*firstChild*/); + +typedef void (* PostChangeSaveUnderProcPtr)( + WindowPtr /*pLayerWin*/, + WindowPtr /*firstChild*/); + +typedef void (* ConfigNotifyProcPtr)( + WindowPtr /*pWin*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + int /*bw*/, + WindowPtr /*pSib*/); + +typedef void (* MoveWindowProcPtr)( + WindowPtr /*pWin*/, + int /*x*/, + int /*y*/, + WindowPtr /*pSib*/, + VTKind /*kind*/); + +typedef void (* ResizeWindowProcPtr)( + WindowPtr /*pWin*/, + int /*x*/, + int /*y*/, + unsigned int /*w*/, + unsigned int /*h*/, + WindowPtr /*pSib*/ +); + +typedef WindowPtr (* GetLayerWindowProcPtr)( + WindowPtr /*pWin*/ +); + +typedef void (* HandleExposuresProcPtr)( + WindowPtr /*pWin*/); + +typedef void (* ReparentWindowProcPtr)( + WindowPtr /*pWin*/, + WindowPtr /*pPriorParent*/); + +typedef void (* SetShapeProcPtr)( + WindowPtr /*pWin*/); + +typedef void (* ChangeBorderWidthProcPtr)( + WindowPtr /*pWin*/, + unsigned int /*width*/); + +typedef void (* MarkUnrealizedWindowProcPtr)( + WindowPtr /*pChild*/, + WindowPtr /*pWin*/, + Bool /*fromConfigure*/); + +typedef Bool (* DeviceCursorInitializeProcPtr)( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScreen */); + +typedef void (* DeviceCursorCleanupProcPtr)( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScreen */); + +typedef struct _Screen { + int myNum; /* index of this instance in Screens[] */ + ATOM id; + short width, height; + short mmWidth, mmHeight; + short numDepths; + unsigned char rootDepth; + DepthPtr allowedDepths; + unsigned long rootVisual; + unsigned long defColormap; + short minInstalledCmaps, maxInstalledCmaps; + char backingStoreSupport, saveUnderSupport; + unsigned long whitePixel, blackPixel; + unsigned long rgf; /* array of flags; she's -- HUNGARIAN */ + GCPtr GCperDepth[MAXFORMATS+1]; + /* next field is a stipple to use as default in + a GC. we don't build default tiles of all depths + because they are likely to be of a color + different from the default fg pixel, so + we don't win anything by building + a standard one. + */ + PixmapPtr PixmapPerDepth[1]; + pointer devPrivate; + short numVisuals; + VisualPtr visuals; + + /* Random screen procedures */ + + CloseScreenProcPtr CloseScreen; + QueryBestSizeProcPtr QueryBestSize; + SaveScreenProcPtr SaveScreen; + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + SourceValidateProcPtr SourceValidate; + + /* Window Procedures */ + + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + PositionWindowProcPtr PositionWindow; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + ValidateTreeProcPtr ValidateTree; + PostValidateTreeProcPtr PostValidateTree; + WindowExposuresProcPtr WindowExposures; + CopyWindowProcPtr CopyWindow; + ClearToBackgroundProcPtr ClearToBackground; + ClipNotifyProcPtr ClipNotify; + RestackWindowProcPtr RestackWindow; + + /* Pixmap procedures */ + + CreatePixmapProcPtr CreatePixmap; + DestroyPixmapProcPtr DestroyPixmap; + + /* Backing store procedures */ + + SaveDoomedAreasProcPtr SaveDoomedAreas; + RestoreAreasProcPtr RestoreAreas; + ExposeCopyProcPtr ExposeCopy; + TranslateBackingStoreProcPtr TranslateBackingStore; + ClearBackingStoreProcPtr ClearBackingStore; + DrawGuaranteeProcPtr DrawGuarantee; + /* + * A read/write copy of the lower level backing store vector is needed now + * that the functions can be wrapped. + */ + BSFuncRec BackingStoreFuncs; + + /* Font procedures */ + + RealizeFontProcPtr RealizeFont; + UnrealizeFontProcPtr UnrealizeFont; + + /* Cursor Procedures */ + + ConstrainCursorProcPtr ConstrainCursor; + CursorLimitsProcPtr CursorLimits; + DisplayCursorProcPtr DisplayCursor; + RealizeCursorProcPtr RealizeCursor; + UnrealizeCursorProcPtr UnrealizeCursor; + RecolorCursorProcPtr RecolorCursor; + SetCursorPositionProcPtr SetCursorPosition; + + /* GC procedures */ + + CreateGCProcPtr CreateGC; + + /* Colormap procedures */ + + CreateColormapProcPtr CreateColormap; + DestroyColormapProcPtr DestroyColormap; + InstallColormapProcPtr InstallColormap; + UninstallColormapProcPtr UninstallColormap; + ListInstalledColormapsProcPtr ListInstalledColormaps; + StoreColorsProcPtr StoreColors; + ResolveColorProcPtr ResolveColor; + + /* Region procedures */ + + BitmapToRegionProcPtr BitmapToRegion; + SendGraphicsExposeProcPtr SendGraphicsExpose; + + /* os layer procedures */ + + ScreenBlockHandlerProcPtr BlockHandler; + ScreenWakeupHandlerProcPtr WakeupHandler; + + pointer blockData; + pointer wakeupData; + + /* anybody can get a piece of this array */ + PrivateRec *devPrivates; + + CreateScreenResourcesProcPtr CreateScreenResources; + ModifyPixmapHeaderProcPtr ModifyPixmapHeader; + + GetWindowPixmapProcPtr GetWindowPixmap; + SetWindowPixmapProcPtr SetWindowPixmap; + GetScreenPixmapProcPtr GetScreenPixmap; + SetScreenPixmapProcPtr SetScreenPixmap; + + PixmapPtr pScratchPixmap; /* scratch pixmap "pool" */ + + unsigned int totalPixmapSize; + + MarkWindowProcPtr MarkWindow; + MarkOverlappedWindowsProcPtr MarkOverlappedWindows; + ChangeSaveUnderProcPtr ChangeSaveUnder; + PostChangeSaveUnderProcPtr PostChangeSaveUnder; + ConfigNotifyProcPtr ConfigNotify; + MoveWindowProcPtr MoveWindow; + ResizeWindowProcPtr ResizeWindow; + GetLayerWindowProcPtr GetLayerWindow; + HandleExposuresProcPtr HandleExposures; + ReparentWindowProcPtr ReparentWindow; + + SetShapeProcPtr SetShape; + + ChangeBorderWidthProcPtr ChangeBorderWidth; + MarkUnrealizedWindowProcPtr MarkUnrealizedWindow; + + /* Device cursor procedures */ + DeviceCursorInitializeProcPtr DeviceCursorInitialize; + DeviceCursorCleanupProcPtr DeviceCursorCleanup; +} ScreenRec; + +typedef struct _ScreenInfo { + int imageByteOrder; + int bitmapScanlineUnit; + int bitmapScanlinePad; + int bitmapBitOrder; + int numPixmapFormats; + PixmapFormatRec + formats[MAXFORMATS]; + int numScreens; + ScreenPtr screens[MAXSCREENS]; +} ScreenInfo; + +extern _X_EXPORT ScreenInfo screenInfo; + +extern _X_EXPORT void InitOutput( + ScreenInfo * /*pScreenInfo*/, + int /*argc*/, + char ** /*argv*/); + +#endif /* SCREENINTSTRUCT_H */ diff --git a/xorg-server/mi/miarc.c b/xorg-server/mi/miarc.c index d182d2592..3b4a628e4 100644 --- a/xorg-server/mi/miarc.c +++ b/xorg-server/mi/miarc.c @@ -213,16 +213,6 @@ typedef struct _miPolyArc { miArcJoinPtr joins; } miPolyArcRec, *miPolyArcPtr; -#define GCValsFunction 0 -#define GCValsForeground 1 -#define GCValsBackground 2 -#define GCValsLineWidth 3 -#define GCValsCapStyle 4 -#define GCValsJoinStyle 5 -#define GCValsMask (GCFunction | GCForeground | GCBackground | \ - GCLineWidth | GCCapStyle | GCJoinStyle) -static CARD32 gcvals[6]; - static void fillSpans(DrawablePtr pDrawable, GCPtr pGC); static void newFinalSpan(int y, int xmin, int xmax); static void drawArc(xArc *tarc, int l, int a0, int a1, miArcFacePtr right, @@ -800,7 +790,7 @@ miComputeWideEllipse(int lw, xArc *parc) if (!lw) lw = 1; k = (parc->height >> 1) + ((lw - 1) >> 1); - spdata = xalloc(sizeof(miArcSpanData) + sizeof(miArcSpan) * (k + 2)); + spdata = malloc(sizeof(miArcSpanData) + sizeof(miArcSpan) * (k + 2)); if (!spdata) return NULL; spdata->spans = (miArcSpan *)(spdata + 1); @@ -831,14 +821,14 @@ miFillWideEllipse( yorgu = parc->height + pGC->lineWidth; n = (sizeof(int) * 2) * yorgu; - widths = xalloc(n + (sizeof(DDXPointRec) * 2) * yorgu); + widths = malloc(n + (sizeof(DDXPointRec) * 2) * yorgu); if (!widths) return; points = (DDXPointPtr)((char *)widths + n); spdata = miComputeWideEllipse((int)pGC->lineWidth, parc); if (!spdata) { - xfree(widths); + free(widths); return; } pts = points; @@ -927,10 +917,10 @@ miFillWideEllipse( wids += 2; } } - xfree(spdata); + free(spdata); (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); - xfree(widths); + free(widths); } /* @@ -1045,13 +1035,18 @@ miPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) pGCTo = GetScratchGC(1, pDraw->pScreen); if (!pGCTo) return; - gcvals[GCValsFunction] = GXcopy; - gcvals[GCValsForeground] = 1; - gcvals[GCValsBackground] = 0; - gcvals[GCValsLineWidth] = pGC->lineWidth; - gcvals[GCValsCapStyle] = pGC->capStyle; - gcvals[GCValsJoinStyle] = pGC->joinStyle; - dixChangeGC(NullClient, pGCTo, GCValsMask, gcvals, NULL); + { + ChangeGCVal gcvals[6]; + gcvals[0].val = GXcopy; + gcvals[1].val = 1; + gcvals[2].val = 0; + gcvals[3].val = pGC->lineWidth; + gcvals[4].val = pGC->capStyle; + gcvals[5].val = pGC->joinStyle; + ChangeGC(NullClient, pGCTo, GCFunction | + GCForeground | GCBackground | GCLineWidth | + GCCapStyle | GCJoinStyle, gcvals); + } /* allocate a 1 bit deep pixmap of the appropriate size, and * validate it */ @@ -1090,11 +1085,14 @@ miPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) iphase >= 0; iphase--) { + ChangeGCVal gcval; if (iphase == 1) { - dixChangeGC (NullClient, pGC, GCForeground, &bg, NULL); + gcval.val = bg; + ChangeGC (NullClient, pGC, GCForeground, &gcval); ValidateGC (pDraw, pGC); } else if (pGC->lineStyle == LineDoubleDash) { - dixChangeGC (NullClient, pGC, GCForeground, &fg, NULL); + gcval.val = fg; + ChangeGC (NullClient, pGC, GCForeground, &gcval); ValidateGC (pDraw, pGC); } for (i = 0; i < polyArcs[iphase].narcs; i++) { @@ -1266,7 +1264,7 @@ miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, arc.height = width; arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x); arc.angle2 = a; - pArcPts = xalloc (3 * sizeof (SppPointRec)); + pArcPts = malloc(3 * sizeof (SppPointRec)); if (!pArcPts) return; pArcPts[0].x = otherCorner.x; @@ -1282,7 +1280,7 @@ miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, * rest of the line */ miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans); } - xfree(pArcPts); + free(pArcPts); return; case JoinMiter: /* @@ -1413,7 +1411,7 @@ miRoundCap( * rest of the line */ miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans); } - xfree(pArcPts); + free(pArcPts); } /* @@ -1511,10 +1509,10 @@ miDatan2 (double dy, double dx) * This procedure allocates the space necessary to fit the arc points. * Sometimes it's convenient for those points to be at the end of an existing * array. (For example, if we want to leave a spare point to make sectors - * instead of segments.) So we pass in the xalloc()ed chunk that contains the + * instead of segments.) So we pass in the malloc()ed chunk that contains the * array and an index saying where we should start stashing the points. * If there isn't an array already, we just pass in a null pointer and - * count on xrealloc() to handle the null pointer correctly. + * count on realloc() to handle the null pointer correctly. */ static int miGetArcPts( @@ -1561,7 +1559,7 @@ miGetArcPts( count++; cdt = 2 * miDcos(dt); - if (!(poly = (SppPointPtr) xrealloc((pointer)*ppPts, + if (!(poly = (SppPointPtr) realloc((pointer)*ppPts, (cpt + count) * sizeof(SppPointRec)))) return(0); *ppPts = poly; @@ -1624,7 +1622,7 @@ addCap ( if (*ncapsp == *sizep) { newsize = *sizep + ADD_REALLOC_STEP; - cap = (miArcCapPtr) xrealloc (*capsp, + cap = (miArcCapPtr) realloc(*capsp, newsize * sizeof (**capsp)); if (!cap) return; @@ -1655,7 +1653,7 @@ addJoin ( if (*njoinsp == *sizep) { newsize = *sizep + ADD_REALLOC_STEP; - join = (miArcJoinPtr) xrealloc (*joinsp, + join = (miArcJoinPtr) realloc(*joinsp, newsize * sizeof (**joinsp)); if (!join) return; @@ -1685,7 +1683,7 @@ addArc ( if (*narcsp == *sizep) { newsize = *sizep + ADD_REALLOC_STEP; - arc = (miArcDataPtr) xrealloc (*arcsp, + arc = (miArcDataPtr) realloc(*arcsp, newsize * sizeof (**arcsp)); if (!arc) return NULL; @@ -1710,13 +1708,13 @@ miFreeArcs( iphase--) { if (arcs[iphase].narcs > 0) - xfree(arcs[iphase].arcs); + free(arcs[iphase].arcs); if (arcs[iphase].njoins > 0) - xfree(arcs[iphase].joins); + free(arcs[iphase].joins); if (arcs[iphase].ncaps > 0) - xfree(arcs[iphase].caps); + free(arcs[iphase].caps); } - xfree(arcs); + free(arcs); } /* @@ -1800,13 +1798,13 @@ miComputeArcs ( isDoubleDash = (pGC->lineStyle == LineDoubleDash); dashOffset = pGC->dashOffset; - data = xalloc (narcs * sizeof (struct arcData)); + data = malloc(narcs * sizeof (struct arcData)); if (!data) return NULL; - arcs = xalloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1)); + arcs = malloc(sizeof (*arcs) * (isDoubleDash ? 2 : 1)); if (!arcs) { - xfree(data); + free(data); return NULL; } for (i = 0; i < narcs; i++) { @@ -2155,11 +2153,11 @@ miComputeArcs ( arcs[iphase].arcs[arcs[iphase].narcs-1].cap = arcs[iphase].ncaps; } - xfree(data); + free(data); return arcs; arcfail: miFreeArcs(arcs, pGC); - xfree(data); + free(data); return NULL; } @@ -3016,7 +3014,7 @@ realAllocSpan (void) struct finalSpan *span; int i; - newChunk = xalloc (sizeof (struct finalSpanChunk)); + newChunk = malloc(sizeof (struct finalSpanChunk)); if (!newChunk) return (struct finalSpan *) NULL; newChunk->next = chunks; @@ -3039,11 +3037,11 @@ disposeFinalSpans (void) for (chunk = chunks; chunk; chunk = next) { next = chunk->next; - xfree (chunk); + free(chunk); } chunks = 0; freeFinalSpans = 0; - xfree(finalSpans); + free(finalSpans); finalSpans = 0; } @@ -3063,8 +3061,8 @@ fillSpans ( if (nspans == 0) return; - xSpan = xSpans = xalloc (nspans * sizeof (DDXPointRec)); - xWidth = xWidths = xalloc (nspans * sizeof (int)); + xSpan = xSpans = malloc(nspans * sizeof (DDXPointRec)); + xWidth = xWidths = malloc(nspans * sizeof (int)); if (xSpans && xWidths) { i = 0; @@ -3084,9 +3082,9 @@ fillSpans ( } disposeFinalSpans (); if (xSpans) - xfree (xSpans); + free(xSpans); if (xWidths) - xfree (xWidths); + free(xWidths); finalMiny = 0; finalMaxy = -1; finalSize = 0; @@ -3121,7 +3119,7 @@ realFindSpan (int y) else change = SPAN_REALLOC; newSize = finalSize + change; - newSpans = xalloc(newSize * sizeof (struct finalSpan *)); + newSpans = malloc(newSize * sizeof (struct finalSpan *)); if (!newSpans) return NULL; newMiny = finalMiny; @@ -3134,7 +3132,7 @@ realFindSpan (int y) memmove(((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *), (char *) finalSpans, finalSize * sizeof (struct finalSpan *)); - xfree (finalSpans); + free(finalSpans); } if ((i = finalMiny - newMiny) > 0) bzero ((char *)newSpans, i * sizeof (struct finalSpan *)); @@ -3477,7 +3475,7 @@ drawArc ( left->counterClock = temp; } } - xfree(spdata); + free(spdata); } static void diff --git a/xorg-server/mi/mibitblt.c b/xorg-server/mi/mibitblt.c index cc8b11d9c..b1e188d5a 100644 --- a/xorg-server/mi/mibitblt.c +++ b/xorg-server/mi/mibitblt.c @@ -1,831 +1,830 @@ -/*********************************************************** - -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. - -******************************************************************/ -/* Author: Todd Newman (aided and abetted by Mr. Drewry) */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xprotostr.h> - -#include "misc.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "scrnintstr.h" -#include "mi.h" -#include "regionstr.h" -#include <X11/Xmd.h> -#include "servermd.h" - -#ifndef HAS_FFS -extern int ffs(int); -#endif - -/* MICOPYAREA -- public entry for the CopyArea request - * For each rectangle in the source region - * get the pixels with GetSpans - * set them in the destination with SetSpans - * We let SetSpans worry about clipping to the destination. - */ -RegionPtr -miCopyArea(DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - int xIn, - int yIn, - int widthSrc, - int heightSrc, - int xOut, - int yOut) -{ - DDXPointPtr ppt, pptFirst; - unsigned int *pwidthFirst, *pwidth, *pbits; - BoxRec srcBox, *prect; - /* may be a new region, or just a copy */ - RegionPtr prgnSrcClip; - /* non-0 if we've created a src clip */ - RegionPtr prgnExposed; - int realSrcClip = 0; - int srcx, srcy, dstx, dsty, i, j, y, width, height, - xMin, xMax, yMin, yMax; - unsigned int *ordering; - int numRects; - BoxPtr boxes; - - srcx = xIn + pSrcDrawable->x; - srcy = yIn + pSrcDrawable->y; - - /* If the destination isn't realized, this is easy */ - if (pDstDrawable->type == DRAWABLE_WINDOW && - !((WindowPtr)pDstDrawable)->realized) - return NULL; - - /* clip the source */ - if (pSrcDrawable->type == DRAWABLE_PIXMAP) - { - BoxRec box; - - box.x1 = pSrcDrawable->x; - box.y1 = pSrcDrawable->y; - box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; - box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; - - prgnSrcClip = REGION_CREATE(pGC->pScreen, &box, 1); - realSrcClip = 1; - } - else - { - if (pGC->subWindowMode == IncludeInferiors) { - prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable); - realSrcClip = 1; - } else - prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; - } - - /* If the src drawable is a window, we need to translate the srcBox so - * that we can compare it with the window's clip region later on. */ - srcBox.x1 = srcx; - srcBox.y1 = srcy; - srcBox.x2 = srcx + widthSrc; - srcBox.y2 = srcy + heightSrc; - - dstx = xOut; - dsty = yOut; - if (pGC->miTranslate) - { - dstx += pDstDrawable->x; - dsty += pDstDrawable->y; - } - - pptFirst = ppt = xalloc(heightSrc * sizeof(DDXPointRec)); - pwidthFirst = pwidth = xalloc(heightSrc * sizeof(unsigned int)); - numRects = REGION_NUM_RECTS(prgnSrcClip); - boxes = REGION_RECTS(prgnSrcClip); - ordering = xalloc(numRects * sizeof(unsigned int)); - if(!pptFirst || !pwidthFirst || !ordering) - { - if (ordering) - xfree(ordering); - if (pwidthFirst) - xfree(pwidthFirst); - if (pptFirst) - xfree(pptFirst); - return NULL; - } - - /* If not the same drawable then order of move doesn't matter. - Following assumes that boxes are sorted from top - to bottom and left to right. - */ - if ((pSrcDrawable != pDstDrawable) && - ((pGC->subWindowMode != IncludeInferiors) || - (pSrcDrawable->type == DRAWABLE_PIXMAP) || - (pDstDrawable->type == DRAWABLE_PIXMAP))) - for (i=0; i < numRects; i++) - ordering[i] = i; - else { /* within same drawable, must sequence moves carefully! */ - if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical. - Vertical order OK */ - if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal. - Horizontal order OK as well */ - for (i=0; i < numRects; i++) - ordering[i] = i; - else { /* scroll right. must reverse horizontal banding of rects. */ - for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) { - /* find extent of current horizontal band */ - y=boxes[i].y1; /* band has this y coordinate */ - while ((j < numRects) && (boxes[j].y1 == y)) - j++; - /* reverse the horizontal band in the output ordering */ - for (j-- ; j >= xMax; j--, i++) - ordering[i] = j; - } - } - } - else { /* Scroll down. Must reverse vertical banding. */ - if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */ - for (i=numRects-1, j=i-1, yMin=i, yMax=0; - i >= 0; - j=i-1, yMin=i) { - /* find extent of current horizontal band */ - y=boxes[i].y1; /* band has this y coordinate */ - while ((j >= 0) && (boxes[j].y1 == y)) - j--; - /* reverse the horizontal band in the output ordering */ - for (j++ ; j <= yMin; j++, i--, yMax++) - ordering[yMax] = j; - } - } - else /* Scroll right or horizontal stationary. - Reverse horizontal order as well (if stationary, horizontal - order can be swapped without penalty and this is faster - to compute). */ - for (i=0, j=numRects-1; i < numRects; i++, j--) - ordering[i] = j; - } - } - - for(i = 0; i < numRects; i++) - { - prect = &boxes[ordering[i]]; - xMin = max(prect->x1, srcBox.x1); - xMax = min(prect->x2, srcBox.x2); - yMin = max(prect->y1, srcBox.y1); - yMax = min(prect->y2, srcBox.y2); - /* is there anything visible here? */ - if(xMax <= xMin || yMax <= yMin) - continue; - - ppt = pptFirst; - pwidth = pwidthFirst; - y = yMin; - height = yMax - yMin; - width = xMax - xMin; - - for(j = 0; j < height; j++) - { - /* We must untranslate before calling GetSpans */ - ppt->x = xMin; - ppt++->y = y++; - *pwidth++ = width; - } - pbits = xalloc(height * PixmapBytePad(width, pSrcDrawable->depth)); - if (pbits) - { - (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst, - (int *)pwidthFirst, height, (char *)pbits); - ppt = pptFirst; - pwidth = pwidthFirst; - xMin -= (srcx - dstx); - y = yMin - (srcy - dsty); - for(j = 0; j < height; j++) - { - ppt->x = xMin; - ppt++->y = y++; - *pwidth++ = width; - } - - (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst, - (int *)pwidthFirst, height, TRUE); - xfree(pbits); - } - } - prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, - widthSrc, heightSrc, xOut, yOut, (unsigned long)0); - if(realSrcClip) - REGION_DESTROY(pGC->pScreen, prgnSrcClip); - - xfree(ordering); - xfree(pwidthFirst); - xfree(pptFirst); - return prgnExposed; -} - -/* MIGETPLANE -- gets a bitmap representing one plane of pDraw - * A helper used for CopyPlane and XY format GetImage - * No clever strategy here, we grab a scanline at a time, pull out the - * bits and then stuff them in a 1 bit deep map. - */ -/* - * This should be replaced with something more general. mi shouldn't have to - * care about such things as scanline padding et alia. - */ -static -MiBits * -miGetPlane( - DrawablePtr pDraw, - int planeNum, /* number of the bitPlane */ - int sx, - int sy, - int w, - int h, - MiBits *result) -{ - int i, j, k, width, bitsPerPixel, widthInBytes; - DDXPointRec pt = {0, 0}; - MiBits pixel; - MiBits bit; - unsigned char *pCharsOut = NULL; - -#if BITMAP_SCANLINE_UNIT == 8 -#define OUT_TYPE unsigned char -#endif -#if BITMAP_SCANLINE_UNIT == 16 -#define OUT_TYPE CARD16 -#endif -#if BITMAP_SCANLINE_UNIT == 32 -#define OUT_TYPE CARD32 -#endif -#if BITMAP_SCANLINE_UNIT == 64 -#define OUT_TYPE CARD64 -#endif - - OUT_TYPE *pOut; - int delta = 0; - - sx += pDraw->x; - sy += pDraw->y; - widthInBytes = BitmapBytePad(w); - if(!result) - result = xcalloc(h, widthInBytes); - if (!result) - return NULL; - bitsPerPixel = pDraw->bitsPerPixel; - pOut = (OUT_TYPE *) result; - if(bitsPerPixel == 1) - { - pCharsOut = (unsigned char *) result; - width = w; - } - else - { - delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) - - (w / BITMAP_SCANLINE_UNIT); - width = 1; -#if IMAGE_BYTE_ORDER == MSBFirst - planeNum += (32 - bitsPerPixel); -#endif - } - pt.y = sy; - for (i = h; --i >= 0; pt.y++) - { - pt.x = sx; - if(bitsPerPixel == 1) - { - (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, - (char *)pCharsOut); - pCharsOut += widthInBytes; - } - else - { - k = 0; - for(j = w; --j >= 0; pt.x++) - { - /* Fetch the next pixel */ - (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, - (char *)&pixel); - /* - * Now get the bit and insert into a bitmap in XY format. - */ - bit = (pixel >> planeNum) & 1; -#if 0 - /* XXX assuming bit order == byte order */ -#if BITMAP_BIT_ORDER == LSBFirst - bit <<= k; -#else - bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k); -#endif -#else - /* XXX assuming byte order == LSBFirst */ - if (screenInfo.bitmapBitOrder == LSBFirst) - bit <<= k; - else - bit <<= ((screenInfo.bitmapScanlineUnit - 1) - - (k % screenInfo.bitmapScanlineUnit)) + - ((k / screenInfo.bitmapScanlineUnit) * - screenInfo.bitmapScanlineUnit); -#endif - *pOut |= (OUT_TYPE) bit; - k++; - if (k == BITMAP_SCANLINE_UNIT) - { - pOut++; - k = 0; - } - } - pOut += delta; - } - } - return(result); - -} - -/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw. - * Drawing through the clip mask we SetSpans() the bits into a - * bitmap and stipple those bits onto the destination drawable by doing a - * PolyFillRect over the whole drawable, - * then we invert the bitmap by copying it onto itself with an alu of - * GXinvert, invert the foreground/background colors of the gc, and draw - * the background bits. - * Note how the clipped out bits of the bitmap are always the background - * color so that the stipple never causes FillRect to draw them. - */ -static void -miOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc, - MiBits *pbits, int srcx, int w, int h, int dstx, int dsty) -{ - int oldfill, i; - unsigned long oldfg; - int *pwidth, *pwidthFirst; - ChangeGCVal gcv[6]; - PixmapPtr pStipple, pPixmap; - DDXPointRec oldOrg; - GCPtr pGCT; - DDXPointPtr ppt, pptFirst; - xRectangle rect; - RegionPtr prgnSrcClip; - - pPixmap = (*pDraw->pScreen->CreatePixmap) - (pDraw->pScreen, w + srcx, h, 1, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pPixmap) - return; - - /* Put the image into a 1 bit deep pixmap */ - pGCT = GetScratchGC(1, pDraw->pScreen); - if (!pGCT) - { - (*pDraw->pScreen->DestroyPixmap)(pPixmap); - return; - } - /* First set the whole pixmap to 0 */ - gcv[0].val = 0; - dixChangeGC(NullClient, pGCT, GCBackground, NULL, gcv); - ValidateGC((DrawablePtr)pPixmap, pGCT); - miClearDrawable((DrawablePtr)pPixmap, pGCT); - ppt = pptFirst = xalloc(h * sizeof(DDXPointRec)); - pwidth = pwidthFirst = xalloc(h * sizeof(int)); - if(!pptFirst || !pwidthFirst) - { - if (pwidthFirst) xfree(pwidthFirst); - if (pptFirst) xfree(pptFirst); - FreeScratchGC(pGCT); - return; - } - - /* we need a temporary region because ChangeClip must be assumed - to destroy what it's sent. note that this means we don't - have to free prgnSrcClip ourselves. - */ - prgnSrcClip = REGION_CREATE(pGCT->pScreen, NULL, 0); - REGION_COPY(pGCT->pScreen, prgnSrcClip, prgnSrc); - REGION_TRANSLATE(pGCT->pScreen, prgnSrcClip, srcx, 0); - (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0); - ValidateGC((DrawablePtr)pPixmap, pGCT); - - /* Since we know pDraw is always a pixmap, we never need to think - * about translation here */ - for(i = 0; i < h; i++) - { - ppt->x = 0; - ppt++->y = i; - *pwidth++ = w + srcx; - } - - (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits, - pptFirst, pwidthFirst, h, TRUE); - xfree(pwidthFirst); - xfree(pptFirst); - - - /* Save current values from the client GC */ - oldfill = pGC->fillStyle; - pStipple = pGC->stipple; - if(pStipple) - pStipple->refcnt++; - oldOrg = pGC->patOrg; - - /* Set a new stipple in the drawable */ - gcv[0].val = FillStippled; - gcv[1].ptr = pPixmap; - gcv[2].val = dstx - srcx; - gcv[3].val = dsty; - - dixChangeGC(NullClient, pGC, - GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, - NULL, gcv); - ValidateGC(pDraw, pGC); - - /* Fill the drawable with the stipple. This will draw the - * foreground color whereever 1 bits are set, leaving everything - * with 0 bits untouched. Note that the part outside the clip - * region is all 0s. */ - rect.x = dstx; - rect.y = dsty; - rect.width = w; - rect.height = h; - (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); - - /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only - * within the clipping region, the part outside is still all 0s */ - gcv[0].val = GXinvert; - dixChangeGC(NullClient, pGCT, GCFunction, NULL, gcv); - ValidateGC((DrawablePtr)pPixmap, pGCT); - (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap, - pGCT, 0, 0, w + srcx, h, 0, 0); - - /* Swap foreground and background colors on the GC for the drawable. - * Now when we fill the drawable, we will fill in the "Background" - * values */ - oldfg = pGC->fgPixel; - gcv[0].val = pGC->bgPixel; - gcv[1].val = oldfg; - gcv[2].ptr = pPixmap; - dixChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, - NULL, gcv); - ValidateGC(pDraw, pGC); - /* PolyFillRect might have bashed the rectangle */ - rect.x = dstx; - rect.y = dsty; - rect.width = w; - rect.height = h; - (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); - - /* Now put things back */ - if(pStipple) - pStipple->refcnt--; - gcv[0].val = oldfg; - gcv[1].val = pGC->fgPixel; - gcv[2].val = oldfill; - gcv[3].ptr = pStipple; - gcv[4].val = oldOrg.x; - gcv[5].val = oldOrg.y; - dixChangeGC(NullClient, pGC, - GCForeground | GCBackground | GCFillStyle | GCStipple | - GCTileStipXOrigin | GCTileStipYOrigin, NULL, gcv); - - ValidateGC(pDraw, pGC); - /* put what we hope is a smaller clip region back in the scratch gc */ - (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0); - FreeScratchGC(pGCT); - (*pDraw->pScreen->DestroyPixmap)(pPixmap); - -} - -/* MICOPYPLANE -- public entry for the CopyPlane request. - * strategy: - * First build up a bitmap out of the bits requested - * build a source clip - * Use the bitmap we've built up as a Stipple for the destination - */ -RegionPtr -miCopyPlane( DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - int srcx, - int srcy, - int width, - int height, - int dstx, - int dsty, - unsigned long bitPlane) -{ - MiBits *ptile; - BoxRec box; - RegionPtr prgnSrc, prgnExposed; - - /* incorporate the source clip */ - - box.x1 = srcx + pSrcDrawable->x; - box.y1 = srcy + pSrcDrawable->y; - box.x2 = box.x1 + width; - box.y2 = box.y1 + height; - /* clip to visible drawable */ - if (box.x1 < pSrcDrawable->x) - box.x1 = pSrcDrawable->x; - if (box.y1 < pSrcDrawable->y) - box.y1 = pSrcDrawable->y; - if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) - box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; - if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) - box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; - if (box.x1 > box.x2) - box.x2 = box.x1; - if (box.y1 > box.y2) - box.y2 = box.y1; - prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1); - - if (pSrcDrawable->type != DRAWABLE_PIXMAP) { - /* clip to visible drawable */ - - if (pGC->subWindowMode == IncludeInferiors) - { - RegionPtr clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable); - REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, clipList); - REGION_DESTROY(pGC->pScreen, clipList); - } else - REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, - &((WindowPtr)pSrcDrawable)->clipList); - } - - box = *REGION_EXTENTS(pGC->pScreen, prgnSrc); - REGION_TRANSLATE(pGC->pScreen, prgnSrc, -box.x1, -box.y1); - - if ((box.x2 > box.x1) && (box.y2 > box.y1)) - { - /* minimize the size of the data extracted */ - /* note that we convert the plane mask bitPlane into a plane number */ - box.x1 -= pSrcDrawable->x; - box.x2 -= pSrcDrawable->x; - box.y1 -= pSrcDrawable->y; - box.y2 -= pSrcDrawable->y; - ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1, - box.x1, box.y1, - box.x2 - box.x1, box.y2 - box.y1, - (MiBits *) NULL); - if (ptile) - { - miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0, - box.x2 - box.x1, box.y2 - box.y1, - dstx + box.x1 - srcx, dsty + box.y1 - srcy); - xfree(ptile); - } - } - prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, - width, height, dstx, dsty, bitPlane); - REGION_DESTROY(pGC->pScreen, prgnSrc); - return prgnExposed; -} - -/* MIGETIMAGE -- public entry for the GetImage Request - * We're getting the image into a memory buffer. While we have to use GetSpans - * to read a line from the device (since we don't know what that looks like), - * we can just write into the destination buffer - * - * two different strategies are used, depending on whether we're getting the - * image in Z format or XY format - * Z format: - * Line at a time, GetSpans a line into the destination buffer, then if the - * planemask is not all ones, we do a SetSpans into a temporary buffer (to get - * bits turned off) and then another GetSpans to get stuff back (because - * pixmaps are opaque, and we are passed in the memory to write into). This is - * pretty ugly and slow but works. Life is hard. - * XY format: - * get the single plane specified in planemask - */ -void -miGetImage( DrawablePtr pDraw, int sx, int sy, int w, int h, - unsigned int format, unsigned long planeMask, char *pDst) -{ - unsigned char depth; - int i, linelength, width, srcx, srcy; - DDXPointRec pt = {0, 0}; - XID gcv[2]; - PixmapPtr pPixmap = NULL; - GCPtr pGC = NULL; - - depth = pDraw->depth; - if(format == ZPixmap) - { - if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 ) - { - xPoint pt; - - pGC = GetScratchGC(depth, pDraw->pScreen); - if (!pGC) - return; - pPixmap = (*pDraw->pScreen->CreatePixmap) - (pDraw->pScreen, w, 1, depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pPixmap) - { - FreeScratchGC(pGC); - return; - } - /* - * Clear the pixmap before doing anything else - */ - ValidateGC((DrawablePtr)pPixmap, pGC); - pt.x = pt.y = 0; - width = w; - (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width, - TRUE); - - /* alu is already GXCopy */ - gcv[0] = (XID)planeMask; - DoChangeGC(pGC, GCPlaneMask, gcv, 0); - ValidateGC((DrawablePtr)pPixmap, pGC); - } - - linelength = PixmapBytePad(w, depth); - srcx = sx + pDraw->x; - srcy = sy + pDraw->y; - for(i = 0; i < h; i++) - { - pt.x = srcx; - pt.y = srcy + i; - width = w; - (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst); - if (pPixmap) - { - pt.x = 0; - pt.y = 0; - width = w; - (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst, - &pt, &width, 1, TRUE); - (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt, - &width, 1, pDst); - } - pDst += linelength; - } - if (pPixmap) - { - (*pGC->pScreen->DestroyPixmap)(pPixmap); - FreeScratchGC(pGC); - } - } - else - { - (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h, - (MiBits *)pDst); - } -} - -/* MIPUTIMAGE -- public entry for the PutImage request - * Here we benefit from knowing the format of the bits pointed to by pImage, - * even if we don't know how pDraw represents them. - * Three different strategies are used depending on the format - * XYBitmap Format: - * we just use the Opaque Stipple helper function to cover the destination - * Note that this covers all the planes of the drawable with the - * foreground color (masked with the GC planemask) where there are 1 bits - * and the background color (masked with the GC planemask) where there are - * 0 bits - * XYPixmap format: - * what we're called with is a series of XYBitmaps, but we only want - * each XYPixmap to update 1 plane, instead of updating all of them. - * we set the foreground color to be all 1s and the background to all 0s - * then for each plane, we set the plane mask to only effect that one - * plane and recursive call ourself with the format set to XYBitmap - * (This clever idea courtesy of RGD.) - * ZPixmap format: - * This part is simple, just call SetSpans - */ -void -miPutImage( DrawablePtr pDraw, GCPtr pGC, int depth, - int x, int y, int w, int h, - int leftPad, int format, char *pImage) -{ - DDXPointPtr pptFirst, ppt; - int *pwidthFirst, *pwidth; - RegionPtr prgnSrc; - BoxRec box; - unsigned long oldFg, oldBg; - XID gcv[3]; - unsigned long oldPlanemask; - unsigned long i; - long bytesPer; - - if (!w || !h) - return; - switch(format) - { - case XYBitmap: - - box.x1 = 0; - box.y1 = 0; - box.x2 = w; - box.y2 = h; - prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1); - - miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage, - leftPad, w, h, x, y); - REGION_DESTROY(pGC->pScreen, prgnSrc); - break; - - case XYPixmap: - depth = pGC->depth; - oldPlanemask = pGC->planemask; - oldFg = pGC->fgPixel; - oldBg = pGC->bgPixel; - gcv[0] = (XID)~0; - gcv[1] = (XID)0; - DoChangeGC(pGC, GCForeground | GCBackground, gcv, 0); - bytesPer = (long)h * BitmapBytePad(w + leftPad); - - for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer) - { - if (i & oldPlanemask) - { - gcv[0] = (XID)i; - DoChangeGC(pGC, GCPlaneMask, gcv, 0); - ValidateGC(pDraw, pGC); - (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad, - XYBitmap, (char *)pImage); - } - } - gcv[0] = (XID)oldPlanemask; - gcv[1] = (XID)oldFg; - gcv[2] = (XID)oldBg; - DoChangeGC(pGC, GCPlaneMask | GCForeground | GCBackground, gcv, 0); - ValidateGC(pDraw, pGC); - break; - - case ZPixmap: - ppt = pptFirst = xalloc(h * sizeof(DDXPointRec)); - pwidth = pwidthFirst = xalloc(h * sizeof(int)); - if(!pptFirst || !pwidthFirst) - { - if (pwidthFirst) - xfree(pwidthFirst); - if (pptFirst) - xfree(pptFirst); - return; - } - if (pGC->miTranslate) - { - x += pDraw->x; - y += pDraw->y; - } - - for(i = 0; i < h; i++) - { - ppt->x = x; - ppt->y = y + i; - ppt++; - *pwidth++ = w; - } - - (*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst, - pwidthFirst, h, TRUE); - xfree(pwidthFirst); - xfree(pptFirst); - break; - } -} +/*********************************************************** + +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. + +******************************************************************/ +/* Author: Todd Newman (aided and abetted by Mr. Drewry) */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xprotostr.h> + +#include "misc.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "mi.h" +#include "regionstr.h" +#include <X11/Xmd.h> +#include "servermd.h" + +#ifndef HAS_FFS +extern int ffs(int); +#endif + +/* MICOPYAREA -- public entry for the CopyArea request + * For each rectangle in the source region + * get the pixels with GetSpans + * set them in the destination with SetSpans + * We let SetSpans worry about clipping to the destination. + */ +RegionPtr +miCopyArea(DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int yOut) +{ + DDXPointPtr ppt, pptFirst; + unsigned int *pwidthFirst, *pwidth, *pbits; + BoxRec srcBox, *prect; + /* may be a new region, or just a copy */ + RegionPtr prgnSrcClip; + /* non-0 if we've created a src clip */ + RegionPtr prgnExposed; + int realSrcClip = 0; + int srcx, srcy, dstx, dsty, i, j, y, width, height, + xMin, xMax, yMin, yMax; + unsigned int *ordering; + int numRects; + BoxPtr boxes; + + srcx = xIn + pSrcDrawable->x; + srcy = yIn + pSrcDrawable->y; + + /* If the destination isn't realized, this is easy */ + if (pDstDrawable->type == DRAWABLE_WINDOW && + !((WindowPtr)pDstDrawable)->realized) + return NULL; + + /* clip the source */ + if (pSrcDrawable->type == DRAWABLE_PIXMAP) + { + BoxRec box; + + box.x1 = pSrcDrawable->x; + box.y1 = pSrcDrawable->y; + box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; + box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; + + prgnSrcClip = REGION_CREATE(pGC->pScreen, &box, 1); + realSrcClip = 1; + } + else + { + if (pGC->subWindowMode == IncludeInferiors) { + prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable); + realSrcClip = 1; + } else + prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; + } + + /* If the src drawable is a window, we need to translate the srcBox so + * that we can compare it with the window's clip region later on. */ + srcBox.x1 = srcx; + srcBox.y1 = srcy; + srcBox.x2 = srcx + widthSrc; + srcBox.y2 = srcy + heightSrc; + + dstx = xOut; + dsty = yOut; + if (pGC->miTranslate) + { + dstx += pDstDrawable->x; + dsty += pDstDrawable->y; + } + + pptFirst = ppt = malloc(heightSrc * sizeof(DDXPointRec)); + pwidthFirst = pwidth = malloc(heightSrc * sizeof(unsigned int)); + numRects = REGION_NUM_RECTS(prgnSrcClip); + boxes = REGION_RECTS(prgnSrcClip); + ordering = malloc(numRects * sizeof(unsigned int)); + if(!pptFirst || !pwidthFirst || !ordering) + { + if (ordering) + free(ordering); + if (pwidthFirst) + free(pwidthFirst); + if (pptFirst) + free(pptFirst); + return NULL; + } + + /* If not the same drawable then order of move doesn't matter. + Following assumes that boxes are sorted from top + to bottom and left to right. + */ + if ((pSrcDrawable != pDstDrawable) && + ((pGC->subWindowMode != IncludeInferiors) || + (pSrcDrawable->type == DRAWABLE_PIXMAP) || + (pDstDrawable->type == DRAWABLE_PIXMAP))) + for (i=0; i < numRects; i++) + ordering[i] = i; + else { /* within same drawable, must sequence moves carefully! */ + if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical. + Vertical order OK */ + if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal. + Horizontal order OK as well */ + for (i=0; i < numRects; i++) + ordering[i] = i; + else { /* scroll right. must reverse horizontal banding of rects. */ + for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) { + /* find extent of current horizontal band */ + y=boxes[i].y1; /* band has this y coordinate */ + while ((j < numRects) && (boxes[j].y1 == y)) + j++; + /* reverse the horizontal band in the output ordering */ + for (j-- ; j >= xMax; j--, i++) + ordering[i] = j; + } + } + } + else { /* Scroll down. Must reverse vertical banding. */ + if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */ + for (i=numRects-1, j=i-1, yMin=i, yMax=0; + i >= 0; + j=i-1, yMin=i) { + /* find extent of current horizontal band */ + y=boxes[i].y1; /* band has this y coordinate */ + while ((j >= 0) && (boxes[j].y1 == y)) + j--; + /* reverse the horizontal band in the output ordering */ + for (j++ ; j <= yMin; j++, i--, yMax++) + ordering[yMax] = j; + } + } + else /* Scroll right or horizontal stationary. + Reverse horizontal order as well (if stationary, horizontal + order can be swapped without penalty and this is faster + to compute). */ + for (i=0, j=numRects-1; i < numRects; i++, j--) + ordering[i] = j; + } + } + + for(i = 0; i < numRects; i++) + { + prect = &boxes[ordering[i]]; + xMin = max(prect->x1, srcBox.x1); + xMax = min(prect->x2, srcBox.x2); + yMin = max(prect->y1, srcBox.y1); + yMax = min(prect->y2, srcBox.y2); + /* is there anything visible here? */ + if(xMax <= xMin || yMax <= yMin) + continue; + + ppt = pptFirst; + pwidth = pwidthFirst; + y = yMin; + height = yMax - yMin; + width = xMax - xMin; + + for(j = 0; j < height; j++) + { + /* We must untranslate before calling GetSpans */ + ppt->x = xMin; + ppt++->y = y++; + *pwidth++ = width; + } + pbits = malloc(height * PixmapBytePad(width, pSrcDrawable->depth)); + if (pbits) + { + (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst, + (int *)pwidthFirst, height, (char *)pbits); + ppt = pptFirst; + pwidth = pwidthFirst; + xMin -= (srcx - dstx); + y = yMin - (srcy - dsty); + for(j = 0; j < height; j++) + { + ppt->x = xMin; + ppt++->y = y++; + *pwidth++ = width; + } + + (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst, + (int *)pwidthFirst, height, TRUE); + free(pbits); + } + } + prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, + widthSrc, heightSrc, xOut, yOut, (unsigned long)0); + if(realSrcClip) + REGION_DESTROY(pGC->pScreen, prgnSrcClip); + + free(ordering); + free(pwidthFirst); + free(pptFirst); + return prgnExposed; +} + +/* MIGETPLANE -- gets a bitmap representing one plane of pDraw + * A helper used for CopyPlane and XY format GetImage + * No clever strategy here, we grab a scanline at a time, pull out the + * bits and then stuff them in a 1 bit deep map. + */ +/* + * This should be replaced with something more general. mi shouldn't have to + * care about such things as scanline padding et alia. + */ +static +MiBits * +miGetPlane( + DrawablePtr pDraw, + int planeNum, /* number of the bitPlane */ + int sx, + int sy, + int w, + int h, + MiBits *result) +{ + int i, j, k, width, bitsPerPixel, widthInBytes; + DDXPointRec pt = {0, 0}; + MiBits pixel; + MiBits bit; + unsigned char *pCharsOut = NULL; + +#if BITMAP_SCANLINE_UNIT == 8 +#define OUT_TYPE unsigned char +#endif +#if BITMAP_SCANLINE_UNIT == 16 +#define OUT_TYPE CARD16 +#endif +#if BITMAP_SCANLINE_UNIT == 32 +#define OUT_TYPE CARD32 +#endif +#if BITMAP_SCANLINE_UNIT == 64 +#define OUT_TYPE CARD64 +#endif + + OUT_TYPE *pOut; + int delta = 0; + + sx += pDraw->x; + sy += pDraw->y; + widthInBytes = BitmapBytePad(w); + if(!result) + result = calloc(h, widthInBytes); + if (!result) + return NULL; + bitsPerPixel = pDraw->bitsPerPixel; + pOut = (OUT_TYPE *) result; + if(bitsPerPixel == 1) + { + pCharsOut = (unsigned char *) result; + width = w; + } + else + { + delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) - + (w / BITMAP_SCANLINE_UNIT); + width = 1; +#if IMAGE_BYTE_ORDER == MSBFirst + planeNum += (32 - bitsPerPixel); +#endif + } + pt.y = sy; + for (i = h; --i >= 0; pt.y++) + { + pt.x = sx; + if(bitsPerPixel == 1) + { + (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, + (char *)pCharsOut); + pCharsOut += widthInBytes; + } + else + { + k = 0; + for(j = w; --j >= 0; pt.x++) + { + /* Fetch the next pixel */ + (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, + (char *)&pixel); + /* + * Now get the bit and insert into a bitmap in XY format. + */ + bit = (pixel >> planeNum) & 1; +#if 0 + /* XXX assuming bit order == byte order */ +#if BITMAP_BIT_ORDER == LSBFirst + bit <<= k; +#else + bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k); +#endif +#else + /* XXX assuming byte order == LSBFirst */ + if (screenInfo.bitmapBitOrder == LSBFirst) + bit <<= k; + else + bit <<= ((screenInfo.bitmapScanlineUnit - 1) - + (k % screenInfo.bitmapScanlineUnit)) + + ((k / screenInfo.bitmapScanlineUnit) * + screenInfo.bitmapScanlineUnit); +#endif + *pOut |= (OUT_TYPE) bit; + k++; + if (k == BITMAP_SCANLINE_UNIT) + { + pOut++; + k = 0; + } + } + pOut += delta; + } + } + return(result); + +} + +/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw. + * Drawing through the clip mask we SetSpans() the bits into a + * bitmap and stipple those bits onto the destination drawable by doing a + * PolyFillRect over the whole drawable, + * then we invert the bitmap by copying it onto itself with an alu of + * GXinvert, invert the foreground/background colors of the gc, and draw + * the background bits. + * Note how the clipped out bits of the bitmap are always the background + * color so that the stipple never causes FillRect to draw them. + */ +static void +miOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc, + MiBits *pbits, int srcx, int w, int h, int dstx, int dsty) +{ + int oldfill, i; + unsigned long oldfg; + int *pwidth, *pwidthFirst; + ChangeGCVal gcv[6]; + PixmapPtr pStipple, pPixmap; + DDXPointRec oldOrg; + GCPtr pGCT; + DDXPointPtr ppt, pptFirst; + xRectangle rect; + RegionPtr prgnSrcClip; + + pPixmap = (*pDraw->pScreen->CreatePixmap) + (pDraw->pScreen, w + srcx, h, 1, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pPixmap) + return; + + /* Put the image into a 1 bit deep pixmap */ + pGCT = GetScratchGC(1, pDraw->pScreen); + if (!pGCT) + { + (*pDraw->pScreen->DestroyPixmap)(pPixmap); + return; + } + /* First set the whole pixmap to 0 */ + gcv[0].val = 0; + ChangeGC(NullClient, pGCT, GCBackground, gcv); + ValidateGC((DrawablePtr)pPixmap, pGCT); + miClearDrawable((DrawablePtr)pPixmap, pGCT); + ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); + pwidth = pwidthFirst = malloc(h * sizeof(int)); + if(!pptFirst || !pwidthFirst) + { + if (pwidthFirst) free(pwidthFirst); + if (pptFirst) free(pptFirst); + FreeScratchGC(pGCT); + return; + } + + /* we need a temporary region because ChangeClip must be assumed + to destroy what it's sent. note that this means we don't + have to free prgnSrcClip ourselves. + */ + prgnSrcClip = REGION_CREATE(pGCT->pScreen, NULL, 0); + REGION_COPY(pGCT->pScreen, prgnSrcClip, prgnSrc); + REGION_TRANSLATE(pGCT->pScreen, prgnSrcClip, srcx, 0); + (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0); + ValidateGC((DrawablePtr)pPixmap, pGCT); + + /* Since we know pDraw is always a pixmap, we never need to think + * about translation here */ + for(i = 0; i < h; i++) + { + ppt->x = 0; + ppt++->y = i; + *pwidth++ = w + srcx; + } + + (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits, + pptFirst, pwidthFirst, h, TRUE); + free(pwidthFirst); + free(pptFirst); + + + /* Save current values from the client GC */ + oldfill = pGC->fillStyle; + pStipple = pGC->stipple; + if(pStipple) + pStipple->refcnt++; + oldOrg = pGC->patOrg; + + /* Set a new stipple in the drawable */ + gcv[0].val = FillStippled; + gcv[1].ptr = pPixmap; + gcv[2].val = dstx - srcx; + gcv[3].val = dsty; + + ChangeGC(NullClient, pGC, + GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, + gcv); + ValidateGC(pDraw, pGC); + + /* Fill the drawable with the stipple. This will draw the + * foreground color whereever 1 bits are set, leaving everything + * with 0 bits untouched. Note that the part outside the clip + * region is all 0s. */ + rect.x = dstx; + rect.y = dsty; + rect.width = w; + rect.height = h; + (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); + + /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only + * within the clipping region, the part outside is still all 0s */ + gcv[0].val = GXinvert; + ChangeGC(NullClient, pGCT, GCFunction, gcv); + ValidateGC((DrawablePtr)pPixmap, pGCT); + (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap, + pGCT, 0, 0, w + srcx, h, 0, 0); + + /* Swap foreground and background colors on the GC for the drawable. + * Now when we fill the drawable, we will fill in the "Background" + * values */ + oldfg = pGC->fgPixel; + gcv[0].val = pGC->bgPixel; + gcv[1].val = oldfg; + gcv[2].ptr = pPixmap; + ChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, gcv); + ValidateGC(pDraw, pGC); + /* PolyFillRect might have bashed the rectangle */ + rect.x = dstx; + rect.y = dsty; + rect.width = w; + rect.height = h; + (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); + + /* Now put things back */ + if(pStipple) + pStipple->refcnt--; + gcv[0].val = oldfg; + gcv[1].val = pGC->fgPixel; + gcv[2].val = oldfill; + gcv[3].ptr = pStipple; + gcv[4].val = oldOrg.x; + gcv[5].val = oldOrg.y; + ChangeGC(NullClient, pGC, + GCForeground | GCBackground | GCFillStyle | GCStipple | + GCTileStipXOrigin | GCTileStipYOrigin, gcv); + + ValidateGC(pDraw, pGC); + /* put what we hope is a smaller clip region back in the scratch gc */ + (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0); + FreeScratchGC(pGCT); + (*pDraw->pScreen->DestroyPixmap)(pPixmap); + +} + +/* MICOPYPLANE -- public entry for the CopyPlane request. + * strategy: + * First build up a bitmap out of the bits requested + * build a source clip + * Use the bitmap we've built up as a Stipple for the destination + */ +RegionPtr +miCopyPlane( DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int srcx, + int srcy, + int width, + int height, + int dstx, + int dsty, + unsigned long bitPlane) +{ + MiBits *ptile; + BoxRec box; + RegionPtr prgnSrc, prgnExposed; + + /* incorporate the source clip */ + + box.x1 = srcx + pSrcDrawable->x; + box.y1 = srcy + pSrcDrawable->y; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + /* clip to visible drawable */ + if (box.x1 < pSrcDrawable->x) + box.x1 = pSrcDrawable->x; + if (box.y1 < pSrcDrawable->y) + box.y1 = pSrcDrawable->y; + if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) + box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; + if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) + box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; + if (box.x1 > box.x2) + box.x2 = box.x1; + if (box.y1 > box.y2) + box.y2 = box.y1; + prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1); + + if (pSrcDrawable->type != DRAWABLE_PIXMAP) { + /* clip to visible drawable */ + + if (pGC->subWindowMode == IncludeInferiors) + { + RegionPtr clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable); + REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, clipList); + REGION_DESTROY(pGC->pScreen, clipList); + } else + REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, + &((WindowPtr)pSrcDrawable)->clipList); + } + + box = *REGION_EXTENTS(pGC->pScreen, prgnSrc); + REGION_TRANSLATE(pGC->pScreen, prgnSrc, -box.x1, -box.y1); + + if ((box.x2 > box.x1) && (box.y2 > box.y1)) + { + /* minimize the size of the data extracted */ + /* note that we convert the plane mask bitPlane into a plane number */ + box.x1 -= pSrcDrawable->x; + box.x2 -= pSrcDrawable->x; + box.y1 -= pSrcDrawable->y; + box.y2 -= pSrcDrawable->y; + ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1, + box.x1, box.y1, + box.x2 - box.x1, box.y2 - box.y1, + (MiBits *) NULL); + if (ptile) + { + miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0, + box.x2 - box.x1, box.y2 - box.y1, + dstx + box.x1 - srcx, dsty + box.y1 - srcy); + free(ptile); + } + } + prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, + width, height, dstx, dsty, bitPlane); + REGION_DESTROY(pGC->pScreen, prgnSrc); + return prgnExposed; +} + +/* MIGETIMAGE -- public entry for the GetImage Request + * We're getting the image into a memory buffer. While we have to use GetSpans + * to read a line from the device (since we don't know what that looks like), + * we can just write into the destination buffer + * + * two different strategies are used, depending on whether we're getting the + * image in Z format or XY format + * Z format: + * Line at a time, GetSpans a line into the destination buffer, then if the + * planemask is not all ones, we do a SetSpans into a temporary buffer (to get + * bits turned off) and then another GetSpans to get stuff back (because + * pixmaps are opaque, and we are passed in the memory to write into). This is + * pretty ugly and slow but works. Life is hard. + * XY format: + * get the single plane specified in planemask + */ +void +miGetImage( DrawablePtr pDraw, int sx, int sy, int w, int h, + unsigned int format, unsigned long planeMask, char *pDst) +{ + unsigned char depth; + int i, linelength, width, srcx, srcy; + DDXPointRec pt = {0, 0}; + PixmapPtr pPixmap = NULL; + GCPtr pGC = NULL; + + depth = pDraw->depth; + if(format == ZPixmap) + { + if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 ) + { + ChangeGCVal gcv; + xPoint pt; + + pGC = GetScratchGC(depth, pDraw->pScreen); + if (!pGC) + return; + pPixmap = (*pDraw->pScreen->CreatePixmap) + (pDraw->pScreen, w, 1, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pPixmap) + { + FreeScratchGC(pGC); + return; + } + /* + * Clear the pixmap before doing anything else + */ + ValidateGC((DrawablePtr)pPixmap, pGC); + pt.x = pt.y = 0; + width = w; + (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width, + TRUE); + + /* alu is already GXCopy */ + gcv.val = (XID)planeMask; + ChangeGC(NullClient, pGC, GCPlaneMask, &gcv); + ValidateGC((DrawablePtr)pPixmap, pGC); + } + + linelength = PixmapBytePad(w, depth); + srcx = sx + pDraw->x; + srcy = sy + pDraw->y; + for(i = 0; i < h; i++) + { + pt.x = srcx; + pt.y = srcy + i; + width = w; + (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst); + if (pPixmap) + { + pt.x = 0; + pt.y = 0; + width = w; + (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst, + &pt, &width, 1, TRUE); + (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt, + &width, 1, pDst); + } + pDst += linelength; + } + if (pPixmap) + { + (*pGC->pScreen->DestroyPixmap)(pPixmap); + FreeScratchGC(pGC); + } + } + else + { + (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h, + (MiBits *)pDst); + } +} + +/* MIPUTIMAGE -- public entry for the PutImage request + * Here we benefit from knowing the format of the bits pointed to by pImage, + * even if we don't know how pDraw represents them. + * Three different strategies are used depending on the format + * XYBitmap Format: + * we just use the Opaque Stipple helper function to cover the destination + * Note that this covers all the planes of the drawable with the + * foreground color (masked with the GC planemask) where there are 1 bits + * and the background color (masked with the GC planemask) where there are + * 0 bits + * XYPixmap format: + * what we're called with is a series of XYBitmaps, but we only want + * each XYPixmap to update 1 plane, instead of updating all of them. + * we set the foreground color to be all 1s and the background to all 0s + * then for each plane, we set the plane mask to only effect that one + * plane and recursive call ourself with the format set to XYBitmap + * (This clever idea courtesy of RGD.) + * ZPixmap format: + * This part is simple, just call SetSpans + */ +void +miPutImage( DrawablePtr pDraw, GCPtr pGC, int depth, + int x, int y, int w, int h, + int leftPad, int format, char *pImage) +{ + DDXPointPtr pptFirst, ppt; + int *pwidthFirst, *pwidth; + RegionPtr prgnSrc; + BoxRec box; + unsigned long oldFg, oldBg; + ChangeGCVal gcv[3]; + unsigned long oldPlanemask; + unsigned long i; + long bytesPer; + + if (!w || !h) + return; + switch(format) + { + case XYBitmap: + + box.x1 = 0; + box.y1 = 0; + box.x2 = w; + box.y2 = h; + prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1); + + miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage, + leftPad, w, h, x, y); + REGION_DESTROY(pGC->pScreen, prgnSrc); + break; + + case XYPixmap: + depth = pGC->depth; + oldPlanemask = pGC->planemask; + oldFg = pGC->fgPixel; + oldBg = pGC->bgPixel; + gcv[0].val = (XID)~0; + gcv[1].val = (XID)0; + ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcv); + bytesPer = (long)h * BitmapBytePad(w + leftPad); + + for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer) + { + if (i & oldPlanemask) + { + gcv[0].val = (XID)i; + ChangeGC(NullClient, pGC, GCPlaneMask, gcv); + ValidateGC(pDraw, pGC); + (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad, + XYBitmap, (char *)pImage); + } + } + gcv[0].val = (XID)oldPlanemask; + gcv[1].val = (XID)oldFg; + gcv[2].val = (XID)oldBg; + ChangeGC(NullClient, pGC, GCPlaneMask | GCForeground | GCBackground, gcv); + ValidateGC(pDraw, pGC); + break; + + case ZPixmap: + ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); + pwidth = pwidthFirst = malloc(h * sizeof(int)); + if(!pptFirst || !pwidthFirst) + { + if (pwidthFirst) + free(pwidthFirst); + if (pptFirst) + free(pptFirst); + return; + } + if (pGC->miTranslate) + { + x += pDraw->x; + y += pDraw->y; + } + + for(i = 0; i < h; i++) + { + ppt->x = x; + ppt->y = y + i; + ppt++; + *pwidth++ = w; + } + + (*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst, + pwidthFirst, h, TRUE); + free(pwidthFirst); + free(pptFirst); + break; + } +} diff --git a/xorg-server/mi/micmap.c b/xorg-server/mi/micmap.c index cc829fc10..ed8641c9e 100644 --- a/xorg-server/mi/micmap.c +++ b/xorg-server/mi/micmap.c @@ -1,666 +1,666 @@ -/* - * Copyright © 1987 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, 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. - */ - -/* - * This is based on cfbcmap.c. The functions here are useful independently - * of cfb, which is the reason for including them here. How "mi" these - * are may be debatable. - */ - - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "scrnintstr.h" -#include "colormapst.h" -#include "resource.h" -#include "globals.h" -#include "micmap.h" - -static int micmapScrPrivateKeyIndex; -DevPrivateKey micmapScrPrivateKey = &micmapScrPrivateKeyIndex; - -int -miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) -{ - if (GetInstalledmiColormap(pScreen)) { - *pmaps = GetInstalledmiColormap(pScreen)->mid; - return (1); - } - return 0; -} - -void -miInstallColormap(ColormapPtr pmap) -{ - ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen); - - if(pmap != oldpmap) - { - /* Uninstall pInstalledMap. No hardware changes required, just - * notify all interested parties. */ - if(oldpmap != (ColormapPtr)None) - WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); - /* Install pmap */ - SetInstalledmiColormap(pmap->pScreen, pmap); - WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); - - } -} - -void -miUninstallColormap(ColormapPtr pmap) -{ - ColormapPtr curpmap = GetInstalledmiColormap(pmap->pScreen); - - if(pmap == curpmap) - { - if (pmap->mid != pmap->pScreen->defColormap) - { - dixLookupResourceByType((pointer *)&curpmap, - pmap->pScreen->defColormap, - RT_COLORMAP, serverClient, - DixUseAccess); - (*pmap->pScreen->InstallColormap)(curpmap); - } - } -} - -void -miResolveColor(unsigned short *pred, unsigned short *pgreen, - unsigned short *pblue, VisualPtr pVisual) -{ - int shift = 16 - pVisual->bitsPerRGBValue; - unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1; - - if ((pVisual->class | DynamicClass) == GrayScale) - { - /* rescale to gray then rgb bits */ - *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100; - *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim; - } - else - { - /* rescale to rgb bits */ - *pred = ((*pred >> shift) * 65535) / lim; - *pgreen = ((*pgreen >> shift) * 65535) / lim; - *pblue = ((*pblue >> shift) * 65535) / lim; - } -} - -Bool -miInitializeColormap(ColormapPtr pmap) -{ - unsigned i; - VisualPtr pVisual; - unsigned lim, maxent, shift; - - pVisual = pmap->pVisual; - lim = (1 << pVisual->bitsPerRGBValue) - 1; - shift = 16 - pVisual->bitsPerRGBValue; - maxent = pVisual->ColormapEntries - 1; - if (pVisual->class == TrueColor) - { - unsigned limr, limg, limb; - - limr = pVisual->redMask >> pVisual->offsetRed; - limg = pVisual->greenMask >> pVisual->offsetGreen; - limb = pVisual->blueMask >> pVisual->offsetBlue; - for(i = 0; i <= maxent; i++) - { - /* rescale to [0..65535] then rgb bits */ - pmap->red[i].co.local.red = - ((((i * 65535) / limr) >> shift) * 65535) / lim; - pmap->green[i].co.local.green = - ((((i * 65535) / limg) >> shift) * 65535) / lim; - pmap->blue[i].co.local.blue = - ((((i * 65535) / limb) >> shift) * 65535) / lim; - } - } - else if (pVisual->class == StaticColor) - { - unsigned limr, limg, limb; - - limr = pVisual->redMask >> pVisual->offsetRed; - limg = pVisual->greenMask >> pVisual->offsetGreen; - limb = pVisual->blueMask >> pVisual->offsetBlue; - for(i = 0; i <= maxent; i++) - { - /* rescale to [0..65535] then rgb bits */ - pmap->red[i].co.local.red = - ((((((i & pVisual->redMask) >> pVisual->offsetRed) - * 65535) / limr) >> shift) * 65535) / lim; - pmap->red[i].co.local.green = - ((((((i & pVisual->greenMask) >> pVisual->offsetGreen) - * 65535) / limg) >> shift) * 65535) / lim; - pmap->red[i].co.local.blue = - ((((((i & pVisual->blueMask) >> pVisual->offsetBlue) - * 65535) / limb) >> shift) * 65535) / lim; - } - } - else if (pVisual->class == StaticGray) - { - for(i = 0; i <= maxent; i++) - { - /* rescale to [0..65535] then rgb bits */ - pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift) - * 65535) / lim; - pmap->red[i].co.local.green = pmap->red[i].co.local.red; - pmap->red[i].co.local.blue = pmap->red[i].co.local.red; - } - } - return TRUE; -} - -/* When simulating DirectColor on PseudoColor hardware, multiple - entries of the colormap must be updated - */ - -#define AddElement(mask) { \ - pixel = red | green | blue; \ - for (i = 0; i < nresult; i++) \ - if (outdefs[i].pixel == pixel) \ - break; \ - if (i == nresult) \ - { \ - nresult++; \ - outdefs[i].pixel = pixel; \ - outdefs[i].flags = 0; \ - } \ - outdefs[i].flags |= (mask); \ - outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \ - outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \ - outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \ -} - -int -miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem *indefs, - xColorItem *outdefs) -{ - int red, green, blue; - int maxred, maxgreen, maxblue; - int stepred, stepgreen, stepblue; - VisualPtr pVisual; - int pixel; - int nresult; - int i; - - pVisual = pmap->pVisual; - - stepred = 1 << pVisual->offsetRed; - stepgreen = 1 << pVisual->offsetGreen; - stepblue = 1 << pVisual->offsetBlue; - maxred = pVisual->redMask; - maxgreen = pVisual->greenMask; - maxblue = pVisual->blueMask; - nresult = 0; - for (;ndef--; indefs++) - { - if (indefs->flags & DoRed) - { - red = indefs->pixel & pVisual->redMask; - for (green = 0; green <= maxgreen; green += stepgreen) - { - for (blue = 0; blue <= maxblue; blue += stepblue) - { - AddElement (DoRed) - } - } - } - if (indefs->flags & DoGreen) - { - green = indefs->pixel & pVisual->greenMask; - for (red = 0; red <= maxred; red += stepred) - { - for (blue = 0; blue <= maxblue; blue += stepblue) - { - AddElement (DoGreen) - } - } - } - if (indefs->flags & DoBlue) - { - blue = indefs->pixel & pVisual->blueMask; - for (red = 0; red <= maxred; red += stepred) - { - for (green = 0; green <= maxgreen; green += stepgreen) - { - AddElement (DoBlue) - } - } - } - } - return nresult; -} - -Bool -miCreateDefColormap(ScreenPtr pScreen) -{ -/* - * In the following sources PC X server vendors may want to delete - * "_not_tog" from "#ifdef WIN32_not_tog" - */ -#ifdef WIN32_not_tog - /* - * these are the MS-Windows desktop colors, adjusted for X's 16-bit - * color specifications. - */ - static xColorItem citems[] = { - { 0, 0, 0, 0, 0, 0 }, - { 1, 0x8000, 0, 0, 0, 0 }, - { 2, 0, 0x8000, 0, 0, 0 }, - { 3, 0x8000, 0x8000, 0, 0, 0 }, - { 4, 0, 0, 0x8000, 0, 0 }, - { 5, 0x8000, 0, 0x8000, 0, 0 }, - { 6, 0, 0x8000, 0x8000, 0, 0 }, - { 7, 0xc000, 0xc000, 0xc000, 0, 0 }, - { 8, 0xc000, 0xdc00, 0xc000, 0, 0 }, - { 9, 0xa600, 0xca00, 0xf000, 0, 0 }, - { 246, 0xff00, 0xfb00, 0xf000, 0, 0 }, - { 247, 0xa000, 0xa000, 0xa400, 0, 0 }, - { 248, 0x8000, 0x8000, 0x8000, 0, 0 }, - { 249, 0xff00, 0, 0, 0, 0 }, - { 250, 0, 0xff00, 0, 0, 0 }, - { 251, 0xff00, 0xff00, 0, 0, 0 }, - { 252, 0, 0, 0xff00, 0, 0 }, - { 253, 0xff00, 0, 0xff00, 0, 0 }, - { 254, 0, 0xff00, 0xff00, 0, 0 }, - { 255, 0xff00, 0xff00, 0xff00, 0, 0 } - }; -#define NUM_DESKTOP_COLORS sizeof citems / sizeof citems[0] - int i; -#else - unsigned short zero = 0, ones = 0xFFFF; -#endif - Pixel wp, bp; - VisualPtr pVisual; - ColormapPtr cmap; - int alloctype; - - for (pVisual = pScreen->visuals; - pVisual->vid != pScreen->rootVisual; - pVisual++) - ; - - if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass)) - alloctype = AllocNone; - else - alloctype = AllocAll; - - if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap, - alloctype, 0) != Success) - return FALSE; - - if (pScreen->rootDepth > 1) { - wp = pScreen->whitePixel; - bp = pScreen->blackPixel; -#ifdef WIN32_not_tog - for (i = 0; i < NUM_DESKTOP_COLORS; i++) { - if (AllocColor (cmap, - &citems[i].red, &citems[i].green, &citems[i].blue, - &citems[i].pixel, 0) != Success) - return FALSE; - } -#else - if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) != - Success) || - (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) != - Success)) - return FALSE; - pScreen->whitePixel = wp; - pScreen->blackPixel = bp; -#endif - } - - (*pScreen->InstallColormap)(cmap); - return TRUE; -} - -/* - * Default true color bitmasks, should be overridden by - * driver - */ - -#define _RZ(d) ((d + 2) / 3) -#define _RS(d) 0 -#define _RM(d) ((1 << _RZ(d)) - 1) -#define _GZ(d) ((d - _RZ(d) + 1) / 2) -#define _GS(d) _RZ(d) -#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d)) -#define _BZ(d) (d - _RZ(d) - _GZ(d)) -#define _BS(d) (_RZ(d) + _GZ(d)) -#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d)) -#define _CE(d) (1 << _RZ(d)) - -typedef struct _miVisuals { - struct _miVisuals *next; - int depth; - int bitsPerRGB; - int visuals; - int count; - int preferredCVC; - Pixel redMask, greenMask, blueMask; -} miVisualsRec, *miVisualsPtr; - -static int miVisualPriority[] = { - PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray -}; - -#define NUM_PRIORITY 6 - -static miVisualsPtr miVisuals; - -void -miClearVisualTypes(void) -{ - miVisualsPtr v; - - while ((v = miVisuals)) { - miVisuals = v->next; - xfree(v); - } -} - - -Bool -miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB, - int preferredCVC, - Pixel redMask, Pixel greenMask, Pixel blueMask) -{ - miVisualsPtr new, *prev, v; - int count; - - new = xalloc (sizeof *new); - if (!new) - return FALSE; - if (!redMask || !greenMask || !blueMask) - { - redMask = _RM(depth); - greenMask = _GM(depth); - blueMask = _BM(depth); - } - new->next = 0; - new->depth = depth; - new->visuals = visuals; - new->bitsPerRGB = bitsPerRGB; - new->preferredCVC = preferredCVC; - new->redMask = redMask; - new->greenMask = greenMask; - new->blueMask = blueMask; - count = (visuals >> 1) & 033333333333; - count = visuals - count - ((count >> 1) & 033333333333); - count = (((count + (count >> 3)) & 030707070707) % 077); /* HAKMEM 169 */ - new->count = count; - for (prev = &miVisuals; (v = *prev); prev = &v->next); - *prev = new; - return TRUE; -} - -Bool -miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC) -{ - return miSetVisualTypesAndMasks (depth, visuals, bitsPerRGB, - preferredCVC, 0, 0, 0); -} - -int -miGetDefaultVisualMask(int depth) -{ - if (depth > MAX_PSEUDO_DEPTH) - return LARGE_VISUALS; - else if (depth >= MIN_TRUE_DEPTH) - return ALL_VISUALS; - else if (depth == 1) - return StaticGrayMask; - else - return SMALL_VISUALS; -} - -static Bool -miVisualTypesSet (int depth) -{ - miVisualsPtr visuals; - - for (visuals = miVisuals; visuals; visuals = visuals->next) - if (visuals->depth == depth) - return TRUE; - return FALSE; -} - -Bool -miSetPixmapDepths (void) -{ - int d, f; - - /* Add any unlisted depths from the pixmap formats */ - for (f = 0; f < screenInfo.numPixmapFormats; f++) - { - d = screenInfo.formats[f].depth; - if (!miVisualTypesSet (d)) - { - if (!miSetVisualTypes (d, 0, 0, -1)) - return FALSE; - } - } - return TRUE; -} - -/* - * Distance to least significant one bit - */ -static int -maskShift (Pixel p) -{ - int s; - - if (!p) return 0; - s = 0; - while (!(p & 1)) - { - s++; - p >>= 1; - } - return s; -} - -/* - * Given a list of formats for a screen, create a list - * of visuals and depths for the screen which corespond to - * the set which can be used with this version of cfb. - */ - -Bool -miInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp, - int *ndepthp, int *rootDepthp, VisualID *defaultVisp, - unsigned long sizes, int bitsPerRGB, int preferredVis) - -{ - int i, j = 0, k; - VisualPtr visual; - DepthPtr depth; - VisualID *vid; - int d, b; - int f; - int ndepth, nvisual; - int nvtype; - int vtype; - miVisualsPtr visuals, nextVisuals; - int *preferredCVCs, *prefp; - int first_depth; - - /* none specified, we'll guess from pixmap formats */ - if (!miVisuals) - { - for (f = 0; f < screenInfo.numPixmapFormats; f++) - { - d = screenInfo.formats[f].depth; - b = screenInfo.formats[f].bitsPerPixel; - if (sizes & (1 << (b - 1))) - vtype = miGetDefaultVisualMask(d); - else - vtype = 0; - if (!miSetVisualTypes (d, vtype, bitsPerRGB, -1)) - return FALSE; - } - } - nvisual = 0; - ndepth = 0; - for (visuals = miVisuals; visuals; visuals = nextVisuals) - { - nextVisuals = visuals->next; - ndepth++; - nvisual += visuals->count; - } - depth = xalloc (ndepth * sizeof (DepthRec)); - visual = xalloc (nvisual * sizeof (VisualRec)); - preferredCVCs = xalloc(ndepth * sizeof(int)); - if (!depth || !visual || !preferredCVCs) - { - xfree (depth); - xfree (visual); - xfree (preferredCVCs); - return FALSE; - } - *depthp = depth; - *visualp = visual; - *ndepthp = ndepth; - *nvisualp = nvisual; - prefp = preferredCVCs; - for (visuals = miVisuals; visuals; visuals = nextVisuals) - { - nextVisuals = visuals->next; - d = visuals->depth; - vtype = visuals->visuals; - nvtype = visuals->count; - *prefp = visuals->preferredCVC; - prefp++; - vid = NULL; - if (nvtype) - { - vid = xalloc (nvtype * sizeof (VisualID)); - if (!vid) { - xfree(preferredCVCs); - return FALSE; - } - } - depth->depth = d; - depth->numVids = nvtype; - depth->vids = vid; - depth++; - for (i = 0; i < NUM_PRIORITY; i++) { - if (! (vtype & (1 << miVisualPriority[i]))) - continue; - visual->class = miVisualPriority[i]; - visual->bitsPerRGBValue = visuals->bitsPerRGB; - visual->ColormapEntries = 1 << d; - visual->nplanes = d; - visual->vid = *vid = FakeClientID (0); - switch (visual->class) { - case PseudoColor: - case GrayScale: - case StaticGray: - visual->redMask = 0; - visual->greenMask = 0; - visual->blueMask = 0; - visual->offsetRed = 0; - visual->offsetGreen = 0; - visual->offsetBlue = 0; - break; - case DirectColor: - case TrueColor: - visual->ColormapEntries = _CE(d); - /* fall through */ - case StaticColor: - visual->redMask = visuals->redMask; - visual->greenMask = visuals->greenMask; - visual->blueMask = visuals->blueMask; - visual->offsetRed = maskShift (visuals->redMask); - visual->offsetGreen = maskShift (visuals->greenMask); - visual->offsetBlue = maskShift (visuals->blueMask); - } - vid++; - visual++; - } - xfree (visuals); - } - miVisuals = NULL; - visual = *visualp; - depth = *depthp; - - /* - * if we did not supplyied by a preferred visual class - * check if there is a preferred class in one of the depth - * structures - if there is, we want to start looking for the - * default visual/depth from that depth. - */ - first_depth = 0; - if (preferredVis < 0 && defaultColorVisualClass < 0 ) { - for (i = 0; i < ndepth; i++) { - if (preferredCVCs[i] >= 0) { - first_depth = i; - break; - } - } - } - - for (i = first_depth; i < ndepth; i++) - { - int prefColorVisualClass = -1; - - if (defaultColorVisualClass >= 0) - prefColorVisualClass = defaultColorVisualClass; - else if (preferredVis >= 0) - prefColorVisualClass = preferredVis; - else if (preferredCVCs[i] >= 0) - prefColorVisualClass = preferredCVCs[i]; - - if (*rootDepthp && *rootDepthp != depth[i].depth) - continue; - - for (j = 0; j < depth[i].numVids; j++) - { - for (k = 0; k < nvisual; k++) - if (visual[k].vid == depth[i].vids[j]) - break; - if (k == nvisual) - continue; - if (prefColorVisualClass < 0 || - visual[k].class == prefColorVisualClass) - break; - } - if (j != depth[i].numVids) - break; - } - if (i == ndepth) { - i = 0; - j = 0; - } - *rootDepthp = depth[i].depth; - *defaultVisp = depth[i].vids[j]; - xfree(preferredCVCs); - - return TRUE; -} +/* + * Copyright © 1987 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, 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. + */ + +/* + * This is based on cfbcmap.c. The functions here are useful independently + * of cfb, which is the reason for including them here. How "mi" these + * are may be debatable. + */ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "colormapst.h" +#include "resource.h" +#include "globals.h" +#include "micmap.h" + +static int micmapScrPrivateKeyIndex; +DevPrivateKey micmapScrPrivateKey = &micmapScrPrivateKeyIndex; + +int +miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) +{ + if (GetInstalledmiColormap(pScreen)) { + *pmaps = GetInstalledmiColormap(pScreen)->mid; + return (1); + } + return 0; +} + +void +miInstallColormap(ColormapPtr pmap) +{ + ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen); + + if(pmap != oldpmap) + { + /* Uninstall pInstalledMap. No hardware changes required, just + * notify all interested parties. */ + if(oldpmap != (ColormapPtr)None) + WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); + /* Install pmap */ + SetInstalledmiColormap(pmap->pScreen, pmap); + WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); + + } +} + +void +miUninstallColormap(ColormapPtr pmap) +{ + ColormapPtr curpmap = GetInstalledmiColormap(pmap->pScreen); + + if(pmap == curpmap) + { + if (pmap->mid != pmap->pScreen->defColormap) + { + dixLookupResourceByType((pointer *)&curpmap, + pmap->pScreen->defColormap, + RT_COLORMAP, serverClient, + DixUseAccess); + (*pmap->pScreen->InstallColormap)(curpmap); + } + } +} + +void +miResolveColor(unsigned short *pred, unsigned short *pgreen, + unsigned short *pblue, VisualPtr pVisual) +{ + int shift = 16 - pVisual->bitsPerRGBValue; + unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1; + + if ((pVisual->class | DynamicClass) == GrayScale) + { + /* rescale to gray then rgb bits */ + *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100; + *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim; + } + else + { + /* rescale to rgb bits */ + *pred = ((*pred >> shift) * 65535) / lim; + *pgreen = ((*pgreen >> shift) * 65535) / lim; + *pblue = ((*pblue >> shift) * 65535) / lim; + } +} + +Bool +miInitializeColormap(ColormapPtr pmap) +{ + unsigned i; + VisualPtr pVisual; + unsigned lim, maxent, shift; + + pVisual = pmap->pVisual; + lim = (1 << pVisual->bitsPerRGBValue) - 1; + shift = 16 - pVisual->bitsPerRGBValue; + maxent = pVisual->ColormapEntries - 1; + if (pVisual->class == TrueColor) + { + unsigned limr, limg, limb; + + limr = pVisual->redMask >> pVisual->offsetRed; + limg = pVisual->greenMask >> pVisual->offsetGreen; + limb = pVisual->blueMask >> pVisual->offsetBlue; + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = + ((((i * 65535) / limr) >> shift) * 65535) / lim; + pmap->green[i].co.local.green = + ((((i * 65535) / limg) >> shift) * 65535) / lim; + pmap->blue[i].co.local.blue = + ((((i * 65535) / limb) >> shift) * 65535) / lim; + } + } + else if (pVisual->class == StaticColor) + { + unsigned limr, limg, limb; + + limr = pVisual->redMask >> pVisual->offsetRed; + limg = pVisual->greenMask >> pVisual->offsetGreen; + limb = pVisual->blueMask >> pVisual->offsetBlue; + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = + ((((((i & pVisual->redMask) >> pVisual->offsetRed) + * 65535) / limr) >> shift) * 65535) / lim; + pmap->red[i].co.local.green = + ((((((i & pVisual->greenMask) >> pVisual->offsetGreen) + * 65535) / limg) >> shift) * 65535) / lim; + pmap->red[i].co.local.blue = + ((((((i & pVisual->blueMask) >> pVisual->offsetBlue) + * 65535) / limb) >> shift) * 65535) / lim; + } + } + else if (pVisual->class == StaticGray) + { + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift) + * 65535) / lim; + pmap->red[i].co.local.green = pmap->red[i].co.local.red; + pmap->red[i].co.local.blue = pmap->red[i].co.local.red; + } + } + return TRUE; +} + +/* When simulating DirectColor on PseudoColor hardware, multiple + entries of the colormap must be updated + */ + +#define AddElement(mask) { \ + pixel = red | green | blue; \ + for (i = 0; i < nresult; i++) \ + if (outdefs[i].pixel == pixel) \ + break; \ + if (i == nresult) \ + { \ + nresult++; \ + outdefs[i].pixel = pixel; \ + outdefs[i].flags = 0; \ + } \ + outdefs[i].flags |= (mask); \ + outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \ + outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \ + outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \ +} + +int +miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem *indefs, + xColorItem *outdefs) +{ + int red, green, blue; + int maxred, maxgreen, maxblue; + int stepred, stepgreen, stepblue; + VisualPtr pVisual; + int pixel; + int nresult; + int i; + + pVisual = pmap->pVisual; + + stepred = 1 << pVisual->offsetRed; + stepgreen = 1 << pVisual->offsetGreen; + stepblue = 1 << pVisual->offsetBlue; + maxred = pVisual->redMask; + maxgreen = pVisual->greenMask; + maxblue = pVisual->blueMask; + nresult = 0; + for (;ndef--; indefs++) + { + if (indefs->flags & DoRed) + { + red = indefs->pixel & pVisual->redMask; + for (green = 0; green <= maxgreen; green += stepgreen) + { + for (blue = 0; blue <= maxblue; blue += stepblue) + { + AddElement (DoRed) + } + } + } + if (indefs->flags & DoGreen) + { + green = indefs->pixel & pVisual->greenMask; + for (red = 0; red <= maxred; red += stepred) + { + for (blue = 0; blue <= maxblue; blue += stepblue) + { + AddElement (DoGreen) + } + } + } + if (indefs->flags & DoBlue) + { + blue = indefs->pixel & pVisual->blueMask; + for (red = 0; red <= maxred; red += stepred) + { + for (green = 0; green <= maxgreen; green += stepgreen) + { + AddElement (DoBlue) + } + } + } + } + return nresult; +} + +Bool +miCreateDefColormap(ScreenPtr pScreen) +{ +/* + * In the following sources PC X server vendors may want to delete + * "_not_tog" from "#ifdef WIN32_not_tog" + */ +#ifdef WIN32_not_tog + /* + * these are the MS-Windows desktop colors, adjusted for X's 16-bit + * color specifications. + */ + static xColorItem citems[] = { + { 0, 0, 0, 0, 0, 0 }, + { 1, 0x8000, 0, 0, 0, 0 }, + { 2, 0, 0x8000, 0, 0, 0 }, + { 3, 0x8000, 0x8000, 0, 0, 0 }, + { 4, 0, 0, 0x8000, 0, 0 }, + { 5, 0x8000, 0, 0x8000, 0, 0 }, + { 6, 0, 0x8000, 0x8000, 0, 0 }, + { 7, 0xc000, 0xc000, 0xc000, 0, 0 }, + { 8, 0xc000, 0xdc00, 0xc000, 0, 0 }, + { 9, 0xa600, 0xca00, 0xf000, 0, 0 }, + { 246, 0xff00, 0xfb00, 0xf000, 0, 0 }, + { 247, 0xa000, 0xa000, 0xa400, 0, 0 }, + { 248, 0x8000, 0x8000, 0x8000, 0, 0 }, + { 249, 0xff00, 0, 0, 0, 0 }, + { 250, 0, 0xff00, 0, 0, 0 }, + { 251, 0xff00, 0xff00, 0, 0, 0 }, + { 252, 0, 0, 0xff00, 0, 0 }, + { 253, 0xff00, 0, 0xff00, 0, 0 }, + { 254, 0, 0xff00, 0xff00, 0, 0 }, + { 255, 0xff00, 0xff00, 0xff00, 0, 0 } + }; +#define NUM_DESKTOP_COLORS sizeof citems / sizeof citems[0] + int i; +#else + unsigned short zero = 0, ones = 0xFFFF; +#endif + Pixel wp, bp; + VisualPtr pVisual; + ColormapPtr cmap; + int alloctype; + + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++) + ; + + if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass)) + alloctype = AllocNone; + else + alloctype = AllocAll; + + if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap, + alloctype, 0) != Success) + return FALSE; + + if (pScreen->rootDepth > 1) { + wp = pScreen->whitePixel; + bp = pScreen->blackPixel; +#ifdef WIN32_not_tog + for (i = 0; i < NUM_DESKTOP_COLORS; i++) { + if (AllocColor (cmap, + &citems[i].red, &citems[i].green, &citems[i].blue, + &citems[i].pixel, 0) != Success) + return FALSE; + } +#else + if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) != + Success) || + (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) != + Success)) + return FALSE; + pScreen->whitePixel = wp; + pScreen->blackPixel = bp; +#endif + } + + (*pScreen->InstallColormap)(cmap); + return TRUE; +} + +/* + * Default true color bitmasks, should be overridden by + * driver + */ + +#define _RZ(d) ((d + 2) / 3) +#define _RS(d) 0 +#define _RM(d) ((1 << _RZ(d)) - 1) +#define _GZ(d) ((d - _RZ(d) + 1) / 2) +#define _GS(d) _RZ(d) +#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d)) +#define _BZ(d) (d - _RZ(d) - _GZ(d)) +#define _BS(d) (_RZ(d) + _GZ(d)) +#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d)) +#define _CE(d) (1 << _RZ(d)) + +typedef struct _miVisuals { + struct _miVisuals *next; + int depth; + int bitsPerRGB; + int visuals; + int count; + int preferredCVC; + Pixel redMask, greenMask, blueMask; +} miVisualsRec, *miVisualsPtr; + +static int miVisualPriority[] = { + PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray +}; + +#define NUM_PRIORITY 6 + +static miVisualsPtr miVisuals; + +void +miClearVisualTypes(void) +{ + miVisualsPtr v; + + while ((v = miVisuals)) { + miVisuals = v->next; + free(v); + } +} + + +Bool +miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB, + int preferredCVC, + Pixel redMask, Pixel greenMask, Pixel blueMask) +{ + miVisualsPtr new, *prev, v; + int count; + + new = malloc(sizeof *new); + if (!new) + return FALSE; + if (!redMask || !greenMask || !blueMask) + { + redMask = _RM(depth); + greenMask = _GM(depth); + blueMask = _BM(depth); + } + new->next = 0; + new->depth = depth; + new->visuals = visuals; + new->bitsPerRGB = bitsPerRGB; + new->preferredCVC = preferredCVC; + new->redMask = redMask; + new->greenMask = greenMask; + new->blueMask = blueMask; + count = (visuals >> 1) & 033333333333; + count = visuals - count - ((count >> 1) & 033333333333); + count = (((count + (count >> 3)) & 030707070707) % 077); /* HAKMEM 169 */ + new->count = count; + for (prev = &miVisuals; (v = *prev); prev = &v->next); + *prev = new; + return TRUE; +} + +Bool +miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC) +{ + return miSetVisualTypesAndMasks (depth, visuals, bitsPerRGB, + preferredCVC, 0, 0, 0); +} + +int +miGetDefaultVisualMask(int depth) +{ + if (depth > MAX_PSEUDO_DEPTH) + return LARGE_VISUALS; + else if (depth >= MIN_TRUE_DEPTH) + return ALL_VISUALS; + else if (depth == 1) + return StaticGrayMask; + else + return SMALL_VISUALS; +} + +static Bool +miVisualTypesSet (int depth) +{ + miVisualsPtr visuals; + + for (visuals = miVisuals; visuals; visuals = visuals->next) + if (visuals->depth == depth) + return TRUE; + return FALSE; +} + +Bool +miSetPixmapDepths (void) +{ + int d, f; + + /* Add any unlisted depths from the pixmap formats */ + for (f = 0; f < screenInfo.numPixmapFormats; f++) + { + d = screenInfo.formats[f].depth; + if (!miVisualTypesSet (d)) + { + if (!miSetVisualTypes (d, 0, 0, -1)) + return FALSE; + } + } + return TRUE; +} + +/* + * Distance to least significant one bit + */ +static int +maskShift (Pixel p) +{ + int s; + + if (!p) return 0; + s = 0; + while (!(p & 1)) + { + s++; + p >>= 1; + } + return s; +} + +/* + * Given a list of formats for a screen, create a list + * of visuals and depths for the screen which corespond to + * the set which can be used with this version of cfb. + */ + +Bool +miInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp, + int *ndepthp, int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB, int preferredVis) + +{ + int i, j = 0, k; + VisualPtr visual; + DepthPtr depth; + VisualID *vid; + int d, b; + int f; + int ndepth, nvisual; + int nvtype; + int vtype; + miVisualsPtr visuals, nextVisuals; + int *preferredCVCs, *prefp; + int first_depth; + + /* none specified, we'll guess from pixmap formats */ + if (!miVisuals) + { + for (f = 0; f < screenInfo.numPixmapFormats; f++) + { + d = screenInfo.formats[f].depth; + b = screenInfo.formats[f].bitsPerPixel; + if (sizes & (1 << (b - 1))) + vtype = miGetDefaultVisualMask(d); + else + vtype = 0; + if (!miSetVisualTypes (d, vtype, bitsPerRGB, -1)) + return FALSE; + } + } + nvisual = 0; + ndepth = 0; + for (visuals = miVisuals; visuals; visuals = nextVisuals) + { + nextVisuals = visuals->next; + ndepth++; + nvisual += visuals->count; + } + depth = malloc(ndepth * sizeof (DepthRec)); + visual = malloc(nvisual * sizeof (VisualRec)); + preferredCVCs = malloc(ndepth * sizeof(int)); + if (!depth || !visual || !preferredCVCs) + { + free(depth); + free(visual); + free(preferredCVCs); + return FALSE; + } + *depthp = depth; + *visualp = visual; + *ndepthp = ndepth; + *nvisualp = nvisual; + prefp = preferredCVCs; + for (visuals = miVisuals; visuals; visuals = nextVisuals) + { + nextVisuals = visuals->next; + d = visuals->depth; + vtype = visuals->visuals; + nvtype = visuals->count; + *prefp = visuals->preferredCVC; + prefp++; + vid = NULL; + if (nvtype) + { + vid = malloc(nvtype * sizeof (VisualID)); + if (!vid) { + free(preferredCVCs); + return FALSE; + } + } + depth->depth = d; + depth->numVids = nvtype; + depth->vids = vid; + depth++; + for (i = 0; i < NUM_PRIORITY; i++) { + if (! (vtype & (1 << miVisualPriority[i]))) + continue; + visual->class = miVisualPriority[i]; + visual->bitsPerRGBValue = visuals->bitsPerRGB; + visual->ColormapEntries = 1 << d; + visual->nplanes = d; + visual->vid = *vid = FakeClientID (0); + switch (visual->class) { + case PseudoColor: + case GrayScale: + case StaticGray: + visual->redMask = 0; + visual->greenMask = 0; + visual->blueMask = 0; + visual->offsetRed = 0; + visual->offsetGreen = 0; + visual->offsetBlue = 0; + break; + case DirectColor: + case TrueColor: + visual->ColormapEntries = _CE(d); + /* fall through */ + case StaticColor: + visual->redMask = visuals->redMask; + visual->greenMask = visuals->greenMask; + visual->blueMask = visuals->blueMask; + visual->offsetRed = maskShift (visuals->redMask); + visual->offsetGreen = maskShift (visuals->greenMask); + visual->offsetBlue = maskShift (visuals->blueMask); + } + vid++; + visual++; + } + free(visuals); + } + miVisuals = NULL; + visual = *visualp; + depth = *depthp; + + /* + * if we did not supplyied by a preferred visual class + * check if there is a preferred class in one of the depth + * structures - if there is, we want to start looking for the + * default visual/depth from that depth. + */ + first_depth = 0; + if (preferredVis < 0 && defaultColorVisualClass < 0 ) { + for (i = 0; i < ndepth; i++) { + if (preferredCVCs[i] >= 0) { + first_depth = i; + break; + } + } + } + + for (i = first_depth; i < ndepth; i++) + { + int prefColorVisualClass = -1; + + if (defaultColorVisualClass >= 0) + prefColorVisualClass = defaultColorVisualClass; + else if (preferredVis >= 0) + prefColorVisualClass = preferredVis; + else if (preferredCVCs[i] >= 0) + prefColorVisualClass = preferredCVCs[i]; + + if (*rootDepthp && *rootDepthp != depth[i].depth) + continue; + + for (j = 0; j < depth[i].numVids; j++) + { + for (k = 0; k < nvisual; k++) + if (visual[k].vid == depth[i].vids[j]) + break; + if (k == nvisual) + continue; + if (prefColorVisualClass < 0 || + visual[k].class == prefColorVisualClass) + break; + } + if (j != depth[i].numVids) + break; + } + if (i == ndepth) { + i = 0; + j = 0; + } + *rootDepthp = depth[i].depth; + *defaultVisp = depth[i].vids[j]; + free(preferredCVCs); + + return TRUE; +} diff --git a/xorg-server/mi/micopy.c b/xorg-server/mi/micopy.c index 3719f4646..9d5c5ce5e 100644 --- a/xorg-server/mi/micopy.c +++ b/xorg-server/mi/micopy.c @@ -1,354 +1,354 @@ -/* - * Copyright © 1998 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 <dix-config.h> -#endif - -#include "mi.h" -#include "scrnintstr.h" -#include "gcstruct.h" -#include "pixmap.h" -#include "pixmapstr.h" -#include "windowstr.h" - -void -miCopyRegion (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - RegionPtr pDstRegion, - int dx, - int dy, - miCopyProc copyProc, - Pixel bitPlane, - void *closure) -{ - int careful; - Bool reverse; - Bool upsidedown; - BoxPtr pbox; - int nbox; - BoxPtr pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp; - - pbox = REGION_RECTS(pDstRegion); - nbox = REGION_NUM_RECTS(pDstRegion); - - /* XXX we have to err on the side of safety when both are windows, - * because we don't know if IncludeInferiors is being used. - */ - careful = ((pSrcDrawable == pDstDrawable) || - ((pSrcDrawable->type == DRAWABLE_WINDOW) && - (pDstDrawable->type == DRAWABLE_WINDOW))); - - pboxNew1 = NULL; - pboxNew2 = NULL; - if (careful && dy < 0) - { - upsidedown = TRUE; - - if (nbox > 1) - { - /* keep ordering in each band, reverse order of bands */ - pboxNew1 = (BoxPtr)xalloc(sizeof(BoxRec) * nbox); - if(!pboxNew1) - return; - pboxBase = pboxNext = pbox+nbox-1; - while (pboxBase >= pbox) - { - while ((pboxNext >= pbox) && - (pboxBase->y1 == pboxNext->y1)) - pboxNext--; - pboxTmp = pboxNext+1; - while (pboxTmp <= pboxBase) - { - *pboxNew1++ = *pboxTmp++; - } - pboxBase = pboxNext; - } - pboxNew1 -= nbox; - pbox = pboxNew1; - } - } - else - { - /* walk source top to bottom */ - upsidedown = FALSE; - } - - if (careful && dx < 0) - { - /* walk source right to left */ - if (dy <= 0) - reverse = TRUE; - else - reverse = FALSE; - - if (nbox > 1) - { - /* reverse order of rects in each band */ - pboxNew2 = (BoxPtr)xalloc(sizeof(BoxRec) * nbox); - if(!pboxNew2) - { - if (pboxNew1) - xfree(pboxNew1); - return; - } - pboxBase = pboxNext = pbox; - while (pboxBase < pbox+nbox) - { - while ((pboxNext < pbox+nbox) && - (pboxNext->y1 == pboxBase->y1)) - pboxNext++; - pboxTmp = pboxNext; - while (pboxTmp != pboxBase) - { - *pboxNew2++ = *--pboxTmp; - } - pboxBase = pboxNext; - } - pboxNew2 -= nbox; - pbox = pboxNew2; - } - } - else - { - /* walk source left to right */ - reverse = FALSE; - } - - (*copyProc) (pSrcDrawable, - pDstDrawable, - pGC, - pbox, - nbox, - dx, dy, - reverse, upsidedown, bitPlane, closure); - - if (pboxNew1) - xfree (pboxNew1); - if (pboxNew2) - xfree (pboxNew2); -} - -RegionPtr -miDoCopy (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - int xIn, - int yIn, - int widthSrc, - int heightSrc, - int xOut, - int yOut, - miCopyProc copyProc, - Pixel bitPlane, - void *closure) -{ - RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */ - Bool freeSrcClip = FALSE; - RegionPtr prgnExposed = NULL; - RegionRec rgnDst; - int dx; - int dy; - int numRects; - int box_x1; - int box_y1; - int box_x2; - int box_y2; - Bool fastSrc = FALSE; /* for fast clipping with pixmap source */ - Bool fastDst = FALSE; /* for fast clipping with one rect dest */ - Bool fastExpose = FALSE; /* for fast exposures with pixmap source */ - - /* Short cut for unmapped windows */ - - if (pDstDrawable->type == DRAWABLE_WINDOW && - !((WindowPtr)pDstDrawable)->realized) - { - return NULL; - } - - if ((pSrcDrawable != pDstDrawable) && - pSrcDrawable->pScreen->SourceValidate) - { - (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn, widthSrc, heightSrc); - } - - /* Compute source clip region */ - if (pSrcDrawable->type == DRAWABLE_PIXMAP) - { - if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE)) - prgnSrcClip = miGetCompositeClip(pGC); - else - fastSrc = TRUE; - } - else - { - if (pGC->subWindowMode == IncludeInferiors) - { - /* - * XFree86 DDX empties the border clip when the - * VT is inactive, make sure the region isn't empty - */ - if (!((WindowPtr) pSrcDrawable)->parent && - REGION_NOTEMPTY (pSrcDrawable->pScreen, - &((WindowPtr) pSrcDrawable)->borderClip)) - { - /* - * special case bitblt from root window in - * IncludeInferiors mode; just like from a pixmap - */ - fastSrc = TRUE; - } - else if ((pSrcDrawable == pDstDrawable) && - (pGC->clientClipType == CT_NONE)) - { - prgnSrcClip = miGetCompositeClip(pGC); - } - else - { - prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable); - freeSrcClip = TRUE; - } - } - else - { - prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; - } - } - - xIn += pSrcDrawable->x; - yIn += pSrcDrawable->y; - - xOut += pDstDrawable->x; - yOut += pDstDrawable->y; - - box_x1 = xIn; - box_y1 = yIn; - box_x2 = xIn + widthSrc; - box_y2 = yIn + heightSrc; - - dx = xIn - xOut; - dy = yIn - yOut; - - /* Don't create a source region if we are doing a fast clip */ - if (fastSrc) - { - RegionPtr cclip; - - fastExpose = TRUE; - /* - * clip the source; if regions extend beyond the source size, - * make sure exposure events get sent - */ - if (box_x1 < pSrcDrawable->x) - { - box_x1 = pSrcDrawable->x; - fastExpose = FALSE; - } - if (box_y1 < pSrcDrawable->y) - { - box_y1 = pSrcDrawable->y; - fastExpose = FALSE; - } - if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width) - { - box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width; - fastExpose = FALSE; - } - if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height) - { - box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height; - fastExpose = FALSE; - } - - /* Translate and clip the dst to the destination composite clip */ - box_x1 -= dx; - box_x2 -= dx; - box_y1 -= dy; - box_y2 -= dy; - - /* If the destination composite clip is one rectangle we can - do the clip directly. Otherwise we have to create a full - blown region and call intersect */ - - cclip = miGetCompositeClip(pGC); - if (REGION_NUM_RECTS(cclip) == 1) - { - BoxPtr pBox = REGION_RECTS(cclip); - - if (box_x1 < pBox->x1) box_x1 = pBox->x1; - if (box_x2 > pBox->x2) box_x2 = pBox->x2; - if (box_y1 < pBox->y1) box_y1 = pBox->y1; - if (box_y2 > pBox->y2) box_y2 = pBox->y2; - fastDst = TRUE; - } - } - - /* Check to see if the region is empty */ - if (box_x1 >= box_x2 || box_y1 >= box_y2) - { - REGION_NULL(pGC->pScreen, &rgnDst); - } - else - { - BoxRec box; - box.x1 = box_x1; - box.y1 = box_y1; - box.x2 = box_x2; - box.y2 = box_y2; - REGION_INIT(pGC->pScreen, &rgnDst, &box, 1); - } - - /* Clip against complex source if needed */ - if (!fastSrc) - { - REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip); - REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy); - } - - /* Clip against complex dest if needed */ - if (!fastDst) - { - REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, - miGetCompositeClip(pGC)); - } - - /* Do bit blitting */ - numRects = REGION_NUM_RECTS(&rgnDst); - if (numRects && widthSrc && heightSrc) - miCopyRegion (pSrcDrawable, pDstDrawable, pGC, - &rgnDst, dx, dy, copyProc, bitPlane, closure); - - /* Pixmap sources generate a NoExposed (we return NULL to do this) */ - if (!fastExpose && pGC->fExpose) - prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, - xIn - pSrcDrawable->x, - yIn - pSrcDrawable->y, - widthSrc, heightSrc, - xOut - pDstDrawable->x, - yOut - pDstDrawable->y, - (unsigned long) bitPlane); - REGION_UNINIT(pGC->pScreen, &rgnDst); - if (freeSrcClip) - REGION_DESTROY(pGC->pScreen, prgnSrcClip); - return prgnExposed; -} +/* + * Copyright © 1998 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 <dix-config.h> +#endif + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmap.h" +#include "pixmapstr.h" +#include "windowstr.h" + +void +miCopyRegion (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + RegionPtr pDstRegion, + int dx, + int dy, + miCopyProc copyProc, + Pixel bitPlane, + void *closure) +{ + int careful; + Bool reverse; + Bool upsidedown; + BoxPtr pbox; + int nbox; + BoxPtr pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp; + + pbox = REGION_RECTS(pDstRegion); + nbox = REGION_NUM_RECTS(pDstRegion); + + /* XXX we have to err on the side of safety when both are windows, + * because we don't know if IncludeInferiors is being used. + */ + careful = ((pSrcDrawable == pDstDrawable) || + ((pSrcDrawable->type == DRAWABLE_WINDOW) && + (pDstDrawable->type == DRAWABLE_WINDOW))); + + pboxNew1 = NULL; + pboxNew2 = NULL; + if (careful && dy < 0) + { + upsidedown = TRUE; + + if (nbox > 1) + { + /* keep ordering in each band, reverse order of bands */ + pboxNew1 = (BoxPtr)malloc(sizeof(BoxRec) * nbox); + if(!pboxNew1) + return; + pboxBase = pboxNext = pbox+nbox-1; + while (pboxBase >= pbox) + { + while ((pboxNext >= pbox) && + (pboxBase->y1 == pboxNext->y1)) + pboxNext--; + pboxTmp = pboxNext+1; + while (pboxTmp <= pboxBase) + { + *pboxNew1++ = *pboxTmp++; + } + pboxBase = pboxNext; + } + pboxNew1 -= nbox; + pbox = pboxNew1; + } + } + else + { + /* walk source top to bottom */ + upsidedown = FALSE; + } + + if (careful && dx < 0) + { + /* walk source right to left */ + if (dy <= 0) + reverse = TRUE; + else + reverse = FALSE; + + if (nbox > 1) + { + /* reverse order of rects in each band */ + pboxNew2 = (BoxPtr)malloc(sizeof(BoxRec) * nbox); + if(!pboxNew2) + { + if (pboxNew1) + free(pboxNew1); + return; + } + pboxBase = pboxNext = pbox; + while (pboxBase < pbox+nbox) + { + while ((pboxNext < pbox+nbox) && + (pboxNext->y1 == pboxBase->y1)) + pboxNext++; + pboxTmp = pboxNext; + while (pboxTmp != pboxBase) + { + *pboxNew2++ = *--pboxTmp; + } + pboxBase = pboxNext; + } + pboxNew2 -= nbox; + pbox = pboxNew2; + } + } + else + { + /* walk source left to right */ + reverse = FALSE; + } + + (*copyProc) (pSrcDrawable, + pDstDrawable, + pGC, + pbox, + nbox, + dx, dy, + reverse, upsidedown, bitPlane, closure); + + if (pboxNew1) + free(pboxNew1); + if (pboxNew2) + free(pboxNew2); +} + +RegionPtr +miDoCopy (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int yOut, + miCopyProc copyProc, + Pixel bitPlane, + void *closure) +{ + RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */ + Bool freeSrcClip = FALSE; + RegionPtr prgnExposed = NULL; + RegionRec rgnDst; + int dx; + int dy; + int numRects; + int box_x1; + int box_y1; + int box_x2; + int box_y2; + Bool fastSrc = FALSE; /* for fast clipping with pixmap source */ + Bool fastDst = FALSE; /* for fast clipping with one rect dest */ + Bool fastExpose = FALSE; /* for fast exposures with pixmap source */ + + /* Short cut for unmapped windows */ + + if (pDstDrawable->type == DRAWABLE_WINDOW && + !((WindowPtr)pDstDrawable)->realized) + { + return NULL; + } + + if ((pSrcDrawable != pDstDrawable) && + pSrcDrawable->pScreen->SourceValidate) + { + (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn, widthSrc, heightSrc); + } + + /* Compute source clip region */ + if (pSrcDrawable->type == DRAWABLE_PIXMAP) + { + if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE)) + prgnSrcClip = miGetCompositeClip(pGC); + else + fastSrc = TRUE; + } + else + { + if (pGC->subWindowMode == IncludeInferiors) + { + /* + * XFree86 DDX empties the border clip when the + * VT is inactive, make sure the region isn't empty + */ + if (!((WindowPtr) pSrcDrawable)->parent && + REGION_NOTEMPTY (pSrcDrawable->pScreen, + &((WindowPtr) pSrcDrawable)->borderClip)) + { + /* + * special case bitblt from root window in + * IncludeInferiors mode; just like from a pixmap + */ + fastSrc = TRUE; + } + else if ((pSrcDrawable == pDstDrawable) && + (pGC->clientClipType == CT_NONE)) + { + prgnSrcClip = miGetCompositeClip(pGC); + } + else + { + prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable); + freeSrcClip = TRUE; + } + } + else + { + prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; + } + } + + xIn += pSrcDrawable->x; + yIn += pSrcDrawable->y; + + xOut += pDstDrawable->x; + yOut += pDstDrawable->y; + + box_x1 = xIn; + box_y1 = yIn; + box_x2 = xIn + widthSrc; + box_y2 = yIn + heightSrc; + + dx = xIn - xOut; + dy = yIn - yOut; + + /* Don't create a source region if we are doing a fast clip */ + if (fastSrc) + { + RegionPtr cclip; + + fastExpose = TRUE; + /* + * clip the source; if regions extend beyond the source size, + * make sure exposure events get sent + */ + if (box_x1 < pSrcDrawable->x) + { + box_x1 = pSrcDrawable->x; + fastExpose = FALSE; + } + if (box_y1 < pSrcDrawable->y) + { + box_y1 = pSrcDrawable->y; + fastExpose = FALSE; + } + if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width) + { + box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width; + fastExpose = FALSE; + } + if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height) + { + box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height; + fastExpose = FALSE; + } + + /* Translate and clip the dst to the destination composite clip */ + box_x1 -= dx; + box_x2 -= dx; + box_y1 -= dy; + box_y2 -= dy; + + /* If the destination composite clip is one rectangle we can + do the clip directly. Otherwise we have to create a full + blown region and call intersect */ + + cclip = miGetCompositeClip(pGC); + if (REGION_NUM_RECTS(cclip) == 1) + { + BoxPtr pBox = REGION_RECTS(cclip); + + if (box_x1 < pBox->x1) box_x1 = pBox->x1; + if (box_x2 > pBox->x2) box_x2 = pBox->x2; + if (box_y1 < pBox->y1) box_y1 = pBox->y1; + if (box_y2 > pBox->y2) box_y2 = pBox->y2; + fastDst = TRUE; + } + } + + /* Check to see if the region is empty */ + if (box_x1 >= box_x2 || box_y1 >= box_y2) + { + REGION_NULL(pGC->pScreen, &rgnDst); + } + else + { + BoxRec box; + box.x1 = box_x1; + box.y1 = box_y1; + box.x2 = box_x2; + box.y2 = box_y2; + REGION_INIT(pGC->pScreen, &rgnDst, &box, 1); + } + + /* Clip against complex source if needed */ + if (!fastSrc) + { + REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip); + REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy); + } + + /* Clip against complex dest if needed */ + if (!fastDst) + { + REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, + miGetCompositeClip(pGC)); + } + + /* Do bit blitting */ + numRects = REGION_NUM_RECTS(&rgnDst); + if (numRects && widthSrc && heightSrc) + miCopyRegion (pSrcDrawable, pDstDrawable, pGC, + &rgnDst, dx, dy, copyProc, bitPlane, closure); + + /* Pixmap sources generate a NoExposed (we return NULL to do this) */ + if (!fastExpose && pGC->fExpose) + prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, + xIn - pSrcDrawable->x, + yIn - pSrcDrawable->y, + widthSrc, heightSrc, + xOut - pDstDrawable->x, + yOut - pDstDrawable->y, + (unsigned long) bitPlane); + REGION_UNINIT(pGC->pScreen, &rgnDst); + if (freeSrcClip) + REGION_DESTROY(pGC->pScreen, prgnSrcClip); + return prgnExposed; +} diff --git a/xorg-server/mi/midispcur.c b/xorg-server/mi/midispcur.c index 904163091..d4b7f132b 100644 --- a/xorg-server/mi/midispcur.c +++ b/xorg-server/mi/midispcur.c @@ -1,874 +1,874 @@ -/* - * midispcur.c - * - * machine independent cursor display routines - */ - - -/* - -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 <dix-config.h> -#endif - -# include <X11/X.h> -# include "misc.h" -# include "input.h" -# include "cursorstr.h" -# include "windowstr.h" -# include "regionstr.h" -# include "dixstruct.h" -# include "scrnintstr.h" -# include "servermd.h" -# include "mipointer.h" -# include "misprite.h" -# include "gcstruct.h" - -#ifdef ARGB_CURSOR -# include "picturestr.h" -#endif - -# include "inputstr.h" - -/* per-screen private data */ -static int miDCScreenKeyIndex; -static DevPrivateKey miDCScreenKey = &miDCScreenKeyIndex; - -static Bool miDCCloseScreen(int index, ScreenPtr pScreen); - -/* per device per-screen private data */ -static int miDCSpriteKeyIndex[MAXSCREENS]; -static DevPrivateKey miDCSpriteKey = miDCSpriteKeyIndex; - -typedef struct { - GCPtr pSourceGC, pMaskGC; - GCPtr pSaveGC, pRestoreGC; - GCPtr pMoveGC; - GCPtr pPixSourceGC, pPixMaskGC; - PixmapPtr pSave, pTemp; -#ifdef ARGB_CURSOR - PicturePtr pRootPicture; - PicturePtr pTempPicture; -#endif -} miDCBufferRec, *miDCBufferPtr; - -#define MIDCBUFFER(dev, screen) \ - ((DevHasCursor(dev)) ? \ - (miDCBufferPtr)dixLookupPrivate(&dev->devPrivates, miDCSpriteKey + (screen)->myNum) : \ - (miDCBufferPtr)dixLookupPrivate(&dev->u.master->devPrivates, miDCSpriteKey + (screen)->myNum)) - -/* - * The core pointer buffer will point to the index of the virtual core pointer - * in the pCursorBuffers array. - */ -typedef struct { - CloseScreenProcPtr CloseScreen; -} miDCScreenRec, *miDCScreenPtr; - -/* per-cursor per-screen private data */ -typedef struct { - PixmapPtr sourceBits; /* source bits */ - PixmapPtr maskBits; /* mask bits */ -#ifdef ARGB_CURSOR - PicturePtr pPicture; -#endif -} miDCCursorRec, *miDCCursorPtr; - -/* - * sprite/cursor method table - */ - -static Bool miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); -static Bool miDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); -static Bool miDCPutUpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor, int x, int y, - unsigned long source, unsigned long mask); -static Bool miDCSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, - int w, int h); -static Bool miDCRestoreUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, - int w, int h); -static Bool miDCMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor, int x, int y, - int w, int h, int dx, int dy, - unsigned long source, unsigned long mask); -static Bool miDCChangeSave(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, int w, int h, - int dx, int dy); - -static Bool miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); -static void miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen); - -static miSpriteCursorFuncRec miDCFuncs = { - miDCRealizeCursor, - miDCUnrealizeCursor, - miDCPutUpCursor, - miDCSaveUnderCursor, - miDCRestoreUnderCursor, - miDCMoveCursor, - miDCChangeSave, - miDCDeviceInitialize, - miDCDeviceCleanup -}; - -Bool -miDCInitialize (ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs) -{ - miDCScreenPtr pScreenPriv; - - pScreenPriv = xalloc (sizeof (miDCScreenRec)); - if (!pScreenPriv) - return FALSE; - - - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = miDCCloseScreen; - - dixSetPrivate(&pScreen->devPrivates, miDCScreenKey, pScreenPriv); - - if (!miSpriteInitialize (pScreen, &miDCFuncs, screenFuncs)) - { - xfree ((pointer) pScreenPriv); - return FALSE; - } - return TRUE; -} - -static Bool -miDCCloseScreen (int index, ScreenPtr pScreen) -{ - miDCScreenPtr pScreenPriv; - - pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - miDCScreenKey); - pScreen->CloseScreen = pScreenPriv->CloseScreen; - xfree ((pointer) pScreenPriv); - return (*pScreen->CloseScreen) (index, pScreen); -} - -static Bool -miDCRealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) -{ - if (pCursor->bits->refcnt <= 1) - dixSetPrivate(&pCursor->bits->devPrivates, CursorScreenKey(pScreen), NULL); - return TRUE; -} - -#ifdef ARGB_CURSOR - -static VisualPtr -miDCGetWindowVisual (WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - VisualID vid = wVisual (pWin); - int i; - - for (i = 0; i < pScreen->numVisuals; i++) - if (pScreen->visuals[i].vid == vid) - return &pScreen->visuals[i]; - return 0; -} - -static PicturePtr -miDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin) -{ - ScreenPtr pScreen = pDraw->pScreen; - VisualPtr pVisual; - PictFormatPtr pFormat; - XID subwindow_mode = IncludeInferiors; - PicturePtr pPicture; - int error; - - pVisual = miDCGetWindowVisual (pWin); - if (!pVisual) - return 0; - pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual); - if (!pFormat) - return 0; - pPicture = CreatePicture (0, pDraw, pFormat, - CPSubwindowMode, &subwindow_mode, - serverClient, &error); - *ppPicture = pPicture; - return pPicture; -} -#endif - -static miDCCursorPtr -miDCRealize (ScreenPtr pScreen, CursorPtr pCursor) -{ - miDCCursorPtr pPriv; - GCPtr pGC; - XID gcvals[3]; - - pPriv = xalloc (sizeof (miDCCursorRec)); - if (!pPriv) - return NULL; -#ifdef ARGB_CURSOR - if (pCursor->bits->argb) - { - PixmapPtr pPixmap; - PictFormatPtr pFormat; - int error; - - pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); - if (!pFormat) - { - xfree ((pointer) pPriv); - return NULL; - } - - pPriv->sourceBits = 0; - pPriv->maskBits = 0; - pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, - pCursor->bits->height, 32, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pPixmap) - { - xfree ((pointer) pPriv); - return NULL; - } - pGC = GetScratchGC (32, pScreen); - if (!pGC) - { - (*pScreen->DestroyPixmap) (pPixmap); - xfree ((pointer) pPriv); - return NULL; - } - ValidateGC (&pPixmap->drawable, pGC); - (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32, - 0, 0, pCursor->bits->width, - pCursor->bits->height, - 0, ZPixmap, (char *) pCursor->bits->argb); - FreeScratchGC (pGC); - pPriv->pPicture = CreatePicture (0, &pPixmap->drawable, - pFormat, 0, 0, serverClient, &error); - (*pScreen->DestroyPixmap) (pPixmap); - if (!pPriv->pPicture) - { - xfree ((pointer) pPriv); - return NULL; - } - dixSetPrivate(&pCursor->bits->devPrivates, CursorScreenKey(pScreen), pPriv); - return pPriv; - } - pPriv->pPicture = 0; -#endif - pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); - if (!pPriv->sourceBits) - { - xfree ((pointer) pPriv); - return NULL; - } - pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); - if (!pPriv->maskBits) - { - (*pScreen->DestroyPixmap) (pPriv->sourceBits); - xfree ((pointer) pPriv); - return NULL; - } - dixSetPrivate(&pCursor->bits->devPrivates, CursorScreenKey(pScreen), pPriv); - - /* create the two sets of bits, clipping as appropriate */ - - pGC = GetScratchGC (1, pScreen); - if (!pGC) - { - (void) miDCUnrealizeCursor (pScreen, pCursor); - return NULL; - } - - ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); - (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, - 0, 0, pCursor->bits->width, pCursor->bits->height, - 0, XYPixmap, (char *)pCursor->bits->source); - gcvals[0] = GXand; - ChangeGC (pGC, GCFunction, gcvals); - ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); - (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, - 0, 0, pCursor->bits->width, pCursor->bits->height, - 0, XYPixmap, (char *)pCursor->bits->mask); - - /* mask bits -- pCursor->mask & ~pCursor->source */ - gcvals[0] = GXcopy; - ChangeGC (pGC, GCFunction, gcvals); - ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); - (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, - 0, 0, pCursor->bits->width, pCursor->bits->height, - 0, XYPixmap, (char *)pCursor->bits->mask); - gcvals[0] = GXandInverted; - ChangeGC (pGC, GCFunction, gcvals); - ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); - (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, - 0, 0, pCursor->bits->width, pCursor->bits->height, - 0, XYPixmap, (char *)pCursor->bits->source); - FreeScratchGC (pGC); - return pPriv; -} - -static Bool -miDCUnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) -{ - miDCCursorPtr pPriv; - - pPriv = (miDCCursorPtr)dixLookupPrivate(&pCursor->bits->devPrivates, - CursorScreenKey(pScreen)); - if (pPriv && (pCursor->bits->refcnt <= 1)) - { - if (pPriv->sourceBits) - (*pScreen->DestroyPixmap) (pPriv->sourceBits); - if (pPriv->maskBits) - (*pScreen->DestroyPixmap) (pPriv->maskBits); -#ifdef ARGB_CURSOR - if (pPriv->pPicture) - FreePicture (pPriv->pPicture, 0); -#endif - xfree ((pointer) pPriv); - dixSetPrivate(&pCursor->bits->devPrivates, CursorScreenKey(pScreen), NULL); - } - return TRUE; -} - -static void -miDCPutBits ( - DrawablePtr pDrawable, - miDCCursorPtr pPriv, - GCPtr sourceGC, - GCPtr maskGC, - int x_org, - int y_org, - unsigned w, - unsigned h, - unsigned long source, - unsigned long mask) -{ - XID gcvals[1]; - int x, y; - - if (sourceGC->fgPixel != source) - { - gcvals[0] = source; - DoChangeGC (sourceGC, GCForeground, gcvals, 0); - } - if (sourceGC->serialNumber != pDrawable->serialNumber) - ValidateGC (pDrawable, sourceGC); - - if(sourceGC->miTranslate) - { - x = pDrawable->x + x_org; - y = pDrawable->y + y_org; - } - else - { - x = x_org; - y = y_org; - } - - (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y); - if (maskGC->fgPixel != mask) - { - gcvals[0] = mask; - DoChangeGC (maskGC, GCForeground, gcvals, 0); - } - if (maskGC->serialNumber != pDrawable->serialNumber) - ValidateGC (pDrawable, maskGC); - - if(maskGC->miTranslate) - { - x = pDrawable->x + x_org; - y = pDrawable->y + y_org; - } - else - { - x = x_org; - y = y_org; - } - - (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y); -} - -static GCPtr -miDCMakeGC(WindowPtr pWin) -{ - GCPtr pGC; - int status; - XID gcvals[2]; - - gcvals[0] = IncludeInferiors; - gcvals[1] = FALSE; - pGC = CreateGC((DrawablePtr)pWin, - GCSubwindowMode|GCGraphicsExposures, gcvals, &status, - (XID)0, serverClient); - return pGC; -} - - -static Bool -miDCPutUpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, - int x, int y, unsigned long source, unsigned long mask) -{ - miDCScreenPtr pScreenPriv; - miDCCursorPtr pPriv; - miDCBufferPtr pBuffer; - WindowPtr pWin; - - pPriv = (miDCCursorPtr)dixLookupPrivate(&pCursor->bits->devPrivates, - CursorScreenKey(pScreen)); - if (!pPriv) - { - pPriv = miDCRealize(pScreen, pCursor); - if (!pPriv) - return FALSE; - } - pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - miDCScreenKey); - pWin = WindowTable[pScreen->myNum]; - pBuffer = MIDCBUFFER(pDev, pScreen); - -#ifdef ARGB_CURSOR - if (pPriv->pPicture) - { - CompositePicture (PictOpOver, - pPriv->pPicture, - NULL, - pBuffer->pRootPicture, - 0, 0, 0, 0, - x, y, - pCursor->bits->width, - pCursor->bits->height); - } - else -#endif - { - miDCPutBits ((DrawablePtr)pWin, pPriv, - pBuffer->pSourceGC, pBuffer->pMaskGC, - x, y, pCursor->bits->width, pCursor->bits->height, - source, mask); - } - return TRUE; -} - -static Bool -miDCSaveUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, int w, int h) -{ - miDCScreenPtr pScreenPriv; - miDCBufferPtr pBuffer; - PixmapPtr pSave; - WindowPtr pWin; - GCPtr pGC; - - pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - miDCScreenKey); - pBuffer = MIDCBUFFER(pDev, pScreen); - - pSave = pBuffer->pSave; - pWin = WindowTable[pScreen->myNum]; - if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) - { - if (pSave) - (*pScreen->DestroyPixmap) (pSave); - pBuffer->pSave = pSave = - (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth, 0); - if (!pSave) - return FALSE; - } - - pGC = pBuffer->pSaveGC; - if (pSave->drawable.serialNumber != pGC->serialNumber) - ValidateGC ((DrawablePtr) pSave, pGC); - (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, - x, y, w, h, 0, 0); - return TRUE; -} - -static Bool -miDCRestoreUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, int w, int h) -{ - miDCScreenPtr pScreenPriv; - miDCBufferPtr pBuffer; - PixmapPtr pSave; - WindowPtr pWin; - GCPtr pGC; - - pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - miDCScreenKey); - pBuffer = MIDCBUFFER(pDev, pScreen); - pSave = pBuffer->pSave; - - pWin = WindowTable[pScreen->myNum]; - if (!pSave) - return FALSE; - - pGC = pBuffer->pRestoreGC; - if (pWin->drawable.serialNumber != pGC->serialNumber) - ValidateGC ((DrawablePtr) pWin, pGC); - (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, - 0, 0, w, h, x, y); - return TRUE; -} - -static Bool -miDCChangeSave (DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, int w, int h, int dx, int dy) -{ - miDCScreenPtr pScreenPriv; - miDCBufferPtr pBuffer; - PixmapPtr pSave; - WindowPtr pWin; - GCPtr pGC; - int sourcex, sourcey, destx, desty, copyw, copyh; - - pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - miDCScreenKey); - pBuffer = MIDCBUFFER(pDev, pScreen); - - pSave = pBuffer->pSave; - pWin = WindowTable[pScreen->myNum]; - /* - * restore the bits which are about to get trashed - */ - if (!pSave) - return FALSE; - - pGC = pBuffer->pRestoreGC; - if (pWin->drawable.serialNumber != pGC->serialNumber) - ValidateGC ((DrawablePtr) pWin, pGC); - /* - * copy the old bits to the screen. - */ - if (dy > 0) - { - (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, - 0, h - dy, w, dy, x + dx, y + h); - } - else if (dy < 0) - { - (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, - 0, 0, w, -dy, x + dx, y + dy); - } - if (dy >= 0) - { - desty = y + dy; - sourcey = 0; - copyh = h - dy; - } - else - { - desty = y; - sourcey = - dy; - copyh = h + dy; - } - if (dx > 0) - { - (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, - w - dx, sourcey, dx, copyh, x + w, desty); - } - else if (dx < 0) - { - (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, - 0, sourcey, -dx, copyh, x + dx, desty); - } - - pGC = pBuffer->pSaveGC; - if (pSave->drawable.serialNumber != pGC->serialNumber) - ValidateGC ((DrawablePtr) pSave, pGC); - /* - * move the bits that are still valid within the pixmap - */ - if (dx >= 0) - { - sourcex = 0; - destx = dx; - copyw = w - dx; - } - else - { - destx = 0; - sourcex = - dx; - copyw = w + dx; - } - if (dy >= 0) - { - sourcey = 0; - desty = dy; - copyh = h - dy; - } - else - { - desty = 0; - sourcey = -dy; - copyh = h + dy; - } - (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pSave, pGC, - sourcex, sourcey, copyw, copyh, destx, desty); - /* - * copy the new bits from the screen into the remaining areas of the - * pixmap - */ - if (dy > 0) - { - (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, - x, y, w, dy, 0, 0); - } - else if (dy < 0) - { - (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, - x, y + h + dy, w, -dy, 0, h + dy); - } - if (dy >= 0) - { - desty = dy; - sourcey = y + dy; - copyh = h - dy; - } - else - { - desty = 0; - sourcey = y; - copyh = h + dy; - } - if (dx > 0) - { - (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, - x, sourcey, dx, copyh, 0, desty); - } - else if (dx < 0) - { - (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, - x + w + dx, sourcey, -dx, copyh, w + dx, desty); - } - return TRUE; -} - -static Bool -miDCMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, - int x, int y, int w, int h, int dx, int dy, - unsigned long source, unsigned long mask) -{ - miDCCursorPtr pPriv; - miDCScreenPtr pScreenPriv; - miDCBufferPtr pBuffer; - int status; - WindowPtr pWin; - GCPtr pGC; - XID gcval = FALSE; - PixmapPtr pTemp; - - pPriv = (miDCCursorPtr)dixLookupPrivate(&pCursor->bits->devPrivates, - CursorScreenKey(pScreen)); - if (!pPriv) - { - pPriv = miDCRealize(pScreen, pCursor); - if (!pPriv) - return FALSE; - } - pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - miDCScreenKey); - pWin = WindowTable[pScreen->myNum]; - pBuffer = MIDCBUFFER(pDev, pScreen); - - pTemp = pBuffer->pTemp; - if (!pTemp || - pTemp->drawable.width != pBuffer->pSave->drawable.width || - pTemp->drawable.height != pBuffer->pSave->drawable.height) - { - if (pTemp) - (*pScreen->DestroyPixmap) (pTemp); -#ifdef ARGB_CURSOR - if (pBuffer->pTempPicture) - { - FreePicture (pBuffer->pTempPicture, 0); - pBuffer->pTempPicture = 0; - } -#endif - pBuffer->pTemp = pTemp = (*pScreen->CreatePixmap) - (pScreen, w, h, pBuffer->pSave->drawable.depth, 0); - if (!pTemp) - return FALSE; - } - if (!pBuffer->pMoveGC) - { - pBuffer->pMoveGC = CreateGC ((DrawablePtr)pTemp, - GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); - if (!pBuffer->pMoveGC) - return FALSE; - } - /* - * copy the saved area to a temporary pixmap - */ - pGC = pBuffer->pMoveGC; - if (pGC->serialNumber != pTemp->drawable.serialNumber) - ValidateGC ((DrawablePtr) pTemp, pGC); - (*pGC->ops->CopyArea)((DrawablePtr)pBuffer->pSave, - (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0); - - /* - * draw the cursor in the temporary pixmap - */ -#ifdef ARGB_CURSOR - if (pPriv->pPicture) - { - if (!pBuffer->pTempPicture) - miDCMakePicture(&pBuffer->pTempPicture, &pTemp->drawable, pWin); - - CompositePicture (PictOpOver, - pPriv->pPicture, - NULL, - pBuffer->pTempPicture, - 0, 0, 0, 0, - dx, dy, - pCursor->bits->width, - pCursor->bits->height); - } - else -#endif - { - miDCPutBits ((DrawablePtr)pTemp, pPriv, - pBuffer->pPixSourceGC, pBuffer->pPixMaskGC, - dx, dy, pCursor->bits->width, pCursor->bits->height, - source, mask); - } - - pGC = pBuffer->pRestoreGC; - if (pWin->drawable.serialNumber != pGC->serialNumber) - ValidateGC ((DrawablePtr) pWin, pGC); - - (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin, - pGC, - 0, 0, w, h, x, y); - return TRUE; -} - -static Bool -miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - miDCBufferPtr pBuffer; - WindowPtr pWin; - XID gcval = FALSE; - int status; - int i; - - if (!DevHasCursor(pDev)) - return TRUE; - - for (i = 0; i < screenInfo.numScreens; i++) - { - pScreen = screenInfo.screens[i]; - - pBuffer = xalloc(sizeof(miDCBufferRec)); - if (!pBuffer) - goto failure; - - dixSetPrivate(&pDev->devPrivates, miDCSpriteKey + pScreen->myNum, pBuffer); - pWin = WindowTable[pScreen->myNum]; - - pBuffer->pSourceGC = miDCMakeGC(pWin); - if (!pBuffer->pSourceGC) - goto failure; - - pBuffer->pMaskGC = miDCMakeGC(pWin); - if (!pBuffer->pMaskGC) - goto failure; - - pBuffer->pSaveGC = miDCMakeGC(pWin); - if (!pBuffer->pSaveGC) - goto failure; - - pBuffer->pRestoreGC = miDCMakeGC(pWin); - if (!pBuffer->pRestoreGC) - goto failure; - - pBuffer->pMoveGC = CreateGC ((DrawablePtr)pWin, - GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); - if (!pBuffer->pMoveGC) - goto failure; - - pBuffer->pPixSourceGC = CreateGC ((DrawablePtr)pWin, - GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); - if (!pBuffer->pPixSourceGC) - goto failure; - - pBuffer->pPixMaskGC = CreateGC ((DrawablePtr)pWin, - GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); - if (!pBuffer->pPixMaskGC) - goto failure; - -#ifdef ARGB_CURSOR - miDCMakePicture(&pBuffer->pRootPicture, &pWin->drawable, pWin); - if (!pBuffer->pRootPicture) - goto failure; - - pBuffer->pTempPicture = NULL; -#endif - - // these get (re)allocated lazily depending on the cursor size - pBuffer->pSave = pBuffer->pTemp = NULL; - } - - return TRUE; - -failure: - - miDCDeviceCleanup(pDev, pScreen); - - return FALSE; -} - -static void -miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - miDCBufferPtr pBuffer; - int i; - - if (DevHasCursor(pDev)) - { - for (i = 0; i < screenInfo.numScreens; i++) - { - pScreen = screenInfo.screens[i]; - - pBuffer = MIDCBUFFER(pDev, pScreen); - - if (pBuffer) - { - if (pBuffer->pSourceGC) FreeGC(pBuffer->pSourceGC, (GContext) 0); - if (pBuffer->pMaskGC) FreeGC(pBuffer->pMaskGC, (GContext) 0); - if (pBuffer->pSaveGC) FreeGC(pBuffer->pSaveGC, (GContext) 0); - if (pBuffer->pRestoreGC) FreeGC(pBuffer->pRestoreGC, (GContext) 0); - if (pBuffer->pMoveGC) FreeGC(pBuffer->pMoveGC, (GContext) 0); - if (pBuffer->pPixSourceGC) FreeGC(pBuffer->pPixSourceGC, (GContext) 0); - if (pBuffer->pPixMaskGC) FreeGC(pBuffer->pPixMaskGC, (GContext) 0); - - if (pBuffer->pSave) (*pScreen->DestroyPixmap)(pBuffer->pSave); - if (pBuffer->pTemp) (*pScreen->DestroyPixmap)(pBuffer->pTemp); - - xfree(pBuffer); - dixSetPrivate(&pDev->devPrivates, miDCSpriteKey + pScreen->myNum, NULL); - } - } - } -} +/* + * midispcur.c + * + * machine independent cursor display routines + */ + + +/* + +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 <dix-config.h> +#endif + +# include <X11/X.h> +# include "misc.h" +# include "input.h" +# include "cursorstr.h" +# include "windowstr.h" +# include "regionstr.h" +# include "dixstruct.h" +# include "scrnintstr.h" +# include "servermd.h" +# include "mipointer.h" +# include "misprite.h" +# include "gcstruct.h" + +#ifdef ARGB_CURSOR +# include "picturestr.h" +#endif + +# include "inputstr.h" + +/* per-screen private data */ +static int miDCScreenKeyIndex; +static DevPrivateKey miDCScreenKey = &miDCScreenKeyIndex; + +static Bool miDCCloseScreen(int index, ScreenPtr pScreen); + +/* per device per-screen private data */ +static int miDCSpriteKeyIndex[MAXSCREENS]; +static DevPrivateKey miDCSpriteKey = miDCSpriteKeyIndex; + +typedef struct { + GCPtr pSourceGC, pMaskGC; + GCPtr pSaveGC, pRestoreGC; + GCPtr pMoveGC; + GCPtr pPixSourceGC, pPixMaskGC; + PixmapPtr pSave, pTemp; +#ifdef ARGB_CURSOR + PicturePtr pRootPicture; + PicturePtr pTempPicture; +#endif +} miDCBufferRec, *miDCBufferPtr; + +#define MIDCBUFFER(dev, screen) \ + ((DevHasCursor(dev)) ? \ + (miDCBufferPtr)dixLookupPrivate(&dev->devPrivates, miDCSpriteKey + (screen)->myNum) : \ + (miDCBufferPtr)dixLookupPrivate(&dev->u.master->devPrivates, miDCSpriteKey + (screen)->myNum)) + +/* + * The core pointer buffer will point to the index of the virtual core pointer + * in the pCursorBuffers array. + */ +typedef struct { + CloseScreenProcPtr CloseScreen; +} miDCScreenRec, *miDCScreenPtr; + +/* per-cursor per-screen private data */ +typedef struct { + PixmapPtr sourceBits; /* source bits */ + PixmapPtr maskBits; /* mask bits */ +#ifdef ARGB_CURSOR + PicturePtr pPicture; +#endif +} miDCCursorRec, *miDCCursorPtr; + +/* + * sprite/cursor method table + */ + +static Bool miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +static Bool miDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +static Bool miDCPutUpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, int x, int y, + unsigned long source, unsigned long mask); +static Bool miDCSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, + int w, int h); +static Bool miDCRestoreUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, + int w, int h); +static Bool miDCMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, int x, int y, + int w, int h, int dx, int dy, + unsigned long source, unsigned long mask); +static Bool miDCChangeSave(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, int w, int h, + int dx, int dy); + +static Bool miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); +static void miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen); + +static miSpriteCursorFuncRec miDCFuncs = { + miDCRealizeCursor, + miDCUnrealizeCursor, + miDCPutUpCursor, + miDCSaveUnderCursor, + miDCRestoreUnderCursor, + miDCMoveCursor, + miDCChangeSave, + miDCDeviceInitialize, + miDCDeviceCleanup +}; + +Bool +miDCInitialize (ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs) +{ + miDCScreenPtr pScreenPriv; + + pScreenPriv = malloc(sizeof (miDCScreenRec)); + if (!pScreenPriv) + return FALSE; + + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = miDCCloseScreen; + + dixSetPrivate(&pScreen->devPrivates, miDCScreenKey, pScreenPriv); + + if (!miSpriteInitialize (pScreen, &miDCFuncs, screenFuncs)) + { + free((pointer) pScreenPriv); + return FALSE; + } + return TRUE; +} + +static Bool +miDCCloseScreen (int index, ScreenPtr pScreen) +{ + miDCScreenPtr pScreenPriv; + + pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + pScreen->CloseScreen = pScreenPriv->CloseScreen; + free((pointer) pScreenPriv); + return (*pScreen->CloseScreen) (index, pScreen); +} + +static Bool +miDCRealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) +{ + if (pCursor->bits->refcnt <= 1) + dixSetPrivate(&pCursor->bits->devPrivates, CursorScreenKey(pScreen), NULL); + return TRUE; +} + +#ifdef ARGB_CURSOR + +static VisualPtr +miDCGetWindowVisual (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + VisualID vid = wVisual (pWin); + int i; + + for (i = 0; i < pScreen->numVisuals; i++) + if (pScreen->visuals[i].vid == vid) + return &pScreen->visuals[i]; + return 0; +} + +static PicturePtr +miDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin) +{ + ScreenPtr pScreen = pDraw->pScreen; + VisualPtr pVisual; + PictFormatPtr pFormat; + XID subwindow_mode = IncludeInferiors; + PicturePtr pPicture; + int error; + + pVisual = miDCGetWindowVisual (pWin); + if (!pVisual) + return 0; + pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual); + if (!pFormat) + return 0; + pPicture = CreatePicture (0, pDraw, pFormat, + CPSubwindowMode, &subwindow_mode, + serverClient, &error); + *ppPicture = pPicture; + return pPicture; +} +#endif + +static miDCCursorPtr +miDCRealize (ScreenPtr pScreen, CursorPtr pCursor) +{ + miDCCursorPtr pPriv; + GCPtr pGC; + ChangeGCVal gcvals; + + pPriv = malloc(sizeof (miDCCursorRec)); + if (!pPriv) + return NULL; +#ifdef ARGB_CURSOR + if (pCursor->bits->argb) + { + PixmapPtr pPixmap; + PictFormatPtr pFormat; + int error; + + pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); + if (!pFormat) + { + free((pointer) pPriv); + return NULL; + } + + pPriv->sourceBits = 0; + pPriv->maskBits = 0; + pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, + pCursor->bits->height, 32, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pPixmap) + { + free((pointer) pPriv); + return NULL; + } + pGC = GetScratchGC (32, pScreen); + if (!pGC) + { + (*pScreen->DestroyPixmap) (pPixmap); + free((pointer) pPriv); + return NULL; + } + ValidateGC (&pPixmap->drawable, pGC); + (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32, + 0, 0, pCursor->bits->width, + pCursor->bits->height, + 0, ZPixmap, (char *) pCursor->bits->argb); + FreeScratchGC (pGC); + pPriv->pPicture = CreatePicture (0, &pPixmap->drawable, + pFormat, 0, 0, serverClient, &error); + (*pScreen->DestroyPixmap) (pPixmap); + if (!pPriv->pPicture) + { + free((pointer) pPriv); + return NULL; + } + dixSetPrivate(&pCursor->bits->devPrivates, CursorScreenKey(pScreen), pPriv); + return pPriv; + } + pPriv->pPicture = 0; +#endif + pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); + if (!pPriv->sourceBits) + { + free((pointer) pPriv); + return NULL; + } + pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); + if (!pPriv->maskBits) + { + (*pScreen->DestroyPixmap) (pPriv->sourceBits); + free((pointer) pPriv); + return NULL; + } + dixSetPrivate(&pCursor->bits->devPrivates, CursorScreenKey(pScreen), pPriv); + + /* create the two sets of bits, clipping as appropriate */ + + pGC = GetScratchGC (1, pScreen); + if (!pGC) + { + (void) miDCUnrealizeCursor (pScreen, pCursor); + return NULL; + } + + ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); + (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, + 0, 0, pCursor->bits->width, pCursor->bits->height, + 0, XYPixmap, (char *)pCursor->bits->source); + gcvals.val = GXand; + ChangeGC (NullClient, pGC, GCFunction, &gcvals); + ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); + (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, + 0, 0, pCursor->bits->width, pCursor->bits->height, + 0, XYPixmap, (char *)pCursor->bits->mask); + + /* mask bits -- pCursor->mask & ~pCursor->source */ + gcvals.val = GXcopy; + ChangeGC (NullClient, pGC, GCFunction, &gcvals); + ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); + (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, + 0, 0, pCursor->bits->width, pCursor->bits->height, + 0, XYPixmap, (char *)pCursor->bits->mask); + gcvals.val = GXandInverted; + ChangeGC (NullClient, pGC, GCFunction, &gcvals); + ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); + (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, + 0, 0, pCursor->bits->width, pCursor->bits->height, + 0, XYPixmap, (char *)pCursor->bits->source); + FreeScratchGC (pGC); + return pPriv; +} + +static Bool +miDCUnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) +{ + miDCCursorPtr pPriv; + + pPriv = (miDCCursorPtr)dixLookupPrivate(&pCursor->bits->devPrivates, + CursorScreenKey(pScreen)); + if (pPriv && (pCursor->bits->refcnt <= 1)) + { + if (pPriv->sourceBits) + (*pScreen->DestroyPixmap) (pPriv->sourceBits); + if (pPriv->maskBits) + (*pScreen->DestroyPixmap) (pPriv->maskBits); +#ifdef ARGB_CURSOR + if (pPriv->pPicture) + FreePicture (pPriv->pPicture, 0); +#endif + free((pointer) pPriv); + dixSetPrivate(&pCursor->bits->devPrivates, CursorScreenKey(pScreen), NULL); + } + return TRUE; +} + +static void +miDCPutBits ( + DrawablePtr pDrawable, + miDCCursorPtr pPriv, + GCPtr sourceGC, + GCPtr maskGC, + int x_org, + int y_org, + unsigned w, + unsigned h, + unsigned long source, + unsigned long mask) +{ + ChangeGCVal gcval; + int x, y; + + if (sourceGC->fgPixel != source) + { + gcval.val = source; + ChangeGC (NullClient, sourceGC, GCForeground, &gcval); + } + if (sourceGC->serialNumber != pDrawable->serialNumber) + ValidateGC (pDrawable, sourceGC); + + if(sourceGC->miTranslate) + { + x = pDrawable->x + x_org; + y = pDrawable->y + y_org; + } + else + { + x = x_org; + y = y_org; + } + + (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y); + if (maskGC->fgPixel != mask) + { + gcval.val = mask; + ChangeGC (NullClient, maskGC, GCForeground, &gcval); + } + if (maskGC->serialNumber != pDrawable->serialNumber) + ValidateGC (pDrawable, maskGC); + + if(maskGC->miTranslate) + { + x = pDrawable->x + x_org; + y = pDrawable->y + y_org; + } + else + { + x = x_org; + y = y_org; + } + + (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y); +} + +static GCPtr +miDCMakeGC(WindowPtr pWin) +{ + GCPtr pGC; + int status; + XID gcvals[2]; + + gcvals[0] = IncludeInferiors; + gcvals[1] = FALSE; + pGC = CreateGC((DrawablePtr)pWin, + GCSubwindowMode|GCGraphicsExposures, gcvals, &status, + (XID)0, serverClient); + return pGC; +} + + +static Bool +miDCPutUpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, + int x, int y, unsigned long source, unsigned long mask) +{ + miDCScreenPtr pScreenPriv; + miDCCursorPtr pPriv; + miDCBufferPtr pBuffer; + WindowPtr pWin; + + pPriv = (miDCCursorPtr)dixLookupPrivate(&pCursor->bits->devPrivates, + CursorScreenKey(pScreen)); + if (!pPriv) + { + pPriv = miDCRealize(pScreen, pCursor); + if (!pPriv) + return FALSE; + } + pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + pWin = WindowTable[pScreen->myNum]; + pBuffer = MIDCBUFFER(pDev, pScreen); + +#ifdef ARGB_CURSOR + if (pPriv->pPicture) + { + CompositePicture (PictOpOver, + pPriv->pPicture, + NULL, + pBuffer->pRootPicture, + 0, 0, 0, 0, + x, y, + pCursor->bits->width, + pCursor->bits->height); + } + else +#endif + { + miDCPutBits ((DrawablePtr)pWin, pPriv, + pBuffer->pSourceGC, pBuffer->pMaskGC, + x, y, pCursor->bits->width, pCursor->bits->height, + source, mask); + } + return TRUE; +} + +static Bool +miDCSaveUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, int w, int h) +{ + miDCScreenPtr pScreenPriv; + miDCBufferPtr pBuffer; + PixmapPtr pSave; + WindowPtr pWin; + GCPtr pGC; + + pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + pBuffer = MIDCBUFFER(pDev, pScreen); + + pSave = pBuffer->pSave; + pWin = WindowTable[pScreen->myNum]; + if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) + { + if (pSave) + (*pScreen->DestroyPixmap) (pSave); + pBuffer->pSave = pSave = + (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth, 0); + if (!pSave) + return FALSE; + } + + pGC = pBuffer->pSaveGC; + if (pSave->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pSave, pGC); + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x, y, w, h, 0, 0); + return TRUE; +} + +static Bool +miDCRestoreUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, int w, int h) +{ + miDCScreenPtr pScreenPriv; + miDCBufferPtr pBuffer; + PixmapPtr pSave; + WindowPtr pWin; + GCPtr pGC; + + pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + pBuffer = MIDCBUFFER(pDev, pScreen); + pSave = pBuffer->pSave; + + pWin = WindowTable[pScreen->myNum]; + if (!pSave) + return FALSE; + + pGC = pBuffer->pRestoreGC; + if (pWin->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pWin, pGC); + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + 0, 0, w, h, x, y); + return TRUE; +} + +static Bool +miDCChangeSave (DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, int w, int h, int dx, int dy) +{ + miDCScreenPtr pScreenPriv; + miDCBufferPtr pBuffer; + PixmapPtr pSave; + WindowPtr pWin; + GCPtr pGC; + int sourcex, sourcey, destx, desty, copyw, copyh; + + pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + pBuffer = MIDCBUFFER(pDev, pScreen); + + pSave = pBuffer->pSave; + pWin = WindowTable[pScreen->myNum]; + /* + * restore the bits which are about to get trashed + */ + if (!pSave) + return FALSE; + + pGC = pBuffer->pRestoreGC; + if (pWin->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pWin, pGC); + /* + * copy the old bits to the screen. + */ + if (dy > 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + 0, h - dy, w, dy, x + dx, y + h); + } + else if (dy < 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + 0, 0, w, -dy, x + dx, y + dy); + } + if (dy >= 0) + { + desty = y + dy; + sourcey = 0; + copyh = h - dy; + } + else + { + desty = y; + sourcey = - dy; + copyh = h + dy; + } + if (dx > 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + w - dx, sourcey, dx, copyh, x + w, desty); + } + else if (dx < 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + 0, sourcey, -dx, copyh, x + dx, desty); + } + + pGC = pBuffer->pSaveGC; + if (pSave->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pSave, pGC); + /* + * move the bits that are still valid within the pixmap + */ + if (dx >= 0) + { + sourcex = 0; + destx = dx; + copyw = w - dx; + } + else + { + destx = 0; + sourcex = - dx; + copyw = w + dx; + } + if (dy >= 0) + { + sourcey = 0; + desty = dy; + copyh = h - dy; + } + else + { + desty = 0; + sourcey = -dy; + copyh = h + dy; + } + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pSave, pGC, + sourcex, sourcey, copyw, copyh, destx, desty); + /* + * copy the new bits from the screen into the remaining areas of the + * pixmap + */ + if (dy > 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x, y, w, dy, 0, 0); + } + else if (dy < 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x, y + h + dy, w, -dy, 0, h + dy); + } + if (dy >= 0) + { + desty = dy; + sourcey = y + dy; + copyh = h - dy; + } + else + { + desty = 0; + sourcey = y; + copyh = h + dy; + } + if (dx > 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x, sourcey, dx, copyh, 0, desty); + } + else if (dx < 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x + w + dx, sourcey, -dx, copyh, w + dx, desty); + } + return TRUE; +} + +static Bool +miDCMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, + int x, int y, int w, int h, int dx, int dy, + unsigned long source, unsigned long mask) +{ + miDCCursorPtr pPriv; + miDCScreenPtr pScreenPriv; + miDCBufferPtr pBuffer; + int status; + WindowPtr pWin; + GCPtr pGC; + XID gcval = FALSE; + PixmapPtr pTemp; + + pPriv = (miDCCursorPtr)dixLookupPrivate(&pCursor->bits->devPrivates, + CursorScreenKey(pScreen)); + if (!pPriv) + { + pPriv = miDCRealize(pScreen, pCursor); + if (!pPriv) + return FALSE; + } + pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + pWin = WindowTable[pScreen->myNum]; + pBuffer = MIDCBUFFER(pDev, pScreen); + + pTemp = pBuffer->pTemp; + if (!pTemp || + pTemp->drawable.width != pBuffer->pSave->drawable.width || + pTemp->drawable.height != pBuffer->pSave->drawable.height) + { + if (pTemp) + (*pScreen->DestroyPixmap) (pTemp); +#ifdef ARGB_CURSOR + if (pBuffer->pTempPicture) + { + FreePicture (pBuffer->pTempPicture, 0); + pBuffer->pTempPicture = 0; + } +#endif + pBuffer->pTemp = pTemp = (*pScreen->CreatePixmap) + (pScreen, w, h, pBuffer->pSave->drawable.depth, 0); + if (!pTemp) + return FALSE; + } + if (!pBuffer->pMoveGC) + { + pBuffer->pMoveGC = CreateGC ((DrawablePtr)pTemp, + GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); + if (!pBuffer->pMoveGC) + return FALSE; + } + /* + * copy the saved area to a temporary pixmap + */ + pGC = pBuffer->pMoveGC; + if (pGC->serialNumber != pTemp->drawable.serialNumber) + ValidateGC ((DrawablePtr) pTemp, pGC); + (*pGC->ops->CopyArea)((DrawablePtr)pBuffer->pSave, + (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0); + + /* + * draw the cursor in the temporary pixmap + */ +#ifdef ARGB_CURSOR + if (pPriv->pPicture) + { + if (!pBuffer->pTempPicture) + miDCMakePicture(&pBuffer->pTempPicture, &pTemp->drawable, pWin); + + CompositePicture (PictOpOver, + pPriv->pPicture, + NULL, + pBuffer->pTempPicture, + 0, 0, 0, 0, + dx, dy, + pCursor->bits->width, + pCursor->bits->height); + } + else +#endif + { + miDCPutBits ((DrawablePtr)pTemp, pPriv, + pBuffer->pPixSourceGC, pBuffer->pPixMaskGC, + dx, dy, pCursor->bits->width, pCursor->bits->height, + source, mask); + } + + pGC = pBuffer->pRestoreGC; + if (pWin->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pWin, pGC); + + (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin, + pGC, + 0, 0, w, h, x, y); + return TRUE; +} + +static Bool +miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miDCBufferPtr pBuffer; + WindowPtr pWin; + XID gcval = FALSE; + int status; + int i; + + if (!DevHasCursor(pDev)) + return TRUE; + + for (i = 0; i < screenInfo.numScreens; i++) + { + pScreen = screenInfo.screens[i]; + + pBuffer = malloc(sizeof(miDCBufferRec)); + if (!pBuffer) + goto failure; + + dixSetPrivate(&pDev->devPrivates, miDCSpriteKey + pScreen->myNum, pBuffer); + pWin = WindowTable[pScreen->myNum]; + + pBuffer->pSourceGC = miDCMakeGC(pWin); + if (!pBuffer->pSourceGC) + goto failure; + + pBuffer->pMaskGC = miDCMakeGC(pWin); + if (!pBuffer->pMaskGC) + goto failure; + + pBuffer->pSaveGC = miDCMakeGC(pWin); + if (!pBuffer->pSaveGC) + goto failure; + + pBuffer->pRestoreGC = miDCMakeGC(pWin); + if (!pBuffer->pRestoreGC) + goto failure; + + pBuffer->pMoveGC = CreateGC ((DrawablePtr)pWin, + GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); + if (!pBuffer->pMoveGC) + goto failure; + + pBuffer->pPixSourceGC = CreateGC ((DrawablePtr)pWin, + GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); + if (!pBuffer->pPixSourceGC) + goto failure; + + pBuffer->pPixMaskGC = CreateGC ((DrawablePtr)pWin, + GCGraphicsExposures, &gcval, &status, (XID)0, serverClient); + if (!pBuffer->pPixMaskGC) + goto failure; + +#ifdef ARGB_CURSOR + miDCMakePicture(&pBuffer->pRootPicture, &pWin->drawable, pWin); + if (!pBuffer->pRootPicture) + goto failure; + + pBuffer->pTempPicture = NULL; +#endif + + // these get (re)allocated lazily depending on the cursor size + pBuffer->pSave = pBuffer->pTemp = NULL; + } + + return TRUE; + +failure: + + miDCDeviceCleanup(pDev, pScreen); + + return FALSE; +} + +static void +miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miDCBufferPtr pBuffer; + int i; + + if (DevHasCursor(pDev)) + { + for (i = 0; i < screenInfo.numScreens; i++) + { + pScreen = screenInfo.screens[i]; + + pBuffer = MIDCBUFFER(pDev, pScreen); + + if (pBuffer) + { + if (pBuffer->pSourceGC) FreeGC(pBuffer->pSourceGC, (GContext) 0); + if (pBuffer->pMaskGC) FreeGC(pBuffer->pMaskGC, (GContext) 0); + if (pBuffer->pSaveGC) FreeGC(pBuffer->pSaveGC, (GContext) 0); + if (pBuffer->pRestoreGC) FreeGC(pBuffer->pRestoreGC, (GContext) 0); + if (pBuffer->pMoveGC) FreeGC(pBuffer->pMoveGC, (GContext) 0); + if (pBuffer->pPixSourceGC) FreeGC(pBuffer->pPixSourceGC, (GContext) 0); + if (pBuffer->pPixMaskGC) FreeGC(pBuffer->pPixMaskGC, (GContext) 0); + + if (pBuffer->pSave) (*pScreen->DestroyPixmap)(pBuffer->pSave); + if (pBuffer->pTemp) (*pScreen->DestroyPixmap)(pBuffer->pTemp); + + free(pBuffer); + dixSetPrivate(&pDev->devPrivates, miDCSpriteKey + pScreen->myNum, NULL); + } + } + } +} diff --git a/xorg-server/mi/mieq.c b/xorg-server/mi/mieq.c index b06ff0447..58db72968 100644 --- a/xorg-server/mi/mieq.c +++ b/xorg-server/mi/mieq.c @@ -191,7 +191,7 @@ mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e) if (evt->evlen < evlen) { evt->evlen = evlen; - evt->event = xrealloc(evt->event, evt->evlen); + evt->event = realloc(evt->event, evt->evlen); if (!evt->event) { ErrorF("[mi] Running out of memory. Tossing event.\n"); @@ -440,7 +440,7 @@ mieqProcessInputEvents(void) evlen = e->events->evlen; if(evlen > event_size) { - event = xrealloc(event, evlen); + event = realloc(event, evlen); event_size = evlen; } diff --git a/xorg-server/mi/miexpose.c b/xorg-server/mi/miexpose.c index f52b49211..f6f195daa 100644 --- a/xorg-server/mi/miexpose.c +++ b/xorg-server/mi/miexpose.c @@ -1,699 +1,700 @@ -/*********************************************************** - -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. - -******************************************************************/ -/***************************************************************** - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/Xprotostr.h> - -#include "misc.h" -#include "regionstr.h" -#include "scrnintstr.h" -#include "gcstruct.h" -#include "windowstr.h" -#include "pixmap.h" -#include "input.h" - -#include "dixstruct.h" -#include "mi.h" -#include <X11/Xmd.h> - -#include "globals.h" - -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif - -/* - machine-independent graphics exposure code. any device that uses -the region package can call this. -*/ - -#ifndef RECTLIMIT -#define RECTLIMIT 25 /* pick a number, any number > 8 */ -#endif - -/* miHandleExposures - generate a region for exposures for areas that were copied from obscured or -non-existent areas to non-obscured areas of the destination. Paint the -background for the region, if the destination is a window. - -NOTE: - this should generally be called, even if graphicsExposures is false, -because this is where bits get recovered from backing store. - -NOTE: - added argument 'plane' is used to indicate how exposures from backing -store should be accomplished. If plane is 0 (i.e. no bit plane), CopyArea -should be used, else a CopyPlane of the indicated plane will be used. The -exposing is done by the backing store's GraphicsExpose function, of course. - -*/ - -RegionPtr -miHandleExposures(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, - GCPtr pGC, int srcx, int srcy, int width, int height, - int dstx, int dsty, unsigned long plane) -{ - ScreenPtr pscr; - RegionPtr prgnSrcClip; /* drawable-relative source clip */ - RegionRec rgnSrcRec; - RegionPtr prgnDstClip; /* drawable-relative dest clip */ - RegionRec rgnDstRec; - BoxRec srcBox; /* unclipped source */ - RegionRec rgnExposed; /* exposed region, calculated source- - relative, made dst relative to - intersect with visible parts of - dest and send events to client, - and then screen relative to paint - the window background - */ - WindowPtr pSrcWin; - BoxRec expBox; - Bool extents; - - /* This prevents warning about pscr not being used. */ - pGC->pScreen = pscr = pGC->pScreen; - - /* avoid work if we can */ - if (!pGC->graphicsExposures && - (pDstDrawable->type == DRAWABLE_PIXMAP) && - ((pSrcDrawable->type == DRAWABLE_PIXMAP) || - (((WindowPtr)pSrcDrawable)->backStorage == NULL))) - return NULL; - - srcBox.x1 = srcx; - srcBox.y1 = srcy; - srcBox.x2 = srcx+width; - srcBox.y2 = srcy+height; - - if (pSrcDrawable->type != DRAWABLE_PIXMAP) - { - BoxRec TsrcBox; - - TsrcBox.x1 = srcx + pSrcDrawable->x; - TsrcBox.y1 = srcy + pSrcDrawable->y; - TsrcBox.x2 = TsrcBox.x1 + width; - TsrcBox.y2 = TsrcBox.y1 + height; - pSrcWin = (WindowPtr) pSrcDrawable; - if (pGC->subWindowMode == IncludeInferiors) - { - prgnSrcClip = NotClippedByChildren (pSrcWin); - if ((RECT_IN_REGION(pscr, prgnSrcClip, &TsrcBox)) == rgnIN) - { - REGION_DESTROY(pscr, prgnSrcClip); - return NULL; - } - } - else - { - if ((RECT_IN_REGION(pscr, &pSrcWin->clipList, &TsrcBox)) == rgnIN) - return NULL; - prgnSrcClip = &rgnSrcRec; - REGION_NULL(pscr, prgnSrcClip); - REGION_COPY(pscr, prgnSrcClip, &pSrcWin->clipList); - } - REGION_TRANSLATE(pscr, prgnSrcClip, - -pSrcDrawable->x, -pSrcDrawable->y); - } - else - { - BoxRec box; - - if ((srcBox.x1 >= 0) && (srcBox.y1 >= 0) && - (srcBox.x2 <= pSrcDrawable->width) && - (srcBox.y2 <= pSrcDrawable->height)) - return NULL; - - box.x1 = 0; - box.y1 = 0; - box.x2 = pSrcDrawable->width; - box.y2 = pSrcDrawable->height; - prgnSrcClip = &rgnSrcRec; - REGION_INIT(pscr, prgnSrcClip, &box, 1); - pSrcWin = NULL; - } - - if (pDstDrawable == pSrcDrawable) - { - prgnDstClip = prgnSrcClip; - } - else if (pDstDrawable->type != DRAWABLE_PIXMAP) - { - if (pGC->subWindowMode == IncludeInferiors) - { - prgnDstClip = NotClippedByChildren((WindowPtr)pDstDrawable); - } - else - { - prgnDstClip = &rgnDstRec; - REGION_NULL(pscr, prgnDstClip); - REGION_COPY(pscr, prgnDstClip, - &((WindowPtr)pDstDrawable)->clipList); - } - REGION_TRANSLATE(pscr, prgnDstClip, - -pDstDrawable->x, -pDstDrawable->y); - } - else - { - BoxRec box; - - box.x1 = 0; - box.y1 = 0; - box.x2 = pDstDrawable->width; - box.y2 = pDstDrawable->height; - prgnDstClip = &rgnDstRec; - REGION_INIT(pscr, prgnDstClip, &box, 1); - } - - /* drawable-relative source region */ - REGION_INIT(pscr, &rgnExposed, &srcBox, 1); - - /* now get the hidden parts of the source box*/ - REGION_SUBTRACT(pscr, &rgnExposed, &rgnExposed, prgnSrcClip); - - /* move them over the destination */ - REGION_TRANSLATE(pscr, &rgnExposed, dstx-srcx, dsty-srcy); - - /* intersect with visible areas of dest */ - REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, prgnDstClip); - - /* intersect with client clip region. */ - if (pGC->clientClipType == CT_REGION) - REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, pGC->clientClip); - - /* - * If we have LOTS of rectangles, we decide to take the extents - * and force an exposure on that. This should require much less - * work overall, on both client and server. This is cheating, but - * isn't prohibited by the protocol ("spontaneous combustion" :-) - * for windows. - */ - extents = pGC->graphicsExposures && - (REGION_NUM_RECTS(&rgnExposed) > RECTLIMIT) && - (pDstDrawable->type != DRAWABLE_PIXMAP); - if (pSrcWin) - { - RegionPtr region; - if (!(region = wClipShape (pSrcWin))) - region = wBoundingShape (pSrcWin); - /* - * If you try to CopyArea the extents of a shaped window, compacting the - * exposed region will undo all our work! - */ - if (extents && pSrcWin && region && - (RECT_IN_REGION(pscr, region, &srcBox) != rgnIN)) - extents = FALSE; - } - if (extents) - { - expBox = *REGION_EXTENTS(pscr, &rgnExposed); - REGION_RESET(pscr, &rgnExposed, &expBox); - } - if ((pDstDrawable->type != DRAWABLE_PIXMAP) && - (((WindowPtr)pDstDrawable)->backgroundState != None)) - { - WindowPtr pWin = (WindowPtr)pDstDrawable; - - /* make the exposed area screen-relative */ - REGION_TRANSLATE(pscr, &rgnExposed, - pDstDrawable->x, pDstDrawable->y); - - if (extents) - { - /* PaintWindowBackground doesn't clip, so we have to */ - REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, &pWin->clipList); - } - miPaintWindow((WindowPtr)pDstDrawable, &rgnExposed, PW_BACKGROUND); - - if (extents) - { - REGION_RESET(pscr, &rgnExposed, &expBox); - } - else - REGION_TRANSLATE(pscr, &rgnExposed, - -pDstDrawable->x, -pDstDrawable->y); - } - if (prgnDstClip == &rgnDstRec) - { - REGION_UNINIT(pscr, prgnDstClip); - } - else if (prgnDstClip != prgnSrcClip) - { - REGION_DESTROY(pscr, prgnDstClip); - } - - if (prgnSrcClip == &rgnSrcRec) - { - REGION_UNINIT(pscr, prgnSrcClip); - } - else - { - REGION_DESTROY(pscr, prgnSrcClip); - } - - if (pGC->graphicsExposures) - { - /* don't look */ - RegionPtr exposed = REGION_CREATE(pscr, NullBox, 0); - *exposed = rgnExposed; - return exposed; - } - else - { - REGION_UNINIT(pscr, &rgnExposed); - return NULL; - } -} - -/* send GraphicsExpose events, or a NoExpose event, based on the region */ - -void -miSendGraphicsExpose (ClientPtr client, RegionPtr pRgn, XID drawable, - int major, int minor) -{ - if (pRgn && !REGION_NIL(pRgn)) - { - xEvent *pEvent; - xEvent *pe; - BoxPtr pBox; - int i; - int numRects; - - numRects = REGION_NUM_RECTS(pRgn); - pBox = REGION_RECTS(pRgn); - if(!(pEvent = xalloc(numRects * sizeof(xEvent)))) - return; - pe = pEvent; - - for (i=1; i<=numRects; i++, pe++, pBox++) - { - pe->u.u.type = GraphicsExpose; - pe->u.graphicsExposure.drawable = drawable; - pe->u.graphicsExposure.x = pBox->x1; - pe->u.graphicsExposure.y = pBox->y1; - pe->u.graphicsExposure.width = pBox->x2 - pBox->x1; - pe->u.graphicsExposure.height = pBox->y2 - pBox->y1; - pe->u.graphicsExposure.count = numRects - i; - pe->u.graphicsExposure.majorEvent = major; - pe->u.graphicsExposure.minorEvent = minor; - } - TryClientEvents(client, NULL, pEvent, numRects, - (Mask)0, NoEventMask, NullGrab); - xfree(pEvent); - } - else - { - xEvent event; - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = NoExpose; - event.u.noExposure.drawable = drawable; - event.u.noExposure.majorEvent = major; - event.u.noExposure.minorEvent = minor; - TryClientEvents(client, NULL, &event, 1, - (Mask)0, NoEventMask, NullGrab); - } -} - - -void -miSendExposures( WindowPtr pWin, RegionPtr pRgn, int dx, int dy) -{ - BoxPtr pBox; - int numRects; - xEvent *pEvent, *pe; - int i; - - pBox = REGION_RECTS(pRgn); - numRects = REGION_NUM_RECTS(pRgn); - if(!(pEvent = xcalloc(1, numRects * sizeof(xEvent)))) - return; - - for (i=numRects, pe = pEvent; --i >= 0; pe++, pBox++) - { - pe->u.u.type = Expose; - pe->u.expose.window = pWin->drawable.id; - pe->u.expose.x = pBox->x1 - dx; - pe->u.expose.y = pBox->y1 - dy; - pe->u.expose.width = pBox->x2 - pBox->x1; - pe->u.expose.height = pBox->y2 - pBox->y1; - pe->u.expose.count = i; - } - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - int scrnum = pWin->drawable.pScreen->myNum; - int x = 0, y = 0; - XID realWin = 0; - - if(!pWin->parent) { - x = panoramiXdataPtr[scrnum].x; - y = panoramiXdataPtr[scrnum].y; - pWin = WindowTable[0]; - realWin = pWin->drawable.id; - } else if (scrnum) { - PanoramiXRes *win; - win = PanoramiXFindIDByScrnum(XRT_WINDOW, - pWin->drawable.id, scrnum); - if(!win) { - xfree(pEvent); - return; - } - realWin = win->info[0].id; - dixLookupWindow(&pWin, realWin, serverClient, DixSendAccess); - } - if(x || y || scrnum) - for (i = 0; i < numRects; i++) { - pEvent[i].u.expose.window = realWin; - pEvent[i].u.expose.x += x; - pEvent[i].u.expose.y += y; - } - } -#endif - - DeliverEvents(pWin, pEvent, numRects, NullWindow); - - xfree(pEvent); -} - -void -miWindowExposures( WindowPtr pWin, RegionPtr prgn, RegionPtr other_exposed) -{ - RegionPtr exposures = prgn; - if ((prgn && !REGION_NIL(prgn)) || - (exposures && !REGION_NIL(exposures)) || other_exposed) - { - RegionRec expRec; - int clientInterested; - - /* - * Restore from backing-store FIRST. - */ - clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & ExposureMask; - if (other_exposed) - { - if (exposures) - { - REGION_UNION(pWin->drawable.pScreen, other_exposed, - exposures, - other_exposed); - if (exposures != prgn) - REGION_DESTROY(pWin->drawable.pScreen, exposures); - } - exposures = other_exposed; - } - if (clientInterested && exposures && (REGION_NUM_RECTS(exposures) > RECTLIMIT)) - { - /* - * If we have LOTS of rectangles, we decide to take the extents - * and force an exposure on that. This should require much less - * work overall, on both client and server. This is cheating, but - * isn't prohibited by the protocol ("spontaneous combustion" :-). - */ - BoxRec box; - - box = *REGION_EXTENTS( pWin->drawable.pScreen, exposures); - if (exposures == prgn) { - exposures = &expRec; - REGION_INIT( pWin->drawable.pScreen, exposures, &box, 1); - REGION_RESET( pWin->drawable.pScreen, prgn, &box); - } else { - REGION_RESET( pWin->drawable.pScreen, exposures, &box); - REGION_UNION( pWin->drawable.pScreen, prgn, prgn, exposures); - } - /* PaintWindowBackground doesn't clip, so we have to */ - REGION_INTERSECT( pWin->drawable.pScreen, prgn, prgn, &pWin->clipList); - } - if (prgn && !REGION_NIL(prgn)) - miPaintWindow(pWin, prgn, PW_BACKGROUND); - if (clientInterested && exposures && !REGION_NIL(exposures)) - miSendExposures(pWin, exposures, - pWin->drawable.x, pWin->drawable.y); - if (exposures == &expRec) - { - REGION_UNINIT( pWin->drawable.pScreen, exposures); - } - else if (exposures && exposures != prgn && exposures != other_exposed) - REGION_DESTROY( pWin->drawable.pScreen, exposures); - if (prgn) - REGION_EMPTY( pWin->drawable.pScreen, prgn); - } - else if (exposures && exposures != prgn) - REGION_DESTROY( pWin->drawable.pScreen, exposures); -} - -#ifdef ROOTLESS -/* Ugly, ugly, but we lost our hooks into miPaintWindow... =/ */ -void RootlessSetPixmapOfAncestors(WindowPtr pWin); -void RootlessStartDrawing(WindowPtr pWin); -void RootlessDamageRegion(WindowPtr pWin, RegionPtr prgn); -Bool IsFramedWindow(WindowPtr pWin); -#endif - -void -miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - ChangeGCVal gcval[6]; - BITS32 gcmask; - GCPtr pGC; - int i; - BoxPtr pbox; - xRectangle *prect; - int numRects; - /* - * Distance from screen to destination drawable, use this - * to adjust rendering coordinates which come in in screen space - */ - int draw_x_off, draw_y_off; - /* - * Tile offset for drawing; these need to align the tile - * to the appropriate window origin - */ - int tile_x_off, tile_y_off; - PixUnion fill; - Bool solid = TRUE; - DrawablePtr drawable = &pWin->drawable; - -#ifdef ROOTLESS - if(!drawable || drawable->type == UNDRAWABLE_WINDOW) - return; - - if(IsFramedWindow(pWin)) { - RootlessStartDrawing(pWin); - RootlessDamageRegion(pWin, prgn); - - if(pWin->backgroundState == ParentRelative) { - if((what == PW_BACKGROUND) || - (what == PW_BORDER && !pWin->borderIsPixel)) - RootlessSetPixmapOfAncestors(pWin); - } - } -#endif - - if (what == PW_BACKGROUND) - { - while (pWin->backgroundState == ParentRelative) - pWin = pWin->parent; - - draw_x_off = drawable->x; - draw_y_off = drawable->y; - - tile_x_off = pWin->drawable.x - draw_x_off; - tile_y_off = pWin->drawable.y - draw_y_off; - fill = pWin->background; - switch (pWin->backgroundState) { - case None: - return; - case BackgroundPixmap: - solid = FALSE; - break; - } - } - else - { - PixmapPtr pixmap; - - tile_x_off = drawable->x; - tile_y_off = drawable->y; - - /* servers without pixmaps draw their own borders */ - if (!pScreen->GetWindowPixmap) - return; - pixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) drawable); - drawable = &pixmap->drawable; -#ifdef COMPOSITE - draw_x_off = pixmap->screen_x; - draw_y_off = pixmap->screen_y; - tile_x_off -= draw_x_off; - tile_y_off -= draw_y_off; -#else - draw_x_off = 0; - draw_y_off = 0; -#endif - fill = pWin->border; - solid = pWin->borderIsPixel; - } - - gcval[0].val = GXcopy; - gcmask = GCFunction; - -#ifdef ROOTLESS_SAFEALPHA -/* Bit mask for alpha channel with a particular number of bits per - * pixel. Note that we only care for 32bpp data. Mac OS X uses planar - * alpha for 16bpp. - */ -#define RootlessAlphaMask(bpp) ((bpp) == 32 ? 0xFF000000 : 0) -#endif - - if (solid) - { -#ifdef ROOTLESS_SAFEALPHA - gcval[1].val = fill.pixel | RootlessAlphaMask(pWin->drawable.bitsPerPixel); -#else - gcval[1].val = fill.pixel; -#endif - gcval[2].val = FillSolid; - gcmask |= GCForeground | GCFillStyle; - } - else - { - int c=1; -#ifdef ROOTLESS_SAFEALPHA - gcval[c++].val = ((CARD32)-1) & ~RootlessAlphaMask(pWin->drawable.bitsPerPixel); - gcmask |= GCPlaneMask; -#endif - gcval[c++].val = FillTiled; - gcval[c++].ptr = (pointer)fill.pixmap; - gcval[c++].val = tile_x_off; - gcval[c++].val = tile_y_off; - gcmask |= GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin; - } - - prect = xalloc(REGION_NUM_RECTS(prgn) * sizeof(xRectangle)); - if (!prect) - return; - - pGC = GetScratchGC(drawable->depth, drawable->pScreen); - if (!pGC) - { - xfree(prect); - return; - } - - dixChangeGC (NullClient, pGC, gcmask, NULL, gcval); - ValidateGC (drawable, pGC); - - numRects = REGION_NUM_RECTS(prgn); - pbox = REGION_RECTS(prgn); - for (i= numRects; --i >= 0; pbox++, prect++) - { - prect->x = pbox->x1 - draw_x_off; - prect->y = pbox->y1 - draw_y_off; - prect->width = pbox->x2 - pbox->x1; - prect->height = pbox->y2 - pbox->y1; - } - prect -= numRects; - (*pGC->ops->PolyFillRect)(drawable, pGC, numRects, prect); - xfree(prect); - - FreeScratchGC(pGC); -} - - -/* MICLEARDRAWABLE -- sets the entire drawable to the background color of - * the GC. Useful when we have a scratch drawable and need to initialize - * it. */ -void -miClearDrawable(DrawablePtr pDraw, GCPtr pGC) -{ - XID fg = pGC->fgPixel; - XID bg = pGC->bgPixel; - xRectangle rect; - - rect.x = 0; - rect.y = 0; - rect.width = pDraw->width; - rect.height = pDraw->height; - DoChangeGC(pGC, GCForeground, &bg, 0); - ValidateGC(pDraw, pGC); - (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); - DoChangeGC(pGC, GCForeground, &fg, 0); - ValidateGC(pDraw, pGC); -} +/*********************************************************** + +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. + +******************************************************************/ +/***************************************************************** + +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 <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/Xprotostr.h> + +#include "misc.h" +#include "regionstr.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmap.h" +#include "input.h" + +#include "dixstruct.h" +#include "mi.h" +#include <X11/Xmd.h> + +#include "globals.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +/* + machine-independent graphics exposure code. any device that uses +the region package can call this. +*/ + +#ifndef RECTLIMIT +#define RECTLIMIT 25 /* pick a number, any number > 8 */ +#endif + +/* miHandleExposures + generate a region for exposures for areas that were copied from obscured or +non-existent areas to non-obscured areas of the destination. Paint the +background for the region, if the destination is a window. + +NOTE: + this should generally be called, even if graphicsExposures is false, +because this is where bits get recovered from backing store. + +NOTE: + added argument 'plane' is used to indicate how exposures from backing +store should be accomplished. If plane is 0 (i.e. no bit plane), CopyArea +should be used, else a CopyPlane of the indicated plane will be used. The +exposing is done by the backing store's GraphicsExpose function, of course. + +*/ + +RegionPtr +miHandleExposures(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, int srcx, int srcy, int width, int height, + int dstx, int dsty, unsigned long plane) +{ + ScreenPtr pscr; + RegionPtr prgnSrcClip; /* drawable-relative source clip */ + RegionRec rgnSrcRec; + RegionPtr prgnDstClip; /* drawable-relative dest clip */ + RegionRec rgnDstRec; + BoxRec srcBox; /* unclipped source */ + RegionRec rgnExposed; /* exposed region, calculated source- + relative, made dst relative to + intersect with visible parts of + dest and send events to client, + and then screen relative to paint + the window background + */ + WindowPtr pSrcWin; + BoxRec expBox; + Bool extents; + + /* This prevents warning about pscr not being used. */ + pGC->pScreen = pscr = pGC->pScreen; + + /* avoid work if we can */ + if (!pGC->graphicsExposures && + (pDstDrawable->type == DRAWABLE_PIXMAP) && + ((pSrcDrawable->type == DRAWABLE_PIXMAP) || + (((WindowPtr)pSrcDrawable)->backStorage == NULL))) + return NULL; + + srcBox.x1 = srcx; + srcBox.y1 = srcy; + srcBox.x2 = srcx+width; + srcBox.y2 = srcy+height; + + if (pSrcDrawable->type != DRAWABLE_PIXMAP) + { + BoxRec TsrcBox; + + TsrcBox.x1 = srcx + pSrcDrawable->x; + TsrcBox.y1 = srcy + pSrcDrawable->y; + TsrcBox.x2 = TsrcBox.x1 + width; + TsrcBox.y2 = TsrcBox.y1 + height; + pSrcWin = (WindowPtr) pSrcDrawable; + if (pGC->subWindowMode == IncludeInferiors) + { + prgnSrcClip = NotClippedByChildren (pSrcWin); + if ((RECT_IN_REGION(pscr, prgnSrcClip, &TsrcBox)) == rgnIN) + { + REGION_DESTROY(pscr, prgnSrcClip); + return NULL; + } + } + else + { + if ((RECT_IN_REGION(pscr, &pSrcWin->clipList, &TsrcBox)) == rgnIN) + return NULL; + prgnSrcClip = &rgnSrcRec; + REGION_NULL(pscr, prgnSrcClip); + REGION_COPY(pscr, prgnSrcClip, &pSrcWin->clipList); + } + REGION_TRANSLATE(pscr, prgnSrcClip, + -pSrcDrawable->x, -pSrcDrawable->y); + } + else + { + BoxRec box; + + if ((srcBox.x1 >= 0) && (srcBox.y1 >= 0) && + (srcBox.x2 <= pSrcDrawable->width) && + (srcBox.y2 <= pSrcDrawable->height)) + return NULL; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pSrcDrawable->width; + box.y2 = pSrcDrawable->height; + prgnSrcClip = &rgnSrcRec; + REGION_INIT(pscr, prgnSrcClip, &box, 1); + pSrcWin = NULL; + } + + if (pDstDrawable == pSrcDrawable) + { + prgnDstClip = prgnSrcClip; + } + else if (pDstDrawable->type != DRAWABLE_PIXMAP) + { + if (pGC->subWindowMode == IncludeInferiors) + { + prgnDstClip = NotClippedByChildren((WindowPtr)pDstDrawable); + } + else + { + prgnDstClip = &rgnDstRec; + REGION_NULL(pscr, prgnDstClip); + REGION_COPY(pscr, prgnDstClip, + &((WindowPtr)pDstDrawable)->clipList); + } + REGION_TRANSLATE(pscr, prgnDstClip, + -pDstDrawable->x, -pDstDrawable->y); + } + else + { + BoxRec box; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pDstDrawable->width; + box.y2 = pDstDrawable->height; + prgnDstClip = &rgnDstRec; + REGION_INIT(pscr, prgnDstClip, &box, 1); + } + + /* drawable-relative source region */ + REGION_INIT(pscr, &rgnExposed, &srcBox, 1); + + /* now get the hidden parts of the source box*/ + REGION_SUBTRACT(pscr, &rgnExposed, &rgnExposed, prgnSrcClip); + + /* move them over the destination */ + REGION_TRANSLATE(pscr, &rgnExposed, dstx-srcx, dsty-srcy); + + /* intersect with visible areas of dest */ + REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, prgnDstClip); + + /* intersect with client clip region. */ + if (pGC->clientClipType == CT_REGION) + REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, pGC->clientClip); + + /* + * If we have LOTS of rectangles, we decide to take the extents + * and force an exposure on that. This should require much less + * work overall, on both client and server. This is cheating, but + * isn't prohibited by the protocol ("spontaneous combustion" :-) + * for windows. + */ + extents = pGC->graphicsExposures && + (REGION_NUM_RECTS(&rgnExposed) > RECTLIMIT) && + (pDstDrawable->type != DRAWABLE_PIXMAP); + if (pSrcWin) + { + RegionPtr region; + if (!(region = wClipShape (pSrcWin))) + region = wBoundingShape (pSrcWin); + /* + * If you try to CopyArea the extents of a shaped window, compacting the + * exposed region will undo all our work! + */ + if (extents && pSrcWin && region && + (RECT_IN_REGION(pscr, region, &srcBox) != rgnIN)) + extents = FALSE; + } + if (extents) + { + expBox = *REGION_EXTENTS(pscr, &rgnExposed); + REGION_RESET(pscr, &rgnExposed, &expBox); + } + if ((pDstDrawable->type != DRAWABLE_PIXMAP) && + (((WindowPtr)pDstDrawable)->backgroundState != None)) + { + WindowPtr pWin = (WindowPtr)pDstDrawable; + + /* make the exposed area screen-relative */ + REGION_TRANSLATE(pscr, &rgnExposed, + pDstDrawable->x, pDstDrawable->y); + + if (extents) + { + /* miPaintWindow doesn't clip, so we have to */ + REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, &pWin->clipList); + } + miPaintWindow((WindowPtr)pDstDrawable, &rgnExposed, PW_BACKGROUND); + + if (extents) + { + REGION_RESET(pscr, &rgnExposed, &expBox); + } + else + REGION_TRANSLATE(pscr, &rgnExposed, + -pDstDrawable->x, -pDstDrawable->y); + } + if (prgnDstClip == &rgnDstRec) + { + REGION_UNINIT(pscr, prgnDstClip); + } + else if (prgnDstClip != prgnSrcClip) + { + REGION_DESTROY(pscr, prgnDstClip); + } + + if (prgnSrcClip == &rgnSrcRec) + { + REGION_UNINIT(pscr, prgnSrcClip); + } + else + { + REGION_DESTROY(pscr, prgnSrcClip); + } + + if (pGC->graphicsExposures) + { + /* don't look */ + RegionPtr exposed = REGION_CREATE(pscr, NullBox, 0); + *exposed = rgnExposed; + return exposed; + } + else + { + REGION_UNINIT(pscr, &rgnExposed); + return NULL; + } +} + +/* send GraphicsExpose events, or a NoExpose event, based on the region */ + +void +miSendGraphicsExpose (ClientPtr client, RegionPtr pRgn, XID drawable, + int major, int minor) +{ + if (pRgn && !REGION_NIL(pRgn)) + { + xEvent *pEvent; + xEvent *pe; + BoxPtr pBox; + int i; + int numRects; + + numRects = REGION_NUM_RECTS(pRgn); + pBox = REGION_RECTS(pRgn); + if(!(pEvent = malloc(numRects * sizeof(xEvent)))) + return; + pe = pEvent; + + for (i=1; i<=numRects; i++, pe++, pBox++) + { + pe->u.u.type = GraphicsExpose; + pe->u.graphicsExposure.drawable = drawable; + pe->u.graphicsExposure.x = pBox->x1; + pe->u.graphicsExposure.y = pBox->y1; + pe->u.graphicsExposure.width = pBox->x2 - pBox->x1; + pe->u.graphicsExposure.height = pBox->y2 - pBox->y1; + pe->u.graphicsExposure.count = numRects - i; + pe->u.graphicsExposure.majorEvent = major; + pe->u.graphicsExposure.minorEvent = minor; + } + TryClientEvents(client, NULL, pEvent, numRects, + (Mask)0, NoEventMask, NullGrab); + free(pEvent); + } + else + { + xEvent event; + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = NoExpose; + event.u.noExposure.drawable = drawable; + event.u.noExposure.majorEvent = major; + event.u.noExposure.minorEvent = minor; + TryClientEvents(client, NULL, &event, 1, + (Mask)0, NoEventMask, NullGrab); + } +} + + +void +miSendExposures( WindowPtr pWin, RegionPtr pRgn, int dx, int dy) +{ + BoxPtr pBox; + int numRects; + xEvent *pEvent, *pe; + int i; + + pBox = REGION_RECTS(pRgn); + numRects = REGION_NUM_RECTS(pRgn); + if(!(pEvent = calloc(1, numRects * sizeof(xEvent)))) + return; + + for (i=numRects, pe = pEvent; --i >= 0; pe++, pBox++) + { + pe->u.u.type = Expose; + pe->u.expose.window = pWin->drawable.id; + pe->u.expose.x = pBox->x1 - dx; + pe->u.expose.y = pBox->y1 - dy; + pe->u.expose.width = pBox->x2 - pBox->x1; + pe->u.expose.height = pBox->y2 - pBox->y1; + pe->u.expose.count = i; + } + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + int scrnum = pWin->drawable.pScreen->myNum; + int x = 0, y = 0; + XID realWin = 0; + + if(!pWin->parent) { + x = panoramiXdataPtr[scrnum].x; + y = panoramiXdataPtr[scrnum].y; + pWin = WindowTable[0]; + realWin = pWin->drawable.id; + } else if (scrnum) { + PanoramiXRes *win; + win = PanoramiXFindIDByScrnum(XRT_WINDOW, + pWin->drawable.id, scrnum); + if(!win) { + free(pEvent); + return; + } + realWin = win->info[0].id; + dixLookupWindow(&pWin, realWin, serverClient, DixSendAccess); + } + if(x || y || scrnum) + for (i = 0; i < numRects; i++) { + pEvent[i].u.expose.window = realWin; + pEvent[i].u.expose.x += x; + pEvent[i].u.expose.y += y; + } + } +#endif + + DeliverEvents(pWin, pEvent, numRects, NullWindow); + + free(pEvent); +} + +void +miWindowExposures( WindowPtr pWin, RegionPtr prgn, RegionPtr other_exposed) +{ + RegionPtr exposures = prgn; + if ((prgn && !REGION_NIL(prgn)) || + (exposures && !REGION_NIL(exposures)) || other_exposed) + { + RegionRec expRec; + int clientInterested; + + /* + * Restore from backing-store FIRST. + */ + clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & ExposureMask; + if (other_exposed) + { + if (exposures) + { + REGION_UNION(pWin->drawable.pScreen, other_exposed, + exposures, + other_exposed); + if (exposures != prgn) + REGION_DESTROY(pWin->drawable.pScreen, exposures); + } + exposures = other_exposed; + } + if (clientInterested && exposures && (REGION_NUM_RECTS(exposures) > RECTLIMIT)) + { + /* + * If we have LOTS of rectangles, we decide to take the extents + * and force an exposure on that. This should require much less + * work overall, on both client and server. This is cheating, but + * isn't prohibited by the protocol ("spontaneous combustion" :-). + */ + BoxRec box; + + box = *REGION_EXTENTS( pWin->drawable.pScreen, exposures); + if (exposures == prgn) { + exposures = &expRec; + REGION_INIT( pWin->drawable.pScreen, exposures, &box, 1); + REGION_RESET( pWin->drawable.pScreen, prgn, &box); + } else { + REGION_RESET( pWin->drawable.pScreen, exposures, &box); + REGION_UNION( pWin->drawable.pScreen, prgn, prgn, exposures); + } + /* miPaintWindow doesn't clip, so we have to */ + REGION_INTERSECT( pWin->drawable.pScreen, prgn, prgn, &pWin->clipList); + } + if (prgn && !REGION_NIL(prgn)) + miPaintWindow(pWin, prgn, PW_BACKGROUND); + if (clientInterested && exposures && !REGION_NIL(exposures)) + miSendExposures(pWin, exposures, + pWin->drawable.x, pWin->drawable.y); + if (exposures == &expRec) + { + REGION_UNINIT( pWin->drawable.pScreen, exposures); + } + else if (exposures && exposures != prgn && exposures != other_exposed) + REGION_DESTROY( pWin->drawable.pScreen, exposures); + if (prgn) + REGION_EMPTY( pWin->drawable.pScreen, prgn); + } + else if (exposures && exposures != prgn) + REGION_DESTROY( pWin->drawable.pScreen, exposures); +} + +#ifdef ROOTLESS +/* Ugly, ugly, but we lost our hooks into miPaintWindow... =/ */ +void RootlessSetPixmapOfAncestors(WindowPtr pWin); +void RootlessStartDrawing(WindowPtr pWin); +void RootlessDamageRegion(WindowPtr pWin, RegionPtr prgn); +Bool IsFramedWindow(WindowPtr pWin); +#endif + +void +miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ChangeGCVal gcval[6]; + BITS32 gcmask; + GCPtr pGC; + int i; + BoxPtr pbox; + xRectangle *prect; + int numRects; + /* + * Distance from screen to destination drawable, use this + * to adjust rendering coordinates which come in in screen space + */ + int draw_x_off, draw_y_off; + /* + * Tile offset for drawing; these need to align the tile + * to the appropriate window origin + */ + int tile_x_off, tile_y_off; + PixUnion fill; + Bool solid = TRUE; + DrawablePtr drawable = &pWin->drawable; + +#ifdef ROOTLESS + if(!drawable || drawable->type == UNDRAWABLE_WINDOW) + return; + + if(IsFramedWindow(pWin)) { + RootlessStartDrawing(pWin); + RootlessDamageRegion(pWin, prgn); + + if(pWin->backgroundState == ParentRelative) { + if((what == PW_BACKGROUND) || + (what == PW_BORDER && !pWin->borderIsPixel)) + RootlessSetPixmapOfAncestors(pWin); + } + } +#endif + + if (what == PW_BACKGROUND) + { + while (pWin->backgroundState == ParentRelative) + pWin = pWin->parent; + + draw_x_off = drawable->x; + draw_y_off = drawable->y; + + tile_x_off = pWin->drawable.x - draw_x_off; + tile_y_off = pWin->drawable.y - draw_y_off; + fill = pWin->background; + switch (pWin->backgroundState) { + case None: + return; + case BackgroundPixmap: + solid = FALSE; + break; + } + } + else + { + PixmapPtr pixmap; + + tile_x_off = drawable->x; + tile_y_off = drawable->y; + + /* servers without pixmaps draw their own borders */ + if (!pScreen->GetWindowPixmap) + return; + pixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) drawable); + drawable = &pixmap->drawable; +#ifdef COMPOSITE + draw_x_off = pixmap->screen_x; + draw_y_off = pixmap->screen_y; + tile_x_off -= draw_x_off; + tile_y_off -= draw_y_off; +#else + draw_x_off = 0; + draw_y_off = 0; +#endif + fill = pWin->border; + solid = pWin->borderIsPixel; + } + + gcval[0].val = GXcopy; + gcmask = GCFunction; + +#ifdef ROOTLESS_SAFEALPHA +/* Bit mask for alpha channel with a particular number of bits per + * pixel. Note that we only care for 32bpp data. Mac OS X uses planar + * alpha for 16bpp. + */ +#define RootlessAlphaMask(bpp) ((bpp) == 32 ? 0xFF000000 : 0) +#endif + + if (solid) + { +#ifdef ROOTLESS_SAFEALPHA + gcval[1].val = fill.pixel | RootlessAlphaMask(pWin->drawable.bitsPerPixel); +#else + gcval[1].val = fill.pixel; +#endif + gcval[2].val = FillSolid; + gcmask |= GCForeground | GCFillStyle; + } + else + { + int c=1; +#ifdef ROOTLESS_SAFEALPHA + gcval[c++].val = ((CARD32)-1) & ~RootlessAlphaMask(pWin->drawable.bitsPerPixel); + gcmask |= GCPlaneMask; +#endif + gcval[c++].val = FillTiled; + gcval[c++].ptr = (pointer)fill.pixmap; + gcval[c++].val = tile_x_off; + gcval[c++].val = tile_y_off; + gcmask |= GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin; + } + + prect = malloc(REGION_NUM_RECTS(prgn) * sizeof(xRectangle)); + if (!prect) + return; + + pGC = GetScratchGC(drawable->depth, drawable->pScreen); + if (!pGC) + { + free(prect); + return; + } + + ChangeGC (NullClient, pGC, gcmask, gcval); + ValidateGC (drawable, pGC); + + numRects = REGION_NUM_RECTS(prgn); + pbox = REGION_RECTS(prgn); + for (i= numRects; --i >= 0; pbox++, prect++) + { + prect->x = pbox->x1 - draw_x_off; + prect->y = pbox->y1 - draw_y_off; + prect->width = pbox->x2 - pbox->x1; + prect->height = pbox->y2 - pbox->y1; + } + prect -= numRects; + (*pGC->ops->PolyFillRect)(drawable, pGC, numRects, prect); + free(prect); + + FreeScratchGC(pGC); +} + + +/* MICLEARDRAWABLE -- sets the entire drawable to the background color of + * the GC. Useful when we have a scratch drawable and need to initialize + * it. */ +void +miClearDrawable(DrawablePtr pDraw, GCPtr pGC) +{ + ChangeGCVal fg, bg; + xRectangle rect; + + fg.val = pGC->fgPixel; + bg.val = pGC->bgPixel; + rect.x = 0; + rect.y = 0; + rect.width = pDraw->width; + rect.height = pDraw->height; + ChangeGC(NullClient, pGC, GCForeground, &bg); + ValidateGC(pDraw, pGC); + (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); + ChangeGC(NullClient, pGC, GCForeground, &fg); + ValidateGC(pDraw, pGC); +} diff --git a/xorg-server/mi/mifillarc.c b/xorg-server/mi/mifillarc.c index c22baf54c..dd0a7b91d 100644 --- a/xorg-server/mi/mifillarc.c +++ b/xorg-server/mi/mifillarc.c @@ -1,798 +1,798 @@ -/************************************************************ - -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. - -Author: Bob Scheifler, MIT X Consortium - -********************************************************/ - - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <math.h> -#include <X11/X.h> -#include <X11/Xprotostr.h> -#include "regionstr.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "mifpoly.h" -#include "mi.h" -#include "mifillarc.h" - -#define QUADRANT (90 * 64) -#define HALFCIRCLE (180 * 64) -#define QUADRANT3 (270 * 64) - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#define Dsin(d) sin((double)d*(M_PI/11520.0)) -#define Dcos(d) cos((double)d*(M_PI/11520.0)) - -void -miFillArcSetup(xArc *arc, miFillArcRec *info) -{ - info->y = arc->height >> 1; - info->dy = arc->height & 1; - info->yorg = arc->y + info->y; - info->dx = arc->width & 1; - info->xorg = arc->x + (arc->width >> 1) + info->dx; - info->dx = 1 - info->dx; - if (arc->width == arc->height) - { - /* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */ - /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */ - info->ym = 8; - info->xm = 8; - info->yk = info->y << 3; - if (!info->dx) - { - info->xk = 0; - info->e = -1; - } - else - { - info->y++; - info->yk += 4; - info->xk = -4; - info->e = - (info->y << 3); - } - } - else - { - /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */ - /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */ - info->ym = (arc->width * arc->width) << 3; - info->xm = (arc->height * arc->height) << 3; - info->yk = info->y * info->ym; - if (!info->dy) - info->yk -= info->ym >> 1; - if (!info->dx) - { - info->xk = 0; - info->e = - (info->xm >> 3); - } - else - { - info->y++; - info->yk += info->ym; - info->xk = -(info->xm >> 1); - info->e = info->xk - info->yk; - } - } -} - -static void -miFillArcDSetup(xArc *arc, miFillArcDRec *info) -{ - /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */ - /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */ - info->y = arc->height >> 1; - info->dy = arc->height & 1; - info->yorg = arc->y + info->y; - info->dx = arc->width & 1; - info->xorg = arc->x + (arc->width >> 1) + info->dx; - info->dx = 1 - info->dx; - info->ym = ((double)arc->width) * (arc->width * 8); - info->xm = ((double)arc->height) * (arc->height * 8); - info->yk = info->y * info->ym; - if (!info->dy) - info->yk -= info->ym / 2.0; - if (!info->dx) - { - info->xk = 0; - info->e = - (info->xm / 8.0); - } - else - { - info->y++; - info->yk += info->ym; - info->xk = -info->xm / 2.0; - info->e = info->xk - info->yk; - } -} - -static void -miGetArcEdge( - xArc *arc, - miSliceEdgePtr edge, - int k, - Bool top, - Bool left ) -{ - int xady, y; - - y = arc->height >> 1; - if (!(arc->width & 1)) - y++; - if (!top) - { - y = -y; - if (arc->height & 1) - y--; - } - xady = k + y * edge->dx; - if (xady <= 0) - edge->x = - ((-xady) / edge->dy + 1); - else - edge->x = (xady - 1) / edge->dy; - edge->e = xady - edge->x * edge->dy; - if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0))) - edge->e = edge->dy - edge->e + 1; - if (left) - edge->x++; - edge->x += arc->x + (arc->width >> 1); - if (edge->dx > 0) - { - edge->deltax = 1; - edge->stepx = edge->dx / edge->dy; - edge->dx = edge->dx % edge->dy; - } - else - { - edge->deltax = -1; - edge->stepx = - ((-edge->dx) / edge->dy); - edge->dx = (-edge->dx) % edge->dy; - } - if (!top) - { - edge->deltax = -edge->deltax; - edge->stepx = -edge->stepx; - } -} - -static void -miEllipseAngleToSlope (int angle, int width, int height, int *dxp, int *dyp, - double *d_dxp, double *d_dyp) -{ - int dx, dy; - double d_dx, d_dy, scale; - Bool negative_dx, negative_dy; - - switch (angle) { - case 0: - *dxp = -1; - *dyp = 0; - if (d_dxp) { - *d_dxp = width / 2.0; - *d_dyp = 0; - } - break; - case QUADRANT: - *dxp = 0; - *dyp = 1; - if (d_dxp) { - *d_dxp = 0; - *d_dyp = - height / 2.0; - } - break; - case HALFCIRCLE: - *dxp = 1; - *dyp = 0; - if (d_dxp) { - *d_dxp = - width / 2.0; - *d_dyp = 0; - } - break; - case QUADRANT3: - *dxp = 0; - *dyp = -1; - if (d_dxp) { - *d_dxp = 0; - *d_dyp = height / 2.0; - } - break; - default: - d_dx = Dcos(angle) * width; - d_dy = Dsin(angle) * height; - if (d_dxp) { - *d_dxp = d_dx / 2.0; - *d_dyp = - d_dy / 2.0; - } - negative_dx = FALSE; - if (d_dx < 0.0) - { - d_dx = -d_dx; - negative_dx = TRUE; - } - negative_dy = FALSE; - if (d_dy < 0.0) - { - d_dy = -d_dy; - negative_dy = TRUE; - } - scale = d_dx; - if (d_dy > d_dx) - scale = d_dy; - dx = floor ((d_dx * 32768) / scale + 0.5); - if (negative_dx) - dx = -dx; - *dxp = dx; - dy = floor ((d_dy * 32768) / scale + 0.5); - if (negative_dy) - dy = -dy; - *dyp = dy; - break; - } -} - -static void -miGetPieEdge( - xArc *arc, - int angle, - miSliceEdgePtr edge, - Bool top, - Bool left ) -{ - int k; - int dx, dy; - - miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0); - - if (dy == 0) - { - edge->x = left ? -65536 : 65536; - edge->stepx = 0; - edge->e = 0; - edge->dx = -1; - return; - } - if (dx == 0) - { - edge->x = arc->x + (arc->width >> 1); - if (left && (arc->width & 1)) - edge->x++; - else if (!left && !(arc->width & 1)) - edge->x--; - edge->stepx = 0; - edge->e = 0; - edge->dx = -1; - return; - } - if (dy < 0) { - dx = -dx; - dy = -dy; - } - k = (arc->height & 1) ? dx : 0; - if (arc->width & 1) - k += dy; - edge->dx = dx << 1; - edge->dy = dy << 1; - miGetArcEdge(arc, edge, k, top, left); -} - -void -miFillArcSliceSetup(xArc *arc, miArcSliceRec *slice, GCPtr pGC) -{ - int angle1, angle2; - - angle1 = arc->angle1; - if (arc->angle2 < 0) - { - angle2 = angle1; - angle1 += arc->angle2; - } - else - angle2 = angle1 + arc->angle2; - while (angle1 < 0) - angle1 += FULLCIRCLE; - while (angle1 >= FULLCIRCLE) - angle1 -= FULLCIRCLE; - while (angle2 < 0) - angle2 += FULLCIRCLE; - while (angle2 >= FULLCIRCLE) - angle2 -= FULLCIRCLE; - slice->min_top_y = 0; - slice->max_top_y = arc->height >> 1; - slice->min_bot_y = 1 - (arc->height & 1); - slice->max_bot_y = slice->max_top_y - 1; - slice->flip_top = FALSE; - slice->flip_bot = FALSE; - if (pGC->arcMode == ArcPieSlice) - { - slice->edge1_top = (angle1 < HALFCIRCLE); - slice->edge2_top = (angle2 <= HALFCIRCLE); - if ((angle2 == 0) || (angle1 == HALFCIRCLE)) - { - if (angle2 ? slice->edge2_top : slice->edge1_top) - slice->min_top_y = slice->min_bot_y; - else - slice->min_top_y = arc->height; - slice->min_bot_y = 0; - } - else if ((angle1 == 0) || (angle2 == HALFCIRCLE)) - { - slice->min_top_y = slice->min_bot_y; - if (angle1 ? slice->edge1_top : slice->edge2_top) - slice->min_bot_y = arc->height; - else - slice->min_bot_y = 0; - } - else if (slice->edge1_top == slice->edge2_top) - { - if (angle2 < angle1) - { - slice->flip_top = slice->edge1_top; - slice->flip_bot = !slice->edge1_top; - } - else if (slice->edge1_top) - { - slice->min_top_y = 1; - slice->min_bot_y = arc->height; - } - else - { - slice->min_bot_y = 0; - slice->min_top_y = arc->height; - } - } - miGetPieEdge(arc, angle1, &slice->edge1, - slice->edge1_top, !slice->edge1_top); - miGetPieEdge(arc, angle2, &slice->edge2, - slice->edge2_top, slice->edge2_top); - } - else - { - double w2, h2, x1, y1, x2, y2, dx, dy, scale; - int signdx, signdy, y, k; - Bool isInt1 = TRUE, isInt2 = TRUE; - - w2 = (double)arc->width / 2.0; - h2 = (double)arc->height / 2.0; - if ((angle1 == 0) || (angle1 == HALFCIRCLE)) - { - x1 = angle1 ? -w2 : w2; - y1 = 0.0; - } - else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3)) - { - x1 = 0.0; - y1 = (angle1 == QUADRANT) ? h2 : -h2; - } - else - { - isInt1 = FALSE; - x1 = Dcos(angle1) * w2; - y1 = Dsin(angle1) * h2; - } - if ((angle2 == 0) || (angle2 == HALFCIRCLE)) - { - x2 = angle2 ? -w2 : w2; - y2 = 0.0; - } - else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3)) - { - x2 = 0.0; - y2 = (angle2 == QUADRANT) ? h2 : -h2; - } - else - { - isInt2 = FALSE; - x2 = Dcos(angle2) * w2; - y2 = Dsin(angle2) * h2; - } - dx = x2 - x1; - dy = y2 - y1; - if (arc->height & 1) - { - y1 -= 0.5; - y2 -= 0.5; - } - if (arc->width & 1) - { - x1 += 0.5; - x2 += 0.5; - } - if (dy < 0.0) - { - dy = -dy; - signdy = -1; - } - else - signdy = 1; - if (dx < 0.0) - { - dx = -dx; - signdx = -1; - } - else - signdx = 1; - if (isInt1 && isInt2) - { - slice->edge1.dx = dx * 2; - slice->edge1.dy = dy * 2; - } - else - { - scale = (dx > dy) ? dx : dy; - slice->edge1.dx = floor((dx * 32768) / scale + .5); - slice->edge1.dy = floor((dy * 32768) / scale + .5); - } - if (!slice->edge1.dy) - { - if (signdx < 0) - { - y = floor(y1 + 1.0); - if (y >= 0) - { - slice->min_top_y = y; - slice->min_bot_y = arc->height; - } - else - { - slice->max_bot_y = -y - (arc->height & 1); - } - } - else - { - y = floor(y1); - if (y >= 0) - slice->max_top_y = y; - else - { - slice->min_top_y = arc->height; - slice->min_bot_y = -y - (arc->height & 1); - } - } - slice->edge1_top = TRUE; - slice->edge1.x = 65536; - slice->edge1.stepx = 0; - slice->edge1.e = 0; - slice->edge1.dx = -1; - slice->edge2 = slice->edge1; - slice->edge2_top = FALSE; - } - else if (!slice->edge1.dx) - { - if (signdy < 0) - x1 -= 1.0; - slice->edge1.x = ceil(x1); - slice->edge1_top = signdy < 0; - slice->edge1.x += arc->x + (arc->width >> 1); - slice->edge1.stepx = 0; - slice->edge1.e = 0; - slice->edge1.dx = -1; - slice->edge2_top = !slice->edge1_top; - slice->edge2 = slice->edge1; - } - else - { - if (signdx < 0) - slice->edge1.dx = -slice->edge1.dx; - if (signdy < 0) - slice->edge1.dx = -slice->edge1.dx; - k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0); - slice->edge2.dx = slice->edge1.dx; - slice->edge2.dy = slice->edge1.dy; - slice->edge1_top = signdy < 0; - slice->edge2_top = !slice->edge1_top; - miGetArcEdge(arc, &slice->edge1, k, - slice->edge1_top, !slice->edge1_top); - miGetArcEdge(arc, &slice->edge2, k, - slice->edge2_top, slice->edge2_top); - } - } -} - -#define ADDSPANS() \ - pts->x = xorg - x; \ - pts->y = yorg - y; \ - *wids = slw; \ - pts++; \ - wids++; \ - if (miFillArcLower(slw)) \ - { \ - pts->x = xorg - x; \ - pts->y = yorg + y + dy; \ - pts++; \ - *wids++ = slw; \ - } - -static void -miFillEllipseI( - DrawablePtr pDraw, - GCPtr pGC, - xArc *arc ) -{ - int x, y, e; - int yk, xk, ym, xm, dx, dy, xorg, yorg; - int slw; - miFillArcRec info; - DDXPointPtr points; - DDXPointPtr pts; - int *widths; - int *wids; - - points = xalloc(sizeof(DDXPointRec) * arc->height); - if (!points) - return; - widths = xalloc(sizeof(int) * arc->height); - if (!widths) - { - xfree(points); - return; - } - miFillArcSetup(arc, &info); - MIFILLARCSETUP(); - if (pGC->miTranslate) - { - xorg += pDraw->x; - yorg += pDraw->y; - } - pts = points; - wids = widths; - while (y > 0) - { - MIFILLARCSTEP(slw); - ADDSPANS(); - } - (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); - xfree(widths); - xfree(points); -} - -static void -miFillEllipseD( - DrawablePtr pDraw, - GCPtr pGC, - xArc *arc ) -{ - int x, y; - int xorg, yorg, dx, dy, slw; - double e, yk, xk, ym, xm; - miFillArcDRec info; - DDXPointPtr points; - DDXPointPtr pts; - int *widths; - int *wids; - - points = xalloc(sizeof(DDXPointRec) * arc->height); - if (!points) - return; - widths = xalloc(sizeof(int) * arc->height); - if (!widths) - { - xfree(points); - return; - } - miFillArcDSetup(arc, &info); - MIFILLARCSETUP(); - if (pGC->miTranslate) - { - xorg += pDraw->x; - yorg += pDraw->y; - } - pts = points; - wids = widths; - while (y > 0) - { - MIFILLARCSTEP(slw); - ADDSPANS(); - } - (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); - xfree(widths); - xfree(points); -} - -#define ADDSPAN(l,r) \ - if (r >= l) \ - { \ - pts->x = l; \ - pts->y = ya; \ - pts++; \ - *wids++ = r - l + 1; \ - } - -#define ADDSLICESPANS(flip) \ - if (!flip) \ - { \ - ADDSPAN(xl, xr); \ - } \ - else \ - { \ - xc = xorg - x; \ - ADDSPAN(xc, xr); \ - xc += slw - 1; \ - ADDSPAN(xl, xc); \ - } - -static void -miFillArcSliceI( - DrawablePtr pDraw, - GCPtr pGC, - xArc *arc ) -{ - int yk, xk, ym, xm, dx, dy, xorg, yorg, slw; - int x, y, e; - miFillArcRec info; - miArcSliceRec slice; - int ya, xl, xr, xc; - DDXPointPtr points; - DDXPointPtr pts; - int *widths; - int *wids; - - miFillArcSetup(arc, &info); - miFillArcSliceSetup(arc, &slice, pGC); - MIFILLARCSETUP(); - slw = arc->height; - if (slice.flip_top || slice.flip_bot) - slw += (arc->height >> 1) + 1; - points = xalloc(sizeof(DDXPointRec) * slw); - if (!points) - return; - widths = xalloc(sizeof(int) * slw); - if (!widths) - { - xfree(points); - return; - } - if (pGC->miTranslate) - { - xorg += pDraw->x; - yorg += pDraw->y; - slice.edge1.x += pDraw->x; - slice.edge2.x += pDraw->x; - } - pts = points; - wids = widths; - while (y > 0) - { - MIFILLARCSTEP(slw); - MIARCSLICESTEP(slice.edge1); - MIARCSLICESTEP(slice.edge2); - if (miFillSliceUpper(slice)) - { - ya = yorg - y; - MIARCSLICEUPPER(xl, xr, slice, slw); - ADDSLICESPANS(slice.flip_top); - } - if (miFillSliceLower(slice)) - { - ya = yorg + y + dy; - MIARCSLICELOWER(xl, xr, slice, slw); - ADDSLICESPANS(slice.flip_bot); - } - } - (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); - xfree(widths); - xfree(points); -} - -static void -miFillArcSliceD( - DrawablePtr pDraw, - GCPtr pGC, - xArc *arc ) -{ - int x, y; - int dx, dy, xorg, yorg, slw; - double e, yk, xk, ym, xm; - miFillArcDRec info; - miArcSliceRec slice; - int ya, xl, xr, xc; - DDXPointPtr points; - DDXPointPtr pts; - int *widths; - int *wids; - - miFillArcDSetup(arc, &info); - miFillArcSliceSetup(arc, &slice, pGC); - MIFILLARCSETUP(); - slw = arc->height; - if (slice.flip_top || slice.flip_bot) - slw += (arc->height >> 1) + 1; - points = xalloc(sizeof(DDXPointRec) * slw); - if (!points) - return; - widths = xalloc(sizeof(int) * slw); - if (!widths) - { - xfree(points); - return; - } - if (pGC->miTranslate) - { - xorg += pDraw->x; - yorg += pDraw->y; - slice.edge1.x += pDraw->x; - slice.edge2.x += pDraw->x; - } - pts = points; - wids = widths; - while (y > 0) - { - MIFILLARCSTEP(slw); - MIARCSLICESTEP(slice.edge1); - MIARCSLICESTEP(slice.edge2); - if (miFillSliceUpper(slice)) - { - ya = yorg - y; - MIARCSLICEUPPER(xl, xr, slice, slw); - ADDSLICESPANS(slice.flip_top); - } - if (miFillSliceLower(slice)) - { - ya = yorg + y + dy; - MIARCSLICELOWER(xl, xr, slice, slw); - ADDSLICESPANS(slice.flip_bot); - } - } - (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); - xfree(widths); - xfree(points); -} - -/* MIPOLYFILLARC -- The public entry for the PolyFillArc request. - * Since we don't have to worry about overlapping segments, we can just - * fill each arc as it comes. - */ -void -miPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) -{ - int i; - xArc *arc; - - for(i = narcs, arc = parcs; --i >= 0; arc++) - { - if (miFillArcEmpty(arc)) - continue; - if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE)) - { - if (miCanFillArc(arc)) - miFillEllipseI(pDraw, pGC, arc); - else - miFillEllipseD(pDraw, pGC, arc); - } - else - { - if (miCanFillArc(arc)) - miFillArcSliceI(pDraw, pGC, arc); - else - miFillArcSliceD(pDraw, pGC, arc); - } - } -} +/************************************************************ + +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. + +Author: Bob Scheifler, MIT X Consortium + +********************************************************/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <math.h> +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "regionstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "mifpoly.h" +#include "mi.h" +#include "mifillarc.h" + +#define QUADRANT (90 * 64) +#define HALFCIRCLE (180 * 64) +#define QUADRANT3 (270 * 64) + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define Dsin(d) sin((double)d*(M_PI/11520.0)) +#define Dcos(d) cos((double)d*(M_PI/11520.0)) + +void +miFillArcSetup(xArc *arc, miFillArcRec *info) +{ + info->y = arc->height >> 1; + info->dy = arc->height & 1; + info->yorg = arc->y + info->y; + info->dx = arc->width & 1; + info->xorg = arc->x + (arc->width >> 1) + info->dx; + info->dx = 1 - info->dx; + if (arc->width == arc->height) + { + /* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */ + /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */ + info->ym = 8; + info->xm = 8; + info->yk = info->y << 3; + if (!info->dx) + { + info->xk = 0; + info->e = -1; + } + else + { + info->y++; + info->yk += 4; + info->xk = -4; + info->e = - (info->y << 3); + } + } + else + { + /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */ + /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */ + info->ym = (arc->width * arc->width) << 3; + info->xm = (arc->height * arc->height) << 3; + info->yk = info->y * info->ym; + if (!info->dy) + info->yk -= info->ym >> 1; + if (!info->dx) + { + info->xk = 0; + info->e = - (info->xm >> 3); + } + else + { + info->y++; + info->yk += info->ym; + info->xk = -(info->xm >> 1); + info->e = info->xk - info->yk; + } + } +} + +static void +miFillArcDSetup(xArc *arc, miFillArcDRec *info) +{ + /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */ + /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */ + info->y = arc->height >> 1; + info->dy = arc->height & 1; + info->yorg = arc->y + info->y; + info->dx = arc->width & 1; + info->xorg = arc->x + (arc->width >> 1) + info->dx; + info->dx = 1 - info->dx; + info->ym = ((double)arc->width) * (arc->width * 8); + info->xm = ((double)arc->height) * (arc->height * 8); + info->yk = info->y * info->ym; + if (!info->dy) + info->yk -= info->ym / 2.0; + if (!info->dx) + { + info->xk = 0; + info->e = - (info->xm / 8.0); + } + else + { + info->y++; + info->yk += info->ym; + info->xk = -info->xm / 2.0; + info->e = info->xk - info->yk; + } +} + +static void +miGetArcEdge( + xArc *arc, + miSliceEdgePtr edge, + int k, + Bool top, + Bool left ) +{ + int xady, y; + + y = arc->height >> 1; + if (!(arc->width & 1)) + y++; + if (!top) + { + y = -y; + if (arc->height & 1) + y--; + } + xady = k + y * edge->dx; + if (xady <= 0) + edge->x = - ((-xady) / edge->dy + 1); + else + edge->x = (xady - 1) / edge->dy; + edge->e = xady - edge->x * edge->dy; + if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0))) + edge->e = edge->dy - edge->e + 1; + if (left) + edge->x++; + edge->x += arc->x + (arc->width >> 1); + if (edge->dx > 0) + { + edge->deltax = 1; + edge->stepx = edge->dx / edge->dy; + edge->dx = edge->dx % edge->dy; + } + else + { + edge->deltax = -1; + edge->stepx = - ((-edge->dx) / edge->dy); + edge->dx = (-edge->dx) % edge->dy; + } + if (!top) + { + edge->deltax = -edge->deltax; + edge->stepx = -edge->stepx; + } +} + +static void +miEllipseAngleToSlope (int angle, int width, int height, int *dxp, int *dyp, + double *d_dxp, double *d_dyp) +{ + int dx, dy; + double d_dx, d_dy, scale; + Bool negative_dx, negative_dy; + + switch (angle) { + case 0: + *dxp = -1; + *dyp = 0; + if (d_dxp) { + *d_dxp = width / 2.0; + *d_dyp = 0; + } + break; + case QUADRANT: + *dxp = 0; + *dyp = 1; + if (d_dxp) { + *d_dxp = 0; + *d_dyp = - height / 2.0; + } + break; + case HALFCIRCLE: + *dxp = 1; + *dyp = 0; + if (d_dxp) { + *d_dxp = - width / 2.0; + *d_dyp = 0; + } + break; + case QUADRANT3: + *dxp = 0; + *dyp = -1; + if (d_dxp) { + *d_dxp = 0; + *d_dyp = height / 2.0; + } + break; + default: + d_dx = Dcos(angle) * width; + d_dy = Dsin(angle) * height; + if (d_dxp) { + *d_dxp = d_dx / 2.0; + *d_dyp = - d_dy / 2.0; + } + negative_dx = FALSE; + if (d_dx < 0.0) + { + d_dx = -d_dx; + negative_dx = TRUE; + } + negative_dy = FALSE; + if (d_dy < 0.0) + { + d_dy = -d_dy; + negative_dy = TRUE; + } + scale = d_dx; + if (d_dy > d_dx) + scale = d_dy; + dx = floor ((d_dx * 32768) / scale + 0.5); + if (negative_dx) + dx = -dx; + *dxp = dx; + dy = floor ((d_dy * 32768) / scale + 0.5); + if (negative_dy) + dy = -dy; + *dyp = dy; + break; + } +} + +static void +miGetPieEdge( + xArc *arc, + int angle, + miSliceEdgePtr edge, + Bool top, + Bool left ) +{ + int k; + int dx, dy; + + miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0); + + if (dy == 0) + { + edge->x = left ? -65536 : 65536; + edge->stepx = 0; + edge->e = 0; + edge->dx = -1; + return; + } + if (dx == 0) + { + edge->x = arc->x + (arc->width >> 1); + if (left && (arc->width & 1)) + edge->x++; + else if (!left && !(arc->width & 1)) + edge->x--; + edge->stepx = 0; + edge->e = 0; + edge->dx = -1; + return; + } + if (dy < 0) { + dx = -dx; + dy = -dy; + } + k = (arc->height & 1) ? dx : 0; + if (arc->width & 1) + k += dy; + edge->dx = dx << 1; + edge->dy = dy << 1; + miGetArcEdge(arc, edge, k, top, left); +} + +void +miFillArcSliceSetup(xArc *arc, miArcSliceRec *slice, GCPtr pGC) +{ + int angle1, angle2; + + angle1 = arc->angle1; + if (arc->angle2 < 0) + { + angle2 = angle1; + angle1 += arc->angle2; + } + else + angle2 = angle1 + arc->angle2; + while (angle1 < 0) + angle1 += FULLCIRCLE; + while (angle1 >= FULLCIRCLE) + angle1 -= FULLCIRCLE; + while (angle2 < 0) + angle2 += FULLCIRCLE; + while (angle2 >= FULLCIRCLE) + angle2 -= FULLCIRCLE; + slice->min_top_y = 0; + slice->max_top_y = arc->height >> 1; + slice->min_bot_y = 1 - (arc->height & 1); + slice->max_bot_y = slice->max_top_y - 1; + slice->flip_top = FALSE; + slice->flip_bot = FALSE; + if (pGC->arcMode == ArcPieSlice) + { + slice->edge1_top = (angle1 < HALFCIRCLE); + slice->edge2_top = (angle2 <= HALFCIRCLE); + if ((angle2 == 0) || (angle1 == HALFCIRCLE)) + { + if (angle2 ? slice->edge2_top : slice->edge1_top) + slice->min_top_y = slice->min_bot_y; + else + slice->min_top_y = arc->height; + slice->min_bot_y = 0; + } + else if ((angle1 == 0) || (angle2 == HALFCIRCLE)) + { + slice->min_top_y = slice->min_bot_y; + if (angle1 ? slice->edge1_top : slice->edge2_top) + slice->min_bot_y = arc->height; + else + slice->min_bot_y = 0; + } + else if (slice->edge1_top == slice->edge2_top) + { + if (angle2 < angle1) + { + slice->flip_top = slice->edge1_top; + slice->flip_bot = !slice->edge1_top; + } + else if (slice->edge1_top) + { + slice->min_top_y = 1; + slice->min_bot_y = arc->height; + } + else + { + slice->min_bot_y = 0; + slice->min_top_y = arc->height; + } + } + miGetPieEdge(arc, angle1, &slice->edge1, + slice->edge1_top, !slice->edge1_top); + miGetPieEdge(arc, angle2, &slice->edge2, + slice->edge2_top, slice->edge2_top); + } + else + { + double w2, h2, x1, y1, x2, y2, dx, dy, scale; + int signdx, signdy, y, k; + Bool isInt1 = TRUE, isInt2 = TRUE; + + w2 = (double)arc->width / 2.0; + h2 = (double)arc->height / 2.0; + if ((angle1 == 0) || (angle1 == HALFCIRCLE)) + { + x1 = angle1 ? -w2 : w2; + y1 = 0.0; + } + else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3)) + { + x1 = 0.0; + y1 = (angle1 == QUADRANT) ? h2 : -h2; + } + else + { + isInt1 = FALSE; + x1 = Dcos(angle1) * w2; + y1 = Dsin(angle1) * h2; + } + if ((angle2 == 0) || (angle2 == HALFCIRCLE)) + { + x2 = angle2 ? -w2 : w2; + y2 = 0.0; + } + else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3)) + { + x2 = 0.0; + y2 = (angle2 == QUADRANT) ? h2 : -h2; + } + else + { + isInt2 = FALSE; + x2 = Dcos(angle2) * w2; + y2 = Dsin(angle2) * h2; + } + dx = x2 - x1; + dy = y2 - y1; + if (arc->height & 1) + { + y1 -= 0.5; + y2 -= 0.5; + } + if (arc->width & 1) + { + x1 += 0.5; + x2 += 0.5; + } + if (dy < 0.0) + { + dy = -dy; + signdy = -1; + } + else + signdy = 1; + if (dx < 0.0) + { + dx = -dx; + signdx = -1; + } + else + signdx = 1; + if (isInt1 && isInt2) + { + slice->edge1.dx = dx * 2; + slice->edge1.dy = dy * 2; + } + else + { + scale = (dx > dy) ? dx : dy; + slice->edge1.dx = floor((dx * 32768) / scale + .5); + slice->edge1.dy = floor((dy * 32768) / scale + .5); + } + if (!slice->edge1.dy) + { + if (signdx < 0) + { + y = floor(y1 + 1.0); + if (y >= 0) + { + slice->min_top_y = y; + slice->min_bot_y = arc->height; + } + else + { + slice->max_bot_y = -y - (arc->height & 1); + } + } + else + { + y = floor(y1); + if (y >= 0) + slice->max_top_y = y; + else + { + slice->min_top_y = arc->height; + slice->min_bot_y = -y - (arc->height & 1); + } + } + slice->edge1_top = TRUE; + slice->edge1.x = 65536; + slice->edge1.stepx = 0; + slice->edge1.e = 0; + slice->edge1.dx = -1; + slice->edge2 = slice->edge1; + slice->edge2_top = FALSE; + } + else if (!slice->edge1.dx) + { + if (signdy < 0) + x1 -= 1.0; + slice->edge1.x = ceil(x1); + slice->edge1_top = signdy < 0; + slice->edge1.x += arc->x + (arc->width >> 1); + slice->edge1.stepx = 0; + slice->edge1.e = 0; + slice->edge1.dx = -1; + slice->edge2_top = !slice->edge1_top; + slice->edge2 = slice->edge1; + } + else + { + if (signdx < 0) + slice->edge1.dx = -slice->edge1.dx; + if (signdy < 0) + slice->edge1.dx = -slice->edge1.dx; + k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0); + slice->edge2.dx = slice->edge1.dx; + slice->edge2.dy = slice->edge1.dy; + slice->edge1_top = signdy < 0; + slice->edge2_top = !slice->edge1_top; + miGetArcEdge(arc, &slice->edge1, k, + slice->edge1_top, !slice->edge1_top); + miGetArcEdge(arc, &slice->edge2, k, + slice->edge2_top, slice->edge2_top); + } + } +} + +#define ADDSPANS() \ + pts->x = xorg - x; \ + pts->y = yorg - y; \ + *wids = slw; \ + pts++; \ + wids++; \ + if (miFillArcLower(slw)) \ + { \ + pts->x = xorg - x; \ + pts->y = yorg + y + dy; \ + pts++; \ + *wids++ = slw; \ + } + +static void +miFillEllipseI( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + int x, y, e; + int yk, xk, ym, xm, dx, dy, xorg, yorg; + int slw; + miFillArcRec info; + DDXPointPtr points; + DDXPointPtr pts; + int *widths; + int *wids; + + points = malloc(sizeof(DDXPointRec) * arc->height); + if (!points) + return; + widths = malloc(sizeof(int) * arc->height); + if (!widths) + { + free(points); + return; + } + miFillArcSetup(arc, &info); + MIFILLARCSETUP(); + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + } + pts = points; + wids = widths; + while (y > 0) + { + MIFILLARCSTEP(slw); + ADDSPANS(); + } + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + free(widths); + free(points); +} + +static void +miFillEllipseD( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + int x, y; + int xorg, yorg, dx, dy, slw; + double e, yk, xk, ym, xm; + miFillArcDRec info; + DDXPointPtr points; + DDXPointPtr pts; + int *widths; + int *wids; + + points = malloc(sizeof(DDXPointRec) * arc->height); + if (!points) + return; + widths = malloc(sizeof(int) * arc->height); + if (!widths) + { + free(points); + return; + } + miFillArcDSetup(arc, &info); + MIFILLARCSETUP(); + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + } + pts = points; + wids = widths; + while (y > 0) + { + MIFILLARCSTEP(slw); + ADDSPANS(); + } + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + free(widths); + free(points); +} + +#define ADDSPAN(l,r) \ + if (r >= l) \ + { \ + pts->x = l; \ + pts->y = ya; \ + pts++; \ + *wids++ = r - l + 1; \ + } + +#define ADDSLICESPANS(flip) \ + if (!flip) \ + { \ + ADDSPAN(xl, xr); \ + } \ + else \ + { \ + xc = xorg - x; \ + ADDSPAN(xc, xr); \ + xc += slw - 1; \ + ADDSPAN(xl, xc); \ + } + +static void +miFillArcSliceI( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + int yk, xk, ym, xm, dx, dy, xorg, yorg, slw; + int x, y, e; + miFillArcRec info; + miArcSliceRec slice; + int ya, xl, xr, xc; + DDXPointPtr points; + DDXPointPtr pts; + int *widths; + int *wids; + + miFillArcSetup(arc, &info); + miFillArcSliceSetup(arc, &slice, pGC); + MIFILLARCSETUP(); + slw = arc->height; + if (slice.flip_top || slice.flip_bot) + slw += (arc->height >> 1) + 1; + points = malloc(sizeof(DDXPointRec) * slw); + if (!points) + return; + widths = malloc(sizeof(int) * slw); + if (!widths) + { + free(points); + return; + } + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + slice.edge1.x += pDraw->x; + slice.edge2.x += pDraw->x; + } + pts = points; + wids = widths; + while (y > 0) + { + MIFILLARCSTEP(slw); + MIARCSLICESTEP(slice.edge1); + MIARCSLICESTEP(slice.edge2); + if (miFillSliceUpper(slice)) + { + ya = yorg - y; + MIARCSLICEUPPER(xl, xr, slice, slw); + ADDSLICESPANS(slice.flip_top); + } + if (miFillSliceLower(slice)) + { + ya = yorg + y + dy; + MIARCSLICELOWER(xl, xr, slice, slw); + ADDSLICESPANS(slice.flip_bot); + } + } + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + free(widths); + free(points); +} + +static void +miFillArcSliceD( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + int x, y; + int dx, dy, xorg, yorg, slw; + double e, yk, xk, ym, xm; + miFillArcDRec info; + miArcSliceRec slice; + int ya, xl, xr, xc; + DDXPointPtr points; + DDXPointPtr pts; + int *widths; + int *wids; + + miFillArcDSetup(arc, &info); + miFillArcSliceSetup(arc, &slice, pGC); + MIFILLARCSETUP(); + slw = arc->height; + if (slice.flip_top || slice.flip_bot) + slw += (arc->height >> 1) + 1; + points = malloc(sizeof(DDXPointRec) * slw); + if (!points) + return; + widths = malloc(sizeof(int) * slw); + if (!widths) + { + free(points); + return; + } + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + slice.edge1.x += pDraw->x; + slice.edge2.x += pDraw->x; + } + pts = points; + wids = widths; + while (y > 0) + { + MIFILLARCSTEP(slw); + MIARCSLICESTEP(slice.edge1); + MIARCSLICESTEP(slice.edge2); + if (miFillSliceUpper(slice)) + { + ya = yorg - y; + MIARCSLICEUPPER(xl, xr, slice, slw); + ADDSLICESPANS(slice.flip_top); + } + if (miFillSliceLower(slice)) + { + ya = yorg + y + dy; + MIARCSLICELOWER(xl, xr, slice, slw); + ADDSLICESPANS(slice.flip_bot); + } + } + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + free(widths); + free(points); +} + +/* MIPOLYFILLARC -- The public entry for the PolyFillArc request. + * Since we don't have to worry about overlapping segments, we can just + * fill each arc as it comes. + */ +void +miPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) +{ + int i; + xArc *arc; + + for(i = narcs, arc = parcs; --i >= 0; arc++) + { + if (miFillArcEmpty(arc)) + continue; + if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE)) + { + if (miCanFillArc(arc)) + miFillEllipseI(pDraw, pGC, arc); + else + miFillEllipseD(pDraw, pGC, arc); + } + else + { + if (miCanFillArc(arc)) + miFillArcSliceI(pDraw, pGC, arc); + else + miFillArcSliceD(pDraw, pGC, arc); + } + } +} diff --git a/xorg-server/mi/mifillrct.c b/xorg-server/mi/mifillrct.c index 6e9979099..a97e5ced3 100644 --- a/xorg-server/mi/mifillrct.c +++ b/xorg-server/mi/mifillrct.c @@ -1,143 +1,143 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xprotostr.h> -#include "gcstruct.h" -#include "windowstr.h" -#include "pixmap.h" -#include "mi.h" -#include "misc.h" - -/* mi rectangles - written by newman, with debts to all and sundry -*/ - -/* MIPOLYFILLRECT -- public entry for PolyFillRect request - * very straight forward: translate rectangles if necessary - * then call FillSpans to fill each rectangle. We let FillSpans worry about - * clipping to the destination - */ -void -miPolyFillRect( - DrawablePtr pDrawable, - GCPtr pGC, - int nrectFill, /* number of rectangles to fill */ - xRectangle *prectInit /* Pointer to first rectangle to fill */ - ) -{ - int i; - int height; - int width; - xRectangle *prect; - int xorg; - int yorg; - int maxheight; - DDXPointPtr pptFirst; - DDXPointPtr ppt; - int *pwFirst; - int *pw; - - if (pGC->miTranslate) - { - xorg = pDrawable->x; - yorg = pDrawable->y; - prect = prectInit; - maxheight = 0; - for (i = 0; i<nrectFill; i++, prect++) - { - prect->x += xorg; - prect->y += yorg; - maxheight = max(maxheight, prect->height); - } - } - else - { - prect = prectInit; - maxheight = 0; - for (i = 0; i<nrectFill; i++, prect++) - maxheight = max(maxheight, prect->height); - } - - pptFirst = xalloc(maxheight * sizeof(DDXPointRec)); - pwFirst = xalloc(maxheight * sizeof(int)); - if(!pptFirst || !pwFirst) - { - if (pwFirst) xfree(pwFirst); - if (pptFirst) xfree(pptFirst); - return; - } - - prect = prectInit; - while(nrectFill--) - { - ppt = pptFirst; - pw = pwFirst; - height = prect->height; - width = prect->width; - xorg = prect->x; - yorg = prect->y; - while(height--) - { - *pw++ = width; - ppt->x = xorg; - ppt->y = yorg; - ppt++; - yorg++; - } - (* pGC->ops->FillSpans)(pDrawable, pGC, - prect->height, pptFirst, pwFirst, - 1); - prect++; - } - xfree(pwFirst); - xfree(pptFirst); -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmap.h" +#include "mi.h" +#include "misc.h" + +/* mi rectangles + written by newman, with debts to all and sundry +*/ + +/* MIPOLYFILLRECT -- public entry for PolyFillRect request + * very straight forward: translate rectangles if necessary + * then call FillSpans to fill each rectangle. We let FillSpans worry about + * clipping to the destination + */ +void +miPolyFillRect( + DrawablePtr pDrawable, + GCPtr pGC, + int nrectFill, /* number of rectangles to fill */ + xRectangle *prectInit /* Pointer to first rectangle to fill */ + ) +{ + int i; + int height; + int width; + xRectangle *prect; + int xorg; + int yorg; + int maxheight; + DDXPointPtr pptFirst; + DDXPointPtr ppt; + int *pwFirst; + int *pw; + + if (pGC->miTranslate) + { + xorg = pDrawable->x; + yorg = pDrawable->y; + prect = prectInit; + maxheight = 0; + for (i = 0; i<nrectFill; i++, prect++) + { + prect->x += xorg; + prect->y += yorg; + maxheight = max(maxheight, prect->height); + } + } + else + { + prect = prectInit; + maxheight = 0; + for (i = 0; i<nrectFill; i++, prect++) + maxheight = max(maxheight, prect->height); + } + + pptFirst = malloc(maxheight * sizeof(DDXPointRec)); + pwFirst = malloc(maxheight * sizeof(int)); + if(!pptFirst || !pwFirst) + { + if (pwFirst) free(pwFirst); + if (pptFirst) free(pptFirst); + return; + } + + prect = prectInit; + while(nrectFill--) + { + ppt = pptFirst; + pw = pwFirst; + height = prect->height; + width = prect->width; + xorg = prect->x; + yorg = prect->y; + while(height--) + { + *pw++ = width; + ppt->x = xorg; + ppt->y = yorg; + ppt++; + yorg++; + } + (* pGC->ops->FillSpans)(pDrawable, pGC, + prect->height, pptFirst, pwFirst, + 1); + prect++; + } + free(pwFirst); + free(pptFirst); +} diff --git a/xorg-server/mi/mifpolycon.c b/xorg-server/mi/mifpolycon.c index 383502f64..8411a1570 100644 --- a/xorg-server/mi/mifpolycon.c +++ b/xorg-server/mi/mifpolycon.c @@ -1,280 +1,280 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <math.h> -#include <X11/X.h> -#include "gcstruct.h" -#include "windowstr.h" -#include "pixmapstr.h" -#include "mifpoly.h" - -static int GetFPolyYBounds(SppPointPtr pts, int n, double yFtrans, - int *by, int *ty); - -/* - * Written by Todd Newman; April. 1987. - * - * Fill a convex polygon. If the given polygon - * is not convex, then the result is undefined. - * The algorithm is to order the edges from smallest - * y to largest by partitioning the array into a left - * edge list and a right edge list. The algorithm used - * to traverse each edge is digital differencing analyzer - * line algorithm with y as the major axis. There's some funny linear - * interpolation involved because of the subpixel postioning. - */ -void -miFillSppPoly( - DrawablePtr dst, - GCPtr pgc, - int count, /* number of points */ - SppPointPtr ptsIn, /* the points */ - int xTrans, int yTrans, /* Translate each point by this */ - double xFtrans, - double yFtrans /* translate before conversion - by this amount. This provides - a mechanism to match rounding - errors with any shape that must - meet the polygon exactly. - */ - ) -{ - double xl = 0.0, xr = 0.0, /* x vals of left and right edges */ - ml = 0.0, /* left edge slope */ - mr = 0.0, /* right edge slope */ - dy, /* delta y */ - i; /* loop counter */ - int y, /* current scanline */ - j, - imin, /* index of vertex with smallest y */ - ymin, /* y-extents of polygon */ - ymax, - *width, - *FirstWidth, /* output buffer */ - *Marked; /* set if this vertex has been used */ - int left, right, /* indices to first endpoints */ - nextleft, - nextright; /* indices to second endpoints */ - DDXPointPtr ptsOut, - FirstPoint; /* output buffer */ - - if (pgc->miTranslate) - { - xTrans += dst->x; - yTrans += dst->y; - } - - imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax); - - y = ymax - ymin + 1; - if ((count < 3) || (y <= 0)) - return; - ptsOut = FirstPoint = xalloc(sizeof(DDXPointRec) * y); - width = FirstWidth = xalloc(sizeof(int) * y); - Marked = xalloc(sizeof(int) * count); - - if(!ptsOut || !width || !Marked) - { - if (Marked) xfree(Marked); - if (width) xfree(width); - if (ptsOut) xfree(ptsOut); - return; - } - - for(j = 0; j < count; j++) - Marked[j] = 0; - nextleft = nextright = imin; - Marked[imin] = -1; - y = ICEIL(ptsIn[nextleft].y + yFtrans); - - /* - * loop through all edges of the polygon - */ - do - { - /* add a left edge if we need to */ - if ((y > (ptsIn[nextleft].y + yFtrans) || - ISEQUAL(y, ptsIn[nextleft].y + yFtrans)) && - Marked[nextleft] != 1) - { - Marked[nextleft]++; - left = nextleft++; - - /* find the next edge, considering the end conditions */ - if (nextleft >= count) - nextleft = 0; - - /* now compute the starting point and slope */ - dy = ptsIn[nextleft].y - ptsIn[left].y; - if (dy != 0.0) - { - ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy; - dy = y - (ptsIn[left].y + yFtrans); - xl = (ptsIn[left].x + xFtrans) + ml * max(dy, 0); - } - } - - /* add a right edge if we need to */ - if ((y > ptsIn[nextright].y + yFtrans) || - (ISEQUAL(y, ptsIn[nextright].y + yFtrans) - && Marked[nextright] != 1)) - { - Marked[nextright]++; - right = nextright--; - - /* find the next edge, considering the end conditions */ - if (nextright < 0) - nextright = count - 1; - - /* now compute the starting point and slope */ - dy = ptsIn[nextright].y - ptsIn[right].y; - if (dy != 0.0) - { - mr = (ptsIn[nextright].x - ptsIn[right].x) / dy; - dy = y - (ptsIn[right].y + yFtrans); - xr = (ptsIn[right].x + xFtrans) + mr * max(dy, 0); - } - } - - - /* - * generate scans to fill while we still have - * a right edge as well as a left edge. - */ - i = (min(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y; - - if (i < EPSILON) - { - if(Marked[nextleft] && Marked[nextright]) - { - /* Arrgh, we're trapped! (no more points) - * Out, we've got to get out of here before this decadence saps - * our will completely! */ - break; - } - continue; - } - else - { - j = (int) i; - if(!j) - j++; - } - while (j > 0) - { - int cxl, cxr; - - ptsOut->y = (y) + yTrans; - - cxl = ICEIL(xl); - cxr = ICEIL(xr); - /* reverse the edges if necessary */ - if (xl < xr) - { - *(width++) = cxr - cxl; - (ptsOut++)->x = cxl + xTrans; - } - else - { - *(width++) = cxl - cxr; - (ptsOut++)->x = cxr + xTrans; - } - y++; - - /* increment down the edges */ - xl += ml; - xr += mr; - j--; - } - } while (y <= ymax); - - /* Finally, fill the spans we've collected */ - (*pgc->ops->FillSpans)(dst, pgc, - ptsOut-FirstPoint, FirstPoint, FirstWidth, 1); - xfree(Marked); - xfree(FirstWidth); - xfree(FirstPoint); -} - - -/* Find the index of the point with the smallest y.also return the - * smallest and largest y */ -static -int -GetFPolyYBounds( - SppPointPtr pts, - int n, - double yFtrans, - int *by, - int *ty) -{ - SppPointPtr ptMin; - double ymin, ymax; - SppPointPtr ptsStart = pts; - - ptMin = pts; - ymin = ymax = (pts++)->y; - - while (--n > 0) { - if (pts->y < ymin) - { - ptMin = pts; - ymin = pts->y; - } - if(pts->y > ymax) - ymax = pts->y; - - pts++; - } - - *by = ICEIL(ymin + yFtrans); - *ty = ICEIL(ymax + yFtrans - 1); - return(ptMin-ptsStart); -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <math.h> +#include <X11/X.h> +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "mifpoly.h" + +static int GetFPolyYBounds(SppPointPtr pts, int n, double yFtrans, + int *by, int *ty); + +/* + * Written by Todd Newman; April. 1987. + * + * Fill a convex polygon. If the given polygon + * is not convex, then the result is undefined. + * The algorithm is to order the edges from smallest + * y to largest by partitioning the array into a left + * edge list and a right edge list. The algorithm used + * to traverse each edge is digital differencing analyzer + * line algorithm with y as the major axis. There's some funny linear + * interpolation involved because of the subpixel postioning. + */ +void +miFillSppPoly( + DrawablePtr dst, + GCPtr pgc, + int count, /* number of points */ + SppPointPtr ptsIn, /* the points */ + int xTrans, int yTrans, /* Translate each point by this */ + double xFtrans, + double yFtrans /* translate before conversion + by this amount. This provides + a mechanism to match rounding + errors with any shape that must + meet the polygon exactly. + */ + ) +{ + double xl = 0.0, xr = 0.0, /* x vals of left and right edges */ + ml = 0.0, /* left edge slope */ + mr = 0.0, /* right edge slope */ + dy, /* delta y */ + i; /* loop counter */ + int y, /* current scanline */ + j, + imin, /* index of vertex with smallest y */ + ymin, /* y-extents of polygon */ + ymax, + *width, + *FirstWidth, /* output buffer */ + *Marked; /* set if this vertex has been used */ + int left, right, /* indices to first endpoints */ + nextleft, + nextright; /* indices to second endpoints */ + DDXPointPtr ptsOut, + FirstPoint; /* output buffer */ + + if (pgc->miTranslate) + { + xTrans += dst->x; + yTrans += dst->y; + } + + imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax); + + y = ymax - ymin + 1; + if ((count < 3) || (y <= 0)) + return; + ptsOut = FirstPoint = malloc(sizeof(DDXPointRec) * y); + width = FirstWidth = malloc(sizeof(int) * y); + Marked = malloc(sizeof(int) * count); + + if(!ptsOut || !width || !Marked) + { + if (Marked) free(Marked); + if (width) free(width); + if (ptsOut) free(ptsOut); + return; + } + + for(j = 0; j < count; j++) + Marked[j] = 0; + nextleft = nextright = imin; + Marked[imin] = -1; + y = ICEIL(ptsIn[nextleft].y + yFtrans); + + /* + * loop through all edges of the polygon + */ + do + { + /* add a left edge if we need to */ + if ((y > (ptsIn[nextleft].y + yFtrans) || + ISEQUAL(y, ptsIn[nextleft].y + yFtrans)) && + Marked[nextleft] != 1) + { + Marked[nextleft]++; + left = nextleft++; + + /* find the next edge, considering the end conditions */ + if (nextleft >= count) + nextleft = 0; + + /* now compute the starting point and slope */ + dy = ptsIn[nextleft].y - ptsIn[left].y; + if (dy != 0.0) + { + ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy; + dy = y - (ptsIn[left].y + yFtrans); + xl = (ptsIn[left].x + xFtrans) + ml * max(dy, 0); + } + } + + /* add a right edge if we need to */ + if ((y > ptsIn[nextright].y + yFtrans) || + (ISEQUAL(y, ptsIn[nextright].y + yFtrans) + && Marked[nextright] != 1)) + { + Marked[nextright]++; + right = nextright--; + + /* find the next edge, considering the end conditions */ + if (nextright < 0) + nextright = count - 1; + + /* now compute the starting point and slope */ + dy = ptsIn[nextright].y - ptsIn[right].y; + if (dy != 0.0) + { + mr = (ptsIn[nextright].x - ptsIn[right].x) / dy; + dy = y - (ptsIn[right].y + yFtrans); + xr = (ptsIn[right].x + xFtrans) + mr * max(dy, 0); + } + } + + + /* + * generate scans to fill while we still have + * a right edge as well as a left edge. + */ + i = (min(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y; + + if (i < EPSILON) + { + if(Marked[nextleft] && Marked[nextright]) + { + /* Arrgh, we're trapped! (no more points) + * Out, we've got to get out of here before this decadence saps + * our will completely! */ + break; + } + continue; + } + else + { + j = (int) i; + if(!j) + j++; + } + while (j > 0) + { + int cxl, cxr; + + ptsOut->y = (y) + yTrans; + + cxl = ICEIL(xl); + cxr = ICEIL(xr); + /* reverse the edges if necessary */ + if (xl < xr) + { + *(width++) = cxr - cxl; + (ptsOut++)->x = cxl + xTrans; + } + else + { + *(width++) = cxl - cxr; + (ptsOut++)->x = cxr + xTrans; + } + y++; + + /* increment down the edges */ + xl += ml; + xr += mr; + j--; + } + } while (y <= ymax); + + /* Finally, fill the spans we've collected */ + (*pgc->ops->FillSpans)(dst, pgc, + ptsOut-FirstPoint, FirstPoint, FirstWidth, 1); + free(Marked); + free(FirstWidth); + free(FirstPoint); +} + + +/* Find the index of the point with the smallest y.also return the + * smallest and largest y */ +static +int +GetFPolyYBounds( + SppPointPtr pts, + int n, + double yFtrans, + int *by, + int *ty) +{ + SppPointPtr ptMin; + double ymin, ymax; + SppPointPtr ptsStart = pts; + + ptMin = pts; + ymin = ymax = (pts++)->y; + + while (--n > 0) { + if (pts->y < ymin) + { + ptMin = pts; + ymin = pts->y; + } + if(pts->y > ymax) + ymax = pts->y; + + pts++; + } + + *by = ICEIL(ymin + yFtrans); + *ty = ICEIL(ymax + yFtrans - 1); + return(ptMin-ptsStart); +} diff --git a/xorg-server/mi/migc.c b/xorg-server/mi/migc.c index a797099cd..e42f29810 100644 --- a/xorg-server/mi/migc.c +++ b/xorg-server/mi/migc.c @@ -1,255 +1,255 @@ -/* - -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 <dix-config.h> -#endif - -#include "scrnintstr.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "migc.h" - -/* ARGSUSED */ -void -miChangeGC(GCPtr pGC, unsigned long mask) -{ - return; -} - -void -miDestroyGC(GCPtr pGC) -{ - if (pGC->pRotatedPixmap) - (*pGC->pScreen->DestroyPixmap) (pGC->pRotatedPixmap); - if (pGC->freeCompClip) - REGION_DESTROY(pGC->pScreen, pGC->pCompositeClip); -} - -void -miDestroyClip(GCPtr pGC) -{ - if (pGC->clientClipType == CT_NONE) - return; - else if (pGC->clientClipType == CT_PIXMAP) - { - (*pGC->pScreen->DestroyPixmap) ((PixmapPtr) (pGC->clientClip)); - } - else - { - /* - * we know we'll never have a list of rectangles, since ChangeClip - * immediately turns them into a region - */ - REGION_DESTROY(pGC->pScreen, pGC->clientClip); - } - pGC->clientClip = NULL; - pGC->clientClipType = CT_NONE; -} - -void -miChangeClip( GCPtr pGC, int type, pointer pvalue, int nrects) -{ - (*pGC->funcs->DestroyClip) (pGC); - if (type == CT_PIXMAP) - { - /* convert the pixmap to a region */ - pGC->clientClip = (pointer) BITMAP_TO_REGION(pGC->pScreen, - (PixmapPtr) pvalue); - (*pGC->pScreen->DestroyPixmap) (pvalue); - } - else if (type == CT_REGION) - { - /* stuff the region in the GC */ - pGC->clientClip = pvalue; - } - else if (type != CT_NONE) - { - pGC->clientClip = (pointer) RECTS_TO_REGION(pGC->pScreen, nrects, - (xRectangle *) pvalue, - type); - xfree(pvalue); - } - pGC->clientClipType = (type != CT_NONE && pGC->clientClip) ? CT_REGION : CT_NONE; - pGC->stateChanges |= GCClipMask; -} - -void -miCopyClip(GCPtr pgcDst, GCPtr pgcSrc) -{ - RegionPtr prgnNew; - - switch (pgcSrc->clientClipType) - { - case CT_PIXMAP: - ((PixmapPtr) pgcSrc->clientClip)->refcnt++; - /* Fall through !! */ - case CT_NONE: - (*pgcDst->funcs->ChangeClip) (pgcDst, (int) pgcSrc->clientClipType, - pgcSrc->clientClip, 0); - break; - case CT_REGION: - prgnNew = REGION_CREATE(pgcSrc->pScreen, NULL, 1); - REGION_COPY(pgcDst->pScreen, prgnNew, - (RegionPtr) (pgcSrc->clientClip)); - (*pgcDst->funcs->ChangeClip) (pgcDst, CT_REGION, (pointer) prgnNew, 0); - break; - } -} - -/* ARGSUSED */ -void -miCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) -{ - return; -} - -void -miComputeCompositeClip( GCPtr pGC, DrawablePtr pDrawable) -{ - ScreenPtr pScreen; - - /* This prevents warnings about pScreen not being used. */ - pGC->pScreen = pScreen = pGC->pScreen; - - if (pDrawable->type == DRAWABLE_WINDOW) - { - WindowPtr pWin = (WindowPtr) pDrawable; - RegionPtr pregWin; - Bool freeTmpClip, freeCompClip; - - if (pGC->subWindowMode == IncludeInferiors) - { - pregWin = NotClippedByChildren(pWin); - freeTmpClip = TRUE; - } - else - { - pregWin = &pWin->clipList; - freeTmpClip = FALSE; - } - freeCompClip = pGC->freeCompClip; - - /* - * if there is no client clip, we can get by with just keeping the - * pointer we got, and remembering whether or not should destroy (or - * maybe re-use) it later. this way, we avoid unnecessary copying of - * regions. (this wins especially if many clients clip by children - * and have no client clip.) - */ - if (pGC->clientClipType == CT_NONE) - { - if (freeCompClip) - REGION_DESTROY(pScreen, pGC->pCompositeClip); - pGC->pCompositeClip = pregWin; - pGC->freeCompClip = freeTmpClip; - } - else - { - /* - * we need one 'real' region to put into the composite clip. if - * pregWin the current composite clip are real, we can get rid of - * one. if pregWin is real and the current composite clip isn't, - * use pregWin for the composite clip. if the current composite - * clip is real and pregWin isn't, use the current composite - * clip. if neither is real, create a new region. - */ - - REGION_TRANSLATE(pScreen, pGC->clientClip, - pDrawable->x + pGC->clipOrg.x, - pDrawable->y + pGC->clipOrg.y); - - if (freeCompClip) - { - REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip, - pregWin, pGC->clientClip); - if (freeTmpClip) - REGION_DESTROY(pScreen, pregWin); - } - else if (freeTmpClip) - { - REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip); - pGC->pCompositeClip = pregWin; - } - else - { - pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); - REGION_INTERSECT(pScreen, pGC->pCompositeClip, - pregWin, pGC->clientClip); - } - pGC->freeCompClip = TRUE; - REGION_TRANSLATE(pScreen, pGC->clientClip, - -(pDrawable->x + pGC->clipOrg.x), - -(pDrawable->y + pGC->clipOrg.y)); - } - } /* end of composite clip for a window */ - else - { - BoxRec pixbounds; - - /* XXX should we translate by drawable.x/y here ? */ - /* If you want pixmaps in offscreen memory, yes */ - pixbounds.x1 = pDrawable->x; - pixbounds.y1 = pDrawable->y; - pixbounds.x2 = pDrawable->x + pDrawable->width; - pixbounds.y2 = pDrawable->y + pDrawable->height; - - if (pGC->freeCompClip) - { - REGION_RESET(pScreen, pGC->pCompositeClip, &pixbounds); - } - else - { - pGC->freeCompClip = TRUE; - pGC->pCompositeClip = REGION_CREATE(pScreen, &pixbounds, 1); - } - - if (pGC->clientClipType == CT_REGION) - { - if(pDrawable->x || pDrawable->y) { - REGION_TRANSLATE(pScreen, pGC->clientClip, - pDrawable->x + pGC->clipOrg.x, - pDrawable->y + pGC->clipOrg.y); - REGION_INTERSECT(pScreen, pGC->pCompositeClip, - pGC->pCompositeClip, pGC->clientClip); - REGION_TRANSLATE(pScreen, pGC->clientClip, - -(pDrawable->x + pGC->clipOrg.x), - -(pDrawable->y + pGC->clipOrg.y)); - } else { - REGION_TRANSLATE(pScreen, pGC->pCompositeClip, - -pGC->clipOrg.x, -pGC->clipOrg.y); - REGION_INTERSECT(pScreen, pGC->pCompositeClip, - pGC->pCompositeClip, pGC->clientClip); - REGION_TRANSLATE(pScreen, pGC->pCompositeClip, - pGC->clipOrg.x, pGC->clipOrg.y); - } - } - } /* end of composite clip for pixmap */ -} /* end miComputeCompositeClip */ +/* + +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 <dix-config.h> +#endif + +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "migc.h" + +/* ARGSUSED */ +void +miChangeGC(GCPtr pGC, unsigned long mask) +{ + return; +} + +void +miDestroyGC(GCPtr pGC) +{ + if (pGC->pRotatedPixmap) + (*pGC->pScreen->DestroyPixmap) (pGC->pRotatedPixmap); + if (pGC->freeCompClip) + REGION_DESTROY(pGC->pScreen, pGC->pCompositeClip); +} + +void +miDestroyClip(GCPtr pGC) +{ + if (pGC->clientClipType == CT_NONE) + return; + else if (pGC->clientClipType == CT_PIXMAP) + { + (*pGC->pScreen->DestroyPixmap) ((PixmapPtr) (pGC->clientClip)); + } + else + { + /* + * we know we'll never have a list of rectangles, since ChangeClip + * immediately turns them into a region + */ + REGION_DESTROY(pGC->pScreen, pGC->clientClip); + } + pGC->clientClip = NULL; + pGC->clientClipType = CT_NONE; +} + +void +miChangeClip( GCPtr pGC, int type, pointer pvalue, int nrects) +{ + (*pGC->funcs->DestroyClip) (pGC); + if (type == CT_PIXMAP) + { + /* convert the pixmap to a region */ + pGC->clientClip = (pointer) BITMAP_TO_REGION(pGC->pScreen, + (PixmapPtr) pvalue); + (*pGC->pScreen->DestroyPixmap) (pvalue); + } + else if (type == CT_REGION) + { + /* stuff the region in the GC */ + pGC->clientClip = pvalue; + } + else if (type != CT_NONE) + { + pGC->clientClip = (pointer) RECTS_TO_REGION(pGC->pScreen, nrects, + (xRectangle *) pvalue, + type); + free(pvalue); + } + pGC->clientClipType = (type != CT_NONE && pGC->clientClip) ? CT_REGION : CT_NONE; + pGC->stateChanges |= GCClipMask; +} + +void +miCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + RegionPtr prgnNew; + + switch (pgcSrc->clientClipType) + { + case CT_PIXMAP: + ((PixmapPtr) pgcSrc->clientClip)->refcnt++; + /* Fall through !! */ + case CT_NONE: + (*pgcDst->funcs->ChangeClip) (pgcDst, (int) pgcSrc->clientClipType, + pgcSrc->clientClip, 0); + break; + case CT_REGION: + prgnNew = REGION_CREATE(pgcSrc->pScreen, NULL, 1); + REGION_COPY(pgcDst->pScreen, prgnNew, + (RegionPtr) (pgcSrc->clientClip)); + (*pgcDst->funcs->ChangeClip) (pgcDst, CT_REGION, (pointer) prgnNew, 0); + break; + } +} + +/* ARGSUSED */ +void +miCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) +{ + return; +} + +void +miComputeCompositeClip( GCPtr pGC, DrawablePtr pDrawable) +{ + ScreenPtr pScreen; + + /* This prevents warnings about pScreen not being used. */ + pGC->pScreen = pScreen = pGC->pScreen; + + if (pDrawable->type == DRAWABLE_WINDOW) + { + WindowPtr pWin = (WindowPtr) pDrawable; + RegionPtr pregWin; + Bool freeTmpClip, freeCompClip; + + if (pGC->subWindowMode == IncludeInferiors) + { + pregWin = NotClippedByChildren(pWin); + freeTmpClip = TRUE; + } + else + { + pregWin = &pWin->clipList; + freeTmpClip = FALSE; + } + freeCompClip = pGC->freeCompClip; + + /* + * if there is no client clip, we can get by with just keeping the + * pointer we got, and remembering whether or not should destroy (or + * maybe re-use) it later. this way, we avoid unnecessary copying of + * regions. (this wins especially if many clients clip by children + * and have no client clip.) + */ + if (pGC->clientClipType == CT_NONE) + { + if (freeCompClip) + REGION_DESTROY(pScreen, pGC->pCompositeClip); + pGC->pCompositeClip = pregWin; + pGC->freeCompClip = freeTmpClip; + } + else + { + /* + * we need one 'real' region to put into the composite clip. if + * pregWin the current composite clip are real, we can get rid of + * one. if pregWin is real and the current composite clip isn't, + * use pregWin for the composite clip. if the current composite + * clip is real and pregWin isn't, use the current composite + * clip. if neither is real, create a new region. + */ + + REGION_TRANSLATE(pScreen, pGC->clientClip, + pDrawable->x + pGC->clipOrg.x, + pDrawable->y + pGC->clipOrg.y); + + if (freeCompClip) + { + REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + if (freeTmpClip) + REGION_DESTROY(pScreen, pregWin); + } + else if (freeTmpClip) + { + REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip); + pGC->pCompositeClip = pregWin; + } + else + { + pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); + REGION_INTERSECT(pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + } + pGC->freeCompClip = TRUE; + REGION_TRANSLATE(pScreen, pGC->clientClip, + -(pDrawable->x + pGC->clipOrg.x), + -(pDrawable->y + pGC->clipOrg.y)); + } + } /* end of composite clip for a window */ + else + { + BoxRec pixbounds; + + /* XXX should we translate by drawable.x/y here ? */ + /* If you want pixmaps in offscreen memory, yes */ + pixbounds.x1 = pDrawable->x; + pixbounds.y1 = pDrawable->y; + pixbounds.x2 = pDrawable->x + pDrawable->width; + pixbounds.y2 = pDrawable->y + pDrawable->height; + + if (pGC->freeCompClip) + { + REGION_RESET(pScreen, pGC->pCompositeClip, &pixbounds); + } + else + { + pGC->freeCompClip = TRUE; + pGC->pCompositeClip = REGION_CREATE(pScreen, &pixbounds, 1); + } + + if (pGC->clientClipType == CT_REGION) + { + if(pDrawable->x || pDrawable->y) { + REGION_TRANSLATE(pScreen, pGC->clientClip, + pDrawable->x + pGC->clipOrg.x, + pDrawable->y + pGC->clipOrg.y); + REGION_INTERSECT(pScreen, pGC->pCompositeClip, + pGC->pCompositeClip, pGC->clientClip); + REGION_TRANSLATE(pScreen, pGC->clientClip, + -(pDrawable->x + pGC->clipOrg.x), + -(pDrawable->y + pGC->clipOrg.y)); + } else { + REGION_TRANSLATE(pScreen, pGC->pCompositeClip, + -pGC->clipOrg.x, -pGC->clipOrg.y); + REGION_INTERSECT(pScreen, pGC->pCompositeClip, + pGC->pCompositeClip, pGC->clientClip); + REGION_TRANSLATE(pScreen, pGC->pCompositeClip, + pGC->clipOrg.x, pGC->clipOrg.y); + } + } + } /* end of composite clip for pixmap */ +} /* end miComputeCompositeClip */ diff --git a/xorg-server/mi/miglblt.c b/xorg-server/mi/miglblt.c index bc715aee9..c299fe554 100644 --- a/xorg-server/mi/miglblt.c +++ b/xorg-server/mi/miglblt.c @@ -1,258 +1,258 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xmd.h> -#include <X11/Xproto.h> -#include "misc.h" -#include <X11/fonts/fontstruct.h> -#include "dixfontstr.h" -#include "gcstruct.h" -#include "windowstr.h" -#include "scrnintstr.h" -#include "pixmap.h" -#include "servermd.h" -#include "mi.h" - -/* - machine-independent glyph blt. - assumes that glyph bits in snf are written in bytes, -have same bit order as the server's bitmap format, -and are byte padded. this corresponds to the snf distributed -with the sample server. - - get a scratch GC. - in the scratch GC set alu = GXcopy, fg = 1, bg = 0 - allocate a bitmap big enough to hold the largest glyph in the font - validate the scratch gc with the bitmap - for each glyph - carefully put the bits of the glyph in a buffer, - padded to the server pixmap scanline padding rules - fake a call to PutImage from the buffer into the bitmap - use the bitmap in a call to PushPixels -*/ - -void -miPolyGlyphBlt( - DrawablePtr pDrawable, - GC *pGC, - int x, - int y, - unsigned int nglyph, - CharInfoPtr *ppci, /* array of character info */ - pointer pglyphBase /* start of array of glyphs */ - ) -{ - int width, height; - PixmapPtr pPixmap; - int nbyLine; /* bytes per line of padded pixmap */ - FontPtr pfont; - GCPtr pGCtmp; - int i; - int j; - unsigned char *pbits; /* buffer for PutImage */ - unsigned char *pb; /* temp pointer into buffer */ - CharInfoPtr pci; /* currect char info */ - unsigned char *pglyph; /* pointer bits in glyph */ - int gWidth, gHeight; /* width and height of glyph */ - int nbyGlyphWidth; /* bytes per scanline of glyph */ - int nbyPadGlyph; /* server padded line of glyph */ - - XID gcvals[3]; - - if (pGC->miTranslate) - { - x += pDrawable->x; - y += pDrawable->y; - } - - pfont = pGC->font; - width = FONTMAXBOUNDS(pfont,rightSideBearing) - - FONTMINBOUNDS(pfont,leftSideBearing); - height = FONTMAXBOUNDS(pfont,ascent) + - FONTMAXBOUNDS(pfont,descent); - - pPixmap = (*pDrawable->pScreen->CreatePixmap)(pDrawable->pScreen, - width, height, 1, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pPixmap) - return; - - pGCtmp = GetScratchGC(1, pDrawable->pScreen); - if (!pGCtmp) - { - (*pDrawable->pScreen->DestroyPixmap)(pPixmap); - return; - } - - gcvals[0] = GXcopy; - gcvals[1] = 1; - gcvals[2] = 0; - - DoChangeGC(pGCtmp, GCFunction|GCForeground|GCBackground, gcvals, 0); - - nbyLine = BitmapBytePad(width); - pbits = xalloc(height*nbyLine); - if (!pbits) - { - (*pDrawable->pScreen->DestroyPixmap)(pPixmap); - FreeScratchGC(pGCtmp); - return; - } - while(nglyph--) - { - pci = *ppci++; - pglyph = FONTGLYPHBITS(pglyphBase, pci); - gWidth = GLYPHWIDTHPIXELS(pci); - gHeight = GLYPHHEIGHTPIXELS(pci); - if (gWidth && gHeight) - { - nbyGlyphWidth = GLYPHWIDTHBYTESPADDED(pci); - nbyPadGlyph = BitmapBytePad(gWidth); - - if (nbyGlyphWidth == nbyPadGlyph -#if GLYPHPADBYTES != 4 - && (((int) pglyph) & 3) == 0 -#endif - ) - { - pb = pglyph; - } - else - { - for (i=0, pb = pbits; i<gHeight; i++, pb = pbits+(i*nbyPadGlyph)) - for (j = 0; j < nbyGlyphWidth; j++) - *pb++ = *pglyph++; - pb = pbits; - } - - if ((pGCtmp->serialNumber) != (pPixmap->drawable.serialNumber)) - ValidateGC((DrawablePtr)pPixmap, pGCtmp); - (*pGCtmp->ops->PutImage)((DrawablePtr)pPixmap, pGCtmp, - pPixmap->drawable.depth, - 0, 0, gWidth, gHeight, - 0, XYBitmap, (char *)pb); - - if ((pGC->serialNumber) != (pDrawable->serialNumber)) - ValidateGC(pDrawable, pGC); - (*pGC->ops->PushPixels)(pGC, pPixmap, pDrawable, - gWidth, gHeight, - x + pci->metrics.leftSideBearing, - y - pci->metrics.ascent); - } - x += pci->metrics.characterWidth; - } - (*pDrawable->pScreen->DestroyPixmap)(pPixmap); - xfree(pbits); - FreeScratchGC(pGCtmp); -} - - -void -miImageGlyphBlt( - DrawablePtr pDrawable, - GC *pGC, - int x, - int y, - unsigned int nglyph, - CharInfoPtr *ppci, /* array of character info */ - pointer pglyphBase /* start of array of glyphs */ - ) -{ - ExtentInfoRec info; /* used by QueryGlyphExtents() */ - XID gcvals[3]; - int oldAlu, oldFS; - unsigned long oldFG; - xRectangle backrect; - - QueryGlyphExtents(pGC->font, ppci, (unsigned long)nglyph, &info); - - if (info.overallWidth >= 0) - { - backrect.x = x; - backrect.width = info.overallWidth; - } - else - { - backrect.x = x + info.overallWidth; - backrect.width = -info.overallWidth; - } - backrect.y = y - FONTASCENT(pGC->font); - backrect.height = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); - - oldAlu = pGC->alu; - oldFG = pGC->fgPixel; - oldFS = pGC->fillStyle; - - /* fill in the background */ - gcvals[0] = GXcopy; - gcvals[1] = pGC->bgPixel; - gcvals[2] = FillSolid; - DoChangeGC(pGC, GCFunction|GCForeground|GCFillStyle, gcvals, 0); - ValidateGC(pDrawable, pGC); - (*pGC->ops->PolyFillRect)(pDrawable, pGC, 1, &backrect); - - /* put down the glyphs */ - gcvals[0] = oldFG; - DoChangeGC(pGC, GCForeground, gcvals, 0); - ValidateGC(pDrawable, pGC); - (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph, ppci, - pglyphBase); - - /* put all the toys away when done playing */ - gcvals[0] = oldAlu; - gcvals[1] = oldFG; - gcvals[2] = oldFS; - DoChangeGC(pGC, GCFunction|GCForeground|GCFillStyle, gcvals, 0); - ValidateGC(pDrawable, pGC); - -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include <X11/Xproto.h> +#include "misc.h" +#include <X11/fonts/fontstruct.h> +#include "dixfontstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "pixmap.h" +#include "servermd.h" +#include "mi.h" + +/* + machine-independent glyph blt. + assumes that glyph bits in snf are written in bytes, +have same bit order as the server's bitmap format, +and are byte padded. this corresponds to the snf distributed +with the sample server. + + get a scratch GC. + in the scratch GC set alu = GXcopy, fg = 1, bg = 0 + allocate a bitmap big enough to hold the largest glyph in the font + validate the scratch gc with the bitmap + for each glyph + carefully put the bits of the glyph in a buffer, + padded to the server pixmap scanline padding rules + fake a call to PutImage from the buffer into the bitmap + use the bitmap in a call to PushPixels +*/ + +void +miPolyGlyphBlt( + DrawablePtr pDrawable, + GC *pGC, + int x, + int y, + unsigned int nglyph, + CharInfoPtr *ppci, /* array of character info */ + pointer pglyphBase /* start of array of glyphs */ + ) +{ + int width, height; + PixmapPtr pPixmap; + int nbyLine; /* bytes per line of padded pixmap */ + FontPtr pfont; + GCPtr pGCtmp; + int i; + int j; + unsigned char *pbits; /* buffer for PutImage */ + unsigned char *pb; /* temp pointer into buffer */ + CharInfoPtr pci; /* currect char info */ + unsigned char *pglyph; /* pointer bits in glyph */ + int gWidth, gHeight; /* width and height of glyph */ + int nbyGlyphWidth; /* bytes per scanline of glyph */ + int nbyPadGlyph; /* server padded line of glyph */ + + ChangeGCVal gcvals[3]; + + if (pGC->miTranslate) + { + x += pDrawable->x; + y += pDrawable->y; + } + + pfont = pGC->font; + width = FONTMAXBOUNDS(pfont,rightSideBearing) - + FONTMINBOUNDS(pfont,leftSideBearing); + height = FONTMAXBOUNDS(pfont,ascent) + + FONTMAXBOUNDS(pfont,descent); + + pPixmap = (*pDrawable->pScreen->CreatePixmap)(pDrawable->pScreen, + width, height, 1, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pPixmap) + return; + + pGCtmp = GetScratchGC(1, pDrawable->pScreen); + if (!pGCtmp) + { + (*pDrawable->pScreen->DestroyPixmap)(pPixmap); + return; + } + + gcvals[0].val = GXcopy; + gcvals[1].val = 1; + gcvals[2].val = 0; + + ChangeGC(NullClient, pGCtmp, GCFunction|GCForeground|GCBackground, gcvals); + + nbyLine = BitmapBytePad(width); + pbits = malloc(height*nbyLine); + if (!pbits) + { + (*pDrawable->pScreen->DestroyPixmap)(pPixmap); + FreeScratchGC(pGCtmp); + return; + } + while(nglyph--) + { + pci = *ppci++; + pglyph = FONTGLYPHBITS(pglyphBase, pci); + gWidth = GLYPHWIDTHPIXELS(pci); + gHeight = GLYPHHEIGHTPIXELS(pci); + if (gWidth && gHeight) + { + nbyGlyphWidth = GLYPHWIDTHBYTESPADDED(pci); + nbyPadGlyph = BitmapBytePad(gWidth); + + if (nbyGlyphWidth == nbyPadGlyph +#if GLYPHPADBYTES != 4 + && (((int) pglyph) & 3) == 0 +#endif + ) + { + pb = pglyph; + } + else + { + for (i=0, pb = pbits; i<gHeight; i++, pb = pbits+(i*nbyPadGlyph)) + for (j = 0; j < nbyGlyphWidth; j++) + *pb++ = *pglyph++; + pb = pbits; + } + + if ((pGCtmp->serialNumber) != (pPixmap->drawable.serialNumber)) + ValidateGC((DrawablePtr)pPixmap, pGCtmp); + (*pGCtmp->ops->PutImage)((DrawablePtr)pPixmap, pGCtmp, + pPixmap->drawable.depth, + 0, 0, gWidth, gHeight, + 0, XYBitmap, (char *)pb); + + if ((pGC->serialNumber) != (pDrawable->serialNumber)) + ValidateGC(pDrawable, pGC); + (*pGC->ops->PushPixels)(pGC, pPixmap, pDrawable, + gWidth, gHeight, + x + pci->metrics.leftSideBearing, + y - pci->metrics.ascent); + } + x += pci->metrics.characterWidth; + } + (*pDrawable->pScreen->DestroyPixmap)(pPixmap); + free(pbits); + FreeScratchGC(pGCtmp); +} + + +void +miImageGlyphBlt( + DrawablePtr pDrawable, + GC *pGC, + int x, + int y, + unsigned int nglyph, + CharInfoPtr *ppci, /* array of character info */ + pointer pglyphBase /* start of array of glyphs */ + ) +{ + ExtentInfoRec info; /* used by QueryGlyphExtents() */ + ChangeGCVal gcvals[3]; + int oldAlu, oldFS; + unsigned long oldFG; + xRectangle backrect; + + QueryGlyphExtents(pGC->font, ppci, (unsigned long)nglyph, &info); + + if (info.overallWidth >= 0) + { + backrect.x = x; + backrect.width = info.overallWidth; + } + else + { + backrect.x = x + info.overallWidth; + backrect.width = -info.overallWidth; + } + backrect.y = y - FONTASCENT(pGC->font); + backrect.height = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); + + oldAlu = pGC->alu; + oldFG = pGC->fgPixel; + oldFS = pGC->fillStyle; + + /* fill in the background */ + gcvals[0].val = GXcopy; + gcvals[1].val = pGC->bgPixel; + gcvals[2].val = FillSolid; + ChangeGC(NullClient, pGC, GCFunction|GCForeground|GCFillStyle, gcvals); + ValidateGC(pDrawable, pGC); + (*pGC->ops->PolyFillRect)(pDrawable, pGC, 1, &backrect); + + /* put down the glyphs */ + gcvals[0].val = oldFG; + ChangeGC(NullClient, pGC, GCForeground, gcvals); + ValidateGC(pDrawable, pGC); + (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + + /* put all the toys away when done playing */ + gcvals[0].val = oldAlu; + gcvals[1].val = oldFG; + gcvals[2].val = oldFS; + ChangeGC(NullClient, pGC, GCFunction|GCForeground|GCFillStyle, gcvals); + ValidateGC(pDrawable, pGC); + +} diff --git a/xorg-server/mi/mioverlay.c b/xorg-server/mi/mioverlay.c index e0aa88017..3de826b74 100644 --- a/xorg-server/mi/mioverlay.c +++ b/xorg-server/mi/mioverlay.c @@ -1,1948 +1,1948 @@ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <X11/X.h> -#include "scrnintstr.h" -#include "validate.h" -#include "windowstr.h" -#include "mi.h" -#include "gcstruct.h" -#include "regionstr.h" -#include "privates.h" -#include "mivalidate.h" -#include "mioverlay.h" -#include "migc.h" - -#include "globals.h" - - -typedef struct { - RegionRec exposed; - RegionRec borderExposed; - RegionPtr borderVisible; - DDXPointRec oldAbsCorner; -} miOverlayValDataRec, *miOverlayValDataPtr; - -typedef struct _TreeRec { - WindowPtr pWin; - struct _TreeRec *parent; - struct _TreeRec *firstChild; - struct _TreeRec *lastChild; - struct _TreeRec *prevSib; - struct _TreeRec *nextSib; - RegionRec borderClip; - RegionRec clipList; - unsigned visibility; - miOverlayValDataPtr valdata; -} miOverlayTreeRec, *miOverlayTreePtr; - -typedef struct { - miOverlayTreePtr tree; -} miOverlayWindowRec, *miOverlayWindowPtr; - -typedef struct { - CloseScreenProcPtr CloseScreen; - CreateWindowProcPtr CreateWindow; - DestroyWindowProcPtr DestroyWindow; - UnrealizeWindowProcPtr UnrealizeWindow; - RealizeWindowProcPtr RealizeWindow; - miOverlayTransFunc MakeTransparent; - miOverlayInOverlayFunc InOverlay; - Bool underlayMarked; - Bool copyUnderlay; -} miOverlayScreenRec, *miOverlayScreenPtr; - -static int miOverlayWindowKeyKeyIndex; -static DevPrivateKey miOverlayWindowKey = &miOverlayWindowKeyKeyIndex; -static int miOverlayScreenKeyIndex; -static DevPrivateKey miOverlayScreenKey = &miOverlayScreenKeyIndex; - -static void RebuildTree(WindowPtr); -static Bool HasUnderlayChildren(WindowPtr); -static void MarkUnderlayWindow(WindowPtr); -static Bool CollectUnderlayChildrenRegions(WindowPtr, RegionPtr); - -static Bool miOverlayCloseScreen(int, ScreenPtr); -static Bool miOverlayCreateWindow(WindowPtr); -static Bool miOverlayDestroyWindow(WindowPtr); -static Bool miOverlayUnrealizeWindow(WindowPtr); -static Bool miOverlayRealizeWindow(WindowPtr); -static void miOverlayMarkWindow(WindowPtr); -static void miOverlayReparentWindow(WindowPtr, WindowPtr); -static void miOverlayRestackWindow(WindowPtr, WindowPtr); -static Bool miOverlayMarkOverlappedWindows(WindowPtr, WindowPtr, WindowPtr*); -static void miOverlayMarkUnrealizedWindow(WindowPtr, WindowPtr, Bool); -static int miOverlayValidateTree(WindowPtr, WindowPtr, VTKind); -static void miOverlayHandleExposures(WindowPtr); -static void miOverlayMoveWindow(WindowPtr, int, int, WindowPtr, VTKind); -static void miOverlayWindowExposures(WindowPtr, RegionPtr, RegionPtr); -static void miOverlayResizeWindow(WindowPtr, int, int, unsigned int, - unsigned int, WindowPtr); -static void miOverlayClearToBackground(WindowPtr, int, int, int, int, Bool); - -static void miOverlaySetShape(WindowPtr); -static void miOverlayChangeBorderWidth(WindowPtr, unsigned int); - -#define MIOVERLAY_GET_SCREEN_PRIVATE(pScreen) ((miOverlayScreenPtr) \ - dixLookupPrivate(&(pScreen)->devPrivates, miOverlayScreenKey)) -#define MIOVERLAY_GET_WINDOW_PRIVATE(pWin) ((miOverlayWindowPtr) \ - dixLookupPrivate(&(pWin)->devPrivates, miOverlayWindowKey)) -#define MIOVERLAY_GET_WINDOW_TREE(pWin) \ - (MIOVERLAY_GET_WINDOW_PRIVATE(pWin)->tree) - -#define IN_UNDERLAY(w) MIOVERLAY_GET_WINDOW_TREE(w) -#define IN_OVERLAY(w) !MIOVERLAY_GET_WINDOW_TREE(w) - -#define MARK_OVERLAY(w) miMarkWindow(w) -#define MARK_UNDERLAY(w) MarkUnderlayWindow(w) - -#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ - HasBorder(w) && \ - (w)->backgroundState == ParentRelative) - -Bool -miInitOverlay( - ScreenPtr pScreen, - miOverlayInOverlayFunc inOverlayFunc, - miOverlayTransFunc transFunc -){ - miOverlayScreenPtr pScreenPriv; - - if(!inOverlayFunc || !transFunc) return FALSE; - - if(!dixRequestPrivate(miOverlayWindowKey, sizeof(miOverlayWindowRec))) - return FALSE; - - if(!(pScreenPriv = xalloc(sizeof(miOverlayScreenRec)))) - return FALSE; - - dixSetPrivate(&pScreen->devPrivates, miOverlayScreenKey, pScreenPriv); - - pScreenPriv->InOverlay = inOverlayFunc; - pScreenPriv->MakeTransparent = transFunc; - pScreenPriv->underlayMarked = FALSE; - - - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreenPriv->CreateWindow = pScreen->CreateWindow; - pScreenPriv->DestroyWindow = pScreen->DestroyWindow; - pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow; - pScreenPriv->RealizeWindow = pScreen->RealizeWindow; - - pScreen->CloseScreen = miOverlayCloseScreen; - pScreen->CreateWindow = miOverlayCreateWindow; - pScreen->DestroyWindow = miOverlayDestroyWindow; - pScreen->UnrealizeWindow = miOverlayUnrealizeWindow; - pScreen->RealizeWindow = miOverlayRealizeWindow; - - pScreen->ReparentWindow = miOverlayReparentWindow; - pScreen->RestackWindow = miOverlayRestackWindow; - pScreen->MarkOverlappedWindows = miOverlayMarkOverlappedWindows; - pScreen->MarkUnrealizedWindow = miOverlayMarkUnrealizedWindow; - pScreen->ValidateTree = miOverlayValidateTree; - pScreen->HandleExposures = miOverlayHandleExposures; - pScreen->MoveWindow = miOverlayMoveWindow; - pScreen->WindowExposures = miOverlayWindowExposures; - pScreen->ResizeWindow = miOverlayResizeWindow; - pScreen->MarkWindow = miOverlayMarkWindow; - pScreen->ClearToBackground = miOverlayClearToBackground; - pScreen->SetShape = miOverlaySetShape; - pScreen->ChangeBorderWidth = miOverlayChangeBorderWidth; - - return TRUE; -} - - -static Bool -miOverlayCloseScreen(int i, ScreenPtr pScreen) -{ - miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - - pScreen->CloseScreen = pScreenPriv->CloseScreen; - pScreen->CreateWindow = pScreenPriv->CreateWindow; - pScreen->DestroyWindow = pScreenPriv->DestroyWindow; - pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow; - pScreen->RealizeWindow = pScreenPriv->RealizeWindow; - - xfree(pScreenPriv); - - return (*pScreen->CloseScreen)(i, pScreen); -} - - -static Bool -miOverlayCreateWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - miOverlayWindowPtr pWinPriv = MIOVERLAY_GET_WINDOW_PRIVATE(pWin); - miOverlayTreePtr pTree = NULL; - Bool result = TRUE; - - pWinPriv->tree = NULL; - - if(!pWin->parent || !((*pScreenPriv->InOverlay)(pWin))) { - if(!(pTree = (miOverlayTreePtr)xcalloc(1, sizeof(miOverlayTreeRec)))) - return FALSE; - } - - if(pScreenPriv->CreateWindow) { - pScreen->CreateWindow = pScreenPriv->CreateWindow; - result = (*pScreen->CreateWindow)(pWin); - pScreen->CreateWindow = miOverlayCreateWindow; - } - - if (pTree) { - if(result) { - pTree->pWin = pWin; - pTree->visibility = VisibilityNotViewable; - pWinPriv->tree = pTree; - if(pWin->parent) { - REGION_NULL(pScreen, &(pTree->borderClip)); - REGION_NULL(pScreen, &(pTree->clipList)); - RebuildTree(pWin); - } else { - BoxRec fullBox; - fullBox.x1 = 0; - fullBox.y1 = 0; - fullBox.x2 = pScreen->width; - fullBox.y2 = pScreen->height; - REGION_INIT(pScreen, &(pTree->borderClip), &fullBox, 1); - REGION_INIT(pScreen, &(pTree->clipList), &fullBox, 1); - } - } else xfree(pTree); - } - - return TRUE; -} - - -static Bool -miOverlayDestroyWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - Bool result = TRUE; - - if (pTree) { - if(pTree->prevSib) - pTree->prevSib->nextSib = pTree->nextSib; - else if(pTree->parent) - pTree->parent->firstChild = pTree->nextSib; - - if(pTree->nextSib) - pTree->nextSib->prevSib = pTree->prevSib; - else if(pTree->parent) - pTree->parent->lastChild = pTree->prevSib; - - REGION_UNINIT(pScreen, &(pTree->borderClip)); - REGION_UNINIT(pScreen, &(pTree->clipList)); - xfree(pTree); - } - - if(pScreenPriv->DestroyWindow) { - pScreen->DestroyWindow = pScreenPriv->DestroyWindow; - result = (*pScreen->DestroyWindow)(pWin); - pScreen->DestroyWindow = miOverlayDestroyWindow; - } - - return result; -} - -static Bool -miOverlayUnrealizeWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - Bool result = TRUE; - - if(pTree) pTree->visibility = VisibilityNotViewable; - - if(pScreenPriv->UnrealizeWindow) { - pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow; - result = (*pScreen->UnrealizeWindow)(pWin); - pScreen->UnrealizeWindow = miOverlayUnrealizeWindow; - } - - return result; -} - - -static Bool -miOverlayRealizeWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - Bool result = TRUE; - - if(pScreenPriv->RealizeWindow) { - pScreen->RealizeWindow = pScreenPriv->RealizeWindow; - result = (*pScreen->RealizeWindow)(pWin); - pScreen->RealizeWindow = miOverlayRealizeWindow; - } - - /* we only need to catch the root window realization */ - - if(result && !pWin->parent && !((*pScreenPriv->InOverlay)(pWin))) - { - BoxRec box; - box.x1 = box.y1 = 0; - box.x2 = pWin->drawable.width; - box.y2 = pWin->drawable.height; - (*pScreenPriv->MakeTransparent)(pScreen, 1, &box); - } - - return result; -} - - -static void -miOverlayReparentWindow(WindowPtr pWin, WindowPtr pPriorParent) -{ - if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) { - /* This could probably be more optimal */ - RebuildTree(WindowTable[pWin->drawable.pScreen->myNum]->firstChild); - } -} - -static void -miOverlayRestackWindow(WindowPtr pWin, WindowPtr oldNextSib) -{ - if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) { - /* This could probably be more optimal */ - RebuildTree(pWin); - } -} - - -static Bool -miOverlayMarkOverlappedWindows( - WindowPtr pWin, - WindowPtr pFirst, - WindowPtr *pLayerWin -){ - ScreenPtr pScreen = pWin->drawable.pScreen; - WindowPtr pChild, pLast; - Bool overMarked, underMarked, doUnderlay, markAll; - miOverlayTreePtr pTree = NULL, tLast, tChild; - BoxPtr box; - - overMarked = underMarked = markAll = FALSE; - - if(pLayerWin) *pLayerWin = pWin; /* hah! */ - - doUnderlay = (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)); - - box = REGION_EXTENTS(pScreen, &pWin->borderSize); - - if((pChild = pFirst)) { - pLast = pChild->parent->lastChild; - while (1) { - if (pChild == pWin) markAll = TRUE; - - if(doUnderlay && IN_UNDERLAY(pChild)) - pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); - - if(pChild->viewable) { - if (REGION_BROKEN (pScreen, &pChild->winSize)) - SetWinSize (pChild); - if (REGION_BROKEN (pScreen, &pChild->borderSize)) - SetBorderSize (pChild); - - if (markAll || - RECT_IN_REGION(pScreen, &pChild->borderSize, box)) - { - MARK_OVERLAY(pChild); - overMarked = TRUE; - if(doUnderlay && IN_UNDERLAY(pChild)) { - MARK_UNDERLAY(pChild); - underMarked = TRUE; - } - if (pChild->firstChild) { - pChild = pChild->firstChild; - continue; - } - } - } - while (!pChild->nextSib && (pChild != pLast)) { - pChild = pChild->parent; - if(doUnderlay && IN_UNDERLAY(pChild)) - pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); - } - - if(pChild == pWin) markAll = FALSE; - - if (pChild == pLast) break; - - pChild = pChild->nextSib; - } - if(overMarked) - MARK_OVERLAY(pWin->parent); - } - - if(doUnderlay && !pTree) { - if(!(pTree = MIOVERLAY_GET_WINDOW_TREE(pWin))) { - pChild = pWin->lastChild; - while(1) { - if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) - break; - - if(pChild->lastChild) { - pChild = pChild->lastChild; - continue; - } - - while(!pChild->prevSib) pChild = pChild->parent; - - pChild = pChild->prevSib; - } - } - } - - if(pTree && pTree->nextSib) { - tChild = pTree->parent->lastChild; - tLast = pTree->nextSib; - - while(1) { - if(tChild->pWin->viewable) { - if (REGION_BROKEN (pScreen, &tChild->pWin->winSize)) - SetWinSize (tChild->pWin); - if (REGION_BROKEN (pScreen, &tChild->pWin->borderSize)) - SetBorderSize (tChild->pWin); - - if(RECT_IN_REGION(pScreen, &(tChild->pWin->borderSize), box)) - { - MARK_UNDERLAY(tChild->pWin); - underMarked = TRUE; - } - } - - if(tChild->lastChild) { - tChild = tChild->lastChild; - continue; - } - - while(!tChild->prevSib && (tChild != tLast)) - tChild = tChild->parent; - - if(tChild == tLast) break; - - tChild = tChild->prevSib; - } - } - - if(underMarked) { - MARK_UNDERLAY(pTree->parent->pWin); - MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->underlayMarked = TRUE; - } - - return (underMarked || overMarked); -} - - -static void -miOverlayComputeClips( - WindowPtr pParent, - RegionPtr universe, - VTKind kind, - RegionPtr exposed -){ - ScreenPtr pScreen = pParent->drawable.pScreen; - int oldVis, newVis, dx, dy; - BoxRec borderSize; - RegionPtr borderVisible; - RegionRec childUniverse, childUnion; - miOverlayTreePtr tParent = MIOVERLAY_GET_WINDOW_TREE(pParent); - miOverlayTreePtr tChild; - Bool overlap; - - borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); - borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); - dx = (int) pParent->drawable.x + (int) pParent->drawable.width + - wBorderWidth(pParent); - if (dx > 32767) dx = 32767; - borderSize.x2 = dx; - dy = (int) pParent->drawable.y + (int) pParent->drawable.height + - wBorderWidth(pParent); - if (dy > 32767) dy = 32767; - borderSize.y2 = dy; - - oldVis = tParent->visibility; - switch (RECT_IN_REGION( pScreen, universe, &borderSize)) { - case rgnIN: - newVis = VisibilityUnobscured; - break; - case rgnPART: - newVis = VisibilityPartiallyObscured; - { - RegionPtr pBounding; - - if ((pBounding = wBoundingShape (pParent))) { - switch (miShapedWindowIn (pScreen, universe, pBounding, - &borderSize, - pParent->drawable.x, - pParent->drawable.y)) - { - case rgnIN: - newVis = VisibilityUnobscured; - break; - case rgnOUT: - newVis = VisibilityFullyObscured; - break; - } - } - } - break; - default: - newVis = VisibilityFullyObscured; - break; - } - tParent->visibility = newVis; - - dx = pParent->drawable.x - tParent->valdata->oldAbsCorner.x; - dy = pParent->drawable.y - tParent->valdata->oldAbsCorner.y; - - switch (kind) { - case VTMap: - case VTStack: - case VTUnmap: - break; - case VTMove: - if ((oldVis == newVis) && - ((oldVis == VisibilityFullyObscured) || - (oldVis == VisibilityUnobscured))) - { - tChild = tParent; - while (1) { - if (tChild->pWin->viewable) { - if (tChild->visibility != VisibilityFullyObscured) { - REGION_TRANSLATE( pScreen, &tChild->borderClip, dx, dy); - REGION_TRANSLATE( pScreen, &tChild->clipList, dx, dy); - - tChild->pWin->drawable.serialNumber = - NEXT_SERIAL_NUMBER; - if (pScreen->ClipNotify) - (* pScreen->ClipNotify) (tChild->pWin, dx, dy); - } - if (tChild->valdata) { - REGION_NULL(pScreen, &tChild->valdata->borderExposed); - if (HasParentRelativeBorder(tChild->pWin)){ - REGION_SUBTRACT(pScreen, - &tChild->valdata->borderExposed, - &tChild->borderClip, - &tChild->pWin->winSize); - } - REGION_NULL(pScreen, &tChild->valdata->exposed); - } - if (tChild->firstChild) { - tChild = tChild->firstChild; - continue; - } - } - while (!tChild->nextSib && (tChild != tParent)) - tChild = tChild->parent; - if (tChild == tParent) - break; - tChild = tChild->nextSib; - } - return; - } - /* fall through */ - default: - if (dx || dy) { - REGION_TRANSLATE( pScreen, &tParent->borderClip, dx, dy); - REGION_TRANSLATE( pScreen, &tParent->clipList, dx, dy); - } - break; - case VTBroken: - REGION_EMPTY (pScreen, &tParent->borderClip); - REGION_EMPTY (pScreen, &tParent->clipList); - break; - } - - borderVisible = tParent->valdata->borderVisible; - REGION_NULL(pScreen, &tParent->valdata->borderExposed); - REGION_NULL(pScreen, &tParent->valdata->exposed); - - if (HasBorder (pParent)) { - if (borderVisible) { - REGION_SUBTRACT( pScreen, exposed, universe, borderVisible); - REGION_DESTROY( pScreen, borderVisible); - } else - REGION_SUBTRACT( pScreen, exposed, universe, &tParent->borderClip); - - if (HasParentRelativeBorder(pParent) && (dx || dy)) - REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed, - universe, &pParent->winSize); - else - REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed, - exposed, &pParent->winSize); - - REGION_COPY( pScreen, &tParent->borderClip, universe); - REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize); - } - else - REGION_COPY( pScreen, &tParent->borderClip, universe); - - if ((tChild = tParent->firstChild) && pParent->mapped) { - REGION_NULL(pScreen, &childUniverse); - REGION_NULL(pScreen, &childUnion); - - for (; tChild; tChild = tChild->nextSib) { - if (tChild->pWin->viewable) - REGION_APPEND( pScreen, &childUnion, &tChild->pWin->borderSize); - } - - REGION_VALIDATE( pScreen, &childUnion, &overlap); - - for (tChild = tParent->firstChild; - tChild; - tChild = tChild->nextSib) - { - if (tChild->pWin->viewable) { - if (tChild->valdata) { - REGION_INTERSECT( pScreen, &childUniverse, universe, - &tChild->pWin->borderSize); - miOverlayComputeClips (tChild->pWin, &childUniverse, - kind, exposed); - } - if (overlap) - REGION_SUBTRACT( pScreen, universe, universe, - &tChild->pWin->borderSize); - } - } - if (!overlap) - REGION_SUBTRACT( pScreen, universe, universe, &childUnion); - REGION_UNINIT( pScreen, &childUnion); - REGION_UNINIT( pScreen, &childUniverse); - } - - if (oldVis == VisibilityFullyObscured || - oldVis == VisibilityNotViewable) - { - REGION_COPY( pScreen, &tParent->valdata->exposed, universe); - } - else if (newVis != VisibilityFullyObscured && - newVis != VisibilityNotViewable) - { - REGION_SUBTRACT( pScreen, &tParent->valdata->exposed, - universe, &tParent->clipList); - } - - /* HACK ALERT - copying contents of regions, instead of regions */ - { - RegionRec tmp; - - tmp = tParent->clipList; - tParent->clipList = *universe; - *universe = tmp; - } - - pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; - - if (pScreen->ClipNotify) - (* pScreen->ClipNotify) (pParent, dx, dy); -} - - -static void -miOverlayMarkWindow(WindowPtr pWin) -{ - miOverlayTreePtr pTree = NULL; - WindowPtr pChild, pGrandChild; - - miMarkWindow(pWin); - - /* look for UnmapValdata among immediate children */ - - if(!(pChild = pWin->firstChild)) return; - - for( ; pChild; pChild = pChild->nextSib) { - if(pChild->valdata == UnmapValData) { - if(IN_UNDERLAY(pChild)) { - pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); - pTree->valdata = (miOverlayValDataPtr)UnmapValData; - continue; - } else { - if(!(pGrandChild = pChild->firstChild)) - continue; - - while(1) { - if(IN_UNDERLAY(pGrandChild)) { - pTree = MIOVERLAY_GET_WINDOW_TREE(pGrandChild); - pTree->valdata = (miOverlayValDataPtr)UnmapValData; - } else if(pGrandChild->firstChild) { - pGrandChild = pGrandChild->firstChild; - continue; - } - - while(!pGrandChild->nextSib && (pGrandChild != pChild)) - pGrandChild = pGrandChild->parent; - - if(pChild == pGrandChild) break; - - pGrandChild = pGrandChild->nextSib; - } - } - } - } - - if(pTree) { - MARK_UNDERLAY(pTree->parent->pWin); - MIOVERLAY_GET_SCREEN_PRIVATE( - pWin->drawable.pScreen)->underlayMarked = TRUE; - } -} - -static void -miOverlayMarkUnrealizedWindow( - WindowPtr pChild, - WindowPtr pWin, - Bool fromConfigure -){ - if ((pChild != pWin) || fromConfigure) { - miOverlayTreePtr pTree; - - REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList); - if (pChild->drawable.pScreen->ClipNotify) - (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0); - REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip); - if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) { - if(pTree->valdata != (miOverlayValDataPtr)UnmapValData) { - REGION_EMPTY(pChild->drawable.pScreen, &pTree->clipList); - REGION_EMPTY(pChild->drawable.pScreen, &pTree->borderClip); - } - } - } -} - - -static int -miOverlayValidateTree( - WindowPtr pParent, - WindowPtr pChild, /* first child effected */ - VTKind kind -){ - ScreenPtr pScreen = pParent->drawable.pScreen; - miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - RegionRec totalClip, childClip, exposed; - miOverlayTreePtr tParent, tChild, tWin; - Bool overlap; - WindowPtr newParent; - - if(!pPriv->underlayMarked) - goto SKIP_UNDERLAY; - - if (!pChild) pChild = pParent->firstChild; - - REGION_NULL(pScreen, &totalClip); - REGION_NULL(pScreen, &childClip); - REGION_NULL(pScreen, &exposed); - - newParent = pParent; - - while(IN_OVERLAY(newParent)) - newParent = newParent->parent; - - tParent = MIOVERLAY_GET_WINDOW_TREE(newParent); - - if(IN_UNDERLAY(pChild)) - tChild = MIOVERLAY_GET_WINDOW_TREE(pChild); - else - tChild = tParent->firstChild; - - if (REGION_BROKEN (pScreen, &tParent->clipList) && - !REGION_BROKEN (pScreen, &tParent->borderClip)) - { - kind = VTBroken; - REGION_COPY (pScreen, &totalClip, &tParent->borderClip); - REGION_INTERSECT (pScreen, &totalClip, &totalClip, - &tParent->pWin->winSize); - - for (tWin = tParent->firstChild; tWin != tChild; tWin = tWin->nextSib) { - if (tWin->pWin->viewable) - REGION_SUBTRACT (pScreen, &totalClip, &totalClip, - &tWin->pWin->borderSize); - } - REGION_EMPTY (pScreen, &tParent->clipList); - } else { - for(tWin = tChild; tWin; tWin = tWin->nextSib) { - if(tWin->valdata) - REGION_APPEND(pScreen, &totalClip, &tWin->borderClip); - } - REGION_VALIDATE(pScreen, &totalClip, &overlap); - } - - if(kind != VTStack) - REGION_UNION(pScreen, &totalClip, &totalClip, &tParent->clipList); - - for(tWin = tChild; tWin; tWin = tWin->nextSib) { - if(tWin->valdata) { - if(tWin->pWin->viewable) { - REGION_INTERSECT(pScreen, &childClip, &totalClip, - &tWin->pWin->borderSize); - miOverlayComputeClips(tWin->pWin, &childClip, kind, &exposed); - REGION_SUBTRACT(pScreen, &totalClip, &totalClip, - &tWin->pWin->borderSize); - } else { /* Means we are unmapping */ - REGION_EMPTY(pScreen, &tWin->clipList); - REGION_EMPTY( pScreen, &tWin->borderClip); - tWin->valdata = NULL; - } - } - } - - REGION_UNINIT(pScreen, &childClip); - - if(!((*pPriv->InOverlay)(newParent))) { - REGION_NULL(pScreen, &tParent->valdata->exposed); - REGION_NULL(pScreen, &tParent->valdata->borderExposed); - } - - switch (kind) { - case VTStack: - break; - default: - if(!((*pPriv->InOverlay)(newParent))) - REGION_SUBTRACT(pScreen, &tParent->valdata->exposed, &totalClip, - &tParent->clipList); - /* fall through */ - case VTMap: - REGION_COPY( pScreen, &tParent->clipList, &totalClip); - if(!((*pPriv->InOverlay)(newParent))) - newParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; - break; - } - - REGION_UNINIT( pScreen, &totalClip); - REGION_UNINIT( pScreen, &exposed); - -SKIP_UNDERLAY: - - miValidateTree(pParent, pChild, kind); - - return 1; -} - - -static void -miOverlayHandleExposures(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - WindowPtr pChild; - ValidatePtr val; - void (* WindowExposures)(WindowPtr, RegionPtr, RegionPtr); - - WindowExposures = pWin->drawable.pScreen->WindowExposures; - if(pPriv->underlayMarked) { - miOverlayTreePtr pTree; - miOverlayValDataPtr mival; - - pChild = pWin; - while(IN_OVERLAY(pChild)) - pChild = pChild->parent; - - pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); - - while (1) { - if((mival = pTree->valdata)) { - if(!((*pPriv->InOverlay)(pTree->pWin))) { - if (REGION_NOTEMPTY(pScreen, &mival->borderExposed)) { - miPaintWindow(pTree->pWin, &mival->borderExposed, - PW_BORDER); - } - REGION_UNINIT(pScreen, &mival->borderExposed); - - (*WindowExposures)(pTree->pWin,&mival->exposed,NullRegion); - REGION_UNINIT(pScreen, &mival->exposed); - } - xfree(mival); - pTree->valdata = NULL; - if (pTree->firstChild) { - pTree = pTree->firstChild; - continue; - } - } - while (!pTree->nextSib && (pTree->pWin != pChild)) - pTree = pTree->parent; - if (pTree->pWin == pChild) - break; - pTree = pTree->nextSib; - } - pPriv->underlayMarked = FALSE; - } - - pChild = pWin; - while (1) { - if ( (val = pChild->valdata) ) { - if(!((*pPriv->InOverlay)(pChild))) { - REGION_UNION(pScreen, &val->after.exposed, &val->after.exposed, - &val->after.borderExposed); - - if (REGION_NOTEMPTY(pScreen, &val->after.exposed)) { - (*(MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent))( - pScreen, - REGION_NUM_RECTS(&val->after.exposed), - REGION_RECTS(&val->after.exposed)); - } - } else { - if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed)) { - miPaintWindow(pChild, &val->after.borderExposed, - PW_BORDER); - } - (*WindowExposures)(pChild, &val->after.exposed, NullRegion); - } - REGION_UNINIT(pScreen, &val->after.borderExposed); - REGION_UNINIT(pScreen, &val->after.exposed); - xfree(val); - pChild->valdata = NULL; - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } -} - - -static void -miOverlayMoveWindow( - WindowPtr pWin, - int x, - int y, - WindowPtr pNextSib, - VTKind kind -){ - ScreenPtr pScreen = pWin->drawable.pScreen; - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - WindowPtr pParent, windowToValidate; - Bool WasViewable = (Bool)(pWin->viewable); - short bw; - RegionRec overReg, underReg; - DDXPointRec oldpt; - - if (!(pParent = pWin->parent)) - return ; - bw = wBorderWidth (pWin); - - oldpt.x = pWin->drawable.x; - oldpt.y = pWin->drawable.y; - if (WasViewable) { - REGION_NULL(pScreen, &overReg); - REGION_NULL(pScreen, &underReg); - if(pTree) { - REGION_COPY(pScreen, &overReg, &pWin->borderClip); - REGION_COPY(pScreen, &underReg, &pTree->borderClip); - } else { - REGION_COPY(pScreen, &overReg, &pWin->borderClip); - CollectUnderlayChildrenRegions(pWin, &underReg); - } - (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); - } - pWin->origin.x = x + (int)bw; - pWin->origin.y = y + (int)bw; - x = pWin->drawable.x = pParent->drawable.x + x + (int)bw; - y = pWin->drawable.y = pParent->drawable.y + y + (int)bw; - - SetWinSize (pWin); - SetBorderSize (pWin); - - (*pScreen->PositionWindow)(pWin, x, y); - - windowToValidate = MoveWindowInStack(pWin, pNextSib); - - ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0); - - if (WasViewable) { - miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - (*pScreen->MarkOverlappedWindows) (pWin, windowToValidate, NULL); - - - (*pScreen->ValidateTree)(pWin->parent, NullWindow, kind); - if(REGION_NOTEMPTY(pScreen, &underReg)) { - pPriv->copyUnderlay = TRUE; - (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &underReg); - } - REGION_UNINIT(pScreen, &underReg); - if(REGION_NOTEMPTY(pScreen, &overReg)) { - pPriv->copyUnderlay = FALSE; - (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &overReg); - } - REGION_UNINIT(pScreen, &overReg); - (*pScreen->HandleExposures)(pWin->parent); - - if (pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pWin->parent, NullWindow, kind); - } - if (pWin->realized) - WindowsRestructured (); -} - -#ifndef RECTLIMIT -#define RECTLIMIT 25 -#endif - -static void -miOverlayWindowExposures( - WindowPtr pWin, - RegionPtr prgn, - RegionPtr other_exposed -){ - RegionPtr exposures = prgn; - ScreenPtr pScreen = pWin->drawable.pScreen; - - if ((prgn && !REGION_NIL(prgn)) || - (exposures && !REGION_NIL(exposures)) || other_exposed) - { - RegionRec expRec; - int clientInterested; - - clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & - ExposureMask; - if (other_exposed) { - if (exposures) { - REGION_UNION(pScreen, other_exposed, exposures, other_exposed); - if (exposures != prgn) - REGION_DESTROY(pScreen, exposures); - } - exposures = other_exposed; - } - if (clientInterested && exposures && - (REGION_NUM_RECTS(exposures) > RECTLIMIT)) - { - miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - BoxRec box; - - box = *REGION_EXTENTS(pScreen, exposures); - if (exposures == prgn) { - exposures = &expRec; - REGION_INIT(pScreen, exposures, &box, 1); - REGION_RESET(pScreen, prgn, &box); - } else { - REGION_RESET(pScreen, exposures, &box); - REGION_UNION(pScreen, prgn, prgn, exposures); - } - /* This is the only reason why we are replacing mi's version - of this file */ - - if(!((*pPriv->InOverlay)(pWin))) { - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - REGION_INTERSECT(pScreen, prgn, prgn, &pTree->clipList); - } else - REGION_INTERSECT(pScreen, prgn, prgn, &pWin->clipList); - } - if (prgn && !REGION_NIL(prgn)) - miPaintWindow(pWin, prgn, PW_BACKGROUND); - if (clientInterested && exposures && !REGION_NIL(exposures)) - miSendExposures(pWin, exposures, - pWin->drawable.x, pWin->drawable.y); - if (exposures == &expRec) { - REGION_UNINIT(pScreen, exposures); - } - else if (exposures && exposures != prgn && exposures != other_exposed) - REGION_DESTROY(pScreen, exposures); - if (prgn) - REGION_EMPTY(pScreen, prgn); - } - else if (exposures && exposures != prgn) - REGION_DESTROY(pScreen, exposures); -} - - -typedef struct { - RegionPtr over; - RegionPtr under; -} miOverlayTwoRegions; - -static int -miOverlayRecomputeExposures ( - WindowPtr pWin, - pointer value -){ - ScreenPtr pScreen; - miOverlayTwoRegions *pValid = (miOverlayTwoRegions*)value; - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - - /* This prevents warning about pScreen not being used. */ - pWin->drawable.pScreen = pScreen = pWin->drawable.pScreen; - - if (pWin->valdata) { - /* - * compute exposed regions of this window - */ - REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, - &pWin->clipList, pValid->over); - /* - * compute exposed regions of the border - */ - REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, - &pWin->borderClip, &pWin->winSize); - REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, - &pWin->valdata->after.borderExposed, pValid->over); - } - - if(pTree && pTree->valdata) { - REGION_SUBTRACT(pScreen, &pTree->valdata->exposed, - &pTree->clipList, pValid->under); - REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed, - &pTree->borderClip, &pWin->winSize); - REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed, - &pTree->valdata->borderExposed, pValid->under); - } else if (!pWin->valdata) - return WT_NOMATCH; - - return WT_WALKCHILDREN; -} - -static void -miOverlayResizeWindow( - WindowPtr pWin, - int x, int y, - unsigned int w, unsigned int h, - WindowPtr pSib -){ - ScreenPtr pScreen = pWin->drawable.pScreen; - WindowPtr pParent; - miOverlayTreePtr tChild, pTree; - Bool WasViewable = (Bool)(pWin->viewable); - unsigned short width = pWin->drawable.width; - unsigned short height = pWin->drawable.height; - short oldx = pWin->drawable.x; - short oldy = pWin->drawable.y; - int bw = wBorderWidth (pWin); - short dw, dh; - DDXPointRec oldpt; - RegionPtr oldRegion = NULL, oldRegion2 = NULL; - WindowPtr pFirstChange; - WindowPtr pChild; - RegionPtr gravitate[StaticGravity + 1]; - RegionPtr gravitate2[StaticGravity + 1]; - unsigned g; - int nx, ny; /* destination x,y */ - int newx, newy; /* new inner window position */ - RegionPtr pRegion = NULL; - RegionPtr destClip, destClip2; - RegionPtr oldWinClip = NULL, oldWinClip2 = NULL; - RegionPtr borderVisible = NullRegion; - RegionPtr borderVisible2 = NullRegion; - Bool shrunk = FALSE; /* shrunk in an inner dimension */ - Bool moved = FALSE; /* window position changed */ - Bool doUnderlay; - - /* if this is a root window, can't be resized */ - if (!(pParent = pWin->parent)) - return ; - - pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - doUnderlay = ((pTree) || HasUnderlayChildren(pWin)); - newx = pParent->drawable.x + x + bw; - newy = pParent->drawable.y + y + bw; - if (WasViewable) - { - /* - * save the visible region of the window - */ - oldRegion = REGION_CREATE(pScreen, NullBox, 1); - REGION_COPY(pScreen, oldRegion, &pWin->winSize); - if(doUnderlay) { - oldRegion2 = REGION_CREATE(pScreen, NullBox, 1); - REGION_COPY(pScreen, oldRegion2, &pWin->winSize); - } - - /* - * categorize child windows into regions to be moved - */ - for (g = 0; g <= StaticGravity; g++) - gravitate[g] = gravitate2[g] = NULL; - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) { - g = pChild->winGravity; - if (g != UnmapGravity) { - if (!gravitate[g]) - gravitate[g] = REGION_CREATE(pScreen, NullBox, 1); - REGION_UNION(pScreen, gravitate[g], - gravitate[g], &pChild->borderClip); - - if(doUnderlay) { - if (!gravitate2[g]) - gravitate2[g] = REGION_CREATE(pScreen, NullBox, 0); - - if((tChild = MIOVERLAY_GET_WINDOW_TREE(pChild))) { - REGION_UNION(pScreen, gravitate2[g], - gravitate2[g], &tChild->borderClip); - } else - CollectUnderlayChildrenRegions(pChild, gravitate2[g]); - } - } else { - UnmapWindow(pChild, TRUE); - } - } - (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); - - - oldWinClip = oldWinClip2 = NULL; - if (pWin->bitGravity != ForgetGravity) { - oldWinClip = REGION_CREATE(pScreen, NullBox, 1); - REGION_COPY(pScreen, oldWinClip, &pWin->clipList); - if(pTree) { - oldWinClip2 = REGION_CREATE(pScreen, NullBox, 1); - REGION_COPY(pScreen, oldWinClip2, &pTree->clipList); - } - } - /* - * if the window is changing size, borderExposed - * can't be computed correctly without some help. - */ - if (pWin->drawable.height > h || pWin->drawable.width > w) - shrunk = TRUE; - - if (newx != oldx || newy != oldy) - moved = TRUE; - - if ((pWin->drawable.height != h || pWin->drawable.width != w) && - HasBorder (pWin)) - { - borderVisible = REGION_CREATE(pScreen, NullBox, 1); - if(pTree) - borderVisible2 = REGION_CREATE(pScreen, NullBox, 1); - /* for tiled borders, we punt and draw the whole thing */ - if (pWin->borderIsPixel || !moved) - { - if (shrunk || moved) - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, - &pWin->winSize); - else - REGION_COPY(pScreen, borderVisible, - &pWin->borderClip); - if(pTree) { - if (shrunk || moved) - REGION_SUBTRACT(pScreen, borderVisible, - &pTree->borderClip, - &pWin->winSize); - else - REGION_COPY(pScreen, borderVisible, - &pTree->borderClip); - } - } - } - } - pWin->origin.x = x + bw; - pWin->origin.y = y + bw; - pWin->drawable.height = h; - pWin->drawable.width = w; - - x = pWin->drawable.x = newx; - y = pWin->drawable.y = newy; - - SetWinSize (pWin); - SetBorderSize (pWin); - - dw = (int)w - (int)width; - dh = (int)h - (int)height; - ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh); - - /* let the hardware adjust background and border pixmaps, if any */ - (*pScreen->PositionWindow)(pWin, x, y); - - pFirstChange = MoveWindowInStack(pWin, pSib); - - if (WasViewable) { - pRegion = REGION_CREATE(pScreen, NullBox, 1); - - (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, NULL); - - pWin->valdata->before.resized = TRUE; - pWin->valdata->before.borderVisible = borderVisible; - if(pTree) - pTree->valdata->borderVisible = borderVisible2; - - - (*pScreen->ValidateTree)(pWin->parent, pFirstChange, VTOther); - /* - * the entire window is trashed unless bitGravity - * recovers portions of it - */ - REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList); - if(pTree) - REGION_COPY(pScreen, &pTree->valdata->exposed, &pTree->clipList); - } - - GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny); - - if (WasViewable) { - miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - miOverlayTwoRegions TwoRegions; - - /* avoid the border */ - if (HasBorder (pWin)) { - int offx, offy, dx, dy; - - /* kruft to avoid double translates for each gravity */ - offx = 0; - offy = 0; - for (g = 0; g <= StaticGravity; g++) { - if (!gravitate[g] && !gravitate2[g]) - continue; - - /* align winSize to gravitate[g]. - * winSize is in new coordinates, - * gravitate[g] is still in old coordinates */ - GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); - - dx = (oldx - nx) - offx; - dy = (oldy - ny) - offy; - if (dx || dy) { - REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy); - offx += dx; - offy += dy; - } - if(gravitate[g]) - REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], - &pWin->winSize); - if(gravitate2[g]) - REGION_INTERSECT(pScreen, gravitate2[g], gravitate2[g], - &pWin->winSize); - } - /* get winSize back where it belongs */ - if (offx || offy) - REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy); - } - /* - * add screen bits to the appropriate bucket - */ - - if (oldWinClip2) - { - REGION_COPY(pScreen, pRegion, oldWinClip2); - REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); - REGION_INTERSECT(pScreen, oldWinClip2, pRegion, &pTree->clipList); - - for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) { - if (gravitate2[g]) - REGION_SUBTRACT(pScreen, oldWinClip2, oldWinClip2, - gravitate2[g]); - } - REGION_TRANSLATE(pScreen, oldWinClip2, oldx - nx, oldy - ny); - g = pWin->bitGravity; - if (!gravitate2[g]) - gravitate2[g] = oldWinClip2; - else { - REGION_UNION(pScreen,gravitate2[g],gravitate2[g],oldWinClip2); - REGION_DESTROY(pScreen, oldWinClip2); - } - } - - if (oldWinClip) - { - /* - * clip to new clipList - */ - REGION_COPY(pScreen, pRegion, oldWinClip); - REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); - REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList); - /* - * don't step on any gravity bits which will be copied after this - * region. Note -- this assumes that the regions will be copied - * in gravity order. - */ - for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) { - if (gravitate[g]) - REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip, - gravitate[g]); - } - REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny); - g = pWin->bitGravity; - if (!gravitate[g]) - gravitate[g] = oldWinClip; - else { - REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip); - REGION_DESTROY(pScreen, oldWinClip); - } - } - - /* - * move the bits on the screen - */ - - destClip = destClip2 = NULL; - - for (g = 0; g <= StaticGravity; g++) { - if (!gravitate[g] && !gravitate2[g]) - continue; - - GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); - - oldpt.x = oldx + (x - nx); - oldpt.y = oldy + (y - ny); - - /* Note that gravitate[g] is *translated* by CopyWindow */ - - /* only copy the remaining useful bits */ - - if(gravitate[g]) - REGION_INTERSECT(pScreen, gravitate[g], - gravitate[g], oldRegion); - if(gravitate2[g]) - REGION_INTERSECT(pScreen, gravitate2[g], - gravitate2[g], oldRegion2); - - /* clip to not overwrite already copied areas */ - - if (destClip && gravitate[g]) { - REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y); - REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip); - REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y); - } - if (destClip2 && gravitate2[g]) { - REGION_TRANSLATE(pScreen, destClip2, oldpt.x - x, oldpt.y - y); - REGION_SUBTRACT(pScreen,gravitate2[g],gravitate2[g],destClip2); - REGION_TRANSLATE(pScreen, destClip2, x - oldpt.x, y - oldpt.y); - } - - /* and move those bits */ - - if (oldpt.x != x || oldpt.y != y) { - if(gravitate2[g]) { - pPriv->copyUnderlay = TRUE; - (*pWin->drawable.pScreen->CopyWindow)( - pWin, oldpt, gravitate2[g]); - } - if(gravitate[g]) { - pPriv->copyUnderlay = FALSE; - (*pWin->drawable.pScreen->CopyWindow)( - pWin, oldpt, gravitate[g]); - } - } - - /* remove any overwritten bits from the remaining useful bits */ - - if(gravitate[g]) - REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]); - if(gravitate2[g]) - REGION_SUBTRACT(pScreen, oldRegion2, oldRegion2, gravitate2[g]); - - /* - * recompute exposed regions of child windows - */ - - - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) { - if (pChild->winGravity != g) - continue; - - TwoRegions.over = gravitate[g]; - TwoRegions.under = gravitate2[g]; - - TraverseTree (pChild, miOverlayRecomputeExposures, - (pointer)(&TwoRegions)); - } - - /* - * remove the successfully copied regions of the - * window from its exposed region - */ - - if (g == pWin->bitGravity) { - if(gravitate[g]) - REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, - &pWin->valdata->after.exposed, gravitate[g]); - if(gravitate2[g] && pTree) - REGION_SUBTRACT(pScreen, &pTree->valdata->exposed, - &pTree->valdata->exposed, gravitate2[g]); - } - if(gravitate[g]) { - if (!destClip) - destClip = gravitate[g]; - else { - REGION_UNION(pScreen, destClip, destClip, gravitate[g]); - REGION_DESTROY(pScreen, gravitate[g]); - } - } - if(gravitate2[g]) { - if (!destClip2) - destClip2 = gravitate2[g]; - else { - REGION_UNION(pScreen, destClip2, destClip2, gravitate2[g]); - REGION_DESTROY(pScreen, gravitate2[g]); - } - } - } - - REGION_DESTROY(pScreen, pRegion); - REGION_DESTROY(pScreen, oldRegion); - if(doUnderlay) - REGION_DESTROY(pScreen, oldRegion2); - if (destClip) - REGION_DESTROY(pScreen, destClip); - if (destClip2) - REGION_DESTROY(pScreen, destClip2); - (*pScreen->HandleExposures)(pWin->parent); - if (pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pWin->parent, pFirstChange, VTOther); - } - if (pWin->realized) - WindowsRestructured (); -} - - -static void -miOverlaySetShape(WindowPtr pWin) -{ - Bool WasViewable = (Bool)(pWin->viewable); - ScreenPtr pScreen = pWin->drawable.pScreen; - - if (WasViewable) { - (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); - - if (HasBorder (pWin)) { - RegionPtr borderVisible; - - borderVisible = REGION_CREATE(pScreen, NullBox, 1); - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, &pWin->winSize); - pWin->valdata->before.borderVisible = borderVisible; - pWin->valdata->before.resized = TRUE; - if(IN_UNDERLAY(pWin)) { - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - RegionPtr borderVisible2; - - borderVisible2 = REGION_CREATE(pScreen, NULL, 1); - REGION_SUBTRACT(pScreen, borderVisible2, - &pTree->borderClip, &pWin->winSize); - pTree->valdata->borderVisible = borderVisible2; - } - } - } - - SetWinSize (pWin); - SetBorderSize (pWin); - - ResizeChildrenWinSize(pWin, 0, 0, 0, 0); - - if (WasViewable) { - (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); - - - (*pScreen->ValidateTree)(pWin->parent, NullWindow, VTOther); - } - - if (WasViewable) { - (*pScreen->HandleExposures)(pWin->parent); - if (pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pWin->parent, NullWindow, VTOther); - } - if (pWin->realized) - WindowsRestructured (); - CheckCursorConfinement(pWin); -} - - - -static void -miOverlayChangeBorderWidth( - WindowPtr pWin, - unsigned int width -){ - int oldwidth; - ScreenPtr pScreen; - Bool WasViewable = (Bool)(pWin->viewable); - Bool HadBorder; - - oldwidth = wBorderWidth (pWin); - if (oldwidth == width) - return; - HadBorder = HasBorder(pWin); - pScreen = pWin->drawable.pScreen; - if (WasViewable && (width < oldwidth)) - (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); - - pWin->borderWidth = width; - SetBorderSize (pWin); - - if (WasViewable) { - if (width > oldwidth) { - (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); - - if (HadBorder) { - RegionPtr borderVisible; - borderVisible = REGION_CREATE(pScreen, NULL, 1); - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, &pWin->winSize); - pWin->valdata->before.borderVisible = borderVisible; - if(IN_UNDERLAY(pWin)) { - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - RegionPtr borderVisible2; - - borderVisible2 = REGION_CREATE(pScreen, NULL, 1); - REGION_SUBTRACT(pScreen, borderVisible2, - &pTree->borderClip, &pWin->winSize); - pTree->valdata->borderVisible = borderVisible2; - } - } - } - (*pScreen->ValidateTree)(pWin->parent, pWin, VTOther); - (*pScreen->HandleExposures)(pWin->parent); - - if (pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pWin->parent, pWin, VTOther); - } - if (pWin->realized) - WindowsRestructured (); -} - -/* We need this as an addition since the xf86 common code doesn't - know about the second tree which is static to this file. */ - -void -miOverlaySetRootClip(ScreenPtr pScreen, Bool enable) -{ - WindowPtr pRoot = WindowTable[pScreen->myNum]; - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pRoot); - - MARK_UNDERLAY(pRoot); - - if(enable) { - BoxRec box; - - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - - REGION_RESET(pScreen, &pTree->borderClip, &box); - } else - REGION_EMPTY(pScreen, &pTree->borderClip); - - REGION_BREAK(pScreen, &pTree->clipList); -} - -static void -miOverlayClearToBackground( - WindowPtr pWin, - int x, int y, - int w, int h, - Bool generateExposures -) -{ - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - BoxRec box; - RegionRec reg; - RegionPtr pBSReg = NullRegion; - ScreenPtr pScreen = pWin->drawable.pScreen; - miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); - RegionPtr clipList; - BoxPtr extents; - int x1, y1, x2, y2; - - x1 = pWin->drawable.x + x; - y1 = pWin->drawable.y + y; - if (w) - x2 = x1 + (int) w; - else - x2 = x1 + (int) pWin->drawable.width - (int) x; - if (h) - y2 = y1 + h; - else - y2 = y1 + (int) pWin->drawable.height - (int) y; - - clipList = ((*pScreenPriv->InOverlay)(pWin)) ? &pWin->clipList : - &pTree->clipList; - - extents = REGION_EXTENTS(pScreen, clipList); - - if (x1 < extents->x1) x1 = extents->x1; - if (x2 > extents->x2) x2 = extents->x2; - if (y1 < extents->y1) y1 = extents->y1; - if (y2 > extents->y2) y2 = extents->y2; - - if (x2 <= x1 || y2 <= y1) - x2 = x1 = y2 = y1 = 0; - - box.x1 = x1; box.x2 = x2; - box.y1 = y1; box.y2 = y2; - - REGION_INIT(pScreen, ®, &box, 1); - - REGION_INTERSECT(pScreen, ®, ®, clipList); - if (generateExposures) - (*pScreen->WindowExposures)(pWin, ®, pBSReg); - else if (pWin->backgroundState != None) - miPaintWindow(pWin, ®, PW_BACKGROUND); - REGION_UNINIT(pScreen, ®); - if (pBSReg) - REGION_DESTROY(pScreen, pBSReg); -} - - -/****************************************************************/ - -/* not used */ -Bool -miOverlayGetPrivateClips( - WindowPtr pWin, - RegionPtr *borderClip, - RegionPtr *clipList -){ - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - - if(pTree) { - *borderClip = &(pTree->borderClip); - *clipList = &(pTree->clipList); - return TRUE; - } - - *borderClip = *clipList = NULL; - - return FALSE; -} - -void -miOverlaySetTransFunction ( - ScreenPtr pScreen, - miOverlayTransFunc transFunc -){ - MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent = transFunc; -} - -Bool -miOverlayCopyUnderlay(ScreenPtr pScreen) -{ - return MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->copyUnderlay; -} - -void -miOverlayComputeCompositeClip(GCPtr pGC, WindowPtr pWin) -{ - ScreenPtr pScreen = pGC->pScreen; - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - RegionPtr pregWin; - Bool freeTmpClip, freeCompClip; - - if(!pTree) { - miComputeCompositeClip(pGC, &pWin->drawable); - return; - } - - if (pGC->subWindowMode == IncludeInferiors) { - pregWin = REGION_CREATE(pScreen, NullBox, 1); - freeTmpClip = TRUE; - if (pWin->parent || (screenIsSaved != SCREEN_SAVER_ON) || - !HasSaverWindow (pScreen->myNum)) - { - REGION_INTERSECT(pScreen,pregWin,&pTree->borderClip,&pWin->winSize); - } - } else { - pregWin = &pTree->clipList; - freeTmpClip = FALSE; - } - freeCompClip = pGC->freeCompClip; - if (pGC->clientClipType == CT_NONE) { - if (freeCompClip) - REGION_DESTROY(pScreen, pGC->pCompositeClip); - pGC->pCompositeClip = pregWin; - pGC->freeCompClip = freeTmpClip; - } else { - REGION_TRANSLATE(pScreen, pGC->clientClip, - pWin->drawable.x + pGC->clipOrg.x, - pWin->drawable.y + pGC->clipOrg.y); - - if (freeCompClip) { - REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip, - pregWin, pGC->clientClip); - if (freeTmpClip) - REGION_DESTROY(pScreen, pregWin); - } else if (freeTmpClip) { - REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip); - pGC->pCompositeClip = pregWin; - } else { - pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); - REGION_INTERSECT(pScreen, pGC->pCompositeClip, - pregWin, pGC->clientClip); - } - pGC->freeCompClip = TRUE; - REGION_TRANSLATE(pScreen, pGC->clientClip, - -(pWin->drawable.x + pGC->clipOrg.x), - -(pWin->drawable.y + pGC->clipOrg.y)); - } -} - -Bool -miOverlayCollectUnderlayRegions( - WindowPtr pWin, - RegionPtr *region -){ - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - - if(pTree) { - *region = &pTree->borderClip; - return FALSE; - } - - *region = REGION_CREATE(pWin->drawable.pScreen, NullBox, 0); - - CollectUnderlayChildrenRegions(pWin, *region); - - return TRUE; -} - - -static miOverlayTreePtr -DoLeaf( - WindowPtr pWin, - miOverlayTreePtr parent, - miOverlayTreePtr prevSib -){ - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - - pTree->parent = parent; - pTree->firstChild = NULL; - pTree->lastChild = NULL; - pTree->prevSib = prevSib; - pTree->nextSib = NULL; - - if(prevSib) - prevSib->nextSib = pTree; - - if(!parent->firstChild) - parent->firstChild = parent->lastChild = pTree; - else if(parent->lastChild == prevSib) - parent->lastChild = pTree; - - return pTree; -} - -static void -RebuildTree(WindowPtr pWin) -{ - miOverlayTreePtr parent, prevSib, tChild; - WindowPtr pChild; - - prevSib = tChild = NULL; - - pWin = pWin->parent; - - while(IN_OVERLAY(pWin)) - pWin = pWin->parent; - - parent = MIOVERLAY_GET_WINDOW_TREE(pWin); - - pChild = pWin->firstChild; - parent->firstChild = parent->lastChild = NULL; - - while(1) { - if(IN_UNDERLAY(pChild)) - prevSib = tChild = DoLeaf(pChild, parent, prevSib); - - if(pChild->firstChild) { - if(IN_UNDERLAY(pChild)) { - parent = tChild; - prevSib = NULL; - } - pChild = pChild->firstChild; - continue; - } - - while(!pChild->nextSib) { - pChild = pChild->parent; - if(pChild == pWin) return; - if(IN_UNDERLAY(pChild)) { - prevSib = tChild = MIOVERLAY_GET_WINDOW_TREE(pChild); - parent = tChild->parent; - } - } - - pChild = pChild->nextSib; - } -} - - -static Bool -HasUnderlayChildren(WindowPtr pWin) -{ - WindowPtr pChild; - - if(!(pChild = pWin->firstChild)) - return FALSE; - - while(1) { - if(IN_UNDERLAY(pChild)) - return TRUE; - - if(pChild->firstChild) { - pChild = pChild->firstChild; - continue; - } - - while(!pChild->nextSib && (pWin != pChild)) - pChild = pChild->parent; - - if(pChild == pWin) break; - - pChild = pChild->nextSib; - } - - return FALSE; -} - - -static Bool -CollectUnderlayChildrenRegions(WindowPtr pWin, RegionPtr pReg) -{ - WindowPtr pChild; - miOverlayTreePtr pTree; - Bool hasUnderlay; - - if(!(pChild = pWin->firstChild)) - return FALSE; - - hasUnderlay = FALSE; - - while(1) { - if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) { - REGION_APPEND(pScreen, pReg, &pTree->borderClip); - hasUnderlay = TRUE; - } else - if(pChild->firstChild) { - pChild = pChild->firstChild; - continue; - } - - while(!pChild->nextSib && (pWin != pChild)) - pChild = pChild->parent; - - if(pChild == pWin) break; - - pChild = pChild->nextSib; - } - - if(hasUnderlay) { - Bool overlap; - REGION_VALIDATE(pScreen, pReg, &overlap); - } - - return hasUnderlay; -} - - -static void -MarkUnderlayWindow(WindowPtr pWin) -{ - miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); - - if(pTree->valdata) return; - pTree->valdata = (miOverlayValDataPtr)xnfalloc(sizeof(miOverlayValDataRec)); - pTree->valdata->oldAbsCorner.x = pWin->drawable.x; - pTree->valdata->oldAbsCorner.y = pWin->drawable.y; - pTree->valdata->borderVisible = NullRegion; -} + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "scrnintstr.h" +#include "validate.h" +#include "windowstr.h" +#include "mi.h" +#include "gcstruct.h" +#include "regionstr.h" +#include "privates.h" +#include "mivalidate.h" +#include "mioverlay.h" +#include "migc.h" + +#include "globals.h" + + +typedef struct { + RegionRec exposed; + RegionRec borderExposed; + RegionPtr borderVisible; + DDXPointRec oldAbsCorner; +} miOverlayValDataRec, *miOverlayValDataPtr; + +typedef struct _TreeRec { + WindowPtr pWin; + struct _TreeRec *parent; + struct _TreeRec *firstChild; + struct _TreeRec *lastChild; + struct _TreeRec *prevSib; + struct _TreeRec *nextSib; + RegionRec borderClip; + RegionRec clipList; + unsigned visibility; + miOverlayValDataPtr valdata; +} miOverlayTreeRec, *miOverlayTreePtr; + +typedef struct { + miOverlayTreePtr tree; +} miOverlayWindowRec, *miOverlayWindowPtr; + +typedef struct { + CloseScreenProcPtr CloseScreen; + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + RealizeWindowProcPtr RealizeWindow; + miOverlayTransFunc MakeTransparent; + miOverlayInOverlayFunc InOverlay; + Bool underlayMarked; + Bool copyUnderlay; +} miOverlayScreenRec, *miOverlayScreenPtr; + +static int miOverlayWindowKeyKeyIndex; +static DevPrivateKey miOverlayWindowKey = &miOverlayWindowKeyKeyIndex; +static int miOverlayScreenKeyIndex; +static DevPrivateKey miOverlayScreenKey = &miOverlayScreenKeyIndex; + +static void RebuildTree(WindowPtr); +static Bool HasUnderlayChildren(WindowPtr); +static void MarkUnderlayWindow(WindowPtr); +static Bool CollectUnderlayChildrenRegions(WindowPtr, RegionPtr); + +static Bool miOverlayCloseScreen(int, ScreenPtr); +static Bool miOverlayCreateWindow(WindowPtr); +static Bool miOverlayDestroyWindow(WindowPtr); +static Bool miOverlayUnrealizeWindow(WindowPtr); +static Bool miOverlayRealizeWindow(WindowPtr); +static void miOverlayMarkWindow(WindowPtr); +static void miOverlayReparentWindow(WindowPtr, WindowPtr); +static void miOverlayRestackWindow(WindowPtr, WindowPtr); +static Bool miOverlayMarkOverlappedWindows(WindowPtr, WindowPtr, WindowPtr*); +static void miOverlayMarkUnrealizedWindow(WindowPtr, WindowPtr, Bool); +static int miOverlayValidateTree(WindowPtr, WindowPtr, VTKind); +static void miOverlayHandleExposures(WindowPtr); +static void miOverlayMoveWindow(WindowPtr, int, int, WindowPtr, VTKind); +static void miOverlayWindowExposures(WindowPtr, RegionPtr, RegionPtr); +static void miOverlayResizeWindow(WindowPtr, int, int, unsigned int, + unsigned int, WindowPtr); +static void miOverlayClearToBackground(WindowPtr, int, int, int, int, Bool); + +static void miOverlaySetShape(WindowPtr); +static void miOverlayChangeBorderWidth(WindowPtr, unsigned int); + +#define MIOVERLAY_GET_SCREEN_PRIVATE(pScreen) ((miOverlayScreenPtr) \ + dixLookupPrivate(&(pScreen)->devPrivates, miOverlayScreenKey)) +#define MIOVERLAY_GET_WINDOW_PRIVATE(pWin) ((miOverlayWindowPtr) \ + dixLookupPrivate(&(pWin)->devPrivates, miOverlayWindowKey)) +#define MIOVERLAY_GET_WINDOW_TREE(pWin) \ + (MIOVERLAY_GET_WINDOW_PRIVATE(pWin)->tree) + +#define IN_UNDERLAY(w) MIOVERLAY_GET_WINDOW_TREE(w) +#define IN_OVERLAY(w) !MIOVERLAY_GET_WINDOW_TREE(w) + +#define MARK_OVERLAY(w) miMarkWindow(w) +#define MARK_UNDERLAY(w) MarkUnderlayWindow(w) + +#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ + HasBorder(w) && \ + (w)->backgroundState == ParentRelative) + +Bool +miInitOverlay( + ScreenPtr pScreen, + miOverlayInOverlayFunc inOverlayFunc, + miOverlayTransFunc transFunc +){ + miOverlayScreenPtr pScreenPriv; + + if(!inOverlayFunc || !transFunc) return FALSE; + + if(!dixRequestPrivate(miOverlayWindowKey, sizeof(miOverlayWindowRec))) + return FALSE; + + if(!(pScreenPriv = malloc(sizeof(miOverlayScreenRec)))) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, miOverlayScreenKey, pScreenPriv); + + pScreenPriv->InOverlay = inOverlayFunc; + pScreenPriv->MakeTransparent = transFunc; + pScreenPriv->underlayMarked = FALSE; + + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreenPriv->CreateWindow = pScreen->CreateWindow; + pScreenPriv->DestroyWindow = pScreen->DestroyWindow; + pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow; + pScreenPriv->RealizeWindow = pScreen->RealizeWindow; + + pScreen->CloseScreen = miOverlayCloseScreen; + pScreen->CreateWindow = miOverlayCreateWindow; + pScreen->DestroyWindow = miOverlayDestroyWindow; + pScreen->UnrealizeWindow = miOverlayUnrealizeWindow; + pScreen->RealizeWindow = miOverlayRealizeWindow; + + pScreen->ReparentWindow = miOverlayReparentWindow; + pScreen->RestackWindow = miOverlayRestackWindow; + pScreen->MarkOverlappedWindows = miOverlayMarkOverlappedWindows; + pScreen->MarkUnrealizedWindow = miOverlayMarkUnrealizedWindow; + pScreen->ValidateTree = miOverlayValidateTree; + pScreen->HandleExposures = miOverlayHandleExposures; + pScreen->MoveWindow = miOverlayMoveWindow; + pScreen->WindowExposures = miOverlayWindowExposures; + pScreen->ResizeWindow = miOverlayResizeWindow; + pScreen->MarkWindow = miOverlayMarkWindow; + pScreen->ClearToBackground = miOverlayClearToBackground; + pScreen->SetShape = miOverlaySetShape; + pScreen->ChangeBorderWidth = miOverlayChangeBorderWidth; + + return TRUE; +} + + +static Bool +miOverlayCloseScreen(int i, ScreenPtr pScreen) +{ + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->CreateWindow = pScreenPriv->CreateWindow; + pScreen->DestroyWindow = pScreenPriv->DestroyWindow; + pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow; + pScreen->RealizeWindow = pScreenPriv->RealizeWindow; + + free(pScreenPriv); + + return (*pScreen->CloseScreen)(i, pScreen); +} + + +static Bool +miOverlayCreateWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayWindowPtr pWinPriv = MIOVERLAY_GET_WINDOW_PRIVATE(pWin); + miOverlayTreePtr pTree = NULL; + Bool result = TRUE; + + pWinPriv->tree = NULL; + + if(!pWin->parent || !((*pScreenPriv->InOverlay)(pWin))) { + if(!(pTree = (miOverlayTreePtr)calloc(1, sizeof(miOverlayTreeRec)))) + return FALSE; + } + + if(pScreenPriv->CreateWindow) { + pScreen->CreateWindow = pScreenPriv->CreateWindow; + result = (*pScreen->CreateWindow)(pWin); + pScreen->CreateWindow = miOverlayCreateWindow; + } + + if (pTree) { + if(result) { + pTree->pWin = pWin; + pTree->visibility = VisibilityNotViewable; + pWinPriv->tree = pTree; + if(pWin->parent) { + REGION_NULL(pScreen, &(pTree->borderClip)); + REGION_NULL(pScreen, &(pTree->clipList)); + RebuildTree(pWin); + } else { + BoxRec fullBox; + fullBox.x1 = 0; + fullBox.y1 = 0; + fullBox.x2 = pScreen->width; + fullBox.y2 = pScreen->height; + REGION_INIT(pScreen, &(pTree->borderClip), &fullBox, 1); + REGION_INIT(pScreen, &(pTree->clipList), &fullBox, 1); + } + } else free(pTree); + } + + return TRUE; +} + + +static Bool +miOverlayDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + Bool result = TRUE; + + if (pTree) { + if(pTree->prevSib) + pTree->prevSib->nextSib = pTree->nextSib; + else if(pTree->parent) + pTree->parent->firstChild = pTree->nextSib; + + if(pTree->nextSib) + pTree->nextSib->prevSib = pTree->prevSib; + else if(pTree->parent) + pTree->parent->lastChild = pTree->prevSib; + + REGION_UNINIT(pScreen, &(pTree->borderClip)); + REGION_UNINIT(pScreen, &(pTree->clipList)); + free(pTree); + } + + if(pScreenPriv->DestroyWindow) { + pScreen->DestroyWindow = pScreenPriv->DestroyWindow; + result = (*pScreen->DestroyWindow)(pWin); + pScreen->DestroyWindow = miOverlayDestroyWindow; + } + + return result; +} + +static Bool +miOverlayUnrealizeWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + Bool result = TRUE; + + if(pTree) pTree->visibility = VisibilityNotViewable; + + if(pScreenPriv->UnrealizeWindow) { + pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow; + result = (*pScreen->UnrealizeWindow)(pWin); + pScreen->UnrealizeWindow = miOverlayUnrealizeWindow; + } + + return result; +} + + +static Bool +miOverlayRealizeWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + Bool result = TRUE; + + if(pScreenPriv->RealizeWindow) { + pScreen->RealizeWindow = pScreenPriv->RealizeWindow; + result = (*pScreen->RealizeWindow)(pWin); + pScreen->RealizeWindow = miOverlayRealizeWindow; + } + + /* we only need to catch the root window realization */ + + if(result && !pWin->parent && !((*pScreenPriv->InOverlay)(pWin))) + { + BoxRec box; + box.x1 = box.y1 = 0; + box.x2 = pWin->drawable.width; + box.y2 = pWin->drawable.height; + (*pScreenPriv->MakeTransparent)(pScreen, 1, &box); + } + + return result; +} + + +static void +miOverlayReparentWindow(WindowPtr pWin, WindowPtr pPriorParent) +{ + if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) { + /* This could probably be more optimal */ + RebuildTree(WindowTable[pWin->drawable.pScreen->myNum]->firstChild); + } +} + +static void +miOverlayRestackWindow(WindowPtr pWin, WindowPtr oldNextSib) +{ + if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) { + /* This could probably be more optimal */ + RebuildTree(pWin); + } +} + + +static Bool +miOverlayMarkOverlappedWindows( + WindowPtr pWin, + WindowPtr pFirst, + WindowPtr *pLayerWin +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pChild, pLast; + Bool overMarked, underMarked, doUnderlay, markAll; + miOverlayTreePtr pTree = NULL, tLast, tChild; + BoxPtr box; + + overMarked = underMarked = markAll = FALSE; + + if(pLayerWin) *pLayerWin = pWin; /* hah! */ + + doUnderlay = (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)); + + box = REGION_EXTENTS(pScreen, &pWin->borderSize); + + if((pChild = pFirst)) { + pLast = pChild->parent->lastChild; + while (1) { + if (pChild == pWin) markAll = TRUE; + + if(doUnderlay && IN_UNDERLAY(pChild)) + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + + if(pChild->viewable) { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + + if (markAll || + RECT_IN_REGION(pScreen, &pChild->borderSize, box)) + { + MARK_OVERLAY(pChild); + overMarked = TRUE; + if(doUnderlay && IN_UNDERLAY(pChild)) { + MARK_UNDERLAY(pChild); + underMarked = TRUE; + } + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + } + } + while (!pChild->nextSib && (pChild != pLast)) { + pChild = pChild->parent; + if(doUnderlay && IN_UNDERLAY(pChild)) + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + } + + if(pChild == pWin) markAll = FALSE; + + if (pChild == pLast) break; + + pChild = pChild->nextSib; + } + if(overMarked) + MARK_OVERLAY(pWin->parent); + } + + if(doUnderlay && !pTree) { + if(!(pTree = MIOVERLAY_GET_WINDOW_TREE(pWin))) { + pChild = pWin->lastChild; + while(1) { + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) + break; + + if(pChild->lastChild) { + pChild = pChild->lastChild; + continue; + } + + while(!pChild->prevSib) pChild = pChild->parent; + + pChild = pChild->prevSib; + } + } + } + + if(pTree && pTree->nextSib) { + tChild = pTree->parent->lastChild; + tLast = pTree->nextSib; + + while(1) { + if(tChild->pWin->viewable) { + if (REGION_BROKEN (pScreen, &tChild->pWin->winSize)) + SetWinSize (tChild->pWin); + if (REGION_BROKEN (pScreen, &tChild->pWin->borderSize)) + SetBorderSize (tChild->pWin); + + if(RECT_IN_REGION(pScreen, &(tChild->pWin->borderSize), box)) + { + MARK_UNDERLAY(tChild->pWin); + underMarked = TRUE; + } + } + + if(tChild->lastChild) { + tChild = tChild->lastChild; + continue; + } + + while(!tChild->prevSib && (tChild != tLast)) + tChild = tChild->parent; + + if(tChild == tLast) break; + + tChild = tChild->prevSib; + } + } + + if(underMarked) { + MARK_UNDERLAY(pTree->parent->pWin); + MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->underlayMarked = TRUE; + } + + return (underMarked || overMarked); +} + + +static void +miOverlayComputeClips( + WindowPtr pParent, + RegionPtr universe, + VTKind kind, + RegionPtr exposed +){ + ScreenPtr pScreen = pParent->drawable.pScreen; + int oldVis, newVis, dx, dy; + BoxRec borderSize; + RegionPtr borderVisible; + RegionRec childUniverse, childUnion; + miOverlayTreePtr tParent = MIOVERLAY_GET_WINDOW_TREE(pParent); + miOverlayTreePtr tChild; + Bool overlap; + + borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); + borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); + dx = (int) pParent->drawable.x + (int) pParent->drawable.width + + wBorderWidth(pParent); + if (dx > 32767) dx = 32767; + borderSize.x2 = dx; + dy = (int) pParent->drawable.y + (int) pParent->drawable.height + + wBorderWidth(pParent); + if (dy > 32767) dy = 32767; + borderSize.y2 = dy; + + oldVis = tParent->visibility; + switch (RECT_IN_REGION( pScreen, universe, &borderSize)) { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnPART: + newVis = VisibilityPartiallyObscured; + { + RegionPtr pBounding; + + if ((pBounding = wBoundingShape (pParent))) { + switch (miShapedWindowIn (pScreen, universe, pBounding, + &borderSize, + pParent->drawable.x, + pParent->drawable.y)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnOUT: + newVis = VisibilityFullyObscured; + break; + } + } + } + break; + default: + newVis = VisibilityFullyObscured; + break; + } + tParent->visibility = newVis; + + dx = pParent->drawable.x - tParent->valdata->oldAbsCorner.x; + dy = pParent->drawable.y - tParent->valdata->oldAbsCorner.y; + + switch (kind) { + case VTMap: + case VTStack: + case VTUnmap: + break; + case VTMove: + if ((oldVis == newVis) && + ((oldVis == VisibilityFullyObscured) || + (oldVis == VisibilityUnobscured))) + { + tChild = tParent; + while (1) { + if (tChild->pWin->viewable) { + if (tChild->visibility != VisibilityFullyObscured) { + REGION_TRANSLATE( pScreen, &tChild->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &tChild->clipList, dx, dy); + + tChild->pWin->drawable.serialNumber = + NEXT_SERIAL_NUMBER; + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (tChild->pWin, dx, dy); + } + if (tChild->valdata) { + REGION_NULL(pScreen, &tChild->valdata->borderExposed); + if (HasParentRelativeBorder(tChild->pWin)){ + REGION_SUBTRACT(pScreen, + &tChild->valdata->borderExposed, + &tChild->borderClip, + &tChild->pWin->winSize); + } + REGION_NULL(pScreen, &tChild->valdata->exposed); + } + if (tChild->firstChild) { + tChild = tChild->firstChild; + continue; + } + } + while (!tChild->nextSib && (tChild != tParent)) + tChild = tChild->parent; + if (tChild == tParent) + break; + tChild = tChild->nextSib; + } + return; + } + /* fall through */ + default: + if (dx || dy) { + REGION_TRANSLATE( pScreen, &tParent->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &tParent->clipList, dx, dy); + } + break; + case VTBroken: + REGION_EMPTY (pScreen, &tParent->borderClip); + REGION_EMPTY (pScreen, &tParent->clipList); + break; + } + + borderVisible = tParent->valdata->borderVisible; + REGION_NULL(pScreen, &tParent->valdata->borderExposed); + REGION_NULL(pScreen, &tParent->valdata->exposed); + + if (HasBorder (pParent)) { + if (borderVisible) { + REGION_SUBTRACT( pScreen, exposed, universe, borderVisible); + REGION_DESTROY( pScreen, borderVisible); + } else + REGION_SUBTRACT( pScreen, exposed, universe, &tParent->borderClip); + + if (HasParentRelativeBorder(pParent) && (dx || dy)) + REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed, + universe, &pParent->winSize); + else + REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed, + exposed, &pParent->winSize); + + REGION_COPY( pScreen, &tParent->borderClip, universe); + REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize); + } + else + REGION_COPY( pScreen, &tParent->borderClip, universe); + + if ((tChild = tParent->firstChild) && pParent->mapped) { + REGION_NULL(pScreen, &childUniverse); + REGION_NULL(pScreen, &childUnion); + + for (; tChild; tChild = tChild->nextSib) { + if (tChild->pWin->viewable) + REGION_APPEND( pScreen, &childUnion, &tChild->pWin->borderSize); + } + + REGION_VALIDATE( pScreen, &childUnion, &overlap); + + for (tChild = tParent->firstChild; + tChild; + tChild = tChild->nextSib) + { + if (tChild->pWin->viewable) { + if (tChild->valdata) { + REGION_INTERSECT( pScreen, &childUniverse, universe, + &tChild->pWin->borderSize); + miOverlayComputeClips (tChild->pWin, &childUniverse, + kind, exposed); + } + if (overlap) + REGION_SUBTRACT( pScreen, universe, universe, + &tChild->pWin->borderSize); + } + } + if (!overlap) + REGION_SUBTRACT( pScreen, universe, universe, &childUnion); + REGION_UNINIT( pScreen, &childUnion); + REGION_UNINIT( pScreen, &childUniverse); + } + + if (oldVis == VisibilityFullyObscured || + oldVis == VisibilityNotViewable) + { + REGION_COPY( pScreen, &tParent->valdata->exposed, universe); + } + else if (newVis != VisibilityFullyObscured && + newVis != VisibilityNotViewable) + { + REGION_SUBTRACT( pScreen, &tParent->valdata->exposed, + universe, &tParent->clipList); + } + + /* HACK ALERT - copying contents of regions, instead of regions */ + { + RegionRec tmp; + + tmp = tParent->clipList; + tParent->clipList = *universe; + *universe = tmp; + } + + pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pParent, dx, dy); +} + + +static void +miOverlayMarkWindow(WindowPtr pWin) +{ + miOverlayTreePtr pTree = NULL; + WindowPtr pChild, pGrandChild; + + miMarkWindow(pWin); + + /* look for UnmapValdata among immediate children */ + + if(!(pChild = pWin->firstChild)) return; + + for( ; pChild; pChild = pChild->nextSib) { + if(pChild->valdata == UnmapValData) { + if(IN_UNDERLAY(pChild)) { + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + pTree->valdata = (miOverlayValDataPtr)UnmapValData; + continue; + } else { + if(!(pGrandChild = pChild->firstChild)) + continue; + + while(1) { + if(IN_UNDERLAY(pGrandChild)) { + pTree = MIOVERLAY_GET_WINDOW_TREE(pGrandChild); + pTree->valdata = (miOverlayValDataPtr)UnmapValData; + } else if(pGrandChild->firstChild) { + pGrandChild = pGrandChild->firstChild; + continue; + } + + while(!pGrandChild->nextSib && (pGrandChild != pChild)) + pGrandChild = pGrandChild->parent; + + if(pChild == pGrandChild) break; + + pGrandChild = pGrandChild->nextSib; + } + } + } + } + + if(pTree) { + MARK_UNDERLAY(pTree->parent->pWin); + MIOVERLAY_GET_SCREEN_PRIVATE( + pWin->drawable.pScreen)->underlayMarked = TRUE; + } +} + +static void +miOverlayMarkUnrealizedWindow( + WindowPtr pChild, + WindowPtr pWin, + Bool fromConfigure +){ + if ((pChild != pWin) || fromConfigure) { + miOverlayTreePtr pTree; + + REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList); + if (pChild->drawable.pScreen->ClipNotify) + (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0); + REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip); + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + if(pTree->valdata != (miOverlayValDataPtr)UnmapValData) { + REGION_EMPTY(pChild->drawable.pScreen, &pTree->clipList); + REGION_EMPTY(pChild->drawable.pScreen, &pTree->borderClip); + } + } + } +} + + +static int +miOverlayValidateTree( + WindowPtr pParent, + WindowPtr pChild, /* first child effected */ + VTKind kind +){ + ScreenPtr pScreen = pParent->drawable.pScreen; + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + RegionRec totalClip, childClip, exposed; + miOverlayTreePtr tParent, tChild, tWin; + Bool overlap; + WindowPtr newParent; + + if(!pPriv->underlayMarked) + goto SKIP_UNDERLAY; + + if (!pChild) pChild = pParent->firstChild; + + REGION_NULL(pScreen, &totalClip); + REGION_NULL(pScreen, &childClip); + REGION_NULL(pScreen, &exposed); + + newParent = pParent; + + while(IN_OVERLAY(newParent)) + newParent = newParent->parent; + + tParent = MIOVERLAY_GET_WINDOW_TREE(newParent); + + if(IN_UNDERLAY(pChild)) + tChild = MIOVERLAY_GET_WINDOW_TREE(pChild); + else + tChild = tParent->firstChild; + + if (REGION_BROKEN (pScreen, &tParent->clipList) && + !REGION_BROKEN (pScreen, &tParent->borderClip)) + { + kind = VTBroken; + REGION_COPY (pScreen, &totalClip, &tParent->borderClip); + REGION_INTERSECT (pScreen, &totalClip, &totalClip, + &tParent->pWin->winSize); + + for (tWin = tParent->firstChild; tWin != tChild; tWin = tWin->nextSib) { + if (tWin->pWin->viewable) + REGION_SUBTRACT (pScreen, &totalClip, &totalClip, + &tWin->pWin->borderSize); + } + REGION_EMPTY (pScreen, &tParent->clipList); + } else { + for(tWin = tChild; tWin; tWin = tWin->nextSib) { + if(tWin->valdata) + REGION_APPEND(pScreen, &totalClip, &tWin->borderClip); + } + REGION_VALIDATE(pScreen, &totalClip, &overlap); + } + + if(kind != VTStack) + REGION_UNION(pScreen, &totalClip, &totalClip, &tParent->clipList); + + for(tWin = tChild; tWin; tWin = tWin->nextSib) { + if(tWin->valdata) { + if(tWin->pWin->viewable) { + REGION_INTERSECT(pScreen, &childClip, &totalClip, + &tWin->pWin->borderSize); + miOverlayComputeClips(tWin->pWin, &childClip, kind, &exposed); + REGION_SUBTRACT(pScreen, &totalClip, &totalClip, + &tWin->pWin->borderSize); + } else { /* Means we are unmapping */ + REGION_EMPTY(pScreen, &tWin->clipList); + REGION_EMPTY( pScreen, &tWin->borderClip); + tWin->valdata = NULL; + } + } + } + + REGION_UNINIT(pScreen, &childClip); + + if(!((*pPriv->InOverlay)(newParent))) { + REGION_NULL(pScreen, &tParent->valdata->exposed); + REGION_NULL(pScreen, &tParent->valdata->borderExposed); + } + + switch (kind) { + case VTStack: + break; + default: + if(!((*pPriv->InOverlay)(newParent))) + REGION_SUBTRACT(pScreen, &tParent->valdata->exposed, &totalClip, + &tParent->clipList); + /* fall through */ + case VTMap: + REGION_COPY( pScreen, &tParent->clipList, &totalClip); + if(!((*pPriv->InOverlay)(newParent))) + newParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + break; + } + + REGION_UNINIT( pScreen, &totalClip); + REGION_UNINIT( pScreen, &exposed); + +SKIP_UNDERLAY: + + miValidateTree(pParent, pChild, kind); + + return 1; +} + + +static void +miOverlayHandleExposures(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + WindowPtr pChild; + ValidatePtr val; + void (* WindowExposures)(WindowPtr, RegionPtr, RegionPtr); + + WindowExposures = pWin->drawable.pScreen->WindowExposures; + if(pPriv->underlayMarked) { + miOverlayTreePtr pTree; + miOverlayValDataPtr mival; + + pChild = pWin; + while(IN_OVERLAY(pChild)) + pChild = pChild->parent; + + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + + while (1) { + if((mival = pTree->valdata)) { + if(!((*pPriv->InOverlay)(pTree->pWin))) { + if (REGION_NOTEMPTY(pScreen, &mival->borderExposed)) { + miPaintWindow(pTree->pWin, &mival->borderExposed, + PW_BORDER); + } + REGION_UNINIT(pScreen, &mival->borderExposed); + + (*WindowExposures)(pTree->pWin,&mival->exposed,NullRegion); + REGION_UNINIT(pScreen, &mival->exposed); + } + free(mival); + pTree->valdata = NULL; + if (pTree->firstChild) { + pTree = pTree->firstChild; + continue; + } + } + while (!pTree->nextSib && (pTree->pWin != pChild)) + pTree = pTree->parent; + if (pTree->pWin == pChild) + break; + pTree = pTree->nextSib; + } + pPriv->underlayMarked = FALSE; + } + + pChild = pWin; + while (1) { + if ( (val = pChild->valdata) ) { + if(!((*pPriv->InOverlay)(pChild))) { + REGION_UNION(pScreen, &val->after.exposed, &val->after.exposed, + &val->after.borderExposed); + + if (REGION_NOTEMPTY(pScreen, &val->after.exposed)) { + (*(MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent))( + pScreen, + REGION_NUM_RECTS(&val->after.exposed), + REGION_RECTS(&val->after.exposed)); + } + } else { + if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed)) { + miPaintWindow(pChild, &val->after.borderExposed, + PW_BORDER); + } + (*WindowExposures)(pChild, &val->after.exposed, NullRegion); + } + REGION_UNINIT(pScreen, &val->after.borderExposed); + REGION_UNINIT(pScreen, &val->after.exposed); + free(val); + pChild->valdata = NULL; + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + + +static void +miOverlayMoveWindow( + WindowPtr pWin, + int x, + int y, + WindowPtr pNextSib, + VTKind kind +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + WindowPtr pParent, windowToValidate; + Bool WasViewable = (Bool)(pWin->viewable); + short bw; + RegionRec overReg, underReg; + DDXPointRec oldpt; + + if (!(pParent = pWin->parent)) + return ; + bw = wBorderWidth (pWin); + + oldpt.x = pWin->drawable.x; + oldpt.y = pWin->drawable.y; + if (WasViewable) { + REGION_NULL(pScreen, &overReg); + REGION_NULL(pScreen, &underReg); + if(pTree) { + REGION_COPY(pScreen, &overReg, &pWin->borderClip); + REGION_COPY(pScreen, &underReg, &pTree->borderClip); + } else { + REGION_COPY(pScreen, &overReg, &pWin->borderClip); + CollectUnderlayChildrenRegions(pWin, &underReg); + } + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + } + pWin->origin.x = x + (int)bw; + pWin->origin.y = y + (int)bw; + x = pWin->drawable.x = pParent->drawable.x + x + (int)bw; + y = pWin->drawable.y = pParent->drawable.y + y + (int)bw; + + SetWinSize (pWin); + SetBorderSize (pWin); + + (*pScreen->PositionWindow)(pWin, x, y); + + windowToValidate = MoveWindowInStack(pWin, pNextSib); + + ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0); + + if (WasViewable) { + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + (*pScreen->MarkOverlappedWindows) (pWin, windowToValidate, NULL); + + + (*pScreen->ValidateTree)(pWin->parent, NullWindow, kind); + if(REGION_NOTEMPTY(pScreen, &underReg)) { + pPriv->copyUnderlay = TRUE; + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &underReg); + } + REGION_UNINIT(pScreen, &underReg); + if(REGION_NOTEMPTY(pScreen, &overReg)) { + pPriv->copyUnderlay = FALSE; + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &overReg); + } + REGION_UNINIT(pScreen, &overReg); + (*pScreen->HandleExposures)(pWin->parent); + + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, NullWindow, kind); + } + if (pWin->realized) + WindowsRestructured (); +} + +#ifndef RECTLIMIT +#define RECTLIMIT 25 +#endif + +static void +miOverlayWindowExposures( + WindowPtr pWin, + RegionPtr prgn, + RegionPtr other_exposed +){ + RegionPtr exposures = prgn; + ScreenPtr pScreen = pWin->drawable.pScreen; + + if ((prgn && !REGION_NIL(prgn)) || + (exposures && !REGION_NIL(exposures)) || other_exposed) + { + RegionRec expRec; + int clientInterested; + + clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & + ExposureMask; + if (other_exposed) { + if (exposures) { + REGION_UNION(pScreen, other_exposed, exposures, other_exposed); + if (exposures != prgn) + REGION_DESTROY(pScreen, exposures); + } + exposures = other_exposed; + } + if (clientInterested && exposures && + (REGION_NUM_RECTS(exposures) > RECTLIMIT)) + { + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + BoxRec box; + + box = *REGION_EXTENTS(pScreen, exposures); + if (exposures == prgn) { + exposures = &expRec; + REGION_INIT(pScreen, exposures, &box, 1); + REGION_RESET(pScreen, prgn, &box); + } else { + REGION_RESET(pScreen, exposures, &box); + REGION_UNION(pScreen, prgn, prgn, exposures); + } + /* This is the only reason why we are replacing mi's version + of this file */ + + if(!((*pPriv->InOverlay)(pWin))) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + REGION_INTERSECT(pScreen, prgn, prgn, &pTree->clipList); + } else + REGION_INTERSECT(pScreen, prgn, prgn, &pWin->clipList); + } + if (prgn && !REGION_NIL(prgn)) + miPaintWindow(pWin, prgn, PW_BACKGROUND); + if (clientInterested && exposures && !REGION_NIL(exposures)) + miSendExposures(pWin, exposures, + pWin->drawable.x, pWin->drawable.y); + if (exposures == &expRec) { + REGION_UNINIT(pScreen, exposures); + } + else if (exposures && exposures != prgn && exposures != other_exposed) + REGION_DESTROY(pScreen, exposures); + if (prgn) + REGION_EMPTY(pScreen, prgn); + } + else if (exposures && exposures != prgn) + REGION_DESTROY(pScreen, exposures); +} + + +typedef struct { + RegionPtr over; + RegionPtr under; +} miOverlayTwoRegions; + +static int +miOverlayRecomputeExposures ( + WindowPtr pWin, + pointer value +){ + ScreenPtr pScreen; + miOverlayTwoRegions *pValid = (miOverlayTwoRegions*)value; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + /* This prevents warning about pScreen not being used. */ + pWin->drawable.pScreen = pScreen = pWin->drawable.pScreen; + + if (pWin->valdata) { + /* + * compute exposed regions of this window + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->clipList, pValid->over); + /* + * compute exposed regions of the border + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->borderClip, &pWin->winSize); + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->valdata->after.borderExposed, pValid->over); + } + + if(pTree && pTree->valdata) { + REGION_SUBTRACT(pScreen, &pTree->valdata->exposed, + &pTree->clipList, pValid->under); + REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed, + &pTree->borderClip, &pWin->winSize); + REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed, + &pTree->valdata->borderExposed, pValid->under); + } else if (!pWin->valdata) + return WT_NOMATCH; + + return WT_WALKCHILDREN; +} + +static void +miOverlayResizeWindow( + WindowPtr pWin, + int x, int y, + unsigned int w, unsigned int h, + WindowPtr pSib +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pParent; + miOverlayTreePtr tChild, pTree; + Bool WasViewable = (Bool)(pWin->viewable); + unsigned short width = pWin->drawable.width; + unsigned short height = pWin->drawable.height; + short oldx = pWin->drawable.x; + short oldy = pWin->drawable.y; + int bw = wBorderWidth (pWin); + short dw, dh; + DDXPointRec oldpt; + RegionPtr oldRegion = NULL, oldRegion2 = NULL; + WindowPtr pFirstChange; + WindowPtr pChild; + RegionPtr gravitate[StaticGravity + 1]; + RegionPtr gravitate2[StaticGravity + 1]; + unsigned g; + int nx, ny; /* destination x,y */ + int newx, newy; /* new inner window position */ + RegionPtr pRegion = NULL; + RegionPtr destClip, destClip2; + RegionPtr oldWinClip = NULL, oldWinClip2 = NULL; + RegionPtr borderVisible = NullRegion; + RegionPtr borderVisible2 = NullRegion; + Bool shrunk = FALSE; /* shrunk in an inner dimension */ + Bool moved = FALSE; /* window position changed */ + Bool doUnderlay; + + /* if this is a root window, can't be resized */ + if (!(pParent = pWin->parent)) + return ; + + pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + doUnderlay = ((pTree) || HasUnderlayChildren(pWin)); + newx = pParent->drawable.x + x + bw; + newy = pParent->drawable.y + y + bw; + if (WasViewable) + { + /* + * save the visible region of the window + */ + oldRegion = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion, &pWin->winSize); + if(doUnderlay) { + oldRegion2 = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion2, &pWin->winSize); + } + + /* + * categorize child windows into regions to be moved + */ + for (g = 0; g <= StaticGravity; g++) + gravitate[g] = gravitate2[g] = NULL; + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) { + g = pChild->winGravity; + if (g != UnmapGravity) { + if (!gravitate[g]) + gravitate[g] = REGION_CREATE(pScreen, NullBox, 1); + REGION_UNION(pScreen, gravitate[g], + gravitate[g], &pChild->borderClip); + + if(doUnderlay) { + if (!gravitate2[g]) + gravitate2[g] = REGION_CREATE(pScreen, NullBox, 0); + + if((tChild = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + REGION_UNION(pScreen, gravitate2[g], + gravitate2[g], &tChild->borderClip); + } else + CollectUnderlayChildrenRegions(pChild, gravitate2[g]); + } + } else { + UnmapWindow(pChild, TRUE); + } + } + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + + oldWinClip = oldWinClip2 = NULL; + if (pWin->bitGravity != ForgetGravity) { + oldWinClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldWinClip, &pWin->clipList); + if(pTree) { + oldWinClip2 = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldWinClip2, &pTree->clipList); + } + } + /* + * if the window is changing size, borderExposed + * can't be computed correctly without some help. + */ + if (pWin->drawable.height > h || pWin->drawable.width > w) + shrunk = TRUE; + + if (newx != oldx || newy != oldy) + moved = TRUE; + + if ((pWin->drawable.height != h || pWin->drawable.width != w) && + HasBorder (pWin)) + { + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + if(pTree) + borderVisible2 = REGION_CREATE(pScreen, NullBox, 1); + /* for tiled borders, we punt and draw the whole thing */ + if (pWin->borderIsPixel || !moved) + { + if (shrunk || moved) + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, + &pWin->winSize); + else + REGION_COPY(pScreen, borderVisible, + &pWin->borderClip); + if(pTree) { + if (shrunk || moved) + REGION_SUBTRACT(pScreen, borderVisible, + &pTree->borderClip, + &pWin->winSize); + else + REGION_COPY(pScreen, borderVisible, + &pTree->borderClip); + } + } + } + } + pWin->origin.x = x + bw; + pWin->origin.y = y + bw; + pWin->drawable.height = h; + pWin->drawable.width = w; + + x = pWin->drawable.x = newx; + y = pWin->drawable.y = newy; + + SetWinSize (pWin); + SetBorderSize (pWin); + + dw = (int)w - (int)width; + dh = (int)h - (int)height; + ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh); + + /* let the hardware adjust background and border pixmaps, if any */ + (*pScreen->PositionWindow)(pWin, x, y); + + pFirstChange = MoveWindowInStack(pWin, pSib); + + if (WasViewable) { + pRegion = REGION_CREATE(pScreen, NullBox, 1); + + (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, NULL); + + pWin->valdata->before.resized = TRUE; + pWin->valdata->before.borderVisible = borderVisible; + if(pTree) + pTree->valdata->borderVisible = borderVisible2; + + + (*pScreen->ValidateTree)(pWin->parent, pFirstChange, VTOther); + /* + * the entire window is trashed unless bitGravity + * recovers portions of it + */ + REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList); + if(pTree) + REGION_COPY(pScreen, &pTree->valdata->exposed, &pTree->clipList); + } + + GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny); + + if (WasViewable) { + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayTwoRegions TwoRegions; + + /* avoid the border */ + if (HasBorder (pWin)) { + int offx, offy, dx, dy; + + /* kruft to avoid double translates for each gravity */ + offx = 0; + offy = 0; + for (g = 0; g <= StaticGravity; g++) { + if (!gravitate[g] && !gravitate2[g]) + continue; + + /* align winSize to gravitate[g]. + * winSize is in new coordinates, + * gravitate[g] is still in old coordinates */ + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + dx = (oldx - nx) - offx; + dy = (oldy - ny) - offy; + if (dx || dy) { + REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy); + offx += dx; + offy += dy; + } + if(gravitate[g]) + REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], + &pWin->winSize); + if(gravitate2[g]) + REGION_INTERSECT(pScreen, gravitate2[g], gravitate2[g], + &pWin->winSize); + } + /* get winSize back where it belongs */ + if (offx || offy) + REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy); + } + /* + * add screen bits to the appropriate bucket + */ + + if (oldWinClip2) + { + REGION_COPY(pScreen, pRegion, oldWinClip2); + REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); + REGION_INTERSECT(pScreen, oldWinClip2, pRegion, &pTree->clipList); + + for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) { + if (gravitate2[g]) + REGION_SUBTRACT(pScreen, oldWinClip2, oldWinClip2, + gravitate2[g]); + } + REGION_TRANSLATE(pScreen, oldWinClip2, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate2[g]) + gravitate2[g] = oldWinClip2; + else { + REGION_UNION(pScreen,gravitate2[g],gravitate2[g],oldWinClip2); + REGION_DESTROY(pScreen, oldWinClip2); + } + } + + if (oldWinClip) + { + /* + * clip to new clipList + */ + REGION_COPY(pScreen, pRegion, oldWinClip); + REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); + REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList); + /* + * don't step on any gravity bits which will be copied after this + * region. Note -- this assumes that the regions will be copied + * in gravity order. + */ + for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) { + if (gravitate[g]) + REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip, + gravitate[g]); + } + REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate[g]) + gravitate[g] = oldWinClip; + else { + REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip); + REGION_DESTROY(pScreen, oldWinClip); + } + } + + /* + * move the bits on the screen + */ + + destClip = destClip2 = NULL; + + for (g = 0; g <= StaticGravity; g++) { + if (!gravitate[g] && !gravitate2[g]) + continue; + + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + oldpt.x = oldx + (x - nx); + oldpt.y = oldy + (y - ny); + + /* Note that gravitate[g] is *translated* by CopyWindow */ + + /* only copy the remaining useful bits */ + + if(gravitate[g]) + REGION_INTERSECT(pScreen, gravitate[g], + gravitate[g], oldRegion); + if(gravitate2[g]) + REGION_INTERSECT(pScreen, gravitate2[g], + gravitate2[g], oldRegion2); + + /* clip to not overwrite already copied areas */ + + if (destClip && gravitate[g]) { + REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y); + REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip); + REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y); + } + if (destClip2 && gravitate2[g]) { + REGION_TRANSLATE(pScreen, destClip2, oldpt.x - x, oldpt.y - y); + REGION_SUBTRACT(pScreen,gravitate2[g],gravitate2[g],destClip2); + REGION_TRANSLATE(pScreen, destClip2, x - oldpt.x, y - oldpt.y); + } + + /* and move those bits */ + + if (oldpt.x != x || oldpt.y != y) { + if(gravitate2[g]) { + pPriv->copyUnderlay = TRUE; + (*pWin->drawable.pScreen->CopyWindow)( + pWin, oldpt, gravitate2[g]); + } + if(gravitate[g]) { + pPriv->copyUnderlay = FALSE; + (*pWin->drawable.pScreen->CopyWindow)( + pWin, oldpt, gravitate[g]); + } + } + + /* remove any overwritten bits from the remaining useful bits */ + + if(gravitate[g]) + REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]); + if(gravitate2[g]) + REGION_SUBTRACT(pScreen, oldRegion2, oldRegion2, gravitate2[g]); + + /* + * recompute exposed regions of child windows + */ + + + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) { + if (pChild->winGravity != g) + continue; + + TwoRegions.over = gravitate[g]; + TwoRegions.under = gravitate2[g]; + + TraverseTree (pChild, miOverlayRecomputeExposures, + (pointer)(&TwoRegions)); + } + + /* + * remove the successfully copied regions of the + * window from its exposed region + */ + + if (g == pWin->bitGravity) { + if(gravitate[g]) + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->valdata->after.exposed, gravitate[g]); + if(gravitate2[g] && pTree) + REGION_SUBTRACT(pScreen, &pTree->valdata->exposed, + &pTree->valdata->exposed, gravitate2[g]); + } + if(gravitate[g]) { + if (!destClip) + destClip = gravitate[g]; + else { + REGION_UNION(pScreen, destClip, destClip, gravitate[g]); + REGION_DESTROY(pScreen, gravitate[g]); + } + } + if(gravitate2[g]) { + if (!destClip2) + destClip2 = gravitate2[g]; + else { + REGION_UNION(pScreen, destClip2, destClip2, gravitate2[g]); + REGION_DESTROY(pScreen, gravitate2[g]); + } + } + } + + REGION_DESTROY(pScreen, pRegion); + REGION_DESTROY(pScreen, oldRegion); + if(doUnderlay) + REGION_DESTROY(pScreen, oldRegion2); + if (destClip) + REGION_DESTROY(pScreen, destClip); + if (destClip2) + REGION_DESTROY(pScreen, destClip2); + (*pScreen->HandleExposures)(pWin->parent); + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, pFirstChange, VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + + +static void +miOverlaySetShape(WindowPtr pWin) +{ + Bool WasViewable = (Bool)(pWin->viewable); + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (WasViewable) { + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + if (HasBorder (pWin)) { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + pWin->valdata->before.resized = TRUE; + if(IN_UNDERLAY(pWin)) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr borderVisible2; + + borderVisible2 = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible2, + &pTree->borderClip, &pWin->winSize); + pTree->valdata->borderVisible = borderVisible2; + } + } + } + + SetWinSize (pWin); + SetBorderSize (pWin); + + ResizeChildrenWinSize(pWin, 0, 0, 0, 0); + + if (WasViewable) { + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + + (*pScreen->ValidateTree)(pWin->parent, NullWindow, VTOther); + } + + if (WasViewable) { + (*pScreen->HandleExposures)(pWin->parent); + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + CheckCursorConfinement(pWin); +} + + + +static void +miOverlayChangeBorderWidth( + WindowPtr pWin, + unsigned int width +){ + int oldwidth; + ScreenPtr pScreen; + Bool WasViewable = (Bool)(pWin->viewable); + Bool HadBorder; + + oldwidth = wBorderWidth (pWin); + if (oldwidth == width) + return; + HadBorder = HasBorder(pWin); + pScreen = pWin->drawable.pScreen; + if (WasViewable && (width < oldwidth)) + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + pWin->borderWidth = width; + SetBorderSize (pWin); + + if (WasViewable) { + if (width > oldwidth) { + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + if (HadBorder) { + RegionPtr borderVisible; + borderVisible = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + if(IN_UNDERLAY(pWin)) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr borderVisible2; + + borderVisible2 = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible2, + &pTree->borderClip, &pWin->winSize); + pTree->valdata->borderVisible = borderVisible2; + } + } + } + (*pScreen->ValidateTree)(pWin->parent, pWin, VTOther); + (*pScreen->HandleExposures)(pWin->parent); + + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, pWin, VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +/* We need this as an addition since the xf86 common code doesn't + know about the second tree which is static to this file. */ + +void +miOverlaySetRootClip(ScreenPtr pScreen, Bool enable) +{ + WindowPtr pRoot = WindowTable[pScreen->myNum]; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pRoot); + + MARK_UNDERLAY(pRoot); + + if(enable) { + BoxRec box; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + + REGION_RESET(pScreen, &pTree->borderClip, &box); + } else + REGION_EMPTY(pScreen, &pTree->borderClip); + + REGION_BREAK(pScreen, &pTree->clipList); +} + +static void +miOverlayClearToBackground( + WindowPtr pWin, + int x, int y, + int w, int h, + Bool generateExposures +) +{ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + BoxRec box; + RegionRec reg; + RegionPtr pBSReg = NullRegion; + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + RegionPtr clipList; + BoxPtr extents; + int x1, y1, x2, y2; + + x1 = pWin->drawable.x + x; + y1 = pWin->drawable.y + y; + if (w) + x2 = x1 + (int) w; + else + x2 = x1 + (int) pWin->drawable.width - (int) x; + if (h) + y2 = y1 + h; + else + y2 = y1 + (int) pWin->drawable.height - (int) y; + + clipList = ((*pScreenPriv->InOverlay)(pWin)) ? &pWin->clipList : + &pTree->clipList; + + extents = REGION_EXTENTS(pScreen, clipList); + + if (x1 < extents->x1) x1 = extents->x1; + if (x2 > extents->x2) x2 = extents->x2; + if (y1 < extents->y1) y1 = extents->y1; + if (y2 > extents->y2) y2 = extents->y2; + + if (x2 <= x1 || y2 <= y1) + x2 = x1 = y2 = y1 = 0; + + box.x1 = x1; box.x2 = x2; + box.y1 = y1; box.y2 = y2; + + REGION_INIT(pScreen, ®, &box, 1); + + REGION_INTERSECT(pScreen, ®, ®, clipList); + if (generateExposures) + (*pScreen->WindowExposures)(pWin, ®, pBSReg); + else if (pWin->backgroundState != None) + miPaintWindow(pWin, ®, PW_BACKGROUND); + REGION_UNINIT(pScreen, ®); + if (pBSReg) + REGION_DESTROY(pScreen, pBSReg); +} + + +/****************************************************************/ + +/* not used */ +Bool +miOverlayGetPrivateClips( + WindowPtr pWin, + RegionPtr *borderClip, + RegionPtr *clipList +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree) { + *borderClip = &(pTree->borderClip); + *clipList = &(pTree->clipList); + return TRUE; + } + + *borderClip = *clipList = NULL; + + return FALSE; +} + +void +miOverlaySetTransFunction ( + ScreenPtr pScreen, + miOverlayTransFunc transFunc +){ + MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent = transFunc; +} + +Bool +miOverlayCopyUnderlay(ScreenPtr pScreen) +{ + return MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->copyUnderlay; +} + +void +miOverlayComputeCompositeClip(GCPtr pGC, WindowPtr pWin) +{ + ScreenPtr pScreen = pGC->pScreen; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr pregWin; + Bool freeTmpClip, freeCompClip; + + if(!pTree) { + miComputeCompositeClip(pGC, &pWin->drawable); + return; + } + + if (pGC->subWindowMode == IncludeInferiors) { + pregWin = REGION_CREATE(pScreen, NullBox, 1); + freeTmpClip = TRUE; + if (pWin->parent || (screenIsSaved != SCREEN_SAVER_ON) || + !HasSaverWindow (pScreen->myNum)) + { + REGION_INTERSECT(pScreen,pregWin,&pTree->borderClip,&pWin->winSize); + } + } else { + pregWin = &pTree->clipList; + freeTmpClip = FALSE; + } + freeCompClip = pGC->freeCompClip; + if (pGC->clientClipType == CT_NONE) { + if (freeCompClip) + REGION_DESTROY(pScreen, pGC->pCompositeClip); + pGC->pCompositeClip = pregWin; + pGC->freeCompClip = freeTmpClip; + } else { + REGION_TRANSLATE(pScreen, pGC->clientClip, + pWin->drawable.x + pGC->clipOrg.x, + pWin->drawable.y + pGC->clipOrg.y); + + if (freeCompClip) { + REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + if (freeTmpClip) + REGION_DESTROY(pScreen, pregWin); + } else if (freeTmpClip) { + REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip); + pGC->pCompositeClip = pregWin; + } else { + pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); + REGION_INTERSECT(pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + } + pGC->freeCompClip = TRUE; + REGION_TRANSLATE(pScreen, pGC->clientClip, + -(pWin->drawable.x + pGC->clipOrg.x), + -(pWin->drawable.y + pGC->clipOrg.y)); + } +} + +Bool +miOverlayCollectUnderlayRegions( + WindowPtr pWin, + RegionPtr *region +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree) { + *region = &pTree->borderClip; + return FALSE; + } + + *region = REGION_CREATE(pWin->drawable.pScreen, NullBox, 0); + + CollectUnderlayChildrenRegions(pWin, *region); + + return TRUE; +} + + +static miOverlayTreePtr +DoLeaf( + WindowPtr pWin, + miOverlayTreePtr parent, + miOverlayTreePtr prevSib +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + pTree->parent = parent; + pTree->firstChild = NULL; + pTree->lastChild = NULL; + pTree->prevSib = prevSib; + pTree->nextSib = NULL; + + if(prevSib) + prevSib->nextSib = pTree; + + if(!parent->firstChild) + parent->firstChild = parent->lastChild = pTree; + else if(parent->lastChild == prevSib) + parent->lastChild = pTree; + + return pTree; +} + +static void +RebuildTree(WindowPtr pWin) +{ + miOverlayTreePtr parent, prevSib, tChild; + WindowPtr pChild; + + prevSib = tChild = NULL; + + pWin = pWin->parent; + + while(IN_OVERLAY(pWin)) + pWin = pWin->parent; + + parent = MIOVERLAY_GET_WINDOW_TREE(pWin); + + pChild = pWin->firstChild; + parent->firstChild = parent->lastChild = NULL; + + while(1) { + if(IN_UNDERLAY(pChild)) + prevSib = tChild = DoLeaf(pChild, parent, prevSib); + + if(pChild->firstChild) { + if(IN_UNDERLAY(pChild)) { + parent = tChild; + prevSib = NULL; + } + pChild = pChild->firstChild; + continue; + } + + while(!pChild->nextSib) { + pChild = pChild->parent; + if(pChild == pWin) return; + if(IN_UNDERLAY(pChild)) { + prevSib = tChild = MIOVERLAY_GET_WINDOW_TREE(pChild); + parent = tChild->parent; + } + } + + pChild = pChild->nextSib; + } +} + + +static Bool +HasUnderlayChildren(WindowPtr pWin) +{ + WindowPtr pChild; + + if(!(pChild = pWin->firstChild)) + return FALSE; + + while(1) { + if(IN_UNDERLAY(pChild)) + return TRUE; + + if(pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + + while(!pChild->nextSib && (pWin != pChild)) + pChild = pChild->parent; + + if(pChild == pWin) break; + + pChild = pChild->nextSib; + } + + return FALSE; +} + + +static Bool +CollectUnderlayChildrenRegions(WindowPtr pWin, RegionPtr pReg) +{ + WindowPtr pChild; + miOverlayTreePtr pTree; + Bool hasUnderlay; + + if(!(pChild = pWin->firstChild)) + return FALSE; + + hasUnderlay = FALSE; + + while(1) { + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + REGION_APPEND(pScreen, pReg, &pTree->borderClip); + hasUnderlay = TRUE; + } else + if(pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + + while(!pChild->nextSib && (pWin != pChild)) + pChild = pChild->parent; + + if(pChild == pWin) break; + + pChild = pChild->nextSib; + } + + if(hasUnderlay) { + Bool overlap; + REGION_VALIDATE(pScreen, pReg, &overlap); + } + + return hasUnderlay; +} + + +static void +MarkUnderlayWindow(WindowPtr pWin) +{ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree->valdata) return; + pTree->valdata = (miOverlayValDataPtr)xnfalloc(sizeof(miOverlayValDataRec)); + pTree->valdata->oldAbsCorner.x = pWin->drawable.x; + pTree->valdata->oldAbsCorner.y = pWin->drawable.y; + pTree->valdata->borderVisible = NullRegion; +} diff --git a/xorg-server/mi/mipointer.c b/xorg-server/mi/mipointer.c index 1b33f82d5..069a38bd8 100644 --- a/xorg-server/mi/mipointer.c +++ b/xorg-server/mi/mipointer.c @@ -1,592 +1,580 @@ -/* - -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 <dix-config.h> -#endif - -# include <X11/X.h> -# include <X11/Xmd.h> -# include <X11/Xproto.h> -# include "misc.h" -# include "windowstr.h" -# include "pixmapstr.h" -# include "mi.h" -# include "scrnintstr.h" -# include "mipointrst.h" -# include "cursorstr.h" -# include "dixstruct.h" -# include "inputstr.h" - -static int miPointerScreenKeyIndex; -DevPrivateKey miPointerScreenKey = &miPointerScreenKeyIndex; - -#define GetScreenPrivate(s) ((miPointerScreenPtr) \ - dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey)) -#define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s) - -static int miPointerPrivKeyIndex; -static DevPrivateKey miPointerPrivKey = &miPointerPrivKeyIndex; - -#define MIPOINTER(dev) \ - ((!IsMaster(dev) && !dev->u.master) ? \ - (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \ - (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey)) - -static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor); -static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor); -static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor); -static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - BoxPtr pBox); -static void miPointerPointerNonInterestBox(DeviceIntPtr pDev, - ScreenPtr pScreen, BoxPtr pBox); -static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor, BoxPtr pHotBox, - BoxPtr pTopLeftBox); -static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, - Bool generateEvent); -static Bool miPointerCloseScreen(int index, ScreenPtr pScreen); -static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y); -static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); -static void miPointerDeviceCleanup(DeviceIntPtr pDev, - ScreenPtr pScreen); - -static EventList* events; /* for WarpPointer MotionNotifies */ - -Bool -miPointerInitialize (ScreenPtr pScreen, - miPointerSpriteFuncPtr spriteFuncs, - miPointerScreenFuncPtr screenFuncs, - Bool waitForUpdate) -{ - miPointerScreenPtr pScreenPriv; - - pScreenPriv = xalloc (sizeof (miPointerScreenRec)); - if (!pScreenPriv) - return FALSE; - pScreenPriv->spriteFuncs = spriteFuncs; - pScreenPriv->screenFuncs = screenFuncs; - /* - * check for uninitialized methods - */ - if (!screenFuncs->EnqueueEvent) - screenFuncs->EnqueueEvent = mieqEnqueue; - if (!screenFuncs->NewEventScreen) - screenFuncs->NewEventScreen = mieqSwitchScreen; - pScreenPriv->waitForUpdate = waitForUpdate; - pScreenPriv->showTransparent = FALSE; - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = miPointerCloseScreen; - dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv); - /* - * set up screen cursor method table - */ - pScreen->ConstrainCursor = miPointerConstrainCursor; - pScreen->CursorLimits = miPointerCursorLimits; - pScreen->DisplayCursor = miPointerDisplayCursor; - pScreen->RealizeCursor = miPointerRealizeCursor; - pScreen->UnrealizeCursor = miPointerUnrealizeCursor; - pScreen->SetCursorPosition = miPointerSetCursorPosition; - pScreen->RecolorCursor = miRecolorCursor; - pScreen->PointerNonInterestBox = miPointerPointerNonInterestBox; - pScreen->DeviceCursorInitialize = miPointerDeviceInitialize; - pScreen->DeviceCursorCleanup = miPointerDeviceCleanup; - - events = NULL; - return TRUE; -} - -static Bool -miPointerCloseScreen (int index, ScreenPtr pScreen) -{ -#if 0 - miPointerPtr pPointer; - DeviceIntPtr pDev; -#endif - - SetupScreen(pScreen); - -#if 0 - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pPointer = MIPOINTER(pDev); - - if (pScreen == pPointer->pScreen) - pPointer->pScreen = 0; - if (pScreen == pPointer->pSpriteScreen) - pPointer->pSpriteScreen = 0; - } - } - - if (MIPOINTER(inputInfo.pointer)->pScreen == pScreen) - MIPOINTER(inputInfo.pointer)->pScreen = 0; - if (MIPOINTER(inputInfo.pointer)->pSpriteScreen == pScreen) - MIPOINTER(inputInfo.pointer)->pSpriteScreen = 0; -#endif - - pScreen->CloseScreen = pScreenPriv->CloseScreen; - xfree ((pointer) pScreenPriv); - FreeEventList(events, GetMaximumEventsNum()); - events = NULL; - return (*pScreen->CloseScreen) (index, pScreen); -} - -/* - * DIX/DDX interface routines - */ - -static Bool -miPointerRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - SetupScreen(pScreen); - return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor); -} - -static Bool -miPointerUnrealizeCursor (DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor) -{ - SetupScreen(pScreen); - return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, pCursor); -} - -static Bool -miPointerDisplayCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - miPointerPtr pPointer; - - /* return for keyboards */ - if ((IsMaster(pDev) && !DevHasCursor(pDev)) || - (!IsMaster(pDev) && pDev->u.master && !DevHasCursor(pDev->u.master))) - return FALSE; - - pPointer = MIPOINTER(pDev); - - pPointer->pCursor = pCursor; - pPointer->pScreen = pScreen; - miPointerUpdateSprite(pDev); - return TRUE; -} - -static void -miPointerConstrainCursor (DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox) -{ - miPointerPtr pPointer; - - pPointer = MIPOINTER(pDev); - - pPointer->limits = *pBox; - pPointer->confined = PointerConfinedToScreen(pDev); -} - -/*ARGSUSED*/ -static void -miPointerPointerNonInterestBox (DeviceIntPtr pDev, - ScreenPtr pScreen, - BoxPtr pBox) -{ - /* until DIX uses this, this will remain a stub */ -} - -/*ARGSUSED*/ -static void -miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, - BoxPtr pHotBox, BoxPtr pTopLeftBox) -{ - *pTopLeftBox = *pHotBox; -} - -static Bool GenerateEvent; - -static Bool -miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, Bool generateEvent) -{ - SetupScreen (pScreen); - - GenerateEvent = generateEvent; - /* device dependent - must pend signal and call miPointerWarpCursor */ - (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y); - if (!generateEvent) - miPointerUpdateSprite(pDev); - return TRUE; -} - -/* Set up sprite information for the device. - This function will be called once for each device after it is initialized - in the DIX. - */ -static Bool -miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - miPointerPtr pPointer; - SetupScreen (pScreen); - - pPointer = xalloc(sizeof(miPointerRec)); - if (!pPointer) - return FALSE; - - pPointer->pScreen = NULL; - pPointer->pSpriteScreen = NULL; - pPointer->pCursor = NULL; - pPointer->pSpriteCursor = NULL; - pPointer->limits.x1 = 0; - pPointer->limits.x2 = 32767; - pPointer->limits.y1 = 0; - pPointer->limits.y2 = 32767; - pPointer->confined = FALSE; - pPointer->x = 0; - pPointer->y = 0; - - if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen))) - { - xfree(pPointer); - return FALSE; - } - - dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer); - return TRUE; -} - -/* Clean up after device. - This function will be called once before the device is freed in the DIX - */ -static void -miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - SetupScreen(pScreen); - - if (!IsMaster(pDev) && pDev->u.master) - return; - - (*pScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen); - xfree(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey)); - dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL); -} - - -/* Once signals are ignored, the WarpCursor function can call this */ - -void -miPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - miPointerPtr pPointer; - BOOL changedScreen = FALSE; - - SetupScreen (pScreen); - pPointer = MIPOINTER(pDev); - - if (pPointer->pScreen != pScreen) - { - (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, TRUE); - changedScreen = TRUE; - } - - if (GenerateEvent) - { - miPointerMove (pDev, pScreen, x, y); - } - else - { - /* everything from miPointerMove except the event and history */ - - if (!pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) - { - pPointer->devx = x; - pPointer->devy = y; - if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) - (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); - } - pPointer->x = x; - pPointer->y = y; - pPointer->pScreen = pScreen; - } - - /* Don't call USFS if we use Xinerama, otherwise the root window is - * updated to the second screen, and we never receive any events. - * (FDO bug #18668) */ - if (changedScreen -#ifdef PANORAMIX - && noPanoramiXExtension -#endif - ) - UpdateSpriteForScreen (pDev, pScreen) ; -} - -/* - * Pointer/CursorDisplay interface routines - */ - -/* - * miPointerUpdateSprite - * - * Syncronize the sprite with the cursor - called from ProcessInputEvents - */ - -void -miPointerUpdateSprite (DeviceIntPtr pDev) -{ - ScreenPtr pScreen; - miPointerScreenPtr pScreenPriv; - CursorPtr pCursor; - int x, y, devx, devy; - miPointerPtr pPointer; - - if (!pDev || !pDev->coreEvents) - return; - - pPointer = MIPOINTER(pDev); - - if (!pPointer) - return; - - pScreen = pPointer->pScreen; - if (!pScreen) - return; - - x = pPointer->x; - y = pPointer->y; - devx = pPointer->devx; - devy = pPointer->devy; - - pScreenPriv = GetScreenPrivate (pScreen); - /* - * if the cursor has switched screens, disable the sprite - * on the old screen - */ - if (pScreen != pPointer->pSpriteScreen) - { - if (pPointer->pSpriteScreen) - { - miPointerScreenPtr pOldPriv; - - pOldPriv = GetScreenPrivate (pPointer->pSpriteScreen); - if (pPointer->pCursor) - { - (*pOldPriv->spriteFuncs->SetCursor) - (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0); - } - (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, FALSE); - } - (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE); - (*pScreenPriv->spriteFuncs->SetCursor) - (pDev, pScreen, pPointer->pCursor, x, y); - pPointer->devx = x; - pPointer->devy = y; - pPointer->pSpriteCursor = pPointer->pCursor; - pPointer->pSpriteScreen = pScreen; - } - /* - * if the cursor has changed, display the new one - */ - else if (pPointer->pCursor != pPointer->pSpriteCursor) - { - pCursor = pPointer->pCursor; - if (!pCursor || (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)) - pCursor = NullCursor; - (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y); - - pPointer->devx = x; - pPointer->devy = y; - pPointer->pSpriteCursor = pPointer->pCursor; - } - else if (x != devx || y != devy) - { - pPointer->devx = x; - pPointer->devy = y; - if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) - (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); - } -} - -void -miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y) -{ - miPointerScreenPtr pScreenPriv; - ScreenPtr pScreen; - miPointerPtr pPointer; - - pPointer = MIPOINTER(pDev); - - pScreen = screenInfo.screens[screen_no]; - pScreenPriv = GetScreenPrivate (pScreen); - (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE); - NewCurrentScreen (pDev, pScreen, x, y); - - pPointer->limits.x2 = pScreen->width; - pPointer->limits.y2 = pScreen->height; -} - -ScreenPtr -miPointerCurrentScreen (void) -{ - return miPointerGetScreen(inputInfo.pointer); -} - -ScreenPtr -miPointerGetScreen(DeviceIntPtr pDev) -{ - miPointerPtr pPointer = MIPOINTER(pDev); - return (pPointer) ? pPointer->pScreen : NULL; -} - -/* Move the pointer on the current screen, and update the sprite. */ -static void -miPointerMoved (DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y) -{ - miPointerPtr pPointer; - SetupScreen(pScreen); - - pPointer = MIPOINTER(pDev); - - /* Hack: We mustn't call into ->MoveCursor for anything but the - * VCP, as this may cause a non-HW rendered cursor to be rendered during - * SIGIO. This again leads to allocs during SIGIO which leads to SIGABRT. - */ - if ((pDev == inputInfo.pointer || (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer)) - && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) - { - pPointer->devx = x; - pPointer->devy = y; - if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) - (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); - } - - pPointer->x = x; - pPointer->y = y; - pPointer->pScreen = pScreen; -} - -void -miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y) -{ - miPointerScreenPtr pScreenPriv; - ScreenPtr pScreen; - ScreenPtr newScreen; - - miPointerPtr pPointer; - - if (!pDev || !pDev->coreEvents) - return; - - pPointer = MIPOINTER(pDev); - pScreen = pPointer->pScreen; - if (!pScreen) - return; /* called before ready */ - - if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height) - { - pScreenPriv = GetScreenPrivate (pScreen); - if (!pPointer->confined) - { - newScreen = pScreen; - (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, x, y); - if (newScreen != pScreen) - { - pScreen = newScreen; - (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, - FALSE); - pScreenPriv = GetScreenPrivate (pScreen); - /* Smash the confine to the new screen */ - pPointer->limits.x2 = pScreen->width; - pPointer->limits.y2 = pScreen->height; - } - } - } - /* Constrain the sprite to the current limits. */ - if (*x < pPointer->limits.x1) - *x = pPointer->limits.x1; - if (*x >= pPointer->limits.x2) - *x = pPointer->limits.x2 - 1; - if (*y < pPointer->limits.y1) - *y = pPointer->limits.y1; - if (*y >= pPointer->limits.y2) - *y = pPointer->limits.y2 - 1; - - if (pPointer->x == *x && pPointer->y == *y && - pPointer->pScreen == pScreen) - return; - - miPointerMoved(pDev, pScreen, *x, *y); -} - -void -miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) -{ - *x = MIPOINTER(pDev)->x; - *y = MIPOINTER(pDev)->y; -} - -#ifdef XQUARTZ -#include <pthread.h> -void darwinEvents_lock(void); -void darwinEvents_unlock(void); -#endif - -void -miPointerMove (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - int i, nevents; - int valuators[2]; - - miPointerMoved(pDev, pScreen, x, y); - - /* generate motion notify */ - valuators[0] = x; - valuators[1] = y; - - if (!events) - { - events = InitEventList(GetMaximumEventsNum()); - - if (!events) - { - FatalError("Could not allocate event store.\n"); - return; - } - } - - nevents = GetPointerEvents(events, pDev, MotionNotify, 0, POINTER_SCREEN | POINTER_ABSOLUTE, 0, 2, valuators); - - OsBlockSignals(); -#ifdef XQUARTZ - darwinEvents_lock(); -#endif - for (i = 0; i < nevents; i++) - mieqEnqueue(pDev, (InternalEvent*)events[i].event); -#ifdef XQUARTZ - darwinEvents_unlock(); -#endif - OsReleaseSignals(); -} +/* + +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 <dix-config.h> +#endif + +# include <X11/X.h> +# include <X11/Xmd.h> +# include <X11/Xproto.h> +# include "misc.h" +# include "windowstr.h" +# include "pixmapstr.h" +# include "mi.h" +# include "scrnintstr.h" +# include "mipointrst.h" +# include "cursorstr.h" +# include "dixstruct.h" +# include "inputstr.h" + +static int miPointerScreenKeyIndex; +DevPrivateKey miPointerScreenKey = &miPointerScreenKeyIndex; + +#define GetScreenPrivate(s) ((miPointerScreenPtr) \ + dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey)) +#define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s) + +static int miPointerPrivKeyIndex; +static DevPrivateKey miPointerPrivKey = &miPointerPrivKeyIndex; + +#define MIPOINTER(dev) \ + ((!IsMaster(dev) && !dev->u.master) ? \ + (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \ + (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey)) + +static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + BoxPtr pBox); +static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, BoxPtr pHotBox, + BoxPtr pTopLeftBox); +static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, + Bool generateEvent); +static Bool miPointerCloseScreen(int index, ScreenPtr pScreen); +static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y); +static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); +static void miPointerDeviceCleanup(DeviceIntPtr pDev, + ScreenPtr pScreen); + +static EventList* events; /* for WarpPointer MotionNotifies */ + +Bool +miPointerInitialize (ScreenPtr pScreen, + miPointerSpriteFuncPtr spriteFuncs, + miPointerScreenFuncPtr screenFuncs, + Bool waitForUpdate) +{ + miPointerScreenPtr pScreenPriv; + + pScreenPriv = malloc(sizeof (miPointerScreenRec)); + if (!pScreenPriv) + return FALSE; + pScreenPriv->spriteFuncs = spriteFuncs; + pScreenPriv->screenFuncs = screenFuncs; + /* + * check for uninitialized methods + */ + if (!screenFuncs->EnqueueEvent) + screenFuncs->EnqueueEvent = mieqEnqueue; + if (!screenFuncs->NewEventScreen) + screenFuncs->NewEventScreen = mieqSwitchScreen; + pScreenPriv->waitForUpdate = waitForUpdate; + pScreenPriv->showTransparent = FALSE; + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = miPointerCloseScreen; + dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv); + /* + * set up screen cursor method table + */ + pScreen->ConstrainCursor = miPointerConstrainCursor; + pScreen->CursorLimits = miPointerCursorLimits; + pScreen->DisplayCursor = miPointerDisplayCursor; + pScreen->RealizeCursor = miPointerRealizeCursor; + pScreen->UnrealizeCursor = miPointerUnrealizeCursor; + pScreen->SetCursorPosition = miPointerSetCursorPosition; + pScreen->RecolorCursor = miRecolorCursor; + pScreen->DeviceCursorInitialize = miPointerDeviceInitialize; + pScreen->DeviceCursorCleanup = miPointerDeviceCleanup; + + events = NULL; + return TRUE; +} + +static Bool +miPointerCloseScreen (int index, ScreenPtr pScreen) +{ +#if 0 + miPointerPtr pPointer; + DeviceIntPtr pDev; +#endif + + SetupScreen(pScreen); + +#if 0 + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pPointer = MIPOINTER(pDev); + + if (pScreen == pPointer->pScreen) + pPointer->pScreen = 0; + if (pScreen == pPointer->pSpriteScreen) + pPointer->pSpriteScreen = 0; + } + } + + if (MIPOINTER(inputInfo.pointer)->pScreen == pScreen) + MIPOINTER(inputInfo.pointer)->pScreen = 0; + if (MIPOINTER(inputInfo.pointer)->pSpriteScreen == pScreen) + MIPOINTER(inputInfo.pointer)->pSpriteScreen = 0; +#endif + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + free((pointer) pScreenPriv); + FreeEventList(events, GetMaximumEventsNum()); + events = NULL; + return (*pScreen->CloseScreen) (index, pScreen); +} + +/* + * DIX/DDX interface routines + */ + +static Bool +miPointerRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + SetupScreen(pScreen); + return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor); +} + +static Bool +miPointerUnrealizeCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) +{ + SetupScreen(pScreen); + return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, pCursor); +} + +static Bool +miPointerDisplayCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + miPointerPtr pPointer; + + /* return for keyboards */ + if ((IsMaster(pDev) && !DevHasCursor(pDev)) || + (!IsMaster(pDev) && pDev->u.master && !DevHasCursor(pDev->u.master))) + return FALSE; + + pPointer = MIPOINTER(pDev); + + pPointer->pCursor = pCursor; + pPointer->pScreen = pScreen; + miPointerUpdateSprite(pDev); + return TRUE; +} + +static void +miPointerConstrainCursor (DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox) +{ + miPointerPtr pPointer; + + pPointer = MIPOINTER(pDev); + + pPointer->limits = *pBox; + pPointer->confined = PointerConfinedToScreen(pDev); +} + +/*ARGSUSED*/ +static void +miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, + BoxPtr pHotBox, BoxPtr pTopLeftBox) +{ + *pTopLeftBox = *pHotBox; +} + +static Bool GenerateEvent; + +static Bool +miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, Bool generateEvent) +{ + SetupScreen (pScreen); + + GenerateEvent = generateEvent; + /* device dependent - must pend signal and call miPointerWarpCursor */ + (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y); + if (!generateEvent) + miPointerUpdateSprite(pDev); + return TRUE; +} + +/* Set up sprite information for the device. + This function will be called once for each device after it is initialized + in the DIX. + */ +static Bool +miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miPointerPtr pPointer; + SetupScreen (pScreen); + + pPointer = malloc(sizeof(miPointerRec)); + if (!pPointer) + return FALSE; + + pPointer->pScreen = NULL; + pPointer->pSpriteScreen = NULL; + pPointer->pCursor = NULL; + pPointer->pSpriteCursor = NULL; + pPointer->limits.x1 = 0; + pPointer->limits.x2 = 32767; + pPointer->limits.y1 = 0; + pPointer->limits.y2 = 32767; + pPointer->confined = FALSE; + pPointer->x = 0; + pPointer->y = 0; + + if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen))) + { + free(pPointer); + return FALSE; + } + + dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer); + return TRUE; +} + +/* Clean up after device. + This function will be called once before the device is freed in the DIX + */ +static void +miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + SetupScreen(pScreen); + + if (!IsMaster(pDev) && pDev->u.master) + return; + + (*pScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen); + free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey)); + dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL); +} + + +/* Once signals are ignored, the WarpCursor function can call this */ + +void +miPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + miPointerPtr pPointer; + BOOL changedScreen = FALSE; + + SetupScreen (pScreen); + pPointer = MIPOINTER(pDev); + + if (pPointer->pScreen != pScreen) + { + (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, TRUE); + changedScreen = TRUE; + } + + if (GenerateEvent) + { + miPointerMove (pDev, pScreen, x, y); + } + else + { + /* everything from miPointerMove except the event and history */ + + if (!pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) + { + pPointer->devx = x; + pPointer->devy = y; + if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); + } + pPointer->x = x; + pPointer->y = y; + pPointer->pScreen = pScreen; + } + + /* Don't call USFS if we use Xinerama, otherwise the root window is + * updated to the second screen, and we never receive any events. + * (FDO bug #18668) */ + if (changedScreen +#ifdef PANORAMIX + && noPanoramiXExtension +#endif + ) + UpdateSpriteForScreen (pDev, pScreen) ; +} + +/* + * Pointer/CursorDisplay interface routines + */ + +/* + * miPointerUpdateSprite + * + * Syncronize the sprite with the cursor - called from ProcessInputEvents + */ + +void +miPointerUpdateSprite (DeviceIntPtr pDev) +{ + ScreenPtr pScreen; + miPointerScreenPtr pScreenPriv; + CursorPtr pCursor; + int x, y, devx, devy; + miPointerPtr pPointer; + + if (!pDev || !pDev->coreEvents) + return; + + pPointer = MIPOINTER(pDev); + + if (!pPointer) + return; + + pScreen = pPointer->pScreen; + if (!pScreen) + return; + + x = pPointer->x; + y = pPointer->y; + devx = pPointer->devx; + devy = pPointer->devy; + + pScreenPriv = GetScreenPrivate (pScreen); + /* + * if the cursor has switched screens, disable the sprite + * on the old screen + */ + if (pScreen != pPointer->pSpriteScreen) + { + if (pPointer->pSpriteScreen) + { + miPointerScreenPtr pOldPriv; + + pOldPriv = GetScreenPrivate (pPointer->pSpriteScreen); + if (pPointer->pCursor) + { + (*pOldPriv->spriteFuncs->SetCursor) + (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0); + } + (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, FALSE); + } + (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE); + (*pScreenPriv->spriteFuncs->SetCursor) + (pDev, pScreen, pPointer->pCursor, x, y); + pPointer->devx = x; + pPointer->devy = y; + pPointer->pSpriteCursor = pPointer->pCursor; + pPointer->pSpriteScreen = pScreen; + } + /* + * if the cursor has changed, display the new one + */ + else if (pPointer->pCursor != pPointer->pSpriteCursor) + { + pCursor = pPointer->pCursor; + if (!pCursor || (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)) + pCursor = NullCursor; + (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y); + + pPointer->devx = x; + pPointer->devy = y; + pPointer->pSpriteCursor = pPointer->pCursor; + } + else if (x != devx || y != devy) + { + pPointer->devx = x; + pPointer->devy = y; + if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); + } +} + +void +miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y) +{ + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; + miPointerPtr pPointer; + + pPointer = MIPOINTER(pDev); + + pScreen = screenInfo.screens[screen_no]; + pScreenPriv = GetScreenPrivate (pScreen); + (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE); + NewCurrentScreen (pDev, pScreen, x, y); + + pPointer->limits.x2 = pScreen->width; + pPointer->limits.y2 = pScreen->height; +} + +ScreenPtr +miPointerCurrentScreen (void) +{ + return miPointerGetScreen(inputInfo.pointer); +} + +ScreenPtr +miPointerGetScreen(DeviceIntPtr pDev) +{ + miPointerPtr pPointer = MIPOINTER(pDev); + return (pPointer) ? pPointer->pScreen : NULL; +} + +/* Move the pointer on the current screen, and update the sprite. */ +static void +miPointerMoved (DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y) +{ + miPointerPtr pPointer; + SetupScreen(pScreen); + + pPointer = MIPOINTER(pDev); + + /* Hack: We mustn't call into ->MoveCursor for anything but the + * VCP, as this may cause a non-HW rendered cursor to be rendered during + * SIGIO. This again leads to allocs during SIGIO which leads to SIGABRT. + */ + if ((pDev == inputInfo.pointer || (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer)) + && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) + { + pPointer->devx = x; + pPointer->devy = y; + if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); + } + + pPointer->x = x; + pPointer->y = y; + pPointer->pScreen = pScreen; +} + +void +miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y) +{ + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; + ScreenPtr newScreen; + + miPointerPtr pPointer; + + if (!pDev || !pDev->coreEvents) + return; + + pPointer = MIPOINTER(pDev); + pScreen = pPointer->pScreen; + if (!pScreen) + return; /* called before ready */ + + if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height) + { + pScreenPriv = GetScreenPrivate (pScreen); + if (!pPointer->confined) + { + newScreen = pScreen; + (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, x, y); + if (newScreen != pScreen) + { + pScreen = newScreen; + (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, + FALSE); + pScreenPriv = GetScreenPrivate (pScreen); + /* Smash the confine to the new screen */ + pPointer->limits.x2 = pScreen->width; + pPointer->limits.y2 = pScreen->height; + } + } + } + /* Constrain the sprite to the current limits. */ + if (*x < pPointer->limits.x1) + *x = pPointer->limits.x1; + if (*x >= pPointer->limits.x2) + *x = pPointer->limits.x2 - 1; + if (*y < pPointer->limits.y1) + *y = pPointer->limits.y1; + if (*y >= pPointer->limits.y2) + *y = pPointer->limits.y2 - 1; + + if (pPointer->x == *x && pPointer->y == *y && + pPointer->pScreen == pScreen) + return; + + miPointerMoved(pDev, pScreen, *x, *y); +} + +void +miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) +{ + *x = MIPOINTER(pDev)->x; + *y = MIPOINTER(pDev)->y; +} + +#ifdef XQUARTZ +#include <pthread.h> +void darwinEvents_lock(void); +void darwinEvents_unlock(void); +#endif + +void +miPointerMove (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + int i, nevents; + int valuators[2]; + + miPointerMoved(pDev, pScreen, x, y); + + /* generate motion notify */ + valuators[0] = x; + valuators[1] = y; + + if (!events) + { + events = InitEventList(GetMaximumEventsNum()); + + if (!events) + { + FatalError("Could not allocate event store.\n"); + return; + } + } + + nevents = GetPointerEvents(events, pDev, MotionNotify, 0, POINTER_SCREEN | POINTER_ABSOLUTE, 0, 2, valuators); + + OsBlockSignals(); +#ifdef XQUARTZ + darwinEvents_lock(); +#endif + for (i = 0; i < nevents; i++) + mieqEnqueue(pDev, (InternalEvent*)events[i].event); +#ifdef XQUARTZ + darwinEvents_unlock(); +#endif + OsReleaseSignals(); +} diff --git a/xorg-server/mi/mipolycon.c b/xorg-server/mi/mipolycon.c index 79384881d..170b2aa1a 100644 --- a/xorg-server/mi/mipolycon.c +++ b/xorg-server/mi/mipolycon.c @@ -1,247 +1,247 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include "gcstruct.h" -#include "pixmap.h" -#include "mi.h" -#include "miscanfill.h" - -static int getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty); - -/* - * convexpoly.c - * - * Written by Brian Kelleher; Dec. 1985. - * - * Fill a convex polygon. If the given polygon - * is not convex, then the result is undefined. - * The algorithm is to order the edges from smallest - * y to largest by partitioning the array into a left - * edge list and a right edge list. The algorithm used - * to traverse each edge is an extension of Bresenham's - * line algorithm with y as the major axis. - * For a derivation of the algorithm, see the author of - * this code. - */ -Bool -miFillConvexPoly( - DrawablePtr dst, - GCPtr pgc, - int count, /* number of points */ - DDXPointPtr ptsIn /* the points */ - ) -{ - int xl = 0, xr = 0; /* x vals of left and right edges */ - int dl = 0, dr = 0; /* decision variables */ - int ml = 0, m1l = 0;/* left edge slope and slope+1 */ - int mr = 0, m1r = 0; /* right edge slope and slope+1 */ - int incr1l = 0, incr2l = 0; /* left edge error increments */ - int incr1r = 0, incr2r = 0; /* right edge error increments */ - int dy; /* delta y */ - int y; /* current scanline */ - int left, right; /* indices to first endpoints */ - int i; /* loop counter */ - int nextleft, nextright; /* indices to second endpoints */ - DDXPointPtr ptsOut, FirstPoint; /* output buffer */ - int *width, *FirstWidth; /* output buffer */ - int imin; /* index of smallest vertex (in y) */ - int ymin; /* y-extents of polygon */ - int ymax; - - /* - * find leftx, bottomy, rightx, topy, and the index - * of bottomy. Also translate the points. - */ - imin = getPolyYBounds(ptsIn, count, &ymin, &ymax); - - dy = ymax - ymin + 1; - if ((count < 3) || (dy < 0)) - return(TRUE); - ptsOut = FirstPoint = xalloc(sizeof(DDXPointRec)*dy); - width = FirstWidth = xalloc(sizeof(int) * dy); - if(!FirstPoint || !FirstWidth) - { - if (FirstWidth) xfree(FirstWidth); - if (FirstPoint) xfree(FirstPoint); - return(FALSE); - } - - nextleft = nextright = imin; - y = ptsIn[nextleft].y; - - /* - * loop through all edges of the polygon - */ - do { - /* - * add a left edge if we need to - */ - if (ptsIn[nextleft].y == y) { - left = nextleft; - - /* - * find the next edge, considering the end - * conditions of the array. - */ - nextleft++; - if (nextleft >= count) - nextleft = 0; - - /* - * now compute all of the random information - * needed to run the iterative algorithm. - */ - BRESINITPGON(ptsIn[nextleft].y-ptsIn[left].y, - ptsIn[left].x,ptsIn[nextleft].x, - xl, dl, ml, m1l, incr1l, incr2l); - } - - /* - * add a right edge if we need to - */ - if (ptsIn[nextright].y == y) { - right = nextright; - - /* - * find the next edge, considering the end - * conditions of the array. - */ - nextright--; - if (nextright < 0) - nextright = count-1; - - /* - * now compute all of the random information - * needed to run the iterative algorithm. - */ - BRESINITPGON(ptsIn[nextright].y-ptsIn[right].y, - ptsIn[right].x,ptsIn[nextright].x, - xr, dr, mr, m1r, incr1r, incr2r); - } - - /* - * generate scans to fill while we still have - * a right edge as well as a left edge. - */ - i = min(ptsIn[nextleft].y, ptsIn[nextright].y) - y; - /* in case we're called with non-convex polygon */ - if(i < 0) - { - xfree(FirstWidth); - xfree(FirstPoint); - return(TRUE); - } - while (i-- > 0) - { - ptsOut->y = y; - - /* - * reverse the edges if necessary - */ - if (xl < xr) - { - *(width++) = xr - xl; - (ptsOut++)->x = xl; - } - else - { - *(width++) = xl - xr; - (ptsOut++)->x = xr; - } - y++; - - /* increment down the edges */ - BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l); - BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r); - } - } while (y != ymax); - - /* - * Finally, fill the <remaining> spans - */ - (*pgc->ops->FillSpans)(dst, pgc, - ptsOut-FirstPoint,FirstPoint,FirstWidth, - 1); - xfree(FirstWidth); - xfree(FirstPoint); - return(TRUE); -} - - -/* - * Find the index of the point with the smallest y. - */ -static int -getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty) -{ - DDXPointPtr ptMin; - int ymin, ymax; - DDXPointPtr ptsStart = pts; - - ptMin = pts; - ymin = ymax = (pts++)->y; - - while (--n > 0) { - if (pts->y < ymin) - { - ptMin = pts; - ymin = pts->y; - } - if(pts->y > ymax) - ymax = pts->y; - - pts++; - } - - *by = ymin; - *ty = ymax; - return(ptMin-ptsStart); -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include "gcstruct.h" +#include "pixmap.h" +#include "mi.h" +#include "miscanfill.h" + +static int getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty); + +/* + * convexpoly.c + * + * Written by Brian Kelleher; Dec. 1985. + * + * Fill a convex polygon. If the given polygon + * is not convex, then the result is undefined. + * The algorithm is to order the edges from smallest + * y to largest by partitioning the array into a left + * edge list and a right edge list. The algorithm used + * to traverse each edge is an extension of Bresenham's + * line algorithm with y as the major axis. + * For a derivation of the algorithm, see the author of + * this code. + */ +Bool +miFillConvexPoly( + DrawablePtr dst, + GCPtr pgc, + int count, /* number of points */ + DDXPointPtr ptsIn /* the points */ + ) +{ + int xl = 0, xr = 0; /* x vals of left and right edges */ + int dl = 0, dr = 0; /* decision variables */ + int ml = 0, m1l = 0;/* left edge slope and slope+1 */ + int mr = 0, m1r = 0; /* right edge slope and slope+1 */ + int incr1l = 0, incr2l = 0; /* left edge error increments */ + int incr1r = 0, incr2r = 0; /* right edge error increments */ + int dy; /* delta y */ + int y; /* current scanline */ + int left, right; /* indices to first endpoints */ + int i; /* loop counter */ + int nextleft, nextright; /* indices to second endpoints */ + DDXPointPtr ptsOut, FirstPoint; /* output buffer */ + int *width, *FirstWidth; /* output buffer */ + int imin; /* index of smallest vertex (in y) */ + int ymin; /* y-extents of polygon */ + int ymax; + + /* + * find leftx, bottomy, rightx, topy, and the index + * of bottomy. Also translate the points. + */ + imin = getPolyYBounds(ptsIn, count, &ymin, &ymax); + + dy = ymax - ymin + 1; + if ((count < 3) || (dy < 0)) + return(TRUE); + ptsOut = FirstPoint = malloc(sizeof(DDXPointRec)*dy); + width = FirstWidth = malloc(sizeof(int) * dy); + if(!FirstPoint || !FirstWidth) + { + if (FirstWidth) free(FirstWidth); + if (FirstPoint) free(FirstPoint); + return(FALSE); + } + + nextleft = nextright = imin; + y = ptsIn[nextleft].y; + + /* + * loop through all edges of the polygon + */ + do { + /* + * add a left edge if we need to + */ + if (ptsIn[nextleft].y == y) { + left = nextleft; + + /* + * find the next edge, considering the end + * conditions of the array. + */ + nextleft++; + if (nextleft >= count) + nextleft = 0; + + /* + * now compute all of the random information + * needed to run the iterative algorithm. + */ + BRESINITPGON(ptsIn[nextleft].y-ptsIn[left].y, + ptsIn[left].x,ptsIn[nextleft].x, + xl, dl, ml, m1l, incr1l, incr2l); + } + + /* + * add a right edge if we need to + */ + if (ptsIn[nextright].y == y) { + right = nextright; + + /* + * find the next edge, considering the end + * conditions of the array. + */ + nextright--; + if (nextright < 0) + nextright = count-1; + + /* + * now compute all of the random information + * needed to run the iterative algorithm. + */ + BRESINITPGON(ptsIn[nextright].y-ptsIn[right].y, + ptsIn[right].x,ptsIn[nextright].x, + xr, dr, mr, m1r, incr1r, incr2r); + } + + /* + * generate scans to fill while we still have + * a right edge as well as a left edge. + */ + i = min(ptsIn[nextleft].y, ptsIn[nextright].y) - y; + /* in case we're called with non-convex polygon */ + if(i < 0) + { + free(FirstWidth); + free(FirstPoint); + return(TRUE); + } + while (i-- > 0) + { + ptsOut->y = y; + + /* + * reverse the edges if necessary + */ + if (xl < xr) + { + *(width++) = xr - xl; + (ptsOut++)->x = xl; + } + else + { + *(width++) = xl - xr; + (ptsOut++)->x = xr; + } + y++; + + /* increment down the edges */ + BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l); + BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r); + } + } while (y != ymax); + + /* + * Finally, fill the <remaining> spans + */ + (*pgc->ops->FillSpans)(dst, pgc, + ptsOut-FirstPoint,FirstPoint,FirstWidth, + 1); + free(FirstWidth); + free(FirstPoint); + return(TRUE); +} + + +/* + * Find the index of the point with the smallest y. + */ +static int +getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty) +{ + DDXPointPtr ptMin; + int ymin, ymax; + DDXPointPtr ptsStart = pts; + + ptMin = pts; + ymin = ymax = (pts++)->y; + + while (--n > 0) { + if (pts->y < ymin) + { + ptMin = pts; + ymin = pts->y; + } + if(pts->y > ymax) + ymax = pts->y; + + pts++; + } + + *by = ymin; + *ty = ymax; + return(ptMin-ptsStart); +} diff --git a/xorg-server/mi/mipolygen.c b/xorg-server/mi/mipolygen.c index 4744583c3..3dbf68960 100644 --- a/xorg-server/mi/mipolygen.c +++ b/xorg-server/mi/mipolygen.c @@ -1,230 +1,230 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include "gcstruct.h" -#include "miscanfill.h" -#include "mipoly.h" -#include "pixmap.h" -#include "mi.h" - -/* - * - * Written by Brian Kelleher; Oct. 1985 - * - * Routine to fill a polygon. Two fill rules are - * supported: frWINDING and frEVENODD. - * - * See fillpoly.h for a complete description of the algorithm. - */ - -Bool -miFillGeneralPoly( - DrawablePtr dst, - GCPtr pgc, - int count, /* number of points */ - DDXPointPtr ptsIn /* the points */ - ) -{ - EdgeTableEntry *pAET; /* the Active Edge Table */ - int y; /* the current scanline */ - int nPts = 0; /* number of pts in buffer */ - EdgeTableEntry *pWETE; /* Winding Edge Table */ - ScanLineList *pSLL; /* Current ScanLineList */ - DDXPointPtr ptsOut; /* ptr to output buffers */ - int *width; - DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */ - int FirstWidth[NUMPTSTOBUFFER]; - EdgeTableEntry *pPrevAET; /* previous AET entry */ - EdgeTable ET; /* Edge Table header node */ - EdgeTableEntry AET; /* Active ET header node */ - EdgeTableEntry *pETEs; /* Edge Table Entries buff */ - ScanLineListBlock SLLBlock; /* header for ScanLineList */ - int fixWAET = 0; - - if (count < 3) - return(TRUE); - - if(!(pETEs = xalloc(sizeof(EdgeTableEntry) * count))) - return(FALSE); - ptsOut = FirstPoint; - width = FirstWidth; - if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) - { - xfree(pETEs); - return(FALSE); - } - pSLL = ET.scanlines.next; - - if (pgc->fillRule == EvenOddRule) - { - /* - * for each scanline - */ - for (y = ET.ymin; y < ET.ymax; y++) - { - /* - * Add a new edge to the active edge table when we - * get to the next edge. - */ - if (pSLL && y == pSLL->scanline) - { - miloadAET(&AET, pSLL->edgelist); - pSLL = pSLL->next; - } - pPrevAET = &AET; - pAET = AET.next; - - /* - * for each active edge - */ - while (pAET) - { - ptsOut->x = pAET->bres.minor; - ptsOut++->y = y; - *width++ = pAET->next->bres.minor - pAET->bres.minor; - nPts++; - - /* - * send out the buffer when its full - */ - if (nPts == NUMPTSTOBUFFER) - { - (*pgc->ops->FillSpans)(dst, pgc, - nPts, FirstPoint, FirstWidth, - 1); - ptsOut = FirstPoint; - width = FirstWidth; - nPts = 0; - } - EVALUATEEDGEEVENODD(pAET, pPrevAET, y) - EVALUATEEDGEEVENODD(pAET, pPrevAET, y); - } - miInsertionSort(&AET); - } - } - else /* default to WindingNumber */ - { - /* - * for each scanline - */ - for (y = ET.ymin; y < ET.ymax; y++) - { - /* - * Add a new edge to the active edge table when we - * get to the next edge. - */ - if (pSLL && y == pSLL->scanline) - { - miloadAET(&AET, pSLL->edgelist); - micomputeWAET(&AET); - pSLL = pSLL->next; - } - pPrevAET = &AET; - pAET = AET.next; - pWETE = pAET; - - /* - * for each active edge - */ - while (pAET) - { - /* - * if the next edge in the active edge table is - * also the next edge in the winding active edge - * table. - */ - if (pWETE == pAET) - { - ptsOut->x = pAET->bres.minor; - ptsOut++->y = y; - *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor; - nPts++; - - /* - * send out the buffer - */ - if (nPts == NUMPTSTOBUFFER) - { - (*pgc->ops->FillSpans)(dst, pgc, nPts, FirstPoint, - FirstWidth, 1); - ptsOut = FirstPoint; - width = FirstWidth; - nPts = 0; - } - - pWETE = pWETE->nextWETE; - while (pWETE != pAET) - EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); - pWETE = pWETE->nextWETE; - } - EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); - } - - /* - * reevaluate the Winding active edge table if we - * just had to resort it or if we just exited an edge. - */ - if (miInsertionSort(&AET) || fixWAET) - { - micomputeWAET(&AET); - fixWAET = 0; - } - } - } - - /* - * Get any spans that we missed by buffering - */ - (*pgc->ops->FillSpans)(dst, pgc, nPts, FirstPoint, FirstWidth, 1); - xfree(pETEs); - miFreeStorage(SLLBlock.next); - return(TRUE); -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <X11/X.h> +#include "gcstruct.h" +#include "miscanfill.h" +#include "mipoly.h" +#include "pixmap.h" +#include "mi.h" + +/* + * + * Written by Brian Kelleher; Oct. 1985 + * + * Routine to fill a polygon. Two fill rules are + * supported: frWINDING and frEVENODD. + * + * See fillpoly.h for a complete description of the algorithm. + */ + +Bool +miFillGeneralPoly( + DrawablePtr dst, + GCPtr pgc, + int count, /* number of points */ + DDXPointPtr ptsIn /* the points */ + ) +{ + EdgeTableEntry *pAET; /* the Active Edge Table */ + int y; /* the current scanline */ + int nPts = 0; /* number of pts in buffer */ + EdgeTableEntry *pWETE; /* Winding Edge Table */ + ScanLineList *pSLL; /* Current ScanLineList */ + DDXPointPtr ptsOut; /* ptr to output buffers */ + int *width; + DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */ + int FirstWidth[NUMPTSTOBUFFER]; + EdgeTableEntry *pPrevAET; /* previous AET entry */ + EdgeTable ET; /* Edge Table header node */ + EdgeTableEntry AET; /* Active ET header node */ + EdgeTableEntry *pETEs; /* Edge Table Entries buff */ + ScanLineListBlock SLLBlock; /* header for ScanLineList */ + int fixWAET = 0; + + if (count < 3) + return(TRUE); + + if(!(pETEs = malloc(sizeof(EdgeTableEntry) * count))) + return(FALSE); + ptsOut = FirstPoint; + width = FirstWidth; + if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) + { + free(pETEs); + return(FALSE); + } + pSLL = ET.scanlines.next; + + if (pgc->fillRule == EvenOddRule) + { + /* + * for each scanline + */ + for (y = ET.ymin; y < ET.ymax; y++) + { + /* + * Add a new edge to the active edge table when we + * get to the next edge. + */ + if (pSLL && y == pSLL->scanline) + { + miloadAET(&AET, pSLL->edgelist); + pSLL = pSLL->next; + } + pPrevAET = &AET; + pAET = AET.next; + + /* + * for each active edge + */ + while (pAET) + { + ptsOut->x = pAET->bres.minor; + ptsOut++->y = y; + *width++ = pAET->next->bres.minor - pAET->bres.minor; + nPts++; + + /* + * send out the buffer when its full + */ + if (nPts == NUMPTSTOBUFFER) + { + (*pgc->ops->FillSpans)(dst, pgc, + nPts, FirstPoint, FirstWidth, + 1); + ptsOut = FirstPoint; + width = FirstWidth; + nPts = 0; + } + EVALUATEEDGEEVENODD(pAET, pPrevAET, y) + EVALUATEEDGEEVENODD(pAET, pPrevAET, y); + } + miInsertionSort(&AET); + } + } + else /* default to WindingNumber */ + { + /* + * for each scanline + */ + for (y = ET.ymin; y < ET.ymax; y++) + { + /* + * Add a new edge to the active edge table when we + * get to the next edge. + */ + if (pSLL && y == pSLL->scanline) + { + miloadAET(&AET, pSLL->edgelist); + micomputeWAET(&AET); + pSLL = pSLL->next; + } + pPrevAET = &AET; + pAET = AET.next; + pWETE = pAET; + + /* + * for each active edge + */ + while (pAET) + { + /* + * if the next edge in the active edge table is + * also the next edge in the winding active edge + * table. + */ + if (pWETE == pAET) + { + ptsOut->x = pAET->bres.minor; + ptsOut++->y = y; + *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor; + nPts++; + + /* + * send out the buffer + */ + if (nPts == NUMPTSTOBUFFER) + { + (*pgc->ops->FillSpans)(dst, pgc, nPts, FirstPoint, + FirstWidth, 1); + ptsOut = FirstPoint; + width = FirstWidth; + nPts = 0; + } + + pWETE = pWETE->nextWETE; + while (pWETE != pAET) + EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); + pWETE = pWETE->nextWETE; + } + EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); + } + + /* + * reevaluate the Winding active edge table if we + * just had to resort it or if we just exited an edge. + */ + if (miInsertionSort(&AET) || fixWAET) + { + micomputeWAET(&AET); + fixWAET = 0; + } + } + } + + /* + * Get any spans that we missed by buffering + */ + (*pgc->ops->FillSpans)(dst, pgc, nPts, FirstPoint, FirstWidth, 1); + free(pETEs); + miFreeStorage(SLLBlock.next); + return(TRUE); +} diff --git a/xorg-server/mi/mipolypnt.c b/xorg-server/mi/mipolypnt.c index 12771ee4e..29d3e29e1 100644 --- a/xorg-server/mi/mipolypnt.c +++ b/xorg-server/mi/mipolypnt.c @@ -1,125 +1,125 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xprotostr.h> -#include "pixmapstr.h" -#include "gcstruct.h" -#include "windowstr.h" -#include "mi.h" - -void -miPolyPoint( - DrawablePtr pDrawable, - GCPtr pGC, - int mode, /* Origin or Previous */ - int npt, - xPoint *pptInit - ) -{ - - int xorg; - int yorg; - int nptTmp; - XID fsOld, fsNew; - int *pwidthInit, *pwidth; - int i; - xPoint *ppt; - - if(!(pwidthInit = xalloc(npt * sizeof(int)))) - return; - - /* make pointlist origin relative */ - if (mode == CoordModePrevious) - { - ppt = pptInit; - nptTmp = npt; - nptTmp--; - while(nptTmp--) - { - ppt++; - ppt->x += (ppt-1)->x; - ppt->y += (ppt-1)->y; - } - } - - if(pGC->miTranslate) - { - ppt = pptInit; - nptTmp = npt; - xorg = pDrawable->x; - yorg = pDrawable->y; - while(nptTmp--) - { - ppt->x += xorg; - ppt++->y += yorg; - } - } - - fsOld = pGC->fillStyle; - fsNew = FillSolid; - if(pGC->fillStyle != FillSolid) - { - DoChangeGC(pGC, GCFillStyle, &fsNew, 0); - ValidateGC(pDrawable, pGC); - } - pwidth = pwidthInit; - for(i = 0; i < npt; i++) - *pwidth++ = 1; - (*pGC->ops->FillSpans)(pDrawable, pGC, npt, pptInit, pwidthInit, FALSE); - - if(fsOld != FillSolid) - { - DoChangeGC(pGC, GCFillStyle, &fsOld, 0); - ValidateGC(pDrawable, pGC); - } - xfree(pwidthInit); -} - +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "pixmapstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "mi.h" + +void +miPolyPoint( + DrawablePtr pDrawable, + GCPtr pGC, + int mode, /* Origin or Previous */ + int npt, + xPoint *pptInit + ) +{ + + int xorg; + int yorg; + int nptTmp; + ChangeGCVal fsOld, fsNew; + int *pwidthInit, *pwidth; + int i; + xPoint *ppt; + + if(!(pwidthInit = malloc(npt * sizeof(int)))) + return; + + /* make pointlist origin relative */ + if (mode == CoordModePrevious) + { + ppt = pptInit; + nptTmp = npt; + nptTmp--; + while(nptTmp--) + { + ppt++; + ppt->x += (ppt-1)->x; + ppt->y += (ppt-1)->y; + } + } + + if(pGC->miTranslate) + { + ppt = pptInit; + nptTmp = npt; + xorg = pDrawable->x; + yorg = pDrawable->y; + while(nptTmp--) + { + ppt->x += xorg; + ppt++->y += yorg; + } + } + + fsOld.val = pGC->fillStyle; + fsNew.val = FillSolid; + if(pGC->fillStyle != FillSolid) + { + ChangeGC(NullClient, pGC, GCFillStyle, &fsNew); + ValidateGC(pDrawable, pGC); + } + pwidth = pwidthInit; + for(i = 0; i < npt; i++) + *pwidth++ = 1; + (*pGC->ops->FillSpans)(pDrawable, pGC, npt, pptInit, pwidthInit, FALSE); + + if(fsOld.val != FillSolid) + { + ChangeGC(NullClient, pGC, GCFillStyle, &fsOld); + ValidateGC(pDrawable, pGC); + } + free(pwidthInit); +} + diff --git a/xorg-server/mi/mipolyrect.c b/xorg-server/mi/mipolyrect.c index 033c7a7c8..8b8810793 100644 --- a/xorg-server/mi/mipolyrect.c +++ b/xorg-server/mi/mipolyrect.c @@ -1,187 +1,187 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xprotostr.h> -#include "regionstr.h" -#include "gcstruct.h" -#include "pixmap.h" -#include "mi.h" - -void -miPolyRectangle(DrawablePtr pDraw, GCPtr pGC, int nrects, xRectangle *pRects) -{ - int i; - xRectangle *pR = pRects; - DDXPointRec rect[5]; - int bound_tmp; - -#define MINBOUND(dst,eqn) bound_tmp = eqn; \ - if (bound_tmp < -32768) \ - bound_tmp = -32768; \ - dst = bound_tmp; - -#define MAXBOUND(dst,eqn) bound_tmp = eqn; \ - if (bound_tmp > 32767) \ - bound_tmp = 32767; \ - dst = bound_tmp; - -#define MAXUBOUND(dst,eqn) bound_tmp = eqn; \ - if (bound_tmp > 65535) \ - bound_tmp = 65535; \ - dst = bound_tmp; - - if (pGC->lineStyle == LineSolid && pGC->joinStyle == JoinMiter && - pGC->lineWidth != 0) - { - xRectangle *tmp, *t; - int ntmp; - int offset1, offset2, offset3; - int x, y, width, height; - - ntmp = (nrects << 2); - offset2 = pGC->lineWidth; - offset1 = offset2 >> 1; - offset3 = offset2 - offset1; - tmp = xalloc(ntmp * sizeof (xRectangle)); - if (!tmp) - return; - t = tmp; - for (i = 0; i < nrects; i++) - { - x = pR->x; - y = pR->y; - width = pR->width; - height = pR->height; - pR++; - if (width == 0 && height == 0) - { - rect[0].x = x; - rect[0].y = y; - rect[1].x = x; - rect[1].y = y; - (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 2, rect); - } - else if (height < offset2 || width < offset1) - { - if (height == 0) - { - t->x = x; - t->width = width; - } - else - { - MINBOUND (t->x, x - offset1) - MAXUBOUND (t->width, width + offset2) - } - if (width == 0) - { - t->y = y; - t->height = height; - } - else - { - MINBOUND (t->y, y - offset1) - MAXUBOUND (t->height, height + offset2) - } - t++; - } - else - { - MINBOUND(t->x, x - offset1) - MINBOUND(t->y, y - offset1) - MAXUBOUND(t->width, width + offset2) - t->height = offset2; - t++; - MINBOUND(t->x, x - offset1) - MAXBOUND(t->y, y + offset3); - t->width = offset2; - t->height = height - offset2; - t++; - MAXBOUND(t->x, x + width - offset1); - MAXBOUND(t->y, y + offset3) - t->width = offset2; - t->height = height - offset2; - t++; - MINBOUND(t->x, x - offset1) - MAXBOUND(t->y, y + height - offset1) - MAXUBOUND(t->width, width + offset2) - t->height = offset2; - t++; - } - } - (*pGC->ops->PolyFillRect) (pDraw, pGC, t - tmp, tmp); - xfree ((pointer) tmp); - } - else - { - - for (i=0; i<nrects; i++) - { - rect[0].x = pR->x; - rect[0].y = pR->y; - - MAXBOUND(rect[1].x, pR->x + (int) pR->width) - rect[1].y = rect[0].y; - - rect[2].x = rect[1].x; - MAXBOUND(rect[2].y, pR->y + (int) pR->height); - - rect[3].x = rect[0].x; - rect[3].y = rect[2].y; - - rect[4].x = rect[0].x; - rect[4].y = rect[0].y; - - (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 5, rect); - pR++; - } - } -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "regionstr.h" +#include "gcstruct.h" +#include "pixmap.h" +#include "mi.h" + +void +miPolyRectangle(DrawablePtr pDraw, GCPtr pGC, int nrects, xRectangle *pRects) +{ + int i; + xRectangle *pR = pRects; + DDXPointRec rect[5]; + int bound_tmp; + +#define MINBOUND(dst,eqn) bound_tmp = eqn; \ + if (bound_tmp < -32768) \ + bound_tmp = -32768; \ + dst = bound_tmp; + +#define MAXBOUND(dst,eqn) bound_tmp = eqn; \ + if (bound_tmp > 32767) \ + bound_tmp = 32767; \ + dst = bound_tmp; + +#define MAXUBOUND(dst,eqn) bound_tmp = eqn; \ + if (bound_tmp > 65535) \ + bound_tmp = 65535; \ + dst = bound_tmp; + + if (pGC->lineStyle == LineSolid && pGC->joinStyle == JoinMiter && + pGC->lineWidth != 0) + { + xRectangle *tmp, *t; + int ntmp; + int offset1, offset2, offset3; + int x, y, width, height; + + ntmp = (nrects << 2); + offset2 = pGC->lineWidth; + offset1 = offset2 >> 1; + offset3 = offset2 - offset1; + tmp = malloc(ntmp * sizeof (xRectangle)); + if (!tmp) + return; + t = tmp; + for (i = 0; i < nrects; i++) + { + x = pR->x; + y = pR->y; + width = pR->width; + height = pR->height; + pR++; + if (width == 0 && height == 0) + { + rect[0].x = x; + rect[0].y = y; + rect[1].x = x; + rect[1].y = y; + (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 2, rect); + } + else if (height < offset2 || width < offset1) + { + if (height == 0) + { + t->x = x; + t->width = width; + } + else + { + MINBOUND (t->x, x - offset1) + MAXUBOUND (t->width, width + offset2) + } + if (width == 0) + { + t->y = y; + t->height = height; + } + else + { + MINBOUND (t->y, y - offset1) + MAXUBOUND (t->height, height + offset2) + } + t++; + } + else + { + MINBOUND(t->x, x - offset1) + MINBOUND(t->y, y - offset1) + MAXUBOUND(t->width, width + offset2) + t->height = offset2; + t++; + MINBOUND(t->x, x - offset1) + MAXBOUND(t->y, y + offset3); + t->width = offset2; + t->height = height - offset2; + t++; + MAXBOUND(t->x, x + width - offset1); + MAXBOUND(t->y, y + offset3) + t->width = offset2; + t->height = height - offset2; + t++; + MINBOUND(t->x, x - offset1) + MAXBOUND(t->y, y + height - offset1) + MAXUBOUND(t->width, width + offset2) + t->height = offset2; + t++; + } + } + (*pGC->ops->PolyFillRect) (pDraw, pGC, t - tmp, tmp); + free((pointer) tmp); + } + else + { + + for (i=0; i<nrects; i++) + { + rect[0].x = pR->x; + rect[0].y = pR->y; + + MAXBOUND(rect[1].x, pR->x + (int) pR->width) + rect[1].y = rect[0].y; + + rect[2].x = rect[1].x; + MAXBOUND(rect[2].y, pR->y + (int) pR->height); + + rect[3].x = rect[0].x; + rect[3].y = rect[2].y; + + rect[4].x = rect[0].x; + rect[4].y = rect[0].y; + + (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 5, rect); + pR++; + } + } +} diff --git a/xorg-server/mi/mipolyutil.c b/xorg-server/mi/mipolyutil.c index 15561b73d..fe0d9e5bf 100644 --- a/xorg-server/mi/mipolyutil.c +++ b/xorg-server/mi/mipolyutil.c @@ -1,385 +1,385 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include "regionstr.h" -#include "gc.h" -#include "miscanfill.h" -#include "mipoly.h" -#include "misc.h" /* MAXINT */ - -/* - * fillUtils.c - * - * Written by Brian Kelleher; Oct. 1985 - * - * This module contains all of the utility functions - * needed to scan convert a polygon. - * - */ - -/* - * InsertEdgeInET - * - * Insert the given edge into the edge table. - * First we must find the correct bucket in the - * Edge table, then find the right slot in the - * bucket. Finally, we can insert it. - * - */ -static Bool -miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline, - ScanLineListBlock **SLLBlock, int *iSLLBlock) -{ - EdgeTableEntry *start, *prev; - ScanLineList *pSLL, *pPrevSLL; - ScanLineListBlock *tmpSLLBlock; - - /* - * find the right bucket to put the edge into - */ - pPrevSLL = &ET->scanlines; - pSLL = pPrevSLL->next; - while (pSLL && (pSLL->scanline < scanline)) - { - pPrevSLL = pSLL; - pSLL = pSLL->next; - } - - /* - * reassign pSLL (pointer to ScanLineList) if necessary - */ - if ((!pSLL) || (pSLL->scanline > scanline)) - { - if (*iSLLBlock > SLLSPERBLOCK-1) - { - tmpSLLBlock = xalloc(sizeof(ScanLineListBlock)); - if (!tmpSLLBlock) - return FALSE; - (*SLLBlock)->next = tmpSLLBlock; - tmpSLLBlock->next = NULL; - *SLLBlock = tmpSLLBlock; - *iSLLBlock = 0; - } - pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]); - - pSLL->next = pPrevSLL->next; - pSLL->edgelist = NULL; - pPrevSLL->next = pSLL; - } - pSLL->scanline = scanline; - - /* - * now insert the edge in the right bucket - */ - prev = NULL; - start = pSLL->edgelist; - while (start && (start->bres.minor < ETE->bres.minor)) - { - prev = start; - start = start->next; - } - ETE->next = start; - - if (prev) - prev->next = ETE; - else - pSLL->edgelist = ETE; - return TRUE; -} - -/* - * CreateEdgeTable - * - * This routine creates the edge table for - * scan converting polygons. - * The Edge Table (ET) looks like: - * - * EdgeTable - * -------- - * | ymax | ScanLineLists - * |scanline|-->------------>-------------->... - * -------- |scanline| |scanline| - * |edgelist| |edgelist| - * --------- --------- - * | | - * | | - * V V - * list of ETEs list of ETEs - * - * where ETE is an EdgeTableEntry data structure, - * and there is one ScanLineList per scanline at - * which an edge is initially entered. - * - */ - -Bool -miCreateETandAET(int count, DDXPointPtr pts, EdgeTable *ET, EdgeTableEntry *AET, - EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock) -{ - DDXPointPtr top, bottom; - DDXPointPtr PrevPt, CurrPt; - int iSLLBlock = 0; - - int dy; - - if (count < 2) return TRUE; - - /* - * initialize the Active Edge Table - */ - AET->next = NULL; - AET->back = NULL; - AET->nextWETE = NULL; - AET->bres.minor = MININT; - - /* - * initialize the Edge Table. - */ - ET->scanlines.next = NULL; - ET->ymax = MININT; - ET->ymin = MAXINT; - pSLLBlock->next = NULL; - - PrevPt = &pts[count-1]; - - /* - * for each vertex in the array of points. - * In this loop we are dealing with two vertices at - * a time -- these make up one edge of the polygon. - */ - while (count--) - { - CurrPt = pts++; - - /* - * find out which point is above and which is below. - */ - if (PrevPt->y > CurrPt->y) - { - bottom = PrevPt, top = CurrPt; - pETEs->ClockWise = 0; - } - else - { - bottom = CurrPt, top = PrevPt; - pETEs->ClockWise = 1; - } - - /* - * don't add horizontal edges to the Edge table. - */ - if (bottom->y != top->y) - { - pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */ - - /* - * initialize integer edge algorithm - */ - dy = bottom->y - top->y; - BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres); - - if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock)) - { - miFreeStorage(pSLLBlock->next); - return FALSE; - } - - ET->ymax = max(ET->ymax, PrevPt->y); - ET->ymin = min(ET->ymin, PrevPt->y); - pETEs++; - } - - PrevPt = CurrPt; - } - return TRUE; -} - -/* - * loadAET - * - * This routine moves EdgeTableEntries from the - * EdgeTable into the Active Edge Table, - * leaving them sorted by smaller x coordinate. - * - */ - -void -miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs) -{ - EdgeTableEntry *pPrevAET; - EdgeTableEntry *tmp; - - pPrevAET = AET; - AET = AET->next; - while (ETEs) - { - while (AET && (AET->bres.minor < ETEs->bres.minor)) - { - pPrevAET = AET; - AET = AET->next; - } - tmp = ETEs->next; - ETEs->next = AET; - if (AET) - AET->back = ETEs; - ETEs->back = pPrevAET; - pPrevAET->next = ETEs; - pPrevAET = ETEs; - - ETEs = tmp; - } -} - -/* - * computeWAET - * - * This routine links the AET by the - * nextWETE (winding EdgeTableEntry) link for - * use by the winding number rule. The final - * Active Edge Table (AET) might look something - * like: - * - * AET - * ---------- --------- --------- - * |ymax | |ymax | |ymax | - * | ... | |... | |... | - * |next |->|next |->|next |->... - * |nextWETE| |nextWETE| |nextWETE| - * --------- --------- ^-------- - * | | | - * V-------------------> V---> ... - * - */ -void -micomputeWAET(EdgeTableEntry *AET) -{ - EdgeTableEntry *pWETE; - int inside = 1; - int isInside = 0; - - AET->nextWETE = NULL; - pWETE = AET; - AET = AET->next; - while (AET) - { - if (AET->ClockWise) - isInside++; - else - isInside--; - - if ((!inside && !isInside) || - ( inside && isInside)) - { - pWETE->nextWETE = AET; - pWETE = AET; - inside = !inside; - } - AET = AET->next; - } - pWETE->nextWETE = NULL; -} - -/* - * InsertionSort - * - * Just a simple insertion sort using - * pointers and back pointers to sort the Active - * Edge Table. - * - */ - -int -miInsertionSort(EdgeTableEntry *AET) -{ - EdgeTableEntry *pETEchase; - EdgeTableEntry *pETEinsert; - EdgeTableEntry *pETEchaseBackTMP; - int changed = 0; - - AET = AET->next; - while (AET) - { - pETEinsert = AET; - pETEchase = AET; - while (pETEchase->back->bres.minor > AET->bres.minor) - pETEchase = pETEchase->back; - - AET = AET->next; - if (pETEchase != pETEinsert) - { - pETEchaseBackTMP = pETEchase->back; - pETEinsert->back->next = AET; - if (AET) - AET->back = pETEinsert->back; - pETEinsert->next = pETEchase; - pETEchase->back->next = pETEinsert; - pETEchase->back = pETEinsert; - pETEinsert->back = pETEchaseBackTMP; - changed = 1; - } - } - return(changed); -} - -/* - * Clean up our act. - */ -void -miFreeStorage(ScanLineListBlock *pSLLBlock) -{ - ScanLineListBlock *tmpSLLBlock; - - while (pSLLBlock) - { - tmpSLLBlock = pSLLBlock->next; - xfree(pSLLBlock); - pSLLBlock = tmpSLLBlock; - } -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include "regionstr.h" +#include "gc.h" +#include "miscanfill.h" +#include "mipoly.h" +#include "misc.h" /* MAXINT */ + +/* + * fillUtils.c + * + * Written by Brian Kelleher; Oct. 1985 + * + * This module contains all of the utility functions + * needed to scan convert a polygon. + * + */ + +/* + * InsertEdgeInET + * + * Insert the given edge into the edge table. + * First we must find the correct bucket in the + * Edge table, then find the right slot in the + * bucket. Finally, we can insert it. + * + */ +static Bool +miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline, + ScanLineListBlock **SLLBlock, int *iSLLBlock) +{ + EdgeTableEntry *start, *prev; + ScanLineList *pSLL, *pPrevSLL; + ScanLineListBlock *tmpSLLBlock; + + /* + * find the right bucket to put the edge into + */ + pPrevSLL = &ET->scanlines; + pSLL = pPrevSLL->next; + while (pSLL && (pSLL->scanline < scanline)) + { + pPrevSLL = pSLL; + pSLL = pSLL->next; + } + + /* + * reassign pSLL (pointer to ScanLineList) if necessary + */ + if ((!pSLL) || (pSLL->scanline > scanline)) + { + if (*iSLLBlock > SLLSPERBLOCK-1) + { + tmpSLLBlock = malloc(sizeof(ScanLineListBlock)); + if (!tmpSLLBlock) + return FALSE; + (*SLLBlock)->next = tmpSLLBlock; + tmpSLLBlock->next = NULL; + *SLLBlock = tmpSLLBlock; + *iSLLBlock = 0; + } + pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]); + + pSLL->next = pPrevSLL->next; + pSLL->edgelist = NULL; + pPrevSLL->next = pSLL; + } + pSLL->scanline = scanline; + + /* + * now insert the edge in the right bucket + */ + prev = NULL; + start = pSLL->edgelist; + while (start && (start->bres.minor < ETE->bres.minor)) + { + prev = start; + start = start->next; + } + ETE->next = start; + + if (prev) + prev->next = ETE; + else + pSLL->edgelist = ETE; + return TRUE; +} + +/* + * CreateEdgeTable + * + * This routine creates the edge table for + * scan converting polygons. + * The Edge Table (ET) looks like: + * + * EdgeTable + * -------- + * | ymax | ScanLineLists + * |scanline|-->------------>-------------->... + * -------- |scanline| |scanline| + * |edgelist| |edgelist| + * --------- --------- + * | | + * | | + * V V + * list of ETEs list of ETEs + * + * where ETE is an EdgeTableEntry data structure, + * and there is one ScanLineList per scanline at + * which an edge is initially entered. + * + */ + +Bool +miCreateETandAET(int count, DDXPointPtr pts, EdgeTable *ET, EdgeTableEntry *AET, + EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock) +{ + DDXPointPtr top, bottom; + DDXPointPtr PrevPt, CurrPt; + int iSLLBlock = 0; + + int dy; + + if (count < 2) return TRUE; + + /* + * initialize the Active Edge Table + */ + AET->next = NULL; + AET->back = NULL; + AET->nextWETE = NULL; + AET->bres.minor = MININT; + + /* + * initialize the Edge Table. + */ + ET->scanlines.next = NULL; + ET->ymax = MININT; + ET->ymin = MAXINT; + pSLLBlock->next = NULL; + + PrevPt = &pts[count-1]; + + /* + * for each vertex in the array of points. + * In this loop we are dealing with two vertices at + * a time -- these make up one edge of the polygon. + */ + while (count--) + { + CurrPt = pts++; + + /* + * find out which point is above and which is below. + */ + if (PrevPt->y > CurrPt->y) + { + bottom = PrevPt, top = CurrPt; + pETEs->ClockWise = 0; + } + else + { + bottom = CurrPt, top = PrevPt; + pETEs->ClockWise = 1; + } + + /* + * don't add horizontal edges to the Edge table. + */ + if (bottom->y != top->y) + { + pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */ + + /* + * initialize integer edge algorithm + */ + dy = bottom->y - top->y; + BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres); + + if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock)) + { + miFreeStorage(pSLLBlock->next); + return FALSE; + } + + ET->ymax = max(ET->ymax, PrevPt->y); + ET->ymin = min(ET->ymin, PrevPt->y); + pETEs++; + } + + PrevPt = CurrPt; + } + return TRUE; +} + +/* + * loadAET + * + * This routine moves EdgeTableEntries from the + * EdgeTable into the Active Edge Table, + * leaving them sorted by smaller x coordinate. + * + */ + +void +miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs) +{ + EdgeTableEntry *pPrevAET; + EdgeTableEntry *tmp; + + pPrevAET = AET; + AET = AET->next; + while (ETEs) + { + while (AET && (AET->bres.minor < ETEs->bres.minor)) + { + pPrevAET = AET; + AET = AET->next; + } + tmp = ETEs->next; + ETEs->next = AET; + if (AET) + AET->back = ETEs; + ETEs->back = pPrevAET; + pPrevAET->next = ETEs; + pPrevAET = ETEs; + + ETEs = tmp; + } +} + +/* + * computeWAET + * + * This routine links the AET by the + * nextWETE (winding EdgeTableEntry) link for + * use by the winding number rule. The final + * Active Edge Table (AET) might look something + * like: + * + * AET + * ---------- --------- --------- + * |ymax | |ymax | |ymax | + * | ... | |... | |... | + * |next |->|next |->|next |->... + * |nextWETE| |nextWETE| |nextWETE| + * --------- --------- ^-------- + * | | | + * V-------------------> V---> ... + * + */ +void +micomputeWAET(EdgeTableEntry *AET) +{ + EdgeTableEntry *pWETE; + int inside = 1; + int isInside = 0; + + AET->nextWETE = NULL; + pWETE = AET; + AET = AET->next; + while (AET) + { + if (AET->ClockWise) + isInside++; + else + isInside--; + + if ((!inside && !isInside) || + ( inside && isInside)) + { + pWETE->nextWETE = AET; + pWETE = AET; + inside = !inside; + } + AET = AET->next; + } + pWETE->nextWETE = NULL; +} + +/* + * InsertionSort + * + * Just a simple insertion sort using + * pointers and back pointers to sort the Active + * Edge Table. + * + */ + +int +miInsertionSort(EdgeTableEntry *AET) +{ + EdgeTableEntry *pETEchase; + EdgeTableEntry *pETEinsert; + EdgeTableEntry *pETEchaseBackTMP; + int changed = 0; + + AET = AET->next; + while (AET) + { + pETEinsert = AET; + pETEchase = AET; + while (pETEchase->back->bres.minor > AET->bres.minor) + pETEchase = pETEchase->back; + + AET = AET->next; + if (pETEchase != pETEinsert) + { + pETEchaseBackTMP = pETEchase->back; + pETEinsert->back->next = AET; + if (AET) + AET->back = pETEinsert->back; + pETEinsert->next = pETEchase; + pETEchase->back->next = pETEinsert; + pETEchase->back = pETEinsert; + pETEinsert->back = pETEchaseBackTMP; + changed = 1; + } + } + return(changed); +} + +/* + * Clean up our act. + */ +void +miFreeStorage(ScanLineListBlock *pSLLBlock) +{ + ScanLineListBlock *tmpSLLBlock; + + while (pSLLBlock) + { + tmpSLLBlock = pSLLBlock->next; + free(pSLLBlock); + pSLLBlock = tmpSLLBlock; + } +} diff --git a/xorg-server/mi/mipushpxl.c b/xorg-server/mi/mipushpxl.c index 3844519d8..9c3d9b342 100644 --- a/xorg-server/mi/mipushpxl.c +++ b/xorg-server/mi/mipushpxl.c @@ -1,271 +1,271 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include "gcstruct.h" -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "regionstr.h" -#include "mi.h" -#include "servermd.h" - -#define NPT 128 - -/* These were stolen from mfb. They don't really belong here. */ -#define LONG2CHARSSAMEORDER(x) ((MiBits)(x)) -#define LONG2CHARSDIFFORDER( x ) ( ( ( ( x ) & (MiBits)0x000000FF ) << 0x18 ) \ - | ( ( ( x ) & (MiBits)0x0000FF00 ) << 0x08 ) \ - | ( ( ( x ) & (MiBits)0x00FF0000 ) >> 0x08 ) \ - | ( ( ( x ) & (MiBits)0xFF000000 ) >> 0x18 ) ) - - -#define PGSZB 4 -#define PPW (PGSZB<<3) /* assuming 8 bits per byte */ -#define PGSZ PPW -#define PLST (PPW-1) -#define PIM PLST -#define PWSH 5 - -/* miPushPixels -- squeegees the fill style of pGC through pBitMap - * into pDrawable. pBitMap is a stencil (dx by dy of it is used, it may - * be bigger) which is placed on the drawable at xOrg, yOrg. Where a 1 bit - * is set in the bitmap, the fill style is put onto the drawable using - * the GC's logical function. The drawable is not changed where the bitmap - * has a zero bit or outside the area covered by the stencil. - -WARNING: - this code works if the 1-bit deep pixmap format returned by GetSpans -is the same as the format defined by the mfb code (i.e. 32-bit padding -per scanline, scanline unit = 32 bits; later, this might mean -bitsizeof(int) padding and sacnline unit == bitsizeof(int).) - - */ - -/* - * in order to have both (MSB_FIRST and LSB_FIRST) versions of this - * in the server, we need to rename one of them - */ -void -miPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, - int dx, int dy, int xOrg, int yOrg) -{ - int h, dxDivPPW, ibEnd; - MiBits *pwLineStart; - MiBits *pw, *pwEnd; - MiBits msk; - int ib, w; - int ipt; /* index into above arrays */ - Bool fInBox; - DDXPointRec pt[NPT], ptThisLine; - int width[NPT]; -#if 1 - MiBits startmask; - if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER) - if (screenInfo.bitmapBitOrder == LSBFirst) - startmask = (MiBits)(-1) ^ - LONG2CHARSSAMEORDER((MiBits)(-1) << 1); - else - startmask = (MiBits)(-1) ^ - LONG2CHARSSAMEORDER((MiBits)(-1) >> 1); - else - if (screenInfo.bitmapBitOrder == LSBFirst) - startmask = (MiBits)(-1) ^ - LONG2CHARSDIFFORDER((MiBits)(-1) << 1); - else - startmask = (MiBits)(-1) ^ - LONG2CHARSDIFFORDER((MiBits)(-1) >> 1); -#endif - - pwLineStart = xalloc(BitmapBytePad(dx)); - if (!pwLineStart) - return; - ipt = 0; - dxDivPPW = dx/PPW; - - for(h = 0, ptThisLine.x = 0, ptThisLine.y = 0; - h < dy; - h++, ptThisLine.y++) - { - - (*pBitMap->drawable.pScreen->GetSpans)((DrawablePtr)pBitMap, dx, - &ptThisLine, &dx, 1, (char *)pwLineStart); - - pw = pwLineStart; - /* Process all words which are fully in the pixmap */ - - fInBox = FALSE; - pwEnd = pwLineStart + dxDivPPW; - while(pw < pwEnd) - { - w = *pw; -#if 1 - msk = startmask; -#else - msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1); -#endif - for(ib = 0; ib < PPW; ib++) - { - if(w & msk) - { - if(!fInBox) - { - pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg; - pt[ipt].y = h + yOrg; - /* start new box */ - fInBox = TRUE; - } - } - else - { - if(fInBox) - { - width[ipt] = ((pw - pwLineStart) << PWSH) + - ib + xOrg - pt[ipt].x; - if (++ipt >= NPT) - { - (*pGC->ops->FillSpans)(pDrawable, pGC, - NPT, pt, width, TRUE); - ipt = 0; - } - /* end box */ - fInBox = FALSE; - } - } -#if 1 - /* This is not quite right, but it'll do for now */ - if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER) - if (screenInfo.bitmapBitOrder == LSBFirst) - msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) << 1); - else - msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) >> 1); - else - if (screenInfo.bitmapBitOrder == LSBFirst) - msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) << 1); - else - msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1); -#else - msk = SCRRIGHT(msk, 1); -#endif - } - pw++; - } - ibEnd = dx & PIM; - if(ibEnd) - { - /* Process final partial word on line */ - w = *pw; -#if 1 - msk = startmask; -#else - msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1); -#endif - for(ib = 0; ib < ibEnd; ib++) - { - if(w & msk) - { - if(!fInBox) - { - /* start new box */ - pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg; - pt[ipt].y = h + yOrg; - fInBox = TRUE; - } - } - else - { - if(fInBox) - { - /* end box */ - width[ipt] = ((pw - pwLineStart) << PWSH) + - ib + xOrg - pt[ipt].x; - if (++ipt >= NPT) - { - (*pGC->ops->FillSpans)(pDrawable, - pGC, NPT, pt, width, TRUE); - ipt = 0; - } - fInBox = FALSE; - } - } -#if 1 - /* This is not quite right, but it'll do for now */ - if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER) - if (screenInfo.bitmapBitOrder == LSBFirst) - msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) << 1); - else - msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) >> 1); - else - if (screenInfo.bitmapBitOrder == LSBFirst) - msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) << 1); - else - msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1); -#else - msk = SCRRIGHT(msk, 1); -#endif - } - } - /* If scanline ended with last bit set, end the box */ - if(fInBox) - { - width[ipt] = dx + xOrg - pt[ipt].x; - if (++ipt >= NPT) - { - (*pGC->ops->FillSpans)(pDrawable, pGC, NPT, pt, width, TRUE); - ipt = 0; - } - } - } - xfree(pwLineStart); - /* Flush any remaining spans */ - if (ipt) - { - (*pGC->ops->FillSpans)(pDrawable, pGC, ipt, pt, width, TRUE); - } -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <X11/X.h> +#include "gcstruct.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "regionstr.h" +#include "mi.h" +#include "servermd.h" + +#define NPT 128 + +/* These were stolen from mfb. They don't really belong here. */ +#define LONG2CHARSSAMEORDER(x) ((MiBits)(x)) +#define LONG2CHARSDIFFORDER( x ) ( ( ( ( x ) & (MiBits)0x000000FF ) << 0x18 ) \ + | ( ( ( x ) & (MiBits)0x0000FF00 ) << 0x08 ) \ + | ( ( ( x ) & (MiBits)0x00FF0000 ) >> 0x08 ) \ + | ( ( ( x ) & (MiBits)0xFF000000 ) >> 0x18 ) ) + + +#define PGSZB 4 +#define PPW (PGSZB<<3) /* assuming 8 bits per byte */ +#define PGSZ PPW +#define PLST (PPW-1) +#define PIM PLST +#define PWSH 5 + +/* miPushPixels -- squeegees the fill style of pGC through pBitMap + * into pDrawable. pBitMap is a stencil (dx by dy of it is used, it may + * be bigger) which is placed on the drawable at xOrg, yOrg. Where a 1 bit + * is set in the bitmap, the fill style is put onto the drawable using + * the GC's logical function. The drawable is not changed where the bitmap + * has a zero bit or outside the area covered by the stencil. + +WARNING: + this code works if the 1-bit deep pixmap format returned by GetSpans +is the same as the format defined by the mfb code (i.e. 32-bit padding +per scanline, scanline unit = 32 bits; later, this might mean +bitsizeof(int) padding and sacnline unit == bitsizeof(int).) + + */ + +/* + * in order to have both (MSB_FIRST and LSB_FIRST) versions of this + * in the server, we need to rename one of them + */ +void +miPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, + int dx, int dy, int xOrg, int yOrg) +{ + int h, dxDivPPW, ibEnd; + MiBits *pwLineStart; + MiBits *pw, *pwEnd; + MiBits msk; + int ib, w; + int ipt; /* index into above arrays */ + Bool fInBox; + DDXPointRec pt[NPT], ptThisLine; + int width[NPT]; +#if 1 + MiBits startmask; + if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER) + if (screenInfo.bitmapBitOrder == LSBFirst) + startmask = (MiBits)(-1) ^ + LONG2CHARSSAMEORDER((MiBits)(-1) << 1); + else + startmask = (MiBits)(-1) ^ + LONG2CHARSSAMEORDER((MiBits)(-1) >> 1); + else + if (screenInfo.bitmapBitOrder == LSBFirst) + startmask = (MiBits)(-1) ^ + LONG2CHARSDIFFORDER((MiBits)(-1) << 1); + else + startmask = (MiBits)(-1) ^ + LONG2CHARSDIFFORDER((MiBits)(-1) >> 1); +#endif + + pwLineStart = malloc(BitmapBytePad(dx)); + if (!pwLineStart) + return; + ipt = 0; + dxDivPPW = dx/PPW; + + for(h = 0, ptThisLine.x = 0, ptThisLine.y = 0; + h < dy; + h++, ptThisLine.y++) + { + + (*pBitMap->drawable.pScreen->GetSpans)((DrawablePtr)pBitMap, dx, + &ptThisLine, &dx, 1, (char *)pwLineStart); + + pw = pwLineStart; + /* Process all words which are fully in the pixmap */ + + fInBox = FALSE; + pwEnd = pwLineStart + dxDivPPW; + while(pw < pwEnd) + { + w = *pw; +#if 1 + msk = startmask; +#else + msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1); +#endif + for(ib = 0; ib < PPW; ib++) + { + if(w & msk) + { + if(!fInBox) + { + pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg; + pt[ipt].y = h + yOrg; + /* start new box */ + fInBox = TRUE; + } + } + else + { + if(fInBox) + { + width[ipt] = ((pw - pwLineStart) << PWSH) + + ib + xOrg - pt[ipt].x; + if (++ipt >= NPT) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, + NPT, pt, width, TRUE); + ipt = 0; + } + /* end box */ + fInBox = FALSE; + } + } +#if 1 + /* This is not quite right, but it'll do for now */ + if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER) + if (screenInfo.bitmapBitOrder == LSBFirst) + msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) << 1); + else + msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) >> 1); + else + if (screenInfo.bitmapBitOrder == LSBFirst) + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) << 1); + else + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1); +#else + msk = SCRRIGHT(msk, 1); +#endif + } + pw++; + } + ibEnd = dx & PIM; + if(ibEnd) + { + /* Process final partial word on line */ + w = *pw; +#if 1 + msk = startmask; +#else + msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1); +#endif + for(ib = 0; ib < ibEnd; ib++) + { + if(w & msk) + { + if(!fInBox) + { + /* start new box */ + pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg; + pt[ipt].y = h + yOrg; + fInBox = TRUE; + } + } + else + { + if(fInBox) + { + /* end box */ + width[ipt] = ((pw - pwLineStart) << PWSH) + + ib + xOrg - pt[ipt].x; + if (++ipt >= NPT) + { + (*pGC->ops->FillSpans)(pDrawable, + pGC, NPT, pt, width, TRUE); + ipt = 0; + } + fInBox = FALSE; + } + } +#if 1 + /* This is not quite right, but it'll do for now */ + if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER) + if (screenInfo.bitmapBitOrder == LSBFirst) + msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) << 1); + else + msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) >> 1); + else + if (screenInfo.bitmapBitOrder == LSBFirst) + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) << 1); + else + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1); +#else + msk = SCRRIGHT(msk, 1); +#endif + } + } + /* If scanline ended with last bit set, end the box */ + if(fInBox) + { + width[ipt] = dx + xOrg - pt[ipt].x; + if (++ipt >= NPT) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, NPT, pt, width, TRUE); + ipt = 0; + } + } + } + free(pwLineStart); + /* Flush any remaining spans */ + if (ipt) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, ipt, pt, width, TRUE); + } +} diff --git a/xorg-server/mi/miregion.c b/xorg-server/mi/miregion.c index c48befc6f..ff58c0372 100644 --- a/xorg-server/mi/miregion.c +++ b/xorg-server/mi/miregion.c @@ -1,1845 +1,1845 @@ -/*********************************************************** - -Copyright 1987, 1988, 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, 1988, 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 <dix-config.h> -#endif - -#include "regionstr.h" -#include <X11/Xprotostr.h> -#include <X11/Xfuncproto.h> -#include "gc.h" -#include "mi.h" -#include "mispans.h" -#include <pixman.h> - -#undef assert -#ifdef REGION_DEBUG -#define assert(expr) { \ - CARD32 *foo = NULL; \ - if (!(expr)) { \ - ErrorF("Assertion failed file %s, line %d: %s\n", \ - __FILE__, __LINE__, #expr); \ - *foo = 0xdeadbeef; /* to get a backtrace */ \ - } \ - } -#else -#define assert(expr) -#endif - -#define good(reg) assert(miValidRegion(reg)) - -/* - * The functions in this file implement the Region abstraction used extensively - * throughout the X11 sample server. A Region is simply a set of disjoint - * (non-overlapping) rectangles, plus an "extent" rectangle which is the - * smallest single rectangle that contains all the non-overlapping rectangles. - * - * A Region is implemented as a "y-x-banded" array of rectangles. This array - * imposes two degrees of order. First, all rectangles are sorted by top side - * y coordinate first (y1), and then by left side x coordinate (x1). - * - * Furthermore, the rectangles are grouped into "bands". Each rectangle in a - * band has the same top y coordinate (y1), and each has the same bottom y - * coordinate (y2). Thus all rectangles in a band differ only in their left - * and right side (x1 and x2). Bands are implicit in the array of rectangles: - * there is no separate list of band start pointers. - * - * The y-x band representation does not minimize rectangles. In particular, - * if a rectangle vertically crosses a band (the rectangle has scanlines in - * the y1 to y2 area spanned by the band), then the rectangle may be broken - * down into two or more smaller rectangles stacked one atop the other. - * - * ----------- ----------- - * | | | | band 0 - * | | -------- ----------- -------- - * | | | | in y-x banded | | | | band 1 - * | | | | form is | | | | - * ----------- | | ----------- -------- - * | | | | band 2 - * -------- -------- - * - * An added constraint on the rectangles is that they must cover as much - * horizontal area as possible: no two rectangles within a band are allowed - * to touch. - * - * Whenever possible, bands will be merged together to cover a greater vertical - * distance (and thus reduce the number of rectangles). Two bands can be merged - * only if the bottom of one touches the top of the other and they have - * rectangles in the same places (of the same width, of course). - * - * Adam de Boor wrote most of the original region code. Joel McCormack - * substantially modified or rewrote most of the core arithmetic routines, - * and added miRegionValidate in order to support several speed improvements - * to miValidateTree. Bob Scheifler changed the representation to be more - * compact when empty or a single rectangle, and did a bunch of gratuitous - * reformatting. - */ - -/* true iff two Boxes overlap */ -#define EXTENTCHECK(r1,r2) \ - (!( ((r1)->x2 <= (r2)->x1) || \ - ((r1)->x1 >= (r2)->x2) || \ - ((r1)->y2 <= (r2)->y1) || \ - ((r1)->y1 >= (r2)->y2) ) ) - -/* true iff (x,y) is in Box */ -#define INBOX(r,x,y) \ - ( ((r)->x2 > x) && \ - ((r)->x1 <= x) && \ - ((r)->y2 > y) && \ - ((r)->y1 <= y) ) - -/* true iff Box r1 contains Box r2 */ -#define SUBSUMES(r1,r2) \ - ( ((r1)->x1 <= (r2)->x1) && \ - ((r1)->x2 >= (r2)->x2) && \ - ((r1)->y1 <= (r2)->y1) && \ - ((r1)->y2 >= (r2)->y2) ) - -#define xallocData(n) xalloc(REGION_SZOF(n)) -#define xfreeData(reg) if ((reg)->data && (reg)->data->size) xfree((reg)->data) - -#define RECTALLOC_BAIL(pReg,n,bail) \ -if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ - if (!miRectAlloc(pReg, n)) { goto bail; } - -#define RECTALLOC(pReg,n) \ -if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ - if (!miRectAlloc(pReg, n)) { return FALSE; } - -#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \ -{ \ - pNextRect->x1 = nx1; \ - pNextRect->y1 = ny1; \ - pNextRect->x2 = nx2; \ - pNextRect->y2 = ny2; \ - pNextRect++; \ -} - -#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \ -{ \ - if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\ - { \ - if (!miRectAlloc(pReg, 1)) \ - return FALSE; \ - pNextRect = REGION_TOP(pReg); \ - } \ - ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \ - pReg->data->numRects++; \ - assert(pReg->data->numRects<=pReg->data->size); \ -} - - -#define DOWNSIZE(reg,numRects) \ -if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \ -{ \ - RegDataPtr NewData; \ - NewData = (RegDataPtr)xrealloc((reg)->data, REGION_SZOF(numRects)); \ - if (NewData) \ - { \ - NewData->size = (numRects); \ - (reg)->data = NewData; \ - } \ -} - - -BoxRec miEmptyBox = {0, 0, 0, 0}; -RegDataRec miEmptyData = {0, 0}; - -RegDataRec miBrokenData = {0, 0}; -static RegionRec miBrokenRegion = { { 0, 0, 0, 0 }, &miBrokenData }; - -void -InitRegions (void) -{ - pixman_region_set_static_pointers (&miEmptyBox, &miEmptyData, &miBrokenData); -} - -/***************************************************************** - * RegionCreate(rect, size) - * This routine does a simple malloc to make a structure of - * REGION of "size" number of rectangles. - *****************************************************************/ - -RegionPtr -miRegionCreate(BoxPtr rect, int size) -{ - RegionPtr pReg; - - pReg = (RegionPtr)xalloc(sizeof(RegionRec)); - if (!pReg) - return &miBrokenRegion; - - miRegionInit (pReg, rect, size); - - return(pReg); -} - -void -miRegionDestroy(RegionPtr pReg) -{ - pixman_region_fini (pReg); - if (pReg != &miBrokenRegion) - xfree(pReg); -} - -void -miPrintRegion(RegionPtr rgn) -{ - int num, size; - int i; - BoxPtr rects; - - num = REGION_NUM_RECTS(rgn); - size = REGION_SIZE(rgn); - rects = REGION_RECTS(rgn); - ErrorF("[mi] num: %d size: %d\n", num, size); - ErrorF("[mi] extents: %d %d %d %d\n", - rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2); - for (i = 0; i < num; i++) - ErrorF("[mi] %d %d %d %d \n", - rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); - ErrorF("[mi] \n"); -} - -Bool -miRegionEqual(RegionPtr reg1, RegionPtr reg2) -{ - return pixman_region_equal (reg1, reg2); -} - -#ifdef DEBUG -Bool -miValidRegion(RegionPtr reg) -{ - int i, numRects; - - if ((reg->extents.x1 > reg->extents.x2) || - (reg->extents.y1 > reg->extents.y2)) - return FALSE; - numRects = REGION_NUM_RECTS(reg); - if (!numRects) - return ((reg->extents.x1 == reg->extents.x2) && - (reg->extents.y1 == reg->extents.y2) && - (reg->data->size || (reg->data == &miEmptyData))); - else if (numRects == 1) - return (!reg->data); - else - { - BoxPtr pboxP, pboxN; - BoxRec box; - - pboxP = REGION_RECTS(reg); - box = *pboxP; - box.y2 = pboxP[numRects-1].y2; - pboxN = pboxP + 1; - for (i = numRects; --i > 0; pboxP++, pboxN++) - { - if ((pboxN->x1 >= pboxN->x2) || - (pboxN->y1 >= pboxN->y2)) - return FALSE; - if (pboxN->x1 < box.x1) - box.x1 = pboxN->x1; - if (pboxN->x2 > box.x2) - box.x2 = pboxN->x2; - if ((pboxN->y1 < pboxP->y1) || - ((pboxN->y1 == pboxP->y1) && - ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2)))) - return FALSE; - } - return ((box.x1 == reg->extents.x1) && - (box.x2 == reg->extents.x2) && - (box.y1 == reg->extents.y1) && - (box.y2 == reg->extents.y2)); - } -} -#endif /* DEBUG */ - -/***************************************************************** - * RegionInit(pReg, rect, size) - * Outer region rect is statically allocated. - *****************************************************************/ - -void -miRegionInit(RegionPtr pReg, BoxPtr rect, int size) -{ - if (rect) - pixman_region_init_with_extents (pReg, rect); - else - pixman_region_init (pReg); -} - -void -miRegionUninit(RegionPtr pReg) -{ - pixman_region_fini (pReg); -} - -Bool -miRegionBreak (RegionPtr pReg) -{ - xfreeData (pReg); - pReg->extents = miEmptyBox; - pReg->data = &miBrokenData; - return FALSE; -} - -Bool -miRectAlloc(RegionPtr pRgn, int n) -{ - RegDataPtr data; - - if (!pRgn->data) - { - n++; - pRgn->data = xallocData(n); - if (!pRgn->data) - return miRegionBreak (pRgn); - pRgn->data->numRects = 1; - *REGION_BOXPTR(pRgn) = pRgn->extents; - } - else if (!pRgn->data->size) - { - pRgn->data = xallocData(n); - if (!pRgn->data) - return miRegionBreak (pRgn); - pRgn->data->numRects = 0; - } - else - { - if (n == 1) - { - n = pRgn->data->numRects; - if (n > 500) /* XXX pick numbers out of a hat */ - n = 250; - } - n += pRgn->data->numRects; - data = (RegDataPtr)xrealloc(pRgn->data, REGION_SZOF(n)); - if (!data) - return miRegionBreak (pRgn); - pRgn->data = data; - } - pRgn->data->size = n; - return TRUE; -} - -Bool -miRegionCopy(RegionPtr dst, RegionPtr src) -{ - return pixman_region_copy (dst, src); -} - -/*====================================================================== - * Generic Region Operator - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * miCoalesce -- - * Attempt to merge the boxes in the current band with those in the - * previous one. We are guaranteed that the current band extends to - * the end of the rects array. Used only by miRegionOp. - * - * Results: - * The new index for the previous band. - * - * Side Effects: - * If coalescing takes place: - * - rectangles in the previous band will have their y2 fields - * altered. - * - pReg->data->numRects will be decreased. - * - *----------------------------------------------------------------------- - */ -_X_INLINE static int -miCoalesce ( - RegionPtr pReg, /* Region to coalesce */ - int prevStart, /* Index of start of previous band */ - int curStart) /* Index of start of current band */ -{ - BoxPtr pPrevBox; /* Current box in previous band */ - BoxPtr pCurBox; /* Current box in current band */ - int numRects; /* Number rectangles in both bands */ - int y2; /* Bottom of current band */ - /* - * Figure out how many rectangles are in the band. - */ - numRects = curStart - prevStart; - assert(numRects == pReg->data->numRects - curStart); - - if (!numRects) return curStart; - - /* - * The bands may only be coalesced if the bottom of the previous - * matches the top scanline of the current. - */ - pPrevBox = REGION_BOX(pReg, prevStart); - pCurBox = REGION_BOX(pReg, curStart); - if (pPrevBox->y2 != pCurBox->y1) return curStart; - - /* - * Make sure the bands have boxes in the same places. This - * assumes that boxes have been added in such a way that they - * cover the most area possible. I.e. two boxes in a band must - * have some horizontal space between them. - */ - y2 = pCurBox->y2; - - do { - if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { - return (curStart); - } - pPrevBox++; - pCurBox++; - numRects--; - } while (numRects); - - /* - * The bands may be merged, so set the bottom y of each box - * in the previous band to the bottom y of the current band. - */ - numRects = curStart - prevStart; - pReg->data->numRects -= numRects; - do { - pPrevBox--; - pPrevBox->y2 = y2; - numRects--; - } while (numRects); - return prevStart; -} - - -/* Quicky macro to avoid trivial reject procedure calls to miCoalesce */ - -#define Coalesce(newReg, prevBand, curBand) \ - if (curBand - prevBand == newReg->data->numRects - curBand) { \ - prevBand = miCoalesce(newReg, prevBand, curBand); \ - } else { \ - prevBand = curBand; \ - } - -/*- - *----------------------------------------------------------------------- - * miAppendNonO -- - * Handle a non-overlapping band for the union and subtract operations. - * Just adds the (top/bottom-clipped) rectangles into the region. - * Doesn't have to check for subsumption or anything. - * - * Results: - * None. - * - * Side Effects: - * pReg->data->numRects is incremented and the rectangles overwritten - * with the rectangles we're passed. - * - *----------------------------------------------------------------------- - */ - -_X_INLINE static Bool -miAppendNonO ( - RegionPtr pReg, - BoxPtr r, - BoxPtr rEnd, - int y1, - int y2) -{ - BoxPtr pNextRect; - int newRects; - - newRects = rEnd - r; - - assert(y1 < y2); - assert(newRects != 0); - - /* Make sure we have enough space for all rectangles to be added */ - RECTALLOC(pReg, newRects); - pNextRect = REGION_TOP(pReg); - pReg->data->numRects += newRects; - do { - assert(r->x1 < r->x2); - ADDRECT(pNextRect, r->x1, y1, r->x2, y2); - r++; - } while (r != rEnd); - - return TRUE; -} - -#define FindBand(r, rBandEnd, rEnd, ry1) \ -{ \ - ry1 = r->y1; \ - rBandEnd = r+1; \ - while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ - rBandEnd++; \ - } \ -} - -#define AppendRegions(newReg, r, rEnd) \ -{ \ - int newRects; \ - if ((newRects = rEnd - r)) { \ - RECTALLOC(newReg, newRects); \ - memmove((char *)REGION_TOP(newReg),(char *)r, \ - newRects * sizeof(BoxRec)); \ - newReg->data->numRects += newRects; \ - } \ -} - -/*- - *----------------------------------------------------------------------- - * miRegionOp -- - * Apply an operation to two regions. Called by miUnion, miInverse, - * miSubtract, miIntersect.... Both regions MUST have at least one - * rectangle, and cannot be the same object. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * The new region is overwritten. - * pOverlap set to TRUE if overlapFunc ever returns TRUE. - * - * Notes: - * The idea behind this function is to view the two regions as sets. - * Together they cover a rectangle of area that this function divides - * into horizontal bands where points are covered only by one region - * or by both. For the first case, the nonOverlapFunc is called with - * each the band and the band's upper and lower extents. For the - * second, the overlapFunc is called to process the entire band. It - * is responsible for clipping the rectangles in the band, though - * this function provides the boundaries. - * At the end of each band, the new region is coalesced, if possible, - * to reduce the number of rectangles in the region. - * - *----------------------------------------------------------------------- - */ - -typedef Bool (*OverlapProcPtr)( - RegionPtr pReg, - BoxPtr r1, - BoxPtr r1End, - BoxPtr r2, - BoxPtr r2End, - short y1, - short y2, - Bool *pOverlap); - -static Bool -miRegionOp( - RegionPtr newReg, /* Place to store result */ - RegionPtr reg1, /* First region in operation */ - RegionPtr reg2, /* 2d region in operation */ - OverlapProcPtr overlapFunc, /* Function to call for over- - * lapping bands */ - Bool appendNon1, /* Append non-overlapping bands */ - /* in region 1 ? */ - Bool appendNon2, /* Append non-overlapping bands */ - /* in region 2 ? */ - Bool *pOverlap) -{ - BoxPtr r1; /* Pointer into first region */ - BoxPtr r2; /* Pointer into 2d region */ - BoxPtr r1End; /* End of 1st region */ - BoxPtr r2End; /* End of 2d region */ - short ybot; /* Bottom of intersection */ - short ytop; /* Top of intersection */ - RegDataPtr oldData; /* Old data for newReg */ - int prevBand; /* Index of start of - * previous band in newReg */ - int curBand; /* Index of start of current - * band in newReg */ - BoxPtr r1BandEnd; /* End of current band in r1 */ - BoxPtr r2BandEnd; /* End of current band in r2 */ - short top; /* Top of non-overlapping band */ - short bot; /* Bottom of non-overlapping band*/ - int r1y1; /* Temps for r1->y1 and r2->y1 */ - int r2y1; - int newSize; - int numRects; - - /* - * Break any region computed from a broken region - */ - if (REGION_NAR (reg1) || REGION_NAR(reg2)) - return miRegionBreak (newReg); - - /* - * Initialization: - * set r1, r2, r1End and r2End appropriately, save the rectangles - * of the destination region until the end in case it's one of - * the two source regions, then mark the "new" region empty, allocating - * another array of rectangles for it to use. - */ - - r1 = REGION_RECTS(reg1); - newSize = REGION_NUM_RECTS(reg1); - r1End = r1 + newSize; - numRects = REGION_NUM_RECTS(reg2); - r2 = REGION_RECTS(reg2); - r2End = r2 + numRects; - assert(r1 != r1End); - assert(r2 != r2End); - - oldData = NULL; - if (((newReg == reg1) && (newSize > 1)) || - ((newReg == reg2) && (numRects > 1))) - { - oldData = newReg->data; - newReg->data = &miEmptyData; - } - /* guess at new size */ - if (numRects > newSize) - newSize = numRects; - newSize <<= 1; - if (!newReg->data) - newReg->data = &miEmptyData; - else if (newReg->data->size) - newReg->data->numRects = 0; - if (newSize > newReg->data->size) - if (!miRectAlloc(newReg, newSize)) - return FALSE; - - /* - * Initialize ybot. - * In the upcoming loop, ybot and ytop serve different functions depending - * on whether the band being handled is an overlapping or non-overlapping - * band. - * In the case of a non-overlapping band (only one of the regions - * has points in the band), ybot is the bottom of the most recent - * intersection and thus clips the top of the rectangles in that band. - * ytop is the top of the next intersection between the two regions and - * serves to clip the bottom of the rectangles in the current band. - * For an overlapping band (where the two regions intersect), ytop clips - * the top of the rectangles of both regions and ybot clips the bottoms. - */ - - ybot = min(r1->y1, r2->y1); - - /* - * prevBand serves to mark the start of the previous band so rectangles - * can be coalesced into larger rectangles. qv. miCoalesce, above. - * In the beginning, there is no previous band, so prevBand == curBand - * (curBand is set later on, of course, but the first band will always - * start at index 0). prevBand and curBand must be indices because of - * the possible expansion, and resultant moving, of the new region's - * array of rectangles. - */ - prevBand = 0; - - do { - /* - * This algorithm proceeds one source-band (as opposed to a - * destination band, which is determined by where the two regions - * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the - * rectangle after the last one in the current band for their - * respective regions. - */ - assert(r1 != r1End); - assert(r2 != r2End); - - FindBand(r1, r1BandEnd, r1End, r1y1); - FindBand(r2, r2BandEnd, r2End, r2y1); - - /* - * First handle the band that doesn't intersect, if any. - * - * Note that attention is restricted to one band in the - * non-intersecting region at once, so if a region has n - * bands between the current position and the next place it overlaps - * the other, this entire loop will be passed through n times. - */ - if (r1y1 < r2y1) { - if (appendNon1) { - top = max(r1y1, ybot); - bot = min(r1->y2, r2y1); - if (top != bot) { - curBand = newReg->data->numRects; - miAppendNonO(newReg, r1, r1BandEnd, top, bot); - Coalesce(newReg, prevBand, curBand); - } - } - ytop = r2y1; - } else if (r2y1 < r1y1) { - if (appendNon2) { - top = max(r2y1, ybot); - bot = min(r2->y2, r1y1); - if (top != bot) { - curBand = newReg->data->numRects; - miAppendNonO(newReg, r2, r2BandEnd, top, bot); - Coalesce(newReg, prevBand, curBand); - } - } - ytop = r1y1; - } else { - ytop = r1y1; - } - - /* - * Now see if we've hit an intersecting band. The two bands only - * intersect if ybot > ytop - */ - ybot = min(r1->y2, r2->y2); - if (ybot > ytop) { - curBand = newReg->data->numRects; - (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, - pOverlap); - Coalesce(newReg, prevBand, curBand); - } - - /* - * If we've finished with a band (y2 == ybot) we skip forward - * in the region to the next band. - */ - if (r1->y2 == ybot) r1 = r1BandEnd; - if (r2->y2 == ybot) r2 = r2BandEnd; - - } while (r1 != r1End && r2 != r2End); - - /* - * Deal with whichever region (if any) still has rectangles left. - * - * We only need to worry about banding and coalescing for the very first - * band left. After that, we can just group all remaining boxes, - * regardless of how many bands, into one final append to the list. - */ - - if ((r1 != r1End) && appendNon1) { - /* Do first nonOverlap1Func call, which may be able to coalesce */ - FindBand(r1, r1BandEnd, r1End, r1y1); - curBand = newReg->data->numRects; - miAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2); - Coalesce(newReg, prevBand, curBand); - /* Just append the rest of the boxes */ - AppendRegions(newReg, r1BandEnd, r1End); - - } else if ((r2 != r2End) && appendNon2) { - /* Do first nonOverlap2Func call, which may be able to coalesce */ - FindBand(r2, r2BandEnd, r2End, r2y1); - curBand = newReg->data->numRects; - miAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2); - Coalesce(newReg, prevBand, curBand); - /* Append rest of boxes */ - AppendRegions(newReg, r2BandEnd, r2End); - } - - if (oldData) - xfree(oldData); - - if (!(numRects = newReg->data->numRects)) - { - xfreeData(newReg); - newReg->data = &miEmptyData; - } - else if (numRects == 1) - { - newReg->extents = *REGION_BOXPTR(newReg); - xfreeData(newReg); - newReg->data = NULL; - } - else - { - DOWNSIZE(newReg, numRects); - } - - return TRUE; -} - -/*- - *----------------------------------------------------------------------- - * miSetExtents -- - * Reset the extents of a region to what they should be. Called by - * miSubtract and miIntersect as they can't figure it out along the - * way or do so easily, as miUnion can. - * - * Results: - * None. - * - * Side Effects: - * The region's 'extents' structure is overwritten. - * - *----------------------------------------------------------------------- - */ -static void -miSetExtents (RegionPtr pReg) -{ - BoxPtr pBox, pBoxEnd; - - if (!pReg->data) - return; - if (!pReg->data->size) - { - pReg->extents.x2 = pReg->extents.x1; - pReg->extents.y2 = pReg->extents.y1; - return; - } - - pBox = REGION_BOXPTR(pReg); - pBoxEnd = REGION_END(pReg); - - /* - * Since pBox is the first rectangle in the region, it must have the - * smallest y1 and since pBoxEnd is the last rectangle in the region, - * it must have the largest y2, because of banding. Initialize x1 and - * x2 from pBox and pBoxEnd, resp., as good things to initialize them - * to... - */ - pReg->extents.x1 = pBox->x1; - pReg->extents.y1 = pBox->y1; - pReg->extents.x2 = pBoxEnd->x2; - pReg->extents.y2 = pBoxEnd->y2; - - assert(pReg->extents.y1 < pReg->extents.y2); - while (pBox <= pBoxEnd) { - if (pBox->x1 < pReg->extents.x1) - pReg->extents.x1 = pBox->x1; - if (pBox->x2 > pReg->extents.x2) - pReg->extents.x2 = pBox->x2; - pBox++; - }; - - assert(pReg->extents.x1 < pReg->extents.x2); -} - -/*====================================================================== - * Region Intersection - *====================================================================*/ -/*- - *----------------------------------------------------------------------- - * miIntersectO -- - * Handle an overlapping band for miIntersect. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * Rectangles may be added to the region. - * - *----------------------------------------------------------------------- - */ -/*ARGSUSED*/ -Bool -miIntersect( - RegionPtr newReg, /* destination Region */ - RegionPtr reg1, - RegionPtr reg2 /* source regions */ - ) -{ - return pixman_region_intersect (newReg, reg1, reg2); -} - -#define MERGERECT(r) \ -{ \ - if (r->x1 <= x2) { \ - /* Merge with current rectangle */ \ - if (r->x1 < x2) *pOverlap = TRUE; \ - if (x2 < r->x2) x2 = r->x2; \ - } else { \ - /* Add current rectangle, start new one */ \ - NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \ - x1 = r->x1; \ - x2 = r->x2; \ - } \ - r++; \ -} - -/*====================================================================== - * Region Union - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * miUnionO -- - * Handle an overlapping band for the union operation. Picks the - * left-most rectangle each time and merges it into the region. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * pReg is overwritten. - * pOverlap is set to TRUE if any boxes overlap. - * - *----------------------------------------------------------------------- - */ -static Bool -miUnionO ( - RegionPtr pReg, - BoxPtr r1, - BoxPtr r1End, - BoxPtr r2, - BoxPtr r2End, - short y1, - short y2, - Bool *pOverlap) -{ - BoxPtr pNextRect; - int x1; /* left and right side of current union */ - int x2; - - assert (y1 < y2); - assert(r1 != r1End && r2 != r2End); - - pNextRect = REGION_TOP(pReg); - - /* Start off current rectangle */ - if (r1->x1 < r2->x1) - { - x1 = r1->x1; - x2 = r1->x2; - r1++; - } - else - { - x1 = r2->x1; - x2 = r2->x2; - r2++; - } - while (r1 != r1End && r2 != r2End) - { - if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2); - } - - /* Finish off whoever (if any) is left */ - if (r1 != r1End) - { - do - { - MERGERECT(r1); - } while (r1 != r1End); - } - else if (r2 != r2End) - { - do - { - MERGERECT(r2); - } while (r2 != r2End); - } - - /* Add current rectangle */ - NEWRECT(pReg, pNextRect, x1, y1, x2, y2); - - return TRUE; -} - -Bool -miUnion( - RegionPtr newReg, /* destination Region */ - RegionPtr reg1, - RegionPtr reg2 /* source regions */ - ) -{ - return pixman_region_union (newReg, reg1, reg2); -} - -/*====================================================================== - * Batch Rectangle Union - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * miRegionAppend -- - * - * "Append" the rgn rectangles onto the end of dstrgn, maintaining - * knowledge of YX-banding when it's easy. Otherwise, dstrgn just - * becomes a non-y-x-banded random collection of rectangles, and not - * yet a true region. After a sequence of appends, the caller must - * call miRegionValidate to ensure that a valid region is constructed. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * dstrgn is modified if rgn has rectangles. - * - */ -Bool -miRegionAppend(RegionPtr dstrgn, RegionPtr rgn) -{ - int numRects, dnumRects, size; - BoxPtr new, old; - Bool prepend; - - if (REGION_NAR(rgn)) - return miRegionBreak (dstrgn); - - if (!rgn->data && (dstrgn->data == &miEmptyData)) - { - dstrgn->extents = rgn->extents; - dstrgn->data = NULL; - return TRUE; - } - - numRects = REGION_NUM_RECTS(rgn); - if (!numRects) - return TRUE; - prepend = FALSE; - size = numRects; - dnumRects = REGION_NUM_RECTS(dstrgn); - if (!dnumRects && (size < 200)) - size = 200; /* XXX pick numbers out of a hat */ - RECTALLOC(dstrgn, size); - old = REGION_RECTS(rgn); - if (!dnumRects) - dstrgn->extents = rgn->extents; - else if (dstrgn->extents.x2 > dstrgn->extents.x1) - { - BoxPtr first, last; - - first = old; - last = REGION_BOXPTR(dstrgn) + (dnumRects - 1); - if ((first->y1 > last->y2) || - ((first->y1 == last->y1) && (first->y2 == last->y2) && - (first->x1 > last->x2))) - { - if (rgn->extents.x1 < dstrgn->extents.x1) - dstrgn->extents.x1 = rgn->extents.x1; - if (rgn->extents.x2 > dstrgn->extents.x2) - dstrgn->extents.x2 = rgn->extents.x2; - dstrgn->extents.y2 = rgn->extents.y2; - } - else - { - first = REGION_BOXPTR(dstrgn); - last = old + (numRects - 1); - if ((first->y1 > last->y2) || - ((first->y1 == last->y1) && (first->y2 == last->y2) && - (first->x1 > last->x2))) - { - prepend = TRUE; - if (rgn->extents.x1 < dstrgn->extents.x1) - dstrgn->extents.x1 = rgn->extents.x1; - if (rgn->extents.x2 > dstrgn->extents.x2) - dstrgn->extents.x2 = rgn->extents.x2; - dstrgn->extents.y1 = rgn->extents.y1; - } - else - dstrgn->extents.x2 = dstrgn->extents.x1; - } - } - if (prepend) - { - new = REGION_BOX(dstrgn, numRects); - if (dnumRects == 1) - *new = *REGION_BOXPTR(dstrgn); - else - memmove((char *)new,(char *)REGION_BOXPTR(dstrgn), - dnumRects * sizeof(BoxRec)); - new = REGION_BOXPTR(dstrgn); - } - else - new = REGION_BOXPTR(dstrgn) + dnumRects; - if (numRects == 1) - *new = *old; - else - memmove((char *)new, (char *)old, numRects * sizeof(BoxRec)); - dstrgn->data->numRects += numRects; - return TRUE; -} - - -#define ExchangeRects(a, b) \ -{ \ - BoxRec t; \ - t = rects[a]; \ - rects[a] = rects[b]; \ - rects[b] = t; \ -} - -static void -QuickSortRects( - BoxRec rects[], - int numRects) -{ - int y1; - int x1; - int i, j; - BoxPtr r; - - /* Always called with numRects > 1 */ - - do - { - if (numRects == 2) - { - if (rects[0].y1 > rects[1].y1 || - (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) - ExchangeRects(0, 1); - return; - } - - /* Choose partition element, stick in location 0 */ - ExchangeRects(0, numRects >> 1); - y1 = rects[0].y1; - x1 = rects[0].x1; - - /* Partition array */ - i = 0; - j = numRects; - do - { - r = &(rects[i]); - do - { - r++; - i++; - } while (i != numRects && - (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); - r = &(rects[j]); - do - { - r--; - j--; - } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); - if (i < j) - ExchangeRects(i, j); - } while (i < j); - - /* Move partition element back to middle */ - ExchangeRects(0, j); - - /* Recurse */ - if (numRects-j-1 > 1) - QuickSortRects(&rects[j+1], numRects-j-1); - numRects = j; - } while (numRects > 1); -} - -/*- - *----------------------------------------------------------------------- - * miRegionValidate -- - * - * Take a ``region'' which is a non-y-x-banded random collection of - * rectangles, and compute a nice region which is the union of all the - * rectangles. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * The passed-in ``region'' may be modified. - * pOverlap set to TRUE if any retangles overlapped, else FALSE; - * - * Strategy: - * Step 1. Sort the rectangles into ascending order with primary key y1 - * and secondary key x1. - * - * Step 2. Split the rectangles into the minimum number of proper y-x - * banded regions. This may require horizontally merging - * rectangles, and vertically coalescing bands. With any luck, - * this step in an identity tranformation (ala the Box widget), - * or a coalescing into 1 box (ala Menus). - * - * Step 3. Merge the separate regions down to a single region by calling - * miUnion. Maximize the work each miUnion call does by using - * a binary merge. - * - *----------------------------------------------------------------------- - */ - -Bool -miRegionValidate(RegionPtr badreg, Bool *pOverlap) -{ - /* Descriptor for regions under construction in Step 2. */ - typedef struct { - RegionRec reg; - int prevBand; - int curBand; - } RegionInfo; - - int numRects; /* Original numRects for badreg */ - RegionInfo *ri; /* Array of current regions */ - int numRI; /* Number of entries used in ri */ - int sizeRI; /* Number of entries available in ri */ - int i; /* Index into rects */ - int j; /* Index into ri */ - RegionInfo *rit; /* &ri[j] */ - RegionPtr reg; /* ri[j].reg */ - BoxPtr box; /* Current box in rects */ - BoxPtr riBox; /* Last box in ri[j].reg */ - RegionPtr hreg; /* ri[j_half].reg */ - Bool ret = TRUE; - - *pOverlap = FALSE; - if (!badreg->data) - { - good(badreg); - return TRUE; - } - numRects = badreg->data->numRects; - if (!numRects) - { - if (REGION_NAR(badreg)) - return FALSE; - good(badreg); - return TRUE; - } - if (badreg->extents.x1 < badreg->extents.x2) - { - if ((numRects) == 1) - { - xfreeData(badreg); - badreg->data = (RegDataPtr) NULL; - } - else - { - DOWNSIZE(badreg, numRects); - } - good(badreg); - return TRUE; - } - - /* Step 1: Sort the rects array into ascending (y1, x1) order */ - QuickSortRects(REGION_BOXPTR(badreg), numRects); - - /* Step 2: Scatter the sorted array into the minimum number of regions */ - - /* Set up the first region to be the first rectangle in badreg */ - /* Note that step 2 code will never overflow the ri[0].reg rects array */ - ri = (RegionInfo *) xalloc(4 * sizeof(RegionInfo)); - if (!ri) - return miRegionBreak (badreg); - sizeRI = 4; - numRI = 1; - ri[0].prevBand = 0; - ri[0].curBand = 0; - ri[0].reg = *badreg; - box = REGION_BOXPTR(&ri[0].reg); - ri[0].reg.extents = *box; - ri[0].reg.data->numRects = 1; - - /* Now scatter rectangles into the minimum set of valid regions. If the - next rectangle to be added to a region would force an existing rectangle - in the region to be split up in order to maintain y-x banding, just - forget it. Try the next region. If it doesn't fit cleanly into any - region, make a new one. */ - - for (i = numRects; --i > 0;) - { - box++; - /* Look for a region to append box to */ - for (j = numRI, rit = ri; --j >= 0; rit++) - { - reg = &rit->reg; - riBox = REGION_END(reg); - - if (box->y1 == riBox->y1 && box->y2 == riBox->y2) - { - /* box is in same band as riBox. Merge or append it */ - if (box->x1 <= riBox->x2) - { - /* Merge it with riBox */ - if (box->x1 < riBox->x2) *pOverlap = TRUE; - if (box->x2 > riBox->x2) riBox->x2 = box->x2; - } - else - { - RECTALLOC_BAIL(reg, 1, bail); - *REGION_TOP(reg) = *box; - reg->data->numRects++; - } - goto NextRect; /* So sue me */ - } - else if (box->y1 >= riBox->y2) - { - /* Put box into new band */ - if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; - if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1; - Coalesce(reg, rit->prevBand, rit->curBand); - rit->curBand = reg->data->numRects; - RECTALLOC_BAIL(reg, 1, bail); - *REGION_TOP(reg) = *box; - reg->data->numRects++; - goto NextRect; - } - /* Well, this region was inappropriate. Try the next one. */ - } /* for j */ - - /* Uh-oh. No regions were appropriate. Create a new one. */ - if (sizeRI == numRI) - { - /* Oops, allocate space for new region information */ - sizeRI <<= 1; - rit = (RegionInfo *) xrealloc(ri, sizeRI * sizeof(RegionInfo)); - if (!rit) - goto bail; - ri = rit; - rit = &ri[numRI]; - } - numRI++; - rit->prevBand = 0; - rit->curBand = 0; - rit->reg.extents = *box; - rit->reg.data = NULL; - if (!miRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */ - goto bail; -NextRect: ; - } /* for i */ - - /* Make a final pass over each region in order to Coalesce and set - extents.x2 and extents.y2 */ - - for (j = numRI, rit = ri; --j >= 0; rit++) - { - reg = &rit->reg; - riBox = REGION_END(reg); - reg->extents.y2 = riBox->y2; - if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; - Coalesce(reg, rit->prevBand, rit->curBand); - if (reg->data->numRects == 1) /* keep unions happy below */ - { - xfreeData(reg); - reg->data = NULL; - } - } - - /* Step 3: Union all regions into a single region */ - while (numRI > 1) - { - int half = numRI/2; - for (j = numRI & 1; j < (half + (numRI & 1)); j++) - { - reg = &ri[j].reg; - hreg = &ri[j+half].reg; - if (!miRegionOp(reg, reg, hreg, miUnionO, TRUE, TRUE, pOverlap)) - ret = FALSE; - if (hreg->extents.x1 < reg->extents.x1) - reg->extents.x1 = hreg->extents.x1; - if (hreg->extents.y1 < reg->extents.y1) - reg->extents.y1 = hreg->extents.y1; - if (hreg->extents.x2 > reg->extents.x2) - reg->extents.x2 = hreg->extents.x2; - if (hreg->extents.y2 > reg->extents.y2) - reg->extents.y2 = hreg->extents.y2; - xfreeData(hreg); - } - numRI -= half; - } - *badreg = ri[0].reg; - xfree(ri); - good(badreg); - return ret; -bail: - for (i = 0; i < numRI; i++) - xfreeData(&ri[i].reg); - xfree (ri); - return miRegionBreak (badreg); -} - -RegionPtr -miRectsToRegion(int nrects, xRectangle *prect, int ctype) -{ - - RegionPtr pRgn; - RegDataPtr pData; - BoxPtr pBox; - int i; - int x1, y1, x2, y2; - - pRgn = miRegionCreate(NullBox, 0); - if (REGION_NAR (pRgn)) - return pRgn; - if (!nrects) - return pRgn; - if (nrects == 1) - { - x1 = prect->x; - y1 = prect->y; - if ((x2 = x1 + (int) prect->width) > MAXSHORT) - x2 = MAXSHORT; - if ((y2 = y1 + (int) prect->height) > MAXSHORT) - y2 = MAXSHORT; - if (x1 != x2 && y1 != y2) - { - pRgn->extents.x1 = x1; - pRgn->extents.y1 = y1; - pRgn->extents.x2 = x2; - pRgn->extents.y2 = y2; - pRgn->data = NULL; - } - return pRgn; - } - pData = xallocData(nrects); - if (!pData) - { - miRegionBreak (pRgn); - return pRgn; - } - pBox = (BoxPtr) (pData + 1); - for (i = nrects; --i >= 0; prect++) - { - x1 = prect->x; - y1 = prect->y; - if ((x2 = x1 + (int) prect->width) > MAXSHORT) - x2 = MAXSHORT; - if ((y2 = y1 + (int) prect->height) > MAXSHORT) - y2 = MAXSHORT; - if (x1 != x2 && y1 != y2) - { - pBox->x1 = x1; - pBox->y1 = y1; - pBox->x2 = x2; - pBox->y2 = y2; - pBox++; - } - } - if (pBox != (BoxPtr) (pData + 1)) - { - pData->size = nrects; - pData->numRects = pBox - (BoxPtr) (pData + 1); - pRgn->data = pData; - if (ctype != CT_YXBANDED) - { - Bool overlap; /* result ignored */ - pRgn->extents.x1 = pRgn->extents.x2 = 0; - miRegionValidate(pRgn, &overlap); - } - else - miSetExtents(pRgn); - good(pRgn); - } - else - { - xfree (pData); - } - return pRgn; -} - -/*====================================================================== - * Region Subtraction - *====================================================================*/ - - -/*- - *----------------------------------------------------------------------- - * miSubtractO -- - * Overlapping band subtraction. x1 is the left-most point not yet - * checked. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * pReg may have rectangles added to it. - * - *----------------------------------------------------------------------- - */ -/*ARGSUSED*/ - -/*- - *----------------------------------------------------------------------- - * miSubtract -- - * Subtract regS from regM and leave the result in regD. - * S stands for subtrahend, M for minuend and D for difference. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * regD is overwritten. - * - *----------------------------------------------------------------------- - */ -Bool -miSubtract(RegionPtr regD, RegionPtr regM, RegionPtr regS) -{ - return pixman_region_subtract (regD, regM, regS); -} - -/*====================================================================== - * Region Inversion - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * miInverse -- - * Take a region and a box and return a region that is everything - * in the box but not in the region. The careful reader will note - * that this is the same as subtracting the region from the box... - * - * Results: - * TRUE. - * - * Side Effects: - * newReg is overwritten. - * - *----------------------------------------------------------------------- - */ -Bool -miInverse( - RegionPtr newReg, /* Destination region */ - RegionPtr reg1, /* Region to invert */ - BoxPtr invRect /* Bounding box for inversion */ - ) -{ - return pixman_region_inverse (newReg, reg1, invRect); -} -int -miRectIn(RegionPtr region, BoxPtr prect) -{ - return pixman_region_contains_rectangle (region, prect); -} - -/* TranslateRegion(pReg, x, y) - translates in place -*/ - -void -miTranslateRegion(RegionPtr pReg, int x, int y) -{ - pixman_region_translate (pReg, x, y); -} - -void -miRegionReset(RegionPtr pReg, BoxPtr pBox) -{ - pixman_region_reset (pReg, pBox); -} - -Bool -miPointInRegion( - RegionPtr pReg, - int x, - int y, - BoxPtr box /* "return" value */ - ) -{ - return pixman_region_contains_point (pReg, x, y, box); -} - -Bool -miRegionNotEmpty(RegionPtr pReg) -{ - return pixman_region_not_empty (pReg); -} - -Bool -miRegionBroken(RegionPtr pReg) -{ - good(pReg); - return (REGION_NAR(pReg)); -} - -void -miRegionEmpty(RegionPtr pReg) -{ - good(pReg); - xfreeData(pReg); - pReg->extents.x2 = pReg->extents.x1; - pReg->extents.y2 = pReg->extents.y1; - pReg->data = &miEmptyData; -} - -BoxPtr -miRegionExtents(RegionPtr pReg) -{ - good(pReg); - return(&pReg->extents); -} - -#define ExchangeSpans(a, b) \ -{ \ - DDXPointRec tpt; \ - int tw; \ - \ - tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \ - tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \ -} - -/* ||| I should apply the merge sort code to rectangle sorting above, and see - if mapping time can be improved. But right now I've been at work 12 hours, - so forget it. -*/ - -static void QuickSortSpans( - DDXPointRec spans[], - int widths[], - int numSpans) -{ - int y; - int i, j, m; - DDXPointPtr r; - - /* Always called with numSpans > 1 */ - /* Sorts only by y, doesn't bother to sort by x */ - - do - { - if (numSpans < 9) - { - /* Do insertion sort */ - int yprev; - - yprev = spans[0].y; - i = 1; - do - { /* while i != numSpans */ - y = spans[i].y; - if (yprev > y) - { - /* spans[i] is out of order. Move into proper location. */ - DDXPointRec tpt; - int tw, k; - - for (j = 0; y >= spans[j].y; j++) {} - tpt = spans[i]; - tw = widths[i]; - for (k = i; k != j; k--) - { - spans[k] = spans[k-1]; - widths[k] = widths[k-1]; - } - spans[j] = tpt; - widths[j] = tw; - y = spans[i].y; - } /* if out of order */ - yprev = y; - i++; - } while (i != numSpans); - return; - } - - /* Choose partition element, stick in location 0 */ - m = numSpans / 2; - if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); - if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1); - if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); - y = spans[0].y; - - /* Partition array */ - i = 0; - j = numSpans; - do - { - r = &(spans[i]); - do - { - r++; - i++; - } while (i != numSpans && r->y < y); - r = &(spans[j]); - do - { - r--; - j--; - } while (y < r->y); - if (i < j) - ExchangeSpans(i, j); - } while (i < j); - - /* Move partition element back to middle */ - ExchangeSpans(0, j); - - /* Recurse */ - if (numSpans-j-1 > 1) - QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1); - numSpans = j; - } while (numSpans > 1); -} - -#define NextBand() \ -{ \ - clipy1 = pboxBandStart->y1; \ - clipy2 = pboxBandStart->y2; \ - pboxBandEnd = pboxBandStart + 1; \ - while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \ - pboxBandEnd++; \ - } \ - for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \ -} - -/* - Clip a list of scanlines to a region. The caller has allocated the - space. FSorted is non-zero if the scanline origins are in ascending - order. - returns the number of new, clipped scanlines. -*/ - -int -miClipSpans( - RegionPtr prgnDst, - DDXPointPtr ppt, - int *pwidth, - int nspans, - DDXPointPtr pptNew, - int *pwidthNew, - int fSorted) -{ - DDXPointPtr pptLast; - int *pwidthNewStart; /* the vengeance of Xerox! */ - int y, x1, x2; - int numRects; - - good(prgnDst); - pptLast = ppt + nspans; - pwidthNewStart = pwidthNew; - - if (!prgnDst->data) - { - /* Do special fast code with clip boundaries in registers(?) */ - /* It doesn't pay much to make use of fSorted in this case, - so we lump everything together. */ - - int clipx1, clipx2, clipy1, clipy2; - - clipx1 = prgnDst->extents.x1; - clipy1 = prgnDst->extents.y1; - clipx2 = prgnDst->extents.x2; - clipy2 = prgnDst->extents.y2; - - for (; ppt != pptLast; ppt++, pwidth++) - { - y = ppt->y; - x1 = ppt->x; - if (clipy1 <= y && y < clipy2) - { - x2 = x1 + *pwidth; - if (x1 < clipx1) x1 = clipx1; - if (x2 > clipx2) x2 = clipx2; - if (x1 < x2) - { - /* part of span in clip rectangle */ - pptNew->x = x1; - pptNew->y = y; - *pwidthNew = x2 - x1; - pptNew++; - pwidthNew++; - } - } - } /* end for */ - - } - else if ((numRects = prgnDst->data->numRects)) - { - /* Have to clip against many boxes */ - BoxPtr pboxBandStart, pboxBandEnd; - BoxPtr pbox; - BoxPtr pboxLast; - int clipy1, clipy2; - - /* In this case, taking advantage of sorted spans gains more than - the sorting costs. */ - if ((! fSorted) && (nspans > 1)) - QuickSortSpans(ppt, pwidth, nspans); - - pboxBandStart = REGION_BOXPTR(prgnDst); - pboxLast = pboxBandStart + numRects; - - NextBand(); - - for (; ppt != pptLast; ) - { - y = ppt->y; - if (y < clipy2) - { - /* span is in the current band */ - pbox = pboxBandStart; - x1 = ppt->x; - x2 = x1 + *pwidth; - do - { /* For each box in band */ - int newx1, newx2; - - newx1 = x1; - newx2 = x2; - if (newx1 < pbox->x1) newx1 = pbox->x1; - if (newx2 > pbox->x2) newx2 = pbox->x2; - if (newx1 < newx2) - { - /* Part of span in clip rectangle */ - pptNew->x = newx1; - pptNew->y = y; - *pwidthNew = newx2 - newx1; - pptNew++; - pwidthNew++; - } - pbox++; - } while (pbox != pboxBandEnd); - ppt++; - pwidth++; - } - else - { - /* Move to next band, adjust ppt as needed */ - pboxBandStart = pboxBandEnd; - if (pboxBandStart == pboxLast) - break; /* We're completely done */ - NextBand(); - } - } - } - return (pwidthNew - pwidthNewStart); -} +/*********************************************************** + +Copyright 1987, 1988, 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, 1988, 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 <dix-config.h> +#endif + +#include "regionstr.h" +#include <X11/Xprotostr.h> +#include <X11/Xfuncproto.h> +#include "gc.h" +#include "mi.h" +#include "mispans.h" +#include <pixman.h> + +#undef assert +#ifdef REGION_DEBUG +#define assert(expr) { \ + CARD32 *foo = NULL; \ + if (!(expr)) { \ + ErrorF("Assertion failed file %s, line %d: %s\n", \ + __FILE__, __LINE__, #expr); \ + *foo = 0xdeadbeef; /* to get a backtrace */ \ + } \ + } +#else +#define assert(expr) +#endif + +#define good(reg) assert(miValidRegion(reg)) + +/* + * The functions in this file implement the Region abstraction used extensively + * throughout the X11 sample server. A Region is simply a set of disjoint + * (non-overlapping) rectangles, plus an "extent" rectangle which is the + * smallest single rectangle that contains all the non-overlapping rectangles. + * + * A Region is implemented as a "y-x-banded" array of rectangles. This array + * imposes two degrees of order. First, all rectangles are sorted by top side + * y coordinate first (y1), and then by left side x coordinate (x1). + * + * Furthermore, the rectangles are grouped into "bands". Each rectangle in a + * band has the same top y coordinate (y1), and each has the same bottom y + * coordinate (y2). Thus all rectangles in a band differ only in their left + * and right side (x1 and x2). Bands are implicit in the array of rectangles: + * there is no separate list of band start pointers. + * + * The y-x band representation does not minimize rectangles. In particular, + * if a rectangle vertically crosses a band (the rectangle has scanlines in + * the y1 to y2 area spanned by the band), then the rectangle may be broken + * down into two or more smaller rectangles stacked one atop the other. + * + * ----------- ----------- + * | | | | band 0 + * | | -------- ----------- -------- + * | | | | in y-x banded | | | | band 1 + * | | | | form is | | | | + * ----------- | | ----------- -------- + * | | | | band 2 + * -------- -------- + * + * An added constraint on the rectangles is that they must cover as much + * horizontal area as possible: no two rectangles within a band are allowed + * to touch. + * + * Whenever possible, bands will be merged together to cover a greater vertical + * distance (and thus reduce the number of rectangles). Two bands can be merged + * only if the bottom of one touches the top of the other and they have + * rectangles in the same places (of the same width, of course). + * + * Adam de Boor wrote most of the original region code. Joel McCormack + * substantially modified or rewrote most of the core arithmetic routines, + * and added miRegionValidate in order to support several speed improvements + * to miValidateTree. Bob Scheifler changed the representation to be more + * compact when empty or a single rectangle, and did a bunch of gratuitous + * reformatting. + */ + +/* true iff two Boxes overlap */ +#define EXTENTCHECK(r1,r2) \ + (!( ((r1)->x2 <= (r2)->x1) || \ + ((r1)->x1 >= (r2)->x2) || \ + ((r1)->y2 <= (r2)->y1) || \ + ((r1)->y1 >= (r2)->y2) ) ) + +/* true iff (x,y) is in Box */ +#define INBOX(r,x,y) \ + ( ((r)->x2 > x) && \ + ((r)->x1 <= x) && \ + ((r)->y2 > y) && \ + ((r)->y1 <= y) ) + +/* true iff Box r1 contains Box r2 */ +#define SUBSUMES(r1,r2) \ + ( ((r1)->x1 <= (r2)->x1) && \ + ((r1)->x2 >= (r2)->x2) && \ + ((r1)->y1 <= (r2)->y1) && \ + ((r1)->y2 >= (r2)->y2) ) + +#define xallocData(n) malloc(REGION_SZOF(n)) +#define xfreeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data) + +#define RECTALLOC_BAIL(pReg,n,bail) \ +if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ + if (!miRectAlloc(pReg, n)) { goto bail; } + +#define RECTALLOC(pReg,n) \ +if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ + if (!miRectAlloc(pReg, n)) { return FALSE; } + +#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \ +{ \ + pNextRect->x1 = nx1; \ + pNextRect->y1 = ny1; \ + pNextRect->x2 = nx2; \ + pNextRect->y2 = ny2; \ + pNextRect++; \ +} + +#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \ +{ \ + if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\ + { \ + if (!miRectAlloc(pReg, 1)) \ + return FALSE; \ + pNextRect = REGION_TOP(pReg); \ + } \ + ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \ + pReg->data->numRects++; \ + assert(pReg->data->numRects<=pReg->data->size); \ +} + + +#define DOWNSIZE(reg,numRects) \ +if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \ +{ \ + RegDataPtr NewData; \ + NewData = (RegDataPtr)realloc((reg)->data, REGION_SZOF(numRects)); \ + if (NewData) \ + { \ + NewData->size = (numRects); \ + (reg)->data = NewData; \ + } \ +} + + +BoxRec miEmptyBox = {0, 0, 0, 0}; +RegDataRec miEmptyData = {0, 0}; + +RegDataRec miBrokenData = {0, 0}; +static RegionRec miBrokenRegion = { { 0, 0, 0, 0 }, &miBrokenData }; + +void +InitRegions (void) +{ + pixman_region_set_static_pointers (&miEmptyBox, &miEmptyData, &miBrokenData); +} + +/***************************************************************** + * RegionCreate(rect, size) + * This routine does a simple malloc to make a structure of + * REGION of "size" number of rectangles. + *****************************************************************/ + +RegionPtr +miRegionCreate(BoxPtr rect, int size) +{ + RegionPtr pReg; + + pReg = (RegionPtr)malloc(sizeof(RegionRec)); + if (!pReg) + return &miBrokenRegion; + + miRegionInit (pReg, rect, size); + + return(pReg); +} + +void +miRegionDestroy(RegionPtr pReg) +{ + pixman_region_fini (pReg); + if (pReg != &miBrokenRegion) + free(pReg); +} + +void +miPrintRegion(RegionPtr rgn) +{ + int num, size; + int i; + BoxPtr rects; + + num = REGION_NUM_RECTS(rgn); + size = REGION_SIZE(rgn); + rects = REGION_RECTS(rgn); + ErrorF("[mi] num: %d size: %d\n", num, size); + ErrorF("[mi] extents: %d %d %d %d\n", + rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2); + for (i = 0; i < num; i++) + ErrorF("[mi] %d %d %d %d \n", + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); + ErrorF("[mi] \n"); +} + +Bool +miRegionEqual(RegionPtr reg1, RegionPtr reg2) +{ + return pixman_region_equal (reg1, reg2); +} + +#ifdef DEBUG +Bool +miValidRegion(RegionPtr reg) +{ + int i, numRects; + + if ((reg->extents.x1 > reg->extents.x2) || + (reg->extents.y1 > reg->extents.y2)) + return FALSE; + numRects = REGION_NUM_RECTS(reg); + if (!numRects) + return ((reg->extents.x1 == reg->extents.x2) && + (reg->extents.y1 == reg->extents.y2) && + (reg->data->size || (reg->data == &miEmptyData))); + else if (numRects == 1) + return (!reg->data); + else + { + BoxPtr pboxP, pboxN; + BoxRec box; + + pboxP = REGION_RECTS(reg); + box = *pboxP; + box.y2 = pboxP[numRects-1].y2; + pboxN = pboxP + 1; + for (i = numRects; --i > 0; pboxP++, pboxN++) + { + if ((pboxN->x1 >= pboxN->x2) || + (pboxN->y1 >= pboxN->y2)) + return FALSE; + if (pboxN->x1 < box.x1) + box.x1 = pboxN->x1; + if (pboxN->x2 > box.x2) + box.x2 = pboxN->x2; + if ((pboxN->y1 < pboxP->y1) || + ((pboxN->y1 == pboxP->y1) && + ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2)))) + return FALSE; + } + return ((box.x1 == reg->extents.x1) && + (box.x2 == reg->extents.x2) && + (box.y1 == reg->extents.y1) && + (box.y2 == reg->extents.y2)); + } +} +#endif /* DEBUG */ + +/***************************************************************** + * RegionInit(pReg, rect, size) + * Outer region rect is statically allocated. + *****************************************************************/ + +void +miRegionInit(RegionPtr pReg, BoxPtr rect, int size) +{ + if (rect) + pixman_region_init_with_extents (pReg, rect); + else + pixman_region_init (pReg); +} + +void +miRegionUninit(RegionPtr pReg) +{ + pixman_region_fini (pReg); +} + +Bool +miRegionBreak (RegionPtr pReg) +{ + xfreeData (pReg); + pReg->extents = miEmptyBox; + pReg->data = &miBrokenData; + return FALSE; +} + +Bool +miRectAlloc(RegionPtr pRgn, int n) +{ + RegDataPtr data; + + if (!pRgn->data) + { + n++; + pRgn->data = xallocData(n); + if (!pRgn->data) + return miRegionBreak (pRgn); + pRgn->data->numRects = 1; + *REGION_BOXPTR(pRgn) = pRgn->extents; + } + else if (!pRgn->data->size) + { + pRgn->data = xallocData(n); + if (!pRgn->data) + return miRegionBreak (pRgn); + pRgn->data->numRects = 0; + } + else + { + if (n == 1) + { + n = pRgn->data->numRects; + if (n > 500) /* XXX pick numbers out of a hat */ + n = 250; + } + n += pRgn->data->numRects; + data = (RegDataPtr)realloc(pRgn->data, REGION_SZOF(n)); + if (!data) + return miRegionBreak (pRgn); + pRgn->data = data; + } + pRgn->data->size = n; + return TRUE; +} + +Bool +miRegionCopy(RegionPtr dst, RegionPtr src) +{ + return pixman_region_copy (dst, src); +} + +/*====================================================================== + * Generic Region Operator + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miCoalesce -- + * Attempt to merge the boxes in the current band with those in the + * previous one. We are guaranteed that the current band extends to + * the end of the rects array. Used only by miRegionOp. + * + * Results: + * The new index for the previous band. + * + * Side Effects: + * If coalescing takes place: + * - rectangles in the previous band will have their y2 fields + * altered. + * - pReg->data->numRects will be decreased. + * + *----------------------------------------------------------------------- + */ +_X_INLINE static int +miCoalesce ( + RegionPtr pReg, /* Region to coalesce */ + int prevStart, /* Index of start of previous band */ + int curStart) /* Index of start of current band */ +{ + BoxPtr pPrevBox; /* Current box in previous band */ + BoxPtr pCurBox; /* Current box in current band */ + int numRects; /* Number rectangles in both bands */ + int y2; /* Bottom of current band */ + /* + * Figure out how many rectangles are in the band. + */ + numRects = curStart - prevStart; + assert(numRects == pReg->data->numRects - curStart); + + if (!numRects) return curStart; + + /* + * The bands may only be coalesced if the bottom of the previous + * matches the top scanline of the current. + */ + pPrevBox = REGION_BOX(pReg, prevStart); + pCurBox = REGION_BOX(pReg, curStart); + if (pPrevBox->y2 != pCurBox->y1) return curStart; + + /* + * Make sure the bands have boxes in the same places. This + * assumes that boxes have been added in such a way that they + * cover the most area possible. I.e. two boxes in a band must + * have some horizontal space between them. + */ + y2 = pCurBox->y2; + + do { + if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { + return (curStart); + } + pPrevBox++; + pCurBox++; + numRects--; + } while (numRects); + + /* + * The bands may be merged, so set the bottom y of each box + * in the previous band to the bottom y of the current band. + */ + numRects = curStart - prevStart; + pReg->data->numRects -= numRects; + do { + pPrevBox--; + pPrevBox->y2 = y2; + numRects--; + } while (numRects); + return prevStart; +} + + +/* Quicky macro to avoid trivial reject procedure calls to miCoalesce */ + +#define Coalesce(newReg, prevBand, curBand) \ + if (curBand - prevBand == newReg->data->numRects - curBand) { \ + prevBand = miCoalesce(newReg, prevBand, curBand); \ + } else { \ + prevBand = curBand; \ + } + +/*- + *----------------------------------------------------------------------- + * miAppendNonO -- + * Handle a non-overlapping band for the union and subtract operations. + * Just adds the (top/bottom-clipped) rectangles into the region. + * Doesn't have to check for subsumption or anything. + * + * Results: + * None. + * + * Side Effects: + * pReg->data->numRects is incremented and the rectangles overwritten + * with the rectangles we're passed. + * + *----------------------------------------------------------------------- + */ + +_X_INLINE static Bool +miAppendNonO ( + RegionPtr pReg, + BoxPtr r, + BoxPtr rEnd, + int y1, + int y2) +{ + BoxPtr pNextRect; + int newRects; + + newRects = rEnd - r; + + assert(y1 < y2); + assert(newRects != 0); + + /* Make sure we have enough space for all rectangles to be added */ + RECTALLOC(pReg, newRects); + pNextRect = REGION_TOP(pReg); + pReg->data->numRects += newRects; + do { + assert(r->x1 < r->x2); + ADDRECT(pNextRect, r->x1, y1, r->x2, y2); + r++; + } while (r != rEnd); + + return TRUE; +} + +#define FindBand(r, rBandEnd, rEnd, ry1) \ +{ \ + ry1 = r->y1; \ + rBandEnd = r+1; \ + while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ + rBandEnd++; \ + } \ +} + +#define AppendRegions(newReg, r, rEnd) \ +{ \ + int newRects; \ + if ((newRects = rEnd - r)) { \ + RECTALLOC(newReg, newRects); \ + memmove((char *)REGION_TOP(newReg),(char *)r, \ + newRects * sizeof(BoxRec)); \ + newReg->data->numRects += newRects; \ + } \ +} + +/*- + *----------------------------------------------------------------------- + * miRegionOp -- + * Apply an operation to two regions. Called by miUnion, miInverse, + * miSubtract, miIntersect.... Both regions MUST have at least one + * rectangle, and cannot be the same object. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * The new region is overwritten. + * pOverlap set to TRUE if overlapFunc ever returns TRUE. + * + * Notes: + * The idea behind this function is to view the two regions as sets. + * Together they cover a rectangle of area that this function divides + * into horizontal bands where points are covered only by one region + * or by both. For the first case, the nonOverlapFunc is called with + * each the band and the band's upper and lower extents. For the + * second, the overlapFunc is called to process the entire band. It + * is responsible for clipping the rectangles in the band, though + * this function provides the boundaries. + * At the end of each band, the new region is coalesced, if possible, + * to reduce the number of rectangles in the region. + * + *----------------------------------------------------------------------- + */ + +typedef Bool (*OverlapProcPtr)( + RegionPtr pReg, + BoxPtr r1, + BoxPtr r1End, + BoxPtr r2, + BoxPtr r2End, + short y1, + short y2, + Bool *pOverlap); + +static Bool +miRegionOp( + RegionPtr newReg, /* Place to store result */ + RegionPtr reg1, /* First region in operation */ + RegionPtr reg2, /* 2d region in operation */ + OverlapProcPtr overlapFunc, /* Function to call for over- + * lapping bands */ + Bool appendNon1, /* Append non-overlapping bands */ + /* in region 1 ? */ + Bool appendNon2, /* Append non-overlapping bands */ + /* in region 2 ? */ + Bool *pOverlap) +{ + BoxPtr r1; /* Pointer into first region */ + BoxPtr r2; /* Pointer into 2d region */ + BoxPtr r1End; /* End of 1st region */ + BoxPtr r2End; /* End of 2d region */ + short ybot; /* Bottom of intersection */ + short ytop; /* Top of intersection */ + RegDataPtr oldData; /* Old data for newReg */ + int prevBand; /* Index of start of + * previous band in newReg */ + int curBand; /* Index of start of current + * band in newReg */ + BoxPtr r1BandEnd; /* End of current band in r1 */ + BoxPtr r2BandEnd; /* End of current band in r2 */ + short top; /* Top of non-overlapping band */ + short bot; /* Bottom of non-overlapping band*/ + int r1y1; /* Temps for r1->y1 and r2->y1 */ + int r2y1; + int newSize; + int numRects; + + /* + * Break any region computed from a broken region + */ + if (REGION_NAR (reg1) || REGION_NAR(reg2)) + return miRegionBreak (newReg); + + /* + * Initialization: + * set r1, r2, r1End and r2End appropriately, save the rectangles + * of the destination region until the end in case it's one of + * the two source regions, then mark the "new" region empty, allocating + * another array of rectangles for it to use. + */ + + r1 = REGION_RECTS(reg1); + newSize = REGION_NUM_RECTS(reg1); + r1End = r1 + newSize; + numRects = REGION_NUM_RECTS(reg2); + r2 = REGION_RECTS(reg2); + r2End = r2 + numRects; + assert(r1 != r1End); + assert(r2 != r2End); + + oldData = NULL; + if (((newReg == reg1) && (newSize > 1)) || + ((newReg == reg2) && (numRects > 1))) + { + oldData = newReg->data; + newReg->data = &miEmptyData; + } + /* guess at new size */ + if (numRects > newSize) + newSize = numRects; + newSize <<= 1; + if (!newReg->data) + newReg->data = &miEmptyData; + else if (newReg->data->size) + newReg->data->numRects = 0; + if (newSize > newReg->data->size) + if (!miRectAlloc(newReg, newSize)) + return FALSE; + + /* + * Initialize ybot. + * In the upcoming loop, ybot and ytop serve different functions depending + * on whether the band being handled is an overlapping or non-overlapping + * band. + * In the case of a non-overlapping band (only one of the regions + * has points in the band), ybot is the bottom of the most recent + * intersection and thus clips the top of the rectangles in that band. + * ytop is the top of the next intersection between the two regions and + * serves to clip the bottom of the rectangles in the current band. + * For an overlapping band (where the two regions intersect), ytop clips + * the top of the rectangles of both regions and ybot clips the bottoms. + */ + + ybot = min(r1->y1, r2->y1); + + /* + * prevBand serves to mark the start of the previous band so rectangles + * can be coalesced into larger rectangles. qv. miCoalesce, above. + * In the beginning, there is no previous band, so prevBand == curBand + * (curBand is set later on, of course, but the first band will always + * start at index 0). prevBand and curBand must be indices because of + * the possible expansion, and resultant moving, of the new region's + * array of rectangles. + */ + prevBand = 0; + + do { + /* + * This algorithm proceeds one source-band (as opposed to a + * destination band, which is determined by where the two regions + * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the + * rectangle after the last one in the current band for their + * respective regions. + */ + assert(r1 != r1End); + assert(r2 != r2End); + + FindBand(r1, r1BandEnd, r1End, r1y1); + FindBand(r2, r2BandEnd, r2End, r2y1); + + /* + * First handle the band that doesn't intersect, if any. + * + * Note that attention is restricted to one band in the + * non-intersecting region at once, so if a region has n + * bands between the current position and the next place it overlaps + * the other, this entire loop will be passed through n times. + */ + if (r1y1 < r2y1) { + if (appendNon1) { + top = max(r1y1, ybot); + bot = min(r1->y2, r2y1); + if (top != bot) { + curBand = newReg->data->numRects; + miAppendNonO(newReg, r1, r1BandEnd, top, bot); + Coalesce(newReg, prevBand, curBand); + } + } + ytop = r2y1; + } else if (r2y1 < r1y1) { + if (appendNon2) { + top = max(r2y1, ybot); + bot = min(r2->y2, r1y1); + if (top != bot) { + curBand = newReg->data->numRects; + miAppendNonO(newReg, r2, r2BandEnd, top, bot); + Coalesce(newReg, prevBand, curBand); + } + } + ytop = r1y1; + } else { + ytop = r1y1; + } + + /* + * Now see if we've hit an intersecting band. The two bands only + * intersect if ybot > ytop + */ + ybot = min(r1->y2, r2->y2); + if (ybot > ytop) { + curBand = newReg->data->numRects; + (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, + pOverlap); + Coalesce(newReg, prevBand, curBand); + } + + /* + * If we've finished with a band (y2 == ybot) we skip forward + * in the region to the next band. + */ + if (r1->y2 == ybot) r1 = r1BandEnd; + if (r2->y2 == ybot) r2 = r2BandEnd; + + } while (r1 != r1End && r2 != r2End); + + /* + * Deal with whichever region (if any) still has rectangles left. + * + * We only need to worry about banding and coalescing for the very first + * band left. After that, we can just group all remaining boxes, + * regardless of how many bands, into one final append to the list. + */ + + if ((r1 != r1End) && appendNon1) { + /* Do first nonOverlap1Func call, which may be able to coalesce */ + FindBand(r1, r1BandEnd, r1End, r1y1); + curBand = newReg->data->numRects; + miAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2); + Coalesce(newReg, prevBand, curBand); + /* Just append the rest of the boxes */ + AppendRegions(newReg, r1BandEnd, r1End); + + } else if ((r2 != r2End) && appendNon2) { + /* Do first nonOverlap2Func call, which may be able to coalesce */ + FindBand(r2, r2BandEnd, r2End, r2y1); + curBand = newReg->data->numRects; + miAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2); + Coalesce(newReg, prevBand, curBand); + /* Append rest of boxes */ + AppendRegions(newReg, r2BandEnd, r2End); + } + + if (oldData) + free(oldData); + + if (!(numRects = newReg->data->numRects)) + { + xfreeData(newReg); + newReg->data = &miEmptyData; + } + else if (numRects == 1) + { + newReg->extents = *REGION_BOXPTR(newReg); + xfreeData(newReg); + newReg->data = NULL; + } + else + { + DOWNSIZE(newReg, numRects); + } + + return TRUE; +} + +/*- + *----------------------------------------------------------------------- + * miSetExtents -- + * Reset the extents of a region to what they should be. Called by + * miSubtract and miIntersect as they can't figure it out along the + * way or do so easily, as miUnion can. + * + * Results: + * None. + * + * Side Effects: + * The region's 'extents' structure is overwritten. + * + *----------------------------------------------------------------------- + */ +static void +miSetExtents (RegionPtr pReg) +{ + BoxPtr pBox, pBoxEnd; + + if (!pReg->data) + return; + if (!pReg->data->size) + { + pReg->extents.x2 = pReg->extents.x1; + pReg->extents.y2 = pReg->extents.y1; + return; + } + + pBox = REGION_BOXPTR(pReg); + pBoxEnd = REGION_END(pReg); + + /* + * Since pBox is the first rectangle in the region, it must have the + * smallest y1 and since pBoxEnd is the last rectangle in the region, + * it must have the largest y2, because of banding. Initialize x1 and + * x2 from pBox and pBoxEnd, resp., as good things to initialize them + * to... + */ + pReg->extents.x1 = pBox->x1; + pReg->extents.y1 = pBox->y1; + pReg->extents.x2 = pBoxEnd->x2; + pReg->extents.y2 = pBoxEnd->y2; + + assert(pReg->extents.y1 < pReg->extents.y2); + while (pBox <= pBoxEnd) { + if (pBox->x1 < pReg->extents.x1) + pReg->extents.x1 = pBox->x1; + if (pBox->x2 > pReg->extents.x2) + pReg->extents.x2 = pBox->x2; + pBox++; + }; + + assert(pReg->extents.x1 < pReg->extents.x2); +} + +/*====================================================================== + * Region Intersection + *====================================================================*/ +/*- + *----------------------------------------------------------------------- + * miIntersectO -- + * Handle an overlapping band for miIntersect. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * Rectangles may be added to the region. + * + *----------------------------------------------------------------------- + */ +/*ARGSUSED*/ +Bool +miIntersect( + RegionPtr newReg, /* destination Region */ + RegionPtr reg1, + RegionPtr reg2 /* source regions */ + ) +{ + return pixman_region_intersect (newReg, reg1, reg2); +} + +#define MERGERECT(r) \ +{ \ + if (r->x1 <= x2) { \ + /* Merge with current rectangle */ \ + if (r->x1 < x2) *pOverlap = TRUE; \ + if (x2 < r->x2) x2 = r->x2; \ + } else { \ + /* Add current rectangle, start new one */ \ + NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \ + x1 = r->x1; \ + x2 = r->x2; \ + } \ + r++; \ +} + +/*====================================================================== + * Region Union + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miUnionO -- + * Handle an overlapping band for the union operation. Picks the + * left-most rectangle each time and merges it into the region. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * pReg is overwritten. + * pOverlap is set to TRUE if any boxes overlap. + * + *----------------------------------------------------------------------- + */ +static Bool +miUnionO ( + RegionPtr pReg, + BoxPtr r1, + BoxPtr r1End, + BoxPtr r2, + BoxPtr r2End, + short y1, + short y2, + Bool *pOverlap) +{ + BoxPtr pNextRect; + int x1; /* left and right side of current union */ + int x2; + + assert (y1 < y2); + assert(r1 != r1End && r2 != r2End); + + pNextRect = REGION_TOP(pReg); + + /* Start off current rectangle */ + if (r1->x1 < r2->x1) + { + x1 = r1->x1; + x2 = r1->x2; + r1++; + } + else + { + x1 = r2->x1; + x2 = r2->x2; + r2++; + } + while (r1 != r1End && r2 != r2End) + { + if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2); + } + + /* Finish off whoever (if any) is left */ + if (r1 != r1End) + { + do + { + MERGERECT(r1); + } while (r1 != r1End); + } + else if (r2 != r2End) + { + do + { + MERGERECT(r2); + } while (r2 != r2End); + } + + /* Add current rectangle */ + NEWRECT(pReg, pNextRect, x1, y1, x2, y2); + + return TRUE; +} + +Bool +miUnion( + RegionPtr newReg, /* destination Region */ + RegionPtr reg1, + RegionPtr reg2 /* source regions */ + ) +{ + return pixman_region_union (newReg, reg1, reg2); +} + +/*====================================================================== + * Batch Rectangle Union + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miRegionAppend -- + * + * "Append" the rgn rectangles onto the end of dstrgn, maintaining + * knowledge of YX-banding when it's easy. Otherwise, dstrgn just + * becomes a non-y-x-banded random collection of rectangles, and not + * yet a true region. After a sequence of appends, the caller must + * call miRegionValidate to ensure that a valid region is constructed. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * dstrgn is modified if rgn has rectangles. + * + */ +Bool +miRegionAppend(RegionPtr dstrgn, RegionPtr rgn) +{ + int numRects, dnumRects, size; + BoxPtr new, old; + Bool prepend; + + if (REGION_NAR(rgn)) + return miRegionBreak (dstrgn); + + if (!rgn->data && (dstrgn->data == &miEmptyData)) + { + dstrgn->extents = rgn->extents; + dstrgn->data = NULL; + return TRUE; + } + + numRects = REGION_NUM_RECTS(rgn); + if (!numRects) + return TRUE; + prepend = FALSE; + size = numRects; + dnumRects = REGION_NUM_RECTS(dstrgn); + if (!dnumRects && (size < 200)) + size = 200; /* XXX pick numbers out of a hat */ + RECTALLOC(dstrgn, size); + old = REGION_RECTS(rgn); + if (!dnumRects) + dstrgn->extents = rgn->extents; + else if (dstrgn->extents.x2 > dstrgn->extents.x1) + { + BoxPtr first, last; + + first = old; + last = REGION_BOXPTR(dstrgn) + (dnumRects - 1); + if ((first->y1 > last->y2) || + ((first->y1 == last->y1) && (first->y2 == last->y2) && + (first->x1 > last->x2))) + { + if (rgn->extents.x1 < dstrgn->extents.x1) + dstrgn->extents.x1 = rgn->extents.x1; + if (rgn->extents.x2 > dstrgn->extents.x2) + dstrgn->extents.x2 = rgn->extents.x2; + dstrgn->extents.y2 = rgn->extents.y2; + } + else + { + first = REGION_BOXPTR(dstrgn); + last = old + (numRects - 1); + if ((first->y1 > last->y2) || + ((first->y1 == last->y1) && (first->y2 == last->y2) && + (first->x1 > last->x2))) + { + prepend = TRUE; + if (rgn->extents.x1 < dstrgn->extents.x1) + dstrgn->extents.x1 = rgn->extents.x1; + if (rgn->extents.x2 > dstrgn->extents.x2) + dstrgn->extents.x2 = rgn->extents.x2; + dstrgn->extents.y1 = rgn->extents.y1; + } + else + dstrgn->extents.x2 = dstrgn->extents.x1; + } + } + if (prepend) + { + new = REGION_BOX(dstrgn, numRects); + if (dnumRects == 1) + *new = *REGION_BOXPTR(dstrgn); + else + memmove((char *)new,(char *)REGION_BOXPTR(dstrgn), + dnumRects * sizeof(BoxRec)); + new = REGION_BOXPTR(dstrgn); + } + else + new = REGION_BOXPTR(dstrgn) + dnumRects; + if (numRects == 1) + *new = *old; + else + memmove((char *)new, (char *)old, numRects * sizeof(BoxRec)); + dstrgn->data->numRects += numRects; + return TRUE; +} + + +#define ExchangeRects(a, b) \ +{ \ + BoxRec t; \ + t = rects[a]; \ + rects[a] = rects[b]; \ + rects[b] = t; \ +} + +static void +QuickSortRects( + BoxRec rects[], + int numRects) +{ + int y1; + int x1; + int i, j; + BoxPtr r; + + /* Always called with numRects > 1 */ + + do + { + if (numRects == 2) + { + if (rects[0].y1 > rects[1].y1 || + (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) + ExchangeRects(0, 1); + return; + } + + /* Choose partition element, stick in location 0 */ + ExchangeRects(0, numRects >> 1); + y1 = rects[0].y1; + x1 = rects[0].x1; + + /* Partition array */ + i = 0; + j = numRects; + do + { + r = &(rects[i]); + do + { + r++; + i++; + } while (i != numRects && + (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); + r = &(rects[j]); + do + { + r--; + j--; + } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); + if (i < j) + ExchangeRects(i, j); + } while (i < j); + + /* Move partition element back to middle */ + ExchangeRects(0, j); + + /* Recurse */ + if (numRects-j-1 > 1) + QuickSortRects(&rects[j+1], numRects-j-1); + numRects = j; + } while (numRects > 1); +} + +/*- + *----------------------------------------------------------------------- + * miRegionValidate -- + * + * Take a ``region'' which is a non-y-x-banded random collection of + * rectangles, and compute a nice region which is the union of all the + * rectangles. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * The passed-in ``region'' may be modified. + * pOverlap set to TRUE if any retangles overlapped, else FALSE; + * + * Strategy: + * Step 1. Sort the rectangles into ascending order with primary key y1 + * and secondary key x1. + * + * Step 2. Split the rectangles into the minimum number of proper y-x + * banded regions. This may require horizontally merging + * rectangles, and vertically coalescing bands. With any luck, + * this step in an identity tranformation (ala the Box widget), + * or a coalescing into 1 box (ala Menus). + * + * Step 3. Merge the separate regions down to a single region by calling + * miUnion. Maximize the work each miUnion call does by using + * a binary merge. + * + *----------------------------------------------------------------------- + */ + +Bool +miRegionValidate(RegionPtr badreg, Bool *pOverlap) +{ + /* Descriptor for regions under construction in Step 2. */ + typedef struct { + RegionRec reg; + int prevBand; + int curBand; + } RegionInfo; + + int numRects; /* Original numRects for badreg */ + RegionInfo *ri; /* Array of current regions */ + int numRI; /* Number of entries used in ri */ + int sizeRI; /* Number of entries available in ri */ + int i; /* Index into rects */ + int j; /* Index into ri */ + RegionInfo *rit; /* &ri[j] */ + RegionPtr reg; /* ri[j].reg */ + BoxPtr box; /* Current box in rects */ + BoxPtr riBox; /* Last box in ri[j].reg */ + RegionPtr hreg; /* ri[j_half].reg */ + Bool ret = TRUE; + + *pOverlap = FALSE; + if (!badreg->data) + { + good(badreg); + return TRUE; + } + numRects = badreg->data->numRects; + if (!numRects) + { + if (REGION_NAR(badreg)) + return FALSE; + good(badreg); + return TRUE; + } + if (badreg->extents.x1 < badreg->extents.x2) + { + if ((numRects) == 1) + { + xfreeData(badreg); + badreg->data = (RegDataPtr) NULL; + } + else + { + DOWNSIZE(badreg, numRects); + } + good(badreg); + return TRUE; + } + + /* Step 1: Sort the rects array into ascending (y1, x1) order */ + QuickSortRects(REGION_BOXPTR(badreg), numRects); + + /* Step 2: Scatter the sorted array into the minimum number of regions */ + + /* Set up the first region to be the first rectangle in badreg */ + /* Note that step 2 code will never overflow the ri[0].reg rects array */ + ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo)); + if (!ri) + return miRegionBreak (badreg); + sizeRI = 4; + numRI = 1; + ri[0].prevBand = 0; + ri[0].curBand = 0; + ri[0].reg = *badreg; + box = REGION_BOXPTR(&ri[0].reg); + ri[0].reg.extents = *box; + ri[0].reg.data->numRects = 1; + + /* Now scatter rectangles into the minimum set of valid regions. If the + next rectangle to be added to a region would force an existing rectangle + in the region to be split up in order to maintain y-x banding, just + forget it. Try the next region. If it doesn't fit cleanly into any + region, make a new one. */ + + for (i = numRects; --i > 0;) + { + box++; + /* Look for a region to append box to */ + for (j = numRI, rit = ri; --j >= 0; rit++) + { + reg = &rit->reg; + riBox = REGION_END(reg); + + if (box->y1 == riBox->y1 && box->y2 == riBox->y2) + { + /* box is in same band as riBox. Merge or append it */ + if (box->x1 <= riBox->x2) + { + /* Merge it with riBox */ + if (box->x1 < riBox->x2) *pOverlap = TRUE; + if (box->x2 > riBox->x2) riBox->x2 = box->x2; + } + else + { + RECTALLOC_BAIL(reg, 1, bail); + *REGION_TOP(reg) = *box; + reg->data->numRects++; + } + goto NextRect; /* So sue me */ + } + else if (box->y1 >= riBox->y2) + { + /* Put box into new band */ + if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; + if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1; + Coalesce(reg, rit->prevBand, rit->curBand); + rit->curBand = reg->data->numRects; + RECTALLOC_BAIL(reg, 1, bail); + *REGION_TOP(reg) = *box; + reg->data->numRects++; + goto NextRect; + } + /* Well, this region was inappropriate. Try the next one. */ + } /* for j */ + + /* Uh-oh. No regions were appropriate. Create a new one. */ + if (sizeRI == numRI) + { + /* Oops, allocate space for new region information */ + sizeRI <<= 1; + rit = (RegionInfo *) realloc(ri, sizeRI * sizeof(RegionInfo)); + if (!rit) + goto bail; + ri = rit; + rit = &ri[numRI]; + } + numRI++; + rit->prevBand = 0; + rit->curBand = 0; + rit->reg.extents = *box; + rit->reg.data = NULL; + if (!miRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */ + goto bail; +NextRect: ; + } /* for i */ + + /* Make a final pass over each region in order to Coalesce and set + extents.x2 and extents.y2 */ + + for (j = numRI, rit = ri; --j >= 0; rit++) + { + reg = &rit->reg; + riBox = REGION_END(reg); + reg->extents.y2 = riBox->y2; + if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; + Coalesce(reg, rit->prevBand, rit->curBand); + if (reg->data->numRects == 1) /* keep unions happy below */ + { + xfreeData(reg); + reg->data = NULL; + } + } + + /* Step 3: Union all regions into a single region */ + while (numRI > 1) + { + int half = numRI/2; + for (j = numRI & 1; j < (half + (numRI & 1)); j++) + { + reg = &ri[j].reg; + hreg = &ri[j+half].reg; + if (!miRegionOp(reg, reg, hreg, miUnionO, TRUE, TRUE, pOverlap)) + ret = FALSE; + if (hreg->extents.x1 < reg->extents.x1) + reg->extents.x1 = hreg->extents.x1; + if (hreg->extents.y1 < reg->extents.y1) + reg->extents.y1 = hreg->extents.y1; + if (hreg->extents.x2 > reg->extents.x2) + reg->extents.x2 = hreg->extents.x2; + if (hreg->extents.y2 > reg->extents.y2) + reg->extents.y2 = hreg->extents.y2; + xfreeData(hreg); + } + numRI -= half; + } + *badreg = ri[0].reg; + free(ri); + good(badreg); + return ret; +bail: + for (i = 0; i < numRI; i++) + xfreeData(&ri[i].reg); + free(ri); + return miRegionBreak (badreg); +} + +RegionPtr +miRectsToRegion(int nrects, xRectangle *prect, int ctype) +{ + + RegionPtr pRgn; + RegDataPtr pData; + BoxPtr pBox; + int i; + int x1, y1, x2, y2; + + pRgn = miRegionCreate(NullBox, 0); + if (REGION_NAR (pRgn)) + return pRgn; + if (!nrects) + return pRgn; + if (nrects == 1) + { + x1 = prect->x; + y1 = prect->y; + if ((x2 = x1 + (int) prect->width) > MAXSHORT) + x2 = MAXSHORT; + if ((y2 = y1 + (int) prect->height) > MAXSHORT) + y2 = MAXSHORT; + if (x1 != x2 && y1 != y2) + { + pRgn->extents.x1 = x1; + pRgn->extents.y1 = y1; + pRgn->extents.x2 = x2; + pRgn->extents.y2 = y2; + pRgn->data = NULL; + } + return pRgn; + } + pData = xallocData(nrects); + if (!pData) + { + miRegionBreak (pRgn); + return pRgn; + } + pBox = (BoxPtr) (pData + 1); + for (i = nrects; --i >= 0; prect++) + { + x1 = prect->x; + y1 = prect->y; + if ((x2 = x1 + (int) prect->width) > MAXSHORT) + x2 = MAXSHORT; + if ((y2 = y1 + (int) prect->height) > MAXSHORT) + y2 = MAXSHORT; + if (x1 != x2 && y1 != y2) + { + pBox->x1 = x1; + pBox->y1 = y1; + pBox->x2 = x2; + pBox->y2 = y2; + pBox++; + } + } + if (pBox != (BoxPtr) (pData + 1)) + { + pData->size = nrects; + pData->numRects = pBox - (BoxPtr) (pData + 1); + pRgn->data = pData; + if (ctype != CT_YXBANDED) + { + Bool overlap; /* result ignored */ + pRgn->extents.x1 = pRgn->extents.x2 = 0; + miRegionValidate(pRgn, &overlap); + } + else + miSetExtents(pRgn); + good(pRgn); + } + else + { + free(pData); + } + return pRgn; +} + +/*====================================================================== + * Region Subtraction + *====================================================================*/ + + +/*- + *----------------------------------------------------------------------- + * miSubtractO -- + * Overlapping band subtraction. x1 is the left-most point not yet + * checked. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * pReg may have rectangles added to it. + * + *----------------------------------------------------------------------- + */ +/*ARGSUSED*/ + +/*- + *----------------------------------------------------------------------- + * miSubtract -- + * Subtract regS from regM and leave the result in regD. + * S stands for subtrahend, M for minuend and D for difference. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * regD is overwritten. + * + *----------------------------------------------------------------------- + */ +Bool +miSubtract(RegionPtr regD, RegionPtr regM, RegionPtr regS) +{ + return pixman_region_subtract (regD, regM, regS); +} + +/*====================================================================== + * Region Inversion + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miInverse -- + * Take a region and a box and return a region that is everything + * in the box but not in the region. The careful reader will note + * that this is the same as subtracting the region from the box... + * + * Results: + * TRUE. + * + * Side Effects: + * newReg is overwritten. + * + *----------------------------------------------------------------------- + */ +Bool +miInverse( + RegionPtr newReg, /* Destination region */ + RegionPtr reg1, /* Region to invert */ + BoxPtr invRect /* Bounding box for inversion */ + ) +{ + return pixman_region_inverse (newReg, reg1, invRect); +} +int +miRectIn(RegionPtr region, BoxPtr prect) +{ + return pixman_region_contains_rectangle (region, prect); +} + +/* TranslateRegion(pReg, x, y) + translates in place +*/ + +void +miTranslateRegion(RegionPtr pReg, int x, int y) +{ + pixman_region_translate (pReg, x, y); +} + +void +miRegionReset(RegionPtr pReg, BoxPtr pBox) +{ + pixman_region_reset (pReg, pBox); +} + +Bool +miPointInRegion( + RegionPtr pReg, + int x, + int y, + BoxPtr box /* "return" value */ + ) +{ + return pixman_region_contains_point (pReg, x, y, box); +} + +Bool +miRegionNotEmpty(RegionPtr pReg) +{ + return pixman_region_not_empty (pReg); +} + +Bool +miRegionBroken(RegionPtr pReg) +{ + good(pReg); + return (REGION_NAR(pReg)); +} + +void +miRegionEmpty(RegionPtr pReg) +{ + good(pReg); + xfreeData(pReg); + pReg->extents.x2 = pReg->extents.x1; + pReg->extents.y2 = pReg->extents.y1; + pReg->data = &miEmptyData; +} + +BoxPtr +miRegionExtents(RegionPtr pReg) +{ + good(pReg); + return(&pReg->extents); +} + +#define ExchangeSpans(a, b) \ +{ \ + DDXPointRec tpt; \ + int tw; \ + \ + tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \ + tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \ +} + +/* ||| I should apply the merge sort code to rectangle sorting above, and see + if mapping time can be improved. But right now I've been at work 12 hours, + so forget it. +*/ + +static void QuickSortSpans( + DDXPointRec spans[], + int widths[], + int numSpans) +{ + int y; + int i, j, m; + DDXPointPtr r; + + /* Always called with numSpans > 1 */ + /* Sorts only by y, doesn't bother to sort by x */ + + do + { + if (numSpans < 9) + { + /* Do insertion sort */ + int yprev; + + yprev = spans[0].y; + i = 1; + do + { /* while i != numSpans */ + y = spans[i].y; + if (yprev > y) + { + /* spans[i] is out of order. Move into proper location. */ + DDXPointRec tpt; + int tw, k; + + for (j = 0; y >= spans[j].y; j++) {} + tpt = spans[i]; + tw = widths[i]; + for (k = i; k != j; k--) + { + spans[k] = spans[k-1]; + widths[k] = widths[k-1]; + } + spans[j] = tpt; + widths[j] = tw; + y = spans[i].y; + } /* if out of order */ + yprev = y; + i++; + } while (i != numSpans); + return; + } + + /* Choose partition element, stick in location 0 */ + m = numSpans / 2; + if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); + if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1); + if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); + y = spans[0].y; + + /* Partition array */ + i = 0; + j = numSpans; + do + { + r = &(spans[i]); + do + { + r++; + i++; + } while (i != numSpans && r->y < y); + r = &(spans[j]); + do + { + r--; + j--; + } while (y < r->y); + if (i < j) + ExchangeSpans(i, j); + } while (i < j); + + /* Move partition element back to middle */ + ExchangeSpans(0, j); + + /* Recurse */ + if (numSpans-j-1 > 1) + QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1); + numSpans = j; + } while (numSpans > 1); +} + +#define NextBand() \ +{ \ + clipy1 = pboxBandStart->y1; \ + clipy2 = pboxBandStart->y2; \ + pboxBandEnd = pboxBandStart + 1; \ + while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \ + pboxBandEnd++; \ + } \ + for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \ +} + +/* + Clip a list of scanlines to a region. The caller has allocated the + space. FSorted is non-zero if the scanline origins are in ascending + order. + returns the number of new, clipped scanlines. +*/ + +int +miClipSpans( + RegionPtr prgnDst, + DDXPointPtr ppt, + int *pwidth, + int nspans, + DDXPointPtr pptNew, + int *pwidthNew, + int fSorted) +{ + DDXPointPtr pptLast; + int *pwidthNewStart; /* the vengeance of Xerox! */ + int y, x1, x2; + int numRects; + + good(prgnDst); + pptLast = ppt + nspans; + pwidthNewStart = pwidthNew; + + if (!prgnDst->data) + { + /* Do special fast code with clip boundaries in registers(?) */ + /* It doesn't pay much to make use of fSorted in this case, + so we lump everything together. */ + + int clipx1, clipx2, clipy1, clipy2; + + clipx1 = prgnDst->extents.x1; + clipy1 = prgnDst->extents.y1; + clipx2 = prgnDst->extents.x2; + clipy2 = prgnDst->extents.y2; + + for (; ppt != pptLast; ppt++, pwidth++) + { + y = ppt->y; + x1 = ppt->x; + if (clipy1 <= y && y < clipy2) + { + x2 = x1 + *pwidth; + if (x1 < clipx1) x1 = clipx1; + if (x2 > clipx2) x2 = clipx2; + if (x1 < x2) + { + /* part of span in clip rectangle */ + pptNew->x = x1; + pptNew->y = y; + *pwidthNew = x2 - x1; + pptNew++; + pwidthNew++; + } + } + } /* end for */ + + } + else if ((numRects = prgnDst->data->numRects)) + { + /* Have to clip against many boxes */ + BoxPtr pboxBandStart, pboxBandEnd; + BoxPtr pbox; + BoxPtr pboxLast; + int clipy1, clipy2; + + /* In this case, taking advantage of sorted spans gains more than + the sorting costs. */ + if ((! fSorted) && (nspans > 1)) + QuickSortSpans(ppt, pwidth, nspans); + + pboxBandStart = REGION_BOXPTR(prgnDst); + pboxLast = pboxBandStart + numRects; + + NextBand(); + + for (; ppt != pptLast; ) + { + y = ppt->y; + if (y < clipy2) + { + /* span is in the current band */ + pbox = pboxBandStart; + x1 = ppt->x; + x2 = x1 + *pwidth; + do + { /* For each box in band */ + int newx1, newx2; + + newx1 = x1; + newx2 = x2; + if (newx1 < pbox->x1) newx1 = pbox->x1; + if (newx2 > pbox->x2) newx2 = pbox->x2; + if (newx1 < newx2) + { + /* Part of span in clip rectangle */ + pptNew->x = newx1; + pptNew->y = y; + *pwidthNew = newx2 - newx1; + pptNew++; + pwidthNew++; + } + pbox++; + } while (pbox != pboxBandEnd); + ppt++; + pwidth++; + } + else + { + /* Move to next band, adjust ppt as needed */ + pboxBandStart = pboxBandEnd; + if (pboxBandStart == pboxLast) + break; /* We're completely done */ + NextBand(); + } + } + } + return (pwidthNew - pwidthNewStart); +} diff --git a/xorg-server/mi/miscrinit.c b/xorg-server/mi/miscrinit.c index 96113d65d..2af17672b 100644 --- a/xorg-server/mi/miscrinit.c +++ b/xorg-server/mi/miscrinit.c @@ -1,313 +1,312 @@ -/* - -Copyright 1990, 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 <dix-config.h> -#endif - -#include <X11/X.h> -#include "servermd.h" -#include "misc.h" -#include "mi.h" -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "dix.h" -#include "miline.h" -#ifdef MITSHM -#include <X11/extensions/shm.h> -#include "shmint.h" -#endif - -/* We use this structure to propogate some information from miScreenInit to - * miCreateScreenResources. miScreenInit allocates the structure, fills it - * in, and puts it into pScreen->devPrivate. miCreateScreenResources - * extracts the info and frees the structure. We could've accomplished the - * same thing by adding fields to the screen structure, but they would have - * ended up being redundant, and would have exposed this mi implementation - * detail to the whole server. - */ - -typedef struct -{ - pointer pbits; /* pointer to framebuffer */ - int width; /* delta to add to a framebuffer addr to move one row down */ -} miScreenInitParmsRec, *miScreenInitParmsPtr; - - -/* this plugs into pScreen->ModifyPixmapHeader */ -Bool -miModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, - int bitsPerPixel, int devKind, pointer pPixData) -{ - if (!pPixmap) - return FALSE; - - /* - * If all arguments are specified, reinitialize everything (including - * validated state). - */ - if ((width > 0) && (height > 0) && (depth > 0) && (bitsPerPixel > 0) && - (devKind > 0) && pPixData) { - pPixmap->drawable.depth = depth; - pPixmap->drawable.bitsPerPixel = bitsPerPixel; - pPixmap->drawable.id = 0; - pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - pPixmap->drawable.x = 0; - pPixmap->drawable.y = 0; - pPixmap->drawable.width = width; - pPixmap->drawable.height = height; - pPixmap->devKind = devKind; - pPixmap->refcnt = 1; - pPixmap->devPrivate.ptr = pPixData; - } else { - /* - * Only modify specified fields, keeping all others intact. - */ - - if (width > 0) - pPixmap->drawable.width = width; - - if (height > 0) - pPixmap->drawable.height = height; - - if (depth > 0) - pPixmap->drawable.depth = depth; - - if (bitsPerPixel > 0) - pPixmap->drawable.bitsPerPixel = bitsPerPixel; - else if ((bitsPerPixel < 0) && (depth > 0)) - pPixmap->drawable.bitsPerPixel = BitsPerPixel(depth); - - /* - * CAVEAT: Non-SI DDXen may use devKind and devPrivate fields for - * other purposes. - */ - if (devKind > 0) - pPixmap->devKind = devKind; - else if ((devKind < 0) && ((width > 0) || (depth > 0))) - pPixmap->devKind = PixmapBytePad(pPixmap->drawable.width, - pPixmap->drawable.depth); - - if (pPixData) - pPixmap->devPrivate.ptr = pPixData; - } - return TRUE; -} - -static Bool -miCloseScreen (int iScreen, ScreenPtr pScreen) -{ - return ((*pScreen->DestroyPixmap)((PixmapPtr)pScreen->devPrivate)); -} - -/* With the introduction of pixmap privates, the "screen pixmap" can no - * longer be created in miScreenInit, since all the modules that could - * possibly ask for pixmap private space have not been initialized at - * that time. pScreen->CreateScreenResources is called after all - * possible private-requesting modules have been inited; we create the - * screen pixmap here. - */ -Bool -miCreateScreenResources(ScreenPtr pScreen) -{ - miScreenInitParmsPtr pScrInitParms; - pointer value; - - pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate; - - /* if width is non-zero, pScreen->devPrivate will be a pixmap - * else it will just take the value pbits - */ - if (pScrInitParms->width) - { - PixmapPtr pPixmap; - - /* create a pixmap with no data, then redirect it to point to - * the screen - */ - pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0); - if (!pPixmap) - return FALSE; - - if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width, - pScreen->height, pScreen->rootDepth, - BitsPerPixel(pScreen->rootDepth), - PixmapBytePad(pScrInitParms->width, pScreen->rootDepth), - pScrInitParms->pbits)) - return FALSE; - value = (pointer)pPixmap; - } - else - { - value = pScrInitParms->pbits; - } - xfree(pScreen->devPrivate); /* freeing miScreenInitParmsRec */ - pScreen->devPrivate = value; /* pPixmap or pbits */ - return TRUE; -} - -Bool -miScreenDevPrivateInit(ScreenPtr pScreen, int width, pointer pbits) -{ - miScreenInitParmsPtr pScrInitParms; - - /* Stash pbits and width in a short-lived miScreenInitParmsRec attached - * to the screen, until CreateScreenResources can put them in the - * screen pixmap. - */ - pScrInitParms = xalloc(sizeof(miScreenInitParmsRec)); - if (!pScrInitParms) - return FALSE; - pScrInitParms->pbits = pbits; - pScrInitParms->width = width; - pScreen->devPrivate = (pointer)pScrInitParms; - return TRUE; -} - -static PixmapPtr -miGetScreenPixmap(ScreenPtr pScreen) -{ - return (PixmapPtr)(pScreen->devPrivate); -} - -static void -miSetScreenPixmap(PixmapPtr pPix) -{ - if (pPix) - pPix->drawable.pScreen->devPrivate = (pointer)pPix; -} - -Bool -miScreenInit( - ScreenPtr pScreen, - pointer pbits, /* pointer to screen bits */ - int xsize, int ysize, /* in pixels */ - int dpix, int dpiy, /* dots per inch */ - int width, /* pixel width of frame buffer */ - int rootDepth, /* depth of root window */ - int numDepths, /* number of depths supported */ - DepthRec *depths, /* supported depths */ - VisualID rootVisual, /* root visual */ - int numVisuals, /* number of visuals supported */ - VisualRec *visuals /* supported visuals */ - ) -{ - pScreen->width = xsize; - pScreen->height = ysize; - pScreen->mmWidth = (xsize * 254 + dpix * 5) / (dpix * 10); - pScreen->mmHeight = (ysize * 254 + dpiy * 5) / (dpiy * 10); - pScreen->numDepths = numDepths; - pScreen->rootDepth = rootDepth; - pScreen->allowedDepths = depths; - pScreen->rootVisual = rootVisual; - /* defColormap */ - pScreen->minInstalledCmaps = 1; - pScreen->maxInstalledCmaps = 1; - pScreen->backingStoreSupport = NotUseful; - pScreen->saveUnderSupport = NotUseful; - /* whitePixel, blackPixel */ - pScreen->ModifyPixmapHeader = miModifyPixmapHeader; - pScreen->CreateScreenResources = miCreateScreenResources; - pScreen->GetScreenPixmap = miGetScreenPixmap; - pScreen->SetScreenPixmap = miSetScreenPixmap; - pScreen->numVisuals = numVisuals; - pScreen->visuals = visuals; - if (width) - { -#ifdef MITSHM - ShmRegisterFbFuncs(pScreen); -#endif - pScreen->CloseScreen = miCloseScreen; - } - /* else CloseScreen */ - /* QueryBestSize, SaveScreen, GetImage, GetSpans */ - pScreen->PointerNonInterestBox = (PointerNonInterestBoxProcPtr) 0; - pScreen->SourceValidate = (SourceValidateProcPtr) 0; - /* CreateWindow, DestroyWindow, PositionWindow, ChangeWindowAttributes */ - /* RealizeWindow, UnrealizeWindow */ - pScreen->ValidateTree = miValidateTree; - pScreen->PostValidateTree = (PostValidateTreeProcPtr) 0; - pScreen->WindowExposures = miWindowExposures; - /* CopyWindow */ - pScreen->ClearToBackground = miClearToBackground; - pScreen->ClipNotify = (ClipNotifyProcPtr) 0; - pScreen->RestackWindow = (RestackWindowProcPtr) 0; - /* CreatePixmap, DestroyPixmap */ - /* RealizeFont, UnrealizeFont */ - /* CreateGC */ - /* CreateColormap, DestroyColormap, InstallColormap, UninstallColormap */ - /* ListInstalledColormaps, StoreColors, ResolveColor */ - /* BitmapToRegion */ - pScreen->SendGraphicsExpose = miSendGraphicsExpose; - pScreen->BlockHandler = (ScreenBlockHandlerProcPtr)NoopDDA; - pScreen->WakeupHandler = (ScreenWakeupHandlerProcPtr)NoopDDA; - pScreen->blockData = (pointer)0; - pScreen->wakeupData = (pointer)0; - pScreen->MarkWindow = miMarkWindow; - pScreen->MarkOverlappedWindows = miMarkOverlappedWindows; - pScreen->ChangeSaveUnder = NULL; - pScreen->PostChangeSaveUnder = NULL; - pScreen->MoveWindow = miMoveWindow; - pScreen->ResizeWindow = miSlideAndSizeWindow; - pScreen->GetLayerWindow = miGetLayerWindow; - pScreen->HandleExposures = miHandleValidateExposures; - pScreen->ReparentWindow = (ReparentWindowProcPtr) 0; - pScreen->ChangeBorderWidth = miChangeBorderWidth; - pScreen->SetShape = miSetShape; - pScreen->MarkUnrealizedWindow = miMarkUnrealizedWindow; - - pScreen->SaveDoomedAreas = 0; - pScreen->RestoreAreas = 0; - pScreen->ExposeCopy = 0; - pScreen->TranslateBackingStore = 0; - pScreen->ClearBackingStore = 0; - pScreen->DrawGuarantee = 0; - - miSetZeroLineBias(pScreen, DEFAULTZEROLINEBIAS); - - return miScreenDevPrivateInit(pScreen, width, pbits); -} - -static int privateKeyIndex; -static DevPrivateKey privateKey = &privateKeyIndex; - -DevPrivateKey -miAllocateGCPrivateIndex(void) -{ - return privateKey; -} - -static int miZeroLineScreenKeyIndex; -DevPrivateKey miZeroLineScreenKey = &miZeroLineScreenKeyIndex; - -void -miSetZeroLineBias(ScreenPtr pScreen, unsigned int bias) -{ - dixSetPrivate(&pScreen->devPrivates, miZeroLineScreenKey, - (unsigned long *)(unsigned long)bias); -} +/* + +Copyright 1990, 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 <dix-config.h> +#endif + +#include <X11/X.h> +#include "servermd.h" +#include "misc.h" +#include "mi.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "dix.h" +#include "miline.h" +#ifdef MITSHM +#include <X11/extensions/shm.h> +#include "shmint.h" +#endif + +/* We use this structure to propogate some information from miScreenInit to + * miCreateScreenResources. miScreenInit allocates the structure, fills it + * in, and puts it into pScreen->devPrivate. miCreateScreenResources + * extracts the info and frees the structure. We could've accomplished the + * same thing by adding fields to the screen structure, but they would have + * ended up being redundant, and would have exposed this mi implementation + * detail to the whole server. + */ + +typedef struct +{ + pointer pbits; /* pointer to framebuffer */ + int width; /* delta to add to a framebuffer addr to move one row down */ +} miScreenInitParmsRec, *miScreenInitParmsPtr; + + +/* this plugs into pScreen->ModifyPixmapHeader */ +Bool +miModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + if (!pPixmap) + return FALSE; + + /* + * If all arguments are specified, reinitialize everything (including + * validated state). + */ + if ((width > 0) && (height > 0) && (depth > 0) && (bitsPerPixel > 0) && + (devKind > 0) && pPixData) { + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bitsPerPixel; + pPixmap->drawable.id = 0; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = devKind; + pPixmap->refcnt = 1; + pPixmap->devPrivate.ptr = pPixData; + } else { + /* + * Only modify specified fields, keeping all others intact. + */ + + if (width > 0) + pPixmap->drawable.width = width; + + if (height > 0) + pPixmap->drawable.height = height; + + if (depth > 0) + pPixmap->drawable.depth = depth; + + if (bitsPerPixel > 0) + pPixmap->drawable.bitsPerPixel = bitsPerPixel; + else if ((bitsPerPixel < 0) && (depth > 0)) + pPixmap->drawable.bitsPerPixel = BitsPerPixel(depth); + + /* + * CAVEAT: Non-SI DDXen may use devKind and devPrivate fields for + * other purposes. + */ + if (devKind > 0) + pPixmap->devKind = devKind; + else if ((devKind < 0) && ((width > 0) || (depth > 0))) + pPixmap->devKind = PixmapBytePad(pPixmap->drawable.width, + pPixmap->drawable.depth); + + if (pPixData) + pPixmap->devPrivate.ptr = pPixData; + } + return TRUE; +} + +static Bool +miCloseScreen (int iScreen, ScreenPtr pScreen) +{ + return ((*pScreen->DestroyPixmap)((PixmapPtr)pScreen->devPrivate)); +} + +/* With the introduction of pixmap privates, the "screen pixmap" can no + * longer be created in miScreenInit, since all the modules that could + * possibly ask for pixmap private space have not been initialized at + * that time. pScreen->CreateScreenResources is called after all + * possible private-requesting modules have been inited; we create the + * screen pixmap here. + */ +Bool +miCreateScreenResources(ScreenPtr pScreen) +{ + miScreenInitParmsPtr pScrInitParms; + pointer value; + + pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate; + + /* if width is non-zero, pScreen->devPrivate will be a pixmap + * else it will just take the value pbits + */ + if (pScrInitParms->width) + { + PixmapPtr pPixmap; + + /* create a pixmap with no data, then redirect it to point to + * the screen + */ + pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0); + if (!pPixmap) + return FALSE; + + if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width, + pScreen->height, pScreen->rootDepth, + BitsPerPixel(pScreen->rootDepth), + PixmapBytePad(pScrInitParms->width, pScreen->rootDepth), + pScrInitParms->pbits)) + return FALSE; + value = (pointer)pPixmap; + } + else + { + value = pScrInitParms->pbits; + } + free(pScreen->devPrivate); /* freeing miScreenInitParmsRec */ + pScreen->devPrivate = value; /* pPixmap or pbits */ + return TRUE; +} + +Bool +miScreenDevPrivateInit(ScreenPtr pScreen, int width, pointer pbits) +{ + miScreenInitParmsPtr pScrInitParms; + + /* Stash pbits and width in a short-lived miScreenInitParmsRec attached + * to the screen, until CreateScreenResources can put them in the + * screen pixmap. + */ + pScrInitParms = malloc(sizeof(miScreenInitParmsRec)); + if (!pScrInitParms) + return FALSE; + pScrInitParms->pbits = pbits; + pScrInitParms->width = width; + pScreen->devPrivate = (pointer)pScrInitParms; + return TRUE; +} + +static PixmapPtr +miGetScreenPixmap(ScreenPtr pScreen) +{ + return (PixmapPtr)(pScreen->devPrivate); +} + +static void +miSetScreenPixmap(PixmapPtr pPix) +{ + if (pPix) + pPix->drawable.pScreen->devPrivate = (pointer)pPix; +} + +Bool +miScreenInit( + ScreenPtr pScreen, + pointer pbits, /* pointer to screen bits */ + int xsize, int ysize, /* in pixels */ + int dpix, int dpiy, /* dots per inch */ + int width, /* pixel width of frame buffer */ + int rootDepth, /* depth of root window */ + int numDepths, /* number of depths supported */ + DepthRec *depths, /* supported depths */ + VisualID rootVisual, /* root visual */ + int numVisuals, /* number of visuals supported */ + VisualRec *visuals /* supported visuals */ + ) +{ + pScreen->width = xsize; + pScreen->height = ysize; + pScreen->mmWidth = (xsize * 254 + dpix * 5) / (dpix * 10); + pScreen->mmHeight = (ysize * 254 + dpiy * 5) / (dpiy * 10); + pScreen->numDepths = numDepths; + pScreen->rootDepth = rootDepth; + pScreen->allowedDepths = depths; + pScreen->rootVisual = rootVisual; + /* defColormap */ + pScreen->minInstalledCmaps = 1; + pScreen->maxInstalledCmaps = 1; + pScreen->backingStoreSupport = NotUseful; + pScreen->saveUnderSupport = NotUseful; + /* whitePixel, blackPixel */ + pScreen->ModifyPixmapHeader = miModifyPixmapHeader; + pScreen->CreateScreenResources = miCreateScreenResources; + pScreen->GetScreenPixmap = miGetScreenPixmap; + pScreen->SetScreenPixmap = miSetScreenPixmap; + pScreen->numVisuals = numVisuals; + pScreen->visuals = visuals; + if (width) + { +#ifdef MITSHM + ShmRegisterFbFuncs(pScreen); +#endif + pScreen->CloseScreen = miCloseScreen; + } + /* else CloseScreen */ + /* QueryBestSize, SaveScreen, GetImage, GetSpans */ + pScreen->SourceValidate = (SourceValidateProcPtr) 0; + /* CreateWindow, DestroyWindow, PositionWindow, ChangeWindowAttributes */ + /* RealizeWindow, UnrealizeWindow */ + pScreen->ValidateTree = miValidateTree; + pScreen->PostValidateTree = (PostValidateTreeProcPtr) 0; + pScreen->WindowExposures = miWindowExposures; + /* CopyWindow */ + pScreen->ClearToBackground = miClearToBackground; + pScreen->ClipNotify = (ClipNotifyProcPtr) 0; + pScreen->RestackWindow = (RestackWindowProcPtr) 0; + /* CreatePixmap, DestroyPixmap */ + /* RealizeFont, UnrealizeFont */ + /* CreateGC */ + /* CreateColormap, DestroyColormap, InstallColormap, UninstallColormap */ + /* ListInstalledColormaps, StoreColors, ResolveColor */ + /* BitmapToRegion */ + pScreen->SendGraphicsExpose = miSendGraphicsExpose; + pScreen->BlockHandler = (ScreenBlockHandlerProcPtr)NoopDDA; + pScreen->WakeupHandler = (ScreenWakeupHandlerProcPtr)NoopDDA; + pScreen->blockData = (pointer)0; + pScreen->wakeupData = (pointer)0; + pScreen->MarkWindow = miMarkWindow; + pScreen->MarkOverlappedWindows = miMarkOverlappedWindows; + pScreen->ChangeSaveUnder = NULL; + pScreen->PostChangeSaveUnder = NULL; + pScreen->MoveWindow = miMoveWindow; + pScreen->ResizeWindow = miSlideAndSizeWindow; + pScreen->GetLayerWindow = miGetLayerWindow; + pScreen->HandleExposures = miHandleValidateExposures; + pScreen->ReparentWindow = (ReparentWindowProcPtr) 0; + pScreen->ChangeBorderWidth = miChangeBorderWidth; + pScreen->SetShape = miSetShape; + pScreen->MarkUnrealizedWindow = miMarkUnrealizedWindow; + + pScreen->SaveDoomedAreas = 0; + pScreen->RestoreAreas = 0; + pScreen->ExposeCopy = 0; + pScreen->TranslateBackingStore = 0; + pScreen->ClearBackingStore = 0; + pScreen->DrawGuarantee = 0; + + miSetZeroLineBias(pScreen, DEFAULTZEROLINEBIAS); + + return miScreenDevPrivateInit(pScreen, width, pbits); +} + +static int privateKeyIndex; +static DevPrivateKey privateKey = &privateKeyIndex; + +DevPrivateKey +miAllocateGCPrivateIndex(void) +{ + return privateKey; +} + +static int miZeroLineScreenKeyIndex; +DevPrivateKey miZeroLineScreenKey = &miZeroLineScreenKeyIndex; + +void +miSetZeroLineBias(ScreenPtr pScreen, unsigned int bias) +{ + dixSetPrivate(&pScreen->devPrivates, miZeroLineScreenKey, + (unsigned long *)(unsigned long)bias); +} diff --git a/xorg-server/mi/mispans.c b/xorg-server/mi/mispans.c index 5504341c4..7b332ee34 100644 --- a/xorg-server/mi/mispans.c +++ b/xorg-server/mi/mispans.c @@ -1,529 +1,529 @@ -/*********************************************************** - -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. - - -Copyright 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. - -******************************************************************/ - - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "misc.h" -#include "pixmapstr.h" -#include "gcstruct.h" -#include "mispans.h" - -/* - -These routines maintain lists of Spans, in order to implement the -``touch-each-pixel-once'' rules of wide lines and arcs. - -Written by Joel McCormack, Summer 1989. - -*/ - - -void miInitSpanGroup(SpanGroup *spanGroup) -{ - spanGroup->size = 0; - spanGroup->count = 0; - spanGroup->group = NULL; - spanGroup->ymin = MAXSHORT; - spanGroup->ymax = MINSHORT; -} /* InitSpanGroup */ - -#define YMIN(spans) (spans->points[0].y) -#define YMAX(spans) (spans->points[spans->count-1].y) - -static void miSubtractSpans (SpanGroup *spanGroup, Spans *sub) -{ - int i, subCount, spansCount; - int ymin, ymax, xmin, xmax; - Spans *spans; - DDXPointPtr subPt, spansPt; - int *subWid, *spansWid; - int extra; - - ymin = YMIN(sub); - ymax = YMAX(sub); - spans = spanGroup->group; - for (i = spanGroup->count; i; i--, spans++) { - if (YMIN(spans) <= ymax && ymin <= YMAX(spans)) { - subCount = sub->count; - subPt = sub->points; - subWid = sub->widths; - spansCount = spans->count; - spansPt = spans->points; - spansWid = spans->widths; - extra = 0; - for (;;) - { - while (spansCount && spansPt->y < subPt->y) - { - spansPt++; spansWid++; spansCount--; - } - if (!spansCount) - break; - while (subCount && subPt->y < spansPt->y) - { - subPt++; subWid++; subCount--; - } - if (!subCount) - break; - if (subPt->y == spansPt->y) - { - xmin = subPt->x; - xmax = xmin + *subWid; - if (xmin >= spansPt->x + *spansWid || spansPt->x >= xmax) - { - ; - } - else if (xmin <= spansPt->x) - { - if (xmax >= spansPt->x + *spansWid) - { - memmove (spansPt, spansPt + 1, sizeof *spansPt * (spansCount - 1)); - memmove (spansWid, spansWid + 1, sizeof *spansWid * (spansCount - 1)); - spansPt--; - spansWid--; - spans->count--; - extra++; - } - else - { - *spansWid = *spansWid - (xmax - spansPt->x); - spansPt->x = xmax; - } - } - else - { - if (xmax >= spansPt->x + *spansWid) - { - *spansWid = xmin - spansPt->x; - } - else - { - if (!extra) { - DDXPointPtr newPt; - int *newwid; - -#define EXTRA 8 - newPt = (DDXPointPtr) xrealloc (spans->points, (spans->count + EXTRA) * sizeof (DDXPointRec)); - if (!newPt) - break; - spansPt = newPt + (spansPt - spans->points); - spans->points = newPt; - newwid = (int *) xrealloc (spans->widths, (spans->count + EXTRA) * sizeof (int)); - if (!newwid) - break; - spansWid = newwid + (spansWid - spans->widths); - spans->widths = newwid; - extra = EXTRA; - } - memmove (spansPt + 1, spansPt, sizeof *spansPt * (spansCount)); - memmove (spansWid + 1, spansWid, sizeof *spansWid * (spansCount)); - spans->count++; - extra--; - *spansWid = xmin - spansPt->x; - spansWid++; - spansPt++; - *spansWid = *spansWid - (xmax - spansPt->x); - spansPt->x = xmax; - } - } - } - spansPt++; spansWid++; spansCount--; - } - } - } -} - -void miAppendSpans(SpanGroup *spanGroup, SpanGroup *otherGroup, Spans *spans) -{ - int ymin, ymax; - int spansCount; - - spansCount = spans->count; - if (spansCount > 0) { - if (spanGroup->size == spanGroup->count) { - spanGroup->size = (spanGroup->size + 8) * 2; - spanGroup->group = (Spans *) - xrealloc(spanGroup->group, sizeof(Spans) * spanGroup->size); - } - - spanGroup->group[spanGroup->count] = *spans; - (spanGroup->count)++; - ymin = spans->points[0].y; - if (ymin < spanGroup->ymin) spanGroup->ymin = ymin; - ymax = spans->points[spansCount - 1].y; - if (ymax > spanGroup->ymax) spanGroup->ymax = ymax; - if (otherGroup && - otherGroup->ymin < ymax && - ymin < otherGroup->ymax) - { - miSubtractSpans (otherGroup, spans); - } - } - else - { - xfree (spans->points); - xfree (spans->widths); - } -} /* AppendSpans */ - -void miFreeSpanGroup(SpanGroup *spanGroup) -{ - if (spanGroup->group != NULL) xfree(spanGroup->group); -} - -static void QuickSortSpansX( - DDXPointRec points[], - int widths[], - int numSpans ) -{ - int x; - int i, j, m; - DDXPointPtr r; - -/* Always called with numSpans > 1 */ -/* Sorts only by x, as all y should be the same */ - -#define ExchangeSpans(a, b) \ -{ \ - DDXPointRec tpt; \ - int tw; \ - \ - tpt = points[a]; points[a] = points[b]; points[b] = tpt; \ - tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \ -} - - do { - if (numSpans < 9) { - /* Do insertion sort */ - int xprev; - - xprev = points[0].x; - i = 1; - do { /* while i != numSpans */ - x = points[i].x; - if (xprev > x) { - /* points[i] is out of order. Move into proper location. */ - DDXPointRec tpt; - int tw, k; - - for (j = 0; x >= points[j].x; j++) {} - tpt = points[i]; - tw = widths[i]; - for (k = i; k != j; k--) { - points[k] = points[k-1]; - widths[k] = widths[k-1]; - } - points[j] = tpt; - widths[j] = tw; - x = points[i].x; - } /* if out of order */ - xprev = x; - i++; - } while (i != numSpans); - return; - } - - /* Choose partition element, stick in location 0 */ - m = numSpans / 2; - if (points[m].x > points[0].x) ExchangeSpans(m, 0); - if (points[m].x > points[numSpans-1].x) ExchangeSpans(m, numSpans-1); - if (points[m].x > points[0].x) ExchangeSpans(m, 0); - x = points[0].x; - - /* Partition array */ - i = 0; - j = numSpans; - do { - r = &(points[i]); - do { - r++; - i++; - } while (i != numSpans && r->x < x); - r = &(points[j]); - do { - r--; - j--; - } while (x < r->x); - if (i < j) ExchangeSpans(i, j); - } while (i < j); - - /* Move partition element back to middle */ - ExchangeSpans(0, j); - - /* Recurse */ - if (numSpans-j-1 > 1) - QuickSortSpansX(&points[j+1], &widths[j+1], numSpans-j-1); - numSpans = j; - } while (numSpans > 1); -} /* QuickSortSpans */ - - -static int UniquifySpansX( - Spans *spans, - DDXPointRec *newPoints, - int *newWidths ) -{ - int newx1, newx2, oldpt, i, y; - DDXPointRec *oldPoints; - int *oldWidths; - int *startNewWidths; - -/* Always called with numSpans > 1 */ -/* Uniquify the spans, and stash them into newPoints and newWidths. Return the - number of unique spans. */ - - - startNewWidths = newWidths; - - oldPoints = spans->points; - oldWidths = spans->widths; - - y = oldPoints->y; - newx1 = oldPoints->x; - newx2 = newx1 + *oldWidths; - - for (i = spans->count-1; i != 0; i--) { - oldPoints++; - oldWidths++; - oldpt = oldPoints->x; - if (oldpt > newx2) { - /* Write current span, start a new one */ - newPoints->x = newx1; - newPoints->y = y; - *newWidths = newx2 - newx1; - newPoints++; - newWidths++; - newx1 = oldpt; - newx2 = oldpt + *oldWidths; - } else { - /* extend current span, if old extends beyond new */ - oldpt = oldpt + *oldWidths; - if (oldpt > newx2) newx2 = oldpt; - } - } /* for */ - - /* Write final span */ - newPoints->x = newx1; - *newWidths = newx2 - newx1; - newPoints->y = y; - - return (newWidths - startNewWidths) + 1; -} /* UniquifySpansX */ - -static void -miDisposeSpanGroup (SpanGroup *spanGroup) -{ - int i; - Spans *spans; - - for (i = 0; i < spanGroup->count; i++) - { - spans = spanGroup->group + i; - xfree (spans->points); - xfree (spans->widths); - } -} - -void miFillUniqueSpanGroup(DrawablePtr pDraw, GCPtr pGC, SpanGroup *spanGroup) -{ - int i; - Spans *spans; - Spans *yspans; - int *ysizes; - int ymin, ylength; - - /* Outgoing spans for one big call to FillSpans */ - DDXPointPtr points; - int *widths; - int count; - - if (spanGroup->count == 0) return; - - if (spanGroup->count == 1) { - /* Already should be sorted, unique */ - spans = spanGroup->group; - (*pGC->ops->FillSpans) - (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE); - xfree(spans->points); - xfree(spans->widths); - } - else - { - /* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */ - /* This seems to be the fastest thing to do. I've tried sorting on - both x and y at the same time rather than creating into all those - y buckets, but it was somewhat slower. */ - - ymin = spanGroup->ymin; - ylength = spanGroup->ymax - ymin + 1; - - /* Allocate Spans for y buckets */ - yspans = xalloc(ylength * sizeof(Spans)); - ysizes = xalloc(ylength * sizeof (int)); - - if (!yspans || !ysizes) - { - if (yspans) - xfree (yspans); - if (ysizes) - xfree (ysizes); - miDisposeSpanGroup (spanGroup); - return; - } - - for (i = 0; i != ylength; i++) { - ysizes[i] = 0; - yspans[i].count = 0; - yspans[i].points = NULL; - yspans[i].widths = NULL; - } - - /* Go through every single span and put it into the correct bucket */ - count = 0; - for (i = 0, spans = spanGroup->group; - i != spanGroup->count; - i++, spans++) { - int index; - int j; - - for (j = 0, points = spans->points, widths = spans->widths; - j != spans->count; - j++, points++, widths++) { - index = points->y - ymin; - if (index >= 0 && index < ylength) { - Spans *newspans = &(yspans[index]); - if (newspans->count == ysizes[index]) { - DDXPointPtr newpoints; - int *newwidths; - ysizes[index] = (ysizes[index] + 8) * 2; - newpoints = (DDXPointPtr) xrealloc( - newspans->points, - ysizes[index] * sizeof(DDXPointRec)); - newwidths = (int *) xrealloc( - newspans->widths, - ysizes[index] * sizeof(int)); - if (!newpoints || !newwidths) - { - int i; - - for (i = 0; i < ylength; i++) - { - xfree (yspans[i].points); - xfree (yspans[i].widths); - } - xfree (yspans); - xfree (ysizes); - miDisposeSpanGroup (spanGroup); - return; - } - newspans->points = newpoints; - newspans->widths = newwidths; - } - newspans->points[newspans->count] = *points; - newspans->widths[newspans->count] = *widths; - (newspans->count)++; - } /* if y value of span in range */ - } /* for j through spans */ - count += spans->count; - xfree(spans->points); - spans->points = NULL; - xfree(spans->widths); - spans->widths = NULL; - } /* for i thorough Spans */ - - /* Now sort by x and uniquify each bucket into the final array */ - points = xalloc(count * sizeof(DDXPointRec)); - widths = xalloc(count * sizeof(int)); - if (!points || !widths) - { - int i; - - for (i = 0; i < ylength; i++) - { - xfree (yspans[i].points); - xfree (yspans[i].widths); - } - xfree (yspans); - xfree (ysizes); - if (points) - xfree (points); - if (widths) - xfree (widths); - return; - } - count = 0; - for (i = 0; i != ylength; i++) { - int ycount = yspans[i].count; - if (ycount > 0) { - if (ycount > 1) { - QuickSortSpansX(yspans[i].points, yspans[i].widths, ycount); - count += UniquifySpansX - (&(yspans[i]), &(points[count]), &(widths[count])); - } else { - points[count] = yspans[i].points[0]; - widths[count] = yspans[i].widths[0]; - count++; - } - xfree(yspans[i].points); - xfree(yspans[i].widths); - } - } - - (*pGC->ops->FillSpans) (pDraw, pGC, count, points, widths, TRUE); - xfree(points); - xfree(widths); - xfree(yspans); - xfree(ysizes); /* use (DE)xalloc for these? */ - } - - spanGroup->count = 0; - spanGroup->ymin = MAXSHORT; - spanGroup->ymax = MINSHORT; -} +/*********************************************************** + +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. + + +Copyright 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. + +******************************************************************/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "misc.h" +#include "pixmapstr.h" +#include "gcstruct.h" +#include "mispans.h" + +/* + +These routines maintain lists of Spans, in order to implement the +``touch-each-pixel-once'' rules of wide lines and arcs. + +Written by Joel McCormack, Summer 1989. + +*/ + + +void miInitSpanGroup(SpanGroup *spanGroup) +{ + spanGroup->size = 0; + spanGroup->count = 0; + spanGroup->group = NULL; + spanGroup->ymin = MAXSHORT; + spanGroup->ymax = MINSHORT; +} /* InitSpanGroup */ + +#define YMIN(spans) (spans->points[0].y) +#define YMAX(spans) (spans->points[spans->count-1].y) + +static void miSubtractSpans (SpanGroup *spanGroup, Spans *sub) +{ + int i, subCount, spansCount; + int ymin, ymax, xmin, xmax; + Spans *spans; + DDXPointPtr subPt, spansPt; + int *subWid, *spansWid; + int extra; + + ymin = YMIN(sub); + ymax = YMAX(sub); + spans = spanGroup->group; + for (i = spanGroup->count; i; i--, spans++) { + if (YMIN(spans) <= ymax && ymin <= YMAX(spans)) { + subCount = sub->count; + subPt = sub->points; + subWid = sub->widths; + spansCount = spans->count; + spansPt = spans->points; + spansWid = spans->widths; + extra = 0; + for (;;) + { + while (spansCount && spansPt->y < subPt->y) + { + spansPt++; spansWid++; spansCount--; + } + if (!spansCount) + break; + while (subCount && subPt->y < spansPt->y) + { + subPt++; subWid++; subCount--; + } + if (!subCount) + break; + if (subPt->y == spansPt->y) + { + xmin = subPt->x; + xmax = xmin + *subWid; + if (xmin >= spansPt->x + *spansWid || spansPt->x >= xmax) + { + ; + } + else if (xmin <= spansPt->x) + { + if (xmax >= spansPt->x + *spansWid) + { + memmove (spansPt, spansPt + 1, sizeof *spansPt * (spansCount - 1)); + memmove (spansWid, spansWid + 1, sizeof *spansWid * (spansCount - 1)); + spansPt--; + spansWid--; + spans->count--; + extra++; + } + else + { + *spansWid = *spansWid - (xmax - spansPt->x); + spansPt->x = xmax; + } + } + else + { + if (xmax >= spansPt->x + *spansWid) + { + *spansWid = xmin - spansPt->x; + } + else + { + if (!extra) { + DDXPointPtr newPt; + int *newwid; + +#define EXTRA 8 + newPt = (DDXPointPtr) realloc(spans->points, (spans->count + EXTRA) * sizeof (DDXPointRec)); + if (!newPt) + break; + spansPt = newPt + (spansPt - spans->points); + spans->points = newPt; + newwid = (int *) realloc(spans->widths, (spans->count + EXTRA) * sizeof (int)); + if (!newwid) + break; + spansWid = newwid + (spansWid - spans->widths); + spans->widths = newwid; + extra = EXTRA; + } + memmove (spansPt + 1, spansPt, sizeof *spansPt * (spansCount)); + memmove (spansWid + 1, spansWid, sizeof *spansWid * (spansCount)); + spans->count++; + extra--; + *spansWid = xmin - spansPt->x; + spansWid++; + spansPt++; + *spansWid = *spansWid - (xmax - spansPt->x); + spansPt->x = xmax; + } + } + } + spansPt++; spansWid++; spansCount--; + } + } + } +} + +void miAppendSpans(SpanGroup *spanGroup, SpanGroup *otherGroup, Spans *spans) +{ + int ymin, ymax; + int spansCount; + + spansCount = spans->count; + if (spansCount > 0) { + if (spanGroup->size == spanGroup->count) { + spanGroup->size = (spanGroup->size + 8) * 2; + spanGroup->group = (Spans *) + realloc(spanGroup->group, sizeof(Spans) * spanGroup->size); + } + + spanGroup->group[spanGroup->count] = *spans; + (spanGroup->count)++; + ymin = spans->points[0].y; + if (ymin < spanGroup->ymin) spanGroup->ymin = ymin; + ymax = spans->points[spansCount - 1].y; + if (ymax > spanGroup->ymax) spanGroup->ymax = ymax; + if (otherGroup && + otherGroup->ymin < ymax && + ymin < otherGroup->ymax) + { + miSubtractSpans (otherGroup, spans); + } + } + else + { + free(spans->points); + free(spans->widths); + } +} /* AppendSpans */ + +void miFreeSpanGroup(SpanGroup *spanGroup) +{ + if (spanGroup->group != NULL) free(spanGroup->group); +} + +static void QuickSortSpansX( + DDXPointRec points[], + int widths[], + int numSpans ) +{ + int x; + int i, j, m; + DDXPointPtr r; + +/* Always called with numSpans > 1 */ +/* Sorts only by x, as all y should be the same */ + +#define ExchangeSpans(a, b) \ +{ \ + DDXPointRec tpt; \ + int tw; \ + \ + tpt = points[a]; points[a] = points[b]; points[b] = tpt; \ + tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \ +} + + do { + if (numSpans < 9) { + /* Do insertion sort */ + int xprev; + + xprev = points[0].x; + i = 1; + do { /* while i != numSpans */ + x = points[i].x; + if (xprev > x) { + /* points[i] is out of order. Move into proper location. */ + DDXPointRec tpt; + int tw, k; + + for (j = 0; x >= points[j].x; j++) {} + tpt = points[i]; + tw = widths[i]; + for (k = i; k != j; k--) { + points[k] = points[k-1]; + widths[k] = widths[k-1]; + } + points[j] = tpt; + widths[j] = tw; + x = points[i].x; + } /* if out of order */ + xprev = x; + i++; + } while (i != numSpans); + return; + } + + /* Choose partition element, stick in location 0 */ + m = numSpans / 2; + if (points[m].x > points[0].x) ExchangeSpans(m, 0); + if (points[m].x > points[numSpans-1].x) ExchangeSpans(m, numSpans-1); + if (points[m].x > points[0].x) ExchangeSpans(m, 0); + x = points[0].x; + + /* Partition array */ + i = 0; + j = numSpans; + do { + r = &(points[i]); + do { + r++; + i++; + } while (i != numSpans && r->x < x); + r = &(points[j]); + do { + r--; + j--; + } while (x < r->x); + if (i < j) ExchangeSpans(i, j); + } while (i < j); + + /* Move partition element back to middle */ + ExchangeSpans(0, j); + + /* Recurse */ + if (numSpans-j-1 > 1) + QuickSortSpansX(&points[j+1], &widths[j+1], numSpans-j-1); + numSpans = j; + } while (numSpans > 1); +} /* QuickSortSpans */ + + +static int UniquifySpansX( + Spans *spans, + DDXPointRec *newPoints, + int *newWidths ) +{ + int newx1, newx2, oldpt, i, y; + DDXPointRec *oldPoints; + int *oldWidths; + int *startNewWidths; + +/* Always called with numSpans > 1 */ +/* Uniquify the spans, and stash them into newPoints and newWidths. Return the + number of unique spans. */ + + + startNewWidths = newWidths; + + oldPoints = spans->points; + oldWidths = spans->widths; + + y = oldPoints->y; + newx1 = oldPoints->x; + newx2 = newx1 + *oldWidths; + + for (i = spans->count-1; i != 0; i--) { + oldPoints++; + oldWidths++; + oldpt = oldPoints->x; + if (oldpt > newx2) { + /* Write current span, start a new one */ + newPoints->x = newx1; + newPoints->y = y; + *newWidths = newx2 - newx1; + newPoints++; + newWidths++; + newx1 = oldpt; + newx2 = oldpt + *oldWidths; + } else { + /* extend current span, if old extends beyond new */ + oldpt = oldpt + *oldWidths; + if (oldpt > newx2) newx2 = oldpt; + } + } /* for */ + + /* Write final span */ + newPoints->x = newx1; + *newWidths = newx2 - newx1; + newPoints->y = y; + + return (newWidths - startNewWidths) + 1; +} /* UniquifySpansX */ + +static void +miDisposeSpanGroup (SpanGroup *spanGroup) +{ + int i; + Spans *spans; + + for (i = 0; i < spanGroup->count; i++) + { + spans = spanGroup->group + i; + free(spans->points); + free(spans->widths); + } +} + +void miFillUniqueSpanGroup(DrawablePtr pDraw, GCPtr pGC, SpanGroup *spanGroup) +{ + int i; + Spans *spans; + Spans *yspans; + int *ysizes; + int ymin, ylength; + + /* Outgoing spans for one big call to FillSpans */ + DDXPointPtr points; + int *widths; + int count; + + if (spanGroup->count == 0) return; + + if (spanGroup->count == 1) { + /* Already should be sorted, unique */ + spans = spanGroup->group; + (*pGC->ops->FillSpans) + (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE); + free(spans->points); + free(spans->widths); + } + else + { + /* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */ + /* This seems to be the fastest thing to do. I've tried sorting on + both x and y at the same time rather than creating into all those + y buckets, but it was somewhat slower. */ + + ymin = spanGroup->ymin; + ylength = spanGroup->ymax - ymin + 1; + + /* Allocate Spans for y buckets */ + yspans = malloc(ylength * sizeof(Spans)); + ysizes = malloc(ylength * sizeof (int)); + + if (!yspans || !ysizes) + { + if (yspans) + free(yspans); + if (ysizes) + free(ysizes); + miDisposeSpanGroup (spanGroup); + return; + } + + for (i = 0; i != ylength; i++) { + ysizes[i] = 0; + yspans[i].count = 0; + yspans[i].points = NULL; + yspans[i].widths = NULL; + } + + /* Go through every single span and put it into the correct bucket */ + count = 0; + for (i = 0, spans = spanGroup->group; + i != spanGroup->count; + i++, spans++) { + int index; + int j; + + for (j = 0, points = spans->points, widths = spans->widths; + j != spans->count; + j++, points++, widths++) { + index = points->y - ymin; + if (index >= 0 && index < ylength) { + Spans *newspans = &(yspans[index]); + if (newspans->count == ysizes[index]) { + DDXPointPtr newpoints; + int *newwidths; + ysizes[index] = (ysizes[index] + 8) * 2; + newpoints = (DDXPointPtr) realloc( + newspans->points, + ysizes[index] * sizeof(DDXPointRec)); + newwidths = (int *) realloc( + newspans->widths, + ysizes[index] * sizeof(int)); + if (!newpoints || !newwidths) + { + int i; + + for (i = 0; i < ylength; i++) + { + free(yspans[i].points); + free(yspans[i].widths); + } + free(yspans); + free(ysizes); + miDisposeSpanGroup (spanGroup); + return; + } + newspans->points = newpoints; + newspans->widths = newwidths; + } + newspans->points[newspans->count] = *points; + newspans->widths[newspans->count] = *widths; + (newspans->count)++; + } /* if y value of span in range */ + } /* for j through spans */ + count += spans->count; + free(spans->points); + spans->points = NULL; + free(spans->widths); + spans->widths = NULL; + } /* for i thorough Spans */ + + /* Now sort by x and uniquify each bucket into the final array */ + points = malloc(count * sizeof(DDXPointRec)); + widths = malloc(count * sizeof(int)); + if (!points || !widths) + { + int i; + + for (i = 0; i < ylength; i++) + { + free(yspans[i].points); + free(yspans[i].widths); + } + free(yspans); + free(ysizes); + if (points) + free(points); + if (widths) + free(widths); + return; + } + count = 0; + for (i = 0; i != ylength; i++) { + int ycount = yspans[i].count; + if (ycount > 0) { + if (ycount > 1) { + QuickSortSpansX(yspans[i].points, yspans[i].widths, ycount); + count += UniquifySpansX + (&(yspans[i]), &(points[count]), &(widths[count])); + } else { + points[count] = yspans[i].points[0]; + widths[count] = yspans[i].widths[0]; + count++; + } + free(yspans[i].points); + free(yspans[i].widths); + } + } + + (*pGC->ops->FillSpans) (pDraw, pGC, count, points, widths, TRUE); + free(points); + free(widths); + free(yspans); + free(ysizes); /* use (DE)xalloc for these? */ + } + + spanGroup->count = 0; + spanGroup->ymin = MAXSHORT; + spanGroup->ymax = MINSHORT; +} diff --git a/xorg-server/mi/misprite.c b/xorg-server/mi/misprite.c index ac025e1ff..b0f7ecd39 100644 --- a/xorg-server/mi/misprite.c +++ b/xorg-server/mi/misprite.c @@ -1,1115 +1,1115 @@ -/* - * misprite.c - * - * machine independent software sprite routines - */ - -/* - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "pixmapstr.h" -#include "input.h" -#include "mi.h" -#include "cursorstr.h" -#include <X11/fonts/font.h> -#include "scrnintstr.h" -#include "colormapst.h" -#include "windowstr.h" -#include "gcstruct.h" -#include "mipointer.h" -#include "misprite.h" -#include "dixfontstr.h" -#include <X11/fonts/fontstruct.h> -#include "inputstr.h" -#include "damage.h" - -typedef struct { - CursorPtr pCursor; - int x; /* cursor hotspot */ - int y; - BoxRec saved; /* saved area from the screen */ - Bool isUp; /* cursor in frame buffer */ - Bool shouldBeUp; /* cursor should be displayed */ - WindowPtr pCacheWin; /* window the cursor last seen in */ - Bool isInCacheWin; - Bool checkPixels; /* check colormap collision */ - ScreenPtr pScreen; -} miCursorInfoRec, *miCursorInfoPtr; - -/* - * per screen information - */ - -typedef struct { - /* screen procedures */ - CloseScreenProcPtr CloseScreen; - GetImageProcPtr GetImage; - GetSpansProcPtr GetSpans; - SourceValidateProcPtr SourceValidate; - - /* window procedures */ - CopyWindowProcPtr CopyWindow; - - /* colormap procedures */ - InstallColormapProcPtr InstallColormap; - StoreColorsProcPtr StoreColors; - - /* os layer procedures */ - ScreenBlockHandlerProcPtr BlockHandler; - - /* device cursor procedures */ - DeviceCursorInitializeProcPtr DeviceCursorInitialize; - DeviceCursorCleanupProcPtr DeviceCursorCleanup; - - xColorItem colors[2]; - ColormapPtr pInstalledMap; - ColormapPtr pColormap; - VisualPtr pVisual; - miSpriteCursorFuncPtr funcs; - DamagePtr pDamage; /* damage tracking structure */ - Bool damageRegistered; -} miSpriteScreenRec, *miSpriteScreenPtr; - -#define SOURCE_COLOR 0 -#define MASK_COLOR 1 - -/* - * Overlap BoxPtr and Box elements - */ -#define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \ - (((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \ - ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2)) - -/* - * Overlap BoxPtr, origins, and rectangle - */ -#define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \ - BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h)) - -/* - * Overlap BoxPtr, origins and RectPtr - */ -#define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \ - ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \ - (int)((pRect)->width), (int)((pRect)->height)) -/* - * Overlap BoxPtr and horizontal span - */ -#define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y)) - -#define LINE_SORT(x1,y1,x2,y2) \ -{ int _t; \ - if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \ - if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } } - -#define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \ - BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2)) - - -#define SPRITE_DEBUG_ENABLE 0 -#if SPRITE_DEBUG_ENABLE -#define SPRITE_DEBUG(x) ErrorF x -#else -#define SPRITE_DEBUG(x) -#endif - -#define MISPRITE(dev) \ - ((!IsMaster(dev) && !dev->u.master) ? \ - (miCursorInfoPtr)dixLookupPrivate(&dev->devPrivates, miSpriteDevPrivatesKey) : \ - (miCursorInfoPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miSpriteDevPrivatesKey)) - -static void -miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) -{ - if (pScreenPriv->damageRegistered) { - DamageUnregister (&(pScreen->GetScreenPixmap(pScreen)->drawable), - pScreenPriv->pDamage); - pScreenPriv->damageRegistered = 0; - } -} - -static void -miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) -{ - if (!pScreenPriv->damageRegistered) { - pScreenPriv->damageRegistered = 1; - DamageRegister (&(pScreen->GetScreenPixmap(pScreen)->drawable), - pScreenPriv->pDamage); - } -} - -static void -miSpriteIsUp(miCursorInfoPtr pDevCursor) -{ - pDevCursor->isUp = TRUE; -} - -static void -miSpriteIsDown(miCursorInfoPtr pDevCursor) -{ - pDevCursor->isUp = FALSE; -} - -/* - * screen wrappers - */ - -static int miSpriteScreenKeyIndex; -static DevPrivateKey miSpriteScreenKey = &miSpriteScreenKeyIndex; -static int miSpriteDevPrivatesKeyIndex; -static DevPrivateKey miSpriteDevPrivatesKey = &miSpriteDevPrivatesKeyIndex; - -static Bool miSpriteCloseScreen(int i, ScreenPtr pScreen); -static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, - int w, int h, unsigned int format, - unsigned long planemask, char *pdstLine); -static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax, - DDXPointPtr ppt, int *pwidth, int nspans, - char *pdstStart); -static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, - int width, int height); -static void miSpriteCopyWindow (WindowPtr pWindow, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc); -static void miSpriteBlockHandler(int i, pointer blockData, - pointer pTimeout, - pointer pReadMask); -static void miSpriteInstallColormap(ColormapPtr pMap); -static void miSpriteStoreColors(ColormapPtr pMap, int ndef, - xColorItem *pdef); - -static void miSpriteComputeSaved(DeviceIntPtr pDev, - ScreenPtr pScreen); - -static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, - ScreenPtr pScreen); -static void miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, - ScreenPtr pScreen); - -#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \ - ((miSpriteScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, \ - miSpriteScreenKey))->field) -#define SCREEN_EPILOGUE(pScreen, field)\ - ((pScreen)->field = miSprite##field) - -/* - * pointer-sprite method table - */ - -static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor); -static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor); -static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor, int x, int y); -static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y); - -miPointerSpriteFuncRec miSpritePointerFuncs = { - miSpriteRealizeCursor, - miSpriteUnrealizeCursor, - miSpriteSetCursor, - miSpriteMoveCursor, - miSpriteDeviceCursorInitialize, - miSpriteDeviceCursorCleanup, -}; - -/* - * other misc functions - */ - -static void miSpriteRemoveCursor(DeviceIntPtr pDev, - ScreenPtr pScreen); -static void miSpriteSaveUnderCursor(DeviceIntPtr pDev, - ScreenPtr pScreen); -static void miSpriteRestoreCursor(DeviceIntPtr pDev, - ScreenPtr pScreen); - -static void -miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) -{ - ScreenPtr pScreen = closure; - miSpriteScreenPtr pScreenPriv; - miCursorInfoPtr pCursorInfo; - DeviceIntPtr pDev; - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pCursorInfo = MISPRITE(pDev); - - if (pCursorInfo->isUp && - pCursorInfo->pScreen == pScreen && - miRectIn(pRegion, &pCursorInfo->saved) != rgnOUT) - { - SPRITE_DEBUG(("Damage remove\n")); - miSpriteRemoveCursor (pDev, pScreen); - } - } - } -} - -/* - * miSpriteInitialize -- called from device-dependent screen - * initialization proc after all of the function pointers have - * been stored in the screen structure. - */ - -Bool -miSpriteInitialize (ScreenPtr pScreen, - miSpriteCursorFuncPtr cursorFuncs, - miPointerScreenFuncPtr screenFuncs) -{ - miSpriteScreenPtr pScreenPriv; - VisualPtr pVisual; - - if (!DamageSetup (pScreen)) - return FALSE; - - pScreenPriv = xalloc (sizeof (miSpriteScreenRec)); - if (!pScreenPriv) - return FALSE; - - pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage, - NULL, - DamageReportRawRegion, - TRUE, - pScreen, - pScreen); - - if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE)) - { - xfree (pScreenPriv); - return FALSE; - } - for (pVisual = pScreen->visuals; - pVisual->vid != pScreen->rootVisual; - pVisual++) - ; - pScreenPriv->pVisual = pVisual; - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreenPriv->GetImage = pScreen->GetImage; - pScreenPriv->GetSpans = pScreen->GetSpans; - pScreenPriv->SourceValidate = pScreen->SourceValidate; - - pScreenPriv->CopyWindow = pScreen->CopyWindow; - - pScreenPriv->InstallColormap = pScreen->InstallColormap; - pScreenPriv->StoreColors = pScreen->StoreColors; - - pScreenPriv->BlockHandler = pScreen->BlockHandler; - - pScreenPriv->DeviceCursorInitialize = pScreen->DeviceCursorInitialize; - pScreenPriv->DeviceCursorCleanup = pScreen->DeviceCursorCleanup; - - pScreenPriv->pInstalledMap = NULL; - pScreenPriv->pColormap = NULL; - pScreenPriv->funcs = cursorFuncs; - pScreenPriv->colors[SOURCE_COLOR].red = 0; - pScreenPriv->colors[SOURCE_COLOR].green = 0; - pScreenPriv->colors[SOURCE_COLOR].blue = 0; - pScreenPriv->colors[MASK_COLOR].red = 0; - pScreenPriv->colors[MASK_COLOR].green = 0; - pScreenPriv->colors[MASK_COLOR].blue = 0; - pScreenPriv->damageRegistered = 0; - - dixSetPrivate(&pScreen->devPrivates, miSpriteScreenKey, pScreenPriv); - - pScreen->CloseScreen = miSpriteCloseScreen; - pScreen->GetImage = miSpriteGetImage; - pScreen->GetSpans = miSpriteGetSpans; - pScreen->SourceValidate = miSpriteSourceValidate; - - pScreen->CopyWindow = miSpriteCopyWindow; - pScreen->InstallColormap = miSpriteInstallColormap; - pScreen->StoreColors = miSpriteStoreColors; - - pScreen->BlockHandler = miSpriteBlockHandler; - - return TRUE; -} - -/* - * Screen wrappers - */ - -/* - * CloseScreen wrapper -- unwrap everything, free the private data - * and call the wrapped function - */ - -static Bool -miSpriteCloseScreen (int i, ScreenPtr pScreen) -{ - miSpriteScreenPtr pScreenPriv; - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - pScreen->CloseScreen = pScreenPriv->CloseScreen; - pScreen->GetImage = pScreenPriv->GetImage; - pScreen->GetSpans = pScreenPriv->GetSpans; - pScreen->SourceValidate = pScreenPriv->SourceValidate; - pScreen->BlockHandler = pScreenPriv->BlockHandler; - pScreen->InstallColormap = pScreenPriv->InstallColormap; - pScreen->StoreColors = pScreenPriv->StoreColors; - - DamageDestroy (pScreenPriv->pDamage); - - xfree (pScreenPriv); - - return (*pScreen->CloseScreen) (i, pScreen); -} - -static void -miSpriteGetImage (DrawablePtr pDrawable, int sx, int sy, int w, int h, - unsigned int format, unsigned long planemask, - char *pdstLine) -{ - ScreenPtr pScreen = pDrawable->pScreen; - miSpriteScreenPtr pScreenPriv; - DeviceIntPtr pDev; - miCursorInfoPtr pCursorInfo; - - SCREEN_PROLOGUE (pScreen, GetImage); - - if (pDrawable->type == DRAWABLE_WINDOW) - { - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates,miSpriteScreenKey); - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pCursorInfo = MISPRITE(pDev); - if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && - ORG_OVERLAP(&pCursorInfo->saved,pDrawable->x,pDrawable->y, - sx, sy, w, h)) - { - SPRITE_DEBUG (("GetImage remove\n")); - miSpriteRemoveCursor (pDev, pScreen); - } - } - } - } - - (*pScreen->GetImage) (pDrawable, sx, sy, w, h, - format, planemask, pdstLine); - - SCREEN_EPILOGUE (pScreen, GetImage); -} - -static void -miSpriteGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, - int *pwidth, int nspans, char *pdstStart) -{ - ScreenPtr pScreen = pDrawable->pScreen; - miSpriteScreenPtr pScreenPriv; - DeviceIntPtr pDev; - miCursorInfoPtr pCursorInfo; - - SCREEN_PROLOGUE (pScreen, GetSpans); - - if (pDrawable->type == DRAWABLE_WINDOW) - { - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates,miSpriteScreenKey); - - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pCursorInfo = MISPRITE(pDev); - - if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) - { - DDXPointPtr pts; - int *widths; - int nPts; - int xorg, - yorg; - - xorg = pDrawable->x; - yorg = pDrawable->y; - - for (pts = ppt, widths = pwidth, nPts = nspans; - nPts--; - pts++, widths++) - { - if (SPN_OVERLAP(&pCursorInfo->saved,pts->y+yorg, - pts->x+xorg,*widths)) - { - SPRITE_DEBUG (("GetSpans remove\n")); - miSpriteRemoveCursor (pDev, pScreen); - break; - } - } - } - } - } - } - - (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); - - SCREEN_EPILOGUE (pScreen, GetSpans); -} - -static void -miSpriteSourceValidate (DrawablePtr pDrawable, int x, int y, int width, - int height) -{ - ScreenPtr pScreen = pDrawable->pScreen; - miSpriteScreenPtr pScreenPriv; - DeviceIntPtr pDev; - miCursorInfoPtr pCursorInfo; - - SCREEN_PROLOGUE (pScreen, SourceValidate); - - if (pDrawable->type == DRAWABLE_WINDOW) - { - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates,miSpriteScreenKey); - - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pCursorInfo = MISPRITE(pDev); - if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && - ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y, - x, y, width, height)) - { - SPRITE_DEBUG (("SourceValidate remove\n")); - miSpriteRemoveCursor (pDev, pScreen); - } - } - } - } - - if (pScreen->SourceValidate) - (*pScreen->SourceValidate) (pDrawable, x, y, width, height); - - SCREEN_EPILOGUE (pScreen, SourceValidate); -} - -static void -miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - miSpriteScreenPtr pScreenPriv; - DeviceIntPtr pDev; - miCursorInfoPtr pCursorInfo; - - SCREEN_PROLOGUE (pScreen, CopyWindow); - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pCursorInfo = MISPRITE(pDev); - /* - * Damage will take care of destination check - */ - if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && - miRectIn(prgnSrc, &pCursorInfo->saved) != rgnOUT) - { - SPRITE_DEBUG (("CopyWindow remove\n")); - miSpriteRemoveCursor (pDev, pScreen); - } - } - } - - (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); - SCREEN_EPILOGUE (pScreen, CopyWindow); -} - -static void -miSpriteBlockHandler (int i, pointer blockData, pointer pTimeout, - pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[i]; - miSpriteScreenPtr pPriv; - DeviceIntPtr pDev; - miCursorInfoPtr pCursorInfo; - - pPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - SCREEN_PROLOGUE(pScreen, BlockHandler); - - (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); - - SCREEN_EPILOGUE(pScreen, BlockHandler); - - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pCursorInfo = MISPRITE(pDev); - if (pCursorInfo && !pCursorInfo->isUp - && pCursorInfo->pScreen == pScreen - && pCursorInfo->shouldBeUp) - { - SPRITE_DEBUG (("BlockHandler restore\n")); - miSpriteSaveUnderCursor (pDev, pScreen); - } - } - } - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pCursorInfo = MISPRITE(pDev); - if (pCursorInfo && !pCursorInfo->isUp && - pCursorInfo->pScreen == pScreen && - pCursorInfo->shouldBeUp) - { - SPRITE_DEBUG (("BlockHandler restore\n")); - miSpriteRestoreCursor (pDev, pScreen); - } - } - } -} - -static void -miSpriteInstallColormap (ColormapPtr pMap) -{ - ScreenPtr pScreen = pMap->pScreen; - miSpriteScreenPtr pPriv; - - pPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - SCREEN_PROLOGUE(pScreen, InstallColormap); - - (*pScreen->InstallColormap) (pMap); - - SCREEN_EPILOGUE(pScreen, InstallColormap); - - /* InstallColormap can be called before devices are initialized. */ - pPriv->pInstalledMap = pMap; - if (pPriv->pColormap != pMap) - { - DeviceIntPtr pDev; - miCursorInfoPtr pCursorInfo; - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pCursorInfo = MISPRITE(pDev); - pCursorInfo->checkPixels = TRUE; - if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) - miSpriteRemoveCursor(pDev, pScreen); - } - } - - } -} - -static void -miSpriteStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef) -{ - ScreenPtr pScreen = pMap->pScreen; - miSpriteScreenPtr pPriv; - int i; - int updated; - VisualPtr pVisual; - DeviceIntPtr pDev; - miCursorInfoPtr pCursorInfo; - - pPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - SCREEN_PROLOGUE(pScreen, StoreColors); - - (*pScreen->StoreColors) (pMap, ndef, pdef); - - SCREEN_EPILOGUE(pScreen, StoreColors); - - if (pPriv->pColormap == pMap) - { - updated = 0; - pVisual = pMap->pVisual; - if (pVisual->class == DirectColor) - { - /* Direct color - match on any of the subfields */ - -#define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask))) - -#define UpdateDAC(dev, plane,dac,mask) {\ - if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\ - dev->colors[plane].dac = pdef[i].dac; \ - updated = 1; \ - } \ -} - -#define CheckDirect(dev, plane) \ - UpdateDAC(dev, plane,red,redMask) \ - UpdateDAC(dev, plane,green,greenMask) \ - UpdateDAC(dev, plane,blue,blueMask) - - for (i = 0; i < ndef; i++) - { - CheckDirect (pPriv, SOURCE_COLOR) - CheckDirect (pPriv, MASK_COLOR) - } - } - else - { - /* PseudoColor/GrayScale - match on exact pixel */ - for (i = 0; i < ndef; i++) - { - if (pdef[i].pixel == - pPriv->colors[SOURCE_COLOR].pixel) - { - pPriv->colors[SOURCE_COLOR] = pdef[i]; - if (++updated == 2) - break; - } - if (pdef[i].pixel == - pPriv->colors[MASK_COLOR].pixel) - { - pPriv->colors[MASK_COLOR] = pdef[i]; - if (++updated == 2) - break; - } - } - } - if (updated) - { - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - pCursorInfo = MISPRITE(pDev); - pCursorInfo->checkPixels = TRUE; - if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) - miSpriteRemoveCursor (pDev, pScreen); - } - } - } - } -} - -static void -miSpriteFindColors (miCursorInfoPtr pDevCursor, ScreenPtr pScreen) -{ - miSpriteScreenPtr pScreenPriv = - dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - CursorPtr pCursor; - xColorItem *sourceColor, *maskColor; - - pCursor = pDevCursor->pCursor; - sourceColor = &pScreenPriv->colors[SOURCE_COLOR]; - maskColor = &pScreenPriv->colors[MASK_COLOR]; - if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap || - !(pCursor->foreRed == sourceColor->red && - pCursor->foreGreen == sourceColor->green && - pCursor->foreBlue == sourceColor->blue && - pCursor->backRed == maskColor->red && - pCursor->backGreen == maskColor->green && - pCursor->backBlue == maskColor->blue)) - { - pScreenPriv->pColormap = pScreenPriv->pInstalledMap; - sourceColor->red = pCursor->foreRed; - sourceColor->green = pCursor->foreGreen; - sourceColor->blue = pCursor->foreBlue; - FakeAllocColor (pScreenPriv->pColormap, sourceColor); - maskColor->red = pCursor->backRed; - maskColor->green = pCursor->backGreen; - maskColor->blue = pCursor->backBlue; - FakeAllocColor (pScreenPriv->pColormap, maskColor); - /* "free" the pixels right away, don't let this confuse you */ - FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel); - FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel); - } - - pDevCursor->checkPixels = FALSE; - -} - -/* - * miPointer interface routines - */ - -#define SPRITE_PAD 8 - -static Bool -miSpriteRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - miSpriteScreenPtr pScreenPriv; - miCursorInfoPtr pCursorInfo; - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - if (!IsMaster(pDev) && !pDev->u.master) - return FALSE; - - pCursorInfo = MISPRITE(pDev); - - if (pCursor == pCursorInfo->pCursor) - pCursorInfo->checkPixels = TRUE; - - return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor); -} - -static Bool -miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - miSpriteScreenPtr pScreenPriv; - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor); -} - -static void -miSpriteSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor, int x, int y) -{ - miSpriteScreenPtr pScreenPriv; - miCursorInfoPtr pPointer; - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - - if (!IsMaster(pDev) && !pDev->u.master) - return; - - pPointer = MISPRITE(pDev); - - if (!pCursor) - { - pPointer->shouldBeUp = FALSE; - if (pPointer->isUp) - miSpriteRemoveCursor (pDev, pScreen); - pPointer->pCursor = 0; - return; - } - pPointer->shouldBeUp = TRUE; - if (pPointer->x == x && - pPointer->y == y && - pPointer->pCursor == pCursor && - !pPointer->checkPixels) - { - return; - } - pPointer->x = x; - pPointer->y = y; - pPointer->pCacheWin = NullWindow; - if (pPointer->checkPixels || pPointer->pCursor != pCursor) - { - pPointer->pCursor = pCursor; - miSpriteFindColors (pPointer, pScreen); - } - if (pPointer->isUp) { -#if 0 - /* FIXME: Disabled for MPX, should be rewritten */ - int sx, sy; - /* - * check to see if the old saved region - * encloses the new sprite, in which case we use - * the flicker-free MoveCursor primitive. - */ - sx = pointer->x - (int)pCursor->bits->xhot; - sy = pointer->y - (int)pCursor->bits->yhot; - if (sx + (int) pCursor->bits->width >= pointer->saved.x1 && - sx < pointer->saved.x2 && - sy + (int) pCursor->bits->height >= pointer->saved.y1 && - sy < pointer->saved.y2 && - (int) pCursor->bits->width + (2 * SPRITE_PAD) == - pointer->saved.x2 - pointer->saved.x1 && - (int) pCursor->bits->height + (2 * SPRITE_PAD) == - pointer->saved.y2 - pointer->saved.y1 - ) - { - DamageDrawInternal (pScreen, TRUE); - miSpriteIsDown(pCursorInfo); - if (!(sx >= pointer->saved.x1 && - sx + (int)pCursor->bits->width < pointer->saved.x2 - && sy >= pointer->saved.y1 && - sy + (int)pCursor->bits->height < - pointer->saved.y2)) - { - int oldx1, oldy1, dx, dy; - - oldx1 = pointer->saved.x1; - oldy1 = pointer->saved.y1; - dx = oldx1 - (sx - SPRITE_PAD); - dy = oldy1 - (sy - SPRITE_PAD); - pointer->saved.x1 -= dx; - pointer->saved.y1 -= dy; - pointer->saved.x2 -= dx; - pointer->saved.y2 -= dy; - (void) (*pScreenPriv->funcs->ChangeSave) (pScreen, - pointer->saved.x1, - pointer->saved.y1, - pointer->saved.x2 - - pointer->saved.x1, - pointer->saved.y2 - - pointer->saved.y1, - dx, dy); - } - (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor, - pointer->saved.x1, - pointer->saved.y1, - pointer->saved.x2 - - pointer->saved.x1, - pointer->saved.y2 - - pointer->saved.y1, - sx - pointer->saved.x1, - sy - pointer->saved.y1, - pointer->colors[SOURCE_COLOR].pixel, - pointer->colors[MASK_COLOR].pixel); - miSpriteIsUp(pCursorInfo); - DamageDrawInternal (pScreen, FALSE); - } - else -#endif - { - SPRITE_DEBUG (("SetCursor remove %d\n", pDev->id)); - miSpriteRemoveCursor (pDev, pScreen); - } - } - - if (!pPointer->isUp && pPointer->pCursor) - { - SPRITE_DEBUG (("SetCursor restore %d\n", pDev->id)); - miSpriteSaveUnderCursor(pDev, pScreen); - miSpriteRestoreCursor (pDev, pScreen); - } - -} - -static void -miSpriteMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - miSpriteScreenPtr pScreenPriv; - CursorPtr pCursor; - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - if (!IsMaster(pDev) && !pDev->u.master) - return; - - pCursor = MISPRITE(pDev)->pCursor; - - miSpriteSetCursor (pDev, pScreen, pCursor, x, y); -} - - -static Bool -miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - miSpriteScreenPtr pScreenPriv; - miCursorInfoPtr pCursorInfo; - int ret = FALSE; - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - - pCursorInfo = xalloc(sizeof(miCursorInfoRec)); - if (!pCursorInfo) - return FALSE; - - pCursorInfo->pCursor = NULL; - pCursorInfo->x = 0; - pCursorInfo->y = 0; - pCursorInfo->isUp = FALSE; - pCursorInfo->shouldBeUp = FALSE; - pCursorInfo->pCacheWin = NullWindow; - pCursorInfo->isInCacheWin = FALSE; - pCursorInfo->checkPixels = TRUE; - pCursorInfo->pScreen = FALSE; - - ret = (*pScreenPriv->funcs->DeviceCursorInitialize)(pDev, pScreen); - if (!ret) - { - xfree(pCursorInfo); - pCursorInfo = NULL; - } - dixSetPrivate(&pDev->devPrivates, miSpriteDevPrivatesKey, pCursorInfo); - return ret; -} - -static void -miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - if (DevHasCursor(pDev)) - { - miSpriteScreenPtr pScreenPriv; - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, - miSpriteScreenKey); - - (*pScreenPriv->funcs->DeviceCursorCleanup)(pDev, pScreen); - } -} - -/* - * undraw/draw cursor - */ - -static void -miSpriteRemoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen) -{ - miSpriteScreenPtr pScreenPriv; - miCursorInfoPtr pCursorInfo; - - - if (!IsMaster(pDev) && !pDev->u.master) - return; - - DamageDrawInternal (pScreen, TRUE); - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - pCursorInfo = MISPRITE(pDev); - - miSpriteIsDown(pCursorInfo); - pCursorInfo->pCacheWin = NullWindow; - miSpriteDisableDamage(pScreen, pScreenPriv); - if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pDev, - pScreen, - pCursorInfo->saved.x1, - pCursorInfo->saved.y1, - pCursorInfo->saved.x2 - - pCursorInfo->saved.x1, - pCursorInfo->saved.y2 - - pCursorInfo->saved.y1)) - { - miSpriteIsUp(pCursorInfo); - } - miSpriteEnableDamage(pScreen, pScreenPriv); - DamageDrawInternal (pScreen, FALSE); -} - -/* - * Called from the block handler, saves area under cursor - * before waiting for something to do. - */ - -static void -miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - miSpriteScreenPtr pScreenPriv; - int x, y; - CursorPtr pCursor; - miCursorInfoPtr pCursorInfo; - - if (!IsMaster(pDev) && !pDev->u.master) - return; - - DamageDrawInternal (pScreen, TRUE); - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - pCursorInfo = MISPRITE(pDev); - - miSpriteComputeSaved (pDev, pScreen); - pCursor = pCursorInfo->pCursor; - - x = pCursorInfo->x - (int)pCursor->bits->xhot; - y = pCursorInfo->y - (int)pCursor->bits->yhot; - miSpriteDisableDamage(pScreen, pScreenPriv); - - (*pScreenPriv->funcs->SaveUnderCursor) (pDev, - pScreen, - pCursorInfo->saved.x1, - pCursorInfo->saved.y1, - pCursorInfo->saved.x2 - - pCursorInfo->saved.x1, - pCursorInfo->saved.y2 - - pCursorInfo->saved.y1); - SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id)); - miSpriteEnableDamage(pScreen, pScreenPriv); - DamageDrawInternal (pScreen, FALSE); -} - - -/* - * Called from the block handler, restores the cursor - * before waiting for something to do. - */ - -static void -miSpriteRestoreCursor (DeviceIntPtr pDev, ScreenPtr pScreen) -{ - miSpriteScreenPtr pScreenPriv; - int x, y; - CursorPtr pCursor; - miCursorInfoPtr pCursorInfo; - - if (!IsMaster(pDev) && !pDev->u.master) - return; - - DamageDrawInternal (pScreen, TRUE); - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - pCursorInfo = MISPRITE(pDev); - - miSpriteComputeSaved (pDev, pScreen); - pCursor = pCursorInfo->pCursor; - - x = pCursorInfo->x - (int)pCursor->bits->xhot; - y = pCursorInfo->y - (int)pCursor->bits->yhot; - miSpriteDisableDamage(pScreen, pScreenPriv); - SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id)); - if (pCursorInfo->checkPixels) - miSpriteFindColors (pCursorInfo, pScreen); - if ((*pScreenPriv->funcs->PutUpCursor) (pDev, pScreen, - pCursor, x, y, - pScreenPriv->colors[SOURCE_COLOR].pixel, - pScreenPriv->colors[MASK_COLOR].pixel)) - { - miSpriteIsUp(pCursorInfo); - pCursorInfo->pScreen = pScreen; - } - miSpriteEnableDamage(pScreen, pScreenPriv); - DamageDrawInternal (pScreen, FALSE); -} - -/* - * compute the desired area of the screen to save - */ - -static void -miSpriteComputeSaved (DeviceIntPtr pDev, ScreenPtr pScreen) -{ - miSpriteScreenPtr pScreenPriv; - int x, y, w, h; - int wpad, hpad; - CursorPtr pCursor; - miCursorInfoPtr pCursorInfo; - - if (!IsMaster(pDev) && !pDev->u.master) - return; - - pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); - pCursorInfo = MISPRITE(pDev); - - pCursor = pCursorInfo->pCursor; - x = pCursorInfo->x - (int)pCursor->bits->xhot; - y = pCursorInfo->y - (int)pCursor->bits->yhot; - w = pCursor->bits->width; - h = pCursor->bits->height; - wpad = SPRITE_PAD; - hpad = SPRITE_PAD; - pCursorInfo->saved.x1 = x - wpad; - pCursorInfo->saved.y1 = y - hpad; - pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2; - pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2; -} - +/* + * misprite.c + * + * machine independent software sprite routines + */ + +/* + +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 <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "pixmapstr.h" +#include "input.h" +#include "mi.h" +#include "cursorstr.h" +#include <X11/fonts/font.h> +#include "scrnintstr.h" +#include "colormapst.h" +#include "windowstr.h" +#include "gcstruct.h" +#include "mipointer.h" +#include "misprite.h" +#include "dixfontstr.h" +#include <X11/fonts/fontstruct.h> +#include "inputstr.h" +#include "damage.h" + +typedef struct { + CursorPtr pCursor; + int x; /* cursor hotspot */ + int y; + BoxRec saved; /* saved area from the screen */ + Bool isUp; /* cursor in frame buffer */ + Bool shouldBeUp; /* cursor should be displayed */ + WindowPtr pCacheWin; /* window the cursor last seen in */ + Bool isInCacheWin; + Bool checkPixels; /* check colormap collision */ + ScreenPtr pScreen; +} miCursorInfoRec, *miCursorInfoPtr; + +/* + * per screen information + */ + +typedef struct { + /* screen procedures */ + CloseScreenProcPtr CloseScreen; + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + SourceValidateProcPtr SourceValidate; + + /* window procedures */ + CopyWindowProcPtr CopyWindow; + + /* colormap procedures */ + InstallColormapProcPtr InstallColormap; + StoreColorsProcPtr StoreColors; + + /* os layer procedures */ + ScreenBlockHandlerProcPtr BlockHandler; + + /* device cursor procedures */ + DeviceCursorInitializeProcPtr DeviceCursorInitialize; + DeviceCursorCleanupProcPtr DeviceCursorCleanup; + + xColorItem colors[2]; + ColormapPtr pInstalledMap; + ColormapPtr pColormap; + VisualPtr pVisual; + miSpriteCursorFuncPtr funcs; + DamagePtr pDamage; /* damage tracking structure */ + Bool damageRegistered; +} miSpriteScreenRec, *miSpriteScreenPtr; + +#define SOURCE_COLOR 0 +#define MASK_COLOR 1 + +/* + * Overlap BoxPtr and Box elements + */ +#define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \ + (((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \ + ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2)) + +/* + * Overlap BoxPtr, origins, and rectangle + */ +#define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \ + BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h)) + +/* + * Overlap BoxPtr, origins and RectPtr + */ +#define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \ + ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \ + (int)((pRect)->width), (int)((pRect)->height)) +/* + * Overlap BoxPtr and horizontal span + */ +#define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y)) + +#define LINE_SORT(x1,y1,x2,y2) \ +{ int _t; \ + if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \ + if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } } + +#define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \ + BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2)) + + +#define SPRITE_DEBUG_ENABLE 0 +#if SPRITE_DEBUG_ENABLE +#define SPRITE_DEBUG(x) ErrorF x +#else +#define SPRITE_DEBUG(x) +#endif + +#define MISPRITE(dev) \ + ((!IsMaster(dev) && !dev->u.master) ? \ + (miCursorInfoPtr)dixLookupPrivate(&dev->devPrivates, miSpriteDevPrivatesKey) : \ + (miCursorInfoPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miSpriteDevPrivatesKey)) + +static void +miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) +{ + if (pScreenPriv->damageRegistered) { + DamageUnregister (&(pScreen->GetScreenPixmap(pScreen)->drawable), + pScreenPriv->pDamage); + pScreenPriv->damageRegistered = 0; + } +} + +static void +miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) +{ + if (!pScreenPriv->damageRegistered) { + pScreenPriv->damageRegistered = 1; + DamageRegister (&(pScreen->GetScreenPixmap(pScreen)->drawable), + pScreenPriv->pDamage); + } +} + +static void +miSpriteIsUp(miCursorInfoPtr pDevCursor) +{ + pDevCursor->isUp = TRUE; +} + +static void +miSpriteIsDown(miCursorInfoPtr pDevCursor) +{ + pDevCursor->isUp = FALSE; +} + +/* + * screen wrappers + */ + +static int miSpriteScreenKeyIndex; +static DevPrivateKey miSpriteScreenKey = &miSpriteScreenKeyIndex; +static int miSpriteDevPrivatesKeyIndex; +static DevPrivateKey miSpriteDevPrivatesKey = &miSpriteDevPrivatesKeyIndex; + +static Bool miSpriteCloseScreen(int i, ScreenPtr pScreen); +static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, + int w, int h, unsigned int format, + unsigned long planemask, char *pdstLine); +static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax, + DDXPointPtr ppt, int *pwidth, int nspans, + char *pdstStart); +static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, + int width, int height); +static void miSpriteCopyWindow (WindowPtr pWindow, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc); +static void miSpriteBlockHandler(int i, pointer blockData, + pointer pTimeout, + pointer pReadMask); +static void miSpriteInstallColormap(ColormapPtr pMap); +static void miSpriteStoreColors(ColormapPtr pMap, int ndef, + xColorItem *pdef); + +static void miSpriteComputeSaved(DeviceIntPtr pDev, + ScreenPtr pScreen); + +static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, + ScreenPtr pScreen); + +#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \ + ((miSpriteScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, \ + miSpriteScreenKey))->field) +#define SCREEN_EPILOGUE(pScreen, field)\ + ((pScreen)->field = miSprite##field) + +/* + * pointer-sprite method table + */ + +static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, int x, int y); +static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y); + +miPointerSpriteFuncRec miSpritePointerFuncs = { + miSpriteRealizeCursor, + miSpriteUnrealizeCursor, + miSpriteSetCursor, + miSpriteMoveCursor, + miSpriteDeviceCursorInitialize, + miSpriteDeviceCursorCleanup, +}; + +/* + * other misc functions + */ + +static void miSpriteRemoveCursor(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miSpriteSaveUnderCursor(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miSpriteRestoreCursor(DeviceIntPtr pDev, + ScreenPtr pScreen); + +static void +miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + ScreenPtr pScreen = closure; + miSpriteScreenPtr pScreenPriv; + miCursorInfoPtr pCursorInfo; + DeviceIntPtr pDev; + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + + if (pCursorInfo->isUp && + pCursorInfo->pScreen == pScreen && + miRectIn(pRegion, &pCursorInfo->saved) != rgnOUT) + { + SPRITE_DEBUG(("Damage remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } +} + +/* + * miSpriteInitialize -- called from device-dependent screen + * initialization proc after all of the function pointers have + * been stored in the screen structure. + */ + +Bool +miSpriteInitialize (ScreenPtr pScreen, + miSpriteCursorFuncPtr cursorFuncs, + miPointerScreenFuncPtr screenFuncs) +{ + miSpriteScreenPtr pScreenPriv; + VisualPtr pVisual; + + if (!DamageSetup (pScreen)) + return FALSE; + + pScreenPriv = malloc(sizeof (miSpriteScreenRec)); + if (!pScreenPriv) + return FALSE; + + pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage, + NULL, + DamageReportRawRegion, + TRUE, + pScreen, + pScreen); + + if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE)) + { + free(pScreenPriv); + return FALSE; + } + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++) + ; + pScreenPriv->pVisual = pVisual; + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreenPriv->GetImage = pScreen->GetImage; + pScreenPriv->GetSpans = pScreen->GetSpans; + pScreenPriv->SourceValidate = pScreen->SourceValidate; + + pScreenPriv->CopyWindow = pScreen->CopyWindow; + + pScreenPriv->InstallColormap = pScreen->InstallColormap; + pScreenPriv->StoreColors = pScreen->StoreColors; + + pScreenPriv->BlockHandler = pScreen->BlockHandler; + + pScreenPriv->DeviceCursorInitialize = pScreen->DeviceCursorInitialize; + pScreenPriv->DeviceCursorCleanup = pScreen->DeviceCursorCleanup; + + pScreenPriv->pInstalledMap = NULL; + pScreenPriv->pColormap = NULL; + pScreenPriv->funcs = cursorFuncs; + pScreenPriv->colors[SOURCE_COLOR].red = 0; + pScreenPriv->colors[SOURCE_COLOR].green = 0; + pScreenPriv->colors[SOURCE_COLOR].blue = 0; + pScreenPriv->colors[MASK_COLOR].red = 0; + pScreenPriv->colors[MASK_COLOR].green = 0; + pScreenPriv->colors[MASK_COLOR].blue = 0; + pScreenPriv->damageRegistered = 0; + + dixSetPrivate(&pScreen->devPrivates, miSpriteScreenKey, pScreenPriv); + + pScreen->CloseScreen = miSpriteCloseScreen; + pScreen->GetImage = miSpriteGetImage; + pScreen->GetSpans = miSpriteGetSpans; + pScreen->SourceValidate = miSpriteSourceValidate; + + pScreen->CopyWindow = miSpriteCopyWindow; + pScreen->InstallColormap = miSpriteInstallColormap; + pScreen->StoreColors = miSpriteStoreColors; + + pScreen->BlockHandler = miSpriteBlockHandler; + + return TRUE; +} + +/* + * Screen wrappers + */ + +/* + * CloseScreen wrapper -- unwrap everything, free the private data + * and call the wrapped function + */ + +static Bool +miSpriteCloseScreen (int i, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->GetImage = pScreenPriv->GetImage; + pScreen->GetSpans = pScreenPriv->GetSpans; + pScreen->SourceValidate = pScreenPriv->SourceValidate; + pScreen->BlockHandler = pScreenPriv->BlockHandler; + pScreen->InstallColormap = pScreenPriv->InstallColormap; + pScreen->StoreColors = pScreenPriv->StoreColors; + + DamageDestroy (pScreenPriv->pDamage); + + free(pScreenPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void +miSpriteGetImage (DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planemask, + char *pdstLine) +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + + SCREEN_PROLOGUE (pScreen, GetImage); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates,miSpriteScreenKey); + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && + ORG_OVERLAP(&pCursorInfo->saved,pDrawable->x,pDrawable->y, + sx, sy, w, h)) + { + SPRITE_DEBUG (("GetImage remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + } + + (*pScreen->GetImage) (pDrawable, sx, sy, w, h, + format, planemask, pdstLine); + + SCREEN_EPILOGUE (pScreen, GetImage); +} + +static void +miSpriteGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, + int *pwidth, int nspans, char *pdstStart) +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + + SCREEN_PROLOGUE (pScreen, GetSpans); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates,miSpriteScreenKey); + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) + { + DDXPointPtr pts; + int *widths; + int nPts; + int xorg, + yorg; + + xorg = pDrawable->x; + yorg = pDrawable->y; + + for (pts = ppt, widths = pwidth, nPts = nspans; + nPts--; + pts++, widths++) + { + if (SPN_OVERLAP(&pCursorInfo->saved,pts->y+yorg, + pts->x+xorg,*widths)) + { + SPRITE_DEBUG (("GetSpans remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + break; + } + } + } + } + } + } + + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + + SCREEN_EPILOGUE (pScreen, GetSpans); +} + +static void +miSpriteSourceValidate (DrawablePtr pDrawable, int x, int y, int width, + int height) +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + + SCREEN_PROLOGUE (pScreen, SourceValidate); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates,miSpriteScreenKey); + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && + ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y, + x, y, width, height)) + { + SPRITE_DEBUG (("SourceValidate remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + } + + if (pScreen->SourceValidate) + (*pScreen->SourceValidate) (pDrawable, x, y, width, height); + + SCREEN_EPILOGUE (pScreen, SourceValidate); +} + +static void +miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + miSpriteScreenPtr pScreenPriv; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + + SCREEN_PROLOGUE (pScreen, CopyWindow); + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + /* + * Damage will take care of destination check + */ + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && + miRectIn(prgnSrc, &pCursorInfo->saved) != rgnOUT) + { + SPRITE_DEBUG (("CopyWindow remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + + (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); + SCREEN_EPILOGUE (pScreen, CopyWindow); +} + +static void +miSpriteBlockHandler (int i, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + miSpriteScreenPtr pPriv; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + + pPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + SCREEN_PROLOGUE(pScreen, BlockHandler); + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + SCREEN_EPILOGUE(pScreen, BlockHandler); + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo && !pCursorInfo->isUp + && pCursorInfo->pScreen == pScreen + && pCursorInfo->shouldBeUp) + { + SPRITE_DEBUG (("BlockHandler restore\n")); + miSpriteSaveUnderCursor (pDev, pScreen); + } + } + } + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo && !pCursorInfo->isUp && + pCursorInfo->pScreen == pScreen && + pCursorInfo->shouldBeUp) + { + SPRITE_DEBUG (("BlockHandler restore\n")); + miSpriteRestoreCursor (pDev, pScreen); + } + } + } +} + +static void +miSpriteInstallColormap (ColormapPtr pMap) +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv; + + pPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + SCREEN_PROLOGUE(pScreen, InstallColormap); + + (*pScreen->InstallColormap) (pMap); + + SCREEN_EPILOGUE(pScreen, InstallColormap); + + /* InstallColormap can be called before devices are initialized. */ + pPriv->pInstalledMap = pMap; + if (pPriv->pColormap != pMap) + { + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + pCursorInfo->checkPixels = TRUE; + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) + miSpriteRemoveCursor(pDev, pScreen); + } + } + + } +} + +static void +miSpriteStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef) +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv; + int i; + int updated; + VisualPtr pVisual; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + + pPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + SCREEN_PROLOGUE(pScreen, StoreColors); + + (*pScreen->StoreColors) (pMap, ndef, pdef); + + SCREEN_EPILOGUE(pScreen, StoreColors); + + if (pPriv->pColormap == pMap) + { + updated = 0; + pVisual = pMap->pVisual; + if (pVisual->class == DirectColor) + { + /* Direct color - match on any of the subfields */ + +#define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask))) + +#define UpdateDAC(dev, plane,dac,mask) {\ + if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\ + dev->colors[plane].dac = pdef[i].dac; \ + updated = 1; \ + } \ +} + +#define CheckDirect(dev, plane) \ + UpdateDAC(dev, plane,red,redMask) \ + UpdateDAC(dev, plane,green,greenMask) \ + UpdateDAC(dev, plane,blue,blueMask) + + for (i = 0; i < ndef; i++) + { + CheckDirect (pPriv, SOURCE_COLOR) + CheckDirect (pPriv, MASK_COLOR) + } + } + else + { + /* PseudoColor/GrayScale - match on exact pixel */ + for (i = 0; i < ndef; i++) + { + if (pdef[i].pixel == + pPriv->colors[SOURCE_COLOR].pixel) + { + pPriv->colors[SOURCE_COLOR] = pdef[i]; + if (++updated == 2) + break; + } + if (pdef[i].pixel == + pPriv->colors[MASK_COLOR].pixel) + { + pPriv->colors[MASK_COLOR] = pdef[i]; + if (++updated == 2) + break; + } + } + } + if (updated) + { + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + pCursorInfo->checkPixels = TRUE; + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + } +} + +static void +miSpriteFindColors (miCursorInfoPtr pDevCursor, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv = + dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + CursorPtr pCursor; + xColorItem *sourceColor, *maskColor; + + pCursor = pDevCursor->pCursor; + sourceColor = &pScreenPriv->colors[SOURCE_COLOR]; + maskColor = &pScreenPriv->colors[MASK_COLOR]; + if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap || + !(pCursor->foreRed == sourceColor->red && + pCursor->foreGreen == sourceColor->green && + pCursor->foreBlue == sourceColor->blue && + pCursor->backRed == maskColor->red && + pCursor->backGreen == maskColor->green && + pCursor->backBlue == maskColor->blue)) + { + pScreenPriv->pColormap = pScreenPriv->pInstalledMap; + sourceColor->red = pCursor->foreRed; + sourceColor->green = pCursor->foreGreen; + sourceColor->blue = pCursor->foreBlue; + FakeAllocColor (pScreenPriv->pColormap, sourceColor); + maskColor->red = pCursor->backRed; + maskColor->green = pCursor->backGreen; + maskColor->blue = pCursor->backBlue; + FakeAllocColor (pScreenPriv->pColormap, maskColor); + /* "free" the pixels right away, don't let this confuse you */ + FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel); + FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel); + } + + pDevCursor->checkPixels = FALSE; + +} + +/* + * miPointer interface routines + */ + +#define SPRITE_PAD 8 + +static Bool +miSpriteRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + miSpriteScreenPtr pScreenPriv; + miCursorInfoPtr pCursorInfo; + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + if (!IsMaster(pDev) && !pDev->u.master) + return FALSE; + + pCursorInfo = MISPRITE(pDev); + + if (pCursor == pCursorInfo->pCursor) + pCursorInfo->checkPixels = TRUE; + + return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor); +} + +static Bool +miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor); +} + +static void +miSpriteSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, int x, int y) +{ + miSpriteScreenPtr pScreenPriv; + miCursorInfoPtr pPointer; + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + pPointer = MISPRITE(pDev); + + if (!pCursor) + { + pPointer->shouldBeUp = FALSE; + if (pPointer->isUp) + miSpriteRemoveCursor (pDev, pScreen); + pPointer->pCursor = 0; + return; + } + pPointer->shouldBeUp = TRUE; + if (pPointer->x == x && + pPointer->y == y && + pPointer->pCursor == pCursor && + !pPointer->checkPixels) + { + return; + } + pPointer->x = x; + pPointer->y = y; + pPointer->pCacheWin = NullWindow; + if (pPointer->checkPixels || pPointer->pCursor != pCursor) + { + pPointer->pCursor = pCursor; + miSpriteFindColors (pPointer, pScreen); + } + if (pPointer->isUp) { +#if 0 + /* FIXME: Disabled for MPX, should be rewritten */ + int sx, sy; + /* + * check to see if the old saved region + * encloses the new sprite, in which case we use + * the flicker-free MoveCursor primitive. + */ + sx = pointer->x - (int)pCursor->bits->xhot; + sy = pointer->y - (int)pCursor->bits->yhot; + if (sx + (int) pCursor->bits->width >= pointer->saved.x1 && + sx < pointer->saved.x2 && + sy + (int) pCursor->bits->height >= pointer->saved.y1 && + sy < pointer->saved.y2 && + (int) pCursor->bits->width + (2 * SPRITE_PAD) == + pointer->saved.x2 - pointer->saved.x1 && + (int) pCursor->bits->height + (2 * SPRITE_PAD) == + pointer->saved.y2 - pointer->saved.y1 + ) + { + DamageDrawInternal (pScreen, TRUE); + miSpriteIsDown(pCursorInfo); + if (!(sx >= pointer->saved.x1 && + sx + (int)pCursor->bits->width < pointer->saved.x2 + && sy >= pointer->saved.y1 && + sy + (int)pCursor->bits->height < + pointer->saved.y2)) + { + int oldx1, oldy1, dx, dy; + + oldx1 = pointer->saved.x1; + oldy1 = pointer->saved.y1; + dx = oldx1 - (sx - SPRITE_PAD); + dy = oldy1 - (sy - SPRITE_PAD); + pointer->saved.x1 -= dx; + pointer->saved.y1 -= dy; + pointer->saved.x2 -= dx; + pointer->saved.y2 -= dy; + (void) (*pScreenPriv->funcs->ChangeSave) (pScreen, + pointer->saved.x1, + pointer->saved.y1, + pointer->saved.x2 - + pointer->saved.x1, + pointer->saved.y2 - + pointer->saved.y1, + dx, dy); + } + (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor, + pointer->saved.x1, + pointer->saved.y1, + pointer->saved.x2 - + pointer->saved.x1, + pointer->saved.y2 - + pointer->saved.y1, + sx - pointer->saved.x1, + sy - pointer->saved.y1, + pointer->colors[SOURCE_COLOR].pixel, + pointer->colors[MASK_COLOR].pixel); + miSpriteIsUp(pCursorInfo); + DamageDrawInternal (pScreen, FALSE); + } + else +#endif + { + SPRITE_DEBUG (("SetCursor remove %d\n", pDev->id)); + miSpriteRemoveCursor (pDev, pScreen); + } + } + + if (!pPointer->isUp && pPointer->pCursor) + { + SPRITE_DEBUG (("SetCursor restore %d\n", pDev->id)); + miSpriteSaveUnderCursor(pDev, pScreen); + miSpriteRestoreCursor (pDev, pScreen); + } + +} + +static void +miSpriteMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + miSpriteScreenPtr pScreenPriv; + CursorPtr pCursor; + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + if (!IsMaster(pDev) && !pDev->u.master) + return; + + pCursor = MISPRITE(pDev)->pCursor; + + miSpriteSetCursor (pDev, pScreen, pCursor, x, y); +} + + +static Bool +miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + miCursorInfoPtr pCursorInfo; + int ret = FALSE; + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + + pCursorInfo = malloc(sizeof(miCursorInfoRec)); + if (!pCursorInfo) + return FALSE; + + pCursorInfo->pCursor = NULL; + pCursorInfo->x = 0; + pCursorInfo->y = 0; + pCursorInfo->isUp = FALSE; + pCursorInfo->shouldBeUp = FALSE; + pCursorInfo->pCacheWin = NullWindow; + pCursorInfo->isInCacheWin = FALSE; + pCursorInfo->checkPixels = TRUE; + pCursorInfo->pScreen = FALSE; + + ret = (*pScreenPriv->funcs->DeviceCursorInitialize)(pDev, pScreen); + if (!ret) + { + free(pCursorInfo); + pCursorInfo = NULL; + } + dixSetPrivate(&pDev->devPrivates, miSpriteDevPrivatesKey, pCursorInfo); + return ret; +} + +static void +miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + if (DevHasCursor(pDev)) + { + miSpriteScreenPtr pScreenPriv; + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, + miSpriteScreenKey); + + (*pScreenPriv->funcs->DeviceCursorCleanup)(pDev, pScreen); + } +} + +/* + * undraw/draw cursor + */ + +static void +miSpriteRemoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + miCursorInfoPtr pCursorInfo; + + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + pCursorInfo = MISPRITE(pDev); + + miSpriteIsDown(pCursorInfo); + pCursorInfo->pCacheWin = NullWindow; + miSpriteDisableDamage(pScreen, pScreenPriv); + if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pDev, + pScreen, + pCursorInfo->saved.x1, + pCursorInfo->saved.y1, + pCursorInfo->saved.x2 - + pCursorInfo->saved.x1, + pCursorInfo->saved.y2 - + pCursorInfo->saved.y1)) + { + miSpriteIsUp(pCursorInfo); + } + miSpriteEnableDamage(pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); +} + +/* + * Called from the block handler, saves area under cursor + * before waiting for something to do. + */ + +static void +miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + int x, y; + CursorPtr pCursor; + miCursorInfoPtr pCursorInfo; + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + pCursorInfo = MISPRITE(pDev); + + miSpriteComputeSaved (pDev, pScreen); + pCursor = pCursorInfo->pCursor; + + x = pCursorInfo->x - (int)pCursor->bits->xhot; + y = pCursorInfo->y - (int)pCursor->bits->yhot; + miSpriteDisableDamage(pScreen, pScreenPriv); + + (*pScreenPriv->funcs->SaveUnderCursor) (pDev, + pScreen, + pCursorInfo->saved.x1, + pCursorInfo->saved.y1, + pCursorInfo->saved.x2 - + pCursorInfo->saved.x1, + pCursorInfo->saved.y2 - + pCursorInfo->saved.y1); + SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id)); + miSpriteEnableDamage(pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); +} + + +/* + * Called from the block handler, restores the cursor + * before waiting for something to do. + */ + +static void +miSpriteRestoreCursor (DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + int x, y; + CursorPtr pCursor; + miCursorInfoPtr pCursorInfo; + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + pCursorInfo = MISPRITE(pDev); + + miSpriteComputeSaved (pDev, pScreen); + pCursor = pCursorInfo->pCursor; + + x = pCursorInfo->x - (int)pCursor->bits->xhot; + y = pCursorInfo->y - (int)pCursor->bits->yhot; + miSpriteDisableDamage(pScreen, pScreenPriv); + SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id)); + if (pCursorInfo->checkPixels) + miSpriteFindColors (pCursorInfo, pScreen); + if ((*pScreenPriv->funcs->PutUpCursor) (pDev, pScreen, + pCursor, x, y, + pScreenPriv->colors[SOURCE_COLOR].pixel, + pScreenPriv->colors[MASK_COLOR].pixel)) + { + miSpriteIsUp(pCursorInfo); + pCursorInfo->pScreen = pScreen; + } + miSpriteEnableDamage(pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); +} + +/* + * compute the desired area of the screen to save + */ + +static void +miSpriteComputeSaved (DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + int x, y, w, h; + int wpad, hpad; + CursorPtr pCursor; + miCursorInfoPtr pCursorInfo; + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey); + pCursorInfo = MISPRITE(pDev); + + pCursor = pCursorInfo->pCursor; + x = pCursorInfo->x - (int)pCursor->bits->xhot; + y = pCursorInfo->y - (int)pCursor->bits->yhot; + w = pCursor->bits->width; + h = pCursor->bits->height; + wpad = SPRITE_PAD; + hpad = SPRITE_PAD; + pCursorInfo->saved.x1 = x - wpad; + pCursorInfo->saved.y1 = y - hpad; + pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2; + pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2; +} + diff --git a/xorg-server/mi/miwideline.c b/xorg-server/mi/miwideline.c index 181b12e48..9fb540c2b 100644 --- a/xorg-server/mi/miwideline.c +++ b/xorg-server/mi/miwideline.c @@ -1,2260 +1,2193 @@ -/* - -Copyright 1988, 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 */ - -/* - * Mostly integer wideline code. Uses a technique similar to - * bresenham zero-width lines, except walks an X edge - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <stdio.h> -#ifdef _XOPEN_SOURCE -#include <math.h> -#else -#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */ -#include <math.h> -#undef _XOPEN_SOURCE -#endif -#include <X11/X.h> -#include "windowstr.h" -#include "gcstruct.h" -#include "regionstr.h" -#include "miwideline.h" -#include "mi.h" - -/* - * interface data to span-merging polygon filler - */ - -typedef struct _SpanData { - SpanGroup fgGroup, bgGroup; -} SpanDataRec, *SpanDataPtr; - -static void -AppendSpanGroup(GCPtr pGC, unsigned long pixel, Spans *spanPtr, SpanDataPtr spanData) -{ - SpanGroup *group, *othergroup = NULL; - if (pixel == pGC->fgPixel) - { - group = &spanData->fgGroup; - if (pGC->lineStyle == LineDoubleDash) - othergroup = &spanData->bgGroup; - } - else - { - group = &spanData->bgGroup; - othergroup = &spanData->fgGroup; - } - miAppendSpans (group, othergroup, spanPtr); -} - - -static void miLineArc(DrawablePtr pDraw, GCPtr pGC, - unsigned long pixel, SpanDataPtr spanData, - LineFacePtr leftFace, - LineFacePtr rightFace, - double xorg, double yorg, Bool isInt); - - -/* - * spans-based polygon filler - */ - -static void -miFillPolyHelper (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, - SpanDataPtr spanData, int y, int overall_height, - PolyEdgePtr left, PolyEdgePtr right, - int left_count, int right_count) -{ - int left_x = 0, left_e = 0; - int left_stepx = 0; - int left_signdx = 0; - int left_dy = 0, left_dx = 0; - - int right_x = 0, right_e = 0; - int right_stepx = 0; - int right_signdx = 0; - int right_dy = 0, right_dx = 0; - - int height = 0; - int left_height = 0, right_height = 0; - - DDXPointPtr ppt; - DDXPointPtr pptInit = NULL; - int *pwidth; - int *pwidthInit = NULL; - XID oldPixel; - int xorg; - Spans spanRec; - - left_height = 0; - right_height = 0; - - if (!spanData) - { - pptInit = xalloc (overall_height * sizeof(*ppt)); - if (!pptInit) - return; - pwidthInit = xalloc (overall_height * sizeof(*pwidth)); - if (!pwidthInit) - { - xfree (pptInit); - return; - } - ppt = pptInit; - pwidth = pwidthInit; - oldPixel = pGC->fgPixel; - if (pixel != oldPixel) - { - XID tmpPixel = (XID)pixel; - DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE); - ValidateGC (pDrawable, pGC); - } - } - else - { - spanRec.points = xalloc (overall_height * sizeof (*ppt)); - if (!spanRec.points) - return; - spanRec.widths = xalloc (overall_height * sizeof (int)); - if (!spanRec.widths) - { - xfree (spanRec.points); - return; - } - ppt = spanRec.points; - pwidth = spanRec.widths; - } - - xorg = 0; - if (pGC->miTranslate) - { - y += pDrawable->y; - xorg = pDrawable->x; - } - while ((left_count || left_height) && - (right_count || right_height)) - { - if (!left_height && left_count) - { - left_height = left->height; - left_x = left->x; - left_stepx = left->stepx; - left_signdx = left->signdx; - left_e = left->e; - left_dy = left->dy; - left_dx = left->dx; - --left_count; - ++left; - } - - if (!right_height && right_count) - { - right_height = right->height; - right_x = right->x; - right_stepx = right->stepx; - right_signdx = right->signdx; - right_e = right->e; - right_dy = right->dy; - right_dx = right->dx; - --right_count; - ++right; - } - - height = left_height; - if (height > right_height) - height = right_height; - - left_height -= height; - right_height -= height; - - while (--height >= 0) - { - if (right_x >= left_x) - { - ppt->y = y; - ppt->x = left_x + xorg; - ppt++; - *pwidth++ = right_x - left_x + 1; - } - y++; - - left_x += left_stepx; - left_e += left_dx; - if (left_e > 0) - { - left_x += left_signdx; - left_e -= left_dy; - } - - right_x += right_stepx; - right_e += right_dx; - if (right_e > 0) - { - right_x += right_signdx; - right_e -= right_dy; - } - } - } - if (!spanData) - { - (*pGC->ops->FillSpans) (pDrawable, pGC, ppt - pptInit, pptInit, pwidthInit, TRUE); - xfree (pwidthInit); - xfree (pptInit); - if (pixel != oldPixel) - { - DoChangeGC (pGC, GCForeground, &oldPixel, FALSE); - ValidateGC (pDrawable, pGC); - } - } - else - { - spanRec.count = ppt - spanRec.points; - AppendSpanGroup (pGC, pixel, &spanRec, spanData); - } -} - -static void -miFillRectPolyHelper ( - DrawablePtr pDrawable, - GCPtr pGC, - unsigned long pixel, - SpanDataPtr spanData, - int x, - int y, - int w, - int h) -{ - DDXPointPtr ppt; - int *pwidth; - XID oldPixel; - Spans spanRec; - xRectangle rect; - - if (!spanData) - { - rect.x = x; - rect.y = y; - rect.width = w; - rect.height = h; - oldPixel = pGC->fgPixel; - if (pixel != oldPixel) - { - XID tmpPixel = (XID)pixel; - DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE); - ValidateGC (pDrawable, pGC); - } - (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect); - if (pixel != oldPixel) - { - DoChangeGC (pGC, GCForeground, &oldPixel, FALSE); - ValidateGC (pDrawable, pGC); - } - } - else - { - spanRec.points = xalloc (h * sizeof (*ppt)); - if (!spanRec.points) - return; - spanRec.widths = xalloc (h * sizeof (int)); - if (!spanRec.widths) - { - xfree (spanRec.points); - return; - } - ppt = spanRec.points; - pwidth = spanRec.widths; - - if (pGC->miTranslate) - { - y += pDrawable->y; - x += pDrawable->x; - } - while (h--) - { - ppt->x = x; - ppt->y = y; - ppt++; - *pwidth++ = w; - y++; - } - spanRec.count = ppt - spanRec.points; - AppendSpanGroup (pGC, pixel, &spanRec, spanData); - } -} - -/* static */ int -miPolyBuildEdge ( - double x0, - double y0, - double k, /* x0 * dy - y0 * dx */ - int dx, - int dy, - int xi, - int yi, - int left, - PolyEdgePtr edge) -{ - int x, y, e; - int xady; - - if (dy < 0) - { - dy = -dy; - dx = -dx; - k = -k; - } - -#ifdef NOTDEF - { - double realk, kerror; - realk = x0 * dy - y0 * dx; - kerror = Fabs (realk - k); - if (kerror > .1) - printf ("realk: %g k: %g\n", realk, k); - } -#endif - y = ICEIL (y0); - xady = ICEIL (k) + y * dx; - - if (xady <= 0) - x = - (-xady / dy) - 1; - else - x = (xady - 1) / dy; - - e = xady - x * dy; - - if (dx >= 0) - { - edge->signdx = 1; - edge->stepx = dx / dy; - edge->dx = dx % dy; - } - else - { - edge->signdx = -1; - edge->stepx = - (-dx / dy); - edge->dx = -dx % dy; - e = dy - e + 1; - } - edge->dy = dy; - edge->x = x + left + xi; - edge->e = e - dy; /* bias to compare against 0 instead of dy */ - return y + yi; -} - -#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr))) - -/* static */ int -miPolyBuildPoly ( - PolyVertexPtr vertices, - PolySlopePtr slopes, - int count, - int xi, - int yi, - PolyEdgePtr left, - PolyEdgePtr right, - int *pnleft, - int *pnright, - int *h) -{ - int top, bottom; - double miny, maxy; - int i; - int j; - int clockwise; - int slopeoff; - int s; - int nright, nleft; - int y, lasty = 0, bottomy, topy = 0; - - /* find the top of the polygon */ - maxy = miny = vertices[0].y; - bottom = top = 0; - for (i = 1; i < count; i++) - { - if (vertices[i].y < miny) - { - top = i; - miny = vertices[i].y; - } - if (vertices[i].y >= maxy) - { - bottom = i; - maxy = vertices[i].y; - } - } - clockwise = 1; - slopeoff = 0; - - i = top; - j = StepAround (top, -1, count); - - if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx) - { - clockwise = -1; - slopeoff = -1; - } - - bottomy = ICEIL (maxy) + yi; - - nright = 0; - - s = StepAround (top, slopeoff, count); - i = top; - while (i != bottom) - { - if (slopes[s].dy != 0) - { - y = miPolyBuildEdge (vertices[i].x, vertices[i].y, - slopes[s].k, - slopes[s].dx, slopes[s].dy, - xi, yi, 0, - &right[nright]); - if (nright != 0) - right[nright-1].height = y - lasty; - else - topy = y; - nright++; - lasty = y; - } - - i = StepAround (i, clockwise, count); - s = StepAround (s, clockwise, count); - } - if (nright != 0) - right[nright-1].height = bottomy - lasty; - - if (slopeoff == 0) - slopeoff = -1; - else - slopeoff = 0; - - nleft = 0; - s = StepAround (top, slopeoff, count); - i = top; - while (i != bottom) - { - if (slopes[s].dy != 0) - { - y = miPolyBuildEdge (vertices[i].x, vertices[i].y, - slopes[s].k, - slopes[s].dx, slopes[s].dy, xi, yi, 1, - &left[nleft]); - - if (nleft != 0) - left[nleft-1].height = y - lasty; - nleft++; - lasty = y; - } - i = StepAround (i, -clockwise, count); - s = StepAround (s, -clockwise, count); - } - if (nleft != 0) - left[nleft-1].height = bottomy - lasty; - *pnleft = nleft; - *pnright = nright; - *h = bottomy - topy; - return topy; -} - -static void -miLineOnePoint ( - DrawablePtr pDrawable, - GCPtr pGC, - unsigned long pixel, - SpanDataPtr spanData, - int x, - int y) -{ - DDXPointRec pt; - int wid; - unsigned long oldPixel; - - MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel); - if (pGC->fillStyle == FillSolid) - { - pt.x = x; - pt.y = y; - (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt); - } - else - { - wid = 1; - if (pGC->miTranslate) - { - x += pDrawable->x; - y += pDrawable->y; - } - pt.x = x; - pt.y = y; - (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE); - } - MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel); -} - -static void -miLineJoin ( - DrawablePtr pDrawable, - GCPtr pGC, - unsigned long pixel, - SpanDataPtr spanData, - LineFacePtr pLeft, - LineFacePtr pRight) -{ - double mx = 0, my = 0; - double denom = 0.0; - PolyVertexRec vertices[4]; - PolySlopeRec slopes[4]; - int edgecount; - PolyEdgeRec left[4], right[4]; - int nleft, nright; - int y, height; - int swapslopes; - int joinStyle = pGC->joinStyle; - int lw = pGC->lineWidth; - - if (lw == 1 && !spanData) { - /* See if one of the lines will draw the joining pixel */ - if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0)) - return; - if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0)) - return; - if (joinStyle != JoinRound) { - denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; - if (denom == 0) - return; /* no join to draw */ - } - if (joinStyle != JoinMiter) { - miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y); - return; - } - } else { - if (joinStyle == JoinRound) - { - miLineArc(pDrawable, pGC, pixel, spanData, - pLeft, pRight, - (double)0.0, (double)0.0, TRUE); - return; - } - denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; - if (denom == 0.0) - return; /* no join to draw */ - } - - swapslopes = 0; - if (denom > 0) - { - pLeft->xa = -pLeft->xa; - pLeft->ya = -pLeft->ya; - pLeft->dx = -pLeft->dx; - pLeft->dy = -pLeft->dy; - } - else - { - swapslopes = 1; - pRight->xa = -pRight->xa; - pRight->ya = -pRight->ya; - pRight->dx = -pRight->dx; - pRight->dy = -pRight->dy; - } - - vertices[0].x = pRight->xa; - vertices[0].y = pRight->ya; - slopes[0].dx = -pRight->dy; - slopes[0].dy = pRight->dx; - slopes[0].k = 0; - - vertices[1].x = 0; - vertices[1].y = 0; - slopes[1].dx = pLeft->dy; - slopes[1].dy = -pLeft->dx; - slopes[1].k = 0; - - vertices[2].x = pLeft->xa; - vertices[2].y = pLeft->ya; - - if (joinStyle == JoinMiter) - { - my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) - - pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx )) / - denom; - if (pLeft->dy != 0) - { - mx = pLeft->xa + (my - pLeft->ya) * - (double) pLeft->dx / (double) pLeft->dy; - } - else - { - mx = pRight->xa + (my - pRight->ya) * - (double) pRight->dx / (double) pRight->dy; - } - /* check miter limit */ - if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw) - joinStyle = JoinBevel; - } - - if (joinStyle == JoinMiter) - { - slopes[2].dx = pLeft->dx; - slopes[2].dy = pLeft->dy; - slopes[2].k = pLeft->k; - if (swapslopes) - { - slopes[2].dx = -slopes[2].dx; - slopes[2].dy = -slopes[2].dy; - slopes[2].k = -slopes[2].k; - } - vertices[3].x = mx; - vertices[3].y = my; - slopes[3].dx = pRight->dx; - slopes[3].dy = pRight->dy; - slopes[3].k = pRight->k; - if (swapslopes) - { - slopes[3].dx = -slopes[3].dx; - slopes[3].dy = -slopes[3].dy; - slopes[3].k = -slopes[3].k; - } - edgecount = 4; - } - else - { - double scale, dx, dy, adx, ady; - - adx = dx = pRight->xa - pLeft->xa; - ady = dy = pRight->ya - pLeft->ya; - if (adx < 0) - adx = -adx; - if (ady < 0) - ady = -ady; - scale = ady; - if (adx > ady) - scale = adx; - slopes[2].dx = (dx * 65536) / scale; - slopes[2].dy = (dy * 65536) / scale; - slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy - - (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0; - edgecount = 3; - } - - y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y, - left, right, &nleft, &nright, &height); - miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright); -} - -static int -miLineArcI ( - DrawablePtr pDraw, - GCPtr pGC, - int xorg, - int yorg, - DDXPointPtr points, - int *widths) -{ - DDXPointPtr tpts, bpts; - int *twids, *bwids; - int x, y, e, ex, slw; - - tpts = points; - twids = widths; - if (pGC->miTranslate) - { - xorg += pDraw->x; - yorg += pDraw->y; - } - slw = pGC->lineWidth; - if (slw == 1) - { - tpts->x = xorg; - tpts->y = yorg; - *twids = 1; - return 1; - } - bpts = tpts + slw; - bwids = twids + slw; - y = (slw >> 1) + 1; - if (slw & 1) - e = - ((y << 2) + 3); - else - e = - (y << 3); - ex = -4; - x = 0; - while (y) - { - e += (y << 3) - 4; - while (e >= 0) - { - x++; - e += (ex = -((x << 3) + 4)); - } - y--; - slw = (x << 1) + 1; - if ((e == ex) && (slw > 1)) - slw--; - tpts->x = xorg - x; - tpts->y = yorg - y; - tpts++; - *twids++ = slw; - if ((y != 0) && ((slw > 1) || (e != ex))) - { - bpts--; - bpts->x = xorg - x; - bpts->y = yorg + y; - *--bwids = slw; - } - } - return (pGC->lineWidth); -} - -#define CLIPSTEPEDGE(edgey,edge,edgeleft) \ - if (ybase == edgey) \ - { \ - if (edgeleft) \ - { \ - if (edge->x > xcl) \ - xcl = edge->x; \ - } \ - else \ - { \ - if (edge->x < xcr) \ - xcr = edge->x; \ - } \ - edgey++; \ - edge->x += edge->stepx; \ - edge->e += edge->dx; \ - if (edge->e > 0) \ - { \ - edge->x += edge->signdx; \ - edge->e -= edge->dy; \ - } \ - } - -static int -miLineArcD ( - DrawablePtr pDraw, - GCPtr pGC, - double xorg, - double yorg, - DDXPointPtr points, - int *widths, - PolyEdgePtr edge1, - int edgey1, - Bool edgeleft1, - PolyEdgePtr edge2, - int edgey2, - Bool edgeleft2) -{ - DDXPointPtr pts; - int *wids; - double radius, x0, y0, el, er, yk, xlk, xrk, k; - int xbase, ybase, y, boty, xl, xr, xcl, xcr; - int ymin, ymax; - Bool edge1IsMin, edge2IsMin; - int ymin1, ymin2; - - pts = points; - wids = widths; - xbase = floor(xorg); - x0 = xorg - xbase; - ybase = ICEIL (yorg); - y0 = yorg - ybase; - if (pGC->miTranslate) - { - xbase += pDraw->x; - ybase += pDraw->y; - edge1->x += pDraw->x; - edge2->x += pDraw->x; - edgey1 += pDraw->y; - edgey2 += pDraw->y; - } - xlk = x0 + x0 + 1.0; - xrk = x0 + x0 - 1.0; - yk = y0 + y0 - 1.0; - radius = ((double)pGC->lineWidth) / 2.0; - y = floor(radius - y0 + 1.0); - ybase -= y; - ymin = ybase; - ymax = 65536; - edge1IsMin = FALSE; - ymin1 = edgey1; - if (edge1->dy >= 0) - { - if (!edge1->dy) - { - if (edgeleft1) - edge1IsMin = TRUE; - else - ymax = edgey1; - edgey1 = 65536; - } - else - { - if ((edge1->signdx < 0) == edgeleft1) - edge1IsMin = TRUE; - } - } - edge2IsMin = FALSE; - ymin2 = edgey2; - if (edge2->dy >= 0) - { - if (!edge2->dy) - { - if (edgeleft2) - edge2IsMin = TRUE; - else - ymax = edgey2; - edgey2 = 65536; - } - else - { - if ((edge2->signdx < 0) == edgeleft2) - edge2IsMin = TRUE; - } - } - if (edge1IsMin) - { - ymin = ymin1; - if (edge2IsMin && ymin1 > ymin2) - ymin = ymin2; - } else if (edge2IsMin) - ymin = ymin2; - el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0); - er = el + xrk; - xl = 1; - xr = 0; - if (x0 < 0.5) - { - xl = 0; - el -= xlk; - } - boty = (y0 < -0.5) ? 1 : 0; - if (ybase + y - boty > ymax) - boty = ymax - ybase - y; - while (y > boty) - { - k = (y << 1) + yk; - er += k; - while (er > 0.0) - { - xr++; - er += xrk - (xr << 1); - } - el += k; - while (el >= 0.0) - { - xl--; - el += (xl << 1) - xlk; - } - y--; - ybase++; - if (ybase < ymin) - continue; - xcl = xl + xbase; - xcr = xr + xbase; - CLIPSTEPEDGE(edgey1, edge1, edgeleft1); - CLIPSTEPEDGE(edgey2, edge2, edgeleft2); - if (xcr >= xcl) - { - pts->x = xcl; - pts->y = ybase; - pts++; - *wids++ = xcr - xcl + 1; - } - } - er = xrk - (xr << 1) - er; - el = (xl << 1) - xlk - el; - boty = floor(-y0 - radius + 1.0); - if (ybase + y - boty > ymax) - boty = ymax - ybase - y; - while (y > boty) - { - k = (y << 1) + yk; - er -= k; - while ((er >= 0.0) && (xr >= 0)) - { - xr--; - er += xrk - (xr << 1); - } - el -= k; - while ((el > 0.0) && (xl <= 0)) - { - xl++; - el += (xl << 1) - xlk; - } - y--; - ybase++; - if (ybase < ymin) - continue; - xcl = xl + xbase; - xcr = xr + xbase; - CLIPSTEPEDGE(edgey1, edge1, edgeleft1); - CLIPSTEPEDGE(edgey2, edge2, edgeleft2); - if (xcr >= xcl) - { - pts->x = xcl; - pts->y = ybase; - pts++; - *wids++ = xcr - xcl + 1; - } - } - return (pts - points); -} - -static int -miRoundJoinFace (LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge) -{ - int y; - int dx, dy; - double xa, ya; - Bool left; - - dx = -face->dy; - dy = face->dx; - xa = face->xa; - ya = face->ya; - left = 1; - if (ya > 0) - { - ya = 0.0; - xa = 0.0; - } - if (dy < 0 || (dy == 0 && dx > 0)) - { - dx = -dx; - dy = -dy; - left = !left; - } - if (dx == 0 && dy == 0) - dy = 1; - if (dy == 0) - { - y = ICEIL (face->ya) + face->y; - edge->x = -32767; - edge->stepx = 0; - edge->signdx = 0; - edge->e = -1; - edge->dy = 0; - edge->dx = 0; - edge->height = 0; - } - else - { - y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge); - edge->height = 32767; - } - *leftEdge = !left; - return y; -} - -void -miRoundJoinClip (LineFacePtr pLeft, LineFacePtr pRight, - PolyEdgePtr edge1, PolyEdgePtr edge2, - int *y1, int *y2, Bool *left1, Bool *left2) -{ - double denom; - - denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; - - if (denom >= 0) - { - pLeft->xa = -pLeft->xa; - pLeft->ya = -pLeft->ya; - } - else - { - pRight->xa = -pRight->xa; - pRight->ya = -pRight->ya; - } - *y1 = miRoundJoinFace (pLeft, edge1, left1); - *y2 = miRoundJoinFace (pRight, edge2, left2); -} - -int -miRoundCapClip (LineFacePtr face, Bool isInt, PolyEdgePtr edge, Bool *leftEdge) -{ - int y; - int dx, dy; - double xa, ya, k; - Bool left; - - dx = -face->dy; - dy = face->dx; - xa = face->xa; - ya = face->ya; - k = 0.0; - if (!isInt) - k = face->k; - left = 1; - if (dy < 0 || (dy == 0 && dx > 0)) - { - dx = -dx; - dy = -dy; - xa = -xa; - ya = -ya; - left = !left; - } - if (dx == 0 && dy == 0) - dy = 1; - if (dy == 0) - { - y = ICEIL (face->ya) + face->y; - edge->x = -32767; - edge->stepx = 0; - edge->signdx = 0; - edge->e = -1; - edge->dy = 0; - edge->dx = 0; - edge->height = 0; - } - else - { - y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge); - edge->height = 32767; - } - *leftEdge = !left; - return y; -} - -static void -miLineArc ( - DrawablePtr pDraw, - GCPtr pGC, - unsigned long pixel, - SpanDataPtr spanData, - LineFacePtr leftFace, - LineFacePtr rightFace, - double xorg, - double yorg, - Bool isInt) -{ - DDXPointPtr points; - int *widths; - int xorgi = 0, yorgi = 0; - XID oldPixel; - Spans spanRec; - int n; - PolyEdgeRec edge1, edge2; - int edgey1, edgey2; - Bool edgeleft1, edgeleft2; - - if (isInt) - { - xorgi = leftFace ? leftFace->x : rightFace->x; - yorgi = leftFace ? leftFace->y : rightFace->y; - } - edgey1 = 65536; - edgey2 = 65536; - edge1.x = 0; /* not used, keep memory checkers happy */ - edge1.dy = -1; - edge2.x = 0; /* not used, keep memory checkers happy */ - edge2.dy = -1; - edgeleft1 = FALSE; - edgeleft2 = FALSE; - if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) && - ((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) || - (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt))) - { - if (isInt) - { - xorg = (double) xorgi; - yorg = (double) yorgi; - } - if (leftFace && rightFace) - { - miRoundJoinClip (leftFace, rightFace, &edge1, &edge2, - &edgey1, &edgey2, &edgeleft1, &edgeleft2); - } - else if (leftFace) - { - edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1); - } - else if (rightFace) - { - edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2); - } - isInt = FALSE; - } - if (!spanData) - { - points = xalloc(sizeof(DDXPointRec) * pGC->lineWidth); - if (!points) - return; - widths = xalloc(sizeof(int) * pGC->lineWidth); - if (!widths) - { - xfree(points); - return; - } - oldPixel = pGC->fgPixel; - if (pixel != oldPixel) - { - XID tmpPixel = (XID)pixel; - DoChangeGC(pGC, GCForeground, &tmpPixel, FALSE); - ValidateGC (pDraw, pGC); - } - } - else - { - points = xalloc (pGC->lineWidth * sizeof (DDXPointRec)); - if (!points) - return; - widths = xalloc (pGC->lineWidth * sizeof (int)); - if (!widths) - { - xfree (points); - return; - } - spanRec.points = points; - spanRec.widths = widths; - } - if (isInt) - n = miLineArcI(pDraw, pGC, xorgi, yorgi, points, widths); - else - n = miLineArcD(pDraw, pGC, xorg, yorg, points, widths, - &edge1, edgey1, edgeleft1, - &edge2, edgey2, edgeleft2); - - if (!spanData) - { - (*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, TRUE); - xfree(widths); - xfree(points); - if (pixel != oldPixel) - { - DoChangeGC(pGC, GCForeground, &oldPixel, FALSE); - ValidateGC (pDraw, pGC); - } - } - else - { - spanRec.count = n; - AppendSpanGroup (pGC, pixel, &spanRec, spanData); - } -} - -static void -miLineProjectingCap (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, - SpanDataPtr spanData, LineFacePtr face, Bool isLeft, - double xorg, double yorg, Bool isInt) -{ - int xorgi = 0, yorgi = 0; - int lw; - PolyEdgeRec lefts[2], rights[2]; - int lefty, righty, topy, bottomy; - PolyEdgePtr left, right; - PolyEdgePtr top, bottom; - double xa,ya; - double k; - double xap, yap; - int dx, dy; - double projectXoff, projectYoff; - double maxy; - int finaly; - - if (isInt) - { - xorgi = face->x; - yorgi = face->y; - } - lw = pGC->lineWidth; - dx = face->dx; - dy = face->dy; - k = face->k; - if (dy == 0) - { - lefts[0].height = lw; - lefts[0].x = xorgi; - if (isLeft) - lefts[0].x -= (lw >> 1); - lefts[0].stepx = 0; - lefts[0].signdx = 1; - lefts[0].e = -lw; - lefts[0].dx = 0; - lefts[0].dy = lw; - rights[0].height = lw; - rights[0].x = xorgi; - if (!isLeft) - rights[0].x += ((lw + 1) >> 1); - rights[0].stepx = 0; - rights[0].signdx = 1; - rights[0].e = -lw; - rights[0].dx = 0; - rights[0].dy = lw; - miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw, - lefts, rights, 1, 1); - } - else if (dx == 0) - { - if (dy < 0) { - dy = -dy; - isLeft = !isLeft; - } - topy = yorgi; - bottomy = yorgi + dy; - if (isLeft) - topy -= (lw >> 1); - else - bottomy += (lw >> 1); - lefts[0].height = bottomy - topy; - lefts[0].x = xorgi - (lw >> 1); - lefts[0].stepx = 0; - lefts[0].signdx = 1; - lefts[0].e = -dy; - lefts[0].dx = dx; - lefts[0].dy = dy; - - rights[0].height = bottomy - topy; - rights[0].x = lefts[0].x + (lw-1); - rights[0].stepx = 0; - rights[0].signdx = 1; - rights[0].e = -dy; - rights[0].dx = dx; - rights[0].dy = dy; - miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1); - } - else - { - xa = face->xa; - ya = face->ya; - projectXoff = -ya; - projectYoff = xa; - if (dx < 0) - { - right = &rights[1]; - left = &lefts[0]; - top = &rights[0]; - bottom = &lefts[1]; - } - else - { - right = &rights[0]; - left = &lefts[1]; - top = &lefts[0]; - bottom = &rights[1]; - } - if (isLeft) - { - righty = miPolyBuildEdge (xa, ya, - k, dx, dy, xorgi, yorgi, 0, right); - - xa = -xa; - ya = -ya; - k = -k; - lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, - k, dx, dy, xorgi, yorgi, 1, left); - if (dx > 0) - { - ya = -ya; - xa = -xa; - } - xap = xa - projectXoff; - yap = ya - projectYoff; - topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, - -dy, dx, xorgi, yorgi, dx > 0, top); - bottomy = miPolyBuildEdge (xa, ya, - 0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom); - maxy = -ya; - } - else - { - righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, - k, dx, dy, xorgi, yorgi, 0, right); - - xa = -xa; - ya = -ya; - k = -k; - lefty = miPolyBuildEdge (xa, ya, - k, dx, dy, xorgi, yorgi, 1, left); - if (dx > 0) - { - ya = -ya; - xa = -xa; - } - xap = xa - projectXoff; - yap = ya - projectYoff; - topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top); - bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, - -dy, dx, xorgi, xorgi, dx < 0, bottom); - maxy = -ya + projectYoff; - } - finaly = ICEIL(maxy) + yorgi; - if (dx < 0) - { - left->height = bottomy - lefty; - right->height = finaly - righty; - top->height = righty - topy; - } - else - { - right->height = bottomy - righty; - left->height = finaly - lefty; - top->height = lefty - topy; - } - bottom->height = finaly - bottomy; - miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, - bottom->height + bottomy - topy, lefts, rights, 2, 2); - } -} - -static void -miWideSegment ( - DrawablePtr pDrawable, - GCPtr pGC, - unsigned long pixel, - SpanDataPtr spanData, - int x1, - int y1, - int x2, - int y2, - Bool projectLeft, - Bool projectRight, - LineFacePtr leftFace, - LineFacePtr rightFace) -{ - double l, L, r; - double xa, ya; - double projectXoff = 0.0, projectYoff = 0.0; - double k; - double maxy; - int x, y; - int dx, dy; - int finaly; - PolyEdgePtr left, right; - PolyEdgePtr top, bottom; - int lefty, righty, topy, bottomy; - int signdx; - PolyEdgeRec lefts[2], rights[2]; - LineFacePtr tface; - int lw = pGC->lineWidth; - - /* draw top-to-bottom always */ - if (y2 < y1 || (y2 == y1 && x2 < x1)) - { - x = x1; - x1 = x2; - x2 = x; - - y = y1; - y1 = y2; - y2 = y; - - x = projectLeft; - projectLeft = projectRight; - projectRight = x; - - tface = leftFace; - leftFace = rightFace; - rightFace = tface; - } - - dy = y2 - y1; - signdx = 1; - dx = x2 - x1; - if (dx < 0) - signdx = -1; - - leftFace->x = x1; - leftFace->y = y1; - leftFace->dx = dx; - leftFace->dy = dy; - - rightFace->x = x2; - rightFace->y = y2; - rightFace->dx = -dx; - rightFace->dy = -dy; - - if (dy == 0) - { - rightFace->xa = 0; - rightFace->ya = (double) lw / 2.0; - rightFace->k = -(double) (lw * dx) / 2.0; - leftFace->xa = 0; - leftFace->ya = -rightFace->ya; - leftFace->k = rightFace->k; - x = x1; - if (projectLeft) - x -= (lw >> 1); - y = y1 - (lw >> 1); - dx = x2 - x; - if (projectRight) - dx += ((lw + 1) >> 1); - dy = lw; - miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, - x, y, dx, dy); - } - else if (dx == 0) - { - leftFace->xa = (double) lw / 2.0; - leftFace->ya = 0; - leftFace->k = (double) (lw * dy) / 2.0; - rightFace->xa = -leftFace->xa; - rightFace->ya = 0; - rightFace->k = leftFace->k; - y = y1; - if (projectLeft) - y -= lw >> 1; - x = x1 - (lw >> 1); - dy = y2 - y; - if (projectRight) - dy += ((lw + 1) >> 1); - dx = lw; - miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, - x, y, dx, dy); - } - else - { - l = ((double) lw) / 2.0; - L = hypot ((double) dx, (double) dy); - - if (dx < 0) - { - right = &rights[1]; - left = &lefts[0]; - top = &rights[0]; - bottom = &lefts[1]; - } - else - { - right = &rights[0]; - left = &lefts[1]; - top = &lefts[0]; - bottom = &rights[1]; - } - r = l / L; - - /* coord of upper bound at integral y */ - ya = -r * dx; - xa = r * dy; - - if (projectLeft | projectRight) - { - projectXoff = -ya; - projectYoff = xa; - } - - /* xa * dy - ya * dx */ - k = l * L; - - leftFace->xa = xa; - leftFace->ya = ya; - leftFace->k = k; - rightFace->xa = -xa; - rightFace->ya = -ya; - rightFace->k = k; - - if (projectLeft) - righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, - k, dx, dy, x1, y1, 0, right); - else - righty = miPolyBuildEdge (xa, ya, - k, dx, dy, x1, y1, 0, right); - - /* coord of lower bound at integral y */ - ya = -ya; - xa = -xa; - - /* xa * dy - ya * dx */ - k = - k; - - if (projectLeft) - lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, - k, dx, dy, x1, y1, 1, left); - else - lefty = miPolyBuildEdge (xa, ya, - k, dx, dy, x1, y1, 1, left); - - /* coord of top face at integral y */ - - if (signdx > 0) - { - ya = -ya; - xa = -xa; - } - - if (projectLeft) - { - double xap = xa - projectXoff; - double yap = ya - projectYoff; - topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, - -dy, dx, x1, y1, dx > 0, top); - } - else - topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top); - - /* coord of bottom face at integral y */ - - if (projectRight) - { - double xap = xa + projectXoff; - double yap = ya + projectYoff; - bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, - -dy, dx, x2, y2, dx < 0, bottom); - maxy = -ya + projectYoff; - } - else - { - bottomy = miPolyBuildEdge (xa, ya, - 0.0, -dy, dx, x2, y2, dx < 0, bottom); - maxy = -ya; - } - - finaly = ICEIL (maxy) + y2; - - if (dx < 0) - { - left->height = bottomy - lefty; - right->height = finaly - righty; - top->height = righty - topy; - } - else - { - right->height = bottomy - righty; - left->height = finaly - lefty; - top->height = lefty - topy; - } - bottom->height = finaly - bottomy; - miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, - bottom->height + bottomy - topy, lefts, rights, 2, 2); - } -} - -static SpanDataPtr -miSetupSpanData (GCPtr pGC, SpanDataPtr spanData, int npt) -{ - if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu)) - return (SpanDataPtr) NULL; - if (pGC->lineStyle == LineDoubleDash) - miInitSpanGroup (&spanData->bgGroup); - miInitSpanGroup (&spanData->fgGroup); - return spanData; -} - -static void -miCleanupSpanData (DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData) -{ - if (pGC->lineStyle == LineDoubleDash) - { - XID oldPixel, pixel; - - pixel = pGC->bgPixel; - oldPixel = pGC->fgPixel; - if (pixel != oldPixel) - { - DoChangeGC (pGC, GCForeground, &pixel, FALSE); - ValidateGC (pDrawable, pGC); - } - miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup); - miFreeSpanGroup (&spanData->bgGroup); - if (pixel != oldPixel) - { - DoChangeGC (pGC, GCForeground, &oldPixel, FALSE); - ValidateGC (pDrawable, pGC); - } - } - miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup); - miFreeSpanGroup (&spanData->fgGroup); -} - -void -miWideLine (DrawablePtr pDrawable, GCPtr pGC, - int mode, int npt, DDXPointPtr pPts) -{ - int x1, y1, x2, y2; - SpanDataRec spanDataRec; - SpanDataPtr spanData; - long pixel; - Bool projectLeft, projectRight; - LineFaceRec leftFace, rightFace, prevRightFace; - LineFaceRec firstFace; - int first; - Bool somethingDrawn = FALSE; - Bool selfJoin; - - spanData = miSetupSpanData (pGC, &spanDataRec, npt); - pixel = pGC->fgPixel; - x2 = pPts->x; - y2 = pPts->y; - first = TRUE; - selfJoin = FALSE; - if (npt > 1) - { - if (mode == CoordModePrevious) - { - int nptTmp; - DDXPointPtr pPtsTmp; - - x1 = x2; - y1 = y2; - nptTmp = npt; - pPtsTmp = pPts + 1; - while (--nptTmp) - { - x1 += pPtsTmp->x; - y1 += pPtsTmp->y; - ++pPtsTmp; - } - if (x2 == x1 && y2 == y1) - selfJoin = TRUE; - } - else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) - { - selfJoin = TRUE; - } - } - projectLeft = pGC->capStyle == CapProjecting && !selfJoin; - projectRight = FALSE; - while (--npt) - { - x1 = x2; - y1 = y2; - ++pPts; - x2 = pPts->x; - y2 = pPts->y; - if (mode == CoordModePrevious) - { - x2 += x1; - y2 += y1; - } - if (x1 != x2 || y1 != y2) - { - somethingDrawn = TRUE; - if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin) - projectRight = TRUE; - miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2, - projectLeft, projectRight, &leftFace, &rightFace); - if (first) - { - if (selfJoin) - firstFace = leftFace; - else if (pGC->capStyle == CapRound) - { - if (pGC->lineWidth == 1 && !spanData) - miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1); - else - miLineArc (pDrawable, pGC, pixel, spanData, - &leftFace, (LineFacePtr) NULL, - (double)0.0, (double)0.0, - TRUE); - } - } - else - { - miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, - &prevRightFace); - } - prevRightFace = rightFace; - first = FALSE; - projectLeft = FALSE; - } - if (npt == 1 && somethingDrawn) - { - if (selfJoin) - miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, - &rightFace); - else if (pGC->capStyle == CapRound) - { - if (pGC->lineWidth == 1 && !spanData) - miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2); - else - miLineArc (pDrawable, pGC, pixel, spanData, - (LineFacePtr) NULL, &rightFace, - (double)0.0, (double)0.0, - TRUE); - } - } - } - /* handle crock where all points are coincedent */ - if (!somethingDrawn) - { - projectLeft = pGC->capStyle == CapProjecting; - miWideSegment (pDrawable, pGC, pixel, spanData, - x2, y2, x2, y2, projectLeft, projectLeft, - &leftFace, &rightFace); - if (pGC->capStyle == CapRound) - { - miLineArc (pDrawable, pGC, pixel, spanData, - &leftFace, (LineFacePtr) NULL, - (double)0.0, (double)0.0, - TRUE); - rightFace.dx = -1; /* sleezy hack to make it work */ - miLineArc (pDrawable, pGC, pixel, spanData, - (LineFacePtr) NULL, &rightFace, - (double)0.0, (double)0.0, - TRUE); - } - } - if (spanData) - miCleanupSpanData (pDrawable, pGC, spanData); -} - -#define V_TOP 0 -#define V_RIGHT 1 -#define V_BOTTOM 2 -#define V_LEFT 3 - -static void -miWideDashSegment ( - DrawablePtr pDrawable, - GCPtr pGC, - SpanDataPtr spanData, - int *pDashOffset, - int *pDashIndex, - int x1, - int y1, - int x2, - int y2, - Bool projectLeft, - Bool projectRight, - LineFacePtr leftFace, - LineFacePtr rightFace) -{ - int dashIndex, dashRemain; - unsigned char *pDash; - double L, l; - double k; - PolyVertexRec vertices[4]; - PolyVertexRec saveRight, saveBottom; - PolySlopeRec slopes[4]; - PolyEdgeRec left[2], right[2]; - LineFaceRec lcapFace, rcapFace; - int nleft, nright; - int h; - int y; - int dy, dx; - unsigned long pixel; - double LRemain; - double r; - double rdx, rdy; - double dashDx, dashDy; - double saveK = 0.0; - Bool first = TRUE; - double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0; - unsigned long fgPixel, bgPixel; - - dx = x2 - x1; - dy = y2 - y1; - dashIndex = *pDashIndex; - pDash = pGC->dash; - dashRemain = pDash[dashIndex] - *pDashOffset; - fgPixel = pGC->fgPixel; - bgPixel = pGC->bgPixel; - if (pGC->fillStyle == FillOpaqueStippled || - pGC->fillStyle == FillTiled) - { - bgPixel = fgPixel; - } - - l = ((double) pGC->lineWidth) / 2.0; - if (dx == 0) - { - L = dy; - rdx = 0; - rdy = l; - if (dy < 0) - { - L = -dy; - rdy = -l; - } - } - else if (dy == 0) - { - L = dx; - rdx = l; - rdy = 0; - if (dx < 0) - { - L = -dx; - rdx = -l; - } - } - else - { - L = hypot ((double) dx, (double) dy); - r = l / L; - - rdx = r * dx; - rdy = r * dy; - } - k = l * L; - LRemain = L; - /* All position comments are relative to a line with dx and dy > 0, - * but the code does not depend on this */ - /* top */ - slopes[V_TOP].dx = dx; - slopes[V_TOP].dy = dy; - slopes[V_TOP].k = k; - /* right */ - slopes[V_RIGHT].dx = -dy; - slopes[V_RIGHT].dy = dx; - slopes[V_RIGHT].k = 0; - /* bottom */ - slopes[V_BOTTOM].dx = -dx; - slopes[V_BOTTOM].dy = -dy; - slopes[V_BOTTOM].k = k; - /* left */ - slopes[V_LEFT].dx = dy; - slopes[V_LEFT].dy = -dx; - slopes[V_LEFT].k = 0; - - /* preload the start coordinates */ - vertices[V_RIGHT].x = vertices[V_TOP].x = rdy; - vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx; - - vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy; - vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx; - - if (projectLeft) - { - vertices[V_TOP].x -= rdx; - vertices[V_TOP].y -= rdy; - - vertices[V_LEFT].x -= rdx; - vertices[V_LEFT].y -= rdy; - - slopes[V_LEFT].k = rdx * dx + rdy * dy; - } - - lcenterx = x1; - lcentery = y1; - - if (pGC->capStyle == CapRound) - { - lcapFace.dx = dx; - lcapFace.dy = dy; - lcapFace.x = x1; - lcapFace.y = y1; - - rcapFace.dx = -dx; - rcapFace.dy = -dy; - rcapFace.x = x1; - rcapFace.y = y1; - } - while (LRemain > dashRemain) - { - dashDx = (dashRemain * dx) / L; - dashDy = (dashRemain * dy) / L; - - rcenterx = lcenterx + dashDx; - rcentery = lcentery + dashDy; - - vertices[V_RIGHT].x += dashDx; - vertices[V_RIGHT].y += dashDy; - - vertices[V_BOTTOM].x += dashDx; - vertices[V_BOTTOM].y += dashDy; - - slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy; - - if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) - { - if (pGC->lineStyle == LineOnOffDash && - pGC->capStyle == CapProjecting) - { - saveRight = vertices[V_RIGHT]; - saveBottom = vertices[V_BOTTOM]; - saveK = slopes[V_RIGHT].k; - - if (!first) - { - vertices[V_TOP].x -= rdx; - vertices[V_TOP].y -= rdy; - - vertices[V_LEFT].x -= rdx; - vertices[V_LEFT].y -= rdy; - - slopes[V_LEFT].k = vertices[V_LEFT].x * - slopes[V_LEFT].dy - - vertices[V_LEFT].y * - slopes[V_LEFT].dx; - } - - vertices[V_RIGHT].x += rdx; - vertices[V_RIGHT].y += rdy; - - vertices[V_BOTTOM].x += rdx; - vertices[V_BOTTOM].y += rdy; - - slopes[V_RIGHT].k = vertices[V_RIGHT].x * - slopes[V_RIGHT].dy - - vertices[V_RIGHT].y * - slopes[V_RIGHT].dx; - } - y = miPolyBuildPoly (vertices, slopes, 4, x1, y1, - left, right, &nleft, &nright, &h); - pixel = (dashIndex & 1) ? bgPixel : fgPixel; - miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); - - if (pGC->lineStyle == LineOnOffDash) - { - switch (pGC->capStyle) - { - case CapProjecting: - vertices[V_BOTTOM] = saveBottom; - vertices[V_RIGHT] = saveRight; - slopes[V_RIGHT].k = saveK; - break; - case CapRound: - if (!first) - { - if (dx < 0) - { - lcapFace.xa = -vertices[V_LEFT].x; - lcapFace.ya = -vertices[V_LEFT].y; - lcapFace.k = slopes[V_LEFT].k; - } - else - { - lcapFace.xa = vertices[V_TOP].x; - lcapFace.ya = vertices[V_TOP].y; - lcapFace.k = -slopes[V_LEFT].k; - } - miLineArc (pDrawable, pGC, pixel, spanData, - &lcapFace, (LineFacePtr) NULL, - lcenterx, lcentery, FALSE); - } - if (dx < 0) - { - rcapFace.xa = vertices[V_BOTTOM].x; - rcapFace.ya = vertices[V_BOTTOM].y; - rcapFace.k = slopes[V_RIGHT].k; - } - else - { - rcapFace.xa = -vertices[V_RIGHT].x; - rcapFace.ya = -vertices[V_RIGHT].y; - rcapFace.k = -slopes[V_RIGHT].k; - } - miLineArc (pDrawable, pGC, pixel, spanData, - (LineFacePtr) NULL, &rcapFace, - rcenterx, rcentery, FALSE); - break; - } - } - } - LRemain -= dashRemain; - ++dashIndex; - if (dashIndex == pGC->numInDashList) - dashIndex = 0; - dashRemain = pDash[dashIndex]; - - lcenterx = rcenterx; - lcentery = rcentery; - - vertices[V_TOP] = vertices[V_RIGHT]; - vertices[V_LEFT] = vertices[V_BOTTOM]; - slopes[V_LEFT].k = -slopes[V_RIGHT].k; - first = FALSE; - } - - if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) - { - vertices[V_TOP].x -= dx; - vertices[V_TOP].y -= dy; - - vertices[V_LEFT].x -= dx; - vertices[V_LEFT].y -= dy; - - vertices[V_RIGHT].x = rdy; - vertices[V_RIGHT].y = -rdx; - - vertices[V_BOTTOM].x = -rdy; - vertices[V_BOTTOM].y = rdx; - - - if (projectRight) - { - vertices[V_RIGHT].x += rdx; - vertices[V_RIGHT].y += rdy; - - vertices[V_BOTTOM].x += rdx; - vertices[V_BOTTOM].y += rdy; - slopes[V_RIGHT].k = vertices[V_RIGHT].x * - slopes[V_RIGHT].dy - - vertices[V_RIGHT].y * - slopes[V_RIGHT].dx; - } - else - slopes[V_RIGHT].k = 0; - - if (!first && pGC->lineStyle == LineOnOffDash && - pGC->capStyle == CapProjecting) - { - vertices[V_TOP].x -= rdx; - vertices[V_TOP].y -= rdy; - - vertices[V_LEFT].x -= rdx; - vertices[V_LEFT].y -= rdy; - slopes[V_LEFT].k = vertices[V_LEFT].x * - slopes[V_LEFT].dy - - vertices[V_LEFT].y * - slopes[V_LEFT].dx; - } - else - slopes[V_LEFT].k += dx * dx + dy * dy; - - - y = miPolyBuildPoly (vertices, slopes, 4, x2, y2, - left, right, &nleft, &nright, &h); - - pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; - miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); - if (!first && pGC->lineStyle == LineOnOffDash && - pGC->capStyle == CapRound) - { - lcapFace.x = x2; - lcapFace.y = y2; - if (dx < 0) - { - lcapFace.xa = -vertices[V_LEFT].x; - lcapFace.ya = -vertices[V_LEFT].y; - lcapFace.k = slopes[V_LEFT].k; - } - else - { - lcapFace.xa = vertices[V_TOP].x; - lcapFace.ya = vertices[V_TOP].y; - lcapFace.k = -slopes[V_LEFT].k; - } - miLineArc (pDrawable, pGC, pixel, spanData, - &lcapFace, (LineFacePtr) NULL, - rcenterx, rcentery, FALSE); - } - } - dashRemain = ((double) dashRemain) - LRemain; - if (dashRemain == 0) - { - dashIndex++; - if (dashIndex == pGC->numInDashList) - dashIndex = 0; - dashRemain = pDash[dashIndex]; - } - - leftFace->x = x1; - leftFace->y = y1; - leftFace->dx = dx; - leftFace->dy = dy; - leftFace->xa = rdy; - leftFace->ya = -rdx; - leftFace->k = k; - - rightFace->x = x2; - rightFace->y = y2; - rightFace->dx = -dx; - rightFace->dy = -dy; - rightFace->xa = -rdy; - rightFace->ya = rdx; - rightFace->k = k; - - *pDashIndex = dashIndex; - *pDashOffset = pDash[dashIndex] - dashRemain; -} - -void -miWideDash (DrawablePtr pDrawable, GCPtr pGC, - int mode, int npt, DDXPointPtr pPts) -{ - int x1, y1, x2, y2; - unsigned long pixel; - Bool projectLeft, projectRight; - LineFaceRec leftFace, rightFace, prevRightFace; - LineFaceRec firstFace; - int first; - int dashIndex, dashOffset; - int prevDashIndex; - SpanDataRec spanDataRec; - SpanDataPtr spanData; - Bool somethingDrawn = FALSE; - Bool selfJoin; - Bool endIsFg = FALSE, startIsFg = FALSE; - Bool firstIsFg = FALSE, prevIsFg = FALSE; - -#if 0 - /* XXX backward compatibility */ - if (pGC->lineWidth == 0) - { - miZeroDashLine (pDrawable, pGC, mode, npt, pPts); - return; - } -#endif - if (pGC->lineStyle == LineDoubleDash && - (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled)) - { - miWideLine (pDrawable, pGC, mode, npt, pPts); - return; - } - if (npt == 0) - return; - spanData = miSetupSpanData (pGC, &spanDataRec, npt); - x2 = pPts->x; - y2 = pPts->y; - first = TRUE; - selfJoin = FALSE; - if (mode == CoordModePrevious) - { - int nptTmp; - DDXPointPtr pPtsTmp; - - x1 = x2; - y1 = y2; - nptTmp = npt; - pPtsTmp = pPts + 1; - while (--nptTmp) - { - x1 += pPtsTmp->x; - y1 += pPtsTmp->y; - ++pPtsTmp; - } - if (x2 == x1 && y2 == y1) - selfJoin = TRUE; - } - else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) - { - selfJoin = TRUE; - } - projectLeft = pGC->capStyle == CapProjecting && !selfJoin; - projectRight = FALSE; - dashIndex = 0; - dashOffset = 0; - miStepDash ((int)pGC->dashOffset, &dashIndex, - pGC->dash, (int)pGC->numInDashList, &dashOffset); - while (--npt) - { - x1 = x2; - y1 = y2; - ++pPts; - x2 = pPts->x; - y2 = pPts->y; - if (mode == CoordModePrevious) - { - x2 += x1; - y2 += y1; - } - if (x1 != x2 || y1 != y2) - { - somethingDrawn = TRUE; - if (npt == 1 && pGC->capStyle == CapProjecting && - (!selfJoin || !firstIsFg)) - projectRight = TRUE; - prevDashIndex = dashIndex; - miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex, - x1, y1, x2, y2, - projectLeft, projectRight, &leftFace, &rightFace); - startIsFg = !(prevDashIndex & 1); - endIsFg = (dashIndex & 1) ^ (dashOffset != 0); - if (pGC->lineStyle == LineDoubleDash || startIsFg) - { - pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel; - if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg)) - { - if (first && selfJoin) - { - firstFace = leftFace; - firstIsFg = startIsFg; - } - else if (pGC->capStyle == CapRound) - miLineArc (pDrawable, pGC, pixel, spanData, - &leftFace, (LineFacePtr) NULL, - (double)0.0, (double)0.0, TRUE); - } - else - { - miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, - &prevRightFace); - } - } - prevRightFace = rightFace; - prevIsFg = endIsFg; - first = FALSE; - projectLeft = FALSE; - } - if (npt == 1 && somethingDrawn) - { - if (pGC->lineStyle == LineDoubleDash || endIsFg) - { - pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel; - if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg)) - { - miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, - &rightFace); - } - else - { - if (pGC->capStyle == CapRound) - miLineArc (pDrawable, pGC, pixel, spanData, - (LineFacePtr) NULL, &rightFace, - (double)0.0, (double)0.0, TRUE); - } - } - else - { - /* glue a cap to the start of the line if - * we're OnOffDash and ended on odd dash - */ - if (selfJoin && firstIsFg) - { - pixel = pGC->fgPixel; - if (pGC->capStyle == CapProjecting) - miLineProjectingCap (pDrawable, pGC, pixel, spanData, - &firstFace, TRUE, - (double)0.0, (double)0.0, TRUE); - else if (pGC->capStyle == CapRound) - miLineArc (pDrawable, pGC, pixel, spanData, - &firstFace, (LineFacePtr) NULL, - (double)0.0, (double)0.0, TRUE); - } - } - } - } - /* handle crock where all points are coincident */ - if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))) - { - /* not the same as endIsFg computation above */ - pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; - switch (pGC->capStyle) { - case CapRound: - miLineArc (pDrawable, pGC, pixel, spanData, - (LineFacePtr) NULL, (LineFacePtr) NULL, - (double)x2, (double)y2, - FALSE); - break; - case CapProjecting: - x1 = pGC->lineWidth; - miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, - x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1); - break; - } - } - if (spanData) - miCleanupSpanData (pDrawable, pGC, spanData); -} +/* + +Copyright 1988, 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 */ + +/* + * Mostly integer wideline code. Uses a technique similar to + * bresenham zero-width lines, except walks an X edge + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdio.h> +#ifdef _XOPEN_SOURCE +#include <math.h> +#else +#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */ +#include <math.h> +#undef _XOPEN_SOURCE +#endif +#include <X11/X.h> +#include "windowstr.h" +#include "gcstruct.h" +#include "regionstr.h" +#include "miwideline.h" +#include "mi.h" + +static Bool +InitSpans(Spans *spans, size_t nspans) +{ + spans->points = malloc(nspans * sizeof (*spans->points)); + if (!spans->points) + return FALSE; + spans->widths = malloc(nspans * sizeof (*spans->widths)); + if (!spans->widths) + { + free(spans->points); + return FALSE; + } + return TRUE; +} + +/* + * interface data to span-merging polygon filler + */ + +typedef struct _SpanData { + SpanGroup fgGroup, bgGroup; +} SpanDataRec, *SpanDataPtr; + +static void +AppendSpanGroup(GCPtr pGC, unsigned long pixel, Spans *spanPtr, SpanDataPtr spanData) +{ + SpanGroup *group, *othergroup = NULL; + if (pixel == pGC->fgPixel) + { + group = &spanData->fgGroup; + if (pGC->lineStyle == LineDoubleDash) + othergroup = &spanData->bgGroup; + } + else + { + group = &spanData->bgGroup; + othergroup = &spanData->fgGroup; + } + miAppendSpans (group, othergroup, spanPtr); +} + + +static void miLineArc(DrawablePtr pDraw, GCPtr pGC, + unsigned long pixel, SpanDataPtr spanData, + LineFacePtr leftFace, + LineFacePtr rightFace, + double xorg, double yorg, Bool isInt); + + +/* + * spans-based polygon filler + */ + +static void +fillSpans(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, Spans *spans, SpanDataPtr spanData) +{ + if (!spanData) + { + ChangeGCVal oldPixel, tmpPixel; + oldPixel.val = pGC->fgPixel; + if (pixel != oldPixel.val) + { + tmpPixel.val = (XID)pixel; + ChangeGC (NullClient, pGC, GCForeground, &tmpPixel); + ValidateGC (pDrawable, pGC); + } + (*pGC->ops->FillSpans) (pDrawable, pGC, spans->count, spans->points, spans->widths, TRUE); + free(spans->widths); + free(spans->points); + if (pixel != oldPixel.val) + { + ChangeGC (NullClient, pGC, GCForeground, &oldPixel); + ValidateGC (pDrawable, pGC); + } + } + else + AppendSpanGroup (pGC, pixel, spans, spanData); +} + +static void +miFillPolyHelper (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, + SpanDataPtr spanData, int y, int overall_height, + PolyEdgePtr left, PolyEdgePtr right, + int left_count, int right_count) +{ + int left_x = 0, left_e = 0; + int left_stepx = 0; + int left_signdx = 0; + int left_dy = 0, left_dx = 0; + + int right_x = 0, right_e = 0; + int right_stepx = 0; + int right_signdx = 0; + int right_dy = 0, right_dx = 0; + + int height = 0; + int left_height = 0, right_height = 0; + + DDXPointPtr ppt; + int *pwidth; + int xorg; + Spans spanRec; + + if (!InitSpans(&spanRec, overall_height)) + return; + ppt = spanRec.points; + pwidth = spanRec.widths; + + xorg = 0; + if (pGC->miTranslate) + { + y += pDrawable->y; + xorg = pDrawable->x; + } + while ((left_count || left_height) && + (right_count || right_height)) + { + if (!left_height && left_count) + { + left_height = left->height; + left_x = left->x; + left_stepx = left->stepx; + left_signdx = left->signdx; + left_e = left->e; + left_dy = left->dy; + left_dx = left->dx; + --left_count; + ++left; + } + + if (!right_height && right_count) + { + right_height = right->height; + right_x = right->x; + right_stepx = right->stepx; + right_signdx = right->signdx; + right_e = right->e; + right_dy = right->dy; + right_dx = right->dx; + --right_count; + ++right; + } + + height = left_height; + if (height > right_height) + height = right_height; + + left_height -= height; + right_height -= height; + + while (--height >= 0) + { + if (right_x >= left_x) + { + ppt->y = y; + ppt->x = left_x + xorg; + ppt++; + *pwidth++ = right_x - left_x + 1; + } + y++; + + left_x += left_stepx; + left_e += left_dx; + if (left_e > 0) + { + left_x += left_signdx; + left_e -= left_dy; + } + + right_x += right_stepx; + right_e += right_dx; + if (right_e > 0) + { + right_x += right_signdx; + right_e -= right_dy; + } + } + } + spanRec.count = ppt - spanRec.points; + fillSpans (pDrawable, pGC, pixel, &spanRec, spanData); +} + +static void +miFillRectPolyHelper ( + DrawablePtr pDrawable, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + int x, + int y, + int w, + int h) +{ + DDXPointPtr ppt; + int *pwidth; + ChangeGCVal oldPixel, tmpPixel; + Spans spanRec; + xRectangle rect; + + if (!spanData) + { + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + oldPixel.val = pGC->fgPixel; + if (pixel != oldPixel.val) + { + tmpPixel.val = (XID)pixel; + ChangeGC (NullClient, pGC, GCForeground, &tmpPixel); + ValidateGC (pDrawable, pGC); + } + (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect); + if (pixel != oldPixel.val) + { + ChangeGC (NullClient, pGC, GCForeground, &oldPixel); + ValidateGC (pDrawable, pGC); + } + } + else + { + if (!InitSpans(&spanRec, h)) + return; + ppt = spanRec.points; + pwidth = spanRec.widths; + + if (pGC->miTranslate) + { + y += pDrawable->y; + x += pDrawable->x; + } + while (h--) + { + ppt->x = x; + ppt->y = y; + ppt++; + *pwidth++ = w; + y++; + } + spanRec.count = ppt - spanRec.points; + AppendSpanGroup (pGC, pixel, &spanRec, spanData); + } +} + +/* static */ int +miPolyBuildEdge ( + double x0, + double y0, + double k, /* x0 * dy - y0 * dx */ + int dx, + int dy, + int xi, + int yi, + int left, + PolyEdgePtr edge) +{ + int x, y, e; + int xady; + + if (dy < 0) + { + dy = -dy; + dx = -dx; + k = -k; + } + +#ifdef NOTDEF + { + double realk, kerror; + realk = x0 * dy - y0 * dx; + kerror = Fabs (realk - k); + if (kerror > .1) + printf ("realk: %g k: %g\n", realk, k); + } +#endif + y = ICEIL (y0); + xady = ICEIL (k) + y * dx; + + if (xady <= 0) + x = - (-xady / dy) - 1; + else + x = (xady - 1) / dy; + + e = xady - x * dy; + + if (dx >= 0) + { + edge->signdx = 1; + edge->stepx = dx / dy; + edge->dx = dx % dy; + } + else + { + edge->signdx = -1; + edge->stepx = - (-dx / dy); + edge->dx = -dx % dy; + e = dy - e + 1; + } + edge->dy = dy; + edge->x = x + left + xi; + edge->e = e - dy; /* bias to compare against 0 instead of dy */ + return y + yi; +} + +#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr))) + +/* static */ int +miPolyBuildPoly ( + PolyVertexPtr vertices, + PolySlopePtr slopes, + int count, + int xi, + int yi, + PolyEdgePtr left, + PolyEdgePtr right, + int *pnleft, + int *pnright, + int *h) +{ + int top, bottom; + double miny, maxy; + int i; + int j; + int clockwise; + int slopeoff; + int s; + int nright, nleft; + int y, lasty = 0, bottomy, topy = 0; + + /* find the top of the polygon */ + maxy = miny = vertices[0].y; + bottom = top = 0; + for (i = 1; i < count; i++) + { + if (vertices[i].y < miny) + { + top = i; + miny = vertices[i].y; + } + if (vertices[i].y >= maxy) + { + bottom = i; + maxy = vertices[i].y; + } + } + clockwise = 1; + slopeoff = 0; + + i = top; + j = StepAround (top, -1, count); + + if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx) + { + clockwise = -1; + slopeoff = -1; + } + + bottomy = ICEIL (maxy) + yi; + + nright = 0; + + s = StepAround (top, slopeoff, count); + i = top; + while (i != bottom) + { + if (slopes[s].dy != 0) + { + y = miPolyBuildEdge (vertices[i].x, vertices[i].y, + slopes[s].k, + slopes[s].dx, slopes[s].dy, + xi, yi, 0, + &right[nright]); + if (nright != 0) + right[nright-1].height = y - lasty; + else + topy = y; + nright++; + lasty = y; + } + + i = StepAround (i, clockwise, count); + s = StepAround (s, clockwise, count); + } + if (nright != 0) + right[nright-1].height = bottomy - lasty; + + if (slopeoff == 0) + slopeoff = -1; + else + slopeoff = 0; + + nleft = 0; + s = StepAround (top, slopeoff, count); + i = top; + while (i != bottom) + { + if (slopes[s].dy != 0) + { + y = miPolyBuildEdge (vertices[i].x, vertices[i].y, + slopes[s].k, + slopes[s].dx, slopes[s].dy, xi, yi, 1, + &left[nleft]); + + if (nleft != 0) + left[nleft-1].height = y - lasty; + nleft++; + lasty = y; + } + i = StepAround (i, -clockwise, count); + s = StepAround (s, -clockwise, count); + } + if (nleft != 0) + left[nleft-1].height = bottomy - lasty; + *pnleft = nleft; + *pnright = nright; + *h = bottomy - topy; + return topy; +} + +static void +miLineOnePoint ( + DrawablePtr pDrawable, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + int x, + int y) +{ + DDXPointRec pt; + int wid; + unsigned long oldPixel; + + MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel); + if (pGC->fillStyle == FillSolid) + { + pt.x = x; + pt.y = y; + (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt); + } + else + { + wid = 1; + if (pGC->miTranslate) + { + x += pDrawable->x; + y += pDrawable->y; + } + pt.x = x; + pt.y = y; + (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE); + } + MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel); +} + +static void +miLineJoin ( + DrawablePtr pDrawable, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + LineFacePtr pLeft, + LineFacePtr pRight) +{ + double mx = 0, my = 0; + double denom = 0.0; + PolyVertexRec vertices[4]; + PolySlopeRec slopes[4]; + int edgecount; + PolyEdgeRec left[4], right[4]; + int nleft, nright; + int y, height; + int swapslopes; + int joinStyle = pGC->joinStyle; + int lw = pGC->lineWidth; + + if (lw == 1 && !spanData) { + /* See if one of the lines will draw the joining pixel */ + if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0)) + return; + if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0)) + return; + if (joinStyle != JoinRound) { + denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; + if (denom == 0) + return; /* no join to draw */ + } + if (joinStyle != JoinMiter) { + miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y); + return; + } + } else { + if (joinStyle == JoinRound) + { + miLineArc(pDrawable, pGC, pixel, spanData, + pLeft, pRight, + (double)0.0, (double)0.0, TRUE); + return; + } + denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; + if (denom == 0.0) + return; /* no join to draw */ + } + + swapslopes = 0; + if (denom > 0) + { + pLeft->xa = -pLeft->xa; + pLeft->ya = -pLeft->ya; + pLeft->dx = -pLeft->dx; + pLeft->dy = -pLeft->dy; + } + else + { + swapslopes = 1; + pRight->xa = -pRight->xa; + pRight->ya = -pRight->ya; + pRight->dx = -pRight->dx; + pRight->dy = -pRight->dy; + } + + vertices[0].x = pRight->xa; + vertices[0].y = pRight->ya; + slopes[0].dx = -pRight->dy; + slopes[0].dy = pRight->dx; + slopes[0].k = 0; + + vertices[1].x = 0; + vertices[1].y = 0; + slopes[1].dx = pLeft->dy; + slopes[1].dy = -pLeft->dx; + slopes[1].k = 0; + + vertices[2].x = pLeft->xa; + vertices[2].y = pLeft->ya; + + if (joinStyle == JoinMiter) + { + my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) - + pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx )) / + denom; + if (pLeft->dy != 0) + { + mx = pLeft->xa + (my - pLeft->ya) * + (double) pLeft->dx / (double) pLeft->dy; + } + else + { + mx = pRight->xa + (my - pRight->ya) * + (double) pRight->dx / (double) pRight->dy; + } + /* check miter limit */ + if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw) + joinStyle = JoinBevel; + } + + if (joinStyle == JoinMiter) + { + slopes[2].dx = pLeft->dx; + slopes[2].dy = pLeft->dy; + slopes[2].k = pLeft->k; + if (swapslopes) + { + slopes[2].dx = -slopes[2].dx; + slopes[2].dy = -slopes[2].dy; + slopes[2].k = -slopes[2].k; + } + vertices[3].x = mx; + vertices[3].y = my; + slopes[3].dx = pRight->dx; + slopes[3].dy = pRight->dy; + slopes[3].k = pRight->k; + if (swapslopes) + { + slopes[3].dx = -slopes[3].dx; + slopes[3].dy = -slopes[3].dy; + slopes[3].k = -slopes[3].k; + } + edgecount = 4; + } + else + { + double scale, dx, dy, adx, ady; + + adx = dx = pRight->xa - pLeft->xa; + ady = dy = pRight->ya - pLeft->ya; + if (adx < 0) + adx = -adx; + if (ady < 0) + ady = -ady; + scale = ady; + if (adx > ady) + scale = adx; + slopes[2].dx = (dx * 65536) / scale; + slopes[2].dy = (dy * 65536) / scale; + slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy - + (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0; + edgecount = 3; + } + + y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y, + left, right, &nleft, &nright, &height); + miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright); +} + +static int +miLineArcI ( + DrawablePtr pDraw, + GCPtr pGC, + int xorg, + int yorg, + DDXPointPtr points, + int *widths) +{ + DDXPointPtr tpts, bpts; + int *twids, *bwids; + int x, y, e, ex, slw; + + tpts = points; + twids = widths; + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + } + slw = pGC->lineWidth; + if (slw == 1) + { + tpts->x = xorg; + tpts->y = yorg; + *twids = 1; + return 1; + } + bpts = tpts + slw; + bwids = twids + slw; + y = (slw >> 1) + 1; + if (slw & 1) + e = - ((y << 2) + 3); + else + e = - (y << 3); + ex = -4; + x = 0; + while (y) + { + e += (y << 3) - 4; + while (e >= 0) + { + x++; + e += (ex = -((x << 3) + 4)); + } + y--; + slw = (x << 1) + 1; + if ((e == ex) && (slw > 1)) + slw--; + tpts->x = xorg - x; + tpts->y = yorg - y; + tpts++; + *twids++ = slw; + if ((y != 0) && ((slw > 1) || (e != ex))) + { + bpts--; + bpts->x = xorg - x; + bpts->y = yorg + y; + *--bwids = slw; + } + } + return (pGC->lineWidth); +} + +#define CLIPSTEPEDGE(edgey,edge,edgeleft) \ + if (ybase == edgey) \ + { \ + if (edgeleft) \ + { \ + if (edge->x > xcl) \ + xcl = edge->x; \ + } \ + else \ + { \ + if (edge->x < xcr) \ + xcr = edge->x; \ + } \ + edgey++; \ + edge->x += edge->stepx; \ + edge->e += edge->dx; \ + if (edge->e > 0) \ + { \ + edge->x += edge->signdx; \ + edge->e -= edge->dy; \ + } \ + } + +static int +miLineArcD ( + DrawablePtr pDraw, + GCPtr pGC, + double xorg, + double yorg, + DDXPointPtr points, + int *widths, + PolyEdgePtr edge1, + int edgey1, + Bool edgeleft1, + PolyEdgePtr edge2, + int edgey2, + Bool edgeleft2) +{ + DDXPointPtr pts; + int *wids; + double radius, x0, y0, el, er, yk, xlk, xrk, k; + int xbase, ybase, y, boty, xl, xr, xcl, xcr; + int ymin, ymax; + Bool edge1IsMin, edge2IsMin; + int ymin1, ymin2; + + pts = points; + wids = widths; + xbase = floor(xorg); + x0 = xorg - xbase; + ybase = ICEIL (yorg); + y0 = yorg - ybase; + if (pGC->miTranslate) + { + xbase += pDraw->x; + ybase += pDraw->y; + edge1->x += pDraw->x; + edge2->x += pDraw->x; + edgey1 += pDraw->y; + edgey2 += pDraw->y; + } + xlk = x0 + x0 + 1.0; + xrk = x0 + x0 - 1.0; + yk = y0 + y0 - 1.0; + radius = ((double)pGC->lineWidth) / 2.0; + y = floor(radius - y0 + 1.0); + ybase -= y; + ymin = ybase; + ymax = 65536; + edge1IsMin = FALSE; + ymin1 = edgey1; + if (edge1->dy >= 0) + { + if (!edge1->dy) + { + if (edgeleft1) + edge1IsMin = TRUE; + else + ymax = edgey1; + edgey1 = 65536; + } + else + { + if ((edge1->signdx < 0) == edgeleft1) + edge1IsMin = TRUE; + } + } + edge2IsMin = FALSE; + ymin2 = edgey2; + if (edge2->dy >= 0) + { + if (!edge2->dy) + { + if (edgeleft2) + edge2IsMin = TRUE; + else + ymax = edgey2; + edgey2 = 65536; + } + else + { + if ((edge2->signdx < 0) == edgeleft2) + edge2IsMin = TRUE; + } + } + if (edge1IsMin) + { + ymin = ymin1; + if (edge2IsMin && ymin1 > ymin2) + ymin = ymin2; + } else if (edge2IsMin) + ymin = ymin2; + el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0); + er = el + xrk; + xl = 1; + xr = 0; + if (x0 < 0.5) + { + xl = 0; + el -= xlk; + } + boty = (y0 < -0.5) ? 1 : 0; + if (ybase + y - boty > ymax) + boty = ymax - ybase - y; + while (y > boty) + { + k = (y << 1) + yk; + er += k; + while (er > 0.0) + { + xr++; + er += xrk - (xr << 1); + } + el += k; + while (el >= 0.0) + { + xl--; + el += (xl << 1) - xlk; + } + y--; + ybase++; + if (ybase < ymin) + continue; + xcl = xl + xbase; + xcr = xr + xbase; + CLIPSTEPEDGE(edgey1, edge1, edgeleft1); + CLIPSTEPEDGE(edgey2, edge2, edgeleft2); + if (xcr >= xcl) + { + pts->x = xcl; + pts->y = ybase; + pts++; + *wids++ = xcr - xcl + 1; + } + } + er = xrk - (xr << 1) - er; + el = (xl << 1) - xlk - el; + boty = floor(-y0 - radius + 1.0); + if (ybase + y - boty > ymax) + boty = ymax - ybase - y; + while (y > boty) + { + k = (y << 1) + yk; + er -= k; + while ((er >= 0.0) && (xr >= 0)) + { + xr--; + er += xrk - (xr << 1); + } + el -= k; + while ((el > 0.0) && (xl <= 0)) + { + xl++; + el += (xl << 1) - xlk; + } + y--; + ybase++; + if (ybase < ymin) + continue; + xcl = xl + xbase; + xcr = xr + xbase; + CLIPSTEPEDGE(edgey1, edge1, edgeleft1); + CLIPSTEPEDGE(edgey2, edge2, edgeleft2); + if (xcr >= xcl) + { + pts->x = xcl; + pts->y = ybase; + pts++; + *wids++ = xcr - xcl + 1; + } + } + return (pts - points); +} + +static int +miRoundJoinFace (LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge) +{ + int y; + int dx, dy; + double xa, ya; + Bool left; + + dx = -face->dy; + dy = face->dx; + xa = face->xa; + ya = face->ya; + left = 1; + if (ya > 0) + { + ya = 0.0; + xa = 0.0; + } + if (dy < 0 || (dy == 0 && dx > 0)) + { + dx = -dx; + dy = -dy; + left = !left; + } + if (dx == 0 && dy == 0) + dy = 1; + if (dy == 0) + { + y = ICEIL (face->ya) + face->y; + edge->x = -32767; + edge->stepx = 0; + edge->signdx = 0; + edge->e = -1; + edge->dy = 0; + edge->dx = 0; + edge->height = 0; + } + else + { + y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge); + edge->height = 32767; + } + *leftEdge = !left; + return y; +} + +void +miRoundJoinClip (LineFacePtr pLeft, LineFacePtr pRight, + PolyEdgePtr edge1, PolyEdgePtr edge2, + int *y1, int *y2, Bool *left1, Bool *left2) +{ + double denom; + + denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; + + if (denom >= 0) + { + pLeft->xa = -pLeft->xa; + pLeft->ya = -pLeft->ya; + } + else + { + pRight->xa = -pRight->xa; + pRight->ya = -pRight->ya; + } + *y1 = miRoundJoinFace (pLeft, edge1, left1); + *y2 = miRoundJoinFace (pRight, edge2, left2); +} + +int +miRoundCapClip (LineFacePtr face, Bool isInt, PolyEdgePtr edge, Bool *leftEdge) +{ + int y; + int dx, dy; + double xa, ya, k; + Bool left; + + dx = -face->dy; + dy = face->dx; + xa = face->xa; + ya = face->ya; + k = 0.0; + if (!isInt) + k = face->k; + left = 1; + if (dy < 0 || (dy == 0 && dx > 0)) + { + dx = -dx; + dy = -dy; + xa = -xa; + ya = -ya; + left = !left; + } + if (dx == 0 && dy == 0) + dy = 1; + if (dy == 0) + { + y = ICEIL (face->ya) + face->y; + edge->x = -32767; + edge->stepx = 0; + edge->signdx = 0; + edge->e = -1; + edge->dy = 0; + edge->dx = 0; + edge->height = 0; + } + else + { + y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge); + edge->height = 32767; + } + *leftEdge = !left; + return y; +} + +static void +miLineArc ( + DrawablePtr pDraw, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + LineFacePtr leftFace, + LineFacePtr rightFace, + double xorg, + double yorg, + Bool isInt) +{ + int xorgi = 0, yorgi = 0; + Spans spanRec; + int n; + PolyEdgeRec edge1, edge2; + int edgey1, edgey2; + Bool edgeleft1, edgeleft2; + + if (isInt) + { + xorgi = leftFace ? leftFace->x : rightFace->x; + yorgi = leftFace ? leftFace->y : rightFace->y; + } + edgey1 = 65536; + edgey2 = 65536; + edge1.x = 0; /* not used, keep memory checkers happy */ + edge1.dy = -1; + edge2.x = 0; /* not used, keep memory checkers happy */ + edge2.dy = -1; + edgeleft1 = FALSE; + edgeleft2 = FALSE; + if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) && + ((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) || + (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt))) + { + if (isInt) + { + xorg = (double) xorgi; + yorg = (double) yorgi; + } + if (leftFace && rightFace) + { + miRoundJoinClip (leftFace, rightFace, &edge1, &edge2, + &edgey1, &edgey2, &edgeleft1, &edgeleft2); + } + else if (leftFace) + { + edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1); + } + else if (rightFace) + { + edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2); + } + isInt = FALSE; + } + if (!InitSpans(&spanRec, pGC->lineWidth)) + return; + if (isInt) + n = miLineArcI(pDraw, pGC, xorgi, yorgi, spanRec.points, spanRec.widths); + else + n = miLineArcD(pDraw, pGC, xorg, yorg, spanRec.points, spanRec.widths, + &edge1, edgey1, edgeleft1, + &edge2, edgey2, edgeleft2); + spanRec.count = n; + fillSpans (pDraw, pGC, pixel, &spanRec, spanData); +} + +static void +miLineProjectingCap (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, + SpanDataPtr spanData, LineFacePtr face, Bool isLeft, + double xorg, double yorg, Bool isInt) +{ + int xorgi = 0, yorgi = 0; + int lw; + PolyEdgeRec lefts[2], rights[2]; + int lefty, righty, topy, bottomy; + PolyEdgePtr left, right; + PolyEdgePtr top, bottom; + double xa,ya; + double k; + double xap, yap; + int dx, dy; + double projectXoff, projectYoff; + double maxy; + int finaly; + + if (isInt) + { + xorgi = face->x; + yorgi = face->y; + } + lw = pGC->lineWidth; + dx = face->dx; + dy = face->dy; + k = face->k; + if (dy == 0) + { + lefts[0].height = lw; + lefts[0].x = xorgi; + if (isLeft) + lefts[0].x -= (lw >> 1); + lefts[0].stepx = 0; + lefts[0].signdx = 1; + lefts[0].e = -lw; + lefts[0].dx = 0; + lefts[0].dy = lw; + rights[0].height = lw; + rights[0].x = xorgi; + if (!isLeft) + rights[0].x += ((lw + 1) >> 1); + rights[0].stepx = 0; + rights[0].signdx = 1; + rights[0].e = -lw; + rights[0].dx = 0; + rights[0].dy = lw; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw, + lefts, rights, 1, 1); + } + else if (dx == 0) + { + if (dy < 0) { + dy = -dy; + isLeft = !isLeft; + } + topy = yorgi; + bottomy = yorgi + dy; + if (isLeft) + topy -= (lw >> 1); + else + bottomy += (lw >> 1); + lefts[0].height = bottomy - topy; + lefts[0].x = xorgi - (lw >> 1); + lefts[0].stepx = 0; + lefts[0].signdx = 1; + lefts[0].e = -dy; + lefts[0].dx = dx; + lefts[0].dy = dy; + + rights[0].height = bottomy - topy; + rights[0].x = lefts[0].x + (lw-1); + rights[0].stepx = 0; + rights[0].signdx = 1; + rights[0].e = -dy; + rights[0].dx = dx; + rights[0].dy = dy; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1); + } + else + { + xa = face->xa; + ya = face->ya; + projectXoff = -ya; + projectYoff = xa; + if (dx < 0) + { + right = &rights[1]; + left = &lefts[0]; + top = &rights[0]; + bottom = &lefts[1]; + } + else + { + right = &rights[0]; + left = &lefts[1]; + top = &lefts[0]; + bottom = &rights[1]; + } + if (isLeft) + { + righty = miPolyBuildEdge (xa, ya, + k, dx, dy, xorgi, yorgi, 0, right); + + xa = -xa; + ya = -ya; + k = -k; + lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, + k, dx, dy, xorgi, yorgi, 1, left); + if (dx > 0) + { + ya = -ya; + xa = -xa; + } + xap = xa - projectXoff; + yap = ya - projectYoff; + topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, + -dy, dx, xorgi, yorgi, dx > 0, top); + bottomy = miPolyBuildEdge (xa, ya, + 0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom); + maxy = -ya; + } + else + { + righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, + k, dx, dy, xorgi, yorgi, 0, right); + + xa = -xa; + ya = -ya; + k = -k; + lefty = miPolyBuildEdge (xa, ya, + k, dx, dy, xorgi, yorgi, 1, left); + if (dx > 0) + { + ya = -ya; + xa = -xa; + } + xap = xa - projectXoff; + yap = ya - projectYoff; + topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top); + bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, + -dy, dx, xorgi, xorgi, dx < 0, bottom); + maxy = -ya + projectYoff; + } + finaly = ICEIL(maxy) + yorgi; + if (dx < 0) + { + left->height = bottomy - lefty; + right->height = finaly - righty; + top->height = righty - topy; + } + else + { + right->height = bottomy - righty; + left->height = finaly - lefty; + top->height = lefty - topy; + } + bottom->height = finaly - bottomy; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, + bottom->height + bottomy - topy, lefts, rights, 2, 2); + } +} + +static void +miWideSegment ( + DrawablePtr pDrawable, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + int x1, + int y1, + int x2, + int y2, + Bool projectLeft, + Bool projectRight, + LineFacePtr leftFace, + LineFacePtr rightFace) +{ + double l, L, r; + double xa, ya; + double projectXoff = 0.0, projectYoff = 0.0; + double k; + double maxy; + int x, y; + int dx, dy; + int finaly; + PolyEdgePtr left, right; + PolyEdgePtr top, bottom; + int lefty, righty, topy, bottomy; + int signdx; + PolyEdgeRec lefts[2], rights[2]; + LineFacePtr tface; + int lw = pGC->lineWidth; + + /* draw top-to-bottom always */ + if (y2 < y1 || (y2 == y1 && x2 < x1)) + { + x = x1; + x1 = x2; + x2 = x; + + y = y1; + y1 = y2; + y2 = y; + + x = projectLeft; + projectLeft = projectRight; + projectRight = x; + + tface = leftFace; + leftFace = rightFace; + rightFace = tface; + } + + dy = y2 - y1; + signdx = 1; + dx = x2 - x1; + if (dx < 0) + signdx = -1; + + leftFace->x = x1; + leftFace->y = y1; + leftFace->dx = dx; + leftFace->dy = dy; + + rightFace->x = x2; + rightFace->y = y2; + rightFace->dx = -dx; + rightFace->dy = -dy; + + if (dy == 0) + { + rightFace->xa = 0; + rightFace->ya = (double) lw / 2.0; + rightFace->k = -(double) (lw * dx) / 2.0; + leftFace->xa = 0; + leftFace->ya = -rightFace->ya; + leftFace->k = rightFace->k; + x = x1; + if (projectLeft) + x -= (lw >> 1); + y = y1 - (lw >> 1); + dx = x2 - x; + if (projectRight) + dx += ((lw + 1) >> 1); + dy = lw; + miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, + x, y, dx, dy); + } + else if (dx == 0) + { + leftFace->xa = (double) lw / 2.0; + leftFace->ya = 0; + leftFace->k = (double) (lw * dy) / 2.0; + rightFace->xa = -leftFace->xa; + rightFace->ya = 0; + rightFace->k = leftFace->k; + y = y1; + if (projectLeft) + y -= lw >> 1; + x = x1 - (lw >> 1); + dy = y2 - y; + if (projectRight) + dy += ((lw + 1) >> 1); + dx = lw; + miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, + x, y, dx, dy); + } + else + { + l = ((double) lw) / 2.0; + L = hypot ((double) dx, (double) dy); + + if (dx < 0) + { + right = &rights[1]; + left = &lefts[0]; + top = &rights[0]; + bottom = &lefts[1]; + } + else + { + right = &rights[0]; + left = &lefts[1]; + top = &lefts[0]; + bottom = &rights[1]; + } + r = l / L; + + /* coord of upper bound at integral y */ + ya = -r * dx; + xa = r * dy; + + if (projectLeft | projectRight) + { + projectXoff = -ya; + projectYoff = xa; + } + + /* xa * dy - ya * dx */ + k = l * L; + + leftFace->xa = xa; + leftFace->ya = ya; + leftFace->k = k; + rightFace->xa = -xa; + rightFace->ya = -ya; + rightFace->k = k; + + if (projectLeft) + righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, + k, dx, dy, x1, y1, 0, right); + else + righty = miPolyBuildEdge (xa, ya, + k, dx, dy, x1, y1, 0, right); + + /* coord of lower bound at integral y */ + ya = -ya; + xa = -xa; + + /* xa * dy - ya * dx */ + k = - k; + + if (projectLeft) + lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, + k, dx, dy, x1, y1, 1, left); + else + lefty = miPolyBuildEdge (xa, ya, + k, dx, dy, x1, y1, 1, left); + + /* coord of top face at integral y */ + + if (signdx > 0) + { + ya = -ya; + xa = -xa; + } + + if (projectLeft) + { + double xap = xa - projectXoff; + double yap = ya - projectYoff; + topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, + -dy, dx, x1, y1, dx > 0, top); + } + else + topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top); + + /* coord of bottom face at integral y */ + + if (projectRight) + { + double xap = xa + projectXoff; + double yap = ya + projectYoff; + bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, + -dy, dx, x2, y2, dx < 0, bottom); + maxy = -ya + projectYoff; + } + else + { + bottomy = miPolyBuildEdge (xa, ya, + 0.0, -dy, dx, x2, y2, dx < 0, bottom); + maxy = -ya; + } + + finaly = ICEIL (maxy) + y2; + + if (dx < 0) + { + left->height = bottomy - lefty; + right->height = finaly - righty; + top->height = righty - topy; + } + else + { + right->height = bottomy - righty; + left->height = finaly - lefty; + top->height = lefty - topy; + } + bottom->height = finaly - bottomy; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, + bottom->height + bottomy - topy, lefts, rights, 2, 2); + } +} + +static SpanDataPtr +miSetupSpanData (GCPtr pGC, SpanDataPtr spanData, int npt) +{ + if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu)) + return (SpanDataPtr) NULL; + if (pGC->lineStyle == LineDoubleDash) + miInitSpanGroup (&spanData->bgGroup); + miInitSpanGroup (&spanData->fgGroup); + return spanData; +} + +static void +miCleanupSpanData (DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData) +{ + if (pGC->lineStyle == LineDoubleDash) + { + ChangeGCVal oldPixel, pixel; + pixel.val = pGC->bgPixel; + oldPixel.val = pGC->fgPixel; + if (pixel.val != oldPixel.val) + { + ChangeGC (NullClient, pGC, GCForeground, &pixel); + ValidateGC (pDrawable, pGC); + } + miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup); + miFreeSpanGroup (&spanData->bgGroup); + if (pixel.val != oldPixel.val) + { + ChangeGC (NullClient, pGC, GCForeground, &oldPixel); + ValidateGC (pDrawable, pGC); + } + } + miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup); + miFreeSpanGroup (&spanData->fgGroup); +} + +void +miWideLine (DrawablePtr pDrawable, GCPtr pGC, + int mode, int npt, DDXPointPtr pPts) +{ + int x1, y1, x2, y2; + SpanDataRec spanDataRec; + SpanDataPtr spanData; + long pixel; + Bool projectLeft, projectRight; + LineFaceRec leftFace, rightFace, prevRightFace; + LineFaceRec firstFace; + int first; + Bool somethingDrawn = FALSE; + Bool selfJoin; + + spanData = miSetupSpanData (pGC, &spanDataRec, npt); + pixel = pGC->fgPixel; + x2 = pPts->x; + y2 = pPts->y; + first = TRUE; + selfJoin = FALSE; + if (npt > 1) + { + if (mode == CoordModePrevious) + { + int nptTmp; + DDXPointPtr pPtsTmp; + + x1 = x2; + y1 = y2; + nptTmp = npt; + pPtsTmp = pPts + 1; + while (--nptTmp) + { + x1 += pPtsTmp->x; + y1 += pPtsTmp->y; + ++pPtsTmp; + } + if (x2 == x1 && y2 == y1) + selfJoin = TRUE; + } + else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) + { + selfJoin = TRUE; + } + } + projectLeft = pGC->capStyle == CapProjecting && !selfJoin; + projectRight = FALSE; + while (--npt) + { + x1 = x2; + y1 = y2; + ++pPts; + x2 = pPts->x; + y2 = pPts->y; + if (mode == CoordModePrevious) + { + x2 += x1; + y2 += y1; + } + if (x1 != x2 || y1 != y2) + { + somethingDrawn = TRUE; + if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin) + projectRight = TRUE; + miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2, + projectLeft, projectRight, &leftFace, &rightFace); + if (first) + { + if (selfJoin) + firstFace = leftFace; + else if (pGC->capStyle == CapRound) + { + if (pGC->lineWidth == 1 && !spanData) + miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1); + else + miLineArc (pDrawable, pGC, pixel, spanData, + &leftFace, (LineFacePtr) NULL, + (double)0.0, (double)0.0, + TRUE); + } + } + else + { + miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, + &prevRightFace); + } + prevRightFace = rightFace; + first = FALSE; + projectLeft = FALSE; + } + if (npt == 1 && somethingDrawn) + { + if (selfJoin) + miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, + &rightFace); + else if (pGC->capStyle == CapRound) + { + if (pGC->lineWidth == 1 && !spanData) + miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2); + else + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, &rightFace, + (double)0.0, (double)0.0, + TRUE); + } + } + } + /* handle crock where all points are coincedent */ + if (!somethingDrawn) + { + projectLeft = pGC->capStyle == CapProjecting; + miWideSegment (pDrawable, pGC, pixel, spanData, + x2, y2, x2, y2, projectLeft, projectLeft, + &leftFace, &rightFace); + if (pGC->capStyle == CapRound) + { + miLineArc (pDrawable, pGC, pixel, spanData, + &leftFace, (LineFacePtr) NULL, + (double)0.0, (double)0.0, + TRUE); + rightFace.dx = -1; /* sleezy hack to make it work */ + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, &rightFace, + (double)0.0, (double)0.0, + TRUE); + } + } + if (spanData) + miCleanupSpanData (pDrawable, pGC, spanData); +} + +#define V_TOP 0 +#define V_RIGHT 1 +#define V_BOTTOM 2 +#define V_LEFT 3 + +static void +miWideDashSegment ( + DrawablePtr pDrawable, + GCPtr pGC, + SpanDataPtr spanData, + int *pDashOffset, + int *pDashIndex, + int x1, + int y1, + int x2, + int y2, + Bool projectLeft, + Bool projectRight, + LineFacePtr leftFace, + LineFacePtr rightFace) +{ + int dashIndex, dashRemain; + unsigned char *pDash; + double L, l; + double k; + PolyVertexRec vertices[4]; + PolyVertexRec saveRight, saveBottom; + PolySlopeRec slopes[4]; + PolyEdgeRec left[2], right[2]; + LineFaceRec lcapFace, rcapFace; + int nleft, nright; + int h; + int y; + int dy, dx; + unsigned long pixel; + double LRemain; + double r; + double rdx, rdy; + double dashDx, dashDy; + double saveK = 0.0; + Bool first = TRUE; + double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0; + unsigned long fgPixel, bgPixel; + + dx = x2 - x1; + dy = y2 - y1; + dashIndex = *pDashIndex; + pDash = pGC->dash; + dashRemain = pDash[dashIndex] - *pDashOffset; + fgPixel = pGC->fgPixel; + bgPixel = pGC->bgPixel; + if (pGC->fillStyle == FillOpaqueStippled || + pGC->fillStyle == FillTiled) + { + bgPixel = fgPixel; + } + + l = ((double) pGC->lineWidth) / 2.0; + if (dx == 0) + { + L = dy; + rdx = 0; + rdy = l; + if (dy < 0) + { + L = -dy; + rdy = -l; + } + } + else if (dy == 0) + { + L = dx; + rdx = l; + rdy = 0; + if (dx < 0) + { + L = -dx; + rdx = -l; + } + } + else + { + L = hypot ((double) dx, (double) dy); + r = l / L; + + rdx = r * dx; + rdy = r * dy; + } + k = l * L; + LRemain = L; + /* All position comments are relative to a line with dx and dy > 0, + * but the code does not depend on this */ + /* top */ + slopes[V_TOP].dx = dx; + slopes[V_TOP].dy = dy; + slopes[V_TOP].k = k; + /* right */ + slopes[V_RIGHT].dx = -dy; + slopes[V_RIGHT].dy = dx; + slopes[V_RIGHT].k = 0; + /* bottom */ + slopes[V_BOTTOM].dx = -dx; + slopes[V_BOTTOM].dy = -dy; + slopes[V_BOTTOM].k = k; + /* left */ + slopes[V_LEFT].dx = dy; + slopes[V_LEFT].dy = -dx; + slopes[V_LEFT].k = 0; + + /* preload the start coordinates */ + vertices[V_RIGHT].x = vertices[V_TOP].x = rdy; + vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx; + + vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy; + vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx; + + if (projectLeft) + { + vertices[V_TOP].x -= rdx; + vertices[V_TOP].y -= rdy; + + vertices[V_LEFT].x -= rdx; + vertices[V_LEFT].y -= rdy; + + slopes[V_LEFT].k = rdx * dx + rdy * dy; + } + + lcenterx = x1; + lcentery = y1; + + if (pGC->capStyle == CapRound) + { + lcapFace.dx = dx; + lcapFace.dy = dy; + lcapFace.x = x1; + lcapFace.y = y1; + + rcapFace.dx = -dx; + rcapFace.dy = -dy; + rcapFace.x = x1; + rcapFace.y = y1; + } + while (LRemain > dashRemain) + { + dashDx = (dashRemain * dx) / L; + dashDy = (dashRemain * dy) / L; + + rcenterx = lcenterx + dashDx; + rcentery = lcentery + dashDy; + + vertices[V_RIGHT].x += dashDx; + vertices[V_RIGHT].y += dashDy; + + vertices[V_BOTTOM].x += dashDx; + vertices[V_BOTTOM].y += dashDy; + + slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy; + + if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) + { + if (pGC->lineStyle == LineOnOffDash && + pGC->capStyle == CapProjecting) + { + saveRight = vertices[V_RIGHT]; + saveBottom = vertices[V_BOTTOM]; + saveK = slopes[V_RIGHT].k; + + if (!first) + { + vertices[V_TOP].x -= rdx; + vertices[V_TOP].y -= rdy; + + vertices[V_LEFT].x -= rdx; + vertices[V_LEFT].y -= rdy; + + slopes[V_LEFT].k = vertices[V_LEFT].x * + slopes[V_LEFT].dy - + vertices[V_LEFT].y * + slopes[V_LEFT].dx; + } + + vertices[V_RIGHT].x += rdx; + vertices[V_RIGHT].y += rdy; + + vertices[V_BOTTOM].x += rdx; + vertices[V_BOTTOM].y += rdy; + + slopes[V_RIGHT].k = vertices[V_RIGHT].x * + slopes[V_RIGHT].dy - + vertices[V_RIGHT].y * + slopes[V_RIGHT].dx; + } + y = miPolyBuildPoly (vertices, slopes, 4, x1, y1, + left, right, &nleft, &nright, &h); + pixel = (dashIndex & 1) ? bgPixel : fgPixel; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); + + if (pGC->lineStyle == LineOnOffDash) + { + switch (pGC->capStyle) + { + case CapProjecting: + vertices[V_BOTTOM] = saveBottom; + vertices[V_RIGHT] = saveRight; + slopes[V_RIGHT].k = saveK; + break; + case CapRound: + if (!first) + { + if (dx < 0) + { + lcapFace.xa = -vertices[V_LEFT].x; + lcapFace.ya = -vertices[V_LEFT].y; + lcapFace.k = slopes[V_LEFT].k; + } + else + { + lcapFace.xa = vertices[V_TOP].x; + lcapFace.ya = vertices[V_TOP].y; + lcapFace.k = -slopes[V_LEFT].k; + } + miLineArc (pDrawable, pGC, pixel, spanData, + &lcapFace, (LineFacePtr) NULL, + lcenterx, lcentery, FALSE); + } + if (dx < 0) + { + rcapFace.xa = vertices[V_BOTTOM].x; + rcapFace.ya = vertices[V_BOTTOM].y; + rcapFace.k = slopes[V_RIGHT].k; + } + else + { + rcapFace.xa = -vertices[V_RIGHT].x; + rcapFace.ya = -vertices[V_RIGHT].y; + rcapFace.k = -slopes[V_RIGHT].k; + } + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, &rcapFace, + rcenterx, rcentery, FALSE); + break; + } + } + } + LRemain -= dashRemain; + ++dashIndex; + if (dashIndex == pGC->numInDashList) + dashIndex = 0; + dashRemain = pDash[dashIndex]; + + lcenterx = rcenterx; + lcentery = rcentery; + + vertices[V_TOP] = vertices[V_RIGHT]; + vertices[V_LEFT] = vertices[V_BOTTOM]; + slopes[V_LEFT].k = -slopes[V_RIGHT].k; + first = FALSE; + } + + if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) + { + vertices[V_TOP].x -= dx; + vertices[V_TOP].y -= dy; + + vertices[V_LEFT].x -= dx; + vertices[V_LEFT].y -= dy; + + vertices[V_RIGHT].x = rdy; + vertices[V_RIGHT].y = -rdx; + + vertices[V_BOTTOM].x = -rdy; + vertices[V_BOTTOM].y = rdx; + + + if (projectRight) + { + vertices[V_RIGHT].x += rdx; + vertices[V_RIGHT].y += rdy; + + vertices[V_BOTTOM].x += rdx; + vertices[V_BOTTOM].y += rdy; + slopes[V_RIGHT].k = vertices[V_RIGHT].x * + slopes[V_RIGHT].dy - + vertices[V_RIGHT].y * + slopes[V_RIGHT].dx; + } + else + slopes[V_RIGHT].k = 0; + + if (!first && pGC->lineStyle == LineOnOffDash && + pGC->capStyle == CapProjecting) + { + vertices[V_TOP].x -= rdx; + vertices[V_TOP].y -= rdy; + + vertices[V_LEFT].x -= rdx; + vertices[V_LEFT].y -= rdy; + slopes[V_LEFT].k = vertices[V_LEFT].x * + slopes[V_LEFT].dy - + vertices[V_LEFT].y * + slopes[V_LEFT].dx; + } + else + slopes[V_LEFT].k += dx * dx + dy * dy; + + + y = miPolyBuildPoly (vertices, slopes, 4, x2, y2, + left, right, &nleft, &nright, &h); + + pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); + if (!first && pGC->lineStyle == LineOnOffDash && + pGC->capStyle == CapRound) + { + lcapFace.x = x2; + lcapFace.y = y2; + if (dx < 0) + { + lcapFace.xa = -vertices[V_LEFT].x; + lcapFace.ya = -vertices[V_LEFT].y; + lcapFace.k = slopes[V_LEFT].k; + } + else + { + lcapFace.xa = vertices[V_TOP].x; + lcapFace.ya = vertices[V_TOP].y; + lcapFace.k = -slopes[V_LEFT].k; + } + miLineArc (pDrawable, pGC, pixel, spanData, + &lcapFace, (LineFacePtr) NULL, + rcenterx, rcentery, FALSE); + } + } + dashRemain = ((double) dashRemain) - LRemain; + if (dashRemain == 0) + { + dashIndex++; + if (dashIndex == pGC->numInDashList) + dashIndex = 0; + dashRemain = pDash[dashIndex]; + } + + leftFace->x = x1; + leftFace->y = y1; + leftFace->dx = dx; + leftFace->dy = dy; + leftFace->xa = rdy; + leftFace->ya = -rdx; + leftFace->k = k; + + rightFace->x = x2; + rightFace->y = y2; + rightFace->dx = -dx; + rightFace->dy = -dy; + rightFace->xa = -rdy; + rightFace->ya = rdx; + rightFace->k = k; + + *pDashIndex = dashIndex; + *pDashOffset = pDash[dashIndex] - dashRemain; +} + +void +miWideDash (DrawablePtr pDrawable, GCPtr pGC, + int mode, int npt, DDXPointPtr pPts) +{ + int x1, y1, x2, y2; + unsigned long pixel; + Bool projectLeft, projectRight; + LineFaceRec leftFace, rightFace, prevRightFace; + LineFaceRec firstFace; + int first; + int dashIndex, dashOffset; + int prevDashIndex; + SpanDataRec spanDataRec; + SpanDataPtr spanData; + Bool somethingDrawn = FALSE; + Bool selfJoin; + Bool endIsFg = FALSE, startIsFg = FALSE; + Bool firstIsFg = FALSE, prevIsFg = FALSE; + +#if 0 + /* XXX backward compatibility */ + if (pGC->lineWidth == 0) + { + miZeroDashLine (pDrawable, pGC, mode, npt, pPts); + return; + } +#endif + if (pGC->lineStyle == LineDoubleDash && + (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled)) + { + miWideLine (pDrawable, pGC, mode, npt, pPts); + return; + } + if (npt == 0) + return; + spanData = miSetupSpanData (pGC, &spanDataRec, npt); + x2 = pPts->x; + y2 = pPts->y; + first = TRUE; + selfJoin = FALSE; + if (mode == CoordModePrevious) + { + int nptTmp; + DDXPointPtr pPtsTmp; + + x1 = x2; + y1 = y2; + nptTmp = npt; + pPtsTmp = pPts + 1; + while (--nptTmp) + { + x1 += pPtsTmp->x; + y1 += pPtsTmp->y; + ++pPtsTmp; + } + if (x2 == x1 && y2 == y1) + selfJoin = TRUE; + } + else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) + { + selfJoin = TRUE; + } + projectLeft = pGC->capStyle == CapProjecting && !selfJoin; + projectRight = FALSE; + dashIndex = 0; + dashOffset = 0; + miStepDash ((int)pGC->dashOffset, &dashIndex, + pGC->dash, (int)pGC->numInDashList, &dashOffset); + while (--npt) + { + x1 = x2; + y1 = y2; + ++pPts; + x2 = pPts->x; + y2 = pPts->y; + if (mode == CoordModePrevious) + { + x2 += x1; + y2 += y1; + } + if (x1 != x2 || y1 != y2) + { + somethingDrawn = TRUE; + if (npt == 1 && pGC->capStyle == CapProjecting && + (!selfJoin || !firstIsFg)) + projectRight = TRUE; + prevDashIndex = dashIndex; + miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex, + x1, y1, x2, y2, + projectLeft, projectRight, &leftFace, &rightFace); + startIsFg = !(prevDashIndex & 1); + endIsFg = (dashIndex & 1) ^ (dashOffset != 0); + if (pGC->lineStyle == LineDoubleDash || startIsFg) + { + pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel; + if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg)) + { + if (first && selfJoin) + { + firstFace = leftFace; + firstIsFg = startIsFg; + } + else if (pGC->capStyle == CapRound) + miLineArc (pDrawable, pGC, pixel, spanData, + &leftFace, (LineFacePtr) NULL, + (double)0.0, (double)0.0, TRUE); + } + else + { + miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, + &prevRightFace); + } + } + prevRightFace = rightFace; + prevIsFg = endIsFg; + first = FALSE; + projectLeft = FALSE; + } + if (npt == 1 && somethingDrawn) + { + if (pGC->lineStyle == LineDoubleDash || endIsFg) + { + pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel; + if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg)) + { + miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, + &rightFace); + } + else + { + if (pGC->capStyle == CapRound) + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, &rightFace, + (double)0.0, (double)0.0, TRUE); + } + } + else + { + /* glue a cap to the start of the line if + * we're OnOffDash and ended on odd dash + */ + if (selfJoin && firstIsFg) + { + pixel = pGC->fgPixel; + if (pGC->capStyle == CapProjecting) + miLineProjectingCap (pDrawable, pGC, pixel, spanData, + &firstFace, TRUE, + (double)0.0, (double)0.0, TRUE); + else if (pGC->capStyle == CapRound) + miLineArc (pDrawable, pGC, pixel, spanData, + &firstFace, (LineFacePtr) NULL, + (double)0.0, (double)0.0, TRUE); + } + } + } + } + /* handle crock where all points are coincident */ + if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))) + { + /* not the same as endIsFg computation above */ + pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; + switch (pGC->capStyle) { + case CapRound: + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, (LineFacePtr) NULL, + (double)x2, (double)y2, + FALSE); + break; + case CapProjecting: + x1 = pGC->lineWidth; + miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, + x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1); + break; + } + } + if (spanData) + miCleanupSpanData (pDrawable, pGC, spanData); +} diff --git a/xorg-server/mi/miwideline.h b/xorg-server/mi/miwideline.h index 1665ebfb1..05d026a38 100644 --- a/xorg-server/mi/miwideline.h +++ b/xorg-server/mi/miwideline.h @@ -1,116 +1,120 @@ -/* - -Copyright 1988, 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 */ - -#include "mispans.h" -#include "mifpoly.h" /* for ICEIL */ - -/* - * Polygon edge description for integer wide-line routines - */ - -typedef struct _PolyEdge { - int height; /* number of scanlines to process */ - int x; /* starting x coordinate */ - int stepx; /* fixed integral dx */ - int signdx; /* variable dx sign */ - int e; /* initial error term */ - int dy; - int dx; -} PolyEdgeRec, *PolyEdgePtr; - -#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - miter limit constant */ - -/* - * types for general polygon routines - */ - -typedef struct _PolyVertex { - double x, y; -} PolyVertexRec, *PolyVertexPtr; - -typedef struct _PolySlope { - int dx, dy; - double k; /* x0 * dy - y0 * dx */ -} PolySlopeRec, *PolySlopePtr; - -/* - * Line face description for caps/joins - */ - -typedef struct _LineFace { - double xa, ya; - int dx, dy; - int x, y; - double k; -} LineFaceRec, *LineFacePtr; - -/* - * macros for polygon fillers - */ - -#define MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \ - oldPixel = pGC->fgPixel; \ - if (pixel != oldPixel) { \ - DoChangeGC (pGC, GCForeground, (XID *) &pixel, FALSE); \ - ValidateGC (pDrawable, pGC); \ - } \ -} -#define MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \ - if (pixel != oldPixel) { \ - DoChangeGC (pGC, GCForeground, (XID *) &oldPixel, FALSE); \ - ValidateGC (pDrawable, pGC); \ - } \ -} - -extern _X_EXPORT void miRoundJoinClip( - LineFacePtr /*pLeft*/, - LineFacePtr /*pRight*/, - PolyEdgePtr /*edge1*/, - PolyEdgePtr /*edge2*/, - int * /*y1*/, - int * /*y2*/, - Bool * /*left1*/, - Bool * /*left2*/ -); - -extern _X_EXPORT int miRoundCapClip( - LineFacePtr /*face*/, - Bool /*isInt*/, - PolyEdgePtr /*edge*/, - Bool * /*leftEdge*/ -); - -extern _X_EXPORT int miPolyBuildEdge(double x0, double y0, double k, int dx, int dy, - int xi, int yi, int left, PolyEdgePtr edge); -extern _X_EXPORT int miPolyBuildPoly(PolyVertexPtr vertices, PolySlopePtr slopes, - int count, int xi, int yi, PolyEdgePtr left, - PolyEdgePtr right, int *pnleft, int *pnright, - int *h); - +/* + +Copyright 1988, 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 */ + +#include "mispans.h" +#include "mifpoly.h" /* for ICEIL */ + +/* + * Polygon edge description for integer wide-line routines + */ + +typedef struct _PolyEdge { + int height; /* number of scanlines to process */ + int x; /* starting x coordinate */ + int stepx; /* fixed integral dx */ + int signdx; /* variable dx sign */ + int e; /* initial error term */ + int dy; + int dx; +} PolyEdgeRec, *PolyEdgePtr; + +#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - miter limit constant */ + +/* + * types for general polygon routines + */ + +typedef struct _PolyVertex { + double x, y; +} PolyVertexRec, *PolyVertexPtr; + +typedef struct _PolySlope { + int dx, dy; + double k; /* x0 * dy - y0 * dx */ +} PolySlopeRec, *PolySlopePtr; + +/* + * Line face description for caps/joins + */ + +typedef struct _LineFace { + double xa, ya; + int dx, dy; + int x, y; + double k; +} LineFaceRec, *LineFacePtr; + +/* + * macros for polygon fillers + */ + +#define MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \ + oldPixel = pGC->fgPixel; \ + if (pixel != oldPixel) { \ + ChangeGCVal gcval; \ + gcval.val = pixel; \ + ChangeGC (NullClient, pGC, GCForeground, &gcval); \ + ValidateGC (pDrawable, pGC); \ + } \ +} +#define MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \ + if (pixel != oldPixel) { \ + ChangeGCVal gcval; \ + gcval.val = oldPixel; \ + ChangeGC (NullClient, pGC, GCForeground, &gcval); \ + ValidateGC (pDrawable, pGC); \ + } \ +} + +extern _X_EXPORT void miRoundJoinClip( + LineFacePtr /*pLeft*/, + LineFacePtr /*pRight*/, + PolyEdgePtr /*edge1*/, + PolyEdgePtr /*edge2*/, + int * /*y1*/, + int * /*y2*/, + Bool * /*left1*/, + Bool * /*left2*/ +); + +extern _X_EXPORT int miRoundCapClip( + LineFacePtr /*face*/, + Bool /*isInt*/, + PolyEdgePtr /*edge*/, + Bool * /*leftEdge*/ +); + +extern _X_EXPORT int miPolyBuildEdge(double x0, double y0, double k, int dx, int dy, + int xi, int yi, int left, PolyEdgePtr edge); +extern _X_EXPORT int miPolyBuildPoly(PolyVertexPtr vertices, PolySlopePtr slopes, + int count, int xi, int yi, PolyEdgePtr left, + PolyEdgePtr right, int *pnleft, int *pnright, + int *h); + diff --git a/xorg-server/mi/miwindow.c b/xorg-server/mi/miwindow.c index c2333938e..479085787 100644 --- a/xorg-server/mi/miwindow.c +++ b/xorg-server/mi/miwindow.c @@ -1,836 +1,836 @@ - -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include "regionstr.h" -#include "region.h" -#include "mi.h" -#include "windowstr.h" -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "mivalidate.h" - -void -miClearToBackground(WindowPtr pWin, - int x, int y, int w, int h, - Bool generateExposures) -{ - BoxRec box; - RegionRec reg; - RegionPtr pBSReg = NullRegion; - ScreenPtr pScreen; - BoxPtr extents; - int x1, y1, x2, y2; - - /* compute everything using ints to avoid overflow */ - - x1 = pWin->drawable.x + x; - y1 = pWin->drawable.y + y; - if (w) - x2 = x1 + (int) w; - else - x2 = x1 + (int) pWin->drawable.width - (int) x; - if (h) - y2 = y1 + h; - else - y2 = y1 + (int) pWin->drawable.height - (int) y; - - extents = &pWin->clipList.extents; - - /* clip the resulting rectangle to the window clipList extents. This - * makes sure that the result will fit in a box, given that the - * screen is < 32768 on a side. - */ - - if (x1 < extents->x1) - x1 = extents->x1; - if (x2 > extents->x2) - x2 = extents->x2; - if (y1 < extents->y1) - y1 = extents->y1; - if (y2 > extents->y2) - y2 = extents->y2; - - if (x2 <= x1 || y2 <= y1) - { - x2 = x1 = 0; - y2 = y1 = 0; - } - - box.x1 = x1; - box.x2 = x2; - box.y1 = y1; - box.y2 = y2; - - pScreen = pWin->drawable.pScreen; - REGION_INIT(pScreen, ®, &box, 1); - - REGION_INTERSECT(pScreen, ®, ®, &pWin->clipList); - if (generateExposures) - (*pScreen->WindowExposures)(pWin, ®, pBSReg); - else if (pWin->backgroundState != None) - miPaintWindow(pWin, ®, PW_BACKGROUND); - REGION_UNINIT(pScreen, ®); - if (pBSReg) - REGION_DESTROY(pScreen, pBSReg); -} - -void -miMarkWindow(WindowPtr pWin) -{ - ValidatePtr val; - - if (pWin->valdata) - return; - val = (ValidatePtr)xnfalloc(sizeof(ValidateRec)); - val->before.oldAbsCorner.x = pWin->drawable.x; - val->before.oldAbsCorner.y = pWin->drawable.y; - val->before.borderVisible = NullRegion; - val->before.resized = FALSE; - pWin->valdata = val; -} - -Bool -miMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst, WindowPtr *ppLayerWin) -{ - BoxPtr box; - WindowPtr pChild, pLast; - Bool anyMarked = FALSE; - MarkWindowProcPtr MarkWindow = pWin->drawable.pScreen->MarkWindow; - ScreenPtr pScreen; - - pScreen = pWin->drawable.pScreen; - - /* single layered systems are easy */ - if (ppLayerWin) *ppLayerWin = pWin; - - if (pWin == pFirst) - { - /* Blindly mark pWin and all of its inferiors. This is a slight - * overkill if there are mapped windows that outside pWin's border, - * but it's better than wasting time on RectIn checks. - */ - pChild = pWin; - while (1) - { - if (pChild->viewable) - { - if (REGION_BROKEN (pScreen, &pChild->winSize)) - SetWinSize (pChild); - if (REGION_BROKEN (pScreen, &pChild->borderSize)) - SetBorderSize (pChild); - (* MarkWindow)(pChild); - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } - anyMarked = TRUE; - pFirst = pFirst->nextSib; - } - if ( (pChild = pFirst) ) - { - box = REGION_EXTENTS(pChild->drawable.pScreen, &pWin->borderSize); - pLast = pChild->parent->lastChild; - while (1) - { - if (pChild->viewable) - { - if (REGION_BROKEN (pScreen, &pChild->winSize)) - SetWinSize (pChild); - if (REGION_BROKEN (pScreen, &pChild->borderSize)) - SetBorderSize (pChild); - if (RECT_IN_REGION(pScreen, &pChild->borderSize, box)) - { - (* MarkWindow)(pChild); - anyMarked = TRUE; - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - } - } - while (!pChild->nextSib && (pChild != pLast)) - pChild = pChild->parent; - if (pChild == pLast) - break; - pChild = pChild->nextSib; - } - } - if (anyMarked) - (* MarkWindow)(pWin->parent); - return anyMarked; -} - -/***** - * miHandleValidateExposures(pWin) - * starting at pWin, draw background in any windows that have exposure - * regions, translate the regions, restore any backing store, - * and then send any regions still exposed to the client - *****/ -void -miHandleValidateExposures(WindowPtr pWin) -{ - WindowPtr pChild; - ValidatePtr val; - ScreenPtr pScreen; - WindowExposuresProcPtr WindowExposures; - - pScreen = pWin->drawable.pScreen; - - pChild = pWin; - WindowExposures = pChild->drawable.pScreen->WindowExposures; - while (1) - { - if ( (val = pChild->valdata) ) - { - if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed)) - miPaintWindow(pChild, &val->after.borderExposed, PW_BORDER); - REGION_UNINIT(pScreen, &val->after.borderExposed); - (*WindowExposures)(pChild, &val->after.exposed, NullRegion); - REGION_UNINIT(pScreen, &val->after.exposed); - xfree(val); - pChild->valdata = NULL; - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } -} - -void -miMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pNextSib, VTKind kind) -{ - WindowPtr pParent; - Bool WasViewable = (Bool)(pWin->viewable); - short bw; - RegionPtr oldRegion = NULL; - DDXPointRec oldpt; - Bool anyMarked = FALSE; - ScreenPtr pScreen; - WindowPtr windowToValidate; - WindowPtr pLayerWin; - - /* if this is a root window, can't be moved */ - if (!(pParent = pWin->parent)) - return ; - pScreen = pWin->drawable.pScreen; - bw = wBorderWidth (pWin); - - oldpt.x = pWin->drawable.x; - oldpt.y = pWin->drawable.y; - if (WasViewable) - { - oldRegion = REGION_CREATE(pScreen, NullBox, 1); - REGION_COPY(pScreen, oldRegion, &pWin->borderClip); - anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin); - } - pWin->origin.x = x + (int)bw; - pWin->origin.y = y + (int)bw; - x = pWin->drawable.x = pParent->drawable.x + x + (int)bw; - y = pWin->drawable.y = pParent->drawable.y + y + (int)bw; - - SetWinSize (pWin); - SetBorderSize (pWin); - - (*pScreen->PositionWindow)(pWin, x, y); - - windowToValidate = MoveWindowInStack(pWin, pNextSib); - - ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0); - - if (WasViewable) - { - if (pLayerWin == pWin) - anyMarked |= (*pScreen->MarkOverlappedWindows) - (pWin, windowToValidate, NULL); - else - anyMarked |= (*pScreen->MarkOverlappedWindows) - (pWin, pLayerWin, NULL); - - - if (anyMarked) - { - (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, kind); - (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, oldRegion); - REGION_DESTROY(pScreen, oldRegion); - /* XXX need to retile border if ParentRelative origin */ - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, kind); - } - if (pWin->realized) - WindowsRestructured (); -} - - -/* - * pValid is a region of the screen which has been - * successfully copied -- recomputed exposed regions for affected windows - */ - -static int -miRecomputeExposures ( - WindowPtr pWin, - pointer value) /* must conform to VisitWindowProcPtr */ -{ - ScreenPtr pScreen; - RegionPtr pValid = (RegionPtr)value; - - if (pWin->valdata) - { -#ifdef COMPOSITE - /* - * Redirected windows are not affected by parent window - * gravity manipulations, so don't recompute their - * exposed areas here. - */ - if (pWin->redirectDraw != RedirectDrawNone) - return WT_DONTWALKCHILDREN; -#endif - pScreen = pWin->drawable.pScreen; - /* - * compute exposed regions of this window - */ - REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, - &pWin->clipList, pValid); - /* - * compute exposed regions of the border - */ - REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, - &pWin->borderClip, &pWin->winSize); - REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, - &pWin->valdata->after.borderExposed, pValid); - return WT_WALKCHILDREN; - } - return WT_NOMATCH; -} - -void -miSlideAndSizeWindow(WindowPtr pWin, - int x, int y, - unsigned int w, unsigned int h, - WindowPtr pSib) -{ - WindowPtr pParent; - Bool WasViewable = (Bool)(pWin->viewable); - unsigned short width = pWin->drawable.width, - height = pWin->drawable.height; - short oldx = pWin->drawable.x, - oldy = pWin->drawable.y; - int bw = wBorderWidth (pWin); - short dw, dh; - DDXPointRec oldpt; - RegionPtr oldRegion = NULL; - Bool anyMarked = FALSE; - ScreenPtr pScreen; - WindowPtr pFirstChange; - WindowPtr pChild; - RegionPtr gravitate[StaticGravity + 1]; - unsigned g; - int nx, ny; /* destination x,y */ - int newx, newy; /* new inner window position */ - RegionPtr pRegion = NULL; - RegionPtr destClip; /* portions of destination already written */ - RegionPtr oldWinClip = NULL; /* old clip list for window */ - RegionPtr borderVisible = NullRegion; /* visible area of the border */ - Bool shrunk = FALSE; /* shrunk in an inner dimension */ - Bool moved = FALSE; /* window position changed */ - WindowPtr pLayerWin; - - /* if this is a root window, can't be resized */ - if (!(pParent = pWin->parent)) - return ; - - pScreen = pWin->drawable.pScreen; - newx = pParent->drawable.x + x + bw; - newy = pParent->drawable.y + y + bw; - if (WasViewable) - { - anyMarked = FALSE; - /* - * save the visible region of the window - */ - oldRegion = REGION_CREATE(pScreen, NullBox, 1); - REGION_COPY(pScreen, oldRegion, &pWin->winSize); - - /* - * categorize child windows into regions to be moved - */ - for (g = 0; g <= StaticGravity; g++) - gravitate[g] = (RegionPtr) NULL; - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - g = pChild->winGravity; - if (g != UnmapGravity) - { - if (!gravitate[g]) - gravitate[g] = REGION_CREATE(pScreen, NullBox, 1); - REGION_UNION(pScreen, gravitate[g], - gravitate[g], &pChild->borderClip); - } - else - { - UnmapWindow(pChild, TRUE); - anyMarked = TRUE; - } - } - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, - &pLayerWin); - - oldWinClip = NULL; - if (pWin->bitGravity != ForgetGravity) - { - oldWinClip = REGION_CREATE(pScreen, NullBox, 1); - REGION_COPY(pScreen, oldWinClip, &pWin->clipList); - } - /* - * if the window is changing size, borderExposed - * can't be computed correctly without some help. - */ - if (pWin->drawable.height > h || pWin->drawable.width > w) - shrunk = TRUE; - - if (newx != oldx || newy != oldy) - moved = TRUE; - - if ((pWin->drawable.height != h || pWin->drawable.width != w) && - HasBorder (pWin)) - { - borderVisible = REGION_CREATE(pScreen, NullBox, 1); - /* for tiled borders, we punt and draw the whole thing */ - if (pWin->borderIsPixel || !moved) - { - if (shrunk || moved) - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, - &pWin->winSize); - else - REGION_COPY(pScreen, borderVisible, - &pWin->borderClip); - } - } - } - pWin->origin.x = x + bw; - pWin->origin.y = y + bw; - pWin->drawable.height = h; - pWin->drawable.width = w; - - x = pWin->drawable.x = newx; - y = pWin->drawable.y = newy; - - SetWinSize (pWin); - SetBorderSize (pWin); - - dw = (int)w - (int)width; - dh = (int)h - (int)height; - ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh); - - /* let the hardware adjust background and border pixmaps, if any */ - (*pScreen->PositionWindow)(pWin, x, y); - - pFirstChange = MoveWindowInStack(pWin, pSib); - - if (WasViewable) - { - pRegion = REGION_CREATE(pScreen, NullBox, 1); - - if (pLayerWin == pWin) - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, - NULL); - else - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin, - NULL); - - if (pWin->valdata) - { - pWin->valdata->before.resized = TRUE; - pWin->valdata->before.borderVisible = borderVisible; - } - - - if (anyMarked) - (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, VTOther); - /* - * the entire window is trashed unless bitGravity - * recovers portions of it - */ - REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList); - } - - GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny); - - if (WasViewable) - { - /* avoid the border */ - if (HasBorder (pWin)) - { - int offx, offy, dx, dy; - - /* kruft to avoid double translates for each gravity */ - offx = 0; - offy = 0; - for (g = 0; g <= StaticGravity; g++) - { - if (!gravitate[g]) - continue; - - /* align winSize to gravitate[g]. - * winSize is in new coordinates, - * gravitate[g] is still in old coordinates */ - GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); - - dx = (oldx - nx) - offx; - dy = (oldy - ny) - offy; - if (dx || dy) - { - REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy); - offx += dx; - offy += dy; - } - REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], - &pWin->winSize); - } - /* get winSize back where it belongs */ - if (offx || offy) - REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy); - } - /* - * add screen bits to the appropriate bucket - */ - - if (oldWinClip) - { - /* - * clip to new clipList - */ - REGION_COPY(pScreen, pRegion, oldWinClip); - REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); - REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList); - /* - * don't step on any gravity bits which will be copied after this - * region. Note -- this assumes that the regions will be copied - * in gravity order. - */ - for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) - { - if (gravitate[g]) - REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip, - gravitate[g]); - } - REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny); - g = pWin->bitGravity; - if (!gravitate[g]) - gravitate[g] = oldWinClip; - else - { - REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip); - REGION_DESTROY(pScreen, oldWinClip); - } - } - - /* - * move the bits on the screen - */ - - destClip = NULL; - - for (g = 0; g <= StaticGravity; g++) - { - if (!gravitate[g]) - continue; - - GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); - - oldpt.x = oldx + (x - nx); - oldpt.y = oldy + (y - ny); - - /* Note that gravitate[g] is *translated* by CopyWindow */ - - /* only copy the remaining useful bits */ - - REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], oldRegion); - - /* clip to not overwrite already copied areas */ - - if (destClip) { - REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y); - REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip); - REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y); - } - - /* and move those bits */ - - if (oldpt.x != x || oldpt.y != y -#ifdef COMPOSITE - || pWin->redirectDraw -#endif - ) - { - (*pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, gravitate[g]); - } - - /* remove any overwritten bits from the remaining useful bits */ - - REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]); - - /* - * recompute exposed regions of child windows - */ - - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - if (pChild->winGravity != g) - continue; - REGION_INTERSECT(pScreen, pRegion, - &pChild->borderClip, gravitate[g]); - TraverseTree (pChild, miRecomputeExposures, (pointer)pRegion); - } - - /* - * remove the successfully copied regions of the - * window from its exposed region - */ - - if (g == pWin->bitGravity) - REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, - &pWin->valdata->after.exposed, gravitate[g]); - if (!destClip) - destClip = gravitate[g]; - else - { - REGION_UNION(pScreen, destClip, destClip, gravitate[g]); - REGION_DESTROY(pScreen, gravitate[g]); - } - } - - REGION_DESTROY(pScreen, oldRegion); - REGION_DESTROY(pScreen, pRegion); - if (destClip) - REGION_DESTROY(pScreen, destClip); - if (anyMarked) - (*pScreen->HandleExposures)(pLayerWin->parent); - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, - VTOther); - } - if (pWin->realized) - WindowsRestructured (); -} - -WindowPtr -miGetLayerWindow(WindowPtr pWin) -{ - return pWin->firstChild; -} - -/****** - * - * miSetShape - * The border/window shape has changed. Recompute winSize/borderSize - * and send appropriate exposure events - */ - -void -miSetShape(WindowPtr pWin) -{ - Bool WasViewable = (Bool)(pWin->viewable); - ScreenPtr pScreen = pWin->drawable.pScreen; - Bool anyMarked = FALSE; - WindowPtr pLayerWin; - - if (WasViewable) - { - anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, - &pLayerWin); - if (pWin->valdata) - { - if (HasBorder (pWin)) - { - RegionPtr borderVisible; - - borderVisible = REGION_CREATE(pScreen, NullBox, 1); - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, &pWin->winSize); - pWin->valdata->before.borderVisible = borderVisible; - } - pWin->valdata->before.resized = TRUE; - } - } - - SetWinSize (pWin); - SetBorderSize (pWin); - - ResizeChildrenWinSize(pWin, 0, 0, 0, 0); - - if (WasViewable) - { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, - NULL); - - - if (anyMarked) - (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, VTOther); - } - - if (WasViewable) - { - if (anyMarked) - (*pScreen->HandleExposures)(pLayerWin->parent); - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, VTOther); - } - if (pWin->realized) - WindowsRestructured (); - CheckCursorConfinement(pWin); -} - -/* Keeps the same inside(!) origin */ - -void -miChangeBorderWidth(WindowPtr pWin, unsigned int width) -{ - int oldwidth; - Bool anyMarked = FALSE; - ScreenPtr pScreen; - Bool WasViewable = (Bool)(pWin->viewable); - Bool HadBorder; - WindowPtr pLayerWin; - - oldwidth = wBorderWidth (pWin); - if (oldwidth == width) - return; - HadBorder = HasBorder(pWin); - pScreen = pWin->drawable.pScreen; - if (WasViewable && width < oldwidth) - anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin); - - pWin->borderWidth = width; - SetBorderSize (pWin); - - if (WasViewable) - { - if (width > oldwidth) - { - anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, - &pLayerWin); - /* - * save the old border visible region to correctly compute - * borderExposed. - */ - if (pWin->valdata && HadBorder) - { - RegionPtr borderVisible; - borderVisible = REGION_CREATE(pScreen, NULL, 1); - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, &pWin->winSize); - pWin->valdata->before.borderVisible = borderVisible; - } - } - - if (anyMarked) - { - (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTOther); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, - VTOther); - } - if (pWin->realized) - WindowsRestructured (); -} - -void -miMarkUnrealizedWindow(WindowPtr pChild, WindowPtr pWin, Bool fromConfigure) -{ - if ((pChild != pWin) || fromConfigure) - { - REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList); - if (pChild->drawable.pScreen->ClipNotify) - (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0); - REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip); - } -} - -void -miSegregateChildren(WindowPtr pWin, RegionPtr pReg, int depth) -{ - ScreenPtr pScreen; - WindowPtr pChild; - - pScreen = pWin->drawable.pScreen; - - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - if (pChild->drawable.depth == depth) - REGION_UNION(pScreen, pReg, pReg, &pChild->borderClip); - - if (pChild->firstChild) - miSegregateChildren(pChild, pReg, depth); - } -} + +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <X11/X.h> +#include "regionstr.h" +#include "region.h" +#include "mi.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "mivalidate.h" + +void +miClearToBackground(WindowPtr pWin, + int x, int y, int w, int h, + Bool generateExposures) +{ + BoxRec box; + RegionRec reg; + RegionPtr pBSReg = NullRegion; + ScreenPtr pScreen; + BoxPtr extents; + int x1, y1, x2, y2; + + /* compute everything using ints to avoid overflow */ + + x1 = pWin->drawable.x + x; + y1 = pWin->drawable.y + y; + if (w) + x2 = x1 + (int) w; + else + x2 = x1 + (int) pWin->drawable.width - (int) x; + if (h) + y2 = y1 + h; + else + y2 = y1 + (int) pWin->drawable.height - (int) y; + + extents = &pWin->clipList.extents; + + /* clip the resulting rectangle to the window clipList extents. This + * makes sure that the result will fit in a box, given that the + * screen is < 32768 on a side. + */ + + if (x1 < extents->x1) + x1 = extents->x1; + if (x2 > extents->x2) + x2 = extents->x2; + if (y1 < extents->y1) + y1 = extents->y1; + if (y2 > extents->y2) + y2 = extents->y2; + + if (x2 <= x1 || y2 <= y1) + { + x2 = x1 = 0; + y2 = y1 = 0; + } + + box.x1 = x1; + box.x2 = x2; + box.y1 = y1; + box.y2 = y2; + + pScreen = pWin->drawable.pScreen; + REGION_INIT(pScreen, ®, &box, 1); + + REGION_INTERSECT(pScreen, ®, ®, &pWin->clipList); + if (generateExposures) + (*pScreen->WindowExposures)(pWin, ®, pBSReg); + else if (pWin->backgroundState != None) + miPaintWindow(pWin, ®, PW_BACKGROUND); + REGION_UNINIT(pScreen, ®); + if (pBSReg) + REGION_DESTROY(pScreen, pBSReg); +} + +void +miMarkWindow(WindowPtr pWin) +{ + ValidatePtr val; + + if (pWin->valdata) + return; + val = (ValidatePtr)xnfalloc(sizeof(ValidateRec)); + val->before.oldAbsCorner.x = pWin->drawable.x; + val->before.oldAbsCorner.y = pWin->drawable.y; + val->before.borderVisible = NullRegion; + val->before.resized = FALSE; + pWin->valdata = val; +} + +Bool +miMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst, WindowPtr *ppLayerWin) +{ + BoxPtr box; + WindowPtr pChild, pLast; + Bool anyMarked = FALSE; + MarkWindowProcPtr MarkWindow = pWin->drawable.pScreen->MarkWindow; + ScreenPtr pScreen; + + pScreen = pWin->drawable.pScreen; + + /* single layered systems are easy */ + if (ppLayerWin) *ppLayerWin = pWin; + + if (pWin == pFirst) + { + /* Blindly mark pWin and all of its inferiors. This is a slight + * overkill if there are mapped windows that outside pWin's border, + * but it's better than wasting time on RectIn checks. + */ + pChild = pWin; + while (1) + { + if (pChild->viewable) + { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + (* MarkWindow)(pChild); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } + anyMarked = TRUE; + pFirst = pFirst->nextSib; + } + if ( (pChild = pFirst) ) + { + box = REGION_EXTENTS(pChild->drawable.pScreen, &pWin->borderSize); + pLast = pChild->parent->lastChild; + while (1) + { + if (pChild->viewable) + { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + if (RECT_IN_REGION(pScreen, &pChild->borderSize, box)) + { + (* MarkWindow)(pChild); + anyMarked = TRUE; + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + } + while (!pChild->nextSib && (pChild != pLast)) + pChild = pChild->parent; + if (pChild == pLast) + break; + pChild = pChild->nextSib; + } + } + if (anyMarked) + (* MarkWindow)(pWin->parent); + return anyMarked; +} + +/***** + * miHandleValidateExposures(pWin) + * starting at pWin, draw background in any windows that have exposure + * regions, translate the regions, restore any backing store, + * and then send any regions still exposed to the client + *****/ +void +miHandleValidateExposures(WindowPtr pWin) +{ + WindowPtr pChild; + ValidatePtr val; + ScreenPtr pScreen; + WindowExposuresProcPtr WindowExposures; + + pScreen = pWin->drawable.pScreen; + + pChild = pWin; + WindowExposures = pChild->drawable.pScreen->WindowExposures; + while (1) + { + if ( (val = pChild->valdata) ) + { + if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed)) + miPaintWindow(pChild, &val->after.borderExposed, PW_BORDER); + REGION_UNINIT(pScreen, &val->after.borderExposed); + (*WindowExposures)(pChild, &val->after.exposed, NullRegion); + REGION_UNINIT(pScreen, &val->after.exposed); + free(val); + pChild->valdata = NULL; + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + +void +miMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pNextSib, VTKind kind) +{ + WindowPtr pParent; + Bool WasViewable = (Bool)(pWin->viewable); + short bw; + RegionPtr oldRegion = NULL; + DDXPointRec oldpt; + Bool anyMarked = FALSE; + ScreenPtr pScreen; + WindowPtr windowToValidate; + WindowPtr pLayerWin; + + /* if this is a root window, can't be moved */ + if (!(pParent = pWin->parent)) + return ; + pScreen = pWin->drawable.pScreen; + bw = wBorderWidth (pWin); + + oldpt.x = pWin->drawable.x; + oldpt.y = pWin->drawable.y; + if (WasViewable) + { + oldRegion = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion, &pWin->borderClip); + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin); + } + pWin->origin.x = x + (int)bw; + pWin->origin.y = y + (int)bw; + x = pWin->drawable.x = pParent->drawable.x + x + (int)bw; + y = pWin->drawable.y = pParent->drawable.y + y + (int)bw; + + SetWinSize (pWin); + SetBorderSize (pWin); + + (*pScreen->PositionWindow)(pWin, x, y); + + windowToValidate = MoveWindowInStack(pWin, pNextSib); + + ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0); + + if (WasViewable) + { + if (pLayerWin == pWin) + anyMarked |= (*pScreen->MarkOverlappedWindows) + (pWin, windowToValidate, NULL); + else + anyMarked |= (*pScreen->MarkOverlappedWindows) + (pWin, pLayerWin, NULL); + + + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, kind); + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, oldRegion); + REGION_DESTROY(pScreen, oldRegion); + /* XXX need to retile border if ParentRelative origin */ + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, kind); + } + if (pWin->realized) + WindowsRestructured (); +} + + +/* + * pValid is a region of the screen which has been + * successfully copied -- recomputed exposed regions for affected windows + */ + +static int +miRecomputeExposures ( + WindowPtr pWin, + pointer value) /* must conform to VisitWindowProcPtr */ +{ + ScreenPtr pScreen; + RegionPtr pValid = (RegionPtr)value; + + if (pWin->valdata) + { +#ifdef COMPOSITE + /* + * Redirected windows are not affected by parent window + * gravity manipulations, so don't recompute their + * exposed areas here. + */ + if (pWin->redirectDraw != RedirectDrawNone) + return WT_DONTWALKCHILDREN; +#endif + pScreen = pWin->drawable.pScreen; + /* + * compute exposed regions of this window + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->clipList, pValid); + /* + * compute exposed regions of the border + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->borderClip, &pWin->winSize); + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->valdata->after.borderExposed, pValid); + return WT_WALKCHILDREN; + } + return WT_NOMATCH; +} + +void +miSlideAndSizeWindow(WindowPtr pWin, + int x, int y, + unsigned int w, unsigned int h, + WindowPtr pSib) +{ + WindowPtr pParent; + Bool WasViewable = (Bool)(pWin->viewable); + unsigned short width = pWin->drawable.width, + height = pWin->drawable.height; + short oldx = pWin->drawable.x, + oldy = pWin->drawable.y; + int bw = wBorderWidth (pWin); + short dw, dh; + DDXPointRec oldpt; + RegionPtr oldRegion = NULL; + Bool anyMarked = FALSE; + ScreenPtr pScreen; + WindowPtr pFirstChange; + WindowPtr pChild; + RegionPtr gravitate[StaticGravity + 1]; + unsigned g; + int nx, ny; /* destination x,y */ + int newx, newy; /* new inner window position */ + RegionPtr pRegion = NULL; + RegionPtr destClip; /* portions of destination already written */ + RegionPtr oldWinClip = NULL; /* old clip list for window */ + RegionPtr borderVisible = NullRegion; /* visible area of the border */ + Bool shrunk = FALSE; /* shrunk in an inner dimension */ + Bool moved = FALSE; /* window position changed */ + WindowPtr pLayerWin; + + /* if this is a root window, can't be resized */ + if (!(pParent = pWin->parent)) + return ; + + pScreen = pWin->drawable.pScreen; + newx = pParent->drawable.x + x + bw; + newy = pParent->drawable.y + y + bw; + if (WasViewable) + { + anyMarked = FALSE; + /* + * save the visible region of the window + */ + oldRegion = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion, &pWin->winSize); + + /* + * categorize child windows into regions to be moved + */ + for (g = 0; g <= StaticGravity; g++) + gravitate[g] = (RegionPtr) NULL; + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + g = pChild->winGravity; + if (g != UnmapGravity) + { + if (!gravitate[g]) + gravitate[g] = REGION_CREATE(pScreen, NullBox, 1); + REGION_UNION(pScreen, gravitate[g], + gravitate[g], &pChild->borderClip); + } + else + { + UnmapWindow(pChild, TRUE); + anyMarked = TRUE; + } + } + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); + + oldWinClip = NULL; + if (pWin->bitGravity != ForgetGravity) + { + oldWinClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldWinClip, &pWin->clipList); + } + /* + * if the window is changing size, borderExposed + * can't be computed correctly without some help. + */ + if (pWin->drawable.height > h || pWin->drawable.width > w) + shrunk = TRUE; + + if (newx != oldx || newy != oldy) + moved = TRUE; + + if ((pWin->drawable.height != h || pWin->drawable.width != w) && + HasBorder (pWin)) + { + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + /* for tiled borders, we punt and draw the whole thing */ + if (pWin->borderIsPixel || !moved) + { + if (shrunk || moved) + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, + &pWin->winSize); + else + REGION_COPY(pScreen, borderVisible, + &pWin->borderClip); + } + } + } + pWin->origin.x = x + bw; + pWin->origin.y = y + bw; + pWin->drawable.height = h; + pWin->drawable.width = w; + + x = pWin->drawable.x = newx; + y = pWin->drawable.y = newy; + + SetWinSize (pWin); + SetBorderSize (pWin); + + dw = (int)w - (int)width; + dh = (int)h - (int)height; + ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh); + + /* let the hardware adjust background and border pixmaps, if any */ + (*pScreen->PositionWindow)(pWin, x, y); + + pFirstChange = MoveWindowInStack(pWin, pSib); + + if (WasViewable) + { + pRegion = REGION_CREATE(pScreen, NullBox, 1); + + if (pLayerWin == pWin) + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, + NULL); + else + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin, + NULL); + + if (pWin->valdata) + { + pWin->valdata->before.resized = TRUE; + pWin->valdata->before.borderVisible = borderVisible; + } + + + if (anyMarked) + (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, VTOther); + /* + * the entire window is trashed unless bitGravity + * recovers portions of it + */ + REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList); + } + + GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny); + + if (WasViewable) + { + /* avoid the border */ + if (HasBorder (pWin)) + { + int offx, offy, dx, dy; + + /* kruft to avoid double translates for each gravity */ + offx = 0; + offy = 0; + for (g = 0; g <= StaticGravity; g++) + { + if (!gravitate[g]) + continue; + + /* align winSize to gravitate[g]. + * winSize is in new coordinates, + * gravitate[g] is still in old coordinates */ + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + dx = (oldx - nx) - offx; + dy = (oldy - ny) - offy; + if (dx || dy) + { + REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy); + offx += dx; + offy += dy; + } + REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], + &pWin->winSize); + } + /* get winSize back where it belongs */ + if (offx || offy) + REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy); + } + /* + * add screen bits to the appropriate bucket + */ + + if (oldWinClip) + { + /* + * clip to new clipList + */ + REGION_COPY(pScreen, pRegion, oldWinClip); + REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); + REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList); + /* + * don't step on any gravity bits which will be copied after this + * region. Note -- this assumes that the regions will be copied + * in gravity order. + */ + for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) + { + if (gravitate[g]) + REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip, + gravitate[g]); + } + REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate[g]) + gravitate[g] = oldWinClip; + else + { + REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip); + REGION_DESTROY(pScreen, oldWinClip); + } + } + + /* + * move the bits on the screen + */ + + destClip = NULL; + + for (g = 0; g <= StaticGravity; g++) + { + if (!gravitate[g]) + continue; + + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + oldpt.x = oldx + (x - nx); + oldpt.y = oldy + (y - ny); + + /* Note that gravitate[g] is *translated* by CopyWindow */ + + /* only copy the remaining useful bits */ + + REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], oldRegion); + + /* clip to not overwrite already copied areas */ + + if (destClip) { + REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y); + REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip); + REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y); + } + + /* and move those bits */ + + if (oldpt.x != x || oldpt.y != y +#ifdef COMPOSITE + || pWin->redirectDraw +#endif + ) + { + (*pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, gravitate[g]); + } + + /* remove any overwritten bits from the remaining useful bits */ + + REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]); + + /* + * recompute exposed regions of child windows + */ + + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + if (pChild->winGravity != g) + continue; + REGION_INTERSECT(pScreen, pRegion, + &pChild->borderClip, gravitate[g]); + TraverseTree (pChild, miRecomputeExposures, (pointer)pRegion); + } + + /* + * remove the successfully copied regions of the + * window from its exposed region + */ + + if (g == pWin->bitGravity) + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->valdata->after.exposed, gravitate[g]); + if (!destClip) + destClip = gravitate[g]; + else + { + REGION_UNION(pScreen, destClip, destClip, gravitate[g]); + REGION_DESTROY(pScreen, gravitate[g]); + } + } + + REGION_DESTROY(pScreen, oldRegion); + REGION_DESTROY(pScreen, pRegion); + if (destClip) + REGION_DESTROY(pScreen, destClip); + if (anyMarked) + (*pScreen->HandleExposures)(pLayerWin->parent); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, + VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +WindowPtr +miGetLayerWindow(WindowPtr pWin) +{ + return pWin->firstChild; +} + +/****** + * + * miSetShape + * The border/window shape has changed. Recompute winSize/borderSize + * and send appropriate exposure events + */ + +void +miSetShape(WindowPtr pWin) +{ + Bool WasViewable = (Bool)(pWin->viewable); + ScreenPtr pScreen = pWin->drawable.pScreen; + Bool anyMarked = FALSE; + WindowPtr pLayerWin; + + if (WasViewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + pWin->valdata->before.resized = TRUE; + } + } + + SetWinSize (pWin); + SetBorderSize (pWin); + + ResizeChildrenWinSize(pWin, 0, 0, 0, 0); + + if (WasViewable) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, + NULL); + + + if (anyMarked) + (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, VTOther); + } + + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pLayerWin->parent); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + CheckCursorConfinement(pWin); +} + +/* Keeps the same inside(!) origin */ + +void +miChangeBorderWidth(WindowPtr pWin, unsigned int width) +{ + int oldwidth; + Bool anyMarked = FALSE; + ScreenPtr pScreen; + Bool WasViewable = (Bool)(pWin->viewable); + Bool HadBorder; + WindowPtr pLayerWin; + + oldwidth = wBorderWidth (pWin); + if (oldwidth == width) + return; + HadBorder = HasBorder(pWin); + pScreen = pWin->drawable.pScreen; + if (WasViewable && width < oldwidth) + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin); + + pWin->borderWidth = width; + SetBorderSize (pWin); + + if (WasViewable) + { + if (width > oldwidth) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); + /* + * save the old border visible region to correctly compute + * borderExposed. + */ + if (pWin->valdata && HadBorder) + { + RegionPtr borderVisible; + borderVisible = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + } + + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTOther); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, + VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +void +miMarkUnrealizedWindow(WindowPtr pChild, WindowPtr pWin, Bool fromConfigure) +{ + if ((pChild != pWin) || fromConfigure) + { + REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList); + if (pChild->drawable.pScreen->ClipNotify) + (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0); + REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip); + } +} + +void +miSegregateChildren(WindowPtr pWin, RegionPtr pReg, int depth) +{ + ScreenPtr pScreen; + WindowPtr pChild; + + pScreen = pWin->drawable.pScreen; + + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + if (pChild->drawable.depth == depth) + REGION_UNION(pScreen, pReg, pReg, &pChild->borderClip); + + if (pChild->firstChild) + miSegregateChildren(pChild, pReg, depth); + } +} diff --git a/xorg-server/mi/mizerarc.c b/xorg-server/mi/mizerarc.c index ad84c0123..713d0bd04 100644 --- a/xorg-server/mi/mizerarc.c +++ b/xorg-server/mi/mizerarc.c @@ -1,844 +1,848 @@ -/************************************************************ - -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. - -Author: Bob Scheifler, MIT X Consortium - -********************************************************/ - - -/* Derived from: - * "Algorithm for drawing ellipses or hyperbolae with a digital plotter" - * by M. L. V. Pitteway - * The Computer Journal, November 1967, Volume 10, Number 3, pp. 282-289 - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <math.h> -#include <X11/X.h> -#include <X11/Xprotostr.h> -#include "regionstr.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "mi.h" -#include "mizerarc.h" - -#define FULLCIRCLE (360 * 64) -#define OCTANT (45 * 64) -#define QUADRANT (90 * 64) -#define HALFCIRCLE (180 * 64) -#define QUADRANT3 (270 * 64) - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#define Dsin(d) ((d) == 0 ? 0.0 : ((d) == QUADRANT ? 1.0 : \ - ((d) == HALFCIRCLE ? 0.0 : \ - ((d) == QUADRANT3 ? -1.0 : sin((double)d*(M_PI/11520.0)))))) - -#define Dcos(d) ((d) == 0 ? 1.0 : ((d) == QUADRANT ? 0.0 : \ - ((d) == HALFCIRCLE ? -1.0 : \ - ((d) == QUADRANT3 ? 0.0 : cos((double)d*(M_PI/11520.0)))))) - -#define EPSILON45 64 - -typedef struct { - int skipStart; - int haveStart; - DDXPointRec startPt; - int haveLast; - int skipLast; - DDXPointRec endPt; - int dashIndex; - int dashOffset; - int dashIndexInit; - int dashOffsetInit; -} DashInfo; - -static miZeroArcPtRec oob = {65536, 65536, 0}; - -/* - * (x - l)^2 / (W/2)^2 + (y + H/2)^2 / (H/2)^2 = 1 - * - * where l is either 0 or .5 - * - * alpha = 4(W^2) - * beta = 4(H^2) - * gamma = 0 - * u = 2(W^2)H - * v = 4(H^2)l - * k = -4(H^2)(l^2) - * - */ - -Bool -miZeroArcSetup(xArc *arc, miZeroArcRec *info, Bool ok360) -{ - int l; - int angle1, angle2; - int startseg, endseg; - int startAngle, endAngle; - int i, overlap; - miZeroArcPtRec start, end; - - l = arc->width & 1; - if (arc->width == arc->height) - { - info->alpha = 4; - info->beta = 4; - info->k1 = -8; - info->k3 = -16; - info->b = 12; - info->a = (arc->width << 2) - 12; - info->d = 17 - (arc->width << 1); - if (l) - { - info->b -= 4; - info->a += 4; - info->d -= 7; - } - } - else if (!arc->width || !arc->height) - { - info->alpha = 0; - info->beta = 0; - info->k1 = 0; - info->k3 = 0; - info->a = -(int)arc->height; - info->b = 0; - info->d = -1; - } - else - { - /* initial conditions */ - info->alpha = (arc->width * arc->width) << 2; - info->beta = (arc->height * arc->height) << 2; - info->k1 = info->beta << 1; - info->k3 = info->k1 + (info->alpha << 1); - info->b = l ? 0 : -info->beta; - info->a = info->alpha * arc->height; - info->d = info->b - (info->a >> 1) - (info->alpha >> 2); - if (l) - info->d -= info->beta >> 2; - info->a -= info->b; - /* take first step, d < 0 always */ - info->b -= info->k1; - info->a += info->k1; - info->d += info->b; - /* octant change, b < 0 always */ - info->k1 = -info->k1; - info->k3 = -info->k3; - info->b = -info->b; - info->d = info->b - info->a - info->d; - info->a = info->a - (info->b << 1); - } - info->dx = 1; - info->dy = 0; - info->w = (arc->width + 1) >> 1; - info->h = arc->height >> 1; - info->xorg = arc->x + (arc->width >> 1); - info->yorg = arc->y; - info->xorgo = info->xorg + l; - info->yorgo = info->yorg + arc->height; - if (!arc->width) - { - if (!arc->height) - { - info->x = 0; - info->y = 0; - info->initialMask = 0; - info->startAngle = 0; - info->endAngle = 0; - info->start = oob; - info->end = oob; - return FALSE; - } - info->x = 0; - info->y = 1; - } - else - { - info->x = 1; - info->y = 0; - } - angle1 = arc->angle1; - angle2 = arc->angle2; - if ((angle1 == 0) && (angle2 >= FULLCIRCLE)) - { - startAngle = 0; - endAngle = 0; - } - else - { - if (angle2 > FULLCIRCLE) - angle2 = FULLCIRCLE; - else if (angle2 < -FULLCIRCLE) - angle2 = -FULLCIRCLE; - if (angle2 < 0) - { - startAngle = angle1 + angle2; - endAngle = angle1; - } - else - { - startAngle = angle1; - endAngle = angle1 + angle2; - } - if (startAngle < 0) - startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; - if (startAngle >= FULLCIRCLE) - startAngle = startAngle % FULLCIRCLE; - if (endAngle < 0) - endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE; - if (endAngle >= FULLCIRCLE) - endAngle = endAngle % FULLCIRCLE; - } - info->startAngle = startAngle; - info->endAngle = endAngle; - if (ok360 && (startAngle == endAngle) && arc->angle2 && - arc->width && arc->height) - { - info->initialMask = 0xf; - info->start = oob; - info->end = oob; - return TRUE; - } - startseg = startAngle / OCTANT; - if (!arc->height || (((startseg + 1) & 2) && arc->width)) - { - start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0); - if (start.x < 0) - start.x = -start.x; - start.y = -1; - } - else - { - start.y = Dsin(startAngle) * (arc->height / 2.0); - if (start.y < 0) - start.y = -start.y; - start.y = info->h - start.y; - start.x = 65536; - } - endseg = endAngle / OCTANT; - if (!arc->height || (((endseg + 1) & 2) && arc->width)) - { - end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0); - if (end.x < 0) - end.x = -end.x; - end.y = -1; - } - else - { - end.y = Dsin(endAngle) * (arc->height / 2.0); - if (end.y < 0) - end.y = -end.y; - end.y = info->h - end.y; - end.x = 65536; - } - info->firstx = start.x; - info->firsty = start.y; - info->initialMask = 0; - overlap = arc->angle2 && (endAngle <= startAngle); - for (i = 0; i < 4; i++) - { - if (overlap ? - ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) : - ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle))) - info->initialMask |= (1 << i); - } - start.mask = info->initialMask; - end.mask = info->initialMask; - startseg >>= 1; - endseg >>= 1; - overlap = overlap && (endseg == startseg); - if (start.x != end.x || start.y != end.y || !overlap) - { - if (startseg & 1) - { - if (!overlap) - info->initialMask &= ~(1 << startseg); - if (start.x > end.x || start.y > end.y) - end.mask &= ~(1 << startseg); - } - else - { - start.mask &= ~(1 << startseg); - if (((start.x < end.x || start.y < end.y) || - (start.x == end.x && start.y == end.y && (endseg & 1))) && - !overlap) - end.mask &= ~(1 << startseg); - } - if (endseg & 1) - { - end.mask &= ~(1 << endseg); - if (((start.x > end.x || start.y > end.y) || - (start.x == end.x && start.y == end.y && !(startseg & 1))) && - !overlap) - start.mask &= ~(1 << endseg); - } - else - { - if (!overlap) - info->initialMask &= ~(1 << endseg); - if (start.x < end.x || start.y < end.y) - start.mask &= ~(1 << endseg); - } - } - /* take care of case when start and stop are both near 45 */ - /* handle here rather than adding extra code to pixelization loops */ - if (startAngle && - ((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0))) - { - i = (startAngle + OCTANT) % OCTANT; - if (i < EPSILON45 || i > OCTANT - EPSILON45) - { - i = (endAngle + OCTANT) % OCTANT; - if (i < EPSILON45 || i > OCTANT - EPSILON45) - { - if (start.y < 0) - { - i = Dsin(startAngle) * (arc->height / 2.0); - if (i < 0) - i = -i; - if (info->h - i == end.y) - start.mask = end.mask; - } - else - { - i = Dsin(endAngle) * (arc->height / 2.0); - if (i < 0) - i = -i; - if (info->h - i == start.y) - end.mask = start.mask; - } - } - } - } - if (startseg & 1) - { - info->start = start; - info->end = oob; - } - else - { - info->end = start; - info->start = oob; - } - if (endseg & 1) - { - info->altend = end; - if (info->altend.x < info->end.x || info->altend.y < info->end.y) - { - miZeroArcPtRec tmp; - tmp = info->altend; - info->altend = info->end; - info->end = tmp; - } - info->altstart = oob; - } - else - { - info->altstart = end; - if (info->altstart.x < info->start.x || - info->altstart.y < info->start.y) - { - miZeroArcPtRec tmp; - tmp = info->altstart; - info->altstart = info->start; - info->start = tmp; - } - info->altend = oob; - } - if (!info->start.x || !info->start.y) - { - info->initialMask = info->start.mask; - info->start = info->altstart; - } - if (!arc->width && (arc->height == 1)) - { - /* kludge! */ - info->initialMask |= info->end.mask; - info->initialMask |= info->initialMask << 1; - info->end.x = 0; - info->end.mask = 0; - } - return FALSE; -} - -#define Pixelate(xval,yval) \ - { \ - pts->x = xval; \ - pts->y = yval; \ - pts++; \ - } - -#define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval); - -static DDXPointPtr -miZeroArcPts(xArc *arc, DDXPointPtr pts) -{ - miZeroArcRec info; - int x, y, a, b, d, mask; - int k1, k3, dx, dy; - Bool do360; - - do360 = miZeroArcSetup(arc, &info, TRUE); - MIARCSETUP(); - mask = info.initialMask; - if (!(arc->width & 1)) - { - DoPix(1, info.xorgo, info.yorg); - DoPix(3, info.xorgo, info.yorgo); - } - if (!info.end.x || !info.end.y) - { - mask = info.end.mask; - info.end = info.altend; - } - if (do360 && (arc->width == arc->height) && !(arc->width & 1)) - { - int yorgh = info.yorg + info.h; - int xorghp = info.xorg + info.h; - int xorghn = info.xorg - info.h; - - while (1) - { - Pixelate(info.xorg + x, info.yorg + y); - Pixelate(info.xorg - x, info.yorg + y); - Pixelate(info.xorg - x, info.yorgo - y); - Pixelate(info.xorg + x, info.yorgo - y); - if (a < 0) - break; - Pixelate(xorghp - y, yorgh - x); - Pixelate(xorghn + y, yorgh - x); - Pixelate(xorghn + y, yorgh + x); - Pixelate(xorghp - y, yorgh + x); - MIARCCIRCLESTEP(;); - } - if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y) - pts -= 4; - x = info.w; - y = info.h; - } - else if (do360) - { - while (y < info.h || x < info.w) - { - MIARCOCTANTSHIFT(;); - Pixelate(info.xorg + x, info.yorg + y); - Pixelate(info.xorgo - x, info.yorg + y); - Pixelate(info.xorgo - x, info.yorgo - y); - Pixelate(info.xorg + x, info.yorgo - y); - MIARCSTEP(;,;); - } - } - else - { - while (y < info.h || x < info.w) - { - MIARCOCTANTSHIFT(;); - if ((x == info.start.x) || (y == info.start.y)) - { - mask = info.start.mask; - info.start = info.altstart; - } - DoPix(0, info.xorg + x, info.yorg + y); - DoPix(1, info.xorgo - x, info.yorg + y); - DoPix(2, info.xorgo - x, info.yorgo - y); - DoPix(3, info.xorg + x, info.yorgo - y); - if ((x == info.end.x) || (y == info.end.y)) - { - mask = info.end.mask; - info.end = info.altend; - } - MIARCSTEP(;,;); - } - } - if ((x == info.start.x) || (y == info.start.y)) - mask = info.start.mask; - DoPix(0, info.xorg + x, info.yorg + y); - DoPix(2, info.xorgo - x, info.yorgo - y); - if (arc->height & 1) - { - DoPix(1, info.xorgo - x, info.yorg + y); - DoPix(3, info.xorg + x, info.yorgo - y); - } - return pts; -} - -#undef DoPix -#define DoPix(idx,xval,yval) \ - if (mask & (1 << idx)) \ - { \ - arcPts[idx]->x = xval; \ - arcPts[idx]->y = yval; \ - arcPts[idx]++; \ - } - -static void -miZeroArcDashPts( - GCPtr pGC, - xArc *arc, - DashInfo *dinfo, - DDXPointPtr points, - int maxPts, - DDXPointPtr *evenPts, - DDXPointPtr *oddPts ) -{ - miZeroArcRec info; - int x, y, a, b, d, mask; - int k1, k3, dx, dy; - int dashRemaining; - DDXPointPtr arcPts[4]; - DDXPointPtr startPts[5], endPts[5]; - int deltas[5]; - DDXPointPtr startPt, pt, lastPt, pts; - int i, j, delta, ptsdelta, seg, startseg; - - for (i = 0; i < 4; i++) - arcPts[i] = points + (i * maxPts); - (void)miZeroArcSetup(arc, &info, FALSE); - MIARCSETUP(); - mask = info.initialMask; - startseg = info.startAngle / QUADRANT; - startPt = arcPts[startseg]; - if (!(arc->width & 1)) - { - DoPix(1, info.xorgo, info.yorg); - DoPix(3, info.xorgo, info.yorgo); - } - if (!info.end.x || !info.end.y) - { - mask = info.end.mask; - info.end = info.altend; - } - while (y < info.h || x < info.w) - { - MIARCOCTANTSHIFT(;); - if ((x == info.firstx) || (y == info.firsty)) - startPt = arcPts[startseg]; - if ((x == info.start.x) || (y == info.start.y)) - { - mask = info.start.mask; - info.start = info.altstart; - } - DoPix(0, info.xorg + x, info.yorg + y); - DoPix(1, info.xorgo - x, info.yorg + y); - DoPix(2, info.xorgo - x, info.yorgo - y); - DoPix(3, info.xorg + x, info.yorgo - y); - if ((x == info.end.x) || (y == info.end.y)) - { - mask = info.end.mask; - info.end = info.altend; - } - MIARCSTEP(;,;); - } - if ((x == info.firstx) || (y == info.firsty)) - startPt = arcPts[startseg]; - if ((x == info.start.x) || (y == info.start.y)) - mask = info.start.mask; - DoPix(0, info.xorg + x, info.yorg + y); - DoPix(2, info.xorgo - x, info.yorgo - y); - if (arc->height & 1) - { - DoPix(1, info.xorgo - x, info.yorg + y); - DoPix(3, info.xorg + x, info.yorgo - y); - } - for (i = 0; i < 4; i++) - { - seg = (startseg + i) & 3; - pt = points + (seg * maxPts); - if (seg & 1) - { - startPts[i] = pt; - endPts[i] = arcPts[seg]; - deltas[i] = 1; - } - else - { - startPts[i] = arcPts[seg] - 1; - endPts[i] = pt - 1; - deltas[i] = -1; - } - } - startPts[4] = startPts[0]; - endPts[4] = startPt; - startPts[0] = startPt; - if (startseg & 1) - { - if (startPts[4] != endPts[4]) - endPts[4]--; - deltas[4] = 1; - } - else - { - if (startPts[0] > startPts[4]) - startPts[0]--; - if (startPts[4] < endPts[4]) - endPts[4]--; - deltas[4] = -1; - } - if (arc->angle2 < 0) - { - DDXPointPtr tmps, tmpe; - int tmpd; - - tmpd = deltas[0]; - tmps = startPts[0] - tmpd; - tmpe = endPts[0] - tmpd; - startPts[0] = endPts[4] - deltas[4]; - endPts[0] = startPts[4] - deltas[4]; - deltas[0] = -deltas[4]; - startPts[4] = tmpe; - endPts[4] = tmps; - deltas[4] = -tmpd; - tmpd = deltas[1]; - tmps = startPts[1] - tmpd; - tmpe = endPts[1] - tmpd; - startPts[1] = endPts[3] - deltas[3]; - endPts[1] = startPts[3] - deltas[3]; - deltas[1] = -deltas[3]; - startPts[3] = tmpe; - endPts[3] = tmps; - deltas[3] = -tmpd; - tmps = startPts[2] - deltas[2]; - startPts[2] = endPts[2] - deltas[2]; - endPts[2] = tmps; - deltas[2] = -deltas[2]; - } - for (i = 0; i < 5 && startPts[i] == endPts[i]; i++) - ; - if (i == 5) - return; - pt = startPts[i]; - for (j = 4; startPts[j] == endPts[j]; j--) - ; - lastPt = endPts[j] - deltas[j]; - if (dinfo->haveLast && - (pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y)) - { - startPts[i] += deltas[i]; - } - else - { - dinfo->dashIndex = dinfo->dashIndexInit; - dinfo->dashOffset = dinfo->dashOffsetInit; - } - if (!dinfo->skipStart && (info.startAngle != info.endAngle)) - { - dinfo->startPt = *pt; - dinfo->haveStart = TRUE; - } - else if (!dinfo->skipLast && dinfo->haveStart && - (lastPt->x == dinfo->startPt.x) && - (lastPt->y == dinfo->startPt.y) && - (lastPt != startPts[i])) - endPts[j] = lastPt; - if (info.startAngle != info.endAngle) - { - dinfo->haveLast = TRUE; - dinfo->endPt = *lastPt; - } - dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset; - for (i = 0; i < 5; i++) - { - pt = startPts[i]; - lastPt = endPts[i]; - delta = deltas[i]; - while (pt != lastPt) - { - if (dinfo->dashIndex & 1) - { - pts = *oddPts; - ptsdelta = -1; - } - else - { - pts = *evenPts; - ptsdelta = 1; - } - while ((pt != lastPt) && --dashRemaining >= 0) - { - *pts = *pt; - pts += ptsdelta; - pt += delta; - } - if (dinfo->dashIndex & 1) - *oddPts = pts; - else - *evenPts = pts; - if (dashRemaining <= 0) - { - if (++(dinfo->dashIndex) == pGC->numInDashList) - dinfo->dashIndex = 0; - dashRemaining = pGC->dash[dinfo->dashIndex]; - } - } - } - dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining; -} - -void -miZeroPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) -{ - int maxPts = 0; - int n, maxw = 0; - xArc *arc; - int i; - DDXPointPtr points, pts, oddPts = NULL; - DDXPointPtr pt; - int numPts; - Bool dospans; - int *widths = NULL; - XID fgPixel = pGC->fgPixel; - DashInfo dinfo; - - for (arc = parcs, i = narcs; --i >= 0; arc++) - { - if (!miCanZeroArc(arc)) - miPolyArc(pDraw, pGC, 1, arc); - else - { - if (arc->width > arc->height) - n = arc->width + (arc->height >> 1); - else - n = arc->height + (arc->width >> 1); - if (n > maxPts) - maxPts = n; - } - } - if (!maxPts) - return; - numPts = maxPts << 2; - dospans = (pGC->fillStyle != FillSolid); - if (dospans) - { - widths = xalloc(sizeof(int) * numPts); - if (!widths) - return; - maxw = 0; - } - if (pGC->lineStyle != LineSolid) - { - numPts <<= 1; - dinfo.haveStart = FALSE; - dinfo.skipStart = FALSE; - dinfo.haveLast = FALSE; - dinfo.dashIndexInit = 0; - dinfo.dashOffsetInit = 0; - miStepDash((int)pGC->dashOffset, &dinfo.dashIndexInit, - (unsigned char *) pGC->dash, (int)pGC->numInDashList, - &dinfo.dashOffsetInit); - } - points = xalloc(sizeof(DDXPointRec) * numPts); - if (!points) - { - if (dospans) - { - xfree(widths); - } - return; - } - for (arc = parcs, i = narcs; --i >= 0; arc++) - { - if (miCanZeroArc(arc)) - { - if (pGC->lineStyle == LineSolid) - pts = miZeroArcPts(arc, points); - else - { - pts = points; - oddPts = &points[(numPts >> 1) - 1]; - dinfo.skipLast = i; - miZeroArcDashPts(pGC, arc, &dinfo, - oddPts + 1, maxPts, &pts, &oddPts); - dinfo.skipStart = TRUE; - } - n = pts - points; - if (!dospans) - (*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, points); - else - { - if (n > maxw) - { - while (maxw < n) - widths[maxw++] = 1; - } - if (pGC->miTranslate) - { - for (pt = points; pt != pts; pt++) - { - pt->x += pDraw->x; - pt->y += pDraw->y; - } - } - (*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, FALSE); - } - if (pGC->lineStyle != LineDoubleDash) - continue; - if ((pGC->fillStyle == FillSolid) || - (pGC->fillStyle == FillStippled)) - { - DoChangeGC(pGC, GCForeground, (XID *)&pGC->bgPixel, 0); - ValidateGC(pDraw, pGC); - } - pts = &points[numPts >> 1]; - oddPts++; - n = pts - oddPts; - if (!dospans) - (*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, oddPts); - else - { - if (n > maxw) - { - while (maxw < n) - widths[maxw++] = 1; - } - if (pGC->miTranslate) - { - for (pt = oddPts; pt != pts; pt++) - { - pt->x += pDraw->x; - pt->y += pDraw->y; - } - } - (*pGC->ops->FillSpans)(pDraw, pGC, n, oddPts, widths, FALSE); - } - if ((pGC->fillStyle == FillSolid) || - (pGC->fillStyle == FillStippled)) - { - DoChangeGC(pGC, GCForeground, &fgPixel, 0); - ValidateGC(pDraw, pGC); - } - } - } - xfree(points); - if (dospans) - { - xfree(widths); - } -} +/************************************************************ + +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. + +Author: Bob Scheifler, MIT X Consortium + +********************************************************/ + + +/* Derived from: + * "Algorithm for drawing ellipses or hyperbolae with a digital plotter" + * by M. L. V. Pitteway + * The Computer Journal, November 1967, Volume 10, Number 3, pp. 282-289 + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <math.h> +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "regionstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "mi.h" +#include "mizerarc.h" + +#define FULLCIRCLE (360 * 64) +#define OCTANT (45 * 64) +#define QUADRANT (90 * 64) +#define HALFCIRCLE (180 * 64) +#define QUADRANT3 (270 * 64) + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define Dsin(d) ((d) == 0 ? 0.0 : ((d) == QUADRANT ? 1.0 : \ + ((d) == HALFCIRCLE ? 0.0 : \ + ((d) == QUADRANT3 ? -1.0 : sin((double)d*(M_PI/11520.0)))))) + +#define Dcos(d) ((d) == 0 ? 1.0 : ((d) == QUADRANT ? 0.0 : \ + ((d) == HALFCIRCLE ? -1.0 : \ + ((d) == QUADRANT3 ? 0.0 : cos((double)d*(M_PI/11520.0)))))) + +#define EPSILON45 64 + +typedef struct { + int skipStart; + int haveStart; + DDXPointRec startPt; + int haveLast; + int skipLast; + DDXPointRec endPt; + int dashIndex; + int dashOffset; + int dashIndexInit; + int dashOffsetInit; +} DashInfo; + +static miZeroArcPtRec oob = {65536, 65536, 0}; + +/* + * (x - l)^2 / (W/2)^2 + (y + H/2)^2 / (H/2)^2 = 1 + * + * where l is either 0 or .5 + * + * alpha = 4(W^2) + * beta = 4(H^2) + * gamma = 0 + * u = 2(W^2)H + * v = 4(H^2)l + * k = -4(H^2)(l^2) + * + */ + +Bool +miZeroArcSetup(xArc *arc, miZeroArcRec *info, Bool ok360) +{ + int l; + int angle1, angle2; + int startseg, endseg; + int startAngle, endAngle; + int i, overlap; + miZeroArcPtRec start, end; + + l = arc->width & 1; + if (arc->width == arc->height) + { + info->alpha = 4; + info->beta = 4; + info->k1 = -8; + info->k3 = -16; + info->b = 12; + info->a = (arc->width << 2) - 12; + info->d = 17 - (arc->width << 1); + if (l) + { + info->b -= 4; + info->a += 4; + info->d -= 7; + } + } + else if (!arc->width || !arc->height) + { + info->alpha = 0; + info->beta = 0; + info->k1 = 0; + info->k3 = 0; + info->a = -(int)arc->height; + info->b = 0; + info->d = -1; + } + else + { + /* initial conditions */ + info->alpha = (arc->width * arc->width) << 2; + info->beta = (arc->height * arc->height) << 2; + info->k1 = info->beta << 1; + info->k3 = info->k1 + (info->alpha << 1); + info->b = l ? 0 : -info->beta; + info->a = info->alpha * arc->height; + info->d = info->b - (info->a >> 1) - (info->alpha >> 2); + if (l) + info->d -= info->beta >> 2; + info->a -= info->b; + /* take first step, d < 0 always */ + info->b -= info->k1; + info->a += info->k1; + info->d += info->b; + /* octant change, b < 0 always */ + info->k1 = -info->k1; + info->k3 = -info->k3; + info->b = -info->b; + info->d = info->b - info->a - info->d; + info->a = info->a - (info->b << 1); + } + info->dx = 1; + info->dy = 0; + info->w = (arc->width + 1) >> 1; + info->h = arc->height >> 1; + info->xorg = arc->x + (arc->width >> 1); + info->yorg = arc->y; + info->xorgo = info->xorg + l; + info->yorgo = info->yorg + arc->height; + if (!arc->width) + { + if (!arc->height) + { + info->x = 0; + info->y = 0; + info->initialMask = 0; + info->startAngle = 0; + info->endAngle = 0; + info->start = oob; + info->end = oob; + return FALSE; + } + info->x = 0; + info->y = 1; + } + else + { + info->x = 1; + info->y = 0; + } + angle1 = arc->angle1; + angle2 = arc->angle2; + if ((angle1 == 0) && (angle2 >= FULLCIRCLE)) + { + startAngle = 0; + endAngle = 0; + } + else + { + if (angle2 > FULLCIRCLE) + angle2 = FULLCIRCLE; + else if (angle2 < -FULLCIRCLE) + angle2 = -FULLCIRCLE; + if (angle2 < 0) + { + startAngle = angle1 + angle2; + endAngle = angle1; + } + else + { + startAngle = angle1; + endAngle = angle1 + angle2; + } + if (startAngle < 0) + startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; + if (startAngle >= FULLCIRCLE) + startAngle = startAngle % FULLCIRCLE; + if (endAngle < 0) + endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE; + if (endAngle >= FULLCIRCLE) + endAngle = endAngle % FULLCIRCLE; + } + info->startAngle = startAngle; + info->endAngle = endAngle; + if (ok360 && (startAngle == endAngle) && arc->angle2 && + arc->width && arc->height) + { + info->initialMask = 0xf; + info->start = oob; + info->end = oob; + return TRUE; + } + startseg = startAngle / OCTANT; + if (!arc->height || (((startseg + 1) & 2) && arc->width)) + { + start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0); + if (start.x < 0) + start.x = -start.x; + start.y = -1; + } + else + { + start.y = Dsin(startAngle) * (arc->height / 2.0); + if (start.y < 0) + start.y = -start.y; + start.y = info->h - start.y; + start.x = 65536; + } + endseg = endAngle / OCTANT; + if (!arc->height || (((endseg + 1) & 2) && arc->width)) + { + end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0); + if (end.x < 0) + end.x = -end.x; + end.y = -1; + } + else + { + end.y = Dsin(endAngle) * (arc->height / 2.0); + if (end.y < 0) + end.y = -end.y; + end.y = info->h - end.y; + end.x = 65536; + } + info->firstx = start.x; + info->firsty = start.y; + info->initialMask = 0; + overlap = arc->angle2 && (endAngle <= startAngle); + for (i = 0; i < 4; i++) + { + if (overlap ? + ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) : + ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle))) + info->initialMask |= (1 << i); + } + start.mask = info->initialMask; + end.mask = info->initialMask; + startseg >>= 1; + endseg >>= 1; + overlap = overlap && (endseg == startseg); + if (start.x != end.x || start.y != end.y || !overlap) + { + if (startseg & 1) + { + if (!overlap) + info->initialMask &= ~(1 << startseg); + if (start.x > end.x || start.y > end.y) + end.mask &= ~(1 << startseg); + } + else + { + start.mask &= ~(1 << startseg); + if (((start.x < end.x || start.y < end.y) || + (start.x == end.x && start.y == end.y && (endseg & 1))) && + !overlap) + end.mask &= ~(1 << startseg); + } + if (endseg & 1) + { + end.mask &= ~(1 << endseg); + if (((start.x > end.x || start.y > end.y) || + (start.x == end.x && start.y == end.y && !(startseg & 1))) && + !overlap) + start.mask &= ~(1 << endseg); + } + else + { + if (!overlap) + info->initialMask &= ~(1 << endseg); + if (start.x < end.x || start.y < end.y) + start.mask &= ~(1 << endseg); + } + } + /* take care of case when start and stop are both near 45 */ + /* handle here rather than adding extra code to pixelization loops */ + if (startAngle && + ((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0))) + { + i = (startAngle + OCTANT) % OCTANT; + if (i < EPSILON45 || i > OCTANT - EPSILON45) + { + i = (endAngle + OCTANT) % OCTANT; + if (i < EPSILON45 || i > OCTANT - EPSILON45) + { + if (start.y < 0) + { + i = Dsin(startAngle) * (arc->height / 2.0); + if (i < 0) + i = -i; + if (info->h - i == end.y) + start.mask = end.mask; + } + else + { + i = Dsin(endAngle) * (arc->height / 2.0); + if (i < 0) + i = -i; + if (info->h - i == start.y) + end.mask = start.mask; + } + } + } + } + if (startseg & 1) + { + info->start = start; + info->end = oob; + } + else + { + info->end = start; + info->start = oob; + } + if (endseg & 1) + { + info->altend = end; + if (info->altend.x < info->end.x || info->altend.y < info->end.y) + { + miZeroArcPtRec tmp; + tmp = info->altend; + info->altend = info->end; + info->end = tmp; + } + info->altstart = oob; + } + else + { + info->altstart = end; + if (info->altstart.x < info->start.x || + info->altstart.y < info->start.y) + { + miZeroArcPtRec tmp; + tmp = info->altstart; + info->altstart = info->start; + info->start = tmp; + } + info->altend = oob; + } + if (!info->start.x || !info->start.y) + { + info->initialMask = info->start.mask; + info->start = info->altstart; + } + if (!arc->width && (arc->height == 1)) + { + /* kludge! */ + info->initialMask |= info->end.mask; + info->initialMask |= info->initialMask << 1; + info->end.x = 0; + info->end.mask = 0; + } + return FALSE; +} + +#define Pixelate(xval,yval) \ + { \ + pts->x = xval; \ + pts->y = yval; \ + pts++; \ + } + +#define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval); + +static DDXPointPtr +miZeroArcPts(xArc *arc, DDXPointPtr pts) +{ + miZeroArcRec info; + int x, y, a, b, d, mask; + int k1, k3, dx, dy; + Bool do360; + + do360 = miZeroArcSetup(arc, &info, TRUE); + MIARCSETUP(); + mask = info.initialMask; + if (!(arc->width & 1)) + { + DoPix(1, info.xorgo, info.yorg); + DoPix(3, info.xorgo, info.yorgo); + } + if (!info.end.x || !info.end.y) + { + mask = info.end.mask; + info.end = info.altend; + } + if (do360 && (arc->width == arc->height) && !(arc->width & 1)) + { + int yorgh = info.yorg + info.h; + int xorghp = info.xorg + info.h; + int xorghn = info.xorg - info.h; + + while (1) + { + Pixelate(info.xorg + x, info.yorg + y); + Pixelate(info.xorg - x, info.yorg + y); + Pixelate(info.xorg - x, info.yorgo - y); + Pixelate(info.xorg + x, info.yorgo - y); + if (a < 0) + break; + Pixelate(xorghp - y, yorgh - x); + Pixelate(xorghn + y, yorgh - x); + Pixelate(xorghn + y, yorgh + x); + Pixelate(xorghp - y, yorgh + x); + MIARCCIRCLESTEP(;); + } + if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y) + pts -= 4; + x = info.w; + y = info.h; + } + else if (do360) + { + while (y < info.h || x < info.w) + { + MIARCOCTANTSHIFT(;); + Pixelate(info.xorg + x, info.yorg + y); + Pixelate(info.xorgo - x, info.yorg + y); + Pixelate(info.xorgo - x, info.yorgo - y); + Pixelate(info.xorg + x, info.yorgo - y); + MIARCSTEP(;,;); + } + } + else + { + while (y < info.h || x < info.w) + { + MIARCOCTANTSHIFT(;); + if ((x == info.start.x) || (y == info.start.y)) + { + mask = info.start.mask; + info.start = info.altstart; + } + DoPix(0, info.xorg + x, info.yorg + y); + DoPix(1, info.xorgo - x, info.yorg + y); + DoPix(2, info.xorgo - x, info.yorgo - y); + DoPix(3, info.xorg + x, info.yorgo - y); + if ((x == info.end.x) || (y == info.end.y)) + { + mask = info.end.mask; + info.end = info.altend; + } + MIARCSTEP(;,;); + } + } + if ((x == info.start.x) || (y == info.start.y)) + mask = info.start.mask; + DoPix(0, info.xorg + x, info.yorg + y); + DoPix(2, info.xorgo - x, info.yorgo - y); + if (arc->height & 1) + { + DoPix(1, info.xorgo - x, info.yorg + y); + DoPix(3, info.xorg + x, info.yorgo - y); + } + return pts; +} + +#undef DoPix +#define DoPix(idx,xval,yval) \ + if (mask & (1 << idx)) \ + { \ + arcPts[idx]->x = xval; \ + arcPts[idx]->y = yval; \ + arcPts[idx]++; \ + } + +static void +miZeroArcDashPts( + GCPtr pGC, + xArc *arc, + DashInfo *dinfo, + DDXPointPtr points, + int maxPts, + DDXPointPtr *evenPts, + DDXPointPtr *oddPts ) +{ + miZeroArcRec info; + int x, y, a, b, d, mask; + int k1, k3, dx, dy; + int dashRemaining; + DDXPointPtr arcPts[4]; + DDXPointPtr startPts[5], endPts[5]; + int deltas[5]; + DDXPointPtr startPt, pt, lastPt, pts; + int i, j, delta, ptsdelta, seg, startseg; + + for (i = 0; i < 4; i++) + arcPts[i] = points + (i * maxPts); + (void)miZeroArcSetup(arc, &info, FALSE); + MIARCSETUP(); + mask = info.initialMask; + startseg = info.startAngle / QUADRANT; + startPt = arcPts[startseg]; + if (!(arc->width & 1)) + { + DoPix(1, info.xorgo, info.yorg); + DoPix(3, info.xorgo, info.yorgo); + } + if (!info.end.x || !info.end.y) + { + mask = info.end.mask; + info.end = info.altend; + } + while (y < info.h || x < info.w) + { + MIARCOCTANTSHIFT(;); + if ((x == info.firstx) || (y == info.firsty)) + startPt = arcPts[startseg]; + if ((x == info.start.x) || (y == info.start.y)) + { + mask = info.start.mask; + info.start = info.altstart; + } + DoPix(0, info.xorg + x, info.yorg + y); + DoPix(1, info.xorgo - x, info.yorg + y); + DoPix(2, info.xorgo - x, info.yorgo - y); + DoPix(3, info.xorg + x, info.yorgo - y); + if ((x == info.end.x) || (y == info.end.y)) + { + mask = info.end.mask; + info.end = info.altend; + } + MIARCSTEP(;,;); + } + if ((x == info.firstx) || (y == info.firsty)) + startPt = arcPts[startseg]; + if ((x == info.start.x) || (y == info.start.y)) + mask = info.start.mask; + DoPix(0, info.xorg + x, info.yorg + y); + DoPix(2, info.xorgo - x, info.yorgo - y); + if (arc->height & 1) + { + DoPix(1, info.xorgo - x, info.yorg + y); + DoPix(3, info.xorg + x, info.yorgo - y); + } + for (i = 0; i < 4; i++) + { + seg = (startseg + i) & 3; + pt = points + (seg * maxPts); + if (seg & 1) + { + startPts[i] = pt; + endPts[i] = arcPts[seg]; + deltas[i] = 1; + } + else + { + startPts[i] = arcPts[seg] - 1; + endPts[i] = pt - 1; + deltas[i] = -1; + } + } + startPts[4] = startPts[0]; + endPts[4] = startPt; + startPts[0] = startPt; + if (startseg & 1) + { + if (startPts[4] != endPts[4]) + endPts[4]--; + deltas[4] = 1; + } + else + { + if (startPts[0] > startPts[4]) + startPts[0]--; + if (startPts[4] < endPts[4]) + endPts[4]--; + deltas[4] = -1; + } + if (arc->angle2 < 0) + { + DDXPointPtr tmps, tmpe; + int tmpd; + + tmpd = deltas[0]; + tmps = startPts[0] - tmpd; + tmpe = endPts[0] - tmpd; + startPts[0] = endPts[4] - deltas[4]; + endPts[0] = startPts[4] - deltas[4]; + deltas[0] = -deltas[4]; + startPts[4] = tmpe; + endPts[4] = tmps; + deltas[4] = -tmpd; + tmpd = deltas[1]; + tmps = startPts[1] - tmpd; + tmpe = endPts[1] - tmpd; + startPts[1] = endPts[3] - deltas[3]; + endPts[1] = startPts[3] - deltas[3]; + deltas[1] = -deltas[3]; + startPts[3] = tmpe; + endPts[3] = tmps; + deltas[3] = -tmpd; + tmps = startPts[2] - deltas[2]; + startPts[2] = endPts[2] - deltas[2]; + endPts[2] = tmps; + deltas[2] = -deltas[2]; + } + for (i = 0; i < 5 && startPts[i] == endPts[i]; i++) + ; + if (i == 5) + return; + pt = startPts[i]; + for (j = 4; startPts[j] == endPts[j]; j--) + ; + lastPt = endPts[j] - deltas[j]; + if (dinfo->haveLast && + (pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y)) + { + startPts[i] += deltas[i]; + } + else + { + dinfo->dashIndex = dinfo->dashIndexInit; + dinfo->dashOffset = dinfo->dashOffsetInit; + } + if (!dinfo->skipStart && (info.startAngle != info.endAngle)) + { + dinfo->startPt = *pt; + dinfo->haveStart = TRUE; + } + else if (!dinfo->skipLast && dinfo->haveStart && + (lastPt->x == dinfo->startPt.x) && + (lastPt->y == dinfo->startPt.y) && + (lastPt != startPts[i])) + endPts[j] = lastPt; + if (info.startAngle != info.endAngle) + { + dinfo->haveLast = TRUE; + dinfo->endPt = *lastPt; + } + dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset; + for (i = 0; i < 5; i++) + { + pt = startPts[i]; + lastPt = endPts[i]; + delta = deltas[i]; + while (pt != lastPt) + { + if (dinfo->dashIndex & 1) + { + pts = *oddPts; + ptsdelta = -1; + } + else + { + pts = *evenPts; + ptsdelta = 1; + } + while ((pt != lastPt) && --dashRemaining >= 0) + { + *pts = *pt; + pts += ptsdelta; + pt += delta; + } + if (dinfo->dashIndex & 1) + *oddPts = pts; + else + *evenPts = pts; + if (dashRemaining <= 0) + { + if (++(dinfo->dashIndex) == pGC->numInDashList) + dinfo->dashIndex = 0; + dashRemaining = pGC->dash[dinfo->dashIndex]; + } + } + } + dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining; +} + +void +miZeroPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) +{ + int maxPts = 0; + int n, maxw = 0; + xArc *arc; + int i; + DDXPointPtr points, pts, oddPts = NULL; + DDXPointPtr pt; + int numPts; + Bool dospans; + int *widths = NULL; + XID fgPixel = pGC->fgPixel; + DashInfo dinfo; + + for (arc = parcs, i = narcs; --i >= 0; arc++) + { + if (!miCanZeroArc(arc)) + miPolyArc(pDraw, pGC, 1, arc); + else + { + if (arc->width > arc->height) + n = arc->width + (arc->height >> 1); + else + n = arc->height + (arc->width >> 1); + if (n > maxPts) + maxPts = n; + } + } + if (!maxPts) + return; + numPts = maxPts << 2; + dospans = (pGC->fillStyle != FillSolid); + if (dospans) + { + widths = malloc(sizeof(int) * numPts); + if (!widths) + return; + maxw = 0; + } + if (pGC->lineStyle != LineSolid) + { + numPts <<= 1; + dinfo.haveStart = FALSE; + dinfo.skipStart = FALSE; + dinfo.haveLast = FALSE; + dinfo.dashIndexInit = 0; + dinfo.dashOffsetInit = 0; + miStepDash((int)pGC->dashOffset, &dinfo.dashIndexInit, + (unsigned char *) pGC->dash, (int)pGC->numInDashList, + &dinfo.dashOffsetInit); + } + points = malloc(sizeof(DDXPointRec) * numPts); + if (!points) + { + if (dospans) + { + free(widths); + } + return; + } + for (arc = parcs, i = narcs; --i >= 0; arc++) + { + if (miCanZeroArc(arc)) + { + if (pGC->lineStyle == LineSolid) + pts = miZeroArcPts(arc, points); + else + { + pts = points; + oddPts = &points[(numPts >> 1) - 1]; + dinfo.skipLast = i; + miZeroArcDashPts(pGC, arc, &dinfo, + oddPts + 1, maxPts, &pts, &oddPts); + dinfo.skipStart = TRUE; + } + n = pts - points; + if (!dospans) + (*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, points); + else + { + if (n > maxw) + { + while (maxw < n) + widths[maxw++] = 1; + } + if (pGC->miTranslate) + { + for (pt = points; pt != pts; pt++) + { + pt->x += pDraw->x; + pt->y += pDraw->y; + } + } + (*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, FALSE); + } + if (pGC->lineStyle != LineDoubleDash) + continue; + if ((pGC->fillStyle == FillSolid) || + (pGC->fillStyle == FillStippled)) + { + ChangeGCVal gcval; + gcval.val = pGC->bgPixel; + ChangeGC(NullClient, pGC, GCForeground, &gcval); + ValidateGC(pDraw, pGC); + } + pts = &points[numPts >> 1]; + oddPts++; + n = pts - oddPts; + if (!dospans) + (*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, oddPts); + else + { + if (n > maxw) + { + while (maxw < n) + widths[maxw++] = 1; + } + if (pGC->miTranslate) + { + for (pt = oddPts; pt != pts; pt++) + { + pt->x += pDraw->x; + pt->y += pDraw->y; + } + } + (*pGC->ops->FillSpans)(pDraw, pGC, n, oddPts, widths, FALSE); + } + if ((pGC->fillStyle == FillSolid) || + (pGC->fillStyle == FillStippled)) + { + ChangeGCVal gcval; + gcval.val = fgPixel; + ChangeGC(NullClient, pGC, GCForeground, &gcval); + ValidateGC(pDraw, pGC); + } + } + } + free(points); + if (dospans) + { + free(widths); + } +} diff --git a/xorg-server/mi/mizerline.c b/xorg-server/mi/mizerline.c index 46e2e2adc..d37e1cc96 100644 --- a/xorg-server/mi/mizerline.c +++ b/xorg-server/mi/mizerline.c @@ -1,379 +1,379 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <X11/X.h> - -#include "misc.h" -#include "scrnintstr.h" -#include "gcstruct.h" -#include "windowstr.h" -#include "pixmap.h" -#include "mi.h" -#include "miline.h" - -/* Draw lineSolid, fillStyle-independent zero width lines. - * - * Must keep X and Y coordinates in "ints" at least until after they're - * translated and clipped to accomodate CoordModePrevious lines with very - * large coordinates. - * - * Draws the same pixels regardless of sign(dx) or sign(dy). - * - * Ken Whaley - * - */ - -/* largest positive value that can fit into a component of a point. - * Assumes that the point structure is {type x, y;} where type is - * a signed type. - */ -#define MAX_COORDINATE ((1 << (((sizeof(DDXPointRec) >> 1) << 3) - 1)) - 1) - -#define MI_OUTPUT_POINT(xx, yy)\ -{\ - if ( !new_span && yy == current_y)\ - {\ - if (xx < spans->x)\ - spans->x = xx;\ - ++*widths;\ - }\ - else\ - {\ - ++Nspans;\ - ++spans;\ - ++widths;\ - spans->x = xx;\ - spans->y = yy;\ - *widths = 1;\ - current_y = yy;\ - new_span = FALSE;\ - }\ -} - -void -miZeroLine( - DrawablePtr pDraw, - GCPtr pGC, - int mode, /* Origin or Previous */ - int npt, /* number of points */ - DDXPointPtr pptInit) -{ - int Nspans, current_y = 0; - DDXPointPtr ppt; - DDXPointPtr pspanInit, spans; - int *pwidthInit, *widths, list_len; - int xleft, ytop, xright, ybottom; - int new_x1, new_y1, new_x2, new_y2; - int x = 0, y = 0, x1, y1, x2, y2, xstart, ystart; - int oc1, oc2; - int result; - int pt1_clipped, pt2_clipped = 0; - Bool new_span; - int signdx, signdy; - int clipdx, clipdy; - int width, height; - int adx, ady; - int octant; - unsigned int bias = miGetZeroLineBias(pDraw->pScreen); - int e, e1, e2, e3; /* Bresenham error terms */ - int length; /* length of lines == # of pixels on major axis */ - - xleft = pDraw->x; - ytop = pDraw->y; - xright = pDraw->x + pDraw->width - 1; - ybottom = pDraw->y + pDraw->height - 1; - - if (!pGC->miTranslate) - { - /* do everything in drawable-relative coordinates */ - xleft = 0; - ytop = 0; - xright -= pDraw->x; - ybottom -= pDraw->y; - } - - /* it doesn't matter whether we're in drawable or screen coordinates, - * FillSpans simply cannot take starting coordinates outside of the - * range of a DDXPointRec component. - */ - if (xright > MAX_COORDINATE) - xright = MAX_COORDINATE; - if (ybottom > MAX_COORDINATE) - ybottom = MAX_COORDINATE; - - /* since we're clipping to the drawable's boundaries & coordinate - * space boundaries, we're guaranteed that the larger of width/height - * is the longest span we'll need to output - */ - width = xright - xleft + 1; - height = ybottom - ytop + 1; - list_len = (height >= width) ? height : width; - pspanInit = xalloc(list_len * sizeof(DDXPointRec)); - pwidthInit = xalloc(list_len * sizeof(int)); - if (!pspanInit || !pwidthInit) - return; - - Nspans = 0; - new_span = TRUE; - spans = pspanInit - 1; - widths = pwidthInit - 1; - ppt = pptInit; - - xstart = ppt->x; - ystart = ppt->y; - if (pGC->miTranslate) - { - xstart += pDraw->x; - ystart += pDraw->y; - } - - /* x2, y2, oc2 copied to x1, y1, oc1 at top of loop to simplify - * iteration logic - */ - x2 = xstart; - y2 = ystart; - oc2 = 0; - MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom); - - while (--npt > 0) - { - if (Nspans > 0) - (*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit, - pwidthInit, FALSE); - Nspans = 0; - new_span = TRUE; - spans = pspanInit - 1; - widths = pwidthInit - 1; - - x1 = x2; - y1 = y2; - oc1 = oc2; - ++ppt; - - x2 = ppt->x; - y2 = ppt->y; - if (pGC->miTranslate && (mode != CoordModePrevious)) - { - x2 += pDraw->x; - y2 += pDraw->y; - } - else if (mode == CoordModePrevious) - { - x2 += x1; - y2 += y1; - } - - oc2 = 0; - MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom); - - CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant); - - if (adx > ady) - { - e1 = ady << 1; - e2 = e1 - (adx << 1); - e = e1 - adx; - length = adx; /* don't draw endpoint in main loop */ - - FIXUP_ERROR(e, octant, bias); - - new_x1 = x1; - new_y1 = y1; - new_x2 = x2; - new_y2 = y2; - pt1_clipped = 0; - pt2_clipped = 0; - - if ((oc1 | oc2) != 0) - { - result = miZeroClipLine(xleft, ytop, xright, ybottom, - &new_x1, &new_y1, &new_x2, &new_y2, - adx, ady, - &pt1_clipped, &pt2_clipped, - octant, bias, oc1, oc2); - if (result == -1) - continue; - - length = abs(new_x2 - new_x1); - - /* if we've clipped the endpoint, always draw the full length - * of the segment, because then the capstyle doesn't matter - */ - if (pt2_clipped) - length++; - - if (pt1_clipped) - { - /* must calculate new error terms */ - clipdx = abs(new_x1 - x1); - clipdy = abs(new_y1 - y1); - e += (clipdy * e2) + ((clipdx - clipdy) * e1); - } - } - - /* draw the segment */ - - x = new_x1; - y = new_y1; - - e3 = e2 - e1; - e = e - e1; - - while (length--) - { - MI_OUTPUT_POINT(x, y); - e += e1; - if (e >= 0) - { - y += signdy; - e += e3; - } - x += signdx; - } - } - else /* Y major line */ - { - e1 = adx << 1; - e2 = e1 - (ady << 1); - e = e1 - ady; - length = ady; /* don't draw endpoint in main loop */ - - SetYMajorOctant(octant); - FIXUP_ERROR(e, octant, bias); - - new_x1 = x1; - new_y1 = y1; - new_x2 = x2; - new_y2 = y2; - pt1_clipped = 0; - pt2_clipped = 0; - - if ((oc1 | oc2) != 0) - { - result = miZeroClipLine(xleft, ytop, xright, ybottom, - &new_x1, &new_y1, &new_x2, &new_y2, - adx, ady, - &pt1_clipped, &pt2_clipped, - octant, bias, oc1, oc2); - if (result == -1) - continue; - - length = abs(new_y2 - new_y1); - - /* if we've clipped the endpoint, always draw the full length - * of the segment, because then the capstyle doesn't matter - */ - if (pt2_clipped) - length++; - - if (pt1_clipped) - { - /* must calculate new error terms */ - clipdx = abs(new_x1 - x1); - clipdy = abs(new_y1 - y1); - e += (clipdx * e2) + ((clipdy - clipdx) * e1); - } - } - - /* draw the segment */ - - x = new_x1; - y = new_y1; - - e3 = e2 - e1; - e = e - e1; - - while (length--) - { - MI_OUTPUT_POINT(x, y); - e += e1; - if (e >= 0) - { - x += signdx; - e += e3; - } - y += signdy; - } - } - } - - /* only do the capnotlast check on the last segment - * and only if the endpoint wasn't clipped. And then, if the last - * point is the same as the first point, do not draw it, unless the - * line is degenerate - */ - if ( (! pt2_clipped) && (pGC->capStyle != CapNotLast) && - (((xstart != x2) || (ystart != y2)) || (ppt == pptInit + 1))) - { - MI_OUTPUT_POINT(x, y); - } - - if (Nspans > 0) - (*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit, - pwidthInit, FALSE); - - xfree(pwidthInit); - xfree(pspanInit); -} - -void -miZeroDashLine( - DrawablePtr dst, - GCPtr pgc, - int mode, - int nptInit, /* number of points in polyline */ - DDXPointRec *pptInit /* points in the polyline */ - ) -{ - /* XXX kludge until real zero-width dash code is written */ - pgc->lineWidth = 1; - miWideDash (dst, pgc, mode, nptInit, pptInit); - pgc->lineWidth = 0; -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <X11/X.h> + +#include "misc.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmap.h" +#include "mi.h" +#include "miline.h" + +/* Draw lineSolid, fillStyle-independent zero width lines. + * + * Must keep X and Y coordinates in "ints" at least until after they're + * translated and clipped to accomodate CoordModePrevious lines with very + * large coordinates. + * + * Draws the same pixels regardless of sign(dx) or sign(dy). + * + * Ken Whaley + * + */ + +/* largest positive value that can fit into a component of a point. + * Assumes that the point structure is {type x, y;} where type is + * a signed type. + */ +#define MAX_COORDINATE ((1 << (((sizeof(DDXPointRec) >> 1) << 3) - 1)) - 1) + +#define MI_OUTPUT_POINT(xx, yy)\ +{\ + if ( !new_span && yy == current_y)\ + {\ + if (xx < spans->x)\ + spans->x = xx;\ + ++*widths;\ + }\ + else\ + {\ + ++Nspans;\ + ++spans;\ + ++widths;\ + spans->x = xx;\ + spans->y = yy;\ + *widths = 1;\ + current_y = yy;\ + new_span = FALSE;\ + }\ +} + +void +miZeroLine( + DrawablePtr pDraw, + GCPtr pGC, + int mode, /* Origin or Previous */ + int npt, /* number of points */ + DDXPointPtr pptInit) +{ + int Nspans, current_y = 0; + DDXPointPtr ppt; + DDXPointPtr pspanInit, spans; + int *pwidthInit, *widths, list_len; + int xleft, ytop, xright, ybottom; + int new_x1, new_y1, new_x2, new_y2; + int x = 0, y = 0, x1, y1, x2, y2, xstart, ystart; + int oc1, oc2; + int result; + int pt1_clipped, pt2_clipped = 0; + Bool new_span; + int signdx, signdy; + int clipdx, clipdy; + int width, height; + int adx, ady; + int octant; + unsigned int bias = miGetZeroLineBias(pDraw->pScreen); + int e, e1, e2, e3; /* Bresenham error terms */ + int length; /* length of lines == # of pixels on major axis */ + + xleft = pDraw->x; + ytop = pDraw->y; + xright = pDraw->x + pDraw->width - 1; + ybottom = pDraw->y + pDraw->height - 1; + + if (!pGC->miTranslate) + { + /* do everything in drawable-relative coordinates */ + xleft = 0; + ytop = 0; + xright -= pDraw->x; + ybottom -= pDraw->y; + } + + /* it doesn't matter whether we're in drawable or screen coordinates, + * FillSpans simply cannot take starting coordinates outside of the + * range of a DDXPointRec component. + */ + if (xright > MAX_COORDINATE) + xright = MAX_COORDINATE; + if (ybottom > MAX_COORDINATE) + ybottom = MAX_COORDINATE; + + /* since we're clipping to the drawable's boundaries & coordinate + * space boundaries, we're guaranteed that the larger of width/height + * is the longest span we'll need to output + */ + width = xright - xleft + 1; + height = ybottom - ytop + 1; + list_len = (height >= width) ? height : width; + pspanInit = malloc(list_len * sizeof(DDXPointRec)); + pwidthInit = malloc(list_len * sizeof(int)); + if (!pspanInit || !pwidthInit) + return; + + Nspans = 0; + new_span = TRUE; + spans = pspanInit - 1; + widths = pwidthInit - 1; + ppt = pptInit; + + xstart = ppt->x; + ystart = ppt->y; + if (pGC->miTranslate) + { + xstart += pDraw->x; + ystart += pDraw->y; + } + + /* x2, y2, oc2 copied to x1, y1, oc1 at top of loop to simplify + * iteration logic + */ + x2 = xstart; + y2 = ystart; + oc2 = 0; + MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom); + + while (--npt > 0) + { + if (Nspans > 0) + (*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit, + pwidthInit, FALSE); + Nspans = 0; + new_span = TRUE; + spans = pspanInit - 1; + widths = pwidthInit - 1; + + x1 = x2; + y1 = y2; + oc1 = oc2; + ++ppt; + + x2 = ppt->x; + y2 = ppt->y; + if (pGC->miTranslate && (mode != CoordModePrevious)) + { + x2 += pDraw->x; + y2 += pDraw->y; + } + else if (mode == CoordModePrevious) + { + x2 += x1; + y2 += y1; + } + + oc2 = 0; + MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom); + + CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant); + + if (adx > ady) + { + e1 = ady << 1; + e2 = e1 - (adx << 1); + e = e1 - adx; + length = adx; /* don't draw endpoint in main loop */ + + FIXUP_ERROR(e, octant, bias); + + new_x1 = x1; + new_y1 = y1; + new_x2 = x2; + new_y2 = y2; + pt1_clipped = 0; + pt2_clipped = 0; + + if ((oc1 | oc2) != 0) + { + result = miZeroClipLine(xleft, ytop, xright, ybottom, + &new_x1, &new_y1, &new_x2, &new_y2, + adx, ady, + &pt1_clipped, &pt2_clipped, + octant, bias, oc1, oc2); + if (result == -1) + continue; + + length = abs(new_x2 - new_x1); + + /* if we've clipped the endpoint, always draw the full length + * of the segment, because then the capstyle doesn't matter + */ + if (pt2_clipped) + length++; + + if (pt1_clipped) + { + /* must calculate new error terms */ + clipdx = abs(new_x1 - x1); + clipdy = abs(new_y1 - y1); + e += (clipdy * e2) + ((clipdx - clipdy) * e1); + } + } + + /* draw the segment */ + + x = new_x1; + y = new_y1; + + e3 = e2 - e1; + e = e - e1; + + while (length--) + { + MI_OUTPUT_POINT(x, y); + e += e1; + if (e >= 0) + { + y += signdy; + e += e3; + } + x += signdx; + } + } + else /* Y major line */ + { + e1 = adx << 1; + e2 = e1 - (ady << 1); + e = e1 - ady; + length = ady; /* don't draw endpoint in main loop */ + + SetYMajorOctant(octant); + FIXUP_ERROR(e, octant, bias); + + new_x1 = x1; + new_y1 = y1; + new_x2 = x2; + new_y2 = y2; + pt1_clipped = 0; + pt2_clipped = 0; + + if ((oc1 | oc2) != 0) + { + result = miZeroClipLine(xleft, ytop, xright, ybottom, + &new_x1, &new_y1, &new_x2, &new_y2, + adx, ady, + &pt1_clipped, &pt2_clipped, + octant, bias, oc1, oc2); + if (result == -1) + continue; + + length = abs(new_y2 - new_y1); + + /* if we've clipped the endpoint, always draw the full length + * of the segment, because then the capstyle doesn't matter + */ + if (pt2_clipped) + length++; + + if (pt1_clipped) + { + /* must calculate new error terms */ + clipdx = abs(new_x1 - x1); + clipdy = abs(new_y1 - y1); + e += (clipdx * e2) + ((clipdy - clipdx) * e1); + } + } + + /* draw the segment */ + + x = new_x1; + y = new_y1; + + e3 = e2 - e1; + e = e - e1; + + while (length--) + { + MI_OUTPUT_POINT(x, y); + e += e1; + if (e >= 0) + { + x += signdx; + e += e3; + } + y += signdy; + } + } + } + + /* only do the capnotlast check on the last segment + * and only if the endpoint wasn't clipped. And then, if the last + * point is the same as the first point, do not draw it, unless the + * line is degenerate + */ + if ( (! pt2_clipped) && (pGC->capStyle != CapNotLast) && + (((xstart != x2) || (ystart != y2)) || (ppt == pptInit + 1))) + { + MI_OUTPUT_POINT(x, y); + } + + if (Nspans > 0) + (*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit, + pwidthInit, FALSE); + + free(pwidthInit); + free(pspanInit); +} + +void +miZeroDashLine( + DrawablePtr dst, + GCPtr pgc, + int mode, + int nptInit, /* number of points in polyline */ + DDXPointRec *pptInit /* points in the polyline */ + ) +{ + /* XXX kludge until real zero-width dash code is written */ + pgc->lineWidth = 1; + miWideDash (dst, pgc, mode, nptInit, pptInit); + pgc->lineWidth = 0; +} diff --git a/xorg-server/miext/cw/cw.c b/xorg-server/miext/cw/cw.c index 247cb83e1..72a90c699 100644 --- a/xorg-server/miext/cw/cw.c +++ b/xorg-server/miext/cw/cw.c @@ -1,522 +1,522 @@ -/* - * Copyright © 2004 Eric Anholt - * - * 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 Eric Anholt not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Eric Anholt makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL ERIC ANHOLT 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 <dix-config.h> -#endif - -#include <string.h> - -#include "gcstruct.h" -#include "windowstr.h" -#include "cw.h" - -#define CW_DEBUG 1 - -#if CW_DEBUG -#define CW_ASSERT(x) do { \ - if (!(x)) { \ - ErrorF("composite wrapper: assertion failed at %s:%d\n", __FUNC__, \ - __LINE__); \ - } \ -} while (0) -#else -#define CW_ASSERT(x) do {} while (0) -#endif - -static int cwGCKeyIndex; -DevPrivateKey cwGCKey = &cwGCKeyIndex; -static int cwScreenKeyIndex; -DevPrivateKey cwScreenKey = &cwScreenKeyIndex; -static int cwWindowKeyIndex; -DevPrivateKey cwWindowKey = &cwWindowKeyIndex; -static int cwPictureKeyIndex; -DevPrivateKey cwPictureKey = &cwPictureKeyIndex; -extern GCOps cwGCOps; - -static Bool -cwCloseScreen (int i, ScreenPtr pScreen); - -static void -cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable); -static void -cwChangeGC(GCPtr pGC, unsigned long mask); -static void -cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); -static void -cwDestroyGC(GCPtr pGC); -static void -cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects); -static void -cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc); -static void -cwDestroyClip(GCPtr pGC); - -GCFuncs cwGCFuncs = { - cwValidateGC, - cwChangeGC, - cwCopyGC, - cwDestroyGC, - cwChangeClip, - cwDestroyClip, - cwCopyClip, -}; - -/* Find the real drawable to draw to, and provide offsets that will translate - * window coordinates to backing pixmap coordinates. - */ -DrawablePtr -cwGetBackingDrawable(DrawablePtr pDrawable, int *x_off, int *y_off) -{ - PixmapPtr pPixmap; - - if (pDrawable->type == DRAWABLE_WINDOW && - (pPixmap = getCwPixmap ((WindowPtr) pDrawable))) - { - *x_off = pDrawable->x - pPixmap->screen_x; - *y_off = pDrawable->y - pPixmap->screen_y; - return &pPixmap->drawable; - } else { - *x_off = *y_off = 0; - return pDrawable; - } -} - -#define FUNC_PROLOGUE(pGC, pPriv) do { \ - (pGC)->funcs = (pPriv)->wrapFuncs; \ - (pGC)->ops = (pPriv)->wrapOps; \ -} while (0) - -#define FUNC_EPILOGUE(pGC, pPriv) do { \ - (pPriv)->wrapFuncs = (pGC)->funcs; \ - (pPriv)->wrapOps = (pGC)->ops; \ - (pGC)->funcs = &cwGCFuncs; \ - (pGC)->ops = &cwGCOps; \ -} while (0) - - -static Bool -cwCreateBackingGC(GCPtr pGC, DrawablePtr pDrawable) -{ - cwGCRec *pPriv = getCwGC(pGC); - int status, x_off, y_off; - XID noexpose = xFalse; - DrawablePtr pBackingDrawable; - - pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off); - pPriv->pBackingGC = CreateGC(pBackingDrawable, GCGraphicsExposures, - &noexpose, &status, (XID)0, serverClient); - if (status != Success) - return FALSE; - - pPriv->serialNumber = 0; - pPriv->stateChanges = (1 << (GCLastBit + 1)) - 1; - - return TRUE; -} - -static void -cwDestroyBackingGC(GCPtr pGC) -{ - cwGCPtr pPriv; - - pPriv = (cwGCPtr) getCwGC (pGC); - - if (pPriv->pBackingGC) { - FreeGC(pPriv->pBackingGC, (XID)0); - pPriv->pBackingGC = NULL; - } -} - -static void -cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable) -{ - GCPtr pBackingGC; - cwGCPtr pPriv; - DrawablePtr pBackingDrawable; - int x_off, y_off; - - pPriv = (cwGCPtr) getCwGC (pGC); - - FUNC_PROLOGUE(pGC, pPriv); - - /* - * Must call ValidateGC to ensure pGC->pCompositeClip is valid - */ - (*pGC->funcs->ValidateGC)(pGC, stateChanges, pDrawable); - - if (!cwDrawableIsRedirWindow(pDrawable)) { - cwDestroyBackingGC(pGC); - FUNC_EPILOGUE(pGC, pPriv); - return; - } else { - if (!pPriv->pBackingGC && !cwCreateBackingGC(pGC, pDrawable)) { - FUNC_EPILOGUE(pGC, pPriv); - return; - } - } - - pBackingGC = pPriv->pBackingGC; - pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off); - - pPriv->stateChanges |= stateChanges; - - /* - * Copy the composite clip into the backing GC if either - * the drawable clip list has changed or the client has changed - * the client clip data - */ - if (pDrawable->serialNumber != pPriv->serialNumber || - (pPriv->stateChanges & (GCClipXOrigin|GCClipYOrigin|GCClipMask))) - { - XID vals[2]; - RegionPtr pCompositeClip; - - pCompositeClip = REGION_CREATE (pScreen, NULL, 0); - REGION_COPY (pScreen, pCompositeClip, pGC->pCompositeClip); - - /* Either the drawable has changed, or the clip list in the drawable has - * changed. Copy the new clip list over and set the new translated - * offset for it. - */ - - (*pBackingGC->funcs->ChangeClip) (pBackingGC, CT_REGION, - (pointer) pCompositeClip, 0); - - vals[0] = x_off - pDrawable->x; - vals[1] = y_off - pDrawable->y; - dixChangeGC(NullClient, pBackingGC, - (GCClipXOrigin | GCClipYOrigin), vals, NULL); - - pPriv->serialNumber = pDrawable->serialNumber; - /* - * Mask off any client clip changes to make sure - * the clip list set above remains in effect - */ - pPriv->stateChanges &= ~(GCClipXOrigin|GCClipYOrigin|GCClipMask); - } - - if (pPriv->stateChanges) { - CopyGC(pGC, pBackingGC, pPriv->stateChanges); - pPriv->stateChanges = 0; - } - - if ((pGC->patOrg.x + x_off) != pBackingGC->patOrg.x || - (pGC->patOrg.y + y_off) != pBackingGC->patOrg.y) - { - XID vals[2]; - vals[0] = pGC->patOrg.x + x_off; - vals[1] = pGC->patOrg.y + y_off; - dixChangeGC(NullClient, pBackingGC, - (GCTileStipXOrigin | GCTileStipYOrigin), vals, NULL); - } - - ValidateGC(pBackingDrawable, pBackingGC); - - FUNC_EPILOGUE(pGC, pPriv); -} - -static void -cwChangeGC(GCPtr pGC, unsigned long mask) -{ - cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey); - - FUNC_PROLOGUE(pGC, pPriv); - - (*pGC->funcs->ChangeGC) (pGC, mask); - - FUNC_EPILOGUE(pGC, pPriv); -} - -static void -cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) -{ - cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGCDst->devPrivates, cwGCKey); - - FUNC_PROLOGUE(pGCDst, pPriv); - - (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); - - FUNC_EPILOGUE(pGCDst, pPriv); -} - -static void -cwDestroyGC(GCPtr pGC) -{ - cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey); - - FUNC_PROLOGUE(pGC, pPriv); - - cwDestroyBackingGC(pGC); - - (*pGC->funcs->DestroyGC) (pGC); - - /* leave it unwrapped */ -} - -static void -cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) -{ - cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey); - - FUNC_PROLOGUE(pGC, pPriv); - - (*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects); - - FUNC_EPILOGUE(pGC, pPriv); -} - -static void -cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc) -{ - cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pgcDst->devPrivates, cwGCKey); - - FUNC_PROLOGUE(pgcDst, pPriv); - - (*pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); - - FUNC_EPILOGUE(pgcDst, pPriv); -} - -static void -cwDestroyClip(GCPtr pGC) -{ - cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey); - - FUNC_PROLOGUE(pGC, pPriv); - - (*pGC->funcs->DestroyClip)(pGC); - - FUNC_EPILOGUE(pGC, pPriv); -} - -/* - * Screen wrappers. - */ - -#define SCREEN_PROLOGUE(pScreen, field) \ - ((pScreen)->field = getCwScreen(pScreen)->field) - -#define SCREEN_EPILOGUE(pScreen, field, wrapper) do { \ - getCwScreen(pScreen)->field = (pScreen)->field; \ - (pScreen)->field = (wrapper); \ -} while (0) - -static Bool -cwCreateGC(GCPtr pGC) -{ - cwGCPtr pPriv = getCwGC(pGC); - ScreenPtr pScreen = pGC->pScreen; - Bool ret; - - bzero(pPriv, sizeof(cwGCRec)); - SCREEN_PROLOGUE(pScreen, CreateGC); - - if ( (ret = (*pScreen->CreateGC)(pGC)) ) - FUNC_EPILOGUE(pGC, pPriv); - - SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC); - - return ret; -} - -static void -cwGetImage(DrawablePtr pSrc, int x, int y, int w, int h, unsigned int format, - unsigned long planemask, char *pdstLine) -{ - ScreenPtr pScreen = pSrc->pScreen; - DrawablePtr pBackingDrawable; - int src_off_x, src_off_y; - - SCREEN_PROLOGUE(pScreen, GetImage); - - pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y); - - CW_OFFSET_XY_SRC(x, y); - - (*pScreen->GetImage)(pBackingDrawable, x, y, w, h, format, planemask, - pdstLine); - - SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage); -} - -static void -cwGetSpans(DrawablePtr pSrc, int wMax, DDXPointPtr ppt, int *pwidth, - int nspans, char *pdstStart) -{ - ScreenPtr pScreen = pSrc->pScreen; - DrawablePtr pBackingDrawable; - int i; - int src_off_x, src_off_y; - - SCREEN_PROLOGUE(pScreen, GetSpans); - - pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y); - - for (i = 0; i < nspans; i++) - CW_OFFSET_XY_SRC(ppt[i].x, ppt[i].y); - - (*pScreen->GetSpans)(pBackingDrawable, wMax, ppt, pwidth, nspans, - pdstStart); - - SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans); -} - - -static void -cwCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - SCREEN_PROLOGUE(pScreen, CopyWindow); - - if (!cwDrawableIsRedirWindow((DrawablePtr)pWin)) { - (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); - } else { - GCPtr pGC; - BoxPtr pExtents; - int x_off, y_off; - int dx, dy; - PixmapPtr pBackingPixmap; - RegionPtr pClip; - int src_x, src_y, dst_x, dst_y, w, h; - - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - - pExtents = REGION_EXTENTS(pScreen, prgnSrc); - - pBackingPixmap = (PixmapPtr) cwGetBackingDrawable((DrawablePtr)pWin, - &x_off, &y_off); - - src_x = pExtents->x1 - pBackingPixmap->screen_x; - src_y = pExtents->y1 - pBackingPixmap->screen_y; - w = pExtents->x2 - pExtents->x1; - h = pExtents->y2 - pExtents->y1; - dst_x = src_x - dx; - dst_y = src_y - dy; - - /* Translate region (as required by API) */ - REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); - - pGC = GetScratchGC(pBackingPixmap->drawable.depth, pScreen); - /* - * Copy region to GC as clip, aligning as dest clip - */ - pClip = REGION_CREATE (pScreen, NULL, 0); - REGION_INTERSECT(pScreen, pClip, &pWin->borderClip, prgnSrc); - REGION_TRANSLATE(pScreen, pClip, - -pBackingPixmap->screen_x, - -pBackingPixmap->screen_y); - - (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pClip, 0); - - ValidateGC(&pBackingPixmap->drawable, pGC); - - (*pGC->ops->CopyArea) (&pBackingPixmap->drawable, - &pBackingPixmap->drawable, pGC, - src_x, src_y, w, h, dst_x, dst_y); - - (*pGC->funcs->DestroyClip) (pGC); - - FreeScratchGC(pGC); - } - - SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow); -} - -static PixmapPtr -cwGetWindowPixmap (WindowPtr pWin) -{ - PixmapPtr pPixmap = getCwPixmap (pWin); - - if (!pPixmap) - { - ScreenPtr pScreen = pWin->drawable.pScreen; - SCREEN_PROLOGUE(pScreen, GetWindowPixmap); - if (pScreen->GetWindowPixmap) - pPixmap = (*pScreen->GetWindowPixmap) (pWin); - SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap); - } - return pPixmap; -} - -static void -cwSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - - if (pPixmap == (*pScreen->GetScreenPixmap) (pScreen)) - pPixmap = NULL; - setCwPixmap (pWindow, pPixmap); -} - -/* Screen initialization/teardown */ -void -miInitializeCompositeWrapper(ScreenPtr pScreen) -{ - cwScreenPtr pScreenPriv; - Bool has_render = GetPictureScreenIfSet(pScreen) != NULL; - - if (!dixRequestPrivate(cwGCKey, sizeof(cwGCRec))) - return; - - pScreenPriv = xalloc(sizeof(cwScreenRec)); - if (!pScreenPriv) - return; - - dixSetPrivate(&pScreen->devPrivates, cwScreenKey, pScreenPriv); - - SCREEN_EPILOGUE(pScreen, CloseScreen, cwCloseScreen); - SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage); - SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans); - SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC); - SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow); - - SCREEN_EPILOGUE(pScreen, SetWindowPixmap, cwSetWindowPixmap); - SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap); - - if (has_render) - cwInitializeRender(pScreen); -} - -static Bool -cwCloseScreen (int i, ScreenPtr pScreen) -{ - cwScreenPtr pScreenPriv; - PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); - - pScreenPriv = (cwScreenPtr)dixLookupPrivate(&pScreen->devPrivates, - cwScreenKey); - pScreen->CloseScreen = pScreenPriv->CloseScreen; - pScreen->GetImage = pScreenPriv->GetImage; - pScreen->GetSpans = pScreenPriv->GetSpans; - pScreen->CreateGC = pScreenPriv->CreateGC; - pScreen->CopyWindow = pScreenPriv->CopyWindow; - - if (ps) - cwFiniRender(pScreen); - - xfree((pointer)pScreenPriv); - - return (*pScreen->CloseScreen)(i, pScreen); -} +/* + * Copyright © 2004 Eric Anholt + * + * 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 Eric Anholt not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Eric Anholt makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ERIC ANHOLT 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 <dix-config.h> +#endif + +#include <string.h> + +#include "gcstruct.h" +#include "windowstr.h" +#include "cw.h" + +#define CW_DEBUG 1 + +#if CW_DEBUG +#define CW_ASSERT(x) do { \ + if (!(x)) { \ + ErrorF("composite wrapper: assertion failed at %s:%d\n", __FUNC__, \ + __LINE__); \ + } \ +} while (0) +#else +#define CW_ASSERT(x) do {} while (0) +#endif + +static int cwGCKeyIndex; +DevPrivateKey cwGCKey = &cwGCKeyIndex; +static int cwScreenKeyIndex; +DevPrivateKey cwScreenKey = &cwScreenKeyIndex; +static int cwWindowKeyIndex; +DevPrivateKey cwWindowKey = &cwWindowKeyIndex; +static int cwPictureKeyIndex; +DevPrivateKey cwPictureKey = &cwPictureKeyIndex; +extern GCOps cwGCOps; + +static Bool +cwCloseScreen (int i, ScreenPtr pScreen); + +static void +cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable); +static void +cwChangeGC(GCPtr pGC, unsigned long mask); +static void +cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void +cwDestroyGC(GCPtr pGC); +static void +cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects); +static void +cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc); +static void +cwDestroyClip(GCPtr pGC); + +GCFuncs cwGCFuncs = { + cwValidateGC, + cwChangeGC, + cwCopyGC, + cwDestroyGC, + cwChangeClip, + cwDestroyClip, + cwCopyClip, +}; + +/* Find the real drawable to draw to, and provide offsets that will translate + * window coordinates to backing pixmap coordinates. + */ +DrawablePtr +cwGetBackingDrawable(DrawablePtr pDrawable, int *x_off, int *y_off) +{ + PixmapPtr pPixmap; + + if (pDrawable->type == DRAWABLE_WINDOW && + (pPixmap = getCwPixmap ((WindowPtr) pDrawable))) + { + *x_off = pDrawable->x - pPixmap->screen_x; + *y_off = pDrawable->y - pPixmap->screen_y; + return &pPixmap->drawable; + } else { + *x_off = *y_off = 0; + return pDrawable; + } +} + +#define FUNC_PROLOGUE(pGC, pPriv) do { \ + (pGC)->funcs = (pPriv)->wrapFuncs; \ + (pGC)->ops = (pPriv)->wrapOps; \ +} while (0) + +#define FUNC_EPILOGUE(pGC, pPriv) do { \ + (pPriv)->wrapFuncs = (pGC)->funcs; \ + (pPriv)->wrapOps = (pGC)->ops; \ + (pGC)->funcs = &cwGCFuncs; \ + (pGC)->ops = &cwGCOps; \ +} while (0) + + +static Bool +cwCreateBackingGC(GCPtr pGC, DrawablePtr pDrawable) +{ + cwGCRec *pPriv = getCwGC(pGC); + int status, x_off, y_off; + XID noexpose = xFalse; + DrawablePtr pBackingDrawable; + + pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off); + pPriv->pBackingGC = CreateGC(pBackingDrawable, GCGraphicsExposures, + &noexpose, &status, (XID)0, serverClient); + if (status != Success) + return FALSE; + + pPriv->serialNumber = 0; + pPriv->stateChanges = GCAllBits; + + return TRUE; +} + +static void +cwDestroyBackingGC(GCPtr pGC) +{ + cwGCPtr pPriv; + + pPriv = (cwGCPtr) getCwGC (pGC); + + if (pPriv->pBackingGC) { + FreeGC(pPriv->pBackingGC, (XID)0); + pPriv->pBackingGC = NULL; + } +} + +static void +cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable) +{ + GCPtr pBackingGC; + cwGCPtr pPriv; + DrawablePtr pBackingDrawable; + int x_off, y_off; + + pPriv = (cwGCPtr) getCwGC (pGC); + + FUNC_PROLOGUE(pGC, pPriv); + + /* + * Must call ValidateGC to ensure pGC->pCompositeClip is valid + */ + (*pGC->funcs->ValidateGC)(pGC, stateChanges, pDrawable); + + if (!cwDrawableIsRedirWindow(pDrawable)) { + cwDestroyBackingGC(pGC); + FUNC_EPILOGUE(pGC, pPriv); + return; + } else { + if (!pPriv->pBackingGC && !cwCreateBackingGC(pGC, pDrawable)) { + FUNC_EPILOGUE(pGC, pPriv); + return; + } + } + + pBackingGC = pPriv->pBackingGC; + pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off); + + pPriv->stateChanges |= stateChanges; + + /* + * Copy the composite clip into the backing GC if either + * the drawable clip list has changed or the client has changed + * the client clip data + */ + if (pDrawable->serialNumber != pPriv->serialNumber || + (pPriv->stateChanges & (GCClipXOrigin|GCClipYOrigin|GCClipMask))) + { + ChangeGCVal vals[2]; + RegionPtr pCompositeClip; + + pCompositeClip = REGION_CREATE (pScreen, NULL, 0); + REGION_COPY (pScreen, pCompositeClip, pGC->pCompositeClip); + + /* Either the drawable has changed, or the clip list in the drawable has + * changed. Copy the new clip list over and set the new translated + * offset for it. + */ + + (*pBackingGC->funcs->ChangeClip) (pBackingGC, CT_REGION, + (pointer) pCompositeClip, 0); + + vals[0].val = x_off - pDrawable->x; + vals[1].val = y_off - pDrawable->y; + ChangeGC(NullClient, pBackingGC, + (GCClipXOrigin | GCClipYOrigin), vals); + + pPriv->serialNumber = pDrawable->serialNumber; + /* + * Mask off any client clip changes to make sure + * the clip list set above remains in effect + */ + pPriv->stateChanges &= ~(GCClipXOrigin|GCClipYOrigin|GCClipMask); + } + + if (pPriv->stateChanges) { + CopyGC(pGC, pBackingGC, pPriv->stateChanges); + pPriv->stateChanges = 0; + } + + if ((pGC->patOrg.x + x_off) != pBackingGC->patOrg.x || + (pGC->patOrg.y + y_off) != pBackingGC->patOrg.y) + { + ChangeGCVal vals[2]; + vals[0].val = pGC->patOrg.x + x_off; + vals[1].val = pGC->patOrg.y + y_off; + ChangeGC(NullClient, pBackingGC, + (GCTileStipXOrigin | GCTileStipYOrigin), vals); + } + + ValidateGC(pBackingDrawable, pBackingGC); + + FUNC_EPILOGUE(pGC, pPriv); +} + +static void +cwChangeGC(GCPtr pGC, unsigned long mask) +{ + cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey); + + FUNC_PROLOGUE(pGC, pPriv); + + (*pGC->funcs->ChangeGC) (pGC, mask); + + FUNC_EPILOGUE(pGC, pPriv); +} + +static void +cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) +{ + cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGCDst->devPrivates, cwGCKey); + + FUNC_PROLOGUE(pGCDst, pPriv); + + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + + FUNC_EPILOGUE(pGCDst, pPriv); +} + +static void +cwDestroyGC(GCPtr pGC) +{ + cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey); + + FUNC_PROLOGUE(pGC, pPriv); + + cwDestroyBackingGC(pGC); + + (*pGC->funcs->DestroyGC) (pGC); + + /* leave it unwrapped */ +} + +static void +cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) +{ + cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey); + + FUNC_PROLOGUE(pGC, pPriv); + + (*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects); + + FUNC_EPILOGUE(pGC, pPriv); +} + +static void +cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pgcDst->devPrivates, cwGCKey); + + FUNC_PROLOGUE(pgcDst, pPriv); + + (*pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + + FUNC_EPILOGUE(pgcDst, pPriv); +} + +static void +cwDestroyClip(GCPtr pGC) +{ + cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey); + + FUNC_PROLOGUE(pGC, pPriv); + + (*pGC->funcs->DestroyClip)(pGC); + + FUNC_EPILOGUE(pGC, pPriv); +} + +/* + * Screen wrappers. + */ + +#define SCREEN_PROLOGUE(pScreen, field) \ + ((pScreen)->field = getCwScreen(pScreen)->field) + +#define SCREEN_EPILOGUE(pScreen, field, wrapper) do { \ + getCwScreen(pScreen)->field = (pScreen)->field; \ + (pScreen)->field = (wrapper); \ +} while (0) + +static Bool +cwCreateGC(GCPtr pGC) +{ + cwGCPtr pPriv = getCwGC(pGC); + ScreenPtr pScreen = pGC->pScreen; + Bool ret; + + bzero(pPriv, sizeof(cwGCRec)); + SCREEN_PROLOGUE(pScreen, CreateGC); + + if ( (ret = (*pScreen->CreateGC)(pGC)) ) + FUNC_EPILOGUE(pGC, pPriv); + + SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC); + + return ret; +} + +static void +cwGetImage(DrawablePtr pSrc, int x, int y, int w, int h, unsigned int format, + unsigned long planemask, char *pdstLine) +{ + ScreenPtr pScreen = pSrc->pScreen; + DrawablePtr pBackingDrawable; + int src_off_x, src_off_y; + + SCREEN_PROLOGUE(pScreen, GetImage); + + pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y); + + CW_OFFSET_XY_SRC(x, y); + + (*pScreen->GetImage)(pBackingDrawable, x, y, w, h, format, planemask, + pdstLine); + + SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage); +} + +static void +cwGetSpans(DrawablePtr pSrc, int wMax, DDXPointPtr ppt, int *pwidth, + int nspans, char *pdstStart) +{ + ScreenPtr pScreen = pSrc->pScreen; + DrawablePtr pBackingDrawable; + int i; + int src_off_x, src_off_y; + + SCREEN_PROLOGUE(pScreen, GetSpans); + + pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y); + + for (i = 0; i < nspans; i++) + CW_OFFSET_XY_SRC(ppt[i].x, ppt[i].y); + + (*pScreen->GetSpans)(pBackingDrawable, wMax, ppt, pwidth, nspans, + pdstStart); + + SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans); +} + + +static void +cwCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE(pScreen, CopyWindow); + + if (!cwDrawableIsRedirWindow((DrawablePtr)pWin)) { + (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); + } else { + GCPtr pGC; + BoxPtr pExtents; + int x_off, y_off; + int dx, dy; + PixmapPtr pBackingPixmap; + RegionPtr pClip; + int src_x, src_y, dst_x, dst_y, w, h; + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + + pExtents = REGION_EXTENTS(pScreen, prgnSrc); + + pBackingPixmap = (PixmapPtr) cwGetBackingDrawable((DrawablePtr)pWin, + &x_off, &y_off); + + src_x = pExtents->x1 - pBackingPixmap->screen_x; + src_y = pExtents->y1 - pBackingPixmap->screen_y; + w = pExtents->x2 - pExtents->x1; + h = pExtents->y2 - pExtents->y1; + dst_x = src_x - dx; + dst_y = src_y - dy; + + /* Translate region (as required by API) */ + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + + pGC = GetScratchGC(pBackingPixmap->drawable.depth, pScreen); + /* + * Copy region to GC as clip, aligning as dest clip + */ + pClip = REGION_CREATE (pScreen, NULL, 0); + REGION_INTERSECT(pScreen, pClip, &pWin->borderClip, prgnSrc); + REGION_TRANSLATE(pScreen, pClip, + -pBackingPixmap->screen_x, + -pBackingPixmap->screen_y); + + (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pClip, 0); + + ValidateGC(&pBackingPixmap->drawable, pGC); + + (*pGC->ops->CopyArea) (&pBackingPixmap->drawable, + &pBackingPixmap->drawable, pGC, + src_x, src_y, w, h, dst_x, dst_y); + + (*pGC->funcs->DestroyClip) (pGC); + + FreeScratchGC(pGC); + } + + SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow); +} + +static PixmapPtr +cwGetWindowPixmap (WindowPtr pWin) +{ + PixmapPtr pPixmap = getCwPixmap (pWin); + + if (!pPixmap) + { + ScreenPtr pScreen = pWin->drawable.pScreen; + SCREEN_PROLOGUE(pScreen, GetWindowPixmap); + if (pScreen->GetWindowPixmap) + pPixmap = (*pScreen->GetWindowPixmap) (pWin); + SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap); + } + return pPixmap; +} + +static void +cwSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + + if (pPixmap == (*pScreen->GetScreenPixmap) (pScreen)) + pPixmap = NULL; + setCwPixmap (pWindow, pPixmap); +} + +/* Screen initialization/teardown */ +void +miInitializeCompositeWrapper(ScreenPtr pScreen) +{ + cwScreenPtr pScreenPriv; + Bool has_render = GetPictureScreenIfSet(pScreen) != NULL; + + if (!dixRequestPrivate(cwGCKey, sizeof(cwGCRec))) + return; + + pScreenPriv = malloc(sizeof(cwScreenRec)); + if (!pScreenPriv) + return; + + dixSetPrivate(&pScreen->devPrivates, cwScreenKey, pScreenPriv); + + SCREEN_EPILOGUE(pScreen, CloseScreen, cwCloseScreen); + SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage); + SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans); + SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC); + SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow); + + SCREEN_EPILOGUE(pScreen, SetWindowPixmap, cwSetWindowPixmap); + SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap); + + if (has_render) + cwInitializeRender(pScreen); +} + +static Bool +cwCloseScreen (int i, ScreenPtr pScreen) +{ + cwScreenPtr pScreenPriv; + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + + pScreenPriv = (cwScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + cwScreenKey); + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->GetImage = pScreenPriv->GetImage; + pScreen->GetSpans = pScreenPriv->GetSpans; + pScreen->CreateGC = pScreenPriv->CreateGC; + pScreen->CopyWindow = pScreenPriv->CopyWindow; + + if (ps) + cwFiniRender(pScreen); + + free((pointer)pScreenPriv); + + return (*pScreen->CloseScreen)(i, pScreen); +} diff --git a/xorg-server/miext/cw/cw_render.c b/xorg-server/miext/cw/cw_render.c index dfe2681e0..260509ce0 100644 --- a/xorg-server/miext/cw/cw_render.c +++ b/xorg-server/miext/cw/cw_render.c @@ -1,469 +1,469 @@ -/* - * Copyright © 2004 Eric Anholt - * - * 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 Eric Anholt not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Eric Anholt makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL ERIC ANHOLT 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 <dix-config.h> -#endif - -#include <string.h> - -#include "gcstruct.h" -#include "windowstr.h" -#include "cw.h" - -#define cwPsDecl(pScreen) \ - PictureScreenPtr ps = GetPictureScreen (pScreen); \ - cwScreenPtr pCwScreen = getCwScreen (pScreen) - -#define cwPicturePrivate \ - cwPicturePtr pPicturePrivate = getCwPicture(pPicture) - -#define cwSrcPictureDecl \ - int src_picture_x_off, src_picture_y_off; \ - PicturePtr pBackingSrcPicture = cwGetBackingPicture(pSrcPicture, \ - &src_picture_x_off,\ - &src_picture_y_off) - -#define cwDstPictureDecl \ - int dst_picture_x_off, dst_picture_y_off; \ - PicturePtr pBackingDstPicture = cwGetBackingPicture(pDstPicture, \ - &dst_picture_x_off,\ - &dst_picture_y_off) - -#define cwMskPictureDecl \ - int msk_picture_x_off = 0, msk_picture_y_off = 0; \ - PicturePtr pBackingMskPicture = (!pMskPicture ? 0 : \ - cwGetBackingPicture(pMskPicture, \ - &msk_picture_x_off,\ - &msk_picture_y_off)) - -#define cwPsUnwrap(elt) { \ - ps->elt = pCwScreen->elt; \ -} - -#define cwPsWrap(elt,func) { \ - pCwScreen->elt = ps->elt; \ - ps->elt = func; \ -} - -static cwPicturePtr -cwCreatePicturePrivate (PicturePtr pPicture) -{ - WindowPtr pWindow = (WindowPtr) pPicture->pDrawable; - PixmapPtr pPixmap = getCwPixmap (pWindow); - int error; - cwPicturePtr pPicturePrivate; - - pPicturePrivate = xalloc (sizeof (cwPictureRec)); - if (!pPicturePrivate) - return NULL; - - pPicturePrivate->pBackingPicture = CreatePicture (0, &pPixmap->drawable, - pPicture->pFormat, - 0, 0, serverClient, - &error); - if (!pPicturePrivate->pBackingPicture) - { - xfree (pPicturePrivate); - return NULL; - } - - /* - * Ensure that this serial number does not match the window's - */ - pPicturePrivate->serialNumber = pPixmap->drawable.serialNumber; - pPicturePrivate->stateChanges = (1 << (CPLastBit + 1)) - 1; - - setCwPicture(pPicture, pPicturePrivate); - - return pPicturePrivate; -} - -static void -cwDestroyPicturePrivate (PicturePtr pPicture) -{ - cwPicturePrivate; - - if (pPicturePrivate) - { - if (pPicturePrivate->pBackingPicture) - FreePicture (pPicturePrivate->pBackingPicture, 0); - xfree (pPicturePrivate); - setCwPicture(pPicture, NULL); - } -} - -static PicturePtr -cwGetBackingPicture (PicturePtr pPicture, int *x_off, int *y_off) -{ - cwPicturePrivate; - - if (pPicturePrivate) - { - DrawablePtr pDrawable = pPicture->pDrawable; - WindowPtr pWindow = (WindowPtr) pDrawable; - PixmapPtr pPixmap = getCwPixmap (pWindow); - - *x_off = pDrawable->x - pPixmap->screen_x; - *y_off = pDrawable->y - pPixmap->screen_y; - - return pPicturePrivate->pBackingPicture; - } - else - { - *x_off = *y_off = 0; - return pPicture; - } -} - -static void -cwDestroyPicture (PicturePtr pPicture) -{ - ScreenPtr pScreen = pPicture->pDrawable->pScreen; - cwPsDecl(pScreen); - - cwPsUnwrap(DestroyPicture); - cwDestroyPicturePrivate (pPicture); - (*ps->DestroyPicture) (pPicture); - cwPsWrap(DestroyPicture, cwDestroyPicture); -} - -static void -cwChangePicture (PicturePtr pPicture, Mask mask) -{ - ScreenPtr pScreen = pPicture->pDrawable->pScreen; - cwPsDecl(pScreen); - cwPicturePtr pPicturePrivate = getCwPicture(pPicture); - - cwPsUnwrap(ChangePicture); - (*ps->ChangePicture) (pPicture, mask); - if (pPicturePrivate) - pPicturePrivate->stateChanges |= mask; - cwPsWrap(ChangePicture, cwChangePicture); -} - - -static void -cwValidatePicture (PicturePtr pPicture, - Mask mask) -{ - DrawablePtr pDrawable = pPicture->pDrawable; - ScreenPtr pScreen = pDrawable->pScreen; - cwPsDecl(pScreen); - cwPicturePrivate; - - cwPsUnwrap(ValidatePicture); - - /* - * Must call ValidatePicture to ensure pPicture->pCompositeClip is valid - */ - (*ps->ValidatePicture) (pPicture, mask); - - if (!cwDrawableIsRedirWindow (pDrawable)) - { - if (pPicturePrivate) - cwDestroyPicturePrivate (pPicture); - } - else - { - PicturePtr pBackingPicture; - DrawablePtr pBackingDrawable; - int x_off, y_off; - - pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off); - - if (pPicturePrivate && - pPicturePrivate->pBackingPicture->pDrawable != pBackingDrawable) - { - cwDestroyPicturePrivate (pPicture); - pPicturePrivate = 0; - } - - if (!pPicturePrivate) - { - pPicturePrivate = cwCreatePicturePrivate (pPicture); - if (!pPicturePrivate) - { - cwPsWrap(ValidatePicture, cwValidatePicture); - return; - } - } - - pBackingPicture = pPicturePrivate->pBackingPicture; - - /* - * Always copy transform and filters because there's no - * indication of when they've changed - */ - SetPictureTransform(pBackingPicture, pPicture->transform); - - if (pBackingPicture->filter != pPicture->filter || - pPicture->filter_nparams > 0) - { - char *filter = PictureGetFilterName (pPicture->filter); - - SetPictureFilter(pBackingPicture, - filter, strlen (filter), - pPicture->filter_params, - pPicture->filter_nparams); - } - - pPicturePrivate->stateChanges |= mask; - - if (pPicturePrivate->serialNumber != pDrawable->serialNumber || - (pPicturePrivate->stateChanges & (CPClipXOrigin|CPClipYOrigin|CPClipMask))) - { - SetPictureClipRegion (pBackingPicture, - x_off - pDrawable->x, - y_off - pDrawable->y, - pPicture->pCompositeClip); - - pPicturePrivate->serialNumber = pDrawable->serialNumber; - pPicturePrivate->stateChanges &= ~(CPClipXOrigin | CPClipYOrigin | CPClipMask); - } - - CopyPicture(pPicture, pPicturePrivate->stateChanges, pBackingPicture); - - ValidatePicture (pBackingPicture); - } - cwPsWrap(ValidatePicture, cwValidatePicture); -} - -static void -cwComposite (CARD8 op, - PicturePtr pSrcPicture, - PicturePtr pMskPicture, - PicturePtr pDstPicture, - INT16 xSrc, - INT16 ySrc, - INT16 xMsk, - INT16 yMsk, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; - cwPsDecl(pScreen); - cwSrcPictureDecl; - cwMskPictureDecl; - cwDstPictureDecl; - - cwPsUnwrap(Composite); - (*ps->Composite) (op, pBackingSrcPicture, pBackingMskPicture, pBackingDstPicture, - xSrc + src_picture_x_off, ySrc + src_picture_y_off, - xMsk + msk_picture_x_off, yMsk + msk_picture_y_off, - xDst + dst_picture_x_off, yDst + dst_picture_y_off, - width, height); - cwPsWrap(Composite, cwComposite); -} - -static void -cwCompositeRects (CARD8 op, - PicturePtr pDstPicture, - xRenderColor *color, - int nRect, - xRectangle *rects) -{ - ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; - cwPsDecl(pScreen); - cwDstPictureDecl; - int i; - - cwPsUnwrap(CompositeRects); - for (i = 0; i < nRect; i++) - { - rects[i].x += dst_picture_x_off; - rects[i].y += dst_picture_y_off; - } - (*ps->CompositeRects) (op, pBackingDstPicture, color, nRect, rects); - cwPsWrap(CompositeRects, cwCompositeRects); -} - -static void -cwTrapezoids (CARD8 op, - PicturePtr pSrcPicture, - PicturePtr pDstPicture, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int ntrap, - xTrapezoid *traps) -{ - ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; - cwPsDecl(pScreen); - cwSrcPictureDecl; - cwDstPictureDecl; - int i; - - cwPsUnwrap(Trapezoids); - if (dst_picture_x_off || dst_picture_y_off) { - for (i = 0; i < ntrap; i++) - { - traps[i].top += dst_picture_y_off << 16; - traps[i].bottom += dst_picture_y_off << 16; - traps[i].left.p1.x += dst_picture_x_off << 16; - traps[i].left.p1.y += dst_picture_y_off << 16; - traps[i].left.p2.x += dst_picture_x_off << 16; - traps[i].left.p2.y += dst_picture_y_off << 16; - traps[i].right.p1.x += dst_picture_x_off << 16; - traps[i].right.p1.y += dst_picture_y_off << 16; - traps[i].right.p2.x += dst_picture_x_off << 16; - traps[i].right.p2.y += dst_picture_y_off << 16; - } - } - (*ps->Trapezoids) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat, - xSrc + src_picture_x_off, ySrc + src_picture_y_off, - ntrap, traps); - cwPsWrap(Trapezoids, cwTrapezoids); -} - -static void -cwTriangles (CARD8 op, - PicturePtr pSrcPicture, - PicturePtr pDstPicture, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int ntri, - xTriangle *tris) -{ - ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; - cwPsDecl(pScreen); - cwSrcPictureDecl; - cwDstPictureDecl; - int i; - - cwPsUnwrap(Triangles); - if (dst_picture_x_off || dst_picture_y_off) { - for (i = 0; i < ntri; i++) - { - tris[i].p1.x += dst_picture_x_off << 16; - tris[i].p1.y += dst_picture_y_off << 16; - tris[i].p2.x += dst_picture_x_off << 16; - tris[i].p2.y += dst_picture_y_off << 16; - tris[i].p3.x += dst_picture_x_off << 16; - tris[i].p3.y += dst_picture_y_off << 16; - } - } - (*ps->Triangles) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat, - xSrc + src_picture_x_off, ySrc + src_picture_y_off, - ntri, tris); - cwPsWrap(Triangles, cwTriangles); -} - -static void -cwTriStrip (CARD8 op, - PicturePtr pSrcPicture, - PicturePtr pDstPicture, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int npoint, - xPointFixed *points) -{ - ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; - cwPsDecl(pScreen); - cwSrcPictureDecl; - cwDstPictureDecl; - int i; - - cwPsUnwrap(TriStrip); - if (dst_picture_x_off || dst_picture_y_off) { - for (i = 0; i < npoint; i++) - { - points[i].x += dst_picture_x_off << 16; - points[i].y += dst_picture_y_off << 16; - } - } - (*ps->TriStrip) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat, - xSrc + src_picture_x_off, ySrc + src_picture_y_off, - npoint, points); - cwPsWrap(TriStrip, cwTriStrip); -} - -static void -cwTriFan (CARD8 op, - PicturePtr pSrcPicture, - PicturePtr pDstPicture, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int npoint, - xPointFixed *points) -{ - ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; - cwPsDecl(pScreen); - cwSrcPictureDecl; - cwDstPictureDecl; - int i; - - cwPsUnwrap(TriFan); - if (dst_picture_x_off || dst_picture_y_off) { - for (i = 0; i < npoint; i++) - { - points[i].x += dst_picture_x_off << 16; - points[i].y += dst_picture_y_off << 16; - } - } - (*ps->TriFan) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat, - xSrc + src_picture_x_off, ySrc + src_picture_y_off, - npoint, points); - cwPsWrap(TriFan, cwTriFan); -} - -void -cwInitializeRender (ScreenPtr pScreen) -{ - cwPsDecl (pScreen); - - cwPsWrap(DestroyPicture, cwDestroyPicture); - cwPsWrap(ChangePicture, cwChangePicture); - cwPsWrap(ValidatePicture, cwValidatePicture); - cwPsWrap(Composite, cwComposite); - cwPsWrap(CompositeRects, cwCompositeRects); - cwPsWrap(Trapezoids, cwTrapezoids); - cwPsWrap(Triangles, cwTriangles); - cwPsWrap(TriStrip, cwTriStrip); - cwPsWrap(TriFan, cwTriFan); - /* There is no need to wrap AddTraps as far as we can tell. AddTraps can - * only be done on alpha-only pictures, and we won't be getting - * alpha-only window pictures, so there's no need to translate. - */ -} - -void -cwFiniRender (ScreenPtr pScreen) -{ - cwPsDecl (pScreen); - - cwPsUnwrap(DestroyPicture); - cwPsUnwrap(ChangePicture); - cwPsUnwrap(ValidatePicture); - cwPsUnwrap(Composite); - cwPsUnwrap(CompositeRects); - cwPsUnwrap(Trapezoids); - cwPsUnwrap(Triangles); - cwPsUnwrap(TriStrip); - cwPsUnwrap(TriFan); -} - +/* + * Copyright © 2004 Eric Anholt + * + * 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 Eric Anholt not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Eric Anholt makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ERIC ANHOLT 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 <dix-config.h> +#endif + +#include <string.h> + +#include "gcstruct.h" +#include "windowstr.h" +#include "cw.h" + +#define cwPsDecl(pScreen) \ + PictureScreenPtr ps = GetPictureScreen (pScreen); \ + cwScreenPtr pCwScreen = getCwScreen (pScreen) + +#define cwPicturePrivate \ + cwPicturePtr pPicturePrivate = getCwPicture(pPicture) + +#define cwSrcPictureDecl \ + int src_picture_x_off, src_picture_y_off; \ + PicturePtr pBackingSrcPicture = cwGetBackingPicture(pSrcPicture, \ + &src_picture_x_off,\ + &src_picture_y_off) + +#define cwDstPictureDecl \ + int dst_picture_x_off, dst_picture_y_off; \ + PicturePtr pBackingDstPicture = cwGetBackingPicture(pDstPicture, \ + &dst_picture_x_off,\ + &dst_picture_y_off) + +#define cwMskPictureDecl \ + int msk_picture_x_off = 0, msk_picture_y_off = 0; \ + PicturePtr pBackingMskPicture = (!pMskPicture ? 0 : \ + cwGetBackingPicture(pMskPicture, \ + &msk_picture_x_off,\ + &msk_picture_y_off)) + +#define cwPsUnwrap(elt) { \ + ps->elt = pCwScreen->elt; \ +} + +#define cwPsWrap(elt,func) { \ + pCwScreen->elt = ps->elt; \ + ps->elt = func; \ +} + +static cwPicturePtr +cwCreatePicturePrivate (PicturePtr pPicture) +{ + WindowPtr pWindow = (WindowPtr) pPicture->pDrawable; + PixmapPtr pPixmap = getCwPixmap (pWindow); + int error; + cwPicturePtr pPicturePrivate; + + pPicturePrivate = malloc(sizeof (cwPictureRec)); + if (!pPicturePrivate) + return NULL; + + pPicturePrivate->pBackingPicture = CreatePicture (0, &pPixmap->drawable, + pPicture->pFormat, + 0, 0, serverClient, + &error); + if (!pPicturePrivate->pBackingPicture) + { + free(pPicturePrivate); + return NULL; + } + + /* + * Ensure that this serial number does not match the window's + */ + pPicturePrivate->serialNumber = pPixmap->drawable.serialNumber; + pPicturePrivate->stateChanges = (1 << (CPLastBit + 1)) - 1; + + setCwPicture(pPicture, pPicturePrivate); + + return pPicturePrivate; +} + +static void +cwDestroyPicturePrivate (PicturePtr pPicture) +{ + cwPicturePrivate; + + if (pPicturePrivate) + { + if (pPicturePrivate->pBackingPicture) + FreePicture (pPicturePrivate->pBackingPicture, 0); + free(pPicturePrivate); + setCwPicture(pPicture, NULL); + } +} + +static PicturePtr +cwGetBackingPicture (PicturePtr pPicture, int *x_off, int *y_off) +{ + cwPicturePrivate; + + if (pPicturePrivate) + { + DrawablePtr pDrawable = pPicture->pDrawable; + WindowPtr pWindow = (WindowPtr) pDrawable; + PixmapPtr pPixmap = getCwPixmap (pWindow); + + *x_off = pDrawable->x - pPixmap->screen_x; + *y_off = pDrawable->y - pPixmap->screen_y; + + return pPicturePrivate->pBackingPicture; + } + else + { + *x_off = *y_off = 0; + return pPicture; + } +} + +static void +cwDestroyPicture (PicturePtr pPicture) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + cwPsDecl(pScreen); + + cwPsUnwrap(DestroyPicture); + cwDestroyPicturePrivate (pPicture); + (*ps->DestroyPicture) (pPicture); + cwPsWrap(DestroyPicture, cwDestroyPicture); +} + +static void +cwChangePicture (PicturePtr pPicture, Mask mask) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + cwPsDecl(pScreen); + cwPicturePtr pPicturePrivate = getCwPicture(pPicture); + + cwPsUnwrap(ChangePicture); + (*ps->ChangePicture) (pPicture, mask); + if (pPicturePrivate) + pPicturePrivate->stateChanges |= mask; + cwPsWrap(ChangePicture, cwChangePicture); +} + + +static void +cwValidatePicture (PicturePtr pPicture, + Mask mask) +{ + DrawablePtr pDrawable = pPicture->pDrawable; + ScreenPtr pScreen = pDrawable->pScreen; + cwPsDecl(pScreen); + cwPicturePrivate; + + cwPsUnwrap(ValidatePicture); + + /* + * Must call ValidatePicture to ensure pPicture->pCompositeClip is valid + */ + (*ps->ValidatePicture) (pPicture, mask); + + if (!cwDrawableIsRedirWindow (pDrawable)) + { + if (pPicturePrivate) + cwDestroyPicturePrivate (pPicture); + } + else + { + PicturePtr pBackingPicture; + DrawablePtr pBackingDrawable; + int x_off, y_off; + + pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off); + + if (pPicturePrivate && + pPicturePrivate->pBackingPicture->pDrawable != pBackingDrawable) + { + cwDestroyPicturePrivate (pPicture); + pPicturePrivate = 0; + } + + if (!pPicturePrivate) + { + pPicturePrivate = cwCreatePicturePrivate (pPicture); + if (!pPicturePrivate) + { + cwPsWrap(ValidatePicture, cwValidatePicture); + return; + } + } + + pBackingPicture = pPicturePrivate->pBackingPicture; + + /* + * Always copy transform and filters because there's no + * indication of when they've changed + */ + SetPictureTransform(pBackingPicture, pPicture->transform); + + if (pBackingPicture->filter != pPicture->filter || + pPicture->filter_nparams > 0) + { + char *filter = PictureGetFilterName (pPicture->filter); + + SetPictureFilter(pBackingPicture, + filter, strlen (filter), + pPicture->filter_params, + pPicture->filter_nparams); + } + + pPicturePrivate->stateChanges |= mask; + + if (pPicturePrivate->serialNumber != pDrawable->serialNumber || + (pPicturePrivate->stateChanges & (CPClipXOrigin|CPClipYOrigin|CPClipMask))) + { + SetPictureClipRegion (pBackingPicture, + x_off - pDrawable->x, + y_off - pDrawable->y, + pPicture->pCompositeClip); + + pPicturePrivate->serialNumber = pDrawable->serialNumber; + pPicturePrivate->stateChanges &= ~(CPClipXOrigin | CPClipYOrigin | CPClipMask); + } + + CopyPicture(pPicture, pPicturePrivate->stateChanges, pBackingPicture); + + ValidatePicture (pBackingPicture); + } + cwPsWrap(ValidatePicture, cwValidatePicture); +} + +static void +cwComposite (CARD8 op, + PicturePtr pSrcPicture, + PicturePtr pMskPicture, + PicturePtr pDstPicture, + INT16 xSrc, + INT16 ySrc, + INT16 xMsk, + INT16 yMsk, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; + cwPsDecl(pScreen); + cwSrcPictureDecl; + cwMskPictureDecl; + cwDstPictureDecl; + + cwPsUnwrap(Composite); + (*ps->Composite) (op, pBackingSrcPicture, pBackingMskPicture, pBackingDstPicture, + xSrc + src_picture_x_off, ySrc + src_picture_y_off, + xMsk + msk_picture_x_off, yMsk + msk_picture_y_off, + xDst + dst_picture_x_off, yDst + dst_picture_y_off, + width, height); + cwPsWrap(Composite, cwComposite); +} + +static void +cwCompositeRects (CARD8 op, + PicturePtr pDstPicture, + xRenderColor *color, + int nRect, + xRectangle *rects) +{ + ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; + cwPsDecl(pScreen); + cwDstPictureDecl; + int i; + + cwPsUnwrap(CompositeRects); + for (i = 0; i < nRect; i++) + { + rects[i].x += dst_picture_x_off; + rects[i].y += dst_picture_y_off; + } + (*ps->CompositeRects) (op, pBackingDstPicture, color, nRect, rects); + cwPsWrap(CompositeRects, cwCompositeRects); +} + +static void +cwTrapezoids (CARD8 op, + PicturePtr pSrcPicture, + PicturePtr pDstPicture, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int ntrap, + xTrapezoid *traps) +{ + ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; + cwPsDecl(pScreen); + cwSrcPictureDecl; + cwDstPictureDecl; + int i; + + cwPsUnwrap(Trapezoids); + if (dst_picture_x_off || dst_picture_y_off) { + for (i = 0; i < ntrap; i++) + { + traps[i].top += dst_picture_y_off << 16; + traps[i].bottom += dst_picture_y_off << 16; + traps[i].left.p1.x += dst_picture_x_off << 16; + traps[i].left.p1.y += dst_picture_y_off << 16; + traps[i].left.p2.x += dst_picture_x_off << 16; + traps[i].left.p2.y += dst_picture_y_off << 16; + traps[i].right.p1.x += dst_picture_x_off << 16; + traps[i].right.p1.y += dst_picture_y_off << 16; + traps[i].right.p2.x += dst_picture_x_off << 16; + traps[i].right.p2.y += dst_picture_y_off << 16; + } + } + (*ps->Trapezoids) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat, + xSrc + src_picture_x_off, ySrc + src_picture_y_off, + ntrap, traps); + cwPsWrap(Trapezoids, cwTrapezoids); +} + +static void +cwTriangles (CARD8 op, + PicturePtr pSrcPicture, + PicturePtr pDstPicture, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int ntri, + xTriangle *tris) +{ + ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; + cwPsDecl(pScreen); + cwSrcPictureDecl; + cwDstPictureDecl; + int i; + + cwPsUnwrap(Triangles); + if (dst_picture_x_off || dst_picture_y_off) { + for (i = 0; i < ntri; i++) + { + tris[i].p1.x += dst_picture_x_off << 16; + tris[i].p1.y += dst_picture_y_off << 16; + tris[i].p2.x += dst_picture_x_off << 16; + tris[i].p2.y += dst_picture_y_off << 16; + tris[i].p3.x += dst_picture_x_off << 16; + tris[i].p3.y += dst_picture_y_off << 16; + } + } + (*ps->Triangles) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat, + xSrc + src_picture_x_off, ySrc + src_picture_y_off, + ntri, tris); + cwPsWrap(Triangles, cwTriangles); +} + +static void +cwTriStrip (CARD8 op, + PicturePtr pSrcPicture, + PicturePtr pDstPicture, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int npoint, + xPointFixed *points) +{ + ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; + cwPsDecl(pScreen); + cwSrcPictureDecl; + cwDstPictureDecl; + int i; + + cwPsUnwrap(TriStrip); + if (dst_picture_x_off || dst_picture_y_off) { + for (i = 0; i < npoint; i++) + { + points[i].x += dst_picture_x_off << 16; + points[i].y += dst_picture_y_off << 16; + } + } + (*ps->TriStrip) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat, + xSrc + src_picture_x_off, ySrc + src_picture_y_off, + npoint, points); + cwPsWrap(TriStrip, cwTriStrip); +} + +static void +cwTriFan (CARD8 op, + PicturePtr pSrcPicture, + PicturePtr pDstPicture, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int npoint, + xPointFixed *points) +{ + ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; + cwPsDecl(pScreen); + cwSrcPictureDecl; + cwDstPictureDecl; + int i; + + cwPsUnwrap(TriFan); + if (dst_picture_x_off || dst_picture_y_off) { + for (i = 0; i < npoint; i++) + { + points[i].x += dst_picture_x_off << 16; + points[i].y += dst_picture_y_off << 16; + } + } + (*ps->TriFan) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat, + xSrc + src_picture_x_off, ySrc + src_picture_y_off, + npoint, points); + cwPsWrap(TriFan, cwTriFan); +} + +void +cwInitializeRender (ScreenPtr pScreen) +{ + cwPsDecl (pScreen); + + cwPsWrap(DestroyPicture, cwDestroyPicture); + cwPsWrap(ChangePicture, cwChangePicture); + cwPsWrap(ValidatePicture, cwValidatePicture); + cwPsWrap(Composite, cwComposite); + cwPsWrap(CompositeRects, cwCompositeRects); + cwPsWrap(Trapezoids, cwTrapezoids); + cwPsWrap(Triangles, cwTriangles); + cwPsWrap(TriStrip, cwTriStrip); + cwPsWrap(TriFan, cwTriFan); + /* There is no need to wrap AddTraps as far as we can tell. AddTraps can + * only be done on alpha-only pictures, and we won't be getting + * alpha-only window pictures, so there's no need to translate. + */ +} + +void +cwFiniRender (ScreenPtr pScreen) +{ + cwPsDecl (pScreen); + + cwPsUnwrap(DestroyPicture); + cwPsUnwrap(ChangePicture); + cwPsUnwrap(ValidatePicture); + cwPsUnwrap(Composite); + cwPsUnwrap(CompositeRects); + cwPsUnwrap(Trapezoids); + cwPsUnwrap(Triangles); + cwPsUnwrap(TriStrip); + cwPsUnwrap(TriFan); +} + diff --git a/xorg-server/miext/damage/damage.c b/xorg-server/miext/damage/damage.c index de1857355..f662e928c 100644 --- a/xorg-server/miext/damage/damage.c +++ b/xorg-server/miext/damage/damage.c @@ -1,2166 +1,2166 @@ -/* - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <stdlib.h> - -#include <X11/X.h> -#include "scrnintstr.h" -#include "windowstr.h" -#include <X11/fonts/font.h> -#include "dixfontstr.h" -#include <X11/fonts/fontstruct.h> -#include "mi.h" -#include "regionstr.h" -#include "globals.h" -#include "gcstruct.h" -#include "damage.h" -#include "damagestr.h" -#ifdef COMPOSITE -#include "cw.h" -#endif - -#define wrap(priv, real, mem, func) {\ - priv->mem = real->mem; \ - real->mem = func; \ -} - -#define unwrap(priv, real, mem) {\ - real->mem = priv->mem; \ -} - -#define BOX_SAME(a,b) \ - ((a)->x1 == (b)->x1 && \ - (a)->y1 == (b)->y1 && \ - (a)->x2 == (b)->x2 && \ - (a)->y2 == (b)->y2) - -#define DAMAGE_VALIDATE_ENABLE 0 -#define DAMAGE_DEBUG_ENABLE 0 -#if DAMAGE_DEBUG_ENABLE -#define DAMAGE_DEBUG(x) ErrorF x -#else -#define DAMAGE_DEBUG(x) -#endif - -#define getPixmapDamageRef(pPixmap) ((DamagePtr *) \ - dixLookupPrivateAddr(&(pPixmap)->devPrivates, damagePixPrivateKey)) - -#define pixmapDamage(pPixmap) damagePixPriv(pPixmap) - -static int damageScrPrivateKeyIndex; -static DevPrivateKey damageScrPrivateKey = &damageScrPrivateKeyIndex; -static int damagePixPrivateKeyIndex; -static DevPrivateKey damagePixPrivateKey = &damagePixPrivateKeyIndex; -static int damageGCPrivateKeyIndex; -static DevPrivateKey damageGCPrivateKey = &damageGCPrivateKeyIndex; -static int damageWinPrivateKeyIndex; -static DevPrivateKey damageWinPrivateKey = &damageWinPrivateKeyIndex; - -static DamagePtr * -getDrawableDamageRef (DrawablePtr pDrawable) -{ - PixmapPtr pPixmap; - - if (pDrawable->type == DRAWABLE_WINDOW) - { - ScreenPtr pScreen = pDrawable->pScreen; - - pPixmap = 0; - if (pScreen->GetWindowPixmap -#ifdef ROOTLESS_WORKAROUND - && ((WindowPtr)pDrawable)->viewable -#endif - ) - pPixmap = (*pScreen->GetWindowPixmap) ((WindowPtr)pDrawable); - - if (!pPixmap) - { - damageScrPriv(pScreen); - - return &pScrPriv->pScreenDamage; - } - } - else - pPixmap = (PixmapPtr) pDrawable; - return getPixmapDamageRef (pPixmap); -} - -#define getDrawableDamage(pDrawable) (*getDrawableDamageRef (pDrawable)) -#define getWindowDamage(pWin) getDrawableDamage(&(pWin)->drawable) - -#define drawableDamage(pDrawable) \ - DamagePtr pDamage = getDrawableDamage(pDrawable) - -#define windowDamage(pWin) drawableDamage(&(pWin)->drawable) - -#define winDamageRef(pWindow) \ - DamagePtr *pPrev = (DamagePtr *) \ - dixLookupPrivateAddr(&(pWindow)->devPrivates, damageWinPrivateKey) - -static void -damageReportDamage (DamagePtr pDamage, RegionPtr pDamageRegion) -{ - BoxRec tmpBox; - RegionRec tmpRegion; - Bool was_empty; - - switch (pDamage->damageLevel) { - case DamageReportRawRegion: - REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, - pDamageRegion); - (*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure); - break; - case DamageReportDeltaRegion: - REGION_NULL (pScreen, &tmpRegion); - REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, &pDamage->damage); - if (REGION_NOTEMPTY (pScreen, &tmpRegion)) { - REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, - pDamageRegion); - (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure); - } - REGION_UNINIT(pScreen, &tmpRegion); - break; - case DamageReportBoundingBox: - tmpBox = *REGION_EXTENTS (pScreen, &pDamage->damage); - REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, - pDamageRegion); - if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &pDamage->damage))) { - (*pDamage->damageReport) (pDamage, &pDamage->damage, - pDamage->closure); - } - break; - case DamageReportNonEmpty: - was_empty = !REGION_NOTEMPTY(pScreen, &pDamage->damage); - REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, - pDamageRegion); - if (was_empty && REGION_NOTEMPTY(pScreen, &pDamage->damage)) { - (*pDamage->damageReport) (pDamage, &pDamage->damage, - pDamage->closure); - } - break; - case DamageReportNone: - REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, - pDamageRegion); - break; - } -} - -static void -damageReportDamagePostRendering (DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pDamageRegion) -{ - BoxRec tmpBox; - RegionRec tmpRegion, newDamage; - Bool was_empty; - - REGION_UNION(pScreem, &newDamage, pOldDamage, pDamageRegion); - - switch (pDamage->damageLevel) { - case DamageReportRawRegion: - (*pDamage->damageReportPostRendering) (pDamage, pDamageRegion, pDamage->closure); - break; - case DamageReportDeltaRegion: - REGION_NULL (pScreen, &tmpRegion); - REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, pOldDamage); - if (REGION_NOTEMPTY (pScreen, &tmpRegion)) { - (*pDamage->damageReportPostRendering) (pDamage, &tmpRegion, pDamage->closure); - } - REGION_UNINIT(pScreen, &tmpRegion); - break; - case DamageReportBoundingBox: - tmpBox = *REGION_EXTENTS (pScreen, pOldDamage); - if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &newDamage))) { - (*pDamage->damageReportPostRendering) (pDamage, &newDamage, - pDamage->closure); - } - break; - case DamageReportNonEmpty: - was_empty = !REGION_NOTEMPTY(pScreen, pOldDamage); - if (was_empty && REGION_NOTEMPTY(pScreen, &newDamage)) { - (*pDamage->damageReportPostRendering) (pDamage, &newDamage, - pDamage->closure); - } - break; - case DamageReportNone: - break; - } - - REGION_UNINIT(pScreen, &newDamage); -} - -#if DAMAGE_DEBUG_ENABLE -static void -_damageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, int subWindowMode, const char *where) -#define damageRegionAppend(d,r,c,m) _damageRegionAppend(d,r,c,m,__FUNCTION__) -#else -static void -damageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, - int subWindowMode) -#endif -{ - ScreenPtr pScreen = pDrawable->pScreen; - damageScrPriv(pScreen); - drawableDamage(pDrawable); - DamagePtr pNext; - RegionRec clippedRec; - RegionPtr pDamageRegion; - RegionRec pixClip; - int draw_x, draw_y; -#ifdef COMPOSITE - int screen_x = 0, screen_y = 0; -#endif - - /* short circuit for empty regions */ - if (!REGION_NOTEMPTY(pScreen, pRegion)) - return; - -#ifdef COMPOSITE - /* - * When drawing to a pixmap which is storing window contents, - * the region presented is in pixmap relative coordinates which - * need to be converted to screen relative coordinates - */ - if (pDrawable->type != DRAWABLE_WINDOW) - { - screen_x = ((PixmapPtr) pDrawable)->screen_x - pDrawable->x; - screen_y = ((PixmapPtr) pDrawable)->screen_y - pDrawable->y; - } - if (screen_x || screen_y) - REGION_TRANSLATE (pScreen, pRegion, screen_x, screen_y); -#endif - - if (pDrawable->type == DRAWABLE_WINDOW && - ((WindowPtr)(pDrawable))->backingStore == NotUseful) - { - if (subWindowMode == ClipByChildren) - { - REGION_INTERSECT(pScreen, pRegion, pRegion, - &((WindowPtr)(pDrawable))->clipList); - } - else if (subWindowMode == IncludeInferiors) - { - RegionPtr pTempRegion = - NotClippedByChildren((WindowPtr)(pDrawable)); - REGION_INTERSECT(pScreen, pRegion, pRegion, pTempRegion); - REGION_DESTROY(pScreen, pTempRegion); - } - /* If subWindowMode is set to an invalid value, don't perform - * any drawable-based clipping. */ - } - - - REGION_NULL (pScreen, &clippedRec); - for (; pDamage; pDamage = pNext) - { - pNext = pDamage->pNext; - /* - * Check for internal damage and don't send events - */ - if (pScrPriv->internalLevel > 0 && !pDamage->isInternal) - { - DAMAGE_DEBUG (("non internal damage, skipping at %d\n", - pScrPriv->internalLevel)); - continue; - } - /* - * Check for unrealized windows - */ - if (pDamage->pDrawable->type == DRAWABLE_WINDOW && - !((WindowPtr) (pDamage->pDrawable))->realized) - { - continue; - } - - draw_x = pDamage->pDrawable->x; - draw_y = pDamage->pDrawable->y; -#ifdef COMPOSITE - /* - * Need to move everyone to screen coordinates - * XXX what about off-screen pixmaps with non-zero x/y? - */ - if (pDamage->pDrawable->type != DRAWABLE_WINDOW) - { - draw_x += ((PixmapPtr) pDamage->pDrawable)->screen_x; - draw_y += ((PixmapPtr) pDamage->pDrawable)->screen_y; - } -#endif - - /* - * Clip against border or pixmap bounds - */ - - pDamageRegion = pRegion; - if (clip || pDamage->pDrawable != pDrawable) - { - pDamageRegion = &clippedRec; - if (pDamage->pDrawable->type == DRAWABLE_WINDOW) { - REGION_INTERSECT (pScreen, pDamageRegion, pRegion, - &((WindowPtr)(pDamage->pDrawable))->borderClip); - } else { - BoxRec box; - box.x1 = draw_x; - box.y1 = draw_y; - box.x2 = draw_x + pDamage->pDrawable->width; - box.y2 = draw_y + pDamage->pDrawable->height; - REGION_INIT(pScreen, &pixClip, &box, 1); - REGION_INTERSECT (pScreen, pDamageRegion, pRegion, &pixClip); - REGION_UNINIT(pScreen, &pixClip); - } - /* - * Short circuit empty results - */ - if (!REGION_NOTEMPTY(pScreen, pDamageRegion)) - continue; - } - - DAMAGE_DEBUG (("%s %d x %d +%d +%d (target 0x%lx monitor 0x%lx)\n", - where, - pDamageRegion->extents.x2 - pDamageRegion->extents.x1, - pDamageRegion->extents.y2 - pDamageRegion->extents.y1, - pDamageRegion->extents.x1, pDamageRegion->extents.y1, - pDrawable->id, pDamage->pDrawable->id)); - - /* - * Move region to target coordinate space - */ - if (draw_x || draw_y) - REGION_TRANSLATE (pScreen, pDamageRegion, -draw_x, -draw_y); - - /* Store damage region if needed after submission. */ - if (pDamage->reportAfter || pDamage->damageMarker) - REGION_UNION(pScreen, &pDamage->pendingDamage, - &pDamage->pendingDamage, pDamageRegion); - - /* Duplicate current damage if needed. */ - if (pDamage->damageMarker) - REGION_COPY(pScreen, &pDamage->backupDamage, &pDamage->damage); - - /* Report damage now, if desired. */ - if (!pDamage->reportAfter) { - if (pDamage->damageReport) - damageReportDamage (pDamage, pDamageRegion); - else - REGION_UNION(pScreen, &pDamage->damage, - &pDamage->damage, pDamageRegion); - } - - /* - * translate original region back - */ - if (pDamageRegion == pRegion && (draw_x || draw_y)) - REGION_TRANSLATE (pScreen, pDamageRegion, draw_x, draw_y); - } -#ifdef COMPOSITE - if (screen_x || screen_y) - REGION_TRANSLATE (pScreen, pRegion, -screen_x, -screen_y); -#endif - - REGION_UNINIT (pScreen, &clippedRec); -} - -static void -damageRegionProcessPending (DrawablePtr pDrawable) -{ - drawableDamage(pDrawable); - - for (; pDamage != NULL; pDamage = pDamage->pNext) - { - /* submit damage marker whenever possible. */ - if (pDamage->damageMarker) - (*pDamage->damageMarker) (pDrawable, pDamage, &pDamage->backupDamage, &pDamage->pendingDamage, pDamage->closure); - if (pDamage->reportAfter) { - /* It's possible that there is only interest in postRendering reporting. */ - if (pDamage->damageReport) - damageReportDamage (pDamage, &pDamage->pendingDamage); - else - REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, - &pDamage->pendingDamage); - } - - if (pDamage->reportAfter || pDamage->damageMarker) - REGION_EMPTY (pScreen, &pDamage->pendingDamage); - if (pDamage->damageMarker) - REGION_EMPTY (pScreen, &pDamage->backupDamage); - } - -} - -#if DAMAGE_DEBUG_ENABLE -#define damageDamageBox(d,b,m) _damageDamageBox(d,b,m,__FUNCTION__) -static void -_damageDamageBox (DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode, const char *where) -#else -static void -damageDamageBox (DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode) -#endif -{ - RegionRec region; - - REGION_INIT (pDrawable->pScreen, ®ion, pBox, 1); -#if DAMAGE_DEBUG_ENABLE - _damageRegionAppend (pDrawable, ®ion, TRUE, subWindowMode, where); -#else - damageRegionAppend (pDrawable, ®ion, TRUE, subWindowMode); -#endif - REGION_UNINIT (pDrawable->pScreen, ®ion); -} - -static void damageValidateGC(GCPtr, unsigned long, DrawablePtr); -static void damageChangeGC(GCPtr, unsigned long); -static void damageCopyGC(GCPtr, unsigned long, GCPtr); -static void damageDestroyGC(GCPtr); -static void damageChangeClip(GCPtr, int, pointer, int); -static void damageDestroyClip(GCPtr); -static void damageCopyClip(GCPtr, GCPtr); - -static GCFuncs damageGCFuncs = { - damageValidateGC, damageChangeGC, damageCopyGC, damageDestroyGC, - damageChangeClip, damageDestroyClip, damageCopyClip -}; - -static GCOps damageGCOps; - -static Bool -damageCreateGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - damageScrPriv(pScreen); - damageGCPriv(pGC); - Bool ret; - - pGC->pCompositeClip = 0; - unwrap (pScrPriv, pScreen, CreateGC); - if((ret = (*pScreen->CreateGC) (pGC))) { - pGCPriv->ops = NULL; - pGCPriv->funcs = pGC->funcs; - pGC->funcs = &damageGCFuncs; - } - wrap (pScrPriv, pScreen, CreateGC, damageCreateGC); - - return ret; -} - -#ifdef NOTUSED -static void -damageWrapGC (GCPtr pGC) -{ - damageGCPriv(pGC); - - pGCPriv->ops = NULL; - pGCPriv->funcs = pGC->funcs; - pGC->funcs = &damageGCFuncs; -} - -static void -damageUnwrapGC (GCPtr pGC) -{ - damageGCPriv(pGC); - - pGC->funcs = pGCPriv->funcs; - if (pGCPriv->ops) - pGC->ops = pGCPriv->ops; -} -#endif - -#define DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable) \ - damageGCPriv(pGC); \ - GCFuncs *oldFuncs = pGC->funcs; \ - unwrap(pGCPriv, pGC, funcs); \ - unwrap(pGCPriv, pGC, ops); \ - -#define DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable) \ - wrap(pGCPriv, pGC, funcs, oldFuncs); \ - wrap(pGCPriv, pGC, ops, &damageGCOps) - -#define DAMAGE_GC_FUNC_PROLOGUE(pGC) \ - damageGCPriv(pGC); \ - unwrap(pGCPriv, pGC, funcs); \ - if (pGCPriv->ops) unwrap(pGCPriv, pGC, ops) - -#define DAMAGE_GC_FUNC_EPILOGUE(pGC) \ - wrap(pGCPriv, pGC, funcs, &damageGCFuncs); \ - if (pGCPriv->ops) wrap(pGCPriv, pGC, ops, &damageGCOps) - -static void -damageValidateGC(GCPtr pGC, - unsigned long changes, - DrawablePtr pDrawable) -{ - DAMAGE_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable); - pGCPriv->ops = pGC->ops; /* just so it's not NULL */ - DAMAGE_GC_FUNC_EPILOGUE (pGC); -} - -static void -damageDestroyGC(GCPtr pGC) -{ - DAMAGE_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->DestroyGC)(pGC); - DAMAGE_GC_FUNC_EPILOGUE (pGC); -} - -static void -damageChangeGC (GCPtr pGC, - unsigned long mask) -{ - DAMAGE_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ChangeGC) (pGC, mask); - DAMAGE_GC_FUNC_EPILOGUE (pGC); -} - -static void -damageCopyGC (GCPtr pGCSrc, - unsigned long mask, - GCPtr pGCDst) -{ - DAMAGE_GC_FUNC_PROLOGUE (pGCDst); - (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); - DAMAGE_GC_FUNC_EPILOGUE (pGCDst); -} - -static void -damageChangeClip (GCPtr pGC, - int type, - pointer pvalue, - int nrects) -{ - DAMAGE_GC_FUNC_PROLOGUE (pGC); - (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); - DAMAGE_GC_FUNC_EPILOGUE (pGC); -} - -static void -damageCopyClip(GCPtr pgcDst, GCPtr pgcSrc) -{ - DAMAGE_GC_FUNC_PROLOGUE (pgcDst); - (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); - DAMAGE_GC_FUNC_EPILOGUE (pgcDst); -} - -static void -damageDestroyClip(GCPtr pGC) -{ - DAMAGE_GC_FUNC_PROLOGUE (pGC); - (* pGC->funcs->DestroyClip)(pGC); - DAMAGE_GC_FUNC_EPILOGUE (pGC); -} - -#define TRIM_BOX(box, pGC) if (pGC->pCompositeClip) { \ - BoxPtr extents = &pGC->pCompositeClip->extents;\ - if(box.x1 < extents->x1) box.x1 = extents->x1; \ - if(box.x2 > extents->x2) box.x2 = extents->x2; \ - if(box.y1 < extents->y1) box.y1 = extents->y1; \ - if(box.y2 > extents->y2) box.y2 = extents->y2; \ - } - -#define TRANSLATE_BOX(box, pDrawable) { \ - box.x1 += pDrawable->x; \ - box.x2 += pDrawable->x; \ - box.y1 += pDrawable->y; \ - box.y2 += pDrawable->y; \ - } - -#define TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC) { \ - TRANSLATE_BOX(box, pDrawable); \ - TRIM_BOX(box, pGC); \ - } - -#define BOX_NOT_EMPTY(box) \ - (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0)) - -#define checkGCDamage(d,g) (getDrawableDamage(d) && \ - (!g->pCompositeClip ||\ - REGION_NOTEMPTY(d->pScreen, \ - g->pCompositeClip))) - -#define TRIM_PICTURE_BOX(box, pDst) { \ - BoxPtr extents = &pDst->pCompositeClip->extents;\ - if(box.x1 < extents->x1) box.x1 = extents->x1; \ - if(box.x2 > extents->x2) box.x2 = extents->x2; \ - if(box.y1 < extents->y1) box.y1 = extents->y1; \ - if(box.y2 > extents->y2) box.y2 = extents->y2; \ - } - -#define checkPictureDamage(p) (getDrawableDamage(p->pDrawable) && \ - REGION_NOTEMPTY(pScreen, p->pCompositeClip)) - -static void -damageComposite (CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - damageScrPriv(pScreen); - - if (checkPictureDamage (pDst)) - { - BoxRec box; - - box.x1 = xDst + pDst->pDrawable->x; - box.y1 = yDst + pDst->pDrawable->y; - box.x2 = box.x1 + width; - box.y2 = box.y1 + height; - TRIM_PICTURE_BOX(box, pDst); - if (BOX_NOT_EMPTY(box)) - damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode); - } - unwrap (pScrPriv, ps, Composite); - (*ps->Composite) (op, - pSrc, - pMask, - pDst, - xSrc, - ySrc, - xMask, - yMask, - xDst, - yDst, - width, - height); - damageRegionProcessPending (pDst->pDrawable); - wrap (pScrPriv, ps, Composite, damageComposite); -} - -static void -damageGlyphs (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int nlist, - GlyphListPtr list, - GlyphPtr *glyphs) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - damageScrPriv(pScreen); - - if (checkPictureDamage (pDst)) - { - int nlistTmp = nlist; - GlyphListPtr listTmp = list; - GlyphPtr *glyphsTmp = glyphs; - int x, y; - int n; - GlyphPtr glyph; - BoxRec box; - int x1, y1, x2, y2; - - box.x1 = 32767; - box.y1 = 32767; - box.x2 = -32767; - box.y2 = -32767; - x = pDst->pDrawable->x; - y = pDst->pDrawable->y; - while (nlistTmp--) - { - x += listTmp->xOff; - y += listTmp->yOff; - n = listTmp->len; - while (n--) - { - glyph = *glyphsTmp++; - x1 = x - glyph->info.x; - y1 = y - glyph->info.y; - x2 = x1 + glyph->info.width; - y2 = y1 + glyph->info.height; - if (x1 < box.x1) - box.x1 = x1; - if (y1 < box.y1) - box.y1 = y1; - if (x2 > box.x2) - box.x2 = x2; - if (y2 > box.y2) - box.y2 = y2; - x += glyph->info.xOff; - y += glyph->info.yOff; - } - listTmp++; - } - TRIM_PICTURE_BOX (box, pDst); - if (BOX_NOT_EMPTY(box)) - damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode); - } - unwrap (pScrPriv, ps, Glyphs); - (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); - damageRegionProcessPending (pDst->pDrawable); - wrap (pScrPriv, ps, Glyphs, damageGlyphs); -} - -static void -damageAddTraps (PicturePtr pPicture, - INT16 x_off, - INT16 y_off, - int ntrap, - xTrap *traps) -{ - ScreenPtr pScreen = pPicture->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - damageScrPriv(pScreen); - - if (checkPictureDamage (pPicture)) - { - BoxRec box; - int i; - int x, y; - xTrap *t = traps; - - box.x1 = 32767; - box.y1 = 32767; - box.x2 = -32767; - box.y2 = -32767; - x = pPicture->pDrawable->x + x_off; - y = pPicture->pDrawable->y + y_off; - for (i = 0; i < ntrap; i++) - { - pixman_fixed_t l = min (t->top.l, t->bot.l); - pixman_fixed_t r = max (t->top.r, t->bot.r); - int x1 = x + pixman_fixed_to_int (l); - int x2 = x + pixman_fixed_to_int (pixman_fixed_ceil (r)); - int y1 = y + pixman_fixed_to_int (t->top.y); - int y2 = y + pixman_fixed_to_int (pixman_fixed_ceil (t->bot.y)); - - if (x1 < box.x1) - box.x1 = x1; - if (x2 > box.x2) - box.x2 = x2; - if (y1 < box.y1) - box.y1 = y1; - if (y2 > box.y2) - box.y2 = y2; - } - TRIM_PICTURE_BOX (box, pPicture); - if (BOX_NOT_EMPTY(box)) - damageDamageBox (pPicture->pDrawable, &box, pPicture->subWindowMode); - } - unwrap (pScrPriv, ps, AddTraps); - (*ps->AddTraps) (pPicture, x_off, y_off, ntrap, traps); - damageRegionProcessPending (pPicture->pDrawable); - wrap (pScrPriv, ps, AddTraps, damageAddTraps); -} - -/**********************************************************/ - - -static void -damageFillSpans(DrawablePtr pDrawable, - GC *pGC, - int npt, - DDXPointPtr ppt, - int *pwidth, - int fSorted) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (npt && checkGCDamage (pDrawable, pGC)) - { - int nptTmp = npt; - DDXPointPtr pptTmp = ppt; - int *pwidthTmp = pwidth; - BoxRec box; - - box.x1 = pptTmp->x; - box.x2 = box.x1 + *pwidthTmp; - box.y2 = box.y1 = pptTmp->y; - - while(--nptTmp) - { - pptTmp++; - pwidthTmp++; - if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; - if(box.x2 < (pptTmp->x + *pwidthTmp)) - box.x2 = pptTmp->x + *pwidthTmp; - if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; - else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; - } - - box.y2++; - - if(!pGC->miTranslate) { - TRANSLATE_BOX(box, pDrawable); - } - TRIM_BOX(box, pGC); - - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - - (*pGC->ops->FillSpans)(pDrawable, pGC, npt, ppt, pwidth, fSorted); - - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damageSetSpans(DrawablePtr pDrawable, - GCPtr pGC, - char *pcharsrc, - DDXPointPtr ppt, - int *pwidth, - int npt, - int fSorted) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (npt && checkGCDamage (pDrawable, pGC)) - { - DDXPointPtr pptTmp = ppt; - int *pwidthTmp = pwidth; - int nptTmp = npt; - BoxRec box; - - box.x1 = pptTmp->x; - box.x2 = box.x1 + *pwidthTmp; - box.y2 = box.y1 = pptTmp->y; - - while(--nptTmp) - { - pptTmp++; - pwidthTmp++; - if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; - if(box.x2 < (pptTmp->x + *pwidthTmp)) - box.x2 = pptTmp->x + *pwidthTmp; - if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; - else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; - } - - box.y2++; - - if(!pGC->miTranslate) { - TRANSLATE_BOX(box, pDrawable); - } - TRIM_BOX(box, pGC); - - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - (*pGC->ops->SetSpans)(pDrawable, pGC, pcharsrc, ppt, pwidth, npt, fSorted); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damagePutImage(DrawablePtr pDrawable, - GCPtr pGC, - int depth, - int x, - int y, - int w, - int h, - int leftPad, - int format, - char *pImage) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - if (checkGCDamage (pDrawable, pGC)) - { - BoxRec box; - - box.x1 = x + pDrawable->x; - box.x2 = box.x1 + w; - box.y1 = y + pDrawable->y; - box.y2 = box.y1 + h; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h, - leftPad, format, pImage); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static RegionPtr -damageCopyArea(DrawablePtr pSrc, - DrawablePtr pDst, - GC *pGC, - int srcx, - int srcy, - int width, - int height, - int dstx, - int dsty) -{ - RegionPtr ret; - DAMAGE_GC_OP_PROLOGUE(pGC, pDst); - - /* The driver will only call SourceValidate() when pSrc != pDst, - * but the software sprite (misprite.c) always need to know when a - * drawable is copied so it can remove the sprite. See #1030. */ - if ((pSrc == pDst) && pSrc->pScreen->SourceValidate && - pSrc->type == DRAWABLE_WINDOW && - ((WindowPtr)pSrc)->viewable) - { - (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height); - } - - if (checkGCDamage (pDst, pGC)) - { - BoxRec box; - - box.x1 = dstx + pDst->x; - box.x2 = box.x1 + width; - box.y1 = dsty + pDst->y; - box.y2 = box.y1 + height; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDst, &box, pGC->subWindowMode); - } - - ret = (*pGC->ops->CopyArea)(pSrc, pDst, - pGC, srcx, srcy, width, height, dstx, dsty); - damageRegionProcessPending (pDst); - DAMAGE_GC_OP_EPILOGUE(pGC, pDst); - return ret; -} - -static RegionPtr -damageCopyPlane(DrawablePtr pSrc, - DrawablePtr pDst, - GCPtr pGC, - int srcx, - int srcy, - int width, - int height, - int dstx, - int dsty, - unsigned long bitPlane) -{ - RegionPtr ret; - DAMAGE_GC_OP_PROLOGUE(pGC, pDst); - - /* The driver will only call SourceValidate() when pSrc != pDst, - * but the software sprite (misprite.c) always need to know when a - * drawable is copied so it can remove the sprite. See #1030. */ - if ((pSrc == pDst) && pSrc->pScreen->SourceValidate && - pSrc->type == DRAWABLE_WINDOW && - ((WindowPtr)pSrc)->viewable) - { - (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height); - } - - if (checkGCDamage (pDst, pGC)) - { - BoxRec box; - - box.x1 = dstx + pDst->x; - box.x2 = box.x1 + width; - box.y1 = dsty + pDst->y; - box.y2 = box.y1 + height; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDst, &box, pGC->subWindowMode); - } - - ret = (*pGC->ops->CopyPlane)(pSrc, pDst, - pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); - damageRegionProcessPending (pDst); - DAMAGE_GC_OP_EPILOGUE(pGC, pDst); - return ret; -} - -static void -damagePolyPoint(DrawablePtr pDrawable, - GCPtr pGC, - int mode, - int npt, - xPoint *ppt) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (npt && checkGCDamage (pDrawable, pGC)) - { - BoxRec box; - int nptTmp = npt; - xPoint *pptTmp = ppt; - - box.x2 = box.x1 = pptTmp->x; - box.y2 = box.y1 = pptTmp->y; - - /* this could be slow if the points were spread out */ - - while(--nptTmp) - { - pptTmp++; - if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; - else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x; - if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; - else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; - } - - box.x2++; - box.y2++; - - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - (*pGC->ops->PolyPoint)(pDrawable, pGC, mode, npt, ppt); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damagePolylines(DrawablePtr pDrawable, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr ppt) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (npt && checkGCDamage (pDrawable, pGC)) - { - int nptTmp = npt; - DDXPointPtr pptTmp = ppt; - BoxRec box; - int extra = pGC->lineWidth >> 1; - - box.x2 = box.x1 = pptTmp->x; - box.y2 = box.y1 = pptTmp->y; - - if(nptTmp > 1) - { - if(pGC->joinStyle == JoinMiter) - extra = 6 * pGC->lineWidth; - else if(pGC->capStyle == CapProjecting) - extra = pGC->lineWidth; - } - - if(mode == CoordModePrevious) - { - int x = box.x1; - int y = box.y1; - while(--nptTmp) - { - pptTmp++; - x += pptTmp->x; - y += pptTmp->y; - if(box.x1 > x) box.x1 = x; - else if(box.x2 < x) box.x2 = x; - if(box.y1 > y) box.y1 = y; - else if(box.y2 < y) box.y2 = y; - } - } - else - { - while(--nptTmp) - { - pptTmp++; - if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; - else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x; - if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; - else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; - } - } - - box.x2++; - box.y2++; - - if(extra) - { - box.x1 -= extra; - box.x2 += extra; - box.y1 -= extra; - box.y2 += extra; - } - - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - (*pGC->ops->Polylines)(pDrawable, pGC, mode, npt, ppt); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damagePolySegment(DrawablePtr pDrawable, - GCPtr pGC, - int nSeg, - xSegment *pSeg) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (nSeg && checkGCDamage (pDrawable, pGC)) - { - BoxRec box; - int extra = pGC->lineWidth; - int nsegTmp = nSeg; - xSegment *pSegTmp = pSeg; - - if(pGC->capStyle != CapProjecting) - extra >>= 1; - - if(pSegTmp->x2 > pSegTmp->x1) { - box.x1 = pSegTmp->x1; - box.x2 = pSegTmp->x2; - } else { - box.x2 = pSegTmp->x1; - box.x1 = pSegTmp->x2; - } - - if(pSegTmp->y2 > pSegTmp->y1) { - box.y1 = pSegTmp->y1; - box.y2 = pSegTmp->y2; - } else { - box.y2 = pSegTmp->y1; - box.y1 = pSegTmp->y2; - } - - while(--nsegTmp) - { - pSegTmp++; - if(pSegTmp->x2 > pSegTmp->x1) - { - if(pSegTmp->x1 < box.x1) box.x1 = pSegTmp->x1; - if(pSegTmp->x2 > box.x2) box.x2 = pSegTmp->x2; - } - else - { - if(pSegTmp->x2 < box.x1) box.x1 = pSegTmp->x2; - if(pSegTmp->x1 > box.x2) box.x2 = pSegTmp->x1; - } - if(pSegTmp->y2 > pSegTmp->y1) - { - if(pSegTmp->y1 < box.y1) box.y1 = pSegTmp->y1; - if(pSegTmp->y2 > box.y2) box.y2 = pSegTmp->y2; - } - else - { - if(pSegTmp->y2 < box.y1) box.y1 = pSegTmp->y2; - if(pSegTmp->y1 > box.y2) box.y2 = pSegTmp->y1; - } - } - - box.x2++; - box.y2++; - - if(extra) - { - box.x1 -= extra; - box.x2 += extra; - box.y1 -= extra; - box.y2 += extra; - } - - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - (*pGC->ops->PolySegment)(pDrawable, pGC, nSeg, pSeg); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damagePolyRectangle(DrawablePtr pDrawable, - GCPtr pGC, - int nRects, - xRectangle *pRects) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (nRects && checkGCDamage (pDrawable, pGC)) - { - BoxRec box; - int offset1, offset2, offset3; - int nRectsTmp = nRects; - xRectangle *pRectsTmp = pRects; - - offset2 = pGC->lineWidth; - if(!offset2) offset2 = 1; - offset1 = offset2 >> 1; - offset3 = offset2 - offset1; - - while(nRectsTmp--) - { - box.x1 = pRectsTmp->x - offset1; - box.y1 = pRectsTmp->y - offset1; - box.x2 = box.x1 + pRectsTmp->width + offset2; - box.y2 = box.y1 + offset2; - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - - box.x1 = pRectsTmp->x - offset1; - box.y1 = pRectsTmp->y + offset3; - box.x2 = box.x1 + offset2; - box.y2 = box.y1 + pRectsTmp->height - offset2; - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - - box.x1 = pRectsTmp->x + pRectsTmp->width - offset1; - box.y1 = pRectsTmp->y + offset3; - box.x2 = box.x1 + offset2; - box.y2 = box.y1 + pRectsTmp->height - offset2; - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - - box.x1 = pRectsTmp->x - offset1; - box.y1 = pRectsTmp->y + pRectsTmp->height - offset1; - box.x2 = box.x1 + pRectsTmp->width + offset2; - box.y2 = box.y1 + offset2; - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - - pRectsTmp++; - } - } - (*pGC->ops->PolyRectangle)(pDrawable, pGC, nRects, pRects); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damagePolyArc(DrawablePtr pDrawable, - GCPtr pGC, - int nArcs, - xArc *pArcs) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (nArcs && checkGCDamage (pDrawable, pGC)) - { - int extra = pGC->lineWidth >> 1; - BoxRec box; - int nArcsTmp = nArcs; - xArc *pArcsTmp = pArcs; - - box.x1 = pArcsTmp->x; - box.x2 = box.x1 + pArcsTmp->width; - box.y1 = pArcsTmp->y; - box.y2 = box.y1 + pArcsTmp->height; - - while(--nArcsTmp) - { - pArcsTmp++; - if(box.x1 > pArcsTmp->x) - box.x1 = pArcsTmp->x; - if(box.x2 < (pArcsTmp->x + pArcsTmp->width)) - box.x2 = pArcsTmp->x + pArcsTmp->width; - if(box.y1 > pArcsTmp->y) - box.y1 = pArcsTmp->y; - if(box.y2 < (pArcsTmp->y + pArcsTmp->height)) - box.y2 = pArcsTmp->y + pArcsTmp->height; - } - - if(extra) - { - box.x1 -= extra; - box.x2 += extra; - box.y1 -= extra; - box.y2 += extra; - } - - box.x2++; - box.y2++; - - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - (*pGC->ops->PolyArc)(pDrawable, pGC, nArcs, pArcs); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damageFillPolygon(DrawablePtr pDrawable, - GCPtr pGC, - int shape, - int mode, - int npt, - DDXPointPtr ppt) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (npt > 2 && checkGCDamage (pDrawable, pGC)) - { - DDXPointPtr pptTmp = ppt; - int nptTmp = npt; - BoxRec box; - - box.x2 = box.x1 = pptTmp->x; - box.y2 = box.y1 = pptTmp->y; - - if(mode != CoordModeOrigin) - { - int x = box.x1; - int y = box.y1; - while(--nptTmp) - { - pptTmp++; - x += pptTmp->x; - y += pptTmp->y; - if(box.x1 > x) box.x1 = x; - else if(box.x2 < x) box.x2 = x; - if(box.y1 > y) box.y1 = y; - else if(box.y2 < y) box.y2 = y; - } - } - else - { - while(--nptTmp) - { - pptTmp++; - if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; - else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x; - if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; - else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; - } - } - - box.x2++; - box.y2++; - - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - - (*pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, npt, ppt); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - - -static void -damagePolyFillRect(DrawablePtr pDrawable, - GCPtr pGC, - int nRects, - xRectangle *pRects) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - if (nRects && checkGCDamage (pDrawable, pGC)) - { - BoxRec box; - xRectangle *pRectsTmp = pRects; - int nRectsTmp = nRects; - - box.x1 = pRectsTmp->x; - box.x2 = box.x1 + pRectsTmp->width; - box.y1 = pRectsTmp->y; - box.y2 = box.y1 + pRectsTmp->height; - - while(--nRectsTmp) - { - pRectsTmp++; - if(box.x1 > pRectsTmp->x) box.x1 = pRectsTmp->x; - if(box.x2 < (pRectsTmp->x + pRectsTmp->width)) - box.x2 = pRectsTmp->x + pRectsTmp->width; - if(box.y1 > pRectsTmp->y) box.y1 = pRectsTmp->y; - if(box.y2 < (pRectsTmp->y + pRectsTmp->height)) - box.y2 = pRectsTmp->y + pRectsTmp->height; - } - - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - (*pGC->ops->PolyFillRect)(pDrawable, pGC, nRects, pRects); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - - -static void -damagePolyFillArc(DrawablePtr pDrawable, - GCPtr pGC, - int nArcs, - xArc *pArcs) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (nArcs && checkGCDamage (pDrawable, pGC)) - { - BoxRec box; - int nArcsTmp = nArcs; - xArc *pArcsTmp = pArcs; - - box.x1 = pArcsTmp->x; - box.x2 = box.x1 + pArcsTmp->width; - box.y1 = pArcsTmp->y; - box.y2 = box.y1 + pArcsTmp->height; - - while(--nArcsTmp) - { - pArcsTmp++; - if(box.x1 > pArcsTmp->x) - box.x1 = pArcsTmp->x; - if(box.x2 < (pArcsTmp->x + pArcsTmp->width)) - box.x2 = pArcsTmp->x + pArcsTmp->width; - if(box.y1 > pArcsTmp->y) - box.y1 = pArcsTmp->y; - if(box.y2 < (pArcsTmp->y + pArcsTmp->height)) - box.y2 = pArcsTmp->y + pArcsTmp->height; - } - - TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - (*pGC->ops->PolyFillArc)(pDrawable, pGC, nArcs, pArcs); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -/* - * general Poly/Image text function. Extract glyph information, - * compute bounding box and remove cursor if it is overlapped. - */ - -static void -damageDamageChars (DrawablePtr pDrawable, - FontPtr font, - int x, - int y, - unsigned int n, - CharInfoPtr *charinfo, - Bool imageblt, - int subWindowMode) -{ - ExtentInfoRec extents; - BoxRec box; - - QueryGlyphExtents(font, charinfo, n, &extents); - if (imageblt) - { - if (extents.overallWidth > extents.overallRight) - extents.overallRight = extents.overallWidth; - if (extents.overallWidth < extents.overallLeft) - extents.overallLeft = extents.overallWidth; - if (extents.overallLeft > 0) - extents.overallLeft = 0; - if (extents.fontAscent > extents.overallAscent) - extents.overallAscent = extents.fontAscent; - if (extents.fontDescent > extents.overallDescent) - extents.overallDescent = extents.fontDescent; - } - box.x1 = x + extents.overallLeft; - box.y1 = y - extents.overallAscent; - box.x2 = x + extents.overallRight; - box.y2 = y + extents.overallDescent; - damageDamageBox (pDrawable, &box, subWindowMode); -} - -/* - * values for textType: - */ -#define TT_POLY8 0 -#define TT_IMAGE8 1 -#define TT_POLY16 2 -#define TT_IMAGE16 3 - -static int -damageText (DrawablePtr pDrawable, - GCPtr pGC, - int x, - int y, - unsigned long count, - char *chars, - FontEncoding fontEncoding, - Bool textType) -{ - CharInfoPtr *charinfo; - CharInfoPtr *info; - unsigned long i; - unsigned int n; - int w; - Bool imageblt; - - imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16); - - charinfo = xalloc(count * sizeof(CharInfoPtr)); - if (!charinfo) - return x; - - GetGlyphs(pGC->font, count, (unsigned char *)chars, - fontEncoding, &i, charinfo); - n = (unsigned int)i; - w = 0; - if (!imageblt) - for (info = charinfo; i--; info++) - w += (*info)->metrics.characterWidth; - - if (n != 0) { - damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, n, - charinfo, imageblt, pGC->subWindowMode); - if (imageblt) - (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, - FONTGLYPHS(pGC->font)); - else - (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, - FONTGLYPHS(pGC->font)); - } - xfree(charinfo); - return x + w; -} - -static int -damagePolyText8(DrawablePtr pDrawable, - GCPtr pGC, - int x, - int y, - int count, - char *chars) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (checkGCDamage (pDrawable, pGC)) - x = damageText (pDrawable, pGC, x, y, (unsigned long) count, chars, - Linear8Bit, TT_POLY8); - else - x = (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); - return x; -} - -static int -damagePolyText16(DrawablePtr pDrawable, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (checkGCDamage (pDrawable, pGC)) - x = damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, - FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, - TT_POLY16); - else - x = (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); - return x; -} - -static void -damageImageText8(DrawablePtr pDrawable, - GCPtr pGC, - int x, - int y, - int count, - char *chars) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (checkGCDamage (pDrawable, pGC)) - damageText (pDrawable, pGC, x, y, (unsigned long) count, chars, - Linear8Bit, TT_IMAGE8); - else - (*pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damageImageText16(DrawablePtr pDrawable, - GCPtr pGC, - int x, - int y, - int count, - unsigned short *chars) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - - if (checkGCDamage (pDrawable, pGC)) - damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, - FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, - TT_IMAGE16); - else - (*pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - - -static void -damageImageGlyphBlt(DrawablePtr pDrawable, - GCPtr pGC, - int x, - int y, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, - nglyph, ppci, TRUE, pGC->subWindowMode); - (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph, - ppci, pglyphBase); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damagePolyGlyphBlt(DrawablePtr pDrawable, - GCPtr pGC, - int x, - int y, - unsigned int nglyph, - CharInfoPtr *ppci, - pointer pglyphBase) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, - nglyph, ppci, FALSE, pGC->subWindowMode); - (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph, - ppci, pglyphBase); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damagePushPixels(GCPtr pGC, - PixmapPtr pBitMap, - DrawablePtr pDrawable, - int dx, - int dy, - int xOrg, - int yOrg) -{ - DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); - if(checkGCDamage (pDrawable, pGC)) - { - BoxRec box; - - box.x1 = xOrg; - box.y1 = yOrg; - - if(!pGC->miTranslate) { - box.x1 += pDrawable->x; - box.y1 += pDrawable->y; - } - - box.x2 = box.x1 + dx; - box.y2 = box.y1 + dy; - - TRIM_BOX(box, pGC); - if(BOX_NOT_EMPTY(box)) - damageDamageBox (pDrawable, &box, pGC->subWindowMode); - } - (*pGC->ops->PushPixels)(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg); - damageRegionProcessPending (pDrawable); - DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); -} - -static void -damageRemoveDamage (DamagePtr *pPrev, DamagePtr pDamage) -{ - while (*pPrev) - { - if (*pPrev == pDamage) - { - *pPrev = pDamage->pNext; - return; - } - pPrev = &(*pPrev)->pNext; - } -#if DAMAGE_VALIDATE_ENABLE - ErrorF ("Damage not on list\n"); - OsAbort (); -#endif -} - -static void -damageInsertDamage (DamagePtr *pPrev, DamagePtr pDamage) -{ -#if DAMAGE_VALIDATE_ENABLE - DamagePtr pOld; - - for (pOld = *pPrev; pOld; pOld = pOld->pNext) - if (pOld == pDamage) { - ErrorF ("Damage already on list\n"); - OsAbort (); - } -#endif - pDamage->pNext = *pPrev; - *pPrev = pDamage; -} - -static Bool -damageDestroyPixmap (PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - damageScrPriv(pScreen); - - if (pPixmap->refcnt == 1) - { - DamagePtr *pPrev = getPixmapDamageRef (pPixmap); - DamagePtr pDamage; - - while ((pDamage = *pPrev)) - { - damageRemoveDamage (pPrev, pDamage); - if (!pDamage->isWindow) - DamageDestroy (pDamage); - } - } - unwrap (pScrPriv, pScreen, DestroyPixmap); - (*pScreen->DestroyPixmap) (pPixmap); - wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap); - return TRUE; -} - -static void -damageCopyWindow(WindowPtr pWindow, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - damageScrPriv(pScreen); - - if (getWindowDamage (pWindow)) - { - int dx = pWindow->drawable.x - ptOldOrg.x; - int dy = pWindow->drawable.y - ptOldOrg.y; - - /* - * The region comes in source relative, but the damage occurs - * at the destination location. Translate back and forth. - */ - REGION_TRANSLATE (pScreen, prgnSrc, dx, dy); - damageRegionAppend (&pWindow->drawable, prgnSrc, FALSE, -1); - REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy); - } - unwrap (pScrPriv, pScreen, CopyWindow); - (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); - damageRegionProcessPending (&pWindow->drawable); - wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow); -} - -static GCOps damageGCOps = { - damageFillSpans, damageSetSpans, - damagePutImage, damageCopyArea, - damageCopyPlane, damagePolyPoint, - damagePolylines, damagePolySegment, - damagePolyRectangle, damagePolyArc, - damageFillPolygon, damagePolyFillRect, - damagePolyFillArc, damagePolyText8, - damagePolyText16, damageImageText8, - damageImageText16, damageImageGlyphBlt, - damagePolyGlyphBlt, damagePushPixels, - {NULL} /* devPrivate */ -}; - -static void -damageSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap) -{ - DamagePtr pDamage; - ScreenPtr pScreen = pWindow->drawable.pScreen; - damageScrPriv(pScreen); - - if ((pDamage = damageGetWinPriv(pWindow))) - { - PixmapPtr pOldPixmap = (*pScreen->GetWindowPixmap) (pWindow); - DamagePtr *pPrev = getPixmapDamageRef(pOldPixmap); - - while (pDamage) - { - damageRemoveDamage (pPrev, pDamage); - pDamage = pDamage->pNextWin; - } - } - unwrap (pScrPriv, pScreen, SetWindowPixmap); - (*pScreen->SetWindowPixmap) (pWindow, pPixmap); - wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap); - if ((pDamage = damageGetWinPriv(pWindow))) - { - DamagePtr *pPrev = getPixmapDamageRef(pPixmap); - - while (pDamage) - { - damageInsertDamage (pPrev, pDamage); - pDamage = pDamage->pNextWin; - } - } -} - -static Bool -damageDestroyWindow (WindowPtr pWindow) -{ - DamagePtr pDamage; - ScreenPtr pScreen = pWindow->drawable.pScreen; - Bool ret; - damageScrPriv(pScreen); - - while ((pDamage = damageGetWinPriv(pWindow))) - { - DamageUnregister (&pWindow->drawable, pDamage); - DamageDestroy (pDamage); - } - unwrap (pScrPriv, pScreen, DestroyWindow); - ret = (*pScreen->DestroyWindow) (pWindow); - wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow); - return ret; -} - -static Bool -damageCloseScreen (int i, ScreenPtr pScreen) -{ - damageScrPriv(pScreen); - - unwrap (pScrPriv, pScreen, DestroyPixmap); - unwrap (pScrPriv, pScreen, CreateGC); - unwrap (pScrPriv, pScreen, CopyWindow); - unwrap (pScrPriv, pScreen, CloseScreen); - xfree (pScrPriv); - return (*pScreen->CloseScreen) (i, pScreen); -} - -/** - * Default implementations of the damage management functions. - */ -void miDamageCreate (DamagePtr pDamage) -{ -} - -void miDamageRegister (DrawablePtr pDrawable, DamagePtr pDamage) -{ -} - -void miDamageUnregister (DrawablePtr pDrawable, DamagePtr pDamage) -{ -} - -void miDamageDestroy (DamagePtr pDamage) -{ -} - -/** - * Public functions for consumption outside this file. - */ - -Bool -DamageSetup (ScreenPtr pScreen) -{ - DamageScrPrivPtr pScrPriv; - PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); - const DamageScreenFuncsRec miFuncs = { - miDamageCreate, miDamageRegister, miDamageUnregister, miDamageDestroy - }; - - if (dixLookupPrivate(&pScreen->devPrivates, damageScrPrivateKey)) - return TRUE; - - if (!dixRequestPrivate(damageGCPrivateKey, sizeof(DamageGCPrivRec))) - return FALSE; - - pScrPriv = xalloc (sizeof (DamageScrPrivRec)); - if (!pScrPriv) - return FALSE; - - pScrPriv->internalLevel = 0; - pScrPriv->pScreenDamage = 0; - - wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap); - wrap (pScrPriv, pScreen, CreateGC, damageCreateGC); - wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow); - wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap); - wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow); - wrap (pScrPriv, pScreen, CloseScreen, damageCloseScreen); - if (ps) { - wrap (pScrPriv, ps, Glyphs, damageGlyphs); - wrap (pScrPriv, ps, Composite, damageComposite); - wrap (pScrPriv, ps, AddTraps, damageAddTraps); - } - - pScrPriv->funcs = miFuncs; - - dixSetPrivate(&pScreen->devPrivates, damageScrPrivateKey, pScrPriv); - return TRUE; -} - -DamagePtr -DamageCreate (DamageReportFunc damageReport, - DamageDestroyFunc damageDestroy, - DamageReportLevel damageLevel, - Bool isInternal, - ScreenPtr pScreen, - void *closure) -{ - damageScrPriv(pScreen); - DamagePtr pDamage; - - pDamage = xalloc (sizeof (DamageRec)); - if (!pDamage) - return 0; - pDamage->pNext = 0; - pDamage->pNextWin = 0; - REGION_NULL(pScreen, &pDamage->damage); - REGION_NULL(pScreen, &pDamage->pendingDamage); - - pDamage->damageLevel = damageLevel; - pDamage->isInternal = isInternal; - pDamage->closure = closure; - pDamage->isWindow = FALSE; - pDamage->pDrawable = 0; - pDamage->reportAfter = FALSE; - - pDamage->damageReport = damageReport; - pDamage->damageReportPostRendering = NULL; - pDamage->damageDestroy = damageDestroy; - pDamage->damageMarker = NULL; - pDamage->pScreen = pScreen; - pDamage->devPrivates = NULL; - - (*pScrPriv->funcs.Create) (pDamage); - - return pDamage; -} - -void -DamageRegister (DrawablePtr pDrawable, - DamagePtr pDamage) -{ - ScreenPtr pScreen = pDrawable->pScreen; - damageScrPriv(pScreen); - -#if DAMAGE_VALIDATE_ENABLE - if (pDrawable->pScreen != pDamage->pScreen) - { - ErrorF ("DamageRegister called with mismatched screens\n"); - OsAbort (); - } -#endif - - if (pDrawable->type == DRAWABLE_WINDOW) - { - WindowPtr pWindow = (WindowPtr) pDrawable; - winDamageRef(pWindow); - -#if DAMAGE_VALIDATE_ENABLE - DamagePtr pOld; - - for (pOld = *pPrev; pOld; pOld = pOld->pNextWin) - if (pOld == pDamage) { - ErrorF ("Damage already on window list\n"); - OsAbort (); - } -#endif - pDamage->pNextWin = *pPrev; - *pPrev = pDamage; - pDamage->isWindow = TRUE; - } - else - pDamage->isWindow = FALSE; - pDamage->pDrawable = pDrawable; - damageInsertDamage (getDrawableDamageRef (pDrawable), pDamage); - (*pScrPriv->funcs.Register) (pDrawable, pDamage); -} - -void -DamageDrawInternal (ScreenPtr pScreen, Bool enable) -{ - damageScrPriv (pScreen); - - pScrPriv->internalLevel += enable ? 1 : -1; -} - -void -DamageUnregister (DrawablePtr pDrawable, - DamagePtr pDamage) -{ - ScreenPtr pScreen = pDrawable->pScreen; - damageScrPriv(pScreen); - - (*pScrPriv->funcs.Unregister) (pDrawable, pDamage); - - if (pDrawable->type == DRAWABLE_WINDOW) - { - WindowPtr pWindow = (WindowPtr) pDrawable; - winDamageRef (pWindow); -#if DAMAGE_VALIDATE_ENABLE - int found = 0; -#endif - - while (*pPrev) - { - if (*pPrev == pDamage) - { - *pPrev = pDamage->pNextWin; -#if DAMAGE_VALIDATE_ENABLE - found = 1; -#endif - break; - } - pPrev = &(*pPrev)->pNextWin; - } -#if DAMAGE_VALIDATE_ENABLE - if (!found) { - ErrorF ("Damage not on window list\n"); - OsAbort (); - } -#endif - } - pDamage->pDrawable = 0; - damageRemoveDamage (getDrawableDamageRef (pDrawable), pDamage); -} - -void -DamageDestroy (DamagePtr pDamage) -{ - ScreenPtr pScreen = pDamage->pScreen; - damageScrPriv(pScreen); - - if (pDamage->damageDestroy) - (*pDamage->damageDestroy) (pDamage, pDamage->closure); - (*pScrPriv->funcs.Destroy) (pDamage); - dixFreePrivates(pDamage->devPrivates); - pDamage->devPrivates = NULL; - REGION_UNINIT (pScreen, &pDamage->damage); - REGION_UNINIT (pScreen, &pDamage->pendingDamage); - xfree (pDamage); -} - -Bool -DamageSubtract (DamagePtr pDamage, - const RegionPtr pRegion) -{ - RegionPtr pClip; - RegionRec pixmapClip; - DrawablePtr pDrawable = pDamage->pDrawable; - - REGION_SUBTRACT (pDrawable->pScreen, &pDamage->damage, &pDamage->damage, pRegion); - if (pDrawable) - { - if (pDrawable->type == DRAWABLE_WINDOW) - pClip = &((WindowPtr) pDrawable)->borderClip; - else - { - BoxRec box; - - box.x1 = pDrawable->x; - box.y1 = pDrawable->y; - box.x2 = pDrawable->x + pDrawable->width; - box.y2 = pDrawable->y + pDrawable->height; - REGION_INIT (pDrawable->pScreen, &pixmapClip, &box, 1); - pClip = &pixmapClip; - } - REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, pDrawable->x, pDrawable->y); - REGION_INTERSECT (pDrawable->pScreen, &pDamage->damage, &pDamage->damage, pClip); - REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, -pDrawable->x, -pDrawable->y); - if (pDrawable->type != DRAWABLE_WINDOW) - REGION_UNINIT(pDrawable->pScreen, &pixmapClip); - } - return REGION_NOTEMPTY (pDrawable->pScreen, &pDamage->damage); -} - -void -DamageEmpty (DamagePtr pDamage) -{ - REGION_EMPTY (pDamage->pDrawable->pScreen, &pDamage->damage); -} - -RegionPtr -DamageRegion (DamagePtr pDamage) -{ - return &pDamage->damage; -} - -RegionPtr -DamagePendingRegion (DamagePtr pDamage) -{ - return &pDamage->pendingDamage; -} - -void -DamageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion) -{ - damageRegionAppend (pDrawable, pRegion, FALSE, -1); -} - -void -DamageRegionProcessPending (DrawablePtr pDrawable) -{ - damageRegionProcessPending (pDrawable); -} - -/* If a damage marker is provided, then this function must be called after rendering is done. */ -/* Please do call back so any future enhancements can assume this function is called. */ -/* There are no strict timing requirements for calling this function, just as soon as (is cheaply) possible. */ -void -DamageRegionRendered (DrawablePtr pDrawable, DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pRegion) -{ - if (pDamage->damageReportPostRendering) - damageReportDamagePostRendering (pDamage, pOldDamage, pRegion); -} - -/* This call is very odd, i'm leaving it intact for API sake, but please don't use it. */ -void -DamageDamageRegion (DrawablePtr pDrawable, - RegionPtr pRegion) -{ - damageRegionAppend (pDrawable, pRegion, FALSE, -1); - - /* Go back and report this damage for DamagePtrs with reportAfter set, since - * this call isn't part of an in-progress drawing op in the call chain and - * the DDX probably just wants to know about it right away. - */ - damageRegionProcessPending (pDrawable); -} - -void -DamageSetReportAfterOp (DamagePtr pDamage, Bool reportAfter) -{ - pDamage->reportAfter = reportAfter; -} - -void -DamageSetPostRenderingFunctions(DamagePtr pDamage, DamageReportFunc damageReportPostRendering, - DamageMarkerFunc damageMarker) -{ - pDamage->damageReportPostRendering = damageReportPostRendering; - pDamage->damageMarker = damageMarker; -} - -DamageScreenFuncsPtr -DamageGetScreenFuncs (ScreenPtr pScreen) -{ - damageScrPriv(pScreen); - return &pScrPriv->funcs; -} +/* + * 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdlib.h> + +#include <X11/X.h> +#include "scrnintstr.h" +#include "windowstr.h" +#include <X11/fonts/font.h> +#include "dixfontstr.h" +#include <X11/fonts/fontstruct.h> +#include "mi.h" +#include "regionstr.h" +#include "globals.h" +#include "gcstruct.h" +#include "damage.h" +#include "damagestr.h" +#ifdef COMPOSITE +#include "cw.h" +#endif + +#define wrap(priv, real, mem, func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define unwrap(priv, real, mem) {\ + real->mem = priv->mem; \ +} + +#define BOX_SAME(a,b) \ + ((a)->x1 == (b)->x1 && \ + (a)->y1 == (b)->y1 && \ + (a)->x2 == (b)->x2 && \ + (a)->y2 == (b)->y2) + +#define DAMAGE_VALIDATE_ENABLE 0 +#define DAMAGE_DEBUG_ENABLE 0 +#if DAMAGE_DEBUG_ENABLE +#define DAMAGE_DEBUG(x) ErrorF x +#else +#define DAMAGE_DEBUG(x) +#endif + +#define getPixmapDamageRef(pPixmap) ((DamagePtr *) \ + dixLookupPrivateAddr(&(pPixmap)->devPrivates, damagePixPrivateKey)) + +#define pixmapDamage(pPixmap) damagePixPriv(pPixmap) + +static int damageScrPrivateKeyIndex; +static DevPrivateKey damageScrPrivateKey = &damageScrPrivateKeyIndex; +static int damagePixPrivateKeyIndex; +static DevPrivateKey damagePixPrivateKey = &damagePixPrivateKeyIndex; +static int damageGCPrivateKeyIndex; +static DevPrivateKey damageGCPrivateKey = &damageGCPrivateKeyIndex; +static int damageWinPrivateKeyIndex; +static DevPrivateKey damageWinPrivateKey = &damageWinPrivateKeyIndex; + +static DamagePtr * +getDrawableDamageRef (DrawablePtr pDrawable) +{ + PixmapPtr pPixmap; + + if (pDrawable->type == DRAWABLE_WINDOW) + { + ScreenPtr pScreen = pDrawable->pScreen; + + pPixmap = 0; + if (pScreen->GetWindowPixmap +#ifdef ROOTLESS_WORKAROUND + && ((WindowPtr)pDrawable)->viewable +#endif + ) + pPixmap = (*pScreen->GetWindowPixmap) ((WindowPtr)pDrawable); + + if (!pPixmap) + { + damageScrPriv(pScreen); + + return &pScrPriv->pScreenDamage; + } + } + else + pPixmap = (PixmapPtr) pDrawable; + return getPixmapDamageRef (pPixmap); +} + +#define getDrawableDamage(pDrawable) (*getDrawableDamageRef (pDrawable)) +#define getWindowDamage(pWin) getDrawableDamage(&(pWin)->drawable) + +#define drawableDamage(pDrawable) \ + DamagePtr pDamage = getDrawableDamage(pDrawable) + +#define windowDamage(pWin) drawableDamage(&(pWin)->drawable) + +#define winDamageRef(pWindow) \ + DamagePtr *pPrev = (DamagePtr *) \ + dixLookupPrivateAddr(&(pWindow)->devPrivates, damageWinPrivateKey) + +static void +damageReportDamage (DamagePtr pDamage, RegionPtr pDamageRegion) +{ + BoxRec tmpBox; + RegionRec tmpRegion; + Bool was_empty; + + switch (pDamage->damageLevel) { + case DamageReportRawRegion: + REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, + pDamageRegion); + (*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure); + break; + case DamageReportDeltaRegion: + REGION_NULL (pScreen, &tmpRegion); + REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, &pDamage->damage); + if (REGION_NOTEMPTY (pScreen, &tmpRegion)) { + REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, + pDamageRegion); + (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure); + } + REGION_UNINIT(pScreen, &tmpRegion); + break; + case DamageReportBoundingBox: + tmpBox = *REGION_EXTENTS (pScreen, &pDamage->damage); + REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, + pDamageRegion); + if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &pDamage->damage))) { + (*pDamage->damageReport) (pDamage, &pDamage->damage, + pDamage->closure); + } + break; + case DamageReportNonEmpty: + was_empty = !REGION_NOTEMPTY(pScreen, &pDamage->damage); + REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, + pDamageRegion); + if (was_empty && REGION_NOTEMPTY(pScreen, &pDamage->damage)) { + (*pDamage->damageReport) (pDamage, &pDamage->damage, + pDamage->closure); + } + break; + case DamageReportNone: + REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, + pDamageRegion); + break; + } +} + +static void +damageReportDamagePostRendering (DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pDamageRegion) +{ + BoxRec tmpBox; + RegionRec tmpRegion, newDamage; + Bool was_empty; + + REGION_UNION(pScreem, &newDamage, pOldDamage, pDamageRegion); + + switch (pDamage->damageLevel) { + case DamageReportRawRegion: + (*pDamage->damageReportPostRendering) (pDamage, pDamageRegion, pDamage->closure); + break; + case DamageReportDeltaRegion: + REGION_NULL (pScreen, &tmpRegion); + REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, pOldDamage); + if (REGION_NOTEMPTY (pScreen, &tmpRegion)) { + (*pDamage->damageReportPostRendering) (pDamage, &tmpRegion, pDamage->closure); + } + REGION_UNINIT(pScreen, &tmpRegion); + break; + case DamageReportBoundingBox: + tmpBox = *REGION_EXTENTS (pScreen, pOldDamage); + if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &newDamage))) { + (*pDamage->damageReportPostRendering) (pDamage, &newDamage, + pDamage->closure); + } + break; + case DamageReportNonEmpty: + was_empty = !REGION_NOTEMPTY(pScreen, pOldDamage); + if (was_empty && REGION_NOTEMPTY(pScreen, &newDamage)) { + (*pDamage->damageReportPostRendering) (pDamage, &newDamage, + pDamage->closure); + } + break; + case DamageReportNone: + break; + } + + REGION_UNINIT(pScreen, &newDamage); +} + +#if DAMAGE_DEBUG_ENABLE +static void +_damageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, int subWindowMode, const char *where) +#define damageRegionAppend(d,r,c,m) _damageRegionAppend(d,r,c,m,__FUNCTION__) +#else +static void +damageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, + int subWindowMode) +#endif +{ + ScreenPtr pScreen = pDrawable->pScreen; + damageScrPriv(pScreen); + drawableDamage(pDrawable); + DamagePtr pNext; + RegionRec clippedRec; + RegionPtr pDamageRegion; + RegionRec pixClip; + int draw_x, draw_y; +#ifdef COMPOSITE + int screen_x = 0, screen_y = 0; +#endif + + /* short circuit for empty regions */ + if (!REGION_NOTEMPTY(pScreen, pRegion)) + return; + +#ifdef COMPOSITE + /* + * When drawing to a pixmap which is storing window contents, + * the region presented is in pixmap relative coordinates which + * need to be converted to screen relative coordinates + */ + if (pDrawable->type != DRAWABLE_WINDOW) + { + screen_x = ((PixmapPtr) pDrawable)->screen_x - pDrawable->x; + screen_y = ((PixmapPtr) pDrawable)->screen_y - pDrawable->y; + } + if (screen_x || screen_y) + REGION_TRANSLATE (pScreen, pRegion, screen_x, screen_y); +#endif + + if (pDrawable->type == DRAWABLE_WINDOW && + ((WindowPtr)(pDrawable))->backingStore == NotUseful) + { + if (subWindowMode == ClipByChildren) + { + REGION_INTERSECT(pScreen, pRegion, pRegion, + &((WindowPtr)(pDrawable))->clipList); + } + else if (subWindowMode == IncludeInferiors) + { + RegionPtr pTempRegion = + NotClippedByChildren((WindowPtr)(pDrawable)); + REGION_INTERSECT(pScreen, pRegion, pRegion, pTempRegion); + REGION_DESTROY(pScreen, pTempRegion); + } + /* If subWindowMode is set to an invalid value, don't perform + * any drawable-based clipping. */ + } + + + REGION_NULL (pScreen, &clippedRec); + for (; pDamage; pDamage = pNext) + { + pNext = pDamage->pNext; + /* + * Check for internal damage and don't send events + */ + if (pScrPriv->internalLevel > 0 && !pDamage->isInternal) + { + DAMAGE_DEBUG (("non internal damage, skipping at %d\n", + pScrPriv->internalLevel)); + continue; + } + /* + * Check for unrealized windows + */ + if (pDamage->pDrawable->type == DRAWABLE_WINDOW && + !((WindowPtr) (pDamage->pDrawable))->realized) + { + continue; + } + + draw_x = pDamage->pDrawable->x; + draw_y = pDamage->pDrawable->y; +#ifdef COMPOSITE + /* + * Need to move everyone to screen coordinates + * XXX what about off-screen pixmaps with non-zero x/y? + */ + if (pDamage->pDrawable->type != DRAWABLE_WINDOW) + { + draw_x += ((PixmapPtr) pDamage->pDrawable)->screen_x; + draw_y += ((PixmapPtr) pDamage->pDrawable)->screen_y; + } +#endif + + /* + * Clip against border or pixmap bounds + */ + + pDamageRegion = pRegion; + if (clip || pDamage->pDrawable != pDrawable) + { + pDamageRegion = &clippedRec; + if (pDamage->pDrawable->type == DRAWABLE_WINDOW) { + REGION_INTERSECT (pScreen, pDamageRegion, pRegion, + &((WindowPtr)(pDamage->pDrawable))->borderClip); + } else { + BoxRec box; + box.x1 = draw_x; + box.y1 = draw_y; + box.x2 = draw_x + pDamage->pDrawable->width; + box.y2 = draw_y + pDamage->pDrawable->height; + REGION_INIT(pScreen, &pixClip, &box, 1); + REGION_INTERSECT (pScreen, pDamageRegion, pRegion, &pixClip); + REGION_UNINIT(pScreen, &pixClip); + } + /* + * Short circuit empty results + */ + if (!REGION_NOTEMPTY(pScreen, pDamageRegion)) + continue; + } + + DAMAGE_DEBUG (("%s %d x %d +%d +%d (target 0x%lx monitor 0x%lx)\n", + where, + pDamageRegion->extents.x2 - pDamageRegion->extents.x1, + pDamageRegion->extents.y2 - pDamageRegion->extents.y1, + pDamageRegion->extents.x1, pDamageRegion->extents.y1, + pDrawable->id, pDamage->pDrawable->id)); + + /* + * Move region to target coordinate space + */ + if (draw_x || draw_y) + REGION_TRANSLATE (pScreen, pDamageRegion, -draw_x, -draw_y); + + /* Store damage region if needed after submission. */ + if (pDamage->reportAfter || pDamage->damageMarker) + REGION_UNION(pScreen, &pDamage->pendingDamage, + &pDamage->pendingDamage, pDamageRegion); + + /* Duplicate current damage if needed. */ + if (pDamage->damageMarker) + REGION_COPY(pScreen, &pDamage->backupDamage, &pDamage->damage); + + /* Report damage now, if desired. */ + if (!pDamage->reportAfter) { + if (pDamage->damageReport) + damageReportDamage (pDamage, pDamageRegion); + else + REGION_UNION(pScreen, &pDamage->damage, + &pDamage->damage, pDamageRegion); + } + + /* + * translate original region back + */ + if (pDamageRegion == pRegion && (draw_x || draw_y)) + REGION_TRANSLATE (pScreen, pDamageRegion, draw_x, draw_y); + } +#ifdef COMPOSITE + if (screen_x || screen_y) + REGION_TRANSLATE (pScreen, pRegion, -screen_x, -screen_y); +#endif + + REGION_UNINIT (pScreen, &clippedRec); +} + +static void +damageRegionProcessPending (DrawablePtr pDrawable) +{ + drawableDamage(pDrawable); + + for (; pDamage != NULL; pDamage = pDamage->pNext) + { + /* submit damage marker whenever possible. */ + if (pDamage->damageMarker) + (*pDamage->damageMarker) (pDrawable, pDamage, &pDamage->backupDamage, &pDamage->pendingDamage, pDamage->closure); + if (pDamage->reportAfter) { + /* It's possible that there is only interest in postRendering reporting. */ + if (pDamage->damageReport) + damageReportDamage (pDamage, &pDamage->pendingDamage); + else + REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, + &pDamage->pendingDamage); + } + + if (pDamage->reportAfter || pDamage->damageMarker) + REGION_EMPTY (pScreen, &pDamage->pendingDamage); + if (pDamage->damageMarker) + REGION_EMPTY (pScreen, &pDamage->backupDamage); + } + +} + +#if DAMAGE_DEBUG_ENABLE +#define damageDamageBox(d,b,m) _damageDamageBox(d,b,m,__FUNCTION__) +static void +_damageDamageBox (DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode, const char *where) +#else +static void +damageDamageBox (DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode) +#endif +{ + RegionRec region; + + REGION_INIT (pDrawable->pScreen, ®ion, pBox, 1); +#if DAMAGE_DEBUG_ENABLE + _damageRegionAppend (pDrawable, ®ion, TRUE, subWindowMode, where); +#else + damageRegionAppend (pDrawable, ®ion, TRUE, subWindowMode); +#endif + REGION_UNINIT (pDrawable->pScreen, ®ion); +} + +static void damageValidateGC(GCPtr, unsigned long, DrawablePtr); +static void damageChangeGC(GCPtr, unsigned long); +static void damageCopyGC(GCPtr, unsigned long, GCPtr); +static void damageDestroyGC(GCPtr); +static void damageChangeClip(GCPtr, int, pointer, int); +static void damageDestroyClip(GCPtr); +static void damageCopyClip(GCPtr, GCPtr); + +static GCFuncs damageGCFuncs = { + damageValidateGC, damageChangeGC, damageCopyGC, damageDestroyGC, + damageChangeClip, damageDestroyClip, damageCopyClip +}; + +static GCOps damageGCOps; + +static Bool +damageCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + damageScrPriv(pScreen); + damageGCPriv(pGC); + Bool ret; + + pGC->pCompositeClip = 0; + unwrap (pScrPriv, pScreen, CreateGC); + if((ret = (*pScreen->CreateGC) (pGC))) { + pGCPriv->ops = NULL; + pGCPriv->funcs = pGC->funcs; + pGC->funcs = &damageGCFuncs; + } + wrap (pScrPriv, pScreen, CreateGC, damageCreateGC); + + return ret; +} + +#ifdef NOTUSED +static void +damageWrapGC (GCPtr pGC) +{ + damageGCPriv(pGC); + + pGCPriv->ops = NULL; + pGCPriv->funcs = pGC->funcs; + pGC->funcs = &damageGCFuncs; +} + +static void +damageUnwrapGC (GCPtr pGC) +{ + damageGCPriv(pGC); + + pGC->funcs = pGCPriv->funcs; + if (pGCPriv->ops) + pGC->ops = pGCPriv->ops; +} +#endif + +#define DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable) \ + damageGCPriv(pGC); \ + GCFuncs *oldFuncs = pGC->funcs; \ + unwrap(pGCPriv, pGC, funcs); \ + unwrap(pGCPriv, pGC, ops); \ + +#define DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable) \ + wrap(pGCPriv, pGC, funcs, oldFuncs); \ + wrap(pGCPriv, pGC, ops, &damageGCOps) + +#define DAMAGE_GC_FUNC_PROLOGUE(pGC) \ + damageGCPriv(pGC); \ + unwrap(pGCPriv, pGC, funcs); \ + if (pGCPriv->ops) unwrap(pGCPriv, pGC, ops) + +#define DAMAGE_GC_FUNC_EPILOGUE(pGC) \ + wrap(pGCPriv, pGC, funcs, &damageGCFuncs); \ + if (pGCPriv->ops) wrap(pGCPriv, pGC, ops, &damageGCOps) + +static void +damageValidateGC(GCPtr pGC, + unsigned long changes, + DrawablePtr pDrawable) +{ + DAMAGE_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable); + pGCPriv->ops = pGC->ops; /* just so it's not NULL */ + DAMAGE_GC_FUNC_EPILOGUE (pGC); +} + +static void +damageDestroyGC(GCPtr pGC) +{ + DAMAGE_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->DestroyGC)(pGC); + DAMAGE_GC_FUNC_EPILOGUE (pGC); +} + +static void +damageChangeGC (GCPtr pGC, + unsigned long mask) +{ + DAMAGE_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeGC) (pGC, mask); + DAMAGE_GC_FUNC_EPILOGUE (pGC); +} + +static void +damageCopyGC (GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst) +{ + DAMAGE_GC_FUNC_PROLOGUE (pGCDst); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + DAMAGE_GC_FUNC_EPILOGUE (pGCDst); +} + +static void +damageChangeClip (GCPtr pGC, + int type, + pointer pvalue, + int nrects) +{ + DAMAGE_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + DAMAGE_GC_FUNC_EPILOGUE (pGC); +} + +static void +damageCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + DAMAGE_GC_FUNC_PROLOGUE (pgcDst); + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + DAMAGE_GC_FUNC_EPILOGUE (pgcDst); +} + +static void +damageDestroyClip(GCPtr pGC) +{ + DAMAGE_GC_FUNC_PROLOGUE (pGC); + (* pGC->funcs->DestroyClip)(pGC); + DAMAGE_GC_FUNC_EPILOGUE (pGC); +} + +#define TRIM_BOX(box, pGC) if (pGC->pCompositeClip) { \ + BoxPtr extents = &pGC->pCompositeClip->extents;\ + if(box.x1 < extents->x1) box.x1 = extents->x1; \ + if(box.x2 > extents->x2) box.x2 = extents->x2; \ + if(box.y1 < extents->y1) box.y1 = extents->y1; \ + if(box.y2 > extents->y2) box.y2 = extents->y2; \ + } + +#define TRANSLATE_BOX(box, pDrawable) { \ + box.x1 += pDrawable->x; \ + box.x2 += pDrawable->x; \ + box.y1 += pDrawable->y; \ + box.y2 += pDrawable->y; \ + } + +#define TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC) { \ + TRANSLATE_BOX(box, pDrawable); \ + TRIM_BOX(box, pGC); \ + } + +#define BOX_NOT_EMPTY(box) \ + (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0)) + +#define checkGCDamage(d,g) (getDrawableDamage(d) && \ + (!g->pCompositeClip ||\ + REGION_NOTEMPTY(d->pScreen, \ + g->pCompositeClip))) + +#define TRIM_PICTURE_BOX(box, pDst) { \ + BoxPtr extents = &pDst->pCompositeClip->extents;\ + if(box.x1 < extents->x1) box.x1 = extents->x1; \ + if(box.x2 > extents->x2) box.x2 = extents->x2; \ + if(box.y1 < extents->y1) box.y1 = extents->y1; \ + if(box.y2 > extents->y2) box.y2 = extents->y2; \ + } + +#define checkPictureDamage(p) (getDrawableDamage(p->pDrawable) && \ + REGION_NOTEMPTY(pScreen, p->pCompositeClip)) + +static void +damageComposite (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + damageScrPriv(pScreen); + + if (checkPictureDamage (pDst)) + { + BoxRec box; + + box.x1 = xDst + pDst->pDrawable->x; + box.y1 = yDst + pDst->pDrawable->y; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + TRIM_PICTURE_BOX(box, pDst); + if (BOX_NOT_EMPTY(box)) + damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode); + } + unwrap (pScrPriv, ps, Composite); + (*ps->Composite) (op, + pSrc, + pMask, + pDst, + xSrc, + ySrc, + xMask, + yMask, + xDst, + yDst, + width, + height); + damageRegionProcessPending (pDst->pDrawable); + wrap (pScrPriv, ps, Composite, damageComposite); +} + +static void +damageGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + damageScrPriv(pScreen); + + if (checkPictureDamage (pDst)) + { + int nlistTmp = nlist; + GlyphListPtr listTmp = list; + GlyphPtr *glyphsTmp = glyphs; + int x, y; + int n; + GlyphPtr glyph; + BoxRec box; + int x1, y1, x2, y2; + + box.x1 = 32767; + box.y1 = 32767; + box.x2 = -32767; + box.y2 = -32767; + x = pDst->pDrawable->x; + y = pDst->pDrawable->y; + while (nlistTmp--) + { + x += listTmp->xOff; + y += listTmp->yOff; + n = listTmp->len; + while (n--) + { + glyph = *glyphsTmp++; + x1 = x - glyph->info.x; + y1 = y - glyph->info.y; + x2 = x1 + glyph->info.width; + y2 = y1 + glyph->info.height; + if (x1 < box.x1) + box.x1 = x1; + if (y1 < box.y1) + box.y1 = y1; + if (x2 > box.x2) + box.x2 = x2; + if (y2 > box.y2) + box.y2 = y2; + x += glyph->info.xOff; + y += glyph->info.yOff; + } + listTmp++; + } + TRIM_PICTURE_BOX (box, pDst); + if (BOX_NOT_EMPTY(box)) + damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode); + } + unwrap (pScrPriv, ps, Glyphs); + (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); + damageRegionProcessPending (pDst->pDrawable); + wrap (pScrPriv, ps, Glyphs, damageGlyphs); +} + +static void +damageAddTraps (PicturePtr pPicture, + INT16 x_off, + INT16 y_off, + int ntrap, + xTrap *traps) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + damageScrPriv(pScreen); + + if (checkPictureDamage (pPicture)) + { + BoxRec box; + int i; + int x, y; + xTrap *t = traps; + + box.x1 = 32767; + box.y1 = 32767; + box.x2 = -32767; + box.y2 = -32767; + x = pPicture->pDrawable->x + x_off; + y = pPicture->pDrawable->y + y_off; + for (i = 0; i < ntrap; i++) + { + pixman_fixed_t l = min (t->top.l, t->bot.l); + pixman_fixed_t r = max (t->top.r, t->bot.r); + int x1 = x + pixman_fixed_to_int (l); + int x2 = x + pixman_fixed_to_int (pixman_fixed_ceil (r)); + int y1 = y + pixman_fixed_to_int (t->top.y); + int y2 = y + pixman_fixed_to_int (pixman_fixed_ceil (t->bot.y)); + + if (x1 < box.x1) + box.x1 = x1; + if (x2 > box.x2) + box.x2 = x2; + if (y1 < box.y1) + box.y1 = y1; + if (y2 > box.y2) + box.y2 = y2; + } + TRIM_PICTURE_BOX (box, pPicture); + if (BOX_NOT_EMPTY(box)) + damageDamageBox (pPicture->pDrawable, &box, pPicture->subWindowMode); + } + unwrap (pScrPriv, ps, AddTraps); + (*ps->AddTraps) (pPicture, x_off, y_off, ntrap, traps); + damageRegionProcessPending (pPicture->pDrawable); + wrap (pScrPriv, ps, AddTraps, damageAddTraps); +} + +/**********************************************************/ + + +static void +damageFillSpans(DrawablePtr pDrawable, + GC *pGC, + int npt, + DDXPointPtr ppt, + int *pwidth, + int fSorted) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (npt && checkGCDamage (pDrawable, pGC)) + { + int nptTmp = npt; + DDXPointPtr pptTmp = ppt; + int *pwidthTmp = pwidth; + BoxRec box; + + box.x1 = pptTmp->x; + box.x2 = box.x1 + *pwidthTmp; + box.y2 = box.y1 = pptTmp->y; + + while(--nptTmp) + { + pptTmp++; + pwidthTmp++; + if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; + if(box.x2 < (pptTmp->x + *pwidthTmp)) + box.x2 = pptTmp->x + *pwidthTmp; + if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; + else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; + } + + box.y2++; + + if(!pGC->miTranslate) { + TRANSLATE_BOX(box, pDrawable); + } + TRIM_BOX(box, pGC); + + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + + (*pGC->ops->FillSpans)(pDrawable, pGC, npt, ppt, pwidth, fSorted); + + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damageSetSpans(DrawablePtr pDrawable, + GCPtr pGC, + char *pcharsrc, + DDXPointPtr ppt, + int *pwidth, + int npt, + int fSorted) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (npt && checkGCDamage (pDrawable, pGC)) + { + DDXPointPtr pptTmp = ppt; + int *pwidthTmp = pwidth; + int nptTmp = npt; + BoxRec box; + + box.x1 = pptTmp->x; + box.x2 = box.x1 + *pwidthTmp; + box.y2 = box.y1 = pptTmp->y; + + while(--nptTmp) + { + pptTmp++; + pwidthTmp++; + if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; + if(box.x2 < (pptTmp->x + *pwidthTmp)) + box.x2 = pptTmp->x + *pwidthTmp; + if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; + else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; + } + + box.y2++; + + if(!pGC->miTranslate) { + TRANSLATE_BOX(box, pDrawable); + } + TRIM_BOX(box, pGC); + + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + (*pGC->ops->SetSpans)(pDrawable, pGC, pcharsrc, ppt, pwidth, npt, fSorted); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damagePutImage(DrawablePtr pDrawable, + GCPtr pGC, + int depth, + int x, + int y, + int w, + int h, + int leftPad, + int format, + char *pImage) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + if (checkGCDamage (pDrawable, pGC)) + { + BoxRec box; + + box.x1 = x + pDrawable->x; + box.x2 = box.x1 + w; + box.y1 = y + pDrawable->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h, + leftPad, format, pImage); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static RegionPtr +damageCopyArea(DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + int srcx, + int srcy, + int width, + int height, + int dstx, + int dsty) +{ + RegionPtr ret; + DAMAGE_GC_OP_PROLOGUE(pGC, pDst); + + /* The driver will only call SourceValidate() when pSrc != pDst, + * but the software sprite (misprite.c) always need to know when a + * drawable is copied so it can remove the sprite. See #1030. */ + if ((pSrc == pDst) && pSrc->pScreen->SourceValidate && + pSrc->type == DRAWABLE_WINDOW && + ((WindowPtr)pSrc)->viewable) + { + (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height); + } + + if (checkGCDamage (pDst, pGC)) + { + BoxRec box; + + box.x1 = dstx + pDst->x; + box.x2 = box.x1 + width; + box.y1 = dsty + pDst->y; + box.y2 = box.y1 + height; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDst, &box, pGC->subWindowMode); + } + + ret = (*pGC->ops->CopyArea)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty); + damageRegionProcessPending (pDst); + DAMAGE_GC_OP_EPILOGUE(pGC, pDst); + return ret; +} + +static RegionPtr +damageCopyPlane(DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, + int srcy, + int width, + int height, + int dstx, + int dsty, + unsigned long bitPlane) +{ + RegionPtr ret; + DAMAGE_GC_OP_PROLOGUE(pGC, pDst); + + /* The driver will only call SourceValidate() when pSrc != pDst, + * but the software sprite (misprite.c) always need to know when a + * drawable is copied so it can remove the sprite. See #1030. */ + if ((pSrc == pDst) && pSrc->pScreen->SourceValidate && + pSrc->type == DRAWABLE_WINDOW && + ((WindowPtr)pSrc)->viewable) + { + (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height); + } + + if (checkGCDamage (pDst, pGC)) + { + BoxRec box; + + box.x1 = dstx + pDst->x; + box.x2 = box.x1 + width; + box.y1 = dsty + pDst->y; + box.y2 = box.y1 + height; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDst, &box, pGC->subWindowMode); + } + + ret = (*pGC->ops->CopyPlane)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); + damageRegionProcessPending (pDst); + DAMAGE_GC_OP_EPILOGUE(pGC, pDst); + return ret; +} + +static void +damagePolyPoint(DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int npt, + xPoint *ppt) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (npt && checkGCDamage (pDrawable, pGC)) + { + BoxRec box; + int nptTmp = npt; + xPoint *pptTmp = ppt; + + box.x2 = box.x1 = pptTmp->x; + box.y2 = box.y1 = pptTmp->y; + + /* this could be slow if the points were spread out */ + + while(--nptTmp) + { + pptTmp++; + if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; + else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x; + if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; + else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + (*pGC->ops->PolyPoint)(pDrawable, pGC, mode, npt, ppt); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damagePolylines(DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr ppt) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (npt && checkGCDamage (pDrawable, pGC)) + { + int nptTmp = npt; + DDXPointPtr pptTmp = ppt; + BoxRec box; + int extra = pGC->lineWidth >> 1; + + box.x2 = box.x1 = pptTmp->x; + box.y2 = box.y1 = pptTmp->y; + + if(nptTmp > 1) + { + if(pGC->joinStyle == JoinMiter) + extra = 6 * pGC->lineWidth; + else if(pGC->capStyle == CapProjecting) + extra = pGC->lineWidth; + } + + if(mode == CoordModePrevious) + { + int x = box.x1; + int y = box.y1; + while(--nptTmp) + { + pptTmp++; + x += pptTmp->x; + y += pptTmp->y; + if(box.x1 > x) box.x1 = x; + else if(box.x2 < x) box.x2 = x; + if(box.y1 > y) box.y1 = y; + else if(box.y2 < y) box.y2 = y; + } + } + else + { + while(--nptTmp) + { + pptTmp++; + if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; + else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x; + if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; + else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; + } + } + + box.x2++; + box.y2++; + + if(extra) + { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + (*pGC->ops->Polylines)(pDrawable, pGC, mode, npt, ppt); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damagePolySegment(DrawablePtr pDrawable, + GCPtr pGC, + int nSeg, + xSegment *pSeg) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (nSeg && checkGCDamage (pDrawable, pGC)) + { + BoxRec box; + int extra = pGC->lineWidth; + int nsegTmp = nSeg; + xSegment *pSegTmp = pSeg; + + if(pGC->capStyle != CapProjecting) + extra >>= 1; + + if(pSegTmp->x2 > pSegTmp->x1) { + box.x1 = pSegTmp->x1; + box.x2 = pSegTmp->x2; + } else { + box.x2 = pSegTmp->x1; + box.x1 = pSegTmp->x2; + } + + if(pSegTmp->y2 > pSegTmp->y1) { + box.y1 = pSegTmp->y1; + box.y2 = pSegTmp->y2; + } else { + box.y2 = pSegTmp->y1; + box.y1 = pSegTmp->y2; + } + + while(--nsegTmp) + { + pSegTmp++; + if(pSegTmp->x2 > pSegTmp->x1) + { + if(pSegTmp->x1 < box.x1) box.x1 = pSegTmp->x1; + if(pSegTmp->x2 > box.x2) box.x2 = pSegTmp->x2; + } + else + { + if(pSegTmp->x2 < box.x1) box.x1 = pSegTmp->x2; + if(pSegTmp->x1 > box.x2) box.x2 = pSegTmp->x1; + } + if(pSegTmp->y2 > pSegTmp->y1) + { + if(pSegTmp->y1 < box.y1) box.y1 = pSegTmp->y1; + if(pSegTmp->y2 > box.y2) box.y2 = pSegTmp->y2; + } + else + { + if(pSegTmp->y2 < box.y1) box.y1 = pSegTmp->y2; + if(pSegTmp->y1 > box.y2) box.y2 = pSegTmp->y1; + } + } + + box.x2++; + box.y2++; + + if(extra) + { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + (*pGC->ops->PolySegment)(pDrawable, pGC, nSeg, pSeg); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damagePolyRectangle(DrawablePtr pDrawable, + GCPtr pGC, + int nRects, + xRectangle *pRects) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (nRects && checkGCDamage (pDrawable, pGC)) + { + BoxRec box; + int offset1, offset2, offset3; + int nRectsTmp = nRects; + xRectangle *pRectsTmp = pRects; + + offset2 = pGC->lineWidth; + if(!offset2) offset2 = 1; + offset1 = offset2 >> 1; + offset3 = offset2 - offset1; + + while(nRectsTmp--) + { + box.x1 = pRectsTmp->x - offset1; + box.y1 = pRectsTmp->y - offset1; + box.x2 = box.x1 + pRectsTmp->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + + box.x1 = pRectsTmp->x - offset1; + box.y1 = pRectsTmp->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRectsTmp->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + + box.x1 = pRectsTmp->x + pRectsTmp->width - offset1; + box.y1 = pRectsTmp->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRectsTmp->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + + box.x1 = pRectsTmp->x - offset1; + box.y1 = pRectsTmp->y + pRectsTmp->height - offset1; + box.x2 = box.x1 + pRectsTmp->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + + pRectsTmp++; + } + } + (*pGC->ops->PolyRectangle)(pDrawable, pGC, nRects, pRects); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damagePolyArc(DrawablePtr pDrawable, + GCPtr pGC, + int nArcs, + xArc *pArcs) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (nArcs && checkGCDamage (pDrawable, pGC)) + { + int extra = pGC->lineWidth >> 1; + BoxRec box; + int nArcsTmp = nArcs; + xArc *pArcsTmp = pArcs; + + box.x1 = pArcsTmp->x; + box.x2 = box.x1 + pArcsTmp->width; + box.y1 = pArcsTmp->y; + box.y2 = box.y1 + pArcsTmp->height; + + while(--nArcsTmp) + { + pArcsTmp++; + if(box.x1 > pArcsTmp->x) + box.x1 = pArcsTmp->x; + if(box.x2 < (pArcsTmp->x + pArcsTmp->width)) + box.x2 = pArcsTmp->x + pArcsTmp->width; + if(box.y1 > pArcsTmp->y) + box.y1 = pArcsTmp->y; + if(box.y2 < (pArcsTmp->y + pArcsTmp->height)) + box.y2 = pArcsTmp->y + pArcsTmp->height; + } + + if(extra) + { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + (*pGC->ops->PolyArc)(pDrawable, pGC, nArcs, pArcs); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damageFillPolygon(DrawablePtr pDrawable, + GCPtr pGC, + int shape, + int mode, + int npt, + DDXPointPtr ppt) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (npt > 2 && checkGCDamage (pDrawable, pGC)) + { + DDXPointPtr pptTmp = ppt; + int nptTmp = npt; + BoxRec box; + + box.x2 = box.x1 = pptTmp->x; + box.y2 = box.y1 = pptTmp->y; + + if(mode != CoordModeOrigin) + { + int x = box.x1; + int y = box.y1; + while(--nptTmp) + { + pptTmp++; + x += pptTmp->x; + y += pptTmp->y; + if(box.x1 > x) box.x1 = x; + else if(box.x2 < x) box.x2 = x; + if(box.y1 > y) box.y1 = y; + else if(box.y2 < y) box.y2 = y; + } + } + else + { + while(--nptTmp) + { + pptTmp++; + if(box.x1 > pptTmp->x) box.x1 = pptTmp->x; + else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x; + if(box.y1 > pptTmp->y) box.y1 = pptTmp->y; + else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y; + } + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + + (*pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, npt, ppt); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + + +static void +damagePolyFillRect(DrawablePtr pDrawable, + GCPtr pGC, + int nRects, + xRectangle *pRects) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + if (nRects && checkGCDamage (pDrawable, pGC)) + { + BoxRec box; + xRectangle *pRectsTmp = pRects; + int nRectsTmp = nRects; + + box.x1 = pRectsTmp->x; + box.x2 = box.x1 + pRectsTmp->width; + box.y1 = pRectsTmp->y; + box.y2 = box.y1 + pRectsTmp->height; + + while(--nRectsTmp) + { + pRectsTmp++; + if(box.x1 > pRectsTmp->x) box.x1 = pRectsTmp->x; + if(box.x2 < (pRectsTmp->x + pRectsTmp->width)) + box.x2 = pRectsTmp->x + pRectsTmp->width; + if(box.y1 > pRectsTmp->y) box.y1 = pRectsTmp->y; + if(box.y2 < (pRectsTmp->y + pRectsTmp->height)) + box.y2 = pRectsTmp->y + pRectsTmp->height; + } + + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + (*pGC->ops->PolyFillRect)(pDrawable, pGC, nRects, pRects); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + + +static void +damagePolyFillArc(DrawablePtr pDrawable, + GCPtr pGC, + int nArcs, + xArc *pArcs) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (nArcs && checkGCDamage (pDrawable, pGC)) + { + BoxRec box; + int nArcsTmp = nArcs; + xArc *pArcsTmp = pArcs; + + box.x1 = pArcsTmp->x; + box.x2 = box.x1 + pArcsTmp->width; + box.y1 = pArcsTmp->y; + box.y2 = box.y1 + pArcsTmp->height; + + while(--nArcsTmp) + { + pArcsTmp++; + if(box.x1 > pArcsTmp->x) + box.x1 = pArcsTmp->x; + if(box.x2 < (pArcsTmp->x + pArcsTmp->width)) + box.x2 = pArcsTmp->x + pArcsTmp->width; + if(box.y1 > pArcsTmp->y) + box.y1 = pArcsTmp->y; + if(box.y2 < (pArcsTmp->y + pArcsTmp->height)) + box.y2 = pArcsTmp->y + pArcsTmp->height; + } + + TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + (*pGC->ops->PolyFillArc)(pDrawable, pGC, nArcs, pArcs); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +/* + * general Poly/Image text function. Extract glyph information, + * compute bounding box and remove cursor if it is overlapped. + */ + +static void +damageDamageChars (DrawablePtr pDrawable, + FontPtr font, + int x, + int y, + unsigned int n, + CharInfoPtr *charinfo, + Bool imageblt, + int subWindowMode) +{ + ExtentInfoRec extents; + BoxRec box; + + QueryGlyphExtents(font, charinfo, n, &extents); + if (imageblt) + { + if (extents.overallWidth > extents.overallRight) + extents.overallRight = extents.overallWidth; + if (extents.overallWidth < extents.overallLeft) + extents.overallLeft = extents.overallWidth; + if (extents.overallLeft > 0) + extents.overallLeft = 0; + if (extents.fontAscent > extents.overallAscent) + extents.overallAscent = extents.fontAscent; + if (extents.fontDescent > extents.overallDescent) + extents.overallDescent = extents.fontDescent; + } + box.x1 = x + extents.overallLeft; + box.y1 = y - extents.overallAscent; + box.x2 = x + extents.overallRight; + box.y2 = y + extents.overallDescent; + damageDamageBox (pDrawable, &box, subWindowMode); +} + +/* + * values for textType: + */ +#define TT_POLY8 0 +#define TT_IMAGE8 1 +#define TT_POLY16 2 +#define TT_IMAGE16 3 + +static int +damageText (DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned long count, + char *chars, + FontEncoding fontEncoding, + Bool textType) +{ + CharInfoPtr *charinfo; + CharInfoPtr *info; + unsigned long i; + unsigned int n; + int w; + Bool imageblt; + + imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16); + + charinfo = malloc(count * sizeof(CharInfoPtr)); + if (!charinfo) + return x; + + GetGlyphs(pGC->font, count, (unsigned char *)chars, + fontEncoding, &i, charinfo); + n = (unsigned int)i; + w = 0; + if (!imageblt) + for (info = charinfo; i--; info++) + w += (*info)->metrics.characterWidth; + + if (n != 0) { + damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, n, + charinfo, imageblt, pGC->subWindowMode); + if (imageblt) + (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, + FONTGLYPHS(pGC->font)); + else + (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, + FONTGLYPHS(pGC->font)); + } + free(charinfo); + return x + w; +} + +static int +damagePolyText8(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + char *chars) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (checkGCDamage (pDrawable, pGC)) + x = damageText (pDrawable, pGC, x, y, (unsigned long) count, chars, + Linear8Bit, TT_POLY8); + else + x = (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); + return x; +} + +static int +damagePolyText16(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (checkGCDamage (pDrawable, pGC)) + x = damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, + FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, + TT_POLY16); + else + x = (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); + return x; +} + +static void +damageImageText8(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + char *chars) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (checkGCDamage (pDrawable, pGC)) + damageText (pDrawable, pGC, x, y, (unsigned long) count, chars, + Linear8Bit, TT_IMAGE8); + else + (*pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damageImageText16(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (checkGCDamage (pDrawable, pGC)) + damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, + FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, + TT_IMAGE16); + else + (*pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + + +static void +damageImageGlyphBlt(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, + nglyph, ppci, TRUE, pGC->subWindowMode); + (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph, + ppci, pglyphBase); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damagePolyGlyphBlt(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, + nglyph, ppci, FALSE, pGC->subWindowMode); + (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph, + ppci, pglyphBase); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damagePushPixels(GCPtr pGC, + PixmapPtr pBitMap, + DrawablePtr pDrawable, + int dx, + int dy, + int xOrg, + int yOrg) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + if(checkGCDamage (pDrawable, pGC)) + { + BoxRec box; + + box.x1 = xOrg; + box.y1 = yOrg; + + if(!pGC->miTranslate) { + box.x1 += pDrawable->x; + box.y1 += pDrawable->y; + } + + box.x2 = box.x1 + dx; + box.y2 = box.y1 + dy; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + damageDamageBox (pDrawable, &box, pGC->subWindowMode); + } + (*pGC->ops->PushPixels)(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg); + damageRegionProcessPending (pDrawable); + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damageRemoveDamage (DamagePtr *pPrev, DamagePtr pDamage) +{ + while (*pPrev) + { + if (*pPrev == pDamage) + { + *pPrev = pDamage->pNext; + return; + } + pPrev = &(*pPrev)->pNext; + } +#if DAMAGE_VALIDATE_ENABLE + ErrorF ("Damage not on list\n"); + OsAbort (); +#endif +} + +static void +damageInsertDamage (DamagePtr *pPrev, DamagePtr pDamage) +{ +#if DAMAGE_VALIDATE_ENABLE + DamagePtr pOld; + + for (pOld = *pPrev; pOld; pOld = pOld->pNext) + if (pOld == pDamage) { + ErrorF ("Damage already on list\n"); + OsAbort (); + } +#endif + pDamage->pNext = *pPrev; + *pPrev = pDamage; +} + +static Bool +damageDestroyPixmap (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + damageScrPriv(pScreen); + + if (pPixmap->refcnt == 1) + { + DamagePtr *pPrev = getPixmapDamageRef (pPixmap); + DamagePtr pDamage; + + while ((pDamage = *pPrev)) + { + damageRemoveDamage (pPrev, pDamage); + if (!pDamage->isWindow) + DamageDestroy (pDamage); + } + } + unwrap (pScrPriv, pScreen, DestroyPixmap); + (*pScreen->DestroyPixmap) (pPixmap); + wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap); + return TRUE; +} + +static void +damageCopyWindow(WindowPtr pWindow, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + damageScrPriv(pScreen); + + if (getWindowDamage (pWindow)) + { + int dx = pWindow->drawable.x - ptOldOrg.x; + int dy = pWindow->drawable.y - ptOldOrg.y; + + /* + * The region comes in source relative, but the damage occurs + * at the destination location. Translate back and forth. + */ + REGION_TRANSLATE (pScreen, prgnSrc, dx, dy); + damageRegionAppend (&pWindow->drawable, prgnSrc, FALSE, -1); + REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy); + } + unwrap (pScrPriv, pScreen, CopyWindow); + (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); + damageRegionProcessPending (&pWindow->drawable); + wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow); +} + +static GCOps damageGCOps = { + damageFillSpans, damageSetSpans, + damagePutImage, damageCopyArea, + damageCopyPlane, damagePolyPoint, + damagePolylines, damagePolySegment, + damagePolyRectangle, damagePolyArc, + damageFillPolygon, damagePolyFillRect, + damagePolyFillArc, damagePolyText8, + damagePolyText16, damageImageText8, + damageImageText16, damageImageGlyphBlt, + damagePolyGlyphBlt, damagePushPixels, + {NULL} /* devPrivate */ +}; + +static void +damageSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap) +{ + DamagePtr pDamage; + ScreenPtr pScreen = pWindow->drawable.pScreen; + damageScrPriv(pScreen); + + if ((pDamage = damageGetWinPriv(pWindow))) + { + PixmapPtr pOldPixmap = (*pScreen->GetWindowPixmap) (pWindow); + DamagePtr *pPrev = getPixmapDamageRef(pOldPixmap); + + while (pDamage) + { + damageRemoveDamage (pPrev, pDamage); + pDamage = pDamage->pNextWin; + } + } + unwrap (pScrPriv, pScreen, SetWindowPixmap); + (*pScreen->SetWindowPixmap) (pWindow, pPixmap); + wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap); + if ((pDamage = damageGetWinPriv(pWindow))) + { + DamagePtr *pPrev = getPixmapDamageRef(pPixmap); + + while (pDamage) + { + damageInsertDamage (pPrev, pDamage); + pDamage = pDamage->pNextWin; + } + } +} + +static Bool +damageDestroyWindow (WindowPtr pWindow) +{ + DamagePtr pDamage; + ScreenPtr pScreen = pWindow->drawable.pScreen; + Bool ret; + damageScrPriv(pScreen); + + while ((pDamage = damageGetWinPriv(pWindow))) + { + DamageUnregister (&pWindow->drawable, pDamage); + DamageDestroy (pDamage); + } + unwrap (pScrPriv, pScreen, DestroyWindow); + ret = (*pScreen->DestroyWindow) (pWindow); + wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow); + return ret; +} + +static Bool +damageCloseScreen (int i, ScreenPtr pScreen) +{ + damageScrPriv(pScreen); + + unwrap (pScrPriv, pScreen, DestroyPixmap); + unwrap (pScrPriv, pScreen, CreateGC); + unwrap (pScrPriv, pScreen, CopyWindow); + unwrap (pScrPriv, pScreen, CloseScreen); + free(pScrPriv); + return (*pScreen->CloseScreen) (i, pScreen); +} + +/** + * Default implementations of the damage management functions. + */ +void miDamageCreate (DamagePtr pDamage) +{ +} + +void miDamageRegister (DrawablePtr pDrawable, DamagePtr pDamage) +{ +} + +void miDamageUnregister (DrawablePtr pDrawable, DamagePtr pDamage) +{ +} + +void miDamageDestroy (DamagePtr pDamage) +{ +} + +/** + * Public functions for consumption outside this file. + */ + +Bool +DamageSetup (ScreenPtr pScreen) +{ + DamageScrPrivPtr pScrPriv; + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + const DamageScreenFuncsRec miFuncs = { + miDamageCreate, miDamageRegister, miDamageUnregister, miDamageDestroy + }; + + if (dixLookupPrivate(&pScreen->devPrivates, damageScrPrivateKey)) + return TRUE; + + if (!dixRequestPrivate(damageGCPrivateKey, sizeof(DamageGCPrivRec))) + return FALSE; + + pScrPriv = malloc(sizeof (DamageScrPrivRec)); + if (!pScrPriv) + return FALSE; + + pScrPriv->internalLevel = 0; + pScrPriv->pScreenDamage = 0; + + wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap); + wrap (pScrPriv, pScreen, CreateGC, damageCreateGC); + wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow); + wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap); + wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow); + wrap (pScrPriv, pScreen, CloseScreen, damageCloseScreen); + if (ps) { + wrap (pScrPriv, ps, Glyphs, damageGlyphs); + wrap (pScrPriv, ps, Composite, damageComposite); + wrap (pScrPriv, ps, AddTraps, damageAddTraps); + } + + pScrPriv->funcs = miFuncs; + + dixSetPrivate(&pScreen->devPrivates, damageScrPrivateKey, pScrPriv); + return TRUE; +} + +DamagePtr +DamageCreate (DamageReportFunc damageReport, + DamageDestroyFunc damageDestroy, + DamageReportLevel damageLevel, + Bool isInternal, + ScreenPtr pScreen, + void *closure) +{ + damageScrPriv(pScreen); + DamagePtr pDamage; + + pDamage = malloc(sizeof (DamageRec)); + if (!pDamage) + return 0; + pDamage->pNext = 0; + pDamage->pNextWin = 0; + REGION_NULL(pScreen, &pDamage->damage); + REGION_NULL(pScreen, &pDamage->pendingDamage); + + pDamage->damageLevel = damageLevel; + pDamage->isInternal = isInternal; + pDamage->closure = closure; + pDamage->isWindow = FALSE; + pDamage->pDrawable = 0; + pDamage->reportAfter = FALSE; + + pDamage->damageReport = damageReport; + pDamage->damageReportPostRendering = NULL; + pDamage->damageDestroy = damageDestroy; + pDamage->damageMarker = NULL; + pDamage->pScreen = pScreen; + pDamage->devPrivates = NULL; + + (*pScrPriv->funcs.Create) (pDamage); + + return pDamage; +} + +void +DamageRegister (DrawablePtr pDrawable, + DamagePtr pDamage) +{ + ScreenPtr pScreen = pDrawable->pScreen; + damageScrPriv(pScreen); + +#if DAMAGE_VALIDATE_ENABLE + if (pDrawable->pScreen != pDamage->pScreen) + { + ErrorF ("DamageRegister called with mismatched screens\n"); + OsAbort (); + } +#endif + + if (pDrawable->type == DRAWABLE_WINDOW) + { + WindowPtr pWindow = (WindowPtr) pDrawable; + winDamageRef(pWindow); + +#if DAMAGE_VALIDATE_ENABLE + DamagePtr pOld; + + for (pOld = *pPrev; pOld; pOld = pOld->pNextWin) + if (pOld == pDamage) { + ErrorF ("Damage already on window list\n"); + OsAbort (); + } +#endif + pDamage->pNextWin = *pPrev; + *pPrev = pDamage; + pDamage->isWindow = TRUE; + } + else + pDamage->isWindow = FALSE; + pDamage->pDrawable = pDrawable; + damageInsertDamage (getDrawableDamageRef (pDrawable), pDamage); + (*pScrPriv->funcs.Register) (pDrawable, pDamage); +} + +void +DamageDrawInternal (ScreenPtr pScreen, Bool enable) +{ + damageScrPriv (pScreen); + + pScrPriv->internalLevel += enable ? 1 : -1; +} + +void +DamageUnregister (DrawablePtr pDrawable, + DamagePtr pDamage) +{ + ScreenPtr pScreen = pDrawable->pScreen; + damageScrPriv(pScreen); + + (*pScrPriv->funcs.Unregister) (pDrawable, pDamage); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + WindowPtr pWindow = (WindowPtr) pDrawable; + winDamageRef (pWindow); +#if DAMAGE_VALIDATE_ENABLE + int found = 0; +#endif + + while (*pPrev) + { + if (*pPrev == pDamage) + { + *pPrev = pDamage->pNextWin; +#if DAMAGE_VALIDATE_ENABLE + found = 1; +#endif + break; + } + pPrev = &(*pPrev)->pNextWin; + } +#if DAMAGE_VALIDATE_ENABLE + if (!found) { + ErrorF ("Damage not on window list\n"); + OsAbort (); + } +#endif + } + pDamage->pDrawable = 0; + damageRemoveDamage (getDrawableDamageRef (pDrawable), pDamage); +} + +void +DamageDestroy (DamagePtr pDamage) +{ + ScreenPtr pScreen = pDamage->pScreen; + damageScrPriv(pScreen); + + if (pDamage->damageDestroy) + (*pDamage->damageDestroy) (pDamage, pDamage->closure); + (*pScrPriv->funcs.Destroy) (pDamage); + dixFreePrivates(pDamage->devPrivates); + pDamage->devPrivates = NULL; + REGION_UNINIT (pScreen, &pDamage->damage); + REGION_UNINIT (pScreen, &pDamage->pendingDamage); + free(pDamage); +} + +Bool +DamageSubtract (DamagePtr pDamage, + const RegionPtr pRegion) +{ + RegionPtr pClip; + RegionRec pixmapClip; + DrawablePtr pDrawable = pDamage->pDrawable; + + REGION_SUBTRACT (pDrawable->pScreen, &pDamage->damage, &pDamage->damage, pRegion); + if (pDrawable) + { + if (pDrawable->type == DRAWABLE_WINDOW) + pClip = &((WindowPtr) pDrawable)->borderClip; + else + { + BoxRec box; + + box.x1 = pDrawable->x; + box.y1 = pDrawable->y; + box.x2 = pDrawable->x + pDrawable->width; + box.y2 = pDrawable->y + pDrawable->height; + REGION_INIT (pDrawable->pScreen, &pixmapClip, &box, 1); + pClip = &pixmapClip; + } + REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, pDrawable->x, pDrawable->y); + REGION_INTERSECT (pDrawable->pScreen, &pDamage->damage, &pDamage->damage, pClip); + REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, -pDrawable->x, -pDrawable->y); + if (pDrawable->type != DRAWABLE_WINDOW) + REGION_UNINIT(pDrawable->pScreen, &pixmapClip); + } + return REGION_NOTEMPTY (pDrawable->pScreen, &pDamage->damage); +} + +void +DamageEmpty (DamagePtr pDamage) +{ + REGION_EMPTY (pDamage->pDrawable->pScreen, &pDamage->damage); +} + +RegionPtr +DamageRegion (DamagePtr pDamage) +{ + return &pDamage->damage; +} + +RegionPtr +DamagePendingRegion (DamagePtr pDamage) +{ + return &pDamage->pendingDamage; +} + +void +DamageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion) +{ + damageRegionAppend (pDrawable, pRegion, FALSE, -1); +} + +void +DamageRegionProcessPending (DrawablePtr pDrawable) +{ + damageRegionProcessPending (pDrawable); +} + +/* If a damage marker is provided, then this function must be called after rendering is done. */ +/* Please do call back so any future enhancements can assume this function is called. */ +/* There are no strict timing requirements for calling this function, just as soon as (is cheaply) possible. */ +void +DamageRegionRendered (DrawablePtr pDrawable, DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pRegion) +{ + if (pDamage->damageReportPostRendering) + damageReportDamagePostRendering (pDamage, pOldDamage, pRegion); +} + +/* This call is very odd, i'm leaving it intact for API sake, but please don't use it. */ +void +DamageDamageRegion (DrawablePtr pDrawable, + RegionPtr pRegion) +{ + damageRegionAppend (pDrawable, pRegion, FALSE, -1); + + /* Go back and report this damage for DamagePtrs with reportAfter set, since + * this call isn't part of an in-progress drawing op in the call chain and + * the DDX probably just wants to know about it right away. + */ + damageRegionProcessPending (pDrawable); +} + +void +DamageSetReportAfterOp (DamagePtr pDamage, Bool reportAfter) +{ + pDamage->reportAfter = reportAfter; +} + +void +DamageSetPostRenderingFunctions(DamagePtr pDamage, DamageReportFunc damageReportPostRendering, + DamageMarkerFunc damageMarker) +{ + pDamage->damageReportPostRendering = damageReportPostRendering; + pDamage->damageMarker = damageMarker; +} + +DamageScreenFuncsPtr +DamageGetScreenFuncs (ScreenPtr pScreen) +{ + damageScrPriv(pScreen); + return &pScrPriv->funcs; +} diff --git a/xorg-server/miext/rootless/rootlessScreen.c b/xorg-server/miext/rootless/rootlessScreen.c index 5f249467b..6f9341d85 100644 --- a/xorg-server/miext/rootless/rootlessScreen.c +++ b/xorg-server/miext/rootless/rootlessScreen.c @@ -1,755 +1,755 @@ -/* - * Screen routines for generic rootless X server - */ -/* - * Copyright (c) 2001 Greg Parker. All Rights Reserved. - * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. - * Copyright (c) 2002 Apple Computer, 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright - * holders shall not be used in advertising or otherwise to promote the sale, - * use or other dealings in this Software without prior written authorization. - */ - - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "mi.h" -#include "scrnintstr.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "propertyst.h" -#include "mivalidate.h" -#include "picturestr.h" -#include "colormapst.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <string.h> - -#include "rootlessCommon.h" -#include "rootlessWindow.h" - -/* In milliseconds */ -#ifndef ROOTLESS_REDISPLAY_DELAY -#define ROOTLESS_REDISPLAY_DELAY 10 -#endif - -extern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild, - VTKind kind); -extern Bool RootlessCreateGC(GCPtr pGC); - -// Initialize globals -static int rootlessGCPrivateKeyIndex; -DevPrivateKey rootlessGCPrivateKey = &rootlessGCPrivateKeyIndex; -static int rootlessScreenPrivateKeyIndex; -DevPrivateKey rootlessScreenPrivateKey = &rootlessScreenPrivateKeyIndex; -static int rootlessWindowPrivateKeyIndex; -DevPrivateKey rootlessWindowPrivateKey = &rootlessWindowPrivateKeyIndex; -static int rootlessWindowOldPixmapPrivateKeyIndex; -DevPrivateKey rootlessWindowOldPixmapPrivateKey = &rootlessWindowOldPixmapPrivateKeyIndex; - - -/* - * RootlessUpdateScreenPixmap - * miCreateScreenResources does not like a null framebuffer pointer, - * it leaves the screen pixmap with an uninitialized data pointer. - * Thus, rootless implementations typically set the framebuffer width - * to zero so that miCreateScreenResources does not allocate a screen - * pixmap for us. We allocate our own screen pixmap here since we need - * the screen pixmap to be valid (e.g. CopyArea from the root window). - */ -void -RootlessUpdateScreenPixmap(ScreenPtr pScreen) -{ - RootlessScreenRec *s = SCREENREC(pScreen); - PixmapPtr pPix; - unsigned int rowbytes; - - pPix = (*pScreen->GetScreenPixmap)(pScreen); - if (pPix == NULL) { - pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0); - (*pScreen->SetScreenPixmap)(pPix); - } - - rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth); - - if (s->pixmap_data_size < rowbytes) { - if (s->pixmap_data != NULL) - xfree(s->pixmap_data); - - s->pixmap_data_size = rowbytes; - s->pixmap_data = xalloc(s->pixmap_data_size); - if (s->pixmap_data == NULL) - return; - - memset(s->pixmap_data, 0xFF, s->pixmap_data_size); - - pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height, - pScreen->rootDepth, - BitsPerPixel(pScreen->rootDepth), - 0, s->pixmap_data); - /* ModifyPixmapHeader ignores zero arguments, so install rowbytes - by hand. */ - pPix->devKind = 0; - } -} - - -/* - * RootlessCreateScreenResources - * Rootless implementations typically set a null framebuffer pointer, which - * causes problems with miCreateScreenResources. We fix things up here. - */ -static Bool -RootlessCreateScreenResources(ScreenPtr pScreen) -{ - Bool ret = TRUE; - - SCREEN_UNWRAP(pScreen, CreateScreenResources); - - if (pScreen->CreateScreenResources != NULL) - ret = (*pScreen->CreateScreenResources)(pScreen); - - SCREEN_WRAP(pScreen, CreateScreenResources); - - if (!ret) - return ret; - - /* Make sure we have a valid screen pixmap. */ - - RootlessUpdateScreenPixmap(pScreen); - - return ret; -} - - -static Bool -RootlessCloseScreen(int i, ScreenPtr pScreen) -{ - RootlessScreenRec *s; - - s = SCREENREC(pScreen); - - // fixme unwrap everything that was wrapped? - pScreen->CloseScreen = s->CloseScreen; - - if (s->pixmap_data != NULL) { - xfree (s->pixmap_data); - s->pixmap_data = NULL; - s->pixmap_data_size = 0; - } - - xfree(s); - return pScreen->CloseScreen(i, pScreen); -} - - -static void -RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, - unsigned int format, unsigned long planeMask, char *pdstLine) -{ - ScreenPtr pScreen = pDrawable->pScreen; - SCREEN_UNWRAP(pScreen, GetImage); - - if (pDrawable->type == DRAWABLE_WINDOW) { - int x0, y0, x1, y1; - RootlessWindowRec *winRec; - - // Many apps use GetImage to sync with the visible frame buffer - // FIXME: entire screen or just window or all screens? - RootlessRedisplayScreen(pScreen); - - // RedisplayScreen stops drawing, so we need to start it again - RootlessStartDrawing((WindowPtr)pDrawable); - - /* Check that we have some place to read from. */ - winRec = WINREC(TopLevelParent((WindowPtr) pDrawable)); - if (winRec == NULL) - goto out; - - /* Clip to top-level window bounds. */ - /* FIXME: fbGetImage uses the width parameter to calculate the - stride of the destination pixmap. If w is clipped, the data - returned will be garbage, although we will not crash. */ - - x0 = pDrawable->x + sx; - y0 = pDrawable->y + sy; - x1 = x0 + w; - y1 = y0 + h; - - x0 = max (x0, winRec->x); - y0 = max (y0, winRec->y); - x1 = min (x1, winRec->x + winRec->width); - y1 = min (y1, winRec->y + winRec->height); - - sx = x0 - pDrawable->x; - sy = y0 - pDrawable->y; - w = x1 - x0; - h = y1 - y0; - - if (w <= 0 || h <= 0) - goto out; - } - - pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); - -out: - SCREEN_WRAP(pScreen, GetImage); -} - - -/* - * RootlessSourceValidate - * CopyArea and CopyPlane use a GC tied to the destination drawable. - * StartDrawing/StopDrawing wrappers won't be called if source is - * a visible window but the destination isn't. So, we call StartDrawing - * here and leave StopDrawing for the block handler. - */ -static void -RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h) -{ - SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate); - if (pDrawable->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDrawable; - RootlessStartDrawing(pWin); - } - if (pDrawable->pScreen->SourceValidate) { - pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h); - } - SCREEN_WRAP(pDrawable->pScreen, SourceValidate); -} - -static void -RootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, - INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, - INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - WindowPtr srcWin, dstWin, maskWin = NULL; - - if (pMask) { // pMask can be NULL - maskWin = (pMask->pDrawable->type == DRAWABLE_WINDOW) ? - (WindowPtr)pMask->pDrawable : NULL; - } - srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ? - (WindowPtr)pSrc->pDrawable : NULL; - dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? - (WindowPtr)pDst->pDrawable : NULL; - - // SCREEN_UNWRAP(ps, Composite); - ps->Composite = SCREENREC(pScreen)->Composite; - - if (srcWin && IsFramedWindow(srcWin)) - RootlessStartDrawing(srcWin); - if (maskWin && IsFramedWindow(maskWin)) - RootlessStartDrawing(maskWin); - if (dstWin && IsFramedWindow(dstWin)) - RootlessStartDrawing(dstWin); - - ps->Composite(op, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, - xDst, yDst, width, height); - - if (dstWin && IsFramedWindow(dstWin)) { - RootlessDamageRect(dstWin, xDst, yDst, width, height); - } - - ps->Composite = RootlessComposite; - // SCREEN_WRAP(ps, Composite); -} - - -static void -RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, - int nlist, GlyphListPtr list, GlyphPtr *glyphs) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - int x, y; - int n; - GlyphPtr glyph; - WindowPtr srcWin, dstWin; - - srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ? - (WindowPtr)pSrc->pDrawable : NULL; - dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? - (WindowPtr)pDst->pDrawable : NULL; - - if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin); - if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin); - - //SCREEN_UNWRAP(ps, Glyphs); - ps->Glyphs = SCREENREC(pScreen)->Glyphs; - ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); - ps->Glyphs = RootlessGlyphs; - //SCREEN_WRAP(ps, Glyphs); - - if (dstWin && IsFramedWindow(dstWin)) { - x = xSrc; - y = ySrc; - - while (nlist--) { - x += list->xOff; - y += list->yOff; - n = list->len; - - /* Calling DamageRect for the bounding box of each glyph is - inefficient. So compute the union of all glyphs in a list - and damage that. */ - - if (n > 0) { - BoxRec box; - - glyph = *glyphs++; - - box.x1 = x - glyph->info.x; - box.y1 = y - glyph->info.y; - box.x2 = box.x1 + glyph->info.width; - box.y2 = box.y2 + glyph->info.height; - - x += glyph->info.xOff; - y += glyph->info.yOff; - - while (--n > 0) { - short x1, y1, x2, y2; - - glyph = *glyphs++; - - x1 = x - glyph->info.x; - y1 = y - glyph->info.y; - x2 = x1 + glyph->info.width; - y2 = y1 + glyph->info.height; - - box.x1 = max (box.x1, x1); - box.y1 = max (box.y1, y1); - box.x2 = max (box.x2, x2); - box.y2 = max (box.y2, y2); - - x += glyph->info.xOff; - y += glyph->info.yOff; - } - - RootlessDamageBox(dstWin, &box); - } - list++; - } - } -} - - -/* - * RootlessValidateTree - * ValidateTree is modified in two ways: - * - top-level windows don't clip each other - * - windows aren't clipped against root. - * These only matter when validating from the root. - */ -static int -RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) -{ - int result; - RegionRec saveRoot; - ScreenPtr pScreen = pParent->drawable.pScreen; - - SCREEN_UNWRAP(pScreen, ValidateTree); - RL_DEBUG_MSG("VALIDATETREE start "); - - // Use our custom version to validate from root - if (IsRoot(pParent)) { - RL_DEBUG_MSG("custom "); - result = RootlessMiValidateTree(pParent, pChild, kind); - } else { - HUGE_ROOT(pParent); - result = pScreen->ValidateTree(pParent, pChild, kind); - NORMAL_ROOT(pParent); - } - - SCREEN_WRAP(pScreen, ValidateTree); - RL_DEBUG_MSG("VALIDATETREE end\n"); - - return result; -} - - -/* - * RootlessMarkOverlappedWindows - * MarkOverlappedWindows is modified to ignore overlapping - * top-level windows. - */ -static Bool -RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst, - WindowPtr *ppLayerWin) -{ - RegionRec saveRoot; - Bool result; - ScreenPtr pScreen = pWin->drawable.pScreen; - SCREEN_UNWRAP(pScreen, MarkOverlappedWindows); - RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start "); - - HUGE_ROOT(pWin); - if (IsRoot(pWin)) { - // root - mark nothing - RL_DEBUG_MSG("is root not marking "); - result = FALSE; - } - else if (! IsTopLevel(pWin)) { - // not top-level window - mark normally - result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin); - } - else { - //top-level window - mark children ONLY - NO overlaps with sibs (?) - // This code copied from miMarkOverlappedWindows() - - register WindowPtr pChild; - Bool anyMarked = FALSE; - MarkWindowProcPtr MarkWindow = pScreen->MarkWindow; - - RL_DEBUG_MSG("is top level! "); - /* single layered systems are easy */ - if (ppLayerWin) *ppLayerWin = pWin; - - if (pWin == pFirst) { - /* Blindly mark pWin and all of its inferiors. This is a slight - * overkill if there are mapped windows that outside pWin's border, - * but it's better than wasting time on RectIn checks. - */ - pChild = pWin; - while (1) { - if (pChild->viewable) { - if (REGION_BROKEN (pScreen, &pChild->winSize)) - SetWinSize (pChild); - if (REGION_BROKEN (pScreen, &pChild->borderSize)) - SetBorderSize (pChild); - (* MarkWindow)(pChild); - if (pChild->firstChild) { - pChild = pChild->firstChild; - continue; - } - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } - anyMarked = TRUE; - pFirst = pFirst->nextSib; - } - if (anyMarked) - (* MarkWindow)(pWin->parent); - result = anyMarked; - } - NORMAL_ROOT(pWin); - SCREEN_WRAP(pScreen, MarkOverlappedWindows); - RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n"); - - return result; -} - -static void expose_1 (WindowPtr pWin) { - WindowPtr pChild; - - if (!pWin->realized) - return; - - miPaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND); - - /* FIXME: comments in windowstr.h indicate that borderClip doesn't - include subwindow visibility. But I'm not so sure.. so we may - be exposing too much.. */ - - miSendExposures (pWin, &pWin->borderClip, - pWin->drawable.x, pWin->drawable.y); - - for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib) - expose_1 (pChild); -} - -void -RootlessScreenExpose (ScreenPtr pScreen) -{ - expose_1 (WindowTable[pScreen->myNum]); -} - - -ColormapPtr -RootlessGetColormap (ScreenPtr pScreen) -{ - RootlessScreenRec *s = SCREENREC (pScreen); - - return s->colormap; -} - -static void -RootlessInstallColormap (ColormapPtr pMap) -{ - ScreenPtr pScreen = pMap->pScreen; - RootlessScreenRec *s = SCREENREC (pScreen); - - SCREEN_UNWRAP(pScreen, InstallColormap); - - if (s->colormap != pMap) { - s->colormap = pMap; - s->colormap_changed = TRUE; - RootlessQueueRedisplay (pScreen); - } - - pScreen->InstallColormap (pMap); - - SCREEN_WRAP (pScreen, InstallColormap); -} - -static void -RootlessUninstallColormap (ColormapPtr pMap) -{ - ScreenPtr pScreen = pMap->pScreen; - RootlessScreenRec *s = SCREENREC (pScreen); - - SCREEN_UNWRAP(pScreen, UninstallColormap); - - if (s->colormap == pMap) - s->colormap = NULL; - - pScreen->UninstallColormap (pMap); - - SCREEN_WRAP(pScreen, UninstallColormap); -} - -static void -RootlessStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef) -{ - ScreenPtr pScreen = pMap->pScreen; - RootlessScreenRec *s = SCREENREC (pScreen); - - SCREEN_UNWRAP(pScreen, StoreColors); - - if (s->colormap == pMap && ndef > 0) { - s->colormap_changed = TRUE; - RootlessQueueRedisplay (pScreen); - } - - pScreen->StoreColors (pMap, ndef, pdef); - - SCREEN_WRAP(pScreen, StoreColors); -} - - -static CARD32 -RootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg) -{ - RootlessScreenRec *screenRec = arg; - - if (!screenRec->redisplay_queued) { - /* No update needed. Stop the timer. */ - - screenRec->redisplay_timer_set = FALSE; - return 0; - } - - screenRec->redisplay_queued = FALSE; - - /* Mark that we should redisplay before waiting for I/O next time */ - screenRec->redisplay_expired = TRUE; - - /* Reinstall the timer immediately, so we get as close to our - redisplay interval as possible. */ - - return ROOTLESS_REDISPLAY_DELAY; -} - - -/* - * RootlessQueueRedisplay - * Queue a redisplay after a timer delay to ensure we do not redisplay - * too frequently. - */ -void -RootlessQueueRedisplay(ScreenPtr pScreen) -{ - RootlessScreenRec *screenRec = SCREENREC(pScreen); - - screenRec->redisplay_queued = TRUE; - - if (screenRec->redisplay_timer_set) - return; - - screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer, - 0, ROOTLESS_REDISPLAY_DELAY, - RootlessRedisplayCallback, - screenRec); - screenRec->redisplay_timer_set = TRUE; -} - - -/* - * RootlessBlockHandler - * If the redisplay timer has expired, flush drawing before blocking - * on select(). - */ -static void -RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask) -{ - ScreenPtr pScreen = pbdata; - RootlessScreenRec *screenRec = SCREENREC(pScreen); - - if (screenRec->redisplay_expired) { - screenRec->redisplay_expired = FALSE; - - RootlessRedisplayScreen(pScreen); - } -} - - -static void -RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask) -{ - // nothing here -} - - -static Bool -RootlessAllocatePrivates(ScreenPtr pScreen) -{ - RootlessScreenRec *s; - - // no allocation needed for screen privates - if (!dixRequestPrivate(rootlessGCPrivateKey, sizeof(RootlessGCRec))) - return FALSE; - - s = xalloc(sizeof(RootlessScreenRec)); - if (! s) return FALSE; - SETSCREENREC(pScreen, s); - - s->pixmap_data = NULL; - s->pixmap_data_size = 0; - - s->redisplay_timer = NULL; - s->redisplay_timer_set = FALSE; - - return TRUE; -} - - -static void -RootlessWrap(ScreenPtr pScreen) -{ - RootlessScreenRec *s = SCREENREC(pScreen); - -#define WRAP(a) \ - if (pScreen->a) { \ - s->a = pScreen->a; \ - } else { \ - RL_DEBUG_MSG("null screen fn " #a "\n"); \ - s->a = NULL; \ - } \ - pScreen->a = Rootless##a - - WRAP(CreateScreenResources); - WRAP(CloseScreen); - WRAP(CreateGC); - WRAP(CopyWindow); - WRAP(GetImage); - WRAP(SourceValidate); - WRAP(CreateWindow); - WRAP(DestroyWindow); - WRAP(RealizeWindow); - WRAP(UnrealizeWindow); - WRAP(MoveWindow); - WRAP(PositionWindow); - WRAP(ResizeWindow); - WRAP(RestackWindow); - WRAP(ReparentWindow); - WRAP(ChangeBorderWidth); - WRAP(MarkOverlappedWindows); - WRAP(ValidateTree); - WRAP(ChangeWindowAttributes); - WRAP(InstallColormap); - WRAP(UninstallColormap); - WRAP(StoreColors); - - WRAP(SetShape); - - { - // Composite and Glyphs don't use normal screen wrapping - PictureScreenPtr ps = GetPictureScreen(pScreen); - s->Composite = ps->Composite; - ps->Composite = RootlessComposite; - s->Glyphs = ps->Glyphs; - ps->Glyphs = RootlessGlyphs; - } - - // WRAP(ClearToBackground); fixme put this back? useful for shaped wins? - -#undef WRAP -} - - -/* - * RootlessInit - * Called by the rootless implementation to initialize the rootless layer. - * Rootless wraps lots of stuff and needs a bunch of devPrivates. - */ -Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs) -{ - RootlessScreenRec *s; - - if (!RootlessAllocatePrivates(pScreen)) - return FALSE; - - s = SCREENREC(pScreen); - - s->imp = procs; - s->colormap = NULL; - s->redisplay_expired = FALSE; - - RootlessWrap(pScreen); - - if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler, - RootlessWakeupHandler, - (pointer) pScreen)) - { - return FALSE; - } - - return TRUE; -} - -void RootlessUpdateRooted (Bool state) { - int i; - - if (!state) - { - for (i = 0; i < screenInfo.numScreens; i++) - RootlessDisableRoot (screenInfo.screens[i]); - } - else - { - for (i = 0; i < screenInfo.numScreens; i++) - RootlessEnableRoot (screenInfo.screens[i]); - } -} +/* + * Screen routines for generic rootless X server + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "propertyst.h" +#include "mivalidate.h" +#include "picturestr.h" +#include "colormapst.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> + +#include "rootlessCommon.h" +#include "rootlessWindow.h" + +/* In milliseconds */ +#ifndef ROOTLESS_REDISPLAY_DELAY +#define ROOTLESS_REDISPLAY_DELAY 10 +#endif + +extern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild, + VTKind kind); +extern Bool RootlessCreateGC(GCPtr pGC); + +// Initialize globals +static int rootlessGCPrivateKeyIndex; +DevPrivateKey rootlessGCPrivateKey = &rootlessGCPrivateKeyIndex; +static int rootlessScreenPrivateKeyIndex; +DevPrivateKey rootlessScreenPrivateKey = &rootlessScreenPrivateKeyIndex; +static int rootlessWindowPrivateKeyIndex; +DevPrivateKey rootlessWindowPrivateKey = &rootlessWindowPrivateKeyIndex; +static int rootlessWindowOldPixmapPrivateKeyIndex; +DevPrivateKey rootlessWindowOldPixmapPrivateKey = &rootlessWindowOldPixmapPrivateKeyIndex; + + +/* + * RootlessUpdateScreenPixmap + * miCreateScreenResources does not like a null framebuffer pointer, + * it leaves the screen pixmap with an uninitialized data pointer. + * Thus, rootless implementations typically set the framebuffer width + * to zero so that miCreateScreenResources does not allocate a screen + * pixmap for us. We allocate our own screen pixmap here since we need + * the screen pixmap to be valid (e.g. CopyArea from the root window). + */ +void +RootlessUpdateScreenPixmap(ScreenPtr pScreen) +{ + RootlessScreenRec *s = SCREENREC(pScreen); + PixmapPtr pPix; + unsigned int rowbytes; + + pPix = (*pScreen->GetScreenPixmap)(pScreen); + if (pPix == NULL) { + pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0); + (*pScreen->SetScreenPixmap)(pPix); + } + + rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth); + + if (s->pixmap_data_size < rowbytes) { + if (s->pixmap_data != NULL) + free(s->pixmap_data); + + s->pixmap_data_size = rowbytes; + s->pixmap_data = malloc(s->pixmap_data_size); + if (s->pixmap_data == NULL) + return; + + memset(s->pixmap_data, 0xFF, s->pixmap_data_size); + + pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height, + pScreen->rootDepth, + BitsPerPixel(pScreen->rootDepth), + 0, s->pixmap_data); + /* ModifyPixmapHeader ignores zero arguments, so install rowbytes + by hand. */ + pPix->devKind = 0; + } +} + + +/* + * RootlessCreateScreenResources + * Rootless implementations typically set a null framebuffer pointer, which + * causes problems with miCreateScreenResources. We fix things up here. + */ +static Bool +RootlessCreateScreenResources(ScreenPtr pScreen) +{ + Bool ret = TRUE; + + SCREEN_UNWRAP(pScreen, CreateScreenResources); + + if (pScreen->CreateScreenResources != NULL) + ret = (*pScreen->CreateScreenResources)(pScreen); + + SCREEN_WRAP(pScreen, CreateScreenResources); + + if (!ret) + return ret; + + /* Make sure we have a valid screen pixmap. */ + + RootlessUpdateScreenPixmap(pScreen); + + return ret; +} + + +static Bool +RootlessCloseScreen(int i, ScreenPtr pScreen) +{ + RootlessScreenRec *s; + + s = SCREENREC(pScreen); + + // fixme unwrap everything that was wrapped? + pScreen->CloseScreen = s->CloseScreen; + + if (s->pixmap_data != NULL) { + free(s->pixmap_data); + s->pixmap_data = NULL; + s->pixmap_data_size = 0; + } + + free(s); + return pScreen->CloseScreen(i, pScreen); +} + + +static void +RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planeMask, char *pdstLine) +{ + ScreenPtr pScreen = pDrawable->pScreen; + SCREEN_UNWRAP(pScreen, GetImage); + + if (pDrawable->type == DRAWABLE_WINDOW) { + int x0, y0, x1, y1; + RootlessWindowRec *winRec; + + // Many apps use GetImage to sync with the visible frame buffer + // FIXME: entire screen or just window or all screens? + RootlessRedisplayScreen(pScreen); + + // RedisplayScreen stops drawing, so we need to start it again + RootlessStartDrawing((WindowPtr)pDrawable); + + /* Check that we have some place to read from. */ + winRec = WINREC(TopLevelParent((WindowPtr) pDrawable)); + if (winRec == NULL) + goto out; + + /* Clip to top-level window bounds. */ + /* FIXME: fbGetImage uses the width parameter to calculate the + stride of the destination pixmap. If w is clipped, the data + returned will be garbage, although we will not crash. */ + + x0 = pDrawable->x + sx; + y0 = pDrawable->y + sy; + x1 = x0 + w; + y1 = y0 + h; + + x0 = max (x0, winRec->x); + y0 = max (y0, winRec->y); + x1 = min (x1, winRec->x + winRec->width); + y1 = min (y1, winRec->y + winRec->height); + + sx = x0 - pDrawable->x; + sy = y0 - pDrawable->y; + w = x1 - x0; + h = y1 - y0; + + if (w <= 0 || h <= 0) + goto out; + } + + pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); + +out: + SCREEN_WRAP(pScreen, GetImage); +} + + +/* + * RootlessSourceValidate + * CopyArea and CopyPlane use a GC tied to the destination drawable. + * StartDrawing/StopDrawing wrappers won't be called if source is + * a visible window but the destination isn't. So, we call StartDrawing + * here and leave StopDrawing for the block handler. + */ +static void +RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h) +{ + SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate); + if (pDrawable->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDrawable; + RootlessStartDrawing(pWin); + } + if (pDrawable->pScreen->SourceValidate) { + pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h); + } + SCREEN_WRAP(pDrawable->pScreen, SourceValidate); +} + +static void +RootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + WindowPtr srcWin, dstWin, maskWin = NULL; + + if (pMask) { // pMask can be NULL + maskWin = (pMask->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pMask->pDrawable : NULL; + } + srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pSrc->pDrawable : NULL; + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pDst->pDrawable : NULL; + + // SCREEN_UNWRAP(ps, Composite); + ps->Composite = SCREENREC(pScreen)->Composite; + + if (srcWin && IsFramedWindow(srcWin)) + RootlessStartDrawing(srcWin); + if (maskWin && IsFramedWindow(maskWin)) + RootlessStartDrawing(maskWin); + if (dstWin && IsFramedWindow(dstWin)) + RootlessStartDrawing(dstWin); + + ps->Composite(op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + if (dstWin && IsFramedWindow(dstWin)) { + RootlessDamageRect(dstWin, xDst, yDst, width, height); + } + + ps->Composite = RootlessComposite; + // SCREEN_WRAP(ps, Composite); +} + + +static void +RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int nlist, GlyphListPtr list, GlyphPtr *glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + int x, y; + int n; + GlyphPtr glyph; + WindowPtr srcWin, dstWin; + + srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pSrc->pDrawable : NULL; + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pDst->pDrawable : NULL; + + if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin); + if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin); + + //SCREEN_UNWRAP(ps, Glyphs); + ps->Glyphs = SCREENREC(pScreen)->Glyphs; + ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); + ps->Glyphs = RootlessGlyphs; + //SCREEN_WRAP(ps, Glyphs); + + if (dstWin && IsFramedWindow(dstWin)) { + x = xSrc; + y = ySrc; + + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + + /* Calling DamageRect for the bounding box of each glyph is + inefficient. So compute the union of all glyphs in a list + and damage that. */ + + if (n > 0) { + BoxRec box; + + glyph = *glyphs++; + + box.x1 = x - glyph->info.x; + box.y1 = y - glyph->info.y; + box.x2 = box.x1 + glyph->info.width; + box.y2 = box.y2 + glyph->info.height; + + x += glyph->info.xOff; + y += glyph->info.yOff; + + while (--n > 0) { + short x1, y1, x2, y2; + + glyph = *glyphs++; + + x1 = x - glyph->info.x; + y1 = y - glyph->info.y; + x2 = x1 + glyph->info.width; + y2 = y1 + glyph->info.height; + + box.x1 = max (box.x1, x1); + box.y1 = max (box.y1, y1); + box.x2 = max (box.x2, x2); + box.y2 = max (box.y2, y2); + + x += glyph->info.xOff; + y += glyph->info.yOff; + } + + RootlessDamageBox(dstWin, &box); + } + list++; + } + } +} + + +/* + * RootlessValidateTree + * ValidateTree is modified in two ways: + * - top-level windows don't clip each other + * - windows aren't clipped against root. + * These only matter when validating from the root. + */ +static int +RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + int result; + RegionRec saveRoot; + ScreenPtr pScreen = pParent->drawable.pScreen; + + SCREEN_UNWRAP(pScreen, ValidateTree); + RL_DEBUG_MSG("VALIDATETREE start "); + + // Use our custom version to validate from root + if (IsRoot(pParent)) { + RL_DEBUG_MSG("custom "); + result = RootlessMiValidateTree(pParent, pChild, kind); + } else { + HUGE_ROOT(pParent); + result = pScreen->ValidateTree(pParent, pChild, kind); + NORMAL_ROOT(pParent); + } + + SCREEN_WRAP(pScreen, ValidateTree); + RL_DEBUG_MSG("VALIDATETREE end\n"); + + return result; +} + + +/* + * RootlessMarkOverlappedWindows + * MarkOverlappedWindows is modified to ignore overlapping + * top-level windows. + */ +static Bool +RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst, + WindowPtr *ppLayerWin) +{ + RegionRec saveRoot; + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + SCREEN_UNWRAP(pScreen, MarkOverlappedWindows); + RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start "); + + HUGE_ROOT(pWin); + if (IsRoot(pWin)) { + // root - mark nothing + RL_DEBUG_MSG("is root not marking "); + result = FALSE; + } + else if (! IsTopLevel(pWin)) { + // not top-level window - mark normally + result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin); + } + else { + //top-level window - mark children ONLY - NO overlaps with sibs (?) + // This code copied from miMarkOverlappedWindows() + + register WindowPtr pChild; + Bool anyMarked = FALSE; + MarkWindowProcPtr MarkWindow = pScreen->MarkWindow; + + RL_DEBUG_MSG("is top level! "); + /* single layered systems are easy */ + if (ppLayerWin) *ppLayerWin = pWin; + + if (pWin == pFirst) { + /* Blindly mark pWin and all of its inferiors. This is a slight + * overkill if there are mapped windows that outside pWin's border, + * but it's better than wasting time on RectIn checks. + */ + pChild = pWin; + while (1) { + if (pChild->viewable) { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + (* MarkWindow)(pChild); + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } + anyMarked = TRUE; + pFirst = pFirst->nextSib; + } + if (anyMarked) + (* MarkWindow)(pWin->parent); + result = anyMarked; + } + NORMAL_ROOT(pWin); + SCREEN_WRAP(pScreen, MarkOverlappedWindows); + RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n"); + + return result; +} + +static void expose_1 (WindowPtr pWin) { + WindowPtr pChild; + + if (!pWin->realized) + return; + + miPaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND); + + /* FIXME: comments in windowstr.h indicate that borderClip doesn't + include subwindow visibility. But I'm not so sure.. so we may + be exposing too much.. */ + + miSendExposures (pWin, &pWin->borderClip, + pWin->drawable.x, pWin->drawable.y); + + for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib) + expose_1 (pChild); +} + +void +RootlessScreenExpose (ScreenPtr pScreen) +{ + expose_1 (WindowTable[pScreen->myNum]); +} + + +ColormapPtr +RootlessGetColormap (ScreenPtr pScreen) +{ + RootlessScreenRec *s = SCREENREC (pScreen); + + return s->colormap; +} + +static void +RootlessInstallColormap (ColormapPtr pMap) +{ + ScreenPtr pScreen = pMap->pScreen; + RootlessScreenRec *s = SCREENREC (pScreen); + + SCREEN_UNWRAP(pScreen, InstallColormap); + + if (s->colormap != pMap) { + s->colormap = pMap; + s->colormap_changed = TRUE; + RootlessQueueRedisplay (pScreen); + } + + pScreen->InstallColormap (pMap); + + SCREEN_WRAP (pScreen, InstallColormap); +} + +static void +RootlessUninstallColormap (ColormapPtr pMap) +{ + ScreenPtr pScreen = pMap->pScreen; + RootlessScreenRec *s = SCREENREC (pScreen); + + SCREEN_UNWRAP(pScreen, UninstallColormap); + + if (s->colormap == pMap) + s->colormap = NULL; + + pScreen->UninstallColormap (pMap); + + SCREEN_WRAP(pScreen, UninstallColormap); +} + +static void +RootlessStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef) +{ + ScreenPtr pScreen = pMap->pScreen; + RootlessScreenRec *s = SCREENREC (pScreen); + + SCREEN_UNWRAP(pScreen, StoreColors); + + if (s->colormap == pMap && ndef > 0) { + s->colormap_changed = TRUE; + RootlessQueueRedisplay (pScreen); + } + + pScreen->StoreColors (pMap, ndef, pdef); + + SCREEN_WRAP(pScreen, StoreColors); +} + + +static CARD32 +RootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg) +{ + RootlessScreenRec *screenRec = arg; + + if (!screenRec->redisplay_queued) { + /* No update needed. Stop the timer. */ + + screenRec->redisplay_timer_set = FALSE; + return 0; + } + + screenRec->redisplay_queued = FALSE; + + /* Mark that we should redisplay before waiting for I/O next time */ + screenRec->redisplay_expired = TRUE; + + /* Reinstall the timer immediately, so we get as close to our + redisplay interval as possible. */ + + return ROOTLESS_REDISPLAY_DELAY; +} + + +/* + * RootlessQueueRedisplay + * Queue a redisplay after a timer delay to ensure we do not redisplay + * too frequently. + */ +void +RootlessQueueRedisplay(ScreenPtr pScreen) +{ + RootlessScreenRec *screenRec = SCREENREC(pScreen); + + screenRec->redisplay_queued = TRUE; + + if (screenRec->redisplay_timer_set) + return; + + screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer, + 0, ROOTLESS_REDISPLAY_DELAY, + RootlessRedisplayCallback, + screenRec); + screenRec->redisplay_timer_set = TRUE; +} + + +/* + * RootlessBlockHandler + * If the redisplay timer has expired, flush drawing before blocking + * on select(). + */ +static void +RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = pbdata; + RootlessScreenRec *screenRec = SCREENREC(pScreen); + + if (screenRec->redisplay_expired) { + screenRec->redisplay_expired = FALSE; + + RootlessRedisplayScreen(pScreen); + } +} + + +static void +RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask) +{ + // nothing here +} + + +static Bool +RootlessAllocatePrivates(ScreenPtr pScreen) +{ + RootlessScreenRec *s; + + // no allocation needed for screen privates + if (!dixRequestPrivate(rootlessGCPrivateKey, sizeof(RootlessGCRec))) + return FALSE; + + s = malloc(sizeof(RootlessScreenRec)); + if (! s) return FALSE; + SETSCREENREC(pScreen, s); + + s->pixmap_data = NULL; + s->pixmap_data_size = 0; + + s->redisplay_timer = NULL; + s->redisplay_timer_set = FALSE; + + return TRUE; +} + + +static void +RootlessWrap(ScreenPtr pScreen) +{ + RootlessScreenRec *s = SCREENREC(pScreen); + +#define WRAP(a) \ + if (pScreen->a) { \ + s->a = pScreen->a; \ + } else { \ + RL_DEBUG_MSG("null screen fn " #a "\n"); \ + s->a = NULL; \ + } \ + pScreen->a = Rootless##a + + WRAP(CreateScreenResources); + WRAP(CloseScreen); + WRAP(CreateGC); + WRAP(CopyWindow); + WRAP(GetImage); + WRAP(SourceValidate); + WRAP(CreateWindow); + WRAP(DestroyWindow); + WRAP(RealizeWindow); + WRAP(UnrealizeWindow); + WRAP(MoveWindow); + WRAP(PositionWindow); + WRAP(ResizeWindow); + WRAP(RestackWindow); + WRAP(ReparentWindow); + WRAP(ChangeBorderWidth); + WRAP(MarkOverlappedWindows); + WRAP(ValidateTree); + WRAP(ChangeWindowAttributes); + WRAP(InstallColormap); + WRAP(UninstallColormap); + WRAP(StoreColors); + + WRAP(SetShape); + + { + // Composite and Glyphs don't use normal screen wrapping + PictureScreenPtr ps = GetPictureScreen(pScreen); + s->Composite = ps->Composite; + ps->Composite = RootlessComposite; + s->Glyphs = ps->Glyphs; + ps->Glyphs = RootlessGlyphs; + } + + // WRAP(ClearToBackground); fixme put this back? useful for shaped wins? + +#undef WRAP +} + + +/* + * RootlessInit + * Called by the rootless implementation to initialize the rootless layer. + * Rootless wraps lots of stuff and needs a bunch of devPrivates. + */ +Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs) +{ + RootlessScreenRec *s; + + if (!RootlessAllocatePrivates(pScreen)) + return FALSE; + + s = SCREENREC(pScreen); + + s->imp = procs; + s->colormap = NULL; + s->redisplay_expired = FALSE; + + RootlessWrap(pScreen); + + if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler, + RootlessWakeupHandler, + (pointer) pScreen)) + { + return FALSE; + } + + return TRUE; +} + +void RootlessUpdateRooted (Bool state) { + int i; + + if (!state) + { + for (i = 0; i < screenInfo.numScreens; i++) + RootlessDisableRoot (screenInfo.screens[i]); + } + else + { + for (i = 0; i < screenInfo.numScreens; i++) + RootlessEnableRoot (screenInfo.screens[i]); + } +} diff --git a/xorg-server/miext/rootless/rootlessWindow.c b/xorg-server/miext/rootless/rootlessWindow.c index 55c7b9689..2f412ee43 100644 --- a/xorg-server/miext/rootless/rootlessWindow.c +++ b/xorg-server/miext/rootless/rootlessWindow.c @@ -1,1656 +1,1656 @@ -/* - * Rootless window management - */ -/* - * Copyright (c) 2001 Greg Parker. All Rights Reserved. - * Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved. - * Copyright (c) 2002 Apple Computer, 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright - * holders shall not be used in advertising or otherwise to promote the sale, - * use or other dealings in this Software without prior written authorization. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <stddef.h> /* For NULL */ -#include <limits.h> /* For CHAR_BIT */ -#include <assert.h> -#include <X11/Xatom.h> -#ifdef __APPLE__ -#include <Xplugin.h> -#include "mi.h" -#include "pixmapstr.h" -#include "windowstr.h" -//#include <X11/extensions/applewm.h> -extern int darwinMainScreenX, darwinMainScreenY; -extern Bool no_configure_window; -#endif -#include "fb.h" - -#include "rootlessCommon.h" -#include "rootlessWindow.h" - -#ifdef ROOTLESS_GLOBAL_COORDS -#define SCREEN_TO_GLOBAL_X \ - (dixScreenOrigins[pScreen->myNum].x + rootlessGlobalOffsetX) -#define SCREEN_TO_GLOBAL_Y \ - (dixScreenOrigins[pScreen->myNum].y + rootlessGlobalOffsetY) -#else -#define SCREEN_TO_GLOBAL_X 0 -#define SCREEN_TO_GLOBAL_Y 0 -#endif - -#define DEFINE_ATOM_HELPER(func,atom_name) \ - static Atom func (void) { \ - static unsigned int generation = 0; \ - static Atom atom; \ - if (generation != serverGeneration) { \ - generation = serverGeneration; \ - atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ - } \ - return atom; \ - } - -DEFINE_ATOM_HELPER (xa_native_window_id, "_NATIVE_WINDOW_ID") - -static Bool windows_hidden; -// TODO - abstract xp functions - -#ifdef __APPLE__ - -// XXX: identical to x_cvt_vptr_to_uint ? -#define MAKE_WINDOW_ID(x) ((xp_window_id)((size_t)(x))) - -void -RootlessNativeWindowStateChanged (WindowPtr pWin, unsigned int state) -{ - RootlessWindowRec *winRec; - - if (pWin == NULL) return; - - winRec = WINREC (pWin); - if (winRec == NULL) return; - - winRec->is_offscreen = ((state & XP_WINDOW_STATE_OFFSCREEN) != 0); - winRec->is_obscured = ((state & XP_WINDOW_STATE_OBSCURED) != 0); - pWin->rootlessUnhittable = winRec->is_offscreen; -} - -void RootlessNativeWindowMoved (WindowPtr pWin) { - xp_box bounds; - int sx, sy, err; - XID vlist[2]; - Mask mask; - ClientPtr pClient; - RootlessWindowRec *winRec; - - winRec = WINREC(pWin); - - if (xp_get_window_bounds (MAKE_WINDOW_ID(winRec->wid), &bounds) != Success) return; - - sx = dixScreenOrigins[pWin->drawable.pScreen->myNum].x + darwinMainScreenX; - sy = dixScreenOrigins[pWin->drawable.pScreen->myNum].y + darwinMainScreenY; - - /* Fake up a ConfigureWindow packet to resize the window to the current bounds. */ - vlist[0] = (INT16) bounds.x1 - sx; - vlist[1] = (INT16) bounds.y1 - sy; - mask = CWX | CWY; - - /* pretend we're the owner of the window! */ - err = dixLookupClient(&pClient, pWin->drawable.id, serverClient, DixUnknownAccess); - if(err != Success) { - ErrorF("RootlessNativeWindowMoved(): Failed to lookup window: 0x%x\n", (unsigned int)pWin->drawable.id); - return; - } - - /* Don't want to do anything to the physical window (avoids - notification-response feedback loops) */ - - no_configure_window = TRUE; - ConfigureWindow (pWin, mask, vlist, pClient); - no_configure_window = FALSE; -} - -#endif /* __APPLE__ */ - -/* - * RootlessCreateWindow - * For now, don't create a physical window until either the window is - * realized, or we really need it (e.g. to attach VRAM surfaces to). - * Do reset the window size so it's not clipped by the root window. - */ -Bool -RootlessCreateWindow(WindowPtr pWin) -{ - Bool result; - RegionRec saveRoot; - - SETWINREC(pWin, NULL); - dixSetPrivate(&pWin->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL); - - SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow); - - if (!IsRoot(pWin)) { - /* win/border size set by DIX, not by wrapped CreateWindow, so - correct it here. Don't HUGE_ROOT when pWin is the root! */ - - HUGE_ROOT(pWin); - SetWinSize(pWin); - SetBorderSize(pWin); - } - - result = pWin->drawable.pScreen->CreateWindow(pWin); - - if (pWin->parent) { - NORMAL_ROOT(pWin); - } - - SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow); - - return result; -} - - -/* - * RootlessDestroyFrame - * Destroy the physical window associated with the given window. - */ -static void -RootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - SCREENREC(pScreen)->imp->DestroyFrame(winRec->wid); - -#ifdef ROOTLESS_TRACK_DAMAGE - REGION_UNINIT(pScreen, &winRec->damage); -#endif - - xfree(winRec); - SETWINREC(pWin, NULL); -} - - -/* - * RootlessDestroyWindow - * Destroy the physical window associated with the given window. - */ -Bool -RootlessDestroyWindow(WindowPtr pWin) -{ - RootlessWindowRec *winRec = WINREC(pWin); - Bool result; - - if (winRec != NULL) { - RootlessDestroyFrame(pWin, winRec); - } - - SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow); - result = pWin->drawable.pScreen->DestroyWindow(pWin); - SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow); - - return result; -} - - - -static Bool -RootlessGetShape(WindowPtr pWin, RegionPtr pShape) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - /* - * Avoid a warning. - * REGION_NULL and the other macros don't actually seem to use pScreen. - */ - (void)pScreen; - - if (wBoundingShape(pWin) == NULL) - return FALSE; - - /* wBoundingShape is relative to *inner* origin of window. - Translate by borderWidth to get the outside-relative position. */ - - REGION_NULL(pScreen, pShape); - REGION_COPY(pScreen, pShape, wBoundingShape(pWin)); - REGION_TRANSLATE(pScreen, pShape, pWin->borderWidth, pWin->borderWidth); - - return TRUE; -} - - -/* - * RootlessReshapeFrame - * Set the frame shape. - */ -static void RootlessReshapeFrame(WindowPtr pWin) -{ - RootlessWindowRec *winRec = WINREC(pWin); - ScreenPtr pScreen = pWin->drawable.pScreen; - RegionRec newShape; - RegionPtr pShape; - - // If the window is not yet framed, do nothing - if (winRec == NULL) - return; - - if (IsRoot(pWin)) - return; - - RootlessStopDrawing(pWin, FALSE); - - pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL; - -#ifdef ROOTLESSDEBUG - RL_DEBUG_MSG("reshaping..."); - if (pShape != NULL) { - RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ", - REGION_NUM_RECTS(&newShape), - newShape.extents.x1, newShape.extents.y1, - newShape.extents.x2, newShape.extents.y2); - } else { - RL_DEBUG_MSG("no shape "); - } -#endif - - SCREENREC(pScreen)->imp->ReshapeFrame(winRec->wid, pShape); - - if (pShape != NULL) - REGION_UNINIT(pScreen, &newShape); -} - - -/* - * RootlessSetShape - * Shape is usually set before a window is mapped and the window will - * not have a frame associated with it. In this case, the frame will be - * shaped when the window is framed. - */ -void -RootlessSetShape(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - SCREEN_UNWRAP(pScreen, SetShape); - pScreen->SetShape(pWin); - SCREEN_WRAP(pScreen, SetShape); - - RootlessReshapeFrame(pWin); -} - - - -/* Disallow ParentRelative background on top-level windows - because the root window doesn't really have the right background. - */ -Bool -RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask) -{ - Bool result; - ScreenPtr pScreen = pWin->drawable.pScreen; - - RL_DEBUG_MSG("change window attributes start "); - - SCREEN_UNWRAP(pScreen, ChangeWindowAttributes); - result = pScreen->ChangeWindowAttributes(pWin, vmask); - SCREEN_WRAP(pScreen, ChangeWindowAttributes); - - if (WINREC(pWin)) { - // disallow ParentRelative background state - if (pWin->backgroundState == ParentRelative) { - XID pixel = 0; - ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); - } - } - - RL_DEBUG_MSG("change window attributes end\n"); - return result; -} - - -/* - * RootlessPositionWindow - * This is a hook for when DIX moves or resizes a window. - * Update the frame position now although the physical window is moved - * in RootlessMoveWindow. (x, y) are *inside* position. After this, - * mi and fb are expecting the pixmap to be at the new location. - */ -Bool -RootlessPositionWindow(WindowPtr pWin, int x, int y) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - RootlessWindowRec *winRec = WINREC(pWin); - Bool result; - - RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y); - - if (winRec) { - if (winRec->is_drawing) { - // Reset frame's pixmap and move it to the new position. - int bw = wBorderWidth(pWin); - - winRec->pixmap->devPrivate.ptr = winRec->pixelData; - SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw); - -#ifdef ROOTLESS_TRACK_DAMAGE - // Move damaged region to correspond to new window position - if (REGION_NOTEMPTY(pScreen, &winRec->damage)) { - REGION_TRANSLATE(pScreen, &winRec->damage, - x - bw - winRec->x, - y - bw - winRec->y); - } -#endif - } - } - - SCREEN_UNWRAP(pScreen, PositionWindow); - result = pScreen->PositionWindow(pWin, x, y); - SCREEN_WRAP(pScreen, PositionWindow); - - RL_DEBUG_MSG("positionwindow end\n"); - return result; -} - - -/* - * RootlessInitializeFrame - * Initialize some basic attributes of the frame. Note that winRec - * may already have valid data in it, so don't overwrite anything - * valuable. - */ -static void -RootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec *winRec) -{ - DrawablePtr d = &pWin->drawable; - int bw = wBorderWidth(pWin); - - winRec->win = pWin; - - winRec->x = d->x - bw; - winRec->y = d->y - bw; - winRec->width = d->width + 2*bw; - winRec->height = d->height + 2*bw; - winRec->borderWidth = bw; - -#ifdef ROOTLESS_TRACK_DAMAGE - REGION_NULL(pScreen, &winRec->damage); -#endif -} - -/* - * RootlessEnsureFrame - * Make sure the given window is framed. If the window doesn't have a - * physical window associated with it, attempt to create one. If that - * is unsuccessful, return NULL. - */ -static RootlessWindowRec * -RootlessEnsureFrame(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - RootlessWindowRec *winRec; - RegionRec shape; - RegionPtr pShape = NULL; - - if (WINREC(pWin) != NULL) - return WINREC(pWin); - - if (!IsTopLevel(pWin) && !IsRoot(pWin)) - return NULL; - - if (pWin->drawable.class != InputOutput) - return NULL; - - winRec = xalloc(sizeof(RootlessWindowRec)); - - if (!winRec) - return NULL; - - RootlessInitializeFrame(pWin, winRec); - - winRec->is_drawing = FALSE; - winRec->is_reorder_pending = FALSE; - winRec->pixmap = NULL; - winRec->wid = NULL; - winRec->level = 0; - - SETWINREC(pWin, winRec); - - // Set the frame's shape if the window is shaped - if (RootlessGetShape(pWin, &shape)) - pShape = &shape; - - RL_DEBUG_MSG("creating frame "); - - if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen, - winRec->x + SCREEN_TO_GLOBAL_X, - winRec->y + SCREEN_TO_GLOBAL_Y, - pShape)) - { - RL_DEBUG_MSG("implementation failed to create frame!\n"); - xfree(winRec); - SETWINREC(pWin, NULL); - return NULL; - } - - if (pWin->drawable.depth == 8) - RootlessFlushWindowColormap(pWin); - - if (pShape != NULL) - REGION_UNINIT(pScreen, &shape); - - return winRec; -} - - -/* - * RootlessRealizeWindow - * The frame is usually created here and not in CreateWindow so that - * windows do not eat memory until they are realized. - */ -Bool -RootlessRealizeWindow(WindowPtr pWin) -{ - Bool result; - RegionRec saveRoot; - ScreenPtr pScreen = pWin->drawable.pScreen; - - RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin); - - if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) { - RootlessWindowRec *winRec; - - winRec = RootlessEnsureFrame(pWin); - if (winRec == NULL) - return FALSE; - - winRec->is_reorder_pending = TRUE; - - RL_DEBUG_MSG("Top level window "); - - // Disallow ParentRelative background state on top-level windows. - // This might have been set before the window was mapped. - if (pWin->backgroundState == ParentRelative) { - XID pixel = 0; - ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); - } - } - - if (!IsRoot(pWin)) HUGE_ROOT(pWin); - SCREEN_UNWRAP(pScreen, RealizeWindow); - result = pScreen->RealizeWindow(pWin); - SCREEN_WRAP(pScreen, RealizeWindow); - if (!IsRoot(pWin)) NORMAL_ROOT(pWin); - - RL_DEBUG_MSG("realizewindow end\n"); - return result; -} - - -/* - * RootlessFrameForWindow - * Returns the frame ID for the physical window displaying the given window. - * If CREATE is true and the window has no frame, attempt to create one. - */ -RootlessFrameID -RootlessFrameForWindow(WindowPtr pWin, Bool create) -{ - WindowPtr pTopWin; - RootlessWindowRec *winRec; - - pTopWin = TopLevelParent(pWin); - if (pTopWin == NULL) - return NULL; - - winRec = WINREC(pTopWin); - - if (winRec == NULL && create && pWin->drawable.class == InputOutput) { - winRec = RootlessEnsureFrame(pTopWin); - } - - if (winRec == NULL) - return NULL; - - return winRec->wid; -} - - -/* - * RootlessUnrealizeWindow - * Unmap the physical window. - */ -Bool -RootlessUnrealizeWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - RootlessWindowRec *winRec = WINREC(pWin); - Bool result; - - RL_DEBUG_MSG("unrealizewindow start "); - - if (winRec) { - RootlessStopDrawing(pWin, FALSE); - - SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid); - - winRec->is_reorder_pending = FALSE; - } - - SCREEN_UNWRAP(pScreen, UnrealizeWindow); - result = pScreen->UnrealizeWindow(pWin); - SCREEN_WRAP(pScreen, UnrealizeWindow); - - RL_DEBUG_MSG("unrealizewindow end\n"); - return result; -} - - -/* - * RootlessReorderWindow - * Reorder the frame associated with the given window so that it's - * physically above the window below it in the X stacking order. - */ -void -RootlessReorderWindow(WindowPtr pWin) -{ - RootlessWindowRec *winRec = WINREC(pWin); - - if (pWin->realized && winRec != NULL && !winRec->is_reorder_pending && !windows_hidden) { - WindowPtr newPrevW; - RootlessWindowRec *newPrev; - RootlessFrameID newPrevID; - ScreenPtr pScreen = pWin->drawable.pScreen; - - /* Check if the implementation wants the frame to not be reordered - even though the X11 window is restacked. This can be useful if - frames are ordered-in with animation so that the reordering is not - done until the animation is complete. */ - if (SCREENREC(pScreen)->imp->DoReorderWindow) { - if (!SCREENREC(pScreen)->imp->DoReorderWindow(winRec)) - return; - } - - RootlessStopDrawing(pWin, FALSE); - - /* Find the next window above this one that has a mapped frame. */ - - newPrevW = pWin->prevSib; - while (newPrevW && (WINREC(newPrevW) == NULL || !newPrevW->realized)) - newPrevW = newPrevW->prevSib; - - newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL; - newPrevID = newPrev != NULL ? newPrev->wid : 0; - - /* If it exists, reorder the frame above us first. */ - - if (newPrev && newPrev->is_reorder_pending) { - newPrev->is_reorder_pending = FALSE; - RootlessReorderWindow(newPrevW); - } - - SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID); - } -} - - -/* - * RootlessRestackWindow - * This is a hook for when DIX changes the window stacking order. - * The window has already been inserted into its new position in the - * DIX window stack. We need to change the order of the physical - * window to match. - */ -void -RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib) -{ - RegionRec saveRoot; - RootlessWindowRec *winRec = WINREC(pWin); - ScreenPtr pScreen = pWin->drawable.pScreen; - - RL_DEBUG_MSG("restackwindow start "); - if (winRec) - RL_DEBUG_MSG("restack top level \n"); - - HUGE_ROOT(pWin); - SCREEN_UNWRAP(pScreen, RestackWindow); - - if (pScreen->RestackWindow) - pScreen->RestackWindow(pWin, pOldNextSib); - - SCREEN_WRAP(pScreen, RestackWindow); - NORMAL_ROOT(pWin); - - if (winRec && pWin->viewable) { - RootlessReorderWindow(pWin); - } - - RL_DEBUG_MSG("restackwindow end\n"); -} - -/* - * Specialized window copy procedures - */ - -// Globals needed during window resize and move. -static pointer gResizeDeathBits = NULL; -static int gResizeDeathCount = 0; -static PixmapPtr gResizeDeathPix[2] = {NULL, NULL}; -static BoxRec gResizeDeathBounds[2]; -static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL; - -/* - * RootlessNoCopyWindow - * CopyWindow() that doesn't do anything. For MoveWindow() of - * top-level windows. - */ -static void -RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, - RegionPtr prgnSrc) -{ - // some code expects the region to be translated - int dx = ptOldOrg.x - pWin->drawable.x; - int dy = ptOldOrg.y - pWin->drawable.y; - - RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW "); - - REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); -} - - -/* - * RootlessResizeCopyWindow - * CopyWindow used during ResizeWindow for gravity moves. Based on - * fbCopyWindow. The original always draws on the root pixmap, which - * we don't have. Instead, draw on the parent window's pixmap. - * Resize version: the old location's pixels are in gResizeCopyWindowSource. - */ -static void -RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, - RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - RegionRec rgnDst; - int dx, dy; - - RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin); - - /* Don't unwrap pScreen->CopyWindow. - The bogus rewrap with RootlessCopyWindow causes a crash if - CopyWindow is called again during the same resize. */ - - if (gResizeDeathCount == 0) - return; - - RootlessStartDrawing(pWin); - - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); - REGION_NULL(pScreen, &rgnDst); - REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); - - if (gResizeDeathCount == 1) { - /* Simple case, we only have a single source pixmap. */ - - fbCopyRegion(&gResizeDeathPix[0]->drawable, - &pScreen->GetWindowPixmap(pWin)->drawable, 0, - &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); - } - else { - int i; - RegionRec clip, clipped; - - /* More complex case, N source pixmaps (usually two). So we - intersect the destination with each source and copy those bits. */ - - for (i = 0; i < gResizeDeathCount; i++) { - REGION_INIT(pScreen, &clip, gResizeDeathBounds + 0, 1); - REGION_NULL(pScreen, &clipped); - REGION_INTERSECT(pScreen, &rgnDst, &clip, &clipped); - - fbCopyRegion(&gResizeDeathPix[i]->drawable, - &pScreen->GetWindowPixmap(pWin)->drawable, 0, - &clipped, dx, dy, fbCopyWindowProc, 0, 0); - - REGION_UNINIT(pScreen, &clipped); - REGION_UNINIT(pScreen, &clip); - } - } - - /* Don't update - resize will update everything */ - REGION_UNINIT(pScreen, &rgnDst); - - fbValidateDrawable(&pWin->drawable); - - RL_DEBUG_MSG("resizecopywindowFB end\n"); -} - - -/* - * RootlessCopyWindow - * Update *new* location of window. Old location is redrawn with - * miPaintWindow. Cloned from fbCopyWindow. - * The original always draws on the root pixmap, which we don't have. - * Instead, draw on the parent window's pixmap. - */ -void -RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - RegionRec rgnDst; - int dx, dy; - BoxPtr extents; - int area; - - RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin); - - SCREEN_UNWRAP(pScreen, CopyWindow); - - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); - - REGION_NULL(pScreen, &rgnDst); - REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); - - extents = REGION_EXTENTS(pScreen, &rgnDst); - area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1); - - /* If the area exceeds threshold, use the implementation's - accelerated version. */ - if (area > rootless_CopyWindow_threshold && - SCREENREC(pScreen)->imp->CopyWindow) - { - RootlessWindowRec *winRec; - WindowPtr top; - - top = TopLevelParent(pWin); - if (top == NULL) { - RL_DEBUG_MSG("no parent\n"); - goto out; - } - - winRec = WINREC(top); - if (winRec == NULL) { - RL_DEBUG_MSG("not framed\n"); - goto out; - } - - /* Move region to window local coords */ - REGION_TRANSLATE(pScreen, &rgnDst, -winRec->x, -winRec->y); - - RootlessStopDrawing(pWin, FALSE); - - SCREENREC(pScreen)->imp->CopyWindow(winRec->wid, - REGION_NUM_RECTS(&rgnDst), - REGION_RECTS(&rgnDst), - dx, dy); - } - else { - RootlessStartDrawing(pWin); - - fbCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin, - 0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); - - /* prgnSrc has been translated to dst position */ - RootlessDamageRegion(pWin, prgnSrc); - } - -out: - REGION_UNINIT(pScreen, &rgnDst); - fbValidateDrawable(&pWin->drawable); - - SCREEN_WRAP(pScreen, CopyWindow); - - RL_DEBUG_MSG("copywindowFB end\n"); -} - - -/* - * Window resize procedures - */ - -enum { - WIDTH_SMALLER = 1, - HEIGHT_SMALLER = 2, -}; - - -/* - * ResizeWeighting - * Choose gravity to avoid local copies. Do that by looking for - * a corner that doesn't move _relative to the screen_. - */ -static inline unsigned int -ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW, - int newX1, int newY1, int newX2, int newY2, int newBW) -{ -#ifdef ROOTLESS_RESIZE_GRAVITY - if (newBW != oldBW) - return RL_GRAVITY_NONE; - - if (newX1 == oldX1 && newY1 == oldY1) - return RL_GRAVITY_NORTH_WEST; - else if (newX1 == oldX1 && newY2 == oldY2) - return RL_GRAVITY_SOUTH_WEST; - else if (newX2 == oldX2 && newY2 == oldY2) - return RL_GRAVITY_SOUTH_EAST; - else if (newX2 == oldX2 && newY1 == oldY1) - return RL_GRAVITY_NORTH_EAST; - else - return RL_GRAVITY_NONE; -#else - return RL_GRAVITY_NONE; -#endif -} - - -/* - * StartFrameResize - * Prepare to resize a top-level window. The old window's pixels are - * saved and the implementation is told to change the window size. - * (x,y,w,h) is outer frame of window (outside border) - */ -static Bool -StartFrameResize(WindowPtr pWin, Bool gravity, - int oldX, int oldY, int oldW, int oldH, int oldBW, - int newX, int newY, int newW, int newH, int newBW) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - RootlessWindowRec *winRec = WINREC(pWin); - Bool need_window_source = FALSE, resize_after = FALSE; - - BoxRec rect; - int oldX2, newX2; - int oldY2, newY2; - unsigned int weight; - - oldX2 = oldX + oldW, newX2 = newX + newW; - oldY2 = oldY + oldH, newY2 = newY + newH; - - /* Decide which resize weighting to use */ - weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW, - newX, newY, newW, newH, newBW); - - /* Compute intersection between old and new rects */ - rect.x1 = max(oldX, newX); - rect.y1 = max(oldY, newY); - rect.x2 = min(oldX2, newX2); - rect.y2 = min(oldY2, newY2); - - RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity); - RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n", - oldX, oldY, oldW, oldH, oldBW, - newX, newY, newW, newH, newBW); - - RootlessRedisplay(pWin); - - /* If gravity is true, then we need to have a way of recovering all - the original bits in the window for when X rearranges the contents - based on the various gravity settings. The obvious way is to just - snapshot the entire backing store before resizing it, but that - it slow on large windows. - - So the optimization here is to use the implementation's resize - weighting options (if available) to allow us to reason about what - is left in the backing store after the resize. We can then only - copy what won't be there after the resize, and do a two-stage copy - operation. - - Most of these optimizations are only applied when the top-left - corner of the window is fixed, since that's the common case. They - could probably be extended with some thought. */ - - gResizeDeathCount = 0; - - if (gravity && weight == RL_GRAVITY_NORTH_WEST) { - unsigned int code = 0; - - /* Top left corner is anchored. We never need to copy the - entire window. */ - - need_window_source = TRUE; - - /* These comparisons were chosen to avoid setting bits when the sizes - are the same. (So the fastest case automatically gets taken when - dimensions are unchanging.) */ - - if (newW < oldW) - code |= WIDTH_SMALLER; - if (newH < oldH) - code |= HEIGHT_SMALLER; - - if (((code ^ (code >> 1)) & 1) == 0) { - /* Both dimensions are either getting larger, or both - are getting smaller. No need to copy anything. */ - - if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) { - /* Since the window is getting smaller, we can do gravity - repair on it with it's current size, then resize it - afterwards. */ - - resize_after = TRUE; - } - - gResizeDeathCount = 1; - } - else { - unsigned int copy_rowbytes, Bpp; - unsigned int copy_rect_width, copy_rect_height; - BoxRec copy_rect; - - /* We can get away with a partial copy. 'rect' is the - intersection between old and new bounds, so copy - everything to the right of or below the intersection. */ - - RootlessStartDrawing(pWin); - - if (code == WIDTH_SMALLER) { - copy_rect.x1 = rect.x2; - copy_rect.y1 = rect.y1; - copy_rect.x2 = oldX2; - copy_rect.y2 = oldY2; - } - else if (code == HEIGHT_SMALLER) { - copy_rect.x1 = rect.x1; - copy_rect.y1 = rect.y2; - copy_rect.x2 = oldX2; - copy_rect.y2 = oldY2; - } - else - OsAbort(); - - Bpp = winRec->win->drawable.bitsPerPixel / 8; - copy_rect_width = copy_rect.x2 - copy_rect.x1; - copy_rect_height = copy_rect.y2 - copy_rect.y1; - copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31; - gResizeDeathBits = xalloc(copy_rowbytes - * copy_rect_height); - - if (copy_rect_width * copy_rect_height > - rootless_CopyBytes_threshold && - SCREENREC(pScreen)->imp->CopyBytes) - { - SCREENREC(pScreen)->imp->CopyBytes( - copy_rect_width * Bpp, copy_rect_height, - ((char *) winRec->pixelData) - + ((copy_rect.y1 - oldY) * winRec->bytesPerRow) - + (copy_rect.x1 - oldX) * Bpp, winRec->bytesPerRow, - gResizeDeathBits, copy_rowbytes); - } else { - fbBlt((FbBits *) (winRec->pixelData - + ((copy_rect.y1 - oldY) * winRec->bytesPerRow) - + (copy_rect.x1 - oldX) * Bpp), - winRec->bytesPerRow / sizeof(FbBits), 0, - (FbBits *) gResizeDeathBits, - copy_rowbytes / sizeof(FbBits), 0, - copy_rect_width * Bpp, copy_rect_height, - GXcopy, FB_ALLONES, Bpp, 0, 0); - } - - gResizeDeathBounds[1] = copy_rect; - gResizeDeathPix[1] - = GetScratchPixmapHeader(pScreen, copy_rect_width, - copy_rect_height, - winRec->win->drawable.depth, - winRec->win->drawable.bitsPerPixel, - winRec->bytesPerRow, - (void *) gResizeDeathBits); - - SetPixmapBaseToScreen(gResizeDeathPix[1], - copy_rect.x1, copy_rect.y1); - - gResizeDeathCount = 2; - } - } - else if (gravity) { - /* The general case. Just copy everything. */ - - RootlessStartDrawing(pWin); - - gResizeDeathBits = xalloc(winRec->bytesPerRow * winRec->height); - - memcpy(gResizeDeathBits, winRec->pixelData, - winRec->bytesPerRow * winRec->height); - - gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2}; - gResizeDeathPix[0] - = GetScratchPixmapHeader(pScreen, winRec->width, - winRec->height, - winRec->win->drawable.depth, - winRec->win->drawable.bitsPerPixel, - winRec->bytesPerRow, - (void *) gResizeDeathBits); - - SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY); - gResizeDeathCount = 1; - } - - RootlessStopDrawing(pWin, FALSE); - - winRec->x = newX; - winRec->y = newY; - winRec->width = newW; - winRec->height = newH; - winRec->borderWidth = newBW; - - /* Unless both dimensions are getting smaller, Resize the frame - before doing gravity repair */ - - if (!resize_after) { - SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, - newX + SCREEN_TO_GLOBAL_X, - newY + SCREEN_TO_GLOBAL_Y, - newW, newH, weight); - } - - RootlessStartDrawing(pWin); - - /* If necessary, create a source pixmap pointing at the current - window bits. */ - - if (need_window_source) { - gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2}; - gResizeDeathPix[0] - = GetScratchPixmapHeader(pScreen, oldW, oldH, - winRec->win->drawable.depth, - winRec->win->drawable.bitsPerPixel, - winRec->bytesPerRow, winRec->pixelData); - - SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY); - } - - /* Use custom CopyWindow when moving gravity bits around - ResizeWindow assumes the old window contents are in the same - pixmap, but here they're in deathPix instead. */ - - if (gravity) { - gResizeOldCopyWindowProc = pScreen->CopyWindow; - pScreen->CopyWindow = RootlessResizeCopyWindow; - } - - /* If we can't rely on the window server preserving the bits we - need in the position we need, copy the pixels in the - intersection from src to dst. ResizeWindow assumes these pixels - are already present when making gravity adjustments. pWin - currently has new-sized pixmap but is in old position. - - FIXME: border width change! (?) */ - - if (gravity && weight == RL_GRAVITY_NONE) { - PixmapPtr src, dst; - - assert(gResizeDeathCount == 1); - - src = gResizeDeathPix[0]; - dst = pScreen->GetWindowPixmap(pWin); - - RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n", - rect.x1, rect.y1, rect.x2, rect.y2); - - /* rect is the intersection of the old location and new location */ - if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) { - /* The window drawable still has the old frame position, which - means that DST doesn't actually point at the origin of our - physical backing store when adjusted by the drawable.x,y - position. So sneakily adjust it temporarily while copying.. */ - - ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData; - SetPixmapBaseToScreen(dst, newX, newY); - - fbCopyWindowProc(&src->drawable, &dst->drawable, NULL, - &rect, 1, 0, 0, FALSE, FALSE, 0, 0); - - ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData; - SetPixmapBaseToScreen(dst, oldX, oldY); - } - } - - return resize_after; -} - - -static void -FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY, - unsigned int oldW, unsigned int oldH, unsigned int oldBW, - int newX, int newY, unsigned int newW, unsigned int newH, - unsigned int newBW, Bool resize_now) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - RootlessWindowRec *winRec = WINREC(pWin); - int i; - - RootlessStopDrawing(pWin, FALSE); - - if (resize_now) { - unsigned int weight; - - /* We didn't resize anything earlier, so do it now, now that - we've finished gravitating the bits. */ - - weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW, - newX, newY, newW, newH, newBW); - - SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, - newX + SCREEN_TO_GLOBAL_X, - newY + SCREEN_TO_GLOBAL_Y, - newW, newH, weight); - } - - /* Redraw everything. FIXME: there must be times when we don't need - to do this. Perhaps when top-left weighting and no gravity? */ - - RootlessDamageRect(pWin, -newBW, -newBW, newW, newH); - - for (i = 0; i < 2; i++) { - if (gResizeDeathPix[i] != NULL) { - FreeScratchPixmapHeader(gResizeDeathPix[i]); - gResizeDeathPix[i] = NULL; - } - } - - if (gResizeDeathBits != NULL) { - xfree(gResizeDeathBits); - gResizeDeathBits = NULL; - } - - if (gravity) { - pScreen->CopyWindow = gResizeOldCopyWindowProc; - } -} - - -/* - * RootlessMoveWindow - * If kind==VTOther, window border is resizing (and borderWidth is - * already changed!!@#$) This case works like window resize, not move. - */ -void -RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind) -{ - RootlessWindowRec *winRec = WINREC(pWin); - ScreenPtr pScreen = pWin->drawable.pScreen; - CopyWindowProcPtr oldCopyWindowProc = NULL; - int oldX = 0, oldY = 0, newX = 0, newY = 0; - unsigned int oldW = 0, oldH = 0, oldBW = 0; - unsigned int newW = 0, newH = 0, newBW = 0; - Bool resize_after = FALSE; - RegionRec saveRoot; - - RL_DEBUG_MSG("movewindow start \n"); - - if (winRec) { - if (kind == VTMove) { - oldX = winRec->x; - oldY = winRec->y; - RootlessRedisplay(pWin); - RootlessStartDrawing(pWin); - } else { - RL_DEBUG_MSG("movewindow border resizing "); - - oldBW = winRec->borderWidth; - oldX = winRec->x; - oldY = winRec->y; - oldW = winRec->width; - oldH = winRec->height; - - newBW = wBorderWidth(pWin); - newX = x; - newY = y; - newW = pWin->drawable.width + 2*newBW; - newH = pWin->drawable.height + 2*newBW; - - resize_after = StartFrameResize(pWin, FALSE, - oldX, oldY, oldW, oldH, oldBW, - newX, newY, newW, newH, newBW); - } - } - - HUGE_ROOT(pWin); - SCREEN_UNWRAP(pScreen, MoveWindow); - - if (winRec) { - oldCopyWindowProc = pScreen->CopyWindow; - pScreen->CopyWindow = RootlessNoCopyWindow; - } - pScreen->MoveWindow(pWin, x, y, pSib, kind); - if (winRec) { - pScreen->CopyWindow = oldCopyWindowProc; - } - - NORMAL_ROOT(pWin); - SCREEN_WRAP(pScreen, MoveWindow); - - if (winRec) { - if (kind == VTMove) { - winRec->x = x; - winRec->y = y; - RootlessStopDrawing(pWin, FALSE); - SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen, - x + SCREEN_TO_GLOBAL_X, - y + SCREEN_TO_GLOBAL_Y); - } else { - FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, - newX, newY, newW, newH, newBW, resize_after); - } - } - - RL_DEBUG_MSG("movewindow end\n"); -} - - -/* - * RootlessResizeWindow - * Note: (x, y, w, h) as passed to this procedure don't match the frame - * definition. (x,y) is corner of very outer edge, *outside* border. - * w,h is width and height *inside* border, *ignoring* border width. - * The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw) - * is total rect and (x+bw, y+bw, w, h) is inner rect. - */ -void -RootlessResizeWindow(WindowPtr pWin, int x, int y, - unsigned int w, unsigned int h, WindowPtr pSib) -{ - RootlessWindowRec *winRec = WINREC(pWin); - ScreenPtr pScreen = pWin->drawable.pScreen; - int oldX = 0, oldY = 0, newX = 0, newY = 0; - unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0; - Bool resize_after = FALSE; - RegionRec saveRoot; - - RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin); - - if(pWin->parent) { - if (winRec) { - oldBW = winRec->borderWidth; - oldX = winRec->x; - oldY = winRec->y; - oldW = winRec->width; - oldH = winRec->height; - - newBW = oldBW; - newX = x; - newY = y; - newW = w + 2*newBW; - newH = h + 2*newBW; - - resize_after = StartFrameResize(pWin, TRUE, - oldX, oldY, oldW, oldH, oldBW, - newX, newY, newW, newH, newBW); - } - - HUGE_ROOT(pWin); - SCREEN_UNWRAP(pScreen, ResizeWindow); - pScreen->ResizeWindow(pWin, x, y, w, h, pSib); - SCREEN_WRAP(pScreen, ResizeWindow); - NORMAL_ROOT(pWin); - - if (winRec) { - FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW, - newX, newY, newW, newH, newBW, resize_after); - } - } else { - /* Special case for resizing the root window */ - BoxRec box; - - pWin->drawable.x = x; - pWin->drawable.y = y; - pWin->drawable.width = w; - pWin->drawable.height = h; - - box.x1 = x; box.y1 = y; - box.x2 = x + w; box.y2 = y + h; - REGION_UNINIT(pScreen, &pWin->winSize); - REGION_INIT(pScreen, &pWin->winSize, &box, 1); - REGION_COPY(pScreen, &pWin->borderSize, &pWin->winSize); - REGION_COPY(pScreen, &pWin->clipList, &pWin->winSize); - REGION_COPY(pScreen, &pWin->borderClip, &pWin->winSize); - - miSendExposures(pWin, &pWin->borderClip, - pWin->drawable.x, pWin->drawable.y); - } - - RL_DEBUG_MSG("resizewindow end\n"); -} - - -/* - * RootlessRepositionWindow - * Called by the implementation when a window needs to be repositioned to - * its correct location on the screen. This routine is typically needed - * due to changes in the underlying window system, such as a screen layout - * change. - */ -void -RootlessRepositionWindow(WindowPtr pWin) -{ - RootlessWindowRec *winRec = WINREC(pWin); - ScreenPtr pScreen = pWin->drawable.pScreen; - - if (winRec == NULL) - return; - - RootlessStopDrawing(pWin, FALSE); - SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen, - winRec->x + SCREEN_TO_GLOBAL_X, - winRec->y + SCREEN_TO_GLOBAL_Y); - - RootlessReorderWindow(pWin); -} - - -/* - * RootlessReparentWindow - * Called after a window has been reparented. Generally windows are not - * framed until they are mapped. However, a window may be framed early by the - * implementation calling RootlessFrameForWindow. (e.g. this could be needed - * to attach a VRAM surface to it.) If the window is subsequently reparented - * by the window manager before being mapped, we need to give the frame to - * the new top-level window. - */ -void -RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - RootlessWindowRec *winRec = WINREC(pWin); - WindowPtr pTopWin; - - /* Check that window is not top-level now, but used to be. */ - if (IsRoot(pWin) || IsRoot(pWin->parent) - || IsTopLevel(pWin) || winRec == NULL) - { - goto out; - } - - /* If the formerly top-level window has a frame, we want to give the - frame to its new top-level parent. If we can't do that, we'll just - have to jettison it... */ - - pTopWin = TopLevelParent(pWin); - assert(pTopWin != pWin); - - pWin->rootlessUnhittable = FALSE; - - DeleteProperty (serverClient, pWin, xa_native_window_id ()); - - if (WINREC(pTopWin) != NULL) { - /* We're screwed. */ - RootlessDestroyFrame(pWin, winRec); - } else { - if (!pTopWin->realized && pWin->realized) { - SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid); - } - - /* Switch the frame record from one to the other. */ - - SETWINREC(pWin, NULL); - SETWINREC(pTopWin, winRec); - - RootlessInitializeFrame(pTopWin, winRec); - RootlessReshapeFrame(pTopWin); - - SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, - winRec->x + SCREEN_TO_GLOBAL_X, - winRec->y + SCREEN_TO_GLOBAL_Y, - winRec->width, winRec->height, - RL_GRAVITY_NONE); - - if (SCREENREC(pScreen)->imp->SwitchWindow) { - SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin); - } - - if (pTopWin->realized && !pWin->realized) - winRec->is_reorder_pending = TRUE; - } - -out: - if (SCREENREC(pScreen)->ReparentWindow) { - SCREEN_UNWRAP(pScreen, ReparentWindow); - pScreen->ReparentWindow(pWin, pPriorParent); - SCREEN_WRAP(pScreen, ReparentWindow); - } -} - - -void -RootlessFlushWindowColormap (WindowPtr pWin) -{ - RootlessWindowRec *winRec = WINREC (pWin); - ScreenPtr pScreen = pWin->drawable.pScreen; - - if (winRec == NULL) - return; - - RootlessStopDrawing (pWin, FALSE); - - if (SCREENREC(pScreen)->imp->UpdateColormap) - SCREENREC(pScreen)->imp->UpdateColormap(winRec->wid, pScreen); -} - -/* - * RootlessChangeBorderWidth - * FIXME: untested! - * pWin inside corner stays the same; pWin->drawable.[xy] stays the same - * Frame moves and resizes. - */ -void -RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width) -{ - RegionRec saveRoot; - Bool resize_after = FALSE; - - RL_DEBUG_MSG("change border width "); - - if (width != wBorderWidth(pWin)) { - RootlessWindowRec *winRec = WINREC(pWin); - int oldX = 0, oldY = 0, newX = 0, newY = 0; - unsigned int oldW = 0, oldH = 0, oldBW = 0; - unsigned int newW = 0, newH = 0, newBW = 0; - - if (winRec) { - oldBW = winRec->borderWidth; - oldX = winRec->x; - oldY = winRec->y; - oldW = winRec->width; - oldH = winRec->height; - - newBW = width; - newX = pWin->drawable.x - newBW; - newY = pWin->drawable.y - newBW; - newW = pWin->drawable.width + 2*newBW; - newH = pWin->drawable.height + 2*newBW; - - resize_after = StartFrameResize(pWin, FALSE, - oldX, oldY, oldW, oldH, oldBW, - newX, newY, newW, newH, newBW); - } - - HUGE_ROOT(pWin); - SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth); - pWin->drawable.pScreen->ChangeBorderWidth(pWin, width); - SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth); - NORMAL_ROOT(pWin); - - if (winRec) { - FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, - newX, newY, newW, newH, newBW, resize_after); - } - } - - RL_DEBUG_MSG("change border width end\n"); -} - -/* - * RootlessOrderAllWindows - * Brings all X11 windows to the top of the window stack - * (i.e in front of Aqua windows) -- called when X11.app is given focus - */ -void -RootlessOrderAllWindows (void) -{ - int i; - WindowPtr pWin; - - if (windows_hidden) - return; - - RL_DEBUG_MSG("RootlessOrderAllWindows() "); - for (i = 0; i < screenInfo.numScreens; i++) { - if (screenInfo.screens[i] == NULL) continue; - pWin = WindowTable[i]; - if (pWin == NULL) continue; - - for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) { - if (!pWin->realized) continue; - if (RootlessEnsureFrame(pWin) == NULL) continue; - RootlessReorderWindow (pWin); - } - } - RL_DEBUG_MSG("RootlessOrderAllWindows() done"); -} - -void -RootlessEnableRoot (ScreenPtr pScreen) -{ - WindowPtr pRoot; - pRoot = WindowTable[pScreen->myNum]; - - RootlessEnsureFrame (pRoot); - (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE); - RootlessReorderWindow (pRoot); -} - -void -RootlessDisableRoot (ScreenPtr pScreen) -{ - WindowPtr pRoot; - RootlessWindowRec *winRec; - - pRoot = WindowTable[pScreen->myNum]; - winRec = WINREC (pRoot); - - if (NULL == winRec) - return; - - RootlessDestroyFrame (pRoot, winRec); - DeleteProperty (serverClient, pRoot, xa_native_window_id ()); -} - -void -RootlessHideAllWindows (void) -{ - int i; - ScreenPtr pScreen; - WindowPtr pWin; - RootlessWindowRec *winRec; - - if (windows_hidden) - return; - - windows_hidden = TRUE; - - for (i = 0; i < screenInfo.numScreens; i++) - { - pScreen = screenInfo.screens[i]; - pWin = WindowTable[i]; - if (pScreen == NULL || pWin == NULL) - continue; - - for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) - { - if (!pWin->realized) - continue; - - RootlessStopDrawing (pWin, FALSE); - - winRec = WINREC (pWin); - if (winRec != NULL) - { - if (SCREENREC(pScreen)->imp->HideWindow) - SCREENREC(pScreen)->imp->HideWindow(winRec->wid); - } - } - } -} - -void -RootlessShowAllWindows (void) -{ - int i; - ScreenPtr pScreen; - WindowPtr pWin; - RootlessWindowRec *winRec; - - if (!windows_hidden) - return; - - windows_hidden = FALSE; - - for (i = 0; i < screenInfo.numScreens; i++) - { - pScreen = screenInfo.screens[i]; - pWin = WindowTable[i]; - if (pScreen == NULL || pWin == NULL) - continue; - - for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) - { - if (!pWin->realized) - continue; - - winRec = RootlessEnsureFrame (pWin); - if (winRec == NULL) - continue; - - RootlessReorderWindow (pWin); - } - - RootlessScreenExpose (pScreen); - } -} - -/* - * SetPixmapOfAncestors - * Set the Pixmaps on all ParentRelative windows up the ancestor chain. - */ -void -RootlessSetPixmapOfAncestors(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - WindowPtr topWin = TopLevelParent(pWin); - RootlessWindowRec *topWinRec = WINREC(topWin); - - while (pWin->backgroundState == ParentRelative) { - if (pWin == topWin) { - // disallow ParentRelative background state on top level - XID pixel = 0; - ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); - RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin); - break; - } - - pWin = pWin->parent; - pScreen->SetWindowPixmap(pWin, topWinRec->pixmap); - } -} - +/* + * Rootless window management + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stddef.h> /* For NULL */ +#include <limits.h> /* For CHAR_BIT */ +#include <assert.h> +#include <X11/Xatom.h> +#ifdef __APPLE__ +#include <Xplugin.h> +#include "mi.h" +#include "pixmapstr.h" +#include "windowstr.h" +//#include <X11/extensions/applewm.h> +extern int darwinMainScreenX, darwinMainScreenY; +extern Bool no_configure_window; +#endif +#include "fb.h" + +#include "rootlessCommon.h" +#include "rootlessWindow.h" + +#ifdef ROOTLESS_GLOBAL_COORDS +#define SCREEN_TO_GLOBAL_X \ + (dixScreenOrigins[pScreen->myNum].x + rootlessGlobalOffsetX) +#define SCREEN_TO_GLOBAL_Y \ + (dixScreenOrigins[pScreen->myNum].y + rootlessGlobalOffsetY) +#else +#define SCREEN_TO_GLOBAL_X 0 +#define SCREEN_TO_GLOBAL_Y 0 +#endif + +#define DEFINE_ATOM_HELPER(func,atom_name) \ + static Atom func (void) { \ + static unsigned int generation = 0; \ + static Atom atom; \ + if (generation != serverGeneration) { \ + generation = serverGeneration; \ + atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ + } \ + return atom; \ + } + +DEFINE_ATOM_HELPER (xa_native_window_id, "_NATIVE_WINDOW_ID") + +static Bool windows_hidden; +// TODO - abstract xp functions + +#ifdef __APPLE__ + +// XXX: identical to x_cvt_vptr_to_uint ? +#define MAKE_WINDOW_ID(x) ((xp_window_id)((size_t)(x))) + +void +RootlessNativeWindowStateChanged (WindowPtr pWin, unsigned int state) +{ + RootlessWindowRec *winRec; + + if (pWin == NULL) return; + + winRec = WINREC (pWin); + if (winRec == NULL) return; + + winRec->is_offscreen = ((state & XP_WINDOW_STATE_OFFSCREEN) != 0); + winRec->is_obscured = ((state & XP_WINDOW_STATE_OBSCURED) != 0); + pWin->rootlessUnhittable = winRec->is_offscreen; +} + +void RootlessNativeWindowMoved (WindowPtr pWin) { + xp_box bounds; + int sx, sy, err; + XID vlist[2]; + Mask mask; + ClientPtr pClient; + RootlessWindowRec *winRec; + + winRec = WINREC(pWin); + + if (xp_get_window_bounds (MAKE_WINDOW_ID(winRec->wid), &bounds) != Success) return; + + sx = dixScreenOrigins[pWin->drawable.pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pWin->drawable.pScreen->myNum].y + darwinMainScreenY; + + /* Fake up a ConfigureWindow packet to resize the window to the current bounds. */ + vlist[0] = (INT16) bounds.x1 - sx; + vlist[1] = (INT16) bounds.y1 - sy; + mask = CWX | CWY; + + /* pretend we're the owner of the window! */ + err = dixLookupClient(&pClient, pWin->drawable.id, serverClient, DixUnknownAccess); + if(err != Success) { + ErrorF("RootlessNativeWindowMoved(): Failed to lookup window: 0x%x\n", (unsigned int)pWin->drawable.id); + return; + } + + /* Don't want to do anything to the physical window (avoids + notification-response feedback loops) */ + + no_configure_window = TRUE; + ConfigureWindow (pWin, mask, vlist, pClient); + no_configure_window = FALSE; +} + +#endif /* __APPLE__ */ + +/* + * RootlessCreateWindow + * For now, don't create a physical window until either the window is + * realized, or we really need it (e.g. to attach VRAM surfaces to). + * Do reset the window size so it's not clipped by the root window. + */ +Bool +RootlessCreateWindow(WindowPtr pWin) +{ + Bool result; + RegionRec saveRoot; + + SETWINREC(pWin, NULL); + dixSetPrivate(&pWin->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL); + + SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow); + + if (!IsRoot(pWin)) { + /* win/border size set by DIX, not by wrapped CreateWindow, so + correct it here. Don't HUGE_ROOT when pWin is the root! */ + + HUGE_ROOT(pWin); + SetWinSize(pWin); + SetBorderSize(pWin); + } + + result = pWin->drawable.pScreen->CreateWindow(pWin); + + if (pWin->parent) { + NORMAL_ROOT(pWin); + } + + SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow); + + return result; +} + + +/* + * RootlessDestroyFrame + * Destroy the physical window associated with the given window. + */ +static void +RootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREENREC(pScreen)->imp->DestroyFrame(winRec->wid); + +#ifdef ROOTLESS_TRACK_DAMAGE + REGION_UNINIT(pScreen, &winRec->damage); +#endif + + free(winRec); + SETWINREC(pWin, NULL); +} + + +/* + * RootlessDestroyWindow + * Destroy the physical window associated with the given window. + */ +Bool +RootlessDestroyWindow(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + Bool result; + + if (winRec != NULL) { + RootlessDestroyFrame(pWin, winRec); + } + + SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow); + result = pWin->drawable.pScreen->DestroyWindow(pWin); + SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow); + + return result; +} + + + +static Bool +RootlessGetShape(WindowPtr pWin, RegionPtr pShape) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + /* + * Avoid a warning. + * REGION_NULL and the other macros don't actually seem to use pScreen. + */ + (void)pScreen; + + if (wBoundingShape(pWin) == NULL) + return FALSE; + + /* wBoundingShape is relative to *inner* origin of window. + Translate by borderWidth to get the outside-relative position. */ + + REGION_NULL(pScreen, pShape); + REGION_COPY(pScreen, pShape, wBoundingShape(pWin)); + REGION_TRANSLATE(pScreen, pShape, pWin->borderWidth, pWin->borderWidth); + + return TRUE; +} + + +/* + * RootlessReshapeFrame + * Set the frame shape. + */ +static void RootlessReshapeFrame(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec newShape; + RegionPtr pShape; + + // If the window is not yet framed, do nothing + if (winRec == NULL) + return; + + if (IsRoot(pWin)) + return; + + RootlessStopDrawing(pWin, FALSE); + + pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL; + +#ifdef ROOTLESSDEBUG + RL_DEBUG_MSG("reshaping..."); + if (pShape != NULL) { + RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ", + REGION_NUM_RECTS(&newShape), + newShape.extents.x1, newShape.extents.y1, + newShape.extents.x2, newShape.extents.y2); + } else { + RL_DEBUG_MSG("no shape "); + } +#endif + + SCREENREC(pScreen)->imp->ReshapeFrame(winRec->wid, pShape); + + if (pShape != NULL) + REGION_UNINIT(pScreen, &newShape); +} + + +/* + * RootlessSetShape + * Shape is usually set before a window is mapped and the window will + * not have a frame associated with it. In this case, the frame will be + * shaped when the window is framed. + */ +void +RootlessSetShape(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREEN_UNWRAP(pScreen, SetShape); + pScreen->SetShape(pWin); + SCREEN_WRAP(pScreen, SetShape); + + RootlessReshapeFrame(pWin); +} + + + +/* Disallow ParentRelative background on top-level windows + because the root window doesn't really have the right background. + */ +Bool +RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask) +{ + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("change window attributes start "); + + SCREEN_UNWRAP(pScreen, ChangeWindowAttributes); + result = pScreen->ChangeWindowAttributes(pWin, vmask); + SCREEN_WRAP(pScreen, ChangeWindowAttributes); + + if (WINREC(pWin)) { + // disallow ParentRelative background state + if (pWin->backgroundState == ParentRelative) { + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + } + } + + RL_DEBUG_MSG("change window attributes end\n"); + return result; +} + + +/* + * RootlessPositionWindow + * This is a hook for when DIX moves or resizes a window. + * Update the frame position now although the physical window is moved + * in RootlessMoveWindow. (x, y) are *inside* position. After this, + * mi and fb are expecting the pixmap to be at the new location. + */ +Bool +RootlessPositionWindow(WindowPtr pWin, int x, int y) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + Bool result; + + RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y); + + if (winRec) { + if (winRec->is_drawing) { + // Reset frame's pixmap and move it to the new position. + int bw = wBorderWidth(pWin); + + winRec->pixmap->devPrivate.ptr = winRec->pixelData; + SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw); + +#ifdef ROOTLESS_TRACK_DAMAGE + // Move damaged region to correspond to new window position + if (REGION_NOTEMPTY(pScreen, &winRec->damage)) { + REGION_TRANSLATE(pScreen, &winRec->damage, + x - bw - winRec->x, + y - bw - winRec->y); + } +#endif + } + } + + SCREEN_UNWRAP(pScreen, PositionWindow); + result = pScreen->PositionWindow(pWin, x, y); + SCREEN_WRAP(pScreen, PositionWindow); + + RL_DEBUG_MSG("positionwindow end\n"); + return result; +} + + +/* + * RootlessInitializeFrame + * Initialize some basic attributes of the frame. Note that winRec + * may already have valid data in it, so don't overwrite anything + * valuable. + */ +static void +RootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec *winRec) +{ + DrawablePtr d = &pWin->drawable; + int bw = wBorderWidth(pWin); + + winRec->win = pWin; + + winRec->x = d->x - bw; + winRec->y = d->y - bw; + winRec->width = d->width + 2*bw; + winRec->height = d->height + 2*bw; + winRec->borderWidth = bw; + +#ifdef ROOTLESS_TRACK_DAMAGE + REGION_NULL(pScreen, &winRec->damage); +#endif +} + +/* + * RootlessEnsureFrame + * Make sure the given window is framed. If the window doesn't have a + * physical window associated with it, attempt to create one. If that + * is unsuccessful, return NULL. + */ +static RootlessWindowRec * +RootlessEnsureFrame(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec; + RegionRec shape; + RegionPtr pShape = NULL; + + if (WINREC(pWin) != NULL) + return WINREC(pWin); + + if (!IsTopLevel(pWin) && !IsRoot(pWin)) + return NULL; + + if (pWin->drawable.class != InputOutput) + return NULL; + + winRec = malloc(sizeof(RootlessWindowRec)); + + if (!winRec) + return NULL; + + RootlessInitializeFrame(pWin, winRec); + + winRec->is_drawing = FALSE; + winRec->is_reorder_pending = FALSE; + winRec->pixmap = NULL; + winRec->wid = NULL; + winRec->level = 0; + + SETWINREC(pWin, winRec); + + // Set the frame's shape if the window is shaped + if (RootlessGetShape(pWin, &shape)) + pShape = &shape; + + RL_DEBUG_MSG("creating frame "); + + if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen, + winRec->x + SCREEN_TO_GLOBAL_X, + winRec->y + SCREEN_TO_GLOBAL_Y, + pShape)) + { + RL_DEBUG_MSG("implementation failed to create frame!\n"); + free(winRec); + SETWINREC(pWin, NULL); + return NULL; + } + + if (pWin->drawable.depth == 8) + RootlessFlushWindowColormap(pWin); + + if (pShape != NULL) + REGION_UNINIT(pScreen, &shape); + + return winRec; +} + + +/* + * RootlessRealizeWindow + * The frame is usually created here and not in CreateWindow so that + * windows do not eat memory until they are realized. + */ +Bool +RootlessRealizeWindow(WindowPtr pWin) +{ + Bool result; + RegionRec saveRoot; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin); + + if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) { + RootlessWindowRec *winRec; + + winRec = RootlessEnsureFrame(pWin); + if (winRec == NULL) + return FALSE; + + winRec->is_reorder_pending = TRUE; + + RL_DEBUG_MSG("Top level window "); + + // Disallow ParentRelative background state on top-level windows. + // This might have been set before the window was mapped. + if (pWin->backgroundState == ParentRelative) { + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + } + } + + if (!IsRoot(pWin)) HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, RealizeWindow); + result = pScreen->RealizeWindow(pWin); + SCREEN_WRAP(pScreen, RealizeWindow); + if (!IsRoot(pWin)) NORMAL_ROOT(pWin); + + RL_DEBUG_MSG("realizewindow end\n"); + return result; +} + + +/* + * RootlessFrameForWindow + * Returns the frame ID for the physical window displaying the given window. + * If CREATE is true and the window has no frame, attempt to create one. + */ +RootlessFrameID +RootlessFrameForWindow(WindowPtr pWin, Bool create) +{ + WindowPtr pTopWin; + RootlessWindowRec *winRec; + + pTopWin = TopLevelParent(pWin); + if (pTopWin == NULL) + return NULL; + + winRec = WINREC(pTopWin); + + if (winRec == NULL && create && pWin->drawable.class == InputOutput) { + winRec = RootlessEnsureFrame(pTopWin); + } + + if (winRec == NULL) + return NULL; + + return winRec->wid; +} + + +/* + * RootlessUnrealizeWindow + * Unmap the physical window. + */ +Bool +RootlessUnrealizeWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + Bool result; + + RL_DEBUG_MSG("unrealizewindow start "); + + if (winRec) { + RootlessStopDrawing(pWin, FALSE); + + SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid); + + winRec->is_reorder_pending = FALSE; + } + + SCREEN_UNWRAP(pScreen, UnrealizeWindow); + result = pScreen->UnrealizeWindow(pWin); + SCREEN_WRAP(pScreen, UnrealizeWindow); + + RL_DEBUG_MSG("unrealizewindow end\n"); + return result; +} + + +/* + * RootlessReorderWindow + * Reorder the frame associated with the given window so that it's + * physically above the window below it in the X stacking order. + */ +void +RootlessReorderWindow(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + + if (pWin->realized && winRec != NULL && !winRec->is_reorder_pending && !windows_hidden) { + WindowPtr newPrevW; + RootlessWindowRec *newPrev; + RootlessFrameID newPrevID; + ScreenPtr pScreen = pWin->drawable.pScreen; + + /* Check if the implementation wants the frame to not be reordered + even though the X11 window is restacked. This can be useful if + frames are ordered-in with animation so that the reordering is not + done until the animation is complete. */ + if (SCREENREC(pScreen)->imp->DoReorderWindow) { + if (!SCREENREC(pScreen)->imp->DoReorderWindow(winRec)) + return; + } + + RootlessStopDrawing(pWin, FALSE); + + /* Find the next window above this one that has a mapped frame. */ + + newPrevW = pWin->prevSib; + while (newPrevW && (WINREC(newPrevW) == NULL || !newPrevW->realized)) + newPrevW = newPrevW->prevSib; + + newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL; + newPrevID = newPrev != NULL ? newPrev->wid : 0; + + /* If it exists, reorder the frame above us first. */ + + if (newPrev && newPrev->is_reorder_pending) { + newPrev->is_reorder_pending = FALSE; + RootlessReorderWindow(newPrevW); + } + + SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID); + } +} + + +/* + * RootlessRestackWindow + * This is a hook for when DIX changes the window stacking order. + * The window has already been inserted into its new position in the + * DIX window stack. We need to change the order of the physical + * window to match. + */ +void +RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib) +{ + RegionRec saveRoot; + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("restackwindow start "); + if (winRec) + RL_DEBUG_MSG("restack top level \n"); + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, RestackWindow); + + if (pScreen->RestackWindow) + pScreen->RestackWindow(pWin, pOldNextSib); + + SCREEN_WRAP(pScreen, RestackWindow); + NORMAL_ROOT(pWin); + + if (winRec && pWin->viewable) { + RootlessReorderWindow(pWin); + } + + RL_DEBUG_MSG("restackwindow end\n"); +} + +/* + * Specialized window copy procedures + */ + +// Globals needed during window resize and move. +static pointer gResizeDeathBits = NULL; +static int gResizeDeathCount = 0; +static PixmapPtr gResizeDeathPix[2] = {NULL, NULL}; +static BoxRec gResizeDeathBounds[2]; +static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL; + +/* + * RootlessNoCopyWindow + * CopyWindow() that doesn't do anything. For MoveWindow() of + * top-level windows. + */ +static void +RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + // some code expects the region to be translated + int dx = ptOldOrg.x - pWin->drawable.x; + int dy = ptOldOrg.y - pWin->drawable.y; + + RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW "); + + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); +} + + +/* + * RootlessResizeCopyWindow + * CopyWindow used during ResizeWindow for gravity moves. Based on + * fbCopyWindow. The original always draws on the root pixmap, which + * we don't have. Instead, draw on the parent window's pixmap. + * Resize version: the old location's pixels are in gResizeCopyWindowSource. + */ +static void +RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec rgnDst; + int dx, dy; + + RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin); + + /* Don't unwrap pScreen->CopyWindow. + The bogus rewrap with RootlessCopyWindow causes a crash if + CopyWindow is called again during the same resize. */ + + if (gResizeDeathCount == 0) + return; + + RootlessStartDrawing(pWin); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + REGION_NULL(pScreen, &rgnDst); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + if (gResizeDeathCount == 1) { + /* Simple case, we only have a single source pixmap. */ + + fbCopyRegion(&gResizeDeathPix[0]->drawable, + &pScreen->GetWindowPixmap(pWin)->drawable, 0, + &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + } + else { + int i; + RegionRec clip, clipped; + + /* More complex case, N source pixmaps (usually two). So we + intersect the destination with each source and copy those bits. */ + + for (i = 0; i < gResizeDeathCount; i++) { + REGION_INIT(pScreen, &clip, gResizeDeathBounds + 0, 1); + REGION_NULL(pScreen, &clipped); + REGION_INTERSECT(pScreen, &rgnDst, &clip, &clipped); + + fbCopyRegion(&gResizeDeathPix[i]->drawable, + &pScreen->GetWindowPixmap(pWin)->drawable, 0, + &clipped, dx, dy, fbCopyWindowProc, 0, 0); + + REGION_UNINIT(pScreen, &clipped); + REGION_UNINIT(pScreen, &clip); + } + } + + /* Don't update - resize will update everything */ + REGION_UNINIT(pScreen, &rgnDst); + + fbValidateDrawable(&pWin->drawable); + + RL_DEBUG_MSG("resizecopywindowFB end\n"); +} + + +/* + * RootlessCopyWindow + * Update *new* location of window. Old location is redrawn with + * miPaintWindow. Cloned from fbCopyWindow. + * The original always draws on the root pixmap, which we don't have. + * Instead, draw on the parent window's pixmap. + */ +void +RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec rgnDst; + int dx, dy; + BoxPtr extents; + int area; + + RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin); + + SCREEN_UNWRAP(pScreen, CopyWindow); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + + REGION_NULL(pScreen, &rgnDst); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + extents = REGION_EXTENTS(pScreen, &rgnDst); + area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1); + + /* If the area exceeds threshold, use the implementation's + accelerated version. */ + if (area > rootless_CopyWindow_threshold && + SCREENREC(pScreen)->imp->CopyWindow) + { + RootlessWindowRec *winRec; + WindowPtr top; + + top = TopLevelParent(pWin); + if (top == NULL) { + RL_DEBUG_MSG("no parent\n"); + goto out; + } + + winRec = WINREC(top); + if (winRec == NULL) { + RL_DEBUG_MSG("not framed\n"); + goto out; + } + + /* Move region to window local coords */ + REGION_TRANSLATE(pScreen, &rgnDst, -winRec->x, -winRec->y); + + RootlessStopDrawing(pWin, FALSE); + + SCREENREC(pScreen)->imp->CopyWindow(winRec->wid, + REGION_NUM_RECTS(&rgnDst), + REGION_RECTS(&rgnDst), + dx, dy); + } + else { + RootlessStartDrawing(pWin); + + fbCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin, + 0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + + /* prgnSrc has been translated to dst position */ + RootlessDamageRegion(pWin, prgnSrc); + } + +out: + REGION_UNINIT(pScreen, &rgnDst); + fbValidateDrawable(&pWin->drawable); + + SCREEN_WRAP(pScreen, CopyWindow); + + RL_DEBUG_MSG("copywindowFB end\n"); +} + + +/* + * Window resize procedures + */ + +enum { + WIDTH_SMALLER = 1, + HEIGHT_SMALLER = 2, +}; + + +/* + * ResizeWeighting + * Choose gravity to avoid local copies. Do that by looking for + * a corner that doesn't move _relative to the screen_. + */ +static inline unsigned int +ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW, + int newX1, int newY1, int newX2, int newY2, int newBW) +{ +#ifdef ROOTLESS_RESIZE_GRAVITY + if (newBW != oldBW) + return RL_GRAVITY_NONE; + + if (newX1 == oldX1 && newY1 == oldY1) + return RL_GRAVITY_NORTH_WEST; + else if (newX1 == oldX1 && newY2 == oldY2) + return RL_GRAVITY_SOUTH_WEST; + else if (newX2 == oldX2 && newY2 == oldY2) + return RL_GRAVITY_SOUTH_EAST; + else if (newX2 == oldX2 && newY1 == oldY1) + return RL_GRAVITY_NORTH_EAST; + else + return RL_GRAVITY_NONE; +#else + return RL_GRAVITY_NONE; +#endif +} + + +/* + * StartFrameResize + * Prepare to resize a top-level window. The old window's pixels are + * saved and the implementation is told to change the window size. + * (x,y,w,h) is outer frame of window (outside border) + */ +static Bool +StartFrameResize(WindowPtr pWin, Bool gravity, + int oldX, int oldY, int oldW, int oldH, int oldBW, + int newX, int newY, int newW, int newH, int newBW) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + Bool need_window_source = FALSE, resize_after = FALSE; + + BoxRec rect; + int oldX2, newX2; + int oldY2, newY2; + unsigned int weight; + + oldX2 = oldX + oldW, newX2 = newX + newW; + oldY2 = oldY + oldH, newY2 = newY + newH; + + /* Decide which resize weighting to use */ + weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + /* Compute intersection between old and new rects */ + rect.x1 = max(oldX, newX); + rect.y1 = max(oldY, newY); + rect.x2 = min(oldX2, newX2); + rect.y2 = min(oldY2, newY2); + + RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity); + RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n", + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + RootlessRedisplay(pWin); + + /* If gravity is true, then we need to have a way of recovering all + the original bits in the window for when X rearranges the contents + based on the various gravity settings. The obvious way is to just + snapshot the entire backing store before resizing it, but that + it slow on large windows. + + So the optimization here is to use the implementation's resize + weighting options (if available) to allow us to reason about what + is left in the backing store after the resize. We can then only + copy what won't be there after the resize, and do a two-stage copy + operation. + + Most of these optimizations are only applied when the top-left + corner of the window is fixed, since that's the common case. They + could probably be extended with some thought. */ + + gResizeDeathCount = 0; + + if (gravity && weight == RL_GRAVITY_NORTH_WEST) { + unsigned int code = 0; + + /* Top left corner is anchored. We never need to copy the + entire window. */ + + need_window_source = TRUE; + + /* These comparisons were chosen to avoid setting bits when the sizes + are the same. (So the fastest case automatically gets taken when + dimensions are unchanging.) */ + + if (newW < oldW) + code |= WIDTH_SMALLER; + if (newH < oldH) + code |= HEIGHT_SMALLER; + + if (((code ^ (code >> 1)) & 1) == 0) { + /* Both dimensions are either getting larger, or both + are getting smaller. No need to copy anything. */ + + if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) { + /* Since the window is getting smaller, we can do gravity + repair on it with it's current size, then resize it + afterwards. */ + + resize_after = TRUE; + } + + gResizeDeathCount = 1; + } + else { + unsigned int copy_rowbytes, Bpp; + unsigned int copy_rect_width, copy_rect_height; + BoxRec copy_rect; + + /* We can get away with a partial copy. 'rect' is the + intersection between old and new bounds, so copy + everything to the right of or below the intersection. */ + + RootlessStartDrawing(pWin); + + if (code == WIDTH_SMALLER) { + copy_rect.x1 = rect.x2; + copy_rect.y1 = rect.y1; + copy_rect.x2 = oldX2; + copy_rect.y2 = oldY2; + } + else if (code == HEIGHT_SMALLER) { + copy_rect.x1 = rect.x1; + copy_rect.y1 = rect.y2; + copy_rect.x2 = oldX2; + copy_rect.y2 = oldY2; + } + else + OsAbort(); + + Bpp = winRec->win->drawable.bitsPerPixel / 8; + copy_rect_width = copy_rect.x2 - copy_rect.x1; + copy_rect_height = copy_rect.y2 - copy_rect.y1; + copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31; + gResizeDeathBits = malloc(copy_rowbytes + * copy_rect_height); + + if (copy_rect_width * copy_rect_height > + rootless_CopyBytes_threshold && + SCREENREC(pScreen)->imp->CopyBytes) + { + SCREENREC(pScreen)->imp->CopyBytes( + copy_rect_width * Bpp, copy_rect_height, + ((char *) winRec->pixelData) + + ((copy_rect.y1 - oldY) * winRec->bytesPerRow) + + (copy_rect.x1 - oldX) * Bpp, winRec->bytesPerRow, + gResizeDeathBits, copy_rowbytes); + } else { + fbBlt((FbBits *) (winRec->pixelData + + ((copy_rect.y1 - oldY) * winRec->bytesPerRow) + + (copy_rect.x1 - oldX) * Bpp), + winRec->bytesPerRow / sizeof(FbBits), 0, + (FbBits *) gResizeDeathBits, + copy_rowbytes / sizeof(FbBits), 0, + copy_rect_width * Bpp, copy_rect_height, + GXcopy, FB_ALLONES, Bpp, 0, 0); + } + + gResizeDeathBounds[1] = copy_rect; + gResizeDeathPix[1] + = GetScratchPixmapHeader(pScreen, copy_rect_width, + copy_rect_height, + winRec->win->drawable.depth, + winRec->win->drawable.bitsPerPixel, + winRec->bytesPerRow, + (void *) gResizeDeathBits); + + SetPixmapBaseToScreen(gResizeDeathPix[1], + copy_rect.x1, copy_rect.y1); + + gResizeDeathCount = 2; + } + } + else if (gravity) { + /* The general case. Just copy everything. */ + + RootlessStartDrawing(pWin); + + gResizeDeathBits = malloc(winRec->bytesPerRow * winRec->height); + + memcpy(gResizeDeathBits, winRec->pixelData, + winRec->bytesPerRow * winRec->height); + + gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2}; + gResizeDeathPix[0] + = GetScratchPixmapHeader(pScreen, winRec->width, + winRec->height, + winRec->win->drawable.depth, + winRec->win->drawable.bitsPerPixel, + winRec->bytesPerRow, + (void *) gResizeDeathBits); + + SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY); + gResizeDeathCount = 1; + } + + RootlessStopDrawing(pWin, FALSE); + + winRec->x = newX; + winRec->y = newY; + winRec->width = newW; + winRec->height = newH; + winRec->borderWidth = newBW; + + /* Unless both dimensions are getting smaller, Resize the frame + before doing gravity repair */ + + if (!resize_after) { + SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, + newX + SCREEN_TO_GLOBAL_X, + newY + SCREEN_TO_GLOBAL_Y, + newW, newH, weight); + } + + RootlessStartDrawing(pWin); + + /* If necessary, create a source pixmap pointing at the current + window bits. */ + + if (need_window_source) { + gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2}; + gResizeDeathPix[0] + = GetScratchPixmapHeader(pScreen, oldW, oldH, + winRec->win->drawable.depth, + winRec->win->drawable.bitsPerPixel, + winRec->bytesPerRow, winRec->pixelData); + + SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY); + } + + /* Use custom CopyWindow when moving gravity bits around + ResizeWindow assumes the old window contents are in the same + pixmap, but here they're in deathPix instead. */ + + if (gravity) { + gResizeOldCopyWindowProc = pScreen->CopyWindow; + pScreen->CopyWindow = RootlessResizeCopyWindow; + } + + /* If we can't rely on the window server preserving the bits we + need in the position we need, copy the pixels in the + intersection from src to dst. ResizeWindow assumes these pixels + are already present when making gravity adjustments. pWin + currently has new-sized pixmap but is in old position. + + FIXME: border width change! (?) */ + + if (gravity && weight == RL_GRAVITY_NONE) { + PixmapPtr src, dst; + + assert(gResizeDeathCount == 1); + + src = gResizeDeathPix[0]; + dst = pScreen->GetWindowPixmap(pWin); + + RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n", + rect.x1, rect.y1, rect.x2, rect.y2); + + /* rect is the intersection of the old location and new location */ + if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) { + /* The window drawable still has the old frame position, which + means that DST doesn't actually point at the origin of our + physical backing store when adjusted by the drawable.x,y + position. So sneakily adjust it temporarily while copying.. */ + + ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData; + SetPixmapBaseToScreen(dst, newX, newY); + + fbCopyWindowProc(&src->drawable, &dst->drawable, NULL, + &rect, 1, 0, 0, FALSE, FALSE, 0, 0); + + ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData; + SetPixmapBaseToScreen(dst, oldX, oldY); + } + } + + return resize_after; +} + + +static void +FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY, + unsigned int oldW, unsigned int oldH, unsigned int oldBW, + int newX, int newY, unsigned int newW, unsigned int newH, + unsigned int newBW, Bool resize_now) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + int i; + + RootlessStopDrawing(pWin, FALSE); + + if (resize_now) { + unsigned int weight; + + /* We didn't resize anything earlier, so do it now, now that + we've finished gravitating the bits. */ + + weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, + newX + SCREEN_TO_GLOBAL_X, + newY + SCREEN_TO_GLOBAL_Y, + newW, newH, weight); + } + + /* Redraw everything. FIXME: there must be times when we don't need + to do this. Perhaps when top-left weighting and no gravity? */ + + RootlessDamageRect(pWin, -newBW, -newBW, newW, newH); + + for (i = 0; i < 2; i++) { + if (gResizeDeathPix[i] != NULL) { + FreeScratchPixmapHeader(gResizeDeathPix[i]); + gResizeDeathPix[i] = NULL; + } + } + + if (gResizeDeathBits != NULL) { + free(gResizeDeathBits); + gResizeDeathBits = NULL; + } + + if (gravity) { + pScreen->CopyWindow = gResizeOldCopyWindowProc; + } +} + + +/* + * RootlessMoveWindow + * If kind==VTOther, window border is resizing (and borderWidth is + * already changed!!@#$) This case works like window resize, not move. + */ +void +RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + CopyWindowProcPtr oldCopyWindowProc = NULL; + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0; + unsigned int newW = 0, newH = 0, newBW = 0; + Bool resize_after = FALSE; + RegionRec saveRoot; + + RL_DEBUG_MSG("movewindow start \n"); + + if (winRec) { + if (kind == VTMove) { + oldX = winRec->x; + oldY = winRec->y; + RootlessRedisplay(pWin); + RootlessStartDrawing(pWin); + } else { + RL_DEBUG_MSG("movewindow border resizing "); + + oldBW = winRec->borderWidth; + oldX = winRec->x; + oldY = winRec->y; + oldW = winRec->width; + oldH = winRec->height; + + newBW = wBorderWidth(pWin); + newX = x; + newY = y; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + + resize_after = StartFrameResize(pWin, FALSE, + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, MoveWindow); + + if (winRec) { + oldCopyWindowProc = pScreen->CopyWindow; + pScreen->CopyWindow = RootlessNoCopyWindow; + } + pScreen->MoveWindow(pWin, x, y, pSib, kind); + if (winRec) { + pScreen->CopyWindow = oldCopyWindowProc; + } + + NORMAL_ROOT(pWin); + SCREEN_WRAP(pScreen, MoveWindow); + + if (winRec) { + if (kind == VTMove) { + winRec->x = x; + winRec->y = y; + RootlessStopDrawing(pWin, FALSE); + SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen, + x + SCREEN_TO_GLOBAL_X, + y + SCREEN_TO_GLOBAL_Y); + } else { + FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW, resize_after); + } + } + + RL_DEBUG_MSG("movewindow end\n"); +} + + +/* + * RootlessResizeWindow + * Note: (x, y, w, h) as passed to this procedure don't match the frame + * definition. (x,y) is corner of very outer edge, *outside* border. + * w,h is width and height *inside* border, *ignoring* border width. + * The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw) + * is total rect and (x+bw, y+bw, w, h) is inner rect. + */ +void +RootlessResizeWindow(WindowPtr pWin, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0; + Bool resize_after = FALSE; + RegionRec saveRoot; + + RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin); + + if(pWin->parent) { + if (winRec) { + oldBW = winRec->borderWidth; + oldX = winRec->x; + oldY = winRec->y; + oldW = winRec->width; + oldH = winRec->height; + + newBW = oldBW; + newX = x; + newY = y; + newW = w + 2*newBW; + newH = h + 2*newBW; + + resize_after = StartFrameResize(pWin, TRUE, + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, ResizeWindow); + pScreen->ResizeWindow(pWin, x, y, w, h, pSib); + SCREEN_WRAP(pScreen, ResizeWindow); + NORMAL_ROOT(pWin); + + if (winRec) { + FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW, resize_after); + } + } else { + /* Special case for resizing the root window */ + BoxRec box; + + pWin->drawable.x = x; + pWin->drawable.y = y; + pWin->drawable.width = w; + pWin->drawable.height = h; + + box.x1 = x; box.y1 = y; + box.x2 = x + w; box.y2 = y + h; + REGION_UNINIT(pScreen, &pWin->winSize); + REGION_INIT(pScreen, &pWin->winSize, &box, 1); + REGION_COPY(pScreen, &pWin->borderSize, &pWin->winSize); + REGION_COPY(pScreen, &pWin->clipList, &pWin->winSize); + REGION_COPY(pScreen, &pWin->borderClip, &pWin->winSize); + + miSendExposures(pWin, &pWin->borderClip, + pWin->drawable.x, pWin->drawable.y); + } + + RL_DEBUG_MSG("resizewindow end\n"); +} + + +/* + * RootlessRepositionWindow + * Called by the implementation when a window needs to be repositioned to + * its correct location on the screen. This routine is typically needed + * due to changes in the underlying window system, such as a screen layout + * change. + */ +void +RootlessRepositionWindow(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (winRec == NULL) + return; + + RootlessStopDrawing(pWin, FALSE); + SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen, + winRec->x + SCREEN_TO_GLOBAL_X, + winRec->y + SCREEN_TO_GLOBAL_Y); + + RootlessReorderWindow(pWin); +} + + +/* + * RootlessReparentWindow + * Called after a window has been reparented. Generally windows are not + * framed until they are mapped. However, a window may be framed early by the + * implementation calling RootlessFrameForWindow. (e.g. this could be needed + * to attach a VRAM surface to it.) If the window is subsequently reparented + * by the window manager before being mapped, we need to give the frame to + * the new top-level window. + */ +void +RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + WindowPtr pTopWin; + + /* Check that window is not top-level now, but used to be. */ + if (IsRoot(pWin) || IsRoot(pWin->parent) + || IsTopLevel(pWin) || winRec == NULL) + { + goto out; + } + + /* If the formerly top-level window has a frame, we want to give the + frame to its new top-level parent. If we can't do that, we'll just + have to jettison it... */ + + pTopWin = TopLevelParent(pWin); + assert(pTopWin != pWin); + + pWin->rootlessUnhittable = FALSE; + + DeleteProperty (serverClient, pWin, xa_native_window_id ()); + + if (WINREC(pTopWin) != NULL) { + /* We're screwed. */ + RootlessDestroyFrame(pWin, winRec); + } else { + if (!pTopWin->realized && pWin->realized) { + SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid); + } + + /* Switch the frame record from one to the other. */ + + SETWINREC(pWin, NULL); + SETWINREC(pTopWin, winRec); + + RootlessInitializeFrame(pTopWin, winRec); + RootlessReshapeFrame(pTopWin); + + SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, + winRec->x + SCREEN_TO_GLOBAL_X, + winRec->y + SCREEN_TO_GLOBAL_Y, + winRec->width, winRec->height, + RL_GRAVITY_NONE); + + if (SCREENREC(pScreen)->imp->SwitchWindow) { + SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin); + } + + if (pTopWin->realized && !pWin->realized) + winRec->is_reorder_pending = TRUE; + } + +out: + if (SCREENREC(pScreen)->ReparentWindow) { + SCREEN_UNWRAP(pScreen, ReparentWindow); + pScreen->ReparentWindow(pWin, pPriorParent); + SCREEN_WRAP(pScreen, ReparentWindow); + } +} + + +void +RootlessFlushWindowColormap (WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC (pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (winRec == NULL) + return; + + RootlessStopDrawing (pWin, FALSE); + + if (SCREENREC(pScreen)->imp->UpdateColormap) + SCREENREC(pScreen)->imp->UpdateColormap(winRec->wid, pScreen); +} + +/* + * RootlessChangeBorderWidth + * FIXME: untested! + * pWin inside corner stays the same; pWin->drawable.[xy] stays the same + * Frame moves and resizes. + */ +void +RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width) +{ + RegionRec saveRoot; + Bool resize_after = FALSE; + + RL_DEBUG_MSG("change border width "); + + if (width != wBorderWidth(pWin)) { + RootlessWindowRec *winRec = WINREC(pWin); + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0; + unsigned int newW = 0, newH = 0, newBW = 0; + + if (winRec) { + oldBW = winRec->borderWidth; + oldX = winRec->x; + oldY = winRec->y; + oldW = winRec->width; + oldH = winRec->height; + + newBW = width; + newX = pWin->drawable.x - newBW; + newY = pWin->drawable.y - newBW; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + + resize_after = StartFrameResize(pWin, FALSE, + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth); + pWin->drawable.pScreen->ChangeBorderWidth(pWin, width); + SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth); + NORMAL_ROOT(pWin); + + if (winRec) { + FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW, resize_after); + } + } + + RL_DEBUG_MSG("change border width end\n"); +} + +/* + * RootlessOrderAllWindows + * Brings all X11 windows to the top of the window stack + * (i.e in front of Aqua windows) -- called when X11.app is given focus + */ +void +RootlessOrderAllWindows (void) +{ + int i; + WindowPtr pWin; + + if (windows_hidden) + return; + + RL_DEBUG_MSG("RootlessOrderAllWindows() "); + for (i = 0; i < screenInfo.numScreens; i++) { + if (screenInfo.screens[i] == NULL) continue; + pWin = WindowTable[i]; + if (pWin == NULL) continue; + + for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) { + if (!pWin->realized) continue; + if (RootlessEnsureFrame(pWin) == NULL) continue; + RootlessReorderWindow (pWin); + } + } + RL_DEBUG_MSG("RootlessOrderAllWindows() done"); +} + +void +RootlessEnableRoot (ScreenPtr pScreen) +{ + WindowPtr pRoot; + pRoot = WindowTable[pScreen->myNum]; + + RootlessEnsureFrame (pRoot); + (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE); + RootlessReorderWindow (pRoot); +} + +void +RootlessDisableRoot (ScreenPtr pScreen) +{ + WindowPtr pRoot; + RootlessWindowRec *winRec; + + pRoot = WindowTable[pScreen->myNum]; + winRec = WINREC (pRoot); + + if (NULL == winRec) + return; + + RootlessDestroyFrame (pRoot, winRec); + DeleteProperty (serverClient, pRoot, xa_native_window_id ()); +} + +void +RootlessHideAllWindows (void) +{ + int i; + ScreenPtr pScreen; + WindowPtr pWin; + RootlessWindowRec *winRec; + + if (windows_hidden) + return; + + windows_hidden = TRUE; + + for (i = 0; i < screenInfo.numScreens; i++) + { + pScreen = screenInfo.screens[i]; + pWin = WindowTable[i]; + if (pScreen == NULL || pWin == NULL) + continue; + + for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) + { + if (!pWin->realized) + continue; + + RootlessStopDrawing (pWin, FALSE); + + winRec = WINREC (pWin); + if (winRec != NULL) + { + if (SCREENREC(pScreen)->imp->HideWindow) + SCREENREC(pScreen)->imp->HideWindow(winRec->wid); + } + } + } +} + +void +RootlessShowAllWindows (void) +{ + int i; + ScreenPtr pScreen; + WindowPtr pWin; + RootlessWindowRec *winRec; + + if (!windows_hidden) + return; + + windows_hidden = FALSE; + + for (i = 0; i < screenInfo.numScreens; i++) + { + pScreen = screenInfo.screens[i]; + pWin = WindowTable[i]; + if (pScreen == NULL || pWin == NULL) + continue; + + for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) + { + if (!pWin->realized) + continue; + + winRec = RootlessEnsureFrame (pWin); + if (winRec == NULL) + continue; + + RootlessReorderWindow (pWin); + } + + RootlessScreenExpose (pScreen); + } +} + +/* + * SetPixmapOfAncestors + * Set the Pixmaps on all ParentRelative windows up the ancestor chain. + */ +void +RootlessSetPixmapOfAncestors(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr topWin = TopLevelParent(pWin); + RootlessWindowRec *topWinRec = WINREC(topWin); + + while (pWin->backgroundState == ParentRelative) { + if (pWin == topWin) { + // disallow ParentRelative background state on top level + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin); + break; + } + + pWin = pWin->parent; + pScreen->SetWindowPixmap(pWin, topWinRec->pixmap); + } +} + diff --git a/xorg-server/miext/shadow/shadow.c b/xorg-server/miext/shadow/shadow.c index 608ccd234..2dcee60b1 100644 --- a/xorg-server/miext/shadow/shadow.c +++ b/xorg-server/miext/shadow/shadow.c @@ -1,249 +1,249 @@ -/* - * Copyright © 2000 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 <dix-config.h> -#endif - -#include <stdlib.h> - -#include <X11/X.h> -#include "scrnintstr.h" -#include "windowstr.h" -#include "dixfontstr.h" -#include "mi.h" -#include "regionstr.h" -#include "globals.h" -#include "gcstruct.h" -#include "shadow.h" - -static int shadowScrPrivateKeyIndex; -DevPrivateKey shadowScrPrivateKey = &shadowScrPrivateKeyIndex; - -#define wrap(priv, real, mem) {\ - priv->mem = real->mem; \ - real->mem = shadow##mem; \ -} - -#define unwrap(priv, real, mem) {\ - real->mem = priv->mem; \ -} - -static void -shadowRedisplay(ScreenPtr pScreen) -{ - shadowBuf(pScreen); - RegionPtr pRegion; - - if (!pBuf || !pBuf->pDamage || !pBuf->update) - return; - pRegion = DamageRegion(pBuf->pDamage); - if (REGION_NOTEMPTY(pScreen, pRegion)) { - (*pBuf->update)(pScreen, pBuf); - DamageEmpty(pBuf->pDamage); - } -} - -static void -shadowBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead) -{ - ScreenPtr pScreen = (ScreenPtr) data; - - shadowRedisplay(pScreen); -} - -static void -shadowWakeupHandler(pointer data, int i, pointer LastSelectMask) -{ -} - -static void -shadowGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, - unsigned int format, unsigned long planeMask, char *pdstLine) -{ - ScreenPtr pScreen = pDrawable->pScreen; - shadowBuf(pScreen); - - /* Many apps use GetImage to sync with the visable frame buffer */ - if (pDrawable->type == DRAWABLE_WINDOW) - shadowRedisplay(pScreen); - unwrap(pBuf, pScreen, GetImage); - pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); - wrap(pBuf, pScreen, GetImage); -} - -#define BACKWARDS_COMPATIBILITY - -static Bool -shadowCloseScreen(int i, ScreenPtr pScreen) -{ - shadowBuf(pScreen); - - unwrap(pBuf, pScreen, GetImage); - unwrap(pBuf, pScreen, CloseScreen); - shadowRemove(pScreen, pBuf->pPixmap); - DamageDestroy(pBuf->pDamage); -#ifdef BACKWARDS_COMPATIBILITY - REGION_UNINIT(pScreen, &pBuf->damage); /* bc */ -#endif - if (pBuf->pPixmap) - pScreen->DestroyPixmap(pBuf->pPixmap); - xfree(pBuf); - return pScreen->CloseScreen(i, pScreen); -} - -#ifdef BACKWARDS_COMPATIBILITY -static void -shadowReportFunc(DamagePtr pDamage, RegionPtr pRegion, void *closure) -{ - ScreenPtr pScreen = closure; - shadowBufPtr pBuf = (shadowBufPtr) - dixLookupPrivate(&pScreen->devPrivates, shadowScrPrivateKey); - - /* Register the damaged region, use DamageReportNone below when we - * want to break BC below... */ - REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, pRegion); - - /* - * BC hack. In 7.0 and earlier several drivers would inspect the - * 'damage' member directly, so we have to keep it existing. - */ - REGION_COPY(pScreen, &pBuf->damage, pRegion); -} -#endif - -Bool -shadowSetup(ScreenPtr pScreen) -{ - shadowBufPtr pBuf; - - if (!DamageSetup(pScreen)) - return FALSE; - - pBuf = xalloc(sizeof(shadowBufRec)); - if (!pBuf) - return FALSE; -#ifdef BACKWARDS_COMPATIBILITY - pBuf->pDamage = DamageCreate((DamageReportFunc)shadowReportFunc, - (DamageDestroyFunc)NULL, - DamageReportRawRegion, - TRUE, pScreen, pScreen); -#else - pBuf->pDamage = DamageCreate((DamageReportFunc)NULL, - (DamageDestroyFunc)NULL, - DamageReportNone, - TRUE, pScreen, pScreen); -#endif - if (!pBuf->pDamage) { - xfree(pBuf); - return FALSE; - } - - wrap(pBuf, pScreen, CloseScreen); - wrap(pBuf, pScreen, GetImage); - pBuf->update = 0; - pBuf->window = 0; - pBuf->pPixmap = 0; - pBuf->closure = 0; - pBuf->randr = 0; -#ifdef BACKWARDS_COMPATIBILITY - REGION_NULL(pScreen, &pBuf->damage); /* bc */ -#endif - - dixSetPrivate(&pScreen->devPrivates, shadowScrPrivateKey, pBuf); - return TRUE; -} - -Bool -shadowAdd(ScreenPtr pScreen, PixmapPtr pPixmap, ShadowUpdateProc update, - ShadowWindowProc window, int randr, void *closure) -{ - shadowBuf(pScreen); - - if (!RegisterBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler, - (pointer)pScreen)) - return FALSE; - - /* - * Map simple rotation values to bitmasks; fortunately, - * these are all unique - */ - switch (randr) { - case 0: - randr = SHADOW_ROTATE_0; - break; - case 90: - randr = SHADOW_ROTATE_90; - break; - case 180: - randr = SHADOW_ROTATE_180; - break; - case 270: - randr = SHADOW_ROTATE_270; - break; - } - pBuf->update = update; - pBuf->window = window; - pBuf->randr = randr; - pBuf->closure = closure; - pBuf->pPixmap = pPixmap; - DamageRegister(&pPixmap->drawable, pBuf->pDamage); - return TRUE; -} - -void -shadowRemove(ScreenPtr pScreen, PixmapPtr pPixmap) -{ - shadowBuf(pScreen); - - if (pBuf->pPixmap) { - DamageUnregister(&pBuf->pPixmap->drawable, pBuf->pDamage); - pBuf->update = 0; - pBuf->window = 0; - pBuf->randr = 0; - pBuf->closure = 0; - pBuf->pPixmap = 0; - } - - RemoveBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler, - (pointer) pScreen); -} - -Bool -shadowInit(ScreenPtr pScreen, ShadowUpdateProc update, ShadowWindowProc window) -{ - PixmapPtr pPixmap; - - pPixmap = pScreen->CreatePixmap(pScreen, pScreen->width, pScreen->height, - pScreen->rootDepth, 0); - if (!pPixmap) - return FALSE; - - if (!shadowSetup(pScreen)) { - pScreen->DestroyPixmap(pPixmap); - return FALSE; - } - - shadowAdd(pScreen, pPixmap, update, window, SHADOW_ROTATE_0, 0); - - return TRUE; -} +/* + * Copyright © 2000 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 <dix-config.h> +#endif + +#include <stdlib.h> + +#include <X11/X.h> +#include "scrnintstr.h" +#include "windowstr.h" +#include "dixfontstr.h" +#include "mi.h" +#include "regionstr.h" +#include "globals.h" +#include "gcstruct.h" +#include "shadow.h" + +static int shadowScrPrivateKeyIndex; +DevPrivateKey shadowScrPrivateKey = &shadowScrPrivateKeyIndex; + +#define wrap(priv, real, mem) {\ + priv->mem = real->mem; \ + real->mem = shadow##mem; \ +} + +#define unwrap(priv, real, mem) {\ + real->mem = priv->mem; \ +} + +static void +shadowRedisplay(ScreenPtr pScreen) +{ + shadowBuf(pScreen); + RegionPtr pRegion; + + if (!pBuf || !pBuf->pDamage || !pBuf->update) + return; + pRegion = DamageRegion(pBuf->pDamage); + if (REGION_NOTEMPTY(pScreen, pRegion)) { + (*pBuf->update)(pScreen, pBuf); + DamageEmpty(pBuf->pDamage); + } +} + +static void +shadowBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead) +{ + ScreenPtr pScreen = (ScreenPtr) data; + + shadowRedisplay(pScreen); +} + +static void +shadowWakeupHandler(pointer data, int i, pointer LastSelectMask) +{ +} + +static void +shadowGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planeMask, char *pdstLine) +{ + ScreenPtr pScreen = pDrawable->pScreen; + shadowBuf(pScreen); + + /* Many apps use GetImage to sync with the visable frame buffer */ + if (pDrawable->type == DRAWABLE_WINDOW) + shadowRedisplay(pScreen); + unwrap(pBuf, pScreen, GetImage); + pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); + wrap(pBuf, pScreen, GetImage); +} + +#define BACKWARDS_COMPATIBILITY + +static Bool +shadowCloseScreen(int i, ScreenPtr pScreen) +{ + shadowBuf(pScreen); + + unwrap(pBuf, pScreen, GetImage); + unwrap(pBuf, pScreen, CloseScreen); + shadowRemove(pScreen, pBuf->pPixmap); + DamageDestroy(pBuf->pDamage); +#ifdef BACKWARDS_COMPATIBILITY + REGION_UNINIT(pScreen, &pBuf->damage); /* bc */ +#endif + if (pBuf->pPixmap) + pScreen->DestroyPixmap(pBuf->pPixmap); + free(pBuf); + return pScreen->CloseScreen(i, pScreen); +} + +#ifdef BACKWARDS_COMPATIBILITY +static void +shadowReportFunc(DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + ScreenPtr pScreen = closure; + shadowBufPtr pBuf = (shadowBufPtr) + dixLookupPrivate(&pScreen->devPrivates, shadowScrPrivateKey); + + /* Register the damaged region, use DamageReportNone below when we + * want to break BC below... */ + REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, pRegion); + + /* + * BC hack. In 7.0 and earlier several drivers would inspect the + * 'damage' member directly, so we have to keep it existing. + */ + REGION_COPY(pScreen, &pBuf->damage, pRegion); +} +#endif + +Bool +shadowSetup(ScreenPtr pScreen) +{ + shadowBufPtr pBuf; + + if (!DamageSetup(pScreen)) + return FALSE; + + pBuf = malloc(sizeof(shadowBufRec)); + if (!pBuf) + return FALSE; +#ifdef BACKWARDS_COMPATIBILITY + pBuf->pDamage = DamageCreate((DamageReportFunc)shadowReportFunc, + (DamageDestroyFunc)NULL, + DamageReportRawRegion, + TRUE, pScreen, pScreen); +#else + pBuf->pDamage = DamageCreate((DamageReportFunc)NULL, + (DamageDestroyFunc)NULL, + DamageReportNone, + TRUE, pScreen, pScreen); +#endif + if (!pBuf->pDamage) { + free(pBuf); + return FALSE; + } + + wrap(pBuf, pScreen, CloseScreen); + wrap(pBuf, pScreen, GetImage); + pBuf->update = 0; + pBuf->window = 0; + pBuf->pPixmap = 0; + pBuf->closure = 0; + pBuf->randr = 0; +#ifdef BACKWARDS_COMPATIBILITY + REGION_NULL(pScreen, &pBuf->damage); /* bc */ +#endif + + dixSetPrivate(&pScreen->devPrivates, shadowScrPrivateKey, pBuf); + return TRUE; +} + +Bool +shadowAdd(ScreenPtr pScreen, PixmapPtr pPixmap, ShadowUpdateProc update, + ShadowWindowProc window, int randr, void *closure) +{ + shadowBuf(pScreen); + + if (!RegisterBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler, + (pointer)pScreen)) + return FALSE; + + /* + * Map simple rotation values to bitmasks; fortunately, + * these are all unique + */ + switch (randr) { + case 0: + randr = SHADOW_ROTATE_0; + break; + case 90: + randr = SHADOW_ROTATE_90; + break; + case 180: + randr = SHADOW_ROTATE_180; + break; + case 270: + randr = SHADOW_ROTATE_270; + break; + } + pBuf->update = update; + pBuf->window = window; + pBuf->randr = randr; + pBuf->closure = closure; + pBuf->pPixmap = pPixmap; + DamageRegister(&pPixmap->drawable, pBuf->pDamage); + return TRUE; +} + +void +shadowRemove(ScreenPtr pScreen, PixmapPtr pPixmap) +{ + shadowBuf(pScreen); + + if (pBuf->pPixmap) { + DamageUnregister(&pBuf->pPixmap->drawable, pBuf->pDamage); + pBuf->update = 0; + pBuf->window = 0; + pBuf->randr = 0; + pBuf->closure = 0; + pBuf->pPixmap = 0; + } + + RemoveBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler, + (pointer) pScreen); +} + +Bool +shadowInit(ScreenPtr pScreen, ShadowUpdateProc update, ShadowWindowProc window) +{ + PixmapPtr pPixmap; + + pPixmap = pScreen->CreatePixmap(pScreen, pScreen->width, pScreen->height, + pScreen->rootDepth, 0); + if (!pPixmap) + return FALSE; + + if (!shadowSetup(pScreen)) { + pScreen->DestroyPixmap(pPixmap); + return FALSE; + } + + shadowAdd(pScreen, pPixmap, update, window, SHADOW_ROTATE_0, 0); + + return TRUE; +} diff --git a/xorg-server/miext/shadow/shalloc.c b/xorg-server/miext/shadow/shalloc.c index 72aa28b14..ebeaaaee6 100644 --- a/xorg-server/miext/shadow/shalloc.c +++ b/xorg-server/miext/shadow/shalloc.c @@ -1,50 +1,50 @@ -/* - * Copyright © 2000 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 <dix-config.h> -#endif - -#include <X11/X.h> -#include "scrnintstr.h" -#include "windowstr.h" -#include <X11/fonts/font.h> -#include "dixfontstr.h" -#include <X11/fonts/fontstruct.h> -#include "mi.h" -#include "regionstr.h" -#include "globals.h" -#include "gcstruct.h" -#include "shadow.h" - -void * -shadowAlloc (int width, int height, int bpp) -{ - int stride; - void *fb; - - /* Cant use PixmapBytePad -- the structure is probably not initialized yet */ - stride = BitmapBytePad (width * bpp); - fb = xalloc (stride * height); - return fb; -} +/* + * Copyright © 2000 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 <dix-config.h> +#endif + +#include <X11/X.h> +#include "scrnintstr.h" +#include "windowstr.h" +#include <X11/fonts/font.h> +#include "dixfontstr.h" +#include <X11/fonts/fontstruct.h> +#include "mi.h" +#include "regionstr.h" +#include "globals.h" +#include "gcstruct.h" +#include "shadow.h" + +void * +shadowAlloc (int width, int height, int bpp) +{ + int stride; + void *fb; + + /* Cant use PixmapBytePad -- the structure is probably not initialized yet */ + stride = BitmapBytePad (width * bpp); + fb = malloc(stride * height); + return fb; +} diff --git a/xorg-server/os/WaitFor.c b/xorg-server/os/WaitFor.c index dfe85e515..ac4b58e48 100644 --- a/xorg-server/os/WaitFor.c +++ b/xorg-server/os/WaitFor.c @@ -1,681 +1,681 @@ -/*********************************************************** - -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. - -******************************************************************/ - - -/***************************************************************** - * OS Dependent input routines: - * - * WaitForSomething - * TimerForce, TimerSet, TimerCheck, TimerFree - * - *****************************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#ifdef WIN32 -#include <X11/Xwinsock.h> -#endif -#include <X11/Xos.h> /* for strings, fcntl, time */ -#include <errno.h> -#include <stdio.h> -#include <X11/X.h> -#include "misc.h" - -#include "osdep.h" -#include <X11/Xpoll.h> -#include "dixstruct.h" -#include "opaque.h" -#ifdef DPMSExtension -#include "dpmsproc.h" -#endif - -#ifdef WIN32 -/* Error codes from windows sockets differ from fileio error codes */ -#undef EINTR -#define EINTR WSAEINTR -#undef EINVAL -#define EINVAL WSAEINVAL -#undef EBADF -#define EBADF WSAENOTSOCK -/* Windows select does not set errno. Use GetErrno as wrapper for - WSAGetLastError */ -#define GetErrno WSAGetLastError -#else -/* This is just a fallback to errno to hide the differences between unix and - Windows in the code */ -#define GetErrno() errno -#endif - -/* like ffs, but uses fd_mask instead of int as argument, so it works - when fd_mask is longer than an int, such as common 64-bit platforms */ -/* modifications by raphael */ -int -mffs(fd_mask mask) -{ - int i; - - if (!mask) return 0; - i = 1; - while (!(mask & 1)) - { - i++; - mask >>= 1; - } - return i; -} - -#ifdef DPMSExtension -#include <X11/extensions/dpmsconst.h> -#endif - -struct _OsTimerRec { - OsTimerPtr next; - CARD32 expires; - CARD32 delta; - OsTimerCallback callback; - pointer arg; -}; - -static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev); -static void CheckAllTimers(void); -static OsTimerPtr timers = NULL; - -/***************** - * WaitForSomething: - * Make the server suspend until there is - * 1. data from clients or - * 2. input events available or - * 3. ddx notices something of interest (graphics - * queue ready, etc.) or - * 4. clients that have buffered replies/events are ready - * - * If the time between INPUT events is - * greater than ScreenSaverTime, the display is turned off (or - * saved, depending on the hardware). So, WaitForSomething() - * has to handle this also (that's why the select() has a timeout. - * For more info on ClientsWithInput, see ReadRequestFromClient(). - * pClientsReady is an array to store ready client->index values into. - *****************/ - -int -WaitForSomething(int *pClientsReady) -{ - int i; - struct timeval waittime, *wt; - INT32 timeout = 0; - fd_set clientsReadable; - fd_set clientsWritable; - int curclient; - int selecterr; - int nready; - fd_set devicesReadable; - CARD32 now = 0; - Bool someReady = FALSE; - - FD_ZERO(&clientsReadable); - - /* We need a while loop here to handle - crashed connections and the screen saver timeout */ - while (1) - { - /* deal with any blocked jobs */ - if (workQueue) - ProcessWorkQueue(); - if (XFD_ANYSET (&ClientsWithInput)) - { - if (!SmartScheduleDisable) - { - someReady = TRUE; - waittime.tv_sec = 0; - waittime.tv_usec = 0; - wt = &waittime; - } - else - { - XFD_COPYSET (&ClientsWithInput, &clientsReadable); - break; - } - } - if (someReady) - { - XFD_COPYSET(&AllSockets, &LastSelectMask); - XFD_UNSET(&LastSelectMask, &ClientsWithInput); - } - else - { - wt = NULL; - if (timers) - { - now = GetTimeInMillis(); - timeout = timers->expires - now; - if (timeout > 0 && timeout > timers->delta + 250) { - /* time has rewound. reset the timers. */ - CheckAllTimers(); - } - - if (timers) { - timeout = timers->expires - now; - if (timeout < 0) - timeout = 0; - waittime.tv_sec = timeout / MILLI_PER_SECOND; - waittime.tv_usec = (timeout % MILLI_PER_SECOND) * - (1000000 / MILLI_PER_SECOND); - wt = &waittime; - } - } - XFD_COPYSET(&AllSockets, &LastSelectMask); - } - SmartScheduleStopTimer (); - - BlockHandler((pointer)&wt, (pointer)&LastSelectMask); - if (NewOutputPending) - FlushAllOutput(); - /* keep this check close to select() call to minimize race */ - if (dispatchException) - i = -1; - else if (AnyClientsWriteBlocked) - { - XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable); - i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); - } - else - { - i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt); - } - selecterr = GetErrno(); - WakeupHandler(i, (pointer)&LastSelectMask); - SmartScheduleStartTimer (); - if (i <= 0) /* An error or timeout occurred */ - { - if (dispatchException) - return 0; - if (i < 0) - { - if (selecterr == EBADF) /* Some client disconnected */ - { - CheckConnections (); - if (! XFD_ANYSET (&AllClients)) - return 0; - } - else if (selecterr == EINVAL) - { - FatalError("WaitForSomething(): select: %s\n", - strerror(selecterr)); - } - else if (selecterr != EINTR && selecterr != EAGAIN) - { - ErrorF("WaitForSomething(): select: %s\n", - strerror(selecterr)); - } - } - else if (someReady) - { - /* - * If no-one else is home, bail quickly - */ - XFD_COPYSET(&ClientsWithInput, &LastSelectMask); - XFD_COPYSET(&ClientsWithInput, &clientsReadable); - break; - } - if (*checkForInput[0] != *checkForInput[1]) - return 0; - - if (timers) - { - int expired = 0; - now = GetTimeInMillis(); - if ((int) (timers->expires - now) <= 0) - expired = 1; - - while (timers && (int) (timers->expires - now) <= 0) - DoTimer(timers, now, &timers); - - if (expired) - return 0; - } - } - else - { - fd_set tmp_set; - - if (*checkForInput[0] == *checkForInput[1]) { - if (timers) - { - int expired = 0; - now = GetTimeInMillis(); - if ((int) (timers->expires - now) <= 0) - expired = 1; - - while (timers && (int) (timers->expires - now) <= 0) - DoTimer(timers, now, &timers); - - if (expired) - return 0; - } - } - if (someReady) - XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); - if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable)) - { - NewOutputPending = TRUE; - XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); - XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); - if (! XFD_ANYSET(&ClientsWriteBlocked)) - AnyClientsWriteBlocked = FALSE; - } - - XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices); - XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); - XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); - if (XFD_ANYSET(&tmp_set)) - QueueWorkProc(EstablishNewConnections, NULL, - (pointer)&LastSelectMask); - - if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable)) - break; - /* check here for DDXes that queue events during Block/Wakeup */ - if (*checkForInput[0] != *checkForInput[1]) - return 0; - } - } - - nready = 0; - if (XFD_ANYSET (&clientsReadable)) - { -#ifndef WIN32 - for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) - { - int highest_priority = 0; - - while (clientsReadable.fds_bits[i]) - { - int client_priority, client_index; - - curclient = mffs (clientsReadable.fds_bits[i]) - 1; - client_index = /* raphael: modified */ - ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))]; -#else - int highest_priority = 0; - fd_set savedClientsReadable; - XFD_COPYSET(&clientsReadable, &savedClientsReadable); - for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++) - { - int client_priority, client_index; - - curclient = XFD_FD(&savedClientsReadable, i); - client_index = GetConnectionTranslation(curclient); -#endif - /* We implement "strict" priorities. - * Only the highest priority client is returned to - * dix. If multiple clients at the same priority are - * ready, they are all returned. This means that an - * aggressive client could take over the server. - * This was not considered a big problem because - * aggressive clients can hose the server in so many - * other ways :) - */ - client_priority = clients[client_index]->priority; - if (nready == 0 || client_priority > highest_priority) - { - /* Either we found the first client, or we found - * a client whose priority is greater than all others - * that have been found so far. Either way, we want - * to initialize the list of clients to contain just - * this client. - */ - pClientsReady[0] = client_index; - highest_priority = client_priority; - nready = 1; - } - /* the following if makes sure that multiple same-priority - * clients get batched together - */ - else if (client_priority == highest_priority) - { - pClientsReady[nready++] = client_index; - } -#ifndef WIN32 - clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); - } -#else - FD_CLR(curclient, &clientsReadable); -#endif - } - } - return nready; -} - -/* If time has rewound, re-run every affected timer. - * Timers might drop out of the list, so we have to restart every time. */ -static void -CheckAllTimers(void) -{ - OsTimerPtr timer; - CARD32 now; - -start: - now = GetTimeInMillis(); - - for (timer = timers; timer; timer = timer->next) { - if (timer->expires - now > timer->delta + 250) { - TimerForce(timer); - goto start; - } - } -} - -static void -DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev) -{ - CARD32 newTime; - - *prev = timer->next; - timer->next = NULL; - newTime = (*timer->callback)(timer, now, timer->arg); - if (newTime) - TimerSet(timer, 0, newTime, timer->callback, timer->arg); -} - -OsTimerPtr -TimerSet(OsTimerPtr timer, int flags, CARD32 millis, - OsTimerCallback func, pointer arg) -{ - register OsTimerPtr *prev; - CARD32 now = GetTimeInMillis(); - - if (!timer) - { - timer = xalloc(sizeof(struct _OsTimerRec)); - if (!timer) - return NULL; - } - else - { - for (prev = &timers; *prev; prev = &(*prev)->next) - { - if (*prev == timer) - { - *prev = timer->next; - if (flags & TimerForceOld) - (void)(*timer->callback)(timer, now, timer->arg); - break; - } - } - } - if (!millis) - return timer; - if (flags & TimerAbsolute) { - timer->delta = millis - now; - } - else { - timer->delta = millis; - millis += now; - } - timer->expires = millis; - timer->callback = func; - timer->arg = arg; - if ((int) (millis - now) <= 0) - { - timer->next = NULL; - millis = (*timer->callback)(timer, now, timer->arg); - if (!millis) - return timer; - } - for (prev = &timers; - *prev && (int) ((*prev)->expires - millis) <= 0; - prev = &(*prev)->next) - ; - timer->next = *prev; - *prev = timer; - return timer; -} - -Bool -TimerForce(OsTimerPtr timer) -{ - OsTimerPtr *prev; - - for (prev = &timers; *prev; prev = &(*prev)->next) - { - if (*prev == timer) - { - DoTimer(timer, GetTimeInMillis(), prev); - return TRUE; - } - } - return FALSE; -} - - -void -TimerCancel(OsTimerPtr timer) -{ - OsTimerPtr *prev; - - if (!timer) - return; - for (prev = &timers; *prev; prev = &(*prev)->next) - { - if (*prev == timer) - { - *prev = timer->next; - break; - } - } -} - -void -TimerFree(OsTimerPtr timer) -{ - if (!timer) - return; - TimerCancel(timer); - xfree(timer); -} - -void -TimerCheck(void) -{ - CARD32 now = GetTimeInMillis(); - - while (timers && (int) (timers->expires - now) <= 0) - DoTimer(timers, now, &timers); -} - -void -TimerInit(void) -{ - OsTimerPtr timer; - - while ((timer = timers)) - { - timers = timer->next; - xfree(timer); - } -} - -#ifdef DPMSExtension - -#define DPMS_CHECK_MODE(mode,time)\ - if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\ - DPMSSet(serverClient, mode); - -#define DPMS_CHECK_TIMEOUT(time)\ - if (time > 0 && (time - timeout) > 0)\ - return time - timeout; - -static CARD32 -NextDPMSTimeout(INT32 timeout) -{ - /* - * Return the amount of time remaining until we should set - * the next power level. Fallthroughs are intentional. - */ - switch (DPMSPowerLevel) - { - case DPMSModeOn: - DPMS_CHECK_TIMEOUT(DPMSStandbyTime) - - case DPMSModeStandby: - DPMS_CHECK_TIMEOUT(DPMSSuspendTime) - - case DPMSModeSuspend: - DPMS_CHECK_TIMEOUT(DPMSOffTime) - - default: /* DPMSModeOff */ - return 0; - } -} -#endif /* DPMSExtension */ - -static CARD32 -ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg) -{ - INT32 timeout = now - lastDeviceEventTime.milliseconds; - CARD32 nextTimeout = 0; - -#ifdef DPMSExtension - /* - * Check each mode lowest to highest, since a lower mode can - * have the same timeout as a higher one. - */ - if (DPMSEnabled) - { - DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime) - DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime) - DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime) - - nextTimeout = NextDPMSTimeout(timeout); - } - - /* - * Only do the screensaver checks if we're not in a DPMS - * power saving mode - */ - if (DPMSPowerLevel != DPMSModeOn) - return nextTimeout; -#endif /* DPMSExtension */ - - if (!ScreenSaverTime) - return nextTimeout; - - if (timeout < ScreenSaverTime) - { - return nextTimeout > 0 ? - min(ScreenSaverTime - timeout, nextTimeout) : - ScreenSaverTime - timeout; - } - - ResetOsBuffers(); /* not ideal, but better than nothing */ - dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive); - - if (ScreenSaverInterval > 0) - { - nextTimeout = nextTimeout > 0 ? - min(ScreenSaverInterval, nextTimeout) : - ScreenSaverInterval; - } - - return nextTimeout; -} - -static OsTimerPtr ScreenSaverTimer = NULL; - -void -FreeScreenSaverTimer(void) -{ - if (ScreenSaverTimer) { - TimerFree(ScreenSaverTimer); - ScreenSaverTimer = NULL; - } -} - -void -SetScreenSaverTimer(void) -{ - CARD32 timeout = 0; - -#ifdef DPMSExtension - if (DPMSEnabled) - { - /* - * A higher DPMS level has a timeout that's either less - * than or equal to that of a lower DPMS level. - */ - if (DPMSStandbyTime > 0) - timeout = DPMSStandbyTime; - - else if (DPMSSuspendTime > 0) - timeout = DPMSSuspendTime; - - else if (DPMSOffTime > 0) - timeout = DPMSOffTime; - } -#endif - - if (ScreenSaverTime > 0) - { - timeout = timeout > 0 ? - min(ScreenSaverTime, timeout) : - ScreenSaverTime; - } - -#ifdef SCREENSAVER - if (timeout && !screenSaverSuspended) { -#else - if (timeout) { -#endif - ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout, - ScreenSaverTimeoutExpire, NULL); - } - else if (ScreenSaverTimer) { - FreeScreenSaverTimer(); - } -} - +/*********************************************************** + +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. + +******************************************************************/ + + +/***************************************************************** + * OS Dependent input routines: + * + * WaitForSomething + * TimerForce, TimerSet, TimerCheck, TimerFree + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <X11/Xos.h> /* for strings, fcntl, time */ +#include <errno.h> +#include <stdio.h> +#include <X11/X.h> +#include "misc.h" + +#include "osdep.h" +#include <X11/Xpoll.h> +#include "dixstruct.h" +#include "opaque.h" +#ifdef DPMSExtension +#include "dpmsproc.h" +#endif + +#ifdef WIN32 +/* Error codes from windows sockets differ from fileio error codes */ +#undef EINTR +#define EINTR WSAEINTR +#undef EINVAL +#define EINVAL WSAEINVAL +#undef EBADF +#define EBADF WSAENOTSOCK +/* Windows select does not set errno. Use GetErrno as wrapper for + WSAGetLastError */ +#define GetErrno WSAGetLastError +#else +/* This is just a fallback to errno to hide the differences between unix and + Windows in the code */ +#define GetErrno() errno +#endif + +/* like ffs, but uses fd_mask instead of int as argument, so it works + when fd_mask is longer than an int, such as common 64-bit platforms */ +/* modifications by raphael */ +int +mffs(fd_mask mask) +{ + int i; + + if (!mask) return 0; + i = 1; + while (!(mask & 1)) + { + i++; + mask >>= 1; + } + return i; +} + +#ifdef DPMSExtension +#include <X11/extensions/dpmsconst.h> +#endif + +struct _OsTimerRec { + OsTimerPtr next; + CARD32 expires; + CARD32 delta; + OsTimerCallback callback; + pointer arg; +}; + +static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev); +static void CheckAllTimers(void); +static OsTimerPtr timers = NULL; + +/***************** + * WaitForSomething: + * Make the server suspend until there is + * 1. data from clients or + * 2. input events available or + * 3. ddx notices something of interest (graphics + * queue ready, etc.) or + * 4. clients that have buffered replies/events are ready + * + * If the time between INPUT events is + * greater than ScreenSaverTime, the display is turned off (or + * saved, depending on the hardware). So, WaitForSomething() + * has to handle this also (that's why the select() has a timeout. + * For more info on ClientsWithInput, see ReadRequestFromClient(). + * pClientsReady is an array to store ready client->index values into. + *****************/ + +int +WaitForSomething(int *pClientsReady) +{ + int i; + struct timeval waittime, *wt; + INT32 timeout = 0; + fd_set clientsReadable; + fd_set clientsWritable; + int curclient; + int selecterr; + int nready; + fd_set devicesReadable; + CARD32 now = 0; + Bool someReady = FALSE; + + FD_ZERO(&clientsReadable); + + /* We need a while loop here to handle + crashed connections and the screen saver timeout */ + while (1) + { + /* deal with any blocked jobs */ + if (workQueue) + ProcessWorkQueue(); + if (XFD_ANYSET (&ClientsWithInput)) + { + if (!SmartScheduleDisable) + { + someReady = TRUE; + waittime.tv_sec = 0; + waittime.tv_usec = 0; + wt = &waittime; + } + else + { + XFD_COPYSET (&ClientsWithInput, &clientsReadable); + break; + } + } + if (someReady) + { + XFD_COPYSET(&AllSockets, &LastSelectMask); + XFD_UNSET(&LastSelectMask, &ClientsWithInput); + } + else + { + wt = NULL; + if (timers) + { + now = GetTimeInMillis(); + timeout = timers->expires - now; + if (timeout > 0 && timeout > timers->delta + 250) { + /* time has rewound. reset the timers. */ + CheckAllTimers(); + } + + if (timers) { + timeout = timers->expires - now; + if (timeout < 0) + timeout = 0; + waittime.tv_sec = timeout / MILLI_PER_SECOND; + waittime.tv_usec = (timeout % MILLI_PER_SECOND) * + (1000000 / MILLI_PER_SECOND); + wt = &waittime; + } + } + XFD_COPYSET(&AllSockets, &LastSelectMask); + } + SmartScheduleStopTimer (); + + BlockHandler((pointer)&wt, (pointer)&LastSelectMask); + if (NewOutputPending) + FlushAllOutput(); + /* keep this check close to select() call to minimize race */ + if (dispatchException) + i = -1; + else if (AnyClientsWriteBlocked) + { + XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable); + i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); + } + else + { + i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt); + } + selecterr = GetErrno(); + WakeupHandler(i, (pointer)&LastSelectMask); + SmartScheduleStartTimer (); + if (i <= 0) /* An error or timeout occurred */ + { + if (dispatchException) + return 0; + if (i < 0) + { + if (selecterr == EBADF) /* Some client disconnected */ + { + CheckConnections (); + if (! XFD_ANYSET (&AllClients)) + return 0; + } + else if (selecterr == EINVAL) + { + FatalError("WaitForSomething(): select: %s\n", + strerror(selecterr)); + } + else if (selecterr != EINTR && selecterr != EAGAIN) + { + ErrorF("WaitForSomething(): select: %s\n", + strerror(selecterr)); + } + } + else if (someReady) + { + /* + * If no-one else is home, bail quickly + */ + XFD_COPYSET(&ClientsWithInput, &LastSelectMask); + XFD_COPYSET(&ClientsWithInput, &clientsReadable); + break; + } + if (*checkForInput[0] != *checkForInput[1]) + return 0; + + if (timers) + { + int expired = 0; + now = GetTimeInMillis(); + if ((int) (timers->expires - now) <= 0) + expired = 1; + + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); + + if (expired) + return 0; + } + } + else + { + fd_set tmp_set; + + if (*checkForInput[0] == *checkForInput[1]) { + if (timers) + { + int expired = 0; + now = GetTimeInMillis(); + if ((int) (timers->expires - now) <= 0) + expired = 1; + + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); + + if (expired) + return 0; + } + } + if (someReady) + XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); + if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable)) + { + NewOutputPending = TRUE; + XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); + XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); + if (! XFD_ANYSET(&ClientsWriteBlocked)) + AnyClientsWriteBlocked = FALSE; + } + + XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices); + XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); + XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); + if (XFD_ANYSET(&tmp_set)) + QueueWorkProc(EstablishNewConnections, NULL, + (pointer)&LastSelectMask); + + if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable)) + break; + /* check here for DDXes that queue events during Block/Wakeup */ + if (*checkForInput[0] != *checkForInput[1]) + return 0; + } + } + + nready = 0; + if (XFD_ANYSET (&clientsReadable)) + { +#ifndef WIN32 + for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) + { + int highest_priority = 0; + + while (clientsReadable.fds_bits[i]) + { + int client_priority, client_index; + + curclient = mffs (clientsReadable.fds_bits[i]) - 1; + client_index = /* raphael: modified */ + ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))]; +#else + int highest_priority = 0; + fd_set savedClientsReadable; + XFD_COPYSET(&clientsReadable, &savedClientsReadable); + for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++) + { + int client_priority, client_index; + + curclient = XFD_FD(&savedClientsReadable, i); + client_index = GetConnectionTranslation(curclient); +#endif + /* We implement "strict" priorities. + * Only the highest priority client is returned to + * dix. If multiple clients at the same priority are + * ready, they are all returned. This means that an + * aggressive client could take over the server. + * This was not considered a big problem because + * aggressive clients can hose the server in so many + * other ways :) + */ + client_priority = clients[client_index]->priority; + if (nready == 0 || client_priority > highest_priority) + { + /* Either we found the first client, or we found + * a client whose priority is greater than all others + * that have been found so far. Either way, we want + * to initialize the list of clients to contain just + * this client. + */ + pClientsReady[0] = client_index; + highest_priority = client_priority; + nready = 1; + } + /* the following if makes sure that multiple same-priority + * clients get batched together + */ + else if (client_priority == highest_priority) + { + pClientsReady[nready++] = client_index; + } +#ifndef WIN32 + clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); + } +#else + FD_CLR(curclient, &clientsReadable); +#endif + } + } + return nready; +} + +/* If time has rewound, re-run every affected timer. + * Timers might drop out of the list, so we have to restart every time. */ +static void +CheckAllTimers(void) +{ + OsTimerPtr timer; + CARD32 now; + +start: + now = GetTimeInMillis(); + + for (timer = timers; timer; timer = timer->next) { + if (timer->expires - now > timer->delta + 250) { + TimerForce(timer); + goto start; + } + } +} + +static void +DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev) +{ + CARD32 newTime; + + *prev = timer->next; + timer->next = NULL; + newTime = (*timer->callback)(timer, now, timer->arg); + if (newTime) + TimerSet(timer, 0, newTime, timer->callback, timer->arg); +} + +OsTimerPtr +TimerSet(OsTimerPtr timer, int flags, CARD32 millis, + OsTimerCallback func, pointer arg) +{ + register OsTimerPtr *prev; + CARD32 now = GetTimeInMillis(); + + if (!timer) + { + timer = malloc(sizeof(struct _OsTimerRec)); + if (!timer) + return NULL; + } + else + { + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + *prev = timer->next; + if (flags & TimerForceOld) + (void)(*timer->callback)(timer, now, timer->arg); + break; + } + } + } + if (!millis) + return timer; + if (flags & TimerAbsolute) { + timer->delta = millis - now; + } + else { + timer->delta = millis; + millis += now; + } + timer->expires = millis; + timer->callback = func; + timer->arg = arg; + if ((int) (millis - now) <= 0) + { + timer->next = NULL; + millis = (*timer->callback)(timer, now, timer->arg); + if (!millis) + return timer; + } + for (prev = &timers; + *prev && (int) ((*prev)->expires - millis) <= 0; + prev = &(*prev)->next) + ; + timer->next = *prev; + *prev = timer; + return timer; +} + +Bool +TimerForce(OsTimerPtr timer) +{ + OsTimerPtr *prev; + + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + DoTimer(timer, GetTimeInMillis(), prev); + return TRUE; + } + } + return FALSE; +} + + +void +TimerCancel(OsTimerPtr timer) +{ + OsTimerPtr *prev; + + if (!timer) + return; + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + *prev = timer->next; + break; + } + } +} + +void +TimerFree(OsTimerPtr timer) +{ + if (!timer) + return; + TimerCancel(timer); + free(timer); +} + +void +TimerCheck(void) +{ + CARD32 now = GetTimeInMillis(); + + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); +} + +void +TimerInit(void) +{ + OsTimerPtr timer; + + while ((timer = timers)) + { + timers = timer->next; + free(timer); + } +} + +#ifdef DPMSExtension + +#define DPMS_CHECK_MODE(mode,time)\ + if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\ + DPMSSet(serverClient, mode); + +#define DPMS_CHECK_TIMEOUT(time)\ + if (time > 0 && (time - timeout) > 0)\ + return time - timeout; + +static CARD32 +NextDPMSTimeout(INT32 timeout) +{ + /* + * Return the amount of time remaining until we should set + * the next power level. Fallthroughs are intentional. + */ + switch (DPMSPowerLevel) + { + case DPMSModeOn: + DPMS_CHECK_TIMEOUT(DPMSStandbyTime) + + case DPMSModeStandby: + DPMS_CHECK_TIMEOUT(DPMSSuspendTime) + + case DPMSModeSuspend: + DPMS_CHECK_TIMEOUT(DPMSOffTime) + + default: /* DPMSModeOff */ + return 0; + } +} +#endif /* DPMSExtension */ + +static CARD32 +ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg) +{ + INT32 timeout = now - lastDeviceEventTime.milliseconds; + CARD32 nextTimeout = 0; + +#ifdef DPMSExtension + /* + * Check each mode lowest to highest, since a lower mode can + * have the same timeout as a higher one. + */ + if (DPMSEnabled) + { + DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime) + DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime) + DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime) + + nextTimeout = NextDPMSTimeout(timeout); + } + + /* + * Only do the screensaver checks if we're not in a DPMS + * power saving mode + */ + if (DPMSPowerLevel != DPMSModeOn) + return nextTimeout; +#endif /* DPMSExtension */ + + if (!ScreenSaverTime) + return nextTimeout; + + if (timeout < ScreenSaverTime) + { + return nextTimeout > 0 ? + min(ScreenSaverTime - timeout, nextTimeout) : + ScreenSaverTime - timeout; + } + + ResetOsBuffers(); /* not ideal, but better than nothing */ + dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive); + + if (ScreenSaverInterval > 0) + { + nextTimeout = nextTimeout > 0 ? + min(ScreenSaverInterval, nextTimeout) : + ScreenSaverInterval; + } + + return nextTimeout; +} + +static OsTimerPtr ScreenSaverTimer = NULL; + +void +FreeScreenSaverTimer(void) +{ + if (ScreenSaverTimer) { + TimerFree(ScreenSaverTimer); + ScreenSaverTimer = NULL; + } +} + +void +SetScreenSaverTimer(void) +{ + CARD32 timeout = 0; + +#ifdef DPMSExtension + if (DPMSEnabled) + { + /* + * A higher DPMS level has a timeout that's either less + * than or equal to that of a lower DPMS level. + */ + if (DPMSStandbyTime > 0) + timeout = DPMSStandbyTime; + + else if (DPMSSuspendTime > 0) + timeout = DPMSSuspendTime; + + else if (DPMSOffTime > 0) + timeout = DPMSOffTime; + } +#endif + + if (ScreenSaverTime > 0) + { + timeout = timeout > 0 ? + min(ScreenSaverTime, timeout) : + ScreenSaverTime; + } + +#ifdef SCREENSAVER + if (timeout && !screenSaverSuspended) { +#else + if (timeout) { +#endif + ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout, + ScreenSaverTimeoutExpire, NULL); + } + else if (ScreenSaverTimer) { + FreeScreenSaverTimer(); + } +} + diff --git a/xorg-server/os/access.c b/xorg-server/os/access.c index 603210f85..2a0ea01cd 100644 --- a/xorg-server/os/access.c +++ b/xorg-server/os/access.c @@ -238,12 +238,12 @@ typedef struct _host { int requested; } HOST; -#define MakeHost(h,l) (h)=xalloc(sizeof *(h)+(l));\ +#define MakeHost(h,l) (h)=malloc(sizeof *(h)+(l));\ if (h) { \ (h)->addr=(unsigned char *) ((h) + 1);\ (h)->requested = FALSE; \ } -#define FreeHost(h) xfree(h) +#define FreeHost(h) free(h) static HOST *selfhosts = NULL; static HOST *validhosts = NULL; static int AccessEnabled = DEFAULT_ACCESS_CONTROL; @@ -587,7 +587,7 @@ DefineSelf (int fd) Error ("Getting interface count"); if (len < (ifn.lifn_count * sizeof(struct lifreq))) { len = ifn.lifn_count * sizeof(struct lifreq); - bufptr = xalloc(len); + bufptr = malloc(len); } #endif @@ -765,7 +765,8 @@ DefineSelf (int fd) continue; #endif /* DNETCONN */ len = sizeof(*(ifr->ifa_addr)); - family = ConvertAddr(ifr->ifa_addr, &len, (pointer *)&addr); + family = ConvertAddr((struct sockaddr *) ifr->ifa_addr, &len, + (pointer *)&addr); if (family == -1 || family == FamilyLocal) continue; #if defined(IPv6) && defined(AF_INET6) @@ -789,7 +790,6 @@ DefineSelf (int fd) } #ifdef XDMCP { - struct sockaddr broad_addr; /* * If this isn't an Internet Address, don't register it. */ @@ -835,11 +835,10 @@ DefineSelf (int fd) if ((ifr->ifa_flags & IFF_BROADCAST) && (ifr->ifa_flags & IFF_UP) && ifr->ifa_broadaddr) - broad_addr = *ifr->ifa_broadaddr; + XdmcpRegisterBroadcastAddress( + (struct sockaddr_in *) ifr->ifa_broadaddr); else continue; - XdmcpRegisterBroadcastAddress((struct sockaddr_in *) - &broad_addr); } #endif /* XDMCP */ @@ -1131,12 +1130,12 @@ Bool LocalClient(ClientPtr client) &alen, (pointer *)&addr); if (family == -1) { - xfree (from); + free(from); return FALSE; } if (family == FamilyLocal) { - xfree (from); + free(from); return TRUE; } for (host = selfhosts; host; host = host->next) @@ -1144,7 +1143,7 @@ Bool LocalClient(ClientPtr client) if (addrEqual (family, addr, alen, host)) return TRUE; } - xfree (from); + free(from); } return FALSE; } @@ -1214,7 +1213,7 @@ GetLocalClientCreds(ClientPtr client, LocalClientCredRec **lccp) } #endif - *lccp = Xcalloc(sizeof(LocalClientCredRec)); + *lccp = calloc(1, sizeof(LocalClientCredRec)); if (*lccp == NULL) return -1; lcc = *lccp; @@ -1250,7 +1249,7 @@ GetLocalClientCreds(ClientPtr client, LocalClientCredRec **lccp) #endif lcc->nSuppGids = ucred_getgroups(peercred, &gids); if (lcc->nSuppGids > 0) { - lcc->pSuppGids = Xcalloc((lcc->nSuppGids) * sizeof(int)); + lcc->pSuppGids = calloc(lcc->nSuppGids, sizeof(int)); if (lcc->pSuppGids == NULL) { lcc->nSuppGids = 0; } else { @@ -1287,9 +1286,9 @@ FreeLocalClientCreds(LocalClientCredRec *lcc) { if (lcc != NULL) { if (lcc->nSuppGids > 0) { - Xfree(lcc->pSuppGids); + free(lcc->pSuppGids); } - Xfree(lcc); + free(lcc); } } @@ -1484,7 +1483,7 @@ GetHosts ( } if (n) { - *data = ptr = xalloc (n); + *data = ptr = malloc(n); if (!ptr) { return(BadAlloc); @@ -1743,7 +1742,7 @@ siTypeAdd(const char *typeName, siAddrMatchFunc addrMatch, } } - s = xalloc(sizeof(struct siType)); + s = malloc(sizeof(struct siType)); if (s == NULL) return BadAlloc; @@ -2085,7 +2084,7 @@ static Bool siLocalCredGetId(const char *addr, int len, siLocalCredPrivPtr lcPriv, int *id) { Bool parsedOK = FALSE; - char *addrbuf = xalloc(len + 1); + char *addrbuf = malloc(len + 1); if (addrbuf == NULL) { return FALSE; @@ -2119,7 +2118,7 @@ siLocalCredGetId(const char *addr, int len, siLocalCredPrivPtr lcPriv, int *id) } } - xfree(addrbuf); + free(addrbuf); return parsedOK; } diff --git a/xorg-server/os/connection.c b/xorg-server/os/connection.c index 61ba72a80..20d1dee28 100644 --- a/xorg-server/os/connection.c +++ b/xorg-server/os/connection.c @@ -1,1300 +1,1300 @@ -/*********************************************************** - -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. - -******************************************************************/ -/***************************************************************** - * Stuff to create connections --- OS dependent - * - * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets, - * CloseDownConnection, CheckConnections, AddEnabledDevice, - * RemoveEnabledDevice, OnlyListToOneClient, - * ListenToAllClients, - * - * (WaitForSomething is in its own file) - * - * In this implementation, a client socket table is not kept. - * Instead, what would be the index into the table is just the - * file descriptor of the socket. This won't work for if the - * socket ids aren't small nums (0 - 2^8) - * - *****************************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#ifdef WIN32 -#include <X11/Xwinsock.h> -#endif -#include <X11/X.h> -#include <X11/Xproto.h> -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include <X11/Xtrans/Xtrans.h> -#include <X11/Xtrans/Xtransint.h> -#include <errno.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> - -#ifndef WIN32 -#include <sys/socket.h> - - - -#if defined(TCPCONN) || defined(STREAMSCONN) -# include <netinet/in.h> -# include <arpa/inet.h> -# ifdef apollo -# ifndef NO_TCP_H -# include <netinet/tcp.h> -# endif -# else -# ifdef CSRG_BASED -# include <sys/param.h> -# endif -# include <netinet/tcp.h> -# endif -# include <arpa/inet.h> -#endif - -#include <sys/uio.h> - -#endif /* WIN32 */ -#include "misc.h" /* for typedef of pointer */ -#include "osdep.h" -#include <X11/Xpoll.h> -#include "opaque.h" -#include "dixstruct.h" -#include "xace.h" - -#define Pid_t pid_t - -#ifdef DNETCONN -#include <netdnet/dn.h> -#endif /* DNETCONN */ - -#ifdef HAS_GETPEERUCRED -# include <ucred.h> -# include <zone.h> -#endif - -#ifdef XSERVER_DTRACE -# include <sys/types.h> -typedef const char *string; -# ifndef HAS_GETPEERUCRED -# define zoneid_t int -# endif -# include "../dix/Xserver-dtrace.h" -#endif - -static int lastfdesc; /* maximum file descriptor */ - -fd_set WellKnownConnections; /* Listener mask */ -fd_set EnabledDevices; /* mask for input devices that are on */ -fd_set AllSockets; /* select on this */ -fd_set AllClients; /* available clients */ -fd_set LastSelectMask; /* mask returned from last select call */ -fd_set ClientsWithInput; /* clients with FULL requests in buffer */ -fd_set ClientsWriteBlocked; /* clients who cannot receive output */ -fd_set OutputPending; /* clients with reply/event data ready to go */ -int MaxClients = 0; -Bool NewOutputPending; /* not yet attempted to write some new output */ -Bool AnyClientsWriteBlocked; /* true if some client blocked on write */ - -static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ -Bool PartialNetwork; /* continue even if unable to bind all addrs */ -static Pid_t ParentProcess; - -static Bool debug_conns = FALSE; - -fd_set IgnoredClientsWithInput; -static fd_set GrabImperviousClients; -static fd_set SavedAllClients; -static fd_set SavedAllSockets; -static fd_set SavedClientsWithInput; -int GrabInProgress = 0; - -#if !defined(WIN32) -int *ConnectionTranslation = NULL; -#else -/* - * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is - * not even a known maximum value, so use something quite arbitrary for now. - * Do storage is a hash table of size 256. Collisions are handled in a linked - * list. - */ - -#undef MAXSOCKS -#define MAXSOCKS 500 -#undef MAXSELECT -#define MAXSELECT 500 - -struct _ct_node { - struct _ct_node *next; - int key; - int value; -}; - -struct _ct_node *ct_head[256]; - -void InitConnectionTranslation(void) -{ - bzero(ct_head, sizeof(ct_head)); -} - -int GetConnectionTranslation(int conn) -{ - struct _ct_node *node = ct_head[conn & 0xff]; - while (node != NULL) - { - if (node->key == conn) - return node->value; - node = node->next; - } - return 0; -} - -void SetConnectionTranslation(int conn, int client) -{ - struct _ct_node **node = ct_head + (conn & 0xff); - if (client == 0) /* remove entry */ - { - while (*node != NULL) - { - if ((*node)->key == conn) - { - struct _ct_node *temp = *node; - *node = (*node)->next; - free(temp); - return; - } - node = &((*node)->next); - } - return; - } else - { - while (*node != NULL) - { - if ((*node)->key == conn) - { - (*node)->value = client; - return; - } - node = &((*node)->next); - } - *node = xalloc(sizeof(struct _ct_node)); - (*node)->next = NULL; - (*node)->key = conn; - (*node)->value = client; - return; - } -} - -void ClearConnectionTranslation(void) -{ - unsigned i; - for (i = 0; i < 256; i++) - { - struct _ct_node *node = ct_head[i]; - while (node != NULL) - { - struct _ct_node *temp = node; - node = node->next; - xfree(temp); - } - } -} -#endif - -static XtransConnInfo *ListenTransConns = NULL; -static int *ListenTransFds = NULL; -static int ListenTransCount; - -static void ErrorConnMax(XtransConnInfo /* trans_conn */); - -static XtransConnInfo -lookup_trans_conn (int fd) -{ - if (ListenTransFds) - { - int i; - for (i = 0; i < ListenTransCount; i++) - if (ListenTransFds[i] == fd) - return ListenTransConns[i]; - } - - return (NULL); -} - -/* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */ - -void -InitConnectionLimits(void) -{ - lastfdesc = -1; - -#ifndef __CYGWIN__ - -#if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX) - lastfdesc = sysconf(_SC_OPEN_MAX) - 1; -#endif - -#ifdef HAS_GETDTABLESIZE - if (lastfdesc < 0) - lastfdesc = getdtablesize() - 1; -#endif - -#ifdef _NFILE - if (lastfdesc < 0) - lastfdesc = _NFILE - 1; -#endif - -#endif /* __CYGWIN__ */ - - /* This is the fallback */ - if (lastfdesc < 0) - lastfdesc = MAXSOCKS; - - if (lastfdesc > MAXSELECT) - lastfdesc = MAXSELECT; - - if (lastfdesc > MAXCLIENTS) - { - lastfdesc = MAXCLIENTS; - if (debug_conns) - ErrorF( "REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS); - } - MaxClients = lastfdesc; - -#ifdef DEBUG - ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients); -#endif - -#if !defined(WIN32) - if (!ConnectionTranslation) - ConnectionTranslation = (int *)xnfalloc(sizeof(int)*(lastfdesc + 1)); -#else - InitConnectionTranslation(); -#endif -} - -/* - * If SIGUSR1 was set to SIG_IGN when the server started, assume that either - * - * a- The parent process is ignoring SIGUSR1 - * - * or - * - * b- The parent process is expecting a SIGUSR1 - * when the server is ready to accept connections - * - * In the first case, the signal will be harmless, in the second case, - * the signal will be quite useful. - */ -static void -InitParentProcess(void) -{ -#if !defined(WIN32) - OsSigHandlerPtr handler; - handler = OsSignal (SIGUSR1, SIG_IGN); - if ( handler == SIG_IGN) - RunFromSmartParent = TRUE; - OsSignal(SIGUSR1, handler); - ParentProcess = getppid (); -#endif -} - -void -NotifyParentProcess(void) -{ -#if !defined(WIN32) - if (RunFromSmartParent) { - if (ParentProcess > 1) { - kill (ParentProcess, SIGUSR1); - } - } -#endif -} - -/***************** - * CreateWellKnownSockets - * At initialization, create the sockets to listen on for new clients. - *****************/ - -void -CreateWellKnownSockets(void) -{ - int i; - int partial; - char port[20]; - - FD_ZERO(&AllSockets); - FD_ZERO(&AllClients); - FD_ZERO(&LastSelectMask); - FD_ZERO(&ClientsWithInput); - -#if !defined(WIN32) - for (i=0; i<MaxClients; i++) ConnectionTranslation[i] = 0; -#else - ClearConnectionTranslation(); -#endif - - FD_ZERO (&WellKnownConnections); - - sprintf (port, "%d", atoi (display)); - - if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial, - &ListenTransCount, &ListenTransConns) >= 0) && - (ListenTransCount >= 1)) - { - if (!PartialNetwork && partial) - { - FatalError ("Failed to establish all listening sockets"); - } - else - { - ListenTransFds = xalloc (ListenTransCount * sizeof (int)); - - for (i = 0; i < ListenTransCount; i++) - { - int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); - - ListenTransFds[i] = fd; - FD_SET (fd, &WellKnownConnections); - - if (!_XSERVTransIsLocal (ListenTransConns[i])) - { - DefineSelf (fd); - } - } - } - } - - if (!XFD_ANYSET (&WellKnownConnections)) - FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running"); -#if !defined(WIN32) - OsSignal (SIGPIPE, SIG_IGN); - OsSignal (SIGHUP, AutoResetServer); -#endif - OsSignal (SIGINT, GiveUp); - OsSignal (SIGTERM, GiveUp); - XFD_COPYSET (&WellKnownConnections, &AllSockets); - ResetHosts(display); - - InitParentProcess(); - -#ifdef XDMCP - XdmcpInit (); -#endif -} - -void -ResetWellKnownSockets (void) -{ - int i; - - ResetOsBuffers(); - - for (i = 0; i < ListenTransCount; i++) - { - int status = _XSERVTransResetListener (ListenTransConns[i]); - - if (status != TRANS_RESET_NOOP) - { - if (status == TRANS_RESET_FAILURE) - { - /* - * ListenTransConns[i] freed by xtrans. - * Remove it from out list. - */ - - FD_CLR (ListenTransFds[i], &WellKnownConnections); - ListenTransFds[i] = ListenTransFds[ListenTransCount - 1]; - ListenTransConns[i] = ListenTransConns[ListenTransCount - 1]; - ListenTransCount -= 1; - i -= 1; - } - else if (status == TRANS_RESET_NEW_FD) - { - /* - * A new file descriptor was allocated (the old one was closed) - */ - - int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); - - FD_CLR (ListenTransFds[i], &WellKnownConnections); - ListenTransFds[i] = newfd; - FD_SET(newfd, &WellKnownConnections); - } - } - } - - ResetAuthorization (); - ResetHosts(display); - /* - * restart XDMCP - */ -#ifdef XDMCP - XdmcpReset (); -#endif -} - -void -CloseWellKnownConnections(void) -{ - int i; - - for (i = 0; i < ListenTransCount; i++) - _XSERVTransClose (ListenTransConns[i]); -} - -static void -AuthAudit (ClientPtr client, Bool letin, - struct sockaddr *saddr, int len, - unsigned int proto_n, char *auth_proto, int auth_id) -{ - char addr[128]; - char *out = addr; - char client_uid_string[64]; - LocalClientCredRec *lcc; -#ifdef XSERVER_DTRACE - pid_t client_pid = -1; - zoneid_t client_zid = -1; -#endif - - if (!len) - strcpy(out, "local host"); - else - switch (saddr->sa_family) - { - case AF_UNSPEC: -#if defined(UNIXCONN) || defined(LOCALCONN) - case AF_UNIX: -#endif - strcpy(out, "local host"); - break; -#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN) - case AF_INET: - sprintf(out, "IP %s", - inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr)); - break; -#if defined(IPv6) && defined(AF_INET6) - case AF_INET6: { - char ipaddr[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr, - ipaddr, sizeof(ipaddr)); - sprintf(out, "IP %s", ipaddr); - } - break; -#endif -#endif -#ifdef DNETCONN - case AF_DECnet: - sprintf(out, "DN %s", - dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add)); - break; -#endif - default: - strcpy(out, "unknown address"); - } - - if (GetLocalClientCreds(client, &lcc) != -1) { - int slen; /* length written to client_uid_string */ - - strcpy(client_uid_string, " ( "); - slen = 3; - - if (lcc->fieldsSet & LCC_UID_SET) { - snprintf(client_uid_string + slen, - sizeof(client_uid_string) - slen, - "uid=%ld ", (long) lcc->euid); - slen = strlen(client_uid_string); - } - - if (lcc->fieldsSet & LCC_GID_SET) { - snprintf(client_uid_string + slen, - sizeof(client_uid_string) - slen, - "gid=%ld ", (long) lcc->egid); - slen = strlen(client_uid_string); - } - - if (lcc->fieldsSet & LCC_PID_SET) { -#ifdef XSERVER_DTRACE - client_pid = lcc->pid; -#endif - snprintf(client_uid_string + slen, - sizeof(client_uid_string) - slen, - "pid=%ld ", (long) lcc->pid); - slen = strlen(client_uid_string); - } - - if (lcc->fieldsSet & LCC_ZID_SET) { -#ifdef XSERVER_DTRACE - client_zid = lcc->zoneid; -#endif - snprintf(client_uid_string + slen, - sizeof(client_uid_string) - slen, - "zoneid=%ld ", (long) lcc->zoneid); - slen = strlen(client_uid_string); - } - - snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen, - ")"); - FreeLocalClientCreds(lcc); - } - else { - client_uid_string[0] = '\0'; - } - -#ifdef XSERVER_DTRACE - XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid); -#endif - if (auditTrailLevel > 1) { - if (proto_n) - AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n", - client->index, letin ? "connected" : "rejected", addr, - client_uid_string, (int)proto_n, auth_proto, auth_id); - else - AuditF("client %d %s from %s%s\n", - client->index, letin ? "connected" : "rejected", addr, - client_uid_string); - - } -} - -XID -AuthorizationIDOfClient(ClientPtr client) -{ - if (client->osPrivate) - return ((OsCommPtr)client->osPrivate)->auth_id; - else - return None; -} - - -/***************************************************************** - * ClientAuthorized - * - * Sent by the client at connection setup: - * typedef struct _xConnClientPrefix { - * CARD8 byteOrder; - * BYTE pad; - * CARD16 majorVersion, minorVersion; - * CARD16 nbytesAuthProto; - * CARD16 nbytesAuthString; - * } xConnClientPrefix; - * - * It is hoped that eventually one protocol will be agreed upon. In the - * mean time, a server that implements a different protocol than the - * client expects, or a server that only implements the host-based - * mechanism, will simply ignore this information. - * - *****************************************************************/ - -char * -ClientAuthorized(ClientPtr client, - unsigned int proto_n, char *auth_proto, - unsigned int string_n, char *auth_string) -{ - OsCommPtr priv; - Xtransaddr *from = NULL; - int family; - int fromlen; - XID auth_id; - char *reason = NULL; - XtransConnInfo trans_conn; - - priv = (OsCommPtr)client->osPrivate; - trans_conn = priv->trans_conn; - - /* Allow any client to connect without authorization on a launchd socket, - because it is securely created -- this prevents a race condition on launch */ - if(trans_conn->flags & TRANS_NOXAUTH) { - auth_id = (XID) 0L; - } else { - auth_id = CheckAuthorization (proto_n, auth_proto, string_n, auth_string, client, &reason); - } - - if (auth_id == (XID) ~0L) - { - if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) - { - if (InvalidHost ((struct sockaddr *) from, fromlen, client)) - AuthAudit(client, FALSE, (struct sockaddr *) from, - fromlen, proto_n, auth_proto, auth_id); - else - { - auth_id = (XID) 0; -#ifdef XSERVER_DTRACE - if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) -#else - if (auditTrailLevel > 1) -#endif - AuthAudit(client, TRUE, - (struct sockaddr *) from, fromlen, - proto_n, auth_proto, auth_id); - } - - xfree (from); - } - - if (auth_id == (XID) ~0L) { - if (reason) - return reason; - else - return "Client is not authorized to connect to Server"; - } - } -#ifdef XSERVER_DTRACE - else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) -#else - else if (auditTrailLevel > 1) -#endif - { - if (_XSERVTransGetPeerAddr (trans_conn, - &family, &fromlen, &from) != -1) - { - AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen, - proto_n, auth_proto, auth_id); - - xfree (from); - } - } - priv->auth_id = auth_id; - priv->conn_time = 0; - -#ifdef XDMCP - /* indicate to Xdmcp protocol that we've opened new client */ - XdmcpOpenDisplay(priv->fd); -#endif /* XDMCP */ - - XaceHook(XACE_AUTH_AVAIL, client, auth_id); - - /* At this point, if the client is authorized to change the access control - * list, we should getpeername() information, and add the client to - * the selfhosts list. It's not really the host machine, but the - * true purpose of the selfhosts list is to see who may change the - * access control list. - */ - return((char *)NULL); -} - -static ClientPtr -AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time) -{ - OsCommPtr oc; - ClientPtr client; - - if ( -#ifndef WIN32 - fd >= lastfdesc -#else - XFD_SETCOUNT(&AllClients) >= MaxClients -#endif - ) - return NullClient; - oc = xalloc(sizeof(OsCommRec)); - if (!oc) - return NullClient; - oc->trans_conn = trans_conn; - oc->fd = fd; - oc->input = (ConnectionInputPtr)NULL; - oc->output = (ConnectionOutputPtr)NULL; - oc->auth_id = None; - oc->conn_time = conn_time; - if (!(client = NextAvailableClient((pointer)oc))) - { - xfree (oc); - return NullClient; - } -#if !defined(WIN32) - ConnectionTranslation[fd] = client->index; -#else - SetConnectionTranslation(fd, client->index); -#endif - if (GrabInProgress) - { - FD_SET(fd, &SavedAllClients); - FD_SET(fd, &SavedAllSockets); - } - else - { - FD_SET(fd, &AllClients); - FD_SET(fd, &AllSockets); - } - -#ifdef DEBUG - ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n", - client->index, fd); -#endif -#ifdef XSERVER_DTRACE - XSERVER_CLIENT_CONNECT(client->index, fd); -#endif - - return client; -} - -/***************** - * EstablishNewConnections - * If anyone is waiting on listened sockets, accept them. - * Returns a mask with indices of new clients. Updates AllClients - * and AllSockets. - *****************/ - -/*ARGSUSED*/ -Bool -EstablishNewConnections(ClientPtr clientUnused, pointer closure) -{ - fd_set readyconnections; /* set of listeners that are ready */ - int curconn; /* fd of listener that's ready */ - register int newconn; /* fd of new client */ - CARD32 connect_time; - register int i; - register ClientPtr client; - register OsCommPtr oc; - fd_set tmask; - - XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections); - XFD_COPYSET(&tmask, &readyconnections); - if (!XFD_ANYSET(&readyconnections)) - return TRUE; - connect_time = GetTimeInMillis(); - /* kill off stragglers */ - for (i=1; i<currentMaxClients; i++) - { - if ((client = clients[i])) - { - oc = (OsCommPtr)(client->osPrivate); - if ((oc && (oc->conn_time != 0) && - (connect_time - oc->conn_time) >= TimeOutValue) || - (client->noClientException != Success && !client->clientGone)) - CloseDownClient(client); - } - } -#ifndef WIN32 - for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) - { - while (readyconnections.fds_bits[i]) -#else - for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++) -#endif - { - XtransConnInfo trans_conn, new_trans_conn; - int status; - -#ifndef WIN32 - curconn = mffs (readyconnections.fds_bits[i]) - 1; - readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn); - curconn += (i * (sizeof(fd_mask)*8)); -#else - curconn = XFD_FD(&readyconnections, i); -#endif - - if ((trans_conn = lookup_trans_conn (curconn)) == NULL) - continue; - - if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL) - continue; - - newconn = _XSERVTransGetConnectionNumber (new_trans_conn); - - if (newconn < lastfdesc) - { - int clientid; -#if !defined(WIN32) - clientid = ConnectionTranslation[newconn]; -#else - clientid = GetConnectionTranslation(newconn); -#endif - if(clientid && (client = clients[clientid])) - CloseDownClient(client); - } - - _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); - - if (!AllocNewConnection (new_trans_conn, newconn, connect_time)) - { - ErrorConnMax(new_trans_conn); - _XSERVTransClose(new_trans_conn); - } - - if(trans_conn->flags & TRANS_NOXAUTH) - new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH; - - } -#ifndef WIN32 - } -#endif - return TRUE; -} - -#define NOROOM "Maximum number of clients reached" - -/************ - * ErrorConnMax - * Fail a connection due to lack of client or file descriptor space - ************/ - -static void -ErrorConnMax(XtransConnInfo trans_conn) -{ - int fd = _XSERVTransGetConnectionNumber (trans_conn); - xConnSetupPrefix csp; - char pad[3]; - struct iovec iov[3]; - char byteOrder = 0; - int whichbyte = 1; - struct timeval waittime; - fd_set mask; - - /* if these seems like a lot of trouble to go to, it probably is */ - waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND; - waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) * - (1000000 / MILLI_PER_SECOND); - FD_ZERO(&mask); - FD_SET(fd, &mask); - (void)Select(fd + 1, &mask, NULL, NULL, &waittime); - /* try to read the byte-order of the connection */ - (void)_XSERVTransRead(trans_conn, &byteOrder, 1); - if ((byteOrder == 'l') || (byteOrder == 'B')) - { - csp.success = xFalse; - csp.lengthReason = sizeof(NOROOM) - 1; - csp.length = (sizeof(NOROOM) + 2) >> 2; - csp.majorVersion = X_PROTOCOL; - csp.minorVersion = X_PROTOCOL_REVISION; - if (((*(char *) &whichbyte) && (byteOrder == 'B')) || - (!(*(char *) &whichbyte) && (byteOrder == 'l'))) - { - swaps(&csp.majorVersion, whichbyte); - swaps(&csp.minorVersion, whichbyte); - swaps(&csp.length, whichbyte); - } - iov[0].iov_len = sz_xConnSetupPrefix; - iov[0].iov_base = (char *) &csp; - iov[1].iov_len = csp.lengthReason; - iov[1].iov_base = NOROOM; - iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3; - iov[2].iov_base = pad; - (void)_XSERVTransWritev(trans_conn, iov, 3); - } -} - -/************ - * CloseDownFileDescriptor: - * Remove this file descriptor and it's I/O buffers, etc. - ************/ - -static void -CloseDownFileDescriptor(OsCommPtr oc) -{ - int connection = oc->fd; - - if (oc->trans_conn) { - _XSERVTransDisconnect(oc->trans_conn); - _XSERVTransClose(oc->trans_conn); - } -#ifndef WIN32 - ConnectionTranslation[connection] = 0; -#else - SetConnectionTranslation(connection, 0); -#endif - FD_CLR(connection, &AllSockets); - FD_CLR(connection, &AllClients); - FD_CLR(connection, &ClientsWithInput); - FD_CLR(connection, &GrabImperviousClients); - if (GrabInProgress) - { - FD_CLR(connection, &SavedAllSockets); - FD_CLR(connection, &SavedAllClients); - FD_CLR(connection, &SavedClientsWithInput); - } - FD_CLR(connection, &ClientsWriteBlocked); - if (!XFD_ANYSET(&ClientsWriteBlocked)) - AnyClientsWriteBlocked = FALSE; - FD_CLR(connection, &OutputPending); -} - -/***************** - * CheckConnections - * Some connection has died, go find which one and shut it down - * The file descriptor has been closed, but is still in AllClients. - * If would truly be wonderful if select() would put the bogus - * file descriptors in the exception mask, but nooooo. So we have - * to check each and every socket individually. - *****************/ - -void -CheckConnections(void) -{ -#ifndef WIN32 - fd_mask mask; -#endif - fd_set tmask; - int curclient, curoff; - int i; - struct timeval notime; - int r; -#ifdef WIN32 - fd_set savedAllClients; -#endif - - notime.tv_sec = 0; - notime.tv_usec = 0; - -#ifndef WIN32 - for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) - { - mask = AllClients.fds_bits[i]; - while (mask) - { - curoff = mffs (mask) - 1; - curclient = curoff + (i * (sizeof(fd_mask)*8)); - FD_ZERO(&tmask); - FD_SET(curclient, &tmask); - do { - r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime); - } while (r < 0 && (errno == EINTR || errno == EAGAIN)); - if (r < 0) - if (ConnectionTranslation[curclient] > 0) - CloseDownClient(clients[ConnectionTranslation[curclient]]); - mask &= ~((fd_mask)1 << curoff); - } - } -#else - XFD_COPYSET(&AllClients, &savedAllClients); - for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++) - { - curclient = XFD_FD(&savedAllClients, i); - FD_ZERO(&tmask); - FD_SET(curclient, &tmask); - do { - r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime); - } while (r < 0 && (errno == EINTR || errno == EAGAIN)); - if (r < 0) - if (GetConnectionTranslation(curclient) > 0) - CloseDownClient(clients[GetConnectionTranslation(curclient)]); - } -#endif -} - - -/***************** - * CloseDownConnection - * Delete client from AllClients and free resources - *****************/ - -void -CloseDownConnection(ClientPtr client) -{ - OsCommPtr oc = (OsCommPtr)client->osPrivate; - - if (oc->output && oc->output->count) - FlushClient(client, oc, (char *)NULL, 0); -#ifdef XDMCP - XdmcpCloseDisplay(oc->fd); -#endif - CloseDownFileDescriptor(oc); - FreeOsBuffers(oc); - xfree(client->osPrivate); - client->osPrivate = (pointer)NULL; - if (auditTrailLevel > 1) - AuditF("client %d disconnected\n", client->index); -} - -void -AddGeneralSocket(int fd) -{ - FD_SET(fd, &AllSockets); - if (GrabInProgress) - FD_SET(fd, &SavedAllSockets); -} - -void -AddEnabledDevice(int fd) -{ - FD_SET(fd, &EnabledDevices); - AddGeneralSocket(fd); -} - -void -RemoveGeneralSocket(int fd) -{ - FD_CLR(fd, &AllSockets); - if (GrabInProgress) - FD_CLR(fd, &SavedAllSockets); -} - -void -RemoveEnabledDevice(int fd) -{ - FD_CLR(fd, &EnabledDevices); - RemoveGeneralSocket(fd); -} - -/***************** - * OnlyListenToOneClient: - * Only accept requests from one client. Continue to handle new - * connections, but don't take any protocol requests from the new - * ones. Note that if GrabInProgress is set, EstablishNewConnections - * needs to put new clients into SavedAllSockets and SavedAllClients. - * Note also that there is no timeout for this in the protocol. - * This routine is "undone" by ListenToAllClients() - *****************/ - -int -OnlyListenToOneClient(ClientPtr client) -{ - OsCommPtr oc = (OsCommPtr)client->osPrivate; - int rc, connection = oc->fd; - - rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess); - if (rc != Success) - return rc; - - if (! GrabInProgress) - { - XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput); - XFD_ANDSET(&ClientsWithInput, - &ClientsWithInput, &GrabImperviousClients); - if (FD_ISSET(connection, &SavedClientsWithInput)) - { - FD_CLR(connection, &SavedClientsWithInput); - FD_SET(connection, &ClientsWithInput); - } - XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients); - XFD_COPYSET(&AllSockets, &SavedAllSockets); - XFD_COPYSET(&AllClients, &SavedAllClients); - XFD_UNSET(&AllSockets, &AllClients); - XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients); - FD_SET(connection, &AllClients); - XFD_ORSET(&AllSockets, &AllSockets, &AllClients); - GrabInProgress = client->index; - } - return rc; -} - -/**************** - * ListenToAllClients: - * Undoes OnlyListentToOneClient() - ****************/ - -void -ListenToAllClients(void) -{ - if (GrabInProgress) - { - XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets); - XFD_ORSET(&AllClients, &AllClients, &SavedAllClients); - XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput); - GrabInProgress = 0; - } -} - -/**************** - * IgnoreClient - * Removes one client from input masks. - * Must have cooresponding call to AttendClient. - ****************/ - -void -IgnoreClient (ClientPtr client) -{ - OsCommPtr oc = (OsCommPtr)client->osPrivate; - int connection = oc->fd; - - isItTimeToYield = TRUE; - if (!GrabInProgress || FD_ISSET(connection, &AllClients)) - { - if (FD_ISSET (connection, &ClientsWithInput)) - FD_SET(connection, &IgnoredClientsWithInput); - else - FD_CLR(connection, &IgnoredClientsWithInput); - FD_CLR(connection, &ClientsWithInput); - FD_CLR(connection, &AllSockets); - FD_CLR(connection, &AllClients); - FD_CLR(connection, &LastSelectMask); - } - else - { - if (FD_ISSET (connection, &SavedClientsWithInput)) - FD_SET(connection, &IgnoredClientsWithInput); - else - FD_CLR(connection, &IgnoredClientsWithInput); - FD_CLR(connection, &SavedClientsWithInput); - FD_CLR(connection, &SavedAllSockets); - FD_CLR(connection, &SavedAllClients); - } -} - -/**************** - * AttendClient - * Adds one client back into the input masks. - ****************/ - -void -AttendClient (ClientPtr client) -{ - OsCommPtr oc = (OsCommPtr)client->osPrivate; - int connection = oc->fd; - if (!GrabInProgress || GrabInProgress == client->index || - FD_ISSET(connection, &GrabImperviousClients)) - { - FD_SET(connection, &AllClients); - FD_SET(connection, &AllSockets); - FD_SET(connection, &LastSelectMask); - if (FD_ISSET (connection, &IgnoredClientsWithInput)) - FD_SET(connection, &ClientsWithInput); - } - else - { - FD_SET(connection, &SavedAllClients); - FD_SET(connection, &SavedAllSockets); - if (FD_ISSET(connection, &IgnoredClientsWithInput)) - FD_SET(connection, &SavedClientsWithInput); - } -} - -/* make client impervious to grabs; assume only executing client calls this */ - -void -MakeClientGrabImpervious(ClientPtr client) -{ - OsCommPtr oc = (OsCommPtr)client->osPrivate; - int connection = oc->fd; - - FD_SET(connection, &GrabImperviousClients); - - if (ServerGrabCallback) - { - ServerGrabInfoRec grabinfo; - grabinfo.client = client; - grabinfo.grabstate = CLIENT_IMPERVIOUS; - CallCallbacks(&ServerGrabCallback, &grabinfo); - } -} - -/* make client pervious to grabs; assume only executing client calls this */ - -void -MakeClientGrabPervious(ClientPtr client) -{ - OsCommPtr oc = (OsCommPtr)client->osPrivate; - int connection = oc->fd; - - FD_CLR(connection, &GrabImperviousClients); - if (GrabInProgress && (GrabInProgress != client->index)) - { - if (FD_ISSET(connection, &ClientsWithInput)) - { - FD_SET(connection, &SavedClientsWithInput); - FD_CLR(connection, &ClientsWithInput); - } - FD_CLR(connection, &AllSockets); - FD_CLR(connection, &AllClients); - isItTimeToYield = TRUE; - } - - if (ServerGrabCallback) - { - ServerGrabInfoRec grabinfo; - grabinfo.client = client; - grabinfo.grabstate = CLIENT_PERVIOUS; - CallCallbacks(&ServerGrabCallback, &grabinfo); - } -} - -#ifdef XQUARTZ -/* Add a fd (from launchd) to our listeners */ -void ListenOnOpenFD(int fd, int noxauth) { - char port[256]; - XtransConnInfo ciptr; - const char *display_env = getenv("DISPLAY"); - - if(display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) { - /* Make the path the launchd socket if our DISPLAY is set right */ - strcpy(port, display_env); - } else { - /* Just some default so things don't break and die. */ - sprintf(port, ":%d", atoi(display)); - } - - /* Make our XtransConnInfo - * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c - */ - ciptr = _XSERVTransReopenCOTSServer(5, fd, port); - if(ciptr == NULL) { - ErrorF("Got NULL while trying to Reopen launchd port.\n"); - return; - } - - if(noxauth) - ciptr->flags = ciptr->flags | TRANS_NOXAUTH; - - /* Allocate space to store it */ - ListenTransFds = (int *) xrealloc(ListenTransFds, (ListenTransCount + 1) * sizeof (int)); - ListenTransConns = (XtransConnInfo *) xrealloc(ListenTransConns, (ListenTransCount + 1) * sizeof (XtransConnInfo)); - - /* Store it */ - ListenTransConns[ListenTransCount] = ciptr; - ListenTransFds[ListenTransCount] = fd; - - FD_SET(fd, &WellKnownConnections); - FD_SET(fd, &AllSockets); - - /* Increment the count */ - ListenTransCount++; - - /* This *might* not be needed... /shrug */ - ResetAuthorization(); - ResetHosts(display); -#ifdef XDMCP - XdmcpReset(); -#endif -} - -#endif +/*********************************************************** + +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. + +******************************************************************/ +/***************************************************************** + * Stuff to create connections --- OS dependent + * + * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets, + * CloseDownConnection, CheckConnections, AddEnabledDevice, + * RemoveEnabledDevice, OnlyListToOneClient, + * ListenToAllClients, + * + * (WaitForSomething is in its own file) + * + * In this implementation, a client socket table is not kept. + * Instead, what would be the index into the table is just the + * file descriptor of the socket. This won't work for if the + * socket ids aren't small nums (0 - 2^8) + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <X11/X.h> +#include <X11/Xproto.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <X11/Xtrans/Xtrans.h> +#include <X11/Xtrans/Xtransint.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef WIN32 +#include <sys/socket.h> + + + +#if defined(TCPCONN) || defined(STREAMSCONN) +# include <netinet/in.h> +# include <arpa/inet.h> +# ifdef apollo +# ifndef NO_TCP_H +# include <netinet/tcp.h> +# endif +# else +# ifdef CSRG_BASED +# include <sys/param.h> +# endif +# include <netinet/tcp.h> +# endif +# include <arpa/inet.h> +#endif + +#include <sys/uio.h> + +#endif /* WIN32 */ +#include "misc.h" /* for typedef of pointer */ +#include "osdep.h" +#include <X11/Xpoll.h> +#include "opaque.h" +#include "dixstruct.h" +#include "xace.h" + +#define Pid_t pid_t + +#ifdef DNETCONN +#include <netdnet/dn.h> +#endif /* DNETCONN */ + +#ifdef HAS_GETPEERUCRED +# include <ucred.h> +# include <zone.h> +#endif + +#ifdef XSERVER_DTRACE +# include <sys/types.h> +typedef const char *string; +# ifndef HAS_GETPEERUCRED +# define zoneid_t int +# endif +# include "../dix/Xserver-dtrace.h" +#endif + +static int lastfdesc; /* maximum file descriptor */ + +fd_set WellKnownConnections; /* Listener mask */ +fd_set EnabledDevices; /* mask for input devices that are on */ +fd_set AllSockets; /* select on this */ +fd_set AllClients; /* available clients */ +fd_set LastSelectMask; /* mask returned from last select call */ +fd_set ClientsWithInput; /* clients with FULL requests in buffer */ +fd_set ClientsWriteBlocked; /* clients who cannot receive output */ +fd_set OutputPending; /* clients with reply/event data ready to go */ +int MaxClients = 0; +Bool NewOutputPending; /* not yet attempted to write some new output */ +Bool AnyClientsWriteBlocked; /* true if some client blocked on write */ + +static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ +Bool PartialNetwork; /* continue even if unable to bind all addrs */ +static Pid_t ParentProcess; + +static Bool debug_conns = FALSE; + +fd_set IgnoredClientsWithInput; +static fd_set GrabImperviousClients; +static fd_set SavedAllClients; +static fd_set SavedAllSockets; +static fd_set SavedClientsWithInput; +int GrabInProgress = 0; + +#if !defined(WIN32) +int *ConnectionTranslation = NULL; +#else +/* + * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is + * not even a known maximum value, so use something quite arbitrary for now. + * Do storage is a hash table of size 256. Collisions are handled in a linked + * list. + */ + +#undef MAXSOCKS +#define MAXSOCKS 500 +#undef MAXSELECT +#define MAXSELECT 500 + +struct _ct_node { + struct _ct_node *next; + int key; + int value; +}; + +struct _ct_node *ct_head[256]; + +void InitConnectionTranslation(void) +{ + bzero(ct_head, sizeof(ct_head)); +} + +int GetConnectionTranslation(int conn) +{ + struct _ct_node *node = ct_head[conn & 0xff]; + while (node != NULL) + { + if (node->key == conn) + return node->value; + node = node->next; + } + return 0; +} + +void SetConnectionTranslation(int conn, int client) +{ + struct _ct_node **node = ct_head + (conn & 0xff); + if (client == 0) /* remove entry */ + { + while (*node != NULL) + { + if ((*node)->key == conn) + { + struct _ct_node *temp = *node; + *node = (*node)->next; + free(temp); + return; + } + node = &((*node)->next); + } + return; + } else + { + while (*node != NULL) + { + if ((*node)->key == conn) + { + (*node)->value = client; + return; + } + node = &((*node)->next); + } + *node = malloc(sizeof(struct _ct_node)); + (*node)->next = NULL; + (*node)->key = conn; + (*node)->value = client; + return; + } +} + +void ClearConnectionTranslation(void) +{ + unsigned i; + for (i = 0; i < 256; i++) + { + struct _ct_node *node = ct_head[i]; + while (node != NULL) + { + struct _ct_node *temp = node; + node = node->next; + free(temp); + } + } +} +#endif + +static XtransConnInfo *ListenTransConns = NULL; +static int *ListenTransFds = NULL; +static int ListenTransCount; + +static void ErrorConnMax(XtransConnInfo /* trans_conn */); + +static XtransConnInfo +lookup_trans_conn (int fd) +{ + if (ListenTransFds) + { + int i; + for (i = 0; i < ListenTransCount; i++) + if (ListenTransFds[i] == fd) + return ListenTransConns[i]; + } + + return (NULL); +} + +/* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */ + +void +InitConnectionLimits(void) +{ + lastfdesc = -1; + +#ifndef __CYGWIN__ + +#if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX) + lastfdesc = sysconf(_SC_OPEN_MAX) - 1; +#endif + +#ifdef HAS_GETDTABLESIZE + if (lastfdesc < 0) + lastfdesc = getdtablesize() - 1; +#endif + +#ifdef _NFILE + if (lastfdesc < 0) + lastfdesc = _NFILE - 1; +#endif + +#endif /* __CYGWIN__ */ + + /* This is the fallback */ + if (lastfdesc < 0) + lastfdesc = MAXSOCKS; + + if (lastfdesc > MAXSELECT) + lastfdesc = MAXSELECT; + + if (lastfdesc > MAXCLIENTS) + { + lastfdesc = MAXCLIENTS; + if (debug_conns) + ErrorF( "REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS); + } + MaxClients = lastfdesc; + +#ifdef DEBUG + ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients); +#endif + +#if !defined(WIN32) + if (!ConnectionTranslation) + ConnectionTranslation = (int *)xnfalloc(sizeof(int)*(lastfdesc + 1)); +#else + InitConnectionTranslation(); +#endif +} + +/* + * If SIGUSR1 was set to SIG_IGN when the server started, assume that either + * + * a- The parent process is ignoring SIGUSR1 + * + * or + * + * b- The parent process is expecting a SIGUSR1 + * when the server is ready to accept connections + * + * In the first case, the signal will be harmless, in the second case, + * the signal will be quite useful. + */ +static void +InitParentProcess(void) +{ +#if !defined(WIN32) + OsSigHandlerPtr handler; + handler = OsSignal (SIGUSR1, SIG_IGN); + if ( handler == SIG_IGN) + RunFromSmartParent = TRUE; + OsSignal(SIGUSR1, handler); + ParentProcess = getppid (); +#endif +} + +void +NotifyParentProcess(void) +{ +#if !defined(WIN32) + if (RunFromSmartParent) { + if (ParentProcess > 1) { + kill (ParentProcess, SIGUSR1); + } + } +#endif +} + +/***************** + * CreateWellKnownSockets + * At initialization, create the sockets to listen on for new clients. + *****************/ + +void +CreateWellKnownSockets(void) +{ + int i; + int partial; + char port[20]; + + FD_ZERO(&AllSockets); + FD_ZERO(&AllClients); + FD_ZERO(&LastSelectMask); + FD_ZERO(&ClientsWithInput); + +#if !defined(WIN32) + for (i=0; i<MaxClients; i++) ConnectionTranslation[i] = 0; +#else + ClearConnectionTranslation(); +#endif + + FD_ZERO (&WellKnownConnections); + + sprintf (port, "%d", atoi (display)); + + if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial, + &ListenTransCount, &ListenTransConns) >= 0) && + (ListenTransCount >= 1)) + { + if (!PartialNetwork && partial) + { + FatalError ("Failed to establish all listening sockets"); + } + else + { + ListenTransFds = malloc(ListenTransCount * sizeof (int)); + + for (i = 0; i < ListenTransCount; i++) + { + int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + ListenTransFds[i] = fd; + FD_SET (fd, &WellKnownConnections); + + if (!_XSERVTransIsLocal (ListenTransConns[i])) + { + DefineSelf (fd); + } + } + } + } + + if (!XFD_ANYSET (&WellKnownConnections)) + FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running"); +#if !defined(WIN32) + OsSignal (SIGPIPE, SIG_IGN); + OsSignal (SIGHUP, AutoResetServer); +#endif + OsSignal (SIGINT, GiveUp); + OsSignal (SIGTERM, GiveUp); + XFD_COPYSET (&WellKnownConnections, &AllSockets); + ResetHosts(display); + + InitParentProcess(); + +#ifdef XDMCP + XdmcpInit (); +#endif +} + +void +ResetWellKnownSockets (void) +{ + int i; + + ResetOsBuffers(); + + for (i = 0; i < ListenTransCount; i++) + { + int status = _XSERVTransResetListener (ListenTransConns[i]); + + if (status != TRANS_RESET_NOOP) + { + if (status == TRANS_RESET_FAILURE) + { + /* + * ListenTransConns[i] freed by xtrans. + * Remove it from out list. + */ + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = ListenTransFds[ListenTransCount - 1]; + ListenTransConns[i] = ListenTransConns[ListenTransCount - 1]; + ListenTransCount -= 1; + i -= 1; + } + else if (status == TRANS_RESET_NEW_FD) + { + /* + * A new file descriptor was allocated (the old one was closed) + */ + + int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = newfd; + FD_SET(newfd, &WellKnownConnections); + } + } + } + + ResetAuthorization (); + ResetHosts(display); + /* + * restart XDMCP + */ +#ifdef XDMCP + XdmcpReset (); +#endif +} + +void +CloseWellKnownConnections(void) +{ + int i; + + for (i = 0; i < ListenTransCount; i++) + _XSERVTransClose (ListenTransConns[i]); +} + +static void +AuthAudit (ClientPtr client, Bool letin, + struct sockaddr *saddr, int len, + unsigned int proto_n, char *auth_proto, int auth_id) +{ + char addr[128]; + char *out = addr; + char client_uid_string[64]; + LocalClientCredRec *lcc; +#ifdef XSERVER_DTRACE + pid_t client_pid = -1; + zoneid_t client_zid = -1; +#endif + + if (!len) + strcpy(out, "local host"); + else + switch (saddr->sa_family) + { + case AF_UNSPEC: +#if defined(UNIXCONN) || defined(LOCALCONN) + case AF_UNIX: +#endif + strcpy(out, "local host"); + break; +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN) + case AF_INET: + sprintf(out, "IP %s", + inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr)); + break; +#if defined(IPv6) && defined(AF_INET6) + case AF_INET6: { + char ipaddr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr, + ipaddr, sizeof(ipaddr)); + sprintf(out, "IP %s", ipaddr); + } + break; +#endif +#endif +#ifdef DNETCONN + case AF_DECnet: + sprintf(out, "DN %s", + dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add)); + break; +#endif + default: + strcpy(out, "unknown address"); + } + + if (GetLocalClientCreds(client, &lcc) != -1) { + int slen; /* length written to client_uid_string */ + + strcpy(client_uid_string, " ( "); + slen = 3; + + if (lcc->fieldsSet & LCC_UID_SET) { + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "uid=%ld ", (long) lcc->euid); + slen = strlen(client_uid_string); + } + + if (lcc->fieldsSet & LCC_GID_SET) { + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "gid=%ld ", (long) lcc->egid); + slen = strlen(client_uid_string); + } + + if (lcc->fieldsSet & LCC_PID_SET) { +#ifdef XSERVER_DTRACE + client_pid = lcc->pid; +#endif + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "pid=%ld ", (long) lcc->pid); + slen = strlen(client_uid_string); + } + + if (lcc->fieldsSet & LCC_ZID_SET) { +#ifdef XSERVER_DTRACE + client_zid = lcc->zoneid; +#endif + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "zoneid=%ld ", (long) lcc->zoneid); + slen = strlen(client_uid_string); + } + + snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen, + ")"); + FreeLocalClientCreds(lcc); + } + else { + client_uid_string[0] = '\0'; + } + +#ifdef XSERVER_DTRACE + XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid); +#endif + if (auditTrailLevel > 1) { + if (proto_n) + AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n", + client->index, letin ? "connected" : "rejected", addr, + client_uid_string, (int)proto_n, auth_proto, auth_id); + else + AuditF("client %d %s from %s%s\n", + client->index, letin ? "connected" : "rejected", addr, + client_uid_string); + + } +} + +XID +AuthorizationIDOfClient(ClientPtr client) +{ + if (client->osPrivate) + return ((OsCommPtr)client->osPrivate)->auth_id; + else + return None; +} + + +/***************************************************************** + * ClientAuthorized + * + * Sent by the client at connection setup: + * typedef struct _xConnClientPrefix { + * CARD8 byteOrder; + * BYTE pad; + * CARD16 majorVersion, minorVersion; + * CARD16 nbytesAuthProto; + * CARD16 nbytesAuthString; + * } xConnClientPrefix; + * + * It is hoped that eventually one protocol will be agreed upon. In the + * mean time, a server that implements a different protocol than the + * client expects, or a server that only implements the host-based + * mechanism, will simply ignore this information. + * + *****************************************************************/ + +char * +ClientAuthorized(ClientPtr client, + unsigned int proto_n, char *auth_proto, + unsigned int string_n, char *auth_string) +{ + OsCommPtr priv; + Xtransaddr *from = NULL; + int family; + int fromlen; + XID auth_id; + char *reason = NULL; + XtransConnInfo trans_conn; + + priv = (OsCommPtr)client->osPrivate; + trans_conn = priv->trans_conn; + + /* Allow any client to connect without authorization on a launchd socket, + because it is securely created -- this prevents a race condition on launch */ + if(trans_conn->flags & TRANS_NOXAUTH) { + auth_id = (XID) 0L; + } else { + auth_id = CheckAuthorization (proto_n, auth_proto, string_n, auth_string, client, &reason); + } + + if (auth_id == (XID) ~0L) + { + if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) + { + if (InvalidHost ((struct sockaddr *) from, fromlen, client)) + AuthAudit(client, FALSE, (struct sockaddr *) from, + fromlen, proto_n, auth_proto, auth_id); + else + { + auth_id = (XID) 0; +#ifdef XSERVER_DTRACE + if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) +#else + if (auditTrailLevel > 1) +#endif + AuthAudit(client, TRUE, + (struct sockaddr *) from, fromlen, + proto_n, auth_proto, auth_id); + } + + free(from); + } + + if (auth_id == (XID) ~0L) { + if (reason) + return reason; + else + return "Client is not authorized to connect to Server"; + } + } +#ifdef XSERVER_DTRACE + else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) +#else + else if (auditTrailLevel > 1) +#endif + { + if (_XSERVTransGetPeerAddr (trans_conn, + &family, &fromlen, &from) != -1) + { + AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen, + proto_n, auth_proto, auth_id); + + free(from); + } + } + priv->auth_id = auth_id; + priv->conn_time = 0; + +#ifdef XDMCP + /* indicate to Xdmcp protocol that we've opened new client */ + XdmcpOpenDisplay(priv->fd); +#endif /* XDMCP */ + + XaceHook(XACE_AUTH_AVAIL, client, auth_id); + + /* At this point, if the client is authorized to change the access control + * list, we should getpeername() information, and add the client to + * the selfhosts list. It's not really the host machine, but the + * true purpose of the selfhosts list is to see who may change the + * access control list. + */ + return((char *)NULL); +} + +static ClientPtr +AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time) +{ + OsCommPtr oc; + ClientPtr client; + + if ( +#ifndef WIN32 + fd >= lastfdesc +#else + XFD_SETCOUNT(&AllClients) >= MaxClients +#endif + ) + return NullClient; + oc = malloc(sizeof(OsCommRec)); + if (!oc) + return NullClient; + oc->trans_conn = trans_conn; + oc->fd = fd; + oc->input = (ConnectionInputPtr)NULL; + oc->output = (ConnectionOutputPtr)NULL; + oc->auth_id = None; + oc->conn_time = conn_time; + if (!(client = NextAvailableClient((pointer)oc))) + { + free(oc); + return NullClient; + } +#if !defined(WIN32) + ConnectionTranslation[fd] = client->index; +#else + SetConnectionTranslation(fd, client->index); +#endif + if (GrabInProgress) + { + FD_SET(fd, &SavedAllClients); + FD_SET(fd, &SavedAllSockets); + } + else + { + FD_SET(fd, &AllClients); + FD_SET(fd, &AllSockets); + } + +#ifdef DEBUG + ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n", + client->index, fd); +#endif +#ifdef XSERVER_DTRACE + XSERVER_CLIENT_CONNECT(client->index, fd); +#endif + + return client; +} + +/***************** + * EstablishNewConnections + * If anyone is waiting on listened sockets, accept them. + * Returns a mask with indices of new clients. Updates AllClients + * and AllSockets. + *****************/ + +/*ARGSUSED*/ +Bool +EstablishNewConnections(ClientPtr clientUnused, pointer closure) +{ + fd_set readyconnections; /* set of listeners that are ready */ + int curconn; /* fd of listener that's ready */ + register int newconn; /* fd of new client */ + CARD32 connect_time; + register int i; + register ClientPtr client; + register OsCommPtr oc; + fd_set tmask; + + XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections); + XFD_COPYSET(&tmask, &readyconnections); + if (!XFD_ANYSET(&readyconnections)) + return TRUE; + connect_time = GetTimeInMillis(); + /* kill off stragglers */ + for (i=1; i<currentMaxClients; i++) + { + if ((client = clients[i])) + { + oc = (OsCommPtr)(client->osPrivate); + if ((oc && (oc->conn_time != 0) && + (connect_time - oc->conn_time) >= TimeOutValue) || + (client->noClientException != Success && !client->clientGone)) + CloseDownClient(client); + } + } +#ifndef WIN32 + for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) + { + while (readyconnections.fds_bits[i]) +#else + for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++) +#endif + { + XtransConnInfo trans_conn, new_trans_conn; + int status; + +#ifndef WIN32 + curconn = mffs (readyconnections.fds_bits[i]) - 1; + readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn); + curconn += (i * (sizeof(fd_mask)*8)); +#else + curconn = XFD_FD(&readyconnections, i); +#endif + + if ((trans_conn = lookup_trans_conn (curconn)) == NULL) + continue; + + if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL) + continue; + + newconn = _XSERVTransGetConnectionNumber (new_trans_conn); + + if (newconn < lastfdesc) + { + int clientid; +#if !defined(WIN32) + clientid = ConnectionTranslation[newconn]; +#else + clientid = GetConnectionTranslation(newconn); +#endif + if(clientid && (client = clients[clientid])) + CloseDownClient(client); + } + + _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); + + if (!AllocNewConnection (new_trans_conn, newconn, connect_time)) + { + ErrorConnMax(new_trans_conn); + _XSERVTransClose(new_trans_conn); + } + + if(trans_conn->flags & TRANS_NOXAUTH) + new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH; + + } +#ifndef WIN32 + } +#endif + return TRUE; +} + +#define NOROOM "Maximum number of clients reached" + +/************ + * ErrorConnMax + * Fail a connection due to lack of client or file descriptor space + ************/ + +static void +ErrorConnMax(XtransConnInfo trans_conn) +{ + int fd = _XSERVTransGetConnectionNumber (trans_conn); + xConnSetupPrefix csp; + char pad[3]; + struct iovec iov[3]; + char byteOrder = 0; + int whichbyte = 1; + struct timeval waittime; + fd_set mask; + + /* if these seems like a lot of trouble to go to, it probably is */ + waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND; + waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) * + (1000000 / MILLI_PER_SECOND); + FD_ZERO(&mask); + FD_SET(fd, &mask); + (void)Select(fd + 1, &mask, NULL, NULL, &waittime); + /* try to read the byte-order of the connection */ + (void)_XSERVTransRead(trans_conn, &byteOrder, 1); + if ((byteOrder == 'l') || (byteOrder == 'B')) + { + csp.success = xFalse; + csp.lengthReason = sizeof(NOROOM) - 1; + csp.length = (sizeof(NOROOM) + 2) >> 2; + csp.majorVersion = X_PROTOCOL; + csp.minorVersion = X_PROTOCOL_REVISION; + if (((*(char *) &whichbyte) && (byteOrder == 'B')) || + (!(*(char *) &whichbyte) && (byteOrder == 'l'))) + { + swaps(&csp.majorVersion, whichbyte); + swaps(&csp.minorVersion, whichbyte); + swaps(&csp.length, whichbyte); + } + iov[0].iov_len = sz_xConnSetupPrefix; + iov[0].iov_base = (char *) &csp; + iov[1].iov_len = csp.lengthReason; + iov[1].iov_base = NOROOM; + iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3; + iov[2].iov_base = pad; + (void)_XSERVTransWritev(trans_conn, iov, 3); + } +} + +/************ + * CloseDownFileDescriptor: + * Remove this file descriptor and it's I/O buffers, etc. + ************/ + +static void +CloseDownFileDescriptor(OsCommPtr oc) +{ + int connection = oc->fd; + + if (oc->trans_conn) { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + } +#ifndef WIN32 + ConnectionTranslation[connection] = 0; +#else + SetConnectionTranslation(connection, 0); +#endif + FD_CLR(connection, &AllSockets); + FD_CLR(connection, &AllClients); + FD_CLR(connection, &ClientsWithInput); + FD_CLR(connection, &GrabImperviousClients); + if (GrabInProgress) + { + FD_CLR(connection, &SavedAllSockets); + FD_CLR(connection, &SavedAllClients); + FD_CLR(connection, &SavedClientsWithInput); + } + FD_CLR(connection, &ClientsWriteBlocked); + if (!XFD_ANYSET(&ClientsWriteBlocked)) + AnyClientsWriteBlocked = FALSE; + FD_CLR(connection, &OutputPending); +} + +/***************** + * CheckConnections + * Some connection has died, go find which one and shut it down + * The file descriptor has been closed, but is still in AllClients. + * If would truly be wonderful if select() would put the bogus + * file descriptors in the exception mask, but nooooo. So we have + * to check each and every socket individually. + *****************/ + +void +CheckConnections(void) +{ +#ifndef WIN32 + fd_mask mask; +#endif + fd_set tmask; + int curclient, curoff; + int i; + struct timeval notime; + int r; +#ifdef WIN32 + fd_set savedAllClients; +#endif + + notime.tv_sec = 0; + notime.tv_usec = 0; + +#ifndef WIN32 + for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) + { + mask = AllClients.fds_bits[i]; + while (mask) + { + curoff = mffs (mask) - 1; + curclient = curoff + (i * (sizeof(fd_mask)*8)); + FD_ZERO(&tmask); + FD_SET(curclient, &tmask); + do { + r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime); + } while (r < 0 && (errno == EINTR || errno == EAGAIN)); + if (r < 0) + if (ConnectionTranslation[curclient] > 0) + CloseDownClient(clients[ConnectionTranslation[curclient]]); + mask &= ~((fd_mask)1 << curoff); + } + } +#else + XFD_COPYSET(&AllClients, &savedAllClients); + for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++) + { + curclient = XFD_FD(&savedAllClients, i); + FD_ZERO(&tmask); + FD_SET(curclient, &tmask); + do { + r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime); + } while (r < 0 && (errno == EINTR || errno == EAGAIN)); + if (r < 0) + if (GetConnectionTranslation(curclient) > 0) + CloseDownClient(clients[GetConnectionTranslation(curclient)]); + } +#endif +} + + +/***************** + * CloseDownConnection + * Delete client from AllClients and free resources + *****************/ + +void +CloseDownConnection(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + + if (oc->output && oc->output->count) + FlushClient(client, oc, (char *)NULL, 0); +#ifdef XDMCP + XdmcpCloseDisplay(oc->fd); +#endif + CloseDownFileDescriptor(oc); + FreeOsBuffers(oc); + free(client->osPrivate); + client->osPrivate = (pointer)NULL; + if (auditTrailLevel > 1) + AuditF("client %d disconnected\n", client->index); +} + +void +AddGeneralSocket(int fd) +{ + FD_SET(fd, &AllSockets); + if (GrabInProgress) + FD_SET(fd, &SavedAllSockets); +} + +void +AddEnabledDevice(int fd) +{ + FD_SET(fd, &EnabledDevices); + AddGeneralSocket(fd); +} + +void +RemoveGeneralSocket(int fd) +{ + FD_CLR(fd, &AllSockets); + if (GrabInProgress) + FD_CLR(fd, &SavedAllSockets); +} + +void +RemoveEnabledDevice(int fd) +{ + FD_CLR(fd, &EnabledDevices); + RemoveGeneralSocket(fd); +} + +/***************** + * OnlyListenToOneClient: + * Only accept requests from one client. Continue to handle new + * connections, but don't take any protocol requests from the new + * ones. Note that if GrabInProgress is set, EstablishNewConnections + * needs to put new clients into SavedAllSockets and SavedAllClients. + * Note also that there is no timeout for this in the protocol. + * This routine is "undone" by ListenToAllClients() + *****************/ + +int +OnlyListenToOneClient(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int rc, connection = oc->fd; + + rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess); + if (rc != Success) + return rc; + + if (! GrabInProgress) + { + XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput); + XFD_ANDSET(&ClientsWithInput, + &ClientsWithInput, &GrabImperviousClients); + if (FD_ISSET(connection, &SavedClientsWithInput)) + { + FD_CLR(connection, &SavedClientsWithInput); + FD_SET(connection, &ClientsWithInput); + } + XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients); + XFD_COPYSET(&AllSockets, &SavedAllSockets); + XFD_COPYSET(&AllClients, &SavedAllClients); + XFD_UNSET(&AllSockets, &AllClients); + XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients); + FD_SET(connection, &AllClients); + XFD_ORSET(&AllSockets, &AllSockets, &AllClients); + GrabInProgress = client->index; + } + return rc; +} + +/**************** + * ListenToAllClients: + * Undoes OnlyListentToOneClient() + ****************/ + +void +ListenToAllClients(void) +{ + if (GrabInProgress) + { + XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets); + XFD_ORSET(&AllClients, &AllClients, &SavedAllClients); + XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput); + GrabInProgress = 0; + } +} + +/**************** + * IgnoreClient + * Removes one client from input masks. + * Must have cooresponding call to AttendClient. + ****************/ + +void +IgnoreClient (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + + isItTimeToYield = TRUE; + if (!GrabInProgress || FD_ISSET(connection, &AllClients)) + { + if (FD_ISSET (connection, &ClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &ClientsWithInput); + FD_CLR(connection, &AllSockets); + FD_CLR(connection, &AllClients); + FD_CLR(connection, &LastSelectMask); + } + else + { + if (FD_ISSET (connection, &SavedClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &SavedClientsWithInput); + FD_CLR(connection, &SavedAllSockets); + FD_CLR(connection, &SavedAllClients); + } +} + +/**************** + * AttendClient + * Adds one client back into the input masks. + ****************/ + +void +AttendClient (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + if (!GrabInProgress || GrabInProgress == client->index || + FD_ISSET(connection, &GrabImperviousClients)) + { + FD_SET(connection, &AllClients); + FD_SET(connection, &AllSockets); + FD_SET(connection, &LastSelectMask); + if (FD_ISSET (connection, &IgnoredClientsWithInput)) + FD_SET(connection, &ClientsWithInput); + } + else + { + FD_SET(connection, &SavedAllClients); + FD_SET(connection, &SavedAllSockets); + if (FD_ISSET(connection, &IgnoredClientsWithInput)) + FD_SET(connection, &SavedClientsWithInput); + } +} + +/* make client impervious to grabs; assume only executing client calls this */ + +void +MakeClientGrabImpervious(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + + FD_SET(connection, &GrabImperviousClients); + + if (ServerGrabCallback) + { + ServerGrabInfoRec grabinfo; + grabinfo.client = client; + grabinfo.grabstate = CLIENT_IMPERVIOUS; + CallCallbacks(&ServerGrabCallback, &grabinfo); + } +} + +/* make client pervious to grabs; assume only executing client calls this */ + +void +MakeClientGrabPervious(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + + FD_CLR(connection, &GrabImperviousClients); + if (GrabInProgress && (GrabInProgress != client->index)) + { + if (FD_ISSET(connection, &ClientsWithInput)) + { + FD_SET(connection, &SavedClientsWithInput); + FD_CLR(connection, &ClientsWithInput); + } + FD_CLR(connection, &AllSockets); + FD_CLR(connection, &AllClients); + isItTimeToYield = TRUE; + } + + if (ServerGrabCallback) + { + ServerGrabInfoRec grabinfo; + grabinfo.client = client; + grabinfo.grabstate = CLIENT_PERVIOUS; + CallCallbacks(&ServerGrabCallback, &grabinfo); + } +} + +#ifdef XQUARTZ +/* Add a fd (from launchd) to our listeners */ +void ListenOnOpenFD(int fd, int noxauth) { + char port[256]; + XtransConnInfo ciptr; + const char *display_env = getenv("DISPLAY"); + + if(display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) { + /* Make the path the launchd socket if our DISPLAY is set right */ + strcpy(port, display_env); + } else { + /* Just some default so things don't break and die. */ + sprintf(port, ":%d", atoi(display)); + } + + /* Make our XtransConnInfo + * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c + */ + ciptr = _XSERVTransReopenCOTSServer(5, fd, port); + if(ciptr == NULL) { + ErrorF("Got NULL while trying to Reopen launchd port.\n"); + return; + } + + if(noxauth) + ciptr->flags = ciptr->flags | TRANS_NOXAUTH; + + /* Allocate space to store it */ + ListenTransFds = (int *) realloc(ListenTransFds, (ListenTransCount + 1) * sizeof (int)); + ListenTransConns = (XtransConnInfo *) realloc(ListenTransConns, (ListenTransCount + 1) * sizeof (XtransConnInfo)); + + /* Store it */ + ListenTransConns[ListenTransCount] = ciptr; + ListenTransFds[ListenTransCount] = fd; + + FD_SET(fd, &WellKnownConnections); + FD_SET(fd, &AllSockets); + + /* Increment the count */ + ListenTransCount++; + + /* This *might* not be needed... /shrug */ + ResetAuthorization(); + ResetHosts(display); +#ifdef XDMCP + XdmcpReset(); +#endif +} + +#endif diff --git a/xorg-server/os/io.c b/xorg-server/os/io.c index 64b64ae75..a963d8653 100644 --- a/xorg-server/os/io.c +++ b/xorg-server/os/io.c @@ -1,1107 +1,1107 @@ -/*********************************************************** - -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. - - -******************************************************************/ -/***************************************************************** - * i/o functions - * - * WriteToClient, ReadRequestFromClient - * InsertFakeRequest, ResetCurrentRequest - * - *****************************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#undef DEBUG_COMMUNICATION - -#ifdef WIN32 -#include <X11/Xwinsock.h> -#endif -#include <stdio.h> -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include <X11/Xtrans/Xtrans.h> -#include <X11/Xmd.h> -#include <errno.h> -#if !defined(WIN32) -#include <sys/uio.h> -#endif -#include <X11/X.h> -#include <X11/Xproto.h> -#include "os.h" -#include "osdep.h" -#include <X11/Xpoll.h> -#include "opaque.h" -#include "dixstruct.h" -#include "misc.h" - -CallbackListPtr ReplyCallback; -CallbackListPtr FlushCallback; - -static ConnectionInputPtr AllocateInputBuffer(void); -static ConnectionOutputPtr AllocateOutputBuffer(void); - -/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX - * systems are broken and return EWOULDBLOCK when they should return EAGAIN - */ -#ifndef WIN32 -#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK) -#else /* WIN32 The socket errorcodes differ from the normal errors*/ -#define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK) -#endif - -static Bool CriticalOutputPending; -static int timesThisConnection = 0; -static ConnectionInputPtr FreeInputs = (ConnectionInputPtr)NULL; -static ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr)NULL; -static OsCommPtr AvailableInput = (OsCommPtr)NULL; - -#define get_req_len(req,cli) ((cli)->swapped ? \ - lswaps((req)->length) : (req)->length) - -#include <X11/extensions/bigreqsproto.h> - -#define get_big_req_len(req,cli) ((cli)->swapped ? \ - lswapl(((xBigReq *)(req))->length) : \ - ((xBigReq *)(req))->length) - -#define MAX_TIMES_PER 10 - -/* - * A lot of the code in this file manipulates a ConnectionInputPtr: - * - * ----------------------------------------------- - * |------- bufcnt ------->| | | - * | |- gotnow ->| | | - * | |-------- needed ------>| | - * |-----------+--------- size --------+---------->| - * ----------------------------------------------- - * ^ ^ - * | | - * buffer bufptr - * - * buffer is a pointer to the start of the buffer. - * bufptr points to the start of the current request. - * bufcnt counts how many bytes are in the buffer. - * size is the size of the buffer in bytes. - * - * In several of the functions, gotnow and needed are local variables - * that do the following: - * - * gotnow is the number of bytes of the request that we're - * trying to read that are currently in the buffer. - * Typically, gotnow = (buffer + bufcnt) - bufptr - * - * needed = the length of the request that we're trying to - * read. Watch out: needed sometimes counts bytes and sometimes - * counts CARD32's. - */ - - -/***************************************************************** - * ReadRequestFromClient - * Returns one request in client->requestBuffer. The request - * length will be in client->req_len. Return status is: - * - * > 0 if successful, specifies length in bytes of the request - * = 0 if entire request is not yet available - * < 0 if client should be terminated - * - * The request returned must be contiguous so that it can be - * cast in the dispatcher to the correct request type. Because requests - * are variable length, ReadRequestFromClient() must look at the first 4 - * or 8 bytes of a request to determine the length (the request length is - * in the 3rd and 4th bytes of the request unless it is a Big Request - * (see the Big Request Extension), in which case the 3rd and 4th bytes - * are zero and the following 4 bytes are the request length. - * - * Note: in order to make the server scheduler (WaitForSomething()) - * "fair", the ClientsWithInput mask is used. This mask tells which - * clients have FULL requests left in their buffers. Clients with - * partial requests require a read. Basically, client buffers - * are drained before select() is called again. But, we can't keep - * reading from a client that is sending buckets of data (or has - * a partial request) because others clients need to be scheduled. - *****************************************************************/ - -static void -YieldControl(void) -{ - isItTimeToYield = TRUE; - timesThisConnection = 0; -} - -static void -YieldControlNoInput(int fd) -{ - YieldControl(); - FD_CLR(fd, &ClientsWithInput); -} - -static void -YieldControlDeath(void) -{ - timesThisConnection = 0; -} - -int -ReadRequestFromClient(ClientPtr client) -{ - OsCommPtr oc = (OsCommPtr)client->osPrivate; - ConnectionInputPtr oci = oc->input; - int fd = oc->fd; - unsigned int gotnow, needed; - int result; - register xReq *request; - Bool need_header; - Bool move_header; - - /* If an input buffer was empty, either free it if it is too big - * or link it into our list of free input buffers. This means that - * different clients can share the same input buffer (at different - * times). This was done to save memory. - */ - - if (AvailableInput) - { - if (AvailableInput != oc) - { - register ConnectionInputPtr aci = AvailableInput->input; - if (aci->size > BUFWATERMARK) - { - xfree(aci->buffer); - xfree(aci); - } - else - { - aci->next = FreeInputs; - FreeInputs = aci; - } - AvailableInput->input = (ConnectionInputPtr)NULL; - } - AvailableInput = (OsCommPtr)NULL; - } - - /* make sure we have an input buffer */ - - if (!oci) - { - if ((oci = FreeInputs)) - { - FreeInputs = oci->next; - } - else if (!(oci = AllocateInputBuffer())) - { - YieldControlDeath(); - return -1; - } - oc->input = oci; - } - - /* advance to start of next request */ - - oci->bufptr += oci->lenLastReq; - - need_header = FALSE; - move_header = FALSE; - gotnow = oci->bufcnt + oci->buffer - oci->bufptr; - if (gotnow < sizeof(xReq)) - { - /* We don't have an entire xReq yet. Can't tell how big - * the request will be until we get the whole xReq. - */ - needed = sizeof(xReq); - need_header = TRUE; - } - else - { - /* We have a whole xReq. We can tell how big the whole - * request will be unless it is a Big Request. - */ - request = (xReq *)oci->bufptr; - needed = get_req_len(request, client); - if (!needed && client->big_requests) - { - /* It's a Big Request. */ - move_header = TRUE; - if (gotnow < sizeof(xBigReq)) - { - /* Still need more data to tell just how big. */ - needed = bytes_to_int32(sizeof(xBigReq)); /* needed is in CARD32s now */ - need_header = TRUE; - } - else - needed = get_big_req_len(request, client); - } - client->req_len = needed; - needed <<= 2; /* needed is in bytes now */ - } - if (gotnow < needed) - { - /* Need to read more data, either so that we can get a - * complete xReq (if need_header is TRUE), a complete - * xBigReq (if move_header is TRUE), or the rest of the - * request (if need_header and move_header are both FALSE). - */ - - oci->lenLastReq = 0; - if (needed > maxBigRequestSize << 2) - { - /* request is too big for us to handle */ - YieldControlDeath(); - return -1; - } - if ((gotnow == 0) || - ((oci->bufptr - oci->buffer + needed) > oci->size)) - { - /* no data, or the request is too big to fit in the buffer */ - - if ((gotnow > 0) && (oci->bufptr != oci->buffer)) - /* save the data we've already read */ - memmove(oci->buffer, oci->bufptr, gotnow); - if (needed > oci->size) - { - /* make buffer bigger to accomodate request */ - char *ibuf; - - ibuf = (char *)xrealloc(oci->buffer, needed); - if (!ibuf) - { - YieldControlDeath(); - return -1; - } - oci->size = needed; - oci->buffer = ibuf; - } - oci->bufptr = oci->buffer; - oci->bufcnt = gotnow; - } - /* XXX this is a workaround. This function is sometimes called - * after the trans_conn has been freed. In this case trans_conn - * will be null. Really ought to restructure things so that we - * never get here in those circumstances. - */ - if (!oc->trans_conn) - { - /* treat as if an error occured on the read, which is what - * used to happen - */ - YieldControlDeath(); - return -1; - } - result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt, - oci->size - oci->bufcnt); - if (result <= 0) - { - if ((result < 0) && ETEST(errno)) - { -#if defined(SVR4) && defined(__i386__) && !defined(sun) - if (0) -#endif - { - YieldControlNoInput(fd); - return 0; - } - } - YieldControlDeath(); - return -1; - } - oci->bufcnt += result; - gotnow += result; - /* free up some space after huge requests */ - if ((oci->size > BUFWATERMARK) && - (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) - { - char *ibuf; - - ibuf = (char *)xrealloc(oci->buffer, BUFSIZE); - if (ibuf) - { - oci->size = BUFSIZE; - oci->buffer = ibuf; - oci->bufptr = ibuf + oci->bufcnt - gotnow; - } - } - if (need_header && gotnow >= needed) - { - /* We wanted an xReq, now we've gotten it. */ - request = (xReq *)oci->bufptr; - needed = get_req_len(request, client); - if (!needed && client->big_requests) - { - move_header = TRUE; - if (gotnow < sizeof(xBigReq)) - needed = bytes_to_int32(sizeof(xBigReq)); - else - needed = get_big_req_len(request, client); - } - client->req_len = needed; - needed <<= 2; - } - if (gotnow < needed) - { - /* Still don't have enough; punt. */ - YieldControlNoInput(fd); - return 0; - } - } - if (needed == 0) - { - if (client->big_requests) - needed = sizeof(xBigReq); - else - needed = sizeof(xReq); - } - oci->lenLastReq = needed; - - /* - * Check to see if client has at least one whole request in the - * buffer beyond the request we're returning to the caller. - * If there is only a partial request, treat like buffer - * is empty so that select() will be called again and other clients - * can get into the queue. - */ - - gotnow -= needed; - if (gotnow >= sizeof(xReq)) - { - request = (xReq *)(oci->bufptr + needed); - if (gotnow >= (result = (get_req_len(request, client) << 2)) - && (result || - (client->big_requests && - (gotnow >= sizeof(xBigReq) && - gotnow >= (get_big_req_len(request, client) << 2)))) - ) - FD_SET(fd, &ClientsWithInput); - else - { - if (!SmartScheduleDisable) - FD_CLR(fd, &ClientsWithInput); - else - YieldControlNoInput(fd); - } - } - else - { - if (!gotnow) - AvailableInput = oc; - if (!SmartScheduleDisable) - FD_CLR(fd, &ClientsWithInput); - else - YieldControlNoInput(fd); - } - if (SmartScheduleDisable) - if (++timesThisConnection >= MAX_TIMES_PER) - YieldControl(); - if (move_header) - { - request = (xReq *)oci->bufptr; - oci->bufptr += (sizeof(xBigReq) - sizeof(xReq)); - *(xReq *)oci->bufptr = *request; - oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq)); - client->req_len -= bytes_to_int32(sizeof(xBigReq) - sizeof(xReq)); - } - client->requestBuffer = (pointer)oci->bufptr; -#ifdef DEBUG_COMMUNICATION - { - xReq *req = client->requestBuffer; - ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n", - client->index,req->reqType,req->data,req->length); - } -#endif - return needed; -} - -/***************************************************************** - * InsertFakeRequest - * Splice a consed up (possibly partial) request in as the next request. - * - **********************/ - -Bool -InsertFakeRequest(ClientPtr client, char *data, int count) -{ - OsCommPtr oc = (OsCommPtr)client->osPrivate; - ConnectionInputPtr oci = oc->input; - int fd = oc->fd; - int gotnow, moveup; - - if (AvailableInput) - { - if (AvailableInput != oc) - { - ConnectionInputPtr aci = AvailableInput->input; - if (aci->size > BUFWATERMARK) - { - xfree(aci->buffer); - xfree(aci); - } - else - { - aci->next = FreeInputs; - FreeInputs = aci; - } - AvailableInput->input = (ConnectionInputPtr)NULL; - } - AvailableInput = (OsCommPtr)NULL; - } - if (!oci) - { - if ((oci = FreeInputs)) - FreeInputs = oci->next; - else if (!(oci = AllocateInputBuffer())) - return FALSE; - oc->input = oci; - } - oci->bufptr += oci->lenLastReq; - oci->lenLastReq = 0; - gotnow = oci->bufcnt + oci->buffer - oci->bufptr; - if ((gotnow + count) > oci->size) - { - char *ibuf; - - ibuf = (char *)xrealloc(oci->buffer, gotnow + count); - if (!ibuf) - return(FALSE); - oci->size = gotnow + count; - oci->buffer = ibuf; - oci->bufptr = ibuf + oci->bufcnt - gotnow; - } - moveup = count - (oci->bufptr - oci->buffer); - if (moveup > 0) - { - if (gotnow > 0) - memmove(oci->bufptr + moveup, oci->bufptr, gotnow); - oci->bufptr += moveup; - oci->bufcnt += moveup; - } - memmove(oci->bufptr - count, data, count); - oci->bufptr -= count; - gotnow += count; - if ((gotnow >= sizeof(xReq)) && - (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2))) - FD_SET(fd, &ClientsWithInput); - else - YieldControlNoInput(fd); - return(TRUE); -} - -/***************************************************************** - * ResetRequestFromClient - * Reset to reexecute the current request, and yield. - * - **********************/ - -void -ResetCurrentRequest(ClientPtr client) -{ - OsCommPtr oc = (OsCommPtr)client->osPrivate; - register ConnectionInputPtr oci = oc->input; - int fd = oc->fd; - register xReq *request; - int gotnow, needed; - if (AvailableInput == oc) - AvailableInput = (OsCommPtr)NULL; - oci->lenLastReq = 0; - gotnow = oci->bufcnt + oci->buffer - oci->bufptr; - if (gotnow < sizeof(xReq)) - { - YieldControlNoInput(fd); - } - else - { - request = (xReq *)oci->bufptr; - needed = get_req_len(request, client); - if (!needed && client->big_requests) - { - oci->bufptr -= sizeof(xBigReq) - sizeof(xReq); - *(xReq *)oci->bufptr = *request; - ((xBigReq *)oci->bufptr)->length = client->req_len; - if (client->swapped) - { - char n; - swapl(&((xBigReq *)oci->bufptr)->length, n); - } - } - if (gotnow >= (needed << 2)) - { - if (FD_ISSET(fd, &AllClients)) - { - FD_SET(fd, &ClientsWithInput); - } - else - { - FD_SET(fd, &IgnoredClientsWithInput); - } - YieldControl(); - } - else - YieldControlNoInput(fd); - } -} - -static const int padlength[4] = {0, 3, 2, 1}; - - /******************** - * FlushAllOutput() - * Flush all clients with output. However, if some client still - * has input in the queue (more requests), then don't flush. This - * will prevent the output queue from being flushed every time around - * the round robin queue. Now, some say that it SHOULD be flushed - * every time around, but... - * - **********************/ - -void -FlushAllOutput(void) -{ - register int index, base; - register fd_mask mask; /* raphael */ - OsCommPtr oc; - register ClientPtr client; - Bool newoutput = NewOutputPending; -#if defined(WIN32) - fd_set newOutputPending; -#endif - - if (FlushCallback) - CallCallbacks(&FlushCallback, NULL); - - if (!newoutput) - return; - - /* - * It may be that some client still has critical output pending, - * but he is not yet ready to receive it anyway, so we will - * simply wait for the select to tell us when he's ready to receive. - */ - CriticalOutputPending = FALSE; - NewOutputPending = FALSE; - -#ifndef WIN32 - for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++) - { - mask = OutputPending.fds_bits[ base ]; - OutputPending.fds_bits[ base ] = 0; - while (mask) - { - index = ffs(mask) - 1; - mask &= ~lowbit(mask); - if ((index = ConnectionTranslation[(base * (sizeof(fd_mask)*8)) + index]) == 0) - continue; - client = clients[index]; - if (client->clientGone) - continue; - oc = (OsCommPtr)client->osPrivate; - if (FD_ISSET(oc->fd, &ClientsWithInput)) - { - FD_SET(oc->fd, &OutputPending); /* set the bit again */ - NewOutputPending = TRUE; - } - else - (void)FlushClient(client, oc, (char *)NULL, 0); - } - } -#else /* WIN32 */ - FD_ZERO(&newOutputPending); - for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++) - { - index = XFD_FD(&OutputPending, base); - if ((index = GetConnectionTranslation(index)) == 0) - continue; - client = clients[index]; - if (client->clientGone) - continue; - oc = (OsCommPtr)client->osPrivate; - if (FD_ISSET(oc->fd, &ClientsWithInput)) - { - FD_SET(oc->fd, &newOutputPending); /* set the bit again */ - NewOutputPending = TRUE; - } - else - (void)FlushClient(client, oc, (char *)NULL, 0); - } - XFD_COPYSET(&newOutputPending, &OutputPending); -#endif /* WIN32 */ -} - -void -FlushIfCriticalOutputPending(void) -{ - if (CriticalOutputPending) - FlushAllOutput(); -} - -void -SetCriticalOutputPending(void) -{ - CriticalOutputPending = TRUE; -} - -/***************** - * WriteToClient - * Copies buf into ClientPtr.buf if it fits (with padding), else - * flushes ClientPtr.buf and buf to client. As of this writing, - * every use of WriteToClient is cast to void, and the result - * is ignored. Potentially, this could be used by requests - * that are sending several chunks of data and want to break - * out of a loop on error. Thus, we will leave the type of - * this routine as int. - *****************/ - -int -WriteToClient (ClientPtr who, int count, const void *__buf) -{ - OsCommPtr oc = (OsCommPtr)who->osPrivate; - ConnectionOutputPtr oco = oc->output; - int padBytes; - const char *buf = __buf; -#ifdef DEBUG_COMMUNICATION - Bool multicount = FALSE; -#endif - if (!count) - return(0); -#ifdef DEBUG_COMMUNICATION - { - char info[128]; - xError *err; - xGenericReply *rep; - xEvent *ev; - - if (!who->replyBytesRemaining) { - switch(buf[0]) { - case X_Reply: - rep = (xGenericReply*)buf; - if (rep->sequenceNumber == who->sequence) { - snprintf(info,127,"Xreply: type: 0x%x data: 0x%x " - "len: %i seq#: 0x%x", rep->type, rep->data1, - rep->length, rep->sequenceNumber); - multicount = TRUE; - } - break; - case X_Error: - err = (xError*)buf; - snprintf(info,127,"Xerror: Code: 0x%x resID: 0x%x maj: 0x%x " - "min: %x", err->errorCode,err->resourceID, - err->minorCode,err->majorCode); - break; - default: - if ((buf[0] & 0x7f) == KeymapNotify) - snprintf(info,127,"KeymapNotifyEvent: %i",buf[0]); - else { - ev = (xEvent*)buf; - snprintf(info,127,"XEvent: type: 0x%x detail: 0x%x " - "seq#: 0x%x", ev->u.u.type, ev->u.u.detail, - ev->u.u.sequenceNumber); - } - } - ErrorF("REPLY: ClientIDX: %i %s\n",who->index, info); - } else - multicount = TRUE; - } -#endif - - if (!oco) - { - if ((oco = FreeOutputs)) - { - FreeOutputs = oco->next; - } - else if (!(oco = AllocateOutputBuffer())) - { - if (oc->trans_conn) { - _XSERVTransDisconnect(oc->trans_conn); - _XSERVTransClose(oc->trans_conn); - oc->trans_conn = NULL; - } - MarkClientException(who); - return -1; - } - oc->output = oco; - } - - padBytes = padlength[count & 3]; - - if(ReplyCallback) - { - ReplyInfoRec replyinfo; - - replyinfo.client = who; - replyinfo.replyData = buf; - replyinfo.dataLenBytes = count + padBytes; - if (who->replyBytesRemaining) - { /* still sending data of an earlier reply */ - who->replyBytesRemaining -= count + padBytes; - replyinfo.startOfReply = FALSE; - replyinfo.bytesRemaining = who->replyBytesRemaining; - CallCallbacks((&ReplyCallback), (pointer)&replyinfo); - } - else if (who->clientState == ClientStateRunning - && buf[0] == X_Reply) - { /* start of new reply */ - CARD32 replylen; - unsigned long bytesleft; - char n; - - replylen = ((xGenericReply *)buf)->length; - if (who->swapped) - swapl(&replylen, n); - bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes; - replyinfo.startOfReply = TRUE; - replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft; - CallCallbacks((&ReplyCallback), (pointer)&replyinfo); - } - } -#ifdef DEBUG_COMMUNICATION - else if (multicount) { - if (who->replyBytesRemaining) { - who->replyBytesRemaining -= (count + padBytes); - } else { - CARD32 replylen; - replylen = ((xGenericReply *)buf)->length; - who->replyBytesRemaining = - (replylen * 4) + SIZEOF(xReply) - count - padBytes; - } - } -#endif - if (oco->count + count + padBytes > oco->size) - { - FD_CLR(oc->fd, &OutputPending); - if(!XFD_ANYSET(&OutputPending)) { - CriticalOutputPending = FALSE; - NewOutputPending = FALSE; - } - return FlushClient(who, oc, buf, count); - } - - NewOutputPending = TRUE; - FD_SET(oc->fd, &OutputPending); - memmove((char *)oco->buf + oco->count, buf, count); - oco->count += count + padBytes; - return(count); -} - - /******************** - * FlushClient() - * If the client isn't keeping up with us, then we try to continue - * buffering the data and set the apropriate bit in ClientsWritable - * (which is used by WaitFor in the select). If the connection yields - * a permanent error, or we can't allocate any more space, we then - * close the connection. - * - **********************/ - -int -FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount) -{ - ConnectionOutputPtr oco = oc->output; - int connection = oc->fd; - XtransConnInfo trans_conn = oc->trans_conn; - struct iovec iov[3]; - static char padBuffer[3]; - const char *extraBuf = __extraBuf; - long written; - long padsize; - long notWritten; - long todo; - - if (!oco) - return 0; - written = 0; - padsize = padlength[extraCount & 3]; - notWritten = oco->count + extraCount + padsize; - todo = notWritten; - while (notWritten) { - long before = written; /* amount of whole thing written */ - long remain = todo; /* amount to try this time, <= notWritten */ - int i = 0; - long len; - - /* You could be very general here and have "in" and "out" iovecs - * and write a loop without using a macro, but what the heck. This - * translates to: - * - * how much of this piece is new? - * if more new then we are trying this time, clamp - * if nothing new - * then bump down amount already written, for next piece - * else put new stuff in iovec, will need all of next piece - * - * Note that todo had better be at least 1 or else we'll end up - * writing 0 iovecs. - */ -#define InsertIOV(pointer, length) \ - len = (length) - before; \ - if (len > remain) \ - len = remain; \ - if (len <= 0) { \ - before = (-len); \ - } else { \ - iov[i].iov_len = len; \ - iov[i].iov_base = (pointer) + before; \ - i++; \ - remain -= len; \ - before = 0; \ - } - - InsertIOV ((char *)oco->buf, oco->count) - InsertIOV ((char *)extraBuf, extraCount) - InsertIOV (padBuffer, padsize) - - errno = 0; - if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0) - { - written += len; - notWritten -= len; - todo = notWritten; - } - else if (ETEST(errno) -#ifdef SUNSYSV /* check for another brain-damaged OS bug */ - || (errno == 0) -#endif -#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ - || ((errno == EMSGSIZE) && (todo == 1)) -#endif - ) - { - /* If we've arrived here, then the client is stuffed to the gills - and not ready to accept more. Make a note of it and buffer - the rest. */ - FD_SET(connection, &ClientsWriteBlocked); - AnyClientsWriteBlocked = TRUE; - - if (written < oco->count) - { - if (written > 0) - { - oco->count -= written; - memmove((char *)oco->buf, - (char *)oco->buf + written, - oco->count); - written = 0; - } - } - else - { - written -= oco->count; - oco->count = 0; - } - - if (notWritten > oco->size) - { - unsigned char *obuf; - - obuf = (unsigned char *)xrealloc(oco->buf, - notWritten + BUFSIZE); - if (!obuf) - { - _XSERVTransDisconnect(oc->trans_conn); - _XSERVTransClose(oc->trans_conn); - oc->trans_conn = NULL; - MarkClientException(who); - oco->count = 0; - return(-1); - } - oco->size = notWritten + BUFSIZE; - oco->buf = obuf; - } - - /* If the amount written extended into the padBuffer, then the - difference "extraCount - written" may be less than 0 */ - if ((len = extraCount - written) > 0) - memmove ((char *)oco->buf + oco->count, - extraBuf + written, - len); - - oco->count = notWritten; /* this will include the pad */ - /* return only the amount explicitly requested */ - return extraCount; - } -#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ - else if (errno == EMSGSIZE) - { - todo >>= 1; - } -#endif - else - { - if (oc->trans_conn) - { - _XSERVTransDisconnect(oc->trans_conn); - _XSERVTransClose(oc->trans_conn); - oc->trans_conn = NULL; - } - MarkClientException(who); - oco->count = 0; - return(-1); - } - } - - /* everything was flushed out */ - oco->count = 0; - /* check to see if this client was write blocked */ - if (AnyClientsWriteBlocked) - { - FD_CLR(oc->fd, &ClientsWriteBlocked); - if (! XFD_ANYSET(&ClientsWriteBlocked)) - AnyClientsWriteBlocked = FALSE; - } - if (oco->size > BUFWATERMARK) - { - xfree(oco->buf); - xfree(oco); - } - else - { - oco->next = FreeOutputs; - FreeOutputs = oco; - } - oc->output = (ConnectionOutputPtr)NULL; - return extraCount; /* return only the amount explicitly requested */ -} - -static ConnectionInputPtr -AllocateInputBuffer(void) -{ - ConnectionInputPtr oci; - - oci = xalloc(sizeof(ConnectionInput)); - if (!oci) - return NULL; - oci->buffer = xalloc(BUFSIZE); - if (!oci->buffer) - { - xfree(oci); - return NULL; - } - oci->size = BUFSIZE; - oci->bufptr = oci->buffer; - oci->bufcnt = 0; - oci->lenLastReq = 0; - return oci; -} - -static ConnectionOutputPtr -AllocateOutputBuffer(void) -{ - ConnectionOutputPtr oco; - - oco = xalloc(sizeof(ConnectionOutput)); - if (!oco) - return NULL; - oco->buf = xcalloc(1, BUFSIZE); - if (!oco->buf) - { - xfree(oco); - return NULL; - } - oco->size = BUFSIZE; - oco->count = 0; - return oco; -} - -void -FreeOsBuffers(OsCommPtr oc) -{ - ConnectionInputPtr oci; - ConnectionOutputPtr oco; - - if (AvailableInput == oc) - AvailableInput = (OsCommPtr)NULL; - if ((oci = oc->input)) - { - if (FreeInputs) - { - xfree(oci->buffer); - xfree(oci); - } - else - { - FreeInputs = oci; - oci->next = (ConnectionInputPtr)NULL; - oci->bufptr = oci->buffer; - oci->bufcnt = 0; - oci->lenLastReq = 0; - } - } - if ((oco = oc->output)) - { - if (FreeOutputs) - { - xfree(oco->buf); - xfree(oco); - } - else - { - FreeOutputs = oco; - oco->next = (ConnectionOutputPtr)NULL; - oco->count = 0; - } - } -} - -void -ResetOsBuffers(void) -{ - ConnectionInputPtr oci; - ConnectionOutputPtr oco; - - while ((oci = FreeInputs)) - { - FreeInputs = oci->next; - xfree(oci->buffer); - xfree(oci); - } - while ((oco = FreeOutputs)) - { - FreeOutputs = oco->next; - xfree(oco->buf); - xfree(oco); - } -} +/*********************************************************** + +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. + + +******************************************************************/ +/***************************************************************** + * i/o functions + * + * WriteToClient, ReadRequestFromClient + * InsertFakeRequest, ResetCurrentRequest + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#undef DEBUG_COMMUNICATION + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <stdio.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <X11/Xtrans/Xtrans.h> +#include <X11/Xmd.h> +#include <errno.h> +#if !defined(WIN32) +#include <sys/uio.h> +#endif +#include <X11/X.h> +#include <X11/Xproto.h> +#include "os.h" +#include "osdep.h" +#include <X11/Xpoll.h> +#include "opaque.h" +#include "dixstruct.h" +#include "misc.h" + +CallbackListPtr ReplyCallback; +CallbackListPtr FlushCallback; + +static ConnectionInputPtr AllocateInputBuffer(void); +static ConnectionOutputPtr AllocateOutputBuffer(void); + +/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX + * systems are broken and return EWOULDBLOCK when they should return EAGAIN + */ +#ifndef WIN32 +#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK) +#else /* WIN32 The socket errorcodes differ from the normal errors*/ +#define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK) +#endif + +static Bool CriticalOutputPending; +static int timesThisConnection = 0; +static ConnectionInputPtr FreeInputs = (ConnectionInputPtr)NULL; +static ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr)NULL; +static OsCommPtr AvailableInput = (OsCommPtr)NULL; + +#define get_req_len(req,cli) ((cli)->swapped ? \ + lswaps((req)->length) : (req)->length) + +#include <X11/extensions/bigreqsproto.h> + +#define get_big_req_len(req,cli) ((cli)->swapped ? \ + lswapl(((xBigReq *)(req))->length) : \ + ((xBigReq *)(req))->length) + +#define MAX_TIMES_PER 10 + +/* + * A lot of the code in this file manipulates a ConnectionInputPtr: + * + * ----------------------------------------------- + * |------- bufcnt ------->| | | + * | |- gotnow ->| | | + * | |-------- needed ------>| | + * |-----------+--------- size --------+---------->| + * ----------------------------------------------- + * ^ ^ + * | | + * buffer bufptr + * + * buffer is a pointer to the start of the buffer. + * bufptr points to the start of the current request. + * bufcnt counts how many bytes are in the buffer. + * size is the size of the buffer in bytes. + * + * In several of the functions, gotnow and needed are local variables + * that do the following: + * + * gotnow is the number of bytes of the request that we're + * trying to read that are currently in the buffer. + * Typically, gotnow = (buffer + bufcnt) - bufptr + * + * needed = the length of the request that we're trying to + * read. Watch out: needed sometimes counts bytes and sometimes + * counts CARD32's. + */ + + +/***************************************************************** + * ReadRequestFromClient + * Returns one request in client->requestBuffer. The request + * length will be in client->req_len. Return status is: + * + * > 0 if successful, specifies length in bytes of the request + * = 0 if entire request is not yet available + * < 0 if client should be terminated + * + * The request returned must be contiguous so that it can be + * cast in the dispatcher to the correct request type. Because requests + * are variable length, ReadRequestFromClient() must look at the first 4 + * or 8 bytes of a request to determine the length (the request length is + * in the 3rd and 4th bytes of the request unless it is a Big Request + * (see the Big Request Extension), in which case the 3rd and 4th bytes + * are zero and the following 4 bytes are the request length. + * + * Note: in order to make the server scheduler (WaitForSomething()) + * "fair", the ClientsWithInput mask is used. This mask tells which + * clients have FULL requests left in their buffers. Clients with + * partial requests require a read. Basically, client buffers + * are drained before select() is called again. But, we can't keep + * reading from a client that is sending buckets of data (or has + * a partial request) because others clients need to be scheduled. + *****************************************************************/ + +static void +YieldControl(void) +{ + isItTimeToYield = TRUE; + timesThisConnection = 0; +} + +static void +YieldControlNoInput(int fd) +{ + YieldControl(); + FD_CLR(fd, &ClientsWithInput); +} + +static void +YieldControlDeath(void) +{ + timesThisConnection = 0; +} + +int +ReadRequestFromClient(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + ConnectionInputPtr oci = oc->input; + int fd = oc->fd; + unsigned int gotnow, needed; + int result; + register xReq *request; + Bool need_header; + Bool move_header; + + /* If an input buffer was empty, either free it if it is too big + * or link it into our list of free input buffers. This means that + * different clients can share the same input buffer (at different + * times). This was done to save memory. + */ + + if (AvailableInput) + { + if (AvailableInput != oc) + { + register ConnectionInputPtr aci = AvailableInput->input; + if (aci->size > BUFWATERMARK) + { + free(aci->buffer); + free(aci); + } + else + { + aci->next = FreeInputs; + FreeInputs = aci; + } + AvailableInput->input = (ConnectionInputPtr)NULL; + } + AvailableInput = (OsCommPtr)NULL; + } + + /* make sure we have an input buffer */ + + if (!oci) + { + if ((oci = FreeInputs)) + { + FreeInputs = oci->next; + } + else if (!(oci = AllocateInputBuffer())) + { + YieldControlDeath(); + return -1; + } + oc->input = oci; + } + + /* advance to start of next request */ + + oci->bufptr += oci->lenLastReq; + + need_header = FALSE; + move_header = FALSE; + gotnow = oci->bufcnt + oci->buffer - oci->bufptr; + if (gotnow < sizeof(xReq)) + { + /* We don't have an entire xReq yet. Can't tell how big + * the request will be until we get the whole xReq. + */ + needed = sizeof(xReq); + need_header = TRUE; + } + else + { + /* We have a whole xReq. We can tell how big the whole + * request will be unless it is a Big Request. + */ + request = (xReq *)oci->bufptr; + needed = get_req_len(request, client); + if (!needed && client->big_requests) + { + /* It's a Big Request. */ + move_header = TRUE; + if (gotnow < sizeof(xBigReq)) + { + /* Still need more data to tell just how big. */ + needed = bytes_to_int32(sizeof(xBigReq)); /* needed is in CARD32s now */ + need_header = TRUE; + } + else + needed = get_big_req_len(request, client); + } + client->req_len = needed; + needed <<= 2; /* needed is in bytes now */ + } + if (gotnow < needed) + { + /* Need to read more data, either so that we can get a + * complete xReq (if need_header is TRUE), a complete + * xBigReq (if move_header is TRUE), or the rest of the + * request (if need_header and move_header are both FALSE). + */ + + oci->lenLastReq = 0; + if (needed > maxBigRequestSize << 2) + { + /* request is too big for us to handle */ + YieldControlDeath(); + return -1; + } + if ((gotnow == 0) || + ((oci->bufptr - oci->buffer + needed) > oci->size)) + { + /* no data, or the request is too big to fit in the buffer */ + + if ((gotnow > 0) && (oci->bufptr != oci->buffer)) + /* save the data we've already read */ + memmove(oci->buffer, oci->bufptr, gotnow); + if (needed > oci->size) + { + /* make buffer bigger to accomodate request */ + char *ibuf; + + ibuf = (char *)realloc(oci->buffer, needed); + if (!ibuf) + { + YieldControlDeath(); + return -1; + } + oci->size = needed; + oci->buffer = ibuf; + } + oci->bufptr = oci->buffer; + oci->bufcnt = gotnow; + } + /* XXX this is a workaround. This function is sometimes called + * after the trans_conn has been freed. In this case trans_conn + * will be null. Really ought to restructure things so that we + * never get here in those circumstances. + */ + if (!oc->trans_conn) + { + /* treat as if an error occured on the read, which is what + * used to happen + */ + YieldControlDeath(); + return -1; + } + result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt, + oci->size - oci->bufcnt); + if (result <= 0) + { + if ((result < 0) && ETEST(errno)) + { +#if defined(SVR4) && defined(__i386__) && !defined(sun) + if (0) +#endif + { + YieldControlNoInput(fd); + return 0; + } + } + YieldControlDeath(); + return -1; + } + oci->bufcnt += result; + gotnow += result; + /* free up some space after huge requests */ + if ((oci->size > BUFWATERMARK) && + (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) + { + char *ibuf; + + ibuf = (char *)realloc(oci->buffer, BUFSIZE); + if (ibuf) + { + oci->size = BUFSIZE; + oci->buffer = ibuf; + oci->bufptr = ibuf + oci->bufcnt - gotnow; + } + } + if (need_header && gotnow >= needed) + { + /* We wanted an xReq, now we've gotten it. */ + request = (xReq *)oci->bufptr; + needed = get_req_len(request, client); + if (!needed && client->big_requests) + { + move_header = TRUE; + if (gotnow < sizeof(xBigReq)) + needed = bytes_to_int32(sizeof(xBigReq)); + else + needed = get_big_req_len(request, client); + } + client->req_len = needed; + needed <<= 2; + } + if (gotnow < needed) + { + /* Still don't have enough; punt. */ + YieldControlNoInput(fd); + return 0; + } + } + if (needed == 0) + { + if (client->big_requests) + needed = sizeof(xBigReq); + else + needed = sizeof(xReq); + } + oci->lenLastReq = needed; + + /* + * Check to see if client has at least one whole request in the + * buffer beyond the request we're returning to the caller. + * If there is only a partial request, treat like buffer + * is empty so that select() will be called again and other clients + * can get into the queue. + */ + + gotnow -= needed; + if (gotnow >= sizeof(xReq)) + { + request = (xReq *)(oci->bufptr + needed); + if (gotnow >= (result = (get_req_len(request, client) << 2)) + && (result || + (client->big_requests && + (gotnow >= sizeof(xBigReq) && + gotnow >= (get_big_req_len(request, client) << 2)))) + ) + FD_SET(fd, &ClientsWithInput); + else + { + if (!SmartScheduleDisable) + FD_CLR(fd, &ClientsWithInput); + else + YieldControlNoInput(fd); + } + } + else + { + if (!gotnow) + AvailableInput = oc; + if (!SmartScheduleDisable) + FD_CLR(fd, &ClientsWithInput); + else + YieldControlNoInput(fd); + } + if (SmartScheduleDisable) + if (++timesThisConnection >= MAX_TIMES_PER) + YieldControl(); + if (move_header) + { + request = (xReq *)oci->bufptr; + oci->bufptr += (sizeof(xBigReq) - sizeof(xReq)); + *(xReq *)oci->bufptr = *request; + oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq)); + client->req_len -= bytes_to_int32(sizeof(xBigReq) - sizeof(xReq)); + } + client->requestBuffer = (pointer)oci->bufptr; +#ifdef DEBUG_COMMUNICATION + { + xReq *req = client->requestBuffer; + ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n", + client->index,req->reqType,req->data,req->length); + } +#endif + return needed; +} + +/***************************************************************** + * InsertFakeRequest + * Splice a consed up (possibly partial) request in as the next request. + * + **********************/ + +Bool +InsertFakeRequest(ClientPtr client, char *data, int count) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + ConnectionInputPtr oci = oc->input; + int fd = oc->fd; + int gotnow, moveup; + + if (AvailableInput) + { + if (AvailableInput != oc) + { + ConnectionInputPtr aci = AvailableInput->input; + if (aci->size > BUFWATERMARK) + { + free(aci->buffer); + free(aci); + } + else + { + aci->next = FreeInputs; + FreeInputs = aci; + } + AvailableInput->input = (ConnectionInputPtr)NULL; + } + AvailableInput = (OsCommPtr)NULL; + } + if (!oci) + { + if ((oci = FreeInputs)) + FreeInputs = oci->next; + else if (!(oci = AllocateInputBuffer())) + return FALSE; + oc->input = oci; + } + oci->bufptr += oci->lenLastReq; + oci->lenLastReq = 0; + gotnow = oci->bufcnt + oci->buffer - oci->bufptr; + if ((gotnow + count) > oci->size) + { + char *ibuf; + + ibuf = (char *)realloc(oci->buffer, gotnow + count); + if (!ibuf) + return(FALSE); + oci->size = gotnow + count; + oci->buffer = ibuf; + oci->bufptr = ibuf + oci->bufcnt - gotnow; + } + moveup = count - (oci->bufptr - oci->buffer); + if (moveup > 0) + { + if (gotnow > 0) + memmove(oci->bufptr + moveup, oci->bufptr, gotnow); + oci->bufptr += moveup; + oci->bufcnt += moveup; + } + memmove(oci->bufptr - count, data, count); + oci->bufptr -= count; + gotnow += count; + if ((gotnow >= sizeof(xReq)) && + (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2))) + FD_SET(fd, &ClientsWithInput); + else + YieldControlNoInput(fd); + return(TRUE); +} + +/***************************************************************** + * ResetRequestFromClient + * Reset to reexecute the current request, and yield. + * + **********************/ + +void +ResetCurrentRequest(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + register ConnectionInputPtr oci = oc->input; + int fd = oc->fd; + register xReq *request; + int gotnow, needed; + if (AvailableInput == oc) + AvailableInput = (OsCommPtr)NULL; + oci->lenLastReq = 0; + gotnow = oci->bufcnt + oci->buffer - oci->bufptr; + if (gotnow < sizeof(xReq)) + { + YieldControlNoInput(fd); + } + else + { + request = (xReq *)oci->bufptr; + needed = get_req_len(request, client); + if (!needed && client->big_requests) + { + oci->bufptr -= sizeof(xBigReq) - sizeof(xReq); + *(xReq *)oci->bufptr = *request; + ((xBigReq *)oci->bufptr)->length = client->req_len; + if (client->swapped) + { + char n; + swapl(&((xBigReq *)oci->bufptr)->length, n); + } + } + if (gotnow >= (needed << 2)) + { + if (FD_ISSET(fd, &AllClients)) + { + FD_SET(fd, &ClientsWithInput); + } + else + { + FD_SET(fd, &IgnoredClientsWithInput); + } + YieldControl(); + } + else + YieldControlNoInput(fd); + } +} + +static const int padlength[4] = {0, 3, 2, 1}; + + /******************** + * FlushAllOutput() + * Flush all clients with output. However, if some client still + * has input in the queue (more requests), then don't flush. This + * will prevent the output queue from being flushed every time around + * the round robin queue. Now, some say that it SHOULD be flushed + * every time around, but... + * + **********************/ + +void +FlushAllOutput(void) +{ + register int index, base; + register fd_mask mask; /* raphael */ + OsCommPtr oc; + register ClientPtr client; + Bool newoutput = NewOutputPending; +#if defined(WIN32) + fd_set newOutputPending; +#endif + + if (FlushCallback) + CallCallbacks(&FlushCallback, NULL); + + if (!newoutput) + return; + + /* + * It may be that some client still has critical output pending, + * but he is not yet ready to receive it anyway, so we will + * simply wait for the select to tell us when he's ready to receive. + */ + CriticalOutputPending = FALSE; + NewOutputPending = FALSE; + +#ifndef WIN32 + for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++) + { + mask = OutputPending.fds_bits[ base ]; + OutputPending.fds_bits[ base ] = 0; + while (mask) + { + index = ffs(mask) - 1; + mask &= ~lowbit(mask); + if ((index = ConnectionTranslation[(base * (sizeof(fd_mask)*8)) + index]) == 0) + continue; + client = clients[index]; + if (client->clientGone) + continue; + oc = (OsCommPtr)client->osPrivate; + if (FD_ISSET(oc->fd, &ClientsWithInput)) + { + FD_SET(oc->fd, &OutputPending); /* set the bit again */ + NewOutputPending = TRUE; + } + else + (void)FlushClient(client, oc, (char *)NULL, 0); + } + } +#else /* WIN32 */ + FD_ZERO(&newOutputPending); + for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++) + { + index = XFD_FD(&OutputPending, base); + if ((index = GetConnectionTranslation(index)) == 0) + continue; + client = clients[index]; + if (client->clientGone) + continue; + oc = (OsCommPtr)client->osPrivate; + if (FD_ISSET(oc->fd, &ClientsWithInput)) + { + FD_SET(oc->fd, &newOutputPending); /* set the bit again */ + NewOutputPending = TRUE; + } + else + (void)FlushClient(client, oc, (char *)NULL, 0); + } + XFD_COPYSET(&newOutputPending, &OutputPending); +#endif /* WIN32 */ +} + +void +FlushIfCriticalOutputPending(void) +{ + if (CriticalOutputPending) + FlushAllOutput(); +} + +void +SetCriticalOutputPending(void) +{ + CriticalOutputPending = TRUE; +} + +/***************** + * WriteToClient + * Copies buf into ClientPtr.buf if it fits (with padding), else + * flushes ClientPtr.buf and buf to client. As of this writing, + * every use of WriteToClient is cast to void, and the result + * is ignored. Potentially, this could be used by requests + * that are sending several chunks of data and want to break + * out of a loop on error. Thus, we will leave the type of + * this routine as int. + *****************/ + +int +WriteToClient (ClientPtr who, int count, const void *__buf) +{ + OsCommPtr oc = (OsCommPtr)who->osPrivate; + ConnectionOutputPtr oco = oc->output; + int padBytes; + const char *buf = __buf; +#ifdef DEBUG_COMMUNICATION + Bool multicount = FALSE; +#endif + if (!count) + return(0); +#ifdef DEBUG_COMMUNICATION + { + char info[128]; + xError *err; + xGenericReply *rep; + xEvent *ev; + + if (!who->replyBytesRemaining) { + switch(buf[0]) { + case X_Reply: + rep = (xGenericReply*)buf; + if (rep->sequenceNumber == who->sequence) { + snprintf(info,127,"Xreply: type: 0x%x data: 0x%x " + "len: %i seq#: 0x%x", rep->type, rep->data1, + rep->length, rep->sequenceNumber); + multicount = TRUE; + } + break; + case X_Error: + err = (xError*)buf; + snprintf(info,127,"Xerror: Code: 0x%x resID: 0x%x maj: 0x%x " + "min: %x", err->errorCode,err->resourceID, + err->minorCode,err->majorCode); + break; + default: + if ((buf[0] & 0x7f) == KeymapNotify) + snprintf(info,127,"KeymapNotifyEvent: %i",buf[0]); + else { + ev = (xEvent*)buf; + snprintf(info,127,"XEvent: type: 0x%x detail: 0x%x " + "seq#: 0x%x", ev->u.u.type, ev->u.u.detail, + ev->u.u.sequenceNumber); + } + } + ErrorF("REPLY: ClientIDX: %i %s\n",who->index, info); + } else + multicount = TRUE; + } +#endif + + if (!oco) + { + if ((oco = FreeOutputs)) + { + FreeOutputs = oco->next; + } + else if (!(oco = AllocateOutputBuffer())) + { + if (oc->trans_conn) { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + oc->trans_conn = NULL; + } + MarkClientException(who); + return -1; + } + oc->output = oco; + } + + padBytes = padlength[count & 3]; + + if(ReplyCallback) + { + ReplyInfoRec replyinfo; + + replyinfo.client = who; + replyinfo.replyData = buf; + replyinfo.dataLenBytes = count + padBytes; + if (who->replyBytesRemaining) + { /* still sending data of an earlier reply */ + who->replyBytesRemaining -= count + padBytes; + replyinfo.startOfReply = FALSE; + replyinfo.bytesRemaining = who->replyBytesRemaining; + CallCallbacks((&ReplyCallback), (pointer)&replyinfo); + } + else if (who->clientState == ClientStateRunning + && buf[0] == X_Reply) + { /* start of new reply */ + CARD32 replylen; + unsigned long bytesleft; + char n; + + replylen = ((xGenericReply *)buf)->length; + if (who->swapped) + swapl(&replylen, n); + bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes; + replyinfo.startOfReply = TRUE; + replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft; + CallCallbacks((&ReplyCallback), (pointer)&replyinfo); + } + } +#ifdef DEBUG_COMMUNICATION + else if (multicount) { + if (who->replyBytesRemaining) { + who->replyBytesRemaining -= (count + padBytes); + } else { + CARD32 replylen; + replylen = ((xGenericReply *)buf)->length; + who->replyBytesRemaining = + (replylen * 4) + SIZEOF(xReply) - count - padBytes; + } + } +#endif + if (oco->count + count + padBytes > oco->size) + { + FD_CLR(oc->fd, &OutputPending); + if(!XFD_ANYSET(&OutputPending)) { + CriticalOutputPending = FALSE; + NewOutputPending = FALSE; + } + return FlushClient(who, oc, buf, count); + } + + NewOutputPending = TRUE; + FD_SET(oc->fd, &OutputPending); + memmove((char *)oco->buf + oco->count, buf, count); + oco->count += count + padBytes; + return(count); +} + + /******************** + * FlushClient() + * If the client isn't keeping up with us, then we try to continue + * buffering the data and set the apropriate bit in ClientsWritable + * (which is used by WaitFor in the select). If the connection yields + * a permanent error, or we can't allocate any more space, we then + * close the connection. + * + **********************/ + +int +FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount) +{ + ConnectionOutputPtr oco = oc->output; + int connection = oc->fd; + XtransConnInfo trans_conn = oc->trans_conn; + struct iovec iov[3]; + static char padBuffer[3]; + const char *extraBuf = __extraBuf; + long written; + long padsize; + long notWritten; + long todo; + + if (!oco) + return 0; + written = 0; + padsize = padlength[extraCount & 3]; + notWritten = oco->count + extraCount + padsize; + todo = notWritten; + while (notWritten) { + long before = written; /* amount of whole thing written */ + long remain = todo; /* amount to try this time, <= notWritten */ + int i = 0; + long len; + + /* You could be very general here and have "in" and "out" iovecs + * and write a loop without using a macro, but what the heck. This + * translates to: + * + * how much of this piece is new? + * if more new then we are trying this time, clamp + * if nothing new + * then bump down amount already written, for next piece + * else put new stuff in iovec, will need all of next piece + * + * Note that todo had better be at least 1 or else we'll end up + * writing 0 iovecs. + */ +#define InsertIOV(pointer, length) \ + len = (length) - before; \ + if (len > remain) \ + len = remain; \ + if (len <= 0) { \ + before = (-len); \ + } else { \ + iov[i].iov_len = len; \ + iov[i].iov_base = (pointer) + before; \ + i++; \ + remain -= len; \ + before = 0; \ + } + + InsertIOV ((char *)oco->buf, oco->count) + InsertIOV ((char *)extraBuf, extraCount) + InsertIOV (padBuffer, padsize) + + errno = 0; + if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0) + { + written += len; + notWritten -= len; + todo = notWritten; + } + else if (ETEST(errno) +#ifdef SUNSYSV /* check for another brain-damaged OS bug */ + || (errno == 0) +#endif +#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ + || ((errno == EMSGSIZE) && (todo == 1)) +#endif + ) + { + /* If we've arrived here, then the client is stuffed to the gills + and not ready to accept more. Make a note of it and buffer + the rest. */ + FD_SET(connection, &ClientsWriteBlocked); + AnyClientsWriteBlocked = TRUE; + + if (written < oco->count) + { + if (written > 0) + { + oco->count -= written; + memmove((char *)oco->buf, + (char *)oco->buf + written, + oco->count); + written = 0; + } + } + else + { + written -= oco->count; + oco->count = 0; + } + + if (notWritten > oco->size) + { + unsigned char *obuf; + + obuf = (unsigned char *)realloc(oco->buf, + notWritten + BUFSIZE); + if (!obuf) + { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + oc->trans_conn = NULL; + MarkClientException(who); + oco->count = 0; + return(-1); + } + oco->size = notWritten + BUFSIZE; + oco->buf = obuf; + } + + /* If the amount written extended into the padBuffer, then the + difference "extraCount - written" may be less than 0 */ + if ((len = extraCount - written) > 0) + memmove ((char *)oco->buf + oco->count, + extraBuf + written, + len); + + oco->count = notWritten; /* this will include the pad */ + /* return only the amount explicitly requested */ + return extraCount; + } +#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ + else if (errno == EMSGSIZE) + { + todo >>= 1; + } +#endif + else + { + if (oc->trans_conn) + { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + oc->trans_conn = NULL; + } + MarkClientException(who); + oco->count = 0; + return(-1); + } + } + + /* everything was flushed out */ + oco->count = 0; + /* check to see if this client was write blocked */ + if (AnyClientsWriteBlocked) + { + FD_CLR(oc->fd, &ClientsWriteBlocked); + if (! XFD_ANYSET(&ClientsWriteBlocked)) + AnyClientsWriteBlocked = FALSE; + } + if (oco->size > BUFWATERMARK) + { + free(oco->buf); + free(oco); + } + else + { + oco->next = FreeOutputs; + FreeOutputs = oco; + } + oc->output = (ConnectionOutputPtr)NULL; + return extraCount; /* return only the amount explicitly requested */ +} + +static ConnectionInputPtr +AllocateInputBuffer(void) +{ + ConnectionInputPtr oci; + + oci = malloc(sizeof(ConnectionInput)); + if (!oci) + return NULL; + oci->buffer = malloc(BUFSIZE); + if (!oci->buffer) + { + free(oci); + return NULL; + } + oci->size = BUFSIZE; + oci->bufptr = oci->buffer; + oci->bufcnt = 0; + oci->lenLastReq = 0; + return oci; +} + +static ConnectionOutputPtr +AllocateOutputBuffer(void) +{ + ConnectionOutputPtr oco; + + oco = malloc(sizeof(ConnectionOutput)); + if (!oco) + return NULL; + oco->buf = calloc(1, BUFSIZE); + if (!oco->buf) + { + free(oco); + return NULL; + } + oco->size = BUFSIZE; + oco->count = 0; + return oco; +} + +void +FreeOsBuffers(OsCommPtr oc) +{ + ConnectionInputPtr oci; + ConnectionOutputPtr oco; + + if (AvailableInput == oc) + AvailableInput = (OsCommPtr)NULL; + if ((oci = oc->input)) + { + if (FreeInputs) + { + free(oci->buffer); + free(oci); + } + else + { + FreeInputs = oci; + oci->next = (ConnectionInputPtr)NULL; + oci->bufptr = oci->buffer; + oci->bufcnt = 0; + oci->lenLastReq = 0; + } + } + if ((oco = oc->output)) + { + if (FreeOutputs) + { + free(oco->buf); + free(oco); + } + else + { + FreeOutputs = oco; + oco->next = (ConnectionOutputPtr)NULL; + oco->count = 0; + } + } +} + +void +ResetOsBuffers(void) +{ + ConnectionInputPtr oci; + ConnectionOutputPtr oco; + + while ((oci = FreeInputs)) + { + FreeInputs = oci->next; + free(oci->buffer); + free(oci); + } + while ((oco = FreeOutputs)) + { + FreeOutputs = oco->next; + free(oco->buf); + free(oco); + } +} diff --git a/xorg-server/os/log.c b/xorg-server/os/log.c index 37733158a..774f0b3cd 100644 --- a/xorg-server/os/log.c +++ b/xorg-server/os/log.c @@ -1,611 +1,610 @@ -/* - -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, -Copyright 1994 Quarterdeck Office Systems. - - 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 and -Quarterdeck not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -DIGITAL AND QUARTERDECK DISCLAIM 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. - -*/ - -/* - * Copyright (c) 1997-2003 by The XFree86 Project, Inc. - * - * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) - * and author(s) 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 copyright holder(s) and author(s). - */ - - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <X11/Xos.h> -#include <stdio.h> -#include <time.h> -#include <sys/stat.h> -#include <stdarg.h> -#include <stdlib.h> /* for malloc() */ -#include <errno.h> - -#include "input.h" -#include "site.h" -#include "opaque.h" - -#ifdef WIN32 -#include <process.h> -#define getpid(x) _getpid(x) -#endif - -#ifdef XF86BIGFONT -#include "xf86bigfontsrv.h" -#endif - -#ifdef DDXOSVERRORF -void (*OsVendorVErrorFProc)(const char *, va_list args) = NULL; -#endif - -static FILE *logFile = NULL; -static Bool logFlush = FALSE; -static Bool logSync = FALSE; -static int logVerbosity = DEFAULT_LOG_VERBOSITY; -static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY; - -/* Buffer to information logged before the log file is opened. */ -static char *saveBuffer = NULL; -static int bufferSize = 0, bufferUnused = 0, bufferPos = 0; -static Bool needBuffer = TRUE; - -#ifdef __APPLE__ -static char __crashreporter_info_buff__[4096] = {0}; -static const char *__crashreporter_info__ = &__crashreporter_info_buff__[0]; -asm (".desc ___crashreporter_info__, 0x10"); -#endif - -/* Prefix strings for log messages. */ -#ifndef X_UNKNOWN_STRING -#define X_UNKNOWN_STRING "(\?\?)" -#endif -#ifndef X_PROBE_STRING -#define X_PROBE_STRING "(--)" -#endif -#ifndef X_CONFIG_STRING -#define X_CONFIG_STRING "(**)" -#endif -#ifndef X_DEFAULT_STRING -#define X_DEFAULT_STRING "(==)" -#endif -#ifndef X_CMDLINE_STRING -#define X_CMDLINE_STRING "(++)" -#endif -#ifndef X_NOTICE_STRING -#define X_NOTICE_STRING "(!!)" -#endif -#ifndef X_ERROR_STRING -#define X_ERROR_STRING "(EE)" -#endif -#ifndef X_WARNING_STRING -#define X_WARNING_STRING "(WW)" -#endif -#ifndef X_INFO_STRING -#define X_INFO_STRING "(II)" -#endif -#ifndef X_NOT_IMPLEMENTED_STRING -#define X_NOT_IMPLEMENTED_STRING "(NI)" -#endif - -/* - * LogInit is called to start logging to a file. It is also called (with - * NULL arguments) when logging to a file is not wanted. It must always be - * called, otherwise log messages will continue to accumulate in a buffer. - * - * %s, if present in the fname or backup strings, is expanded to the display - * string. - */ - -const char * -LogInit(const char *fname, const char *backup) -{ - char *logFileName = NULL; - - if (fname && *fname) { - /* xalloc() can't be used yet. */ - logFileName = malloc(strlen(fname) + strlen(display) + 1); - if (!logFileName) - FatalError("Cannot allocate space for the log file name\n"); - sprintf(logFileName, fname, display); - - if (backup && *backup) { - struct stat buf; - - if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) { - char *suffix; - char *oldLog; - - oldLog = malloc(strlen(logFileName) + strlen(backup) + - strlen(display) + 1); - suffix = malloc(strlen(backup) + strlen(display) + 1); - if (!oldLog || !suffix) - FatalError("Cannot allocate space for the log file name\n"); - sprintf(suffix, backup, display); - sprintf(oldLog, "%s%s", logFileName, suffix); - free(suffix); - if (rename(logFileName, oldLog) == -1) { - FatalError("Cannot move old log file \"%s\" to \"%s\"\n", - logFileName, oldLog); - } - free(oldLog); - } - } - if ((logFile = fopen(logFileName, "w")) == NULL) - FatalError("Cannot open log file \"%s\"\n", logFileName); - setvbuf(logFile, NULL, _IONBF, 0); - - /* Flush saved log information. */ - if (saveBuffer && bufferSize > 0) { - fwrite(saveBuffer, bufferPos, 1, logFile); - fflush(logFile); -#ifndef WIN32 - fsync(fileno(logFile)); -#endif - } - } - - /* - * Unconditionally free the buffer, and flag that the buffer is no longer - * needed. - */ - if (saveBuffer && bufferSize > 0) { - free(saveBuffer); /* Must be free(), not xfree() */ - saveBuffer = NULL; - bufferSize = 0; - } - needBuffer = FALSE; - - return logFileName; -} - -void -LogClose(void) -{ - if (logFile) { - fclose(logFile); - logFile = NULL; - } -} - -Bool -LogSetParameter(LogParameter param, int value) -{ - switch (param) { - case XLOG_FLUSH: - logFlush = value ? TRUE : FALSE; - return TRUE; - case XLOG_SYNC: - logSync = value ? TRUE : FALSE; - return TRUE; - case XLOG_VERBOSITY: - logVerbosity = value; - return TRUE; - case XLOG_FILE_VERBOSITY: - logFileVerbosity = value; - return TRUE; - default: - return FALSE; - } -} - -/* This function does the actual log message writes. */ - -void -LogVWrite(int verb, const char *f, va_list args) -{ - static char tmpBuffer[1024]; - int len = 0; - static Bool newline = TRUE; - - if (newline) { - sprintf(tmpBuffer, "[%10.3f] ", GetTimeInMillis() / 1000.0); - len = strlen(tmpBuffer); - if (logFile) - fwrite(tmpBuffer, len, 1, logFile); - } - - /* - * Since a va_list can only be processed once, write the string to a - * buffer, and then write the buffer out to the appropriate output - * stream(s). - */ - if (verb < 0 || logFileVerbosity >= verb || logVerbosity >= verb) { - vsnprintf(tmpBuffer, sizeof(tmpBuffer), f, args); - len = strlen(tmpBuffer); - } - newline = (tmpBuffer[len-1] == '\n'); - if ((verb < 0 || logVerbosity >= verb) && len > 0) - fwrite(tmpBuffer, len, 1, stderr); - if ((verb < 0 || logFileVerbosity >= verb) && len > 0) { - if (logFile) { - fwrite(tmpBuffer, len, 1, logFile); - if (logFlush) { - fflush(logFile); -#ifndef WIN32 - if (logSync) - fsync(fileno(logFile)); -#endif - } - } else if (needBuffer) { - /* - * Note, this code is used before OsInit() has been called, so - * xalloc() and friends can't be used. - */ - if (len > bufferUnused) { - bufferSize += 1024; - bufferUnused += 1024; - if (saveBuffer) - saveBuffer = realloc(saveBuffer, bufferSize); - else - saveBuffer = malloc(bufferSize); - if (!saveBuffer) - FatalError("realloc() failed while saving log messages\n"); - } - bufferUnused -= len; - memcpy(saveBuffer + bufferPos, tmpBuffer, len); - bufferPos += len; - } - } -} - -void -LogWrite(int verb, const char *f, ...) -{ - va_list args; - - va_start(args, f); - LogVWrite(verb, f, args); - va_end(args); -} - -void -LogVMessageVerb(MessageType type, int verb, const char *format, va_list args) -{ - const char *s = X_UNKNOWN_STRING; - char tmpBuf[1024]; - - /* Ignore verbosity for X_ERROR */ - if (logVerbosity >= verb || logFileVerbosity >= verb || type == X_ERROR) { - switch (type) { - case X_PROBED: - s = X_PROBE_STRING; - break; - case X_CONFIG: - s = X_CONFIG_STRING; - break; - case X_DEFAULT: - s = X_DEFAULT_STRING; - break; - case X_CMDLINE: - s = X_CMDLINE_STRING; - break; - case X_NOTICE: - s = X_NOTICE_STRING; - break; - case X_ERROR: - s = X_ERROR_STRING; - if (verb > 0) - verb = 0; - break; - case X_WARNING: - s = X_WARNING_STRING; - break; - case X_INFO: - s = X_INFO_STRING; - break; - case X_NOT_IMPLEMENTED: - s = X_NOT_IMPLEMENTED_STRING; - break; - case X_UNKNOWN: - s = X_UNKNOWN_STRING; - break; - case X_NONE: - s = NULL; - break; - } - - /* if s is not NULL we need a space before format */ - snprintf(tmpBuf, sizeof(tmpBuf), "%s%s%s", s ? s : "", - s ? " " : "", - format); - LogVWrite(verb, tmpBuf, args); - } -} - -/* Log message with verbosity level specified. */ -void -LogMessageVerb(MessageType type, int verb, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - LogVMessageVerb(type, verb, format, ap); - va_end(ap); -} - -/* Log a message with the standard verbosity level of 1. */ -void -LogMessage(MessageType type, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - LogVMessageVerb(type, 1, format, ap); - va_end(ap); -} - -#ifdef __GNUC__ -void AbortServer(void) __attribute__((noreturn)); -#endif - -void -AbortServer(void) -{ -#ifdef XF86BIGFONT - XF86BigfontCleanup(); -#endif - CloseWellKnownConnections(); - OsCleanup(TRUE); - CloseDownDevices(); - AbortDDX(); - fflush(stderr); - if (CoreDump) - OsAbort(); - exit (1); -} - -#define AUDIT_PREFIX "AUDIT: %s: %ld: " -#ifndef AUDIT_TIMEOUT -#define AUDIT_TIMEOUT ((CARD32)(120 * 1000)) /* 2 mn */ -#endif - -static int nrepeat = 0; -static int oldlen = -1; -static OsTimerPtr auditTimer = NULL; - -void -FreeAuditTimer(void) -{ - if (auditTimer != NULL) { - /* Force output of pending messages */ - TimerForce(auditTimer); - TimerFree(auditTimer); - auditTimer = NULL; - } -} - -static char * -AuditPrefix(void) -{ - time_t tm; - char *autime, *s; - char *tmpBuf; - int len; - - time(&tm); - autime = ctime(&tm); - if ((s = strchr(autime, '\n'))) - *s = '\0'; - len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1; - tmpBuf = malloc(len); - if (!tmpBuf) - return NULL; - snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long)getpid()); - return tmpBuf; -} - -void -AuditF(const char * f, ...) -{ - va_list args; - - va_start(args, f); - - VAuditF(f, args); - va_end(args); -} - -static CARD32 -AuditFlush(OsTimerPtr timer, CARD32 now, pointer arg) -{ - char *prefix; - - if (nrepeat > 0) { - prefix = AuditPrefix(); - ErrorF("%slast message repeated %d times\n", - prefix != NULL ? prefix : "", nrepeat); - nrepeat = 0; - if (prefix != NULL) - free(prefix); - return AUDIT_TIMEOUT; - } else { - /* if the timer expires without anything to print, flush the message */ - oldlen = -1; - return 0; - } -} - -void -VAuditF(const char *f, va_list args) -{ - char *prefix; - char buf[1024]; - int len; - static char oldbuf[1024]; - - prefix = AuditPrefix(); - len = vsnprintf(buf, sizeof(buf), f, args); - - if (len == oldlen && strcmp(buf, oldbuf) == 0) { - /* Message already seen */ - nrepeat++; - } else { - /* new message */ - if (auditTimer != NULL) - TimerForce(auditTimer); - ErrorF("%s%s", prefix != NULL ? prefix : "", buf); - strlcpy(oldbuf, buf, sizeof(oldbuf)); - oldlen = len; - nrepeat = 0; - auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL); - } - if (prefix != NULL) - free(prefix); -} - -void -FatalError(const char *f, ...) -{ - va_list args; - static Bool beenhere = FALSE; - - if (beenhere) - ErrorF("\nFatalError re-entered, aborting\n"); - else - ErrorF("\nFatal server error:\n"); - - va_start(args, f); -#ifdef __APPLE__ - (void)vsnprintf(__crashreporter_info_buff__, sizeof(__crashreporter_info_buff__), f, args); -#endif - VErrorF(f, args); - va_end(args); - ErrorF("\n"); - if (!beenhere) - OsVendorFatalError(); - if (!beenhere) { - beenhere = TRUE; - AbortServer(); - } else - OsAbort(); - /*NOTREACHED*/ -} - -void -VErrorF(const char *f, va_list args) -{ -#ifdef DDXOSVERRORF - if (OsVendorVErrorFProc) - OsVendorVErrorFProc(f, args); - else - LogVWrite(-1, f, args); -#else - LogVWrite(-1, f, args); -#endif -} - -void -ErrorF(const char * f, ...) -{ - va_list args; - - va_start(args, f); - VErrorF(f, args); - va_end(args); -} - -/* A perror() workalike. */ - -void -Error(char *str) -{ - char *err = NULL; - int saveErrno = errno; - - if (str) { - err = malloc(strlen(strerror(saveErrno)) + strlen(str) + 2 + 1); - if (!err) - return; - sprintf(err, "%s: ", str); - strcat(err, strerror(saveErrno)); - LogWrite(-1, "%s", err); - free(err); - } else - LogWrite(-1, "%s", strerror(saveErrno)); -} - -void -LogPrintMarkers(void) -{ - /* Show what the message marker symbols mean. */ - LogWrite(0, "Markers: "); - LogMessageVerb(X_PROBED, 0, "probed, "); - LogMessageVerb(X_CONFIG, 0, "from config file, "); - LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t"); - LogMessageVerb(X_CMDLINE, 0, "from command line, "); - LogMessageVerb(X_NOTICE, 0, "notice, "); - LogMessageVerb(X_INFO, 0, "informational,\n\t"); - LogMessageVerb(X_WARNING, 0, "warning, "); - LogMessageVerb(X_ERROR, 0, "error, "); - LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, "); - LogMessageVerb(X_UNKNOWN, 0, "unknown.\n"); -} - +/* + +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, +Copyright 1994 Quarterdeck Office Systems. + + 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 and +Quarterdeck not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +DIGITAL AND QUARTERDECK DISCLAIM 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. + +*/ + +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/Xos.h> +#include <stdio.h> +#include <time.h> +#include <sys/stat.h> +#include <stdarg.h> +#include <stdlib.h> /* for malloc() */ +#include <errno.h> + +#include "input.h" +#include "site.h" +#include "opaque.h" + +#ifdef WIN32 +#include <process.h> +#define getpid(x) _getpid(x) +#endif + +#ifdef XF86BIGFONT +#include "xf86bigfontsrv.h" +#endif + +#ifdef DDXOSVERRORF +void (*OsVendorVErrorFProc)(const char *, va_list args) = NULL; +#endif + +static FILE *logFile = NULL; +static Bool logFlush = FALSE; +static Bool logSync = FALSE; +static int logVerbosity = DEFAULT_LOG_VERBOSITY; +static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY; + +/* Buffer to information logged before the log file is opened. */ +static char *saveBuffer = NULL; +static int bufferSize = 0, bufferUnused = 0, bufferPos = 0; +static Bool needBuffer = TRUE; + +#ifdef __APPLE__ +static char __crashreporter_info_buff__[4096] = {0}; +static const char *__crashreporter_info__ = &__crashreporter_info_buff__[0]; +asm (".desc ___crashreporter_info__, 0x10"); +#endif + +/* Prefix strings for log messages. */ +#ifndef X_UNKNOWN_STRING +#define X_UNKNOWN_STRING "(\?\?)" +#endif +#ifndef X_PROBE_STRING +#define X_PROBE_STRING "(--)" +#endif +#ifndef X_CONFIG_STRING +#define X_CONFIG_STRING "(**)" +#endif +#ifndef X_DEFAULT_STRING +#define X_DEFAULT_STRING "(==)" +#endif +#ifndef X_CMDLINE_STRING +#define X_CMDLINE_STRING "(++)" +#endif +#ifndef X_NOTICE_STRING +#define X_NOTICE_STRING "(!!)" +#endif +#ifndef X_ERROR_STRING +#define X_ERROR_STRING "(EE)" +#endif +#ifndef X_WARNING_STRING +#define X_WARNING_STRING "(WW)" +#endif +#ifndef X_INFO_STRING +#define X_INFO_STRING "(II)" +#endif +#ifndef X_NOT_IMPLEMENTED_STRING +#define X_NOT_IMPLEMENTED_STRING "(NI)" +#endif + +/* + * LogInit is called to start logging to a file. It is also called (with + * NULL arguments) when logging to a file is not wanted. It must always be + * called, otherwise log messages will continue to accumulate in a buffer. + * + * %s, if present in the fname or backup strings, is expanded to the display + * string. + */ + +const char * +LogInit(const char *fname, const char *backup) +{ + char *logFileName = NULL; + + if (fname && *fname) { + /* malloc() can't be used yet. */ + logFileName = malloc(strlen(fname) + strlen(display) + 1); + if (!logFileName) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(logFileName, fname, display); + + if (backup && *backup) { + struct stat buf; + + if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) { + char *suffix; + char *oldLog; + + oldLog = malloc(strlen(logFileName) + strlen(backup) + + strlen(display) + 1); + suffix = malloc(strlen(backup) + strlen(display) + 1); + if (!oldLog || !suffix) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(suffix, backup, display); + sprintf(oldLog, "%s%s", logFileName, suffix); + free(suffix); + if (rename(logFileName, oldLog) == -1) { + FatalError("Cannot move old log file \"%s\" to \"%s\"\n", + logFileName, oldLog); + } + free(oldLog); + } + } + if ((logFile = fopen(logFileName, "w")) == NULL) + FatalError("Cannot open log file \"%s\"\n", logFileName); + setvbuf(logFile, NULL, _IONBF, 0); + + /* Flush saved log information. */ + if (saveBuffer && bufferSize > 0) { + fwrite(saveBuffer, bufferPos, 1, logFile); + fflush(logFile); +#ifndef WIN32 + fsync(fileno(logFile)); +#endif + } + } + + /* + * Unconditionally free the buffer, and flag that the buffer is no longer + * needed. + */ + if (saveBuffer && bufferSize > 0) { + free(saveBuffer); /* Must be free(), not free() */ + saveBuffer = NULL; + bufferSize = 0; + } + needBuffer = FALSE; + + return logFileName; +} + +void +LogClose(void) +{ + if (logFile) { + fclose(logFile); + logFile = NULL; + } +} + +Bool +LogSetParameter(LogParameter param, int value) +{ + switch (param) { + case XLOG_FLUSH: + logFlush = value ? TRUE : FALSE; + return TRUE; + case XLOG_SYNC: + logSync = value ? TRUE : FALSE; + return TRUE; + case XLOG_VERBOSITY: + logVerbosity = value; + return TRUE; + case XLOG_FILE_VERBOSITY: + logFileVerbosity = value; + return TRUE; + default: + return FALSE; + } +} + +/* This function does the actual log message writes. */ + +void +LogVWrite(int verb, const char *f, va_list args) +{ + static char tmpBuffer[1024]; + int len = 0; + static Bool newline = TRUE; + + if (newline) { + sprintf(tmpBuffer, "[%10.3f] ", GetTimeInMillis() / 1000.0); + len = strlen(tmpBuffer); + if (logFile) + fwrite(tmpBuffer, len, 1, logFile); + } + + /* + * Since a va_list can only be processed once, write the string to a + * buffer, and then write the buffer out to the appropriate output + * stream(s). + */ + if (verb < 0 || logFileVerbosity >= verb || logVerbosity >= verb) { + vsnprintf(tmpBuffer, sizeof(tmpBuffer), f, args); + len = strlen(tmpBuffer); + } + newline = (tmpBuffer[len-1] == '\n'); + if ((verb < 0 || logVerbosity >= verb) && len > 0) + fwrite(tmpBuffer, len, 1, stderr); + if ((verb < 0 || logFileVerbosity >= verb) && len > 0) { + if (logFile) { + fwrite(tmpBuffer, len, 1, logFile); + if (logFlush) { + fflush(logFile); +#ifndef WIN32 + if (logSync) + fsync(fileno(logFile)); +#endif + } + } else if (needBuffer) { + /* + * Note, this code is used before OsInit() has been called, so + * malloc() and friends can't be used. + */ + if (len > bufferUnused) { + bufferSize += 1024; + bufferUnused += 1024; + if (saveBuffer) + saveBuffer = realloc(saveBuffer, bufferSize); + else + saveBuffer = malloc(bufferSize); + if (!saveBuffer) + FatalError("realloc() failed while saving log messages\n"); + } + bufferUnused -= len; + memcpy(saveBuffer + bufferPos, tmpBuffer, len); + bufferPos += len; + } + } +} + +void +LogWrite(int verb, const char *f, ...) +{ + va_list args; + + va_start(args, f); + LogVWrite(verb, f, args); + va_end(args); +} + +void +LogVMessageVerb(MessageType type, int verb, const char *format, va_list args) +{ + const char *s = X_UNKNOWN_STRING; + char tmpBuf[1024]; + + /* Ignore verbosity for X_ERROR */ + if (logVerbosity >= verb || logFileVerbosity >= verb || type == X_ERROR) { + switch (type) { + case X_PROBED: + s = X_PROBE_STRING; + break; + case X_CONFIG: + s = X_CONFIG_STRING; + break; + case X_DEFAULT: + s = X_DEFAULT_STRING; + break; + case X_CMDLINE: + s = X_CMDLINE_STRING; + break; + case X_NOTICE: + s = X_NOTICE_STRING; + break; + case X_ERROR: + s = X_ERROR_STRING; + if (verb > 0) + verb = 0; + break; + case X_WARNING: + s = X_WARNING_STRING; + break; + case X_INFO: + s = X_INFO_STRING; + break; + case X_NOT_IMPLEMENTED: + s = X_NOT_IMPLEMENTED_STRING; + break; + case X_UNKNOWN: + s = X_UNKNOWN_STRING; + break; + case X_NONE: + s = NULL; + break; + } + + /* if s is not NULL we need a space before format */ + snprintf(tmpBuf, sizeof(tmpBuf), "%s%s%s", s ? s : "", + s ? " " : "", + format); + LogVWrite(verb, tmpBuf, args); + } +} + +/* Log message with verbosity level specified. */ +void +LogMessageVerb(MessageType type, int verb, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + LogVMessageVerb(type, verb, format, ap); + va_end(ap); +} + +/* Log a message with the standard verbosity level of 1. */ +void +LogMessage(MessageType type, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + LogVMessageVerb(type, 1, format, ap); + va_end(ap); +} + +void +AbortServer(void) _X_NORETURN; + +void +AbortServer(void) +{ +#ifdef XF86BIGFONT + XF86BigfontCleanup(); +#endif + CloseWellKnownConnections(); + OsCleanup(TRUE); + CloseDownDevices(); + AbortDDX(); + fflush(stderr); + if (CoreDump) + OsAbort(); + exit (1); +} + +#define AUDIT_PREFIX "AUDIT: %s: %ld: " +#ifndef AUDIT_TIMEOUT +#define AUDIT_TIMEOUT ((CARD32)(120 * 1000)) /* 2 mn */ +#endif + +static int nrepeat = 0; +static int oldlen = -1; +static OsTimerPtr auditTimer = NULL; + +void +FreeAuditTimer(void) +{ + if (auditTimer != NULL) { + /* Force output of pending messages */ + TimerForce(auditTimer); + TimerFree(auditTimer); + auditTimer = NULL; + } +} + +static char * +AuditPrefix(void) +{ + time_t tm; + char *autime, *s; + char *tmpBuf; + int len; + + time(&tm); + autime = ctime(&tm); + if ((s = strchr(autime, '\n'))) + *s = '\0'; + len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1; + tmpBuf = malloc(len); + if (!tmpBuf) + return NULL; + snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long)getpid()); + return tmpBuf; +} + +void +AuditF(const char * f, ...) +{ + va_list args; + + va_start(args, f); + + VAuditF(f, args); + va_end(args); +} + +static CARD32 +AuditFlush(OsTimerPtr timer, CARD32 now, pointer arg) +{ + char *prefix; + + if (nrepeat > 0) { + prefix = AuditPrefix(); + ErrorF("%slast message repeated %d times\n", + prefix != NULL ? prefix : "", nrepeat); + nrepeat = 0; + if (prefix != NULL) + free(prefix); + return AUDIT_TIMEOUT; + } else { + /* if the timer expires without anything to print, flush the message */ + oldlen = -1; + return 0; + } +} + +void +VAuditF(const char *f, va_list args) +{ + char *prefix; + char buf[1024]; + int len; + static char oldbuf[1024]; + + prefix = AuditPrefix(); + len = vsnprintf(buf, sizeof(buf), f, args); + + if (len == oldlen && strcmp(buf, oldbuf) == 0) { + /* Message already seen */ + nrepeat++; + } else { + /* new message */ + if (auditTimer != NULL) + TimerForce(auditTimer); + ErrorF("%s%s", prefix != NULL ? prefix : "", buf); + strlcpy(oldbuf, buf, sizeof(oldbuf)); + oldlen = len; + nrepeat = 0; + auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL); + } + if (prefix != NULL) + free(prefix); +} + +void +FatalError(const char *f, ...) +{ + va_list args; + static Bool beenhere = FALSE; + + if (beenhere) + ErrorF("\nFatalError re-entered, aborting\n"); + else + ErrorF("\nFatal server error:\n"); + + va_start(args, f); +#ifdef __APPLE__ + (void)vsnprintf(__crashreporter_info_buff__, sizeof(__crashreporter_info_buff__), f, args); +#endif + VErrorF(f, args); + va_end(args); + ErrorF("\n"); + if (!beenhere) + OsVendorFatalError(); + if (!beenhere) { + beenhere = TRUE; + AbortServer(); + } else + OsAbort(); + /*NOTREACHED*/ +} + +void +VErrorF(const char *f, va_list args) +{ +#ifdef DDXOSVERRORF + if (OsVendorVErrorFProc) + OsVendorVErrorFProc(f, args); + else + LogVWrite(-1, f, args); +#else + LogVWrite(-1, f, args); +#endif +} + +void +ErrorF(const char * f, ...) +{ + va_list args; + + va_start(args, f); + VErrorF(f, args); + va_end(args); +} + +/* A perror() workalike. */ + +void +Error(char *str) +{ + char *err = NULL; + int saveErrno = errno; + + if (str) { + err = malloc(strlen(strerror(saveErrno)) + strlen(str) + 2 + 1); + if (!err) + return; + sprintf(err, "%s: ", str); + strcat(err, strerror(saveErrno)); + LogWrite(-1, "%s", err); + free(err); + } else + LogWrite(-1, "%s", strerror(saveErrno)); +} + +void +LogPrintMarkers(void) +{ + /* Show what the message marker symbols mean. */ + LogWrite(0, "Markers: "); + LogMessageVerb(X_PROBED, 0, "probed, "); + LogMessageVerb(X_CONFIG, 0, "from config file, "); + LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t"); + LogMessageVerb(X_CMDLINE, 0, "from command line, "); + LogMessageVerb(X_NOTICE, 0, "notice, "); + LogMessageVerb(X_INFO, 0, "informational,\n\t"); + LogMessageVerb(X_WARNING, 0, "warning, "); + LogMessageVerb(X_ERROR, 0, "error, "); + LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, "); + LogMessageVerb(X_UNKNOWN, 0, "unknown.\n"); +} + diff --git a/xorg-server/os/mitauth.c b/xorg-server/os/mitauth.c index 5baf552bc..8dfb42be6 100644 --- a/xorg-server/os/mitauth.c +++ b/xorg-server/os/mitauth.c @@ -55,12 +55,12 @@ MitAddCookie ( { struct auth *new; - new = xalloc (sizeof (struct auth)); + new = malloc(sizeof (struct auth)); if (!new) return 0; - new->data = xalloc ((unsigned) data_length); + new->data = malloc((unsigned) data_length); if (!new->data) { - xfree(new); + free(new); return 0; } new->next = mit_auth; @@ -96,8 +96,8 @@ MitResetCookie (void) for (auth = mit_auth; auth; auth=next) { next = auth->next; - xfree (auth->data); - xfree (auth); + free(auth->data); + free(auth); } mit_auth = 0; return 0; @@ -152,8 +152,8 @@ MitRemoveCookie ( prev->next = auth->next; else mit_auth = auth->next; - xfree (auth->data); - xfree (auth); + free(auth->data); + free(auth); return 1; } } diff --git a/xorg-server/os/osinit.c b/xorg-server/os/osinit.c index e8fcd4540..6d61d6200 100644 --- a/xorg-server/os/osinit.c +++ b/xorg-server/os/osinit.c @@ -1,327 +1,326 @@ -/*********************************************************** - -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 <dix-config.h> -#endif - -#include <stdio.h> -#include <X11/X.h> -#include "os.h" -#include "osdep.h" -#include <X11/Xos.h> -#include <signal.h> -#include <errno.h> -#ifdef HAVE_DLFCN_H -# include <dlfcn.h> -#endif -#ifdef HAVE_BACKTRACE -#include <execinfo.h> -#endif - - -#include "dixstruct.h" - -#ifndef PATH_MAX -#ifdef MAXPATHLEN -#define PATH_MAX MAXPATHLEN -#else -#define PATH_MAX 1024 -#endif -#endif - -#if defined(__SCO__) -#include <sys/wait.h> -#endif - -#if !defined(SYSV) && !defined(WIN32) -#include <sys/resource.h> -#endif - -#ifndef ADMPATH -#define ADMPATH "/usr/adm/X%smsgs" -#endif - -extern char *display; -#ifdef RLIMIT_DATA -int limitDataSpace = -1; -#endif -#ifdef RLIMIT_STACK -int limitStackSpace = -1; -#endif -#ifdef RLIMIT_NOFILE -int limitNoFile = -1; -#endif - -static OsSigWrapperPtr OsSigWrapper = NULL; - -OsSigWrapperPtr -OsRegisterSigWrapper(OsSigWrapperPtr newSigWrapper) -{ - OsSigWrapperPtr oldSigWrapper = OsSigWrapper; - - OsSigWrapper = newSigWrapper; - - return oldSigWrapper; -} - -/* - * OsSigHandler -- - * Catch unexpected signals and exit or continue cleanly. - */ -static void -#ifdef SA_SIGINFO -OsSigHandler(int signo, siginfo_t *sip, void *unused) -#else -OsSigHandler(int signo) -#endif -{ -#ifdef RTLD_DI_SETSIGNAL - const char *dlerr = dlerror(); - - if (dlerr) { - LogMessage(X_ERROR, "Dynamic loader error: %s\n", dlerr); - } -#endif /* RTLD_DI_SETSIGNAL */ - - if (OsSigWrapper != NULL) { - if (OsSigWrapper(signo) == 0) { - /* ddx handled signal and wants us to continue */ - return; - } - } - - /* log, cleanup, and abort */ - xorg_backtrace(); - -#ifdef SA_SIGINFO - if (sip->si_code == SI_USER) { - ErrorF("Recieved signal %d sent by process %ld, uid %ld\n", - signo, (long) sip->si_pid, (long) sip->si_uid); - } else { - switch (signo) { - case SIGSEGV: - case SIGBUS: - case SIGILL: - case SIGFPE: - ErrorF("%s at address %p\n", strsignal(signo), sip->si_addr); - } - } -#endif - - FatalError("Caught signal %d (%s). Server aborting\n", - signo, strsignal(signo)); -} - -void -OsInit(void) -{ - static Bool been_here = FALSE; - static char* admpath = ADMPATH; - static char* devnull = "/dev/null"; - char fname[PATH_MAX]; - - if (!been_here) { - struct sigaction act, oact; - int i; - int siglist[] = { SIGSEGV, SIGQUIT, SIGILL, SIGFPE, SIGBUS, -#ifdef SIGSYS - SIGSYS, -#endif -#ifdef SIGXCPU - SIGXCPU, -#endif -#ifdef SIGXFSZ - SIGXFSZ, -#endif -#ifdef SIGEMT - SIGEMT, -#endif - 0 /* must be last */ }; - sigemptyset(&act.sa_mask); -#ifdef SA_SIGINFO - act.sa_sigaction = OsSigHandler; - act.sa_flags = SA_SIGINFO; -#else - act.sa_handler = OsSigHandler; - act.sa_flags = 0; -#endif - for (i = 0; siglist[i] != 0; i++) { - if (sigaction(siglist[i], &act, &oact)) { - ErrorF("failed to install signal handler for signal %d: %s\n", - siglist[i], strerror(errno)); - } - } -#ifdef HAVE_BACKTRACE - /* - * initialize the backtracer, since the ctor calls dlopen(), which - * calls malloc(), which isn't signal-safe. - */ - do { - void *array; - backtrace(&array, 1); - } while (0); -#endif - -#ifdef RTLD_DI_SETSIGNAL - /* Tell runtime linker to send a signal we can catch instead of SIGKILL - * for failures to load libraries/modules at runtime so we can clean up - * after ourselves. - */ - int failure_signal = SIGQUIT; - dlinfo(RTLD_SELF, RTLD_DI_SETSIGNAL, &failure_signal); -#endif - -#if !defined(__SCO__) && !defined(__CYGWIN__) && !defined(__UNIXWARE__) - fclose(stdin); - fclose(stdout); -#endif - /* - * If a write of zero bytes to stderr returns non-zero, i.e. -1, - * then writing to stderr failed, and we'll write somewhere else - * instead. (Apparently this never happens in the Real World.) - */ - if (write (2, fname, 0) == -1) - { - FILE *err; - - if (strlen (display) + strlen (admpath) + 1 < sizeof fname) - sprintf (fname, admpath, display); - else - strcpy (fname, devnull); - /* - * uses stdio to avoid os dependencies here, - * a real os would use - * open (fname, O_WRONLY|O_APPEND|O_CREAT, 0666) - */ - if (!(err = fopen (fname, "a+"))) - err = fopen (devnull, "w"); - if (err && (fileno(err) != 2)) { - dup2 (fileno (err), 2); - fclose (err); - } -#if defined(SYSV) || defined(SVR4) || defined(WIN32) || defined(__CYGWIN__) - { - static char buf[BUFSIZ]; - setvbuf (stderr, buf, _IOLBF, BUFSIZ); - } -#else - setlinebuf(stderr); -#endif - } - - if (getpgrp () == 0) - setpgid (0, 0); - -#ifdef RLIMIT_DATA - if (limitDataSpace >= 0) - { - struct rlimit rlim; - - if (!getrlimit(RLIMIT_DATA, &rlim)) - { - if ((limitDataSpace > 0) && (limitDataSpace < rlim.rlim_max)) - rlim.rlim_cur = limitDataSpace; - else - rlim.rlim_cur = rlim.rlim_max; - (void)setrlimit(RLIMIT_DATA, &rlim); - } - } -#endif -#ifdef RLIMIT_STACK - if (limitStackSpace >= 0) - { - struct rlimit rlim; - - if (!getrlimit(RLIMIT_STACK, &rlim)) - { - if ((limitStackSpace > 0) && (limitStackSpace < rlim.rlim_max)) - rlim.rlim_cur = limitStackSpace; - else - rlim.rlim_cur = rlim.rlim_max; - (void)setrlimit(RLIMIT_STACK, &rlim); - } - } -#endif -#ifdef RLIMIT_NOFILE - if (limitNoFile >= 0) - { - struct rlimit rlim; - - if (!getrlimit(RLIMIT_NOFILE, &rlim)) - { - if ((limitNoFile > 0) && (limitNoFile < rlim.rlim_max)) - rlim.rlim_cur = limitNoFile; - else - rlim.rlim_cur = rlim.rlim_max; - (void)setrlimit(RLIMIT_NOFILE, &rlim); - } - } -#endif - LockServer(); - been_here = TRUE; - } - TimerInit(); - OsVendorInit(); - /* - * No log file by default. OsVendorInit() should call LogInit() with the - * log file name if logging to a file is desired. - */ - LogInit(NULL, NULL); - if (!SmartScheduleDisable) - if (!SmartScheduleInit ()) - SmartScheduleDisable = TRUE; -} - -void -OsCleanup(Bool terminating) -{ - if (terminating) - { - UnlockServer(); - } -} +/*********************************************************** + +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 <dix-config.h> +#endif + +#include <stdio.h> +#include <X11/X.h> +#include "os.h" +#include "osdep.h" +#include <X11/Xos.h> +#include <signal.h> +#include <errno.h> +#ifdef HAVE_DLFCN_H +# include <dlfcn.h> +#endif +#ifdef HAVE_BACKTRACE +#include <execinfo.h> +#endif + + +#include "dixstruct.h" + +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + +#if defined(__SCO__) +#include <sys/wait.h> +#endif + +#if !defined(SYSV) && !defined(WIN32) +#include <sys/resource.h> +#endif + +#ifndef ADMPATH +#define ADMPATH "/usr/adm/X%smsgs" +#endif + +extern char *display; +#ifdef RLIMIT_DATA +int limitDataSpace = -1; +#endif +#ifdef RLIMIT_STACK +int limitStackSpace = -1; +#endif +#ifdef RLIMIT_NOFILE +int limitNoFile = -1; +#endif + +static OsSigWrapperPtr OsSigWrapper = NULL; + +OsSigWrapperPtr +OsRegisterSigWrapper(OsSigWrapperPtr newSigWrapper) +{ + OsSigWrapperPtr oldSigWrapper = OsSigWrapper; + + OsSigWrapper = newSigWrapper; + + return oldSigWrapper; +} + +/* + * OsSigHandler -- + * Catch unexpected signals and exit or continue cleanly. + */ +static void +#ifdef SA_SIGINFO +OsSigHandler(int signo, siginfo_t *sip, void *unused) +#else +OsSigHandler(int signo) +#endif +{ +#ifdef RTLD_DI_SETSIGNAL + const char *dlerr = dlerror(); + + if (dlerr) { + LogMessage(X_ERROR, "Dynamic loader error: %s\n", dlerr); + } +#endif /* RTLD_DI_SETSIGNAL */ + + if (OsSigWrapper != NULL) { + if (OsSigWrapper(signo) == 0) { + /* ddx handled signal and wants us to continue */ + return; + } + } + + /* log, cleanup, and abort */ + xorg_backtrace(); + +#ifdef SA_SIGINFO + if (sip->si_code == SI_USER) { + ErrorF("Recieved signal %d sent by process %ld, uid %ld\n", + signo, (long) sip->si_pid, (long) sip->si_uid); + } else { + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGILL: + case SIGFPE: + ErrorF("%s at address %p\n", strsignal(signo), sip->si_addr); + } + } +#endif + + FatalError("Caught signal %d (%s). Server aborting\n", + signo, strsignal(signo)); +} + +void +OsInit(void) +{ + static Bool been_here = FALSE; + static char* devnull = "/dev/null"; + char fname[PATH_MAX]; + + if (!been_here) { + struct sigaction act, oact; + int i; + int siglist[] = { SIGSEGV, SIGQUIT, SIGILL, SIGFPE, SIGBUS, +#ifdef SIGSYS + SIGSYS, +#endif +#ifdef SIGXCPU + SIGXCPU, +#endif +#ifdef SIGXFSZ + SIGXFSZ, +#endif +#ifdef SIGEMT + SIGEMT, +#endif + 0 /* must be last */ }; + sigemptyset(&act.sa_mask); +#ifdef SA_SIGINFO + act.sa_sigaction = OsSigHandler; + act.sa_flags = SA_SIGINFO; +#else + act.sa_handler = OsSigHandler; + act.sa_flags = 0; +#endif + for (i = 0; siglist[i] != 0; i++) { + if (sigaction(siglist[i], &act, &oact)) { + ErrorF("failed to install signal handler for signal %d: %s\n", + siglist[i], strerror(errno)); + } + } +#ifdef HAVE_BACKTRACE + /* + * initialize the backtracer, since the ctor calls dlopen(), which + * calls malloc(), which isn't signal-safe. + */ + do { + void *array; + backtrace(&array, 1); + } while (0); +#endif + +#ifdef RTLD_DI_SETSIGNAL + /* Tell runtime linker to send a signal we can catch instead of SIGKILL + * for failures to load libraries/modules at runtime so we can clean up + * after ourselves. + */ + int failure_signal = SIGQUIT; + dlinfo(RTLD_SELF, RTLD_DI_SETSIGNAL, &failure_signal); +#endif + +#if !defined(__SCO__) && !defined(__CYGWIN__) && !defined(__UNIXWARE__) + fclose(stdin); + fclose(stdout); +#endif + /* + * If a write of zero bytes to stderr returns non-zero, i.e. -1, + * then writing to stderr failed, and we'll write somewhere else + * instead. (Apparently this never happens in the Real World.) + */ + if (write (2, fname, 0) == -1) + { + FILE *err; + + if (strlen (display) + strlen (ADMPATH) + 1 < sizeof fname) + sprintf (fname, ADMPATH, display); + else + strcpy (fname, devnull); + /* + * uses stdio to avoid os dependencies here, + * a real os would use + * open (fname, O_WRONLY|O_APPEND|O_CREAT, 0666) + */ + if (!(err = fopen (fname, "a+"))) + err = fopen (devnull, "w"); + if (err && (fileno(err) != 2)) { + dup2 (fileno (err), 2); + fclose (err); + } +#if defined(SYSV) || defined(SVR4) || defined(WIN32) || defined(__CYGWIN__) + { + static char buf[BUFSIZ]; + setvbuf (stderr, buf, _IOLBF, BUFSIZ); + } +#else + setlinebuf(stderr); +#endif + } + + if (getpgrp () == 0) + setpgid (0, 0); + +#ifdef RLIMIT_DATA + if (limitDataSpace >= 0) + { + struct rlimit rlim; + + if (!getrlimit(RLIMIT_DATA, &rlim)) + { + if ((limitDataSpace > 0) && (limitDataSpace < rlim.rlim_max)) + rlim.rlim_cur = limitDataSpace; + else + rlim.rlim_cur = rlim.rlim_max; + (void)setrlimit(RLIMIT_DATA, &rlim); + } + } +#endif +#ifdef RLIMIT_STACK + if (limitStackSpace >= 0) + { + struct rlimit rlim; + + if (!getrlimit(RLIMIT_STACK, &rlim)) + { + if ((limitStackSpace > 0) && (limitStackSpace < rlim.rlim_max)) + rlim.rlim_cur = limitStackSpace; + else + rlim.rlim_cur = rlim.rlim_max; + (void)setrlimit(RLIMIT_STACK, &rlim); + } + } +#endif +#ifdef RLIMIT_NOFILE + if (limitNoFile >= 0) + { + struct rlimit rlim; + + if (!getrlimit(RLIMIT_NOFILE, &rlim)) + { + if ((limitNoFile > 0) && (limitNoFile < rlim.rlim_max)) + rlim.rlim_cur = limitNoFile; + else + rlim.rlim_cur = rlim.rlim_max; + (void)setrlimit(RLIMIT_NOFILE, &rlim); + } + } +#endif + LockServer(); + been_here = TRUE; + } + TimerInit(); + OsVendorInit(); + /* + * No log file by default. OsVendorInit() should call LogInit() with the + * log file name if logging to a file is desired. + */ + LogInit(NULL, NULL); + if (!SmartScheduleDisable) + if (!SmartScheduleInit ()) + SmartScheduleDisable = TRUE; +} + +void +OsCleanup(Bool terminating) +{ + if (terminating) + { + UnlockServer(); + } +} diff --git a/xorg-server/os/rpcauth.c b/xorg-server/os/rpcauth.c index a63304375..b40f9359a 100644 --- a/xorg-server/os/rpcauth.c +++ b/xorg-server/os/rpcauth.c @@ -66,7 +66,7 @@ authdes_ezdecode(const char *inmsg, int len) XDR xdr; SVCXPRT xprt; - temp_inmsg = xalloc(len); + temp_inmsg = malloc(len); memmove(temp_inmsg, inmsg, len); memset((char *)&msg, 0, sizeof(msg)); @@ -79,7 +79,7 @@ authdes_ezdecode(const char *inmsg, int len) why = AUTH_FAILED; xdrmem_create(&xdr, temp_inmsg, len, XDR_DECODE); - if ((r.rq_clntcred = xalloc(MAX_AUTH_BYTES)) == NULL) + if ((r.rq_clntcred = malloc(MAX_AUTH_BYTES)) == NULL) goto bad1; r.rq_xprt = &xprt; @@ -106,7 +106,7 @@ authdes_ezdecode(const char *inmsg, int len) return (((struct authdes_cred *) r.rq_clntcred)->adc_fullname.name); bad2: - xfree(r.rq_clntcred); + free(r.rq_clntcred); bad1: return ((char *)0); /* ((struct authdes_cred *) NULL); */ } diff --git a/xorg-server/os/utils.c b/xorg-server/os/utils.c index 7ab7cc3db..7f556a912 100644 --- a/xorg-server/os/utils.c +++ b/xorg-server/os/utils.c @@ -1,1957 +1,1910 @@ -/* - -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, -Copyright 1994 Quarterdeck Office Systems. - - 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 and -Quarterdeck not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -DIGITAL AND QUARTERDECK DISCLAIM 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 <dix-config.h> -#endif - -#ifdef __CYGWIN__ -#include <stdlib.h> -#include <signal.h> -/* - Sigh... We really need a prototype for this to know it is stdcall, - but #include-ing <windows.h> here is not a good idea... -*/ -__stdcall unsigned long GetTickCount(void); -#endif - -#if defined(WIN32) && !defined(__CYGWIN__) -#include <X11/Xwinsock.h> -#endif -#include <X11/Xos.h> -#include <stdio.h> -#include <time.h> -#if !defined(WIN32) || !defined(__MINGW32__) -#include <sys/time.h> -#include <sys/resource.h> -#endif -#include "misc.h" -#include <X11/X.h> -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include <X11/Xtrans/Xtrans.h> -#include "input.h" -#include "dixfont.h" -#include "osdep.h" -#include "extension.h" -#ifdef X_POSIX_C_SOURCE -#define _POSIX_C_SOURCE X_POSIX_C_SOURCE -#include <signal.h> -#undef _POSIX_C_SOURCE -#else -#if defined(_POSIX_SOURCE) -#include <signal.h> -#else -#define _POSIX_SOURCE -#include <signal.h> -#undef _POSIX_SOURCE -#endif -#endif -#ifndef WIN32 -#include <sys/wait.h> -#endif -#if !defined(SYSV) && !defined(WIN32) -#include <sys/resource.h> -#endif -#include <sys/stat.h> -#include <ctype.h> /* for isspace */ -#include <stdarg.h> - -#include <stdlib.h> /* for malloc() */ - -#if defined(TCPCONN) || defined(STREAMSCONN) -# ifndef WIN32 -# include <netdb.h> -# endif -#endif - -#include "opaque.h" - -#include "dixstruct.h" - -#include "xkbsrv.h" - -#include "picture.h" - -Bool noTestExtensions; -#ifdef COMPOSITE -Bool noCompositeExtension = FALSE; -#endif - -#ifdef DAMAGE -Bool noDamageExtension = FALSE; -#endif -#ifdef DBE -Bool noDbeExtension = FALSE; -#endif -#ifdef DPMSExtension -Bool noDPMSExtension = FALSE; -#endif -#ifdef GLXEXT -Bool noGlxExtension = FALSE; -Bool noGlxVisualInit = FALSE; -#endif -#ifdef SCREENSAVER -Bool noScreenSaverExtension = FALSE; -#endif -#ifdef MITSHM -Bool noMITShmExtension = FALSE; -#endif -#ifdef RANDR -Bool noRRExtension = FALSE; -#endif -Bool noRenderExtension = FALSE; -#ifdef XCSECURITY -Bool noSecurityExtension = FALSE; -#endif -#ifdef RES -Bool noResExtension = FALSE; -#endif -#ifdef XF86BIGFONT -Bool noXFree86BigfontExtension = FALSE; -#endif -#ifdef XFreeXDGA -Bool noXFree86DGAExtension = FALSE; -#endif -#ifdef XF86DRI -Bool noXFree86DRIExtension = FALSE; -#endif -#ifdef XF86VIDMODE -Bool noXFree86VidModeExtension = FALSE; -#endif -#ifdef XFIXES -Bool noXFixesExtension = FALSE; -#endif -#ifdef PANORAMIX -/* Xinerama is disabled by default unless enabled via +xinerama */ -Bool noPanoramiXExtension = TRUE; -#endif -#ifdef XSELINUX -Bool noSELinuxExtension = FALSE; -int selinuxEnforcingState = SELINUX_MODE_DEFAULT; -#endif -#ifdef XV -Bool noXvExtension = FALSE; -#endif -#ifdef DRI2 -Bool noDRI2Extension = FALSE; -#endif - -Bool noGEExtension = FALSE; - -#define X_INCLUDE_NETDB_H -#include <X11/Xos_r.h> - -#include <errno.h> - -Bool CoreDump; - -#ifdef PANORAMIX -Bool PanoramiXExtensionDisabledHack = FALSE; -#endif - -int auditTrailLevel = 1; - -#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) -#define HAS_SAVED_IDS_AND_SETEUID -#endif - -static char *dev_tty_from_init = NULL; /* since we need to parse it anyway */ - -OsSigHandlerPtr -OsSignal(int sig, OsSigHandlerPtr handler) -{ - struct sigaction act, oact; - - sigemptyset(&act.sa_mask); - if (handler != SIG_IGN) - sigaddset(&act.sa_mask, sig); - act.sa_flags = 0; - act.sa_handler = handler; - if (sigaction(sig, &act, &oact)) - perror("sigaction"); - return oact.sa_handler; -} - -/* - * Explicit support for a server lock file like the ones used for UUCP. - * For architectures with virtual terminals that can run more than one - * server at a time. This keeps the servers from stomping on each other - * if the user forgets to give them different display numbers. - */ -#define LOCK_DIR "/tmp" -#define LOCK_TMP_PREFIX "/.tX" -#define LOCK_PREFIX "/.X" -#define LOCK_SUFFIX "-lock" - -#ifndef PATH_MAX -#include <sys/param.h> -#ifndef PATH_MAX -#ifdef MAXPATHLEN -#define PATH_MAX MAXPATHLEN -#else -#define PATH_MAX 1024 -#endif -#endif -#endif - -static Bool StillLocking = FALSE; -static char LockFile[PATH_MAX]; -static Bool nolock = FALSE; - -/* - * LockServer -- - * Check if the server lock file exists. If so, check if the PID - * contained inside is valid. If so, then die. Otherwise, create - * the lock file containing the PID. - */ -void -LockServer(void) -{ - char tmp[PATH_MAX], pid_str[12]; - int lfd, i, haslock, l_pid, t; - char *tmppath = NULL; - int len; - char port[20]; - - if (nolock) return; - /* - * Path names - */ - tmppath = LOCK_DIR; - - sprintf(port, "%d", atoi(display)); - len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : - strlen(LOCK_TMP_PREFIX); - len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; - if (len > sizeof(LockFile)) - FatalError("Display name `%s' is too long\n", port); - (void)sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); - (void)sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); - - /* - * Create a temporary file containing our PID. Attempt three times - * to create the file. - */ - StillLocking = TRUE; - i = 0; - do { - i++; - lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); - if (lfd < 0) - sleep(2); - else - break; - } while (i < 3); - if (lfd < 0) { - unlink(tmp); - i = 0; - do { - i++; - lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); - if (lfd < 0) - sleep(2); - else - break; - } while (i < 3); - } - if (lfd < 0) - FatalError("Could not create lock file in %s\n", tmp); - (void) sprintf(pid_str, "%10ld\n", (long)getpid()); - (void) write(lfd, pid_str, 11); - (void) chmod(tmp, 0444); - (void) close(lfd); - - /* - * OK. Now the tmp file exists. Try three times to move it in place - * for the lock. - */ - i = 0; - haslock = 0; - while ((!haslock) && (i++ < 3)) { - haslock = (link(tmp,LockFile) == 0); - if (haslock) { - /* - * We're done. - */ - break; - } - else { - /* - * Read the pid from the existing file - */ - lfd = open(LockFile, O_RDONLY); - if (lfd < 0) { - unlink(tmp); - FatalError("Can't read lock file %s\n", LockFile); - } - pid_str[0] = '\0'; - if (read(lfd, pid_str, 11) != 11) { - /* - * Bogus lock file. - */ - unlink(LockFile); - close(lfd); - continue; - } - pid_str[11] = '\0'; - sscanf(pid_str, "%d", &l_pid); - close(lfd); - - /* - * Now try to kill the PID to see if it exists. - */ - errno = 0; - t = kill(l_pid, 0); - if ((t< 0) && (errno == ESRCH)) { - /* - * Stale lock file. - */ - unlink(LockFile); - continue; - } - else if (((t < 0) && (errno == EPERM)) || (t == 0)) { - /* - * Process is still active. - */ - unlink(tmp); - FatalError("Server is already active for display %s\n%s %s\n%s\n", - port, "\tIf this server is no longer running, remove", - LockFile, "\tand start again."); - } - } - } - unlink(tmp); - if (!haslock) - FatalError("Could not create server lock file: %s\n", LockFile); - StillLocking = FALSE; -} - -/* - * UnlockServer -- - * Remove the server lock file. - */ -void -UnlockServer(void) -{ - if (nolock) return; - - if (!StillLocking){ - - (void) unlink(LockFile); - } -} - -/* Force connections to close on SIGHUP from init */ - -void -AutoResetServer (int sig) -{ - int olderrno = errno; - - dispatchException |= DE_RESET; - isItTimeToYield = TRUE; - errno = olderrno; -} - -/* Force connections to close and then exit on SIGTERM, SIGINT */ - -void -GiveUp(int sig) -{ - int olderrno = errno; - - dispatchException |= DE_TERMINATE; - isItTimeToYield = TRUE; - errno = olderrno; -} - -#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__) -CARD32 -GetTimeInMillis (void) -{ - return GetTickCount (); -} -#else -CARD32 -GetTimeInMillis(void) -{ - struct timeval tv; - -#ifdef MONOTONIC_CLOCK - struct timespec tp; - if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) - return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); -#endif - - X_GETTIMEOFDAY(&tv); - return(tv.tv_sec * 1000) + (tv.tv_usec / 1000); -} -#endif - -void -AdjustWaitForDelay (pointer waitTime, unsigned long newdelay) -{ - static struct timeval delay_val; - struct timeval **wt = (struct timeval **) waitTime; - unsigned long olddelay; - - if (*wt == NULL) - { - delay_val.tv_sec = newdelay / 1000; - delay_val.tv_usec = 1000 * (newdelay % 1000); - *wt = &delay_val; - } - else - { - olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000; - if (newdelay < olddelay) - { - (*wt)->tv_sec = newdelay / 1000; - (*wt)->tv_usec = 1000 * (newdelay % 1000); - } - } -} - -void UseMsg(void) -{ - ErrorF("use: X [:<display>] [option]\n"); - ErrorF("-a # default pointer acceleration (factor)\n"); - ErrorF("-ac disable access control restrictions\n"); - ErrorF("-audit int set audit trail level\n"); - ErrorF("-auth file select authorization file\n"); - ErrorF("-br create root window with black background\n"); - ErrorF("+bs enable any backing store support\n"); - ErrorF("-bs disable any backing store support\n"); - ErrorF("-c turns off key-click\n"); - ErrorF("c # key-click volume (0-100)\n"); - ErrorF("-cc int default color visual class\n"); - ErrorF("-nocursor disable the cursor\n"); - ErrorF("-core generate core dump on fatal error\n"); - ErrorF("-dpi int screen resolution in dots per inch\n"); -#ifdef DPMSExtension - ErrorF("-dpms disables VESA DPMS monitor control\n"); -#endif - ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); - ErrorF("-f # bell base (0-100)\n"); - ErrorF("-fc string cursor font\n"); - ErrorF("-fn string default font name\n"); - ErrorF("-fp string default font path\n"); - ErrorF("-help prints message with these options\n"); - ErrorF("-I ignore all remaining arguments\n"); -#ifdef RLIMIT_DATA - ErrorF("-ld int limit data space to N Kb\n"); -#endif -#ifdef RLIMIT_NOFILE - ErrorF("-lf int limit number of open files to N\n"); -#endif -#ifdef RLIMIT_STACK - ErrorF("-ls int limit stack space to N Kb\n"); -#endif - ErrorF("-nolock disable the locking mechanism\n"); -#ifndef NOLOGOHACK - ErrorF("-logo enable logo in screen saver\n"); - ErrorF("nologo disable logo in screen saver\n"); -#endif - ErrorF("-nolisten string don't listen on protocol\n"); - ErrorF("-noreset don't reset after last client exists\n"); - ErrorF("-reset reset after last client exists\n"); - ErrorF("-p # screen-saver pattern duration (minutes)\n"); - ErrorF("-pn accept failure to listen on all ports\n"); - ErrorF("-nopn reject failure to listen on all ports\n"); - ErrorF("-r turns off auto-repeat\n"); - ErrorF("r turns on auto-repeat \n"); - ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); - ErrorF("-retro start with classic stipple and cursor\n"); - ErrorF("-s # screen-saver timeout (minutes)\n"); - ErrorF("-t # default pointer threshold (pixels/t)\n"); - ErrorF("-terminate terminate at server reset\n"); - ErrorF("-to # connection time out\n"); - ErrorF("-tst disable testing extensions\n"); - ErrorF("ttyxx server started from init on /dev/ttyxx\n"); - ErrorF("v video blanking for screen-saver\n"); - ErrorF("-v screen-saver without video blanking\n"); - ErrorF("-wm WhenMapped default backing-store\n"); - ErrorF("-wr create root window with white background\n"); - ErrorF("-maxbigreqsize set maximal bigrequest size \n"); -#ifdef PANORAMIX - ErrorF("+xinerama Enable XINERAMA extension\n"); - ErrorF("-xinerama Disable XINERAMA extension\n"); -#endif - ErrorF("-dumbSched Disable smart scheduling, enable old behavior\n"); - ErrorF("-schedInterval int Set scheduler interval in msec\n"); - ErrorF("+extension name Enable extension\n"); - ErrorF("-extension name Disable extension\n"); -#ifdef XDMCP - XdmcpUseMsg(); -#endif - XkbUseMsg(); - ddxUseMsg(); -} - -/* This function performs a rudimentary sanity check - * on the display name passed in on the command-line, - * since this string is used to generate filenames. - * It is especially important that the display name - * not contain a "/" and not start with a "-". - * --kvajk - */ -static int -VerifyDisplayName(const char *d) -{ - if ( d == (char *)0 ) return( 0 ); /* null */ - if ( *d == '\0' ) return( 0 ); /* empty */ - if ( *d == '-' ) return( 0 ); /* could be confused for an option */ - if ( *d == '.' ) return( 0 ); /* must not equal "." or ".." */ - if ( strchr(d, '/') != (char *)0 ) return( 0 ); /* very important!!! */ - return( 1 ); -} - -/* - * This function parses the command line. Handles device-independent fields - * and allows ddx to handle additional fields. It is not allowed to modify - * argc or any of the strings pointed to by argv. - */ -void -ProcessCommandLine(int argc, char *argv[]) -{ - int i, skip; - - defaultKeyboardControl.autoRepeat = TRUE; - -#ifdef NO_PART_NET - PartialNetwork = FALSE; -#else - PartialNetwork = TRUE; -#endif - - for ( i = 1; i < argc; i++ ) - { - /* call ddx first, so it can peek/override if it wants */ - if((skip = ddxProcessArgument(argc, argv, i))) - { - i += (skip - 1); - } - else if(argv[i][0] == ':') - { - /* initialize display */ - display = argv[i]; - display++; - if( ! VerifyDisplayName( display ) ) { - ErrorF("Bad display name: %s\n", display); - UseMsg(); - FatalError("Bad display name, exiting: %s\n", display); - } - } - else if ( strcmp( argv[i], "-a") == 0) - { - if(++i < argc) - defaultPointerControl.num = atoi(argv[i]); - else - UseMsg(); - } - else if ( strcmp( argv[i], "-ac") == 0) - { - defeatAccessControl = TRUE; - } - else if ( strcmp( argv[i], "-audit") == 0) - { - if(++i < argc) - auditTrailLevel = atoi(argv[i]); - else - UseMsg(); - } - else if ( strcmp( argv[i], "-auth") == 0) - { - if(++i < argc) - InitAuthorization (argv[i]); - else - UseMsg(); - } - else if ( strcmp( argv[i], "-br") == 0) ; /* default */ - else if ( strcmp( argv[i], "+bs") == 0) - enableBackingStore = TRUE; - else if ( strcmp( argv[i], "-bs") == 0) - disableBackingStore = TRUE; - else if ( strcmp( argv[i], "c") == 0) - { - if(++i < argc) - defaultKeyboardControl.click = atoi(argv[i]); - else - UseMsg(); - } - else if ( strcmp( argv[i], "-c") == 0) - { - defaultKeyboardControl.click = 0; - } - else if ( strcmp( argv[i], "-cc") == 0) - { - if(++i < argc) - defaultColorVisualClass = atoi(argv[i]); - else - UseMsg(); - } - else if ( strcmp( argv[i], "-core") == 0) - { -#if !defined(WIN32) || !defined(__MINGW32__) - struct rlimit core_limit; - getrlimit (RLIMIT_CORE, &core_limit); - core_limit.rlim_cur = core_limit.rlim_max; - setrlimit (RLIMIT_CORE, &core_limit); -#endif - CoreDump = TRUE; - } - else if ( strcmp( argv[i], "-nocursor") == 0) - { - EnableCursor = FALSE; - } - else if ( strcmp( argv[i], "-dpi") == 0) - { - if(++i < argc) - monitorResolution = atoi(argv[i]); - else - UseMsg(); - } -#ifdef DPMSExtension - else if ( strcmp( argv[i], "dpms") == 0) - /* ignored for compatibility */ ; - else if ( strcmp( argv[i], "-dpms") == 0) - DPMSDisabledSwitch = TRUE; -#endif - else if ( strcmp( argv[i], "-deferglyphs") == 0) - { - if(++i >= argc || !ParseGlyphCachingMode(argv[i])) - UseMsg(); - } - else if ( strcmp( argv[i], "-f") == 0) - { - if(++i < argc) - defaultKeyboardControl.bell = atoi(argv[i]); - else - UseMsg(); - } - else if ( strcmp( argv[i], "-fc") == 0) - { - if(++i < argc) - defaultCursorFont = argv[i]; - else - UseMsg(); - } - else if ( strcmp( argv[i], "-fn") == 0) - { - if(++i < argc) - defaultTextFont = argv[i]; - else - UseMsg(); - } - else if ( strcmp( argv[i], "-fp") == 0) - { - if(++i < argc) - { - defaultFontPath = argv[i]; - } - else - UseMsg(); - } - else if ( strcmp( argv[i], "-help") == 0) - { - UseMsg(); - exit(0); - } - else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) { - if (skip>0) - i+= skip-1; - else UseMsg(); - } -#ifdef RLIMIT_DATA - else if ( strcmp( argv[i], "-ld") == 0) - { - if(++i < argc) - { - limitDataSpace = atoi(argv[i]); - if (limitDataSpace > 0) - limitDataSpace *= 1024; - } - else - UseMsg(); - } -#endif -#ifdef RLIMIT_NOFILE - else if ( strcmp( argv[i], "-lf") == 0) - { - if(++i < argc) - limitNoFile = atoi(argv[i]); - else - UseMsg(); - } -#endif -#ifdef RLIMIT_STACK - else if ( strcmp( argv[i], "-ls") == 0) - { - if(++i < argc) - { - limitStackSpace = atoi(argv[i]); - if (limitStackSpace > 0) - limitStackSpace *= 1024; - } - else - UseMsg(); - } -#endif - else if ( strcmp ( argv[i], "-nolock") == 0) - { -#if !defined(WIN32) && !defined(__CYGWIN__) - if (getuid() != 0) - ErrorF("Warning: the -nolock option can only be used by root\n"); - else -#endif - nolock = TRUE; - } -#ifndef NOLOGOHACK - else if ( strcmp( argv[i], "-logo") == 0) - { - logoScreenSaver = 1; - } - else if ( strcmp( argv[i], "nologo") == 0) - { - logoScreenSaver = 0; - } -#endif - else if ( strcmp( argv[i], "-nolisten") == 0) - { - if(++i < argc) { - if (_XSERVTransNoListen(argv[i])) - FatalError ("Failed to disable listen for %s transport", - argv[i]); - } else - UseMsg(); - } - else if ( strcmp( argv[i], "-noreset") == 0) - { - dispatchExceptionAtReset = 0; - } - else if ( strcmp( argv[i], "-reset") == 0) - { - dispatchExceptionAtReset = DE_RESET; - } - else if ( strcmp( argv[i], "-p") == 0) - { - if(++i < argc) - defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) * - MILLI_PER_MIN; - else - UseMsg(); - } - else if (strcmp(argv[i], "-pogo") == 0) - { - dispatchException = DE_TERMINATE; - } - else if ( strcmp( argv[i], "-pn") == 0) - PartialNetwork = TRUE; - else if ( strcmp( argv[i], "-nopn") == 0) - PartialNetwork = FALSE; - else if ( strcmp( argv[i], "r") == 0) - defaultKeyboardControl.autoRepeat = TRUE; - else if ( strcmp( argv[i], "-r") == 0) - defaultKeyboardControl.autoRepeat = FALSE; - else if ( strcmp( argv[i], "-retro") == 0) - party_like_its_1989 = TRUE; - else if ( strcmp( argv[i], "-s") == 0) - { - if(++i < argc) - defaultScreenSaverTime = ((CARD32)atoi(argv[i])) * - MILLI_PER_MIN; - else - UseMsg(); - } - else if ( strcmp( argv[i], "-t") == 0) - { - if(++i < argc) - defaultPointerControl.threshold = atoi(argv[i]); - else - UseMsg(); - } - else if ( strcmp( argv[i], "-terminate") == 0) - { - dispatchExceptionAtReset = DE_TERMINATE; - } - else if ( strcmp( argv[i], "-to") == 0) - { - if(++i < argc) - TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND; - else - UseMsg(); - } - else if ( strcmp( argv[i], "-tst") == 0) - { - noTestExtensions = TRUE; - } - else if ( strcmp( argv[i], "v") == 0) - defaultScreenSaverBlanking = PreferBlanking; - else if ( strcmp( argv[i], "-v") == 0) - defaultScreenSaverBlanking = DontPreferBlanking; - else if ( strcmp( argv[i], "-wm") == 0) - defaultBackingStore = WhenMapped; - else if ( strcmp( argv[i], "-wr") == 0) - whiteRoot = TRUE; - else if ( strcmp( argv[i], "-maxbigreqsize") == 0) { - if(++i < argc) { - long reqSizeArg = atol(argv[i]); - - /* Request size > 128MB does not make much sense... */ - if( reqSizeArg > 0L && reqSizeArg < 128L ) { - maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; - } - else - { - UseMsg(); - } - } - else - { - UseMsg(); - } - } -#ifdef PANORAMIX - else if ( strcmp( argv[i], "+xinerama") == 0){ - noPanoramiXExtension = FALSE; - } - else if ( strcmp( argv[i], "-xinerama") == 0){ - noPanoramiXExtension = TRUE; - } - else if ( strcmp( argv[i], "-disablexineramaextension") == 0){ - PanoramiXExtensionDisabledHack = TRUE; - } -#endif - else if ( strcmp( argv[i], "-I") == 0) - { - /* ignore all remaining arguments */ - break; - } - else if (strncmp (argv[i], "tty", 3) == 0) - { - /* just in case any body is interested */ - dev_tty_from_init = argv[i]; - } -#ifdef XDMCP - else if ((skip = XdmcpOptions(argc, argv, i)) != i) - { - i = skip - 1; - } -#endif - else if ( strcmp( argv[i], "-dumbSched") == 0) - { - SmartScheduleDisable = TRUE; - } - else if ( strcmp( argv[i], "-schedInterval") == 0) - { - if (++i < argc) - { - SmartScheduleInterval = atoi(argv[i]); - SmartScheduleSlice = SmartScheduleInterval; - } - else - UseMsg(); - } - else if ( strcmp( argv[i], "-schedMax") == 0) - { - if (++i < argc) - { - SmartScheduleMaxSlice = atoi(argv[i]); - } - else - UseMsg(); - } - else if ( strcmp( argv[i], "-render" ) == 0) - { - if (++i < argc) - { - int policy = PictureParseCmapPolicy (argv[i]); - - if (policy != PictureCmapPolicyInvalid) - PictureCmapPolicy = policy; - else - UseMsg (); - } - else - UseMsg (); - } - else if ( strcmp( argv[i], "+extension") == 0) - { - if (++i < argc) - { - if (!EnableDisableExtension(argv[i], TRUE)) - EnableDisableExtensionError(argv[i], TRUE); - } - else - UseMsg(); - } - else if ( strcmp( argv[i], "-extension") == 0) - { - if (++i < argc) - { - if (!EnableDisableExtension(argv[i], FALSE)) - EnableDisableExtensionError(argv[i], FALSE); - } - else - UseMsg(); - } - else - { - ErrorF("Unrecognized option: %s\n", argv[i]); - UseMsg(); - FatalError("Unrecognized option: %s\n", argv[i]); - } - } -} - -/* Implement a simple-minded font authorization scheme. The authorization - name is "hp-hostname-1", the contents are simply the host name. */ -int -set_font_authorizations(char **authorizations, int *authlen, pointer client) -{ -#define AUTHORIZATION_NAME "hp-hostname-1" -#if defined(TCPCONN) || defined(STREAMSCONN) - static char *result = NULL; - static char *p = NULL; - - if (p == NULL) - { - char hname[1024], *hnameptr; - unsigned int len; -#if defined(IPv6) && defined(AF_INET6) - struct addrinfo hints, *ai = NULL; -#else - struct hostent *host; -#ifdef XTHREADS_NEEDS_BYNAMEPARAMS - _Xgethostbynameparams hparams; -#endif -#endif - - gethostname(hname, 1024); -#if defined(IPv6) && defined(AF_INET6) - bzero(&hints, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; - if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { - hnameptr = ai->ai_canonname; - } else { - hnameptr = hname; - } -#else - host = _XGethostbyname(hname, hparams); - if (host == NULL) - hnameptr = hname; - else - hnameptr = host->h_name; -#endif - - len = strlen(hnameptr) + 1; - result = xalloc(len + sizeof(AUTHORIZATION_NAME) + 4); - - p = result; - *p++ = sizeof(AUTHORIZATION_NAME) >> 8; - *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; - *p++ = (len) >> 8; - *p++ = (len & 0xff); - - memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); - p += sizeof(AUTHORIZATION_NAME); - memmove(p, hnameptr, len); - p += len; -#if defined(IPv6) && defined(AF_INET6) - if (ai) { - freeaddrinfo(ai); - } -#endif - } - *authlen = p - result; - *authorizations = result; - return 1; -#else /* TCPCONN */ - return 0; -#endif /* TCPCONN */ -} - -void * -Xalloc(unsigned long amount) -{ - void *ptr; - - if ((long)amount <= 0) { - return NULL; - } - /* aligned extra on long word boundary */ - amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); - ptr = malloc(amount); - return ptr; -} - -/***************** - * XNFalloc - * "no failure" realloc - *****************/ - -void * -XNFalloc(unsigned long amount) -{ - void *ptr; - - if ((long)amount <= 0) - return NULL; - /* aligned extra on long word boundary */ - amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); - ptr = malloc(amount); - if (!ptr) - FatalError("Out of memory"); - return ptr; -} - -/***************** - * Xcalloc - *****************/ - -void * -Xcalloc(unsigned long amount) -{ - void *ret; - - ret = Xalloc (amount); - if (ret) - bzero (ret, (int) amount); - return ret; -} - -/***************** - * XNFcalloc - *****************/ - -void * -XNFcalloc(unsigned long amount) -{ - void *ret; - - ret = Xalloc (amount); - if (ret) - bzero (ret, (int) amount); - else if ((long)amount > 0) - FatalError("Out of memory"); - return ret; -} - -/***************** - * Xrealloc - *****************/ - -void * -Xrealloc(pointer ptr, unsigned long amount) -{ - if ((long)amount <= 0) - { - if (ptr && !amount) - free(ptr); - return NULL; - } - amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); - if (ptr) - ptr = realloc(ptr, amount); - else - ptr = malloc(amount); - - return ptr; -} - -/***************** - * XNFrealloc - * "no failure" realloc - *****************/ - -void * -XNFrealloc(pointer ptr, unsigned long amount) -{ - if ((ptr = Xrealloc(ptr, amount)) == NULL) - { - if ((long)amount > 0) - FatalError( "Out of memory" ); - } - return ptr; -} - -/***************** - * Xfree - * calls free - *****************/ - -void -Xfree(pointer ptr) -{ - if (ptr) - free(ptr); -} - - -char * -Xstrdup(const char *s) -{ - char *sd; - - if (s == NULL) - return NULL; - - sd = Xalloc(strlen(s) + 1); - if (sd != NULL) - strcpy(sd, s); - return sd; -} - - -char * -XNFstrdup(const char *s) -{ - char *sd; - - if (s == NULL) - return NULL; - - sd = XNFalloc(strlen(s) + 1); - strcpy(sd, s); - return sd; -} - - -#ifdef SIGVTALRM -#define SMART_SCHEDULE_POSSIBLE -#endif - -#ifdef SMART_SCHEDULE_POSSIBLE -#define SMART_SCHEDULE_SIGNAL SIGALRM -#define SMART_SCHEDULE_TIMER ITIMER_REAL -#endif - -void -SmartScheduleStopTimer (void) -{ -#ifdef SMART_SCHEDULE_POSSIBLE - struct itimerval timer; - - if (SmartScheduleDisable) - return; - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_usec = 0; - timer.it_value.tv_sec = 0; - timer.it_value.tv_usec = 0; - (void) setitimer (ITIMER_REAL, &timer, 0); -#endif -} - -void -SmartScheduleStartTimer (void) -{ -#ifdef SMART_SCHEDULE_POSSIBLE - struct itimerval timer; - - if (SmartScheduleDisable) - return; - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_usec = SmartScheduleInterval * 1000; - timer.it_value.tv_sec = 0; - timer.it_value.tv_usec = SmartScheduleInterval * 1000; - setitimer (ITIMER_REAL, &timer, 0); -#endif -} - -#ifdef SMART_SCHEDULE_POSSIBLE -static void -SmartScheduleTimer (int sig) -{ - SmartScheduleTime += SmartScheduleInterval; -} -#endif - -Bool -SmartScheduleInit (void) -{ -#ifdef SMART_SCHEDULE_POSSIBLE - struct sigaction act; - - if (SmartScheduleDisable) - return TRUE; - - bzero ((char *) &act, sizeof(struct sigaction)); - - /* Set up the timer signal function */ - act.sa_handler = SmartScheduleTimer; - sigemptyset (&act.sa_mask); - sigaddset (&act.sa_mask, SMART_SCHEDULE_SIGNAL); - if (sigaction (SMART_SCHEDULE_SIGNAL, &act, 0) < 0) - { - perror ("sigaction for smart scheduler"); - return FALSE; - } - return TRUE; -#else - return FALSE; -#endif -} - -#ifdef SIG_BLOCK -static sigset_t PreviousSignalMask; -static int BlockedSignalCount; -#endif - -void -OsBlockSignals (void) -{ -#ifdef SIG_BLOCK - if (BlockedSignalCount++ == 0) - { - sigset_t set; - - sigemptyset (&set); -#ifdef SIGALRM - sigaddset (&set, SIGALRM); -#endif -#ifdef SIGVTALRM - sigaddset (&set, SIGVTALRM); -#endif -#ifdef SIGWINCH - sigaddset (&set, SIGWINCH); -#endif -#ifdef SIGIO - sigaddset (&set, SIGIO); -#endif -#ifdef SIGTSTP - sigaddset (&set, SIGTSTP); -#endif -#ifdef SIGTTIN - sigaddset (&set, SIGTTIN); -#endif -#ifdef SIGTTOU - sigaddset (&set, SIGTTOU); -#endif -#ifdef SIGCHLD - sigaddset (&set, SIGCHLD); -#endif - sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask); - } -#endif -} - -void -OsReleaseSignals (void) -{ -#ifdef SIG_BLOCK - if (--BlockedSignalCount == 0) - { - sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0); - } -#endif -} - -/* - * Pending signals may interfere with core dumping. Provide a - * mechanism to block signals when aborting. - */ - -void -OsAbort (void) -{ -#ifndef __APPLE__ - OsBlockSignals(); -#endif - abort(); -} - -#if !defined(WIN32) -/* - * "safer" versions of system(3), popen(3) and pclose(3) which give up - * all privs before running a command. - * - * This is based on the code in FreeBSD 2.2 libc. - * - * XXX It'd be good to redirect stderr so that it ends up in the log file - * as well. As it is now, xkbcomp messages don't end up in the log file. - */ - -int -System(char *command) -{ - int pid, p; -#ifdef SIGCHLD - void (*csig)(int); -#endif - int status; - - if (!command) - return(1); - -#ifdef SIGCHLD - csig = signal(SIGCHLD, SIG_DFL); - if (csig == SIG_ERR) { - perror("signal"); - return -1; - } -#endif - -#ifdef DEBUG - ErrorF("System: `%s'\n", command); -#endif - - switch (pid = fork()) { - case -1: /* error */ - p = -1; - case 0: /* child */ - if (setgid(getgid()) == -1) - _exit(127); - if (setuid(getuid()) == -1) - _exit(127); - execl("/bin/sh", "sh", "-c", command, (char *)NULL); - _exit(127); - default: /* parent */ - do { - p = waitpid(pid, &status, 0); - } while (p == -1 && errno == EINTR); - - } - -#ifdef SIGCHLD - if (signal(SIGCHLD, csig) == SIG_ERR) { - perror("signal"); - return -1; - } -#endif - - return p == -1 ? -1 : status; -} - -static struct pid { - struct pid *next; - FILE *fp; - int pid; -} *pidlist; - -OsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */ - -pointer -Popen(char *command, char *type) -{ - struct pid *cur; - FILE *iop; - int pdes[2], pid; - - if (command == NULL || type == NULL) - return NULL; - - if ((*type != 'r' && *type != 'w') || type[1]) - return NULL; - - if ((cur = xalloc(sizeof(struct pid))) == NULL) - return NULL; - - if (pipe(pdes) < 0) { - xfree(cur); - return NULL; - } - - /* Ignore the smart scheduler while this is going on */ - old_alarm = OsSignal(SIGALRM, SIG_IGN); - if (old_alarm == SIG_ERR) { - perror("signal"); - return NULL; - } - - switch (pid = fork()) { - case -1: /* error */ - close(pdes[0]); - close(pdes[1]); - xfree(cur); - if (OsSignal(SIGALRM, old_alarm) == SIG_ERR) - perror("signal"); - return NULL; - case 0: /* child */ - if (setgid(getgid()) == -1) - _exit(127); - if (setuid(getuid()) == -1) - _exit(127); - if (*type == 'r') { - if (pdes[1] != 1) { - /* stdout */ - dup2(pdes[1], 1); - close(pdes[1]); - } - close(pdes[0]); - } else { - if (pdes[0] != 0) { - /* stdin */ - dup2(pdes[0], 0); - close(pdes[0]); - } - close(pdes[1]); - } - execl("/bin/sh", "sh", "-c", command, (char *)NULL); - _exit(127); - } - - /* Avoid EINTR during stdio calls */ - OsBlockSignals (); - - /* parent */ - if (*type == 'r') { - iop = fdopen(pdes[0], type); - close(pdes[1]); - } else { - iop = fdopen(pdes[1], type); - close(pdes[0]); - } - - cur->fp = iop; - cur->pid = pid; - cur->next = pidlist; - pidlist = cur; - -#ifdef DEBUG - ErrorF("Popen: `%s', fp = %p\n", command, iop); -#endif - - return iop; -} - -/* fopen that drops privileges */ -pointer -Fopen(char *file, char *type) -{ - FILE *iop; -#ifndef HAS_SAVED_IDS_AND_SETEUID - struct pid *cur; - int pdes[2], pid; - - if (file == NULL || type == NULL) - return NULL; - - if ((*type != 'r' && *type != 'w') || type[1]) - return NULL; - - if ((cur = xalloc(sizeof(struct pid))) == NULL) - return NULL; - - if (pipe(pdes) < 0) { - xfree(cur); - return NULL; - } - - switch (pid = fork()) { - case -1: /* error */ - close(pdes[0]); - close(pdes[1]); - xfree(cur); - return NULL; - case 0: /* child */ - if (setgid(getgid()) == -1) - _exit(127); - if (setuid(getuid()) == -1) - _exit(127); - if (*type == 'r') { - if (pdes[1] != 1) { - /* stdout */ - dup2(pdes[1], 1); - close(pdes[1]); - } - close(pdes[0]); - } else { - if (pdes[0] != 0) { - /* stdin */ - dup2(pdes[0], 0); - close(pdes[0]); - } - close(pdes[1]); - } - execl("/bin/cat", "cat", file, (char *)NULL); - _exit(127); - } - - /* Avoid EINTR during stdio calls */ - OsBlockSignals (); - - /* parent */ - if (*type == 'r') { - iop = fdopen(pdes[0], type); - close(pdes[1]); - } else { - iop = fdopen(pdes[1], type); - close(pdes[0]); - } - - cur->fp = iop; - cur->pid = pid; - cur->next = pidlist; - pidlist = cur; - -#ifdef DEBUG - ErrorF("Fopen(%s), fp = %p\n", file, iop); -#endif - - return iop; -#else - int ruid, euid; - - ruid = getuid(); - euid = geteuid(); - - if (seteuid(ruid) == -1) { - return NULL; - } - iop = fopen(file, type); - - if (seteuid(euid) == -1) { - fclose(iop); - return NULL; - } - return iop; -#endif /* HAS_SAVED_IDS_AND_SETEUID */ -} - -int -Pclose(pointer iop) -{ - struct pid *cur, *last; - int pstat; - int pid; - -#ifdef DEBUG - ErrorF("Pclose: fp = %p\n", iop); -#endif - - fclose(iop); - - for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) - if (cur->fp == iop) - break; - if (cur == NULL) - return -1; - - do { - pid = waitpid(cur->pid, &pstat, 0); - } while (pid == -1 && errno == EINTR); - - if (last == NULL) - pidlist = cur->next; - else - last->next = cur->next; - xfree(cur); - - /* allow EINTR again */ - OsReleaseSignals (); - - if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) { - perror("signal"); - return -1; - } - - return pid == -1 ? -1 : pstat; -} - -int -Fclose(pointer iop) -{ -#ifdef HAS_SAVED_IDS_AND_SETEUID - return fclose(iop); -#else - return Pclose(iop); -#endif -} - -#endif /* !WIN32 */ - - -/* - * CheckUserParameters: check for long command line arguments and long - * environment variables. By default, these checks are only done when - * the server's euid != ruid. In 3.3.x, these checks were done in an - * external wrapper utility. - */ - -/* Consider LD* variables insecure? */ -#ifndef REMOVE_ENV_LD -#define REMOVE_ENV_LD 1 -#endif - -/* Remove long environment variables? */ -#ifndef REMOVE_LONG_ENV -#define REMOVE_LONG_ENV 1 -#endif - -/* - * Disallow stdout or stderr as pipes? It's possible to block the X server - * when piping stdout+stderr to a pipe. - * - * Don't enable this because it looks like it's going to cause problems. - */ -#ifndef NO_OUTPUT_PIPES -#define NO_OUTPUT_PIPES 0 -#endif - - -/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ -#ifndef CHECK_EUID -#ifndef WIN32 -#define CHECK_EUID 1 -#else -#define CHECK_EUID 0 -#endif -#endif - -/* - * Maybe the locale can be faked to make isprint(3) report that everything - * is printable? Avoid it by default. - */ -#ifndef USE_ISPRINT -#define USE_ISPRINT 0 -#endif - -#define MAX_ARG_LENGTH 128 -#define MAX_ENV_LENGTH 256 -#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ - -#if USE_ISPRINT -#include <ctype.h> -#define checkPrintable(c) isprint(c) -#else -#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) -#endif - -enum BadCode { - NotBad = 0, - UnsafeArg, - ArgTooLong, - UnprintableArg, - EnvTooLong, - OutputIsPipe, - InternalError -}; - -#if defined(VENDORSUPPORT) -#define BUGADDRESS VENDORSUPPORT -#elif defined(BUILDERADDR) -#define BUGADDRESS BUILDERADDR -#else -#define BUGADDRESS "xorg@freedesktop.org" -#endif - -void -CheckUserParameters(int argc, char **argv, char **envp) -{ - enum BadCode bad = NotBad; - int i = 0, j; - char *a, *e = NULL; - -#if CHECK_EUID - if (geteuid() == 0 && getuid() != geteuid()) -#endif - { - /* Check each argv[] */ - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-fp") == 0) - { - i++; /* continue with next argument. skip the length check */ - if (i >= argc) - break; - } else - { - if (strlen(argv[i]) > MAX_ARG_LENGTH) { - bad = ArgTooLong; - break; - } - } - a = argv[i]; - while (*a) { - if (checkPrintable(*a) == 0) { - bad = UnprintableArg; - break; - } - a++; - } - if (bad) - break; - } - if (!bad) { - /* Check each envp[] */ - for (i = 0; envp[i]; i++) { - - /* Check for bad environment variables and values */ -#if REMOVE_ENV_LD - while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { - for (j = i; envp[j]; j++) { - envp[j] = envp[j+1]; - } - } -#endif - if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { -#if REMOVE_LONG_ENV - for (j = i; envp[j]; j++) { - envp[j] = envp[j+1]; - } - i--; -#else - char *eq; - int len; - - eq = strchr(envp[i], '='); - if (!eq) - continue; - len = eq - envp[i]; - e = malloc(len + 1); - if (!e) { - bad = InternalError; - break; - } - strncpy(e, envp[i], len); - e[len] = 0; - if (len >= 4 && - (strcmp(e + len - 4, "PATH") == 0 || - strcmp(e, "TERMCAP") == 0)) { - if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { - bad = EnvTooLong; - break; - } else { - free(e); - } - } else { - bad = EnvTooLong; - break; - } -#endif - } - } - } -#if NO_OUTPUT_PIPES - if (!bad) { - struct stat buf; - - if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) - bad = OutputIsPipe; - if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) - bad = OutputIsPipe; - } -#endif - } - switch (bad) { - case NotBad: - return; - case UnsafeArg: - ErrorF("Command line argument number %d is unsafe\n", i); - break; - case ArgTooLong: - ErrorF("Command line argument number %d is too long\n", i); - break; - case UnprintableArg: - ErrorF("Command line argument number %d contains unprintable" - " characters\n", i); - break; - case EnvTooLong: - ErrorF("Environment variable `%s' is too long\n", e); - break; - case OutputIsPipe: - ErrorF("Stdout and/or stderr is a pipe\n"); - break; - case InternalError: - ErrorF("Internal Error\n"); - break; - default: - ErrorF("Unknown error\n"); - break; - } - FatalError("X server aborted because of unsafe environment\n"); -} - -/* - * CheckUserAuthorization: check if the user is allowed to start the - * X server. This usually means some sort of PAM checking, and it is - * usually only done for setuid servers (uid != euid). - */ - -#ifdef USE_PAM -#include <security/pam_appl.h> -#include <security/pam_misc.h> -#include <pwd.h> -#endif /* USE_PAM */ - -void -CheckUserAuthorization(void) -{ -#ifdef USE_PAM - static struct pam_conv conv = { - misc_conv, - NULL - }; - - pam_handle_t *pamh = NULL; - struct passwd *pw; - int retval; - - if (getuid() != geteuid()) { - pw = getpwuid(getuid()); - if (pw == NULL) - FatalError("getpwuid() failed for uid %d\n", getuid()); - - retval = pam_start("xserver", pw->pw_name, &conv, &pamh); - if (retval != PAM_SUCCESS) - FatalError("pam_start() failed.\n" - "\tMissing or mangled PAM config file or module?\n"); - - retval = pam_authenticate(pamh, 0); - if (retval != PAM_SUCCESS) { - pam_end(pamh, retval); - FatalError("PAM authentication failed, cannot start X server.\n" - "\tPerhaps you do not have console ownership?\n"); - } - - retval = pam_acct_mgmt(pamh, 0); - if (retval != PAM_SUCCESS) { - pam_end(pamh, retval); - FatalError("PAM authentication failed, cannot start X server.\n" - "\tPerhaps you do not have console ownership?\n"); - } - - /* this is not a session, so do not do session management */ - pam_end(pamh, PAM_SUCCESS); - } -#endif -} - -/* - * Tokenize a string into a NULL terminated array of strings. Always returns - * an allocated array unless an error occurs. - */ -char** -xstrtokenize(const char *str, const char *separators) -{ - char **list, **nlist; - char *tok, *tmp; - unsigned num = 0, n; - - if (!str) - return NULL; - list = calloc(1, sizeof(*list)); - if (!list) - return NULL; - tmp = strdup(str); - if (!tmp) - goto error; - for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { - nlist = realloc(list, (num + 2) * sizeof(*list)); - if (!nlist) - goto error; - list = nlist; - list[num] = strdup(tok); - if (!list[num]) - goto error; - list[++num] = NULL; - } - free(tmp); - return list; - -error: - free(tmp); - for (n = 0; n < num; n++) - free(list[n]); - free(list); - return NULL; -} - -#ifdef __SCO__ -#include <fcntl.h> - -static void -lockit (int fd, short what) -{ - struct flock lck; - - lck.l_whence = 0; - lck.l_start = 0; - lck.l_len = 1; - lck.l_type = what; - - (void)fcntl (fd, F_SETLKW, &lck); -} - -/* SCO OpenServer 5 lacks pread/pwrite. Emulate them. */ -ssize_t -pread (int fd, void *buf, size_t nbytes, off_t offset) -{ - off_t saved; - ssize_t ret; - - lockit (fd, F_RDLCK); - saved = lseek (fd, 0, SEEK_CUR); - lseek (fd, offset, SEEK_SET); - ret = read (fd, buf, nbytes); - lseek (fd, saved, SEEK_SET); - lockit (fd, F_UNLCK); - - return ret; -} - -ssize_t -pwrite (int fd, const void *buf, size_t nbytes, off_t offset) -{ - off_t saved; - ssize_t ret; - - lockit (fd, F_WRLCK); - saved = lseek (fd, 0, SEEK_CUR); - lseek (fd, offset, SEEK_SET); - ret = write (fd, buf, nbytes); - lseek (fd, saved, SEEK_SET); - lockit (fd, F_UNLCK); - - return ret; -} -#endif /* __SCO__ */ +/* + +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, +Copyright 1994 Quarterdeck Office Systems. + + 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 and +Quarterdeck not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +DIGITAL AND QUARTERDECK DISCLAIM 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 <dix-config.h> +#endif + +#ifdef __CYGWIN__ +#include <stdlib.h> +#include <signal.h> +/* + Sigh... We really need a prototype for this to know it is stdcall, + but #include-ing <windows.h> here is not a good idea... +*/ +__stdcall unsigned long GetTickCount(void); +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +#include <X11/Xwinsock.h> +#endif +#include <X11/Xos.h> +#include <stdio.h> +#include <time.h> +#if !defined(WIN32) || !defined(__MINGW32__) +#include <sys/time.h> +#include <sys/resource.h> +#endif +#include "misc.h" +#include <X11/X.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <X11/Xtrans/Xtrans.h> +#include "input.h" +#include "dixfont.h" +#include "osdep.h" +#include "extension.h" +#ifdef X_POSIX_C_SOURCE +#define _POSIX_C_SOURCE X_POSIX_C_SOURCE +#include <signal.h> +#undef _POSIX_C_SOURCE +#else +#if defined(_POSIX_SOURCE) +#include <signal.h> +#else +#define _POSIX_SOURCE +#include <signal.h> +#undef _POSIX_SOURCE +#endif +#endif +#ifndef WIN32 +#include <sys/wait.h> +#endif +#if !defined(SYSV) && !defined(WIN32) +#include <sys/resource.h> +#endif +#include <sys/stat.h> +#include <ctype.h> /* for isspace */ +#include <stdarg.h> + +#include <stdlib.h> /* for malloc() */ + +#if defined(TCPCONN) || defined(STREAMSCONN) +# ifndef WIN32 +# include <netdb.h> +# endif +#endif + +#include "opaque.h" + +#include "dixstruct.h" + +#include "xkbsrv.h" + +#include "picture.h" + +Bool noTestExtensions; +#ifdef COMPOSITE +Bool noCompositeExtension = FALSE; +#endif + +#ifdef DAMAGE +Bool noDamageExtension = FALSE; +#endif +#ifdef DBE +Bool noDbeExtension = FALSE; +#endif +#ifdef DPMSExtension +Bool noDPMSExtension = FALSE; +#endif +#ifdef GLXEXT +Bool noGlxExtension = FALSE; +Bool noGlxVisualInit = FALSE; +#endif +#ifdef SCREENSAVER +Bool noScreenSaverExtension = FALSE; +#endif +#ifdef MITSHM +Bool noMITShmExtension = FALSE; +#endif +#ifdef RANDR +Bool noRRExtension = FALSE; +#endif +Bool noRenderExtension = FALSE; +#ifdef XCSECURITY +Bool noSecurityExtension = FALSE; +#endif +#ifdef RES +Bool noResExtension = FALSE; +#endif +#ifdef XF86BIGFONT +Bool noXFree86BigfontExtension = FALSE; +#endif +#ifdef XFreeXDGA +Bool noXFree86DGAExtension = FALSE; +#endif +#ifdef XF86DRI +Bool noXFree86DRIExtension = FALSE; +#endif +#ifdef XF86VIDMODE +Bool noXFree86VidModeExtension = FALSE; +#endif +#ifdef XFIXES +Bool noXFixesExtension = FALSE; +#endif +#ifdef PANORAMIX +/* Xinerama is disabled by default unless enabled via +xinerama */ +Bool noPanoramiXExtension = TRUE; +#endif +#ifdef XSELINUX +Bool noSELinuxExtension = FALSE; +int selinuxEnforcingState = SELINUX_MODE_DEFAULT; +#endif +#ifdef XV +Bool noXvExtension = FALSE; +#endif +#ifdef DRI2 +Bool noDRI2Extension = FALSE; +#endif + +Bool noGEExtension = FALSE; + +#define X_INCLUDE_NETDB_H +#include <X11/Xos_r.h> + +#include <errno.h> + +Bool CoreDump; + +#ifdef PANORAMIX +Bool PanoramiXExtensionDisabledHack = FALSE; +#endif + +int auditTrailLevel = 1; + +#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) +#define HAS_SAVED_IDS_AND_SETEUID +#endif + +static char *dev_tty_from_init = NULL; /* since we need to parse it anyway */ + +OsSigHandlerPtr +OsSignal(int sig, OsSigHandlerPtr handler) +{ + struct sigaction act, oact; + + sigemptyset(&act.sa_mask); + if (handler != SIG_IGN) + sigaddset(&act.sa_mask, sig); + act.sa_flags = 0; + act.sa_handler = handler; + if (sigaction(sig, &act, &oact)) + perror("sigaction"); + return oact.sa_handler; +} + +/* + * Explicit support for a server lock file like the ones used for UUCP. + * For architectures with virtual terminals that can run more than one + * server at a time. This keeps the servers from stomping on each other + * if the user forgets to give them different display numbers. + */ +#define LOCK_DIR "/tmp" +#define LOCK_TMP_PREFIX "/.tX" +#define LOCK_PREFIX "/.X" +#define LOCK_SUFFIX "-lock" + +#ifndef PATH_MAX +#include <sys/param.h> +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif +#endif + +static Bool StillLocking = FALSE; +static char LockFile[PATH_MAX]; +static Bool nolock = FALSE; + +/* + * LockServer -- + * Check if the server lock file exists. If so, check if the PID + * contained inside is valid. If so, then die. Otherwise, create + * the lock file containing the PID. + */ +void +LockServer(void) +{ + char tmp[PATH_MAX], pid_str[12]; + int lfd, i, haslock, l_pid, t; + char *tmppath = NULL; + int len; + char port[20]; + + if (nolock) return; + /* + * Path names + */ + tmppath = LOCK_DIR; + + sprintf(port, "%d", atoi(display)); + len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : + strlen(LOCK_TMP_PREFIX); + len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; + if (len > sizeof(LockFile)) + FatalError("Display name `%s' is too long\n", port); + (void)sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); + (void)sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); + + /* + * Create a temporary file containing our PID. Attempt three times + * to create the file. + */ + StillLocking = TRUE; + i = 0; + do { + i++; + lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); + if (lfd < 0) + sleep(2); + else + break; + } while (i < 3); + if (lfd < 0) { + unlink(tmp); + i = 0; + do { + i++; + lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); + if (lfd < 0) + sleep(2); + else + break; + } while (i < 3); + } + if (lfd < 0) + FatalError("Could not create lock file in %s\n", tmp); + (void) sprintf(pid_str, "%10ld\n", (long)getpid()); + (void) write(lfd, pid_str, 11); + (void) chmod(tmp, 0444); + (void) close(lfd); + + /* + * OK. Now the tmp file exists. Try three times to move it in place + * for the lock. + */ + i = 0; + haslock = 0; + while ((!haslock) && (i++ < 3)) { + haslock = (link(tmp,LockFile) == 0); + if (haslock) { + /* + * We're done. + */ + break; + } + else { + /* + * Read the pid from the existing file + */ + lfd = open(LockFile, O_RDONLY); + if (lfd < 0) { + unlink(tmp); + FatalError("Can't read lock file %s\n", LockFile); + } + pid_str[0] = '\0'; + if (read(lfd, pid_str, 11) != 11) { + /* + * Bogus lock file. + */ + unlink(LockFile); + close(lfd); + continue; + } + pid_str[11] = '\0'; + sscanf(pid_str, "%d", &l_pid); + close(lfd); + + /* + * Now try to kill the PID to see if it exists. + */ + errno = 0; + t = kill(l_pid, 0); + if ((t< 0) && (errno == ESRCH)) { + /* + * Stale lock file. + */ + unlink(LockFile); + continue; + } + else if (((t < 0) && (errno == EPERM)) || (t == 0)) { + /* + * Process is still active. + */ + unlink(tmp); + FatalError("Server is already active for display %s\n%s %s\n%s\n", + port, "\tIf this server is no longer running, remove", + LockFile, "\tand start again."); + } + } + } + unlink(tmp); + if (!haslock) + FatalError("Could not create server lock file: %s\n", LockFile); + StillLocking = FALSE; +} + +/* + * UnlockServer -- + * Remove the server lock file. + */ +void +UnlockServer(void) +{ + if (nolock) return; + + if (!StillLocking){ + + (void) unlink(LockFile); + } +} + +/* Force connections to close on SIGHUP from init */ + +void +AutoResetServer (int sig) +{ + int olderrno = errno; + + dispatchException |= DE_RESET; + isItTimeToYield = TRUE; + errno = olderrno; +} + +/* Force connections to close and then exit on SIGTERM, SIGINT */ + +void +GiveUp(int sig) +{ + int olderrno = errno; + + dispatchException |= DE_TERMINATE; + isItTimeToYield = TRUE; + errno = olderrno; +} + +#if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__) +CARD32 +GetTimeInMillis (void) +{ + return GetTickCount (); +} +#else +CARD32 +GetTimeInMillis(void) +{ + struct timeval tv; + +#ifdef MONOTONIC_CLOCK + struct timespec tp; + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) + return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); +#endif + + X_GETTIMEOFDAY(&tv); + return(tv.tv_sec * 1000) + (tv.tv_usec / 1000); +} +#endif + +void +AdjustWaitForDelay (pointer waitTime, unsigned long newdelay) +{ + static struct timeval delay_val; + struct timeval **wt = (struct timeval **) waitTime; + unsigned long olddelay; + + if (*wt == NULL) + { + delay_val.tv_sec = newdelay / 1000; + delay_val.tv_usec = 1000 * (newdelay % 1000); + *wt = &delay_val; + } + else + { + olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000; + if (newdelay < olddelay) + { + (*wt)->tv_sec = newdelay / 1000; + (*wt)->tv_usec = 1000 * (newdelay % 1000); + } + } +} + +void UseMsg(void) +{ + ErrorF("use: X [:<display>] [option]\n"); + ErrorF("-a # default pointer acceleration (factor)\n"); + ErrorF("-ac disable access control restrictions\n"); + ErrorF("-audit int set audit trail level\n"); + ErrorF("-auth file select authorization file\n"); + ErrorF("-br create root window with black background\n"); + ErrorF("+bs enable any backing store support\n"); + ErrorF("-bs disable any backing store support\n"); + ErrorF("-c turns off key-click\n"); + ErrorF("c # key-click volume (0-100)\n"); + ErrorF("-cc int default color visual class\n"); + ErrorF("-nocursor disable the cursor\n"); + ErrorF("-core generate core dump on fatal error\n"); + ErrorF("-dpi int screen resolution in dots per inch\n"); +#ifdef DPMSExtension + ErrorF("-dpms disables VESA DPMS monitor control\n"); +#endif + ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); + ErrorF("-f # bell base (0-100)\n"); + ErrorF("-fc string cursor font\n"); + ErrorF("-fn string default font name\n"); + ErrorF("-fp string default font path\n"); + ErrorF("-help prints message with these options\n"); + ErrorF("-I ignore all remaining arguments\n"); +#ifdef RLIMIT_DATA + ErrorF("-ld int limit data space to N Kb\n"); +#endif +#ifdef RLIMIT_NOFILE + ErrorF("-lf int limit number of open files to N\n"); +#endif +#ifdef RLIMIT_STACK + ErrorF("-ls int limit stack space to N Kb\n"); +#endif + ErrorF("-nolock disable the locking mechanism\n"); +#ifndef NOLOGOHACK + ErrorF("-logo enable logo in screen saver\n"); + ErrorF("nologo disable logo in screen saver\n"); +#endif + ErrorF("-nolisten string don't listen on protocol\n"); + ErrorF("-noreset don't reset after last client exists\n"); + ErrorF("-reset reset after last client exists\n"); + ErrorF("-p # screen-saver pattern duration (minutes)\n"); + ErrorF("-pn accept failure to listen on all ports\n"); + ErrorF("-nopn reject failure to listen on all ports\n"); + ErrorF("-r turns off auto-repeat\n"); + ErrorF("r turns on auto-repeat \n"); + ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); + ErrorF("-retro start with classic stipple and cursor\n"); + ErrorF("-s # screen-saver timeout (minutes)\n"); + ErrorF("-t # default pointer threshold (pixels/t)\n"); + ErrorF("-terminate terminate at server reset\n"); + ErrorF("-to # connection time out\n"); + ErrorF("-tst disable testing extensions\n"); + ErrorF("ttyxx server started from init on /dev/ttyxx\n"); + ErrorF("v video blanking for screen-saver\n"); + ErrorF("-v screen-saver without video blanking\n"); + ErrorF("-wm WhenMapped default backing-store\n"); + ErrorF("-wr create root window with white background\n"); + ErrorF("-maxbigreqsize set maximal bigrequest size \n"); +#ifdef PANORAMIX + ErrorF("+xinerama Enable XINERAMA extension\n"); + ErrorF("-xinerama Disable XINERAMA extension\n"); +#endif + ErrorF("-dumbSched Disable smart scheduling, enable old behavior\n"); + ErrorF("-schedInterval int Set scheduler interval in msec\n"); + ErrorF("+extension name Enable extension\n"); + ErrorF("-extension name Disable extension\n"); +#ifdef XDMCP + XdmcpUseMsg(); +#endif + XkbUseMsg(); + ddxUseMsg(); +} + +/* This function performs a rudimentary sanity check + * on the display name passed in on the command-line, + * since this string is used to generate filenames. + * It is especially important that the display name + * not contain a "/" and not start with a "-". + * --kvajk + */ +static int +VerifyDisplayName(const char *d) +{ + if ( d == (char *)0 ) return( 0 ); /* null */ + if ( *d == '\0' ) return( 0 ); /* empty */ + if ( *d == '-' ) return( 0 ); /* could be confused for an option */ + if ( *d == '.' ) return( 0 ); /* must not equal "." or ".." */ + if ( strchr(d, '/') != (char *)0 ) return( 0 ); /* very important!!! */ + return( 1 ); +} + +/* + * This function parses the command line. Handles device-independent fields + * and allows ddx to handle additional fields. It is not allowed to modify + * argc or any of the strings pointed to by argv. + */ +void +ProcessCommandLine(int argc, char *argv[]) +{ + int i, skip; + + defaultKeyboardControl.autoRepeat = TRUE; + +#ifdef NO_PART_NET + PartialNetwork = FALSE; +#else + PartialNetwork = TRUE; +#endif + + for ( i = 1; i < argc; i++ ) + { + /* call ddx first, so it can peek/override if it wants */ + if((skip = ddxProcessArgument(argc, argv, i))) + { + i += (skip - 1); + } + else if(argv[i][0] == ':') + { + /* initialize display */ + display = argv[i]; + display++; + if( ! VerifyDisplayName( display ) ) { + ErrorF("Bad display name: %s\n", display); + UseMsg(); + FatalError("Bad display name, exiting: %s\n", display); + } + } + else if ( strcmp( argv[i], "-a") == 0) + { + if(++i < argc) + defaultPointerControl.num = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-ac") == 0) + { + defeatAccessControl = TRUE; + } + else if ( strcmp( argv[i], "-audit") == 0) + { + if(++i < argc) + auditTrailLevel = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-auth") == 0) + { + if(++i < argc) + InitAuthorization (argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-br") == 0) ; /* default */ + else if ( strcmp( argv[i], "+bs") == 0) + enableBackingStore = TRUE; + else if ( strcmp( argv[i], "-bs") == 0) + disableBackingStore = TRUE; + else if ( strcmp( argv[i], "c") == 0) + { + if(++i < argc) + defaultKeyboardControl.click = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-c") == 0) + { + defaultKeyboardControl.click = 0; + } + else if ( strcmp( argv[i], "-cc") == 0) + { + if(++i < argc) + defaultColorVisualClass = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-core") == 0) + { +#if !defined(WIN32) || !defined(__MINGW32__) + struct rlimit core_limit; + getrlimit (RLIMIT_CORE, &core_limit); + core_limit.rlim_cur = core_limit.rlim_max; + setrlimit (RLIMIT_CORE, &core_limit); +#endif + CoreDump = TRUE; + } + else if ( strcmp( argv[i], "-nocursor") == 0) + { + EnableCursor = FALSE; + } + else if ( strcmp( argv[i], "-dpi") == 0) + { + if(++i < argc) + monitorResolution = atoi(argv[i]); + else + UseMsg(); + } +#ifdef DPMSExtension + else if ( strcmp( argv[i], "dpms") == 0) + /* ignored for compatibility */ ; + else if ( strcmp( argv[i], "-dpms") == 0) + DPMSDisabledSwitch = TRUE; +#endif + else if ( strcmp( argv[i], "-deferglyphs") == 0) + { + if(++i >= argc || !ParseGlyphCachingMode(argv[i])) + UseMsg(); + } + else if ( strcmp( argv[i], "-f") == 0) + { + if(++i < argc) + defaultKeyboardControl.bell = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fc") == 0) + { + if(++i < argc) + defaultCursorFont = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fn") == 0) + { + if(++i < argc) + defaultTextFont = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fp") == 0) + { + if(++i < argc) + { + defaultFontPath = argv[i]; + } + else + UseMsg(); + } + else if ( strcmp( argv[i], "-help") == 0) + { + UseMsg(); + exit(0); + } + else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) { + if (skip>0) + i+= skip-1; + else UseMsg(); + } +#ifdef RLIMIT_DATA + else if ( strcmp( argv[i], "-ld") == 0) + { + if(++i < argc) + { + limitDataSpace = atoi(argv[i]); + if (limitDataSpace > 0) + limitDataSpace *= 1024; + } + else + UseMsg(); + } +#endif +#ifdef RLIMIT_NOFILE + else if ( strcmp( argv[i], "-lf") == 0) + { + if(++i < argc) + limitNoFile = atoi(argv[i]); + else + UseMsg(); + } +#endif +#ifdef RLIMIT_STACK + else if ( strcmp( argv[i], "-ls") == 0) + { + if(++i < argc) + { + limitStackSpace = atoi(argv[i]); + if (limitStackSpace > 0) + limitStackSpace *= 1024; + } + else + UseMsg(); + } +#endif + else if ( strcmp ( argv[i], "-nolock") == 0) + { +#if !defined(WIN32) && !defined(__CYGWIN__) + if (getuid() != 0) + ErrorF("Warning: the -nolock option can only be used by root\n"); + else +#endif + nolock = TRUE; + } +#ifndef NOLOGOHACK + else if ( strcmp( argv[i], "-logo") == 0) + { + logoScreenSaver = 1; + } + else if ( strcmp( argv[i], "nologo") == 0) + { + logoScreenSaver = 0; + } +#endif + else if ( strcmp( argv[i], "-nolisten") == 0) + { + if(++i < argc) { + if (_XSERVTransNoListen(argv[i])) + FatalError ("Failed to disable listen for %s transport", + argv[i]); + } else + UseMsg(); + } + else if ( strcmp( argv[i], "-noreset") == 0) + { + dispatchExceptionAtReset = 0; + } + else if ( strcmp( argv[i], "-reset") == 0) + { + dispatchExceptionAtReset = DE_RESET; + } + else if ( strcmp( argv[i], "-p") == 0) + { + if(++i < argc) + defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) * + MILLI_PER_MIN; + else + UseMsg(); + } + else if (strcmp(argv[i], "-pogo") == 0) + { + dispatchException = DE_TERMINATE; + } + else if ( strcmp( argv[i], "-pn") == 0) + PartialNetwork = TRUE; + else if ( strcmp( argv[i], "-nopn") == 0) + PartialNetwork = FALSE; + else if ( strcmp( argv[i], "r") == 0) + defaultKeyboardControl.autoRepeat = TRUE; + else if ( strcmp( argv[i], "-r") == 0) + defaultKeyboardControl.autoRepeat = FALSE; + else if ( strcmp( argv[i], "-retro") == 0) + party_like_its_1989 = TRUE; + else if ( strcmp( argv[i], "-s") == 0) + { + if(++i < argc) + defaultScreenSaverTime = ((CARD32)atoi(argv[i])) * + MILLI_PER_MIN; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-t") == 0) + { + if(++i < argc) + defaultPointerControl.threshold = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-terminate") == 0) + { + dispatchExceptionAtReset = DE_TERMINATE; + } + else if ( strcmp( argv[i], "-to") == 0) + { + if(++i < argc) + TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-tst") == 0) + { + noTestExtensions = TRUE; + } + else if ( strcmp( argv[i], "v") == 0) + defaultScreenSaverBlanking = PreferBlanking; + else if ( strcmp( argv[i], "-v") == 0) + defaultScreenSaverBlanking = DontPreferBlanking; + else if ( strcmp( argv[i], "-wm") == 0) + defaultBackingStore = WhenMapped; + else if ( strcmp( argv[i], "-wr") == 0) + whiteRoot = TRUE; + else if ( strcmp( argv[i], "-maxbigreqsize") == 0) { + if(++i < argc) { + long reqSizeArg = atol(argv[i]); + + /* Request size > 128MB does not make much sense... */ + if( reqSizeArg > 0L && reqSizeArg < 128L ) { + maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; + } + else + { + UseMsg(); + } + } + else + { + UseMsg(); + } + } +#ifdef PANORAMIX + else if ( strcmp( argv[i], "+xinerama") == 0){ + noPanoramiXExtension = FALSE; + } + else if ( strcmp( argv[i], "-xinerama") == 0){ + noPanoramiXExtension = TRUE; + } + else if ( strcmp( argv[i], "-disablexineramaextension") == 0){ + PanoramiXExtensionDisabledHack = TRUE; + } +#endif + else if ( strcmp( argv[i], "-I") == 0) + { + /* ignore all remaining arguments */ + break; + } + else if (strncmp (argv[i], "tty", 3) == 0) + { + /* just in case any body is interested */ + dev_tty_from_init = argv[i]; + } +#ifdef XDMCP + else if ((skip = XdmcpOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif + else if ( strcmp( argv[i], "-dumbSched") == 0) + { + SmartScheduleDisable = TRUE; + } + else if ( strcmp( argv[i], "-schedInterval") == 0) + { + if (++i < argc) + { + SmartScheduleInterval = atoi(argv[i]); + SmartScheduleSlice = SmartScheduleInterval; + } + else + UseMsg(); + } + else if ( strcmp( argv[i], "-schedMax") == 0) + { + if (++i < argc) + { + SmartScheduleMaxSlice = atoi(argv[i]); + } + else + UseMsg(); + } + else if ( strcmp( argv[i], "-render" ) == 0) + { + if (++i < argc) + { + int policy = PictureParseCmapPolicy (argv[i]); + + if (policy != PictureCmapPolicyInvalid) + PictureCmapPolicy = policy; + else + UseMsg (); + } + else + UseMsg (); + } + else if ( strcmp( argv[i], "+extension") == 0) + { + if (++i < argc) + { + if (!EnableDisableExtension(argv[i], TRUE)) + EnableDisableExtensionError(argv[i], TRUE); + } + else + UseMsg(); + } + else if ( strcmp( argv[i], "-extension") == 0) + { + if (++i < argc) + { + if (!EnableDisableExtension(argv[i], FALSE)) + EnableDisableExtensionError(argv[i], FALSE); + } + else + UseMsg(); + } + else + { + ErrorF("Unrecognized option: %s\n", argv[i]); + UseMsg(); + FatalError("Unrecognized option: %s\n", argv[i]); + } + } +} + +/* Implement a simple-minded font authorization scheme. The authorization + name is "hp-hostname-1", the contents are simply the host name. */ +int +set_font_authorizations(char **authorizations, int *authlen, pointer client) +{ +#define AUTHORIZATION_NAME "hp-hostname-1" +#if defined(TCPCONN) || defined(STREAMSCONN) + static char *result = NULL; + static char *p = NULL; + + if (p == NULL) + { + char hname[1024], *hnameptr; + unsigned int len; +#if defined(IPv6) && defined(AF_INET6) + struct addrinfo hints, *ai = NULL; +#else + struct hostent *host; +#ifdef XTHREADS_NEEDS_BYNAMEPARAMS + _Xgethostbynameparams hparams; +#endif +#endif + + gethostname(hname, 1024); +#if defined(IPv6) && defined(AF_INET6) + bzero(&hints, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { + hnameptr = ai->ai_canonname; + } else { + hnameptr = hname; + } +#else + host = _XGethostbyname(hname, hparams); + if (host == NULL) + hnameptr = hname; + else + hnameptr = host->h_name; +#endif + + len = strlen(hnameptr) + 1; + result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); + + p = result; + *p++ = sizeof(AUTHORIZATION_NAME) >> 8; + *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; + *p++ = (len) >> 8; + *p++ = (len & 0xff); + + memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); + p += sizeof(AUTHORIZATION_NAME); + memmove(p, hnameptr, len); + p += len; +#if defined(IPv6) && defined(AF_INET6) + if (ai) { + freeaddrinfo(ai); + } +#endif + } + *authlen = p - result; + *authorizations = result; + return 1; +#else /* TCPCONN */ + return 0; +#endif /* TCPCONN */ +} + +void * +Xalloc(unsigned long amount) +{ + /* + * Xalloc used to return NULL when large amount of memory is requested. In + * order to catch the buggy callers this warning has been added, slated to + * removal by anyone who touches this code (or just looks at it) in 2011. + * + * -- Mikhail Gusarov + */ + if ((long)amount <= 0) + ErrorF("Warning: Xalloc: " + "requesting unpleasantly large amount of memory: %lu bytes.\n", + amount); + + return malloc(amount); +} + +void * +XNFalloc(unsigned long amount) +{ + void *ptr = malloc(amount); + if (!ptr) + FatalError("Out of memory"); + return ptr; +} + +void * +Xcalloc(unsigned long amount) +{ + return calloc(1, amount); +} + +void * +XNFcalloc(unsigned long amount) +{ + void *ret = calloc(1, amount); + if (!ret) + FatalError("XNFcalloc: Out of memory"); + return ret; +} + +void * +Xrealloc(void *ptr, unsigned long amount) +{ + /* + * Xrealloc used to return NULL when large amount of memory is requested. In + * order to catch the buggy callers this warning has been added, slated to + * removal by anyone who touches this code (or just looks at it) in 2011. + * + * -- Mikhail Gusarov + */ + if ((long)amount <= 0) + ErrorF("Warning: Xrealloc: " + "requesting unpleasantly large amount of memory: %lu bytes.\n", + amount); + + return realloc(ptr, amount); +} + +void * +XNFrealloc(void *ptr, unsigned long amount) +{ + void *ret = realloc(ptr, amount); + if (!ret) + FatalError("XNFrealloc: Out of memory"); + return ret; +} + +void +Xfree(void *ptr) +{ + free(ptr); +} + + +char * +Xstrdup(const char *s) +{ + if (s == NULL) + return NULL; + return strdup(s); +} + +char * +XNFstrdup(const char *s) +{ + char *ret; + + if (s == NULL) + return NULL; + + ret = strdup(s); + if (!ret) + FatalError("XNFstrdup: Out of memory"); + return ret; +} + + +#ifdef SIGVTALRM +#define SMART_SCHEDULE_POSSIBLE +#endif + +#ifdef SMART_SCHEDULE_POSSIBLE +#define SMART_SCHEDULE_SIGNAL SIGALRM +#define SMART_SCHEDULE_TIMER ITIMER_REAL +#endif + +void +SmartScheduleStopTimer (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct itimerval timer; + + if (SmartScheduleDisable) + return; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = 0; + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = 0; + (void) setitimer (ITIMER_REAL, &timer, 0); +#endif +} + +void +SmartScheduleStartTimer (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct itimerval timer; + + if (SmartScheduleDisable) + return; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = SmartScheduleInterval * 1000; + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = SmartScheduleInterval * 1000; + setitimer (ITIMER_REAL, &timer, 0); +#endif +} + +#ifdef SMART_SCHEDULE_POSSIBLE +static void +SmartScheduleTimer (int sig) +{ + SmartScheduleTime += SmartScheduleInterval; +} +#endif + +Bool +SmartScheduleInit (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct sigaction act; + + if (SmartScheduleDisable) + return TRUE; + + bzero ((char *) &act, sizeof(struct sigaction)); + + /* Set up the timer signal function */ + act.sa_handler = SmartScheduleTimer; + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SMART_SCHEDULE_SIGNAL); + if (sigaction (SMART_SCHEDULE_SIGNAL, &act, 0) < 0) + { + perror ("sigaction for smart scheduler"); + return FALSE; + } + return TRUE; +#else + return FALSE; +#endif +} + +#ifdef SIG_BLOCK +static sigset_t PreviousSignalMask; +static int BlockedSignalCount; +#endif + +void +OsBlockSignals (void) +{ +#ifdef SIG_BLOCK + if (BlockedSignalCount++ == 0) + { + sigset_t set; + + sigemptyset (&set); +#ifdef SIGALRM + sigaddset (&set, SIGALRM); +#endif +#ifdef SIGVTALRM + sigaddset (&set, SIGVTALRM); +#endif +#ifdef SIGWINCH + sigaddset (&set, SIGWINCH); +#endif +#ifdef SIGIO + sigaddset (&set, SIGIO); +#endif +#ifdef SIGTSTP + sigaddset (&set, SIGTSTP); +#endif +#ifdef SIGTTIN + sigaddset (&set, SIGTTIN); +#endif +#ifdef SIGTTOU + sigaddset (&set, SIGTTOU); +#endif +#ifdef SIGCHLD + sigaddset (&set, SIGCHLD); +#endif + sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask); + } +#endif +} + +void +OsReleaseSignals (void) +{ +#ifdef SIG_BLOCK + if (--BlockedSignalCount == 0) + { + sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0); + } +#endif +} + +/* + * Pending signals may interfere with core dumping. Provide a + * mechanism to block signals when aborting. + */ + +void +OsAbort (void) +{ +#ifndef __APPLE__ + OsBlockSignals(); +#endif + abort(); +} + +#if !defined(WIN32) +/* + * "safer" versions of system(3), popen(3) and pclose(3) which give up + * all privs before running a command. + * + * This is based on the code in FreeBSD 2.2 libc. + * + * XXX It'd be good to redirect stderr so that it ends up in the log file + * as well. As it is now, xkbcomp messages don't end up in the log file. + */ + +int +System(char *command) +{ + int pid, p; +#ifdef SIGCHLD + void (*csig)(int); +#endif + int status; + + if (!command) + return(1); + +#ifdef SIGCHLD + csig = signal(SIGCHLD, SIG_DFL); + if (csig == SIG_ERR) { + perror("signal"); + return -1; + } +#endif + +#ifdef DEBUG + ErrorF("System: `%s'\n", command); +#endif + + switch (pid = fork()) { + case -1: /* error */ + p = -1; + case 0: /* child */ + if (setgid(getgid()) == -1) + _exit(127); + if (setuid(getuid()) == -1) + _exit(127); + execl("/bin/sh", "sh", "-c", command, (char *)NULL); + _exit(127); + default: /* parent */ + do { + p = waitpid(pid, &status, 0); + } while (p == -1 && errno == EINTR); + + } + +#ifdef SIGCHLD + if (signal(SIGCHLD, csig) == SIG_ERR) { + perror("signal"); + return -1; + } +#endif + + return p == -1 ? -1 : status; +} + +static struct pid { + struct pid *next; + FILE *fp; + int pid; +} *pidlist; + +OsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */ + +pointer +Popen(char *command, char *type) +{ + struct pid *cur; + FILE *iop; + int pdes[2], pid; + + if (command == NULL || type == NULL) + return NULL; + + if ((*type != 'r' && *type != 'w') || type[1]) + return NULL; + + if ((cur = malloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + free(cur); + return NULL; + } + + /* Ignore the smart scheduler while this is going on */ + old_alarm = OsSignal(SIGALRM, SIG_IGN); + if (old_alarm == SIG_ERR) { + perror("signal"); + return NULL; + } + + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + free(cur); + if (OsSignal(SIGALRM, old_alarm) == SIG_ERR) + perror("signal"); + return NULL; + case 0: /* child */ + if (setgid(getgid()) == -1) + _exit(127); + if (setuid(getuid()) == -1) + _exit(127); + if (*type == 'r') { + if (pdes[1] != 1) { + /* stdout */ + dup2(pdes[1], 1); + close(pdes[1]); + } + close(pdes[0]); + } else { + if (pdes[0] != 0) { + /* stdin */ + dup2(pdes[0], 0); + close(pdes[0]); + } + close(pdes[1]); + } + execl("/bin/sh", "sh", "-c", command, (char *)NULL); + _exit(127); + } + + /* Avoid EINTR during stdio calls */ + OsBlockSignals (); + + /* parent */ + if (*type == 'r') { + iop = fdopen(pdes[0], type); + close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); + close(pdes[0]); + } + + cur->fp = iop; + cur->pid = pid; + cur->next = pidlist; + pidlist = cur; + +#ifdef DEBUG + ErrorF("Popen: `%s', fp = %p\n", command, iop); +#endif + + return iop; +} + +/* fopen that drops privileges */ +pointer +Fopen(char *file, char *type) +{ + FILE *iop; +#ifndef HAS_SAVED_IDS_AND_SETEUID + struct pid *cur; + int pdes[2], pid; + + if (file == NULL || type == NULL) + return NULL; + + if ((*type != 'r' && *type != 'w') || type[1]) + return NULL; + + if ((cur = malloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + free(cur); + return NULL; + } + + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + free(cur); + return NULL; + case 0: /* child */ + if (setgid(getgid()) == -1) + _exit(127); + if (setuid(getuid()) == -1) + _exit(127); + if (*type == 'r') { + if (pdes[1] != 1) { + /* stdout */ + dup2(pdes[1], 1); + close(pdes[1]); + } + close(pdes[0]); + } else { + if (pdes[0] != 0) { + /* stdin */ + dup2(pdes[0], 0); + close(pdes[0]); + } + close(pdes[1]); + } + execl("/bin/cat", "cat", file, (char *)NULL); + _exit(127); + } + + /* Avoid EINTR during stdio calls */ + OsBlockSignals (); + + /* parent */ + if (*type == 'r') { + iop = fdopen(pdes[0], type); + close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); + close(pdes[0]); + } + + cur->fp = iop; + cur->pid = pid; + cur->next = pidlist; + pidlist = cur; + +#ifdef DEBUG + ErrorF("Fopen(%s), fp = %p\n", file, iop); +#endif + + return iop; +#else + int ruid, euid; + + ruid = getuid(); + euid = geteuid(); + + if (seteuid(ruid) == -1) { + return NULL; + } + iop = fopen(file, type); + + if (seteuid(euid) == -1) { + fclose(iop); + return NULL; + } + return iop; +#endif /* HAS_SAVED_IDS_AND_SETEUID */ +} + +int +Pclose(pointer iop) +{ + struct pid *cur, *last; + int pstat; + int pid; + +#ifdef DEBUG + ErrorF("Pclose: fp = %p\n", iop); +#endif + + fclose(iop); + + for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) + if (cur->fp == iop) + break; + if (cur == NULL) + return -1; + + do { + pid = waitpid(cur->pid, &pstat, 0); + } while (pid == -1 && errno == EINTR); + + if (last == NULL) + pidlist = cur->next; + else + last->next = cur->next; + free(cur); + + /* allow EINTR again */ + OsReleaseSignals (); + + if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) { + perror("signal"); + return -1; + } + + return pid == -1 ? -1 : pstat; +} + +int +Fclose(pointer iop) +{ +#ifdef HAS_SAVED_IDS_AND_SETEUID + return fclose(iop); +#else + return Pclose(iop); +#endif +} + +#endif /* !WIN32 */ + + +/* + * CheckUserParameters: check for long command line arguments and long + * environment variables. By default, these checks are only done when + * the server's euid != ruid. In 3.3.x, these checks were done in an + * external wrapper utility. + */ + +/* Consider LD* variables insecure? */ +#ifndef REMOVE_ENV_LD +#define REMOVE_ENV_LD 1 +#endif + +/* Remove long environment variables? */ +#ifndef REMOVE_LONG_ENV +#define REMOVE_LONG_ENV 1 +#endif + +/* + * Disallow stdout or stderr as pipes? It's possible to block the X server + * when piping stdout+stderr to a pipe. + * + * Don't enable this because it looks like it's going to cause problems. + */ +#ifndef NO_OUTPUT_PIPES +#define NO_OUTPUT_PIPES 0 +#endif + + +/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ +#ifndef CHECK_EUID +#ifndef WIN32 +#define CHECK_EUID 1 +#else +#define CHECK_EUID 0 +#endif +#endif + +/* + * Maybe the locale can be faked to make isprint(3) report that everything + * is printable? Avoid it by default. + */ +#ifndef USE_ISPRINT +#define USE_ISPRINT 0 +#endif + +#define MAX_ARG_LENGTH 128 +#define MAX_ENV_LENGTH 256 +#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ + +#if USE_ISPRINT +#include <ctype.h> +#define checkPrintable(c) isprint(c) +#else +#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) +#endif + +enum BadCode { + NotBad = 0, + UnsafeArg, + ArgTooLong, + UnprintableArg, + EnvTooLong, + OutputIsPipe, + InternalError +}; + +#if defined(VENDORSUPPORT) +#define BUGADDRESS VENDORSUPPORT +#elif defined(BUILDERADDR) +#define BUGADDRESS BUILDERADDR +#else +#define BUGADDRESS "xorg@freedesktop.org" +#endif + +void +CheckUserParameters(int argc, char **argv, char **envp) +{ + enum BadCode bad = NotBad; + int i = 0, j; + char *a, *e = NULL; + +#if CHECK_EUID + if (geteuid() == 0 && getuid() != geteuid()) +#endif + { + /* Check each argv[] */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-fp") == 0) + { + i++; /* continue with next argument. skip the length check */ + if (i >= argc) + break; + } else + { + if (strlen(argv[i]) > MAX_ARG_LENGTH) { + bad = ArgTooLong; + break; + } + } + a = argv[i]; + while (*a) { + if (checkPrintable(*a) == 0) { + bad = UnprintableArg; + break; + } + a++; + } + if (bad) + break; + } + if (!bad) { + /* Check each envp[] */ + for (i = 0; envp[i]; i++) { + + /* Check for bad environment variables and values */ +#if REMOVE_ENV_LD + while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { + for (j = i; envp[j]; j++) { + envp[j] = envp[j+1]; + } + } +#endif + if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { +#if REMOVE_LONG_ENV + for (j = i; envp[j]; j++) { + envp[j] = envp[j+1]; + } + i--; +#else + char *eq; + int len; + + eq = strchr(envp[i], '='); + if (!eq) + continue; + len = eq - envp[i]; + e = malloc(len + 1); + if (!e) { + bad = InternalError; + break; + } + strncpy(e, envp[i], len); + e[len] = 0; + if (len >= 4 && + (strcmp(e + len - 4, "PATH") == 0 || + strcmp(e, "TERMCAP") == 0)) { + if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { + bad = EnvTooLong; + break; + } else { + free(e); + } + } else { + bad = EnvTooLong; + break; + } +#endif + } + } + } +#if NO_OUTPUT_PIPES + if (!bad) { + struct stat buf; + + if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) + bad = OutputIsPipe; + if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) + bad = OutputIsPipe; + } +#endif + } + switch (bad) { + case NotBad: + return; + case UnsafeArg: + ErrorF("Command line argument number %d is unsafe\n", i); + break; + case ArgTooLong: + ErrorF("Command line argument number %d is too long\n", i); + break; + case UnprintableArg: + ErrorF("Command line argument number %d contains unprintable" + " characters\n", i); + break; + case EnvTooLong: + ErrorF("Environment variable `%s' is too long\n", e); + break; + case OutputIsPipe: + ErrorF("Stdout and/or stderr is a pipe\n"); + break; + case InternalError: + ErrorF("Internal Error\n"); + break; + default: + ErrorF("Unknown error\n"); + break; + } + FatalError("X server aborted because of unsafe environment\n"); +} + +/* + * CheckUserAuthorization: check if the user is allowed to start the + * X server. This usually means some sort of PAM checking, and it is + * usually only done for setuid servers (uid != euid). + */ + +#ifdef USE_PAM +#include <security/pam_appl.h> +#include <security/pam_misc.h> +#include <pwd.h> +#endif /* USE_PAM */ + +void +CheckUserAuthorization(void) +{ +#ifdef USE_PAM + static struct pam_conv conv = { + misc_conv, + NULL + }; + + pam_handle_t *pamh = NULL; + struct passwd *pw; + int retval; + + if (getuid() != geteuid()) { + pw = getpwuid(getuid()); + if (pw == NULL) + FatalError("getpwuid() failed for uid %d\n", getuid()); + + retval = pam_start("xserver", pw->pw_name, &conv, &pamh); + if (retval != PAM_SUCCESS) + FatalError("pam_start() failed.\n" + "\tMissing or mangled PAM config file or module?\n"); + + retval = pam_authenticate(pamh, 0); + if (retval != PAM_SUCCESS) { + pam_end(pamh, retval); + FatalError("PAM authentication failed, cannot start X server.\n" + "\tPerhaps you do not have console ownership?\n"); + } + + retval = pam_acct_mgmt(pamh, 0); + if (retval != PAM_SUCCESS) { + pam_end(pamh, retval); + FatalError("PAM authentication failed, cannot start X server.\n" + "\tPerhaps you do not have console ownership?\n"); + } + + /* this is not a session, so do not do session management */ + pam_end(pamh, PAM_SUCCESS); + } +#endif +} + +/* + * Tokenize a string into a NULL terminated array of strings. Always returns + * an allocated array unless an error occurs. + */ +char** +xstrtokenize(const char *str, const char *separators) +{ + char **list, **nlist; + char *tok, *tmp; + unsigned num = 0, n; + + if (!str) + return NULL; + list = calloc(1, sizeof(*list)); + if (!list) + return NULL; + tmp = strdup(str); + if (!tmp) + goto error; + for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { + nlist = realloc(list, (num + 2) * sizeof(*list)); + if (!nlist) + goto error; + list = nlist; + list[num] = strdup(tok); + if (!list[num]) + goto error; + list[++num] = NULL; + } + free(tmp); + return list; + +error: + free(tmp); + for (n = 0; n < num; n++) + free(list[n]); + free(list); + return NULL; +} + +#ifdef __SCO__ +#include <fcntl.h> + +static void +lockit (int fd, short what) +{ + struct flock lck; + + lck.l_whence = 0; + lck.l_start = 0; + lck.l_len = 1; + lck.l_type = what; + + (void)fcntl (fd, F_SETLKW, &lck); +} + +/* SCO OpenServer 5 lacks pread/pwrite. Emulate them. */ +ssize_t +pread (int fd, void *buf, size_t nbytes, off_t offset) +{ + off_t saved; + ssize_t ret; + + lockit (fd, F_RDLCK); + saved = lseek (fd, 0, SEEK_CUR); + lseek (fd, offset, SEEK_SET); + ret = read (fd, buf, nbytes); + lseek (fd, saved, SEEK_SET); + lockit (fd, F_UNLCK); + + return ret; +} + +ssize_t +pwrite (int fd, const void *buf, size_t nbytes, off_t offset) +{ + off_t saved; + ssize_t ret; + + lockit (fd, F_WRLCK); + saved = lseek (fd, 0, SEEK_CUR); + lseek (fd, offset, SEEK_SET); + ret = write (fd, buf, nbytes); + lseek (fd, saved, SEEK_SET); + lockit (fd, F_UNLCK); + + return ret; +} +#endif /* __SCO__ */ diff --git a/xorg-server/os/xdmauth.c b/xorg-server/os/xdmauth.c index 7834b56f8..b58d1d7cc 100644 --- a/xorg-server/os/xdmauth.c +++ b/xorg-server/os/xdmauth.c @@ -239,7 +239,7 @@ XdmClientAuthTimeout (long now) prev->next = next; else xdmClients = next; - xfree (client); + free(client); } else prev = client; @@ -259,20 +259,20 @@ XdmAuthorizationValidate (unsigned char *plain, int length, *reason = "Bad XDM authorization key length"; return NULL; } - client = xalloc (sizeof (XdmClientAuthRec)); + client = malloc(sizeof (XdmClientAuthRec)); if (!client) return NULL; XdmClientAuthDecode (plain, client); if (!XdmcpCompareKeys (&client->rho, rho)) { - xfree (client); + free(client); if (reason) *reason = "Invalid XDM-AUTHORIZATION-1 key (failed key comparison)"; return NULL; } for (i = 18; i < 24; i++) if (plain[i] != 0) { - xfree (client); + free(client); if (reason) *reason = "Invalid XDM-AUTHORIZATION-1 key (failed NULL check)"; return NULL; @@ -287,15 +287,15 @@ XdmAuthorizationValidate (unsigned char *plain, int length, #if defined(TCPCONN) || defined(STREAMSCONN) if (family == FamilyInternet && memcmp((char *)addr, client->client, 4) != 0) { - xfree (client); - xfree (addr); + free(client); + free(addr); if (reason) *reason = "Invalid XDM-AUTHORIZATION-1 key (failed address comparison)"; return NULL; } #endif - xfree (addr); + free(addr); } } now = time(0); @@ -308,7 +308,7 @@ XdmAuthorizationValidate (unsigned char *plain, int length, XdmClientAuthTimeout (now); if (abs (client->time - now) > TwentyMinutes) { - xfree (client); + free(client); if (reason) *reason = "Excessive XDM-AUTHORIZATION-1 time offset"; return NULL; @@ -317,7 +317,7 @@ XdmAuthorizationValidate (unsigned char *plain, int length, { if (XdmClientAuthCompare (existing, client)) { - xfree (client); + free(client); if (reason) *reason = "XDM authorization key matches an existing client!"; return NULL; @@ -363,7 +363,7 @@ XdmAddCookie (unsigned short data_length, const char *data, XID id) /* the first octet of the key must be zero */ if (key_bits[0] != '\0') return 0; - new = xalloc (sizeof (XdmAuthorizationRec)); + new = malloc(sizeof (XdmAuthorizationRec)); if (!new) return 0; new->next = xdmAuth; @@ -385,7 +385,7 @@ XdmCheckCookie (unsigned short cookie_length, const char *cookie, /* Auth packets must be a multiple of 8 bytes long */ if (cookie_length & 7) return (XID) -1; - plain = xalloc (cookie_length); + plain = malloc(cookie_length); if (!plain) return (XID) -1; for (auth = xdmAuth; auth; auth=auth->next) { @@ -394,11 +394,11 @@ XdmCheckCookie (unsigned short cookie_length, const char *cookie, { client->next = xdmClients; xdmClients = client; - xfree (plain); + free(plain); return auth->id; } } - xfree (plain); + free(plain); return (XID) -1; } @@ -411,13 +411,13 @@ XdmResetCookie (void) for (auth = xdmAuth; auth; auth=next_auth) { next_auth = auth->next; - xfree (auth); + free(auth); } xdmAuth = 0; for (client = xdmClients; client; client=next_client) { next_client = client->next; - xfree (client); + free(client); } xdmClients = (XdmClientAuthPtr) 0; return 1; @@ -430,21 +430,21 @@ XdmToID (unsigned short cookie_length, char *cookie) XdmClientAuthPtr client; unsigned char *plain; - plain = xalloc (cookie_length); + plain = malloc(cookie_length); if (!plain) return (XID) -1; for (auth = xdmAuth; auth; auth=auth->next) { XdmcpUnwrap ((unsigned char *)cookie, (unsigned char *)&auth->key, plain, cookie_length); if ((client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, NULL, NULL)) != NULL) { - xfree (client); - xfree (cookie); - xfree (plain); + free(client); + free(cookie); + free(plain); return auth->id; } } - xfree (cookie); - xfree (plain); + free(cookie); + free(plain); return (XID) -1; } @@ -489,7 +489,7 @@ XdmRemoveCookie (unsigned short data_length, const char *data) XdmcpCompareKeys (key_bits, &auth->key)) { xdmAuth = auth->next; - xfree (auth); + free(auth); return 1; } } diff --git a/xorg-server/os/xdmcp.c b/xorg-server/os/xdmcp.c index 436ec726e..0368102f6 100644 --- a/xorg-server/os/xdmcp.c +++ b/xorg-server/os/xdmcp.c @@ -391,7 +391,7 @@ XdmcpRegisterAuthentication ( AuthenticationNames.length + 1) && XdmcpReallocARRAYofARRAY8 (&AuthenticationDatas, AuthenticationDatas.length + 1) && - (newFuncs = xalloc ((AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec))))) + (newFuncs = malloc((AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec))))) { XdmcpDisposeARRAY8 (&AuthenticationName); XdmcpDisposeARRAY8 (&AuthenticationData); @@ -402,7 +402,7 @@ XdmcpRegisterAuthentication ( newFuncs[AuthenticationNames.length-1].Validator = Validator; newFuncs[AuthenticationNames.length-1].Generator = Generator; newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth; - xfree (AuthenticationFuncsList); + free(AuthenticationFuncsList); AuthenticationFuncsList = newFuncs; AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName; AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData; @@ -492,18 +492,18 @@ XdmcpRegisterConnection ( } if (ConnectionAddresses.length + 1 == 256) return; - newAddress = xalloc (addrlen * sizeof (CARD8)); + newAddress = malloc(addrlen * sizeof (CARD8)); if (!newAddress) return; if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1)) { - xfree (newAddress); + free(newAddress); return; } if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses, ConnectionAddresses.length + 1)) { - xfree (newAddress); + free(newAddress); return; } ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type; @@ -533,12 +533,12 @@ XdmcpRegisterAuthorization (const char *name, int namelen) ARRAY8 authName; int i; - authName.data = xalloc (namelen * sizeof (CARD8)); + authName.data = malloc(namelen * sizeof (CARD8)); if (!authName.data) return; if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1)) { - xfree (authName.data); + free(authName.data); return; } for (i = 0; i < namelen; i++) diff --git a/xorg-server/os/xprintf.c b/xorg-server/os/xprintf.c index 07eaa1f58..5a42df2d1 100644 --- a/xorg-server/os/xprintf.c +++ b/xorg-server/os/xprintf.c @@ -1,104 +1,104 @@ -/* - * printf routines which xalloc their buffer - */ -/* - * Copyright (c) 2004 Alexander Gottwald - * - * 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright - * holders shall not be used in advertising or otherwise to promote the sale, - * use or other dealings in this Software without prior written authorization. - */ -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <X11/Xos.h> -#include "os.h" -#include <stdarg.h> -#include <stdio.h> - -#ifndef va_copy -# ifdef __va_copy -# define va_copy __va_copy -# else -# error "no working va_copy was found" -# endif -#endif - -char * -Xvprintf(const char *format, va_list va) -{ - char *ret; - int size; - va_list va2; - - va_copy(va2, va); - size = vsnprintf(NULL, 0, format, va2); - va_end(va2); - - ret = (char *)Xalloc(size + 1); - if (ret == NULL) - return NULL; - - vsnprintf(ret, size + 1, format, va); - ret[size] = 0; - return ret; -} - -char *Xprintf(const char *format, ...) -{ - char *ret; - va_list va; - va_start(va, format); - ret = Xvprintf(format, va); - va_end(va); - return ret; -} - -char * -XNFvprintf(const char *format, va_list va) -{ - char *ret; - int size; - va_list va2; - - va_copy(va2, va); - size = vsnprintf(NULL, 0, format, va2); - va_end(va2); - - ret = (char *)XNFalloc(size + 1); - if (ret == NULL) - return NULL; - - vsnprintf(ret, size + 1, format, va); - ret[size] = 0; - return ret; -} - -char *XNFprintf(const char *format, ...) -{ - char *ret; - va_list va; - va_start(va, format); - ret = XNFvprintf(format, va); - va_end(va); - return ret; -} +/* + * printf routines which xalloc their buffer + */ +/* + * Copyright (c) 2004 Alexander Gottwald + * + * 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 ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/Xos.h> +#include "os.h" +#include <stdarg.h> +#include <stdio.h> + +#ifndef va_copy +# ifdef __va_copy +# define va_copy __va_copy +# else +# error "no working va_copy was found" +# endif +#endif + +char * +Xvprintf(const char *format, va_list va) +{ + char *ret; + int size; + va_list va2; + + va_copy(va2, va); + size = vsnprintf(NULL, 0, format, va2); + va_end(va2); + + ret = (char *)malloc(size + 1); + if (ret == NULL) + return NULL; + + vsnprintf(ret, size + 1, format, va); + ret[size] = 0; + return ret; +} + +char *Xprintf(const char *format, ...) +{ + char *ret; + va_list va; + va_start(va, format); + ret = Xvprintf(format, va); + va_end(va); + return ret; +} + +char * +XNFvprintf(const char *format, va_list va) +{ + char *ret; + int size; + va_list va2; + + va_copy(va2, va); + size = vsnprintf(NULL, 0, format, va2); + va_end(va2); + + ret = (char *)xnfalloc(size + 1); + if (ret == NULL) + return NULL; + + vsnprintf(ret, size + 1, format, va); + ret[size] = 0; + return ret; +} + +char *XNFprintf(const char *format, ...) +{ + char *ret; + va_list va; + va_start(va, format); + ret = XNFvprintf(format, va); + va_end(va); + return ret; +} diff --git a/xorg-server/os/xsha1.c b/xorg-server/os/xsha1.c index 355862fb1..518745b4c 100644 --- a/xorg-server/os/xsha1.c +++ b/xorg-server/os/xsha1.c @@ -1,168 +1,168 @@ -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "os.h" -#include "xsha1.h" - -#if defined(HAVE_SHA1_IN_LIBMD) /* Use libmd for SHA1 */ \ - || defined(HAVE_SHA1_IN_LIBC) /* Use libc for SHA1 */ - -# include <sha1.h> - -void *x_sha1_init(void) -{ - SHA1_CTX *ctx = xalloc(sizeof(*ctx)); - if (!ctx) - return NULL; - SHA1Init(ctx); - return ctx; -} - -int x_sha1_update(void *ctx, void *data, int size) -{ - SHA1_CTX *sha1_ctx = ctx; - SHA1Update(sha1_ctx, data, size); - return 1; -} - -int x_sha1_final(void *ctx, unsigned char result[20]) -{ - SHA1_CTX *sha1_ctx = ctx; - SHA1Final(result, sha1_ctx); - xfree(sha1_ctx); - return 1; -} - -#elif defined(HAVE_SHA1_IN_COMMONCRYPTO) /* Use CommonCrypto for SHA1 */ - -#include <CommonCrypto/CommonDigest.h> - -void *x_sha1_init(void) -{ - CC_SHA1_CTX *ctx = xalloc(sizeof(*ctx)); - if (!ctx) - return NULL; - CC_SHA1_Init(ctx); - return ctx; -} - -int x_sha1_update(void *ctx, void *data, int size) -{ - CC_SHA1_CTX *sha1_ctx = ctx; - CC_SHA1_Update(sha1_ctx, data, size); - return 1; -} - -int x_sha1_final(void *ctx, unsigned char result[20]) -{ - CC_SHA1_CTX *sha1_ctx = ctx; - CC_SHA1_Final(result, sha1_ctx); - xfree(sha1_ctx); - return 1; -} - -#elif defined(HAVE_SHA1_IN_LIBGCRYPT) /* Use libgcrypt for SHA1 */ - -# include <gcrypt.h> - -void *x_sha1_init(void) -{ - static int init; - gcry_md_hd_t h; - gcry_error_t err; - - if (!init) { - if (!gcry_check_version(NULL)) - return NULL; - gcry_control(GCRYCTL_DISABLE_SECMEM, 0); - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); - init = 1; - } - - err = gcry_md_open(&h, GCRY_MD_SHA1, 0); - if (err) - return NULL; - return h; -} - -int x_sha1_update(void *ctx, void *data, int size) -{ - gcry_md_hd_t h = ctx; - gcry_md_write(h, data, size); - return 1; -} - -int x_sha1_final(void *ctx, unsigned char result[20]) -{ - gcry_md_hd_t h = ctx; - memcpy(result, gcry_md_read(h, GCRY_MD_SHA1), 20); - gcry_md_close(h); - return 1; -} - -#elif defined(HAVE_SHA1_IN_LIBSHA1) /* Use libsha1 */ - -# include <libsha1.h> - -void *x_sha1_init(void) -{ - sha1_ctx *ctx = xalloc(sizeof(*ctx)); - if(!ctx) - return NULL; - sha1_begin(ctx); - return ctx; -} - -int x_sha1_update(void *ctx, void *data, int size) -{ - sha1_hash(data, size, ctx); - return 1; -} - -int x_sha1_final(void *ctx, unsigned char result[20]) -{ - sha1_end(result, ctx); - xfree(ctx); - return 1; -} - -#else /* Use OpenSSL's libcrypto */ - -# include <stddef.h> /* buggy openssl/sha.h wants size_t */ -# include <openssl/sha.h> - -void *x_sha1_init(void) -{ - int ret; - SHA_CTX *ctx = xalloc(sizeof(*ctx)); - if (!ctx) - return NULL; - ret = SHA1_Init(ctx); - if (!ret) { - xfree(ctx); - return NULL; - } - return ctx; -} - -int x_sha1_update(void *ctx, void *data, int size) -{ - int ret; - SHA_CTX *sha_ctx = ctx; - ret = SHA1_Update(sha_ctx, data, size); - if (!ret) - xfree(sha_ctx); - return ret; -} - -int x_sha1_final(void *ctx, unsigned char result[20]) -{ - int ret; - SHA_CTX *sha_ctx = ctx; - ret = SHA1_Final(result, sha_ctx); - xfree(sha_ctx); - return ret; -} - -#endif +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "os.h" +#include "xsha1.h" + +#if defined(HAVE_SHA1_IN_LIBMD) /* Use libmd for SHA1 */ \ + || defined(HAVE_SHA1_IN_LIBC) /* Use libc for SHA1 */ + +# include <sha1.h> + +void *x_sha1_init(void) +{ + SHA1_CTX *ctx = malloc(sizeof(*ctx)); + if (!ctx) + return NULL; + SHA1Init(ctx); + return ctx; +} + +int x_sha1_update(void *ctx, void *data, int size) +{ + SHA1_CTX *sha1_ctx = ctx; + SHA1Update(sha1_ctx, data, size); + return 1; +} + +int x_sha1_final(void *ctx, unsigned char result[20]) +{ + SHA1_CTX *sha1_ctx = ctx; + SHA1Final(result, sha1_ctx); + free(sha1_ctx); + return 1; +} + +#elif defined(HAVE_SHA1_IN_COMMONCRYPTO) /* Use CommonCrypto for SHA1 */ + +#include <CommonCrypto/CommonDigest.h> + +void *x_sha1_init(void) +{ + CC_SHA1_CTX *ctx = malloc(sizeof(*ctx)); + if (!ctx) + return NULL; + CC_SHA1_Init(ctx); + return ctx; +} + +int x_sha1_update(void *ctx, void *data, int size) +{ + CC_SHA1_CTX *sha1_ctx = ctx; + CC_SHA1_Update(sha1_ctx, data, size); + return 1; +} + +int x_sha1_final(void *ctx, unsigned char result[20]) +{ + CC_SHA1_CTX *sha1_ctx = ctx; + CC_SHA1_Final(result, sha1_ctx); + free(sha1_ctx); + return 1; +} + +#elif defined(HAVE_SHA1_IN_LIBGCRYPT) /* Use libgcrypt for SHA1 */ + +# include <gcrypt.h> + +void *x_sha1_init(void) +{ + static int init; + gcry_md_hd_t h; + gcry_error_t err; + + if (!init) { + if (!gcry_check_version(NULL)) + return NULL; + gcry_control(GCRYCTL_DISABLE_SECMEM, 0); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); + init = 1; + } + + err = gcry_md_open(&h, GCRY_MD_SHA1, 0); + if (err) + return NULL; + return h; +} + +int x_sha1_update(void *ctx, void *data, int size) +{ + gcry_md_hd_t h = ctx; + gcry_md_write(h, data, size); + return 1; +} + +int x_sha1_final(void *ctx, unsigned char result[20]) +{ + gcry_md_hd_t h = ctx; + memcpy(result, gcry_md_read(h, GCRY_MD_SHA1), 20); + gcry_md_close(h); + return 1; +} + +#elif defined(HAVE_SHA1_IN_LIBSHA1) /* Use libsha1 */ + +# include <libsha1.h> + +void *x_sha1_init(void) +{ + sha1_ctx *ctx = malloc(sizeof(*ctx)); + if(!ctx) + return NULL; + sha1_begin(ctx); + return ctx; +} + +int x_sha1_update(void *ctx, void *data, int size) +{ + sha1_hash(data, size, ctx); + return 1; +} + +int x_sha1_final(void *ctx, unsigned char result[20]) +{ + sha1_end(result, ctx); + free(ctx); + return 1; +} + +#else /* Use OpenSSL's libcrypto */ + +# include <stddef.h> /* buggy openssl/sha.h wants size_t */ +# include <openssl/sha.h> + +void *x_sha1_init(void) +{ + int ret; + SHA_CTX *ctx = malloc(sizeof(*ctx)); + if (!ctx) + return NULL; + ret = SHA1_Init(ctx); + if (!ret) { + free(ctx); + return NULL; + } + return ctx; +} + +int x_sha1_update(void *ctx, void *data, int size) +{ + int ret; + SHA_CTX *sha_ctx = ctx; + ret = SHA1_Update(sha_ctx, data, size); + if (!ret) + free(sha_ctx); + return ret; +} + +int x_sha1_final(void *ctx, unsigned char result[20]) +{ + int ret; + SHA_CTX *sha_ctx = ctx; + ret = SHA1_Final(result, sha_ctx); + free(sha_ctx); + return ret; +} + +#endif diff --git a/xorg-server/randr/randr.c b/xorg-server/randr/randr.c index b63a7f22e..b843f588d 100644 --- a/xorg-server/randr/randr.c +++ b/xorg-server/randr/randr.c @@ -1,496 +1,496 @@ -/* - * Copyright © 2000 Compaq Computer Corporation - * Copyright © 2002 Hewlett-Packard Company - * Copyright © 2006 Intel Corporation - * - * 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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. - * - * Author: Jim Gettys, Hewlett-Packard Company, Inc. - * Keith Packard, Intel Corporation - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "randrstr.h" - -/* From render.h */ -#ifndef SubPixelUnknown -#define SubPixelUnknown 0 -#endif - -#define RR_VALIDATE -static int RRNScreens; - -#define wrap(priv,real,mem,func) {\ - priv->mem = real->mem; \ - real->mem = func; \ -} - -#define unwrap(priv,real,mem) {\ - real->mem = priv->mem; \ -} - -static int ProcRRDispatch (ClientPtr pClient); -static int SProcRRDispatch (ClientPtr pClient); - -int RREventBase; -int RRErrorBase; -RESTYPE RRClientType, RREventType; /* resource types for event masks */ -static int RRClientPrivateKeyIndex; -DevPrivateKey RRClientPrivateKey = &RRClientPrivateKeyIndex; - -static int rrPrivKeyIndex; -DevPrivateKey rrPrivKey = &rrPrivKeyIndex; - -static void -RRClientCallback (CallbackListPtr *list, - pointer closure, - pointer data) -{ - NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; - ClientPtr pClient = clientinfo->client; - rrClientPriv(pClient); - RRTimesPtr pTimes = (RRTimesPtr) (pRRClient + 1); - int i; - - pRRClient->major_version = 0; - pRRClient->minor_version = 0; - for (i = 0; i < screenInfo.numScreens; i++) - { - ScreenPtr pScreen = screenInfo.screens[i]; - rrScrPriv(pScreen); - - if (pScrPriv) - { - pTimes[i].setTime = pScrPriv->lastSetTime; - pTimes[i].configTime = pScrPriv->lastConfigTime; - } - } -} - -static Bool -RRCloseScreen (int i, ScreenPtr pScreen) -{ - rrScrPriv(pScreen); - int j; - - unwrap (pScrPriv, pScreen, CloseScreen); - for (j = pScrPriv->numCrtcs - 1; j >= 0; j--) - RRCrtcDestroy (pScrPriv->crtcs[j]); - for (j = pScrPriv->numOutputs - 1; j >= 0; j--) - RROutputDestroy (pScrPriv->outputs[j]); - - xfree (pScrPriv->crtcs); - xfree (pScrPriv->outputs); - xfree (pScrPriv); - RRNScreens -= 1; /* ok, one fewer screen with RandR running */ - return (*pScreen->CloseScreen) (i, pScreen); -} - -static void -SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent *from, - xRRScreenChangeNotifyEvent *to) -{ - to->type = from->type; - to->rotation = from->rotation; - cpswaps(from->sequenceNumber, to->sequenceNumber); - cpswapl(from->timestamp, to->timestamp); - cpswapl(from->configTimestamp, to->configTimestamp); - cpswapl(from->root, to->root); - cpswapl(from->window, to->window); - cpswaps(from->sizeID, to->sizeID); - cpswaps(from->subpixelOrder, to->subpixelOrder); - cpswaps(from->widthInPixels, to->widthInPixels); - cpswaps(from->heightInPixels, to->heightInPixels); - cpswaps(from->widthInMillimeters, to->widthInMillimeters); - cpswaps(from->heightInMillimeters, to->heightInMillimeters); -} - -static void -SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent *from, - xRRCrtcChangeNotifyEvent *to) -{ - to->type = from->type; - to->subCode = from->subCode; - cpswaps(from->sequenceNumber, to->sequenceNumber); - cpswapl(from->timestamp, to->timestamp); - cpswapl(from->window, to->window); - cpswapl(from->crtc, to->crtc); - cpswapl(from->mode, to->mode); - cpswaps(from->rotation, to->rotation); - /* pad1 */ - cpswaps(from->x, to->x); - cpswaps(from->y, to->y); - cpswaps(from->width, to->width); - cpswaps(from->height, to->height); -} - -static void -SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent *from, - xRROutputChangeNotifyEvent *to) -{ - to->type = from->type; - to->subCode = from->subCode; - cpswaps(from->sequenceNumber, to->sequenceNumber); - cpswapl(from->timestamp, to->timestamp); - cpswapl(from->configTimestamp, to->configTimestamp); - cpswapl(from->window, to->window); - cpswapl(from->output, to->output); - cpswapl(from->crtc, to->crtc); - cpswapl(from->mode, to->mode); - cpswaps(from->rotation, to->rotation); - to->connection = from->connection; - to->subpixelOrder = from->subpixelOrder; -} - -static void -SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent *from, - xRROutputPropertyNotifyEvent *to) -{ - to->type = from->type; - to->subCode = from->subCode; - cpswaps(from->sequenceNumber, to->sequenceNumber); - cpswapl(from->window, to->window); - cpswapl(from->output, to->output); - cpswapl(from->atom, to->atom); - cpswapl(from->timestamp, to->timestamp); - to->state = from->state; - /* pad1 */ - /* pad2 */ - /* pad3 */ - /* pad4 */ -} - -static void -SRRNotifyEvent (xEvent *from, - xEvent *to) -{ - switch (from->u.u.detail) { - case RRNotify_CrtcChange: - SRRCrtcChangeNotifyEvent ((xRRCrtcChangeNotifyEvent *) from, - (xRRCrtcChangeNotifyEvent *) to); - break; - case RRNotify_OutputChange: - SRROutputChangeNotifyEvent ((xRROutputChangeNotifyEvent *) from, - (xRROutputChangeNotifyEvent *) to); - break; - case RRNotify_OutputProperty: - SRROutputPropertyNotifyEvent ((xRROutputPropertyNotifyEvent *) from, - (xRROutputPropertyNotifyEvent *) to); - break; - default: - break; - } -} - -static int RRGeneration; - -Bool RRInit (void) -{ - if (RRGeneration != serverGeneration) - { - if (!RRModeInit ()) - return FALSE; - if (!RRCrtcInit ()) - return FALSE; - if (!RROutputInit ()) - return FALSE; - RRGeneration = serverGeneration; - } - return TRUE; -} - -Bool RRScreenInit(ScreenPtr pScreen) -{ - rrScrPrivPtr pScrPriv; - - if (!RRInit ()) - return FALSE; - - pScrPriv = (rrScrPrivPtr) xcalloc (1, sizeof (rrScrPrivRec)); - if (!pScrPriv) - return FALSE; - - SetRRScreen(pScreen, pScrPriv); - - /* - * Calling function best set these function vectors - */ - pScrPriv->rrGetInfo = 0; - pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width; - pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height; - - pScrPriv->width = pScreen->width; - pScrPriv->height = pScreen->height; - pScrPriv->mmWidth = pScreen->mmWidth; - pScrPriv->mmHeight = pScreen->mmHeight; -#if RANDR_12_INTERFACE - pScrPriv->rrScreenSetSize = NULL; - pScrPriv->rrCrtcSet = NULL; - pScrPriv->rrCrtcSetGamma = NULL; -#endif -#if RANDR_10_INTERFACE - pScrPriv->rrSetConfig = 0; - pScrPriv->rotations = RR_Rotate_0; - pScrPriv->reqWidth = pScreen->width; - pScrPriv->reqHeight = pScreen->height; - pScrPriv->nSizes = 0; - pScrPriv->pSizes = NULL; - pScrPriv->rotation = RR_Rotate_0; - pScrPriv->rate = 0; - pScrPriv->size = 0; -#endif - - /* - * This value doesn't really matter -- any client must call - * GetScreenInfo before reading it which will automatically update - * the time - */ - pScrPriv->lastSetTime = currentTime; - pScrPriv->lastConfigTime = currentTime; - - wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen); - - pScrPriv->numOutputs = 0; - pScrPriv->outputs = NULL; - pScrPriv->numCrtcs = 0; - pScrPriv->crtcs = NULL; - - RRNScreens += 1; /* keep count of screens that implement randr */ - return TRUE; -} - -/*ARGSUSED*/ -static int -RRFreeClient (pointer data, XID id) -{ - RREventPtr pRREvent; - WindowPtr pWin; - RREventPtr *pHead, pCur, pPrev; - - pRREvent = (RREventPtr) data; - pWin = pRREvent->window; - dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, - RREventType, serverClient, DixDestroyAccess); - if (pHead) { - pPrev = 0; - for (pCur = *pHead; pCur && pCur != pRREvent; pCur=pCur->next) - pPrev = pCur; - if (pCur) - { - if (pPrev) - pPrev->next = pRREvent->next; - else - *pHead = pRREvent->next; - } - } - xfree ((pointer) pRREvent); - return 1; -} - -/*ARGSUSED*/ -static int -RRFreeEvents (pointer data, XID id) -{ - RREventPtr *pHead, pCur, pNext; - - pHead = (RREventPtr *) data; - for (pCur = *pHead; pCur; pCur = pNext) { - pNext = pCur->next; - FreeResource (pCur->clientResource, RRClientType); - xfree ((pointer) pCur); - } - xfree ((pointer) pHead); - return 1; -} - -void -RRExtensionInit (void) -{ - ExtensionEntry *extEntry; - - if (RRNScreens == 0) return; - - if (!dixRequestPrivate(RRClientPrivateKey, - sizeof (RRClientRec) + - screenInfo.numScreens * sizeof (RRTimesRec))) - return; - if (!AddCallback (&ClientStateCallback, RRClientCallback, 0)) - return; - - RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient"); - if (!RRClientType) - return; - RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent"); - if (!RREventType) - return; - extEntry = AddExtension (RANDR_NAME, RRNumberEvents, RRNumberErrors, - ProcRRDispatch, SProcRRDispatch, - NULL, StandardMinorOpcode); - if (!extEntry) - return; - RRErrorBase = extEntry->errorBase; - RREventBase = extEntry->eventBase; - EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr) - SRRScreenChangeNotifyEvent; - EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr) - SRRNotifyEvent; -#ifdef PANORAMIX - RRXineramaExtensionInit(); -#endif -} - -static int -TellChanged (WindowPtr pWin, pointer value) -{ - RREventPtr *pHead, pRREvent; - ClientPtr client; - ScreenPtr pScreen = pWin->drawable.pScreen; - rrScrPriv(pScreen); - int i; - - dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, - RREventType, serverClient, DixReadAccess); - if (!pHead) - return WT_WALKCHILDREN; - - for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) - { - client = pRREvent->client; - if (client == serverClient || client->clientGone) - continue; - - if (pRREvent->mask & RRScreenChangeNotifyMask) - RRDeliverScreenEvent (client, pWin, pScreen); - - if (pRREvent->mask & RRCrtcChangeNotifyMask) - { - for (i = 0; i < pScrPriv->numCrtcs; i++) - { - RRCrtcPtr crtc = pScrPriv->crtcs[i]; - if (crtc->changed) - RRDeliverCrtcEvent (client, pWin, crtc); - } - } - - if (pRREvent->mask & RROutputChangeNotifyMask) - { - for (i = 0; i < pScrPriv->numOutputs; i++) - { - RROutputPtr output = pScrPriv->outputs[i]; - if (output->changed) - RRDeliverOutputEvent (client, pWin, output); - } - } - } - return WT_WALKCHILDREN; -} - -/* - * Something changed; send events and adjust pointer position - */ -void -RRTellChanged (ScreenPtr pScreen) -{ - rrScrPriv (pScreen); - int i; - - if (pScrPriv->changed) - { - UpdateCurrentTime (); - if (pScrPriv->configChanged) - { - pScrPriv->lastConfigTime = currentTime; - pScrPriv->configChanged = FALSE; - } - pScrPriv->changed = FALSE; - WalkTree (pScreen, TellChanged, (pointer) pScreen); - for (i = 0; i < pScrPriv->numOutputs; i++) - pScrPriv->outputs[i]->changed = FALSE; - for (i = 0; i < pScrPriv->numCrtcs; i++) - pScrPriv->crtcs[i]->changed = FALSE; - if (pScrPriv->layoutChanged) - { - pScrPriv->layoutChanged = FALSE; - RRPointerScreenConfigured (pScreen); - RRSendConfigNotify (pScreen); - } - } -} - -/* - * Return the first output which is connected to an active CRTC - * Used in emulating 1.0 behaviour - */ -RROutputPtr -RRFirstOutput (ScreenPtr pScreen) -{ - rrScrPriv(pScreen); - RROutputPtr output; - int i, j; - - if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) - return pScrPriv->primaryOutput; - - for (i = 0; i < pScrPriv->numCrtcs; i++) - { - RRCrtcPtr crtc = pScrPriv->crtcs[i]; - for (j = 0; j < pScrPriv->numOutputs; j++) - { - output = pScrPriv->outputs[j]; - if (output->crtc == crtc) - return output; - } - } - return NULL; -} - -CARD16 -RRVerticalRefresh (xRRModeInfo *mode) -{ - CARD32 refresh; - CARD32 dots = mode->hTotal * mode->vTotal; - if (!dots) - return 0; - refresh = (mode->dotClock + dots/2) / dots; - if (refresh > 0xffff) - refresh = 0xffff; - return (CARD16) refresh; -} - -static int -ProcRRDispatch (ClientPtr client) -{ - REQUEST(xReq); - if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data]) - return BadRequest; - return (*ProcRandrVector[stuff->data]) (client); -} - -static int -SProcRRDispatch (ClientPtr client) -{ - REQUEST(xReq); - if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data]) - return BadRequest; - return (*SProcRandrVector[stuff->data]) (client); -} - +/* + * Copyright © 2000 Compaq Computer Corporation + * Copyright © 2002 Hewlett-Packard Company + * Copyright © 2006 Intel Corporation + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + * + * Author: Jim Gettys, Hewlett-Packard Company, Inc. + * Keith Packard, Intel Corporation + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "randrstr.h" + +/* From render.h */ +#ifndef SubPixelUnknown +#define SubPixelUnknown 0 +#endif + +#define RR_VALIDATE +static int RRNScreens; + +#define wrap(priv,real,mem,func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define unwrap(priv,real,mem) {\ + real->mem = priv->mem; \ +} + +static int ProcRRDispatch (ClientPtr pClient); +static int SProcRRDispatch (ClientPtr pClient); + +int RREventBase; +int RRErrorBase; +RESTYPE RRClientType, RREventType; /* resource types for event masks */ +static int RRClientPrivateKeyIndex; +DevPrivateKey RRClientPrivateKey = &RRClientPrivateKeyIndex; + +static int rrPrivKeyIndex; +DevPrivateKey rrPrivKey = &rrPrivKeyIndex; + +static void +RRClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + rrClientPriv(pClient); + RRTimesPtr pTimes = (RRTimesPtr) (pRRClient + 1); + int i; + + pRRClient->major_version = 0; + pRRClient->minor_version = 0; + for (i = 0; i < screenInfo.numScreens; i++) + { + ScreenPtr pScreen = screenInfo.screens[i]; + rrScrPriv(pScreen); + + if (pScrPriv) + { + pTimes[i].setTime = pScrPriv->lastSetTime; + pTimes[i].configTime = pScrPriv->lastConfigTime; + } + } +} + +static Bool +RRCloseScreen (int i, ScreenPtr pScreen) +{ + rrScrPriv(pScreen); + int j; + + unwrap (pScrPriv, pScreen, CloseScreen); + for (j = pScrPriv->numCrtcs - 1; j >= 0; j--) + RRCrtcDestroy (pScrPriv->crtcs[j]); + for (j = pScrPriv->numOutputs - 1; j >= 0; j--) + RROutputDestroy (pScrPriv->outputs[j]); + + free(pScrPriv->crtcs); + free(pScrPriv->outputs); + free(pScrPriv); + RRNScreens -= 1; /* ok, one fewer screen with RandR running */ + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void +SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent *from, + xRRScreenChangeNotifyEvent *to) +{ + to->type = from->type; + to->rotation = from->rotation; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->timestamp, to->timestamp); + cpswapl(from->configTimestamp, to->configTimestamp); + cpswapl(from->root, to->root); + cpswapl(from->window, to->window); + cpswaps(from->sizeID, to->sizeID); + cpswaps(from->subpixelOrder, to->subpixelOrder); + cpswaps(from->widthInPixels, to->widthInPixels); + cpswaps(from->heightInPixels, to->heightInPixels); + cpswaps(from->widthInMillimeters, to->widthInMillimeters); + cpswaps(from->heightInMillimeters, to->heightInMillimeters); +} + +static void +SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent *from, + xRRCrtcChangeNotifyEvent *to) +{ + to->type = from->type; + to->subCode = from->subCode; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->timestamp, to->timestamp); + cpswapl(from->window, to->window); + cpswapl(from->crtc, to->crtc); + cpswapl(from->mode, to->mode); + cpswaps(from->rotation, to->rotation); + /* pad1 */ + cpswaps(from->x, to->x); + cpswaps(from->y, to->y); + cpswaps(from->width, to->width); + cpswaps(from->height, to->height); +} + +static void +SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent *from, + xRROutputChangeNotifyEvent *to) +{ + to->type = from->type; + to->subCode = from->subCode; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->timestamp, to->timestamp); + cpswapl(from->configTimestamp, to->configTimestamp); + cpswapl(from->window, to->window); + cpswapl(from->output, to->output); + cpswapl(from->crtc, to->crtc); + cpswapl(from->mode, to->mode); + cpswaps(from->rotation, to->rotation); + to->connection = from->connection; + to->subpixelOrder = from->subpixelOrder; +} + +static void +SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent *from, + xRROutputPropertyNotifyEvent *to) +{ + to->type = from->type; + to->subCode = from->subCode; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->window, to->window); + cpswapl(from->output, to->output); + cpswapl(from->atom, to->atom); + cpswapl(from->timestamp, to->timestamp); + to->state = from->state; + /* pad1 */ + /* pad2 */ + /* pad3 */ + /* pad4 */ +} + +static void +SRRNotifyEvent (xEvent *from, + xEvent *to) +{ + switch (from->u.u.detail) { + case RRNotify_CrtcChange: + SRRCrtcChangeNotifyEvent ((xRRCrtcChangeNotifyEvent *) from, + (xRRCrtcChangeNotifyEvent *) to); + break; + case RRNotify_OutputChange: + SRROutputChangeNotifyEvent ((xRROutputChangeNotifyEvent *) from, + (xRROutputChangeNotifyEvent *) to); + break; + case RRNotify_OutputProperty: + SRROutputPropertyNotifyEvent ((xRROutputPropertyNotifyEvent *) from, + (xRROutputPropertyNotifyEvent *) to); + break; + default: + break; + } +} + +static int RRGeneration; + +Bool RRInit (void) +{ + if (RRGeneration != serverGeneration) + { + if (!RRModeInit ()) + return FALSE; + if (!RRCrtcInit ()) + return FALSE; + if (!RROutputInit ()) + return FALSE; + RRGeneration = serverGeneration; + } + return TRUE; +} + +Bool RRScreenInit(ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (!RRInit ()) + return FALSE; + + pScrPriv = (rrScrPrivPtr) calloc(1, sizeof (rrScrPrivRec)); + if (!pScrPriv) + return FALSE; + + SetRRScreen(pScreen, pScrPriv); + + /* + * Calling function best set these function vectors + */ + pScrPriv->rrGetInfo = 0; + pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width; + pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height; + + pScrPriv->width = pScreen->width; + pScrPriv->height = pScreen->height; + pScrPriv->mmWidth = pScreen->mmWidth; + pScrPriv->mmHeight = pScreen->mmHeight; +#if RANDR_12_INTERFACE + pScrPriv->rrScreenSetSize = NULL; + pScrPriv->rrCrtcSet = NULL; + pScrPriv->rrCrtcSetGamma = NULL; +#endif +#if RANDR_10_INTERFACE + pScrPriv->rrSetConfig = 0; + pScrPriv->rotations = RR_Rotate_0; + pScrPriv->reqWidth = pScreen->width; + pScrPriv->reqHeight = pScreen->height; + pScrPriv->nSizes = 0; + pScrPriv->pSizes = NULL; + pScrPriv->rotation = RR_Rotate_0; + pScrPriv->rate = 0; + pScrPriv->size = 0; +#endif + + /* + * This value doesn't really matter -- any client must call + * GetScreenInfo before reading it which will automatically update + * the time + */ + pScrPriv->lastSetTime = currentTime; + pScrPriv->lastConfigTime = currentTime; + + wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen); + + pScrPriv->numOutputs = 0; + pScrPriv->outputs = NULL; + pScrPriv->numCrtcs = 0; + pScrPriv->crtcs = NULL; + + RRNScreens += 1; /* keep count of screens that implement randr */ + return TRUE; +} + +/*ARGSUSED*/ +static int +RRFreeClient (pointer data, XID id) +{ + RREventPtr pRREvent; + WindowPtr pWin; + RREventPtr *pHead, pCur, pPrev; + + pRREvent = (RREventPtr) data; + pWin = pRREvent->window; + dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, + RREventType, serverClient, DixDestroyAccess); + if (pHead) { + pPrev = 0; + for (pCur = *pHead; pCur && pCur != pRREvent; pCur=pCur->next) + pPrev = pCur; + if (pCur) + { + if (pPrev) + pPrev->next = pRREvent->next; + else + *pHead = pRREvent->next; + } + } + free((pointer) pRREvent); + return 1; +} + +/*ARGSUSED*/ +static int +RRFreeEvents (pointer data, XID id) +{ + RREventPtr *pHead, pCur, pNext; + + pHead = (RREventPtr *) data; + for (pCur = *pHead; pCur; pCur = pNext) { + pNext = pCur->next; + FreeResource (pCur->clientResource, RRClientType); + free((pointer) pCur); + } + free((pointer) pHead); + return 1; +} + +void +RRExtensionInit (void) +{ + ExtensionEntry *extEntry; + + if (RRNScreens == 0) return; + + if (!dixRequestPrivate(RRClientPrivateKey, + sizeof (RRClientRec) + + screenInfo.numScreens * sizeof (RRTimesRec))) + return; + if (!AddCallback (&ClientStateCallback, RRClientCallback, 0)) + return; + + RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient"); + if (!RRClientType) + return; + RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent"); + if (!RREventType) + return; + extEntry = AddExtension (RANDR_NAME, RRNumberEvents, RRNumberErrors, + ProcRRDispatch, SProcRRDispatch, + NULL, StandardMinorOpcode); + if (!extEntry) + return; + RRErrorBase = extEntry->errorBase; + RREventBase = extEntry->eventBase; + EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr) + SRRScreenChangeNotifyEvent; + EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr) + SRRNotifyEvent; +#ifdef PANORAMIX + RRXineramaExtensionInit(); +#endif +} + +static int +TellChanged (WindowPtr pWin, pointer value) +{ + RREventPtr *pHead, pRREvent; + ClientPtr client; + ScreenPtr pScreen = pWin->drawable.pScreen; + rrScrPriv(pScreen); + int i; + + dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, + RREventType, serverClient, DixReadAccess); + if (!pHead) + return WT_WALKCHILDREN; + + for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) + { + client = pRREvent->client; + if (client == serverClient || client->clientGone) + continue; + + if (pRREvent->mask & RRScreenChangeNotifyMask) + RRDeliverScreenEvent (client, pWin, pScreen); + + if (pRREvent->mask & RRCrtcChangeNotifyMask) + { + for (i = 0; i < pScrPriv->numCrtcs; i++) + { + RRCrtcPtr crtc = pScrPriv->crtcs[i]; + if (crtc->changed) + RRDeliverCrtcEvent (client, pWin, crtc); + } + } + + if (pRREvent->mask & RROutputChangeNotifyMask) + { + for (i = 0; i < pScrPriv->numOutputs; i++) + { + RROutputPtr output = pScrPriv->outputs[i]; + if (output->changed) + RRDeliverOutputEvent (client, pWin, output); + } + } + } + return WT_WALKCHILDREN; +} + +/* + * Something changed; send events and adjust pointer position + */ +void +RRTellChanged (ScreenPtr pScreen) +{ + rrScrPriv (pScreen); + int i; + + if (pScrPriv->changed) + { + UpdateCurrentTime (); + if (pScrPriv->configChanged) + { + pScrPriv->lastConfigTime = currentTime; + pScrPriv->configChanged = FALSE; + } + pScrPriv->changed = FALSE; + WalkTree (pScreen, TellChanged, (pointer) pScreen); + for (i = 0; i < pScrPriv->numOutputs; i++) + pScrPriv->outputs[i]->changed = FALSE; + for (i = 0; i < pScrPriv->numCrtcs; i++) + pScrPriv->crtcs[i]->changed = FALSE; + if (pScrPriv->layoutChanged) + { + pScrPriv->layoutChanged = FALSE; + RRPointerScreenConfigured (pScreen); + RRSendConfigNotify (pScreen); + } + } +} + +/* + * Return the first output which is connected to an active CRTC + * Used in emulating 1.0 behaviour + */ +RROutputPtr +RRFirstOutput (ScreenPtr pScreen) +{ + rrScrPriv(pScreen); + RROutputPtr output; + int i, j; + + if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) + return pScrPriv->primaryOutput; + + for (i = 0; i < pScrPriv->numCrtcs; i++) + { + RRCrtcPtr crtc = pScrPriv->crtcs[i]; + for (j = 0; j < pScrPriv->numOutputs; j++) + { + output = pScrPriv->outputs[j]; + if (output->crtc == crtc) + return output; + } + } + return NULL; +} + +CARD16 +RRVerticalRefresh (xRRModeInfo *mode) +{ + CARD32 refresh; + CARD32 dots = mode->hTotal * mode->vTotal; + if (!dots) + return 0; + refresh = (mode->dotClock + dots/2) / dots; + if (refresh > 0xffff) + refresh = 0xffff; + return (CARD16) refresh; +} + +static int +ProcRRDispatch (ClientPtr client) +{ + REQUEST(xReq); + if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data]) + return BadRequest; + return (*ProcRandrVector[stuff->data]) (client); +} + +static int +SProcRRDispatch (ClientPtr client) +{ + REQUEST(xReq); + if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data]) + return BadRequest; + return (*SProcRandrVector[stuff->data]) (client); +} + diff --git a/xorg-server/randr/rrcrtc.c b/xorg-server/randr/rrcrtc.c index a9eb2d262..2544903e9 100644 --- a/xorg-server/randr/rrcrtc.c +++ b/xorg-server/randr/rrcrtc.c @@ -1,1387 +1,1387 @@ -/* - * Copyright © 2006 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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. - */ - -#include "randrstr.h" -#include "swaprep.h" - -RESTYPE RRCrtcType; - -/* - * Notify the CRTC of some change - */ -void -RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged) -{ - ScreenPtr pScreen = crtc->pScreen; - - crtc->changed = TRUE; - if (pScreen) - { - rrScrPriv(pScreen); - - pScrPriv->changed = TRUE; - /* - * Send ConfigureNotify on any layout change - */ - if (layoutChanged) - pScrPriv->layoutChanged = TRUE; - } -} - -/* - * Create a CRTC - */ -RRCrtcPtr -RRCrtcCreate (ScreenPtr pScreen, void *devPrivate) -{ - RRCrtcPtr crtc; - RRCrtcPtr *crtcs; - rrScrPrivPtr pScrPriv; - - if (!RRInit()) - return NULL; - - pScrPriv = rrGetScrPriv(pScreen); - - /* make space for the crtc pointer */ - if (pScrPriv->numCrtcs) - crtcs = xrealloc (pScrPriv->crtcs, - (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr)); - else - crtcs = xalloc (sizeof (RRCrtcPtr)); - if (!crtcs) - return FALSE; - pScrPriv->crtcs = crtcs; - - crtc = xcalloc (1, sizeof (RRCrtcRec)); - if (!crtc) - return NULL; - crtc->id = FakeClientID (0); - crtc->pScreen = pScreen; - crtc->mode = NULL; - crtc->x = 0; - crtc->y = 0; - crtc->rotation = RR_Rotate_0; - crtc->rotations = RR_Rotate_0; - crtc->outputs = NULL; - crtc->numOutputs = 0; - crtc->gammaSize = 0; - crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL; - crtc->changed = FALSE; - crtc->devPrivate = devPrivate; - RRTransformInit (&crtc->client_pending_transform); - RRTransformInit (&crtc->client_current_transform); - pixman_transform_init_identity (&crtc->transform); - pixman_f_transform_init_identity (&crtc->f_transform); - pixman_f_transform_init_identity (&crtc->f_inverse); - - if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc)) - return NULL; - - /* attach the screen and crtc together */ - crtc->pScreen = pScreen; - pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc; - - return crtc; -} - -/* - * Set the allowed rotations on a CRTC - */ -void -RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations) -{ - crtc->rotations = rotations; -} - -/* - * Set whether transforms are allowed on a CRTC - */ -void -RRCrtcSetTransformSupport (RRCrtcPtr crtc, Bool transforms) -{ - crtc->transforms = transforms; -} - -/* - * Notify the extension that the Crtc has been reconfigured, - * the driver calls this whenever it has updated the mode - */ -Bool -RRCrtcNotify (RRCrtcPtr crtc, - RRModePtr mode, - int x, - int y, - Rotation rotation, - RRTransformPtr transform, - int numOutputs, - RROutputPtr *outputs) -{ - int i, j; - - /* - * Check to see if any of the new outputs were - * not in the old list and mark them as changed - */ - for (i = 0; i < numOutputs; i++) - { - for (j = 0; j < crtc->numOutputs; j++) - if (outputs[i] == crtc->outputs[j]) - break; - if (j == crtc->numOutputs) - { - outputs[i]->crtc = crtc; - RROutputChanged (outputs[i], FALSE); - RRCrtcChanged (crtc, FALSE); - } - } - /* - * Check to see if any of the old outputs are - * not in the new list and mark them as changed - */ - for (j = 0; j < crtc->numOutputs; j++) - { - for (i = 0; i < numOutputs; i++) - if (outputs[i] == crtc->outputs[j]) - break; - if (i == numOutputs) - { - if (crtc->outputs[j]->crtc == crtc) - crtc->outputs[j]->crtc = NULL; - RROutputChanged (crtc->outputs[j], FALSE); - RRCrtcChanged (crtc, FALSE); - } - } - /* - * Reallocate the crtc output array if necessary - */ - if (numOutputs != crtc->numOutputs) - { - RROutputPtr *newoutputs; - - if (numOutputs) - { - if (crtc->numOutputs) - newoutputs = xrealloc (crtc->outputs, - numOutputs * sizeof (RROutputPtr)); - else - newoutputs = xalloc (numOutputs * sizeof (RROutputPtr)); - if (!newoutputs) - return FALSE; - } - else - { - if (crtc->outputs) - xfree (crtc->outputs); - newoutputs = NULL; - } - crtc->outputs = newoutputs; - crtc->numOutputs = numOutputs; - } - /* - * Copy the new list of outputs into the crtc - */ - memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)); - /* - * Update remaining crtc fields - */ - if (mode != crtc->mode) - { - if (crtc->mode) - RRModeDestroy (crtc->mode); - crtc->mode = mode; - if (mode != NULL) - mode->refcnt++; - RRCrtcChanged (crtc, TRUE); - } - if (x != crtc->x) - { - crtc->x = x; - RRCrtcChanged (crtc, TRUE); - } - if (y != crtc->y) - { - crtc->y = y; - RRCrtcChanged (crtc, TRUE); - } - if (rotation != crtc->rotation) - { - crtc->rotation = rotation; - RRCrtcChanged (crtc, TRUE); - } - if (!RRTransformEqual (transform, &crtc->client_current_transform)) { - RRTransformCopy (&crtc->client_current_transform, transform); - RRCrtcChanged (crtc, TRUE); - } - if (crtc->changed && mode) - { - RRTransformCompute (x, y, - mode->mode.width, mode->mode.height, - rotation, - &crtc->client_current_transform, - &crtc->transform, &crtc->f_transform, - &crtc->f_inverse); - } - return TRUE; -} - -void -RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - rrScrPriv (pScreen); - xRRCrtcChangeNotifyEvent ce; - RRModePtr mode = crtc->mode; - - ce.type = RRNotify + RREventBase; - ce.subCode = RRNotify_CrtcChange; - ce.sequenceNumber = client->sequence; - ce.timestamp = pScrPriv->lastSetTime.milliseconds; - ce.window = pWin->drawable.id; - ce.crtc = crtc->id; - ce.rotation = crtc->rotation; - if (mode) - { - ce.mode = mode->mode.id; - ce.x = crtc->x; - ce.y = crtc->y; - ce.width = mode->mode.width; - ce.height = mode->mode.height; - } - else - { - ce.mode = None; - ce.x = 0; - ce.y = 0; - ce.width = 0; - ce.height = 0; - } - WriteEventsToClient (client, 1, (xEvent *) &ce); -} - -static Bool -RRCrtcPendingProperties (RRCrtcPtr crtc) -{ - ScreenPtr pScreen = crtc->pScreen; - rrScrPriv(pScreen); - int o; - - for (o = 0; o < pScrPriv->numOutputs; o++) - { - RROutputPtr output = pScrPriv->outputs[o]; - if (output->crtc == crtc && output->pendingProperties) - return TRUE; - } - return FALSE; -} - -/* - * Request that the Crtc be reconfigured - */ -Bool -RRCrtcSet (RRCrtcPtr crtc, - RRModePtr mode, - int x, - int y, - Rotation rotation, - int numOutputs, - RROutputPtr *outputs) -{ - ScreenPtr pScreen = crtc->pScreen; - Bool ret = FALSE; - rrScrPriv(pScreen); - - /* See if nothing changed */ - if (crtc->mode == mode && - crtc->x == x && - crtc->y == y && - crtc->rotation == rotation && - crtc->numOutputs == numOutputs && - !memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) && - !RRCrtcPendingProperties (crtc) && - !RRCrtcPendingTransform (crtc)) - { - ret = TRUE; - } - else - { -#if RANDR_12_INTERFACE - if (pScrPriv->rrCrtcSet) - { - ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, - rotation, numOutputs, outputs); - } - else -#endif - { -#if RANDR_10_INTERFACE - if (pScrPriv->rrSetConfig) - { - RRScreenSize size; - RRScreenRate rate; - - if (!mode) - { - RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL); - ret = TRUE; - } - else - { - size.width = mode->mode.width; - size.height = mode->mode.height; - if (outputs[0]->mmWidth && outputs[0]->mmHeight) - { - size.mmWidth = outputs[0]->mmWidth; - size.mmHeight = outputs[0]->mmHeight; - } - else - { - size.mmWidth = pScreen->mmWidth; - size.mmHeight = pScreen->mmHeight; - } - size.nRates = 1; - rate.rate = RRVerticalRefresh (&mode->mode); - size.pRates = &rate; - ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size); - /* - * Old 1.0 interface tied screen size to mode size - */ - if (ret) - { - RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs); - RRScreenSizeNotify (pScreen); - } - } - } -#endif - } - if (ret) - { - int o; - RRTellChanged (pScreen); - - for (o = 0; o < numOutputs; o++) - RRPostPendingProperties (outputs[o]); - } - } - return ret; -} - -/* - * Return crtc transform - */ -RRTransformPtr -RRCrtcGetTransform (RRCrtcPtr crtc) -{ - RRTransformPtr transform = &crtc->client_pending_transform; - - if (pixman_transform_is_identity (&transform->transform)) - return NULL; - return transform; -} - -/* - * Check whether the pending and current transforms are the same - */ -Bool -RRCrtcPendingTransform (RRCrtcPtr crtc) -{ - return memcmp (&crtc->client_current_transform.transform, - &crtc->client_pending_transform.transform, - sizeof (PictTransform)) != 0; -} - -/* - * Destroy a Crtc at shutdown - */ -void -RRCrtcDestroy (RRCrtcPtr crtc) -{ - FreeResource (crtc->id, 0); -} - -static int -RRCrtcDestroyResource (pointer value, XID pid) -{ - RRCrtcPtr crtc = (RRCrtcPtr) value; - ScreenPtr pScreen = crtc->pScreen; - - if (pScreen) - { - rrScrPriv(pScreen); - int i; - - for (i = 0; i < pScrPriv->numCrtcs; i++) - { - if (pScrPriv->crtcs[i] == crtc) - { - memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1, - (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr)); - --pScrPriv->numCrtcs; - break; - } - } - } - if (crtc->gammaRed) - xfree (crtc->gammaRed); - if (crtc->mode) - RRModeDestroy (crtc->mode); - xfree (crtc); - return 1; -} - -/* - * Request that the Crtc gamma be changed - */ - -Bool -RRCrtcGammaSet (RRCrtcPtr crtc, - CARD16 *red, - CARD16 *green, - CARD16 *blue) -{ - Bool ret = TRUE; -#if RANDR_12_INTERFACE - ScreenPtr pScreen = crtc->pScreen; -#endif - - memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16)); - memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16)); - memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16)); -#if RANDR_12_INTERFACE - if (pScreen) - { - rrScrPriv(pScreen); - if (pScrPriv->rrCrtcSetGamma) - ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc); - } -#endif - return ret; -} - -/* - * Request current gamma back from the DDX (if possible). - * This includes gamma size. - */ -Bool -RRCrtcGammaGet(RRCrtcPtr crtc) -{ - Bool ret = TRUE; -#if RANDR_12_INTERFACE - ScreenPtr pScreen = crtc->pScreen; -#endif - -#if RANDR_12_INTERFACE - if (pScreen) - { - rrScrPriv(pScreen); - if (pScrPriv->rrCrtcGetGamma) - ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc); - } -#endif - return ret; -} - -/* - * Notify the extension that the Crtc gamma has been changed - * The driver calls this whenever it has changed the gamma values - * in the RRCrtcRec - */ - -Bool -RRCrtcGammaNotify (RRCrtcPtr crtc) -{ - return TRUE; /* not much going on here */ -} - -static void -RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform, - int *width, int *height) -{ - BoxRec box; - - if (mode == NULL) { - *width = 0; - *height = 0; - return; - } - - box.x1 = 0; - box.y1 = 0; - box.x2 = mode->mode.width; - box.y2 = mode->mode.height; - - pixman_transform_bounds (transform, &box); - *width = box.x2 - box.x1; - *height = box.y2 - box.y1; -} - -/** - * Returns the width/height that the crtc scans out from the framebuffer - */ -void -RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) -{ - return RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height); -} - -/* - * Set the size of the gamma table at server startup time - */ - -Bool -RRCrtcGammaSetSize (RRCrtcPtr crtc, - int size) -{ - CARD16 *gamma; - - if (size == crtc->gammaSize) - return TRUE; - if (size) - { - gamma = xalloc (size * 3 * sizeof (CARD16)); - if (!gamma) - return FALSE; - } - else - gamma = NULL; - if (crtc->gammaRed) - xfree (crtc->gammaRed); - crtc->gammaRed = gamma; - crtc->gammaGreen = gamma + size; - crtc->gammaBlue = gamma + size*2; - crtc->gammaSize = size; - return TRUE; -} - -/* - * Set the pending CRTC transformation - */ - -int -RRCrtcTransformSet (RRCrtcPtr crtc, - PictTransformPtr transform, - struct pixman_f_transform *f_transform, - struct pixman_f_transform *f_inverse, - char *filter_name, - int filter_len, - xFixed *params, - int nparams) -{ - PictFilterPtr filter = NULL; - int width = 0, height = 0; - - if (!crtc->transforms) - return BadValue; - - if (filter_len) - { - filter = PictureFindFilter (crtc->pScreen, - filter_name, - filter_len); - if (!filter) - return BadName; - if (filter->ValidateParams) - { - if (!filter->ValidateParams (crtc->pScreen, filter->id, - params, nparams, &width, &height)) - return BadMatch; - } - else { - width = filter->width; - height = filter->height; - } - } - else - { - if (nparams) - return BadMatch; - } - if (!RRTransformSetFilter (&crtc->client_pending_transform, - filter, params, nparams, width, height)) - return BadAlloc; - - crtc->client_pending_transform.transform = *transform; - crtc->client_pending_transform.f_transform = *f_transform; - crtc->client_pending_transform.f_inverse = *f_inverse; - return Success; -} - -/* - * Initialize crtc type - */ -Bool -RRCrtcInit (void) -{ - RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource, "CRTC"); - if (!RRCrtcType) - return FALSE; - return TRUE; -} - -int -ProcRRGetCrtcInfo (ClientPtr client) -{ - REQUEST(xRRGetCrtcInfoReq); - xRRGetCrtcInfoReply rep; - RRCrtcPtr crtc; - CARD8 *extra; - unsigned long extraLen; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - RRModePtr mode; - RROutput *outputs; - RROutput *possible; - int i, j, k, n; - int width, height; - BoxRec panned_area; - - REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); - VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); - - /* All crtcs must be associated with screens before client - * requests are processed - */ - pScreen = crtc->pScreen; - pScrPriv = rrGetScrPriv(pScreen); - - mode = crtc->mode; - - rep.type = X_Reply; - rep.status = RRSetConfigSuccess; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.timestamp = pScrPriv->lastSetTime.milliseconds; - if (pScrPriv->rrGetPanning && - pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) && - (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) - { - rep.x = panned_area.x1; - rep.y = panned_area.y1; - rep.width = panned_area.x2 - panned_area.x1; - rep.height = panned_area.y2 - panned_area.y1; - } - else - { - RRCrtcGetScanoutSize (crtc, &width, &height); - rep.x = crtc->x; - rep.y = crtc->y; - rep.width = width; - rep.height = height; - } - rep.mode = mode ? mode->mode.id : 0; - rep.rotation = crtc->rotation; - rep.rotations = crtc->rotations; - rep.nOutput = crtc->numOutputs; - k = 0; - for (i = 0; i < pScrPriv->numOutputs; i++) - for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) - if (pScrPriv->outputs[i]->crtcs[j] == crtc) - k++; - rep.nPossibleOutput = k; - - rep.length = rep.nOutput + rep.nPossibleOutput; - - extraLen = rep.length << 2; - if (extraLen) - { - extra = xalloc (extraLen); - if (!extra) - return BadAlloc; - } - else - extra = NULL; - - outputs = (RROutput *) extra; - possible = (RROutput *) (outputs + rep.nOutput); - - for (i = 0; i < crtc->numOutputs; i++) - { - outputs[i] = crtc->outputs[i]->id; - if (client->swapped) - swapl (&outputs[i], n); - } - k = 0; - for (i = 0; i < pScrPriv->numOutputs; i++) - for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) - if (pScrPriv->outputs[i]->crtcs[j] == crtc) - { - possible[k] = pScrPriv->outputs[i]->id; - if (client->swapped) - swapl (&possible[k], n); - k++; - } - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.timestamp, n); - swaps(&rep.x, n); - swaps(&rep.y, n); - swaps(&rep.width, n); - swaps(&rep.height, n); - swapl(&rep.mode, n); - swaps(&rep.rotation, n); - swaps(&rep.rotations, n); - swaps(&rep.nOutput, n); - swaps(&rep.nPossibleOutput, n); - } - WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep); - if (extraLen) - { - WriteToClient (client, extraLen, (char *) extra); - xfree (extra); - } - - return client->noClientException; -} - -int -ProcRRSetCrtcConfig (ClientPtr client) -{ - REQUEST(xRRSetCrtcConfigReq); - xRRSetCrtcConfigReply rep; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - RRCrtcPtr crtc; - RRModePtr mode; - int numOutputs; - RROutputPtr *outputs = NULL; - RROutput *outputIds; - TimeStamp configTime; - TimeStamp time; - Rotation rotation; - int rc, i, j; - - REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); - numOutputs = (stuff->length - bytes_to_int32(SIZEOF (xRRSetCrtcConfigReq))); - - VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); - - if (stuff->mode == None) - { - mode = NULL; - if (numOutputs > 0) - return BadMatch; - } - else - { - VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); - if (numOutputs == 0) - return BadMatch; - } - if (numOutputs) - { - outputs = xalloc (numOutputs * sizeof (RROutputPtr)); - if (!outputs) - return BadAlloc; - } - else - outputs = NULL; - - outputIds = (RROutput *) (stuff + 1); - for (i = 0; i < numOutputs; i++) - { - rc = dixLookupResourceByType((pointer *)(outputs + i), outputIds[i], - RROutputType, client, DixSetAttrAccess); - if (rc != Success) - { - if (outputs) - xfree (outputs); - return (rc == BadValue) ? RRErrorBase + BadRROutput : rc; - } - /* validate crtc for this output */ - for (j = 0; j < outputs[i]->numCrtcs; j++) - if (outputs[i]->crtcs[j] == crtc) - break; - if (j == outputs[i]->numCrtcs) - { - if (outputs) - xfree (outputs); - return BadMatch; - } - /* validate mode for this output */ - for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) - { - RRModePtr m = (j < outputs[i]->numModes ? - outputs[i]->modes[j] : - outputs[i]->userModes[j - outputs[i]->numModes]); - if (m == mode) - break; - } - if (j == outputs[i]->numModes + outputs[i]->numUserModes) - { - if (outputs) - xfree (outputs); - return BadMatch; - } - } - /* validate clones */ - for (i = 0; i < numOutputs; i++) - { - for (j = 0; j < numOutputs; j++) - { - int k; - if (i == j) - continue; - for (k = 0; k < outputs[i]->numClones; k++) - { - if (outputs[i]->clones[k] == outputs[j]) - break; - } - if (k == outputs[i]->numClones) - { - if (outputs) - xfree (outputs); - return BadMatch; - } - } - } - - pScreen = crtc->pScreen; - pScrPriv = rrGetScrPriv(pScreen); - - time = ClientTimeToServerTime(stuff->timestamp); - configTime = ClientTimeToServerTime(stuff->configTimestamp); - - if (!pScrPriv) - { - time = currentTime; - rep.status = RRSetConfigFailed; - goto sendReply; - } - -#if 0 - /* - * if the client's config timestamp is not the same as the last config - * timestamp, then the config information isn't up-to-date and - * can't even be validated - */ - if (CompareTimeStamps (configTime, pScrPriv->lastConfigTime) != 0) - { - rep.status = RRSetConfigInvalidConfigTime; - goto sendReply; - } -#endif - - /* - * Validate requested rotation - */ - rotation = (Rotation) stuff->rotation; - - /* test the rotation bits only! */ - switch (rotation & 0xf) { - case RR_Rotate_0: - case RR_Rotate_90: - case RR_Rotate_180: - case RR_Rotate_270: - break; - default: - /* - * Invalid rotation - */ - client->errorValue = stuff->rotation; - if (outputs) - xfree (outputs); - return BadValue; - } - - if (mode) - { - if ((~crtc->rotations) & rotation) - { - /* - * requested rotation or reflection not supported by screen - */ - client->errorValue = stuff->rotation; - if (outputs) - xfree (outputs); - return BadMatch; - } - -#ifdef RANDR_12_INTERFACE - /* - * Check screen size bounds if the DDX provides a 1.2 interface - * for setting screen size. Else, assume the CrtcSet sets - * the size along with the mode. If the driver supports transforms, - * then it must allow crtcs to display a subset of the screen, so - * only do this check for drivers without transform support. - */ - if (pScrPriv->rrScreenSetSize && !crtc->transforms) - { - int source_width; - int source_height; - PictTransform transform; - struct pixman_f_transform f_transform, f_inverse; - - RRTransformCompute (stuff->x, stuff->y, - mode->mode.width, mode->mode.height, - rotation, - &crtc->client_pending_transform, - &transform, &f_transform, &f_inverse); - - RRModeGetScanoutSize (mode, &transform, &source_width, &source_height); - if (stuff->x + source_width > pScreen->width) - { - client->errorValue = stuff->x; - if (outputs) - xfree (outputs); - return BadValue; - } - - if (stuff->y + source_height > pScreen->height) - { - client->errorValue = stuff->y; - if (outputs) - xfree (outputs); - return BadValue; - } - } -#endif - } - - /* - * Make sure the requested set-time is not older than - * the last set-time - */ - if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0) - { - rep.status = RRSetConfigInvalidTime; - goto sendReply; - } - - if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y, - rotation, numOutputs, outputs)) - { - rep.status = RRSetConfigFailed; - goto sendReply; - } - rep.status = RRSetConfigSuccess; - pScrPriv->lastSetTime = time; - -sendReply: - if (outputs) - xfree (outputs); - - rep.type = X_Reply; - /* rep.status has already been filled in */ - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; - - if (client->swapped) - { - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.newTimestamp, n); - } - WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep); - - return client->noClientException; -} - -int -ProcRRGetPanning (ClientPtr client) -{ - REQUEST(xRRGetPanningReq); - xRRGetPanningReply rep; - RRCrtcPtr crtc; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - BoxRec total; - BoxRec tracking; - INT16 border[4]; - int n; - - REQUEST_SIZE_MATCH(xRRGetPanningReq); - VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); - - /* All crtcs must be associated with screens before client - * requests are processed - */ - pScreen = crtc->pScreen; - pScrPriv = rrGetScrPriv(pScreen); - - if (!pScrPriv) - return RRErrorBase + BadRRCrtc; - - memset(&rep, 0, sizeof(rep)); - rep.type = X_Reply; - rep.status = RRSetConfigSuccess; - rep.sequenceNumber = client->sequence; - rep.length = 1; - rep.timestamp = pScrPriv->lastSetTime.milliseconds; - - if (pScrPriv->rrGetPanning && - pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) { - rep.left = total.x1; - rep.top = total.y1; - rep.width = total.x2 - total.x1; - rep.height = total.y2 - total.y1; - rep.track_left = tracking.x1; - rep.track_top = tracking.y1; - rep.track_width = tracking.x2 - tracking.x1; - rep.track_height = tracking.y2 - tracking.y1; - rep.border_left = border[0]; - rep.border_top = border[1]; - rep.border_right = border[2]; - rep.border_bottom = border[3]; - } - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.timestamp, n); - swaps(&rep.left, n); - swaps(&rep.top, n); - swaps(&rep.width, n); - swaps(&rep.height, n); - swaps(&rep.track_left, n); - swaps(&rep.track_top, n); - swaps(&rep.track_width, n); - swaps(&rep.track_height, n); - swaps(&rep.border_left, n); - swaps(&rep.border_top, n); - swaps(&rep.border_right, n); - swaps(&rep.border_bottom, n); - } - WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep); - return client->noClientException; -} - -int -ProcRRSetPanning (ClientPtr client) -{ - REQUEST(xRRSetPanningReq); - xRRSetPanningReply rep; - RRCrtcPtr crtc; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - TimeStamp time; - BoxRec total; - BoxRec tracking; - INT16 border[4]; - int n; - - REQUEST_SIZE_MATCH(xRRSetPanningReq); - VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); - - /* All crtcs must be associated with screens before client - * requests are processed - */ - pScreen = crtc->pScreen; - pScrPriv = rrGetScrPriv(pScreen); - - if (!pScrPriv) { - time = currentTime; - rep.status = RRSetConfigFailed; - goto sendReply; - } - - time = ClientTimeToServerTime(stuff->timestamp); - - /* - * Make sure the requested set-time is not older than - * the last set-time - */ - if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0) - { - rep.status = RRSetConfigInvalidTime; - goto sendReply; - } - - if (!pScrPriv->rrGetPanning) - return RRErrorBase + BadRRCrtc; - - total.x1 = stuff->left; - total.y1 = stuff->top; - total.x2 = total.x1 + stuff->width; - total.y2 = total.y1 + stuff->height; - tracking.x1 = stuff->track_left; - tracking.y1 = stuff->track_top; - tracking.x2 = tracking.x1 + stuff->track_width; - tracking.y2 = tracking.y1 + stuff->track_height; - border[0] = stuff->border_left; - border[1] = stuff->border_top; - border[2] = stuff->border_right; - border[3] = stuff->border_bottom; - - if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border)) - return BadMatch; - - pScrPriv->lastSetTime = time; - - rep.status = RRSetConfigSuccess; - -sendReply: - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.newTimestamp, n); - } - WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep); - return client->noClientException; -} - -int -ProcRRGetCrtcGammaSize (ClientPtr client) -{ - REQUEST(xRRGetCrtcGammaSizeReq); - xRRGetCrtcGammaSizeReply reply; - RRCrtcPtr crtc; - int n; - - REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); - VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); - - /* Gamma retrieval failed, any better error? */ - if (!RRCrtcGammaGet(crtc)) - return RRErrorBase + BadRRCrtc; - - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = 0; - reply.size = crtc->gammaSize; - if (client->swapped) { - swaps (&reply.sequenceNumber, n); - swapl (&reply.length, n); - swaps (&reply.size, n); - } - WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply); - return client->noClientException; -} - -int -ProcRRGetCrtcGamma (ClientPtr client) -{ - REQUEST(xRRGetCrtcGammaReq); - xRRGetCrtcGammaReply reply; - RRCrtcPtr crtc; - int n; - unsigned long len; - char *extra = NULL; - - REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); - VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); - - /* Gamma retrieval failed, any better error? */ - if (!RRCrtcGammaGet(crtc)) - return RRErrorBase + BadRRCrtc; - - len = crtc->gammaSize * 3 * 2; - - if (crtc->gammaSize) { - extra = xalloc(len); - if (!extra) - return BadAlloc; - } - - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = bytes_to_int32(len); - reply.size = crtc->gammaSize; - if (client->swapped) { - swaps (&reply.sequenceNumber, n); - swapl (&reply.length, n); - swaps (&reply.size, n); - } - WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply); - if (crtc->gammaSize) - { - memcpy(extra, crtc->gammaRed, len); - client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; - WriteSwappedDataToClient (client, len, extra); - xfree(extra); - } - return client->noClientException; -} - -int -ProcRRSetCrtcGamma (ClientPtr client) -{ - REQUEST(xRRSetCrtcGammaReq); - RRCrtcPtr crtc; - unsigned long len; - CARD16 *red, *green, *blue; - - REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); - VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); - - len = client->req_len - bytes_to_int32(sizeof (xRRSetCrtcGammaReq)); - if (len < (stuff->size * 3 + 1) >> 1) - return BadLength; - - if (stuff->size != crtc->gammaSize) - return BadMatch; - - red = (CARD16 *) (stuff + 1); - green = red + crtc->gammaSize; - blue = green + crtc->gammaSize; - - RRCrtcGammaSet (crtc, red, green, blue); - - return Success; -} - -/* Version 1.3 additions */ - -int -ProcRRSetCrtcTransform (ClientPtr client) -{ - REQUEST(xRRSetCrtcTransformReq); - RRCrtcPtr crtc; - PictTransform transform; - struct pixman_f_transform f_transform, f_inverse; - char *filter; - int nbytes; - xFixed *params; - int nparams; - - REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); - VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); - - PictTransform_from_xRenderTransform (&transform, &stuff->transform); - pixman_f_transform_from_pixman_transform (&f_transform, &transform); - if (!pixman_f_transform_invert (&f_inverse, &f_transform)) - return BadMatch; - - filter = (char *) (stuff + 1); - nbytes = stuff->nbytesFilter; - params = (xFixed *) (filter + pad_to_int32(nbytes)); - nparams = ((xFixed *) stuff + client->req_len) - params; - if (nparams < 0) - return BadLength; - - return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse, - filter, nbytes, params, nparams); -} - - -#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) - -static int -transform_filter_length (RRTransformPtr transform) -{ - int nbytes, nparams; - - if (transform->filter == NULL) - return 0; - nbytes = strlen (transform->filter->name); - nparams = transform->nparams; - return pad_to_int32(nbytes) + (nparams * sizeof (xFixed)); -} - -static int -transform_filter_encode (ClientPtr client, char *output, - CARD16 *nbytesFilter, - CARD16 *nparamsFilter, - RRTransformPtr transform) -{ - int nbytes, nparams; - int n; - - if (transform->filter == NULL) { - *nbytesFilter = 0; - *nparamsFilter = 0; - return 0; - } - nbytes = strlen (transform->filter->name); - nparams = transform->nparams; - *nbytesFilter = nbytes; - *nparamsFilter = nparams; - memcpy (output, transform->filter->name, nbytes); - while ((nbytes & 3) != 0) - output[nbytes++] = 0; - memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed)); - if (client->swapped) { - swaps (nbytesFilter, n); - swaps (nparamsFilter, n); - SwapLongs ((CARD32 *) (output + nbytes), nparams); - } - nbytes += nparams * sizeof (xFixed); - return nbytes; -} - -static void -transform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict) -{ - xRenderTransform_from_PictTransform (wire, pict); - if (client->swapped) - SwapLongs ((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); -} - -int -ProcRRGetCrtcTransform (ClientPtr client) -{ - REQUEST(xRRGetCrtcTransformReq); - xRRGetCrtcTransformReply *reply; - RRCrtcPtr crtc; - int n, nextra; - RRTransformPtr current, pending; - char *extra; - - REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq); - VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); - - pending = &crtc->client_pending_transform; - current = &crtc->client_current_transform; - - nextra = (transform_filter_length (pending) + - transform_filter_length (current)); - - reply = xalloc (sizeof (xRRGetCrtcTransformReply) + nextra); - if (!reply) - return BadAlloc; - - extra = (char *) (reply + 1); - reply->type = X_Reply; - reply->sequenceNumber = client->sequence; - reply->length = bytes_to_int32(CrtcTransformExtra + nextra); - - reply->hasTransforms = crtc->transforms; - - transform_encode (client, &reply->pendingTransform, &pending->transform); - extra += transform_filter_encode (client, extra, - &reply->pendingNbytesFilter, - &reply->pendingNparamsFilter, - pending); - - transform_encode (client, &reply->currentTransform, ¤t->transform); - extra += transform_filter_encode (client, extra, - &reply->currentNbytesFilter, - &reply->currentNparamsFilter, - current); - - if (client->swapped) { - swaps (&reply->sequenceNumber, n); - swapl (&reply->length, n); - } - WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply); - xfree(reply); - return client->noClientException; -} +/* + * Copyright © 2006 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "randrstr.h" +#include "swaprep.h" + +RESTYPE RRCrtcType; + +/* + * Notify the CRTC of some change + */ +void +RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged) +{ + ScreenPtr pScreen = crtc->pScreen; + + crtc->changed = TRUE; + if (pScreen) + { + rrScrPriv(pScreen); + + pScrPriv->changed = TRUE; + /* + * Send ConfigureNotify on any layout change + */ + if (layoutChanged) + pScrPriv->layoutChanged = TRUE; + } +} + +/* + * Create a CRTC + */ +RRCrtcPtr +RRCrtcCreate (ScreenPtr pScreen, void *devPrivate) +{ + RRCrtcPtr crtc; + RRCrtcPtr *crtcs; + rrScrPrivPtr pScrPriv; + + if (!RRInit()) + return NULL; + + pScrPriv = rrGetScrPriv(pScreen); + + /* make space for the crtc pointer */ + if (pScrPriv->numCrtcs) + crtcs = realloc(pScrPriv->crtcs, + (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr)); + else + crtcs = malloc(sizeof (RRCrtcPtr)); + if (!crtcs) + return FALSE; + pScrPriv->crtcs = crtcs; + + crtc = calloc(1, sizeof (RRCrtcRec)); + if (!crtc) + return NULL; + crtc->id = FakeClientID (0); + crtc->pScreen = pScreen; + crtc->mode = NULL; + crtc->x = 0; + crtc->y = 0; + crtc->rotation = RR_Rotate_0; + crtc->rotations = RR_Rotate_0; + crtc->outputs = NULL; + crtc->numOutputs = 0; + crtc->gammaSize = 0; + crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL; + crtc->changed = FALSE; + crtc->devPrivate = devPrivate; + RRTransformInit (&crtc->client_pending_transform); + RRTransformInit (&crtc->client_current_transform); + pixman_transform_init_identity (&crtc->transform); + pixman_f_transform_init_identity (&crtc->f_transform); + pixman_f_transform_init_identity (&crtc->f_inverse); + + if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc)) + return NULL; + + /* attach the screen and crtc together */ + crtc->pScreen = pScreen; + pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc; + + return crtc; +} + +/* + * Set the allowed rotations on a CRTC + */ +void +RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations) +{ + crtc->rotations = rotations; +} + +/* + * Set whether transforms are allowed on a CRTC + */ +void +RRCrtcSetTransformSupport (RRCrtcPtr crtc, Bool transforms) +{ + crtc->transforms = transforms; +} + +/* + * Notify the extension that the Crtc has been reconfigured, + * the driver calls this whenever it has updated the mode + */ +Bool +RRCrtcNotify (RRCrtcPtr crtc, + RRModePtr mode, + int x, + int y, + Rotation rotation, + RRTransformPtr transform, + int numOutputs, + RROutputPtr *outputs) +{ + int i, j; + + /* + * Check to see if any of the new outputs were + * not in the old list and mark them as changed + */ + for (i = 0; i < numOutputs; i++) + { + for (j = 0; j < crtc->numOutputs; j++) + if (outputs[i] == crtc->outputs[j]) + break; + if (j == crtc->numOutputs) + { + outputs[i]->crtc = crtc; + RROutputChanged (outputs[i], FALSE); + RRCrtcChanged (crtc, FALSE); + } + } + /* + * Check to see if any of the old outputs are + * not in the new list and mark them as changed + */ + for (j = 0; j < crtc->numOutputs; j++) + { + for (i = 0; i < numOutputs; i++) + if (outputs[i] == crtc->outputs[j]) + break; + if (i == numOutputs) + { + if (crtc->outputs[j]->crtc == crtc) + crtc->outputs[j]->crtc = NULL; + RROutputChanged (crtc->outputs[j], FALSE); + RRCrtcChanged (crtc, FALSE); + } + } + /* + * Reallocate the crtc output array if necessary + */ + if (numOutputs != crtc->numOutputs) + { + RROutputPtr *newoutputs; + + if (numOutputs) + { + if (crtc->numOutputs) + newoutputs = realloc(crtc->outputs, + numOutputs * sizeof (RROutputPtr)); + else + newoutputs = malloc(numOutputs * sizeof (RROutputPtr)); + if (!newoutputs) + return FALSE; + } + else + { + if (crtc->outputs) + free(crtc->outputs); + newoutputs = NULL; + } + crtc->outputs = newoutputs; + crtc->numOutputs = numOutputs; + } + /* + * Copy the new list of outputs into the crtc + */ + memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)); + /* + * Update remaining crtc fields + */ + if (mode != crtc->mode) + { + if (crtc->mode) + RRModeDestroy (crtc->mode); + crtc->mode = mode; + if (mode != NULL) + mode->refcnt++; + RRCrtcChanged (crtc, TRUE); + } + if (x != crtc->x) + { + crtc->x = x; + RRCrtcChanged (crtc, TRUE); + } + if (y != crtc->y) + { + crtc->y = y; + RRCrtcChanged (crtc, TRUE); + } + if (rotation != crtc->rotation) + { + crtc->rotation = rotation; + RRCrtcChanged (crtc, TRUE); + } + if (!RRTransformEqual (transform, &crtc->client_current_transform)) { + RRTransformCopy (&crtc->client_current_transform, transform); + RRCrtcChanged (crtc, TRUE); + } + if (crtc->changed && mode) + { + RRTransformCompute (x, y, + mode->mode.width, mode->mode.height, + rotation, + &crtc->client_current_transform, + &crtc->transform, &crtc->f_transform, + &crtc->f_inverse); + } + return TRUE; +} + +void +RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + rrScrPriv (pScreen); + xRRCrtcChangeNotifyEvent ce; + RRModePtr mode = crtc->mode; + + ce.type = RRNotify + RREventBase; + ce.subCode = RRNotify_CrtcChange; + ce.sequenceNumber = client->sequence; + ce.timestamp = pScrPriv->lastSetTime.milliseconds; + ce.window = pWin->drawable.id; + ce.crtc = crtc->id; + ce.rotation = crtc->rotation; + if (mode) + { + ce.mode = mode->mode.id; + ce.x = crtc->x; + ce.y = crtc->y; + ce.width = mode->mode.width; + ce.height = mode->mode.height; + } + else + { + ce.mode = None; + ce.x = 0; + ce.y = 0; + ce.width = 0; + ce.height = 0; + } + WriteEventsToClient (client, 1, (xEvent *) &ce); +} + +static Bool +RRCrtcPendingProperties (RRCrtcPtr crtc) +{ + ScreenPtr pScreen = crtc->pScreen; + rrScrPriv(pScreen); + int o; + + for (o = 0; o < pScrPriv->numOutputs; o++) + { + RROutputPtr output = pScrPriv->outputs[o]; + if (output->crtc == crtc && output->pendingProperties) + return TRUE; + } + return FALSE; +} + +/* + * Request that the Crtc be reconfigured + */ +Bool +RRCrtcSet (RRCrtcPtr crtc, + RRModePtr mode, + int x, + int y, + Rotation rotation, + int numOutputs, + RROutputPtr *outputs) +{ + ScreenPtr pScreen = crtc->pScreen; + Bool ret = FALSE; + rrScrPriv(pScreen); + + /* See if nothing changed */ + if (crtc->mode == mode && + crtc->x == x && + crtc->y == y && + crtc->rotation == rotation && + crtc->numOutputs == numOutputs && + !memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) && + !RRCrtcPendingProperties (crtc) && + !RRCrtcPendingTransform (crtc)) + { + ret = TRUE; + } + else + { +#if RANDR_12_INTERFACE + if (pScrPriv->rrCrtcSet) + { + ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, + rotation, numOutputs, outputs); + } + else +#endif + { +#if RANDR_10_INTERFACE + if (pScrPriv->rrSetConfig) + { + RRScreenSize size; + RRScreenRate rate; + + if (!mode) + { + RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL); + ret = TRUE; + } + else + { + size.width = mode->mode.width; + size.height = mode->mode.height; + if (outputs[0]->mmWidth && outputs[0]->mmHeight) + { + size.mmWidth = outputs[0]->mmWidth; + size.mmHeight = outputs[0]->mmHeight; + } + else + { + size.mmWidth = pScreen->mmWidth; + size.mmHeight = pScreen->mmHeight; + } + size.nRates = 1; + rate.rate = RRVerticalRefresh (&mode->mode); + size.pRates = &rate; + ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size); + /* + * Old 1.0 interface tied screen size to mode size + */ + if (ret) + { + RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs); + RRScreenSizeNotify (pScreen); + } + } + } +#endif + } + if (ret) + { + int o; + RRTellChanged (pScreen); + + for (o = 0; o < numOutputs; o++) + RRPostPendingProperties (outputs[o]); + } + } + return ret; +} + +/* + * Return crtc transform + */ +RRTransformPtr +RRCrtcGetTransform (RRCrtcPtr crtc) +{ + RRTransformPtr transform = &crtc->client_pending_transform; + + if (pixman_transform_is_identity (&transform->transform)) + return NULL; + return transform; +} + +/* + * Check whether the pending and current transforms are the same + */ +Bool +RRCrtcPendingTransform (RRCrtcPtr crtc) +{ + return memcmp (&crtc->client_current_transform.transform, + &crtc->client_pending_transform.transform, + sizeof (PictTransform)) != 0; +} + +/* + * Destroy a Crtc at shutdown + */ +void +RRCrtcDestroy (RRCrtcPtr crtc) +{ + FreeResource (crtc->id, 0); +} + +static int +RRCrtcDestroyResource (pointer value, XID pid) +{ + RRCrtcPtr crtc = (RRCrtcPtr) value; + ScreenPtr pScreen = crtc->pScreen; + + if (pScreen) + { + rrScrPriv(pScreen); + int i; + + for (i = 0; i < pScrPriv->numCrtcs; i++) + { + if (pScrPriv->crtcs[i] == crtc) + { + memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1, + (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr)); + --pScrPriv->numCrtcs; + break; + } + } + } + if (crtc->gammaRed) + free(crtc->gammaRed); + if (crtc->mode) + RRModeDestroy (crtc->mode); + free(crtc); + return 1; +} + +/* + * Request that the Crtc gamma be changed + */ + +Bool +RRCrtcGammaSet (RRCrtcPtr crtc, + CARD16 *red, + CARD16 *green, + CARD16 *blue) +{ + Bool ret = TRUE; +#if RANDR_12_INTERFACE + ScreenPtr pScreen = crtc->pScreen; +#endif + + memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16)); + memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16)); + memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16)); +#if RANDR_12_INTERFACE + if (pScreen) + { + rrScrPriv(pScreen); + if (pScrPriv->rrCrtcSetGamma) + ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc); + } +#endif + return ret; +} + +/* + * Request current gamma back from the DDX (if possible). + * This includes gamma size. + */ +Bool +RRCrtcGammaGet(RRCrtcPtr crtc) +{ + Bool ret = TRUE; +#if RANDR_12_INTERFACE + ScreenPtr pScreen = crtc->pScreen; +#endif + +#if RANDR_12_INTERFACE + if (pScreen) + { + rrScrPriv(pScreen); + if (pScrPriv->rrCrtcGetGamma) + ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc); + } +#endif + return ret; +} + +/* + * Notify the extension that the Crtc gamma has been changed + * The driver calls this whenever it has changed the gamma values + * in the RRCrtcRec + */ + +Bool +RRCrtcGammaNotify (RRCrtcPtr crtc) +{ + return TRUE; /* not much going on here */ +} + +static void +RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform, + int *width, int *height) +{ + BoxRec box; + + if (mode == NULL) { + *width = 0; + *height = 0; + return; + } + + box.x1 = 0; + box.y1 = 0; + box.x2 = mode->mode.width; + box.y2 = mode->mode.height; + + pixman_transform_bounds (transform, &box); + *width = box.x2 - box.x1; + *height = box.y2 - box.y1; +} + +/** + * Returns the width/height that the crtc scans out from the framebuffer + */ +void +RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) +{ + return RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height); +} + +/* + * Set the size of the gamma table at server startup time + */ + +Bool +RRCrtcGammaSetSize (RRCrtcPtr crtc, + int size) +{ + CARD16 *gamma; + + if (size == crtc->gammaSize) + return TRUE; + if (size) + { + gamma = malloc(size * 3 * sizeof (CARD16)); + if (!gamma) + return FALSE; + } + else + gamma = NULL; + if (crtc->gammaRed) + free(crtc->gammaRed); + crtc->gammaRed = gamma; + crtc->gammaGreen = gamma + size; + crtc->gammaBlue = gamma + size*2; + crtc->gammaSize = size; + return TRUE; +} + +/* + * Set the pending CRTC transformation + */ + +int +RRCrtcTransformSet (RRCrtcPtr crtc, + PictTransformPtr transform, + struct pixman_f_transform *f_transform, + struct pixman_f_transform *f_inverse, + char *filter_name, + int filter_len, + xFixed *params, + int nparams) +{ + PictFilterPtr filter = NULL; + int width = 0, height = 0; + + if (!crtc->transforms) + return BadValue; + + if (filter_len) + { + filter = PictureFindFilter (crtc->pScreen, + filter_name, + filter_len); + if (!filter) + return BadName; + if (filter->ValidateParams) + { + if (!filter->ValidateParams (crtc->pScreen, filter->id, + params, nparams, &width, &height)) + return BadMatch; + } + else { + width = filter->width; + height = filter->height; + } + } + else + { + if (nparams) + return BadMatch; + } + if (!RRTransformSetFilter (&crtc->client_pending_transform, + filter, params, nparams, width, height)) + return BadAlloc; + + crtc->client_pending_transform.transform = *transform; + crtc->client_pending_transform.f_transform = *f_transform; + crtc->client_pending_transform.f_inverse = *f_inverse; + return Success; +} + +/* + * Initialize crtc type + */ +Bool +RRCrtcInit (void) +{ + RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource, "CRTC"); + if (!RRCrtcType) + return FALSE; + return TRUE; +} + +int +ProcRRGetCrtcInfo (ClientPtr client) +{ + REQUEST(xRRGetCrtcInfoReq); + xRRGetCrtcInfoReply rep; + RRCrtcPtr crtc; + CARD8 *extra; + unsigned long extraLen; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + RRModePtr mode; + RROutput *outputs; + RROutput *possible; + int i, j, k, n; + int width, height; + BoxRec panned_area; + + REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); + VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); + + /* All crtcs must be associated with screens before client + * requests are processed + */ + pScreen = crtc->pScreen; + pScrPriv = rrGetScrPriv(pScreen); + + mode = crtc->mode; + + rep.type = X_Reply; + rep.status = RRSetConfigSuccess; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.timestamp = pScrPriv->lastSetTime.milliseconds; + if (pScrPriv->rrGetPanning && + pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) && + (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) + { + rep.x = panned_area.x1; + rep.y = panned_area.y1; + rep.width = panned_area.x2 - panned_area.x1; + rep.height = panned_area.y2 - panned_area.y1; + } + else + { + RRCrtcGetScanoutSize (crtc, &width, &height); + rep.x = crtc->x; + rep.y = crtc->y; + rep.width = width; + rep.height = height; + } + rep.mode = mode ? mode->mode.id : 0; + rep.rotation = crtc->rotation; + rep.rotations = crtc->rotations; + rep.nOutput = crtc->numOutputs; + k = 0; + for (i = 0; i < pScrPriv->numOutputs; i++) + for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) + if (pScrPriv->outputs[i]->crtcs[j] == crtc) + k++; + rep.nPossibleOutput = k; + + rep.length = rep.nOutput + rep.nPossibleOutput; + + extraLen = rep.length << 2; + if (extraLen) + { + extra = malloc(extraLen); + if (!extra) + return BadAlloc; + } + else + extra = NULL; + + outputs = (RROutput *) extra; + possible = (RROutput *) (outputs + rep.nOutput); + + for (i = 0; i < crtc->numOutputs; i++) + { + outputs[i] = crtc->outputs[i]->id; + if (client->swapped) + swapl (&outputs[i], n); + } + k = 0; + for (i = 0; i < pScrPriv->numOutputs; i++) + for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) + if (pScrPriv->outputs[i]->crtcs[j] == crtc) + { + possible[k] = pScrPriv->outputs[i]->id; + if (client->swapped) + swapl (&possible[k], n); + k++; + } + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.timestamp, n); + swaps(&rep.x, n); + swaps(&rep.y, n); + swaps(&rep.width, n); + swaps(&rep.height, n); + swapl(&rep.mode, n); + swaps(&rep.rotation, n); + swaps(&rep.rotations, n); + swaps(&rep.nOutput, n); + swaps(&rep.nPossibleOutput, n); + } + WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep); + if (extraLen) + { + WriteToClient (client, extraLen, (char *) extra); + free(extra); + } + + return Success; +} + +int +ProcRRSetCrtcConfig (ClientPtr client) +{ + REQUEST(xRRSetCrtcConfigReq); + xRRSetCrtcConfigReply rep; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + RRCrtcPtr crtc; + RRModePtr mode; + int numOutputs; + RROutputPtr *outputs = NULL; + RROutput *outputIds; + TimeStamp configTime; + TimeStamp time; + Rotation rotation; + int rc, i, j; + + REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); + numOutputs = (stuff->length - bytes_to_int32(SIZEOF (xRRSetCrtcConfigReq))); + + VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); + + if (stuff->mode == None) + { + mode = NULL; + if (numOutputs > 0) + return BadMatch; + } + else + { + VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); + if (numOutputs == 0) + return BadMatch; + } + if (numOutputs) + { + outputs = malloc(numOutputs * sizeof (RROutputPtr)); + if (!outputs) + return BadAlloc; + } + else + outputs = NULL; + + outputIds = (RROutput *) (stuff + 1); + for (i = 0; i < numOutputs; i++) + { + rc = dixLookupResourceByType((pointer *)(outputs + i), outputIds[i], + RROutputType, client, DixSetAttrAccess); + if (rc != Success) + { + if (outputs) + free(outputs); + return (rc == BadValue) ? RRErrorBase + BadRROutput : rc; + } + /* validate crtc for this output */ + for (j = 0; j < outputs[i]->numCrtcs; j++) + if (outputs[i]->crtcs[j] == crtc) + break; + if (j == outputs[i]->numCrtcs) + { + if (outputs) + free(outputs); + return BadMatch; + } + /* validate mode for this output */ + for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) + { + RRModePtr m = (j < outputs[i]->numModes ? + outputs[i]->modes[j] : + outputs[i]->userModes[j - outputs[i]->numModes]); + if (m == mode) + break; + } + if (j == outputs[i]->numModes + outputs[i]->numUserModes) + { + if (outputs) + free(outputs); + return BadMatch; + } + } + /* validate clones */ + for (i = 0; i < numOutputs; i++) + { + for (j = 0; j < numOutputs; j++) + { + int k; + if (i == j) + continue; + for (k = 0; k < outputs[i]->numClones; k++) + { + if (outputs[i]->clones[k] == outputs[j]) + break; + } + if (k == outputs[i]->numClones) + { + if (outputs) + free(outputs); + return BadMatch; + } + } + } + + pScreen = crtc->pScreen; + pScrPriv = rrGetScrPriv(pScreen); + + time = ClientTimeToServerTime(stuff->timestamp); + configTime = ClientTimeToServerTime(stuff->configTimestamp); + + if (!pScrPriv) + { + time = currentTime; + rep.status = RRSetConfigFailed; + goto sendReply; + } + +#if 0 + /* + * if the client's config timestamp is not the same as the last config + * timestamp, then the config information isn't up-to-date and + * can't even be validated + */ + if (CompareTimeStamps (configTime, pScrPriv->lastConfigTime) != 0) + { + rep.status = RRSetConfigInvalidConfigTime; + goto sendReply; + } +#endif + + /* + * Validate requested rotation + */ + rotation = (Rotation) stuff->rotation; + + /* test the rotation bits only! */ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_90: + case RR_Rotate_180: + case RR_Rotate_270: + break; + default: + /* + * Invalid rotation + */ + client->errorValue = stuff->rotation; + if (outputs) + free(outputs); + return BadValue; + } + + if (mode) + { + if ((~crtc->rotations) & rotation) + { + /* + * requested rotation or reflection not supported by screen + */ + client->errorValue = stuff->rotation; + if (outputs) + free(outputs); + return BadMatch; + } + +#ifdef RANDR_12_INTERFACE + /* + * Check screen size bounds if the DDX provides a 1.2 interface + * for setting screen size. Else, assume the CrtcSet sets + * the size along with the mode. If the driver supports transforms, + * then it must allow crtcs to display a subset of the screen, so + * only do this check for drivers without transform support. + */ + if (pScrPriv->rrScreenSetSize && !crtc->transforms) + { + int source_width; + int source_height; + PictTransform transform; + struct pixman_f_transform f_transform, f_inverse; + + RRTransformCompute (stuff->x, stuff->y, + mode->mode.width, mode->mode.height, + rotation, + &crtc->client_pending_transform, + &transform, &f_transform, &f_inverse); + + RRModeGetScanoutSize (mode, &transform, &source_width, &source_height); + if (stuff->x + source_width > pScreen->width) + { + client->errorValue = stuff->x; + if (outputs) + free(outputs); + return BadValue; + } + + if (stuff->y + source_height > pScreen->height) + { + client->errorValue = stuff->y; + if (outputs) + free(outputs); + return BadValue; + } + } +#endif + } + + /* + * Make sure the requested set-time is not older than + * the last set-time + */ + if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0) + { + rep.status = RRSetConfigInvalidTime; + goto sendReply; + } + + if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y, + rotation, numOutputs, outputs)) + { + rep.status = RRSetConfigFailed; + goto sendReply; + } + rep.status = RRSetConfigSuccess; + pScrPriv->lastSetTime = time; + +sendReply: + if (outputs) + free(outputs); + + rep.type = X_Reply; + /* rep.status has already been filled in */ + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; + + if (client->swapped) + { + int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.newTimestamp, n); + } + WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep); + + return Success; +} + +int +ProcRRGetPanning (ClientPtr client) +{ + REQUEST(xRRGetPanningReq); + xRRGetPanningReply rep; + RRCrtcPtr crtc; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + BoxRec total; + BoxRec tracking; + INT16 border[4]; + int n; + + REQUEST_SIZE_MATCH(xRRGetPanningReq); + VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); + + /* All crtcs must be associated with screens before client + * requests are processed + */ + pScreen = crtc->pScreen; + pScrPriv = rrGetScrPriv(pScreen); + + if (!pScrPriv) + return RRErrorBase + BadRRCrtc; + + memset(&rep, 0, sizeof(rep)); + rep.type = X_Reply; + rep.status = RRSetConfigSuccess; + rep.sequenceNumber = client->sequence; + rep.length = 1; + rep.timestamp = pScrPriv->lastSetTime.milliseconds; + + if (pScrPriv->rrGetPanning && + pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) { + rep.left = total.x1; + rep.top = total.y1; + rep.width = total.x2 - total.x1; + rep.height = total.y2 - total.y1; + rep.track_left = tracking.x1; + rep.track_top = tracking.y1; + rep.track_width = tracking.x2 - tracking.x1; + rep.track_height = tracking.y2 - tracking.y1; + rep.border_left = border[0]; + rep.border_top = border[1]; + rep.border_right = border[2]; + rep.border_bottom = border[3]; + } + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.timestamp, n); + swaps(&rep.left, n); + swaps(&rep.top, n); + swaps(&rep.width, n); + swaps(&rep.height, n); + swaps(&rep.track_left, n); + swaps(&rep.track_top, n); + swaps(&rep.track_width, n); + swaps(&rep.track_height, n); + swaps(&rep.border_left, n); + swaps(&rep.border_top, n); + swaps(&rep.border_right, n); + swaps(&rep.border_bottom, n); + } + WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep); + return Success; +} + +int +ProcRRSetPanning (ClientPtr client) +{ + REQUEST(xRRSetPanningReq); + xRRSetPanningReply rep; + RRCrtcPtr crtc; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + TimeStamp time; + BoxRec total; + BoxRec tracking; + INT16 border[4]; + int n; + + REQUEST_SIZE_MATCH(xRRSetPanningReq); + VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); + + /* All crtcs must be associated with screens before client + * requests are processed + */ + pScreen = crtc->pScreen; + pScrPriv = rrGetScrPriv(pScreen); + + if (!pScrPriv) { + time = currentTime; + rep.status = RRSetConfigFailed; + goto sendReply; + } + + time = ClientTimeToServerTime(stuff->timestamp); + + /* + * Make sure the requested set-time is not older than + * the last set-time + */ + if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0) + { + rep.status = RRSetConfigInvalidTime; + goto sendReply; + } + + if (!pScrPriv->rrGetPanning) + return RRErrorBase + BadRRCrtc; + + total.x1 = stuff->left; + total.y1 = stuff->top; + total.x2 = total.x1 + stuff->width; + total.y2 = total.y1 + stuff->height; + tracking.x1 = stuff->track_left; + tracking.y1 = stuff->track_top; + tracking.x2 = tracking.x1 + stuff->track_width; + tracking.y2 = tracking.y1 + stuff->track_height; + border[0] = stuff->border_left; + border[1] = stuff->border_top; + border[2] = stuff->border_right; + border[3] = stuff->border_bottom; + + if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border)) + return BadMatch; + + pScrPriv->lastSetTime = time; + + rep.status = RRSetConfigSuccess; + +sendReply: + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.newTimestamp, n); + } + WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep); + return Success; +} + +int +ProcRRGetCrtcGammaSize (ClientPtr client) +{ + REQUEST(xRRGetCrtcGammaSizeReq); + xRRGetCrtcGammaSizeReply reply; + RRCrtcPtr crtc; + int n; + + REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); + VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); + + /* Gamma retrieval failed, any better error? */ + if (!RRCrtcGammaGet(crtc)) + return RRErrorBase + BadRRCrtc; + + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = 0; + reply.size = crtc->gammaSize; + if (client->swapped) { + swaps (&reply.sequenceNumber, n); + swapl (&reply.length, n); + swaps (&reply.size, n); + } + WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply); + return Success; +} + +int +ProcRRGetCrtcGamma (ClientPtr client) +{ + REQUEST(xRRGetCrtcGammaReq); + xRRGetCrtcGammaReply reply; + RRCrtcPtr crtc; + int n; + unsigned long len; + char *extra = NULL; + + REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); + VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); + + /* Gamma retrieval failed, any better error? */ + if (!RRCrtcGammaGet(crtc)) + return RRErrorBase + BadRRCrtc; + + len = crtc->gammaSize * 3 * 2; + + if (crtc->gammaSize) { + extra = malloc(len); + if (!extra) + return BadAlloc; + } + + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = bytes_to_int32(len); + reply.size = crtc->gammaSize; + if (client->swapped) { + swaps (&reply.sequenceNumber, n); + swapl (&reply.length, n); + swaps (&reply.size, n); + } + WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply); + if (crtc->gammaSize) + { + memcpy(extra, crtc->gammaRed, len); + client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; + WriteSwappedDataToClient (client, len, extra); + free(extra); + } + return Success; +} + +int +ProcRRSetCrtcGamma (ClientPtr client) +{ + REQUEST(xRRSetCrtcGammaReq); + RRCrtcPtr crtc; + unsigned long len; + CARD16 *red, *green, *blue; + + REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); + VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); + + len = client->req_len - bytes_to_int32(sizeof (xRRSetCrtcGammaReq)); + if (len < (stuff->size * 3 + 1) >> 1) + return BadLength; + + if (stuff->size != crtc->gammaSize) + return BadMatch; + + red = (CARD16 *) (stuff + 1); + green = red + crtc->gammaSize; + blue = green + crtc->gammaSize; + + RRCrtcGammaSet (crtc, red, green, blue); + + return Success; +} + +/* Version 1.3 additions */ + +int +ProcRRSetCrtcTransform (ClientPtr client) +{ + REQUEST(xRRSetCrtcTransformReq); + RRCrtcPtr crtc; + PictTransform transform; + struct pixman_f_transform f_transform, f_inverse; + char *filter; + int nbytes; + xFixed *params; + int nparams; + + REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); + VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); + + PictTransform_from_xRenderTransform (&transform, &stuff->transform); + pixman_f_transform_from_pixman_transform (&f_transform, &transform); + if (!pixman_f_transform_invert (&f_inverse, &f_transform)) + return BadMatch; + + filter = (char *) (stuff + 1); + nbytes = stuff->nbytesFilter; + params = (xFixed *) (filter + pad_to_int32(nbytes)); + nparams = ((xFixed *) stuff + client->req_len) - params; + if (nparams < 0) + return BadLength; + + return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse, + filter, nbytes, params, nparams); +} + + +#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) + +static int +transform_filter_length (RRTransformPtr transform) +{ + int nbytes, nparams; + + if (transform->filter == NULL) + return 0; + nbytes = strlen (transform->filter->name); + nparams = transform->nparams; + return pad_to_int32(nbytes) + (nparams * sizeof (xFixed)); +} + +static int +transform_filter_encode (ClientPtr client, char *output, + CARD16 *nbytesFilter, + CARD16 *nparamsFilter, + RRTransformPtr transform) +{ + int nbytes, nparams; + int n; + + if (transform->filter == NULL) { + *nbytesFilter = 0; + *nparamsFilter = 0; + return 0; + } + nbytes = strlen (transform->filter->name); + nparams = transform->nparams; + *nbytesFilter = nbytes; + *nparamsFilter = nparams; + memcpy (output, transform->filter->name, nbytes); + while ((nbytes & 3) != 0) + output[nbytes++] = 0; + memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed)); + if (client->swapped) { + swaps (nbytesFilter, n); + swaps (nparamsFilter, n); + SwapLongs ((CARD32 *) (output + nbytes), nparams); + } + nbytes += nparams * sizeof (xFixed); + return nbytes; +} + +static void +transform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict) +{ + xRenderTransform_from_PictTransform (wire, pict); + if (client->swapped) + SwapLongs ((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); +} + +int +ProcRRGetCrtcTransform (ClientPtr client) +{ + REQUEST(xRRGetCrtcTransformReq); + xRRGetCrtcTransformReply *reply; + RRCrtcPtr crtc; + int n, nextra; + RRTransformPtr current, pending; + char *extra; + + REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq); + VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); + + pending = &crtc->client_pending_transform; + current = &crtc->client_current_transform; + + nextra = (transform_filter_length (pending) + + transform_filter_length (current)); + + reply = malloc(sizeof (xRRGetCrtcTransformReply) + nextra); + if (!reply) + return BadAlloc; + + extra = (char *) (reply + 1); + reply->type = X_Reply; + reply->sequenceNumber = client->sequence; + reply->length = bytes_to_int32(CrtcTransformExtra + nextra); + + reply->hasTransforms = crtc->transforms; + + transform_encode (client, &reply->pendingTransform, &pending->transform); + extra += transform_filter_encode (client, extra, + &reply->pendingNbytesFilter, + &reply->pendingNparamsFilter, + pending); + + transform_encode (client, &reply->currentTransform, ¤t->transform); + extra += transform_filter_encode (client, extra, + &reply->currentNbytesFilter, + &reply->currentNparamsFilter, + current); + + if (client->swapped) { + swaps (&reply->sequenceNumber, n); + swapl (&reply->length, n); + } + WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply); + free(reply); + return Success; +} diff --git a/xorg-server/randr/rrdispatch.c b/xorg-server/randr/rrdispatch.c index ffb46a48c..b54086bcb 100644 --- a/xorg-server/randr/rrdispatch.c +++ b/xorg-server/randr/rrdispatch.c @@ -1,228 +1,228 @@ -/* - * Copyright © 2006 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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. - */ - -#include "randrstr.h" -#include "protocol-versions.h" - -Bool -RRClientKnowsRates (ClientPtr pClient) -{ - rrClientPriv(pClient); - - return (pRRClient->major_version > 1 || - (pRRClient->major_version == 1 && pRRClient->minor_version >= 1)); -} - -static int -ProcRRQueryVersion (ClientPtr client) -{ - xRRQueryVersionReply rep; - register int n; - REQUEST(xRRQueryVersionReq); - rrClientPriv(client); - - REQUEST_SIZE_MATCH(xRRQueryVersionReq); - pRRClient->major_version = stuff->majorVersion; - pRRClient->minor_version = stuff->minorVersion; - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if ((stuff->majorVersion * 1000 + stuff->minorVersion) < - (SERVER_RANDR_MAJOR_VERSION * 1000 + SERVER_RANDR_MINOR_VERSION)) - { - rep.majorVersion = stuff->majorVersion; - rep.minorVersion = stuff->minorVersion; - } else - { - rep.majorVersion = SERVER_RANDR_MAJOR_VERSION; - rep.minorVersion = SERVER_RANDR_MINOR_VERSION; - } - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.majorVersion, n); - swapl(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xRRQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -static int -ProcRRSelectInput (ClientPtr client) -{ - REQUEST(xRRSelectInputReq); - rrClientPriv(client); - RRTimesPtr pTimes; - WindowPtr pWin; - RREventPtr pRREvent, *pHead; - XID clientResource; - int rc; - - REQUEST_SIZE_MATCH(xRRSelectInputReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixReceiveAccess); - if (rc != Success) - return rc; - rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, - RREventType, client, DixWriteAccess); - if (rc != Success && rc != BadValue) - return rc; - - if (stuff->enable & (RRScreenChangeNotifyMask| - RRCrtcChangeNotifyMask| - RROutputChangeNotifyMask| - RROutputPropertyNotifyMask)) - { - ScreenPtr pScreen = pWin->drawable.pScreen; - rrScrPriv (pScreen); - - pRREvent = NULL; - if (pHead) - { - /* check for existing entry. */ - for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) - if (pRREvent->client == client) - break; - } - - if (!pRREvent) - { - /* build the entry */ - pRREvent = (RREventPtr) xalloc (sizeof (RREventRec)); - if (!pRREvent) - return BadAlloc; - pRREvent->next = 0; - pRREvent->client = client; - pRREvent->window = pWin; - pRREvent->mask = stuff->enable; - /* - * add a resource that will be deleted when - * the client goes away - */ - clientResource = FakeClientID (client->index); - pRREvent->clientResource = clientResource; - if (!AddResource (clientResource, RRClientType, (pointer)pRREvent)) - 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 = (RREventPtr *) xalloc (sizeof (RREventPtr)); - if (!pHead || - !AddResource (pWin->drawable.id, RREventType, (pointer)pHead)) - { - FreeResource (clientResource, RT_NONE); - return BadAlloc; - } - *pHead = 0; - } - pRREvent->next = *pHead; - *pHead = pRREvent; - } - /* - * Now see if the client needs an event - */ - if (pScrPriv && (pRREvent->mask & RRScreenChangeNotifyMask)) - { - pTimes = &((RRTimesPtr) (pRRClient + 1))[pScreen->myNum]; - if (CompareTimeStamps (pTimes->setTime, - pScrPriv->lastSetTime) != 0 || - CompareTimeStamps (pTimes->configTime, - pScrPriv->lastConfigTime) != 0) - { - RRDeliverScreenEvent (client, pWin, pScreen); - } - } - } - else if (stuff->enable == 0) - { - /* delete the interest */ - if (pHead) { - RREventPtr pNewRREvent = 0; - for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) { - if (pRREvent->client == client) - break; - pNewRREvent = pRREvent; - } - if (pRREvent) { - FreeResource (pRREvent->clientResource, RRClientType); - if (pNewRREvent) - pNewRREvent->next = pRREvent->next; - else - *pHead = pRREvent->next; - xfree (pRREvent); - } - } - } - else - { - client->errorValue = stuff->enable; - return BadValue; - } - return Success; -} - -int (*ProcRandrVector[RRNumberRequests])(ClientPtr) = { - ProcRRQueryVersion, /* 0 */ -/* we skip 1 to make old clients fail pretty immediately */ - NULL, /* 1 ProcRandrOldGetScreenInfo */ -/* V1.0 apps share the same set screen config request id */ - ProcRRSetScreenConfig, /* 2 */ - NULL, /* 3 ProcRandrOldScreenChangeSelectInput */ -/* 3 used to be ScreenChangeSelectInput; deprecated */ - ProcRRSelectInput, /* 4 */ - ProcRRGetScreenInfo, /* 5 */ -/* V1.2 additions */ - ProcRRGetScreenSizeRange, /* 6 */ - ProcRRSetScreenSize, /* 7 */ - ProcRRGetScreenResources, /* 8 */ - ProcRRGetOutputInfo, /* 9 */ - ProcRRListOutputProperties, /* 10 */ - ProcRRQueryOutputProperty, /* 11 */ - ProcRRConfigureOutputProperty, /* 12 */ - ProcRRChangeOutputProperty, /* 13 */ - ProcRRDeleteOutputProperty, /* 14 */ - ProcRRGetOutputProperty, /* 15 */ - ProcRRCreateMode, /* 16 */ - ProcRRDestroyMode, /* 17 */ - ProcRRAddOutputMode, /* 18 */ - ProcRRDeleteOutputMode, /* 19 */ - ProcRRGetCrtcInfo, /* 20 */ - ProcRRSetCrtcConfig, /* 21 */ - ProcRRGetCrtcGammaSize, /* 22 */ - ProcRRGetCrtcGamma, /* 23 */ - ProcRRSetCrtcGamma, /* 24 */ -/* V1.3 additions */ - ProcRRGetScreenResourcesCurrent, /* 25 */ - ProcRRSetCrtcTransform, /* 26 */ - ProcRRGetCrtcTransform, /* 27 */ - ProcRRGetPanning, /* 28 */ - ProcRRSetPanning, /* 29 */ - ProcRRSetOutputPrimary, /* 30 */ - ProcRRGetOutputPrimary, /* 31 */ -}; - +/* + * Copyright © 2006 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "randrstr.h" +#include "protocol-versions.h" + +Bool +RRClientKnowsRates (ClientPtr pClient) +{ + rrClientPriv(pClient); + + return (pRRClient->major_version > 1 || + (pRRClient->major_version == 1 && pRRClient->minor_version >= 1)); +} + +static int +ProcRRQueryVersion (ClientPtr client) +{ + xRRQueryVersionReply rep; + register int n; + REQUEST(xRRQueryVersionReq); + rrClientPriv(client); + + REQUEST_SIZE_MATCH(xRRQueryVersionReq); + pRRClient->major_version = stuff->majorVersion; + pRRClient->minor_version = stuff->minorVersion; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if ((stuff->majorVersion * 1000 + stuff->minorVersion) < + (SERVER_RANDR_MAJOR_VERSION * 1000 + SERVER_RANDR_MINOR_VERSION)) + { + rep.majorVersion = stuff->majorVersion; + rep.minorVersion = stuff->minorVersion; + } else + { + rep.majorVersion = SERVER_RANDR_MAJOR_VERSION; + rep.minorVersion = SERVER_RANDR_MINOR_VERSION; + } + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xRRQueryVersionReply), (char *)&rep); + return Success; +} + +static int +ProcRRSelectInput (ClientPtr client) +{ + REQUEST(xRRSelectInputReq); + rrClientPriv(client); + RRTimesPtr pTimes; + WindowPtr pWin; + RREventPtr pRREvent, *pHead; + XID clientResource; + int rc; + + REQUEST_SIZE_MATCH(xRRSelectInputReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixReceiveAccess); + if (rc != Success) + return rc; + rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, + RREventType, client, DixWriteAccess); + if (rc != Success && rc != BadValue) + return rc; + + if (stuff->enable & (RRScreenChangeNotifyMask| + RRCrtcChangeNotifyMask| + RROutputChangeNotifyMask| + RROutputPropertyNotifyMask)) + { + ScreenPtr pScreen = pWin->drawable.pScreen; + rrScrPriv (pScreen); + + pRREvent = NULL; + if (pHead) + { + /* check for existing entry. */ + for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) + if (pRREvent->client == client) + break; + } + + if (!pRREvent) + { + /* build the entry */ + pRREvent = (RREventPtr) malloc(sizeof (RREventRec)); + if (!pRREvent) + return BadAlloc; + pRREvent->next = 0; + pRREvent->client = client; + pRREvent->window = pWin; + pRREvent->mask = stuff->enable; + /* + * add a resource that will be deleted when + * the client goes away + */ + clientResource = FakeClientID (client->index); + pRREvent->clientResource = clientResource; + if (!AddResource (clientResource, RRClientType, (pointer)pRREvent)) + 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 = (RREventPtr *) malloc(sizeof (RREventPtr)); + if (!pHead || + !AddResource (pWin->drawable.id, RREventType, (pointer)pHead)) + { + FreeResource (clientResource, RT_NONE); + return BadAlloc; + } + *pHead = 0; + } + pRREvent->next = *pHead; + *pHead = pRREvent; + } + /* + * Now see if the client needs an event + */ + if (pScrPriv && (pRREvent->mask & RRScreenChangeNotifyMask)) + { + pTimes = &((RRTimesPtr) (pRRClient + 1))[pScreen->myNum]; + if (CompareTimeStamps (pTimes->setTime, + pScrPriv->lastSetTime) != 0 || + CompareTimeStamps (pTimes->configTime, + pScrPriv->lastConfigTime) != 0) + { + RRDeliverScreenEvent (client, pWin, pScreen); + } + } + } + else if (stuff->enable == 0) + { + /* delete the interest */ + if (pHead) { + RREventPtr pNewRREvent = 0; + for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) { + if (pRREvent->client == client) + break; + pNewRREvent = pRREvent; + } + if (pRREvent) { + FreeResource (pRREvent->clientResource, RRClientType); + if (pNewRREvent) + pNewRREvent->next = pRREvent->next; + else + *pHead = pRREvent->next; + free(pRREvent); + } + } + } + else + { + client->errorValue = stuff->enable; + return BadValue; + } + return Success; +} + +int (*ProcRandrVector[RRNumberRequests])(ClientPtr) = { + ProcRRQueryVersion, /* 0 */ +/* we skip 1 to make old clients fail pretty immediately */ + NULL, /* 1 ProcRandrOldGetScreenInfo */ +/* V1.0 apps share the same set screen config request id */ + ProcRRSetScreenConfig, /* 2 */ + NULL, /* 3 ProcRandrOldScreenChangeSelectInput */ +/* 3 used to be ScreenChangeSelectInput; deprecated */ + ProcRRSelectInput, /* 4 */ + ProcRRGetScreenInfo, /* 5 */ +/* V1.2 additions */ + ProcRRGetScreenSizeRange, /* 6 */ + ProcRRSetScreenSize, /* 7 */ + ProcRRGetScreenResources, /* 8 */ + ProcRRGetOutputInfo, /* 9 */ + ProcRRListOutputProperties, /* 10 */ + ProcRRQueryOutputProperty, /* 11 */ + ProcRRConfigureOutputProperty, /* 12 */ + ProcRRChangeOutputProperty, /* 13 */ + ProcRRDeleteOutputProperty, /* 14 */ + ProcRRGetOutputProperty, /* 15 */ + ProcRRCreateMode, /* 16 */ + ProcRRDestroyMode, /* 17 */ + ProcRRAddOutputMode, /* 18 */ + ProcRRDeleteOutputMode, /* 19 */ + ProcRRGetCrtcInfo, /* 20 */ + ProcRRSetCrtcConfig, /* 21 */ + ProcRRGetCrtcGammaSize, /* 22 */ + ProcRRGetCrtcGamma, /* 23 */ + ProcRRSetCrtcGamma, /* 24 */ +/* V1.3 additions */ + ProcRRGetScreenResourcesCurrent, /* 25 */ + ProcRRSetCrtcTransform, /* 26 */ + ProcRRGetCrtcTransform, /* 27 */ + ProcRRGetPanning, /* 28 */ + ProcRRSetPanning, /* 29 */ + ProcRRSetOutputPrimary, /* 30 */ + ProcRRGetOutputPrimary, /* 31 */ +}; + diff --git a/xorg-server/randr/rrinfo.c b/xorg-server/randr/rrinfo.c index 20066d5fc..04c1a6c98 100644 --- a/xorg-server/randr/rrinfo.c +++ b/xorg-server/randr/rrinfo.c @@ -1,341 +1,341 @@ -/* - * Copyright © 2006 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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. - */ - -#include "randrstr.h" - -#ifdef RANDR_10_INTERFACE -static RRModePtr -RROldModeAdd (RROutputPtr output, RRScreenSizePtr size, int refresh) -{ - ScreenPtr pScreen = output->pScreen; - rrScrPriv(pScreen); - xRRModeInfo modeInfo; - char name[100]; - RRModePtr mode; - int i; - RRModePtr *modes; - - memset (&modeInfo, '\0', sizeof (modeInfo)); - sprintf (name, "%dx%d", size->width, size->height); - - modeInfo.width = size->width; - modeInfo.height = size->height; - modeInfo.hTotal = size->width; - modeInfo.vTotal = size->height; - modeInfo.dotClock = ((CARD32) size->width * (CARD32) size->height * - (CARD32) refresh); - modeInfo.nameLength = strlen (name); - mode = RRModeGet (&modeInfo, name); - if (!mode) - return NULL; - for (i = 0; i < output->numModes; i++) - if (output->modes[i] == mode) - { - RRModeDestroy (mode); - return mode; - } - - if (output->numModes) - modes = xrealloc (output->modes, - (output->numModes + 1) * sizeof (RRModePtr)); - else - modes = xalloc (sizeof (RRModePtr)); - if (!modes) - { - RRModeDestroy (mode); - FreeResource (mode->mode.id, 0); - return NULL; - } - modes[output->numModes++] = mode; - output->modes = modes; - output->changed = TRUE; - pScrPriv->changed = TRUE; - pScrPriv->configChanged = TRUE; - return mode; -} - -static void -RRScanOldConfig (ScreenPtr pScreen, Rotation rotations) -{ - rrScrPriv(pScreen); - RROutputPtr output; - RRCrtcPtr crtc; - RRModePtr mode, newMode = NULL; - int i; - CARD16 minWidth = MAXSHORT, minHeight = MAXSHORT; - CARD16 maxWidth = 0, maxHeight = 0; - - /* - * First time through, create a crtc and output and hook - * them together - */ - if (pScrPriv->numOutputs == 0 && - pScrPriv->numCrtcs == 0) - { - crtc = RRCrtcCreate (pScreen, NULL); - if (!crtc) - return; - output = RROutputCreate (pScreen, "default", 7, NULL); - if (!output) - return; - RROutputSetCrtcs (output, &crtc, 1); - RROutputSetConnection (output, RR_Connected); - RROutputSetSubpixelOrder (output, PictureGetSubpixelOrder (pScreen)); - } - - output = pScrPriv->outputs[0]; - if (!output) - return; - crtc = pScrPriv->crtcs[0]; - if (!crtc) - return; - - /* check rotations */ - if (rotations != crtc->rotations) - { - crtc->rotations = rotations; - crtc->changed = TRUE; - pScrPriv->changed = TRUE; - } - - /* regenerate mode list */ - for (i = 0; i < pScrPriv->nSizes; i++) - { - RRScreenSizePtr size = &pScrPriv->pSizes[i]; - int r; - - if (size->nRates) - { - for (r = 0; r < size->nRates; r++) - { - mode = RROldModeAdd (output, size, size->pRates[r].rate); - if (i == pScrPriv->size && - size->pRates[r].rate == pScrPriv->rate) - { - newMode = mode; - } - } - xfree (size->pRates); - } - else - { - mode = RROldModeAdd (output, size, 0); - if (i == pScrPriv->size) - newMode = mode; - } - } - if (pScrPriv->nSizes) - xfree (pScrPriv->pSizes); - pScrPriv->pSizes = NULL; - pScrPriv->nSizes = 0; - - /* find size bounds */ - for (i = 0; i < output->numModes + output->numUserModes; i++) - { - RRModePtr mode = (i < output->numModes ? - output->modes[i] : - output->userModes[i-output->numModes]); - CARD16 width = mode->mode.width; - CARD16 height = mode->mode.height; - - if (width < minWidth) minWidth = width; - if (width > maxWidth) maxWidth = width; - if (height < minHeight) minHeight = height; - if (height > maxHeight) maxHeight = height; - } - - RRScreenSetSizeRange (pScreen, minWidth, minHeight, maxWidth, maxHeight); - - /* notice current mode */ - if (newMode) - RRCrtcNotify (crtc, newMode, 0, 0, pScrPriv->rotation, - NULL, 1, &output); -} -#endif - -/* - * Poll the driver for changed information - */ -Bool -RRGetInfo (ScreenPtr pScreen, Bool force_query) -{ - rrScrPriv (pScreen); - Rotation rotations; - int i; - - /* Return immediately if we don't need to re-query and we already have the - * information. - */ - if (!force_query) { - if (pScrPriv->numCrtcs != 0 || pScrPriv->numOutputs != 0) - return TRUE; - } - - for (i = 0; i < pScrPriv->numOutputs; i++) - pScrPriv->outputs[i]->changed = FALSE; - for (i = 0; i < pScrPriv->numCrtcs; i++) - pScrPriv->crtcs[i]->changed = FALSE; - - rotations = 0; - pScrPriv->changed = FALSE; - pScrPriv->configChanged = FALSE; - - if (!(*pScrPriv->rrGetInfo) (pScreen, &rotations)) - return FALSE; - -#if RANDR_10_INTERFACE - if (pScrPriv->nSizes) - RRScanOldConfig (pScreen, rotations); -#endif - RRTellChanged (pScreen); - return TRUE; -} - -/* - * Register the range of sizes for the screen - */ -void -RRScreenSetSizeRange (ScreenPtr pScreen, - CARD16 minWidth, - CARD16 minHeight, - CARD16 maxWidth, - CARD16 maxHeight) -{ - rrScrPriv (pScreen); - - if (!pScrPriv) - return; - if (pScrPriv->minWidth == minWidth && pScrPriv->minHeight == minHeight && - pScrPriv->maxWidth == maxWidth && pScrPriv->maxHeight == maxHeight) - { - return; - } - - pScrPriv->minWidth = minWidth; - pScrPriv->minHeight = minHeight; - pScrPriv->maxWidth = maxWidth; - pScrPriv->maxHeight = maxHeight; - pScrPriv->changed = TRUE; - pScrPriv->configChanged = TRUE; -} - -#ifdef RANDR_10_INTERFACE -static Bool -RRScreenSizeMatches (RRScreenSizePtr a, - RRScreenSizePtr b) -{ - if (a->width != b->width) - return FALSE; - if (a->height != b->height) - return FALSE; - if (a->mmWidth != b->mmWidth) - return FALSE; - if (a->mmHeight != b->mmHeight) - return FALSE; - return TRUE; -} - -RRScreenSizePtr -RRRegisterSize (ScreenPtr pScreen, - short width, - short height, - short mmWidth, - short mmHeight) -{ - rrScrPriv (pScreen); - int i; - RRScreenSize tmp; - RRScreenSizePtr pNew; - - if (!pScrPriv) - return 0; - - tmp.id = 0; - tmp.width = width; - tmp.height= height; - tmp.mmWidth = mmWidth; - tmp.mmHeight = mmHeight; - tmp.pRates = 0; - tmp.nRates = 0; - for (i = 0; i < pScrPriv->nSizes; i++) - if (RRScreenSizeMatches (&tmp, &pScrPriv->pSizes[i])) - return &pScrPriv->pSizes[i]; - pNew = xrealloc (pScrPriv->pSizes, - (pScrPriv->nSizes + 1) * sizeof (RRScreenSize)); - if (!pNew) - return 0; - pNew[pScrPriv->nSizes++] = tmp; - pScrPriv->pSizes = pNew; - return &pNew[pScrPriv->nSizes-1]; -} - -Bool RRRegisterRate (ScreenPtr pScreen, - RRScreenSizePtr pSize, - int rate) -{ - rrScrPriv(pScreen); - int i; - RRScreenRatePtr pNew, pRate; - - if (!pScrPriv) - return FALSE; - - for (i = 0; i < pSize->nRates; i++) - if (pSize->pRates[i].rate == rate) - return TRUE; - - pNew = xrealloc (pSize->pRates, - (pSize->nRates + 1) * sizeof (RRScreenRate)); - if (!pNew) - return FALSE; - pRate = &pNew[pSize->nRates++]; - pRate->rate = rate; - pSize->pRates = pNew; - return TRUE; -} - -Rotation -RRGetRotation(ScreenPtr pScreen) -{ - RROutputPtr output = RRFirstOutput (pScreen); - - if (!output) - return RR_Rotate_0; - - return output->crtc->rotation; -} - -void -RRSetCurrentConfig (ScreenPtr pScreen, - Rotation rotation, - int rate, - RRScreenSizePtr pSize) -{ - rrScrPriv (pScreen); - - if (!pScrPriv) - return; - pScrPriv->size = pSize - pScrPriv->pSizes; - pScrPriv->rotation = rotation; - pScrPriv->rate = rate; -} -#endif +/* + * Copyright © 2006 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "randrstr.h" + +#ifdef RANDR_10_INTERFACE +static RRModePtr +RROldModeAdd (RROutputPtr output, RRScreenSizePtr size, int refresh) +{ + ScreenPtr pScreen = output->pScreen; + rrScrPriv(pScreen); + xRRModeInfo modeInfo; + char name[100]; + RRModePtr mode; + int i; + RRModePtr *modes; + + memset (&modeInfo, '\0', sizeof (modeInfo)); + sprintf (name, "%dx%d", size->width, size->height); + + modeInfo.width = size->width; + modeInfo.height = size->height; + modeInfo.hTotal = size->width; + modeInfo.vTotal = size->height; + modeInfo.dotClock = ((CARD32) size->width * (CARD32) size->height * + (CARD32) refresh); + modeInfo.nameLength = strlen (name); + mode = RRModeGet (&modeInfo, name); + if (!mode) + return NULL; + for (i = 0; i < output->numModes; i++) + if (output->modes[i] == mode) + { + RRModeDestroy (mode); + return mode; + } + + if (output->numModes) + modes = realloc(output->modes, + (output->numModes + 1) * sizeof (RRModePtr)); + else + modes = malloc(sizeof (RRModePtr)); + if (!modes) + { + RRModeDestroy (mode); + FreeResource (mode->mode.id, 0); + return NULL; + } + modes[output->numModes++] = mode; + output->modes = modes; + output->changed = TRUE; + pScrPriv->changed = TRUE; + pScrPriv->configChanged = TRUE; + return mode; +} + +static void +RRScanOldConfig (ScreenPtr pScreen, Rotation rotations) +{ + rrScrPriv(pScreen); + RROutputPtr output; + RRCrtcPtr crtc; + RRModePtr mode, newMode = NULL; + int i; + CARD16 minWidth = MAXSHORT, minHeight = MAXSHORT; + CARD16 maxWidth = 0, maxHeight = 0; + + /* + * First time through, create a crtc and output and hook + * them together + */ + if (pScrPriv->numOutputs == 0 && + pScrPriv->numCrtcs == 0) + { + crtc = RRCrtcCreate (pScreen, NULL); + if (!crtc) + return; + output = RROutputCreate (pScreen, "default", 7, NULL); + if (!output) + return; + RROutputSetCrtcs (output, &crtc, 1); + RROutputSetConnection (output, RR_Connected); + RROutputSetSubpixelOrder (output, PictureGetSubpixelOrder (pScreen)); + } + + output = pScrPriv->outputs[0]; + if (!output) + return; + crtc = pScrPriv->crtcs[0]; + if (!crtc) + return; + + /* check rotations */ + if (rotations != crtc->rotations) + { + crtc->rotations = rotations; + crtc->changed = TRUE; + pScrPriv->changed = TRUE; + } + + /* regenerate mode list */ + for (i = 0; i < pScrPriv->nSizes; i++) + { + RRScreenSizePtr size = &pScrPriv->pSizes[i]; + int r; + + if (size->nRates) + { + for (r = 0; r < size->nRates; r++) + { + mode = RROldModeAdd (output, size, size->pRates[r].rate); + if (i == pScrPriv->size && + size->pRates[r].rate == pScrPriv->rate) + { + newMode = mode; + } + } + free(size->pRates); + } + else + { + mode = RROldModeAdd (output, size, 0); + if (i == pScrPriv->size) + newMode = mode; + } + } + if (pScrPriv->nSizes) + free(pScrPriv->pSizes); + pScrPriv->pSizes = NULL; + pScrPriv->nSizes = 0; + + /* find size bounds */ + for (i = 0; i < output->numModes + output->numUserModes; i++) + { + RRModePtr mode = (i < output->numModes ? + output->modes[i] : + output->userModes[i-output->numModes]); + CARD16 width = mode->mode.width; + CARD16 height = mode->mode.height; + + if (width < minWidth) minWidth = width; + if (width > maxWidth) maxWidth = width; + if (height < minHeight) minHeight = height; + if (height > maxHeight) maxHeight = height; + } + + RRScreenSetSizeRange (pScreen, minWidth, minHeight, maxWidth, maxHeight); + + /* notice current mode */ + if (newMode) + RRCrtcNotify (crtc, newMode, 0, 0, pScrPriv->rotation, + NULL, 1, &output); +} +#endif + +/* + * Poll the driver for changed information + */ +Bool +RRGetInfo (ScreenPtr pScreen, Bool force_query) +{ + rrScrPriv (pScreen); + Rotation rotations; + int i; + + /* Return immediately if we don't need to re-query and we already have the + * information. + */ + if (!force_query) { + if (pScrPriv->numCrtcs != 0 || pScrPriv->numOutputs != 0) + return TRUE; + } + + for (i = 0; i < pScrPriv->numOutputs; i++) + pScrPriv->outputs[i]->changed = FALSE; + for (i = 0; i < pScrPriv->numCrtcs; i++) + pScrPriv->crtcs[i]->changed = FALSE; + + rotations = 0; + pScrPriv->changed = FALSE; + pScrPriv->configChanged = FALSE; + + if (!(*pScrPriv->rrGetInfo) (pScreen, &rotations)) + return FALSE; + +#if RANDR_10_INTERFACE + if (pScrPriv->nSizes) + RRScanOldConfig (pScreen, rotations); +#endif + RRTellChanged (pScreen); + return TRUE; +} + +/* + * Register the range of sizes for the screen + */ +void +RRScreenSetSizeRange (ScreenPtr pScreen, + CARD16 minWidth, + CARD16 minHeight, + CARD16 maxWidth, + CARD16 maxHeight) +{ + rrScrPriv (pScreen); + + if (!pScrPriv) + return; + if (pScrPriv->minWidth == minWidth && pScrPriv->minHeight == minHeight && + pScrPriv->maxWidth == maxWidth && pScrPriv->maxHeight == maxHeight) + { + return; + } + + pScrPriv->minWidth = minWidth; + pScrPriv->minHeight = minHeight; + pScrPriv->maxWidth = maxWidth; + pScrPriv->maxHeight = maxHeight; + pScrPriv->changed = TRUE; + pScrPriv->configChanged = TRUE; +} + +#ifdef RANDR_10_INTERFACE +static Bool +RRScreenSizeMatches (RRScreenSizePtr a, + RRScreenSizePtr b) +{ + if (a->width != b->width) + return FALSE; + if (a->height != b->height) + return FALSE; + if (a->mmWidth != b->mmWidth) + return FALSE; + if (a->mmHeight != b->mmHeight) + return FALSE; + return TRUE; +} + +RRScreenSizePtr +RRRegisterSize (ScreenPtr pScreen, + short width, + short height, + short mmWidth, + short mmHeight) +{ + rrScrPriv (pScreen); + int i; + RRScreenSize tmp; + RRScreenSizePtr pNew; + + if (!pScrPriv) + return 0; + + tmp.id = 0; + tmp.width = width; + tmp.height= height; + tmp.mmWidth = mmWidth; + tmp.mmHeight = mmHeight; + tmp.pRates = 0; + tmp.nRates = 0; + for (i = 0; i < pScrPriv->nSizes; i++) + if (RRScreenSizeMatches (&tmp, &pScrPriv->pSizes[i])) + return &pScrPriv->pSizes[i]; + pNew = realloc(pScrPriv->pSizes, + (pScrPriv->nSizes + 1) * sizeof (RRScreenSize)); + if (!pNew) + return 0; + pNew[pScrPriv->nSizes++] = tmp; + pScrPriv->pSizes = pNew; + return &pNew[pScrPriv->nSizes-1]; +} + +Bool RRRegisterRate (ScreenPtr pScreen, + RRScreenSizePtr pSize, + int rate) +{ + rrScrPriv(pScreen); + int i; + RRScreenRatePtr pNew, pRate; + + if (!pScrPriv) + return FALSE; + + for (i = 0; i < pSize->nRates; i++) + if (pSize->pRates[i].rate == rate) + return TRUE; + + pNew = realloc(pSize->pRates, + (pSize->nRates + 1) * sizeof (RRScreenRate)); + if (!pNew) + return FALSE; + pRate = &pNew[pSize->nRates++]; + pRate->rate = rate; + pSize->pRates = pNew; + return TRUE; +} + +Rotation +RRGetRotation(ScreenPtr pScreen) +{ + RROutputPtr output = RRFirstOutput (pScreen); + + if (!output) + return RR_Rotate_0; + + return output->crtc->rotation; +} + +void +RRSetCurrentConfig (ScreenPtr pScreen, + Rotation rotation, + int rate, + RRScreenSizePtr pSize) +{ + rrScrPriv (pScreen); + + if (!pScrPriv) + return; + pScrPriv->size = pSize - pScrPriv->pSizes; + pScrPriv->rotation = rotation; + pScrPriv->rate = rate; +} +#endif diff --git a/xorg-server/randr/rrmode.c b/xorg-server/randr/rrmode.c index 139619367..7412e6f3e 100644 --- a/xorg-server/randr/rrmode.c +++ b/xorg-server/randr/rrmode.c @@ -1,369 +1,369 @@ -/* - * Copyright © 2006 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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. - */ - -#include "randrstr.h" - -RESTYPE RRModeType; - -static Bool -RRModeEqual (xRRModeInfo *a, xRRModeInfo *b) -{ - if (a->width != b->width) return FALSE; - if (a->height != b->height) return FALSE; - if (a->dotClock != b->dotClock) return FALSE; - if (a->hSyncStart != b->hSyncStart) return FALSE; - if (a->hSyncEnd != b->hSyncEnd) return FALSE; - if (a->hTotal != b->hTotal) return FALSE; - if (a->hSkew != b->hSkew) return FALSE; - if (a->vSyncStart != b->vSyncStart) return FALSE; - if (a->vSyncEnd != b->vSyncEnd) return FALSE; - if (a->vTotal != b->vTotal) return FALSE; - if (a->nameLength != b->nameLength) return FALSE; - if (a->modeFlags != b->modeFlags) return FALSE; - return TRUE; -} - -/* - * Keep a list so it's easy to find modes in the resource database. - */ -static int num_modes; -static RRModePtr *modes; - -static RRModePtr -RRModeCreate (xRRModeInfo *modeInfo, - const char *name, - ScreenPtr userScreen) -{ - RRModePtr mode, *newModes; - - if (!RRInit ()) - return NULL; - - mode = xalloc (sizeof (RRModeRec) + modeInfo->nameLength + 1); - if (!mode) - return NULL; - mode->refcnt = 1; - mode->mode = *modeInfo; - mode->name = (char *) (mode + 1); - memcpy (mode->name, name, modeInfo->nameLength); - mode->name[modeInfo->nameLength] = '\0'; - mode->userScreen = userScreen; - - if (num_modes) - newModes = xrealloc (modes, (num_modes + 1) * sizeof (RRModePtr)); - else - newModes = xalloc (sizeof (RRModePtr)); - - if (!newModes) - { - xfree (mode); - return NULL; - } - - mode->mode.id = FakeClientID(0); - if (!AddResource (mode->mode.id, RRModeType, (pointer) mode)) - return NULL; - modes = newModes; - modes[num_modes++] = mode; - - /* - * give the caller a reference to this mode - */ - ++mode->refcnt; - return mode; -} - -static RRModePtr -RRModeFindByName (const char *name, - CARD16 nameLength) -{ - int i; - RRModePtr mode; - - for (i = 0; i < num_modes; i++) - { - mode = modes[i]; - if (mode->mode.nameLength == nameLength && - !memcmp (name, mode->name, nameLength)) - { - return mode; - } - } - return NULL; -} - -RRModePtr -RRModeGet (xRRModeInfo *modeInfo, - const char *name) -{ - int i; - - for (i = 0; i < num_modes; i++) - { - RRModePtr mode = modes[i]; - if (RRModeEqual (&mode->mode, modeInfo) && - !memcmp (name, mode->name, modeInfo->nameLength)) - { - ++mode->refcnt; - return mode; - } - } - - return RRModeCreate (modeInfo, name, NULL); -} - -static RRModePtr -RRModeCreateUser (ScreenPtr pScreen, - xRRModeInfo *modeInfo, - const char *name, - int *error) -{ - RRModePtr mode; - - mode = RRModeFindByName (name, modeInfo->nameLength); - if (mode) - { - *error = BadName; - return NULL; - } - - mode = RRModeCreate (modeInfo, name, pScreen); - if (!mode) - { - *error = BadAlloc; - return NULL; - } - *error = Success; - return mode; -} - -RRModePtr * -RRModesForScreen (ScreenPtr pScreen, int *num_ret) -{ - rrScrPriv(pScreen); - int o, c, m; - RRModePtr *screen_modes; - int num_screen_modes = 0; - - screen_modes = xalloc ((num_modes ? num_modes : 1) * sizeof (RRModePtr)); - if (!screen_modes) - return NULL; - - /* - * Add modes from all outputs - */ - for (o = 0; o < pScrPriv->numOutputs; o++) - { - RROutputPtr output = pScrPriv->outputs[o]; - int m, n; - - for (m = 0; m < output->numModes + output->numUserModes; m++) - { - RRModePtr mode = (m < output->numModes ? - output->modes[m] : - output->userModes[m-output->numModes]); - for (n = 0; n < num_screen_modes; n++) - if (screen_modes[n] == mode) - break; - if (n == num_screen_modes) - screen_modes[num_screen_modes++] = mode; - } - } - /* - * Add modes from all crtcs. The goal is to - * make sure all available and active modes - * are visible to the client - */ - for (c = 0; c < pScrPriv->numCrtcs; c++) - { - RRCrtcPtr crtc = pScrPriv->crtcs[c]; - RRModePtr mode = crtc->mode; - int n; - - if (!mode) continue; - for (n = 0; n < num_screen_modes; n++) - if (screen_modes[n] == mode) - break; - if (n == num_screen_modes) - screen_modes[num_screen_modes++] = mode; - } - /* - * Add all user modes for this screen - */ - for (m = 0; m < num_modes; m++) - { - RRModePtr mode = modes[m]; - int n; - - if (mode->userScreen != pScreen) - continue; - for (n = 0; n < num_screen_modes; n++) - if (screen_modes[n] == mode) - break; - if (n == num_screen_modes) - screen_modes[num_screen_modes++] = mode; - } - - *num_ret = num_screen_modes; - return screen_modes; -} - -void -RRModeDestroy (RRModePtr mode) -{ - int m; - - if (--mode->refcnt > 0) - return; - for (m = 0; m < num_modes; m++) - { - if (modes[m] == mode) - { - memmove (modes + m, modes + m + 1, - (num_modes - m - 1) * sizeof (RRModePtr)); - num_modes--; - if (!num_modes) - { - xfree (modes); - modes = NULL; - } - break; - } - } - - xfree (mode); -} - -static int -RRModeDestroyResource (pointer value, XID pid) -{ - RRModeDestroy ((RRModePtr) value); - return 1; -} - -Bool -RRModeInit (void) -{ - assert (num_modes == 0); - assert (modes == NULL); - RRModeType = CreateNewResourceType (RRModeDestroyResource, "MODE"); - if (!RRModeType) - return FALSE; - return TRUE; -} - -int -ProcRRCreateMode (ClientPtr client) -{ - REQUEST(xRRCreateModeReq); - xRRCreateModeReply rep; - WindowPtr pWin; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - xRRModeInfo *modeInfo; - long units_after; - char *name; - int error, rc; - RRModePtr mode; - - REQUEST_AT_LEAST_SIZE (xRRCreateModeReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - pScreen = pWin->drawable.pScreen; - pScrPriv = rrGetScrPriv(pScreen); - - modeInfo = &stuff->modeInfo; - name = (char *) (stuff + 1); - units_after = (stuff->length - bytes_to_int32(sizeof (xRRCreateModeReq))); - - /* check to make sure requested name fits within the data provided */ - if (bytes_to_int32(modeInfo->nameLength) > units_after) - return BadLength; - - mode = RRModeCreateUser (pScreen, modeInfo, name, &error); - if (!mode) - return error; - - rep.type = X_Reply; - rep.pad0 = 0; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.mode = mode->mode.id; - if (client->swapped) - { - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.mode, n); - } - WriteToClient(client, sizeof(xRRCreateModeReply), (char *)&rep); - /* Drop out reference to this mode */ - RRModeDestroy (mode); - return client->noClientException; -} - -int -ProcRRDestroyMode (ClientPtr client) -{ - REQUEST(xRRDestroyModeReq); - RRModePtr mode; - - REQUEST_SIZE_MATCH(xRRDestroyModeReq); - VERIFY_RR_MODE(stuff->mode, mode, DixDestroyAccess); - - if (!mode->userScreen) - return BadMatch; - if (mode->refcnt > 1) - return BadAccess; - FreeResource (stuff->mode, 0); - return Success; -} - -int -ProcRRAddOutputMode (ClientPtr client) -{ - REQUEST(xRRAddOutputModeReq); - RRModePtr mode; - RROutputPtr output; - - REQUEST_SIZE_MATCH(xRRAddOutputModeReq); - VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); - VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); - - return RROutputAddUserMode (output, mode); -} - -int -ProcRRDeleteOutputMode (ClientPtr client) -{ - REQUEST(xRRDeleteOutputModeReq); - RRModePtr mode; - RROutputPtr output; - - REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq); - VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); - VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); - - return RROutputDeleteUserMode (output, mode); -} +/* + * Copyright © 2006 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "randrstr.h" + +RESTYPE RRModeType; + +static Bool +RRModeEqual (xRRModeInfo *a, xRRModeInfo *b) +{ + if (a->width != b->width) return FALSE; + if (a->height != b->height) return FALSE; + if (a->dotClock != b->dotClock) return FALSE; + if (a->hSyncStart != b->hSyncStart) return FALSE; + if (a->hSyncEnd != b->hSyncEnd) return FALSE; + if (a->hTotal != b->hTotal) return FALSE; + if (a->hSkew != b->hSkew) return FALSE; + if (a->vSyncStart != b->vSyncStart) return FALSE; + if (a->vSyncEnd != b->vSyncEnd) return FALSE; + if (a->vTotal != b->vTotal) return FALSE; + if (a->nameLength != b->nameLength) return FALSE; + if (a->modeFlags != b->modeFlags) return FALSE; + return TRUE; +} + +/* + * Keep a list so it's easy to find modes in the resource database. + */ +static int num_modes; +static RRModePtr *modes; + +static RRModePtr +RRModeCreate (xRRModeInfo *modeInfo, + const char *name, + ScreenPtr userScreen) +{ + RRModePtr mode, *newModes; + + if (!RRInit ()) + return NULL; + + mode = malloc(sizeof (RRModeRec) + modeInfo->nameLength + 1); + if (!mode) + return NULL; + mode->refcnt = 1; + mode->mode = *modeInfo; + mode->name = (char *) (mode + 1); + memcpy (mode->name, name, modeInfo->nameLength); + mode->name[modeInfo->nameLength] = '\0'; + mode->userScreen = userScreen; + + if (num_modes) + newModes = realloc(modes, (num_modes + 1) * sizeof (RRModePtr)); + else + newModes = malloc(sizeof (RRModePtr)); + + if (!newModes) + { + free(mode); + return NULL; + } + + mode->mode.id = FakeClientID(0); + if (!AddResource (mode->mode.id, RRModeType, (pointer) mode)) + return NULL; + modes = newModes; + modes[num_modes++] = mode; + + /* + * give the caller a reference to this mode + */ + ++mode->refcnt; + return mode; +} + +static RRModePtr +RRModeFindByName (const char *name, + CARD16 nameLength) +{ + int i; + RRModePtr mode; + + for (i = 0; i < num_modes; i++) + { + mode = modes[i]; + if (mode->mode.nameLength == nameLength && + !memcmp (name, mode->name, nameLength)) + { + return mode; + } + } + return NULL; +} + +RRModePtr +RRModeGet (xRRModeInfo *modeInfo, + const char *name) +{ + int i; + + for (i = 0; i < num_modes; i++) + { + RRModePtr mode = modes[i]; + if (RRModeEqual (&mode->mode, modeInfo) && + !memcmp (name, mode->name, modeInfo->nameLength)) + { + ++mode->refcnt; + return mode; + } + } + + return RRModeCreate (modeInfo, name, NULL); +} + +static RRModePtr +RRModeCreateUser (ScreenPtr pScreen, + xRRModeInfo *modeInfo, + const char *name, + int *error) +{ + RRModePtr mode; + + mode = RRModeFindByName (name, modeInfo->nameLength); + if (mode) + { + *error = BadName; + return NULL; + } + + mode = RRModeCreate (modeInfo, name, pScreen); + if (!mode) + { + *error = BadAlloc; + return NULL; + } + *error = Success; + return mode; +} + +RRModePtr * +RRModesForScreen (ScreenPtr pScreen, int *num_ret) +{ + rrScrPriv(pScreen); + int o, c, m; + RRModePtr *screen_modes; + int num_screen_modes = 0; + + screen_modes = malloc((num_modes ? num_modes : 1) * sizeof (RRModePtr)); + if (!screen_modes) + return NULL; + + /* + * Add modes from all outputs + */ + for (o = 0; o < pScrPriv->numOutputs; o++) + { + RROutputPtr output = pScrPriv->outputs[o]; + int m, n; + + for (m = 0; m < output->numModes + output->numUserModes; m++) + { + RRModePtr mode = (m < output->numModes ? + output->modes[m] : + output->userModes[m-output->numModes]); + for (n = 0; n < num_screen_modes; n++) + if (screen_modes[n] == mode) + break; + if (n == num_screen_modes) + screen_modes[num_screen_modes++] = mode; + } + } + /* + * Add modes from all crtcs. The goal is to + * make sure all available and active modes + * are visible to the client + */ + for (c = 0; c < pScrPriv->numCrtcs; c++) + { + RRCrtcPtr crtc = pScrPriv->crtcs[c]; + RRModePtr mode = crtc->mode; + int n; + + if (!mode) continue; + for (n = 0; n < num_screen_modes; n++) + if (screen_modes[n] == mode) + break; + if (n == num_screen_modes) + screen_modes[num_screen_modes++] = mode; + } + /* + * Add all user modes for this screen + */ + for (m = 0; m < num_modes; m++) + { + RRModePtr mode = modes[m]; + int n; + + if (mode->userScreen != pScreen) + continue; + for (n = 0; n < num_screen_modes; n++) + if (screen_modes[n] == mode) + break; + if (n == num_screen_modes) + screen_modes[num_screen_modes++] = mode; + } + + *num_ret = num_screen_modes; + return screen_modes; +} + +void +RRModeDestroy (RRModePtr mode) +{ + int m; + + if (--mode->refcnt > 0) + return; + for (m = 0; m < num_modes; m++) + { + if (modes[m] == mode) + { + memmove (modes + m, modes + m + 1, + (num_modes - m - 1) * sizeof (RRModePtr)); + num_modes--; + if (!num_modes) + { + free(modes); + modes = NULL; + } + break; + } + } + + free(mode); +} + +static int +RRModeDestroyResource (pointer value, XID pid) +{ + RRModeDestroy ((RRModePtr) value); + return 1; +} + +Bool +RRModeInit (void) +{ + assert (num_modes == 0); + assert (modes == NULL); + RRModeType = CreateNewResourceType (RRModeDestroyResource, "MODE"); + if (!RRModeType) + return FALSE; + return TRUE; +} + +int +ProcRRCreateMode (ClientPtr client) +{ + REQUEST(xRRCreateModeReq); + xRRCreateModeReply rep; + WindowPtr pWin; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + xRRModeInfo *modeInfo; + long units_after; + char *name; + int error, rc; + RRModePtr mode; + + REQUEST_AT_LEAST_SIZE (xRRCreateModeReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + pScrPriv = rrGetScrPriv(pScreen); + + modeInfo = &stuff->modeInfo; + name = (char *) (stuff + 1); + units_after = (stuff->length - bytes_to_int32(sizeof (xRRCreateModeReq))); + + /* check to make sure requested name fits within the data provided */ + if (bytes_to_int32(modeInfo->nameLength) > units_after) + return BadLength; + + mode = RRModeCreateUser (pScreen, modeInfo, name, &error); + if (!mode) + return error; + + rep.type = X_Reply; + rep.pad0 = 0; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.mode = mode->mode.id; + if (client->swapped) + { + int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.mode, n); + } + WriteToClient(client, sizeof(xRRCreateModeReply), (char *)&rep); + /* Drop out reference to this mode */ + RRModeDestroy (mode); + return Success; +} + +int +ProcRRDestroyMode (ClientPtr client) +{ + REQUEST(xRRDestroyModeReq); + RRModePtr mode; + + REQUEST_SIZE_MATCH(xRRDestroyModeReq); + VERIFY_RR_MODE(stuff->mode, mode, DixDestroyAccess); + + if (!mode->userScreen) + return BadMatch; + if (mode->refcnt > 1) + return BadAccess; + FreeResource (stuff->mode, 0); + return Success; +} + +int +ProcRRAddOutputMode (ClientPtr client) +{ + REQUEST(xRRAddOutputModeReq); + RRModePtr mode; + RROutputPtr output; + + REQUEST_SIZE_MATCH(xRRAddOutputModeReq); + VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); + VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); + + return RROutputAddUserMode (output, mode); +} + +int +ProcRRDeleteOutputMode (ClientPtr client) +{ + REQUEST(xRRDeleteOutputModeReq); + RRModePtr mode; + RROutputPtr output; + + REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq); + VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); + VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); + + return RROutputDeleteUserMode (output, mode); +} diff --git a/xorg-server/randr/rroutput.c b/xorg-server/randr/rroutput.c index 3a1b8bbea..a65b45912 100644 --- a/xorg-server/randr/rroutput.c +++ b/xorg-server/randr/rroutput.c @@ -1,621 +1,621 @@ -/* - * Copyright © 2006 Keith Packard - * Copyright © 2008 Red Hat, Inc. - * - * 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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. - */ - -#include "randrstr.h" - -RESTYPE RROutputType; - -/* - * Notify the output of some change - */ -void -RROutputChanged (RROutputPtr output, Bool configChanged) -{ - ScreenPtr pScreen = output->pScreen; - - output->changed = TRUE; - if (pScreen) - { - rrScrPriv (pScreen); - pScrPriv->changed = TRUE; - if (configChanged) - pScrPriv->configChanged = TRUE; - } -} - -/* - * Create an output - */ - -RROutputPtr -RROutputCreate (ScreenPtr pScreen, - const char *name, - int nameLength, - void *devPrivate) -{ - RROutputPtr output; - RROutputPtr *outputs; - rrScrPrivPtr pScrPriv; - - if (!RRInit()) - return NULL; - - pScrPriv = rrGetScrPriv(pScreen); - - if (pScrPriv->numOutputs) - outputs = xrealloc (pScrPriv->outputs, - (pScrPriv->numOutputs + 1) * sizeof (RROutputPtr)); - else - outputs = xalloc (sizeof (RROutputPtr)); - if (!outputs) - return FALSE; - - pScrPriv->outputs = outputs; - - output = xalloc (sizeof (RROutputRec) + nameLength + 1); - if (!output) - return NULL; - output->id = FakeClientID (0); - output->pScreen = pScreen; - output->name = (char *) (output + 1); - output->nameLength = nameLength; - memcpy (output->name, name, nameLength); - output->name[nameLength] = '\0'; - output->connection = RR_UnknownConnection; - output->subpixelOrder = SubPixelUnknown; - output->mmWidth = 0; - output->mmHeight = 0; - output->crtc = NULL; - output->numCrtcs = 0; - output->crtcs = NULL; - output->numClones = 0; - output->clones = NULL; - output->numModes = 0; - output->numPreferred = 0; - output->modes = NULL; - output->numUserModes = 0; - output->userModes = NULL; - output->properties = NULL; - output->pendingProperties = FALSE; - output->changed = FALSE; - output->devPrivate = devPrivate; - - if (!AddResource (output->id, RROutputType, (pointer) output)) - return NULL; - - pScrPriv->outputs[pScrPriv->numOutputs++] = output; - return output; -} - -/* - * Notify extension that output parameters have been changed - */ -Bool -RROutputSetClones (RROutputPtr output, - RROutputPtr *clones, - int numClones) -{ - RROutputPtr *newClones; - int i; - - if (numClones == output->numClones) - { - for (i = 0; i < numClones; i++) - if (output->clones[i] != clones[i]) - break; - if (i == numClones) - return TRUE; - } - if (numClones) - { - newClones = xalloc (numClones * sizeof (RROutputPtr)); - if (!newClones) - return FALSE; - } - else - newClones = NULL; - if (output->clones) - xfree (output->clones); - memcpy (newClones, clones, numClones * sizeof (RROutputPtr)); - output->clones = newClones; - output->numClones = numClones; - RROutputChanged (output, TRUE); - return TRUE; -} - -Bool -RROutputSetModes (RROutputPtr output, - RRModePtr *modes, - int numModes, - int numPreferred) -{ - RRModePtr *newModes; - int i; - - if (numModes == output->numModes && numPreferred == output->numPreferred) - { - for (i = 0; i < numModes; i++) - if (output->modes[i] != modes[i]) - break; - if (i == numModes) - { - for (i = 0; i < numModes; i++) - RRModeDestroy (modes[i]); - return TRUE; - } - } - - if (numModes) - { - newModes = xalloc (numModes * sizeof (RRModePtr)); - if (!newModes) - return FALSE; - } - else - newModes = NULL; - if (output->modes) - { - for (i = 0; i < output->numModes; i++) - RRModeDestroy (output->modes[i]); - xfree (output->modes); - } - memcpy (newModes, modes, numModes * sizeof (RRModePtr)); - output->modes = newModes; - output->numModes = numModes; - output->numPreferred = numPreferred; - RROutputChanged (output, TRUE); - return TRUE; -} - -int -RROutputAddUserMode (RROutputPtr output, - RRModePtr mode) -{ - int m; - ScreenPtr pScreen = output->pScreen; - rrScrPriv(pScreen); - RRModePtr *newModes; - - /* Check to see if this mode is already listed for this output */ - for (m = 0; m < output->numModes + output->numUserModes; m++) - { - RRModePtr e = (m < output->numModes ? - output->modes[m] : - output->userModes[m - output->numModes]); - if (mode == e) - return Success; - } - - /* Check with the DDX to see if this mode is OK */ - if (pScrPriv->rrOutputValidateMode) - if (!pScrPriv->rrOutputValidateMode (pScreen, output, mode)) - return BadMatch; - - if (output->userModes) - newModes = xrealloc (output->userModes, - (output->numUserModes + 1) * sizeof (RRModePtr)); - else - newModes = xalloc (sizeof (RRModePtr)); - if (!newModes) - return BadAlloc; - - output->userModes = newModes; - output->userModes[output->numUserModes++] = mode; - ++mode->refcnt; - RROutputChanged (output, TRUE); - RRTellChanged (pScreen); - return Success; -} - -int -RROutputDeleteUserMode (RROutputPtr output, - RRModePtr mode) -{ - int m; - - /* Find this mode in the user mode list */ - for (m = 0; m < output->numUserModes; m++) - { - RRModePtr e = output->userModes[m]; - - if (mode == e) - break; - } - /* Not there, access error */ - if (m == output->numUserModes) - return BadAccess; - - /* make sure the mode isn't active for this output */ - if (output->crtc && output->crtc->mode == mode) - return BadMatch; - - memmove (output->userModes + m, output->userModes + m + 1, - (output->numUserModes - m - 1) * sizeof (RRModePtr)); - output->numUserModes--; - RRModeDestroy (mode); - return Success; -} - -Bool -RROutputSetCrtcs (RROutputPtr output, - RRCrtcPtr *crtcs, - int numCrtcs) -{ - RRCrtcPtr *newCrtcs; - int i; - - if (numCrtcs == output->numCrtcs) - { - for (i = 0; i < numCrtcs; i++) - if (output->crtcs[i] != crtcs[i]) - break; - if (i == numCrtcs) - return TRUE; - } - if (numCrtcs) - { - newCrtcs = xalloc (numCrtcs * sizeof (RRCrtcPtr)); - if (!newCrtcs) - return FALSE; - } - else - newCrtcs = NULL; - if (output->crtcs) - xfree (output->crtcs); - memcpy (newCrtcs, crtcs, numCrtcs * sizeof (RRCrtcPtr)); - output->crtcs = newCrtcs; - output->numCrtcs = numCrtcs; - RROutputChanged (output, TRUE); - return TRUE; -} - -Bool -RROutputSetConnection (RROutputPtr output, - CARD8 connection) -{ - if (output->connection == connection) - return TRUE; - output->connection = connection; - RROutputChanged (output, TRUE); - return TRUE; -} - -Bool -RROutputSetSubpixelOrder (RROutputPtr output, - int subpixelOrder) -{ - if (output->subpixelOrder == subpixelOrder) - return TRUE; - - output->subpixelOrder = subpixelOrder; - RROutputChanged (output, FALSE); - return TRUE; -} - -Bool -RROutputSetPhysicalSize (RROutputPtr output, - int mmWidth, - int mmHeight) -{ - if (output->mmWidth == mmWidth && output->mmHeight == mmHeight) - return TRUE; - output->mmWidth = mmWidth; - output->mmHeight = mmHeight; - RROutputChanged (output, FALSE); - return TRUE; -} - - -void -RRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - rrScrPriv (pScreen); - xRROutputChangeNotifyEvent oe; - RRCrtcPtr crtc = output->crtc; - RRModePtr mode = crtc ? crtc->mode : 0; - - oe.type = RRNotify + RREventBase; - oe.subCode = RRNotify_OutputChange; - oe.sequenceNumber = client->sequence; - oe.timestamp = pScrPriv->lastSetTime.milliseconds; - oe.configTimestamp = pScrPriv->lastConfigTime.milliseconds; - oe.window = pWin->drawable.id; - oe.output = output->id; - if (crtc) - { - oe.crtc = crtc->id; - oe.mode = mode ? mode->mode.id : None; - oe.rotation = crtc->rotation; - } - else - { - oe.crtc = None; - oe.mode = None; - oe.rotation = RR_Rotate_0; - } - oe.connection = output->connection; - oe.subpixelOrder = output->subpixelOrder; - WriteEventsToClient (client, 1, (xEvent *) &oe); -} - -/* - * Destroy a Output at shutdown - */ -void -RROutputDestroy (RROutputPtr output) -{ - FreeResource (output->id, 0); -} - -static int -RROutputDestroyResource (pointer value, XID pid) -{ - RROutputPtr output = (RROutputPtr) value; - ScreenPtr pScreen = output->pScreen; - int m; - - if (pScreen) - { - rrScrPriv(pScreen); - int i; - - if (pScrPriv->primaryOutput == output) - pScrPriv->primaryOutput = NULL; - - for (i = 0; i < pScrPriv->numOutputs; i++) - { - if (pScrPriv->outputs[i] == output) - { - memmove (pScrPriv->outputs + i, pScrPriv->outputs + i + 1, - (pScrPriv->numOutputs - (i + 1)) * sizeof (RROutputPtr)); - --pScrPriv->numOutputs; - break; - } - } - } - if (output->modes) - { - for (m = 0; m < output->numModes; m++) - RRModeDestroy (output->modes[m]); - xfree (output->modes); - } - - for (m = 0; m < output->numUserModes; m++) - RRModeDestroy (output->userModes[m]); - if (output->userModes) - xfree (output->userModes); - - if (output->crtcs) - xfree (output->crtcs); - if (output->clones) - xfree (output->clones); - RRDeleteAllOutputProperties (output); - xfree (output); - return 1; -} - -/* - * Initialize output type - */ -Bool -RROutputInit (void) -{ - RROutputType = CreateNewResourceType (RROutputDestroyResource, "OUTPUT"); - if (!RROutputType) - return FALSE; - return TRUE; -} - -#define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32) - -int -ProcRRGetOutputInfo (ClientPtr client) -{ - REQUEST(xRRGetOutputInfoReq); - xRRGetOutputInfoReply rep; - RROutputPtr output; - CARD8 *extra; - unsigned long extraLen; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - RRCrtc *crtcs; - RRMode *modes; - RROutput *clones; - char *name; - int i, n; - - REQUEST_SIZE_MATCH(xRRGetOutputInfoReq); - VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); - - pScreen = output->pScreen; - pScrPriv = rrGetScrPriv(pScreen); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = bytes_to_int32(OutputInfoExtra); - rep.timestamp = pScrPriv->lastSetTime.milliseconds; - rep.crtc = output->crtc ? output->crtc->id : None; - rep.mmWidth = output->mmWidth; - rep.mmHeight = output->mmHeight; - rep.connection = output->connection; - rep.subpixelOrder = output->subpixelOrder; - rep.nCrtcs = output->numCrtcs; - rep.nModes = output->numModes + output->numUserModes; - rep.nPreferred = output->numPreferred; - rep.nClones = output->numClones; - rep.nameLength = output->nameLength; - - extraLen = ((output->numCrtcs + - output->numModes + output->numUserModes + - output->numClones + - bytes_to_int32(rep.nameLength)) << 2); - - if (extraLen) - { - rep.length += bytes_to_int32(extraLen); - extra = xalloc (extraLen); - if (!extra) - return BadAlloc; - } - else - extra = NULL; - - crtcs = (RRCrtc *) extra; - modes = (RRMode *) (crtcs + output->numCrtcs); - clones = (RROutput *) (modes + output->numModes + output->numUserModes); - name = (char *) (clones + output->numClones); - - for (i = 0; i < output->numCrtcs; i++) - { - crtcs[i] = output->crtcs[i]->id; - if (client->swapped) - swapl (&crtcs[i], n); - } - for (i = 0; i < output->numModes + output->numUserModes; i++) - { - if (i < output->numModes) - modes[i] = output->modes[i]->mode.id; - else - modes[i] = output->userModes[i - output->numModes]->mode.id; - if (client->swapped) - swapl (&modes[i], n); - } - for (i = 0; i < output->numClones; i++) - { - clones[i] = output->clones[i]->id; - if (client->swapped) - swapl (&clones[i], n); - } - memcpy (name, output->name, output->nameLength); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.timestamp, n); - swapl(&rep.crtc, n); - swapl(&rep.mmWidth, n); - swapl(&rep.mmHeight, n); - swaps(&rep.nCrtcs, n); - swaps(&rep.nModes, n); - swaps(&rep.nClones, n); - swaps(&rep.nameLength, n); - } - WriteToClient(client, sizeof(xRRGetOutputInfoReply), (char *)&rep); - if (extraLen) - { - WriteToClient (client, extraLen, (char *) extra); - xfree (extra); - } - - return client->noClientException; -} - -static void -RRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv, - RROutputPtr output) -{ - if (pScrPriv->primaryOutput == output) - return; - - /* clear the old primary */ - if (pScrPriv->primaryOutput) { - RROutputChanged(pScrPriv->primaryOutput, 0); - pScrPriv->primaryOutput = NULL; - } - - /* set the new primary */ - if (output) { - pScrPriv->primaryOutput = output; - RROutputChanged(output, 0); - } - - pScrPriv->layoutChanged = TRUE; - - RRTellChanged(pScreen); -} - -int -ProcRRSetOutputPrimary(ClientPtr client) -{ - REQUEST(xRRSetOutputPrimaryReq); - RROutputPtr output = NULL; - WindowPtr pWin; - rrScrPrivPtr pScrPriv; - int rc; - - REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq); - - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - if (stuff->output) { - VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); - - if (output->pScreen != pWin->drawable.pScreen) { - client->errorValue = stuff->window; - return BadMatch; - } - } - - pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); - RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output); - - return client->noClientException; -} - -int -ProcRRGetOutputPrimary(ClientPtr client) -{ - REQUEST(xRRGetOutputPrimaryReq); - WindowPtr pWin; - rrScrPrivPtr pScrPriv; - xRRGetOutputPrimaryReply rep; - RROutputPtr primary = NULL; - int rc; - - REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq); - - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); - if (pScrPriv) - primary = pScrPriv->primaryOutput; - - memset(&rep, 0, sizeof(rep)); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.output = primary ? primary->id : None; - - if (client->swapped) { - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.output, n); - } - - WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep); - - return client->noClientException; -} +/* + * Copyright © 2006 Keith Packard + * Copyright © 2008 Red Hat, Inc. + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "randrstr.h" + +RESTYPE RROutputType; + +/* + * Notify the output of some change + */ +void +RROutputChanged (RROutputPtr output, Bool configChanged) +{ + ScreenPtr pScreen = output->pScreen; + + output->changed = TRUE; + if (pScreen) + { + rrScrPriv (pScreen); + pScrPriv->changed = TRUE; + if (configChanged) + pScrPriv->configChanged = TRUE; + } +} + +/* + * Create an output + */ + +RROutputPtr +RROutputCreate (ScreenPtr pScreen, + const char *name, + int nameLength, + void *devPrivate) +{ + RROutputPtr output; + RROutputPtr *outputs; + rrScrPrivPtr pScrPriv; + + if (!RRInit()) + return NULL; + + pScrPriv = rrGetScrPriv(pScreen); + + if (pScrPriv->numOutputs) + outputs = realloc(pScrPriv->outputs, + (pScrPriv->numOutputs + 1) * sizeof (RROutputPtr)); + else + outputs = malloc(sizeof (RROutputPtr)); + if (!outputs) + return FALSE; + + pScrPriv->outputs = outputs; + + output = malloc(sizeof (RROutputRec) + nameLength + 1); + if (!output) + return NULL; + output->id = FakeClientID (0); + output->pScreen = pScreen; + output->name = (char *) (output + 1); + output->nameLength = nameLength; + memcpy (output->name, name, nameLength); + output->name[nameLength] = '\0'; + output->connection = RR_UnknownConnection; + output->subpixelOrder = SubPixelUnknown; + output->mmWidth = 0; + output->mmHeight = 0; + output->crtc = NULL; + output->numCrtcs = 0; + output->crtcs = NULL; + output->numClones = 0; + output->clones = NULL; + output->numModes = 0; + output->numPreferred = 0; + output->modes = NULL; + output->numUserModes = 0; + output->userModes = NULL; + output->properties = NULL; + output->pendingProperties = FALSE; + output->changed = FALSE; + output->devPrivate = devPrivate; + + if (!AddResource (output->id, RROutputType, (pointer) output)) + return NULL; + + pScrPriv->outputs[pScrPriv->numOutputs++] = output; + return output; +} + +/* + * Notify extension that output parameters have been changed + */ +Bool +RROutputSetClones (RROutputPtr output, + RROutputPtr *clones, + int numClones) +{ + RROutputPtr *newClones; + int i; + + if (numClones == output->numClones) + { + for (i = 0; i < numClones; i++) + if (output->clones[i] != clones[i]) + break; + if (i == numClones) + return TRUE; + } + if (numClones) + { + newClones = malloc(numClones * sizeof (RROutputPtr)); + if (!newClones) + return FALSE; + } + else + newClones = NULL; + if (output->clones) + free(output->clones); + memcpy (newClones, clones, numClones * sizeof (RROutputPtr)); + output->clones = newClones; + output->numClones = numClones; + RROutputChanged (output, TRUE); + return TRUE; +} + +Bool +RROutputSetModes (RROutputPtr output, + RRModePtr *modes, + int numModes, + int numPreferred) +{ + RRModePtr *newModes; + int i; + + if (numModes == output->numModes && numPreferred == output->numPreferred) + { + for (i = 0; i < numModes; i++) + if (output->modes[i] != modes[i]) + break; + if (i == numModes) + { + for (i = 0; i < numModes; i++) + RRModeDestroy (modes[i]); + return TRUE; + } + } + + if (numModes) + { + newModes = malloc(numModes * sizeof (RRModePtr)); + if (!newModes) + return FALSE; + } + else + newModes = NULL; + if (output->modes) + { + for (i = 0; i < output->numModes; i++) + RRModeDestroy (output->modes[i]); + free(output->modes); + } + memcpy (newModes, modes, numModes * sizeof (RRModePtr)); + output->modes = newModes; + output->numModes = numModes; + output->numPreferred = numPreferred; + RROutputChanged (output, TRUE); + return TRUE; +} + +int +RROutputAddUserMode (RROutputPtr output, + RRModePtr mode) +{ + int m; + ScreenPtr pScreen = output->pScreen; + rrScrPriv(pScreen); + RRModePtr *newModes; + + /* Check to see if this mode is already listed for this output */ + for (m = 0; m < output->numModes + output->numUserModes; m++) + { + RRModePtr e = (m < output->numModes ? + output->modes[m] : + output->userModes[m - output->numModes]); + if (mode == e) + return Success; + } + + /* Check with the DDX to see if this mode is OK */ + if (pScrPriv->rrOutputValidateMode) + if (!pScrPriv->rrOutputValidateMode (pScreen, output, mode)) + return BadMatch; + + if (output->userModes) + newModes = realloc(output->userModes, + (output->numUserModes + 1) * sizeof (RRModePtr)); + else + newModes = malloc(sizeof (RRModePtr)); + if (!newModes) + return BadAlloc; + + output->userModes = newModes; + output->userModes[output->numUserModes++] = mode; + ++mode->refcnt; + RROutputChanged (output, TRUE); + RRTellChanged (pScreen); + return Success; +} + +int +RROutputDeleteUserMode (RROutputPtr output, + RRModePtr mode) +{ + int m; + + /* Find this mode in the user mode list */ + for (m = 0; m < output->numUserModes; m++) + { + RRModePtr e = output->userModes[m]; + + if (mode == e) + break; + } + /* Not there, access error */ + if (m == output->numUserModes) + return BadAccess; + + /* make sure the mode isn't active for this output */ + if (output->crtc && output->crtc->mode == mode) + return BadMatch; + + memmove (output->userModes + m, output->userModes + m + 1, + (output->numUserModes - m - 1) * sizeof (RRModePtr)); + output->numUserModes--; + RRModeDestroy (mode); + return Success; +} + +Bool +RROutputSetCrtcs (RROutputPtr output, + RRCrtcPtr *crtcs, + int numCrtcs) +{ + RRCrtcPtr *newCrtcs; + int i; + + if (numCrtcs == output->numCrtcs) + { + for (i = 0; i < numCrtcs; i++) + if (output->crtcs[i] != crtcs[i]) + break; + if (i == numCrtcs) + return TRUE; + } + if (numCrtcs) + { + newCrtcs = malloc(numCrtcs * sizeof (RRCrtcPtr)); + if (!newCrtcs) + return FALSE; + } + else + newCrtcs = NULL; + if (output->crtcs) + free(output->crtcs); + memcpy (newCrtcs, crtcs, numCrtcs * sizeof (RRCrtcPtr)); + output->crtcs = newCrtcs; + output->numCrtcs = numCrtcs; + RROutputChanged (output, TRUE); + return TRUE; +} + +Bool +RROutputSetConnection (RROutputPtr output, + CARD8 connection) +{ + if (output->connection == connection) + return TRUE; + output->connection = connection; + RROutputChanged (output, TRUE); + return TRUE; +} + +Bool +RROutputSetSubpixelOrder (RROutputPtr output, + int subpixelOrder) +{ + if (output->subpixelOrder == subpixelOrder) + return TRUE; + + output->subpixelOrder = subpixelOrder; + RROutputChanged (output, FALSE); + return TRUE; +} + +Bool +RROutputSetPhysicalSize (RROutputPtr output, + int mmWidth, + int mmHeight) +{ + if (output->mmWidth == mmWidth && output->mmHeight == mmHeight) + return TRUE; + output->mmWidth = mmWidth; + output->mmHeight = mmHeight; + RROutputChanged (output, FALSE); + return TRUE; +} + + +void +RRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + rrScrPriv (pScreen); + xRROutputChangeNotifyEvent oe; + RRCrtcPtr crtc = output->crtc; + RRModePtr mode = crtc ? crtc->mode : 0; + + oe.type = RRNotify + RREventBase; + oe.subCode = RRNotify_OutputChange; + oe.sequenceNumber = client->sequence; + oe.timestamp = pScrPriv->lastSetTime.milliseconds; + oe.configTimestamp = pScrPriv->lastConfigTime.milliseconds; + oe.window = pWin->drawable.id; + oe.output = output->id; + if (crtc) + { + oe.crtc = crtc->id; + oe.mode = mode ? mode->mode.id : None; + oe.rotation = crtc->rotation; + } + else + { + oe.crtc = None; + oe.mode = None; + oe.rotation = RR_Rotate_0; + } + oe.connection = output->connection; + oe.subpixelOrder = output->subpixelOrder; + WriteEventsToClient (client, 1, (xEvent *) &oe); +} + +/* + * Destroy a Output at shutdown + */ +void +RROutputDestroy (RROutputPtr output) +{ + FreeResource (output->id, 0); +} + +static int +RROutputDestroyResource (pointer value, XID pid) +{ + RROutputPtr output = (RROutputPtr) value; + ScreenPtr pScreen = output->pScreen; + int m; + + if (pScreen) + { + rrScrPriv(pScreen); + int i; + + if (pScrPriv->primaryOutput == output) + pScrPriv->primaryOutput = NULL; + + for (i = 0; i < pScrPriv->numOutputs; i++) + { + if (pScrPriv->outputs[i] == output) + { + memmove (pScrPriv->outputs + i, pScrPriv->outputs + i + 1, + (pScrPriv->numOutputs - (i + 1)) * sizeof (RROutputPtr)); + --pScrPriv->numOutputs; + break; + } + } + } + if (output->modes) + { + for (m = 0; m < output->numModes; m++) + RRModeDestroy (output->modes[m]); + free(output->modes); + } + + for (m = 0; m < output->numUserModes; m++) + RRModeDestroy (output->userModes[m]); + if (output->userModes) + free(output->userModes); + + if (output->crtcs) + free(output->crtcs); + if (output->clones) + free(output->clones); + RRDeleteAllOutputProperties (output); + free(output); + return 1; +} + +/* + * Initialize output type + */ +Bool +RROutputInit (void) +{ + RROutputType = CreateNewResourceType (RROutputDestroyResource, "OUTPUT"); + if (!RROutputType) + return FALSE; + return TRUE; +} + +#define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32) + +int +ProcRRGetOutputInfo (ClientPtr client) +{ + REQUEST(xRRGetOutputInfoReq); + xRRGetOutputInfoReply rep; + RROutputPtr output; + CARD8 *extra; + unsigned long extraLen; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + RRCrtc *crtcs; + RRMode *modes; + RROutput *clones; + char *name; + int i, n; + + REQUEST_SIZE_MATCH(xRRGetOutputInfoReq); + VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); + + pScreen = output->pScreen; + pScrPriv = rrGetScrPriv(pScreen); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = bytes_to_int32(OutputInfoExtra); + rep.timestamp = pScrPriv->lastSetTime.milliseconds; + rep.crtc = output->crtc ? output->crtc->id : None; + rep.mmWidth = output->mmWidth; + rep.mmHeight = output->mmHeight; + rep.connection = output->connection; + rep.subpixelOrder = output->subpixelOrder; + rep.nCrtcs = output->numCrtcs; + rep.nModes = output->numModes + output->numUserModes; + rep.nPreferred = output->numPreferred; + rep.nClones = output->numClones; + rep.nameLength = output->nameLength; + + extraLen = ((output->numCrtcs + + output->numModes + output->numUserModes + + output->numClones + + bytes_to_int32(rep.nameLength)) << 2); + + if (extraLen) + { + rep.length += bytes_to_int32(extraLen); + extra = malloc(extraLen); + if (!extra) + return BadAlloc; + } + else + extra = NULL; + + crtcs = (RRCrtc *) extra; + modes = (RRMode *) (crtcs + output->numCrtcs); + clones = (RROutput *) (modes + output->numModes + output->numUserModes); + name = (char *) (clones + output->numClones); + + for (i = 0; i < output->numCrtcs; i++) + { + crtcs[i] = output->crtcs[i]->id; + if (client->swapped) + swapl (&crtcs[i], n); + } + for (i = 0; i < output->numModes + output->numUserModes; i++) + { + if (i < output->numModes) + modes[i] = output->modes[i]->mode.id; + else + modes[i] = output->userModes[i - output->numModes]->mode.id; + if (client->swapped) + swapl (&modes[i], n); + } + for (i = 0; i < output->numClones; i++) + { + clones[i] = output->clones[i]->id; + if (client->swapped) + swapl (&clones[i], n); + } + memcpy (name, output->name, output->nameLength); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.timestamp, n); + swapl(&rep.crtc, n); + swapl(&rep.mmWidth, n); + swapl(&rep.mmHeight, n); + swaps(&rep.nCrtcs, n); + swaps(&rep.nModes, n); + swaps(&rep.nClones, n); + swaps(&rep.nameLength, n); + } + WriteToClient(client, sizeof(xRRGetOutputInfoReply), (char *)&rep); + if (extraLen) + { + WriteToClient (client, extraLen, (char *) extra); + free(extra); + } + + return Success; +} + +static void +RRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv, + RROutputPtr output) +{ + if (pScrPriv->primaryOutput == output) + return; + + /* clear the old primary */ + if (pScrPriv->primaryOutput) { + RROutputChanged(pScrPriv->primaryOutput, 0); + pScrPriv->primaryOutput = NULL; + } + + /* set the new primary */ + if (output) { + pScrPriv->primaryOutput = output; + RROutputChanged(output, 0); + } + + pScrPriv->layoutChanged = TRUE; + + RRTellChanged(pScreen); +} + +int +ProcRRSetOutputPrimary(ClientPtr client) +{ + REQUEST(xRRSetOutputPrimaryReq); + RROutputPtr output = NULL; + WindowPtr pWin; + rrScrPrivPtr pScrPriv; + int rc; + + REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq); + + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + if (stuff->output) { + VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); + + if (output->pScreen != pWin->drawable.pScreen) { + client->errorValue = stuff->window; + return BadMatch; + } + } + + pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); + RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output); + + return Success; +} + +int +ProcRRGetOutputPrimary(ClientPtr client) +{ + REQUEST(xRRGetOutputPrimaryReq); + WindowPtr pWin; + rrScrPrivPtr pScrPriv; + xRRGetOutputPrimaryReply rep; + RROutputPtr primary = NULL; + int rc; + + REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq); + + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); + if (pScrPriv) + primary = pScrPriv->primaryOutput; + + memset(&rep, 0, sizeof(rep)); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.output = primary ? primary->id : None; + + if (client->swapped) { + int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.output, n); + } + + WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep); + + return Success; +} diff --git a/xorg-server/randr/rrproperty.c b/xorg-server/randr/rrproperty.c index 96e27a9dc..20f07f42a 100644 --- a/xorg-server/randr/rrproperty.c +++ b/xorg-server/randr/rrproperty.c @@ -76,10 +76,10 @@ RRDeleteAllOutputProperties (RROutputPtr output) event.timestamp = currentTime.milliseconds; RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event); if (prop->current.data) - xfree(prop->current.data); + free(prop->current.data); if (prop->pending.data) - xfree(prop->pending.data); - xfree(prop); + free(prop->pending.data); + free(prop); } } @@ -97,7 +97,7 @@ RRCreateOutputProperty (Atom property) { RRPropertyPtr prop; - prop = (RRPropertyPtr)xalloc(sizeof(RRPropertyRec)); + prop = (RRPropertyPtr)malloc(sizeof(RRPropertyRec)); if (!prop) return NULL; prop->next = NULL; @@ -116,14 +116,14 @@ static void RRDestroyOutputProperty (RRPropertyPtr prop) { if (prop->valid_values) - xfree (prop->valid_values); + free(prop->valid_values); if (prop->current.data) - xfree(prop->current.data); + free(prop->current.data); if (prop->pending.data) - xfree(prop->pending.data); + free(prop->pending.data); if (prop->valid_values) - xfree(prop->valid_values); - xfree(prop); + free(prop->valid_values); + free(prop); } void @@ -201,7 +201,7 @@ RRChangeOutputProperty (RROutputPtr output, Atom property, Atom type, pointer new_data = NULL, old_data = NULL; total_size = total_len * size_in_bytes; - new_value.data = (pointer)xalloc (total_size); + new_value.data = (pointer)malloc(total_size); if (!new_value.data && total_size) { if (add) @@ -239,11 +239,11 @@ RRChangeOutputProperty (RROutputPtr output, Atom property, Atom type, prop->propertyName, &new_value)) { if (new_value.data) - xfree (new_value.data); + free(new_value.data); return (BadValue); } if (prop_value->data) - xfree (prop_value->data); + free(prop_value->data); *prop_value = new_value; } @@ -372,7 +372,7 @@ RRConfigureOutputProperty (RROutputPtr output, Atom property, if (range && (num_values & 1)) return BadMatch; - new_values = xalloc (num_values * sizeof (INT32)); + new_values = malloc(num_values * sizeof (INT32)); if (!new_values && num_values) return BadAlloc; if (num_values) @@ -385,7 +385,7 @@ RRConfigureOutputProperty (RROutputPtr output, Atom property, if (prop->is_pending && !pending) { if (prop->pending.data) - xfree (prop->pending.data); + free(prop->pending.data); RRInitOutputPropertyValue (&prop->pending); } @@ -394,7 +394,7 @@ RRConfigureOutputProperty (RROutputPtr output, Atom property, prop->immutable = immutable; prop->num_valid = num_values; if (prop->valid_values) - xfree (prop->valid_values); + free(prop->valid_values); prop->valid_values = new_values; if (add) { @@ -422,7 +422,7 @@ ProcRRListOutputProperties (ClientPtr client) for (prop = output->properties; prop; prop = prop->next) numProps++; if (numProps) - if(!(pAtoms = (Atom *)xalloc(numProps * sizeof(Atom)))) + if(!(pAtoms = (Atom *)malloc(numProps * sizeof(Atom)))) return(BadAlloc); rep.type = X_Reply; @@ -445,9 +445,9 @@ ProcRRListOutputProperties (ClientPtr client) { client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); - xfree(pAtoms); + free(pAtoms); } - return(client->noClientException); + return Success; } int @@ -468,7 +468,7 @@ ProcRRQueryOutputProperty (ClientPtr client) return BadName; if (prop->num_valid) { - extra = xalloc(prop->num_valid * sizeof(INT32)); + extra = malloc(prop->num_valid * sizeof(INT32)); if (!extra) return BadAlloc; } @@ -491,9 +491,9 @@ ProcRRQueryOutputProperty (ClientPtr client) client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32), extra); - xfree(extra); + free(extra); } - return(client->noClientException); + return Success; } int @@ -566,7 +566,7 @@ ProcRRChangeOutputProperty (ClientPtr client) if (err != Success) return err; else - return client->noClientException; + return Success; } int @@ -587,7 +587,7 @@ ProcRRDeleteOutputProperty (ClientPtr client) RRDeleteOutputProperty(output, stuff->property); - return client->noClientException; + return Success; } int @@ -646,7 +646,7 @@ ProcRRGetOutputProperty (ClientPtr client) swapl(&reply.nItems, n); } WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply); - return(client->noClientException); + return Success; } if (prop->immutable && stuff->delete) @@ -678,7 +678,7 @@ ProcRRGetOutputProperty (ClientPtr client) swapl(&reply.nItems, n); } WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply); - return(client->noClientException); + return Success; } /* @@ -699,7 +699,7 @@ ProcRRGetOutputProperty (ClientPtr client) len = min(n - ind, 4 * stuff->longLength); if (len) { - extra = xalloc(len); + extra = malloc(len); if (!extra) return BadAlloc; } @@ -745,7 +745,7 @@ ProcRRGetOutputProperty (ClientPtr client) } WriteSwappedDataToClient(client, len, extra); - xfree(extra); + free(extra); } if (stuff->delete && (reply.bytesAfter == 0)) @@ -753,6 +753,6 @@ ProcRRGetOutputProperty (ClientPtr client) *prev = prop->next; RRDestroyOutputProperty (prop); } - return(client->noClientException); + return Success; } diff --git a/xorg-server/randr/rrscreen.c b/xorg-server/randr/rrscreen.c index 26de1e2e2..526e95177 100644 --- a/xorg-server/randr/rrscreen.c +++ b/xorg-server/randr/rrscreen.c @@ -1,1004 +1,1004 @@ -/* - * Copyright © 2006 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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. - */ - -#include "randrstr.h" - -static const int padlength[4] = {0, 3, 2, 1}; - -static CARD16 -RR10CurrentSizeID (ScreenPtr pScreen); - -/* - * Edit connection information block so that new clients - * see the current screen size on connect - */ -static void -RREditConnectionInfo (ScreenPtr pScreen) -{ - xConnSetup *connSetup; - char *vendor; - xPixmapFormat *formats; - xWindowRoot *root; - xDepth *depth; - xVisualType *visual; - int screen = 0; - int d; - - connSetup = (xConnSetup *) ConnectionInfo; - vendor = (char *) connSetup + sizeof (xConnSetup); - formats = (xPixmapFormat *) ((char *) vendor + - connSetup->nbytesVendor + - padlength[connSetup->nbytesVendor & 3]); - root = (xWindowRoot *) ((char *) formats + - sizeof (xPixmapFormat) * screenInfo.numPixmapFormats); - while (screen != pScreen->myNum) - { - depth = (xDepth *) ((char *) root + - sizeof (xWindowRoot)); - for (d = 0; d < root->nDepths; d++) - { - visual = (xVisualType *) ((char *) depth + - sizeof (xDepth)); - depth = (xDepth *) ((char *) visual + - depth->nVisuals * sizeof (xVisualType)); - } - root = (xWindowRoot *) ((char *) depth); - screen++; - } - root->pixWidth = pScreen->width; - root->pixHeight = pScreen->height; - root->mmWidth = pScreen->mmWidth; - root->mmHeight = pScreen->mmHeight; -} - -void -RRSendConfigNotify (ScreenPtr pScreen) -{ - WindowPtr pWin = WindowTable[pScreen->myNum]; - xEvent event; - - event.u.u.type = ConfigureNotify; - event.u.configureNotify.window = pWin->drawable.id; - event.u.configureNotify.aboveSibling = None; - event.u.configureNotify.x = 0; - event.u.configureNotify.y = 0; - - /* XXX xinerama stuff ? */ - - event.u.configureNotify.width = pWin->drawable.width; - event.u.configureNotify.height = pWin->drawable.height; - event.u.configureNotify.borderWidth = wBorderWidth (pWin); - event.u.configureNotify.override = pWin->overrideRedirect; - DeliverEvents(pWin, &event, 1, NullWindow); -} - -void -RRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen) -{ - rrScrPriv (pScreen); - xRRScreenChangeNotifyEvent se; - RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL; - WindowPtr pRoot = WindowTable[pScreen->myNum]; - - se.type = RRScreenChangeNotify + RREventBase; - se.rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0); - se.timestamp = pScrPriv->lastSetTime.milliseconds; - se.sequenceNumber = client->sequence; - se.configTimestamp = pScrPriv->lastConfigTime.milliseconds; - se.root = pRoot->drawable.id; - se.window = pWin->drawable.id; - se.subpixelOrder = PictureGetSubpixelOrder (pScreen); - - se.sequenceNumber = client->sequence; - se.sizeID = RR10CurrentSizeID (pScreen); - - if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) { - se.widthInPixels = pScreen->height; - se.heightInPixels = pScreen->width; - se.widthInMillimeters = pScreen->mmHeight; - se.heightInMillimeters = pScreen->mmWidth; - } else { - se.widthInPixels = pScreen->width; - se.heightInPixels = pScreen->height; - se.widthInMillimeters = pScreen->mmWidth; - se.heightInMillimeters = pScreen->mmHeight; - } - - WriteEventsToClient (client, 1, (xEvent *) &se); -} - -/* - * Notify the extension that the screen size has been changed. - * The driver is responsible for calling this whenever it has changed - * the size of the screen - */ -void -RRScreenSizeNotify (ScreenPtr pScreen) -{ - rrScrPriv(pScreen); - /* - * Deliver ConfigureNotify events when root changes - * pixel size - */ - if (pScrPriv->width == pScreen->width && - pScrPriv->height == pScreen->height && - pScrPriv->mmWidth == pScreen->mmWidth && - pScrPriv->mmHeight == pScreen->mmHeight) - return; - - pScrPriv->width = pScreen->width; - pScrPriv->height = pScreen->height; - pScrPriv->mmWidth = pScreen->mmWidth; - pScrPriv->mmHeight = pScreen->mmHeight; - pScrPriv->changed = TRUE; -/* pScrPriv->sizeChanged = TRUE; */ - - RRTellChanged (pScreen); - RRSendConfigNotify (pScreen); - RREditConnectionInfo (pScreen); - - RRPointerScreenConfigured (pScreen); - /* - * Fix pointer bounds and location - */ - ScreenRestructured (pScreen); -} - -/* - * Request that the screen be resized - */ -Bool -RRScreenSizeSet (ScreenPtr pScreen, - CARD16 width, - CARD16 height, - CARD32 mmWidth, - CARD32 mmHeight) -{ - rrScrPriv(pScreen); - -#if RANDR_12_INTERFACE - if (pScrPriv->rrScreenSetSize) - { - return (*pScrPriv->rrScreenSetSize) (pScreen, - width, height, - mmWidth, mmHeight); - } -#endif -#if RANDR_10_INTERFACE - if (pScrPriv->rrSetConfig) - { - return TRUE; /* can't set size separately */ - } -#endif - return FALSE; -} - -/* - * Retrieve valid screen size range - */ -int -ProcRRGetScreenSizeRange (ClientPtr client) -{ - REQUEST(xRRGetScreenSizeRangeReq); - xRRGetScreenSizeRangeReply rep; - WindowPtr pWin; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - int rc; - - REQUEST_SIZE_MATCH(xRRGetScreenInfoReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - pScreen = pWin->drawable.pScreen; - pScrPriv = rrGetScrPriv(pScreen); - - rep.type = X_Reply; - rep.pad = 0; - rep.sequenceNumber = client->sequence; - rep.length = 0; - - if (pScrPriv) - { - if (!RRGetInfo (pScreen, FALSE)) - return BadAlloc; - rep.minWidth = pScrPriv->minWidth; - rep.minHeight = pScrPriv->minHeight; - rep.maxWidth = pScrPriv->maxWidth; - rep.maxHeight = pScrPriv->maxHeight; - } - else - { - rep.maxWidth = rep.minWidth = pScreen->width; - rep.maxHeight = rep.minHeight = pScreen->height; - } - if (client->swapped) - { - int n; - - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.minWidth, n); - swaps(&rep.minHeight, n); - swaps(&rep.maxWidth, n); - swaps(&rep.maxHeight, n); - } - WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), (char *)&rep); - return (client->noClientException); -} - -int -ProcRRSetScreenSize (ClientPtr client) -{ - REQUEST(xRRSetScreenSizeReq); - WindowPtr pWin; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - int i, rc; - - REQUEST_SIZE_MATCH(xRRSetScreenSizeReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - pScreen = pWin->drawable.pScreen; - pScrPriv = rrGetScrPriv(pScreen); - if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width) - { - client->errorValue = stuff->width; - return BadValue; - } - if (stuff->height < pScrPriv->minHeight || - pScrPriv->maxHeight < stuff->height) - { - client->errorValue = stuff->height; - return BadValue; - } - for (i = 0; i < pScrPriv->numCrtcs; i++) - { - RRCrtcPtr crtc = pScrPriv->crtcs[i]; - RRModePtr mode = crtc->mode; - if (mode) - { - int source_width = mode->mode.width; - int source_height = mode->mode.height; - Rotation rotation = crtc->rotation; - - if (rotation == RR_Rotate_90 || rotation == RR_Rotate_270) - { - source_width = mode->mode.height; - source_height = mode->mode.width; - } - - if (crtc->x + source_width > stuff->width || - crtc->y + source_height > stuff->height) - return BadMatch; - } - } - if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0) - { - client->errorValue = 0; - return BadValue; - } - if (!RRScreenSizeSet (pScreen, - stuff->width, stuff->height, - stuff->widthInMillimeters, - stuff->heightInMillimeters)) - { - return BadMatch; - } - return Success; -} - -static int -rrGetScreenResources(ClientPtr client, Bool query) -{ - REQUEST(xRRGetScreenResourcesReq); - xRRGetScreenResourcesReply rep; - WindowPtr pWin; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - CARD8 *extra; - unsigned long extraLen; - int i, n, rc, has_primary = 0; - RRCrtc *crtcs; - RROutput *outputs; - xRRModeInfo *modeinfos; - CARD8 *names; - - REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - pScreen = pWin->drawable.pScreen; - pScrPriv = rrGetScrPriv(pScreen); - rep.pad = 0; - - if (query && pScrPriv) - if (!RRGetInfo (pScreen, query)) - return BadAlloc; - - if (!pScrPriv) - { - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.timestamp = currentTime.milliseconds; - rep.configTimestamp = currentTime.milliseconds; - rep.nCrtcs = 0; - rep.nOutputs = 0; - rep.nModes = 0; - rep.nbytesNames = 0; - extra = NULL; - extraLen = 0; - } - else - { - RRModePtr *modes; - int num_modes; - - modes = RRModesForScreen (pScreen, &num_modes); - if (!modes) - return BadAlloc; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.timestamp = pScrPriv->lastSetTime.milliseconds; - rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds; - rep.nCrtcs = pScrPriv->numCrtcs; - rep.nOutputs = pScrPriv->numOutputs; - rep.nModes = num_modes; - rep.nbytesNames = 0; - - for (i = 0; i < num_modes; i++) - rep.nbytesNames += modes[i]->mode.nameLength; - - rep.length = (pScrPriv->numCrtcs + - pScrPriv->numOutputs + - num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) + - bytes_to_int32(rep.nbytesNames)); - - extraLen = rep.length << 2; - if (extraLen) - { - extra = xalloc (extraLen); - if (!extra) - { - xfree (modes); - return BadAlloc; - } - } - else - extra = NULL; - - crtcs = (RRCrtc *) extra; - outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs); - modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs); - names = (CARD8 *) (modeinfos + num_modes); - - if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) - { - has_primary = 1; - crtcs[0] = pScrPriv->primaryOutput->crtc->id; - if (client->swapped) - swapl (&crtcs[0], n); - } - - for (i = 0; i < pScrPriv->numCrtcs; i++) - { - if (has_primary && - pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) - { - has_primary = 0; - continue; - } - crtcs[i + has_primary] = pScrPriv->crtcs[i]->id; - if (client->swapped) - swapl (&crtcs[i + has_primary], n); - } - - for (i = 0; i < pScrPriv->numOutputs; i++) - { - outputs[i] = pScrPriv->outputs[i]->id; - if (client->swapped) - swapl (&outputs[i], n); - } - - for (i = 0; i < num_modes; i++) - { - RRModePtr mode = modes[i]; - modeinfos[i] = mode->mode; - if (client->swapped) - { - swapl (&modeinfos[i].id, n); - swaps (&modeinfos[i].width, n); - swaps (&modeinfos[i].height, n); - swapl (&modeinfos[i].dotClock, n); - swaps (&modeinfos[i].hSyncStart, n); - swaps (&modeinfos[i].hSyncEnd, n); - swaps (&modeinfos[i].hTotal, n); - swaps (&modeinfos[i].hSkew, n); - swaps (&modeinfos[i].vSyncStart, n); - swaps (&modeinfos[i].vSyncEnd, n); - swaps (&modeinfos[i].vTotal, n); - swaps (&modeinfos[i].nameLength, n); - swapl (&modeinfos[i].modeFlags, n); - } - memcpy (names, mode->name, - mode->mode.nameLength); - names += mode->mode.nameLength; - } - xfree (modes); - assert (bytes_to_int32((char *) names - (char *) extra) == rep.length); - } - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.timestamp, n); - swapl(&rep.configTimestamp, n); - swaps(&rep.nCrtcs, n); - swaps(&rep.nOutputs, n); - swaps(&rep.nModes, n); - swaps(&rep.nbytesNames, n); - } - WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *)&rep); - if (extraLen) - { - WriteToClient (client, extraLen, (char *) extra); - xfree (extra); - } - return client->noClientException; -} - -int -ProcRRGetScreenResources (ClientPtr client) -{ - return rrGetScreenResources(client, TRUE); -} - -int -ProcRRGetScreenResourcesCurrent (ClientPtr client) -{ - return rrGetScreenResources(client, FALSE); -} - -typedef struct _RR10Data { - RRScreenSizePtr sizes; - int nsize; - int nrefresh; - int size; - CARD16 refresh; -} RR10DataRec, *RR10DataPtr; - -/* - * Convert 1.2 monitor data into 1.0 screen data - */ -static RR10DataPtr -RR10GetData (ScreenPtr pScreen, RROutputPtr output) -{ - RR10DataPtr data; - RRScreenSizePtr size; - int nmode = output->numModes + output->numUserModes; - int o, os, l, r; - RRScreenRatePtr refresh; - CARD16 vRefresh; - RRModePtr mode; - Bool *used; - - /* Make sure there is plenty of space for any combination */ - data = malloc (sizeof (RR10DataRec) + - sizeof (RRScreenSize) * nmode + - sizeof (RRScreenRate) * nmode + - sizeof (Bool) * nmode); - if (!data) - return NULL; - size = (RRScreenSizePtr) (data + 1); - refresh = (RRScreenRatePtr) (size + nmode); - used = (Bool *) (refresh + nmode); - memset (used, '\0', sizeof (Bool) * nmode); - data->sizes = size; - data->nsize = 0; - data->nrefresh = 0; - data->size = 0; - data->refresh = 0; - - /* - * find modes not yet listed - */ - for (o = 0; o < output->numModes + output->numUserModes; o++) - { - if (used[o]) continue; - - if (o < output->numModes) - mode = output->modes[o]; - else - mode = output->userModes[o - output->numModes]; - - l = data->nsize; - size[l].id = data->nsize; - size[l].width = mode->mode.width; - size[l].height = mode->mode.height; - if (output->mmWidth && output->mmHeight) { - size[l].mmWidth = output->mmWidth; - size[l].mmHeight = output->mmHeight; - } else { - size[l].mmWidth = pScreen->mmWidth; - size[l].mmHeight = pScreen->mmHeight; - } - size[l].nRates = 0; - size[l].pRates = &refresh[data->nrefresh]; - data->nsize++; - - /* - * Find all modes with matching size - */ - for (os = o; os < output->numModes + output->numUserModes; os++) - { - if (os < output->numModes) - mode = output->modes[os]; - else - mode = output->userModes[os - output->numModes]; - if (mode->mode.width == size[l].width && - mode->mode.height == size[l].height) - { - vRefresh = RRVerticalRefresh (&mode->mode); - used[os] = TRUE; - - for (r = 0; r < size[l].nRates; r++) - if (vRefresh == size[l].pRates[r].rate) - break; - if (r == size[l].nRates) - { - size[l].pRates[r].rate = vRefresh; - size[l].pRates[r].mode = mode; - size[l].nRates++; - data->nrefresh++; - } - if (mode == output->crtc->mode) - { - data->size = l; - data->refresh = vRefresh; - } - } - } - } - return data; -} - -int -ProcRRGetScreenInfo (ClientPtr client) -{ - REQUEST(xRRGetScreenInfoReq); - xRRGetScreenInfoReply rep; - WindowPtr pWin; - int n, rc; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - CARD8 *extra; - unsigned long extraLen; - RROutputPtr output; - - REQUEST_SIZE_MATCH(xRRGetScreenInfoReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - pScreen = pWin->drawable.pScreen; - pScrPriv = rrGetScrPriv(pScreen); - rep.pad = 0; - - if (pScrPriv) - if (!RRGetInfo (pScreen, TRUE)) - return BadAlloc; - - output = RRFirstOutput (pScreen); - - if (!pScrPriv || !output) - { - rep.type = X_Reply; - rep.setOfRotations = RR_Rotate_0; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id; - rep.timestamp = currentTime.milliseconds; - rep.configTimestamp = currentTime.milliseconds; - rep.nSizes = 0; - rep.sizeID = 0; - rep.rotation = RR_Rotate_0; - rep.rate = 0; - rep.nrateEnts = 0; - extra = 0; - extraLen = 0; - } - else - { - int i, j; - xScreenSizes *size; - CARD16 *rates; - CARD8 *data8; - Bool has_rate = RRClientKnowsRates (client); - RR10DataPtr pData; - RRScreenSizePtr pSize; - - pData = RR10GetData (pScreen, output); - if (!pData) - return BadAlloc; - - rep.type = X_Reply; - rep.setOfRotations = output->crtc->rotations; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id; - rep.timestamp = pScrPriv->lastSetTime.milliseconds; - rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds; - rep.rotation = output->crtc->rotation; - rep.nSizes = pData->nsize; - rep.nrateEnts = pData->nrefresh + pData->nsize; - rep.sizeID = pData->size; - rep.rate = pData->refresh; - - extraLen = rep.nSizes * sizeof (xScreenSizes); - if (has_rate) - extraLen += rep.nrateEnts * sizeof (CARD16); - - if (extraLen) - { - extra = (CARD8 *) xalloc (extraLen); - if (!extra) - { - xfree (pData); - return BadAlloc; - } - } - else - extra = NULL; - - /* - * First comes the size information - */ - size = (xScreenSizes *) extra; - rates = (CARD16 *) (size + rep.nSizes); - for (i = 0; i < pData->nsize; i++) - { - pSize = &pData->sizes[i]; - size->widthInPixels = pSize->width; - size->heightInPixels = pSize->height; - size->widthInMillimeters = pSize->mmWidth; - size->heightInMillimeters = pSize->mmHeight; - if (client->swapped) - { - swaps (&size->widthInPixels, n); - swaps (&size->heightInPixels, n); - swaps (&size->widthInMillimeters, n); - swaps (&size->heightInMillimeters, n); - } - size++; - if (has_rate) - { - *rates = pSize->nRates; - if (client->swapped) - { - swaps (rates, n); - } - rates++; - for (j = 0; j < pSize->nRates; j++) - { - *rates = pSize->pRates[j].rate; - if (client->swapped) - { - swaps (rates, n); - } - rates++; - } - } - } - xfree (pData); - - data8 = (CARD8 *) rates; - - if (data8 - (CARD8 *) extra != extraLen) - FatalError ("RRGetScreenInfo bad extra len %ld != %ld\n", - (unsigned long)(data8 - (CARD8 *) extra), extraLen); - rep.length = bytes_to_int32(extraLen); - } - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.timestamp, n); - swaps(&rep.rotation, n); - swaps(&rep.nSizes, n); - swaps(&rep.sizeID, n); - swaps(&rep.rate, n); - swaps(&rep.nrateEnts, n); - } - WriteToClient(client, sizeof(xRRGetScreenInfoReply), (char *)&rep); - if (extraLen) - { - WriteToClient (client, extraLen, (char *) extra); - xfree (extra); - } - return (client->noClientException); -} - -int -ProcRRSetScreenConfig (ClientPtr client) -{ - REQUEST(xRRSetScreenConfigReq); - xRRSetScreenConfigReply rep; - DrawablePtr pDraw; - int n, rc; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - TimeStamp time; - int i; - Rotation rotation; - int rate; - Bool has_rate; - RROutputPtr output; - RRCrtcPtr crtc; - RRModePtr mode; - RR10DataPtr pData = NULL; - RRScreenSizePtr pSize; - int width, height; - - UpdateCurrentTime (); - - if (RRClientKnowsRates (client)) - { - REQUEST_SIZE_MATCH (xRRSetScreenConfigReq); - has_rate = TRUE; - } - else - { - REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq); - has_rate = FALSE; - } - - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess); - if (rc != Success) - return rc; - - pScreen = pDraw->pScreen; - - pScrPriv = rrGetScrPriv(pScreen); - - time = ClientTimeToServerTime(stuff->timestamp); - - if (!pScrPriv) - { - time = currentTime; - rep.status = RRSetConfigFailed; - goto sendReply; - } - if (!RRGetInfo (pScreen, FALSE)) - return BadAlloc; - - output = RRFirstOutput (pScreen); - if (!output) - { - time = currentTime; - rep.status = RRSetConfigFailed; - goto sendReply; - } - - crtc = output->crtc; - - /* - * If the client's config timestamp is not the same as the last config - * timestamp, then the config information isn't up-to-date and - * can't even be validated. - * - * Note that the client only knows about the milliseconds part of the - * timestamp, so using CompareTimeStamps here would cause randr to suddenly - * stop working after several hours have passed (freedesktop bug #6502). - */ - if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds) - { - rep.status = RRSetConfigInvalidConfigTime; - goto sendReply; - } - - pData = RR10GetData (pScreen, output); - if (!pData) - return BadAlloc; - - if (stuff->sizeID >= pData->nsize) - { - /* - * Invalid size ID - */ - client->errorValue = stuff->sizeID; - xfree (pData); - return BadValue; - } - pSize = &pData->sizes[stuff->sizeID]; - - /* - * Validate requested rotation - */ - rotation = (Rotation) stuff->rotation; - - /* test the rotation bits only! */ - switch (rotation & 0xf) { - case RR_Rotate_0: - case RR_Rotate_90: - case RR_Rotate_180: - case RR_Rotate_270: - break; - default: - /* - * Invalid rotation - */ - client->errorValue = stuff->rotation; - xfree (pData); - return BadValue; - } - - if ((~crtc->rotations) & rotation) - { - /* - * requested rotation or reflection not supported by screen - */ - client->errorValue = stuff->rotation; - xfree (pData); - return BadMatch; - } - - /* - * Validate requested refresh - */ - if (has_rate) - rate = (int) stuff->rate; - else - rate = 0; - - if (rate) - { - for (i = 0; i < pSize->nRates; i++) - { - if (pSize->pRates[i].rate == rate) - break; - } - if (i == pSize->nRates) - { - /* - * Invalid rate - */ - client->errorValue = rate; - xfree (pData); - return BadValue; - } - mode = pSize->pRates[i].mode; - } - else - mode = pSize->pRates[0].mode; - - /* - * Make sure the requested set-time is not older than - * the last set-time - */ - if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0) - { - rep.status = RRSetConfigInvalidTime; - goto sendReply; - } - - /* - * If the screen size is changing, adjust all of the other outputs - * to fit the new size, mirroring as much as possible - */ - width = mode->mode.width; - height = mode->mode.height; - if (rotation & (RR_Rotate_90|RR_Rotate_270)) - { - width = mode->mode.height; - height = mode->mode.width; - } - if (width != pScreen->width || height != pScreen->height) - { - int c; - - for (c = 0; c < pScrPriv->numCrtcs; c++) - { - if (!RRCrtcSet (pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0, - 0, NULL)) - { - rep.status = RRSetConfigFailed; - /* XXX recover from failure */ - goto sendReply; - } - } - if (!RRScreenSizeSet (pScreen, width, height, - pScreen->mmWidth, pScreen->mmHeight)) - { - rep.status = RRSetConfigFailed; - /* XXX recover from failure */ - goto sendReply; - } - } - - if (!RRCrtcSet (crtc, mode, 0, 0, stuff->rotation, 1, &output)) - rep.status = RRSetConfigFailed; - else { - pScrPriv->lastSetTime = time; - rep.status = RRSetConfigSuccess; - } - - /* - * XXX Configure other crtcs to mirror as much as possible - */ - -sendReply: - - if (pData) - xfree (pData); - - rep.type = X_Reply; - /* rep.status has already been filled in */ - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; - rep.newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds; - rep.root = WindowTable[pDraw->pScreen->myNum]->drawable.id; - - if (client->swapped) - { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.newTimestamp, n); - swapl(&rep.newConfigTimestamp, n); - swapl(&rep.root, n); - } - WriteToClient(client, sizeof(xRRSetScreenConfigReply), (char *)&rep); - - return (client->noClientException); -} - -static CARD16 -RR10CurrentSizeID (ScreenPtr pScreen) -{ - CARD16 sizeID = 0xffff; - RROutputPtr output = RRFirstOutput (pScreen); - - if (output) - { - RR10DataPtr data = RR10GetData (pScreen, output); - if (data) - { - int i; - for (i = 0; i < data->nsize; i++) - if (data->sizes[i].width == pScreen->width && - data->sizes[i].height == pScreen->height) - { - sizeID = (CARD16) i; - break; - } - xfree (data); - } - } - return sizeID; -} +/* + * Copyright © 2006 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "randrstr.h" + +static const int padlength[4] = {0, 3, 2, 1}; + +static CARD16 +RR10CurrentSizeID (ScreenPtr pScreen); + +/* + * Edit connection information block so that new clients + * see the current screen size on connect + */ +static void +RREditConnectionInfo (ScreenPtr pScreen) +{ + xConnSetup *connSetup; + char *vendor; + xPixmapFormat *formats; + xWindowRoot *root; + xDepth *depth; + xVisualType *visual; + int screen = 0; + int d; + + connSetup = (xConnSetup *) ConnectionInfo; + vendor = (char *) connSetup + sizeof (xConnSetup); + formats = (xPixmapFormat *) ((char *) vendor + + connSetup->nbytesVendor + + padlength[connSetup->nbytesVendor & 3]); + root = (xWindowRoot *) ((char *) formats + + sizeof (xPixmapFormat) * screenInfo.numPixmapFormats); + while (screen != pScreen->myNum) + { + depth = (xDepth *) ((char *) root + + sizeof (xWindowRoot)); + for (d = 0; d < root->nDepths; d++) + { + visual = (xVisualType *) ((char *) depth + + sizeof (xDepth)); + depth = (xDepth *) ((char *) visual + + depth->nVisuals * sizeof (xVisualType)); + } + root = (xWindowRoot *) ((char *) depth); + screen++; + } + root->pixWidth = pScreen->width; + root->pixHeight = pScreen->height; + root->mmWidth = pScreen->mmWidth; + root->mmHeight = pScreen->mmHeight; +} + +void +RRSendConfigNotify (ScreenPtr pScreen) +{ + WindowPtr pWin = WindowTable[pScreen->myNum]; + xEvent event; + + event.u.u.type = ConfigureNotify; + event.u.configureNotify.window = pWin->drawable.id; + event.u.configureNotify.aboveSibling = None; + event.u.configureNotify.x = 0; + event.u.configureNotify.y = 0; + + /* XXX xinerama stuff ? */ + + event.u.configureNotify.width = pWin->drawable.width; + event.u.configureNotify.height = pWin->drawable.height; + event.u.configureNotify.borderWidth = wBorderWidth (pWin); + event.u.configureNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); +} + +void +RRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen) +{ + rrScrPriv (pScreen); + xRRScreenChangeNotifyEvent se; + RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + + se.type = RRScreenChangeNotify + RREventBase; + se.rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0); + se.timestamp = pScrPriv->lastSetTime.milliseconds; + se.sequenceNumber = client->sequence; + se.configTimestamp = pScrPriv->lastConfigTime.milliseconds; + se.root = pRoot->drawable.id; + se.window = pWin->drawable.id; + se.subpixelOrder = PictureGetSubpixelOrder (pScreen); + + se.sequenceNumber = client->sequence; + se.sizeID = RR10CurrentSizeID (pScreen); + + if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) { + se.widthInPixels = pScreen->height; + se.heightInPixels = pScreen->width; + se.widthInMillimeters = pScreen->mmHeight; + se.heightInMillimeters = pScreen->mmWidth; + } else { + se.widthInPixels = pScreen->width; + se.heightInPixels = pScreen->height; + se.widthInMillimeters = pScreen->mmWidth; + se.heightInMillimeters = pScreen->mmHeight; + } + + WriteEventsToClient (client, 1, (xEvent *) &se); +} + +/* + * Notify the extension that the screen size has been changed. + * The driver is responsible for calling this whenever it has changed + * the size of the screen + */ +void +RRScreenSizeNotify (ScreenPtr pScreen) +{ + rrScrPriv(pScreen); + /* + * Deliver ConfigureNotify events when root changes + * pixel size + */ + if (pScrPriv->width == pScreen->width && + pScrPriv->height == pScreen->height && + pScrPriv->mmWidth == pScreen->mmWidth && + pScrPriv->mmHeight == pScreen->mmHeight) + return; + + pScrPriv->width = pScreen->width; + pScrPriv->height = pScreen->height; + pScrPriv->mmWidth = pScreen->mmWidth; + pScrPriv->mmHeight = pScreen->mmHeight; + pScrPriv->changed = TRUE; +/* pScrPriv->sizeChanged = TRUE; */ + + RRTellChanged (pScreen); + RRSendConfigNotify (pScreen); + RREditConnectionInfo (pScreen); + + RRPointerScreenConfigured (pScreen); + /* + * Fix pointer bounds and location + */ + ScreenRestructured (pScreen); +} + +/* + * Request that the screen be resized + */ +Bool +RRScreenSizeSet (ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD32 mmWidth, + CARD32 mmHeight) +{ + rrScrPriv(pScreen); + +#if RANDR_12_INTERFACE + if (pScrPriv->rrScreenSetSize) + { + return (*pScrPriv->rrScreenSetSize) (pScreen, + width, height, + mmWidth, mmHeight); + } +#endif +#if RANDR_10_INTERFACE + if (pScrPriv->rrSetConfig) + { + return TRUE; /* can't set size separately */ + } +#endif + return FALSE; +} + +/* + * Retrieve valid screen size range + */ +int +ProcRRGetScreenSizeRange (ClientPtr client) +{ + REQUEST(xRRGetScreenSizeRangeReq); + xRRGetScreenSizeRangeReply rep; + WindowPtr pWin; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + int rc; + + REQUEST_SIZE_MATCH(xRRGetScreenInfoReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + pScrPriv = rrGetScrPriv(pScreen); + + rep.type = X_Reply; + rep.pad = 0; + rep.sequenceNumber = client->sequence; + rep.length = 0; + + if (pScrPriv) + { + if (!RRGetInfo (pScreen, FALSE)) + return BadAlloc; + rep.minWidth = pScrPriv->minWidth; + rep.minHeight = pScrPriv->minHeight; + rep.maxWidth = pScrPriv->maxWidth; + rep.maxHeight = pScrPriv->maxHeight; + } + else + { + rep.maxWidth = rep.minWidth = pScreen->width; + rep.maxHeight = rep.minHeight = pScreen->height; + } + if (client->swapped) + { + int n; + + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.minWidth, n); + swaps(&rep.minHeight, n); + swaps(&rep.maxWidth, n); + swaps(&rep.maxHeight, n); + } + WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), (char *)&rep); + return Success; +} + +int +ProcRRSetScreenSize (ClientPtr client) +{ + REQUEST(xRRSetScreenSizeReq); + WindowPtr pWin; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + int i, rc; + + REQUEST_SIZE_MATCH(xRRSetScreenSizeReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + pScrPriv = rrGetScrPriv(pScreen); + if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width) + { + client->errorValue = stuff->width; + return BadValue; + } + if (stuff->height < pScrPriv->minHeight || + pScrPriv->maxHeight < stuff->height) + { + client->errorValue = stuff->height; + return BadValue; + } + for (i = 0; i < pScrPriv->numCrtcs; i++) + { + RRCrtcPtr crtc = pScrPriv->crtcs[i]; + RRModePtr mode = crtc->mode; + if (mode) + { + int source_width = mode->mode.width; + int source_height = mode->mode.height; + Rotation rotation = crtc->rotation; + + if (rotation == RR_Rotate_90 || rotation == RR_Rotate_270) + { + source_width = mode->mode.height; + source_height = mode->mode.width; + } + + if (crtc->x + source_width > stuff->width || + crtc->y + source_height > stuff->height) + return BadMatch; + } + } + if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0) + { + client->errorValue = 0; + return BadValue; + } + if (!RRScreenSizeSet (pScreen, + stuff->width, stuff->height, + stuff->widthInMillimeters, + stuff->heightInMillimeters)) + { + return BadMatch; + } + return Success; +} + +static int +rrGetScreenResources(ClientPtr client, Bool query) +{ + REQUEST(xRRGetScreenResourcesReq); + xRRGetScreenResourcesReply rep; + WindowPtr pWin; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + CARD8 *extra; + unsigned long extraLen; + int i, n, rc, has_primary = 0; + RRCrtc *crtcs; + RROutput *outputs; + xRRModeInfo *modeinfos; + CARD8 *names; + + REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + pScrPriv = rrGetScrPriv(pScreen); + rep.pad = 0; + + if (query && pScrPriv) + if (!RRGetInfo (pScreen, query)) + return BadAlloc; + + if (!pScrPriv) + { + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.timestamp = currentTime.milliseconds; + rep.configTimestamp = currentTime.milliseconds; + rep.nCrtcs = 0; + rep.nOutputs = 0; + rep.nModes = 0; + rep.nbytesNames = 0; + extra = NULL; + extraLen = 0; + } + else + { + RRModePtr *modes; + int num_modes; + + modes = RRModesForScreen (pScreen, &num_modes); + if (!modes) + return BadAlloc; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.timestamp = pScrPriv->lastSetTime.milliseconds; + rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds; + rep.nCrtcs = pScrPriv->numCrtcs; + rep.nOutputs = pScrPriv->numOutputs; + rep.nModes = num_modes; + rep.nbytesNames = 0; + + for (i = 0; i < num_modes; i++) + rep.nbytesNames += modes[i]->mode.nameLength; + + rep.length = (pScrPriv->numCrtcs + + pScrPriv->numOutputs + + num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) + + bytes_to_int32(rep.nbytesNames)); + + extraLen = rep.length << 2; + if (extraLen) + { + extra = malloc(extraLen); + if (!extra) + { + free(modes); + return BadAlloc; + } + } + else + extra = NULL; + + crtcs = (RRCrtc *) extra; + outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs); + modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs); + names = (CARD8 *) (modeinfos + num_modes); + + if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) + { + has_primary = 1; + crtcs[0] = pScrPriv->primaryOutput->crtc->id; + if (client->swapped) + swapl (&crtcs[0], n); + } + + for (i = 0; i < pScrPriv->numCrtcs; i++) + { + if (has_primary && + pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) + { + has_primary = 0; + continue; + } + crtcs[i + has_primary] = pScrPriv->crtcs[i]->id; + if (client->swapped) + swapl (&crtcs[i + has_primary], n); + } + + for (i = 0; i < pScrPriv->numOutputs; i++) + { + outputs[i] = pScrPriv->outputs[i]->id; + if (client->swapped) + swapl (&outputs[i], n); + } + + for (i = 0; i < num_modes; i++) + { + RRModePtr mode = modes[i]; + modeinfos[i] = mode->mode; + if (client->swapped) + { + swapl (&modeinfos[i].id, n); + swaps (&modeinfos[i].width, n); + swaps (&modeinfos[i].height, n); + swapl (&modeinfos[i].dotClock, n); + swaps (&modeinfos[i].hSyncStart, n); + swaps (&modeinfos[i].hSyncEnd, n); + swaps (&modeinfos[i].hTotal, n); + swaps (&modeinfos[i].hSkew, n); + swaps (&modeinfos[i].vSyncStart, n); + swaps (&modeinfos[i].vSyncEnd, n); + swaps (&modeinfos[i].vTotal, n); + swaps (&modeinfos[i].nameLength, n); + swapl (&modeinfos[i].modeFlags, n); + } + memcpy (names, mode->name, + mode->mode.nameLength); + names += mode->mode.nameLength; + } + free(modes); + assert (bytes_to_int32((char *) names - (char *) extra) == rep.length); + } + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.timestamp, n); + swapl(&rep.configTimestamp, n); + swaps(&rep.nCrtcs, n); + swaps(&rep.nOutputs, n); + swaps(&rep.nModes, n); + swaps(&rep.nbytesNames, n); + } + WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *)&rep); + if (extraLen) + { + WriteToClient (client, extraLen, (char *) extra); + free(extra); + } + return Success; +} + +int +ProcRRGetScreenResources (ClientPtr client) +{ + return rrGetScreenResources(client, TRUE); +} + +int +ProcRRGetScreenResourcesCurrent (ClientPtr client) +{ + return rrGetScreenResources(client, FALSE); +} + +typedef struct _RR10Data { + RRScreenSizePtr sizes; + int nsize; + int nrefresh; + int size; + CARD16 refresh; +} RR10DataRec, *RR10DataPtr; + +/* + * Convert 1.2 monitor data into 1.0 screen data + */ +static RR10DataPtr +RR10GetData (ScreenPtr pScreen, RROutputPtr output) +{ + RR10DataPtr data; + RRScreenSizePtr size; + int nmode = output->numModes + output->numUserModes; + int o, os, l, r; + RRScreenRatePtr refresh; + CARD16 vRefresh; + RRModePtr mode; + Bool *used; + + /* Make sure there is plenty of space for any combination */ + data = malloc (sizeof (RR10DataRec) + + sizeof (RRScreenSize) * nmode + + sizeof (RRScreenRate) * nmode + + sizeof (Bool) * nmode); + if (!data) + return NULL; + size = (RRScreenSizePtr) (data + 1); + refresh = (RRScreenRatePtr) (size + nmode); + used = (Bool *) (refresh + nmode); + memset (used, '\0', sizeof (Bool) * nmode); + data->sizes = size; + data->nsize = 0; + data->nrefresh = 0; + data->size = 0; + data->refresh = 0; + + /* + * find modes not yet listed + */ + for (o = 0; o < output->numModes + output->numUserModes; o++) + { + if (used[o]) continue; + + if (o < output->numModes) + mode = output->modes[o]; + else + mode = output->userModes[o - output->numModes]; + + l = data->nsize; + size[l].id = data->nsize; + size[l].width = mode->mode.width; + size[l].height = mode->mode.height; + if (output->mmWidth && output->mmHeight) { + size[l].mmWidth = output->mmWidth; + size[l].mmHeight = output->mmHeight; + } else { + size[l].mmWidth = pScreen->mmWidth; + size[l].mmHeight = pScreen->mmHeight; + } + size[l].nRates = 0; + size[l].pRates = &refresh[data->nrefresh]; + data->nsize++; + + /* + * Find all modes with matching size + */ + for (os = o; os < output->numModes + output->numUserModes; os++) + { + if (os < output->numModes) + mode = output->modes[os]; + else + mode = output->userModes[os - output->numModes]; + if (mode->mode.width == size[l].width && + mode->mode.height == size[l].height) + { + vRefresh = RRVerticalRefresh (&mode->mode); + used[os] = TRUE; + + for (r = 0; r < size[l].nRates; r++) + if (vRefresh == size[l].pRates[r].rate) + break; + if (r == size[l].nRates) + { + size[l].pRates[r].rate = vRefresh; + size[l].pRates[r].mode = mode; + size[l].nRates++; + data->nrefresh++; + } + if (mode == output->crtc->mode) + { + data->size = l; + data->refresh = vRefresh; + } + } + } + } + return data; +} + +int +ProcRRGetScreenInfo (ClientPtr client) +{ + REQUEST(xRRGetScreenInfoReq); + xRRGetScreenInfoReply rep; + WindowPtr pWin; + int n, rc; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + CARD8 *extra; + unsigned long extraLen; + RROutputPtr output; + + REQUEST_SIZE_MATCH(xRRGetScreenInfoReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + pScrPriv = rrGetScrPriv(pScreen); + rep.pad = 0; + + if (pScrPriv) + if (!RRGetInfo (pScreen, TRUE)) + return BadAlloc; + + output = RRFirstOutput (pScreen); + + if (!pScrPriv || !output) + { + rep.type = X_Reply; + rep.setOfRotations = RR_Rotate_0; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id; + rep.timestamp = currentTime.milliseconds; + rep.configTimestamp = currentTime.milliseconds; + rep.nSizes = 0; + rep.sizeID = 0; + rep.rotation = RR_Rotate_0; + rep.rate = 0; + rep.nrateEnts = 0; + extra = 0; + extraLen = 0; + } + else + { + int i, j; + xScreenSizes *size; + CARD16 *rates; + CARD8 *data8; + Bool has_rate = RRClientKnowsRates (client); + RR10DataPtr pData; + RRScreenSizePtr pSize; + + pData = RR10GetData (pScreen, output); + if (!pData) + return BadAlloc; + + rep.type = X_Reply; + rep.setOfRotations = output->crtc->rotations; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id; + rep.timestamp = pScrPriv->lastSetTime.milliseconds; + rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds; + rep.rotation = output->crtc->rotation; + rep.nSizes = pData->nsize; + rep.nrateEnts = pData->nrefresh + pData->nsize; + rep.sizeID = pData->size; + rep.rate = pData->refresh; + + extraLen = rep.nSizes * sizeof (xScreenSizes); + if (has_rate) + extraLen += rep.nrateEnts * sizeof (CARD16); + + if (extraLen) + { + extra = (CARD8 *) malloc(extraLen); + if (!extra) + { + free(pData); + return BadAlloc; + } + } + else + extra = NULL; + + /* + * First comes the size information + */ + size = (xScreenSizes *) extra; + rates = (CARD16 *) (size + rep.nSizes); + for (i = 0; i < pData->nsize; i++) + { + pSize = &pData->sizes[i]; + size->widthInPixels = pSize->width; + size->heightInPixels = pSize->height; + size->widthInMillimeters = pSize->mmWidth; + size->heightInMillimeters = pSize->mmHeight; + if (client->swapped) + { + swaps (&size->widthInPixels, n); + swaps (&size->heightInPixels, n); + swaps (&size->widthInMillimeters, n); + swaps (&size->heightInMillimeters, n); + } + size++; + if (has_rate) + { + *rates = pSize->nRates; + if (client->swapped) + { + swaps (rates, n); + } + rates++; + for (j = 0; j < pSize->nRates; j++) + { + *rates = pSize->pRates[j].rate; + if (client->swapped) + { + swaps (rates, n); + } + rates++; + } + } + } + free(pData); + + data8 = (CARD8 *) rates; + + if (data8 - (CARD8 *) extra != extraLen) + FatalError ("RRGetScreenInfo bad extra len %ld != %ld\n", + (unsigned long)(data8 - (CARD8 *) extra), extraLen); + rep.length = bytes_to_int32(extraLen); + } + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.timestamp, n); + swaps(&rep.rotation, n); + swaps(&rep.nSizes, n); + swaps(&rep.sizeID, n); + swaps(&rep.rate, n); + swaps(&rep.nrateEnts, n); + } + WriteToClient(client, sizeof(xRRGetScreenInfoReply), (char *)&rep); + if (extraLen) + { + WriteToClient (client, extraLen, (char *) extra); + free(extra); + } + return Success; +} + +int +ProcRRSetScreenConfig (ClientPtr client) +{ + REQUEST(xRRSetScreenConfigReq); + xRRSetScreenConfigReply rep; + DrawablePtr pDraw; + int n, rc; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + TimeStamp time; + int i; + Rotation rotation; + int rate; + Bool has_rate; + RROutputPtr output; + RRCrtcPtr crtc; + RRModePtr mode; + RR10DataPtr pData = NULL; + RRScreenSizePtr pSize; + int width, height; + + UpdateCurrentTime (); + + if (RRClientKnowsRates (client)) + { + REQUEST_SIZE_MATCH (xRRSetScreenConfigReq); + has_rate = TRUE; + } + else + { + REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq); + has_rate = FALSE; + } + + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess); + if (rc != Success) + return rc; + + pScreen = pDraw->pScreen; + + pScrPriv = rrGetScrPriv(pScreen); + + time = ClientTimeToServerTime(stuff->timestamp); + + if (!pScrPriv) + { + time = currentTime; + rep.status = RRSetConfigFailed; + goto sendReply; + } + if (!RRGetInfo (pScreen, FALSE)) + return BadAlloc; + + output = RRFirstOutput (pScreen); + if (!output) + { + time = currentTime; + rep.status = RRSetConfigFailed; + goto sendReply; + } + + crtc = output->crtc; + + /* + * If the client's config timestamp is not the same as the last config + * timestamp, then the config information isn't up-to-date and + * can't even be validated. + * + * Note that the client only knows about the milliseconds part of the + * timestamp, so using CompareTimeStamps here would cause randr to suddenly + * stop working after several hours have passed (freedesktop bug #6502). + */ + if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds) + { + rep.status = RRSetConfigInvalidConfigTime; + goto sendReply; + } + + pData = RR10GetData (pScreen, output); + if (!pData) + return BadAlloc; + + if (stuff->sizeID >= pData->nsize) + { + /* + * Invalid size ID + */ + client->errorValue = stuff->sizeID; + free(pData); + return BadValue; + } + pSize = &pData->sizes[stuff->sizeID]; + + /* + * Validate requested rotation + */ + rotation = (Rotation) stuff->rotation; + + /* test the rotation bits only! */ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_90: + case RR_Rotate_180: + case RR_Rotate_270: + break; + default: + /* + * Invalid rotation + */ + client->errorValue = stuff->rotation; + free(pData); + return BadValue; + } + + if ((~crtc->rotations) & rotation) + { + /* + * requested rotation or reflection not supported by screen + */ + client->errorValue = stuff->rotation; + free(pData); + return BadMatch; + } + + /* + * Validate requested refresh + */ + if (has_rate) + rate = (int) stuff->rate; + else + rate = 0; + + if (rate) + { + for (i = 0; i < pSize->nRates; i++) + { + if (pSize->pRates[i].rate == rate) + break; + } + if (i == pSize->nRates) + { + /* + * Invalid rate + */ + client->errorValue = rate; + free(pData); + return BadValue; + } + mode = pSize->pRates[i].mode; + } + else + mode = pSize->pRates[0].mode; + + /* + * Make sure the requested set-time is not older than + * the last set-time + */ + if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0) + { + rep.status = RRSetConfigInvalidTime; + goto sendReply; + } + + /* + * If the screen size is changing, adjust all of the other outputs + * to fit the new size, mirroring as much as possible + */ + width = mode->mode.width; + height = mode->mode.height; + if (rotation & (RR_Rotate_90|RR_Rotate_270)) + { + width = mode->mode.height; + height = mode->mode.width; + } + if (width != pScreen->width || height != pScreen->height) + { + int c; + + for (c = 0; c < pScrPriv->numCrtcs; c++) + { + if (!RRCrtcSet (pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0, + 0, NULL)) + { + rep.status = RRSetConfigFailed; + /* XXX recover from failure */ + goto sendReply; + } + } + if (!RRScreenSizeSet (pScreen, width, height, + pScreen->mmWidth, pScreen->mmHeight)) + { + rep.status = RRSetConfigFailed; + /* XXX recover from failure */ + goto sendReply; + } + } + + if (!RRCrtcSet (crtc, mode, 0, 0, stuff->rotation, 1, &output)) + rep.status = RRSetConfigFailed; + else { + pScrPriv->lastSetTime = time; + rep.status = RRSetConfigSuccess; + } + + /* + * XXX Configure other crtcs to mirror as much as possible + */ + +sendReply: + + if (pData) + free(pData); + + rep.type = X_Reply; + /* rep.status has already been filled in */ + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; + rep.newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds; + rep.root = WindowTable[pDraw->pScreen->myNum]->drawable.id; + + if (client->swapped) + { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.newTimestamp, n); + swapl(&rep.newConfigTimestamp, n); + swapl(&rep.root, n); + } + WriteToClient(client, sizeof(xRRSetScreenConfigReply), (char *)&rep); + + return Success; +} + +static CARD16 +RR10CurrentSizeID (ScreenPtr pScreen) +{ + CARD16 sizeID = 0xffff; + RROutputPtr output = RRFirstOutput (pScreen); + + if (output) + { + RR10DataPtr data = RR10GetData (pScreen, output); + if (data) + { + int i; + for (i = 0; i < data->nsize; i++) + if (data->sizes[i].width == pScreen->width && + data->sizes[i].height == pScreen->height) + { + sizeID = (CARD16) i; + break; + } + free(data); + } + } + return sizeID; +} diff --git a/xorg-server/randr/rrtransform.c b/xorg-server/randr/rrtransform.c index 06f62984d..6740e4825 100644 --- a/xorg-server/randr/rrtransform.c +++ b/xorg-server/randr/rrtransform.c @@ -1,285 +1,285 @@ -/* - * Copyright © 2007 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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. - */ - -#include "randrstr.h" -#include "rrtransform.h" - -void -RRTransformInit (RRTransformPtr transform) -{ - pixman_transform_init_identity (&transform->transform); - pixman_f_transform_init_identity (&transform->f_transform); - pixman_f_transform_init_identity (&transform->f_inverse); - transform->filter = NULL; - transform->params = NULL; - transform->nparams = 0; -} - -void -RRTransformFini (RRTransformPtr transform) -{ - if (transform->params) - xfree (transform->params); -} - -Bool -RRTransformEqual (RRTransformPtr a, RRTransformPtr b) -{ - if (a && pixman_transform_is_identity (&a->transform)) - a = NULL; - if (b && pixman_transform_is_identity (&b->transform)) - b = NULL; - if (a == NULL && b == NULL) - return TRUE; - if (a == NULL || b == NULL) - return FALSE; - if (memcmp (&a->transform, &b->transform, sizeof (a->transform)) != 0) - return FALSE; - if (a->filter != b->filter) - return FALSE; - if (a->nparams != b->nparams) - return FALSE; - if (memcmp (a->params, b->params, a->nparams * sizeof (xFixed)) != 0) - return FALSE; - return TRUE; -} - -Bool -RRTransformSetFilter (RRTransformPtr dst, - PictFilterPtr filter, - xFixed *params, - int nparams, - int width, - int height) -{ - xFixed *new_params; - - if (nparams) - { - new_params = xalloc (nparams * sizeof (xFixed)); - if (!new_params) - return FALSE; - memcpy (new_params, params, nparams * sizeof (xFixed)); - } - else - new_params = NULL; - if (dst->params) - xfree (dst->params); - dst->filter = filter; - dst->params = new_params; - dst->nparams = nparams; - dst->width = width; - dst->height = height; - return TRUE; -} - -Bool -RRTransformCopy (RRTransformPtr dst, RRTransformPtr src) -{ - if (src && pixman_transform_is_identity (&src->transform)) - src = NULL; - - if (src) - { - if (!RRTransformSetFilter (dst, src->filter, - src->params, src->nparams, src->width, src->height)) - return FALSE; - dst->transform = src->transform; - dst->f_transform = src->f_transform; - dst->f_inverse = src->f_inverse; - } - else - { - if (!RRTransformSetFilter (dst, NULL, NULL, 0, 0, 0)) - return FALSE; - pixman_transform_init_identity (&dst->transform); - pixman_f_transform_init_identity (&dst->f_transform); - pixman_f_transform_init_identity (&dst->f_inverse); - } - return TRUE; -} - -#define F(x) IntToxFixed(x) - -static void -RRTransformRescale(struct pixman_f_transform *f_transform, double limit) -{ - double max = 0, v, scale; - int i, j; - - for (j = 0; j < 3; j++) - for (i = 0; i < 3; i++) - if ((v = abs (f_transform->m[j][i])) > max) - max = v; - scale = limit / max; - for (j = 0; j < 3; j++) - for (i = 0; i < 3; i++) - f_transform->m[j][i] *= scale; -} - -/* - * Compute the complete transformation matrix including - * client-specified transform, rotation/reflection values and the crtc - * offset. - * - * Return TRUE if the resulting transform is not a simple translation. - */ -Bool -RRTransformCompute (int x, - int y, - int width, - int height, - Rotation rotation, - RRTransformPtr rr_transform, - - PictTransformPtr transform, - struct pixman_f_transform *f_transform, - struct pixman_f_transform *f_inverse) -{ - PictTransform t_transform, inverse; - struct pixman_f_transform tf_transform, tf_inverse; - Bool overflow = FALSE; - - if (!transform) transform = &t_transform; - if (!f_transform) f_transform = &tf_transform; - if (!f_inverse) f_inverse = &tf_inverse; - - pixman_transform_init_identity (transform); - pixman_transform_init_identity (&inverse); - pixman_f_transform_init_identity (f_transform); - pixman_f_transform_init_identity (f_inverse); - if (rotation != RR_Rotate_0) - { - double f_rot_cos, f_rot_sin, f_rot_dx, f_rot_dy; - double f_scale_x, f_scale_y, f_scale_dx, f_scale_dy; - xFixed rot_cos, rot_sin, rot_dx, rot_dy; - xFixed scale_x, scale_y, scale_dx, scale_dy; - - /* rotation */ - switch (rotation & 0xf) { - default: - case RR_Rotate_0: - f_rot_cos = 1; f_rot_sin = 0; - f_rot_dx = 0; f_rot_dy = 0; - rot_cos = F ( 1); rot_sin = F ( 0); - rot_dx = F ( 0); rot_dy = F ( 0); - break; - case RR_Rotate_90: - f_rot_cos = 0; f_rot_sin = 1; - f_rot_dx = height-1; f_rot_dy = 0; - rot_cos = F ( 0); rot_sin = F ( 1); - rot_dx = F (height-1); rot_dy = F (0); - break; - case RR_Rotate_180: - f_rot_cos = -1; f_rot_sin = 0; - f_rot_dx = width - 1; f_rot_dy = height - 1; - rot_cos = F (-1); rot_sin = F ( 0); - rot_dx = F (width-1); rot_dy = F ( height-1); - break; - case RR_Rotate_270: - f_rot_cos = 0; f_rot_sin = -1; - f_rot_dx = 0; f_rot_dy = width-1; - rot_cos = F ( 0); rot_sin = F (-1); - rot_dx = F ( 0); rot_dy = F ( width-1); - break; - } - - pixman_transform_rotate (transform, &inverse, rot_cos, rot_sin); - pixman_transform_translate (transform, &inverse, rot_dx, rot_dy); - pixman_f_transform_rotate (f_transform, f_inverse, f_rot_cos, f_rot_sin); - pixman_f_transform_translate (f_transform, f_inverse, f_rot_dx, f_rot_dy); - - /* reflection */ - f_scale_x = 1; - f_scale_dx = 0; - f_scale_y = 1; - f_scale_dy = 0; - scale_x = F (1); - scale_dx = 0; - scale_y = F (1); - scale_dy = 0; - if (rotation & RR_Reflect_X) - { - f_scale_x = -1; - scale_x = F(-1); - if (rotation & (RR_Rotate_0|RR_Rotate_180)) { - f_scale_dx = width-1; - scale_dx = F(width-1); - } else { - f_scale_dx = height-1; - scale_dx = F(height-1); - } - } - if (rotation & RR_Reflect_Y) - { - f_scale_y = -1; - scale_y = F(-1); - if (rotation & (RR_Rotate_0|RR_Rotate_180)) { - f_scale_dy = height-1; - scale_dy = F(height-1); - } else { - f_scale_dy = width-1; - scale_dy = F(width-1); - } - } - - pixman_transform_scale (transform, &inverse, scale_x, scale_y); - pixman_f_transform_scale (f_transform, f_inverse, f_scale_x, f_scale_y); - pixman_transform_translate (transform, &inverse, scale_dx, scale_dy); - pixman_f_transform_translate (f_transform, f_inverse, f_scale_dx, f_scale_dy); - } - -#ifdef RANDR_12_INTERFACE - if (rr_transform) - { - if (!pixman_transform_multiply (transform, &rr_transform->transform, transform)) - overflow = TRUE; - pixman_f_transform_multiply (f_transform, &rr_transform->f_transform, f_transform); - pixman_f_transform_multiply (f_inverse, f_inverse, &rr_transform->f_inverse); - } -#endif - /* - * Compute the class of the resulting transform - */ - if (!overflow && pixman_transform_is_identity (transform)) - { - pixman_transform_init_translate (transform, F ( x), F ( y)); - - pixman_f_transform_init_translate (f_transform, x, y); - pixman_f_transform_init_translate (f_inverse, -x, -y); - return FALSE; - } - else - { - pixman_f_transform_translate (f_transform, f_inverse, x, y); - if (!pixman_transform_translate (transform, &inverse, F(x), F(y))) - overflow = TRUE; - if (overflow) - { - struct pixman_f_transform f_scaled; - f_scaled = *f_transform; - RRTransformRescale(&f_scaled, 16384.0); - pixman_transform_from_pixman_f_transform(transform, &f_scaled); - } - return TRUE; - } -} +/* + * Copyright © 2007 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "randrstr.h" +#include "rrtransform.h" + +void +RRTransformInit (RRTransformPtr transform) +{ + pixman_transform_init_identity (&transform->transform); + pixman_f_transform_init_identity (&transform->f_transform); + pixman_f_transform_init_identity (&transform->f_inverse); + transform->filter = NULL; + transform->params = NULL; + transform->nparams = 0; +} + +void +RRTransformFini (RRTransformPtr transform) +{ + if (transform->params) + free(transform->params); +} + +Bool +RRTransformEqual (RRTransformPtr a, RRTransformPtr b) +{ + if (a && pixman_transform_is_identity (&a->transform)) + a = NULL; + if (b && pixman_transform_is_identity (&b->transform)) + b = NULL; + if (a == NULL && b == NULL) + return TRUE; + if (a == NULL || b == NULL) + return FALSE; + if (memcmp (&a->transform, &b->transform, sizeof (a->transform)) != 0) + return FALSE; + if (a->filter != b->filter) + return FALSE; + if (a->nparams != b->nparams) + return FALSE; + if (memcmp (a->params, b->params, a->nparams * sizeof (xFixed)) != 0) + return FALSE; + return TRUE; +} + +Bool +RRTransformSetFilter (RRTransformPtr dst, + PictFilterPtr filter, + xFixed *params, + int nparams, + int width, + int height) +{ + xFixed *new_params; + + if (nparams) + { + new_params = malloc(nparams * sizeof (xFixed)); + if (!new_params) + return FALSE; + memcpy (new_params, params, nparams * sizeof (xFixed)); + } + else + new_params = NULL; + if (dst->params) + free(dst->params); + dst->filter = filter; + dst->params = new_params; + dst->nparams = nparams; + dst->width = width; + dst->height = height; + return TRUE; +} + +Bool +RRTransformCopy (RRTransformPtr dst, RRTransformPtr src) +{ + if (src && pixman_transform_is_identity (&src->transform)) + src = NULL; + + if (src) + { + if (!RRTransformSetFilter (dst, src->filter, + src->params, src->nparams, src->width, src->height)) + return FALSE; + dst->transform = src->transform; + dst->f_transform = src->f_transform; + dst->f_inverse = src->f_inverse; + } + else + { + if (!RRTransformSetFilter (dst, NULL, NULL, 0, 0, 0)) + return FALSE; + pixman_transform_init_identity (&dst->transform); + pixman_f_transform_init_identity (&dst->f_transform); + pixman_f_transform_init_identity (&dst->f_inverse); + } + return TRUE; +} + +#define F(x) IntToxFixed(x) + +static void +RRTransformRescale(struct pixman_f_transform *f_transform, double limit) +{ + double max = 0, v, scale; + int i, j; + + for (j = 0; j < 3; j++) + for (i = 0; i < 3; i++) + if ((v = abs (f_transform->m[j][i])) > max) + max = v; + scale = limit / max; + for (j = 0; j < 3; j++) + for (i = 0; i < 3; i++) + f_transform->m[j][i] *= scale; +} + +/* + * Compute the complete transformation matrix including + * client-specified transform, rotation/reflection values and the crtc + * offset. + * + * Return TRUE if the resulting transform is not a simple translation. + */ +Bool +RRTransformCompute (int x, + int y, + int width, + int height, + Rotation rotation, + RRTransformPtr rr_transform, + + PictTransformPtr transform, + struct pixman_f_transform *f_transform, + struct pixman_f_transform *f_inverse) +{ + PictTransform t_transform, inverse; + struct pixman_f_transform tf_transform, tf_inverse; + Bool overflow = FALSE; + + if (!transform) transform = &t_transform; + if (!f_transform) f_transform = &tf_transform; + if (!f_inverse) f_inverse = &tf_inverse; + + pixman_transform_init_identity (transform); + pixman_transform_init_identity (&inverse); + pixman_f_transform_init_identity (f_transform); + pixman_f_transform_init_identity (f_inverse); + if (rotation != RR_Rotate_0) + { + double f_rot_cos, f_rot_sin, f_rot_dx, f_rot_dy; + double f_scale_x, f_scale_y, f_scale_dx, f_scale_dy; + xFixed rot_cos, rot_sin, rot_dx, rot_dy; + xFixed scale_x, scale_y, scale_dx, scale_dy; + + /* rotation */ + switch (rotation & 0xf) { + default: + case RR_Rotate_0: + f_rot_cos = 1; f_rot_sin = 0; + f_rot_dx = 0; f_rot_dy = 0; + rot_cos = F ( 1); rot_sin = F ( 0); + rot_dx = F ( 0); rot_dy = F ( 0); + break; + case RR_Rotate_90: + f_rot_cos = 0; f_rot_sin = 1; + f_rot_dx = height-1; f_rot_dy = 0; + rot_cos = F ( 0); rot_sin = F ( 1); + rot_dx = F (height-1); rot_dy = F (0); + break; + case RR_Rotate_180: + f_rot_cos = -1; f_rot_sin = 0; + f_rot_dx = width - 1; f_rot_dy = height - 1; + rot_cos = F (-1); rot_sin = F ( 0); + rot_dx = F (width-1); rot_dy = F ( height-1); + break; + case RR_Rotate_270: + f_rot_cos = 0; f_rot_sin = -1; + f_rot_dx = 0; f_rot_dy = width-1; + rot_cos = F ( 0); rot_sin = F (-1); + rot_dx = F ( 0); rot_dy = F ( width-1); + break; + } + + pixman_transform_rotate (transform, &inverse, rot_cos, rot_sin); + pixman_transform_translate (transform, &inverse, rot_dx, rot_dy); + pixman_f_transform_rotate (f_transform, f_inverse, f_rot_cos, f_rot_sin); + pixman_f_transform_translate (f_transform, f_inverse, f_rot_dx, f_rot_dy); + + /* reflection */ + f_scale_x = 1; + f_scale_dx = 0; + f_scale_y = 1; + f_scale_dy = 0; + scale_x = F (1); + scale_dx = 0; + scale_y = F (1); + scale_dy = 0; + if (rotation & RR_Reflect_X) + { + f_scale_x = -1; + scale_x = F(-1); + if (rotation & (RR_Rotate_0|RR_Rotate_180)) { + f_scale_dx = width-1; + scale_dx = F(width-1); + } else { + f_scale_dx = height-1; + scale_dx = F(height-1); + } + } + if (rotation & RR_Reflect_Y) + { + f_scale_y = -1; + scale_y = F(-1); + if (rotation & (RR_Rotate_0|RR_Rotate_180)) { + f_scale_dy = height-1; + scale_dy = F(height-1); + } else { + f_scale_dy = width-1; + scale_dy = F(width-1); + } + } + + pixman_transform_scale (transform, &inverse, scale_x, scale_y); + pixman_f_transform_scale (f_transform, f_inverse, f_scale_x, f_scale_y); + pixman_transform_translate (transform, &inverse, scale_dx, scale_dy); + pixman_f_transform_translate (f_transform, f_inverse, f_scale_dx, f_scale_dy); + } + +#ifdef RANDR_12_INTERFACE + if (rr_transform) + { + if (!pixman_transform_multiply (transform, &rr_transform->transform, transform)) + overflow = TRUE; + pixman_f_transform_multiply (f_transform, &rr_transform->f_transform, f_transform); + pixman_f_transform_multiply (f_inverse, f_inverse, &rr_transform->f_inverse); + } +#endif + /* + * Compute the class of the resulting transform + */ + if (!overflow && pixman_transform_is_identity (transform)) + { + pixman_transform_init_translate (transform, F ( x), F ( y)); + + pixman_f_transform_init_translate (f_transform, x, y); + pixman_f_transform_init_translate (f_inverse, -x, -y); + return FALSE; + } + else + { + pixman_f_transform_translate (f_transform, f_inverse, x, y); + if (!pixman_transform_translate (transform, &inverse, F(x), F(y))) + overflow = TRUE; + if (overflow) + { + struct pixman_f_transform f_scaled; + f_scaled = *f_transform; + RRTransformRescale(&f_scaled, 16384.0); + pixman_transform_from_pixman_f_transform(transform, &f_scaled); + } + return TRUE; + } +} diff --git a/xorg-server/randr/rrxinerama.c b/xorg-server/randr/rrxinerama.c index 94c8e54e5..374789374 100644 --- a/xorg-server/randr/rrxinerama.c +++ b/xorg-server/randr/rrxinerama.c @@ -1,476 +1,476 @@ -/* - * Copyright © 2006 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 the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS 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 Xinerama implementation comes from the SiS driver which has - * the following notice: - */ -/* - * SiS driver main code - * - * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1) Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3) The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Thomas Winischhofer <thomas@winischhofer.net> - * - driver entirely rewritten since 2001, only basic structure taken from - * old code (except sis_dri.c, sis_shadow.c, sis_accel.c and parts of - * sis_dga.c; these were mostly taken over; sis_dri.c was changed for - * new versions of the DRI layer) - * - * This notice covers the entire driver code unless indicated otherwise. - * - * Formerly based on code which was - * Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England. - * Written by: - * Alan Hourihane <alanh@fairlite.demon.co.uk>, - * Mike Chapman <mike@paranoia.com>, - * Juanjo Santamarta <santamarta@ctv.es>, - * Mitani Hiroshi <hmitani@drl.mei.co.jp>, - * David Thomas <davtom@dream.org.uk>. - */ - -#include "randrstr.h" -#include "swaprep.h" -#include <X11/extensions/panoramiXproto.h> -#include "protocol-versions.h" - -/* Xinerama is not multi-screen capable; just report about screen 0 */ -#define RR_XINERAMA_SCREEN 0 - -static int ProcRRXineramaQueryVersion(ClientPtr client); -static int ProcRRXineramaGetState(ClientPtr client); -static int ProcRRXineramaGetScreenCount(ClientPtr client); -static int ProcRRXineramaGetScreenSize(ClientPtr client); -static int ProcRRXineramaIsActive(ClientPtr client); -static int ProcRRXineramaQueryScreens(ClientPtr client); -static int SProcRRXineramaDispatch(ClientPtr client); - -/* Proc */ - -int -ProcRRXineramaQueryVersion(ClientPtr client) -{ - xPanoramiXQueryVersionReply rep; - register int n; - - REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_RRXINERAMA_MAJOR_VERSION; - rep.minorVersion = SERVER_RRXINERAMA_MINOR_VERSION; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -int -ProcRRXineramaGetState(ClientPtr client) -{ - REQUEST(xPanoramiXGetStateReq); - WindowPtr pWin; - xPanoramiXGetStateReply rep; - register int n, rc; - ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - Bool active = FALSE; - - REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if(rc != Success) - return rc; - - pScreen = pWin->drawable.pScreen; - pScrPriv = rrGetScrPriv(pScreen); - if (pScrPriv) - { - /* XXX do we need more than this? */ - active = TRUE; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.state = active; - rep.window = stuff->window; - if(client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swapl (&rep.window, n); - } - WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep); - return client->noClientException; -} - -static Bool -RRXineramaCrtcActive (RRCrtcPtr crtc) -{ - return crtc->mode != NULL && crtc->numOutputs > 0; -} - -static int -RRXineramaScreenCount (ScreenPtr pScreen) -{ - int i, n; - - n = 0; - if (rrGetScrPriv (pScreen)) - { - rrScrPriv(pScreen); - for (i = 0; i < pScrPriv->numCrtcs; i++) - if (RRXineramaCrtcActive (pScrPriv->crtcs[i])) - n++; - } - return n; -} - -static Bool -RRXineramaScreenActive (ScreenPtr pScreen) -{ - return RRXineramaScreenCount (pScreen) > 0; -} - -int -ProcRRXineramaGetScreenCount(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenCountReq); - WindowPtr pWin; - xPanoramiXGetScreenCountReply rep; - register int n, rc; - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.ScreenCount = RRXineramaScreenCount (pWin->drawable.pScreen); - rep.window = stuff->window; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.window, n); - } - WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); - return client->noClientException; -} - -int -ProcRRXineramaGetScreenSize(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenSizeReq); - WindowPtr pWin, pRoot; - ScreenPtr pScreen; - xPanoramiXGetScreenSizeReply rep; - register int n, rc; - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - pScreen = pWin->drawable.pScreen; - pRoot = WindowTable[pScreen->myNum]; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.width = pRoot->drawable.width; - rep.height = pRoot->drawable.height; - rep.window = stuff->window; - rep.screen = stuff->screen; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.width, n); - swapl(&rep.height, n); - swapl(&rep.window, n); - swapl(&rep.screen, n); - } - WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); - return client->noClientException; -} - -int -ProcRRXineramaIsActive(ClientPtr client) -{ - xXineramaIsActiveReply rep; - - REQUEST_SIZE_MATCH(xXineramaIsActiveReq); - - memset(&rep, 0, sizeof(xXineramaIsActiveReply)); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.state = RRXineramaScreenActive (screenInfo.screens[RR_XINERAMA_SCREEN]); - if(client->swapped) { - register int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.state, n); - } - WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep); - return client->noClientException; -} - -static void -RRXineramaWriteCrtc(ClientPtr client, RRCrtcPtr crtc) -{ - xXineramaScreenInfo scratch; - - if (RRXineramaCrtcActive (crtc)) - { - ScreenPtr pScreen = crtc->pScreen; - rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen); - BoxRec panned_area; - - /* Check to see if crtc is panned and return the full area when applicable. */ - if (pScrPriv && pScrPriv->rrGetPanning && - pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) && - (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) { - scratch.x_org = panned_area.x1; - scratch.y_org = panned_area.y1; - scratch.width = panned_area.x2 - panned_area.x1; - scratch.height = panned_area.y2 - panned_area.y1; - } else { - int width, height; - RRCrtcGetScanoutSize (crtc, &width, &height); - scratch.x_org = crtc->x; - scratch.y_org = crtc->y; - scratch.width = width; - scratch.height = height; - } - if(client->swapped) { - register int n; - swaps(&scratch.x_org, n); - swaps(&scratch.y_org, n); - swaps(&scratch.width, n); - swaps(&scratch.height, n); - } - WriteToClient(client, sz_XineramaScreenInfo, &scratch); - } -} - -int -ProcRRXineramaQueryScreens(ClientPtr client) -{ - xXineramaQueryScreensReply rep; - ScreenPtr pScreen = screenInfo.screens[RR_XINERAMA_SCREEN]; - - REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); - - if (RRXineramaScreenActive (pScreen)) - RRGetInfo (pScreen, FALSE); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.number = RRXineramaScreenCount (pScreen); - rep.length = bytes_to_int32(rep.number * sz_XineramaScreenInfo); - if(client->swapped) { - register int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.number, n); - } - WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep); - - if(rep.number) { - rrScrPriv(pScreen); - int i; - int has_primary = 0; - - if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) { - has_primary = 1; - RRXineramaWriteCrtc(client, pScrPriv->primaryOutput->crtc); - } - - for(i = 0; i < pScrPriv->numCrtcs; i++) { - if (has_primary && - pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) - { - has_primary = 0; - continue; - } - RRXineramaWriteCrtc(client, pScrPriv->crtcs[i]); - } - } - - return client->noClientException; -} - -static int -ProcRRXineramaDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_PanoramiXQueryVersion: - return ProcRRXineramaQueryVersion(client); - case X_PanoramiXGetState: - return ProcRRXineramaGetState(client); - case X_PanoramiXGetScreenCount: - return ProcRRXineramaGetScreenCount(client); - case X_PanoramiXGetScreenSize: - return ProcRRXineramaGetScreenSize(client); - case X_XineramaIsActive: - return ProcRRXineramaIsActive(client); - case X_XineramaQueryScreens: - return ProcRRXineramaQueryScreens(client); - } - return BadRequest; -} - -/* SProc */ - -static int -SProcRRXineramaQueryVersion (ClientPtr client) -{ - REQUEST(xPanoramiXQueryVersionReq); - register int n; - swaps(&stuff->length,n); - REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); - return ProcRRXineramaQueryVersion(client); -} - -static int -SProcRRXineramaGetState(ClientPtr client) -{ - REQUEST(xPanoramiXGetStateReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); - swapl (&stuff->window, n); - return ProcRRXineramaGetState(client); -} - -static int -SProcRRXineramaGetScreenCount(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenCountReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); - swapl (&stuff->window, n); - return ProcRRXineramaGetScreenCount(client); -} - -static int -SProcRRXineramaGetScreenSize(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenSizeReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); - swapl (&stuff->window, n); - swapl (&stuff->screen, n); - return ProcRRXineramaGetScreenSize(client); -} - -static int -SProcRRXineramaIsActive(ClientPtr client) -{ - REQUEST(xXineramaIsActiveReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXineramaIsActiveReq); - return ProcRRXineramaIsActive(client); -} - -static int -SProcRRXineramaQueryScreens(ClientPtr client) -{ - REQUEST(xXineramaQueryScreensReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); - return ProcRRXineramaQueryScreens(client); -} - -int -SProcRRXineramaDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_PanoramiXQueryVersion: - return SProcRRXineramaQueryVersion(client); - case X_PanoramiXGetState: - return SProcRRXineramaGetState(client); - case X_PanoramiXGetScreenCount: - return SProcRRXineramaGetScreenCount(client); - case X_PanoramiXGetScreenSize: - return SProcRRXineramaGetScreenSize(client); - case X_XineramaIsActive: - return SProcRRXineramaIsActive(client); - case X_XineramaQueryScreens: - return SProcRRXineramaQueryScreens(client); - } - return BadRequest; -} - -void -RRXineramaExtensionInit(void) -{ -#ifdef PANORAMIX - if(!noPanoramiXExtension) - return; -#endif - - /* - * Xinerama isn't capable enough to have multiple protocol screens each - * with their own output geometry. So if there's more than one protocol - * screen, just don't even try. - */ - if (screenInfo.numScreens > 1) - return; - - (void) AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, - ProcRRXineramaDispatch, - SProcRRXineramaDispatch, - NULL, - StandardMinorOpcode); -} +/* + * Copyright © 2006 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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 Xinerama implementation comes from the SiS driver which has + * the following notice: + */ +/* + * SiS driver main code + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1) Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2) Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3) The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * - driver entirely rewritten since 2001, only basic structure taken from + * old code (except sis_dri.c, sis_shadow.c, sis_accel.c and parts of + * sis_dga.c; these were mostly taken over; sis_dri.c was changed for + * new versions of the DRI layer) + * + * This notice covers the entire driver code unless indicated otherwise. + * + * Formerly based on code which was + * Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England. + * Written by: + * Alan Hourihane <alanh@fairlite.demon.co.uk>, + * Mike Chapman <mike@paranoia.com>, + * Juanjo Santamarta <santamarta@ctv.es>, + * Mitani Hiroshi <hmitani@drl.mei.co.jp>, + * David Thomas <davtom@dream.org.uk>. + */ + +#include "randrstr.h" +#include "swaprep.h" +#include <X11/extensions/panoramiXproto.h> +#include "protocol-versions.h" + +/* Xinerama is not multi-screen capable; just report about screen 0 */ +#define RR_XINERAMA_SCREEN 0 + +static int ProcRRXineramaQueryVersion(ClientPtr client); +static int ProcRRXineramaGetState(ClientPtr client); +static int ProcRRXineramaGetScreenCount(ClientPtr client); +static int ProcRRXineramaGetScreenSize(ClientPtr client); +static int ProcRRXineramaIsActive(ClientPtr client); +static int ProcRRXineramaQueryScreens(ClientPtr client); +static int SProcRRXineramaDispatch(ClientPtr client); + +/* Proc */ + +int +ProcRRXineramaQueryVersion(ClientPtr client) +{ + xPanoramiXQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_RRXINERAMA_MAJOR_VERSION; + rep.minorVersion = SERVER_RRXINERAMA_MINOR_VERSION; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep); + return Success; +} + +int +ProcRRXineramaGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + WindowPtr pWin; + xPanoramiXGetStateReply rep; + register int n, rc; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + Bool active = FALSE; + + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if(rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + pScrPriv = rrGetScrPriv(pScreen); + if (pScrPriv) + { + /* XXX do we need more than this? */ + active = TRUE; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = active; + rep.window = stuff->window; + if(client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.window, n); + } + WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep); + return Success; +} + +static Bool +RRXineramaCrtcActive (RRCrtcPtr crtc) +{ + return crtc->mode != NULL && crtc->numOutputs > 0; +} + +static int +RRXineramaScreenCount (ScreenPtr pScreen) +{ + int i, n; + + n = 0; + if (rrGetScrPriv (pScreen)) + { + rrScrPriv(pScreen); + for (i = 0; i < pScrPriv->numCrtcs; i++) + if (RRXineramaCrtcActive (pScrPriv->crtcs[i])) + n++; + } + return n; +} + +static Bool +RRXineramaScreenActive (ScreenPtr pScreen) +{ + return RRXineramaScreenCount (pScreen) > 0; +} + +int +ProcRRXineramaGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + WindowPtr pWin; + xPanoramiXGetScreenCountReply rep; + register int n, rc; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.ScreenCount = RRXineramaScreenCount (pWin->drawable.pScreen); + rep.window = stuff->window; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.window, n); + } + WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); + return Success; +} + +int +ProcRRXineramaGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + WindowPtr pWin, pRoot; + ScreenPtr pScreen; + xPanoramiXGetScreenSizeReply rep; + register int n, rc; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + pRoot = WindowTable[pScreen->myNum]; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.width = pRoot->drawable.width; + rep.height = pRoot->drawable.height; + rep.window = stuff->window; + rep.screen = stuff->screen; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.width, n); + swapl(&rep.height, n); + swapl(&rep.window, n); + swapl(&rep.screen, n); + } + WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); + return Success; +} + +int +ProcRRXineramaIsActive(ClientPtr client) +{ + xXineramaIsActiveReply rep; + + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + + memset(&rep, 0, sizeof(xXineramaIsActiveReply)); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = RRXineramaScreenActive (screenInfo.screens[RR_XINERAMA_SCREEN]); + if(client->swapped) { + register int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.state, n); + } + WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep); + return Success; +} + +static void +RRXineramaWriteCrtc(ClientPtr client, RRCrtcPtr crtc) +{ + xXineramaScreenInfo scratch; + + if (RRXineramaCrtcActive (crtc)) + { + ScreenPtr pScreen = crtc->pScreen; + rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen); + BoxRec panned_area; + + /* Check to see if crtc is panned and return the full area when applicable. */ + if (pScrPriv && pScrPriv->rrGetPanning && + pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) && + (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) { + scratch.x_org = panned_area.x1; + scratch.y_org = panned_area.y1; + scratch.width = panned_area.x2 - panned_area.x1; + scratch.height = panned_area.y2 - panned_area.y1; + } else { + int width, height; + RRCrtcGetScanoutSize (crtc, &width, &height); + scratch.x_org = crtc->x; + scratch.y_org = crtc->y; + scratch.width = width; + scratch.height = height; + } + if(client->swapped) { + register int n; + swaps(&scratch.x_org, n); + swaps(&scratch.y_org, n); + swaps(&scratch.width, n); + swaps(&scratch.height, n); + } + WriteToClient(client, sz_XineramaScreenInfo, &scratch); + } +} + +int +ProcRRXineramaQueryScreens(ClientPtr client) +{ + xXineramaQueryScreensReply rep; + ScreenPtr pScreen = screenInfo.screens[RR_XINERAMA_SCREEN]; + + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + + if (RRXineramaScreenActive (pScreen)) + RRGetInfo (pScreen, FALSE); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.number = RRXineramaScreenCount (pScreen); + rep.length = bytes_to_int32(rep.number * sz_XineramaScreenInfo); + if(client->swapped) { + register int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.number, n); + } + WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep); + + if(rep.number) { + rrScrPriv(pScreen); + int i; + int has_primary = 0; + + if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) { + has_primary = 1; + RRXineramaWriteCrtc(client, pScrPriv->primaryOutput->crtc); + } + + for(i = 0; i < pScrPriv->numCrtcs; i++) { + if (has_primary && + pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) + { + has_primary = 0; + continue; + } + RRXineramaWriteCrtc(client, pScrPriv->crtcs[i]); + } + } + + return Success; +} + +static int +ProcRRXineramaDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_PanoramiXQueryVersion: + return ProcRRXineramaQueryVersion(client); + case X_PanoramiXGetState: + return ProcRRXineramaGetState(client); + case X_PanoramiXGetScreenCount: + return ProcRRXineramaGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return ProcRRXineramaGetScreenSize(client); + case X_XineramaIsActive: + return ProcRRXineramaIsActive(client); + case X_XineramaQueryScreens: + return ProcRRXineramaQueryScreens(client); + } + return BadRequest; +} + +/* SProc */ + +static int +SProcRRXineramaQueryVersion (ClientPtr client) +{ + REQUEST(xPanoramiXQueryVersionReq); + register int n; + swaps(&stuff->length,n); + REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); + return ProcRRXineramaQueryVersion(client); +} + +static int +SProcRRXineramaGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + swapl (&stuff->window, n); + return ProcRRXineramaGetState(client); +} + +static int +SProcRRXineramaGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + swapl (&stuff->window, n); + return ProcRRXineramaGetScreenCount(client); +} + +static int +SProcRRXineramaGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + swapl (&stuff->window, n); + swapl (&stuff->screen, n); + return ProcRRXineramaGetScreenSize(client); +} + +static int +SProcRRXineramaIsActive(ClientPtr client) +{ + REQUEST(xXineramaIsActiveReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + return ProcRRXineramaIsActive(client); +} + +static int +SProcRRXineramaQueryScreens(ClientPtr client) +{ + REQUEST(xXineramaQueryScreensReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + return ProcRRXineramaQueryScreens(client); +} + +int +SProcRRXineramaDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_PanoramiXQueryVersion: + return SProcRRXineramaQueryVersion(client); + case X_PanoramiXGetState: + return SProcRRXineramaGetState(client); + case X_PanoramiXGetScreenCount: + return SProcRRXineramaGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return SProcRRXineramaGetScreenSize(client); + case X_XineramaIsActive: + return SProcRRXineramaIsActive(client); + case X_XineramaQueryScreens: + return SProcRRXineramaQueryScreens(client); + } + return BadRequest; +} + +void +RRXineramaExtensionInit(void) +{ +#ifdef PANORAMIX + if(!noPanoramiXExtension) + return; +#endif + + /* + * Xinerama isn't capable enough to have multiple protocol screens each + * with their own output geometry. So if there's more than one protocol + * screen, just don't even try. + */ + if (screenInfo.numScreens > 1) + return; + + (void) AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, + ProcRRXineramaDispatch, + SProcRRXineramaDispatch, + NULL, + StandardMinorOpcode); +} diff --git a/xorg-server/record/record.c b/xorg-server/record/record.c index 1a10c9edc..f79a5a889 100644 --- a/xorg-server/record/record.c +++ b/xorg-server/record/record.c @@ -1,2917 +1,2917 @@ - -/* - -Copyright 1995, 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: David P. Wiggins, The Open Group - -This work benefited from earlier work done by Martha Zimet of NCD -and Jim Haggerty of Metheus. - -*/ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "dixstruct.h" -#include "extnsionst.h" -#include <X11/extensions/recordproto.h> -#include "set.h" -#include "swaprep.h" -#include "inputstr.h" -#include "eventconvert.h" - - -#include <stdio.h> -#include <assert.h> - -#ifdef PANORAMIX -#include "globals.h" -#include "panoramiX.h" -#include "panoramiXsrv.h" -#include "cursor.h" -#endif - -#include "protocol-versions.h" - -static RESTYPE RTContext; /* internal resource type for Record contexts */ -static int RecordErrorBase; /* first Record error number */ - -/* How many bytes of protocol data to buffer in a context. Don't set to less - * than 32. - */ -#define REPLY_BUF_SIZE 1024 - -/* Record Context structure */ - -typedef struct { - XID id; /* resource id of context */ - ClientPtr pRecordingClient; /* client that has context enabled */ - struct _RecordClientsAndProtocolRec *pListOfRCAP; /* all registered info */ - ClientPtr pBufClient; /* client whose protocol is in replyBuffer*/ - unsigned int continuedReply:1; /* recording a reply that is split up? */ - char elemHeaders; /* element header flags (time/seq no.) */ - char bufCategory; /* category of protocol in replyBuffer */ - int numBufBytes; /* number of bytes in replyBuffer */ - char replyBuffer[REPLY_BUF_SIZE]; /* buffered recorded protocol */ -} RecordContextRec, *RecordContextPtr; - -/* RecordMinorOpRec - to hold minor opcode selections for extension requests - * and replies - */ - -typedef union { - int count; /* first element of array: how many "major" structs to follow */ - struct { /* rest of array elements are this */ - short first; /* first major opcode */ - short last; /* last major opcode */ - RecordSetPtr pMinOpSet; /* minor opcode set for above major range */ - } major; -} RecordMinorOpRec, *RecordMinorOpPtr; - - -/* RecordClientsAndProtocolRec, nicknamed RCAP - holds all the client and - * protocol selections passed in a single CreateContext or RegisterClients. - * Generally, a context will have one of these from the create and an - * additional one for each RegisterClients. RCAPs are freed when all their - * clients are unregistered. - */ - -typedef struct _RecordClientsAndProtocolRec { - RecordContextPtr pContext; /* context that owns this RCAP */ - struct _RecordClientsAndProtocolRec *pNextRCAP; /* next RCAP on context */ - RecordSetPtr pRequestMajorOpSet; /* requests to record */ - RecordMinorOpPtr pRequestMinOpInfo; /* extension requests to record */ - RecordSetPtr pReplyMajorOpSet; /* replies to record */ - RecordMinorOpPtr pReplyMinOpInfo; /* extension replies to record */ - RecordSetPtr pDeviceEventSet; /* device events to record */ - RecordSetPtr pDeliveredEventSet; /* delivered events to record */ - RecordSetPtr pErrorSet; /* errors to record */ - XID * pClientIDs; /* array of clients to record */ - short numClients; /* number of clients in pClientIDs */ - short sizeClients; /* size of pClientIDs array */ - unsigned int clientStarted:1; /* record new client connections? */ - unsigned int clientDied:1; /* record client disconnections? */ - unsigned int clientIDsSeparatelyAllocated:1; /* pClientIDs malloced? */ -} RecordClientsAndProtocolRec, *RecordClientsAndProtocolPtr; - -/* how much bigger to make pRCAP->pClientIDs when reallocing */ -#define CLIENT_ARRAY_GROWTH_INCREMENT 4 - -/* counts the total number of RCAPs belonging to enabled contexts. */ -static int numEnabledRCAPs; - -/* void VERIFY_CONTEXT(RecordContextPtr, XID, ClientPtr) - * In the spirit of the VERIFY_* macros in dix.h, this macro fills in - * the context pointer if the given ID is a valid Record Context, else it - * returns an error. - */ -#define VERIFY_CONTEXT(_pContext, _contextid, _client) { \ - int rc = dixLookupResourceByType((pointer *)&(_pContext), _contextid, \ - RTContext, _client, DixUseAccess); \ - if (rc != Success) \ - return (rc == BadValue) ? RecordErrorBase + XRecordBadContext : rc; \ -} - -static int RecordDeleteContext( - pointer /*value*/, - XID /*id*/ -); - -void RecordExtensionInit(void); - -/***************************************************************************/ - -/* client private stuff */ - -/* To make declarations less obfuscated, have a typedef for a pointer to a - * Proc function. - */ -typedef int (*ProcFunctionPtr)( - ClientPtr /*pClient*/ -); - -/* Record client private. Generally a client only has one of these if - * any of its requests are being recorded. - */ -typedef struct { -/* ptr to client's proc vector before Record stuck its nose in */ - ProcFunctionPtr *originalVector; - -/* proc vector with pointers for recorded requests redirected to the - * function RecordARequest - */ - ProcFunctionPtr recordVector[256]; -} RecordClientPrivateRec, *RecordClientPrivatePtr; - -static int RecordClientPrivateKeyIndex; -static DevPrivateKey RecordClientPrivateKey = &RecordClientPrivateKeyIndex; - -/* RecordClientPrivatePtr RecordClientPrivate(ClientPtr) - * gets the client private of the given client. Syntactic sugar. - */ -#define RecordClientPrivate(_pClient) (RecordClientPrivatePtr) \ - dixLookupPrivate(&(_pClient)->devPrivates, RecordClientPrivateKey) - - -/***************************************************************************/ - -/* global list of all contexts */ - -static RecordContextPtr *ppAllContexts; - -static int numContexts;/* number of contexts in ppAllContexts */ - -/* number of currently enabled contexts. All enabled contexts are bunched - * up at the front of the ppAllContexts array, from ppAllContexts[0] to - * ppAllContexts[numEnabledContexts-1], to eliminate time spent skipping - * past disabled contexts. - */ -static int numEnabledContexts; - -/* RecordFindContextOnAllContexts - * - * Arguments: - * pContext is the context to search for. - * - * Returns: - * The index into the array ppAllContexts at which pContext is stored. - * If pContext is not found in ppAllContexts, returns -1. - * - * Side Effects: none. - */ -static int -RecordFindContextOnAllContexts(RecordContextPtr pContext) -{ - int i; - - assert(numContexts >= numEnabledContexts); - for (i = 0; i < numContexts; i++) - { - if (ppAllContexts[i] == pContext) - return i; - } - return -1; -} /* RecordFindContextOnAllContexts */ - - -/***************************************************************************/ - -/* RecordFlushReplyBuffer - * - * Arguments: - * pContext is the context to flush. - * data1 is a pointer to additional data, and len1 is its length in bytes. - * data2 is a pointer to additional data, and len2 is its length in bytes. - * - * Returns: nothing. - * - * Side Effects: - * If the context is enabled, any buffered (recorded) protocol is written - * to the recording client, and the number of buffered bytes is set to - * zero. If len1 is not zero, data1/len1 are then written to the - * recording client, and similarly for data2/len2 (written after - * data1/len1). - */ -static void -RecordFlushReplyBuffer( - RecordContextPtr pContext, - pointer data1, - int len1, - pointer data2, - int len2 -) -{ - if (!pContext->pRecordingClient || pContext->pRecordingClient->clientGone) - return; - if (pContext->numBufBytes) - WriteToClient(pContext->pRecordingClient, pContext->numBufBytes, - (char *)pContext->replyBuffer); - pContext->numBufBytes = 0; - if (len1) - WriteToClient(pContext->pRecordingClient, len1, (char *)data1); - if (len2) - WriteToClient(pContext->pRecordingClient, len2, (char *)data2); -} /* RecordFlushReplyBuffer */ - - -/* RecordAProtocolElement - * - * Arguments: - * pContext is the context that is recording a protocol element. - * pClient is the client whose protocol is being recorded. For - * device events and EndOfData, pClient is NULL. - * category is the category of the protocol element, as defined - * by the RECORD spec. - * data is a pointer to the protocol data, and datalen is its length - * in bytes. - * futurelen is the number of bytes that will be sent in subsequent - * calls to this function to complete this protocol element. - * In those subsequent calls, futurelen will be -1 to indicate - * that the current data is a continuation of the same protocol - * element. - * - * Returns: nothing. - * - * Side Effects: - * The context may be flushed. The new protocol element will be - * added to the context's protocol buffer with appropriate element - * headers prepended (sequence number and timestamp). If the data - * is continuation data (futurelen == -1), element headers won't - * be added. If the protocol element and headers won't fit in - * the context's buffer, it is sent directly to the recording - * client (after any buffered data). - */ -static void -RecordAProtocolElement(RecordContextPtr pContext, ClientPtr pClient, - int category, pointer data, int datalen, int futurelen) -{ - CARD32 elemHeaderData[2]; - int numElemHeaders = 0; - Bool recordingClientSwapped = pContext->pRecordingClient->swapped; - int n; - CARD32 serverTime = 0; - Bool gotServerTime = FALSE; - int replylen; - - if (futurelen >= 0) - { /* start of new protocol element */ - xRecordEnableContextReply *pRep = (xRecordEnableContextReply *) - pContext->replyBuffer; - if (pContext->pBufClient != pClient || - pContext->bufCategory != category) - { - RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0); - pContext->pBufClient = pClient; - pContext->bufCategory = category; - } - - if (!pContext->numBufBytes) - { - serverTime = GetTimeInMillis(); - gotServerTime = TRUE; - pRep->type = X_Reply; - pRep->category = category; - pRep->sequenceNumber = pContext->pRecordingClient->sequence; - pRep->length = 0; - pRep->elementHeader = pContext->elemHeaders; - pRep->serverTime = serverTime; - if (pClient) - { - pRep->clientSwapped = - (pClient->swapped != recordingClientSwapped); - pRep->idBase = pClient->clientAsMask; - pRep->recordedSequenceNumber = pClient->sequence; - } - else /* it's a device event, StartOfData, or EndOfData */ - { - pRep->clientSwapped = (category != XRecordFromServer) && - recordingClientSwapped; - pRep->idBase = 0; - pRep->recordedSequenceNumber = 0; - } - - if (recordingClientSwapped) - { - swaps(&pRep->sequenceNumber, n); - swapl(&pRep->length, n); - swapl(&pRep->idBase, n); - swapl(&pRep->serverTime, n); - swapl(&pRep->recordedSequenceNumber, n); - } - pContext->numBufBytes = SIZEOF(xRecordEnableContextReply); - } - - /* generate element headers if needed */ - - if ( ( (pContext->elemHeaders & XRecordFromClientTime) - && category == XRecordFromClient) - || - ( (pContext->elemHeaders & XRecordFromServerTime) - && category == XRecordFromServer)) - { - if (gotServerTime) - elemHeaderData[numElemHeaders] = serverTime; - else - elemHeaderData[numElemHeaders] = GetTimeInMillis(); - if (recordingClientSwapped) - swapl(&elemHeaderData[numElemHeaders], n); - numElemHeaders++; - } - - if ( (pContext->elemHeaders & XRecordFromClientSequence) - && - (category == XRecordFromClient || category == XRecordClientDied)) - { - elemHeaderData[numElemHeaders] = pClient->sequence; - if (recordingClientSwapped) - swapl(&elemHeaderData[numElemHeaders], n); - numElemHeaders++; - } - - /* adjust reply length */ - - replylen = pRep->length; - if (recordingClientSwapped) swapl(&replylen, n); - replylen += numElemHeaders + bytes_to_int32(datalen) + - bytes_to_int32(futurelen); - if (recordingClientSwapped) swapl(&replylen, n); - pRep->length = replylen; - } /* end if not continued reply */ - - numElemHeaders *= 4; - - /* if space available >= space needed, buffer the data */ - - if (REPLY_BUF_SIZE - pContext->numBufBytes >= datalen + numElemHeaders) - { - if (numElemHeaders) - { - memcpy(pContext->replyBuffer + pContext->numBufBytes, - elemHeaderData, numElemHeaders); - pContext->numBufBytes += numElemHeaders; - } - if (datalen) - { - memcpy(pContext->replyBuffer + pContext->numBufBytes, - data, datalen); - pContext->numBufBytes += datalen; - } - } - else - RecordFlushReplyBuffer(pContext, (pointer)elemHeaderData, - numElemHeaders, (pointer)data, datalen); - -} /* RecordAProtocolElement */ - - -/* RecordFindClientOnContext - * - * Arguments: - * pContext is the context to search. - * clientspec is the resource ID mask identifying the client to search - * for, or XRecordFutureClients. - * pposition is a pointer to an int, or NULL. See Returns. - * - * Returns: - * The RCAP on which clientspec was found, or NULL if not found on - * any RCAP on the given context. - * If pposition was not NULL and the returned RCAP is not NULL, - * *pposition will be set to the index into the returned the RCAP's - * pClientIDs array that holds clientspec. - * - * Side Effects: none. - */ -static RecordClientsAndProtocolPtr -RecordFindClientOnContext( - RecordContextPtr pContext, - XID clientspec, - int *pposition -) -{ - RecordClientsAndProtocolPtr pRCAP; - - for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) - { - int i; - for (i = 0; i < pRCAP->numClients; i++) - { - if (pRCAP->pClientIDs[i] == clientspec) - { - if (pposition) - *pposition = i; - return pRCAP; - } - } - } - return NULL; -} /* RecordFindClientOnContext */ - - -/* RecordABigRequest - * - * Arguments: - * pContext is the recording context. - * client is the client being recorded. - * stuff is a pointer to the big request of client (see the Big Requests - * extension for details.) - * - * Returns: nothing. - * - * Side Effects: - * The big request is recorded with the correct length field re-inserted. - * - * Note: this function exists mainly to make RecordARequest smaller. - */ -static void -RecordABigRequest(RecordContextPtr pContext, ClientPtr client, xReq *stuff) -{ - CARD32 bigLength; - char n; - int bytesLeft; - - /* note: client->req_len has been frobbed by ReadRequestFromClient - * (os/io.c) to discount the extra 4 bytes taken by the extended length - * field in a big request. The actual request length to record is - * client->req_len + 1 (measured in CARD32s). - */ - - /* record the request header */ - bytesLeft = client->req_len << 2; - RecordAProtocolElement(pContext, client, XRecordFromClient, - (pointer)stuff, SIZEOF(xReq), bytesLeft); - - /* reinsert the extended length field that was squished out */ - bigLength = client->req_len + bytes_to_int32(sizeof(bigLength)); - if (client->swapped) - swapl(&bigLength, n); - RecordAProtocolElement(pContext, client, XRecordFromClient, - (pointer)&bigLength, sizeof(bigLength), /* continuation */ -1); - bytesLeft -= sizeof(bigLength); - - /* record the rest of the request after the length */ - RecordAProtocolElement(pContext, client, XRecordFromClient, - (pointer)(stuff + 1), bytesLeft, /* continuation */ -1); -} /* RecordABigRequest */ - - -/* RecordARequest - * - * Arguments: - * client is a client that the server has dispatched a request to by - * calling client->requestVector[request opcode] . - * The request is in client->requestBuffer. - * - * Returns: - * Whatever is returned by the "real" Proc function for this request. - * The "real" Proc function is the function that was in - * client->requestVector[request opcode] before it was replaced by - * RecordARequest. (See the function RecordInstallHooks.) - * - * Side Effects: - * The request is recorded by all contexts that have registered this - * request for this client. The real Proc function is called. - */ -static int -RecordARequest(ClientPtr client) -{ - RecordContextPtr pContext; - RecordClientsAndProtocolPtr pRCAP; - int i; - RecordClientPrivatePtr pClientPriv; - REQUEST(xReq); - int majorop; - - majorop = stuff->reqType; - for (i = 0; i < numEnabledContexts; i++) - { - pContext = ppAllContexts[i]; - pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask, - NULL); - if (pRCAP && pRCAP->pRequestMajorOpSet && - RecordIsMemberOfSet(pRCAP->pRequestMajorOpSet, majorop)) - { - if (majorop <= 127) - { /* core request */ - - if (stuff->length == 0) - RecordABigRequest(pContext, client, stuff); - else - RecordAProtocolElement(pContext, client, XRecordFromClient, - (pointer)stuff, client->req_len << 2, 0); - } - else /* extension, check minor opcode */ - { - int minorop = MinorOpcodeOfRequest(client); - int numMinOpInfo; - RecordMinorOpPtr pMinorOpInfo = pRCAP->pRequestMinOpInfo; - - assert (pMinorOpInfo); - numMinOpInfo = pMinorOpInfo->count; - pMinorOpInfo++; - assert (numMinOpInfo); - for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++) - { - if (majorop >= pMinorOpInfo->major.first && - majorop <= pMinorOpInfo->major.last && - RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet, - minorop)) - { - if (stuff->length == 0) - RecordABigRequest(pContext, client, stuff); - else - RecordAProtocolElement(pContext, client, - XRecordFromClient, (pointer)stuff, - client->req_len << 2, 0); - break; - } - } /* end for each minor op info */ - } /* end extension request */ - } /* end this RCAP wants this major opcode */ - } /* end for each context */ - pClientPriv = RecordClientPrivate(client); - assert(pClientPriv); - return (* pClientPriv->originalVector[majorop])(client); -} /* RecordARequest */ - -/* RecordAReply - * - * Arguments: - * pcbl is &ReplyCallback. - * nulldata is NULL. - * calldata is a pointer to a ReplyInfoRec (include/os.h) - * which provides information about replies that are being sent - * to clients. - * - * Returns: nothing. - * - * Side Effects: - * The reply is recorded by all contexts that have registered this - * reply type for this client. If more data belonging to the same - * reply is expected, and if the reply is being recorded by any - * context, pContext->continuedReply is set to 1. - * If pContext->continuedReply was already 1 and this is the last - * chunk of data belonging to this reply, it is set to 0. - */ -static void -RecordAReply(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) -{ - RecordContextPtr pContext; - RecordClientsAndProtocolPtr pRCAP; - int eci; - int majorop; - ReplyInfoRec *pri = (ReplyInfoRec *)calldata; - ClientPtr client = pri->client; - REQUEST(xReq); - - majorop = stuff->reqType; - for (eci = 0; eci < numEnabledContexts; eci++) - { - pContext = ppAllContexts[eci]; - pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask, - NULL); - if (pRCAP) - { - if (pContext->continuedReply) - { - RecordAProtocolElement(pContext, client, XRecordFromServer, - (pointer)pri->replyData, pri->dataLenBytes, /* continuation */ -1); - if (!pri->bytesRemaining) - pContext->continuedReply = 0; - } - else if (pri->startOfReply && pRCAP->pReplyMajorOpSet && - RecordIsMemberOfSet(pRCAP->pReplyMajorOpSet, majorop)) - { - if (majorop <= 127) - { /* core reply */ - RecordAProtocolElement(pContext, client, XRecordFromServer, - (pointer)pri->replyData, pri->dataLenBytes, pri->bytesRemaining); - if (pri->bytesRemaining) - pContext->continuedReply = 1; - } - else /* extension, check minor opcode */ - { - int minorop = MinorOpcodeOfRequest(client); - int numMinOpInfo; - RecordMinorOpPtr pMinorOpInfo = pRCAP->pReplyMinOpInfo; - assert (pMinorOpInfo); - numMinOpInfo = pMinorOpInfo->count; - pMinorOpInfo++; - assert (numMinOpInfo); - for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++) - { - if (majorop >= pMinorOpInfo->major.first && - majorop <= pMinorOpInfo->major.last && - RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet, - minorop)) - { - RecordAProtocolElement(pContext, client, - XRecordFromServer, (pointer)pri->replyData, - pri->dataLenBytes, pri->bytesRemaining); - if (pri->bytesRemaining) - pContext->continuedReply = 1; - break; - } - } /* end for each minor op info */ - } /* end extension reply */ - } /* end continued reply vs. start of reply */ - } /* end client is registered on this context */ - } /* end for each context */ -} /* RecordAReply */ - - -/* RecordADeliveredEventOrError - * - * Arguments: - * pcbl is &EventCallback. - * nulldata is NULL. - * calldata is a pointer to a EventInfoRec (include/dix.h) - * which provides information about events that are being sent - * to clients. - * - * Returns: nothing. - * - * Side Effects: - * The event or error is recorded by all contexts that have registered - * it for this client. - */ -static void -RecordADeliveredEventOrError(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) -{ - EventInfoRec *pei = (EventInfoRec *)calldata; - RecordContextPtr pContext; - RecordClientsAndProtocolPtr pRCAP; - int eci; /* enabled context index */ - ClientPtr pClient = pei->client; - - for (eci = 0; eci < numEnabledContexts; eci++) - { - pContext = ppAllContexts[eci]; - pRCAP = RecordFindClientOnContext(pContext, pClient->clientAsMask, - NULL); - if (pRCAP && (pRCAP->pDeliveredEventSet || pRCAP->pErrorSet)) - { - int ev; /* event index */ - xEvent *pev = pei->events; - for (ev = 0; ev < pei->count; ev++, pev++) - { - int recordit = 0; - if (pRCAP->pErrorSet) - { - recordit = RecordIsMemberOfSet(pRCAP->pErrorSet, - ((xError *)(pev))->errorCode); - } - else if (pRCAP->pDeliveredEventSet) - { - recordit = RecordIsMemberOfSet(pRCAP->pDeliveredEventSet, - pev->u.u.type & 0177); - } - if (recordit) - { - xEvent swappedEvent; - xEvent *pEvToRecord = pev; - - if (pClient->swapped) - { - (*EventSwapVector[pev->u.u.type & 0177]) - (pev, &swappedEvent); - pEvToRecord = &swappedEvent; - - } - RecordAProtocolElement(pContext, pClient, - XRecordFromServer, pEvToRecord, SIZEOF(xEvent), 0); - } - } /* end for each event */ - } /* end this client is on this context */ - } /* end for each enabled context */ -} /* RecordADeliveredEventOrError */ - - -static void -RecordSendProtocolEvents(RecordClientsAndProtocolPtr pRCAP, - RecordContextPtr pContext, - xEvent* pev, int count) -{ - int ev; /* event index */ - - for (ev = 0; ev < count; ev++, pev++) - { - if (RecordIsMemberOfSet(pRCAP->pDeviceEventSet, - pev->u.u.type & 0177)) - { - xEvent swappedEvent; - xEvent *pEvToRecord = pev; -#ifdef PANORAMIX - xEvent shiftedEvent; - - if (!noPanoramiXExtension && - (pev->u.u.type == MotionNotify || - pev->u.u.type == ButtonPress || - pev->u.u.type == ButtonRelease || - pev->u.u.type == KeyPress || - pev->u.u.type == KeyRelease)) { - int scr = XineramaGetCursorScreen(inputInfo.pointer); - memcpy(&shiftedEvent, pev, sizeof(xEvent)); - shiftedEvent.u.keyButtonPointer.rootX += - panoramiXdataPtr[scr].x - - panoramiXdataPtr[0].x; - shiftedEvent.u.keyButtonPointer.rootY += - panoramiXdataPtr[scr].y - - panoramiXdataPtr[0].y; - pEvToRecord = &shiftedEvent; - } -#endif /* PANORAMIX */ - - if (pContext->pRecordingClient->swapped) - { - (*EventSwapVector[pEvToRecord->u.u.type & 0177]) - (pEvToRecord, &swappedEvent); - pEvToRecord = &swappedEvent; - } - - RecordAProtocolElement(pContext, NULL, - XRecordFromServer, pEvToRecord, SIZEOF(xEvent), 0); - /* make sure device events get flushed in the absence - * of other client activity - */ - SetCriticalOutputPending(); - } - } /* end for each event */ - -} /* RecordADeviceEvent */ - -/* RecordADeviceEvent - * - * Arguments: - * pcbl is &DeviceEventCallback. - * nulldata is NULL. - * calldata is a pointer to a DeviceEventInfoRec (include/dix.h) - * which provides information about device events that occur. - * - * Returns: nothing. - * - * Side Effects: - * The device event is recorded by all contexts that have registered - * it for this client. - */ -static void -RecordADeviceEvent(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) -{ - DeviceEventInfoRec *pei = (DeviceEventInfoRec *)calldata; - RecordContextPtr pContext; - RecordClientsAndProtocolPtr pRCAP; - int eci; /* enabled context index */ - - for (eci = 0; eci < numEnabledContexts; eci++) - { - pContext = ppAllContexts[eci]; - for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) - { - if (pRCAP->pDeviceEventSet) - { - int count; - xEvent *xi_events = NULL; - - /* TODO check return values */ - if (IsMaster(pei->device)) - { - xEvent xE; - EventToCore(pei->event, &xE); - RecordSendProtocolEvents(pRCAP, pContext, &xE, 1); - } - - EventToXI(pei->event, &xi_events, &count); - RecordSendProtocolEvents(pRCAP, pContext, xi_events, count); - xfree(xi_events); - } /* end this RCAP selects device events */ - } /* end for each RCAP on this context */ - } /* end for each enabled context */ -} - - -/* RecordFlushAllContexts - * - * Arguments: - * pcbl is &FlushCallback. - * nulldata and calldata are NULL. - * - * Returns: nothing. - * - * Side Effects: - * All buffered reply data of all enabled contexts is written to - * the recording clients. - */ -static void -RecordFlushAllContexts( - CallbackListPtr *pcbl, - pointer nulldata, - pointer calldata -) -{ - int eci; /* enabled context index */ - RecordContextPtr pContext; - - for (eci = 0; eci < numEnabledContexts; eci++) - { - pContext = ppAllContexts[eci]; - - /* In most cases we leave it to RecordFlushReplyBuffer to make - * this check, but this function could be called very often, so we - * check before calling hoping to save the function call cost - * most of the time. - */ - if (pContext->numBufBytes) - RecordFlushReplyBuffer(ppAllContexts[eci], NULL, 0, NULL, 0); - } -} /* RecordFlushAllContexts */ - - -/* RecordInstallHooks - * - * Arguments: - * pRCAP is an RCAP on an enabled or being-enabled context. - * oneclient can be zero or the resource ID mask identifying a client. - * - * Returns: BadAlloc if a memory allocation error occurred, else Success. - * - * Side Effects: - * Recording hooks needed by RCAP are installed. - * If oneclient is zero, recording hooks needed for all clients and - * protocol on the RCAP are installed. If oneclient is non-zero, - * only those hooks needed for the specified client are installed. - * - * Client requestVectors may be altered. numEnabledRCAPs will be - * incremented if oneclient == 0. Callbacks may be added to - * various callback lists. - */ -static int -RecordInstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient) -{ - int i = 0; - XID client; - - if (oneclient) - client = oneclient; - else - client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0; - - while (client) - { - if (client != XRecordFutureClients) - { - if (pRCAP->pRequestMajorOpSet) - { - RecordSetIteratePtr pIter = NULL; - RecordSetInterval interval; - ClientPtr pClient = clients[CLIENT_ID(client)]; - - if (pClient && !RecordClientPrivate(pClient)) - { - RecordClientPrivatePtr pClientPriv; - /* no Record proc vector; allocate one */ - pClientPriv = (RecordClientPrivatePtr) - xalloc(sizeof(RecordClientPrivateRec)); - if (!pClientPriv) - return BadAlloc; - /* copy old proc vector to new */ - memcpy(pClientPriv->recordVector, pClient->requestVector, - sizeof (pClientPriv->recordVector)); - pClientPriv->originalVector = pClient->requestVector; - dixSetPrivate(&pClient->devPrivates, - RecordClientPrivateKey, pClientPriv); - pClient->requestVector = pClientPriv->recordVector; - } - while ((pIter = RecordIterateSet(pRCAP->pRequestMajorOpSet, - pIter, &interval))) - { - unsigned int j; - for (j = interval.first; j <= interval.last; j++) - pClient->requestVector[j] = RecordARequest; - } - } - } - if (oneclient) - client = 0; - else - client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0; - } - - assert(numEnabledRCAPs >= 0); - if (!oneclient && ++numEnabledRCAPs == 1) - { /* we're enabling the first context */ - if (!AddCallback(&EventCallback, RecordADeliveredEventOrError, NULL)) - return BadAlloc; - if (!AddCallback(&DeviceEventCallback, RecordADeviceEvent, NULL)) - return BadAlloc; - if (!AddCallback(&ReplyCallback, RecordAReply, NULL)) - return BadAlloc; - if (!AddCallback(&FlushCallback, RecordFlushAllContexts, NULL)) - return BadAlloc; - /* Alternate context flushing scheme: delete the line above - * and call RegisterBlockAndWakeupHandlers here passing - * RecordFlushAllContexts. Is this any better? - */ - } - return Success; -} /* RecordInstallHooks */ - - -/* RecordUninstallHooks - * - * Arguments: - * pRCAP is an RCAP on an enabled or being-disabled context. - * oneclient can be zero or the resource ID mask identifying a client. - * - * Returns: nothing. - * - * Side Effects: - * Recording hooks needed by RCAP may be uninstalled. - * If oneclient is zero, recording hooks needed for all clients and - * protocol on the RCAP may be uninstalled. If oneclient is non-zero, - * only those hooks needed for the specified client may be uninstalled. - * - * Client requestVectors may be altered. numEnabledRCAPs will be - * decremented if oneclient == 0. Callbacks may be deleted from - * various callback lists. - */ -static void -RecordUninstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient) -{ - int i = 0; - XID client; - - if (oneclient) - client = oneclient; - else - client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0; - - while (client) - { - if (client != XRecordFutureClients) - { - if (pRCAP->pRequestMajorOpSet) - { - ClientPtr pClient = clients[CLIENT_ID(client)]; - int c; - Bool otherRCAPwantsProcVector = FALSE; - RecordClientPrivatePtr pClientPriv = - RecordClientPrivate(pClient); - - assert (pClient && RecordClientPrivate(pClient)); - memcpy(pClientPriv->recordVector, pClientPriv->originalVector, - sizeof (pClientPriv->recordVector)); - - for (c = 0; c < numEnabledContexts; c++) - { - RecordClientsAndProtocolPtr pOtherRCAP; - RecordContextPtr pContext = ppAllContexts[c]; - - if (pContext == pRCAP->pContext) continue; - pOtherRCAP = RecordFindClientOnContext(pContext, client, - NULL); - if (pOtherRCAP && pOtherRCAP->pRequestMajorOpSet) - { - RecordSetIteratePtr pIter = NULL; - RecordSetInterval interval; - - otherRCAPwantsProcVector = TRUE; - while ((pIter = RecordIterateSet( - pOtherRCAP->pRequestMajorOpSet, - pIter, &interval))) - { - unsigned int j; - for (j = interval.first; j <= interval.last; j++) - pClient->requestVector[j] = RecordARequest; - } - } - } - if (!otherRCAPwantsProcVector) - { /* nobody needs it, so free it */ - pClient->requestVector = pClientPriv->originalVector; - dixSetPrivate(&pClient->devPrivates, - RecordClientPrivateKey, NULL); - xfree(pClientPriv); - } - } /* end if this RCAP specifies any requests */ - } /* end if not future clients */ - if (oneclient) - client = 0; - else - client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0; - } - - assert(numEnabledRCAPs >= 1); - if (!oneclient && --numEnabledRCAPs == 0) - { /* we're disabling the last context */ - DeleteCallback(&EventCallback, RecordADeliveredEventOrError, NULL); - DeleteCallback(&DeviceEventCallback, RecordADeviceEvent, NULL); - DeleteCallback(&ReplyCallback, RecordAReply, NULL); - DeleteCallback(&FlushCallback, RecordFlushAllContexts, NULL); - /* Alternate context flushing scheme: delete the line above - * and call RemoveBlockAndWakeupHandlers here passing - * RecordFlushAllContexts. Is this any better? - */ - /* Having deleted the callback, call it one last time. -gildea */ - RecordFlushAllContexts(&FlushCallback, NULL, NULL); - } -} /* RecordUninstallHooks */ - - -/* RecordDeleteClientFromRCAP - * - * Arguments: - * pRCAP is an RCAP to delete the client from. - * position is the index into the array pRCAP->pClientIDs of the - * client to delete. - * - * Returns: nothing. - * - * Side Effects: - * Recording hooks needed by client will be uninstalled if the context - * is enabled. The designated client will be removed from the - * pRCAP->pClientIDs array. If it was the only client on the RCAP, - * the RCAP is removed from the context and freed. (Invariant: RCAPs - * have at least one client.) - */ -static void -RecordDeleteClientFromRCAP(RecordClientsAndProtocolPtr pRCAP, int position) -{ - if (pRCAP->pContext->pRecordingClient) - RecordUninstallHooks(pRCAP, pRCAP->pClientIDs[position]); - if (position != pRCAP->numClients - 1) - pRCAP->pClientIDs[position] = pRCAP->pClientIDs[pRCAP->numClients - 1]; - if (--pRCAP->numClients == 0) - { /* no more clients; remove RCAP from context's list */ - RecordContextPtr pContext = pRCAP->pContext; - if (pContext->pRecordingClient) - RecordUninstallHooks(pRCAP, 0); - if (pContext->pListOfRCAP == pRCAP) - pContext->pListOfRCAP = pRCAP->pNextRCAP; - else - { - RecordClientsAndProtocolPtr prevRCAP; - for (prevRCAP = pContext->pListOfRCAP; - prevRCAP->pNextRCAP != pRCAP; - prevRCAP = prevRCAP->pNextRCAP) - ; - prevRCAP->pNextRCAP = pRCAP->pNextRCAP; - } - /* free the RCAP */ - if (pRCAP->clientIDsSeparatelyAllocated) - xfree(pRCAP->pClientIDs); - xfree(pRCAP); - } -} /* RecordDeleteClientFromRCAP */ - - -/* RecordAddClientToRCAP - * - * Arguments: - * pRCAP is an RCAP to add the client to. - * clientspec is the resource ID mask identifying a client, or - * XRecordFutureClients. - * - * Returns: nothing. - * - * Side Effects: - * Recording hooks needed by client will be installed if the context - * is enabled. The designated client will be added to the - * pRCAP->pClientIDs array, which may be realloced. - * pRCAP->clientIDsSeparatelyAllocated may be set to 1 if there - * is no more room to hold clients internal to the RCAP. - */ -static void -RecordAddClientToRCAP(RecordClientsAndProtocolPtr pRCAP, XID clientspec) -{ - if (pRCAP->numClients == pRCAP->sizeClients) - { - if (pRCAP->clientIDsSeparatelyAllocated) - { - XID *pNewIDs = (XID *)xrealloc(pRCAP->pClientIDs, - (pRCAP->sizeClients + CLIENT_ARRAY_GROWTH_INCREMENT) * - sizeof(XID)); - if (!pNewIDs) - return; - pRCAP->pClientIDs = pNewIDs; - pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT; - } - else - { - XID *pNewIDs = (XID *)xalloc((pRCAP->sizeClients + - CLIENT_ARRAY_GROWTH_INCREMENT) * sizeof(XID)); - if (!pNewIDs) - return; - memcpy(pNewIDs, pRCAP->pClientIDs, pRCAP->numClients *sizeof(XID)); - pRCAP->pClientIDs = pNewIDs; - pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT; - pRCAP->clientIDsSeparatelyAllocated = 1; - } - } - pRCAP->pClientIDs[pRCAP->numClients++] = clientspec; - if (pRCAP->pContext->pRecordingClient) - RecordInstallHooks(pRCAP, clientspec); -} /* RecordDeleteClientFromRCAP */ - - -/* RecordDeleteClientFromContext - * - * Arguments: - * pContext is the context to delete from. - * clientspec is the resource ID mask identifying a client, or - * XRecordFutureClients. - * - * Returns: nothing. - * - * Side Effects: - * If clientspec is on any RCAP of the context, it is deleted from that - * RCAP. (A given clientspec can only be on one RCAP of a context.) - */ -static void -RecordDeleteClientFromContext(RecordContextPtr pContext, XID clientspec) -{ - RecordClientsAndProtocolPtr pRCAP; - int position; - - if ((pRCAP = RecordFindClientOnContext(pContext, clientspec, &position))) - RecordDeleteClientFromRCAP(pRCAP, position); -} /* RecordDeleteClientFromContext */ - - -/* RecordSanityCheckClientSpecifiers - * - * Arguments: - * clientspecs is an array of alleged CLIENTSPECs passed by the client. - * nspecs is the number of elements in clientspecs. - * errorspec, if non-zero, is the resource id base of a client that - * must not appear in clienspecs. - * - * Returns: BadMatch if any of the clientspecs are invalid, else Success. - * - * Side Effects: none. - */ -static int -RecordSanityCheckClientSpecifiers(ClientPtr client, XID *clientspecs, int nspecs, XID errorspec) -{ - int i; - int clientIndex; - int rc; - pointer value; - - for (i = 0; i < nspecs; i++) - { - if (clientspecs[i] == XRecordCurrentClients || - clientspecs[i] == XRecordFutureClients || - clientspecs[i] == XRecordAllClients) - continue; - if (errorspec && (CLIENT_BITS(clientspecs[i]) == errorspec) ) - return BadMatch; - clientIndex = CLIENT_ID(clientspecs[i]); - if (clientIndex && clients[clientIndex] && - clients[clientIndex]->clientState == ClientStateRunning) - { - if (clientspecs[i] == clients[clientIndex]->clientAsMask) - continue; - rc = dixLookupResourceByClass(&value, clientspecs[i], RC_ANY, - client, DixGetAttrAccess); - if (rc != Success) - return rc; - } - else - return BadMatch; - } - return Success; -} /* RecordSanityCheckClientSpecifiers */ - - -/* RecordCanonicalizeClientSpecifiers - * - * Arguments: - * pClientspecs is an array of CLIENTSPECs that have been sanity - * checked. - * pNumClientspecs is a pointer to the number of elements in pClientspecs. - * excludespec, if non-zero, is the resource id base of a client that - * should not be included in the expansion of XRecordAllClients or - * XRecordCurrentClients. - * - * Returns: - * A pointer to an array of CLIENTSPECs that is the same as the - * passed array with the following modifications: - * - all but the client id bits of resource IDs are stripped off. - * - duplicates removed. - * - XRecordAllClients expanded to a list of all currently connected - * clients + XRecordFutureClients - excludespec (if non-zero) - * - XRecordCurrentClients expanded to a list of all currently - * connected clients - excludespec (if non-zero) - * The returned array may be the passed array modified in place, or - * it may be an Xalloc'ed array. The caller should keep a pointer to the - * original array and free the returned array if it is different. - * - * *pNumClientspecs is set to the number of elements in the returned - * array. - * - * Side Effects: - * pClientspecs may be modified in place. - */ -static XID * -RecordCanonicalizeClientSpecifiers(XID *pClientspecs, int *pNumClientspecs, XID excludespec) -{ - int i; - int numClients = *pNumClientspecs; - - /* first pass strips off the resource index bits, leaving just the - * client id bits. This makes searching for a particular client simpler - * (and faster.) - */ - for (i = 0; i < numClients; i++) - { - XID cs = pClientspecs[i]; - if (cs > XRecordAllClients) - pClientspecs[i] = CLIENT_BITS(cs); - } - - for (i = 0; i < numClients; i++) - { - if (pClientspecs[i] == XRecordAllClients || - pClientspecs[i] == XRecordCurrentClients) - { /* expand All/Current */ - int j, nc; - XID *pCanon = (XID *)xalloc(sizeof(XID) * (currentMaxClients + 1)); - if (!pCanon) return NULL; - for (nc = 0, j = 1; j < currentMaxClients; j++) - { - ClientPtr client = clients[j]; - if (client != NullClient && - client->clientState == ClientStateRunning && - client->clientAsMask != excludespec) - { - pCanon[nc++] = client->clientAsMask; - } - } - if (pClientspecs[i] == XRecordAllClients) - pCanon[nc++] = XRecordFutureClients; - *pNumClientspecs = nc; - return pCanon; - } - else /* not All or Current */ - { - int j; - for (j = i + 1; j < numClients; ) - { - if (pClientspecs[i] == pClientspecs[j]) - { - pClientspecs[j] = pClientspecs[--numClients]; - } - else - j++; - } - } - } /* end for each clientspec */ - *pNumClientspecs = numClients; - return pClientspecs; -} /* RecordCanonicalizeClientSpecifiers */ - - -/****************************************************************************/ - -/* stuff for RegisterClients */ - -/* RecordPadAlign - * - * Arguments: - * size is the number of bytes taken by an object. - * align is a byte boundary (e.g. 4, 8) - * - * Returns: - * the number of pad bytes to add at the end of an object of the - * given size so that an object placed immediately behind it will - * begin on an <align>-byte boundary. - * - * Side Effects: none. - */ -static int -RecordPadAlign(int size, int align) -{ - return (align - (size & (align - 1))) & (align - 1); -} /* RecordPadAlign */ - - -/* RecordSanityCheckRegisterClients - * - * Arguments: - * pContext is the context being registered on. - * client is the client that issued a RecordCreateContext or - * RecordRegisterClients request. - * stuff is a pointer to the request. - * - * Returns: - * Any one of several possible error values if any of the request - * arguments are invalid. Success if everything is OK. - * - * Side Effects: none. - */ -static int -RecordSanityCheckRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff) -{ - int err; - xRecordRange *pRange; - int i; - XID recordingClient; - - if (((client->req_len << 2) - SIZEOF(xRecordRegisterClientsReq)) != - 4 * stuff->nClients + SIZEOF(xRecordRange) * stuff->nRanges) - return BadLength; - - if (stuff->elementHeader & - ~(XRecordFromClientSequence|XRecordFromClientTime|XRecordFromServerTime)) - { - client->errorValue = stuff->elementHeader; - return BadValue; - } - - recordingClient = pContext->pRecordingClient ? - pContext->pRecordingClient->clientAsMask : 0; - err = RecordSanityCheckClientSpecifiers(client, (XID *)&stuff[1], - stuff->nClients, recordingClient); - if (err != Success) return err; - - pRange = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients); - for (i = 0; i < stuff->nRanges; i++, pRange++) - { - if (pRange->coreRequestsFirst > pRange->coreRequestsLast) - { - client->errorValue = pRange->coreRequestsFirst; - return BadValue; - } - if (pRange->coreRepliesFirst > pRange->coreRepliesLast) - { - client->errorValue = pRange->coreRepliesFirst; - return BadValue; - } - if ((pRange->extRequestsMajorFirst || pRange->extRequestsMajorLast) && - (pRange->extRequestsMajorFirst < 128 || - pRange->extRequestsMajorLast < 128 || - pRange->extRequestsMajorFirst > pRange->extRequestsMajorLast)) - { - client->errorValue = pRange->extRequestsMajorFirst; - return BadValue; - } - if (pRange->extRequestsMinorFirst > pRange->extRequestsMinorLast) - { - client->errorValue = pRange->extRequestsMinorFirst; - return BadValue; - } - if ((pRange->extRepliesMajorFirst || pRange->extRepliesMajorLast) && - (pRange->extRepliesMajorFirst < 128 || - pRange->extRepliesMajorLast < 128 || - pRange->extRepliesMajorFirst > pRange->extRepliesMajorLast)) - { - client->errorValue = pRange->extRepliesMajorFirst; - return BadValue; - } - if (pRange->extRepliesMinorFirst > pRange->extRepliesMinorLast) - { - client->errorValue = pRange->extRepliesMinorFirst; - return BadValue; - } - if ((pRange->deliveredEventsFirst || pRange->deliveredEventsLast) && - (pRange->deliveredEventsFirst < 2 || - pRange->deliveredEventsLast < 2 || - pRange->deliveredEventsFirst > pRange->deliveredEventsLast)) - { - client->errorValue = pRange->deliveredEventsFirst; - return BadValue; - } - if ((pRange->deviceEventsFirst || pRange->deviceEventsLast) && - (pRange->deviceEventsFirst < 2 || - pRange->deviceEventsLast < 2 || - pRange->deviceEventsFirst > pRange->deviceEventsLast)) - { - client->errorValue = pRange->deviceEventsFirst; - return BadValue; - } - if (pRange->errorsFirst > pRange->errorsLast) - { - client->errorValue = pRange->errorsFirst; - return BadValue; - } - if (pRange->clientStarted != xFalse && pRange->clientStarted != xTrue) - { - client->errorValue = pRange->clientStarted; - return BadValue; - } - if (pRange->clientDied != xFalse && pRange->clientDied != xTrue) - { - client->errorValue = pRange->clientDied; - return BadValue; - } - } /* end for each range */ - return Success; -} /* end RecordSanityCheckRegisterClients */ - -/* This is a tactical structure used to gather information about all the sets - * (RecordSetPtr) that need to be created for an RCAP in the process of - * digesting a list of RECORDRANGEs (converting it to the internal - * representation). - */ -typedef struct -{ - int nintervals; /* number of intervals in following array */ - RecordSetInterval *intervals; /* array of intervals for this set */ - int size; /* size of intevals array; >= nintervals */ - int align; /* alignment restriction for set */ - int offset; /* where to store set pointer rel. to start of RCAP */ - short first, last; /* if for extension, major opcode interval */ -} SetInfoRec, *SetInfoPtr; - -/* These constant are used to index into an array of SetInfoRec. */ -enum {REQ, /* set info for requests */ - REP, /* set info for replies */ - ERR, /* set info for errors */ - DEV, /* set info for device events */ - DLEV, /* set info for delivered events */ - PREDEFSETS}; /* number of predefined array entries */ - - -/* RecordAllocIntervals - * - * Arguments: - * psi is a pointer to a SetInfoRec whose intervals pointer is NULL. - * nIntervals is the desired size of the intervals array. - * - * Returns: BadAlloc if a memory allocation error occurred, else Success. - * - * Side Effects: - * If Success is returned, psi->intervals is a pointer to size - * RecordSetIntervals, all zeroed, and psi->size is set to size. - */ -static int -RecordAllocIntervals(SetInfoPtr psi, int nIntervals) -{ - assert(!psi->intervals); - psi->intervals = (RecordSetInterval *) - xalloc(nIntervals * sizeof(RecordSetInterval)); - if (!psi->intervals) - return BadAlloc; - bzero(psi->intervals, nIntervals * sizeof(RecordSetInterval)); - psi->size = nIntervals; - return Success; -} /* end RecordAllocIntervals */ - - -/* RecordConvertRangesToIntervals - * - * Arguments: - * psi is a pointer to the SetInfoRec we are building. - * pRanges is an array of xRecordRanges. - * nRanges is the number of elements in pRanges. - * byteoffset is the offset from the start of an xRecordRange of the - * two bytes (1 for first, 1 for last) we are interested in. - * pExtSetInfo, if non-NULL, indicates that the two bytes mentioned - * above are followed by four bytes (2 for first, 2 for last) - * representing a minor opcode range, and this information should be - * stored in one of the SetInfoRecs starting at pExtSetInfo. - * pnExtSetInfo is the number of elements in the pExtSetInfo array. - * - * Returns: BadAlloc if a memory allocation error occurred, else Success. - * - * Side Effects: - * The slice of pRanges indicated by byteoffset is stored in psi. - * If pExtSetInfo is non-NULL, minor opcode intervals are stored - * in an existing SetInfoRec if the major opcode interval matches, else - * they are stored in a new SetInfoRec, and *pnExtSetInfo is - * increased accordingly. - */ -static int -RecordConvertRangesToIntervals( - SetInfoPtr psi, - xRecordRange *pRanges, - int nRanges, - int byteoffset, - SetInfoPtr pExtSetInfo, - int *pnExtSetInfo -) -{ - int i; - CARD8 *pCARD8; - int first, last; - int err; - - for (i = 0; i < nRanges; i++, pRanges++) - { - pCARD8 = ((CARD8 *)pRanges) + byteoffset; - first = pCARD8[0]; - last = pCARD8[1]; - if (first || last) - { - if (!psi->intervals) - { - err = RecordAllocIntervals(psi, 2 * (nRanges - i)); - if (err != Success) - return err; - } - psi->intervals[psi->nintervals].first = first; - psi->intervals[psi->nintervals].last = last; - psi->nintervals++; - assert(psi->nintervals <= psi->size); - if (pExtSetInfo) - { - SetInfoPtr pesi = pExtSetInfo; - CARD16 *pCARD16 = (CARD16 *)(pCARD8 + 2); - int j; - - for (j = 0; j < *pnExtSetInfo; j++, pesi++) - { - if ( (first == pesi->first) && (last == pesi->last) ) - break; - } - if (j == *pnExtSetInfo) - { - err = RecordAllocIntervals(pesi, 2 * (nRanges - i)); - if (err != Success) - return err; - pesi->first = first; - pesi->last = last; - (*pnExtSetInfo)++; - } - pesi->intervals[pesi->nintervals].first = pCARD16[0]; - pesi->intervals[pesi->nintervals].last = pCARD16[1]; - pesi->nintervals++; - assert(pesi->nintervals <= pesi->size); - } - } - } - return Success; -} /* end RecordConvertRangesToIntervals */ - -#define offset_of(_structure, _field) \ - ((char *)(& (_structure . _field)) - (char *)(&_structure)) - -/* RecordRegisterClients - * - * Arguments: - * pContext is the context on which to register the clients. - * client is the client that issued the RecordCreateContext or - * RecordRegisterClients request. - * stuff is a pointer to the request. - * - * Returns: - * Any one of several possible error values defined by the protocol. - * Success if everything is OK. - * - * Side Effects: - * If different element headers are specified, the context is flushed. - * If any of the specified clients are already registered on the - * context, they are first unregistered. A new RCAP is created to - * hold the specified protocol and clients, and it is linked onto the - * context. If the context is enabled, appropriate hooks are installed - * to record the new clients and protocol. - */ -static int -RecordRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff) -{ - int err; - int i; - SetInfoPtr si; - int maxSets; - int nExtReqSets = 0; - int nExtRepSets = 0; - int extReqSetsOffset = 0; - int extRepSetsOffset = 0; - SetInfoPtr pExtReqSets, pExtRepSets; - int clientListOffset; - XID *pCanonClients; - int clientStarted = 0, clientDied = 0; - xRecordRange *pRanges, rr; - int nClients; - int sizeClients; - int totRCAPsize; - RecordClientsAndProtocolPtr pRCAP; - int pad; - XID recordingClient; - - /* do all sanity checking up front */ - - err = RecordSanityCheckRegisterClients(pContext, client, stuff); - if (err != Success) - return err; - - /* if element headers changed, flush buffer */ - - if (pContext->elemHeaders != stuff->elementHeader) - { - RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0); - pContext->elemHeaders = stuff->elementHeader; - } - - nClients = stuff->nClients; - if (!nClients) - /* if empty clients list, we're done. */ - return Success; - - recordingClient = pContext->pRecordingClient ? - pContext->pRecordingClient->clientAsMask : 0; - pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1], - &nClients, recordingClient); - if (!pCanonClients) - return BadAlloc; - - /* We may have to create as many as one set for each "predefined" - * protocol types, plus one per range for extension reuests, plus one per - * range for extension replies. - */ - maxSets = PREDEFSETS + 2 * stuff->nRanges; - si = (SetInfoPtr)xalloc(sizeof(SetInfoRec) * maxSets); - if (!si) - { - err = BadAlloc; - goto bailout; - } - bzero(si, sizeof(SetInfoRec) * maxSets); - - /* theoretically you must do this because NULL may not be all-bits-zero */ - for (i = 0; i < maxSets; i++) - si[i].intervals = NULL; - - pExtReqSets = si + PREDEFSETS; - pExtRepSets = pExtReqSets + stuff->nRanges; - - pRanges = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients); - - err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges, - offset_of(rr, coreRequestsFirst), NULL, NULL); - if (err != Success) goto bailout; - - err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges, - offset_of(rr, extRequestsMajorFirst), pExtReqSets, &nExtReqSets); - if (err != Success) goto bailout; - - err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges, - offset_of(rr, coreRepliesFirst), NULL, NULL); - if (err != Success) goto bailout; - - err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges, - offset_of(rr, extRepliesMajorFirst), pExtRepSets, &nExtRepSets); - if (err != Success) goto bailout; - - err = RecordConvertRangesToIntervals(&si[ERR], pRanges, stuff->nRanges, - offset_of(rr, errorsFirst), NULL, NULL); - if (err != Success) goto bailout; - - err = RecordConvertRangesToIntervals(&si[DLEV], pRanges, stuff->nRanges, - offset_of(rr, deliveredEventsFirst), NULL, NULL); - if (err != Success) goto bailout; - - err = RecordConvertRangesToIntervals(&si[DEV], pRanges, stuff->nRanges, - offset_of(rr, deviceEventsFirst), NULL, NULL); - if (err != Success) goto bailout; - - /* collect client-started and client-died */ - - for (i = 0; i < stuff->nRanges; i++) - { - if (pRanges[i].clientStarted) clientStarted = TRUE; - if (pRanges[i].clientDied) clientDied = TRUE; - } - - /* We now have all the information collected to create all the sets, - * and we can compute the total memory required for the RCAP. - */ - - totRCAPsize = sizeof(RecordClientsAndProtocolRec); - - /* leave a little room to grow before forcing a separate allocation */ - sizeClients = nClients + CLIENT_ARRAY_GROWTH_INCREMENT; - pad = RecordPadAlign(totRCAPsize, sizeof(XID)); - clientListOffset = totRCAPsize + pad; - totRCAPsize += pad + sizeClients * sizeof(XID); - - if (nExtReqSets) - { - pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr)); - extReqSetsOffset = totRCAPsize + pad; - totRCAPsize += pad + (nExtReqSets + 1) * sizeof(RecordMinorOpRec); - } - if (nExtRepSets) - { - pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr)); - extRepSetsOffset = totRCAPsize + pad; - totRCAPsize += pad + (nExtRepSets + 1) * sizeof(RecordMinorOpRec); - } - - for (i = 0; i < maxSets; i++) - { - if (si[i].nintervals) - { - si[i].size = RecordSetMemoryRequirements( - si[i].intervals, si[i].nintervals, &si[i].align); - pad = RecordPadAlign(totRCAPsize, si[i].align); - si[i].offset = pad + totRCAPsize; - totRCAPsize += pad + si[i].size; - } - } - - /* allocate memory for the whole RCAP */ - - pRCAP = (RecordClientsAndProtocolPtr)xalloc(totRCAPsize); - if (!pRCAP) - { - err = BadAlloc; - goto bailout; - } - - /* fill in the RCAP */ - - pRCAP->pContext = pContext; - pRCAP->pClientIDs = (XID *)((char *)pRCAP + clientListOffset); - pRCAP->numClients = nClients; - pRCAP->sizeClients = sizeClients; - pRCAP->clientIDsSeparatelyAllocated = 0; - for (i = 0; i < nClients; i++) - { - RecordDeleteClientFromContext(pContext, pCanonClients[i]); - pRCAP->pClientIDs[i] = pCanonClients[i]; - } - - /* create all the sets */ - - if (si[REQ].intervals) - { - pRCAP->pRequestMajorOpSet = - RecordCreateSet(si[REQ].intervals, si[REQ].nintervals, - (RecordSetPtr)((char *)pRCAP + si[REQ].offset), si[REQ].size); - } - else pRCAP->pRequestMajorOpSet = NULL; - - if (si[REP].intervals) - { - pRCAP->pReplyMajorOpSet = - RecordCreateSet(si[REP].intervals, si[REP].nintervals, - (RecordSetPtr)((char *)pRCAP + si[REP].offset), si[REP].size); - } - else pRCAP->pReplyMajorOpSet = NULL; - - if (si[ERR].intervals) - { - pRCAP->pErrorSet = - RecordCreateSet(si[ERR].intervals, si[ERR].nintervals, - (RecordSetPtr)((char *)pRCAP + si[ERR].offset), si[ERR].size); - } - else pRCAP->pErrorSet = NULL; - - if (si[DEV].intervals) - { - pRCAP->pDeviceEventSet = - RecordCreateSet(si[DEV].intervals, si[DEV].nintervals, - (RecordSetPtr)((char *)pRCAP + si[DEV].offset), si[DEV].size); - } - else pRCAP->pDeviceEventSet = NULL; - - if (si[DLEV].intervals) - { - pRCAP->pDeliveredEventSet = - RecordCreateSet(si[DLEV].intervals, si[DLEV].nintervals, - (RecordSetPtr)((char *)pRCAP + si[DLEV].offset), si[DLEV].size); - } - else pRCAP->pDeliveredEventSet = NULL; - - if (nExtReqSets) - { - pRCAP->pRequestMinOpInfo = (RecordMinorOpPtr) - ((char *)pRCAP + extReqSetsOffset); - pRCAP->pRequestMinOpInfo[0].count = nExtReqSets; - for (i = 0; i < nExtReqSets; i++, pExtReqSets++) - { - pRCAP->pRequestMinOpInfo[i+1].major.first = pExtReqSets->first; - pRCAP->pRequestMinOpInfo[i+1].major.last = pExtReqSets->last; - pRCAP->pRequestMinOpInfo[i+1].major.pMinOpSet = - RecordCreateSet(pExtReqSets->intervals, - pExtReqSets->nintervals, - (RecordSetPtr)((char *)pRCAP + pExtReqSets->offset), - pExtReqSets->size); - } - } - else pRCAP->pRequestMinOpInfo = NULL; - - if (nExtRepSets) - { - pRCAP->pReplyMinOpInfo = (RecordMinorOpPtr) - ((char *)pRCAP + extRepSetsOffset); - pRCAP->pReplyMinOpInfo[0].count = nExtRepSets; - for (i = 0; i < nExtRepSets; i++, pExtRepSets++) - { - pRCAP->pReplyMinOpInfo[i+1].major.first = pExtRepSets->first; - pRCAP->pReplyMinOpInfo[i+1].major.last = pExtRepSets->last; - pRCAP->pReplyMinOpInfo[i+1].major.pMinOpSet = - RecordCreateSet(pExtRepSets->intervals, - pExtRepSets->nintervals, - (RecordSetPtr)((char *)pRCAP + pExtRepSets->offset), - pExtRepSets->size); - } - } - else pRCAP->pReplyMinOpInfo = NULL; - - pRCAP->clientStarted = clientStarted; - pRCAP->clientDied = clientDied; - - /* link the RCAP onto the context */ - - pRCAP->pNextRCAP = pContext->pListOfRCAP; - pContext->pListOfRCAP = pRCAP; - - if (pContext->pRecordingClient) /* context enabled */ - RecordInstallHooks(pRCAP, 0); - -bailout: - if (si) - { - for (i = 0; i < maxSets; i++) - if (si[i].intervals) - xfree(si[i].intervals); - xfree(si); - } - if (pCanonClients && pCanonClients != (XID *)&stuff[1]) - xfree(pCanonClients); - return err; -} /* RecordRegisterClients */ - - -/* Proc functions all take a client argument, execute the request in - * client->requestBuffer, and return a protocol error status. - */ - -static int -ProcRecordQueryVersion(ClientPtr client) -{ - /* REQUEST(xRecordQueryVersionReq); */ - xRecordQueryVersionReply rep; - int n; - - REQUEST_SIZE_MATCH(xRecordQueryVersionReq); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.majorVersion = SERVER_RECORD_MAJOR_VERSION; - rep.minorVersion = SERVER_RECORD_MINOR_VERSION; - if(client->swapped) - { - swaps(&rep.sequenceNumber, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - (void)WriteToClient(client, sizeof(xRecordQueryVersionReply), - (char *)&rep); - return (client->noClientException); -} /* ProcRecordQueryVersion */ - - -static int -ProcRecordCreateContext(ClientPtr client) -{ - REQUEST(xRecordCreateContextReq); - RecordContextPtr pContext; - RecordContextPtr *ppNewAllContexts = NULL; - int err = BadAlloc; - - REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq); - LEGAL_NEW_RESOURCE(stuff->context, client); - - pContext = (RecordContextPtr)xalloc(sizeof(RecordContextRec)); - if (!pContext) - goto bailout; - - /* make sure there is room in ppAllContexts to store the new context */ - - ppNewAllContexts = (RecordContextPtr *) - xrealloc(ppAllContexts, sizeof(RecordContextPtr) * (numContexts + 1)); - if (!ppNewAllContexts) - goto bailout; - ppAllContexts = ppNewAllContexts; - - pContext->id = stuff->context; - pContext->pRecordingClient = NULL; - pContext->pListOfRCAP = NULL; - pContext->elemHeaders = 0; - pContext->bufCategory = 0; - pContext->numBufBytes = 0; - pContext->pBufClient = NULL; - pContext->continuedReply = 0; - - err = RecordRegisterClients(pContext, client, - (xRecordRegisterClientsReq *)stuff); - if (err != Success) - goto bailout; - - if (AddResource(pContext->id, RTContext, pContext)) - { - ppAllContexts[numContexts++] = pContext; - return Success; - } - else - { - RecordDeleteContext((pointer)pContext, pContext->id); - err = BadAlloc; - } -bailout: - if (pContext) - xfree(pContext); - return err; -} /* ProcRecordCreateContext */ - - -static int -ProcRecordRegisterClients(ClientPtr client) -{ - RecordContextPtr pContext; - REQUEST(xRecordRegisterClientsReq); - - REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq); - VERIFY_CONTEXT(pContext, stuff->context, client); - - return RecordRegisterClients(pContext, client, stuff); -} /* ProcRecordRegisterClients */ - - -static int -ProcRecordUnregisterClients(ClientPtr client) -{ - RecordContextPtr pContext; - int err; - REQUEST(xRecordUnregisterClientsReq); - XID *pCanonClients; - int nClients; - int i; - - REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq); - if ((client->req_len << 2) - SIZEOF(xRecordUnregisterClientsReq) != - 4 * stuff->nClients) - return BadLength; - VERIFY_CONTEXT(pContext, stuff->context, client); - err = RecordSanityCheckClientSpecifiers(client, (XID *)&stuff[1], - stuff->nClients, 0); - if (err != Success) - return err; - - nClients = stuff->nClients; - pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1], - &nClients, 0); - if (!pCanonClients) - return BadAlloc; - - for (i = 0; i < nClients; i++) - { - RecordDeleteClientFromContext(pContext, pCanonClients[i]); - } - if (pCanonClients != (XID *)&stuff[1]) - xfree(pCanonClients); - return Success; -} /* ProcRecordUnregisterClients */ - - -/****************************************************************************/ - -/* stuff for GetContext */ - -/* This is a tactical structure used to hold the xRecordRanges as they are - * being reconstituted from the sets in the RCAPs. - */ - -typedef struct { - xRecordRange *pRanges; /* array of xRecordRanges for one RCAP */ - int size; /* number of elements in pRanges, >= nRanges */ - int nRanges; /* number of occupied element of pRanges */ -} GetContextRangeInfoRec, *GetContextRangeInfoPtr; - - -/* RecordAllocRanges - * - * Arguments: - * pri is a pointer to a GetContextRangeInfoRec to allocate for. - * nRanges is the number of xRecordRanges desired for pri. - * - * Returns: BadAlloc if a memory allocation error occurred, else Success. - * - * Side Effects: - * If Success is returned, pri->pRanges points to at least nRanges - * ranges. pri->nRanges is set to nRanges. pri->size is the actual - * number of ranges. Newly allocated ranges are zeroed. - */ -static int -RecordAllocRanges(GetContextRangeInfoPtr pri, int nRanges) -{ - int newsize; - xRecordRange *pNewRange; -#define SZINCR 8 - - newsize = max(pri->size + SZINCR, nRanges); - pNewRange = (xRecordRange *)xrealloc(pri->pRanges, - newsize * sizeof(xRecordRange)); - if (!pNewRange) - return BadAlloc; - - pri->pRanges = pNewRange; - pri->size = newsize; - bzero(&pri->pRanges[pri->size - SZINCR], SZINCR * sizeof(xRecordRange)); - if (pri->nRanges < nRanges) - pri->nRanges = nRanges; - return Success; -} /* RecordAllocRanges */ - - -/* RecordConvertSetToRanges - * - * Arguments: - * pSet is the set to be converted. - * pri is where the result should be stored. - * byteoffset is the offset from the start of an xRecordRange of the - * two vales (first, last) we are interested in. - * card8 is TRUE if the vales are one byte each and FALSE if two bytes - * each. - * imax is the largest set value to store in pri->pRanges. - * pStartIndex, if non-NULL, is the index of the first range in - * pri->pRanges that should be stored to. If NULL, - * start at index 0. - * - * Returns: BadAlloc if a memory allocation error occurred, else Success. - * - * Side Effects: - * If Success is returned, the slice of pri->pRanges indicated by - * byteoffset and card8 is filled in with the intervals from pSet. - * if pStartIndex was non-NULL, *pStartIndex is filled in with one - * more than the index of the last xRecordRange that was touched. - */ -static int -RecordConvertSetToRanges( - RecordSetPtr pSet, - GetContextRangeInfoPtr pri, - int byteoffset, - Bool card8, - unsigned int imax, - int *pStartIndex -) -{ - int nRanges; - RecordSetIteratePtr pIter = NULL; - RecordSetInterval interval; - CARD8 *pCARD8; - CARD16 *pCARD16; - int err; - - if (!pSet) - return Success; - - nRanges = pStartIndex ? *pStartIndex : 0; - while ((pIter = RecordIterateSet(pSet, pIter, &interval))) - { - if (interval.first > imax) break; - if (interval.last > imax) interval.last = imax; - nRanges++; - if (nRanges > pri->size) - { - err = RecordAllocRanges(pri, nRanges); - if (err != Success) - return err; - } - else - pri->nRanges = max(pri->nRanges, nRanges); - if (card8) - { - pCARD8 = ((CARD8 *)&pri->pRanges[nRanges-1]) + byteoffset; - *pCARD8++ = interval.first; - *pCARD8 = interval.last; - } - else - { - pCARD16 = (CARD16 *) - (((char *)&pri->pRanges[nRanges-1]) + byteoffset); - *pCARD16++ = interval.first; - *pCARD16 = interval.last; - } - } - if (pStartIndex) - *pStartIndex = nRanges; - return Success; -} /* RecordConvertSetToRanges */ - - -/* RecordConvertMinorOpInfoToRanges - * - * Arguments: - * pMinOpInfo is the minor opcode info to convert to xRecordRanges. - * pri is where the result should be stored. - * byteoffset is the offset from the start of an xRecordRange of the - * four vales (CARD8 major_first, CARD8 major_last, - * CARD16 minor_first, CARD16 minor_last) we are going to store. - * - * Returns: BadAlloc if a memory allocation error occurred, else Success. - * - * Side Effects: - * If Success is returned, the slice of pri->pRanges indicated by - * byteoffset is filled in with the information from pMinOpInfo. - */ -static int -RecordConvertMinorOpInfoToRanges( - RecordMinorOpPtr pMinOpInfo, - GetContextRangeInfoPtr pri, - int byteoffset -) -{ - int nsets; - int start; - int i; - int err; - - if (!pMinOpInfo) - return Success; - - nsets = pMinOpInfo->count; - pMinOpInfo++; - start = 0; - for (i = 0; i < nsets; i++) - { - int j, s; - s = start; - err = RecordConvertSetToRanges(pMinOpInfo[i].major.pMinOpSet, pri, - byteoffset + 2, FALSE, 65535, &start); - if (err != Success) return err; - for (j = s; j < start; j++) - { - CARD8 *pCARD8 = ((CARD8 *)&pri->pRanges[j]) + byteoffset; - *pCARD8++ = pMinOpInfo[i].major.first; - *pCARD8 = pMinOpInfo[i].major.last; - } - } - return Success; -} /* RecordConvertMinorOpInfoToRanges */ - - -/* RecordSwapRanges - * - * Arguments: - * pRanges is an array of xRecordRanges. - * nRanges is the number of elements in pRanges. - * - * Returns: nothing. - * - * Side Effects: - * The 16 bit fields of each xRecordRange are byte swapped. - */ -static void -RecordSwapRanges(xRecordRange *pRanges, int nRanges) -{ - int i; - register char n; - for (i = 0; i < nRanges; i++, pRanges++) - { - swaps(&pRanges->extRequestsMinorFirst, n); - swaps(&pRanges->extRequestsMinorLast, n); - swaps(&pRanges->extRepliesMinorFirst, n); - swaps(&pRanges->extRepliesMinorLast, n); - } -} /* RecordSwapRanges */ - - -static int -ProcRecordGetContext(ClientPtr client) -{ - RecordContextPtr pContext; - REQUEST(xRecordGetContextReq); - xRecordGetContextReply rep; - int n; - RecordClientsAndProtocolPtr pRCAP; - int nRCAPs = 0; - GetContextRangeInfoPtr pRangeInfo; - GetContextRangeInfoPtr pri; - int i; - int err; - - REQUEST_SIZE_MATCH(xRecordGetContextReq); - VERIFY_CONTEXT(pContext, stuff->context, client); - - /* how many RCAPs are there on this context? */ - - for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) - nRCAPs++; - - /* allocate and initialize space for record range info */ - - pRangeInfo = (GetContextRangeInfoPtr)xalloc( - nRCAPs * sizeof(GetContextRangeInfoRec)); - if (!pRangeInfo && nRCAPs > 0) - return BadAlloc; - for (i = 0; i < nRCAPs; i++) - { - pRangeInfo[i].pRanges = NULL; - pRangeInfo[i].size = 0; - pRangeInfo[i].nRanges = 0; - } - - /* convert the RCAP (internal) representation of the recorded protocol - * to the wire protocol (external) representation, storing the information - * for the ith RCAP in pri[i] - */ - - for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo; - pRCAP; - pRCAP = pRCAP->pNextRCAP, pri++) - { - xRecordRange rr; - - err = RecordConvertSetToRanges(pRCAP->pRequestMajorOpSet, pri, - offset_of(rr, coreRequestsFirst), TRUE, 127, NULL); - if (err != Success) goto bailout; - - err = RecordConvertSetToRanges(pRCAP->pReplyMajorOpSet, pri, - offset_of(rr, coreRepliesFirst), TRUE, 127, NULL); - if (err != Success) goto bailout; - - err = RecordConvertSetToRanges(pRCAP->pDeliveredEventSet, pri, - offset_of(rr, deliveredEventsFirst), TRUE, 255, NULL); - if (err != Success) goto bailout; - - err = RecordConvertSetToRanges(pRCAP->pDeviceEventSet, pri, - offset_of(rr, deviceEventsFirst), TRUE, 255, NULL); - if (err != Success) goto bailout; - - err = RecordConvertSetToRanges(pRCAP->pErrorSet, pri, - offset_of(rr, errorsFirst), TRUE, 255, NULL); - if (err != Success) goto bailout; - - err = RecordConvertMinorOpInfoToRanges(pRCAP->pRequestMinOpInfo, - pri, offset_of(rr, extRequestsMajorFirst)); - if (err != Success) goto bailout; - - err = RecordConvertMinorOpInfoToRanges(pRCAP->pReplyMinOpInfo, - pri, offset_of(rr, extRepliesMajorFirst)); - if (err != Success) goto bailout; - - if (pRCAP->clientStarted || pRCAP->clientDied) - { - if (pri->nRanges == 0) - RecordAllocRanges(pri, 1); - pri->pRanges[0].clientStarted = pRCAP->clientStarted; - pri->pRanges[0].clientDied = pRCAP->clientDied; - } - } - - /* calculate number of clients and reply length */ - - rep.nClients = 0; - rep.length = 0; - for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo; - pRCAP; - pRCAP = pRCAP->pNextRCAP, pri++) - { - rep.nClients += pRCAP->numClients; - rep.length += pRCAP->numClients * - ( bytes_to_int32(sizeof(xRecordClientInfo)) + - pri->nRanges * bytes_to_int32(sizeof(xRecordRange))); - } - - /* write the reply header */ - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.enabled = pContext->pRecordingClient != NULL; - rep.elementHeader = pContext->elemHeaders; - if(client->swapped) - { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.nClients, n); - } - (void)WriteToClient(client, sizeof(xRecordGetContextReply), - (char *)&rep); - - /* write all the CLIENT_INFOs */ - - for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo; - pRCAP; - pRCAP = pRCAP->pNextRCAP, pri++) - { - xRecordClientInfo rci; - rci.nRanges = pri->nRanges; - if (client->swapped) - { - swapl(&rci.nRanges, n); - RecordSwapRanges(pri->pRanges, pri->nRanges); - } - for (i = 0; i < pRCAP->numClients; i++) - { - rci.clientResource = pRCAP->pClientIDs[i]; - if (client->swapped) swapl(&rci.clientResource, n); - WriteToClient(client, sizeof(xRecordClientInfo), (char *)&rci); - WriteToClient(client, sizeof(xRecordRange) * pri->nRanges, - (char *)pri->pRanges); - } - } - err = client->noClientException; - -bailout: - for (i = 0; i < nRCAPs; i++) - { - if (pRangeInfo[i].pRanges) xfree(pRangeInfo[i].pRanges); - } - xfree(pRangeInfo); - return err; -} /* ProcRecordGetContext */ - - -static int -ProcRecordEnableContext(ClientPtr client) -{ - RecordContextPtr pContext; - REQUEST(xRecordEnableContextReq); - int i; - RecordClientsAndProtocolPtr pRCAP; - - REQUEST_SIZE_MATCH(xRecordGetContextReq); - VERIFY_CONTEXT(pContext, stuff->context, client); - if (pContext->pRecordingClient) - return BadMatch; /* already enabled */ - - /* install record hooks for each RCAP */ - - for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) - { - int err = RecordInstallHooks(pRCAP, 0); - if (err != Success) - { /* undo the previous installs */ - RecordClientsAndProtocolPtr pUninstallRCAP; - for (pUninstallRCAP = pContext->pListOfRCAP; - pUninstallRCAP != pRCAP; - pUninstallRCAP = pUninstallRCAP->pNextRCAP) - { - RecordUninstallHooks(pUninstallRCAP, 0); - } - return err; - } - } - - /* Disallow further request processing on this connection until - * the context is disabled. - */ - IgnoreClient(client); - pContext->pRecordingClient = client; - - /* Don't allow the data connection to record itself; unregister it. */ - RecordDeleteClientFromContext(pContext, - pContext->pRecordingClient->clientAsMask); - - /* move the newly enabled context to the front part of ppAllContexts, - * where all the enabled contexts are - */ - i = RecordFindContextOnAllContexts(pContext); - assert(i >= numEnabledContexts); - if (i != numEnabledContexts) - { - ppAllContexts[i] = ppAllContexts[numEnabledContexts]; - ppAllContexts[numEnabledContexts] = pContext; - } - - ++numEnabledContexts; - assert(numEnabledContexts > 0); - - /* send StartOfData */ - RecordAProtocolElement(pContext, NULL, XRecordStartOfData, NULL, 0, 0); - RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0); - return Success; -} /* ProcRecordEnableContext */ - - -/* RecordDisableContext - * - * Arguments: - * pContext is the context to disable. - * nRanges is the number of elements in pRanges. - * - * Returns: nothing. - * - * Side Effects: - * If the context was enabled, it is disabled. An EndOfData - * message is sent to the recording client. Recording hooks for - * this context are uninstalled. The context is moved to the - * rear part of the ppAllContexts array. numEnabledContexts is - * decremented. Request processing for the formerly recording client - * is resumed. - */ -static void -RecordDisableContext(RecordContextPtr pContext) -{ - RecordClientsAndProtocolPtr pRCAP; - int i; - - if (!pContext->pRecordingClient) return; - if (!pContext->pRecordingClient->clientGone) - { - RecordAProtocolElement(pContext, NULL, XRecordEndOfData, NULL, 0, 0); - RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0); - /* Re-enable request processing on this connection. */ - AttendClient(pContext->pRecordingClient); - } - - for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) - { - RecordUninstallHooks(pRCAP, 0); - } - - pContext->pRecordingClient = NULL; - - /* move the newly disabled context to the rear part of ppAllContexts, - * where all the disabled contexts are - */ - i = RecordFindContextOnAllContexts(pContext); - assert( (i != -1) && (i < numEnabledContexts) ); - if (i != (numEnabledContexts - 1) ) - { - ppAllContexts[i] = ppAllContexts[numEnabledContexts-1]; - ppAllContexts[numEnabledContexts-1] = pContext; - } - --numEnabledContexts; - assert(numEnabledContexts >= 0); -} /* RecordDisableContext */ - - -static int -ProcRecordDisableContext(ClientPtr client) -{ - RecordContextPtr pContext; - REQUEST(xRecordDisableContextReq); - - REQUEST_SIZE_MATCH(xRecordDisableContextReq); - VERIFY_CONTEXT(pContext, stuff->context, client); - RecordDisableContext(pContext); - return Success; -} /* ProcRecordDisableContext */ - - -/* RecordDeleteContext - * - * Arguments: - * value is the context to delete. - * id is its resource ID. - * - * Returns: Success. - * - * Side Effects: - * Disables the context, frees all associated memory, and removes - * it from the ppAllContexts array. - */ -static int -RecordDeleteContext(pointer value, XID id) -{ - int i; - RecordContextPtr pContext = (RecordContextPtr)value; - RecordClientsAndProtocolPtr pRCAP; - - RecordDisableContext(pContext); - - /* Remove all the clients from all the RCAPs. - * As a result, the RCAPs will be freed. - */ - - while ((pRCAP = pContext->pListOfRCAP)) - { - int numClients = pRCAP->numClients; - /* when the last client is deleted, the RCAP will go away. */ - while(numClients--) - { - RecordDeleteClientFromRCAP(pRCAP, numClients); - } - } - - xfree(pContext); - - /* remove context from AllContexts list */ - - if (-1 != (i = RecordFindContextOnAllContexts(pContext))) - { - ppAllContexts[i] = ppAllContexts[numContexts - 1]; - if (--numContexts == 0) - { - xfree(ppAllContexts); - ppAllContexts = NULL; - } - } - return Success; -} /* RecordDeleteContext */ - - -static int -ProcRecordFreeContext(ClientPtr client) -{ - RecordContextPtr pContext; - REQUEST(xRecordFreeContextReq); - - REQUEST_SIZE_MATCH(xRecordFreeContextReq); - VERIFY_CONTEXT(pContext, stuff->context, client); - FreeResource(stuff->context, RT_NONE); - return Success; -} /* ProcRecordFreeContext */ - - -static int -ProcRecordDispatch(ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) - { - case X_RecordQueryVersion: - return ProcRecordQueryVersion(client); - case X_RecordCreateContext: - return ProcRecordCreateContext(client); - case X_RecordRegisterClients: - return ProcRecordRegisterClients(client); - case X_RecordUnregisterClients: - return ProcRecordUnregisterClients(client); - case X_RecordGetContext: - return ProcRecordGetContext(client); - case X_RecordEnableContext: - return ProcRecordEnableContext(client); - case X_RecordDisableContext: - return ProcRecordDisableContext(client); - case X_RecordFreeContext: - return ProcRecordFreeContext(client); - default: - return BadRequest; - } -} /* ProcRecordDispatch */ - - -static int -SProcRecordQueryVersion(ClientPtr client) -{ - REQUEST(xRecordQueryVersionReq); - register char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xRecordQueryVersionReq); - swaps(&stuff->majorVersion, n); - swaps(&stuff->minorVersion,n); - return ProcRecordQueryVersion(client); -} /* SProcRecordQueryVersion */ - - -static int -SwapCreateRegister(xRecordRegisterClientsReq *stuff) -{ - register char n; - int i; - XID *pClientID; - - swapl(&stuff->context, n); - swapl(&stuff->nClients, n); - swapl(&stuff->nRanges, n); - pClientID = (XID *)&stuff[1]; - if (stuff->nClients > stuff->length - bytes_to_int32(sz_xRecordRegisterClientsReq)) - return BadLength; - for (i = 0; i < stuff->nClients; i++, pClientID++) - { - swapl(pClientID, n); - } - if (stuff->nRanges > stuff->length - bytes_to_int32(sz_xRecordRegisterClientsReq) - - stuff->nClients) - return BadLength; - RecordSwapRanges((xRecordRange *)pClientID, stuff->nRanges); - return Success; -} /* SwapCreateRegister */ - - -static int -SProcRecordCreateContext(ClientPtr client) -{ - REQUEST(xRecordCreateContextReq); - int status; - register char n; - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq); - if ((status = SwapCreateRegister((pointer)stuff)) != Success) - return status; - return ProcRecordCreateContext(client); -} /* SProcRecordCreateContext */ - - -static int -SProcRecordRegisterClients(ClientPtr client) -{ - REQUEST(xRecordRegisterClientsReq); - int status; - register char n; - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq); - if ((status = SwapCreateRegister((pointer)stuff)) != Success) - return status; - return ProcRecordRegisterClients(client); -} /* SProcRecordRegisterClients */ - - -static int -SProcRecordUnregisterClients(ClientPtr client) -{ - REQUEST(xRecordUnregisterClientsReq); - register char n; - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq); - swapl(&stuff->context, n); - swapl(&stuff->nClients, n); - SwapRestL(stuff); - return ProcRecordUnregisterClients(client); -} /* SProcRecordUnregisterClients */ - - -static int -SProcRecordGetContext(ClientPtr client) -{ - REQUEST(xRecordGetContextReq); - register char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xRecordGetContextReq); - swapl(&stuff->context, n); - return ProcRecordGetContext(client); -} /* SProcRecordGetContext */ - -static int -SProcRecordEnableContext(ClientPtr client) -{ - REQUEST(xRecordEnableContextReq); - register char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xRecordEnableContextReq); - swapl(&stuff->context, n); - return ProcRecordEnableContext(client); -} /* SProcRecordEnableContext */ - - -static int -SProcRecordDisableContext(ClientPtr client) -{ - REQUEST(xRecordDisableContextReq); - register char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xRecordDisableContextReq); - swapl(&stuff->context, n); - return ProcRecordDisableContext(client); -} /* SProcRecordDisableContext */ - - -static int -SProcRecordFreeContext(ClientPtr client) -{ - REQUEST(xRecordFreeContextReq); - register char n; - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xRecordFreeContextReq); - swapl(&stuff->context, n); - return ProcRecordFreeContext(client); -} /* SProcRecordFreeContext */ - - -static int -SProcRecordDispatch(ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) - { - case X_RecordQueryVersion: - return SProcRecordQueryVersion(client); - case X_RecordCreateContext: - return SProcRecordCreateContext(client); - case X_RecordRegisterClients: - return SProcRecordRegisterClients(client); - case X_RecordUnregisterClients: - return SProcRecordUnregisterClients(client); - case X_RecordGetContext: - return SProcRecordGetContext(client); - case X_RecordEnableContext: - return SProcRecordEnableContext(client); - case X_RecordDisableContext: - return SProcRecordDisableContext(client); - case X_RecordFreeContext: - return SProcRecordFreeContext(client); - default: - return BadRequest; - } -} /* SProcRecordDispatch */ - -/* RecordConnectionSetupInfo - * - * Arguments: - * pContext is an enabled context that specifies recording of - * connection setup info. - * pci holds the connection setup info. - * - * Returns: nothing. - * - * Side Effects: - * The connection setup info is sent to the recording client. - */ -static void -RecordConnectionSetupInfo(RecordContextPtr pContext, NewClientInfoRec *pci) -{ - int prefixsize = SIZEOF(xConnSetupPrefix); - int restsize = pci->prefix->length * 4; - - if (pci->client->swapped) - { - char *pConnSetup = (char *)xalloc(prefixsize + restsize); - if (!pConnSetup) - return; - SwapConnSetupPrefix(pci->prefix, (xConnSetupPrefix*)pConnSetup); - SwapConnSetupInfo((char*)pci->setup, (char*)(pConnSetup + prefixsize)); - RecordAProtocolElement(pContext, pci->client, XRecordClientStarted, - (pointer)pConnSetup, prefixsize + restsize, 0); - xfree(pConnSetup); - } - else - { - /* don't alloc and copy as in the swapped case; just send the - * data in two pieces - */ - RecordAProtocolElement(pContext, pci->client, XRecordClientStarted, - (pointer)pci->prefix, prefixsize, restsize); - RecordAProtocolElement(pContext, pci->client, XRecordClientStarted, - (pointer)pci->setup, restsize, /* continuation */ -1); - } -} /* RecordConnectionSetupInfo */ - - -/* RecordDeleteContext - * - * Arguments: - * pcbl is &ClientStateCallback. - * nullata is NULL. - * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h) - * which contains information about client state changes. - * - * Returns: nothing. - * - * Side Effects: - * If a new client has connected and any contexts have specified - * XRecordFutureClients, the new client is registered on those contexts. - * If any of those contexts specify recording of the connection setup - * info, it is recorded. - * - * If an existing client has disconnected, it is deleted from any - * contexts that it was registered on. If any of those contexts - * specified XRecordClientDied, they record a ClientDied protocol element. - * If the disconnectiong client happened to be the data connection of an - * enabled context, the context is disabled. - */ - -static void -RecordAClientStateChange(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) -{ - NewClientInfoRec *pci = (NewClientInfoRec *)calldata; - int i; - ClientPtr pClient = pci->client; - - switch (pClient->clientState) - { - case ClientStateRunning: /* new client */ - for (i = 0; i < numContexts; i++) - { - RecordClientsAndProtocolPtr pRCAP; - RecordContextPtr pContext = ppAllContexts[i]; - - if ((pRCAP = RecordFindClientOnContext(pContext, - XRecordFutureClients, NULL))) - { - RecordAddClientToRCAP(pRCAP, pClient->clientAsMask); - if (pContext->pRecordingClient && pRCAP->clientStarted) - RecordConnectionSetupInfo(pContext, pci); - } - } - break; - - case ClientStateGone: - case ClientStateRetained: /* client disconnected */ - for (i = 0; i < numContexts; i++) - { - RecordClientsAndProtocolPtr pRCAP; - RecordContextPtr pContext = ppAllContexts[i]; - int pos; - - if (pContext->pRecordingClient == pClient) - RecordDisableContext(pContext); - if ((pRCAP = RecordFindClientOnContext(pContext, - pClient->clientAsMask, &pos))) - { - if (pContext->pRecordingClient && pRCAP->clientDied) - RecordAProtocolElement(pContext, pClient, - XRecordClientDied, NULL, 0, 0); - RecordDeleteClientFromRCAP(pRCAP, pos); - } - } - break; - - default: - break; - } /* end switch on client state */ -} /* RecordAClientStateChange */ - - -/* RecordCloseDown - * - * Arguments: - * extEntry is the extension information for RECORD. - * - * Returns: nothing. - * - * Side Effects: - * Performs any cleanup needed by RECORD at server shutdown time. - * - */ -static void -RecordCloseDown(ExtensionEntry *extEntry) -{ - DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL); -} /* RecordCloseDown */ - - -/* RecordExtensionInit - * - * Arguments: none. - * - * Returns: nothing. - * - * Side Effects: - * Enables the RECORD extension if possible. - */ -void -RecordExtensionInit(void) -{ - ExtensionEntry *extentry; - - RTContext = CreateNewResourceType(RecordDeleteContext, "RecordContext"); - if (!RTContext) - return; - - ppAllContexts = NULL; - numContexts = numEnabledContexts = numEnabledRCAPs = 0; - - if (!AddCallback(&ClientStateCallback, RecordAClientStateChange, NULL)) - return; - - extentry = AddExtension(RECORD_NAME, RecordNumEvents, RecordNumErrors, - ProcRecordDispatch, SProcRecordDispatch, - RecordCloseDown, StandardMinorOpcode); - if (!extentry) - { - DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL); - return; - } - RecordErrorBase = extentry->errorBase; - -} /* RecordExtensionInit */ - + +/* + +Copyright 1995, 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: David P. Wiggins, The Open Group + +This work benefited from earlier work done by Martha Zimet of NCD +and Jim Haggerty of Metheus. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "dixstruct.h" +#include "extnsionst.h" +#include <X11/extensions/recordproto.h> +#include "set.h" +#include "swaprep.h" +#include "inputstr.h" +#include "eventconvert.h" + + +#include <stdio.h> +#include <assert.h> + +#ifdef PANORAMIX +#include "globals.h" +#include "panoramiX.h" +#include "panoramiXsrv.h" +#include "cursor.h" +#endif + +#include "protocol-versions.h" + +static RESTYPE RTContext; /* internal resource type for Record contexts */ +static int RecordErrorBase; /* first Record error number */ + +/* How many bytes of protocol data to buffer in a context. Don't set to less + * than 32. + */ +#define REPLY_BUF_SIZE 1024 + +/* Record Context structure */ + +typedef struct { + XID id; /* resource id of context */ + ClientPtr pRecordingClient; /* client that has context enabled */ + struct _RecordClientsAndProtocolRec *pListOfRCAP; /* all registered info */ + ClientPtr pBufClient; /* client whose protocol is in replyBuffer*/ + unsigned int continuedReply:1; /* recording a reply that is split up? */ + char elemHeaders; /* element header flags (time/seq no.) */ + char bufCategory; /* category of protocol in replyBuffer */ + int numBufBytes; /* number of bytes in replyBuffer */ + char replyBuffer[REPLY_BUF_SIZE]; /* buffered recorded protocol */ +} RecordContextRec, *RecordContextPtr; + +/* RecordMinorOpRec - to hold minor opcode selections for extension requests + * and replies + */ + +typedef union { + int count; /* first element of array: how many "major" structs to follow */ + struct { /* rest of array elements are this */ + short first; /* first major opcode */ + short last; /* last major opcode */ + RecordSetPtr pMinOpSet; /* minor opcode set for above major range */ + } major; +} RecordMinorOpRec, *RecordMinorOpPtr; + + +/* RecordClientsAndProtocolRec, nicknamed RCAP - holds all the client and + * protocol selections passed in a single CreateContext or RegisterClients. + * Generally, a context will have one of these from the create and an + * additional one for each RegisterClients. RCAPs are freed when all their + * clients are unregistered. + */ + +typedef struct _RecordClientsAndProtocolRec { + RecordContextPtr pContext; /* context that owns this RCAP */ + struct _RecordClientsAndProtocolRec *pNextRCAP; /* next RCAP on context */ + RecordSetPtr pRequestMajorOpSet; /* requests to record */ + RecordMinorOpPtr pRequestMinOpInfo; /* extension requests to record */ + RecordSetPtr pReplyMajorOpSet; /* replies to record */ + RecordMinorOpPtr pReplyMinOpInfo; /* extension replies to record */ + RecordSetPtr pDeviceEventSet; /* device events to record */ + RecordSetPtr pDeliveredEventSet; /* delivered events to record */ + RecordSetPtr pErrorSet; /* errors to record */ + XID * pClientIDs; /* array of clients to record */ + short numClients; /* number of clients in pClientIDs */ + short sizeClients; /* size of pClientIDs array */ + unsigned int clientStarted:1; /* record new client connections? */ + unsigned int clientDied:1; /* record client disconnections? */ + unsigned int clientIDsSeparatelyAllocated:1; /* pClientIDs malloced? */ +} RecordClientsAndProtocolRec, *RecordClientsAndProtocolPtr; + +/* how much bigger to make pRCAP->pClientIDs when reallocing */ +#define CLIENT_ARRAY_GROWTH_INCREMENT 4 + +/* counts the total number of RCAPs belonging to enabled contexts. */ +static int numEnabledRCAPs; + +/* void VERIFY_CONTEXT(RecordContextPtr, XID, ClientPtr) + * In the spirit of the VERIFY_* macros in dix.h, this macro fills in + * the context pointer if the given ID is a valid Record Context, else it + * returns an error. + */ +#define VERIFY_CONTEXT(_pContext, _contextid, _client) { \ + int rc = dixLookupResourceByType((pointer *)&(_pContext), _contextid, \ + RTContext, _client, DixUseAccess); \ + if (rc != Success) \ + return (rc == BadValue) ? RecordErrorBase + XRecordBadContext : rc; \ +} + +static int RecordDeleteContext( + pointer /*value*/, + XID /*id*/ +); + +void RecordExtensionInit(void); + +/***************************************************************************/ + +/* client private stuff */ + +/* To make declarations less obfuscated, have a typedef for a pointer to a + * Proc function. + */ +typedef int (*ProcFunctionPtr)( + ClientPtr /*pClient*/ +); + +/* Record client private. Generally a client only has one of these if + * any of its requests are being recorded. + */ +typedef struct { +/* ptr to client's proc vector before Record stuck its nose in */ + ProcFunctionPtr *originalVector; + +/* proc vector with pointers for recorded requests redirected to the + * function RecordARequest + */ + ProcFunctionPtr recordVector[256]; +} RecordClientPrivateRec, *RecordClientPrivatePtr; + +static int RecordClientPrivateKeyIndex; +static DevPrivateKey RecordClientPrivateKey = &RecordClientPrivateKeyIndex; + +/* RecordClientPrivatePtr RecordClientPrivate(ClientPtr) + * gets the client private of the given client. Syntactic sugar. + */ +#define RecordClientPrivate(_pClient) (RecordClientPrivatePtr) \ + dixLookupPrivate(&(_pClient)->devPrivates, RecordClientPrivateKey) + + +/***************************************************************************/ + +/* global list of all contexts */ + +static RecordContextPtr *ppAllContexts; + +static int numContexts;/* number of contexts in ppAllContexts */ + +/* number of currently enabled contexts. All enabled contexts are bunched + * up at the front of the ppAllContexts array, from ppAllContexts[0] to + * ppAllContexts[numEnabledContexts-1], to eliminate time spent skipping + * past disabled contexts. + */ +static int numEnabledContexts; + +/* RecordFindContextOnAllContexts + * + * Arguments: + * pContext is the context to search for. + * + * Returns: + * The index into the array ppAllContexts at which pContext is stored. + * If pContext is not found in ppAllContexts, returns -1. + * + * Side Effects: none. + */ +static int +RecordFindContextOnAllContexts(RecordContextPtr pContext) +{ + int i; + + assert(numContexts >= numEnabledContexts); + for (i = 0; i < numContexts; i++) + { + if (ppAllContexts[i] == pContext) + return i; + } + return -1; +} /* RecordFindContextOnAllContexts */ + + +/***************************************************************************/ + +/* RecordFlushReplyBuffer + * + * Arguments: + * pContext is the context to flush. + * data1 is a pointer to additional data, and len1 is its length in bytes. + * data2 is a pointer to additional data, and len2 is its length in bytes. + * + * Returns: nothing. + * + * Side Effects: + * If the context is enabled, any buffered (recorded) protocol is written + * to the recording client, and the number of buffered bytes is set to + * zero. If len1 is not zero, data1/len1 are then written to the + * recording client, and similarly for data2/len2 (written after + * data1/len1). + */ +static void +RecordFlushReplyBuffer( + RecordContextPtr pContext, + pointer data1, + int len1, + pointer data2, + int len2 +) +{ + if (!pContext->pRecordingClient || pContext->pRecordingClient->clientGone) + return; + if (pContext->numBufBytes) + WriteToClient(pContext->pRecordingClient, pContext->numBufBytes, + (char *)pContext->replyBuffer); + pContext->numBufBytes = 0; + if (len1) + WriteToClient(pContext->pRecordingClient, len1, (char *)data1); + if (len2) + WriteToClient(pContext->pRecordingClient, len2, (char *)data2); +} /* RecordFlushReplyBuffer */ + + +/* RecordAProtocolElement + * + * Arguments: + * pContext is the context that is recording a protocol element. + * pClient is the client whose protocol is being recorded. For + * device events and EndOfData, pClient is NULL. + * category is the category of the protocol element, as defined + * by the RECORD spec. + * data is a pointer to the protocol data, and datalen is its length + * in bytes. + * futurelen is the number of bytes that will be sent in subsequent + * calls to this function to complete this protocol element. + * In those subsequent calls, futurelen will be -1 to indicate + * that the current data is a continuation of the same protocol + * element. + * + * Returns: nothing. + * + * Side Effects: + * The context may be flushed. The new protocol element will be + * added to the context's protocol buffer with appropriate element + * headers prepended (sequence number and timestamp). If the data + * is continuation data (futurelen == -1), element headers won't + * be added. If the protocol element and headers won't fit in + * the context's buffer, it is sent directly to the recording + * client (after any buffered data). + */ +static void +RecordAProtocolElement(RecordContextPtr pContext, ClientPtr pClient, + int category, pointer data, int datalen, int futurelen) +{ + CARD32 elemHeaderData[2]; + int numElemHeaders = 0; + Bool recordingClientSwapped = pContext->pRecordingClient->swapped; + int n; + CARD32 serverTime = 0; + Bool gotServerTime = FALSE; + int replylen; + + if (futurelen >= 0) + { /* start of new protocol element */ + xRecordEnableContextReply *pRep = (xRecordEnableContextReply *) + pContext->replyBuffer; + if (pContext->pBufClient != pClient || + pContext->bufCategory != category) + { + RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0); + pContext->pBufClient = pClient; + pContext->bufCategory = category; + } + + if (!pContext->numBufBytes) + { + serverTime = GetTimeInMillis(); + gotServerTime = TRUE; + pRep->type = X_Reply; + pRep->category = category; + pRep->sequenceNumber = pContext->pRecordingClient->sequence; + pRep->length = 0; + pRep->elementHeader = pContext->elemHeaders; + pRep->serverTime = serverTime; + if (pClient) + { + pRep->clientSwapped = + (pClient->swapped != recordingClientSwapped); + pRep->idBase = pClient->clientAsMask; + pRep->recordedSequenceNumber = pClient->sequence; + } + else /* it's a device event, StartOfData, or EndOfData */ + { + pRep->clientSwapped = (category != XRecordFromServer) && + recordingClientSwapped; + pRep->idBase = 0; + pRep->recordedSequenceNumber = 0; + } + + if (recordingClientSwapped) + { + swaps(&pRep->sequenceNumber, n); + swapl(&pRep->length, n); + swapl(&pRep->idBase, n); + swapl(&pRep->serverTime, n); + swapl(&pRep->recordedSequenceNumber, n); + } + pContext->numBufBytes = SIZEOF(xRecordEnableContextReply); + } + + /* generate element headers if needed */ + + if ( ( (pContext->elemHeaders & XRecordFromClientTime) + && category == XRecordFromClient) + || + ( (pContext->elemHeaders & XRecordFromServerTime) + && category == XRecordFromServer)) + { + if (gotServerTime) + elemHeaderData[numElemHeaders] = serverTime; + else + elemHeaderData[numElemHeaders] = GetTimeInMillis(); + if (recordingClientSwapped) + swapl(&elemHeaderData[numElemHeaders], n); + numElemHeaders++; + } + + if ( (pContext->elemHeaders & XRecordFromClientSequence) + && + (category == XRecordFromClient || category == XRecordClientDied)) + { + elemHeaderData[numElemHeaders] = pClient->sequence; + if (recordingClientSwapped) + swapl(&elemHeaderData[numElemHeaders], n); + numElemHeaders++; + } + + /* adjust reply length */ + + replylen = pRep->length; + if (recordingClientSwapped) swapl(&replylen, n); + replylen += numElemHeaders + bytes_to_int32(datalen) + + bytes_to_int32(futurelen); + if (recordingClientSwapped) swapl(&replylen, n); + pRep->length = replylen; + } /* end if not continued reply */ + + numElemHeaders *= 4; + + /* if space available >= space needed, buffer the data */ + + if (REPLY_BUF_SIZE - pContext->numBufBytes >= datalen + numElemHeaders) + { + if (numElemHeaders) + { + memcpy(pContext->replyBuffer + pContext->numBufBytes, + elemHeaderData, numElemHeaders); + pContext->numBufBytes += numElemHeaders; + } + if (datalen) + { + memcpy(pContext->replyBuffer + pContext->numBufBytes, + data, datalen); + pContext->numBufBytes += datalen; + } + } + else + RecordFlushReplyBuffer(pContext, (pointer)elemHeaderData, + numElemHeaders, (pointer)data, datalen); + +} /* RecordAProtocolElement */ + + +/* RecordFindClientOnContext + * + * Arguments: + * pContext is the context to search. + * clientspec is the resource ID mask identifying the client to search + * for, or XRecordFutureClients. + * pposition is a pointer to an int, or NULL. See Returns. + * + * Returns: + * The RCAP on which clientspec was found, or NULL if not found on + * any RCAP on the given context. + * If pposition was not NULL and the returned RCAP is not NULL, + * *pposition will be set to the index into the returned the RCAP's + * pClientIDs array that holds clientspec. + * + * Side Effects: none. + */ +static RecordClientsAndProtocolPtr +RecordFindClientOnContext( + RecordContextPtr pContext, + XID clientspec, + int *pposition +) +{ + RecordClientsAndProtocolPtr pRCAP; + + for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) + { + int i; + for (i = 0; i < pRCAP->numClients; i++) + { + if (pRCAP->pClientIDs[i] == clientspec) + { + if (pposition) + *pposition = i; + return pRCAP; + } + } + } + return NULL; +} /* RecordFindClientOnContext */ + + +/* RecordABigRequest + * + * Arguments: + * pContext is the recording context. + * client is the client being recorded. + * stuff is a pointer to the big request of client (see the Big Requests + * extension for details.) + * + * Returns: nothing. + * + * Side Effects: + * The big request is recorded with the correct length field re-inserted. + * + * Note: this function exists mainly to make RecordARequest smaller. + */ +static void +RecordABigRequest(RecordContextPtr pContext, ClientPtr client, xReq *stuff) +{ + CARD32 bigLength; + char n; + int bytesLeft; + + /* note: client->req_len has been frobbed by ReadRequestFromClient + * (os/io.c) to discount the extra 4 bytes taken by the extended length + * field in a big request. The actual request length to record is + * client->req_len + 1 (measured in CARD32s). + */ + + /* record the request header */ + bytesLeft = client->req_len << 2; + RecordAProtocolElement(pContext, client, XRecordFromClient, + (pointer)stuff, SIZEOF(xReq), bytesLeft); + + /* reinsert the extended length field that was squished out */ + bigLength = client->req_len + bytes_to_int32(sizeof(bigLength)); + if (client->swapped) + swapl(&bigLength, n); + RecordAProtocolElement(pContext, client, XRecordFromClient, + (pointer)&bigLength, sizeof(bigLength), /* continuation */ -1); + bytesLeft -= sizeof(bigLength); + + /* record the rest of the request after the length */ + RecordAProtocolElement(pContext, client, XRecordFromClient, + (pointer)(stuff + 1), bytesLeft, /* continuation */ -1); +} /* RecordABigRequest */ + + +/* RecordARequest + * + * Arguments: + * client is a client that the server has dispatched a request to by + * calling client->requestVector[request opcode] . + * The request is in client->requestBuffer. + * + * Returns: + * Whatever is returned by the "real" Proc function for this request. + * The "real" Proc function is the function that was in + * client->requestVector[request opcode] before it was replaced by + * RecordARequest. (See the function RecordInstallHooks.) + * + * Side Effects: + * The request is recorded by all contexts that have registered this + * request for this client. The real Proc function is called. + */ +static int +RecordARequest(ClientPtr client) +{ + RecordContextPtr pContext; + RecordClientsAndProtocolPtr pRCAP; + int i; + RecordClientPrivatePtr pClientPriv; + REQUEST(xReq); + int majorop; + + majorop = stuff->reqType; + for (i = 0; i < numEnabledContexts; i++) + { + pContext = ppAllContexts[i]; + pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask, + NULL); + if (pRCAP && pRCAP->pRequestMajorOpSet && + RecordIsMemberOfSet(pRCAP->pRequestMajorOpSet, majorop)) + { + if (majorop <= 127) + { /* core request */ + + if (stuff->length == 0) + RecordABigRequest(pContext, client, stuff); + else + RecordAProtocolElement(pContext, client, XRecordFromClient, + (pointer)stuff, client->req_len << 2, 0); + } + else /* extension, check minor opcode */ + { + int minorop = MinorOpcodeOfRequest(client); + int numMinOpInfo; + RecordMinorOpPtr pMinorOpInfo = pRCAP->pRequestMinOpInfo; + + assert (pMinorOpInfo); + numMinOpInfo = pMinorOpInfo->count; + pMinorOpInfo++; + assert (numMinOpInfo); + for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++) + { + if (majorop >= pMinorOpInfo->major.first && + majorop <= pMinorOpInfo->major.last && + RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet, + minorop)) + { + if (stuff->length == 0) + RecordABigRequest(pContext, client, stuff); + else + RecordAProtocolElement(pContext, client, + XRecordFromClient, (pointer)stuff, + client->req_len << 2, 0); + break; + } + } /* end for each minor op info */ + } /* end extension request */ + } /* end this RCAP wants this major opcode */ + } /* end for each context */ + pClientPriv = RecordClientPrivate(client); + assert(pClientPriv); + return (* pClientPriv->originalVector[majorop])(client); +} /* RecordARequest */ + +/* RecordAReply + * + * Arguments: + * pcbl is &ReplyCallback. + * nulldata is NULL. + * calldata is a pointer to a ReplyInfoRec (include/os.h) + * which provides information about replies that are being sent + * to clients. + * + * Returns: nothing. + * + * Side Effects: + * The reply is recorded by all contexts that have registered this + * reply type for this client. If more data belonging to the same + * reply is expected, and if the reply is being recorded by any + * context, pContext->continuedReply is set to 1. + * If pContext->continuedReply was already 1 and this is the last + * chunk of data belonging to this reply, it is set to 0. + */ +static void +RecordAReply(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) +{ + RecordContextPtr pContext; + RecordClientsAndProtocolPtr pRCAP; + int eci; + int majorop; + ReplyInfoRec *pri = (ReplyInfoRec *)calldata; + ClientPtr client = pri->client; + REQUEST(xReq); + + majorop = stuff->reqType; + for (eci = 0; eci < numEnabledContexts; eci++) + { + pContext = ppAllContexts[eci]; + pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask, + NULL); + if (pRCAP) + { + if (pContext->continuedReply) + { + RecordAProtocolElement(pContext, client, XRecordFromServer, + (pointer)pri->replyData, pri->dataLenBytes, /* continuation */ -1); + if (!pri->bytesRemaining) + pContext->continuedReply = 0; + } + else if (pri->startOfReply && pRCAP->pReplyMajorOpSet && + RecordIsMemberOfSet(pRCAP->pReplyMajorOpSet, majorop)) + { + if (majorop <= 127) + { /* core reply */ + RecordAProtocolElement(pContext, client, XRecordFromServer, + (pointer)pri->replyData, pri->dataLenBytes, pri->bytesRemaining); + if (pri->bytesRemaining) + pContext->continuedReply = 1; + } + else /* extension, check minor opcode */ + { + int minorop = MinorOpcodeOfRequest(client); + int numMinOpInfo; + RecordMinorOpPtr pMinorOpInfo = pRCAP->pReplyMinOpInfo; + assert (pMinorOpInfo); + numMinOpInfo = pMinorOpInfo->count; + pMinorOpInfo++; + assert (numMinOpInfo); + for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++) + { + if (majorop >= pMinorOpInfo->major.first && + majorop <= pMinorOpInfo->major.last && + RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet, + minorop)) + { + RecordAProtocolElement(pContext, client, + XRecordFromServer, (pointer)pri->replyData, + pri->dataLenBytes, pri->bytesRemaining); + if (pri->bytesRemaining) + pContext->continuedReply = 1; + break; + } + } /* end for each minor op info */ + } /* end extension reply */ + } /* end continued reply vs. start of reply */ + } /* end client is registered on this context */ + } /* end for each context */ +} /* RecordAReply */ + + +/* RecordADeliveredEventOrError + * + * Arguments: + * pcbl is &EventCallback. + * nulldata is NULL. + * calldata is a pointer to a EventInfoRec (include/dix.h) + * which provides information about events that are being sent + * to clients. + * + * Returns: nothing. + * + * Side Effects: + * The event or error is recorded by all contexts that have registered + * it for this client. + */ +static void +RecordADeliveredEventOrError(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) +{ + EventInfoRec *pei = (EventInfoRec *)calldata; + RecordContextPtr pContext; + RecordClientsAndProtocolPtr pRCAP; + int eci; /* enabled context index */ + ClientPtr pClient = pei->client; + + for (eci = 0; eci < numEnabledContexts; eci++) + { + pContext = ppAllContexts[eci]; + pRCAP = RecordFindClientOnContext(pContext, pClient->clientAsMask, + NULL); + if (pRCAP && (pRCAP->pDeliveredEventSet || pRCAP->pErrorSet)) + { + int ev; /* event index */ + xEvent *pev = pei->events; + for (ev = 0; ev < pei->count; ev++, pev++) + { + int recordit = 0; + if (pRCAP->pErrorSet) + { + recordit = RecordIsMemberOfSet(pRCAP->pErrorSet, + ((xError *)(pev))->errorCode); + } + else if (pRCAP->pDeliveredEventSet) + { + recordit = RecordIsMemberOfSet(pRCAP->pDeliveredEventSet, + pev->u.u.type & 0177); + } + if (recordit) + { + xEvent swappedEvent; + xEvent *pEvToRecord = pev; + + if (pClient->swapped) + { + (*EventSwapVector[pev->u.u.type & 0177]) + (pev, &swappedEvent); + pEvToRecord = &swappedEvent; + + } + RecordAProtocolElement(pContext, pClient, + XRecordFromServer, pEvToRecord, SIZEOF(xEvent), 0); + } + } /* end for each event */ + } /* end this client is on this context */ + } /* end for each enabled context */ +} /* RecordADeliveredEventOrError */ + + +static void +RecordSendProtocolEvents(RecordClientsAndProtocolPtr pRCAP, + RecordContextPtr pContext, + xEvent* pev, int count) +{ + int ev; /* event index */ + + for (ev = 0; ev < count; ev++, pev++) + { + if (RecordIsMemberOfSet(pRCAP->pDeviceEventSet, + pev->u.u.type & 0177)) + { + xEvent swappedEvent; + xEvent *pEvToRecord = pev; +#ifdef PANORAMIX + xEvent shiftedEvent; + + if (!noPanoramiXExtension && + (pev->u.u.type == MotionNotify || + pev->u.u.type == ButtonPress || + pev->u.u.type == ButtonRelease || + pev->u.u.type == KeyPress || + pev->u.u.type == KeyRelease)) { + int scr = XineramaGetCursorScreen(inputInfo.pointer); + memcpy(&shiftedEvent, pev, sizeof(xEvent)); + shiftedEvent.u.keyButtonPointer.rootX += + panoramiXdataPtr[scr].x - + panoramiXdataPtr[0].x; + shiftedEvent.u.keyButtonPointer.rootY += + panoramiXdataPtr[scr].y - + panoramiXdataPtr[0].y; + pEvToRecord = &shiftedEvent; + } +#endif /* PANORAMIX */ + + if (pContext->pRecordingClient->swapped) + { + (*EventSwapVector[pEvToRecord->u.u.type & 0177]) + (pEvToRecord, &swappedEvent); + pEvToRecord = &swappedEvent; + } + + RecordAProtocolElement(pContext, NULL, + XRecordFromServer, pEvToRecord, SIZEOF(xEvent), 0); + /* make sure device events get flushed in the absence + * of other client activity + */ + SetCriticalOutputPending(); + } + } /* end for each event */ + +} /* RecordADeviceEvent */ + +/* RecordADeviceEvent + * + * Arguments: + * pcbl is &DeviceEventCallback. + * nulldata is NULL. + * calldata is a pointer to a DeviceEventInfoRec (include/dix.h) + * which provides information about device events that occur. + * + * Returns: nothing. + * + * Side Effects: + * The device event is recorded by all contexts that have registered + * it for this client. + */ +static void +RecordADeviceEvent(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) +{ + DeviceEventInfoRec *pei = (DeviceEventInfoRec *)calldata; + RecordContextPtr pContext; + RecordClientsAndProtocolPtr pRCAP; + int eci; /* enabled context index */ + + for (eci = 0; eci < numEnabledContexts; eci++) + { + pContext = ppAllContexts[eci]; + for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) + { + if (pRCAP->pDeviceEventSet) + { + int count; + xEvent *xi_events = NULL; + + /* TODO check return values */ + if (IsMaster(pei->device)) + { + xEvent xE; + EventToCore(pei->event, &xE); + RecordSendProtocolEvents(pRCAP, pContext, &xE, 1); + } + + EventToXI(pei->event, &xi_events, &count); + RecordSendProtocolEvents(pRCAP, pContext, xi_events, count); + free(xi_events); + } /* end this RCAP selects device events */ + } /* end for each RCAP on this context */ + } /* end for each enabled context */ +} + + +/* RecordFlushAllContexts + * + * Arguments: + * pcbl is &FlushCallback. + * nulldata and calldata are NULL. + * + * Returns: nothing. + * + * Side Effects: + * All buffered reply data of all enabled contexts is written to + * the recording clients. + */ +static void +RecordFlushAllContexts( + CallbackListPtr *pcbl, + pointer nulldata, + pointer calldata +) +{ + int eci; /* enabled context index */ + RecordContextPtr pContext; + + for (eci = 0; eci < numEnabledContexts; eci++) + { + pContext = ppAllContexts[eci]; + + /* In most cases we leave it to RecordFlushReplyBuffer to make + * this check, but this function could be called very often, so we + * check before calling hoping to save the function call cost + * most of the time. + */ + if (pContext->numBufBytes) + RecordFlushReplyBuffer(ppAllContexts[eci], NULL, 0, NULL, 0); + } +} /* RecordFlushAllContexts */ + + +/* RecordInstallHooks + * + * Arguments: + * pRCAP is an RCAP on an enabled or being-enabled context. + * oneclient can be zero or the resource ID mask identifying a client. + * + * Returns: BadAlloc if a memory allocation error occurred, else Success. + * + * Side Effects: + * Recording hooks needed by RCAP are installed. + * If oneclient is zero, recording hooks needed for all clients and + * protocol on the RCAP are installed. If oneclient is non-zero, + * only those hooks needed for the specified client are installed. + * + * Client requestVectors may be altered. numEnabledRCAPs will be + * incremented if oneclient == 0. Callbacks may be added to + * various callback lists. + */ +static int +RecordInstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient) +{ + int i = 0; + XID client; + + if (oneclient) + client = oneclient; + else + client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0; + + while (client) + { + if (client != XRecordFutureClients) + { + if (pRCAP->pRequestMajorOpSet) + { + RecordSetIteratePtr pIter = NULL; + RecordSetInterval interval; + ClientPtr pClient = clients[CLIENT_ID(client)]; + + if (pClient && !RecordClientPrivate(pClient)) + { + RecordClientPrivatePtr pClientPriv; + /* no Record proc vector; allocate one */ + pClientPriv = (RecordClientPrivatePtr) + malloc(sizeof(RecordClientPrivateRec)); + if (!pClientPriv) + return BadAlloc; + /* copy old proc vector to new */ + memcpy(pClientPriv->recordVector, pClient->requestVector, + sizeof (pClientPriv->recordVector)); + pClientPriv->originalVector = pClient->requestVector; + dixSetPrivate(&pClient->devPrivates, + RecordClientPrivateKey, pClientPriv); + pClient->requestVector = pClientPriv->recordVector; + } + while ((pIter = RecordIterateSet(pRCAP->pRequestMajorOpSet, + pIter, &interval))) + { + unsigned int j; + for (j = interval.first; j <= interval.last; j++) + pClient->requestVector[j] = RecordARequest; + } + } + } + if (oneclient) + client = 0; + else + client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0; + } + + assert(numEnabledRCAPs >= 0); + if (!oneclient && ++numEnabledRCAPs == 1) + { /* we're enabling the first context */ + if (!AddCallback(&EventCallback, RecordADeliveredEventOrError, NULL)) + return BadAlloc; + if (!AddCallback(&DeviceEventCallback, RecordADeviceEvent, NULL)) + return BadAlloc; + if (!AddCallback(&ReplyCallback, RecordAReply, NULL)) + return BadAlloc; + if (!AddCallback(&FlushCallback, RecordFlushAllContexts, NULL)) + return BadAlloc; + /* Alternate context flushing scheme: delete the line above + * and call RegisterBlockAndWakeupHandlers here passing + * RecordFlushAllContexts. Is this any better? + */ + } + return Success; +} /* RecordInstallHooks */ + + +/* RecordUninstallHooks + * + * Arguments: + * pRCAP is an RCAP on an enabled or being-disabled context. + * oneclient can be zero or the resource ID mask identifying a client. + * + * Returns: nothing. + * + * Side Effects: + * Recording hooks needed by RCAP may be uninstalled. + * If oneclient is zero, recording hooks needed for all clients and + * protocol on the RCAP may be uninstalled. If oneclient is non-zero, + * only those hooks needed for the specified client may be uninstalled. + * + * Client requestVectors may be altered. numEnabledRCAPs will be + * decremented if oneclient == 0. Callbacks may be deleted from + * various callback lists. + */ +static void +RecordUninstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient) +{ + int i = 0; + XID client; + + if (oneclient) + client = oneclient; + else + client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0; + + while (client) + { + if (client != XRecordFutureClients) + { + if (pRCAP->pRequestMajorOpSet) + { + ClientPtr pClient = clients[CLIENT_ID(client)]; + int c; + Bool otherRCAPwantsProcVector = FALSE; + RecordClientPrivatePtr pClientPriv = + RecordClientPrivate(pClient); + + assert (pClient && RecordClientPrivate(pClient)); + memcpy(pClientPriv->recordVector, pClientPriv->originalVector, + sizeof (pClientPriv->recordVector)); + + for (c = 0; c < numEnabledContexts; c++) + { + RecordClientsAndProtocolPtr pOtherRCAP; + RecordContextPtr pContext = ppAllContexts[c]; + + if (pContext == pRCAP->pContext) continue; + pOtherRCAP = RecordFindClientOnContext(pContext, client, + NULL); + if (pOtherRCAP && pOtherRCAP->pRequestMajorOpSet) + { + RecordSetIteratePtr pIter = NULL; + RecordSetInterval interval; + + otherRCAPwantsProcVector = TRUE; + while ((pIter = RecordIterateSet( + pOtherRCAP->pRequestMajorOpSet, + pIter, &interval))) + { + unsigned int j; + for (j = interval.first; j <= interval.last; j++) + pClient->requestVector[j] = RecordARequest; + } + } + } + if (!otherRCAPwantsProcVector) + { /* nobody needs it, so free it */ + pClient->requestVector = pClientPriv->originalVector; + dixSetPrivate(&pClient->devPrivates, + RecordClientPrivateKey, NULL); + free(pClientPriv); + } + } /* end if this RCAP specifies any requests */ + } /* end if not future clients */ + if (oneclient) + client = 0; + else + client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0; + } + + assert(numEnabledRCAPs >= 1); + if (!oneclient && --numEnabledRCAPs == 0) + { /* we're disabling the last context */ + DeleteCallback(&EventCallback, RecordADeliveredEventOrError, NULL); + DeleteCallback(&DeviceEventCallback, RecordADeviceEvent, NULL); + DeleteCallback(&ReplyCallback, RecordAReply, NULL); + DeleteCallback(&FlushCallback, RecordFlushAllContexts, NULL); + /* Alternate context flushing scheme: delete the line above + * and call RemoveBlockAndWakeupHandlers here passing + * RecordFlushAllContexts. Is this any better? + */ + /* Having deleted the callback, call it one last time. -gildea */ + RecordFlushAllContexts(&FlushCallback, NULL, NULL); + } +} /* RecordUninstallHooks */ + + +/* RecordDeleteClientFromRCAP + * + * Arguments: + * pRCAP is an RCAP to delete the client from. + * position is the index into the array pRCAP->pClientIDs of the + * client to delete. + * + * Returns: nothing. + * + * Side Effects: + * Recording hooks needed by client will be uninstalled if the context + * is enabled. The designated client will be removed from the + * pRCAP->pClientIDs array. If it was the only client on the RCAP, + * the RCAP is removed from the context and freed. (Invariant: RCAPs + * have at least one client.) + */ +static void +RecordDeleteClientFromRCAP(RecordClientsAndProtocolPtr pRCAP, int position) +{ + if (pRCAP->pContext->pRecordingClient) + RecordUninstallHooks(pRCAP, pRCAP->pClientIDs[position]); + if (position != pRCAP->numClients - 1) + pRCAP->pClientIDs[position] = pRCAP->pClientIDs[pRCAP->numClients - 1]; + if (--pRCAP->numClients == 0) + { /* no more clients; remove RCAP from context's list */ + RecordContextPtr pContext = pRCAP->pContext; + if (pContext->pRecordingClient) + RecordUninstallHooks(pRCAP, 0); + if (pContext->pListOfRCAP == pRCAP) + pContext->pListOfRCAP = pRCAP->pNextRCAP; + else + { + RecordClientsAndProtocolPtr prevRCAP; + for (prevRCAP = pContext->pListOfRCAP; + prevRCAP->pNextRCAP != pRCAP; + prevRCAP = prevRCAP->pNextRCAP) + ; + prevRCAP->pNextRCAP = pRCAP->pNextRCAP; + } + /* free the RCAP */ + if (pRCAP->clientIDsSeparatelyAllocated) + free(pRCAP->pClientIDs); + free(pRCAP); + } +} /* RecordDeleteClientFromRCAP */ + + +/* RecordAddClientToRCAP + * + * Arguments: + * pRCAP is an RCAP to add the client to. + * clientspec is the resource ID mask identifying a client, or + * XRecordFutureClients. + * + * Returns: nothing. + * + * Side Effects: + * Recording hooks needed by client will be installed if the context + * is enabled. The designated client will be added to the + * pRCAP->pClientIDs array, which may be realloced. + * pRCAP->clientIDsSeparatelyAllocated may be set to 1 if there + * is no more room to hold clients internal to the RCAP. + */ +static void +RecordAddClientToRCAP(RecordClientsAndProtocolPtr pRCAP, XID clientspec) +{ + if (pRCAP->numClients == pRCAP->sizeClients) + { + if (pRCAP->clientIDsSeparatelyAllocated) + { + XID *pNewIDs = (XID *)realloc(pRCAP->pClientIDs, + (pRCAP->sizeClients + CLIENT_ARRAY_GROWTH_INCREMENT) * + sizeof(XID)); + if (!pNewIDs) + return; + pRCAP->pClientIDs = pNewIDs; + pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT; + } + else + { + XID *pNewIDs = (XID *)malloc((pRCAP->sizeClients + + CLIENT_ARRAY_GROWTH_INCREMENT) * sizeof(XID)); + if (!pNewIDs) + return; + memcpy(pNewIDs, pRCAP->pClientIDs, pRCAP->numClients *sizeof(XID)); + pRCAP->pClientIDs = pNewIDs; + pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT; + pRCAP->clientIDsSeparatelyAllocated = 1; + } + } + pRCAP->pClientIDs[pRCAP->numClients++] = clientspec; + if (pRCAP->pContext->pRecordingClient) + RecordInstallHooks(pRCAP, clientspec); +} /* RecordDeleteClientFromRCAP */ + + +/* RecordDeleteClientFromContext + * + * Arguments: + * pContext is the context to delete from. + * clientspec is the resource ID mask identifying a client, or + * XRecordFutureClients. + * + * Returns: nothing. + * + * Side Effects: + * If clientspec is on any RCAP of the context, it is deleted from that + * RCAP. (A given clientspec can only be on one RCAP of a context.) + */ +static void +RecordDeleteClientFromContext(RecordContextPtr pContext, XID clientspec) +{ + RecordClientsAndProtocolPtr pRCAP; + int position; + + if ((pRCAP = RecordFindClientOnContext(pContext, clientspec, &position))) + RecordDeleteClientFromRCAP(pRCAP, position); +} /* RecordDeleteClientFromContext */ + + +/* RecordSanityCheckClientSpecifiers + * + * Arguments: + * clientspecs is an array of alleged CLIENTSPECs passed by the client. + * nspecs is the number of elements in clientspecs. + * errorspec, if non-zero, is the resource id base of a client that + * must not appear in clienspecs. + * + * Returns: BadMatch if any of the clientspecs are invalid, else Success. + * + * Side Effects: none. + */ +static int +RecordSanityCheckClientSpecifiers(ClientPtr client, XID *clientspecs, int nspecs, XID errorspec) +{ + int i; + int clientIndex; + int rc; + pointer value; + + for (i = 0; i < nspecs; i++) + { + if (clientspecs[i] == XRecordCurrentClients || + clientspecs[i] == XRecordFutureClients || + clientspecs[i] == XRecordAllClients) + continue; + if (errorspec && (CLIENT_BITS(clientspecs[i]) == errorspec) ) + return BadMatch; + clientIndex = CLIENT_ID(clientspecs[i]); + if (clientIndex && clients[clientIndex] && + clients[clientIndex]->clientState == ClientStateRunning) + { + if (clientspecs[i] == clients[clientIndex]->clientAsMask) + continue; + rc = dixLookupResourceByClass(&value, clientspecs[i], RC_ANY, + client, DixGetAttrAccess); + if (rc != Success) + return rc; + } + else + return BadMatch; + } + return Success; +} /* RecordSanityCheckClientSpecifiers */ + + +/* RecordCanonicalizeClientSpecifiers + * + * Arguments: + * pClientspecs is an array of CLIENTSPECs that have been sanity + * checked. + * pNumClientspecs is a pointer to the number of elements in pClientspecs. + * excludespec, if non-zero, is the resource id base of a client that + * should not be included in the expansion of XRecordAllClients or + * XRecordCurrentClients. + * + * Returns: + * A pointer to an array of CLIENTSPECs that is the same as the + * passed array with the following modifications: + * - all but the client id bits of resource IDs are stripped off. + * - duplicates removed. + * - XRecordAllClients expanded to a list of all currently connected + * clients + XRecordFutureClients - excludespec (if non-zero) + * - XRecordCurrentClients expanded to a list of all currently + * connected clients - excludespec (if non-zero) + * The returned array may be the passed array modified in place, or + * it may be an malloc'ed array. The caller should keep a pointer to the + * original array and free the returned array if it is different. + * + * *pNumClientspecs is set to the number of elements in the returned + * array. + * + * Side Effects: + * pClientspecs may be modified in place. + */ +static XID * +RecordCanonicalizeClientSpecifiers(XID *pClientspecs, int *pNumClientspecs, XID excludespec) +{ + int i; + int numClients = *pNumClientspecs; + + /* first pass strips off the resource index bits, leaving just the + * client id bits. This makes searching for a particular client simpler + * (and faster.) + */ + for (i = 0; i < numClients; i++) + { + XID cs = pClientspecs[i]; + if (cs > XRecordAllClients) + pClientspecs[i] = CLIENT_BITS(cs); + } + + for (i = 0; i < numClients; i++) + { + if (pClientspecs[i] == XRecordAllClients || + pClientspecs[i] == XRecordCurrentClients) + { /* expand All/Current */ + int j, nc; + XID *pCanon = (XID *)malloc(sizeof(XID) * (currentMaxClients + 1)); + if (!pCanon) return NULL; + for (nc = 0, j = 1; j < currentMaxClients; j++) + { + ClientPtr client = clients[j]; + if (client != NullClient && + client->clientState == ClientStateRunning && + client->clientAsMask != excludespec) + { + pCanon[nc++] = client->clientAsMask; + } + } + if (pClientspecs[i] == XRecordAllClients) + pCanon[nc++] = XRecordFutureClients; + *pNumClientspecs = nc; + return pCanon; + } + else /* not All or Current */ + { + int j; + for (j = i + 1; j < numClients; ) + { + if (pClientspecs[i] == pClientspecs[j]) + { + pClientspecs[j] = pClientspecs[--numClients]; + } + else + j++; + } + } + } /* end for each clientspec */ + *pNumClientspecs = numClients; + return pClientspecs; +} /* RecordCanonicalizeClientSpecifiers */ + + +/****************************************************************************/ + +/* stuff for RegisterClients */ + +/* RecordPadAlign + * + * Arguments: + * size is the number of bytes taken by an object. + * align is a byte boundary (e.g. 4, 8) + * + * Returns: + * the number of pad bytes to add at the end of an object of the + * given size so that an object placed immediately behind it will + * begin on an <align>-byte boundary. + * + * Side Effects: none. + */ +static int +RecordPadAlign(int size, int align) +{ + return (align - (size & (align - 1))) & (align - 1); +} /* RecordPadAlign */ + + +/* RecordSanityCheckRegisterClients + * + * Arguments: + * pContext is the context being registered on. + * client is the client that issued a RecordCreateContext or + * RecordRegisterClients request. + * stuff is a pointer to the request. + * + * Returns: + * Any one of several possible error values if any of the request + * arguments are invalid. Success if everything is OK. + * + * Side Effects: none. + */ +static int +RecordSanityCheckRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff) +{ + int err; + xRecordRange *pRange; + int i; + XID recordingClient; + + if (((client->req_len << 2) - SIZEOF(xRecordRegisterClientsReq)) != + 4 * stuff->nClients + SIZEOF(xRecordRange) * stuff->nRanges) + return BadLength; + + if (stuff->elementHeader & + ~(XRecordFromClientSequence|XRecordFromClientTime|XRecordFromServerTime)) + { + client->errorValue = stuff->elementHeader; + return BadValue; + } + + recordingClient = pContext->pRecordingClient ? + pContext->pRecordingClient->clientAsMask : 0; + err = RecordSanityCheckClientSpecifiers(client, (XID *)&stuff[1], + stuff->nClients, recordingClient); + if (err != Success) return err; + + pRange = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients); + for (i = 0; i < stuff->nRanges; i++, pRange++) + { + if (pRange->coreRequestsFirst > pRange->coreRequestsLast) + { + client->errorValue = pRange->coreRequestsFirst; + return BadValue; + } + if (pRange->coreRepliesFirst > pRange->coreRepliesLast) + { + client->errorValue = pRange->coreRepliesFirst; + return BadValue; + } + if ((pRange->extRequestsMajorFirst || pRange->extRequestsMajorLast) && + (pRange->extRequestsMajorFirst < 128 || + pRange->extRequestsMajorLast < 128 || + pRange->extRequestsMajorFirst > pRange->extRequestsMajorLast)) + { + client->errorValue = pRange->extRequestsMajorFirst; + return BadValue; + } + if (pRange->extRequestsMinorFirst > pRange->extRequestsMinorLast) + { + client->errorValue = pRange->extRequestsMinorFirst; + return BadValue; + } + if ((pRange->extRepliesMajorFirst || pRange->extRepliesMajorLast) && + (pRange->extRepliesMajorFirst < 128 || + pRange->extRepliesMajorLast < 128 || + pRange->extRepliesMajorFirst > pRange->extRepliesMajorLast)) + { + client->errorValue = pRange->extRepliesMajorFirst; + return BadValue; + } + if (pRange->extRepliesMinorFirst > pRange->extRepliesMinorLast) + { + client->errorValue = pRange->extRepliesMinorFirst; + return BadValue; + } + if ((pRange->deliveredEventsFirst || pRange->deliveredEventsLast) && + (pRange->deliveredEventsFirst < 2 || + pRange->deliveredEventsLast < 2 || + pRange->deliveredEventsFirst > pRange->deliveredEventsLast)) + { + client->errorValue = pRange->deliveredEventsFirst; + return BadValue; + } + if ((pRange->deviceEventsFirst || pRange->deviceEventsLast) && + (pRange->deviceEventsFirst < 2 || + pRange->deviceEventsLast < 2 || + pRange->deviceEventsFirst > pRange->deviceEventsLast)) + { + client->errorValue = pRange->deviceEventsFirst; + return BadValue; + } + if (pRange->errorsFirst > pRange->errorsLast) + { + client->errorValue = pRange->errorsFirst; + return BadValue; + } + if (pRange->clientStarted != xFalse && pRange->clientStarted != xTrue) + { + client->errorValue = pRange->clientStarted; + return BadValue; + } + if (pRange->clientDied != xFalse && pRange->clientDied != xTrue) + { + client->errorValue = pRange->clientDied; + return BadValue; + } + } /* end for each range */ + return Success; +} /* end RecordSanityCheckRegisterClients */ + +/* This is a tactical structure used to gather information about all the sets + * (RecordSetPtr) that need to be created for an RCAP in the process of + * digesting a list of RECORDRANGEs (converting it to the internal + * representation). + */ +typedef struct +{ + int nintervals; /* number of intervals in following array */ + RecordSetInterval *intervals; /* array of intervals for this set */ + int size; /* size of intevals array; >= nintervals */ + int align; /* alignment restriction for set */ + int offset; /* where to store set pointer rel. to start of RCAP */ + short first, last; /* if for extension, major opcode interval */ +} SetInfoRec, *SetInfoPtr; + +/* These constant are used to index into an array of SetInfoRec. */ +enum {REQ, /* set info for requests */ + REP, /* set info for replies */ + ERR, /* set info for errors */ + DEV, /* set info for device events */ + DLEV, /* set info for delivered events */ + PREDEFSETS}; /* number of predefined array entries */ + + +/* RecordAllocIntervals + * + * Arguments: + * psi is a pointer to a SetInfoRec whose intervals pointer is NULL. + * nIntervals is the desired size of the intervals array. + * + * Returns: BadAlloc if a memory allocation error occurred, else Success. + * + * Side Effects: + * If Success is returned, psi->intervals is a pointer to size + * RecordSetIntervals, all zeroed, and psi->size is set to size. + */ +static int +RecordAllocIntervals(SetInfoPtr psi, int nIntervals) +{ + assert(!psi->intervals); + psi->intervals = (RecordSetInterval *) + malloc(nIntervals * sizeof(RecordSetInterval)); + if (!psi->intervals) + return BadAlloc; + bzero(psi->intervals, nIntervals * sizeof(RecordSetInterval)); + psi->size = nIntervals; + return Success; +} /* end RecordAllocIntervals */ + + +/* RecordConvertRangesToIntervals + * + * Arguments: + * psi is a pointer to the SetInfoRec we are building. + * pRanges is an array of xRecordRanges. + * nRanges is the number of elements in pRanges. + * byteoffset is the offset from the start of an xRecordRange of the + * two bytes (1 for first, 1 for last) we are interested in. + * pExtSetInfo, if non-NULL, indicates that the two bytes mentioned + * above are followed by four bytes (2 for first, 2 for last) + * representing a minor opcode range, and this information should be + * stored in one of the SetInfoRecs starting at pExtSetInfo. + * pnExtSetInfo is the number of elements in the pExtSetInfo array. + * + * Returns: BadAlloc if a memory allocation error occurred, else Success. + * + * Side Effects: + * The slice of pRanges indicated by byteoffset is stored in psi. + * If pExtSetInfo is non-NULL, minor opcode intervals are stored + * in an existing SetInfoRec if the major opcode interval matches, else + * they are stored in a new SetInfoRec, and *pnExtSetInfo is + * increased accordingly. + */ +static int +RecordConvertRangesToIntervals( + SetInfoPtr psi, + xRecordRange *pRanges, + int nRanges, + int byteoffset, + SetInfoPtr pExtSetInfo, + int *pnExtSetInfo +) +{ + int i; + CARD8 *pCARD8; + int first, last; + int err; + + for (i = 0; i < nRanges; i++, pRanges++) + { + pCARD8 = ((CARD8 *)pRanges) + byteoffset; + first = pCARD8[0]; + last = pCARD8[1]; + if (first || last) + { + if (!psi->intervals) + { + err = RecordAllocIntervals(psi, 2 * (nRanges - i)); + if (err != Success) + return err; + } + psi->intervals[psi->nintervals].first = first; + psi->intervals[psi->nintervals].last = last; + psi->nintervals++; + assert(psi->nintervals <= psi->size); + if (pExtSetInfo) + { + SetInfoPtr pesi = pExtSetInfo; + CARD16 *pCARD16 = (CARD16 *)(pCARD8 + 2); + int j; + + for (j = 0; j < *pnExtSetInfo; j++, pesi++) + { + if ( (first == pesi->first) && (last == pesi->last) ) + break; + } + if (j == *pnExtSetInfo) + { + err = RecordAllocIntervals(pesi, 2 * (nRanges - i)); + if (err != Success) + return err; + pesi->first = first; + pesi->last = last; + (*pnExtSetInfo)++; + } + pesi->intervals[pesi->nintervals].first = pCARD16[0]; + pesi->intervals[pesi->nintervals].last = pCARD16[1]; + pesi->nintervals++; + assert(pesi->nintervals <= pesi->size); + } + } + } + return Success; +} /* end RecordConvertRangesToIntervals */ + +#define offset_of(_structure, _field) \ + ((char *)(& (_structure . _field)) - (char *)(&_structure)) + +/* RecordRegisterClients + * + * Arguments: + * pContext is the context on which to register the clients. + * client is the client that issued the RecordCreateContext or + * RecordRegisterClients request. + * stuff is a pointer to the request. + * + * Returns: + * Any one of several possible error values defined by the protocol. + * Success if everything is OK. + * + * Side Effects: + * If different element headers are specified, the context is flushed. + * If any of the specified clients are already registered on the + * context, they are first unregistered. A new RCAP is created to + * hold the specified protocol and clients, and it is linked onto the + * context. If the context is enabled, appropriate hooks are installed + * to record the new clients and protocol. + */ +static int +RecordRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff) +{ + int err; + int i; + SetInfoPtr si; + int maxSets; + int nExtReqSets = 0; + int nExtRepSets = 0; + int extReqSetsOffset = 0; + int extRepSetsOffset = 0; + SetInfoPtr pExtReqSets, pExtRepSets; + int clientListOffset; + XID *pCanonClients; + int clientStarted = 0, clientDied = 0; + xRecordRange *pRanges, rr; + int nClients; + int sizeClients; + int totRCAPsize; + RecordClientsAndProtocolPtr pRCAP; + int pad; + XID recordingClient; + + /* do all sanity checking up front */ + + err = RecordSanityCheckRegisterClients(pContext, client, stuff); + if (err != Success) + return err; + + /* if element headers changed, flush buffer */ + + if (pContext->elemHeaders != stuff->elementHeader) + { + RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0); + pContext->elemHeaders = stuff->elementHeader; + } + + nClients = stuff->nClients; + if (!nClients) + /* if empty clients list, we're done. */ + return Success; + + recordingClient = pContext->pRecordingClient ? + pContext->pRecordingClient->clientAsMask : 0; + pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1], + &nClients, recordingClient); + if (!pCanonClients) + return BadAlloc; + + /* We may have to create as many as one set for each "predefined" + * protocol types, plus one per range for extension reuests, plus one per + * range for extension replies. + */ + maxSets = PREDEFSETS + 2 * stuff->nRanges; + si = (SetInfoPtr)malloc(sizeof(SetInfoRec) * maxSets); + if (!si) + { + err = BadAlloc; + goto bailout; + } + bzero(si, sizeof(SetInfoRec) * maxSets); + + /* theoretically you must do this because NULL may not be all-bits-zero */ + for (i = 0; i < maxSets; i++) + si[i].intervals = NULL; + + pExtReqSets = si + PREDEFSETS; + pExtRepSets = pExtReqSets + stuff->nRanges; + + pRanges = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients); + + err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges, + offset_of(rr, coreRequestsFirst), NULL, NULL); + if (err != Success) goto bailout; + + err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges, + offset_of(rr, extRequestsMajorFirst), pExtReqSets, &nExtReqSets); + if (err != Success) goto bailout; + + err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges, + offset_of(rr, coreRepliesFirst), NULL, NULL); + if (err != Success) goto bailout; + + err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges, + offset_of(rr, extRepliesMajorFirst), pExtRepSets, &nExtRepSets); + if (err != Success) goto bailout; + + err = RecordConvertRangesToIntervals(&si[ERR], pRanges, stuff->nRanges, + offset_of(rr, errorsFirst), NULL, NULL); + if (err != Success) goto bailout; + + err = RecordConvertRangesToIntervals(&si[DLEV], pRanges, stuff->nRanges, + offset_of(rr, deliveredEventsFirst), NULL, NULL); + if (err != Success) goto bailout; + + err = RecordConvertRangesToIntervals(&si[DEV], pRanges, stuff->nRanges, + offset_of(rr, deviceEventsFirst), NULL, NULL); + if (err != Success) goto bailout; + + /* collect client-started and client-died */ + + for (i = 0; i < stuff->nRanges; i++) + { + if (pRanges[i].clientStarted) clientStarted = TRUE; + if (pRanges[i].clientDied) clientDied = TRUE; + } + + /* We now have all the information collected to create all the sets, + * and we can compute the total memory required for the RCAP. + */ + + totRCAPsize = sizeof(RecordClientsAndProtocolRec); + + /* leave a little room to grow before forcing a separate allocation */ + sizeClients = nClients + CLIENT_ARRAY_GROWTH_INCREMENT; + pad = RecordPadAlign(totRCAPsize, sizeof(XID)); + clientListOffset = totRCAPsize + pad; + totRCAPsize += pad + sizeClients * sizeof(XID); + + if (nExtReqSets) + { + pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr)); + extReqSetsOffset = totRCAPsize + pad; + totRCAPsize += pad + (nExtReqSets + 1) * sizeof(RecordMinorOpRec); + } + if (nExtRepSets) + { + pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr)); + extRepSetsOffset = totRCAPsize + pad; + totRCAPsize += pad + (nExtRepSets + 1) * sizeof(RecordMinorOpRec); + } + + for (i = 0; i < maxSets; i++) + { + if (si[i].nintervals) + { + si[i].size = RecordSetMemoryRequirements( + si[i].intervals, si[i].nintervals, &si[i].align); + pad = RecordPadAlign(totRCAPsize, si[i].align); + si[i].offset = pad + totRCAPsize; + totRCAPsize += pad + si[i].size; + } + } + + /* allocate memory for the whole RCAP */ + + pRCAP = (RecordClientsAndProtocolPtr)malloc(totRCAPsize); + if (!pRCAP) + { + err = BadAlloc; + goto bailout; + } + + /* fill in the RCAP */ + + pRCAP->pContext = pContext; + pRCAP->pClientIDs = (XID *)((char *)pRCAP + clientListOffset); + pRCAP->numClients = nClients; + pRCAP->sizeClients = sizeClients; + pRCAP->clientIDsSeparatelyAllocated = 0; + for (i = 0; i < nClients; i++) + { + RecordDeleteClientFromContext(pContext, pCanonClients[i]); + pRCAP->pClientIDs[i] = pCanonClients[i]; + } + + /* create all the sets */ + + if (si[REQ].intervals) + { + pRCAP->pRequestMajorOpSet = + RecordCreateSet(si[REQ].intervals, si[REQ].nintervals, + (RecordSetPtr)((char *)pRCAP + si[REQ].offset), si[REQ].size); + } + else pRCAP->pRequestMajorOpSet = NULL; + + if (si[REP].intervals) + { + pRCAP->pReplyMajorOpSet = + RecordCreateSet(si[REP].intervals, si[REP].nintervals, + (RecordSetPtr)((char *)pRCAP + si[REP].offset), si[REP].size); + } + else pRCAP->pReplyMajorOpSet = NULL; + + if (si[ERR].intervals) + { + pRCAP->pErrorSet = + RecordCreateSet(si[ERR].intervals, si[ERR].nintervals, + (RecordSetPtr)((char *)pRCAP + si[ERR].offset), si[ERR].size); + } + else pRCAP->pErrorSet = NULL; + + if (si[DEV].intervals) + { + pRCAP->pDeviceEventSet = + RecordCreateSet(si[DEV].intervals, si[DEV].nintervals, + (RecordSetPtr)((char *)pRCAP + si[DEV].offset), si[DEV].size); + } + else pRCAP->pDeviceEventSet = NULL; + + if (si[DLEV].intervals) + { + pRCAP->pDeliveredEventSet = + RecordCreateSet(si[DLEV].intervals, si[DLEV].nintervals, + (RecordSetPtr)((char *)pRCAP + si[DLEV].offset), si[DLEV].size); + } + else pRCAP->pDeliveredEventSet = NULL; + + if (nExtReqSets) + { + pRCAP->pRequestMinOpInfo = (RecordMinorOpPtr) + ((char *)pRCAP + extReqSetsOffset); + pRCAP->pRequestMinOpInfo[0].count = nExtReqSets; + for (i = 0; i < nExtReqSets; i++, pExtReqSets++) + { + pRCAP->pRequestMinOpInfo[i+1].major.first = pExtReqSets->first; + pRCAP->pRequestMinOpInfo[i+1].major.last = pExtReqSets->last; + pRCAP->pRequestMinOpInfo[i+1].major.pMinOpSet = + RecordCreateSet(pExtReqSets->intervals, + pExtReqSets->nintervals, + (RecordSetPtr)((char *)pRCAP + pExtReqSets->offset), + pExtReqSets->size); + } + } + else pRCAP->pRequestMinOpInfo = NULL; + + if (nExtRepSets) + { + pRCAP->pReplyMinOpInfo = (RecordMinorOpPtr) + ((char *)pRCAP + extRepSetsOffset); + pRCAP->pReplyMinOpInfo[0].count = nExtRepSets; + for (i = 0; i < nExtRepSets; i++, pExtRepSets++) + { + pRCAP->pReplyMinOpInfo[i+1].major.first = pExtRepSets->first; + pRCAP->pReplyMinOpInfo[i+1].major.last = pExtRepSets->last; + pRCAP->pReplyMinOpInfo[i+1].major.pMinOpSet = + RecordCreateSet(pExtRepSets->intervals, + pExtRepSets->nintervals, + (RecordSetPtr)((char *)pRCAP + pExtRepSets->offset), + pExtRepSets->size); + } + } + else pRCAP->pReplyMinOpInfo = NULL; + + pRCAP->clientStarted = clientStarted; + pRCAP->clientDied = clientDied; + + /* link the RCAP onto the context */ + + pRCAP->pNextRCAP = pContext->pListOfRCAP; + pContext->pListOfRCAP = pRCAP; + + if (pContext->pRecordingClient) /* context enabled */ + RecordInstallHooks(pRCAP, 0); + +bailout: + if (si) + { + for (i = 0; i < maxSets; i++) + if (si[i].intervals) + free(si[i].intervals); + free(si); + } + if (pCanonClients && pCanonClients != (XID *)&stuff[1]) + free(pCanonClients); + return err; +} /* RecordRegisterClients */ + + +/* Proc functions all take a client argument, execute the request in + * client->requestBuffer, and return a protocol error status. + */ + +static int +ProcRecordQueryVersion(ClientPtr client) +{ + /* REQUEST(xRecordQueryVersionReq); */ + xRecordQueryVersionReply rep; + int n; + + REQUEST_SIZE_MATCH(xRecordQueryVersionReq); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.majorVersion = SERVER_RECORD_MAJOR_VERSION; + rep.minorVersion = SERVER_RECORD_MINOR_VERSION; + if(client->swapped) + { + swaps(&rep.sequenceNumber, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + (void)WriteToClient(client, sizeof(xRecordQueryVersionReply), + (char *)&rep); + return Success; +} /* ProcRecordQueryVersion */ + + +static int +ProcRecordCreateContext(ClientPtr client) +{ + REQUEST(xRecordCreateContextReq); + RecordContextPtr pContext; + RecordContextPtr *ppNewAllContexts = NULL; + int err = BadAlloc; + + REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq); + LEGAL_NEW_RESOURCE(stuff->context, client); + + pContext = (RecordContextPtr)malloc(sizeof(RecordContextRec)); + if (!pContext) + goto bailout; + + /* make sure there is room in ppAllContexts to store the new context */ + + ppNewAllContexts = (RecordContextPtr *) + realloc(ppAllContexts, sizeof(RecordContextPtr) * (numContexts + 1)); + if (!ppNewAllContexts) + goto bailout; + ppAllContexts = ppNewAllContexts; + + pContext->id = stuff->context; + pContext->pRecordingClient = NULL; + pContext->pListOfRCAP = NULL; + pContext->elemHeaders = 0; + pContext->bufCategory = 0; + pContext->numBufBytes = 0; + pContext->pBufClient = NULL; + pContext->continuedReply = 0; + + err = RecordRegisterClients(pContext, client, + (xRecordRegisterClientsReq *)stuff); + if (err != Success) + goto bailout; + + if (AddResource(pContext->id, RTContext, pContext)) + { + ppAllContexts[numContexts++] = pContext; + return Success; + } + else + { + RecordDeleteContext((pointer)pContext, pContext->id); + err = BadAlloc; + } +bailout: + if (pContext) + free(pContext); + return err; +} /* ProcRecordCreateContext */ + + +static int +ProcRecordRegisterClients(ClientPtr client) +{ + RecordContextPtr pContext; + REQUEST(xRecordRegisterClientsReq); + + REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq); + VERIFY_CONTEXT(pContext, stuff->context, client); + + return RecordRegisterClients(pContext, client, stuff); +} /* ProcRecordRegisterClients */ + + +static int +ProcRecordUnregisterClients(ClientPtr client) +{ + RecordContextPtr pContext; + int err; + REQUEST(xRecordUnregisterClientsReq); + XID *pCanonClients; + int nClients; + int i; + + REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq); + if ((client->req_len << 2) - SIZEOF(xRecordUnregisterClientsReq) != + 4 * stuff->nClients) + return BadLength; + VERIFY_CONTEXT(pContext, stuff->context, client); + err = RecordSanityCheckClientSpecifiers(client, (XID *)&stuff[1], + stuff->nClients, 0); + if (err != Success) + return err; + + nClients = stuff->nClients; + pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1], + &nClients, 0); + if (!pCanonClients) + return BadAlloc; + + for (i = 0; i < nClients; i++) + { + RecordDeleteClientFromContext(pContext, pCanonClients[i]); + } + if (pCanonClients != (XID *)&stuff[1]) + free(pCanonClients); + return Success; +} /* ProcRecordUnregisterClients */ + + +/****************************************************************************/ + +/* stuff for GetContext */ + +/* This is a tactical structure used to hold the xRecordRanges as they are + * being reconstituted from the sets in the RCAPs. + */ + +typedef struct { + xRecordRange *pRanges; /* array of xRecordRanges for one RCAP */ + int size; /* number of elements in pRanges, >= nRanges */ + int nRanges; /* number of occupied element of pRanges */ +} GetContextRangeInfoRec, *GetContextRangeInfoPtr; + + +/* RecordAllocRanges + * + * Arguments: + * pri is a pointer to a GetContextRangeInfoRec to allocate for. + * nRanges is the number of xRecordRanges desired for pri. + * + * Returns: BadAlloc if a memory allocation error occurred, else Success. + * + * Side Effects: + * If Success is returned, pri->pRanges points to at least nRanges + * ranges. pri->nRanges is set to nRanges. pri->size is the actual + * number of ranges. Newly allocated ranges are zeroed. + */ +static int +RecordAllocRanges(GetContextRangeInfoPtr pri, int nRanges) +{ + int newsize; + xRecordRange *pNewRange; +#define SZINCR 8 + + newsize = max(pri->size + SZINCR, nRanges); + pNewRange = (xRecordRange *)realloc(pri->pRanges, + newsize * sizeof(xRecordRange)); + if (!pNewRange) + return BadAlloc; + + pri->pRanges = pNewRange; + pri->size = newsize; + bzero(&pri->pRanges[pri->size - SZINCR], SZINCR * sizeof(xRecordRange)); + if (pri->nRanges < nRanges) + pri->nRanges = nRanges; + return Success; +} /* RecordAllocRanges */ + + +/* RecordConvertSetToRanges + * + * Arguments: + * pSet is the set to be converted. + * pri is where the result should be stored. + * byteoffset is the offset from the start of an xRecordRange of the + * two vales (first, last) we are interested in. + * card8 is TRUE if the vales are one byte each and FALSE if two bytes + * each. + * imax is the largest set value to store in pri->pRanges. + * pStartIndex, if non-NULL, is the index of the first range in + * pri->pRanges that should be stored to. If NULL, + * start at index 0. + * + * Returns: BadAlloc if a memory allocation error occurred, else Success. + * + * Side Effects: + * If Success is returned, the slice of pri->pRanges indicated by + * byteoffset and card8 is filled in with the intervals from pSet. + * if pStartIndex was non-NULL, *pStartIndex is filled in with one + * more than the index of the last xRecordRange that was touched. + */ +static int +RecordConvertSetToRanges( + RecordSetPtr pSet, + GetContextRangeInfoPtr pri, + int byteoffset, + Bool card8, + unsigned int imax, + int *pStartIndex +) +{ + int nRanges; + RecordSetIteratePtr pIter = NULL; + RecordSetInterval interval; + CARD8 *pCARD8; + CARD16 *pCARD16; + int err; + + if (!pSet) + return Success; + + nRanges = pStartIndex ? *pStartIndex : 0; + while ((pIter = RecordIterateSet(pSet, pIter, &interval))) + { + if (interval.first > imax) break; + if (interval.last > imax) interval.last = imax; + nRanges++; + if (nRanges > pri->size) + { + err = RecordAllocRanges(pri, nRanges); + if (err != Success) + return err; + } + else + pri->nRanges = max(pri->nRanges, nRanges); + if (card8) + { + pCARD8 = ((CARD8 *)&pri->pRanges[nRanges-1]) + byteoffset; + *pCARD8++ = interval.first; + *pCARD8 = interval.last; + } + else + { + pCARD16 = (CARD16 *) + (((char *)&pri->pRanges[nRanges-1]) + byteoffset); + *pCARD16++ = interval.first; + *pCARD16 = interval.last; + } + } + if (pStartIndex) + *pStartIndex = nRanges; + return Success; +} /* RecordConvertSetToRanges */ + + +/* RecordConvertMinorOpInfoToRanges + * + * Arguments: + * pMinOpInfo is the minor opcode info to convert to xRecordRanges. + * pri is where the result should be stored. + * byteoffset is the offset from the start of an xRecordRange of the + * four vales (CARD8 major_first, CARD8 major_last, + * CARD16 minor_first, CARD16 minor_last) we are going to store. + * + * Returns: BadAlloc if a memory allocation error occurred, else Success. + * + * Side Effects: + * If Success is returned, the slice of pri->pRanges indicated by + * byteoffset is filled in with the information from pMinOpInfo. + */ +static int +RecordConvertMinorOpInfoToRanges( + RecordMinorOpPtr pMinOpInfo, + GetContextRangeInfoPtr pri, + int byteoffset +) +{ + int nsets; + int start; + int i; + int err; + + if (!pMinOpInfo) + return Success; + + nsets = pMinOpInfo->count; + pMinOpInfo++; + start = 0; + for (i = 0; i < nsets; i++) + { + int j, s; + s = start; + err = RecordConvertSetToRanges(pMinOpInfo[i].major.pMinOpSet, pri, + byteoffset + 2, FALSE, 65535, &start); + if (err != Success) return err; + for (j = s; j < start; j++) + { + CARD8 *pCARD8 = ((CARD8 *)&pri->pRanges[j]) + byteoffset; + *pCARD8++ = pMinOpInfo[i].major.first; + *pCARD8 = pMinOpInfo[i].major.last; + } + } + return Success; +} /* RecordConvertMinorOpInfoToRanges */ + + +/* RecordSwapRanges + * + * Arguments: + * pRanges is an array of xRecordRanges. + * nRanges is the number of elements in pRanges. + * + * Returns: nothing. + * + * Side Effects: + * The 16 bit fields of each xRecordRange are byte swapped. + */ +static void +RecordSwapRanges(xRecordRange *pRanges, int nRanges) +{ + int i; + register char n; + for (i = 0; i < nRanges; i++, pRanges++) + { + swaps(&pRanges->extRequestsMinorFirst, n); + swaps(&pRanges->extRequestsMinorLast, n); + swaps(&pRanges->extRepliesMinorFirst, n); + swaps(&pRanges->extRepliesMinorLast, n); + } +} /* RecordSwapRanges */ + + +static int +ProcRecordGetContext(ClientPtr client) +{ + RecordContextPtr pContext; + REQUEST(xRecordGetContextReq); + xRecordGetContextReply rep; + int n; + RecordClientsAndProtocolPtr pRCAP; + int nRCAPs = 0; + GetContextRangeInfoPtr pRangeInfo; + GetContextRangeInfoPtr pri; + int i; + int err; + + REQUEST_SIZE_MATCH(xRecordGetContextReq); + VERIFY_CONTEXT(pContext, stuff->context, client); + + /* how many RCAPs are there on this context? */ + + for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) + nRCAPs++; + + /* allocate and initialize space for record range info */ + + pRangeInfo = (GetContextRangeInfoPtr)malloc( + nRCAPs * sizeof(GetContextRangeInfoRec)); + if (!pRangeInfo && nRCAPs > 0) + return BadAlloc; + for (i = 0; i < nRCAPs; i++) + { + pRangeInfo[i].pRanges = NULL; + pRangeInfo[i].size = 0; + pRangeInfo[i].nRanges = 0; + } + + /* convert the RCAP (internal) representation of the recorded protocol + * to the wire protocol (external) representation, storing the information + * for the ith RCAP in pri[i] + */ + + for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo; + pRCAP; + pRCAP = pRCAP->pNextRCAP, pri++) + { + xRecordRange rr; + + err = RecordConvertSetToRanges(pRCAP->pRequestMajorOpSet, pri, + offset_of(rr, coreRequestsFirst), TRUE, 127, NULL); + if (err != Success) goto bailout; + + err = RecordConvertSetToRanges(pRCAP->pReplyMajorOpSet, pri, + offset_of(rr, coreRepliesFirst), TRUE, 127, NULL); + if (err != Success) goto bailout; + + err = RecordConvertSetToRanges(pRCAP->pDeliveredEventSet, pri, + offset_of(rr, deliveredEventsFirst), TRUE, 255, NULL); + if (err != Success) goto bailout; + + err = RecordConvertSetToRanges(pRCAP->pDeviceEventSet, pri, + offset_of(rr, deviceEventsFirst), TRUE, 255, NULL); + if (err != Success) goto bailout; + + err = RecordConvertSetToRanges(pRCAP->pErrorSet, pri, + offset_of(rr, errorsFirst), TRUE, 255, NULL); + if (err != Success) goto bailout; + + err = RecordConvertMinorOpInfoToRanges(pRCAP->pRequestMinOpInfo, + pri, offset_of(rr, extRequestsMajorFirst)); + if (err != Success) goto bailout; + + err = RecordConvertMinorOpInfoToRanges(pRCAP->pReplyMinOpInfo, + pri, offset_of(rr, extRepliesMajorFirst)); + if (err != Success) goto bailout; + + if (pRCAP->clientStarted || pRCAP->clientDied) + { + if (pri->nRanges == 0) + RecordAllocRanges(pri, 1); + pri->pRanges[0].clientStarted = pRCAP->clientStarted; + pri->pRanges[0].clientDied = pRCAP->clientDied; + } + } + + /* calculate number of clients and reply length */ + + rep.nClients = 0; + rep.length = 0; + for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo; + pRCAP; + pRCAP = pRCAP->pNextRCAP, pri++) + { + rep.nClients += pRCAP->numClients; + rep.length += pRCAP->numClients * + ( bytes_to_int32(sizeof(xRecordClientInfo)) + + pri->nRanges * bytes_to_int32(sizeof(xRecordRange))); + } + + /* write the reply header */ + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.enabled = pContext->pRecordingClient != NULL; + rep.elementHeader = pContext->elemHeaders; + if(client->swapped) + { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.nClients, n); + } + (void)WriteToClient(client, sizeof(xRecordGetContextReply), + (char *)&rep); + + /* write all the CLIENT_INFOs */ + + for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo; + pRCAP; + pRCAP = pRCAP->pNextRCAP, pri++) + { + xRecordClientInfo rci; + rci.nRanges = pri->nRanges; + if (client->swapped) + { + swapl(&rci.nRanges, n); + RecordSwapRanges(pri->pRanges, pri->nRanges); + } + for (i = 0; i < pRCAP->numClients; i++) + { + rci.clientResource = pRCAP->pClientIDs[i]; + if (client->swapped) swapl(&rci.clientResource, n); + WriteToClient(client, sizeof(xRecordClientInfo), (char *)&rci); + WriteToClient(client, sizeof(xRecordRange) * pri->nRanges, + (char *)pri->pRanges); + } + } + err = Success; + +bailout: + for (i = 0; i < nRCAPs; i++) + { + if (pRangeInfo[i].pRanges) free(pRangeInfo[i].pRanges); + } + free(pRangeInfo); + return err; +} /* ProcRecordGetContext */ + + +static int +ProcRecordEnableContext(ClientPtr client) +{ + RecordContextPtr pContext; + REQUEST(xRecordEnableContextReq); + int i; + RecordClientsAndProtocolPtr pRCAP; + + REQUEST_SIZE_MATCH(xRecordGetContextReq); + VERIFY_CONTEXT(pContext, stuff->context, client); + if (pContext->pRecordingClient) + return BadMatch; /* already enabled */ + + /* install record hooks for each RCAP */ + + for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) + { + int err = RecordInstallHooks(pRCAP, 0); + if (err != Success) + { /* undo the previous installs */ + RecordClientsAndProtocolPtr pUninstallRCAP; + for (pUninstallRCAP = pContext->pListOfRCAP; + pUninstallRCAP != pRCAP; + pUninstallRCAP = pUninstallRCAP->pNextRCAP) + { + RecordUninstallHooks(pUninstallRCAP, 0); + } + return err; + } + } + + /* Disallow further request processing on this connection until + * the context is disabled. + */ + IgnoreClient(client); + pContext->pRecordingClient = client; + + /* Don't allow the data connection to record itself; unregister it. */ + RecordDeleteClientFromContext(pContext, + pContext->pRecordingClient->clientAsMask); + + /* move the newly enabled context to the front part of ppAllContexts, + * where all the enabled contexts are + */ + i = RecordFindContextOnAllContexts(pContext); + assert(i >= numEnabledContexts); + if (i != numEnabledContexts) + { + ppAllContexts[i] = ppAllContexts[numEnabledContexts]; + ppAllContexts[numEnabledContexts] = pContext; + } + + ++numEnabledContexts; + assert(numEnabledContexts > 0); + + /* send StartOfData */ + RecordAProtocolElement(pContext, NULL, XRecordStartOfData, NULL, 0, 0); + RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0); + return Success; +} /* ProcRecordEnableContext */ + + +/* RecordDisableContext + * + * Arguments: + * pContext is the context to disable. + * nRanges is the number of elements in pRanges. + * + * Returns: nothing. + * + * Side Effects: + * If the context was enabled, it is disabled. An EndOfData + * message is sent to the recording client. Recording hooks for + * this context are uninstalled. The context is moved to the + * rear part of the ppAllContexts array. numEnabledContexts is + * decremented. Request processing for the formerly recording client + * is resumed. + */ +static void +RecordDisableContext(RecordContextPtr pContext) +{ + RecordClientsAndProtocolPtr pRCAP; + int i; + + if (!pContext->pRecordingClient) return; + if (!pContext->pRecordingClient->clientGone) + { + RecordAProtocolElement(pContext, NULL, XRecordEndOfData, NULL, 0, 0); + RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0); + /* Re-enable request processing on this connection. */ + AttendClient(pContext->pRecordingClient); + } + + for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) + { + RecordUninstallHooks(pRCAP, 0); + } + + pContext->pRecordingClient = NULL; + + /* move the newly disabled context to the rear part of ppAllContexts, + * where all the disabled contexts are + */ + i = RecordFindContextOnAllContexts(pContext); + assert( (i != -1) && (i < numEnabledContexts) ); + if (i != (numEnabledContexts - 1) ) + { + ppAllContexts[i] = ppAllContexts[numEnabledContexts-1]; + ppAllContexts[numEnabledContexts-1] = pContext; + } + --numEnabledContexts; + assert(numEnabledContexts >= 0); +} /* RecordDisableContext */ + + +static int +ProcRecordDisableContext(ClientPtr client) +{ + RecordContextPtr pContext; + REQUEST(xRecordDisableContextReq); + + REQUEST_SIZE_MATCH(xRecordDisableContextReq); + VERIFY_CONTEXT(pContext, stuff->context, client); + RecordDisableContext(pContext); + return Success; +} /* ProcRecordDisableContext */ + + +/* RecordDeleteContext + * + * Arguments: + * value is the context to delete. + * id is its resource ID. + * + * Returns: Success. + * + * Side Effects: + * Disables the context, frees all associated memory, and removes + * it from the ppAllContexts array. + */ +static int +RecordDeleteContext(pointer value, XID id) +{ + int i; + RecordContextPtr pContext = (RecordContextPtr)value; + RecordClientsAndProtocolPtr pRCAP; + + RecordDisableContext(pContext); + + /* Remove all the clients from all the RCAPs. + * As a result, the RCAPs will be freed. + */ + + while ((pRCAP = pContext->pListOfRCAP)) + { + int numClients = pRCAP->numClients; + /* when the last client is deleted, the RCAP will go away. */ + while(numClients--) + { + RecordDeleteClientFromRCAP(pRCAP, numClients); + } + } + + free(pContext); + + /* remove context from AllContexts list */ + + if (-1 != (i = RecordFindContextOnAllContexts(pContext))) + { + ppAllContexts[i] = ppAllContexts[numContexts - 1]; + if (--numContexts == 0) + { + free(ppAllContexts); + ppAllContexts = NULL; + } + } + return Success; +} /* RecordDeleteContext */ + + +static int +ProcRecordFreeContext(ClientPtr client) +{ + RecordContextPtr pContext; + REQUEST(xRecordFreeContextReq); + + REQUEST_SIZE_MATCH(xRecordFreeContextReq); + VERIFY_CONTEXT(pContext, stuff->context, client); + FreeResource(stuff->context, RT_NONE); + return Success; +} /* ProcRecordFreeContext */ + + +static int +ProcRecordDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_RecordQueryVersion: + return ProcRecordQueryVersion(client); + case X_RecordCreateContext: + return ProcRecordCreateContext(client); + case X_RecordRegisterClients: + return ProcRecordRegisterClients(client); + case X_RecordUnregisterClients: + return ProcRecordUnregisterClients(client); + case X_RecordGetContext: + return ProcRecordGetContext(client); + case X_RecordEnableContext: + return ProcRecordEnableContext(client); + case X_RecordDisableContext: + return ProcRecordDisableContext(client); + case X_RecordFreeContext: + return ProcRecordFreeContext(client); + default: + return BadRequest; + } +} /* ProcRecordDispatch */ + + +static int +SProcRecordQueryVersion(ClientPtr client) +{ + REQUEST(xRecordQueryVersionReq); + register char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xRecordQueryVersionReq); + swaps(&stuff->majorVersion, n); + swaps(&stuff->minorVersion,n); + return ProcRecordQueryVersion(client); +} /* SProcRecordQueryVersion */ + + +static int +SwapCreateRegister(xRecordRegisterClientsReq *stuff) +{ + register char n; + int i; + XID *pClientID; + + swapl(&stuff->context, n); + swapl(&stuff->nClients, n); + swapl(&stuff->nRanges, n); + pClientID = (XID *)&stuff[1]; + if (stuff->nClients > stuff->length - bytes_to_int32(sz_xRecordRegisterClientsReq)) + return BadLength; + for (i = 0; i < stuff->nClients; i++, pClientID++) + { + swapl(pClientID, n); + } + if (stuff->nRanges > stuff->length - bytes_to_int32(sz_xRecordRegisterClientsReq) + - stuff->nClients) + return BadLength; + RecordSwapRanges((xRecordRange *)pClientID, stuff->nRanges); + return Success; +} /* SwapCreateRegister */ + + +static int +SProcRecordCreateContext(ClientPtr client) +{ + REQUEST(xRecordCreateContextReq); + int status; + register char n; + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq); + if ((status = SwapCreateRegister((pointer)stuff)) != Success) + return status; + return ProcRecordCreateContext(client); +} /* SProcRecordCreateContext */ + + +static int +SProcRecordRegisterClients(ClientPtr client) +{ + REQUEST(xRecordRegisterClientsReq); + int status; + register char n; + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq); + if ((status = SwapCreateRegister((pointer)stuff)) != Success) + return status; + return ProcRecordRegisterClients(client); +} /* SProcRecordRegisterClients */ + + +static int +SProcRecordUnregisterClients(ClientPtr client) +{ + REQUEST(xRecordUnregisterClientsReq); + register char n; + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq); + swapl(&stuff->context, n); + swapl(&stuff->nClients, n); + SwapRestL(stuff); + return ProcRecordUnregisterClients(client); +} /* SProcRecordUnregisterClients */ + + +static int +SProcRecordGetContext(ClientPtr client) +{ + REQUEST(xRecordGetContextReq); + register char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xRecordGetContextReq); + swapl(&stuff->context, n); + return ProcRecordGetContext(client); +} /* SProcRecordGetContext */ + +static int +SProcRecordEnableContext(ClientPtr client) +{ + REQUEST(xRecordEnableContextReq); + register char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xRecordEnableContextReq); + swapl(&stuff->context, n); + return ProcRecordEnableContext(client); +} /* SProcRecordEnableContext */ + + +static int +SProcRecordDisableContext(ClientPtr client) +{ + REQUEST(xRecordDisableContextReq); + register char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xRecordDisableContextReq); + swapl(&stuff->context, n); + return ProcRecordDisableContext(client); +} /* SProcRecordDisableContext */ + + +static int +SProcRecordFreeContext(ClientPtr client) +{ + REQUEST(xRecordFreeContextReq); + register char n; + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xRecordFreeContextReq); + swapl(&stuff->context, n); + return ProcRecordFreeContext(client); +} /* SProcRecordFreeContext */ + + +static int +SProcRecordDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_RecordQueryVersion: + return SProcRecordQueryVersion(client); + case X_RecordCreateContext: + return SProcRecordCreateContext(client); + case X_RecordRegisterClients: + return SProcRecordRegisterClients(client); + case X_RecordUnregisterClients: + return SProcRecordUnregisterClients(client); + case X_RecordGetContext: + return SProcRecordGetContext(client); + case X_RecordEnableContext: + return SProcRecordEnableContext(client); + case X_RecordDisableContext: + return SProcRecordDisableContext(client); + case X_RecordFreeContext: + return SProcRecordFreeContext(client); + default: + return BadRequest; + } +} /* SProcRecordDispatch */ + +/* RecordConnectionSetupInfo + * + * Arguments: + * pContext is an enabled context that specifies recording of + * connection setup info. + * pci holds the connection setup info. + * + * Returns: nothing. + * + * Side Effects: + * The connection setup info is sent to the recording client. + */ +static void +RecordConnectionSetupInfo(RecordContextPtr pContext, NewClientInfoRec *pci) +{ + int prefixsize = SIZEOF(xConnSetupPrefix); + int restsize = pci->prefix->length * 4; + + if (pci->client->swapped) + { + char *pConnSetup = (char *)malloc(prefixsize + restsize); + if (!pConnSetup) + return; + SwapConnSetupPrefix(pci->prefix, (xConnSetupPrefix*)pConnSetup); + SwapConnSetupInfo((char*)pci->setup, (char*)(pConnSetup + prefixsize)); + RecordAProtocolElement(pContext, pci->client, XRecordClientStarted, + (pointer)pConnSetup, prefixsize + restsize, 0); + free(pConnSetup); + } + else + { + /* don't alloc and copy as in the swapped case; just send the + * data in two pieces + */ + RecordAProtocolElement(pContext, pci->client, XRecordClientStarted, + (pointer)pci->prefix, prefixsize, restsize); + RecordAProtocolElement(pContext, pci->client, XRecordClientStarted, + (pointer)pci->setup, restsize, /* continuation */ -1); + } +} /* RecordConnectionSetupInfo */ + + +/* RecordDeleteContext + * + * Arguments: + * pcbl is &ClientStateCallback. + * nullata is NULL. + * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h) + * which contains information about client state changes. + * + * Returns: nothing. + * + * Side Effects: + * If a new client has connected and any contexts have specified + * XRecordFutureClients, the new client is registered on those contexts. + * If any of those contexts specify recording of the connection setup + * info, it is recorded. + * + * If an existing client has disconnected, it is deleted from any + * contexts that it was registered on. If any of those contexts + * specified XRecordClientDied, they record a ClientDied protocol element. + * If the disconnectiong client happened to be the data connection of an + * enabled context, the context is disabled. + */ + +static void +RecordAClientStateChange(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) +{ + NewClientInfoRec *pci = (NewClientInfoRec *)calldata; + int i; + ClientPtr pClient = pci->client; + + switch (pClient->clientState) + { + case ClientStateRunning: /* new client */ + for (i = 0; i < numContexts; i++) + { + RecordClientsAndProtocolPtr pRCAP; + RecordContextPtr pContext = ppAllContexts[i]; + + if ((pRCAP = RecordFindClientOnContext(pContext, + XRecordFutureClients, NULL))) + { + RecordAddClientToRCAP(pRCAP, pClient->clientAsMask); + if (pContext->pRecordingClient && pRCAP->clientStarted) + RecordConnectionSetupInfo(pContext, pci); + } + } + break; + + case ClientStateGone: + case ClientStateRetained: /* client disconnected */ + for (i = 0; i < numContexts; i++) + { + RecordClientsAndProtocolPtr pRCAP; + RecordContextPtr pContext = ppAllContexts[i]; + int pos; + + if (pContext->pRecordingClient == pClient) + RecordDisableContext(pContext); + if ((pRCAP = RecordFindClientOnContext(pContext, + pClient->clientAsMask, &pos))) + { + if (pContext->pRecordingClient && pRCAP->clientDied) + RecordAProtocolElement(pContext, pClient, + XRecordClientDied, NULL, 0, 0); + RecordDeleteClientFromRCAP(pRCAP, pos); + } + } + break; + + default: + break; + } /* end switch on client state */ +} /* RecordAClientStateChange */ + + +/* RecordCloseDown + * + * Arguments: + * extEntry is the extension information for RECORD. + * + * Returns: nothing. + * + * Side Effects: + * Performs any cleanup needed by RECORD at server shutdown time. + * + */ +static void +RecordCloseDown(ExtensionEntry *extEntry) +{ + DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL); +} /* RecordCloseDown */ + + +/* RecordExtensionInit + * + * Arguments: none. + * + * Returns: nothing. + * + * Side Effects: + * Enables the RECORD extension if possible. + */ +void +RecordExtensionInit(void) +{ + ExtensionEntry *extentry; + + RTContext = CreateNewResourceType(RecordDeleteContext, "RecordContext"); + if (!RTContext) + return; + + ppAllContexts = NULL; + numContexts = numEnabledContexts = numEnabledRCAPs = 0; + + if (!AddCallback(&ClientStateCallback, RecordAClientStateChange, NULL)) + return; + + extentry = AddExtension(RECORD_NAME, RecordNumEvents, RecordNumErrors, + ProcRecordDispatch, SProcRecordDispatch, + RecordCloseDown, StandardMinorOpcode); + if (!extentry) + { + DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL); + return; + } + RecordErrorBase = extentry->errorBase; + +} /* RecordExtensionInit */ + diff --git a/xorg-server/record/set.c b/xorg-server/record/set.c index f0e094eed..12f0d1267 100644 --- a/xorg-server/record/set.c +++ b/xorg-server/record/set.c @@ -1,431 +1,431 @@ -/* - -Copyright 1995, 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. - -*/ - -/* - - See the header set.h for a description of the set ADT. - - Implementation Strategy - - A bit vector is an obvious choice to represent the set, but may take - too much memory, depending on the numerically largest member in the - set. One expected common case is for the client to ask for *all* - protocol. This means it would ask for minor opcodes 0 through 65535. - Representing this as a bit vector takes 8K -- and there may be - multiple minor opcode intervals, as many as one per major (extension) - opcode). In such cases, a list-of-intervals representation would be - preferable to reduce memory consumption. Both representations will be - implemented, and RecordCreateSet will decide heuristically which one - to use based on the set members. - -*/ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <string.h> - -#include "misc.h" -#include "set.h" - -static int -maxMemberInInterval(RecordSetInterval *pIntervals, int nIntervals) -{ - int i; - int maxMember = -1; - for (i = 0; i < nIntervals; i++) - { - if (maxMember < (int)pIntervals[i].last) - maxMember = pIntervals[i].last; - } - return maxMember; -} - -static void -NoopDestroySet(RecordSetPtr pSet) -{ -} - -/***************************************************************************/ - -/* set operations for bit vector representation */ - -typedef struct { - RecordSetRec baseSet; - int maxMember; - /* followed by the bit vector itself */ -} BitVectorSet, *BitVectorSetPtr; - -#define BITS_PER_LONG (sizeof(unsigned long) * 8) - -static void -BitVectorDestroySet(RecordSetPtr pSet) -{ - xfree(pSet); -} - -static unsigned long -BitVectorIsMemberOfSet(RecordSetPtr pSet, int pm) -{ - BitVectorSetPtr pbvs = (BitVectorSetPtr)pSet; - unsigned long *pbitvec; - - if ((int)pm > pbvs->maxMember) return FALSE; - pbitvec = (unsigned long *)(&pbvs[1]); - return (pbitvec[pm / BITS_PER_LONG] & ((unsigned long)1 << (pm % BITS_PER_LONG))); -} - - -static int -BitVectorFindBit(RecordSetPtr pSet, int iterbit, Bool bitval) -{ - BitVectorSetPtr pbvs = (BitVectorSetPtr)pSet; - unsigned long *pbitvec = (unsigned long *)(&pbvs[1]); - int startlong; - int startbit; - int walkbit; - int maxMember; - unsigned long skipval; - unsigned long bits; - unsigned long usefulbits; - - startlong = iterbit / BITS_PER_LONG; - pbitvec += startlong; - startbit = startlong * BITS_PER_LONG; - skipval = bitval ? 0L : ~0L; - maxMember = pbvs->maxMember; - - - if (startbit > maxMember) return -1; - bits = *pbitvec; - usefulbits = ~(((unsigned long)1 << (iterbit - startbit)) - 1); - if ( (bits & usefulbits) == (skipval & usefulbits) ) - { - pbitvec++; - startbit += BITS_PER_LONG; - - while (startbit <= maxMember && *pbitvec == skipval) - { - pbitvec++; - startbit += BITS_PER_LONG; - } - if (startbit > maxMember) return -1; - } - - walkbit = (startbit < iterbit) ? iterbit - startbit : 0; - - bits = *pbitvec; - while (walkbit < BITS_PER_LONG && ((!(bits & ((unsigned long)1 << walkbit))) == bitval)) - walkbit++; - - return startbit + walkbit; -} - - -static RecordSetIteratePtr -BitVectorIterateSet(RecordSetPtr pSet, RecordSetIteratePtr pIter, - RecordSetInterval *pInterval) -{ - int iterbit = (int)(long)pIter; - int b; - - b = BitVectorFindBit(pSet, iterbit, TRUE); - if (b == -1) return (RecordSetIteratePtr)0; - pInterval->first = b; - - b = BitVectorFindBit(pSet, b, FALSE); - pInterval->last = (b < 0) ? ((BitVectorSetPtr)pSet)->maxMember : b - 1; - return (RecordSetIteratePtr)(long)(pInterval->last + 1); -} - -static RecordSetOperations BitVectorSetOperations = { - BitVectorDestroySet, BitVectorIsMemberOfSet, BitVectorIterateSet }; - -static RecordSetOperations BitVectorNoFreeOperations = { - NoopDestroySet, BitVectorIsMemberOfSet, BitVectorIterateSet }; - -static int -BitVectorSetMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals, - int maxMember, int *alignment) -{ - int nlongs; - - *alignment = sizeof(unsigned long); - nlongs = (maxMember + BITS_PER_LONG) / BITS_PER_LONG; - return (sizeof(BitVectorSet) + nlongs * sizeof(unsigned long)); -} - -static RecordSetPtr -BitVectorCreateSet(RecordSetInterval *pIntervals, int nIntervals, - void *pMem, int memsize) -{ - BitVectorSetPtr pbvs; - int i, j; - unsigned long *pbitvec; - - /* allocate all storage needed by this set in one chunk */ - - if (pMem) - { - memset(pMem, 0, memsize); - pbvs = (BitVectorSetPtr)pMem; - pbvs->baseSet.ops = &BitVectorNoFreeOperations; - } - else - { - pbvs = (BitVectorSetPtr)Xcalloc(memsize); - if (!pbvs) return NULL; - pbvs->baseSet.ops = &BitVectorSetOperations; - } - - pbvs->maxMember = maxMemberInInterval(pIntervals, nIntervals); - - /* fill in the set */ - - pbitvec = (unsigned long *)(&pbvs[1]); - for (i = 0; i < nIntervals; i++) - { - for (j = pIntervals[i].first; j <= (int)pIntervals[i].last; j++) - { - pbitvec[j/BITS_PER_LONG] |= ((unsigned long)1 << (j % BITS_PER_LONG)); - } - } - return (RecordSetPtr)pbvs; -} - - -/***************************************************************************/ - -/* set operations for interval list representation */ - -typedef struct { - RecordSetRec baseSet; - int nIntervals; - /* followed by the intervals (RecordSetInterval) */ -} IntervalListSet, *IntervalListSetPtr; - -static void -IntervalListDestroySet(RecordSetPtr pSet) -{ - xfree(pSet); -} - -static unsigned long -IntervalListIsMemberOfSet(RecordSetPtr pSet, int pm) -{ - IntervalListSetPtr prls = (IntervalListSetPtr)pSet; - RecordSetInterval *pInterval = (RecordSetInterval *)(&prls[1]); - int hi, lo, probe; - - /* binary search */ - lo = 0; hi = prls->nIntervals - 1; - while (lo <= hi) - { - probe = (hi + lo) / 2; - if (pm >= pInterval[probe].first && pm <= pInterval[probe].last) return 1; - else if (pm < pInterval[probe].first) hi = probe - 1; - else lo = probe + 1; - } - return 0; -} - - -static RecordSetIteratePtr -IntervalListIterateSet(RecordSetPtr pSet, RecordSetIteratePtr pIter, - RecordSetInterval *pIntervalReturn) -{ - RecordSetInterval *pInterval = (RecordSetInterval *)pIter; - IntervalListSetPtr prls = (IntervalListSetPtr)pSet; - - if (pInterval == NULL) - { - pInterval = (RecordSetInterval *)(&prls[1]); - } - - if ( (pInterval - (RecordSetInterval *)(&prls[1])) < prls->nIntervals ) - { - *pIntervalReturn = *pInterval; - return (RecordSetIteratePtr)(++pInterval); - } - else - return (RecordSetIteratePtr)NULL; -} - -static RecordSetOperations IntervalListSetOperations = { - IntervalListDestroySet, IntervalListIsMemberOfSet, IntervalListIterateSet }; - -static RecordSetOperations IntervalListNoFreeOperations = { - NoopDestroySet, IntervalListIsMemberOfSet, IntervalListIterateSet }; - -static int -IntervalListMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals, - int maxMember, int *alignment) -{ - *alignment = sizeof(unsigned long); - return sizeof(IntervalListSet) + nIntervals * sizeof(RecordSetInterval); -} - -static RecordSetPtr -IntervalListCreateSet(RecordSetInterval *pIntervals, int nIntervals, - void *pMem, int memsize) -{ - IntervalListSetPtr prls; - int i, j, k; - RecordSetInterval *stackIntervals = NULL; - CARD16 first; - - if (nIntervals > 0) - { - stackIntervals = (RecordSetInterval *)xalloc( - sizeof(RecordSetInterval) * nIntervals); - if (!stackIntervals) return NULL; - - /* sort intervals, store in stackIntervals (insertion sort) */ - - for (i = 0; i < nIntervals; i++) - { - first = pIntervals[i].first; - for (j = 0; j < i; j++) - { - if (first < stackIntervals[j].first) - break; - } - for (k = i; k > j; k--) - { - stackIntervals[k] = stackIntervals[k-1]; - } - stackIntervals[j] = pIntervals[i]; - } - - /* merge abutting/overlapping intervals */ - - for (i = 0; i < nIntervals - 1; ) - { - if ( (stackIntervals[i].last + (unsigned int)1) < - stackIntervals[i + 1].first) - { - i++; /* disjoint intervals */ - } - else - { - stackIntervals[i].last = max(stackIntervals[i].last, - stackIntervals[i + 1].last); - nIntervals--; - for (j = i + 1; j < nIntervals; j++) - stackIntervals[j] = stackIntervals[j + 1]; - } - } - } - - /* allocate and fill in set structure */ - - if (pMem) - { - prls = (IntervalListSetPtr)pMem; - prls->baseSet.ops = &IntervalListNoFreeOperations; - } - else - { - prls = (IntervalListSetPtr) - xalloc(sizeof(IntervalListSet) + nIntervals * sizeof(RecordSetInterval)); - if (!prls) goto bailout; - prls->baseSet.ops = &IntervalListSetOperations; - } - memcpy(&prls[1], stackIntervals, nIntervals * sizeof(RecordSetInterval)); - prls->nIntervals = nIntervals; -bailout: - if (stackIntervals) xfree(stackIntervals); - return (RecordSetPtr)prls; -} - -typedef RecordSetPtr (*RecordCreateSetProcPtr)( - RecordSetInterval *pIntervals, - int nIntervals, - void *pMem, - int memsize -); - -static int -_RecordSetMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals, - int *alignment, - RecordCreateSetProcPtr *ppCreateSet) -{ - int bmsize, rlsize, bma, rla; - int maxMember; - - /* find maximum member of set so we know how big to make the bit vector */ - maxMember = maxMemberInInterval(pIntervals, nIntervals); - - bmsize = BitVectorSetMemoryRequirements(pIntervals, nIntervals, maxMember, - &bma); - rlsize = IntervalListMemoryRequirements(pIntervals, nIntervals, maxMember, - &rla); - if ( ( (nIntervals > 1) && (maxMember <= 255) ) - || (bmsize < rlsize) ) - { - *alignment = bma; - *ppCreateSet = BitVectorCreateSet; - return bmsize; - } - else - { - *alignment = rla; - *ppCreateSet = IntervalListCreateSet; - return rlsize; - } -} - -/***************************************************************************/ - -/* user-visible functions */ - -int -RecordSetMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals, int *alignment) -{ - RecordCreateSetProcPtr pCreateSet; - return _RecordSetMemoryRequirements(pIntervals, nIntervals, alignment, - &pCreateSet); -} - -RecordSetPtr -RecordCreateSet(RecordSetInterval *pIntervals, int nIntervals, void *pMem, int memsize) -{ - RecordCreateSetProcPtr pCreateSet; - int alignment; - int size; - - size = _RecordSetMemoryRequirements(pIntervals, nIntervals, &alignment, - &pCreateSet); - if (pMem) - { - if ( ((long)pMem & (alignment-1) ) || memsize < size) - return NULL; - } - return (*pCreateSet)(pIntervals, nIntervals, pMem, size); -} +/* + +Copyright 1995, 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. + +*/ + +/* + + See the header set.h for a description of the set ADT. + + Implementation Strategy + + A bit vector is an obvious choice to represent the set, but may take + too much memory, depending on the numerically largest member in the + set. One expected common case is for the client to ask for *all* + protocol. This means it would ask for minor opcodes 0 through 65535. + Representing this as a bit vector takes 8K -- and there may be + multiple minor opcode intervals, as many as one per major (extension) + opcode). In such cases, a list-of-intervals representation would be + preferable to reduce memory consumption. Both representations will be + implemented, and RecordCreateSet will decide heuristically which one + to use based on the set members. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "misc.h" +#include "set.h" + +static int +maxMemberInInterval(RecordSetInterval *pIntervals, int nIntervals) +{ + int i; + int maxMember = -1; + for (i = 0; i < nIntervals; i++) + { + if (maxMember < (int)pIntervals[i].last) + maxMember = pIntervals[i].last; + } + return maxMember; +} + +static void +NoopDestroySet(RecordSetPtr pSet) +{ +} + +/***************************************************************************/ + +/* set operations for bit vector representation */ + +typedef struct { + RecordSetRec baseSet; + int maxMember; + /* followed by the bit vector itself */ +} BitVectorSet, *BitVectorSetPtr; + +#define BITS_PER_LONG (sizeof(unsigned long) * 8) + +static void +BitVectorDestroySet(RecordSetPtr pSet) +{ + free(pSet); +} + +static unsigned long +BitVectorIsMemberOfSet(RecordSetPtr pSet, int pm) +{ + BitVectorSetPtr pbvs = (BitVectorSetPtr)pSet; + unsigned long *pbitvec; + + if ((int)pm > pbvs->maxMember) return FALSE; + pbitvec = (unsigned long *)(&pbvs[1]); + return (pbitvec[pm / BITS_PER_LONG] & ((unsigned long)1 << (pm % BITS_PER_LONG))); +} + + +static int +BitVectorFindBit(RecordSetPtr pSet, int iterbit, Bool bitval) +{ + BitVectorSetPtr pbvs = (BitVectorSetPtr)pSet; + unsigned long *pbitvec = (unsigned long *)(&pbvs[1]); + int startlong; + int startbit; + int walkbit; + int maxMember; + unsigned long skipval; + unsigned long bits; + unsigned long usefulbits; + + startlong = iterbit / BITS_PER_LONG; + pbitvec += startlong; + startbit = startlong * BITS_PER_LONG; + skipval = bitval ? 0L : ~0L; + maxMember = pbvs->maxMember; + + + if (startbit > maxMember) return -1; + bits = *pbitvec; + usefulbits = ~(((unsigned long)1 << (iterbit - startbit)) - 1); + if ( (bits & usefulbits) == (skipval & usefulbits) ) + { + pbitvec++; + startbit += BITS_PER_LONG; + + while (startbit <= maxMember && *pbitvec == skipval) + { + pbitvec++; + startbit += BITS_PER_LONG; + } + if (startbit > maxMember) return -1; + } + + walkbit = (startbit < iterbit) ? iterbit - startbit : 0; + + bits = *pbitvec; + while (walkbit < BITS_PER_LONG && ((!(bits & ((unsigned long)1 << walkbit))) == bitval)) + walkbit++; + + return startbit + walkbit; +} + + +static RecordSetIteratePtr +BitVectorIterateSet(RecordSetPtr pSet, RecordSetIteratePtr pIter, + RecordSetInterval *pInterval) +{ + int iterbit = (int)(long)pIter; + int b; + + b = BitVectorFindBit(pSet, iterbit, TRUE); + if (b == -1) return (RecordSetIteratePtr)0; + pInterval->first = b; + + b = BitVectorFindBit(pSet, b, FALSE); + pInterval->last = (b < 0) ? ((BitVectorSetPtr)pSet)->maxMember : b - 1; + return (RecordSetIteratePtr)(long)(pInterval->last + 1); +} + +static RecordSetOperations BitVectorSetOperations = { + BitVectorDestroySet, BitVectorIsMemberOfSet, BitVectorIterateSet }; + +static RecordSetOperations BitVectorNoFreeOperations = { + NoopDestroySet, BitVectorIsMemberOfSet, BitVectorIterateSet }; + +static int +BitVectorSetMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals, + int maxMember, int *alignment) +{ + int nlongs; + + *alignment = sizeof(unsigned long); + nlongs = (maxMember + BITS_PER_LONG) / BITS_PER_LONG; + return (sizeof(BitVectorSet) + nlongs * sizeof(unsigned long)); +} + +static RecordSetPtr +BitVectorCreateSet(RecordSetInterval *pIntervals, int nIntervals, + void *pMem, int memsize) +{ + BitVectorSetPtr pbvs; + int i, j; + unsigned long *pbitvec; + + /* allocate all storage needed by this set in one chunk */ + + if (pMem) + { + memset(pMem, 0, memsize); + pbvs = (BitVectorSetPtr)pMem; + pbvs->baseSet.ops = &BitVectorNoFreeOperations; + } + else + { + pbvs = (BitVectorSetPtr)calloc(1, memsize); + if (!pbvs) return NULL; + pbvs->baseSet.ops = &BitVectorSetOperations; + } + + pbvs->maxMember = maxMemberInInterval(pIntervals, nIntervals); + + /* fill in the set */ + + pbitvec = (unsigned long *)(&pbvs[1]); + for (i = 0; i < nIntervals; i++) + { + for (j = pIntervals[i].first; j <= (int)pIntervals[i].last; j++) + { + pbitvec[j/BITS_PER_LONG] |= ((unsigned long)1 << (j % BITS_PER_LONG)); + } + } + return (RecordSetPtr)pbvs; +} + + +/***************************************************************************/ + +/* set operations for interval list representation */ + +typedef struct { + RecordSetRec baseSet; + int nIntervals; + /* followed by the intervals (RecordSetInterval) */ +} IntervalListSet, *IntervalListSetPtr; + +static void +IntervalListDestroySet(RecordSetPtr pSet) +{ + free(pSet); +} + +static unsigned long +IntervalListIsMemberOfSet(RecordSetPtr pSet, int pm) +{ + IntervalListSetPtr prls = (IntervalListSetPtr)pSet; + RecordSetInterval *pInterval = (RecordSetInterval *)(&prls[1]); + int hi, lo, probe; + + /* binary search */ + lo = 0; hi = prls->nIntervals - 1; + while (lo <= hi) + { + probe = (hi + lo) / 2; + if (pm >= pInterval[probe].first && pm <= pInterval[probe].last) return 1; + else if (pm < pInterval[probe].first) hi = probe - 1; + else lo = probe + 1; + } + return 0; +} + + +static RecordSetIteratePtr +IntervalListIterateSet(RecordSetPtr pSet, RecordSetIteratePtr pIter, + RecordSetInterval *pIntervalReturn) +{ + RecordSetInterval *pInterval = (RecordSetInterval *)pIter; + IntervalListSetPtr prls = (IntervalListSetPtr)pSet; + + if (pInterval == NULL) + { + pInterval = (RecordSetInterval *)(&prls[1]); + } + + if ( (pInterval - (RecordSetInterval *)(&prls[1])) < prls->nIntervals ) + { + *pIntervalReturn = *pInterval; + return (RecordSetIteratePtr)(++pInterval); + } + else + return (RecordSetIteratePtr)NULL; +} + +static RecordSetOperations IntervalListSetOperations = { + IntervalListDestroySet, IntervalListIsMemberOfSet, IntervalListIterateSet }; + +static RecordSetOperations IntervalListNoFreeOperations = { + NoopDestroySet, IntervalListIsMemberOfSet, IntervalListIterateSet }; + +static int +IntervalListMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals, + int maxMember, int *alignment) +{ + *alignment = sizeof(unsigned long); + return sizeof(IntervalListSet) + nIntervals * sizeof(RecordSetInterval); +} + +static RecordSetPtr +IntervalListCreateSet(RecordSetInterval *pIntervals, int nIntervals, + void *pMem, int memsize) +{ + IntervalListSetPtr prls; + int i, j, k; + RecordSetInterval *stackIntervals = NULL; + CARD16 first; + + if (nIntervals > 0) + { + stackIntervals = (RecordSetInterval *)malloc( + sizeof(RecordSetInterval) * nIntervals); + if (!stackIntervals) return NULL; + + /* sort intervals, store in stackIntervals (insertion sort) */ + + for (i = 0; i < nIntervals; i++) + { + first = pIntervals[i].first; + for (j = 0; j < i; j++) + { + if (first < stackIntervals[j].first) + break; + } + for (k = i; k > j; k--) + { + stackIntervals[k] = stackIntervals[k-1]; + } + stackIntervals[j] = pIntervals[i]; + } + + /* merge abutting/overlapping intervals */ + + for (i = 0; i < nIntervals - 1; ) + { + if ( (stackIntervals[i].last + (unsigned int)1) < + stackIntervals[i + 1].first) + { + i++; /* disjoint intervals */ + } + else + { + stackIntervals[i].last = max(stackIntervals[i].last, + stackIntervals[i + 1].last); + nIntervals--; + for (j = i + 1; j < nIntervals; j++) + stackIntervals[j] = stackIntervals[j + 1]; + } + } + } + + /* allocate and fill in set structure */ + + if (pMem) + { + prls = (IntervalListSetPtr)pMem; + prls->baseSet.ops = &IntervalListNoFreeOperations; + } + else + { + prls = (IntervalListSetPtr) + malloc(sizeof(IntervalListSet) + nIntervals * sizeof(RecordSetInterval)); + if (!prls) goto bailout; + prls->baseSet.ops = &IntervalListSetOperations; + } + memcpy(&prls[1], stackIntervals, nIntervals * sizeof(RecordSetInterval)); + prls->nIntervals = nIntervals; +bailout: + if (stackIntervals) free(stackIntervals); + return (RecordSetPtr)prls; +} + +typedef RecordSetPtr (*RecordCreateSetProcPtr)( + RecordSetInterval *pIntervals, + int nIntervals, + void *pMem, + int memsize +); + +static int +_RecordSetMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals, + int *alignment, + RecordCreateSetProcPtr *ppCreateSet) +{ + int bmsize, rlsize, bma, rla; + int maxMember; + + /* find maximum member of set so we know how big to make the bit vector */ + maxMember = maxMemberInInterval(pIntervals, nIntervals); + + bmsize = BitVectorSetMemoryRequirements(pIntervals, nIntervals, maxMember, + &bma); + rlsize = IntervalListMemoryRequirements(pIntervals, nIntervals, maxMember, + &rla); + if ( ( (nIntervals > 1) && (maxMember <= 255) ) + || (bmsize < rlsize) ) + { + *alignment = bma; + *ppCreateSet = BitVectorCreateSet; + return bmsize; + } + else + { + *alignment = rla; + *ppCreateSet = IntervalListCreateSet; + return rlsize; + } +} + +/***************************************************************************/ + +/* user-visible functions */ + +int +RecordSetMemoryRequirements(RecordSetInterval *pIntervals, int nIntervals, int *alignment) +{ + RecordCreateSetProcPtr pCreateSet; + return _RecordSetMemoryRequirements(pIntervals, nIntervals, alignment, + &pCreateSet); +} + +RecordSetPtr +RecordCreateSet(RecordSetInterval *pIntervals, int nIntervals, void *pMem, int memsize) +{ + RecordCreateSetProcPtr pCreateSet; + int alignment; + int size; + + size = _RecordSetMemoryRequirements(pIntervals, nIntervals, &alignment, + &pCreateSet); + if (pMem) + { + if ( ((long)pMem & (alignment-1) ) || memsize < size) + return NULL; + } + return (*pCreateSet)(pIntervals, nIntervals, pMem, size); +} diff --git a/xorg-server/render/animcur.c b/xorg-server/render/animcur.c index 276e5e4af..dd44bd17f 100644 --- a/xorg-server/render/animcur.c +++ b/xorg-server/render/animcur.c @@ -1,430 +1,430 @@ -/* - * - * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. - * - * 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. - */ - -/* - * Animated cursors for X. Not specific to Render in any way, but - * stuck there because Render has the other cool cursor extension. - * Besides, everyone has Render. - * - * Implemented as a simple layer over the core cursor code; it - * creates composite cursors out of a set of static cursors and - * delta times between each image. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xmd.h> -#include "servermd.h" -#include "scrnintstr.h" -#include "dixstruct.h" -#include "cursorstr.h" -#include "dixfontstr.h" -#include "opaque.h" -#include "picturestr.h" -#include "inputstr.h" -#include "xace.h" - -typedef struct _AnimCurElt { - CursorPtr pCursor; /* cursor to show */ - CARD32 delay; /* in ms */ -} AnimCurElt; - -typedef struct _AnimCur { - int nelt; /* number of elements in the elts array */ - AnimCurElt *elts; /* actually allocated right after the structure */ -} AnimCurRec, *AnimCurPtr; - -typedef struct _AnimScrPriv { - CursorPtr pCursor; - int elt; - CARD32 time; - - CloseScreenProcPtr CloseScreen; - - ScreenBlockHandlerProcPtr BlockHandler; - - CursorLimitsProcPtr CursorLimits; - DisplayCursorProcPtr DisplayCursor; - SetCursorPositionProcPtr SetCursorPosition; - RealizeCursorProcPtr RealizeCursor; - UnrealizeCursorProcPtr UnrealizeCursor; - RecolorCursorProcPtr RecolorCursor; -} AnimCurScreenRec, *AnimCurScreenPtr; - -typedef struct _AnimCurState { - CursorPtr pCursor; - ScreenPtr pScreen; - int elt; - CARD32 time; -} AnimCurStateRec, *AnimCurStatePtr; - -/* What a waste. But we need an API change to alloc it per device only. */ -static AnimCurStateRec animCurState[MAXDEVICES]; - -static unsigned char empty[4]; - -static CursorBits animCursorBits = { - empty, empty, 2, 1, 1, 0, 0, 1 -}; - -static int AnimCurGeneration; - -static int AnimCurScreenPrivateKeyIndex; -static DevPrivateKey AnimCurScreenPrivateKey = &AnimCurScreenPrivateKeyIndex; - -#define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits)) -#define GetAnimCur(c) ((AnimCurPtr) ((c) + 1)) -#define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey)) -#define GetAnimCurScreenIfSet(s) GetAnimCurScreen(s) -#define SetAnimCurScreen(s,p) dixSetPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey, p) - -#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) -#define Unwrap(as,s,elt) ((s)->elt = (as)->elt) - - -static Bool -AnimCurCloseScreen (int index, ScreenPtr pScreen) -{ - AnimCurScreenPtr as = GetAnimCurScreen(pScreen); - Bool ret; - - Unwrap(as, pScreen, CloseScreen); - - Unwrap(as, pScreen, BlockHandler); - - Unwrap(as, pScreen, CursorLimits); - Unwrap(as, pScreen, DisplayCursor); - Unwrap(as, pScreen, SetCursorPosition); - Unwrap(as, pScreen, RealizeCursor); - Unwrap(as, pScreen, UnrealizeCursor); - Unwrap(as, pScreen, RecolorCursor); - SetAnimCurScreen(pScreen,0); - ret = (*pScreen->CloseScreen) (index, pScreen); - xfree (as); - return ret; -} - -static void -AnimCurCursorLimits (DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor, - BoxPtr pHotBox, - BoxPtr pTopLeftBox) -{ - AnimCurScreenPtr as = GetAnimCurScreen(pScreen); - - Unwrap (as, pScreen, CursorLimits); - if (IsAnimCur(pCursor)) - { - AnimCurPtr ac = GetAnimCur(pCursor); - - (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor, - pHotBox, pTopLeftBox); - } - else - { - (*pScreen->CursorLimits) (pDev, pScreen, pCursor, - pHotBox, pTopLeftBox); - } - Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits); -} - -/* - * This has to be a screen block handler instead of a generic - * block handler so that it is well ordered with respect to the DRI - * block handler responsible for releasing the hardware to DRI clients - */ - -static void -AnimCurScreenBlockHandler (int screenNum, - pointer blockData, - pointer pTimeout, - pointer pReadmask) -{ - ScreenPtr pScreen = screenInfo.screens[screenNum]; - AnimCurScreenPtr as = GetAnimCurScreen(pScreen); - DeviceIntPtr dev; - CARD32 now = 0, - soonest = ~0; /* earliest time to wakeup again */ - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (IsPointerDevice(dev) && pScreen == animCurState[dev->id].pScreen) - { - if (!now) now = GetTimeInMillis (); - - if ((INT32) (now - animCurState[dev->id].time) >= 0) - { - AnimCurPtr ac = GetAnimCur(animCurState[dev->id].pCursor); - int elt = (animCurState[dev->id].elt + 1) % ac->nelt; - DisplayCursorProcPtr DisplayCursor; - - /* - * Not a simple Unwrap/Wrap as this - * isn't called along the DisplayCursor - * wrapper chain. - */ - DisplayCursor = pScreen->DisplayCursor; - pScreen->DisplayCursor = as->DisplayCursor; - (void) (*pScreen->DisplayCursor) (dev, - pScreen, - ac->elts[elt].pCursor); - as->DisplayCursor = pScreen->DisplayCursor; - pScreen->DisplayCursor = DisplayCursor; - - animCurState[dev->id].elt = elt; - animCurState[dev->id].time = now + ac->elts[elt].delay; - } - - if (soonest > animCurState[dev->id].time) - soonest = animCurState[dev->id].time; - } - } - - if (now) - AdjustWaitForDelay (pTimeout, soonest - now); - - Unwrap (as, pScreen, BlockHandler); - (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); - Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler); -} - -static Bool -AnimCurDisplayCursor (DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor) -{ - AnimCurScreenPtr as = GetAnimCurScreen(pScreen); - Bool ret; - - Unwrap (as, pScreen, DisplayCursor); - if (IsAnimCur(pCursor)) - { - if (pCursor != animCurState[pDev->id].pCursor) - { - AnimCurPtr ac = GetAnimCur(pCursor); - - ret = (*pScreen->DisplayCursor) - (pDev, pScreen, ac->elts[0].pCursor); - if (ret) - { - animCurState[pDev->id].elt = 0; - animCurState[pDev->id].time = GetTimeInMillis () + ac->elts[0].delay; - animCurState[pDev->id].pCursor = pCursor; - animCurState[pDev->id].pScreen = pScreen; - } - } - else - ret = TRUE; - } - else - { - animCurState[pDev->id].pCursor = 0; - animCurState[pDev->id].pScreen = 0; - ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); - } - Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor); - return ret; -} - -static Bool -AnimCurSetCursorPosition (DeviceIntPtr pDev, - ScreenPtr pScreen, - int x, - int y, - Bool generateEvent) -{ - AnimCurScreenPtr as = GetAnimCurScreen(pScreen); - Bool ret; - - Unwrap (as, pScreen, SetCursorPosition); - if (animCurState[pDev->id].pCursor) - animCurState[pDev->id].pScreen = pScreen; - ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent); - Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); - return ret; -} - -static Bool -AnimCurRealizeCursor (DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor) -{ - AnimCurScreenPtr as = GetAnimCurScreen(pScreen); - Bool ret; - - Unwrap (as, pScreen, RealizeCursor); - if (IsAnimCur(pCursor)) - ret = TRUE; - else - ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor); - Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor); - return ret; -} - -static Bool -AnimCurUnrealizeCursor (DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor) -{ - AnimCurScreenPtr as = GetAnimCurScreen(pScreen); - Bool ret; - - Unwrap (as, pScreen, UnrealizeCursor); - if (IsAnimCur(pCursor)) - { - AnimCurPtr ac = GetAnimCur(pCursor); - int i; - - if (pScreen->myNum == 0) - for (i = 0; i < ac->nelt; i++) - FreeCursor (ac->elts[i].pCursor, 0); - ret = TRUE; - } - else - ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); - Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); - return ret; -} - -static void -AnimCurRecolorCursor (DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor, - Bool displayed) -{ - AnimCurScreenPtr as = GetAnimCurScreen(pScreen); - - Unwrap (as, pScreen, RecolorCursor); - if (IsAnimCur(pCursor)) - { - AnimCurPtr ac = GetAnimCur(pCursor); - int i; - - for (i = 0; i < ac->nelt; i++) - (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor, - displayed && - animCurState[pDev->id].elt == i); - } - else - (*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed); - Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor); -} - -Bool -AnimCurInit (ScreenPtr pScreen) -{ - AnimCurScreenPtr as; - - if (AnimCurGeneration != serverGeneration) - { - int i; - AnimCurGeneration = serverGeneration; - for (i = 0; i < MAXDEVICES; i++) { - animCurState[i].pCursor = 0; - animCurState[i].pScreen = 0; - animCurState[i].elt = 0; - animCurState[i].time = 0; - } - } - as = (AnimCurScreenPtr) xalloc (sizeof (AnimCurScreenRec)); - if (!as) - return FALSE; - Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen); - - Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); - - Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); - Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); - Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); - Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); - Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); - Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); - SetAnimCurScreen(pScreen,as); - return TRUE; -} - -int -AnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor, ClientPtr client, XID cid) -{ - CursorPtr pCursor; - int rc, i; - AnimCurPtr ac; - - for (i = 0; i < screenInfo.numScreens; i++) - if (!GetAnimCurScreenIfSet (screenInfo.screens[i])) - return BadImplementation; - - for (i = 0; i < ncursor; i++) - if (IsAnimCur (cursors[i])) - return BadMatch; - - pCursor = (CursorPtr) xalloc (sizeof (CursorRec) + - sizeof (AnimCurRec) + - ncursor * sizeof (AnimCurElt)); - if (!pCursor) - return BadAlloc; - pCursor->bits = &animCursorBits; - pCursor->refcnt = 1; - - pCursor->foreRed = cursors[0]->foreRed; - pCursor->foreGreen = cursors[0]->foreGreen; - pCursor->foreBlue = cursors[0]->foreBlue; - - pCursor->backRed = cursors[0]->backRed; - pCursor->backGreen = cursors[0]->backGreen; - pCursor->backBlue = cursors[0]->backBlue; - - pCursor->id = cid; - pCursor->devPrivates = NULL; - - /* security creation/labeling check */ - rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor, - RT_NONE, NULL, DixCreateAccess); - if (rc != Success) { - dixFreePrivates(pCursor->devPrivates); - xfree(pCursor); - return rc; - } - - /* - * Fill in the AnimCurRec - */ - animCursorBits.refcnt++; - ac = GetAnimCur (pCursor); - ac->nelt = ncursor; - ac->elts = (AnimCurElt *) (ac + 1); - - for (i = 0; i < ncursor; i++) - { - cursors[i]->refcnt++; - ac->elts[i].pCursor = cursors[i]; - ac->elts[i].delay = deltas[i]; - } - - *ppCursor = pCursor; - return Success; -} +/* + * + * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. + * + * 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. + */ + +/* + * Animated cursors for X. Not specific to Render in any way, but + * stuck there because Render has the other cool cursor extension. + * Besides, everyone has Render. + * + * Implemented as a simple layer over the core cursor code; it + * creates composite cursors out of a set of static cursors and + * delta times between each image. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include "servermd.h" +#include "scrnintstr.h" +#include "dixstruct.h" +#include "cursorstr.h" +#include "dixfontstr.h" +#include "opaque.h" +#include "picturestr.h" +#include "inputstr.h" +#include "xace.h" + +typedef struct _AnimCurElt { + CursorPtr pCursor; /* cursor to show */ + CARD32 delay; /* in ms */ +} AnimCurElt; + +typedef struct _AnimCur { + int nelt; /* number of elements in the elts array */ + AnimCurElt *elts; /* actually allocated right after the structure */ +} AnimCurRec, *AnimCurPtr; + +typedef struct _AnimScrPriv { + CursorPtr pCursor; + int elt; + CARD32 time; + + CloseScreenProcPtr CloseScreen; + + ScreenBlockHandlerProcPtr BlockHandler; + + CursorLimitsProcPtr CursorLimits; + DisplayCursorProcPtr DisplayCursor; + SetCursorPositionProcPtr SetCursorPosition; + RealizeCursorProcPtr RealizeCursor; + UnrealizeCursorProcPtr UnrealizeCursor; + RecolorCursorProcPtr RecolorCursor; +} AnimCurScreenRec, *AnimCurScreenPtr; + +typedef struct _AnimCurState { + CursorPtr pCursor; + ScreenPtr pScreen; + int elt; + CARD32 time; +} AnimCurStateRec, *AnimCurStatePtr; + +/* What a waste. But we need an API change to alloc it per device only. */ +static AnimCurStateRec animCurState[MAXDEVICES]; + +static unsigned char empty[4]; + +static CursorBits animCursorBits = { + empty, empty, 2, 1, 1, 0, 0, 1 +}; + +static int AnimCurGeneration; + +static int AnimCurScreenPrivateKeyIndex; +static DevPrivateKey AnimCurScreenPrivateKey = &AnimCurScreenPrivateKeyIndex; + +#define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits)) +#define GetAnimCur(c) ((AnimCurPtr) ((c) + 1)) +#define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey)) +#define GetAnimCurScreenIfSet(s) GetAnimCurScreen(s) +#define SetAnimCurScreen(s,p) dixSetPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey, p) + +#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) +#define Unwrap(as,s,elt) ((s)->elt = (as)->elt) + + +static Bool +AnimCurCloseScreen (int index, ScreenPtr pScreen) +{ + AnimCurScreenPtr as = GetAnimCurScreen(pScreen); + Bool ret; + + Unwrap(as, pScreen, CloseScreen); + + Unwrap(as, pScreen, BlockHandler); + + Unwrap(as, pScreen, CursorLimits); + Unwrap(as, pScreen, DisplayCursor); + Unwrap(as, pScreen, SetCursorPosition); + Unwrap(as, pScreen, RealizeCursor); + Unwrap(as, pScreen, UnrealizeCursor); + Unwrap(as, pScreen, RecolorCursor); + SetAnimCurScreen(pScreen,0); + ret = (*pScreen->CloseScreen) (index, pScreen); + free(as); + return ret; +} + +static void +AnimCurCursorLimits (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor, + BoxPtr pHotBox, + BoxPtr pTopLeftBox) +{ + AnimCurScreenPtr as = GetAnimCurScreen(pScreen); + + Unwrap (as, pScreen, CursorLimits); + if (IsAnimCur(pCursor)) + { + AnimCurPtr ac = GetAnimCur(pCursor); + + (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor, + pHotBox, pTopLeftBox); + } + else + { + (*pScreen->CursorLimits) (pDev, pScreen, pCursor, + pHotBox, pTopLeftBox); + } + Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits); +} + +/* + * This has to be a screen block handler instead of a generic + * block handler so that it is well ordered with respect to the DRI + * block handler responsible for releasing the hardware to DRI clients + */ + +static void +AnimCurScreenBlockHandler (int screenNum, + pointer blockData, + pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + AnimCurScreenPtr as = GetAnimCurScreen(pScreen); + DeviceIntPtr dev; + CARD32 now = 0, + soonest = ~0; /* earliest time to wakeup again */ + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (IsPointerDevice(dev) && pScreen == animCurState[dev->id].pScreen) + { + if (!now) now = GetTimeInMillis (); + + if ((INT32) (now - animCurState[dev->id].time) >= 0) + { + AnimCurPtr ac = GetAnimCur(animCurState[dev->id].pCursor); + int elt = (animCurState[dev->id].elt + 1) % ac->nelt; + DisplayCursorProcPtr DisplayCursor; + + /* + * Not a simple Unwrap/Wrap as this + * isn't called along the DisplayCursor + * wrapper chain. + */ + DisplayCursor = pScreen->DisplayCursor; + pScreen->DisplayCursor = as->DisplayCursor; + (void) (*pScreen->DisplayCursor) (dev, + pScreen, + ac->elts[elt].pCursor); + as->DisplayCursor = pScreen->DisplayCursor; + pScreen->DisplayCursor = DisplayCursor; + + animCurState[dev->id].elt = elt; + animCurState[dev->id].time = now + ac->elts[elt].delay; + } + + if (soonest > animCurState[dev->id].time) + soonest = animCurState[dev->id].time; + } + } + + if (now) + AdjustWaitForDelay (pTimeout, soonest - now); + + Unwrap (as, pScreen, BlockHandler); + (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); + Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler); +} + +static Bool +AnimCurDisplayCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) +{ + AnimCurScreenPtr as = GetAnimCurScreen(pScreen); + Bool ret; + + Unwrap (as, pScreen, DisplayCursor); + if (IsAnimCur(pCursor)) + { + if (pCursor != animCurState[pDev->id].pCursor) + { + AnimCurPtr ac = GetAnimCur(pCursor); + + ret = (*pScreen->DisplayCursor) + (pDev, pScreen, ac->elts[0].pCursor); + if (ret) + { + animCurState[pDev->id].elt = 0; + animCurState[pDev->id].time = GetTimeInMillis () + ac->elts[0].delay; + animCurState[pDev->id].pCursor = pCursor; + animCurState[pDev->id].pScreen = pScreen; + } + } + else + ret = TRUE; + } + else + { + animCurState[pDev->id].pCursor = 0; + animCurState[pDev->id].pScreen = 0; + ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); + } + Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor); + return ret; +} + +static Bool +AnimCurSetCursorPosition (DeviceIntPtr pDev, + ScreenPtr pScreen, + int x, + int y, + Bool generateEvent) +{ + AnimCurScreenPtr as = GetAnimCurScreen(pScreen); + Bool ret; + + Unwrap (as, pScreen, SetCursorPosition); + if (animCurState[pDev->id].pCursor) + animCurState[pDev->id].pScreen = pScreen; + ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent); + Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); + return ret; +} + +static Bool +AnimCurRealizeCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) +{ + AnimCurScreenPtr as = GetAnimCurScreen(pScreen); + Bool ret; + + Unwrap (as, pScreen, RealizeCursor); + if (IsAnimCur(pCursor)) + ret = TRUE; + else + ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor); + Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor); + return ret; +} + +static Bool +AnimCurUnrealizeCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) +{ + AnimCurScreenPtr as = GetAnimCurScreen(pScreen); + Bool ret; + + Unwrap (as, pScreen, UnrealizeCursor); + if (IsAnimCur(pCursor)) + { + AnimCurPtr ac = GetAnimCur(pCursor); + int i; + + if (pScreen->myNum == 0) + for (i = 0; i < ac->nelt; i++) + FreeCursor (ac->elts[i].pCursor, 0); + ret = TRUE; + } + else + ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); + Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); + return ret; +} + +static void +AnimCurRecolorCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor, + Bool displayed) +{ + AnimCurScreenPtr as = GetAnimCurScreen(pScreen); + + Unwrap (as, pScreen, RecolorCursor); + if (IsAnimCur(pCursor)) + { + AnimCurPtr ac = GetAnimCur(pCursor); + int i; + + for (i = 0; i < ac->nelt; i++) + (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor, + displayed && + animCurState[pDev->id].elt == i); + } + else + (*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed); + Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor); +} + +Bool +AnimCurInit (ScreenPtr pScreen) +{ + AnimCurScreenPtr as; + + if (AnimCurGeneration != serverGeneration) + { + int i; + AnimCurGeneration = serverGeneration; + for (i = 0; i < MAXDEVICES; i++) { + animCurState[i].pCursor = 0; + animCurState[i].pScreen = 0; + animCurState[i].elt = 0; + animCurState[i].time = 0; + } + } + as = (AnimCurScreenPtr) malloc(sizeof (AnimCurScreenRec)); + if (!as) + return FALSE; + Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen); + + Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); + + Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); + Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); + Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); + Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); + Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); + Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); + SetAnimCurScreen(pScreen,as); + return TRUE; +} + +int +AnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor, ClientPtr client, XID cid) +{ + CursorPtr pCursor; + int rc, i; + AnimCurPtr ac; + + for (i = 0; i < screenInfo.numScreens; i++) + if (!GetAnimCurScreenIfSet (screenInfo.screens[i])) + return BadImplementation; + + for (i = 0; i < ncursor; i++) + if (IsAnimCur (cursors[i])) + return BadMatch; + + pCursor = (CursorPtr) malloc(sizeof (CursorRec) + + sizeof (AnimCurRec) + + ncursor * sizeof (AnimCurElt)); + if (!pCursor) + return BadAlloc; + pCursor->bits = &animCursorBits; + pCursor->refcnt = 1; + + pCursor->foreRed = cursors[0]->foreRed; + pCursor->foreGreen = cursors[0]->foreGreen; + pCursor->foreBlue = cursors[0]->foreBlue; + + pCursor->backRed = cursors[0]->backRed; + pCursor->backGreen = cursors[0]->backGreen; + pCursor->backBlue = cursors[0]->backBlue; + + pCursor->id = cid; + pCursor->devPrivates = NULL; + + /* security creation/labeling check */ + rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor, + RT_NONE, NULL, DixCreateAccess); + if (rc != Success) { + dixFreePrivates(pCursor->devPrivates); + free(pCursor); + return rc; + } + + /* + * Fill in the AnimCurRec + */ + animCursorBits.refcnt++; + ac = GetAnimCur (pCursor); + ac->nelt = ncursor; + ac->elts = (AnimCurElt *) (ac + 1); + + for (i = 0; i < ncursor; i++) + { + cursors[i]->refcnt++; + ac->elts[i].pCursor = cursors[i]; + ac->elts[i].delay = deltas[i]; + } + + *ppCursor = pCursor; + return Success; +} diff --git a/xorg-server/render/filter.c b/xorg-server/render/filter.c index 89cc0646a..53fb86f3d 100644 --- a/xorg-server/render/filter.c +++ b/xorg-server/render/filter.c @@ -1,359 +1,359 @@ -/* - * 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 <dix-config.h> -#endif - -#include "misc.h" -#include "scrnintstr.h" -#include "os.h" -#include "regionstr.h" -#include "validate.h" -#include "windowstr.h" -#include "input.h" -#include "resource.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "dixstruct.h" -#include "gcstruct.h" -#include "servermd.h" -#include "picturestr.h" - -static char **filterNames; -static int nfilterNames; - -/* - * standard but not required filters don't have constant indices - */ - -int -PictureGetFilterId (char *filter, int len, Bool makeit) -{ - int i; - char *name; - char **names; - - if (len < 0) - len = strlen (filter); - for (i = 0; i < nfilterNames; i++) - if (!CompareISOLatin1Lowered ((unsigned char *) filterNames[i], -1, (unsigned char *) filter, len)) - return i; - if (!makeit) - return -1; - name = xalloc (len + 1); - if (!name) - return -1; - memcpy (name, filter, len); - name[len] = '\0'; - if (filterNames) - names = xrealloc (filterNames, (nfilterNames + 1) * sizeof (char *)); - else - names = xalloc (sizeof (char *)); - if (!names) - { - xfree (name); - return -1; - } - filterNames = names; - i = nfilterNames++; - filterNames[i] = name; - return i; -} - -static Bool -PictureSetDefaultIds (void) -{ - /* careful here -- this list must match the #define values */ - - if (PictureGetFilterId (FilterNearest, -1, TRUE) != PictFilterNearest) - return FALSE; - if (PictureGetFilterId (FilterBilinear, -1, TRUE) != PictFilterBilinear) - return FALSE; - - if (PictureGetFilterId (FilterFast, -1, TRUE) != PictFilterFast) - return FALSE; - if (PictureGetFilterId (FilterGood, -1, TRUE) != PictFilterGood) - return FALSE; - if (PictureGetFilterId (FilterBest, -1, TRUE) != PictFilterBest) - return FALSE; - - if (PictureGetFilterId (FilterConvolution, -1, TRUE) != PictFilterConvolution) - return FALSE; - return TRUE; -} - -char * -PictureGetFilterName (int id) -{ - if (0 <= id && id < nfilterNames) - return filterNames[id]; - else - return 0; -} - -static void -PictureFreeFilterIds (void) -{ - int i; - - for (i = 0; i < nfilterNames; i++) - xfree (filterNames[i]); - xfree (filterNames); - nfilterNames = 0; - filterNames = 0; -} - -int -PictureAddFilter (ScreenPtr pScreen, - char *filter, - PictFilterValidateParamsProcPtr ValidateParams, - int width, - int height) -{ - PictureScreenPtr ps = GetPictureScreen(pScreen); - int id = PictureGetFilterId (filter, -1, TRUE); - int i; - PictFilterPtr filters; - - if (id < 0) - return -1; - /* - * It's an error to attempt to reregister a filter - */ - for (i = 0; i < ps->nfilters; i++) - if (ps->filters[i].id == id) - return -1; - if (ps->filters) - filters = xrealloc (ps->filters, (ps->nfilters + 1) * sizeof (PictFilterRec)); - else - filters = xalloc (sizeof (PictFilterRec)); - if (!filters) - return -1; - ps->filters = filters; - i = ps->nfilters++; - ps->filters[i].name = PictureGetFilterName (id); - ps->filters[i].id = id; - ps->filters[i].ValidateParams = ValidateParams; - ps->filters[i].width = width; - ps->filters[i].height = height; - return id; -} - -Bool -PictureSetFilterAlias (ScreenPtr pScreen, char *filter, char *alias) -{ - PictureScreenPtr ps = GetPictureScreen(pScreen); - int filter_id = PictureGetFilterId (filter, -1, FALSE); - int alias_id = PictureGetFilterId (alias, -1, TRUE); - int i; - - if (filter_id < 0 || alias_id < 0) - return FALSE; - for (i = 0; i < ps->nfilterAliases; i++) - if (ps->filterAliases[i].alias_id == alias_id) - break; - if (i == ps->nfilterAliases) - { - PictFilterAliasPtr aliases; - - if (ps->filterAliases) - aliases = xrealloc (ps->filterAliases, - (ps->nfilterAliases + 1) * - sizeof (PictFilterAliasRec)); - else - aliases = xalloc (sizeof (PictFilterAliasRec)); - if (!aliases) - return FALSE; - ps->filterAliases = aliases; - ps->filterAliases[i].alias = PictureGetFilterName (alias_id); - ps->filterAliases[i].alias_id = alias_id; - ps->nfilterAliases++; - } - ps->filterAliases[i].filter_id = filter_id; - return TRUE; -} - -PictFilterPtr -PictureFindFilter (ScreenPtr pScreen, char *name, int len) -{ - PictureScreenPtr ps = GetPictureScreen(pScreen); - int id = PictureGetFilterId (name, len, FALSE); - int i; - - if (id < 0) - return 0; - /* Check for an alias, allow them to recurse */ - for (i = 0; i < ps->nfilterAliases; i++) - if (ps->filterAliases[i].alias_id == id) - { - id = ps->filterAliases[i].filter_id; - i = 0; - } - /* find the filter */ - for (i = 0; i < ps->nfilters; i++) - if (ps->filters[i].id == id) - return &ps->filters[i]; - return 0; -} - -static Bool -convolutionFilterValidateParams (ScreenPtr pScreen, - int filter, - xFixed *params, - int nparams, - int *width, - int *height) -{ - int w, h; - if (nparams < 3) - return FALSE; - - if (xFixedFrac (params[0]) || xFixedFrac (params[1])) - return FALSE; - - w = xFixedToInt (params[0]); - h = xFixedToInt (params[1]); - - nparams -= 2; - if (w * h > nparams) - return FALSE; - - *width = w; - *height = h; - return TRUE; -} - - -Bool -PictureSetDefaultFilters (ScreenPtr pScreen) -{ - if (!filterNames) - if (!PictureSetDefaultIds ()) - return FALSE; - if (PictureAddFilter (pScreen, FilterNearest, 0, 1, 1) < 0) - return FALSE; - if (PictureAddFilter (pScreen, FilterBilinear, 0, 2, 2) < 0) - return FALSE; - - if (!PictureSetFilterAlias (pScreen, FilterNearest, FilterFast)) - return FALSE; - if (!PictureSetFilterAlias (pScreen, FilterBilinear, FilterGood)) - return FALSE; - if (!PictureSetFilterAlias (pScreen, FilterBilinear, FilterBest)) - return FALSE; - - if (PictureAddFilter (pScreen, FilterConvolution, convolutionFilterValidateParams, 0, 0) < 0) - return FALSE; - - return TRUE; -} - -void -PictureResetFilters (ScreenPtr pScreen) -{ - PictureScreenPtr ps = GetPictureScreen(pScreen); - - xfree (ps->filters); - xfree (ps->filterAliases); - PictureFreeFilterIds (); -} - -int -SetPictureFilter (PicturePtr pPicture, char *name, int len, xFixed *params, int nparams) -{ - PictFilterPtr pFilter; - ScreenPtr pScreen; - - if (pPicture->pDrawable != NULL) - pScreen = pPicture->pDrawable->pScreen; - else - pScreen = screenInfo.screens[0]; - - pFilter = PictureFindFilter (pScreen, name, len); - - if (!pFilter) - return BadName; - - if (pPicture->pDrawable == NULL) - { - int s; - /* For source pictures, the picture isn't tied to a screen. So, ensure - * that all screens can handle a filter we set for the picture. - */ - for (s = 1; s < screenInfo.numScreens; s++) - { - PictFilterPtr pScreenFilter; - pScreenFilter = PictureFindFilter (screenInfo.screens[s], - name, len); - if (!pScreenFilter || pScreenFilter->id != pFilter->id) - return BadMatch; - } - } - return SetPicturePictFilter (pPicture, pFilter, params, nparams); -} - -int -SetPicturePictFilter (PicturePtr pPicture, PictFilterPtr pFilter, - xFixed *params, int nparams) -{ - ScreenPtr pScreen; - int i; - - if (pPicture->pDrawable) - pScreen = pPicture->pDrawable->pScreen; - else - pScreen = screenInfo.screens[0]; - - if (pFilter->ValidateParams) - { - int width, height; - if (!(*pFilter->ValidateParams) (pScreen, pFilter->id, params, nparams, &width, &height)) - return BadMatch; - } - else if (nparams) - return BadMatch; - - if (nparams != pPicture->filter_nparams) - { - xFixed *new_params = xalloc (nparams * sizeof (xFixed)); - if (!new_params && nparams) - return BadAlloc; - xfree (pPicture->filter_params); - pPicture->filter_params = new_params; - pPicture->filter_nparams = nparams; - } - for (i = 0; i < nparams; i++) - pPicture->filter_params[i] = params[i]; - pPicture->filter = pFilter->id; - - if (pPicture->pDrawable) - { - PictureScreenPtr ps = GetPictureScreen(pScreen); - int result; - - result = (*ps->ChangePictureFilter) (pPicture, pPicture->filter, - params, nparams); - return result; - } - return Success; -} +/* + * 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 <dix-config.h> +#endif + +#include "misc.h" +#include "scrnintstr.h" +#include "os.h" +#include "regionstr.h" +#include "validate.h" +#include "windowstr.h" +#include "input.h" +#include "resource.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "servermd.h" +#include "picturestr.h" + +static char **filterNames; +static int nfilterNames; + +/* + * standard but not required filters don't have constant indices + */ + +int +PictureGetFilterId (char *filter, int len, Bool makeit) +{ + int i; + char *name; + char **names; + + if (len < 0) + len = strlen (filter); + for (i = 0; i < nfilterNames; i++) + if (!CompareISOLatin1Lowered ((unsigned char *) filterNames[i], -1, (unsigned char *) filter, len)) + return i; + if (!makeit) + return -1; + name = malloc(len + 1); + if (!name) + return -1; + memcpy (name, filter, len); + name[len] = '\0'; + if (filterNames) + names = realloc(filterNames, (nfilterNames + 1) * sizeof (char *)); + else + names = malloc(sizeof (char *)); + if (!names) + { + free(name); + return -1; + } + filterNames = names; + i = nfilterNames++; + filterNames[i] = name; + return i; +} + +static Bool +PictureSetDefaultIds (void) +{ + /* careful here -- this list must match the #define values */ + + if (PictureGetFilterId (FilterNearest, -1, TRUE) != PictFilterNearest) + return FALSE; + if (PictureGetFilterId (FilterBilinear, -1, TRUE) != PictFilterBilinear) + return FALSE; + + if (PictureGetFilterId (FilterFast, -1, TRUE) != PictFilterFast) + return FALSE; + if (PictureGetFilterId (FilterGood, -1, TRUE) != PictFilterGood) + return FALSE; + if (PictureGetFilterId (FilterBest, -1, TRUE) != PictFilterBest) + return FALSE; + + if (PictureGetFilterId (FilterConvolution, -1, TRUE) != PictFilterConvolution) + return FALSE; + return TRUE; +} + +char * +PictureGetFilterName (int id) +{ + if (0 <= id && id < nfilterNames) + return filterNames[id]; + else + return 0; +} + +static void +PictureFreeFilterIds (void) +{ + int i; + + for (i = 0; i < nfilterNames; i++) + free(filterNames[i]); + free(filterNames); + nfilterNames = 0; + filterNames = 0; +} + +int +PictureAddFilter (ScreenPtr pScreen, + char *filter, + PictFilterValidateParamsProcPtr ValidateParams, + int width, + int height) +{ + PictureScreenPtr ps = GetPictureScreen(pScreen); + int id = PictureGetFilterId (filter, -1, TRUE); + int i; + PictFilterPtr filters; + + if (id < 0) + return -1; + /* + * It's an error to attempt to reregister a filter + */ + for (i = 0; i < ps->nfilters; i++) + if (ps->filters[i].id == id) + return -1; + if (ps->filters) + filters = realloc(ps->filters, (ps->nfilters + 1) * sizeof (PictFilterRec)); + else + filters = malloc(sizeof (PictFilterRec)); + if (!filters) + return -1; + ps->filters = filters; + i = ps->nfilters++; + ps->filters[i].name = PictureGetFilterName (id); + ps->filters[i].id = id; + ps->filters[i].ValidateParams = ValidateParams; + ps->filters[i].width = width; + ps->filters[i].height = height; + return id; +} + +Bool +PictureSetFilterAlias (ScreenPtr pScreen, char *filter, char *alias) +{ + PictureScreenPtr ps = GetPictureScreen(pScreen); + int filter_id = PictureGetFilterId (filter, -1, FALSE); + int alias_id = PictureGetFilterId (alias, -1, TRUE); + int i; + + if (filter_id < 0 || alias_id < 0) + return FALSE; + for (i = 0; i < ps->nfilterAliases; i++) + if (ps->filterAliases[i].alias_id == alias_id) + break; + if (i == ps->nfilterAliases) + { + PictFilterAliasPtr aliases; + + if (ps->filterAliases) + aliases = realloc(ps->filterAliases, + (ps->nfilterAliases + 1) * + sizeof (PictFilterAliasRec)); + else + aliases = malloc(sizeof (PictFilterAliasRec)); + if (!aliases) + return FALSE; + ps->filterAliases = aliases; + ps->filterAliases[i].alias = PictureGetFilterName (alias_id); + ps->filterAliases[i].alias_id = alias_id; + ps->nfilterAliases++; + } + ps->filterAliases[i].filter_id = filter_id; + return TRUE; +} + +PictFilterPtr +PictureFindFilter (ScreenPtr pScreen, char *name, int len) +{ + PictureScreenPtr ps = GetPictureScreen(pScreen); + int id = PictureGetFilterId (name, len, FALSE); + int i; + + if (id < 0) + return 0; + /* Check for an alias, allow them to recurse */ + for (i = 0; i < ps->nfilterAliases; i++) + if (ps->filterAliases[i].alias_id == id) + { + id = ps->filterAliases[i].filter_id; + i = 0; + } + /* find the filter */ + for (i = 0; i < ps->nfilters; i++) + if (ps->filters[i].id == id) + return &ps->filters[i]; + return 0; +} + +static Bool +convolutionFilterValidateParams (ScreenPtr pScreen, + int filter, + xFixed *params, + int nparams, + int *width, + int *height) +{ + int w, h; + if (nparams < 3) + return FALSE; + + if (xFixedFrac (params[0]) || xFixedFrac (params[1])) + return FALSE; + + w = xFixedToInt (params[0]); + h = xFixedToInt (params[1]); + + nparams -= 2; + if (w * h > nparams) + return FALSE; + + *width = w; + *height = h; + return TRUE; +} + + +Bool +PictureSetDefaultFilters (ScreenPtr pScreen) +{ + if (!filterNames) + if (!PictureSetDefaultIds ()) + return FALSE; + if (PictureAddFilter (pScreen, FilterNearest, 0, 1, 1) < 0) + return FALSE; + if (PictureAddFilter (pScreen, FilterBilinear, 0, 2, 2) < 0) + return FALSE; + + if (!PictureSetFilterAlias (pScreen, FilterNearest, FilterFast)) + return FALSE; + if (!PictureSetFilterAlias (pScreen, FilterBilinear, FilterGood)) + return FALSE; + if (!PictureSetFilterAlias (pScreen, FilterBilinear, FilterBest)) + return FALSE; + + if (PictureAddFilter (pScreen, FilterConvolution, convolutionFilterValidateParams, 0, 0) < 0) + return FALSE; + + return TRUE; +} + +void +PictureResetFilters (ScreenPtr pScreen) +{ + PictureScreenPtr ps = GetPictureScreen(pScreen); + + free(ps->filters); + free(ps->filterAliases); + PictureFreeFilterIds (); +} + +int +SetPictureFilter (PicturePtr pPicture, char *name, int len, xFixed *params, int nparams) +{ + PictFilterPtr pFilter; + ScreenPtr pScreen; + + if (pPicture->pDrawable != NULL) + pScreen = pPicture->pDrawable->pScreen; + else + pScreen = screenInfo.screens[0]; + + pFilter = PictureFindFilter (pScreen, name, len); + + if (!pFilter) + return BadName; + + if (pPicture->pDrawable == NULL) + { + int s; + /* For source pictures, the picture isn't tied to a screen. So, ensure + * that all screens can handle a filter we set for the picture. + */ + for (s = 1; s < screenInfo.numScreens; s++) + { + PictFilterPtr pScreenFilter; + pScreenFilter = PictureFindFilter (screenInfo.screens[s], + name, len); + if (!pScreenFilter || pScreenFilter->id != pFilter->id) + return BadMatch; + } + } + return SetPicturePictFilter (pPicture, pFilter, params, nparams); +} + +int +SetPicturePictFilter (PicturePtr pPicture, PictFilterPtr pFilter, + xFixed *params, int nparams) +{ + ScreenPtr pScreen; + int i; + + if (pPicture->pDrawable) + pScreen = pPicture->pDrawable->pScreen; + else + pScreen = screenInfo.screens[0]; + + if (pFilter->ValidateParams) + { + int width, height; + if (!(*pFilter->ValidateParams) (pScreen, pFilter->id, params, nparams, &width, &height)) + return BadMatch; + } + else if (nparams) + return BadMatch; + + if (nparams != pPicture->filter_nparams) + { + xFixed *new_params = malloc(nparams * sizeof (xFixed)); + if (!new_params && nparams) + return BadAlloc; + free(pPicture->filter_params); + pPicture->filter_params = new_params; + pPicture->filter_nparams = nparams; + } + for (i = 0; i < nparams; i++) + pPicture->filter_params[i] = params[i]; + pPicture->filter = pFilter->id; + + if (pPicture->pDrawable) + { + PictureScreenPtr ps = GetPictureScreen(pScreen); + int result; + + result = (*ps->ChangePictureFilter) (pPicture, pPicture->filter, + params, nparams); + return result; + } + return Success; +} diff --git a/xorg-server/render/glyph.c b/xorg-server/render/glyph.c index 6b81118ec..b147331c8 100644 --- a/xorg-server/render/glyph.c +++ b/xorg-server/render/glyph.c @@ -1,754 +1,754 @@ -/* - * - * Copyright © 2000 SuSE, Inc. - * - * 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 SuSE not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. SuSE makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - * - * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE - * 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. - * - * Author: Keith Packard, SuSE, Inc. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "xsha1.h" - -#include "misc.h" -#include "scrnintstr.h" -#include "os.h" -#include "regionstr.h" -#include "validate.h" -#include "windowstr.h" -#include "input.h" -#include "resource.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "dixstruct.h" -#include "gcstruct.h" -#include "servermd.h" -#include "picturestr.h" -#include "glyphstr.h" -#include "mipict.h" - -/* - * From Knuth -- a good choice for hash/rehash values is p, p-2 where - * p and p-2 are both prime. These tables are sized to have an extra 10% - * free to avoid exponential performance degradation as the hash table fills - */ -static GlyphHashSetRec glyphHashSets[] = { - { 32, 43, 41 }, - { 64, 73, 71 }, - { 128, 151, 149 }, - { 256, 283, 281 }, - { 512, 571, 569 }, - { 1024, 1153, 1151 }, - { 2048, 2269, 2267 }, - { 4096, 4519, 4517 }, - { 8192, 9013, 9011 }, - { 16384, 18043, 18041 }, - { 32768, 36109, 36107 }, - { 65536, 72091, 72089 }, - { 131072, 144409, 144407 }, - { 262144, 288361, 288359 }, - { 524288, 576883, 576881 }, - { 1048576, 1153459, 1153457 }, - { 2097152, 2307163, 2307161 }, - { 4194304, 4613893, 4613891 }, - { 8388608, 9227641, 9227639 }, - { 16777216, 18455029, 18455027 }, - { 33554432, 36911011, 36911009 }, - { 67108864, 73819861, 73819859 }, - { 134217728, 147639589, 147639587 }, - { 268435456, 295279081, 295279079 }, - { 536870912, 590559793, 590559791 } -}; - -#define NGLYPHHASHSETS (sizeof(glyphHashSets)/sizeof(glyphHashSets[0])) - -static const CARD8 glyphDepths[GlyphFormatNum] = { 1, 4, 8, 16, 32 }; - -static GlyphHashRec globalGlyphs[GlyphFormatNum]; - -static void -FreeGlyphPrivates (GlyphPtr glyph) -{ - dixFreePrivates(glyph->devPrivates); - glyph->devPrivates = NULL; -} - -void -GlyphUninit (ScreenPtr pScreen) -{ - PictureScreenPtr ps = GetPictureScreen (pScreen); - GlyphPtr glyph; - int fdepth, i; - - for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++) - { - if (!globalGlyphs[fdepth].hashSet) - continue; - - for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++) - { - glyph = globalGlyphs[fdepth].table[i].glyph; - if (glyph && glyph != DeletedGlyph) - { - (*ps->UnrealizeGlyph) (pScreen, glyph); - FreeGlyphPrivates(glyph); - } - } - } -} - -GlyphHashSetPtr -FindGlyphHashSet (CARD32 filled) -{ - int i; - - for (i = 0; i < NGLYPHHASHSETS; i++) - if (glyphHashSets[i].entries >= filled) - return &glyphHashSets[i]; - return 0; -} - -GlyphRefPtr -FindGlyphRef (GlyphHashPtr hash, - CARD32 signature, - Bool match, - unsigned char sha1[20]) -{ - CARD32 elt, step, s; - GlyphPtr glyph; - GlyphRefPtr table, gr, del; - CARD32 tableSize = hash->hashSet->size; - - table = hash->table; - elt = signature % tableSize; - step = 0; - del = 0; - for (;;) - { - gr = &table[elt]; - s = gr->signature; - glyph = gr->glyph; - if (!glyph) - { - if (del) - gr = del; - break; - } - if (glyph == DeletedGlyph) - { - if (!del) - del = gr; - else if (gr == del) - break; - } - else if (s == signature && - (!match || - memcmp (glyph->sha1, sha1, 20) == 0)) - { - break; - } - if (!step) - { - step = signature % hash->hashSet->rehash; - if (!step) - step = 1; - } - elt += step; - if (elt >= tableSize) - elt -= tableSize; - } - return gr; -} - -int -HashGlyph (xGlyphInfo *gi, - CARD8 *bits, - unsigned long size, - unsigned char sha1[20]) -{ - void *ctx = x_sha1_init(); - int success; - - if (!ctx) - return BadAlloc; - - success = x_sha1_update(ctx, gi, sizeof(xGlyphInfo)); - if (!success) - return BadAlloc; - success = x_sha1_update(ctx, bits, size); - if (!success) - return BadAlloc; - success = x_sha1_final(ctx, sha1); - if (!success) - return BadAlloc; - return Success; -} - -GlyphPtr -FindGlyphByHash (unsigned char sha1[20], int format) -{ - GlyphRefPtr gr; - CARD32 signature = *(CARD32 *) sha1; - - if (!globalGlyphs[format].hashSet) - return NULL; - - gr = FindGlyphRef (&globalGlyphs[format], - signature, TRUE, sha1); - - if (gr->glyph && gr->glyph != DeletedGlyph) - return gr->glyph; - else - return NULL; -} - -#ifdef CHECK_DUPLICATES -void -DuplicateRef (GlyphPtr glyph, char *where) -{ - ErrorF ("Duplicate Glyph 0x%x from %s\n", glyph, where); -} - -void -CheckDuplicates (GlyphHashPtr hash, char *where) -{ - GlyphPtr g; - int i, j; - - for (i = 0; i < hash->hashSet->size; i++) - { - g = hash->table[i].glyph; - if (!g || g == DeletedGlyph) - continue; - for (j = i + 1; j < hash->hashSet->size; j++) - if (hash->table[j].glyph == g) - DuplicateRef (g, where); - } -} -#else -#define CheckDuplicates(a,b) -#define DuplicateRef(a,b) -#endif - -static void -FreeGlyphPicture(GlyphPtr glyph) -{ - PictureScreenPtr ps; - int i; - - for (i = 0; i < screenInfo.numScreens; i++) - { - ScreenPtr pScreen = screenInfo.screens[i]; - - if (GlyphPicture(glyph)[i]) - FreePicture ((pointer) GlyphPicture (glyph)[i], 0); - - ps = GetPictureScreenIfSet (pScreen); - if (ps) - (*ps->UnrealizeGlyph) (pScreen, glyph); - } -} - - -void -FreeGlyph (GlyphPtr glyph, int format) -{ - CheckDuplicates (&globalGlyphs[format], "FreeGlyph"); - if (--glyph->refcnt == 0) - { - GlyphRefPtr gr; - int i; - int first; - CARD32 signature; - - first = -1; - for (i = 0; i < globalGlyphs[format].hashSet->size; i++) - if (globalGlyphs[format].table[i].glyph == glyph) - { - if (first != -1) - DuplicateRef (glyph, "FreeGlyph check"); - first = i; - } - - signature = *(CARD32 *) glyph->sha1; - gr = FindGlyphRef (&globalGlyphs[format], signature, - TRUE, glyph->sha1); - if (gr - globalGlyphs[format].table != first) - DuplicateRef (glyph, "Found wrong one"); - if (gr->glyph && gr->glyph != DeletedGlyph) - { - gr->glyph = DeletedGlyph; - gr->signature = 0; - globalGlyphs[format].tableEntries--; - } - - FreeGlyphPicture(glyph); - FreeGlyphPrivates(glyph); - xfree (glyph); - } -} - -void -AddGlyph (GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id) -{ - GlyphRefPtr gr; - CARD32 signature; - - CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph top global"); - /* Locate existing matching glyph */ - signature = *(CARD32 *) glyph->sha1; - gr = FindGlyphRef (&globalGlyphs[glyphSet->fdepth], signature, - TRUE, glyph->sha1); - if (gr->glyph && gr->glyph != DeletedGlyph && gr->glyph != glyph) - { - FreeGlyphPicture(glyph); - FreeGlyphPrivates(glyph); - xfree (glyph); - glyph = gr->glyph; - } - else if (gr->glyph != glyph) - { - gr->glyph = glyph; - gr->signature = signature; - globalGlyphs[glyphSet->fdepth].tableEntries++; - } - - /* Insert/replace glyphset value */ - gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0); - ++glyph->refcnt; - if (gr->glyph && gr->glyph != DeletedGlyph) - FreeGlyph (gr->glyph, glyphSet->fdepth); - else - glyphSet->hash.tableEntries++; - gr->glyph = glyph; - gr->signature = id; - CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom"); -} - -Bool -DeleteGlyph (GlyphSetPtr glyphSet, Glyph id) -{ - GlyphRefPtr gr; - GlyphPtr glyph; - - gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0); - glyph = gr->glyph; - if (glyph && glyph != DeletedGlyph) - { - gr->glyph = DeletedGlyph; - glyphSet->hash.tableEntries--; - FreeGlyph (glyph, glyphSet->fdepth); - return TRUE; - } - return FALSE; -} - -GlyphPtr -FindGlyph (GlyphSetPtr glyphSet, Glyph id) -{ - GlyphPtr glyph; - - glyph = FindGlyphRef (&glyphSet->hash, id, FALSE, 0)->glyph; - if (glyph == DeletedGlyph) - glyph = 0; - return glyph; -} - -GlyphPtr -AllocateGlyph (xGlyphInfo *gi, int fdepth) -{ - PictureScreenPtr ps; - int size; - GlyphPtr glyph; - int i; - - size = screenInfo.numScreens * sizeof (PicturePtr); - glyph = (GlyphPtr) xalloc (size + sizeof (GlyphRec)); - if (!glyph) - return 0; - glyph->refcnt = 0; - glyph->size = size + sizeof (xGlyphInfo); - glyph->info = *gi; - glyph->devPrivates = NULL; - - for (i = 0; i < screenInfo.numScreens; i++) - { - GlyphPicture(glyph)[i] = NULL; - ps = GetPictureScreenIfSet (screenInfo.screens[i]); - - if (ps) - { - if (!(*ps->RealizeGlyph) (screenInfo.screens[i], glyph)) - goto bail; - } - } - - return glyph; - -bail: - while (i--) - { - ps = GetPictureScreenIfSet (screenInfo.screens[i]); - if (ps) - (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph); - } - - FreeGlyphPrivates(glyph); - xfree (glyph); - return 0; -} - -Bool -AllocateGlyphHash (GlyphHashPtr hash, GlyphHashSetPtr hashSet) -{ - hash->table = xcalloc (hashSet->size, sizeof (GlyphRefRec)); - if (!hash->table) - return FALSE; - hash->hashSet = hashSet; - hash->tableEntries = 0; - return TRUE; -} - -Bool -ResizeGlyphHash (GlyphHashPtr hash, CARD32 change, Bool global) -{ - CARD32 tableEntries; - GlyphHashSetPtr hashSet; - GlyphHashRec newHash; - GlyphRefPtr gr; - GlyphPtr glyph; - int i; - int oldSize; - CARD32 s; - - tableEntries = hash->tableEntries + change; - hashSet = FindGlyphHashSet (tableEntries); - if (hashSet == hash->hashSet) - return TRUE; - if (global) - CheckDuplicates (hash, "ResizeGlyphHash top"); - if (!AllocateGlyphHash (&newHash, hashSet)) - return FALSE; - if (hash->table) - { - oldSize = hash->hashSet->size; - for (i = 0; i < oldSize; i++) - { - glyph = hash->table[i].glyph; - if (glyph && glyph != DeletedGlyph) - { - s = hash->table[i].signature; - gr = FindGlyphRef (&newHash, s, global, glyph->sha1); - gr->signature = s; - gr->glyph = glyph; - ++newHash.tableEntries; - } - } - xfree (hash->table); - } - *hash = newHash; - if (global) - CheckDuplicates (hash, "ResizeGlyphHash bottom"); - return TRUE; -} - -Bool -ResizeGlyphSet (GlyphSetPtr glyphSet, CARD32 change) -{ - return (ResizeGlyphHash (&glyphSet->hash, change, FALSE) && - ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], change, TRUE)); -} - -GlyphSetPtr -AllocateGlyphSet (int fdepth, PictFormatPtr format) -{ - GlyphSetPtr glyphSet; - int size; - - if (!globalGlyphs[fdepth].hashSet) - { - if (!AllocateGlyphHash (&globalGlyphs[fdepth], &glyphHashSets[0])) - return FALSE; - } - - size = sizeof (GlyphSetRec); - glyphSet = xcalloc (1, size); - if (!glyphSet) - return FALSE; - - if (!AllocateGlyphHash (&glyphSet->hash, &glyphHashSets[0])) - { - xfree (glyphSet); - return FALSE; - } - glyphSet->refcnt = 1; - glyphSet->fdepth = fdepth; - glyphSet->format = format; - return glyphSet; -} - -int -FreeGlyphSet (pointer value, - XID gid) -{ - GlyphSetPtr glyphSet = (GlyphSetPtr) value; - - if (--glyphSet->refcnt == 0) - { - CARD32 i, tableSize = glyphSet->hash.hashSet->size; - GlyphRefPtr table = glyphSet->hash.table; - GlyphPtr glyph; - - for (i = 0; i < tableSize; i++) - { - glyph = table[i].glyph; - if (glyph && glyph != DeletedGlyph) - FreeGlyph (glyph, glyphSet->fdepth); - } - if (!globalGlyphs[glyphSet->fdepth].tableEntries) - { - xfree (globalGlyphs[glyphSet->fdepth].table); - globalGlyphs[glyphSet->fdepth].table = 0; - globalGlyphs[glyphSet->fdepth].hashSet = 0; - } - else - ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], 0, TRUE); - xfree (table); - dixFreePrivates(glyphSet->devPrivates); - xfree (glyphSet); - } - return Success; -} - -static void -GlyphExtents (int nlist, - GlyphListPtr list, - GlyphPtr *glyphs, - BoxPtr extents) -{ - int x1, x2, y1, y2; - int n; - GlyphPtr glyph; - int x, y; - - x = 0; - y = 0; - extents->x1 = MAXSHORT; - extents->x2 = MINSHORT; - extents->y1 = MAXSHORT; - extents->y2 = MINSHORT; - while (nlist--) - { - x += list->xOff; - y += list->yOff; - n = list->len; - list++; - while (n--) - { - glyph = *glyphs++; - x1 = x - glyph->info.x; - if (x1 < MINSHORT) - x1 = MINSHORT; - y1 = y - glyph->info.y; - if (y1 < MINSHORT) - y1 = MINSHORT; - x2 = x1 + glyph->info.width; - if (x2 > MAXSHORT) - x2 = MAXSHORT; - y2 = y1 + glyph->info.height; - if (y2 > MAXSHORT) - y2 = MAXSHORT; - if (x1 < extents->x1) - extents->x1 = x1; - if (x2 > extents->x2) - extents->x2 = x2; - if (y1 < extents->y1) - extents->y1 = y1; - if (y2 > extents->y2) - extents->y2 = y2; - x += glyph->info.xOff; - y += glyph->info.yOff; - } - } -} - -#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) - -void -CompositeGlyphs (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int nlist, - GlyphListPtr lists, - GlyphPtr *glyphs) -{ - PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen); - - ValidatePicture (pSrc); - ValidatePicture (pDst); - (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, lists, glyphs); -} - -Bool -miRealizeGlyph (ScreenPtr pScreen, - GlyphPtr glyph) -{ - return TRUE; -} - -void -miUnrealizeGlyph (ScreenPtr pScreen, - GlyphPtr glyph) -{ -} - -void -miGlyphs (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int nlist, - GlyphListPtr list, - GlyphPtr *glyphs) -{ - PicturePtr pPicture; - PixmapPtr pMaskPixmap = 0; - PicturePtr pMask; - ScreenPtr pScreen = pDst->pDrawable->pScreen; - int width = 0, height = 0; - int x, y; - int xDst = list->xOff, yDst = list->yOff; - int n; - GlyphPtr glyph; - int error; - BoxRec extents = {0, 0, 0, 0}; - CARD32 component_alpha; - - if (maskFormat) - { - GCPtr pGC; - xRectangle rect; - - GlyphExtents (nlist, list, glyphs, &extents); - - if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) - return; - width = extents.x2 - extents.x1; - height = extents.y2 - extents.y1; - pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, - maskFormat->depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pMaskPixmap) - return; - component_alpha = NeedsComponent(maskFormat->format); - pMask = CreatePicture (0, &pMaskPixmap->drawable, - maskFormat, CPComponentAlpha, &component_alpha, - serverClient, &error); - if (!pMask) - { - (*pScreen->DestroyPixmap) (pMaskPixmap); - return; - } - pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); - ValidateGC (&pMaskPixmap->drawable, pGC); - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); - FreeScratchGC (pGC); - x = -extents.x1; - y = -extents.y1; - } - else - { - pMask = pDst; - x = 0; - y = 0; - } - while (nlist--) - { - x += list->xOff; - y += list->yOff; - n = list->len; - while (n--) - { - glyph = *glyphs++; - pPicture = GlyphPicture (glyph)[pScreen->myNum]; - - if (pPicture) - { - if (maskFormat) - { - CompositePicture (PictOpAdd, - pPicture, - None, - pMask, - 0, 0, - 0, 0, - x - glyph->info.x, - y - glyph->info.y, - glyph->info.width, - glyph->info.height); - } - else - { - CompositePicture (op, - pSrc, - pPicture, - pDst, - xSrc + (x - glyph->info.x) - xDst, - ySrc + (y - glyph->info.y) - yDst, - 0, 0, - x - glyph->info.x, - y - glyph->info.y, - glyph->info.width, - glyph->info.height); - } - } - - x += glyph->info.xOff; - y += glyph->info.yOff; - } - list++; - } - if (maskFormat) - { - x = extents.x1; - y = extents.y1; - CompositePicture (op, - pSrc, - pMask, - pDst, - xSrc + x - xDst, - ySrc + y - yDst, - 0, 0, - x, y, - width, height); - FreePicture ((pointer) pMask, (XID) 0); - (*pScreen->DestroyPixmap) (pMaskPixmap); - } -} +/* + * + * Copyright © 2000 SuSE, Inc. + * + * 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 SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * 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. + * + * Author: Keith Packard, SuSE, Inc. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "xsha1.h" + +#include "misc.h" +#include "scrnintstr.h" +#include "os.h" +#include "regionstr.h" +#include "validate.h" +#include "windowstr.h" +#include "input.h" +#include "resource.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "servermd.h" +#include "picturestr.h" +#include "glyphstr.h" +#include "mipict.h" + +/* + * From Knuth -- a good choice for hash/rehash values is p, p-2 where + * p and p-2 are both prime. These tables are sized to have an extra 10% + * free to avoid exponential performance degradation as the hash table fills + */ +static GlyphHashSetRec glyphHashSets[] = { + { 32, 43, 41 }, + { 64, 73, 71 }, + { 128, 151, 149 }, + { 256, 283, 281 }, + { 512, 571, 569 }, + { 1024, 1153, 1151 }, + { 2048, 2269, 2267 }, + { 4096, 4519, 4517 }, + { 8192, 9013, 9011 }, + { 16384, 18043, 18041 }, + { 32768, 36109, 36107 }, + { 65536, 72091, 72089 }, + { 131072, 144409, 144407 }, + { 262144, 288361, 288359 }, + { 524288, 576883, 576881 }, + { 1048576, 1153459, 1153457 }, + { 2097152, 2307163, 2307161 }, + { 4194304, 4613893, 4613891 }, + { 8388608, 9227641, 9227639 }, + { 16777216, 18455029, 18455027 }, + { 33554432, 36911011, 36911009 }, + { 67108864, 73819861, 73819859 }, + { 134217728, 147639589, 147639587 }, + { 268435456, 295279081, 295279079 }, + { 536870912, 590559793, 590559791 } +}; + +#define NGLYPHHASHSETS (sizeof(glyphHashSets)/sizeof(glyphHashSets[0])) + +static const CARD8 glyphDepths[GlyphFormatNum] = { 1, 4, 8, 16, 32 }; + +static GlyphHashRec globalGlyphs[GlyphFormatNum]; + +static void +FreeGlyphPrivates (GlyphPtr glyph) +{ + dixFreePrivates(glyph->devPrivates); + glyph->devPrivates = NULL; +} + +void +GlyphUninit (ScreenPtr pScreen) +{ + PictureScreenPtr ps = GetPictureScreen (pScreen); + GlyphPtr glyph; + int fdepth, i; + + for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++) + { + if (!globalGlyphs[fdepth].hashSet) + continue; + + for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++) + { + glyph = globalGlyphs[fdepth].table[i].glyph; + if (glyph && glyph != DeletedGlyph) + { + (*ps->UnrealizeGlyph) (pScreen, glyph); + FreeGlyphPrivates(glyph); + } + } + } +} + +GlyphHashSetPtr +FindGlyphHashSet (CARD32 filled) +{ + int i; + + for (i = 0; i < NGLYPHHASHSETS; i++) + if (glyphHashSets[i].entries >= filled) + return &glyphHashSets[i]; + return 0; +} + +GlyphRefPtr +FindGlyphRef (GlyphHashPtr hash, + CARD32 signature, + Bool match, + unsigned char sha1[20]) +{ + CARD32 elt, step, s; + GlyphPtr glyph; + GlyphRefPtr table, gr, del; + CARD32 tableSize = hash->hashSet->size; + + table = hash->table; + elt = signature % tableSize; + step = 0; + del = 0; + for (;;) + { + gr = &table[elt]; + s = gr->signature; + glyph = gr->glyph; + if (!glyph) + { + if (del) + gr = del; + break; + } + if (glyph == DeletedGlyph) + { + if (!del) + del = gr; + else if (gr == del) + break; + } + else if (s == signature && + (!match || + memcmp (glyph->sha1, sha1, 20) == 0)) + { + break; + } + if (!step) + { + step = signature % hash->hashSet->rehash; + if (!step) + step = 1; + } + elt += step; + if (elt >= tableSize) + elt -= tableSize; + } + return gr; +} + +int +HashGlyph (xGlyphInfo *gi, + CARD8 *bits, + unsigned long size, + unsigned char sha1[20]) +{ + void *ctx = x_sha1_init(); + int success; + + if (!ctx) + return BadAlloc; + + success = x_sha1_update(ctx, gi, sizeof(xGlyphInfo)); + if (!success) + return BadAlloc; + success = x_sha1_update(ctx, bits, size); + if (!success) + return BadAlloc; + success = x_sha1_final(ctx, sha1); + if (!success) + return BadAlloc; + return Success; +} + +GlyphPtr +FindGlyphByHash (unsigned char sha1[20], int format) +{ + GlyphRefPtr gr; + CARD32 signature = *(CARD32 *) sha1; + + if (!globalGlyphs[format].hashSet) + return NULL; + + gr = FindGlyphRef (&globalGlyphs[format], + signature, TRUE, sha1); + + if (gr->glyph && gr->glyph != DeletedGlyph) + return gr->glyph; + else + return NULL; +} + +#ifdef CHECK_DUPLICATES +void +DuplicateRef (GlyphPtr glyph, char *where) +{ + ErrorF ("Duplicate Glyph 0x%x from %s\n", glyph, where); +} + +void +CheckDuplicates (GlyphHashPtr hash, char *where) +{ + GlyphPtr g; + int i, j; + + for (i = 0; i < hash->hashSet->size; i++) + { + g = hash->table[i].glyph; + if (!g || g == DeletedGlyph) + continue; + for (j = i + 1; j < hash->hashSet->size; j++) + if (hash->table[j].glyph == g) + DuplicateRef (g, where); + } +} +#else +#define CheckDuplicates(a,b) +#define DuplicateRef(a,b) +#endif + +static void +FreeGlyphPicture(GlyphPtr glyph) +{ + PictureScreenPtr ps; + int i; + + for (i = 0; i < screenInfo.numScreens; i++) + { + ScreenPtr pScreen = screenInfo.screens[i]; + + if (GlyphPicture(glyph)[i]) + FreePicture ((pointer) GlyphPicture (glyph)[i], 0); + + ps = GetPictureScreenIfSet (pScreen); + if (ps) + (*ps->UnrealizeGlyph) (pScreen, glyph); + } +} + + +void +FreeGlyph (GlyphPtr glyph, int format) +{ + CheckDuplicates (&globalGlyphs[format], "FreeGlyph"); + if (--glyph->refcnt == 0) + { + GlyphRefPtr gr; + int i; + int first; + CARD32 signature; + + first = -1; + for (i = 0; i < globalGlyphs[format].hashSet->size; i++) + if (globalGlyphs[format].table[i].glyph == glyph) + { + if (first != -1) + DuplicateRef (glyph, "FreeGlyph check"); + first = i; + } + + signature = *(CARD32 *) glyph->sha1; + gr = FindGlyphRef (&globalGlyphs[format], signature, + TRUE, glyph->sha1); + if (gr - globalGlyphs[format].table != first) + DuplicateRef (glyph, "Found wrong one"); + if (gr->glyph && gr->glyph != DeletedGlyph) + { + gr->glyph = DeletedGlyph; + gr->signature = 0; + globalGlyphs[format].tableEntries--; + } + + FreeGlyphPicture(glyph); + FreeGlyphPrivates(glyph); + free(glyph); + } +} + +void +AddGlyph (GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id) +{ + GlyphRefPtr gr; + CARD32 signature; + + CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph top global"); + /* Locate existing matching glyph */ + signature = *(CARD32 *) glyph->sha1; + gr = FindGlyphRef (&globalGlyphs[glyphSet->fdepth], signature, + TRUE, glyph->sha1); + if (gr->glyph && gr->glyph != DeletedGlyph && gr->glyph != glyph) + { + FreeGlyphPicture(glyph); + FreeGlyphPrivates(glyph); + free(glyph); + glyph = gr->glyph; + } + else if (gr->glyph != glyph) + { + gr->glyph = glyph; + gr->signature = signature; + globalGlyphs[glyphSet->fdepth].tableEntries++; + } + + /* Insert/replace glyphset value */ + gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0); + ++glyph->refcnt; + if (gr->glyph && gr->glyph != DeletedGlyph) + FreeGlyph (gr->glyph, glyphSet->fdepth); + else + glyphSet->hash.tableEntries++; + gr->glyph = glyph; + gr->signature = id; + CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom"); +} + +Bool +DeleteGlyph (GlyphSetPtr glyphSet, Glyph id) +{ + GlyphRefPtr gr; + GlyphPtr glyph; + + gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0); + glyph = gr->glyph; + if (glyph && glyph != DeletedGlyph) + { + gr->glyph = DeletedGlyph; + glyphSet->hash.tableEntries--; + FreeGlyph (glyph, glyphSet->fdepth); + return TRUE; + } + return FALSE; +} + +GlyphPtr +FindGlyph (GlyphSetPtr glyphSet, Glyph id) +{ + GlyphPtr glyph; + + glyph = FindGlyphRef (&glyphSet->hash, id, FALSE, 0)->glyph; + if (glyph == DeletedGlyph) + glyph = 0; + return glyph; +} + +GlyphPtr +AllocateGlyph (xGlyphInfo *gi, int fdepth) +{ + PictureScreenPtr ps; + int size; + GlyphPtr glyph; + int i; + + size = screenInfo.numScreens * sizeof (PicturePtr); + glyph = (GlyphPtr) malloc(size + sizeof (GlyphRec)); + if (!glyph) + return 0; + glyph->refcnt = 0; + glyph->size = size + sizeof (xGlyphInfo); + glyph->info = *gi; + glyph->devPrivates = NULL; + + for (i = 0; i < screenInfo.numScreens; i++) + { + GlyphPicture(glyph)[i] = NULL; + ps = GetPictureScreenIfSet (screenInfo.screens[i]); + + if (ps) + { + if (!(*ps->RealizeGlyph) (screenInfo.screens[i], glyph)) + goto bail; + } + } + + return glyph; + +bail: + while (i--) + { + ps = GetPictureScreenIfSet (screenInfo.screens[i]); + if (ps) + (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph); + } + + FreeGlyphPrivates(glyph); + free(glyph); + return 0; +} + +Bool +AllocateGlyphHash (GlyphHashPtr hash, GlyphHashSetPtr hashSet) +{ + hash->table = calloc(hashSet->size, sizeof (GlyphRefRec)); + if (!hash->table) + return FALSE; + hash->hashSet = hashSet; + hash->tableEntries = 0; + return TRUE; +} + +Bool +ResizeGlyphHash (GlyphHashPtr hash, CARD32 change, Bool global) +{ + CARD32 tableEntries; + GlyphHashSetPtr hashSet; + GlyphHashRec newHash; + GlyphRefPtr gr; + GlyphPtr glyph; + int i; + int oldSize; + CARD32 s; + + tableEntries = hash->tableEntries + change; + hashSet = FindGlyphHashSet (tableEntries); + if (hashSet == hash->hashSet) + return TRUE; + if (global) + CheckDuplicates (hash, "ResizeGlyphHash top"); + if (!AllocateGlyphHash (&newHash, hashSet)) + return FALSE; + if (hash->table) + { + oldSize = hash->hashSet->size; + for (i = 0; i < oldSize; i++) + { + glyph = hash->table[i].glyph; + if (glyph && glyph != DeletedGlyph) + { + s = hash->table[i].signature; + gr = FindGlyphRef (&newHash, s, global, glyph->sha1); + gr->signature = s; + gr->glyph = glyph; + ++newHash.tableEntries; + } + } + free(hash->table); + } + *hash = newHash; + if (global) + CheckDuplicates (hash, "ResizeGlyphHash bottom"); + return TRUE; +} + +Bool +ResizeGlyphSet (GlyphSetPtr glyphSet, CARD32 change) +{ + return (ResizeGlyphHash (&glyphSet->hash, change, FALSE) && + ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], change, TRUE)); +} + +GlyphSetPtr +AllocateGlyphSet (int fdepth, PictFormatPtr format) +{ + GlyphSetPtr glyphSet; + int size; + + if (!globalGlyphs[fdepth].hashSet) + { + if (!AllocateGlyphHash (&globalGlyphs[fdepth], &glyphHashSets[0])) + return FALSE; + } + + size = sizeof (GlyphSetRec); + glyphSet = calloc(1, size); + if (!glyphSet) + return FALSE; + + if (!AllocateGlyphHash (&glyphSet->hash, &glyphHashSets[0])) + { + free(glyphSet); + return FALSE; + } + glyphSet->refcnt = 1; + glyphSet->fdepth = fdepth; + glyphSet->format = format; + return glyphSet; +} + +int +FreeGlyphSet (pointer value, + XID gid) +{ + GlyphSetPtr glyphSet = (GlyphSetPtr) value; + + if (--glyphSet->refcnt == 0) + { + CARD32 i, tableSize = glyphSet->hash.hashSet->size; + GlyphRefPtr table = glyphSet->hash.table; + GlyphPtr glyph; + + for (i = 0; i < tableSize; i++) + { + glyph = table[i].glyph; + if (glyph && glyph != DeletedGlyph) + FreeGlyph (glyph, glyphSet->fdepth); + } + if (!globalGlyphs[glyphSet->fdepth].tableEntries) + { + free(globalGlyphs[glyphSet->fdepth].table); + globalGlyphs[glyphSet->fdepth].table = 0; + globalGlyphs[glyphSet->fdepth].hashSet = 0; + } + else + ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], 0, TRUE); + free(table); + dixFreePrivates(glyphSet->devPrivates); + free(glyphSet); + } + return Success; +} + +static void +GlyphExtents (int nlist, + GlyphListPtr list, + GlyphPtr *glyphs, + BoxPtr extents) +{ + int x1, x2, y1, y2; + int n; + GlyphPtr glyph; + int x, y; + + x = 0; + y = 0; + extents->x1 = MAXSHORT; + extents->x2 = MINSHORT; + extents->y1 = MAXSHORT; + extents->y2 = MINSHORT; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) + { + glyph = *glyphs++; + x1 = x - glyph->info.x; + if (x1 < MINSHORT) + x1 = MINSHORT; + y1 = y - glyph->info.y; + if (y1 < MINSHORT) + y1 = MINSHORT; + x2 = x1 + glyph->info.width; + if (x2 > MAXSHORT) + x2 = MAXSHORT; + y2 = y1 + glyph->info.height; + if (y2 > MAXSHORT) + y2 = MAXSHORT; + if (x1 < extents->x1) + extents->x1 = x1; + if (x2 > extents->x2) + extents->x2 = x2; + if (y1 < extents->y1) + extents->y1 = y1; + if (y2 > extents->y2) + extents->y2 = y2; + x += glyph->info.xOff; + y += glyph->info.yOff; + } + } +} + +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) + +void +CompositeGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr lists, + GlyphPtr *glyphs) +{ + PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen); + + ValidatePicture (pSrc); + ValidatePicture (pDst); + (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, lists, glyphs); +} + +Bool +miRealizeGlyph (ScreenPtr pScreen, + GlyphPtr glyph) +{ + return TRUE; +} + +void +miUnrealizeGlyph (ScreenPtr pScreen, + GlyphPtr glyph) +{ +} + +void +miGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ + PicturePtr pPicture; + PixmapPtr pMaskPixmap = 0; + PicturePtr pMask; + ScreenPtr pScreen = pDst->pDrawable->pScreen; + int width = 0, height = 0; + int x, y; + int xDst = list->xOff, yDst = list->yOff; + int n; + GlyphPtr glyph; + int error; + BoxRec extents = {0, 0, 0, 0}; + CARD32 component_alpha; + + if (maskFormat) + { + GCPtr pGC; + xRectangle rect; + + GlyphExtents (nlist, list, glyphs, &extents); + + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pMaskPixmap) + return; + component_alpha = NeedsComponent(maskFormat->format); + pMask = CreatePicture (0, &pMaskPixmap->drawable, + maskFormat, CPComponentAlpha, &component_alpha, + serverClient, &error); + if (!pMask) + { + (*pScreen->DestroyPixmap) (pMaskPixmap); + return; + } + pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); + ValidateGC (&pMaskPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); + FreeScratchGC (pGC); + x = -extents.x1; + y = -extents.y1; + } + else + { + pMask = pDst; + x = 0; + y = 0; + } + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) + { + glyph = *glyphs++; + pPicture = GlyphPicture (glyph)[pScreen->myNum]; + + if (pPicture) + { + if (maskFormat) + { + CompositePicture (PictOpAdd, + pPicture, + None, + pMask, + 0, 0, + 0, 0, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + } + else + { + CompositePicture (op, + pSrc, + pPicture, + pDst, + xSrc + (x - glyph->info.x) - xDst, + ySrc + (y - glyph->info.y) - yDst, + 0, 0, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + } + } + + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + if (maskFormat) + { + x = extents.x1; + y = extents.y1; + CompositePicture (op, + pSrc, + pMask, + pDst, + xSrc + x - xDst, + ySrc + y - yDst, + 0, 0, + x, y, + width, height); + FreePicture ((pointer) pMask, (XID) 0); + (*pScreen->DestroyPixmap) (pMaskPixmap); + } +} diff --git a/xorg-server/render/miindex.c b/xorg-server/render/miindex.c index 4e0cf0084..75f941477 100644 --- a/xorg-server/render/miindex.c +++ b/xorg-server/render/miindex.c @@ -1,358 +1,358 @@ -/* - * - * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. - * - * 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 <dix-config.h> -#endif - -#ifndef _MIINDEX_H_ -#define _MIINDEX_H_ - -#include "scrnintstr.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "mi.h" -#include "picturestr.h" -#include "mipict.h" -#include "colormapst.h" - -#define NUM_CUBE_LEVELS 4 -#define NUM_GRAY_LEVELS 13 - -static Bool -miBuildRenderColormap (ColormapPtr pColormap, Pixel *pixels, int *nump) -{ - int r, g, b; - unsigned short red, green, blue; - Pixel pixel; - Bool used[MI_MAX_INDEXED]; - int needed; - int policy; - int cube, gray; - int i, n; - - if (pColormap->mid != pColormap->pScreen->defColormap) - { - policy = PictureCmapPolicyAll; - } - else - { - int avail = pColormap->pVisual->ColormapEntries; - policy = PictureCmapPolicy; - if (policy == PictureCmapPolicyDefault) - { - if (avail >= 256 && (pColormap->pVisual->class|DynamicClass) == PseudoColor) - policy = PictureCmapPolicyColor; - else if (avail >= 64) - policy = PictureCmapPolicyGray; - else - policy = PictureCmapPolicyMono; - } - } - /* - * Make sure enough cells are free for the chosen policy - */ - for (;;) - { - switch (policy) { - case PictureCmapPolicyAll: - needed = 0; - break; - case PictureCmapPolicyColor: - needed = 71; - break; - case PictureCmapPolicyGray: - needed = 11; - break; - case PictureCmapPolicyMono: - default: - needed = 0; - break; - } - if (needed <= pColormap->freeRed) - break; - policy--; - } - - /* - * Compute size of cube and gray ramps - */ - cube = gray = 0; - switch (policy) { - case PictureCmapPolicyAll: - /* - * Allocate as big a cube as possible - */ - if ((pColormap->pVisual->class|DynamicClass) == PseudoColor) - { - for (cube = 1; cube * cube * cube < pColormap->pVisual->ColormapEntries; cube++) - ; - cube--; - if (cube == 1) - cube = 0; - } - else - cube = 0; - /* - * Figure out how many gray levels to use so that they - * line up neatly with the cube - */ - if (cube) - { - needed = pColormap->pVisual->ColormapEntries - (cube*cube*cube); - /* levels to fill in with */ - gray = needed / (cube - 1); - /* total levels */ - gray = (gray + 1) * (cube - 1) + 1; - } - else - gray = pColormap->pVisual->ColormapEntries; - break; - - case PictureCmapPolicyColor: - cube = NUM_CUBE_LEVELS; - /* fall through ... */ - case PictureCmapPolicyGray: - gray = NUM_GRAY_LEVELS; - break; - case PictureCmapPolicyMono: - default: - gray = 2; - break; - } - - memset (used, '\0', pColormap->pVisual->ColormapEntries * sizeof (Bool)); - for (r = 0; r < cube; r++) - for (g = 0; g < cube; g++) - for (b = 0; b < cube; b++) - { - pixel = 0; - red = (r * 65535 + (cube-1)/2) / (cube - 1); - green = (g * 65535 + (cube-1)/2) / (cube - 1); - blue = (b * 65535 + (cube-1)/2) / (cube - 1); - if (AllocColor (pColormap, &red, &green, - &blue, &pixel, 0) != Success) - return FALSE; - used[pixel] = TRUE; - } - for (g = 0; g < gray; g++) - { - pixel = 0; - red = green = blue = (g * 65535 + (gray-1)/2) / (gray - 1); - if (AllocColor (pColormap, &red, &green, &blue, &pixel, 0) != Success) - return FALSE; - used[pixel] = TRUE; - } - n = 0; - for (i = 0; i < pColormap->pVisual->ColormapEntries; i++) - if (used[i]) - pixels[n++] = i; - - *nump = n; - - return TRUE; -} - -/* 0 <= red, green, blue < 32 */ -static Pixel -FindBestColor (miIndexedPtr pIndexed, Pixel *pixels, int num, - int red, int green, int blue) -{ - Pixel best = pixels[0]; - int bestDist = 1 << 30; - int dist; - int dr, dg, db; - while (num--) - { - Pixel pixel = *pixels++; - CARD32 v = pIndexed->rgba[pixel]; - - dr = ((v >> 19) & 0x1f); - dg = ((v >> 11) & 0x1f); - db = ((v >> 3) & 0x1f); - dr = dr - red; - dg = dg - green; - db = db - blue; - dist = dr * dr + dg * dg + db * db; - if (dist < bestDist) - { - bestDist = dist; - best = pixel; - } - } - return best; -} - -/* 0 <= gray < 32768 */ -static Pixel -FindBestGray (miIndexedPtr pIndexed, Pixel *pixels, int num, int gray) -{ - Pixel best = pixels[0]; - int bestDist = 1 << 30; - int dist; - int dr; - int r; - - while (num--) - { - Pixel pixel = *pixels++; - CARD32 v = pIndexed->rgba[pixel]; - - r = v & 0xff; - r = r | (r << 8); - dr = gray - (r >> 1); - dist = dr * dr; - if (dist < bestDist) - { - bestDist = dist; - best = pixel; - } - } - return best; -} - -Bool -miInitIndexed (ScreenPtr pScreen, - PictFormatPtr pFormat) -{ - ColormapPtr pColormap = pFormat->index.pColormap; - VisualPtr pVisual = pColormap->pVisual; - miIndexedPtr pIndexed; - Pixel pixels[MI_MAX_INDEXED]; - xrgb rgb[MI_MAX_INDEXED]; - int num; - int i; - Pixel p, r, g, b; - - if (pVisual->ColormapEntries > MI_MAX_INDEXED) - return FALSE; - - if (pVisual->class & DynamicClass) - { - if (!miBuildRenderColormap (pColormap, pixels, &num)) - return FALSE; - } - else - { - num = pVisual->ColormapEntries; - for (p = 0; p < num; p++) - pixels[p] = p; - } - - pIndexed = xalloc (sizeof (miIndexedRec)); - if (!pIndexed) - return FALSE; - - pFormat->index.nvalues = num; - pFormat->index.pValues = xalloc (num * sizeof (xIndexValue)); - if (!pFormat->index.pValues) - { - xfree (pIndexed); - return FALSE; - } - - - /* - * Build mapping from pixel value to ARGB - */ - QueryColors (pColormap, num, pixels, rgb); - for (i = 0; i < num; i++) - { - p = pixels[i]; - pFormat->index.pValues[i].pixel = p; - pFormat->index.pValues[i].red = rgb[i].red; - pFormat->index.pValues[i].green = rgb[i].green; - pFormat->index.pValues[i].blue = rgb[i].blue; - pFormat->index.pValues[i].alpha = 0xffff; - pIndexed->rgba[p] = (0xff000000 | - ((rgb[i].red & 0xff00) << 8) | - ((rgb[i].green & 0xff00) ) | - ((rgb[i].blue & 0xff00) >> 8)); - } - - /* - * Build mapping from RGB to pixel value. This could probably be - * done a bit quicker... - */ - switch (pVisual->class | DynamicClass) { - case GrayScale: - pIndexed->color = FALSE; - for (r = 0; r < 32768; r++) - pIndexed->ent[r] = FindBestGray (pIndexed, pixels, num, r); - break; - case PseudoColor: - pIndexed->color = TRUE; - p = 0; - for (r = 0; r < 32; r++) - for (g = 0; g < 32; g++) - for (b = 0; b < 32; b++) - { - pIndexed->ent[p] = FindBestColor (pIndexed, pixels, num, - r, g, b); - p++; - } - break; - } - pFormat->index.devPrivate = pIndexed; - return TRUE; -} - -void -miCloseIndexed (ScreenPtr pScreen, - PictFormatPtr pFormat) -{ - if (pFormat->index.devPrivate) - { - xfree (pFormat->index.devPrivate); - pFormat->index.devPrivate = 0; - } - if (pFormat->index.pValues) - { - xfree (pFormat->index.pValues); - pFormat->index.pValues = 0; - } -} - -void -miUpdateIndexed (ScreenPtr pScreen, - PictFormatPtr pFormat, - int ndef, - xColorItem *pdef) -{ - miIndexedPtr pIndexed = pFormat->index.devPrivate; - - if (pIndexed) - { - while (ndef--) - { - pIndexed->rgba[pdef->pixel] = (0xff000000 | - ((pdef->red & 0xff00) << 8) | - ((pdef->green & 0xff00) ) | - ((pdef->blue & 0xff00) >> 8)); - pdef++; - } - } -} - -#endif /* _MIINDEX_H_ */ +/* + * + * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. + * + * 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 <dix-config.h> +#endif + +#ifndef _MIINDEX_H_ +#define _MIINDEX_H_ + +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "mi.h" +#include "picturestr.h" +#include "mipict.h" +#include "colormapst.h" + +#define NUM_CUBE_LEVELS 4 +#define NUM_GRAY_LEVELS 13 + +static Bool +miBuildRenderColormap (ColormapPtr pColormap, Pixel *pixels, int *nump) +{ + int r, g, b; + unsigned short red, green, blue; + Pixel pixel; + Bool used[MI_MAX_INDEXED]; + int needed; + int policy; + int cube, gray; + int i, n; + + if (pColormap->mid != pColormap->pScreen->defColormap) + { + policy = PictureCmapPolicyAll; + } + else + { + int avail = pColormap->pVisual->ColormapEntries; + policy = PictureCmapPolicy; + if (policy == PictureCmapPolicyDefault) + { + if (avail >= 256 && (pColormap->pVisual->class|DynamicClass) == PseudoColor) + policy = PictureCmapPolicyColor; + else if (avail >= 64) + policy = PictureCmapPolicyGray; + else + policy = PictureCmapPolicyMono; + } + } + /* + * Make sure enough cells are free for the chosen policy + */ + for (;;) + { + switch (policy) { + case PictureCmapPolicyAll: + needed = 0; + break; + case PictureCmapPolicyColor: + needed = 71; + break; + case PictureCmapPolicyGray: + needed = 11; + break; + case PictureCmapPolicyMono: + default: + needed = 0; + break; + } + if (needed <= pColormap->freeRed) + break; + policy--; + } + + /* + * Compute size of cube and gray ramps + */ + cube = gray = 0; + switch (policy) { + case PictureCmapPolicyAll: + /* + * Allocate as big a cube as possible + */ + if ((pColormap->pVisual->class|DynamicClass) == PseudoColor) + { + for (cube = 1; cube * cube * cube < pColormap->pVisual->ColormapEntries; cube++) + ; + cube--; + if (cube == 1) + cube = 0; + } + else + cube = 0; + /* + * Figure out how many gray levels to use so that they + * line up neatly with the cube + */ + if (cube) + { + needed = pColormap->pVisual->ColormapEntries - (cube*cube*cube); + /* levels to fill in with */ + gray = needed / (cube - 1); + /* total levels */ + gray = (gray + 1) * (cube - 1) + 1; + } + else + gray = pColormap->pVisual->ColormapEntries; + break; + + case PictureCmapPolicyColor: + cube = NUM_CUBE_LEVELS; + /* fall through ... */ + case PictureCmapPolicyGray: + gray = NUM_GRAY_LEVELS; + break; + case PictureCmapPolicyMono: + default: + gray = 2; + break; + } + + memset (used, '\0', pColormap->pVisual->ColormapEntries * sizeof (Bool)); + for (r = 0; r < cube; r++) + for (g = 0; g < cube; g++) + for (b = 0; b < cube; b++) + { + pixel = 0; + red = (r * 65535 + (cube-1)/2) / (cube - 1); + green = (g * 65535 + (cube-1)/2) / (cube - 1); + blue = (b * 65535 + (cube-1)/2) / (cube - 1); + if (AllocColor (pColormap, &red, &green, + &blue, &pixel, 0) != Success) + return FALSE; + used[pixel] = TRUE; + } + for (g = 0; g < gray; g++) + { + pixel = 0; + red = green = blue = (g * 65535 + (gray-1)/2) / (gray - 1); + if (AllocColor (pColormap, &red, &green, &blue, &pixel, 0) != Success) + return FALSE; + used[pixel] = TRUE; + } + n = 0; + for (i = 0; i < pColormap->pVisual->ColormapEntries; i++) + if (used[i]) + pixels[n++] = i; + + *nump = n; + + return TRUE; +} + +/* 0 <= red, green, blue < 32 */ +static Pixel +FindBestColor (miIndexedPtr pIndexed, Pixel *pixels, int num, + int red, int green, int blue) +{ + Pixel best = pixels[0]; + int bestDist = 1 << 30; + int dist; + int dr, dg, db; + while (num--) + { + Pixel pixel = *pixels++; + CARD32 v = pIndexed->rgba[pixel]; + + dr = ((v >> 19) & 0x1f); + dg = ((v >> 11) & 0x1f); + db = ((v >> 3) & 0x1f); + dr = dr - red; + dg = dg - green; + db = db - blue; + dist = dr * dr + dg * dg + db * db; + if (dist < bestDist) + { + bestDist = dist; + best = pixel; + } + } + return best; +} + +/* 0 <= gray < 32768 */ +static Pixel +FindBestGray (miIndexedPtr pIndexed, Pixel *pixels, int num, int gray) +{ + Pixel best = pixels[0]; + int bestDist = 1 << 30; + int dist; + int dr; + int r; + + while (num--) + { + Pixel pixel = *pixels++; + CARD32 v = pIndexed->rgba[pixel]; + + r = v & 0xff; + r = r | (r << 8); + dr = gray - (r >> 1); + dist = dr * dr; + if (dist < bestDist) + { + bestDist = dist; + best = pixel; + } + } + return best; +} + +Bool +miInitIndexed (ScreenPtr pScreen, + PictFormatPtr pFormat) +{ + ColormapPtr pColormap = pFormat->index.pColormap; + VisualPtr pVisual = pColormap->pVisual; + miIndexedPtr pIndexed; + Pixel pixels[MI_MAX_INDEXED]; + xrgb rgb[MI_MAX_INDEXED]; + int num; + int i; + Pixel p, r, g, b; + + if (pVisual->ColormapEntries > MI_MAX_INDEXED) + return FALSE; + + if (pVisual->class & DynamicClass) + { + if (!miBuildRenderColormap (pColormap, pixels, &num)) + return FALSE; + } + else + { + num = pVisual->ColormapEntries; + for (p = 0; p < num; p++) + pixels[p] = p; + } + + pIndexed = malloc(sizeof (miIndexedRec)); + if (!pIndexed) + return FALSE; + + pFormat->index.nvalues = num; + pFormat->index.pValues = malloc(num * sizeof (xIndexValue)); + if (!pFormat->index.pValues) + { + free(pIndexed); + return FALSE; + } + + + /* + * Build mapping from pixel value to ARGB + */ + QueryColors (pColormap, num, pixels, rgb, serverClient); + for (i = 0; i < num; i++) + { + p = pixels[i]; + pFormat->index.pValues[i].pixel = p; + pFormat->index.pValues[i].red = rgb[i].red; + pFormat->index.pValues[i].green = rgb[i].green; + pFormat->index.pValues[i].blue = rgb[i].blue; + pFormat->index.pValues[i].alpha = 0xffff; + pIndexed->rgba[p] = (0xff000000 | + ((rgb[i].red & 0xff00) << 8) | + ((rgb[i].green & 0xff00) ) | + ((rgb[i].blue & 0xff00) >> 8)); + } + + /* + * Build mapping from RGB to pixel value. This could probably be + * done a bit quicker... + */ + switch (pVisual->class | DynamicClass) { + case GrayScale: + pIndexed->color = FALSE; + for (r = 0; r < 32768; r++) + pIndexed->ent[r] = FindBestGray (pIndexed, pixels, num, r); + break; + case PseudoColor: + pIndexed->color = TRUE; + p = 0; + for (r = 0; r < 32; r++) + for (g = 0; g < 32; g++) + for (b = 0; b < 32; b++) + { + pIndexed->ent[p] = FindBestColor (pIndexed, pixels, num, + r, g, b); + p++; + } + break; + } + pFormat->index.devPrivate = pIndexed; + return TRUE; +} + +void +miCloseIndexed (ScreenPtr pScreen, + PictFormatPtr pFormat) +{ + if (pFormat->index.devPrivate) + { + free(pFormat->index.devPrivate); + pFormat->index.devPrivate = 0; + } + if (pFormat->index.pValues) + { + free(pFormat->index.pValues); + pFormat->index.pValues = 0; + } +} + +void +miUpdateIndexed (ScreenPtr pScreen, + PictFormatPtr pFormat, + int ndef, + xColorItem *pdef) +{ + miIndexedPtr pIndexed = pFormat->index.devPrivate; + + if (pIndexed) + { + while (ndef--) + { + pIndexed->rgba[pdef->pixel] = (0xff000000 | + ((pdef->red & 0xff00) << 8) | + ((pdef->green & 0xff00) ) | + ((pdef->blue & 0xff00) >> 8)); + pdef++; + } + } +} + +#endif /* _MIINDEX_H_ */ diff --git a/xorg-server/render/mipict.c b/xorg-server/render/mipict.c index b5dfcb2ba..3f88beba2 100644 --- a/xorg-server/render/mipict.c +++ b/xorg-server/render/mipict.c @@ -1,643 +1,643 @@ -/* - * - * Copyright © 1999 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 <dix-config.h> -#endif - -#include "scrnintstr.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "mi.h" -#include "picturestr.h" -#include "mipict.h" - -#ifndef __GNUC__ -#define __inline -#endif - -int -miCreatePicture (PicturePtr pPicture) -{ - return Success; -} - -void -miDestroyPicture (PicturePtr pPicture) -{ - if (pPicture->freeCompClip) - REGION_DESTROY(pPicture->pDrawable->pScreen, pPicture->pCompositeClip); -} - -void -miDestroyPictureClip (PicturePtr pPicture) -{ - switch (pPicture->clientClipType) { - case CT_NONE: - return; - case CT_PIXMAP: - (*pPicture->pDrawable->pScreen->DestroyPixmap) ((PixmapPtr) (pPicture->clientClip)); - break; - default: - /* - * we know we'll never have a list of rectangles, since ChangeClip - * immediately turns them into a region - */ - REGION_DESTROY(pPicture->pDrawable->pScreen, pPicture->clientClip); - break; - } - pPicture->clientClip = NULL; - pPicture->clientClipType = CT_NONE; -} - -int -miChangePictureClip (PicturePtr pPicture, - int type, - pointer value, - int n) -{ - ScreenPtr pScreen = pPicture->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - pointer clientClip; - int clientClipType; - - switch (type) { - case CT_PIXMAP: - /* convert the pixmap to a region */ - clientClip = (pointer) BITMAP_TO_REGION(pScreen, (PixmapPtr) value); - if (!clientClip) - return BadAlloc; - clientClipType = CT_REGION; - (*pScreen->DestroyPixmap) ((PixmapPtr) value); - break; - case CT_REGION: - clientClip = value; - clientClipType = CT_REGION; - break; - case CT_NONE: - clientClip = 0; - clientClipType = CT_NONE; - break; - default: - clientClip = (pointer) RECTS_TO_REGION(pScreen, n, - (xRectangle *) value, - type); - if (!clientClip) - return BadAlloc; - clientClipType = CT_REGION; - xfree(value); - break; - } - (*ps->DestroyPictureClip) (pPicture); - pPicture->clientClip = clientClip; - pPicture->clientClipType = clientClipType; - pPicture->stateChanges |= CPClipMask; - return Success; -} - -void -miChangePicture (PicturePtr pPicture, - Mask mask) -{ - return; -} - -void -miValidatePicture (PicturePtr pPicture, - Mask mask) -{ - DrawablePtr pDrawable = pPicture->pDrawable; - - if ((mask & (CPClipXOrigin|CPClipYOrigin|CPClipMask|CPSubwindowMode)) || - (pDrawable->serialNumber != (pPicture->serialNumber & DRAWABLE_SERIAL_BITS))) - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - WindowPtr pWin = (WindowPtr) pDrawable; - RegionPtr pregWin; - Bool freeTmpClip, freeCompClip; - - if (pPicture->subWindowMode == IncludeInferiors) - { - pregWin = NotClippedByChildren(pWin); - freeTmpClip = TRUE; - } - else - { - pregWin = &pWin->clipList; - freeTmpClip = FALSE; - } - freeCompClip = pPicture->freeCompClip; - - /* - * if there is no client clip, we can get by with just keeping the - * pointer we got, and remembering whether or not should destroy - * (or maybe re-use) it later. this way, we avoid unnecessary - * copying of regions. (this wins especially if many clients clip - * by children and have no client clip.) - */ - if (pPicture->clientClipType == CT_NONE) - { - if (freeCompClip) - REGION_DESTROY(pScreen, pPicture->pCompositeClip); - pPicture->pCompositeClip = pregWin; - pPicture->freeCompClip = freeTmpClip; - } - else - { - /* - * we need one 'real' region to put into the composite clip. if - * pregWin the current composite clip are real, we can get rid of - * one. if pregWin is real and the current composite clip isn't, - * use pregWin for the composite clip. if the current composite - * clip is real and pregWin isn't, use the current composite - * clip. if neither is real, create a new region. - */ - - REGION_TRANSLATE(pScreen, pPicture->clientClip, - pDrawable->x + pPicture->clipOrigin.x, - pDrawable->y + pPicture->clipOrigin.y); - - if (freeCompClip) - { - REGION_INTERSECT(pScreen, pPicture->pCompositeClip, - pregWin, pPicture->clientClip); - if (freeTmpClip) - REGION_DESTROY(pScreen, pregWin); - } - else if (freeTmpClip) - { - REGION_INTERSECT(pScreen, pregWin, pregWin, pPicture->clientClip); - pPicture->pCompositeClip = pregWin; - } - else - { - pPicture->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); - REGION_INTERSECT(pScreen, pPicture->pCompositeClip, - pregWin, pPicture->clientClip); - } - pPicture->freeCompClip = TRUE; - REGION_TRANSLATE(pScreen, pPicture->clientClip, - -(pDrawable->x + pPicture->clipOrigin.x), - -(pDrawable->y + pPicture->clipOrigin.y)); - } - } /* end of composite clip for a window */ - else - { - BoxRec pixbounds; - - /* XXX should we translate by drawable.x/y here ? */ - /* If you want pixmaps in offscreen memory, yes */ - pixbounds.x1 = pDrawable->x; - pixbounds.y1 = pDrawable->y; - pixbounds.x2 = pDrawable->x + pDrawable->width; - pixbounds.y2 = pDrawable->y + pDrawable->height; - - if (pPicture->freeCompClip) - { - REGION_RESET(pScreen, pPicture->pCompositeClip, &pixbounds); - } - else - { - pPicture->freeCompClip = TRUE; - pPicture->pCompositeClip = REGION_CREATE(pScreen, &pixbounds, 1); - } - - if (pPicture->clientClipType == CT_REGION) - { - if(pDrawable->x || pDrawable->y) { - REGION_TRANSLATE(pScreen, pPicture->clientClip, - pDrawable->x + pPicture->clipOrigin.x, - pDrawable->y + pPicture->clipOrigin.y); - REGION_INTERSECT(pScreen, pPicture->pCompositeClip, - pPicture->pCompositeClip, pPicture->clientClip); - REGION_TRANSLATE(pScreen, pPicture->clientClip, - -(pDrawable->x + pPicture->clipOrigin.x), - -(pDrawable->y + pPicture->clipOrigin.y)); - } else { - REGION_TRANSLATE(pScreen, pPicture->pCompositeClip, - -pPicture->clipOrigin.x, -pPicture->clipOrigin.y); - REGION_INTERSECT(pScreen, pPicture->pCompositeClip, - pPicture->pCompositeClip, pPicture->clientClip); - REGION_TRANSLATE(pScreen, pPicture->pCompositeClip, - pPicture->clipOrigin.x, pPicture->clipOrigin.y); - } - } - } /* end of composite clip for pixmap */ - } -} - -int -miChangePictureTransform (PicturePtr pPicture, - PictTransform *transform) -{ - return Success; -} - -int -miChangePictureFilter (PicturePtr pPicture, - int filter, - xFixed *params, - int nparams) -{ - return Success; -} - -#define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) - -static inline pixman_bool_t -miClipPictureReg (pixman_region16_t * pRegion, - pixman_region16_t * pClip, - int dx, - int dy) -{ - if (pixman_region_n_rects(pRegion) == 1 && - pixman_region_n_rects(pClip) == 1) - { - pixman_box16_t * pRbox = pixman_region_rectangles(pRegion, NULL); - pixman_box16_t * pCbox = pixman_region_rectangles(pClip, NULL); - int v; - - if (pRbox->x1 < (v = pCbox->x1 + dx)) - pRbox->x1 = BOUND(v); - if (pRbox->x2 > (v = pCbox->x2 + dx)) - pRbox->x2 = BOUND(v); - if (pRbox->y1 < (v = pCbox->y1 + dy)) - pRbox->y1 = BOUND(v); - if (pRbox->y2 > (v = pCbox->y2 + dy)) - pRbox->y2 = BOUND(v); - if (pRbox->x1 >= pRbox->x2 || - pRbox->y1 >= pRbox->y2) - { - pixman_region_init (pRegion); - } - } - else if (!pixman_region_not_empty (pClip)) - return FALSE; - else - { - if (dx || dy) - pixman_region_translate (pRegion, -dx, -dy); - if (!pixman_region_intersect (pRegion, pRegion, pClip)) - return FALSE; - if (dx || dy) - pixman_region_translate(pRegion, dx, dy); - } - return pixman_region_not_empty(pRegion); -} - -static __inline Bool -miClipPictureSrc (RegionPtr pRegion, - PicturePtr pPicture, - int dx, - int dy) -{ - if (pPicture->clientClipType != CT_NONE) - { - Bool result; - - pixman_region_translate ( pPicture->clientClip, - pPicture->clipOrigin.x + dx, - pPicture->clipOrigin.y + dy); - - result = REGION_INTERSECT (pScreen, pRegion, pRegion, pPicture->clientClip); - - pixman_region_translate ( pPicture->clientClip, - - (pPicture->clipOrigin.x + dx), - - (pPicture->clipOrigin.y + dy)); - - if (!result) - return FALSE; - } - return TRUE; -} - -void -miCompositeSourceValidate (PicturePtr pPicture, - INT16 x, - INT16 y, - CARD16 width, - CARD16 height) -{ - DrawablePtr pDrawable = pPicture->pDrawable; - ScreenPtr pScreen; - - if (!pDrawable) - return; - - pScreen = pDrawable->pScreen; - - if (pScreen->SourceValidate) - { - if (pPicture->transform) - { - xPoint points[4]; - int i; - int xmin, ymin, xmax, ymax; - -#define VectorSet(i,_x,_y) { points[i].x = _x; points[i].y = _y; } - VectorSet (0, x, y); - VectorSet (1, x + width, y); - VectorSet (2, x, y + height); - VectorSet (3, x + width, y + height); - xmin = ymin = 32767; - xmax = ymax = -32737; - for (i = 0; i < 4; i++) - { - PictVector t; - t.vector[0] = IntToxFixed (points[i].x); - t.vector[1] = IntToxFixed (points[i].y); - t.vector[2] = xFixed1; - if (pixman_transform_point (pPicture->transform, &t)) - { - int tx = xFixedToInt (t.vector[0]); - int ty = xFixedToInt (t.vector[1]); - if (tx < xmin) xmin = tx; - if (tx > xmax) xmax = tx; - if (ty < ymin) ymin = ty; - if (ty > ymax) ymax = ty; - } - } - x = xmin; - y = ymin; - width = xmax - xmin; - height = ymax - ymin; - } - x += pPicture->pDrawable->x; - y += pPicture->pDrawable->y; - (*pScreen->SourceValidate) (pDrawable, x, y, width, height); - } -} - -/* - * returns FALSE if the final region is empty. Indistinguishable from - * an allocation failure, but rendering ignores those anyways. - */ - -Bool -miComputeCompositeRegion (RegionPtr pRegion, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - - int v; - - pRegion->extents.x1 = xDst; - v = xDst + width; - pRegion->extents.x2 = BOUND(v); - pRegion->extents.y1 = yDst; - v = yDst + height; - pRegion->extents.y2 = BOUND(v); - pRegion->data = 0; - /* Check for empty operation */ - if (pRegion->extents.x1 >= pRegion->extents.x2 || - pRegion->extents.y1 >= pRegion->extents.y2) - { - pixman_region_init (pRegion); - return FALSE; - } - /* clip against dst */ - if (!miClipPictureReg (pRegion, pDst->pCompositeClip, 0, 0)) - { - pixman_region_fini (pRegion); - return FALSE; - } - if (pDst->alphaMap) - { - if (!miClipPictureReg (pRegion, pDst->alphaMap->pCompositeClip, - -pDst->alphaOrigin.x, - -pDst->alphaOrigin.y)) - { - pixman_region_fini (pRegion); - return FALSE; - } - } - /* clip against src */ - if (!miClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc)) - { - pixman_region_fini (pRegion); - return FALSE; - } - if (pSrc->alphaMap) - { - if (!miClipPictureSrc (pRegion, pSrc->alphaMap, - xDst - (xSrc - pSrc->alphaOrigin.x), - yDst - (ySrc - pSrc->alphaOrigin.y))) - { - pixman_region_fini (pRegion); - return FALSE; - } - } - /* clip against mask */ - if (pMask) - { - if (!miClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask)) - { - pixman_region_fini (pRegion); - return FALSE; - } - if (pMask->alphaMap) - { - if (!miClipPictureSrc (pRegion, pMask->alphaMap, - xDst - (xMask - pMask->alphaOrigin.x), - yDst - (yMask - pMask->alphaOrigin.y))) - { - pixman_region_fini (pRegion); - return FALSE; - } - } - } - - - miCompositeSourceValidate (pSrc, xSrc, ySrc, width, height); - if (pMask) - miCompositeSourceValidate (pMask, xMask, yMask, width, height); - - return TRUE; -} - -void -miRenderColorToPixel (PictFormatPtr format, - xRenderColor *color, - CARD32 *pixel) -{ - CARD32 r, g, b, a; - miIndexedPtr pIndexed; - - switch (format->type) { - case PictTypeDirect: - r = color->red >> (16 - Ones (format->direct.redMask)); - g = color->green >> (16 - Ones (format->direct.greenMask)); - b = color->blue >> (16 - Ones (format->direct.blueMask)); - a = color->alpha >> (16 - Ones (format->direct.alphaMask)); - r = r << format->direct.red; - g = g << format->direct.green; - b = b << format->direct.blue; - a = a << format->direct.alpha; - *pixel = r|g|b|a; - break; - case PictTypeIndexed: - pIndexed = (miIndexedPtr) (format->index.devPrivate); - if (pIndexed->color) - { - r = color->red >> 11; - g = color->green >> 11; - b = color->blue >> 11; - *pixel = miIndexToEnt15 (pIndexed, (r << 10) | (g << 5) | b); - } - else - { - r = color->red >> 8; - g = color->green >> 8; - b = color->blue >> 8; - *pixel = miIndexToEntY24 (pIndexed, (r << 16) | (g << 8) | b); - } - break; - } -} - -static CARD16 -miFillColor (CARD32 pixel, int bits) -{ - while (bits < 16) - { - pixel |= pixel << bits; - bits <<= 1; - } - return (CARD16) pixel; -} - -Bool -miIsSolidAlpha (PicturePtr pSrc) -{ - ScreenPtr pScreen; - char line[1]; - - if (!pSrc->pDrawable) - return FALSE; - - pScreen = pSrc->pDrawable->pScreen; - - /* Alpha-only */ - if (PICT_FORMAT_TYPE (pSrc->format) != PICT_TYPE_A) - return FALSE; - /* repeat */ - if (!pSrc->repeat) - return FALSE; - /* 1x1 */ - if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1) - return FALSE; - line[0] = 1; - (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line); - switch (pSrc->pDrawable->bitsPerPixel) { - case 1: - return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80; - case 4: - return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0; - case 8: - return (CARD8) line[0] == 0xff; - default: - return FALSE; - } -} - -void -miRenderPixelToColor (PictFormatPtr format, - CARD32 pixel, - xRenderColor *color) -{ - CARD32 r, g, b, a; - miIndexedPtr pIndexed; - - switch (format->type) { - case PictTypeDirect: - r = (pixel >> format->direct.red) & format->direct.redMask; - g = (pixel >> format->direct.green) & format->direct.greenMask; - b = (pixel >> format->direct.blue) & format->direct.blueMask; - a = (pixel >> format->direct.alpha) & format->direct.alphaMask; - color->red = miFillColor (r, Ones (format->direct.redMask)); - color->green = miFillColor (g, Ones (format->direct.greenMask)); - color->blue = miFillColor (b, Ones (format->direct.blueMask)); - color->alpha = miFillColor (a, Ones (format->direct.alphaMask)); - break; - case PictTypeIndexed: - pIndexed = (miIndexedPtr) (format->index.devPrivate); - pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED-1)]; - r = (pixel >> 16) & 0xff; - g = (pixel >> 8) & 0xff; - b = (pixel ) & 0xff; - color->red = miFillColor (r, 8); - color->green = miFillColor (g, 8); - color->blue = miFillColor (b, 8); - color->alpha = 0xffff; - break; - } -} - -Bool -miPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats) -{ - PictureScreenPtr ps; - - if (!PictureInit (pScreen, formats, nformats)) - return FALSE; - ps = GetPictureScreen(pScreen); - ps->CreatePicture = miCreatePicture; - ps->DestroyPicture = miDestroyPicture; - ps->ChangePictureClip = miChangePictureClip; - ps->DestroyPictureClip = miDestroyPictureClip; - ps->ChangePicture = miChangePicture; - ps->ValidatePicture = miValidatePicture; - ps->InitIndexed = miInitIndexed; - ps->CloseIndexed = miCloseIndexed; - ps->UpdateIndexed = miUpdateIndexed; - ps->ChangePictureTransform = miChangePictureTransform; - ps->ChangePictureFilter = miChangePictureFilter; - ps->RealizeGlyph = miRealizeGlyph; - ps->UnrealizeGlyph = miUnrealizeGlyph; - - /* MI rendering routines */ - ps->Composite = 0; /* requires DDX support */ - ps->Glyphs = miGlyphs; - ps->CompositeRects = miCompositeRects; - ps->Trapezoids = miTrapezoids; - ps->Triangles = miTriangles; - ps->TriStrip = miTriStrip; - ps->TriFan = miTriFan; - - ps->RasterizeTrapezoid = 0; /* requires DDX support */ - ps->AddTraps = 0; /* requires DDX support */ - ps->AddTriangles = 0; /* requires DDX support */ - - return TRUE; -} +/* + * + * Copyright © 1999 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 <dix-config.h> +#endif + +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "mi.h" +#include "picturestr.h" +#include "mipict.h" + +#ifndef __GNUC__ +#define __inline +#endif + +int +miCreatePicture (PicturePtr pPicture) +{ + return Success; +} + +void +miDestroyPicture (PicturePtr pPicture) +{ + if (pPicture->freeCompClip) + REGION_DESTROY(pPicture->pDrawable->pScreen, pPicture->pCompositeClip); +} + +void +miDestroyPictureClip (PicturePtr pPicture) +{ + switch (pPicture->clientClipType) { + case CT_NONE: + return; + case CT_PIXMAP: + (*pPicture->pDrawable->pScreen->DestroyPixmap) ((PixmapPtr) (pPicture->clientClip)); + break; + default: + /* + * we know we'll never have a list of rectangles, since ChangeClip + * immediately turns them into a region + */ + REGION_DESTROY(pPicture->pDrawable->pScreen, pPicture->clientClip); + break; + } + pPicture->clientClip = NULL; + pPicture->clientClipType = CT_NONE; +} + +int +miChangePictureClip (PicturePtr pPicture, + int type, + pointer value, + int n) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + pointer clientClip; + int clientClipType; + + switch (type) { + case CT_PIXMAP: + /* convert the pixmap to a region */ + clientClip = (pointer) BITMAP_TO_REGION(pScreen, (PixmapPtr) value); + if (!clientClip) + return BadAlloc; + clientClipType = CT_REGION; + (*pScreen->DestroyPixmap) ((PixmapPtr) value); + break; + case CT_REGION: + clientClip = value; + clientClipType = CT_REGION; + break; + case CT_NONE: + clientClip = 0; + clientClipType = CT_NONE; + break; + default: + clientClip = (pointer) RECTS_TO_REGION(pScreen, n, + (xRectangle *) value, + type); + if (!clientClip) + return BadAlloc; + clientClipType = CT_REGION; + free(value); + break; + } + (*ps->DestroyPictureClip) (pPicture); + pPicture->clientClip = clientClip; + pPicture->clientClipType = clientClipType; + pPicture->stateChanges |= CPClipMask; + return Success; +} + +void +miChangePicture (PicturePtr pPicture, + Mask mask) +{ + return; +} + +void +miValidatePicture (PicturePtr pPicture, + Mask mask) +{ + DrawablePtr pDrawable = pPicture->pDrawable; + + if ((mask & (CPClipXOrigin|CPClipYOrigin|CPClipMask|CPSubwindowMode)) || + (pDrawable->serialNumber != (pPicture->serialNumber & DRAWABLE_SERIAL_BITS))) + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + WindowPtr pWin = (WindowPtr) pDrawable; + RegionPtr pregWin; + Bool freeTmpClip, freeCompClip; + + if (pPicture->subWindowMode == IncludeInferiors) + { + pregWin = NotClippedByChildren(pWin); + freeTmpClip = TRUE; + } + else + { + pregWin = &pWin->clipList; + freeTmpClip = FALSE; + } + freeCompClip = pPicture->freeCompClip; + + /* + * if there is no client clip, we can get by with just keeping the + * pointer we got, and remembering whether or not should destroy + * (or maybe re-use) it later. this way, we avoid unnecessary + * copying of regions. (this wins especially if many clients clip + * by children and have no client clip.) + */ + if (pPicture->clientClipType == CT_NONE) + { + if (freeCompClip) + REGION_DESTROY(pScreen, pPicture->pCompositeClip); + pPicture->pCompositeClip = pregWin; + pPicture->freeCompClip = freeTmpClip; + } + else + { + /* + * we need one 'real' region to put into the composite clip. if + * pregWin the current composite clip are real, we can get rid of + * one. if pregWin is real and the current composite clip isn't, + * use pregWin for the composite clip. if the current composite + * clip is real and pregWin isn't, use the current composite + * clip. if neither is real, create a new region. + */ + + REGION_TRANSLATE(pScreen, pPicture->clientClip, + pDrawable->x + pPicture->clipOrigin.x, + pDrawable->y + pPicture->clipOrigin.y); + + if (freeCompClip) + { + REGION_INTERSECT(pScreen, pPicture->pCompositeClip, + pregWin, pPicture->clientClip); + if (freeTmpClip) + REGION_DESTROY(pScreen, pregWin); + } + else if (freeTmpClip) + { + REGION_INTERSECT(pScreen, pregWin, pregWin, pPicture->clientClip); + pPicture->pCompositeClip = pregWin; + } + else + { + pPicture->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); + REGION_INTERSECT(pScreen, pPicture->pCompositeClip, + pregWin, pPicture->clientClip); + } + pPicture->freeCompClip = TRUE; + REGION_TRANSLATE(pScreen, pPicture->clientClip, + -(pDrawable->x + pPicture->clipOrigin.x), + -(pDrawable->y + pPicture->clipOrigin.y)); + } + } /* end of composite clip for a window */ + else + { + BoxRec pixbounds; + + /* XXX should we translate by drawable.x/y here ? */ + /* If you want pixmaps in offscreen memory, yes */ + pixbounds.x1 = pDrawable->x; + pixbounds.y1 = pDrawable->y; + pixbounds.x2 = pDrawable->x + pDrawable->width; + pixbounds.y2 = pDrawable->y + pDrawable->height; + + if (pPicture->freeCompClip) + { + REGION_RESET(pScreen, pPicture->pCompositeClip, &pixbounds); + } + else + { + pPicture->freeCompClip = TRUE; + pPicture->pCompositeClip = REGION_CREATE(pScreen, &pixbounds, 1); + } + + if (pPicture->clientClipType == CT_REGION) + { + if(pDrawable->x || pDrawable->y) { + REGION_TRANSLATE(pScreen, pPicture->clientClip, + pDrawable->x + pPicture->clipOrigin.x, + pDrawable->y + pPicture->clipOrigin.y); + REGION_INTERSECT(pScreen, pPicture->pCompositeClip, + pPicture->pCompositeClip, pPicture->clientClip); + REGION_TRANSLATE(pScreen, pPicture->clientClip, + -(pDrawable->x + pPicture->clipOrigin.x), + -(pDrawable->y + pPicture->clipOrigin.y)); + } else { + REGION_TRANSLATE(pScreen, pPicture->pCompositeClip, + -pPicture->clipOrigin.x, -pPicture->clipOrigin.y); + REGION_INTERSECT(pScreen, pPicture->pCompositeClip, + pPicture->pCompositeClip, pPicture->clientClip); + REGION_TRANSLATE(pScreen, pPicture->pCompositeClip, + pPicture->clipOrigin.x, pPicture->clipOrigin.y); + } + } + } /* end of composite clip for pixmap */ + } +} + +int +miChangePictureTransform (PicturePtr pPicture, + PictTransform *transform) +{ + return Success; +} + +int +miChangePictureFilter (PicturePtr pPicture, + int filter, + xFixed *params, + int nparams) +{ + return Success; +} + +#define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) + +static inline pixman_bool_t +miClipPictureReg (pixman_region16_t * pRegion, + pixman_region16_t * pClip, + int dx, + int dy) +{ + if (pixman_region_n_rects(pRegion) == 1 && + pixman_region_n_rects(pClip) == 1) + { + pixman_box16_t * pRbox = pixman_region_rectangles(pRegion, NULL); + pixman_box16_t * pCbox = pixman_region_rectangles(pClip, NULL); + int v; + + if (pRbox->x1 < (v = pCbox->x1 + dx)) + pRbox->x1 = BOUND(v); + if (pRbox->x2 > (v = pCbox->x2 + dx)) + pRbox->x2 = BOUND(v); + if (pRbox->y1 < (v = pCbox->y1 + dy)) + pRbox->y1 = BOUND(v); + if (pRbox->y2 > (v = pCbox->y2 + dy)) + pRbox->y2 = BOUND(v); + if (pRbox->x1 >= pRbox->x2 || + pRbox->y1 >= pRbox->y2) + { + pixman_region_init (pRegion); + } + } + else if (!pixman_region_not_empty (pClip)) + return FALSE; + else + { + if (dx || dy) + pixman_region_translate (pRegion, -dx, -dy); + if (!pixman_region_intersect (pRegion, pRegion, pClip)) + return FALSE; + if (dx || dy) + pixman_region_translate(pRegion, dx, dy); + } + return pixman_region_not_empty(pRegion); +} + +static __inline Bool +miClipPictureSrc (RegionPtr pRegion, + PicturePtr pPicture, + int dx, + int dy) +{ + if (pPicture->clientClipType != CT_NONE) + { + Bool result; + + pixman_region_translate ( pPicture->clientClip, + pPicture->clipOrigin.x + dx, + pPicture->clipOrigin.y + dy); + + result = REGION_INTERSECT (pScreen, pRegion, pRegion, pPicture->clientClip); + + pixman_region_translate ( pPicture->clientClip, + - (pPicture->clipOrigin.x + dx), + - (pPicture->clipOrigin.y + dy)); + + if (!result) + return FALSE; + } + return TRUE; +} + +void +miCompositeSourceValidate (PicturePtr pPicture, + INT16 x, + INT16 y, + CARD16 width, + CARD16 height) +{ + DrawablePtr pDrawable = pPicture->pDrawable; + ScreenPtr pScreen; + + if (!pDrawable) + return; + + pScreen = pDrawable->pScreen; + + if (pScreen->SourceValidate) + { + if (pPicture->transform) + { + xPoint points[4]; + int i; + int xmin, ymin, xmax, ymax; + +#define VectorSet(i,_x,_y) { points[i].x = _x; points[i].y = _y; } + VectorSet (0, x, y); + VectorSet (1, x + width, y); + VectorSet (2, x, y + height); + VectorSet (3, x + width, y + height); + xmin = ymin = 32767; + xmax = ymax = -32737; + for (i = 0; i < 4; i++) + { + PictVector t; + t.vector[0] = IntToxFixed (points[i].x); + t.vector[1] = IntToxFixed (points[i].y); + t.vector[2] = xFixed1; + if (pixman_transform_point (pPicture->transform, &t)) + { + int tx = xFixedToInt (t.vector[0]); + int ty = xFixedToInt (t.vector[1]); + if (tx < xmin) xmin = tx; + if (tx > xmax) xmax = tx; + if (ty < ymin) ymin = ty; + if (ty > ymax) ymax = ty; + } + } + x = xmin; + y = ymin; + width = xmax - xmin; + height = ymax - ymin; + } + x += pPicture->pDrawable->x; + y += pPicture->pDrawable->y; + (*pScreen->SourceValidate) (pDrawable, x, y, width, height); + } +} + +/* + * returns FALSE if the final region is empty. Indistinguishable from + * an allocation failure, but rendering ignores those anyways. + */ + +Bool +miComputeCompositeRegion (RegionPtr pRegion, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + + int v; + + pRegion->extents.x1 = xDst; + v = xDst + width; + pRegion->extents.x2 = BOUND(v); + pRegion->extents.y1 = yDst; + v = yDst + height; + pRegion->extents.y2 = BOUND(v); + pRegion->data = 0; + /* Check for empty operation */ + if (pRegion->extents.x1 >= pRegion->extents.x2 || + pRegion->extents.y1 >= pRegion->extents.y2) + { + pixman_region_init (pRegion); + return FALSE; + } + /* clip against dst */ + if (!miClipPictureReg (pRegion, pDst->pCompositeClip, 0, 0)) + { + pixman_region_fini (pRegion); + return FALSE; + } + if (pDst->alphaMap) + { + if (!miClipPictureReg (pRegion, pDst->alphaMap->pCompositeClip, + -pDst->alphaOrigin.x, + -pDst->alphaOrigin.y)) + { + pixman_region_fini (pRegion); + return FALSE; + } + } + /* clip against src */ + if (!miClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc)) + { + pixman_region_fini (pRegion); + return FALSE; + } + if (pSrc->alphaMap) + { + if (!miClipPictureSrc (pRegion, pSrc->alphaMap, + xDst - (xSrc - pSrc->alphaOrigin.x), + yDst - (ySrc - pSrc->alphaOrigin.y))) + { + pixman_region_fini (pRegion); + return FALSE; + } + } + /* clip against mask */ + if (pMask) + { + if (!miClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask)) + { + pixman_region_fini (pRegion); + return FALSE; + } + if (pMask->alphaMap) + { + if (!miClipPictureSrc (pRegion, pMask->alphaMap, + xDst - (xMask - pMask->alphaOrigin.x), + yDst - (yMask - pMask->alphaOrigin.y))) + { + pixman_region_fini (pRegion); + return FALSE; + } + } + } + + + miCompositeSourceValidate (pSrc, xSrc, ySrc, width, height); + if (pMask) + miCompositeSourceValidate (pMask, xMask, yMask, width, height); + + return TRUE; +} + +void +miRenderColorToPixel (PictFormatPtr format, + xRenderColor *color, + CARD32 *pixel) +{ + CARD32 r, g, b, a; + miIndexedPtr pIndexed; + + switch (format->type) { + case PictTypeDirect: + r = color->red >> (16 - Ones (format->direct.redMask)); + g = color->green >> (16 - Ones (format->direct.greenMask)); + b = color->blue >> (16 - Ones (format->direct.blueMask)); + a = color->alpha >> (16 - Ones (format->direct.alphaMask)); + r = r << format->direct.red; + g = g << format->direct.green; + b = b << format->direct.blue; + a = a << format->direct.alpha; + *pixel = r|g|b|a; + break; + case PictTypeIndexed: + pIndexed = (miIndexedPtr) (format->index.devPrivate); + if (pIndexed->color) + { + r = color->red >> 11; + g = color->green >> 11; + b = color->blue >> 11; + *pixel = miIndexToEnt15 (pIndexed, (r << 10) | (g << 5) | b); + } + else + { + r = color->red >> 8; + g = color->green >> 8; + b = color->blue >> 8; + *pixel = miIndexToEntY24 (pIndexed, (r << 16) | (g << 8) | b); + } + break; + } +} + +static CARD16 +miFillColor (CARD32 pixel, int bits) +{ + while (bits < 16) + { + pixel |= pixel << bits; + bits <<= 1; + } + return (CARD16) pixel; +} + +Bool +miIsSolidAlpha (PicturePtr pSrc) +{ + ScreenPtr pScreen; + char line[1]; + + if (!pSrc->pDrawable) + return FALSE; + + pScreen = pSrc->pDrawable->pScreen; + + /* Alpha-only */ + if (PICT_FORMAT_TYPE (pSrc->format) != PICT_TYPE_A) + return FALSE; + /* repeat */ + if (!pSrc->repeat) + return FALSE; + /* 1x1 */ + if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1) + return FALSE; + line[0] = 1; + (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line); + switch (pSrc->pDrawable->bitsPerPixel) { + case 1: + return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80; + case 4: + return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0; + case 8: + return (CARD8) line[0] == 0xff; + default: + return FALSE; + } +} + +void +miRenderPixelToColor (PictFormatPtr format, + CARD32 pixel, + xRenderColor *color) +{ + CARD32 r, g, b, a; + miIndexedPtr pIndexed; + + switch (format->type) { + case PictTypeDirect: + r = (pixel >> format->direct.red) & format->direct.redMask; + g = (pixel >> format->direct.green) & format->direct.greenMask; + b = (pixel >> format->direct.blue) & format->direct.blueMask; + a = (pixel >> format->direct.alpha) & format->direct.alphaMask; + color->red = miFillColor (r, Ones (format->direct.redMask)); + color->green = miFillColor (g, Ones (format->direct.greenMask)); + color->blue = miFillColor (b, Ones (format->direct.blueMask)); + color->alpha = miFillColor (a, Ones (format->direct.alphaMask)); + break; + case PictTypeIndexed: + pIndexed = (miIndexedPtr) (format->index.devPrivate); + pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED-1)]; + r = (pixel >> 16) & 0xff; + g = (pixel >> 8) & 0xff; + b = (pixel ) & 0xff; + color->red = miFillColor (r, 8); + color->green = miFillColor (g, 8); + color->blue = miFillColor (b, 8); + color->alpha = 0xffff; + break; + } +} + +Bool +miPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats) +{ + PictureScreenPtr ps; + + if (!PictureInit (pScreen, formats, nformats)) + return FALSE; + ps = GetPictureScreen(pScreen); + ps->CreatePicture = miCreatePicture; + ps->DestroyPicture = miDestroyPicture; + ps->ChangePictureClip = miChangePictureClip; + ps->DestroyPictureClip = miDestroyPictureClip; + ps->ChangePicture = miChangePicture; + ps->ValidatePicture = miValidatePicture; + ps->InitIndexed = miInitIndexed; + ps->CloseIndexed = miCloseIndexed; + ps->UpdateIndexed = miUpdateIndexed; + ps->ChangePictureTransform = miChangePictureTransform; + ps->ChangePictureFilter = miChangePictureFilter; + ps->RealizeGlyph = miRealizeGlyph; + ps->UnrealizeGlyph = miUnrealizeGlyph; + + /* MI rendering routines */ + ps->Composite = 0; /* requires DDX support */ + ps->Glyphs = miGlyphs; + ps->CompositeRects = miCompositeRects; + ps->Trapezoids = miTrapezoids; + ps->Triangles = miTriangles; + ps->TriStrip = miTriStrip; + ps->TriFan = miTriFan; + + ps->RasterizeTrapezoid = 0; /* requires DDX support */ + ps->AddTraps = 0; /* requires DDX support */ + ps->AddTriangles = 0; /* requires DDX support */ + + return TRUE; +} diff --git a/xorg-server/render/mirect.c b/xorg-server/render/mirect.c index b54fe6fe6..70bdf63f6 100644 --- a/xorg-server/render/mirect.c +++ b/xorg-server/render/mirect.c @@ -1,185 +1,186 @@ -/* - * - * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. - * - * 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 <dix-config.h> -#endif - -#include "scrnintstr.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "mi.h" -#include "picturestr.h" -#include "mipict.h" - -static void -miColorRects (PicturePtr pDst, - PicturePtr pClipPict, - xRenderColor *color, - int nRect, - xRectangle *rects, - int xoff, - int yoff) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - CARD32 pixel; - GCPtr pGC; - CARD32 tmpval[5]; - RegionPtr pClip; - unsigned long mask; - - miRenderColorToPixel (pDst->pFormat, color, &pixel); - - pGC = GetScratchGC (pDst->pDrawable->depth, pScreen); - if (!pGC) - return; - tmpval[0] = GXcopy; - tmpval[1] = pixel; - tmpval[2] = pDst->subWindowMode; - mask = GCFunction | GCForeground | GCSubwindowMode; - if (pClipPict->clientClipType == CT_REGION) - { - tmpval[3] = pDst->clipOrigin.x - xoff; - tmpval[4] = pDst->clipOrigin.y - yoff; - mask |= GCClipXOrigin|GCClipYOrigin; - - pClip = REGION_CREATE (pScreen, NULL, 1); - REGION_COPY (pScreen, pClip, - (RegionPtr) pClipPict->clientClip); - (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pClip, 0); - } - - ChangeGC (pGC, mask, tmpval); - ValidateGC (pDst->pDrawable, pGC); - if (xoff || yoff) - { - int i; - for (i = 0; i < nRect; i++) - { - rects[i].x -= xoff; - rects[i].y -= yoff; - } - } - (*pGC->ops->PolyFillRect) (pDst->pDrawable, pGC, nRect, rects); - if (xoff || yoff) - { - int i; - for (i = 0; i < nRect; i++) - { - rects[i].x += xoff; - rects[i].y += yoff; - } - } - FreeScratchGC (pGC); -} - -void -miCompositeRects (CARD8 op, - PicturePtr pDst, - xRenderColor *color, - int nRect, - xRectangle *rects) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - - if (color->alpha == 0xffff) - { - if (op == PictOpOver) - op = PictOpSrc; - } - if (op == PictOpClear) - color->red = color->green = color->blue = color->alpha = 0; - - if (op == PictOpSrc || op == PictOpClear) - { - miColorRects (pDst, pDst, color, nRect, rects, 0, 0); - if (pDst->alphaMap) - miColorRects (pDst->alphaMap, pDst, - color, nRect, rects, - pDst->alphaOrigin.x, - pDst->alphaOrigin.y); - } - else - { - PictFormatPtr rgbaFormat; - PixmapPtr pPixmap; - PicturePtr pSrc; - xRectangle one; - int error; - Pixel pixel; - GCPtr pGC; - CARD32 tmpval[2]; - - rgbaFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); - if (!rgbaFormat) - goto bail1; - - pPixmap = (*pScreen->CreatePixmap) (pScreen, 1, 1, rgbaFormat->depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pPixmap) - goto bail2; - - miRenderColorToPixel (rgbaFormat, color, &pixel); - - pGC = GetScratchGC (rgbaFormat->depth, pScreen); - if (!pGC) - goto bail3; - tmpval[0] = GXcopy; - tmpval[1] = pixel; - - ChangeGC (pGC, GCFunction | GCForeground, tmpval); - ValidateGC (&pPixmap->drawable, pGC); - one.x = 0; - one.y = 0; - one.width = 1; - one.height = 1; - (*pGC->ops->PolyFillRect) (&pPixmap->drawable, pGC, 1, &one); - - tmpval[0] = xTrue; - pSrc = CreatePicture (0, &pPixmap->drawable, rgbaFormat, - CPRepeat, tmpval, serverClient, &error); - - if (!pSrc) - goto bail4; - - while (nRect--) - { - CompositePicture (op, pSrc, 0, pDst, 0, 0, 0, 0, - rects->x, - rects->y, - rects->width, - rects->height); - rects++; - } - - FreePicture ((pointer) pSrc, 0); -bail4: - FreeScratchGC (pGC); -bail3: - (*pScreen->DestroyPixmap) (pPixmap); -bail2: -bail1: - ; - } -} +/* + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * + * 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 <dix-config.h> +#endif + +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "mi.h" +#include "picturestr.h" +#include "mipict.h" + +static void +miColorRects (PicturePtr pDst, + PicturePtr pClipPict, + xRenderColor *color, + int nRect, + xRectangle *rects, + int xoff, + int yoff) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + CARD32 pixel; + GCPtr pGC; + ChangeGCVal tmpval[5]; + RegionPtr pClip; + unsigned long mask; + + miRenderColorToPixel (pDst->pFormat, color, &pixel); + + pGC = GetScratchGC (pDst->pDrawable->depth, pScreen); + if (!pGC) + return; + tmpval[0].val = GXcopy; + tmpval[1].val = pixel; + tmpval[2].val = pDst->subWindowMode; + mask = GCFunction | GCForeground | GCSubwindowMode; + if (pClipPict->clientClipType == CT_REGION) + { + tmpval[3].val = pDst->clipOrigin.x - xoff; + tmpval[4].val = pDst->clipOrigin.y - yoff; + mask |= GCClipXOrigin|GCClipYOrigin; + + pClip = REGION_CREATE (pScreen, NULL, 1); + REGION_COPY (pScreen, pClip, + (RegionPtr) pClipPict->clientClip); + (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pClip, 0); + } + + ChangeGC (NullClient, pGC, mask, tmpval); + ValidateGC (pDst->pDrawable, pGC); + if (xoff || yoff) + { + int i; + for (i = 0; i < nRect; i++) + { + rects[i].x -= xoff; + rects[i].y -= yoff; + } + } + (*pGC->ops->PolyFillRect) (pDst->pDrawable, pGC, nRect, rects); + if (xoff || yoff) + { + int i; + for (i = 0; i < nRect; i++) + { + rects[i].x += xoff; + rects[i].y += yoff; + } + } + FreeScratchGC (pGC); +} + +void +miCompositeRects (CARD8 op, + PicturePtr pDst, + xRenderColor *color, + int nRect, + xRectangle *rects) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + + if (color->alpha == 0xffff) + { + if (op == PictOpOver) + op = PictOpSrc; + } + if (op == PictOpClear) + color->red = color->green = color->blue = color->alpha = 0; + + if (op == PictOpSrc || op == PictOpClear) + { + miColorRects (pDst, pDst, color, nRect, rects, 0, 0); + if (pDst->alphaMap) + miColorRects (pDst->alphaMap, pDst, + color, nRect, rects, + pDst->alphaOrigin.x, + pDst->alphaOrigin.y); + } + else + { + PictFormatPtr rgbaFormat; + PixmapPtr pPixmap; + PicturePtr pSrc; + xRectangle one; + int error; + Pixel pixel; + GCPtr pGC; + ChangeGCVal gcvals[2]; + XID tmpval[1]; + + rgbaFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); + if (!rgbaFormat) + goto bail1; + + pPixmap = (*pScreen->CreatePixmap) (pScreen, 1, 1, rgbaFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pPixmap) + goto bail2; + + miRenderColorToPixel (rgbaFormat, color, &pixel); + + pGC = GetScratchGC (rgbaFormat->depth, pScreen); + if (!pGC) + goto bail3; + gcvals[0].val = GXcopy; + gcvals[1].val = pixel; + + ChangeGC (NullClient, pGC, GCFunction | GCForeground, gcvals); + ValidateGC (&pPixmap->drawable, pGC); + one.x = 0; + one.y = 0; + one.width = 1; + one.height = 1; + (*pGC->ops->PolyFillRect) (&pPixmap->drawable, pGC, 1, &one); + + tmpval[0] = xTrue; + pSrc = CreatePicture (0, &pPixmap->drawable, rgbaFormat, + CPRepeat, tmpval, serverClient, &error); + + if (!pSrc) + goto bail4; + + while (nRect--) + { + CompositePicture (op, pSrc, 0, pDst, 0, 0, 0, 0, + rects->x, + rects->y, + rects->width, + rects->height); + rects++; + } + + FreePicture ((pointer) pSrc, 0); +bail4: + FreeScratchGC (pGC); +bail3: + (*pScreen->DestroyPixmap) (pPixmap); +bail2: +bail1: + ; + } +} diff --git a/xorg-server/render/mitri.c b/xorg-server/render/mitri.c index a92c19b7e..3e11cffd9 100644 --- a/xorg-server/render/mitri.c +++ b/xorg-server/render/mitri.c @@ -1,191 +1,191 @@ -/* - * - * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. - * - * 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 <dix-config.h> -#endif - -#include "scrnintstr.h" -#include "gcstruct.h" -#include "pixmapstr.h" -#include "windowstr.h" -#include "mi.h" -#include "picturestr.h" -#include "mipict.h" - -void -miPointFixedBounds (int npoint, xPointFixed *points, BoxPtr bounds) -{ - bounds->x1 = xFixedToInt (points->x); - bounds->x2 = xFixedToInt (xFixedCeil (points->x)); - bounds->y1 = xFixedToInt (points->y); - bounds->y2 = xFixedToInt (xFixedCeil (points->y)); - points++; - npoint--; - while (npoint-- > 0) - { - INT16 x1 = xFixedToInt (points->x); - INT16 x2 = xFixedToInt (xFixedCeil (points->x)); - INT16 y1 = xFixedToInt (points->y); - INT16 y2 = xFixedToInt (xFixedCeil (points->y)); - - if (x1 < bounds->x1) - bounds->x1 = x1; - else if (x2 > bounds->x2) - bounds->x2 = x2; - if (y1 < bounds->y1) - bounds->y1 = y1; - else if (y2 > bounds->y2) - bounds->y2 = y2; - points++; - } -} - -void -miTriangleBounds (int ntri, xTriangle *tris, BoxPtr bounds) -{ - miPointFixedBounds (ntri * 3, (xPointFixed *) tris, bounds); -} - -void -miTriangles (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int ntri, - xTriangle *tris) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - - /* - * Check for solid alpha add - */ - if (op == PictOpAdd && miIsSolidAlpha (pSrc)) - { - (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); - } - else if (maskFormat) - { - BoxRec bounds; - PicturePtr pPicture; - INT16 xDst, yDst; - INT16 xRel, yRel; - - xDst = tris[0].p1.x >> 16; - yDst = tris[0].p1.y >> 16; - - miTriangleBounds (ntri, tris, &bounds); - if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) - return; - pPicture = miCreateAlphaPicture (pScreen, pDst, maskFormat, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!pPicture) - return; - (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); - - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - CompositePicture (op, pSrc, pPicture, pDst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); - FreePicture (pPicture, 0); - } - else - { - if (pDst->polyEdge == PolyEdgeSharp) - maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); - else - maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); - - for (; ntri; ntri--, tris++) - miTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); - } -} - -void -miTriStrip (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int npoint, - xPointFixed *points) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - xTriangle *tris, *tri; - int ntri; - - if (npoint < 3) - return; - ntri = npoint - 2; - tris = xalloc (ntri * sizeof (xTriangle)); - if (!tris) - return; - for (tri = tris; npoint >= 3; npoint--, points++, tri++) - { - tri->p1 = points[0]; - tri->p2 = points[1]; - tri->p3 = points[2]; - } - (*ps->Triangles) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); - xfree (tris); -} - -void -miTriFan (CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, - int npoint, - xPointFixed *points) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - xTriangle *tris, *tri; - xPointFixed *first; - int ntri; - - if (npoint < 3) - return; - ntri = npoint - 2; - tris = xalloc (ntri * sizeof (xTriangle)); - if (!tris) - return; - first = points++; - for (tri = tris; npoint >= 3; npoint--, points++, tri++) - { - tri->p1 = *first; - tri->p2 = points[0]; - tri->p3 = points[1]; - } - (*ps->Triangles) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); - xfree (tris); -} +/* + * + * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. + * + * 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 <dix-config.h> +#endif + +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "mi.h" +#include "picturestr.h" +#include "mipict.h" + +void +miPointFixedBounds (int npoint, xPointFixed *points, BoxPtr bounds) +{ + bounds->x1 = xFixedToInt (points->x); + bounds->x2 = xFixedToInt (xFixedCeil (points->x)); + bounds->y1 = xFixedToInt (points->y); + bounds->y2 = xFixedToInt (xFixedCeil (points->y)); + points++; + npoint--; + while (npoint-- > 0) + { + INT16 x1 = xFixedToInt (points->x); + INT16 x2 = xFixedToInt (xFixedCeil (points->x)); + INT16 y1 = xFixedToInt (points->y); + INT16 y2 = xFixedToInt (xFixedCeil (points->y)); + + if (x1 < bounds->x1) + bounds->x1 = x1; + else if (x2 > bounds->x2) + bounds->x2 = x2; + if (y1 < bounds->y1) + bounds->y1 = y1; + else if (y2 > bounds->y2) + bounds->y2 = y2; + points++; + } +} + +void +miTriangleBounds (int ntri, xTriangle *tris, BoxPtr bounds) +{ + miPointFixedBounds (ntri * 3, (xPointFixed *) tris, bounds); +} + +void +miTriangles (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int ntri, + xTriangle *tris) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + + /* + * Check for solid alpha add + */ + if (op == PictOpAdd && miIsSolidAlpha (pSrc)) + { + (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); + } + else if (maskFormat) + { + BoxRec bounds; + PicturePtr pPicture; + INT16 xDst, yDst; + INT16 xRel, yRel; + + xDst = tris[0].p1.x >> 16; + yDst = tris[0].p1.y >> 16; + + miTriangleBounds (ntri, tris, &bounds); + if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) + return; + pPicture = miCreateAlphaPicture (pScreen, pDst, maskFormat, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!pPicture) + return; + (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); + + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture (op, pSrc, pPicture, pDst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); + FreePicture (pPicture, 0); + } + else + { + if (pDst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + + for (; ntri; ntri--, tris++) + miTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); + } +} + +void +miTriStrip (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int npoint, + xPointFixed *points) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + xTriangle *tris, *tri; + int ntri; + + if (npoint < 3) + return; + ntri = npoint - 2; + tris = malloc(ntri * sizeof (xTriangle)); + if (!tris) + return; + for (tri = tris; npoint >= 3; npoint--, points++, tri++) + { + tri->p1 = points[0]; + tri->p2 = points[1]; + tri->p3 = points[2]; + } + (*ps->Triangles) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); + free(tris); +} + +void +miTriFan (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int npoint, + xPointFixed *points) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + xTriangle *tris, *tri; + xPointFixed *first; + int ntri; + + if (npoint < 3) + return; + ntri = npoint - 2; + tris = malloc(ntri * sizeof (xTriangle)); + if (!tris) + return; + first = points++; + for (tri = tris; npoint >= 3; npoint--, points++, tri++) + { + tri->p1 = *first; + tri->p2 = points[0]; + tri->p3 = points[1]; + } + (*ps->Triangles) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); + free(tris); +} diff --git a/xorg-server/render/picture.c b/xorg-server/render/picture.c index 6005683c0..12d1cee93 100644 --- a/xorg-server/render/picture.c +++ b/xorg-server/render/picture.c @@ -89,8 +89,8 @@ PictureCloseScreen (int index, ScreenPtr pScreen) (*ps->CloseIndexed) (pScreen, &ps->formats[n]); GlyphUninit (pScreen); SetPictureScreen(pScreen, 0); - xfree (ps->formats); - xfree (ps); + free(ps->formats); + free(ps); return ret; } @@ -337,7 +337,7 @@ PictureCreateDefaultFormats (ScreenPtr pScreen, int *nformatp) } - pFormats = xcalloc (nformats, sizeof (PictFormatRec)); + pFormats = calloc(nformats, sizeof (PictFormatRec)); if (!pFormats) return 0; for (f = 0; f < nformats; f++) @@ -638,7 +638,7 @@ PictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats) { if (!AddResource (formats[n].id, PictFormatType, (pointer) (formats+n))) { - xfree (formats); + free(formats); return FALSE; } if (formats[n].type == PictTypeIndexed) @@ -669,10 +669,10 @@ PictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats) } formats[n].format = PICT_FORMAT(0,type,a,r,g,b); } - ps = (PictureScreenPtr) xalloc (sizeof (PictureScreenRec)); + ps = (PictureScreenPtr) malloc(sizeof (PictureScreenRec)); if (!ps) { - xfree (formats); + free(formats); return FALSE; } SetPictureScreen(pScreen, ps); @@ -699,8 +699,8 @@ PictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats) { PictureResetFilters (pScreen); SetPictureScreen(pScreen, 0); - xfree (formats); - xfree (ps); + free(formats); + free(ps); return FALSE; } @@ -753,7 +753,7 @@ CreatePicture (Picture pid, PicturePtr pPicture; PictureScreenPtr ps = GetPictureScreen(pDrawable->pScreen); - pPicture = (PicturePtr)xalloc(sizeof(PictureRec)); + pPicture = (PicturePtr)malloc(sizeof(PictureRec)); if (!pPicture) { *error = BadAlloc; @@ -874,7 +874,7 @@ static void initGradient(SourcePictPtr pGradient, int stopCount, dpos = stopPoints[i]; } - pGradient->gradient.stops = xalloc(stopCount*sizeof(PictGradientStop)); + pGradient->gradient.stops = malloc(stopCount*sizeof(PictGradientStop)); if (!pGradient->gradient.stops) { *error = BadAlloc; return; @@ -896,7 +896,7 @@ static void initGradient(SourcePictPtr pGradient, int stopCount, static PicturePtr createSourcePicture(void) { PicturePtr pPicture; - pPicture = (PicturePtr) xalloc(sizeof(PictureRec)); + pPicture = (PicturePtr) malloc(sizeof(PictureRec)); pPicture->pDrawable = 0; pPicture->pFormat = 0; pPicture->pNext = 0; @@ -918,10 +918,10 @@ CreateSolidPicture (Picture pid, xRenderColor *color, int *error) } pPicture->id = pid; - pPicture->pSourcePict = (SourcePictPtr) xalloc(sizeof(PictSolidFill)); + pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictSolidFill)); if (!pPicture->pSourcePict) { *error = BadAlloc; - xfree(pPicture); + free(pPicture); return 0; } pPicture->pSourcePict->type = SourcePictTypeSolidFill; @@ -947,10 +947,10 @@ CreateLinearGradientPicture (Picture pid, xPointFixed *p1, xPointFixed *p2, } pPicture->id = pid; - pPicture->pSourcePict = (SourcePictPtr) xalloc(sizeof(PictLinearGradient)); + pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictLinearGradient)); if (!pPicture->pSourcePict) { *error = BadAlloc; - xfree(pPicture); + free(pPicture); return 0; } @@ -960,7 +960,7 @@ CreateLinearGradientPicture (Picture pid, xPointFixed *p1, xPointFixed *p2, initGradient(pPicture->pSourcePict, nStops, stops, colors, error); if (*error) { - xfree(pPicture); + free(pPicture); return 0; } return pPicture; @@ -988,10 +988,10 @@ CreateRadialGradientPicture (Picture pid, xPointFixed *inner, xPointFixed *outer } pPicture->id = pid; - pPicture->pSourcePict = (SourcePictPtr) xalloc(sizeof(PictRadialGradient)); + pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictRadialGradient)); if (!pPicture->pSourcePict) { *error = BadAlloc; - xfree(pPicture); + free(pPicture); return 0; } radial = &pPicture->pSourcePict->radial; @@ -1012,7 +1012,7 @@ CreateRadialGradientPicture (Picture pid, xPointFixed *inner, xPointFixed *outer initGradient(pPicture->pSourcePict, nStops, stops, colors, error); if (*error) { - xfree(pPicture); + free(pPicture); return 0; } return pPicture; @@ -1036,10 +1036,10 @@ CreateConicalGradientPicture (Picture pid, xPointFixed *center, xFixed angle, } pPicture->id = pid; - pPicture->pSourcePict = (SourcePictPtr) xalloc(sizeof(PictConicalGradient)); + pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictConicalGradient)); if (!pPicture->pSourcePict) { *error = BadAlloc; - xfree(pPicture); + free(pPicture); return 0; } @@ -1049,7 +1049,7 @@ CreateConicalGradientPicture (Picture pid, xPointFixed *center, xFixed angle, initGradient(pPicture->pSourcePict, nStops, stops, colors, error); if (*error) { - xfree(pPicture); + free(pPicture); return 0; } return pPicture; @@ -1385,7 +1385,7 @@ SetPictureTransform (PicturePtr pPicture, { if (!pPicture->transform) { - pPicture->transform = (PictTransform *) xalloc (sizeof (PictTransform)); + pPicture->transform = (PictTransform *) malloc(sizeof (PictTransform)); if (!pPicture->transform) return BadAlloc; } @@ -1395,7 +1395,7 @@ SetPictureTransform (PicturePtr pPicture, { if (pPicture->transform) { - xfree (pPicture->transform); + free(pPicture->transform); pPicture->transform = 0; } } @@ -1527,14 +1527,14 @@ FreePicture (pointer value, if (--pPicture->refcnt == 0) { if (pPicture->transform) - xfree (pPicture->transform); + free(pPicture->transform); if (pPicture->pSourcePict) { if (pPicture->pSourcePict->type != SourcePictTypeSolidFill) - xfree(pPicture->pSourcePict->linear.stops); + free(pPicture->pSourcePict->linear.stops); - xfree(pPicture->pSourcePict); + free(pPicture->pSourcePict); } if (pPicture->pDrawable) @@ -1569,7 +1569,7 @@ FreePicture (pointer value, } } dixFreePrivates(pPicture->devPrivates); - xfree (pPicture); + free(pPicture); } return Success; } diff --git a/xorg-server/render/render.c b/xorg-server/render/render.c index 9ccbf3937..9bbff1b6d 100644 --- a/xorg-server/render/render.c +++ b/xorg-server/render/render.c @@ -290,7 +290,7 @@ ProcRenderQueryVersion (ClientPtr client) swapl(&rep.minorVersion, n); } WriteToClient(client, sizeof(xRenderQueryVersionReply), (char *)&rep); - return (client->noClientException); + return Success; } static VisualPtr @@ -375,7 +375,7 @@ ProcRenderQueryPictFormats (ClientPtr client) ndepth * sizeof (xPictDepth) + nvisual * sizeof (xPictVisual) + numSubpixel * sizeof (CARD32)); - reply = (xRenderQueryPictFormatsReply *) xcalloc (1, rlength); + reply = (xRenderQueryPictFormatsReply *) calloc(1, rlength); if (!reply) return BadAlloc; reply->type = X_Reply; @@ -512,8 +512,8 @@ ProcRenderQueryPictFormats (ClientPtr client) swapl (&reply->numSubpixel, n); } WriteToClient(client, rlength, (char *) reply); - xfree (reply); - return client->noClientException; + free(reply); + return Success; } static int @@ -542,7 +542,7 @@ ProcRenderQueryPictIndexValues (ClientPtr client) num = pFormat->index.nvalues; rlength = (sizeof (xRenderQueryPictIndexValuesReply) + num * sizeof(xIndexValue)); - reply = (xRenderQueryPictIndexValuesReply *) xalloc (rlength); + reply = (xRenderQueryPictIndexValuesReply *) malloc(rlength); if (!reply) return BadAlloc; @@ -571,8 +571,8 @@ ProcRenderQueryPictIndexValues (ClientPtr client) } WriteToClient(client, rlength, (char *) reply); - xfree(reply); - return (client->noClientException); + free(reply); + return Success; } static int @@ -647,7 +647,6 @@ ProcRenderSetPictureClipRectangles (ClientPtr client) REQUEST(xRenderSetPictureClipRectanglesReq); PicturePtr pPicture; int nr; - int result; REQUEST_AT_LEAST_SIZE(xRenderSetPictureClipRectanglesReq); VERIFY_PICTURE (pPicture, stuff->picture, client, DixSetAttrAccess); @@ -658,13 +657,9 @@ ProcRenderSetPictureClipRectangles (ClientPtr client) if (nr & 4) return BadLength; nr >>= 3; - result = SetPictureClipRects (pPicture, + return SetPictureClipRects (pPicture, stuff->xOrigin, stuff->yOrigin, nr, (xRectangle *) &stuff[1]); - if (client->noClientException != Success) - return(client->noClientException); - else - return(result); } static int @@ -677,7 +672,7 @@ ProcRenderFreePicture (ClientPtr client) VERIFY_PICTURE (pPicture, stuff->picture, client, DixDestroyAccess); FreeResource (stuff->picture, RT_NONE); - return(client->noClientException); + return Success; } static Bool @@ -772,7 +767,7 @@ ProcRenderTrapezoids (ClientPtr client) CompositeTrapezoids (stuff->op, pSrc, pDst, pFormat, stuff->xSrc, stuff->ySrc, ntraps, (xTrapezoid *) &stuff[1]); - return client->noClientException; + return Success; } static int @@ -812,7 +807,7 @@ ProcRenderTriangles (ClientPtr client) CompositeTriangles (stuff->op, pSrc, pDst, pFormat, stuff->xSrc, stuff->ySrc, ntris, (xTriangle *) &stuff[1]); - return client->noClientException; + return Success; } static int @@ -852,7 +847,7 @@ ProcRenderTriStrip (ClientPtr client) CompositeTriStrip (stuff->op, pSrc, pDst, pFormat, stuff->xSrc, stuff->ySrc, npoints, (xPointFixed *) &stuff[1]); - return client->noClientException; + return Success; } static int @@ -892,7 +887,7 @@ ProcRenderTriFan (ClientPtr client) CompositeTriFan (stuff->op, pSrc, pDst, pFormat, stuff->xSrc, stuff->ySrc, npoints, (xPointFixed *) &stuff[1]); - return client->noClientException; + return Success; } static int @@ -984,7 +979,7 @@ ProcRenderReferenceGlyphSet (ClientPtr client) glyphSet->refcnt++; if (!AddResource (stuff->gsid, GlyphSetType, (pointer)glyphSet)) return BadAlloc; - return client->noClientException; + return Success; } #define NLOCALDELTA 64 @@ -1006,7 +1001,7 @@ ProcRenderFreeGlyphSet (ClientPtr client) return (rc == BadValue) ? RenderErrBase + BadGlyphSet : rc; } FreeResource (stuff->glyphset, RT_NONE); - return client->noClientException; + return Success; } typedef struct _GlyphNew { @@ -1058,7 +1053,7 @@ ProcRenderAddGlyphs (ClientPtr client) } else { - glyphsBase = (GlyphNewPtr) Xcalloc (nglyphs * sizeof (GlyphNewRec)); + glyphsBase = (GlyphNewPtr)calloc(nglyphs, sizeof (GlyphNewRec)); if (!glyphsBase) return BadAlloc; } @@ -1200,8 +1195,8 @@ ProcRenderAddGlyphs (ClientPtr client) AddGlyph (glyphSet, glyphs[i].glyph, glyphs[i].id); if (glyphsBase != glyphsLocal) - Xfree (glyphsBase); - return client->noClientException; + free(glyphsBase); + return Success; bail: if (pSrc) FreePicture ((pointer) pSrc, 0); @@ -1209,9 +1204,9 @@ bail: FreeScratchPixmapHeader (pSrcPix); for (i = 0; i < nglyphs; i++) if (glyphs[i].glyph && ! glyphs[i].found) - xfree (glyphs[i].glyph); + free(glyphs[i].glyph); if (glyphsBase != glyphsLocal) - Xfree (glyphsBase); + free(glyphsBase); return err; } @@ -1249,7 +1244,7 @@ ProcRenderFreeGlyphs (ClientPtr client) return RenderErrBase + BadGlyph; } } - return client->noClientException; + return Success; } static int @@ -1335,7 +1330,7 @@ ProcRenderCompositeGlyphs (ClientPtr client) glyphsBase = glyphsLocal; else { - glyphsBase = (GlyphPtr *) xalloc (nglyph * sizeof (GlyphPtr)); + glyphsBase = (GlyphPtr *) malloc(nglyph * sizeof (GlyphPtr)); if (!glyphsBase) return BadAlloc; } @@ -1343,7 +1338,7 @@ ProcRenderCompositeGlyphs (ClientPtr client) listsBase = listsLocal; else { - listsBase = (GlyphListPtr) xalloc (nlist * sizeof (GlyphListRec)); + listsBase = (GlyphListPtr) malloc(nlist * sizeof (GlyphListRec)); if (!listsBase) return BadAlloc; } @@ -1366,9 +1361,9 @@ ProcRenderCompositeGlyphs (ClientPtr client) if (rc != Success) { if (glyphsBase != glyphsLocal) - xfree (glyphsBase); + free(glyphsBase); if (listsBase != listsLocal) - xfree (listsBase); + free(listsBase); return (rc == BadValue) ? RenderErrBase + BadGlyphSet : rc; } } @@ -1422,11 +1417,11 @@ ProcRenderCompositeGlyphs (ClientPtr client) glyphsBase); if (glyphsBase != glyphsLocal) - xfree (glyphsBase); + free(glyphsBase); if (listsBase != listsLocal) - xfree (listsBase); + free(listsBase); - return client->noClientException; + return Success; } static int @@ -1457,7 +1452,7 @@ ProcRenderFillRectangles (ClientPtr client) things, (xRectangle *) &stuff[1]); - return client->noClientException; + return Success; } static void @@ -1518,23 +1513,23 @@ ProcRenderCreateCursor (ClientPtr client) if ( stuff->x > width || stuff->y > height ) return (BadMatch); - argbbits = xalloc (width * height * sizeof (CARD32)); + argbbits = malloc(width * height * sizeof (CARD32)); if (!argbbits) return (BadAlloc); stride = BitmapBytePad(width); nbytes_mono = stride*height; - srcbits = xcalloc(1, nbytes_mono); + srcbits = calloc(1, nbytes_mono); if (!srcbits) { - xfree (argbbits); + free(argbbits); return (BadAlloc); } - mskbits = xcalloc(1, nbytes_mono); + mskbits = calloc(1, nbytes_mono); if (!mskbits) { - xfree(argbbits); - xfree(srcbits); + free(argbbits); + free(srcbits); return (BadAlloc); } @@ -1554,27 +1549,27 @@ ProcRenderCreateCursor (ClientPtr client) pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); if (!pFormat) { - xfree (argbbits); - xfree (srcbits); - xfree (mskbits); + free(argbbits); + free(srcbits); + free(mskbits); return (BadImplementation); } pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 32, CREATE_PIXMAP_USAGE_SCRATCH); if (!pPixmap) { - xfree (argbbits); - xfree (srcbits); - xfree (mskbits); + free(argbbits); + free(srcbits); + free(mskbits); return (BadAlloc); } pPicture = CreatePicture (0, &pPixmap->drawable, pFormat, 0, 0, client, &error); if (!pPicture) { - xfree (argbbits); - xfree (srcbits); - xfree (mskbits); + free(argbbits); + free(srcbits); + free(mskbits); return error; } (*pScreen->DestroyPixmap) (pPixmap); @@ -1658,7 +1653,7 @@ ProcRenderCreateCursor (ClientPtr client) } else { - xfree (argbbits); + free(argbbits); argbbits = 0; } @@ -1682,7 +1677,7 @@ ProcRenderCreateCursor (ClientPtr client) if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) return BadAlloc; - return client->noClientException; + return Success; } static int @@ -1690,15 +1685,10 @@ ProcRenderSetPictureTransform (ClientPtr client) { REQUEST(xRenderSetPictureTransformReq); PicturePtr pPicture; - int result; REQUEST_SIZE_MATCH(xRenderSetPictureTransformReq); VERIFY_PICTURE (pPicture, stuff->picture, client, DixSetAttrAccess); - result = SetPictureTransform (pPicture, (PictTransform *) &stuff->transform); - if (client->noClientException != Success) - return(client->noClientException); - else - return(result); + return SetPictureTransform (pPicture, (PictTransform *) &stuff->transform); } static int @@ -1735,7 +1725,7 @@ ProcRenderQueryFilters (ClientPtr client) } len = ((nnames + 1) >> 1) + bytes_to_int32(nbytesName); total_bytes = sizeof (xRenderQueryFiltersReply) + (len << 2); - reply = (xRenderQueryFiltersReply *) xalloc (total_bytes); + reply = (xRenderQueryFiltersReply *) malloc(total_bytes); if (!reply) return BadAlloc; aliases = (INT16 *) (reply + 1); @@ -1806,9 +1796,9 @@ ProcRenderQueryFilters (ClientPtr client) swapl(&reply->numFilters, n); } WriteToClient(client, total_bytes, (char *) reply); - xfree (reply); + free(reply); - return(client->noClientException); + return Success; } static int @@ -1847,7 +1837,7 @@ ProcRenderCreateAnimCursor (ClientPtr client) if (client->req_len & 1) return BadLength; ncursor = (client->req_len - (bytes_to_int32(sizeof(xRenderCreateAnimCursorReq)))) >> 1; - cursors = xalloc (ncursor * (sizeof (CursorPtr) + sizeof (CARD32))); + cursors = malloc(ncursor * (sizeof (CursorPtr) + sizeof (CARD32))); if (!cursors) return BadAlloc; deltas = (CARD32 *) (cursors + ncursor); @@ -1858,7 +1848,7 @@ ProcRenderCreateAnimCursor (ClientPtr client) RT_CURSOR, client, DixReadAccess); if (ret != Success) { - xfree (cursors); + free(cursors); return (ret == BadValue) ? BadCursor : ret; } deltas[i] = elt->delay; @@ -1866,12 +1856,12 @@ ProcRenderCreateAnimCursor (ClientPtr client) } ret = AnimCursorCreate (cursors, deltas, ncursor, &pCursor, client, stuff->cid); - xfree (cursors); + free(cursors); if (ret != Success) return ret; if (AddResource (stuff->cid, RT_CURSOR, (pointer)pCursor)) - return client->noClientException; + return Success; return BadAlloc; } @@ -1894,7 +1884,7 @@ ProcRenderAddTraps (ClientPtr client) AddTraps (pPicture, stuff->xOff, stuff->yOff, ntraps, (xTrap *) &stuff[1]); - return client->noClientException; + return Success; } static int ProcRenderCreateSolidFill(ClientPtr client) @@ -2669,7 +2659,7 @@ PanoramiXRenderCreatePicture (ClientPtr client) XRC_DRAWABLE, client, DixWriteAccess); if (result != Success) return (result == BadValue) ? BadDrawable : result; - if(!(newPict = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes)))) + if(!(newPict = (PanoramiXRes *) malloc(sizeof(PanoramiXRes)))) return BadAlloc; newPict->type = XRT_PICTURE; newPict->info[0].id = stuff->pid; @@ -2695,7 +2685,7 @@ PanoramiXRenderCreatePicture (ClientPtr client) if (result == Success) AddResource(newPict->info[0].id, XRT_PICTURE, newPict); else - xfree(newPict); + free(newPict); return (result); } @@ -2905,7 +2895,7 @@ PanoramiXRenderFillRectangles (ClientPtr client) VERIFY_XIN_PICTURE (dst, stuff->dst, client, DixWriteAccess); extra_len = (client->req_len << 2) - sizeof (xRenderFillRectanglesReq); if (extra_len && - (extra = (char *) xalloc (extra_len))) + (extra = (char *) malloc(extra_len))) { memcpy (extra, stuff + 1, extra_len); FOR_NSCREENS_FORWARD(j) { @@ -2931,7 +2921,7 @@ PanoramiXRenderFillRectangles (ClientPtr client) result = (*PanoramiXSaveRenderVector[X_RenderFillRectangles]) (client); if(result != Success) break; } - xfree(extra); + free(extra); } return result; @@ -2954,7 +2944,7 @@ PanoramiXRenderTrapezoids(ClientPtr client) extra_len = (client->req_len << 2) - sizeof (xRenderTrapezoidsReq); if (extra_len && - (extra = (char *) xalloc (extra_len))) { + (extra = (char *) malloc(extra_len))) { memcpy (extra, stuff + 1, extra_len); FOR_NSCREENS_FORWARD(j) { @@ -2991,7 +2981,7 @@ PanoramiXRenderTrapezoids(ClientPtr client) if(result != Success) break; } - xfree(extra); + free(extra); } return result; @@ -3014,7 +3004,7 @@ PanoramiXRenderTriangles(ClientPtr client) extra_len = (client->req_len << 2) - sizeof (xRenderTrianglesReq); if (extra_len && - (extra = (char *) xalloc (extra_len))) { + (extra = (char *) malloc(extra_len))) { memcpy (extra, stuff + 1, extra_len); FOR_NSCREENS_FORWARD(j) { @@ -3047,7 +3037,7 @@ PanoramiXRenderTriangles(ClientPtr client) if(result != Success) break; } - xfree(extra); + free(extra); } return result; @@ -3070,7 +3060,7 @@ PanoramiXRenderTriStrip(ClientPtr client) extra_len = (client->req_len << 2) - sizeof (xRenderTriStripReq); if (extra_len && - (extra = (char *) xalloc (extra_len))) { + (extra = (char *) malloc(extra_len))) { memcpy (extra, stuff + 1, extra_len); FOR_NSCREENS_FORWARD(j) { @@ -3099,7 +3089,7 @@ PanoramiXRenderTriStrip(ClientPtr client) if(result != Success) break; } - xfree(extra); + free(extra); } return result; @@ -3122,7 +3112,7 @@ PanoramiXRenderTriFan(ClientPtr client) extra_len = (client->req_len << 2) - sizeof (xRenderTriFanReq); if (extra_len && - (extra = (char *) xalloc (extra_len))) { + (extra = (char *) malloc(extra_len))) { memcpy (extra, stuff + 1, extra_len); FOR_NSCREENS_FORWARD(j) { @@ -3151,7 +3141,7 @@ PanoramiXRenderTriFan(ClientPtr client) if(result != Success) break; } - xfree(extra); + free(extra); } return result; @@ -3171,7 +3161,7 @@ PanoramiXRenderAddTraps (ClientPtr client) VERIFY_XIN_PICTURE (picture, stuff->picture, client, DixWriteAccess); extra_len = (client->req_len << 2) - sizeof (xRenderAddTrapsReq); if (extra_len && - (extra = (char *) xalloc (extra_len))) + (extra = (char *) malloc(extra_len))) { memcpy (extra, stuff + 1, extra_len); x_off = stuff->xOff; @@ -3188,7 +3178,7 @@ PanoramiXRenderAddTraps (ClientPtr client) result = (*PanoramiXSaveRenderVector[X_RenderAddTraps]) (client); if(result != Success) break; } - xfree(extra); + free(extra); } return result; @@ -3203,7 +3193,7 @@ PanoramiXRenderCreateSolidFill (ClientPtr client) REQUEST_AT_LEAST_SIZE(xRenderCreateSolidFillReq); - if(!(newPict = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes)))) + if(!(newPict = (PanoramiXRes *) malloc(sizeof(PanoramiXRes)))) return BadAlloc; newPict->type = XRT_PICTURE; @@ -3222,7 +3212,7 @@ PanoramiXRenderCreateSolidFill (ClientPtr client) if (result == Success) AddResource(newPict->info[0].id, XRT_PICTURE, newPict); else - xfree(newPict); + free(newPict); return result; } @@ -3236,7 +3226,7 @@ PanoramiXRenderCreateLinearGradient (ClientPtr client) REQUEST_AT_LEAST_SIZE(xRenderCreateLinearGradientReq); - if(!(newPict = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes)))) + if(!(newPict = (PanoramiXRes *) malloc(sizeof(PanoramiXRes)))) return BadAlloc; newPict->type = XRT_PICTURE; @@ -3255,7 +3245,7 @@ PanoramiXRenderCreateLinearGradient (ClientPtr client) if (result == Success) AddResource(newPict->info[0].id, XRT_PICTURE, newPict); else - xfree(newPict); + free(newPict); return result; } @@ -3269,7 +3259,7 @@ PanoramiXRenderCreateRadialGradient (ClientPtr client) REQUEST_AT_LEAST_SIZE(xRenderCreateRadialGradientReq); - if(!(newPict = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes)))) + if(!(newPict = (PanoramiXRes *) malloc(sizeof(PanoramiXRes)))) return BadAlloc; newPict->type = XRT_PICTURE; @@ -3288,7 +3278,7 @@ PanoramiXRenderCreateRadialGradient (ClientPtr client) if (result == Success) AddResource(newPict->info[0].id, XRT_PICTURE, newPict); else - xfree(newPict); + free(newPict); return result; } @@ -3302,7 +3292,7 @@ PanoramiXRenderCreateConicalGradient (ClientPtr client) REQUEST_AT_LEAST_SIZE(xRenderCreateConicalGradientReq); - if(!(newPict = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes)))) + if(!(newPict = (PanoramiXRes *) malloc(sizeof(PanoramiXRes)))) return BadAlloc; newPict->type = XRT_PICTURE; @@ -3321,7 +3311,7 @@ PanoramiXRenderCreateConicalGradient (ClientPtr client) if (result == Success) AddResource(newPict->info[0].id, XRT_PICTURE, newPict); else - xfree(newPict); + free(newPict); return result; } diff --git a/xorg-server/test/xi2/protocol-common.c b/xorg-server/test/xi2/protocol-common.c index 0afa55a40..a06c5a913 100644 --- a/xorg-server/test/xi2/protocol-common.c +++ b/xorg-server/test/xi2/protocol-common.c @@ -1,168 +1,169 @@ -/** - * Copyright © 2009 Red Hat, Inc. - * - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <stdint.h> -#include "extinit.h" /* for XInputExtensionInit */ -#include <glib.h> - -#include "protocol-common.h" - -struct devices devices; -ScreenRec screen; -WindowRec root; -WindowRec window; - -void *userdata; - -extern int CorePointerProc(DeviceIntPtr pDev, int what); -extern int CoreKeyboardProc(DeviceIntPtr pDev, int what); - -static void fake_init_sprite(DeviceIntPtr dev) -{ - SpritePtr sprite; - sprite = dev->spriteInfo->sprite; - - sprite->spriteTraceSize = 10; - sprite->spriteTrace = xcalloc(sprite->spriteTraceSize, sizeof(WindowPtr)); - sprite->spriteTraceGood = 1; - sprite->spriteTrace[0] = &root; - sprite->hot.x = SPRITE_X; - sprite->hot.y = SPRITE_Y; - sprite->hotPhys.x = sprite->hot.x; - sprite->hotPhys.y = sprite->hot.y; - sprite->win = &window; - sprite->hotPhys.pScreen = &screen; - sprite->physLimits.x1 = 0; - sprite->physLimits.y1 = 0; - sprite->physLimits.x2 = screen.width; - sprite->physLimits.y2 = screen.height; -} - -/** - * Create and init 2 master devices (VCP + VCK) and two slave devices, one - * default mouse, one default keyboard. - */ -struct devices init_devices(void) -{ - ClientRec client; - struct devices devices; - - client = init_client(0, NULL); - - AllocDevicePair(&client, "Virtual core", &devices.vcp, &devices.vck, - CorePointerProc, CoreKeyboardProc, TRUE); - inputInfo.pointer = devices.vcp; - inputInfo.keyboard = devices.vck; - ActivateDevice(devices.vcp, FALSE); - ActivateDevice(devices.vck, FALSE); - EnableDevice(devices.vcp, FALSE); - EnableDevice(devices.vck, FALSE); - - AllocDevicePair(&client, "", &devices.mouse, &devices.kbd, - CorePointerProc, CoreKeyboardProc, FALSE); - ActivateDevice(devices.mouse, FALSE); - ActivateDevice(devices.kbd, FALSE); - EnableDevice(devices.mouse, FALSE); - EnableDevice(devices.kbd, FALSE); - - devices.num_devices = 4; - devices.num_master_devices = 2; - - fake_init_sprite(devices.mouse); - fake_init_sprite(devices.vcp); - - return devices; -} - - -/* Create minimal client, with the given buffer and len as request buffer */ -ClientRec init_client(int len, void *data) -{ - ClientRec client = { 0 }; - - /* we store the privates now and reassign it after the memset. this way - * we can share them across multiple test runs and don't have to worry - * about freeing them after each test run. */ - PrivateRec *privates = client.devPrivates; - - client.index = CLIENT_INDEX; - client.clientAsMask = CLIENT_MASK; - client.sequence = CLIENT_SEQUENCE; - client.req_len = len; - - client.requestBuffer = data; - client.devPrivates = privates; - return client; -} - -void init_window(WindowPtr window, WindowPtr parent, int id) -{ - memset(window, 0, sizeof(window)); - - window->drawable.id = id; - if (parent) - { - window->drawable.x = 30; - window->drawable.y = 50; - window->drawable.width = 100; - window->drawable.height = 200; - } - window->parent = parent; - window->optional = xcalloc(1, sizeof(WindowOptRec)); - g_assert(window->optional); -} - -/* Needed for the screen setup, otherwise we crash during sprite initialization */ -static Bool device_cursor_init(DeviceIntPtr dev, ScreenPtr screen) { return TRUE; } -static Bool set_cursor_pos(DeviceIntPtr dev, ScreenPtr screen, int x, int y, Bool event) { return TRUE; } -void init_simple(void) -{ - screenInfo.numScreens = 1; - screenInfo.screens[0] = &screen; - - screen.myNum = 0; - screen.id = 100; - screen.width = 640; - screen.height = 480; - screen.DeviceCursorInitialize = device_cursor_init; - screen.SetCursorPosition = set_cursor_pos; - - dixResetPrivates(); - XInputExtensionInit(); - init_window(&root, NULL, ROOT_WINDOW_ID); - init_window(&window, &root, CLIENT_WINDOW_ID); - - devices = init_devices(); -} - -void __wrap_WriteToClient(ClientPtr client, int len, void *data) -{ - g_assert(reply_handler != NULL); - - (*reply_handler)(client, len, data, userdata); -} - +/** + * Copyright © 2009 Red Hat, Inc. + * + * 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdint.h> +#include "extinit.h" /* for XInputExtensionInit */ +#include <glib.h> + +#include "protocol-common.h" + +struct devices devices; +ScreenRec screen; +WindowRec root; +WindowRec window; + +void *userdata; + +extern int CorePointerProc(DeviceIntPtr pDev, int what); +extern int CoreKeyboardProc(DeviceIntPtr pDev, int what); + +static void fake_init_sprite(DeviceIntPtr dev) +{ + SpritePtr sprite; + sprite = dev->spriteInfo->sprite; + + sprite->spriteTraceSize = 10; + sprite->spriteTrace = calloc(sprite->spriteTraceSize, sizeof(WindowPtr)); + sprite->spriteTraceGood = 1; + sprite->spriteTrace[0] = &root; + sprite->hot.x = SPRITE_X; + sprite->hot.y = SPRITE_Y; + sprite->hotPhys.x = sprite->hot.x; + sprite->hotPhys.y = sprite->hot.y; + sprite->win = &window; + sprite->hotPhys.pScreen = &screen; + sprite->physLimits.x1 = 0; + sprite->physLimits.y1 = 0; + sprite->physLimits.x2 = screen.width; + sprite->physLimits.y2 = screen.height; +} + +/** + * Create and init 2 master devices (VCP + VCK) and two slave devices, one + * default mouse, one default keyboard. + */ +struct devices init_devices(void) +{ + ClientRec client; + struct devices devices; + + client = init_client(0, NULL); + + AllocDevicePair(&client, "Virtual core", &devices.vcp, &devices.vck, + CorePointerProc, CoreKeyboardProc, TRUE); + inputInfo.pointer = devices.vcp; + inputInfo.keyboard = devices.vck; + ActivateDevice(devices.vcp, FALSE); + ActivateDevice(devices.vck, FALSE); + EnableDevice(devices.vcp, FALSE); + EnableDevice(devices.vck, FALSE); + + AllocDevicePair(&client, "", &devices.mouse, &devices.kbd, + CorePointerProc, CoreKeyboardProc, FALSE); + ActivateDevice(devices.mouse, FALSE); + ActivateDevice(devices.kbd, FALSE); + EnableDevice(devices.mouse, FALSE); + EnableDevice(devices.kbd, FALSE); + + devices.num_devices = 4; + devices.num_master_devices = 2; + + fake_init_sprite(devices.mouse); + fake_init_sprite(devices.vcp); + + return devices; +} + + +/* Create minimal client, with the given buffer and len as request buffer */ +ClientRec init_client(int len, void *data) +{ + ClientRec client = { 0 }; + + /* we store the privates now and reassign it after the memset. this way + * we can share them across multiple test runs and don't have to worry + * about freeing them after each test run. */ + PrivateRec *privates = client.devPrivates; + + client.index = CLIENT_INDEX; + client.clientAsMask = CLIENT_MASK; + client.sequence = CLIENT_SEQUENCE; + client.req_len = len; + + client.requestBuffer = data; + client.devPrivates = privates; + return client; +} + +void init_window(WindowPtr window, WindowPtr parent, int id) +{ + memset(window, 0, sizeof(window)); + + window->drawable.id = id; + if (parent) + { + window->drawable.x = 30; + window->drawable.y = 50; + window->drawable.width = 100; + window->drawable.height = 200; + } + window->parent = parent; + window->optional = calloc(1, sizeof(WindowOptRec)); + g_assert(window->optional); +} + +/* Needed for the screen setup, otherwise we crash during sprite initialization */ +static Bool device_cursor_init(DeviceIntPtr dev, ScreenPtr screen) { return TRUE; } +static Bool set_cursor_pos(DeviceIntPtr dev, ScreenPtr screen, int x, int y, Bool event) { return TRUE; } +void init_simple(void) +{ + screenInfo.numScreens = 1; + screenInfo.screens[0] = &screen; + + screen.myNum = 0; + screen.id = 100; + screen.width = 640; + screen.height = 480; + screen.DeviceCursorInitialize = device_cursor_init; + screen.SetCursorPosition = set_cursor_pos; + + dixResetPrivates(); + InitAtoms(); + XInputExtensionInit(); + init_window(&root, NULL, ROOT_WINDOW_ID); + init_window(&window, &root, CLIENT_WINDOW_ID); + + devices = init_devices(); +} + +void __wrap_WriteToClient(ClientPtr client, int len, void *data) +{ + g_assert(reply_handler != NULL); + + (*reply_handler)(client, len, data, userdata); +} + diff --git a/xorg-server/test/xi2/protocol-eventconvert.c b/xorg-server/test/xi2/protocol-eventconvert.c index f20a10a57..8184886c0 100644 --- a/xorg-server/test/xi2/protocol-eventconvert.c +++ b/xorg-server/test/xi2/protocol-eventconvert.c @@ -1,907 +1,907 @@ -/** - * Copyright © 2009 Red Hat, Inc. - * - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <stdint.h> -#include <glib.h> - -#include "inputstr.h" -#include "eventstr.h" -#include "eventconvert.h" -#include "exevents.h" -#include <X11/extensions/XI2proto.h> - - -static void test_values_XIRawEvent(RawDeviceEvent *in, xXIRawEvent *out, - BOOL swap) -{ - int i; - unsigned char *ptr; - FP3232 *value, *raw_value; - int nvals = 0; - int bits_set; - int len; - - if (swap) - { - char n; - - swaps(&out->sequenceNumber, n); - swapl(&out->length, n); - swaps(&out->evtype, n); - swaps(&out->deviceid, n); - swapl(&out->time, n); - swapl(&out->detail, n); - swaps(&out->valuators_len, n); - } - - - g_assert(out->type == GenericEvent); - g_assert(out->extension == 0); /* IReqCode defaults to 0 */ - g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); - g_assert(out->time == in->time); - g_assert(out->detail == in->detail.button); - g_assert(out->deviceid == in->deviceid); - g_assert(out->valuators_len >= bytes_to_int32(bits_to_bytes(sizeof(in->valuators.mask)))); - g_assert(out->flags == 0); /* FIXME: we don't set the flags yet */ - - ptr = (unsigned char*)&out[1]; - bits_set = 0; - - for (i = 0; out->valuators_len && i < sizeof(in->valuators.mask) * 8; i++) - { - g_assert (XIMaskIsSet(in->valuators.mask, i) == XIMaskIsSet(ptr, i)); - if (XIMaskIsSet(in->valuators.mask, i)) - bits_set++; - } - - /* length is len of valuator mask (in 4-byte units) + the number of bits - * set. Each bit set represents 2 8-byte values, hence the - * 'bits_set * 4' */ - len = out->valuators_len + bits_set * 4; - g_assert(out->length == len); - - nvals = 0; - - for (i = 0; out->valuators_len && i < MAX_VALUATORS; i++) - { - g_assert (XIMaskIsSet(in->valuators.mask, i) == XIMaskIsSet(ptr, i)); - if (XIMaskIsSet(in->valuators.mask, i)) - { - FP3232 vi, vo; - value = (FP3232*)(((unsigned char*)&out[1]) + out->valuators_len * 4); - value += nvals; - - vi.integral = in->valuators.data[i]; - vi.frac = in->valuators.data_frac[i]; - - vo.integral = value->integral; - vo.frac = value->frac; - if (swap) - { - char n; - swapl(&vo.integral, n); - swapl(&vo.frac, n); - } - - g_assert(vi.integral == vo.integral); - g_assert(vi.frac == vo.frac); - - raw_value = value + bits_set; - - vi.integral = in->valuators.data_raw[i]; - vi.frac = in->valuators.data_raw_frac[i]; - - vo.integral = raw_value->integral; - vo.frac = raw_value->frac; - if (swap) - { - char n; - swapl(&vo.integral, n); - swapl(&vo.frac, n); - } - - g_assert(vi.integral == vo.integral); - g_assert(vi.frac == vo.frac); - - nvals++; - } - } -} - -static void test_XIRawEvent(RawDeviceEvent *in) -{ - xXIRawEvent *out, *swapped; - int rc; - - rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); - g_assert(rc == Success); - - test_values_XIRawEvent(in, out, FALSE); - - swapped = xcalloc(1, sizeof(xEvent) + out->length * 4); - XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); - test_values_XIRawEvent(in, swapped, TRUE); - - xfree(out); - xfree(swapped); -} - -static void test_convert_XIFocusEvent(void) -{ - xEvent *out; - DeviceEvent in; - int rc; - - in.header = ET_Internal; - in.type = ET_Enter; - rc = EventToXI2((InternalEvent*)&in, &out); - g_assert(rc == Success); - g_assert(out == NULL); - - in.header = ET_Internal; - in.type = ET_FocusIn; - rc = EventToXI2((InternalEvent*)&in, &out); - g_assert(rc == Success); - g_assert(out == NULL); - - in.header = ET_Internal; - in.type = ET_FocusOut; - rc = EventToXI2((InternalEvent*)&in, &out); - g_assert(rc == BadImplementation); - - in.header = ET_Internal; - in.type = ET_Leave; - rc = EventToXI2((InternalEvent*)&in, &out); - g_assert(rc == BadImplementation); -} - - -static void test_convert_XIRawEvent(void) -{ - RawDeviceEvent in; - int i; - - memset(&in, 0, sizeof(in)); - - g_test_message("Testing all event types"); - in.header = ET_Internal; - in.type = ET_RawMotion; - test_XIRawEvent(&in); - - in.header = ET_Internal; - in.type = ET_RawKeyPress; - test_XIRawEvent(&in); - - in.header = ET_Internal; - in.type = ET_RawKeyRelease; - test_XIRawEvent(&in); - - in.header = ET_Internal; - in.type = ET_RawButtonPress; - test_XIRawEvent(&in); - - in.header = ET_Internal; - in.type = ET_RawButtonRelease; - test_XIRawEvent(&in); - - g_test_message("Testing details and other fields"); - in.detail.button = 1L; - test_XIRawEvent(&in); - in.detail.button = 1L << 8; - test_XIRawEvent(&in); - in.detail.button = 1L << 16; - test_XIRawEvent(&in); - in.detail.button = 1L << 24; - test_XIRawEvent(&in); - in.detail.button = ~0L; - test_XIRawEvent(&in); - - in.detail.button = 0; - - in.time = 1L; - test_XIRawEvent(&in); - in.time = 1L << 8; - test_XIRawEvent(&in); - in.time = 1L << 16; - test_XIRawEvent(&in); - in.time = 1L << 24; - test_XIRawEvent(&in); - in.time = ~0L; - test_XIRawEvent(&in); - - in.deviceid = 1; - test_XIRawEvent(&in); - in.deviceid = 1 << 8; - test_XIRawEvent(&in); - in.deviceid = ~0 & 0xFF; - test_XIRawEvent(&in); - - g_test_message("Testing valuator masks"); - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - test_XIRawEvent(&in); - XIClearMask(in.valuators.mask, i); - } - - for (i = 0; i < MAX_VALUATORS; i++) - { - XISetMask(in.valuators.mask, i); - - in.valuators.data[i] = i; - in.valuators.data_raw[i] = i + 10; - in.valuators.data_frac[i] = i + 20; - in.valuators.data_raw_frac[i] = i + 30; - test_XIRawEvent(&in); - XIClearMask(in.valuators.mask, i); - } - - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - test_XIRawEvent(&in); - } -} - -static void test_values_XIDeviceEvent(DeviceEvent *in, xXIDeviceEvent *out, - BOOL swap) -{ - int buttons, valuators; - int i; - unsigned char *ptr; - FP3232 *values; - - if (swap) { - char n; - - swaps(&out->sequenceNumber, n); - swapl(&out->length, n); - swaps(&out->evtype, n); - swaps(&out->deviceid, n); - swaps(&out->sourceid, n); - swapl(&out->time, n); - swapl(&out->detail, n); - swapl(&out->root, n); - swapl(&out->event, n); - swapl(&out->child, n); - swapl(&out->root_x, n); - swapl(&out->root_y, n); - swapl(&out->event_x, n); - swapl(&out->event_y, n); - swaps(&out->buttons_len, n); - swaps(&out->valuators_len, n); - swapl(&out->mods.base_mods, n); - swapl(&out->mods.latched_mods, n); - swapl(&out->mods.locked_mods, n); - swapl(&out->mods.effective_mods, n); - } - - g_assert(out->extension == 0); /* IReqCode defaults to 0 */ - g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); - g_assert(out->time == in->time); - g_assert(out->detail == in->detail.button); - g_assert(out->length >= 12); - - g_assert(out->deviceid == in->deviceid); - g_assert(out->sourceid == in->sourceid); - - g_assert(out->flags == 0); /* FIXME: we don't set the flags yet */ - - g_assert(out->root == in->root); - g_assert(out->event == None); /* set in FixUpEventFromWindow */ - g_assert(out->child == None); /* set in FixUpEventFromWindow */ - - g_assert(out->mods.base_mods == in->mods.base); - g_assert(out->mods.latched_mods == in->mods.latched); - g_assert(out->mods.locked_mods == in->mods.locked); - g_assert(out->mods.effective_mods == in->mods.effective); - - g_assert(out->group.base_group == in->group.base); - g_assert(out->group.latched_group == in->group.latched); - g_assert(out->group.locked_group == in->group.locked); - g_assert(out->group.effective_group == in->group.effective); - - g_assert(out->event_x == 0); /* set in FixUpEventFromWindow */ - g_assert(out->event_y == 0); /* set in FixUpEventFromWindow */ - - g_assert(out->root_x == FP1616(in->root_x, in->root_x_frac)); - g_assert(out->root_y == FP1616(in->root_y, in->root_y_frac)); - - buttons = 0; - for (i = 0; i < bits_to_bytes(sizeof(in->buttons)); i++) - { - if (XIMaskIsSet(in->buttons, i)) - { - g_assert(out->buttons_len >= bytes_to_int32(bits_to_bytes(i))); - buttons++; - } - } - - ptr = (unsigned char*)&out[1]; - for (i = 0; i < sizeof(in->buttons) * 8; i++) - g_assert(XIMaskIsSet(in->buttons, i) == XIMaskIsSet(ptr, i)); - - - valuators = 0; - for (i = 0; i < sizeof(in->valuators.mask) * 8; i++) - if (XIMaskIsSet(in->valuators.mask, i)) - valuators++; - - g_assert(out->valuators_len >= bytes_to_int32(bits_to_bytes(valuators))); - - ptr += out->buttons_len * 4; - values = (FP3232*)(ptr + out->valuators_len * 4); - for (i = 0; i < sizeof(in->valuators.mask) * 8 || - i < (out->valuators_len * 4) * 8; i++) - { - if (i > sizeof(in->valuators.mask) * 8) - g_assert(!XIMaskIsSet(ptr, i)); - else if (i > out->valuators_len * 4 * 8) - g_assert(!XIMaskIsSet(in->valuators.mask, i)); - else { - g_assert(XIMaskIsSet(in->valuators.mask, i) == - XIMaskIsSet(ptr, i)); - - if (XIMaskIsSet(ptr, i)) - { - FP3232 vi, vo; - - vi.integral = in->valuators.data[i]; - vi.frac = in->valuators.data_frac[i]; - - vo = *values; - - if (swap) - { - char n; - swapl(&vo.integral, n); - swapl(&vo.frac, n); - } - - - g_assert(vi.integral == vo.integral); - g_assert(vi.frac == vo.frac); - values++; - } - } - } -} - -static void test_XIDeviceEvent(DeviceEvent *in) -{ - xXIDeviceEvent *out, *swapped; - int rc; - - rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); - g_assert(rc == Success); - - test_values_XIDeviceEvent(in, out, FALSE); - - swapped = xcalloc(1, sizeof(xEvent) + out->length * 4); - XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); - test_values_XIDeviceEvent(in, swapped, TRUE); - - xfree(out); - xfree(swapped); -} - -static void test_convert_XIDeviceEvent(void) -{ - DeviceEvent in; - int i; - - memset(&in, 0, sizeof(in)); - - g_test_message("Testing simple field values"); - in.header = ET_Internal; - in.type = ET_Motion; - in.length = sizeof(DeviceEvent); - in.time = 0; - in.deviceid = 1; - in.sourceid = 2; - in.root = 3; - in.root_x = 4; - in.root_x_frac = 5; - in.root_y = 6; - in.root_y_frac = 7; - in.detail.button = 8; - in.mods.base = 9; - in.mods.latched = 10; - in.mods.locked = 11; - in.mods.effective = 11; - in.group.base = 12; - in.group.latched = 13; - in.group.locked = 14; - in.group.effective = 15; - - test_XIDeviceEvent(&in); - - g_test_message("Testing field ranges"); - /* 32 bit */ - in.detail.button = 1L; - test_XIDeviceEvent(&in); - in.detail.button = 1L << 8; - test_XIDeviceEvent(&in); - in.detail.button = 1L << 16; - test_XIDeviceEvent(&in); - in.detail.button = 1L << 24; - test_XIDeviceEvent(&in); - in.detail.button = ~0L; - test_XIDeviceEvent(&in); - - /* 32 bit */ - in.time = 1L; - test_XIDeviceEvent(&in); - in.time = 1L << 8; - test_XIDeviceEvent(&in); - in.time = 1L << 16; - test_XIDeviceEvent(&in); - in.time = 1L << 24; - test_XIDeviceEvent(&in); - in.time = ~0L; - test_XIDeviceEvent(&in); - - /* 16 bit */ - in.deviceid = 1; - test_XIDeviceEvent(&in); - in.deviceid = 1 << 8; - test_XIDeviceEvent(&in); - in.deviceid = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - /* 16 bit */ - in.sourceid = 1; - test_XIDeviceEvent(&in); - in.deviceid = 1 << 8; - test_XIDeviceEvent(&in); - in.deviceid = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - /* 32 bit */ - in.root = 1L; - test_XIDeviceEvent(&in); - in.root = 1L << 8; - test_XIDeviceEvent(&in); - in.root = 1L << 16; - test_XIDeviceEvent(&in); - in.root = 1L << 24; - test_XIDeviceEvent(&in); - in.root = ~0L; - test_XIDeviceEvent(&in); - - /* 16 bit */ - in.root_x = 1; - test_XIDeviceEvent(&in); - in.root_x = 1 << 8; - test_XIDeviceEvent(&in); - in.root_x = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.root_x_frac = 1; - test_XIDeviceEvent(&in); - in.root_x_frac = 1 << 8; - test_XIDeviceEvent(&in); - in.root_x_frac = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.root_y = 1; - test_XIDeviceEvent(&in); - in.root_y = 1 << 8; - test_XIDeviceEvent(&in); - in.root_y = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.root_y_frac = 1; - test_XIDeviceEvent(&in); - in.root_y_frac = 1 << 8; - test_XIDeviceEvent(&in); - in.root_y_frac = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - /* 32 bit */ - in.mods.base = 1L; - test_XIDeviceEvent(&in); - in.mods.base = 1L << 8; - test_XIDeviceEvent(&in); - in.mods.base = 1L << 16; - test_XIDeviceEvent(&in); - in.mods.base = 1L << 24; - test_XIDeviceEvent(&in); - in.mods.base = ~0L; - test_XIDeviceEvent(&in); - - in.mods.latched = 1L; - test_XIDeviceEvent(&in); - in.mods.latched = 1L << 8; - test_XIDeviceEvent(&in); - in.mods.latched = 1L << 16; - test_XIDeviceEvent(&in); - in.mods.latched = 1L << 24; - test_XIDeviceEvent(&in); - in.mods.latched = ~0L; - test_XIDeviceEvent(&in); - - in.mods.locked = 1L; - test_XIDeviceEvent(&in); - in.mods.locked = 1L << 8; - test_XIDeviceEvent(&in); - in.mods.locked = 1L << 16; - test_XIDeviceEvent(&in); - in.mods.locked = 1L << 24; - test_XIDeviceEvent(&in); - in.mods.locked = ~0L; - test_XIDeviceEvent(&in); - - in.mods.effective = 1L; - test_XIDeviceEvent(&in); - in.mods.effective = 1L << 8; - test_XIDeviceEvent(&in); - in.mods.effective = 1L << 16; - test_XIDeviceEvent(&in); - in.mods.effective = 1L << 24; - test_XIDeviceEvent(&in); - in.mods.effective = ~0L; - test_XIDeviceEvent(&in); - - /* 8 bit */ - in.group.base = 1; - test_XIDeviceEvent(&in); - in.group.base = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.group.latched = 1; - test_XIDeviceEvent(&in); - in.group.latched = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.group.locked = 1; - test_XIDeviceEvent(&in); - in.group.locked = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.mods.effective = 1; - test_XIDeviceEvent(&in); - in.mods.effective = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - g_test_message("Testing button masks"); - for (i = 0; i < sizeof(in.buttons) * 8; i++) - { - XISetMask(in.buttons, i); - test_XIDeviceEvent(&in); - XIClearMask(in.buttons, i); - } - - for (i = 0; i < sizeof(in.buttons) * 8; i++) - { - XISetMask(in.buttons, i); - test_XIDeviceEvent(&in); - } - - g_test_message("Testing valuator masks"); - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - test_XIDeviceEvent(&in); - XIClearMask(in.valuators.mask, i); - } - - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - - in.valuators.data[i] = i; - in.valuators.data_frac[i] = i + 20; - test_XIDeviceEvent(&in); - XIClearMask(in.valuators.mask, i); - } - - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - test_XIDeviceEvent(&in); - } -} - -static void test_values_XIDeviceChangedEvent(DeviceChangedEvent *in, - xXIDeviceChangedEvent *out, - BOOL swap) -{ - int i, j; - unsigned char *ptr; - - if (swap) - { - char n; - - swaps(&out->sequenceNumber, n); - swapl(&out->length, n); - swaps(&out->evtype, n); - swaps(&out->deviceid, n); - swaps(&out->sourceid, n); - swapl(&out->time, n); - swaps(&out->num_classes, n); - } - - g_assert(out->type == GenericEvent); - g_assert(out->extension == 0); /* IReqCode defaults to 0 */ - g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); - g_assert(out->time == in->time); - g_assert(out->deviceid == in->deviceid); - g_assert(out->sourceid == in->sourceid); - - ptr = (unsigned char*)&out[1]; - for (i = 0; i < out->num_classes; i++) - { - xXIAnyInfo* any = (xXIAnyInfo*)ptr; - - if (swap) - { - char n; - swaps(&any->length, n); - swaps(&any->type, n); - swaps(&any->sourceid, n); - } - - switch(any->type) - { - case XIButtonClass: - { - xXIButtonInfo *b = (xXIButtonInfo*)any; - Atom *names; - - if (swap) - { - char n; - swaps(&b->num_buttons, n); - } - - g_assert(b->length == - bytes_to_int32(sizeof(xXIButtonInfo)) + - bytes_to_int32(bits_to_bytes(b->num_buttons)) + - b->num_buttons); - g_assert(b->num_buttons == in->buttons.num_buttons); - - names = (Atom*)((char*)&b[1] + - pad_to_int32(bits_to_bytes(b->num_buttons))); - for (j = 0; j < b->num_buttons; j++) - { - if (swap) - { - char n; - swapl(&names[j], n); - } - g_assert(names[j] == in->buttons.names[j]); - } - } - break; - case XIKeyClass: - { - xXIKeyInfo *k = (xXIKeyInfo*)any; - uint32_t *kc; - - if (swap) - { - char n; - swaps(&k->num_keycodes, n); - } - - g_assert(k->length == - bytes_to_int32(sizeof(xXIKeyInfo)) + - k->num_keycodes); - g_assert(k->num_keycodes == in->keys.max_keycode - - in->keys.min_keycode + 1); - - kc = (uint32_t*)&k[1]; - for (j = 0; j < k->num_keycodes; j++) - { - if (swap) - { - char n; - swapl(&kc[j], n); - } - g_assert(kc[j] >= in->keys.min_keycode); - g_assert(kc[j] <= in->keys.max_keycode); - } - } - break; - case XIValuatorClass: - { - xXIValuatorInfo *v = (xXIValuatorInfo*)any; - g_assert(v->length == - bytes_to_int32(sizeof(xXIValuatorInfo))); - - } - break; - default: - g_error("Invalid class type.\n"); - break; - } - - ptr += any->length * 4; - } - -} - -static void test_XIDeviceChangedEvent(DeviceChangedEvent *in) -{ - xXIDeviceChangedEvent *out, *swapped; - int rc; - - rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); - g_assert(rc == Success); - - test_values_XIDeviceChangedEvent(in, out, FALSE); - - swapped = xcalloc(1, sizeof(xEvent) + out->length * 4); - XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); - test_values_XIDeviceChangedEvent(in, swapped, TRUE); - - xfree(out); - xfree(swapped); -} - -static void test_convert_XIDeviceChangedEvent(void) -{ - DeviceChangedEvent in; - int i; - - g_test_message("Testing simple field values"); - memset(&in, 0, sizeof(in)); - in.header = ET_Internal; - in.type = ET_DeviceChanged; - in.length = sizeof(DeviceChangedEvent); - in.time = 0; - in.deviceid = 1; - in.sourceid = 2; - in.masterid = 3; - in.num_valuators = 4; - in.flags = DEVCHANGE_SLAVE_SWITCH | DEVCHANGE_POINTER_EVENT | DEVCHANGE_KEYBOARD_EVENT; - - for (i = 0; i < MAX_BUTTONS; i++) - in.buttons.names[i] = i + 10; - - in.keys.min_keycode = 8; - in.keys.max_keycode = 255; - - test_XIDeviceChangedEvent(&in); - - in.time = 1L; - test_XIDeviceChangedEvent(&in); - in.time = 1L << 8; - test_XIDeviceChangedEvent(&in); - in.time = 1L << 16; - test_XIDeviceChangedEvent(&in); - in.time = 1L << 24; - test_XIDeviceChangedEvent(&in); - in.time = ~0L; - test_XIDeviceChangedEvent(&in); - - in.deviceid = 1L; - test_XIDeviceChangedEvent(&in); - in.deviceid = 1L << 8; - test_XIDeviceChangedEvent(&in); - in.deviceid = ~0 & 0xFFFF; - test_XIDeviceChangedEvent(&in); - - in.sourceid = 1L; - test_XIDeviceChangedEvent(&in); - in.sourceid = 1L << 8; - test_XIDeviceChangedEvent(&in); - in.sourceid = ~0 & 0xFFFF; - test_XIDeviceChangedEvent(&in); - - in.masterid = 1L; - test_XIDeviceChangedEvent(&in); - in.masterid = 1L << 8; - test_XIDeviceChangedEvent(&in); - in.masterid = ~0 & 0xFFFF; - test_XIDeviceChangedEvent(&in); - - in.buttons.num_buttons = 0; - test_XIDeviceChangedEvent(&in); - - in.buttons.num_buttons = 1; - test_XIDeviceChangedEvent(&in); - - in.buttons.num_buttons = MAX_BUTTONS; - test_XIDeviceChangedEvent(&in); - - in.keys.min_keycode = 0; - in.keys.max_keycode = 0; - test_XIDeviceChangedEvent(&in); - - in.keys.max_keycode = 1 << 8; - test_XIDeviceChangedEvent(&in); - - in.keys.max_keycode = 0xFFFC; /* highest range, above that the length - field gives up */ - test_XIDeviceChangedEvent(&in); - - in.keys.min_keycode = 1 << 8; - in.keys.max_keycode = 1 << 8; - test_XIDeviceChangedEvent(&in); - - in.keys.min_keycode = 1 << 8; - in.keys.max_keycode = 0; - test_XIDeviceChangedEvent(&in); - - in.num_valuators = 0; - test_XIDeviceChangedEvent(&in); - - in.num_valuators = 1; - test_XIDeviceChangedEvent(&in); - - in.num_valuators = MAX_VALUATORS; - test_XIDeviceChangedEvent(&in); - - for (i = 0; i < MAX_VALUATORS; i++) - { - in.valuators[i].min = 0; - in.valuators[i].max = 0; - test_XIDeviceChangedEvent(&in); - - in.valuators[i].max = 1 << 8; - test_XIDeviceChangedEvent(&in); - in.valuators[i].max = 1 << 16; - test_XIDeviceChangedEvent(&in); - in.valuators[i].max = 1 << 24; - test_XIDeviceChangedEvent(&in); - in.valuators[i].max = abs(~0); - test_XIDeviceChangedEvent(&in); - - in.valuators[i].resolution = 1 << 8; - test_XIDeviceChangedEvent(&in); - in.valuators[i].resolution = 1 << 16; - test_XIDeviceChangedEvent(&in); - in.valuators[i].resolution = 1 << 24; - test_XIDeviceChangedEvent(&in); - in.valuators[i].resolution = abs(~0); - test_XIDeviceChangedEvent(&in); - - in.valuators[i].name = i; - test_XIDeviceChangedEvent(&in); - - in.valuators[i].mode = Relative; - test_XIDeviceChangedEvent(&in); - - in.valuators[i].mode = Absolute; - test_XIDeviceChangedEvent(&in); - } -} - -int main(int argc, char** argv) -{ - g_test_init(&argc, &argv,NULL); - g_test_bug_base("https://bugzilla.freedesktop.org/show_bug.cgi?id="); - - g_test_add_func("/xi2/eventconvert/XIRawEvent", test_convert_XIRawEvent); - g_test_add_func("/xi2/eventconvert/XIFocusEvent", test_convert_XIFocusEvent); - g_test_add_func("/xi2/eventconvert/XIDeviceEvent", test_convert_XIDeviceEvent); - g_test_add_func("/xi2/eventconvert/XIDeviceChangedEvent", test_convert_XIDeviceChangedEvent); - - return g_test_run(); -} +/** + * Copyright © 2009 Red Hat, Inc. + * + * 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdint.h> +#include <glib.h> + +#include "inputstr.h" +#include "eventstr.h" +#include "eventconvert.h" +#include "exevents.h" +#include <X11/extensions/XI2proto.h> + + +static void test_values_XIRawEvent(RawDeviceEvent *in, xXIRawEvent *out, + BOOL swap) +{ + int i; + unsigned char *ptr; + FP3232 *value, *raw_value; + int nvals = 0; + int bits_set; + int len; + + if (swap) + { + char n; + + swaps(&out->sequenceNumber, n); + swapl(&out->length, n); + swaps(&out->evtype, n); + swaps(&out->deviceid, n); + swapl(&out->time, n); + swapl(&out->detail, n); + swaps(&out->valuators_len, n); + } + + + g_assert(out->type == GenericEvent); + g_assert(out->extension == 0); /* IReqCode defaults to 0 */ + g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); + g_assert(out->time == in->time); + g_assert(out->detail == in->detail.button); + g_assert(out->deviceid == in->deviceid); + g_assert(out->valuators_len >= bytes_to_int32(bits_to_bytes(sizeof(in->valuators.mask)))); + g_assert(out->flags == 0); /* FIXME: we don't set the flags yet */ + + ptr = (unsigned char*)&out[1]; + bits_set = 0; + + for (i = 0; out->valuators_len && i < sizeof(in->valuators.mask) * 8; i++) + { + g_assert (XIMaskIsSet(in->valuators.mask, i) == XIMaskIsSet(ptr, i)); + if (XIMaskIsSet(in->valuators.mask, i)) + bits_set++; + } + + /* length is len of valuator mask (in 4-byte units) + the number of bits + * set. Each bit set represents 2 8-byte values, hence the + * 'bits_set * 4' */ + len = out->valuators_len + bits_set * 4; + g_assert(out->length == len); + + nvals = 0; + + for (i = 0; out->valuators_len && i < MAX_VALUATORS; i++) + { + g_assert (XIMaskIsSet(in->valuators.mask, i) == XIMaskIsSet(ptr, i)); + if (XIMaskIsSet(in->valuators.mask, i)) + { + FP3232 vi, vo; + value = (FP3232*)(((unsigned char*)&out[1]) + out->valuators_len * 4); + value += nvals; + + vi.integral = in->valuators.data[i]; + vi.frac = in->valuators.data_frac[i]; + + vo.integral = value->integral; + vo.frac = value->frac; + if (swap) + { + char n; + swapl(&vo.integral, n); + swapl(&vo.frac, n); + } + + g_assert(vi.integral == vo.integral); + g_assert(vi.frac == vo.frac); + + raw_value = value + bits_set; + + vi.integral = in->valuators.data_raw[i]; + vi.frac = in->valuators.data_raw_frac[i]; + + vo.integral = raw_value->integral; + vo.frac = raw_value->frac; + if (swap) + { + char n; + swapl(&vo.integral, n); + swapl(&vo.frac, n); + } + + g_assert(vi.integral == vo.integral); + g_assert(vi.frac == vo.frac); + + nvals++; + } + } +} + +static void test_XIRawEvent(RawDeviceEvent *in) +{ + xXIRawEvent *out, *swapped; + int rc; + + rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); + g_assert(rc == Success); + + test_values_XIRawEvent(in, out, FALSE); + + swapped = calloc(1, sizeof(xEvent) + out->length * 4); + XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); + test_values_XIRawEvent(in, swapped, TRUE); + + free(out); + free(swapped); +} + +static void test_convert_XIFocusEvent(void) +{ + xEvent *out; + DeviceEvent in; + int rc; + + in.header = ET_Internal; + in.type = ET_Enter; + rc = EventToXI2((InternalEvent*)&in, &out); + g_assert(rc == Success); + g_assert(out == NULL); + + in.header = ET_Internal; + in.type = ET_FocusIn; + rc = EventToXI2((InternalEvent*)&in, &out); + g_assert(rc == Success); + g_assert(out == NULL); + + in.header = ET_Internal; + in.type = ET_FocusOut; + rc = EventToXI2((InternalEvent*)&in, &out); + g_assert(rc == BadImplementation); + + in.header = ET_Internal; + in.type = ET_Leave; + rc = EventToXI2((InternalEvent*)&in, &out); + g_assert(rc == BadImplementation); +} + + +static void test_convert_XIRawEvent(void) +{ + RawDeviceEvent in; + int i; + + memset(&in, 0, sizeof(in)); + + g_test_message("Testing all event types"); + in.header = ET_Internal; + in.type = ET_RawMotion; + test_XIRawEvent(&in); + + in.header = ET_Internal; + in.type = ET_RawKeyPress; + test_XIRawEvent(&in); + + in.header = ET_Internal; + in.type = ET_RawKeyRelease; + test_XIRawEvent(&in); + + in.header = ET_Internal; + in.type = ET_RawButtonPress; + test_XIRawEvent(&in); + + in.header = ET_Internal; + in.type = ET_RawButtonRelease; + test_XIRawEvent(&in); + + g_test_message("Testing details and other fields"); + in.detail.button = 1L; + test_XIRawEvent(&in); + in.detail.button = 1L << 8; + test_XIRawEvent(&in); + in.detail.button = 1L << 16; + test_XIRawEvent(&in); + in.detail.button = 1L << 24; + test_XIRawEvent(&in); + in.detail.button = ~0L; + test_XIRawEvent(&in); + + in.detail.button = 0; + + in.time = 1L; + test_XIRawEvent(&in); + in.time = 1L << 8; + test_XIRawEvent(&in); + in.time = 1L << 16; + test_XIRawEvent(&in); + in.time = 1L << 24; + test_XIRawEvent(&in); + in.time = ~0L; + test_XIRawEvent(&in); + + in.deviceid = 1; + test_XIRawEvent(&in); + in.deviceid = 1 << 8; + test_XIRawEvent(&in); + in.deviceid = ~0 & 0xFF; + test_XIRawEvent(&in); + + g_test_message("Testing valuator masks"); + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + test_XIRawEvent(&in); + XIClearMask(in.valuators.mask, i); + } + + for (i = 0; i < MAX_VALUATORS; i++) + { + XISetMask(in.valuators.mask, i); + + in.valuators.data[i] = i; + in.valuators.data_raw[i] = i + 10; + in.valuators.data_frac[i] = i + 20; + in.valuators.data_raw_frac[i] = i + 30; + test_XIRawEvent(&in); + XIClearMask(in.valuators.mask, i); + } + + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + test_XIRawEvent(&in); + } +} + +static void test_values_XIDeviceEvent(DeviceEvent *in, xXIDeviceEvent *out, + BOOL swap) +{ + int buttons, valuators; + int i; + unsigned char *ptr; + FP3232 *values; + + if (swap) { + char n; + + swaps(&out->sequenceNumber, n); + swapl(&out->length, n); + swaps(&out->evtype, n); + swaps(&out->deviceid, n); + swaps(&out->sourceid, n); + swapl(&out->time, n); + swapl(&out->detail, n); + swapl(&out->root, n); + swapl(&out->event, n); + swapl(&out->child, n); + swapl(&out->root_x, n); + swapl(&out->root_y, n); + swapl(&out->event_x, n); + swapl(&out->event_y, n); + swaps(&out->buttons_len, n); + swaps(&out->valuators_len, n); + swapl(&out->mods.base_mods, n); + swapl(&out->mods.latched_mods, n); + swapl(&out->mods.locked_mods, n); + swapl(&out->mods.effective_mods, n); + } + + g_assert(out->extension == 0); /* IReqCode defaults to 0 */ + g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); + g_assert(out->time == in->time); + g_assert(out->detail == in->detail.button); + g_assert(out->length >= 12); + + g_assert(out->deviceid == in->deviceid); + g_assert(out->sourceid == in->sourceid); + + g_assert(out->flags == 0); /* FIXME: we don't set the flags yet */ + + g_assert(out->root == in->root); + g_assert(out->event == None); /* set in FixUpEventFromWindow */ + g_assert(out->child == None); /* set in FixUpEventFromWindow */ + + g_assert(out->mods.base_mods == in->mods.base); + g_assert(out->mods.latched_mods == in->mods.latched); + g_assert(out->mods.locked_mods == in->mods.locked); + g_assert(out->mods.effective_mods == in->mods.effective); + + g_assert(out->group.base_group == in->group.base); + g_assert(out->group.latched_group == in->group.latched); + g_assert(out->group.locked_group == in->group.locked); + g_assert(out->group.effective_group == in->group.effective); + + g_assert(out->event_x == 0); /* set in FixUpEventFromWindow */ + g_assert(out->event_y == 0); /* set in FixUpEventFromWindow */ + + g_assert(out->root_x == FP1616(in->root_x, in->root_x_frac)); + g_assert(out->root_y == FP1616(in->root_y, in->root_y_frac)); + + buttons = 0; + for (i = 0; i < bits_to_bytes(sizeof(in->buttons)); i++) + { + if (XIMaskIsSet(in->buttons, i)) + { + g_assert(out->buttons_len >= bytes_to_int32(bits_to_bytes(i))); + buttons++; + } + } + + ptr = (unsigned char*)&out[1]; + for (i = 0; i < sizeof(in->buttons) * 8; i++) + g_assert(XIMaskIsSet(in->buttons, i) == XIMaskIsSet(ptr, i)); + + + valuators = 0; + for (i = 0; i < sizeof(in->valuators.mask) * 8; i++) + if (XIMaskIsSet(in->valuators.mask, i)) + valuators++; + + g_assert(out->valuators_len >= bytes_to_int32(bits_to_bytes(valuators))); + + ptr += out->buttons_len * 4; + values = (FP3232*)(ptr + out->valuators_len * 4); + for (i = 0; i < sizeof(in->valuators.mask) * 8 || + i < (out->valuators_len * 4) * 8; i++) + { + if (i > sizeof(in->valuators.mask) * 8) + g_assert(!XIMaskIsSet(ptr, i)); + else if (i > out->valuators_len * 4 * 8) + g_assert(!XIMaskIsSet(in->valuators.mask, i)); + else { + g_assert(XIMaskIsSet(in->valuators.mask, i) == + XIMaskIsSet(ptr, i)); + + if (XIMaskIsSet(ptr, i)) + { + FP3232 vi, vo; + + vi.integral = in->valuators.data[i]; + vi.frac = in->valuators.data_frac[i]; + + vo = *values; + + if (swap) + { + char n; + swapl(&vo.integral, n); + swapl(&vo.frac, n); + } + + + g_assert(vi.integral == vo.integral); + g_assert(vi.frac == vo.frac); + values++; + } + } + } +} + +static void test_XIDeviceEvent(DeviceEvent *in) +{ + xXIDeviceEvent *out, *swapped; + int rc; + + rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); + g_assert(rc == Success); + + test_values_XIDeviceEvent(in, out, FALSE); + + swapped = calloc(1, sizeof(xEvent) + out->length * 4); + XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); + test_values_XIDeviceEvent(in, swapped, TRUE); + + free(out); + free(swapped); +} + +static void test_convert_XIDeviceEvent(void) +{ + DeviceEvent in; + int i; + + memset(&in, 0, sizeof(in)); + + g_test_message("Testing simple field values"); + in.header = ET_Internal; + in.type = ET_Motion; + in.length = sizeof(DeviceEvent); + in.time = 0; + in.deviceid = 1; + in.sourceid = 2; + in.root = 3; + in.root_x = 4; + in.root_x_frac = 5; + in.root_y = 6; + in.root_y_frac = 7; + in.detail.button = 8; + in.mods.base = 9; + in.mods.latched = 10; + in.mods.locked = 11; + in.mods.effective = 11; + in.group.base = 12; + in.group.latched = 13; + in.group.locked = 14; + in.group.effective = 15; + + test_XIDeviceEvent(&in); + + g_test_message("Testing field ranges"); + /* 32 bit */ + in.detail.button = 1L; + test_XIDeviceEvent(&in); + in.detail.button = 1L << 8; + test_XIDeviceEvent(&in); + in.detail.button = 1L << 16; + test_XIDeviceEvent(&in); + in.detail.button = 1L << 24; + test_XIDeviceEvent(&in); + in.detail.button = ~0L; + test_XIDeviceEvent(&in); + + /* 32 bit */ + in.time = 1L; + test_XIDeviceEvent(&in); + in.time = 1L << 8; + test_XIDeviceEvent(&in); + in.time = 1L << 16; + test_XIDeviceEvent(&in); + in.time = 1L << 24; + test_XIDeviceEvent(&in); + in.time = ~0L; + test_XIDeviceEvent(&in); + + /* 16 bit */ + in.deviceid = 1; + test_XIDeviceEvent(&in); + in.deviceid = 1 << 8; + test_XIDeviceEvent(&in); + in.deviceid = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + /* 16 bit */ + in.sourceid = 1; + test_XIDeviceEvent(&in); + in.deviceid = 1 << 8; + test_XIDeviceEvent(&in); + in.deviceid = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + /* 32 bit */ + in.root = 1L; + test_XIDeviceEvent(&in); + in.root = 1L << 8; + test_XIDeviceEvent(&in); + in.root = 1L << 16; + test_XIDeviceEvent(&in); + in.root = 1L << 24; + test_XIDeviceEvent(&in); + in.root = ~0L; + test_XIDeviceEvent(&in); + + /* 16 bit */ + in.root_x = 1; + test_XIDeviceEvent(&in); + in.root_x = 1 << 8; + test_XIDeviceEvent(&in); + in.root_x = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.root_x_frac = 1; + test_XIDeviceEvent(&in); + in.root_x_frac = 1 << 8; + test_XIDeviceEvent(&in); + in.root_x_frac = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.root_y = 1; + test_XIDeviceEvent(&in); + in.root_y = 1 << 8; + test_XIDeviceEvent(&in); + in.root_y = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.root_y_frac = 1; + test_XIDeviceEvent(&in); + in.root_y_frac = 1 << 8; + test_XIDeviceEvent(&in); + in.root_y_frac = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + /* 32 bit */ + in.mods.base = 1L; + test_XIDeviceEvent(&in); + in.mods.base = 1L << 8; + test_XIDeviceEvent(&in); + in.mods.base = 1L << 16; + test_XIDeviceEvent(&in); + in.mods.base = 1L << 24; + test_XIDeviceEvent(&in); + in.mods.base = ~0L; + test_XIDeviceEvent(&in); + + in.mods.latched = 1L; + test_XIDeviceEvent(&in); + in.mods.latched = 1L << 8; + test_XIDeviceEvent(&in); + in.mods.latched = 1L << 16; + test_XIDeviceEvent(&in); + in.mods.latched = 1L << 24; + test_XIDeviceEvent(&in); + in.mods.latched = ~0L; + test_XIDeviceEvent(&in); + + in.mods.locked = 1L; + test_XIDeviceEvent(&in); + in.mods.locked = 1L << 8; + test_XIDeviceEvent(&in); + in.mods.locked = 1L << 16; + test_XIDeviceEvent(&in); + in.mods.locked = 1L << 24; + test_XIDeviceEvent(&in); + in.mods.locked = ~0L; + test_XIDeviceEvent(&in); + + in.mods.effective = 1L; + test_XIDeviceEvent(&in); + in.mods.effective = 1L << 8; + test_XIDeviceEvent(&in); + in.mods.effective = 1L << 16; + test_XIDeviceEvent(&in); + in.mods.effective = 1L << 24; + test_XIDeviceEvent(&in); + in.mods.effective = ~0L; + test_XIDeviceEvent(&in); + + /* 8 bit */ + in.group.base = 1; + test_XIDeviceEvent(&in); + in.group.base = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.group.latched = 1; + test_XIDeviceEvent(&in); + in.group.latched = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.group.locked = 1; + test_XIDeviceEvent(&in); + in.group.locked = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.mods.effective = 1; + test_XIDeviceEvent(&in); + in.mods.effective = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + g_test_message("Testing button masks"); + for (i = 0; i < sizeof(in.buttons) * 8; i++) + { + XISetMask(in.buttons, i); + test_XIDeviceEvent(&in); + XIClearMask(in.buttons, i); + } + + for (i = 0; i < sizeof(in.buttons) * 8; i++) + { + XISetMask(in.buttons, i); + test_XIDeviceEvent(&in); + } + + g_test_message("Testing valuator masks"); + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + test_XIDeviceEvent(&in); + XIClearMask(in.valuators.mask, i); + } + + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + + in.valuators.data[i] = i; + in.valuators.data_frac[i] = i + 20; + test_XIDeviceEvent(&in); + XIClearMask(in.valuators.mask, i); + } + + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + test_XIDeviceEvent(&in); + } +} + +static void test_values_XIDeviceChangedEvent(DeviceChangedEvent *in, + xXIDeviceChangedEvent *out, + BOOL swap) +{ + int i, j; + unsigned char *ptr; + + if (swap) + { + char n; + + swaps(&out->sequenceNumber, n); + swapl(&out->length, n); + swaps(&out->evtype, n); + swaps(&out->deviceid, n); + swaps(&out->sourceid, n); + swapl(&out->time, n); + swaps(&out->num_classes, n); + } + + g_assert(out->type == GenericEvent); + g_assert(out->extension == 0); /* IReqCode defaults to 0 */ + g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); + g_assert(out->time == in->time); + g_assert(out->deviceid == in->deviceid); + g_assert(out->sourceid == in->sourceid); + + ptr = (unsigned char*)&out[1]; + for (i = 0; i < out->num_classes; i++) + { + xXIAnyInfo* any = (xXIAnyInfo*)ptr; + + if (swap) + { + char n; + swaps(&any->length, n); + swaps(&any->type, n); + swaps(&any->sourceid, n); + } + + switch(any->type) + { + case XIButtonClass: + { + xXIButtonInfo *b = (xXIButtonInfo*)any; + Atom *names; + + if (swap) + { + char n; + swaps(&b->num_buttons, n); + } + + g_assert(b->length == + bytes_to_int32(sizeof(xXIButtonInfo)) + + bytes_to_int32(bits_to_bytes(b->num_buttons)) + + b->num_buttons); + g_assert(b->num_buttons == in->buttons.num_buttons); + + names = (Atom*)((char*)&b[1] + + pad_to_int32(bits_to_bytes(b->num_buttons))); + for (j = 0; j < b->num_buttons; j++) + { + if (swap) + { + char n; + swapl(&names[j], n); + } + g_assert(names[j] == in->buttons.names[j]); + } + } + break; + case XIKeyClass: + { + xXIKeyInfo *k = (xXIKeyInfo*)any; + uint32_t *kc; + + if (swap) + { + char n; + swaps(&k->num_keycodes, n); + } + + g_assert(k->length == + bytes_to_int32(sizeof(xXIKeyInfo)) + + k->num_keycodes); + g_assert(k->num_keycodes == in->keys.max_keycode - + in->keys.min_keycode + 1); + + kc = (uint32_t*)&k[1]; + for (j = 0; j < k->num_keycodes; j++) + { + if (swap) + { + char n; + swapl(&kc[j], n); + } + g_assert(kc[j] >= in->keys.min_keycode); + g_assert(kc[j] <= in->keys.max_keycode); + } + } + break; + case XIValuatorClass: + { + xXIValuatorInfo *v = (xXIValuatorInfo*)any; + g_assert(v->length == + bytes_to_int32(sizeof(xXIValuatorInfo))); + + } + break; + default: + g_error("Invalid class type.\n"); + break; + } + + ptr += any->length * 4; + } + +} + +static void test_XIDeviceChangedEvent(DeviceChangedEvent *in) +{ + xXIDeviceChangedEvent *out, *swapped; + int rc; + + rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); + g_assert(rc == Success); + + test_values_XIDeviceChangedEvent(in, out, FALSE); + + swapped = calloc(1, sizeof(xEvent) + out->length * 4); + XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); + test_values_XIDeviceChangedEvent(in, swapped, TRUE); + + free(out); + free(swapped); +} + +static void test_convert_XIDeviceChangedEvent(void) +{ + DeviceChangedEvent in; + int i; + + g_test_message("Testing simple field values"); + memset(&in, 0, sizeof(in)); + in.header = ET_Internal; + in.type = ET_DeviceChanged; + in.length = sizeof(DeviceChangedEvent); + in.time = 0; + in.deviceid = 1; + in.sourceid = 2; + in.masterid = 3; + in.num_valuators = 4; + in.flags = DEVCHANGE_SLAVE_SWITCH | DEVCHANGE_POINTER_EVENT | DEVCHANGE_KEYBOARD_EVENT; + + for (i = 0; i < MAX_BUTTONS; i++) + in.buttons.names[i] = i + 10; + + in.keys.min_keycode = 8; + in.keys.max_keycode = 255; + + test_XIDeviceChangedEvent(&in); + + in.time = 1L; + test_XIDeviceChangedEvent(&in); + in.time = 1L << 8; + test_XIDeviceChangedEvent(&in); + in.time = 1L << 16; + test_XIDeviceChangedEvent(&in); + in.time = 1L << 24; + test_XIDeviceChangedEvent(&in); + in.time = ~0L; + test_XIDeviceChangedEvent(&in); + + in.deviceid = 1L; + test_XIDeviceChangedEvent(&in); + in.deviceid = 1L << 8; + test_XIDeviceChangedEvent(&in); + in.deviceid = ~0 & 0xFFFF; + test_XIDeviceChangedEvent(&in); + + in.sourceid = 1L; + test_XIDeviceChangedEvent(&in); + in.sourceid = 1L << 8; + test_XIDeviceChangedEvent(&in); + in.sourceid = ~0 & 0xFFFF; + test_XIDeviceChangedEvent(&in); + + in.masterid = 1L; + test_XIDeviceChangedEvent(&in); + in.masterid = 1L << 8; + test_XIDeviceChangedEvent(&in); + in.masterid = ~0 & 0xFFFF; + test_XIDeviceChangedEvent(&in); + + in.buttons.num_buttons = 0; + test_XIDeviceChangedEvent(&in); + + in.buttons.num_buttons = 1; + test_XIDeviceChangedEvent(&in); + + in.buttons.num_buttons = MAX_BUTTONS; + test_XIDeviceChangedEvent(&in); + + in.keys.min_keycode = 0; + in.keys.max_keycode = 0; + test_XIDeviceChangedEvent(&in); + + in.keys.max_keycode = 1 << 8; + test_XIDeviceChangedEvent(&in); + + in.keys.max_keycode = 0xFFFC; /* highest range, above that the length + field gives up */ + test_XIDeviceChangedEvent(&in); + + in.keys.min_keycode = 1 << 8; + in.keys.max_keycode = 1 << 8; + test_XIDeviceChangedEvent(&in); + + in.keys.min_keycode = 1 << 8; + in.keys.max_keycode = 0; + test_XIDeviceChangedEvent(&in); + + in.num_valuators = 0; + test_XIDeviceChangedEvent(&in); + + in.num_valuators = 1; + test_XIDeviceChangedEvent(&in); + + in.num_valuators = MAX_VALUATORS; + test_XIDeviceChangedEvent(&in); + + for (i = 0; i < MAX_VALUATORS; i++) + { + in.valuators[i].min = 0; + in.valuators[i].max = 0; + test_XIDeviceChangedEvent(&in); + + in.valuators[i].max = 1 << 8; + test_XIDeviceChangedEvent(&in); + in.valuators[i].max = 1 << 16; + test_XIDeviceChangedEvent(&in); + in.valuators[i].max = 1 << 24; + test_XIDeviceChangedEvent(&in); + in.valuators[i].max = abs(~0); + test_XIDeviceChangedEvent(&in); + + in.valuators[i].resolution = 1 << 8; + test_XIDeviceChangedEvent(&in); + in.valuators[i].resolution = 1 << 16; + test_XIDeviceChangedEvent(&in); + in.valuators[i].resolution = 1 << 24; + test_XIDeviceChangedEvent(&in); + in.valuators[i].resolution = abs(~0); + test_XIDeviceChangedEvent(&in); + + in.valuators[i].name = i; + test_XIDeviceChangedEvent(&in); + + in.valuators[i].mode = Relative; + test_XIDeviceChangedEvent(&in); + + in.valuators[i].mode = Absolute; + test_XIDeviceChangedEvent(&in); + } +} + +int main(int argc, char** argv) +{ + g_test_init(&argc, &argv,NULL); + g_test_bug_base("https://bugzilla.freedesktop.org/show_bug.cgi?id="); + + g_test_add_func("/xi2/eventconvert/XIRawEvent", test_convert_XIRawEvent); + g_test_add_func("/xi2/eventconvert/XIFocusEvent", test_convert_XIFocusEvent); + g_test_add_func("/xi2/eventconvert/XIDeviceEvent", test_convert_XIDeviceEvent); + g_test_add_func("/xi2/eventconvert/XIDeviceChangedEvent", test_convert_XIDeviceChangedEvent); + + return g_test_run(); +} diff --git a/xorg-server/xfixes/cursor.c b/xorg-server/xfixes/cursor.c index 2aba0cec9..296836055 100644 --- a/xorg-server/xfixes/cursor.c +++ b/xorg-server/xfixes/cursor.c @@ -1,1104 +1,1104 @@ -/* - * Copyright © 2006 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, 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. - * - * 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 <dix-config.h> -#endif - -#include "xfixesint.h" -#include "scrnintstr.h" -#include "cursorstr.h" -#include "dixevents.h" -#include "servermd.h" -#include "inputstr.h" -#include "windowstr.h" -#include "xace.h" - -static RESTYPE CursorClientType; -static RESTYPE CursorHideCountType; -static RESTYPE CursorWindowType; -static CursorPtr CursorCurrent[MAXDEVICES]; -static CursorPtr pInvisibleCursor = NULL; - -static int CursorScreenPrivateKeyIndex; -static DevPrivateKey CursorScreenPrivateKey = &CursorScreenPrivateKeyIndex; - -static void deleteCursorHideCountsForScreen (ScreenPtr pScreen); - -#define VERIFY_CURSOR(pCursor, cursor, client, access) \ - do { \ - int err; \ - err = dixLookupResourceByType((pointer *) &pCursor, cursor, \ - RT_CURSOR, client, access); \ - if (err == BadValue) { \ - client->errorValue = cursor; \ - return BadCursor; \ - } else if (err != Success) { \ - client->errorValue = cursor; \ - return err; \ - } \ - } while (0) - -/* - * There is a global list of windows selecting for cursor events - */ - -typedef struct _CursorEvent *CursorEventPtr; - -typedef struct _CursorEvent { - CursorEventPtr next; - CARD32 eventMask; - ClientPtr pClient; - WindowPtr pWindow; - XID clientResource; -} CursorEventRec; - -static CursorEventPtr cursorEvents; - -/* - * Each screen has a list of clients which have requested - * that the cursor be hid, and the number of times each - * client has requested. -*/ - -typedef struct _CursorHideCountRec *CursorHideCountPtr; - -typedef struct _CursorHideCountRec { - CursorHideCountPtr pNext; - ClientPtr pClient; - ScreenPtr pScreen; - int hideCount; - XID resource; -} CursorHideCountRec; - -/* - * Wrap DisplayCursor to catch cursor change events - */ - -typedef struct _CursorScreen { - DisplayCursorProcPtr DisplayCursor; - CloseScreenProcPtr CloseScreen; - CursorHideCountPtr pCursorHideCounts; -} CursorScreenRec, *CursorScreenPtr; - -#define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey)) -#define GetCursorScreenIfSet(s) GetCursorScreen(s) -#define SetCursorScreen(s,p) dixSetPrivate(&(s)->devPrivates, CursorScreenPrivateKey, p) -#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) -#define Unwrap(as,s,elt,backup) (((backup) = (s)->elt), (s)->elt = (as)->elt) - -/* The cursor doesn't show up until the first XDefineCursor() */ -static Bool CursorVisible = FALSE; - -Bool EnableCursor = TRUE; - -static Bool -CursorDisplayCursor (DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor) -{ - CursorScreenPtr cs = GetCursorScreen(pScreen); - Bool ret; - DisplayCursorProcPtr backupProc; - - Unwrap (cs, pScreen, DisplayCursor, backupProc); - - /* - * Have to check ConnectionInfo to distinguish client requests from - * initial root window setup. Not a great way to do it, I admit. - */ - if (ConnectionInfo) - CursorVisible = EnableCursor; - - if (cs->pCursorHideCounts != NULL || !CursorVisible) { - ret = ((*pScreen->RealizeCursor)(pDev, pScreen, pInvisibleCursor) && - (*pScreen->DisplayCursor) (pDev, pScreen, pInvisibleCursor)); - } else { - ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); - } - - if (pCursor != CursorCurrent[pDev->id]) - { - CursorEventPtr e; - - CursorCurrent[pDev->id] = pCursor; - for (e = cursorEvents; e; e = e->next) - { - if ((e->eventMask & XFixesDisplayCursorNotifyMask) && - !e->pClient->clientGone) - { - xXFixesCursorNotifyEvent ev; - ev.type = XFixesEventBase + XFixesCursorNotify; - ev.subtype = XFixesDisplayCursorNotify; - ev.sequenceNumber = e->pClient->sequence; - ev.window = e->pWindow->drawable.id; - ev.cursorSerial = pCursor->serialNumber; - ev.timestamp = currentTime.milliseconds; - ev.name = pCursor->name; - WriteEventsToClient (e->pClient, 1, (xEvent *) &ev); - } - } - } - Wrap (cs, pScreen, DisplayCursor, backupProc); - - return ret; -} - -static Bool -CursorCloseScreen (int index, ScreenPtr pScreen) -{ - CursorScreenPtr cs = GetCursorScreen (pScreen); - Bool ret; - CloseScreenProcPtr close_proc; - DisplayCursorProcPtr display_proc; - - Unwrap (cs, pScreen, CloseScreen, close_proc); - Unwrap (cs, pScreen, DisplayCursor, display_proc); - deleteCursorHideCountsForScreen(pScreen); - ret = (*pScreen->CloseScreen) (index, pScreen); - xfree (cs); - return ret; -} - -#define CursorAllEvents (XFixesDisplayCursorNotifyMask) - -static int -XFixesSelectCursorInput (ClientPtr pClient, - WindowPtr pWindow, - CARD32 eventMask) -{ - CursorEventPtr *prev, e; - pointer val; - int rc; - - for (prev = &cursorEvents; (e = *prev); prev = &e->next) - { - if (e->pClient == pClient && - e->pWindow == pWindow) - { - break; - } - } - if (!eventMask) - { - if (e) - { - FreeResource (e->clientResource, 0); - } - return Success; - } - if (!e) - { - e = (CursorEventPtr) xalloc (sizeof (CursorEventRec)); - if (!e) - return BadAlloc; - - e->next = 0; - e->pClient = pClient; - e->pWindow = pWindow; - e->clientResource = FakeClientID(pClient->index); - - /* - * Add a resource hanging from the window to - * catch window destroy - */ - rc = dixLookupResourceByType( &val, pWindow->drawable.id, - CursorWindowType, serverClient, - DixGetAttrAccess); - if (rc != Success) - if (!AddResource (pWindow->drawable.id, CursorWindowType, - (pointer) pWindow)) - { - xfree (e); - return BadAlloc; - } - - if (!AddResource (e->clientResource, CursorClientType, (pointer) e)) - return BadAlloc; - - *prev = e; - } - e->eventMask = eventMask; - return Success; -} - -int -ProcXFixesSelectCursorInput (ClientPtr client) -{ - REQUEST (xXFixesSelectCursorInputReq); - WindowPtr pWin; - int rc; - - REQUEST_SIZE_MATCH (xXFixesSelectCursorInputReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - if (stuff->eventMask & ~CursorAllEvents) - { - client->errorValue = stuff->eventMask; - return( BadValue ); - } - return XFixesSelectCursorInput (client, pWin, stuff->eventMask); -} - -static int -GetBit (unsigned char *line, int x) -{ - unsigned char mask; - - if (screenInfo.bitmapBitOrder == LSBFirst) - mask = (1 << (x & 7)); - else - mask = (0x80 >> (x & 7)); - /* XXX assumes byte order is host byte order */ - line += (x >> 3); - if (*line & mask) - return 1; - return 0; -} - -int -SProcXFixesSelectCursorInput (ClientPtr client) -{ - register int n; - REQUEST(xXFixesSelectCursorInputReq); - - swaps(&stuff->length, n); - swapl(&stuff->window, n); - swapl(&stuff->eventMask, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -void -SXFixesCursorNotifyEvent (xXFixesCursorNotifyEvent *from, - xXFixesCursorNotifyEvent *to) -{ - to->type = from->type; - cpswaps (from->sequenceNumber, to->sequenceNumber); - cpswapl (from->window, to->window); - cpswapl (from->cursorSerial, to->cursorSerial); - cpswapl (from->timestamp, to->timestamp); - cpswapl (from->name, to->name); -} - -static void -CopyCursorToImage (CursorPtr pCursor, CARD32 *image) -{ - int width = pCursor->bits->width; - int height = pCursor->bits->height; - int npixels = width * height; - -#ifdef ARGB_CURSOR - if (pCursor->bits->argb) - memcpy (image, pCursor->bits->argb, npixels * sizeof (CARD32)); - else -#endif - { - unsigned char *srcLine = pCursor->bits->source; - unsigned char *mskLine = pCursor->bits->mask; - int stride = BitmapBytePad (width); - int x, y; - CARD32 fg, bg; - - fg = (0xff000000 | - ((pCursor->foreRed & 0xff00) << 8) | - (pCursor->foreGreen & 0xff00) | - (pCursor->foreBlue >> 8)); - bg = (0xff000000 | - ((pCursor->backRed & 0xff00) << 8) | - (pCursor->backGreen & 0xff00) | - (pCursor->backBlue >> 8)); - for (y = 0; y < height; y++) - { - for (x = 0; x < width; x++) - { - if (GetBit (mskLine, x)) - { - if (GetBit (srcLine, x)) - *image++ = fg; - else - *image++ = bg; - } - else - *image++ = 0; - } - srcLine += stride; - mskLine += stride; - } - } -} - -int -ProcXFixesGetCursorImage (ClientPtr client) -{ -/* REQUEST(xXFixesGetCursorImageReq); */ - xXFixesGetCursorImageReply *rep; - CursorPtr pCursor; - CARD32 *image; - int npixels, width, height, rc, x, y; - - REQUEST_SIZE_MATCH(xXFixesGetCursorImageReq); - pCursor = CursorCurrent[PickPointer(client)->id]; - if (!pCursor) - return BadCursor; - rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, - pCursor, RT_NONE, NULL, DixReadAccess); - if (rc != Success) - return rc; - GetSpritePosition (PickPointer(client), &x, &y); - width = pCursor->bits->width; - height = pCursor->bits->height; - npixels = width * height; - rep = xalloc (sizeof (xXFixesGetCursorImageReply) + - npixels * sizeof (CARD32)); - if (!rep) - return BadAlloc; - - rep->type = X_Reply; - rep->sequenceNumber = client->sequence; - rep->length = npixels; - rep->width = width; - rep->height = height; - rep->x = x; - rep->y = y; - rep->xhot = pCursor->bits->xhot; - rep->yhot = pCursor->bits->yhot; - rep->cursorSerial = pCursor->serialNumber; - - image = (CARD32 *) (rep + 1); - CopyCursorToImage (pCursor, image); - if (client->swapped) - { - int n; - swaps (&rep->sequenceNumber, n); - swapl (&rep->length, n); - swaps (&rep->x, n); - swaps (&rep->y, n); - swaps (&rep->width, n); - swaps (&rep->height, n); - swaps (&rep->xhot, n); - swaps (&rep->yhot, n); - swapl (&rep->cursorSerial, n); - SwapLongs (image, npixels); - } - WriteToClient(client, sizeof (xXFixesGetCursorImageReply) + - (npixels << 2), (char *) rep); - xfree (rep); - return client->noClientException; -} - -int -SProcXFixesGetCursorImage (ClientPtr client) -{ - int n; - REQUEST(xXFixesGetCursorImageReq); - swaps (&stuff->length, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -int -ProcXFixesSetCursorName (ClientPtr client) -{ - CursorPtr pCursor; - char *tchar; - REQUEST(xXFixesSetCursorNameReq); - Atom atom; - - REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); - VERIFY_CURSOR(pCursor, stuff->cursor, client, DixSetAttrAccess); - tchar = (char *) &stuff[1]; - atom = MakeAtom (tchar, stuff->nbytes, TRUE); - if (atom == BAD_RESOURCE) - return BadAlloc; - - pCursor->name = atom; - return(client->noClientException); -} - -int -SProcXFixesSetCursorName (ClientPtr client) -{ - int n; - REQUEST(xXFixesSetCursorNameReq); - - swaps (&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); - swapl (&stuff->cursor, n); - swaps (&stuff->nbytes, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -int -ProcXFixesGetCursorName (ClientPtr client) -{ - CursorPtr pCursor; - xXFixesGetCursorNameReply reply; - REQUEST(xXFixesGetCursorNameReq); - const char *str; - int len; - - REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); - VERIFY_CURSOR(pCursor, stuff->cursor, client, DixGetAttrAccess); - if (pCursor->name) - str = NameForAtom (pCursor->name); - else - str = ""; - len = strlen (str); - - reply.type = X_Reply; - reply.length = bytes_to_int32(len); - reply.sequenceNumber = client->sequence; - reply.atom = pCursor->name; - reply.nbytes = len; - if (client->swapped) - { - int n; - swaps (&reply.sequenceNumber, n); - swapl (&reply.length, n); - swapl (&reply.atom, n); - swaps (&reply.nbytes, n); - } - WriteReplyToClient(client, sizeof(xXFixesGetCursorNameReply), &reply); - WriteToClient(client, len, str); - - return(client->noClientException); -} - -int -SProcXFixesGetCursorName (ClientPtr client) -{ - int n; - REQUEST(xXFixesGetCursorNameReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); - swapl (&stuff->cursor, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -int -ProcXFixesGetCursorImageAndName (ClientPtr client) -{ -/* REQUEST(xXFixesGetCursorImageAndNameReq); */ - xXFixesGetCursorImageAndNameReply *rep; - CursorPtr pCursor; - CARD32 *image; - int npixels; - const char *name; - int nbytes, nbytesRound; - int width, height; - int rc, x, y; - - REQUEST_SIZE_MATCH(xXFixesGetCursorImageAndNameReq); - pCursor = CursorCurrent[PickPointer(client)->id]; - if (!pCursor) - return BadCursor; - rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, - pCursor, RT_NONE, NULL, DixReadAccess|DixGetAttrAccess); - if (rc != Success) - return rc; - GetSpritePosition (PickPointer(client), &x, &y); - width = pCursor->bits->width; - height = pCursor->bits->height; - npixels = width * height; - name = pCursor->name ? NameForAtom (pCursor->name) : ""; - nbytes = strlen (name); - nbytesRound = pad_to_int32(nbytes); - rep = xalloc (sizeof (xXFixesGetCursorImageAndNameReply) + - npixels * sizeof (CARD32) + nbytesRound); - if (!rep) - return BadAlloc; - - rep->type = X_Reply; - rep->sequenceNumber = client->sequence; - rep->length = npixels + bytes_to_int32(nbytesRound); - rep->width = width; - rep->height = height; - rep->x = x; - rep->y = y; - rep->xhot = pCursor->bits->xhot; - rep->yhot = pCursor->bits->yhot; - rep->cursorSerial = pCursor->serialNumber; - rep->cursorName = pCursor->name; - rep->nbytes = nbytes; - - image = (CARD32 *) (rep + 1); - CopyCursorToImage (pCursor, image); - memcpy ((image + npixels), name, nbytes); - if (client->swapped) - { - int n; - swaps (&rep->sequenceNumber, n); - swapl (&rep->length, n); - swaps (&rep->x, n); - swaps (&rep->y, n); - swaps (&rep->width, n); - swaps (&rep->height, n); - swaps (&rep->xhot, n); - swaps (&rep->yhot, n); - swapl (&rep->cursorSerial, n); - swapl (&rep->cursorName, n); - swaps (&rep->nbytes, n); - SwapLongs (image, npixels); - } - WriteToClient(client, sizeof (xXFixesGetCursorImageAndNameReply) + - (npixels << 2) + nbytesRound, (char *) rep); - xfree (rep); - return client->noClientException; -} - -int -SProcXFixesGetCursorImageAndName (ClientPtr client) -{ - int n; - REQUEST(xXFixesGetCursorImageAndNameReq); - swaps (&stuff->length, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -/* - * Find every cursor reference in the system, ask testCursor - * whether it should be replaced with a reference to pCursor. - */ - -typedef Bool (*TestCursorFunc) (CursorPtr pOld, pointer closure); - -typedef struct { - RESTYPE type; - TestCursorFunc testCursor; - CursorPtr pNew; - pointer closure; -} ReplaceCursorLookupRec, *ReplaceCursorLookupPtr; - -static const RESTYPE CursorRestypes[] = { - RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR -}; - -#define NUM_CURSOR_RESTYPES (sizeof (CursorRestypes) / sizeof (CursorRestypes[0])) - -static Bool -ReplaceCursorLookup (pointer value, XID id, pointer closure) -{ - ReplaceCursorLookupPtr rcl = (ReplaceCursorLookupPtr) closure; - WindowPtr pWin; - GrabPtr pGrab; - CursorPtr pCursor = 0, *pCursorRef = 0; - XID cursor = 0; - - switch (rcl->type) { - case RT_WINDOW: - pWin = (WindowPtr) value; - if (pWin->optional) - { - pCursorRef = &pWin->optional->cursor; - pCursor = *pCursorRef; - } - break; - case RT_PASSIVEGRAB: - pGrab = (GrabPtr) value; - pCursorRef = &pGrab->cursor; - pCursor = *pCursorRef; - break; - case RT_CURSOR: - pCursorRef = 0; - pCursor = (CursorPtr) value; - cursor = id; - break; - } - if (pCursor && pCursor != rcl->pNew) - { - if ((*rcl->testCursor) (pCursor, rcl->closure)) - { - rcl->pNew->refcnt++; - /* either redirect reference or update resource database */ - if (pCursorRef) - *pCursorRef = rcl->pNew; - else - ChangeResourceValue (id, RT_CURSOR, rcl->pNew); - FreeCursor (pCursor, cursor); - } - } - return FALSE; /* keep walking */ -} - -static void -ReplaceCursor (CursorPtr pCursor, - TestCursorFunc testCursor, - pointer closure) -{ - int clientIndex; - int resIndex; - ReplaceCursorLookupRec rcl; - - /* - * Cursors exist only in the resource database, windows and grabs. - * All of these are always pointed at by the resource database. Walk - * the whole thing looking for cursors - */ - rcl.testCursor = testCursor; - rcl.pNew = pCursor; - rcl.closure = closure; - - /* for each client */ - for (clientIndex = 0; clientIndex < currentMaxClients; clientIndex++) - { - if (!clients[clientIndex]) - continue; - for (resIndex = 0; resIndex < NUM_CURSOR_RESTYPES; resIndex++) - { - rcl.type = CursorRestypes[resIndex]; - /* - * This function walks the entire client resource database - */ - LookupClientResourceComplex (clients[clientIndex], - rcl.type, - ReplaceCursorLookup, - (pointer) &rcl); - } - } - /* this "knows" that WindowHasNewCursor doesn't depend on it's argument */ - WindowHasNewCursor (WindowTable[0]); -} - -static Bool -TestForCursor (CursorPtr pCursor, pointer closure) -{ - return (pCursor == (CursorPtr) closure); -} - -int -ProcXFixesChangeCursor (ClientPtr client) -{ - CursorPtr pSource, pDestination; - REQUEST(xXFixesChangeCursorReq); - - REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); - VERIFY_CURSOR (pSource, stuff->source, client, - DixReadAccess|DixGetAttrAccess); - VERIFY_CURSOR (pDestination, stuff->destination, client, - DixWriteAccess|DixSetAttrAccess); - - ReplaceCursor (pSource, TestForCursor, (pointer) pDestination); - return (client->noClientException); -} - -int -SProcXFixesChangeCursor (ClientPtr client) -{ - int n; - REQUEST(xXFixesChangeCursorReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); - swapl (&stuff->source, n); - swapl (&stuff->destination, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -static Bool -TestForCursorName (CursorPtr pCursor, pointer closure) -{ - Atom *pName = closure; - return (pCursor->name == *pName); -} - -int -ProcXFixesChangeCursorByName (ClientPtr client) -{ - CursorPtr pSource; - Atom name; - char *tchar; - REQUEST(xXFixesChangeCursorByNameReq); - - REQUEST_FIXED_SIZE(xXFixesChangeCursorByNameReq, stuff->nbytes); - VERIFY_CURSOR(pSource, stuff->source, client, - DixReadAccess|DixGetAttrAccess); - tchar = (char *) &stuff[1]; - name = MakeAtom (tchar, stuff->nbytes, FALSE); - if (name) - ReplaceCursor (pSource, TestForCursorName, &name); - return (client->noClientException); -} - -int -SProcXFixesChangeCursorByName (ClientPtr client) -{ - int n; - REQUEST(xXFixesChangeCursorByNameReq); - - swaps (&stuff->length, n); - REQUEST_AT_LEAST_SIZE (xXFixesChangeCursorByNameReq); - swapl (&stuff->source, n); - swaps (&stuff->nbytes, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -/* - * Routines for manipulating the per-screen hide counts list. - * This list indicates which clients have requested cursor hiding - * for that screen. - */ - -/* Return the screen's hide-counts list element for the given client */ -static CursorHideCountPtr -findCursorHideCount (ClientPtr pClient, ScreenPtr pScreen) -{ - CursorScreenPtr cs = GetCursorScreen(pScreen); - CursorHideCountPtr pChc; - - for (pChc = cs->pCursorHideCounts; pChc != NULL; pChc = pChc->pNext) { - if (pChc->pClient == pClient) { - return pChc; - } - } - - return NULL; -} - -static int -createCursorHideCount (ClientPtr pClient, ScreenPtr pScreen) -{ - CursorScreenPtr cs = GetCursorScreen(pScreen); - CursorHideCountPtr pChc; - - pChc = (CursorHideCountPtr) xalloc(sizeof(CursorHideCountRec)); - if (pChc == NULL) { - return BadAlloc; - } - pChc->pClient = pClient; - pChc->pScreen = pScreen; - pChc->hideCount = 1; - pChc->resource = FakeClientID(pClient->index); - pChc->pNext = cs->pCursorHideCounts; - cs->pCursorHideCounts = pChc; - - /* - * Create a resource for this element so it can be deleted - * when the client goes away. - */ - if (!AddResource (pChc->resource, CursorHideCountType, - (pointer) pChc)) { - xfree(pChc); - return BadAlloc; - } - - return Success; -} - -/* - * Delete the given hide-counts list element from its screen list. - */ -static void -deleteCursorHideCount (CursorHideCountPtr pChcToDel, ScreenPtr pScreen) -{ - CursorScreenPtr cs = GetCursorScreen(pScreen); - CursorHideCountPtr pChc, pNext; - CursorHideCountPtr pChcLast = NULL; - - pChc = cs->pCursorHideCounts; - while (pChc != NULL) { - pNext = pChc->pNext; - if (pChc == pChcToDel) { - xfree(pChc); - if (pChcLast == NULL) { - cs->pCursorHideCounts = pNext; - } else { - pChcLast->pNext = pNext; - } - return; - } - pChcLast = pChc; - pChc = pNext; - } -} - -/* - * Delete all the hide-counts list elements for this screen. - */ -static void -deleteCursorHideCountsForScreen (ScreenPtr pScreen) -{ - CursorScreenPtr cs = GetCursorScreen(pScreen); - CursorHideCountPtr pChc, pTmp; - - pChc = cs->pCursorHideCounts; - while (pChc != NULL) { - pTmp = pChc->pNext; - FreeResource(pChc->resource, 0); - pChc = pTmp; - } - cs->pCursorHideCounts = NULL; -} - -int -ProcXFixesHideCursor (ClientPtr client) -{ - WindowPtr pWin; - CursorHideCountPtr pChc; - REQUEST(xXFixesHideCursorReq); - int ret; - - REQUEST_SIZE_MATCH (xXFixesHideCursorReq); - - ret = dixLookupResourceByType((pointer *)&pWin, stuff->window, RT_WINDOW, - client, DixGetAttrAccess); - if (ret != Success) { - client->errorValue = stuff->window; - return (ret == BadValue) ? BadWindow : ret; - } - - /* - * Has client hidden the cursor before on this screen? - * If so, just increment the count. - */ - - pChc = findCursorHideCount(client, pWin->drawable.pScreen); - if (pChc != NULL) { - pChc->hideCount++; - return client->noClientException; - } - - /* - * This is the first time this client has hid the cursor - * for this screen. - */ - ret = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, - DixHideAccess); - if (ret != Success) - return ret; - - ret = createCursorHideCount(client, pWin->drawable.pScreen); - - if (ret == Success) { - DeviceIntPtr dev; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (IsMaster(dev) && IsPointerDevice(dev)) - CursorDisplayCursor(dev, pWin->drawable.pScreen, CursorCurrent[dev->id]); - } - } - - return ret; -} - -int -SProcXFixesHideCursor (ClientPtr client) -{ - int n; - REQUEST(xXFixesHideCursorReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH (xXFixesHideCursorReq); - swapl (&stuff->window, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -int -ProcXFixesShowCursor (ClientPtr client) -{ - WindowPtr pWin; - CursorHideCountPtr pChc; - int rc; - REQUEST(xXFixesShowCursorReq); - - REQUEST_SIZE_MATCH (xXFixesShowCursorReq); - - rc = dixLookupResourceByType((pointer *)&pWin, stuff->window, RT_WINDOW, - client, DixGetAttrAccess); - if (rc != Success) { - client->errorValue = stuff->window; - return (rc == BadValue) ? BadWindow : rc; - } - - /* - * Has client hidden the cursor on this screen? - * If not, generate an error. - */ - pChc = findCursorHideCount(client, pWin->drawable.pScreen); - if (pChc == NULL) { - return BadMatch; - } - - rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, - DixShowAccess); - if (rc != Success) - return rc; - - pChc->hideCount--; - if (pChc->hideCount <= 0) { - FreeResource(pChc->resource, 0); - } - - return (client->noClientException); -} - -int -SProcXFixesShowCursor (ClientPtr client) -{ - int n; - REQUEST(xXFixesShowCursorReq); - - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH (xXFixesShowCursorReq); - swapl (&stuff->window, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -static int -CursorFreeClient (pointer data, XID id) -{ - CursorEventPtr old = (CursorEventPtr) data; - CursorEventPtr *prev, e; - - for (prev = &cursorEvents; (e = *prev); prev = &e->next) - { - if (e == old) - { - *prev = e->next; - xfree (e); - break; - } - } - return 1; -} - -static int -CursorFreeHideCount (pointer data, XID id) -{ - CursorHideCountPtr pChc = (CursorHideCountPtr) data; - ScreenPtr pScreen = pChc->pScreen; - DeviceIntPtr dev; - - deleteCursorHideCount(pChc, pChc->pScreen); - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (IsMaster(dev) && IsPointerDevice(dev)) - CursorDisplayCursor(dev, pScreen, CursorCurrent[dev->id]); - } - - return 1; -} - -static int -CursorFreeWindow (pointer data, XID id) -{ - WindowPtr pWindow = (WindowPtr) data; - CursorEventPtr e, next; - - for (e = cursorEvents; e; e = next) - { - next = e->next; - if (e->pWindow == pWindow) - { - FreeResource (e->clientResource, 0); - } - } - return 1; -} - -static CursorPtr -createInvisibleCursor (void) -{ - CursorPtr pCursor; - unsigned char *psrcbits, *pmaskbits; - CursorMetricRec cm; - - psrcbits = (unsigned char *) xcalloc(4, 1); - pmaskbits = (unsigned char *) xcalloc(4, 1); - if (psrcbits == NULL || pmaskbits == NULL) { - return NULL; - } - - cm.width = 1; - cm.height = 1; - cm.xhot = 0; - cm.yhot = 0; - - if (AllocARGBCursor(psrcbits, pmaskbits, - NULL, &cm, - 0, 0, 0, - 0, 0, 0, - &pCursor, serverClient, (XID)0) != Success) - return NullCursor; - - if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer) pCursor)) - return NullCursor; - - return pCursor; -} - -Bool -XFixesCursorInit (void) -{ - int i; - - if (party_like_its_1989) - CursorVisible = EnableCursor; - - for (i = 0; i < screenInfo.numScreens; i++) - { - ScreenPtr pScreen = screenInfo.screens[i]; - CursorScreenPtr cs; - - cs = (CursorScreenPtr) xalloc (sizeof (CursorScreenRec)); - if (!cs) - return FALSE; - Wrap (cs, pScreen, CloseScreen, CursorCloseScreen); - Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor); - cs->pCursorHideCounts = NULL; - SetCursorScreen (pScreen, cs); - } - CursorClientType = CreateNewResourceType(CursorFreeClient, - "XFixesCursorClient"); - CursorHideCountType = CreateNewResourceType(CursorFreeHideCount, - "XFixesCursorHideCount"); - CursorWindowType = CreateNewResourceType(CursorFreeWindow, - "XFixesCursorWindow"); - - pInvisibleCursor = createInvisibleCursor(); - if (pInvisibleCursor == NULL) - return BadAlloc; - - return CursorClientType && CursorHideCountType && CursorWindowType; -} - +/* + * Copyright © 2006 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, 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. + * + * 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 <dix-config.h> +#endif + +#include "xfixesint.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "dixevents.h" +#include "servermd.h" +#include "inputstr.h" +#include "windowstr.h" +#include "xace.h" + +static RESTYPE CursorClientType; +static RESTYPE CursorHideCountType; +static RESTYPE CursorWindowType; +static CursorPtr CursorCurrent[MAXDEVICES]; +static CursorPtr pInvisibleCursor = NULL; + +static int CursorScreenPrivateKeyIndex; +static DevPrivateKey CursorScreenPrivateKey = &CursorScreenPrivateKeyIndex; + +static void deleteCursorHideCountsForScreen (ScreenPtr pScreen); + +#define VERIFY_CURSOR(pCursor, cursor, client, access) \ + do { \ + int err; \ + err = dixLookupResourceByType((pointer *) &pCursor, cursor, \ + RT_CURSOR, client, access); \ + if (err == BadValue) { \ + client->errorValue = cursor; \ + return BadCursor; \ + } else if (err != Success) { \ + client->errorValue = cursor; \ + return err; \ + } \ + } while (0) + +/* + * There is a global list of windows selecting for cursor events + */ + +typedef struct _CursorEvent *CursorEventPtr; + +typedef struct _CursorEvent { + CursorEventPtr next; + CARD32 eventMask; + ClientPtr pClient; + WindowPtr pWindow; + XID clientResource; +} CursorEventRec; + +static CursorEventPtr cursorEvents; + +/* + * Each screen has a list of clients which have requested + * that the cursor be hid, and the number of times each + * client has requested. +*/ + +typedef struct _CursorHideCountRec *CursorHideCountPtr; + +typedef struct _CursorHideCountRec { + CursorHideCountPtr pNext; + ClientPtr pClient; + ScreenPtr pScreen; + int hideCount; + XID resource; +} CursorHideCountRec; + +/* + * Wrap DisplayCursor to catch cursor change events + */ + +typedef struct _CursorScreen { + DisplayCursorProcPtr DisplayCursor; + CloseScreenProcPtr CloseScreen; + CursorHideCountPtr pCursorHideCounts; +} CursorScreenRec, *CursorScreenPtr; + +#define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey)) +#define GetCursorScreenIfSet(s) GetCursorScreen(s) +#define SetCursorScreen(s,p) dixSetPrivate(&(s)->devPrivates, CursorScreenPrivateKey, p) +#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) +#define Unwrap(as,s,elt,backup) (((backup) = (s)->elt), (s)->elt = (as)->elt) + +/* The cursor doesn't show up until the first XDefineCursor() */ +static Bool CursorVisible = FALSE; + +Bool EnableCursor = TRUE; + +static Bool +CursorDisplayCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) +{ + CursorScreenPtr cs = GetCursorScreen(pScreen); + Bool ret; + DisplayCursorProcPtr backupProc; + + Unwrap (cs, pScreen, DisplayCursor, backupProc); + + /* + * Have to check ConnectionInfo to distinguish client requests from + * initial root window setup. Not a great way to do it, I admit. + */ + if (ConnectionInfo) + CursorVisible = EnableCursor; + + if (cs->pCursorHideCounts != NULL || !CursorVisible) { + ret = ((*pScreen->RealizeCursor)(pDev, pScreen, pInvisibleCursor) && + (*pScreen->DisplayCursor) (pDev, pScreen, pInvisibleCursor)); + } else { + ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); + } + + if (pCursor != CursorCurrent[pDev->id]) + { + CursorEventPtr e; + + CursorCurrent[pDev->id] = pCursor; + for (e = cursorEvents; e; e = e->next) + { + if ((e->eventMask & XFixesDisplayCursorNotifyMask) && + !e->pClient->clientGone) + { + xXFixesCursorNotifyEvent ev; + ev.type = XFixesEventBase + XFixesCursorNotify; + ev.subtype = XFixesDisplayCursorNotify; + ev.sequenceNumber = e->pClient->sequence; + ev.window = e->pWindow->drawable.id; + ev.cursorSerial = pCursor->serialNumber; + ev.timestamp = currentTime.milliseconds; + ev.name = pCursor->name; + WriteEventsToClient (e->pClient, 1, (xEvent *) &ev); + } + } + } + Wrap (cs, pScreen, DisplayCursor, backupProc); + + return ret; +} + +static Bool +CursorCloseScreen (int index, ScreenPtr pScreen) +{ + CursorScreenPtr cs = GetCursorScreen (pScreen); + Bool ret; + CloseScreenProcPtr close_proc; + DisplayCursorProcPtr display_proc; + + Unwrap (cs, pScreen, CloseScreen, close_proc); + Unwrap (cs, pScreen, DisplayCursor, display_proc); + deleteCursorHideCountsForScreen(pScreen); + ret = (*pScreen->CloseScreen) (index, pScreen); + free(cs); + return ret; +} + +#define CursorAllEvents (XFixesDisplayCursorNotifyMask) + +static int +XFixesSelectCursorInput (ClientPtr pClient, + WindowPtr pWindow, + CARD32 eventMask) +{ + CursorEventPtr *prev, e; + pointer val; + int rc; + + for (prev = &cursorEvents; (e = *prev); prev = &e->next) + { + if (e->pClient == pClient && + e->pWindow == pWindow) + { + break; + } + } + if (!eventMask) + { + if (e) + { + FreeResource (e->clientResource, 0); + } + return Success; + } + if (!e) + { + e = (CursorEventPtr) malloc(sizeof (CursorEventRec)); + if (!e) + return BadAlloc; + + e->next = 0; + e->pClient = pClient; + e->pWindow = pWindow; + e->clientResource = FakeClientID(pClient->index); + + /* + * Add a resource hanging from the window to + * catch window destroy + */ + rc = dixLookupResourceByType( &val, pWindow->drawable.id, + CursorWindowType, serverClient, + DixGetAttrAccess); + if (rc != Success) + if (!AddResource (pWindow->drawable.id, CursorWindowType, + (pointer) pWindow)) + { + free(e); + return BadAlloc; + } + + if (!AddResource (e->clientResource, CursorClientType, (pointer) e)) + return BadAlloc; + + *prev = e; + } + e->eventMask = eventMask; + return Success; +} + +int +ProcXFixesSelectCursorInput (ClientPtr client) +{ + REQUEST (xXFixesSelectCursorInputReq); + WindowPtr pWin; + int rc; + + REQUEST_SIZE_MATCH (xXFixesSelectCursorInputReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + if (stuff->eventMask & ~CursorAllEvents) + { + client->errorValue = stuff->eventMask; + return( BadValue ); + } + return XFixesSelectCursorInput (client, pWin, stuff->eventMask); +} + +static int +GetBit (unsigned char *line, int x) +{ + unsigned char mask; + + if (screenInfo.bitmapBitOrder == LSBFirst) + mask = (1 << (x & 7)); + else + mask = (0x80 >> (x & 7)); + /* XXX assumes byte order is host byte order */ + line += (x >> 3); + if (*line & mask) + return 1; + return 0; +} + +int +SProcXFixesSelectCursorInput (ClientPtr client) +{ + register int n; + REQUEST(xXFixesSelectCursorInputReq); + + swaps(&stuff->length, n); + swapl(&stuff->window, n); + swapl(&stuff->eventMask, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +void +SXFixesCursorNotifyEvent (xXFixesCursorNotifyEvent *from, + xXFixesCursorNotifyEvent *to) +{ + to->type = from->type; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->window, to->window); + cpswapl (from->cursorSerial, to->cursorSerial); + cpswapl (from->timestamp, to->timestamp); + cpswapl (from->name, to->name); +} + +static void +CopyCursorToImage (CursorPtr pCursor, CARD32 *image) +{ + int width = pCursor->bits->width; + int height = pCursor->bits->height; + int npixels = width * height; + +#ifdef ARGB_CURSOR + if (pCursor->bits->argb) + memcpy (image, pCursor->bits->argb, npixels * sizeof (CARD32)); + else +#endif + { + unsigned char *srcLine = pCursor->bits->source; + unsigned char *mskLine = pCursor->bits->mask; + int stride = BitmapBytePad (width); + int x, y; + CARD32 fg, bg; + + fg = (0xff000000 | + ((pCursor->foreRed & 0xff00) << 8) | + (pCursor->foreGreen & 0xff00) | + (pCursor->foreBlue >> 8)); + bg = (0xff000000 | + ((pCursor->backRed & 0xff00) << 8) | + (pCursor->backGreen & 0xff00) | + (pCursor->backBlue >> 8)); + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + if (GetBit (mskLine, x)) + { + if (GetBit (srcLine, x)) + *image++ = fg; + else + *image++ = bg; + } + else + *image++ = 0; + } + srcLine += stride; + mskLine += stride; + } + } +} + +int +ProcXFixesGetCursorImage (ClientPtr client) +{ +/* REQUEST(xXFixesGetCursorImageReq); */ + xXFixesGetCursorImageReply *rep; + CursorPtr pCursor; + CARD32 *image; + int npixels, width, height, rc, x, y; + + REQUEST_SIZE_MATCH(xXFixesGetCursorImageReq); + pCursor = CursorCurrent[PickPointer(client)->id]; + if (!pCursor) + return BadCursor; + rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, + pCursor, RT_NONE, NULL, DixReadAccess); + if (rc != Success) + return rc; + GetSpritePosition (PickPointer(client), &x, &y); + width = pCursor->bits->width; + height = pCursor->bits->height; + npixels = width * height; + rep = malloc(sizeof (xXFixesGetCursorImageReply) + + npixels * sizeof (CARD32)); + if (!rep) + return BadAlloc; + + rep->type = X_Reply; + rep->sequenceNumber = client->sequence; + rep->length = npixels; + rep->width = width; + rep->height = height; + rep->x = x; + rep->y = y; + rep->xhot = pCursor->bits->xhot; + rep->yhot = pCursor->bits->yhot; + rep->cursorSerial = pCursor->serialNumber; + + image = (CARD32 *) (rep + 1); + CopyCursorToImage (pCursor, image); + if (client->swapped) + { + int n; + swaps (&rep->sequenceNumber, n); + swapl (&rep->length, n); + swaps (&rep->x, n); + swaps (&rep->y, n); + swaps (&rep->width, n); + swaps (&rep->height, n); + swaps (&rep->xhot, n); + swaps (&rep->yhot, n); + swapl (&rep->cursorSerial, n); + SwapLongs (image, npixels); + } + WriteToClient(client, sizeof (xXFixesGetCursorImageReply) + + (npixels << 2), (char *) rep); + free(rep); + return Success; +} + +int +SProcXFixesGetCursorImage (ClientPtr client) +{ + int n; + REQUEST(xXFixesGetCursorImageReq); + swaps (&stuff->length, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesSetCursorName (ClientPtr client) +{ + CursorPtr pCursor; + char *tchar; + REQUEST(xXFixesSetCursorNameReq); + Atom atom; + + REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); + VERIFY_CURSOR(pCursor, stuff->cursor, client, DixSetAttrAccess); + tchar = (char *) &stuff[1]; + atom = MakeAtom (tchar, stuff->nbytes, TRUE); + if (atom == BAD_RESOURCE) + return BadAlloc; + + pCursor->name = atom; + return Success; +} + +int +SProcXFixesSetCursorName (ClientPtr client) +{ + int n; + REQUEST(xXFixesSetCursorNameReq); + + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); + swapl (&stuff->cursor, n); + swaps (&stuff->nbytes, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesGetCursorName (ClientPtr client) +{ + CursorPtr pCursor; + xXFixesGetCursorNameReply reply; + REQUEST(xXFixesGetCursorNameReq); + const char *str; + int len; + + REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); + VERIFY_CURSOR(pCursor, stuff->cursor, client, DixGetAttrAccess); + if (pCursor->name) + str = NameForAtom (pCursor->name); + else + str = ""; + len = strlen (str); + + reply.type = X_Reply; + reply.length = bytes_to_int32(len); + reply.sequenceNumber = client->sequence; + reply.atom = pCursor->name; + reply.nbytes = len; + if (client->swapped) + { + int n; + swaps (&reply.sequenceNumber, n); + swapl (&reply.length, n); + swapl (&reply.atom, n); + swaps (&reply.nbytes, n); + } + WriteReplyToClient(client, sizeof(xXFixesGetCursorNameReply), &reply); + WriteToClient(client, len, str); + + return Success; +} + +int +SProcXFixesGetCursorName (ClientPtr client) +{ + int n; + REQUEST(xXFixesGetCursorNameReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); + swapl (&stuff->cursor, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesGetCursorImageAndName (ClientPtr client) +{ +/* REQUEST(xXFixesGetCursorImageAndNameReq); */ + xXFixesGetCursorImageAndNameReply *rep; + CursorPtr pCursor; + CARD32 *image; + int npixels; + const char *name; + int nbytes, nbytesRound; + int width, height; + int rc, x, y; + + REQUEST_SIZE_MATCH(xXFixesGetCursorImageAndNameReq); + pCursor = CursorCurrent[PickPointer(client)->id]; + if (!pCursor) + return BadCursor; + rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, + pCursor, RT_NONE, NULL, DixReadAccess|DixGetAttrAccess); + if (rc != Success) + return rc; + GetSpritePosition (PickPointer(client), &x, &y); + width = pCursor->bits->width; + height = pCursor->bits->height; + npixels = width * height; + name = pCursor->name ? NameForAtom (pCursor->name) : ""; + nbytes = strlen (name); + nbytesRound = pad_to_int32(nbytes); + rep = malloc(sizeof (xXFixesGetCursorImageAndNameReply) + + npixels * sizeof (CARD32) + nbytesRound); + if (!rep) + return BadAlloc; + + rep->type = X_Reply; + rep->sequenceNumber = client->sequence; + rep->length = npixels + bytes_to_int32(nbytesRound); + rep->width = width; + rep->height = height; + rep->x = x; + rep->y = y; + rep->xhot = pCursor->bits->xhot; + rep->yhot = pCursor->bits->yhot; + rep->cursorSerial = pCursor->serialNumber; + rep->cursorName = pCursor->name; + rep->nbytes = nbytes; + + image = (CARD32 *) (rep + 1); + CopyCursorToImage (pCursor, image); + memcpy ((image + npixels), name, nbytes); + if (client->swapped) + { + int n; + swaps (&rep->sequenceNumber, n); + swapl (&rep->length, n); + swaps (&rep->x, n); + swaps (&rep->y, n); + swaps (&rep->width, n); + swaps (&rep->height, n); + swaps (&rep->xhot, n); + swaps (&rep->yhot, n); + swapl (&rep->cursorSerial, n); + swapl (&rep->cursorName, n); + swaps (&rep->nbytes, n); + SwapLongs (image, npixels); + } + WriteToClient(client, sizeof (xXFixesGetCursorImageAndNameReply) + + (npixels << 2) + nbytesRound, (char *) rep); + free(rep); + return Success; +} + +int +SProcXFixesGetCursorImageAndName (ClientPtr client) +{ + int n; + REQUEST(xXFixesGetCursorImageAndNameReq); + swaps (&stuff->length, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +/* + * Find every cursor reference in the system, ask testCursor + * whether it should be replaced with a reference to pCursor. + */ + +typedef Bool (*TestCursorFunc) (CursorPtr pOld, pointer closure); + +typedef struct { + RESTYPE type; + TestCursorFunc testCursor; + CursorPtr pNew; + pointer closure; +} ReplaceCursorLookupRec, *ReplaceCursorLookupPtr; + +static const RESTYPE CursorRestypes[] = { + RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR +}; + +#define NUM_CURSOR_RESTYPES (sizeof (CursorRestypes) / sizeof (CursorRestypes[0])) + +static Bool +ReplaceCursorLookup (pointer value, XID id, pointer closure) +{ + ReplaceCursorLookupPtr rcl = (ReplaceCursorLookupPtr) closure; + WindowPtr pWin; + GrabPtr pGrab; + CursorPtr pCursor = 0, *pCursorRef = 0; + XID cursor = 0; + + switch (rcl->type) { + case RT_WINDOW: + pWin = (WindowPtr) value; + if (pWin->optional) + { + pCursorRef = &pWin->optional->cursor; + pCursor = *pCursorRef; + } + break; + case RT_PASSIVEGRAB: + pGrab = (GrabPtr) value; + pCursorRef = &pGrab->cursor; + pCursor = *pCursorRef; + break; + case RT_CURSOR: + pCursorRef = 0; + pCursor = (CursorPtr) value; + cursor = id; + break; + } + if (pCursor && pCursor != rcl->pNew) + { + if ((*rcl->testCursor) (pCursor, rcl->closure)) + { + rcl->pNew->refcnt++; + /* either redirect reference or update resource database */ + if (pCursorRef) + *pCursorRef = rcl->pNew; + else + ChangeResourceValue (id, RT_CURSOR, rcl->pNew); + FreeCursor (pCursor, cursor); + } + } + return FALSE; /* keep walking */ +} + +static void +ReplaceCursor (CursorPtr pCursor, + TestCursorFunc testCursor, + pointer closure) +{ + int clientIndex; + int resIndex; + ReplaceCursorLookupRec rcl; + + /* + * Cursors exist only in the resource database, windows and grabs. + * All of these are always pointed at by the resource database. Walk + * the whole thing looking for cursors + */ + rcl.testCursor = testCursor; + rcl.pNew = pCursor; + rcl.closure = closure; + + /* for each client */ + for (clientIndex = 0; clientIndex < currentMaxClients; clientIndex++) + { + if (!clients[clientIndex]) + continue; + for (resIndex = 0; resIndex < NUM_CURSOR_RESTYPES; resIndex++) + { + rcl.type = CursorRestypes[resIndex]; + /* + * This function walks the entire client resource database + */ + LookupClientResourceComplex (clients[clientIndex], + rcl.type, + ReplaceCursorLookup, + (pointer) &rcl); + } + } + /* this "knows" that WindowHasNewCursor doesn't depend on it's argument */ + WindowHasNewCursor (WindowTable[0]); +} + +static Bool +TestForCursor (CursorPtr pCursor, pointer closure) +{ + return (pCursor == (CursorPtr) closure); +} + +int +ProcXFixesChangeCursor (ClientPtr client) +{ + CursorPtr pSource, pDestination; + REQUEST(xXFixesChangeCursorReq); + + REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); + VERIFY_CURSOR (pSource, stuff->source, client, + DixReadAccess|DixGetAttrAccess); + VERIFY_CURSOR (pDestination, stuff->destination, client, + DixWriteAccess|DixSetAttrAccess); + + ReplaceCursor (pSource, TestForCursor, (pointer) pDestination); + return Success; +} + +int +SProcXFixesChangeCursor (ClientPtr client) +{ + int n; + REQUEST(xXFixesChangeCursorReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); + swapl (&stuff->source, n); + swapl (&stuff->destination, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +static Bool +TestForCursorName (CursorPtr pCursor, pointer closure) +{ + Atom *pName = closure; + return (pCursor->name == *pName); +} + +int +ProcXFixesChangeCursorByName (ClientPtr client) +{ + CursorPtr pSource; + Atom name; + char *tchar; + REQUEST(xXFixesChangeCursorByNameReq); + + REQUEST_FIXED_SIZE(xXFixesChangeCursorByNameReq, stuff->nbytes); + VERIFY_CURSOR(pSource, stuff->source, client, + DixReadAccess|DixGetAttrAccess); + tchar = (char *) &stuff[1]; + name = MakeAtom (tchar, stuff->nbytes, FALSE); + if (name) + ReplaceCursor (pSource, TestForCursorName, &name); + return Success; +} + +int +SProcXFixesChangeCursorByName (ClientPtr client) +{ + int n; + REQUEST(xXFixesChangeCursorByNameReq); + + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE (xXFixesChangeCursorByNameReq); + swapl (&stuff->source, n); + swaps (&stuff->nbytes, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +/* + * Routines for manipulating the per-screen hide counts list. + * This list indicates which clients have requested cursor hiding + * for that screen. + */ + +/* Return the screen's hide-counts list element for the given client */ +static CursorHideCountPtr +findCursorHideCount (ClientPtr pClient, ScreenPtr pScreen) +{ + CursorScreenPtr cs = GetCursorScreen(pScreen); + CursorHideCountPtr pChc; + + for (pChc = cs->pCursorHideCounts; pChc != NULL; pChc = pChc->pNext) { + if (pChc->pClient == pClient) { + return pChc; + } + } + + return NULL; +} + +static int +createCursorHideCount (ClientPtr pClient, ScreenPtr pScreen) +{ + CursorScreenPtr cs = GetCursorScreen(pScreen); + CursorHideCountPtr pChc; + + pChc = (CursorHideCountPtr) malloc(sizeof(CursorHideCountRec)); + if (pChc == NULL) { + return BadAlloc; + } + pChc->pClient = pClient; + pChc->pScreen = pScreen; + pChc->hideCount = 1; + pChc->resource = FakeClientID(pClient->index); + pChc->pNext = cs->pCursorHideCounts; + cs->pCursorHideCounts = pChc; + + /* + * Create a resource for this element so it can be deleted + * when the client goes away. + */ + if (!AddResource (pChc->resource, CursorHideCountType, + (pointer) pChc)) { + free(pChc); + return BadAlloc; + } + + return Success; +} + +/* + * Delete the given hide-counts list element from its screen list. + */ +static void +deleteCursorHideCount (CursorHideCountPtr pChcToDel, ScreenPtr pScreen) +{ + CursorScreenPtr cs = GetCursorScreen(pScreen); + CursorHideCountPtr pChc, pNext; + CursorHideCountPtr pChcLast = NULL; + + pChc = cs->pCursorHideCounts; + while (pChc != NULL) { + pNext = pChc->pNext; + if (pChc == pChcToDel) { + free(pChc); + if (pChcLast == NULL) { + cs->pCursorHideCounts = pNext; + } else { + pChcLast->pNext = pNext; + } + return; + } + pChcLast = pChc; + pChc = pNext; + } +} + +/* + * Delete all the hide-counts list elements for this screen. + */ +static void +deleteCursorHideCountsForScreen (ScreenPtr pScreen) +{ + CursorScreenPtr cs = GetCursorScreen(pScreen); + CursorHideCountPtr pChc, pTmp; + + pChc = cs->pCursorHideCounts; + while (pChc != NULL) { + pTmp = pChc->pNext; + FreeResource(pChc->resource, 0); + pChc = pTmp; + } + cs->pCursorHideCounts = NULL; +} + +int +ProcXFixesHideCursor (ClientPtr client) +{ + WindowPtr pWin; + CursorHideCountPtr pChc; + REQUEST(xXFixesHideCursorReq); + int ret; + + REQUEST_SIZE_MATCH (xXFixesHideCursorReq); + + ret = dixLookupResourceByType((pointer *)&pWin, stuff->window, RT_WINDOW, + client, DixGetAttrAccess); + if (ret != Success) { + client->errorValue = stuff->window; + return (ret == BadValue) ? BadWindow : ret; + } + + /* + * Has client hidden the cursor before on this screen? + * If so, just increment the count. + */ + + pChc = findCursorHideCount(client, pWin->drawable.pScreen); + if (pChc != NULL) { + pChc->hideCount++; + return Success; + } + + /* + * This is the first time this client has hid the cursor + * for this screen. + */ + ret = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, + DixHideAccess); + if (ret != Success) + return ret; + + ret = createCursorHideCount(client, pWin->drawable.pScreen); + + if (ret == Success) { + DeviceIntPtr dev; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (IsMaster(dev) && IsPointerDevice(dev)) + CursorDisplayCursor(dev, pWin->drawable.pScreen, CursorCurrent[dev->id]); + } + } + + return ret; +} + +int +SProcXFixesHideCursor (ClientPtr client) +{ + int n; + REQUEST(xXFixesHideCursorReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xXFixesHideCursorReq); + swapl (&stuff->window, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesShowCursor (ClientPtr client) +{ + WindowPtr pWin; + CursorHideCountPtr pChc; + int rc; + REQUEST(xXFixesShowCursorReq); + + REQUEST_SIZE_MATCH (xXFixesShowCursorReq); + + rc = dixLookupResourceByType((pointer *)&pWin, stuff->window, RT_WINDOW, + client, DixGetAttrAccess); + if (rc != Success) { + client->errorValue = stuff->window; + return (rc == BadValue) ? BadWindow : rc; + } + + /* + * Has client hidden the cursor on this screen? + * If not, generate an error. + */ + pChc = findCursorHideCount(client, pWin->drawable.pScreen); + if (pChc == NULL) { + return BadMatch; + } + + rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, + DixShowAccess); + if (rc != Success) + return rc; + + pChc->hideCount--; + if (pChc->hideCount <= 0) { + FreeResource(pChc->resource, 0); + } + + return Success; +} + +int +SProcXFixesShowCursor (ClientPtr client) +{ + int n; + REQUEST(xXFixesShowCursorReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xXFixesShowCursorReq); + swapl (&stuff->window, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +static int +CursorFreeClient (pointer data, XID id) +{ + CursorEventPtr old = (CursorEventPtr) data; + CursorEventPtr *prev, e; + + for (prev = &cursorEvents; (e = *prev); prev = &e->next) + { + if (e == old) + { + *prev = e->next; + free(e); + break; + } + } + return 1; +} + +static int +CursorFreeHideCount (pointer data, XID id) +{ + CursorHideCountPtr pChc = (CursorHideCountPtr) data; + ScreenPtr pScreen = pChc->pScreen; + DeviceIntPtr dev; + + deleteCursorHideCount(pChc, pChc->pScreen); + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (IsMaster(dev) && IsPointerDevice(dev)) + CursorDisplayCursor(dev, pScreen, CursorCurrent[dev->id]); + } + + return 1; +} + +static int +CursorFreeWindow (pointer data, XID id) +{ + WindowPtr pWindow = (WindowPtr) data; + CursorEventPtr e, next; + + for (e = cursorEvents; e; e = next) + { + next = e->next; + if (e->pWindow == pWindow) + { + FreeResource (e->clientResource, 0); + } + } + return 1; +} + +static CursorPtr +createInvisibleCursor (void) +{ + CursorPtr pCursor; + unsigned char *psrcbits, *pmaskbits; + CursorMetricRec cm; + + psrcbits = (unsigned char *) calloc(4, 1); + pmaskbits = (unsigned char *) calloc(4, 1); + if (psrcbits == NULL || pmaskbits == NULL) { + return NULL; + } + + cm.width = 1; + cm.height = 1; + cm.xhot = 0; + cm.yhot = 0; + + if (AllocARGBCursor(psrcbits, pmaskbits, + NULL, &cm, + 0, 0, 0, + 0, 0, 0, + &pCursor, serverClient, (XID)0) != Success) + return NullCursor; + + if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer) pCursor)) + return NullCursor; + + return pCursor; +} + +Bool +XFixesCursorInit (void) +{ + int i; + + if (party_like_its_1989) + CursorVisible = EnableCursor; + + for (i = 0; i < screenInfo.numScreens; i++) + { + ScreenPtr pScreen = screenInfo.screens[i]; + CursorScreenPtr cs; + + cs = (CursorScreenPtr) malloc(sizeof (CursorScreenRec)); + if (!cs) + return FALSE; + Wrap (cs, pScreen, CloseScreen, CursorCloseScreen); + Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor); + cs->pCursorHideCounts = NULL; + SetCursorScreen (pScreen, cs); + } + CursorClientType = CreateNewResourceType(CursorFreeClient, + "XFixesCursorClient"); + CursorHideCountType = CreateNewResourceType(CursorFreeHideCount, + "XFixesCursorHideCount"); + CursorWindowType = CreateNewResourceType(CursorFreeWindow, + "XFixesCursorWindow"); + + pInvisibleCursor = createInvisibleCursor(); + if (pInvisibleCursor == NULL) + return BadAlloc; + + return CursorClientType && CursorHideCountType && CursorWindowType; +} + diff --git a/xorg-server/xfixes/region.c b/xorg-server/xfixes/region.c index dc050c9fc..2276ab8b6 100644 --- a/xorg-server/xfixes/region.c +++ b/xorg-server/xfixes/region.c @@ -87,7 +87,7 @@ ProcXFixesCreateRegion (ClientPtr client) if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) return BadAlloc; - return(client->noClientException); + return Success; } int @@ -132,7 +132,7 @@ ProcXFixesCreateRegionFromBitmap (ClientPtr client) if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) return BadAlloc; - return(client->noClientException); + return Success; } int @@ -194,7 +194,7 @@ ProcXFixesCreateRegionFromWindow (ClientPtr client) if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) return BadAlloc; - return(client->noClientException); + return Success; } int @@ -244,7 +244,7 @@ ProcXFixesCreateRegionFromGC (ClientPtr client) if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) return BadAlloc; - return(client->noClientException); + return Success; } int @@ -291,7 +291,7 @@ ProcXFixesCreateRegionFromPicture (ClientPtr client) if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) return BadAlloc; - return(client->noClientException); + return Success; } int @@ -316,7 +316,7 @@ ProcXFixesDestroyRegion (ClientPtr client) REQUEST_SIZE_MATCH(xXFixesDestroyRegionReq); VERIFY_REGION(pRegion, stuff->region, client, DixWriteAccess); FreeResource (stuff->region, RT_NONE); - return(client->noClientException); + return Success; } int @@ -355,7 +355,7 @@ ProcXFixesSetRegion (ClientPtr client) return BadAlloc; } REGION_DESTROY (0, pNew); - return(client->noClientException); + return Success; } int @@ -383,7 +383,7 @@ ProcXFixesCopyRegion (ClientPtr client) if (!REGION_COPY(pScreen, pDestination, pSource)) return BadAlloc; - return(client->noClientException); + return Success; } int @@ -403,7 +403,6 @@ int ProcXFixesCombineRegion (ClientPtr client) { RegionPtr pSource1, pSource2, pDestination; - int ret = Success; REQUEST (xXFixesCombineRegionReq); REQUEST_SIZE_MATCH (xXFixesCombineRegionReq); @@ -414,21 +413,19 @@ ProcXFixesCombineRegion (ClientPtr client) switch (stuff->xfixesReqType) { case X_XFixesUnionRegion: if (!REGION_UNION (0, pDestination, pSource1, pSource2)) - ret = BadAlloc; + return BadAlloc; break; case X_XFixesIntersectRegion: if (!REGION_INTERSECT (0, pDestination, pSource1, pSource2)) - ret = BadAlloc; + return BadAlloc; break; case X_XFixesSubtractRegion: if (!REGION_SUBTRACT (0, pDestination, pSource1, pSource2)) - ret = BadAlloc; + return BadAlloc; break; } - if (ret == Success) - ret = client->noClientException; - return ret; + return Success; } int @@ -450,7 +447,6 @@ ProcXFixesInvertRegion (ClientPtr client) { RegionPtr pSource, pDestination; BoxRec bounds; - int ret = Success; REQUEST(xXFixesInvertRegionReq); REQUEST_SIZE_MATCH(xXFixesInvertRegionReq); @@ -471,11 +467,9 @@ ProcXFixesInvertRegion (ClientPtr client) bounds.y2 = stuff->y + stuff->height; if (!REGION_INVERSE(0, pDestination, pSource, &bounds)) - ret = BadAlloc; + return BadAlloc; - if (ret == Success) - ret = client->noClientException; - return ret; + return Success; } int @@ -505,7 +499,7 @@ ProcXFixesTranslateRegion (ClientPtr client) VERIFY_REGION(pRegion, stuff->region, client, DixWriteAccess); REGION_TRANSLATE(pScreen, pRegion, stuff->dx, stuff->dy); - return (client->noClientException); + return Success; } int @@ -534,7 +528,7 @@ ProcXFixesRegionExtents (ClientPtr client) REGION_RESET (0, pDestination, REGION_EXTENTS (0, pSource)); - return (client->noClientException); + return Success; } int @@ -568,7 +562,7 @@ ProcXFixesFetchRegion (ClientPtr client) pBox = REGION_RECTS (pRegion); nBox = REGION_NUM_RECTS (pRegion); - reply = xalloc (sizeof (xXFixesFetchRegionReply) + + reply = malloc(sizeof (xXFixesFetchRegionReply) + nBox * sizeof (xRectangle)); if (!reply) return BadAlloc; @@ -601,8 +595,8 @@ ProcXFixesFetchRegion (ClientPtr client) } (void) WriteToClient(client, sizeof (xXFixesFetchRegionReply) + nBox * sizeof (xRectangle), (char *) reply); - xfree (reply); - return (client->noClientException); + free(reply); + return Success; } int @@ -622,7 +616,7 @@ ProcXFixesSetGCClipRegion (ClientPtr client) { GCPtr pGC; RegionPtr pRegion; - XID vals[2]; + ChangeGCVal vals[2]; int rc; REQUEST(xXFixesSetGCClipRegionReq); REQUEST_SIZE_MATCH(xXFixesSetGCClipRegionReq); @@ -640,12 +634,12 @@ ProcXFixesSetGCClipRegion (ClientPtr client) return BadAlloc; } - vals[0] = stuff->xOrigin; - vals[1] = stuff->yOrigin; - DoChangeGC (pGC, GCClipXOrigin|GCClipYOrigin, vals, 0); + vals[0].val = stuff->xOrigin; + vals[1].val = stuff->yOrigin; + ChangeGC (NullClient, pGC, GCClipXOrigin|GCClipYOrigin, vals); (*pGC->funcs->ChangeClip)(pGC, pRegion ? CT_REGION : CT_NONE, (pointer)pRegion, 0); - return (client->noClientException); + return Success; } int @@ -741,7 +735,7 @@ ProcXFixesSetWindowShapeRegion (ClientPtr client) *pDestRegion = pRegion; (*pScreen->SetShape) (pWin); SendShapeNotify (pWin, stuff->destKind); - return (client->noClientException); + return Success; } int @@ -797,7 +791,6 @@ int ProcXFixesExpandRegion (ClientPtr client) { RegionPtr pSource, pDestination; - int ret = Success; REQUEST (xXFixesExpandRegionReq); BoxPtr pTmp; BoxPtr pSrc; @@ -812,7 +805,7 @@ ProcXFixesExpandRegion (ClientPtr client) pSrc = REGION_RECTS(pSource); if (nBoxes) { - pTmp = xalloc (nBoxes * sizeof (BoxRec)); + pTmp = malloc(nBoxes * sizeof (BoxRec)); if (!pTmp) return BadAlloc; for (i = 0; i < nBoxes; i++) @@ -829,11 +822,9 @@ ProcXFixesExpandRegion (ClientPtr client) REGION_INIT (pScreen, &r, &pTmp[i], 0); REGION_UNION (pScreen, pDestination, pDestination, &r); } - xfree(pTmp); + free(pTmp); } - if (ret == Success) - ret = client->noClientException; - return ret; + return Success; } int diff --git a/xorg-server/xfixes/saveset.c b/xorg-server/xfixes/saveset.c index 29de0d8f2..72bbb4952 100644 --- a/xorg-server/xfixes/saveset.c +++ b/xorg-server/xfixes/saveset.c @@ -1,76 +1,72 @@ -/* - * 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 <dix-config.h> -#endif - -#include "xfixesint.h" - -int -ProcXFixesChangeSaveSet(ClientPtr client) -{ - Bool toRoot, map; - int result; - WindowPtr pWin; - REQUEST(xXFixesChangeSaveSetReq); - - REQUEST_SIZE_MATCH(xXFixesChangeSaveSetReq); - result = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); - if (result != Success) - return result; - if (client->clientAsMask == (CLIENT_BITS(pWin->drawable.id))) - return BadMatch; - if ((stuff->mode != SetModeInsert) && (stuff->mode != SetModeDelete)) - { - client->errorValue = stuff->mode; - return( BadValue ); - } - if ((stuff->target != SaveSetNearest) && (stuff->target != SaveSetRoot)) - { - client->errorValue = stuff->target; - return( BadValue ); - } - if ((stuff->map != SaveSetMap) && (stuff->map != SaveSetUnmap)) - { - client->errorValue = stuff->map; - return( BadValue ); - } - toRoot = (stuff->target == SaveSetRoot); - map = (stuff->map == SaveSetMap); - result = AlterSaveSetForClient(client, pWin, stuff->mode, toRoot, map); - if (client->noClientException != Success) - return(client->noClientException); - else - return(result); -} - -int -SProcXFixesChangeSaveSet(ClientPtr client) -{ - register int n; - REQUEST(xXFixesChangeSaveSetReq); - - swaps(&stuff->length, n); - swapl(&stuff->window, n); - return (*ProcXFixesVector[stuff->xfixesReqType])(client); -} +/* + * 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 <dix-config.h> +#endif + +#include "xfixesint.h" + +int +ProcXFixesChangeSaveSet(ClientPtr client) +{ + Bool toRoot, map; + int result; + WindowPtr pWin; + REQUEST(xXFixesChangeSaveSetReq); + + REQUEST_SIZE_MATCH(xXFixesChangeSaveSetReq); + result = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); + if (result != Success) + return result; + if (client->clientAsMask == (CLIENT_BITS(pWin->drawable.id))) + return BadMatch; + if ((stuff->mode != SetModeInsert) && (stuff->mode != SetModeDelete)) + { + client->errorValue = stuff->mode; + return( BadValue ); + } + if ((stuff->target != SaveSetNearest) && (stuff->target != SaveSetRoot)) + { + client->errorValue = stuff->target; + return( BadValue ); + } + if ((stuff->map != SaveSetMap) && (stuff->map != SaveSetUnmap)) + { + client->errorValue = stuff->map; + return( BadValue ); + } + toRoot = (stuff->target == SaveSetRoot); + map = (stuff->map == SaveSetMap); + return AlterSaveSetForClient(client, pWin, stuff->mode, toRoot, map); +} + +int +SProcXFixesChangeSaveSet(ClientPtr client) +{ + register int n; + REQUEST(xXFixesChangeSaveSetReq); + + swaps(&stuff->length, n); + swapl(&stuff->window, n); + return (*ProcXFixesVector[stuff->xfixesReqType])(client); +} diff --git a/xorg-server/xfixes/select.c b/xorg-server/xfixes/select.c index 5ba7896cb..044294ee1 100644 --- a/xorg-server/xfixes/select.c +++ b/xorg-server/xfixes/select.c @@ -1,292 +1,292 @@ -/* - * 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 <dix-config.h> -#endif - -#include "xfixesint.h" -#include "xace.h" - -static RESTYPE SelectionClientType, SelectionWindowType; -static Bool SelectionCallbackRegistered = FALSE; - -/* - * There is a global list of windows selecting for selection events - * on every selection. This should be plenty efficient for the - * expected usage, if it does become a problem, it should be easily - * replaced with a hash table of some kind keyed off the selection atom - */ - -typedef struct _SelectionEvent *SelectionEventPtr; - -typedef struct _SelectionEvent { - SelectionEventPtr next; - Atom selection; - CARD32 eventMask; - ClientPtr pClient; - WindowPtr pWindow; - XID clientResource; -} SelectionEventRec; - -static SelectionEventPtr selectionEvents; - -static void -XFixesSelectionCallback (CallbackListPtr *callbacks, pointer data, pointer args) -{ - SelectionEventPtr e; - SelectionInfoRec *info = (SelectionInfoRec *) args; - Selection *selection = info->selection; - int subtype; - CARD32 eventMask; - - switch (info->kind) { - case SelectionSetOwner: - subtype = XFixesSetSelectionOwnerNotify; - eventMask = XFixesSetSelectionOwnerNotifyMask; - break; - case SelectionWindowDestroy: - subtype = XFixesSelectionWindowDestroyNotify; - eventMask = XFixesSelectionWindowDestroyNotifyMask; - break; - case SelectionClientClose: - subtype = XFixesSelectionClientCloseNotify; - eventMask = XFixesSelectionClientCloseNotifyMask; - break; - default: - return; - } - for (e = selectionEvents; e; e = e->next) - { - if (e->selection == selection->selection && - (e->eventMask & eventMask) && - !e->pClient->clientGone) - { - xXFixesSelectionNotifyEvent ev; - - memset(&ev, 0, sizeof(xXFixesSelectionNotifyEvent)); - ev.type = XFixesEventBase + XFixesSelectionNotify; - ev.subtype = subtype; - ev.sequenceNumber = e->pClient->sequence; - ev.window = e->pWindow->drawable.id; - if (subtype == XFixesSetSelectionOwnerNotify) - ev.owner = selection->window; - else - ev.owner = 0; - ev.selection = e->selection; - ev.timestamp = currentTime.milliseconds; - ev.selectionTimestamp = selection->lastTimeChanged.milliseconds; - WriteEventsToClient (e->pClient, 1, (xEvent *) &ev); - } - } -} - -static Bool -CheckSelectionCallback (void) -{ - if (selectionEvents) - { - if (!SelectionCallbackRegistered) - { - if (!AddCallback (&SelectionCallback, XFixesSelectionCallback, NULL)) - return FALSE; - SelectionCallbackRegistered = TRUE; - } - } - else - { - if (SelectionCallbackRegistered) - { - DeleteCallback (&SelectionCallback, XFixesSelectionCallback, NULL); - SelectionCallbackRegistered = FALSE; - } - } - return TRUE; -} - -#define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\ - XFixesSelectionWindowDestroyNotifyMask |\ - XFixesSelectionClientCloseNotifyMask) - -static int -XFixesSelectSelectionInput (ClientPtr pClient, - Atom selection, - WindowPtr pWindow, - CARD32 eventMask) -{ - pointer val; - int rc; - SelectionEventPtr *prev, e; - - rc = XaceHook(XACE_SELECTION_ACCESS, pClient, selection, DixGetAttrAccess); - if (rc != Success) - return rc; - - for (prev = &selectionEvents; (e = *prev); prev = &e->next) - { - if (e->selection == selection && - e->pClient == pClient && - e->pWindow == pWindow) - { - break; - } - } - if (!eventMask) - { - if (e) - { - FreeResource (e->clientResource, 0); - } - return Success; - } - if (!e) - { - e = (SelectionEventPtr) xalloc (sizeof (SelectionEventRec)); - if (!e) - return BadAlloc; - - e->next = 0; - e->selection = selection; - e->pClient = pClient; - e->pWindow = pWindow; - e->clientResource = FakeClientID(pClient->index); - - /* - * Add a resource hanging from the window to - * catch window destroy - */ - rc = dixLookupResourceByType (&val, pWindow->drawable.id, - SelectionWindowType, serverClient, - DixGetAttrAccess); - if (rc != Success) - if (!AddResource (pWindow->drawable.id, SelectionWindowType, - (pointer) pWindow)) - { - xfree (e); - return BadAlloc; - } - - if (!AddResource (e->clientResource, SelectionClientType, (pointer) e)) - return BadAlloc; - - *prev = e; - if (!CheckSelectionCallback ()) - { - FreeResource (e->clientResource, 0); - return BadAlloc; - } - } - e->eventMask = eventMask; - return Success; -} - -int -ProcXFixesSelectSelectionInput (ClientPtr client) -{ - REQUEST (xXFixesSelectSelectionInputReq); - WindowPtr pWin; - int rc; - - REQUEST_SIZE_MATCH (xXFixesSelectSelectionInputReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - if (stuff->eventMask & ~SelectionAllEvents) - { - client->errorValue = stuff->eventMask; - return( BadValue ); - } - return XFixesSelectSelectionInput (client, stuff->selection, - pWin, stuff->eventMask); -} - -int -SProcXFixesSelectSelectionInput (ClientPtr client) -{ - register int n; - REQUEST(xXFixesSelectSelectionInputReq); - - swaps(&stuff->length, n); - swapl(&stuff->window, n); - swapl(&stuff->selection, n); - swapl(&stuff->eventMask, n); - return (*ProcXFixesVector[stuff->xfixesReqType])(client); -} - -void -SXFixesSelectionNotifyEvent (xXFixesSelectionNotifyEvent *from, - xXFixesSelectionNotifyEvent *to) -{ - to->type = from->type; - cpswaps (from->sequenceNumber, to->sequenceNumber); - cpswapl (from->window, to->window); - cpswapl (from->owner, to->owner); - cpswapl (from->selection, to->selection); - cpswapl (from->timestamp, to->timestamp); - cpswapl (from->selectionTimestamp, to->selectionTimestamp); -} - -static int -SelectionFreeClient (pointer data, XID id) -{ - SelectionEventPtr old = (SelectionEventPtr) data; - SelectionEventPtr *prev, e; - - for (prev = &selectionEvents; (e = *prev); prev = &e->next) - { - if (e == old) - { - *prev = e->next; - xfree (e); - CheckSelectionCallback (); - break; - } - } - return 1; -} - -static int -SelectionFreeWindow (pointer data, XID id) -{ - WindowPtr pWindow = (WindowPtr) data; - SelectionEventPtr e, next; - - for (e = selectionEvents; e; e = next) - { - next = e->next; - if (e->pWindow == pWindow) - { - FreeResource (e->clientResource, 0); - } - } - return 1; -} - -Bool -XFixesSelectionInit (void) -{ - SelectionClientType = CreateNewResourceType(SelectionFreeClient, - "XFixesSelectionClient"); - SelectionWindowType = CreateNewResourceType(SelectionFreeWindow, - "XFixesSelectionWindow"); - return SelectionClientType && SelectionWindowType; -} +/* + * 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 <dix-config.h> +#endif + +#include "xfixesint.h" +#include "xace.h" + +static RESTYPE SelectionClientType, SelectionWindowType; +static Bool SelectionCallbackRegistered = FALSE; + +/* + * There is a global list of windows selecting for selection events + * on every selection. This should be plenty efficient for the + * expected usage, if it does become a problem, it should be easily + * replaced with a hash table of some kind keyed off the selection atom + */ + +typedef struct _SelectionEvent *SelectionEventPtr; + +typedef struct _SelectionEvent { + SelectionEventPtr next; + Atom selection; + CARD32 eventMask; + ClientPtr pClient; + WindowPtr pWindow; + XID clientResource; +} SelectionEventRec; + +static SelectionEventPtr selectionEvents; + +static void +XFixesSelectionCallback (CallbackListPtr *callbacks, pointer data, pointer args) +{ + SelectionEventPtr e; + SelectionInfoRec *info = (SelectionInfoRec *) args; + Selection *selection = info->selection; + int subtype; + CARD32 eventMask; + + switch (info->kind) { + case SelectionSetOwner: + subtype = XFixesSetSelectionOwnerNotify; + eventMask = XFixesSetSelectionOwnerNotifyMask; + break; + case SelectionWindowDestroy: + subtype = XFixesSelectionWindowDestroyNotify; + eventMask = XFixesSelectionWindowDestroyNotifyMask; + break; + case SelectionClientClose: + subtype = XFixesSelectionClientCloseNotify; + eventMask = XFixesSelectionClientCloseNotifyMask; + break; + default: + return; + } + for (e = selectionEvents; e; e = e->next) + { + if (e->selection == selection->selection && + (e->eventMask & eventMask) && + !e->pClient->clientGone) + { + xXFixesSelectionNotifyEvent ev; + + memset(&ev, 0, sizeof(xXFixesSelectionNotifyEvent)); + ev.type = XFixesEventBase + XFixesSelectionNotify; + ev.subtype = subtype; + ev.sequenceNumber = e->pClient->sequence; + ev.window = e->pWindow->drawable.id; + if (subtype == XFixesSetSelectionOwnerNotify) + ev.owner = selection->window; + else + ev.owner = 0; + ev.selection = e->selection; + ev.timestamp = currentTime.milliseconds; + ev.selectionTimestamp = selection->lastTimeChanged.milliseconds; + WriteEventsToClient (e->pClient, 1, (xEvent *) &ev); + } + } +} + +static Bool +CheckSelectionCallback (void) +{ + if (selectionEvents) + { + if (!SelectionCallbackRegistered) + { + if (!AddCallback (&SelectionCallback, XFixesSelectionCallback, NULL)) + return FALSE; + SelectionCallbackRegistered = TRUE; + } + } + else + { + if (SelectionCallbackRegistered) + { + DeleteCallback (&SelectionCallback, XFixesSelectionCallback, NULL); + SelectionCallbackRegistered = FALSE; + } + } + return TRUE; +} + +#define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\ + XFixesSelectionWindowDestroyNotifyMask |\ + XFixesSelectionClientCloseNotifyMask) + +static int +XFixesSelectSelectionInput (ClientPtr pClient, + Atom selection, + WindowPtr pWindow, + CARD32 eventMask) +{ + pointer val; + int rc; + SelectionEventPtr *prev, e; + + rc = XaceHook(XACE_SELECTION_ACCESS, pClient, selection, DixGetAttrAccess); + if (rc != Success) + return rc; + + for (prev = &selectionEvents; (e = *prev); prev = &e->next) + { + if (e->selection == selection && + e->pClient == pClient && + e->pWindow == pWindow) + { + break; + } + } + if (!eventMask) + { + if (e) + { + FreeResource (e->clientResource, 0); + } + return Success; + } + if (!e) + { + e = (SelectionEventPtr) malloc(sizeof (SelectionEventRec)); + if (!e) + return BadAlloc; + + e->next = 0; + e->selection = selection; + e->pClient = pClient; + e->pWindow = pWindow; + e->clientResource = FakeClientID(pClient->index); + + /* + * Add a resource hanging from the window to + * catch window destroy + */ + rc = dixLookupResourceByType (&val, pWindow->drawable.id, + SelectionWindowType, serverClient, + DixGetAttrAccess); + if (rc != Success) + if (!AddResource (pWindow->drawable.id, SelectionWindowType, + (pointer) pWindow)) + { + free(e); + return BadAlloc; + } + + if (!AddResource (e->clientResource, SelectionClientType, (pointer) e)) + return BadAlloc; + + *prev = e; + if (!CheckSelectionCallback ()) + { + FreeResource (e->clientResource, 0); + return BadAlloc; + } + } + e->eventMask = eventMask; + return Success; +} + +int +ProcXFixesSelectSelectionInput (ClientPtr client) +{ + REQUEST (xXFixesSelectSelectionInputReq); + WindowPtr pWin; + int rc; + + REQUEST_SIZE_MATCH (xXFixesSelectSelectionInputReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + if (stuff->eventMask & ~SelectionAllEvents) + { + client->errorValue = stuff->eventMask; + return( BadValue ); + } + return XFixesSelectSelectionInput (client, stuff->selection, + pWin, stuff->eventMask); +} + +int +SProcXFixesSelectSelectionInput (ClientPtr client) +{ + register int n; + REQUEST(xXFixesSelectSelectionInputReq); + + swaps(&stuff->length, n); + swapl(&stuff->window, n); + swapl(&stuff->selection, n); + swapl(&stuff->eventMask, n); + return (*ProcXFixesVector[stuff->xfixesReqType])(client); +} + +void +SXFixesSelectionNotifyEvent (xXFixesSelectionNotifyEvent *from, + xXFixesSelectionNotifyEvent *to) +{ + to->type = from->type; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->window, to->window); + cpswapl (from->owner, to->owner); + cpswapl (from->selection, to->selection); + cpswapl (from->timestamp, to->timestamp); + cpswapl (from->selectionTimestamp, to->selectionTimestamp); +} + +static int +SelectionFreeClient (pointer data, XID id) +{ + SelectionEventPtr old = (SelectionEventPtr) data; + SelectionEventPtr *prev, e; + + for (prev = &selectionEvents; (e = *prev); prev = &e->next) + { + if (e == old) + { + *prev = e->next; + free(e); + CheckSelectionCallback (); + break; + } + } + return 1; +} + +static int +SelectionFreeWindow (pointer data, XID id) +{ + WindowPtr pWindow = (WindowPtr) data; + SelectionEventPtr e, next; + + for (e = selectionEvents; e; e = next) + { + next = e->next; + if (e->pWindow == pWindow) + { + FreeResource (e->clientResource, 0); + } + } + return 1; +} + +Bool +XFixesSelectionInit (void) +{ + SelectionClientType = CreateNewResourceType(SelectionFreeClient, + "XFixesSelectionClient"); + SelectionWindowType = CreateNewResourceType(SelectionFreeWindow, + "XFixesSelectionWindow"); + return SelectionClientType && SelectionWindowType; +} diff --git a/xorg-server/xfixes/xfixes.c b/xorg-server/xfixes/xfixes.c index 5163dc11e..fd23a5cb7 100644 --- a/xorg-server/xfixes/xfixes.c +++ b/xorg-server/xfixes/xfixes.c @@ -1,263 +1,263 @@ -/* - * Copyright © 2006 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, 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. - * - * 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 <dix-config.h> -#endif - -#include "xfixesint.h" -#include "protocol-versions.h" -/* - * Must use these instead of the constants from xfixeswire.h. They advertise - * what we implement, not what the protocol headers define. - */ - -static unsigned char XFixesReqCode; -int XFixesEventBase; -int XFixesErrorBase; - -static int XFixesClientPrivateKeyIndex; -static DevPrivateKey XFixesClientPrivateKey = &XFixesClientPrivateKeyIndex; - -static int -ProcXFixesQueryVersion(ClientPtr client) -{ - XFixesClientPtr pXFixesClient = GetXFixesClient (client); - xXFixesQueryVersionReply rep; - register int n; - REQUEST(xXFixesQueryVersionReq); - - REQUEST_SIZE_MATCH(xXFixesQueryVersionReq); - memset(&rep, 0, sizeof(xXFixesQueryVersionReply)); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - if (stuff->majorVersion < SERVER_XFIXES_MAJOR_VERSION) { - rep.majorVersion = stuff->majorVersion; - rep.minorVersion = stuff->minorVersion; - } else { - rep.majorVersion = SERVER_XFIXES_MAJOR_VERSION; - if (stuff->majorVersion == SERVER_XFIXES_MAJOR_VERSION && - stuff->minorVersion < SERVER_XFIXES_MINOR_VERSION) - rep.minorVersion = stuff->minorVersion; - else - rep.minorVersion = SERVER_XFIXES_MINOR_VERSION; - } - pXFixesClient->major_version = rep.majorVersion; - pXFixesClient->minor_version = rep.minorVersion; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.majorVersion, n); - swapl(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xXFixesQueryVersionReply), (char *)&rep); - return(client->noClientException); -} - -/* Major version controls available requests */ -static const int version_requests[] = { - X_XFixesQueryVersion, /* before client sends QueryVersion */ - X_XFixesGetCursorImage, /* Version 1 */ - X_XFixesChangeCursorByName, /* Version 2 */ - X_XFixesExpandRegion, /* Version 3 */ - X_XFixesShowCursor, /* Version 4 */ -}; - -#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) - -int (*ProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { -/*************** Version 1 ******************/ - ProcXFixesQueryVersion, - ProcXFixesChangeSaveSet, - ProcXFixesSelectSelectionInput, - ProcXFixesSelectCursorInput, - ProcXFixesGetCursorImage, -/*************** Version 2 ******************/ - ProcXFixesCreateRegion, - ProcXFixesCreateRegionFromBitmap, - ProcXFixesCreateRegionFromWindow, - ProcXFixesCreateRegionFromGC, - ProcXFixesCreateRegionFromPicture, - ProcXFixesDestroyRegion, - ProcXFixesSetRegion, - ProcXFixesCopyRegion, - ProcXFixesCombineRegion, - ProcXFixesCombineRegion, - ProcXFixesCombineRegion, - ProcXFixesInvertRegion, - ProcXFixesTranslateRegion, - ProcXFixesRegionExtents, - ProcXFixesFetchRegion, - ProcXFixesSetGCClipRegion, - ProcXFixesSetWindowShapeRegion, - ProcXFixesSetPictureClipRegion, - ProcXFixesSetCursorName, - ProcXFixesGetCursorName, - ProcXFixesGetCursorImageAndName, - ProcXFixesChangeCursor, - ProcXFixesChangeCursorByName, -/*************** Version 3 ******************/ - ProcXFixesExpandRegion, -/*************** Version 4 ****************/ - ProcXFixesHideCursor, - ProcXFixesShowCursor, -}; - -static int -ProcXFixesDispatch (ClientPtr client) -{ - REQUEST(xXFixesReq); - XFixesClientPtr pXFixesClient = GetXFixesClient (client); - - if (pXFixesClient->major_version >= NUM_VERSION_REQUESTS) - return BadRequest; - if (stuff->xfixesReqType > version_requests[pXFixesClient->major_version]) - return BadRequest; - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -static int -SProcXFixesQueryVersion(ClientPtr client) -{ - register int n; - REQUEST(xXFixesQueryVersionReq); - - swaps(&stuff->length, n); - swapl(&stuff->majorVersion, n); - swapl(&stuff->minorVersion, n); - return (*ProcXFixesVector[stuff->xfixesReqType]) (client); -} - -static int (*SProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { -/*************** Version 1 ******************/ - SProcXFixesQueryVersion, - SProcXFixesChangeSaveSet, - SProcXFixesSelectSelectionInput, - SProcXFixesSelectCursorInput, - SProcXFixesGetCursorImage, -/*************** Version 2 ******************/ - SProcXFixesCreateRegion, - SProcXFixesCreateRegionFromBitmap, - SProcXFixesCreateRegionFromWindow, - SProcXFixesCreateRegionFromGC, - SProcXFixesCreateRegionFromPicture, - SProcXFixesDestroyRegion, - SProcXFixesSetRegion, - SProcXFixesCopyRegion, - SProcXFixesCombineRegion, - SProcXFixesCombineRegion, - SProcXFixesCombineRegion, - SProcXFixesInvertRegion, - SProcXFixesTranslateRegion, - SProcXFixesRegionExtents, - SProcXFixesFetchRegion, - SProcXFixesSetGCClipRegion, - SProcXFixesSetWindowShapeRegion, - SProcXFixesSetPictureClipRegion, - SProcXFixesSetCursorName, - SProcXFixesGetCursorName, - SProcXFixesGetCursorImageAndName, - SProcXFixesChangeCursor, - SProcXFixesChangeCursorByName, -/*************** Version 3 ******************/ - SProcXFixesExpandRegion, -/*************** Version 4 ****************/ - SProcXFixesHideCursor, - SProcXFixesShowCursor, -}; - -static int -SProcXFixesDispatch (ClientPtr client) -{ - REQUEST(xXFixesReq); - if (stuff->xfixesReqType >= XFixesNumberRequests) - return BadRequest; - return (*SProcXFixesVector[stuff->xfixesReqType]) (client); -} - -static void -XFixesClientCallback (CallbackListPtr *list, - pointer closure, - pointer data) -{ - NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; - ClientPtr pClient = clientinfo->client; - XFixesClientPtr pXFixesClient = GetXFixesClient (pClient); - - pXFixesClient->major_version = 0; - pXFixesClient->minor_version = 0; -} - -/*ARGSUSED*/ -static void -XFixesResetProc (ExtensionEntry *extEntry) -{ - DeleteCallback (&ClientStateCallback, XFixesClientCallback, 0); -} - -void -XFixesExtensionInit(void) -{ - ExtensionEntry *extEntry; - - if (!dixRequestPrivate(XFixesClientPrivateKey, sizeof (XFixesClientRec))) - return; - if (!AddCallback (&ClientStateCallback, XFixesClientCallback, 0)) - return; - - if (XFixesSelectionInit() && XFixesCursorInit () && XFixesRegionInit () && - (extEntry = AddExtension(XFIXES_NAME, XFixesNumberEvents, - XFixesNumberErrors, - ProcXFixesDispatch, SProcXFixesDispatch, - XFixesResetProc, StandardMinorOpcode)) != 0) - { - XFixesReqCode = (unsigned char)extEntry->base; - XFixesEventBase = extEntry->eventBase; - XFixesErrorBase = extEntry->errorBase; - EventSwapVector[XFixesEventBase + XFixesSelectionNotify] = - (EventSwapPtr) SXFixesSelectionNotifyEvent; - EventSwapVector[XFixesEventBase + XFixesCursorNotify] = - (EventSwapPtr) SXFixesCursorNotifyEvent; - } -} +/* + * Copyright © 2006 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, 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. + * + * 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 <dix-config.h> +#endif + +#include "xfixesint.h" +#include "protocol-versions.h" +/* + * Must use these instead of the constants from xfixeswire.h. They advertise + * what we implement, not what the protocol headers define. + */ + +static unsigned char XFixesReqCode; +int XFixesEventBase; +int XFixesErrorBase; + +static int XFixesClientPrivateKeyIndex; +static DevPrivateKey XFixesClientPrivateKey = &XFixesClientPrivateKeyIndex; + +static int +ProcXFixesQueryVersion(ClientPtr client) +{ + XFixesClientPtr pXFixesClient = GetXFixesClient (client); + xXFixesQueryVersionReply rep; + register int n; + REQUEST(xXFixesQueryVersionReq); + + REQUEST_SIZE_MATCH(xXFixesQueryVersionReq); + memset(&rep, 0, sizeof(xXFixesQueryVersionReply)); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (stuff->majorVersion < SERVER_XFIXES_MAJOR_VERSION) { + rep.majorVersion = stuff->majorVersion; + rep.minorVersion = stuff->minorVersion; + } else { + rep.majorVersion = SERVER_XFIXES_MAJOR_VERSION; + if (stuff->majorVersion == SERVER_XFIXES_MAJOR_VERSION && + stuff->minorVersion < SERVER_XFIXES_MINOR_VERSION) + rep.minorVersion = stuff->minorVersion; + else + rep.minorVersion = SERVER_XFIXES_MINOR_VERSION; + } + pXFixesClient->major_version = rep.majorVersion; + pXFixesClient->minor_version = rep.minorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xXFixesQueryVersionReply), (char *)&rep); + return Success; +} + +/* Major version controls available requests */ +static const int version_requests[] = { + X_XFixesQueryVersion, /* before client sends QueryVersion */ + X_XFixesGetCursorImage, /* Version 1 */ + X_XFixesChangeCursorByName, /* Version 2 */ + X_XFixesExpandRegion, /* Version 3 */ + X_XFixesShowCursor, /* Version 4 */ +}; + +#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) + +int (*ProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { +/*************** Version 1 ******************/ + ProcXFixesQueryVersion, + ProcXFixesChangeSaveSet, + ProcXFixesSelectSelectionInput, + ProcXFixesSelectCursorInput, + ProcXFixesGetCursorImage, +/*************** Version 2 ******************/ + ProcXFixesCreateRegion, + ProcXFixesCreateRegionFromBitmap, + ProcXFixesCreateRegionFromWindow, + ProcXFixesCreateRegionFromGC, + ProcXFixesCreateRegionFromPicture, + ProcXFixesDestroyRegion, + ProcXFixesSetRegion, + ProcXFixesCopyRegion, + ProcXFixesCombineRegion, + ProcXFixesCombineRegion, + ProcXFixesCombineRegion, + ProcXFixesInvertRegion, + ProcXFixesTranslateRegion, + ProcXFixesRegionExtents, + ProcXFixesFetchRegion, + ProcXFixesSetGCClipRegion, + ProcXFixesSetWindowShapeRegion, + ProcXFixesSetPictureClipRegion, + ProcXFixesSetCursorName, + ProcXFixesGetCursorName, + ProcXFixesGetCursorImageAndName, + ProcXFixesChangeCursor, + ProcXFixesChangeCursorByName, +/*************** Version 3 ******************/ + ProcXFixesExpandRegion, +/*************** Version 4 ****************/ + ProcXFixesHideCursor, + ProcXFixesShowCursor, +}; + +static int +ProcXFixesDispatch (ClientPtr client) +{ + REQUEST(xXFixesReq); + XFixesClientPtr pXFixesClient = GetXFixesClient (client); + + if (pXFixesClient->major_version >= NUM_VERSION_REQUESTS) + return BadRequest; + if (stuff->xfixesReqType > version_requests[pXFixesClient->major_version]) + return BadRequest; + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +static int +SProcXFixesQueryVersion(ClientPtr client) +{ + register int n; + REQUEST(xXFixesQueryVersionReq); + + swaps(&stuff->length, n); + swapl(&stuff->majorVersion, n); + swapl(&stuff->minorVersion, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +static int (*SProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { +/*************** Version 1 ******************/ + SProcXFixesQueryVersion, + SProcXFixesChangeSaveSet, + SProcXFixesSelectSelectionInput, + SProcXFixesSelectCursorInput, + SProcXFixesGetCursorImage, +/*************** Version 2 ******************/ + SProcXFixesCreateRegion, + SProcXFixesCreateRegionFromBitmap, + SProcXFixesCreateRegionFromWindow, + SProcXFixesCreateRegionFromGC, + SProcXFixesCreateRegionFromPicture, + SProcXFixesDestroyRegion, + SProcXFixesSetRegion, + SProcXFixesCopyRegion, + SProcXFixesCombineRegion, + SProcXFixesCombineRegion, + SProcXFixesCombineRegion, + SProcXFixesInvertRegion, + SProcXFixesTranslateRegion, + SProcXFixesRegionExtents, + SProcXFixesFetchRegion, + SProcXFixesSetGCClipRegion, + SProcXFixesSetWindowShapeRegion, + SProcXFixesSetPictureClipRegion, + SProcXFixesSetCursorName, + SProcXFixesGetCursorName, + SProcXFixesGetCursorImageAndName, + SProcXFixesChangeCursor, + SProcXFixesChangeCursorByName, +/*************** Version 3 ******************/ + SProcXFixesExpandRegion, +/*************** Version 4 ****************/ + SProcXFixesHideCursor, + SProcXFixesShowCursor, +}; + +static int +SProcXFixesDispatch (ClientPtr client) +{ + REQUEST(xXFixesReq); + if (stuff->xfixesReqType >= XFixesNumberRequests) + return BadRequest; + return (*SProcXFixesVector[stuff->xfixesReqType]) (client); +} + +static void +XFixesClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + XFixesClientPtr pXFixesClient = GetXFixesClient (pClient); + + pXFixesClient->major_version = 0; + pXFixesClient->minor_version = 0; +} + +/*ARGSUSED*/ +static void +XFixesResetProc (ExtensionEntry *extEntry) +{ + DeleteCallback (&ClientStateCallback, XFixesClientCallback, 0); +} + +void +XFixesExtensionInit(void) +{ + ExtensionEntry *extEntry; + + if (!dixRequestPrivate(XFixesClientPrivateKey, sizeof (XFixesClientRec))) + return; + if (!AddCallback (&ClientStateCallback, XFixesClientCallback, 0)) + return; + + if (XFixesSelectionInit() && XFixesCursorInit () && XFixesRegionInit () && + (extEntry = AddExtension(XFIXES_NAME, XFixesNumberEvents, + XFixesNumberErrors, + ProcXFixesDispatch, SProcXFixesDispatch, + XFixesResetProc, StandardMinorOpcode)) != 0) + { + XFixesReqCode = (unsigned char)extEntry->base; + XFixesEventBase = extEntry->eventBase; + XFixesErrorBase = extEntry->errorBase; + EventSwapVector[XFixesEventBase + XFixesSelectionNotify] = + (EventSwapPtr) SXFixesSelectionNotifyEvent; + EventSwapVector[XFixesEventBase + XFixesCursorNotify] = + (EventSwapPtr) SXFixesCursorNotifyEvent; + } +} diff --git a/xorg-server/xkb/XKBAlloc.c b/xorg-server/xkb/XKBAlloc.c index d40aa3345..4d342a0fa 100644 --- a/xorg-server/xkb/XKBAlloc.c +++ b/xorg-server/xkb/XKBAlloc.c @@ -1,337 +1,337 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#endif - -#include <stdio.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "inputstr.h" -#include <xkbsrv.h> -#include "xkbgeom.h" -#include <os.h> -#include <string.h> - -/***===================================================================***/ - -/*ARGSUSED*/ -Status -XkbAllocCompatMap(XkbDescPtr xkb,unsigned which,unsigned nSI) -{ -XkbCompatMapPtr compat; -XkbSymInterpretRec *prev_interpret; - - if (!xkb) - return BadMatch; - if (xkb->compat) { - if (xkb->compat->size_si>=nSI) - return Success; - compat= xkb->compat; - compat->size_si= nSI; - if (compat->sym_interpret==NULL) - compat->num_si= 0; - prev_interpret = compat->sym_interpret; - compat->sym_interpret= xrealloc(compat->sym_interpret, - nSI * sizeof(XkbSymInterpretRec)); - if (compat->sym_interpret==NULL) { - xfree(prev_interpret); - compat->size_si= compat->num_si= 0; - return BadAlloc; - } - if (compat->num_si!=0) { - memset(&compat->sym_interpret[compat->num_si], 0, - (compat->size_si - compat->num_si) * sizeof(XkbSymInterpretRec)); - } - return Success; - } - compat= xcalloc(1, sizeof(XkbCompatMapRec)); - if (compat==NULL) - return BadAlloc; - if (nSI>0) { - compat->sym_interpret= xcalloc(nSI, sizeof(XkbSymInterpretRec)); - if (!compat->sym_interpret) { - xfree(compat); - return BadAlloc; - } - } - compat->size_si= nSI; - compat->num_si= 0; - bzero((char *)&compat->groups[0],XkbNumKbdGroups*sizeof(XkbModsRec)); - xkb->compat= compat; - return Success; -} - - -void -XkbFreeCompatMap(XkbDescPtr xkb,unsigned which,Bool freeMap) -{ -register XkbCompatMapPtr compat; - - if ((xkb==NULL)||(xkb->compat==NULL)) - return; - compat= xkb->compat; - if (freeMap) - which= XkbAllCompatMask; - if (which&XkbGroupCompatMask) - bzero((char *)&compat->groups[0],XkbNumKbdGroups*sizeof(XkbModsRec)); - if (which&XkbSymInterpMask) { - if ((compat->sym_interpret)&&(compat->size_si>0)) - xfree(compat->sym_interpret); - compat->size_si= compat->num_si= 0; - compat->sym_interpret= NULL; - } - if (freeMap) { - xfree(compat); - xkb->compat= NULL; - } - return; -} - -/***===================================================================***/ - -Status -XkbAllocNames(XkbDescPtr xkb,unsigned which,int nTotalRG,int nTotalAliases) -{ -XkbNamesPtr names; - - if (xkb==NULL) - return BadMatch; - if (xkb->names==NULL) { - xkb->names = xcalloc(1, sizeof(XkbNamesRec)); - if (xkb->names==NULL) - return BadAlloc; - } - names= xkb->names; - if ((which&XkbKTLevelNamesMask)&&(xkb->map!=NULL)&&(xkb->map->types!=NULL)){ - register int i; - XkbKeyTypePtr type; - - type= xkb->map->types; - for (i=0;i<xkb->map->num_types;i++,type++) { - if (type->level_names==NULL) { - type->level_names= xcalloc(type->num_levels, sizeof(Atom)); - if (type->level_names==NULL) - return BadAlloc; - } - } - } - if ((which&XkbKeyNamesMask)&&(names->keys==NULL)) { - if ((!XkbIsLegalKeycode(xkb->min_key_code))|| - (!XkbIsLegalKeycode(xkb->max_key_code))|| - (xkb->max_key_code<xkb->min_key_code)) - return BadValue; - names->keys= xcalloc((xkb->max_key_code+1), sizeof(XkbKeyNameRec)); - if (names->keys==NULL) - return BadAlloc; - } - if ((which&XkbKeyAliasesMask)&&(nTotalAliases>0)) { - if (names->key_aliases==NULL) { - names->key_aliases= xcalloc(nTotalAliases, sizeof(XkbKeyAliasRec)); - } - else if (nTotalAliases>names->num_key_aliases) { - XkbKeyAliasRec *prev_aliases = names->key_aliases; - - names->key_aliases= xrealloc(names->key_aliases, - nTotalAliases * sizeof(XkbKeyAliasRec)); - if (names->key_aliases!=NULL) { - memset(&names->key_aliases[names->num_key_aliases], 0, - (nTotalAliases - names->num_key_aliases) * sizeof(XkbKeyAliasRec)); - } else { - xfree(prev_aliases); - } - } - if (names->key_aliases==NULL) { - names->num_key_aliases= 0; - return BadAlloc; - } - names->num_key_aliases= nTotalAliases; - } - if ((which&XkbRGNamesMask)&&(nTotalRG>0)) { - if (names->radio_groups==NULL) { - names->radio_groups= xcalloc(nTotalRG, sizeof(Atom)); - } - else if (nTotalRG>names->num_rg) { - Atom *prev_radio_groups = names->radio_groups; - - names->radio_groups= xrealloc(names->radio_groups, - nTotalRG * sizeof(Atom)); - if (names->radio_groups!=NULL) { - memset(&names->radio_groups[names->num_rg], 0, - (nTotalRG - names->num_rg) * sizeof(Atom)); - } else { - xfree(prev_radio_groups); - } - } - if (names->radio_groups==NULL) - return BadAlloc; - names->num_rg= nTotalRG; - } - return Success; -} - -void -XkbFreeNames(XkbDescPtr xkb,unsigned which,Bool freeMap) -{ -XkbNamesPtr names; - - if ((xkb==NULL)||(xkb->names==NULL)) - return; - names= xkb->names; - if (freeMap) - which= XkbAllNamesMask; - if (which&XkbKTLevelNamesMask) { - XkbClientMapPtr map= xkb->map; - if ((map!=NULL)&&(map->types!=NULL)) { - register int i; - register XkbKeyTypePtr type; - type= map->types; - for (i=0;i<map->num_types;i++,type++) { - if (type->level_names!=NULL) { - xfree(type->level_names); - type->level_names= NULL; - } - } - } - } - if ((which&XkbKeyNamesMask)&&(names->keys!=NULL)) { - xfree(names->keys); - names->keys= NULL; - names->num_keys= 0; - } - if ((which&XkbKeyAliasesMask)&&(names->key_aliases)){ - xfree(names->key_aliases); - names->key_aliases=NULL; - names->num_key_aliases=0; - } - if ((which&XkbRGNamesMask)&&(names->radio_groups)) { - xfree(names->radio_groups); - names->radio_groups= NULL; - names->num_rg= 0; - } - if (freeMap) { - xfree(names); - xkb->names= NULL; - } - return; -} - -/***===================================================================***/ - -/*ARGSUSED*/ -Status -XkbAllocControls(XkbDescPtr xkb,unsigned which) -{ - if (xkb==NULL) - return BadMatch; - - if (xkb->ctrls==NULL) { - xkb->ctrls= xcalloc(1, sizeof(XkbControlsRec)); - if (!xkb->ctrls) - return BadAlloc; - } - return Success; -} - -/*ARGSUSED*/ -static void -XkbFreeControls(XkbDescPtr xkb,unsigned which,Bool freeMap) -{ - if (freeMap && (xkb!=NULL) && (xkb->ctrls!=NULL)) { - xfree(xkb->ctrls); - xkb->ctrls= NULL; - } - return; -} - -/***===================================================================***/ - -Status -XkbAllocIndicatorMaps(XkbDescPtr xkb) -{ - if (xkb==NULL) - return BadMatch; - if (xkb->indicators==NULL) { - xkb->indicators= xcalloc(1, sizeof(XkbIndicatorRec)); - if (!xkb->indicators) - return BadAlloc; - } - return Success; -} - -static void -XkbFreeIndicatorMaps(XkbDescPtr xkb) -{ - if ((xkb!=NULL)&&(xkb->indicators!=NULL)) { - xfree(xkb->indicators); - xkb->indicators= NULL; - } - return; -} - -/***====================================================================***/ - -XkbDescRec * -XkbAllocKeyboard(void) -{ -XkbDescRec *xkb; - - xkb = xcalloc(1, sizeof(XkbDescRec)); - if (xkb) - xkb->device_spec= XkbUseCoreKbd; - return xkb; -} - -void -XkbFreeKeyboard(XkbDescPtr xkb,unsigned which,Bool freeAll) -{ - if (xkb==NULL) - return; - if (freeAll) - which= XkbAllComponentsMask; - if (which&XkbClientMapMask) - XkbFreeClientMap(xkb,XkbAllClientInfoMask,TRUE); - if (which&XkbServerMapMask) - XkbFreeServerMap(xkb,XkbAllServerInfoMask,TRUE); - if (which&XkbCompatMapMask) - XkbFreeCompatMap(xkb,XkbAllCompatMask,TRUE); - if (which&XkbIndicatorMapMask) - XkbFreeIndicatorMaps(xkb); - if (which&XkbNamesMask) - XkbFreeNames(xkb,XkbAllNamesMask,TRUE); - if ((which&XkbGeometryMask) && (xkb->geom!=NULL)) { - XkbFreeGeometry(xkb->geom,XkbGeomAllMask,TRUE); - /* PERHAPS BONGHITS etc */ - xkb->geom = NULL; - } - if (which&XkbControlsMask) - XkbFreeControls(xkb,XkbAllControlsMask,TRUE); - if (freeAll) - xfree(xkb); - return; -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#endif + +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "inputstr.h" +#include <xkbsrv.h> +#include "xkbgeom.h" +#include <os.h> +#include <string.h> + +/***===================================================================***/ + +/*ARGSUSED*/ +Status +XkbAllocCompatMap(XkbDescPtr xkb,unsigned which,unsigned nSI) +{ +XkbCompatMapPtr compat; +XkbSymInterpretRec *prev_interpret; + + if (!xkb) + return BadMatch; + if (xkb->compat) { + if (xkb->compat->size_si>=nSI) + return Success; + compat= xkb->compat; + compat->size_si= nSI; + if (compat->sym_interpret==NULL) + compat->num_si= 0; + prev_interpret = compat->sym_interpret; + compat->sym_interpret= realloc(compat->sym_interpret, + nSI * sizeof(XkbSymInterpretRec)); + if (compat->sym_interpret==NULL) { + free(prev_interpret); + compat->size_si= compat->num_si= 0; + return BadAlloc; + } + if (compat->num_si!=0) { + memset(&compat->sym_interpret[compat->num_si], 0, + (compat->size_si - compat->num_si) * sizeof(XkbSymInterpretRec)); + } + return Success; + } + compat= calloc(1, sizeof(XkbCompatMapRec)); + if (compat==NULL) + return BadAlloc; + if (nSI>0) { + compat->sym_interpret= calloc(nSI, sizeof(XkbSymInterpretRec)); + if (!compat->sym_interpret) { + free(compat); + return BadAlloc; + } + } + compat->size_si= nSI; + compat->num_si= 0; + bzero((char *)&compat->groups[0],XkbNumKbdGroups*sizeof(XkbModsRec)); + xkb->compat= compat; + return Success; +} + + +void +XkbFreeCompatMap(XkbDescPtr xkb,unsigned which,Bool freeMap) +{ +register XkbCompatMapPtr compat; + + if ((xkb==NULL)||(xkb->compat==NULL)) + return; + compat= xkb->compat; + if (freeMap) + which= XkbAllCompatMask; + if (which&XkbGroupCompatMask) + bzero((char *)&compat->groups[0],XkbNumKbdGroups*sizeof(XkbModsRec)); + if (which&XkbSymInterpMask) { + if ((compat->sym_interpret)&&(compat->size_si>0)) + free(compat->sym_interpret); + compat->size_si= compat->num_si= 0; + compat->sym_interpret= NULL; + } + if (freeMap) { + free(compat); + xkb->compat= NULL; + } + return; +} + +/***===================================================================***/ + +Status +XkbAllocNames(XkbDescPtr xkb,unsigned which,int nTotalRG,int nTotalAliases) +{ +XkbNamesPtr names; + + if (xkb==NULL) + return BadMatch; + if (xkb->names==NULL) { + xkb->names = calloc(1, sizeof(XkbNamesRec)); + if (xkb->names==NULL) + return BadAlloc; + } + names= xkb->names; + if ((which&XkbKTLevelNamesMask)&&(xkb->map!=NULL)&&(xkb->map->types!=NULL)){ + register int i; + XkbKeyTypePtr type; + + type= xkb->map->types; + for (i=0;i<xkb->map->num_types;i++,type++) { + if (type->level_names==NULL) { + type->level_names= calloc(type->num_levels, sizeof(Atom)); + if (type->level_names==NULL) + return BadAlloc; + } + } + } + if ((which&XkbKeyNamesMask)&&(names->keys==NULL)) { + if ((!XkbIsLegalKeycode(xkb->min_key_code))|| + (!XkbIsLegalKeycode(xkb->max_key_code))|| + (xkb->max_key_code<xkb->min_key_code)) + return BadValue; + names->keys= calloc((xkb->max_key_code+1), sizeof(XkbKeyNameRec)); + if (names->keys==NULL) + return BadAlloc; + } + if ((which&XkbKeyAliasesMask)&&(nTotalAliases>0)) { + if (names->key_aliases==NULL) { + names->key_aliases= calloc(nTotalAliases, sizeof(XkbKeyAliasRec)); + } + else if (nTotalAliases>names->num_key_aliases) { + XkbKeyAliasRec *prev_aliases = names->key_aliases; + + names->key_aliases= realloc(names->key_aliases, + nTotalAliases * sizeof(XkbKeyAliasRec)); + if (names->key_aliases!=NULL) { + memset(&names->key_aliases[names->num_key_aliases], 0, + (nTotalAliases - names->num_key_aliases) * sizeof(XkbKeyAliasRec)); + } else { + free(prev_aliases); + } + } + if (names->key_aliases==NULL) { + names->num_key_aliases= 0; + return BadAlloc; + } + names->num_key_aliases= nTotalAliases; + } + if ((which&XkbRGNamesMask)&&(nTotalRG>0)) { + if (names->radio_groups==NULL) { + names->radio_groups= calloc(nTotalRG, sizeof(Atom)); + } + else if (nTotalRG>names->num_rg) { + Atom *prev_radio_groups = names->radio_groups; + + names->radio_groups= realloc(names->radio_groups, + nTotalRG * sizeof(Atom)); + if (names->radio_groups!=NULL) { + memset(&names->radio_groups[names->num_rg], 0, + (nTotalRG - names->num_rg) * sizeof(Atom)); + } else { + free(prev_radio_groups); + } + } + if (names->radio_groups==NULL) + return BadAlloc; + names->num_rg= nTotalRG; + } + return Success; +} + +void +XkbFreeNames(XkbDescPtr xkb,unsigned which,Bool freeMap) +{ +XkbNamesPtr names; + + if ((xkb==NULL)||(xkb->names==NULL)) + return; + names= xkb->names; + if (freeMap) + which= XkbAllNamesMask; + if (which&XkbKTLevelNamesMask) { + XkbClientMapPtr map= xkb->map; + if ((map!=NULL)&&(map->types!=NULL)) { + register int i; + register XkbKeyTypePtr type; + type= map->types; + for (i=0;i<map->num_types;i++,type++) { + if (type->level_names!=NULL) { + free(type->level_names); + type->level_names= NULL; + } + } + } + } + if ((which&XkbKeyNamesMask)&&(names->keys!=NULL)) { + free(names->keys); + names->keys= NULL; + names->num_keys= 0; + } + if ((which&XkbKeyAliasesMask)&&(names->key_aliases)){ + free(names->key_aliases); + names->key_aliases=NULL; + names->num_key_aliases=0; + } + if ((which&XkbRGNamesMask)&&(names->radio_groups)) { + free(names->radio_groups); + names->radio_groups= NULL; + names->num_rg= 0; + } + if (freeMap) { + free(names); + xkb->names= NULL; + } + return; +} + +/***===================================================================***/ + +/*ARGSUSED*/ +Status +XkbAllocControls(XkbDescPtr xkb,unsigned which) +{ + if (xkb==NULL) + return BadMatch; + + if (xkb->ctrls==NULL) { + xkb->ctrls= calloc(1, sizeof(XkbControlsRec)); + if (!xkb->ctrls) + return BadAlloc; + } + return Success; +} + +/*ARGSUSED*/ +static void +XkbFreeControls(XkbDescPtr xkb,unsigned which,Bool freeMap) +{ + if (freeMap && (xkb!=NULL) && (xkb->ctrls!=NULL)) { + free(xkb->ctrls); + xkb->ctrls= NULL; + } + return; +} + +/***===================================================================***/ + +Status +XkbAllocIndicatorMaps(XkbDescPtr xkb) +{ + if (xkb==NULL) + return BadMatch; + if (xkb->indicators==NULL) { + xkb->indicators= calloc(1, sizeof(XkbIndicatorRec)); + if (!xkb->indicators) + return BadAlloc; + } + return Success; +} + +static void +XkbFreeIndicatorMaps(XkbDescPtr xkb) +{ + if ((xkb!=NULL)&&(xkb->indicators!=NULL)) { + free(xkb->indicators); + xkb->indicators= NULL; + } + return; +} + +/***====================================================================***/ + +XkbDescRec * +XkbAllocKeyboard(void) +{ +XkbDescRec *xkb; + + xkb = calloc(1, sizeof(XkbDescRec)); + if (xkb) + xkb->device_spec= XkbUseCoreKbd; + return xkb; +} + +void +XkbFreeKeyboard(XkbDescPtr xkb,unsigned which,Bool freeAll) +{ + if (xkb==NULL) + return; + if (freeAll) + which= XkbAllComponentsMask; + if (which&XkbClientMapMask) + XkbFreeClientMap(xkb,XkbAllClientInfoMask,TRUE); + if (which&XkbServerMapMask) + XkbFreeServerMap(xkb,XkbAllServerInfoMask,TRUE); + if (which&XkbCompatMapMask) + XkbFreeCompatMap(xkb,XkbAllCompatMask,TRUE); + if (which&XkbIndicatorMapMask) + XkbFreeIndicatorMaps(xkb); + if (which&XkbNamesMask) + XkbFreeNames(xkb,XkbAllNamesMask,TRUE); + if ((which&XkbGeometryMask) && (xkb->geom!=NULL)) { + XkbFreeGeometry(xkb->geom,XkbGeomAllMask,TRUE); + /* PERHAPS BONGHITS etc */ + xkb->geom = NULL; + } + if (which&XkbControlsMask) + XkbFreeControls(xkb,XkbAllControlsMask,TRUE); + if (freeAll) + free(xkb); + return; +} diff --git a/xorg-server/xkb/XKBGAlloc.c b/xorg-server/xkb/XKBGAlloc.c index b01005dd0..4dc3e7017 100644 --- a/xorg-server/xkb/XKBGAlloc.c +++ b/xorg-server/xkb/XKBGAlloc.c @@ -1,997 +1,997 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#endif - - -#include <stdio.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "inputstr.h" -#include <xkbsrv.h> -#include "xkbgeom.h" - -/***====================================================================***/ - -static void -_XkbFreeGeomLeafElems( Bool freeAll, - int first, - int count, - unsigned short * num_inout, - unsigned short * sz_inout, - char ** elems, - unsigned int elem_sz) -{ - if ((freeAll)||(*elems==NULL)) { - *num_inout= *sz_inout= 0; - if (*elems!=NULL) { - xfree(*elems); - *elems= NULL; - } - return; - } - - if ((first>=(*num_inout))||(first<0)||(count<1)) - return; - - if (first+count>=(*num_inout)) { - /* truncating the array is easy */ - (*num_inout)= first; - } - else { - char * ptr; - int extra; - ptr= *elems; - extra= ((*num_inout)-(first+count))*elem_sz; - if (extra>0) - memmove(&ptr[first*elem_sz],&ptr[(first+count)*elem_sz],extra); - (*num_inout)-= count; - } - return; -} - -typedef void (*ContentsClearFunc)( - char * /* priv */ -); - -static void -_XkbFreeGeomNonLeafElems( Bool freeAll, - int first, - int count, - unsigned short * num_inout, - unsigned short * sz_inout, - char ** elems, - unsigned int elem_sz, - ContentsClearFunc freeFunc) -{ -register int i; -register char *ptr; - - if (freeAll) { - first= 0; - count= (*num_inout); - } - else if ((first>=(*num_inout))||(first<0)||(count<1)) - return; - else if (first+count>(*num_inout)) - count= (*num_inout)-first; - if (*elems==NULL) - return; - - if (freeFunc) { - ptr= *elems; - ptr+= first*elem_sz; - for (i=0;i<count;i++) { - (*freeFunc)(ptr); - ptr+= elem_sz; - } - } - if (freeAll) { - (*num_inout)= (*sz_inout)= 0; - if (*elems) { - xfree(*elems); - *elems= NULL; - } - } - else if (first+count>=(*num_inout)) - *num_inout= first; - else { - i= ((*num_inout)-(first+count))*elem_sz; - ptr= *elems; - memmove(&ptr[first*elem_sz],&ptr[(first+count)*elem_sz],i); - (*num_inout)-= count; - } - return; -} - -/***====================================================================***/ - -static void -_XkbClearProperty(char *prop_in) -{ -XkbPropertyPtr prop= (XkbPropertyPtr)prop_in; - - if (prop->name) { - xfree(prop->name); - prop->name= NULL; - } - if (prop->value) { - xfree(prop->value); - prop->value= NULL; - } - return; -} - -void -XkbFreeGeomProperties( XkbGeometryPtr geom, - int first, - int count, - Bool freeAll) -{ - _XkbFreeGeomNonLeafElems(freeAll,first,count, - &geom->num_properties,&geom->sz_properties, - (char **)&geom->properties, - sizeof(XkbPropertyRec),_XkbClearProperty); - return; -} - -/***====================================================================***/ - -void -XkbFreeGeomKeyAliases( XkbGeometryPtr geom, - int first, - int count, - Bool freeAll) -{ - _XkbFreeGeomLeafElems(freeAll,first,count, - &geom->num_key_aliases,&geom->sz_key_aliases, - (char **)&geom->key_aliases, - sizeof(XkbKeyAliasRec)); - return; -} - -/***====================================================================***/ - -static void -_XkbClearColor(char *color_in) -{ -XkbColorPtr color= (XkbColorPtr)color_in; - - if (color->spec) - xfree(color->spec); - return; -} - -void -XkbFreeGeomColors(XkbGeometryPtr geom,int first,int count,Bool freeAll) -{ - _XkbFreeGeomNonLeafElems(freeAll,first,count, - &geom->num_colors,&geom->sz_colors, - (char **)&geom->colors, - sizeof(XkbColorRec),_XkbClearColor); - return; -} - -/***====================================================================***/ - -void -XkbFreeGeomPoints(XkbOutlinePtr outline,int first,int count,Bool freeAll) -{ - _XkbFreeGeomLeafElems(freeAll,first,count, - &outline->num_points,&outline->sz_points, - (char **)&outline->points, - sizeof(XkbPointRec)); - return; -} - -/***====================================================================***/ - -static void -_XkbClearOutline(char *outline_in) -{ -XkbOutlinePtr outline= (XkbOutlinePtr)outline_in; - - if (outline->points!=NULL) - XkbFreeGeomPoints(outline,0,outline->num_points,TRUE); - return; -} - -void -XkbFreeGeomOutlines(XkbShapePtr shape,int first,int count,Bool freeAll) -{ - _XkbFreeGeomNonLeafElems(freeAll,first,count, - &shape->num_outlines,&shape->sz_outlines, - (char **)&shape->outlines, - sizeof(XkbOutlineRec),_XkbClearOutline); - - return; -} - -/***====================================================================***/ - -static void -_XkbClearShape(char *shape_in) -{ -XkbShapePtr shape= (XkbShapePtr)shape_in; - - if (shape->outlines) - XkbFreeGeomOutlines(shape,0,shape->num_outlines,TRUE); - return; -} - -void -XkbFreeGeomShapes(XkbGeometryPtr geom,int first,int count,Bool freeAll) -{ - _XkbFreeGeomNonLeafElems(freeAll,first,count, - &geom->num_shapes,&geom->sz_shapes, - (char **)&geom->shapes, - sizeof(XkbShapeRec),_XkbClearShape); - return; -} - -/***====================================================================***/ - -void -XkbFreeGeomOverlayKeys(XkbOverlayRowPtr row,int first,int count,Bool freeAll) -{ - _XkbFreeGeomLeafElems(freeAll,first,count, - &row->num_keys,&row->sz_keys, - (char **)&row->keys, - sizeof(XkbOverlayKeyRec)); - return; -} - -/***====================================================================***/ - -static void -_XkbClearOverlayRow(char *row_in) -{ -XkbOverlayRowPtr row= (XkbOverlayRowPtr)row_in; - - if (row->keys!=NULL) - XkbFreeGeomOverlayKeys(row,0,row->num_keys,TRUE); - return; -} - -void -XkbFreeGeomOverlayRows(XkbOverlayPtr overlay,int first,int count,Bool freeAll) -{ - _XkbFreeGeomNonLeafElems(freeAll,first,count, - &overlay->num_rows,&overlay->sz_rows, - (char **)&overlay->rows, - sizeof(XkbOverlayRowRec),_XkbClearOverlayRow); - return; -} - -/***====================================================================***/ - -static void -_XkbClearOverlay(char *overlay_in) -{ -XkbOverlayPtr overlay= (XkbOverlayPtr)overlay_in; - - if (overlay->rows!=NULL) - XkbFreeGeomOverlayRows(overlay,0,overlay->num_rows,TRUE); - return; -} - -void -XkbFreeGeomOverlays(XkbSectionPtr section,int first,int count,Bool freeAll) -{ - _XkbFreeGeomNonLeafElems(freeAll,first,count, - §ion->num_overlays,§ion->sz_overlays, - (char **)§ion->overlays, - sizeof(XkbOverlayRec),_XkbClearOverlay); - return; -} - -/***====================================================================***/ - -void -XkbFreeGeomKeys(XkbRowPtr row,int first,int count,Bool freeAll) -{ - _XkbFreeGeomLeafElems(freeAll,first,count, - &row->num_keys,&row->sz_keys, - (char **)&row->keys, - sizeof(XkbKeyRec)); - return; -} - -/***====================================================================***/ - -static void -_XkbClearRow(char *row_in) -{ -XkbRowPtr row= (XkbRowPtr)row_in; - - if (row->keys!=NULL) - XkbFreeGeomKeys(row,0,row->num_keys,TRUE); - return; -} - -void -XkbFreeGeomRows(XkbSectionPtr section,int first,int count,Bool freeAll) -{ - _XkbFreeGeomNonLeafElems(freeAll,first,count, - §ion->num_rows,§ion->sz_rows, - (char **)§ion->rows, - sizeof(XkbRowRec),_XkbClearRow); -} - -/***====================================================================***/ - -static void -_XkbClearSection(char *section_in) -{ -XkbSectionPtr section= (XkbSectionPtr)section_in; - - if (section->rows!=NULL) - XkbFreeGeomRows(section,0,section->num_rows,TRUE); - if (section->doodads!=NULL) { - XkbFreeGeomDoodads(section->doodads,section->num_doodads,TRUE); - section->doodads= NULL; - } - return; -} - -void -XkbFreeGeomSections(XkbGeometryPtr geom,int first,int count,Bool freeAll) -{ - _XkbFreeGeomNonLeafElems(freeAll,first,count, - &geom->num_sections,&geom->sz_sections, - (char **)&geom->sections, - sizeof(XkbSectionRec),_XkbClearSection); - return; -} - -/***====================================================================***/ - -static void -_XkbClearDoodad(char *doodad_in) -{ -XkbDoodadPtr doodad= (XkbDoodadPtr)doodad_in; - - switch (doodad->any.type) { - case XkbTextDoodad: - { - if (doodad->text.text!=NULL) { - xfree(doodad->text.text); - doodad->text.text= NULL; - } - if (doodad->text.font!=NULL) { - xfree(doodad->text.font); - doodad->text.font= NULL; - } - } - break; - case XkbLogoDoodad: - { - if (doodad->logo.logo_name!=NULL) { - xfree(doodad->logo.logo_name); - doodad->logo.logo_name= NULL; - } - } - break; - } - return; -} - -void -XkbFreeGeomDoodads(XkbDoodadPtr doodads,int nDoodads,Bool freeAll) -{ -register int i; -register XkbDoodadPtr doodad; - - if (doodads) { - for (i=0,doodad= doodads;i<nDoodads;i++,doodad++) { - _XkbClearDoodad((char *)doodad); - } - if (freeAll) - xfree(doodads); - } - return; -} - -void -XkbFreeGeometry(XkbGeometryPtr geom,unsigned which,Bool freeMap) -{ - if (geom==NULL) - return; - if (freeMap) - which= XkbGeomAllMask; - if ((which&XkbGeomPropertiesMask)&&(geom->properties!=NULL)) - XkbFreeGeomProperties(geom,0,geom->num_properties,TRUE); - if ((which&XkbGeomColorsMask)&&(geom->colors!=NULL)) - XkbFreeGeomColors(geom,0,geom->num_colors,TRUE); - if ((which&XkbGeomShapesMask)&&(geom->shapes!=NULL)) - XkbFreeGeomShapes(geom,0,geom->num_shapes,TRUE); - if ((which&XkbGeomSectionsMask)&&(geom->sections!=NULL)) - XkbFreeGeomSections(geom,0,geom->num_sections,TRUE); - if ((which&XkbGeomDoodadsMask)&&(geom->doodads!= NULL)) { - XkbFreeGeomDoodads(geom->doodads,geom->num_doodads,TRUE); - geom->doodads= NULL; - geom->num_doodads= geom->sz_doodads= 0; - } - if ((which&XkbGeomKeyAliasesMask)&&(geom->key_aliases!=NULL)) - XkbFreeGeomKeyAliases(geom,0,geom->num_key_aliases,TRUE); - if (freeMap) { - if (geom->label_font!=NULL) { - xfree(geom->label_font); - geom->label_font= NULL; - } - xfree(geom); - } - return; -} - -/***====================================================================***/ - -static Status -_XkbGeomAlloc( void ** old, - unsigned short * num, - unsigned short * total, - int num_new, - size_t sz_elem) -{ - if (num_new<1) - return Success; - if ((*old)==NULL) - *num= *total= 0; - - if ((*num)+num_new<=(*total)) - return Success; - - *total= (*num)+num_new; - if ((*old)!=NULL) - (*old)= xrealloc((*old),(*total)*sz_elem); - else (*old)= xcalloc((*total),sz_elem); - if ((*old)==NULL) { - *total= *num= 0; - return BadAlloc; - } - - if (*num>0) { - char *tmp= (char *)(*old); - bzero(&tmp[sz_elem*(*num)],(num_new*sz_elem)); - } - return Success; -} - -#define _XkbAllocProps(g,n) _XkbGeomAlloc((void *)&(g)->properties,\ - &(g)->num_properties,&(g)->sz_properties,\ - (n),sizeof(XkbPropertyRec)) -#define _XkbAllocColors(g,n) _XkbGeomAlloc((void *)&(g)->colors,\ - &(g)->num_colors,&(g)->sz_colors,\ - (n),sizeof(XkbColorRec)) -#define _XkbAllocShapes(g,n) _XkbGeomAlloc((void *)&(g)->shapes,\ - &(g)->num_shapes,&(g)->sz_shapes,\ - (n),sizeof(XkbShapeRec)) -#define _XkbAllocSections(g,n) _XkbGeomAlloc((void *)&(g)->sections,\ - &(g)->num_sections,&(g)->sz_sections,\ - (n),sizeof(XkbSectionRec)) -#define _XkbAllocDoodads(g,n) _XkbGeomAlloc((void *)&(g)->doodads,\ - &(g)->num_doodads,&(g)->sz_doodads,\ - (n),sizeof(XkbDoodadRec)) -#define _XkbAllocKeyAliases(g,n) _XkbGeomAlloc((void *)&(g)->key_aliases,\ - &(g)->num_key_aliases,&(g)->sz_key_aliases,\ - (n),sizeof(XkbKeyAliasRec)) - -#define _XkbAllocOutlines(s,n) _XkbGeomAlloc((void *)&(s)->outlines,\ - &(s)->num_outlines,&(s)->sz_outlines,\ - (n),sizeof(XkbOutlineRec)) -#define _XkbAllocRows(s,n) _XkbGeomAlloc((void *)&(s)->rows,\ - &(s)->num_rows,&(s)->sz_rows,\ - (n),sizeof(XkbRowRec)) -#define _XkbAllocPoints(o,n) _XkbGeomAlloc((void *)&(o)->points,\ - &(o)->num_points,&(o)->sz_points,\ - (n),sizeof(XkbPointRec)) -#define _XkbAllocKeys(r,n) _XkbGeomAlloc((void *)&(r)->keys,\ - &(r)->num_keys,&(r)->sz_keys,\ - (n),sizeof(XkbKeyRec)) -#define _XkbAllocOverlays(s,n) _XkbGeomAlloc((void *)&(s)->overlays,\ - &(s)->num_overlays,&(s)->sz_overlays,\ - (n),sizeof(XkbOverlayRec)) -#define _XkbAllocOverlayRows(o,n) _XkbGeomAlloc((void *)&(o)->rows,\ - &(o)->num_rows,&(o)->sz_rows,\ - (n),sizeof(XkbOverlayRowRec)) -#define _XkbAllocOverlayKeys(r,n) _XkbGeomAlloc((void *)&(r)->keys,\ - &(r)->num_keys,&(r)->sz_keys,\ - (n),sizeof(XkbOverlayKeyRec)) - -Status -XkbAllocGeomProps(XkbGeometryPtr geom,int nProps) -{ - return _XkbAllocProps(geom,nProps); -} - -Status -XkbAllocGeomColors(XkbGeometryPtr geom,int nColors) -{ - return _XkbAllocColors(geom,nColors); -} - -Status -XkbAllocGeomKeyAliases(XkbGeometryPtr geom,int nKeyAliases) -{ - return _XkbAllocKeyAliases(geom,nKeyAliases); -} - -Status -XkbAllocGeomShapes(XkbGeometryPtr geom,int nShapes) -{ - return _XkbAllocShapes(geom,nShapes); -} - -Status -XkbAllocGeomSections(XkbGeometryPtr geom,int nSections) -{ - return _XkbAllocSections(geom,nSections); -} - -Status -XkbAllocGeomOverlays(XkbSectionPtr section,int nOverlays) -{ - return _XkbAllocOverlays(section,nOverlays); -} - -Status -XkbAllocGeomOverlayRows(XkbOverlayPtr overlay,int nRows) -{ - return _XkbAllocOverlayRows(overlay,nRows); -} - -Status -XkbAllocGeomOverlayKeys(XkbOverlayRowPtr row,int nKeys) -{ - return _XkbAllocOverlayKeys(row,nKeys); -} - -Status -XkbAllocGeomDoodads(XkbGeometryPtr geom,int nDoodads) -{ - return _XkbAllocDoodads(geom,nDoodads); -} - -Status -XkbAllocGeomSectionDoodads(XkbSectionPtr section,int nDoodads) -{ - return _XkbAllocDoodads(section,nDoodads); -} - -Status -XkbAllocGeomOutlines(XkbShapePtr shape,int nOL) -{ - return _XkbAllocOutlines(shape,nOL); -} - -Status -XkbAllocGeomRows(XkbSectionPtr section,int nRows) -{ - return _XkbAllocRows(section,nRows); -} - -Status -XkbAllocGeomPoints(XkbOutlinePtr ol,int nPts) -{ - return _XkbAllocPoints(ol,nPts); -} - -Status -XkbAllocGeomKeys(XkbRowPtr row,int nKeys) -{ - return _XkbAllocKeys(row,nKeys); -} - -Status -XkbAllocGeometry(XkbDescPtr xkb,XkbGeometrySizesPtr sizes) -{ -XkbGeometryPtr geom; -Status rtrn; - - if (xkb->geom==NULL) { - xkb->geom= xcalloc(1, sizeof(XkbGeometryRec)); - if (!xkb->geom) - return BadAlloc; - } - geom= xkb->geom; - if ((sizes->which&XkbGeomPropertiesMask)&& - ((rtrn=_XkbAllocProps(geom,sizes->num_properties))!=Success)) { - goto BAIL; - } - if ((sizes->which&XkbGeomColorsMask)&& - ((rtrn=_XkbAllocColors(geom,sizes->num_colors))!=Success)) { - goto BAIL; - } - if ((sizes->which&XkbGeomShapesMask)&& - ((rtrn=_XkbAllocShapes(geom,sizes->num_shapes))!=Success)) { - goto BAIL; - } - if ((sizes->which&XkbGeomSectionsMask)&& - ((rtrn=_XkbAllocSections(geom,sizes->num_sections))!=Success)) { - goto BAIL; - } - if ((sizes->which&XkbGeomDoodadsMask)&& - ((rtrn=_XkbAllocDoodads(geom,sizes->num_doodads))!=Success)) { - goto BAIL; - } - if ((sizes->which&XkbGeomKeyAliasesMask)&& - ((rtrn=_XkbAllocKeyAliases(geom,sizes->num_key_aliases))!=Success)) { - goto BAIL; - } - return Success; -BAIL: - XkbFreeGeometry(geom,XkbGeomAllMask,TRUE); - xkb->geom= NULL; - return rtrn; -} - -/***====================================================================***/ - -XkbPropertyPtr -XkbAddGeomProperty(XkbGeometryPtr geom,char *name,char *value) -{ -register int i; -register XkbPropertyPtr prop; - - if ((!geom)||(!name)||(!value)) - return NULL; - for (i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) { - if ((prop->name)&&(strcmp(name,prop->name)==0)) { - if (prop->value) - xfree(prop->value); - prop->value= xalloc(strlen(value)+1); - if (prop->value) - strcpy(prop->value,value); - return prop; - } - } - if ((geom->num_properties>=geom->sz_properties)&& - (_XkbAllocProps(geom,1)!=Success)) { - return NULL; - } - prop= &geom->properties[geom->num_properties]; - prop->name= xalloc(strlen(name)+1); - if (!name) - return NULL; - strcpy(prop->name,name); - prop->value= xalloc(strlen(value)+1); - if (!value) { - xfree(prop->name); - prop->name= NULL; - return NULL; - } - strcpy(prop->value,value); - geom->num_properties++; - return prop; -} - -XkbKeyAliasPtr -XkbAddGeomKeyAlias(XkbGeometryPtr geom,char *aliasStr,char *realStr) -{ -register int i; -register XkbKeyAliasPtr alias; - - if ((!geom)||(!aliasStr)||(!realStr)||(!aliasStr[0])||(!realStr[0])) - return NULL; - for (i=0,alias=geom->key_aliases;i<geom->num_key_aliases;i++,alias++) { - if (strncmp(alias->alias,aliasStr,XkbKeyNameLength)==0) { - bzero(alias->real,XkbKeyNameLength); - strncpy(alias->real,realStr,XkbKeyNameLength); - return alias; - } - } - if ((geom->num_key_aliases>=geom->sz_key_aliases)&& - (_XkbAllocKeyAliases(geom,1)!=Success)) { - return NULL; - } - alias= &geom->key_aliases[geom->num_key_aliases]; - bzero(alias,sizeof(XkbKeyAliasRec)); - strncpy(alias->alias,aliasStr,XkbKeyNameLength); - strncpy(alias->real,realStr,XkbKeyNameLength); - geom->num_key_aliases++; - return alias; -} - -XkbColorPtr -XkbAddGeomColor(XkbGeometryPtr geom,char *spec,unsigned int pixel) -{ -register int i; -register XkbColorPtr color; - - if ((!geom)||(!spec)) - return NULL; - for (i=0,color=geom->colors;i<geom->num_colors;i++,color++) { - if ((color->spec)&&(strcmp(color->spec,spec)==0)) { - color->pixel= pixel; - return color; - } - } - if ((geom->num_colors>=geom->sz_colors)&& - (_XkbAllocColors(geom,1)!=Success)) { - return NULL; - } - color= &geom->colors[geom->num_colors]; - color->pixel= pixel; - color->spec= xalloc(strlen(spec)+1); - if (!color->spec) - return NULL; - strcpy(color->spec,spec); - geom->num_colors++; - return color; -} - -XkbOutlinePtr -XkbAddGeomOutline(XkbShapePtr shape,int sz_points) -{ -XkbOutlinePtr outline; - - if ((!shape)||(sz_points<0)) - return NULL; - if ((shape->num_outlines>=shape->sz_outlines)&& - (_XkbAllocOutlines(shape,1)!=Success)) { - return NULL; - } - outline= &shape->outlines[shape->num_outlines]; - bzero(outline,sizeof(XkbOutlineRec)); - if ((sz_points>0)&&(_XkbAllocPoints(outline,sz_points)!=Success)) - return NULL; - shape->num_outlines++; - return outline; -} - -XkbShapePtr -XkbAddGeomShape(XkbGeometryPtr geom,Atom name,int sz_outlines) -{ -XkbShapePtr shape; -register int i; - - if ((!geom)||(!name)||(sz_outlines<0)) - return NULL; - if (geom->num_shapes>0) { - for (shape=geom->shapes,i=0;i<geom->num_shapes;i++,shape++) { - if (name==shape->name) - return shape; - } - } - if ((geom->num_shapes>=geom->sz_shapes)&& - (_XkbAllocShapes(geom,1)!=Success)) - return NULL; - shape= &geom->shapes[geom->num_shapes]; - bzero(shape,sizeof(XkbShapeRec)); - if ((sz_outlines>0)&&(_XkbAllocOutlines(shape,sz_outlines)!=Success)) - return NULL; - shape->name= name; - shape->primary= shape->approx= NULL; - geom->num_shapes++; - return shape; -} - -XkbKeyPtr -XkbAddGeomKey(XkbRowPtr row) -{ -XkbKeyPtr key; - if (!row) - return NULL; - if ((row->num_keys>=row->sz_keys)&&(_XkbAllocKeys(row,1)!=Success)) - return NULL; - key= &row->keys[row->num_keys++]; - bzero(key,sizeof(XkbKeyRec)); - return key; -} - -XkbRowPtr -XkbAddGeomRow(XkbSectionPtr section,int sz_keys) -{ -XkbRowPtr row; - - if ((!section)||(sz_keys<0)) - return NULL; - if ((section->num_rows>=section->sz_rows)&& - (_XkbAllocRows(section,1)!=Success)) - return NULL; - row= §ion->rows[section->num_rows]; - bzero(row,sizeof(XkbRowRec)); - if ((sz_keys>0)&&(_XkbAllocKeys(row,sz_keys)!=Success)) - return NULL; - section->num_rows++; - return row; -} - -XkbSectionPtr -XkbAddGeomSection( XkbGeometryPtr geom, - Atom name, - int sz_rows, - int sz_doodads, - int sz_over) -{ -register int i; -XkbSectionPtr section; - - if ((!geom)||(name==None)||(sz_rows<0)) - return NULL; - for (i=0,section=geom->sections;i<geom->num_sections;i++,section++) { - if (section->name!=name) - continue; - if (((sz_rows>0)&&(_XkbAllocRows(section,sz_rows)!=Success))|| - ((sz_doodads>0)&&(_XkbAllocDoodads(section,sz_doodads)!=Success))|| - ((sz_over>0)&&(_XkbAllocOverlays(section,sz_over)!=Success))) - return NULL; - return section; - } - if ((geom->num_sections>=geom->sz_sections)&& - (_XkbAllocSections(geom,1)!=Success)) - return NULL; - section= &geom->sections[geom->num_sections]; - if ((sz_rows>0)&&(_XkbAllocRows(section,sz_rows)!=Success)) - return NULL; - if ((sz_doodads>0)&&(_XkbAllocDoodads(section,sz_doodads)!=Success)) { - if (section->rows) { - xfree(section->rows); - section->rows= NULL; - section->sz_rows= section->num_rows= 0; - } - return NULL; - } - section->name= name; - geom->num_sections++; - return section; -} - -XkbDoodadPtr -XkbAddGeomDoodad(XkbGeometryPtr geom,XkbSectionPtr section,Atom name) -{ -XkbDoodadPtr old,doodad; -register int i,nDoodads; - - if ((!geom)||(name==None)) - return NULL; - if ((section!=NULL)&&(section->num_doodads>0)) { - old= section->doodads; - nDoodads= section->num_doodads; - } - else { - old= geom->doodads; - nDoodads= geom->num_doodads; - } - for (i=0,doodad=old;i<nDoodads;i++,doodad++) { - if (doodad->any.name==name) - return doodad; - } - if (section) { - if ((section->num_doodads>=geom->sz_doodads)&& - (_XkbAllocDoodads(section,1)!=Success)) { - return NULL; - } - doodad= §ion->doodads[section->num_doodads++]; - } - else { - if ((geom->num_doodads>=geom->sz_doodads)&& - (_XkbAllocDoodads(geom,1)!=Success)) - return NULL; - doodad= &geom->doodads[geom->num_doodads++]; - } - bzero(doodad,sizeof(XkbDoodadRec)); - doodad->any.name= name; - return doodad; -} - -XkbOverlayKeyPtr -XkbAddGeomOverlayKey( XkbOverlayPtr overlay, - XkbOverlayRowPtr row, - char * over, - char * under) -{ -register int i; -XkbOverlayKeyPtr key; -XkbSectionPtr section; -XkbRowPtr row_under; -Bool found; - - if ((!overlay)||(!row)||(!over)||(!under)) - return NULL; - section= overlay->section_under; - if (row->row_under>=section->num_rows) - return NULL; - row_under= §ion->rows[row->row_under]; - for (i=0,found=FALSE;i<row_under->num_keys;i++) { - if (strncmp(under,row_under->keys[i].name.name,XkbKeyNameLength)==0) { - found= TRUE; - break; - } - } - if (!found) - return NULL; - if ((row->num_keys>=row->sz_keys)&&(_XkbAllocOverlayKeys(row,1)!=Success)) - return NULL; - key= &row->keys[row->num_keys]; - strncpy(key->under.name,under,XkbKeyNameLength); - strncpy(key->over.name,over,XkbKeyNameLength); - row->num_keys++; - return key; -} - -XkbOverlayRowPtr -XkbAddGeomOverlayRow(XkbOverlayPtr overlay,int row_under,int sz_keys) -{ -register int i; -XkbOverlayRowPtr row; - - if ((!overlay)||(sz_keys<0)) - return NULL; - if (row_under>=overlay->section_under->num_rows) - return NULL; - for (i=0;i<overlay->num_rows;i++) { - if (overlay->rows[i].row_under==row_under) { - row= &overlay->rows[i]; - if ((row->sz_keys<sz_keys)&& - (_XkbAllocOverlayKeys(row,sz_keys)!=Success)) { - return NULL; - } - return &overlay->rows[i]; - } - } - if ((overlay->num_rows>=overlay->sz_rows)&& - (_XkbAllocOverlayRows(overlay,1)!=Success)) - return NULL; - row= &overlay->rows[overlay->num_rows]; - bzero(row,sizeof(XkbOverlayRowRec)); - if ((sz_keys>0)&&(_XkbAllocOverlayKeys(row,sz_keys)!=Success)) - return NULL; - row->row_under= row_under; - overlay->num_rows++; - return row; -} - -XkbOverlayPtr -XkbAddGeomOverlay(XkbSectionPtr section,Atom name,int sz_rows) -{ -register int i; -XkbOverlayPtr overlay; - - if ((!section)||(name==None)||(sz_rows==0)) - return NULL; - - for (i=0,overlay=section->overlays;i<section->num_overlays;i++,overlay++) { - if (overlay->name==name) { - if ((sz_rows>0)&&(_XkbAllocOverlayRows(overlay,sz_rows)!=Success)) - return NULL; - return overlay; - } - } - if ((section->num_overlays>=section->sz_overlays)&& - (_XkbAllocOverlays(section,1)!=Success)) - return NULL; - overlay= §ion->overlays[section->num_overlays]; - if ((sz_rows>0)&&(_XkbAllocOverlayRows(overlay,sz_rows)!=Success)) - return NULL; - overlay->name= name; - overlay->section_under= section; - section->num_overlays++; - return overlay; -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#endif + + +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "inputstr.h" +#include <xkbsrv.h> +#include "xkbgeom.h" + +/***====================================================================***/ + +static void +_XkbFreeGeomLeafElems( Bool freeAll, + int first, + int count, + unsigned short * num_inout, + unsigned short * sz_inout, + char ** elems, + unsigned int elem_sz) +{ + if ((freeAll)||(*elems==NULL)) { + *num_inout= *sz_inout= 0; + if (*elems!=NULL) { + free(*elems); + *elems= NULL; + } + return; + } + + if ((first>=(*num_inout))||(first<0)||(count<1)) + return; + + if (first+count>=(*num_inout)) { + /* truncating the array is easy */ + (*num_inout)= first; + } + else { + char * ptr; + int extra; + ptr= *elems; + extra= ((*num_inout)-(first+count))*elem_sz; + if (extra>0) + memmove(&ptr[first*elem_sz],&ptr[(first+count)*elem_sz],extra); + (*num_inout)-= count; + } + return; +} + +typedef void (*ContentsClearFunc)( + char * /* priv */ +); + +static void +_XkbFreeGeomNonLeafElems( Bool freeAll, + int first, + int count, + unsigned short * num_inout, + unsigned short * sz_inout, + char ** elems, + unsigned int elem_sz, + ContentsClearFunc freeFunc) +{ +register int i; +register char *ptr; + + if (freeAll) { + first= 0; + count= (*num_inout); + } + else if ((first>=(*num_inout))||(first<0)||(count<1)) + return; + else if (first+count>(*num_inout)) + count= (*num_inout)-first; + if (*elems==NULL) + return; + + if (freeFunc) { + ptr= *elems; + ptr+= first*elem_sz; + for (i=0;i<count;i++) { + (*freeFunc)(ptr); + ptr+= elem_sz; + } + } + if (freeAll) { + (*num_inout)= (*sz_inout)= 0; + if (*elems) { + free(*elems); + *elems= NULL; + } + } + else if (first+count>=(*num_inout)) + *num_inout= first; + else { + i= ((*num_inout)-(first+count))*elem_sz; + ptr= *elems; + memmove(&ptr[first*elem_sz],&ptr[(first+count)*elem_sz],i); + (*num_inout)-= count; + } + return; +} + +/***====================================================================***/ + +static void +_XkbClearProperty(char *prop_in) +{ +XkbPropertyPtr prop= (XkbPropertyPtr)prop_in; + + if (prop->name) { + free(prop->name); + prop->name= NULL; + } + if (prop->value) { + free(prop->value); + prop->value= NULL; + } + return; +} + +void +XkbFreeGeomProperties( XkbGeometryPtr geom, + int first, + int count, + Bool freeAll) +{ + _XkbFreeGeomNonLeafElems(freeAll,first,count, + &geom->num_properties,&geom->sz_properties, + (char **)&geom->properties, + sizeof(XkbPropertyRec),_XkbClearProperty); + return; +} + +/***====================================================================***/ + +void +XkbFreeGeomKeyAliases( XkbGeometryPtr geom, + int first, + int count, + Bool freeAll) +{ + _XkbFreeGeomLeafElems(freeAll,first,count, + &geom->num_key_aliases,&geom->sz_key_aliases, + (char **)&geom->key_aliases, + sizeof(XkbKeyAliasRec)); + return; +} + +/***====================================================================***/ + +static void +_XkbClearColor(char *color_in) +{ +XkbColorPtr color= (XkbColorPtr)color_in; + + if (color->spec) + free(color->spec); + return; +} + +void +XkbFreeGeomColors(XkbGeometryPtr geom,int first,int count,Bool freeAll) +{ + _XkbFreeGeomNonLeafElems(freeAll,first,count, + &geom->num_colors,&geom->sz_colors, + (char **)&geom->colors, + sizeof(XkbColorRec),_XkbClearColor); + return; +} + +/***====================================================================***/ + +void +XkbFreeGeomPoints(XkbOutlinePtr outline,int first,int count,Bool freeAll) +{ + _XkbFreeGeomLeafElems(freeAll,first,count, + &outline->num_points,&outline->sz_points, + (char **)&outline->points, + sizeof(XkbPointRec)); + return; +} + +/***====================================================================***/ + +static void +_XkbClearOutline(char *outline_in) +{ +XkbOutlinePtr outline= (XkbOutlinePtr)outline_in; + + if (outline->points!=NULL) + XkbFreeGeomPoints(outline,0,outline->num_points,TRUE); + return; +} + +void +XkbFreeGeomOutlines(XkbShapePtr shape,int first,int count,Bool freeAll) +{ + _XkbFreeGeomNonLeafElems(freeAll,first,count, + &shape->num_outlines,&shape->sz_outlines, + (char **)&shape->outlines, + sizeof(XkbOutlineRec),_XkbClearOutline); + + return; +} + +/***====================================================================***/ + +static void +_XkbClearShape(char *shape_in) +{ +XkbShapePtr shape= (XkbShapePtr)shape_in; + + if (shape->outlines) + XkbFreeGeomOutlines(shape,0,shape->num_outlines,TRUE); + return; +} + +void +XkbFreeGeomShapes(XkbGeometryPtr geom,int first,int count,Bool freeAll) +{ + _XkbFreeGeomNonLeafElems(freeAll,first,count, + &geom->num_shapes,&geom->sz_shapes, + (char **)&geom->shapes, + sizeof(XkbShapeRec),_XkbClearShape); + return; +} + +/***====================================================================***/ + +void +XkbFreeGeomOverlayKeys(XkbOverlayRowPtr row,int first,int count,Bool freeAll) +{ + _XkbFreeGeomLeafElems(freeAll,first,count, + &row->num_keys,&row->sz_keys, + (char **)&row->keys, + sizeof(XkbOverlayKeyRec)); + return; +} + +/***====================================================================***/ + +static void +_XkbClearOverlayRow(char *row_in) +{ +XkbOverlayRowPtr row= (XkbOverlayRowPtr)row_in; + + if (row->keys!=NULL) + XkbFreeGeomOverlayKeys(row,0,row->num_keys,TRUE); + return; +} + +void +XkbFreeGeomOverlayRows(XkbOverlayPtr overlay,int first,int count,Bool freeAll) +{ + _XkbFreeGeomNonLeafElems(freeAll,first,count, + &overlay->num_rows,&overlay->sz_rows, + (char **)&overlay->rows, + sizeof(XkbOverlayRowRec),_XkbClearOverlayRow); + return; +} + +/***====================================================================***/ + +static void +_XkbClearOverlay(char *overlay_in) +{ +XkbOverlayPtr overlay= (XkbOverlayPtr)overlay_in; + + if (overlay->rows!=NULL) + XkbFreeGeomOverlayRows(overlay,0,overlay->num_rows,TRUE); + return; +} + +void +XkbFreeGeomOverlays(XkbSectionPtr section,int first,int count,Bool freeAll) +{ + _XkbFreeGeomNonLeafElems(freeAll,first,count, + §ion->num_overlays,§ion->sz_overlays, + (char **)§ion->overlays, + sizeof(XkbOverlayRec),_XkbClearOverlay); + return; +} + +/***====================================================================***/ + +void +XkbFreeGeomKeys(XkbRowPtr row,int first,int count,Bool freeAll) +{ + _XkbFreeGeomLeafElems(freeAll,first,count, + &row->num_keys,&row->sz_keys, + (char **)&row->keys, + sizeof(XkbKeyRec)); + return; +} + +/***====================================================================***/ + +static void +_XkbClearRow(char *row_in) +{ +XkbRowPtr row= (XkbRowPtr)row_in; + + if (row->keys!=NULL) + XkbFreeGeomKeys(row,0,row->num_keys,TRUE); + return; +} + +void +XkbFreeGeomRows(XkbSectionPtr section,int first,int count,Bool freeAll) +{ + _XkbFreeGeomNonLeafElems(freeAll,first,count, + §ion->num_rows,§ion->sz_rows, + (char **)§ion->rows, + sizeof(XkbRowRec),_XkbClearRow); +} + +/***====================================================================***/ + +static void +_XkbClearSection(char *section_in) +{ +XkbSectionPtr section= (XkbSectionPtr)section_in; + + if (section->rows!=NULL) + XkbFreeGeomRows(section,0,section->num_rows,TRUE); + if (section->doodads!=NULL) { + XkbFreeGeomDoodads(section->doodads,section->num_doodads,TRUE); + section->doodads= NULL; + } + return; +} + +void +XkbFreeGeomSections(XkbGeometryPtr geom,int first,int count,Bool freeAll) +{ + _XkbFreeGeomNonLeafElems(freeAll,first,count, + &geom->num_sections,&geom->sz_sections, + (char **)&geom->sections, + sizeof(XkbSectionRec),_XkbClearSection); + return; +} + +/***====================================================================***/ + +static void +_XkbClearDoodad(char *doodad_in) +{ +XkbDoodadPtr doodad= (XkbDoodadPtr)doodad_in; + + switch (doodad->any.type) { + case XkbTextDoodad: + { + if (doodad->text.text!=NULL) { + free(doodad->text.text); + doodad->text.text= NULL; + } + if (doodad->text.font!=NULL) { + free(doodad->text.font); + doodad->text.font= NULL; + } + } + break; + case XkbLogoDoodad: + { + if (doodad->logo.logo_name!=NULL) { + free(doodad->logo.logo_name); + doodad->logo.logo_name= NULL; + } + } + break; + } + return; +} + +void +XkbFreeGeomDoodads(XkbDoodadPtr doodads,int nDoodads,Bool freeAll) +{ +register int i; +register XkbDoodadPtr doodad; + + if (doodads) { + for (i=0,doodad= doodads;i<nDoodads;i++,doodad++) { + _XkbClearDoodad((char *)doodad); + } + if (freeAll) + free(doodads); + } + return; +} + +void +XkbFreeGeometry(XkbGeometryPtr geom,unsigned which,Bool freeMap) +{ + if (geom==NULL) + return; + if (freeMap) + which= XkbGeomAllMask; + if ((which&XkbGeomPropertiesMask)&&(geom->properties!=NULL)) + XkbFreeGeomProperties(geom,0,geom->num_properties,TRUE); + if ((which&XkbGeomColorsMask)&&(geom->colors!=NULL)) + XkbFreeGeomColors(geom,0,geom->num_colors,TRUE); + if ((which&XkbGeomShapesMask)&&(geom->shapes!=NULL)) + XkbFreeGeomShapes(geom,0,geom->num_shapes,TRUE); + if ((which&XkbGeomSectionsMask)&&(geom->sections!=NULL)) + XkbFreeGeomSections(geom,0,geom->num_sections,TRUE); + if ((which&XkbGeomDoodadsMask)&&(geom->doodads!= NULL)) { + XkbFreeGeomDoodads(geom->doodads,geom->num_doodads,TRUE); + geom->doodads= NULL; + geom->num_doodads= geom->sz_doodads= 0; + } + if ((which&XkbGeomKeyAliasesMask)&&(geom->key_aliases!=NULL)) + XkbFreeGeomKeyAliases(geom,0,geom->num_key_aliases,TRUE); + if (freeMap) { + if (geom->label_font!=NULL) { + free(geom->label_font); + geom->label_font= NULL; + } + free(geom); + } + return; +} + +/***====================================================================***/ + +static Status +_XkbGeomAlloc( void ** old, + unsigned short * num, + unsigned short * total, + int num_new, + size_t sz_elem) +{ + if (num_new<1) + return Success; + if ((*old)==NULL) + *num= *total= 0; + + if ((*num)+num_new<=(*total)) + return Success; + + *total= (*num)+num_new; + if ((*old)!=NULL) + (*old)= realloc((*old),(*total)*sz_elem); + else (*old)= calloc((*total),sz_elem); + if ((*old)==NULL) { + *total= *num= 0; + return BadAlloc; + } + + if (*num>0) { + char *tmp= (char *)(*old); + bzero(&tmp[sz_elem*(*num)],(num_new*sz_elem)); + } + return Success; +} + +#define _XkbAllocProps(g,n) _XkbGeomAlloc((void *)&(g)->properties,\ + &(g)->num_properties,&(g)->sz_properties,\ + (n),sizeof(XkbPropertyRec)) +#define _XkbAllocColors(g,n) _XkbGeomAlloc((void *)&(g)->colors,\ + &(g)->num_colors,&(g)->sz_colors,\ + (n),sizeof(XkbColorRec)) +#define _XkbAllocShapes(g,n) _XkbGeomAlloc((void *)&(g)->shapes,\ + &(g)->num_shapes,&(g)->sz_shapes,\ + (n),sizeof(XkbShapeRec)) +#define _XkbAllocSections(g,n) _XkbGeomAlloc((void *)&(g)->sections,\ + &(g)->num_sections,&(g)->sz_sections,\ + (n),sizeof(XkbSectionRec)) +#define _XkbAllocDoodads(g,n) _XkbGeomAlloc((void *)&(g)->doodads,\ + &(g)->num_doodads,&(g)->sz_doodads,\ + (n),sizeof(XkbDoodadRec)) +#define _XkbAllocKeyAliases(g,n) _XkbGeomAlloc((void *)&(g)->key_aliases,\ + &(g)->num_key_aliases,&(g)->sz_key_aliases,\ + (n),sizeof(XkbKeyAliasRec)) + +#define _XkbAllocOutlines(s,n) _XkbGeomAlloc((void *)&(s)->outlines,\ + &(s)->num_outlines,&(s)->sz_outlines,\ + (n),sizeof(XkbOutlineRec)) +#define _XkbAllocRows(s,n) _XkbGeomAlloc((void *)&(s)->rows,\ + &(s)->num_rows,&(s)->sz_rows,\ + (n),sizeof(XkbRowRec)) +#define _XkbAllocPoints(o,n) _XkbGeomAlloc((void *)&(o)->points,\ + &(o)->num_points,&(o)->sz_points,\ + (n),sizeof(XkbPointRec)) +#define _XkbAllocKeys(r,n) _XkbGeomAlloc((void *)&(r)->keys,\ + &(r)->num_keys,&(r)->sz_keys,\ + (n),sizeof(XkbKeyRec)) +#define _XkbAllocOverlays(s,n) _XkbGeomAlloc((void *)&(s)->overlays,\ + &(s)->num_overlays,&(s)->sz_overlays,\ + (n),sizeof(XkbOverlayRec)) +#define _XkbAllocOverlayRows(o,n) _XkbGeomAlloc((void *)&(o)->rows,\ + &(o)->num_rows,&(o)->sz_rows,\ + (n),sizeof(XkbOverlayRowRec)) +#define _XkbAllocOverlayKeys(r,n) _XkbGeomAlloc((void *)&(r)->keys,\ + &(r)->num_keys,&(r)->sz_keys,\ + (n),sizeof(XkbOverlayKeyRec)) + +Status +XkbAllocGeomProps(XkbGeometryPtr geom,int nProps) +{ + return _XkbAllocProps(geom,nProps); +} + +Status +XkbAllocGeomColors(XkbGeometryPtr geom,int nColors) +{ + return _XkbAllocColors(geom,nColors); +} + +Status +XkbAllocGeomKeyAliases(XkbGeometryPtr geom,int nKeyAliases) +{ + return _XkbAllocKeyAliases(geom,nKeyAliases); +} + +Status +XkbAllocGeomShapes(XkbGeometryPtr geom,int nShapes) +{ + return _XkbAllocShapes(geom,nShapes); +} + +Status +XkbAllocGeomSections(XkbGeometryPtr geom,int nSections) +{ + return _XkbAllocSections(geom,nSections); +} + +Status +XkbAllocGeomOverlays(XkbSectionPtr section,int nOverlays) +{ + return _XkbAllocOverlays(section,nOverlays); +} + +Status +XkbAllocGeomOverlayRows(XkbOverlayPtr overlay,int nRows) +{ + return _XkbAllocOverlayRows(overlay,nRows); +} + +Status +XkbAllocGeomOverlayKeys(XkbOverlayRowPtr row,int nKeys) +{ + return _XkbAllocOverlayKeys(row,nKeys); +} + +Status +XkbAllocGeomDoodads(XkbGeometryPtr geom,int nDoodads) +{ + return _XkbAllocDoodads(geom,nDoodads); +} + +Status +XkbAllocGeomSectionDoodads(XkbSectionPtr section,int nDoodads) +{ + return _XkbAllocDoodads(section,nDoodads); +} + +Status +XkbAllocGeomOutlines(XkbShapePtr shape,int nOL) +{ + return _XkbAllocOutlines(shape,nOL); +} + +Status +XkbAllocGeomRows(XkbSectionPtr section,int nRows) +{ + return _XkbAllocRows(section,nRows); +} + +Status +XkbAllocGeomPoints(XkbOutlinePtr ol,int nPts) +{ + return _XkbAllocPoints(ol,nPts); +} + +Status +XkbAllocGeomKeys(XkbRowPtr row,int nKeys) +{ + return _XkbAllocKeys(row,nKeys); +} + +Status +XkbAllocGeometry(XkbDescPtr xkb,XkbGeometrySizesPtr sizes) +{ +XkbGeometryPtr geom; +Status rtrn; + + if (xkb->geom==NULL) { + xkb->geom= calloc(1, sizeof(XkbGeometryRec)); + if (!xkb->geom) + return BadAlloc; + } + geom= xkb->geom; + if ((sizes->which&XkbGeomPropertiesMask)&& + ((rtrn=_XkbAllocProps(geom,sizes->num_properties))!=Success)) { + goto BAIL; + } + if ((sizes->which&XkbGeomColorsMask)&& + ((rtrn=_XkbAllocColors(geom,sizes->num_colors))!=Success)) { + goto BAIL; + } + if ((sizes->which&XkbGeomShapesMask)&& + ((rtrn=_XkbAllocShapes(geom,sizes->num_shapes))!=Success)) { + goto BAIL; + } + if ((sizes->which&XkbGeomSectionsMask)&& + ((rtrn=_XkbAllocSections(geom,sizes->num_sections))!=Success)) { + goto BAIL; + } + if ((sizes->which&XkbGeomDoodadsMask)&& + ((rtrn=_XkbAllocDoodads(geom,sizes->num_doodads))!=Success)) { + goto BAIL; + } + if ((sizes->which&XkbGeomKeyAliasesMask)&& + ((rtrn=_XkbAllocKeyAliases(geom,sizes->num_key_aliases))!=Success)) { + goto BAIL; + } + return Success; +BAIL: + XkbFreeGeometry(geom,XkbGeomAllMask,TRUE); + xkb->geom= NULL; + return rtrn; +} + +/***====================================================================***/ + +XkbPropertyPtr +XkbAddGeomProperty(XkbGeometryPtr geom,char *name,char *value) +{ +register int i; +register XkbPropertyPtr prop; + + if ((!geom)||(!name)||(!value)) + return NULL; + for (i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) { + if ((prop->name)&&(strcmp(name,prop->name)==0)) { + if (prop->value) + free(prop->value); + prop->value= malloc(strlen(value)+1); + if (prop->value) + strcpy(prop->value,value); + return prop; + } + } + if ((geom->num_properties>=geom->sz_properties)&& + (_XkbAllocProps(geom,1)!=Success)) { + return NULL; + } + prop= &geom->properties[geom->num_properties]; + prop->name= malloc(strlen(name)+1); + if (!name) + return NULL; + strcpy(prop->name,name); + prop->value= malloc(strlen(value)+1); + if (!value) { + free(prop->name); + prop->name= NULL; + return NULL; + } + strcpy(prop->value,value); + geom->num_properties++; + return prop; +} + +XkbKeyAliasPtr +XkbAddGeomKeyAlias(XkbGeometryPtr geom,char *aliasStr,char *realStr) +{ +register int i; +register XkbKeyAliasPtr alias; + + if ((!geom)||(!aliasStr)||(!realStr)||(!aliasStr[0])||(!realStr[0])) + return NULL; + for (i=0,alias=geom->key_aliases;i<geom->num_key_aliases;i++,alias++) { + if (strncmp(alias->alias,aliasStr,XkbKeyNameLength)==0) { + bzero(alias->real,XkbKeyNameLength); + strncpy(alias->real,realStr,XkbKeyNameLength); + return alias; + } + } + if ((geom->num_key_aliases>=geom->sz_key_aliases)&& + (_XkbAllocKeyAliases(geom,1)!=Success)) { + return NULL; + } + alias= &geom->key_aliases[geom->num_key_aliases]; + bzero(alias,sizeof(XkbKeyAliasRec)); + strncpy(alias->alias,aliasStr,XkbKeyNameLength); + strncpy(alias->real,realStr,XkbKeyNameLength); + geom->num_key_aliases++; + return alias; +} + +XkbColorPtr +XkbAddGeomColor(XkbGeometryPtr geom,char *spec,unsigned int pixel) +{ +register int i; +register XkbColorPtr color; + + if ((!geom)||(!spec)) + return NULL; + for (i=0,color=geom->colors;i<geom->num_colors;i++,color++) { + if ((color->spec)&&(strcmp(color->spec,spec)==0)) { + color->pixel= pixel; + return color; + } + } + if ((geom->num_colors>=geom->sz_colors)&& + (_XkbAllocColors(geom,1)!=Success)) { + return NULL; + } + color= &geom->colors[geom->num_colors]; + color->pixel= pixel; + color->spec= malloc(strlen(spec)+1); + if (!color->spec) + return NULL; + strcpy(color->spec,spec); + geom->num_colors++; + return color; +} + +XkbOutlinePtr +XkbAddGeomOutline(XkbShapePtr shape,int sz_points) +{ +XkbOutlinePtr outline; + + if ((!shape)||(sz_points<0)) + return NULL; + if ((shape->num_outlines>=shape->sz_outlines)&& + (_XkbAllocOutlines(shape,1)!=Success)) { + return NULL; + } + outline= &shape->outlines[shape->num_outlines]; + bzero(outline,sizeof(XkbOutlineRec)); + if ((sz_points>0)&&(_XkbAllocPoints(outline,sz_points)!=Success)) + return NULL; + shape->num_outlines++; + return outline; +} + +XkbShapePtr +XkbAddGeomShape(XkbGeometryPtr geom,Atom name,int sz_outlines) +{ +XkbShapePtr shape; +register int i; + + if ((!geom)||(!name)||(sz_outlines<0)) + return NULL; + if (geom->num_shapes>0) { + for (shape=geom->shapes,i=0;i<geom->num_shapes;i++,shape++) { + if (name==shape->name) + return shape; + } + } + if ((geom->num_shapes>=geom->sz_shapes)&& + (_XkbAllocShapes(geom,1)!=Success)) + return NULL; + shape= &geom->shapes[geom->num_shapes]; + bzero(shape,sizeof(XkbShapeRec)); + if ((sz_outlines>0)&&(_XkbAllocOutlines(shape,sz_outlines)!=Success)) + return NULL; + shape->name= name; + shape->primary= shape->approx= NULL; + geom->num_shapes++; + return shape; +} + +XkbKeyPtr +XkbAddGeomKey(XkbRowPtr row) +{ +XkbKeyPtr key; + if (!row) + return NULL; + if ((row->num_keys>=row->sz_keys)&&(_XkbAllocKeys(row,1)!=Success)) + return NULL; + key= &row->keys[row->num_keys++]; + bzero(key,sizeof(XkbKeyRec)); + return key; +} + +XkbRowPtr +XkbAddGeomRow(XkbSectionPtr section,int sz_keys) +{ +XkbRowPtr row; + + if ((!section)||(sz_keys<0)) + return NULL; + if ((section->num_rows>=section->sz_rows)&& + (_XkbAllocRows(section,1)!=Success)) + return NULL; + row= §ion->rows[section->num_rows]; + bzero(row,sizeof(XkbRowRec)); + if ((sz_keys>0)&&(_XkbAllocKeys(row,sz_keys)!=Success)) + return NULL; + section->num_rows++; + return row; +} + +XkbSectionPtr +XkbAddGeomSection( XkbGeometryPtr geom, + Atom name, + int sz_rows, + int sz_doodads, + int sz_over) +{ +register int i; +XkbSectionPtr section; + + if ((!geom)||(name==None)||(sz_rows<0)) + return NULL; + for (i=0,section=geom->sections;i<geom->num_sections;i++,section++) { + if (section->name!=name) + continue; + if (((sz_rows>0)&&(_XkbAllocRows(section,sz_rows)!=Success))|| + ((sz_doodads>0)&&(_XkbAllocDoodads(section,sz_doodads)!=Success))|| + ((sz_over>0)&&(_XkbAllocOverlays(section,sz_over)!=Success))) + return NULL; + return section; + } + if ((geom->num_sections>=geom->sz_sections)&& + (_XkbAllocSections(geom,1)!=Success)) + return NULL; + section= &geom->sections[geom->num_sections]; + if ((sz_rows>0)&&(_XkbAllocRows(section,sz_rows)!=Success)) + return NULL; + if ((sz_doodads>0)&&(_XkbAllocDoodads(section,sz_doodads)!=Success)) { + if (section->rows) { + free(section->rows); + section->rows= NULL; + section->sz_rows= section->num_rows= 0; + } + return NULL; + } + section->name= name; + geom->num_sections++; + return section; +} + +XkbDoodadPtr +XkbAddGeomDoodad(XkbGeometryPtr geom,XkbSectionPtr section,Atom name) +{ +XkbDoodadPtr old,doodad; +register int i,nDoodads; + + if ((!geom)||(name==None)) + return NULL; + if ((section!=NULL)&&(section->num_doodads>0)) { + old= section->doodads; + nDoodads= section->num_doodads; + } + else { + old= geom->doodads; + nDoodads= geom->num_doodads; + } + for (i=0,doodad=old;i<nDoodads;i++,doodad++) { + if (doodad->any.name==name) + return doodad; + } + if (section) { + if ((section->num_doodads>=geom->sz_doodads)&& + (_XkbAllocDoodads(section,1)!=Success)) { + return NULL; + } + doodad= §ion->doodads[section->num_doodads++]; + } + else { + if ((geom->num_doodads>=geom->sz_doodads)&& + (_XkbAllocDoodads(geom,1)!=Success)) + return NULL; + doodad= &geom->doodads[geom->num_doodads++]; + } + bzero(doodad,sizeof(XkbDoodadRec)); + doodad->any.name= name; + return doodad; +} + +XkbOverlayKeyPtr +XkbAddGeomOverlayKey( XkbOverlayPtr overlay, + XkbOverlayRowPtr row, + char * over, + char * under) +{ +register int i; +XkbOverlayKeyPtr key; +XkbSectionPtr section; +XkbRowPtr row_under; +Bool found; + + if ((!overlay)||(!row)||(!over)||(!under)) + return NULL; + section= overlay->section_under; + if (row->row_under>=section->num_rows) + return NULL; + row_under= §ion->rows[row->row_under]; + for (i=0,found=FALSE;i<row_under->num_keys;i++) { + if (strncmp(under,row_under->keys[i].name.name,XkbKeyNameLength)==0) { + found= TRUE; + break; + } + } + if (!found) + return NULL; + if ((row->num_keys>=row->sz_keys)&&(_XkbAllocOverlayKeys(row,1)!=Success)) + return NULL; + key= &row->keys[row->num_keys]; + strncpy(key->under.name,under,XkbKeyNameLength); + strncpy(key->over.name,over,XkbKeyNameLength); + row->num_keys++; + return key; +} + +XkbOverlayRowPtr +XkbAddGeomOverlayRow(XkbOverlayPtr overlay,int row_under,int sz_keys) +{ +register int i; +XkbOverlayRowPtr row; + + if ((!overlay)||(sz_keys<0)) + return NULL; + if (row_under>=overlay->section_under->num_rows) + return NULL; + for (i=0;i<overlay->num_rows;i++) { + if (overlay->rows[i].row_under==row_under) { + row= &overlay->rows[i]; + if ((row->sz_keys<sz_keys)&& + (_XkbAllocOverlayKeys(row,sz_keys)!=Success)) { + return NULL; + } + return &overlay->rows[i]; + } + } + if ((overlay->num_rows>=overlay->sz_rows)&& + (_XkbAllocOverlayRows(overlay,1)!=Success)) + return NULL; + row= &overlay->rows[overlay->num_rows]; + bzero(row,sizeof(XkbOverlayRowRec)); + if ((sz_keys>0)&&(_XkbAllocOverlayKeys(row,sz_keys)!=Success)) + return NULL; + row->row_under= row_under; + overlay->num_rows++; + return row; +} + +XkbOverlayPtr +XkbAddGeomOverlay(XkbSectionPtr section,Atom name,int sz_rows) +{ +register int i; +XkbOverlayPtr overlay; + + if ((!section)||(name==None)||(sz_rows==0)) + return NULL; + + for (i=0,overlay=section->overlays;i<section->num_overlays;i++,overlay++) { + if (overlay->name==name) { + if ((sz_rows>0)&&(_XkbAllocOverlayRows(overlay,sz_rows)!=Success)) + return NULL; + return overlay; + } + } + if ((section->num_overlays>=section->sz_overlays)&& + (_XkbAllocOverlays(section,1)!=Success)) + return NULL; + overlay= §ion->overlays[section->num_overlays]; + if ((sz_rows>0)&&(_XkbAllocOverlayRows(overlay,sz_rows)!=Success)) + return NULL; + overlay->name= name; + overlay->section_under= section; + section->num_overlays++; + return overlay; +} diff --git a/xorg-server/xkb/XKBMAlloc.c b/xorg-server/xkb/XKBMAlloc.c index fd12e2b6c..34e52835d 100644 --- a/xorg-server/xkb/XKBMAlloc.c +++ b/xorg-server/xkb/XKBMAlloc.c @@ -1,900 +1,900 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#elif defined(HAVE_CONFIG_H) -#include <config.h> -#endif - -#include <stdio.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "inputstr.h" -#include <X11/keysym.h> -#define XKBSRV_NEED_FILE_FUNCS -#include <xkbsrv.h> - -/***====================================================================***/ - -Status -XkbAllocClientMap(XkbDescPtr xkb,unsigned which,unsigned nTotalTypes) -{ -register int i; -XkbClientMapPtr map; - - if ((xkb==NULL)||((nTotalTypes>0)&&(nTotalTypes<XkbNumRequiredTypes))) - return BadValue; - if ((which&XkbKeySymsMask)&& - ((!XkbIsLegalKeycode(xkb->min_key_code))|| - (!XkbIsLegalKeycode(xkb->max_key_code))|| - (xkb->max_key_code<xkb->min_key_code))) { - DebugF("bad keycode (%d,%d) in XkbAllocClientMap\n", - xkb->min_key_code,xkb->max_key_code); - return BadValue; - } - - if (xkb->map==NULL) { - map= xcalloc(1, sizeof(XkbClientMapRec)); - if (map==NULL) - return BadAlloc; - xkb->map= map; - } - else map= xkb->map; - - if ((which&XkbKeyTypesMask)&&(nTotalTypes>0)) { - if (map->types==NULL) { - map->types= xcalloc(nTotalTypes, sizeof(XkbKeyTypeRec)); - if (map->types==NULL) - return BadAlloc; - map->num_types= 0; - map->size_types= nTotalTypes; - } - else if (map->size_types<nTotalTypes) { - XkbKeyTypeRec *prev_types = map->types; - - map->types= xrealloc(map->types,nTotalTypes * sizeof(XkbKeyTypeRec)); - if (map->types==NULL) { - xfree(prev_types); - map->num_types= map->size_types= 0; - return BadAlloc; - } - map->size_types= nTotalTypes; - bzero(&map->types[map->num_types], - ((map->size_types-map->num_types)*sizeof(XkbKeyTypeRec))); - } - } - if (which&XkbKeySymsMask) { - int nKeys= XkbNumKeys(xkb); - if (map->syms==NULL) { - map->size_syms= (nKeys*15)/10; - map->syms= xcalloc(map->size_syms, sizeof(KeySym)); - if (!map->syms) { - map->size_syms= 0; - return BadAlloc; - } - map->num_syms= 1; - map->syms[0]= NoSymbol; - } - if (map->key_sym_map==NULL) { - i= xkb->max_key_code+1; - map->key_sym_map= xcalloc(i, sizeof(XkbSymMapRec)); - if (map->key_sym_map==NULL) - return BadAlloc; - } - } - if (which&XkbModifierMapMask) { - if ((!XkbIsLegalKeycode(xkb->min_key_code))|| - (!XkbIsLegalKeycode(xkb->max_key_code))|| - (xkb->max_key_code<xkb->min_key_code)) - return BadMatch; - if (map->modmap==NULL) { - i= xkb->max_key_code+1; - map->modmap= xcalloc(i, sizeof(unsigned char)); - if (map->modmap==NULL) - return BadAlloc; - } - } - return Success; -} - -Status -XkbAllocServerMap(XkbDescPtr xkb,unsigned which,unsigned nNewActions) -{ -register int i; -XkbServerMapPtr map; - - if (xkb==NULL) - return BadMatch; - if (xkb->server==NULL) { - map= xcalloc(1, sizeof(XkbServerMapRec)); - if (map==NULL) - return BadAlloc; - for (i=0;i<XkbNumVirtualMods;i++) { - map->vmods[i]= XkbNoModifierMask; - } - xkb->server= map; - } - else map= xkb->server; - if (which&XkbExplicitComponentsMask) { - if ((!XkbIsLegalKeycode(xkb->min_key_code))|| - (!XkbIsLegalKeycode(xkb->max_key_code))|| - (xkb->max_key_code<xkb->min_key_code)) - return BadMatch; - if (map->explicit==NULL) { - i= xkb->max_key_code+1; - map->explicit= xcalloc(i, sizeof(unsigned char)); - if (map->explicit==NULL) - return BadAlloc; - } - } - if (which&XkbKeyActionsMask) { - if ((!XkbIsLegalKeycode(xkb->min_key_code))|| - (!XkbIsLegalKeycode(xkb->max_key_code))|| - (xkb->max_key_code<xkb->min_key_code)) - return BadMatch; - if (nNewActions<1) - nNewActions= 1; - if (map->acts==NULL) { - map->acts= xcalloc((nNewActions+1), sizeof(XkbAction)); - if (map->acts==NULL) - return BadAlloc; - map->num_acts= 1; - map->size_acts= nNewActions+1; - } - else if ((map->size_acts-map->num_acts)<nNewActions) { - unsigned need; - XkbAction *prev_acts = map->acts; - need= map->num_acts+nNewActions; - map->acts= xrealloc(map->acts,need * sizeof(XkbAction)); - if (map->acts==NULL) { - xfree(prev_acts); - map->num_acts= map->size_acts= 0; - return BadAlloc; - } - map->size_acts= need; - bzero(&map->acts[map->num_acts], - ((map->size_acts-map->num_acts)*sizeof(XkbAction))); - } - if (map->key_acts==NULL) { - i= xkb->max_key_code+1; - map->key_acts= xcalloc(i, sizeof(unsigned short)); - if (map->key_acts==NULL) - return BadAlloc; - } - } - if (which&XkbKeyBehaviorsMask) { - if ((!XkbIsLegalKeycode(xkb->min_key_code))|| - (!XkbIsLegalKeycode(xkb->max_key_code))|| - (xkb->max_key_code<xkb->min_key_code)) - return BadMatch; - if (map->behaviors==NULL) { - i= xkb->max_key_code+1; - map->behaviors= xcalloc(i, sizeof(XkbBehavior)); - if (map->behaviors==NULL) - return BadAlloc; - } - } - if (which&XkbVirtualModMapMask) { - if ((!XkbIsLegalKeycode(xkb->min_key_code))|| - (!XkbIsLegalKeycode(xkb->max_key_code))|| - (xkb->max_key_code<xkb->min_key_code)) - return BadMatch; - if (map->vmodmap==NULL) { - i= xkb->max_key_code+1; - map->vmodmap= xcalloc(i, sizeof(unsigned short)); - if (map->vmodmap==NULL) - return BadAlloc; - } - } - return Success; -} - -/***====================================================================***/ - -static Status -XkbCopyKeyType(XkbKeyTypePtr from,XkbKeyTypePtr into) -{ - if ((!from)||(!into)) - return BadMatch; - if (into->map) { - xfree(into->map); - into->map= NULL; - } - if (into->preserve) { - xfree(into->preserve); - into->preserve= NULL; - } - if (into->level_names) { - xfree(into->level_names); - into->level_names= NULL; - } - *into= *from; - if ((from->map)&&(into->map_count>0)) { - into->map= xcalloc(into->map_count, sizeof(XkbKTMapEntryRec)); - if (!into->map) - return BadAlloc; - memcpy(into->map,from->map,into->map_count*sizeof(XkbKTMapEntryRec)); - } - if ((from->preserve)&&(into->map_count>0)) { - into->preserve= xcalloc(into->map_count, sizeof(XkbModsRec)); - if (!into->preserve) - return BadAlloc; - memcpy(into->preserve,from->preserve, - into->map_count*sizeof(XkbModsRec)); - } - if ((from->level_names)&&(into->num_levels>0)) { - into->level_names= xcalloc(into->num_levels, sizeof(Atom)); - if (!into->level_names) - return BadAlloc; - memcpy(into->level_names,from->level_names, - into->num_levels*sizeof(Atom)); - } - return Success; -} - -Status -XkbCopyKeyTypes(XkbKeyTypePtr from,XkbKeyTypePtr into,int num_types) -{ -register int i,rtrn; - - if ((!from)||(!into)||(num_types<0)) - return BadMatch; - for (i=0;i<num_types;i++) { - if ((rtrn= XkbCopyKeyType(from++,into++))!=Success) - return rtrn; - } - return Success; -} - -Status -XkbResizeKeyType( XkbDescPtr xkb, - int type_ndx, - int map_count, - Bool want_preserve, - int new_num_lvls) -{ -XkbKeyTypePtr type; -KeyCode matchingKeys[XkbMaxKeyCount],nMatchingKeys; - - if ((type_ndx<0)||(type_ndx>=xkb->map->num_types)||(map_count<0)|| - (new_num_lvls<1)) - return BadValue; - switch (type_ndx) { - case XkbOneLevelIndex: - if (new_num_lvls!=1) - return BadMatch; - break; - case XkbTwoLevelIndex: - case XkbAlphabeticIndex: - case XkbKeypadIndex: - if (new_num_lvls!=2) - return BadMatch; - break; - } - type= &xkb->map->types[type_ndx]; - if (map_count==0) { - if (type->map!=NULL) - xfree(type->map); - type->map= NULL; - if (type->preserve!=NULL) - xfree(type->preserve); - type->preserve= NULL; - type->map_count= 0; - } - else { - XkbKTMapEntryRec *prev_map = type->map; - - if ((map_count>type->map_count)||(type->map==NULL)) - type->map = xrealloc(type->map,map_count * sizeof(XkbKTMapEntryRec)); - if (!type->map) { - if (prev_map) - xfree(prev_map); - return BadAlloc; - } - if (want_preserve) { - XkbModsRec *prev_preserve = type->preserve; - - if ((map_count>type->map_count)||(type->preserve==NULL)) { - type->preserve = xrealloc(type->preserve, - map_count * sizeof(XkbModsRec)); - } - if (!type->preserve) { - if (prev_preserve) - xfree(prev_preserve); - return BadAlloc; - } - } - else if (type->preserve!=NULL) { - xfree(type->preserve); - type->preserve= NULL; - } - type->map_count= map_count; - } - - if ((new_num_lvls>type->num_levels)||(type->level_names==NULL)) { - Atom * prev_level_names = type->level_names; - - type->level_names = xrealloc(type->level_names, - new_num_lvls * sizeof(Atom)); - if (!type->level_names) { - if (prev_level_names) - xfree(prev_level_names); - return BadAlloc; - } - } - /* - * Here's the theory: - * If the width of the type changed, we might have to resize the symbol - * maps for any keys that use the type for one or more groups. This is - * expensive, so we'll try to cull out any keys that are obviously okay: - * In any case: - * - keys that have a group width <= the old width are okay (because - * they could not possibly have been associated with the old type) - * If the key type increased in size: - * - keys that already have a group width >= to the new width are okay - * + keys that have a group width >= the old width but < the new width - * might have to be enlarged. - * If the key type decreased in size: - * - keys that have a group width > the old width don't have to be - * resized (because they must have some other wider type associated - * with some group). - * + keys that have a group width == the old width might have to be - * shrunk. - * The possibilities marked with '+' require us to examine the key types - * associated with each group for the key. - */ - bzero(matchingKeys,XkbMaxKeyCount*sizeof(KeyCode)); - nMatchingKeys= 0; - if (new_num_lvls>type->num_levels) { - int nTotal; - KeySym * newSyms; - int width,match,nResize; - register int i,g,nSyms; - - nResize= 0; - for (nTotal=1,i=xkb->min_key_code;i<=xkb->max_key_code;i++) { - width= XkbKeyGroupsWidth(xkb,i); - if (width<type->num_levels) - continue; - for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) { - if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) { - matchingKeys[nMatchingKeys++]= i; - match= 1; - } - } - if ((!match)||(width>=new_num_lvls)) - nTotal+= XkbKeyNumSyms(xkb,i); - else { - nTotal+= XkbKeyNumGroups(xkb,i)*new_num_lvls; - nResize++; - } - } - if (nResize>0) { - int nextMatch; - xkb->map->size_syms= (nTotal*15)/10; - newSyms = xcalloc(xkb->map->size_syms, sizeof(KeySym)); - if (newSyms==NULL) - return BadAlloc; - nextMatch= 0; - nSyms= 1; - for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { - if (matchingKeys[nextMatch]==i) { - KeySym *pOld; - nextMatch++; - width= XkbKeyGroupsWidth(xkb,i); - pOld= XkbKeySymsPtr(xkb,i); - for (g=XkbKeyNumGroups(xkb,i)-1;g>=0;g--) { - memcpy(&newSyms[nSyms+(new_num_lvls*g)],&pOld[width*g], - width*sizeof(KeySym)); - } - xkb->map->key_sym_map[i].offset= nSyms; - nSyms+= XkbKeyNumGroups(xkb,i)*new_num_lvls; - } - else { - memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i), - XkbKeyNumSyms(xkb,i)*sizeof(KeySym)); - xkb->map->key_sym_map[i].offset= nSyms; - nSyms+= XkbKeyNumSyms(xkb,i); - } - } - type->num_levels= new_num_lvls; - xfree(xkb->map->syms); - xkb->map->syms= newSyms; - xkb->map->num_syms= nSyms; - return Success; - } - } - else if (new_num_lvls<type->num_levels) { - int width,match; - register int g,i; - for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { - width= XkbKeyGroupsWidth(xkb,i); - if (width<type->num_levels) - continue; - for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) { - if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) { - matchingKeys[nMatchingKeys++]= i; - match= 1; - } - } - } - } - if (nMatchingKeys>0) { - int key,firstClear; - register int i,g; - if (new_num_lvls>type->num_levels) - firstClear= type->num_levels; - else firstClear= new_num_lvls; - for (i=0;i<nMatchingKeys;i++) { - KeySym * pSyms; - int width,nClear; - - key= matchingKeys[i]; - width= XkbKeyGroupsWidth(xkb,key); - nClear= width-firstClear; - pSyms= XkbKeySymsPtr(xkb,key); - for (g=XkbKeyNumGroups(xkb,key)-1;g>=0;g--) { - if (XkbKeyKeyTypeIndex(xkb,key,g)==type_ndx) { - if (nClear>0) - bzero(&pSyms[g*width+firstClear],nClear*sizeof(KeySym)); - } - } - } - } - type->num_levels= new_num_lvls; - return Success; -} - -KeySym * -XkbResizeKeySyms(XkbDescPtr xkb,int key,int needed) -{ -register int i,nSyms,nKeySyms; -unsigned nOldSyms; -KeySym *newSyms; - - if (needed==0) { - xkb->map->key_sym_map[key].offset= 0; - return xkb->map->syms; - } - nOldSyms= XkbKeyNumSyms(xkb,key); - if (nOldSyms>=(unsigned)needed) { - return XkbKeySymsPtr(xkb,key); - } - if (xkb->map->size_syms-xkb->map->num_syms>=(unsigned)needed) { - if (nOldSyms>0) { - memcpy(&xkb->map->syms[xkb->map->num_syms],XkbKeySymsPtr(xkb,key), - nOldSyms*sizeof(KeySym)); - } - if ((needed-nOldSyms)>0) { - bzero(&xkb->map->syms[xkb->map->num_syms+XkbKeyNumSyms(xkb,key)], - (needed-nOldSyms)*sizeof(KeySym)); - } - xkb->map->key_sym_map[key].offset = xkb->map->num_syms; - xkb->map->num_syms+= needed; - return &xkb->map->syms[xkb->map->key_sym_map[key].offset]; - } - xkb->map->size_syms+= (needed>32?needed:32); - newSyms = xcalloc(xkb->map->size_syms, sizeof(KeySym)); - if (newSyms==NULL) - return NULL; - newSyms[0]= NoSymbol; - nSyms = 1; - for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) { - int nCopy; - - nCopy= nKeySyms= XkbKeyNumSyms(xkb,i); - if ((nKeySyms==0)&&(i!=key)) - continue; - if (i==key) - nKeySyms= needed; - if (nCopy!=0) - memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),nCopy*sizeof(KeySym)); - if (nKeySyms>nCopy) - bzero(&newSyms[nSyms+nCopy],(nKeySyms-nCopy)*sizeof(KeySym)); - xkb->map->key_sym_map[i].offset = nSyms; - nSyms+= nKeySyms; - } - xfree(xkb->map->syms); - xkb->map->syms = newSyms; - xkb->map->num_syms = nSyms; - return &xkb->map->syms[xkb->map->key_sym_map[key].offset]; -} - -static unsigned -_ExtendRange( unsigned int old_flags, - unsigned int flag, - KeyCode newKC, - KeyCode * old_min, - unsigned char * old_num) -{ - if ((old_flags&flag)==0) { - old_flags|= flag; - *old_min= newKC; - *old_num= 1; - } - else { - int last= (*old_min)+(*old_num)-1; - if (newKC<*old_min) { - *old_min= newKC; - *old_num= (last-newKC)+1; - } - else if (newKC>last) { - *old_num= (newKC-(*old_min))+1; - } - } - return old_flags; -} - -Status -XkbChangeKeycodeRange( XkbDescPtr xkb, - int minKC, - int maxKC, - XkbChangesPtr changes) -{ -int tmp; - - if ((!xkb)||(minKC<XkbMinLegalKeyCode)||(maxKC>XkbMaxLegalKeyCode)) - return BadValue; - if (minKC>maxKC) - return BadMatch; - if (minKC<xkb->min_key_code) { - if (changes) - changes->map.min_key_code= minKC; - tmp= xkb->min_key_code-minKC; - if (xkb->map) { - if (xkb->map->key_sym_map) { - bzero((char *)&xkb->map->key_sym_map[minKC], - tmp*sizeof(XkbSymMapRec)); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbKeySymsMask,minKC, - &changes->map.first_key_sym, - &changes->map.num_key_syms); - } - } - if (xkb->map->modmap) { - bzero((char *)&xkb->map->modmap[minKC],tmp); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbModifierMapMask,minKC, - &changes->map.first_modmap_key, - &changes->map.num_modmap_keys); - } - } - } - if (xkb->server) { - if (xkb->server->behaviors) { - bzero((char *)&xkb->server->behaviors[minKC], - tmp*sizeof(XkbBehavior)); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbKeyBehaviorsMask,minKC, - &changes->map.first_key_behavior, - &changes->map.num_key_behaviors); - } - } - if (xkb->server->key_acts) { - bzero((char *)&xkb->server->key_acts[minKC], - tmp*sizeof(unsigned short)); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbKeyActionsMask,minKC, - &changes->map.first_key_act, - &changes->map.num_key_acts); - } - } - if (xkb->server->vmodmap) { - bzero((char *)&xkb->server->vmodmap[minKC], - tmp*sizeof(unsigned short)); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbVirtualModMapMask,minKC, - &changes->map.first_modmap_key, - &changes->map.num_vmodmap_keys); - } - } - } - if ((xkb->names)&&(xkb->names->keys)) { - bzero((char *)&xkb->names->keys[minKC],tmp*sizeof(XkbKeyNameRec)); - if (changes) { - changes->names.changed= _ExtendRange(changes->names.changed, - XkbKeyNamesMask,minKC, - &changes->names.first_key, - &changes->names.num_keys); - } - } - xkb->min_key_code= minKC; - } - if (maxKC>xkb->max_key_code) { - if (changes) - changes->map.max_key_code= maxKC; - tmp= maxKC-xkb->max_key_code; - if (xkb->map) { - if (xkb->map->key_sym_map) { - XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map; - - xkb->map->key_sym_map = xrealloc(xkb->map->key_sym_map, - (maxKC+1) * sizeof(XkbSymMapRec)); - if (!xkb->map->key_sym_map) { - xfree(prev_key_sym_map); - return BadAlloc; - } - bzero((char *)&xkb->map->key_sym_map[xkb->max_key_code], - tmp*sizeof(XkbSymMapRec)); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbKeySymsMask,maxKC, - &changes->map.first_key_sym, - &changes->map.num_key_syms); - } - } - if (xkb->map->modmap) { - unsigned char *prev_modmap = xkb->map->modmap; - - xkb->map->modmap = xrealloc(xkb->map->modmap, - (maxKC+1) * sizeof(unsigned char)); - if (!xkb->map->modmap) { - xfree(prev_modmap); - return BadAlloc; - } - bzero((char *)&xkb->map->modmap[xkb->max_key_code],tmp); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbModifierMapMask,maxKC, - &changes->map.first_modmap_key, - &changes->map.num_modmap_keys); - } - } - } - if (xkb->server) { - if (xkb->server->behaviors) { - XkbBehavior *prev_behaviors = xkb->server->behaviors; - - xkb->server->behaviors = xrealloc(xkb->server->behaviors, - (maxKC+1) * sizeof(XkbBehavior)); - if (!xkb->server->behaviors) { - xfree(prev_behaviors); - return BadAlloc; - } - bzero((char *)&xkb->server->behaviors[xkb->max_key_code], - tmp*sizeof(XkbBehavior)); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbKeyBehaviorsMask,maxKC, - &changes->map.first_key_behavior, - &changes->map.num_key_behaviors); - } - } - if (xkb->server->key_acts) { - unsigned short *prev_key_acts = xkb->server->key_acts; - - xkb->server->key_acts= xrealloc(xkb->server->key_acts, - (maxKC+1) * sizeof(unsigned short)); - if (!xkb->server->key_acts) { - xfree(prev_key_acts); - return BadAlloc; - } - bzero((char *)&xkb->server->key_acts[xkb->max_key_code], - tmp*sizeof(unsigned short)); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbKeyActionsMask,maxKC, - &changes->map.first_key_act, - &changes->map.num_key_acts); - } - } - if (xkb->server->vmodmap) { - unsigned short *prev_vmodmap = xkb->server->vmodmap; - - xkb->server->vmodmap= xrealloc(xkb->server->vmodmap, - (maxKC+1) * sizeof(unsigned short)); - if (!xkb->server->vmodmap) { - xfree(prev_vmodmap); - return BadAlloc; - } - bzero((char *)&xkb->server->vmodmap[xkb->max_key_code], - tmp*sizeof(unsigned short)); - if (changes) { - changes->map.changed= _ExtendRange(changes->map.changed, - XkbVirtualModMapMask,maxKC, - &changes->map.first_modmap_key, - &changes->map.num_vmodmap_keys); - } - } - } - if ((xkb->names)&&(xkb->names->keys)) { - XkbKeyNameRec *prev_keys = xkb->names->keys; - - xkb->names->keys = xrealloc(xkb->names->keys, - (maxKC+1) * sizeof(XkbKeyNameRec)); - if (!xkb->names->keys) { - xfree(prev_keys); - return BadAlloc; - } - bzero((char *)&xkb->names->keys[xkb->max_key_code], - tmp*sizeof(XkbKeyNameRec)); - if (changes) { - changes->names.changed= _ExtendRange(changes->names.changed, - XkbKeyNamesMask,maxKC, - &changes->names.first_key, - &changes->names.num_keys); - } - } - xkb->max_key_code= maxKC; - } - return Success; -} - -XkbAction * -XkbResizeKeyActions(XkbDescPtr xkb,int key,int needed) -{ -register int i,nActs; -XkbAction *newActs; - - if (needed==0) { - xkb->server->key_acts[key]= 0; - return NULL; - } - if (XkbKeyHasActions(xkb,key)&&(XkbKeyNumSyms(xkb,key)>=(unsigned)needed)) - return XkbKeyActionsPtr(xkb,key); - if (xkb->server->size_acts-xkb->server->num_acts>=(unsigned)needed) { - xkb->server->key_acts[key]= xkb->server->num_acts; - xkb->server->num_acts+= needed; - return &xkb->server->acts[xkb->server->key_acts[key]]; - } - xkb->server->size_acts= xkb->server->num_acts+needed+8; - newActs = xcalloc(xkb->server->size_acts, sizeof(XkbAction)); - if (newActs==NULL) - return NULL; - newActs[0].type = XkbSA_NoAction; - nActs = 1; - for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) { - int nKeyActs,nCopy; - - if ((xkb->server->key_acts[i]==0)&&(i!=key)) - continue; - - nCopy= nKeyActs= XkbKeyNumActions(xkb,i); - if (i==key) { - nKeyActs= needed; - if (needed<nCopy) - nCopy= needed; - } - - if (nCopy>0) - memcpy(&newActs[nActs],XkbKeyActionsPtr(xkb,i), - nCopy*sizeof(XkbAction)); - if (nCopy<nKeyActs) - bzero(&newActs[nActs+nCopy],(nKeyActs-nCopy)*sizeof(XkbAction)); - xkb->server->key_acts[i]= nActs; - nActs+= nKeyActs; - } - xfree(xkb->server->acts); - xkb->server->acts = newActs; - xkb->server->num_acts= nActs; - return &xkb->server->acts[xkb->server->key_acts[key]]; -} - -void -XkbFreeClientMap(XkbDescPtr xkb,unsigned what,Bool freeMap) -{ -XkbClientMapPtr map; - - if ((xkb==NULL)||(xkb->map==NULL)) - return; - if (freeMap) - what= XkbAllClientInfoMask; - map= xkb->map; - if (what&XkbKeyTypesMask) { - if (map->types!=NULL) { - if (map->num_types>0) { - register int i; - XkbKeyTypePtr type; - for (i=0,type=map->types;i<map->num_types;i++,type++) { - if (type->map!=NULL) { - xfree(type->map); - type->map= NULL; - } - if (type->preserve!=NULL) { - xfree(type->preserve); - type->preserve= NULL; - } - type->map_count= 0; - if (type->level_names!=NULL) { - xfree(type->level_names); - type->level_names= NULL; - } - } - } - xfree(map->types); - map->num_types= map->size_types= 0; - map->types= NULL; - } - } - if (what&XkbKeySymsMask) { - if (map->key_sym_map!=NULL) { - xfree(map->key_sym_map); - map->key_sym_map= NULL; - } - if (map->syms!=NULL) { - xfree(map->syms); - map->size_syms= map->num_syms= 0; - map->syms= NULL; - } - } - if ((what&XkbModifierMapMask)&&(map->modmap!=NULL)) { - xfree(map->modmap); - map->modmap= NULL; - } - if (freeMap) { - xfree(xkb->map); - xkb->map= NULL; - } - return; -} - -void -XkbFreeServerMap(XkbDescPtr xkb,unsigned what,Bool freeMap) -{ -XkbServerMapPtr map; - - if ((xkb==NULL)||(xkb->server==NULL)) - return; - if (freeMap) - what= XkbAllServerInfoMask; - map= xkb->server; - if ((what&XkbExplicitComponentsMask)&&(map->explicit!=NULL)) { - xfree(map->explicit); - map->explicit= NULL; - } - if (what&XkbKeyActionsMask) { - if (map->key_acts!=NULL) { - xfree(map->key_acts); - map->key_acts= NULL; - } - if (map->acts!=NULL) { - xfree(map->acts); - map->num_acts= map->size_acts= 0; - map->acts= NULL; - } - } - if ((what&XkbKeyBehaviorsMask)&&(map->behaviors!=NULL)) { - xfree(map->behaviors); - map->behaviors= NULL; - } - if ((what&XkbVirtualModMapMask)&&(map->vmodmap!=NULL)) { - xfree(map->vmodmap); - map->vmodmap= NULL; - } - - if (freeMap) { - xfree(xkb->server); - xkb->server= NULL; - } - return; -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#elif defined(HAVE_CONFIG_H) +#include <config.h> +#endif + +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "inputstr.h" +#include <X11/keysym.h> +#define XKBSRV_NEED_FILE_FUNCS +#include <xkbsrv.h> + +/***====================================================================***/ + +Status +XkbAllocClientMap(XkbDescPtr xkb,unsigned which,unsigned nTotalTypes) +{ +register int i; +XkbClientMapPtr map; + + if ((xkb==NULL)||((nTotalTypes>0)&&(nTotalTypes<XkbNumRequiredTypes))) + return BadValue; + if ((which&XkbKeySymsMask)&& + ((!XkbIsLegalKeycode(xkb->min_key_code))|| + (!XkbIsLegalKeycode(xkb->max_key_code))|| + (xkb->max_key_code<xkb->min_key_code))) { + DebugF("bad keycode (%d,%d) in XkbAllocClientMap\n", + xkb->min_key_code,xkb->max_key_code); + return BadValue; + } + + if (xkb->map==NULL) { + map= calloc(1, sizeof(XkbClientMapRec)); + if (map==NULL) + return BadAlloc; + xkb->map= map; + } + else map= xkb->map; + + if ((which&XkbKeyTypesMask)&&(nTotalTypes>0)) { + if (map->types==NULL) { + map->types= calloc(nTotalTypes, sizeof(XkbKeyTypeRec)); + if (map->types==NULL) + return BadAlloc; + map->num_types= 0; + map->size_types= nTotalTypes; + } + else if (map->size_types<nTotalTypes) { + XkbKeyTypeRec *prev_types = map->types; + + map->types= realloc(map->types,nTotalTypes * sizeof(XkbKeyTypeRec)); + if (map->types==NULL) { + free(prev_types); + map->num_types= map->size_types= 0; + return BadAlloc; + } + map->size_types= nTotalTypes; + bzero(&map->types[map->num_types], + ((map->size_types-map->num_types)*sizeof(XkbKeyTypeRec))); + } + } + if (which&XkbKeySymsMask) { + int nKeys= XkbNumKeys(xkb); + if (map->syms==NULL) { + map->size_syms= (nKeys*15)/10; + map->syms= calloc(map->size_syms, sizeof(KeySym)); + if (!map->syms) { + map->size_syms= 0; + return BadAlloc; + } + map->num_syms= 1; + map->syms[0]= NoSymbol; + } + if (map->key_sym_map==NULL) { + i= xkb->max_key_code+1; + map->key_sym_map= calloc(i, sizeof(XkbSymMapRec)); + if (map->key_sym_map==NULL) + return BadAlloc; + } + } + if (which&XkbModifierMapMask) { + if ((!XkbIsLegalKeycode(xkb->min_key_code))|| + (!XkbIsLegalKeycode(xkb->max_key_code))|| + (xkb->max_key_code<xkb->min_key_code)) + return BadMatch; + if (map->modmap==NULL) { + i= xkb->max_key_code+1; + map->modmap= calloc(i, sizeof(unsigned char)); + if (map->modmap==NULL) + return BadAlloc; + } + } + return Success; +} + +Status +XkbAllocServerMap(XkbDescPtr xkb,unsigned which,unsigned nNewActions) +{ +register int i; +XkbServerMapPtr map; + + if (xkb==NULL) + return BadMatch; + if (xkb->server==NULL) { + map= calloc(1, sizeof(XkbServerMapRec)); + if (map==NULL) + return BadAlloc; + for (i=0;i<XkbNumVirtualMods;i++) { + map->vmods[i]= XkbNoModifierMask; + } + xkb->server= map; + } + else map= xkb->server; + if (which&XkbExplicitComponentsMask) { + if ((!XkbIsLegalKeycode(xkb->min_key_code))|| + (!XkbIsLegalKeycode(xkb->max_key_code))|| + (xkb->max_key_code<xkb->min_key_code)) + return BadMatch; + if (map->explicit==NULL) { + i= xkb->max_key_code+1; + map->explicit= calloc(i, sizeof(unsigned char)); + if (map->explicit==NULL) + return BadAlloc; + } + } + if (which&XkbKeyActionsMask) { + if ((!XkbIsLegalKeycode(xkb->min_key_code))|| + (!XkbIsLegalKeycode(xkb->max_key_code))|| + (xkb->max_key_code<xkb->min_key_code)) + return BadMatch; + if (nNewActions<1) + nNewActions= 1; + if (map->acts==NULL) { + map->acts= calloc((nNewActions+1), sizeof(XkbAction)); + if (map->acts==NULL) + return BadAlloc; + map->num_acts= 1; + map->size_acts= nNewActions+1; + } + else if ((map->size_acts-map->num_acts)<nNewActions) { + unsigned need; + XkbAction *prev_acts = map->acts; + need= map->num_acts+nNewActions; + map->acts= realloc(map->acts,need * sizeof(XkbAction)); + if (map->acts==NULL) { + free(prev_acts); + map->num_acts= map->size_acts= 0; + return BadAlloc; + } + map->size_acts= need; + bzero(&map->acts[map->num_acts], + ((map->size_acts-map->num_acts)*sizeof(XkbAction))); + } + if (map->key_acts==NULL) { + i= xkb->max_key_code+1; + map->key_acts= calloc(i, sizeof(unsigned short)); + if (map->key_acts==NULL) + return BadAlloc; + } + } + if (which&XkbKeyBehaviorsMask) { + if ((!XkbIsLegalKeycode(xkb->min_key_code))|| + (!XkbIsLegalKeycode(xkb->max_key_code))|| + (xkb->max_key_code<xkb->min_key_code)) + return BadMatch; + if (map->behaviors==NULL) { + i= xkb->max_key_code+1; + map->behaviors= calloc(i, sizeof(XkbBehavior)); + if (map->behaviors==NULL) + return BadAlloc; + } + } + if (which&XkbVirtualModMapMask) { + if ((!XkbIsLegalKeycode(xkb->min_key_code))|| + (!XkbIsLegalKeycode(xkb->max_key_code))|| + (xkb->max_key_code<xkb->min_key_code)) + return BadMatch; + if (map->vmodmap==NULL) { + i= xkb->max_key_code+1; + map->vmodmap= calloc(i, sizeof(unsigned short)); + if (map->vmodmap==NULL) + return BadAlloc; + } + } + return Success; +} + +/***====================================================================***/ + +static Status +XkbCopyKeyType(XkbKeyTypePtr from,XkbKeyTypePtr into) +{ + if ((!from)||(!into)) + return BadMatch; + if (into->map) { + free(into->map); + into->map= NULL; + } + if (into->preserve) { + free(into->preserve); + into->preserve= NULL; + } + if (into->level_names) { + free(into->level_names); + into->level_names= NULL; + } + *into= *from; + if ((from->map)&&(into->map_count>0)) { + into->map= calloc(into->map_count, sizeof(XkbKTMapEntryRec)); + if (!into->map) + return BadAlloc; + memcpy(into->map,from->map,into->map_count*sizeof(XkbKTMapEntryRec)); + } + if ((from->preserve)&&(into->map_count>0)) { + into->preserve= calloc(into->map_count, sizeof(XkbModsRec)); + if (!into->preserve) + return BadAlloc; + memcpy(into->preserve,from->preserve, + into->map_count*sizeof(XkbModsRec)); + } + if ((from->level_names)&&(into->num_levels>0)) { + into->level_names= calloc(into->num_levels, sizeof(Atom)); + if (!into->level_names) + return BadAlloc; + memcpy(into->level_names,from->level_names, + into->num_levels*sizeof(Atom)); + } + return Success; +} + +Status +XkbCopyKeyTypes(XkbKeyTypePtr from,XkbKeyTypePtr into,int num_types) +{ +register int i,rtrn; + + if ((!from)||(!into)||(num_types<0)) + return BadMatch; + for (i=0;i<num_types;i++) { + if ((rtrn= XkbCopyKeyType(from++,into++))!=Success) + return rtrn; + } + return Success; +} + +Status +XkbResizeKeyType( XkbDescPtr xkb, + int type_ndx, + int map_count, + Bool want_preserve, + int new_num_lvls) +{ +XkbKeyTypePtr type; +KeyCode matchingKeys[XkbMaxKeyCount],nMatchingKeys; + + if ((type_ndx<0)||(type_ndx>=xkb->map->num_types)||(map_count<0)|| + (new_num_lvls<1)) + return BadValue; + switch (type_ndx) { + case XkbOneLevelIndex: + if (new_num_lvls!=1) + return BadMatch; + break; + case XkbTwoLevelIndex: + case XkbAlphabeticIndex: + case XkbKeypadIndex: + if (new_num_lvls!=2) + return BadMatch; + break; + } + type= &xkb->map->types[type_ndx]; + if (map_count==0) { + if (type->map!=NULL) + free(type->map); + type->map= NULL; + if (type->preserve!=NULL) + free(type->preserve); + type->preserve= NULL; + type->map_count= 0; + } + else { + XkbKTMapEntryRec *prev_map = type->map; + + if ((map_count>type->map_count)||(type->map==NULL)) + type->map = realloc(type->map,map_count * sizeof(XkbKTMapEntryRec)); + if (!type->map) { + if (prev_map) + free(prev_map); + return BadAlloc; + } + if (want_preserve) { + XkbModsRec *prev_preserve = type->preserve; + + if ((map_count>type->map_count)||(type->preserve==NULL)) { + type->preserve = realloc(type->preserve, + map_count * sizeof(XkbModsRec)); + } + if (!type->preserve) { + if (prev_preserve) + free(prev_preserve); + return BadAlloc; + } + } + else if (type->preserve!=NULL) { + free(type->preserve); + type->preserve= NULL; + } + type->map_count= map_count; + } + + if ((new_num_lvls>type->num_levels)||(type->level_names==NULL)) { + Atom * prev_level_names = type->level_names; + + type->level_names = realloc(type->level_names, + new_num_lvls * sizeof(Atom)); + if (!type->level_names) { + if (prev_level_names) + free(prev_level_names); + return BadAlloc; + } + } + /* + * Here's the theory: + * If the width of the type changed, we might have to resize the symbol + * maps for any keys that use the type for one or more groups. This is + * expensive, so we'll try to cull out any keys that are obviously okay: + * In any case: + * - keys that have a group width <= the old width are okay (because + * they could not possibly have been associated with the old type) + * If the key type increased in size: + * - keys that already have a group width >= to the new width are okay + * + keys that have a group width >= the old width but < the new width + * might have to be enlarged. + * If the key type decreased in size: + * - keys that have a group width > the old width don't have to be + * resized (because they must have some other wider type associated + * with some group). + * + keys that have a group width == the old width might have to be + * shrunk. + * The possibilities marked with '+' require us to examine the key types + * associated with each group for the key. + */ + bzero(matchingKeys,XkbMaxKeyCount*sizeof(KeyCode)); + nMatchingKeys= 0; + if (new_num_lvls>type->num_levels) { + int nTotal; + KeySym * newSyms; + int width,match,nResize; + register int i,g,nSyms; + + nResize= 0; + for (nTotal=1,i=xkb->min_key_code;i<=xkb->max_key_code;i++) { + width= XkbKeyGroupsWidth(xkb,i); + if (width<type->num_levels) + continue; + for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) { + if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) { + matchingKeys[nMatchingKeys++]= i; + match= 1; + } + } + if ((!match)||(width>=new_num_lvls)) + nTotal+= XkbKeyNumSyms(xkb,i); + else { + nTotal+= XkbKeyNumGroups(xkb,i)*new_num_lvls; + nResize++; + } + } + if (nResize>0) { + int nextMatch; + xkb->map->size_syms= (nTotal*15)/10; + newSyms = calloc(xkb->map->size_syms, sizeof(KeySym)); + if (newSyms==NULL) + return BadAlloc; + nextMatch= 0; + nSyms= 1; + for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { + if (matchingKeys[nextMatch]==i) { + KeySym *pOld; + nextMatch++; + width= XkbKeyGroupsWidth(xkb,i); + pOld= XkbKeySymsPtr(xkb,i); + for (g=XkbKeyNumGroups(xkb,i)-1;g>=0;g--) { + memcpy(&newSyms[nSyms+(new_num_lvls*g)],&pOld[width*g], + width*sizeof(KeySym)); + } + xkb->map->key_sym_map[i].offset= nSyms; + nSyms+= XkbKeyNumGroups(xkb,i)*new_num_lvls; + } + else { + memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i), + XkbKeyNumSyms(xkb,i)*sizeof(KeySym)); + xkb->map->key_sym_map[i].offset= nSyms; + nSyms+= XkbKeyNumSyms(xkb,i); + } + } + type->num_levels= new_num_lvls; + free(xkb->map->syms); + xkb->map->syms= newSyms; + xkb->map->num_syms= nSyms; + return Success; + } + } + else if (new_num_lvls<type->num_levels) { + int width,match; + register int g,i; + for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { + width= XkbKeyGroupsWidth(xkb,i); + if (width<type->num_levels) + continue; + for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) { + if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) { + matchingKeys[nMatchingKeys++]= i; + match= 1; + } + } + } + } + if (nMatchingKeys>0) { + int key,firstClear; + register int i,g; + if (new_num_lvls>type->num_levels) + firstClear= type->num_levels; + else firstClear= new_num_lvls; + for (i=0;i<nMatchingKeys;i++) { + KeySym * pSyms; + int width,nClear; + + key= matchingKeys[i]; + width= XkbKeyGroupsWidth(xkb,key); + nClear= width-firstClear; + pSyms= XkbKeySymsPtr(xkb,key); + for (g=XkbKeyNumGroups(xkb,key)-1;g>=0;g--) { + if (XkbKeyKeyTypeIndex(xkb,key,g)==type_ndx) { + if (nClear>0) + bzero(&pSyms[g*width+firstClear],nClear*sizeof(KeySym)); + } + } + } + } + type->num_levels= new_num_lvls; + return Success; +} + +KeySym * +XkbResizeKeySyms(XkbDescPtr xkb,int key,int needed) +{ +register int i,nSyms,nKeySyms; +unsigned nOldSyms; +KeySym *newSyms; + + if (needed==0) { + xkb->map->key_sym_map[key].offset= 0; + return xkb->map->syms; + } + nOldSyms= XkbKeyNumSyms(xkb,key); + if (nOldSyms>=(unsigned)needed) { + return XkbKeySymsPtr(xkb,key); + } + if (xkb->map->size_syms-xkb->map->num_syms>=(unsigned)needed) { + if (nOldSyms>0) { + memcpy(&xkb->map->syms[xkb->map->num_syms],XkbKeySymsPtr(xkb,key), + nOldSyms*sizeof(KeySym)); + } + if ((needed-nOldSyms)>0) { + bzero(&xkb->map->syms[xkb->map->num_syms+XkbKeyNumSyms(xkb,key)], + (needed-nOldSyms)*sizeof(KeySym)); + } + xkb->map->key_sym_map[key].offset = xkb->map->num_syms; + xkb->map->num_syms+= needed; + return &xkb->map->syms[xkb->map->key_sym_map[key].offset]; + } + xkb->map->size_syms+= (needed>32?needed:32); + newSyms = calloc(xkb->map->size_syms, sizeof(KeySym)); + if (newSyms==NULL) + return NULL; + newSyms[0]= NoSymbol; + nSyms = 1; + for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) { + int nCopy; + + nCopy= nKeySyms= XkbKeyNumSyms(xkb,i); + if ((nKeySyms==0)&&(i!=key)) + continue; + if (i==key) + nKeySyms= needed; + if (nCopy!=0) + memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),nCopy*sizeof(KeySym)); + if (nKeySyms>nCopy) + bzero(&newSyms[nSyms+nCopy],(nKeySyms-nCopy)*sizeof(KeySym)); + xkb->map->key_sym_map[i].offset = nSyms; + nSyms+= nKeySyms; + } + free(xkb->map->syms); + xkb->map->syms = newSyms; + xkb->map->num_syms = nSyms; + return &xkb->map->syms[xkb->map->key_sym_map[key].offset]; +} + +static unsigned +_ExtendRange( unsigned int old_flags, + unsigned int flag, + KeyCode newKC, + KeyCode * old_min, + unsigned char * old_num) +{ + if ((old_flags&flag)==0) { + old_flags|= flag; + *old_min= newKC; + *old_num= 1; + } + else { + int last= (*old_min)+(*old_num)-1; + if (newKC<*old_min) { + *old_min= newKC; + *old_num= (last-newKC)+1; + } + else if (newKC>last) { + *old_num= (newKC-(*old_min))+1; + } + } + return old_flags; +} + +Status +XkbChangeKeycodeRange( XkbDescPtr xkb, + int minKC, + int maxKC, + XkbChangesPtr changes) +{ +int tmp; + + if ((!xkb)||(minKC<XkbMinLegalKeyCode)||(maxKC>XkbMaxLegalKeyCode)) + return BadValue; + if (minKC>maxKC) + return BadMatch; + if (minKC<xkb->min_key_code) { + if (changes) + changes->map.min_key_code= minKC; + tmp= xkb->min_key_code-minKC; + if (xkb->map) { + if (xkb->map->key_sym_map) { + bzero((char *)&xkb->map->key_sym_map[minKC], + tmp*sizeof(XkbSymMapRec)); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbKeySymsMask,minKC, + &changes->map.first_key_sym, + &changes->map.num_key_syms); + } + } + if (xkb->map->modmap) { + bzero((char *)&xkb->map->modmap[minKC],tmp); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbModifierMapMask,minKC, + &changes->map.first_modmap_key, + &changes->map.num_modmap_keys); + } + } + } + if (xkb->server) { + if (xkb->server->behaviors) { + bzero((char *)&xkb->server->behaviors[minKC], + tmp*sizeof(XkbBehavior)); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbKeyBehaviorsMask,minKC, + &changes->map.first_key_behavior, + &changes->map.num_key_behaviors); + } + } + if (xkb->server->key_acts) { + bzero((char *)&xkb->server->key_acts[minKC], + tmp*sizeof(unsigned short)); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbKeyActionsMask,minKC, + &changes->map.first_key_act, + &changes->map.num_key_acts); + } + } + if (xkb->server->vmodmap) { + bzero((char *)&xkb->server->vmodmap[minKC], + tmp*sizeof(unsigned short)); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbVirtualModMapMask,minKC, + &changes->map.first_modmap_key, + &changes->map.num_vmodmap_keys); + } + } + } + if ((xkb->names)&&(xkb->names->keys)) { + bzero((char *)&xkb->names->keys[minKC],tmp*sizeof(XkbKeyNameRec)); + if (changes) { + changes->names.changed= _ExtendRange(changes->names.changed, + XkbKeyNamesMask,minKC, + &changes->names.first_key, + &changes->names.num_keys); + } + } + xkb->min_key_code= minKC; + } + if (maxKC>xkb->max_key_code) { + if (changes) + changes->map.max_key_code= maxKC; + tmp= maxKC-xkb->max_key_code; + if (xkb->map) { + if (xkb->map->key_sym_map) { + XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map; + + xkb->map->key_sym_map = realloc(xkb->map->key_sym_map, + (maxKC+1) * sizeof(XkbSymMapRec)); + if (!xkb->map->key_sym_map) { + free(prev_key_sym_map); + return BadAlloc; + } + bzero((char *)&xkb->map->key_sym_map[xkb->max_key_code], + tmp*sizeof(XkbSymMapRec)); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbKeySymsMask,maxKC, + &changes->map.first_key_sym, + &changes->map.num_key_syms); + } + } + if (xkb->map->modmap) { + unsigned char *prev_modmap = xkb->map->modmap; + + xkb->map->modmap = realloc(xkb->map->modmap, + (maxKC+1) * sizeof(unsigned char)); + if (!xkb->map->modmap) { + free(prev_modmap); + return BadAlloc; + } + bzero((char *)&xkb->map->modmap[xkb->max_key_code],tmp); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbModifierMapMask,maxKC, + &changes->map.first_modmap_key, + &changes->map.num_modmap_keys); + } + } + } + if (xkb->server) { + if (xkb->server->behaviors) { + XkbBehavior *prev_behaviors = xkb->server->behaviors; + + xkb->server->behaviors = realloc(xkb->server->behaviors, + (maxKC+1) * sizeof(XkbBehavior)); + if (!xkb->server->behaviors) { + free(prev_behaviors); + return BadAlloc; + } + bzero((char *)&xkb->server->behaviors[xkb->max_key_code], + tmp*sizeof(XkbBehavior)); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbKeyBehaviorsMask,maxKC, + &changes->map.first_key_behavior, + &changes->map.num_key_behaviors); + } + } + if (xkb->server->key_acts) { + unsigned short *prev_key_acts = xkb->server->key_acts; + + xkb->server->key_acts= realloc(xkb->server->key_acts, + (maxKC+1) * sizeof(unsigned short)); + if (!xkb->server->key_acts) { + free(prev_key_acts); + return BadAlloc; + } + bzero((char *)&xkb->server->key_acts[xkb->max_key_code], + tmp*sizeof(unsigned short)); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbKeyActionsMask,maxKC, + &changes->map.first_key_act, + &changes->map.num_key_acts); + } + } + if (xkb->server->vmodmap) { + unsigned short *prev_vmodmap = xkb->server->vmodmap; + + xkb->server->vmodmap= realloc(xkb->server->vmodmap, + (maxKC+1) * sizeof(unsigned short)); + if (!xkb->server->vmodmap) { + free(prev_vmodmap); + return BadAlloc; + } + bzero((char *)&xkb->server->vmodmap[xkb->max_key_code], + tmp*sizeof(unsigned short)); + if (changes) { + changes->map.changed= _ExtendRange(changes->map.changed, + XkbVirtualModMapMask,maxKC, + &changes->map.first_modmap_key, + &changes->map.num_vmodmap_keys); + } + } + } + if ((xkb->names)&&(xkb->names->keys)) { + XkbKeyNameRec *prev_keys = xkb->names->keys; + + xkb->names->keys = realloc(xkb->names->keys, + (maxKC+1) * sizeof(XkbKeyNameRec)); + if (!xkb->names->keys) { + free(prev_keys); + return BadAlloc; + } + bzero((char *)&xkb->names->keys[xkb->max_key_code], + tmp*sizeof(XkbKeyNameRec)); + if (changes) { + changes->names.changed= _ExtendRange(changes->names.changed, + XkbKeyNamesMask,maxKC, + &changes->names.first_key, + &changes->names.num_keys); + } + } + xkb->max_key_code= maxKC; + } + return Success; +} + +XkbAction * +XkbResizeKeyActions(XkbDescPtr xkb,int key,int needed) +{ +register int i,nActs; +XkbAction *newActs; + + if (needed==0) { + xkb->server->key_acts[key]= 0; + return NULL; + } + if (XkbKeyHasActions(xkb,key)&&(XkbKeyNumSyms(xkb,key)>=(unsigned)needed)) + return XkbKeyActionsPtr(xkb,key); + if (xkb->server->size_acts-xkb->server->num_acts>=(unsigned)needed) { + xkb->server->key_acts[key]= xkb->server->num_acts; + xkb->server->num_acts+= needed; + return &xkb->server->acts[xkb->server->key_acts[key]]; + } + xkb->server->size_acts= xkb->server->num_acts+needed+8; + newActs = calloc(xkb->server->size_acts, sizeof(XkbAction)); + if (newActs==NULL) + return NULL; + newActs[0].type = XkbSA_NoAction; + nActs = 1; + for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) { + int nKeyActs,nCopy; + + if ((xkb->server->key_acts[i]==0)&&(i!=key)) + continue; + + nCopy= nKeyActs= XkbKeyNumActions(xkb,i); + if (i==key) { + nKeyActs= needed; + if (needed<nCopy) + nCopy= needed; + } + + if (nCopy>0) + memcpy(&newActs[nActs],XkbKeyActionsPtr(xkb,i), + nCopy*sizeof(XkbAction)); + if (nCopy<nKeyActs) + bzero(&newActs[nActs+nCopy],(nKeyActs-nCopy)*sizeof(XkbAction)); + xkb->server->key_acts[i]= nActs; + nActs+= nKeyActs; + } + free(xkb->server->acts); + xkb->server->acts = newActs; + xkb->server->num_acts= nActs; + return &xkb->server->acts[xkb->server->key_acts[key]]; +} + +void +XkbFreeClientMap(XkbDescPtr xkb,unsigned what,Bool freeMap) +{ +XkbClientMapPtr map; + + if ((xkb==NULL)||(xkb->map==NULL)) + return; + if (freeMap) + what= XkbAllClientInfoMask; + map= xkb->map; + if (what&XkbKeyTypesMask) { + if (map->types!=NULL) { + if (map->num_types>0) { + register int i; + XkbKeyTypePtr type; + for (i=0,type=map->types;i<map->num_types;i++,type++) { + if (type->map!=NULL) { + free(type->map); + type->map= NULL; + } + if (type->preserve!=NULL) { + free(type->preserve); + type->preserve= NULL; + } + type->map_count= 0; + if (type->level_names!=NULL) { + free(type->level_names); + type->level_names= NULL; + } + } + } + free(map->types); + map->num_types= map->size_types= 0; + map->types= NULL; + } + } + if (what&XkbKeySymsMask) { + if (map->key_sym_map!=NULL) { + free(map->key_sym_map); + map->key_sym_map= NULL; + } + if (map->syms!=NULL) { + free(map->syms); + map->size_syms= map->num_syms= 0; + map->syms= NULL; + } + } + if ((what&XkbModifierMapMask)&&(map->modmap!=NULL)) { + free(map->modmap); + map->modmap= NULL; + } + if (freeMap) { + free(xkb->map); + xkb->map= NULL; + } + return; +} + +void +XkbFreeServerMap(XkbDescPtr xkb,unsigned what,Bool freeMap) +{ +XkbServerMapPtr map; + + if ((xkb==NULL)||(xkb->server==NULL)) + return; + if (freeMap) + what= XkbAllServerInfoMask; + map= xkb->server; + if ((what&XkbExplicitComponentsMask)&&(map->explicit!=NULL)) { + free(map->explicit); + map->explicit= NULL; + } + if (what&XkbKeyActionsMask) { + if (map->key_acts!=NULL) { + free(map->key_acts); + map->key_acts= NULL; + } + if (map->acts!=NULL) { + free(map->acts); + map->num_acts= map->size_acts= 0; + map->acts= NULL; + } + } + if ((what&XkbKeyBehaviorsMask)&&(map->behaviors!=NULL)) { + free(map->behaviors); + map->behaviors= NULL; + } + if ((what&XkbVirtualModMapMask)&&(map->vmodmap!=NULL)) { + free(map->vmodmap); + map->vmodmap= NULL; + } + + if (freeMap) { + free(xkb->server); + xkb->server= NULL; + } + return; +} diff --git a/xorg-server/xkb/XKBMisc.c b/xorg-server/xkb/XKBMisc.c index 2bb4a2452..758638f4b 100644 --- a/xorg-server/xkb/XKBMisc.c +++ b/xorg-server/xkb/XKBMisc.c @@ -1,839 +1,839 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#elif defined(HAVE_CONFIG_H) -#include <config.h> -#endif - -#include <stdio.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "inputstr.h" -#include <X11/keysym.h> -#define XKBSRV_NEED_FILE_FUNCS -#include <xkbsrv.h> - -/***====================================================================***/ - -#define CORE_SYM(i) (i<map_width?core_syms[i]:NoSymbol) -#define XKB_OFFSET(g,l) (((g)*groupsWidth)+(l)) - -int -XkbKeyTypesForCoreSymbols( XkbDescPtr xkb, - int map_width, - KeySym * core_syms, - unsigned int protected, - int * types_inout, - KeySym * xkb_syms_rtrn) -{ -register int i; -unsigned int empty; -int nSyms[XkbNumKbdGroups]; -int nGroups,tmp,groupsWidth; -BOOL replicated = FALSE; - - /* Section 12.2 of the protocol describes this process in more detail */ - /* Step 1: find the # of symbols in the core mapping per group */ - groupsWidth= 2; - for (i=0;i<XkbNumKbdGroups;i++) { - if ((protected&(1<<i))&&(types_inout[i]<xkb->map->num_types)) { - nSyms[i]= xkb->map->types[types_inout[i]].num_levels; - if (nSyms[i]>groupsWidth) - groupsWidth= nSyms[i]; - } - else { - types_inout[i]= XkbTwoLevelIndex; /* don't really know, yet */ - nSyms[i]= 2; - } - } - if (nSyms[XkbGroup1Index]<2) - nSyms[XkbGroup1Index]= 2; - if (nSyms[XkbGroup2Index]<2) - nSyms[XkbGroup2Index]= 2; - /* Step 2: Copy the symbols from the core ordering to XKB ordering */ - /* symbols in the core are in the order: */ - /* G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*] */ - xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,0)]= CORE_SYM(0); - xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,1)]= CORE_SYM(1); - for (i=2;i<nSyms[XkbGroup1Index];i++) { - xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,i)]= CORE_SYM(2+i); - } - xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,0)]= CORE_SYM(2); - xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,1)]= CORE_SYM(3); - tmp= 2+(nSyms[XkbGroup1Index]-2); /* offset to extra group2 syms */ - for (i=2;i<nSyms[XkbGroup2Index];i++) { - xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,i)]= CORE_SYM(tmp+i); - } - - /* Special case: if only the first group is explicit, and the symbols - * replicate across all groups, then we have a Section 12.4 replication */ - if ((protected & ~XkbExplicitKeyType1Mask) == 0) - { - int j, width = nSyms[XkbGroup1Index]; - - replicated = TRUE; - - /* Check ABAB in ABABCDECDEABCDE */ - if ((width > 0 && CORE_SYM(0) != CORE_SYM(2)) || - (width > 1 && CORE_SYM(1) != CORE_SYM(3))) - replicated = FALSE; - - /* Check CDECDE in ABABCDECDEABCDE */ - for (i = 2; i < width && replicated; i++) - { - if (CORE_SYM(2 + i) != CORE_SYM(i + width)) - replicated = FALSE; - } - - /* Check ABCDE in ABABCDECDEABCDE */ - for (j = 2; replicated && - j < XkbNumKbdGroups && - map_width >= width * (j + 1); j++) - { - for (i = 0; i < width && replicated; i++) - { - if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j)) - replicated = FALSE; - } - } - } - - if (replicated) - { - nSyms[XkbGroup2Index]= 0; - nSyms[XkbGroup3Index]= 0; - nSyms[XkbGroup4Index]= 0; - nGroups= 1; - } else - { - tmp= nSyms[XkbGroup1Index]+nSyms[XkbGroup2Index]; - if ((tmp>=map_width)&& - ((protected&(XkbExplicitKeyType3Mask|XkbExplicitKeyType4Mask))==0)) { - nSyms[XkbGroup3Index]= 0; - nSyms[XkbGroup4Index]= 0; - nGroups= 2; - } else - { - nGroups= 3; - for (i=0;i<nSyms[XkbGroup3Index];i++,tmp++) { - xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index,i)]= CORE_SYM(tmp); - } - if ((tmp<map_width)||(protected&XkbExplicitKeyType4Mask)) { - nGroups= 4; - for (i=0;i<nSyms[XkbGroup4Index];i++,tmp++) { - xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index,i)]= CORE_SYM(tmp); - } - } - else { - nSyms[XkbGroup4Index]= 0; - } - } - } - /* steps 3&4: alphanumeric expansion, assign canonical types */ - empty= 0; - for (i=0;i<nGroups;i++) { - KeySym *syms; - syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)]; - if ((nSyms[i]>1)&&(syms[1]==NoSymbol)&&(syms[0]!=NoSymbol)) { - KeySym upper,lower; - XkbConvertCase(syms[0],&lower,&upper); - if (upper!=lower) { - xkb_syms_rtrn[XKB_OFFSET(i,0)]= lower; - xkb_syms_rtrn[XKB_OFFSET(i,1)]= upper; - if ((protected&(1<<i))==0) - types_inout[i]= XkbAlphabeticIndex; - } - else if ((protected&(1<<i))==0) { - types_inout[i]= XkbOneLevelIndex; - /* nSyms[i]= 1;*/ - } - } - if (((protected&(1<<i))==0)&&(types_inout[i]==XkbTwoLevelIndex)) { - if (XkbKSIsKeypad(syms[0])||XkbKSIsKeypad(syms[1])) - types_inout[i]= XkbKeypadIndex; - else { - KeySym upper,lower; - XkbConvertCase(syms[0],&lower,&upper); - if ((syms[0]==lower)&&(syms[1]==upper)) - types_inout[i]= XkbAlphabeticIndex; - } - } - if (syms[0]==NoSymbol) { - register int n; - Bool found; - for (n=1,found=FALSE;(!found)&&(n<nSyms[i]);n++) { - found= (syms[n]!=NoSymbol); - } - if (!found) - empty|= (1<<i); - } - } - /* step 5: squoosh out empty groups */ - if (empty) { - for (i=nGroups-1;i>=0;i--) { - if (((empty&(1<<i))==0)||(protected&(1<<i))) - break; - nGroups--; - } - } - if (nGroups<1) - return 0; - - /* step 6: replicate group 1 into group two, if necessary */ - if ((nGroups>1)&&((empty&(XkbGroup1Mask|XkbGroup2Mask))==XkbGroup2Mask)) { - if ((protected&(XkbExplicitKeyType1Mask|XkbExplicitKeyType2Mask))==0) { - nSyms[XkbGroup2Index]= nSyms[XkbGroup1Index]; - types_inout[XkbGroup2Index]= types_inout[XkbGroup1Index]; - memcpy((char *)&xkb_syms_rtrn[2],(char *)xkb_syms_rtrn, - 2*sizeof(KeySym)); - } - else if (types_inout[XkbGroup1Index]==types_inout[XkbGroup2Index]) { - memcpy((char *)&xkb_syms_rtrn[nSyms[XkbGroup1Index]], - (char *)xkb_syms_rtrn, - nSyms[XkbGroup1Index]*sizeof(KeySym)); - } - } - - /* step 7: check for all groups identical or all width 1 - * - * Special feature: if group 1 has an explicit type and all other groups - * have canonical types with same symbols, we assume it's info lost from - * the core replication. - */ - if (nGroups>1) { - Bool sameType,allOneLevel, canonical = TRUE; - allOneLevel= (xkb->map->types[types_inout[0]].num_levels==1); - for (i=1,sameType=TRUE;(allOneLevel||sameType)&&(i<nGroups);i++) { - sameType=(sameType&&(types_inout[i]==types_inout[XkbGroup1Index])); - if (allOneLevel) - allOneLevel= (xkb->map->types[types_inout[i]].num_levels==1); - if (types_inout[i] > XkbLastRequiredType) - canonical = FALSE; - } - if (((sameType) || canonical)&& - (!(protected&(XkbExplicitKeyTypesMask&~XkbExplicitKeyType1Mask)))){ - register int s; - Bool identical; - for (i=1,identical=TRUE;identical&&(i<nGroups);i++) { - KeySym *syms; - if (nSyms[i] != nSyms[XkbGroup1Index]) - identical = FALSE; - syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)]; - for (s=0;identical&&(s<nSyms[i]);s++) { - if (syms[s]!=xkb_syms_rtrn[s]) - identical= FALSE; - } - } - if (identical) - nGroups= 1; - } - if (allOneLevel && (nGroups>1)) { - KeySym *syms; - syms= &xkb_syms_rtrn[nSyms[XkbGroup1Index]]; - nSyms[XkbGroup1Index]= 1; - for (i=1;i<nGroups;i++) { - xkb_syms_rtrn[i]= syms[0]; - syms+= nSyms[i]; - nSyms[i]= 1; - } - } - } - return nGroups; -} - -static XkbSymInterpretPtr -_XkbFindMatchingInterp( XkbDescPtr xkb, - KeySym sym, - unsigned int real_mods, - unsigned int level) -{ -register unsigned i; -XkbSymInterpretPtr interp,rtrn; -CARD8 mods; - - rtrn= NULL; - interp= xkb->compat->sym_interpret; - for (i=0;i<xkb->compat->num_si;i++,interp++) { - if ((interp->sym==NoSymbol)||(sym==interp->sym)) { - int match; - if ((level==0)||((interp->match&XkbSI_LevelOneOnly)==0)) - mods= real_mods; - else mods= 0; - switch (interp->match&XkbSI_OpMask) { - case XkbSI_NoneOf: - match= ((interp->mods&mods)==0); - break; - case XkbSI_AnyOfOrNone: - match= ((mods==0)||((interp->mods&mods)!=0)); - break; - case XkbSI_AnyOf: - match= ((interp->mods&mods)!=0); - break; - case XkbSI_AllOf: - match= ((interp->mods&mods)==interp->mods); - break; - case XkbSI_Exactly: - match= (interp->mods==mods); - break; - default: - match= 0; - break; - } - if (match) { - if (interp->sym!=NoSymbol) { - return interp; - } - else if (rtrn==NULL) { - rtrn= interp; - } - } - } - } - return rtrn; -} - -static void -_XkbAddKeyChange(KeyCode *pFirst,unsigned char *pNum,KeyCode newKey) -{ -KeyCode last; - - last= (*pFirst)+(*pNum); - if (newKey<*pFirst) { - *pFirst= newKey; - *pNum= (last-newKey)+1; - } - else if (newKey>last) { - *pNum= (last-*pFirst)+1; - } - return; -} - -static void -_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods) -{ -unsigned tmp; - - switch (act->type) { - case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: - if (act->mods.flags&XkbSA_UseModMapMods) - act->mods.real_mods= act->mods.mask= mods; - if ((tmp= XkbModActionVMods(&act->mods))!=0) { - XkbVirtualModsToReal(xkb,tmp,&tmp); - act->mods.mask|= tmp; - } - break; - case XkbSA_ISOLock: - if (act->iso.flags&XkbSA_UseModMapMods) - act->iso.real_mods= act->iso.mask= mods; - if ((tmp= XkbModActionVMods(&act->iso))!=0) { - XkbVirtualModsToReal(xkb,tmp,&tmp); - act->iso.mask|= tmp; - } - break; - } - return; -} - -#define IBUF_SIZE 8 - -Bool -XkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes) -{ -KeySym * syms; -unsigned char explicit,mods; -XkbSymInterpretPtr *interps,ibuf[IBUF_SIZE]; -int n,nSyms,found; -unsigned changed,tmp; - - if ((!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)|| - (!xkb->compat)||(!xkb->compat->sym_interpret)|| - (key<xkb->min_key_code)||(key>xkb->max_key_code)) { - return FALSE; - } - if (((!xkb->server)||(!xkb->server->key_acts))&& - (XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success)) { - return FALSE; - } - changed= 0; /* keeps track of what has changed in _this_ call */ - explicit= xkb->server->explicit[key]; - if (explicit&XkbExplicitInterpretMask) /* nothing to do */ - return TRUE; - mods= (xkb->map->modmap?xkb->map->modmap[key]:0); - nSyms= XkbKeyNumSyms(xkb,key); - syms= XkbKeySymsPtr(xkb,key); - if (nSyms>IBUF_SIZE) { - interps= xcalloc(nSyms, sizeof(XkbSymInterpretPtr)); - if (interps==NULL) { - interps= ibuf; - nSyms= IBUF_SIZE; - } - } - else { - interps= ibuf; - } - found= 0; - for (n=0;n<nSyms;n++) { - unsigned level= (n%XkbKeyGroupsWidth(xkb,key)); - interps[n]= NULL; - if (syms[n]!=NoSymbol) { - interps[n]= _XkbFindMatchingInterp(xkb,syms[n],mods,level); - if (interps[n]&&interps[n]->act.type!=XkbSA_NoAction) - found++; - else interps[n]= NULL; - } - } - /* 1/28/96 (ef) -- XXX! WORKING HERE */ - if (!found) { - if (xkb->server->key_acts[key]!=0) { - xkb->server->key_acts[key]= 0; - changed|= XkbKeyActionsMask; - } - } - else { - XkbAction *pActs; - unsigned int new_vmodmask; - changed|= XkbKeyActionsMask; - pActs= XkbResizeKeyActions(xkb,key,nSyms); - if (!pActs) { - if (nSyms > IBUF_SIZE) - xfree(interps); - return FALSE; - } - new_vmodmask= 0; - for (n=0;n<nSyms;n++) { - if (interps[n]) { - unsigned effMods; - - pActs[n]= *((XkbAction *)&interps[n]->act); - if ((n==0)||((interps[n]->match&XkbSI_LevelOneOnly)==0)) { - effMods= mods; - if (interps[n]->virtual_mod!=XkbNoModifier) - new_vmodmask|= (1<<interps[n]->virtual_mod); - } - else effMods= 0; - _XkbSetActionKeyMods(xkb,&pActs[n],effMods); - } - else pActs[n].type= XkbSA_NoAction; - } - if (((explicit&XkbExplicitVModMapMask)==0)&& - (xkb->server->vmodmap[key]!=new_vmodmask)) { - changed|= XkbVirtualModMapMask; - xkb->server->vmodmap[key]= new_vmodmask; - } - if (interps[0]) { - if ((interps[0]->flags&XkbSI_LockingKey)&& - ((explicit&XkbExplicitBehaviorMask)==0)) { - xkb->server->behaviors[key].type= XkbKB_Lock; - changed|= XkbKeyBehaviorsMask; - } - if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) { - CARD8 old; - old= xkb->ctrls->per_key_repeat[key/8]; - if (interps[0]->flags&XkbSI_AutoRepeat) - xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8)); - else xkb->ctrls->per_key_repeat[key/8]&= ~(1<<(key%8)); - if (changes && (old!=xkb->ctrls->per_key_repeat[key/8])) - changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask; - } - } - } - if ((!found)||(interps[0]==NULL)) { - if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) { - CARD8 old; - old= xkb->ctrls->per_key_repeat[key/8]; - xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8)); - if (changes && (old!=xkb->ctrls->per_key_repeat[key/8])) - changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask; - } - if (((explicit&XkbExplicitBehaviorMask)==0)&& - (xkb->server->behaviors[key].type==XkbKB_Lock)) { - xkb->server->behaviors[key].type= XkbKB_Default; - changed|= XkbKeyBehaviorsMask; - } - } - if (changes) { - XkbMapChangesPtr mc; - mc= &changes->map; - tmp= (changed&mc->changed); - if (tmp&XkbKeyActionsMask) - _XkbAddKeyChange(&mc->first_key_act,&mc->num_key_acts,key); - else if (changed&XkbKeyActionsMask) { - mc->changed|= XkbKeyActionsMask; - mc->first_key_act= key; - mc->num_key_acts= 1; - } - if (tmp&XkbKeyBehaviorsMask) { - _XkbAddKeyChange(&mc->first_key_behavior,&mc->num_key_behaviors, - key); - } - else if (changed&XkbKeyBehaviorsMask) { - mc->changed|= XkbKeyBehaviorsMask; - mc->first_key_behavior= key; - mc->num_key_behaviors= 1; - } - if (tmp&XkbVirtualModMapMask) - _XkbAddKeyChange(&mc->first_vmodmap_key,&mc->num_vmodmap_keys,key); - else if (changed&XkbVirtualModMapMask) { - mc->changed|= XkbVirtualModMapMask; - mc->first_vmodmap_key= key; - mc->num_vmodmap_keys= 1; - } - mc->changed|= changed; - } - if (interps!=ibuf) - xfree(interps); - return TRUE; -} - -Status -XkbChangeTypesOfKey( XkbDescPtr xkb, - int key, - int nGroups, - unsigned groups, - int * newTypesIn, - XkbMapChangesPtr changes) -{ -XkbKeyTypePtr pOldType,pNewType; -register int i; -int width,nOldGroups,oldWidth,newTypes[XkbNumKbdGroups]; - - if ((!xkb) || (!XkbKeycodeInRange(xkb,key)) || (!xkb->map) || - (!xkb->map->types)||(!newTypesIn)||((groups&XkbAllGroupsMask)==0)|| - (nGroups>XkbNumKbdGroups)) { - return BadMatch; - } - if (nGroups==0) { - for (i=0;i<XkbNumKbdGroups;i++) { - xkb->map->key_sym_map[key].kt_index[i]= XkbOneLevelIndex; - } - i= xkb->map->key_sym_map[key].group_info; - i= XkbSetNumGroups(i,0); - xkb->map->key_sym_map[key].group_info= i; - XkbResizeKeySyms(xkb,key,0); - return Success; - } - - nOldGroups= XkbKeyNumGroups(xkb,key); - oldWidth= XkbKeyGroupsWidth(xkb,key); - for (width=i=0;i<nGroups;i++) { - if (groups&(1<<i)) - newTypes[i]= newTypesIn[i]; - else if (i<nOldGroups) - newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,i); - else if (nOldGroups>0) - newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index); - else newTypes[i]= XkbTwoLevelIndex; - if (newTypes[i]>xkb->map->num_types) - return BadMatch; - pNewType= &xkb->map->types[newTypes[i]]; - if (pNewType->num_levels>width) - width= pNewType->num_levels; - } - if ((xkb->ctrls)&&(nGroups>xkb->ctrls->num_groups)) - xkb->ctrls->num_groups= nGroups; - if ((width!=oldWidth)||(nGroups!=nOldGroups)) { - KeySym oldSyms[XkbMaxSymsPerKey],*pSyms; - int nCopy; - - if (nOldGroups==0) { - pSyms= XkbResizeKeySyms(xkb,key,width*nGroups); - if (pSyms!=NULL) { - i= xkb->map->key_sym_map[key].group_info; - i= XkbSetNumGroups(i,nGroups); - xkb->map->key_sym_map[key].group_info= i; - xkb->map->key_sym_map[key].width= width; - for (i=0;i<nGroups;i++) { - xkb->map->key_sym_map[key].kt_index[i]= newTypes[i]; - } - return Success; - } - return BadAlloc; - } - pSyms= XkbKeySymsPtr(xkb,key); - memcpy(oldSyms,pSyms,XkbKeyNumSyms(xkb,key)*sizeof(KeySym)); - pSyms= XkbResizeKeySyms(xkb,key,width*nGroups); - if (pSyms==NULL) - return BadAlloc; - bzero(pSyms,width*nGroups*sizeof(KeySym)); - for (i=0;(i<nGroups)&&(i<nOldGroups);i++) { - pOldType= XkbKeyKeyType(xkb,key,i); - pNewType= &xkb->map->types[newTypes[i]]; - if (pNewType->num_levels>pOldType->num_levels) - nCopy= pOldType->num_levels; - else nCopy= pNewType->num_levels; - memcpy(&pSyms[i*width],&oldSyms[i*oldWidth],nCopy*sizeof(KeySym)); - } - if (XkbKeyHasActions(xkb,key)) { - XkbAction oldActs[XkbMaxSymsPerKey],*pActs; - pActs= XkbKeyActionsPtr(xkb,key); - memcpy(oldActs,pActs,XkbKeyNumSyms(xkb,key)*sizeof(XkbAction)); - pActs= XkbResizeKeyActions(xkb,key,width*nGroups); - if (pActs==NULL) - return BadAlloc; - bzero(pActs,width*nGroups*sizeof(XkbAction)); - for (i=0;(i<nGroups)&&(i<nOldGroups);i++) { - pOldType= XkbKeyKeyType(xkb,key,i); - pNewType= &xkb->map->types[newTypes[i]]; - if (pNewType->num_levels>pOldType->num_levels) - nCopy= pOldType->num_levels; - else nCopy= pNewType->num_levels; - memcpy(&pActs[i*width],&oldActs[i*oldWidth], - nCopy*sizeof(XkbAction)); - } - } - i= xkb->map->key_sym_map[key].group_info; - i= XkbSetNumGroups(i,nGroups); - xkb->map->key_sym_map[key].group_info= i; - xkb->map->key_sym_map[key].width= width; - } - width= 0; - for (i=0;i<nGroups;i++) { - xkb->map->key_sym_map[key].kt_index[i]= newTypes[i]; - if (xkb->map->types[newTypes[i]].num_levels>width) - width= xkb->map->types[newTypes[i]].num_levels; - } - xkb->map->key_sym_map[key].width= width; - if (changes!=NULL) { - if (changes->changed&XkbKeySymsMask) { - _XkbAddKeyChange(&changes->first_key_sym,&changes->num_key_syms, - key); - } - else { - changes->changed|= XkbKeySymsMask; - changes->first_key_sym= key; - changes->num_key_syms= 1; - } - } - return Success; -} - -/***====================================================================***/ - -Bool -XkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned *mask_rtrn) -{ -register int i,bit; -register unsigned mask; - - if (xkb==NULL) - return FALSE; - if (virtual_mask==0) { - *mask_rtrn= 0; - return TRUE; - } - if (xkb->server==NULL) - return FALSE; - for (i=mask=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - if (virtual_mask&bit) - mask|= xkb->server->vmods[i]; - } - *mask_rtrn= mask; - return TRUE; -} - -/***====================================================================***/ - -static Bool -XkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction *act,unsigned changed) -{ -unsigned int tmp; - - switch (act->type) { - case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: - if (((tmp= XkbModActionVMods(&act->mods))&changed)!=0) { - XkbVirtualModsToReal(xkb,tmp,&tmp); - act->mods.mask= act->mods.real_mods; - act->mods.mask|= tmp; - return TRUE; - } - break; - case XkbSA_ISOLock: - if ((((tmp= XkbModActionVMods(&act->iso))!=0)&changed)!=0) { - XkbVirtualModsToReal(xkb,tmp,&tmp); - act->iso.mask= act->iso.real_mods; - act->iso.mask|= tmp; - return TRUE; - } - break; - } - return FALSE; -} - -static void -XkbUpdateKeyTypeVirtualMods( XkbDescPtr xkb, - XkbKeyTypePtr type, - unsigned int changed, - XkbChangesPtr changes) -{ -register unsigned int i; -unsigned int mask; - - XkbVirtualModsToReal(xkb,type->mods.vmods,&mask); - type->mods.mask= type->mods.real_mods|mask; - if ((type->map_count>0)&&(type->mods.vmods!=0)) { - XkbKTMapEntryPtr entry; - for (i=0,entry=type->map;i<type->map_count;i++,entry++) { - if (entry->mods.vmods!=0) { - XkbVirtualModsToReal(xkb,entry->mods.vmods,&mask); - entry->mods.mask=entry->mods.real_mods|mask; - /* entry is active if vmods are bound*/ - entry->active= (mask!=0); - } - else entry->active= 1; - } - } - if (changes) { - int type_ndx; - type_ndx= type-xkb->map->types; - if ((type_ndx<0)||(type_ndx>xkb->map->num_types)) - return; - if (changes->map.changed&XkbKeyTypesMask) { - int last; - last= changes->map.first_type+changes->map.num_types-1; - if (type_ndx<changes->map.first_type) { - changes->map.first_type= type_ndx; - changes->map.num_types= (last-type_ndx)+1; - } - else if (type_ndx>last) { - changes->map.num_types= (type_ndx-changes->map.first_type)+1; - } - } - else { - changes->map.changed|= XkbKeyTypesMask; - changes->map.first_type= type_ndx; - changes->map.num_types= 1; - } - } - return; -} - -Bool -XkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes) -{ -register int i; -unsigned int checkState = 0; - - if ((!xkb) || (!xkb->map) || (changed==0)) - return FALSE; - for (i=0;i<xkb->map->num_types;i++) { - if (xkb->map->types[i].mods.vmods & changed) - XkbUpdateKeyTypeVirtualMods(xkb,&xkb->map->types[i],changed,changes); - } - if (changed&xkb->ctrls->internal.vmods) { - unsigned int newMask; - XkbVirtualModsToReal(xkb,xkb->ctrls->internal.vmods,&newMask); - newMask|= xkb->ctrls->internal.real_mods; - if (xkb->ctrls->internal.mask!=newMask) { - xkb->ctrls->internal.mask= newMask; - if (changes) { - changes->ctrls.changed_ctrls|= XkbInternalModsMask; - checkState= TRUE; - } - } - } - if (changed&xkb->ctrls->ignore_lock.vmods) { - unsigned int newMask; - XkbVirtualModsToReal(xkb,xkb->ctrls->ignore_lock.vmods,&newMask); - newMask|= xkb->ctrls->ignore_lock.real_mods; - if (xkb->ctrls->ignore_lock.mask!=newMask) { - xkb->ctrls->ignore_lock.mask= newMask; - if (changes) { - changes->ctrls.changed_ctrls|= XkbIgnoreLockModsMask; - checkState= TRUE; - } - } - } - if (xkb->indicators!=NULL) { - XkbIndicatorMapPtr map; - map= &xkb->indicators->maps[0]; - for (i=0;i<XkbNumIndicators;i++,map++) { - if (map->mods.vmods&changed) { - unsigned int newMask; - XkbVirtualModsToReal(xkb,map->mods.vmods,&newMask); - newMask|= map->mods.real_mods; - if (newMask!=map->mods.mask) { - map->mods.mask= newMask; - if (changes) { - changes->indicators.map_changes|= (1<<i); - checkState= TRUE; - } - } - } - } - } - if (xkb->compat!=NULL) { - XkbCompatMapPtr compat; - compat= xkb->compat; - for (i=0;i<XkbNumKbdGroups;i++) { - unsigned int newMask; - XkbVirtualModsToReal(xkb,compat->groups[i].vmods,&newMask); - newMask|= compat->groups[i].real_mods; - if (compat->groups[i].mask!=newMask) { - compat->groups[i].mask= newMask; - if (changes) { - changes->compat.changed_groups|= (1<<i); - checkState= TRUE; - } - } - } - } - if (xkb->map && xkb->server) { - int highChange = 0, lowChange = -1; - for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { - if (XkbKeyHasActions(xkb,i)) { - register XkbAction *pAct; - register int n; - - pAct= XkbKeyActionsPtr(xkb,i); - for (n=XkbKeyNumActions(xkb,i);n>0;n--,pAct++) { - if ((pAct->type!=XkbSA_NoAction)&& - XkbUpdateActionVirtualMods(xkb,pAct,changed)) { - if (lowChange<0) - lowChange= i; - highChange= i; - } - } - } - } - if (changes && (lowChange>0)) { /* something changed */ - if (changes->map.changed&XkbKeyActionsMask) { - int last; - if (changes->map.first_key_act<lowChange) - lowChange= changes->map.first_key_act; - last= changes->map.first_key_act+changes->map.num_key_acts-1; - if (last>highChange) - highChange= last; - } - changes->map.changed|= XkbKeyActionsMask; - changes->map.first_key_act= lowChange; - changes->map.num_key_acts= (highChange-lowChange)+1; - } - } - return checkState; -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#elif defined(HAVE_CONFIG_H) +#include <config.h> +#endif + +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "inputstr.h" +#include <X11/keysym.h> +#define XKBSRV_NEED_FILE_FUNCS +#include <xkbsrv.h> + +/***====================================================================***/ + +#define CORE_SYM(i) (i<map_width?core_syms[i]:NoSymbol) +#define XKB_OFFSET(g,l) (((g)*groupsWidth)+(l)) + +int +XkbKeyTypesForCoreSymbols( XkbDescPtr xkb, + int map_width, + KeySym * core_syms, + unsigned int protected, + int * types_inout, + KeySym * xkb_syms_rtrn) +{ +register int i; +unsigned int empty; +int nSyms[XkbNumKbdGroups]; +int nGroups,tmp,groupsWidth; +BOOL replicated = FALSE; + + /* Section 12.2 of the protocol describes this process in more detail */ + /* Step 1: find the # of symbols in the core mapping per group */ + groupsWidth= 2; + for (i=0;i<XkbNumKbdGroups;i++) { + if ((protected&(1<<i))&&(types_inout[i]<xkb->map->num_types)) { + nSyms[i]= xkb->map->types[types_inout[i]].num_levels; + if (nSyms[i]>groupsWidth) + groupsWidth= nSyms[i]; + } + else { + types_inout[i]= XkbTwoLevelIndex; /* don't really know, yet */ + nSyms[i]= 2; + } + } + if (nSyms[XkbGroup1Index]<2) + nSyms[XkbGroup1Index]= 2; + if (nSyms[XkbGroup2Index]<2) + nSyms[XkbGroup2Index]= 2; + /* Step 2: Copy the symbols from the core ordering to XKB ordering */ + /* symbols in the core are in the order: */ + /* G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*] */ + xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,0)]= CORE_SYM(0); + xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,1)]= CORE_SYM(1); + for (i=2;i<nSyms[XkbGroup1Index];i++) { + xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,i)]= CORE_SYM(2+i); + } + xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,0)]= CORE_SYM(2); + xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,1)]= CORE_SYM(3); + tmp= 2+(nSyms[XkbGroup1Index]-2); /* offset to extra group2 syms */ + for (i=2;i<nSyms[XkbGroup2Index];i++) { + xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,i)]= CORE_SYM(tmp+i); + } + + /* Special case: if only the first group is explicit, and the symbols + * replicate across all groups, then we have a Section 12.4 replication */ + if ((protected & ~XkbExplicitKeyType1Mask) == 0) + { + int j, width = nSyms[XkbGroup1Index]; + + replicated = TRUE; + + /* Check ABAB in ABABCDECDEABCDE */ + if ((width > 0 && CORE_SYM(0) != CORE_SYM(2)) || + (width > 1 && CORE_SYM(1) != CORE_SYM(3))) + replicated = FALSE; + + /* Check CDECDE in ABABCDECDEABCDE */ + for (i = 2; i < width && replicated; i++) + { + if (CORE_SYM(2 + i) != CORE_SYM(i + width)) + replicated = FALSE; + } + + /* Check ABCDE in ABABCDECDEABCDE */ + for (j = 2; replicated && + j < XkbNumKbdGroups && + map_width >= width * (j + 1); j++) + { + for (i = 0; i < width && replicated; i++) + { + if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j)) + replicated = FALSE; + } + } + } + + if (replicated) + { + nSyms[XkbGroup2Index]= 0; + nSyms[XkbGroup3Index]= 0; + nSyms[XkbGroup4Index]= 0; + nGroups= 1; + } else + { + tmp= nSyms[XkbGroup1Index]+nSyms[XkbGroup2Index]; + if ((tmp>=map_width)&& + ((protected&(XkbExplicitKeyType3Mask|XkbExplicitKeyType4Mask))==0)) { + nSyms[XkbGroup3Index]= 0; + nSyms[XkbGroup4Index]= 0; + nGroups= 2; + } else + { + nGroups= 3; + for (i=0;i<nSyms[XkbGroup3Index];i++,tmp++) { + xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index,i)]= CORE_SYM(tmp); + } + if ((tmp<map_width)||(protected&XkbExplicitKeyType4Mask)) { + nGroups= 4; + for (i=0;i<nSyms[XkbGroup4Index];i++,tmp++) { + xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index,i)]= CORE_SYM(tmp); + } + } + else { + nSyms[XkbGroup4Index]= 0; + } + } + } + /* steps 3&4: alphanumeric expansion, assign canonical types */ + empty= 0; + for (i=0;i<nGroups;i++) { + KeySym *syms; + syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)]; + if ((nSyms[i]>1)&&(syms[1]==NoSymbol)&&(syms[0]!=NoSymbol)) { + KeySym upper,lower; + XkbConvertCase(syms[0],&lower,&upper); + if (upper!=lower) { + xkb_syms_rtrn[XKB_OFFSET(i,0)]= lower; + xkb_syms_rtrn[XKB_OFFSET(i,1)]= upper; + if ((protected&(1<<i))==0) + types_inout[i]= XkbAlphabeticIndex; + } + else if ((protected&(1<<i))==0) { + types_inout[i]= XkbOneLevelIndex; + /* nSyms[i]= 1;*/ + } + } + if (((protected&(1<<i))==0)&&(types_inout[i]==XkbTwoLevelIndex)) { + if (XkbKSIsKeypad(syms[0])||XkbKSIsKeypad(syms[1])) + types_inout[i]= XkbKeypadIndex; + else { + KeySym upper,lower; + XkbConvertCase(syms[0],&lower,&upper); + if ((syms[0]==lower)&&(syms[1]==upper)) + types_inout[i]= XkbAlphabeticIndex; + } + } + if (syms[0]==NoSymbol) { + register int n; + Bool found; + for (n=1,found=FALSE;(!found)&&(n<nSyms[i]);n++) { + found= (syms[n]!=NoSymbol); + } + if (!found) + empty|= (1<<i); + } + } + /* step 5: squoosh out empty groups */ + if (empty) { + for (i=nGroups-1;i>=0;i--) { + if (((empty&(1<<i))==0)||(protected&(1<<i))) + break; + nGroups--; + } + } + if (nGroups<1) + return 0; + + /* step 6: replicate group 1 into group two, if necessary */ + if ((nGroups>1)&&((empty&(XkbGroup1Mask|XkbGroup2Mask))==XkbGroup2Mask)) { + if ((protected&(XkbExplicitKeyType1Mask|XkbExplicitKeyType2Mask))==0) { + nSyms[XkbGroup2Index]= nSyms[XkbGroup1Index]; + types_inout[XkbGroup2Index]= types_inout[XkbGroup1Index]; + memcpy((char *)&xkb_syms_rtrn[2],(char *)xkb_syms_rtrn, + 2*sizeof(KeySym)); + } + else if (types_inout[XkbGroup1Index]==types_inout[XkbGroup2Index]) { + memcpy((char *)&xkb_syms_rtrn[nSyms[XkbGroup1Index]], + (char *)xkb_syms_rtrn, + nSyms[XkbGroup1Index]*sizeof(KeySym)); + } + } + + /* step 7: check for all groups identical or all width 1 + * + * Special feature: if group 1 has an explicit type and all other groups + * have canonical types with same symbols, we assume it's info lost from + * the core replication. + */ + if (nGroups>1) { + Bool sameType,allOneLevel, canonical = TRUE; + allOneLevel= (xkb->map->types[types_inout[0]].num_levels==1); + for (i=1,sameType=TRUE;(allOneLevel||sameType)&&(i<nGroups);i++) { + sameType=(sameType&&(types_inout[i]==types_inout[XkbGroup1Index])); + if (allOneLevel) + allOneLevel= (xkb->map->types[types_inout[i]].num_levels==1); + if (types_inout[i] > XkbLastRequiredType) + canonical = FALSE; + } + if (((sameType) || canonical)&& + (!(protected&(XkbExplicitKeyTypesMask&~XkbExplicitKeyType1Mask)))){ + register int s; + Bool identical; + for (i=1,identical=TRUE;identical&&(i<nGroups);i++) { + KeySym *syms; + if (nSyms[i] != nSyms[XkbGroup1Index]) + identical = FALSE; + syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)]; + for (s=0;identical&&(s<nSyms[i]);s++) { + if (syms[s]!=xkb_syms_rtrn[s]) + identical= FALSE; + } + } + if (identical) + nGroups= 1; + } + if (allOneLevel && (nGroups>1)) { + KeySym *syms; + syms= &xkb_syms_rtrn[nSyms[XkbGroup1Index]]; + nSyms[XkbGroup1Index]= 1; + for (i=1;i<nGroups;i++) { + xkb_syms_rtrn[i]= syms[0]; + syms+= nSyms[i]; + nSyms[i]= 1; + } + } + } + return nGroups; +} + +static XkbSymInterpretPtr +_XkbFindMatchingInterp( XkbDescPtr xkb, + KeySym sym, + unsigned int real_mods, + unsigned int level) +{ +register unsigned i; +XkbSymInterpretPtr interp,rtrn; +CARD8 mods; + + rtrn= NULL; + interp= xkb->compat->sym_interpret; + for (i=0;i<xkb->compat->num_si;i++,interp++) { + if ((interp->sym==NoSymbol)||(sym==interp->sym)) { + int match; + if ((level==0)||((interp->match&XkbSI_LevelOneOnly)==0)) + mods= real_mods; + else mods= 0; + switch (interp->match&XkbSI_OpMask) { + case XkbSI_NoneOf: + match= ((interp->mods&mods)==0); + break; + case XkbSI_AnyOfOrNone: + match= ((mods==0)||((interp->mods&mods)!=0)); + break; + case XkbSI_AnyOf: + match= ((interp->mods&mods)!=0); + break; + case XkbSI_AllOf: + match= ((interp->mods&mods)==interp->mods); + break; + case XkbSI_Exactly: + match= (interp->mods==mods); + break; + default: + match= 0; + break; + } + if (match) { + if (interp->sym!=NoSymbol) { + return interp; + } + else if (rtrn==NULL) { + rtrn= interp; + } + } + } + } + return rtrn; +} + +static void +_XkbAddKeyChange(KeyCode *pFirst,unsigned char *pNum,KeyCode newKey) +{ +KeyCode last; + + last= (*pFirst)+(*pNum); + if (newKey<*pFirst) { + *pFirst= newKey; + *pNum= (last-newKey)+1; + } + else if (newKey>last) { + *pNum= (last-*pFirst)+1; + } + return; +} + +static void +_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods) +{ +unsigned tmp; + + switch (act->type) { + case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: + if (act->mods.flags&XkbSA_UseModMapMods) + act->mods.real_mods= act->mods.mask= mods; + if ((tmp= XkbModActionVMods(&act->mods))!=0) { + XkbVirtualModsToReal(xkb,tmp,&tmp); + act->mods.mask|= tmp; + } + break; + case XkbSA_ISOLock: + if (act->iso.flags&XkbSA_UseModMapMods) + act->iso.real_mods= act->iso.mask= mods; + if ((tmp= XkbModActionVMods(&act->iso))!=0) { + XkbVirtualModsToReal(xkb,tmp,&tmp); + act->iso.mask|= tmp; + } + break; + } + return; +} + +#define IBUF_SIZE 8 + +Bool +XkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes) +{ +KeySym * syms; +unsigned char explicit,mods; +XkbSymInterpretPtr *interps,ibuf[IBUF_SIZE]; +int n,nSyms,found; +unsigned changed,tmp; + + if ((!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)|| + (!xkb->compat)||(!xkb->compat->sym_interpret)|| + (key<xkb->min_key_code)||(key>xkb->max_key_code)) { + return FALSE; + } + if (((!xkb->server)||(!xkb->server->key_acts))&& + (XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success)) { + return FALSE; + } + changed= 0; /* keeps track of what has changed in _this_ call */ + explicit= xkb->server->explicit[key]; + if (explicit&XkbExplicitInterpretMask) /* nothing to do */ + return TRUE; + mods= (xkb->map->modmap?xkb->map->modmap[key]:0); + nSyms= XkbKeyNumSyms(xkb,key); + syms= XkbKeySymsPtr(xkb,key); + if (nSyms>IBUF_SIZE) { + interps= calloc(nSyms, sizeof(XkbSymInterpretPtr)); + if (interps==NULL) { + interps= ibuf; + nSyms= IBUF_SIZE; + } + } + else { + interps= ibuf; + } + found= 0; + for (n=0;n<nSyms;n++) { + unsigned level= (n%XkbKeyGroupsWidth(xkb,key)); + interps[n]= NULL; + if (syms[n]!=NoSymbol) { + interps[n]= _XkbFindMatchingInterp(xkb,syms[n],mods,level); + if (interps[n]&&interps[n]->act.type!=XkbSA_NoAction) + found++; + else interps[n]= NULL; + } + } + /* 1/28/96 (ef) -- XXX! WORKING HERE */ + if (!found) { + if (xkb->server->key_acts[key]!=0) { + xkb->server->key_acts[key]= 0; + changed|= XkbKeyActionsMask; + } + } + else { + XkbAction *pActs; + unsigned int new_vmodmask; + changed|= XkbKeyActionsMask; + pActs= XkbResizeKeyActions(xkb,key,nSyms); + if (!pActs) { + if (nSyms > IBUF_SIZE) + free(interps); + return FALSE; + } + new_vmodmask= 0; + for (n=0;n<nSyms;n++) { + if (interps[n]) { + unsigned effMods; + + pActs[n]= *((XkbAction *)&interps[n]->act); + if ((n==0)||((interps[n]->match&XkbSI_LevelOneOnly)==0)) { + effMods= mods; + if (interps[n]->virtual_mod!=XkbNoModifier) + new_vmodmask|= (1<<interps[n]->virtual_mod); + } + else effMods= 0; + _XkbSetActionKeyMods(xkb,&pActs[n],effMods); + } + else pActs[n].type= XkbSA_NoAction; + } + if (((explicit&XkbExplicitVModMapMask)==0)&& + (xkb->server->vmodmap[key]!=new_vmodmask)) { + changed|= XkbVirtualModMapMask; + xkb->server->vmodmap[key]= new_vmodmask; + } + if (interps[0]) { + if ((interps[0]->flags&XkbSI_LockingKey)&& + ((explicit&XkbExplicitBehaviorMask)==0)) { + xkb->server->behaviors[key].type= XkbKB_Lock; + changed|= XkbKeyBehaviorsMask; + } + if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) { + CARD8 old; + old= xkb->ctrls->per_key_repeat[key/8]; + if (interps[0]->flags&XkbSI_AutoRepeat) + xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8)); + else xkb->ctrls->per_key_repeat[key/8]&= ~(1<<(key%8)); + if (changes && (old!=xkb->ctrls->per_key_repeat[key/8])) + changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask; + } + } + } + if ((!found)||(interps[0]==NULL)) { + if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) { + CARD8 old; + old= xkb->ctrls->per_key_repeat[key/8]; + xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8)); + if (changes && (old!=xkb->ctrls->per_key_repeat[key/8])) + changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask; + } + if (((explicit&XkbExplicitBehaviorMask)==0)&& + (xkb->server->behaviors[key].type==XkbKB_Lock)) { + xkb->server->behaviors[key].type= XkbKB_Default; + changed|= XkbKeyBehaviorsMask; + } + } + if (changes) { + XkbMapChangesPtr mc; + mc= &changes->map; + tmp= (changed&mc->changed); + if (tmp&XkbKeyActionsMask) + _XkbAddKeyChange(&mc->first_key_act,&mc->num_key_acts,key); + else if (changed&XkbKeyActionsMask) { + mc->changed|= XkbKeyActionsMask; + mc->first_key_act= key; + mc->num_key_acts= 1; + } + if (tmp&XkbKeyBehaviorsMask) { + _XkbAddKeyChange(&mc->first_key_behavior,&mc->num_key_behaviors, + key); + } + else if (changed&XkbKeyBehaviorsMask) { + mc->changed|= XkbKeyBehaviorsMask; + mc->first_key_behavior= key; + mc->num_key_behaviors= 1; + } + if (tmp&XkbVirtualModMapMask) + _XkbAddKeyChange(&mc->first_vmodmap_key,&mc->num_vmodmap_keys,key); + else if (changed&XkbVirtualModMapMask) { + mc->changed|= XkbVirtualModMapMask; + mc->first_vmodmap_key= key; + mc->num_vmodmap_keys= 1; + } + mc->changed|= changed; + } + if (interps!=ibuf) + free(interps); + return TRUE; +} + +Status +XkbChangeTypesOfKey( XkbDescPtr xkb, + int key, + int nGroups, + unsigned groups, + int * newTypesIn, + XkbMapChangesPtr changes) +{ +XkbKeyTypePtr pOldType,pNewType; +register int i; +int width,nOldGroups,oldWidth,newTypes[XkbNumKbdGroups]; + + if ((!xkb) || (!XkbKeycodeInRange(xkb,key)) || (!xkb->map) || + (!xkb->map->types)||(!newTypesIn)||((groups&XkbAllGroupsMask)==0)|| + (nGroups>XkbNumKbdGroups)) { + return BadMatch; + } + if (nGroups==0) { + for (i=0;i<XkbNumKbdGroups;i++) { + xkb->map->key_sym_map[key].kt_index[i]= XkbOneLevelIndex; + } + i= xkb->map->key_sym_map[key].group_info; + i= XkbSetNumGroups(i,0); + xkb->map->key_sym_map[key].group_info= i; + XkbResizeKeySyms(xkb,key,0); + return Success; + } + + nOldGroups= XkbKeyNumGroups(xkb,key); + oldWidth= XkbKeyGroupsWidth(xkb,key); + for (width=i=0;i<nGroups;i++) { + if (groups&(1<<i)) + newTypes[i]= newTypesIn[i]; + else if (i<nOldGroups) + newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,i); + else if (nOldGroups>0) + newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index); + else newTypes[i]= XkbTwoLevelIndex; + if (newTypes[i]>xkb->map->num_types) + return BadMatch; + pNewType= &xkb->map->types[newTypes[i]]; + if (pNewType->num_levels>width) + width= pNewType->num_levels; + } + if ((xkb->ctrls)&&(nGroups>xkb->ctrls->num_groups)) + xkb->ctrls->num_groups= nGroups; + if ((width!=oldWidth)||(nGroups!=nOldGroups)) { + KeySym oldSyms[XkbMaxSymsPerKey],*pSyms; + int nCopy; + + if (nOldGroups==0) { + pSyms= XkbResizeKeySyms(xkb,key,width*nGroups); + if (pSyms!=NULL) { + i= xkb->map->key_sym_map[key].group_info; + i= XkbSetNumGroups(i,nGroups); + xkb->map->key_sym_map[key].group_info= i; + xkb->map->key_sym_map[key].width= width; + for (i=0;i<nGroups;i++) { + xkb->map->key_sym_map[key].kt_index[i]= newTypes[i]; + } + return Success; + } + return BadAlloc; + } + pSyms= XkbKeySymsPtr(xkb,key); + memcpy(oldSyms,pSyms,XkbKeyNumSyms(xkb,key)*sizeof(KeySym)); + pSyms= XkbResizeKeySyms(xkb,key,width*nGroups); + if (pSyms==NULL) + return BadAlloc; + bzero(pSyms,width*nGroups*sizeof(KeySym)); + for (i=0;(i<nGroups)&&(i<nOldGroups);i++) { + pOldType= XkbKeyKeyType(xkb,key,i); + pNewType= &xkb->map->types[newTypes[i]]; + if (pNewType->num_levels>pOldType->num_levels) + nCopy= pOldType->num_levels; + else nCopy= pNewType->num_levels; + memcpy(&pSyms[i*width],&oldSyms[i*oldWidth],nCopy*sizeof(KeySym)); + } + if (XkbKeyHasActions(xkb,key)) { + XkbAction oldActs[XkbMaxSymsPerKey],*pActs; + pActs= XkbKeyActionsPtr(xkb,key); + memcpy(oldActs,pActs,XkbKeyNumSyms(xkb,key)*sizeof(XkbAction)); + pActs= XkbResizeKeyActions(xkb,key,width*nGroups); + if (pActs==NULL) + return BadAlloc; + bzero(pActs,width*nGroups*sizeof(XkbAction)); + for (i=0;(i<nGroups)&&(i<nOldGroups);i++) { + pOldType= XkbKeyKeyType(xkb,key,i); + pNewType= &xkb->map->types[newTypes[i]]; + if (pNewType->num_levels>pOldType->num_levels) + nCopy= pOldType->num_levels; + else nCopy= pNewType->num_levels; + memcpy(&pActs[i*width],&oldActs[i*oldWidth], + nCopy*sizeof(XkbAction)); + } + } + i= xkb->map->key_sym_map[key].group_info; + i= XkbSetNumGroups(i,nGroups); + xkb->map->key_sym_map[key].group_info= i; + xkb->map->key_sym_map[key].width= width; + } + width= 0; + for (i=0;i<nGroups;i++) { + xkb->map->key_sym_map[key].kt_index[i]= newTypes[i]; + if (xkb->map->types[newTypes[i]].num_levels>width) + width= xkb->map->types[newTypes[i]].num_levels; + } + xkb->map->key_sym_map[key].width= width; + if (changes!=NULL) { + if (changes->changed&XkbKeySymsMask) { + _XkbAddKeyChange(&changes->first_key_sym,&changes->num_key_syms, + key); + } + else { + changes->changed|= XkbKeySymsMask; + changes->first_key_sym= key; + changes->num_key_syms= 1; + } + } + return Success; +} + +/***====================================================================***/ + +Bool +XkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned *mask_rtrn) +{ +register int i,bit; +register unsigned mask; + + if (xkb==NULL) + return FALSE; + if (virtual_mask==0) { + *mask_rtrn= 0; + return TRUE; + } + if (xkb->server==NULL) + return FALSE; + for (i=mask=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + if (virtual_mask&bit) + mask|= xkb->server->vmods[i]; + } + *mask_rtrn= mask; + return TRUE; +} + +/***====================================================================***/ + +static Bool +XkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction *act,unsigned changed) +{ +unsigned int tmp; + + switch (act->type) { + case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: + if (((tmp= XkbModActionVMods(&act->mods))&changed)!=0) { + XkbVirtualModsToReal(xkb,tmp,&tmp); + act->mods.mask= act->mods.real_mods; + act->mods.mask|= tmp; + return TRUE; + } + break; + case XkbSA_ISOLock: + if ((((tmp= XkbModActionVMods(&act->iso))!=0)&changed)!=0) { + XkbVirtualModsToReal(xkb,tmp,&tmp); + act->iso.mask= act->iso.real_mods; + act->iso.mask|= tmp; + return TRUE; + } + break; + } + return FALSE; +} + +static void +XkbUpdateKeyTypeVirtualMods( XkbDescPtr xkb, + XkbKeyTypePtr type, + unsigned int changed, + XkbChangesPtr changes) +{ +register unsigned int i; +unsigned int mask; + + XkbVirtualModsToReal(xkb,type->mods.vmods,&mask); + type->mods.mask= type->mods.real_mods|mask; + if ((type->map_count>0)&&(type->mods.vmods!=0)) { + XkbKTMapEntryPtr entry; + for (i=0,entry=type->map;i<type->map_count;i++,entry++) { + if (entry->mods.vmods!=0) { + XkbVirtualModsToReal(xkb,entry->mods.vmods,&mask); + entry->mods.mask=entry->mods.real_mods|mask; + /* entry is active if vmods are bound*/ + entry->active= (mask!=0); + } + else entry->active= 1; + } + } + if (changes) { + int type_ndx; + type_ndx= type-xkb->map->types; + if ((type_ndx<0)||(type_ndx>xkb->map->num_types)) + return; + if (changes->map.changed&XkbKeyTypesMask) { + int last; + last= changes->map.first_type+changes->map.num_types-1; + if (type_ndx<changes->map.first_type) { + changes->map.first_type= type_ndx; + changes->map.num_types= (last-type_ndx)+1; + } + else if (type_ndx>last) { + changes->map.num_types= (type_ndx-changes->map.first_type)+1; + } + } + else { + changes->map.changed|= XkbKeyTypesMask; + changes->map.first_type= type_ndx; + changes->map.num_types= 1; + } + } + return; +} + +Bool +XkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes) +{ +register int i; +unsigned int checkState = 0; + + if ((!xkb) || (!xkb->map) || (changed==0)) + return FALSE; + for (i=0;i<xkb->map->num_types;i++) { + if (xkb->map->types[i].mods.vmods & changed) + XkbUpdateKeyTypeVirtualMods(xkb,&xkb->map->types[i],changed,changes); + } + if (changed&xkb->ctrls->internal.vmods) { + unsigned int newMask; + XkbVirtualModsToReal(xkb,xkb->ctrls->internal.vmods,&newMask); + newMask|= xkb->ctrls->internal.real_mods; + if (xkb->ctrls->internal.mask!=newMask) { + xkb->ctrls->internal.mask= newMask; + if (changes) { + changes->ctrls.changed_ctrls|= XkbInternalModsMask; + checkState= TRUE; + } + } + } + if (changed&xkb->ctrls->ignore_lock.vmods) { + unsigned int newMask; + XkbVirtualModsToReal(xkb,xkb->ctrls->ignore_lock.vmods,&newMask); + newMask|= xkb->ctrls->ignore_lock.real_mods; + if (xkb->ctrls->ignore_lock.mask!=newMask) { + xkb->ctrls->ignore_lock.mask= newMask; + if (changes) { + changes->ctrls.changed_ctrls|= XkbIgnoreLockModsMask; + checkState= TRUE; + } + } + } + if (xkb->indicators!=NULL) { + XkbIndicatorMapPtr map; + map= &xkb->indicators->maps[0]; + for (i=0;i<XkbNumIndicators;i++,map++) { + if (map->mods.vmods&changed) { + unsigned int newMask; + XkbVirtualModsToReal(xkb,map->mods.vmods,&newMask); + newMask|= map->mods.real_mods; + if (newMask!=map->mods.mask) { + map->mods.mask= newMask; + if (changes) { + changes->indicators.map_changes|= (1<<i); + checkState= TRUE; + } + } + } + } + } + if (xkb->compat!=NULL) { + XkbCompatMapPtr compat; + compat= xkb->compat; + for (i=0;i<XkbNumKbdGroups;i++) { + unsigned int newMask; + XkbVirtualModsToReal(xkb,compat->groups[i].vmods,&newMask); + newMask|= compat->groups[i].real_mods; + if (compat->groups[i].mask!=newMask) { + compat->groups[i].mask= newMask; + if (changes) { + changes->compat.changed_groups|= (1<<i); + checkState= TRUE; + } + } + } + } + if (xkb->map && xkb->server) { + int highChange = 0, lowChange = -1; + for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { + if (XkbKeyHasActions(xkb,i)) { + register XkbAction *pAct; + register int n; + + pAct= XkbKeyActionsPtr(xkb,i); + for (n=XkbKeyNumActions(xkb,i);n>0;n--,pAct++) { + if ((pAct->type!=XkbSA_NoAction)&& + XkbUpdateActionVirtualMods(xkb,pAct,changed)) { + if (lowChange<0) + lowChange= i; + highChange= i; + } + } + } + } + if (changes && (lowChange>0)) { /* something changed */ + if (changes->map.changed&XkbKeyActionsMask) { + int last; + if (changes->map.first_key_act<lowChange) + lowChange= changes->map.first_key_act; + last= changes->map.first_key_act+changes->map.num_key_acts-1; + if (last>highChange) + highChange= last; + } + changes->map.changed|= XkbKeyActionsMask; + changes->map.first_key_act= lowChange; + changes->map.num_key_acts= (highChange-lowChange)+1; + } + } + return checkState; +} diff --git a/xorg-server/xkb/ddxList.c b/xorg-server/xkb/ddxList.c index e212ea3b5..927b885fb 100644 --- a/xorg-server/xkb/ddxList.c +++ b/xorg-server/xkb/ddxList.c @@ -1,293 +1,293 @@ -/************************************************************ -Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#endif - -#include <stdio.h> -#include <ctype.h> -#include <X11/X.h> -#include <X11/Xos.h> -#include <X11/Xproto.h> -#include <X11/keysym.h> -#include <X11/extensions/XKM.h> -#include "inputstr.h" -#include "scrnintstr.h" -#include "windowstr.h" -#define XKBSRV_NEED_FILE_FUNCS -#include <xkbsrv.h> -#include <X11/extensions/XI.h> - -#ifdef WIN32 -/* from ddxLoad.c */ -extern const char* Win32TempDir(); -extern int Win32System(const char *cmdline); -#undef System -#define System Win32System - -#define W32_tmparg " '%s'" -#define W32_tmpfile ,tmpname -#define W32_tmplen strlen(tmpname)+3 -#else -#define W32_tmparg -#define W32_tmpfile -#define W32_tmplen 0 -#endif - -/***====================================================================***/ - -static char *componentDirs[_XkbListNumComponents] = { - "keycodes", "types", "compat", "symbols", "geometry" -}; - -/***====================================================================***/ - -static Status -_AddListComponent( XkbSrvListInfoPtr list, - int what, - unsigned flags, - char * str, - ClientPtr client) -{ -int slen,wlen; -unsigned char * wire8; -unsigned short *wire16; -char * tmp; - - if (list->nTotal>=list->maxRtrn) { - list->nTotal++; - return Success; - } - tmp= strchr(str,')'); - if ((tmp==NULL)&&((tmp=strchr(str,'('))==NULL)) { - slen= strlen(str); - while ((slen>0) && isspace(str[slen-1])) { - slen--; - } - } - else { - slen= (tmp-str+1); - } - wlen= (((slen+1)/2)*2)+4; /* four bytes for flags and length, pad to */ - /* 2-byte boundary */ - if ((list->szPool-list->nPool)<wlen) { - if (wlen>1024) list->szPool+= XkbPaddedSize(wlen*2); - else list->szPool+= 1024; - list->pool= xrealloc(list->pool, list->szPool * sizeof(char)); - if (!list->pool) - return BadAlloc; - } - wire16= (unsigned short *)&list->pool[list->nPool]; - wire8= (unsigned char *)&wire16[2]; - wire16[0]= flags; - wire16[1]= slen; - memcpy(wire8,str,slen); - if (client->swapped) { - register int n; - swaps(&wire16[0],n); - swaps(&wire16[1],n); - } - list->nPool+= wlen; - list->nFound[what]++; - list->nTotal++; - return Success; -} - -/***====================================================================***/ -static Status -XkbDDXListComponent( DeviceIntPtr dev, - int what, - XkbSrvListInfoPtr list, - ClientPtr client) -{ -char *file,*map,*tmp,*buf=NULL; -FILE *in; -Status status; -int rval; -Bool haveDir; -#ifdef WIN32 -char tmpname[PATH_MAX]; -#endif - - if ((list->pattern[what]==NULL)||(list->pattern[what][0]=='\0')) - return Success; - file= list->pattern[what]; - map= strrchr(file,'('); - if (map!=NULL) { - char *tmp; - map++; - tmp= strrchr(map,')'); - if ((tmp==NULL)||(tmp[1]!='\0')) { - /* illegal pattern. No error, but no match */ - return Success; - } - } - - in= NULL; - haveDir= TRUE; -#ifdef WIN32 - strcpy(tmpname, Win32TempDir()); - strcat(tmpname, "\\xkb_XXXXXX"); - (void) mktemp(tmpname); -#endif - if (XkbBaseDirectory!=NULL) { - if ((list->pattern[what][0]=='*')&&(list->pattern[what][1]=='\0')) { - buf = Xprintf("%s/%s.dir",XkbBaseDirectory,componentDirs[what]); - in= fopen(buf,"r"); - } - if (!in) { - haveDir= FALSE; - buf = Xprintf( - "'%s/xkbcomp' '-R%s/%s' -w %ld -l -vlfhpR '%s'" W32_tmparg, - XkbBinDirectory,XkbBaseDirectory,componentDirs[what],(long) - ((xkbDebugFlags<2)?1:((xkbDebugFlags>10)?10:xkbDebugFlags)), - file W32_tmpfile - ); - } - } - else { - if ((list->pattern[what][0]=='*')&&(list->pattern[what][1]=='\0')) { - buf = Xprintf("%s.dir",componentDirs[what]); - in= fopen(buf,"r"); - } - if (!in) { - haveDir= FALSE; - buf = Xprintf( - "xkbcomp -R%s -w %ld -l -vlfhpR '%s'" W32_tmparg, - componentDirs[what],(long) - ((xkbDebugFlags<2)?1:((xkbDebugFlags>10)?10:xkbDebugFlags)), - file W32_tmpfile - ); - } - } - status= Success; - if (!haveDir) - { -#ifndef WIN32 - in= Popen(buf,"r"); -#else - if (xkbDebugFlags) - DebugF("[xkb] xkbList executes: %s\n",buf); - if (System(buf) < 0) - ErrorF("[xkb] Could not invoke keymap compiler\n"); - else - in= fopen(tmpname, "r"); -#endif - } - if (!in) - { - if (buf != NULL) - xfree (buf); -#ifdef WIN32 - unlink(tmpname); -#endif - return BadImplementation; - } - list->nFound[what]= 0; - if (buf) { - xfree(buf); - buf = NULL; - } - buf = xalloc(PATH_MAX * sizeof(char)); - if (!buf) - return BadAlloc; - while ((status==Success)&&((tmp=fgets(buf,PATH_MAX,in))!=NULL)) { - unsigned flags; - register unsigned int i; - if (*tmp=='#') /* comment, skip it */ - continue; - if (!strncmp(tmp, "Warning:", 8) || !strncmp(tmp, " ", 8)) - /* skip warnings too */ - continue; - flags= 0; - /* each line in the listing is supposed to start with two */ - /* groups of eight characters, which specify the general */ - /* flags and the flags that are specific to the component */ - /* if they're missing, fail with BadImplementation */ - for (i=0;(i<8)&&(status==Success);i++) { /* read the general flags */ - if (isalpha(*tmp)) flags|= (1L<<i); - else if (*tmp!='-') status= BadImplementation; - tmp++; - } - if (status != Success) break; - if (!isspace(*tmp)) { - status= BadImplementation; - break; - } - else tmp++; - for (i=0;(i<8)&&(status==Success);i++) { /* read the component flags */ - if (isalpha(*tmp)) flags|= (1L<<(i+8)); - else if (*tmp!='-') status= BadImplementation; - tmp++; - } - if (status != Success) break; - if (isspace(*tmp)) { - while (isspace(*tmp)) { - tmp++; - } - } - else { - status= BadImplementation; - break; - } - status= _AddListComponent(list,what,flags,tmp,client); - } -#ifndef WIN32 - if (haveDir) - fclose(in); - else if ((rval=Pclose(in))!=0) { - if (xkbDebugFlags) - ErrorF("[xkb] xkbcomp returned exit code %d\n",rval); - } -#else - fclose(in); - unlink(tmpname); -#endif - if (buf != NULL) - xfree (buf); - return status; -} - -/***====================================================================***/ - -/* ARGSUSED */ -Status -XkbDDXList(DeviceIntPtr dev,XkbSrvListInfoPtr list,ClientPtr client) -{ -Status status; - - status= XkbDDXListComponent(dev,_XkbListKeycodes,list,client); - if (status==Success) - status= XkbDDXListComponent(dev,_XkbListTypes,list,client); - if (status==Success) - status= XkbDDXListComponent(dev,_XkbListCompat,list,client); - if (status==Success) - status= XkbDDXListComponent(dev,_XkbListSymbols,list,client); - if (status==Success) - status= XkbDDXListComponent(dev,_XkbListGeometry,list,client); - return status; -} +/************************************************************ +Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#endif + +#include <stdio.h> +#include <ctype.h> +#include <X11/X.h> +#include <X11/Xos.h> +#include <X11/Xproto.h> +#include <X11/keysym.h> +#include <X11/extensions/XKM.h> +#include "inputstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#define XKBSRV_NEED_FILE_FUNCS +#include <xkbsrv.h> +#include <X11/extensions/XI.h> + +#ifdef WIN32 +/* from ddxLoad.c */ +extern const char* Win32TempDir(); +extern int Win32System(const char *cmdline); +#undef System +#define System Win32System + +#define W32_tmparg " '%s'" +#define W32_tmpfile ,tmpname +#define W32_tmplen strlen(tmpname)+3 +#else +#define W32_tmparg +#define W32_tmpfile +#define W32_tmplen 0 +#endif + +/***====================================================================***/ + +static char *componentDirs[_XkbListNumComponents] = { + "keycodes", "types", "compat", "symbols", "geometry" +}; + +/***====================================================================***/ + +static Status +_AddListComponent( XkbSrvListInfoPtr list, + int what, + unsigned flags, + char * str, + ClientPtr client) +{ +int slen,wlen; +unsigned char * wire8; +unsigned short *wire16; +char * tmp; + + if (list->nTotal>=list->maxRtrn) { + list->nTotal++; + return Success; + } + tmp= strchr(str,')'); + if ((tmp==NULL)&&((tmp=strchr(str,'('))==NULL)) { + slen= strlen(str); + while ((slen>0) && isspace(str[slen-1])) { + slen--; + } + } + else { + slen= (tmp-str+1); + } + wlen= (((slen+1)/2)*2)+4; /* four bytes for flags and length, pad to */ + /* 2-byte boundary */ + if ((list->szPool-list->nPool)<wlen) { + if (wlen>1024) list->szPool+= XkbPaddedSize(wlen*2); + else list->szPool+= 1024; + list->pool= realloc(list->pool, list->szPool * sizeof(char)); + if (!list->pool) + return BadAlloc; + } + wire16= (unsigned short *)&list->pool[list->nPool]; + wire8= (unsigned char *)&wire16[2]; + wire16[0]= flags; + wire16[1]= slen; + memcpy(wire8,str,slen); + if (client->swapped) { + register int n; + swaps(&wire16[0],n); + swaps(&wire16[1],n); + } + list->nPool+= wlen; + list->nFound[what]++; + list->nTotal++; + return Success; +} + +/***====================================================================***/ +static Status +XkbDDXListComponent( DeviceIntPtr dev, + int what, + XkbSrvListInfoPtr list, + ClientPtr client) +{ +char *file,*map,*tmp,*buf=NULL; +FILE *in; +Status status; +int rval; +Bool haveDir; +#ifdef WIN32 +char tmpname[PATH_MAX]; +#endif + + if ((list->pattern[what]==NULL)||(list->pattern[what][0]=='\0')) + return Success; + file= list->pattern[what]; + map= strrchr(file,'('); + if (map!=NULL) { + char *tmp; + map++; + tmp= strrchr(map,')'); + if ((tmp==NULL)||(tmp[1]!='\0')) { + /* illegal pattern. No error, but no match */ + return Success; + } + } + + in= NULL; + haveDir= TRUE; +#ifdef WIN32 + strcpy(tmpname, Win32TempDir()); + strcat(tmpname, "\\xkb_XXXXXX"); + (void) mktemp(tmpname); +#endif + if (XkbBaseDirectory!=NULL) { + if ((list->pattern[what][0]=='*')&&(list->pattern[what][1]=='\0')) { + buf = Xprintf("%s/%s.dir",XkbBaseDirectory,componentDirs[what]); + in= fopen(buf,"r"); + } + if (!in) { + haveDir= FALSE; + buf = Xprintf( + "'%s/xkbcomp' '-R%s/%s' -w %ld -l -vlfhpR '%s'" W32_tmparg, + XkbBinDirectory,XkbBaseDirectory,componentDirs[what],(long) + ((xkbDebugFlags<2)?1:((xkbDebugFlags>10)?10:xkbDebugFlags)), + file W32_tmpfile + ); + } + } + else { + if ((list->pattern[what][0]=='*')&&(list->pattern[what][1]=='\0')) { + buf = Xprintf("%s.dir",componentDirs[what]); + in= fopen(buf,"r"); + } + if (!in) { + haveDir= FALSE; + buf = Xprintf( + "xkbcomp -R%s -w %ld -l -vlfhpR '%s'" W32_tmparg, + componentDirs[what],(long) + ((xkbDebugFlags<2)?1:((xkbDebugFlags>10)?10:xkbDebugFlags)), + file W32_tmpfile + ); + } + } + status= Success; + if (!haveDir) + { +#ifndef WIN32 + in= Popen(buf,"r"); +#else + if (xkbDebugFlags) + DebugF("[xkb] xkbList executes: %s\n",buf); + if (System(buf) < 0) + ErrorF("[xkb] Could not invoke keymap compiler\n"); + else + in= fopen(tmpname, "r"); +#endif + } + if (!in) + { + if (buf != NULL) + free(buf); +#ifdef WIN32 + unlink(tmpname); +#endif + return BadImplementation; + } + list->nFound[what]= 0; + if (buf) { + free(buf); + buf = NULL; + } + buf = malloc(PATH_MAX * sizeof(char)); + if (!buf) + return BadAlloc; + while ((status==Success)&&((tmp=fgets(buf,PATH_MAX,in))!=NULL)) { + unsigned flags; + register unsigned int i; + if (*tmp=='#') /* comment, skip it */ + continue; + if (!strncmp(tmp, "Warning:", 8) || !strncmp(tmp, " ", 8)) + /* skip warnings too */ + continue; + flags= 0; + /* each line in the listing is supposed to start with two */ + /* groups of eight characters, which specify the general */ + /* flags and the flags that are specific to the component */ + /* if they're missing, fail with BadImplementation */ + for (i=0;(i<8)&&(status==Success);i++) { /* read the general flags */ + if (isalpha(*tmp)) flags|= (1L<<i); + else if (*tmp!='-') status= BadImplementation; + tmp++; + } + if (status != Success) break; + if (!isspace(*tmp)) { + status= BadImplementation; + break; + } + else tmp++; + for (i=0;(i<8)&&(status==Success);i++) { /* read the component flags */ + if (isalpha(*tmp)) flags|= (1L<<(i+8)); + else if (*tmp!='-') status= BadImplementation; + tmp++; + } + if (status != Success) break; + if (isspace(*tmp)) { + while (isspace(*tmp)) { + tmp++; + } + } + else { + status= BadImplementation; + break; + } + status= _AddListComponent(list,what,flags,tmp,client); + } +#ifndef WIN32 + if (haveDir) + fclose(in); + else if ((rval=Pclose(in))!=0) { + if (xkbDebugFlags) + ErrorF("[xkb] xkbcomp returned exit code %d\n",rval); + } +#else + fclose(in); + unlink(tmpname); +#endif + if (buf != NULL) + free(buf); + return status; +} + +/***====================================================================***/ + +/* ARGSUSED */ +Status +XkbDDXList(DeviceIntPtr dev,XkbSrvListInfoPtr list,ClientPtr client) +{ +Status status; + + status= XkbDDXListComponent(dev,_XkbListKeycodes,list,client); + if (status==Success) + status= XkbDDXListComponent(dev,_XkbListTypes,list,client); + if (status==Success) + status= XkbDDXListComponent(dev,_XkbListCompat,list,client); + if (status==Success) + status= XkbDDXListComponent(dev,_XkbListSymbols,list,client); + if (status==Success) + status= XkbDDXListComponent(dev,_XkbListGeometry,list,client); + return status; +} diff --git a/xorg-server/xkb/ddxLoad.c b/xorg-server/xkb/ddxLoad.c index 4ccdddaf0..32125015f 100644 --- a/xorg-server/xkb/ddxLoad.c +++ b/xorg-server/xkb/ddxLoad.c @@ -1,459 +1,457 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#endif - -#include <xkb-config.h> - -#include <stdio.h> -#include <ctype.h> -#include <X11/X.h> -#include <X11/Xos.h> -#include <X11/Xproto.h> -#include <X11/keysym.h> -#include <X11/extensions/XKM.h> -#include "inputstr.h" -#include "scrnintstr.h" -#include "windowstr.h" -#define XKBSRV_NEED_FILE_FUNCS -#include <xkbsrv.h> -#include <X11/extensions/XI.h> -#include "xkb.h" - -#if defined(CSRG_BASED) || defined(linux) || defined(__GNU__) -#include <paths.h> -#endif - - /* - * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is - * relative to the top-level XKB configuration directory. - * Making the server write to a subdirectory of that directory - * requires some work in the general case (install procedure - * has to create links to /var or somesuch on many machines), - * so we just compile into /usr/tmp for now. - */ -#ifndef XKM_OUTPUT_DIR -#define XKM_OUTPUT_DIR "compiled/" -#endif - -#define PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\"" -#define ERROR_PREFIX "\"> \"" -#define POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\"" -#define POST_ERROR_MSG2 "\"End of messages from xkbcomp\"" - -#if defined(WIN32) -#define PATHSEPARATOR "\\" -#else -#define PATHSEPARATOR "/" -#endif - -#ifdef WIN32 - -#include <X11/Xwindows.h> -const char* -Win32TempDir() -{ - static char buffer[PATH_MAX]; - if (GetTempPath(sizeof(buffer), buffer)) - { - int len; - buffer[sizeof(buffer)-1] = 0; - len = strlen(buffer); - if (len > 0) - if (buffer[len-1] == '\\') - buffer[len-1] = 0; - return buffer; - } - if (getenv("TEMP") != NULL) - return getenv("TEMP"); - else if (getenv("TMP") != NULL) - return getenv("TEMP"); - else - return "/tmp"; -} - -int -Win32System(const char *cmdline) -{ - STARTUPINFO si; - PROCESS_INFORMATION pi; - DWORD dwExitCode; - char *cmd = xstrdup(cmdline); - - ZeroMemory( &si, sizeof(si) ); - si.cb = sizeof(si); - ZeroMemory( &pi, sizeof(pi) ); - - if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) - { - LPVOID buffer; - if (!FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &buffer, - 0, - NULL )) - { - ErrorF("[xkb] Starting '%s' failed!\n", cmdline); - } - else - { - ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *)buffer); - LocalFree(buffer); - } - - xfree(cmd); - return -1; - } - /* Wait until child process exits. */ - WaitForSingleObject( pi.hProcess, INFINITE ); - - GetExitCodeProcess( pi.hProcess, &dwExitCode); - - /* Close process and thread handles. */ - CloseHandle( pi.hProcess ); - CloseHandle( pi.hThread ); - xfree(cmd); - - return dwExitCode; -} -#undef System -#define System(x) Win32System(x) -#endif - -static void -OutputDirectory( - char* outdir, - size_t size) -{ -#ifndef WIN32 - /* Can we write an xkm and then open it too? */ - if (access(XKM_OUTPUT_DIR, W_OK | X_OK) == 0 && (strlen(XKM_OUTPUT_DIR) < size)) - { - (void) strcpy (outdir, XKM_OUTPUT_DIR); - } else -#else - if (strlen(Win32TempDir()) + 1 < size) - { - (void) strcpy(outdir, Win32TempDir()); - (void) strcat(outdir, "\\"); - } else -#endif - if (strlen("/tmp/") < size) - { - (void) strcpy (outdir, "/tmp/"); - } -} - -static Bool -XkbDDXCompileKeymapByNames( XkbDescPtr xkb, - XkbComponentNamesPtr names, - unsigned want, - unsigned need, - char * nameRtrn, - int nameRtrnLen) -{ - FILE * out; - char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX]; - - const char *emptystring = ""; - const char *xkbbasedirflag = emptystring; - const char *xkbbindir = emptystring; - const char *xkbbindirsep = emptystring; - -#ifdef WIN32 - /* WIN32 has no popen. The input must be stored in a file which is - used as input for xkbcomp. xkbcomp does not read from stdin. */ - char tmpname[PATH_MAX]; - const char *xkmfile = tmpname; -#else - const char *xkmfile = "-"; -#endif - - snprintf(keymap, sizeof(keymap), "server-%s", display); - - OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir)); - -#ifdef WIN32 - strcpy(tmpname, Win32TempDir()); - strcat(tmpname, "\\xkb_XXXXXX"); - (void) mktemp(tmpname); -#endif - - if (XkbBaseDirectory != NULL) { - xkbbasedirflag = Xprintf("\"-R%s\"", XkbBaseDirectory); - } - - if (XkbBinDirectory != NULL) { - int ld = strlen(XkbBinDirectory); - int lps = strlen(PATHSEPARATOR); - - xkbbindir = XkbBinDirectory; - - if ((ld >= lps) && - (strcmp(xkbbindir + ld - lps, PATHSEPARATOR) != 0)) { - xkbbindirsep = PATHSEPARATOR; - } - } - - buf = Xprintf("\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" " - "-em1 %s -emp %s -eml %s \"%s%s.xkm\"", - xkbbindir, xkbbindirsep, - ( (xkbDebugFlags < 2) ? 1 : - ((xkbDebugFlags > 10) ? 10 : (int)xkbDebugFlags) ), - xkbbasedirflag, xkmfile, - PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1, - xkm_output_dir, keymap); - - if (xkbbasedirflag != emptystring) { - xfree(xkbbasedirflag); - } - -#ifndef WIN32 - out= Popen(buf,"w"); -#else - out= fopen(tmpname, "w"); -#endif - - if (out!=NULL) { -#ifdef DEBUG - if (xkbDebugFlags) { - ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n"); - XkbWriteXKBKeymapForNames(stderr,names,xkb,want,need); - } -#endif - XkbWriteXKBKeymapForNames(out,names,xkb,want,need); -#ifndef WIN32 - if (Pclose(out)==0) -#else - if (fclose(out)==0 && System(buf) >= 0) -#endif - { - if (xkbDebugFlags) - DebugF("[xkb] xkb executes: %s\n",buf); - if (nameRtrn) { - strncpy(nameRtrn,keymap,nameRtrnLen); - nameRtrn[nameRtrnLen-1]= '\0'; - } - if (buf != NULL) - xfree (buf); - return TRUE; - } - else - LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap); -#ifdef WIN32 - /* remove the temporary file */ - unlink(tmpname); -#endif - } - else { -#ifndef WIN32 - LogMessage(X_ERROR, "XKB: Could not invoke xkbcomp\n"); -#else - LogMessage(X_ERROR, "Could not open file %s\n", tmpname); -#endif - } - if (nameRtrn) - nameRtrn[0]= '\0'; - if (buf != NULL) - xfree (buf); - return FALSE; -} - -static FILE * -XkbDDXOpenConfigFile(char *mapName,char *fileNameRtrn,int fileNameRtrnLen) -{ -char buf[PATH_MAX],xkm_output_dir[PATH_MAX]; -FILE * file; - - buf[0]= '\0'; - if (mapName!=NULL) { - OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir)); - if ((XkbBaseDirectory!=NULL)&&(xkm_output_dir[0]!='/') -#ifdef WIN32 - &&(!isalpha(xkm_output_dir[0]) || xkm_output_dir[1]!=':') -#endif - ) { - if (strlen(XkbBaseDirectory)+strlen(xkm_output_dir) - +strlen(mapName)+6 <= PATH_MAX) - { - sprintf(buf,"%s/%s%s.xkm",XkbBaseDirectory, - xkm_output_dir,mapName); - } - } - else if (strlen(xkm_output_dir)+strlen(mapName)+5 <= PATH_MAX) - sprintf(buf,"%s%s.xkm",xkm_output_dir,mapName); - if (buf[0] != '\0') - file= fopen(buf,"rb"); - else file= NULL; - } - else file= NULL; - if ((fileNameRtrn!=NULL)&&(fileNameRtrnLen>0)) { - strncpy(fileNameRtrn,buf,fileNameRtrnLen); - buf[fileNameRtrnLen-1]= '\0'; - } - return file; -} - -unsigned -XkbDDXLoadKeymapByNames( DeviceIntPtr keybd, - XkbComponentNamesPtr names, - unsigned want, - unsigned need, - XkbDescPtr * xkbRtrn, - char * nameRtrn, - int nameRtrnLen) -{ -XkbDescPtr xkb; -FILE * file; -char fileName[PATH_MAX]; -unsigned missing; - - *xkbRtrn = NULL; - if ((keybd==NULL)||(keybd->key==NULL)||(keybd->key->xkbInfo==NULL)) - xkb= NULL; - else xkb= keybd->key->xkbInfo->desc; - if ((names->keycodes==NULL)&&(names->types==NULL)&& - (names->compat==NULL)&&(names->symbols==NULL)&& - (names->geometry==NULL)) { - LogMessage(X_ERROR, "XKB: No components provided for device %s\n", - keybd->name ? keybd->name : "(unnamed keyboard)"); - return 0; - } - else if (!XkbDDXCompileKeymapByNames(xkb,names,want,need, - nameRtrn,nameRtrnLen)){ - LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n"); - return 0; - } - file= XkbDDXOpenConfigFile(nameRtrn,fileName,PATH_MAX); - if (file==NULL) { - LogMessage(X_ERROR, "Couldn't open compiled keymap file %s\n",fileName); - return 0; - } - missing= XkmReadFile(file,need,want,xkbRtrn); - if (*xkbRtrn==NULL) { - LogMessage(X_ERROR, "Error loading keymap %s\n",fileName); - fclose(file); - (void) unlink (fileName); - return 0; - } - else { - DebugF("Loaded XKB keymap %s, defined=0x%x\n",fileName,(*xkbRtrn)->defined); - } - fclose(file); - (void) unlink (fileName); - return (need|want)&(~missing); -} - -Bool -XkbDDXNamesFromRules( DeviceIntPtr keybd, - char * rules_name, - XkbRF_VarDefsPtr defs, - XkbComponentNamesPtr names) -{ -char buf[PATH_MAX]; -FILE * file; -Bool complete; -XkbRF_RulesPtr rules; - - if (!rules_name) - return FALSE; - - if (strlen(XkbBaseDirectory) + strlen(rules_name) + 8 > PATH_MAX) { - LogMessage(X_ERROR, "XKB: Rules name is too long\n"); - return FALSE; - } - sprintf(buf,"%s/rules/%s", XkbBaseDirectory, rules_name); - - file = fopen(buf, "r"); - if (!file) { - LogMessage(X_ERROR, "XKB: Couldn't open rules file %s\n", buf); - return FALSE; - } - - rules = XkbRF_Create(); - if (!rules) { - LogMessage(X_ERROR, "XKB: Couldn't create rules struct\n"); - fclose(file); - return FALSE; - } - - if (!XkbRF_LoadRules(file, rules)) { - LogMessage(X_ERROR, "XKB: Couldn't parse rules file %s\n", rules_name); - fclose(file); - XkbRF_Free(rules,TRUE); - return FALSE; - } - - memset(names, 0, sizeof(*names)); - complete = XkbRF_GetComponents(rules,defs,names); - fclose(file); - XkbRF_Free(rules, TRUE); - - if (!complete) - LogMessage(X_ERROR, "XKB: Rules returned no components\n"); - - return complete; -} - -XkbDescPtr -XkbCompileKeymap(DeviceIntPtr dev, XkbRMLVOSet *rmlvo) -{ - XkbComponentNamesRec kccgst; - XkbRF_VarDefsRec mlvo; - XkbDescPtr xkb; - char name[PATH_MAX]; - - if (!dev || !rmlvo) { - LogMessage(X_ERROR, "XKB: No device or RMLVO specified\n"); - return NULL; - } - - mlvo.model = rmlvo->model; - mlvo.layout = rmlvo->layout; - mlvo.variant = rmlvo->variant; - mlvo.options = rmlvo->options; - - /* XDNFR already logs for us. */ - if (!XkbDDXNamesFromRules(dev, rmlvo->rules, &mlvo, &kccgst)) - return NULL; - - /* XDLKBN too, but it might return 0 as well as allocating. */ - if (!XkbDDXLoadKeymapByNames(dev, &kccgst, XkmAllIndicesMask, 0, &xkb, name, - PATH_MAX)) { - if (xkb) - XkbFreeKeyboard(xkb, 0, TRUE); - return NULL; - } - - return xkb; -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#endif + +#include <xkb-config.h> + +#include <stdio.h> +#include <ctype.h> +#include <X11/X.h> +#include <X11/Xos.h> +#include <X11/Xproto.h> +#include <X11/keysym.h> +#include <X11/extensions/XKM.h> +#include "inputstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#define XKBSRV_NEED_FILE_FUNCS +#include <xkbsrv.h> +#include <X11/extensions/XI.h> +#include "xkb.h" + +#if defined(CSRG_BASED) || defined(linux) || defined(__GNU__) +#include <paths.h> +#endif + + /* + * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is + * relative to the top-level XKB configuration directory. + * Making the server write to a subdirectory of that directory + * requires some work in the general case (install procedure + * has to create links to /var or somesuch on many machines), + * so we just compile into /usr/tmp for now. + */ +#ifndef XKM_OUTPUT_DIR +#define XKM_OUTPUT_DIR "compiled/" +#endif + +#define PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\"" +#define ERROR_PREFIX "\"> \"" +#define POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\"" +#define POST_ERROR_MSG2 "\"End of messages from xkbcomp\"" + +#if defined(WIN32) +#define PATHSEPARATOR "\\" +#else +#define PATHSEPARATOR "/" +#endif + +#ifdef WIN32 + +#include <X11/Xwindows.h> +const char* +Win32TempDir() +{ + static char buffer[PATH_MAX]; + if (GetTempPath(sizeof(buffer), buffer)) + { + int len; + buffer[sizeof(buffer)-1] = 0; + len = strlen(buffer); + if (len > 0) + if (buffer[len-1] == '\\') + buffer[len-1] = 0; + return buffer; + } + if (getenv("TEMP") != NULL) + return getenv("TEMP"); + else if (getenv("TMP") != NULL) + return getenv("TEMP"); + else + return "/tmp"; +} + +int +Win32System(const char *cmdline) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + DWORD dwExitCode; + char *cmd = xstrdup(cmdline); + + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + + if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + LPVOID buffer; + if (!FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &buffer, + 0, + NULL )) + { + ErrorF("[xkb] Starting '%s' failed!\n", cmdline); + } + else + { + ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *)buffer); + LocalFree(buffer); + } + + free(cmd); + return -1; + } + /* Wait until child process exits. */ + WaitForSingleObject( pi.hProcess, INFINITE ); + + GetExitCodeProcess( pi.hProcess, &dwExitCode); + + /* Close process and thread handles. */ + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + free(cmd); + + return dwExitCode; +} +#undef System +#define System(x) Win32System(x) +#endif + +static void +OutputDirectory( + char* outdir, + size_t size) +{ +#ifndef WIN32 + /* Can we write an xkm and then open it too? */ + if (access(XKM_OUTPUT_DIR, W_OK | X_OK) == 0 && (strlen(XKM_OUTPUT_DIR) < size)) + { + (void) strcpy (outdir, XKM_OUTPUT_DIR); + } else +#else + if (strlen(Win32TempDir()) + 1 < size) + { + (void) strcpy(outdir, Win32TempDir()); + (void) strcat(outdir, "\\"); + } else +#endif + if (strlen("/tmp/") < size) + { + (void) strcpy (outdir, "/tmp/"); + } +} + +static Bool +XkbDDXCompileKeymapByNames( XkbDescPtr xkb, + XkbComponentNamesPtr names, + unsigned want, + unsigned need, + char * nameRtrn, + int nameRtrnLen) +{ + FILE * out; + char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX]; + + const char *emptystring = ""; + char *xkbbasedirflag = NULL; + const char *xkbbindir = emptystring; + const char *xkbbindirsep = emptystring; + +#ifdef WIN32 + /* WIN32 has no popen. The input must be stored in a file which is + used as input for xkbcomp. xkbcomp does not read from stdin. */ + char tmpname[PATH_MAX]; + const char *xkmfile = tmpname; +#else + const char *xkmfile = "-"; +#endif + + snprintf(keymap, sizeof(keymap), "server-%s", display); + + OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir)); + +#ifdef WIN32 + strcpy(tmpname, Win32TempDir()); + strcat(tmpname, "\\xkb_XXXXXX"); + (void) mktemp(tmpname); +#endif + + if (XkbBaseDirectory != NULL) { + xkbbasedirflag = Xprintf("\"-R%s\"", XkbBaseDirectory); + } + + if (XkbBinDirectory != NULL) { + int ld = strlen(XkbBinDirectory); + int lps = strlen(PATHSEPARATOR); + + xkbbindir = XkbBinDirectory; + + if ((ld >= lps) && + (strcmp(xkbbindir + ld - lps, PATHSEPARATOR) != 0)) { + xkbbindirsep = PATHSEPARATOR; + } + } + + buf = Xprintf("\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" " + "-em1 %s -emp %s -eml %s \"%s%s.xkm\"", + xkbbindir, xkbbindirsep, + ( (xkbDebugFlags < 2) ? 1 : + ((xkbDebugFlags > 10) ? 10 : (int)xkbDebugFlags) ), + xkbbasedirflag ? xkbbasedirflag : "", xkmfile, + PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1, + xkm_output_dir, keymap); + + free(xkbbasedirflag); + +#ifndef WIN32 + out= Popen(buf,"w"); +#else + out= fopen(tmpname, "w"); +#endif + + if (out!=NULL) { +#ifdef DEBUG + if (xkbDebugFlags) { + ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n"); + XkbWriteXKBKeymapForNames(stderr,names,xkb,want,need); + } +#endif + XkbWriteXKBKeymapForNames(out,names,xkb,want,need); +#ifndef WIN32 + if (Pclose(out)==0) +#else + if (fclose(out)==0 && System(buf) >= 0) +#endif + { + if (xkbDebugFlags) + DebugF("[xkb] xkb executes: %s\n",buf); + if (nameRtrn) { + strncpy(nameRtrn,keymap,nameRtrnLen); + nameRtrn[nameRtrnLen-1]= '\0'; + } + if (buf != NULL) + free(buf); + return TRUE; + } + else + LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap); +#ifdef WIN32 + /* remove the temporary file */ + unlink(tmpname); +#endif + } + else { +#ifndef WIN32 + LogMessage(X_ERROR, "XKB: Could not invoke xkbcomp\n"); +#else + LogMessage(X_ERROR, "Could not open file %s\n", tmpname); +#endif + } + if (nameRtrn) + nameRtrn[0]= '\0'; + if (buf != NULL) + free(buf); + return FALSE; +} + +static FILE * +XkbDDXOpenConfigFile(char *mapName,char *fileNameRtrn,int fileNameRtrnLen) +{ +char buf[PATH_MAX],xkm_output_dir[PATH_MAX]; +FILE * file; + + buf[0]= '\0'; + if (mapName!=NULL) { + OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir)); + if ((XkbBaseDirectory!=NULL)&&(xkm_output_dir[0]!='/') +#ifdef WIN32 + &&(!isalpha(xkm_output_dir[0]) || xkm_output_dir[1]!=':') +#endif + ) { + if (strlen(XkbBaseDirectory)+strlen(xkm_output_dir) + +strlen(mapName)+6 <= PATH_MAX) + { + sprintf(buf,"%s/%s%s.xkm",XkbBaseDirectory, + xkm_output_dir,mapName); + } + } + else if (strlen(xkm_output_dir)+strlen(mapName)+5 <= PATH_MAX) + sprintf(buf,"%s%s.xkm",xkm_output_dir,mapName); + if (buf[0] != '\0') + file= fopen(buf,"rb"); + else file= NULL; + } + else file= NULL; + if ((fileNameRtrn!=NULL)&&(fileNameRtrnLen>0)) { + strncpy(fileNameRtrn,buf,fileNameRtrnLen); + buf[fileNameRtrnLen-1]= '\0'; + } + return file; +} + +unsigned +XkbDDXLoadKeymapByNames( DeviceIntPtr keybd, + XkbComponentNamesPtr names, + unsigned want, + unsigned need, + XkbDescPtr * xkbRtrn, + char * nameRtrn, + int nameRtrnLen) +{ +XkbDescPtr xkb; +FILE * file; +char fileName[PATH_MAX]; +unsigned missing; + + *xkbRtrn = NULL; + if ((keybd==NULL)||(keybd->key==NULL)||(keybd->key->xkbInfo==NULL)) + xkb= NULL; + else xkb= keybd->key->xkbInfo->desc; + if ((names->keycodes==NULL)&&(names->types==NULL)&& + (names->compat==NULL)&&(names->symbols==NULL)&& + (names->geometry==NULL)) { + LogMessage(X_ERROR, "XKB: No components provided for device %s\n", + keybd->name ? keybd->name : "(unnamed keyboard)"); + return 0; + } + else if (!XkbDDXCompileKeymapByNames(xkb,names,want,need, + nameRtrn,nameRtrnLen)){ + LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n"); + return 0; + } + file= XkbDDXOpenConfigFile(nameRtrn,fileName,PATH_MAX); + if (file==NULL) { + LogMessage(X_ERROR, "Couldn't open compiled keymap file %s\n",fileName); + return 0; + } + missing= XkmReadFile(file,need,want,xkbRtrn); + if (*xkbRtrn==NULL) { + LogMessage(X_ERROR, "Error loading keymap %s\n",fileName); + fclose(file); + (void) unlink (fileName); + return 0; + } + else { + DebugF("Loaded XKB keymap %s, defined=0x%x\n",fileName,(*xkbRtrn)->defined); + } + fclose(file); + (void) unlink (fileName); + return (need|want)&(~missing); +} + +Bool +XkbDDXNamesFromRules( DeviceIntPtr keybd, + char * rules_name, + XkbRF_VarDefsPtr defs, + XkbComponentNamesPtr names) +{ +char buf[PATH_MAX]; +FILE * file; +Bool complete; +XkbRF_RulesPtr rules; + + if (!rules_name) + return FALSE; + + if (strlen(XkbBaseDirectory) + strlen(rules_name) + 8 > PATH_MAX) { + LogMessage(X_ERROR, "XKB: Rules name is too long\n"); + return FALSE; + } + sprintf(buf,"%s/rules/%s", XkbBaseDirectory, rules_name); + + file = fopen(buf, "r"); + if (!file) { + LogMessage(X_ERROR, "XKB: Couldn't open rules file %s\n", buf); + return FALSE; + } + + rules = XkbRF_Create(); + if (!rules) { + LogMessage(X_ERROR, "XKB: Couldn't create rules struct\n"); + fclose(file); + return FALSE; + } + + if (!XkbRF_LoadRules(file, rules)) { + LogMessage(X_ERROR, "XKB: Couldn't parse rules file %s\n", rules_name); + fclose(file); + XkbRF_Free(rules,TRUE); + return FALSE; + } + + memset(names, 0, sizeof(*names)); + complete = XkbRF_GetComponents(rules,defs,names); + fclose(file); + XkbRF_Free(rules, TRUE); + + if (!complete) + LogMessage(X_ERROR, "XKB: Rules returned no components\n"); + + return complete; +} + +XkbDescPtr +XkbCompileKeymap(DeviceIntPtr dev, XkbRMLVOSet *rmlvo) +{ + XkbComponentNamesRec kccgst; + XkbRF_VarDefsRec mlvo; + XkbDescPtr xkb; + char name[PATH_MAX]; + + if (!dev || !rmlvo) { + LogMessage(X_ERROR, "XKB: No device or RMLVO specified\n"); + return NULL; + } + + mlvo.model = rmlvo->model; + mlvo.layout = rmlvo->layout; + mlvo.variant = rmlvo->variant; + mlvo.options = rmlvo->options; + + /* XDNFR already logs for us. */ + if (!XkbDDXNamesFromRules(dev, rmlvo->rules, &mlvo, &kccgst)) + return NULL; + + /* XDLKBN too, but it might return 0 as well as allocating. */ + if (!XkbDDXLoadKeymapByNames(dev, &kccgst, XkmAllIndicesMask, 0, &xkb, name, + PATH_MAX)) { + if (xkb) + XkbFreeKeyboard(xkb, 0, TRUE); + return NULL; + } + + return xkb; +} diff --git a/xorg-server/xkb/maprules.c b/xorg-server/xkb/maprules.c index 3467c4238..a717aa456 100644 --- a/xorg-server/xkb/maprules.c +++ b/xorg-server/xkb/maprules.c @@ -1,1019 +1,1019 @@ -/************************************************************ - Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc. - - 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 Silicon Graphics not be - used in advertising or publicity pertaining to distribution - of the software without specific prior written permission. - Silicon Graphics makes no representation about the suitability - of this software for any purpose. It is provided "as is" - without any express or implied warranty. - - SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON - GRAPHICS 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 <dix-config.h> -#endif - -#include <stdio.h> -#include <ctype.h> -#include <stdlib.h> - -#define X_INCLUDE_STRING_H -#define XOS_USE_NO_LOCKING -#include <X11/Xos_r.h> - -#include <X11/Xproto.h> -#include <X11/X.h> -#include <X11/Xos.h> -#include <X11/Xfuncs.h> -#include <X11/Xatom.h> -#include <X11/keysym.h> -#include "misc.h" -#include "inputstr.h" -#include "dix.h" -#include "os.h" -#include "xkbstr.h" -#define XKBSRV_NEED_FILE_FUNCS -#include <xkbsrv.h> - -/***====================================================================***/ - - - -#define DFLT_LINE_SIZE 128 - -typedef struct { - int line_num; - int sz_line; - int num_line; - char buf[DFLT_LINE_SIZE]; - char * line; -} InputLine; - -static void -InitInputLine(InputLine *line) -{ - line->line_num= 1; - line->num_line= 0; - line->sz_line= DFLT_LINE_SIZE; - line->line= line->buf; - return; -} - -static void -FreeInputLine(InputLine *line) -{ - if (line->line!=line->buf) - xfree(line->line); - line->line_num= 1; - line->num_line= 0; - line->sz_line= DFLT_LINE_SIZE; - line->line= line->buf; - return; -} - -static int -InputLineAddChar(InputLine *line,int ch) -{ - if (line->num_line>=line->sz_line) { - if (line->line==line->buf) { - line->line= xalloc(line->sz_line*2); - memcpy(line->line,line->buf,line->sz_line); - } - else { - line->line= xrealloc((char *)line->line,line->sz_line*2); - } - line->sz_line*= 2; - } - line->line[line->num_line++]= ch; - return ch; -} - -#define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\ - (int)((l)->line[(l)->num_line++]= (c)):\ - InputLineAddChar(l,c)) - -static Bool -GetInputLine(FILE *file,InputLine *line,Bool checkbang) -{ -int ch; -Bool endOfFile,spacePending,slashPending,inComment; - - endOfFile= FALSE; - while ((!endOfFile)&&(line->num_line==0)) { - spacePending= slashPending= inComment= FALSE; - while (((ch=getc(file))!='\n')&&(ch!=EOF)) { - if (ch=='\\') { - if ((ch=getc(file))==EOF) - break; - if (ch=='\n') { - inComment= FALSE; - ch= ' '; - line->line_num++; - } - } - if (inComment) - continue; - if (ch=='/') { - if (slashPending) { - inComment= TRUE; - slashPending= FALSE; - } - else { - slashPending= TRUE; - } - continue; - } - else if (slashPending) { - if (spacePending) { - ADD_CHAR(line,' '); - spacePending= FALSE; - } - ADD_CHAR(line,'/'); - slashPending= FALSE; - } - if (isspace(ch)) { - while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) { - ch= getc(file); - } - if (ch==EOF) - break; - if ((ch!='\n')&&(line->num_line>0)) - spacePending= TRUE; - ungetc(ch,file); - } - else { - if (spacePending) { - ADD_CHAR(line,' '); - spacePending= FALSE; - } - if (checkbang && ch=='!') { - if (line->num_line!=0) { - DebugF("The '!' legal only at start of line\n"); - DebugF("Line containing '!' ignored\n"); - line->num_line= 0; - inComment= 0; - break; - } - - } - ADD_CHAR(line,ch); - } - } - if (ch==EOF) - endOfFile= TRUE; -/* else line->num_line++;*/ - } - if ((line->num_line==0)&&(endOfFile)) - return FALSE; - ADD_CHAR(line,'\0'); - return TRUE; -} - -/***====================================================================***/ - -#define MODEL 0 -#define LAYOUT 1 -#define VARIANT 2 -#define OPTION 3 -#define KEYCODES 4 -#define SYMBOLS 5 -#define TYPES 6 -#define COMPAT 7 -#define GEOMETRY 8 -#define MAX_WORDS 9 - -#define PART_MASK 0x000F -#define COMPONENT_MASK 0x03F0 - -static char * cname[MAX_WORDS] = { - "model", "layout", "variant", "option", - "keycodes", "symbols", "types", "compat", "geometry" -}; - -typedef struct _RemapSpec { - int number; - int num_remap; - struct { - int word; - int index; - } remap[MAX_WORDS]; -} RemapSpec; - -typedef struct _FileSpec { - char * name[MAX_WORDS]; - struct _FileSpec * pending; -} FileSpec; - -typedef struct { - char * model; - char * layout[XkbNumKbdGroups+1]; - char * variant[XkbNumKbdGroups+1]; - char * options; -} XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr; - -#define NDX_BUFF_SIZE 4 - -/***====================================================================***/ - -static char* -get_index(char *str, int *ndx) -{ - char ndx_buf[NDX_BUFF_SIZE]; - char *end; - - if (*str != '[') { - *ndx = 0; - return str; - } - str++; - end = strchr(str, ']'); - if (end == NULL) { - *ndx = -1; - return str - 1; - } - if ( (end - str) >= NDX_BUFF_SIZE) { - *ndx = -1; - return end + 1; - } - strncpy(ndx_buf, str, end - str); - ndx_buf[end - str] = '\0'; - *ndx = atoi(ndx_buf); - return end + 1; -} - -static void -SetUpRemap(InputLine *line,RemapSpec *remap) -{ -char * tok,*str; -unsigned present, l_ndx_present, v_ndx_present; -register int i; -int len, ndx; -_Xstrtokparams strtok_buf; -Bool found; - - - l_ndx_present = v_ndx_present = present= 0; - str= &line->line[1]; - len = remap->number; - bzero((char *)remap,sizeof(RemapSpec)); - remap->number = len; - while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) { - found= FALSE; - str= NULL; - if (strcmp(tok,"=")==0) - continue; - for (i=0;i<MAX_WORDS;i++) { - len = strlen(cname[i]); - if (strncmp(cname[i],tok,len)==0) { - if(strlen(tok) > len) { - char *end = get_index(tok+len, &ndx); - if ((i != LAYOUT && i != VARIANT) || - *end != '\0' || ndx == -1) - break; - if (ndx < 1 || ndx > XkbNumKbdGroups) { - DebugF("Illegal %s index: %d\n", cname[i], ndx); - DebugF("Index must be in range 1..%d\n", - XkbNumKbdGroups); - break; - } - } else { - ndx = 0; - } - found= TRUE; - if (present&(1<<i)) { - if ((i == LAYOUT && l_ndx_present&(1<<ndx)) || - (i == VARIANT && v_ndx_present&(1<<ndx)) ) { - DebugF("Component \"%s\" listed twice\n",tok); - DebugF("Second definition ignored\n"); - break; - } - } - present |= (1<<i); - if (i == LAYOUT) - l_ndx_present |= 1 << ndx; - if (i == VARIANT) - v_ndx_present |= 1 << ndx; - remap->remap[remap->num_remap].word= i; - remap->remap[remap->num_remap++].index= ndx; - break; - } - } - if (!found) { - fprintf(stderr,"Unknown component \"%s\" ignored\n",tok); - } - } - if ((present&PART_MASK)==0) { - unsigned mask= PART_MASK; - ErrorF("Mapping needs at least one of "); - for (i=0; (i<MAX_WORDS); i++) { - if ((1L<<i)&mask) { - mask&= ~(1L<<i); - if (mask) DebugF("\"%s,\" ",cname[i]); - else DebugF("or \"%s\"\n",cname[i]); - } - } - DebugF("Illegal mapping ignored\n"); - remap->num_remap= 0; - return; - } - if ((present&COMPONENT_MASK)==0) { - DebugF("Mapping needs at least one component\n"); - DebugF("Illegal mapping ignored\n"); - remap->num_remap= 0; - return; - } - remap->number++; - return; -} - -static Bool -MatchOneOf(char *wanted,char *vals_defined) -{ -char *str,*next; -int want_len= strlen(wanted); - - for (str=vals_defined,next=NULL;str!=NULL;str=next) { - int len; - next= strchr(str,','); - if (next) { - len= next-str; - next++; - } - else { - len= strlen(str); - } - if ((len==want_len)&&(strncmp(wanted,str,len)==0)) - return TRUE; - } - return FALSE; -} - -/***====================================================================***/ - -static Bool -CheckLine( InputLine * line, - RemapSpec * remap, - XkbRF_RulePtr rule, - XkbRF_GroupPtr group) -{ -char * str,*tok; -register int nread, i; -FileSpec tmp; -_Xstrtokparams strtok_buf; -Bool append = FALSE; - - if (line->line[0]=='!') { - if (line->line[1] == '$' || - (line->line[1] == ' ' && line->line[2] == '$')) { - char *gname = strchr(line->line, '$'); - char *words = strchr(gname, ' '); - if(!words) - return FALSE; - *words++ = '\0'; - for (; *words; words++) { - if (*words != '=' && *words != ' ') - break; - } - if (*words == '\0') - return FALSE; - group->name = _XkbDupString(gname); - group->words = _XkbDupString(words); - for (i = 1, words = group->words; *words; words++) { - if ( *words == ' ') { - *words++ = '\0'; - i++; - } - } - group->number = i; - return TRUE; - } else { - SetUpRemap(line,remap); - return FALSE; - } - } - - if (remap->num_remap==0) { - DebugF("Must have a mapping before first line of data\n"); - DebugF("Illegal line of data ignored\n"); - return FALSE; - } - bzero((char *)&tmp,sizeof(FileSpec)); - str= line->line; - for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) { - str= NULL; - if (strcmp(tok,"=")==0) { - nread--; - continue; - } - if (nread>remap->num_remap) { - DebugF("Too many words on a line\n"); - DebugF("Extra word \"%s\" ignored\n",tok); - continue; - } - tmp.name[remap->remap[nread].word]= tok; - if (*tok == '+' || *tok == '|') - append = TRUE; - } - if (nread<remap->num_remap) { - DebugF("Too few words on a line: %s\n", line->line); - DebugF("line ignored\n"); - return FALSE; - } - - rule->flags= 0; - rule->number = remap->number; - if (tmp.name[OPTION]) - rule->flags|= XkbRF_Option; - else if (append) - rule->flags|= XkbRF_Append; - else - rule->flags|= XkbRF_Normal; - rule->model= _XkbDupString(tmp.name[MODEL]); - rule->layout= _XkbDupString(tmp.name[LAYOUT]); - rule->variant= _XkbDupString(tmp.name[VARIANT]); - rule->option= _XkbDupString(tmp.name[OPTION]); - - rule->keycodes= _XkbDupString(tmp.name[KEYCODES]); - rule->symbols= _XkbDupString(tmp.name[SYMBOLS]); - rule->types= _XkbDupString(tmp.name[TYPES]); - rule->compat= _XkbDupString(tmp.name[COMPAT]); - rule->geometry= _XkbDupString(tmp.name[GEOMETRY]); - - rule->layout_num = rule->variant_num = 0; - for (i = 0; i < nread; i++) { - if (remap->remap[i].index) { - if (remap->remap[i].word == LAYOUT) - rule->layout_num = remap->remap[i].index; - if (remap->remap[i].word == VARIANT) - rule->variant_num = remap->remap[i].index; - } - } - return TRUE; -} - -static char * -_Concat(char *str1,char *str2) -{ -int len; - - if ((!str1)||(!str2)) - return str1; - len= strlen(str1)+strlen(str2)+1; - str1= xrealloc(str1,len * sizeof(char)); - if (str1) - strcat(str1,str2); - return str1; -} - -static void -squeeze_spaces(char *p1) -{ - char *p2; - for (p2 = p1; *p2; p2++) { - *p1 = *p2; - if (*p1 != ' ') p1++; - } - *p1 = '\0'; -} - -static Bool -MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs) -{ - - bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec)); - mdefs->model = defs->model; - mdefs->options = _XkbDupString(defs->options); - if (mdefs->options) squeeze_spaces(mdefs->options); - - if (defs->layout) { - if (!strchr(defs->layout, ',')) { - mdefs->layout[0] = defs->layout; - } else { - char *p; - int i; - mdefs->layout[1] = _XkbDupString(defs->layout); - if (mdefs->layout[1] == NULL) - return FALSE; - squeeze_spaces(mdefs->layout[1]); - p = mdefs->layout[1]; - for (i = 2; i <= XkbNumKbdGroups; i++) { - if ((p = strchr(p, ','))) { - *p++ = '\0'; - mdefs->layout[i] = p; - } else { - break; - } - } - if (p && (p = strchr(p, ','))) - *p = '\0'; - } - } - - if (defs->variant) { - if (!strchr(defs->variant, ',')) { - mdefs->variant[0] = defs->variant; - } else { - char *p; - int i; - mdefs->variant[1] = _XkbDupString(defs->variant); - if (mdefs->variant[1] == NULL) - return FALSE; - squeeze_spaces(mdefs->variant[1]); - p = mdefs->variant[1]; - for (i = 2; i <= XkbNumKbdGroups; i++) { - if ((p = strchr(p, ','))) { - *p++ = '\0'; - mdefs->variant[i] = p; - } else { - break; - } - } - if (p && (p = strchr(p, ','))) - *p = '\0'; - } - } - return TRUE; -} - -static void -FreeMultiDefs(XkbRF_MultiDefsPtr defs) -{ - if (defs->options) xfree(defs->options); - if (defs->layout[1]) xfree(defs->layout[1]); - if (defs->variant[1]) xfree(defs->variant[1]); -} - -static void -Apply(char *src, char **dst) -{ - if (src) { - if (*src == '+' || *src == '!') { - *dst= _Concat(*dst, src); - } else { - if (*dst == NULL) - *dst= _XkbDupString(src); - } - } -} - -static void -XkbRF_ApplyRule( XkbRF_RulePtr rule, - XkbComponentNamesPtr names) -{ - rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */ - - Apply(rule->keycodes, &names->keycodes); - Apply(rule->symbols, &names->symbols); - Apply(rule->types, &names->types); - Apply(rule->compat, &names->compat); - Apply(rule->geometry, &names->geometry); -} - -static Bool -CheckGroup( XkbRF_RulesPtr rules, - char * group_name, - char * name) -{ - int i; - char *p; - XkbRF_GroupPtr group; - - for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) { - if (! strcmp(group->name, group_name)) { - break; - } - } - if (i == rules->num_groups) - return FALSE; - for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) { - if (! strcmp(p, name)) { - return TRUE; - } - } - return FALSE; -} - -static int -XkbRF_CheckApplyRule( XkbRF_RulePtr rule, - XkbRF_MultiDefsPtr mdefs, - XkbComponentNamesPtr names, - XkbRF_RulesPtr rules) -{ - Bool pending = FALSE; - - if (rule->model != NULL) { - if(mdefs->model == NULL) - return 0; - if (strcmp(rule->model, "*") == 0) { - pending = TRUE; - } else { - if (rule->model[0] == '$') { - if (!CheckGroup(rules, rule->model, mdefs->model)) - return 0; - } else { - if (strcmp(rule->model, mdefs->model) != 0) - return 0; - } - } - } - if (rule->option != NULL) { - if (mdefs->options == NULL) - return 0; - if ((!MatchOneOf(rule->option,mdefs->options))) - return 0; - } - - if (rule->layout != NULL) { - if(mdefs->layout[rule->layout_num] == NULL || - *mdefs->layout[rule->layout_num] == '\0') - return 0; - if (strcmp(rule->layout, "*") == 0) { - pending = TRUE; - } else { - if (rule->layout[0] == '$') { - if (!CheckGroup(rules, rule->layout, - mdefs->layout[rule->layout_num])) - return 0; - } else { - if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0) - return 0; - } - } - } - if (rule->variant != NULL) { - if (mdefs->variant[rule->variant_num] == NULL || - *mdefs->variant[rule->variant_num] == '\0') - return 0; - if (strcmp(rule->variant, "*") == 0) { - pending = TRUE; - } else { - if (rule->variant[0] == '$') { - if (!CheckGroup(rules, rule->variant, - mdefs->variant[rule->variant_num])) - return 0; - } else { - if (strcmp(rule->variant, - mdefs->variant[rule->variant_num]) != 0) - return 0; - } - } - } - if (pending) { - rule->flags|= XkbRF_PendingMatch; - return rule->number; - } - /* exact match, apply it now */ - XkbRF_ApplyRule(rule,names); - return rule->number; -} - -static void -XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules) -{ -register int i; -XkbRF_RulePtr rule; - - for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { - rule->flags&= ~XkbRF_PendingMatch; - } -} - -static void -XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names) -{ -int i; -XkbRF_RulePtr rule; - - for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) { - if ((rule->flags&XkbRF_PendingMatch)==0) - continue; - XkbRF_ApplyRule(rule,names); - } -} - -static void -XkbRF_CheckApplyRules( XkbRF_RulesPtr rules, - XkbRF_MultiDefsPtr mdefs, - XkbComponentNamesPtr names, - int flags) -{ -int i; -XkbRF_RulePtr rule; -int skip; - - for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) { - if ((rule->flags & flags) != flags) - continue; - skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules); - if (skip && !(flags & XkbRF_Option)) { - for ( ;(i < rules->num_rules) && (rule->number == skip); - rule++, i++); - rule--; i--; - } - } -} - -/***====================================================================***/ - -static char * -XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs) -{ -char *str, *outstr, *orig, *var; -int len, ndx; - - orig= name; - str= index(name,'%'); - if (str==NULL) - return name; - len= strlen(name); - while (str!=NULL) { - char pfx= str[1]; - int extra_len= 0; - if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { - extra_len= 1; - str++; - } - else if (pfx=='(') { - extra_len= 2; - str++; - } - var = str + 1; - str = get_index(var + 1, &ndx); - if (ndx == -1) { - str = index(str,'%'); - continue; - } - if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) - len+= strlen(mdefs->layout[ndx])+extra_len; - else if ((*var=='m')&&mdefs->model) - len+= strlen(mdefs->model)+extra_len; - else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) - len+= strlen(mdefs->variant[ndx])+extra_len; - if ((pfx=='(')&&(*str==')')) { - str++; - } - str= index(&str[0],'%'); - } - name= xalloc(len+1); - str= orig; - outstr= name; - while (*str!='\0') { - if (str[0]=='%') { - char pfx,sfx; - str++; - pfx= str[0]; - sfx= '\0'; - if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { - str++; - } - else if (pfx=='(') { - sfx= ')'; - str++; - } - else pfx= '\0'; - - var = str; - str = get_index(var + 1, &ndx); - if (ndx == -1) { - continue; - } - if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) { - if (pfx) *outstr++= pfx; - strcpy(outstr,mdefs->layout[ndx]); - outstr+= strlen(mdefs->layout[ndx]); - if (sfx) *outstr++= sfx; - } - else if ((*var=='m')&&(mdefs->model)) { - if (pfx) *outstr++= pfx; - strcpy(outstr,mdefs->model); - outstr+= strlen(mdefs->model); - if (sfx) *outstr++= sfx; - } - else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) { - if (pfx) *outstr++= pfx; - strcpy(outstr,mdefs->variant[ndx]); - outstr+= strlen(mdefs->variant[ndx]); - if (sfx) *outstr++= sfx; - } - if ((pfx=='(')&&(*str==')')) - str++; - } - else { - *outstr++= *str++; - } - } - *outstr++= '\0'; - if (orig!=name) - xfree(orig); - return name; -} - -/***====================================================================***/ - -Bool -XkbRF_GetComponents( XkbRF_RulesPtr rules, - XkbRF_VarDefsPtr defs, - XkbComponentNamesPtr names) -{ - XkbRF_MultiDefsRec mdefs; - - MakeMultiDefs(&mdefs, defs); - - bzero((char *)names,sizeof(XkbComponentNamesRec)); - XkbRF_ClearPartialMatches(rules); - XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal); - XkbRF_ApplyPartialMatches(rules, names); - XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append); - XkbRF_ApplyPartialMatches(rules, names); - XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option); - - if (names->keycodes) - names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs); - if (names->symbols) - names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs); - if (names->types) - names->types= XkbRF_SubstituteVars(names->types, &mdefs); - if (names->compat) - names->compat= XkbRF_SubstituteVars(names->compat, &mdefs); - if (names->geometry) - names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs); - - FreeMultiDefs(&mdefs); - return (names->keycodes && names->symbols && names->types && - names->compat && names->geometry); -} - -static XkbRF_RulePtr -XkbRF_AddRule(XkbRF_RulesPtr rules) -{ - if (rules->sz_rules<1) { - rules->sz_rules= 16; - rules->num_rules= 0; - rules->rules= xcalloc(rules->sz_rules, sizeof(XkbRF_RuleRec)); - } - else if (rules->num_rules>=rules->sz_rules) { - rules->sz_rules*= 2; - rules->rules= xrealloc(rules->rules, - rules->sz_rules * sizeof(XkbRF_RuleRec)); - } - if (!rules->rules) { - rules->sz_rules= rules->num_rules= 0; - DebugF("Allocation failure in XkbRF_AddRule\n"); - return NULL; - } - bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec)); - return &rules->rules[rules->num_rules++]; -} - -static XkbRF_GroupPtr -XkbRF_AddGroup(XkbRF_RulesPtr rules) -{ - if (rules->sz_groups<1) { - rules->sz_groups= 16; - rules->num_groups= 0; - rules->groups= xcalloc(rules->sz_groups, sizeof(XkbRF_GroupRec)); - } - else if (rules->num_groups >= rules->sz_groups) { - rules->sz_groups *= 2; - rules->groups= xrealloc(rules->groups, - rules->sz_groups * sizeof(XkbRF_GroupRec)); - } - if (!rules->groups) { - rules->sz_groups= rules->num_groups= 0; - return NULL; - } - - bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec)); - return &rules->groups[rules->num_groups++]; -} - -Bool -XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules) -{ -InputLine line; -RemapSpec remap; -XkbRF_RuleRec trule,*rule; -XkbRF_GroupRec tgroup,*group; - - if (!(rules && file)) - return FALSE; - bzero((char *)&remap,sizeof(RemapSpec)); - bzero((char *)&tgroup,sizeof(XkbRF_GroupRec)); - InitInputLine(&line); - while (GetInputLine(file,&line,TRUE)) { - if (CheckLine(&line,&remap,&trule,&tgroup)) { - if (tgroup.number) { - if ((group= XkbRF_AddGroup(rules))!=NULL) { - *group= tgroup; - bzero((char *)&tgroup,sizeof(XkbRF_GroupRec)); - } - } else { - if ((rule= XkbRF_AddRule(rules))!=NULL) { - *rule= trule; - bzero((char *)&trule,sizeof(XkbRF_RuleRec)); - } - } - } - line.num_line= 0; - } - FreeInputLine(&line); - return TRUE; -} - -Bool -XkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules) -{ -FILE * file; -char buf[PATH_MAX]; -Bool ok; - - if ((!base)||(!rules)) - return FALSE; - if (locale) { - if (strlen(base)+strlen(locale)+2 > PATH_MAX) - return FALSE; - sprintf(buf,"%s-%s", base, locale); - } - else { - if (strlen(base)+1 > PATH_MAX) - return FALSE; - strcpy(buf,base); - } - - file= fopen(buf, "r"); - if ((!file)&&(locale)) { /* fallback if locale was specified */ - strcpy(buf,base); - file= fopen(buf, "r"); - } - if (!file) - return FALSE; - ok= XkbRF_LoadRules(file,rules); - fclose(file); - return ok; -} - -/***====================================================================***/ - -XkbRF_RulesPtr -XkbRF_Create(void) -{ - return xcalloc(1, sizeof( XkbRF_RulesRec)); -} - -/***====================================================================***/ - -void -XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules) -{ -int i; -XkbRF_RulePtr rule; -XkbRF_GroupPtr group; - - if (!rules) - return; - if (rules->rules) { - for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { - if (rule->model) xfree(rule->model); - if (rule->layout) xfree(rule->layout); - if (rule->variant) xfree(rule->variant); - if (rule->option) xfree(rule->option); - if (rule->keycodes) xfree(rule->keycodes); - if (rule->symbols) xfree(rule->symbols); - if (rule->types) xfree(rule->types); - if (rule->compat) xfree(rule->compat); - if (rule->geometry) xfree(rule->geometry); - bzero((char *)rule,sizeof(XkbRF_RuleRec)); - } - xfree(rules->rules); - rules->num_rules= rules->sz_rules= 0; - rules->rules= NULL; - } - - if (rules->groups) { - for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) { - if (group->name) xfree(group->name); - if (group->words) xfree(group->words); - } - xfree(rules->groups); - rules->num_groups= 0; - rules->groups= NULL; - } - if (freeRules) - xfree(rules); - return; -} +/************************************************************ + Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc. + + 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 Silicon Graphics not be + used in advertising or publicity pertaining to distribution + of the software without specific prior written permission. + Silicon Graphics makes no representation about the suitability + of this software for any purpose. It is provided "as is" + without any express or implied warranty. + + SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + GRAPHICS 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 <dix-config.h> +#endif + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> + +#define X_INCLUDE_STRING_H +#define XOS_USE_NO_LOCKING +#include <X11/Xos_r.h> + +#include <X11/Xproto.h> +#include <X11/X.h> +#include <X11/Xos.h> +#include <X11/Xfuncs.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> +#include "misc.h" +#include "inputstr.h" +#include "dix.h" +#include "os.h" +#include "xkbstr.h" +#define XKBSRV_NEED_FILE_FUNCS +#include <xkbsrv.h> + +/***====================================================================***/ + + + +#define DFLT_LINE_SIZE 128 + +typedef struct { + int line_num; + int sz_line; + int num_line; + char buf[DFLT_LINE_SIZE]; + char * line; +} InputLine; + +static void +InitInputLine(InputLine *line) +{ + line->line_num= 1; + line->num_line= 0; + line->sz_line= DFLT_LINE_SIZE; + line->line= line->buf; + return; +} + +static void +FreeInputLine(InputLine *line) +{ + if (line->line!=line->buf) + free(line->line); + line->line_num= 1; + line->num_line= 0; + line->sz_line= DFLT_LINE_SIZE; + line->line= line->buf; + return; +} + +static int +InputLineAddChar(InputLine *line,int ch) +{ + if (line->num_line>=line->sz_line) { + if (line->line==line->buf) { + line->line= malloc(line->sz_line*2); + memcpy(line->line,line->buf,line->sz_line); + } + else { + line->line= realloc((char *)line->line,line->sz_line*2); + } + line->sz_line*= 2; + } + line->line[line->num_line++]= ch; + return ch; +} + +#define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\ + (int)((l)->line[(l)->num_line++]= (c)):\ + InputLineAddChar(l,c)) + +static Bool +GetInputLine(FILE *file,InputLine *line,Bool checkbang) +{ +int ch; +Bool endOfFile,spacePending,slashPending,inComment; + + endOfFile= FALSE; + while ((!endOfFile)&&(line->num_line==0)) { + spacePending= slashPending= inComment= FALSE; + while (((ch=getc(file))!='\n')&&(ch!=EOF)) { + if (ch=='\\') { + if ((ch=getc(file))==EOF) + break; + if (ch=='\n') { + inComment= FALSE; + ch= ' '; + line->line_num++; + } + } + if (inComment) + continue; + if (ch=='/') { + if (slashPending) { + inComment= TRUE; + slashPending= FALSE; + } + else { + slashPending= TRUE; + } + continue; + } + else if (slashPending) { + if (spacePending) { + ADD_CHAR(line,' '); + spacePending= FALSE; + } + ADD_CHAR(line,'/'); + slashPending= FALSE; + } + if (isspace(ch)) { + while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) { + ch= getc(file); + } + if (ch==EOF) + break; + if ((ch!='\n')&&(line->num_line>0)) + spacePending= TRUE; + ungetc(ch,file); + } + else { + if (spacePending) { + ADD_CHAR(line,' '); + spacePending= FALSE; + } + if (checkbang && ch=='!') { + if (line->num_line!=0) { + DebugF("The '!' legal only at start of line\n"); + DebugF("Line containing '!' ignored\n"); + line->num_line= 0; + inComment= 0; + break; + } + + } + ADD_CHAR(line,ch); + } + } + if (ch==EOF) + endOfFile= TRUE; +/* else line->num_line++;*/ + } + if ((line->num_line==0)&&(endOfFile)) + return FALSE; + ADD_CHAR(line,'\0'); + return TRUE; +} + +/***====================================================================***/ + +#define MODEL 0 +#define LAYOUT 1 +#define VARIANT 2 +#define OPTION 3 +#define KEYCODES 4 +#define SYMBOLS 5 +#define TYPES 6 +#define COMPAT 7 +#define GEOMETRY 8 +#define MAX_WORDS 9 + +#define PART_MASK 0x000F +#define COMPONENT_MASK 0x03F0 + +static char * cname[MAX_WORDS] = { + "model", "layout", "variant", "option", + "keycodes", "symbols", "types", "compat", "geometry" +}; + +typedef struct _RemapSpec { + int number; + int num_remap; + struct { + int word; + int index; + } remap[MAX_WORDS]; +} RemapSpec; + +typedef struct _FileSpec { + char * name[MAX_WORDS]; + struct _FileSpec * pending; +} FileSpec; + +typedef struct { + char * model; + char * layout[XkbNumKbdGroups+1]; + char * variant[XkbNumKbdGroups+1]; + char * options; +} XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr; + +#define NDX_BUFF_SIZE 4 + +/***====================================================================***/ + +static char* +get_index(char *str, int *ndx) +{ + char ndx_buf[NDX_BUFF_SIZE]; + char *end; + + if (*str != '[') { + *ndx = 0; + return str; + } + str++; + end = strchr(str, ']'); + if (end == NULL) { + *ndx = -1; + return str - 1; + } + if ( (end - str) >= NDX_BUFF_SIZE) { + *ndx = -1; + return end + 1; + } + strncpy(ndx_buf, str, end - str); + ndx_buf[end - str] = '\0'; + *ndx = atoi(ndx_buf); + return end + 1; +} + +static void +SetUpRemap(InputLine *line,RemapSpec *remap) +{ +char * tok,*str; +unsigned present, l_ndx_present, v_ndx_present; +register int i; +int len, ndx; +_Xstrtokparams strtok_buf; +Bool found; + + + l_ndx_present = v_ndx_present = present= 0; + str= &line->line[1]; + len = remap->number; + bzero((char *)remap,sizeof(RemapSpec)); + remap->number = len; + while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) { + found= FALSE; + str= NULL; + if (strcmp(tok,"=")==0) + continue; + for (i=0;i<MAX_WORDS;i++) { + len = strlen(cname[i]); + if (strncmp(cname[i],tok,len)==0) { + if(strlen(tok) > len) { + char *end = get_index(tok+len, &ndx); + if ((i != LAYOUT && i != VARIANT) || + *end != '\0' || ndx == -1) + break; + if (ndx < 1 || ndx > XkbNumKbdGroups) { + DebugF("Illegal %s index: %d\n", cname[i], ndx); + DebugF("Index must be in range 1..%d\n", + XkbNumKbdGroups); + break; + } + } else { + ndx = 0; + } + found= TRUE; + if (present&(1<<i)) { + if ((i == LAYOUT && l_ndx_present&(1<<ndx)) || + (i == VARIANT && v_ndx_present&(1<<ndx)) ) { + DebugF("Component \"%s\" listed twice\n",tok); + DebugF("Second definition ignored\n"); + break; + } + } + present |= (1<<i); + if (i == LAYOUT) + l_ndx_present |= 1 << ndx; + if (i == VARIANT) + v_ndx_present |= 1 << ndx; + remap->remap[remap->num_remap].word= i; + remap->remap[remap->num_remap++].index= ndx; + break; + } + } + if (!found) { + fprintf(stderr,"Unknown component \"%s\" ignored\n",tok); + } + } + if ((present&PART_MASK)==0) { + unsigned mask= PART_MASK; + ErrorF("Mapping needs at least one of "); + for (i=0; (i<MAX_WORDS); i++) { + if ((1L<<i)&mask) { + mask&= ~(1L<<i); + if (mask) DebugF("\"%s,\" ",cname[i]); + else DebugF("or \"%s\"\n",cname[i]); + } + } + DebugF("Illegal mapping ignored\n"); + remap->num_remap= 0; + return; + } + if ((present&COMPONENT_MASK)==0) { + DebugF("Mapping needs at least one component\n"); + DebugF("Illegal mapping ignored\n"); + remap->num_remap= 0; + return; + } + remap->number++; + return; +} + +static Bool +MatchOneOf(char *wanted,char *vals_defined) +{ +char *str,*next; +int want_len= strlen(wanted); + + for (str=vals_defined,next=NULL;str!=NULL;str=next) { + int len; + next= strchr(str,','); + if (next) { + len= next-str; + next++; + } + else { + len= strlen(str); + } + if ((len==want_len)&&(strncmp(wanted,str,len)==0)) + return TRUE; + } + return FALSE; +} + +/***====================================================================***/ + +static Bool +CheckLine( InputLine * line, + RemapSpec * remap, + XkbRF_RulePtr rule, + XkbRF_GroupPtr group) +{ +char * str,*tok; +register int nread, i; +FileSpec tmp; +_Xstrtokparams strtok_buf; +Bool append = FALSE; + + if (line->line[0]=='!') { + if (line->line[1] == '$' || + (line->line[1] == ' ' && line->line[2] == '$')) { + char *gname = strchr(line->line, '$'); + char *words = strchr(gname, ' '); + if(!words) + return FALSE; + *words++ = '\0'; + for (; *words; words++) { + if (*words != '=' && *words != ' ') + break; + } + if (*words == '\0') + return FALSE; + group->name = _XkbDupString(gname); + group->words = _XkbDupString(words); + for (i = 1, words = group->words; *words; words++) { + if ( *words == ' ') { + *words++ = '\0'; + i++; + } + } + group->number = i; + return TRUE; + } else { + SetUpRemap(line,remap); + return FALSE; + } + } + + if (remap->num_remap==0) { + DebugF("Must have a mapping before first line of data\n"); + DebugF("Illegal line of data ignored\n"); + return FALSE; + } + bzero((char *)&tmp,sizeof(FileSpec)); + str= line->line; + for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) { + str= NULL; + if (strcmp(tok,"=")==0) { + nread--; + continue; + } + if (nread>remap->num_remap) { + DebugF("Too many words on a line\n"); + DebugF("Extra word \"%s\" ignored\n",tok); + continue; + } + tmp.name[remap->remap[nread].word]= tok; + if (*tok == '+' || *tok == '|') + append = TRUE; + } + if (nread<remap->num_remap) { + DebugF("Too few words on a line: %s\n", line->line); + DebugF("line ignored\n"); + return FALSE; + } + + rule->flags= 0; + rule->number = remap->number; + if (tmp.name[OPTION]) + rule->flags|= XkbRF_Option; + else if (append) + rule->flags|= XkbRF_Append; + else + rule->flags|= XkbRF_Normal; + rule->model= _XkbDupString(tmp.name[MODEL]); + rule->layout= _XkbDupString(tmp.name[LAYOUT]); + rule->variant= _XkbDupString(tmp.name[VARIANT]); + rule->option= _XkbDupString(tmp.name[OPTION]); + + rule->keycodes= _XkbDupString(tmp.name[KEYCODES]); + rule->symbols= _XkbDupString(tmp.name[SYMBOLS]); + rule->types= _XkbDupString(tmp.name[TYPES]); + rule->compat= _XkbDupString(tmp.name[COMPAT]); + rule->geometry= _XkbDupString(tmp.name[GEOMETRY]); + + rule->layout_num = rule->variant_num = 0; + for (i = 0; i < nread; i++) { + if (remap->remap[i].index) { + if (remap->remap[i].word == LAYOUT) + rule->layout_num = remap->remap[i].index; + if (remap->remap[i].word == VARIANT) + rule->variant_num = remap->remap[i].index; + } + } + return TRUE; +} + +static char * +_Concat(char *str1,char *str2) +{ +int len; + + if ((!str1)||(!str2)) + return str1; + len= strlen(str1)+strlen(str2)+1; + str1= realloc(str1,len * sizeof(char)); + if (str1) + strcat(str1,str2); + return str1; +} + +static void +squeeze_spaces(char *p1) +{ + char *p2; + for (p2 = p1; *p2; p2++) { + *p1 = *p2; + if (*p1 != ' ') p1++; + } + *p1 = '\0'; +} + +static Bool +MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs) +{ + + bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec)); + mdefs->model = defs->model; + mdefs->options = _XkbDupString(defs->options); + if (mdefs->options) squeeze_spaces(mdefs->options); + + if (defs->layout) { + if (!strchr(defs->layout, ',')) { + mdefs->layout[0] = defs->layout; + } else { + char *p; + int i; + mdefs->layout[1] = _XkbDupString(defs->layout); + if (mdefs->layout[1] == NULL) + return FALSE; + squeeze_spaces(mdefs->layout[1]); + p = mdefs->layout[1]; + for (i = 2; i <= XkbNumKbdGroups; i++) { + if ((p = strchr(p, ','))) { + *p++ = '\0'; + mdefs->layout[i] = p; + } else { + break; + } + } + if (p && (p = strchr(p, ','))) + *p = '\0'; + } + } + + if (defs->variant) { + if (!strchr(defs->variant, ',')) { + mdefs->variant[0] = defs->variant; + } else { + char *p; + int i; + mdefs->variant[1] = _XkbDupString(defs->variant); + if (mdefs->variant[1] == NULL) + return FALSE; + squeeze_spaces(mdefs->variant[1]); + p = mdefs->variant[1]; + for (i = 2; i <= XkbNumKbdGroups; i++) { + if ((p = strchr(p, ','))) { + *p++ = '\0'; + mdefs->variant[i] = p; + } else { + break; + } + } + if (p && (p = strchr(p, ','))) + *p = '\0'; + } + } + return TRUE; +} + +static void +FreeMultiDefs(XkbRF_MultiDefsPtr defs) +{ + if (defs->options) free(defs->options); + if (defs->layout[1]) free(defs->layout[1]); + if (defs->variant[1]) free(defs->variant[1]); +} + +static void +Apply(char *src, char **dst) +{ + if (src) { + if (*src == '+' || *src == '!') { + *dst= _Concat(*dst, src); + } else { + if (*dst == NULL) + *dst= _XkbDupString(src); + } + } +} + +static void +XkbRF_ApplyRule( XkbRF_RulePtr rule, + XkbComponentNamesPtr names) +{ + rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */ + + Apply(rule->keycodes, &names->keycodes); + Apply(rule->symbols, &names->symbols); + Apply(rule->types, &names->types); + Apply(rule->compat, &names->compat); + Apply(rule->geometry, &names->geometry); +} + +static Bool +CheckGroup( XkbRF_RulesPtr rules, + char * group_name, + char * name) +{ + int i; + char *p; + XkbRF_GroupPtr group; + + for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) { + if (! strcmp(group->name, group_name)) { + break; + } + } + if (i == rules->num_groups) + return FALSE; + for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) { + if (! strcmp(p, name)) { + return TRUE; + } + } + return FALSE; +} + +static int +XkbRF_CheckApplyRule( XkbRF_RulePtr rule, + XkbRF_MultiDefsPtr mdefs, + XkbComponentNamesPtr names, + XkbRF_RulesPtr rules) +{ + Bool pending = FALSE; + + if (rule->model != NULL) { + if(mdefs->model == NULL) + return 0; + if (strcmp(rule->model, "*") == 0) { + pending = TRUE; + } else { + if (rule->model[0] == '$') { + if (!CheckGroup(rules, rule->model, mdefs->model)) + return 0; + } else { + if (strcmp(rule->model, mdefs->model) != 0) + return 0; + } + } + } + if (rule->option != NULL) { + if (mdefs->options == NULL) + return 0; + if ((!MatchOneOf(rule->option,mdefs->options))) + return 0; + } + + if (rule->layout != NULL) { + if(mdefs->layout[rule->layout_num] == NULL || + *mdefs->layout[rule->layout_num] == '\0') + return 0; + if (strcmp(rule->layout, "*") == 0) { + pending = TRUE; + } else { + if (rule->layout[0] == '$') { + if (!CheckGroup(rules, rule->layout, + mdefs->layout[rule->layout_num])) + return 0; + } else { + if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0) + return 0; + } + } + } + if (rule->variant != NULL) { + if (mdefs->variant[rule->variant_num] == NULL || + *mdefs->variant[rule->variant_num] == '\0') + return 0; + if (strcmp(rule->variant, "*") == 0) { + pending = TRUE; + } else { + if (rule->variant[0] == '$') { + if (!CheckGroup(rules, rule->variant, + mdefs->variant[rule->variant_num])) + return 0; + } else { + if (strcmp(rule->variant, + mdefs->variant[rule->variant_num]) != 0) + return 0; + } + } + } + if (pending) { + rule->flags|= XkbRF_PendingMatch; + return rule->number; + } + /* exact match, apply it now */ + XkbRF_ApplyRule(rule,names); + return rule->number; +} + +static void +XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules) +{ +register int i; +XkbRF_RulePtr rule; + + for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { + rule->flags&= ~XkbRF_PendingMatch; + } +} + +static void +XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names) +{ +int i; +XkbRF_RulePtr rule; + + for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) { + if ((rule->flags&XkbRF_PendingMatch)==0) + continue; + XkbRF_ApplyRule(rule,names); + } +} + +static void +XkbRF_CheckApplyRules( XkbRF_RulesPtr rules, + XkbRF_MultiDefsPtr mdefs, + XkbComponentNamesPtr names, + int flags) +{ +int i; +XkbRF_RulePtr rule; +int skip; + + for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) { + if ((rule->flags & flags) != flags) + continue; + skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules); + if (skip && !(flags & XkbRF_Option)) { + for ( ;(i < rules->num_rules) && (rule->number == skip); + rule++, i++); + rule--; i--; + } + } +} + +/***====================================================================***/ + +static char * +XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs) +{ +char *str, *outstr, *orig, *var; +int len, ndx; + + orig= name; + str= index(name,'%'); + if (str==NULL) + return name; + len= strlen(name); + while (str!=NULL) { + char pfx= str[1]; + int extra_len= 0; + if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { + extra_len= 1; + str++; + } + else if (pfx=='(') { + extra_len= 2; + str++; + } + var = str + 1; + str = get_index(var + 1, &ndx); + if (ndx == -1) { + str = index(str,'%'); + continue; + } + if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) + len+= strlen(mdefs->layout[ndx])+extra_len; + else if ((*var=='m')&&mdefs->model) + len+= strlen(mdefs->model)+extra_len; + else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) + len+= strlen(mdefs->variant[ndx])+extra_len; + if ((pfx=='(')&&(*str==')')) { + str++; + } + str= index(&str[0],'%'); + } + name= malloc(len+1); + str= orig; + outstr= name; + while (*str!='\0') { + if (str[0]=='%') { + char pfx,sfx; + str++; + pfx= str[0]; + sfx= '\0'; + if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { + str++; + } + else if (pfx=='(') { + sfx= ')'; + str++; + } + else pfx= '\0'; + + var = str; + str = get_index(var + 1, &ndx); + if (ndx == -1) { + continue; + } + if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) { + if (pfx) *outstr++= pfx; + strcpy(outstr,mdefs->layout[ndx]); + outstr+= strlen(mdefs->layout[ndx]); + if (sfx) *outstr++= sfx; + } + else if ((*var=='m')&&(mdefs->model)) { + if (pfx) *outstr++= pfx; + strcpy(outstr,mdefs->model); + outstr+= strlen(mdefs->model); + if (sfx) *outstr++= sfx; + } + else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) { + if (pfx) *outstr++= pfx; + strcpy(outstr,mdefs->variant[ndx]); + outstr+= strlen(mdefs->variant[ndx]); + if (sfx) *outstr++= sfx; + } + if ((pfx=='(')&&(*str==')')) + str++; + } + else { + *outstr++= *str++; + } + } + *outstr++= '\0'; + if (orig!=name) + free(orig); + return name; +} + +/***====================================================================***/ + +Bool +XkbRF_GetComponents( XkbRF_RulesPtr rules, + XkbRF_VarDefsPtr defs, + XkbComponentNamesPtr names) +{ + XkbRF_MultiDefsRec mdefs; + + MakeMultiDefs(&mdefs, defs); + + bzero((char *)names,sizeof(XkbComponentNamesRec)); + XkbRF_ClearPartialMatches(rules); + XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal); + XkbRF_ApplyPartialMatches(rules, names); + XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append); + XkbRF_ApplyPartialMatches(rules, names); + XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option); + + if (names->keycodes) + names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs); + if (names->symbols) + names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs); + if (names->types) + names->types= XkbRF_SubstituteVars(names->types, &mdefs); + if (names->compat) + names->compat= XkbRF_SubstituteVars(names->compat, &mdefs); + if (names->geometry) + names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs); + + FreeMultiDefs(&mdefs); + return (names->keycodes && names->symbols && names->types && + names->compat && names->geometry); +} + +static XkbRF_RulePtr +XkbRF_AddRule(XkbRF_RulesPtr rules) +{ + if (rules->sz_rules<1) { + rules->sz_rules= 16; + rules->num_rules= 0; + rules->rules= calloc(rules->sz_rules, sizeof(XkbRF_RuleRec)); + } + else if (rules->num_rules>=rules->sz_rules) { + rules->sz_rules*= 2; + rules->rules= realloc(rules->rules, + rules->sz_rules * sizeof(XkbRF_RuleRec)); + } + if (!rules->rules) { + rules->sz_rules= rules->num_rules= 0; + DebugF("Allocation failure in XkbRF_AddRule\n"); + return NULL; + } + bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec)); + return &rules->rules[rules->num_rules++]; +} + +static XkbRF_GroupPtr +XkbRF_AddGroup(XkbRF_RulesPtr rules) +{ + if (rules->sz_groups<1) { + rules->sz_groups= 16; + rules->num_groups= 0; + rules->groups= calloc(rules->sz_groups, sizeof(XkbRF_GroupRec)); + } + else if (rules->num_groups >= rules->sz_groups) { + rules->sz_groups *= 2; + rules->groups= realloc(rules->groups, + rules->sz_groups * sizeof(XkbRF_GroupRec)); + } + if (!rules->groups) { + rules->sz_groups= rules->num_groups= 0; + return NULL; + } + + bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec)); + return &rules->groups[rules->num_groups++]; +} + +Bool +XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules) +{ +InputLine line; +RemapSpec remap; +XkbRF_RuleRec trule,*rule; +XkbRF_GroupRec tgroup,*group; + + if (!(rules && file)) + return FALSE; + bzero((char *)&remap,sizeof(RemapSpec)); + bzero((char *)&tgroup,sizeof(XkbRF_GroupRec)); + InitInputLine(&line); + while (GetInputLine(file,&line,TRUE)) { + if (CheckLine(&line,&remap,&trule,&tgroup)) { + if (tgroup.number) { + if ((group= XkbRF_AddGroup(rules))!=NULL) { + *group= tgroup; + bzero((char *)&tgroup,sizeof(XkbRF_GroupRec)); + } + } else { + if ((rule= XkbRF_AddRule(rules))!=NULL) { + *rule= trule; + bzero((char *)&trule,sizeof(XkbRF_RuleRec)); + } + } + } + line.num_line= 0; + } + FreeInputLine(&line); + return TRUE; +} + +Bool +XkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules) +{ +FILE * file; +char buf[PATH_MAX]; +Bool ok; + + if ((!base)||(!rules)) + return FALSE; + if (locale) { + if (strlen(base)+strlen(locale)+2 > PATH_MAX) + return FALSE; + sprintf(buf,"%s-%s", base, locale); + } + else { + if (strlen(base)+1 > PATH_MAX) + return FALSE; + strcpy(buf,base); + } + + file= fopen(buf, "r"); + if ((!file)&&(locale)) { /* fallback if locale was specified */ + strcpy(buf,base); + file= fopen(buf, "r"); + } + if (!file) + return FALSE; + ok= XkbRF_LoadRules(file,rules); + fclose(file); + return ok; +} + +/***====================================================================***/ + +XkbRF_RulesPtr +XkbRF_Create(void) +{ + return calloc(1, sizeof( XkbRF_RulesRec)); +} + +/***====================================================================***/ + +void +XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules) +{ +int i; +XkbRF_RulePtr rule; +XkbRF_GroupPtr group; + + if (!rules) + return; + if (rules->rules) { + for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { + if (rule->model) free(rule->model); + if (rule->layout) free(rule->layout); + if (rule->variant) free(rule->variant); + if (rule->option) free(rule->option); + if (rule->keycodes) free(rule->keycodes); + if (rule->symbols) free(rule->symbols); + if (rule->types) free(rule->types); + if (rule->compat) free(rule->compat); + if (rule->geometry) free(rule->geometry); + bzero((char *)rule,sizeof(XkbRF_RuleRec)); + } + free(rules->rules); + rules->num_rules= rules->sz_rules= 0; + rules->rules= NULL; + } + + if (rules->groups) { + for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) { + if (group->name) free(group->name); + if (group->words) free(group->words); + } + free(rules->groups); + rules->num_groups= 0; + rules->groups= NULL; + } + if (freeRules) + free(rules); + return; +} diff --git a/xorg-server/xkb/xkb.c b/xorg-server/xkb/xkb.c index 29052bf13..7d0124c25 100644 --- a/xorg-server/xkb/xkb.c +++ b/xorg-server/xkb/xkb.c @@ -1,6721 +1,6721 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#endif - -#include <stdio.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "inputstr.h" -#define XKBSRV_NEED_FILE_FUNCS -#include <xkbsrv.h> -#include "extnsionst.h" -#include "xace.h" -#include "xkb.h" -#include "protocol-versions.h" - -#include <X11/extensions/XI.h> -#include <X11/extensions/XKMformat.h> - -int XkbEventBase; -static int XkbErrorBase; -int XkbReqCode; -int XkbKeyboardErrorCode; -CARD32 xkbDebugFlags = 0; -static CARD32 xkbDebugCtrls = 0; - -static RESTYPE RT_XKBCLIENT; - -/***====================================================================***/ - -#define CHK_DEVICE(dev, id, client, access_mode, lf) {\ - int why;\ - int rc = lf(&(dev), id, client, access_mode, &why);\ - if (rc != Success) {\ - client->errorValue = _XkbErrCode2(why, id);\ - return rc;\ - }\ -} - -#define CHK_KBD_DEVICE(dev, id, client, mode) \ - CHK_DEVICE(dev, id, client, mode, _XkbLookupKeyboard) -#define CHK_LED_DEVICE(dev, id, client, mode) \ - CHK_DEVICE(dev, id, client, mode, _XkbLookupLedDevice) -#define CHK_BELL_DEVICE(dev, id, client, mode) \ - CHK_DEVICE(dev, id, client, mode, _XkbLookupBellDevice) -#define CHK_ANY_DEVICE(dev, id, client, mode) \ - CHK_DEVICE(dev, id, client, mode, _XkbLookupAnyDevice) - -#define CHK_ATOM_ONLY2(a,ev,er) {\ - if (((a)==None)||(!ValidAtom((a)))) {\ - (ev)= (XID)(a);\ - return er;\ - }\ -} -#define CHK_ATOM_ONLY(a) \ - CHK_ATOM_ONLY2(a,client->errorValue,BadAtom) - -#define CHK_ATOM_OR_NONE3(a,ev,er,ret) {\ - if (((a)!=None)&&(!ValidAtom((a)))) {\ - (ev)= (XID)(a);\ - (er)= BadAtom;\ - return ret;\ - }\ -} -#define CHK_ATOM_OR_NONE2(a,ev,er) {\ - if (((a)!=None)&&(!ValidAtom((a)))) {\ - (ev)= (XID)(a);\ - return er;\ - }\ -} -#define CHK_ATOM_OR_NONE(a) \ - CHK_ATOM_OR_NONE2(a,client->errorValue,BadAtom) - -#define CHK_MASK_LEGAL3(err,mask,legal,ev,er,ret) {\ - if ((mask)&(~(legal))) { \ - (ev)= _XkbErrCode2((err),((mask)&(~(legal))));\ - (er)= BadValue;\ - return ret;\ - }\ -} -#define CHK_MASK_LEGAL2(err,mask,legal,ev,er) {\ - if ((mask)&(~(legal))) { \ - (ev)= _XkbErrCode2((err),((mask)&(~(legal))));\ - return er;\ - }\ -} -#define CHK_MASK_LEGAL(err,mask,legal) \ - CHK_MASK_LEGAL2(err,mask,legal,client->errorValue,BadValue) - -#define CHK_MASK_MATCH(err,affect,value) {\ - if ((value)&(~(affect))) { \ - client->errorValue= _XkbErrCode2((err),((value)&(~(affect))));\ - return BadMatch;\ - }\ -} -#define CHK_MASK_OVERLAP(err,m1,m2) {\ - if ((m1)&(m2)) { \ - client->errorValue= _XkbErrCode2((err),((m1)&(m2)));\ - return BadMatch;\ - }\ -} -#define CHK_KEY_RANGE2(err,first,num,x,ev,er) {\ - if (((unsigned)(first)+(num)-1)>(x)->max_key_code) {\ - (ev)=_XkbErrCode4(err,(first),(num),(x)->max_key_code);\ - return er;\ - }\ - else if ( (first)<(x)->min_key_code ) {\ - (ev)=_XkbErrCode3(err+1,(first),xkb->min_key_code);\ - return er;\ - }\ -} -#define CHK_KEY_RANGE(err,first,num,x) \ - CHK_KEY_RANGE2(err,first,num,x,client->errorValue,BadValue) - -#define CHK_REQ_KEY_RANGE2(err,first,num,r,ev,er) {\ - if (((unsigned)(first)+(num)-1)>(r)->maxKeyCode) {\ - (ev)=_XkbErrCode4(err,(first),(num),(r)->maxKeyCode);\ - return er;\ - }\ - else if ( (first)<(r)->minKeyCode ) {\ - (ev)=_XkbErrCode3(err+1,(first),(r)->minKeyCode);\ - return er;\ - }\ -} -#define CHK_REQ_KEY_RANGE(err,first,num,r) \ - CHK_REQ_KEY_RANGE2(err,first,num,r,client->errorValue,BadValue) - -/***====================================================================***/ - -int -ProcXkbUseExtension(ClientPtr client) -{ - REQUEST(xkbUseExtensionReq); - xkbUseExtensionReply rep; - register int n; - int supported; - - REQUEST_SIZE_MATCH(xkbUseExtensionReq); - if (stuff->wantedMajor != SERVER_XKB_MAJOR_VERSION) { - /* pre-release version 0.65 is compatible with 1.00 */ - supported= ((SERVER_XKB_MAJOR_VERSION==1)&& - (stuff->wantedMajor==0)&&(stuff->wantedMinor==65)); - } - else supported = 1; - - if ((supported) && (!(client->xkbClientFlags&_XkbClientInitialized))) { - client->xkbClientFlags= _XkbClientInitialized; - client->vMajor= stuff->wantedMajor; - client->vMinor= stuff->wantedMinor; - } - else if (xkbDebugFlags&0x1) { - ErrorF("[xkb] Rejecting client %d (0x%lx) (wants %d.%02d, have %d.%02d)\n", - client->index, - (long)client->clientAsMask, - stuff->wantedMajor,stuff->wantedMinor, - SERVER_XKB_MAJOR_VERSION,SERVER_XKB_MINOR_VERSION); - } - memset(&rep, 0, sizeof(xkbUseExtensionReply)); - rep.type = X_Reply; - rep.supported = supported; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.serverMajor = SERVER_XKB_MAJOR_VERSION; - rep.serverMinor = SERVER_XKB_MINOR_VERSION; - if ( client->swapped ) { - swaps(&rep.sequenceNumber, n); - swaps(&rep.serverMajor, n); - swaps(&rep.serverMinor, n); - } - WriteToClient(client,SIZEOF(xkbUseExtensionReply), (char *)&rep); - return client->noClientException; -} - -/***====================================================================***/ - -int -ProcXkbSelectEvents(ClientPtr client) -{ - unsigned legal; - DeviceIntPtr dev; - XkbInterestPtr masks; - REQUEST(xkbSelectEventsReq); - - REQUEST_AT_LEAST_SIZE(xkbSelectEventsReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixUseAccess); - - if (((stuff->affectWhich&XkbMapNotifyMask)!=0)&&(stuff->affectMap)) { - client->mapNotifyMask&= ~stuff->affectMap; - client->mapNotifyMask|= (stuff->affectMap&stuff->map); - } - if ((stuff->affectWhich&(~XkbMapNotifyMask))==0) - return client->noClientException; - - masks = XkbFindClientResource((DevicePtr)dev,client); - if (!masks){ - XID id = FakeClientID(client->index); - AddResource(id,RT_XKBCLIENT,dev); - masks= XkbAddClientResource((DevicePtr)dev,client,id); - } - if (masks) { - union { - CARD8 *c8; - CARD16 *c16; - CARD32 *c32; - } from,to; - register unsigned bit,ndx,maskLeft,dataLeft,size; - - from.c8= (CARD8 *)&stuff[1]; - dataLeft= (stuff->length*4)-SIZEOF(xkbSelectEventsReq); - maskLeft= (stuff->affectWhich&(~XkbMapNotifyMask)); - for (ndx=0,bit=1; (maskLeft!=0); ndx++, bit<<=1) { - if ((bit&maskLeft)==0) - continue; - maskLeft&= ~bit; - switch (ndx) { - case XkbNewKeyboardNotify: - to.c16= &client->newKeyboardNotifyMask; - legal= XkbAllNewKeyboardEventsMask; - size= 2; - break; - case XkbStateNotify: - to.c16= &masks->stateNotifyMask; - legal= XkbAllStateEventsMask; - size= 2; - break; - case XkbControlsNotify: - to.c32= &masks->ctrlsNotifyMask; - legal= XkbAllControlEventsMask; - size= 4; - break; - case XkbIndicatorStateNotify: - to.c32= &masks->iStateNotifyMask; - legal= XkbAllIndicatorEventsMask; - size= 4; - break; - case XkbIndicatorMapNotify: - to.c32= &masks->iMapNotifyMask; - legal= XkbAllIndicatorEventsMask; - size= 4; - break; - case XkbNamesNotify: - to.c16= &masks->namesNotifyMask; - legal= XkbAllNameEventsMask; - size= 2; - break; - case XkbCompatMapNotify: - to.c8= &masks->compatNotifyMask; - legal= XkbAllCompatMapEventsMask; - size= 1; - break; - case XkbBellNotify: - to.c8= &masks->bellNotifyMask; - legal= XkbAllBellEventsMask; - size= 1; - break; - case XkbActionMessage: - to.c8= &masks->actionMessageMask; - legal= XkbAllActionMessagesMask; - size= 1; - break; - case XkbAccessXNotify: - to.c16= &masks->accessXNotifyMask; - legal= XkbAllAccessXEventsMask; - size= 2; - break; - case XkbExtensionDeviceNotify: - to.c16= &masks->extDevNotifyMask; - legal= XkbAllExtensionDeviceEventsMask; - size= 2; - break; - default: - client->errorValue = _XkbErrCode2(33,bit); - return BadValue; - } - - if (stuff->clear&bit) { - if (size==2) to.c16[0]= 0; - else if (size==4) to.c32[0]= 0; - else to.c8[0]= 0; - } - else if (stuff->selectAll&bit) { - if (size==2) to.c16[0]= ~0; - else if (size==4) to.c32[0]= ~0; - else to.c8[0]= ~0; - } - else { - if (dataLeft<(size*2)) - return BadLength; - if (size==2) { - CHK_MASK_MATCH(ndx,from.c16[0],from.c16[1]); - CHK_MASK_LEGAL(ndx,from.c16[0],legal); - to.c16[0]&= ~from.c16[0]; - to.c16[0]|= (from.c16[0]&from.c16[1]); - } - else if (size==4) { - CHK_MASK_MATCH(ndx,from.c32[0],from.c32[1]); - CHK_MASK_LEGAL(ndx,from.c32[0],legal); - to.c32[0]&= ~from.c32[0]; - to.c32[0]|= (from.c32[0]&from.c32[1]); - } - else { - CHK_MASK_MATCH(ndx,from.c8[0],from.c8[1]); - CHK_MASK_LEGAL(ndx,from.c8[0],legal); - to.c8[0]&= ~from.c8[0]; - to.c8[0]|= (from.c8[0]&from.c8[1]); - size= 2; - } - from.c8+= (size*2); - dataLeft-= (size*2); - } - } - if (dataLeft>2) { - ErrorF("[xkb] Extra data (%d bytes) after SelectEvents\n",dataLeft); - return BadLength; - } - return client->noClientException; - } - return BadAlloc; -} - -/***====================================================================***/ -/** - * Ring a bell on the given device for the given client. - */ -static int -_XkbBell(ClientPtr client, DeviceIntPtr dev, WindowPtr pWin, - int bellClass, int bellID, int pitch, int duration, - int percent, int forceSound, int eventOnly, Atom name) -{ - int base; - pointer ctrl; - int oldPitch, oldDuration; - int newPercent; - - if (bellClass == KbdFeedbackClass) { - KbdFeedbackPtr k; - if (bellID==XkbDfltXIId) - k= dev->kbdfeed; - else { - for (k=dev->kbdfeed; k; k=k->next) { - if (k->ctrl.id == bellID) - break; - } - } - if (!k) { - client->errorValue = _XkbErrCode2(0x5,bellID); - return BadValue; - } - base = k->ctrl.bell; - ctrl = (pointer) &(k->ctrl); - oldPitch= k->ctrl.bell_pitch; - oldDuration= k->ctrl.bell_duration; - if (pitch!=0) { - if (pitch==-1) - k->ctrl.bell_pitch= defaultKeyboardControl.bell_pitch; - else k->ctrl.bell_pitch= pitch; - } - if (duration!=0) { - if (duration==-1) - k->ctrl.bell_duration= defaultKeyboardControl.bell_duration; - else k->ctrl.bell_duration= duration; - } - } - else if (bellClass == BellFeedbackClass) { - BellFeedbackPtr b; - if (bellID==XkbDfltXIId) - b= dev->bell; - else { - for (b=dev->bell; b; b=b->next) { - if (b->ctrl.id == bellID) - break; - } - } - if (!b) { - client->errorValue = _XkbErrCode2(0x6,bellID); - return BadValue; - } - base = b->ctrl.percent; - ctrl = (pointer) &(b->ctrl); - oldPitch= b->ctrl.pitch; - oldDuration= b->ctrl.duration; - if (pitch!=0) { - if (pitch==-1) - b->ctrl.pitch= defaultKeyboardControl.bell_pitch; - else b->ctrl.pitch= pitch; - } - if (duration!=0) { - if (duration==-1) - b->ctrl.duration= defaultKeyboardControl.bell_duration; - else b->ctrl.duration= duration; - } - } - else { - client->errorValue = _XkbErrCode2(0x7, bellClass); - return BadValue; - } - - newPercent = (base * percent)/100; - if (percent < 0) - newPercent = base + newPercent; - else newPercent = base - newPercent + percent; - - XkbHandleBell(forceSound, eventOnly, - dev, newPercent, ctrl, bellClass, - name, pWin, client); - if ((pitch!=0)||(duration!=0)) { - if (bellClass == KbdFeedbackClass) { - KbdFeedbackPtr k; - k= (KbdFeedbackPtr)ctrl; - if (pitch!=0) - k->ctrl.bell_pitch= oldPitch; - if (duration!=0) - k->ctrl.bell_duration= oldDuration; - } - else { - BellFeedbackPtr b; - b= (BellFeedbackPtr)ctrl; - if (pitch!=0) - b->ctrl.pitch= oldPitch; - if (duration!=0) - b->ctrl.duration= oldDuration; - } - } - - return Success; -} - -int -ProcXkbBell(ClientPtr client) -{ - REQUEST(xkbBellReq); - DeviceIntPtr dev; - WindowPtr pWin; - int rc; - - REQUEST_SIZE_MATCH(xkbBellReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_BELL_DEVICE(dev, stuff->deviceSpec, client, DixBellAccess); - CHK_ATOM_OR_NONE(stuff->name); - - /* device-independent checks request for sane values */ - if ((stuff->forceSound)&&(stuff->eventOnly)) { - client->errorValue=_XkbErrCode3(0x1,stuff->forceSound,stuff->eventOnly); - return BadMatch; - } - if (stuff->percent < -100 || stuff->percent > 100) { - client->errorValue = _XkbErrCode2(0x2,stuff->percent); - return BadValue; - } - if (stuff->duration<-1) { - client->errorValue = _XkbErrCode2(0x3,stuff->duration); - return BadValue; - } - if (stuff->pitch<-1) { - client->errorValue = _XkbErrCode2(0x4,stuff->pitch); - return BadValue; - } - - if (stuff->bellClass == XkbDfltXIClass) { - if (dev->kbdfeed!=NULL) - stuff->bellClass= KbdFeedbackClass; - else stuff->bellClass= BellFeedbackClass; - } - - if (stuff->window!=None) { - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) { - client->errorValue= stuff->window; - return rc; - } - } - else pWin= NULL; - - /* Client wants to ring a bell on the core keyboard? - Ring the bell on the core keyboard (which does nothing, but if that - fails the client is screwed anyway), and then on all extension devices. - Fail if the core keyboard fails but not the extension devices. this - may cause some keyboards to ding and others to stay silent. Fix - your client to use explicit keyboards to avoid this. - - dev is the device the client requested. - */ - rc = _XkbBell(client, dev, pWin, stuff->bellClass, stuff->bellID, - stuff->pitch, stuff->duration, stuff->percent, - stuff->forceSound, stuff->eventOnly, stuff->name); - - if ((rc == Success) && ((stuff->deviceSpec == XkbUseCoreKbd) || - (stuff->deviceSpec == XkbUseCorePtr))) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) - { - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixBellAccess); - if (rc == Success) - _XkbBell(client, other, pWin, stuff->bellClass, - stuff->bellID, stuff->pitch, stuff->duration, - stuff->percent, stuff->forceSound, - stuff->eventOnly, stuff->name); - } - } - rc = Success; /* reset to success, that's what we got for the VCK */ - } - - return rc; -} - -/***====================================================================***/ - -int -ProcXkbGetState(ClientPtr client) -{ - REQUEST(xkbGetStateReq); - DeviceIntPtr dev; - xkbGetStateReply rep; - XkbStateRec *xkb; - - REQUEST_SIZE_MATCH(xkbGetStateReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); - - xkb= &dev->key->xkbInfo->state; - bzero(&rep,sizeof(xkbGetStateReply)); - rep.type= X_Reply; - rep.sequenceNumber= client->sequence; - rep.length = 0; - rep.deviceID = dev->id; - rep.mods = XkbStateFieldFromRec(xkb) & 0xff; - rep.baseMods = xkb->base_mods; - rep.lockedMods = xkb->locked_mods; - rep.latchedMods = xkb->latched_mods; - rep.group = xkb->group; - rep.baseGroup = xkb->base_group; - rep.latchedGroup = xkb->latched_group; - rep.lockedGroup = xkb->locked_group; - rep.compatState = xkb->compat_state; - rep.ptrBtnState = xkb->ptr_buttons; - if (client->swapped) { - register int n; - swaps(&rep.sequenceNumber,n); - swaps(&rep.ptrBtnState,n); - } - WriteToClient(client, SIZEOF(xkbGetStateReply), (char *)&rep); - return client->noClientException; -} - -/***====================================================================***/ - -int -ProcXkbLatchLockState(ClientPtr client) -{ - int status; - DeviceIntPtr dev, tmpd; - XkbStateRec oldState,*newState; - CARD16 changed; - xkbStateNotify sn; - XkbEventCauseRec cause; - - REQUEST(xkbLatchLockStateReq); - REQUEST_SIZE_MATCH(xkbLatchLockStateReq); - - if (!(client->xkbClientFlags & _XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess); - CHK_MASK_MATCH(0x01, stuff->affectModLocks, stuff->modLocks); - CHK_MASK_MATCH(0x01, stuff->affectModLatches, stuff->modLatches); - - status = Success; - - for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) { - if ((tmpd == dev) || (!IsMaster(tmpd) && tmpd->u.master == dev)) { - if (!tmpd->key || !tmpd->key->xkbInfo) - continue; - - oldState = tmpd->key->xkbInfo->state; - newState = &tmpd->key->xkbInfo->state; - if (stuff->affectModLocks) { - newState->locked_mods &= ~stuff->affectModLocks; - newState->locked_mods |= (stuff->affectModLocks & stuff->modLocks); - } - if (status == Success && stuff->lockGroup) - newState->locked_group = stuff->groupLock; - if (status == Success && stuff->affectModLatches) - status = XkbLatchModifiers(tmpd, stuff->affectModLatches, - stuff->modLatches); - if (status == Success && stuff->latchGroup) - status = XkbLatchGroup(tmpd, stuff->groupLatch); - - if (status != Success) - return status; - - XkbComputeDerivedState(tmpd->key->xkbInfo); - - changed = XkbStateChangedFlags(&oldState, newState); - if (changed) { - sn.keycode = 0; - sn.eventType = 0; - sn.requestMajor = XkbReqCode; - sn.requestMinor = X_kbLatchLockState; - sn.changed = changed; - XkbSendStateNotify(tmpd, &sn); - changed = XkbIndicatorsToUpdate(tmpd, changed, FALSE); - if (changed) { - XkbSetCauseXkbReq(&cause, X_kbLatchLockState, client); - XkbUpdateIndicators(tmpd, changed, TRUE, NULL, &cause); - } - } - } - } - - return client->noClientException; -} - -/***====================================================================***/ - -int -ProcXkbGetControls(ClientPtr client) -{ - xkbGetControlsReply rep; - XkbControlsPtr xkb; - DeviceIntPtr dev; - register int n; - - REQUEST(xkbGetControlsReq); - REQUEST_SIZE_MATCH(xkbGetControlsReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); - - xkb = dev->key->xkbInfo->desc->ctrls; - rep.type = X_Reply; - rep.length = bytes_to_int32(SIZEOF(xkbGetControlsReply)- - SIZEOF(xGenericReply)); - rep.sequenceNumber = client->sequence; - rep.deviceID = ((DeviceIntPtr)dev)->id; - rep.numGroups = xkb->num_groups; - rep.groupsWrap = xkb->groups_wrap; - rep.internalMods = xkb->internal.mask; - rep.ignoreLockMods = xkb->ignore_lock.mask; - rep.internalRealMods = xkb->internal.real_mods; - rep.ignoreLockRealMods = xkb->ignore_lock.real_mods; - rep.internalVMods = xkb->internal.vmods; - rep.ignoreLockVMods = xkb->ignore_lock.vmods; - rep.enabledCtrls = xkb->enabled_ctrls; - rep.repeatDelay = xkb->repeat_delay; - rep.repeatInterval = xkb->repeat_interval; - rep.slowKeysDelay = xkb->slow_keys_delay; - rep.debounceDelay = xkb->debounce_delay; - rep.mkDelay = xkb->mk_delay; - rep.mkInterval = xkb->mk_interval; - rep.mkTimeToMax = xkb->mk_time_to_max; - rep.mkMaxSpeed = xkb->mk_max_speed; - rep.mkCurve = xkb->mk_curve; - rep.mkDfltBtn = xkb->mk_dflt_btn; - rep.axTimeout = xkb->ax_timeout; - rep.axtCtrlsMask = xkb->axt_ctrls_mask; - rep.axtCtrlsValues = xkb->axt_ctrls_values; - rep.axtOptsMask = xkb->axt_opts_mask; - rep.axtOptsValues = xkb->axt_opts_values; - rep.axOptions = xkb->ax_options; - memcpy(rep.perKeyRepeat,xkb->per_key_repeat,XkbPerKeyBitArraySize); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length,n); - swaps(&rep.internalVMods, n); - swaps(&rep.ignoreLockVMods, n); - swapl(&rep.enabledCtrls, n); - swaps(&rep.repeatDelay, n); - swaps(&rep.repeatInterval, n); - swaps(&rep.slowKeysDelay, n); - swaps(&rep.debounceDelay, n); - swaps(&rep.mkDelay, n); - swaps(&rep.mkInterval, n); - swaps(&rep.mkTimeToMax, n); - swaps(&rep.mkMaxSpeed, n); - swaps(&rep.mkCurve, n); - swaps(&rep.axTimeout, n); - swapl(&rep.axtCtrlsMask, n); - swapl(&rep.axtCtrlsValues, n); - swaps(&rep.axtOptsMask, n); - swaps(&rep.axtOptsValues, n); - swaps(&rep.axOptions, n); - } - WriteToClient(client, SIZEOF(xkbGetControlsReply), (char *)&rep); - return(client->noClientException); -} - -int -ProcXkbSetControls(ClientPtr client) -{ - DeviceIntPtr dev, tmpd; - XkbSrvInfoPtr xkbi; - XkbControlsPtr ctrl; - XkbControlsRec new,old; - xkbControlsNotify cn; - XkbEventCauseRec cause; - XkbSrvLedInfoPtr sli; - - REQUEST(xkbSetControlsReq); - REQUEST_SIZE_MATCH(xkbSetControlsReq); - - if (!(client->xkbClientFlags & _XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); - CHK_MASK_LEGAL(0x01, stuff->changeCtrls, XkbAllControlsMask); - - for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) { - if (!tmpd->key || !tmpd->key->xkbInfo) - continue; - if ((tmpd == dev) || (!IsMaster(tmpd) && tmpd->u.master == dev)) { - xkbi = tmpd->key->xkbInfo; - ctrl = xkbi->desc->ctrls; - new = *ctrl; - XkbSetCauseXkbReq(&cause, X_kbSetControls, client); - - if (stuff->changeCtrls & XkbInternalModsMask) { - CHK_MASK_MATCH(0x02, stuff->affectInternalMods, - stuff->internalMods); - CHK_MASK_MATCH(0x03, stuff->affectInternalVMods, - stuff->internalVMods); - - new.internal.real_mods &= ~(stuff->affectInternalMods); - new.internal.real_mods |= (stuff->affectInternalMods & - stuff->internalMods); - new.internal.vmods &= ~(stuff->affectInternalVMods); - new.internal.vmods |= (stuff->affectInternalVMods & - stuff->internalVMods); - new.internal.mask = new.internal.real_mods | - XkbMaskForVMask(xkbi->desc, - new.internal.vmods); - } - - if (stuff->changeCtrls & XkbIgnoreLockModsMask) { - CHK_MASK_MATCH(0x4, stuff->affectIgnoreLockMods, - stuff->ignoreLockMods); - CHK_MASK_MATCH(0x5, stuff->affectIgnoreLockVMods, - stuff->ignoreLockVMods); - - new.ignore_lock.real_mods &= ~(stuff->affectIgnoreLockMods); - new.ignore_lock.real_mods |= (stuff->affectIgnoreLockMods & - stuff->ignoreLockMods); - new.ignore_lock.vmods &= ~(stuff->affectIgnoreLockVMods); - new.ignore_lock.vmods |= (stuff->affectIgnoreLockVMods & - stuff->ignoreLockVMods); - new.ignore_lock.mask = new.ignore_lock.real_mods | - XkbMaskForVMask(xkbi->desc, - new.ignore_lock.vmods); - } - - CHK_MASK_MATCH(0x06, stuff->affectEnabledCtrls, - stuff->enabledCtrls); - if (stuff->affectEnabledCtrls) { - CHK_MASK_LEGAL(0x07, stuff->affectEnabledCtrls, - XkbAllBooleanCtrlsMask); - - new.enabled_ctrls &= ~(stuff->affectEnabledCtrls); - new.enabled_ctrls |= (stuff->affectEnabledCtrls & - stuff->enabledCtrls); - } - - if (stuff->changeCtrls & XkbRepeatKeysMask) { - if (stuff->repeatDelay < 1 || stuff->repeatInterval < 1) { - client->errorValue = _XkbErrCode3(0x08, stuff->repeatDelay, - stuff->repeatInterval); - return BadValue; - } - - new.repeat_delay = stuff->repeatDelay; - new.repeat_interval = stuff->repeatInterval; - } - - if (stuff->changeCtrls & XkbSlowKeysMask) { - if (stuff->slowKeysDelay < 1) { - client->errorValue = _XkbErrCode2(0x09, - stuff->slowKeysDelay); - return BadValue; - } - - new.slow_keys_delay = stuff->slowKeysDelay; - } - - if (stuff->changeCtrls & XkbBounceKeysMask) { - if (stuff->debounceDelay < 1) { - client->errorValue = _XkbErrCode2(0x0A, - stuff->debounceDelay); - return BadValue; - } - - new.debounce_delay = stuff->debounceDelay; - } - - if (stuff->changeCtrls & XkbMouseKeysMask) { - if (stuff->mkDfltBtn > XkbMaxMouseKeysBtn) { - client->errorValue = _XkbErrCode2(0x0B, stuff->mkDfltBtn); - return BadValue; - } - - new.mk_dflt_btn = stuff->mkDfltBtn; - } - - if (stuff->changeCtrls & XkbMouseKeysAccelMask) { - if (stuff->mkDelay < 1 || stuff->mkInterval < 1 || - stuff->mkTimeToMax < 1 || stuff->mkMaxSpeed < 1 || - stuff->mkCurve < -1000) { - client->errorValue = _XkbErrCode2(0x0C,0); - return BadValue; - } - - new.mk_delay = stuff->mkDelay; - new.mk_interval = stuff->mkInterval; - new.mk_time_to_max = stuff->mkTimeToMax; - new.mk_max_speed = stuff->mkMaxSpeed; - new.mk_curve = stuff->mkCurve; - AccessXComputeCurveFactor(xkbi, &new); - } - - if (stuff->changeCtrls & XkbGroupsWrapMask) { - unsigned act, num; - - act = XkbOutOfRangeGroupAction(stuff->groupsWrap); - switch (act) { - case XkbRedirectIntoRange: - num = XkbOutOfRangeGroupNumber(stuff->groupsWrap); - if (num >= new.num_groups) { - client->errorValue = _XkbErrCode3(0x0D, new.num_groups, - num); - return BadValue; - } - case XkbWrapIntoRange: - case XkbClampIntoRange: - break; - default: - client->errorValue = _XkbErrCode2(0x0E, act); - return BadValue; - } - - new.groups_wrap= stuff->groupsWrap; - } - - CHK_MASK_LEGAL(0x0F, stuff->axOptions, XkbAX_AllOptionsMask); - if (stuff->changeCtrls & XkbAccessXKeysMask) { - new.ax_options = stuff->axOptions & XkbAX_AllOptionsMask; - } - else { - if (stuff->changeCtrls & XkbStickyKeysMask) { - new.ax_options &= ~(XkbAX_SKOptionsMask); - new.ax_options |= (stuff->axOptions & XkbAX_SKOptionsMask); - } - - if (stuff->changeCtrls & XkbAccessXFeedbackMask) { - new.ax_options &= ~(XkbAX_FBOptionsMask); - new.ax_options |= (stuff->axOptions & XkbAX_FBOptionsMask); - } - } - - if (stuff->changeCtrls & XkbAccessXTimeoutMask) { - if (stuff->axTimeout < 1) { - client->errorValue = _XkbErrCode2(0x10, stuff->axTimeout); - return BadValue; - } - CHK_MASK_MATCH(0x11, stuff->axtCtrlsMask, - stuff->axtCtrlsValues); - CHK_MASK_LEGAL(0x12, stuff->axtCtrlsMask, - XkbAllBooleanCtrlsMask); - CHK_MASK_MATCH(0x13, stuff->axtOptsMask, stuff->axtOptsValues); - CHK_MASK_LEGAL(0x14, stuff->axtOptsMask, XkbAX_AllOptionsMask); - new.ax_timeout = stuff->axTimeout; - new.axt_ctrls_mask = stuff->axtCtrlsMask; - new.axt_ctrls_values = (stuff->axtCtrlsValues & - stuff->axtCtrlsMask); - new.axt_opts_mask = stuff->axtOptsMask; - new.axt_opts_values = (stuff->axtOptsValues & - stuff->axtOptsMask); - } - - if (stuff->changeCtrls & XkbPerKeyRepeatMask) - memcpy(new.per_key_repeat, stuff->perKeyRepeat, - XkbPerKeyBitArraySize); - - old= *ctrl; - *ctrl= new; - XkbDDXChangeControls(tmpd, &old, ctrl); - - if (XkbComputeControlsNotify(tmpd, &old, ctrl, &cn, FALSE)) { - cn.keycode = 0; - cn.eventType = 0; - cn.requestMajor = XkbReqCode; - cn.requestMinor = X_kbSetControls; - XkbSendControlsNotify(tmpd, &cn); - } - - sli = XkbFindSrvLedInfo(tmpd, XkbDfltXIClass, XkbDfltXIId, 0); - if (sli) - XkbUpdateIndicators(tmpd, sli->usesControls, TRUE, NULL, - &cause); - - /* If sticky keys were disabled, clear all locks and latches */ - if ((old.enabled_ctrls & XkbStickyKeysMask) && - !(ctrl->enabled_ctrls & XkbStickyKeysMask)) - XkbClearAllLatchesAndLocks(tmpd, xkbi, TRUE, &cause); - } - } - - return client->noClientException; -} - -/***====================================================================***/ - -static int -XkbSizeKeyTypes(XkbDescPtr xkb,xkbGetMapReply *rep) -{ - XkbKeyTypeRec *type; - unsigned i,len; - - len= 0; - if (((rep->present&XkbKeyTypesMask)==0)||(rep->nTypes<1)|| - (!xkb)||(!xkb->map)||(!xkb->map->types)) { - rep->present&= ~XkbKeyTypesMask; - rep->firstType= rep->nTypes= 0; - return 0; - } - type= &xkb->map->types[rep->firstType]; - for (i=0;i<rep->nTypes;i++,type++){ - len+= SIZEOF(xkbKeyTypeWireDesc); - if (type->map_count>0) { - len+= (type->map_count*SIZEOF(xkbKTMapEntryWireDesc)); - if (type->preserve) - len+= (type->map_count*SIZEOF(xkbModsWireDesc)); - } - } - return len; -} - -static char * -XkbWriteKeyTypes( XkbDescPtr xkb, - xkbGetMapReply * rep, - char * buf, - ClientPtr client) -{ - XkbKeyTypePtr type; - unsigned i; - xkbKeyTypeWireDesc *wire; - - type= &xkb->map->types[rep->firstType]; - for (i=0;i<rep->nTypes;i++,type++) { - register unsigned n; - wire= (xkbKeyTypeWireDesc *)buf; - wire->mask = type->mods.mask; - wire->realMods = type->mods.real_mods; - wire->virtualMods = type->mods.vmods; - wire->numLevels = type->num_levels; - wire->nMapEntries = type->map_count; - wire->preserve = (type->preserve!=NULL); - if (client->swapped) { - register int n; - swaps(&wire->virtualMods,n); - } - - buf= (char *)&wire[1]; - if (wire->nMapEntries>0) { - xkbKTMapEntryWireDesc * wire; - XkbKTMapEntryPtr entry; - wire= (xkbKTMapEntryWireDesc *)buf; - entry= type->map; - for (n=0;n<type->map_count;n++,wire++,entry++) { - wire->active= entry->active; - wire->mask= entry->mods.mask; - wire->level= entry->level; - wire->realMods= entry->mods.real_mods; - wire->virtualMods= entry->mods.vmods; - if (client->swapped) { - register int n; - swaps(&wire->virtualMods,n); - } - } - buf= (char *)wire; - if (type->preserve!=NULL) { - xkbModsWireDesc * pwire; - XkbModsPtr preserve; - pwire= (xkbModsWireDesc *)buf; - preserve= type->preserve; - for (n=0;n<type->map_count;n++,pwire++,preserve++) { - pwire->mask= preserve->mask; - pwire->realMods= preserve->real_mods; - pwire->virtualMods= preserve->vmods; - if (client->swapped) { - register int n; - swaps(&pwire->virtualMods,n); - } - } - buf= (char *)pwire; - } - } - } - return buf; -} - -static int -XkbSizeKeySyms(XkbDescPtr xkb,xkbGetMapReply *rep) -{ - XkbSymMapPtr symMap; - unsigned i,len; - unsigned nSyms,nSymsThisKey; - - if (((rep->present&XkbKeySymsMask)==0)||(rep->nKeySyms<1)|| - (!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)) { - rep->present&= ~XkbKeySymsMask; - rep->firstKeySym= rep->nKeySyms= 0; - rep->totalSyms= 0; - return 0; - } - len= rep->nKeySyms*SIZEOF(xkbSymMapWireDesc); - symMap = &xkb->map->key_sym_map[rep->firstKeySym]; - for (i=nSyms=0;i<rep->nKeySyms;i++,symMap++) { - if (symMap->offset!=0) { - nSymsThisKey= XkbNumGroups(symMap->group_info)*symMap->width; - nSyms+= nSymsThisKey; - } - } - len+= nSyms*4; - rep->totalSyms= nSyms; - return len; -} - -static int -XkbSizeVirtualMods(XkbDescPtr xkb,xkbGetMapReply *rep) -{ -register unsigned i,nMods,bit; - - if (((rep->present&XkbVirtualModsMask)==0)||(rep->virtualMods==0)|| - (!xkb)||(!xkb->server)) { - rep->present&= ~XkbVirtualModsMask; - rep->virtualMods= 0; - return 0; - } - for (i=nMods=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - if (rep->virtualMods&bit) - nMods++; - } - return XkbPaddedSize(nMods); -} - -static char * -XkbWriteKeySyms(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf,ClientPtr client) -{ -register KeySym * pSym; -XkbSymMapPtr symMap; -xkbSymMapWireDesc * outMap; -register unsigned i; - - symMap = &xkb->map->key_sym_map[rep->firstKeySym]; - for (i=0;i<rep->nKeySyms;i++,symMap++) { - outMap = (xkbSymMapWireDesc *)buf; - outMap->ktIndex[0] = symMap->kt_index[0]; - outMap->ktIndex[1] = symMap->kt_index[1]; - outMap->ktIndex[2] = symMap->kt_index[2]; - outMap->ktIndex[3] = symMap->kt_index[3]; - outMap->groupInfo = symMap->group_info; - outMap->width= symMap->width; - outMap->nSyms = symMap->width*XkbNumGroups(symMap->group_info); - buf= (char *)&outMap[1]; - if (outMap->nSyms==0) - continue; - - pSym = &xkb->map->syms[symMap->offset]; - memcpy((char *)buf,(char *)pSym,outMap->nSyms*4); - if (client->swapped) { - register int n,nSyms= outMap->nSyms; - swaps(&outMap->nSyms,n); - while (nSyms-->0) { - swapl(buf,n); - buf+= 4; - } - } - else buf+= outMap->nSyms*4; - } - return buf; -} - -static int -XkbSizeKeyActions(XkbDescPtr xkb,xkbGetMapReply *rep) -{ - unsigned i,len,nActs; - register KeyCode firstKey; - - if (((rep->present&XkbKeyActionsMask)==0)||(rep->nKeyActs<1)|| - (!xkb)||(!xkb->server)||(!xkb->server->key_acts)) { - rep->present&= ~XkbKeyActionsMask; - rep->firstKeyAct= rep->nKeyActs= 0; - rep->totalActs= 0; - return 0; - } - firstKey= rep->firstKeyAct; - for (nActs=i=0;i<rep->nKeyActs;i++) { - if (xkb->server->key_acts[i+firstKey]!=0) - nActs+= XkbKeyNumActions(xkb,i+firstKey); - } - len= XkbPaddedSize(rep->nKeyActs)+(nActs*SIZEOF(xkbActionWireDesc)); - rep->totalActs= nActs; - return len; -} - -static char * -XkbWriteKeyActions(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf, - ClientPtr client) -{ - unsigned i; - CARD8 * numDesc; - XkbAnyAction * actDesc; - - numDesc = (CARD8 *)buf; - for (i=0;i<rep->nKeyActs;i++) { - if (xkb->server->key_acts[i+rep->firstKeyAct]==0) - numDesc[i] = 0; - else numDesc[i] = XkbKeyNumActions(xkb,(i+rep->firstKeyAct)); - } - buf+= XkbPaddedSize(rep->nKeyActs); - - actDesc = (XkbAnyAction *)buf; - for (i=0;i<rep->nKeyActs;i++) { - if (xkb->server->key_acts[i+rep->firstKeyAct]!=0) { - unsigned int num; - num = XkbKeyNumActions(xkb,(i+rep->firstKeyAct)); - memcpy((char *)actDesc, - (char*)XkbKeyActionsPtr(xkb,(i+rep->firstKeyAct)), - num*SIZEOF(xkbActionWireDesc)); - actDesc+= num; - } - } - buf = (char *)actDesc; - return buf; -} - -static int -XkbSizeKeyBehaviors(XkbDescPtr xkb,xkbGetMapReply *rep) -{ - unsigned i,len,nBhvr; - XkbBehavior * bhv; - - if (((rep->present&XkbKeyBehaviorsMask)==0)||(rep->nKeyBehaviors<1)|| - (!xkb)||(!xkb->server)||(!xkb->server->behaviors)) { - rep->present&= ~XkbKeyBehaviorsMask; - rep->firstKeyBehavior= rep->nKeyBehaviors= 0; - rep->totalKeyBehaviors= 0; - return 0; - } - bhv= &xkb->server->behaviors[rep->firstKeyBehavior]; - for (nBhvr=i=0;i<rep->nKeyBehaviors;i++,bhv++) { - if (bhv->type!=XkbKB_Default) - nBhvr++; - } - len= nBhvr*SIZEOF(xkbBehaviorWireDesc); - rep->totalKeyBehaviors= nBhvr; - return len; -} - -static char * -XkbWriteKeyBehaviors(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf, - ClientPtr client) -{ - unsigned i; - xkbBehaviorWireDesc *wire; - XkbBehavior *pBhvr; - - wire = (xkbBehaviorWireDesc *)buf; - pBhvr= &xkb->server->behaviors[rep->firstKeyBehavior]; - for (i=0;i<rep->nKeyBehaviors;i++,pBhvr++) { - if (pBhvr->type!=XkbKB_Default) { - wire->key= i+rep->firstKeyBehavior; - wire->type= pBhvr->type; - wire->data= pBhvr->data; - wire++; - } - } - buf = (char *)wire; - return buf; -} - -static int -XkbSizeExplicit(XkbDescPtr xkb,xkbGetMapReply *rep) -{ - unsigned i,len,nRtrn; - - if (((rep->present&XkbExplicitComponentsMask)==0)||(rep->nKeyExplicit<1)|| - (!xkb)||(!xkb->server)||(!xkb->server->explicit)) { - rep->present&= ~XkbExplicitComponentsMask; - rep->firstKeyExplicit= rep->nKeyExplicit= 0; - rep->totalKeyExplicit= 0; - return 0; - } - for (nRtrn=i=0;i<rep->nKeyExplicit;i++) { - if (xkb->server->explicit[i+rep->firstKeyExplicit]!=0) - nRtrn++; - } - rep->totalKeyExplicit= nRtrn; - len= XkbPaddedSize(nRtrn*2); /* two bytes per non-zero explicit component */ - return len; -} - -static char * -XkbWriteExplicit(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf,ClientPtr client) -{ -unsigned i; -char * start; -unsigned char * pExp; - - start= buf; - pExp= &xkb->server->explicit[rep->firstKeyExplicit]; - for (i=0;i<rep->nKeyExplicit;i++,pExp++) { - if (*pExp!=0) { - *buf++= i+rep->firstKeyExplicit; - *buf++= *pExp; - } - } - i= XkbPaddedSize(buf-start)-(buf-start); /* pad to word boundary */ - return buf+i; -} - -static int -XkbSizeModifierMap(XkbDescPtr xkb,xkbGetMapReply *rep) -{ - unsigned i,len,nRtrn; - - if (((rep->present&XkbModifierMapMask)==0)||(rep->nModMapKeys<1)|| - (!xkb)||(!xkb->map)||(!xkb->map->modmap)) { - rep->present&= ~XkbModifierMapMask; - rep->firstModMapKey= rep->nModMapKeys= 0; - rep->totalModMapKeys= 0; - return 0; - } - for (nRtrn=i=0;i<rep->nModMapKeys;i++) { - if (xkb->map->modmap[i+rep->firstModMapKey]!=0) - nRtrn++; - } - rep->totalModMapKeys= nRtrn; - len= XkbPaddedSize(nRtrn*2); /* two bytes per non-zero modmap component */ - return len; -} - -static char * -XkbWriteModifierMap(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf, - ClientPtr client) -{ -unsigned i; -char * start; -unsigned char * pMap; - - start= buf; - pMap= &xkb->map->modmap[rep->firstModMapKey]; - for (i=0;i<rep->nModMapKeys;i++,pMap++) { - if (*pMap!=0) { - *buf++= i+rep->firstModMapKey; - *buf++= *pMap; - } - } - i= XkbPaddedSize(buf-start)-(buf-start); /* pad to word boundary */ - return buf+i; -} - -static int -XkbSizeVirtualModMap(XkbDescPtr xkb,xkbGetMapReply *rep) -{ - unsigned i,len,nRtrn; - - if (((rep->present&XkbVirtualModMapMask)==0)||(rep->nVModMapKeys<1)|| - (!xkb)||(!xkb->server)||(!xkb->server->vmodmap)) { - rep->present&= ~XkbVirtualModMapMask; - rep->firstVModMapKey= rep->nVModMapKeys= 0; - rep->totalVModMapKeys= 0; - return 0; - } - for (nRtrn=i=0;i<rep->nVModMapKeys;i++) { - if (xkb->server->vmodmap[i+rep->firstVModMapKey]!=0) - nRtrn++; - } - rep->totalVModMapKeys= nRtrn; - len= nRtrn*SIZEOF(xkbVModMapWireDesc); - return len; -} - -static char * -XkbWriteVirtualModMap(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf, - ClientPtr client) -{ -unsigned i; -xkbVModMapWireDesc * wire; -unsigned short * pMap; - - wire= (xkbVModMapWireDesc *)buf; - pMap= &xkb->server->vmodmap[rep->firstVModMapKey]; - for (i=0;i<rep->nVModMapKeys;i++,pMap++) { - if (*pMap!=0) { - wire->key= i+rep->firstVModMapKey; - wire->vmods= *pMap; - wire++; - } - } - return (char *)wire; -} - -static Status -XkbComputeGetMapReplySize(XkbDescPtr xkb,xkbGetMapReply *rep) -{ -int len; - - rep->minKeyCode= xkb->min_key_code; - rep->maxKeyCode= xkb->max_key_code; - len= XkbSizeKeyTypes(xkb,rep); - len+= XkbSizeKeySyms(xkb,rep); - len+= XkbSizeKeyActions(xkb,rep); - len+= XkbSizeKeyBehaviors(xkb,rep); - len+= XkbSizeVirtualMods(xkb,rep); - len+= XkbSizeExplicit(xkb,rep); - len+= XkbSizeModifierMap(xkb,rep); - len+= XkbSizeVirtualModMap(xkb,rep); - rep->length+= (len/4); - return Success; -} - -static int -XkbSendMap(ClientPtr client,XkbDescPtr xkb,xkbGetMapReply *rep) -{ -unsigned i,len; -char *desc,*start; - - len= (rep->length*4)-(SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply)); - start= desc= xcalloc(1, len); - if (!start) - return BadAlloc; - if ( rep->nTypes>0 ) - desc = XkbWriteKeyTypes(xkb,rep,desc,client); - if ( rep->nKeySyms>0 ) - desc = XkbWriteKeySyms(xkb,rep,desc,client); - if ( rep->nKeyActs>0 ) - desc = XkbWriteKeyActions(xkb,rep,desc,client); - if ( rep->totalKeyBehaviors>0 ) - desc = XkbWriteKeyBehaviors(xkb,rep,desc,client); - if ( rep->virtualMods ) { - register int sz,bit; - for (i=sz=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - if (rep->virtualMods&bit) { - desc[sz++]= xkb->server->vmods[i]; - } - } - desc+= XkbPaddedSize(sz); - } - if ( rep->totalKeyExplicit>0 ) - desc= XkbWriteExplicit(xkb,rep,desc,client); - if ( rep->totalModMapKeys>0 ) - desc= XkbWriteModifierMap(xkb,rep,desc,client); - if ( rep->totalVModMapKeys>0 ) - desc= XkbWriteVirtualModMap(xkb,rep,desc,client); - if ((desc-start)!=(len)) { - ErrorF("[xkb] BOGUS LENGTH in write keyboard desc, expected %d, got %ld\n", - len, (unsigned long)(desc-start)); - } - if (client->swapped) { - register int n; - swaps(&rep->sequenceNumber,n); - swapl(&rep->length,n); - swaps(&rep->present,n); - swaps(&rep->totalSyms,n); - swaps(&rep->totalActs,n); - } - WriteToClient(client, (i=SIZEOF(xkbGetMapReply)), (char *)rep); - WriteToClient(client, len, start); - xfree((char *)start); - return client->noClientException; -} - -int -ProcXkbGetMap(ClientPtr client) -{ - DeviceIntPtr dev; - xkbGetMapReply rep; - XkbDescRec *xkb; - int n,status; - - REQUEST(xkbGetMapReq); - REQUEST_SIZE_MATCH(xkbGetMapReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); - CHK_MASK_OVERLAP(0x01,stuff->full,stuff->partial); - CHK_MASK_LEGAL(0x02,stuff->full,XkbAllMapComponentsMask); - CHK_MASK_LEGAL(0x03,stuff->partial,XkbAllMapComponentsMask); - - xkb= dev->key->xkbInfo->desc; - bzero(&rep,sizeof(xkbGetMapReply)); - rep.type= X_Reply; - rep.sequenceNumber= client->sequence; - rep.length = (SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply))>>2; - rep.deviceID = dev->id; - rep.present = stuff->partial|stuff->full; - rep.minKeyCode = xkb->min_key_code; - rep.maxKeyCode = xkb->max_key_code; - if ( stuff->full&XkbKeyTypesMask ) { - rep.firstType = 0; - rep.nTypes = xkb->map->num_types; - } - else if (stuff->partial&XkbKeyTypesMask) { - if (((unsigned)stuff->firstType+stuff->nTypes)>xkb->map->num_types) { - client->errorValue = _XkbErrCode4(0x04,xkb->map->num_types, - stuff->firstType,stuff->nTypes); - return BadValue; - } - rep.firstType = stuff->firstType; - rep.nTypes = stuff->nTypes; - } - else rep.nTypes = 0; - rep.totalTypes = xkb->map->num_types; - - n= XkbNumKeys(xkb); - if ( stuff->full&XkbKeySymsMask ) { - rep.firstKeySym = xkb->min_key_code; - rep.nKeySyms = n; - } - else if (stuff->partial&XkbKeySymsMask) { - CHK_KEY_RANGE(0x05,stuff->firstKeySym,stuff->nKeySyms,xkb); - rep.firstKeySym = stuff->firstKeySym; - rep.nKeySyms = stuff->nKeySyms; - } - else rep.nKeySyms = 0; - rep.totalSyms= 0; - - if ( stuff->full&XkbKeyActionsMask ) { - rep.firstKeyAct= xkb->min_key_code; - rep.nKeyActs= n; - } - else if (stuff->partial&XkbKeyActionsMask) { - CHK_KEY_RANGE(0x07,stuff->firstKeyAct,stuff->nKeyActs,xkb); - rep.firstKeyAct= stuff->firstKeyAct; - rep.nKeyActs= stuff->nKeyActs; - } - else rep.nKeyActs= 0; - rep.totalActs= 0; - - if ( stuff->full&XkbKeyBehaviorsMask ) { - rep.firstKeyBehavior = xkb->min_key_code; - rep.nKeyBehaviors = n; - } - else if (stuff->partial&XkbKeyBehaviorsMask) { - CHK_KEY_RANGE(0x09,stuff->firstKeyBehavior,stuff->nKeyBehaviors,xkb); - rep.firstKeyBehavior= stuff->firstKeyBehavior; - rep.nKeyBehaviors= stuff->nKeyBehaviors; - } - else rep.nKeyBehaviors = 0; - rep.totalKeyBehaviors= 0; - - if (stuff->full&XkbVirtualModsMask) - rep.virtualMods= ~0; - else if (stuff->partial&XkbVirtualModsMask) - rep.virtualMods= stuff->virtualMods; - - if (stuff->full&XkbExplicitComponentsMask) { - rep.firstKeyExplicit= xkb->min_key_code; - rep.nKeyExplicit= n; - } - else if (stuff->partial&XkbExplicitComponentsMask) { - CHK_KEY_RANGE(0x0B,stuff->firstKeyExplicit,stuff->nKeyExplicit,xkb); - rep.firstKeyExplicit= stuff->firstKeyExplicit; - rep.nKeyExplicit= stuff->nKeyExplicit; - } - else rep.nKeyExplicit = 0; - rep.totalKeyExplicit= 0; - - if (stuff->full&XkbModifierMapMask) { - rep.firstModMapKey= xkb->min_key_code; - rep.nModMapKeys= n; - } - else if (stuff->partial&XkbModifierMapMask) { - CHK_KEY_RANGE(0x0D,stuff->firstModMapKey,stuff->nModMapKeys,xkb); - rep.firstModMapKey= stuff->firstModMapKey; - rep.nModMapKeys= stuff->nModMapKeys; - } - else rep.nModMapKeys = 0; - rep.totalModMapKeys= 0; - - if (stuff->full&XkbVirtualModMapMask) { - rep.firstVModMapKey= xkb->min_key_code; - rep.nVModMapKeys= n; - } - else if (stuff->partial&XkbVirtualModMapMask) { - CHK_KEY_RANGE(0x0F,stuff->firstVModMapKey,stuff->nVModMapKeys,xkb); - rep.firstVModMapKey= stuff->firstVModMapKey; - rep.nVModMapKeys= stuff->nVModMapKeys; - } - else rep.nVModMapKeys = 0; - rep.totalVModMapKeys= 0; - - if ((status=XkbComputeGetMapReplySize(xkb,&rep))!=Success) - return status; - return XkbSendMap(client,xkb,&rep); -} - -/***====================================================================***/ - -static int -CheckKeyTypes( ClientPtr client, - XkbDescPtr xkb, - xkbSetMapReq * req, - xkbKeyTypeWireDesc **wireRtrn, - int * nMapsRtrn, - CARD8 * mapWidthRtrn) -{ -unsigned nMaps; -register unsigned i,n; -register CARD8 * map; -register xkbKeyTypeWireDesc *wire = *wireRtrn; - - if (req->firstType>((unsigned)xkb->map->num_types)) { - *nMapsRtrn = _XkbErrCode3(0x01,req->firstType,xkb->map->num_types); - return 0; - } - if (req->flags&XkbSetMapResizeTypes) { - nMaps = req->firstType+req->nTypes; - if (nMaps<XkbNumRequiredTypes) { /* canonical types must be there */ - *nMapsRtrn= _XkbErrCode4(0x02,req->firstType,req->nTypes,4); - return 0; - } - } - else if (req->present&XkbKeyTypesMask) { - nMaps = xkb->map->num_types; - if ((req->firstType+req->nTypes)>nMaps) { - *nMapsRtrn = req->firstType+req->nTypes; - return 0; - } - } - else { - *nMapsRtrn = xkb->map->num_types; - for (i=0;i<xkb->map->num_types;i++) { - mapWidthRtrn[i] = xkb->map->types[i].num_levels; - } - return 1; - } - - for (i=0;i<req->firstType;i++) { - mapWidthRtrn[i] = xkb->map->types[i].num_levels; - } - for (i=0;i<req->nTypes;i++) { - unsigned width; - if (client->swapped) { - register int s; - swaps(&wire->virtualMods,s); - } - n= i+req->firstType; - width= wire->numLevels; - if (width<1) { - *nMapsRtrn= _XkbErrCode3(0x04,n,width); - return 0; - } - else if ((n==XkbOneLevelIndex)&&(width!=1)) { /* must be width 1 */ - *nMapsRtrn= _XkbErrCode3(0x05,n,width); - return 0; - } - else if ((width!=2)&& - ((n==XkbTwoLevelIndex)||(n==XkbKeypadIndex)|| - (n==XkbAlphabeticIndex))) { - /* TWO_LEVEL, ALPHABETIC and KEYPAD must be width 2 */ - *nMapsRtrn= _XkbErrCode3(0x05,n,width); - return 0; - } - if (wire->nMapEntries>0) { - xkbKTSetMapEntryWireDesc * mapWire; - xkbModsWireDesc * preWire; - mapWire= (xkbKTSetMapEntryWireDesc *)&wire[1]; - preWire= (xkbModsWireDesc *)&mapWire[wire->nMapEntries]; - for (n=0;n<wire->nMapEntries;n++) { - if (client->swapped) { - register int s; - swaps(&mapWire[n].virtualMods,s); - } - if (mapWire[n].realMods&(~wire->realMods)) { - *nMapsRtrn= _XkbErrCode4(0x06,n,mapWire[n].realMods, - wire->realMods); - return 0; - } - if (mapWire[n].virtualMods&(~wire->virtualMods)) { - *nMapsRtrn= _XkbErrCode3(0x07,n,mapWire[n].virtualMods); - return 0; - } - if (mapWire[n].level>=wire->numLevels) { - *nMapsRtrn= _XkbErrCode4(0x08,n,wire->numLevels, - mapWire[n].level); - return 0; - } - if (wire->preserve) { - if (client->swapped) { - register int s; - swaps(&preWire[n].virtualMods,s); - } - if (preWire[n].realMods&(~mapWire[n].realMods)) { - *nMapsRtrn= _XkbErrCode4(0x09,n,preWire[n].realMods, - mapWire[n].realMods); - return 0; - } - if (preWire[n].virtualMods&(~mapWire[n].virtualMods)) { - *nMapsRtrn=_XkbErrCode3(0x0a,n,preWire[n].virtualMods); - return 0; - } - } - } - if (wire->preserve) - map= (CARD8 *)&preWire[wire->nMapEntries]; - else map= (CARD8 *)&mapWire[wire->nMapEntries]; - } - else map= (CARD8 *)&wire[1]; - mapWidthRtrn[i+req->firstType] = wire->numLevels; - wire= (xkbKeyTypeWireDesc *)map; - } - for (i=req->firstType+req->nTypes;i<nMaps;i++) { - mapWidthRtrn[i] = xkb->map->types[i].num_levels; - } - *nMapsRtrn = nMaps; - *wireRtrn = wire; - return 1; -} - -static int -CheckKeySyms( ClientPtr client, - XkbDescPtr xkb, - xkbSetMapReq * req, - int nTypes, - CARD8 * mapWidths, - CARD16 * symsPerKey, - xkbSymMapWireDesc ** wireRtrn, - int * errorRtrn) -{ -register unsigned i; -XkbSymMapPtr map; -xkbSymMapWireDesc* wire = *wireRtrn; - - if (!(XkbKeySymsMask&req->present)) - return 1; - CHK_REQ_KEY_RANGE2(0x11,req->firstKeySym,req->nKeySyms,req,(*errorRtrn),0); - map = &xkb->map->key_sym_map[xkb->min_key_code]; - for (i=xkb->min_key_code;i<(unsigned)req->firstKeySym;i++,map++) { - register int g,ng,w; - ng= XkbNumGroups(map->group_info); - for (w=g=0;g<ng;g++) { - if (map->kt_index[g]>=(unsigned)nTypes) { - *errorRtrn = _XkbErrCode4(0x13,i,g,map->kt_index[g]); - return 0; - } - if (mapWidths[map->kt_index[g]]>w) - w= mapWidths[map->kt_index[g]]; - } - symsPerKey[i] = w*ng; - } - for (i=0;i<req->nKeySyms;i++) { - KeySym *pSyms; - register unsigned nG; - if (client->swapped) { - swaps(&wire->nSyms,nG); - } - nG = XkbNumGroups(wire->groupInfo); - if (nG>XkbNumKbdGroups) { - *errorRtrn = _XkbErrCode3(0x14,i+req->firstKeySym,nG); - return 0; - } - if (nG>0) { - register int g,w; - for (g=w=0;g<nG;g++) { - if (wire->ktIndex[g]>=(unsigned)nTypes) { - *errorRtrn= _XkbErrCode4(0x15,i+req->firstKeySym,g, - wire->ktIndex[g]); - return 0; - } - if (mapWidths[wire->ktIndex[g]]>w) - w= mapWidths[wire->ktIndex[g]]; - } - if (wire->width!=w) { - *errorRtrn= _XkbErrCode3(0x16,i+req->firstKeySym,wire->width); - return 0; - } - w*= nG; - symsPerKey[i+req->firstKeySym] = w; - if (w!=wire->nSyms) { - *errorRtrn=_XkbErrCode4(0x16,i+req->firstKeySym,wire->nSyms,w); - return 0; - } - } - else if (wire->nSyms!=0) { - *errorRtrn = _XkbErrCode3(0x17,i+req->firstKeySym,wire->nSyms); - return 0; - } - pSyms = (KeySym *)&wire[1]; - wire = (xkbSymMapWireDesc *)&pSyms[wire->nSyms]; - } - - map = &xkb->map->key_sym_map[i]; - for (;i<=(unsigned)xkb->max_key_code;i++,map++) { - register int g,nG,w; - nG= XkbKeyNumGroups(xkb,i); - for (w=g=0;g<nG;g++) { - if (map->kt_index[g]>=(unsigned)nTypes) { - *errorRtrn = _XkbErrCode4(0x18,i,g,map->kt_index[g]); - return 0; - } - if (mapWidths[map->kt_index[g]]>w) - w= mapWidths[map->kt_index[g]]; - } - symsPerKey[i] = w*nG; - } - *wireRtrn = wire; - return 1; -} - -static int -CheckKeyActions( XkbDescPtr xkb, - xkbSetMapReq * req, - int nTypes, - CARD8 * mapWidths, - CARD16 * symsPerKey, - CARD8 ** wireRtrn, - int * nActsRtrn) -{ -int nActs; -CARD8 * wire = *wireRtrn; -register unsigned i; - - if (!(XkbKeyActionsMask&req->present)) - return 1; - CHK_REQ_KEY_RANGE2(0x21,req->firstKeyAct,req->nKeyActs,req,(*nActsRtrn),0); - for (nActs=i=0;i<req->nKeyActs;i++) { - if (wire[0]!=0) { - if (wire[0]==symsPerKey[i+req->firstKeyAct]) - nActs+= wire[0]; - else { - *nActsRtrn= _XkbErrCode3(0x23,i+req->firstKeyAct,wire[0]); - return 0; - } - } - wire++; - } - if (req->nKeyActs%4) - wire+= 4-(req->nKeyActs%4); - *wireRtrn = (CARD8 *)(((XkbAnyAction *)wire)+nActs); - *nActsRtrn = nActs; - return 1; -} - -static int -CheckKeyBehaviors( XkbDescPtr xkb, - xkbSetMapReq * req, - xkbBehaviorWireDesc ** wireRtrn, - int * errorRtrn) -{ -register xkbBehaviorWireDesc * wire = *wireRtrn; -register XkbServerMapPtr server = xkb->server; -register unsigned i; -unsigned first,last; - - if (((req->present&XkbKeyBehaviorsMask)==0)||(req->nKeyBehaviors<1)) { - req->present&= ~XkbKeyBehaviorsMask; - req->nKeyBehaviors= 0; - return 1; - } - first= req->firstKeyBehavior; - last= req->firstKeyBehavior+req->nKeyBehaviors-1; - if (first<req->minKeyCode) { - *errorRtrn = _XkbErrCode3(0x31,first,req->minKeyCode); - return 0; - } - if (last>req->maxKeyCode) { - *errorRtrn = _XkbErrCode3(0x32,last,req->maxKeyCode); - return 0; - } - - for (i=0;i<req->totalKeyBehaviors;i++,wire++) { - if ((wire->key<first)||(wire->key>last)) { - *errorRtrn = _XkbErrCode4(0x33,first,last,wire->key); - return 0; - } - if ((wire->type&XkbKB_Permanent)&& - ((server->behaviors[wire->key].type!=wire->type)|| - (server->behaviors[wire->key].data!=wire->data))) { - *errorRtrn = _XkbErrCode3(0x33,wire->key,wire->type); - return 0; - } - if ((wire->type==XkbKB_RadioGroup)&& - ((wire->data&(~XkbKB_RGAllowNone))>XkbMaxRadioGroups)) { - *errorRtrn= _XkbErrCode4(0x34,wire->key,wire->data, - XkbMaxRadioGroups); - return 0; - } - if ((wire->type==XkbKB_Overlay1)||(wire->type==XkbKB_Overlay2)) { - CHK_KEY_RANGE2(0x35,wire->key,1,xkb,*errorRtrn,0); - } - } - *wireRtrn = wire; - return 1; -} - -static int -CheckVirtualMods( XkbDescRec * xkb, - xkbSetMapReq * req, - CARD8 ** wireRtrn, - int * errorRtrn) -{ -register CARD8 *wire = *wireRtrn; -register unsigned i,nMods,bit; - - if (((req->present&XkbVirtualModsMask)==0)||(req->virtualMods==0)) - return 1; - for (i=nMods=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - if (req->virtualMods&bit) - nMods++; - } - *wireRtrn= (wire+XkbPaddedSize(nMods)); - return 1; -} - -static int -CheckKeyExplicit( XkbDescPtr xkb, - xkbSetMapReq * req, - CARD8 ** wireRtrn, - int * errorRtrn) -{ -register CARD8 * wire = *wireRtrn; -CARD8 * start; -register unsigned i; -int first,last; - - if (((req->present&XkbExplicitComponentsMask)==0)||(req->nKeyExplicit<1)) { - req->present&= ~XkbExplicitComponentsMask; - req->nKeyExplicit= 0; - return 1; - } - first= req->firstKeyExplicit; - last= first+req->nKeyExplicit-1; - if (first<req->minKeyCode) { - *errorRtrn = _XkbErrCode3(0x51,first,req->minKeyCode); - return 0; - } - if (last>req->maxKeyCode) { - *errorRtrn = _XkbErrCode3(0x52,last,req->maxKeyCode); - return 0; - } - start= wire; - for (i=0;i<req->totalKeyExplicit;i++,wire+=2) { - if ((wire[0]<first)||(wire[0]>last)) { - *errorRtrn = _XkbErrCode4(0x53,first,last,wire[0]); - return 0; - } - if (wire[1]&(~XkbAllExplicitMask)) { - *errorRtrn= _XkbErrCode3(0x52,~XkbAllExplicitMask,wire[1]); - return 0; - } - } - wire+= XkbPaddedSize(wire-start)-(wire-start); - *wireRtrn= wire; - return 1; -} - -static int -CheckModifierMap(XkbDescPtr xkb,xkbSetMapReq *req,CARD8 **wireRtrn,int *errRtrn) -{ -register CARD8 * wire = *wireRtrn; -CARD8 * start; -register unsigned i; -int first,last; - - if (((req->present&XkbModifierMapMask)==0)||(req->nModMapKeys<1)) { - req->present&= ~XkbModifierMapMask; - req->nModMapKeys= 0; - return 1; - } - first= req->firstModMapKey; - last= first+req->nModMapKeys-1; - if (first<req->minKeyCode) { - *errRtrn = _XkbErrCode3(0x61,first,req->minKeyCode); - return 0; - } - if (last>req->maxKeyCode) { - *errRtrn = _XkbErrCode3(0x62,last,req->maxKeyCode); - return 0; - } - start= wire; - for (i=0;i<req->totalModMapKeys;i++,wire+=2) { - if ((wire[0]<first)||(wire[0]>last)) { - *errRtrn = _XkbErrCode4(0x63,first,last,wire[0]); - return 0; - } - } - wire+= XkbPaddedSize(wire-start)-(wire-start); - *wireRtrn= wire; - return 1; -} - -static int -CheckVirtualModMap( XkbDescPtr xkb, - xkbSetMapReq *req, - xkbVModMapWireDesc **wireRtrn, - int *errRtrn) -{ -register xkbVModMapWireDesc * wire = *wireRtrn; -register unsigned i; -int first,last; - - if (((req->present&XkbVirtualModMapMask)==0)||(req->nVModMapKeys<1)) { - req->present&= ~XkbVirtualModMapMask; - req->nVModMapKeys= 0; - return 1; - } - first= req->firstVModMapKey; - last= first+req->nVModMapKeys-1; - if (first<req->minKeyCode) { - *errRtrn = _XkbErrCode3(0x71,first,req->minKeyCode); - return 0; - } - if (last>req->maxKeyCode) { - *errRtrn = _XkbErrCode3(0x72,last,req->maxKeyCode); - return 0; - } - for (i=0;i<req->totalVModMapKeys;i++,wire++) { - if ((wire->key<first)||(wire->key>last)) { - *errRtrn = _XkbErrCode4(0x73,first,last,wire->key); - return 0; - } - } - *wireRtrn= wire; - return 1; -} - -static char * -SetKeyTypes( XkbDescPtr xkb, - xkbSetMapReq * req, - xkbKeyTypeWireDesc * wire, - XkbChangesPtr changes) -{ -register unsigned i; -unsigned first,last; -CARD8 *map; - - if ((unsigned)(req->firstType+req->nTypes)>xkb->map->size_types) { - i= req->firstType+req->nTypes; - if (XkbAllocClientMap(xkb,XkbKeyTypesMask,i)!=Success) { - return NULL; - } - } - if ((unsigned)(req->firstType+req->nTypes)>xkb->map->num_types) - xkb->map->num_types= req->firstType+req->nTypes; - - for (i=0;i<req->nTypes;i++) { - XkbKeyTypePtr pOld; - register unsigned n; - - if (XkbResizeKeyType(xkb,i+req->firstType,wire->nMapEntries, - wire->preserve,wire->numLevels)!=Success) { - return NULL; - } - pOld = &xkb->map->types[i+req->firstType]; - map = (CARD8 *)&wire[1]; - - pOld->mods.real_mods = wire->realMods; - pOld->mods.vmods= wire->virtualMods; - pOld->num_levels = wire->numLevels; - pOld->map_count= wire->nMapEntries; - - pOld->mods.mask= pOld->mods.real_mods| - XkbMaskForVMask(xkb,pOld->mods.vmods); - - if (wire->nMapEntries) { - xkbKTSetMapEntryWireDesc *mapWire; - xkbModsWireDesc *preWire; - unsigned tmp; - mapWire= (xkbKTSetMapEntryWireDesc *)map; - preWire= (xkbModsWireDesc *)&mapWire[wire->nMapEntries]; - for (n=0;n<wire->nMapEntries;n++) { - pOld->map[n].active= 1; - pOld->map[n].mods.mask= mapWire[n].realMods; - pOld->map[n].mods.real_mods= mapWire[n].realMods; - pOld->map[n].mods.vmods= mapWire[n].virtualMods; - pOld->map[n].level= mapWire[n].level; - if (mapWire[n].virtualMods!=0) { - tmp= XkbMaskForVMask(xkb,mapWire[n].virtualMods); - pOld->map[n].active= (tmp!=0); - pOld->map[n].mods.mask|= tmp; - } - if (wire->preserve) { - pOld->preserve[n].real_mods= preWire[n].realMods; - pOld->preserve[n].vmods= preWire[n].virtualMods; - tmp= XkbMaskForVMask(xkb,preWire[n].virtualMods); - pOld->preserve[n].mask= preWire[n].realMods|tmp; - } - } - if (wire->preserve) - map= (CARD8 *)&preWire[wire->nMapEntries]; - else map= (CARD8 *)&mapWire[wire->nMapEntries]; - } - else map= (CARD8 *)&wire[1]; - wire = (xkbKeyTypeWireDesc *)map; - } - first= req->firstType; - last= first+req->nTypes-1; /* last changed type */ - if (changes->map.changed&XkbKeyTypesMask) { - int oldLast; - oldLast= changes->map.first_type+changes->map.num_types-1; - if (changes->map.first_type<first) - first= changes->map.first_type; - if (oldLast>last) - last= oldLast; - } - changes->map.changed|= XkbKeyTypesMask; - changes->map.first_type = first; - changes->map.num_types = (last-first)+1; - return (char *)wire; -} - -static char * -SetKeySyms( ClientPtr client, - XkbDescPtr xkb, - xkbSetMapReq * req, - xkbSymMapWireDesc * wire, - XkbChangesPtr changes, - DeviceIntPtr dev) -{ -register unsigned i,s; -XkbSymMapPtr oldMap; -KeySym * newSyms; -KeySym * pSyms; -unsigned first,last; - - oldMap = &xkb->map->key_sym_map[req->firstKeySym]; - for (i=0;i<req->nKeySyms;i++,oldMap++) { - pSyms = (KeySym *)&wire[1]; - if (wire->nSyms>0) { - newSyms = XkbResizeKeySyms(xkb,i+req->firstKeySym,wire->nSyms); - for (s=0;s<wire->nSyms;s++) { - newSyms[s]= pSyms[s]; - } - if (client->swapped) { - int n; - for (s=0;s<wire->nSyms;s++) { - swapl(&newSyms[s],n); - } - } - } - oldMap->kt_index[0] = wire->ktIndex[0]; - oldMap->kt_index[1] = wire->ktIndex[1]; - oldMap->kt_index[2] = wire->ktIndex[2]; - oldMap->kt_index[3] = wire->ktIndex[3]; - oldMap->group_info = wire->groupInfo; - oldMap->width = wire->width; - wire= (xkbSymMapWireDesc *)&pSyms[wire->nSyms]; - } - first= req->firstKeySym; - last= first+req->nKeySyms-1; - if (changes->map.changed&XkbKeySymsMask) { - int oldLast= (changes->map.first_key_sym+changes->map.num_key_syms-1); - if (changes->map.first_key_sym<first) - first= changes->map.first_key_sym; - if (oldLast>last) - last= oldLast; - } - changes->map.changed|= XkbKeySymsMask; - changes->map.first_key_sym = first; - changes->map.num_key_syms = (last-first+1); - - s= 0; - for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { - if (XkbKeyNumGroups(xkb,i)>s) - s= XkbKeyNumGroups(xkb,i); - } - if (s!=xkb->ctrls->num_groups) { - xkbControlsNotify cn; - XkbControlsRec old; - cn.keycode= 0; - cn.eventType= 0; - cn.requestMajor= XkbReqCode; - cn.requestMinor= X_kbSetMap; - old= *xkb->ctrls; - xkb->ctrls->num_groups= s; - if (XkbComputeControlsNotify(dev,&old,xkb->ctrls,&cn,FALSE)) - XkbSendControlsNotify(dev,&cn); - } - return (char *)wire; -} - -static char * -SetKeyActions( XkbDescPtr xkb, - xkbSetMapReq * req, - CARD8 * wire, - XkbChangesPtr changes) -{ -register unsigned i,first,last; -CARD8 * nActs = wire; -XkbAction * newActs; - - wire+= XkbPaddedSize(req->nKeyActs); - for (i=0;i<req->nKeyActs;i++) { - if (nActs[i]==0) - xkb->server->key_acts[i+req->firstKeyAct]= 0; - else { - newActs= XkbResizeKeyActions(xkb,i+req->firstKeyAct,nActs[i]); - memcpy((char *)newActs,(char *)wire, - nActs[i]*SIZEOF(xkbActionWireDesc)); - wire+= nActs[i]*SIZEOF(xkbActionWireDesc); - } - } - first= req->firstKeyAct; - last= (first+req->nKeyActs-1); - if (changes->map.changed&XkbKeyActionsMask) { - int oldLast; - oldLast= changes->map.first_key_act+changes->map.num_key_acts-1; - if (changes->map.first_key_act<first) - first= changes->map.first_key_act; - if (oldLast>last) - last= oldLast; - } - changes->map.changed|= XkbKeyActionsMask; - changes->map.first_key_act= first; - changes->map.num_key_acts= (last-first+1); - return (char *)wire; -} - -static char * -SetKeyBehaviors( XkbSrvInfoPtr xkbi, - xkbSetMapReq *req, - xkbBehaviorWireDesc *wire, - XkbChangesPtr changes) -{ -register unsigned i; -int maxRG = -1; -XkbDescPtr xkb = xkbi->desc; -XkbServerMapPtr server = xkb->server; -unsigned first,last; - - first= req->firstKeyBehavior; - last= req->firstKeyBehavior+req->nKeyBehaviors-1; - bzero(&server->behaviors[first],req->nKeyBehaviors*sizeof(XkbBehavior)); - for (i=0;i<req->totalKeyBehaviors;i++) { - if ((server->behaviors[wire->key].type&XkbKB_Permanent)==0) { - server->behaviors[wire->key].type= wire->type; - server->behaviors[wire->key].data= wire->data; - if ((wire->type==XkbKB_RadioGroup)&&(((int)wire->data)>maxRG)) - maxRG= wire->data + 1; - } - wire++; - } - - if (maxRG>(int)xkbi->nRadioGroups) { - int sz = maxRG*sizeof(XkbRadioGroupRec); - if (xkbi->radioGroups) - xkbi->radioGroups= xrealloc(xkbi->radioGroups,sz); - else xkbi->radioGroups= xcalloc(1, sz); - if (xkbi->radioGroups) { - if (xkbi->nRadioGroups) - bzero(&xkbi->radioGroups[xkbi->nRadioGroups], - (maxRG-xkbi->nRadioGroups)*sizeof(XkbRadioGroupRec)); - xkbi->nRadioGroups= maxRG; - } - else xkbi->nRadioGroups= 0; - /* should compute members here */ - } - if (changes->map.changed&XkbKeyBehaviorsMask) { - unsigned oldLast; - oldLast= changes->map.first_key_behavior+ - changes->map.num_key_behaviors-1; - if (changes->map.first_key_behavior<req->firstKeyBehavior) - first= changes->map.first_key_behavior; - if (oldLast>last) - last= oldLast; - } - changes->map.changed|= XkbKeyBehaviorsMask; - changes->map.first_key_behavior = first; - changes->map.num_key_behaviors = (last-first+1); - return (char *)wire; -} - -static char * -SetVirtualMods(XkbSrvInfoPtr xkbi,xkbSetMapReq *req,CARD8 *wire, - XkbChangesPtr changes) -{ -register int i,bit,nMods; -XkbServerMapPtr srv = xkbi->desc->server; - - if (((req->present&XkbVirtualModsMask)==0)||(req->virtualMods==0)) - return (char *)wire; - for (i=nMods=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - if (req->virtualMods&bit) { - if (srv->vmods[i]!=wire[nMods]) { - changes->map.changed|= XkbVirtualModsMask; - changes->map.vmods|= bit; - srv->vmods[i]= wire[nMods]; - } - nMods++; - } - } - return (char *)(wire+XkbPaddedSize(nMods)); -} - -static char * -SetKeyExplicit(XkbSrvInfoPtr xkbi,xkbSetMapReq *req,CARD8 *wire, - XkbChangesPtr changes) -{ -register unsigned i,first,last; -XkbServerMapPtr xkb = xkbi->desc->server; -CARD8 * start; - - start= wire; - first= req->firstKeyExplicit; - last= req->firstKeyExplicit+req->nKeyExplicit-1; - bzero(&xkb->explicit[first],req->nKeyExplicit); - for (i=0;i<req->totalKeyExplicit;i++,wire+= 2) { - xkb->explicit[wire[0]]= wire[1]; - } - if (first>0) { - if (changes->map.changed&XkbExplicitComponentsMask) { - int oldLast; - oldLast= changes->map.first_key_explicit+ - changes->map.num_key_explicit-1; - if (changes->map.first_key_explicit<first) - first= changes->map.first_key_explicit; - if (oldLast>last) - last= oldLast; - } - changes->map.first_key_explicit= first; - changes->map.num_key_explicit= (last-first)+1; - } - wire+= XkbPaddedSize(wire-start)-(wire-start); - return (char *)wire; -} - -static char * -SetModifierMap( XkbSrvInfoPtr xkbi, - xkbSetMapReq * req, - CARD8 * wire, - XkbChangesPtr changes) -{ -register unsigned i,first,last; -XkbClientMapPtr xkb = xkbi->desc->map; -CARD8 * start; - - start= wire; - first= req->firstModMapKey; - last= req->firstModMapKey+req->nModMapKeys-1; - bzero(&xkb->modmap[first],req->nModMapKeys); - for (i=0;i<req->totalModMapKeys;i++,wire+= 2) { - xkb->modmap[wire[0]]= wire[1]; - } - if (first>0) { - if (changes->map.changed&XkbModifierMapMask) { - int oldLast; - oldLast= changes->map.first_modmap_key+ - changes->map.num_modmap_keys-1; - if (changes->map.first_modmap_key<first) - first= changes->map.first_modmap_key; - if (oldLast>last) - last= oldLast; - } - changes->map.first_modmap_key= first; - changes->map.num_modmap_keys= (last-first)+1; - } - wire+= XkbPaddedSize(wire-start)-(wire-start); - return (char *)wire; -} - -static char * -SetVirtualModMap( XkbSrvInfoPtr xkbi, - xkbSetMapReq * req, - xkbVModMapWireDesc * wire, - XkbChangesPtr changes) -{ -register unsigned i,first,last; -XkbServerMapPtr srv = xkbi->desc->server; - - first= req->firstVModMapKey; - last= req->firstVModMapKey+req->nVModMapKeys-1; - bzero(&srv->vmodmap[first],req->nVModMapKeys*sizeof(unsigned short)); - for (i=0;i<req->totalVModMapKeys;i++,wire++) { - srv->vmodmap[wire->key]= wire->vmods; - } - if (first>0) { - if (changes->map.changed&XkbVirtualModMapMask) { - int oldLast; - oldLast= changes->map.first_vmodmap_key+ - changes->map.num_vmodmap_keys-1; - if (changes->map.first_vmodmap_key<first) - first= changes->map.first_vmodmap_key; - if (oldLast>last) - last= oldLast; - } - changes->map.first_vmodmap_key= first; - changes->map.num_vmodmap_keys= (last-first)+1; - } - return (char *)wire; -} - -/** - * Check if the given request can be applied to the given device but don't - * actually do anything.. - */ -static int -_XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq *req, char* values) -{ - XkbSrvInfoPtr xkbi; - XkbDescPtr xkb; - int error; - int nTypes = 0, nActions; - CARD8 mapWidths[XkbMaxLegalKeyCode + 1]; - CARD16 symsPerKey[XkbMaxLegalKeyCode + 1]; - - xkbi= dev->key->xkbInfo; - xkb = xkbi->desc; - - if ((xkb->min_key_code != req->minKeyCode)|| - (xkb->max_key_code != req->maxKeyCode)) { - if (client->vMajor!=1) { /* pre 1.0 versions of Xlib have a bug */ - req->minKeyCode= xkb->min_key_code; - req->maxKeyCode= xkb->max_key_code; - } - else { - if (!XkbIsLegalKeycode(req->minKeyCode)) { - client->errorValue = _XkbErrCode3(2, req->minKeyCode, req->maxKeyCode); - return BadValue; - } - if (req->minKeyCode > req->maxKeyCode) { - client->errorValue = _XkbErrCode3(3, req->minKeyCode, req->maxKeyCode); - return BadMatch; - } - } - } - - if ((req->present & XkbKeyTypesMask) && - (!CheckKeyTypes(client,xkb,req,(xkbKeyTypeWireDesc **)&values, - &nTypes,mapWidths))) { - client->errorValue = nTypes; - return BadValue; - } - if ((req->present & XkbKeySymsMask) && - (!CheckKeySyms(client,xkb,req,nTypes,mapWidths,symsPerKey, - (xkbSymMapWireDesc **)&values,&error))) { - client->errorValue = error; - return BadValue; - } - - if ((req->present & XkbKeyActionsMask) && - (!CheckKeyActions(xkb,req,nTypes,mapWidths,symsPerKey, - (CARD8 **)&values,&nActions))) { - client->errorValue = nActions; - return BadValue; - } - - if ((req->present & XkbKeyBehaviorsMask) && - (!CheckKeyBehaviors(xkb,req,(xkbBehaviorWireDesc**)&values,&error))) { - client->errorValue = error; - return BadValue; - } - - if ((req->present & XkbVirtualModsMask) && - (!CheckVirtualMods(xkb,req,(CARD8 **)&values,&error))) { - client->errorValue= error; - return BadValue; - } - if ((req->present&XkbExplicitComponentsMask) && - (!CheckKeyExplicit(xkb,req,(CARD8 **)&values,&error))) { - client->errorValue= error; - return BadValue; - } - if ((req->present&XkbModifierMapMask) && - (!CheckModifierMap(xkb,req,(CARD8 **)&values,&error))) { - client->errorValue= error; - return BadValue; - } - if ((req->present&XkbVirtualModMapMask) && - (!CheckVirtualModMap(xkb,req,(xkbVModMapWireDesc **)&values,&error))) { - client->errorValue= error; - return BadValue; - } - - if (((values-((char *)req))/4)!= req->length) { - ErrorF("[xkb] Internal error! Bad length in XkbSetMap (after check)\n"); - client->errorValue = values-((char *)&req[1]); - return BadLength; - } - - return Success; -} - -/** - * Apply the given request on the given device. - */ -static int -_XkbSetMap(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq *req, char *values) -{ - XkbEventCauseRec cause; - XkbChangesRec change; - Bool sentNKN; - XkbSrvInfoPtr xkbi; - XkbDescPtr xkb; - - xkbi= dev->key->xkbInfo; - xkb = xkbi->desc; - - XkbSetCauseXkbReq(&cause,X_kbSetMap,client); - bzero(&change, sizeof(change)); - sentNKN = FALSE; - if ((xkb->min_key_code!=req->minKeyCode)|| - (xkb->max_key_code!=req->maxKeyCode)) { - Status status; - xkbNewKeyboardNotify nkn; - nkn.deviceID = nkn.oldDeviceID = dev->id; - nkn.oldMinKeyCode = xkb->min_key_code; - nkn.oldMaxKeyCode = xkb->max_key_code; - status= XkbChangeKeycodeRange(xkb, req->minKeyCode, - req->maxKeyCode, &change); - if (status != Success) - return status; /* oh-oh. what about the other keyboards? */ - nkn.minKeyCode = xkb->min_key_code; - nkn.maxKeyCode = xkb->max_key_code; - nkn.requestMajor = XkbReqCode; - nkn.requestMinor = X_kbSetMap; - nkn.changed = XkbNKN_KeycodesMask; - XkbSendNewKeyboardNotify(dev,&nkn); - sentNKN = TRUE; - } - - if (req->present&XkbKeyTypesMask) { - values = SetKeyTypes(xkb,req,(xkbKeyTypeWireDesc *)values,&change); - if (!values) goto allocFailure; - } - if (req->present&XkbKeySymsMask) { - values = SetKeySyms(client,xkb,req,(xkbSymMapWireDesc *)values,&change,dev); - if (!values) goto allocFailure; - } - if (req->present&XkbKeyActionsMask) { - values = SetKeyActions(xkb,req,(CARD8 *)values,&change); - if (!values) goto allocFailure; - } - if (req->present&XkbKeyBehaviorsMask) { - values= SetKeyBehaviors(xkbi,req,(xkbBehaviorWireDesc *)values,&change); - if (!values) goto allocFailure; - } - if (req->present&XkbVirtualModsMask) - values= SetVirtualMods(xkbi,req,(CARD8 *)values,&change); - if (req->present&XkbExplicitComponentsMask) - values= SetKeyExplicit(xkbi,req,(CARD8 *)values,&change); - if (req->present&XkbModifierMapMask) - values= SetModifierMap(xkbi,req,(CARD8 *)values,&change); - if (req->present&XkbVirtualModMapMask) - values= SetVirtualModMap(xkbi,req,(xkbVModMapWireDesc *)values,&change); - if (((values-((char *)req))/4)!=req->length) { - ErrorF("[xkb] Internal error! Bad length in XkbSetMap (after set)\n"); - client->errorValue = values-((char *)&req[1]); - return BadLength; - } - if (req->flags&XkbSetMapRecomputeActions) { - KeyCode first,last,firstMM,lastMM; - if (change.map.num_key_syms>0) { - first= change.map.first_key_sym; - last= first+change.map.num_key_syms-1; - } - else first= last= 0; - if (change.map.num_modmap_keys>0) { - firstMM= change.map.first_modmap_key; - lastMM= first+change.map.num_modmap_keys-1; - } - else firstMM= lastMM= 0; - if ((last>0) && (lastMM>0)) { - if (firstMM<first) - first= firstMM; - if (lastMM>last) - last= lastMM; - } - else if (lastMM>0) { - first= firstMM; - last= lastMM; - } - if (last>0) { - unsigned check= 0; - XkbUpdateActions(dev,first,(last-first+1),&change,&check,&cause); - if (check) - XkbCheckSecondaryEffects(xkbi,check,&change,&cause); - } - } - if (!sentNKN) - XkbSendNotification(dev,&change,&cause); - - return Success; -allocFailure: - return BadAlloc; -} - - -int -ProcXkbSetMap(ClientPtr client) -{ - DeviceIntPtr dev; - char * tmp; - int rc; - - REQUEST(xkbSetMapReq); - REQUEST_AT_LEAST_SIZE(xkbSetMapReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); - CHK_MASK_LEGAL(0x01,stuff->present,XkbAllMapComponentsMask); - - tmp = (char *)&stuff[1]; - - /* Check if we can to the SetMap on the requested device. If this - succeeds, do the same thing for all extension devices (if needed). - If any of them fails, fail. */ - rc = _XkbSetMapChecks(client, dev, stuff, tmp); - - if (rc != Success) - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) - { - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); - if (rc == Success) - { - rc = _XkbSetMapChecks(client, other, stuff, tmp); - if (rc != Success) - return rc; - } - } - } - } - - /* We know now that we will succed with the SetMap. In theory anyway. */ - rc = _XkbSetMap(client, dev, stuff, tmp); - if (rc != Success) - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) - { - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); - if (rc == Success) - _XkbSetMap(client, other, stuff, tmp); - /* ignore rc. if the SetMap failed although the check above - reported true there isn't much we can do. we still need to - set all other devices, hoping that at least they stay in - sync. */ - } - } - } - - return client->noClientException; -} - -/***====================================================================***/ - -static Status -XkbComputeGetCompatMapReplySize( XkbCompatMapPtr compat, - xkbGetCompatMapReply * rep) -{ -unsigned size,nGroups; - - nGroups= 0; - if (rep->groups!=0) { - register int i,bit; - for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { - if (rep->groups&bit) - nGroups++; - } - } - size= nGroups*SIZEOF(xkbModsWireDesc); - size+= (rep->nSI*SIZEOF(xkbSymInterpretWireDesc)); - rep->length= size/4; - return Success; -} - -static int -XkbSendCompatMap( ClientPtr client, - XkbCompatMapPtr compat, - xkbGetCompatMapReply * rep) -{ -char * data; -int size; - - size= rep->length*4; - if (size>0) { - data = xalloc(size); - if (data) { - register unsigned i,bit; - xkbModsWireDesc * grp; - XkbSymInterpretPtr sym= &compat->sym_interpret[rep->firstSI]; - xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *)data; - for (i=0;i<rep->nSI;i++,sym++,wire++) { - wire->sym= sym->sym; - wire->mods= sym->mods; - wire->match= sym->match; - wire->virtualMod= sym->virtual_mod; - wire->flags= sym->flags; - memcpy((char*)&wire->act,(char*)&sym->act,sz_xkbActionWireDesc); - if (client->swapped) { - register int n; - swapl(&wire->sym,n); - } - } - if (rep->groups) { - grp = (xkbModsWireDesc *)wire; - for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { - if (rep->groups&bit) { - grp->mask= compat->groups[i].mask; - grp->realMods= compat->groups[i].real_mods; - grp->virtualMods= compat->groups[i].vmods; - if (client->swapped) { - register int n; - swaps(&grp->virtualMods,n); - } - grp++; - } - } - wire= (xkbSymInterpretWireDesc*)grp; - } - } - else return BadAlloc; - } - else data= NULL; - - if (client->swapped) { - register int n; - swaps(&rep->sequenceNumber,n); - swapl(&rep->length,n); - swaps(&rep->firstSI,n); - swaps(&rep->nSI,n); - swaps(&rep->nTotalSI,n); - } - - WriteToClient(client, SIZEOF(xkbGetCompatMapReply), (char *)rep); - if (data) { - WriteToClient(client, size, data); - xfree((char *)data); - } - return client->noClientException; -} - -int -ProcXkbGetCompatMap(ClientPtr client) -{ - xkbGetCompatMapReply rep; - DeviceIntPtr dev; - XkbDescPtr xkb; - XkbCompatMapPtr compat; - - REQUEST(xkbGetCompatMapReq); - REQUEST_SIZE_MATCH(xkbGetCompatMapReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); - - xkb = dev->key->xkbInfo->desc; - compat= xkb->compat; - - rep.type = X_Reply; - rep.deviceID = dev->id; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.firstSI = stuff->firstSI; - rep.nSI = stuff->nSI; - if (stuff->getAllSI) { - rep.firstSI = 0; - rep.nSI = compat->num_si; - } - else if ((((unsigned)stuff->nSI)>0)&& - ((unsigned)(stuff->firstSI+stuff->nSI-1)>=compat->num_si)) { - client->errorValue = _XkbErrCode2(0x05,compat->num_si); - return BadValue; - } - rep.nTotalSI = compat->num_si; - rep.groups= stuff->groups; - XkbComputeGetCompatMapReplySize(compat,&rep); - return XkbSendCompatMap(client,compat,&rep); -} - -/** - * Apply the given request on the given device. - * If dryRun is TRUE, then value checks are performed, but the device isn't - * modified. - */ -static int -_XkbSetCompatMap(ClientPtr client, DeviceIntPtr dev, - xkbSetCompatMapReq *req, char* data, BOOL dryRun) -{ - XkbSrvInfoPtr xkbi; - XkbDescPtr xkb; - XkbCompatMapPtr compat; - int nGroups; - unsigned i,bit; - - xkbi = dev->key->xkbInfo; - xkb = xkbi->desc; - compat = xkb->compat; - - if ((req->nSI>0)||(req->truncateSI)) { - xkbSymInterpretWireDesc *wire; - if (req->firstSI>compat->num_si) { - client->errorValue = _XkbErrCode2(0x02,compat->num_si); - return BadValue; - } - wire= (xkbSymInterpretWireDesc *)data; - wire+= req->nSI; - data = (char *)wire; - } - - nGroups= 0; - if (req->groups!=0) { - for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { - if ( req->groups&bit ) - nGroups++; - } - } - data+= nGroups*SIZEOF(xkbModsWireDesc); - if (((data-((char *)req))/4)!=req->length) { - return BadLength; - } - - /* Done all the checks we can do */ - if (dryRun) - return Success; - - data = (char *)&req[1]; - if (req->nSI>0) { - xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *)data; - XkbSymInterpretPtr sym; - if ((unsigned)(req->firstSI+req->nSI)>compat->num_si) { - compat->num_si= req->firstSI+req->nSI; - compat->sym_interpret= xrealloc(compat->sym_interpret, - compat->num_si * sizeof(XkbSymInterpretRec)); - if (!compat->sym_interpret) { - compat->num_si= 0; - return BadAlloc; - } - } - else if (req->truncateSI) { - compat->num_si = req->firstSI+req->nSI; - } - sym = &compat->sym_interpret[req->firstSI]; - for (i=0;i<req->nSI;i++,wire++,sym++) { - if (client->swapped) { - int n; - swapl(&wire->sym,n); - } - sym->sym= wire->sym; - sym->mods= wire->mods; - sym->match= wire->match; - sym->flags= wire->flags; - sym->virtual_mod= wire->virtualMod; - memcpy((char *)&sym->act,(char *)&wire->act, - SIZEOF(xkbActionWireDesc)); - } - data = (char *)wire; - } - else if (req->truncateSI) { - compat->num_si = req->firstSI; - } - - if (req->groups!=0) { - unsigned i, bit; - xkbModsWireDesc *wire = (xkbModsWireDesc *)data; - for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) { - if (req->groups & bit) { - if (client->swapped) { - int n; - swaps(&wire->virtualMods,n); - } - compat->groups[i].mask= wire->realMods; - compat->groups[i].real_mods= wire->realMods; - compat->groups[i].vmods= wire->virtualMods; - if (wire->virtualMods!=0) { - unsigned tmp; - tmp= XkbMaskForVMask(xkb,wire->virtualMods); - compat->groups[i].mask|= tmp; - } - data+= SIZEOF(xkbModsWireDesc); - wire= (xkbModsWireDesc *)data; - } - } - } - i= XkbPaddedSize((data-((char *)req))); - if ((i/4)!=req->length) { - ErrorF("[xkb] Internal length error on read in _XkbSetCompatMap\n"); - return BadLength; - } - - if (dev->xkb_interest) { - xkbCompatMapNotify ev; - ev.deviceID = dev->id; - ev.changedGroups = req->groups; - ev.firstSI = req->firstSI; - ev.nSI = req->nSI; - ev.nTotalSI = compat->num_si; - XkbSendCompatMapNotify(dev,&ev); - } - - if (req->recomputeActions) { - XkbChangesRec change; - unsigned check; - XkbEventCauseRec cause; - - XkbSetCauseXkbReq(&cause,X_kbSetCompatMap,client); - bzero(&change,sizeof(XkbChangesRec)); - XkbUpdateActions(dev,xkb->min_key_code,XkbNumKeys(xkb),&change,&check, - &cause); - if (check) - XkbCheckSecondaryEffects(xkbi,check,&change,&cause); - XkbSendNotification(dev,&change,&cause); - } - return Success; -} - -int -ProcXkbSetCompatMap(ClientPtr client) -{ - DeviceIntPtr dev; - char *data; - int rc; - - REQUEST(xkbSetCompatMapReq); - REQUEST_AT_LEAST_SIZE(xkbSetCompatMapReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); - - data = (char *)&stuff[1]; - - /* check first using a dry-run */ - rc = _XkbSetCompatMap(client, dev, stuff, data, TRUE); - if (rc != Success) - return rc; - if (stuff->deviceSpec == XkbUseCoreKbd) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) - { - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); - if (rc == Success) - { - /* dry-run */ - rc = _XkbSetCompatMap(client, other, stuff, data, TRUE); - if (rc != Success) - return rc; - } - } - } - } - - /* Yay, the dry-runs succeed. Let's apply */ - rc = _XkbSetCompatMap(client, dev, stuff, data, FALSE); - if (rc != Success) - return rc; - if (stuff->deviceSpec == XkbUseCoreKbd) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) - { - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); - if (rc == Success) - { - rc = _XkbSetCompatMap(client, other, stuff, data, FALSE); - if (rc != Success) - return rc; - } - } - } - } - - return client->noClientException; -} - -/***====================================================================***/ - -int -ProcXkbGetIndicatorState(ClientPtr client) -{ - xkbGetIndicatorStateReply rep; - XkbSrvLedInfoPtr sli; - DeviceIntPtr dev; - register int i; - - REQUEST(xkbGetIndicatorStateReq); - REQUEST_SIZE_MATCH(xkbGetIndicatorStateReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixReadAccess); - - sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId, - XkbXI_IndicatorStateMask); - if (!sli) - return BadAlloc; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.deviceID = dev->id; - rep.state = sli->effectiveState; - - if (client->swapped) { - swaps(&rep.sequenceNumber,i); - swapl(&rep.state,i); - } - WriteToClient(client, SIZEOF(xkbGetIndicatorStateReply), (char *)&rep); - return client->noClientException; -} - -/***====================================================================***/ - -static Status -XkbComputeGetIndicatorMapReplySize( - XkbIndicatorPtr indicators, - xkbGetIndicatorMapReply *rep) -{ -register int i,bit; -int nIndicators; - - rep->realIndicators = indicators->phys_indicators; - for (i=nIndicators=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { - if (rep->which&bit) - nIndicators++; - } - rep->length = (nIndicators*SIZEOF(xkbIndicatorMapWireDesc))/4; - return Success; -} - -static int -XkbSendIndicatorMap( ClientPtr client, - XkbIndicatorPtr indicators, - xkbGetIndicatorMapReply * rep) -{ -int length; -CARD8 * map; -register int i; -register unsigned bit; - - length = rep->length*4; - if (length>0) { - CARD8 *to; - to= map= xalloc(length); - if (map) { - xkbIndicatorMapWireDesc *wire = (xkbIndicatorMapWireDesc *)to; - for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { - if (rep->which&bit) { - wire->flags= indicators->maps[i].flags; - wire->whichGroups= indicators->maps[i].which_groups; - wire->groups= indicators->maps[i].groups; - wire->whichMods= indicators->maps[i].which_mods; - wire->mods= indicators->maps[i].mods.mask; - wire->realMods= indicators->maps[i].mods.real_mods; - wire->virtualMods= indicators->maps[i].mods.vmods; - wire->ctrls= indicators->maps[i].ctrls; - if (client->swapped) { - register int n; - swaps(&wire->virtualMods,n); - swapl(&wire->ctrls,n); - } - wire++; - } - } - to = (CARD8 *)wire; - if ((to-map)!=length) { - client->errorValue = _XkbErrCode2(0xff,length); - return BadLength; - } - } - else return BadAlloc; - } - else map = NULL; - if (client->swapped) { - swaps(&rep->sequenceNumber,i); - swapl(&rep->length,i); - swapl(&rep->which,i); - swapl(&rep->realIndicators,i); - } - WriteToClient(client, SIZEOF(xkbGetIndicatorMapReply), (char *)rep); - if (map) { - WriteToClient(client, length, (char *)map); - xfree((char *)map); - } - return client->noClientException; -} - -int -ProcXkbGetIndicatorMap(ClientPtr client) -{ -xkbGetIndicatorMapReply rep; -DeviceIntPtr dev; -XkbDescPtr xkb; -XkbIndicatorPtr leds; - - REQUEST(xkbGetIndicatorMapReq); - REQUEST_SIZE_MATCH(xkbGetIndicatorMapReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); - - xkb= dev->key->xkbInfo->desc; - leds= xkb->indicators; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.deviceID = dev->id; - rep.which = stuff->which; - XkbComputeGetIndicatorMapReplySize(leds,&rep); - return XkbSendIndicatorMap(client,leds,&rep); -} - -/** - * Apply the given map to the given device. Which specifies which components - * to apply. - */ -static int -_XkbSetIndicatorMap(ClientPtr client, DeviceIntPtr dev, - int which, xkbIndicatorMapWireDesc *desc) -{ - XkbSrvInfoPtr xkbi; - XkbSrvLedInfoPtr sli; - XkbEventCauseRec cause; - int i, bit; - - xkbi = dev->key->xkbInfo; - - sli= XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, - XkbXI_IndicatorMapsMask); - if (!sli) - return BadAlloc; - - for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) { - if (which & bit) { - sli->maps[i].flags = desc->flags; - sli->maps[i].which_groups = desc->whichGroups; - sli->maps[i].groups = desc->groups; - sli->maps[i].which_mods = desc->whichMods; - sli->maps[i].mods.mask = desc->mods; - sli->maps[i].mods.real_mods = desc->mods; - sli->maps[i].mods.vmods= desc->virtualMods; - sli->maps[i].ctrls = desc->ctrls; - if (desc->virtualMods!=0) { - unsigned tmp; - tmp= XkbMaskForVMask(xkbi->desc,desc->virtualMods); - sli->maps[i].mods.mask= desc->mods|tmp; - } - desc++; - } - } - - XkbSetCauseXkbReq(&cause,X_kbSetIndicatorMap,client); - XkbApplyLedMapChanges(dev,sli,which,NULL,NULL,&cause); - - return Success; -} - -int -ProcXkbSetIndicatorMap(ClientPtr client) -{ - int i, bit; - int nIndicators; - DeviceIntPtr dev; - xkbIndicatorMapWireDesc *from; - int rc; - - REQUEST(xkbSetIndicatorMapReq); - REQUEST_AT_LEAST_SIZE(xkbSetIndicatorMapReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess); - - if (stuff->which==0) - return client->noClientException; - - for (nIndicators=i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { - if (stuff->which&bit) - nIndicators++; - } - if (stuff->length!=((SIZEOF(xkbSetIndicatorMapReq)+ - (nIndicators*SIZEOF(xkbIndicatorMapWireDesc)))/4)) { - return BadLength; - } - - from = (xkbIndicatorMapWireDesc *)&stuff[1]; - for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { - if (stuff->which&bit) { - if (client->swapped) { - int n; - swaps(&from->virtualMods,n); - swapl(&from->ctrls,n); - } - CHK_MASK_LEGAL(i,from->whichGroups,XkbIM_UseAnyGroup); - CHK_MASK_LEGAL(i,from->whichMods,XkbIM_UseAnyMods); - from++; - } - } - - from = (xkbIndicatorMapWireDesc *)&stuff[1]; - rc = _XkbSetIndicatorMap(client, dev, stuff->which, from); - if (rc != Success) - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) - { - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess); - if (rc == Success) - _XkbSetIndicatorMap(client, other, stuff->which, from); - } - } - } - - return Success; -} - -/***====================================================================***/ - -int -ProcXkbGetNamedIndicator(ClientPtr client) -{ - DeviceIntPtr dev; - xkbGetNamedIndicatorReply rep; - register int i = 0; - XkbSrvLedInfoPtr sli; - XkbIndicatorMapPtr map = NULL; - - REQUEST(xkbGetNamedIndicatorReq); - REQUEST_SIZE_MATCH(xkbGetNamedIndicatorReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_LED_DEVICE(dev, stuff->deviceSpec, client, DixReadAccess); - CHK_ATOM_ONLY(stuff->indicator); - - sli= XkbFindSrvLedInfo(dev,stuff->ledClass,stuff->ledID,0); - if (!sli) - return BadAlloc; - - i= 0; - map= NULL; - if ((sli->names)&&(sli->maps)) { - for (i=0;i<XkbNumIndicators;i++) { - if (stuff->indicator==sli->names[i]) { - map= &sli->maps[i]; - break; - } - } - } - - rep.type= X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.deviceID = dev->id; - rep.indicator= stuff->indicator; - if (map!=NULL) { - rep.found= TRUE; - rep.on= ((sli->effectiveState&(1<<i))!=0); - rep.realIndicator= ((sli->physIndicators&(1<<i))!=0); - rep.ndx= i; - rep.flags= map->flags; - rep.whichGroups= map->which_groups; - rep.groups= map->groups; - rep.whichMods= map->which_mods; - rep.mods= map->mods.mask; - rep.realMods= map->mods.real_mods; - rep.virtualMods= map->mods.vmods; - rep.ctrls= map->ctrls; - rep.supported= TRUE; - } - else { - rep.found= FALSE; - rep.on= FALSE; - rep.realIndicator= FALSE; - rep.ndx= XkbNoIndicator; - rep.flags= 0; - rep.whichGroups= 0; - rep.groups= 0; - rep.whichMods= 0; - rep.mods= 0; - rep.realMods= 0; - rep.virtualMods= 0; - rep.ctrls= 0; - rep.supported= TRUE; - } - if ( client->swapped ) { - register int n; - swapl(&rep.length,n); - swaps(&rep.sequenceNumber,n); - swapl(&rep.indicator,n); - swaps(&rep.virtualMods,n); - swapl(&rep.ctrls,n); - } - - WriteToClient(client,SIZEOF(xkbGetNamedIndicatorReply), (char *)&rep); - return client->noClientException; -} - - -/** - * Find the IM on the device. - * Returns the map, or NULL if the map doesn't exist. - * If the return value is NULL, led_return is undefined. Otherwise, led_return - * is set to the led index of the map. - */ -static XkbIndicatorMapPtr -_XkbFindNamedIndicatorMap(XkbSrvLedInfoPtr sli, Atom indicator, - int *led_return) -{ - XkbIndicatorMapPtr map; - - /* search for the right indicator */ - map = NULL; - if (sli->names && sli->maps) { - int led; - - for (led = 0; (led < XkbNumIndicators) && (map == NULL); led++) { - if (sli->names[led] == indicator) { - map= &sli->maps[led]; - *led_return = led; - break; - } - } - } - - return map; -} - -/** - * Creates an indicator map on the device. If dryRun is TRUE, it only checks - * if creation is possible, but doesn't actually create it. - */ -static int -_XkbCreateIndicatorMap(DeviceIntPtr dev, Atom indicator, - int ledClass, int ledID, - XkbIndicatorMapPtr *map_return, int *led_return, - Bool dryRun) -{ - XkbSrvLedInfoPtr sli; - XkbIndicatorMapPtr map; - int led; - - sli = XkbFindSrvLedInfo(dev, ledClass, ledID, XkbXI_IndicatorsMask); - if (!sli) - return BadAlloc; - - map = _XkbFindNamedIndicatorMap(sli, indicator, &led); - - if (!map) - { - /* find first unused indicator maps and assign the name to it */ - for (led = 0, map = NULL; (led < XkbNumIndicators) && (map == NULL); led++) { - if ((sli->names) && (sli->maps) && (sli->names[led] == None) && - (!XkbIM_InUse(&sli->maps[led]))) - { - map = &sli->maps[led]; - if (!dryRun) - sli->names[led] = indicator; - break; - } - } - } - - if (!map) - return BadAlloc; - - *led_return = led; - *map_return = map; - return Success; -} - -static int -_XkbSetNamedIndicator(ClientPtr client, DeviceIntPtr dev, - xkbSetNamedIndicatorReq *stuff) -{ - unsigned int extDevReason; - unsigned int statec, namec, mapc; - XkbSrvLedInfoPtr sli; - int led = 0; - XkbIndicatorMapPtr map; - DeviceIntPtr kbd; - XkbEventCauseRec cause; - xkbExtensionDeviceNotify ed; - XkbChangesRec changes; - int rc; - - rc = _XkbCreateIndicatorMap(dev, stuff->indicator, stuff->ledClass, - stuff->ledID, &map, &led, FALSE); - if (rc != Success || !map) /* oh-oh */ - return rc; - - sli = XkbFindSrvLedInfo(dev, stuff->ledClass, stuff->ledID, - XkbXI_IndicatorsMask); - if (!sli) - return BadAlloc; - - namec = mapc = statec = 0; - extDevReason = 0; - - namec |= (1<<led); - sli->namesPresent |= ((stuff->indicator != None) ? (1 << led) : 0); - extDevReason |= XkbXI_IndicatorNamesMask; - - if (stuff->setMap) { - map->flags = stuff->flags; - map->which_groups = stuff->whichGroups; - map->groups = stuff->groups; - map->which_mods = stuff->whichMods; - map->mods.mask = stuff->realMods; - map->mods.real_mods = stuff->realMods; - map->mods.vmods= stuff->virtualMods; - map->ctrls = stuff->ctrls; - mapc|= (1<<led); - } - - if ((stuff->setState) && ((map->flags & XkbIM_NoExplicit) == 0)) - { - if (stuff->on) sli->explicitState |= (1<<led); - else sli->explicitState &= ~(1<<led); - statec |= ((sli->effectiveState ^ sli->explicitState) & (1 << led)); - } - - bzero((char *)&ed,sizeof(xkbExtensionDeviceNotify)); - bzero((char *)&changes,sizeof(XkbChangesRec)); - XkbSetCauseXkbReq(&cause,X_kbSetNamedIndicator,client); - if (namec) - XkbApplyLedNameChanges(dev,sli,namec,&ed,&changes,&cause); - if (mapc) - XkbApplyLedMapChanges(dev,sli,mapc,&ed,&changes,&cause); - if (statec) - XkbApplyLedStateChanges(dev,sli,statec,&ed,&changes,&cause); - - kbd = dev; - if ((sli->flags&XkbSLI_HasOwnState)==0) - kbd = inputInfo.keyboard; - XkbFlushLedEvents(dev, kbd, sli, &ed, &changes, &cause); - - return Success; -} - -int -ProcXkbSetNamedIndicator(ClientPtr client) -{ - int rc; - DeviceIntPtr dev; - int led = 0; - XkbIndicatorMapPtr map; - - REQUEST(xkbSetNamedIndicatorReq); - REQUEST_SIZE_MATCH(xkbSetNamedIndicatorReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_LED_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess); - CHK_ATOM_ONLY(stuff->indicator); - CHK_MASK_LEGAL(0x10,stuff->whichGroups,XkbIM_UseAnyGroup); - CHK_MASK_LEGAL(0x11,stuff->whichMods,XkbIM_UseAnyMods); - - /* Dry-run for checks */ - rc = _XkbCreateIndicatorMap(dev, stuff->indicator, - stuff->ledClass, stuff->ledID, - &map, &led, TRUE); - if (rc != Success || !map) /* couldn't be created or didn't exist */ - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd || - stuff->deviceSpec == XkbUseCorePtr) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && !IsMaster(other) && (other->u.master == dev) && - (other->kbdfeed || other->leds) && - (XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess) == Success)) - { - rc = _XkbCreateIndicatorMap(other, stuff->indicator, - stuff->ledClass, stuff->ledID, - &map, &led, TRUE); - if (rc != Success || !map) - return rc; - } - } - } - - /* All checks passed, let's do it */ - rc = _XkbSetNamedIndicator(client, dev, stuff); - if (rc != Success) - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd || - stuff->deviceSpec == XkbUseCorePtr) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && !IsMaster(other) && (other->u.master == dev) && - (other->kbdfeed || other->leds) && - (XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess) == Success)) - { - _XkbSetNamedIndicator(client, other, stuff); - } - } - } - - return client->noClientException; -} - -/***====================================================================***/ - -static CARD32 -_XkbCountAtoms(Atom *atoms,int maxAtoms,int *count) -{ -register unsigned int i,bit,nAtoms; -register CARD32 atomsPresent; - - for (i=nAtoms=atomsPresent=0,bit=1;i<maxAtoms;i++,bit<<=1) { - if (atoms[i]!=None) { - atomsPresent|= bit; - nAtoms++; - } - } - if (count) - *count= nAtoms; - return atomsPresent; -} - -static char * -_XkbWriteAtoms(char *wire,Atom *atoms,int maxAtoms,int swap) -{ -register unsigned int i; -Atom *atm; - - atm = (Atom *)wire; - for (i=0;i<maxAtoms;i++) { - if (atoms[i]!=None) { - *atm= atoms[i]; - if (swap) { - register int n; - swapl(atm,n); - } - atm++; - } - } - return (char *)atm; -} - -static Status -XkbComputeGetNamesReplySize(XkbDescPtr xkb,xkbGetNamesReply *rep) -{ -register unsigned which,length; -register int i; - - rep->minKeyCode= xkb->min_key_code; - rep->maxKeyCode= xkb->max_key_code; - which= rep->which; - length= 0; - if (xkb->names!=NULL) { - if (which&XkbKeycodesNameMask) length++; - if (which&XkbGeometryNameMask) length++; - if (which&XkbSymbolsNameMask) length++; - if (which&XkbPhysSymbolsNameMask) length++; - if (which&XkbTypesNameMask) length++; - if (which&XkbCompatNameMask) length++; - } - else which&= ~XkbComponentNamesMask; - - if (xkb->map!=NULL) { - if (which&XkbKeyTypeNamesMask) - length+= xkb->map->num_types; - rep->nTypes= xkb->map->num_types; - if (which&XkbKTLevelNamesMask) { - XkbKeyTypePtr pType = xkb->map->types; - int nKTLevels = 0; - - length+= XkbPaddedSize(xkb->map->num_types)/4; - for (i=0;i<xkb->map->num_types;i++,pType++) { - if (pType->level_names!=NULL) - nKTLevels+= pType->num_levels; - } - rep->nKTLevels= nKTLevels; - length+= nKTLevels; - } - } - else { - rep->nTypes= 0; - rep->nKTLevels= 0; - which&= ~(XkbKeyTypeNamesMask|XkbKTLevelNamesMask); - } - - rep->minKeyCode= xkb->min_key_code; - rep->maxKeyCode= xkb->max_key_code; - rep->indicators= 0; - rep->virtualMods= 0; - rep->groupNames= 0; - if (xkb->names!=NULL) { - if (which&XkbIndicatorNamesMask) { - int nLeds; - rep->indicators= - _XkbCountAtoms(xkb->names->indicators,XkbNumIndicators,&nLeds); - length+= nLeds; - if (nLeds==0) - which&= ~XkbIndicatorNamesMask; - } - - if (which&XkbVirtualModNamesMask) { - int nVMods; - rep->virtualMods= - _XkbCountAtoms(xkb->names->vmods,XkbNumVirtualMods,&nVMods); - length+= nVMods; - if (nVMods==0) - which&= ~XkbVirtualModNamesMask; - } - - if (which&XkbGroupNamesMask) { - int nGroups; - rep->groupNames= - _XkbCountAtoms(xkb->names->groups,XkbNumKbdGroups,&nGroups); - length+= nGroups; - if (nGroups==0) - which&= ~XkbGroupNamesMask; - } - - if ((which&XkbKeyNamesMask)&&(xkb->names->keys)) - length+= rep->nKeys; - else which&= ~XkbKeyNamesMask; - - if ((which&XkbKeyAliasesMask)&& - (xkb->names->key_aliases)&&(xkb->names->num_key_aliases>0)) { - rep->nKeyAliases= xkb->names->num_key_aliases; - length+= rep->nKeyAliases*2; - } - else { - which&= ~XkbKeyAliasesMask; - rep->nKeyAliases= 0; - } - - if ((which&XkbRGNamesMask)&&(xkb->names->num_rg>0)) - length+= xkb->names->num_rg; - else which&= ~XkbRGNamesMask; - } - else { - which&= ~(XkbIndicatorNamesMask|XkbVirtualModNamesMask); - which&= ~(XkbGroupNamesMask|XkbKeyNamesMask|XkbKeyAliasesMask); - which&= ~XkbRGNamesMask; - } - - rep->length= length; - rep->which= which; - return Success; -} - -static int -XkbSendNames(ClientPtr client,XkbDescPtr xkb,xkbGetNamesReply *rep) -{ -register unsigned i,length,which; -char * start; -char * desc; -register int n; - - length= rep->length*4; - which= rep->which; - if (client->swapped) { - swaps(&rep->sequenceNumber,n); - swapl(&rep->length,n); - swapl(&rep->which,n); - swaps(&rep->virtualMods,n); - swapl(&rep->indicators,n); - } - - start = desc = xalloc(length); - if ( !start ) - return BadAlloc; - if (xkb->names) { - if (which&XkbKeycodesNameMask) { - *((CARD32 *)desc)= xkb->names->keycodes; - if (client->swapped) { - swapl(desc,n); - } - desc+= 4; - } - if (which&XkbGeometryNameMask) { - *((CARD32 *)desc)= xkb->names->geometry; - if (client->swapped) { - swapl(desc,n); - } - desc+= 4; - } - if (which&XkbSymbolsNameMask) { - *((CARD32 *)desc)= xkb->names->symbols; - if (client->swapped) { - swapl(desc,n); - } - desc+= 4; - } - if (which&XkbPhysSymbolsNameMask) { - register CARD32 *atm= (CARD32 *)desc; - atm[0]= (CARD32)xkb->names->phys_symbols; - if (client->swapped) { - swapl(&atm[0],n); - } - desc+= 4; - } - if (which&XkbTypesNameMask) { - *((CARD32 *)desc)= (CARD32)xkb->names->types; - if (client->swapped) { - swapl(desc,n); - } - desc+= 4; - } - if (which&XkbCompatNameMask) { - *((CARD32 *)desc)= (CARD32)xkb->names->compat; - if (client->swapped) { - swapl(desc,n); - } - desc+= 4; - } - if (which&XkbKeyTypeNamesMask) { - register CARD32 *atm= (CARD32 *)desc; - register XkbKeyTypePtr type= xkb->map->types; - - for (i=0;i<xkb->map->num_types;i++,atm++,type++) { - *atm= (CARD32)type->name; - if (client->swapped) { - swapl(atm,n); - } - } - desc= (char *)atm; - } - if (which&XkbKTLevelNamesMask && xkb->map) { - XkbKeyTypePtr type = xkb->map->types; - register CARD32 *atm; - for (i=0;i<rep->nTypes;i++,type++) { - *desc++ = type->num_levels; - } - desc+= XkbPaddedSize(rep->nTypes)-rep->nTypes; - - atm= (CARD32 *)desc; - type = xkb->map->types; - for (i=0;i<xkb->map->num_types;i++,type++) { - register unsigned l; - if (type->level_names) { - for (l=0;l<type->num_levels;l++,atm++) { - *atm= type->level_names[l]; - if (client->swapped) { - swapl(atm,n); - } - } - desc+= type->num_levels*4; - } - } - } - if (which&XkbIndicatorNamesMask) { - desc= _XkbWriteAtoms(desc,xkb->names->indicators,XkbNumIndicators, - client->swapped); - } - if (which&XkbVirtualModNamesMask) { - desc= _XkbWriteAtoms(desc,xkb->names->vmods,XkbNumVirtualMods, - client->swapped); - } - if (which&XkbGroupNamesMask) { - desc= _XkbWriteAtoms(desc,xkb->names->groups,XkbNumKbdGroups, - client->swapped); - } - if (which&XkbKeyNamesMask) { - for (i=0;i<rep->nKeys;i++,desc+= sizeof(XkbKeyNameRec)) { - *((XkbKeyNamePtr)desc)= xkb->names->keys[i+rep->firstKey]; - } - } - if (which&XkbKeyAliasesMask) { - XkbKeyAliasPtr pAl; - pAl= xkb->names->key_aliases; - for (i=0;i<rep->nKeyAliases;i++,pAl++,desc+=2*XkbKeyNameLength) { - *((XkbKeyAliasPtr)desc)= *pAl; - } - } - if ((which&XkbRGNamesMask)&&(rep->nRadioGroups>0)) { - register CARD32 *atm= (CARD32 *)desc; - for (i=0;i<rep->nRadioGroups;i++,atm++) { - *atm= (CARD32)xkb->names->radio_groups[i]; - if (client->swapped) { - swapl(atm,n); - } - } - desc+= rep->nRadioGroups*4; - } - } - - if ((desc-start)!=(length)) { - ErrorF("[xkb] BOGUS LENGTH in write names, expected %d, got %ld\n", - length, (unsigned long)(desc-start)); - } - WriteToClient(client, SIZEOF(xkbGetNamesReply), (char *)rep); - WriteToClient(client, length, start); - xfree((char *)start); - return client->noClientException; -} - -int -ProcXkbGetNames(ClientPtr client) -{ - DeviceIntPtr dev; - XkbDescPtr xkb; - xkbGetNamesReply rep; - - REQUEST(xkbGetNamesReq); - REQUEST_SIZE_MATCH(xkbGetNamesReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); - CHK_MASK_LEGAL(0x01,stuff->which,XkbAllNamesMask); - - xkb = dev->key->xkbInfo->desc; - memset(&rep, 0, sizeof(xkbGetNamesReply)); - rep.type= X_Reply; - rep.sequenceNumber= client->sequence; - rep.length = 0; - rep.deviceID = dev->id; - rep.which = stuff->which; - rep.nTypes = xkb->map->num_types; - rep.firstKey = xkb->min_key_code; - rep.nKeys = XkbNumKeys(xkb); - if (xkb->names!=NULL) { - rep.nKeyAliases= xkb->names->num_key_aliases; - rep.nRadioGroups = xkb->names->num_rg; - } - else { - rep.nKeyAliases= rep.nRadioGroups= 0; - } - XkbComputeGetNamesReplySize(xkb,&rep); - return XkbSendNames(client,xkb,&rep); -} - -/***====================================================================***/ - -static CARD32 * -_XkbCheckAtoms(CARD32 *wire,int nAtoms,int swapped,Atom *pError) -{ -register int i; - - for (i=0;i<nAtoms;i++,wire++) { - if (swapped) { - register int n; - swapl(wire,n); - } - if ((((Atom)*wire)!=None)&&(!ValidAtom((Atom)*wire))) { - *pError= ((Atom)*wire); - return NULL; - } - } - return wire; -} - -static CARD32 * -_XkbCheckMaskedAtoms(CARD32 *wire,int nAtoms,CARD32 present,int swapped, - Atom *pError) -{ -register unsigned i,bit; - - for (i=0,bit=1;(i<nAtoms)&&(present);i++,bit<<=1) { - if ((present&bit)==0) - continue; - if (swapped) { - register int n; - swapl(wire,n); - } - if ((((Atom)*wire)!=None)&&(!ValidAtom(((Atom)*wire)))) { - *pError= (Atom)*wire; - return NULL; - } - wire++; - } - return wire; -} - -static Atom * -_XkbCopyMaskedAtoms( Atom *wire, - Atom *dest, - int nAtoms, - CARD32 present) -{ -register int i,bit; - - for (i=0,bit=1;(i<nAtoms)&&(present);i++,bit<<=1) { - if ((present&bit)==0) - continue; - dest[i]= *wire++; - } - return wire; -} - -static Bool -_XkbCheckTypeName(Atom name,int typeNdx) -{ -const char * str; - - str= NameForAtom(name); - if ((strcmp(str,"ONE_LEVEL")==0)||(strcmp(str,"TWO_LEVEL")==0)|| - (strcmp(str,"ALPHABETIC")==0)||(strcmp(str,"KEYPAD")==0)) - return FALSE; - return TRUE; -} - -/** - * Check the device-dependent data in the request against the device. Returns - * Success, or the appropriate error code. - */ -static int -_XkbSetNamesCheck(ClientPtr client, DeviceIntPtr dev, - xkbSetNamesReq *stuff, CARD32 *data) -{ - XkbDescRec *xkb; - XkbNamesRec *names; - CARD32 *tmp; - Atom bad; - - tmp = data; - xkb = dev->key->xkbInfo->desc; - names = xkb->names; - - - if (stuff->which & XkbKeyTypeNamesMask) { - int i; - CARD32 *old; - if ( stuff->nTypes<1 ) { - client->errorValue = _XkbErrCode2(0x02,stuff->nTypes); - return BadValue; - } - if ((unsigned)(stuff->firstType+stuff->nTypes-1)>=xkb->map->num_types) { - client->errorValue = _XkbErrCode4(0x03,stuff->firstType, - stuff->nTypes, - xkb->map->num_types); - return BadValue; - } - if (((unsigned)stuff->firstType)<=XkbLastRequiredType) { - client->errorValue = _XkbErrCode2(0x04,stuff->firstType); - return BadAccess; - } - old= tmp; - tmp= _XkbCheckAtoms(tmp,stuff->nTypes,client->swapped,&bad); - if (!tmp) { - client->errorValue= bad; - return BadAtom; - } - for (i=0;i<stuff->nTypes;i++,old++) { - if (!_XkbCheckTypeName((Atom)*old,stuff->firstType+i)) - client->errorValue= _XkbErrCode2(0x05,i); - } - } - if (stuff->which&XkbKTLevelNamesMask) { - unsigned i; - XkbKeyTypePtr type; - CARD8 * width; - if ( stuff->nKTLevels<1 ) { - client->errorValue = _XkbErrCode2(0x05,stuff->nKTLevels); - return BadValue; - } - if ((unsigned)(stuff->firstKTLevel+stuff->nKTLevels-1)>= - xkb->map->num_types) { - client->errorValue = _XkbErrCode4(0x06,stuff->firstKTLevel, - stuff->nKTLevels,xkb->map->num_types); - return BadValue; - } - width = (CARD8 *)tmp; - tmp= (CARD32 *)(((char *)tmp)+XkbPaddedSize(stuff->nKTLevels)); - type = &xkb->map->types[stuff->firstKTLevel]; - for (i=0;i<stuff->nKTLevels;i++,type++) { - if (width[i]==0) - continue; - else if (width[i]!=type->num_levels) { - client->errorValue= _XkbErrCode4(0x07,i+stuff->firstKTLevel, - type->num_levels,width[i]); - return BadMatch; - } - tmp= _XkbCheckAtoms(tmp,width[i],client->swapped,&bad); - if (!tmp) { - client->errorValue= bad; - return BadAtom; - } - } - } - if (stuff->which&XkbIndicatorNamesMask) { - if (stuff->indicators==0) { - client->errorValue= 0x08; - return BadMatch; - } - tmp= _XkbCheckMaskedAtoms(tmp,XkbNumIndicators,stuff->indicators, - client->swapped,&bad); - if (!tmp) { - client->errorValue= bad; - return BadAtom; - } - } - if (stuff->which&XkbVirtualModNamesMask) { - if (stuff->virtualMods==0) { - client->errorValue= 0x09; - return BadMatch; - } - tmp= _XkbCheckMaskedAtoms(tmp,XkbNumVirtualMods, - (CARD32)stuff->virtualMods, - client->swapped,&bad); - if (!tmp) { - client->errorValue = bad; - return BadAtom; - } - } - if (stuff->which&XkbGroupNamesMask) { - if (stuff->groupNames==0) { - client->errorValue= 0x0a; - return BadMatch; - } - tmp= _XkbCheckMaskedAtoms(tmp,XkbNumKbdGroups, - (CARD32)stuff->groupNames, - client->swapped,&bad); - if (!tmp) { - client->errorValue = bad; - return BadAtom; - } - } - if (stuff->which&XkbKeyNamesMask) { - if (stuff->firstKey<(unsigned)xkb->min_key_code) { - client->errorValue= _XkbErrCode3(0x0b,xkb->min_key_code, - stuff->firstKey); - return BadValue; - } - if (((unsigned)(stuff->firstKey+stuff->nKeys-1)>xkb->max_key_code)|| - (stuff->nKeys<1)) { - client->errorValue= _XkbErrCode4(0x0c,xkb->max_key_code, - stuff->firstKey,stuff->nKeys); - return BadValue; - } - tmp+= stuff->nKeys; - } - if ((stuff->which&XkbKeyAliasesMask)&&(stuff->nKeyAliases>0)) { - tmp+= stuff->nKeyAliases*2; - } - if (stuff->which&XkbRGNamesMask) { - if ( stuff->nRadioGroups<1 ) { - client->errorValue= _XkbErrCode2(0x0d,stuff->nRadioGroups); - return BadValue; - } - tmp= _XkbCheckAtoms(tmp,stuff->nRadioGroups,client->swapped,&bad); - if (!tmp) { - client->errorValue= bad; - return BadAtom; - } - } - if ((tmp-((CARD32 *)stuff))!=stuff->length) { - client->errorValue = stuff->length; - return BadLength; - } - - - - return Success; -} - -static int -_XkbSetNames(ClientPtr client, DeviceIntPtr dev, xkbSetNamesReq *stuff) -{ - XkbDescRec *xkb; - XkbNamesRec *names; - CARD32 *tmp; - xkbNamesNotify nn; - - tmp = (CARD32 *)&stuff[1]; - xkb = dev->key->xkbInfo->desc; - names = xkb->names; - - if (XkbAllocNames(xkb,stuff->which,stuff->nRadioGroups, - stuff->nKeyAliases)!=Success) { - return BadAlloc; - } - - bzero(&nn,sizeof(xkbNamesNotify)); - nn.changed= stuff->which; - tmp = (CARD32 *)&stuff[1]; - if (stuff->which&XkbKeycodesNameMask) - names->keycodes= *tmp++; - if (stuff->which&XkbGeometryNameMask) - names->geometry= *tmp++; - if (stuff->which&XkbSymbolsNameMask) - names->symbols= *tmp++; - if (stuff->which&XkbPhysSymbolsNameMask) - names->phys_symbols= *tmp++; - if (stuff->which&XkbTypesNameMask) - names->types= *tmp++; - if (stuff->which&XkbCompatNameMask) - names->compat= *tmp++; - if ((stuff->which&XkbKeyTypeNamesMask)&&(stuff->nTypes>0)) { - register unsigned i; - register XkbKeyTypePtr type; - - type= &xkb->map->types[stuff->firstType]; - for (i=0;i<stuff->nTypes;i++,type++) { - type->name= *tmp++; - } - nn.firstType= stuff->firstType; - nn.nTypes= stuff->nTypes; - } - if (stuff->which&XkbKTLevelNamesMask) { - register XkbKeyTypePtr type; - register unsigned i; - CARD8 *width; - - width = (CARD8 *)tmp; - tmp= (CARD32 *)(((char *)tmp)+XkbPaddedSize(stuff->nKTLevels)); - type= &xkb->map->types[stuff->firstKTLevel]; - for (i=0;i<stuff->nKTLevels;i++,type++) { - if (width[i]>0) { - if (type->level_names) { - register unsigned n; - for (n=0;n<width[i];n++) { - type->level_names[n]= tmp[n]; - } - } - tmp+= width[i]; - } - } - nn.firstLevelName= 0; - nn.nLevelNames= stuff->nTypes; - } - if (stuff->which&XkbIndicatorNamesMask) { - tmp= _XkbCopyMaskedAtoms(tmp,names->indicators,XkbNumIndicators, - stuff->indicators); - nn.changedIndicators= stuff->indicators; - } - if (stuff->which&XkbVirtualModNamesMask) { - tmp= _XkbCopyMaskedAtoms(tmp,names->vmods,XkbNumVirtualMods, - stuff->virtualMods); - nn.changedVirtualMods= stuff->virtualMods; - } - if (stuff->which&XkbGroupNamesMask) { - tmp= _XkbCopyMaskedAtoms(tmp,names->groups,XkbNumKbdGroups, - stuff->groupNames); - nn.changedVirtualMods= stuff->groupNames; - } - if (stuff->which&XkbKeyNamesMask) { - memcpy((char*)&names->keys[stuff->firstKey],(char *)tmp, - stuff->nKeys*XkbKeyNameLength); - tmp+= stuff->nKeys; - nn.firstKey= stuff->firstKey; - nn.nKeys= stuff->nKeys; - } - if (stuff->which&XkbKeyAliasesMask) { - if (stuff->nKeyAliases>0) { - register int na= stuff->nKeyAliases; - if (XkbAllocNames(xkb,XkbKeyAliasesMask,0,na)!=Success) - return BadAlloc; - memcpy((char *)names->key_aliases,(char *)tmp, - stuff->nKeyAliases*sizeof(XkbKeyAliasRec)); - tmp+= stuff->nKeyAliases*2; - } - else if (names->key_aliases!=NULL) { - xfree(names->key_aliases); - names->key_aliases= NULL; - names->num_key_aliases= 0; - } - nn.nAliases= names->num_key_aliases; - } - if (stuff->which&XkbRGNamesMask) { - if (stuff->nRadioGroups>0) { - register unsigned i,nrg; - nrg= stuff->nRadioGroups; - if (XkbAllocNames(xkb,XkbRGNamesMask,nrg,0)!=Success) - return BadAlloc; - - for (i=0;i<stuff->nRadioGroups;i++) { - names->radio_groups[i]= tmp[i]; - } - tmp+= stuff->nRadioGroups; - } - else if (names->radio_groups) { - xfree(names->radio_groups); - names->radio_groups= NULL; - names->num_rg= 0; - } - nn.nRadioGroups= names->num_rg; - } - if (nn.changed) { - Bool needExtEvent; - needExtEvent= (nn.changed&XkbIndicatorNamesMask)!=0; - XkbSendNamesNotify(dev,&nn); - if (needExtEvent) { - XkbSrvLedInfoPtr sli; - xkbExtensionDeviceNotify edev; - register int i; - register unsigned bit; - - sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId, - XkbXI_IndicatorsMask); - sli->namesPresent= 0; - for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { - if (names->indicators[i]!=None) - sli->namesPresent|= bit; - } - bzero(&edev,sizeof(xkbExtensionDeviceNotify)); - edev.reason= XkbXI_IndicatorNamesMask; - edev.ledClass= KbdFeedbackClass; - edev.ledID= dev->kbdfeed->ctrl.id; - edev.ledsDefined= sli->namesPresent|sli->mapsPresent; - edev.ledState= sli->effectiveState; - edev.firstBtn= 0; - edev.nBtns= 0; - edev.supported= XkbXI_AllFeaturesMask; - edev.unsupported= 0; - XkbSendExtensionDeviceNotify(dev,client,&edev); - } - } - return Success; -} - -int -ProcXkbSetNames(ClientPtr client) -{ - DeviceIntPtr dev; - CARD32 *tmp; - Atom bad; - int rc; - - REQUEST(xkbSetNamesReq); - REQUEST_AT_LEAST_SIZE(xkbSetNamesReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); - CHK_MASK_LEGAL(0x01,stuff->which,XkbAllNamesMask); - - /* check device-independent stuff */ - tmp = (CARD32 *)&stuff[1]; - - if (stuff->which&XkbKeycodesNameMask) { - tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); - if (!tmp) { - client->errorValue = bad; - return BadAtom; - } - } - if (stuff->which&XkbGeometryNameMask) { - tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); - if (!tmp) { - client->errorValue = bad; - return BadAtom; - } - } - if (stuff->which&XkbSymbolsNameMask) { - tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); - if (!tmp) { - client->errorValue = bad; - return BadAtom; - } - } - if (stuff->which&XkbPhysSymbolsNameMask) { - tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); - if (!tmp) { - client->errorValue= bad; - return BadAtom; - } - } - if (stuff->which&XkbTypesNameMask) { - tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); - if (!tmp) { - client->errorValue = bad; - return BadAtom; - } - } - if (stuff->which&XkbCompatNameMask) { - tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); - if (!tmp) { - client->errorValue = bad; - return BadAtom; - } - } - - /* start of device-dependent tests */ - rc = _XkbSetNamesCheck(client, dev, stuff, tmp); - if (rc != Success) - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) - { - - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); - if (rc == Success) - { - rc = _XkbSetNamesCheck(client, other, stuff, tmp); - if (rc != Success) - return rc; - } - } - } - } - - /* everything is okay -- update names */ - - rc = _XkbSetNames(client, dev, stuff); - if (rc != Success) - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) - { - - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); - if (rc == Success) - _XkbSetNames(client, other, stuff); - } - } - } - - /* everything is okay -- update names */ - - return client->noClientException; -} - -/***====================================================================***/ - -#include "xkbgeom.h" - -#define XkbSizeCountedString(s) ((s)?((((2+strlen(s))+3)/4)*4):4) - -static char * -XkbWriteCountedString(char *wire,char *str,Bool swap) -{ - CARD16 len,*pLen; - - if (!str) - return wire; - - len= strlen(str); - pLen= (CARD16 *)wire; - *pLen= len; - if (swap) { - register int n; - swaps(pLen,n); - } - memcpy(&wire[2],str,len); - wire+= ((2+len+3)/4)*4; - return wire; -} - -static int -XkbSizeGeomProperties(XkbGeometryPtr geom) -{ -register int i,size; -XkbPropertyPtr prop; - - for (size=i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) { - size+= XkbSizeCountedString(prop->name); - size+= XkbSizeCountedString(prop->value); - } - return size; -} - -static char * -XkbWriteGeomProperties(char *wire,XkbGeometryPtr geom,Bool swap) -{ -register int i; -register XkbPropertyPtr prop; - - for (i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) { - wire= XkbWriteCountedString(wire,prop->name,swap); - wire= XkbWriteCountedString(wire,prop->value,swap); - } - return wire; -} - -static int -XkbSizeGeomKeyAliases(XkbGeometryPtr geom) -{ - return geom->num_key_aliases*(2*XkbKeyNameLength); -} - -static char * -XkbWriteGeomKeyAliases(char *wire,XkbGeometryPtr geom,Bool swap) -{ -register int sz; - - sz= geom->num_key_aliases*(XkbKeyNameLength*2); - if (sz>0) { - memcpy(wire,(char *)geom->key_aliases,sz); - wire+= sz; - } - return wire; -} - -static int -XkbSizeGeomColors(XkbGeometryPtr geom) -{ -register int i,size; -register XkbColorPtr color; - - for (i=size=0,color=geom->colors;i<geom->num_colors;i++,color++) { - size+= XkbSizeCountedString(color->spec); - } - return size; -} - -static char * -XkbWriteGeomColors(char *wire,XkbGeometryPtr geom,Bool swap) -{ -register int i; -register XkbColorPtr color; - - for (i=0,color=geom->colors;i<geom->num_colors;i++,color++) { - wire= XkbWriteCountedString(wire,color->spec,swap); - } - return wire; -} - -static int -XkbSizeGeomShapes(XkbGeometryPtr geom) -{ -register int i,size; -register XkbShapePtr shape; - - for (i=size=0,shape=geom->shapes;i<geom->num_shapes;i++,shape++) { - register int n; - register XkbOutlinePtr ol; - size+= SIZEOF(xkbShapeWireDesc); - for (n=0,ol=shape->outlines;n<shape->num_outlines;n++,ol++) { - size+= SIZEOF(xkbOutlineWireDesc); - size+= ol->num_points*SIZEOF(xkbPointWireDesc); - } - } - return size; -} - -static char * -XkbWriteGeomShapes(char *wire,XkbGeometryPtr geom,Bool swap) -{ -int i; -XkbShapePtr shape; -xkbShapeWireDesc * shapeWire; - - for (i=0,shape=geom->shapes;i<geom->num_shapes;i++,shape++) { - register int o; - XkbOutlinePtr ol; - xkbOutlineWireDesc * olWire; - shapeWire= (xkbShapeWireDesc *)wire; - shapeWire->name= shape->name; - shapeWire->nOutlines= shape->num_outlines; - if (shape->primary!=NULL) - shapeWire->primaryNdx= XkbOutlineIndex(shape,shape->primary); - else shapeWire->primaryNdx= XkbNoShape; - if (shape->approx!=NULL) - shapeWire->approxNdx= XkbOutlineIndex(shape,shape->approx); - else shapeWire->approxNdx= XkbNoShape; - if (swap) { - register int n; - swapl(&shapeWire->name,n); - } - wire= (char *)&shapeWire[1]; - for (o=0,ol=shape->outlines;o<shape->num_outlines;o++,ol++) { - register int p; - XkbPointPtr pt; - xkbPointWireDesc * ptWire; - olWire= (xkbOutlineWireDesc *)wire; - olWire->nPoints= ol->num_points; - olWire->cornerRadius= ol->corner_radius; - wire= (char *)&olWire[1]; - ptWire= (xkbPointWireDesc *)wire; - for (p=0,pt=ol->points;p<ol->num_points;p++,pt++) { - ptWire[p].x= pt->x; - ptWire[p].y= pt->y; - if (swap) { - register int n; - swaps(&ptWire[p].x,n); - swaps(&ptWire[p].y,n); - } - } - wire= (char *)&ptWire[ol->num_points]; - } - } - return wire; -} - -static int -XkbSizeGeomDoodads(int num_doodads,XkbDoodadPtr doodad) -{ -register int i,size; - - for (i=size=0;i<num_doodads;i++,doodad++) { - size+= SIZEOF(xkbAnyDoodadWireDesc); - if (doodad->any.type==XkbTextDoodad) { - size+= XkbSizeCountedString(doodad->text.text); - size+= XkbSizeCountedString(doodad->text.font); - } - else if (doodad->any.type==XkbLogoDoodad) { - size+= XkbSizeCountedString(doodad->logo.logo_name); - } - } - return size; -} - -static char * -XkbWriteGeomDoodads(char *wire,int num_doodads,XkbDoodadPtr doodad,Bool swap) -{ -register int i; -xkbDoodadWireDesc * doodadWire; - - for (i=0;i<num_doodads;i++,doodad++) { - doodadWire= (xkbDoodadWireDesc *)wire; - wire= (char *)&doodadWire[1]; - bzero(doodadWire,SIZEOF(xkbDoodadWireDesc)); - doodadWire->any.name= doodad->any.name; - doodadWire->any.type= doodad->any.type; - doodadWire->any.priority= doodad->any.priority; - doodadWire->any.top= doodad->any.top; - doodadWire->any.left= doodad->any.left; - if (swap) { - register int n; - swapl(&doodadWire->any.name,n); - swaps(&doodadWire->any.top,n); - swaps(&doodadWire->any.left,n); - } - switch (doodad->any.type) { - case XkbOutlineDoodad: - case XkbSolidDoodad: - doodadWire->shape.angle= doodad->shape.angle; - doodadWire->shape.colorNdx= doodad->shape.color_ndx; - doodadWire->shape.shapeNdx= doodad->shape.shape_ndx; - if (swap) { - register int n; - swaps(&doodadWire->shape.angle,n); - } - break; - case XkbTextDoodad: - doodadWire->text.angle= doodad->text.angle; - doodadWire->text.width= doodad->text.width; - doodadWire->text.height= doodad->text.height; - doodadWire->text.colorNdx= doodad->text.color_ndx; - if (swap) { - register int n; - swaps(&doodadWire->text.angle,n); - swaps(&doodadWire->text.width,n); - swaps(&doodadWire->text.height,n); - } - wire= XkbWriteCountedString(wire,doodad->text.text,swap); - wire= XkbWriteCountedString(wire,doodad->text.font,swap); - break; - case XkbIndicatorDoodad: - doodadWire->indicator.shapeNdx= doodad->indicator.shape_ndx; - doodadWire->indicator.onColorNdx=doodad->indicator.on_color_ndx; - doodadWire->indicator.offColorNdx= - doodad->indicator.off_color_ndx; - break; - case XkbLogoDoodad: - doodadWire->logo.angle= doodad->logo.angle; - doodadWire->logo.colorNdx= doodad->logo.color_ndx; - doodadWire->logo.shapeNdx= doodad->logo.shape_ndx; - wire= XkbWriteCountedString(wire,doodad->logo.logo_name,swap); - break; - default: - ErrorF("[xkb] Unknown doodad type %d in XkbWriteGeomDoodads\n", - doodad->any.type); - ErrorF("[xkb] Ignored\n"); - break; - } - } - return wire; -} - -static char * -XkbWriteGeomOverlay(char *wire,XkbOverlayPtr ol,Bool swap) -{ -register int r; -XkbOverlayRowPtr row; -xkbOverlayWireDesc * olWire; - - olWire= (xkbOverlayWireDesc *)wire; - olWire->name= ol->name; - olWire->nRows= ol->num_rows; - if (swap) { - register int n; - swapl(&olWire->name,n); - } - wire= (char *)&olWire[1]; - for (r=0,row=ol->rows;r<ol->num_rows;r++,row++) { - unsigned int k; - XkbOverlayKeyPtr key; - xkbOverlayRowWireDesc * rowWire; - rowWire= (xkbOverlayRowWireDesc *)wire; - rowWire->rowUnder= row->row_under; - rowWire->nKeys= row->num_keys; - wire= (char *)&rowWire[1]; - for (k=0,key=row->keys;k<row->num_keys;k++,key++) { - xkbOverlayKeyWireDesc * keyWire; - keyWire= (xkbOverlayKeyWireDesc *)wire; - memcpy(keyWire->over,key->over.name,XkbKeyNameLength); - memcpy(keyWire->under,key->under.name,XkbKeyNameLength); - wire= (char *)&keyWire[1]; - } - } - return wire; -} - -static int -XkbSizeGeomSections(XkbGeometryPtr geom) -{ -register int i,size; -XkbSectionPtr section; - - for (i=size=0,section=geom->sections;i<geom->num_sections;i++,section++) { - size+= SIZEOF(xkbSectionWireDesc); - if (section->rows) { - int r; - XkbRowPtr row; - for (r=0,row=section->rows;r<section->num_rows;row++,r++) { - size+= SIZEOF(xkbRowWireDesc); - size+= row->num_keys*SIZEOF(xkbKeyWireDesc); - } - } - if (section->doodads) - size+= XkbSizeGeomDoodads(section->num_doodads,section->doodads); - if (section->overlays) { - int o; - XkbOverlayPtr ol; - for (o=0,ol=section->overlays;o<section->num_overlays;o++,ol++) { - int r; - XkbOverlayRowPtr row; - size+= SIZEOF(xkbOverlayWireDesc); - for (r=0,row=ol->rows;r<ol->num_rows;r++,row++) { - size+= SIZEOF(xkbOverlayRowWireDesc); - size+= row->num_keys*SIZEOF(xkbOverlayKeyWireDesc); - } - } - } - } - return size; -} - -static char * -XkbWriteGeomSections(char *wire,XkbGeometryPtr geom,Bool swap) -{ -register int i; -XkbSectionPtr section; -xkbSectionWireDesc * sectionWire; - - for (i=0,section=geom->sections;i<geom->num_sections;i++,section++) { - sectionWire= (xkbSectionWireDesc *)wire; - sectionWire->name= section->name; - sectionWire->top= section->top; - sectionWire->left= section->left; - sectionWire->width= section->width; - sectionWire->height= section->height; - sectionWire->angle= section->angle; - sectionWire->priority= section->priority; - sectionWire->nRows= section->num_rows; - sectionWire->nDoodads= section->num_doodads; - sectionWire->nOverlays= section->num_overlays; - sectionWire->pad= 0; - if (swap) { - register int n; - swapl(§ionWire->name,n); - swaps(§ionWire->top,n); - swaps(§ionWire->left,n); - swaps(§ionWire->width,n); - swaps(§ionWire->height,n); - swaps(§ionWire->angle,n); - } - wire= (char *)§ionWire[1]; - if (section->rows) { - int r; - XkbRowPtr row; - xkbRowWireDesc * rowWire; - for (r=0,row=section->rows;r<section->num_rows;r++,row++) { - rowWire= (xkbRowWireDesc *)wire; - rowWire->top= row->top; - rowWire->left= row->left; - rowWire->nKeys= row->num_keys; - rowWire->vertical= row->vertical; - rowWire->pad= 0; - if (swap) { - register int n; - swaps(&rowWire->top,n); - swaps(&rowWire->left,n); - } - wire= (char *)&rowWire[1]; - if (row->keys) { - int k; - XkbKeyPtr key; - xkbKeyWireDesc * keyWire; - keyWire= (xkbKeyWireDesc *)wire; - for (k=0,key=row->keys;k<row->num_keys;k++,key++) { - memcpy(keyWire[k].name,key->name.name,XkbKeyNameLength); - keyWire[k].gap= key->gap; - keyWire[k].shapeNdx= key->shape_ndx; - keyWire[k].colorNdx= key->color_ndx; - if (swap) { - register int n; - swaps(&keyWire[k].gap,n); - } - } - wire= (char *)&keyWire[row->num_keys]; - } - } - } - if (section->doodads) { - wire= XkbWriteGeomDoodads(wire, - section->num_doodads,section->doodads, - swap); - } - if (section->overlays) { - register int o; - for (o=0;o<section->num_overlays;o++) { - wire= XkbWriteGeomOverlay(wire,§ion->overlays[o],swap); - } - } - } - return wire; -} - -static Status -XkbComputeGetGeometryReplySize( XkbGeometryPtr geom, - xkbGetGeometryReply * rep, - Atom name) -{ -int len; - - if (geom!=NULL) { - len= XkbSizeCountedString(geom->label_font); - len+= XkbSizeGeomProperties(geom); - len+= XkbSizeGeomColors(geom); - len+= XkbSizeGeomShapes(geom); - len+= XkbSizeGeomSections(geom); - len+= XkbSizeGeomDoodads(geom->num_doodads,geom->doodads); - len+= XkbSizeGeomKeyAliases(geom); - rep->length= len/4; - rep->found= TRUE; - rep->name= geom->name; - rep->widthMM= geom->width_mm; - rep->heightMM= geom->height_mm; - rep->nProperties= geom->num_properties; - rep->nColors= geom->num_colors; - rep->nShapes= geom->num_shapes; - rep->nSections= geom->num_sections; - rep->nDoodads= geom->num_doodads; - rep->nKeyAliases= geom->num_key_aliases; - rep->baseColorNdx= XkbGeomColorIndex(geom,geom->base_color); - rep->labelColorNdx= XkbGeomColorIndex(geom,geom->label_color); - } - else { - rep->length= 0; - rep->found= FALSE; - rep->name= name; - rep->widthMM= rep->heightMM= 0; - rep->nProperties= rep->nColors= rep->nShapes= 0; - rep->nSections= rep->nDoodads= 0; - rep->nKeyAliases= 0; - rep->labelColorNdx= rep->baseColorNdx= 0; - } - return Success; -} - -static int -XkbSendGeometry( ClientPtr client, - XkbGeometryPtr geom, - xkbGetGeometryReply * rep, - Bool freeGeom) -{ - char *desc,*start; - int len; - - if (geom!=NULL) { - len= rep->length*4; - start= desc= xalloc(len); - if (!start) - return BadAlloc; - desc= XkbWriteCountedString(desc,geom->label_font,client->swapped); - if ( rep->nProperties>0 ) - desc = XkbWriteGeomProperties(desc,geom,client->swapped); - if ( rep->nColors>0 ) - desc = XkbWriteGeomColors(desc,geom,client->swapped); - if ( rep->nShapes>0 ) - desc = XkbWriteGeomShapes(desc,geom,client->swapped); - if ( rep->nSections>0 ) - desc = XkbWriteGeomSections(desc,geom,client->swapped); - if ( rep->nDoodads>0 ) - desc = XkbWriteGeomDoodads(desc,geom->num_doodads,geom->doodads, - client->swapped); - if ( rep->nKeyAliases>0 ) - desc = XkbWriteGeomKeyAliases(desc,geom,client->swapped); - if ((desc-start)!=(len)) { - ErrorF("[xkb] BOGUS LENGTH in XkbSendGeometry, expected %d, got %ld\n", - len, (unsigned long)(desc-start)); - } - } - else { - len= 0; - start= NULL; - } - if (client->swapped) { - register int n; - swaps(&rep->sequenceNumber,n); - swapl(&rep->length,n); - swapl(&rep->name,n); - swaps(&rep->widthMM,n); - swaps(&rep->heightMM,n); - swaps(&rep->nProperties,n); - swaps(&rep->nColors,n); - swaps(&rep->nShapes,n); - swaps(&rep->nSections,n); - swaps(&rep->nDoodads,n); - swaps(&rep->nKeyAliases,n); - } - WriteToClient(client, SIZEOF(xkbGetGeometryReply), (char *)rep); - if (len>0) - WriteToClient(client, len, start); - if (start!=NULL) - xfree((char *)start); - if (freeGeom) - XkbFreeGeometry(geom,XkbGeomAllMask,TRUE); - return client->noClientException; -} - -int -ProcXkbGetGeometry(ClientPtr client) -{ - DeviceIntPtr dev; - xkbGetGeometryReply rep; - XkbGeometryPtr geom; - Bool shouldFree; - Status status; - - REQUEST(xkbGetGeometryReq); - REQUEST_SIZE_MATCH(xkbGetGeometryReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); - CHK_ATOM_OR_NONE(stuff->name); - - geom= XkbLookupNamedGeometry(dev,stuff->name,&shouldFree); - rep.type= X_Reply; - rep.deviceID= dev->id; - rep.sequenceNumber= client->sequence; - rep.length= 0; - status= XkbComputeGetGeometryReplySize(geom,&rep,stuff->name); - if (status!=Success) - return status; - else return XkbSendGeometry(client,geom,&rep,shouldFree); -} - -/***====================================================================***/ - -static char * -_GetCountedString(char **wire_inout,Bool swap) -{ -char * wire,*str; -CARD16 len,*plen; - - wire= *wire_inout; - plen= (CARD16 *)wire; - if (swap) { - register int n; - swaps(plen,n); - } - len= *plen; - str= xalloc(len+1); - if (str) { - memcpy(str,&wire[2],len); - str[len]= '\0'; - } - wire+= XkbPaddedSize(len+2); - *wire_inout= wire; - return str; -} - -static Status -_CheckSetDoodad( char ** wire_inout, - XkbGeometryPtr geom, - XkbSectionPtr section, - ClientPtr client) -{ -char * wire; -xkbDoodadWireDesc * dWire; -XkbDoodadPtr doodad; - - dWire= (xkbDoodadWireDesc *)(*wire_inout); - wire= (char *)&dWire[1]; - if (client->swapped) { - register int n; - swapl(&dWire->any.name,n); - swaps(&dWire->any.top,n); - swaps(&dWire->any.left,n); - swaps(&dWire->any.angle,n); - } - CHK_ATOM_ONLY(dWire->any.name); - doodad= XkbAddGeomDoodad(geom,section,dWire->any.name); - if (!doodad) - return BadAlloc; - doodad->any.type= dWire->any.type; - doodad->any.priority= dWire->any.priority; - doodad->any.top= dWire->any.top; - doodad->any.left= dWire->any.left; - doodad->any.angle= dWire->any.angle; - switch (doodad->any.type) { - case XkbOutlineDoodad: - case XkbSolidDoodad: - if (dWire->shape.colorNdx>=geom->num_colors) { - client->errorValue= _XkbErrCode3(0x40,geom->num_colors, - dWire->shape.colorNdx); - return BadMatch; - } - if (dWire->shape.shapeNdx>=geom->num_shapes) { - client->errorValue= _XkbErrCode3(0x41,geom->num_shapes, - dWire->shape.shapeNdx); - return BadMatch; - } - doodad->shape.color_ndx= dWire->shape.colorNdx; - doodad->shape.shape_ndx= dWire->shape.shapeNdx; - break; - case XkbTextDoodad: - if (dWire->text.colorNdx>=geom->num_colors) { - client->errorValue= _XkbErrCode3(0x42,geom->num_colors, - dWire->text.colorNdx); - return BadMatch; - } - if (client->swapped) { - register int n; - swaps(&dWire->text.width,n); - swaps(&dWire->text.height,n); - } - doodad->text.width= dWire->text.width; - doodad->text.height= dWire->text.height; - doodad->text.color_ndx= dWire->text.colorNdx; - doodad->text.text= _GetCountedString(&wire,client->swapped); - doodad->text.font= _GetCountedString(&wire,client->swapped); - break; - case XkbIndicatorDoodad: - if (dWire->indicator.onColorNdx>=geom->num_colors) { - client->errorValue= _XkbErrCode3(0x43,geom->num_colors, - dWire->indicator.onColorNdx); - return BadMatch; - } - if (dWire->indicator.offColorNdx>=geom->num_colors) { - client->errorValue= _XkbErrCode3(0x44,geom->num_colors, - dWire->indicator.offColorNdx); - return BadMatch; - } - if (dWire->indicator.shapeNdx>=geom->num_shapes) { - client->errorValue= _XkbErrCode3(0x45,geom->num_shapes, - dWire->indicator.shapeNdx); - return BadMatch; - } - doodad->indicator.shape_ndx= dWire->indicator.shapeNdx; - doodad->indicator.on_color_ndx= dWire->indicator.onColorNdx; - doodad->indicator.off_color_ndx= dWire->indicator.offColorNdx; - break; - case XkbLogoDoodad: - if (dWire->logo.colorNdx>=geom->num_colors) { - client->errorValue= _XkbErrCode3(0x46,geom->num_colors, - dWire->logo.colorNdx); - return BadMatch; - } - if (dWire->logo.shapeNdx>=geom->num_shapes) { - client->errorValue= _XkbErrCode3(0x47,geom->num_shapes, - dWire->logo.shapeNdx); - return BadMatch; - } - doodad->logo.color_ndx= dWire->logo.colorNdx; - doodad->logo.shape_ndx= dWire->logo.shapeNdx; - doodad->logo.logo_name= _GetCountedString(&wire,client->swapped); - break; - default: - client->errorValue= _XkbErrCode2(0x4F,dWire->any.type); - return BadValue; - } - *wire_inout= wire; - return Success; -} - -static Status -_CheckSetOverlay( char ** wire_inout, - XkbGeometryPtr geom, - XkbSectionPtr section, - ClientPtr client) -{ -register int r; -char * wire; -XkbOverlayPtr ol; -xkbOverlayWireDesc * olWire; -xkbOverlayRowWireDesc * rWire; - - wire= *wire_inout; - olWire= (xkbOverlayWireDesc *)wire; - if (client->swapped) { - register int n; - swapl(&olWire->name,n); - } - CHK_ATOM_ONLY(olWire->name); - ol= XkbAddGeomOverlay(section,olWire->name,olWire->nRows); - rWire= (xkbOverlayRowWireDesc *)&olWire[1]; - for (r=0;r<olWire->nRows;r++) { - register int k; - xkbOverlayKeyWireDesc * kWire; - XkbOverlayRowPtr row; - - if (rWire->rowUnder>section->num_rows) { - client->errorValue= _XkbErrCode4(0x20,r,section->num_rows, - rWire->rowUnder); - return BadMatch; - } - row= XkbAddGeomOverlayRow(ol,rWire->rowUnder,rWire->nKeys); - kWire= (xkbOverlayKeyWireDesc *)&rWire[1]; - for (k=0;k<rWire->nKeys;k++,kWire++) { - if (XkbAddGeomOverlayKey(ol,row, - (char *)kWire->over,(char *)kWire->under)==NULL) { - client->errorValue= _XkbErrCode3(0x21,r,k); - return BadMatch; - } - } - rWire= (xkbOverlayRowWireDesc *)kWire; - } - olWire= (xkbOverlayWireDesc *)rWire; - wire= (char *)olWire; - *wire_inout= wire; - return Success; -} - -static Status -_CheckSetSections( XkbGeometryPtr geom, - xkbSetGeometryReq * req, - char ** wire_inout, - ClientPtr client) -{ -Status status; -register int s; -char * wire; -xkbSectionWireDesc * sWire; -XkbSectionPtr section; - - wire= *wire_inout; - if (req->nSections<1) - return Success; - sWire= (xkbSectionWireDesc *)wire; - for (s=0;s<req->nSections;s++) { - register int r; - xkbRowWireDesc * rWire; - if (client->swapped) { - register int n; - swapl(&sWire->name,n); - swaps(&sWire->top,n); - swaps(&sWire->left,n); - swaps(&sWire->width,n); - swaps(&sWire->height,n); - swaps(&sWire->angle,n); - } - CHK_ATOM_ONLY(sWire->name); - section= XkbAddGeomSection(geom,sWire->name,sWire->nRows, - sWire->nDoodads,sWire->nOverlays); - if (!section) - return BadAlloc; - section->priority= sWire->priority; - section->top= sWire->top; - section->left= sWire->left; - section->width= sWire->width; - section->height= sWire->height; - section->angle= sWire->angle; - rWire= (xkbRowWireDesc *)&sWire[1]; - for (r=0;r<sWire->nRows;r++) { - register int k; - XkbRowPtr row; - xkbKeyWireDesc * kWire; - if (client->swapped) { - register int n; - swaps(&rWire->top,n); - swaps(&rWire->left,n); - } - row= XkbAddGeomRow(section,rWire->nKeys); - if (!row) - return BadAlloc; - row->top= rWire->top; - row->left= rWire->left; - row->vertical= rWire->vertical; - kWire= (xkbKeyWireDesc *)&rWire[1]; - for (k=0;k<rWire->nKeys;k++) { - XkbKeyPtr key; - key= XkbAddGeomKey(row); - if (!key) - return BadAlloc; - memcpy(key->name.name,kWire[k].name,XkbKeyNameLength); - key->gap= kWire[k].gap; - key->shape_ndx= kWire[k].shapeNdx; - key->color_ndx= kWire[k].colorNdx; - if (key->shape_ndx>=geom->num_shapes) { - client->errorValue= _XkbErrCode3(0x10,key->shape_ndx, - geom->num_shapes); - return BadMatch; - } - if (key->color_ndx>=geom->num_colors) { - client->errorValue= _XkbErrCode3(0x11,key->color_ndx, - geom->num_colors); - return BadMatch; - } - } - rWire= (xkbRowWireDesc *)&kWire[rWire->nKeys]; - } - wire= (char *)rWire; - if (sWire->nDoodads>0) { - register int d; - for (d=0;d<sWire->nDoodads;d++) { - status=_CheckSetDoodad(&wire,geom,section,client); - if (status!=Success) - return status; - } - } - if (sWire->nOverlays>0) { - register int o; - for (o=0;o<sWire->nOverlays;o++) { - status= _CheckSetOverlay(&wire,geom,section,client); - if (status!=Success) - return status; - } - } - sWire= (xkbSectionWireDesc *)wire; - } - wire= (char *)sWire; - *wire_inout= wire; - return Success; -} - -static Status -_CheckSetShapes( XkbGeometryPtr geom, - xkbSetGeometryReq * req, - char ** wire_inout, - ClientPtr client) -{ -register int i; -char * wire; - - wire= *wire_inout; - if (req->nShapes<1) { - client->errorValue= _XkbErrCode2(0x06,req->nShapes); - return BadValue; - } - else { - xkbShapeWireDesc * shapeWire; - XkbShapePtr shape; - register int o; - shapeWire= (xkbShapeWireDesc *)wire; - for (i=0;i<req->nShapes;i++) { - xkbOutlineWireDesc * olWire; - XkbOutlinePtr ol; - shape= XkbAddGeomShape(geom,shapeWire->name,shapeWire->nOutlines); - if (!shape) - return BadAlloc; - olWire= (xkbOutlineWireDesc *)(&shapeWire[1]); - for (o=0;o<shapeWire->nOutlines;o++) { - register int p; - XkbPointPtr pt; - xkbPointWireDesc * ptWire; - - ol= XkbAddGeomOutline(shape,olWire->nPoints); - if (!ol) - return BadAlloc; - ol->corner_radius= olWire->cornerRadius; - ptWire= (xkbPointWireDesc *)&olWire[1]; - for (p=0,pt=ol->points;p<olWire->nPoints;p++,pt++) { - pt->x= ptWire[p].x; - pt->y= ptWire[p].y; - if (client->swapped) { - register int n; - swaps(&pt->x,n); - swaps(&pt->y,n); - } - } - ol->num_points= olWire->nPoints; - olWire= (xkbOutlineWireDesc *)(&ptWire[olWire->nPoints]); - } - if (shapeWire->primaryNdx!=XkbNoShape) - shape->primary= &shape->outlines[shapeWire->primaryNdx]; - if (shapeWire->approxNdx!=XkbNoShape) - shape->approx= &shape->outlines[shapeWire->approxNdx]; - shapeWire= (xkbShapeWireDesc *)olWire; - } - wire= (char *)shapeWire; - } - if (geom->num_shapes!=req->nShapes) { - client->errorValue= _XkbErrCode3(0x07,geom->num_shapes,req->nShapes); - return BadMatch; - } - - *wire_inout= wire; - return Success; -} - -static Status -_CheckSetGeom( XkbGeometryPtr geom, - xkbSetGeometryReq * req, - ClientPtr client) -{ -register int i; -Status status; -char * wire; - - wire= (char *)&req[1]; - geom->label_font= _GetCountedString(&wire,client->swapped); - - for (i=0;i<req->nProperties;i++) { - char *name,*val; - name= _GetCountedString(&wire,client->swapped); - if (!name) - return BadAlloc; - val= _GetCountedString(&wire,client->swapped); - if (!val) { - xfree(name); - return BadAlloc; - } - if (XkbAddGeomProperty(geom,name,val)==NULL) { - xfree(name); - xfree(val); - return BadAlloc; - } - xfree(name); - xfree(val); - } - - if (req->nColors<2) { - client->errorValue= _XkbErrCode3(0x01,2,req->nColors); - return BadValue; - } - if (req->baseColorNdx>req->nColors) { - client->errorValue=_XkbErrCode3(0x03,req->nColors,req->baseColorNdx); - return BadMatch; - } - if (req->labelColorNdx>req->nColors) { - client->errorValue= _XkbErrCode3(0x03,req->nColors,req->labelColorNdx); - return BadMatch; - } - if (req->labelColorNdx==req->baseColorNdx) { - client->errorValue= _XkbErrCode3(0x04,req->baseColorNdx, - req->labelColorNdx); - return BadMatch; - } - - for (i=0;i<req->nColors;i++) { - char *name; - name= _GetCountedString(&wire,client->swapped); - if (!name) - return BadAlloc; - if (!XkbAddGeomColor(geom,name,geom->num_colors)) { - xfree(name); - return BadAlloc; - } - xfree(name); - } - if (req->nColors!=geom->num_colors) { - client->errorValue= _XkbErrCode3(0x05,req->nColors,geom->num_colors); - return BadMatch; - } - geom->label_color= &geom->colors[req->labelColorNdx]; - geom->base_color= &geom->colors[req->baseColorNdx]; - - if ((status=_CheckSetShapes(geom,req,&wire,client))!=Success) - return status; - - if ((status=_CheckSetSections(geom,req,&wire,client))!=Success) - return status; - - for (i=0;i<req->nDoodads;i++) { - status=_CheckSetDoodad(&wire,geom,NULL,client); - if (status!=Success) - return status; - } - - for (i=0;i<req->nKeyAliases;i++) { - if (XkbAddGeomKeyAlias(geom,&wire[XkbKeyNameLength],wire)==NULL) - return BadAlloc; - wire+= 2*XkbKeyNameLength; - } - return Success; -} - -static int -_XkbSetGeometry(ClientPtr client, DeviceIntPtr dev, xkbSetGeometryReq *stuff) -{ - XkbDescPtr xkb; - Bool new_name; - xkbNewKeyboardNotify nkn; - XkbGeometryPtr geom,old; - XkbGeometrySizesRec sizes; - Status status; - - xkb= dev->key->xkbInfo->desc; - old= xkb->geom; - xkb->geom= NULL; - - sizes.which= XkbGeomAllMask; - sizes.num_properties= stuff->nProperties; - sizes.num_colors= stuff->nColors; - sizes.num_shapes= stuff->nShapes; - sizes.num_sections= stuff->nSections; - sizes.num_doodads= stuff->nDoodads; - sizes.num_key_aliases= stuff->nKeyAliases; - if ((status= XkbAllocGeometry(xkb,&sizes))!=Success) { - xkb->geom= old; - return status; - } - geom= xkb->geom; - geom->name= stuff->name; - geom->width_mm= stuff->widthMM; - geom->height_mm= stuff->heightMM; - if ((status= _CheckSetGeom(geom,stuff,client))!=Success) { - XkbFreeGeometry(geom,XkbGeomAllMask,TRUE); - xkb->geom= old; - return status; - } - new_name= (xkb->names->geometry!=geom->name); - xkb->names->geometry= geom->name; - if (old) - XkbFreeGeometry(old,XkbGeomAllMask,TRUE); - if (new_name) { - xkbNamesNotify nn; - bzero(&nn,sizeof(xkbNamesNotify)); - nn.changed= XkbGeometryNameMask; - XkbSendNamesNotify(dev,&nn); - } - nkn.deviceID= nkn.oldDeviceID= dev->id; - nkn.minKeyCode= nkn.oldMinKeyCode= xkb->min_key_code; - nkn.maxKeyCode= nkn.oldMaxKeyCode= xkb->max_key_code; - nkn.requestMajor= XkbReqCode; - nkn.requestMinor= X_kbSetGeometry; - nkn.changed= XkbNKN_GeometryMask; - XkbSendNewKeyboardNotify(dev,&nkn); - return Success; -} - -int -ProcXkbSetGeometry(ClientPtr client) -{ - DeviceIntPtr dev; - int rc; - - REQUEST(xkbSetGeometryReq); - REQUEST_AT_LEAST_SIZE(xkbSetGeometryReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); - CHK_ATOM_OR_NONE(stuff->name); - - rc = _XkbSetGeometry(client, dev, stuff); - if (rc != Success) - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) - { - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); - if (rc == Success) - _XkbSetGeometry(client, other, stuff); - } - } - } - - return Success; -} - -/***====================================================================***/ - -int -ProcXkbPerClientFlags(ClientPtr client) -{ - DeviceIntPtr dev; - xkbPerClientFlagsReply rep; - XkbInterestPtr interest; - Mask access_mode = DixGetAttrAccess | DixSetAttrAccess; - - REQUEST(xkbPerClientFlagsReq); - REQUEST_SIZE_MATCH(xkbPerClientFlagsReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, access_mode); - CHK_MASK_LEGAL(0x01,stuff->change,XkbPCF_AllFlagsMask); - CHK_MASK_MATCH(0x02,stuff->change,stuff->value); - - interest = XkbFindClientResource((DevicePtr)dev,client); - memset(&rep, 0, sizeof(xkbPerClientFlagsReply)); - rep.type= X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - if (stuff->change) { - client->xkbClientFlags&= ~stuff->change; - client->xkbClientFlags|= stuff->value; - } - if (stuff->change&XkbPCF_AutoResetControlsMask) { - Bool want; - want= stuff->value&XkbPCF_AutoResetControlsMask; - if (interest && !want) { - interest->autoCtrls= interest->autoCtrlValues= 0; - } - else if (want && (!interest)) { - XID id = FakeClientID(client->index); - AddResource(id,RT_XKBCLIENT,dev); - interest= XkbAddClientResource((DevicePtr)dev,client,id); - if (!interest) - return BadAlloc; - } - if (interest && want ) { - register unsigned affect; - affect= stuff->ctrlsToChange; - - CHK_MASK_LEGAL(0x03,affect,XkbAllBooleanCtrlsMask); - CHK_MASK_MATCH(0x04,affect,stuff->autoCtrls); - CHK_MASK_MATCH(0x05,stuff->autoCtrls,stuff->autoCtrlValues); - - interest->autoCtrls&= ~affect; - interest->autoCtrlValues&= ~affect; - interest->autoCtrls|= stuff->autoCtrls&affect; - interest->autoCtrlValues|= stuff->autoCtrlValues&affect; - } - } - rep.supported = XkbPCF_AllFlagsMask; - rep.value= client->xkbClientFlags&XkbPCF_AllFlagsMask; - if (interest) { - rep.autoCtrls= interest->autoCtrls; - rep.autoCtrlValues= interest->autoCtrlValues; - } - else { - rep.autoCtrls= rep.autoCtrlValues= 0; - } - if ( client->swapped ) { - register int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.supported,n); - swapl(&rep.value,n); - swapl(&rep.autoCtrls,n); - swapl(&rep.autoCtrlValues,n); - } - WriteToClient(client,SIZEOF(xkbPerClientFlagsReply), (char *)&rep); - return client->noClientException; -} - -/***====================================================================***/ - -/* all latin-1 alphanumerics, plus parens, minus, underscore, slash */ -/* and wildcards */ -static unsigned char componentSpecLegal[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x87, - 0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff -}; - -/* same as above but accepts percent, plus and bar too */ -static unsigned char componentExprLegal[] = { - 0x00, 0x00, 0x00, 0x00, 0x20, 0xaf, 0xff, 0x87, - 0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x17, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff -}; - -static char * -GetComponentSpec(unsigned char **pWire,Bool allowExpr,int *errRtrn) -{ -int len; -register int i; -unsigned char *wire,*str,*tmp,*legal; - - if (allowExpr) legal= &componentExprLegal[0]; - else legal= &componentSpecLegal[0]; - - wire= *pWire; - len= (*(unsigned char *)wire++); - if (len>0) { - str= xcalloc(1, len+1); - if (str) { - tmp= str; - for (i=0;i<len;i++) { - if (legal[(*wire)/8]&(1<<((*wire)%8))) - *tmp++= *wire++; - else wire++; - } - if (tmp!=str) - *tmp++= '\0'; - else { - xfree(str); - str= NULL; - } - } - else { - *errRtrn= BadAlloc; - } - } - else { - str= NULL; - } - *pWire= wire; - return (char *)str; -} - -/***====================================================================***/ - -int -ProcXkbListComponents(ClientPtr client) -{ - DeviceIntPtr dev; - xkbListComponentsReply rep; - unsigned len; - int status; - unsigned char * str; - XkbSrvListInfoRec list; - - REQUEST(xkbListComponentsReq); - REQUEST_AT_LEAST_SIZE(xkbListComponentsReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); - - status= Success; - str= (unsigned char *)&stuff[1]; - bzero(&list,sizeof(XkbSrvListInfoRec)); - list.maxRtrn= stuff->maxNames; - list.pattern[_XkbListKeycodes]= GetComponentSpec(&str,FALSE,&status); - list.pattern[_XkbListTypes]= GetComponentSpec(&str,FALSE,&status); - list.pattern[_XkbListCompat]= GetComponentSpec(&str,FALSE,&status); - list.pattern[_XkbListSymbols]= GetComponentSpec(&str,FALSE,&status); - list.pattern[_XkbListGeometry]= GetComponentSpec(&str,FALSE,&status); - if (status!=Success) - return status; - len= str-((unsigned char *)stuff); - if ((XkbPaddedSize(len)/4)!=stuff->length) - return BadLength; - if ((status=XkbDDXList(dev,&list,client))!=Success) { - if (list.pool) { - xfree(list.pool); - list.pool= NULL; - } - return status; - } - bzero(&rep,sizeof(xkbListComponentsReply)); - rep.type= X_Reply; - rep.deviceID = dev->id; - rep.sequenceNumber = client->sequence; - rep.length = XkbPaddedSize(list.nPool)/4; - rep.nKeymaps = 0; - rep.nKeycodes = list.nFound[_XkbListKeycodes]; - rep.nTypes = list.nFound[_XkbListTypes]; - rep.nCompatMaps = list.nFound[_XkbListCompat]; - rep.nSymbols = list.nFound[_XkbListSymbols]; - rep.nGeometries = list.nFound[_XkbListGeometry]; - rep.extra= 0; - if (list.nTotal>list.maxRtrn) - rep.extra = (list.nTotal-list.maxRtrn); - if (client->swapped) { - register int n; - swaps(&rep.sequenceNumber,n); - swapl(&rep.length,n); - swaps(&rep.nKeymaps,n); - swaps(&rep.nKeycodes,n); - swaps(&rep.nTypes,n); - swaps(&rep.nCompatMaps,n); - swaps(&rep.nSymbols,n); - swaps(&rep.nGeometries,n); - swaps(&rep.extra,n); - } - WriteToClient(client,SIZEOF(xkbListComponentsReply),(char *)&rep); - if (list.nPool && list.pool) { - WriteToClient(client,XkbPaddedSize(list.nPool), (char *)list.pool); - xfree(list.pool); - list.pool= NULL; - } - return client->noClientException; -} - -/***====================================================================***/ - -int -ProcXkbGetKbdByName(ClientPtr client) -{ - DeviceIntPtr dev; - DeviceIntPtr tmpd; - xkbGetKbdByNameReply rep; - xkbGetMapReply mrep; - xkbGetCompatMapReply crep; - xkbGetIndicatorMapReply irep; - xkbGetNamesReply nrep; - xkbGetGeometryReply grep; - XkbComponentNamesRec names; - XkbDescPtr xkb, new; - unsigned char * str; - char mapFile[PATH_MAX]; - unsigned len; - unsigned fwant,fneed,reported; - int status; - Bool geom_changed; - XkbSrvLedInfoPtr old_sli; - XkbSrvLedInfoPtr sli; - Mask access_mode = DixGetAttrAccess | DixManageAccess; - - REQUEST(xkbGetKbdByNameReq); - REQUEST_AT_LEAST_SIZE(xkbGetKbdByNameReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, access_mode); - - xkb = dev->key->xkbInfo->desc; - status= Success; - str= (unsigned char *)&stuff[1]; - if (GetComponentSpec(&str,TRUE,&status)) /* keymap, unsupported */ - return BadMatch; - names.keycodes= GetComponentSpec(&str,TRUE,&status); - names.types= GetComponentSpec(&str,TRUE,&status); - names.compat= GetComponentSpec(&str,TRUE,&status); - names.symbols= GetComponentSpec(&str,TRUE,&status); - names.geometry= GetComponentSpec(&str,TRUE,&status); - if (status!=Success) - return status; - len= str-((unsigned char *)stuff); - if ((XkbPaddedSize(len)/4)!=stuff->length) - return BadLength; - - CHK_MASK_LEGAL(0x01,stuff->want,XkbGBN_AllComponentsMask); - CHK_MASK_LEGAL(0x02,stuff->need,XkbGBN_AllComponentsMask); - - if (stuff->load) - fwant= XkbGBN_AllComponentsMask; - else fwant= stuff->want|stuff->need; - if ((!names.compat)&& - (fwant&(XkbGBN_CompatMapMask|XkbGBN_IndicatorMapMask))) { - names.compat= _XkbDupString("%"); - } - if ((!names.types)&&(fwant&(XkbGBN_TypesMask))) { - names.types= _XkbDupString("%"); - } - if ((!names.symbols)&&(fwant&XkbGBN_SymbolsMask)) { - names.symbols= _XkbDupString("%"); - } - geom_changed= ((names.geometry!=NULL)&&(strcmp(names.geometry,"%")!=0)); - if ((!names.geometry)&&(fwant&XkbGBN_GeometryMask)) { - names.geometry= _XkbDupString("%"); - geom_changed= FALSE; - } - - bzero(mapFile,PATH_MAX); - rep.type= X_Reply; - rep.deviceID = dev->id; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.minKeyCode = xkb->min_key_code; - rep.maxKeyCode = xkb->max_key_code; - rep.loaded= FALSE; - fwant= XkbConvertGetByNameComponents(TRUE,stuff->want)|XkmVirtualModsMask; - fneed= XkbConvertGetByNameComponents(TRUE,stuff->need); - rep.reported= XkbConvertGetByNameComponents(FALSE,fwant|fneed); - if (stuff->load) { - fneed|= XkmKeymapRequired; - fwant|= XkmKeymapLegal; - } - if ((fwant|fneed)&XkmSymbolsMask) { - fneed|= XkmKeyNamesIndex|XkmTypesIndex; - fwant|= XkmIndicatorsIndex; - } - - /* We pass dev in here so we can get the old names out if needed. */ - rep.found = XkbDDXLoadKeymapByNames(dev,&names,fwant,fneed,&new, - mapFile,PATH_MAX); - rep.newKeyboard= FALSE; - rep.pad1= rep.pad2= rep.pad3= rep.pad4= 0; - - stuff->want|= stuff->need; - if (new==NULL) - rep.reported= 0; - else { - if (stuff->load) - rep.loaded= TRUE; - if (stuff->load || - ((rep.reported&XkbGBN_SymbolsMask) && (new->compat))) { - XkbChangesRec changes; - bzero(&changes,sizeof(changes)); - XkbUpdateDescActions(new, - new->min_key_code,XkbNumKeys(new), - &changes); - } - - if (new->map==NULL) - rep.reported&= ~(XkbGBN_SymbolsMask|XkbGBN_TypesMask); - else if (rep.reported&(XkbGBN_SymbolsMask|XkbGBN_TypesMask)) { - mrep.type= X_Reply; - mrep.deviceID = dev->id; - mrep.sequenceNumber= client->sequence; - mrep.length = ((SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply))>>2); - mrep.minKeyCode = new->min_key_code; - mrep.maxKeyCode = new->max_key_code; - mrep.present = 0; - mrep.totalSyms = mrep.totalActs = - mrep.totalKeyBehaviors= mrep.totalKeyExplicit= - mrep.totalModMapKeys= mrep.totalVModMapKeys= 0; - if (rep.reported&(XkbGBN_TypesMask|XkbGBN_ClientSymbolsMask)) { - mrep.present|= XkbKeyTypesMask; - mrep.firstType = 0; - mrep.nTypes = mrep.totalTypes= new->map->num_types; - } - else { - mrep.firstType = mrep.nTypes= 0; - mrep.totalTypes= 0; - } - if (rep.reported&XkbGBN_ClientSymbolsMask) { - mrep.present|= (XkbKeySymsMask|XkbModifierMapMask); - mrep.firstKeySym = mrep.firstModMapKey= new->min_key_code; - mrep.nKeySyms = mrep.nModMapKeys= XkbNumKeys(new); - } - else { - mrep.firstKeySym= mrep.firstModMapKey= 0; - mrep.nKeySyms= mrep.nModMapKeys= 0; - } - if (rep.reported&XkbGBN_ServerSymbolsMask) { - mrep.present|= XkbAllServerInfoMask; - mrep.virtualMods= ~0; - mrep.firstKeyAct = mrep.firstKeyBehavior = - mrep.firstKeyExplicit = new->min_key_code; - mrep.nKeyActs = mrep.nKeyBehaviors = - mrep.nKeyExplicit = XkbNumKeys(new); - mrep.firstVModMapKey= new->min_key_code; - mrep.nVModMapKeys= XkbNumKeys(new); - } - else { - mrep.virtualMods= 0; - mrep.firstKeyAct= mrep.firstKeyBehavior= - mrep.firstKeyExplicit = 0; - mrep.nKeyActs= mrep.nKeyBehaviors= mrep.nKeyExplicit= 0; - } - XkbComputeGetMapReplySize(new,&mrep); - rep.length+= SIZEOF(xGenericReply)/4+mrep.length; - } - if (new->compat==NULL) - rep.reported&= ~XkbGBN_CompatMapMask; - else if (rep.reported&XkbGBN_CompatMapMask) { - crep.type= X_Reply; - crep.deviceID= dev->id; - crep.sequenceNumber= client->sequence; - crep.length= 0; - crep.groups= XkbAllGroupsMask; - crep.firstSI= 0; - crep.nSI= crep.nTotalSI= new->compat->num_si; - XkbComputeGetCompatMapReplySize(new->compat,&crep); - rep.length+= SIZEOF(xGenericReply)/4+crep.length; - } - if (new->indicators==NULL) - rep.reported&= ~XkbGBN_IndicatorMapMask; - else if (rep.reported&XkbGBN_IndicatorMapMask) { - irep.type= X_Reply; - irep.deviceID= dev->id; - irep.sequenceNumber= client->sequence; - irep.length= 0; - irep.which= XkbAllIndicatorsMask; - XkbComputeGetIndicatorMapReplySize(new->indicators,&irep); - rep.length+= SIZEOF(xGenericReply)/4+irep.length; - } - if (new->names==NULL) - rep.reported&= ~(XkbGBN_OtherNamesMask|XkbGBN_KeyNamesMask); - else if (rep.reported&(XkbGBN_OtherNamesMask|XkbGBN_KeyNamesMask)) { - nrep.type= X_Reply; - nrep.deviceID= dev->id; - nrep.sequenceNumber= client->sequence; - nrep.length= 0; - nrep.minKeyCode= new->min_key_code; - nrep.maxKeyCode= new->max_key_code; - if (rep.reported&XkbGBN_OtherNamesMask) { - nrep.which= XkbAllNamesMask; - if (new->map!=NULL) - nrep.nTypes= new->map->num_types; - else nrep.nTypes= 0; - nrep.nKTLevels= 0; - nrep.groupNames= XkbAllGroupsMask; - nrep.virtualMods= XkbAllVirtualModsMask; - nrep.indicators= XkbAllIndicatorsMask; - nrep.nRadioGroups= new->names->num_rg; - } - else { - nrep.which= 0; - nrep.nTypes= 0; - nrep.nKTLevels= 0; - nrep.groupNames= 0; - nrep.virtualMods= 0; - nrep.indicators= 0; - nrep.nRadioGroups= 0; - } - if (rep.reported&XkbGBN_KeyNamesMask) { - nrep.which|= XkbKeyNamesMask; - nrep.firstKey= new->min_key_code; - nrep.nKeys= XkbNumKeys(new); - nrep.nKeyAliases= new->names->num_key_aliases; - if (nrep.nKeyAliases) - nrep.which|= XkbKeyAliasesMask; - } - else { - nrep.which&= ~(XkbKeyNamesMask|XkbKeyAliasesMask); - nrep.firstKey= nrep.nKeys= 0; - nrep.nKeyAliases= 0; - } - XkbComputeGetNamesReplySize(new,&nrep); - rep.length+= SIZEOF(xGenericReply)/4+nrep.length; - } - if (new->geom==NULL) - rep.reported&= ~XkbGBN_GeometryMask; - else if (rep.reported&XkbGBN_GeometryMask) { - grep.type= X_Reply; - grep.deviceID= dev->id; - grep.sequenceNumber= client->sequence; - grep.length= 0; - grep.found= TRUE; - grep.pad= 0; - grep.widthMM= grep.heightMM= 0; - grep.nProperties= grep.nColors= grep.nShapes= 0; - grep.nSections= grep.nDoodads= 0; - grep.baseColorNdx= grep.labelColorNdx= 0; - XkbComputeGetGeometryReplySize(new->geom,&grep,None); - rep.length+= SIZEOF(xGenericReply)/4+grep.length; - } - } - - reported= rep.reported; - if ( client->swapped ) { - register int n; - swaps(&rep.sequenceNumber,n); - swapl(&rep.length,n); - swaps(&rep.found,n); - swaps(&rep.reported,n); - } - WriteToClient(client,SIZEOF(xkbGetKbdByNameReply), (char *)&rep); - if (reported&(XkbGBN_SymbolsMask|XkbGBN_TypesMask)) - XkbSendMap(client,new,&mrep); - if (reported&XkbGBN_CompatMapMask) - XkbSendCompatMap(client,new->compat,&crep); - if (reported&XkbGBN_IndicatorMapMask) - XkbSendIndicatorMap(client,new->indicators,&irep); - if (reported&(XkbGBN_KeyNamesMask|XkbGBN_OtherNamesMask)) - XkbSendNames(client,new,&nrep); - if (reported&XkbGBN_GeometryMask) - XkbSendGeometry(client,new->geom,&grep,FALSE); - if (rep.loaded) { - XkbDescPtr old_xkb; - xkbNewKeyboardNotify nkn; - int i,nG,nTG; - old_xkb= xkb; - xkb= new; - dev->key->xkbInfo->desc= xkb; - new= old_xkb; /* so it'll get freed automatically */ - - *xkb->ctrls= *old_xkb->ctrls; - for (nG=nTG=0,i=xkb->min_key_code;i<=xkb->max_key_code;i++) { - nG= XkbKeyNumGroups(xkb,i); - if (nG>=XkbNumKbdGroups) { - nTG= XkbNumKbdGroups; - break; - } - if (nG>nTG) { - nTG= nG; - } - } - xkb->ctrls->num_groups= nTG; - - for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) { - if ((tmpd == dev) || (!IsMaster(tmpd) && tmpd->u.master == dev)) { - if (tmpd != dev) - XkbCopyDeviceKeymap(tmpd, dev); - - if (tmpd->kbdfeed && tmpd->kbdfeed->xkb_sli) { - old_sli = tmpd->kbdfeed->xkb_sli; - tmpd->kbdfeed->xkb_sli = NULL; - sli = XkbAllocSrvLedInfo(tmpd, tmpd->kbdfeed, NULL, 0); - if (sli) { - sli->explicitState = old_sli->explicitState; - sli->effectiveState = old_sli->effectiveState; - } - tmpd->kbdfeed->xkb_sli = sli; - XkbFreeSrvLedInfo(old_sli); - } - } - } - - nkn.deviceID= nkn.oldDeviceID= dev->id; - nkn.minKeyCode= new->min_key_code; - nkn.maxKeyCode= new->max_key_code; - nkn.oldMinKeyCode= xkb->min_key_code; - nkn.oldMaxKeyCode= xkb->max_key_code; - nkn.requestMajor= XkbReqCode; - nkn.requestMinor= X_kbGetKbdByName; - nkn.changed= XkbNKN_KeycodesMask; - if (geom_changed) - nkn.changed|= XkbNKN_GeometryMask; - XkbSendNewKeyboardNotify(dev,&nkn); - - if (!IsMaster(dev) && dev->u.master) - { - DeviceIntPtr master = dev->u.master; - if (master->u.lastSlave == dev) - { - XkbCopyDeviceKeymap(dev->u.master, dev); - XkbSendNewKeyboardNotify(dev,&nkn); - } - } - } - if ((new!=NULL)&&(new!=xkb)) { - XkbFreeKeyboard(new,XkbAllComponentsMask,TRUE); - new= NULL; - } - if (names.keycodes) { xfree(names.keycodes); names.keycodes= NULL; } - if (names.types) { xfree(names.types); names.types= NULL; } - if (names.compat) { xfree(names.compat); names.compat= NULL; } - if (names.symbols) { xfree(names.symbols); names.symbols= NULL; } - if (names.geometry) { xfree(names.geometry); names.geometry= NULL; } - return client->noClientException; -} - -/***====================================================================***/ - -static int -ComputeDeviceLedInfoSize( DeviceIntPtr dev, - unsigned int what, - XkbSrvLedInfoPtr sli) -{ -int nNames,nMaps; -register unsigned n,bit; - - if (sli==NULL) - return 0; - nNames= nMaps= 0; - if ((what&XkbXI_IndicatorNamesMask)==0) - sli->namesPresent= 0; - if ((what&XkbXI_IndicatorMapsMask)==0) - sli->mapsPresent= 0; - - for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) { - if (sli->names && sli->names[n]!=None) { - sli->namesPresent|= bit; - nNames++; - } - if (sli->maps && XkbIM_InUse(&sli->maps[n])) { - sli->mapsPresent|= bit; - nMaps++; - } - } - return (nNames*4)+(nMaps*SIZEOF(xkbIndicatorMapWireDesc)); -} - -static int -CheckDeviceLedFBs( DeviceIntPtr dev, - int class, - int id, - xkbGetDeviceInfoReply * rep, - ClientPtr client) -{ -int nFBs= 0; -int length= 0; -Bool classOk; - - if (class==XkbDfltXIClass) { - if (dev->kbdfeed) class= KbdFeedbackClass; - else if (dev->leds) class= LedFeedbackClass; - else { - client->errorValue= _XkbErrCode2(XkbErr_BadClass,class); - return XkbKeyboardErrorCode; - } - } - classOk= FALSE; - if ((dev->kbdfeed)&&((class==KbdFeedbackClass)||(class==XkbAllXIClasses))) { - KbdFeedbackPtr kf; - classOk= TRUE; - for (kf= dev->kbdfeed;(kf);kf=kf->next) { - if ((id!=XkbAllXIIds)&&(id!=XkbDfltXIId)&&(id!=kf->ctrl.id)) - continue; - nFBs++; - length+= SIZEOF(xkbDeviceLedsWireDesc); - if (!kf->xkb_sli) - kf->xkb_sli= XkbAllocSrvLedInfo(dev,kf,NULL,0); - length+= ComputeDeviceLedInfoSize(dev,rep->present,kf->xkb_sli); - if (id!=XkbAllXIIds) - break; - } - } - if ((dev->leds)&&((class==LedFeedbackClass)||(class==XkbAllXIClasses))) { - LedFeedbackPtr lf; - classOk= TRUE; - for (lf= dev->leds;(lf);lf=lf->next) { - if ((id!=XkbAllXIIds)&&(id!=XkbDfltXIId)&&(id!=lf->ctrl.id)) - continue; - nFBs++; - length+= SIZEOF(xkbDeviceLedsWireDesc); - if (!lf->xkb_sli) - lf->xkb_sli= XkbAllocSrvLedInfo(dev,NULL,lf,0); - length+= ComputeDeviceLedInfoSize(dev,rep->present,lf->xkb_sli); - if (id!=XkbAllXIIds) - break; - } - } - if (nFBs>0) { - rep->nDeviceLedFBs= nFBs; - rep->length+= (length/4); - return Success; - } - if (classOk) client->errorValue= _XkbErrCode2(XkbErr_BadId,id); - else client->errorValue= _XkbErrCode2(XkbErr_BadClass,class); - return XkbKeyboardErrorCode; -} - -static int -SendDeviceLedInfo( XkbSrvLedInfoPtr sli, - ClientPtr client) -{ -xkbDeviceLedsWireDesc wire; -int length; - - length= 0; - wire.ledClass= sli->class; - wire.ledID= sli->id; - wire.namesPresent= sli->namesPresent; - wire.mapsPresent= sli->mapsPresent; - wire.physIndicators= sli->physIndicators; - wire.state= sli->effectiveState; - if (client->swapped) { - register int n; - swaps(&wire.ledClass,n); - swaps(&wire.ledID,n); - swapl(&wire.namesPresent,n); - swapl(&wire.mapsPresent,n); - swapl(&wire.physIndicators,n); - swapl(&wire.state,n); - } - WriteToClient(client,SIZEOF(xkbDeviceLedsWireDesc),(char *)&wire); - length+= SIZEOF(xkbDeviceLedsWireDesc); - if (sli->namesPresent|sli->mapsPresent) { - register unsigned i,bit; - if (sli->namesPresent) { - CARD32 awire; - for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { - if (sli->namesPresent&bit) { - awire= (CARD32)sli->names[i]; - if (client->swapped) { - register int n; - swapl(&awire,n); - } - WriteToClient(client,4,(char *)&awire); - length+= 4; - } - } - } - if (sli->mapsPresent) { - for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { - xkbIndicatorMapWireDesc iwire; - if (sli->mapsPresent&bit) { - iwire.flags= sli->maps[i].flags; - iwire.whichGroups= sli->maps[i].which_groups; - iwire.groups= sli->maps[i].groups; - iwire.whichMods= sli->maps[i].which_mods; - iwire.mods= sli->maps[i].mods.mask; - iwire.realMods= sli->maps[i].mods.real_mods; - iwire.virtualMods= sli->maps[i].mods.vmods; - iwire.ctrls= sli->maps[i].ctrls; - if (client->swapped) { - register int n; - swaps(&iwire.virtualMods,n); - swapl(&iwire.ctrls,n); - } - WriteToClient(client,SIZEOF(xkbIndicatorMapWireDesc), - (char *)&iwire); - length+= SIZEOF(xkbIndicatorMapWireDesc); - } - } - } - } - return length; -} - -static int -SendDeviceLedFBs( DeviceIntPtr dev, - int class, - int id, - unsigned wantLength, - ClientPtr client) -{ -int length= 0; - - if (class==XkbDfltXIClass) { - if (dev->kbdfeed) class= KbdFeedbackClass; - else if (dev->leds) class= LedFeedbackClass; - } - if ((dev->kbdfeed)&& - ((class==KbdFeedbackClass)||(class==XkbAllXIClasses))) { - KbdFeedbackPtr kf; - for (kf= dev->kbdfeed;(kf);kf=kf->next) { - if ((id==XkbAllXIIds)||(id==XkbDfltXIId)||(id==kf->ctrl.id)) { - length+= SendDeviceLedInfo(kf->xkb_sli,client); - if (id!=XkbAllXIIds) - break; - } - } - } - if ((dev->leds)&& - ((class==LedFeedbackClass)||(class==XkbAllXIClasses))) { - LedFeedbackPtr lf; - for (lf= dev->leds;(lf);lf=lf->next) { - if ((id==XkbAllXIIds)||(id==XkbDfltXIId)||(id==lf->ctrl.id)) { - length+= SendDeviceLedInfo(lf->xkb_sli,client); - if (id!=XkbAllXIIds) - break; - } - } - } - if (length==wantLength) - return Success; - else return BadLength; -} - -int -ProcXkbGetDeviceInfo(ClientPtr client) -{ -DeviceIntPtr dev; -xkbGetDeviceInfoReply rep; -int status,nDeviceLedFBs; -unsigned length,nameLen; -CARD16 ledClass,ledID; -unsigned wanted; -char * str; - - REQUEST(xkbGetDeviceInfoReq); - REQUEST_SIZE_MATCH(xkbGetDeviceInfoReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - wanted= stuff->wanted; - - CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); - CHK_MASK_LEGAL(0x01,wanted,XkbXI_AllDeviceFeaturesMask); - - if ((!dev->button)||((stuff->nBtns<1)&&(!stuff->allBtns))) - wanted&= ~XkbXI_ButtonActionsMask; - if ((!dev->kbdfeed)&&(!dev->leds)) - wanted&= ~XkbXI_IndicatorsMask; - - nameLen= XkbSizeCountedString(dev->name); - bzero((char *)&rep,SIZEOF(xkbGetDeviceInfoReply)); - rep.type = X_Reply; - rep.deviceID= dev->id; - rep.sequenceNumber = client->sequence; - rep.length = nameLen/4; - rep.present = wanted; - rep.supported = XkbXI_AllDeviceFeaturesMask; - rep.unsupported = 0; - rep.firstBtnWanted = rep.nBtnsWanted = 0; - rep.firstBtnRtrn = rep.nBtnsRtrn = 0; - if (dev->button) - rep.totalBtns= dev->button->numButtons; - else rep.totalBtns= 0; - rep.devType= dev->xinput_type; - rep.hasOwnState= (dev->key && dev->key->xkbInfo); - rep.nDeviceLedFBs = 0; - if (dev->kbdfeed) rep.dfltKbdFB= dev->kbdfeed->ctrl.id; - else rep.dfltKbdFB= XkbXINone; - if (dev->leds) rep.dfltLedFB= dev->leds->ctrl.id; - else rep.dfltLedFB= XkbXINone; - - ledClass= stuff->ledClass; - ledID= stuff->ledID; - - rep.firstBtnWanted= rep.nBtnsWanted= 0; - rep.firstBtnRtrn= rep.nBtnsRtrn= 0; - if (wanted&XkbXI_ButtonActionsMask) { - if (stuff->allBtns) { - stuff->firstBtn= 0; - stuff->nBtns= dev->button->numButtons; - } - - if ((stuff->firstBtn+stuff->nBtns)>dev->button->numButtons) { - client->errorValue = _XkbErrCode4(0x02,dev->button->numButtons, - stuff->firstBtn, - stuff->nBtns); - return BadValue; - } - else { - rep.firstBtnWanted= stuff->firstBtn; - rep.nBtnsWanted= stuff->nBtns; - if (dev->button->xkb_acts!=NULL) { - XkbAction *act; - register int i; - - rep.firstBtnRtrn= stuff->firstBtn; - rep.nBtnsRtrn= stuff->nBtns; - act= &dev->button->xkb_acts[rep.firstBtnWanted]; - for (i=0;i<rep.nBtnsRtrn;i++,act++) { - if (act->type!=XkbSA_NoAction) - break; - } - rep.firstBtnRtrn+= i; - rep.nBtnsRtrn-= i; - act= &dev->button->xkb_acts[rep.firstBtnRtrn+rep.nBtnsRtrn-1]; - for (i=0;i<rep.nBtnsRtrn;i++,act--) { - if (act->type!=XkbSA_NoAction) - break; - } - rep.nBtnsRtrn-= i; - } - rep.length+= (rep.nBtnsRtrn*SIZEOF(xkbActionWireDesc))/4; - } - } - - if (wanted&XkbXI_IndicatorsMask) { - status= CheckDeviceLedFBs(dev,ledClass,ledID,&rep,client); - if (status!=Success) - return status; - } - length= rep.length*4; - nDeviceLedFBs = rep.nDeviceLedFBs; - if (client->swapped) { - register int n; - swaps(&rep.sequenceNumber,n); - swapl(&rep.length,n); - swaps(&rep.present,n); - swaps(&rep.supported,n); - swaps(&rep.unsupported,n); - swaps(&rep.nDeviceLedFBs,n); - swapl(&rep.type,n); - } - WriteToClient(client,SIZEOF(xkbGetDeviceInfoReply), (char *)&rep); - - str= xalloc(nameLen); - if (!str) - return BadAlloc; - XkbWriteCountedString(str,dev->name,client->swapped); - WriteToClient(client,nameLen,str); - xfree(str); - length-= nameLen; - - if (rep.nBtnsRtrn>0) { - int sz; - xkbActionWireDesc * awire; - sz= rep.nBtnsRtrn*SIZEOF(xkbActionWireDesc); - awire= (xkbActionWireDesc *)&dev->button->xkb_acts[rep.firstBtnRtrn]; - WriteToClient(client,sz,(char *)awire); - length-= sz; - } - if (nDeviceLedFBs>0) { - status= SendDeviceLedFBs(dev,ledClass,ledID,length,client); - if (status!=Success) - return status; - } - else if (length!=0) { - ErrorF("[xkb] Internal Error! BadLength in ProcXkbGetDeviceInfo\n"); - ErrorF("[xkb] Wrote %d fewer bytes than expected\n",length); - return BadLength; - } - return client->noClientException; -} - -static char * -CheckSetDeviceIndicators( char * wire, - DeviceIntPtr dev, - int num, - int * status_rtrn, - ClientPtr client) -{ -xkbDeviceLedsWireDesc * ledWire; -int i; -XkbSrvLedInfoPtr sli; - - ledWire= (xkbDeviceLedsWireDesc *)wire; - for (i=0;i<num;i++) { - if (client->swapped) { - register int n; - swaps(&ledWire->ledClass,n); - swaps(&ledWire->ledID,n); - swapl(&ledWire->namesPresent,n); - swapl(&ledWire->mapsPresent,n); - swapl(&ledWire->physIndicators,n); - } - - sli= XkbFindSrvLedInfo(dev,ledWire->ledClass,ledWire->ledID, - XkbXI_IndicatorsMask); - if (sli!=NULL) { - register int n; - register unsigned bit; - int nMaps,nNames; - CARD32 *atomWire; - xkbIndicatorMapWireDesc *mapWire; - - nMaps= nNames= 0; - for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) { - if (ledWire->namesPresent&bit) - nNames++; - if (ledWire->mapsPresent&bit) - nMaps++; - } - atomWire= (CARD32 *)&ledWire[1]; - if (nNames>0) { - for (n=0;n<nNames;n++) { - if (client->swapped) { - register int t; - swapl(atomWire,t); - } - CHK_ATOM_OR_NONE3(((Atom)(*atomWire)),client->errorValue, - *status_rtrn,NULL); - atomWire++; - } - } - mapWire= (xkbIndicatorMapWireDesc *)atomWire; - if (nMaps>0) { - for (n=0;n<nMaps;n++) { - if (client->swapped) { - register int t; - swaps(&mapWire->virtualMods,t); - swapl(&mapWire->ctrls,t); - } - CHK_MASK_LEGAL3(0x21,mapWire->whichGroups, - XkbIM_UseAnyGroup, - client->errorValue, - *status_rtrn,NULL); - CHK_MASK_LEGAL3(0x22,mapWire->whichMods,XkbIM_UseAnyMods, - client->errorValue, - *status_rtrn,NULL); - mapWire++; - } - } - ledWire= (xkbDeviceLedsWireDesc *)mapWire; - } - else { - /* SHOULD NEVER HAPPEN */ - return (char *)ledWire; - } - } - return (char *)ledWire; -} - -static char * -SetDeviceIndicators( char * wire, - DeviceIntPtr dev, - unsigned changed, - int num, - int * status_rtrn, - ClientPtr client, - xkbExtensionDeviceNotify *ev) -{ -xkbDeviceLedsWireDesc * ledWire; -int i; -XkbEventCauseRec cause; -unsigned namec,mapc,statec; -xkbExtensionDeviceNotify ed; -XkbChangesRec changes; -DeviceIntPtr kbd; - - bzero((char *)&ed,sizeof(xkbExtensionDeviceNotify)); - bzero((char *)&changes,sizeof(XkbChangesRec)); - XkbSetCauseXkbReq(&cause,X_kbSetDeviceInfo,client); - ledWire= (xkbDeviceLedsWireDesc *)wire; - for (i=0;i<num;i++) { - register int n; - register unsigned bit; - CARD32 * atomWire; - xkbIndicatorMapWireDesc * mapWire; - XkbSrvLedInfoPtr sli; - - namec= mapc= statec= 0; - sli= XkbFindSrvLedInfo(dev,ledWire->ledClass,ledWire->ledID, - XkbXI_IndicatorMapsMask); - if (!sli) { - /* SHOULD NEVER HAPPEN!! */ - return (char *)ledWire; - } - - atomWire= (CARD32 *)&ledWire[1]; - if (changed&XkbXI_IndicatorNamesMask) { - namec= sli->namesPresent|ledWire->namesPresent; - bzero((char *)sli->names,XkbNumIndicators*sizeof(Atom)); - } - if (ledWire->namesPresent) { - sli->namesPresent= ledWire->namesPresent; - bzero((char *)sli->names,XkbNumIndicators*sizeof(Atom)); - for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) { - if (ledWire->namesPresent&bit) { - sli->names[n]= (Atom)*atomWire; - if (sli->names[n]==None) - ledWire->namesPresent&= ~bit; - atomWire++; - } - } - } - mapWire= (xkbIndicatorMapWireDesc *)atomWire; - if (changed&XkbXI_IndicatorMapsMask) { - mapc= sli->mapsPresent|ledWire->mapsPresent; - sli->mapsPresent= ledWire->mapsPresent; - bzero((char*)sli->maps,XkbNumIndicators*sizeof(XkbIndicatorMapRec)); - } - if (ledWire->mapsPresent) { - for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) { - if (ledWire->mapsPresent&bit) { - sli->maps[n].flags= mapWire->flags; - sli->maps[n].which_groups= mapWire->whichGroups; - sli->maps[n].groups= mapWire->groups; - sli->maps[n].which_mods= mapWire->whichMods; - sli->maps[n].mods.mask= mapWire->mods; - sli->maps[n].mods.real_mods=mapWire->realMods; - sli->maps[n].mods.vmods= mapWire->virtualMods; - sli->maps[n].ctrls= mapWire->ctrls; - mapWire++; - } - } - } - if (changed&XkbXI_IndicatorStateMask) { - statec= sli->effectiveState^ledWire->state; - sli->explicitState&= ~statec; - sli->explicitState|= (ledWire->state&statec); - } - if (namec) - XkbApplyLedNameChanges(dev,sli,namec,&ed,&changes,&cause); - if (mapc) - XkbApplyLedMapChanges(dev,sli,mapc,&ed,&changes,&cause); - if (statec) - XkbApplyLedStateChanges(dev,sli,statec,&ed,&changes,&cause); - - kbd= dev; - if ((sli->flags&XkbSLI_HasOwnState)==0) - kbd = inputInfo.keyboard; - - XkbFlushLedEvents(dev,kbd,sli,&ed,&changes,&cause); - ledWire= (xkbDeviceLedsWireDesc *)mapWire; - } - return (char *)ledWire; -} - - -static int -_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev, - xkbSetDeviceInfoReq *stuff) -{ - char *wire; - - wire= (char *)&stuff[1]; - if (stuff->change&XkbXI_ButtonActionsMask) { - if (!dev->button) { - client->errorValue = _XkbErrCode2(XkbErr_BadClass,ButtonClass); - return XkbKeyboardErrorCode; - } - if ((stuff->firstBtn+stuff->nBtns)>dev->button->numButtons) { - client->errorValue= _XkbErrCode4(0x02,stuff->firstBtn,stuff->nBtns, - dev->button->numButtons); - return BadMatch; - } - wire+= (stuff->nBtns*SIZEOF(xkbActionWireDesc)); - } - if (stuff->change&XkbXI_IndicatorsMask) { - int status= Success; - wire= CheckSetDeviceIndicators(wire,dev,stuff->nDeviceLedFBs, - &status,client); - if (status!=Success) - return status; - } - if (((wire-((char *)stuff))/4)!=stuff->length) - return BadLength; - - return Success; -} - -static int -_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev, - xkbSetDeviceInfoReq *stuff) -{ - char *wire; - xkbExtensionDeviceNotify ed; - - bzero((char *)&ed,SIZEOF(xkbExtensionDeviceNotify)); - ed.deviceID= dev->id; - wire= (char *)&stuff[1]; - if (stuff->change&XkbXI_ButtonActionsMask) { - int nBtns,sz,i; - XkbAction * acts; - DeviceIntPtr kbd; - - nBtns= dev->button->numButtons; - acts= dev->button->xkb_acts; - if (acts==NULL) { - acts= xcalloc(nBtns, sizeof(XkbAction)); - if (!acts) - return BadAlloc; - dev->button->xkb_acts= acts; - } - sz= stuff->nBtns*SIZEOF(xkbActionWireDesc); - memcpy((char *)&acts[stuff->firstBtn],(char *)wire,sz); - wire+= sz; - ed.reason|= XkbXI_ButtonActionsMask; - ed.firstBtn= stuff->firstBtn; - ed.nBtns= stuff->nBtns; - - if (dev->key) kbd= dev; - else kbd= inputInfo.keyboard; - acts= &dev->button->xkb_acts[stuff->firstBtn]; - for (i=0;i<stuff->nBtns;i++,acts++) { - if (acts->type!=XkbSA_NoAction) - XkbSetActionKeyMods(kbd->key->xkbInfo->desc,acts,0); - } - } - if (stuff->change&XkbXI_IndicatorsMask) { - int status= Success; - wire= SetDeviceIndicators(wire,dev,stuff->change, - stuff->nDeviceLedFBs, &status,client,&ed); - if (status!=Success) - return status; - } - if ((stuff->change)&&(ed.reason)) - XkbSendExtensionDeviceNotify(dev,client,&ed); - return Success; -} - -int -ProcXkbSetDeviceInfo(ClientPtr client) -{ - DeviceIntPtr dev; - int rc; - - REQUEST(xkbSetDeviceInfoReq); - REQUEST_AT_LEAST_SIZE(xkbSetDeviceInfoReq); - - if (!(client->xkbClientFlags&_XkbClientInitialized)) - return BadAccess; - - CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); - CHK_MASK_LEGAL(0x01,stuff->change,XkbXI_AllFeaturesMask); - - rc = _XkbSetDeviceInfoCheck(client, dev, stuff); - - if (rc != Success) - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd || stuff->deviceSpec == XkbUseCorePtr) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if (((other != dev) && !IsMaster(other) && (other->u.master == dev)) && - ((stuff->deviceSpec == XkbUseCoreKbd && other->key) || - (stuff->deviceSpec == XkbUseCorePtr && other->button))) - { - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); - if (rc == Success) - { - rc = _XkbSetDeviceInfoCheck(client, other, stuff); - if (rc != Success) - return rc; - } - } - } - } - - /* checks done, apply */ - rc = _XkbSetDeviceInfo(client, dev, stuff); - if (rc != Success) - return rc; - - if (stuff->deviceSpec == XkbUseCoreKbd || stuff->deviceSpec == XkbUseCorePtr) - { - DeviceIntPtr other; - for (other = inputInfo.devices; other; other = other->next) - { - if (((other != dev) && !IsMaster(other) && (other->u.master == dev)) && - ((stuff->deviceSpec == XkbUseCoreKbd && other->key) || - (stuff->deviceSpec == XkbUseCorePtr && other->button))) - { - rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); - if (rc == Success) - { - rc = _XkbSetDeviceInfo(client, other, stuff); - if (rc != Success) - return rc; - } - } - } - } - - return client->noClientException; -} - -/***====================================================================***/ - -int -ProcXkbSetDebuggingFlags(ClientPtr client) -{ -CARD32 newFlags,newCtrls,extraLength; -xkbSetDebuggingFlagsReply rep; -int rc; - - REQUEST(xkbSetDebuggingFlagsReq); - REQUEST_AT_LEAST_SIZE(xkbSetDebuggingFlagsReq); - - rc = XaceHook(XACE_SERVER_ACCESS, client, DixDebugAccess); - if (rc != Success) - return rc; - - newFlags= xkbDebugFlags&(~stuff->affectFlags); - newFlags|= (stuff->flags&stuff->affectFlags); - newCtrls= xkbDebugCtrls&(~stuff->affectCtrls); - newCtrls|= (stuff->ctrls&stuff->affectCtrls); - if (xkbDebugFlags || newFlags || stuff->msgLength) { - ErrorF("[xkb] XkbDebug: Setting debug flags to 0x%lx\n",(long)newFlags); - if (newCtrls!=xkbDebugCtrls) - ErrorF("[xkb] XkbDebug: Setting debug controls to 0x%lx\n",(long)newCtrls); - } - extraLength= (stuff->length<<2)-sz_xkbSetDebuggingFlagsReq; - if (stuff->msgLength>0) { - char *msg; - if (extraLength<XkbPaddedSize(stuff->msgLength)) { - ErrorF("[xkb] XkbDebug: msgLength= %d, length= %ld (should be %d)\n", - stuff->msgLength,(long)extraLength, - XkbPaddedSize(stuff->msgLength)); - return BadLength; - } - msg= (char *)&stuff[1]; - if (msg[stuff->msgLength-1]!='\0') { - ErrorF("[xkb] XkbDebug: message not null-terminated\n"); - return BadValue; - } - ErrorF("[xkb] XkbDebug: %s\n",msg); - } - xkbDebugFlags = newFlags; - xkbDebugCtrls = newCtrls; - - rep.type= X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.currentFlags = newFlags; - rep.currentCtrls = newCtrls; - rep.supportedFlags = ~0; - rep.supportedCtrls = ~0; - if ( client->swapped ) { - register int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.currentFlags, n); - swapl(&rep.currentCtrls, n); - swapl(&rep.supportedFlags, n); - swapl(&rep.supportedCtrls, n); - } - WriteToClient(client,SIZEOF(xkbSetDebuggingFlagsReply), (char *)&rep); - return client->noClientException; -} - -/***====================================================================***/ - -static int -ProcXkbDispatch (ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) - { - case X_kbUseExtension: - return ProcXkbUseExtension(client); - case X_kbSelectEvents: - return ProcXkbSelectEvents(client); - case X_kbBell: - return ProcXkbBell(client); - case X_kbGetState: - return ProcXkbGetState(client); - case X_kbLatchLockState: - return ProcXkbLatchLockState(client); - case X_kbGetControls: - return ProcXkbGetControls(client); - case X_kbSetControls: - return ProcXkbSetControls(client); - case X_kbGetMap: - return ProcXkbGetMap(client); - case X_kbSetMap: - return ProcXkbSetMap(client); - case X_kbGetCompatMap: - return ProcXkbGetCompatMap(client); - case X_kbSetCompatMap: - return ProcXkbSetCompatMap(client); - case X_kbGetIndicatorState: - return ProcXkbGetIndicatorState(client); - case X_kbGetIndicatorMap: - return ProcXkbGetIndicatorMap(client); - case X_kbSetIndicatorMap: - return ProcXkbSetIndicatorMap(client); - case X_kbGetNamedIndicator: - return ProcXkbGetNamedIndicator(client); - case X_kbSetNamedIndicator: - return ProcXkbSetNamedIndicator(client); - case X_kbGetNames: - return ProcXkbGetNames(client); - case X_kbSetNames: - return ProcXkbSetNames(client); - case X_kbGetGeometry: - return ProcXkbGetGeometry(client); - case X_kbSetGeometry: - return ProcXkbSetGeometry(client); - case X_kbPerClientFlags: - return ProcXkbPerClientFlags(client); - case X_kbListComponents: - return ProcXkbListComponents(client); - case X_kbGetKbdByName: - return ProcXkbGetKbdByName(client); - case X_kbGetDeviceInfo: - return ProcXkbGetDeviceInfo(client); - case X_kbSetDeviceInfo: - return ProcXkbSetDeviceInfo(client); - case X_kbSetDebuggingFlags: - return ProcXkbSetDebuggingFlags(client); - default: - return BadRequest; - } -} - -static int -XkbClientGone(pointer data,XID id) -{ - DevicePtr pXDev = (DevicePtr)data; - - if (!XkbRemoveResourceClient(pXDev,id)) { - ErrorF("[xkb] Internal Error! bad RemoveResourceClient in XkbClientGone\n"); - } - return 1; -} - -void -XkbExtensionInit(void) -{ - ExtensionEntry *extEntry; - - RT_XKBCLIENT = CreateNewResourceType(XkbClientGone, "XkbClient"); - if (!RT_XKBCLIENT) - return; - - if ((extEntry = AddExtension(XkbName, XkbNumberEvents, XkbNumberErrors, - ProcXkbDispatch, SProcXkbDispatch, - NULL, StandardMinorOpcode))) { - XkbReqCode = (unsigned char)extEntry->base; - XkbEventBase = (unsigned char)extEntry->eventBase; - XkbErrorBase = (unsigned char)extEntry->errorBase; - XkbKeyboardErrorCode = XkbErrorBase+XkbKeyboard; - } - return; -} - - +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#endif + +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "inputstr.h" +#define XKBSRV_NEED_FILE_FUNCS +#include <xkbsrv.h> +#include "extnsionst.h" +#include "xace.h" +#include "xkb.h" +#include "protocol-versions.h" + +#include <X11/extensions/XI.h> +#include <X11/extensions/XKMformat.h> + +int XkbEventBase; +static int XkbErrorBase; +int XkbReqCode; +int XkbKeyboardErrorCode; +CARD32 xkbDebugFlags = 0; +static CARD32 xkbDebugCtrls = 0; + +static RESTYPE RT_XKBCLIENT; + +/***====================================================================***/ + +#define CHK_DEVICE(dev, id, client, access_mode, lf) {\ + int why;\ + int rc = lf(&(dev), id, client, access_mode, &why);\ + if (rc != Success) {\ + client->errorValue = _XkbErrCode2(why, id);\ + return rc;\ + }\ +} + +#define CHK_KBD_DEVICE(dev, id, client, mode) \ + CHK_DEVICE(dev, id, client, mode, _XkbLookupKeyboard) +#define CHK_LED_DEVICE(dev, id, client, mode) \ + CHK_DEVICE(dev, id, client, mode, _XkbLookupLedDevice) +#define CHK_BELL_DEVICE(dev, id, client, mode) \ + CHK_DEVICE(dev, id, client, mode, _XkbLookupBellDevice) +#define CHK_ANY_DEVICE(dev, id, client, mode) \ + CHK_DEVICE(dev, id, client, mode, _XkbLookupAnyDevice) + +#define CHK_ATOM_ONLY2(a,ev,er) {\ + if (((a)==None)||(!ValidAtom((a)))) {\ + (ev)= (XID)(a);\ + return er;\ + }\ +} +#define CHK_ATOM_ONLY(a) \ + CHK_ATOM_ONLY2(a,client->errorValue,BadAtom) + +#define CHK_ATOM_OR_NONE3(a,ev,er,ret) {\ + if (((a)!=None)&&(!ValidAtom((a)))) {\ + (ev)= (XID)(a);\ + (er)= BadAtom;\ + return ret;\ + }\ +} +#define CHK_ATOM_OR_NONE2(a,ev,er) {\ + if (((a)!=None)&&(!ValidAtom((a)))) {\ + (ev)= (XID)(a);\ + return er;\ + }\ +} +#define CHK_ATOM_OR_NONE(a) \ + CHK_ATOM_OR_NONE2(a,client->errorValue,BadAtom) + +#define CHK_MASK_LEGAL3(err,mask,legal,ev,er,ret) {\ + if ((mask)&(~(legal))) { \ + (ev)= _XkbErrCode2((err),((mask)&(~(legal))));\ + (er)= BadValue;\ + return ret;\ + }\ +} +#define CHK_MASK_LEGAL2(err,mask,legal,ev,er) {\ + if ((mask)&(~(legal))) { \ + (ev)= _XkbErrCode2((err),((mask)&(~(legal))));\ + return er;\ + }\ +} +#define CHK_MASK_LEGAL(err,mask,legal) \ + CHK_MASK_LEGAL2(err,mask,legal,client->errorValue,BadValue) + +#define CHK_MASK_MATCH(err,affect,value) {\ + if ((value)&(~(affect))) { \ + client->errorValue= _XkbErrCode2((err),((value)&(~(affect))));\ + return BadMatch;\ + }\ +} +#define CHK_MASK_OVERLAP(err,m1,m2) {\ + if ((m1)&(m2)) { \ + client->errorValue= _XkbErrCode2((err),((m1)&(m2)));\ + return BadMatch;\ + }\ +} +#define CHK_KEY_RANGE2(err,first,num,x,ev,er) {\ + if (((unsigned)(first)+(num)-1)>(x)->max_key_code) {\ + (ev)=_XkbErrCode4(err,(first),(num),(x)->max_key_code);\ + return er;\ + }\ + else if ( (first)<(x)->min_key_code ) {\ + (ev)=_XkbErrCode3(err+1,(first),xkb->min_key_code);\ + return er;\ + }\ +} +#define CHK_KEY_RANGE(err,first,num,x) \ + CHK_KEY_RANGE2(err,first,num,x,client->errorValue,BadValue) + +#define CHK_REQ_KEY_RANGE2(err,first,num,r,ev,er) {\ + if (((unsigned)(first)+(num)-1)>(r)->maxKeyCode) {\ + (ev)=_XkbErrCode4(err,(first),(num),(r)->maxKeyCode);\ + return er;\ + }\ + else if ( (first)<(r)->minKeyCode ) {\ + (ev)=_XkbErrCode3(err+1,(first),(r)->minKeyCode);\ + return er;\ + }\ +} +#define CHK_REQ_KEY_RANGE(err,first,num,r) \ + CHK_REQ_KEY_RANGE2(err,first,num,r,client->errorValue,BadValue) + +/***====================================================================***/ + +int +ProcXkbUseExtension(ClientPtr client) +{ + REQUEST(xkbUseExtensionReq); + xkbUseExtensionReply rep; + register int n; + int supported; + + REQUEST_SIZE_MATCH(xkbUseExtensionReq); + if (stuff->wantedMajor != SERVER_XKB_MAJOR_VERSION) { + /* pre-release version 0.65 is compatible with 1.00 */ + supported= ((SERVER_XKB_MAJOR_VERSION==1)&& + (stuff->wantedMajor==0)&&(stuff->wantedMinor==65)); + } + else supported = 1; + + if ((supported) && (!(client->xkbClientFlags&_XkbClientInitialized))) { + client->xkbClientFlags= _XkbClientInitialized; + client->vMajor= stuff->wantedMajor; + client->vMinor= stuff->wantedMinor; + } + else if (xkbDebugFlags&0x1) { + ErrorF("[xkb] Rejecting client %d (0x%lx) (wants %d.%02d, have %d.%02d)\n", + client->index, + (long)client->clientAsMask, + stuff->wantedMajor,stuff->wantedMinor, + SERVER_XKB_MAJOR_VERSION,SERVER_XKB_MINOR_VERSION); + } + memset(&rep, 0, sizeof(xkbUseExtensionReply)); + rep.type = X_Reply; + rep.supported = supported; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.serverMajor = SERVER_XKB_MAJOR_VERSION; + rep.serverMinor = SERVER_XKB_MINOR_VERSION; + if ( client->swapped ) { + swaps(&rep.sequenceNumber, n); + swaps(&rep.serverMajor, n); + swaps(&rep.serverMinor, n); + } + WriteToClient(client,SIZEOF(xkbUseExtensionReply), (char *)&rep); + return Success; +} + +/***====================================================================***/ + +int +ProcXkbSelectEvents(ClientPtr client) +{ + unsigned legal; + DeviceIntPtr dev; + XkbInterestPtr masks; + REQUEST(xkbSelectEventsReq); + + REQUEST_AT_LEAST_SIZE(xkbSelectEventsReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixUseAccess); + + if (((stuff->affectWhich&XkbMapNotifyMask)!=0)&&(stuff->affectMap)) { + client->mapNotifyMask&= ~stuff->affectMap; + client->mapNotifyMask|= (stuff->affectMap&stuff->map); + } + if ((stuff->affectWhich&(~XkbMapNotifyMask))==0) + return Success; + + masks = XkbFindClientResource((DevicePtr)dev,client); + if (!masks){ + XID id = FakeClientID(client->index); + AddResource(id,RT_XKBCLIENT,dev); + masks= XkbAddClientResource((DevicePtr)dev,client,id); + } + if (masks) { + union { + CARD8 *c8; + CARD16 *c16; + CARD32 *c32; + } from,to; + register unsigned bit,ndx,maskLeft,dataLeft,size; + + from.c8= (CARD8 *)&stuff[1]; + dataLeft= (stuff->length*4)-SIZEOF(xkbSelectEventsReq); + maskLeft= (stuff->affectWhich&(~XkbMapNotifyMask)); + for (ndx=0,bit=1; (maskLeft!=0); ndx++, bit<<=1) { + if ((bit&maskLeft)==0) + continue; + maskLeft&= ~bit; + switch (ndx) { + case XkbNewKeyboardNotify: + to.c16= &client->newKeyboardNotifyMask; + legal= XkbAllNewKeyboardEventsMask; + size= 2; + break; + case XkbStateNotify: + to.c16= &masks->stateNotifyMask; + legal= XkbAllStateEventsMask; + size= 2; + break; + case XkbControlsNotify: + to.c32= &masks->ctrlsNotifyMask; + legal= XkbAllControlEventsMask; + size= 4; + break; + case XkbIndicatorStateNotify: + to.c32= &masks->iStateNotifyMask; + legal= XkbAllIndicatorEventsMask; + size= 4; + break; + case XkbIndicatorMapNotify: + to.c32= &masks->iMapNotifyMask; + legal= XkbAllIndicatorEventsMask; + size= 4; + break; + case XkbNamesNotify: + to.c16= &masks->namesNotifyMask; + legal= XkbAllNameEventsMask; + size= 2; + break; + case XkbCompatMapNotify: + to.c8= &masks->compatNotifyMask; + legal= XkbAllCompatMapEventsMask; + size= 1; + break; + case XkbBellNotify: + to.c8= &masks->bellNotifyMask; + legal= XkbAllBellEventsMask; + size= 1; + break; + case XkbActionMessage: + to.c8= &masks->actionMessageMask; + legal= XkbAllActionMessagesMask; + size= 1; + break; + case XkbAccessXNotify: + to.c16= &masks->accessXNotifyMask; + legal= XkbAllAccessXEventsMask; + size= 2; + break; + case XkbExtensionDeviceNotify: + to.c16= &masks->extDevNotifyMask; + legal= XkbAllExtensionDeviceEventsMask; + size= 2; + break; + default: + client->errorValue = _XkbErrCode2(33,bit); + return BadValue; + } + + if (stuff->clear&bit) { + if (size==2) to.c16[0]= 0; + else if (size==4) to.c32[0]= 0; + else to.c8[0]= 0; + } + else if (stuff->selectAll&bit) { + if (size==2) to.c16[0]= ~0; + else if (size==4) to.c32[0]= ~0; + else to.c8[0]= ~0; + } + else { + if (dataLeft<(size*2)) + return BadLength; + if (size==2) { + CHK_MASK_MATCH(ndx,from.c16[0],from.c16[1]); + CHK_MASK_LEGAL(ndx,from.c16[0],legal); + to.c16[0]&= ~from.c16[0]; + to.c16[0]|= (from.c16[0]&from.c16[1]); + } + else if (size==4) { + CHK_MASK_MATCH(ndx,from.c32[0],from.c32[1]); + CHK_MASK_LEGAL(ndx,from.c32[0],legal); + to.c32[0]&= ~from.c32[0]; + to.c32[0]|= (from.c32[0]&from.c32[1]); + } + else { + CHK_MASK_MATCH(ndx,from.c8[0],from.c8[1]); + CHK_MASK_LEGAL(ndx,from.c8[0],legal); + to.c8[0]&= ~from.c8[0]; + to.c8[0]|= (from.c8[0]&from.c8[1]); + size= 2; + } + from.c8+= (size*2); + dataLeft-= (size*2); + } + } + if (dataLeft>2) { + ErrorF("[xkb] Extra data (%d bytes) after SelectEvents\n",dataLeft); + return BadLength; + } + return Success; + } + return BadAlloc; +} + +/***====================================================================***/ +/** + * Ring a bell on the given device for the given client. + */ +static int +_XkbBell(ClientPtr client, DeviceIntPtr dev, WindowPtr pWin, + int bellClass, int bellID, int pitch, int duration, + int percent, int forceSound, int eventOnly, Atom name) +{ + int base; + pointer ctrl; + int oldPitch, oldDuration; + int newPercent; + + if (bellClass == KbdFeedbackClass) { + KbdFeedbackPtr k; + if (bellID==XkbDfltXIId) + k= dev->kbdfeed; + else { + for (k=dev->kbdfeed; k; k=k->next) { + if (k->ctrl.id == bellID) + break; + } + } + if (!k) { + client->errorValue = _XkbErrCode2(0x5,bellID); + return BadValue; + } + base = k->ctrl.bell; + ctrl = (pointer) &(k->ctrl); + oldPitch= k->ctrl.bell_pitch; + oldDuration= k->ctrl.bell_duration; + if (pitch!=0) { + if (pitch==-1) + k->ctrl.bell_pitch= defaultKeyboardControl.bell_pitch; + else k->ctrl.bell_pitch= pitch; + } + if (duration!=0) { + if (duration==-1) + k->ctrl.bell_duration= defaultKeyboardControl.bell_duration; + else k->ctrl.bell_duration= duration; + } + } + else if (bellClass == BellFeedbackClass) { + BellFeedbackPtr b; + if (bellID==XkbDfltXIId) + b= dev->bell; + else { + for (b=dev->bell; b; b=b->next) { + if (b->ctrl.id == bellID) + break; + } + } + if (!b) { + client->errorValue = _XkbErrCode2(0x6,bellID); + return BadValue; + } + base = b->ctrl.percent; + ctrl = (pointer) &(b->ctrl); + oldPitch= b->ctrl.pitch; + oldDuration= b->ctrl.duration; + if (pitch!=0) { + if (pitch==-1) + b->ctrl.pitch= defaultKeyboardControl.bell_pitch; + else b->ctrl.pitch= pitch; + } + if (duration!=0) { + if (duration==-1) + b->ctrl.duration= defaultKeyboardControl.bell_duration; + else b->ctrl.duration= duration; + } + } + else { + client->errorValue = _XkbErrCode2(0x7, bellClass); + return BadValue; + } + + newPercent = (base * percent)/100; + if (percent < 0) + newPercent = base + newPercent; + else newPercent = base - newPercent + percent; + + XkbHandleBell(forceSound, eventOnly, + dev, newPercent, ctrl, bellClass, + name, pWin, client); + if ((pitch!=0)||(duration!=0)) { + if (bellClass == KbdFeedbackClass) { + KbdFeedbackPtr k; + k= (KbdFeedbackPtr)ctrl; + if (pitch!=0) + k->ctrl.bell_pitch= oldPitch; + if (duration!=0) + k->ctrl.bell_duration= oldDuration; + } + else { + BellFeedbackPtr b; + b= (BellFeedbackPtr)ctrl; + if (pitch!=0) + b->ctrl.pitch= oldPitch; + if (duration!=0) + b->ctrl.duration= oldDuration; + } + } + + return Success; +} + +int +ProcXkbBell(ClientPtr client) +{ + REQUEST(xkbBellReq); + DeviceIntPtr dev; + WindowPtr pWin; + int rc; + + REQUEST_SIZE_MATCH(xkbBellReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_BELL_DEVICE(dev, stuff->deviceSpec, client, DixBellAccess); + CHK_ATOM_OR_NONE(stuff->name); + + /* device-independent checks request for sane values */ + if ((stuff->forceSound)&&(stuff->eventOnly)) { + client->errorValue=_XkbErrCode3(0x1,stuff->forceSound,stuff->eventOnly); + return BadMatch; + } + if (stuff->percent < -100 || stuff->percent > 100) { + client->errorValue = _XkbErrCode2(0x2,stuff->percent); + return BadValue; + } + if (stuff->duration<-1) { + client->errorValue = _XkbErrCode2(0x3,stuff->duration); + return BadValue; + } + if (stuff->pitch<-1) { + client->errorValue = _XkbErrCode2(0x4,stuff->pitch); + return BadValue; + } + + if (stuff->bellClass == XkbDfltXIClass) { + if (dev->kbdfeed!=NULL) + stuff->bellClass= KbdFeedbackClass; + else stuff->bellClass= BellFeedbackClass; + } + + if (stuff->window!=None) { + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) { + client->errorValue= stuff->window; + return rc; + } + } + else pWin= NULL; + + /* Client wants to ring a bell on the core keyboard? + Ring the bell on the core keyboard (which does nothing, but if that + fails the client is screwed anyway), and then on all extension devices. + Fail if the core keyboard fails but not the extension devices. this + may cause some keyboards to ding and others to stay silent. Fix + your client to use explicit keyboards to avoid this. + + dev is the device the client requested. + */ + rc = _XkbBell(client, dev, pWin, stuff->bellClass, stuff->bellID, + stuff->pitch, stuff->duration, stuff->percent, + stuff->forceSound, stuff->eventOnly, stuff->name); + + if ((rc == Success) && ((stuff->deviceSpec == XkbUseCoreKbd) || + (stuff->deviceSpec == XkbUseCorePtr))) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) + { + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixBellAccess); + if (rc == Success) + _XkbBell(client, other, pWin, stuff->bellClass, + stuff->bellID, stuff->pitch, stuff->duration, + stuff->percent, stuff->forceSound, + stuff->eventOnly, stuff->name); + } + } + rc = Success; /* reset to success, that's what we got for the VCK */ + } + + return rc; +} + +/***====================================================================***/ + +int +ProcXkbGetState(ClientPtr client) +{ + REQUEST(xkbGetStateReq); + DeviceIntPtr dev; + xkbGetStateReply rep; + XkbStateRec *xkb; + + REQUEST_SIZE_MATCH(xkbGetStateReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); + + xkb= &dev->key->xkbInfo->state; + bzero(&rep,sizeof(xkbGetStateReply)); + rep.type= X_Reply; + rep.sequenceNumber= client->sequence; + rep.length = 0; + rep.deviceID = dev->id; + rep.mods = XkbStateFieldFromRec(xkb) & 0xff; + rep.baseMods = xkb->base_mods; + rep.lockedMods = xkb->locked_mods; + rep.latchedMods = xkb->latched_mods; + rep.group = xkb->group; + rep.baseGroup = xkb->base_group; + rep.latchedGroup = xkb->latched_group; + rep.lockedGroup = xkb->locked_group; + rep.compatState = xkb->compat_state; + rep.ptrBtnState = xkb->ptr_buttons; + if (client->swapped) { + register int n; + swaps(&rep.sequenceNumber,n); + swaps(&rep.ptrBtnState,n); + } + WriteToClient(client, SIZEOF(xkbGetStateReply), (char *)&rep); + return Success; +} + +/***====================================================================***/ + +int +ProcXkbLatchLockState(ClientPtr client) +{ + int status; + DeviceIntPtr dev, tmpd; + XkbStateRec oldState,*newState; + CARD16 changed; + xkbStateNotify sn; + XkbEventCauseRec cause; + + REQUEST(xkbLatchLockStateReq); + REQUEST_SIZE_MATCH(xkbLatchLockStateReq); + + if (!(client->xkbClientFlags & _XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess); + CHK_MASK_MATCH(0x01, stuff->affectModLocks, stuff->modLocks); + CHK_MASK_MATCH(0x01, stuff->affectModLatches, stuff->modLatches); + + status = Success; + + for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) { + if ((tmpd == dev) || (!IsMaster(tmpd) && tmpd->u.master == dev)) { + if (!tmpd->key || !tmpd->key->xkbInfo) + continue; + + oldState = tmpd->key->xkbInfo->state; + newState = &tmpd->key->xkbInfo->state; + if (stuff->affectModLocks) { + newState->locked_mods &= ~stuff->affectModLocks; + newState->locked_mods |= (stuff->affectModLocks & stuff->modLocks); + } + if (status == Success && stuff->lockGroup) + newState->locked_group = stuff->groupLock; + if (status == Success && stuff->affectModLatches) + status = XkbLatchModifiers(tmpd, stuff->affectModLatches, + stuff->modLatches); + if (status == Success && stuff->latchGroup) + status = XkbLatchGroup(tmpd, stuff->groupLatch); + + if (status != Success) + return status; + + XkbComputeDerivedState(tmpd->key->xkbInfo); + + changed = XkbStateChangedFlags(&oldState, newState); + if (changed) { + sn.keycode = 0; + sn.eventType = 0; + sn.requestMajor = XkbReqCode; + sn.requestMinor = X_kbLatchLockState; + sn.changed = changed; + XkbSendStateNotify(tmpd, &sn); + changed = XkbIndicatorsToUpdate(tmpd, changed, FALSE); + if (changed) { + XkbSetCauseXkbReq(&cause, X_kbLatchLockState, client); + XkbUpdateIndicators(tmpd, changed, TRUE, NULL, &cause); + } + } + } + } + + return Success; +} + +/***====================================================================***/ + +int +ProcXkbGetControls(ClientPtr client) +{ + xkbGetControlsReply rep; + XkbControlsPtr xkb; + DeviceIntPtr dev; + register int n; + + REQUEST(xkbGetControlsReq); + REQUEST_SIZE_MATCH(xkbGetControlsReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); + + xkb = dev->key->xkbInfo->desc->ctrls; + rep.type = X_Reply; + rep.length = bytes_to_int32(SIZEOF(xkbGetControlsReply)- + SIZEOF(xGenericReply)); + rep.sequenceNumber = client->sequence; + rep.deviceID = ((DeviceIntPtr)dev)->id; + rep.numGroups = xkb->num_groups; + rep.groupsWrap = xkb->groups_wrap; + rep.internalMods = xkb->internal.mask; + rep.ignoreLockMods = xkb->ignore_lock.mask; + rep.internalRealMods = xkb->internal.real_mods; + rep.ignoreLockRealMods = xkb->ignore_lock.real_mods; + rep.internalVMods = xkb->internal.vmods; + rep.ignoreLockVMods = xkb->ignore_lock.vmods; + rep.enabledCtrls = xkb->enabled_ctrls; + rep.repeatDelay = xkb->repeat_delay; + rep.repeatInterval = xkb->repeat_interval; + rep.slowKeysDelay = xkb->slow_keys_delay; + rep.debounceDelay = xkb->debounce_delay; + rep.mkDelay = xkb->mk_delay; + rep.mkInterval = xkb->mk_interval; + rep.mkTimeToMax = xkb->mk_time_to_max; + rep.mkMaxSpeed = xkb->mk_max_speed; + rep.mkCurve = xkb->mk_curve; + rep.mkDfltBtn = xkb->mk_dflt_btn; + rep.axTimeout = xkb->ax_timeout; + rep.axtCtrlsMask = xkb->axt_ctrls_mask; + rep.axtCtrlsValues = xkb->axt_ctrls_values; + rep.axtOptsMask = xkb->axt_opts_mask; + rep.axtOptsValues = xkb->axt_opts_values; + rep.axOptions = xkb->ax_options; + memcpy(rep.perKeyRepeat,xkb->per_key_repeat,XkbPerKeyBitArraySize); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length,n); + swaps(&rep.internalVMods, n); + swaps(&rep.ignoreLockVMods, n); + swapl(&rep.enabledCtrls, n); + swaps(&rep.repeatDelay, n); + swaps(&rep.repeatInterval, n); + swaps(&rep.slowKeysDelay, n); + swaps(&rep.debounceDelay, n); + swaps(&rep.mkDelay, n); + swaps(&rep.mkInterval, n); + swaps(&rep.mkTimeToMax, n); + swaps(&rep.mkMaxSpeed, n); + swaps(&rep.mkCurve, n); + swaps(&rep.axTimeout, n); + swapl(&rep.axtCtrlsMask, n); + swapl(&rep.axtCtrlsValues, n); + swaps(&rep.axtOptsMask, n); + swaps(&rep.axtOptsValues, n); + swaps(&rep.axOptions, n); + } + WriteToClient(client, SIZEOF(xkbGetControlsReply), (char *)&rep); + return Success; +} + +int +ProcXkbSetControls(ClientPtr client) +{ + DeviceIntPtr dev, tmpd; + XkbSrvInfoPtr xkbi; + XkbControlsPtr ctrl; + XkbControlsRec new,old; + xkbControlsNotify cn; + XkbEventCauseRec cause; + XkbSrvLedInfoPtr sli; + + REQUEST(xkbSetControlsReq); + REQUEST_SIZE_MATCH(xkbSetControlsReq); + + if (!(client->xkbClientFlags & _XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); + CHK_MASK_LEGAL(0x01, stuff->changeCtrls, XkbAllControlsMask); + + for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) { + if (!tmpd->key || !tmpd->key->xkbInfo) + continue; + if ((tmpd == dev) || (!IsMaster(tmpd) && tmpd->u.master == dev)) { + xkbi = tmpd->key->xkbInfo; + ctrl = xkbi->desc->ctrls; + new = *ctrl; + XkbSetCauseXkbReq(&cause, X_kbSetControls, client); + + if (stuff->changeCtrls & XkbInternalModsMask) { + CHK_MASK_MATCH(0x02, stuff->affectInternalMods, + stuff->internalMods); + CHK_MASK_MATCH(0x03, stuff->affectInternalVMods, + stuff->internalVMods); + + new.internal.real_mods &= ~(stuff->affectInternalMods); + new.internal.real_mods |= (stuff->affectInternalMods & + stuff->internalMods); + new.internal.vmods &= ~(stuff->affectInternalVMods); + new.internal.vmods |= (stuff->affectInternalVMods & + stuff->internalVMods); + new.internal.mask = new.internal.real_mods | + XkbMaskForVMask(xkbi->desc, + new.internal.vmods); + } + + if (stuff->changeCtrls & XkbIgnoreLockModsMask) { + CHK_MASK_MATCH(0x4, stuff->affectIgnoreLockMods, + stuff->ignoreLockMods); + CHK_MASK_MATCH(0x5, stuff->affectIgnoreLockVMods, + stuff->ignoreLockVMods); + + new.ignore_lock.real_mods &= ~(stuff->affectIgnoreLockMods); + new.ignore_lock.real_mods |= (stuff->affectIgnoreLockMods & + stuff->ignoreLockMods); + new.ignore_lock.vmods &= ~(stuff->affectIgnoreLockVMods); + new.ignore_lock.vmods |= (stuff->affectIgnoreLockVMods & + stuff->ignoreLockVMods); + new.ignore_lock.mask = new.ignore_lock.real_mods | + XkbMaskForVMask(xkbi->desc, + new.ignore_lock.vmods); + } + + CHK_MASK_MATCH(0x06, stuff->affectEnabledCtrls, + stuff->enabledCtrls); + if (stuff->affectEnabledCtrls) { + CHK_MASK_LEGAL(0x07, stuff->affectEnabledCtrls, + XkbAllBooleanCtrlsMask); + + new.enabled_ctrls &= ~(stuff->affectEnabledCtrls); + new.enabled_ctrls |= (stuff->affectEnabledCtrls & + stuff->enabledCtrls); + } + + if (stuff->changeCtrls & XkbRepeatKeysMask) { + if (stuff->repeatDelay < 1 || stuff->repeatInterval < 1) { + client->errorValue = _XkbErrCode3(0x08, stuff->repeatDelay, + stuff->repeatInterval); + return BadValue; + } + + new.repeat_delay = stuff->repeatDelay; + new.repeat_interval = stuff->repeatInterval; + } + + if (stuff->changeCtrls & XkbSlowKeysMask) { + if (stuff->slowKeysDelay < 1) { + client->errorValue = _XkbErrCode2(0x09, + stuff->slowKeysDelay); + return BadValue; + } + + new.slow_keys_delay = stuff->slowKeysDelay; + } + + if (stuff->changeCtrls & XkbBounceKeysMask) { + if (stuff->debounceDelay < 1) { + client->errorValue = _XkbErrCode2(0x0A, + stuff->debounceDelay); + return BadValue; + } + + new.debounce_delay = stuff->debounceDelay; + } + + if (stuff->changeCtrls & XkbMouseKeysMask) { + if (stuff->mkDfltBtn > XkbMaxMouseKeysBtn) { + client->errorValue = _XkbErrCode2(0x0B, stuff->mkDfltBtn); + return BadValue; + } + + new.mk_dflt_btn = stuff->mkDfltBtn; + } + + if (stuff->changeCtrls & XkbMouseKeysAccelMask) { + if (stuff->mkDelay < 1 || stuff->mkInterval < 1 || + stuff->mkTimeToMax < 1 || stuff->mkMaxSpeed < 1 || + stuff->mkCurve < -1000) { + client->errorValue = _XkbErrCode2(0x0C,0); + return BadValue; + } + + new.mk_delay = stuff->mkDelay; + new.mk_interval = stuff->mkInterval; + new.mk_time_to_max = stuff->mkTimeToMax; + new.mk_max_speed = stuff->mkMaxSpeed; + new.mk_curve = stuff->mkCurve; + AccessXComputeCurveFactor(xkbi, &new); + } + + if (stuff->changeCtrls & XkbGroupsWrapMask) { + unsigned act, num; + + act = XkbOutOfRangeGroupAction(stuff->groupsWrap); + switch (act) { + case XkbRedirectIntoRange: + num = XkbOutOfRangeGroupNumber(stuff->groupsWrap); + if (num >= new.num_groups) { + client->errorValue = _XkbErrCode3(0x0D, new.num_groups, + num); + return BadValue; + } + case XkbWrapIntoRange: + case XkbClampIntoRange: + break; + default: + client->errorValue = _XkbErrCode2(0x0E, act); + return BadValue; + } + + new.groups_wrap= stuff->groupsWrap; + } + + CHK_MASK_LEGAL(0x0F, stuff->axOptions, XkbAX_AllOptionsMask); + if (stuff->changeCtrls & XkbAccessXKeysMask) { + new.ax_options = stuff->axOptions & XkbAX_AllOptionsMask; + } + else { + if (stuff->changeCtrls & XkbStickyKeysMask) { + new.ax_options &= ~(XkbAX_SKOptionsMask); + new.ax_options |= (stuff->axOptions & XkbAX_SKOptionsMask); + } + + if (stuff->changeCtrls & XkbAccessXFeedbackMask) { + new.ax_options &= ~(XkbAX_FBOptionsMask); + new.ax_options |= (stuff->axOptions & XkbAX_FBOptionsMask); + } + } + + if (stuff->changeCtrls & XkbAccessXTimeoutMask) { + if (stuff->axTimeout < 1) { + client->errorValue = _XkbErrCode2(0x10, stuff->axTimeout); + return BadValue; + } + CHK_MASK_MATCH(0x11, stuff->axtCtrlsMask, + stuff->axtCtrlsValues); + CHK_MASK_LEGAL(0x12, stuff->axtCtrlsMask, + XkbAllBooleanCtrlsMask); + CHK_MASK_MATCH(0x13, stuff->axtOptsMask, stuff->axtOptsValues); + CHK_MASK_LEGAL(0x14, stuff->axtOptsMask, XkbAX_AllOptionsMask); + new.ax_timeout = stuff->axTimeout; + new.axt_ctrls_mask = stuff->axtCtrlsMask; + new.axt_ctrls_values = (stuff->axtCtrlsValues & + stuff->axtCtrlsMask); + new.axt_opts_mask = stuff->axtOptsMask; + new.axt_opts_values = (stuff->axtOptsValues & + stuff->axtOptsMask); + } + + if (stuff->changeCtrls & XkbPerKeyRepeatMask) + memcpy(new.per_key_repeat, stuff->perKeyRepeat, + XkbPerKeyBitArraySize); + + old= *ctrl; + *ctrl= new; + XkbDDXChangeControls(tmpd, &old, ctrl); + + if (XkbComputeControlsNotify(tmpd, &old, ctrl, &cn, FALSE)) { + cn.keycode = 0; + cn.eventType = 0; + cn.requestMajor = XkbReqCode; + cn.requestMinor = X_kbSetControls; + XkbSendControlsNotify(tmpd, &cn); + } + + sli = XkbFindSrvLedInfo(tmpd, XkbDfltXIClass, XkbDfltXIId, 0); + if (sli) + XkbUpdateIndicators(tmpd, sli->usesControls, TRUE, NULL, + &cause); + + /* If sticky keys were disabled, clear all locks and latches */ + if ((old.enabled_ctrls & XkbStickyKeysMask) && + !(ctrl->enabled_ctrls & XkbStickyKeysMask)) + XkbClearAllLatchesAndLocks(tmpd, xkbi, TRUE, &cause); + } + } + + return Success; +} + +/***====================================================================***/ + +static int +XkbSizeKeyTypes(XkbDescPtr xkb,xkbGetMapReply *rep) +{ + XkbKeyTypeRec *type; + unsigned i,len; + + len= 0; + if (((rep->present&XkbKeyTypesMask)==0)||(rep->nTypes<1)|| + (!xkb)||(!xkb->map)||(!xkb->map->types)) { + rep->present&= ~XkbKeyTypesMask; + rep->firstType= rep->nTypes= 0; + return 0; + } + type= &xkb->map->types[rep->firstType]; + for (i=0;i<rep->nTypes;i++,type++){ + len+= SIZEOF(xkbKeyTypeWireDesc); + if (type->map_count>0) { + len+= (type->map_count*SIZEOF(xkbKTMapEntryWireDesc)); + if (type->preserve) + len+= (type->map_count*SIZEOF(xkbModsWireDesc)); + } + } + return len; +} + +static char * +XkbWriteKeyTypes( XkbDescPtr xkb, + xkbGetMapReply * rep, + char * buf, + ClientPtr client) +{ + XkbKeyTypePtr type; + unsigned i; + xkbKeyTypeWireDesc *wire; + + type= &xkb->map->types[rep->firstType]; + for (i=0;i<rep->nTypes;i++,type++) { + register unsigned n; + wire= (xkbKeyTypeWireDesc *)buf; + wire->mask = type->mods.mask; + wire->realMods = type->mods.real_mods; + wire->virtualMods = type->mods.vmods; + wire->numLevels = type->num_levels; + wire->nMapEntries = type->map_count; + wire->preserve = (type->preserve!=NULL); + if (client->swapped) { + register int n; + swaps(&wire->virtualMods,n); + } + + buf= (char *)&wire[1]; + if (wire->nMapEntries>0) { + xkbKTMapEntryWireDesc * wire; + XkbKTMapEntryPtr entry; + wire= (xkbKTMapEntryWireDesc *)buf; + entry= type->map; + for (n=0;n<type->map_count;n++,wire++,entry++) { + wire->active= entry->active; + wire->mask= entry->mods.mask; + wire->level= entry->level; + wire->realMods= entry->mods.real_mods; + wire->virtualMods= entry->mods.vmods; + if (client->swapped) { + register int n; + swaps(&wire->virtualMods,n); + } + } + buf= (char *)wire; + if (type->preserve!=NULL) { + xkbModsWireDesc * pwire; + XkbModsPtr preserve; + pwire= (xkbModsWireDesc *)buf; + preserve= type->preserve; + for (n=0;n<type->map_count;n++,pwire++,preserve++) { + pwire->mask= preserve->mask; + pwire->realMods= preserve->real_mods; + pwire->virtualMods= preserve->vmods; + if (client->swapped) { + register int n; + swaps(&pwire->virtualMods,n); + } + } + buf= (char *)pwire; + } + } + } + return buf; +} + +static int +XkbSizeKeySyms(XkbDescPtr xkb,xkbGetMapReply *rep) +{ + XkbSymMapPtr symMap; + unsigned i,len; + unsigned nSyms,nSymsThisKey; + + if (((rep->present&XkbKeySymsMask)==0)||(rep->nKeySyms<1)|| + (!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)) { + rep->present&= ~XkbKeySymsMask; + rep->firstKeySym= rep->nKeySyms= 0; + rep->totalSyms= 0; + return 0; + } + len= rep->nKeySyms*SIZEOF(xkbSymMapWireDesc); + symMap = &xkb->map->key_sym_map[rep->firstKeySym]; + for (i=nSyms=0;i<rep->nKeySyms;i++,symMap++) { + if (symMap->offset!=0) { + nSymsThisKey= XkbNumGroups(symMap->group_info)*symMap->width; + nSyms+= nSymsThisKey; + } + } + len+= nSyms*4; + rep->totalSyms= nSyms; + return len; +} + +static int +XkbSizeVirtualMods(XkbDescPtr xkb,xkbGetMapReply *rep) +{ +register unsigned i,nMods,bit; + + if (((rep->present&XkbVirtualModsMask)==0)||(rep->virtualMods==0)|| + (!xkb)||(!xkb->server)) { + rep->present&= ~XkbVirtualModsMask; + rep->virtualMods= 0; + return 0; + } + for (i=nMods=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + if (rep->virtualMods&bit) + nMods++; + } + return XkbPaddedSize(nMods); +} + +static char * +XkbWriteKeySyms(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf,ClientPtr client) +{ +register KeySym * pSym; +XkbSymMapPtr symMap; +xkbSymMapWireDesc * outMap; +register unsigned i; + + symMap = &xkb->map->key_sym_map[rep->firstKeySym]; + for (i=0;i<rep->nKeySyms;i++,symMap++) { + outMap = (xkbSymMapWireDesc *)buf; + outMap->ktIndex[0] = symMap->kt_index[0]; + outMap->ktIndex[1] = symMap->kt_index[1]; + outMap->ktIndex[2] = symMap->kt_index[2]; + outMap->ktIndex[3] = symMap->kt_index[3]; + outMap->groupInfo = symMap->group_info; + outMap->width= symMap->width; + outMap->nSyms = symMap->width*XkbNumGroups(symMap->group_info); + buf= (char *)&outMap[1]; + if (outMap->nSyms==0) + continue; + + pSym = &xkb->map->syms[symMap->offset]; + memcpy((char *)buf,(char *)pSym,outMap->nSyms*4); + if (client->swapped) { + register int n,nSyms= outMap->nSyms; + swaps(&outMap->nSyms,n); + while (nSyms-->0) { + swapl(buf,n); + buf+= 4; + } + } + else buf+= outMap->nSyms*4; + } + return buf; +} + +static int +XkbSizeKeyActions(XkbDescPtr xkb,xkbGetMapReply *rep) +{ + unsigned i,len,nActs; + register KeyCode firstKey; + + if (((rep->present&XkbKeyActionsMask)==0)||(rep->nKeyActs<1)|| + (!xkb)||(!xkb->server)||(!xkb->server->key_acts)) { + rep->present&= ~XkbKeyActionsMask; + rep->firstKeyAct= rep->nKeyActs= 0; + rep->totalActs= 0; + return 0; + } + firstKey= rep->firstKeyAct; + for (nActs=i=0;i<rep->nKeyActs;i++) { + if (xkb->server->key_acts[i+firstKey]!=0) + nActs+= XkbKeyNumActions(xkb,i+firstKey); + } + len= XkbPaddedSize(rep->nKeyActs)+(nActs*SIZEOF(xkbActionWireDesc)); + rep->totalActs= nActs; + return len; +} + +static char * +XkbWriteKeyActions(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf, + ClientPtr client) +{ + unsigned i; + CARD8 * numDesc; + XkbAnyAction * actDesc; + + numDesc = (CARD8 *)buf; + for (i=0;i<rep->nKeyActs;i++) { + if (xkb->server->key_acts[i+rep->firstKeyAct]==0) + numDesc[i] = 0; + else numDesc[i] = XkbKeyNumActions(xkb,(i+rep->firstKeyAct)); + } + buf+= XkbPaddedSize(rep->nKeyActs); + + actDesc = (XkbAnyAction *)buf; + for (i=0;i<rep->nKeyActs;i++) { + if (xkb->server->key_acts[i+rep->firstKeyAct]!=0) { + unsigned int num; + num = XkbKeyNumActions(xkb,(i+rep->firstKeyAct)); + memcpy((char *)actDesc, + (char*)XkbKeyActionsPtr(xkb,(i+rep->firstKeyAct)), + num*SIZEOF(xkbActionWireDesc)); + actDesc+= num; + } + } + buf = (char *)actDesc; + return buf; +} + +static int +XkbSizeKeyBehaviors(XkbDescPtr xkb,xkbGetMapReply *rep) +{ + unsigned i,len,nBhvr; + XkbBehavior * bhv; + + if (((rep->present&XkbKeyBehaviorsMask)==0)||(rep->nKeyBehaviors<1)|| + (!xkb)||(!xkb->server)||(!xkb->server->behaviors)) { + rep->present&= ~XkbKeyBehaviorsMask; + rep->firstKeyBehavior= rep->nKeyBehaviors= 0; + rep->totalKeyBehaviors= 0; + return 0; + } + bhv= &xkb->server->behaviors[rep->firstKeyBehavior]; + for (nBhvr=i=0;i<rep->nKeyBehaviors;i++,bhv++) { + if (bhv->type!=XkbKB_Default) + nBhvr++; + } + len= nBhvr*SIZEOF(xkbBehaviorWireDesc); + rep->totalKeyBehaviors= nBhvr; + return len; +} + +static char * +XkbWriteKeyBehaviors(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf, + ClientPtr client) +{ + unsigned i; + xkbBehaviorWireDesc *wire; + XkbBehavior *pBhvr; + + wire = (xkbBehaviorWireDesc *)buf; + pBhvr= &xkb->server->behaviors[rep->firstKeyBehavior]; + for (i=0;i<rep->nKeyBehaviors;i++,pBhvr++) { + if (pBhvr->type!=XkbKB_Default) { + wire->key= i+rep->firstKeyBehavior; + wire->type= pBhvr->type; + wire->data= pBhvr->data; + wire++; + } + } + buf = (char *)wire; + return buf; +} + +static int +XkbSizeExplicit(XkbDescPtr xkb,xkbGetMapReply *rep) +{ + unsigned i,len,nRtrn; + + if (((rep->present&XkbExplicitComponentsMask)==0)||(rep->nKeyExplicit<1)|| + (!xkb)||(!xkb->server)||(!xkb->server->explicit)) { + rep->present&= ~XkbExplicitComponentsMask; + rep->firstKeyExplicit= rep->nKeyExplicit= 0; + rep->totalKeyExplicit= 0; + return 0; + } + for (nRtrn=i=0;i<rep->nKeyExplicit;i++) { + if (xkb->server->explicit[i+rep->firstKeyExplicit]!=0) + nRtrn++; + } + rep->totalKeyExplicit= nRtrn; + len= XkbPaddedSize(nRtrn*2); /* two bytes per non-zero explicit component */ + return len; +} + +static char * +XkbWriteExplicit(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf,ClientPtr client) +{ +unsigned i; +char * start; +unsigned char * pExp; + + start= buf; + pExp= &xkb->server->explicit[rep->firstKeyExplicit]; + for (i=0;i<rep->nKeyExplicit;i++,pExp++) { + if (*pExp!=0) { + *buf++= i+rep->firstKeyExplicit; + *buf++= *pExp; + } + } + i= XkbPaddedSize(buf-start)-(buf-start); /* pad to word boundary */ + return buf+i; +} + +static int +XkbSizeModifierMap(XkbDescPtr xkb,xkbGetMapReply *rep) +{ + unsigned i,len,nRtrn; + + if (((rep->present&XkbModifierMapMask)==0)||(rep->nModMapKeys<1)|| + (!xkb)||(!xkb->map)||(!xkb->map->modmap)) { + rep->present&= ~XkbModifierMapMask; + rep->firstModMapKey= rep->nModMapKeys= 0; + rep->totalModMapKeys= 0; + return 0; + } + for (nRtrn=i=0;i<rep->nModMapKeys;i++) { + if (xkb->map->modmap[i+rep->firstModMapKey]!=0) + nRtrn++; + } + rep->totalModMapKeys= nRtrn; + len= XkbPaddedSize(nRtrn*2); /* two bytes per non-zero modmap component */ + return len; +} + +static char * +XkbWriteModifierMap(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf, + ClientPtr client) +{ +unsigned i; +char * start; +unsigned char * pMap; + + start= buf; + pMap= &xkb->map->modmap[rep->firstModMapKey]; + for (i=0;i<rep->nModMapKeys;i++,pMap++) { + if (*pMap!=0) { + *buf++= i+rep->firstModMapKey; + *buf++= *pMap; + } + } + i= XkbPaddedSize(buf-start)-(buf-start); /* pad to word boundary */ + return buf+i; +} + +static int +XkbSizeVirtualModMap(XkbDescPtr xkb,xkbGetMapReply *rep) +{ + unsigned i,len,nRtrn; + + if (((rep->present&XkbVirtualModMapMask)==0)||(rep->nVModMapKeys<1)|| + (!xkb)||(!xkb->server)||(!xkb->server->vmodmap)) { + rep->present&= ~XkbVirtualModMapMask; + rep->firstVModMapKey= rep->nVModMapKeys= 0; + rep->totalVModMapKeys= 0; + return 0; + } + for (nRtrn=i=0;i<rep->nVModMapKeys;i++) { + if (xkb->server->vmodmap[i+rep->firstVModMapKey]!=0) + nRtrn++; + } + rep->totalVModMapKeys= nRtrn; + len= nRtrn*SIZEOF(xkbVModMapWireDesc); + return len; +} + +static char * +XkbWriteVirtualModMap(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf, + ClientPtr client) +{ +unsigned i; +xkbVModMapWireDesc * wire; +unsigned short * pMap; + + wire= (xkbVModMapWireDesc *)buf; + pMap= &xkb->server->vmodmap[rep->firstVModMapKey]; + for (i=0;i<rep->nVModMapKeys;i++,pMap++) { + if (*pMap!=0) { + wire->key= i+rep->firstVModMapKey; + wire->vmods= *pMap; + wire++; + } + } + return (char *)wire; +} + +static Status +XkbComputeGetMapReplySize(XkbDescPtr xkb,xkbGetMapReply *rep) +{ +int len; + + rep->minKeyCode= xkb->min_key_code; + rep->maxKeyCode= xkb->max_key_code; + len= XkbSizeKeyTypes(xkb,rep); + len+= XkbSizeKeySyms(xkb,rep); + len+= XkbSizeKeyActions(xkb,rep); + len+= XkbSizeKeyBehaviors(xkb,rep); + len+= XkbSizeVirtualMods(xkb,rep); + len+= XkbSizeExplicit(xkb,rep); + len+= XkbSizeModifierMap(xkb,rep); + len+= XkbSizeVirtualModMap(xkb,rep); + rep->length+= (len/4); + return Success; +} + +static int +XkbSendMap(ClientPtr client,XkbDescPtr xkb,xkbGetMapReply *rep) +{ +unsigned i,len; +char *desc,*start; + + len= (rep->length*4)-(SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply)); + start= desc= calloc(1, len); + if (!start) + return BadAlloc; + if ( rep->nTypes>0 ) + desc = XkbWriteKeyTypes(xkb,rep,desc,client); + if ( rep->nKeySyms>0 ) + desc = XkbWriteKeySyms(xkb,rep,desc,client); + if ( rep->nKeyActs>0 ) + desc = XkbWriteKeyActions(xkb,rep,desc,client); + if ( rep->totalKeyBehaviors>0 ) + desc = XkbWriteKeyBehaviors(xkb,rep,desc,client); + if ( rep->virtualMods ) { + register int sz,bit; + for (i=sz=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + if (rep->virtualMods&bit) { + desc[sz++]= xkb->server->vmods[i]; + } + } + desc+= XkbPaddedSize(sz); + } + if ( rep->totalKeyExplicit>0 ) + desc= XkbWriteExplicit(xkb,rep,desc,client); + if ( rep->totalModMapKeys>0 ) + desc= XkbWriteModifierMap(xkb,rep,desc,client); + if ( rep->totalVModMapKeys>0 ) + desc= XkbWriteVirtualModMap(xkb,rep,desc,client); + if ((desc-start)!=(len)) { + ErrorF("[xkb] BOGUS LENGTH in write keyboard desc, expected %d, got %ld\n", + len, (unsigned long)(desc-start)); + } + if (client->swapped) { + register int n; + swaps(&rep->sequenceNumber,n); + swapl(&rep->length,n); + swaps(&rep->present,n); + swaps(&rep->totalSyms,n); + swaps(&rep->totalActs,n); + } + WriteToClient(client, (i=SIZEOF(xkbGetMapReply)), (char *)rep); + WriteToClient(client, len, start); + free((char *)start); + return Success; +} + +int +ProcXkbGetMap(ClientPtr client) +{ + DeviceIntPtr dev; + xkbGetMapReply rep; + XkbDescRec *xkb; + int n,status; + + REQUEST(xkbGetMapReq); + REQUEST_SIZE_MATCH(xkbGetMapReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); + CHK_MASK_OVERLAP(0x01,stuff->full,stuff->partial); + CHK_MASK_LEGAL(0x02,stuff->full,XkbAllMapComponentsMask); + CHK_MASK_LEGAL(0x03,stuff->partial,XkbAllMapComponentsMask); + + xkb= dev->key->xkbInfo->desc; + bzero(&rep,sizeof(xkbGetMapReply)); + rep.type= X_Reply; + rep.sequenceNumber= client->sequence; + rep.length = (SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply))>>2; + rep.deviceID = dev->id; + rep.present = stuff->partial|stuff->full; + rep.minKeyCode = xkb->min_key_code; + rep.maxKeyCode = xkb->max_key_code; + if ( stuff->full&XkbKeyTypesMask ) { + rep.firstType = 0; + rep.nTypes = xkb->map->num_types; + } + else if (stuff->partial&XkbKeyTypesMask) { + if (((unsigned)stuff->firstType+stuff->nTypes)>xkb->map->num_types) { + client->errorValue = _XkbErrCode4(0x04,xkb->map->num_types, + stuff->firstType,stuff->nTypes); + return BadValue; + } + rep.firstType = stuff->firstType; + rep.nTypes = stuff->nTypes; + } + else rep.nTypes = 0; + rep.totalTypes = xkb->map->num_types; + + n= XkbNumKeys(xkb); + if ( stuff->full&XkbKeySymsMask ) { + rep.firstKeySym = xkb->min_key_code; + rep.nKeySyms = n; + } + else if (stuff->partial&XkbKeySymsMask) { + CHK_KEY_RANGE(0x05,stuff->firstKeySym,stuff->nKeySyms,xkb); + rep.firstKeySym = stuff->firstKeySym; + rep.nKeySyms = stuff->nKeySyms; + } + else rep.nKeySyms = 0; + rep.totalSyms= 0; + + if ( stuff->full&XkbKeyActionsMask ) { + rep.firstKeyAct= xkb->min_key_code; + rep.nKeyActs= n; + } + else if (stuff->partial&XkbKeyActionsMask) { + CHK_KEY_RANGE(0x07,stuff->firstKeyAct,stuff->nKeyActs,xkb); + rep.firstKeyAct= stuff->firstKeyAct; + rep.nKeyActs= stuff->nKeyActs; + } + else rep.nKeyActs= 0; + rep.totalActs= 0; + + if ( stuff->full&XkbKeyBehaviorsMask ) { + rep.firstKeyBehavior = xkb->min_key_code; + rep.nKeyBehaviors = n; + } + else if (stuff->partial&XkbKeyBehaviorsMask) { + CHK_KEY_RANGE(0x09,stuff->firstKeyBehavior,stuff->nKeyBehaviors,xkb); + rep.firstKeyBehavior= stuff->firstKeyBehavior; + rep.nKeyBehaviors= stuff->nKeyBehaviors; + } + else rep.nKeyBehaviors = 0; + rep.totalKeyBehaviors= 0; + + if (stuff->full&XkbVirtualModsMask) + rep.virtualMods= ~0; + else if (stuff->partial&XkbVirtualModsMask) + rep.virtualMods= stuff->virtualMods; + + if (stuff->full&XkbExplicitComponentsMask) { + rep.firstKeyExplicit= xkb->min_key_code; + rep.nKeyExplicit= n; + } + else if (stuff->partial&XkbExplicitComponentsMask) { + CHK_KEY_RANGE(0x0B,stuff->firstKeyExplicit,stuff->nKeyExplicit,xkb); + rep.firstKeyExplicit= stuff->firstKeyExplicit; + rep.nKeyExplicit= stuff->nKeyExplicit; + } + else rep.nKeyExplicit = 0; + rep.totalKeyExplicit= 0; + + if (stuff->full&XkbModifierMapMask) { + rep.firstModMapKey= xkb->min_key_code; + rep.nModMapKeys= n; + } + else if (stuff->partial&XkbModifierMapMask) { + CHK_KEY_RANGE(0x0D,stuff->firstModMapKey,stuff->nModMapKeys,xkb); + rep.firstModMapKey= stuff->firstModMapKey; + rep.nModMapKeys= stuff->nModMapKeys; + } + else rep.nModMapKeys = 0; + rep.totalModMapKeys= 0; + + if (stuff->full&XkbVirtualModMapMask) { + rep.firstVModMapKey= xkb->min_key_code; + rep.nVModMapKeys= n; + } + else if (stuff->partial&XkbVirtualModMapMask) { + CHK_KEY_RANGE(0x0F,stuff->firstVModMapKey,stuff->nVModMapKeys,xkb); + rep.firstVModMapKey= stuff->firstVModMapKey; + rep.nVModMapKeys= stuff->nVModMapKeys; + } + else rep.nVModMapKeys = 0; + rep.totalVModMapKeys= 0; + + if ((status=XkbComputeGetMapReplySize(xkb,&rep))!=Success) + return status; + return XkbSendMap(client,xkb,&rep); +} + +/***====================================================================***/ + +static int +CheckKeyTypes( ClientPtr client, + XkbDescPtr xkb, + xkbSetMapReq * req, + xkbKeyTypeWireDesc **wireRtrn, + int * nMapsRtrn, + CARD8 * mapWidthRtrn) +{ +unsigned nMaps; +register unsigned i,n; +register CARD8 * map; +register xkbKeyTypeWireDesc *wire = *wireRtrn; + + if (req->firstType>((unsigned)xkb->map->num_types)) { + *nMapsRtrn = _XkbErrCode3(0x01,req->firstType,xkb->map->num_types); + return 0; + } + if (req->flags&XkbSetMapResizeTypes) { + nMaps = req->firstType+req->nTypes; + if (nMaps<XkbNumRequiredTypes) { /* canonical types must be there */ + *nMapsRtrn= _XkbErrCode4(0x02,req->firstType,req->nTypes,4); + return 0; + } + } + else if (req->present&XkbKeyTypesMask) { + nMaps = xkb->map->num_types; + if ((req->firstType+req->nTypes)>nMaps) { + *nMapsRtrn = req->firstType+req->nTypes; + return 0; + } + } + else { + *nMapsRtrn = xkb->map->num_types; + for (i=0;i<xkb->map->num_types;i++) { + mapWidthRtrn[i] = xkb->map->types[i].num_levels; + } + return 1; + } + + for (i=0;i<req->firstType;i++) { + mapWidthRtrn[i] = xkb->map->types[i].num_levels; + } + for (i=0;i<req->nTypes;i++) { + unsigned width; + if (client->swapped) { + register int s; + swaps(&wire->virtualMods,s); + } + n= i+req->firstType; + width= wire->numLevels; + if (width<1) { + *nMapsRtrn= _XkbErrCode3(0x04,n,width); + return 0; + } + else if ((n==XkbOneLevelIndex)&&(width!=1)) { /* must be width 1 */ + *nMapsRtrn= _XkbErrCode3(0x05,n,width); + return 0; + } + else if ((width!=2)&& + ((n==XkbTwoLevelIndex)||(n==XkbKeypadIndex)|| + (n==XkbAlphabeticIndex))) { + /* TWO_LEVEL, ALPHABETIC and KEYPAD must be width 2 */ + *nMapsRtrn= _XkbErrCode3(0x05,n,width); + return 0; + } + if (wire->nMapEntries>0) { + xkbKTSetMapEntryWireDesc * mapWire; + xkbModsWireDesc * preWire; + mapWire= (xkbKTSetMapEntryWireDesc *)&wire[1]; + preWire= (xkbModsWireDesc *)&mapWire[wire->nMapEntries]; + for (n=0;n<wire->nMapEntries;n++) { + if (client->swapped) { + register int s; + swaps(&mapWire[n].virtualMods,s); + } + if (mapWire[n].realMods&(~wire->realMods)) { + *nMapsRtrn= _XkbErrCode4(0x06,n,mapWire[n].realMods, + wire->realMods); + return 0; + } + if (mapWire[n].virtualMods&(~wire->virtualMods)) { + *nMapsRtrn= _XkbErrCode3(0x07,n,mapWire[n].virtualMods); + return 0; + } + if (mapWire[n].level>=wire->numLevels) { + *nMapsRtrn= _XkbErrCode4(0x08,n,wire->numLevels, + mapWire[n].level); + return 0; + } + if (wire->preserve) { + if (client->swapped) { + register int s; + swaps(&preWire[n].virtualMods,s); + } + if (preWire[n].realMods&(~mapWire[n].realMods)) { + *nMapsRtrn= _XkbErrCode4(0x09,n,preWire[n].realMods, + mapWire[n].realMods); + return 0; + } + if (preWire[n].virtualMods&(~mapWire[n].virtualMods)) { + *nMapsRtrn=_XkbErrCode3(0x0a,n,preWire[n].virtualMods); + return 0; + } + } + } + if (wire->preserve) + map= (CARD8 *)&preWire[wire->nMapEntries]; + else map= (CARD8 *)&mapWire[wire->nMapEntries]; + } + else map= (CARD8 *)&wire[1]; + mapWidthRtrn[i+req->firstType] = wire->numLevels; + wire= (xkbKeyTypeWireDesc *)map; + } + for (i=req->firstType+req->nTypes;i<nMaps;i++) { + mapWidthRtrn[i] = xkb->map->types[i].num_levels; + } + *nMapsRtrn = nMaps; + *wireRtrn = wire; + return 1; +} + +static int +CheckKeySyms( ClientPtr client, + XkbDescPtr xkb, + xkbSetMapReq * req, + int nTypes, + CARD8 * mapWidths, + CARD16 * symsPerKey, + xkbSymMapWireDesc ** wireRtrn, + int * errorRtrn) +{ +register unsigned i; +XkbSymMapPtr map; +xkbSymMapWireDesc* wire = *wireRtrn; + + if (!(XkbKeySymsMask&req->present)) + return 1; + CHK_REQ_KEY_RANGE2(0x11,req->firstKeySym,req->nKeySyms,req,(*errorRtrn),0); + map = &xkb->map->key_sym_map[xkb->min_key_code]; + for (i=xkb->min_key_code;i<(unsigned)req->firstKeySym;i++,map++) { + register int g,ng,w; + ng= XkbNumGroups(map->group_info); + for (w=g=0;g<ng;g++) { + if (map->kt_index[g]>=(unsigned)nTypes) { + *errorRtrn = _XkbErrCode4(0x13,i,g,map->kt_index[g]); + return 0; + } + if (mapWidths[map->kt_index[g]]>w) + w= mapWidths[map->kt_index[g]]; + } + symsPerKey[i] = w*ng; + } + for (i=0;i<req->nKeySyms;i++) { + KeySym *pSyms; + register unsigned nG; + if (client->swapped) { + swaps(&wire->nSyms,nG); + } + nG = XkbNumGroups(wire->groupInfo); + if (nG>XkbNumKbdGroups) { + *errorRtrn = _XkbErrCode3(0x14,i+req->firstKeySym,nG); + return 0; + } + if (nG>0) { + register int g,w; + for (g=w=0;g<nG;g++) { + if (wire->ktIndex[g]>=(unsigned)nTypes) { + *errorRtrn= _XkbErrCode4(0x15,i+req->firstKeySym,g, + wire->ktIndex[g]); + return 0; + } + if (mapWidths[wire->ktIndex[g]]>w) + w= mapWidths[wire->ktIndex[g]]; + } + if (wire->width!=w) { + *errorRtrn= _XkbErrCode3(0x16,i+req->firstKeySym,wire->width); + return 0; + } + w*= nG; + symsPerKey[i+req->firstKeySym] = w; + if (w!=wire->nSyms) { + *errorRtrn=_XkbErrCode4(0x16,i+req->firstKeySym,wire->nSyms,w); + return 0; + } + } + else if (wire->nSyms!=0) { + *errorRtrn = _XkbErrCode3(0x17,i+req->firstKeySym,wire->nSyms); + return 0; + } + pSyms = (KeySym *)&wire[1]; + wire = (xkbSymMapWireDesc *)&pSyms[wire->nSyms]; + } + + map = &xkb->map->key_sym_map[i]; + for (;i<=(unsigned)xkb->max_key_code;i++,map++) { + register int g,nG,w; + nG= XkbKeyNumGroups(xkb,i); + for (w=g=0;g<nG;g++) { + if (map->kt_index[g]>=(unsigned)nTypes) { + *errorRtrn = _XkbErrCode4(0x18,i,g,map->kt_index[g]); + return 0; + } + if (mapWidths[map->kt_index[g]]>w) + w= mapWidths[map->kt_index[g]]; + } + symsPerKey[i] = w*nG; + } + *wireRtrn = wire; + return 1; +} + +static int +CheckKeyActions( XkbDescPtr xkb, + xkbSetMapReq * req, + int nTypes, + CARD8 * mapWidths, + CARD16 * symsPerKey, + CARD8 ** wireRtrn, + int * nActsRtrn) +{ +int nActs; +CARD8 * wire = *wireRtrn; +register unsigned i; + + if (!(XkbKeyActionsMask&req->present)) + return 1; + CHK_REQ_KEY_RANGE2(0x21,req->firstKeyAct,req->nKeyActs,req,(*nActsRtrn),0); + for (nActs=i=0;i<req->nKeyActs;i++) { + if (wire[0]!=0) { + if (wire[0]==symsPerKey[i+req->firstKeyAct]) + nActs+= wire[0]; + else { + *nActsRtrn= _XkbErrCode3(0x23,i+req->firstKeyAct,wire[0]); + return 0; + } + } + wire++; + } + if (req->nKeyActs%4) + wire+= 4-(req->nKeyActs%4); + *wireRtrn = (CARD8 *)(((XkbAnyAction *)wire)+nActs); + *nActsRtrn = nActs; + return 1; +} + +static int +CheckKeyBehaviors( XkbDescPtr xkb, + xkbSetMapReq * req, + xkbBehaviorWireDesc ** wireRtrn, + int * errorRtrn) +{ +register xkbBehaviorWireDesc * wire = *wireRtrn; +register XkbServerMapPtr server = xkb->server; +register unsigned i; +unsigned first,last; + + if (((req->present&XkbKeyBehaviorsMask)==0)||(req->nKeyBehaviors<1)) { + req->present&= ~XkbKeyBehaviorsMask; + req->nKeyBehaviors= 0; + return 1; + } + first= req->firstKeyBehavior; + last= req->firstKeyBehavior+req->nKeyBehaviors-1; + if (first<req->minKeyCode) { + *errorRtrn = _XkbErrCode3(0x31,first,req->minKeyCode); + return 0; + } + if (last>req->maxKeyCode) { + *errorRtrn = _XkbErrCode3(0x32,last,req->maxKeyCode); + return 0; + } + + for (i=0;i<req->totalKeyBehaviors;i++,wire++) { + if ((wire->key<first)||(wire->key>last)) { + *errorRtrn = _XkbErrCode4(0x33,first,last,wire->key); + return 0; + } + if ((wire->type&XkbKB_Permanent)&& + ((server->behaviors[wire->key].type!=wire->type)|| + (server->behaviors[wire->key].data!=wire->data))) { + *errorRtrn = _XkbErrCode3(0x33,wire->key,wire->type); + return 0; + } + if ((wire->type==XkbKB_RadioGroup)&& + ((wire->data&(~XkbKB_RGAllowNone))>XkbMaxRadioGroups)) { + *errorRtrn= _XkbErrCode4(0x34,wire->key,wire->data, + XkbMaxRadioGroups); + return 0; + } + if ((wire->type==XkbKB_Overlay1)||(wire->type==XkbKB_Overlay2)) { + CHK_KEY_RANGE2(0x35,wire->key,1,xkb,*errorRtrn,0); + } + } + *wireRtrn = wire; + return 1; +} + +static int +CheckVirtualMods( XkbDescRec * xkb, + xkbSetMapReq * req, + CARD8 ** wireRtrn, + int * errorRtrn) +{ +register CARD8 *wire = *wireRtrn; +register unsigned i,nMods,bit; + + if (((req->present&XkbVirtualModsMask)==0)||(req->virtualMods==0)) + return 1; + for (i=nMods=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + if (req->virtualMods&bit) + nMods++; + } + *wireRtrn= (wire+XkbPaddedSize(nMods)); + return 1; +} + +static int +CheckKeyExplicit( XkbDescPtr xkb, + xkbSetMapReq * req, + CARD8 ** wireRtrn, + int * errorRtrn) +{ +register CARD8 * wire = *wireRtrn; +CARD8 * start; +register unsigned i; +int first,last; + + if (((req->present&XkbExplicitComponentsMask)==0)||(req->nKeyExplicit<1)) { + req->present&= ~XkbExplicitComponentsMask; + req->nKeyExplicit= 0; + return 1; + } + first= req->firstKeyExplicit; + last= first+req->nKeyExplicit-1; + if (first<req->minKeyCode) { + *errorRtrn = _XkbErrCode3(0x51,first,req->minKeyCode); + return 0; + } + if (last>req->maxKeyCode) { + *errorRtrn = _XkbErrCode3(0x52,last,req->maxKeyCode); + return 0; + } + start= wire; + for (i=0;i<req->totalKeyExplicit;i++,wire+=2) { + if ((wire[0]<first)||(wire[0]>last)) { + *errorRtrn = _XkbErrCode4(0x53,first,last,wire[0]); + return 0; + } + if (wire[1]&(~XkbAllExplicitMask)) { + *errorRtrn= _XkbErrCode3(0x52,~XkbAllExplicitMask,wire[1]); + return 0; + } + } + wire+= XkbPaddedSize(wire-start)-(wire-start); + *wireRtrn= wire; + return 1; +} + +static int +CheckModifierMap(XkbDescPtr xkb,xkbSetMapReq *req,CARD8 **wireRtrn,int *errRtrn) +{ +register CARD8 * wire = *wireRtrn; +CARD8 * start; +register unsigned i; +int first,last; + + if (((req->present&XkbModifierMapMask)==0)||(req->nModMapKeys<1)) { + req->present&= ~XkbModifierMapMask; + req->nModMapKeys= 0; + return 1; + } + first= req->firstModMapKey; + last= first+req->nModMapKeys-1; + if (first<req->minKeyCode) { + *errRtrn = _XkbErrCode3(0x61,first,req->minKeyCode); + return 0; + } + if (last>req->maxKeyCode) { + *errRtrn = _XkbErrCode3(0x62,last,req->maxKeyCode); + return 0; + } + start= wire; + for (i=0;i<req->totalModMapKeys;i++,wire+=2) { + if ((wire[0]<first)||(wire[0]>last)) { + *errRtrn = _XkbErrCode4(0x63,first,last,wire[0]); + return 0; + } + } + wire+= XkbPaddedSize(wire-start)-(wire-start); + *wireRtrn= wire; + return 1; +} + +static int +CheckVirtualModMap( XkbDescPtr xkb, + xkbSetMapReq *req, + xkbVModMapWireDesc **wireRtrn, + int *errRtrn) +{ +register xkbVModMapWireDesc * wire = *wireRtrn; +register unsigned i; +int first,last; + + if (((req->present&XkbVirtualModMapMask)==0)||(req->nVModMapKeys<1)) { + req->present&= ~XkbVirtualModMapMask; + req->nVModMapKeys= 0; + return 1; + } + first= req->firstVModMapKey; + last= first+req->nVModMapKeys-1; + if (first<req->minKeyCode) { + *errRtrn = _XkbErrCode3(0x71,first,req->minKeyCode); + return 0; + } + if (last>req->maxKeyCode) { + *errRtrn = _XkbErrCode3(0x72,last,req->maxKeyCode); + return 0; + } + for (i=0;i<req->totalVModMapKeys;i++,wire++) { + if ((wire->key<first)||(wire->key>last)) { + *errRtrn = _XkbErrCode4(0x73,first,last,wire->key); + return 0; + } + } + *wireRtrn= wire; + return 1; +} + +static char * +SetKeyTypes( XkbDescPtr xkb, + xkbSetMapReq * req, + xkbKeyTypeWireDesc * wire, + XkbChangesPtr changes) +{ +register unsigned i; +unsigned first,last; +CARD8 *map; + + if ((unsigned)(req->firstType+req->nTypes)>xkb->map->size_types) { + i= req->firstType+req->nTypes; + if (XkbAllocClientMap(xkb,XkbKeyTypesMask,i)!=Success) { + return NULL; + } + } + if ((unsigned)(req->firstType+req->nTypes)>xkb->map->num_types) + xkb->map->num_types= req->firstType+req->nTypes; + + for (i=0;i<req->nTypes;i++) { + XkbKeyTypePtr pOld; + register unsigned n; + + if (XkbResizeKeyType(xkb,i+req->firstType,wire->nMapEntries, + wire->preserve,wire->numLevels)!=Success) { + return NULL; + } + pOld = &xkb->map->types[i+req->firstType]; + map = (CARD8 *)&wire[1]; + + pOld->mods.real_mods = wire->realMods; + pOld->mods.vmods= wire->virtualMods; + pOld->num_levels = wire->numLevels; + pOld->map_count= wire->nMapEntries; + + pOld->mods.mask= pOld->mods.real_mods| + XkbMaskForVMask(xkb,pOld->mods.vmods); + + if (wire->nMapEntries) { + xkbKTSetMapEntryWireDesc *mapWire; + xkbModsWireDesc *preWire; + unsigned tmp; + mapWire= (xkbKTSetMapEntryWireDesc *)map; + preWire= (xkbModsWireDesc *)&mapWire[wire->nMapEntries]; + for (n=0;n<wire->nMapEntries;n++) { + pOld->map[n].active= 1; + pOld->map[n].mods.mask= mapWire[n].realMods; + pOld->map[n].mods.real_mods= mapWire[n].realMods; + pOld->map[n].mods.vmods= mapWire[n].virtualMods; + pOld->map[n].level= mapWire[n].level; + if (mapWire[n].virtualMods!=0) { + tmp= XkbMaskForVMask(xkb,mapWire[n].virtualMods); + pOld->map[n].active= (tmp!=0); + pOld->map[n].mods.mask|= tmp; + } + if (wire->preserve) { + pOld->preserve[n].real_mods= preWire[n].realMods; + pOld->preserve[n].vmods= preWire[n].virtualMods; + tmp= XkbMaskForVMask(xkb,preWire[n].virtualMods); + pOld->preserve[n].mask= preWire[n].realMods|tmp; + } + } + if (wire->preserve) + map= (CARD8 *)&preWire[wire->nMapEntries]; + else map= (CARD8 *)&mapWire[wire->nMapEntries]; + } + else map= (CARD8 *)&wire[1]; + wire = (xkbKeyTypeWireDesc *)map; + } + first= req->firstType; + last= first+req->nTypes-1; /* last changed type */ + if (changes->map.changed&XkbKeyTypesMask) { + int oldLast; + oldLast= changes->map.first_type+changes->map.num_types-1; + if (changes->map.first_type<first) + first= changes->map.first_type; + if (oldLast>last) + last= oldLast; + } + changes->map.changed|= XkbKeyTypesMask; + changes->map.first_type = first; + changes->map.num_types = (last-first)+1; + return (char *)wire; +} + +static char * +SetKeySyms( ClientPtr client, + XkbDescPtr xkb, + xkbSetMapReq * req, + xkbSymMapWireDesc * wire, + XkbChangesPtr changes, + DeviceIntPtr dev) +{ +register unsigned i,s; +XkbSymMapPtr oldMap; +KeySym * newSyms; +KeySym * pSyms; +unsigned first,last; + + oldMap = &xkb->map->key_sym_map[req->firstKeySym]; + for (i=0;i<req->nKeySyms;i++,oldMap++) { + pSyms = (KeySym *)&wire[1]; + if (wire->nSyms>0) { + newSyms = XkbResizeKeySyms(xkb,i+req->firstKeySym,wire->nSyms); + for (s=0;s<wire->nSyms;s++) { + newSyms[s]= pSyms[s]; + } + if (client->swapped) { + int n; + for (s=0;s<wire->nSyms;s++) { + swapl(&newSyms[s],n); + } + } + } + oldMap->kt_index[0] = wire->ktIndex[0]; + oldMap->kt_index[1] = wire->ktIndex[1]; + oldMap->kt_index[2] = wire->ktIndex[2]; + oldMap->kt_index[3] = wire->ktIndex[3]; + oldMap->group_info = wire->groupInfo; + oldMap->width = wire->width; + wire= (xkbSymMapWireDesc *)&pSyms[wire->nSyms]; + } + first= req->firstKeySym; + last= first+req->nKeySyms-1; + if (changes->map.changed&XkbKeySymsMask) { + int oldLast= (changes->map.first_key_sym+changes->map.num_key_syms-1); + if (changes->map.first_key_sym<first) + first= changes->map.first_key_sym; + if (oldLast>last) + last= oldLast; + } + changes->map.changed|= XkbKeySymsMask; + changes->map.first_key_sym = first; + changes->map.num_key_syms = (last-first+1); + + s= 0; + for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { + if (XkbKeyNumGroups(xkb,i)>s) + s= XkbKeyNumGroups(xkb,i); + } + if (s!=xkb->ctrls->num_groups) { + xkbControlsNotify cn; + XkbControlsRec old; + cn.keycode= 0; + cn.eventType= 0; + cn.requestMajor= XkbReqCode; + cn.requestMinor= X_kbSetMap; + old= *xkb->ctrls; + xkb->ctrls->num_groups= s; + if (XkbComputeControlsNotify(dev,&old,xkb->ctrls,&cn,FALSE)) + XkbSendControlsNotify(dev,&cn); + } + return (char *)wire; +} + +static char * +SetKeyActions( XkbDescPtr xkb, + xkbSetMapReq * req, + CARD8 * wire, + XkbChangesPtr changes) +{ +register unsigned i,first,last; +CARD8 * nActs = wire; +XkbAction * newActs; + + wire+= XkbPaddedSize(req->nKeyActs); + for (i=0;i<req->nKeyActs;i++) { + if (nActs[i]==0) + xkb->server->key_acts[i+req->firstKeyAct]= 0; + else { + newActs= XkbResizeKeyActions(xkb,i+req->firstKeyAct,nActs[i]); + memcpy((char *)newActs,(char *)wire, + nActs[i]*SIZEOF(xkbActionWireDesc)); + wire+= nActs[i]*SIZEOF(xkbActionWireDesc); + } + } + first= req->firstKeyAct; + last= (first+req->nKeyActs-1); + if (changes->map.changed&XkbKeyActionsMask) { + int oldLast; + oldLast= changes->map.first_key_act+changes->map.num_key_acts-1; + if (changes->map.first_key_act<first) + first= changes->map.first_key_act; + if (oldLast>last) + last= oldLast; + } + changes->map.changed|= XkbKeyActionsMask; + changes->map.first_key_act= first; + changes->map.num_key_acts= (last-first+1); + return (char *)wire; +} + +static char * +SetKeyBehaviors( XkbSrvInfoPtr xkbi, + xkbSetMapReq *req, + xkbBehaviorWireDesc *wire, + XkbChangesPtr changes) +{ +register unsigned i; +int maxRG = -1; +XkbDescPtr xkb = xkbi->desc; +XkbServerMapPtr server = xkb->server; +unsigned first,last; + + first= req->firstKeyBehavior; + last= req->firstKeyBehavior+req->nKeyBehaviors-1; + bzero(&server->behaviors[first],req->nKeyBehaviors*sizeof(XkbBehavior)); + for (i=0;i<req->totalKeyBehaviors;i++) { + if ((server->behaviors[wire->key].type&XkbKB_Permanent)==0) { + server->behaviors[wire->key].type= wire->type; + server->behaviors[wire->key].data= wire->data; + if ((wire->type==XkbKB_RadioGroup)&&(((int)wire->data)>maxRG)) + maxRG= wire->data + 1; + } + wire++; + } + + if (maxRG>(int)xkbi->nRadioGroups) { + int sz = maxRG*sizeof(XkbRadioGroupRec); + if (xkbi->radioGroups) + xkbi->radioGroups= realloc(xkbi->radioGroups,sz); + else xkbi->radioGroups= calloc(1, sz); + if (xkbi->radioGroups) { + if (xkbi->nRadioGroups) + bzero(&xkbi->radioGroups[xkbi->nRadioGroups], + (maxRG-xkbi->nRadioGroups)*sizeof(XkbRadioGroupRec)); + xkbi->nRadioGroups= maxRG; + } + else xkbi->nRadioGroups= 0; + /* should compute members here */ + } + if (changes->map.changed&XkbKeyBehaviorsMask) { + unsigned oldLast; + oldLast= changes->map.first_key_behavior+ + changes->map.num_key_behaviors-1; + if (changes->map.first_key_behavior<req->firstKeyBehavior) + first= changes->map.first_key_behavior; + if (oldLast>last) + last= oldLast; + } + changes->map.changed|= XkbKeyBehaviorsMask; + changes->map.first_key_behavior = first; + changes->map.num_key_behaviors = (last-first+1); + return (char *)wire; +} + +static char * +SetVirtualMods(XkbSrvInfoPtr xkbi,xkbSetMapReq *req,CARD8 *wire, + XkbChangesPtr changes) +{ +register int i,bit,nMods; +XkbServerMapPtr srv = xkbi->desc->server; + + if (((req->present&XkbVirtualModsMask)==0)||(req->virtualMods==0)) + return (char *)wire; + for (i=nMods=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + if (req->virtualMods&bit) { + if (srv->vmods[i]!=wire[nMods]) { + changes->map.changed|= XkbVirtualModsMask; + changes->map.vmods|= bit; + srv->vmods[i]= wire[nMods]; + } + nMods++; + } + } + return (char *)(wire+XkbPaddedSize(nMods)); +} + +static char * +SetKeyExplicit(XkbSrvInfoPtr xkbi,xkbSetMapReq *req,CARD8 *wire, + XkbChangesPtr changes) +{ +register unsigned i,first,last; +XkbServerMapPtr xkb = xkbi->desc->server; +CARD8 * start; + + start= wire; + first= req->firstKeyExplicit; + last= req->firstKeyExplicit+req->nKeyExplicit-1; + bzero(&xkb->explicit[first],req->nKeyExplicit); + for (i=0;i<req->totalKeyExplicit;i++,wire+= 2) { + xkb->explicit[wire[0]]= wire[1]; + } + if (first>0) { + if (changes->map.changed&XkbExplicitComponentsMask) { + int oldLast; + oldLast= changes->map.first_key_explicit+ + changes->map.num_key_explicit-1; + if (changes->map.first_key_explicit<first) + first= changes->map.first_key_explicit; + if (oldLast>last) + last= oldLast; + } + changes->map.first_key_explicit= first; + changes->map.num_key_explicit= (last-first)+1; + } + wire+= XkbPaddedSize(wire-start)-(wire-start); + return (char *)wire; +} + +static char * +SetModifierMap( XkbSrvInfoPtr xkbi, + xkbSetMapReq * req, + CARD8 * wire, + XkbChangesPtr changes) +{ +register unsigned i,first,last; +XkbClientMapPtr xkb = xkbi->desc->map; +CARD8 * start; + + start= wire; + first= req->firstModMapKey; + last= req->firstModMapKey+req->nModMapKeys-1; + bzero(&xkb->modmap[first],req->nModMapKeys); + for (i=0;i<req->totalModMapKeys;i++,wire+= 2) { + xkb->modmap[wire[0]]= wire[1]; + } + if (first>0) { + if (changes->map.changed&XkbModifierMapMask) { + int oldLast; + oldLast= changes->map.first_modmap_key+ + changes->map.num_modmap_keys-1; + if (changes->map.first_modmap_key<first) + first= changes->map.first_modmap_key; + if (oldLast>last) + last= oldLast; + } + changes->map.first_modmap_key= first; + changes->map.num_modmap_keys= (last-first)+1; + } + wire+= XkbPaddedSize(wire-start)-(wire-start); + return (char *)wire; +} + +static char * +SetVirtualModMap( XkbSrvInfoPtr xkbi, + xkbSetMapReq * req, + xkbVModMapWireDesc * wire, + XkbChangesPtr changes) +{ +register unsigned i,first,last; +XkbServerMapPtr srv = xkbi->desc->server; + + first= req->firstVModMapKey; + last= req->firstVModMapKey+req->nVModMapKeys-1; + bzero(&srv->vmodmap[first],req->nVModMapKeys*sizeof(unsigned short)); + for (i=0;i<req->totalVModMapKeys;i++,wire++) { + srv->vmodmap[wire->key]= wire->vmods; + } + if (first>0) { + if (changes->map.changed&XkbVirtualModMapMask) { + int oldLast; + oldLast= changes->map.first_vmodmap_key+ + changes->map.num_vmodmap_keys-1; + if (changes->map.first_vmodmap_key<first) + first= changes->map.first_vmodmap_key; + if (oldLast>last) + last= oldLast; + } + changes->map.first_vmodmap_key= first; + changes->map.num_vmodmap_keys= (last-first)+1; + } + return (char *)wire; +} + +/** + * Check if the given request can be applied to the given device but don't + * actually do anything.. + */ +static int +_XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq *req, char* values) +{ + XkbSrvInfoPtr xkbi; + XkbDescPtr xkb; + int error; + int nTypes = 0, nActions; + CARD8 mapWidths[XkbMaxLegalKeyCode + 1]; + CARD16 symsPerKey[XkbMaxLegalKeyCode + 1]; + + xkbi= dev->key->xkbInfo; + xkb = xkbi->desc; + + if ((xkb->min_key_code != req->minKeyCode)|| + (xkb->max_key_code != req->maxKeyCode)) { + if (client->vMajor!=1) { /* pre 1.0 versions of Xlib have a bug */ + req->minKeyCode= xkb->min_key_code; + req->maxKeyCode= xkb->max_key_code; + } + else { + if (!XkbIsLegalKeycode(req->minKeyCode)) { + client->errorValue = _XkbErrCode3(2, req->minKeyCode, req->maxKeyCode); + return BadValue; + } + if (req->minKeyCode > req->maxKeyCode) { + client->errorValue = _XkbErrCode3(3, req->minKeyCode, req->maxKeyCode); + return BadMatch; + } + } + } + + if ((req->present & XkbKeyTypesMask) && + (!CheckKeyTypes(client,xkb,req,(xkbKeyTypeWireDesc **)&values, + &nTypes,mapWidths))) { + client->errorValue = nTypes; + return BadValue; + } + if ((req->present & XkbKeySymsMask) && + (!CheckKeySyms(client,xkb,req,nTypes,mapWidths,symsPerKey, + (xkbSymMapWireDesc **)&values,&error))) { + client->errorValue = error; + return BadValue; + } + + if ((req->present & XkbKeyActionsMask) && + (!CheckKeyActions(xkb,req,nTypes,mapWidths,symsPerKey, + (CARD8 **)&values,&nActions))) { + client->errorValue = nActions; + return BadValue; + } + + if ((req->present & XkbKeyBehaviorsMask) && + (!CheckKeyBehaviors(xkb,req,(xkbBehaviorWireDesc**)&values,&error))) { + client->errorValue = error; + return BadValue; + } + + if ((req->present & XkbVirtualModsMask) && + (!CheckVirtualMods(xkb,req,(CARD8 **)&values,&error))) { + client->errorValue= error; + return BadValue; + } + if ((req->present&XkbExplicitComponentsMask) && + (!CheckKeyExplicit(xkb,req,(CARD8 **)&values,&error))) { + client->errorValue= error; + return BadValue; + } + if ((req->present&XkbModifierMapMask) && + (!CheckModifierMap(xkb,req,(CARD8 **)&values,&error))) { + client->errorValue= error; + return BadValue; + } + if ((req->present&XkbVirtualModMapMask) && + (!CheckVirtualModMap(xkb,req,(xkbVModMapWireDesc **)&values,&error))) { + client->errorValue= error; + return BadValue; + } + + if (((values-((char *)req))/4)!= req->length) { + ErrorF("[xkb] Internal error! Bad length in XkbSetMap (after check)\n"); + client->errorValue = values-((char *)&req[1]); + return BadLength; + } + + return Success; +} + +/** + * Apply the given request on the given device. + */ +static int +_XkbSetMap(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq *req, char *values) +{ + XkbEventCauseRec cause; + XkbChangesRec change; + Bool sentNKN; + XkbSrvInfoPtr xkbi; + XkbDescPtr xkb; + + xkbi= dev->key->xkbInfo; + xkb = xkbi->desc; + + XkbSetCauseXkbReq(&cause,X_kbSetMap,client); + bzero(&change, sizeof(change)); + sentNKN = FALSE; + if ((xkb->min_key_code!=req->minKeyCode)|| + (xkb->max_key_code!=req->maxKeyCode)) { + Status status; + xkbNewKeyboardNotify nkn; + nkn.deviceID = nkn.oldDeviceID = dev->id; + nkn.oldMinKeyCode = xkb->min_key_code; + nkn.oldMaxKeyCode = xkb->max_key_code; + status= XkbChangeKeycodeRange(xkb, req->minKeyCode, + req->maxKeyCode, &change); + if (status != Success) + return status; /* oh-oh. what about the other keyboards? */ + nkn.minKeyCode = xkb->min_key_code; + nkn.maxKeyCode = xkb->max_key_code; + nkn.requestMajor = XkbReqCode; + nkn.requestMinor = X_kbSetMap; + nkn.changed = XkbNKN_KeycodesMask; + XkbSendNewKeyboardNotify(dev,&nkn); + sentNKN = TRUE; + } + + if (req->present&XkbKeyTypesMask) { + values = SetKeyTypes(xkb,req,(xkbKeyTypeWireDesc *)values,&change); + if (!values) goto allocFailure; + } + if (req->present&XkbKeySymsMask) { + values = SetKeySyms(client,xkb,req,(xkbSymMapWireDesc *)values,&change,dev); + if (!values) goto allocFailure; + } + if (req->present&XkbKeyActionsMask) { + values = SetKeyActions(xkb,req,(CARD8 *)values,&change); + if (!values) goto allocFailure; + } + if (req->present&XkbKeyBehaviorsMask) { + values= SetKeyBehaviors(xkbi,req,(xkbBehaviorWireDesc *)values,&change); + if (!values) goto allocFailure; + } + if (req->present&XkbVirtualModsMask) + values= SetVirtualMods(xkbi,req,(CARD8 *)values,&change); + if (req->present&XkbExplicitComponentsMask) + values= SetKeyExplicit(xkbi,req,(CARD8 *)values,&change); + if (req->present&XkbModifierMapMask) + values= SetModifierMap(xkbi,req,(CARD8 *)values,&change); + if (req->present&XkbVirtualModMapMask) + values= SetVirtualModMap(xkbi,req,(xkbVModMapWireDesc *)values,&change); + if (((values-((char *)req))/4)!=req->length) { + ErrorF("[xkb] Internal error! Bad length in XkbSetMap (after set)\n"); + client->errorValue = values-((char *)&req[1]); + return BadLength; + } + if (req->flags&XkbSetMapRecomputeActions) { + KeyCode first,last,firstMM,lastMM; + if (change.map.num_key_syms>0) { + first= change.map.first_key_sym; + last= first+change.map.num_key_syms-1; + } + else first= last= 0; + if (change.map.num_modmap_keys>0) { + firstMM= change.map.first_modmap_key; + lastMM= first+change.map.num_modmap_keys-1; + } + else firstMM= lastMM= 0; + if ((last>0) && (lastMM>0)) { + if (firstMM<first) + first= firstMM; + if (lastMM>last) + last= lastMM; + } + else if (lastMM>0) { + first= firstMM; + last= lastMM; + } + if (last>0) { + unsigned check= 0; + XkbUpdateActions(dev,first,(last-first+1),&change,&check,&cause); + if (check) + XkbCheckSecondaryEffects(xkbi,check,&change,&cause); + } + } + if (!sentNKN) + XkbSendNotification(dev,&change,&cause); + + return Success; +allocFailure: + return BadAlloc; +} + + +int +ProcXkbSetMap(ClientPtr client) +{ + DeviceIntPtr dev; + char * tmp; + int rc; + + REQUEST(xkbSetMapReq); + REQUEST_AT_LEAST_SIZE(xkbSetMapReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); + CHK_MASK_LEGAL(0x01,stuff->present,XkbAllMapComponentsMask); + + tmp = (char *)&stuff[1]; + + /* Check if we can to the SetMap on the requested device. If this + succeeds, do the same thing for all extension devices (if needed). + If any of them fails, fail. */ + rc = _XkbSetMapChecks(client, dev, stuff, tmp); + + if (rc != Success) + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) + { + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); + if (rc == Success) + { + rc = _XkbSetMapChecks(client, other, stuff, tmp); + if (rc != Success) + return rc; + } + } + } + } + + /* We know now that we will succed with the SetMap. In theory anyway. */ + rc = _XkbSetMap(client, dev, stuff, tmp); + if (rc != Success) + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) + { + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); + if (rc == Success) + _XkbSetMap(client, other, stuff, tmp); + /* ignore rc. if the SetMap failed although the check above + reported true there isn't much we can do. we still need to + set all other devices, hoping that at least they stay in + sync. */ + } + } + } + + return Success; +} + +/***====================================================================***/ + +static Status +XkbComputeGetCompatMapReplySize( XkbCompatMapPtr compat, + xkbGetCompatMapReply * rep) +{ +unsigned size,nGroups; + + nGroups= 0; + if (rep->groups!=0) { + register int i,bit; + for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { + if (rep->groups&bit) + nGroups++; + } + } + size= nGroups*SIZEOF(xkbModsWireDesc); + size+= (rep->nSI*SIZEOF(xkbSymInterpretWireDesc)); + rep->length= size/4; + return Success; +} + +static int +XkbSendCompatMap( ClientPtr client, + XkbCompatMapPtr compat, + xkbGetCompatMapReply * rep) +{ +char * data; +int size; + + size= rep->length*4; + if (size>0) { + data = malloc(size); + if (data) { + register unsigned i,bit; + xkbModsWireDesc * grp; + XkbSymInterpretPtr sym= &compat->sym_interpret[rep->firstSI]; + xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *)data; + for (i=0;i<rep->nSI;i++,sym++,wire++) { + wire->sym= sym->sym; + wire->mods= sym->mods; + wire->match= sym->match; + wire->virtualMod= sym->virtual_mod; + wire->flags= sym->flags; + memcpy((char*)&wire->act,(char*)&sym->act,sz_xkbActionWireDesc); + if (client->swapped) { + register int n; + swapl(&wire->sym,n); + } + } + if (rep->groups) { + grp = (xkbModsWireDesc *)wire; + for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { + if (rep->groups&bit) { + grp->mask= compat->groups[i].mask; + grp->realMods= compat->groups[i].real_mods; + grp->virtualMods= compat->groups[i].vmods; + if (client->swapped) { + register int n; + swaps(&grp->virtualMods,n); + } + grp++; + } + } + wire= (xkbSymInterpretWireDesc*)grp; + } + } + else return BadAlloc; + } + else data= NULL; + + if (client->swapped) { + register int n; + swaps(&rep->sequenceNumber,n); + swapl(&rep->length,n); + swaps(&rep->firstSI,n); + swaps(&rep->nSI,n); + swaps(&rep->nTotalSI,n); + } + + WriteToClient(client, SIZEOF(xkbGetCompatMapReply), (char *)rep); + if (data) { + WriteToClient(client, size, data); + free((char *)data); + } + return Success; +} + +int +ProcXkbGetCompatMap(ClientPtr client) +{ + xkbGetCompatMapReply rep; + DeviceIntPtr dev; + XkbDescPtr xkb; + XkbCompatMapPtr compat; + + REQUEST(xkbGetCompatMapReq); + REQUEST_SIZE_MATCH(xkbGetCompatMapReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); + + xkb = dev->key->xkbInfo->desc; + compat= xkb->compat; + + rep.type = X_Reply; + rep.deviceID = dev->id; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.firstSI = stuff->firstSI; + rep.nSI = stuff->nSI; + if (stuff->getAllSI) { + rep.firstSI = 0; + rep.nSI = compat->num_si; + } + else if ((((unsigned)stuff->nSI)>0)&& + ((unsigned)(stuff->firstSI+stuff->nSI-1)>=compat->num_si)) { + client->errorValue = _XkbErrCode2(0x05,compat->num_si); + return BadValue; + } + rep.nTotalSI = compat->num_si; + rep.groups= stuff->groups; + XkbComputeGetCompatMapReplySize(compat,&rep); + return XkbSendCompatMap(client,compat,&rep); +} + +/** + * Apply the given request on the given device. + * If dryRun is TRUE, then value checks are performed, but the device isn't + * modified. + */ +static int +_XkbSetCompatMap(ClientPtr client, DeviceIntPtr dev, + xkbSetCompatMapReq *req, char* data, BOOL dryRun) +{ + XkbSrvInfoPtr xkbi; + XkbDescPtr xkb; + XkbCompatMapPtr compat; + int nGroups; + unsigned i,bit; + + xkbi = dev->key->xkbInfo; + xkb = xkbi->desc; + compat = xkb->compat; + + if ((req->nSI>0)||(req->truncateSI)) { + xkbSymInterpretWireDesc *wire; + if (req->firstSI>compat->num_si) { + client->errorValue = _XkbErrCode2(0x02,compat->num_si); + return BadValue; + } + wire= (xkbSymInterpretWireDesc *)data; + wire+= req->nSI; + data = (char *)wire; + } + + nGroups= 0; + if (req->groups!=0) { + for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { + if ( req->groups&bit ) + nGroups++; + } + } + data+= nGroups*SIZEOF(xkbModsWireDesc); + if (((data-((char *)req))/4)!=req->length) { + return BadLength; + } + + /* Done all the checks we can do */ + if (dryRun) + return Success; + + data = (char *)&req[1]; + if (req->nSI>0) { + xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *)data; + XkbSymInterpretPtr sym; + if ((unsigned)(req->firstSI+req->nSI)>compat->num_si) { + compat->num_si= req->firstSI+req->nSI; + compat->sym_interpret= realloc(compat->sym_interpret, + compat->num_si * sizeof(XkbSymInterpretRec)); + if (!compat->sym_interpret) { + compat->num_si= 0; + return BadAlloc; + } + } + else if (req->truncateSI) { + compat->num_si = req->firstSI+req->nSI; + } + sym = &compat->sym_interpret[req->firstSI]; + for (i=0;i<req->nSI;i++,wire++,sym++) { + if (client->swapped) { + int n; + swapl(&wire->sym,n); + } + sym->sym= wire->sym; + sym->mods= wire->mods; + sym->match= wire->match; + sym->flags= wire->flags; + sym->virtual_mod= wire->virtualMod; + memcpy((char *)&sym->act,(char *)&wire->act, + SIZEOF(xkbActionWireDesc)); + } + data = (char *)wire; + } + else if (req->truncateSI) { + compat->num_si = req->firstSI; + } + + if (req->groups!=0) { + unsigned i, bit; + xkbModsWireDesc *wire = (xkbModsWireDesc *)data; + for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) { + if (req->groups & bit) { + if (client->swapped) { + int n; + swaps(&wire->virtualMods,n); + } + compat->groups[i].mask= wire->realMods; + compat->groups[i].real_mods= wire->realMods; + compat->groups[i].vmods= wire->virtualMods; + if (wire->virtualMods!=0) { + unsigned tmp; + tmp= XkbMaskForVMask(xkb,wire->virtualMods); + compat->groups[i].mask|= tmp; + } + data+= SIZEOF(xkbModsWireDesc); + wire= (xkbModsWireDesc *)data; + } + } + } + i= XkbPaddedSize((data-((char *)req))); + if ((i/4)!=req->length) { + ErrorF("[xkb] Internal length error on read in _XkbSetCompatMap\n"); + return BadLength; + } + + if (dev->xkb_interest) { + xkbCompatMapNotify ev; + ev.deviceID = dev->id; + ev.changedGroups = req->groups; + ev.firstSI = req->firstSI; + ev.nSI = req->nSI; + ev.nTotalSI = compat->num_si; + XkbSendCompatMapNotify(dev,&ev); + } + + if (req->recomputeActions) { + XkbChangesRec change; + unsigned check; + XkbEventCauseRec cause; + + XkbSetCauseXkbReq(&cause,X_kbSetCompatMap,client); + bzero(&change,sizeof(XkbChangesRec)); + XkbUpdateActions(dev,xkb->min_key_code,XkbNumKeys(xkb),&change,&check, + &cause); + if (check) + XkbCheckSecondaryEffects(xkbi,check,&change,&cause); + XkbSendNotification(dev,&change,&cause); + } + return Success; +} + +int +ProcXkbSetCompatMap(ClientPtr client) +{ + DeviceIntPtr dev; + char *data; + int rc; + + REQUEST(xkbSetCompatMapReq); + REQUEST_AT_LEAST_SIZE(xkbSetCompatMapReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); + + data = (char *)&stuff[1]; + + /* check first using a dry-run */ + rc = _XkbSetCompatMap(client, dev, stuff, data, TRUE); + if (rc != Success) + return rc; + if (stuff->deviceSpec == XkbUseCoreKbd) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) + { + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); + if (rc == Success) + { + /* dry-run */ + rc = _XkbSetCompatMap(client, other, stuff, data, TRUE); + if (rc != Success) + return rc; + } + } + } + } + + /* Yay, the dry-runs succeed. Let's apply */ + rc = _XkbSetCompatMap(client, dev, stuff, data, FALSE); + if (rc != Success) + return rc; + if (stuff->deviceSpec == XkbUseCoreKbd) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) + { + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); + if (rc == Success) + { + rc = _XkbSetCompatMap(client, other, stuff, data, FALSE); + if (rc != Success) + return rc; + } + } + } + } + + return Success; +} + +/***====================================================================***/ + +int +ProcXkbGetIndicatorState(ClientPtr client) +{ + xkbGetIndicatorStateReply rep; + XkbSrvLedInfoPtr sli; + DeviceIntPtr dev; + register int i; + + REQUEST(xkbGetIndicatorStateReq); + REQUEST_SIZE_MATCH(xkbGetIndicatorStateReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixReadAccess); + + sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId, + XkbXI_IndicatorStateMask); + if (!sli) + return BadAlloc; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.deviceID = dev->id; + rep.state = sli->effectiveState; + + if (client->swapped) { + swaps(&rep.sequenceNumber,i); + swapl(&rep.state,i); + } + WriteToClient(client, SIZEOF(xkbGetIndicatorStateReply), (char *)&rep); + return Success; +} + +/***====================================================================***/ + +static Status +XkbComputeGetIndicatorMapReplySize( + XkbIndicatorPtr indicators, + xkbGetIndicatorMapReply *rep) +{ +register int i,bit; +int nIndicators; + + rep->realIndicators = indicators->phys_indicators; + for (i=nIndicators=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { + if (rep->which&bit) + nIndicators++; + } + rep->length = (nIndicators*SIZEOF(xkbIndicatorMapWireDesc))/4; + return Success; +} + +static int +XkbSendIndicatorMap( ClientPtr client, + XkbIndicatorPtr indicators, + xkbGetIndicatorMapReply * rep) +{ +int length; +CARD8 * map; +register int i; +register unsigned bit; + + length = rep->length*4; + if (length>0) { + CARD8 *to; + to= map= malloc(length); + if (map) { + xkbIndicatorMapWireDesc *wire = (xkbIndicatorMapWireDesc *)to; + for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { + if (rep->which&bit) { + wire->flags= indicators->maps[i].flags; + wire->whichGroups= indicators->maps[i].which_groups; + wire->groups= indicators->maps[i].groups; + wire->whichMods= indicators->maps[i].which_mods; + wire->mods= indicators->maps[i].mods.mask; + wire->realMods= indicators->maps[i].mods.real_mods; + wire->virtualMods= indicators->maps[i].mods.vmods; + wire->ctrls= indicators->maps[i].ctrls; + if (client->swapped) { + register int n; + swaps(&wire->virtualMods,n); + swapl(&wire->ctrls,n); + } + wire++; + } + } + to = (CARD8 *)wire; + if ((to-map)!=length) { + client->errorValue = _XkbErrCode2(0xff,length); + return BadLength; + } + } + else return BadAlloc; + } + else map = NULL; + if (client->swapped) { + swaps(&rep->sequenceNumber,i); + swapl(&rep->length,i); + swapl(&rep->which,i); + swapl(&rep->realIndicators,i); + } + WriteToClient(client, SIZEOF(xkbGetIndicatorMapReply), (char *)rep); + if (map) { + WriteToClient(client, length, (char *)map); + free((char *)map); + } + return Success; +} + +int +ProcXkbGetIndicatorMap(ClientPtr client) +{ +xkbGetIndicatorMapReply rep; +DeviceIntPtr dev; +XkbDescPtr xkb; +XkbIndicatorPtr leds; + + REQUEST(xkbGetIndicatorMapReq); + REQUEST_SIZE_MATCH(xkbGetIndicatorMapReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); + + xkb= dev->key->xkbInfo->desc; + leds= xkb->indicators; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.deviceID = dev->id; + rep.which = stuff->which; + XkbComputeGetIndicatorMapReplySize(leds,&rep); + return XkbSendIndicatorMap(client,leds,&rep); +} + +/** + * Apply the given map to the given device. Which specifies which components + * to apply. + */ +static int +_XkbSetIndicatorMap(ClientPtr client, DeviceIntPtr dev, + int which, xkbIndicatorMapWireDesc *desc) +{ + XkbSrvInfoPtr xkbi; + XkbSrvLedInfoPtr sli; + XkbEventCauseRec cause; + int i, bit; + + xkbi = dev->key->xkbInfo; + + sli= XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, + XkbXI_IndicatorMapsMask); + if (!sli) + return BadAlloc; + + for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) { + if (which & bit) { + sli->maps[i].flags = desc->flags; + sli->maps[i].which_groups = desc->whichGroups; + sli->maps[i].groups = desc->groups; + sli->maps[i].which_mods = desc->whichMods; + sli->maps[i].mods.mask = desc->mods; + sli->maps[i].mods.real_mods = desc->mods; + sli->maps[i].mods.vmods= desc->virtualMods; + sli->maps[i].ctrls = desc->ctrls; + if (desc->virtualMods!=0) { + unsigned tmp; + tmp= XkbMaskForVMask(xkbi->desc,desc->virtualMods); + sli->maps[i].mods.mask= desc->mods|tmp; + } + desc++; + } + } + + XkbSetCauseXkbReq(&cause,X_kbSetIndicatorMap,client); + XkbApplyLedMapChanges(dev,sli,which,NULL,NULL,&cause); + + return Success; +} + +int +ProcXkbSetIndicatorMap(ClientPtr client) +{ + int i, bit; + int nIndicators; + DeviceIntPtr dev; + xkbIndicatorMapWireDesc *from; + int rc; + + REQUEST(xkbSetIndicatorMapReq); + REQUEST_AT_LEAST_SIZE(xkbSetIndicatorMapReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess); + + if (stuff->which==0) + return Success; + + for (nIndicators=i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { + if (stuff->which&bit) + nIndicators++; + } + if (stuff->length!=((SIZEOF(xkbSetIndicatorMapReq)+ + (nIndicators*SIZEOF(xkbIndicatorMapWireDesc)))/4)) { + return BadLength; + } + + from = (xkbIndicatorMapWireDesc *)&stuff[1]; + for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { + if (stuff->which&bit) { + if (client->swapped) { + int n; + swaps(&from->virtualMods,n); + swapl(&from->ctrls,n); + } + CHK_MASK_LEGAL(i,from->whichGroups,XkbIM_UseAnyGroup); + CHK_MASK_LEGAL(i,from->whichMods,XkbIM_UseAnyMods); + from++; + } + } + + from = (xkbIndicatorMapWireDesc *)&stuff[1]; + rc = _XkbSetIndicatorMap(client, dev, stuff->which, from); + if (rc != Success) + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) + { + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess); + if (rc == Success) + _XkbSetIndicatorMap(client, other, stuff->which, from); + } + } + } + + return Success; +} + +/***====================================================================***/ + +int +ProcXkbGetNamedIndicator(ClientPtr client) +{ + DeviceIntPtr dev; + xkbGetNamedIndicatorReply rep; + register int i = 0; + XkbSrvLedInfoPtr sli; + XkbIndicatorMapPtr map = NULL; + + REQUEST(xkbGetNamedIndicatorReq); + REQUEST_SIZE_MATCH(xkbGetNamedIndicatorReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_LED_DEVICE(dev, stuff->deviceSpec, client, DixReadAccess); + CHK_ATOM_ONLY(stuff->indicator); + + sli= XkbFindSrvLedInfo(dev,stuff->ledClass,stuff->ledID,0); + if (!sli) + return BadAlloc; + + i= 0; + map= NULL; + if ((sli->names)&&(sli->maps)) { + for (i=0;i<XkbNumIndicators;i++) { + if (stuff->indicator==sli->names[i]) { + map= &sli->maps[i]; + break; + } + } + } + + rep.type= X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.deviceID = dev->id; + rep.indicator= stuff->indicator; + if (map!=NULL) { + rep.found= TRUE; + rep.on= ((sli->effectiveState&(1<<i))!=0); + rep.realIndicator= ((sli->physIndicators&(1<<i))!=0); + rep.ndx= i; + rep.flags= map->flags; + rep.whichGroups= map->which_groups; + rep.groups= map->groups; + rep.whichMods= map->which_mods; + rep.mods= map->mods.mask; + rep.realMods= map->mods.real_mods; + rep.virtualMods= map->mods.vmods; + rep.ctrls= map->ctrls; + rep.supported= TRUE; + } + else { + rep.found= FALSE; + rep.on= FALSE; + rep.realIndicator= FALSE; + rep.ndx= XkbNoIndicator; + rep.flags= 0; + rep.whichGroups= 0; + rep.groups= 0; + rep.whichMods= 0; + rep.mods= 0; + rep.realMods= 0; + rep.virtualMods= 0; + rep.ctrls= 0; + rep.supported= TRUE; + } + if ( client->swapped ) { + register int n; + swapl(&rep.length,n); + swaps(&rep.sequenceNumber,n); + swapl(&rep.indicator,n); + swaps(&rep.virtualMods,n); + swapl(&rep.ctrls,n); + } + + WriteToClient(client,SIZEOF(xkbGetNamedIndicatorReply), (char *)&rep); + return Success; +} + + +/** + * Find the IM on the device. + * Returns the map, or NULL if the map doesn't exist. + * If the return value is NULL, led_return is undefined. Otherwise, led_return + * is set to the led index of the map. + */ +static XkbIndicatorMapPtr +_XkbFindNamedIndicatorMap(XkbSrvLedInfoPtr sli, Atom indicator, + int *led_return) +{ + XkbIndicatorMapPtr map; + + /* search for the right indicator */ + map = NULL; + if (sli->names && sli->maps) { + int led; + + for (led = 0; (led < XkbNumIndicators) && (map == NULL); led++) { + if (sli->names[led] == indicator) { + map= &sli->maps[led]; + *led_return = led; + break; + } + } + } + + return map; +} + +/** + * Creates an indicator map on the device. If dryRun is TRUE, it only checks + * if creation is possible, but doesn't actually create it. + */ +static int +_XkbCreateIndicatorMap(DeviceIntPtr dev, Atom indicator, + int ledClass, int ledID, + XkbIndicatorMapPtr *map_return, int *led_return, + Bool dryRun) +{ + XkbSrvLedInfoPtr sli; + XkbIndicatorMapPtr map; + int led; + + sli = XkbFindSrvLedInfo(dev, ledClass, ledID, XkbXI_IndicatorsMask); + if (!sli) + return BadAlloc; + + map = _XkbFindNamedIndicatorMap(sli, indicator, &led); + + if (!map) + { + /* find first unused indicator maps and assign the name to it */ + for (led = 0, map = NULL; (led < XkbNumIndicators) && (map == NULL); led++) { + if ((sli->names) && (sli->maps) && (sli->names[led] == None) && + (!XkbIM_InUse(&sli->maps[led]))) + { + map = &sli->maps[led]; + if (!dryRun) + sli->names[led] = indicator; + break; + } + } + } + + if (!map) + return BadAlloc; + + *led_return = led; + *map_return = map; + return Success; +} + +static int +_XkbSetNamedIndicator(ClientPtr client, DeviceIntPtr dev, + xkbSetNamedIndicatorReq *stuff) +{ + unsigned int extDevReason; + unsigned int statec, namec, mapc; + XkbSrvLedInfoPtr sli; + int led = 0; + XkbIndicatorMapPtr map; + DeviceIntPtr kbd; + XkbEventCauseRec cause; + xkbExtensionDeviceNotify ed; + XkbChangesRec changes; + int rc; + + rc = _XkbCreateIndicatorMap(dev, stuff->indicator, stuff->ledClass, + stuff->ledID, &map, &led, FALSE); + if (rc != Success || !map) /* oh-oh */ + return rc; + + sli = XkbFindSrvLedInfo(dev, stuff->ledClass, stuff->ledID, + XkbXI_IndicatorsMask); + if (!sli) + return BadAlloc; + + namec = mapc = statec = 0; + extDevReason = 0; + + namec |= (1<<led); + sli->namesPresent |= ((stuff->indicator != None) ? (1 << led) : 0); + extDevReason |= XkbXI_IndicatorNamesMask; + + if (stuff->setMap) { + map->flags = stuff->flags; + map->which_groups = stuff->whichGroups; + map->groups = stuff->groups; + map->which_mods = stuff->whichMods; + map->mods.mask = stuff->realMods; + map->mods.real_mods = stuff->realMods; + map->mods.vmods= stuff->virtualMods; + map->ctrls = stuff->ctrls; + mapc|= (1<<led); + } + + if ((stuff->setState) && ((map->flags & XkbIM_NoExplicit) == 0)) + { + if (stuff->on) sli->explicitState |= (1<<led); + else sli->explicitState &= ~(1<<led); + statec |= ((sli->effectiveState ^ sli->explicitState) & (1 << led)); + } + + bzero((char *)&ed,sizeof(xkbExtensionDeviceNotify)); + bzero((char *)&changes,sizeof(XkbChangesRec)); + XkbSetCauseXkbReq(&cause,X_kbSetNamedIndicator,client); + if (namec) + XkbApplyLedNameChanges(dev,sli,namec,&ed,&changes,&cause); + if (mapc) + XkbApplyLedMapChanges(dev,sli,mapc,&ed,&changes,&cause); + if (statec) + XkbApplyLedStateChanges(dev,sli,statec,&ed,&changes,&cause); + + kbd = dev; + if ((sli->flags&XkbSLI_HasOwnState)==0) + kbd = inputInfo.keyboard; + XkbFlushLedEvents(dev, kbd, sli, &ed, &changes, &cause); + + return Success; +} + +int +ProcXkbSetNamedIndicator(ClientPtr client) +{ + int rc; + DeviceIntPtr dev; + int led = 0; + XkbIndicatorMapPtr map; + + REQUEST(xkbSetNamedIndicatorReq); + REQUEST_SIZE_MATCH(xkbSetNamedIndicatorReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_LED_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess); + CHK_ATOM_ONLY(stuff->indicator); + CHK_MASK_LEGAL(0x10,stuff->whichGroups,XkbIM_UseAnyGroup); + CHK_MASK_LEGAL(0x11,stuff->whichMods,XkbIM_UseAnyMods); + + /* Dry-run for checks */ + rc = _XkbCreateIndicatorMap(dev, stuff->indicator, + stuff->ledClass, stuff->ledID, + &map, &led, TRUE); + if (rc != Success || !map) /* couldn't be created or didn't exist */ + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd || + stuff->deviceSpec == XkbUseCorePtr) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && !IsMaster(other) && (other->u.master == dev) && + (other->kbdfeed || other->leds) && + (XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess) == Success)) + { + rc = _XkbCreateIndicatorMap(other, stuff->indicator, + stuff->ledClass, stuff->ledID, + &map, &led, TRUE); + if (rc != Success || !map) + return rc; + } + } + } + + /* All checks passed, let's do it */ + rc = _XkbSetNamedIndicator(client, dev, stuff); + if (rc != Success) + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd || + stuff->deviceSpec == XkbUseCorePtr) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && !IsMaster(other) && (other->u.master == dev) && + (other->kbdfeed || other->leds) && + (XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess) == Success)) + { + _XkbSetNamedIndicator(client, other, stuff); + } + } + } + + return Success; +} + +/***====================================================================***/ + +static CARD32 +_XkbCountAtoms(Atom *atoms,int maxAtoms,int *count) +{ +register unsigned int i,bit,nAtoms; +register CARD32 atomsPresent; + + for (i=nAtoms=atomsPresent=0,bit=1;i<maxAtoms;i++,bit<<=1) { + if (atoms[i]!=None) { + atomsPresent|= bit; + nAtoms++; + } + } + if (count) + *count= nAtoms; + return atomsPresent; +} + +static char * +_XkbWriteAtoms(char *wire,Atom *atoms,int maxAtoms,int swap) +{ +register unsigned int i; +Atom *atm; + + atm = (Atom *)wire; + for (i=0;i<maxAtoms;i++) { + if (atoms[i]!=None) { + *atm= atoms[i]; + if (swap) { + register int n; + swapl(atm,n); + } + atm++; + } + } + return (char *)atm; +} + +static Status +XkbComputeGetNamesReplySize(XkbDescPtr xkb,xkbGetNamesReply *rep) +{ +register unsigned which,length; +register int i; + + rep->minKeyCode= xkb->min_key_code; + rep->maxKeyCode= xkb->max_key_code; + which= rep->which; + length= 0; + if (xkb->names!=NULL) { + if (which&XkbKeycodesNameMask) length++; + if (which&XkbGeometryNameMask) length++; + if (which&XkbSymbolsNameMask) length++; + if (which&XkbPhysSymbolsNameMask) length++; + if (which&XkbTypesNameMask) length++; + if (which&XkbCompatNameMask) length++; + } + else which&= ~XkbComponentNamesMask; + + if (xkb->map!=NULL) { + if (which&XkbKeyTypeNamesMask) + length+= xkb->map->num_types; + rep->nTypes= xkb->map->num_types; + if (which&XkbKTLevelNamesMask) { + XkbKeyTypePtr pType = xkb->map->types; + int nKTLevels = 0; + + length+= XkbPaddedSize(xkb->map->num_types)/4; + for (i=0;i<xkb->map->num_types;i++,pType++) { + if (pType->level_names!=NULL) + nKTLevels+= pType->num_levels; + } + rep->nKTLevels= nKTLevels; + length+= nKTLevels; + } + } + else { + rep->nTypes= 0; + rep->nKTLevels= 0; + which&= ~(XkbKeyTypeNamesMask|XkbKTLevelNamesMask); + } + + rep->minKeyCode= xkb->min_key_code; + rep->maxKeyCode= xkb->max_key_code; + rep->indicators= 0; + rep->virtualMods= 0; + rep->groupNames= 0; + if (xkb->names!=NULL) { + if (which&XkbIndicatorNamesMask) { + int nLeds; + rep->indicators= + _XkbCountAtoms(xkb->names->indicators,XkbNumIndicators,&nLeds); + length+= nLeds; + if (nLeds==0) + which&= ~XkbIndicatorNamesMask; + } + + if (which&XkbVirtualModNamesMask) { + int nVMods; + rep->virtualMods= + _XkbCountAtoms(xkb->names->vmods,XkbNumVirtualMods,&nVMods); + length+= nVMods; + if (nVMods==0) + which&= ~XkbVirtualModNamesMask; + } + + if (which&XkbGroupNamesMask) { + int nGroups; + rep->groupNames= + _XkbCountAtoms(xkb->names->groups,XkbNumKbdGroups,&nGroups); + length+= nGroups; + if (nGroups==0) + which&= ~XkbGroupNamesMask; + } + + if ((which&XkbKeyNamesMask)&&(xkb->names->keys)) + length+= rep->nKeys; + else which&= ~XkbKeyNamesMask; + + if ((which&XkbKeyAliasesMask)&& + (xkb->names->key_aliases)&&(xkb->names->num_key_aliases>0)) { + rep->nKeyAliases= xkb->names->num_key_aliases; + length+= rep->nKeyAliases*2; + } + else { + which&= ~XkbKeyAliasesMask; + rep->nKeyAliases= 0; + } + + if ((which&XkbRGNamesMask)&&(xkb->names->num_rg>0)) + length+= xkb->names->num_rg; + else which&= ~XkbRGNamesMask; + } + else { + which&= ~(XkbIndicatorNamesMask|XkbVirtualModNamesMask); + which&= ~(XkbGroupNamesMask|XkbKeyNamesMask|XkbKeyAliasesMask); + which&= ~XkbRGNamesMask; + } + + rep->length= length; + rep->which= which; + return Success; +} + +static int +XkbSendNames(ClientPtr client,XkbDescPtr xkb,xkbGetNamesReply *rep) +{ +register unsigned i,length,which; +char * start; +char * desc; +register int n; + + length= rep->length*4; + which= rep->which; + if (client->swapped) { + swaps(&rep->sequenceNumber,n); + swapl(&rep->length,n); + swapl(&rep->which,n); + swaps(&rep->virtualMods,n); + swapl(&rep->indicators,n); + } + + start = desc = malloc(length); + if ( !start ) + return BadAlloc; + if (xkb->names) { + if (which&XkbKeycodesNameMask) { + *((CARD32 *)desc)= xkb->names->keycodes; + if (client->swapped) { + swapl(desc,n); + } + desc+= 4; + } + if (which&XkbGeometryNameMask) { + *((CARD32 *)desc)= xkb->names->geometry; + if (client->swapped) { + swapl(desc,n); + } + desc+= 4; + } + if (which&XkbSymbolsNameMask) { + *((CARD32 *)desc)= xkb->names->symbols; + if (client->swapped) { + swapl(desc,n); + } + desc+= 4; + } + if (which&XkbPhysSymbolsNameMask) { + register CARD32 *atm= (CARD32 *)desc; + atm[0]= (CARD32)xkb->names->phys_symbols; + if (client->swapped) { + swapl(&atm[0],n); + } + desc+= 4; + } + if (which&XkbTypesNameMask) { + *((CARD32 *)desc)= (CARD32)xkb->names->types; + if (client->swapped) { + swapl(desc,n); + } + desc+= 4; + } + if (which&XkbCompatNameMask) { + *((CARD32 *)desc)= (CARD32)xkb->names->compat; + if (client->swapped) { + swapl(desc,n); + } + desc+= 4; + } + if (which&XkbKeyTypeNamesMask) { + register CARD32 *atm= (CARD32 *)desc; + register XkbKeyTypePtr type= xkb->map->types; + + for (i=0;i<xkb->map->num_types;i++,atm++,type++) { + *atm= (CARD32)type->name; + if (client->swapped) { + swapl(atm,n); + } + } + desc= (char *)atm; + } + if (which&XkbKTLevelNamesMask && xkb->map) { + XkbKeyTypePtr type = xkb->map->types; + register CARD32 *atm; + for (i=0;i<rep->nTypes;i++,type++) { + *desc++ = type->num_levels; + } + desc+= XkbPaddedSize(rep->nTypes)-rep->nTypes; + + atm= (CARD32 *)desc; + type = xkb->map->types; + for (i=0;i<xkb->map->num_types;i++,type++) { + register unsigned l; + if (type->level_names) { + for (l=0;l<type->num_levels;l++,atm++) { + *atm= type->level_names[l]; + if (client->swapped) { + swapl(atm,n); + } + } + desc+= type->num_levels*4; + } + } + } + if (which&XkbIndicatorNamesMask) { + desc= _XkbWriteAtoms(desc,xkb->names->indicators,XkbNumIndicators, + client->swapped); + } + if (which&XkbVirtualModNamesMask) { + desc= _XkbWriteAtoms(desc,xkb->names->vmods,XkbNumVirtualMods, + client->swapped); + } + if (which&XkbGroupNamesMask) { + desc= _XkbWriteAtoms(desc,xkb->names->groups,XkbNumKbdGroups, + client->swapped); + } + if (which&XkbKeyNamesMask) { + for (i=0;i<rep->nKeys;i++,desc+= sizeof(XkbKeyNameRec)) { + *((XkbKeyNamePtr)desc)= xkb->names->keys[i+rep->firstKey]; + } + } + if (which&XkbKeyAliasesMask) { + XkbKeyAliasPtr pAl; + pAl= xkb->names->key_aliases; + for (i=0;i<rep->nKeyAliases;i++,pAl++,desc+=2*XkbKeyNameLength) { + *((XkbKeyAliasPtr)desc)= *pAl; + } + } + if ((which&XkbRGNamesMask)&&(rep->nRadioGroups>0)) { + register CARD32 *atm= (CARD32 *)desc; + for (i=0;i<rep->nRadioGroups;i++,atm++) { + *atm= (CARD32)xkb->names->radio_groups[i]; + if (client->swapped) { + swapl(atm,n); + } + } + desc+= rep->nRadioGroups*4; + } + } + + if ((desc-start)!=(length)) { + ErrorF("[xkb] BOGUS LENGTH in write names, expected %d, got %ld\n", + length, (unsigned long)(desc-start)); + } + WriteToClient(client, SIZEOF(xkbGetNamesReply), (char *)rep); + WriteToClient(client, length, start); + free((char *)start); + return Success; +} + +int +ProcXkbGetNames(ClientPtr client) +{ + DeviceIntPtr dev; + XkbDescPtr xkb; + xkbGetNamesReply rep; + + REQUEST(xkbGetNamesReq); + REQUEST_SIZE_MATCH(xkbGetNamesReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); + CHK_MASK_LEGAL(0x01,stuff->which,XkbAllNamesMask); + + xkb = dev->key->xkbInfo->desc; + memset(&rep, 0, sizeof(xkbGetNamesReply)); + rep.type= X_Reply; + rep.sequenceNumber= client->sequence; + rep.length = 0; + rep.deviceID = dev->id; + rep.which = stuff->which; + rep.nTypes = xkb->map->num_types; + rep.firstKey = xkb->min_key_code; + rep.nKeys = XkbNumKeys(xkb); + if (xkb->names!=NULL) { + rep.nKeyAliases= xkb->names->num_key_aliases; + rep.nRadioGroups = xkb->names->num_rg; + } + else { + rep.nKeyAliases= rep.nRadioGroups= 0; + } + XkbComputeGetNamesReplySize(xkb,&rep); + return XkbSendNames(client,xkb,&rep); +} + +/***====================================================================***/ + +static CARD32 * +_XkbCheckAtoms(CARD32 *wire,int nAtoms,int swapped,Atom *pError) +{ +register int i; + + for (i=0;i<nAtoms;i++,wire++) { + if (swapped) { + register int n; + swapl(wire,n); + } + if ((((Atom)*wire)!=None)&&(!ValidAtom((Atom)*wire))) { + *pError= ((Atom)*wire); + return NULL; + } + } + return wire; +} + +static CARD32 * +_XkbCheckMaskedAtoms(CARD32 *wire,int nAtoms,CARD32 present,int swapped, + Atom *pError) +{ +register unsigned i,bit; + + for (i=0,bit=1;(i<nAtoms)&&(present);i++,bit<<=1) { + if ((present&bit)==0) + continue; + if (swapped) { + register int n; + swapl(wire,n); + } + if ((((Atom)*wire)!=None)&&(!ValidAtom(((Atom)*wire)))) { + *pError= (Atom)*wire; + return NULL; + } + wire++; + } + return wire; +} + +static Atom * +_XkbCopyMaskedAtoms( Atom *wire, + Atom *dest, + int nAtoms, + CARD32 present) +{ +register int i,bit; + + for (i=0,bit=1;(i<nAtoms)&&(present);i++,bit<<=1) { + if ((present&bit)==0) + continue; + dest[i]= *wire++; + } + return wire; +} + +static Bool +_XkbCheckTypeName(Atom name,int typeNdx) +{ +const char * str; + + str= NameForAtom(name); + if ((strcmp(str,"ONE_LEVEL")==0)||(strcmp(str,"TWO_LEVEL")==0)|| + (strcmp(str,"ALPHABETIC")==0)||(strcmp(str,"KEYPAD")==0)) + return FALSE; + return TRUE; +} + +/** + * Check the device-dependent data in the request against the device. Returns + * Success, or the appropriate error code. + */ +static int +_XkbSetNamesCheck(ClientPtr client, DeviceIntPtr dev, + xkbSetNamesReq *stuff, CARD32 *data) +{ + XkbDescRec *xkb; + XkbNamesRec *names; + CARD32 *tmp; + Atom bad; + + tmp = data; + xkb = dev->key->xkbInfo->desc; + names = xkb->names; + + + if (stuff->which & XkbKeyTypeNamesMask) { + int i; + CARD32 *old; + if ( stuff->nTypes<1 ) { + client->errorValue = _XkbErrCode2(0x02,stuff->nTypes); + return BadValue; + } + if ((unsigned)(stuff->firstType+stuff->nTypes-1)>=xkb->map->num_types) { + client->errorValue = _XkbErrCode4(0x03,stuff->firstType, + stuff->nTypes, + xkb->map->num_types); + return BadValue; + } + if (((unsigned)stuff->firstType)<=XkbLastRequiredType) { + client->errorValue = _XkbErrCode2(0x04,stuff->firstType); + return BadAccess; + } + old= tmp; + tmp= _XkbCheckAtoms(tmp,stuff->nTypes,client->swapped,&bad); + if (!tmp) { + client->errorValue= bad; + return BadAtom; + } + for (i=0;i<stuff->nTypes;i++,old++) { + if (!_XkbCheckTypeName((Atom)*old,stuff->firstType+i)) + client->errorValue= _XkbErrCode2(0x05,i); + } + } + if (stuff->which&XkbKTLevelNamesMask) { + unsigned i; + XkbKeyTypePtr type; + CARD8 * width; + if ( stuff->nKTLevels<1 ) { + client->errorValue = _XkbErrCode2(0x05,stuff->nKTLevels); + return BadValue; + } + if ((unsigned)(stuff->firstKTLevel+stuff->nKTLevels-1)>= + xkb->map->num_types) { + client->errorValue = _XkbErrCode4(0x06,stuff->firstKTLevel, + stuff->nKTLevels,xkb->map->num_types); + return BadValue; + } + width = (CARD8 *)tmp; + tmp= (CARD32 *)(((char *)tmp)+XkbPaddedSize(stuff->nKTLevels)); + type = &xkb->map->types[stuff->firstKTLevel]; + for (i=0;i<stuff->nKTLevels;i++,type++) { + if (width[i]==0) + continue; + else if (width[i]!=type->num_levels) { + client->errorValue= _XkbErrCode4(0x07,i+stuff->firstKTLevel, + type->num_levels,width[i]); + return BadMatch; + } + tmp= _XkbCheckAtoms(tmp,width[i],client->swapped,&bad); + if (!tmp) { + client->errorValue= bad; + return BadAtom; + } + } + } + if (stuff->which&XkbIndicatorNamesMask) { + if (stuff->indicators==0) { + client->errorValue= 0x08; + return BadMatch; + } + tmp= _XkbCheckMaskedAtoms(tmp,XkbNumIndicators,stuff->indicators, + client->swapped,&bad); + if (!tmp) { + client->errorValue= bad; + return BadAtom; + } + } + if (stuff->which&XkbVirtualModNamesMask) { + if (stuff->virtualMods==0) { + client->errorValue= 0x09; + return BadMatch; + } + tmp= _XkbCheckMaskedAtoms(tmp,XkbNumVirtualMods, + (CARD32)stuff->virtualMods, + client->swapped,&bad); + if (!tmp) { + client->errorValue = bad; + return BadAtom; + } + } + if (stuff->which&XkbGroupNamesMask) { + if (stuff->groupNames==0) { + client->errorValue= 0x0a; + return BadMatch; + } + tmp= _XkbCheckMaskedAtoms(tmp,XkbNumKbdGroups, + (CARD32)stuff->groupNames, + client->swapped,&bad); + if (!tmp) { + client->errorValue = bad; + return BadAtom; + } + } + if (stuff->which&XkbKeyNamesMask) { + if (stuff->firstKey<(unsigned)xkb->min_key_code) { + client->errorValue= _XkbErrCode3(0x0b,xkb->min_key_code, + stuff->firstKey); + return BadValue; + } + if (((unsigned)(stuff->firstKey+stuff->nKeys-1)>xkb->max_key_code)|| + (stuff->nKeys<1)) { + client->errorValue= _XkbErrCode4(0x0c,xkb->max_key_code, + stuff->firstKey,stuff->nKeys); + return BadValue; + } + tmp+= stuff->nKeys; + } + if ((stuff->which&XkbKeyAliasesMask)&&(stuff->nKeyAliases>0)) { + tmp+= stuff->nKeyAliases*2; + } + if (stuff->which&XkbRGNamesMask) { + if ( stuff->nRadioGroups<1 ) { + client->errorValue= _XkbErrCode2(0x0d,stuff->nRadioGroups); + return BadValue; + } + tmp= _XkbCheckAtoms(tmp,stuff->nRadioGroups,client->swapped,&bad); + if (!tmp) { + client->errorValue= bad; + return BadAtom; + } + } + if ((tmp-((CARD32 *)stuff))!=stuff->length) { + client->errorValue = stuff->length; + return BadLength; + } + + + + return Success; +} + +static int +_XkbSetNames(ClientPtr client, DeviceIntPtr dev, xkbSetNamesReq *stuff) +{ + XkbDescRec *xkb; + XkbNamesRec *names; + CARD32 *tmp; + xkbNamesNotify nn; + + tmp = (CARD32 *)&stuff[1]; + xkb = dev->key->xkbInfo->desc; + names = xkb->names; + + if (XkbAllocNames(xkb,stuff->which,stuff->nRadioGroups, + stuff->nKeyAliases)!=Success) { + return BadAlloc; + } + + bzero(&nn,sizeof(xkbNamesNotify)); + nn.changed= stuff->which; + tmp = (CARD32 *)&stuff[1]; + if (stuff->which&XkbKeycodesNameMask) + names->keycodes= *tmp++; + if (stuff->which&XkbGeometryNameMask) + names->geometry= *tmp++; + if (stuff->which&XkbSymbolsNameMask) + names->symbols= *tmp++; + if (stuff->which&XkbPhysSymbolsNameMask) + names->phys_symbols= *tmp++; + if (stuff->which&XkbTypesNameMask) + names->types= *tmp++; + if (stuff->which&XkbCompatNameMask) + names->compat= *tmp++; + if ((stuff->which&XkbKeyTypeNamesMask)&&(stuff->nTypes>0)) { + register unsigned i; + register XkbKeyTypePtr type; + + type= &xkb->map->types[stuff->firstType]; + for (i=0;i<stuff->nTypes;i++,type++) { + type->name= *tmp++; + } + nn.firstType= stuff->firstType; + nn.nTypes= stuff->nTypes; + } + if (stuff->which&XkbKTLevelNamesMask) { + register XkbKeyTypePtr type; + register unsigned i; + CARD8 *width; + + width = (CARD8 *)tmp; + tmp= (CARD32 *)(((char *)tmp)+XkbPaddedSize(stuff->nKTLevels)); + type= &xkb->map->types[stuff->firstKTLevel]; + for (i=0;i<stuff->nKTLevels;i++,type++) { + if (width[i]>0) { + if (type->level_names) { + register unsigned n; + for (n=0;n<width[i];n++) { + type->level_names[n]= tmp[n]; + } + } + tmp+= width[i]; + } + } + nn.firstLevelName= 0; + nn.nLevelNames= stuff->nTypes; + } + if (stuff->which&XkbIndicatorNamesMask) { + tmp= _XkbCopyMaskedAtoms(tmp,names->indicators,XkbNumIndicators, + stuff->indicators); + nn.changedIndicators= stuff->indicators; + } + if (stuff->which&XkbVirtualModNamesMask) { + tmp= _XkbCopyMaskedAtoms(tmp,names->vmods,XkbNumVirtualMods, + stuff->virtualMods); + nn.changedVirtualMods= stuff->virtualMods; + } + if (stuff->which&XkbGroupNamesMask) { + tmp= _XkbCopyMaskedAtoms(tmp,names->groups,XkbNumKbdGroups, + stuff->groupNames); + nn.changedVirtualMods= stuff->groupNames; + } + if (stuff->which&XkbKeyNamesMask) { + memcpy((char*)&names->keys[stuff->firstKey],(char *)tmp, + stuff->nKeys*XkbKeyNameLength); + tmp+= stuff->nKeys; + nn.firstKey= stuff->firstKey; + nn.nKeys= stuff->nKeys; + } + if (stuff->which&XkbKeyAliasesMask) { + if (stuff->nKeyAliases>0) { + register int na= stuff->nKeyAliases; + if (XkbAllocNames(xkb,XkbKeyAliasesMask,0,na)!=Success) + return BadAlloc; + memcpy((char *)names->key_aliases,(char *)tmp, + stuff->nKeyAliases*sizeof(XkbKeyAliasRec)); + tmp+= stuff->nKeyAliases*2; + } + else if (names->key_aliases!=NULL) { + free(names->key_aliases); + names->key_aliases= NULL; + names->num_key_aliases= 0; + } + nn.nAliases= names->num_key_aliases; + } + if (stuff->which&XkbRGNamesMask) { + if (stuff->nRadioGroups>0) { + register unsigned i,nrg; + nrg= stuff->nRadioGroups; + if (XkbAllocNames(xkb,XkbRGNamesMask,nrg,0)!=Success) + return BadAlloc; + + for (i=0;i<stuff->nRadioGroups;i++) { + names->radio_groups[i]= tmp[i]; + } + tmp+= stuff->nRadioGroups; + } + else if (names->radio_groups) { + free(names->radio_groups); + names->radio_groups= NULL; + names->num_rg= 0; + } + nn.nRadioGroups= names->num_rg; + } + if (nn.changed) { + Bool needExtEvent; + needExtEvent= (nn.changed&XkbIndicatorNamesMask)!=0; + XkbSendNamesNotify(dev,&nn); + if (needExtEvent) { + XkbSrvLedInfoPtr sli; + xkbExtensionDeviceNotify edev; + register int i; + register unsigned bit; + + sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId, + XkbXI_IndicatorsMask); + sli->namesPresent= 0; + for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { + if (names->indicators[i]!=None) + sli->namesPresent|= bit; + } + bzero(&edev,sizeof(xkbExtensionDeviceNotify)); + edev.reason= XkbXI_IndicatorNamesMask; + edev.ledClass= KbdFeedbackClass; + edev.ledID= dev->kbdfeed->ctrl.id; + edev.ledsDefined= sli->namesPresent|sli->mapsPresent; + edev.ledState= sli->effectiveState; + edev.firstBtn= 0; + edev.nBtns= 0; + edev.supported= XkbXI_AllFeaturesMask; + edev.unsupported= 0; + XkbSendExtensionDeviceNotify(dev,client,&edev); + } + } + return Success; +} + +int +ProcXkbSetNames(ClientPtr client) +{ + DeviceIntPtr dev; + CARD32 *tmp; + Atom bad; + int rc; + + REQUEST(xkbSetNamesReq); + REQUEST_AT_LEAST_SIZE(xkbSetNamesReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); + CHK_MASK_LEGAL(0x01,stuff->which,XkbAllNamesMask); + + /* check device-independent stuff */ + tmp = (CARD32 *)&stuff[1]; + + if (stuff->which&XkbKeycodesNameMask) { + tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); + if (!tmp) { + client->errorValue = bad; + return BadAtom; + } + } + if (stuff->which&XkbGeometryNameMask) { + tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); + if (!tmp) { + client->errorValue = bad; + return BadAtom; + } + } + if (stuff->which&XkbSymbolsNameMask) { + tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); + if (!tmp) { + client->errorValue = bad; + return BadAtom; + } + } + if (stuff->which&XkbPhysSymbolsNameMask) { + tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); + if (!tmp) { + client->errorValue= bad; + return BadAtom; + } + } + if (stuff->which&XkbTypesNameMask) { + tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); + if (!tmp) { + client->errorValue = bad; + return BadAtom; + } + } + if (stuff->which&XkbCompatNameMask) { + tmp= _XkbCheckAtoms(tmp,1,client->swapped,&bad); + if (!tmp) { + client->errorValue = bad; + return BadAtom; + } + } + + /* start of device-dependent tests */ + rc = _XkbSetNamesCheck(client, dev, stuff, tmp); + if (rc != Success) + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) + { + + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); + if (rc == Success) + { + rc = _XkbSetNamesCheck(client, other, stuff, tmp); + if (rc != Success) + return rc; + } + } + } + } + + /* everything is okay -- update names */ + + rc = _XkbSetNames(client, dev, stuff); + if (rc != Success) + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) + { + + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); + if (rc == Success) + _XkbSetNames(client, other, stuff); + } + } + } + + /* everything is okay -- update names */ + + return Success; +} + +/***====================================================================***/ + +#include "xkbgeom.h" + +#define XkbSizeCountedString(s) ((s)?((((2+strlen(s))+3)/4)*4):4) + +static char * +XkbWriteCountedString(char *wire,char *str,Bool swap) +{ + CARD16 len,*pLen; + + if (!str) + return wire; + + len= strlen(str); + pLen= (CARD16 *)wire; + *pLen= len; + if (swap) { + register int n; + swaps(pLen,n); + } + memcpy(&wire[2],str,len); + wire+= ((2+len+3)/4)*4; + return wire; +} + +static int +XkbSizeGeomProperties(XkbGeometryPtr geom) +{ +register int i,size; +XkbPropertyPtr prop; + + for (size=i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) { + size+= XkbSizeCountedString(prop->name); + size+= XkbSizeCountedString(prop->value); + } + return size; +} + +static char * +XkbWriteGeomProperties(char *wire,XkbGeometryPtr geom,Bool swap) +{ +register int i; +register XkbPropertyPtr prop; + + for (i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) { + wire= XkbWriteCountedString(wire,prop->name,swap); + wire= XkbWriteCountedString(wire,prop->value,swap); + } + return wire; +} + +static int +XkbSizeGeomKeyAliases(XkbGeometryPtr geom) +{ + return geom->num_key_aliases*(2*XkbKeyNameLength); +} + +static char * +XkbWriteGeomKeyAliases(char *wire,XkbGeometryPtr geom,Bool swap) +{ +register int sz; + + sz= geom->num_key_aliases*(XkbKeyNameLength*2); + if (sz>0) { + memcpy(wire,(char *)geom->key_aliases,sz); + wire+= sz; + } + return wire; +} + +static int +XkbSizeGeomColors(XkbGeometryPtr geom) +{ +register int i,size; +register XkbColorPtr color; + + for (i=size=0,color=geom->colors;i<geom->num_colors;i++,color++) { + size+= XkbSizeCountedString(color->spec); + } + return size; +} + +static char * +XkbWriteGeomColors(char *wire,XkbGeometryPtr geom,Bool swap) +{ +register int i; +register XkbColorPtr color; + + for (i=0,color=geom->colors;i<geom->num_colors;i++,color++) { + wire= XkbWriteCountedString(wire,color->spec,swap); + } + return wire; +} + +static int +XkbSizeGeomShapes(XkbGeometryPtr geom) +{ +register int i,size; +register XkbShapePtr shape; + + for (i=size=0,shape=geom->shapes;i<geom->num_shapes;i++,shape++) { + register int n; + register XkbOutlinePtr ol; + size+= SIZEOF(xkbShapeWireDesc); + for (n=0,ol=shape->outlines;n<shape->num_outlines;n++,ol++) { + size+= SIZEOF(xkbOutlineWireDesc); + size+= ol->num_points*SIZEOF(xkbPointWireDesc); + } + } + return size; +} + +static char * +XkbWriteGeomShapes(char *wire,XkbGeometryPtr geom,Bool swap) +{ +int i; +XkbShapePtr shape; +xkbShapeWireDesc * shapeWire; + + for (i=0,shape=geom->shapes;i<geom->num_shapes;i++,shape++) { + register int o; + XkbOutlinePtr ol; + xkbOutlineWireDesc * olWire; + shapeWire= (xkbShapeWireDesc *)wire; + shapeWire->name= shape->name; + shapeWire->nOutlines= shape->num_outlines; + if (shape->primary!=NULL) + shapeWire->primaryNdx= XkbOutlineIndex(shape,shape->primary); + else shapeWire->primaryNdx= XkbNoShape; + if (shape->approx!=NULL) + shapeWire->approxNdx= XkbOutlineIndex(shape,shape->approx); + else shapeWire->approxNdx= XkbNoShape; + if (swap) { + register int n; + swapl(&shapeWire->name,n); + } + wire= (char *)&shapeWire[1]; + for (o=0,ol=shape->outlines;o<shape->num_outlines;o++,ol++) { + register int p; + XkbPointPtr pt; + xkbPointWireDesc * ptWire; + olWire= (xkbOutlineWireDesc *)wire; + olWire->nPoints= ol->num_points; + olWire->cornerRadius= ol->corner_radius; + wire= (char *)&olWire[1]; + ptWire= (xkbPointWireDesc *)wire; + for (p=0,pt=ol->points;p<ol->num_points;p++,pt++) { + ptWire[p].x= pt->x; + ptWire[p].y= pt->y; + if (swap) { + register int n; + swaps(&ptWire[p].x,n); + swaps(&ptWire[p].y,n); + } + } + wire= (char *)&ptWire[ol->num_points]; + } + } + return wire; +} + +static int +XkbSizeGeomDoodads(int num_doodads,XkbDoodadPtr doodad) +{ +register int i,size; + + for (i=size=0;i<num_doodads;i++,doodad++) { + size+= SIZEOF(xkbAnyDoodadWireDesc); + if (doodad->any.type==XkbTextDoodad) { + size+= XkbSizeCountedString(doodad->text.text); + size+= XkbSizeCountedString(doodad->text.font); + } + else if (doodad->any.type==XkbLogoDoodad) { + size+= XkbSizeCountedString(doodad->logo.logo_name); + } + } + return size; +} + +static char * +XkbWriteGeomDoodads(char *wire,int num_doodads,XkbDoodadPtr doodad,Bool swap) +{ +register int i; +xkbDoodadWireDesc * doodadWire; + + for (i=0;i<num_doodads;i++,doodad++) { + doodadWire= (xkbDoodadWireDesc *)wire; + wire= (char *)&doodadWire[1]; + bzero(doodadWire,SIZEOF(xkbDoodadWireDesc)); + doodadWire->any.name= doodad->any.name; + doodadWire->any.type= doodad->any.type; + doodadWire->any.priority= doodad->any.priority; + doodadWire->any.top= doodad->any.top; + doodadWire->any.left= doodad->any.left; + if (swap) { + register int n; + swapl(&doodadWire->any.name,n); + swaps(&doodadWire->any.top,n); + swaps(&doodadWire->any.left,n); + } + switch (doodad->any.type) { + case XkbOutlineDoodad: + case XkbSolidDoodad: + doodadWire->shape.angle= doodad->shape.angle; + doodadWire->shape.colorNdx= doodad->shape.color_ndx; + doodadWire->shape.shapeNdx= doodad->shape.shape_ndx; + if (swap) { + register int n; + swaps(&doodadWire->shape.angle,n); + } + break; + case XkbTextDoodad: + doodadWire->text.angle= doodad->text.angle; + doodadWire->text.width= doodad->text.width; + doodadWire->text.height= doodad->text.height; + doodadWire->text.colorNdx= doodad->text.color_ndx; + if (swap) { + register int n; + swaps(&doodadWire->text.angle,n); + swaps(&doodadWire->text.width,n); + swaps(&doodadWire->text.height,n); + } + wire= XkbWriteCountedString(wire,doodad->text.text,swap); + wire= XkbWriteCountedString(wire,doodad->text.font,swap); + break; + case XkbIndicatorDoodad: + doodadWire->indicator.shapeNdx= doodad->indicator.shape_ndx; + doodadWire->indicator.onColorNdx=doodad->indicator.on_color_ndx; + doodadWire->indicator.offColorNdx= + doodad->indicator.off_color_ndx; + break; + case XkbLogoDoodad: + doodadWire->logo.angle= doodad->logo.angle; + doodadWire->logo.colorNdx= doodad->logo.color_ndx; + doodadWire->logo.shapeNdx= doodad->logo.shape_ndx; + wire= XkbWriteCountedString(wire,doodad->logo.logo_name,swap); + break; + default: + ErrorF("[xkb] Unknown doodad type %d in XkbWriteGeomDoodads\n", + doodad->any.type); + ErrorF("[xkb] Ignored\n"); + break; + } + } + return wire; +} + +static char * +XkbWriteGeomOverlay(char *wire,XkbOverlayPtr ol,Bool swap) +{ +register int r; +XkbOverlayRowPtr row; +xkbOverlayWireDesc * olWire; + + olWire= (xkbOverlayWireDesc *)wire; + olWire->name= ol->name; + olWire->nRows= ol->num_rows; + if (swap) { + register int n; + swapl(&olWire->name,n); + } + wire= (char *)&olWire[1]; + for (r=0,row=ol->rows;r<ol->num_rows;r++,row++) { + unsigned int k; + XkbOverlayKeyPtr key; + xkbOverlayRowWireDesc * rowWire; + rowWire= (xkbOverlayRowWireDesc *)wire; + rowWire->rowUnder= row->row_under; + rowWire->nKeys= row->num_keys; + wire= (char *)&rowWire[1]; + for (k=0,key=row->keys;k<row->num_keys;k++,key++) { + xkbOverlayKeyWireDesc * keyWire; + keyWire= (xkbOverlayKeyWireDesc *)wire; + memcpy(keyWire->over,key->over.name,XkbKeyNameLength); + memcpy(keyWire->under,key->under.name,XkbKeyNameLength); + wire= (char *)&keyWire[1]; + } + } + return wire; +} + +static int +XkbSizeGeomSections(XkbGeometryPtr geom) +{ +register int i,size; +XkbSectionPtr section; + + for (i=size=0,section=geom->sections;i<geom->num_sections;i++,section++) { + size+= SIZEOF(xkbSectionWireDesc); + if (section->rows) { + int r; + XkbRowPtr row; + for (r=0,row=section->rows;r<section->num_rows;row++,r++) { + size+= SIZEOF(xkbRowWireDesc); + size+= row->num_keys*SIZEOF(xkbKeyWireDesc); + } + } + if (section->doodads) + size+= XkbSizeGeomDoodads(section->num_doodads,section->doodads); + if (section->overlays) { + int o; + XkbOverlayPtr ol; + for (o=0,ol=section->overlays;o<section->num_overlays;o++,ol++) { + int r; + XkbOverlayRowPtr row; + size+= SIZEOF(xkbOverlayWireDesc); + for (r=0,row=ol->rows;r<ol->num_rows;r++,row++) { + size+= SIZEOF(xkbOverlayRowWireDesc); + size+= row->num_keys*SIZEOF(xkbOverlayKeyWireDesc); + } + } + } + } + return size; +} + +static char * +XkbWriteGeomSections(char *wire,XkbGeometryPtr geom,Bool swap) +{ +register int i; +XkbSectionPtr section; +xkbSectionWireDesc * sectionWire; + + for (i=0,section=geom->sections;i<geom->num_sections;i++,section++) { + sectionWire= (xkbSectionWireDesc *)wire; + sectionWire->name= section->name; + sectionWire->top= section->top; + sectionWire->left= section->left; + sectionWire->width= section->width; + sectionWire->height= section->height; + sectionWire->angle= section->angle; + sectionWire->priority= section->priority; + sectionWire->nRows= section->num_rows; + sectionWire->nDoodads= section->num_doodads; + sectionWire->nOverlays= section->num_overlays; + sectionWire->pad= 0; + if (swap) { + register int n; + swapl(§ionWire->name,n); + swaps(§ionWire->top,n); + swaps(§ionWire->left,n); + swaps(§ionWire->width,n); + swaps(§ionWire->height,n); + swaps(§ionWire->angle,n); + } + wire= (char *)§ionWire[1]; + if (section->rows) { + int r; + XkbRowPtr row; + xkbRowWireDesc * rowWire; + for (r=0,row=section->rows;r<section->num_rows;r++,row++) { + rowWire= (xkbRowWireDesc *)wire; + rowWire->top= row->top; + rowWire->left= row->left; + rowWire->nKeys= row->num_keys; + rowWire->vertical= row->vertical; + rowWire->pad= 0; + if (swap) { + register int n; + swaps(&rowWire->top,n); + swaps(&rowWire->left,n); + } + wire= (char *)&rowWire[1]; + if (row->keys) { + int k; + XkbKeyPtr key; + xkbKeyWireDesc * keyWire; + keyWire= (xkbKeyWireDesc *)wire; + for (k=0,key=row->keys;k<row->num_keys;k++,key++) { + memcpy(keyWire[k].name,key->name.name,XkbKeyNameLength); + keyWire[k].gap= key->gap; + keyWire[k].shapeNdx= key->shape_ndx; + keyWire[k].colorNdx= key->color_ndx; + if (swap) { + register int n; + swaps(&keyWire[k].gap,n); + } + } + wire= (char *)&keyWire[row->num_keys]; + } + } + } + if (section->doodads) { + wire= XkbWriteGeomDoodads(wire, + section->num_doodads,section->doodads, + swap); + } + if (section->overlays) { + register int o; + for (o=0;o<section->num_overlays;o++) { + wire= XkbWriteGeomOverlay(wire,§ion->overlays[o],swap); + } + } + } + return wire; +} + +static Status +XkbComputeGetGeometryReplySize( XkbGeometryPtr geom, + xkbGetGeometryReply * rep, + Atom name) +{ +int len; + + if (geom!=NULL) { + len= XkbSizeCountedString(geom->label_font); + len+= XkbSizeGeomProperties(geom); + len+= XkbSizeGeomColors(geom); + len+= XkbSizeGeomShapes(geom); + len+= XkbSizeGeomSections(geom); + len+= XkbSizeGeomDoodads(geom->num_doodads,geom->doodads); + len+= XkbSizeGeomKeyAliases(geom); + rep->length= len/4; + rep->found= TRUE; + rep->name= geom->name; + rep->widthMM= geom->width_mm; + rep->heightMM= geom->height_mm; + rep->nProperties= geom->num_properties; + rep->nColors= geom->num_colors; + rep->nShapes= geom->num_shapes; + rep->nSections= geom->num_sections; + rep->nDoodads= geom->num_doodads; + rep->nKeyAliases= geom->num_key_aliases; + rep->baseColorNdx= XkbGeomColorIndex(geom,geom->base_color); + rep->labelColorNdx= XkbGeomColorIndex(geom,geom->label_color); + } + else { + rep->length= 0; + rep->found= FALSE; + rep->name= name; + rep->widthMM= rep->heightMM= 0; + rep->nProperties= rep->nColors= rep->nShapes= 0; + rep->nSections= rep->nDoodads= 0; + rep->nKeyAliases= 0; + rep->labelColorNdx= rep->baseColorNdx= 0; + } + return Success; +} + +static int +XkbSendGeometry( ClientPtr client, + XkbGeometryPtr geom, + xkbGetGeometryReply * rep, + Bool freeGeom) +{ + char *desc,*start; + int len; + + if (geom!=NULL) { + len= rep->length*4; + start= desc= malloc(len); + if (!start) + return BadAlloc; + desc= XkbWriteCountedString(desc,geom->label_font,client->swapped); + if ( rep->nProperties>0 ) + desc = XkbWriteGeomProperties(desc,geom,client->swapped); + if ( rep->nColors>0 ) + desc = XkbWriteGeomColors(desc,geom,client->swapped); + if ( rep->nShapes>0 ) + desc = XkbWriteGeomShapes(desc,geom,client->swapped); + if ( rep->nSections>0 ) + desc = XkbWriteGeomSections(desc,geom,client->swapped); + if ( rep->nDoodads>0 ) + desc = XkbWriteGeomDoodads(desc,geom->num_doodads,geom->doodads, + client->swapped); + if ( rep->nKeyAliases>0 ) + desc = XkbWriteGeomKeyAliases(desc,geom,client->swapped); + if ((desc-start)!=(len)) { + ErrorF("[xkb] BOGUS LENGTH in XkbSendGeometry, expected %d, got %ld\n", + len, (unsigned long)(desc-start)); + } + } + else { + len= 0; + start= NULL; + } + if (client->swapped) { + register int n; + swaps(&rep->sequenceNumber,n); + swapl(&rep->length,n); + swapl(&rep->name,n); + swaps(&rep->widthMM,n); + swaps(&rep->heightMM,n); + swaps(&rep->nProperties,n); + swaps(&rep->nColors,n); + swaps(&rep->nShapes,n); + swaps(&rep->nSections,n); + swaps(&rep->nDoodads,n); + swaps(&rep->nKeyAliases,n); + } + WriteToClient(client, SIZEOF(xkbGetGeometryReply), (char *)rep); + if (len>0) + WriteToClient(client, len, start); + if (start!=NULL) + free((char *)start); + if (freeGeom) + XkbFreeGeometry(geom,XkbGeomAllMask,TRUE); + return Success; +} + +int +ProcXkbGetGeometry(ClientPtr client) +{ + DeviceIntPtr dev; + xkbGetGeometryReply rep; + XkbGeometryPtr geom; + Bool shouldFree; + Status status; + + REQUEST(xkbGetGeometryReq); + REQUEST_SIZE_MATCH(xkbGetGeometryReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); + CHK_ATOM_OR_NONE(stuff->name); + + geom= XkbLookupNamedGeometry(dev,stuff->name,&shouldFree); + rep.type= X_Reply; + rep.deviceID= dev->id; + rep.sequenceNumber= client->sequence; + rep.length= 0; + status= XkbComputeGetGeometryReplySize(geom,&rep,stuff->name); + if (status!=Success) + return status; + else return XkbSendGeometry(client,geom,&rep,shouldFree); +} + +/***====================================================================***/ + +static char * +_GetCountedString(char **wire_inout,Bool swap) +{ +char * wire,*str; +CARD16 len,*plen; + + wire= *wire_inout; + plen= (CARD16 *)wire; + if (swap) { + register int n; + swaps(plen,n); + } + len= *plen; + str= malloc(len+1); + if (str) { + memcpy(str,&wire[2],len); + str[len]= '\0'; + } + wire+= XkbPaddedSize(len+2); + *wire_inout= wire; + return str; +} + +static Status +_CheckSetDoodad( char ** wire_inout, + XkbGeometryPtr geom, + XkbSectionPtr section, + ClientPtr client) +{ +char * wire; +xkbDoodadWireDesc * dWire; +XkbDoodadPtr doodad; + + dWire= (xkbDoodadWireDesc *)(*wire_inout); + wire= (char *)&dWire[1]; + if (client->swapped) { + register int n; + swapl(&dWire->any.name,n); + swaps(&dWire->any.top,n); + swaps(&dWire->any.left,n); + swaps(&dWire->any.angle,n); + } + CHK_ATOM_ONLY(dWire->any.name); + doodad= XkbAddGeomDoodad(geom,section,dWire->any.name); + if (!doodad) + return BadAlloc; + doodad->any.type= dWire->any.type; + doodad->any.priority= dWire->any.priority; + doodad->any.top= dWire->any.top; + doodad->any.left= dWire->any.left; + doodad->any.angle= dWire->any.angle; + switch (doodad->any.type) { + case XkbOutlineDoodad: + case XkbSolidDoodad: + if (dWire->shape.colorNdx>=geom->num_colors) { + client->errorValue= _XkbErrCode3(0x40,geom->num_colors, + dWire->shape.colorNdx); + return BadMatch; + } + if (dWire->shape.shapeNdx>=geom->num_shapes) { + client->errorValue= _XkbErrCode3(0x41,geom->num_shapes, + dWire->shape.shapeNdx); + return BadMatch; + } + doodad->shape.color_ndx= dWire->shape.colorNdx; + doodad->shape.shape_ndx= dWire->shape.shapeNdx; + break; + case XkbTextDoodad: + if (dWire->text.colorNdx>=geom->num_colors) { + client->errorValue= _XkbErrCode3(0x42,geom->num_colors, + dWire->text.colorNdx); + return BadMatch; + } + if (client->swapped) { + register int n; + swaps(&dWire->text.width,n); + swaps(&dWire->text.height,n); + } + doodad->text.width= dWire->text.width; + doodad->text.height= dWire->text.height; + doodad->text.color_ndx= dWire->text.colorNdx; + doodad->text.text= _GetCountedString(&wire,client->swapped); + doodad->text.font= _GetCountedString(&wire,client->swapped); + break; + case XkbIndicatorDoodad: + if (dWire->indicator.onColorNdx>=geom->num_colors) { + client->errorValue= _XkbErrCode3(0x43,geom->num_colors, + dWire->indicator.onColorNdx); + return BadMatch; + } + if (dWire->indicator.offColorNdx>=geom->num_colors) { + client->errorValue= _XkbErrCode3(0x44,geom->num_colors, + dWire->indicator.offColorNdx); + return BadMatch; + } + if (dWire->indicator.shapeNdx>=geom->num_shapes) { + client->errorValue= _XkbErrCode3(0x45,geom->num_shapes, + dWire->indicator.shapeNdx); + return BadMatch; + } + doodad->indicator.shape_ndx= dWire->indicator.shapeNdx; + doodad->indicator.on_color_ndx= dWire->indicator.onColorNdx; + doodad->indicator.off_color_ndx= dWire->indicator.offColorNdx; + break; + case XkbLogoDoodad: + if (dWire->logo.colorNdx>=geom->num_colors) { + client->errorValue= _XkbErrCode3(0x46,geom->num_colors, + dWire->logo.colorNdx); + return BadMatch; + } + if (dWire->logo.shapeNdx>=geom->num_shapes) { + client->errorValue= _XkbErrCode3(0x47,geom->num_shapes, + dWire->logo.shapeNdx); + return BadMatch; + } + doodad->logo.color_ndx= dWire->logo.colorNdx; + doodad->logo.shape_ndx= dWire->logo.shapeNdx; + doodad->logo.logo_name= _GetCountedString(&wire,client->swapped); + break; + default: + client->errorValue= _XkbErrCode2(0x4F,dWire->any.type); + return BadValue; + } + *wire_inout= wire; + return Success; +} + +static Status +_CheckSetOverlay( char ** wire_inout, + XkbGeometryPtr geom, + XkbSectionPtr section, + ClientPtr client) +{ +register int r; +char * wire; +XkbOverlayPtr ol; +xkbOverlayWireDesc * olWire; +xkbOverlayRowWireDesc * rWire; + + wire= *wire_inout; + olWire= (xkbOverlayWireDesc *)wire; + if (client->swapped) { + register int n; + swapl(&olWire->name,n); + } + CHK_ATOM_ONLY(olWire->name); + ol= XkbAddGeomOverlay(section,olWire->name,olWire->nRows); + rWire= (xkbOverlayRowWireDesc *)&olWire[1]; + for (r=0;r<olWire->nRows;r++) { + register int k; + xkbOverlayKeyWireDesc * kWire; + XkbOverlayRowPtr row; + + if (rWire->rowUnder>section->num_rows) { + client->errorValue= _XkbErrCode4(0x20,r,section->num_rows, + rWire->rowUnder); + return BadMatch; + } + row= XkbAddGeomOverlayRow(ol,rWire->rowUnder,rWire->nKeys); + kWire= (xkbOverlayKeyWireDesc *)&rWire[1]; + for (k=0;k<rWire->nKeys;k++,kWire++) { + if (XkbAddGeomOverlayKey(ol,row, + (char *)kWire->over,(char *)kWire->under)==NULL) { + client->errorValue= _XkbErrCode3(0x21,r,k); + return BadMatch; + } + } + rWire= (xkbOverlayRowWireDesc *)kWire; + } + olWire= (xkbOverlayWireDesc *)rWire; + wire= (char *)olWire; + *wire_inout= wire; + return Success; +} + +static Status +_CheckSetSections( XkbGeometryPtr geom, + xkbSetGeometryReq * req, + char ** wire_inout, + ClientPtr client) +{ +Status status; +register int s; +char * wire; +xkbSectionWireDesc * sWire; +XkbSectionPtr section; + + wire= *wire_inout; + if (req->nSections<1) + return Success; + sWire= (xkbSectionWireDesc *)wire; + for (s=0;s<req->nSections;s++) { + register int r; + xkbRowWireDesc * rWire; + if (client->swapped) { + register int n; + swapl(&sWire->name,n); + swaps(&sWire->top,n); + swaps(&sWire->left,n); + swaps(&sWire->width,n); + swaps(&sWire->height,n); + swaps(&sWire->angle,n); + } + CHK_ATOM_ONLY(sWire->name); + section= XkbAddGeomSection(geom,sWire->name,sWire->nRows, + sWire->nDoodads,sWire->nOverlays); + if (!section) + return BadAlloc; + section->priority= sWire->priority; + section->top= sWire->top; + section->left= sWire->left; + section->width= sWire->width; + section->height= sWire->height; + section->angle= sWire->angle; + rWire= (xkbRowWireDesc *)&sWire[1]; + for (r=0;r<sWire->nRows;r++) { + register int k; + XkbRowPtr row; + xkbKeyWireDesc * kWire; + if (client->swapped) { + register int n; + swaps(&rWire->top,n); + swaps(&rWire->left,n); + } + row= XkbAddGeomRow(section,rWire->nKeys); + if (!row) + return BadAlloc; + row->top= rWire->top; + row->left= rWire->left; + row->vertical= rWire->vertical; + kWire= (xkbKeyWireDesc *)&rWire[1]; + for (k=0;k<rWire->nKeys;k++) { + XkbKeyPtr key; + key= XkbAddGeomKey(row); + if (!key) + return BadAlloc; + memcpy(key->name.name,kWire[k].name,XkbKeyNameLength); + key->gap= kWire[k].gap; + key->shape_ndx= kWire[k].shapeNdx; + key->color_ndx= kWire[k].colorNdx; + if (key->shape_ndx>=geom->num_shapes) { + client->errorValue= _XkbErrCode3(0x10,key->shape_ndx, + geom->num_shapes); + return BadMatch; + } + if (key->color_ndx>=geom->num_colors) { + client->errorValue= _XkbErrCode3(0x11,key->color_ndx, + geom->num_colors); + return BadMatch; + } + } + rWire= (xkbRowWireDesc *)&kWire[rWire->nKeys]; + } + wire= (char *)rWire; + if (sWire->nDoodads>0) { + register int d; + for (d=0;d<sWire->nDoodads;d++) { + status=_CheckSetDoodad(&wire,geom,section,client); + if (status!=Success) + return status; + } + } + if (sWire->nOverlays>0) { + register int o; + for (o=0;o<sWire->nOverlays;o++) { + status= _CheckSetOverlay(&wire,geom,section,client); + if (status!=Success) + return status; + } + } + sWire= (xkbSectionWireDesc *)wire; + } + wire= (char *)sWire; + *wire_inout= wire; + return Success; +} + +static Status +_CheckSetShapes( XkbGeometryPtr geom, + xkbSetGeometryReq * req, + char ** wire_inout, + ClientPtr client) +{ +register int i; +char * wire; + + wire= *wire_inout; + if (req->nShapes<1) { + client->errorValue= _XkbErrCode2(0x06,req->nShapes); + return BadValue; + } + else { + xkbShapeWireDesc * shapeWire; + XkbShapePtr shape; + register int o; + shapeWire= (xkbShapeWireDesc *)wire; + for (i=0;i<req->nShapes;i++) { + xkbOutlineWireDesc * olWire; + XkbOutlinePtr ol; + shape= XkbAddGeomShape(geom,shapeWire->name,shapeWire->nOutlines); + if (!shape) + return BadAlloc; + olWire= (xkbOutlineWireDesc *)(&shapeWire[1]); + for (o=0;o<shapeWire->nOutlines;o++) { + register int p; + XkbPointPtr pt; + xkbPointWireDesc * ptWire; + + ol= XkbAddGeomOutline(shape,olWire->nPoints); + if (!ol) + return BadAlloc; + ol->corner_radius= olWire->cornerRadius; + ptWire= (xkbPointWireDesc *)&olWire[1]; + for (p=0,pt=ol->points;p<olWire->nPoints;p++,pt++) { + pt->x= ptWire[p].x; + pt->y= ptWire[p].y; + if (client->swapped) { + register int n; + swaps(&pt->x,n); + swaps(&pt->y,n); + } + } + ol->num_points= olWire->nPoints; + olWire= (xkbOutlineWireDesc *)(&ptWire[olWire->nPoints]); + } + if (shapeWire->primaryNdx!=XkbNoShape) + shape->primary= &shape->outlines[shapeWire->primaryNdx]; + if (shapeWire->approxNdx!=XkbNoShape) + shape->approx= &shape->outlines[shapeWire->approxNdx]; + shapeWire= (xkbShapeWireDesc *)olWire; + } + wire= (char *)shapeWire; + } + if (geom->num_shapes!=req->nShapes) { + client->errorValue= _XkbErrCode3(0x07,geom->num_shapes,req->nShapes); + return BadMatch; + } + + *wire_inout= wire; + return Success; +} + +static Status +_CheckSetGeom( XkbGeometryPtr geom, + xkbSetGeometryReq * req, + ClientPtr client) +{ +register int i; +Status status; +char * wire; + + wire= (char *)&req[1]; + geom->label_font= _GetCountedString(&wire,client->swapped); + + for (i=0;i<req->nProperties;i++) { + char *name,*val; + name= _GetCountedString(&wire,client->swapped); + if (!name) + return BadAlloc; + val= _GetCountedString(&wire,client->swapped); + if (!val) { + free(name); + return BadAlloc; + } + if (XkbAddGeomProperty(geom,name,val)==NULL) { + free(name); + free(val); + return BadAlloc; + } + free(name); + free(val); + } + + if (req->nColors<2) { + client->errorValue= _XkbErrCode3(0x01,2,req->nColors); + return BadValue; + } + if (req->baseColorNdx>req->nColors) { + client->errorValue=_XkbErrCode3(0x03,req->nColors,req->baseColorNdx); + return BadMatch; + } + if (req->labelColorNdx>req->nColors) { + client->errorValue= _XkbErrCode3(0x03,req->nColors,req->labelColorNdx); + return BadMatch; + } + if (req->labelColorNdx==req->baseColorNdx) { + client->errorValue= _XkbErrCode3(0x04,req->baseColorNdx, + req->labelColorNdx); + return BadMatch; + } + + for (i=0;i<req->nColors;i++) { + char *name; + name= _GetCountedString(&wire,client->swapped); + if (!name) + return BadAlloc; + if (!XkbAddGeomColor(geom,name,geom->num_colors)) { + free(name); + return BadAlloc; + } + free(name); + } + if (req->nColors!=geom->num_colors) { + client->errorValue= _XkbErrCode3(0x05,req->nColors,geom->num_colors); + return BadMatch; + } + geom->label_color= &geom->colors[req->labelColorNdx]; + geom->base_color= &geom->colors[req->baseColorNdx]; + + if ((status=_CheckSetShapes(geom,req,&wire,client))!=Success) + return status; + + if ((status=_CheckSetSections(geom,req,&wire,client))!=Success) + return status; + + for (i=0;i<req->nDoodads;i++) { + status=_CheckSetDoodad(&wire,geom,NULL,client); + if (status!=Success) + return status; + } + + for (i=0;i<req->nKeyAliases;i++) { + if (XkbAddGeomKeyAlias(geom,&wire[XkbKeyNameLength],wire)==NULL) + return BadAlloc; + wire+= 2*XkbKeyNameLength; + } + return Success; +} + +static int +_XkbSetGeometry(ClientPtr client, DeviceIntPtr dev, xkbSetGeometryReq *stuff) +{ + XkbDescPtr xkb; + Bool new_name; + xkbNewKeyboardNotify nkn; + XkbGeometryPtr geom,old; + XkbGeometrySizesRec sizes; + Status status; + + xkb= dev->key->xkbInfo->desc; + old= xkb->geom; + xkb->geom= NULL; + + sizes.which= XkbGeomAllMask; + sizes.num_properties= stuff->nProperties; + sizes.num_colors= stuff->nColors; + sizes.num_shapes= stuff->nShapes; + sizes.num_sections= stuff->nSections; + sizes.num_doodads= stuff->nDoodads; + sizes.num_key_aliases= stuff->nKeyAliases; + if ((status= XkbAllocGeometry(xkb,&sizes))!=Success) { + xkb->geom= old; + return status; + } + geom= xkb->geom; + geom->name= stuff->name; + geom->width_mm= stuff->widthMM; + geom->height_mm= stuff->heightMM; + if ((status= _CheckSetGeom(geom,stuff,client))!=Success) { + XkbFreeGeometry(geom,XkbGeomAllMask,TRUE); + xkb->geom= old; + return status; + } + new_name= (xkb->names->geometry!=geom->name); + xkb->names->geometry= geom->name; + if (old) + XkbFreeGeometry(old,XkbGeomAllMask,TRUE); + if (new_name) { + xkbNamesNotify nn; + bzero(&nn,sizeof(xkbNamesNotify)); + nn.changed= XkbGeometryNameMask; + XkbSendNamesNotify(dev,&nn); + } + nkn.deviceID= nkn.oldDeviceID= dev->id; + nkn.minKeyCode= nkn.oldMinKeyCode= xkb->min_key_code; + nkn.maxKeyCode= nkn.oldMaxKeyCode= xkb->max_key_code; + nkn.requestMajor= XkbReqCode; + nkn.requestMinor= X_kbSetGeometry; + nkn.changed= XkbNKN_GeometryMask; + XkbSendNewKeyboardNotify(dev,&nkn); + return Success; +} + +int +ProcXkbSetGeometry(ClientPtr client) +{ + DeviceIntPtr dev; + int rc; + + REQUEST(xkbSetGeometryReq); + REQUEST_AT_LEAST_SIZE(xkbSetGeometryReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); + CHK_ATOM_OR_NONE(stuff->name); + + rc = _XkbSetGeometry(client, dev, stuff); + if (rc != Success) + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if ((other != dev) && other->key && !IsMaster(other) && (other->u.master == dev)) + { + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); + if (rc == Success) + _XkbSetGeometry(client, other, stuff); + } + } + } + + return Success; +} + +/***====================================================================***/ + +int +ProcXkbPerClientFlags(ClientPtr client) +{ + DeviceIntPtr dev; + xkbPerClientFlagsReply rep; + XkbInterestPtr interest; + Mask access_mode = DixGetAttrAccess | DixSetAttrAccess; + + REQUEST(xkbPerClientFlagsReq); + REQUEST_SIZE_MATCH(xkbPerClientFlagsReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, access_mode); + CHK_MASK_LEGAL(0x01,stuff->change,XkbPCF_AllFlagsMask); + CHK_MASK_MATCH(0x02,stuff->change,stuff->value); + + interest = XkbFindClientResource((DevicePtr)dev,client); + memset(&rep, 0, sizeof(xkbPerClientFlagsReply)); + rep.type= X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (stuff->change) { + client->xkbClientFlags&= ~stuff->change; + client->xkbClientFlags|= stuff->value; + } + if (stuff->change&XkbPCF_AutoResetControlsMask) { + Bool want; + want= stuff->value&XkbPCF_AutoResetControlsMask; + if (interest && !want) { + interest->autoCtrls= interest->autoCtrlValues= 0; + } + else if (want && (!interest)) { + XID id = FakeClientID(client->index); + AddResource(id,RT_XKBCLIENT,dev); + interest= XkbAddClientResource((DevicePtr)dev,client,id); + if (!interest) + return BadAlloc; + } + if (interest && want ) { + register unsigned affect; + affect= stuff->ctrlsToChange; + + CHK_MASK_LEGAL(0x03,affect,XkbAllBooleanCtrlsMask); + CHK_MASK_MATCH(0x04,affect,stuff->autoCtrls); + CHK_MASK_MATCH(0x05,stuff->autoCtrls,stuff->autoCtrlValues); + + interest->autoCtrls&= ~affect; + interest->autoCtrlValues&= ~affect; + interest->autoCtrls|= stuff->autoCtrls&affect; + interest->autoCtrlValues|= stuff->autoCtrlValues&affect; + } + } + rep.supported = XkbPCF_AllFlagsMask; + rep.value= client->xkbClientFlags&XkbPCF_AllFlagsMask; + if (interest) { + rep.autoCtrls= interest->autoCtrls; + rep.autoCtrlValues= interest->autoCtrlValues; + } + else { + rep.autoCtrls= rep.autoCtrlValues= 0; + } + if ( client->swapped ) { + register int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.supported,n); + swapl(&rep.value,n); + swapl(&rep.autoCtrls,n); + swapl(&rep.autoCtrlValues,n); + } + WriteToClient(client,SIZEOF(xkbPerClientFlagsReply), (char *)&rep); + return Success; +} + +/***====================================================================***/ + +/* all latin-1 alphanumerics, plus parens, minus, underscore, slash */ +/* and wildcards */ +static unsigned char componentSpecLegal[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x87, + 0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff +}; + +/* same as above but accepts percent, plus and bar too */ +static unsigned char componentExprLegal[] = { + 0x00, 0x00, 0x00, 0x00, 0x20, 0xaf, 0xff, 0x87, + 0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff +}; + +static char * +GetComponentSpec(unsigned char **pWire,Bool allowExpr,int *errRtrn) +{ +int len; +register int i; +unsigned char *wire,*str,*tmp,*legal; + + if (allowExpr) legal= &componentExprLegal[0]; + else legal= &componentSpecLegal[0]; + + wire= *pWire; + len= (*(unsigned char *)wire++); + if (len>0) { + str= calloc(1, len+1); + if (str) { + tmp= str; + for (i=0;i<len;i++) { + if (legal[(*wire)/8]&(1<<((*wire)%8))) + *tmp++= *wire++; + else wire++; + } + if (tmp!=str) + *tmp++= '\0'; + else { + free(str); + str= NULL; + } + } + else { + *errRtrn= BadAlloc; + } + } + else { + str= NULL; + } + *pWire= wire; + return (char *)str; +} + +/***====================================================================***/ + +int +ProcXkbListComponents(ClientPtr client) +{ + DeviceIntPtr dev; + xkbListComponentsReply rep; + unsigned len; + int status; + unsigned char * str; + XkbSrvListInfoRec list; + + REQUEST(xkbListComponentsReq); + REQUEST_AT_LEAST_SIZE(xkbListComponentsReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); + + status= Success; + str= (unsigned char *)&stuff[1]; + bzero(&list,sizeof(XkbSrvListInfoRec)); + list.maxRtrn= stuff->maxNames; + list.pattern[_XkbListKeycodes]= GetComponentSpec(&str,FALSE,&status); + list.pattern[_XkbListTypes]= GetComponentSpec(&str,FALSE,&status); + list.pattern[_XkbListCompat]= GetComponentSpec(&str,FALSE,&status); + list.pattern[_XkbListSymbols]= GetComponentSpec(&str,FALSE,&status); + list.pattern[_XkbListGeometry]= GetComponentSpec(&str,FALSE,&status); + if (status!=Success) + return status; + len= str-((unsigned char *)stuff); + if ((XkbPaddedSize(len)/4)!=stuff->length) + return BadLength; + if ((status=XkbDDXList(dev,&list,client))!=Success) { + if (list.pool) { + free(list.pool); + list.pool= NULL; + } + return status; + } + bzero(&rep,sizeof(xkbListComponentsReply)); + rep.type= X_Reply; + rep.deviceID = dev->id; + rep.sequenceNumber = client->sequence; + rep.length = XkbPaddedSize(list.nPool)/4; + rep.nKeymaps = 0; + rep.nKeycodes = list.nFound[_XkbListKeycodes]; + rep.nTypes = list.nFound[_XkbListTypes]; + rep.nCompatMaps = list.nFound[_XkbListCompat]; + rep.nSymbols = list.nFound[_XkbListSymbols]; + rep.nGeometries = list.nFound[_XkbListGeometry]; + rep.extra= 0; + if (list.nTotal>list.maxRtrn) + rep.extra = (list.nTotal-list.maxRtrn); + if (client->swapped) { + register int n; + swaps(&rep.sequenceNumber,n); + swapl(&rep.length,n); + swaps(&rep.nKeymaps,n); + swaps(&rep.nKeycodes,n); + swaps(&rep.nTypes,n); + swaps(&rep.nCompatMaps,n); + swaps(&rep.nSymbols,n); + swaps(&rep.nGeometries,n); + swaps(&rep.extra,n); + } + WriteToClient(client,SIZEOF(xkbListComponentsReply),(char *)&rep); + if (list.nPool && list.pool) { + WriteToClient(client,XkbPaddedSize(list.nPool), (char *)list.pool); + free(list.pool); + list.pool= NULL; + } + return Success; +} + +/***====================================================================***/ + +int +ProcXkbGetKbdByName(ClientPtr client) +{ + DeviceIntPtr dev; + DeviceIntPtr tmpd; + xkbGetKbdByNameReply rep; + xkbGetMapReply mrep; + xkbGetCompatMapReply crep; + xkbGetIndicatorMapReply irep; + xkbGetNamesReply nrep; + xkbGetGeometryReply grep; + XkbComponentNamesRec names; + XkbDescPtr xkb, new; + unsigned char * str; + char mapFile[PATH_MAX]; + unsigned len; + unsigned fwant,fneed,reported; + int status; + Bool geom_changed; + XkbSrvLedInfoPtr old_sli; + XkbSrvLedInfoPtr sli; + Mask access_mode = DixGetAttrAccess | DixManageAccess; + + REQUEST(xkbGetKbdByNameReq); + REQUEST_AT_LEAST_SIZE(xkbGetKbdByNameReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, access_mode); + + xkb = dev->key->xkbInfo->desc; + status= Success; + str= (unsigned char *)&stuff[1]; + if (GetComponentSpec(&str,TRUE,&status)) /* keymap, unsupported */ + return BadMatch; + names.keycodes= GetComponentSpec(&str,TRUE,&status); + names.types= GetComponentSpec(&str,TRUE,&status); + names.compat= GetComponentSpec(&str,TRUE,&status); + names.symbols= GetComponentSpec(&str,TRUE,&status); + names.geometry= GetComponentSpec(&str,TRUE,&status); + if (status!=Success) + return status; + len= str-((unsigned char *)stuff); + if ((XkbPaddedSize(len)/4)!=stuff->length) + return BadLength; + + CHK_MASK_LEGAL(0x01,stuff->want,XkbGBN_AllComponentsMask); + CHK_MASK_LEGAL(0x02,stuff->need,XkbGBN_AllComponentsMask); + + if (stuff->load) + fwant= XkbGBN_AllComponentsMask; + else fwant= stuff->want|stuff->need; + if ((!names.compat)&& + (fwant&(XkbGBN_CompatMapMask|XkbGBN_IndicatorMapMask))) { + names.compat= _XkbDupString("%"); + } + if ((!names.types)&&(fwant&(XkbGBN_TypesMask))) { + names.types= _XkbDupString("%"); + } + if ((!names.symbols)&&(fwant&XkbGBN_SymbolsMask)) { + names.symbols= _XkbDupString("%"); + } + geom_changed= ((names.geometry!=NULL)&&(strcmp(names.geometry,"%")!=0)); + if ((!names.geometry)&&(fwant&XkbGBN_GeometryMask)) { + names.geometry= _XkbDupString("%"); + geom_changed= FALSE; + } + + bzero(mapFile,PATH_MAX); + rep.type= X_Reply; + rep.deviceID = dev->id; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.minKeyCode = xkb->min_key_code; + rep.maxKeyCode = xkb->max_key_code; + rep.loaded= FALSE; + fwant= XkbConvertGetByNameComponents(TRUE,stuff->want)|XkmVirtualModsMask; + fneed= XkbConvertGetByNameComponents(TRUE,stuff->need); + rep.reported= XkbConvertGetByNameComponents(FALSE,fwant|fneed); + if (stuff->load) { + fneed|= XkmKeymapRequired; + fwant|= XkmKeymapLegal; + } + if ((fwant|fneed)&XkmSymbolsMask) { + fneed|= XkmKeyNamesIndex|XkmTypesIndex; + fwant|= XkmIndicatorsIndex; + } + + /* We pass dev in here so we can get the old names out if needed. */ + rep.found = XkbDDXLoadKeymapByNames(dev,&names,fwant,fneed,&new, + mapFile,PATH_MAX); + rep.newKeyboard= FALSE; + rep.pad1= rep.pad2= rep.pad3= rep.pad4= 0; + + stuff->want|= stuff->need; + if (new==NULL) + rep.reported= 0; + else { + if (stuff->load) + rep.loaded= TRUE; + if (stuff->load || + ((rep.reported&XkbGBN_SymbolsMask) && (new->compat))) { + XkbChangesRec changes; + bzero(&changes,sizeof(changes)); + XkbUpdateDescActions(new, + new->min_key_code,XkbNumKeys(new), + &changes); + } + + if (new->map==NULL) + rep.reported&= ~(XkbGBN_SymbolsMask|XkbGBN_TypesMask); + else if (rep.reported&(XkbGBN_SymbolsMask|XkbGBN_TypesMask)) { + mrep.type= X_Reply; + mrep.deviceID = dev->id; + mrep.sequenceNumber= client->sequence; + mrep.length = ((SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply))>>2); + mrep.minKeyCode = new->min_key_code; + mrep.maxKeyCode = new->max_key_code; + mrep.present = 0; + mrep.totalSyms = mrep.totalActs = + mrep.totalKeyBehaviors= mrep.totalKeyExplicit= + mrep.totalModMapKeys= mrep.totalVModMapKeys= 0; + if (rep.reported&(XkbGBN_TypesMask|XkbGBN_ClientSymbolsMask)) { + mrep.present|= XkbKeyTypesMask; + mrep.firstType = 0; + mrep.nTypes = mrep.totalTypes= new->map->num_types; + } + else { + mrep.firstType = mrep.nTypes= 0; + mrep.totalTypes= 0; + } + if (rep.reported&XkbGBN_ClientSymbolsMask) { + mrep.present|= (XkbKeySymsMask|XkbModifierMapMask); + mrep.firstKeySym = mrep.firstModMapKey= new->min_key_code; + mrep.nKeySyms = mrep.nModMapKeys= XkbNumKeys(new); + } + else { + mrep.firstKeySym= mrep.firstModMapKey= 0; + mrep.nKeySyms= mrep.nModMapKeys= 0; + } + if (rep.reported&XkbGBN_ServerSymbolsMask) { + mrep.present|= XkbAllServerInfoMask; + mrep.virtualMods= ~0; + mrep.firstKeyAct = mrep.firstKeyBehavior = + mrep.firstKeyExplicit = new->min_key_code; + mrep.nKeyActs = mrep.nKeyBehaviors = + mrep.nKeyExplicit = XkbNumKeys(new); + mrep.firstVModMapKey= new->min_key_code; + mrep.nVModMapKeys= XkbNumKeys(new); + } + else { + mrep.virtualMods= 0; + mrep.firstKeyAct= mrep.firstKeyBehavior= + mrep.firstKeyExplicit = 0; + mrep.nKeyActs= mrep.nKeyBehaviors= mrep.nKeyExplicit= 0; + } + XkbComputeGetMapReplySize(new,&mrep); + rep.length+= SIZEOF(xGenericReply)/4+mrep.length; + } + if (new->compat==NULL) + rep.reported&= ~XkbGBN_CompatMapMask; + else if (rep.reported&XkbGBN_CompatMapMask) { + crep.type= X_Reply; + crep.deviceID= dev->id; + crep.sequenceNumber= client->sequence; + crep.length= 0; + crep.groups= XkbAllGroupsMask; + crep.firstSI= 0; + crep.nSI= crep.nTotalSI= new->compat->num_si; + XkbComputeGetCompatMapReplySize(new->compat,&crep); + rep.length+= SIZEOF(xGenericReply)/4+crep.length; + } + if (new->indicators==NULL) + rep.reported&= ~XkbGBN_IndicatorMapMask; + else if (rep.reported&XkbGBN_IndicatorMapMask) { + irep.type= X_Reply; + irep.deviceID= dev->id; + irep.sequenceNumber= client->sequence; + irep.length= 0; + irep.which= XkbAllIndicatorsMask; + XkbComputeGetIndicatorMapReplySize(new->indicators,&irep); + rep.length+= SIZEOF(xGenericReply)/4+irep.length; + } + if (new->names==NULL) + rep.reported&= ~(XkbGBN_OtherNamesMask|XkbGBN_KeyNamesMask); + else if (rep.reported&(XkbGBN_OtherNamesMask|XkbGBN_KeyNamesMask)) { + nrep.type= X_Reply; + nrep.deviceID= dev->id; + nrep.sequenceNumber= client->sequence; + nrep.length= 0; + nrep.minKeyCode= new->min_key_code; + nrep.maxKeyCode= new->max_key_code; + if (rep.reported&XkbGBN_OtherNamesMask) { + nrep.which= XkbAllNamesMask; + if (new->map!=NULL) + nrep.nTypes= new->map->num_types; + else nrep.nTypes= 0; + nrep.nKTLevels= 0; + nrep.groupNames= XkbAllGroupsMask; + nrep.virtualMods= XkbAllVirtualModsMask; + nrep.indicators= XkbAllIndicatorsMask; + nrep.nRadioGroups= new->names->num_rg; + } + else { + nrep.which= 0; + nrep.nTypes= 0; + nrep.nKTLevels= 0; + nrep.groupNames= 0; + nrep.virtualMods= 0; + nrep.indicators= 0; + nrep.nRadioGroups= 0; + } + if (rep.reported&XkbGBN_KeyNamesMask) { + nrep.which|= XkbKeyNamesMask; + nrep.firstKey= new->min_key_code; + nrep.nKeys= XkbNumKeys(new); + nrep.nKeyAliases= new->names->num_key_aliases; + if (nrep.nKeyAliases) + nrep.which|= XkbKeyAliasesMask; + } + else { + nrep.which&= ~(XkbKeyNamesMask|XkbKeyAliasesMask); + nrep.firstKey= nrep.nKeys= 0; + nrep.nKeyAliases= 0; + } + XkbComputeGetNamesReplySize(new,&nrep); + rep.length+= SIZEOF(xGenericReply)/4+nrep.length; + } + if (new->geom==NULL) + rep.reported&= ~XkbGBN_GeometryMask; + else if (rep.reported&XkbGBN_GeometryMask) { + grep.type= X_Reply; + grep.deviceID= dev->id; + grep.sequenceNumber= client->sequence; + grep.length= 0; + grep.found= TRUE; + grep.pad= 0; + grep.widthMM= grep.heightMM= 0; + grep.nProperties= grep.nColors= grep.nShapes= 0; + grep.nSections= grep.nDoodads= 0; + grep.baseColorNdx= grep.labelColorNdx= 0; + XkbComputeGetGeometryReplySize(new->geom,&grep,None); + rep.length+= SIZEOF(xGenericReply)/4+grep.length; + } + } + + reported= rep.reported; + if ( client->swapped ) { + register int n; + swaps(&rep.sequenceNumber,n); + swapl(&rep.length,n); + swaps(&rep.found,n); + swaps(&rep.reported,n); + } + WriteToClient(client,SIZEOF(xkbGetKbdByNameReply), (char *)&rep); + if (reported&(XkbGBN_SymbolsMask|XkbGBN_TypesMask)) + XkbSendMap(client,new,&mrep); + if (reported&XkbGBN_CompatMapMask) + XkbSendCompatMap(client,new->compat,&crep); + if (reported&XkbGBN_IndicatorMapMask) + XkbSendIndicatorMap(client,new->indicators,&irep); + if (reported&(XkbGBN_KeyNamesMask|XkbGBN_OtherNamesMask)) + XkbSendNames(client,new,&nrep); + if (reported&XkbGBN_GeometryMask) + XkbSendGeometry(client,new->geom,&grep,FALSE); + if (rep.loaded) { + XkbDescPtr old_xkb; + xkbNewKeyboardNotify nkn; + int i,nG,nTG; + old_xkb= xkb; + xkb= new; + dev->key->xkbInfo->desc= xkb; + new= old_xkb; /* so it'll get freed automatically */ + + *xkb->ctrls= *old_xkb->ctrls; + for (nG=nTG=0,i=xkb->min_key_code;i<=xkb->max_key_code;i++) { + nG= XkbKeyNumGroups(xkb,i); + if (nG>=XkbNumKbdGroups) { + nTG= XkbNumKbdGroups; + break; + } + if (nG>nTG) { + nTG= nG; + } + } + xkb->ctrls->num_groups= nTG; + + for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) { + if ((tmpd == dev) || (!IsMaster(tmpd) && tmpd->u.master == dev)) { + if (tmpd != dev) + XkbCopyDeviceKeymap(tmpd, dev); + + if (tmpd->kbdfeed && tmpd->kbdfeed->xkb_sli) { + old_sli = tmpd->kbdfeed->xkb_sli; + tmpd->kbdfeed->xkb_sli = NULL; + sli = XkbAllocSrvLedInfo(tmpd, tmpd->kbdfeed, NULL, 0); + if (sli) { + sli->explicitState = old_sli->explicitState; + sli->effectiveState = old_sli->effectiveState; + } + tmpd->kbdfeed->xkb_sli = sli; + XkbFreeSrvLedInfo(old_sli); + } + } + } + + nkn.deviceID= nkn.oldDeviceID= dev->id; + nkn.minKeyCode= new->min_key_code; + nkn.maxKeyCode= new->max_key_code; + nkn.oldMinKeyCode= xkb->min_key_code; + nkn.oldMaxKeyCode= xkb->max_key_code; + nkn.requestMajor= XkbReqCode; + nkn.requestMinor= X_kbGetKbdByName; + nkn.changed= XkbNKN_KeycodesMask; + if (geom_changed) + nkn.changed|= XkbNKN_GeometryMask; + XkbSendNewKeyboardNotify(dev,&nkn); + + if (!IsMaster(dev) && dev->u.master) + { + DeviceIntPtr master = dev->u.master; + if (master->u.lastSlave == dev) + { + XkbCopyDeviceKeymap(dev->u.master, dev); + XkbSendNewKeyboardNotify(dev,&nkn); + } + } + } + if ((new!=NULL)&&(new!=xkb)) { + XkbFreeKeyboard(new,XkbAllComponentsMask,TRUE); + new= NULL; + } + if (names.keycodes) { free(names.keycodes); names.keycodes= NULL; } + if (names.types) { free(names.types); names.types= NULL; } + if (names.compat) { free(names.compat); names.compat= NULL; } + if (names.symbols) { free(names.symbols); names.symbols= NULL; } + if (names.geometry) { free(names.geometry); names.geometry= NULL; } + return Success; +} + +/***====================================================================***/ + +static int +ComputeDeviceLedInfoSize( DeviceIntPtr dev, + unsigned int what, + XkbSrvLedInfoPtr sli) +{ +int nNames,nMaps; +register unsigned n,bit; + + if (sli==NULL) + return 0; + nNames= nMaps= 0; + if ((what&XkbXI_IndicatorNamesMask)==0) + sli->namesPresent= 0; + if ((what&XkbXI_IndicatorMapsMask)==0) + sli->mapsPresent= 0; + + for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) { + if (sli->names && sli->names[n]!=None) { + sli->namesPresent|= bit; + nNames++; + } + if (sli->maps && XkbIM_InUse(&sli->maps[n])) { + sli->mapsPresent|= bit; + nMaps++; + } + } + return (nNames*4)+(nMaps*SIZEOF(xkbIndicatorMapWireDesc)); +} + +static int +CheckDeviceLedFBs( DeviceIntPtr dev, + int class, + int id, + xkbGetDeviceInfoReply * rep, + ClientPtr client) +{ +int nFBs= 0; +int length= 0; +Bool classOk; + + if (class==XkbDfltXIClass) { + if (dev->kbdfeed) class= KbdFeedbackClass; + else if (dev->leds) class= LedFeedbackClass; + else { + client->errorValue= _XkbErrCode2(XkbErr_BadClass,class); + return XkbKeyboardErrorCode; + } + } + classOk= FALSE; + if ((dev->kbdfeed)&&((class==KbdFeedbackClass)||(class==XkbAllXIClasses))) { + KbdFeedbackPtr kf; + classOk= TRUE; + for (kf= dev->kbdfeed;(kf);kf=kf->next) { + if ((id!=XkbAllXIIds)&&(id!=XkbDfltXIId)&&(id!=kf->ctrl.id)) + continue; + nFBs++; + length+= SIZEOF(xkbDeviceLedsWireDesc); + if (!kf->xkb_sli) + kf->xkb_sli= XkbAllocSrvLedInfo(dev,kf,NULL,0); + length+= ComputeDeviceLedInfoSize(dev,rep->present,kf->xkb_sli); + if (id!=XkbAllXIIds) + break; + } + } + if ((dev->leds)&&((class==LedFeedbackClass)||(class==XkbAllXIClasses))) { + LedFeedbackPtr lf; + classOk= TRUE; + for (lf= dev->leds;(lf);lf=lf->next) { + if ((id!=XkbAllXIIds)&&(id!=XkbDfltXIId)&&(id!=lf->ctrl.id)) + continue; + nFBs++; + length+= SIZEOF(xkbDeviceLedsWireDesc); + if (!lf->xkb_sli) + lf->xkb_sli= XkbAllocSrvLedInfo(dev,NULL,lf,0); + length+= ComputeDeviceLedInfoSize(dev,rep->present,lf->xkb_sli); + if (id!=XkbAllXIIds) + break; + } + } + if (nFBs>0) { + rep->nDeviceLedFBs= nFBs; + rep->length+= (length/4); + return Success; + } + if (classOk) client->errorValue= _XkbErrCode2(XkbErr_BadId,id); + else client->errorValue= _XkbErrCode2(XkbErr_BadClass,class); + return XkbKeyboardErrorCode; +} + +static int +SendDeviceLedInfo( XkbSrvLedInfoPtr sli, + ClientPtr client) +{ +xkbDeviceLedsWireDesc wire; +int length; + + length= 0; + wire.ledClass= sli->class; + wire.ledID= sli->id; + wire.namesPresent= sli->namesPresent; + wire.mapsPresent= sli->mapsPresent; + wire.physIndicators= sli->physIndicators; + wire.state= sli->effectiveState; + if (client->swapped) { + register int n; + swaps(&wire.ledClass,n); + swaps(&wire.ledID,n); + swapl(&wire.namesPresent,n); + swapl(&wire.mapsPresent,n); + swapl(&wire.physIndicators,n); + swapl(&wire.state,n); + } + WriteToClient(client,SIZEOF(xkbDeviceLedsWireDesc),(char *)&wire); + length+= SIZEOF(xkbDeviceLedsWireDesc); + if (sli->namesPresent|sli->mapsPresent) { + register unsigned i,bit; + if (sli->namesPresent) { + CARD32 awire; + for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { + if (sli->namesPresent&bit) { + awire= (CARD32)sli->names[i]; + if (client->swapped) { + register int n; + swapl(&awire,n); + } + WriteToClient(client,4,(char *)&awire); + length+= 4; + } + } + } + if (sli->mapsPresent) { + for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { + xkbIndicatorMapWireDesc iwire; + if (sli->mapsPresent&bit) { + iwire.flags= sli->maps[i].flags; + iwire.whichGroups= sli->maps[i].which_groups; + iwire.groups= sli->maps[i].groups; + iwire.whichMods= sli->maps[i].which_mods; + iwire.mods= sli->maps[i].mods.mask; + iwire.realMods= sli->maps[i].mods.real_mods; + iwire.virtualMods= sli->maps[i].mods.vmods; + iwire.ctrls= sli->maps[i].ctrls; + if (client->swapped) { + register int n; + swaps(&iwire.virtualMods,n); + swapl(&iwire.ctrls,n); + } + WriteToClient(client,SIZEOF(xkbIndicatorMapWireDesc), + (char *)&iwire); + length+= SIZEOF(xkbIndicatorMapWireDesc); + } + } + } + } + return length; +} + +static int +SendDeviceLedFBs( DeviceIntPtr dev, + int class, + int id, + unsigned wantLength, + ClientPtr client) +{ +int length= 0; + + if (class==XkbDfltXIClass) { + if (dev->kbdfeed) class= KbdFeedbackClass; + else if (dev->leds) class= LedFeedbackClass; + } + if ((dev->kbdfeed)&& + ((class==KbdFeedbackClass)||(class==XkbAllXIClasses))) { + KbdFeedbackPtr kf; + for (kf= dev->kbdfeed;(kf);kf=kf->next) { + if ((id==XkbAllXIIds)||(id==XkbDfltXIId)||(id==kf->ctrl.id)) { + length+= SendDeviceLedInfo(kf->xkb_sli,client); + if (id!=XkbAllXIIds) + break; + } + } + } + if ((dev->leds)&& + ((class==LedFeedbackClass)||(class==XkbAllXIClasses))) { + LedFeedbackPtr lf; + for (lf= dev->leds;(lf);lf=lf->next) { + if ((id==XkbAllXIIds)||(id==XkbDfltXIId)||(id==lf->ctrl.id)) { + length+= SendDeviceLedInfo(lf->xkb_sli,client); + if (id!=XkbAllXIIds) + break; + } + } + } + if (length==wantLength) + return Success; + else return BadLength; +} + +int +ProcXkbGetDeviceInfo(ClientPtr client) +{ +DeviceIntPtr dev; +xkbGetDeviceInfoReply rep; +int status,nDeviceLedFBs; +unsigned length,nameLen; +CARD16 ledClass,ledID; +unsigned wanted; +char * str; + + REQUEST(xkbGetDeviceInfoReq); + REQUEST_SIZE_MATCH(xkbGetDeviceInfoReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + wanted= stuff->wanted; + + CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess); + CHK_MASK_LEGAL(0x01,wanted,XkbXI_AllDeviceFeaturesMask); + + if ((!dev->button)||((stuff->nBtns<1)&&(!stuff->allBtns))) + wanted&= ~XkbXI_ButtonActionsMask; + if ((!dev->kbdfeed)&&(!dev->leds)) + wanted&= ~XkbXI_IndicatorsMask; + + nameLen= XkbSizeCountedString(dev->name); + bzero((char *)&rep,SIZEOF(xkbGetDeviceInfoReply)); + rep.type = X_Reply; + rep.deviceID= dev->id; + rep.sequenceNumber = client->sequence; + rep.length = nameLen/4; + rep.present = wanted; + rep.supported = XkbXI_AllDeviceFeaturesMask; + rep.unsupported = 0; + rep.firstBtnWanted = rep.nBtnsWanted = 0; + rep.firstBtnRtrn = rep.nBtnsRtrn = 0; + if (dev->button) + rep.totalBtns= dev->button->numButtons; + else rep.totalBtns= 0; + rep.devType= dev->xinput_type; + rep.hasOwnState= (dev->key && dev->key->xkbInfo); + rep.nDeviceLedFBs = 0; + if (dev->kbdfeed) rep.dfltKbdFB= dev->kbdfeed->ctrl.id; + else rep.dfltKbdFB= XkbXINone; + if (dev->leds) rep.dfltLedFB= dev->leds->ctrl.id; + else rep.dfltLedFB= XkbXINone; + + ledClass= stuff->ledClass; + ledID= stuff->ledID; + + rep.firstBtnWanted= rep.nBtnsWanted= 0; + rep.firstBtnRtrn= rep.nBtnsRtrn= 0; + if (wanted&XkbXI_ButtonActionsMask) { + if (stuff->allBtns) { + stuff->firstBtn= 0; + stuff->nBtns= dev->button->numButtons; + } + + if ((stuff->firstBtn+stuff->nBtns)>dev->button->numButtons) { + client->errorValue = _XkbErrCode4(0x02,dev->button->numButtons, + stuff->firstBtn, + stuff->nBtns); + return BadValue; + } + else { + rep.firstBtnWanted= stuff->firstBtn; + rep.nBtnsWanted= stuff->nBtns; + if (dev->button->xkb_acts!=NULL) { + XkbAction *act; + register int i; + + rep.firstBtnRtrn= stuff->firstBtn; + rep.nBtnsRtrn= stuff->nBtns; + act= &dev->button->xkb_acts[rep.firstBtnWanted]; + for (i=0;i<rep.nBtnsRtrn;i++,act++) { + if (act->type!=XkbSA_NoAction) + break; + } + rep.firstBtnRtrn+= i; + rep.nBtnsRtrn-= i; + act= &dev->button->xkb_acts[rep.firstBtnRtrn+rep.nBtnsRtrn-1]; + for (i=0;i<rep.nBtnsRtrn;i++,act--) { + if (act->type!=XkbSA_NoAction) + break; + } + rep.nBtnsRtrn-= i; + } + rep.length+= (rep.nBtnsRtrn*SIZEOF(xkbActionWireDesc))/4; + } + } + + if (wanted&XkbXI_IndicatorsMask) { + status= CheckDeviceLedFBs(dev,ledClass,ledID,&rep,client); + if (status!=Success) + return status; + } + length= rep.length*4; + nDeviceLedFBs = rep.nDeviceLedFBs; + if (client->swapped) { + register int n; + swaps(&rep.sequenceNumber,n); + swapl(&rep.length,n); + swaps(&rep.present,n); + swaps(&rep.supported,n); + swaps(&rep.unsupported,n); + swaps(&rep.nDeviceLedFBs,n); + swapl(&rep.type,n); + } + WriteToClient(client,SIZEOF(xkbGetDeviceInfoReply), (char *)&rep); + + str= malloc(nameLen); + if (!str) + return BadAlloc; + XkbWriteCountedString(str,dev->name,client->swapped); + WriteToClient(client,nameLen,str); + free(str); + length-= nameLen; + + if (rep.nBtnsRtrn>0) { + int sz; + xkbActionWireDesc * awire; + sz= rep.nBtnsRtrn*SIZEOF(xkbActionWireDesc); + awire= (xkbActionWireDesc *)&dev->button->xkb_acts[rep.firstBtnRtrn]; + WriteToClient(client,sz,(char *)awire); + length-= sz; + } + if (nDeviceLedFBs>0) { + status= SendDeviceLedFBs(dev,ledClass,ledID,length,client); + if (status!=Success) + return status; + } + else if (length!=0) { + ErrorF("[xkb] Internal Error! BadLength in ProcXkbGetDeviceInfo\n"); + ErrorF("[xkb] Wrote %d fewer bytes than expected\n",length); + return BadLength; + } + return Success; +} + +static char * +CheckSetDeviceIndicators( char * wire, + DeviceIntPtr dev, + int num, + int * status_rtrn, + ClientPtr client) +{ +xkbDeviceLedsWireDesc * ledWire; +int i; +XkbSrvLedInfoPtr sli; + + ledWire= (xkbDeviceLedsWireDesc *)wire; + for (i=0;i<num;i++) { + if (client->swapped) { + register int n; + swaps(&ledWire->ledClass,n); + swaps(&ledWire->ledID,n); + swapl(&ledWire->namesPresent,n); + swapl(&ledWire->mapsPresent,n); + swapl(&ledWire->physIndicators,n); + } + + sli= XkbFindSrvLedInfo(dev,ledWire->ledClass,ledWire->ledID, + XkbXI_IndicatorsMask); + if (sli!=NULL) { + register int n; + register unsigned bit; + int nMaps,nNames; + CARD32 *atomWire; + xkbIndicatorMapWireDesc *mapWire; + + nMaps= nNames= 0; + for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) { + if (ledWire->namesPresent&bit) + nNames++; + if (ledWire->mapsPresent&bit) + nMaps++; + } + atomWire= (CARD32 *)&ledWire[1]; + if (nNames>0) { + for (n=0;n<nNames;n++) { + if (client->swapped) { + register int t; + swapl(atomWire,t); + } + CHK_ATOM_OR_NONE3(((Atom)(*atomWire)),client->errorValue, + *status_rtrn,NULL); + atomWire++; + } + } + mapWire= (xkbIndicatorMapWireDesc *)atomWire; + if (nMaps>0) { + for (n=0;n<nMaps;n++) { + if (client->swapped) { + register int t; + swaps(&mapWire->virtualMods,t); + swapl(&mapWire->ctrls,t); + } + CHK_MASK_LEGAL3(0x21,mapWire->whichGroups, + XkbIM_UseAnyGroup, + client->errorValue, + *status_rtrn,NULL); + CHK_MASK_LEGAL3(0x22,mapWire->whichMods,XkbIM_UseAnyMods, + client->errorValue, + *status_rtrn,NULL); + mapWire++; + } + } + ledWire= (xkbDeviceLedsWireDesc *)mapWire; + } + else { + /* SHOULD NEVER HAPPEN */ + return (char *)ledWire; + } + } + return (char *)ledWire; +} + +static char * +SetDeviceIndicators( char * wire, + DeviceIntPtr dev, + unsigned changed, + int num, + int * status_rtrn, + ClientPtr client, + xkbExtensionDeviceNotify *ev) +{ +xkbDeviceLedsWireDesc * ledWire; +int i; +XkbEventCauseRec cause; +unsigned namec,mapc,statec; +xkbExtensionDeviceNotify ed; +XkbChangesRec changes; +DeviceIntPtr kbd; + + bzero((char *)&ed,sizeof(xkbExtensionDeviceNotify)); + bzero((char *)&changes,sizeof(XkbChangesRec)); + XkbSetCauseXkbReq(&cause,X_kbSetDeviceInfo,client); + ledWire= (xkbDeviceLedsWireDesc *)wire; + for (i=0;i<num;i++) { + register int n; + register unsigned bit; + CARD32 * atomWire; + xkbIndicatorMapWireDesc * mapWire; + XkbSrvLedInfoPtr sli; + + namec= mapc= statec= 0; + sli= XkbFindSrvLedInfo(dev,ledWire->ledClass,ledWire->ledID, + XkbXI_IndicatorMapsMask); + if (!sli) { + /* SHOULD NEVER HAPPEN!! */ + return (char *)ledWire; + } + + atomWire= (CARD32 *)&ledWire[1]; + if (changed&XkbXI_IndicatorNamesMask) { + namec= sli->namesPresent|ledWire->namesPresent; + bzero((char *)sli->names,XkbNumIndicators*sizeof(Atom)); + } + if (ledWire->namesPresent) { + sli->namesPresent= ledWire->namesPresent; + bzero((char *)sli->names,XkbNumIndicators*sizeof(Atom)); + for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) { + if (ledWire->namesPresent&bit) { + sli->names[n]= (Atom)*atomWire; + if (sli->names[n]==None) + ledWire->namesPresent&= ~bit; + atomWire++; + } + } + } + mapWire= (xkbIndicatorMapWireDesc *)atomWire; + if (changed&XkbXI_IndicatorMapsMask) { + mapc= sli->mapsPresent|ledWire->mapsPresent; + sli->mapsPresent= ledWire->mapsPresent; + bzero((char*)sli->maps,XkbNumIndicators*sizeof(XkbIndicatorMapRec)); + } + if (ledWire->mapsPresent) { + for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) { + if (ledWire->mapsPresent&bit) { + sli->maps[n].flags= mapWire->flags; + sli->maps[n].which_groups= mapWire->whichGroups; + sli->maps[n].groups= mapWire->groups; + sli->maps[n].which_mods= mapWire->whichMods; + sli->maps[n].mods.mask= mapWire->mods; + sli->maps[n].mods.real_mods=mapWire->realMods; + sli->maps[n].mods.vmods= mapWire->virtualMods; + sli->maps[n].ctrls= mapWire->ctrls; + mapWire++; + } + } + } + if (changed&XkbXI_IndicatorStateMask) { + statec= sli->effectiveState^ledWire->state; + sli->explicitState&= ~statec; + sli->explicitState|= (ledWire->state&statec); + } + if (namec) + XkbApplyLedNameChanges(dev,sli,namec,&ed,&changes,&cause); + if (mapc) + XkbApplyLedMapChanges(dev,sli,mapc,&ed,&changes,&cause); + if (statec) + XkbApplyLedStateChanges(dev,sli,statec,&ed,&changes,&cause); + + kbd= dev; + if ((sli->flags&XkbSLI_HasOwnState)==0) + kbd = inputInfo.keyboard; + + XkbFlushLedEvents(dev,kbd,sli,&ed,&changes,&cause); + ledWire= (xkbDeviceLedsWireDesc *)mapWire; + } + return (char *)ledWire; +} + + +static int +_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev, + xkbSetDeviceInfoReq *stuff) +{ + char *wire; + + wire= (char *)&stuff[1]; + if (stuff->change&XkbXI_ButtonActionsMask) { + if (!dev->button) { + client->errorValue = _XkbErrCode2(XkbErr_BadClass,ButtonClass); + return XkbKeyboardErrorCode; + } + if ((stuff->firstBtn+stuff->nBtns)>dev->button->numButtons) { + client->errorValue= _XkbErrCode4(0x02,stuff->firstBtn,stuff->nBtns, + dev->button->numButtons); + return BadMatch; + } + wire+= (stuff->nBtns*SIZEOF(xkbActionWireDesc)); + } + if (stuff->change&XkbXI_IndicatorsMask) { + int status= Success; + wire= CheckSetDeviceIndicators(wire,dev,stuff->nDeviceLedFBs, + &status,client); + if (status!=Success) + return status; + } + if (((wire-((char *)stuff))/4)!=stuff->length) + return BadLength; + + return Success; +} + +static int +_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev, + xkbSetDeviceInfoReq *stuff) +{ + char *wire; + xkbExtensionDeviceNotify ed; + + bzero((char *)&ed,SIZEOF(xkbExtensionDeviceNotify)); + ed.deviceID= dev->id; + wire= (char *)&stuff[1]; + if (stuff->change&XkbXI_ButtonActionsMask) { + int nBtns,sz,i; + XkbAction * acts; + DeviceIntPtr kbd; + + nBtns= dev->button->numButtons; + acts= dev->button->xkb_acts; + if (acts==NULL) { + acts= calloc(nBtns, sizeof(XkbAction)); + if (!acts) + return BadAlloc; + dev->button->xkb_acts= acts; + } + sz= stuff->nBtns*SIZEOF(xkbActionWireDesc); + memcpy((char *)&acts[stuff->firstBtn],(char *)wire,sz); + wire+= sz; + ed.reason|= XkbXI_ButtonActionsMask; + ed.firstBtn= stuff->firstBtn; + ed.nBtns= stuff->nBtns; + + if (dev->key) kbd= dev; + else kbd= inputInfo.keyboard; + acts= &dev->button->xkb_acts[stuff->firstBtn]; + for (i=0;i<stuff->nBtns;i++,acts++) { + if (acts->type!=XkbSA_NoAction) + XkbSetActionKeyMods(kbd->key->xkbInfo->desc,acts,0); + } + } + if (stuff->change&XkbXI_IndicatorsMask) { + int status= Success; + wire= SetDeviceIndicators(wire,dev,stuff->change, + stuff->nDeviceLedFBs, &status,client,&ed); + if (status!=Success) + return status; + } + if ((stuff->change)&&(ed.reason)) + XkbSendExtensionDeviceNotify(dev,client,&ed); + return Success; +} + +int +ProcXkbSetDeviceInfo(ClientPtr client) +{ + DeviceIntPtr dev; + int rc; + + REQUEST(xkbSetDeviceInfoReq); + REQUEST_AT_LEAST_SIZE(xkbSetDeviceInfoReq); + + if (!(client->xkbClientFlags&_XkbClientInitialized)) + return BadAccess; + + CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess); + CHK_MASK_LEGAL(0x01,stuff->change,XkbXI_AllFeaturesMask); + + rc = _XkbSetDeviceInfoCheck(client, dev, stuff); + + if (rc != Success) + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd || stuff->deviceSpec == XkbUseCorePtr) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if (((other != dev) && !IsMaster(other) && (other->u.master == dev)) && + ((stuff->deviceSpec == XkbUseCoreKbd && other->key) || + (stuff->deviceSpec == XkbUseCorePtr && other->button))) + { + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); + if (rc == Success) + { + rc = _XkbSetDeviceInfoCheck(client, other, stuff); + if (rc != Success) + return rc; + } + } + } + } + + /* checks done, apply */ + rc = _XkbSetDeviceInfo(client, dev, stuff); + if (rc != Success) + return rc; + + if (stuff->deviceSpec == XkbUseCoreKbd || stuff->deviceSpec == XkbUseCorePtr) + { + DeviceIntPtr other; + for (other = inputInfo.devices; other; other = other->next) + { + if (((other != dev) && !IsMaster(other) && (other->u.master == dev)) && + ((stuff->deviceSpec == XkbUseCoreKbd && other->key) || + (stuff->deviceSpec == XkbUseCorePtr && other->button))) + { + rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess); + if (rc == Success) + { + rc = _XkbSetDeviceInfo(client, other, stuff); + if (rc != Success) + return rc; + } + } + } + } + + return Success; +} + +/***====================================================================***/ + +int +ProcXkbSetDebuggingFlags(ClientPtr client) +{ +CARD32 newFlags,newCtrls,extraLength; +xkbSetDebuggingFlagsReply rep; +int rc; + + REQUEST(xkbSetDebuggingFlagsReq); + REQUEST_AT_LEAST_SIZE(xkbSetDebuggingFlagsReq); + + rc = XaceHook(XACE_SERVER_ACCESS, client, DixDebugAccess); + if (rc != Success) + return rc; + + newFlags= xkbDebugFlags&(~stuff->affectFlags); + newFlags|= (stuff->flags&stuff->affectFlags); + newCtrls= xkbDebugCtrls&(~stuff->affectCtrls); + newCtrls|= (stuff->ctrls&stuff->affectCtrls); + if (xkbDebugFlags || newFlags || stuff->msgLength) { + ErrorF("[xkb] XkbDebug: Setting debug flags to 0x%lx\n",(long)newFlags); + if (newCtrls!=xkbDebugCtrls) + ErrorF("[xkb] XkbDebug: Setting debug controls to 0x%lx\n",(long)newCtrls); + } + extraLength= (stuff->length<<2)-sz_xkbSetDebuggingFlagsReq; + if (stuff->msgLength>0) { + char *msg; + if (extraLength<XkbPaddedSize(stuff->msgLength)) { + ErrorF("[xkb] XkbDebug: msgLength= %d, length= %ld (should be %d)\n", + stuff->msgLength,(long)extraLength, + XkbPaddedSize(stuff->msgLength)); + return BadLength; + } + msg= (char *)&stuff[1]; + if (msg[stuff->msgLength-1]!='\0') { + ErrorF("[xkb] XkbDebug: message not null-terminated\n"); + return BadValue; + } + ErrorF("[xkb] XkbDebug: %s\n",msg); + } + xkbDebugFlags = newFlags; + xkbDebugCtrls = newCtrls; + + rep.type= X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.currentFlags = newFlags; + rep.currentCtrls = newCtrls; + rep.supportedFlags = ~0; + rep.supportedCtrls = ~0; + if ( client->swapped ) { + register int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.currentFlags, n); + swapl(&rep.currentCtrls, n); + swapl(&rep.supportedFlags, n); + swapl(&rep.supportedCtrls, n); + } + WriteToClient(client,SIZEOF(xkbSetDebuggingFlagsReply), (char *)&rep); + return Success; +} + +/***====================================================================***/ + +static int +ProcXkbDispatch (ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_kbUseExtension: + return ProcXkbUseExtension(client); + case X_kbSelectEvents: + return ProcXkbSelectEvents(client); + case X_kbBell: + return ProcXkbBell(client); + case X_kbGetState: + return ProcXkbGetState(client); + case X_kbLatchLockState: + return ProcXkbLatchLockState(client); + case X_kbGetControls: + return ProcXkbGetControls(client); + case X_kbSetControls: + return ProcXkbSetControls(client); + case X_kbGetMap: + return ProcXkbGetMap(client); + case X_kbSetMap: + return ProcXkbSetMap(client); + case X_kbGetCompatMap: + return ProcXkbGetCompatMap(client); + case X_kbSetCompatMap: + return ProcXkbSetCompatMap(client); + case X_kbGetIndicatorState: + return ProcXkbGetIndicatorState(client); + case X_kbGetIndicatorMap: + return ProcXkbGetIndicatorMap(client); + case X_kbSetIndicatorMap: + return ProcXkbSetIndicatorMap(client); + case X_kbGetNamedIndicator: + return ProcXkbGetNamedIndicator(client); + case X_kbSetNamedIndicator: + return ProcXkbSetNamedIndicator(client); + case X_kbGetNames: + return ProcXkbGetNames(client); + case X_kbSetNames: + return ProcXkbSetNames(client); + case X_kbGetGeometry: + return ProcXkbGetGeometry(client); + case X_kbSetGeometry: + return ProcXkbSetGeometry(client); + case X_kbPerClientFlags: + return ProcXkbPerClientFlags(client); + case X_kbListComponents: + return ProcXkbListComponents(client); + case X_kbGetKbdByName: + return ProcXkbGetKbdByName(client); + case X_kbGetDeviceInfo: + return ProcXkbGetDeviceInfo(client); + case X_kbSetDeviceInfo: + return ProcXkbSetDeviceInfo(client); + case X_kbSetDebuggingFlags: + return ProcXkbSetDebuggingFlags(client); + default: + return BadRequest; + } +} + +static int +XkbClientGone(pointer data,XID id) +{ + DevicePtr pXDev = (DevicePtr)data; + + if (!XkbRemoveResourceClient(pXDev,id)) { + ErrorF("[xkb] Internal Error! bad RemoveResourceClient in XkbClientGone\n"); + } + return 1; +} + +void +XkbExtensionInit(void) +{ + ExtensionEntry *extEntry; + + RT_XKBCLIENT = CreateNewResourceType(XkbClientGone, "XkbClient"); + if (!RT_XKBCLIENT) + return; + + if ((extEntry = AddExtension(XkbName, XkbNumberEvents, XkbNumberErrors, + ProcXkbDispatch, SProcXkbDispatch, + NULL, StandardMinorOpcode))) { + XkbReqCode = (unsigned char)extEntry->base; + XkbEventBase = (unsigned char)extEntry->eventBase; + XkbErrorBase = (unsigned char)extEntry->errorBase; + XkbKeyboardErrorCode = XkbErrorBase+XkbKeyboard; + } + return; +} + + diff --git a/xorg-server/xkb/xkbActions.c b/xorg-server/xkb/xkbActions.c index 6a9943fbc..747f945bb 100644 --- a/xorg-server/xkb/xkbActions.c +++ b/xorg-server/xkb/xkbActions.c @@ -1,1389 +1,1389 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#endif - -#include <stdio.h> -#include <math.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/keysym.h> -#include "misc.h" -#include "inputstr.h" -#include "exevents.h" -#include "eventstr.h" -#include <xkbsrv.h> -#include "xkb.h" -#include <ctype.h> -#include "mi.h" -#define EXTENSION_EVENT_BASE 64 - -static int xkbDevicePrivateKeyIndex; -DevPrivateKey xkbDevicePrivateKey = &xkbDevicePrivateKeyIndex; - -static void XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button); -static void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y); - -void -xkbUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc, - pointer data) -{ - xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device); - ProcessInputProc backupproc; - if(xkbPrivPtr->unwrapProc) - xkbPrivPtr->unwrapProc = NULL; - - UNWRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr, backupproc); - proc(device,data); - COND_WRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr, - backupproc,xkbUnwrapProc); -} - - -void -XkbSetExtension(DeviceIntPtr device, ProcessInputProc proc) -{ - xkbDeviceInfoPtr xkbPrivPtr; - - xkbPrivPtr = (xkbDeviceInfoPtr) xcalloc(1, sizeof(xkbDeviceInfoRec)); - if (!xkbPrivPtr) - return; - xkbPrivPtr->unwrapProc = NULL; - - dixSetPrivate(&device->devPrivates, xkbDevicePrivateKey, xkbPrivPtr); - WRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, proc, xkbUnwrapProc); -} - -/***====================================================================***/ - -static XkbAction -_FixUpAction(XkbDescPtr xkb,XkbAction *act) -{ -static XkbAction fake; - - if (XkbIsPtrAction(act)&&(!(xkb->ctrls->enabled_ctrls&XkbMouseKeysMask))) { - fake.type = XkbSA_NoAction; - return fake; - } - if (xkb->ctrls->enabled_ctrls&XkbStickyKeysMask) { - if (act->any.type==XkbSA_SetMods) { - fake.mods.type = XkbSA_LatchMods; - fake.mods.mask = act->mods.mask; - if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask)) - fake.mods.flags= XkbSA_ClearLocks|XkbSA_LatchToLock; - else fake.mods.flags= XkbSA_ClearLocks; - return fake; - } - if (act->any.type==XkbSA_SetGroup) { - fake.group.type = XkbSA_LatchGroup; - if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask)) - fake.group.flags= XkbSA_ClearLocks|XkbSA_LatchToLock; - else fake.group.flags= XkbSA_ClearLocks; - XkbSASetGroup(&fake.group,XkbSAGroup(&act->group)); - return fake; - } - } - return *act; -} - -static XkbAction -XkbGetKeyAction(XkbSrvInfoPtr xkbi,XkbStatePtr xkbState,CARD8 key) -{ -int effectiveGroup; -int col; -XkbDescPtr xkb; -XkbKeyTypePtr type; -XkbAction * pActs; -static XkbAction fake; - - xkb= xkbi->desc; - if (!XkbKeyHasActions(xkb,key) || !XkbKeycodeInRange(xkb,key)) { - fake.type = XkbSA_NoAction; - return fake; - } - pActs= XkbKeyActionsPtr(xkb,key); - col= 0; - - effectiveGroup = XkbGetEffectiveGroup(xkbi, xkbState, key); - if (effectiveGroup != XkbGroup1Index) - col += (effectiveGroup * XkbKeyGroupsWidth(xkb, key)); - - type= XkbKeyKeyType(xkb,key,effectiveGroup); - if (type->map!=NULL) { - register unsigned i,mods; - register XkbKTMapEntryPtr entry; - mods= xkbState->mods&type->mods.mask; - for (entry= type->map,i=0;i<type->map_count;i++,entry++) { - if ((entry->active)&&(entry->mods.mask==mods)) { - col+= entry->level; - break; - } - } - } - if (pActs[col].any.type==XkbSA_NoAction) - return pActs[col]; - fake= _FixUpAction(xkb,&pActs[col]); - return fake; -} - -static XkbAction -XkbGetButtonAction(DeviceIntPtr kbd,DeviceIntPtr dev,int button) -{ -XkbAction fake; - if ((dev->button)&&(dev->button->xkb_acts)) { - if (dev->button->xkb_acts[button-1].any.type!=XkbSA_NoAction) { - fake= _FixUpAction(kbd->key->xkbInfo->desc, - &dev->button->xkb_acts[button-1]); - return fake; - } - } - fake.any.type= XkbSA_NoAction; - return fake; -} - -/***====================================================================***/ - -#define SYNTHETIC_KEYCODE 1 -#define BTN_ACT_FLAG 0x100 - -static int -_XkbFilterSetState( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction *pAction) -{ - if (filter->keycode==0) { /* initial press */ - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = ((pAction->mods.mask&XkbSA_ClearLocks)!=0); - filter->priv = 0; - filter->filter = _XkbFilterSetState; - if (pAction->type==XkbSA_SetMods) { - filter->upAction = *pAction; - xkbi->setMods= pAction->mods.mask; - } - else { - xkbi->groupChange = XkbSAGroup(&pAction->group); - if (pAction->group.flags&XkbSA_GroupAbsolute) - xkbi->groupChange-= xkbi->state.base_group; - filter->upAction= *pAction; - XkbSASetGroup(&filter->upAction.group,xkbi->groupChange); - } - } - else if (filter->keycode==keycode) { - if (filter->upAction.type==XkbSA_SetMods) { - xkbi->clearMods = filter->upAction.mods.mask; - if (filter->upAction.mods.flags&XkbSA_ClearLocks) { - xkbi->state.locked_mods&= ~filter->upAction.mods.mask; - } - } - else { - if (filter->upAction.group.flags&XkbSA_ClearLocks) { - xkbi->state.locked_group = 0; - } - xkbi->groupChange = -XkbSAGroup(&filter->upAction.group); - } - filter->active = 0; - } - else { - filter->upAction.mods.flags&= ~XkbSA_ClearLocks; - filter->filterOthers = 0; - } - return 1; -} - -#define LATCH_KEY_DOWN 1 -#define LATCH_PENDING 2 -#define NO_LATCH 3 - -static int -_XkbFilterLatchState( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ - - if (filter->keycode==0) { /* initial press */ - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 1; - filter->priv = LATCH_KEY_DOWN; - filter->filter = _XkbFilterLatchState; - if (pAction->type==XkbSA_LatchMods) { - filter->upAction = *pAction; - xkbi->setMods = pAction->mods.mask; - } - else { - xkbi->groupChange = XkbSAGroup(&pAction->group); - if (pAction->group.flags&XkbSA_GroupAbsolute) - xkbi->groupChange-= xkbi->state.base_group; - filter->upAction= *pAction; - XkbSASetGroup(&filter->upAction.group,xkbi->groupChange); - } - } - else if ( pAction && (filter->priv==LATCH_PENDING) ) { - if (((1<<pAction->type)&XkbSA_BreakLatch)!=0) { - filter->active = 0; - if (filter->upAction.type==XkbSA_LatchMods) - xkbi->state.latched_mods&= ~filter->upAction.mods.mask; - else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group); - } - else if ((pAction->type==filter->upAction.type)&& - (pAction->mods.flags==filter->upAction.mods.flags)&& - (pAction->mods.mask==filter->upAction.mods.mask)) { - if (filter->upAction.mods.flags&XkbSA_LatchToLock) { - XkbControlsPtr ctrls= xkbi->desc->ctrls; - if (filter->upAction.type==XkbSA_LatchMods) - pAction->mods.type= XkbSA_LockMods; - else pAction->group.type= XkbSA_LockGroup; - if (XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask)&& - (ctrls->enabled_ctrls&XkbStickyKeysMask)) { - XkbDDXAccessXBeep(xkbi->device,_BEEP_STICKY_LOCK, - XkbStickyKeysMask); - } - } - else { - if (filter->upAction.type==XkbSA_LatchMods) - pAction->mods.type= XkbSA_SetMods; - else pAction->group.type= XkbSA_SetGroup; - } - if (filter->upAction.type==XkbSA_LatchMods) - xkbi->state.latched_mods&= ~filter->upAction.mods.mask; - else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group); - filter->active = 0; - } - } - else if (filter->keycode==keycode) { /* release */ - XkbControlsPtr ctrls= xkbi->desc->ctrls; - int needBeep; - int beepType= _BEEP_NONE; - - needBeep= ((ctrls->enabled_ctrls&XkbStickyKeysMask)&& - XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask)); - if (filter->upAction.type==XkbSA_LatchMods) { - xkbi->clearMods = filter->upAction.mods.mask; - if ((filter->upAction.mods.flags&XkbSA_ClearLocks)&& - (xkbi->clearMods&xkbi->state.locked_mods)==xkbi->clearMods) { - xkbi->state.locked_mods&= ~xkbi->clearMods; - filter->priv= NO_LATCH; - beepType= _BEEP_STICKY_UNLOCK; - } - } - else { - xkbi->groupChange = -XkbSAGroup(&filter->upAction.group); - if ((filter->upAction.group.flags&XkbSA_ClearLocks)&& - (xkbi->state.locked_group)) { - xkbi->state.locked_group = 0; - filter->priv = NO_LATCH; - beepType= _BEEP_STICKY_UNLOCK; - } - } - if (filter->priv==NO_LATCH) { - filter->active= 0; - } - else { - filter->priv= LATCH_PENDING; - if (filter->upAction.type==XkbSA_LatchMods) { - xkbi->state.latched_mods |= filter->upAction.mods.mask; - needBeep = xkbi->state.latched_mods ? needBeep : 0; - xkbi->state.latched_mods |= filter->upAction.mods.mask; - } - else { - xkbi->state.latched_group+= XkbSAGroup(&filter->upAction.group); - } - if (needBeep && (beepType==_BEEP_NONE)) - beepType= _BEEP_STICKY_LATCH; - } - if (needBeep && (beepType!=_BEEP_NONE)) - XkbDDXAccessXBeep(xkbi->device,beepType,XkbStickyKeysMask); - } - else if (filter->priv==LATCH_KEY_DOWN) { - filter->priv= NO_LATCH; - filter->filterOthers = 0; - } - return 1; -} - -static int -_XkbFilterLockState( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ - if (pAction&&(pAction->type==XkbSA_LockGroup)) { - if (pAction->group.flags&XkbSA_GroupAbsolute) - xkbi->state.locked_group= XkbSAGroup(&pAction->group); - else xkbi->state.locked_group+= XkbSAGroup(&pAction->group); - return 1; - } - if (filter->keycode==0) { /* initial press */ - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 0; - filter->priv = 0; - filter->filter = _XkbFilterLockState; - filter->upAction = *pAction; - xkbi->state.locked_mods^= pAction->mods.mask; - xkbi->setMods = pAction->mods.mask; - } - else if (filter->keycode==keycode) { - filter->active = 0; - xkbi->clearMods = filter->upAction.mods.mask; - } - return 1; -} - -#define ISO_KEY_DOWN 0 -#define NO_ISO_LOCK 1 - -static int -_XkbFilterISOLock( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ - - if (filter->keycode==0) { /* initial press */ - CARD8 flags= pAction->iso.flags; - - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 1; - filter->priv = ISO_KEY_DOWN; - filter->upAction = *pAction; - filter->filter = _XkbFilterISOLock; - if (flags&XkbSA_ISODfltIsGroup) { - xkbi->groupChange = XkbSAGroup(&pAction->iso); - xkbi->setMods = 0; - } - else { - xkbi->setMods = pAction->iso.mask; - xkbi->groupChange = 0; - } - if ((!(flags&XkbSA_ISONoAffectMods))&&(xkbi->state.base_mods)) { - filter->priv= NO_ISO_LOCK; - xkbi->state.locked_mods^= xkbi->state.base_mods; - } - if ((!(flags&XkbSA_ISONoAffectGroup))&&(xkbi->state.base_group)) { -/* 6/22/93 (ef) -- lock groups if group key is down first */ - } - if (!(flags&XkbSA_ISONoAffectPtr)) { -/* 6/22/93 (ef) -- lock mouse buttons if they're down */ - } - } - else if (filter->keycode==keycode) { - CARD8 flags= filter->upAction.iso.flags; - - if (flags&XkbSA_ISODfltIsGroup) { - xkbi->groupChange = -XkbSAGroup(&filter->upAction.iso); - xkbi->clearMods = 0; - if (filter->priv==ISO_KEY_DOWN) - xkbi->state.locked_group+= XkbSAGroup(&filter->upAction.iso); - } - else { - xkbi->clearMods= filter->upAction.iso.mask; - xkbi->groupChange= 0; - if (filter->priv==ISO_KEY_DOWN) - xkbi->state.locked_mods^= filter->upAction.iso.mask; - } - filter->active = 0; - } - else if (pAction) { - CARD8 flags= filter->upAction.iso.flags; - - switch (pAction->type) { - case XkbSA_SetMods: case XkbSA_LatchMods: - if (!(flags&XkbSA_ISONoAffectMods)) { - pAction->type= XkbSA_LockMods; - filter->priv= NO_ISO_LOCK; - } - break; - case XkbSA_SetGroup: case XkbSA_LatchGroup: - if (!(flags&XkbSA_ISONoAffectGroup)) { - pAction->type= XkbSA_LockGroup; - filter->priv= NO_ISO_LOCK; - } - break; - case XkbSA_PtrBtn: - if (!(flags&XkbSA_ISONoAffectPtr)) { - pAction->type= XkbSA_LockPtrBtn; - filter->priv= NO_ISO_LOCK; - } - break; - case XkbSA_SetControls: - if (!(flags&XkbSA_ISONoAffectCtrls)) { - pAction->type= XkbSA_LockControls; - filter->priv= NO_ISO_LOCK; - } - break; - } - } - return 1; -} - - -static CARD32 -_XkbPtrAccelExpire(OsTimerPtr timer,CARD32 now,pointer arg) -{ -XkbSrvInfoPtr xkbi= (XkbSrvInfoPtr)arg; -XkbControlsPtr ctrls= xkbi->desc->ctrls; -int dx,dy; - - if (xkbi->mouseKey==0) - return 0; - - if (xkbi->mouseKeysAccel) { - if ((xkbi->mouseKeysCounter)<ctrls->mk_time_to_max) { - double step; - xkbi->mouseKeysCounter++; - step= xkbi->mouseKeysCurveFactor* - pow((double)xkbi->mouseKeysCounter,xkbi->mouseKeysCurve); - if (xkbi->mouseKeysDX<0) - dx= floor( ((double)xkbi->mouseKeysDX)*step ); - else dx= ceil( ((double)xkbi->mouseKeysDX)*step ); - if (xkbi->mouseKeysDY<0) - dy= floor( ((double)xkbi->mouseKeysDY)*step ); - else dy= ceil( ((double)xkbi->mouseKeysDY)*step ); - } - else { - dx= xkbi->mouseKeysDX*ctrls->mk_max_speed; - dy= xkbi->mouseKeysDY*ctrls->mk_max_speed; - } - if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteX) - dx= xkbi->mouseKeysDX; - if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteY) - dy= xkbi->mouseKeysDY; - } - else { - dx= xkbi->mouseKeysDX; - dy= xkbi->mouseKeysDY; - } - XkbFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags,dx,dy); - return xkbi->desc->ctrls->mk_interval; -} - -static int -_XkbFilterPointerMove( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ -int x,y; -Bool accel; - - if (xkbi->device == inputInfo.keyboard) - return 0; - - if (filter->keycode==0) { /* initial press */ - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 0; - filter->priv=0; - filter->filter = _XkbFilterPointerMove; - filter->upAction= *pAction; - xkbi->mouseKeysCounter= 0; - xkbi->mouseKey= keycode; - accel= ((pAction->ptr.flags&XkbSA_NoAcceleration)==0); - x= XkbPtrActionX(&pAction->ptr); - y= XkbPtrActionY(&pAction->ptr); - XkbFakePointerMotion(xkbi->device, pAction->ptr.flags,x,y); - AccessXCancelRepeatKey(xkbi,keycode); - xkbi->mouseKeysAccel= accel&& - (xkbi->desc->ctrls->enabled_ctrls&XkbMouseKeysAccelMask); - xkbi->mouseKeysFlags= pAction->ptr.flags; - xkbi->mouseKeysDX= XkbPtrActionX(&pAction->ptr); - xkbi->mouseKeysDY= XkbPtrActionY(&pAction->ptr); - xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0, - xkbi->desc->ctrls->mk_delay, - _XkbPtrAccelExpire,(pointer)xkbi); - } - else if (filter->keycode==keycode) { - filter->active = 0; - if (xkbi->mouseKey==keycode) { - xkbi->mouseKey= 0; - xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0, 0, - NULL, NULL); - } - } - return 0; -} - -static int -_XkbFilterPointerBtn( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ - if (filter->keycode==0) { /* initial press */ - int button= pAction->btn.button; - - if (button==XkbSA_UseDfltButton) - button = xkbi->desc->ctrls->mk_dflt_btn; - - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 0; - filter->priv=0; - filter->filter = _XkbFilterPointerBtn; - filter->upAction= *pAction; - filter->upAction.btn.button= button; - switch (pAction->type) { - case XkbSA_LockPtrBtn: - if (((xkbi->lockedPtrButtons&(1<<button))==0)&& - ((pAction->btn.flags&XkbSA_LockNoLock)==0)) { - xkbi->lockedPtrButtons|= (1<<button); - AccessXCancelRepeatKey(xkbi,keycode); - XkbFakeDeviceButton(xkbi->device, 1, button); - filter->upAction.type= XkbSA_NoAction; - } - break; - case XkbSA_PtrBtn: - { - register int i,nClicks; - AccessXCancelRepeatKey(xkbi,keycode); - if (pAction->btn.count>0) { - nClicks= pAction->btn.count; - for (i=0;i<nClicks;i++) { - XkbFakeDeviceButton(xkbi->device, 1, button); - XkbFakeDeviceButton(xkbi->device, 0, button); - } - filter->upAction.type= XkbSA_NoAction; - } - else XkbFakeDeviceButton(xkbi->device, 1, button); - } - break; - case XkbSA_SetPtrDflt: - { - XkbControlsPtr ctrls= xkbi->desc->ctrls; - XkbControlsRec old; - xkbControlsNotify cn; - - old= *ctrls; - AccessXCancelRepeatKey(xkbi,keycode); - switch (pAction->dflt.affect) { - case XkbSA_AffectDfltBtn: - if (pAction->dflt.flags&XkbSA_DfltBtnAbsolute) - ctrls->mk_dflt_btn= - XkbSAPtrDfltValue(&pAction->dflt); - else { - ctrls->mk_dflt_btn+= - XkbSAPtrDfltValue(&pAction->dflt); - if (ctrls->mk_dflt_btn>5) - ctrls->mk_dflt_btn= 5; - else if (ctrls->mk_dflt_btn<1) - ctrls->mk_dflt_btn= 1; - } - break; - default: - ErrorF( - "Attempt to change unknown pointer default (%d) ignored\n", - pAction->dflt.affect); - break; - } - if (XkbComputeControlsNotify(xkbi->device, - &old,xkbi->desc->ctrls, - &cn,FALSE)) { - cn.keycode = keycode; - /* XXX: what about DeviceKeyPress? */ - cn.eventType = KeyPress; - cn.requestMajor = 0; - cn.requestMinor = 0; - XkbSendControlsNotify(xkbi->device,&cn); - } - } - break; - } - } - else if (filter->keycode==keycode) { - int button= filter->upAction.btn.button; - - switch (filter->upAction.type) { - case XkbSA_LockPtrBtn: - if (((filter->upAction.btn.flags&XkbSA_LockNoUnlock)!=0)|| - ((xkbi->lockedPtrButtons&(1<<button))==0)) { - break; - } - xkbi->lockedPtrButtons&= ~(1<<button); - case XkbSA_PtrBtn: - XkbFakeDeviceButton(xkbi->device, 0, button); - break; - } - filter->active = 0; - } - return 0; -} - -static int -_XkbFilterControls( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ -XkbControlsRec old; -XkbControlsPtr ctrls; -DeviceIntPtr kbd; -unsigned int change; -XkbEventCauseRec cause; - - kbd= xkbi->device; - ctrls= xkbi->desc->ctrls; - old= *ctrls; - if (filter->keycode==0) { /* initial press */ - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 0; - change= XkbActionCtrls(&pAction->ctrls); - filter->priv = change; - filter->filter = _XkbFilterControls; - filter->upAction = *pAction; - - if (pAction->type==XkbSA_LockControls) { - filter->priv= (ctrls->enabled_ctrls&change); - change&= ~ctrls->enabled_ctrls; - } - - if (change) { - xkbControlsNotify cn; - XkbSrvLedInfoPtr sli; - - ctrls->enabled_ctrls|= change; - if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) { - cn.keycode = keycode; - /* XXX: what about DeviceKeyPress? */ - cn.eventType = KeyPress; - cn.requestMajor = 0; - cn.requestMinor = 0; - XkbSendControlsNotify(kbd,&cn); - } - - XkbSetCauseKey(&cause,keycode,KeyPress); - - /* If sticky keys were disabled, clear all locks and latches */ - if ((old.enabled_ctrls&XkbStickyKeysMask)&& - (!(ctrls->enabled_ctrls&XkbStickyKeysMask))) { - XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause); - } - sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); - XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause); - if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) - XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_ON,change); - } - } - else if (filter->keycode==keycode) { - change= filter->priv; - if (change) { - xkbControlsNotify cn; - XkbSrvLedInfoPtr sli; - - ctrls->enabled_ctrls&= ~change; - if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) { - cn.keycode = keycode; - cn.eventType = KeyRelease; - cn.requestMajor = 0; - cn.requestMinor = 0; - XkbSendControlsNotify(kbd,&cn); - } - - XkbSetCauseKey(&cause,keycode,KeyRelease); - /* If sticky keys were disabled, clear all locks and latches */ - if ((old.enabled_ctrls&XkbStickyKeysMask)&& - (!(ctrls->enabled_ctrls&XkbStickyKeysMask))) { - XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause); - } - sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); - XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause); - if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) - XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_OFF,change); - } - filter->keycode= 0; - filter->active= 0; - } - return 1; -} - -static int -_XkbFilterActionMessage(XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ -XkbMessageAction * pMsg; -DeviceIntPtr kbd; - - kbd= xkbi->device; - if (filter->keycode==0) { /* initial press */ - pMsg= &pAction->msg; - if ((pMsg->flags&XkbSA_MessageOnRelease)|| - ((pMsg->flags&XkbSA_MessageGenKeyEvent)==0)) { - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 0; - filter->priv = 0; - filter->filter = _XkbFilterActionMessage; - filter->upAction = *pAction; - } - if (pMsg->flags&XkbSA_MessageOnPress) { - xkbActionMessage msg; - - msg.keycode= keycode; - msg.press= 1; - msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0); - memcpy((char *)msg.message, - (char *)pMsg->message,XkbActionMessageLength); - XkbSendActionMessage(kbd,&msg); - } - return ((pAction->msg.flags&XkbSA_MessageGenKeyEvent)!=0); - } - else if (filter->keycode==keycode) { - pMsg= &filter->upAction.msg; - if (pMsg->flags&XkbSA_MessageOnRelease) { - xkbActionMessage msg; - - msg.keycode= keycode; - msg.press= 0; - msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0); - memcpy((char *)msg.message,(char *)pMsg->message, - XkbActionMessageLength); - XkbSendActionMessage(kbd,&msg); - } - filter->keycode= 0; - filter->active= 0; - return ((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0); - } - return 0; -} - -static int -_XkbFilterRedirectKey( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ -DeviceEvent ev; -int x,y; -XkbStateRec old; -unsigned mods,mask; -xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device); -ProcessInputProc backupproc; - - /* never actually used uninitialised, but gcc isn't smart enough - * to work that out. */ - memset(&old, 0, sizeof(old)); - - if ((filter->keycode!=0)&&(filter->keycode!=keycode)) - return 1; - - GetSpritePosition(xkbi->device, &x,&y); - ev.header = ET_Internal; - ev.length = sizeof(DeviceEvent); - ev.time = GetTimeInMillis(); - ev.root_x = x; - ev.root_y = y; - - if (filter->keycode==0) { /* initial press */ - if ((pAction->redirect.new_key<xkbi->desc->min_key_code)|| - (pAction->redirect.new_key>xkbi->desc->max_key_code)) { - return 1; - } - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 0; - filter->priv = 0; - filter->filter = _XkbFilterRedirectKey; - filter->upAction = *pAction; - - ev.type = ET_KeyPress; - ev.detail.key = pAction->redirect.new_key; - - mask= XkbSARedirectVModsMask(&pAction->redirect); - mods= XkbSARedirectVMods(&pAction->redirect); - if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask); - if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods); - mask|= pAction->redirect.mods_mask; - mods|= pAction->redirect.mods; - - if ( mask || mods ) { - old= xkbi->state; - xkbi->state.base_mods&= ~mask; - xkbi->state.base_mods|= (mods&mask); - xkbi->state.latched_mods&= ~mask; - xkbi->state.latched_mods|= (mods&mask); - xkbi->state.locked_mods&= ~mask; - xkbi->state.locked_mods|= (mods&mask); - XkbComputeDerivedState(xkbi); - } - - UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc); - xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device); - COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, - backupproc,xkbUnwrapProc); - - if ( mask || mods ) - xkbi->state= old; - } - else if (filter->keycode==keycode) { - - ev.type = ET_KeyRelease; - ev.detail.key = filter->upAction.redirect.new_key; - - mask= XkbSARedirectVModsMask(&filter->upAction.redirect); - mods= XkbSARedirectVMods(&filter->upAction.redirect); - if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask); - if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods); - mask|= filter->upAction.redirect.mods_mask; - mods|= filter->upAction.redirect.mods; - - if ( mask || mods ) { - old= xkbi->state; - xkbi->state.base_mods&= ~mask; - xkbi->state.base_mods|= (mods&mask); - xkbi->state.latched_mods&= ~mask; - xkbi->state.latched_mods|= (mods&mask); - xkbi->state.locked_mods&= ~mask; - xkbi->state.locked_mods|= (mods&mask); - XkbComputeDerivedState(xkbi); - } - - UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc); - xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device); - COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, - backupproc,xkbUnwrapProc); - - if ( mask || mods ) - xkbi->state= old; - - filter->keycode= 0; - filter->active= 0; - } - return 0; -} - -static int -_XkbFilterSwitchScreen( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ - DeviceIntPtr dev = xkbi->device; - if (dev == inputInfo.keyboard) - return 0; - - if (filter->keycode==0) { /* initial press */ - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 0; - filter->filter = _XkbFilterSwitchScreen; - AccessXCancelRepeatKey(xkbi, keycode); - XkbDDXSwitchScreen(dev,keycode,pAction); - return 0; - } - else if (filter->keycode==keycode) { - filter->active= 0; - return 0; - } - return 1; -} - -static int -_XkbFilterXF86Private( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ - DeviceIntPtr dev = xkbi->device; - if (dev == inputInfo.keyboard) - return 0; - - if (filter->keycode==0) { /* initial press */ - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 0; - filter->filter = _XkbFilterXF86Private; - XkbDDXPrivate(dev,keycode,pAction); - return 0; - } - else if (filter->keycode==keycode) { - filter->active= 0; - return 0; - } - return 1; -} - - -static int -_XkbFilterDeviceBtn( XkbSrvInfoPtr xkbi, - XkbFilterPtr filter, - unsigned keycode, - XkbAction * pAction) -{ -DeviceIntPtr dev; -int button; - - if (xkbi->device == inputInfo.keyboard) - return 0; - - if (filter->keycode==0) { /* initial press */ - _XkbLookupButtonDevice(&dev, pAction->devbtn.device, serverClient, - DixUnknownAccess, &button); - if (!dev || !dev->public.on) - return 1; - - button= pAction->devbtn.button; - if ((button<1)||(button>dev->button->numButtons)) - return 1; - - filter->keycode = keycode; - filter->active = 1; - filter->filterOthers = 0; - filter->priv=0; - filter->filter = _XkbFilterDeviceBtn; - filter->upAction= *pAction; - switch (pAction->type) { - case XkbSA_LockDeviceBtn: - if ((pAction->devbtn.flags&XkbSA_LockNoLock)|| - BitIsOn(dev->button->down, button)) - return 0; - XkbFakeDeviceButton(dev,TRUE,button); - filter->upAction.type= XkbSA_NoAction; - break; - case XkbSA_DeviceBtn: - if (pAction->devbtn.count>0) { - int nClicks,i; - nClicks= pAction->btn.count; - for (i=0;i<nClicks;i++) { - XkbFakeDeviceButton(dev,TRUE,button); - XkbFakeDeviceButton(dev,FALSE,button); - } - filter->upAction.type= XkbSA_NoAction; - } - else XkbFakeDeviceButton(dev,TRUE,button); - break; - } - } - else if (filter->keycode==keycode) { - int button; - - filter->active= 0; - _XkbLookupButtonDevice(&dev, filter->upAction.devbtn.device, - serverClient, DixUnknownAccess, &button); - if (!dev || !dev->public.on) - return 1; - - button= filter->upAction.btn.button; - switch (filter->upAction.type) { - case XkbSA_LockDeviceBtn: - if ((filter->upAction.devbtn.flags&XkbSA_LockNoUnlock)|| - !BitIsOn(dev->button->down, button)) - return 0; - XkbFakeDeviceButton(dev,FALSE,button); - break; - case XkbSA_DeviceBtn: - XkbFakeDeviceButton(dev,FALSE,button); - break; - } - filter->active = 0; - } - return 0; -} - -static XkbFilterPtr -_XkbNextFreeFilter( - XkbSrvInfoPtr xkbi -) -{ -register int i; - - if (xkbi->szFilters==0) { - xkbi->szFilters = 4; - xkbi->filters = xcalloc(xkbi->szFilters, sizeof(XkbFilterRec)); - /* 6/21/93 (ef) -- XXX! deal with allocation failure */ - } - for (i=0;i<xkbi->szFilters;i++) { - if (!xkbi->filters[i].active) { - xkbi->filters[i].keycode = 0; - return &xkbi->filters[i]; - } - } - xkbi->szFilters*=2; - xkbi->filters= xrealloc(xkbi->filters, - xkbi->szFilters * sizeof(XkbFilterRec)); - /* 6/21/93 (ef) -- XXX! deal with allocation failure */ - bzero(&xkbi->filters[xkbi->szFilters/2], - (xkbi->szFilters/2)*sizeof(XkbFilterRec)); - return &xkbi->filters[xkbi->szFilters/2]; -} - -static int -_XkbApplyFilters(XkbSrvInfoPtr xkbi,unsigned kc,XkbAction *pAction) -{ -register int i,send; - - send= 1; - for (i=0;i<xkbi->szFilters;i++) { - if ((xkbi->filters[i].active)&&(xkbi->filters[i].filter)) - send= ((*xkbi->filters[i].filter)(xkbi,&xkbi->filters[i],kc,pAction) - && send); - } - return send; -} - -void -XkbHandleActions(DeviceIntPtr dev, DeviceIntPtr kbd, DeviceEvent* event) -{ -int key,bit,i; -XkbSrvInfoPtr xkbi; -KeyClassPtr keyc; -int changed,sendEvent; -Bool genStateNotify; -XkbAction act; -XkbFilterPtr filter; -Bool keyEvent; -Bool pressEvent; -ProcessInputProc backupproc; - -xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev); - - keyc= kbd->key; - xkbi= keyc->xkbInfo; - key= event->detail.key; - /* The state may change, so if we're not in the middle of sending a state - * notify, prepare for it */ - if ((xkbi->flags&_XkbStateNotifyInProgress)==0) { - xkbi->prev_state = xkbi->state; - xkbi->flags|= _XkbStateNotifyInProgress; - genStateNotify= TRUE; - } - else genStateNotify= FALSE; - - xkbi->clearMods = xkbi->setMods = 0; - xkbi->groupChange = 0; - - sendEvent = 1; - keyEvent= ((event->type == ET_KeyPress) || (event->type == ET_KeyRelease)); - pressEvent= ((event->type == ET_KeyPress)|| (event->type == ET_ButtonPress)); - - if (pressEvent) { - if (keyEvent) - act = XkbGetKeyAction(xkbi,&xkbi->state,key); - else { - act = XkbGetButtonAction(kbd,dev,key); - key|= BTN_ACT_FLAG; - } - sendEvent = _XkbApplyFilters(xkbi,key,&act); - if (sendEvent) { - switch (act.type) { - case XkbSA_SetMods: - case XkbSA_SetGroup: - filter = _XkbNextFreeFilter(xkbi); - sendEvent = _XkbFilterSetState(xkbi,filter,key,&act); - break; - case XkbSA_LatchMods: - case XkbSA_LatchGroup: - filter = _XkbNextFreeFilter(xkbi); - sendEvent=_XkbFilterLatchState(xkbi,filter,key,&act); - break; - case XkbSA_LockMods: - case XkbSA_LockGroup: - filter = _XkbNextFreeFilter(xkbi); - sendEvent=_XkbFilterLockState(xkbi,filter,key,&act); - break; - case XkbSA_ISOLock: - filter = _XkbNextFreeFilter(xkbi); - sendEvent=_XkbFilterISOLock(xkbi,filter,key,&act); - break; - case XkbSA_MovePtr: - filter = _XkbNextFreeFilter(xkbi); - sendEvent= _XkbFilterPointerMove(xkbi,filter,key,&act); - break; - case XkbSA_PtrBtn: - case XkbSA_LockPtrBtn: - case XkbSA_SetPtrDflt: - filter = _XkbNextFreeFilter(xkbi); - sendEvent= _XkbFilterPointerBtn(xkbi,filter,key,&act); - break; - case XkbSA_Terminate: - sendEvent= XkbDDXTerminateServer(dev,key,&act); - break; - case XkbSA_SwitchScreen: - filter = _XkbNextFreeFilter(xkbi); - sendEvent=_XkbFilterSwitchScreen(xkbi,filter,key,&act); - break; - case XkbSA_SetControls: - case XkbSA_LockControls: - filter = _XkbNextFreeFilter(xkbi); - sendEvent=_XkbFilterControls(xkbi,filter,key,&act); - break; - case XkbSA_ActionMessage: - filter = _XkbNextFreeFilter(xkbi); - sendEvent=_XkbFilterActionMessage(xkbi,filter,key,&act); - break; - case XkbSA_RedirectKey: - filter = _XkbNextFreeFilter(xkbi); - sendEvent= _XkbFilterRedirectKey(xkbi,filter,key,&act); - break; - case XkbSA_DeviceBtn: - case XkbSA_LockDeviceBtn: - filter = _XkbNextFreeFilter(xkbi); - sendEvent= _XkbFilterDeviceBtn(xkbi,filter,key,&act); - break; - case XkbSA_XFree86Private: - filter = _XkbNextFreeFilter(xkbi); - sendEvent= _XkbFilterXF86Private(xkbi,filter,key,&act); - break; - } - } - } - else { - if (!keyEvent) - key|= BTN_ACT_FLAG; - sendEvent = _XkbApplyFilters(xkbi,key,NULL); - } - - if (xkbi->groupChange!=0) - xkbi->state.base_group+= xkbi->groupChange; - if (xkbi->setMods) { - for (i=0,bit=1; xkbi->setMods; i++,bit<<=1 ) { - if (xkbi->setMods&bit) { - keyc->modifierKeyCount[i]++; - xkbi->state.base_mods|= bit; - xkbi->setMods&= ~bit; - } - } - } - if (xkbi->clearMods) { - for (i=0,bit=1; xkbi->clearMods; i++,bit<<=1 ) { - if (xkbi->clearMods&bit) { - keyc->modifierKeyCount[i]--; - if (keyc->modifierKeyCount[i]<=0) { - xkbi->state.base_mods&= ~bit; - keyc->modifierKeyCount[i] = 0; - } - xkbi->clearMods&= ~bit; - } - } - } - - if (sendEvent) { - DeviceIntPtr tmpdev; - if (keyEvent) - tmpdev = dev; - else - tmpdev = GetPairedDevice(dev); - - UNWRAP_PROCESS_INPUT_PROC(tmpdev,xkbPrivPtr, backupproc); - dev->public.processInputProc((InternalEvent*)event, tmpdev); - COND_WRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr, - backupproc,xkbUnwrapProc); - } - else if (keyEvent) { - FixKeyState(event, dev); - } - - XkbComputeDerivedState(xkbi); - changed = XkbStateChangedFlags(&xkbi->prev_state,&xkbi->state); - if (genStateNotify) { - if (changed) { - xkbStateNotify sn; - sn.keycode= key; - sn.eventType= event->type; - sn.requestMajor = sn.requestMinor = 0; - sn.changed= changed; - XkbSendStateNotify(dev,&sn); - } - xkbi->flags&= ~_XkbStateNotifyInProgress; - } - changed= XkbIndicatorsToUpdate(dev,changed,FALSE); - if (changed) { - XkbEventCauseRec cause; - XkbSetCauseKey(&cause, key, event->type); - XkbUpdateIndicators(dev,changed,FALSE,NULL,&cause); - } - return; -} - -int -XkbLatchModifiers(DeviceIntPtr pXDev,CARD8 mask,CARD8 latches) -{ -XkbSrvInfoPtr xkbi; -XkbFilterPtr filter; -XkbAction act; -unsigned clear; - - if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) { - xkbi = pXDev->key->xkbInfo; - clear= (mask&(~latches)); - xkbi->state.latched_mods&= ~clear; - /* Clear any pending latch to locks. - */ - act.type = XkbSA_NoAction; - _XkbApplyFilters(xkbi,SYNTHETIC_KEYCODE,&act); - act.type = XkbSA_LatchMods; - act.mods.flags = 0; - act.mods.mask = mask&latches; - filter = _XkbNextFreeFilter(xkbi); - _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act); - _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL); - return Success; - } - return BadValue; -} - -int -XkbLatchGroup(DeviceIntPtr pXDev,int group) -{ -XkbSrvInfoPtr xkbi; -XkbFilterPtr filter; -XkbAction act; - - if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) { - xkbi = pXDev->key->xkbInfo; - act.type = XkbSA_LatchGroup; - act.group.flags = 0; - XkbSASetGroup(&act.group,group); - filter = _XkbNextFreeFilter(xkbi); - _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act); - _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL); - return Success; - } - return BadValue; -} - -/***====================================================================***/ - -void -XkbClearAllLatchesAndLocks( DeviceIntPtr dev, - XkbSrvInfoPtr xkbi, - Bool genEv, - XkbEventCausePtr cause) -{ -XkbStateRec os; -xkbStateNotify sn; - - sn.changed= 0; - os= xkbi->state; - if (os.latched_mods) { /* clear all latches */ - XkbLatchModifiers(dev,~0,0); - sn.changed|= XkbModifierLatchMask; - } - if (os.latched_group) { - XkbLatchGroup(dev,0); - sn.changed|= XkbGroupLatchMask; - } - if (os.locked_mods) { - xkbi->state.locked_mods= 0; - sn.changed|= XkbModifierLockMask; - } - if (os.locked_group) { - xkbi->state.locked_group= 0; - sn.changed|= XkbGroupLockMask; - } - if ( genEv && sn.changed) { - CARD32 changed; - - XkbComputeDerivedState(xkbi); - sn.keycode= cause->kc; - sn.eventType= cause->event; - sn.requestMajor= cause->mjr; - sn.requestMinor= cause->mnr; - sn.changed= XkbStateChangedFlags(&os,&xkbi->state); - XkbSendStateNotify(dev,&sn); - changed= XkbIndicatorsToUpdate(dev,sn.changed,FALSE); - if (changed) { - XkbUpdateIndicators(dev,changed,TRUE,NULL,cause); - } - } - return; -} - -static void -XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y) -{ - EventListPtr events; - int nevents, i; - DeviceIntPtr ptr; - int gpe_flags = 0; - - if (!dev->u.master) - ptr = dev; - else - ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER)); - - if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY) - gpe_flags = POINTER_ABSOLUTE; - else - gpe_flags = POINTER_RELATIVE; - - events = InitEventList(GetMaximumEventsNum()); - OsBlockSignals(); - nevents = GetPointerEvents(events, ptr, - MotionNotify, 0, - gpe_flags, 0, 2, (int[]){x, y}); - OsReleaseSignals(); - - for (i = 0; i < nevents; i++) - mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL); - - FreeEventList(events, GetMaximumEventsNum()); -} - -static void -XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button) -{ - EventListPtr events; - int nevents, i; - DeviceIntPtr ptr; - - /* If dev is a slave device, and the SD is attached, do nothing. If we'd - * post through the attached master pointer we'd get duplicate events. - * - * if dev is a master keyboard, post through the XTEST device - * - * if dev is a floating slave, post through the device itself. - */ - - if (IsMaster(dev)) - ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER)); - else if (!dev->u.master) - ptr = dev; - else - return; - - events = InitEventList(GetMaximumEventsNum()); - OsBlockSignals(); - nevents = GetPointerEvents(events, ptr, - press ? ButtonPress : ButtonRelease, button, - 0 /* flags */, 0 /* first */, - 0 /* num_val */, NULL); - OsReleaseSignals(); - - - for (i = 0; i < nevents; i++) - mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL); - - FreeEventList(events, GetMaximumEventsNum()); -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#endif + +#include <stdio.h> +#include <math.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/keysym.h> +#include "misc.h" +#include "inputstr.h" +#include "exevents.h" +#include "eventstr.h" +#include <xkbsrv.h> +#include "xkb.h" +#include <ctype.h> +#include "mi.h" +#define EXTENSION_EVENT_BASE 64 + +static int xkbDevicePrivateKeyIndex; +DevPrivateKey xkbDevicePrivateKey = &xkbDevicePrivateKeyIndex; + +static void XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button); +static void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y); + +void +xkbUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc, + pointer data) +{ + xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device); + ProcessInputProc backupproc; + if(xkbPrivPtr->unwrapProc) + xkbPrivPtr->unwrapProc = NULL; + + UNWRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr, backupproc); + proc(device,data); + COND_WRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr, + backupproc,xkbUnwrapProc); +} + + +void +XkbSetExtension(DeviceIntPtr device, ProcessInputProc proc) +{ + xkbDeviceInfoPtr xkbPrivPtr; + + xkbPrivPtr = (xkbDeviceInfoPtr) calloc(1, sizeof(xkbDeviceInfoRec)); + if (!xkbPrivPtr) + return; + xkbPrivPtr->unwrapProc = NULL; + + dixSetPrivate(&device->devPrivates, xkbDevicePrivateKey, xkbPrivPtr); + WRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, proc, xkbUnwrapProc); +} + +/***====================================================================***/ + +static XkbAction +_FixUpAction(XkbDescPtr xkb,XkbAction *act) +{ +static XkbAction fake; + + if (XkbIsPtrAction(act)&&(!(xkb->ctrls->enabled_ctrls&XkbMouseKeysMask))) { + fake.type = XkbSA_NoAction; + return fake; + } + if (xkb->ctrls->enabled_ctrls&XkbStickyKeysMask) { + if (act->any.type==XkbSA_SetMods) { + fake.mods.type = XkbSA_LatchMods; + fake.mods.mask = act->mods.mask; + if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask)) + fake.mods.flags= XkbSA_ClearLocks|XkbSA_LatchToLock; + else fake.mods.flags= XkbSA_ClearLocks; + return fake; + } + if (act->any.type==XkbSA_SetGroup) { + fake.group.type = XkbSA_LatchGroup; + if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask)) + fake.group.flags= XkbSA_ClearLocks|XkbSA_LatchToLock; + else fake.group.flags= XkbSA_ClearLocks; + XkbSASetGroup(&fake.group,XkbSAGroup(&act->group)); + return fake; + } + } + return *act; +} + +static XkbAction +XkbGetKeyAction(XkbSrvInfoPtr xkbi,XkbStatePtr xkbState,CARD8 key) +{ +int effectiveGroup; +int col; +XkbDescPtr xkb; +XkbKeyTypePtr type; +XkbAction * pActs; +static XkbAction fake; + + xkb= xkbi->desc; + if (!XkbKeyHasActions(xkb,key) || !XkbKeycodeInRange(xkb,key)) { + fake.type = XkbSA_NoAction; + return fake; + } + pActs= XkbKeyActionsPtr(xkb,key); + col= 0; + + effectiveGroup = XkbGetEffectiveGroup(xkbi, xkbState, key); + if (effectiveGroup != XkbGroup1Index) + col += (effectiveGroup * XkbKeyGroupsWidth(xkb, key)); + + type= XkbKeyKeyType(xkb,key,effectiveGroup); + if (type->map!=NULL) { + register unsigned i,mods; + register XkbKTMapEntryPtr entry; + mods= xkbState->mods&type->mods.mask; + for (entry= type->map,i=0;i<type->map_count;i++,entry++) { + if ((entry->active)&&(entry->mods.mask==mods)) { + col+= entry->level; + break; + } + } + } + if (pActs[col].any.type==XkbSA_NoAction) + return pActs[col]; + fake= _FixUpAction(xkb,&pActs[col]); + return fake; +} + +static XkbAction +XkbGetButtonAction(DeviceIntPtr kbd,DeviceIntPtr dev,int button) +{ +XkbAction fake; + if ((dev->button)&&(dev->button->xkb_acts)) { + if (dev->button->xkb_acts[button-1].any.type!=XkbSA_NoAction) { + fake= _FixUpAction(kbd->key->xkbInfo->desc, + &dev->button->xkb_acts[button-1]); + return fake; + } + } + fake.any.type= XkbSA_NoAction; + return fake; +} + +/***====================================================================***/ + +#define SYNTHETIC_KEYCODE 1 +#define BTN_ACT_FLAG 0x100 + +static int +_XkbFilterSetState( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction *pAction) +{ + if (filter->keycode==0) { /* initial press */ + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = ((pAction->mods.mask&XkbSA_ClearLocks)!=0); + filter->priv = 0; + filter->filter = _XkbFilterSetState; + if (pAction->type==XkbSA_SetMods) { + filter->upAction = *pAction; + xkbi->setMods= pAction->mods.mask; + } + else { + xkbi->groupChange = XkbSAGroup(&pAction->group); + if (pAction->group.flags&XkbSA_GroupAbsolute) + xkbi->groupChange-= xkbi->state.base_group; + filter->upAction= *pAction; + XkbSASetGroup(&filter->upAction.group,xkbi->groupChange); + } + } + else if (filter->keycode==keycode) { + if (filter->upAction.type==XkbSA_SetMods) { + xkbi->clearMods = filter->upAction.mods.mask; + if (filter->upAction.mods.flags&XkbSA_ClearLocks) { + xkbi->state.locked_mods&= ~filter->upAction.mods.mask; + } + } + else { + if (filter->upAction.group.flags&XkbSA_ClearLocks) { + xkbi->state.locked_group = 0; + } + xkbi->groupChange = -XkbSAGroup(&filter->upAction.group); + } + filter->active = 0; + } + else { + filter->upAction.mods.flags&= ~XkbSA_ClearLocks; + filter->filterOthers = 0; + } + return 1; +} + +#define LATCH_KEY_DOWN 1 +#define LATCH_PENDING 2 +#define NO_LATCH 3 + +static int +_XkbFilterLatchState( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ + + if (filter->keycode==0) { /* initial press */ + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 1; + filter->priv = LATCH_KEY_DOWN; + filter->filter = _XkbFilterLatchState; + if (pAction->type==XkbSA_LatchMods) { + filter->upAction = *pAction; + xkbi->setMods = pAction->mods.mask; + } + else { + xkbi->groupChange = XkbSAGroup(&pAction->group); + if (pAction->group.flags&XkbSA_GroupAbsolute) + xkbi->groupChange-= xkbi->state.base_group; + filter->upAction= *pAction; + XkbSASetGroup(&filter->upAction.group,xkbi->groupChange); + } + } + else if ( pAction && (filter->priv==LATCH_PENDING) ) { + if (((1<<pAction->type)&XkbSA_BreakLatch)!=0) { + filter->active = 0; + if (filter->upAction.type==XkbSA_LatchMods) + xkbi->state.latched_mods&= ~filter->upAction.mods.mask; + else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group); + } + else if ((pAction->type==filter->upAction.type)&& + (pAction->mods.flags==filter->upAction.mods.flags)&& + (pAction->mods.mask==filter->upAction.mods.mask)) { + if (filter->upAction.mods.flags&XkbSA_LatchToLock) { + XkbControlsPtr ctrls= xkbi->desc->ctrls; + if (filter->upAction.type==XkbSA_LatchMods) + pAction->mods.type= XkbSA_LockMods; + else pAction->group.type= XkbSA_LockGroup; + if (XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask)&& + (ctrls->enabled_ctrls&XkbStickyKeysMask)) { + XkbDDXAccessXBeep(xkbi->device,_BEEP_STICKY_LOCK, + XkbStickyKeysMask); + } + } + else { + if (filter->upAction.type==XkbSA_LatchMods) + pAction->mods.type= XkbSA_SetMods; + else pAction->group.type= XkbSA_SetGroup; + } + if (filter->upAction.type==XkbSA_LatchMods) + xkbi->state.latched_mods&= ~filter->upAction.mods.mask; + else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group); + filter->active = 0; + } + } + else if (filter->keycode==keycode) { /* release */ + XkbControlsPtr ctrls= xkbi->desc->ctrls; + int needBeep; + int beepType= _BEEP_NONE; + + needBeep= ((ctrls->enabled_ctrls&XkbStickyKeysMask)&& + XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask)); + if (filter->upAction.type==XkbSA_LatchMods) { + xkbi->clearMods = filter->upAction.mods.mask; + if ((filter->upAction.mods.flags&XkbSA_ClearLocks)&& + (xkbi->clearMods&xkbi->state.locked_mods)==xkbi->clearMods) { + xkbi->state.locked_mods&= ~xkbi->clearMods; + filter->priv= NO_LATCH; + beepType= _BEEP_STICKY_UNLOCK; + } + } + else { + xkbi->groupChange = -XkbSAGroup(&filter->upAction.group); + if ((filter->upAction.group.flags&XkbSA_ClearLocks)&& + (xkbi->state.locked_group)) { + xkbi->state.locked_group = 0; + filter->priv = NO_LATCH; + beepType= _BEEP_STICKY_UNLOCK; + } + } + if (filter->priv==NO_LATCH) { + filter->active= 0; + } + else { + filter->priv= LATCH_PENDING; + if (filter->upAction.type==XkbSA_LatchMods) { + xkbi->state.latched_mods |= filter->upAction.mods.mask; + needBeep = xkbi->state.latched_mods ? needBeep : 0; + xkbi->state.latched_mods |= filter->upAction.mods.mask; + } + else { + xkbi->state.latched_group+= XkbSAGroup(&filter->upAction.group); + } + if (needBeep && (beepType==_BEEP_NONE)) + beepType= _BEEP_STICKY_LATCH; + } + if (needBeep && (beepType!=_BEEP_NONE)) + XkbDDXAccessXBeep(xkbi->device,beepType,XkbStickyKeysMask); + } + else if (filter->priv==LATCH_KEY_DOWN) { + filter->priv= NO_LATCH; + filter->filterOthers = 0; + } + return 1; +} + +static int +_XkbFilterLockState( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ + if (pAction&&(pAction->type==XkbSA_LockGroup)) { + if (pAction->group.flags&XkbSA_GroupAbsolute) + xkbi->state.locked_group= XkbSAGroup(&pAction->group); + else xkbi->state.locked_group+= XkbSAGroup(&pAction->group); + return 1; + } + if (filter->keycode==0) { /* initial press */ + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 0; + filter->priv = 0; + filter->filter = _XkbFilterLockState; + filter->upAction = *pAction; + xkbi->state.locked_mods^= pAction->mods.mask; + xkbi->setMods = pAction->mods.mask; + } + else if (filter->keycode==keycode) { + filter->active = 0; + xkbi->clearMods = filter->upAction.mods.mask; + } + return 1; +} + +#define ISO_KEY_DOWN 0 +#define NO_ISO_LOCK 1 + +static int +_XkbFilterISOLock( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ + + if (filter->keycode==0) { /* initial press */ + CARD8 flags= pAction->iso.flags; + + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 1; + filter->priv = ISO_KEY_DOWN; + filter->upAction = *pAction; + filter->filter = _XkbFilterISOLock; + if (flags&XkbSA_ISODfltIsGroup) { + xkbi->groupChange = XkbSAGroup(&pAction->iso); + xkbi->setMods = 0; + } + else { + xkbi->setMods = pAction->iso.mask; + xkbi->groupChange = 0; + } + if ((!(flags&XkbSA_ISONoAffectMods))&&(xkbi->state.base_mods)) { + filter->priv= NO_ISO_LOCK; + xkbi->state.locked_mods^= xkbi->state.base_mods; + } + if ((!(flags&XkbSA_ISONoAffectGroup))&&(xkbi->state.base_group)) { +/* 6/22/93 (ef) -- lock groups if group key is down first */ + } + if (!(flags&XkbSA_ISONoAffectPtr)) { +/* 6/22/93 (ef) -- lock mouse buttons if they're down */ + } + } + else if (filter->keycode==keycode) { + CARD8 flags= filter->upAction.iso.flags; + + if (flags&XkbSA_ISODfltIsGroup) { + xkbi->groupChange = -XkbSAGroup(&filter->upAction.iso); + xkbi->clearMods = 0; + if (filter->priv==ISO_KEY_DOWN) + xkbi->state.locked_group+= XkbSAGroup(&filter->upAction.iso); + } + else { + xkbi->clearMods= filter->upAction.iso.mask; + xkbi->groupChange= 0; + if (filter->priv==ISO_KEY_DOWN) + xkbi->state.locked_mods^= filter->upAction.iso.mask; + } + filter->active = 0; + } + else if (pAction) { + CARD8 flags= filter->upAction.iso.flags; + + switch (pAction->type) { + case XkbSA_SetMods: case XkbSA_LatchMods: + if (!(flags&XkbSA_ISONoAffectMods)) { + pAction->type= XkbSA_LockMods; + filter->priv= NO_ISO_LOCK; + } + break; + case XkbSA_SetGroup: case XkbSA_LatchGroup: + if (!(flags&XkbSA_ISONoAffectGroup)) { + pAction->type= XkbSA_LockGroup; + filter->priv= NO_ISO_LOCK; + } + break; + case XkbSA_PtrBtn: + if (!(flags&XkbSA_ISONoAffectPtr)) { + pAction->type= XkbSA_LockPtrBtn; + filter->priv= NO_ISO_LOCK; + } + break; + case XkbSA_SetControls: + if (!(flags&XkbSA_ISONoAffectCtrls)) { + pAction->type= XkbSA_LockControls; + filter->priv= NO_ISO_LOCK; + } + break; + } + } + return 1; +} + + +static CARD32 +_XkbPtrAccelExpire(OsTimerPtr timer,CARD32 now,pointer arg) +{ +XkbSrvInfoPtr xkbi= (XkbSrvInfoPtr)arg; +XkbControlsPtr ctrls= xkbi->desc->ctrls; +int dx,dy; + + if (xkbi->mouseKey==0) + return 0; + + if (xkbi->mouseKeysAccel) { + if ((xkbi->mouseKeysCounter)<ctrls->mk_time_to_max) { + double step; + xkbi->mouseKeysCounter++; + step= xkbi->mouseKeysCurveFactor* + pow((double)xkbi->mouseKeysCounter,xkbi->mouseKeysCurve); + if (xkbi->mouseKeysDX<0) + dx= floor( ((double)xkbi->mouseKeysDX)*step ); + else dx= ceil( ((double)xkbi->mouseKeysDX)*step ); + if (xkbi->mouseKeysDY<0) + dy= floor( ((double)xkbi->mouseKeysDY)*step ); + else dy= ceil( ((double)xkbi->mouseKeysDY)*step ); + } + else { + dx= xkbi->mouseKeysDX*ctrls->mk_max_speed; + dy= xkbi->mouseKeysDY*ctrls->mk_max_speed; + } + if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteX) + dx= xkbi->mouseKeysDX; + if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteY) + dy= xkbi->mouseKeysDY; + } + else { + dx= xkbi->mouseKeysDX; + dy= xkbi->mouseKeysDY; + } + XkbFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags,dx,dy); + return xkbi->desc->ctrls->mk_interval; +} + +static int +_XkbFilterPointerMove( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ +int x,y; +Bool accel; + + if (xkbi->device == inputInfo.keyboard) + return 0; + + if (filter->keycode==0) { /* initial press */ + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 0; + filter->priv=0; + filter->filter = _XkbFilterPointerMove; + filter->upAction= *pAction; + xkbi->mouseKeysCounter= 0; + xkbi->mouseKey= keycode; + accel= ((pAction->ptr.flags&XkbSA_NoAcceleration)==0); + x= XkbPtrActionX(&pAction->ptr); + y= XkbPtrActionY(&pAction->ptr); + XkbFakePointerMotion(xkbi->device, pAction->ptr.flags,x,y); + AccessXCancelRepeatKey(xkbi,keycode); + xkbi->mouseKeysAccel= accel&& + (xkbi->desc->ctrls->enabled_ctrls&XkbMouseKeysAccelMask); + xkbi->mouseKeysFlags= pAction->ptr.flags; + xkbi->mouseKeysDX= XkbPtrActionX(&pAction->ptr); + xkbi->mouseKeysDY= XkbPtrActionY(&pAction->ptr); + xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0, + xkbi->desc->ctrls->mk_delay, + _XkbPtrAccelExpire,(pointer)xkbi); + } + else if (filter->keycode==keycode) { + filter->active = 0; + if (xkbi->mouseKey==keycode) { + xkbi->mouseKey= 0; + xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0, 0, + NULL, NULL); + } + } + return 0; +} + +static int +_XkbFilterPointerBtn( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ + if (filter->keycode==0) { /* initial press */ + int button= pAction->btn.button; + + if (button==XkbSA_UseDfltButton) + button = xkbi->desc->ctrls->mk_dflt_btn; + + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 0; + filter->priv=0; + filter->filter = _XkbFilterPointerBtn; + filter->upAction= *pAction; + filter->upAction.btn.button= button; + switch (pAction->type) { + case XkbSA_LockPtrBtn: + if (((xkbi->lockedPtrButtons&(1<<button))==0)&& + ((pAction->btn.flags&XkbSA_LockNoLock)==0)) { + xkbi->lockedPtrButtons|= (1<<button); + AccessXCancelRepeatKey(xkbi,keycode); + XkbFakeDeviceButton(xkbi->device, 1, button); + filter->upAction.type= XkbSA_NoAction; + } + break; + case XkbSA_PtrBtn: + { + register int i,nClicks; + AccessXCancelRepeatKey(xkbi,keycode); + if (pAction->btn.count>0) { + nClicks= pAction->btn.count; + for (i=0;i<nClicks;i++) { + XkbFakeDeviceButton(xkbi->device, 1, button); + XkbFakeDeviceButton(xkbi->device, 0, button); + } + filter->upAction.type= XkbSA_NoAction; + } + else XkbFakeDeviceButton(xkbi->device, 1, button); + } + break; + case XkbSA_SetPtrDflt: + { + XkbControlsPtr ctrls= xkbi->desc->ctrls; + XkbControlsRec old; + xkbControlsNotify cn; + + old= *ctrls; + AccessXCancelRepeatKey(xkbi,keycode); + switch (pAction->dflt.affect) { + case XkbSA_AffectDfltBtn: + if (pAction->dflt.flags&XkbSA_DfltBtnAbsolute) + ctrls->mk_dflt_btn= + XkbSAPtrDfltValue(&pAction->dflt); + else { + ctrls->mk_dflt_btn+= + XkbSAPtrDfltValue(&pAction->dflt); + if (ctrls->mk_dflt_btn>5) + ctrls->mk_dflt_btn= 5; + else if (ctrls->mk_dflt_btn<1) + ctrls->mk_dflt_btn= 1; + } + break; + default: + ErrorF( + "Attempt to change unknown pointer default (%d) ignored\n", + pAction->dflt.affect); + break; + } + if (XkbComputeControlsNotify(xkbi->device, + &old,xkbi->desc->ctrls, + &cn,FALSE)) { + cn.keycode = keycode; + /* XXX: what about DeviceKeyPress? */ + cn.eventType = KeyPress; + cn.requestMajor = 0; + cn.requestMinor = 0; + XkbSendControlsNotify(xkbi->device,&cn); + } + } + break; + } + } + else if (filter->keycode==keycode) { + int button= filter->upAction.btn.button; + + switch (filter->upAction.type) { + case XkbSA_LockPtrBtn: + if (((filter->upAction.btn.flags&XkbSA_LockNoUnlock)!=0)|| + ((xkbi->lockedPtrButtons&(1<<button))==0)) { + break; + } + xkbi->lockedPtrButtons&= ~(1<<button); + case XkbSA_PtrBtn: + XkbFakeDeviceButton(xkbi->device, 0, button); + break; + } + filter->active = 0; + } + return 0; +} + +static int +_XkbFilterControls( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ +XkbControlsRec old; +XkbControlsPtr ctrls; +DeviceIntPtr kbd; +unsigned int change; +XkbEventCauseRec cause; + + kbd= xkbi->device; + ctrls= xkbi->desc->ctrls; + old= *ctrls; + if (filter->keycode==0) { /* initial press */ + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 0; + change= XkbActionCtrls(&pAction->ctrls); + filter->priv = change; + filter->filter = _XkbFilterControls; + filter->upAction = *pAction; + + if (pAction->type==XkbSA_LockControls) { + filter->priv= (ctrls->enabled_ctrls&change); + change&= ~ctrls->enabled_ctrls; + } + + if (change) { + xkbControlsNotify cn; + XkbSrvLedInfoPtr sli; + + ctrls->enabled_ctrls|= change; + if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) { + cn.keycode = keycode; + /* XXX: what about DeviceKeyPress? */ + cn.eventType = KeyPress; + cn.requestMajor = 0; + cn.requestMinor = 0; + XkbSendControlsNotify(kbd,&cn); + } + + XkbSetCauseKey(&cause,keycode,KeyPress); + + /* If sticky keys were disabled, clear all locks and latches */ + if ((old.enabled_ctrls&XkbStickyKeysMask)&& + (!(ctrls->enabled_ctrls&XkbStickyKeysMask))) { + XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause); + } + sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); + XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause); + if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) + XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_ON,change); + } + } + else if (filter->keycode==keycode) { + change= filter->priv; + if (change) { + xkbControlsNotify cn; + XkbSrvLedInfoPtr sli; + + ctrls->enabled_ctrls&= ~change; + if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) { + cn.keycode = keycode; + cn.eventType = KeyRelease; + cn.requestMajor = 0; + cn.requestMinor = 0; + XkbSendControlsNotify(kbd,&cn); + } + + XkbSetCauseKey(&cause,keycode,KeyRelease); + /* If sticky keys were disabled, clear all locks and latches */ + if ((old.enabled_ctrls&XkbStickyKeysMask)&& + (!(ctrls->enabled_ctrls&XkbStickyKeysMask))) { + XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause); + } + sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); + XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause); + if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) + XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_OFF,change); + } + filter->keycode= 0; + filter->active= 0; + } + return 1; +} + +static int +_XkbFilterActionMessage(XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ +XkbMessageAction * pMsg; +DeviceIntPtr kbd; + + kbd= xkbi->device; + if (filter->keycode==0) { /* initial press */ + pMsg= &pAction->msg; + if ((pMsg->flags&XkbSA_MessageOnRelease)|| + ((pMsg->flags&XkbSA_MessageGenKeyEvent)==0)) { + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 0; + filter->priv = 0; + filter->filter = _XkbFilterActionMessage; + filter->upAction = *pAction; + } + if (pMsg->flags&XkbSA_MessageOnPress) { + xkbActionMessage msg; + + msg.keycode= keycode; + msg.press= 1; + msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0); + memcpy((char *)msg.message, + (char *)pMsg->message,XkbActionMessageLength); + XkbSendActionMessage(kbd,&msg); + } + return ((pAction->msg.flags&XkbSA_MessageGenKeyEvent)!=0); + } + else if (filter->keycode==keycode) { + pMsg= &filter->upAction.msg; + if (pMsg->flags&XkbSA_MessageOnRelease) { + xkbActionMessage msg; + + msg.keycode= keycode; + msg.press= 0; + msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0); + memcpy((char *)msg.message,(char *)pMsg->message, + XkbActionMessageLength); + XkbSendActionMessage(kbd,&msg); + } + filter->keycode= 0; + filter->active= 0; + return ((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0); + } + return 0; +} + +static int +_XkbFilterRedirectKey( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ +DeviceEvent ev; +int x,y; +XkbStateRec old; +unsigned mods,mask; +xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device); +ProcessInputProc backupproc; + + /* never actually used uninitialised, but gcc isn't smart enough + * to work that out. */ + memset(&old, 0, sizeof(old)); + + if ((filter->keycode!=0)&&(filter->keycode!=keycode)) + return 1; + + GetSpritePosition(xkbi->device, &x,&y); + ev.header = ET_Internal; + ev.length = sizeof(DeviceEvent); + ev.time = GetTimeInMillis(); + ev.root_x = x; + ev.root_y = y; + + if (filter->keycode==0) { /* initial press */ + if ((pAction->redirect.new_key<xkbi->desc->min_key_code)|| + (pAction->redirect.new_key>xkbi->desc->max_key_code)) { + return 1; + } + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 0; + filter->priv = 0; + filter->filter = _XkbFilterRedirectKey; + filter->upAction = *pAction; + + ev.type = ET_KeyPress; + ev.detail.key = pAction->redirect.new_key; + + mask= XkbSARedirectVModsMask(&pAction->redirect); + mods= XkbSARedirectVMods(&pAction->redirect); + if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask); + if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods); + mask|= pAction->redirect.mods_mask; + mods|= pAction->redirect.mods; + + if ( mask || mods ) { + old= xkbi->state; + xkbi->state.base_mods&= ~mask; + xkbi->state.base_mods|= (mods&mask); + xkbi->state.latched_mods&= ~mask; + xkbi->state.latched_mods|= (mods&mask); + xkbi->state.locked_mods&= ~mask; + xkbi->state.locked_mods|= (mods&mask); + XkbComputeDerivedState(xkbi); + } + + UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc); + xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device); + COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, + backupproc,xkbUnwrapProc); + + if ( mask || mods ) + xkbi->state= old; + } + else if (filter->keycode==keycode) { + + ev.type = ET_KeyRelease; + ev.detail.key = filter->upAction.redirect.new_key; + + mask= XkbSARedirectVModsMask(&filter->upAction.redirect); + mods= XkbSARedirectVMods(&filter->upAction.redirect); + if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask); + if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods); + mask|= filter->upAction.redirect.mods_mask; + mods|= filter->upAction.redirect.mods; + + if ( mask || mods ) { + old= xkbi->state; + xkbi->state.base_mods&= ~mask; + xkbi->state.base_mods|= (mods&mask); + xkbi->state.latched_mods&= ~mask; + xkbi->state.latched_mods|= (mods&mask); + xkbi->state.locked_mods&= ~mask; + xkbi->state.locked_mods|= (mods&mask); + XkbComputeDerivedState(xkbi); + } + + UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc); + xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device); + COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, + backupproc,xkbUnwrapProc); + + if ( mask || mods ) + xkbi->state= old; + + filter->keycode= 0; + filter->active= 0; + } + return 0; +} + +static int +_XkbFilterSwitchScreen( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ + DeviceIntPtr dev = xkbi->device; + if (dev == inputInfo.keyboard) + return 0; + + if (filter->keycode==0) { /* initial press */ + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 0; + filter->filter = _XkbFilterSwitchScreen; + AccessXCancelRepeatKey(xkbi, keycode); + XkbDDXSwitchScreen(dev,keycode,pAction); + return 0; + } + else if (filter->keycode==keycode) { + filter->active= 0; + return 0; + } + return 1; +} + +static int +_XkbFilterXF86Private( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ + DeviceIntPtr dev = xkbi->device; + if (dev == inputInfo.keyboard) + return 0; + + if (filter->keycode==0) { /* initial press */ + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 0; + filter->filter = _XkbFilterXF86Private; + XkbDDXPrivate(dev,keycode,pAction); + return 0; + } + else if (filter->keycode==keycode) { + filter->active= 0; + return 0; + } + return 1; +} + + +static int +_XkbFilterDeviceBtn( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ +DeviceIntPtr dev; +int button; + + if (xkbi->device == inputInfo.keyboard) + return 0; + + if (filter->keycode==0) { /* initial press */ + _XkbLookupButtonDevice(&dev, pAction->devbtn.device, serverClient, + DixUnknownAccess, &button); + if (!dev || !dev->public.on) + return 1; + + button= pAction->devbtn.button; + if ((button<1)||(button>dev->button->numButtons)) + return 1; + + filter->keycode = keycode; + filter->active = 1; + filter->filterOthers = 0; + filter->priv=0; + filter->filter = _XkbFilterDeviceBtn; + filter->upAction= *pAction; + switch (pAction->type) { + case XkbSA_LockDeviceBtn: + if ((pAction->devbtn.flags&XkbSA_LockNoLock)|| + BitIsOn(dev->button->down, button)) + return 0; + XkbFakeDeviceButton(dev,TRUE,button); + filter->upAction.type= XkbSA_NoAction; + break; + case XkbSA_DeviceBtn: + if (pAction->devbtn.count>0) { + int nClicks,i; + nClicks= pAction->btn.count; + for (i=0;i<nClicks;i++) { + XkbFakeDeviceButton(dev,TRUE,button); + XkbFakeDeviceButton(dev,FALSE,button); + } + filter->upAction.type= XkbSA_NoAction; + } + else XkbFakeDeviceButton(dev,TRUE,button); + break; + } + } + else if (filter->keycode==keycode) { + int button; + + filter->active= 0; + _XkbLookupButtonDevice(&dev, filter->upAction.devbtn.device, + serverClient, DixUnknownAccess, &button); + if (!dev || !dev->public.on) + return 1; + + button= filter->upAction.btn.button; + switch (filter->upAction.type) { + case XkbSA_LockDeviceBtn: + if ((filter->upAction.devbtn.flags&XkbSA_LockNoUnlock)|| + !BitIsOn(dev->button->down, button)) + return 0; + XkbFakeDeviceButton(dev,FALSE,button); + break; + case XkbSA_DeviceBtn: + XkbFakeDeviceButton(dev,FALSE,button); + break; + } + filter->active = 0; + } + return 0; +} + +static XkbFilterPtr +_XkbNextFreeFilter( + XkbSrvInfoPtr xkbi +) +{ +register int i; + + if (xkbi->szFilters==0) { + xkbi->szFilters = 4; + xkbi->filters = calloc(xkbi->szFilters, sizeof(XkbFilterRec)); + /* 6/21/93 (ef) -- XXX! deal with allocation failure */ + } + for (i=0;i<xkbi->szFilters;i++) { + if (!xkbi->filters[i].active) { + xkbi->filters[i].keycode = 0; + return &xkbi->filters[i]; + } + } + xkbi->szFilters*=2; + xkbi->filters= realloc(xkbi->filters, + xkbi->szFilters * sizeof(XkbFilterRec)); + /* 6/21/93 (ef) -- XXX! deal with allocation failure */ + bzero(&xkbi->filters[xkbi->szFilters/2], + (xkbi->szFilters/2)*sizeof(XkbFilterRec)); + return &xkbi->filters[xkbi->szFilters/2]; +} + +static int +_XkbApplyFilters(XkbSrvInfoPtr xkbi,unsigned kc,XkbAction *pAction) +{ +register int i,send; + + send= 1; + for (i=0;i<xkbi->szFilters;i++) { + if ((xkbi->filters[i].active)&&(xkbi->filters[i].filter)) + send= ((*xkbi->filters[i].filter)(xkbi,&xkbi->filters[i],kc,pAction) + && send); + } + return send; +} + +void +XkbHandleActions(DeviceIntPtr dev, DeviceIntPtr kbd, DeviceEvent* event) +{ +int key,bit,i; +XkbSrvInfoPtr xkbi; +KeyClassPtr keyc; +int changed,sendEvent; +Bool genStateNotify; +XkbAction act; +XkbFilterPtr filter; +Bool keyEvent; +Bool pressEvent; +ProcessInputProc backupproc; + +xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev); + + keyc= kbd->key; + xkbi= keyc->xkbInfo; + key= event->detail.key; + /* The state may change, so if we're not in the middle of sending a state + * notify, prepare for it */ + if ((xkbi->flags&_XkbStateNotifyInProgress)==0) { + xkbi->prev_state = xkbi->state; + xkbi->flags|= _XkbStateNotifyInProgress; + genStateNotify= TRUE; + } + else genStateNotify= FALSE; + + xkbi->clearMods = xkbi->setMods = 0; + xkbi->groupChange = 0; + + sendEvent = 1; + keyEvent= ((event->type == ET_KeyPress) || (event->type == ET_KeyRelease)); + pressEvent= ((event->type == ET_KeyPress)|| (event->type == ET_ButtonPress)); + + if (pressEvent) { + if (keyEvent) + act = XkbGetKeyAction(xkbi,&xkbi->state,key); + else { + act = XkbGetButtonAction(kbd,dev,key); + key|= BTN_ACT_FLAG; + } + sendEvent = _XkbApplyFilters(xkbi,key,&act); + if (sendEvent) { + switch (act.type) { + case XkbSA_SetMods: + case XkbSA_SetGroup: + filter = _XkbNextFreeFilter(xkbi); + sendEvent = _XkbFilterSetState(xkbi,filter,key,&act); + break; + case XkbSA_LatchMods: + case XkbSA_LatchGroup: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterLatchState(xkbi,filter,key,&act); + break; + case XkbSA_LockMods: + case XkbSA_LockGroup: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterLockState(xkbi,filter,key,&act); + break; + case XkbSA_ISOLock: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterISOLock(xkbi,filter,key,&act); + break; + case XkbSA_MovePtr: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterPointerMove(xkbi,filter,key,&act); + break; + case XkbSA_PtrBtn: + case XkbSA_LockPtrBtn: + case XkbSA_SetPtrDflt: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterPointerBtn(xkbi,filter,key,&act); + break; + case XkbSA_Terminate: + sendEvent= XkbDDXTerminateServer(dev,key,&act); + break; + case XkbSA_SwitchScreen: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterSwitchScreen(xkbi,filter,key,&act); + break; + case XkbSA_SetControls: + case XkbSA_LockControls: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterControls(xkbi,filter,key,&act); + break; + case XkbSA_ActionMessage: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterActionMessage(xkbi,filter,key,&act); + break; + case XkbSA_RedirectKey: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterRedirectKey(xkbi,filter,key,&act); + break; + case XkbSA_DeviceBtn: + case XkbSA_LockDeviceBtn: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterDeviceBtn(xkbi,filter,key,&act); + break; + case XkbSA_XFree86Private: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterXF86Private(xkbi,filter,key,&act); + break; + } + } + } + else { + if (!keyEvent) + key|= BTN_ACT_FLAG; + sendEvent = _XkbApplyFilters(xkbi,key,NULL); + } + + if (xkbi->groupChange!=0) + xkbi->state.base_group+= xkbi->groupChange; + if (xkbi->setMods) { + for (i=0,bit=1; xkbi->setMods; i++,bit<<=1 ) { + if (xkbi->setMods&bit) { + keyc->modifierKeyCount[i]++; + xkbi->state.base_mods|= bit; + xkbi->setMods&= ~bit; + } + } + } + if (xkbi->clearMods) { + for (i=0,bit=1; xkbi->clearMods; i++,bit<<=1 ) { + if (xkbi->clearMods&bit) { + keyc->modifierKeyCount[i]--; + if (keyc->modifierKeyCount[i]<=0) { + xkbi->state.base_mods&= ~bit; + keyc->modifierKeyCount[i] = 0; + } + xkbi->clearMods&= ~bit; + } + } + } + + if (sendEvent) { + DeviceIntPtr tmpdev; + if (keyEvent) + tmpdev = dev; + else + tmpdev = GetPairedDevice(dev); + + UNWRAP_PROCESS_INPUT_PROC(tmpdev,xkbPrivPtr, backupproc); + dev->public.processInputProc((InternalEvent*)event, tmpdev); + COND_WRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr, + backupproc,xkbUnwrapProc); + } + else if (keyEvent) { + FixKeyState(event, dev); + } + + XkbComputeDerivedState(xkbi); + changed = XkbStateChangedFlags(&xkbi->prev_state,&xkbi->state); + if (genStateNotify) { + if (changed) { + xkbStateNotify sn; + sn.keycode= key; + sn.eventType= event->type; + sn.requestMajor = sn.requestMinor = 0; + sn.changed= changed; + XkbSendStateNotify(dev,&sn); + } + xkbi->flags&= ~_XkbStateNotifyInProgress; + } + changed= XkbIndicatorsToUpdate(dev,changed,FALSE); + if (changed) { + XkbEventCauseRec cause; + XkbSetCauseKey(&cause, key, event->type); + XkbUpdateIndicators(dev,changed,FALSE,NULL,&cause); + } + return; +} + +int +XkbLatchModifiers(DeviceIntPtr pXDev,CARD8 mask,CARD8 latches) +{ +XkbSrvInfoPtr xkbi; +XkbFilterPtr filter; +XkbAction act; +unsigned clear; + + if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) { + xkbi = pXDev->key->xkbInfo; + clear= (mask&(~latches)); + xkbi->state.latched_mods&= ~clear; + /* Clear any pending latch to locks. + */ + act.type = XkbSA_NoAction; + _XkbApplyFilters(xkbi,SYNTHETIC_KEYCODE,&act); + act.type = XkbSA_LatchMods; + act.mods.flags = 0; + act.mods.mask = mask&latches; + filter = _XkbNextFreeFilter(xkbi); + _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act); + _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL); + return Success; + } + return BadValue; +} + +int +XkbLatchGroup(DeviceIntPtr pXDev,int group) +{ +XkbSrvInfoPtr xkbi; +XkbFilterPtr filter; +XkbAction act; + + if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) { + xkbi = pXDev->key->xkbInfo; + act.type = XkbSA_LatchGroup; + act.group.flags = 0; + XkbSASetGroup(&act.group,group); + filter = _XkbNextFreeFilter(xkbi); + _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act); + _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL); + return Success; + } + return BadValue; +} + +/***====================================================================***/ + +void +XkbClearAllLatchesAndLocks( DeviceIntPtr dev, + XkbSrvInfoPtr xkbi, + Bool genEv, + XkbEventCausePtr cause) +{ +XkbStateRec os; +xkbStateNotify sn; + + sn.changed= 0; + os= xkbi->state; + if (os.latched_mods) { /* clear all latches */ + XkbLatchModifiers(dev,~0,0); + sn.changed|= XkbModifierLatchMask; + } + if (os.latched_group) { + XkbLatchGroup(dev,0); + sn.changed|= XkbGroupLatchMask; + } + if (os.locked_mods) { + xkbi->state.locked_mods= 0; + sn.changed|= XkbModifierLockMask; + } + if (os.locked_group) { + xkbi->state.locked_group= 0; + sn.changed|= XkbGroupLockMask; + } + if ( genEv && sn.changed) { + CARD32 changed; + + XkbComputeDerivedState(xkbi); + sn.keycode= cause->kc; + sn.eventType= cause->event; + sn.requestMajor= cause->mjr; + sn.requestMinor= cause->mnr; + sn.changed= XkbStateChangedFlags(&os,&xkbi->state); + XkbSendStateNotify(dev,&sn); + changed= XkbIndicatorsToUpdate(dev,sn.changed,FALSE); + if (changed) { + XkbUpdateIndicators(dev,changed,TRUE,NULL,cause); + } + } + return; +} + +static void +XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y) +{ + EventListPtr events; + int nevents, i; + DeviceIntPtr ptr; + int gpe_flags = 0; + + if (!dev->u.master) + ptr = dev; + else + ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER)); + + if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY) + gpe_flags = POINTER_ABSOLUTE; + else + gpe_flags = POINTER_RELATIVE; + + events = InitEventList(GetMaximumEventsNum()); + OsBlockSignals(); + nevents = GetPointerEvents(events, ptr, + MotionNotify, 0, + gpe_flags, 0, 2, (int[]){x, y}); + OsReleaseSignals(); + + for (i = 0; i < nevents; i++) + mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL); + + FreeEventList(events, GetMaximumEventsNum()); +} + +static void +XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button) +{ + EventListPtr events; + int nevents, i; + DeviceIntPtr ptr; + + /* If dev is a slave device, and the SD is attached, do nothing. If we'd + * post through the attached master pointer we'd get duplicate events. + * + * if dev is a master keyboard, post through the XTEST device + * + * if dev is a floating slave, post through the device itself. + */ + + if (IsMaster(dev)) + ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER)); + else if (!dev->u.master) + ptr = dev; + else + return; + + events = InitEventList(GetMaximumEventsNum()); + OsBlockSignals(); + nevents = GetPointerEvents(events, ptr, + press ? ButtonPress : ButtonRelease, button, + 0 /* flags */, 0 /* first */, + 0 /* num_val */, NULL); + OsReleaseSignals(); + + + for (i = 0; i < nevents; i++) + mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL); + + FreeEventList(events, GetMaximumEventsNum()); +} diff --git a/xorg-server/xkb/xkbEvents.c b/xorg-server/xkb/xkbEvents.c index 9755f9846..659c8c89d 100644 --- a/xorg-server/xkb/xkbEvents.c +++ b/xorg-server/xkb/xkbEvents.c @@ -1,1112 +1,1112 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#endif - -#include <stdio.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/keysym.h> -#include <X11/extensions/XI.h> -#include <X11/extensions/XIproto.h> -#include "inputstr.h" -#include "exevents.h" -#include "exglobals.h" -#include "windowstr.h" -#include "exevents.h" -#include <xkbsrv.h> -#include "xkb.h" - -/***====================================================================***/ - -/* - * This function sends out two kinds of notification: - * - Core mapping notify events sent to clients for whom kbd is the - * current core ('picked') keyboard _and_ have not explicitly - * selected for XKB mapping notify events; - * - Xi mapping events, sent unconditionally to all clients who have - * explicitly selected for them (including those who have explicitly - * selected for XKB mapping notify events!). - */ -static void -XkbSendLegacyMapNotify(DeviceIntPtr kbd, CARD16 xkb_event, CARD16 changed, - int first_key, int num_keys) -{ - int i; - int keymap_changed = 0; - int modmap_changed = 0; - xEvent core_mn; - deviceMappingNotify xi_mn; - CARD32 time = GetTimeInMillis(); - - if (xkb_event == XkbNewKeyboardNotify) { - if (changed & XkbNKN_KeycodesMask) { - keymap_changed = 1; - modmap_changed = 1; - } - } - else if (xkb_event == XkbMapNotify) { - if (changed & XkbKeySymsMask) - keymap_changed = 1; - if (changed & XkbModifierMapMask) - modmap_changed = 1; - } - if (!keymap_changed && !modmap_changed) - return; - - core_mn.u.u.type = MappingNotify; - xi_mn.type = DeviceMappingNotify; - xi_mn.deviceid = kbd->id; - xi_mn.time = time; - - /* 0 is serverClient. */ - for (i = 1; i < currentMaxClients; i++) { - if (!clients[i] || clients[i]->clientState != ClientStateRunning) - continue; - - /* Ignore clients which will have already received this. - * Inconsistent with themselves, but consistent with previous - * behaviour.*/ - if (xkb_event == XkbMapNotify && (clients[i]->mapNotifyMask & changed)) - continue; - if (xkb_event == XkbNewKeyboardNotify && - (clients[i]->xkbClientFlags & _XkbClientInitialized)) - continue; - - /* Don't send core events to clients who don't know about us. */ - if (!XIShouldNotify(clients[i], kbd)) - continue; - - core_mn.u.u.sequenceNumber = clients[i]->sequence; - if (keymap_changed) { - core_mn.u.mappingNotify.request = MappingKeyboard; - - /* Clip the keycode range to what the client knows about, so it - * doesn't freak out. */ - if (first_key >= clients[i]->minKC) - core_mn.u.mappingNotify.firstKeyCode = first_key; - else - core_mn.u.mappingNotify.firstKeyCode = clients[i]->minKC; - if (first_key + num_keys - 1 <= clients[i]->maxKC) - core_mn.u.mappingNotify.count = num_keys; - else - core_mn.u.mappingNotify.count = clients[i]->maxKC - - clients[i]->minKC + 1; - - WriteEventsToClient(clients[i], 1, &core_mn); - } - if (modmap_changed) { - core_mn.u.mappingNotify.request = MappingModifier; - core_mn.u.mappingNotify.firstKeyCode = 0; - core_mn.u.mappingNotify.count = 0; - WriteEventsToClient(clients[i], 1, &core_mn); - } - } - - /* Hmm, maybe we can accidentally generate Xi events for core devices - * here? Clients might be upset, but that seems better than the - * alternative of stale keymaps. -ds */ - if (keymap_changed) { - xi_mn.request = MappingKeyboard; - xi_mn.firstKeyCode = first_key; - xi_mn.count = num_keys; - SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn, - 1); - } - if (modmap_changed) { - xi_mn.request = MappingModifier; - xi_mn.firstKeyCode = 0; - xi_mn.count = 0; - SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn, - 1); - } -} - -/***====================================================================***/ - -void -XkbSendNewKeyboardNotify(DeviceIntPtr kbd,xkbNewKeyboardNotify *pNKN) -{ - int i; - Time time = GetTimeInMillis(); - CARD16 changed = pNKN->changed; - - pNKN->type = XkbEventCode + XkbEventBase; - pNKN->xkbType = XkbNewKeyboardNotify; - - for (i=1; i<currentMaxClients; i++) { - if (!clients[i] || clients[i]->clientState != ClientStateRunning) - continue; - - if (!(clients[i]->newKeyboardNotifyMask & changed)) - continue; - - if (!XIShouldNotify(clients[i], kbd)) - continue; - - pNKN->sequenceNumber = clients[i]->sequence; - pNKN->time = time; - pNKN->changed = changed; - if (clients[i]->swapped) { - int n; - swaps(&pNKN->sequenceNumber,n); - swapl(&pNKN->time,n); - swaps(&pNKN->changed,n); - } - WriteToClient(clients[i], sizeof(xEvent), pNKN); - - if (changed & XkbNKN_KeycodesMask) { - clients[i]->minKC = pNKN->minKeyCode; - clients[i]->maxKC = pNKN->maxKeyCode; - } - } - - XkbSendLegacyMapNotify(kbd, XkbNewKeyboardNotify, changed, pNKN->minKeyCode, - pNKN->maxKeyCode - pNKN->minKeyCode + 1); - - return; -} - -/***====================================================================***/ - -void -XkbSendStateNotify(DeviceIntPtr kbd,xkbStateNotify *pSN) -{ -XkbSrvInfoPtr xkbi; -XkbStatePtr state; -XkbInterestPtr interest; -Time time; -register CARD16 changed,bState; - - interest = kbd->xkb_interest; - if (!interest || !kbd->key || !kbd->key->xkbInfo) - return; - xkbi = kbd->key->xkbInfo; - state= &xkbi->state; - - pSN->type = XkbEventCode + XkbEventBase; - pSN->xkbType = XkbStateNotify; - pSN->deviceID = kbd->id; - pSN->time = time = GetTimeInMillis(); - pSN->mods = state->mods; - pSN->baseMods = state->base_mods; - pSN->latchedMods = state->latched_mods; - pSN->lockedMods = state->locked_mods; - pSN->group = state->group; - pSN->baseGroup = state->base_group; - pSN->latchedGroup = state->latched_group; - pSN->lockedGroup = state->locked_group; - pSN->compatState = state->compat_state; - pSN->grabMods = state->grab_mods; - pSN->compatGrabMods = state->compat_grab_mods; - pSN->lookupMods = state->lookup_mods; - pSN->compatLookupMods = state->compat_lookup_mods; - pSN->ptrBtnState = state->ptr_buttons; - changed = pSN->changed; - bState= pSN->ptrBtnState; - - while (interest) { - if ((!interest->client->clientGone) && - (interest->client->requestVector != InitialVector) && - (interest->client->xkbClientFlags&_XkbClientInitialized) && - (interest->stateNotifyMask&changed) && - XIShouldNotify(interest->client,kbd)) { - pSN->sequenceNumber = interest->client->sequence; - pSN->time = time; - pSN->changed = changed; - pSN->ptrBtnState = bState; - if ( interest->client->swapped ) { - register int n; - swaps(&pSN->sequenceNumber,n); - swapl(&pSN->time,n); - swaps(&pSN->changed,n); - swaps(&pSN->ptrBtnState,n); - } - WriteToClient(interest->client, sizeof(xEvent), (char *)pSN); - } - interest= interest->next; - } - return; -} - -/***====================================================================***/ - -/* - * This function sends out XKB mapping notify events to clients which - * have explicitly selected for them. Core and Xi events are handled by - * XkbSendLegacyMapNotify. */ -void -XkbSendMapNotify(DeviceIntPtr kbd, xkbMapNotify *pMN) -{ - int i; - CARD32 time = GetTimeInMillis(); - CARD16 changed = pMN->changed; - XkbSrvInfoPtr xkbi = kbd->key->xkbInfo; - - pMN->minKeyCode = xkbi->desc->min_key_code; - pMN->maxKeyCode = xkbi->desc->max_key_code; - pMN->type = XkbEventCode + XkbEventBase; - pMN->xkbType = XkbMapNotify; - pMN->deviceID = kbd->id; - - /* 0 is serverClient. */ - for (i = 1; i < currentMaxClients; i++) { - if (!clients[i] || clients[i]->clientState != ClientStateRunning) - continue; - - if (!(clients[i]->mapNotifyMask & changed)) - continue; - - if (!XIShouldNotify(clients[i], kbd)) - continue; - - pMN->time = time; - pMN->sequenceNumber = clients[i]->sequence; - pMN->changed = changed; - - if (clients[i]->swapped) { - int n; - swaps(&pMN->sequenceNumber, n); - swapl(&pMN->time, n); - swaps(&pMN->changed, n); - } - WriteToClient(clients[i], sizeof(xEvent), pMN); - } - - XkbSendLegacyMapNotify(kbd, XkbMapNotify, changed, pMN->firstKeySym, - pMN->nKeySyms); -} - -int -XkbComputeControlsNotify( DeviceIntPtr kbd, - XkbControlsPtr old, - XkbControlsPtr new, - xkbControlsNotify * pCN, - Bool forceCtrlProc) -{ -int i; -CARD32 changedControls; - - changedControls= 0; - - if (!kbd || !kbd->kbdfeed) - return 0; - - if (old->enabled_ctrls!=new->enabled_ctrls) - changedControls|= XkbControlsEnabledMask; - if ((old->repeat_delay!=new->repeat_delay)|| - (old->repeat_interval!=new->repeat_interval)) - changedControls|= XkbRepeatKeysMask; - for (i = 0; i < XkbPerKeyBitArraySize; i++) - if (old->per_key_repeat[i] != new->per_key_repeat[i]) - changedControls|= XkbPerKeyRepeatMask; - if (old->slow_keys_delay!=new->slow_keys_delay) - changedControls|= XkbSlowKeysMask; - if (old->debounce_delay!=new->debounce_delay) - changedControls|= XkbBounceKeysMask; - if ((old->mk_delay!=new->mk_delay)|| - (old->mk_interval!=new->mk_interval)|| - (old->mk_dflt_btn!=new->mk_dflt_btn)) - changedControls|= XkbMouseKeysMask; - if ((old->mk_time_to_max!=new->mk_time_to_max)|| - (old->mk_curve!=new->mk_curve)|| - (old->mk_max_speed!=new->mk_max_speed)) - changedControls|= XkbMouseKeysAccelMask; - if (old->ax_options!=new->ax_options) - changedControls|= XkbAccessXKeysMask; - if ((old->ax_options^new->ax_options) & XkbAX_SKOptionsMask) - changedControls|= XkbStickyKeysMask; - if ((old->ax_options^new->ax_options) & XkbAX_FBOptionsMask) - changedControls|= XkbAccessXFeedbackMask; - if ((old->ax_timeout!=new->ax_timeout)|| - (old->axt_ctrls_mask!=new->axt_ctrls_mask)|| - (old->axt_ctrls_values!=new->axt_ctrls_values)|| - (old->axt_opts_mask!=new->axt_opts_mask)|| - (old->axt_opts_values!= new->axt_opts_values)) { - changedControls|= XkbAccessXTimeoutMask; - } - if ((old->internal.mask!=new->internal.mask)|| - (old->internal.real_mods!=new->internal.real_mods)|| - (old->internal.vmods!=new->internal.vmods)) - changedControls|= XkbInternalModsMask; - if ((old->ignore_lock.mask!=new->ignore_lock.mask)|| - (old->ignore_lock.real_mods!=new->ignore_lock.real_mods)|| - (old->ignore_lock.vmods!=new->ignore_lock.vmods)) - changedControls|= XkbIgnoreLockModsMask; - - if (new->enabled_ctrls&XkbRepeatKeysMask) - kbd->kbdfeed->ctrl.autoRepeat=TRUE; - else kbd->kbdfeed->ctrl.autoRepeat=FALSE; - - if (kbd->kbdfeed && kbd->kbdfeed->CtrlProc && - (changedControls || forceCtrlProc)) - (*kbd->kbdfeed->CtrlProc)(kbd, &kbd->kbdfeed->ctrl); - - if ((!changedControls)&&(old->num_groups==new->num_groups)) - return 0; - - if (!kbd->xkb_interest) - return 0; - - pCN->changedControls = changedControls; - pCN->enabledControls = new->enabled_ctrls; - pCN->enabledControlChanges = (new->enabled_ctrls^old->enabled_ctrls); - pCN->numGroups = new->num_groups; - - return 1; -} - -void -XkbSendControlsNotify(DeviceIntPtr kbd,xkbControlsNotify *pCN) -{ -int initialized; -CARD32 changedControls, enabledControls, enabledChanges = 0; -XkbSrvInfoPtr xkbi; -XkbInterestPtr interest; -Time time = 0; - - interest = kbd->xkb_interest; - if (!interest || !kbd->key || !kbd->key->xkbInfo) - return; - xkbi = kbd->key->xkbInfo; - - initialized = 0; - enabledControls = xkbi->desc->ctrls->enabled_ctrls; - changedControls = pCN->changedControls; - pCN->numGroups= xkbi->desc->ctrls->num_groups; - while (interest) { - if ((!interest->client->clientGone) && - (interest->client->requestVector != InitialVector) && - (interest->client->xkbClientFlags&_XkbClientInitialized) && - (interest->ctrlsNotifyMask&changedControls) && - XIShouldNotify(interest->client, kbd)) { - if (!initialized) { - pCN->type = XkbEventCode + XkbEventBase; - pCN->xkbType = XkbControlsNotify; - pCN->deviceID = kbd->id; - pCN->time = time = GetTimeInMillis(); - enabledChanges = pCN->enabledControlChanges; - initialized= 1; - } - pCN->changedControls = changedControls; - pCN->enabledControls = enabledControls; - pCN->enabledControlChanges = enabledChanges; - pCN->sequenceNumber = interest->client->sequence; - pCN->time = time; - if ( interest->client->swapped ) { - register int n; - swaps(&pCN->sequenceNumber,n); - swapl(&pCN->changedControls,n); - swapl(&pCN->enabledControls,n); - swapl(&pCN->enabledControlChanges,n); - swapl(&pCN->time,n); - } - WriteToClient(interest->client, sizeof(xEvent), (char *)pCN); - } - interest= interest->next; - } - return; -} - -static void -XkbSendIndicatorNotify(DeviceIntPtr kbd,int xkbType,xkbIndicatorNotify *pEv) -{ -int initialized; -XkbInterestPtr interest; -Time time = 0; -CARD32 state,changed; - - interest = kbd->xkb_interest; - if (!interest) - return; - - initialized = 0; - state = pEv->state; - changed = pEv->changed; - while (interest) { - if ((!interest->client->clientGone) && - (interest->client->requestVector != InitialVector) && - (interest->client->xkbClientFlags&_XkbClientInitialized) && - XIShouldNotify(interest->client, kbd) && - (((xkbType==XkbIndicatorStateNotify)&& - (interest->iStateNotifyMask&changed))|| - ((xkbType==XkbIndicatorMapNotify)&& - (interest->iMapNotifyMask&changed)))) { - if (!initialized) { - pEv->type = XkbEventCode + XkbEventBase; - pEv->xkbType = xkbType; - pEv->deviceID = kbd->id; - pEv->time = time = GetTimeInMillis(); - initialized= 1; - } - pEv->sequenceNumber = interest->client->sequence; - pEv->time = time; - pEv->changed = changed; - pEv->state = state; - if ( interest->client->swapped ) { - register int n; - swaps(&pEv->sequenceNumber,n); - swapl(&pEv->time,n); - swapl(&pEv->changed,n); - swapl(&pEv->state,n); - } - WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); - } - interest= interest->next; - } - return; -} - - -void -XkbHandleBell( BOOL force, - BOOL eventOnly, - DeviceIntPtr kbd, - CARD8 percent, - pointer pCtrl, - CARD8 class, - Atom name, - WindowPtr pWin, - ClientPtr pClient) -{ -xkbBellNotify bn; -int initialized; -XkbSrvInfoPtr xkbi; -XkbInterestPtr interest; -CARD8 id; -CARD16 pitch,duration; -Time time = 0; -XID winID = 0; - - if (!kbd->key || !kbd->key->xkbInfo) - return; - - xkbi = kbd->key->xkbInfo; - - if ((force||(xkbi->desc->ctrls->enabled_ctrls&XkbAudibleBellMask))&& - (!eventOnly)) { - if (kbd->kbdfeed->BellProc) - (*kbd->kbdfeed->BellProc)(percent,kbd,(pointer)pCtrl,class); - } - interest = kbd->xkb_interest; - if ((!interest)||(force)) - return; - - if ((class==0)||(class==KbdFeedbackClass)) { - KeybdCtrl *pKeyCtrl= (KeybdCtrl *)pCtrl; - id= pKeyCtrl->id; - pitch= pKeyCtrl->bell_pitch; - duration= pKeyCtrl->bell_duration; - } - else if (class==BellFeedbackClass) { - BellCtrl *pBellCtrl= (BellCtrl *)pCtrl; - id= pBellCtrl->id; - pitch= pBellCtrl->pitch; - duration= pBellCtrl->duration; - } - else return; - - initialized = 0; - while (interest) { - if ((!interest->client->clientGone) && - (interest->client->requestVector != InitialVector) && - (interest->client->xkbClientFlags&_XkbClientInitialized) && - (interest->bellNotifyMask) && - XIShouldNotify(interest->client,kbd)) { - if (!initialized) { - time = GetTimeInMillis(); - bn.type = XkbEventCode + XkbEventBase; - bn.xkbType = XkbBellNotify; - bn.deviceID = kbd->id; - bn.bellClass = class; - bn.bellID = id; - bn.percent= percent; - bn.eventOnly = (eventOnly!=0); - winID= (pWin?pWin->drawable.id:None); - initialized= 1; - } - bn.sequenceNumber = interest->client->sequence; - bn.time = time; - bn.pitch = pitch; - bn.duration = duration; - bn.name = name; - bn.window= winID; - if ( interest->client->swapped ) { - register int n; - swaps(&bn.sequenceNumber,n); - swapl(&bn.time,n); - swaps(&bn.pitch,n); - swaps(&bn.duration,n); - swapl(&bn.name,n); - swapl(&bn.window,n); - } - WriteToClient(interest->client, sizeof(xEvent), (char *)&bn); - } - interest= interest->next; - } - return; -} - -void -XkbSendAccessXNotify(DeviceIntPtr kbd,xkbAccessXNotify *pEv) -{ -int initialized; -XkbInterestPtr interest; -Time time = 0; -CARD16 sk_delay,db_delay; - - interest = kbd->xkb_interest; - if (!interest) - return; - - initialized = 0; - sk_delay= pEv->slowKeysDelay; - db_delay= pEv->debounceDelay; - while (interest) { - if ((!interest->client->clientGone) && - (interest->client->requestVector != InitialVector) && - (interest->client->xkbClientFlags&_XkbClientInitialized) && - (interest->accessXNotifyMask&(1<<pEv->detail)) && - XIShouldNotify(interest->client, kbd)) { - if (!initialized) { - pEv->type = XkbEventCode + XkbEventBase; - pEv->xkbType = XkbAccessXNotify; - pEv->deviceID = kbd->id; - pEv->time = time = GetTimeInMillis(); - initialized= 1; - } - pEv->sequenceNumber = interest->client->sequence; - pEv->time = time; - pEv->slowKeysDelay = sk_delay; - pEv->debounceDelay = db_delay; - if ( interest->client->swapped ) { - register int n; - swaps(&pEv->sequenceNumber,n); - swapl(&pEv->time,n); - swaps(&pEv->slowKeysDelay,n); - swaps(&pEv->debounceDelay,n); - } - WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); - } - interest= interest->next; - } - return; -} - -void -XkbSendNamesNotify(DeviceIntPtr kbd,xkbNamesNotify *pEv) -{ -int initialized; -XkbInterestPtr interest; -Time time = 0; -CARD16 changed,changedVirtualMods; -CARD32 changedIndicators; - - interest = kbd->xkb_interest; - if (!interest) - return; - - initialized = 0; - changed= pEv->changed; - changedIndicators= pEv->changedIndicators; - changedVirtualMods= pEv->changedVirtualMods; - while (interest) { - if ((!interest->client->clientGone) && - (interest->client->requestVector != InitialVector) && - (interest->client->xkbClientFlags&_XkbClientInitialized) && - (interest->namesNotifyMask&pEv->changed) && - XIShouldNotify(interest->client, kbd)) { - if (!initialized) { - pEv->type = XkbEventCode + XkbEventBase; - pEv->xkbType = XkbNamesNotify; - pEv->deviceID = kbd->id; - pEv->time = time = GetTimeInMillis(); - initialized= 1; - } - pEv->sequenceNumber = interest->client->sequence; - pEv->time = time; - pEv->changed = changed; - pEv->changedIndicators = changedIndicators; - pEv->changedVirtualMods= changedVirtualMods; - if ( interest->client->swapped ) { - register int n; - swaps(&pEv->sequenceNumber,n); - swapl(&pEv->time,n); - swaps(&pEv->changed,n); - swapl(&pEv->changedIndicators,n); - swaps(&pEv->changedVirtualMods,n); - } - WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); - } - interest= interest->next; - } - return; -} - -void -XkbSendCompatMapNotify(DeviceIntPtr kbd,xkbCompatMapNotify *pEv) -{ -int initialized; -XkbInterestPtr interest; -Time time = 0; -CARD16 firstSI = 0, nSI = 0, nTotalSI = 0; - - interest = kbd->xkb_interest; - if (!interest) - return; - - initialized = 0; - while (interest) { - if ((!interest->client->clientGone) && - (interest->client->requestVector != InitialVector) && - (interest->client->xkbClientFlags&_XkbClientInitialized) && - (interest->compatNotifyMask) && - XIShouldNotify(interest->client, kbd)) { - if (!initialized) { - pEv->type = XkbEventCode + XkbEventBase; - pEv->xkbType = XkbCompatMapNotify; - pEv->deviceID = kbd->id; - pEv->time = time = GetTimeInMillis(); - firstSI= pEv->firstSI; - nSI= pEv->nSI; - nTotalSI= pEv->nTotalSI; - initialized= 1; - } - pEv->sequenceNumber = interest->client->sequence; - pEv->time = time; - pEv->firstSI = firstSI; - pEv->nSI = nSI; - pEv->nTotalSI = nTotalSI; - if ( interest->client->swapped ) { - register int n; - swaps(&pEv->sequenceNumber,n); - swapl(&pEv->time,n); - swaps(&pEv->firstSI,n); - swaps(&pEv->nSI,n); - swaps(&pEv->nTotalSI,n); - } - WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); - } - interest= interest->next; - } - return; -} - -void -XkbSendActionMessage(DeviceIntPtr kbd,xkbActionMessage *pEv) -{ -int initialized; -XkbSrvInfoPtr xkbi; -XkbInterestPtr interest; -Time time = 0; - - interest = kbd->xkb_interest; - if (!interest || !kbd->key || !kbd->key->xkbInfo) - return; - - xkbi = kbd->key->xkbInfo; - - initialized = 0; - pEv->mods= xkbi->state.mods; - pEv->group= xkbi->state.group; - while (interest) { - if ((!interest->client->clientGone) && - (interest->client->requestVector != InitialVector) && - (interest->client->xkbClientFlags&_XkbClientInitialized) && - (interest->actionMessageMask) && - XIShouldNotify(interest->client, kbd)) { - if (!initialized) { - pEv->type = XkbEventCode + XkbEventBase; - pEv->xkbType = XkbActionMessage; - pEv->deviceID = kbd->id; - pEv->sequenceNumber = interest->client->sequence; - pEv->time = time = GetTimeInMillis(); - initialized= 1; - } - pEv->sequenceNumber = interest->client->sequence; - pEv->time = time; - if ( interest->client->swapped ) { - register int n; - swaps(&pEv->sequenceNumber,n); - swapl(&pEv->time,n); - } - WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); - } - interest= interest->next; - } - return; -} - -void -XkbSendExtensionDeviceNotify( DeviceIntPtr dev, - ClientPtr client, - xkbExtensionDeviceNotify * pEv) -{ -int initialized; -XkbInterestPtr interest; -Time time = 0; -CARD32 defined, state; -CARD16 reason; - - interest = dev->xkb_interest; - if (!interest) - return; - - initialized = 0; - reason= pEv->reason; - defined= pEv->ledsDefined; - state= pEv->ledState; - while (interest) { - if ((!interest->client->clientGone) && - (interest->client->requestVector != InitialVector) && - (interest->client->xkbClientFlags&_XkbClientInitialized) && - (interest->extDevNotifyMask&reason) && - XIShouldNotify(interest->client, dev)) { - if (!initialized) { - pEv->type = XkbEventCode + XkbEventBase; - pEv->xkbType = XkbExtensionDeviceNotify; - pEv->deviceID = dev->id; - pEv->sequenceNumber = interest->client->sequence; - pEv->time = time = GetTimeInMillis(); - initialized= 1; - } - else { - pEv->sequenceNumber = interest->client->sequence; - pEv->time = time; - pEv->ledsDefined= defined; - pEv->ledState= state; - pEv->reason= reason; - pEv->supported= XkbXI_AllFeaturesMask; - } - if ( interest->client->swapped ) { - register int n; - swaps(&pEv->sequenceNumber,n); - swapl(&pEv->time,n); - swapl(&pEv->ledsDefined,n); - swapl(&pEv->ledState,n); - swaps(&pEv->reason,n); - swaps(&pEv->supported,n); - } - WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); - } - interest= interest->next; - } - return; -} - -void -XkbSendNotification( DeviceIntPtr kbd, - XkbChangesPtr pChanges, - XkbEventCausePtr cause) -{ -XkbSrvLedInfoPtr sli; - - sli= NULL; - if (pChanges->state_changes) { - xkbStateNotify sn; - sn.changed= pChanges->state_changes; - sn.keycode= cause->kc; - sn.eventType= cause->event; - sn.requestMajor= cause->mjr; - sn.requestMinor= cause->mnr; - XkbSendStateNotify(kbd,&sn); - } - if (pChanges->map.changed) { - xkbMapNotify mn; - memset(&mn, 0, sizeof(xkbMapNotify)); - mn.changed= pChanges->map.changed; - mn.firstType= pChanges->map.first_type; - mn.nTypes= pChanges->map.num_types; - mn.firstKeySym= pChanges->map.first_key_sym; - mn.nKeySyms= pChanges->map.num_key_syms; - mn.firstKeyAct= pChanges->map.first_key_act; - mn.nKeyActs= pChanges->map.num_key_acts; - mn.firstKeyBehavior= pChanges->map.first_key_behavior; - mn.nKeyBehaviors= pChanges->map.num_key_behaviors; - mn.virtualMods= pChanges->map.vmods; - mn.firstKeyExplicit= pChanges->map.first_key_explicit; - mn.nKeyExplicit= pChanges->map.num_key_explicit; - mn.firstModMapKey= pChanges->map.first_modmap_key; - mn.nModMapKeys= pChanges->map.num_modmap_keys; - mn.firstVModMapKey= pChanges->map.first_vmodmap_key; - mn.nVModMapKeys= pChanges->map.num_vmodmap_keys; - XkbSendMapNotify(kbd,&mn); - } - if ((pChanges->ctrls.changed_ctrls)|| - (pChanges->ctrls.enabled_ctrls_changes)) { - xkbControlsNotify cn; - memset(&cn, 0, sizeof(xkbControlsNotify)); - cn.changedControls= pChanges->ctrls.changed_ctrls; - cn.enabledControlChanges= pChanges->ctrls.enabled_ctrls_changes; - cn.keycode= cause->kc; - cn.eventType= cause->event; - cn.requestMajor= cause->mjr; - cn.requestMinor= cause->mnr; - XkbSendControlsNotify(kbd,&cn); - } - if (pChanges->indicators.map_changes) { - xkbIndicatorNotify in; - if (sli==NULL) - sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); - memset(&in, 0, sizeof(xkbIndicatorNotify)); - in.state= sli->effectiveState; - in.changed= pChanges->indicators.map_changes; - XkbSendIndicatorNotify(kbd,XkbIndicatorMapNotify,&in); - } - if (pChanges->indicators.state_changes) { - xkbIndicatorNotify in; - if (sli==NULL) - sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); - memset(&in, 0, sizeof(xkbIndicatorNotify)); - in.state= sli->effectiveState; - in.changed= pChanges->indicators.state_changes; - XkbSendIndicatorNotify(kbd,XkbIndicatorStateNotify,&in); - } - if (pChanges->names.changed) { - xkbNamesNotify nn; - memset(&nn, 0, sizeof(xkbNamesNotify)); - nn.changed= pChanges->names.changed; - nn.firstType= pChanges->names.first_type; - nn.nTypes= pChanges->names.num_types; - nn.firstLevelName= pChanges->names.first_lvl; - nn.nLevelNames= pChanges->names.num_lvls; - nn.nRadioGroups= pChanges->names.num_rg; - nn.changedVirtualMods= pChanges->names.changed_vmods; - nn.changedIndicators= pChanges->names.changed_indicators; - XkbSendNamesNotify(kbd,&nn); - } - if ((pChanges->compat.changed_groups)||(pChanges->compat.num_si>0)) { - xkbCompatMapNotify cmn; - memset(&cmn, 0, sizeof(xkbCompatMapNotify)); - cmn.changedGroups= pChanges->compat.changed_groups; - cmn.firstSI= pChanges->compat.first_si; - cmn.nSI= pChanges->compat.num_si; - cmn.nTotalSI= kbd->key->xkbInfo->desc->compat->num_si; - XkbSendCompatMapNotify(kbd,&cmn); - } - return; -} - -/***====================================================================***/ - -void -XkbFilterEvents(ClientPtr client,int nEvents,xEvent *xE) -{ - DeviceIntPtr dev = NULL; - XkbSrvInfoPtr xkbi; - CARD8 type = xE[0].u.u.type; - - if (xE->u.u.type & EXTENSION_EVENT_BASE) - dev = XIGetDevice(xE); - - if (!dev) - dev = PickKeyboard(client); - - if (!dev->key) - return; - - xkbi = dev->key->xkbInfo; - - if (client->xkbClientFlags & _XkbClientInitialized) { - if ((xkbDebugFlags&0x10)&& - (type == KeyPress || type == KeyRelease || - type == DeviceKeyPress || type == DeviceKeyRelease)) - DebugF("[xkb] XkbFilterWriteEvents (XKB client): state 0x%04x\n", - xE[0].u.keyButtonPointer.state); - - if (dev->deviceGrab.grab != NullGrab && dev->deviceGrab.fromPassiveGrab && - (type == KeyPress || type == KeyRelease || - type == DeviceKeyPress || type == DeviceKeyRelease)) { - unsigned int state, flags; - - flags = client->xkbClientFlags; - state = xkbi->state.compat_grab_mods; - if (flags & XkbPCF_GrabsUseXKBStateMask) { - int group; - if (flags & XkbPCF_LookupStateWhenGrabbed) { - group = xkbi->state.group; - state = xkbi->state.lookup_mods; - } - else { - state = xkbi->state.grab_mods; - group = xkbi->state.base_group + xkbi->state.latched_group; - if (group < 0 || group >= xkbi->desc->ctrls->num_groups) - group = XkbAdjustGroup(group, xkbi->desc->ctrls); - } - state = XkbBuildCoreState(state, group); - } - else if (flags & XkbPCF_LookupStateWhenGrabbed) { - state = xkbi->state.compat_lookup_mods; - } - xE[0].u.keyButtonPointer.state = state; - } - } - else { - if ((xkbDebugFlags & 0x4) && - (xE[0].u.u.type == KeyPress || xE[0].u.u.type==KeyRelease || - xE[0].u.u.type == DeviceKeyPress || - xE[0].u.u.type == DeviceKeyRelease)) { - DebugF("[xkb] XKbFilterWriteEvents (non-XKB):\n"); - DebugF("[xkb] event= 0x%04x\n",xE[0].u.keyButtonPointer.state); - DebugF("[xkb] lookup= 0x%02x, grab= 0x%02x\n", - xkbi->state.lookup_mods, xkbi->state.grab_mods); - DebugF("[xkb] compat lookup= 0x%02x, grab= 0x%02x\n", - xkbi->state.compat_lookup_mods, xkbi->state.compat_grab_mods); - } - if (type >= KeyPress && type <= MotionNotify) { - CARD16 old, new; - - old = xE[0].u.keyButtonPointer.state & ~0x1f00; - new = xE[0].u.keyButtonPointer.state & 0x1F00; - - if (old == XkbStateFieldFromRec(&xkbi->state)) - new |= xkbi->state.compat_lookup_mods; - else - new |= xkbi->state.compat_grab_mods; - xE[0].u.keyButtonPointer.state = new; - } - else if (type == EnterNotify || type == LeaveNotify) { - xE[0].u.enterLeave.state &= 0x1F00; - xE[0].u.enterLeave.state |= xkbi->state.compat_grab_mods; - } - else if (type >= DeviceKeyPress && type <= DeviceMotionNotify) { - CARD16 old, new; - deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer*) &xE[0]; - - old = kbp->state & ~0x1F00; - new = kbp->state & 0x1F00; - if (old == XkbStateFieldFromRec(&xkbi->state)) - new |= xkbi->state.compat_lookup_mods; - else - new |= xkbi->state.compat_grab_mods; - kbp->state = new; - } - } -} - -/***====================================================================***/ - -XkbInterestPtr -XkbFindClientResource(DevicePtr inDev,ClientPtr client) -{ -DeviceIntPtr dev = (DeviceIntPtr)inDev; -XkbInterestPtr interest; - - if ( dev->xkb_interest ) { - interest = dev->xkb_interest; - while (interest){ - if (interest->client==client) { - return interest; - } - interest = interest->next; - } - } - return NULL; -} - -XkbInterestPtr -XkbAddClientResource(DevicePtr inDev,ClientPtr client,XID id) -{ -DeviceIntPtr dev = (DeviceIntPtr)inDev; -XkbInterestPtr interest; - - interest = dev->xkb_interest; - while (interest) { - if (interest->client==client) - return ((interest->resource==id)?interest:NULL); - interest = interest->next; - } - interest = xcalloc(1, sizeof(XkbInterestRec)); - if (interest) { - interest->dev = dev; - interest->client = client; - interest->resource = id; - interest->stateNotifyMask= 0; - interest->ctrlsNotifyMask= 0; - interest->namesNotifyMask= 0; - interest->compatNotifyMask= 0; - interest->bellNotifyMask= FALSE; - interest->accessXNotifyMask= 0; - interest->iStateNotifyMask= 0; - interest->iMapNotifyMask= 0; - interest->altSymsNotifyMask= 0; - interest->next = dev->xkb_interest; - dev->xkb_interest= interest; - return interest; - } - return NULL; -} - -int -XkbRemoveResourceClient(DevicePtr inDev,XID id) -{ -XkbSrvInfoPtr xkbi; -DeviceIntPtr dev = (DeviceIntPtr)inDev; -XkbInterestPtr interest; -Bool found; -unsigned long autoCtrls,autoValues; -ClientPtr client = NULL; - - found= FALSE; - - if (!dev->key || !dev->key->xkbInfo) - return found; - - autoCtrls= autoValues= 0; - if ( dev->xkb_interest ) { - interest = dev->xkb_interest; - if (interest && (interest->resource==id)){ - dev->xkb_interest = interest->next; - autoCtrls= interest->autoCtrls; - autoValues= interest->autoCtrlValues; - client= interest->client; - xfree(interest); - found= TRUE; - } - while ((!found)&&(interest->next)) { - if (interest->next->resource==id) { - XkbInterestPtr victim = interest->next; - interest->next = victim->next; - autoCtrls= victim->autoCtrls; - autoValues= victim->autoCtrlValues; - client= victim->client; - xfree(victim); - found= TRUE; - } - interest = interest->next; - } - } - if (found && autoCtrls && dev->key && dev->key->xkbInfo ) { - XkbEventCauseRec cause; - - xkbi= dev->key->xkbInfo; - XkbSetCauseXkbReq(&cause,X_kbPerClientFlags,client); - XkbEnableDisableControls(xkbi,autoCtrls,autoValues,NULL,&cause); - } - return found; -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#endif + +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/keysym.h> +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "inputstr.h" +#include "exevents.h" +#include "exglobals.h" +#include "windowstr.h" +#include "exevents.h" +#include <xkbsrv.h> +#include "xkb.h" + +/***====================================================================***/ + +/* + * This function sends out two kinds of notification: + * - Core mapping notify events sent to clients for whom kbd is the + * current core ('picked') keyboard _and_ have not explicitly + * selected for XKB mapping notify events; + * - Xi mapping events, sent unconditionally to all clients who have + * explicitly selected for them (including those who have explicitly + * selected for XKB mapping notify events!). + */ +static void +XkbSendLegacyMapNotify(DeviceIntPtr kbd, CARD16 xkb_event, CARD16 changed, + int first_key, int num_keys) +{ + int i; + int keymap_changed = 0; + int modmap_changed = 0; + xEvent core_mn; + deviceMappingNotify xi_mn; + CARD32 time = GetTimeInMillis(); + + if (xkb_event == XkbNewKeyboardNotify) { + if (changed & XkbNKN_KeycodesMask) { + keymap_changed = 1; + modmap_changed = 1; + } + } + else if (xkb_event == XkbMapNotify) { + if (changed & XkbKeySymsMask) + keymap_changed = 1; + if (changed & XkbModifierMapMask) + modmap_changed = 1; + } + if (!keymap_changed && !modmap_changed) + return; + + core_mn.u.u.type = MappingNotify; + xi_mn.type = DeviceMappingNotify; + xi_mn.deviceid = kbd->id; + xi_mn.time = time; + + /* 0 is serverClient. */ + for (i = 1; i < currentMaxClients; i++) { + if (!clients[i] || clients[i]->clientState != ClientStateRunning) + continue; + + /* Ignore clients which will have already received this. + * Inconsistent with themselves, but consistent with previous + * behaviour.*/ + if (xkb_event == XkbMapNotify && (clients[i]->mapNotifyMask & changed)) + continue; + if (xkb_event == XkbNewKeyboardNotify && + (clients[i]->xkbClientFlags & _XkbClientInitialized)) + continue; + + /* Don't send core events to clients who don't know about us. */ + if (!XIShouldNotify(clients[i], kbd)) + continue; + + core_mn.u.u.sequenceNumber = clients[i]->sequence; + if (keymap_changed) { + core_mn.u.mappingNotify.request = MappingKeyboard; + + /* Clip the keycode range to what the client knows about, so it + * doesn't freak out. */ + if (first_key >= clients[i]->minKC) + core_mn.u.mappingNotify.firstKeyCode = first_key; + else + core_mn.u.mappingNotify.firstKeyCode = clients[i]->minKC; + if (first_key + num_keys - 1 <= clients[i]->maxKC) + core_mn.u.mappingNotify.count = num_keys; + else + core_mn.u.mappingNotify.count = clients[i]->maxKC - + clients[i]->minKC + 1; + + WriteEventsToClient(clients[i], 1, &core_mn); + } + if (modmap_changed) { + core_mn.u.mappingNotify.request = MappingModifier; + core_mn.u.mappingNotify.firstKeyCode = 0; + core_mn.u.mappingNotify.count = 0; + WriteEventsToClient(clients[i], 1, &core_mn); + } + } + + /* Hmm, maybe we can accidentally generate Xi events for core devices + * here? Clients might be upset, but that seems better than the + * alternative of stale keymaps. -ds */ + if (keymap_changed) { + xi_mn.request = MappingKeyboard; + xi_mn.firstKeyCode = first_key; + xi_mn.count = num_keys; + SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn, + 1); + } + if (modmap_changed) { + xi_mn.request = MappingModifier; + xi_mn.firstKeyCode = 0; + xi_mn.count = 0; + SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn, + 1); + } +} + +/***====================================================================***/ + +void +XkbSendNewKeyboardNotify(DeviceIntPtr kbd,xkbNewKeyboardNotify *pNKN) +{ + int i; + Time time = GetTimeInMillis(); + CARD16 changed = pNKN->changed; + + pNKN->type = XkbEventCode + XkbEventBase; + pNKN->xkbType = XkbNewKeyboardNotify; + + for (i=1; i<currentMaxClients; i++) { + if (!clients[i] || clients[i]->clientState != ClientStateRunning) + continue; + + if (!(clients[i]->newKeyboardNotifyMask & changed)) + continue; + + if (!XIShouldNotify(clients[i], kbd)) + continue; + + pNKN->sequenceNumber = clients[i]->sequence; + pNKN->time = time; + pNKN->changed = changed; + if (clients[i]->swapped) { + int n; + swaps(&pNKN->sequenceNumber,n); + swapl(&pNKN->time,n); + swaps(&pNKN->changed,n); + } + WriteToClient(clients[i], sizeof(xEvent), pNKN); + + if (changed & XkbNKN_KeycodesMask) { + clients[i]->minKC = pNKN->minKeyCode; + clients[i]->maxKC = pNKN->maxKeyCode; + } + } + + XkbSendLegacyMapNotify(kbd, XkbNewKeyboardNotify, changed, pNKN->minKeyCode, + pNKN->maxKeyCode - pNKN->minKeyCode + 1); + + return; +} + +/***====================================================================***/ + +void +XkbSendStateNotify(DeviceIntPtr kbd,xkbStateNotify *pSN) +{ +XkbSrvInfoPtr xkbi; +XkbStatePtr state; +XkbInterestPtr interest; +Time time; +register CARD16 changed,bState; + + interest = kbd->xkb_interest; + if (!interest || !kbd->key || !kbd->key->xkbInfo) + return; + xkbi = kbd->key->xkbInfo; + state= &xkbi->state; + + pSN->type = XkbEventCode + XkbEventBase; + pSN->xkbType = XkbStateNotify; + pSN->deviceID = kbd->id; + pSN->time = time = GetTimeInMillis(); + pSN->mods = state->mods; + pSN->baseMods = state->base_mods; + pSN->latchedMods = state->latched_mods; + pSN->lockedMods = state->locked_mods; + pSN->group = state->group; + pSN->baseGroup = state->base_group; + pSN->latchedGroup = state->latched_group; + pSN->lockedGroup = state->locked_group; + pSN->compatState = state->compat_state; + pSN->grabMods = state->grab_mods; + pSN->compatGrabMods = state->compat_grab_mods; + pSN->lookupMods = state->lookup_mods; + pSN->compatLookupMods = state->compat_lookup_mods; + pSN->ptrBtnState = state->ptr_buttons; + changed = pSN->changed; + bState= pSN->ptrBtnState; + + while (interest) { + if ((!interest->client->clientGone) && + (interest->client->requestVector != InitialVector) && + (interest->client->xkbClientFlags&_XkbClientInitialized) && + (interest->stateNotifyMask&changed) && + XIShouldNotify(interest->client,kbd)) { + pSN->sequenceNumber = interest->client->sequence; + pSN->time = time; + pSN->changed = changed; + pSN->ptrBtnState = bState; + if ( interest->client->swapped ) { + register int n; + swaps(&pSN->sequenceNumber,n); + swapl(&pSN->time,n); + swaps(&pSN->changed,n); + swaps(&pSN->ptrBtnState,n); + } + WriteToClient(interest->client, sizeof(xEvent), (char *)pSN); + } + interest= interest->next; + } + return; +} + +/***====================================================================***/ + +/* + * This function sends out XKB mapping notify events to clients which + * have explicitly selected for them. Core and Xi events are handled by + * XkbSendLegacyMapNotify. */ +void +XkbSendMapNotify(DeviceIntPtr kbd, xkbMapNotify *pMN) +{ + int i; + CARD32 time = GetTimeInMillis(); + CARD16 changed = pMN->changed; + XkbSrvInfoPtr xkbi = kbd->key->xkbInfo; + + pMN->minKeyCode = xkbi->desc->min_key_code; + pMN->maxKeyCode = xkbi->desc->max_key_code; + pMN->type = XkbEventCode + XkbEventBase; + pMN->xkbType = XkbMapNotify; + pMN->deviceID = kbd->id; + + /* 0 is serverClient. */ + for (i = 1; i < currentMaxClients; i++) { + if (!clients[i] || clients[i]->clientState != ClientStateRunning) + continue; + + if (!(clients[i]->mapNotifyMask & changed)) + continue; + + if (!XIShouldNotify(clients[i], kbd)) + continue; + + pMN->time = time; + pMN->sequenceNumber = clients[i]->sequence; + pMN->changed = changed; + + if (clients[i]->swapped) { + int n; + swaps(&pMN->sequenceNumber, n); + swapl(&pMN->time, n); + swaps(&pMN->changed, n); + } + WriteToClient(clients[i], sizeof(xEvent), pMN); + } + + XkbSendLegacyMapNotify(kbd, XkbMapNotify, changed, pMN->firstKeySym, + pMN->nKeySyms); +} + +int +XkbComputeControlsNotify( DeviceIntPtr kbd, + XkbControlsPtr old, + XkbControlsPtr new, + xkbControlsNotify * pCN, + Bool forceCtrlProc) +{ +int i; +CARD32 changedControls; + + changedControls= 0; + + if (!kbd || !kbd->kbdfeed) + return 0; + + if (old->enabled_ctrls!=new->enabled_ctrls) + changedControls|= XkbControlsEnabledMask; + if ((old->repeat_delay!=new->repeat_delay)|| + (old->repeat_interval!=new->repeat_interval)) + changedControls|= XkbRepeatKeysMask; + for (i = 0; i < XkbPerKeyBitArraySize; i++) + if (old->per_key_repeat[i] != new->per_key_repeat[i]) + changedControls|= XkbPerKeyRepeatMask; + if (old->slow_keys_delay!=new->slow_keys_delay) + changedControls|= XkbSlowKeysMask; + if (old->debounce_delay!=new->debounce_delay) + changedControls|= XkbBounceKeysMask; + if ((old->mk_delay!=new->mk_delay)|| + (old->mk_interval!=new->mk_interval)|| + (old->mk_dflt_btn!=new->mk_dflt_btn)) + changedControls|= XkbMouseKeysMask; + if ((old->mk_time_to_max!=new->mk_time_to_max)|| + (old->mk_curve!=new->mk_curve)|| + (old->mk_max_speed!=new->mk_max_speed)) + changedControls|= XkbMouseKeysAccelMask; + if (old->ax_options!=new->ax_options) + changedControls|= XkbAccessXKeysMask; + if ((old->ax_options^new->ax_options) & XkbAX_SKOptionsMask) + changedControls|= XkbStickyKeysMask; + if ((old->ax_options^new->ax_options) & XkbAX_FBOptionsMask) + changedControls|= XkbAccessXFeedbackMask; + if ((old->ax_timeout!=new->ax_timeout)|| + (old->axt_ctrls_mask!=new->axt_ctrls_mask)|| + (old->axt_ctrls_values!=new->axt_ctrls_values)|| + (old->axt_opts_mask!=new->axt_opts_mask)|| + (old->axt_opts_values!= new->axt_opts_values)) { + changedControls|= XkbAccessXTimeoutMask; + } + if ((old->internal.mask!=new->internal.mask)|| + (old->internal.real_mods!=new->internal.real_mods)|| + (old->internal.vmods!=new->internal.vmods)) + changedControls|= XkbInternalModsMask; + if ((old->ignore_lock.mask!=new->ignore_lock.mask)|| + (old->ignore_lock.real_mods!=new->ignore_lock.real_mods)|| + (old->ignore_lock.vmods!=new->ignore_lock.vmods)) + changedControls|= XkbIgnoreLockModsMask; + + if (new->enabled_ctrls&XkbRepeatKeysMask) + kbd->kbdfeed->ctrl.autoRepeat=TRUE; + else kbd->kbdfeed->ctrl.autoRepeat=FALSE; + + if (kbd->kbdfeed && kbd->kbdfeed->CtrlProc && + (changedControls || forceCtrlProc)) + (*kbd->kbdfeed->CtrlProc)(kbd, &kbd->kbdfeed->ctrl); + + if ((!changedControls)&&(old->num_groups==new->num_groups)) + return 0; + + if (!kbd->xkb_interest) + return 0; + + pCN->changedControls = changedControls; + pCN->enabledControls = new->enabled_ctrls; + pCN->enabledControlChanges = (new->enabled_ctrls^old->enabled_ctrls); + pCN->numGroups = new->num_groups; + + return 1; +} + +void +XkbSendControlsNotify(DeviceIntPtr kbd,xkbControlsNotify *pCN) +{ +int initialized; +CARD32 changedControls, enabledControls, enabledChanges = 0; +XkbSrvInfoPtr xkbi; +XkbInterestPtr interest; +Time time = 0; + + interest = kbd->xkb_interest; + if (!interest || !kbd->key || !kbd->key->xkbInfo) + return; + xkbi = kbd->key->xkbInfo; + + initialized = 0; + enabledControls = xkbi->desc->ctrls->enabled_ctrls; + changedControls = pCN->changedControls; + pCN->numGroups= xkbi->desc->ctrls->num_groups; + while (interest) { + if ((!interest->client->clientGone) && + (interest->client->requestVector != InitialVector) && + (interest->client->xkbClientFlags&_XkbClientInitialized) && + (interest->ctrlsNotifyMask&changedControls) && + XIShouldNotify(interest->client, kbd)) { + if (!initialized) { + pCN->type = XkbEventCode + XkbEventBase; + pCN->xkbType = XkbControlsNotify; + pCN->deviceID = kbd->id; + pCN->time = time = GetTimeInMillis(); + enabledChanges = pCN->enabledControlChanges; + initialized= 1; + } + pCN->changedControls = changedControls; + pCN->enabledControls = enabledControls; + pCN->enabledControlChanges = enabledChanges; + pCN->sequenceNumber = interest->client->sequence; + pCN->time = time; + if ( interest->client->swapped ) { + register int n; + swaps(&pCN->sequenceNumber,n); + swapl(&pCN->changedControls,n); + swapl(&pCN->enabledControls,n); + swapl(&pCN->enabledControlChanges,n); + swapl(&pCN->time,n); + } + WriteToClient(interest->client, sizeof(xEvent), (char *)pCN); + } + interest= interest->next; + } + return; +} + +static void +XkbSendIndicatorNotify(DeviceIntPtr kbd,int xkbType,xkbIndicatorNotify *pEv) +{ +int initialized; +XkbInterestPtr interest; +Time time = 0; +CARD32 state,changed; + + interest = kbd->xkb_interest; + if (!interest) + return; + + initialized = 0; + state = pEv->state; + changed = pEv->changed; + while (interest) { + if ((!interest->client->clientGone) && + (interest->client->requestVector != InitialVector) && + (interest->client->xkbClientFlags&_XkbClientInitialized) && + XIShouldNotify(interest->client, kbd) && + (((xkbType==XkbIndicatorStateNotify)&& + (interest->iStateNotifyMask&changed))|| + ((xkbType==XkbIndicatorMapNotify)&& + (interest->iMapNotifyMask&changed)))) { + if (!initialized) { + pEv->type = XkbEventCode + XkbEventBase; + pEv->xkbType = xkbType; + pEv->deviceID = kbd->id; + pEv->time = time = GetTimeInMillis(); + initialized= 1; + } + pEv->sequenceNumber = interest->client->sequence; + pEv->time = time; + pEv->changed = changed; + pEv->state = state; + if ( interest->client->swapped ) { + register int n; + swaps(&pEv->sequenceNumber,n); + swapl(&pEv->time,n); + swapl(&pEv->changed,n); + swapl(&pEv->state,n); + } + WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); + } + interest= interest->next; + } + return; +} + + +void +XkbHandleBell( BOOL force, + BOOL eventOnly, + DeviceIntPtr kbd, + CARD8 percent, + pointer pCtrl, + CARD8 class, + Atom name, + WindowPtr pWin, + ClientPtr pClient) +{ +xkbBellNotify bn; +int initialized; +XkbSrvInfoPtr xkbi; +XkbInterestPtr interest; +CARD8 id; +CARD16 pitch,duration; +Time time = 0; +XID winID = 0; + + if (!kbd->key || !kbd->key->xkbInfo) + return; + + xkbi = kbd->key->xkbInfo; + + if ((force||(xkbi->desc->ctrls->enabled_ctrls&XkbAudibleBellMask))&& + (!eventOnly)) { + if (kbd->kbdfeed->BellProc) + (*kbd->kbdfeed->BellProc)(percent,kbd,(pointer)pCtrl,class); + } + interest = kbd->xkb_interest; + if ((!interest)||(force)) + return; + + if ((class==0)||(class==KbdFeedbackClass)) { + KeybdCtrl *pKeyCtrl= (KeybdCtrl *)pCtrl; + id= pKeyCtrl->id; + pitch= pKeyCtrl->bell_pitch; + duration= pKeyCtrl->bell_duration; + } + else if (class==BellFeedbackClass) { + BellCtrl *pBellCtrl= (BellCtrl *)pCtrl; + id= pBellCtrl->id; + pitch= pBellCtrl->pitch; + duration= pBellCtrl->duration; + } + else return; + + initialized = 0; + while (interest) { + if ((!interest->client->clientGone) && + (interest->client->requestVector != InitialVector) && + (interest->client->xkbClientFlags&_XkbClientInitialized) && + (interest->bellNotifyMask) && + XIShouldNotify(interest->client,kbd)) { + if (!initialized) { + time = GetTimeInMillis(); + bn.type = XkbEventCode + XkbEventBase; + bn.xkbType = XkbBellNotify; + bn.deviceID = kbd->id; + bn.bellClass = class; + bn.bellID = id; + bn.percent= percent; + bn.eventOnly = (eventOnly!=0); + winID= (pWin?pWin->drawable.id:None); + initialized= 1; + } + bn.sequenceNumber = interest->client->sequence; + bn.time = time; + bn.pitch = pitch; + bn.duration = duration; + bn.name = name; + bn.window= winID; + if ( interest->client->swapped ) { + register int n; + swaps(&bn.sequenceNumber,n); + swapl(&bn.time,n); + swaps(&bn.pitch,n); + swaps(&bn.duration,n); + swapl(&bn.name,n); + swapl(&bn.window,n); + } + WriteToClient(interest->client, sizeof(xEvent), (char *)&bn); + } + interest= interest->next; + } + return; +} + +void +XkbSendAccessXNotify(DeviceIntPtr kbd,xkbAccessXNotify *pEv) +{ +int initialized; +XkbInterestPtr interest; +Time time = 0; +CARD16 sk_delay,db_delay; + + interest = kbd->xkb_interest; + if (!interest) + return; + + initialized = 0; + sk_delay= pEv->slowKeysDelay; + db_delay= pEv->debounceDelay; + while (interest) { + if ((!interest->client->clientGone) && + (interest->client->requestVector != InitialVector) && + (interest->client->xkbClientFlags&_XkbClientInitialized) && + (interest->accessXNotifyMask&(1<<pEv->detail)) && + XIShouldNotify(interest->client, kbd)) { + if (!initialized) { + pEv->type = XkbEventCode + XkbEventBase; + pEv->xkbType = XkbAccessXNotify; + pEv->deviceID = kbd->id; + pEv->time = time = GetTimeInMillis(); + initialized= 1; + } + pEv->sequenceNumber = interest->client->sequence; + pEv->time = time; + pEv->slowKeysDelay = sk_delay; + pEv->debounceDelay = db_delay; + if ( interest->client->swapped ) { + register int n; + swaps(&pEv->sequenceNumber,n); + swapl(&pEv->time,n); + swaps(&pEv->slowKeysDelay,n); + swaps(&pEv->debounceDelay,n); + } + WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); + } + interest= interest->next; + } + return; +} + +void +XkbSendNamesNotify(DeviceIntPtr kbd,xkbNamesNotify *pEv) +{ +int initialized; +XkbInterestPtr interest; +Time time = 0; +CARD16 changed,changedVirtualMods; +CARD32 changedIndicators; + + interest = kbd->xkb_interest; + if (!interest) + return; + + initialized = 0; + changed= pEv->changed; + changedIndicators= pEv->changedIndicators; + changedVirtualMods= pEv->changedVirtualMods; + while (interest) { + if ((!interest->client->clientGone) && + (interest->client->requestVector != InitialVector) && + (interest->client->xkbClientFlags&_XkbClientInitialized) && + (interest->namesNotifyMask&pEv->changed) && + XIShouldNotify(interest->client, kbd)) { + if (!initialized) { + pEv->type = XkbEventCode + XkbEventBase; + pEv->xkbType = XkbNamesNotify; + pEv->deviceID = kbd->id; + pEv->time = time = GetTimeInMillis(); + initialized= 1; + } + pEv->sequenceNumber = interest->client->sequence; + pEv->time = time; + pEv->changed = changed; + pEv->changedIndicators = changedIndicators; + pEv->changedVirtualMods= changedVirtualMods; + if ( interest->client->swapped ) { + register int n; + swaps(&pEv->sequenceNumber,n); + swapl(&pEv->time,n); + swaps(&pEv->changed,n); + swapl(&pEv->changedIndicators,n); + swaps(&pEv->changedVirtualMods,n); + } + WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); + } + interest= interest->next; + } + return; +} + +void +XkbSendCompatMapNotify(DeviceIntPtr kbd,xkbCompatMapNotify *pEv) +{ +int initialized; +XkbInterestPtr interest; +Time time = 0; +CARD16 firstSI = 0, nSI = 0, nTotalSI = 0; + + interest = kbd->xkb_interest; + if (!interest) + return; + + initialized = 0; + while (interest) { + if ((!interest->client->clientGone) && + (interest->client->requestVector != InitialVector) && + (interest->client->xkbClientFlags&_XkbClientInitialized) && + (interest->compatNotifyMask) && + XIShouldNotify(interest->client, kbd)) { + if (!initialized) { + pEv->type = XkbEventCode + XkbEventBase; + pEv->xkbType = XkbCompatMapNotify; + pEv->deviceID = kbd->id; + pEv->time = time = GetTimeInMillis(); + firstSI= pEv->firstSI; + nSI= pEv->nSI; + nTotalSI= pEv->nTotalSI; + initialized= 1; + } + pEv->sequenceNumber = interest->client->sequence; + pEv->time = time; + pEv->firstSI = firstSI; + pEv->nSI = nSI; + pEv->nTotalSI = nTotalSI; + if ( interest->client->swapped ) { + register int n; + swaps(&pEv->sequenceNumber,n); + swapl(&pEv->time,n); + swaps(&pEv->firstSI,n); + swaps(&pEv->nSI,n); + swaps(&pEv->nTotalSI,n); + } + WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); + } + interest= interest->next; + } + return; +} + +void +XkbSendActionMessage(DeviceIntPtr kbd,xkbActionMessage *pEv) +{ +int initialized; +XkbSrvInfoPtr xkbi; +XkbInterestPtr interest; +Time time = 0; + + interest = kbd->xkb_interest; + if (!interest || !kbd->key || !kbd->key->xkbInfo) + return; + + xkbi = kbd->key->xkbInfo; + + initialized = 0; + pEv->mods= xkbi->state.mods; + pEv->group= xkbi->state.group; + while (interest) { + if ((!interest->client->clientGone) && + (interest->client->requestVector != InitialVector) && + (interest->client->xkbClientFlags&_XkbClientInitialized) && + (interest->actionMessageMask) && + XIShouldNotify(interest->client, kbd)) { + if (!initialized) { + pEv->type = XkbEventCode + XkbEventBase; + pEv->xkbType = XkbActionMessage; + pEv->deviceID = kbd->id; + pEv->sequenceNumber = interest->client->sequence; + pEv->time = time = GetTimeInMillis(); + initialized= 1; + } + pEv->sequenceNumber = interest->client->sequence; + pEv->time = time; + if ( interest->client->swapped ) { + register int n; + swaps(&pEv->sequenceNumber,n); + swapl(&pEv->time,n); + } + WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); + } + interest= interest->next; + } + return; +} + +void +XkbSendExtensionDeviceNotify( DeviceIntPtr dev, + ClientPtr client, + xkbExtensionDeviceNotify * pEv) +{ +int initialized; +XkbInterestPtr interest; +Time time = 0; +CARD32 defined, state; +CARD16 reason; + + interest = dev->xkb_interest; + if (!interest) + return; + + initialized = 0; + reason= pEv->reason; + defined= pEv->ledsDefined; + state= pEv->ledState; + while (interest) { + if ((!interest->client->clientGone) && + (interest->client->requestVector != InitialVector) && + (interest->client->xkbClientFlags&_XkbClientInitialized) && + (interest->extDevNotifyMask&reason) && + XIShouldNotify(interest->client, dev)) { + if (!initialized) { + pEv->type = XkbEventCode + XkbEventBase; + pEv->xkbType = XkbExtensionDeviceNotify; + pEv->deviceID = dev->id; + pEv->sequenceNumber = interest->client->sequence; + pEv->time = time = GetTimeInMillis(); + initialized= 1; + } + else { + pEv->sequenceNumber = interest->client->sequence; + pEv->time = time; + pEv->ledsDefined= defined; + pEv->ledState= state; + pEv->reason= reason; + pEv->supported= XkbXI_AllFeaturesMask; + } + if ( interest->client->swapped ) { + register int n; + swaps(&pEv->sequenceNumber,n); + swapl(&pEv->time,n); + swapl(&pEv->ledsDefined,n); + swapl(&pEv->ledState,n); + swaps(&pEv->reason,n); + swaps(&pEv->supported,n); + } + WriteToClient(interest->client, sizeof(xEvent), (char *)pEv); + } + interest= interest->next; + } + return; +} + +void +XkbSendNotification( DeviceIntPtr kbd, + XkbChangesPtr pChanges, + XkbEventCausePtr cause) +{ +XkbSrvLedInfoPtr sli; + + sli= NULL; + if (pChanges->state_changes) { + xkbStateNotify sn; + sn.changed= pChanges->state_changes; + sn.keycode= cause->kc; + sn.eventType= cause->event; + sn.requestMajor= cause->mjr; + sn.requestMinor= cause->mnr; + XkbSendStateNotify(kbd,&sn); + } + if (pChanges->map.changed) { + xkbMapNotify mn; + memset(&mn, 0, sizeof(xkbMapNotify)); + mn.changed= pChanges->map.changed; + mn.firstType= pChanges->map.first_type; + mn.nTypes= pChanges->map.num_types; + mn.firstKeySym= pChanges->map.first_key_sym; + mn.nKeySyms= pChanges->map.num_key_syms; + mn.firstKeyAct= pChanges->map.first_key_act; + mn.nKeyActs= pChanges->map.num_key_acts; + mn.firstKeyBehavior= pChanges->map.first_key_behavior; + mn.nKeyBehaviors= pChanges->map.num_key_behaviors; + mn.virtualMods= pChanges->map.vmods; + mn.firstKeyExplicit= pChanges->map.first_key_explicit; + mn.nKeyExplicit= pChanges->map.num_key_explicit; + mn.firstModMapKey= pChanges->map.first_modmap_key; + mn.nModMapKeys= pChanges->map.num_modmap_keys; + mn.firstVModMapKey= pChanges->map.first_vmodmap_key; + mn.nVModMapKeys= pChanges->map.num_vmodmap_keys; + XkbSendMapNotify(kbd,&mn); + } + if ((pChanges->ctrls.changed_ctrls)|| + (pChanges->ctrls.enabled_ctrls_changes)) { + xkbControlsNotify cn; + memset(&cn, 0, sizeof(xkbControlsNotify)); + cn.changedControls= pChanges->ctrls.changed_ctrls; + cn.enabledControlChanges= pChanges->ctrls.enabled_ctrls_changes; + cn.keycode= cause->kc; + cn.eventType= cause->event; + cn.requestMajor= cause->mjr; + cn.requestMinor= cause->mnr; + XkbSendControlsNotify(kbd,&cn); + } + if (pChanges->indicators.map_changes) { + xkbIndicatorNotify in; + if (sli==NULL) + sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); + memset(&in, 0, sizeof(xkbIndicatorNotify)); + in.state= sli->effectiveState; + in.changed= pChanges->indicators.map_changes; + XkbSendIndicatorNotify(kbd,XkbIndicatorMapNotify,&in); + } + if (pChanges->indicators.state_changes) { + xkbIndicatorNotify in; + if (sli==NULL) + sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); + memset(&in, 0, sizeof(xkbIndicatorNotify)); + in.state= sli->effectiveState; + in.changed= pChanges->indicators.state_changes; + XkbSendIndicatorNotify(kbd,XkbIndicatorStateNotify,&in); + } + if (pChanges->names.changed) { + xkbNamesNotify nn; + memset(&nn, 0, sizeof(xkbNamesNotify)); + nn.changed= pChanges->names.changed; + nn.firstType= pChanges->names.first_type; + nn.nTypes= pChanges->names.num_types; + nn.firstLevelName= pChanges->names.first_lvl; + nn.nLevelNames= pChanges->names.num_lvls; + nn.nRadioGroups= pChanges->names.num_rg; + nn.changedVirtualMods= pChanges->names.changed_vmods; + nn.changedIndicators= pChanges->names.changed_indicators; + XkbSendNamesNotify(kbd,&nn); + } + if ((pChanges->compat.changed_groups)||(pChanges->compat.num_si>0)) { + xkbCompatMapNotify cmn; + memset(&cmn, 0, sizeof(xkbCompatMapNotify)); + cmn.changedGroups= pChanges->compat.changed_groups; + cmn.firstSI= pChanges->compat.first_si; + cmn.nSI= pChanges->compat.num_si; + cmn.nTotalSI= kbd->key->xkbInfo->desc->compat->num_si; + XkbSendCompatMapNotify(kbd,&cmn); + } + return; +} + +/***====================================================================***/ + +void +XkbFilterEvents(ClientPtr client,int nEvents,xEvent *xE) +{ + DeviceIntPtr dev = NULL; + XkbSrvInfoPtr xkbi; + CARD8 type = xE[0].u.u.type; + + if (xE->u.u.type & EXTENSION_EVENT_BASE) + dev = XIGetDevice(xE); + + if (!dev) + dev = PickKeyboard(client); + + if (!dev->key) + return; + + xkbi = dev->key->xkbInfo; + + if (client->xkbClientFlags & _XkbClientInitialized) { + if ((xkbDebugFlags&0x10)&& + (type == KeyPress || type == KeyRelease || + type == DeviceKeyPress || type == DeviceKeyRelease)) + DebugF("[xkb] XkbFilterWriteEvents (XKB client): state 0x%04x\n", + xE[0].u.keyButtonPointer.state); + + if (dev->deviceGrab.grab != NullGrab && dev->deviceGrab.fromPassiveGrab && + (type == KeyPress || type == KeyRelease || + type == DeviceKeyPress || type == DeviceKeyRelease)) { + unsigned int state, flags; + + flags = client->xkbClientFlags; + state = xkbi->state.compat_grab_mods; + if (flags & XkbPCF_GrabsUseXKBStateMask) { + int group; + if (flags & XkbPCF_LookupStateWhenGrabbed) { + group = xkbi->state.group; + state = xkbi->state.lookup_mods; + } + else { + state = xkbi->state.grab_mods; + group = xkbi->state.base_group + xkbi->state.latched_group; + if (group < 0 || group >= xkbi->desc->ctrls->num_groups) + group = XkbAdjustGroup(group, xkbi->desc->ctrls); + } + state = XkbBuildCoreState(state, group); + } + else if (flags & XkbPCF_LookupStateWhenGrabbed) { + state = xkbi->state.compat_lookup_mods; + } + xE[0].u.keyButtonPointer.state = state; + } + } + else { + if ((xkbDebugFlags & 0x4) && + (xE[0].u.u.type == KeyPress || xE[0].u.u.type==KeyRelease || + xE[0].u.u.type == DeviceKeyPress || + xE[0].u.u.type == DeviceKeyRelease)) { + DebugF("[xkb] XKbFilterWriteEvents (non-XKB):\n"); + DebugF("[xkb] event= 0x%04x\n",xE[0].u.keyButtonPointer.state); + DebugF("[xkb] lookup= 0x%02x, grab= 0x%02x\n", + xkbi->state.lookup_mods, xkbi->state.grab_mods); + DebugF("[xkb] compat lookup= 0x%02x, grab= 0x%02x\n", + xkbi->state.compat_lookup_mods, xkbi->state.compat_grab_mods); + } + if (type >= KeyPress && type <= MotionNotify) { + CARD16 old, new; + + old = xE[0].u.keyButtonPointer.state & ~0x1f00; + new = xE[0].u.keyButtonPointer.state & 0x1F00; + + if (old == XkbStateFieldFromRec(&xkbi->state)) + new |= xkbi->state.compat_lookup_mods; + else + new |= xkbi->state.compat_grab_mods; + xE[0].u.keyButtonPointer.state = new; + } + else if (type == EnterNotify || type == LeaveNotify) { + xE[0].u.enterLeave.state &= 0x1F00; + xE[0].u.enterLeave.state |= xkbi->state.compat_grab_mods; + } + else if (type >= DeviceKeyPress && type <= DeviceMotionNotify) { + CARD16 old, new; + deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer*) &xE[0]; + + old = kbp->state & ~0x1F00; + new = kbp->state & 0x1F00; + if (old == XkbStateFieldFromRec(&xkbi->state)) + new |= xkbi->state.compat_lookup_mods; + else + new |= xkbi->state.compat_grab_mods; + kbp->state = new; + } + } +} + +/***====================================================================***/ + +XkbInterestPtr +XkbFindClientResource(DevicePtr inDev,ClientPtr client) +{ +DeviceIntPtr dev = (DeviceIntPtr)inDev; +XkbInterestPtr interest; + + if ( dev->xkb_interest ) { + interest = dev->xkb_interest; + while (interest){ + if (interest->client==client) { + return interest; + } + interest = interest->next; + } + } + return NULL; +} + +XkbInterestPtr +XkbAddClientResource(DevicePtr inDev,ClientPtr client,XID id) +{ +DeviceIntPtr dev = (DeviceIntPtr)inDev; +XkbInterestPtr interest; + + interest = dev->xkb_interest; + while (interest) { + if (interest->client==client) + return ((interest->resource==id)?interest:NULL); + interest = interest->next; + } + interest = calloc(1, sizeof(XkbInterestRec)); + if (interest) { + interest->dev = dev; + interest->client = client; + interest->resource = id; + interest->stateNotifyMask= 0; + interest->ctrlsNotifyMask= 0; + interest->namesNotifyMask= 0; + interest->compatNotifyMask= 0; + interest->bellNotifyMask= FALSE; + interest->accessXNotifyMask= 0; + interest->iStateNotifyMask= 0; + interest->iMapNotifyMask= 0; + interest->altSymsNotifyMask= 0; + interest->next = dev->xkb_interest; + dev->xkb_interest= interest; + return interest; + } + return NULL; +} + +int +XkbRemoveResourceClient(DevicePtr inDev,XID id) +{ +XkbSrvInfoPtr xkbi; +DeviceIntPtr dev = (DeviceIntPtr)inDev; +XkbInterestPtr interest; +Bool found; +unsigned long autoCtrls,autoValues; +ClientPtr client = NULL; + + found= FALSE; + + if (!dev->key || !dev->key->xkbInfo) + return found; + + autoCtrls= autoValues= 0; + if ( dev->xkb_interest ) { + interest = dev->xkb_interest; + if (interest && (interest->resource==id)){ + dev->xkb_interest = interest->next; + autoCtrls= interest->autoCtrls; + autoValues= interest->autoCtrlValues; + client= interest->client; + free(interest); + found= TRUE; + } + while ((!found)&&(interest->next)) { + if (interest->next->resource==id) { + XkbInterestPtr victim = interest->next; + interest->next = victim->next; + autoCtrls= victim->autoCtrls; + autoValues= victim->autoCtrlValues; + client= victim->client; + free(victim); + found= TRUE; + } + interest = interest->next; + } + } + if (found && autoCtrls && dev->key && dev->key->xkbInfo ) { + XkbEventCauseRec cause; + + xkbi= dev->key->xkbInfo; + XkbSetCauseXkbReq(&cause,X_kbPerClientFlags,client); + XkbEnableDisableControls(xkbi,autoCtrls,autoValues,NULL,&cause); + } + return found; +} diff --git a/xorg-server/xkb/xkbInit.c b/xorg-server/xkb/xkbInit.c index 4a3219e2a..0bb232f5a 100644 --- a/xorg-server/xkb/xkbInit.c +++ b/xorg-server/xkb/xkbInit.c @@ -1,779 +1,779 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#endif - -#include <xkb-config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <unistd.h> -#include <math.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/keysym.h> -#include <X11/Xatom.h> -#include "misc.h" -#include "inputstr.h" -#include "opaque.h" -#include "property.h" -#define XKBSRV_NEED_FILE_FUNCS -#include <xkbsrv.h> -#include "xkbgeom.h" -#include <X11/extensions/XKMformat.h> -#include "xkbfile.h" -#include "xkb.h" - -#define CREATE_ATOM(s) MakeAtom(s,sizeof(s)-1,1) - -#if defined(__alpha) || defined(__alpha__) -#define LED_COMPOSE 2 -#define LED_CAPS 3 -#define LED_SCROLL 4 -#define LED_NUM 5 -#define PHYS_LEDS 0x1f -#else -#ifdef sun -#define LED_NUM 1 -#define LED_SCROLL 2 -#define LED_COMPOSE 3 -#define LED_CAPS 4 -#define PHYS_LEDS 0x0f -#else -#define LED_CAPS 1 -#define LED_NUM 2 -#define LED_SCROLL 3 -#define PHYS_LEDS 0x07 -#endif -#endif - -#define MAX_TOC 16 -typedef struct _SrvXkmInfo { - DeviceIntPtr dev; - FILE * file; - XkbDescPtr xkb; -} SrvXkmInfo; - - -/***====================================================================***/ - -#ifndef XKB_DFLT_RULES_PROP -#define XKB_DFLT_RULES_PROP TRUE -#endif - -char * XkbBaseDirectory= XKB_BASE_DIRECTORY; -char * XkbBinDirectory= XKB_BIN_DIRECTORY; -static int XkbWantAccessX= 0; - -static char * XkbRulesDflt= NULL; -static char * XkbModelDflt= NULL; -static char * XkbLayoutDflt= NULL; -static char * XkbVariantDflt= NULL; -static char * XkbOptionsDflt= NULL; - -static char * XkbRulesUsed= NULL; -static char * XkbModelUsed= NULL; -static char * XkbLayoutUsed= NULL; -static char * XkbVariantUsed= NULL; -static char * XkbOptionsUsed= NULL; - -static XkbDescPtr xkb_cached_map = NULL; - -static Bool XkbWantRulesProp= XKB_DFLT_RULES_PROP; - -/***====================================================================***/ - -/** - * Get the current default XKB rules. - * Caller must free the data in rmlvo. - */ -void -XkbGetRulesDflts(XkbRMLVOSet *rmlvo) -{ - if (XkbRulesDflt) rmlvo->rules = XkbRulesDflt; - else rmlvo->rules = XKB_DFLT_RULES; - if (XkbModelDflt) rmlvo->model= XkbModelDflt; - else rmlvo->model= XKB_DFLT_MODEL; - if (XkbLayoutDflt) rmlvo->layout= XkbLayoutDflt; - else rmlvo->layout= XKB_DFLT_LAYOUT; - if (XkbVariantDflt) rmlvo->variant= XkbVariantDflt; - else rmlvo->variant= XKB_DFLT_VARIANT; - if (XkbOptionsDflt) rmlvo->options= XkbOptionsDflt; - else rmlvo->options= XKB_DFLT_OPTIONS; - - rmlvo->rules = strdup(rmlvo->rules); - rmlvo->model = strdup(rmlvo->model); - rmlvo->layout = strdup(rmlvo->layout); - rmlvo->variant = strdup(rmlvo->variant); - rmlvo->options = strdup(rmlvo->options); -} - -void -XkbFreeRMLVOSet(XkbRMLVOSet *rmlvo, Bool freeRMLVO) -{ - if (!rmlvo) - return; - - xfree(rmlvo->rules); - xfree(rmlvo->model); - xfree(rmlvo->layout); - xfree(rmlvo->variant); - xfree(rmlvo->options); - - if (freeRMLVO) - xfree(rmlvo); - else - memset(rmlvo, 0, sizeof(XkbRMLVOSet)); -} - -static Bool -XkbWriteRulesProp(ClientPtr client, pointer closure) -{ -int len,out; -Atom name; -char * pval; - - len= (XkbRulesUsed?strlen(XkbRulesUsed):0); - len+= (XkbModelUsed?strlen(XkbModelUsed):0); - len+= (XkbLayoutUsed?strlen(XkbLayoutUsed):0); - len+= (XkbVariantUsed?strlen(XkbVariantUsed):0); - len+= (XkbOptionsUsed?strlen(XkbOptionsUsed):0); - if (len<1) - return TRUE; - - len+= 5; /* trailing NULs */ - - name= MakeAtom(_XKB_RF_NAMES_PROP_ATOM,strlen(_XKB_RF_NAMES_PROP_ATOM),1); - if (name==None) { - ErrorF("[xkb] Atom error: %s not created\n",_XKB_RF_NAMES_PROP_ATOM); - return TRUE; - } - pval= (char*) xalloc(len); - if (!pval) { - ErrorF("[xkb] Allocation error: %s proprerty not created\n", - _XKB_RF_NAMES_PROP_ATOM); - return TRUE; - } - out= 0; - if (XkbRulesUsed) { - strcpy(&pval[out],XkbRulesUsed); - out+= strlen(XkbRulesUsed); - } - pval[out++]= '\0'; - if (XkbModelUsed) { - strcpy(&pval[out],XkbModelUsed); - out+= strlen(XkbModelUsed); - } - pval[out++]= '\0'; - if (XkbLayoutUsed) { - strcpy(&pval[out],XkbLayoutUsed); - out+= strlen(XkbLayoutUsed); - } - pval[out++]= '\0'; - if (XkbVariantUsed) { - strcpy(&pval[out],XkbVariantUsed); - out+= strlen(XkbVariantUsed); - } - pval[out++]= '\0'; - if (XkbOptionsUsed) { - strcpy(&pval[out],XkbOptionsUsed); - out+= strlen(XkbOptionsUsed); - } - pval[out++]= '\0'; - if (out!=len) { - ErrorF("[xkb] Internal Error! bad size (%d!=%d) for _XKB_RULES_NAMES\n", - out,len); - } - dixChangeWindowProperty(serverClient, WindowTable[0], name, XA_STRING, 8, - PropModeReplace, len, pval, TRUE); - xfree(pval); - return TRUE; -} - -static void -XkbSetRulesUsed(XkbRMLVOSet *rmlvo) -{ - if (XkbRulesUsed) - xfree(XkbRulesUsed); - XkbRulesUsed= (rmlvo->rules?_XkbDupString(rmlvo->rules):NULL); - if (XkbModelUsed) - xfree(XkbModelUsed); - XkbModelUsed= (rmlvo->model?_XkbDupString(rmlvo->model):NULL); - if (XkbLayoutUsed) - xfree(XkbLayoutUsed); - XkbLayoutUsed= (rmlvo->layout?_XkbDupString(rmlvo->layout):NULL); - if (XkbVariantUsed) - xfree(XkbVariantUsed); - XkbVariantUsed= (rmlvo->variant?_XkbDupString(rmlvo->variant):NULL); - if (XkbOptionsUsed) - xfree(XkbOptionsUsed); - XkbOptionsUsed= (rmlvo->options?_XkbDupString(rmlvo->options):NULL); - if (XkbWantRulesProp) - QueueWorkProc(XkbWriteRulesProp,NULL,NULL); - return; -} - -void -XkbSetRulesDflts(XkbRMLVOSet *rmlvo) -{ - if (rmlvo->rules) { - if (XkbRulesDflt) - xfree(XkbRulesDflt); - XkbRulesDflt= _XkbDupString(rmlvo->rules); - } - if (rmlvo->model) { - if (XkbModelDflt) - xfree(XkbModelDflt); - XkbModelDflt= _XkbDupString(rmlvo->model); - } - if (rmlvo->layout) { - if (XkbLayoutDflt) - xfree(XkbLayoutDflt); - XkbLayoutDflt= _XkbDupString(rmlvo->layout); - } - if (rmlvo->variant) { - if (XkbVariantDflt) - xfree(XkbVariantDflt); - XkbVariantDflt= _XkbDupString(rmlvo->variant); - } - if (rmlvo->options) { - if (XkbOptionsDflt) - xfree(XkbOptionsDflt); - XkbOptionsDflt= _XkbDupString(rmlvo->options); - } - return; -} - -void -XkbDeleteRulesDflts(void) -{ - xfree(XkbRulesDflt); - XkbRulesDflt = NULL; - xfree(XkbModelDflt); - XkbModelDflt = NULL; - xfree(XkbLayoutDflt); - XkbLayoutDflt = NULL; - xfree(XkbVariantDflt); - XkbVariantDflt = NULL; - xfree(XkbOptionsDflt); - XkbOptionsDflt = NULL; - - XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE); - xkb_cached_map = NULL; -} - -#define DIFFERS(a, b) (strcmp((a) ? (a) : "", (b) ? (b) : "") != 0) - -static Bool -XkbCompareUsedRMLVO(XkbRMLVOSet *rmlvo) -{ - if (DIFFERS(rmlvo->rules, XkbRulesUsed) || - DIFFERS(rmlvo->model, XkbModelUsed) || - DIFFERS(rmlvo->layout, XkbLayoutUsed) || - DIFFERS(rmlvo->variant, XkbVariantUsed) || - DIFFERS(rmlvo->options, XkbOptionsUsed)) - return FALSE; - return TRUE; -} - -#undef DIFFERS - -/***====================================================================***/ - -#include "xkbDflts.h" - -static Bool -XkbInitKeyTypes(XkbDescPtr xkb) -{ - if (xkb->defined & XkmTypesMask) - return TRUE; - - initTypeNames(NULL); - if (XkbAllocClientMap(xkb,XkbKeyTypesMask,num_dflt_types)!=Success) - return FALSE; - if (XkbCopyKeyTypes(dflt_types,xkb->map->types,num_dflt_types)!= - Success) { - return FALSE; - } - xkb->map->size_types= xkb->map->num_types= num_dflt_types; - return TRUE; -} - -static void -XkbInitRadioGroups(XkbSrvInfoPtr xkbi) -{ - xkbi->nRadioGroups = 0; - xkbi->radioGroups = NULL; - return; -} - - -static Status -XkbInitCompatStructs(XkbDescPtr xkb) -{ -register int i; -XkbCompatMapPtr compat; - - if (xkb->defined & XkmCompatMapMask) - return TRUE; - - if (XkbAllocCompatMap(xkb,XkbAllCompatMask,num_dfltSI)!=Success) - return BadAlloc; - compat = xkb->compat; - if (compat->sym_interpret) { - compat->num_si = num_dfltSI; - memcpy((char *)compat->sym_interpret,(char *)dfltSI,sizeof(dfltSI)); - } - for (i=0;i<XkbNumKbdGroups;i++) { - compat->groups[i]= compatMap.groups[i]; - if (compat->groups[i].vmods!=0) { - unsigned mask; - mask= XkbMaskForVMask(xkb,compat->groups[i].vmods); - compat->groups[i].mask= compat->groups[i].real_mods|mask; - } - else compat->groups[i].mask= compat->groups[i].real_mods; - } - return Success; -} - -static void -XkbInitSemantics(XkbDescPtr xkb) -{ - XkbInitKeyTypes(xkb); - XkbInitCompatStructs(xkb); - return; -} - -/***====================================================================***/ - -static Status -XkbInitNames(XkbSrvInfoPtr xkbi) -{ -XkbDescPtr xkb; -XkbNamesPtr names; -Status rtrn; -Atom unknown; - - xkb= xkbi->desc; - if ((rtrn=XkbAllocNames(xkb,XkbAllNamesMask,0,0))!=Success) - return rtrn; - unknown= CREATE_ATOM("unknown"); - names = xkb->names; - if (names->keycodes==None) names->keycodes= unknown; - if (names->geometry==None) names->geometry= unknown; - if (names->phys_symbols==None) names->phys_symbols= unknown; - if (names->symbols==None) names->symbols= unknown; - if (names->types==None) names->types= unknown; - if (names->compat==None) names->compat= unknown; - if (!(xkb->defined & XkmVirtualModsMask)) { - if (names->vmods[vmod_NumLock]==None) - names->vmods[vmod_NumLock]= CREATE_ATOM("NumLock"); - if (names->vmods[vmod_Alt]==None) - names->vmods[vmod_Alt]= CREATE_ATOM("Alt"); - if (names->vmods[vmod_AltGr]==None) - names->vmods[vmod_AltGr]= CREATE_ATOM("ModeSwitch"); - } - - if (!(xkb->defined & XkmIndicatorsMask) || - !(xkb->defined & XkmGeometryMask)) { - initIndicatorNames(NULL,xkb); - if (names->indicators[LED_CAPS-1]==None) - names->indicators[LED_CAPS-1] = CREATE_ATOM("Caps Lock"); - if (names->indicators[LED_NUM-1]==None) - names->indicators[LED_NUM-1] = CREATE_ATOM("Num Lock"); - if (names->indicators[LED_SCROLL-1]==None) - names->indicators[LED_SCROLL-1] = CREATE_ATOM("Scroll Lock"); -#ifdef LED_COMPOSE - if (names->indicators[LED_COMPOSE-1]==None) - names->indicators[LED_COMPOSE-1] = CREATE_ATOM("Compose"); -#endif - } - - if (xkb->geom!=NULL) - names->geometry= xkb->geom->name; - else names->geometry= unknown; - - return Success; -} - -static Status -XkbInitIndicatorMap(XkbSrvInfoPtr xkbi) -{ -XkbDescPtr xkb; -XkbIndicatorPtr map; -XkbSrvLedInfoPtr sli; - - xkb= xkbi->desc; - if (XkbAllocIndicatorMaps(xkb)!=Success) - return BadAlloc; - - if (!(xkb->defined & XkmIndicatorsMask)) { - map= xkb->indicators; - map->phys_indicators = PHYS_LEDS; - map->maps[LED_CAPS-1].flags= XkbIM_NoExplicit; - map->maps[LED_CAPS-1].which_mods= XkbIM_UseLocked; - map->maps[LED_CAPS-1].mods.mask= LockMask; - map->maps[LED_CAPS-1].mods.real_mods= LockMask; - - map->maps[LED_NUM-1].flags= XkbIM_NoExplicit; - map->maps[LED_NUM-1].which_mods= XkbIM_UseLocked; - map->maps[LED_NUM-1].mods.mask= 0; - map->maps[LED_NUM-1].mods.real_mods= 0; - map->maps[LED_NUM-1].mods.vmods= vmod_NumLockMask; - - map->maps[LED_SCROLL-1].flags= XkbIM_NoExplicit; - map->maps[LED_SCROLL-1].which_mods= XkbIM_UseLocked; - map->maps[LED_SCROLL-1].mods.mask= Mod3Mask; - map->maps[LED_SCROLL-1].mods.real_mods= Mod3Mask; - } - - sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0); - if (sli) - XkbCheckIndicatorMaps(xkbi->device,sli,XkbAllIndicatorsMask); - - return Success; -} - -static Status -XkbInitControls(DeviceIntPtr pXDev,XkbSrvInfoPtr xkbi) -{ -XkbDescPtr xkb; -XkbControlsPtr ctrls; - - xkb= xkbi->desc; - /* 12/31/94 (ef) -- XXX! Should check if controls loaded from file */ - if (XkbAllocControls(xkb,XkbAllControlsMask)!=Success) - FatalError("Couldn't allocate keyboard controls\n"); - ctrls= xkb->ctrls; - if (!(xkb->defined & XkmSymbolsMask)) - ctrls->num_groups = 1; - ctrls->groups_wrap = XkbSetGroupInfo(1,XkbWrapIntoRange,0); - ctrls->internal.mask = 0; - ctrls->internal.real_mods = 0; - ctrls->internal.vmods = 0; - ctrls->ignore_lock.mask = 0; - ctrls->ignore_lock.real_mods = 0; - ctrls->ignore_lock.vmods = 0; - ctrls->enabled_ctrls = XkbAccessXTimeoutMask|XkbRepeatKeysMask| - XkbMouseKeysAccelMask|XkbAudibleBellMask| - XkbIgnoreGroupLockMask; - if (XkbWantAccessX) - ctrls->enabled_ctrls|= XkbAccessXKeysMask; - AccessXInit(pXDev); - return Success; -} - -_X_EXPORT Bool -InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet *rmlvo, - BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func) -{ - int i; - unsigned int check; - XkbSrvInfoPtr xkbi; - XkbDescPtr xkb; - XkbSrvLedInfoPtr sli; - XkbChangesRec changes; - XkbEventCauseRec cause; - XkbRMLVOSet rmlvo_dflts = { NULL }; - - if (dev->key || dev->kbdfeed) - return FALSE; - - if (!rmlvo) - { - rmlvo = &rmlvo_dflts; - XkbGetRulesDflts(rmlvo); - } - - - memset(&changes, 0, sizeof(changes)); - XkbSetCauseUnknown(&cause); - - dev->key = xcalloc(1, sizeof(*dev->key)); - if (!dev->key) { - ErrorF("XKB: Failed to allocate key class\n"); - return FALSE; - } - dev->key->sourceid = dev->id; - - dev->kbdfeed = xcalloc(1, sizeof(*dev->kbdfeed)); - if (!dev->kbdfeed) { - ErrorF("XKB: Failed to allocate key feedback class\n"); - goto unwind_key; - } - - xkbi = xcalloc(1, sizeof(*xkbi)); - if (!xkbi) { - ErrorF("XKB: Failed to allocate XKB info\n"); - goto unwind_kbdfeed; - } - dev->key->xkbInfo = xkbi; - - if (xkb_cached_map && !XkbCompareUsedRMLVO(rmlvo)) { - XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE); - xkb_cached_map = NULL; - } - - if (xkb_cached_map) - LogMessageVerb(X_INFO, 4, "XKB: Reusing cached keymap\n"); - else { - xkb_cached_map = XkbCompileKeymap(dev, rmlvo); - if (!xkb_cached_map) { - ErrorF("XKB: Failed to compile keymap\n"); - goto unwind_info; - } - } - - xkb = XkbAllocKeyboard(); - if (!xkb) { - ErrorF("XKB: Failed to allocate keyboard description\n"); - goto unwind_info; - } - - if (!XkbCopyKeymap(xkb, xkb_cached_map)) { - ErrorF("XKB: Failed to copy keymap\n"); - goto unwind_desc; - } - xkb->defined = xkb_cached_map->defined; - xkb->flags = xkb_cached_map->flags; - xkb->device_spec = xkb_cached_map->device_spec; - xkbi->desc = xkb; - - if (xkb->min_key_code == 0) - xkb->min_key_code = 8; - if (xkb->max_key_code == 0) - xkb->max_key_code = 255; - - i = XkbNumKeys(xkb) / 3 + 1; - if (XkbAllocClientMap(xkb, XkbAllClientInfoMask, 0) != Success) - goto unwind_desc; - if (XkbAllocServerMap(xkb, XkbAllServerInfoMask, i) != Success) - goto unwind_desc; - - xkbi->dfltPtrDelta = 1; - xkbi->device = dev; - - XkbInitSemantics(xkb); - XkbInitNames(xkbi); - XkbInitRadioGroups(xkbi); - - XkbInitControls(dev, xkbi); - - XkbInitIndicatorMap(xkbi); - - XkbUpdateActions(dev, xkb->min_key_code, XkbNumKeys(xkb), &changes, - &check, &cause); - - InitFocusClassDeviceStruct(dev); - - xkbi->kbdProc = ctrl_func; - dev->kbdfeed->BellProc = bell_func; - dev->kbdfeed->CtrlProc = XkbDDXKeybdCtrlProc; - - dev->kbdfeed->ctrl = defaultKeyboardControl; - if (dev->kbdfeed->ctrl.autoRepeat) - xkb->ctrls->enabled_ctrls |= XkbRepeatKeysMask; - - memcpy(dev->kbdfeed->ctrl.autoRepeats, xkb->ctrls->per_key_repeat, - XkbPerKeyBitArraySize); - - sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0); - if (sli) - XkbCheckIndicatorMaps(dev, sli, XkbAllIndicatorsMask); - else - DebugF("XKB: No indicator feedback in XkbFinishInit!\n"); - - dev->kbdfeed->CtrlProc(dev,&dev->kbdfeed->ctrl); - - XkbSetRulesDflts(rmlvo); - XkbSetRulesUsed(rmlvo); - XkbFreeRMLVOSet(&rmlvo_dflts, FALSE); - - return TRUE; - -unwind_desc: - XkbFreeKeyboard(xkb, 0, TRUE); -unwind_info: - xfree(xkbi); - dev->key->xkbInfo = NULL; -unwind_kbdfeed: - xfree(dev->kbdfeed); - dev->kbdfeed = NULL; -unwind_key: - xfree(dev->key); - dev->key = NULL; - return FALSE; -} - - -/***====================================================================***/ - - /* - * Be very careful about what does and doesn't get freed by this - * function. To reduce fragmentation, XkbInitDevice allocates a - * single huge block per device and divides it up into most of the - * fixed-size structures for the device. Don't free anything that - * is part of this larger block. - */ -void -XkbFreeInfo(XkbSrvInfoPtr xkbi) -{ - if (xkbi->radioGroups) { - xfree(xkbi->radioGroups); - xkbi->radioGroups= NULL; - } - if (xkbi->mouseKeyTimer) { - TimerFree(xkbi->mouseKeyTimer); - xkbi->mouseKeyTimer= NULL; - } - if (xkbi->slowKeysTimer) { - TimerFree(xkbi->slowKeysTimer); - xkbi->slowKeysTimer= NULL; - } - if (xkbi->bounceKeysTimer) { - TimerFree(xkbi->bounceKeysTimer); - xkbi->bounceKeysTimer= NULL; - } - if (xkbi->repeatKeyTimer) { - TimerFree(xkbi->repeatKeyTimer); - xkbi->repeatKeyTimer= NULL; - } - if (xkbi->krgTimer) { - TimerFree(xkbi->krgTimer); - xkbi->krgTimer= NULL; - } - xkbi->beepType= _BEEP_NONE; - if (xkbi->beepTimer) { - TimerFree(xkbi->beepTimer); - xkbi->beepTimer= NULL; - } - if (xkbi->desc) { - XkbFreeKeyboard(xkbi->desc,XkbAllComponentsMask,TRUE); - xkbi->desc= NULL; - } - xfree(xkbi); - return; -} - -/***====================================================================***/ - -extern int XkbDfltRepeatDelay; -extern int XkbDfltRepeatInterval; - -extern unsigned short XkbDfltAccessXTimeout; -extern unsigned int XkbDfltAccessXTimeoutMask; -extern unsigned int XkbDfltAccessXFeedback; -extern unsigned char XkbDfltAccessXOptions; - -int -XkbProcessArguments(int argc,char *argv[],int i) -{ - if (strncmp(argv[i], "-xkbdir", 7) == 0) { - if(++i < argc) { -#if !defined(WIN32) && !defined(__CYGWIN__) - if (getuid() != geteuid()) { - LogMessage(X_WARNING, "-xkbdir is not available for setuid X servers\n"); - return -1; - } else -#endif - { - if (strlen(argv[i]) < PATH_MAX) { - XkbBaseDirectory= argv[i]; - return 2; - } else { - LogMessage(X_ERROR, "-xkbdir pathname too long\n"); - return -1; - } - } - } - else { - return -1; - } - } - else if ((strncmp(argv[i],"-accessx",8)==0)|| - (strncmp(argv[i],"+accessx",8)==0)) { - int j=1; - if (argv[i][0]=='-') - XkbWantAccessX= 0; - else { - XkbWantAccessX= 1; - - if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) { - XkbDfltAccessXTimeout = atoi(argv[++i]); - j++; - - if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) { - /* - * presumption that the reasonably useful range of - * values fits in 0..MAXINT since SunOS 4 doesn't - * have strtoul. - */ - XkbDfltAccessXTimeoutMask=(unsigned int) - strtol(argv[++i],NULL,16); - j++; - } - if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) { - if (argv[++i][0] == '1' ) - XkbDfltAccessXFeedback=XkbAccessXFeedbackMask; - else - XkbDfltAccessXFeedback=0; - j++; - } - if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) { - XkbDfltAccessXOptions=(unsigned char) - strtol(argv[++i],NULL,16); - j++; - } - } - } - return j; - } - if ((strcmp(argv[i], "-ardelay") == 0) || - (strcmp (argv[i], "-ar1") == 0)) { /* -ardelay int */ - if (++i >= argc) UseMsg (); - XkbDfltRepeatDelay = (long)atoi(argv[i]); - return 2; - } - if ((strcmp(argv[i], "-arinterval") == 0) || - (strcmp (argv[i], "-ar2") == 0)) { /* -arinterval int */ - if (++i >= argc) UseMsg (); - XkbDfltRepeatInterval = (long)atoi(argv[i]); - return 2; - } - return 0; -} - -void -XkbUseMsg(void) -{ - ErrorF("[+-]accessx [ timeout [ timeout_mask [ feedback [ options_mask] ] ] ]\n"); - ErrorF(" enable/disable accessx key sequences\n"); - ErrorF("-ardelay set XKB autorepeat delay\n"); - ErrorF("-arinterval set XKB autorepeat interval\n"); -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#endif + +#include <xkb-config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <math.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include "misc.h" +#include "inputstr.h" +#include "opaque.h" +#include "property.h" +#define XKBSRV_NEED_FILE_FUNCS +#include <xkbsrv.h> +#include "xkbgeom.h" +#include <X11/extensions/XKMformat.h> +#include "xkbfile.h" +#include "xkb.h" + +#define CREATE_ATOM(s) MakeAtom(s,sizeof(s)-1,1) + +#if defined(__alpha) || defined(__alpha__) +#define LED_COMPOSE 2 +#define LED_CAPS 3 +#define LED_SCROLL 4 +#define LED_NUM 5 +#define PHYS_LEDS 0x1f +#else +#ifdef sun +#define LED_NUM 1 +#define LED_SCROLL 2 +#define LED_COMPOSE 3 +#define LED_CAPS 4 +#define PHYS_LEDS 0x0f +#else +#define LED_CAPS 1 +#define LED_NUM 2 +#define LED_SCROLL 3 +#define PHYS_LEDS 0x07 +#endif +#endif + +#define MAX_TOC 16 +typedef struct _SrvXkmInfo { + DeviceIntPtr dev; + FILE * file; + XkbDescPtr xkb; +} SrvXkmInfo; + + +/***====================================================================***/ + +#ifndef XKB_DFLT_RULES_PROP +#define XKB_DFLT_RULES_PROP TRUE +#endif + +char * XkbBaseDirectory= XKB_BASE_DIRECTORY; +char * XkbBinDirectory= XKB_BIN_DIRECTORY; +static int XkbWantAccessX= 0; + +static char * XkbRulesDflt= NULL; +static char * XkbModelDflt= NULL; +static char * XkbLayoutDflt= NULL; +static char * XkbVariantDflt= NULL; +static char * XkbOptionsDflt= NULL; + +static char * XkbRulesUsed= NULL; +static char * XkbModelUsed= NULL; +static char * XkbLayoutUsed= NULL; +static char * XkbVariantUsed= NULL; +static char * XkbOptionsUsed= NULL; + +static XkbDescPtr xkb_cached_map = NULL; + +static Bool XkbWantRulesProp= XKB_DFLT_RULES_PROP; + +/***====================================================================***/ + +/** + * Get the current default XKB rules. + * Caller must free the data in rmlvo. + */ +void +XkbGetRulesDflts(XkbRMLVOSet *rmlvo) +{ + if (XkbRulesDflt) rmlvo->rules = XkbRulesDflt; + else rmlvo->rules = XKB_DFLT_RULES; + if (XkbModelDflt) rmlvo->model= XkbModelDflt; + else rmlvo->model= XKB_DFLT_MODEL; + if (XkbLayoutDflt) rmlvo->layout= XkbLayoutDflt; + else rmlvo->layout= XKB_DFLT_LAYOUT; + if (XkbVariantDflt) rmlvo->variant= XkbVariantDflt; + else rmlvo->variant= XKB_DFLT_VARIANT; + if (XkbOptionsDflt) rmlvo->options= XkbOptionsDflt; + else rmlvo->options= XKB_DFLT_OPTIONS; + + rmlvo->rules = strdup(rmlvo->rules); + rmlvo->model = strdup(rmlvo->model); + rmlvo->layout = strdup(rmlvo->layout); + rmlvo->variant = strdup(rmlvo->variant); + rmlvo->options = strdup(rmlvo->options); +} + +void +XkbFreeRMLVOSet(XkbRMLVOSet *rmlvo, Bool freeRMLVO) +{ + if (!rmlvo) + return; + + free(rmlvo->rules); + free(rmlvo->model); + free(rmlvo->layout); + free(rmlvo->variant); + free(rmlvo->options); + + if (freeRMLVO) + free(rmlvo); + else + memset(rmlvo, 0, sizeof(XkbRMLVOSet)); +} + +static Bool +XkbWriteRulesProp(ClientPtr client, pointer closure) +{ +int len,out; +Atom name; +char * pval; + + len= (XkbRulesUsed?strlen(XkbRulesUsed):0); + len+= (XkbModelUsed?strlen(XkbModelUsed):0); + len+= (XkbLayoutUsed?strlen(XkbLayoutUsed):0); + len+= (XkbVariantUsed?strlen(XkbVariantUsed):0); + len+= (XkbOptionsUsed?strlen(XkbOptionsUsed):0); + if (len<1) + return TRUE; + + len+= 5; /* trailing NULs */ + + name= MakeAtom(_XKB_RF_NAMES_PROP_ATOM,strlen(_XKB_RF_NAMES_PROP_ATOM),1); + if (name==None) { + ErrorF("[xkb] Atom error: %s not created\n",_XKB_RF_NAMES_PROP_ATOM); + return TRUE; + } + pval= (char*) malloc(len); + if (!pval) { + ErrorF("[xkb] Allocation error: %s proprerty not created\n", + _XKB_RF_NAMES_PROP_ATOM); + return TRUE; + } + out= 0; + if (XkbRulesUsed) { + strcpy(&pval[out],XkbRulesUsed); + out+= strlen(XkbRulesUsed); + } + pval[out++]= '\0'; + if (XkbModelUsed) { + strcpy(&pval[out],XkbModelUsed); + out+= strlen(XkbModelUsed); + } + pval[out++]= '\0'; + if (XkbLayoutUsed) { + strcpy(&pval[out],XkbLayoutUsed); + out+= strlen(XkbLayoutUsed); + } + pval[out++]= '\0'; + if (XkbVariantUsed) { + strcpy(&pval[out],XkbVariantUsed); + out+= strlen(XkbVariantUsed); + } + pval[out++]= '\0'; + if (XkbOptionsUsed) { + strcpy(&pval[out],XkbOptionsUsed); + out+= strlen(XkbOptionsUsed); + } + pval[out++]= '\0'; + if (out!=len) { + ErrorF("[xkb] Internal Error! bad size (%d!=%d) for _XKB_RULES_NAMES\n", + out,len); + } + dixChangeWindowProperty(serverClient, WindowTable[0], name, XA_STRING, 8, + PropModeReplace, len, pval, TRUE); + free(pval); + return TRUE; +} + +static void +XkbSetRulesUsed(XkbRMLVOSet *rmlvo) +{ + if (XkbRulesUsed) + free(XkbRulesUsed); + XkbRulesUsed= (rmlvo->rules?_XkbDupString(rmlvo->rules):NULL); + if (XkbModelUsed) + free(XkbModelUsed); + XkbModelUsed= (rmlvo->model?_XkbDupString(rmlvo->model):NULL); + if (XkbLayoutUsed) + free(XkbLayoutUsed); + XkbLayoutUsed= (rmlvo->layout?_XkbDupString(rmlvo->layout):NULL); + if (XkbVariantUsed) + free(XkbVariantUsed); + XkbVariantUsed= (rmlvo->variant?_XkbDupString(rmlvo->variant):NULL); + if (XkbOptionsUsed) + free(XkbOptionsUsed); + XkbOptionsUsed= (rmlvo->options?_XkbDupString(rmlvo->options):NULL); + if (XkbWantRulesProp) + QueueWorkProc(XkbWriteRulesProp,NULL,NULL); + return; +} + +void +XkbSetRulesDflts(XkbRMLVOSet *rmlvo) +{ + if (rmlvo->rules) { + if (XkbRulesDflt) + free(XkbRulesDflt); + XkbRulesDflt= _XkbDupString(rmlvo->rules); + } + if (rmlvo->model) { + if (XkbModelDflt) + free(XkbModelDflt); + XkbModelDflt= _XkbDupString(rmlvo->model); + } + if (rmlvo->layout) { + if (XkbLayoutDflt) + free(XkbLayoutDflt); + XkbLayoutDflt= _XkbDupString(rmlvo->layout); + } + if (rmlvo->variant) { + if (XkbVariantDflt) + free(XkbVariantDflt); + XkbVariantDflt= _XkbDupString(rmlvo->variant); + } + if (rmlvo->options) { + if (XkbOptionsDflt) + free(XkbOptionsDflt); + XkbOptionsDflt= _XkbDupString(rmlvo->options); + } + return; +} + +void +XkbDeleteRulesDflts(void) +{ + free(XkbRulesDflt); + XkbRulesDflt = NULL; + free(XkbModelDflt); + XkbModelDflt = NULL; + free(XkbLayoutDflt); + XkbLayoutDflt = NULL; + free(XkbVariantDflt); + XkbVariantDflt = NULL; + free(XkbOptionsDflt); + XkbOptionsDflt = NULL; + + XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE); + xkb_cached_map = NULL; +} + +#define DIFFERS(a, b) (strcmp((a) ? (a) : "", (b) ? (b) : "") != 0) + +static Bool +XkbCompareUsedRMLVO(XkbRMLVOSet *rmlvo) +{ + if (DIFFERS(rmlvo->rules, XkbRulesUsed) || + DIFFERS(rmlvo->model, XkbModelUsed) || + DIFFERS(rmlvo->layout, XkbLayoutUsed) || + DIFFERS(rmlvo->variant, XkbVariantUsed) || + DIFFERS(rmlvo->options, XkbOptionsUsed)) + return FALSE; + return TRUE; +} + +#undef DIFFERS + +/***====================================================================***/ + +#include "xkbDflts.h" + +static Bool +XkbInitKeyTypes(XkbDescPtr xkb) +{ + if (xkb->defined & XkmTypesMask) + return TRUE; + + initTypeNames(NULL); + if (XkbAllocClientMap(xkb,XkbKeyTypesMask,num_dflt_types)!=Success) + return FALSE; + if (XkbCopyKeyTypes(dflt_types,xkb->map->types,num_dflt_types)!= + Success) { + return FALSE; + } + xkb->map->size_types= xkb->map->num_types= num_dflt_types; + return TRUE; +} + +static void +XkbInitRadioGroups(XkbSrvInfoPtr xkbi) +{ + xkbi->nRadioGroups = 0; + xkbi->radioGroups = NULL; + return; +} + + +static Status +XkbInitCompatStructs(XkbDescPtr xkb) +{ +register int i; +XkbCompatMapPtr compat; + + if (xkb->defined & XkmCompatMapMask) + return TRUE; + + if (XkbAllocCompatMap(xkb,XkbAllCompatMask,num_dfltSI)!=Success) + return BadAlloc; + compat = xkb->compat; + if (compat->sym_interpret) { + compat->num_si = num_dfltSI; + memcpy((char *)compat->sym_interpret,(char *)dfltSI,sizeof(dfltSI)); + } + for (i=0;i<XkbNumKbdGroups;i++) { + compat->groups[i]= compatMap.groups[i]; + if (compat->groups[i].vmods!=0) { + unsigned mask; + mask= XkbMaskForVMask(xkb,compat->groups[i].vmods); + compat->groups[i].mask= compat->groups[i].real_mods|mask; + } + else compat->groups[i].mask= compat->groups[i].real_mods; + } + return Success; +} + +static void +XkbInitSemantics(XkbDescPtr xkb) +{ + XkbInitKeyTypes(xkb); + XkbInitCompatStructs(xkb); + return; +} + +/***====================================================================***/ + +static Status +XkbInitNames(XkbSrvInfoPtr xkbi) +{ +XkbDescPtr xkb; +XkbNamesPtr names; +Status rtrn; +Atom unknown; + + xkb= xkbi->desc; + if ((rtrn=XkbAllocNames(xkb,XkbAllNamesMask,0,0))!=Success) + return rtrn; + unknown= CREATE_ATOM("unknown"); + names = xkb->names; + if (names->keycodes==None) names->keycodes= unknown; + if (names->geometry==None) names->geometry= unknown; + if (names->phys_symbols==None) names->phys_symbols= unknown; + if (names->symbols==None) names->symbols= unknown; + if (names->types==None) names->types= unknown; + if (names->compat==None) names->compat= unknown; + if (!(xkb->defined & XkmVirtualModsMask)) { + if (names->vmods[vmod_NumLock]==None) + names->vmods[vmod_NumLock]= CREATE_ATOM("NumLock"); + if (names->vmods[vmod_Alt]==None) + names->vmods[vmod_Alt]= CREATE_ATOM("Alt"); + if (names->vmods[vmod_AltGr]==None) + names->vmods[vmod_AltGr]= CREATE_ATOM("ModeSwitch"); + } + + if (!(xkb->defined & XkmIndicatorsMask) || + !(xkb->defined & XkmGeometryMask)) { + initIndicatorNames(NULL,xkb); + if (names->indicators[LED_CAPS-1]==None) + names->indicators[LED_CAPS-1] = CREATE_ATOM("Caps Lock"); + if (names->indicators[LED_NUM-1]==None) + names->indicators[LED_NUM-1] = CREATE_ATOM("Num Lock"); + if (names->indicators[LED_SCROLL-1]==None) + names->indicators[LED_SCROLL-1] = CREATE_ATOM("Scroll Lock"); +#ifdef LED_COMPOSE + if (names->indicators[LED_COMPOSE-1]==None) + names->indicators[LED_COMPOSE-1] = CREATE_ATOM("Compose"); +#endif + } + + if (xkb->geom!=NULL) + names->geometry= xkb->geom->name; + else names->geometry= unknown; + + return Success; +} + +static Status +XkbInitIndicatorMap(XkbSrvInfoPtr xkbi) +{ +XkbDescPtr xkb; +XkbIndicatorPtr map; +XkbSrvLedInfoPtr sli; + + xkb= xkbi->desc; + if (XkbAllocIndicatorMaps(xkb)!=Success) + return BadAlloc; + + if (!(xkb->defined & XkmIndicatorsMask)) { + map= xkb->indicators; + map->phys_indicators = PHYS_LEDS; + map->maps[LED_CAPS-1].flags= XkbIM_NoExplicit; + map->maps[LED_CAPS-1].which_mods= XkbIM_UseLocked; + map->maps[LED_CAPS-1].mods.mask= LockMask; + map->maps[LED_CAPS-1].mods.real_mods= LockMask; + + map->maps[LED_NUM-1].flags= XkbIM_NoExplicit; + map->maps[LED_NUM-1].which_mods= XkbIM_UseLocked; + map->maps[LED_NUM-1].mods.mask= 0; + map->maps[LED_NUM-1].mods.real_mods= 0; + map->maps[LED_NUM-1].mods.vmods= vmod_NumLockMask; + + map->maps[LED_SCROLL-1].flags= XkbIM_NoExplicit; + map->maps[LED_SCROLL-1].which_mods= XkbIM_UseLocked; + map->maps[LED_SCROLL-1].mods.mask= Mod3Mask; + map->maps[LED_SCROLL-1].mods.real_mods= Mod3Mask; + } + + sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0); + if (sli) + XkbCheckIndicatorMaps(xkbi->device,sli,XkbAllIndicatorsMask); + + return Success; +} + +static Status +XkbInitControls(DeviceIntPtr pXDev,XkbSrvInfoPtr xkbi) +{ +XkbDescPtr xkb; +XkbControlsPtr ctrls; + + xkb= xkbi->desc; + /* 12/31/94 (ef) -- XXX! Should check if controls loaded from file */ + if (XkbAllocControls(xkb,XkbAllControlsMask)!=Success) + FatalError("Couldn't allocate keyboard controls\n"); + ctrls= xkb->ctrls; + if (!(xkb->defined & XkmSymbolsMask)) + ctrls->num_groups = 1; + ctrls->groups_wrap = XkbSetGroupInfo(1,XkbWrapIntoRange,0); + ctrls->internal.mask = 0; + ctrls->internal.real_mods = 0; + ctrls->internal.vmods = 0; + ctrls->ignore_lock.mask = 0; + ctrls->ignore_lock.real_mods = 0; + ctrls->ignore_lock.vmods = 0; + ctrls->enabled_ctrls = XkbAccessXTimeoutMask|XkbRepeatKeysMask| + XkbMouseKeysAccelMask|XkbAudibleBellMask| + XkbIgnoreGroupLockMask; + if (XkbWantAccessX) + ctrls->enabled_ctrls|= XkbAccessXKeysMask; + AccessXInit(pXDev); + return Success; +} + +_X_EXPORT Bool +InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet *rmlvo, + BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func) +{ + int i; + unsigned int check; + XkbSrvInfoPtr xkbi; + XkbDescPtr xkb; + XkbSrvLedInfoPtr sli; + XkbChangesRec changes; + XkbEventCauseRec cause; + XkbRMLVOSet rmlvo_dflts = { NULL }; + + if (dev->key || dev->kbdfeed) + return FALSE; + + if (!rmlvo) + { + rmlvo = &rmlvo_dflts; + XkbGetRulesDflts(rmlvo); + } + + + memset(&changes, 0, sizeof(changes)); + XkbSetCauseUnknown(&cause); + + dev->key = calloc(1, sizeof(*dev->key)); + if (!dev->key) { + ErrorF("XKB: Failed to allocate key class\n"); + return FALSE; + } + dev->key->sourceid = dev->id; + + dev->kbdfeed = calloc(1, sizeof(*dev->kbdfeed)); + if (!dev->kbdfeed) { + ErrorF("XKB: Failed to allocate key feedback class\n"); + goto unwind_key; + } + + xkbi = calloc(1, sizeof(*xkbi)); + if (!xkbi) { + ErrorF("XKB: Failed to allocate XKB info\n"); + goto unwind_kbdfeed; + } + dev->key->xkbInfo = xkbi; + + if (xkb_cached_map && !XkbCompareUsedRMLVO(rmlvo)) { + XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE); + xkb_cached_map = NULL; + } + + if (xkb_cached_map) + LogMessageVerb(X_INFO, 4, "XKB: Reusing cached keymap\n"); + else { + xkb_cached_map = XkbCompileKeymap(dev, rmlvo); + if (!xkb_cached_map) { + ErrorF("XKB: Failed to compile keymap\n"); + goto unwind_info; + } + } + + xkb = XkbAllocKeyboard(); + if (!xkb) { + ErrorF("XKB: Failed to allocate keyboard description\n"); + goto unwind_info; + } + + if (!XkbCopyKeymap(xkb, xkb_cached_map)) { + ErrorF("XKB: Failed to copy keymap\n"); + goto unwind_desc; + } + xkb->defined = xkb_cached_map->defined; + xkb->flags = xkb_cached_map->flags; + xkb->device_spec = xkb_cached_map->device_spec; + xkbi->desc = xkb; + + if (xkb->min_key_code == 0) + xkb->min_key_code = 8; + if (xkb->max_key_code == 0) + xkb->max_key_code = 255; + + i = XkbNumKeys(xkb) / 3 + 1; + if (XkbAllocClientMap(xkb, XkbAllClientInfoMask, 0) != Success) + goto unwind_desc; + if (XkbAllocServerMap(xkb, XkbAllServerInfoMask, i) != Success) + goto unwind_desc; + + xkbi->dfltPtrDelta = 1; + xkbi->device = dev; + + XkbInitSemantics(xkb); + XkbInitNames(xkbi); + XkbInitRadioGroups(xkbi); + + XkbInitControls(dev, xkbi); + + XkbInitIndicatorMap(xkbi); + + XkbUpdateActions(dev, xkb->min_key_code, XkbNumKeys(xkb), &changes, + &check, &cause); + + InitFocusClassDeviceStruct(dev); + + xkbi->kbdProc = ctrl_func; + dev->kbdfeed->BellProc = bell_func; + dev->kbdfeed->CtrlProc = XkbDDXKeybdCtrlProc; + + dev->kbdfeed->ctrl = defaultKeyboardControl; + if (dev->kbdfeed->ctrl.autoRepeat) + xkb->ctrls->enabled_ctrls |= XkbRepeatKeysMask; + + memcpy(dev->kbdfeed->ctrl.autoRepeats, xkb->ctrls->per_key_repeat, + XkbPerKeyBitArraySize); + + sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0); + if (sli) + XkbCheckIndicatorMaps(dev, sli, XkbAllIndicatorsMask); + else + DebugF("XKB: No indicator feedback in XkbFinishInit!\n"); + + dev->kbdfeed->CtrlProc(dev,&dev->kbdfeed->ctrl); + + XkbSetRulesDflts(rmlvo); + XkbSetRulesUsed(rmlvo); + XkbFreeRMLVOSet(&rmlvo_dflts, FALSE); + + return TRUE; + +unwind_desc: + XkbFreeKeyboard(xkb, 0, TRUE); +unwind_info: + free(xkbi); + dev->key->xkbInfo = NULL; +unwind_kbdfeed: + free(dev->kbdfeed); + dev->kbdfeed = NULL; +unwind_key: + free(dev->key); + dev->key = NULL; + return FALSE; +} + + +/***====================================================================***/ + + /* + * Be very careful about what does and doesn't get freed by this + * function. To reduce fragmentation, XkbInitDevice allocates a + * single huge block per device and divides it up into most of the + * fixed-size structures for the device. Don't free anything that + * is part of this larger block. + */ +void +XkbFreeInfo(XkbSrvInfoPtr xkbi) +{ + if (xkbi->radioGroups) { + free(xkbi->radioGroups); + xkbi->radioGroups= NULL; + } + if (xkbi->mouseKeyTimer) { + TimerFree(xkbi->mouseKeyTimer); + xkbi->mouseKeyTimer= NULL; + } + if (xkbi->slowKeysTimer) { + TimerFree(xkbi->slowKeysTimer); + xkbi->slowKeysTimer= NULL; + } + if (xkbi->bounceKeysTimer) { + TimerFree(xkbi->bounceKeysTimer); + xkbi->bounceKeysTimer= NULL; + } + if (xkbi->repeatKeyTimer) { + TimerFree(xkbi->repeatKeyTimer); + xkbi->repeatKeyTimer= NULL; + } + if (xkbi->krgTimer) { + TimerFree(xkbi->krgTimer); + xkbi->krgTimer= NULL; + } + xkbi->beepType= _BEEP_NONE; + if (xkbi->beepTimer) { + TimerFree(xkbi->beepTimer); + xkbi->beepTimer= NULL; + } + if (xkbi->desc) { + XkbFreeKeyboard(xkbi->desc,XkbAllComponentsMask,TRUE); + xkbi->desc= NULL; + } + free(xkbi); + return; +} + +/***====================================================================***/ + +extern int XkbDfltRepeatDelay; +extern int XkbDfltRepeatInterval; + +extern unsigned short XkbDfltAccessXTimeout; +extern unsigned int XkbDfltAccessXTimeoutMask; +extern unsigned int XkbDfltAccessXFeedback; +extern unsigned char XkbDfltAccessXOptions; + +int +XkbProcessArguments(int argc,char *argv[],int i) +{ + if (strncmp(argv[i], "-xkbdir", 7) == 0) { + if(++i < argc) { +#if !defined(WIN32) && !defined(__CYGWIN__) + if (getuid() != geteuid()) { + LogMessage(X_WARNING, "-xkbdir is not available for setuid X servers\n"); + return -1; + } else +#endif + { + if (strlen(argv[i]) < PATH_MAX) { + XkbBaseDirectory= argv[i]; + return 2; + } else { + LogMessage(X_ERROR, "-xkbdir pathname too long\n"); + return -1; + } + } + } + else { + return -1; + } + } + else if ((strncmp(argv[i],"-accessx",8)==0)|| + (strncmp(argv[i],"+accessx",8)==0)) { + int j=1; + if (argv[i][0]=='-') + XkbWantAccessX= 0; + else { + XkbWantAccessX= 1; + + if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) { + XkbDfltAccessXTimeout = atoi(argv[++i]); + j++; + + if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) { + /* + * presumption that the reasonably useful range of + * values fits in 0..MAXINT since SunOS 4 doesn't + * have strtoul. + */ + XkbDfltAccessXTimeoutMask=(unsigned int) + strtol(argv[++i],NULL,16); + j++; + } + if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) { + if (argv[++i][0] == '1' ) + XkbDfltAccessXFeedback=XkbAccessXFeedbackMask; + else + XkbDfltAccessXFeedback=0; + j++; + } + if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) { + XkbDfltAccessXOptions=(unsigned char) + strtol(argv[++i],NULL,16); + j++; + } + } + } + return j; + } + if ((strcmp(argv[i], "-ardelay") == 0) || + (strcmp (argv[i], "-ar1") == 0)) { /* -ardelay int */ + if (++i >= argc) UseMsg (); + XkbDfltRepeatDelay = (long)atoi(argv[i]); + return 2; + } + if ((strcmp(argv[i], "-arinterval") == 0) || + (strcmp (argv[i], "-ar2") == 0)) { /* -arinterval int */ + if (++i >= argc) UseMsg (); + XkbDfltRepeatInterval = (long)atoi(argv[i]); + return 2; + } + return 0; +} + +void +XkbUseMsg(void) +{ + ErrorF("[+-]accessx [ timeout [ timeout_mask [ feedback [ options_mask] ] ] ]\n"); + ErrorF(" enable/disable accessx key sequences\n"); + ErrorF("-ardelay set XKB autorepeat delay\n"); + ErrorF("-arinterval set XKB autorepeat interval\n"); +} diff --git a/xorg-server/xkb/xkbLEDs.c b/xorg-server/xkb/xkbLEDs.c index 8c28513ec..a0a037fd7 100644 --- a/xorg-server/xkb/xkbLEDs.c +++ b/xorg-server/xkb/xkbLEDs.c @@ -1,977 +1,977 @@ -/************************************************************ -Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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 <dix-config.h> -#endif - -#include <stdio.h> -#include <ctype.h> -#include <math.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#include "misc.h" -#include "inputstr.h" - -#include <X11/extensions/XI.h> -#include <xkbsrv.h> -#include "xkb.h" - -/***====================================================================***/ - - /* - * unsigned - * XkbIndicatorsToUpdate(dev,changed,check_devs_rtrn) - * - * Given a keyboard and a set of state components that have changed, - * this function returns the indicators on the default keyboard - * feedback that might be affected. It also reports whether or not - * any extension devices might be affected in check_devs_rtrn. - */ - -unsigned -XkbIndicatorsToUpdate( DeviceIntPtr dev, - unsigned long state_changes, - Bool enable_changes) -{ -register unsigned update= 0; -XkbSrvLedInfoPtr sli; - - sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0); - - if (!sli) - return update; - - if (state_changes&(XkbModifierStateMask|XkbGroupStateMask)) - update|= sli->usesEffective; - if (state_changes&(XkbModifierBaseMask|XkbGroupBaseMask)) - update|= sli->usesBase; - if (state_changes&(XkbModifierLatchMask|XkbGroupLatchMask)) - update|= sli->usesLatched; - if (state_changes&(XkbModifierLockMask|XkbGroupLockMask)) - update|= sli->usesLocked; - if (state_changes&XkbCompatStateMask) - update|= sli->usesCompat; - if (enable_changes) - update|= sli->usesControls; - return update; -} - -/***====================================================================***/ - - /* - * Bool - *XkbApplyLEDChangeToKeyboard(xkbi,map,on,change) - * - * Some indicators "drive" the keyboard when their state is explicitly - * changed, as described in section 9.2.1 of the XKB protocol spec. - * This function updates the state and controls for the keyboard - * specified by 'xkbi' to reflect any changes that are required - * when the indicator described by 'map' is turned on or off. The - * extent of the changes is reported in change, which must be defined. - */ -static Bool -XkbApplyLEDChangeToKeyboard( XkbSrvInfoPtr xkbi, - XkbIndicatorMapPtr map, - Bool on, - XkbChangesPtr change) -{ -Bool ctrlChange,stateChange; -XkbStatePtr state; - - if ((map->flags&XkbIM_NoExplicit)||((map->flags&XkbIM_LEDDrivesKB)==0)) - return FALSE; - ctrlChange= stateChange= FALSE; - if (map->ctrls) { - XkbControlsPtr ctrls= xkbi->desc->ctrls; - unsigned old; - - old= ctrls->enabled_ctrls; - if (on) ctrls->enabled_ctrls|= map->ctrls; - else ctrls->enabled_ctrls&= ~map->ctrls; - if (old!=ctrls->enabled_ctrls) { - change->ctrls.changed_ctrls= XkbControlsEnabledMask; - change->ctrls.enabled_ctrls_changes= old^ctrls->enabled_ctrls; - ctrlChange= TRUE; - } - } - state= &xkbi->state; - if ((map->groups)&&((map->which_groups&(~XkbIM_UseBase))!=0)) { - register int i; - register unsigned bit,match; - - if (on) match= (map->groups)&XkbAllGroupsMask; - else match= (~map->groups)&XkbAllGroupsMask; - if (map->which_groups&(XkbIM_UseLocked|XkbIM_UseEffective)) { - for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { - if (bit&match) - break; - } - if (map->which_groups&XkbIM_UseLatched) - XkbLatchGroup(xkbi->device,0); /* unlatch group */ - state->locked_group= i; - stateChange= TRUE; - } - else if (map->which_groups&(XkbIM_UseLatched|XkbIM_UseEffective)) { - for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { - if (bit&match) - break; - } - state->locked_group= 0; - XkbLatchGroup(xkbi->device,i); - stateChange= TRUE; - } - } - if ((map->mods.mask)&&((map->which_mods&(~XkbIM_UseBase))!=0)) { - if (map->which_mods&(XkbIM_UseLocked|XkbIM_UseEffective)) { - register unsigned long old; - old= state->locked_mods; - if (on) state->locked_mods|= map->mods.mask; - else state->locked_mods&= ~map->mods.mask; - if (state->locked_mods!=old) - stateChange= TRUE; - } - if (map->which_mods&(XkbIM_UseLatched|XkbIM_UseEffective)) { - register unsigned long newmods; - newmods= state->latched_mods; - if (on) newmods|= map->mods.mask; - else newmods&= ~map->mods.mask; - if (newmods!=state->locked_mods) { - newmods&= map->mods.mask; - XkbLatchModifiers(xkbi->device,map->mods.mask,newmods); - stateChange= TRUE; - } - } - } - return (stateChange || ctrlChange); -} - - /* - * Bool - * ComputeAutoState(map,state,ctrls) - * - * This function reports the effect of applying the specified - * indicator map given the specified state and controls, as - * described in section 9.2 of the XKB protocol specification. - */ - -static Bool -ComputeAutoState( XkbIndicatorMapPtr map, - XkbStatePtr state, - XkbControlsPtr ctrls) -{ -Bool on; -CARD8 mods,group; - - on= FALSE; - mods= group= 0; - if (map->which_mods&XkbIM_UseAnyMods) { - if (map->which_mods&XkbIM_UseBase) - mods|= state->base_mods; - if (map->which_mods&XkbIM_UseLatched) - mods|= state->latched_mods; - if (map->which_mods&XkbIM_UseLocked) - mods|= state->locked_mods; - if (map->which_mods&XkbIM_UseEffective) - mods|= state->mods; - if (map->which_mods&XkbIM_UseCompat) - mods|= state->compat_state; - on = ((map->mods.mask&mods)!=0); - on = on||((mods==0)&&(map->mods.mask==0)&&(map->mods.vmods==0)); - } - if (map->which_groups&XkbIM_UseAnyGroup) { - if (map->which_groups&XkbIM_UseBase) - group|= (1L << state->base_group); - if (map->which_groups&XkbIM_UseLatched) - group|= (1L << state->latched_group); - if (map->which_groups&XkbIM_UseLocked) - group|= (1L << state->locked_group); - if (map->which_groups&XkbIM_UseEffective) - group|= (1L << state->group); - on = on||(((map->groups&group)!=0)||(map->groups==0)); - } - if (map->ctrls) - on = on||(ctrls->enabled_ctrls&map->ctrls); - return on; -} - - -static void -XkbUpdateLedAutoState( DeviceIntPtr dev, - XkbSrvLedInfoPtr sli, - unsigned maps_to_check, - xkbExtensionDeviceNotify * ed, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ -DeviceIntPtr kbd; -XkbStatePtr state; -XkbControlsPtr ctrls; -XkbChangesRec my_changes; -xkbExtensionDeviceNotify my_ed; -register unsigned i,bit,affected; -register XkbIndicatorMapPtr map; -unsigned oldState; - - if ((maps_to_check==0)||(sli->maps==NULL)||(sli->mapsPresent==0)) - return; - - if (dev->key && dev->key->xkbInfo) - kbd= dev; - else kbd= inputInfo.keyboard; - - state= &kbd->key->xkbInfo->state; - ctrls= kbd->key->xkbInfo->desc->ctrls; - affected= maps_to_check; - oldState= sli->effectiveState; - sli->autoState&= ~affected; - for (i=0,bit=1;(i<XkbNumIndicators)&&(affected);i++,bit<<=1) { - if ((affected&bit)==0) - continue; - affected&= ~bit; - map= &sli->maps[i]; - if((!(map->flags&XkbIM_NoAutomatic))&&ComputeAutoState(map,state,ctrls)) - sli->autoState|= bit; - } - sli->effectiveState= (sli->autoState|sli->explicitState); - affected= sli->effectiveState^oldState; - if (affected==0) - return; - - if (ed==NULL) { - ed= &my_ed; - bzero((char *)ed,sizeof(xkbExtensionDeviceNotify)); - } - else if ((ed->reason&XkbXI_IndicatorsMask)&& - ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) { - XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); - } - - if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) { - if (changes==NULL) { - changes= &my_changes; - bzero((char *)changes,sizeof(XkbChangesRec)); - } - changes->indicators.state_changes|= affected; - } - - ed->reason|= XkbXI_IndicatorStateMask; - ed->ledClass= sli->class; - ed->ledID= sli->id; - ed->ledsDefined= sli->namesPresent|sli->mapsPresent; - ed->ledState= sli->effectiveState; - ed->unsupported= 0; - ed->supported= XkbXI_AllFeaturesMask; - - if (changes!=&my_changes) changes= NULL; - if (ed!=&my_ed) ed= NULL; - if (changes || ed) - XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); - return; -} - -static void -XkbUpdateAllDeviceIndicators(XkbChangesPtr changes,XkbEventCausePtr cause) -{ -DeviceIntPtr edev; -XkbSrvLedInfoPtr sli; - - for (edev=inputInfo.devices;edev!=NULL;edev=edev->next) { - if (edev->kbdfeed) { - KbdFeedbackPtr kf; - for (kf=edev->kbdfeed;kf!=NULL;kf=kf->next) { - if ((kf->xkb_sli==NULL)||(kf->xkb_sli->maps==NULL)) - continue; - sli= kf->xkb_sli; - XkbUpdateLedAutoState(edev,sli,sli->mapsPresent,NULL, - changes,cause); - - } - } - if (edev->leds) { - LedFeedbackPtr lf; - for (lf=edev->leds;lf!=NULL;lf=lf->next) { - if ((lf->xkb_sli==NULL)||(lf->xkb_sli->maps==NULL)) - continue; - sli= lf->xkb_sli; - XkbUpdateLedAutoState(edev,sli,sli->mapsPresent,NULL, - changes,cause); - - } - } - } - return; -} - - -/***====================================================================***/ - - /* - * void - * XkbSetIndicators(dev,affect,values,cause) - * - * Attempts to change the indicators specified in 'affect' to the - * states specified in 'values' for the default keyboard feedback - * on the keyboard specified by 'dev.' Attempts to change indicator - * state might be ignored or have no affect, depending on the XKB - * indicator map for any affected indicators, as described in section - * 9.2 of the XKB protocol specification. - * - * If 'changes' is non-NULL, this function notes any changes to the - * keyboard state, controls, or indicator state that result from this - * attempted change. If 'changes' is NULL, this function generates - * XKB events to report any such changes to interested clients. - * - * If 'cause' is non-NULL, it specifies the reason for the change, - * as reported in some XKB events. If it is NULL, this function - * assumes that the change is the result of a core protocol - * ChangeKeyboardMapping request. - */ - -void -XkbSetIndicators( DeviceIntPtr dev, - CARD32 affect, - CARD32 values, - XkbEventCausePtr cause) -{ -XkbSrvLedInfoPtr sli; -XkbChangesRec changes; -xkbExtensionDeviceNotify ed; -unsigned side_affected; - - bzero((char *)&changes,sizeof(XkbChangesRec)); - bzero((char *)&ed,sizeof(xkbExtensionDeviceNotify)); - sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0); - sli->explicitState&= ~affect; - sli->explicitState|= (affect&values); - XkbApplyLedStateChanges(dev,sli,affect,&ed,&changes,cause); - - side_affected= 0; - if (changes.state_changes!=0) - side_affected|= XkbIndicatorsToUpdate(dev,changes.state_changes,FALSE); - if (changes.ctrls.enabled_ctrls_changes) - side_affected|= sli->usesControls; - - if (side_affected) { - XkbUpdateLedAutoState(dev,sli,side_affected,&ed,&changes,cause); - affect|= side_affected; - } - if (changes.state_changes || changes.ctrls.enabled_ctrls_changes) - XkbUpdateAllDeviceIndicators(NULL,cause); - - XkbFlushLedEvents(dev,dev,sli,&ed,&changes,cause); - return; -} - -/***====================================================================***/ - -/***====================================================================***/ - - /* - * void - * XkbUpdateIndicators(dev,update,check_edevs,changes,cause) - * - * Applies the indicator maps for any indicators specified in - * 'update' from the default keyboard feedback on the device - * specified by 'dev.' - * - * If 'changes' is NULL, this function generates and XKB events - * required to report the necessary changes, otherwise it simply - * notes the indicators with changed state. - * - * If 'check_edevs' is TRUE, this function also checks the indicator - * maps for any open extension devices that have them, and updates - * the state of any extension device indicators as necessary. - */ - -void -XkbUpdateIndicators( DeviceIntPtr dev, - register CARD32 update, - Bool check_edevs, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ -XkbSrvLedInfoPtr sli; - - sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0); - XkbUpdateLedAutoState(dev,sli,update,NULL,changes,cause); - if (check_edevs) - XkbUpdateAllDeviceIndicators(changes,cause); - return; -} - -/***====================================================================***/ - -/***====================================================================***/ - - /* - * void - * XkbCheckIndicatorMaps(dev,sli,which) - * - * Updates the 'indicator accelerators' for the indicators specified - * by 'which' in the feedback specified by 'sli.' The indicator - * accelerators are internal to the server and are used to simplify - * and speed up the process of figuring out which indicators might - * be affected by a particular change in keyboard state or controls. - */ - -void -XkbCheckIndicatorMaps(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned which) -{ -register unsigned i,bit; -XkbIndicatorMapPtr map; -XkbDescPtr xkb; - - if ((sli->flags&XkbSLI_HasOwnState)==0) - return; - - sli->usesBase&= ~which; - sli->usesLatched&= ~which; - sli->usesLocked&= ~which; - sli->usesEffective&= ~which; - sli->usesCompat&= ~which; - sli->usesControls&= ~which; - sli->mapsPresent&= ~which; - - xkb= dev->key->xkbInfo->desc; - for (i=0,bit=1,map=sli->maps;i<XkbNumIndicators;i++,bit<<=1,map++) { - if (which&bit) { - CARD8 what; - - if (!map || !XkbIM_InUse(map)) - continue; - sli->mapsPresent|= bit; - - what= (map->which_mods|map->which_groups); - if (what&XkbIM_UseBase) - sli->usesBase|= bit; - if (what&XkbIM_UseLatched) - sli->usesLatched|= bit; - if (what&XkbIM_UseLocked) - sli->usesLocked|= bit; - if (what&XkbIM_UseEffective) - sli->usesEffective|= bit; - if (what&XkbIM_UseCompat) - sli->usesCompat|= bit; - if (map->ctrls) - sli->usesControls|= bit; - - map->mods.mask= map->mods.real_mods; - if (map->mods.vmods!=0) { - map->mods.mask|= XkbMaskForVMask(xkb,map->mods.vmods); - } - } - } - sli->usedComponents= 0; - if (sli->usesBase) - sli->usedComponents|= XkbModifierBaseMask|XkbGroupBaseMask; - if (sli->usesLatched) - sli->usedComponents|= XkbModifierLatchMask|XkbGroupLatchMask; - if (sli->usesLocked) - sli->usedComponents|= XkbModifierLockMask|XkbGroupLockMask; - if (sli->usesEffective) - sli->usedComponents|= XkbModifierStateMask|XkbGroupStateMask; - if (sli->usesCompat) - sli->usedComponents|= XkbCompatStateMask; - return; -} - -/***====================================================================***/ - - /* - * XkbSrvLedInfoPtr - * XkbAllocSrvLedInfo(dev,kf,lf,needed_parts) - * - * Allocates an XkbSrvLedInfoPtr for the feedback specified by either - * 'kf' or 'lf' on the keyboard specified by 'dev.' - * - * If 'needed_parts' is non-zero, this function makes sure that any - * of the parts speicified therein are allocated. - */ -XkbSrvLedInfoPtr -XkbAllocSrvLedInfo( DeviceIntPtr dev, - KbdFeedbackPtr kf, - LedFeedbackPtr lf, - unsigned needed_parts) -{ -XkbSrvLedInfoPtr sli; -Bool checkAccel; -Bool checkNames; - - sli= NULL; - checkAccel= checkNames= FALSE; - if ((kf!=NULL)&&(kf->xkb_sli==NULL)) { - kf->xkb_sli= sli= xcalloc(1, sizeof(XkbSrvLedInfoRec)); - if (sli==NULL) - return NULL; /* ALLOCATION ERROR */ - if (dev->key && dev->key->xkbInfo) - sli->flags= XkbSLI_HasOwnState; - else sli->flags= 0; - sli->class= KbdFeedbackClass; - sli->id= kf->ctrl.id; - sli->fb.kf= kf; - - sli->autoState= 0; - sli->explicitState= kf->ctrl.leds; - sli->effectiveState= kf->ctrl.leds; - - if ((kf==dev->kbdfeed) && (dev->key) && (dev->key->xkbInfo)) { - XkbDescPtr xkb; - xkb= dev->key->xkbInfo->desc; - sli->flags|= XkbSLI_IsDefault; - sli->physIndicators= xkb->indicators->phys_indicators; - sli->names= xkb->names->indicators; - sli->maps= xkb->indicators->maps; - checkNames= checkAccel= TRUE; - } - else { - sli->physIndicators= XkbAllIndicatorsMask; - sli->names= NULL; - sli->maps= NULL; - } - } - else if ((kf!=NULL)&&((kf->xkb_sli->flags&XkbSLI_IsDefault)!=0)) { - XkbDescPtr xkb; - xkb= dev->key->xkbInfo->desc; - sli->physIndicators= xkb->indicators->phys_indicators; - if (xkb->names->indicators!=sli->names) { - checkNames= TRUE; - sli->names= xkb->names->indicators; - } - if (xkb->indicators->maps!=sli->maps) { - checkAccel= TRUE; - sli->maps= xkb->indicators->maps; - } - } - else if ((lf!=NULL)&&(lf->xkb_sli==NULL)) { - lf->xkb_sli= sli= xcalloc(1, sizeof(XkbSrvLedInfoRec)); - if (sli==NULL) - return NULL; /* ALLOCATION ERROR */ - if (dev->key && dev->key->xkbInfo) - sli->flags= XkbSLI_HasOwnState; - else sli->flags= 0; - sli->class= LedFeedbackClass; - sli->id= lf->ctrl.id; - sli->fb.lf= lf; - - sli->physIndicators= lf->ctrl.led_mask; - sli->autoState= 0; - sli->explicitState= lf->ctrl.led_values; - sli->effectiveState= lf->ctrl.led_values; - sli->maps= NULL; - sli->names= NULL; - } - if ((sli->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask)) - sli->names= xcalloc(XkbNumIndicators, sizeof(Atom)); - if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask)) - sli->maps= xcalloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec)); - if (checkNames) { - register unsigned i,bit; - sli->namesPresent= 0; - for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { - if (sli->names[i]!=None) - sli->namesPresent|= bit; - } - } - if (checkAccel) - XkbCheckIndicatorMaps(dev,sli,XkbAllIndicatorsMask); - return sli; -} - -void -XkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli) -{ - if ((sli->flags&XkbSLI_IsDefault)==0) { - if (sli->maps) xfree(sli->maps); - if (sli->names) xfree(sli->names); - } - sli->maps= NULL; - sli->names= NULL; - xfree(sli); - return; -} - -/* - * XkbSrvLedInfoPtr - * XkbCopySrvLedInfo(dev,src,kf,lf) - * - * Takes the given XkbSrvLedInfoPtr and duplicates it. A deep copy is made, - * thus the new copy behaves like the original one and can be freed with - * XkbFreeSrvLedInfo. - */ -XkbSrvLedInfoPtr -XkbCopySrvLedInfo( DeviceIntPtr from, - XkbSrvLedInfoPtr src, - KbdFeedbackPtr kf, - LedFeedbackPtr lf) -{ - XkbSrvLedInfoPtr sli_new = NULL; - - if (!src) - goto finish; - - sli_new = xcalloc(1, sizeof( XkbSrvLedInfoRec)); - if (!sli_new) - goto finish; - - memcpy(sli_new, src, sizeof(XkbSrvLedInfoRec)); - if (sli_new->class == KbdFeedbackClass) - sli_new->fb.kf = kf; - else - sli_new->fb.lf = lf; - - if (!(sli_new->flags & XkbSLI_IsDefault)) { - sli_new->names= xcalloc(XkbNumIndicators, sizeof(Atom)); - sli_new->maps= xcalloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec)); - } /* else sli_new->names/maps is pointing to - dev->key->xkbInfo->desc->names->indicators; - dev->key->xkbInfo->desc->names->indicators; */ - -finish: - return sli_new; -} - -/***====================================================================***/ - - /* - * XkbSrvLedInfoPtr - * XkbFindSrvLedInfo(dev,class,id,needed_parts) - * - * Finds the XkbSrvLedInfoPtr for the specified 'class' and 'id' - * on the device specified by 'dev.' If the class and id specify - * a valid device feedback, this function returns the existing - * feedback or allocates a new one. - * - */ - -XkbSrvLedInfoPtr -XkbFindSrvLedInfo( DeviceIntPtr dev, - unsigned class, - unsigned id, - unsigned needed_parts) -{ -XkbSrvLedInfoPtr sli; - - /* optimization to check for most common case */ - if (((class==XkbDfltXIClass)&&(id==XkbDfltXIId))&&(dev->kbdfeed)) { - XkbSrvLedInfoPtr sli; - sli= dev->kbdfeed->xkb_sli; - if (dev->kbdfeed->xkb_sli==NULL) { - sli= XkbAllocSrvLedInfo(dev,dev->kbdfeed,NULL,needed_parts); - dev->kbdfeed->xkb_sli= sli; - } - return dev->kbdfeed->xkb_sli; - } - - sli= NULL; - if (class==XkbDfltXIClass) { - if (dev->kbdfeed) class= KbdFeedbackClass; - else if (dev->leds) class= LedFeedbackClass; - else return NULL; - } - if (class==KbdFeedbackClass) { - KbdFeedbackPtr kf; - for (kf=dev->kbdfeed;kf!=NULL;kf=kf->next) { - if ((id==XkbDfltXIId)||(id==kf->ctrl.id)) { - if (kf->xkb_sli==NULL) - kf->xkb_sli= XkbAllocSrvLedInfo(dev,kf,NULL,needed_parts); - sli= kf->xkb_sli; - break; - } - } - } - else if (class==LedFeedbackClass) { - LedFeedbackPtr lf; - for (lf=dev->leds;lf!=NULL;lf=lf->next) { - if ((id==XkbDfltXIId)||(id==lf->ctrl.id)) { - if (lf->xkb_sli==NULL) - lf->xkb_sli= XkbAllocSrvLedInfo(dev,NULL,lf,needed_parts); - sli= lf->xkb_sli; - break; - } - } - } - if ((sli->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask)) - sli->names= xcalloc(XkbNumIndicators, sizeof(Atom)); - if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask)) - sli->maps= xcalloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec)); - return sli; -} - -/***====================================================================***/ - -void -XkbFlushLedEvents( DeviceIntPtr dev, - DeviceIntPtr kbd, - XkbSrvLedInfoPtr sli, - xkbExtensionDeviceNotify * ed, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ - if (changes) { - if (changes->indicators.state_changes) - XkbDDXUpdateDeviceIndicators(dev,sli,sli->effectiveState); - XkbSendNotification(kbd,changes,cause); - bzero((char *)changes,sizeof(XkbChangesRec)); - - if (XkbAX_NeedFeedback(kbd->key->xkbInfo->desc->ctrls, XkbAX_IndicatorFBMask)) { - if (sli->effectiveState) - /* it appears that the which parameter is not used */ - XkbDDXAccessXBeep(dev, _BEEP_LED_ON, XkbAccessXFeedbackMask); - else - XkbDDXAccessXBeep(dev, _BEEP_LED_OFF, XkbAccessXFeedbackMask); - } - } - if (ed) { - if (ed->reason) { - if ((dev!=kbd)&&(ed->reason&XkbXI_IndicatorStateMask)) - XkbDDXUpdateDeviceIndicators(dev,sli,sli->effectiveState); - XkbSendExtensionDeviceNotify(dev,cause->client,ed); - } - bzero((char *)ed,sizeof(XkbExtensionDeviceNotify)); - } - return; -} - -/***====================================================================***/ - -void -XkbApplyLedNameChanges( DeviceIntPtr dev, - XkbSrvLedInfoPtr sli, - unsigned changed_names, - xkbExtensionDeviceNotify * ed, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ -DeviceIntPtr kbd; -XkbChangesRec my_changes; -xkbExtensionDeviceNotify my_ed; - - if (changed_names==0) - return; - if (dev->key && dev->key->xkbInfo) - kbd= dev; - else kbd= inputInfo.keyboard; - - if (ed==NULL) { - ed= &my_ed; - bzero((char *)ed,sizeof(xkbExtensionDeviceNotify)); - } - else if ((ed->reason&XkbXI_IndicatorsMask)&& - ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) { - XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); - } - - if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) { - if (changes==NULL) { - changes= &my_changes; - bzero((char *)changes,sizeof(XkbChangesRec)); - } - changes->names.changed|= XkbIndicatorNamesMask; - changes->names.changed_indicators|= changed_names; - } - - ed->reason|= XkbXI_IndicatorNamesMask; - ed->ledClass= sli->class; - ed->ledID= sli->id; - ed->ledsDefined= sli->namesPresent|sli->mapsPresent; - ed->ledState= sli->effectiveState; - ed->unsupported= 0; - ed->supported= XkbXI_AllFeaturesMask; - - if (changes!=&my_changes) changes= NULL; - if (ed!=&my_ed) ed= NULL; - if (changes || ed) - XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); - return; -} -/***====================================================================***/ - - /* - * void - * XkbApplyLedMapChanges(dev,sli,changed_maps,changes,cause) - * - * Handles all of the secondary effects of the changes to the - * feedback specified by 'sli' on the device specified by 'dev.' - * - * If 'changed_maps' specifies any indicators, this function generates - * XkbExtensionDeviceNotify events and possibly IndicatorMapNotify - * events to report the changes, and recalculates the effective - * state of each indicator with a changed map. If any indicators - * change state, the server generates XkbExtensionDeviceNotify and - * XkbIndicatorStateNotify events as appropriate. - * - * If 'changes' is non-NULL, this function updates it to reflect - * any changes to the keyboard state or controls or to the 'core' - * indicator names, maps, or state. If 'changes' is NULL, this - * function generates XKB events as needed to report the changes. - * If 'dev' is not a keyboard device, any changes are reported - * for the core keyboard. - * - * The 'cause' specifies the reason for the event (key event or - * request) for the change, as reported in some XKB events. - */ - -void -XkbApplyLedMapChanges( DeviceIntPtr dev, - XkbSrvLedInfoPtr sli, - unsigned changed_maps, - xkbExtensionDeviceNotify * ed, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ -DeviceIntPtr kbd; -XkbChangesRec my_changes; -xkbExtensionDeviceNotify my_ed; - - if (changed_maps==0) - return; - if (dev->key && dev->key->xkbInfo) - kbd= dev; - else kbd= inputInfo.keyboard; - - if (ed==NULL) { - ed= &my_ed; - bzero((char *)ed,sizeof(xkbExtensionDeviceNotify)); - } - else if ((ed->reason&XkbXI_IndicatorsMask)&& - ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) { - XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); - } - - if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) { - if (changes==NULL) { - changes= &my_changes; - bzero((char *)changes,sizeof(XkbChangesRec)); - } - changes->indicators.map_changes|= changed_maps; - } - - XkbCheckIndicatorMaps(dev,sli,changed_maps); - - ed->reason|= XkbXI_IndicatorMapsMask; - ed->ledClass= sli->class; - ed->ledID= sli->id; - ed->ledsDefined= sli->namesPresent|sli->mapsPresent; - ed->ledState= sli->effectiveState; - ed->unsupported= 0; - ed->supported= XkbXI_AllFeaturesMask; - - XkbUpdateLedAutoState(dev,sli,changed_maps,ed,changes,cause); - - if (changes!=&my_changes) changes= NULL; - if (ed!=&my_ed) ed= NULL; - if (changes || ed) - XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); - return; -} - -/***====================================================================***/ - -void -XkbApplyLedStateChanges(DeviceIntPtr dev, - XkbSrvLedInfoPtr sli, - unsigned changed_leds, - xkbExtensionDeviceNotify * ed, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ -XkbSrvInfoPtr xkbi; -DeviceIntPtr kbd; -XkbChangesRec my_changes; -xkbExtensionDeviceNotify my_ed; -register unsigned i,bit,affected; -XkbIndicatorMapPtr map; -unsigned oldState; -Bool kb_changed; - - if (changed_leds==0) - return; - if (dev->key && dev->key->xkbInfo) - kbd= dev; - else kbd= inputInfo.keyboard; - xkbi= kbd->key->xkbInfo; - - if (changes==NULL) { - changes= &my_changes; - bzero((char *)changes,sizeof(XkbChangesRec)); - } - - kb_changed= FALSE; - affected= changed_leds; - oldState= sli->effectiveState; - for (i=0,bit=1;(i<XkbNumIndicators)&&(affected);i++,bit<<=1) { - if ((affected&bit)==0) - continue; - affected&= ~bit; - map= &sli->maps[i]; - if (map->flags&XkbIM_NoExplicit) { - sli->explicitState&= ~bit; - continue; - } - if (map->flags&XkbIM_LEDDrivesKB) { - Bool on= ((sli->explicitState&bit)!=0); - if (XkbApplyLEDChangeToKeyboard(xkbi,map,on,changes)) - kb_changed= TRUE; - } - } - sli->effectiveState= (sli->autoState|sli->explicitState); - affected= sli->effectiveState^oldState; - - if (ed==NULL) { - ed= &my_ed; - bzero((char *)ed,sizeof(xkbExtensionDeviceNotify)); - } - else if (affected&&(ed->reason&XkbXI_IndicatorsMask)&& - ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) { - XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); - } - - if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) - changes->indicators.state_changes|= affected; - if (affected) { - ed->reason|= XkbXI_IndicatorStateMask; - ed->ledClass= sli->class; - ed->ledID= sli->id; - ed->ledsDefined= sli->namesPresent|sli->mapsPresent; - ed->ledState= sli->effectiveState; - ed->unsupported= 0; - ed->supported= XkbXI_AllFeaturesMask; - } - - if (kb_changed) { - XkbComputeDerivedState(kbd->key->xkbInfo); - XkbUpdateLedAutoState(dev,sli,sli->mapsPresent,ed,changes,cause); - } - - if (changes!=&my_changes) changes= NULL; - if (ed!=&my_ed) ed= NULL; - if (changes || ed) - XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); - if (kb_changed) - XkbUpdateAllDeviceIndicators(NULL,cause); - return; -} +/************************************************************ +Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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 <dix-config.h> +#endif + +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "inputstr.h" + +#include <X11/extensions/XI.h> +#include <xkbsrv.h> +#include "xkb.h" + +/***====================================================================***/ + + /* + * unsigned + * XkbIndicatorsToUpdate(dev,changed,check_devs_rtrn) + * + * Given a keyboard and a set of state components that have changed, + * this function returns the indicators on the default keyboard + * feedback that might be affected. It also reports whether or not + * any extension devices might be affected in check_devs_rtrn. + */ + +unsigned +XkbIndicatorsToUpdate( DeviceIntPtr dev, + unsigned long state_changes, + Bool enable_changes) +{ +register unsigned update= 0; +XkbSrvLedInfoPtr sli; + + sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0); + + if (!sli) + return update; + + if (state_changes&(XkbModifierStateMask|XkbGroupStateMask)) + update|= sli->usesEffective; + if (state_changes&(XkbModifierBaseMask|XkbGroupBaseMask)) + update|= sli->usesBase; + if (state_changes&(XkbModifierLatchMask|XkbGroupLatchMask)) + update|= sli->usesLatched; + if (state_changes&(XkbModifierLockMask|XkbGroupLockMask)) + update|= sli->usesLocked; + if (state_changes&XkbCompatStateMask) + update|= sli->usesCompat; + if (enable_changes) + update|= sli->usesControls; + return update; +} + +/***====================================================================***/ + + /* + * Bool + *XkbApplyLEDChangeToKeyboard(xkbi,map,on,change) + * + * Some indicators "drive" the keyboard when their state is explicitly + * changed, as described in section 9.2.1 of the XKB protocol spec. + * This function updates the state and controls for the keyboard + * specified by 'xkbi' to reflect any changes that are required + * when the indicator described by 'map' is turned on or off. The + * extent of the changes is reported in change, which must be defined. + */ +static Bool +XkbApplyLEDChangeToKeyboard( XkbSrvInfoPtr xkbi, + XkbIndicatorMapPtr map, + Bool on, + XkbChangesPtr change) +{ +Bool ctrlChange,stateChange; +XkbStatePtr state; + + if ((map->flags&XkbIM_NoExplicit)||((map->flags&XkbIM_LEDDrivesKB)==0)) + return FALSE; + ctrlChange= stateChange= FALSE; + if (map->ctrls) { + XkbControlsPtr ctrls= xkbi->desc->ctrls; + unsigned old; + + old= ctrls->enabled_ctrls; + if (on) ctrls->enabled_ctrls|= map->ctrls; + else ctrls->enabled_ctrls&= ~map->ctrls; + if (old!=ctrls->enabled_ctrls) { + change->ctrls.changed_ctrls= XkbControlsEnabledMask; + change->ctrls.enabled_ctrls_changes= old^ctrls->enabled_ctrls; + ctrlChange= TRUE; + } + } + state= &xkbi->state; + if ((map->groups)&&((map->which_groups&(~XkbIM_UseBase))!=0)) { + register int i; + register unsigned bit,match; + + if (on) match= (map->groups)&XkbAllGroupsMask; + else match= (~map->groups)&XkbAllGroupsMask; + if (map->which_groups&(XkbIM_UseLocked|XkbIM_UseEffective)) { + for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { + if (bit&match) + break; + } + if (map->which_groups&XkbIM_UseLatched) + XkbLatchGroup(xkbi->device,0); /* unlatch group */ + state->locked_group= i; + stateChange= TRUE; + } + else if (map->which_groups&(XkbIM_UseLatched|XkbIM_UseEffective)) { + for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { + if (bit&match) + break; + } + state->locked_group= 0; + XkbLatchGroup(xkbi->device,i); + stateChange= TRUE; + } + } + if ((map->mods.mask)&&((map->which_mods&(~XkbIM_UseBase))!=0)) { + if (map->which_mods&(XkbIM_UseLocked|XkbIM_UseEffective)) { + register unsigned long old; + old= state->locked_mods; + if (on) state->locked_mods|= map->mods.mask; + else state->locked_mods&= ~map->mods.mask; + if (state->locked_mods!=old) + stateChange= TRUE; + } + if (map->which_mods&(XkbIM_UseLatched|XkbIM_UseEffective)) { + register unsigned long newmods; + newmods= state->latched_mods; + if (on) newmods|= map->mods.mask; + else newmods&= ~map->mods.mask; + if (newmods!=state->locked_mods) { + newmods&= map->mods.mask; + XkbLatchModifiers(xkbi->device,map->mods.mask,newmods); + stateChange= TRUE; + } + } + } + return (stateChange || ctrlChange); +} + + /* + * Bool + * ComputeAutoState(map,state,ctrls) + * + * This function reports the effect of applying the specified + * indicator map given the specified state and controls, as + * described in section 9.2 of the XKB protocol specification. + */ + +static Bool +ComputeAutoState( XkbIndicatorMapPtr map, + XkbStatePtr state, + XkbControlsPtr ctrls) +{ +Bool on; +CARD8 mods,group; + + on= FALSE; + mods= group= 0; + if (map->which_mods&XkbIM_UseAnyMods) { + if (map->which_mods&XkbIM_UseBase) + mods|= state->base_mods; + if (map->which_mods&XkbIM_UseLatched) + mods|= state->latched_mods; + if (map->which_mods&XkbIM_UseLocked) + mods|= state->locked_mods; + if (map->which_mods&XkbIM_UseEffective) + mods|= state->mods; + if (map->which_mods&XkbIM_UseCompat) + mods|= state->compat_state; + on = ((map->mods.mask&mods)!=0); + on = on||((mods==0)&&(map->mods.mask==0)&&(map->mods.vmods==0)); + } + if (map->which_groups&XkbIM_UseAnyGroup) { + if (map->which_groups&XkbIM_UseBase) + group|= (1L << state->base_group); + if (map->which_groups&XkbIM_UseLatched) + group|= (1L << state->latched_group); + if (map->which_groups&XkbIM_UseLocked) + group|= (1L << state->locked_group); + if (map->which_groups&XkbIM_UseEffective) + group|= (1L << state->group); + on = on||(((map->groups&group)!=0)||(map->groups==0)); + } + if (map->ctrls) + on = on||(ctrls->enabled_ctrls&map->ctrls); + return on; +} + + +static void +XkbUpdateLedAutoState( DeviceIntPtr dev, + XkbSrvLedInfoPtr sli, + unsigned maps_to_check, + xkbExtensionDeviceNotify * ed, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ +DeviceIntPtr kbd; +XkbStatePtr state; +XkbControlsPtr ctrls; +XkbChangesRec my_changes; +xkbExtensionDeviceNotify my_ed; +register unsigned i,bit,affected; +register XkbIndicatorMapPtr map; +unsigned oldState; + + if ((maps_to_check==0)||(sli->maps==NULL)||(sli->mapsPresent==0)) + return; + + if (dev->key && dev->key->xkbInfo) + kbd= dev; + else kbd= inputInfo.keyboard; + + state= &kbd->key->xkbInfo->state; + ctrls= kbd->key->xkbInfo->desc->ctrls; + affected= maps_to_check; + oldState= sli->effectiveState; + sli->autoState&= ~affected; + for (i=0,bit=1;(i<XkbNumIndicators)&&(affected);i++,bit<<=1) { + if ((affected&bit)==0) + continue; + affected&= ~bit; + map= &sli->maps[i]; + if((!(map->flags&XkbIM_NoAutomatic))&&ComputeAutoState(map,state,ctrls)) + sli->autoState|= bit; + } + sli->effectiveState= (sli->autoState|sli->explicitState); + affected= sli->effectiveState^oldState; + if (affected==0) + return; + + if (ed==NULL) { + ed= &my_ed; + bzero((char *)ed,sizeof(xkbExtensionDeviceNotify)); + } + else if ((ed->reason&XkbXI_IndicatorsMask)&& + ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) { + XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); + } + + if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) { + if (changes==NULL) { + changes= &my_changes; + bzero((char *)changes,sizeof(XkbChangesRec)); + } + changes->indicators.state_changes|= affected; + } + + ed->reason|= XkbXI_IndicatorStateMask; + ed->ledClass= sli->class; + ed->ledID= sli->id; + ed->ledsDefined= sli->namesPresent|sli->mapsPresent; + ed->ledState= sli->effectiveState; + ed->unsupported= 0; + ed->supported= XkbXI_AllFeaturesMask; + + if (changes!=&my_changes) changes= NULL; + if (ed!=&my_ed) ed= NULL; + if (changes || ed) + XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); + return; +} + +static void +XkbUpdateAllDeviceIndicators(XkbChangesPtr changes,XkbEventCausePtr cause) +{ +DeviceIntPtr edev; +XkbSrvLedInfoPtr sli; + + for (edev=inputInfo.devices;edev!=NULL;edev=edev->next) { + if (edev->kbdfeed) { + KbdFeedbackPtr kf; + for (kf=edev->kbdfeed;kf!=NULL;kf=kf->next) { + if ((kf->xkb_sli==NULL)||(kf->xkb_sli->maps==NULL)) + continue; + sli= kf->xkb_sli; + XkbUpdateLedAutoState(edev,sli,sli->mapsPresent,NULL, + changes,cause); + + } + } + if (edev->leds) { + LedFeedbackPtr lf; + for (lf=edev->leds;lf!=NULL;lf=lf->next) { + if ((lf->xkb_sli==NULL)||(lf->xkb_sli->maps==NULL)) + continue; + sli= lf->xkb_sli; + XkbUpdateLedAutoState(edev,sli,sli->mapsPresent,NULL, + changes,cause); + + } + } + } + return; +} + + +/***====================================================================***/ + + /* + * void + * XkbSetIndicators(dev,affect,values,cause) + * + * Attempts to change the indicators specified in 'affect' to the + * states specified in 'values' for the default keyboard feedback + * on the keyboard specified by 'dev.' Attempts to change indicator + * state might be ignored or have no affect, depending on the XKB + * indicator map for any affected indicators, as described in section + * 9.2 of the XKB protocol specification. + * + * If 'changes' is non-NULL, this function notes any changes to the + * keyboard state, controls, or indicator state that result from this + * attempted change. If 'changes' is NULL, this function generates + * XKB events to report any such changes to interested clients. + * + * If 'cause' is non-NULL, it specifies the reason for the change, + * as reported in some XKB events. If it is NULL, this function + * assumes that the change is the result of a core protocol + * ChangeKeyboardMapping request. + */ + +void +XkbSetIndicators( DeviceIntPtr dev, + CARD32 affect, + CARD32 values, + XkbEventCausePtr cause) +{ +XkbSrvLedInfoPtr sli; +XkbChangesRec changes; +xkbExtensionDeviceNotify ed; +unsigned side_affected; + + bzero((char *)&changes,sizeof(XkbChangesRec)); + bzero((char *)&ed,sizeof(xkbExtensionDeviceNotify)); + sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0); + sli->explicitState&= ~affect; + sli->explicitState|= (affect&values); + XkbApplyLedStateChanges(dev,sli,affect,&ed,&changes,cause); + + side_affected= 0; + if (changes.state_changes!=0) + side_affected|= XkbIndicatorsToUpdate(dev,changes.state_changes,FALSE); + if (changes.ctrls.enabled_ctrls_changes) + side_affected|= sli->usesControls; + + if (side_affected) { + XkbUpdateLedAutoState(dev,sli,side_affected,&ed,&changes,cause); + affect|= side_affected; + } + if (changes.state_changes || changes.ctrls.enabled_ctrls_changes) + XkbUpdateAllDeviceIndicators(NULL,cause); + + XkbFlushLedEvents(dev,dev,sli,&ed,&changes,cause); + return; +} + +/***====================================================================***/ + +/***====================================================================***/ + + /* + * void + * XkbUpdateIndicators(dev,update,check_edevs,changes,cause) + * + * Applies the indicator maps for any indicators specified in + * 'update' from the default keyboard feedback on the device + * specified by 'dev.' + * + * If 'changes' is NULL, this function generates and XKB events + * required to report the necessary changes, otherwise it simply + * notes the indicators with changed state. + * + * If 'check_edevs' is TRUE, this function also checks the indicator + * maps for any open extension devices that have them, and updates + * the state of any extension device indicators as necessary. + */ + +void +XkbUpdateIndicators( DeviceIntPtr dev, + register CARD32 update, + Bool check_edevs, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ +XkbSrvLedInfoPtr sli; + + sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0); + XkbUpdateLedAutoState(dev,sli,update,NULL,changes,cause); + if (check_edevs) + XkbUpdateAllDeviceIndicators(changes,cause); + return; +} + +/***====================================================================***/ + +/***====================================================================***/ + + /* + * void + * XkbCheckIndicatorMaps(dev,sli,which) + * + * Updates the 'indicator accelerators' for the indicators specified + * by 'which' in the feedback specified by 'sli.' The indicator + * accelerators are internal to the server and are used to simplify + * and speed up the process of figuring out which indicators might + * be affected by a particular change in keyboard state or controls. + */ + +void +XkbCheckIndicatorMaps(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned which) +{ +register unsigned i,bit; +XkbIndicatorMapPtr map; +XkbDescPtr xkb; + + if ((sli->flags&XkbSLI_HasOwnState)==0) + return; + + sli->usesBase&= ~which; + sli->usesLatched&= ~which; + sli->usesLocked&= ~which; + sli->usesEffective&= ~which; + sli->usesCompat&= ~which; + sli->usesControls&= ~which; + sli->mapsPresent&= ~which; + + xkb= dev->key->xkbInfo->desc; + for (i=0,bit=1,map=sli->maps;i<XkbNumIndicators;i++,bit<<=1,map++) { + if (which&bit) { + CARD8 what; + + if (!map || !XkbIM_InUse(map)) + continue; + sli->mapsPresent|= bit; + + what= (map->which_mods|map->which_groups); + if (what&XkbIM_UseBase) + sli->usesBase|= bit; + if (what&XkbIM_UseLatched) + sli->usesLatched|= bit; + if (what&XkbIM_UseLocked) + sli->usesLocked|= bit; + if (what&XkbIM_UseEffective) + sli->usesEffective|= bit; + if (what&XkbIM_UseCompat) + sli->usesCompat|= bit; + if (map->ctrls) + sli->usesControls|= bit; + + map->mods.mask= map->mods.real_mods; + if (map->mods.vmods!=0) { + map->mods.mask|= XkbMaskForVMask(xkb,map->mods.vmods); + } + } + } + sli->usedComponents= 0; + if (sli->usesBase) + sli->usedComponents|= XkbModifierBaseMask|XkbGroupBaseMask; + if (sli->usesLatched) + sli->usedComponents|= XkbModifierLatchMask|XkbGroupLatchMask; + if (sli->usesLocked) + sli->usedComponents|= XkbModifierLockMask|XkbGroupLockMask; + if (sli->usesEffective) + sli->usedComponents|= XkbModifierStateMask|XkbGroupStateMask; + if (sli->usesCompat) + sli->usedComponents|= XkbCompatStateMask; + return; +} + +/***====================================================================***/ + + /* + * XkbSrvLedInfoPtr + * XkbAllocSrvLedInfo(dev,kf,lf,needed_parts) + * + * Allocates an XkbSrvLedInfoPtr for the feedback specified by either + * 'kf' or 'lf' on the keyboard specified by 'dev.' + * + * If 'needed_parts' is non-zero, this function makes sure that any + * of the parts speicified therein are allocated. + */ +XkbSrvLedInfoPtr +XkbAllocSrvLedInfo( DeviceIntPtr dev, + KbdFeedbackPtr kf, + LedFeedbackPtr lf, + unsigned needed_parts) +{ +XkbSrvLedInfoPtr sli; +Bool checkAccel; +Bool checkNames; + + sli= NULL; + checkAccel= checkNames= FALSE; + if ((kf!=NULL)&&(kf->xkb_sli==NULL)) { + kf->xkb_sli= sli= calloc(1, sizeof(XkbSrvLedInfoRec)); + if (sli==NULL) + return NULL; /* ALLOCATION ERROR */ + if (dev->key && dev->key->xkbInfo) + sli->flags= XkbSLI_HasOwnState; + else sli->flags= 0; + sli->class= KbdFeedbackClass; + sli->id= kf->ctrl.id; + sli->fb.kf= kf; + + sli->autoState= 0; + sli->explicitState= kf->ctrl.leds; + sli->effectiveState= kf->ctrl.leds; + + if ((kf==dev->kbdfeed) && (dev->key) && (dev->key->xkbInfo)) { + XkbDescPtr xkb; + xkb= dev->key->xkbInfo->desc; + sli->flags|= XkbSLI_IsDefault; + sli->physIndicators= xkb->indicators->phys_indicators; + sli->names= xkb->names->indicators; + sli->maps= xkb->indicators->maps; + checkNames= checkAccel= TRUE; + } + else { + sli->physIndicators= XkbAllIndicatorsMask; + sli->names= NULL; + sli->maps= NULL; + } + } + else if ((kf!=NULL)&&((kf->xkb_sli->flags&XkbSLI_IsDefault)!=0)) { + XkbDescPtr xkb; + xkb= dev->key->xkbInfo->desc; + sli->physIndicators= xkb->indicators->phys_indicators; + if (xkb->names->indicators!=sli->names) { + checkNames= TRUE; + sli->names= xkb->names->indicators; + } + if (xkb->indicators->maps!=sli->maps) { + checkAccel= TRUE; + sli->maps= xkb->indicators->maps; + } + } + else if ((lf!=NULL)&&(lf->xkb_sli==NULL)) { + lf->xkb_sli= sli= calloc(1, sizeof(XkbSrvLedInfoRec)); + if (sli==NULL) + return NULL; /* ALLOCATION ERROR */ + if (dev->key && dev->key->xkbInfo) + sli->flags= XkbSLI_HasOwnState; + else sli->flags= 0; + sli->class= LedFeedbackClass; + sli->id= lf->ctrl.id; + sli->fb.lf= lf; + + sli->physIndicators= lf->ctrl.led_mask; + sli->autoState= 0; + sli->explicitState= lf->ctrl.led_values; + sli->effectiveState= lf->ctrl.led_values; + sli->maps= NULL; + sli->names= NULL; + } + if ((sli->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask)) + sli->names= calloc(XkbNumIndicators, sizeof(Atom)); + if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask)) + sli->maps= calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec)); + if (checkNames) { + register unsigned i,bit; + sli->namesPresent= 0; + for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) { + if (sli->names[i]!=None) + sli->namesPresent|= bit; + } + } + if (checkAccel) + XkbCheckIndicatorMaps(dev,sli,XkbAllIndicatorsMask); + return sli; +} + +void +XkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli) +{ + if ((sli->flags&XkbSLI_IsDefault)==0) { + if (sli->maps) free(sli->maps); + if (sli->names) free(sli->names); + } + sli->maps= NULL; + sli->names= NULL; + free(sli); + return; +} + +/* + * XkbSrvLedInfoPtr + * XkbCopySrvLedInfo(dev,src,kf,lf) + * + * Takes the given XkbSrvLedInfoPtr and duplicates it. A deep copy is made, + * thus the new copy behaves like the original one and can be freed with + * XkbFreeSrvLedInfo. + */ +XkbSrvLedInfoPtr +XkbCopySrvLedInfo( DeviceIntPtr from, + XkbSrvLedInfoPtr src, + KbdFeedbackPtr kf, + LedFeedbackPtr lf) +{ + XkbSrvLedInfoPtr sli_new = NULL; + + if (!src) + goto finish; + + sli_new = calloc(1, sizeof( XkbSrvLedInfoRec)); + if (!sli_new) + goto finish; + + memcpy(sli_new, src, sizeof(XkbSrvLedInfoRec)); + if (sli_new->class == KbdFeedbackClass) + sli_new->fb.kf = kf; + else + sli_new->fb.lf = lf; + + if (!(sli_new->flags & XkbSLI_IsDefault)) { + sli_new->names= calloc(XkbNumIndicators, sizeof(Atom)); + sli_new->maps= calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec)); + } /* else sli_new->names/maps is pointing to + dev->key->xkbInfo->desc->names->indicators; + dev->key->xkbInfo->desc->names->indicators; */ + +finish: + return sli_new; +} + +/***====================================================================***/ + + /* + * XkbSrvLedInfoPtr + * XkbFindSrvLedInfo(dev,class,id,needed_parts) + * + * Finds the XkbSrvLedInfoPtr for the specified 'class' and 'id' + * on the device specified by 'dev.' If the class and id specify + * a valid device feedback, this function returns the existing + * feedback or allocates a new one. + * + */ + +XkbSrvLedInfoPtr +XkbFindSrvLedInfo( DeviceIntPtr dev, + unsigned class, + unsigned id, + unsigned needed_parts) +{ +XkbSrvLedInfoPtr sli; + + /* optimization to check for most common case */ + if (((class==XkbDfltXIClass)&&(id==XkbDfltXIId))&&(dev->kbdfeed)) { + XkbSrvLedInfoPtr sli; + sli= dev->kbdfeed->xkb_sli; + if (dev->kbdfeed->xkb_sli==NULL) { + sli= XkbAllocSrvLedInfo(dev,dev->kbdfeed,NULL,needed_parts); + dev->kbdfeed->xkb_sli= sli; + } + return dev->kbdfeed->xkb_sli; + } + + sli= NULL; + if (class==XkbDfltXIClass) { + if (dev->kbdfeed) class= KbdFeedbackClass; + else if (dev->leds) class= LedFeedbackClass; + else return NULL; + } + if (class==KbdFeedbackClass) { + KbdFeedbackPtr kf; + for (kf=dev->kbdfeed;kf!=NULL;kf=kf->next) { + if ((id==XkbDfltXIId)||(id==kf->ctrl.id)) { + if (kf->xkb_sli==NULL) + kf->xkb_sli= XkbAllocSrvLedInfo(dev,kf,NULL,needed_parts); + sli= kf->xkb_sli; + break; + } + } + } + else if (class==LedFeedbackClass) { + LedFeedbackPtr lf; + for (lf=dev->leds;lf!=NULL;lf=lf->next) { + if ((id==XkbDfltXIId)||(id==lf->ctrl.id)) { + if (lf->xkb_sli==NULL) + lf->xkb_sli= XkbAllocSrvLedInfo(dev,NULL,lf,needed_parts); + sli= lf->xkb_sli; + break; + } + } + } + if ((sli->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask)) + sli->names= calloc(XkbNumIndicators, sizeof(Atom)); + if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask)) + sli->maps= calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec)); + return sli; +} + +/***====================================================================***/ + +void +XkbFlushLedEvents( DeviceIntPtr dev, + DeviceIntPtr kbd, + XkbSrvLedInfoPtr sli, + xkbExtensionDeviceNotify * ed, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ + if (changes) { + if (changes->indicators.state_changes) + XkbDDXUpdateDeviceIndicators(dev,sli,sli->effectiveState); + XkbSendNotification(kbd,changes,cause); + bzero((char *)changes,sizeof(XkbChangesRec)); + + if (XkbAX_NeedFeedback(kbd->key->xkbInfo->desc->ctrls, XkbAX_IndicatorFBMask)) { + if (sli->effectiveState) + /* it appears that the which parameter is not used */ + XkbDDXAccessXBeep(dev, _BEEP_LED_ON, XkbAccessXFeedbackMask); + else + XkbDDXAccessXBeep(dev, _BEEP_LED_OFF, XkbAccessXFeedbackMask); + } + } + if (ed) { + if (ed->reason) { + if ((dev!=kbd)&&(ed->reason&XkbXI_IndicatorStateMask)) + XkbDDXUpdateDeviceIndicators(dev,sli,sli->effectiveState); + XkbSendExtensionDeviceNotify(dev,cause->client,ed); + } + bzero((char *)ed,sizeof(XkbExtensionDeviceNotify)); + } + return; +} + +/***====================================================================***/ + +void +XkbApplyLedNameChanges( DeviceIntPtr dev, + XkbSrvLedInfoPtr sli, + unsigned changed_names, + xkbExtensionDeviceNotify * ed, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ +DeviceIntPtr kbd; +XkbChangesRec my_changes; +xkbExtensionDeviceNotify my_ed; + + if (changed_names==0) + return; + if (dev->key && dev->key->xkbInfo) + kbd= dev; + else kbd= inputInfo.keyboard; + + if (ed==NULL) { + ed= &my_ed; + bzero((char *)ed,sizeof(xkbExtensionDeviceNotify)); + } + else if ((ed->reason&XkbXI_IndicatorsMask)&& + ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) { + XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); + } + + if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) { + if (changes==NULL) { + changes= &my_changes; + bzero((char *)changes,sizeof(XkbChangesRec)); + } + changes->names.changed|= XkbIndicatorNamesMask; + changes->names.changed_indicators|= changed_names; + } + + ed->reason|= XkbXI_IndicatorNamesMask; + ed->ledClass= sli->class; + ed->ledID= sli->id; + ed->ledsDefined= sli->namesPresent|sli->mapsPresent; + ed->ledState= sli->effectiveState; + ed->unsupported= 0; + ed->supported= XkbXI_AllFeaturesMask; + + if (changes!=&my_changes) changes= NULL; + if (ed!=&my_ed) ed= NULL; + if (changes || ed) + XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); + return; +} +/***====================================================================***/ + + /* + * void + * XkbApplyLedMapChanges(dev,sli,changed_maps,changes,cause) + * + * Handles all of the secondary effects of the changes to the + * feedback specified by 'sli' on the device specified by 'dev.' + * + * If 'changed_maps' specifies any indicators, this function generates + * XkbExtensionDeviceNotify events and possibly IndicatorMapNotify + * events to report the changes, and recalculates the effective + * state of each indicator with a changed map. If any indicators + * change state, the server generates XkbExtensionDeviceNotify and + * XkbIndicatorStateNotify events as appropriate. + * + * If 'changes' is non-NULL, this function updates it to reflect + * any changes to the keyboard state or controls or to the 'core' + * indicator names, maps, or state. If 'changes' is NULL, this + * function generates XKB events as needed to report the changes. + * If 'dev' is not a keyboard device, any changes are reported + * for the core keyboard. + * + * The 'cause' specifies the reason for the event (key event or + * request) for the change, as reported in some XKB events. + */ + +void +XkbApplyLedMapChanges( DeviceIntPtr dev, + XkbSrvLedInfoPtr sli, + unsigned changed_maps, + xkbExtensionDeviceNotify * ed, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ +DeviceIntPtr kbd; +XkbChangesRec my_changes; +xkbExtensionDeviceNotify my_ed; + + if (changed_maps==0) + return; + if (dev->key && dev->key->xkbInfo) + kbd= dev; + else kbd= inputInfo.keyboard; + + if (ed==NULL) { + ed= &my_ed; + bzero((char *)ed,sizeof(xkbExtensionDeviceNotify)); + } + else if ((ed->reason&XkbXI_IndicatorsMask)&& + ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) { + XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); + } + + if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) { + if (changes==NULL) { + changes= &my_changes; + bzero((char *)changes,sizeof(XkbChangesRec)); + } + changes->indicators.map_changes|= changed_maps; + } + + XkbCheckIndicatorMaps(dev,sli,changed_maps); + + ed->reason|= XkbXI_IndicatorMapsMask; + ed->ledClass= sli->class; + ed->ledID= sli->id; + ed->ledsDefined= sli->namesPresent|sli->mapsPresent; + ed->ledState= sli->effectiveState; + ed->unsupported= 0; + ed->supported= XkbXI_AllFeaturesMask; + + XkbUpdateLedAutoState(dev,sli,changed_maps,ed,changes,cause); + + if (changes!=&my_changes) changes= NULL; + if (ed!=&my_ed) ed= NULL; + if (changes || ed) + XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); + return; +} + +/***====================================================================***/ + +void +XkbApplyLedStateChanges(DeviceIntPtr dev, + XkbSrvLedInfoPtr sli, + unsigned changed_leds, + xkbExtensionDeviceNotify * ed, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ +XkbSrvInfoPtr xkbi; +DeviceIntPtr kbd; +XkbChangesRec my_changes; +xkbExtensionDeviceNotify my_ed; +register unsigned i,bit,affected; +XkbIndicatorMapPtr map; +unsigned oldState; +Bool kb_changed; + + if (changed_leds==0) + return; + if (dev->key && dev->key->xkbInfo) + kbd= dev; + else kbd= inputInfo.keyboard; + xkbi= kbd->key->xkbInfo; + + if (changes==NULL) { + changes= &my_changes; + bzero((char *)changes,sizeof(XkbChangesRec)); + } + + kb_changed= FALSE; + affected= changed_leds; + oldState= sli->effectiveState; + for (i=0,bit=1;(i<XkbNumIndicators)&&(affected);i++,bit<<=1) { + if ((affected&bit)==0) + continue; + affected&= ~bit; + map= &sli->maps[i]; + if (map->flags&XkbIM_NoExplicit) { + sli->explicitState&= ~bit; + continue; + } + if (map->flags&XkbIM_LEDDrivesKB) { + Bool on= ((sli->explicitState&bit)!=0); + if (XkbApplyLEDChangeToKeyboard(xkbi,map,on,changes)) + kb_changed= TRUE; + } + } + sli->effectiveState= (sli->autoState|sli->explicitState); + affected= sli->effectiveState^oldState; + + if (ed==NULL) { + ed= &my_ed; + bzero((char *)ed,sizeof(xkbExtensionDeviceNotify)); + } + else if (affected&&(ed->reason&XkbXI_IndicatorsMask)&& + ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) { + XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); + } + + if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) + changes->indicators.state_changes|= affected; + if (affected) { + ed->reason|= XkbXI_IndicatorStateMask; + ed->ledClass= sli->class; + ed->ledID= sli->id; + ed->ledsDefined= sli->namesPresent|sli->mapsPresent; + ed->ledState= sli->effectiveState; + ed->unsupported= 0; + ed->supported= XkbXI_AllFeaturesMask; + } + + if (kb_changed) { + XkbComputeDerivedState(kbd->key->xkbInfo); + XkbUpdateLedAutoState(dev,sli,sli->mapsPresent,ed,changes,cause); + } + + if (changes!=&my_changes) changes= NULL; + if (ed!=&my_ed) ed= NULL; + if (changes || ed) + XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause); + if (kb_changed) + XkbUpdateAllDeviceIndicators(NULL,cause); + return; +} diff --git a/xorg-server/xkb/xkbUtils.c b/xorg-server/xkb/xkbUtils.c index 6d0901a36..286fab073 100644 --- a/xorg-server/xkb/xkbUtils.c +++ b/xorg-server/xkb/xkbUtils.c @@ -1,2192 +1,2192 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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. - -********************************************************/ -/* - -Copyright © 2008 Red Hat Inc. - -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. - -*/ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "os.h" -#include <stdio.h> -#include <ctype.h> -#include <math.h> -#include <X11/X.h> -#include <X11/Xproto.h> -#define XK_CYRILLIC -#include <X11/keysym.h> -#include "misc.h" -#include "inputstr.h" -#include "eventstr.h" - -#define XKBSRV_NEED_FILE_FUNCS -#include <xkbsrv.h> -#include "xkbgeom.h" -#include "xkb.h" - -/***====================================================================***/ - -int -_XkbLookupAnyDevice(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - int rc = XkbKeyboardErrorCode; - - if (id == XkbUseCoreKbd) - id = PickKeyboard(client)->id; - else if (id == XkbUseCorePtr) - id = PickPointer(client)->id; - - rc = dixLookupDevice(pDev, id, client, access_mode); - if (rc != Success) - *xkb_err = XkbErr_BadDevice; - - return rc; -} - -int -_XkbLookupKeyboard(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - DeviceIntPtr dev; - int rc; - - if (id == XkbDfltXIId) - id = XkbUseCoreKbd; - - rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); - if (rc != Success) - return rc; - - dev = *pDev; - if (!dev->key || !dev->key->xkbInfo) { - *pDev = NULL; - *xkb_err= XkbErr_BadClass; - return XkbKeyboardErrorCode; - } - return Success; -} - -int -_XkbLookupBellDevice(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - DeviceIntPtr dev; - int rc; - - rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); - if (rc != Success) - return rc; - - dev = *pDev; - if (!dev->kbdfeed && !dev->bell) { - *pDev = NULL; - *xkb_err= XkbErr_BadClass; - return XkbKeyboardErrorCode; - } - return Success; -} - -int -_XkbLookupLedDevice(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - DeviceIntPtr dev; - int rc; - - if (id == XkbDfltXIId) - id = XkbUseCorePtr; - - rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); - if (rc != Success) - return rc; - - dev = *pDev; - if (!dev->kbdfeed && !dev->leds) { - *pDev = NULL; - *xkb_err= XkbErr_BadClass; - return XkbKeyboardErrorCode; - } - return Success; -} - -int -_XkbLookupButtonDevice(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - DeviceIntPtr dev; - int rc; - - rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); - if (rc != Success) - return rc; - - dev = *pDev; - if (!dev->button) { - *pDev = NULL; - *xkb_err= XkbErr_BadClass; - return XkbKeyboardErrorCode; - } - return Success; -} - -void -XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods) -{ -register unsigned tmp; - - switch (act->type) { - case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: - if (act->mods.flags&XkbSA_UseModMapMods) - act->mods.real_mods= act->mods.mask= mods; - if ((tmp= XkbModActionVMods(&act->mods))!=0) - act->mods.mask|= XkbMaskForVMask(xkb,tmp); - break; - case XkbSA_ISOLock: - if (act->iso.flags&XkbSA_UseModMapMods) - act->iso.real_mods= act->iso.mask= mods; - if ((tmp= XkbModActionVMods(&act->iso))!=0) - act->iso.mask|= XkbMaskForVMask(xkb,tmp); - break; - } - return; -} - -unsigned -XkbMaskForVMask(XkbDescPtr xkb,unsigned vmask) -{ -register int i,bit; -register unsigned mask; - - for (mask=i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - if (vmask&bit) - mask|= xkb->server->vmods[i]; - } - return mask; -} - -/***====================================================================***/ - -void -XkbUpdateKeyTypesFromCore( DeviceIntPtr pXDev, - KeySymsPtr pCore, - KeyCode first, - CARD8 num, - XkbChangesPtr changes) -{ -XkbDescPtr xkb; -unsigned key,nG,explicit; -int types[XkbNumKbdGroups]; -KeySym tsyms[XkbMaxSymsPerKey],*syms; -XkbMapChangesPtr mc; - - xkb= pXDev->key->xkbInfo->desc; - if (first+num-1>xkb->max_key_code) { - /* 1/12/95 (ef) -- XXX! should allow XKB structures to grow */ - num= xkb->max_key_code-first+1; - } - - mc= (changes?(&changes->map):NULL); - - syms= &pCore->map[(first - pCore->minKeyCode) * pCore->mapWidth]; - for (key=first; key<(first+num); key++,syms+= pCore->mapWidth) { - explicit= xkb->server->explicit[key]&XkbExplicitKeyTypesMask; - types[XkbGroup1Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index); - types[XkbGroup2Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup2Index); - types[XkbGroup3Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup3Index); - types[XkbGroup4Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup4Index); - nG= XkbKeyTypesForCoreSymbols(xkb,pCore->mapWidth,syms,explicit,types, - tsyms); - XkbChangeTypesOfKey(xkb,key,nG,XkbAllGroupsMask,types,mc); - memcpy((char *)XkbKeySymsPtr(xkb,key),(char *)tsyms, - XkbKeyNumSyms(xkb,key)*sizeof(KeySym)); - } - if (changes->map.changed&XkbKeySymsMask) { - CARD8 oldLast,newLast; - oldLast = changes->map.first_key_sym+changes->map.num_key_syms-1; - newLast = first+num-1; - - if (first<changes->map.first_key_sym) - changes->map.first_key_sym = first; - if (oldLast>newLast) - newLast= oldLast; - changes->map.num_key_syms = newLast-changes->map.first_key_sym+1; - } - else { - changes->map.changed|= XkbKeySymsMask; - changes->map.first_key_sym = first; - changes->map.num_key_syms = num; - } - return; -} - -void -XkbUpdateDescActions( XkbDescPtr xkb, - KeyCode first, - CARD8 num, - XkbChangesPtr changes) -{ -register unsigned key; - - for (key=first;key<(first+num);key++) { - XkbApplyCompatMapToKey(xkb,key,changes); - } - - if (changes->map.changed&(XkbVirtualModMapMask|XkbModifierMapMask)) { - unsigned char newVMods[XkbNumVirtualMods]; - register unsigned bit,i; - unsigned present; - - bzero(newVMods,XkbNumVirtualMods); - present= 0; - for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { - if (xkb->server->vmodmap[key]==0) - continue; - for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - if (bit&xkb->server->vmodmap[key]) { - present|= bit; - newVMods[i]|= xkb->map->modmap[key]; - } - } - } - for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - if ((bit&present)&&(newVMods[i]!=xkb->server->vmods[i])) { - changes->map.changed|= XkbVirtualModsMask; - changes->map.vmods|= bit; - xkb->server->vmods[i]= newVMods[i]; - } - } - } - if (changes->map.changed&XkbVirtualModsMask) - XkbApplyVirtualModChanges(xkb,changes->map.vmods,changes); - - if (changes->map.changed&XkbKeyActionsMask) { - CARD8 oldLast,newLast; - oldLast= changes->map.first_key_act+changes->map.num_key_acts-1; - newLast = first+num-1; - - if (first<changes->map.first_key_act) - changes->map.first_key_act = first; - if (newLast>oldLast) - newLast= oldLast; - changes->map.num_key_acts= newLast-changes->map.first_key_act+1; - } - else { - changes->map.changed|= XkbKeyActionsMask; - changes->map.first_key_act = first; - changes->map.num_key_acts = num; - } - return; -} - -void -XkbUpdateActions( DeviceIntPtr pXDev, - KeyCode first, - CARD8 num, - XkbChangesPtr changes, - unsigned * needChecksRtrn, - XkbEventCausePtr cause) -{ -XkbSrvInfoPtr xkbi; -XkbDescPtr xkb; -CARD8 * repeat; - - if (needChecksRtrn) - *needChecksRtrn= 0; - xkbi= pXDev->key->xkbInfo; - xkb= xkbi->desc; - repeat= xkb->ctrls->per_key_repeat; - - if (pXDev->kbdfeed) - memcpy(repeat,pXDev->kbdfeed->ctrl.autoRepeats,XkbPerKeyBitArraySize); - - XkbUpdateDescActions(xkb,first,num,changes); - - if ((pXDev->kbdfeed)&& - (changes->ctrls.enabled_ctrls_changes&XkbPerKeyRepeatMask)) { - memcpy(pXDev->kbdfeed->ctrl.autoRepeats,repeat, XkbPerKeyBitArraySize); - (*pXDev->kbdfeed->CtrlProc)(pXDev, &pXDev->kbdfeed->ctrl); - } - return; -} - -KeySymsPtr -XkbGetCoreMap(DeviceIntPtr keybd) -{ -register int key,tmp; -int maxSymsPerKey, maxGroup1Width; -XkbDescPtr xkb; -KeySymsPtr syms; -int maxNumberOfGroups; - - if (!keybd || !keybd->key || !keybd->key->xkbInfo) - return NULL; - - xkb= keybd->key->xkbInfo->desc; - maxSymsPerKey= maxGroup1Width= 0; - maxNumberOfGroups = 0; - - /* determine sizes */ - for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { - if (XkbKeycodeInRange(xkb,key)) { - int nGroups; - int w; - nGroups= XkbKeyNumGroups(xkb,key); - tmp= 0; - if (nGroups>0) { - if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup1Index))<=2) - tmp+= 2; - else tmp+= w + 2; - /* remember highest G1 width */ - if (w > maxGroup1Width) - maxGroup1Width = w; - } - if (nGroups>1) { - if (tmp <= 2) { - if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))<2) - tmp+= 2; - else tmp+= w; - } else { - if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))>2) - tmp+= w - 2; - } - } - if (nGroups>2) - tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup3Index); - if (nGroups>3) - tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup4Index); - if (tmp>maxSymsPerKey) - maxSymsPerKey= tmp; - if (nGroups > maxNumberOfGroups) - maxNumberOfGroups = nGroups; - } - } - - if (maxSymsPerKey <= 0) - return NULL; - - syms = xcalloc(1, sizeof(*syms)); - if (!syms) - return NULL; - - /* See Section 12.4 of the XKB Protocol spec. Because of the - * single-group distribution for multi-group keyboards, we have to - * have enough symbols for the largest group 1 to replicate across the - * number of groups on the keyboard. e.g. a single-group key with 4 - * symbols on a keyboard that has 3 groups -> 12 syms per key */ - if (maxSymsPerKey < maxNumberOfGroups * maxGroup1Width) - maxSymsPerKey = maxNumberOfGroups * maxGroup1Width; - - syms->mapWidth = maxSymsPerKey; - syms->minKeyCode = xkb->min_key_code; - syms->maxKeyCode = xkb->max_key_code; - - tmp = syms->mapWidth * (xkb->max_key_code - xkb->min_key_code + 1); - syms->map = xcalloc(tmp, sizeof(*syms->map)); - if (!syms->map) { - xfree(syms); - return NULL; - } - - for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { - KeySym *pCore,*pXKB; - unsigned nGroups,groupWidth,n,nOut; - - nGroups= XkbKeyNumGroups(xkb,key); - n= (key-xkb->min_key_code)*syms->mapWidth; - pCore= &syms->map[n]; - pXKB= XkbKeySymsPtr(xkb,key); - nOut= 2; - if (nGroups>0) { - groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup1Index); - if (groupWidth>0) pCore[0]= pXKB[0]; - if (groupWidth>1) pCore[1]= pXKB[1]; - for (n=2;n<groupWidth;n++) - pCore[2+n]= pXKB[n]; - if (groupWidth>2) - nOut= groupWidth; - } - - /* See XKB Protocol Sec, Section 12.4. - A 1-group key with ABCDE on a 2 group keyboard must be - duplicated across all groups as ABABCDECDE. - */ - if (nGroups == 1) - { - int idx, j; - - groupWidth = XkbKeyGroupWidth(xkb, key, XkbGroup1Index); - - /* AB..CDE... -> ABABCDE... */ - if (groupWidth > 0 && syms->mapWidth >= 3) - pCore[2] = pCore[0]; - if (groupWidth > 1 && syms->mapWidth >= 4) - pCore[3] = pCore[1]; - - /* ABABCDE... -> ABABCDECDE */ - idx = 2 + groupWidth; - while (groupWidth > 2 && idx < syms->mapWidth && - idx < groupWidth * 2) - { - pCore[idx] = pCore[idx - groupWidth + 2]; - idx++; - } - idx = 2 * groupWidth; - if (idx < 4) - idx = 4; - /* 3 or more groups: ABABCDECDEABCDEABCDE */ - for (j = 3; j <= maxNumberOfGroups; j++) - for (n = 0; n < groupWidth && idx < maxSymsPerKey; n++) - pCore[idx++] = pXKB[n]; - } - - pXKB+= XkbKeyGroupsWidth(xkb,key); - nOut+= 2; - if (nGroups>1) { - groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup2Index); - if (groupWidth>0) pCore[2]= pXKB[0]; - if (groupWidth>1) pCore[3]= pXKB[1]; - for (n=2;n<groupWidth;n++) { - pCore[nOut+(n-2)]= pXKB[n]; - } - if (groupWidth>2) - nOut+= (groupWidth-2); - } - pXKB+= XkbKeyGroupsWidth(xkb,key); - for (n=XkbGroup3Index;n<nGroups;n++) { - register int s; - groupWidth= XkbKeyGroupWidth(xkb,key,n); - for (s=0;s<groupWidth;s++) { - pCore[nOut++]= pXKB[s]; - } - pXKB+= XkbKeyGroupsWidth(xkb,key); - } - } - - return syms; -} - -void -XkbSetRepeatKeys(DeviceIntPtr pXDev,int key,int onoff) -{ - if (pXDev && pXDev->key && pXDev->key->xkbInfo) { - xkbControlsNotify cn; - XkbControlsPtr ctrls = pXDev->key->xkbInfo->desc->ctrls; - XkbControlsRec old; - old = *ctrls; - - if (key== -1) { /* global autorepeat setting changed */ - if (onoff) ctrls->enabled_ctrls |= XkbRepeatKeysMask; - else ctrls->enabled_ctrls &= ~XkbRepeatKeysMask; - } - else if (pXDev->kbdfeed) { - ctrls->per_key_repeat[key/8] = - pXDev->kbdfeed->ctrl.autoRepeats[key/8]; - } - - if (XkbComputeControlsNotify(pXDev,&old,ctrls,&cn,TRUE)) - XkbSendControlsNotify(pXDev,&cn); - } - return; -} - -/* Applies a change to a single device, does not traverse the device tree. */ -void -XkbApplyMappingChange(DeviceIntPtr kbd, KeySymsPtr map, KeyCode first_key, - CARD8 num_keys, CARD8 *modmap, ClientPtr client) -{ - XkbDescPtr xkb = kbd->key->xkbInfo->desc; - XkbEventCauseRec cause; - XkbChangesRec changes; - unsigned int check; - - memset(&changes, 0, sizeof(changes)); - memset(&cause, 0, sizeof(cause)); - - if (map && first_key && num_keys) { - check = 0; - XkbSetCauseCoreReq(&cause, X_ChangeKeyboardMapping, client); - - XkbUpdateKeyTypesFromCore(kbd, map, first_key, num_keys, &changes); - XkbUpdateActions(kbd, first_key, num_keys, &changes, &check, &cause); - - if (check) - XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause); - } - - if (modmap) { - /* A keymap change can imply a modmap change, se we prefer the - * former. */ - if (!cause.mjr) - XkbSetCauseCoreReq(&cause,X_SetModifierMapping,client); - - check = 0; - num_keys = xkb->max_key_code - xkb->min_key_code + 1; - changes.map.changed |= XkbModifierMapMask; - changes.map.first_modmap_key = xkb->min_key_code; - changes.map.num_modmap_keys = num_keys; - memcpy(kbd->key->xkbInfo->desc->map->modmap, modmap, MAP_LENGTH); - XkbUpdateActions(kbd, xkb->min_key_code, num_keys, &changes, &check, - &cause); - - if (check) - XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause); - } - - XkbSendNotification(kbd, &changes, &cause); -} - -void -XkbDisableComputedAutoRepeats(DeviceIntPtr dev,unsigned key) -{ -XkbSrvInfoPtr xkbi = dev->key->xkbInfo; -xkbMapNotify mn; - - xkbi->desc->server->explicit[key]|= XkbExplicitAutoRepeatMask; - bzero(&mn,sizeof(mn)); - mn.changed= XkbExplicitComponentsMask; - mn.firstKeyExplicit= key; - mn.nKeyExplicit= 1; - XkbSendMapNotify(dev,&mn); - return; -} - -unsigned -XkbStateChangedFlags(XkbStatePtr old,XkbStatePtr new) -{ -int changed; - - changed=(old->group!=new->group?XkbGroupStateMask:0); - changed|=(old->base_group!=new->base_group?XkbGroupBaseMask:0); - changed|=(old->latched_group!=new->latched_group?XkbGroupLatchMask:0); - changed|=(old->locked_group!=new->locked_group?XkbGroupLockMask:0); - changed|=(old->mods!=new->mods?XkbModifierStateMask:0); - changed|=(old->base_mods!=new->base_mods?XkbModifierBaseMask:0); - changed|=(old->latched_mods!=new->latched_mods?XkbModifierLatchMask:0); - changed|=(old->locked_mods!=new->locked_mods?XkbModifierLockMask:0); - changed|=(old->compat_state!=new->compat_state?XkbCompatStateMask:0); - changed|=(old->grab_mods!=new->grab_mods?XkbGrabModsMask:0); - if (old->compat_grab_mods!=new->compat_grab_mods) - changed|= XkbCompatGrabModsMask; - changed|=(old->lookup_mods!=new->lookup_mods?XkbLookupModsMask:0); - if (old->compat_lookup_mods!=new->compat_lookup_mods) - changed|= XkbCompatLookupModsMask; - changed|=(old->ptr_buttons!=new->ptr_buttons?XkbPointerButtonMask:0); - return changed; -} - -static void -XkbComputeCompatState(XkbSrvInfoPtr xkbi) -{ -CARD16 grp_mask; -XkbStatePtr state= &xkbi->state; -XkbCompatMapPtr map; - - if (!state || !xkbi->desc || !xkbi->desc->ctrls || !xkbi->desc->compat) - return; - - map= xkbi->desc->compat; - grp_mask= map->groups[state->group].mask; - state->compat_state = state->mods|grp_mask; - state->compat_lookup_mods= state->lookup_mods|grp_mask; - - if (xkbi->desc->ctrls->enabled_ctrls&XkbIgnoreGroupLockMask) - grp_mask= map->groups[state->base_group].mask; - state->compat_grab_mods= state->grab_mods|grp_mask; - return; -} - -unsigned -XkbAdjustGroup(int group,XkbControlsPtr ctrls) -{ -unsigned act; - - act= XkbOutOfRangeGroupAction(ctrls->groups_wrap); - if (group<0) { - while ( group < 0 ) { - if (act==XkbClampIntoRange) { - group= XkbGroup1Index; - } - else if (act==XkbRedirectIntoRange) { - int newGroup; - newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap); - if (newGroup>=ctrls->num_groups) - group= XkbGroup1Index; - else group= newGroup; - } - else { - group+= ctrls->num_groups; - } - } - } - else if (group>=ctrls->num_groups) { - if (act==XkbClampIntoRange) { - group= ctrls->num_groups-1; - } - else if (act==XkbRedirectIntoRange) { - int newGroup; - newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap); - if (newGroup>=ctrls->num_groups) - group= XkbGroup1Index; - else group= newGroup; - } - else { - group%= ctrls->num_groups; - } - } - return group; -} - -void -XkbComputeDerivedState(XkbSrvInfoPtr xkbi) -{ -XkbStatePtr state= &xkbi->state; -XkbControlsPtr ctrls= xkbi->desc->ctrls; -unsigned char grp; - - if (!state || !ctrls) - return; - - state->mods= (state->base_mods|state->latched_mods|state->locked_mods); - state->lookup_mods= state->mods&(~ctrls->internal.mask); - state->grab_mods= state->lookup_mods&(~ctrls->ignore_lock.mask); - state->grab_mods|= - ((state->base_mods|state->latched_mods)&ctrls->ignore_lock.mask); - - - grp= state->locked_group; - if (grp>=ctrls->num_groups) - state->locked_group= XkbAdjustGroup(XkbCharToInt(grp),ctrls); - - grp= state->locked_group+state->base_group+state->latched_group; - if (grp>=ctrls->num_groups) - state->group= XkbAdjustGroup(XkbCharToInt(grp),ctrls); - else state->group= grp; - XkbComputeCompatState(xkbi); - return; -} - -/***====================================================================***/ - -void -XkbCheckSecondaryEffects( XkbSrvInfoPtr xkbi, - unsigned which, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ - if (which&XkbStateNotifyMask) { - XkbStateRec old; - old= xkbi->state; - changes->state_changes|= XkbStateChangedFlags(&old,&xkbi->state); - XkbComputeDerivedState(xkbi); - } - if (which&XkbIndicatorStateNotifyMask) - XkbUpdateIndicators(xkbi->device,XkbAllIndicatorsMask,TRUE,changes, - cause); - return; -} - -/***====================================================================***/ - -Bool -XkbEnableDisableControls( XkbSrvInfoPtr xkbi, - unsigned long change, - unsigned long newValues, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ -XkbControlsPtr ctrls; -unsigned old; -XkbSrvLedInfoPtr sli; - - ctrls= xkbi->desc->ctrls; - old= ctrls->enabled_ctrls; - ctrls->enabled_ctrls&= ~change; - ctrls->enabled_ctrls|= (change&newValues); - if (old==ctrls->enabled_ctrls) - return FALSE; - if (cause!=NULL) { - xkbControlsNotify cn; - cn.numGroups= ctrls->num_groups; - cn.changedControls= XkbControlsEnabledMask; - cn.enabledControls= ctrls->enabled_ctrls; - cn.enabledControlChanges= (ctrls->enabled_ctrls^old); - cn.keycode= cause->kc; - cn.eventType= cause->event; - cn.requestMajor= cause->mjr; - cn.requestMinor= cause->mnr; - XkbSendControlsNotify(xkbi->device,&cn); - } - else { - /* Yes, this really should be an XOR. If ctrls->enabled_ctrls_changes*/ - /* is non-zero, the controls in question changed already in "this" */ - /* request and this change merely undoes the previous one. By the */ - /* same token, we have to figure out whether or not ControlsEnabled */ - /* should be set or not in the changes structure */ - changes->ctrls.enabled_ctrls_changes^= (ctrls->enabled_ctrls^old); - if (changes->ctrls.enabled_ctrls_changes) - changes->ctrls.changed_ctrls|= XkbControlsEnabledMask; - else changes->ctrls.changed_ctrls&= ~XkbControlsEnabledMask; - } - sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0); - XkbUpdateIndicators(xkbi->device,sli->usesControls,TRUE,changes,cause); - return TRUE; -} - -/***====================================================================***/ - -#define MAX_TOC 16 - -XkbGeometryPtr -XkbLookupNamedGeometry(DeviceIntPtr dev,Atom name,Bool *shouldFree) -{ -XkbSrvInfoPtr xkbi= dev->key->xkbInfo; -XkbDescPtr xkb= xkbi->desc; - - *shouldFree= 0; - if (name==None) { - if (xkb->geom!=NULL) - return xkb->geom; - name= xkb->names->geometry; - } - if ((xkb->geom!=NULL)&&(xkb->geom->name==name)) - return xkb->geom; - *shouldFree= 1; - return NULL; -} - -void -XkbConvertCase(register KeySym sym, KeySym *lower, KeySym *upper) -{ - *lower = sym; - *upper = sym; - switch(sym >> 8) { - case 0: /* Latin 1 */ - if ((sym >= XK_A) && (sym <= XK_Z)) - *lower += (XK_a - XK_A); - else if ((sym >= XK_a) && (sym <= XK_z)) - *upper -= (XK_a - XK_A); - else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) - *lower += (XK_agrave - XK_Agrave); - else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) - *upper -= (XK_agrave - XK_Agrave); - else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) - *lower += (XK_oslash - XK_Ooblique); - else if ((sym >= XK_oslash) && (sym <= XK_thorn)) - *upper -= (XK_oslash - XK_Ooblique); - break; - case 1: /* Latin 2 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym == XK_Aogonek) - *lower = XK_aogonek; - else if (sym >= XK_Lstroke && sym <= XK_Sacute) - *lower += (XK_lstroke - XK_Lstroke); - else if (sym >= XK_Scaron && sym <= XK_Zacute) - *lower += (XK_scaron - XK_Scaron); - else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) - *lower += (XK_zcaron - XK_Zcaron); - else if (sym == XK_aogonek) - *upper = XK_Aogonek; - else if (sym >= XK_lstroke && sym <= XK_sacute) - *upper -= (XK_lstroke - XK_Lstroke); - else if (sym >= XK_scaron && sym <= XK_zacute) - *upper -= (XK_scaron - XK_Scaron); - else if (sym >= XK_zcaron && sym <= XK_zabovedot) - *upper -= (XK_zcaron - XK_Zcaron); - else if (sym >= XK_Racute && sym <= XK_Tcedilla) - *lower += (XK_racute - XK_Racute); - else if (sym >= XK_racute && sym <= XK_tcedilla) - *upper -= (XK_racute - XK_Racute); - break; - case 2: /* Latin 3 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) - *lower += (XK_hstroke - XK_Hstroke); - else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) - *lower += (XK_gbreve - XK_Gbreve); - else if (sym >= XK_hstroke && sym <= XK_hcircumflex) - *upper -= (XK_hstroke - XK_Hstroke); - else if (sym >= XK_gbreve && sym <= XK_jcircumflex) - *upper -= (XK_gbreve - XK_Gbreve); - else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) - *lower += (XK_cabovedot - XK_Cabovedot); - else if (sym >= XK_cabovedot && sym <= XK_scircumflex) - *upper -= (XK_cabovedot - XK_Cabovedot); - break; - case 3: /* Latin 4 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Rcedilla && sym <= XK_Tslash) - *lower += (XK_rcedilla - XK_Rcedilla); - else if (sym >= XK_rcedilla && sym <= XK_tslash) - *upper -= (XK_rcedilla - XK_Rcedilla); - else if (sym == XK_ENG) - *lower = XK_eng; - else if (sym == XK_eng) - *upper = XK_ENG; - else if (sym >= XK_Amacron && sym <= XK_Umacron) - *lower += (XK_amacron - XK_Amacron); - else if (sym >= XK_amacron && sym <= XK_umacron) - *upper -= (XK_amacron - XK_Amacron); - break; - case 6: /* Cyrillic */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) - *lower -= (XK_Serbian_DJE - XK_Serbian_dje); - else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) - *upper += (XK_Serbian_DJE - XK_Serbian_dje); - else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) - *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); - else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) - *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); - break; - case 7: /* Greek */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) - *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); - else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && - sym != XK_Greek_iotaaccentdieresis && - sym != XK_Greek_upsilonaccentdieresis) - *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); - else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) - *lower += (XK_Greek_alpha - XK_Greek_ALPHA); - else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && - sym != XK_Greek_finalsmallsigma) - *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); - break; - } -} - -static Bool -_XkbCopyClientMap(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - int i; - XkbKeyTypePtr stype = NULL, dtype = NULL; - - /* client map */ - if (src->map) { - if (!dst->map) { - tmp = xcalloc(1, sizeof(XkbClientMapRec)); - if (!tmp) - return FALSE; - dst->map = tmp; - } - - if (src->map->syms) { - if (src->map->size_syms != dst->map->size_syms) { - if (dst->map->syms) - tmp = xrealloc(dst->map->syms, - src->map->size_syms * sizeof(KeySym)); - else - tmp = xalloc(src->map->size_syms * sizeof(KeySym)); - if (!tmp) - return FALSE; - dst->map->syms = tmp; - - } - memcpy(dst->map->syms, src->map->syms, - src->map->size_syms * sizeof(KeySym)); - } - else { - if (dst->map->syms) { - xfree(dst->map->syms); - dst->map->syms = NULL; - } - } - dst->map->num_syms = src->map->num_syms; - dst->map->size_syms = src->map->size_syms; - - if (src->map->key_sym_map) { - if (src->max_key_code != dst->max_key_code) { - if (dst->map->key_sym_map) - tmp = xrealloc(dst->map->key_sym_map, - (src->max_key_code + 1) * - sizeof(XkbSymMapRec)); - else - tmp = xalloc((src->max_key_code + 1) * - sizeof(XkbSymMapRec)); - if (!tmp) - return FALSE; - dst->map->key_sym_map = tmp; - } - memcpy(dst->map->key_sym_map, src->map->key_sym_map, - (src->max_key_code + 1) * sizeof(XkbSymMapRec)); - } - else { - if (dst->map->key_sym_map) { - xfree(dst->map->key_sym_map); - dst->map->key_sym_map = NULL; - } - } - - if (src->map->types && src->map->num_types) { - if (src->map->num_types > dst->map->size_types || - !dst->map->types || !dst->map->size_types) { - if (dst->map->types && dst->map->size_types) { - tmp = xrealloc(dst->map->types, - src->map->num_types * sizeof(XkbKeyTypeRec)); - if (!tmp) - return FALSE; - dst->map->types = tmp; - bzero(dst->map->types + dst->map->num_types, - (src->map->num_types - dst->map->num_types) * - sizeof(XkbKeyTypeRec)); - } - else { - tmp = xcalloc(src->map->num_types, sizeof(XkbKeyTypeRec)); - if (!tmp) - return FALSE; - dst->map->types = tmp; - } - } - else if (src->map->num_types < dst->map->num_types && - dst->map->types) { - for (i = src->map->num_types, dtype = (dst->map->types + i); - i < dst->map->num_types; i++, dtype++) { - if (dtype->level_names) - xfree(dtype->level_names); - dtype->level_names = NULL; - dtype->num_levels = 0; - if (dtype->map_count) { - if (dtype->map) - xfree(dtype->map); - if (dtype->preserve) - xfree(dtype->preserve); - } - } - } - - stype = src->map->types; - dtype = dst->map->types; - for (i = 0; i < src->map->num_types; i++, dtype++, stype++) { - if (stype->num_levels && stype->level_names) { - if (stype->num_levels != dtype->num_levels && - dtype->num_levels && dtype->level_names && - i < dst->map->num_types) { - tmp = xrealloc(dtype->level_names, - stype->num_levels * sizeof(Atom)); - if (!tmp) - continue; - dtype->level_names = tmp; - } - else if (!dtype->num_levels || !dtype->level_names || - i >= dst->map->num_types) { - tmp = xalloc(stype->num_levels * sizeof(Atom)); - if (!tmp) - continue; - dtype->level_names = tmp; - } - dtype->num_levels = stype->num_levels; - memcpy(dtype->level_names, stype->level_names, - stype->num_levels * sizeof(Atom)); - } - else { - if (dtype->num_levels && dtype->level_names && - i < dst->map->num_types) - xfree(dtype->level_names); - dtype->num_levels = 0; - dtype->level_names = NULL; - } - - dtype->name = stype->name; - memcpy(&dtype->mods, &stype->mods, sizeof(XkbModsRec)); - - if (stype->map_count) { - if (stype->map) { - if (stype->map_count != dtype->map_count && - dtype->map_count && dtype->map && - i < dst->map->num_types) { - tmp = xrealloc(dtype->map, - stype->map_count * - sizeof(XkbKTMapEntryRec)); - if (!tmp) - return FALSE; - dtype->map = tmp; - } - else if (!dtype->map_count || !dtype->map || - i >= dst->map->num_types) { - tmp = xalloc(stype->map_count * - sizeof(XkbKTMapEntryRec)); - if (!tmp) - return FALSE; - dtype->map = tmp; - } - - memcpy(dtype->map, stype->map, - stype->map_count * sizeof(XkbKTMapEntryRec)); - } - else { - if (dtype->map && i < dst->map->num_types) - xfree(dtype->map); - dtype->map = NULL; - } - - if (stype->preserve) { - if (stype->map_count != dtype->map_count && - dtype->map_count && dtype->preserve && - i < dst->map->num_types) { - tmp = xrealloc(dtype->preserve, - stype->map_count * - sizeof(XkbModsRec)); - if (!tmp) - return FALSE; - dtype->preserve = tmp; - } - else if (!dtype->preserve || !dtype->map_count || - i >= dst->map->num_types) { - tmp = xalloc(stype->map_count * - sizeof(XkbModsRec)); - if (!tmp) - return FALSE; - dtype->preserve = tmp; - } - - memcpy(dtype->preserve, stype->preserve, - stype->map_count * sizeof(XkbModsRec)); - } - else { - if (dtype->preserve && i < dst->map->num_types) - xfree(dtype->preserve); - dtype->preserve = NULL; - } - - dtype->map_count = stype->map_count; - } - else { - if (dtype->map_count && i < dst->map->num_types) { - if (dtype->map) - xfree(dtype->map); - if (dtype->preserve) - xfree(dtype->preserve); - } - dtype->map_count = 0; - dtype->map = NULL; - dtype->preserve = NULL; - } - } - - dst->map->size_types = src->map->num_types; - dst->map->num_types = src->map->num_types; - } - else { - if (dst->map->types) { - for (i = 0, dtype = dst->map->types; i < dst->map->num_types; - i++, dtype++) { - if (dtype->level_names) - xfree(dtype->level_names); - if (dtype->map && dtype->map_count) - xfree(dtype->map); - if (dtype->preserve && dtype->map_count) - xfree(dtype->preserve); - } - xfree(dst->map->types); - dst->map->types = NULL; - } - dst->map->num_types = 0; - dst->map->size_types = 0; - } - - if (src->map->modmap) { - if (src->max_key_code != dst->max_key_code) { - if (dst->map->modmap) - tmp = xrealloc(dst->map->modmap, src->max_key_code + 1); - else - tmp = xalloc(src->max_key_code + 1); - if (!tmp) - return FALSE; - dst->map->modmap = tmp; - } - memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1); - } - else { - if (dst->map->modmap) { - xfree(dst->map->modmap); - dst->map->modmap = NULL; - } - } - } - else { - if (dst->map) - XkbFreeClientMap(dst, XkbAllClientInfoMask, TRUE); - } - - return TRUE; -} - -static Bool -_XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - - /* server map */ - if (src->server) { - if (!dst->server) { - tmp = xcalloc(1, sizeof(XkbServerMapRec)); - if (!tmp) - return FALSE; - dst->server = tmp; - } - - if (src->server->explicit) { - if (src->max_key_code != dst->max_key_code) { - if (dst->server->explicit) - tmp = xrealloc(dst->server->explicit, src->max_key_code + 1); - else - tmp = xalloc(src->max_key_code + 1); - if (!tmp) - return FALSE; - dst->server->explicit = tmp; - } - memcpy(dst->server->explicit, src->server->explicit, - src->max_key_code + 1); - } - else { - if (dst->server->explicit) { - xfree(dst->server->explicit); - dst->server->explicit = NULL; - } - } - - if (src->server->acts) { - if (src->server->size_acts != dst->server->size_acts) { - if (dst->server->acts) - tmp = xrealloc(dst->server->acts, - src->server->size_acts * sizeof(XkbAction)); - else - tmp = xalloc(src->server->size_acts * sizeof(XkbAction)); - if (!tmp) - return FALSE; - dst->server->acts = tmp; - } - memcpy(dst->server->acts, src->server->acts, - src->server->size_acts * sizeof(XkbAction)); - } - else { - if (dst->server->acts) { - xfree(dst->server->acts); - dst->server->acts = NULL; - } - } - dst->server->size_acts = src->server->size_acts; - dst->server->num_acts = src->server->num_acts; - - if (src->server->key_acts) { - if (src->max_key_code != dst->max_key_code) { - if (dst->server->key_acts) - tmp = xrealloc(dst->server->key_acts, - (src->max_key_code + 1) * - sizeof(unsigned short)); - else - tmp = xalloc((src->max_key_code + 1) * - sizeof(unsigned short)); - if (!tmp) - return FALSE; - dst->server->key_acts = tmp; - } - memcpy(dst->server->key_acts, src->server->key_acts, - (src->max_key_code + 1) * sizeof(unsigned short)); - } - else { - if (dst->server->key_acts) { - xfree(dst->server->key_acts); - dst->server->key_acts = NULL; - } - } - - if (src->server->behaviors) { - if (src->max_key_code != dst->max_key_code) { - if (dst->server->behaviors) - tmp = xrealloc(dst->server->behaviors, - (src->max_key_code + 1) * - sizeof(XkbBehavior)); - else - tmp = xalloc((src->max_key_code + 1) * - sizeof(XkbBehavior)); - if (!tmp) - return FALSE; - dst->server->behaviors = tmp; - } - memcpy(dst->server->behaviors, src->server->behaviors, - (src->max_key_code + 1) * sizeof(XkbBehavior)); - } - else { - if (dst->server->behaviors) { - xfree(dst->server->behaviors); - dst->server->behaviors = NULL; - } - } - - memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods); - - if (src->server->vmodmap) { - if (src->max_key_code != dst->max_key_code) { - if (dst->server->vmodmap) - tmp = xrealloc(dst->server->vmodmap, - (src->max_key_code + 1) * - sizeof(unsigned short)); - else - tmp = xalloc((src->max_key_code + 1) * - sizeof(unsigned short)); - if (!tmp) - return FALSE; - dst->server->vmodmap = tmp; - } - memcpy(dst->server->vmodmap, src->server->vmodmap, - (src->max_key_code + 1) * sizeof(unsigned short)); - } - else { - if (dst->server->vmodmap) { - xfree(dst->server->vmodmap); - dst->server->vmodmap = NULL; - } - } - } - else { - if (dst->server) - XkbFreeServerMap(dst, XkbAllServerInfoMask, TRUE); - } - - return TRUE; -} - -static Bool -_XkbCopyNames(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - - /* names */ - if (src->names) { - if (!dst->names) { - dst->names = xcalloc(1, sizeof(XkbNamesRec)); - if (!dst->names) - return FALSE; - } - - if (src->names->keys) { - if (src->max_key_code != dst->max_key_code) { - if (dst->names->keys) - tmp = xrealloc(dst->names->keys, (src->max_key_code + 1) * - sizeof(XkbKeyNameRec)); - else - tmp = xalloc((src->max_key_code + 1) * - sizeof(XkbKeyNameRec)); - if (!tmp) - return FALSE; - dst->names->keys = tmp; - } - memcpy(dst->names->keys, src->names->keys, - (src->max_key_code + 1) * sizeof(XkbKeyNameRec)); - } - else { - if (dst->names->keys) { - xfree(dst->names->keys); - dst->names->keys = NULL; - } - } - - if (src->names->num_key_aliases) { - if (src->names->num_key_aliases != dst->names->num_key_aliases) { - if (dst->names->key_aliases) - tmp = xrealloc(dst->names->key_aliases, - src->names->num_key_aliases * - sizeof(XkbKeyAliasRec)); - else - tmp = xalloc(src->names->num_key_aliases * - sizeof(XkbKeyAliasRec)); - if (!tmp) - return FALSE; - dst->names->key_aliases = tmp; - } - memcpy(dst->names->key_aliases, src->names->key_aliases, - src->names->num_key_aliases * sizeof(XkbKeyAliasRec)); - } - else { - if (dst->names->key_aliases) { - xfree(dst->names->key_aliases); - dst->names->key_aliases = NULL; - } - } - dst->names->num_key_aliases = src->names->num_key_aliases; - - if (src->names->num_rg) { - if (src->names->num_rg != dst->names->num_rg) { - if (dst->names->radio_groups) - tmp = xrealloc(dst->names->radio_groups, - src->names->num_rg * sizeof(Atom)); - else - tmp = xalloc(src->names->num_rg * sizeof(Atom)); - if (!tmp) - return FALSE; - dst->names->radio_groups = tmp; - } - memcpy(dst->names->radio_groups, src->names->radio_groups, - src->names->num_rg * sizeof(Atom)); - } - else { - if (dst->names->radio_groups) - xfree(dst->names->radio_groups); - } - dst->names->num_rg = src->names->num_rg; - - dst->names->keycodes = src->names->keycodes; - dst->names->geometry = src->names->geometry; - dst->names->symbols = src->names->symbols; - dst->names->types = src->names->types; - dst->names->compat = src->names->compat; - dst->names->phys_symbols = src->names->phys_symbols; - - memcpy(dst->names->vmods, src->names->vmods, - XkbNumVirtualMods * sizeof(Atom)); - memcpy(dst->names->indicators, src->names->indicators, - XkbNumIndicators * sizeof(Atom)); - memcpy(dst->names->groups, src->names->groups, - XkbNumKbdGroups * sizeof(Atom)); - } - else { - if (dst->names) - XkbFreeNames(dst, XkbAllNamesMask, TRUE); - } - - return TRUE; -} - -static Bool -_XkbCopyCompat(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - - /* compat */ - if (src->compat) { - if (!dst->compat) { - dst->compat = xcalloc(1, sizeof(XkbCompatMapRec)); - if (!dst->compat) - return FALSE; - } - - if (src->compat->sym_interpret && src->compat->num_si) { - if (src->compat->num_si != dst->compat->size_si) { - if (dst->compat->sym_interpret) - tmp = xrealloc(dst->compat->sym_interpret, - src->compat->num_si * - sizeof(XkbSymInterpretRec)); - else - tmp = xalloc(src->compat->num_si * - sizeof(XkbSymInterpretRec)); - if (!tmp) - return FALSE; - dst->compat->sym_interpret = tmp; - } - memcpy(dst->compat->sym_interpret, src->compat->sym_interpret, - src->compat->num_si * sizeof(XkbSymInterpretRec)); - - dst->compat->num_si = src->compat->num_si; - dst->compat->size_si = src->compat->num_si; - } - else { - if (dst->compat->sym_interpret && dst->compat->size_si) - xfree(dst->compat->sym_interpret); - - dst->compat->sym_interpret = NULL; - dst->compat->num_si = 0; - dst->compat->size_si = 0; - } - - memcpy(dst->compat->groups, src->compat->groups, - XkbNumKbdGroups * sizeof(XkbModsRec)); - } - else { - if (dst->compat) - XkbFreeCompatMap(dst, XkbAllCompatMask, TRUE); - } - - return TRUE; -} - -static Bool -_XkbCopyGeom(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - int i = 0, j = 0, k = 0; - XkbColorPtr scolor = NULL, dcolor = NULL; - XkbDoodadPtr sdoodad = NULL, ddoodad = NULL; - XkbOutlinePtr soutline = NULL, doutline = NULL; - XkbPropertyPtr sprop = NULL, dprop = NULL; - XkbRowPtr srow = NULL, drow = NULL; - XkbSectionPtr ssection = NULL, dsection = NULL; - XkbShapePtr sshape = NULL, dshape = NULL; - - /* geometry */ - if (src->geom) { - if (!dst->geom) { - dst->geom = xcalloc(sizeof(XkbGeometryRec), 1); - if (!dst->geom) - return FALSE; - } - - /* properties */ - if (src->geom->num_properties) { - if (src->geom->num_properties != dst->geom->sz_properties) { - /* If we've got more properties in the destination than - * the source, run through and free all the excess ones - * first. */ - if (src->geom->num_properties < dst->geom->sz_properties) { - for (i = src->geom->num_properties, - dprop = dst->geom->properties + i; - i < dst->geom->num_properties; - i++, dprop++) { - xfree(dprop->name); - xfree(dprop->value); - } - } - - if (dst->geom->sz_properties) - tmp = xrealloc(dst->geom->properties, - src->geom->num_properties * - sizeof(XkbPropertyRec)); - else - tmp = xalloc(src->geom->num_properties * - sizeof(XkbPropertyRec)); - if (!tmp) - return FALSE; - dst->geom->properties = tmp; - } - - /* We don't set num_properties as we need it to try and avoid - * too much reallocing. */ - dst->geom->sz_properties = src->geom->num_properties; - - if (dst->geom->sz_properties > dst->geom->num_properties) { - bzero(dst->geom->properties + dst->geom->num_properties, - (dst->geom->sz_properties - dst->geom->num_properties) * - sizeof(XkbPropertyRec)); - } - - for (i = 0, - sprop = src->geom->properties, - dprop = dst->geom->properties; - i < src->geom->num_properties; - i++, sprop++, dprop++) { - if (i < dst->geom->num_properties) { - if (strlen(sprop->name) != strlen(dprop->name)) { - tmp = xrealloc(dprop->name, strlen(sprop->name) + 1); - if (!tmp) - return FALSE; - dprop->name = tmp; - } - if (strlen(sprop->value) != strlen(dprop->value)) { - tmp = xrealloc(dprop->value, strlen(sprop->value) + 1); - if (!tmp) - return FALSE; - dprop->value = tmp; - } - strcpy(dprop->name, sprop->name); - strcpy(dprop->value, sprop->value); - } - else { - dprop->name = xstrdup(sprop->name); - dprop->value = xstrdup(sprop->value); - } - } - - /* ... which is already src->geom->num_properties. */ - dst->geom->num_properties = dst->geom->sz_properties; - } - else { - if (dst->geom->sz_properties) { - for (i = 0, dprop = dst->geom->properties; - i < dst->geom->num_properties; - i++, dprop++) { - xfree(dprop->name); - xfree(dprop->value); - } - xfree(dst->geom->properties); - dst->geom->properties = NULL; - } - - dst->geom->num_properties = 0; - dst->geom->sz_properties = 0; - } - - /* colors */ - if (src->geom->num_colors) { - if (src->geom->num_colors != dst->geom->sz_colors) { - if (src->geom->num_colors < dst->geom->sz_colors) { - for (i = src->geom->num_colors, - dcolor = dst->geom->colors + i; - i < dst->geom->num_colors; - i++, dcolor++) { - xfree(dcolor->spec); - } - } - - if (dst->geom->sz_colors) - tmp = xrealloc(dst->geom->colors, - src->geom->num_colors * - sizeof(XkbColorRec)); - else - tmp = xalloc(src->geom->num_colors * - sizeof(XkbColorRec)); - if (!tmp) - return FALSE; - dst->geom->colors = tmp; - } - - dst->geom->sz_colors = src->geom->num_colors; - - if (dst->geom->sz_colors > dst->geom->num_colors) { - bzero(dst->geom->colors + dst->geom->num_colors, - (dst->geom->sz_colors - dst->geom->num_colors) * - sizeof(XkbColorRec)); - } - - for (i = 0, - scolor = src->geom->colors, - dcolor = dst->geom->colors; - i < src->geom->num_colors; - i++, scolor++, dcolor++) { - if (i < dst->geom->num_colors) { - if (strlen(scolor->spec) != strlen(dcolor->spec)) { - tmp = xrealloc(dcolor->spec, strlen(scolor->spec) + 1); - if (!tmp) - return FALSE; - dcolor->spec = tmp; - } - strcpy(dcolor->spec, scolor->spec); - } - else { - dcolor->spec = xstrdup(scolor->spec); - } - dcolor->pixel = scolor->pixel; - } - - dst->geom->num_colors = dst->geom->sz_colors; - } - else { - if (dst->geom->sz_colors) { - for (i = 0, dcolor = dst->geom->colors; - i < dst->geom->num_colors; - i++, dcolor++) { - xfree(dcolor->spec); - } - xfree(dst->geom->colors); - dst->geom->colors = NULL; - } - - dst->geom->num_colors = 0; - dst->geom->sz_colors = 0; - } - - /* shapes */ - /* shapes break down into outlines, which break down into points. */ - if (dst->geom->num_shapes) { - for (i = 0, dshape = dst->geom->shapes; - i < dst->geom->num_shapes; - i++, dshape++) { - for (j = 0, doutline = dshape->outlines; - j < dshape->num_outlines; - j++, doutline++) { - if (doutline->sz_points) - xfree(doutline->points); - } - - if (dshape->sz_outlines) { - xfree(dshape->outlines); - dshape->outlines = NULL; - } - - dshape->num_outlines = 0; - dshape->sz_outlines = 0; - } - } - - if (src->geom->num_shapes) { - tmp = xcalloc(src->geom->num_shapes, sizeof(XkbShapeRec)); - if (!tmp) - return FALSE; - dst->geom->shapes = tmp; - - for (i = 0, sshape = src->geom->shapes, dshape = dst->geom->shapes; - i < src->geom->num_shapes; - i++, sshape++, dshape++) { - if (sshape->num_outlines) { - tmp = xcalloc(sshape->num_outlines, sizeof(XkbOutlineRec)); - if (!tmp) - return FALSE; - dshape->outlines = tmp; - - for (j = 0, - soutline = sshape->outlines, - doutline = dshape->outlines; - j < sshape->num_outlines; - j++, soutline++, doutline++) { - if (soutline->num_points) { - tmp = xalloc(soutline->num_points * - sizeof(XkbPointRec)); - if (!tmp) - return FALSE; - doutline->points = tmp; - - memcpy(doutline->points, soutline->points, - soutline->num_points * sizeof(XkbPointRec)); - - doutline->corner_radius = soutline->corner_radius; - } - - doutline->num_points = soutline->num_points; - doutline->sz_points = soutline->num_points; - } - } - - dshape->num_outlines = sshape->num_outlines; - dshape->sz_outlines = sshape->num_outlines; - dshape->name = sshape->name; - dshape->bounds = sshape->bounds; - - dshape->approx = NULL; - if (sshape->approx && sshape->num_outlines > 0) { - - const ptrdiff_t approx_idx = - sshape->approx - sshape->outlines; - - if (approx_idx < dshape->num_outlines) { - dshape->approx = dshape->outlines + approx_idx; - } else { - LogMessage(X_WARNING, "XKB: approx outline " - "index is out of range\n"); - } - } - - dshape->primary = NULL; - if (sshape->primary && sshape->num_outlines > 0) { - - const ptrdiff_t primary_idx = - sshape->primary - sshape->outlines; - - if (primary_idx < dshape->num_outlines) { - dshape->primary = dshape->outlines + primary_idx; - } else { - LogMessage(X_WARNING, "XKB: primary outline " - "index is out of range\n"); - } - } - } - - dst->geom->num_shapes = src->geom->num_shapes; - dst->geom->sz_shapes = src->geom->num_shapes; - } - else { - if (dst->geom->sz_shapes) { - xfree(dst->geom->shapes); - } - dst->geom->shapes = NULL; - dst->geom->num_shapes = 0; - dst->geom->sz_shapes = 0; - } - - /* sections */ - /* sections break down into doodads, and also into rows, which break - * down into keys. */ - if (dst->geom->num_sections) { - for (i = 0, dsection = dst->geom->sections; - i < dst->geom->num_sections; - i++, dsection++) { - for (j = 0, drow = dsection->rows; - j < dsection->num_rows; - j++, drow++) { - if (drow->num_keys) - xfree(drow->keys); - } - - if (dsection->num_rows) - xfree(dsection->rows); - - /* cut and waste from geom/doodad below. */ - for (j = 0, ddoodad = dsection->doodads; - j < dsection->num_doodads; - j++, ddoodad++) { - if (ddoodad->any.type == XkbTextDoodad) { - if (ddoodad->text.text) { - xfree(ddoodad->text.text); - ddoodad->text.text = NULL; - } - if (ddoodad->text.font) { - xfree(ddoodad->text.font); - ddoodad->text.font = NULL; - } - } - else if (ddoodad->any.type == XkbLogoDoodad) { - if (ddoodad->logo.logo_name) { - xfree(ddoodad->logo.logo_name); - ddoodad->logo.logo_name = NULL; - } - } - } - - if (dsection->num_doodads) - xfree(dsection->doodads); - } - - dst->geom->num_sections = 0; - dst->geom->sections = NULL; - } - - if (src->geom->num_sections) { - if (dst->geom->sz_sections) - tmp = xrealloc(dst->geom->sections, - src->geom->num_sections * - sizeof(XkbSectionRec)); - else - tmp = xalloc(src->geom->num_sections * sizeof(XkbSectionRec)); - if (!tmp) - return FALSE; - memset(tmp, 0, src->geom->num_sections * sizeof(XkbSectionRec)); - dst->geom->sections = tmp; - dst->geom->num_sections = src->geom->num_sections; - dst->geom->sz_sections = src->geom->num_sections; - - for (i = 0, - ssection = src->geom->sections, - dsection = dst->geom->sections; - i < src->geom->num_sections; - i++, ssection++, dsection++) { - *dsection = *ssection; - if (ssection->num_rows) { - tmp = xcalloc(ssection->num_rows, sizeof(XkbRowRec)); - if (!tmp) - return FALSE; - dsection->rows = tmp; - } - dsection->num_rows = ssection->num_rows; - dsection->sz_rows = ssection->num_rows; - - for (j = 0, srow = ssection->rows, drow = dsection->rows; - j < ssection->num_rows; - j++, srow++, drow++) { - if (srow->num_keys) { - tmp = xalloc(srow->num_keys * sizeof(XkbKeyRec)); - if (!tmp) - return FALSE; - drow->keys = tmp; - memcpy(drow->keys, srow->keys, - srow->num_keys * sizeof(XkbKeyRec)); - } - drow->num_keys = srow->num_keys; - drow->sz_keys = srow->num_keys; - drow->top = srow->top; - drow->left = srow->left; - drow->vertical = srow->vertical; - drow->bounds = srow->bounds; - } - - if (ssection->num_doodads) { - tmp = xcalloc(ssection->num_doodads, sizeof(XkbDoodadRec)); - if (!tmp) - return FALSE; - dsection->doodads = tmp; - } - else { - dsection->doodads = NULL; - } - - dsection->sz_doodads = ssection->num_doodads; - for (k = 0, - sdoodad = ssection->doodads, - ddoodad = dsection->doodads; - k < ssection->num_doodads; - k++, sdoodad++, ddoodad++) { - memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec)); - if (sdoodad->any.type == XkbTextDoodad) { - if (sdoodad->text.text) - ddoodad->text.text = - xstrdup(sdoodad->text.text); - if (sdoodad->text.font) - ddoodad->text.font = - xstrdup(sdoodad->text.font); - } - else if (sdoodad->any.type == XkbLogoDoodad) { - if (sdoodad->logo.logo_name) - ddoodad->logo.logo_name = - xstrdup(sdoodad->logo.logo_name); - } - } - dsection->overlays = NULL; - dsection->sz_overlays = 0; - dsection->num_overlays = 0; - } - } - else { - if (dst->geom->sz_sections) { - xfree(dst->geom->sections); - } - - dst->geom->sections = NULL; - dst->geom->num_sections = 0; - dst->geom->sz_sections = 0; - } - - /* doodads */ - if (dst->geom->num_doodads) { - for (i = src->geom->num_doodads, - ddoodad = dst->geom->doodads + - src->geom->num_doodads; - i < dst->geom->num_doodads; - i++, ddoodad++) { - if (ddoodad->any.type == XkbTextDoodad) { - if (ddoodad->text.text) { - xfree(ddoodad->text.text); - ddoodad->text.text = NULL; - } - if (ddoodad->text.font) { - xfree(ddoodad->text.font); - ddoodad->text.font = NULL; - } - } - else if (ddoodad->any.type == XkbLogoDoodad) { - if (ddoodad->logo.logo_name) { - xfree(ddoodad->logo.logo_name); - ddoodad->logo.logo_name = NULL; - } - } - } - dst->geom->num_doodads = 0; - dst->geom->doodads = NULL; - } - - if (src->geom->num_doodads) { - if (dst->geom->sz_doodads) - tmp = xrealloc(dst->geom->doodads, - src->geom->num_doodads * - sizeof(XkbDoodadRec)); - else - tmp = xalloc(src->geom->num_doodads * - sizeof(XkbDoodadRec)); - if (!tmp) - return FALSE; - memset(tmp, 0, src->geom->num_doodads * sizeof(XkbDoodadRec)); - dst->geom->doodads = tmp; - - dst->geom->sz_doodads = src->geom->num_doodads; - - for (i = 0, - sdoodad = src->geom->doodads, - ddoodad = dst->geom->doodads; - i < src->geom->num_doodads; - i++, sdoodad++, ddoodad++) { - memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec)); - if (sdoodad->any.type == XkbTextDoodad) { - if (sdoodad->text.text) - ddoodad->text.text = xstrdup(sdoodad->text.text); - if (sdoodad->text.font) - ddoodad->text.font = xstrdup(sdoodad->text.font); - } - else if (sdoodad->any.type == XkbLogoDoodad) { - if (sdoodad->logo.logo_name) - ddoodad->logo.logo_name = - xstrdup(sdoodad->logo.logo_name); - } - } - - dst->geom->num_doodads = dst->geom->sz_doodads; - } - else { - if (dst->geom->sz_doodads) { - xfree(dst->geom->doodads); - } - - dst->geom->doodads = NULL; - dst->geom->num_doodads = 0; - dst->geom->sz_doodads = 0; - } - - /* key aliases */ - if (src->geom->num_key_aliases) { - if (src->geom->num_key_aliases != dst->geom->sz_key_aliases) { - if (dst->geom->sz_key_aliases) - tmp = xrealloc(dst->geom->key_aliases, - src->geom->num_key_aliases * - 2 * XkbKeyNameLength); - else - tmp = xalloc(src->geom->num_key_aliases * - 2 * XkbKeyNameLength); - if (!tmp) - return FALSE; - dst->geom->key_aliases = tmp; - - dst->geom->sz_key_aliases = src->geom->num_key_aliases; - } - - memcpy(dst->geom->key_aliases, src->geom->key_aliases, - src->geom->num_key_aliases * 2 * XkbKeyNameLength); - - dst->geom->num_key_aliases = dst->geom->sz_key_aliases; - } - else { - if (dst->geom->key_aliases) { - xfree(dst->geom->key_aliases); - } - dst->geom->key_aliases = NULL; - dst->geom->num_key_aliases = 0; - dst->geom->sz_key_aliases = 0; - } - - /* font */ - if (src->geom->label_font) { - if (!dst->geom->label_font) { - tmp = xalloc(strlen(src->geom->label_font)); - if (!tmp) - return FALSE; - dst->geom->label_font = tmp; - } - else if (strlen(src->geom->label_font) != - strlen(dst->geom->label_font)) { - tmp = xrealloc(dst->geom->label_font, - strlen(src->geom->label_font)); - if (!tmp) - return FALSE; - dst->geom->label_font = tmp; - } - - strcpy(dst->geom->label_font, src->geom->label_font); - i = XkbGeomColorIndex(src->geom, src->geom->label_color); - dst->geom->label_color = &(dst->geom->colors[i]); - i = XkbGeomColorIndex(src->geom, src->geom->base_color); - dst->geom->base_color = &(dst->geom->colors[i]); - } - else { - if (dst->geom->label_font) { - xfree(dst->geom->label_font); - } - dst->geom->label_font = NULL; - dst->geom->label_color = NULL; - dst->geom->base_color = NULL; - } - - dst->geom->name = src->geom->name; - dst->geom->width_mm = src->geom->width_mm; - dst->geom->height_mm = src->geom->height_mm; - } - else - { - if (dst->geom) { - /* I LOVE THE DIFFERENT CALL SIGNATURE. REALLY, I DO. */ - XkbFreeGeometry(dst->geom, XkbGeomAllMask, TRUE); - dst->geom = NULL; - } - } - - return TRUE; -} - -static Bool -_XkbCopyIndicators(XkbDescPtr src, XkbDescPtr dst) -{ - /* indicators */ - if (src->indicators) { - if (!dst->indicators) { - dst->indicators = xalloc(sizeof(XkbIndicatorRec)); - if (!dst->indicators) - return FALSE; - } - memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec)); - } - else { - if (dst->indicators) { - xfree(dst->indicators); - dst->indicators = NULL; - } - } - return TRUE; -} - -static Bool -_XkbCopyControls(XkbDescPtr src, XkbDescPtr dst) -{ - /* controls */ - if (src->ctrls) { - if (!dst->ctrls) { - dst->ctrls = xalloc(sizeof(XkbControlsRec)); - if (!dst->ctrls) - return FALSE; - } - memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec)); - } - else { - if (dst->ctrls) { - xfree(dst->ctrls); - dst->ctrls = NULL; - } - } - return TRUE; -} - -/** - * Copy an XKB map from src to dst, reallocating when necessary: if some - * map components are present in one, but not in the other, the destination - * components will be allocated or freed as necessary. - * - * Basic map consistency is assumed on both sides, so maps with random - * uninitialised data (e.g. names->radio_grous == NULL, names->num_rg == 19) - * _will_ cause failures. You've been warned. - * - * Returns TRUE on success, or FALSE on failure. If this function fails, - * dst may be in an inconsistent state: all its pointers are guaranteed - * to remain valid, but part of the map may be from src and part from dst. - * - */ - -Bool -XkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src) -{ - - if (!src || !dst) { - DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst); - return FALSE; - } - - if (src == dst) - return TRUE; - - if (!_XkbCopyClientMap(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy client map\n"); - return FALSE; - } - if (!_XkbCopyServerMap(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy server map\n"); - return FALSE; - } - if (!_XkbCopyIndicators(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy indicators\n"); - return FALSE; - } - if (!_XkbCopyControls(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy controls\n"); - return FALSE; - } - if (!_XkbCopyNames(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy names\n"); - return FALSE; - } - if (!_XkbCopyCompat(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy compat map\n"); - return FALSE; - } - if (!_XkbCopyGeom(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy geometry\n"); - return FALSE; - } - - dst->min_key_code = src->min_key_code; - dst->max_key_code = src->max_key_code; - - return TRUE; -} - -Bool -XkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src) -{ - xkbNewKeyboardNotify nkn; - Bool ret; - - if (!dst->key || !src->key) - return FALSE; - - memset(&nkn, 0, sizeof(xkbNewKeyboardNotify)); - nkn.oldMinKeyCode = dst->key->xkbInfo->desc->min_key_code; - nkn.oldMaxKeyCode = dst->key->xkbInfo->desc->max_key_code; - nkn.deviceID = dst->id; - nkn.oldDeviceID = dst->id; /* maybe src->id? */ - nkn.minKeyCode = src->key->xkbInfo->desc->min_key_code; - nkn.maxKeyCode = src->key->xkbInfo->desc->max_key_code; - nkn.requestMajor = XkbReqCode; - nkn.requestMinor = X_kbSetMap; /* Near enough's good enough. */ - nkn.changed = XkbNKN_KeycodesMask; - if (src->key->xkbInfo->desc->geom) - nkn.changed |= XkbNKN_GeometryMask; - - ret = XkbCopyKeymap(dst->key->xkbInfo->desc, src->key->xkbInfo->desc); - if (ret) - XkbSendNewKeyboardNotify(dst, &nkn); - - return ret; -} - -int -XkbGetEffectiveGroup(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 keycode) -{ - XkbDescPtr xkb = xkbi->desc; - int effectiveGroup = xkbState->group; - - if (!XkbKeycodeInRange(xkb, keycode)) - return -1; - - if (effectiveGroup == XkbGroup1Index) - return effectiveGroup; - - if (XkbKeyNumGroups(xkb,keycode) > 1U) { - if (effectiveGroup >= XkbKeyNumGroups(xkb,keycode)) { - unsigned int gi = XkbKeyGroupInfo(xkb,keycode); - switch (XkbOutOfRangeGroupAction(gi)) { - default: - case XkbWrapIntoRange: - effectiveGroup %= XkbKeyNumGroups(xkb, keycode); - break; - case XkbClampIntoRange: - effectiveGroup = XkbKeyNumGroups(xkb, keycode) - 1; - break; - case XkbRedirectIntoRange: - effectiveGroup = XkbOutOfRangeGroupInfo(gi); - if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode)) - effectiveGroup = 0; - break; - } - } - } - else effectiveGroup = XkbGroup1Index; - - return effectiveGroup; -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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. + +********************************************************/ +/* + +Copyright © 2008 Red Hat Inc. + +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. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "os.h" +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#define XK_CYRILLIC +#include <X11/keysym.h> +#include "misc.h" +#include "inputstr.h" +#include "eventstr.h" + +#define XKBSRV_NEED_FILE_FUNCS +#include <xkbsrv.h> +#include "xkbgeom.h" +#include "xkb.h" + +/***====================================================================***/ + +int +_XkbLookupAnyDevice(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + int rc = XkbKeyboardErrorCode; + + if (id == XkbUseCoreKbd) + id = PickKeyboard(client)->id; + else if (id == XkbUseCorePtr) + id = PickPointer(client)->id; + + rc = dixLookupDevice(pDev, id, client, access_mode); + if (rc != Success) + *xkb_err = XkbErr_BadDevice; + + return rc; +} + +int +_XkbLookupKeyboard(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + DeviceIntPtr dev; + int rc; + + if (id == XkbDfltXIId) + id = XkbUseCoreKbd; + + rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); + if (rc != Success) + return rc; + + dev = *pDev; + if (!dev->key || !dev->key->xkbInfo) { + *pDev = NULL; + *xkb_err= XkbErr_BadClass; + return XkbKeyboardErrorCode; + } + return Success; +} + +int +_XkbLookupBellDevice(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + DeviceIntPtr dev; + int rc; + + rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); + if (rc != Success) + return rc; + + dev = *pDev; + if (!dev->kbdfeed && !dev->bell) { + *pDev = NULL; + *xkb_err= XkbErr_BadClass; + return XkbKeyboardErrorCode; + } + return Success; +} + +int +_XkbLookupLedDevice(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + DeviceIntPtr dev; + int rc; + + if (id == XkbDfltXIId) + id = XkbUseCorePtr; + + rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); + if (rc != Success) + return rc; + + dev = *pDev; + if (!dev->kbdfeed && !dev->leds) { + *pDev = NULL; + *xkb_err= XkbErr_BadClass; + return XkbKeyboardErrorCode; + } + return Success; +} + +int +_XkbLookupButtonDevice(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + DeviceIntPtr dev; + int rc; + + rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); + if (rc != Success) + return rc; + + dev = *pDev; + if (!dev->button) { + *pDev = NULL; + *xkb_err= XkbErr_BadClass; + return XkbKeyboardErrorCode; + } + return Success; +} + +void +XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods) +{ +register unsigned tmp; + + switch (act->type) { + case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: + if (act->mods.flags&XkbSA_UseModMapMods) + act->mods.real_mods= act->mods.mask= mods; + if ((tmp= XkbModActionVMods(&act->mods))!=0) + act->mods.mask|= XkbMaskForVMask(xkb,tmp); + break; + case XkbSA_ISOLock: + if (act->iso.flags&XkbSA_UseModMapMods) + act->iso.real_mods= act->iso.mask= mods; + if ((tmp= XkbModActionVMods(&act->iso))!=0) + act->iso.mask|= XkbMaskForVMask(xkb,tmp); + break; + } + return; +} + +unsigned +XkbMaskForVMask(XkbDescPtr xkb,unsigned vmask) +{ +register int i,bit; +register unsigned mask; + + for (mask=i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + if (vmask&bit) + mask|= xkb->server->vmods[i]; + } + return mask; +} + +/***====================================================================***/ + +void +XkbUpdateKeyTypesFromCore( DeviceIntPtr pXDev, + KeySymsPtr pCore, + KeyCode first, + CARD8 num, + XkbChangesPtr changes) +{ +XkbDescPtr xkb; +unsigned key,nG,explicit; +int types[XkbNumKbdGroups]; +KeySym tsyms[XkbMaxSymsPerKey],*syms; +XkbMapChangesPtr mc; + + xkb= pXDev->key->xkbInfo->desc; + if (first+num-1>xkb->max_key_code) { + /* 1/12/95 (ef) -- XXX! should allow XKB structures to grow */ + num= xkb->max_key_code-first+1; + } + + mc= (changes?(&changes->map):NULL); + + syms= &pCore->map[(first - pCore->minKeyCode) * pCore->mapWidth]; + for (key=first; key<(first+num); key++,syms+= pCore->mapWidth) { + explicit= xkb->server->explicit[key]&XkbExplicitKeyTypesMask; + types[XkbGroup1Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index); + types[XkbGroup2Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup2Index); + types[XkbGroup3Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup3Index); + types[XkbGroup4Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup4Index); + nG= XkbKeyTypesForCoreSymbols(xkb,pCore->mapWidth,syms,explicit,types, + tsyms); + XkbChangeTypesOfKey(xkb,key,nG,XkbAllGroupsMask,types,mc); + memcpy((char *)XkbKeySymsPtr(xkb,key),(char *)tsyms, + XkbKeyNumSyms(xkb,key)*sizeof(KeySym)); + } + if (changes->map.changed&XkbKeySymsMask) { + CARD8 oldLast,newLast; + oldLast = changes->map.first_key_sym+changes->map.num_key_syms-1; + newLast = first+num-1; + + if (first<changes->map.first_key_sym) + changes->map.first_key_sym = first; + if (oldLast>newLast) + newLast= oldLast; + changes->map.num_key_syms = newLast-changes->map.first_key_sym+1; + } + else { + changes->map.changed|= XkbKeySymsMask; + changes->map.first_key_sym = first; + changes->map.num_key_syms = num; + } + return; +} + +void +XkbUpdateDescActions( XkbDescPtr xkb, + KeyCode first, + CARD8 num, + XkbChangesPtr changes) +{ +register unsigned key; + + for (key=first;key<(first+num);key++) { + XkbApplyCompatMapToKey(xkb,key,changes); + } + + if (changes->map.changed&(XkbVirtualModMapMask|XkbModifierMapMask)) { + unsigned char newVMods[XkbNumVirtualMods]; + register unsigned bit,i; + unsigned present; + + bzero(newVMods,XkbNumVirtualMods); + present= 0; + for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { + if (xkb->server->vmodmap[key]==0) + continue; + for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + if (bit&xkb->server->vmodmap[key]) { + present|= bit; + newVMods[i]|= xkb->map->modmap[key]; + } + } + } + for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + if ((bit&present)&&(newVMods[i]!=xkb->server->vmods[i])) { + changes->map.changed|= XkbVirtualModsMask; + changes->map.vmods|= bit; + xkb->server->vmods[i]= newVMods[i]; + } + } + } + if (changes->map.changed&XkbVirtualModsMask) + XkbApplyVirtualModChanges(xkb,changes->map.vmods,changes); + + if (changes->map.changed&XkbKeyActionsMask) { + CARD8 oldLast,newLast; + oldLast= changes->map.first_key_act+changes->map.num_key_acts-1; + newLast = first+num-1; + + if (first<changes->map.first_key_act) + changes->map.first_key_act = first; + if (newLast>oldLast) + newLast= oldLast; + changes->map.num_key_acts= newLast-changes->map.first_key_act+1; + } + else { + changes->map.changed|= XkbKeyActionsMask; + changes->map.first_key_act = first; + changes->map.num_key_acts = num; + } + return; +} + +void +XkbUpdateActions( DeviceIntPtr pXDev, + KeyCode first, + CARD8 num, + XkbChangesPtr changes, + unsigned * needChecksRtrn, + XkbEventCausePtr cause) +{ +XkbSrvInfoPtr xkbi; +XkbDescPtr xkb; +CARD8 * repeat; + + if (needChecksRtrn) + *needChecksRtrn= 0; + xkbi= pXDev->key->xkbInfo; + xkb= xkbi->desc; + repeat= xkb->ctrls->per_key_repeat; + + if (pXDev->kbdfeed) + memcpy(repeat,pXDev->kbdfeed->ctrl.autoRepeats,XkbPerKeyBitArraySize); + + XkbUpdateDescActions(xkb,first,num,changes); + + if ((pXDev->kbdfeed)&& + (changes->ctrls.enabled_ctrls_changes&XkbPerKeyRepeatMask)) { + memcpy(pXDev->kbdfeed->ctrl.autoRepeats,repeat, XkbPerKeyBitArraySize); + (*pXDev->kbdfeed->CtrlProc)(pXDev, &pXDev->kbdfeed->ctrl); + } + return; +} + +KeySymsPtr +XkbGetCoreMap(DeviceIntPtr keybd) +{ +register int key,tmp; +int maxSymsPerKey, maxGroup1Width; +XkbDescPtr xkb; +KeySymsPtr syms; +int maxNumberOfGroups; + + if (!keybd || !keybd->key || !keybd->key->xkbInfo) + return NULL; + + xkb= keybd->key->xkbInfo->desc; + maxSymsPerKey= maxGroup1Width= 0; + maxNumberOfGroups = 0; + + /* determine sizes */ + for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { + if (XkbKeycodeInRange(xkb,key)) { + int nGroups; + int w; + nGroups= XkbKeyNumGroups(xkb,key); + tmp= 0; + if (nGroups>0) { + if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup1Index))<=2) + tmp+= 2; + else tmp+= w + 2; + /* remember highest G1 width */ + if (w > maxGroup1Width) + maxGroup1Width = w; + } + if (nGroups>1) { + if (tmp <= 2) { + if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))<2) + tmp+= 2; + else tmp+= w; + } else { + if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))>2) + tmp+= w - 2; + } + } + if (nGroups>2) + tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup3Index); + if (nGroups>3) + tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup4Index); + if (tmp>maxSymsPerKey) + maxSymsPerKey= tmp; + if (nGroups > maxNumberOfGroups) + maxNumberOfGroups = nGroups; + } + } + + if (maxSymsPerKey <= 0) + return NULL; + + syms = calloc(1, sizeof(*syms)); + if (!syms) + return NULL; + + /* See Section 12.4 of the XKB Protocol spec. Because of the + * single-group distribution for multi-group keyboards, we have to + * have enough symbols for the largest group 1 to replicate across the + * number of groups on the keyboard. e.g. a single-group key with 4 + * symbols on a keyboard that has 3 groups -> 12 syms per key */ + if (maxSymsPerKey < maxNumberOfGroups * maxGroup1Width) + maxSymsPerKey = maxNumberOfGroups * maxGroup1Width; + + syms->mapWidth = maxSymsPerKey; + syms->minKeyCode = xkb->min_key_code; + syms->maxKeyCode = xkb->max_key_code; + + tmp = syms->mapWidth * (xkb->max_key_code - xkb->min_key_code + 1); + syms->map = calloc(tmp, sizeof(*syms->map)); + if (!syms->map) { + free(syms); + return NULL; + } + + for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { + KeySym *pCore,*pXKB; + unsigned nGroups,groupWidth,n,nOut; + + nGroups= XkbKeyNumGroups(xkb,key); + n= (key-xkb->min_key_code)*syms->mapWidth; + pCore= &syms->map[n]; + pXKB= XkbKeySymsPtr(xkb,key); + nOut= 2; + if (nGroups>0) { + groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup1Index); + if (groupWidth>0) pCore[0]= pXKB[0]; + if (groupWidth>1) pCore[1]= pXKB[1]; + for (n=2;n<groupWidth;n++) + pCore[2+n]= pXKB[n]; + if (groupWidth>2) + nOut= groupWidth; + } + + /* See XKB Protocol Sec, Section 12.4. + A 1-group key with ABCDE on a 2 group keyboard must be + duplicated across all groups as ABABCDECDE. + */ + if (nGroups == 1) + { + int idx, j; + + groupWidth = XkbKeyGroupWidth(xkb, key, XkbGroup1Index); + + /* AB..CDE... -> ABABCDE... */ + if (groupWidth > 0 && syms->mapWidth >= 3) + pCore[2] = pCore[0]; + if (groupWidth > 1 && syms->mapWidth >= 4) + pCore[3] = pCore[1]; + + /* ABABCDE... -> ABABCDECDE */ + idx = 2 + groupWidth; + while (groupWidth > 2 && idx < syms->mapWidth && + idx < groupWidth * 2) + { + pCore[idx] = pCore[idx - groupWidth + 2]; + idx++; + } + idx = 2 * groupWidth; + if (idx < 4) + idx = 4; + /* 3 or more groups: ABABCDECDEABCDEABCDE */ + for (j = 3; j <= maxNumberOfGroups; j++) + for (n = 0; n < groupWidth && idx < maxSymsPerKey; n++) + pCore[idx++] = pXKB[n]; + } + + pXKB+= XkbKeyGroupsWidth(xkb,key); + nOut+= 2; + if (nGroups>1) { + groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup2Index); + if (groupWidth>0) pCore[2]= pXKB[0]; + if (groupWidth>1) pCore[3]= pXKB[1]; + for (n=2;n<groupWidth;n++) { + pCore[nOut+(n-2)]= pXKB[n]; + } + if (groupWidth>2) + nOut+= (groupWidth-2); + } + pXKB+= XkbKeyGroupsWidth(xkb,key); + for (n=XkbGroup3Index;n<nGroups;n++) { + register int s; + groupWidth= XkbKeyGroupWidth(xkb,key,n); + for (s=0;s<groupWidth;s++) { + pCore[nOut++]= pXKB[s]; + } + pXKB+= XkbKeyGroupsWidth(xkb,key); + } + } + + return syms; +} + +void +XkbSetRepeatKeys(DeviceIntPtr pXDev,int key,int onoff) +{ + if (pXDev && pXDev->key && pXDev->key->xkbInfo) { + xkbControlsNotify cn; + XkbControlsPtr ctrls = pXDev->key->xkbInfo->desc->ctrls; + XkbControlsRec old; + old = *ctrls; + + if (key== -1) { /* global autorepeat setting changed */ + if (onoff) ctrls->enabled_ctrls |= XkbRepeatKeysMask; + else ctrls->enabled_ctrls &= ~XkbRepeatKeysMask; + } + else if (pXDev->kbdfeed) { + ctrls->per_key_repeat[key/8] = + pXDev->kbdfeed->ctrl.autoRepeats[key/8]; + } + + if (XkbComputeControlsNotify(pXDev,&old,ctrls,&cn,TRUE)) + XkbSendControlsNotify(pXDev,&cn); + } + return; +} + +/* Applies a change to a single device, does not traverse the device tree. */ +void +XkbApplyMappingChange(DeviceIntPtr kbd, KeySymsPtr map, KeyCode first_key, + CARD8 num_keys, CARD8 *modmap, ClientPtr client) +{ + XkbDescPtr xkb = kbd->key->xkbInfo->desc; + XkbEventCauseRec cause; + XkbChangesRec changes; + unsigned int check; + + memset(&changes, 0, sizeof(changes)); + memset(&cause, 0, sizeof(cause)); + + if (map && first_key && num_keys) { + check = 0; + XkbSetCauseCoreReq(&cause, X_ChangeKeyboardMapping, client); + + XkbUpdateKeyTypesFromCore(kbd, map, first_key, num_keys, &changes); + XkbUpdateActions(kbd, first_key, num_keys, &changes, &check, &cause); + + if (check) + XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause); + } + + if (modmap) { + /* A keymap change can imply a modmap change, se we prefer the + * former. */ + if (!cause.mjr) + XkbSetCauseCoreReq(&cause,X_SetModifierMapping,client); + + check = 0; + num_keys = xkb->max_key_code - xkb->min_key_code + 1; + changes.map.changed |= XkbModifierMapMask; + changes.map.first_modmap_key = xkb->min_key_code; + changes.map.num_modmap_keys = num_keys; + memcpy(kbd->key->xkbInfo->desc->map->modmap, modmap, MAP_LENGTH); + XkbUpdateActions(kbd, xkb->min_key_code, num_keys, &changes, &check, + &cause); + + if (check) + XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause); + } + + XkbSendNotification(kbd, &changes, &cause); +} + +void +XkbDisableComputedAutoRepeats(DeviceIntPtr dev,unsigned key) +{ +XkbSrvInfoPtr xkbi = dev->key->xkbInfo; +xkbMapNotify mn; + + xkbi->desc->server->explicit[key]|= XkbExplicitAutoRepeatMask; + bzero(&mn,sizeof(mn)); + mn.changed= XkbExplicitComponentsMask; + mn.firstKeyExplicit= key; + mn.nKeyExplicit= 1; + XkbSendMapNotify(dev,&mn); + return; +} + +unsigned +XkbStateChangedFlags(XkbStatePtr old,XkbStatePtr new) +{ +int changed; + + changed=(old->group!=new->group?XkbGroupStateMask:0); + changed|=(old->base_group!=new->base_group?XkbGroupBaseMask:0); + changed|=(old->latched_group!=new->latched_group?XkbGroupLatchMask:0); + changed|=(old->locked_group!=new->locked_group?XkbGroupLockMask:0); + changed|=(old->mods!=new->mods?XkbModifierStateMask:0); + changed|=(old->base_mods!=new->base_mods?XkbModifierBaseMask:0); + changed|=(old->latched_mods!=new->latched_mods?XkbModifierLatchMask:0); + changed|=(old->locked_mods!=new->locked_mods?XkbModifierLockMask:0); + changed|=(old->compat_state!=new->compat_state?XkbCompatStateMask:0); + changed|=(old->grab_mods!=new->grab_mods?XkbGrabModsMask:0); + if (old->compat_grab_mods!=new->compat_grab_mods) + changed|= XkbCompatGrabModsMask; + changed|=(old->lookup_mods!=new->lookup_mods?XkbLookupModsMask:0); + if (old->compat_lookup_mods!=new->compat_lookup_mods) + changed|= XkbCompatLookupModsMask; + changed|=(old->ptr_buttons!=new->ptr_buttons?XkbPointerButtonMask:0); + return changed; +} + +static void +XkbComputeCompatState(XkbSrvInfoPtr xkbi) +{ +CARD16 grp_mask; +XkbStatePtr state= &xkbi->state; +XkbCompatMapPtr map; + + if (!state || !xkbi->desc || !xkbi->desc->ctrls || !xkbi->desc->compat) + return; + + map= xkbi->desc->compat; + grp_mask= map->groups[state->group].mask; + state->compat_state = state->mods|grp_mask; + state->compat_lookup_mods= state->lookup_mods|grp_mask; + + if (xkbi->desc->ctrls->enabled_ctrls&XkbIgnoreGroupLockMask) + grp_mask= map->groups[state->base_group].mask; + state->compat_grab_mods= state->grab_mods|grp_mask; + return; +} + +unsigned +XkbAdjustGroup(int group,XkbControlsPtr ctrls) +{ +unsigned act; + + act= XkbOutOfRangeGroupAction(ctrls->groups_wrap); + if (group<0) { + while ( group < 0 ) { + if (act==XkbClampIntoRange) { + group= XkbGroup1Index; + } + else if (act==XkbRedirectIntoRange) { + int newGroup; + newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap); + if (newGroup>=ctrls->num_groups) + group= XkbGroup1Index; + else group= newGroup; + } + else { + group+= ctrls->num_groups; + } + } + } + else if (group>=ctrls->num_groups) { + if (act==XkbClampIntoRange) { + group= ctrls->num_groups-1; + } + else if (act==XkbRedirectIntoRange) { + int newGroup; + newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap); + if (newGroup>=ctrls->num_groups) + group= XkbGroup1Index; + else group= newGroup; + } + else { + group%= ctrls->num_groups; + } + } + return group; +} + +void +XkbComputeDerivedState(XkbSrvInfoPtr xkbi) +{ +XkbStatePtr state= &xkbi->state; +XkbControlsPtr ctrls= xkbi->desc->ctrls; +unsigned char grp; + + if (!state || !ctrls) + return; + + state->mods= (state->base_mods|state->latched_mods|state->locked_mods); + state->lookup_mods= state->mods&(~ctrls->internal.mask); + state->grab_mods= state->lookup_mods&(~ctrls->ignore_lock.mask); + state->grab_mods|= + ((state->base_mods|state->latched_mods)&ctrls->ignore_lock.mask); + + + grp= state->locked_group; + if (grp>=ctrls->num_groups) + state->locked_group= XkbAdjustGroup(XkbCharToInt(grp),ctrls); + + grp= state->locked_group+state->base_group+state->latched_group; + if (grp>=ctrls->num_groups) + state->group= XkbAdjustGroup(XkbCharToInt(grp),ctrls); + else state->group= grp; + XkbComputeCompatState(xkbi); + return; +} + +/***====================================================================***/ + +void +XkbCheckSecondaryEffects( XkbSrvInfoPtr xkbi, + unsigned which, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ + if (which&XkbStateNotifyMask) { + XkbStateRec old; + old= xkbi->state; + changes->state_changes|= XkbStateChangedFlags(&old,&xkbi->state); + XkbComputeDerivedState(xkbi); + } + if (which&XkbIndicatorStateNotifyMask) + XkbUpdateIndicators(xkbi->device,XkbAllIndicatorsMask,TRUE,changes, + cause); + return; +} + +/***====================================================================***/ + +Bool +XkbEnableDisableControls( XkbSrvInfoPtr xkbi, + unsigned long change, + unsigned long newValues, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ +XkbControlsPtr ctrls; +unsigned old; +XkbSrvLedInfoPtr sli; + + ctrls= xkbi->desc->ctrls; + old= ctrls->enabled_ctrls; + ctrls->enabled_ctrls&= ~change; + ctrls->enabled_ctrls|= (change&newValues); + if (old==ctrls->enabled_ctrls) + return FALSE; + if (cause!=NULL) { + xkbControlsNotify cn; + cn.numGroups= ctrls->num_groups; + cn.changedControls= XkbControlsEnabledMask; + cn.enabledControls= ctrls->enabled_ctrls; + cn.enabledControlChanges= (ctrls->enabled_ctrls^old); + cn.keycode= cause->kc; + cn.eventType= cause->event; + cn.requestMajor= cause->mjr; + cn.requestMinor= cause->mnr; + XkbSendControlsNotify(xkbi->device,&cn); + } + else { + /* Yes, this really should be an XOR. If ctrls->enabled_ctrls_changes*/ + /* is non-zero, the controls in question changed already in "this" */ + /* request and this change merely undoes the previous one. By the */ + /* same token, we have to figure out whether or not ControlsEnabled */ + /* should be set or not in the changes structure */ + changes->ctrls.enabled_ctrls_changes^= (ctrls->enabled_ctrls^old); + if (changes->ctrls.enabled_ctrls_changes) + changes->ctrls.changed_ctrls|= XkbControlsEnabledMask; + else changes->ctrls.changed_ctrls&= ~XkbControlsEnabledMask; + } + sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0); + XkbUpdateIndicators(xkbi->device,sli->usesControls,TRUE,changes,cause); + return TRUE; +} + +/***====================================================================***/ + +#define MAX_TOC 16 + +XkbGeometryPtr +XkbLookupNamedGeometry(DeviceIntPtr dev,Atom name,Bool *shouldFree) +{ +XkbSrvInfoPtr xkbi= dev->key->xkbInfo; +XkbDescPtr xkb= xkbi->desc; + + *shouldFree= 0; + if (name==None) { + if (xkb->geom!=NULL) + return xkb->geom; + name= xkb->names->geometry; + } + if ((xkb->geom!=NULL)&&(xkb->geom->name==name)) + return xkb->geom; + *shouldFree= 1; + return NULL; +} + +void +XkbConvertCase(register KeySym sym, KeySym *lower, KeySym *upper) +{ + *lower = sym; + *upper = sym; + switch(sym >> 8) { + case 0: /* Latin 1 */ + if ((sym >= XK_A) && (sym <= XK_Z)) + *lower += (XK_a - XK_A); + else if ((sym >= XK_a) && (sym <= XK_z)) + *upper -= (XK_a - XK_A); + else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) + *lower += (XK_agrave - XK_Agrave); + else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) + *upper -= (XK_agrave - XK_Agrave); + else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) + *lower += (XK_oslash - XK_Ooblique); + else if ((sym >= XK_oslash) && (sym <= XK_thorn)) + *upper -= (XK_oslash - XK_Ooblique); + break; + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == XK_Aogonek) + *lower = XK_aogonek; + else if (sym >= XK_Lstroke && sym <= XK_Sacute) + *lower += (XK_lstroke - XK_Lstroke); + else if (sym >= XK_Scaron && sym <= XK_Zacute) + *lower += (XK_scaron - XK_Scaron); + else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) + *lower += (XK_zcaron - XK_Zcaron); + else if (sym == XK_aogonek) + *upper = XK_Aogonek; + else if (sym >= XK_lstroke && sym <= XK_sacute) + *upper -= (XK_lstroke - XK_Lstroke); + else if (sym >= XK_scaron && sym <= XK_zacute) + *upper -= (XK_scaron - XK_Scaron); + else if (sym >= XK_zcaron && sym <= XK_zabovedot) + *upper -= (XK_zcaron - XK_Zcaron); + else if (sym >= XK_Racute && sym <= XK_Tcedilla) + *lower += (XK_racute - XK_Racute); + else if (sym >= XK_racute && sym <= XK_tcedilla) + *upper -= (XK_racute - XK_Racute); + break; + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) + *lower += (XK_hstroke - XK_Hstroke); + else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) + *lower += (XK_gbreve - XK_Gbreve); + else if (sym >= XK_hstroke && sym <= XK_hcircumflex) + *upper -= (XK_hstroke - XK_Hstroke); + else if (sym >= XK_gbreve && sym <= XK_jcircumflex) + *upper -= (XK_gbreve - XK_Gbreve); + else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) + *lower += (XK_cabovedot - XK_Cabovedot); + else if (sym >= XK_cabovedot && sym <= XK_scircumflex) + *upper -= (XK_cabovedot - XK_Cabovedot); + break; + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Rcedilla && sym <= XK_Tslash) + *lower += (XK_rcedilla - XK_Rcedilla); + else if (sym >= XK_rcedilla && sym <= XK_tslash) + *upper -= (XK_rcedilla - XK_Rcedilla); + else if (sym == XK_ENG) + *lower = XK_eng; + else if (sym == XK_eng) + *upper = XK_ENG; + else if (sym >= XK_Amacron && sym <= XK_Umacron) + *lower += (XK_amacron - XK_Amacron); + else if (sym >= XK_amacron && sym <= XK_umacron) + *upper -= (XK_amacron - XK_Amacron); + break; + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) + *lower -= (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) + *upper += (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) + *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); + else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) + *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); + break; + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) + *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && + sym != XK_Greek_iotaaccentdieresis && + sym != XK_Greek_upsilonaccentdieresis) + *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) + *lower += (XK_Greek_alpha - XK_Greek_ALPHA); + else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && + sym != XK_Greek_finalsmallsigma) + *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); + break; + } +} + +static Bool +_XkbCopyClientMap(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + int i; + XkbKeyTypePtr stype = NULL, dtype = NULL; + + /* client map */ + if (src->map) { + if (!dst->map) { + tmp = calloc(1, sizeof(XkbClientMapRec)); + if (!tmp) + return FALSE; + dst->map = tmp; + } + + if (src->map->syms) { + if (src->map->size_syms != dst->map->size_syms) { + if (dst->map->syms) + tmp = realloc(dst->map->syms, + src->map->size_syms * sizeof(KeySym)); + else + tmp = malloc(src->map->size_syms * sizeof(KeySym)); + if (!tmp) + return FALSE; + dst->map->syms = tmp; + + } + memcpy(dst->map->syms, src->map->syms, + src->map->size_syms * sizeof(KeySym)); + } + else { + if (dst->map->syms) { + free(dst->map->syms); + dst->map->syms = NULL; + } + } + dst->map->num_syms = src->map->num_syms; + dst->map->size_syms = src->map->size_syms; + + if (src->map->key_sym_map) { + if (src->max_key_code != dst->max_key_code) { + if (dst->map->key_sym_map) + tmp = realloc(dst->map->key_sym_map, + (src->max_key_code + 1) * + sizeof(XkbSymMapRec)); + else + tmp = malloc((src->max_key_code + 1) * + sizeof(XkbSymMapRec)); + if (!tmp) + return FALSE; + dst->map->key_sym_map = tmp; + } + memcpy(dst->map->key_sym_map, src->map->key_sym_map, + (src->max_key_code + 1) * sizeof(XkbSymMapRec)); + } + else { + if (dst->map->key_sym_map) { + free(dst->map->key_sym_map); + dst->map->key_sym_map = NULL; + } + } + + if (src->map->types && src->map->num_types) { + if (src->map->num_types > dst->map->size_types || + !dst->map->types || !dst->map->size_types) { + if (dst->map->types && dst->map->size_types) { + tmp = realloc(dst->map->types, + src->map->num_types * sizeof(XkbKeyTypeRec)); + if (!tmp) + return FALSE; + dst->map->types = tmp; + bzero(dst->map->types + dst->map->num_types, + (src->map->num_types - dst->map->num_types) * + sizeof(XkbKeyTypeRec)); + } + else { + tmp = calloc(src->map->num_types, sizeof(XkbKeyTypeRec)); + if (!tmp) + return FALSE; + dst->map->types = tmp; + } + } + else if (src->map->num_types < dst->map->num_types && + dst->map->types) { + for (i = src->map->num_types, dtype = (dst->map->types + i); + i < dst->map->num_types; i++, dtype++) { + if (dtype->level_names) + free(dtype->level_names); + dtype->level_names = NULL; + dtype->num_levels = 0; + if (dtype->map_count) { + if (dtype->map) + free(dtype->map); + if (dtype->preserve) + free(dtype->preserve); + } + } + } + + stype = src->map->types; + dtype = dst->map->types; + for (i = 0; i < src->map->num_types; i++, dtype++, stype++) { + if (stype->num_levels && stype->level_names) { + if (stype->num_levels != dtype->num_levels && + dtype->num_levels && dtype->level_names && + i < dst->map->num_types) { + tmp = realloc(dtype->level_names, + stype->num_levels * sizeof(Atom)); + if (!tmp) + continue; + dtype->level_names = tmp; + } + else if (!dtype->num_levels || !dtype->level_names || + i >= dst->map->num_types) { + tmp = malloc(stype->num_levels * sizeof(Atom)); + if (!tmp) + continue; + dtype->level_names = tmp; + } + dtype->num_levels = stype->num_levels; + memcpy(dtype->level_names, stype->level_names, + stype->num_levels * sizeof(Atom)); + } + else { + if (dtype->num_levels && dtype->level_names && + i < dst->map->num_types) + free(dtype->level_names); + dtype->num_levels = 0; + dtype->level_names = NULL; + } + + dtype->name = stype->name; + memcpy(&dtype->mods, &stype->mods, sizeof(XkbModsRec)); + + if (stype->map_count) { + if (stype->map) { + if (stype->map_count != dtype->map_count && + dtype->map_count && dtype->map && + i < dst->map->num_types) { + tmp = realloc(dtype->map, + stype->map_count * + sizeof(XkbKTMapEntryRec)); + if (!tmp) + return FALSE; + dtype->map = tmp; + } + else if (!dtype->map_count || !dtype->map || + i >= dst->map->num_types) { + tmp = malloc(stype->map_count * + sizeof(XkbKTMapEntryRec)); + if (!tmp) + return FALSE; + dtype->map = tmp; + } + + memcpy(dtype->map, stype->map, + stype->map_count * sizeof(XkbKTMapEntryRec)); + } + else { + if (dtype->map && i < dst->map->num_types) + free(dtype->map); + dtype->map = NULL; + } + + if (stype->preserve) { + if (stype->map_count != dtype->map_count && + dtype->map_count && dtype->preserve && + i < dst->map->num_types) { + tmp = realloc(dtype->preserve, + stype->map_count * + sizeof(XkbModsRec)); + if (!tmp) + return FALSE; + dtype->preserve = tmp; + } + else if (!dtype->preserve || !dtype->map_count || + i >= dst->map->num_types) { + tmp = malloc(stype->map_count * + sizeof(XkbModsRec)); + if (!tmp) + return FALSE; + dtype->preserve = tmp; + } + + memcpy(dtype->preserve, stype->preserve, + stype->map_count * sizeof(XkbModsRec)); + } + else { + if (dtype->preserve && i < dst->map->num_types) + free(dtype->preserve); + dtype->preserve = NULL; + } + + dtype->map_count = stype->map_count; + } + else { + if (dtype->map_count && i < dst->map->num_types) { + if (dtype->map) + free(dtype->map); + if (dtype->preserve) + free(dtype->preserve); + } + dtype->map_count = 0; + dtype->map = NULL; + dtype->preserve = NULL; + } + } + + dst->map->size_types = src->map->num_types; + dst->map->num_types = src->map->num_types; + } + else { + if (dst->map->types) { + for (i = 0, dtype = dst->map->types; i < dst->map->num_types; + i++, dtype++) { + if (dtype->level_names) + free(dtype->level_names); + if (dtype->map && dtype->map_count) + free(dtype->map); + if (dtype->preserve && dtype->map_count) + free(dtype->preserve); + } + free(dst->map->types); + dst->map->types = NULL; + } + dst->map->num_types = 0; + dst->map->size_types = 0; + } + + if (src->map->modmap) { + if (src->max_key_code != dst->max_key_code) { + if (dst->map->modmap) + tmp = realloc(dst->map->modmap, src->max_key_code + 1); + else + tmp = malloc(src->max_key_code + 1); + if (!tmp) + return FALSE; + dst->map->modmap = tmp; + } + memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1); + } + else { + if (dst->map->modmap) { + free(dst->map->modmap); + dst->map->modmap = NULL; + } + } + } + else { + if (dst->map) + XkbFreeClientMap(dst, XkbAllClientInfoMask, TRUE); + } + + return TRUE; +} + +static Bool +_XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + + /* server map */ + if (src->server) { + if (!dst->server) { + tmp = calloc(1, sizeof(XkbServerMapRec)); + if (!tmp) + return FALSE; + dst->server = tmp; + } + + if (src->server->explicit) { + if (src->max_key_code != dst->max_key_code) { + if (dst->server->explicit) + tmp = realloc(dst->server->explicit, src->max_key_code + 1); + else + tmp = malloc(src->max_key_code + 1); + if (!tmp) + return FALSE; + dst->server->explicit = tmp; + } + memcpy(dst->server->explicit, src->server->explicit, + src->max_key_code + 1); + } + else { + if (dst->server->explicit) { + free(dst->server->explicit); + dst->server->explicit = NULL; + } + } + + if (src->server->acts) { + if (src->server->size_acts != dst->server->size_acts) { + if (dst->server->acts) + tmp = realloc(dst->server->acts, + src->server->size_acts * sizeof(XkbAction)); + else + tmp = malloc(src->server->size_acts * sizeof(XkbAction)); + if (!tmp) + return FALSE; + dst->server->acts = tmp; + } + memcpy(dst->server->acts, src->server->acts, + src->server->size_acts * sizeof(XkbAction)); + } + else { + if (dst->server->acts) { + free(dst->server->acts); + dst->server->acts = NULL; + } + } + dst->server->size_acts = src->server->size_acts; + dst->server->num_acts = src->server->num_acts; + + if (src->server->key_acts) { + if (src->max_key_code != dst->max_key_code) { + if (dst->server->key_acts) + tmp = realloc(dst->server->key_acts, + (src->max_key_code + 1) * + sizeof(unsigned short)); + else + tmp = malloc((src->max_key_code + 1) * + sizeof(unsigned short)); + if (!tmp) + return FALSE; + dst->server->key_acts = tmp; + } + memcpy(dst->server->key_acts, src->server->key_acts, + (src->max_key_code + 1) * sizeof(unsigned short)); + } + else { + if (dst->server->key_acts) { + free(dst->server->key_acts); + dst->server->key_acts = NULL; + } + } + + if (src->server->behaviors) { + if (src->max_key_code != dst->max_key_code) { + if (dst->server->behaviors) + tmp = realloc(dst->server->behaviors, + (src->max_key_code + 1) * + sizeof(XkbBehavior)); + else + tmp = malloc((src->max_key_code + 1) * + sizeof(XkbBehavior)); + if (!tmp) + return FALSE; + dst->server->behaviors = tmp; + } + memcpy(dst->server->behaviors, src->server->behaviors, + (src->max_key_code + 1) * sizeof(XkbBehavior)); + } + else { + if (dst->server->behaviors) { + free(dst->server->behaviors); + dst->server->behaviors = NULL; + } + } + + memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods); + + if (src->server->vmodmap) { + if (src->max_key_code != dst->max_key_code) { + if (dst->server->vmodmap) + tmp = realloc(dst->server->vmodmap, + (src->max_key_code + 1) * + sizeof(unsigned short)); + else + tmp = malloc((src->max_key_code + 1) * + sizeof(unsigned short)); + if (!tmp) + return FALSE; + dst->server->vmodmap = tmp; + } + memcpy(dst->server->vmodmap, src->server->vmodmap, + (src->max_key_code + 1) * sizeof(unsigned short)); + } + else { + if (dst->server->vmodmap) { + free(dst->server->vmodmap); + dst->server->vmodmap = NULL; + } + } + } + else { + if (dst->server) + XkbFreeServerMap(dst, XkbAllServerInfoMask, TRUE); + } + + return TRUE; +} + +static Bool +_XkbCopyNames(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + + /* names */ + if (src->names) { + if (!dst->names) { + dst->names = calloc(1, sizeof(XkbNamesRec)); + if (!dst->names) + return FALSE; + } + + if (src->names->keys) { + if (src->max_key_code != dst->max_key_code) { + if (dst->names->keys) + tmp = realloc(dst->names->keys, (src->max_key_code + 1) * + sizeof(XkbKeyNameRec)); + else + tmp = malloc((src->max_key_code + 1) * + sizeof(XkbKeyNameRec)); + if (!tmp) + return FALSE; + dst->names->keys = tmp; + } + memcpy(dst->names->keys, src->names->keys, + (src->max_key_code + 1) * sizeof(XkbKeyNameRec)); + } + else { + if (dst->names->keys) { + free(dst->names->keys); + dst->names->keys = NULL; + } + } + + if (src->names->num_key_aliases) { + if (src->names->num_key_aliases != dst->names->num_key_aliases) { + if (dst->names->key_aliases) + tmp = realloc(dst->names->key_aliases, + src->names->num_key_aliases * + sizeof(XkbKeyAliasRec)); + else + tmp = malloc(src->names->num_key_aliases * + sizeof(XkbKeyAliasRec)); + if (!tmp) + return FALSE; + dst->names->key_aliases = tmp; + } + memcpy(dst->names->key_aliases, src->names->key_aliases, + src->names->num_key_aliases * sizeof(XkbKeyAliasRec)); + } + else { + if (dst->names->key_aliases) { + free(dst->names->key_aliases); + dst->names->key_aliases = NULL; + } + } + dst->names->num_key_aliases = src->names->num_key_aliases; + + if (src->names->num_rg) { + if (src->names->num_rg != dst->names->num_rg) { + if (dst->names->radio_groups) + tmp = realloc(dst->names->radio_groups, + src->names->num_rg * sizeof(Atom)); + else + tmp = malloc(src->names->num_rg * sizeof(Atom)); + if (!tmp) + return FALSE; + dst->names->radio_groups = tmp; + } + memcpy(dst->names->radio_groups, src->names->radio_groups, + src->names->num_rg * sizeof(Atom)); + } + else { + if (dst->names->radio_groups) + free(dst->names->radio_groups); + } + dst->names->num_rg = src->names->num_rg; + + dst->names->keycodes = src->names->keycodes; + dst->names->geometry = src->names->geometry; + dst->names->symbols = src->names->symbols; + dst->names->types = src->names->types; + dst->names->compat = src->names->compat; + dst->names->phys_symbols = src->names->phys_symbols; + + memcpy(dst->names->vmods, src->names->vmods, + XkbNumVirtualMods * sizeof(Atom)); + memcpy(dst->names->indicators, src->names->indicators, + XkbNumIndicators * sizeof(Atom)); + memcpy(dst->names->groups, src->names->groups, + XkbNumKbdGroups * sizeof(Atom)); + } + else { + if (dst->names) + XkbFreeNames(dst, XkbAllNamesMask, TRUE); + } + + return TRUE; +} + +static Bool +_XkbCopyCompat(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + + /* compat */ + if (src->compat) { + if (!dst->compat) { + dst->compat = calloc(1, sizeof(XkbCompatMapRec)); + if (!dst->compat) + return FALSE; + } + + if (src->compat->sym_interpret && src->compat->num_si) { + if (src->compat->num_si != dst->compat->size_si) { + if (dst->compat->sym_interpret) + tmp = realloc(dst->compat->sym_interpret, + src->compat->num_si * + sizeof(XkbSymInterpretRec)); + else + tmp = malloc(src->compat->num_si * + sizeof(XkbSymInterpretRec)); + if (!tmp) + return FALSE; + dst->compat->sym_interpret = tmp; + } + memcpy(dst->compat->sym_interpret, src->compat->sym_interpret, + src->compat->num_si * sizeof(XkbSymInterpretRec)); + + dst->compat->num_si = src->compat->num_si; + dst->compat->size_si = src->compat->num_si; + } + else { + if (dst->compat->sym_interpret && dst->compat->size_si) + free(dst->compat->sym_interpret); + + dst->compat->sym_interpret = NULL; + dst->compat->num_si = 0; + dst->compat->size_si = 0; + } + + memcpy(dst->compat->groups, src->compat->groups, + XkbNumKbdGroups * sizeof(XkbModsRec)); + } + else { + if (dst->compat) + XkbFreeCompatMap(dst, XkbAllCompatMask, TRUE); + } + + return TRUE; +} + +static Bool +_XkbCopyGeom(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + int i = 0, j = 0, k = 0; + XkbColorPtr scolor = NULL, dcolor = NULL; + XkbDoodadPtr sdoodad = NULL, ddoodad = NULL; + XkbOutlinePtr soutline = NULL, doutline = NULL; + XkbPropertyPtr sprop = NULL, dprop = NULL; + XkbRowPtr srow = NULL, drow = NULL; + XkbSectionPtr ssection = NULL, dsection = NULL; + XkbShapePtr sshape = NULL, dshape = NULL; + + /* geometry */ + if (src->geom) { + if (!dst->geom) { + dst->geom = calloc(sizeof(XkbGeometryRec), 1); + if (!dst->geom) + return FALSE; + } + + /* properties */ + if (src->geom->num_properties) { + if (src->geom->num_properties != dst->geom->sz_properties) { + /* If we've got more properties in the destination than + * the source, run through and free all the excess ones + * first. */ + if (src->geom->num_properties < dst->geom->sz_properties) { + for (i = src->geom->num_properties, + dprop = dst->geom->properties + i; + i < dst->geom->num_properties; + i++, dprop++) { + free(dprop->name); + free(dprop->value); + } + } + + if (dst->geom->sz_properties) + tmp = realloc(dst->geom->properties, + src->geom->num_properties * + sizeof(XkbPropertyRec)); + else + tmp = malloc(src->geom->num_properties * + sizeof(XkbPropertyRec)); + if (!tmp) + return FALSE; + dst->geom->properties = tmp; + } + + /* We don't set num_properties as we need it to try and avoid + * too much reallocing. */ + dst->geom->sz_properties = src->geom->num_properties; + + if (dst->geom->sz_properties > dst->geom->num_properties) { + bzero(dst->geom->properties + dst->geom->num_properties, + (dst->geom->sz_properties - dst->geom->num_properties) * + sizeof(XkbPropertyRec)); + } + + for (i = 0, + sprop = src->geom->properties, + dprop = dst->geom->properties; + i < src->geom->num_properties; + i++, sprop++, dprop++) { + if (i < dst->geom->num_properties) { + if (strlen(sprop->name) != strlen(dprop->name)) { + tmp = realloc(dprop->name, strlen(sprop->name) + 1); + if (!tmp) + return FALSE; + dprop->name = tmp; + } + if (strlen(sprop->value) != strlen(dprop->value)) { + tmp = realloc(dprop->value, strlen(sprop->value) + 1); + if (!tmp) + return FALSE; + dprop->value = tmp; + } + strcpy(dprop->name, sprop->name); + strcpy(dprop->value, sprop->value); + } + else { + dprop->name = xstrdup(sprop->name); + dprop->value = xstrdup(sprop->value); + } + } + + /* ... which is already src->geom->num_properties. */ + dst->geom->num_properties = dst->geom->sz_properties; + } + else { + if (dst->geom->sz_properties) { + for (i = 0, dprop = dst->geom->properties; + i < dst->geom->num_properties; + i++, dprop++) { + free(dprop->name); + free(dprop->value); + } + free(dst->geom->properties); + dst->geom->properties = NULL; + } + + dst->geom->num_properties = 0; + dst->geom->sz_properties = 0; + } + + /* colors */ + if (src->geom->num_colors) { + if (src->geom->num_colors != dst->geom->sz_colors) { + if (src->geom->num_colors < dst->geom->sz_colors) { + for (i = src->geom->num_colors, + dcolor = dst->geom->colors + i; + i < dst->geom->num_colors; + i++, dcolor++) { + free(dcolor->spec); + } + } + + if (dst->geom->sz_colors) + tmp = realloc(dst->geom->colors, + src->geom->num_colors * + sizeof(XkbColorRec)); + else + tmp = malloc(src->geom->num_colors * + sizeof(XkbColorRec)); + if (!tmp) + return FALSE; + dst->geom->colors = tmp; + } + + dst->geom->sz_colors = src->geom->num_colors; + + if (dst->geom->sz_colors > dst->geom->num_colors) { + bzero(dst->geom->colors + dst->geom->num_colors, + (dst->geom->sz_colors - dst->geom->num_colors) * + sizeof(XkbColorRec)); + } + + for (i = 0, + scolor = src->geom->colors, + dcolor = dst->geom->colors; + i < src->geom->num_colors; + i++, scolor++, dcolor++) { + if (i < dst->geom->num_colors) { + if (strlen(scolor->spec) != strlen(dcolor->spec)) { + tmp = realloc(dcolor->spec, strlen(scolor->spec) + 1); + if (!tmp) + return FALSE; + dcolor->spec = tmp; + } + strcpy(dcolor->spec, scolor->spec); + } + else { + dcolor->spec = xstrdup(scolor->spec); + } + dcolor->pixel = scolor->pixel; + } + + dst->geom->num_colors = dst->geom->sz_colors; + } + else { + if (dst->geom->sz_colors) { + for (i = 0, dcolor = dst->geom->colors; + i < dst->geom->num_colors; + i++, dcolor++) { + free(dcolor->spec); + } + free(dst->geom->colors); + dst->geom->colors = NULL; + } + + dst->geom->num_colors = 0; + dst->geom->sz_colors = 0; + } + + /* shapes */ + /* shapes break down into outlines, which break down into points. */ + if (dst->geom->num_shapes) { + for (i = 0, dshape = dst->geom->shapes; + i < dst->geom->num_shapes; + i++, dshape++) { + for (j = 0, doutline = dshape->outlines; + j < dshape->num_outlines; + j++, doutline++) { + if (doutline->sz_points) + free(doutline->points); + } + + if (dshape->sz_outlines) { + free(dshape->outlines); + dshape->outlines = NULL; + } + + dshape->num_outlines = 0; + dshape->sz_outlines = 0; + } + } + + if (src->geom->num_shapes) { + tmp = calloc(src->geom->num_shapes, sizeof(XkbShapeRec)); + if (!tmp) + return FALSE; + dst->geom->shapes = tmp; + + for (i = 0, sshape = src->geom->shapes, dshape = dst->geom->shapes; + i < src->geom->num_shapes; + i++, sshape++, dshape++) { + if (sshape->num_outlines) { + tmp = calloc(sshape->num_outlines, sizeof(XkbOutlineRec)); + if (!tmp) + return FALSE; + dshape->outlines = tmp; + + for (j = 0, + soutline = sshape->outlines, + doutline = dshape->outlines; + j < sshape->num_outlines; + j++, soutline++, doutline++) { + if (soutline->num_points) { + tmp = malloc(soutline->num_points * + sizeof(XkbPointRec)); + if (!tmp) + return FALSE; + doutline->points = tmp; + + memcpy(doutline->points, soutline->points, + soutline->num_points * sizeof(XkbPointRec)); + + doutline->corner_radius = soutline->corner_radius; + } + + doutline->num_points = soutline->num_points; + doutline->sz_points = soutline->num_points; + } + } + + dshape->num_outlines = sshape->num_outlines; + dshape->sz_outlines = sshape->num_outlines; + dshape->name = sshape->name; + dshape->bounds = sshape->bounds; + + dshape->approx = NULL; + if (sshape->approx && sshape->num_outlines > 0) { + + const ptrdiff_t approx_idx = + sshape->approx - sshape->outlines; + + if (approx_idx < dshape->num_outlines) { + dshape->approx = dshape->outlines + approx_idx; + } else { + LogMessage(X_WARNING, "XKB: approx outline " + "index is out of range\n"); + } + } + + dshape->primary = NULL; + if (sshape->primary && sshape->num_outlines > 0) { + + const ptrdiff_t primary_idx = + sshape->primary - sshape->outlines; + + if (primary_idx < dshape->num_outlines) { + dshape->primary = dshape->outlines + primary_idx; + } else { + LogMessage(X_WARNING, "XKB: primary outline " + "index is out of range\n"); + } + } + } + + dst->geom->num_shapes = src->geom->num_shapes; + dst->geom->sz_shapes = src->geom->num_shapes; + } + else { + if (dst->geom->sz_shapes) { + free(dst->geom->shapes); + } + dst->geom->shapes = NULL; + dst->geom->num_shapes = 0; + dst->geom->sz_shapes = 0; + } + + /* sections */ + /* sections break down into doodads, and also into rows, which break + * down into keys. */ + if (dst->geom->num_sections) { + for (i = 0, dsection = dst->geom->sections; + i < dst->geom->num_sections; + i++, dsection++) { + for (j = 0, drow = dsection->rows; + j < dsection->num_rows; + j++, drow++) { + if (drow->num_keys) + free(drow->keys); + } + + if (dsection->num_rows) + free(dsection->rows); + + /* cut and waste from geom/doodad below. */ + for (j = 0, ddoodad = dsection->doodads; + j < dsection->num_doodads; + j++, ddoodad++) { + if (ddoodad->any.type == XkbTextDoodad) { + if (ddoodad->text.text) { + free(ddoodad->text.text); + ddoodad->text.text = NULL; + } + if (ddoodad->text.font) { + free(ddoodad->text.font); + ddoodad->text.font = NULL; + } + } + else if (ddoodad->any.type == XkbLogoDoodad) { + if (ddoodad->logo.logo_name) { + free(ddoodad->logo.logo_name); + ddoodad->logo.logo_name = NULL; + } + } + } + + if (dsection->num_doodads) + free(dsection->doodads); + } + + dst->geom->num_sections = 0; + dst->geom->sections = NULL; + } + + if (src->geom->num_sections) { + if (dst->geom->sz_sections) + tmp = realloc(dst->geom->sections, + src->geom->num_sections * + sizeof(XkbSectionRec)); + else + tmp = malloc(src->geom->num_sections * sizeof(XkbSectionRec)); + if (!tmp) + return FALSE; + memset(tmp, 0, src->geom->num_sections * sizeof(XkbSectionRec)); + dst->geom->sections = tmp; + dst->geom->num_sections = src->geom->num_sections; + dst->geom->sz_sections = src->geom->num_sections; + + for (i = 0, + ssection = src->geom->sections, + dsection = dst->geom->sections; + i < src->geom->num_sections; + i++, ssection++, dsection++) { + *dsection = *ssection; + if (ssection->num_rows) { + tmp = calloc(ssection->num_rows, sizeof(XkbRowRec)); + if (!tmp) + return FALSE; + dsection->rows = tmp; + } + dsection->num_rows = ssection->num_rows; + dsection->sz_rows = ssection->num_rows; + + for (j = 0, srow = ssection->rows, drow = dsection->rows; + j < ssection->num_rows; + j++, srow++, drow++) { + if (srow->num_keys) { + tmp = malloc(srow->num_keys * sizeof(XkbKeyRec)); + if (!tmp) + return FALSE; + drow->keys = tmp; + memcpy(drow->keys, srow->keys, + srow->num_keys * sizeof(XkbKeyRec)); + } + drow->num_keys = srow->num_keys; + drow->sz_keys = srow->num_keys; + drow->top = srow->top; + drow->left = srow->left; + drow->vertical = srow->vertical; + drow->bounds = srow->bounds; + } + + if (ssection->num_doodads) { + tmp = calloc(ssection->num_doodads, sizeof(XkbDoodadRec)); + if (!tmp) + return FALSE; + dsection->doodads = tmp; + } + else { + dsection->doodads = NULL; + } + + dsection->sz_doodads = ssection->num_doodads; + for (k = 0, + sdoodad = ssection->doodads, + ddoodad = dsection->doodads; + k < ssection->num_doodads; + k++, sdoodad++, ddoodad++) { + memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec)); + if (sdoodad->any.type == XkbTextDoodad) { + if (sdoodad->text.text) + ddoodad->text.text = + xstrdup(sdoodad->text.text); + if (sdoodad->text.font) + ddoodad->text.font = + xstrdup(sdoodad->text.font); + } + else if (sdoodad->any.type == XkbLogoDoodad) { + if (sdoodad->logo.logo_name) + ddoodad->logo.logo_name = + xstrdup(sdoodad->logo.logo_name); + } + } + dsection->overlays = NULL; + dsection->sz_overlays = 0; + dsection->num_overlays = 0; + } + } + else { + if (dst->geom->sz_sections) { + free(dst->geom->sections); + } + + dst->geom->sections = NULL; + dst->geom->num_sections = 0; + dst->geom->sz_sections = 0; + } + + /* doodads */ + if (dst->geom->num_doodads) { + for (i = src->geom->num_doodads, + ddoodad = dst->geom->doodads + + src->geom->num_doodads; + i < dst->geom->num_doodads; + i++, ddoodad++) { + if (ddoodad->any.type == XkbTextDoodad) { + if (ddoodad->text.text) { + free(ddoodad->text.text); + ddoodad->text.text = NULL; + } + if (ddoodad->text.font) { + free(ddoodad->text.font); + ddoodad->text.font = NULL; + } + } + else if (ddoodad->any.type == XkbLogoDoodad) { + if (ddoodad->logo.logo_name) { + free(ddoodad->logo.logo_name); + ddoodad->logo.logo_name = NULL; + } + } + } + dst->geom->num_doodads = 0; + dst->geom->doodads = NULL; + } + + if (src->geom->num_doodads) { + if (dst->geom->sz_doodads) + tmp = realloc(dst->geom->doodads, + src->geom->num_doodads * + sizeof(XkbDoodadRec)); + else + tmp = malloc(src->geom->num_doodads * + sizeof(XkbDoodadRec)); + if (!tmp) + return FALSE; + memset(tmp, 0, src->geom->num_doodads * sizeof(XkbDoodadRec)); + dst->geom->doodads = tmp; + + dst->geom->sz_doodads = src->geom->num_doodads; + + for (i = 0, + sdoodad = src->geom->doodads, + ddoodad = dst->geom->doodads; + i < src->geom->num_doodads; + i++, sdoodad++, ddoodad++) { + memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec)); + if (sdoodad->any.type == XkbTextDoodad) { + if (sdoodad->text.text) + ddoodad->text.text = xstrdup(sdoodad->text.text); + if (sdoodad->text.font) + ddoodad->text.font = xstrdup(sdoodad->text.font); + } + else if (sdoodad->any.type == XkbLogoDoodad) { + if (sdoodad->logo.logo_name) + ddoodad->logo.logo_name = + xstrdup(sdoodad->logo.logo_name); + } + } + + dst->geom->num_doodads = dst->geom->sz_doodads; + } + else { + if (dst->geom->sz_doodads) { + free(dst->geom->doodads); + } + + dst->geom->doodads = NULL; + dst->geom->num_doodads = 0; + dst->geom->sz_doodads = 0; + } + + /* key aliases */ + if (src->geom->num_key_aliases) { + if (src->geom->num_key_aliases != dst->geom->sz_key_aliases) { + if (dst->geom->sz_key_aliases) + tmp = realloc(dst->geom->key_aliases, + src->geom->num_key_aliases * + 2 * XkbKeyNameLength); + else + tmp = malloc(src->geom->num_key_aliases * + 2 * XkbKeyNameLength); + if (!tmp) + return FALSE; + dst->geom->key_aliases = tmp; + + dst->geom->sz_key_aliases = src->geom->num_key_aliases; + } + + memcpy(dst->geom->key_aliases, src->geom->key_aliases, + src->geom->num_key_aliases * 2 * XkbKeyNameLength); + + dst->geom->num_key_aliases = dst->geom->sz_key_aliases; + } + else { + if (dst->geom->key_aliases) { + free(dst->geom->key_aliases); + } + dst->geom->key_aliases = NULL; + dst->geom->num_key_aliases = 0; + dst->geom->sz_key_aliases = 0; + } + + /* font */ + if (src->geom->label_font) { + if (!dst->geom->label_font) { + tmp = malloc(strlen(src->geom->label_font)); + if (!tmp) + return FALSE; + dst->geom->label_font = tmp; + } + else if (strlen(src->geom->label_font) != + strlen(dst->geom->label_font)) { + tmp = realloc(dst->geom->label_font, + strlen(src->geom->label_font)); + if (!tmp) + return FALSE; + dst->geom->label_font = tmp; + } + + strcpy(dst->geom->label_font, src->geom->label_font); + i = XkbGeomColorIndex(src->geom, src->geom->label_color); + dst->geom->label_color = &(dst->geom->colors[i]); + i = XkbGeomColorIndex(src->geom, src->geom->base_color); + dst->geom->base_color = &(dst->geom->colors[i]); + } + else { + if (dst->geom->label_font) { + free(dst->geom->label_font); + } + dst->geom->label_font = NULL; + dst->geom->label_color = NULL; + dst->geom->base_color = NULL; + } + + dst->geom->name = src->geom->name; + dst->geom->width_mm = src->geom->width_mm; + dst->geom->height_mm = src->geom->height_mm; + } + else + { + if (dst->geom) { + /* I LOVE THE DIFFERENT CALL SIGNATURE. REALLY, I DO. */ + XkbFreeGeometry(dst->geom, XkbGeomAllMask, TRUE); + dst->geom = NULL; + } + } + + return TRUE; +} + +static Bool +_XkbCopyIndicators(XkbDescPtr src, XkbDescPtr dst) +{ + /* indicators */ + if (src->indicators) { + if (!dst->indicators) { + dst->indicators = malloc(sizeof(XkbIndicatorRec)); + if (!dst->indicators) + return FALSE; + } + memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec)); + } + else { + if (dst->indicators) { + free(dst->indicators); + dst->indicators = NULL; + } + } + return TRUE; +} + +static Bool +_XkbCopyControls(XkbDescPtr src, XkbDescPtr dst) +{ + /* controls */ + if (src->ctrls) { + if (!dst->ctrls) { + dst->ctrls = malloc(sizeof(XkbControlsRec)); + if (!dst->ctrls) + return FALSE; + } + memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec)); + } + else { + if (dst->ctrls) { + free(dst->ctrls); + dst->ctrls = NULL; + } + } + return TRUE; +} + +/** + * Copy an XKB map from src to dst, reallocating when necessary: if some + * map components are present in one, but not in the other, the destination + * components will be allocated or freed as necessary. + * + * Basic map consistency is assumed on both sides, so maps with random + * uninitialised data (e.g. names->radio_grous == NULL, names->num_rg == 19) + * _will_ cause failures. You've been warned. + * + * Returns TRUE on success, or FALSE on failure. If this function fails, + * dst may be in an inconsistent state: all its pointers are guaranteed + * to remain valid, but part of the map may be from src and part from dst. + * + */ + +Bool +XkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src) +{ + + if (!src || !dst) { + DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst); + return FALSE; + } + + if (src == dst) + return TRUE; + + if (!_XkbCopyClientMap(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy client map\n"); + return FALSE; + } + if (!_XkbCopyServerMap(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy server map\n"); + return FALSE; + } + if (!_XkbCopyIndicators(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy indicators\n"); + return FALSE; + } + if (!_XkbCopyControls(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy controls\n"); + return FALSE; + } + if (!_XkbCopyNames(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy names\n"); + return FALSE; + } + if (!_XkbCopyCompat(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy compat map\n"); + return FALSE; + } + if (!_XkbCopyGeom(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy geometry\n"); + return FALSE; + } + + dst->min_key_code = src->min_key_code; + dst->max_key_code = src->max_key_code; + + return TRUE; +} + +Bool +XkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src) +{ + xkbNewKeyboardNotify nkn; + Bool ret; + + if (!dst->key || !src->key) + return FALSE; + + memset(&nkn, 0, sizeof(xkbNewKeyboardNotify)); + nkn.oldMinKeyCode = dst->key->xkbInfo->desc->min_key_code; + nkn.oldMaxKeyCode = dst->key->xkbInfo->desc->max_key_code; + nkn.deviceID = dst->id; + nkn.oldDeviceID = dst->id; /* maybe src->id? */ + nkn.minKeyCode = src->key->xkbInfo->desc->min_key_code; + nkn.maxKeyCode = src->key->xkbInfo->desc->max_key_code; + nkn.requestMajor = XkbReqCode; + nkn.requestMinor = X_kbSetMap; /* Near enough's good enough. */ + nkn.changed = XkbNKN_KeycodesMask; + if (src->key->xkbInfo->desc->geom) + nkn.changed |= XkbNKN_GeometryMask; + + ret = XkbCopyKeymap(dst->key->xkbInfo->desc, src->key->xkbInfo->desc); + if (ret) + XkbSendNewKeyboardNotify(dst, &nkn); + + return ret; +} + +int +XkbGetEffectiveGroup(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 keycode) +{ + XkbDescPtr xkb = xkbi->desc; + int effectiveGroup = xkbState->group; + + if (!XkbKeycodeInRange(xkb, keycode)) + return -1; + + if (effectiveGroup == XkbGroup1Index) + return effectiveGroup; + + if (XkbKeyNumGroups(xkb,keycode) > 1U) { + if (effectiveGroup >= XkbKeyNumGroups(xkb,keycode)) { + unsigned int gi = XkbKeyGroupInfo(xkb,keycode); + switch (XkbOutOfRangeGroupAction(gi)) { + default: + case XkbWrapIntoRange: + effectiveGroup %= XkbKeyNumGroups(xkb, keycode); + break; + case XkbClampIntoRange: + effectiveGroup = XkbKeyNumGroups(xkb, keycode) - 1; + break; + case XkbRedirectIntoRange: + effectiveGroup = XkbOutOfRangeGroupInfo(gi); + if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode)) + effectiveGroup = 0; + break; + } + } + } + else effectiveGroup = XkbGroup1Index; + + return effectiveGroup; +} diff --git a/xorg-server/xkb/xkmread.c b/xorg-server/xkb/xkmread.c index a201731f3..660884a7f 100644 --- a/xorg-server/xkb/xkmread.c +++ b/xorg-server/xkb/xkmread.c @@ -1,1238 +1,1238 @@ -/************************************************************ - Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc. - - 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 Silicon Graphics not be - used in advertising or publicity pertaining to distribution - of the software without specific prior written permission. - Silicon Graphics makes no representation about the suitability - of this software for any purpose. It is provided "as is" - without any express or implied warranty. - - SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON - GRAPHICS 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 <dix-config.h> -#endif - -#include <stdio.h> - -#include <X11/Xos.h> -#include <X11/Xfuncs.h> - -#include <X11/X.h> -#include <X11/Xproto.h> -#include <X11/keysym.h> -#include <X11/extensions/XKMformat.h> -#include "misc.h" -#include "inputstr.h" -#include "xkbstr.h" -#include "xkbsrv.h" -#include "xkbgeom.h" - -Atom -XkbInternAtom(char *str,Bool only_if_exists) -{ - if (str==NULL) - return None; - return MakeAtom(str,strlen(str),!only_if_exists); -} - -char * -_XkbDupString(const char *str) -{ -char *new; - - if (str==NULL) - return NULL; - new= xcalloc(strlen(str)+1,sizeof(char)); - if (new) - strcpy(new,str); - return new; -} - -/***====================================================================***/ - -static void * -XkmInsureSize(void *oldPtr,int oldCount,int *newCountRtrn,int elemSize) -{ -int newCount= *newCountRtrn; - - if (oldPtr==NULL) { - if (newCount==0) - return NULL; - oldPtr= xcalloc(newCount,elemSize); - } - else if (oldCount<newCount) { - oldPtr= xrealloc(oldPtr,newCount*elemSize); - if (oldPtr!=NULL) { - char *tmp= (char *)oldPtr; - bzero(&tmp[oldCount*elemSize],(newCount-oldCount)*elemSize); - } - } - else if (newCount<oldCount) { - *newCountRtrn= oldCount; - } - return oldPtr; -} - -#define XkmInsureTypedSize(p,o,n,t) ((p)=((t *)XkmInsureSize((char *)(p),(o),(n),sizeof(t)))) - -static CARD8 -XkmGetCARD8(FILE *file,int *pNRead) -{ -int tmp; - tmp= getc(file); - if (pNRead&&(tmp!=EOF)) - (*pNRead)+= 1; - return tmp; -} - -static CARD16 -XkmGetCARD16(FILE *file,int *pNRead) -{ -CARD16 val; - - if ((fread(&val,2,1,file)==1)&&(pNRead)) - (*pNRead)+= 2; - return val; -} - -static CARD32 -XkmGetCARD32(FILE *file,int *pNRead) -{ -CARD32 val; - - if ((fread(&val,4,1,file)==1)&&(pNRead)) - (*pNRead)+= 4; - return val; -} - -static int -XkmSkipPadding(FILE *file,unsigned pad) -{ -register int i,nRead=0; - - for (i=0;i<pad;i++) { - if (getc(file)!=EOF) - nRead++; - } - return nRead; -} - -static int -XkmGetCountedString(FILE *file,char *str,int max_len) -{ -int count,nRead=0; - - count= XkmGetCARD16(file,&nRead); - if (count>0) { - int tmp; - if (count>max_len) { - tmp= fread(str,1,max_len,file); - while (tmp<count) { - if ((getc(file))!=EOF) - tmp++; - else break; - } - } - else { - tmp= fread(str,1,count,file); - } - nRead+= tmp; - } - if (count>=max_len) str[max_len-1]= '\0'; - else str[count]= '\0'; - count= XkbPaddedSize(nRead)-nRead; - if (count>0) - nRead+= XkmSkipPadding(file,count); - return nRead; -} - -/***====================================================================***/ - -static int -ReadXkmVirtualMods(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) -{ -register unsigned int i,bit; -unsigned int bound,named,tmp; -int nRead=0; - - if (XkbAllocServerMap(xkb,XkbVirtualModsMask,0)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmVirtualMods",0); - return -1; - } - bound= XkmGetCARD16(file,&nRead); - named= XkmGetCARD16(file,&nRead); - for (i=tmp=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - if (bound&bit) { - xkb->server->vmods[i]= XkmGetCARD8(file,&nRead); - if (changes) - changes->map.vmods|= bit; - tmp++; - } - } - if ((i= XkbPaddedSize(tmp)-tmp)>0) - nRead+= XkmSkipPadding(file,i); - if (XkbAllocNames(xkb,XkbVirtualModNamesMask,0,0)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmVirtualMods",0); - return -1; - } - for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { - char name[100]; - if (named&bit) { - if (nRead+=XkmGetCountedString(file,name,100)) { - xkb->names->vmods[i]= XkbInternAtom(name,FALSE); - if (changes) - changes->names.changed_vmods|= bit; - } - } - } - return nRead; -} - -/***====================================================================***/ - -static int -ReadXkmKeycodes(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) -{ -register int i; -unsigned minKC,maxKC,nAl; -int nRead=0; -char name[100]; -XkbKeyNamePtr pN; - - name[0]= '\0'; - nRead+= XkmGetCountedString(file,name,100); - minKC= XkmGetCARD8(file,&nRead); - maxKC= XkmGetCARD8(file,&nRead); - if (xkb->min_key_code==0) { - xkb->min_key_code= minKC; - xkb->max_key_code= maxKC; - } - else { - if (minKC<xkb->min_key_code) - xkb->min_key_code= minKC; - if (maxKC>xkb->max_key_code) { - _XkbLibError(_XkbErrBadValue,"ReadXkmKeycodes",maxKC); - return -1; - } - } - nAl= XkmGetCARD8(file,&nRead); - nRead+= XkmSkipPadding(file,1); - -#define WANTED (XkbKeycodesNameMask|XkbKeyNamesMask|XkbKeyAliasesMask) - if (XkbAllocNames(xkb,WANTED,0,nAl)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmKeycodes",0); - return -1; - } - if (name[0]!='\0') { - xkb->names->keycodes= XkbInternAtom(name,FALSE); - } - - for (pN=&xkb->names->keys[minKC],i=minKC;i<=(int)maxKC;i++,pN++) { - if (fread(pN,1,XkbKeyNameLength,file)!=XkbKeyNameLength) { - _XkbLibError(_XkbErrBadLength,"ReadXkmKeycodes",0); - return -1; - } - nRead+= XkbKeyNameLength; - } - if (nAl>0) { - XkbKeyAliasPtr pAl; - for (pAl= xkb->names->key_aliases,i=0;i<nAl;i++,pAl++) { - int tmp; - tmp= fread(pAl,1,2*XkbKeyNameLength,file); - if (tmp!=2*XkbKeyNameLength) { - _XkbLibError(_XkbErrBadLength,"ReadXkmKeycodes",0); - return -1; - } - nRead+= 2*XkbKeyNameLength; - } - if (changes) - changes->names.changed|= XkbKeyAliasesMask; - } - if (changes) - changes->names.changed|= XkbKeyNamesMask; - return nRead; -} - -/***====================================================================***/ - -static int -ReadXkmKeyTypes(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) -{ -register unsigned i,n; -unsigned num_types; -int nRead=0; -int tmp; -XkbKeyTypePtr type; -xkmKeyTypeDesc wire; -XkbKTMapEntryPtr entry; -xkmKTMapEntryDesc wire_entry; -char buf[100]; - - if ((tmp= XkmGetCountedString(file,buf,100))<1) { - _XkbLibError(_XkbErrBadLength,"ReadXkmKeyTypes",0); - return -1; - } - nRead+= tmp; - if (buf[0]!='\0') { - if (XkbAllocNames(xkb,XkbTypesNameMask,0,0)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmKeyTypes",0); - return -1; - } - xkb->names->types= XkbInternAtom(buf,FALSE); - } - num_types= XkmGetCARD16(file,&nRead); - nRead+= XkmSkipPadding(file,2); - if (num_types<1) - return nRead; - if (XkbAllocClientMap(xkb,XkbKeyTypesMask,num_types)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmKeyTypes",0); - return nRead; - } - xkb->map->num_types= num_types; - if (num_types<XkbNumRequiredTypes) { - _XkbLibError(_XkbErrMissingReqTypes,"ReadXkmKeyTypes",0); - return -1; - } - type= xkb->map->types; - for (i=0;i<num_types;i++,type++) { - if ((int)fread(&wire,SIZEOF(xkmKeyTypeDesc),1,file)<1) { - _XkbLibError(_XkbErrBadLength,"ReadXkmKeyTypes",0); - return -1; - } - nRead+= SIZEOF(xkmKeyTypeDesc); - if (((i==XkbOneLevelIndex)&&(wire.numLevels!=1))|| - (((i==XkbTwoLevelIndex)||(i==XkbAlphabeticIndex)|| - ((i)==XkbKeypadIndex))&&(wire.numLevels!=2))) { - _XkbLibError(_XkbErrBadTypeWidth,"ReadXkmKeyTypes",i); - return -1; - } - tmp= wire.nMapEntries; - XkmInsureTypedSize(type->map,type->map_count,&tmp,XkbKTMapEntryRec); - if ((wire.nMapEntries>0)&&(type->map==NULL)) { - _XkbLibError(_XkbErrBadValue,"ReadXkmKeyTypes",wire.nMapEntries); - return -1; - } - for (n=0,entry= type->map;n<wire.nMapEntries;n++,entry++) { - if (fread(&wire_entry,SIZEOF(xkmKTMapEntryDesc),1,file)<(int)1) { - _XkbLibError(_XkbErrBadLength,"ReadXkmKeyTypes",0); - return -1; - } - nRead+= SIZEOF(xkmKTMapEntryDesc); - entry->active= (wire_entry.virtualMods==0); - entry->level= wire_entry.level; - entry->mods.mask= wire_entry.realMods; - entry->mods.real_mods= wire_entry.realMods; - entry->mods.vmods= wire_entry.virtualMods; - } - nRead+= XkmGetCountedString(file,buf,100); - if (((i==XkbOneLevelIndex)&&(strcmp(buf,"ONE_LEVEL")!=0))|| - ((i==XkbTwoLevelIndex)&&(strcmp(buf,"TWO_LEVEL")!=0))|| - ((i==XkbAlphabeticIndex)&&(strcmp(buf,"ALPHABETIC")!=0))|| - ((i==XkbKeypadIndex)&&(strcmp(buf,"KEYPAD")!=0))) { - _XkbLibError(_XkbErrBadTypeName,"ReadXkmKeyTypes",0); - return -1; - } - if (buf[0]!='\0') { - type->name= XkbInternAtom(buf,FALSE); - } - else type->name= None; - - if (wire.preserve) { - xkmModsDesc p_entry; - XkbModsPtr pre; - XkmInsureTypedSize(type->preserve,type->map_count,&tmp, - XkbModsRec); - if (type->preserve==NULL) { - _XkbLibError(_XkbErrBadMatch,"ReadXkmKeycodes",0); - return -1; - } - for (n=0,pre=type->preserve;n<wire.nMapEntries;n++,pre++) { - if (fread(&p_entry,SIZEOF(xkmModsDesc),1,file)<1) { - _XkbLibError(_XkbErrBadLength,"ReadXkmKeycodes",0); - return -1; - } - nRead+= SIZEOF(xkmModsDesc); - pre->mask= p_entry.realMods; - pre->real_mods= p_entry.realMods; - pre->vmods= p_entry.virtualMods; - } - } - if (wire.nLevelNames>0) { - int width= wire.numLevels; - if (wire.nLevelNames>(unsigned)width) { - _XkbLibError(_XkbErrBadMatch,"ReadXkmKeycodes",0); - return -1; - } - XkmInsureTypedSize(type->level_names,type->num_levels,&width,Atom); - if (type->level_names!=NULL) { - for (n=0;n<wire.nLevelNames;n++) { - if ((tmp=XkmGetCountedString(file,buf,100))<1) - return -1; - nRead+= tmp; - if (strlen(buf)==0) - type->level_names[n]= None; - else type->level_names[n]= XkbInternAtom(buf,0); - } - } - } - type->mods.mask= wire.realMods; - type->mods.real_mods= wire.realMods; - type->mods.vmods= wire.virtualMods; - type->num_levels= wire.numLevels; - type->map_count= wire.nMapEntries; - } - if (changes) { - changes->map.changed|= XkbKeyTypesMask; - changes->map.first_type= 0; - changes->map.num_types= xkb->map->num_types; - } - return nRead; -} - -/***====================================================================***/ - -static int -ReadXkmCompatMap(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) -{ -register int i; -unsigned num_si,groups; -char name[100]; -XkbSymInterpretPtr interp; -xkmSymInterpretDesc wire; -unsigned tmp; -int nRead=0; -XkbCompatMapPtr compat; -XkbAction *act; - - if ((tmp= XkmGetCountedString(file,name,100))<1) { - _XkbLibError(_XkbErrBadLength,"ReadXkmCompatMap",0); - return -1; - } - nRead+= tmp; - if (name[0]!='\0') { - if (XkbAllocNames(xkb,XkbCompatNameMask,0,0)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmCompatMap",0); - return -1; - } - xkb->names->compat= XkbInternAtom(name,FALSE); - } - num_si= XkmGetCARD16(file,&nRead); - groups= XkmGetCARD8(file,&nRead); - nRead+= XkmSkipPadding(file,1); - if (XkbAllocCompatMap(xkb,XkbAllCompatMask,num_si)!=Success) - return -1; - compat= xkb->compat; - compat->num_si= num_si; - interp= compat->sym_interpret; - for (i=0;i<num_si;i++,interp++) { - tmp= fread(&wire,SIZEOF(xkmSymInterpretDesc),1,file); - nRead+= tmp*SIZEOF(xkmSymInterpretDesc); - interp->sym= wire.sym; - interp->mods= wire.mods; - interp->match= wire.match; - interp->virtual_mod= wire.virtualMod; - interp->flags= wire.flags; - interp->act.type= wire.actionType; - act = (XkbAction *) &interp->act; - - switch (interp->act.type) { - case XkbSA_SetMods: - case XkbSA_LatchMods: - case XkbSA_LockMods: - act->mods.flags = wire.actionData[0]; - act->mods.mask = wire.actionData[1]; - act->mods.real_mods = wire.actionData[2]; - act->mods.vmods1 = wire.actionData[3]; - act->mods.vmods2 = wire.actionData[4]; - break; - case XkbSA_SetGroup: - case XkbSA_LatchGroup: - case XkbSA_LockGroup: - act->group.flags = wire.actionData[0]; - act->group.group_XXX = wire.actionData[1]; - break; - case XkbSA_MovePtr: - act->ptr.flags = wire.actionData[0]; - act->ptr.high_XXX = wire.actionData[1]; - act->ptr.low_XXX = wire.actionData[2]; - act->ptr.high_YYY = wire.actionData[3]; - act->ptr.low_YYY = wire.actionData[4]; - break; - case XkbSA_PtrBtn: - case XkbSA_LockPtrBtn: - act->btn.flags = wire.actionData[0]; - act->btn.count = wire.actionData[1]; - act->btn.button = wire.actionData[2]; - break; - case XkbSA_DeviceBtn: - case XkbSA_LockDeviceBtn: - act->devbtn.flags = wire.actionData[0]; - act->devbtn.count = wire.actionData[1]; - act->devbtn.button = wire.actionData[2]; - act->devbtn.device = wire.actionData[3]; - break; - case XkbSA_SetPtrDflt: - act->dflt.flags = wire.actionData[0]; - act->dflt.affect = wire.actionData[1]; - act->dflt.valueXXX = wire.actionData[2]; - break; - case XkbSA_ISOLock: - act->iso.flags = wire.actionData[0]; - act->iso.mask = wire.actionData[1]; - act->iso.real_mods = wire.actionData[2]; - act->iso.group_XXX = wire.actionData[3]; - act->iso.affect = wire.actionData[4]; - act->iso.vmods1 = wire.actionData[5]; - act->iso.vmods2 = wire.actionData[6]; - break; - case XkbSA_SwitchScreen: - act->screen.flags = wire.actionData[0]; - act->screen.screenXXX = wire.actionData[1]; - break; - case XkbSA_SetControls: - case XkbSA_LockControls: - act->ctrls.flags = wire.actionData[0]; - act->ctrls.ctrls3 = wire.actionData[1]; - act->ctrls.ctrls2 = wire.actionData[2]; - act->ctrls.ctrls1 = wire.actionData[3]; - act->ctrls.ctrls0 = wire.actionData[4]; - break; - case XkbSA_RedirectKey: - act->redirect.new_key = wire.actionData[0]; - act->redirect.mods_mask = wire.actionData[1]; - act->redirect.mods = wire.actionData[2]; - act->redirect.vmods_mask0 = wire.actionData[3]; - act->redirect.vmods_mask1 = wire.actionData[4]; - act->redirect.vmods0 = wire.actionData[4]; - act->redirect.vmods1 = wire.actionData[5]; - break; - case XkbSA_DeviceValuator: - act->devval.device = wire.actionData[0]; - act->devval.v1_what = wire.actionData[1]; - act->devval.v1_ndx = wire.actionData[2]; - act->devval.v1_value = wire.actionData[3]; - act->devval.v2_what = wire.actionData[4]; - act->devval.v2_ndx = wire.actionData[5]; - act->devval.v2_what = wire.actionData[6]; - break; - - case XkbSA_XFree86Private: - /* copy the kind of action */ - strncpy((char*)act->any.data, (char*)wire.actionData, - XkbAnyActionDataSize); - break ; - - case XkbSA_Terminate: - /* no args, kinda (note: untrue for xfree86). */ - break; - case XkbSA_ActionMessage: - /* unsupported. */ - break; - } - } - if ((num_si>0)&&(changes)) { - changes->compat.first_si= 0; - changes->compat.num_si= num_si; - } - if (groups) { - register unsigned bit; - for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { - xkmModsDesc md; - if (groups&bit) { - tmp= fread(&md,SIZEOF(xkmModsDesc),1,file); - nRead+= tmp*SIZEOF(xkmModsDesc); - xkb->compat->groups[i].real_mods= md.realMods; - xkb->compat->groups[i].vmods= md.virtualMods; - if (md.virtualMods != 0) { - unsigned mask; - if (XkbVirtualModsToReal(xkb,md.virtualMods,&mask)) - xkb->compat->groups[i].mask= md.realMods|mask; - } - else xkb->compat->groups[i].mask= md.realMods; - } - } - if (changes) - changes->compat.changed_groups|= groups; - } - return nRead; -} - -static int -ReadXkmIndicators(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) -{ -register unsigned nLEDs; -xkmIndicatorMapDesc wire; -char buf[100]; -unsigned tmp; -int nRead=0; - - if ((xkb->indicators==NULL)&&(XkbAllocIndicatorMaps(xkb)!=Success)) { - _XkbLibError(_XkbErrBadAlloc,"indicator rec",0); - return -1; - } - if (XkbAllocNames(xkb,XkbIndicatorNamesMask,0,0)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"indicator names",0); - return -1; - } - nLEDs= XkmGetCARD8(file,&nRead); - nRead+= XkmSkipPadding(file,3); - xkb->indicators->phys_indicators= XkmGetCARD32(file,&nRead); - while (nLEDs-->0) { - Atom name; - XkbIndicatorMapPtr map; - - if ((tmp=XkmGetCountedString(file,buf,100))<1) { - _XkbLibError(_XkbErrBadLength,"ReadXkmIndicators",0); - return -1; - } - nRead+= tmp; - if (buf[0]!='\0') - name= XkbInternAtom(buf,FALSE); - else name= None; - if ((tmp=fread(&wire,SIZEOF(xkmIndicatorMapDesc),1,file))<1) { - _XkbLibError(_XkbErrBadLength,"ReadXkmIndicators",0); - return -1; - } - nRead+= tmp*SIZEOF(xkmIndicatorMapDesc); - if (xkb->names) { - xkb->names->indicators[wire.indicator-1]= name; - if (changes) - changes->names.changed_indicators|= (1<<(wire.indicator-1)); - } - map= &xkb->indicators->maps[wire.indicator-1]; - map->flags= wire.flags; - map->which_groups= wire.which_groups; - map->groups= wire.groups; - map->which_mods= wire.which_mods; - map->mods.mask= wire.real_mods; - map->mods.real_mods= wire.real_mods; - map->mods.vmods= wire.vmods; - map->ctrls= wire.ctrls; - } - return nRead; -} - -static XkbKeyTypePtr -FindTypeForKey(XkbDescPtr xkb,Atom name,unsigned width,KeySym *syms) -{ - if ((!xkb)||(!xkb->map)) - return NULL; - if (name!=None) { - register unsigned i; - for (i=0;i<xkb->map->num_types;i++) { - if (xkb->map->types[i].name==name) { - if (xkb->map->types[i].num_levels!=width) - DebugF("Group width mismatch between key and type\n"); - return &xkb->map->types[i]; - } - } - } - if ((width<2)||((syms!=NULL)&&(syms[1]==NoSymbol))) - return &xkb->map->types[XkbOneLevelIndex]; - if (syms!=NULL) { - if (XkbKSIsLower(syms[0])&&XkbKSIsUpper(syms[1])) - return &xkb->map->types[XkbAlphabeticIndex]; - else if (XkbKSIsKeypad(syms[0])||XkbKSIsKeypad(syms[1])) - return &xkb->map->types[XkbKeypadIndex]; - } - return &xkb->map->types[XkbTwoLevelIndex]; -} - -static int -ReadXkmSymbols(FILE *file,XkbDescPtr xkb) -{ -register int i,g,s,totalVModMaps; -xkmKeySymMapDesc wireMap; -char buf[100]; -unsigned minKC,maxKC,groupNames,tmp; -int nRead=0; - - if ((tmp=XkmGetCountedString(file,buf,100))<1) - return -1; - nRead+= tmp; - minKC= XkmGetCARD8(file,&nRead); - maxKC= XkmGetCARD8(file,&nRead); - groupNames= XkmGetCARD8(file,&nRead); - totalVModMaps= XkmGetCARD8(file,&nRead); - if (XkbAllocNames(xkb, - XkbSymbolsNameMask|XkbPhysSymbolsNameMask|XkbGroupNamesMask, - 0,0)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"physical names",0); - return -1; - } - if ((buf[0]!='\0')&&(xkb->names)) { - Atom name; - name= XkbInternAtom(buf,0); - xkb->names->symbols= name; - xkb->names->phys_symbols= name; - } - for (i=0,g=1;i<XkbNumKbdGroups;i++,g<<=1) { - if (groupNames&g) { - if ((tmp=XkmGetCountedString(file,buf,100))<1) - return -1; - nRead+= tmp; - if ((buf[0]!='\0')&&(xkb->names)) { - Atom name; - name= XkbInternAtom(buf,0); - xkb->names->groups[i]= name; - } - else xkb->names->groups[i]= None; - } - } - if (XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"server map",0); - return -1; - } - if (XkbAllocClientMap(xkb,XkbAllClientInfoMask,0)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"client map",0); - return -1; - } - if (XkbAllocControls(xkb,XkbAllControlsMask)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"controls",0); - return -1; - } - if ((xkb->map==NULL)||(xkb->server==NULL)) - return -1; - if (xkb->min_key_code<8) xkb->min_key_code= minKC; - if (xkb->max_key_code<8) xkb->max_key_code= maxKC; - if ((minKC>=8)&&(minKC<xkb->min_key_code)) - xkb->min_key_code= minKC; - if ((maxKC>=8)&&(maxKC>xkb->max_key_code)) { - _XkbLibError(_XkbErrBadValue,"keys in symbol map",maxKC); - return -1; - } - for (i=minKC;i<=(int)maxKC;i++) { - Atom typeName[XkbNumKbdGroups]; - XkbKeyTypePtr type[XkbNumKbdGroups]; - if ((tmp=fread(&wireMap,SIZEOF(xkmKeySymMapDesc),1,file))<1) { - _XkbLibError(_XkbErrBadLength,"ReadXkmSymbols",0); - return -1; - } - nRead+= tmp*SIZEOF(xkmKeySymMapDesc); - bzero((char *)typeName,XkbNumKbdGroups*sizeof(Atom)); - bzero((char *)type,XkbNumKbdGroups*sizeof(XkbKeyTypePtr)); - if (wireMap.flags&XkmKeyHasTypes) { - register int g; - for (g=0;g<XkbNumKbdGroups;g++) { - if ((wireMap.flags&(1<<g))&& - ((tmp=XkmGetCountedString(file,buf,100))>0)) { - typeName[g]= XkbInternAtom(buf,1); - nRead+= tmp; - } - type[g]=FindTypeForKey(xkb,typeName[g],wireMap.width,NULL); - if (type[g]==NULL) { - _XkbLibError(_XkbErrMissingTypes,"ReadXkmSymbols",0); - return -1; - } - if (typeName[g]==type[g]->name) - xkb->server->explicit[i]|= (1<<g); - } - } - if (wireMap.flags&XkmRepeatingKey) { - xkb->ctrls->per_key_repeat[i/8]|= (1<<(i%8)); - xkb->server->explicit[i]|= XkbExplicitAutoRepeatMask; - } - else if (wireMap.flags&XkmNonRepeatingKey) { - xkb->ctrls->per_key_repeat[i/8]&= ~(1<<(i%8)); - xkb->server->explicit[i]|= XkbExplicitAutoRepeatMask; - } - xkb->map->modmap[i]= wireMap.modifier_map; - if (XkbNumGroups(wireMap.num_groups)>0) { - KeySym *sym; - int nSyms; - - if (XkbNumGroups(wireMap.num_groups)>xkb->ctrls->num_groups) - xkb->ctrls->num_groups= wireMap.num_groups; - nSyms= XkbNumGroups(wireMap.num_groups)*wireMap.width; - sym= XkbResizeKeySyms(xkb,i,nSyms); - if (!sym) - return -1; - for (s=0;s<nSyms;s++) { - *sym++= XkmGetCARD32(file,&nRead); - } - if (wireMap.flags&XkmKeyHasActions) { - XkbAction * act; - act= XkbResizeKeyActions(xkb,i,nSyms); - for (s=0;s<nSyms;s++,act++) { - tmp=fread(act,SIZEOF(xkmActionDesc),1,file); - nRead+= tmp*SIZEOF(xkmActionDesc); - } - xkb->server->explicit[i]|= XkbExplicitInterpretMask; - } - } - for (g=0;g<XkbNumGroups(wireMap.num_groups);g++) { - if (((xkb->server->explicit[i]&(1<<g))==0)||(type[g]==NULL)) { - KeySym *tmpSyms; - tmpSyms= XkbKeySymsPtr(xkb,i)+(wireMap.width*g); - type[g]= FindTypeForKey(xkb,None,wireMap.width,tmpSyms); - } - xkb->map->key_sym_map[i].kt_index[g]= type[g]-(&xkb->map->types[0]); - } - xkb->map->key_sym_map[i].group_info= wireMap.num_groups; - xkb->map->key_sym_map[i].width= wireMap.width; - if (wireMap.flags&XkmKeyHasBehavior) { - xkmBehaviorDesc b; - tmp= fread(&b,SIZEOF(xkmBehaviorDesc),1,file); - nRead+= tmp*SIZEOF(xkmBehaviorDesc); - xkb->server->behaviors[i].type= b.type; - xkb->server->behaviors[i].data= b.data; - xkb->server->explicit[i]|= XkbExplicitBehaviorMask; - } - } - if (totalVModMaps>0) { - xkmVModMapDesc v; - for (i=0;i<totalVModMaps;i++) { - tmp= fread(&v,SIZEOF(xkmVModMapDesc),1,file); - nRead+= tmp*SIZEOF(xkmVModMapDesc); - if (tmp>0) - xkb->server->vmodmap[v.key]= v.vmods; - } - } - return nRead; -} - -static int -ReadXkmGeomDoodad( - FILE * file, - XkbGeometryPtr geom, - XkbSectionPtr section) -{ -XkbDoodadPtr doodad; -xkmDoodadDesc doodadWire; -char buf[100]; -unsigned tmp; -int nRead=0; - - nRead+= XkmGetCountedString(file,buf,100); - tmp= fread(&doodadWire,SIZEOF(xkmDoodadDesc),1,file); - nRead+= SIZEOF(xkmDoodadDesc)*tmp; - doodad= XkbAddGeomDoodad(geom,section,XkbInternAtom(buf,FALSE)); - if (!doodad) - return nRead; - doodad->any.type= doodadWire.any.type; - doodad->any.priority= doodadWire.any.priority; - doodad->any.top= doodadWire.any.top; - doodad->any.left= doodadWire.any.left; - switch (doodadWire.any.type) { - case XkbOutlineDoodad: - case XkbSolidDoodad: - doodad->shape.angle= doodadWire.shape.angle; - doodad->shape.color_ndx= doodadWire.shape.color_ndx; - doodad->shape.shape_ndx= doodadWire.shape.shape_ndx; - break; - case XkbTextDoodad: - doodad->text.angle= doodadWire.text.angle; - doodad->text.width= doodadWire.text.width; - doodad->text.height= doodadWire.text.height; - doodad->text.color_ndx= doodadWire.text.color_ndx; - nRead+= XkmGetCountedString(file,buf,100); - doodad->text.text= _XkbDupString(buf); - nRead+= XkmGetCountedString(file,buf,100); - doodad->text.font= _XkbDupString(buf); - break; - case XkbIndicatorDoodad: - doodad->indicator.shape_ndx= doodadWire.indicator.shape_ndx; - doodad->indicator.on_color_ndx= doodadWire.indicator.on_color_ndx; - doodad->indicator.off_color_ndx= doodadWire.indicator.off_color_ndx; - break; - case XkbLogoDoodad: - doodad->logo.angle= doodadWire.logo.angle; - doodad->logo.color_ndx= doodadWire.logo.color_ndx; - doodad->logo.shape_ndx= doodadWire.logo.shape_ndx; - nRead+= XkmGetCountedString(file,buf,100); - doodad->logo.logo_name= _XkbDupString(buf); - break; - default: - /* report error? */ - return nRead; - } - return nRead; -} - -static int -ReadXkmGeomOverlay( FILE * file, - XkbGeometryPtr geom, - XkbSectionPtr section) -{ -char buf[100]; -unsigned tmp; -int nRead=0; -XkbOverlayPtr ol; -XkbOverlayRowPtr row; -xkmOverlayDesc olWire; -xkmOverlayRowDesc rowWire; -register int r; - - nRead+= XkmGetCountedString(file,buf,100); - tmp= fread(&olWire,SIZEOF(xkmOverlayDesc),1,file); - nRead+= tmp*SIZEOF(xkmOverlayDesc); - ol= XkbAddGeomOverlay(section,XkbInternAtom(buf,FALSE), - olWire.num_rows); - if (!ol) - return nRead; - for (r=0;r<olWire.num_rows;r++) { - int k; - xkmOverlayKeyDesc keyWire; - tmp= fread(&rowWire,SIZEOF(xkmOverlayRowDesc),1,file); - nRead+= tmp*SIZEOF(xkmOverlayRowDesc); - row= XkbAddGeomOverlayRow(ol,rowWire.row_under,rowWire.num_keys); - if (!row) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomOverlay",0); - return nRead; - } - for (k=0;k<rowWire.num_keys;k++) { - tmp= fread(&keyWire,SIZEOF(xkmOverlayKeyDesc),1,file); - nRead+= tmp*SIZEOF(xkmOverlayKeyDesc); - memcpy(row->keys[k].over.name,keyWire.over,XkbKeyNameLength); - memcpy(row->keys[k].under.name,keyWire.under,XkbKeyNameLength); - } - row->num_keys= rowWire.num_keys; - } - return nRead; -} - -static int -ReadXkmGeomSection( FILE * file, - XkbGeometryPtr geom) -{ -register int i; -XkbSectionPtr section; -xkmSectionDesc sectionWire; -unsigned tmp; -int nRead= 0; -char buf[100]; -Atom nameAtom; - - nRead+= XkmGetCountedString(file,buf,100); - nameAtom= XkbInternAtom(buf,FALSE); - tmp= fread(§ionWire,SIZEOF(xkmSectionDesc),1,file); - nRead+= SIZEOF(xkmSectionDesc)*tmp; - section= XkbAddGeomSection(geom,nameAtom,sectionWire.num_rows, - sectionWire.num_doodads, - sectionWire.num_overlays); - if (!section) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomSection",0); - return nRead; - } - section->top= sectionWire.top; - section->left= sectionWire.left; - section->width= sectionWire.width; - section->height= sectionWire.height; - section->angle= sectionWire.angle; - section->priority= sectionWire.priority; - if (sectionWire.num_rows>0) { - register int k; - XkbRowPtr row; - xkmRowDesc rowWire; - XkbKeyPtr key; - xkmKeyDesc keyWire; - - for (i=0;i<sectionWire.num_rows;i++) { - tmp= fread(&rowWire,SIZEOF(xkmRowDesc),1,file); - nRead+= SIZEOF(xkmRowDesc)*tmp; - row= XkbAddGeomRow(section,rowWire.num_keys); - if (!row) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmKeycodes",0); - return nRead; - } - row->top= rowWire.top; - row->left= rowWire.left; - row->vertical= rowWire.vertical; - for (k=0;k<rowWire.num_keys;k++) { - tmp= fread(&keyWire,SIZEOF(xkmKeyDesc),1,file); - nRead+= SIZEOF(xkmKeyDesc)*tmp; - key= XkbAddGeomKey(row); - if (!key) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomSection",0); - return nRead; - } - memcpy(key->name.name,keyWire.name,XkbKeyNameLength); - key->gap= keyWire.gap; - key->shape_ndx= keyWire.shape_ndx; - key->color_ndx= keyWire.color_ndx; - } - } - } - if (sectionWire.num_doodads>0) { - for (i=0;i<sectionWire.num_doodads;i++) { - tmp= ReadXkmGeomDoodad(file,geom,section); - nRead+= tmp; - if (tmp<1) - return nRead; - } - } - if (sectionWire.num_overlays>0) { - for (i=0;i<sectionWire.num_overlays;i++) { - tmp= ReadXkmGeomOverlay(file,geom,section); - nRead+= tmp; - if (tmp<1) - return nRead; - } - } - return nRead; -} - -static int -ReadXkmGeometry(FILE *file,XkbDescPtr xkb) -{ -register int i; -char buf[100]; -unsigned tmp; -int nRead= 0; -xkmGeometryDesc wireGeom; -XkbGeometryPtr geom; -XkbGeometrySizesRec sizes; - - nRead+= XkmGetCountedString(file,buf,100); - tmp= fread(&wireGeom,SIZEOF(xkmGeometryDesc),1,file); - nRead+= tmp*SIZEOF(xkmGeometryDesc); - sizes.which= XkbGeomAllMask; - sizes.num_properties= wireGeom.num_properties; - sizes.num_colors= wireGeom.num_colors; - sizes.num_shapes= wireGeom.num_shapes; - sizes.num_sections= wireGeom.num_sections; - sizes.num_doodads= wireGeom.num_doodads; - sizes.num_key_aliases= wireGeom.num_key_aliases; - if (XkbAllocGeometry(xkb,&sizes)!=Success) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); - return nRead; - } - geom= xkb->geom; - geom->name= XkbInternAtom(buf,FALSE); - geom->width_mm= wireGeom.width_mm; - geom->height_mm= wireGeom.height_mm; - nRead+= XkmGetCountedString(file,buf,100); - geom->label_font= _XkbDupString(buf); - if (wireGeom.num_properties>0) { - char val[1024]; - for (i=0;i<wireGeom.num_properties;i++) { - nRead+= XkmGetCountedString(file,buf,100); - nRead+= XkmGetCountedString(file,val,1024); - if (XkbAddGeomProperty(geom,buf,val)==NULL) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); - return nRead; - } - } - } - if (wireGeom.num_colors>0) { - for (i=0;i<wireGeom.num_colors;i++) { - nRead+= XkmGetCountedString(file,buf,100); - if (XkbAddGeomColor(geom,buf,i)==NULL) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); - return nRead; - } - } - } - geom->base_color= &geom->colors[wireGeom.base_color_ndx]; - geom->label_color= &geom->colors[wireGeom.label_color_ndx]; - if (wireGeom.num_shapes>0) { - XkbShapePtr shape; - xkmShapeDesc shapeWire; - Atom nameAtom; - for (i=0;i<wireGeom.num_shapes;i++) { - register int n; - XkbOutlinePtr ol; - xkmOutlineDesc olWire; - nRead+= XkmGetCountedString(file,buf,100); - nameAtom= XkbInternAtom(buf,FALSE); - tmp= fread(&shapeWire,SIZEOF(xkmShapeDesc),1,file); - nRead+= tmp*SIZEOF(xkmShapeDesc); - shape= XkbAddGeomShape(geom,nameAtom,shapeWire.num_outlines); - if (!shape) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); - return nRead; - } - for (n=0;n<shapeWire.num_outlines;n++) { - register int p; - xkmPointDesc ptWire; - tmp= fread(&olWire,SIZEOF(xkmOutlineDesc),1,file); - nRead+= tmp*SIZEOF(xkmOutlineDesc); - ol= XkbAddGeomOutline(shape,olWire.num_points); - if (!ol) { - _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); - return nRead; - } - ol->num_points= olWire.num_points; - ol->corner_radius= olWire.corner_radius; - for (p=0;p<olWire.num_points;p++) { - tmp= fread(&ptWire,SIZEOF(xkmPointDesc),1,file); - nRead+= tmp*SIZEOF(xkmPointDesc); - ol->points[p].x= ptWire.x; - ol->points[p].y= ptWire.y; - if (ptWire.x<shape->bounds.x1) shape->bounds.x1= ptWire.x; - if (ptWire.x>shape->bounds.x2) shape->bounds.x2= ptWire.x; - if (ptWire.y<shape->bounds.y1) shape->bounds.y1= ptWire.y; - if (ptWire.y>shape->bounds.y2) shape->bounds.y2= ptWire.y; - } - } - if (shapeWire.primary_ndx!=XkbNoShape) - shape->primary= &shape->outlines[shapeWire.primary_ndx]; - if (shapeWire.approx_ndx!=XkbNoShape) - shape->approx= &shape->outlines[shapeWire.approx_ndx]; - } - } - if (wireGeom.num_sections>0) { - for (i=0;i<wireGeom.num_sections;i++) { - tmp= ReadXkmGeomSection(file,geom); - nRead+= tmp; - if (tmp==0) - return nRead; - } - } - if (wireGeom.num_doodads>0) { - for (i=0;i<wireGeom.num_doodads;i++) { - tmp= ReadXkmGeomDoodad(file,geom,NULL); - nRead+= tmp; - if (tmp==0) - return nRead; - } - } - if ((wireGeom.num_key_aliases>0)&&(geom->key_aliases)) { - int sz= XkbKeyNameLength*2; - int num= wireGeom.num_key_aliases; - if (fread(geom->key_aliases,sz,num,file)!=num) { - _XkbLibError(_XkbErrBadLength,"ReadXkmGeometry",0); - return -1; - } - nRead+= (num*sz); - geom->num_key_aliases= num; - } - return nRead; -} - -Bool -XkmProbe(FILE *file) -{ -unsigned hdr,tmp; -int nRead=0; - - hdr= (('x'<<24)|('k'<<16)|('m'<<8)|XkmFileVersion); - tmp= XkmGetCARD32(file,&nRead); - if (tmp!=hdr) { - if ((tmp&(~0xff))==(hdr&(~0xff))) { - _XkbLibError(_XkbErrBadFileVersion,"XkmProbe",tmp&0xff); - } - return 0; - } - return 1; -} - -static Bool -XkmReadTOC(FILE *file,xkmFileInfo* file_info,int max_toc,xkmSectionInfo *toc) -{ -unsigned hdr,tmp; -int nRead=0; -unsigned i,size_toc; - - hdr= (('x'<<24)|('k'<<16)|('m'<<8)|XkmFileVersion); - tmp= XkmGetCARD32(file,&nRead); - if (tmp!=hdr) { - if ((tmp&(~0xff))==(hdr&(~0xff))) { - _XkbLibError(_XkbErrBadFileVersion,"XkmReadTOC",tmp&0xff); - } - else { - _XkbLibError(_XkbErrBadFileType,"XkmReadTOC",tmp); - } - return 0; - } - fread(file_info,SIZEOF(xkmFileInfo),1,file); - size_toc= file_info->num_toc; - if (size_toc>max_toc) { - DebugF("Warning! Too many TOC entries; last %d ignored\n", - size_toc-max_toc); - size_toc= max_toc; - } - for (i=0;i<size_toc;i++) { - fread(&toc[i],SIZEOF(xkmSectionInfo),1,file); - } - return 1; -} - -/***====================================================================***/ - -#define MAX_TOC 16 -unsigned -XkmReadFile(FILE *file,unsigned need,unsigned want,XkbDescPtr *xkb) -{ -register unsigned i; -xkmSectionInfo toc[MAX_TOC],tmpTOC; -xkmFileInfo fileInfo; -unsigned tmp,nRead=0; -unsigned which= need|want; - - if (!XkmReadTOC(file,&fileInfo,MAX_TOC,toc)) - return which; - if ((fileInfo.present&need)!=need) { - _XkbLibError(_XkbErrIllegalContents,"XkmReadFile", - need&(~fileInfo.present)); - return which; - } - if (*xkb==NULL) - *xkb= XkbAllocKeyboard(); - for (i=0;i<fileInfo.num_toc;i++) { - fseek(file,toc[i].offset,SEEK_SET); - tmp= fread(&tmpTOC,SIZEOF(xkmSectionInfo),1,file); - nRead= tmp*SIZEOF(xkmSectionInfo); - if ((tmpTOC.type!=toc[i].type)||(tmpTOC.format!=toc[i].format)|| - (tmpTOC.size!=toc[i].size)||(tmpTOC.offset!=toc[i].offset)) { - return which; - } - if ((which&(1<<tmpTOC.type))==0) { - continue; - } - switch (tmpTOC.type) { - case XkmVirtualModsIndex: - tmp= ReadXkmVirtualMods(file,*xkb,NULL); - break; - case XkmTypesIndex: - tmp= ReadXkmKeyTypes(file,*xkb,NULL); - break; - case XkmCompatMapIndex: - tmp= ReadXkmCompatMap(file,*xkb,NULL); - break; - case XkmKeyNamesIndex: - tmp= ReadXkmKeycodes(file,*xkb,NULL); - break; - case XkmIndicatorsIndex: - tmp= ReadXkmIndicators(file,*xkb,NULL); - break; - case XkmSymbolsIndex: - tmp= ReadXkmSymbols(file,*xkb); - break; - case XkmGeometryIndex: - tmp= ReadXkmGeometry(file,*xkb); - break; - default: - _XkbLibError(_XkbErrBadImplementation, - XkbConfigText(tmpTOC.type,XkbMessage),0); - tmp= 0; - break; - } - if (tmp>0) { - nRead+= tmp; - which&= ~(1<<toc[i].type); - (*xkb)->defined|= (1<<toc[i].type); - } - if (nRead!=tmpTOC.size) { - _XkbLibError(_XkbErrBadLength,XkbConfigText(tmpTOC.type,XkbMessage), - nRead-tmpTOC.size); - } - } - return which; -} +/************************************************************ + Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc. + + 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 Silicon Graphics not be + used in advertising or publicity pertaining to distribution + of the software without specific prior written permission. + Silicon Graphics makes no representation about the suitability + of this software for any purpose. It is provided "as is" + without any express or implied warranty. + + SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + GRAPHICS 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 <dix-config.h> +#endif + +#include <stdio.h> + +#include <X11/Xos.h> +#include <X11/Xfuncs.h> + +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/keysym.h> +#include <X11/extensions/XKMformat.h> +#include "misc.h" +#include "inputstr.h" +#include "xkbstr.h" +#include "xkbsrv.h" +#include "xkbgeom.h" + +Atom +XkbInternAtom(char *str,Bool only_if_exists) +{ + if (str==NULL) + return None; + return MakeAtom(str,strlen(str),!only_if_exists); +} + +char * +_XkbDupString(const char *str) +{ +char *new; + + if (str==NULL) + return NULL; + new= calloc(strlen(str)+1,sizeof(char)); + if (new) + strcpy(new,str); + return new; +} + +/***====================================================================***/ + +static void * +XkmInsureSize(void *oldPtr,int oldCount,int *newCountRtrn,int elemSize) +{ +int newCount= *newCountRtrn; + + if (oldPtr==NULL) { + if (newCount==0) + return NULL; + oldPtr= calloc(newCount,elemSize); + } + else if (oldCount<newCount) { + oldPtr= realloc(oldPtr,newCount*elemSize); + if (oldPtr!=NULL) { + char *tmp= (char *)oldPtr; + bzero(&tmp[oldCount*elemSize],(newCount-oldCount)*elemSize); + } + } + else if (newCount<oldCount) { + *newCountRtrn= oldCount; + } + return oldPtr; +} + +#define XkmInsureTypedSize(p,o,n,t) ((p)=((t *)XkmInsureSize((char *)(p),(o),(n),sizeof(t)))) + +static CARD8 +XkmGetCARD8(FILE *file,int *pNRead) +{ +int tmp; + tmp= getc(file); + if (pNRead&&(tmp!=EOF)) + (*pNRead)+= 1; + return tmp; +} + +static CARD16 +XkmGetCARD16(FILE *file,int *pNRead) +{ +CARD16 val; + + if ((fread(&val,2,1,file)==1)&&(pNRead)) + (*pNRead)+= 2; + return val; +} + +static CARD32 +XkmGetCARD32(FILE *file,int *pNRead) +{ +CARD32 val; + + if ((fread(&val,4,1,file)==1)&&(pNRead)) + (*pNRead)+= 4; + return val; +} + +static int +XkmSkipPadding(FILE *file,unsigned pad) +{ +register int i,nRead=0; + + for (i=0;i<pad;i++) { + if (getc(file)!=EOF) + nRead++; + } + return nRead; +} + +static int +XkmGetCountedString(FILE *file,char *str,int max_len) +{ +int count,nRead=0; + + count= XkmGetCARD16(file,&nRead); + if (count>0) { + int tmp; + if (count>max_len) { + tmp= fread(str,1,max_len,file); + while (tmp<count) { + if ((getc(file))!=EOF) + tmp++; + else break; + } + } + else { + tmp= fread(str,1,count,file); + } + nRead+= tmp; + } + if (count>=max_len) str[max_len-1]= '\0'; + else str[count]= '\0'; + count= XkbPaddedSize(nRead)-nRead; + if (count>0) + nRead+= XkmSkipPadding(file,count); + return nRead; +} + +/***====================================================================***/ + +static int +ReadXkmVirtualMods(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) +{ +register unsigned int i,bit; +unsigned int bound,named,tmp; +int nRead=0; + + if (XkbAllocServerMap(xkb,XkbVirtualModsMask,0)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmVirtualMods",0); + return -1; + } + bound= XkmGetCARD16(file,&nRead); + named= XkmGetCARD16(file,&nRead); + for (i=tmp=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + if (bound&bit) { + xkb->server->vmods[i]= XkmGetCARD8(file,&nRead); + if (changes) + changes->map.vmods|= bit; + tmp++; + } + } + if ((i= XkbPaddedSize(tmp)-tmp)>0) + nRead+= XkmSkipPadding(file,i); + if (XkbAllocNames(xkb,XkbVirtualModNamesMask,0,0)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmVirtualMods",0); + return -1; + } + for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) { + char name[100]; + if (named&bit) { + if (nRead+=XkmGetCountedString(file,name,100)) { + xkb->names->vmods[i]= XkbInternAtom(name,FALSE); + if (changes) + changes->names.changed_vmods|= bit; + } + } + } + return nRead; +} + +/***====================================================================***/ + +static int +ReadXkmKeycodes(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) +{ +register int i; +unsigned minKC,maxKC,nAl; +int nRead=0; +char name[100]; +XkbKeyNamePtr pN; + + name[0]= '\0'; + nRead+= XkmGetCountedString(file,name,100); + minKC= XkmGetCARD8(file,&nRead); + maxKC= XkmGetCARD8(file,&nRead); + if (xkb->min_key_code==0) { + xkb->min_key_code= minKC; + xkb->max_key_code= maxKC; + } + else { + if (minKC<xkb->min_key_code) + xkb->min_key_code= minKC; + if (maxKC>xkb->max_key_code) { + _XkbLibError(_XkbErrBadValue,"ReadXkmKeycodes",maxKC); + return -1; + } + } + nAl= XkmGetCARD8(file,&nRead); + nRead+= XkmSkipPadding(file,1); + +#define WANTED (XkbKeycodesNameMask|XkbKeyNamesMask|XkbKeyAliasesMask) + if (XkbAllocNames(xkb,WANTED,0,nAl)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmKeycodes",0); + return -1; + } + if (name[0]!='\0') { + xkb->names->keycodes= XkbInternAtom(name,FALSE); + } + + for (pN=&xkb->names->keys[minKC],i=minKC;i<=(int)maxKC;i++,pN++) { + if (fread(pN,1,XkbKeyNameLength,file)!=XkbKeyNameLength) { + _XkbLibError(_XkbErrBadLength,"ReadXkmKeycodes",0); + return -1; + } + nRead+= XkbKeyNameLength; + } + if (nAl>0) { + XkbKeyAliasPtr pAl; + for (pAl= xkb->names->key_aliases,i=0;i<nAl;i++,pAl++) { + int tmp; + tmp= fread(pAl,1,2*XkbKeyNameLength,file); + if (tmp!=2*XkbKeyNameLength) { + _XkbLibError(_XkbErrBadLength,"ReadXkmKeycodes",0); + return -1; + } + nRead+= 2*XkbKeyNameLength; + } + if (changes) + changes->names.changed|= XkbKeyAliasesMask; + } + if (changes) + changes->names.changed|= XkbKeyNamesMask; + return nRead; +} + +/***====================================================================***/ + +static int +ReadXkmKeyTypes(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) +{ +register unsigned i,n; +unsigned num_types; +int nRead=0; +int tmp; +XkbKeyTypePtr type; +xkmKeyTypeDesc wire; +XkbKTMapEntryPtr entry; +xkmKTMapEntryDesc wire_entry; +char buf[100]; + + if ((tmp= XkmGetCountedString(file,buf,100))<1) { + _XkbLibError(_XkbErrBadLength,"ReadXkmKeyTypes",0); + return -1; + } + nRead+= tmp; + if (buf[0]!='\0') { + if (XkbAllocNames(xkb,XkbTypesNameMask,0,0)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmKeyTypes",0); + return -1; + } + xkb->names->types= XkbInternAtom(buf,FALSE); + } + num_types= XkmGetCARD16(file,&nRead); + nRead+= XkmSkipPadding(file,2); + if (num_types<1) + return nRead; + if (XkbAllocClientMap(xkb,XkbKeyTypesMask,num_types)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmKeyTypes",0); + return nRead; + } + xkb->map->num_types= num_types; + if (num_types<XkbNumRequiredTypes) { + _XkbLibError(_XkbErrMissingReqTypes,"ReadXkmKeyTypes",0); + return -1; + } + type= xkb->map->types; + for (i=0;i<num_types;i++,type++) { + if ((int)fread(&wire,SIZEOF(xkmKeyTypeDesc),1,file)<1) { + _XkbLibError(_XkbErrBadLength,"ReadXkmKeyTypes",0); + return -1; + } + nRead+= SIZEOF(xkmKeyTypeDesc); + if (((i==XkbOneLevelIndex)&&(wire.numLevels!=1))|| + (((i==XkbTwoLevelIndex)||(i==XkbAlphabeticIndex)|| + ((i)==XkbKeypadIndex))&&(wire.numLevels!=2))) { + _XkbLibError(_XkbErrBadTypeWidth,"ReadXkmKeyTypes",i); + return -1; + } + tmp= wire.nMapEntries; + XkmInsureTypedSize(type->map,type->map_count,&tmp,XkbKTMapEntryRec); + if ((wire.nMapEntries>0)&&(type->map==NULL)) { + _XkbLibError(_XkbErrBadValue,"ReadXkmKeyTypes",wire.nMapEntries); + return -1; + } + for (n=0,entry= type->map;n<wire.nMapEntries;n++,entry++) { + if (fread(&wire_entry,SIZEOF(xkmKTMapEntryDesc),1,file)<(int)1) { + _XkbLibError(_XkbErrBadLength,"ReadXkmKeyTypes",0); + return -1; + } + nRead+= SIZEOF(xkmKTMapEntryDesc); + entry->active= (wire_entry.virtualMods==0); + entry->level= wire_entry.level; + entry->mods.mask= wire_entry.realMods; + entry->mods.real_mods= wire_entry.realMods; + entry->mods.vmods= wire_entry.virtualMods; + } + nRead+= XkmGetCountedString(file,buf,100); + if (((i==XkbOneLevelIndex)&&(strcmp(buf,"ONE_LEVEL")!=0))|| + ((i==XkbTwoLevelIndex)&&(strcmp(buf,"TWO_LEVEL")!=0))|| + ((i==XkbAlphabeticIndex)&&(strcmp(buf,"ALPHABETIC")!=0))|| + ((i==XkbKeypadIndex)&&(strcmp(buf,"KEYPAD")!=0))) { + _XkbLibError(_XkbErrBadTypeName,"ReadXkmKeyTypes",0); + return -1; + } + if (buf[0]!='\0') { + type->name= XkbInternAtom(buf,FALSE); + } + else type->name= None; + + if (wire.preserve) { + xkmModsDesc p_entry; + XkbModsPtr pre; + XkmInsureTypedSize(type->preserve,type->map_count,&tmp, + XkbModsRec); + if (type->preserve==NULL) { + _XkbLibError(_XkbErrBadMatch,"ReadXkmKeycodes",0); + return -1; + } + for (n=0,pre=type->preserve;n<wire.nMapEntries;n++,pre++) { + if (fread(&p_entry,SIZEOF(xkmModsDesc),1,file)<1) { + _XkbLibError(_XkbErrBadLength,"ReadXkmKeycodes",0); + return -1; + } + nRead+= SIZEOF(xkmModsDesc); + pre->mask= p_entry.realMods; + pre->real_mods= p_entry.realMods; + pre->vmods= p_entry.virtualMods; + } + } + if (wire.nLevelNames>0) { + int width= wire.numLevels; + if (wire.nLevelNames>(unsigned)width) { + _XkbLibError(_XkbErrBadMatch,"ReadXkmKeycodes",0); + return -1; + } + XkmInsureTypedSize(type->level_names,type->num_levels,&width,Atom); + if (type->level_names!=NULL) { + for (n=0;n<wire.nLevelNames;n++) { + if ((tmp=XkmGetCountedString(file,buf,100))<1) + return -1; + nRead+= tmp; + if (strlen(buf)==0) + type->level_names[n]= None; + else type->level_names[n]= XkbInternAtom(buf,0); + } + } + } + type->mods.mask= wire.realMods; + type->mods.real_mods= wire.realMods; + type->mods.vmods= wire.virtualMods; + type->num_levels= wire.numLevels; + type->map_count= wire.nMapEntries; + } + if (changes) { + changes->map.changed|= XkbKeyTypesMask; + changes->map.first_type= 0; + changes->map.num_types= xkb->map->num_types; + } + return nRead; +} + +/***====================================================================***/ + +static int +ReadXkmCompatMap(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) +{ +register int i; +unsigned num_si,groups; +char name[100]; +XkbSymInterpretPtr interp; +xkmSymInterpretDesc wire; +unsigned tmp; +int nRead=0; +XkbCompatMapPtr compat; +XkbAction *act; + + if ((tmp= XkmGetCountedString(file,name,100))<1) { + _XkbLibError(_XkbErrBadLength,"ReadXkmCompatMap",0); + return -1; + } + nRead+= tmp; + if (name[0]!='\0') { + if (XkbAllocNames(xkb,XkbCompatNameMask,0,0)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmCompatMap",0); + return -1; + } + xkb->names->compat= XkbInternAtom(name,FALSE); + } + num_si= XkmGetCARD16(file,&nRead); + groups= XkmGetCARD8(file,&nRead); + nRead+= XkmSkipPadding(file,1); + if (XkbAllocCompatMap(xkb,XkbAllCompatMask,num_si)!=Success) + return -1; + compat= xkb->compat; + compat->num_si= num_si; + interp= compat->sym_interpret; + for (i=0;i<num_si;i++,interp++) { + tmp= fread(&wire,SIZEOF(xkmSymInterpretDesc),1,file); + nRead+= tmp*SIZEOF(xkmSymInterpretDesc); + interp->sym= wire.sym; + interp->mods= wire.mods; + interp->match= wire.match; + interp->virtual_mod= wire.virtualMod; + interp->flags= wire.flags; + interp->act.type= wire.actionType; + act = (XkbAction *) &interp->act; + + switch (interp->act.type) { + case XkbSA_SetMods: + case XkbSA_LatchMods: + case XkbSA_LockMods: + act->mods.flags = wire.actionData[0]; + act->mods.mask = wire.actionData[1]; + act->mods.real_mods = wire.actionData[2]; + act->mods.vmods1 = wire.actionData[3]; + act->mods.vmods2 = wire.actionData[4]; + break; + case XkbSA_SetGroup: + case XkbSA_LatchGroup: + case XkbSA_LockGroup: + act->group.flags = wire.actionData[0]; + act->group.group_XXX = wire.actionData[1]; + break; + case XkbSA_MovePtr: + act->ptr.flags = wire.actionData[0]; + act->ptr.high_XXX = wire.actionData[1]; + act->ptr.low_XXX = wire.actionData[2]; + act->ptr.high_YYY = wire.actionData[3]; + act->ptr.low_YYY = wire.actionData[4]; + break; + case XkbSA_PtrBtn: + case XkbSA_LockPtrBtn: + act->btn.flags = wire.actionData[0]; + act->btn.count = wire.actionData[1]; + act->btn.button = wire.actionData[2]; + break; + case XkbSA_DeviceBtn: + case XkbSA_LockDeviceBtn: + act->devbtn.flags = wire.actionData[0]; + act->devbtn.count = wire.actionData[1]; + act->devbtn.button = wire.actionData[2]; + act->devbtn.device = wire.actionData[3]; + break; + case XkbSA_SetPtrDflt: + act->dflt.flags = wire.actionData[0]; + act->dflt.affect = wire.actionData[1]; + act->dflt.valueXXX = wire.actionData[2]; + break; + case XkbSA_ISOLock: + act->iso.flags = wire.actionData[0]; + act->iso.mask = wire.actionData[1]; + act->iso.real_mods = wire.actionData[2]; + act->iso.group_XXX = wire.actionData[3]; + act->iso.affect = wire.actionData[4]; + act->iso.vmods1 = wire.actionData[5]; + act->iso.vmods2 = wire.actionData[6]; + break; + case XkbSA_SwitchScreen: + act->screen.flags = wire.actionData[0]; + act->screen.screenXXX = wire.actionData[1]; + break; + case XkbSA_SetControls: + case XkbSA_LockControls: + act->ctrls.flags = wire.actionData[0]; + act->ctrls.ctrls3 = wire.actionData[1]; + act->ctrls.ctrls2 = wire.actionData[2]; + act->ctrls.ctrls1 = wire.actionData[3]; + act->ctrls.ctrls0 = wire.actionData[4]; + break; + case XkbSA_RedirectKey: + act->redirect.new_key = wire.actionData[0]; + act->redirect.mods_mask = wire.actionData[1]; + act->redirect.mods = wire.actionData[2]; + act->redirect.vmods_mask0 = wire.actionData[3]; + act->redirect.vmods_mask1 = wire.actionData[4]; + act->redirect.vmods0 = wire.actionData[4]; + act->redirect.vmods1 = wire.actionData[5]; + break; + case XkbSA_DeviceValuator: + act->devval.device = wire.actionData[0]; + act->devval.v1_what = wire.actionData[1]; + act->devval.v1_ndx = wire.actionData[2]; + act->devval.v1_value = wire.actionData[3]; + act->devval.v2_what = wire.actionData[4]; + act->devval.v2_ndx = wire.actionData[5]; + act->devval.v2_what = wire.actionData[6]; + break; + + case XkbSA_XFree86Private: + /* copy the kind of action */ + strncpy((char*)act->any.data, (char*)wire.actionData, + XkbAnyActionDataSize); + break ; + + case XkbSA_Terminate: + /* no args, kinda (note: untrue for xfree86). */ + break; + case XkbSA_ActionMessage: + /* unsupported. */ + break; + } + } + if ((num_si>0)&&(changes)) { + changes->compat.first_si= 0; + changes->compat.num_si= num_si; + } + if (groups) { + register unsigned bit; + for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { + xkmModsDesc md; + if (groups&bit) { + tmp= fread(&md,SIZEOF(xkmModsDesc),1,file); + nRead+= tmp*SIZEOF(xkmModsDesc); + xkb->compat->groups[i].real_mods= md.realMods; + xkb->compat->groups[i].vmods= md.virtualMods; + if (md.virtualMods != 0) { + unsigned mask; + if (XkbVirtualModsToReal(xkb,md.virtualMods,&mask)) + xkb->compat->groups[i].mask= md.realMods|mask; + } + else xkb->compat->groups[i].mask= md.realMods; + } + } + if (changes) + changes->compat.changed_groups|= groups; + } + return nRead; +} + +static int +ReadXkmIndicators(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes) +{ +register unsigned nLEDs; +xkmIndicatorMapDesc wire; +char buf[100]; +unsigned tmp; +int nRead=0; + + if ((xkb->indicators==NULL)&&(XkbAllocIndicatorMaps(xkb)!=Success)) { + _XkbLibError(_XkbErrBadAlloc,"indicator rec",0); + return -1; + } + if (XkbAllocNames(xkb,XkbIndicatorNamesMask,0,0)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"indicator names",0); + return -1; + } + nLEDs= XkmGetCARD8(file,&nRead); + nRead+= XkmSkipPadding(file,3); + xkb->indicators->phys_indicators= XkmGetCARD32(file,&nRead); + while (nLEDs-->0) { + Atom name; + XkbIndicatorMapPtr map; + + if ((tmp=XkmGetCountedString(file,buf,100))<1) { + _XkbLibError(_XkbErrBadLength,"ReadXkmIndicators",0); + return -1; + } + nRead+= tmp; + if (buf[0]!='\0') + name= XkbInternAtom(buf,FALSE); + else name= None; + if ((tmp=fread(&wire,SIZEOF(xkmIndicatorMapDesc),1,file))<1) { + _XkbLibError(_XkbErrBadLength,"ReadXkmIndicators",0); + return -1; + } + nRead+= tmp*SIZEOF(xkmIndicatorMapDesc); + if (xkb->names) { + xkb->names->indicators[wire.indicator-1]= name; + if (changes) + changes->names.changed_indicators|= (1<<(wire.indicator-1)); + } + map= &xkb->indicators->maps[wire.indicator-1]; + map->flags= wire.flags; + map->which_groups= wire.which_groups; + map->groups= wire.groups; + map->which_mods= wire.which_mods; + map->mods.mask= wire.real_mods; + map->mods.real_mods= wire.real_mods; + map->mods.vmods= wire.vmods; + map->ctrls= wire.ctrls; + } + return nRead; +} + +static XkbKeyTypePtr +FindTypeForKey(XkbDescPtr xkb,Atom name,unsigned width,KeySym *syms) +{ + if ((!xkb)||(!xkb->map)) + return NULL; + if (name!=None) { + register unsigned i; + for (i=0;i<xkb->map->num_types;i++) { + if (xkb->map->types[i].name==name) { + if (xkb->map->types[i].num_levels!=width) + DebugF("Group width mismatch between key and type\n"); + return &xkb->map->types[i]; + } + } + } + if ((width<2)||((syms!=NULL)&&(syms[1]==NoSymbol))) + return &xkb->map->types[XkbOneLevelIndex]; + if (syms!=NULL) { + if (XkbKSIsLower(syms[0])&&XkbKSIsUpper(syms[1])) + return &xkb->map->types[XkbAlphabeticIndex]; + else if (XkbKSIsKeypad(syms[0])||XkbKSIsKeypad(syms[1])) + return &xkb->map->types[XkbKeypadIndex]; + } + return &xkb->map->types[XkbTwoLevelIndex]; +} + +static int +ReadXkmSymbols(FILE *file,XkbDescPtr xkb) +{ +register int i,g,s,totalVModMaps; +xkmKeySymMapDesc wireMap; +char buf[100]; +unsigned minKC,maxKC,groupNames,tmp; +int nRead=0; + + if ((tmp=XkmGetCountedString(file,buf,100))<1) + return -1; + nRead+= tmp; + minKC= XkmGetCARD8(file,&nRead); + maxKC= XkmGetCARD8(file,&nRead); + groupNames= XkmGetCARD8(file,&nRead); + totalVModMaps= XkmGetCARD8(file,&nRead); + if (XkbAllocNames(xkb, + XkbSymbolsNameMask|XkbPhysSymbolsNameMask|XkbGroupNamesMask, + 0,0)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"physical names",0); + return -1; + } + if ((buf[0]!='\0')&&(xkb->names)) { + Atom name; + name= XkbInternAtom(buf,0); + xkb->names->symbols= name; + xkb->names->phys_symbols= name; + } + for (i=0,g=1;i<XkbNumKbdGroups;i++,g<<=1) { + if (groupNames&g) { + if ((tmp=XkmGetCountedString(file,buf,100))<1) + return -1; + nRead+= tmp; + if ((buf[0]!='\0')&&(xkb->names)) { + Atom name; + name= XkbInternAtom(buf,0); + xkb->names->groups[i]= name; + } + else xkb->names->groups[i]= None; + } + } + if (XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"server map",0); + return -1; + } + if (XkbAllocClientMap(xkb,XkbAllClientInfoMask,0)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"client map",0); + return -1; + } + if (XkbAllocControls(xkb,XkbAllControlsMask)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"controls",0); + return -1; + } + if ((xkb->map==NULL)||(xkb->server==NULL)) + return -1; + if (xkb->min_key_code<8) xkb->min_key_code= minKC; + if (xkb->max_key_code<8) xkb->max_key_code= maxKC; + if ((minKC>=8)&&(minKC<xkb->min_key_code)) + xkb->min_key_code= minKC; + if ((maxKC>=8)&&(maxKC>xkb->max_key_code)) { + _XkbLibError(_XkbErrBadValue,"keys in symbol map",maxKC); + return -1; + } + for (i=minKC;i<=(int)maxKC;i++) { + Atom typeName[XkbNumKbdGroups]; + XkbKeyTypePtr type[XkbNumKbdGroups]; + if ((tmp=fread(&wireMap,SIZEOF(xkmKeySymMapDesc),1,file))<1) { + _XkbLibError(_XkbErrBadLength,"ReadXkmSymbols",0); + return -1; + } + nRead+= tmp*SIZEOF(xkmKeySymMapDesc); + bzero((char *)typeName,XkbNumKbdGroups*sizeof(Atom)); + bzero((char *)type,XkbNumKbdGroups*sizeof(XkbKeyTypePtr)); + if (wireMap.flags&XkmKeyHasTypes) { + register int g; + for (g=0;g<XkbNumKbdGroups;g++) { + if ((wireMap.flags&(1<<g))&& + ((tmp=XkmGetCountedString(file,buf,100))>0)) { + typeName[g]= XkbInternAtom(buf,1); + nRead+= tmp; + } + type[g]=FindTypeForKey(xkb,typeName[g],wireMap.width,NULL); + if (type[g]==NULL) { + _XkbLibError(_XkbErrMissingTypes,"ReadXkmSymbols",0); + return -1; + } + if (typeName[g]==type[g]->name) + xkb->server->explicit[i]|= (1<<g); + } + } + if (wireMap.flags&XkmRepeatingKey) { + xkb->ctrls->per_key_repeat[i/8]|= (1<<(i%8)); + xkb->server->explicit[i]|= XkbExplicitAutoRepeatMask; + } + else if (wireMap.flags&XkmNonRepeatingKey) { + xkb->ctrls->per_key_repeat[i/8]&= ~(1<<(i%8)); + xkb->server->explicit[i]|= XkbExplicitAutoRepeatMask; + } + xkb->map->modmap[i]= wireMap.modifier_map; + if (XkbNumGroups(wireMap.num_groups)>0) { + KeySym *sym; + int nSyms; + + if (XkbNumGroups(wireMap.num_groups)>xkb->ctrls->num_groups) + xkb->ctrls->num_groups= wireMap.num_groups; + nSyms= XkbNumGroups(wireMap.num_groups)*wireMap.width; + sym= XkbResizeKeySyms(xkb,i,nSyms); + if (!sym) + return -1; + for (s=0;s<nSyms;s++) { + *sym++= XkmGetCARD32(file,&nRead); + } + if (wireMap.flags&XkmKeyHasActions) { + XkbAction * act; + act= XkbResizeKeyActions(xkb,i,nSyms); + for (s=0;s<nSyms;s++,act++) { + tmp=fread(act,SIZEOF(xkmActionDesc),1,file); + nRead+= tmp*SIZEOF(xkmActionDesc); + } + xkb->server->explicit[i]|= XkbExplicitInterpretMask; + } + } + for (g=0;g<XkbNumGroups(wireMap.num_groups);g++) { + if (((xkb->server->explicit[i]&(1<<g))==0)||(type[g]==NULL)) { + KeySym *tmpSyms; + tmpSyms= XkbKeySymsPtr(xkb,i)+(wireMap.width*g); + type[g]= FindTypeForKey(xkb,None,wireMap.width,tmpSyms); + } + xkb->map->key_sym_map[i].kt_index[g]= type[g]-(&xkb->map->types[0]); + } + xkb->map->key_sym_map[i].group_info= wireMap.num_groups; + xkb->map->key_sym_map[i].width= wireMap.width; + if (wireMap.flags&XkmKeyHasBehavior) { + xkmBehaviorDesc b; + tmp= fread(&b,SIZEOF(xkmBehaviorDesc),1,file); + nRead+= tmp*SIZEOF(xkmBehaviorDesc); + xkb->server->behaviors[i].type= b.type; + xkb->server->behaviors[i].data= b.data; + xkb->server->explicit[i]|= XkbExplicitBehaviorMask; + } + } + if (totalVModMaps>0) { + xkmVModMapDesc v; + for (i=0;i<totalVModMaps;i++) { + tmp= fread(&v,SIZEOF(xkmVModMapDesc),1,file); + nRead+= tmp*SIZEOF(xkmVModMapDesc); + if (tmp>0) + xkb->server->vmodmap[v.key]= v.vmods; + } + } + return nRead; +} + +static int +ReadXkmGeomDoodad( + FILE * file, + XkbGeometryPtr geom, + XkbSectionPtr section) +{ +XkbDoodadPtr doodad; +xkmDoodadDesc doodadWire; +char buf[100]; +unsigned tmp; +int nRead=0; + + nRead+= XkmGetCountedString(file,buf,100); + tmp= fread(&doodadWire,SIZEOF(xkmDoodadDesc),1,file); + nRead+= SIZEOF(xkmDoodadDesc)*tmp; + doodad= XkbAddGeomDoodad(geom,section,XkbInternAtom(buf,FALSE)); + if (!doodad) + return nRead; + doodad->any.type= doodadWire.any.type; + doodad->any.priority= doodadWire.any.priority; + doodad->any.top= doodadWire.any.top; + doodad->any.left= doodadWire.any.left; + switch (doodadWire.any.type) { + case XkbOutlineDoodad: + case XkbSolidDoodad: + doodad->shape.angle= doodadWire.shape.angle; + doodad->shape.color_ndx= doodadWire.shape.color_ndx; + doodad->shape.shape_ndx= doodadWire.shape.shape_ndx; + break; + case XkbTextDoodad: + doodad->text.angle= doodadWire.text.angle; + doodad->text.width= doodadWire.text.width; + doodad->text.height= doodadWire.text.height; + doodad->text.color_ndx= doodadWire.text.color_ndx; + nRead+= XkmGetCountedString(file,buf,100); + doodad->text.text= _XkbDupString(buf); + nRead+= XkmGetCountedString(file,buf,100); + doodad->text.font= _XkbDupString(buf); + break; + case XkbIndicatorDoodad: + doodad->indicator.shape_ndx= doodadWire.indicator.shape_ndx; + doodad->indicator.on_color_ndx= doodadWire.indicator.on_color_ndx; + doodad->indicator.off_color_ndx= doodadWire.indicator.off_color_ndx; + break; + case XkbLogoDoodad: + doodad->logo.angle= doodadWire.logo.angle; + doodad->logo.color_ndx= doodadWire.logo.color_ndx; + doodad->logo.shape_ndx= doodadWire.logo.shape_ndx; + nRead+= XkmGetCountedString(file,buf,100); + doodad->logo.logo_name= _XkbDupString(buf); + break; + default: + /* report error? */ + return nRead; + } + return nRead; +} + +static int +ReadXkmGeomOverlay( FILE * file, + XkbGeometryPtr geom, + XkbSectionPtr section) +{ +char buf[100]; +unsigned tmp; +int nRead=0; +XkbOverlayPtr ol; +XkbOverlayRowPtr row; +xkmOverlayDesc olWire; +xkmOverlayRowDesc rowWire; +register int r; + + nRead+= XkmGetCountedString(file,buf,100); + tmp= fread(&olWire,SIZEOF(xkmOverlayDesc),1,file); + nRead+= tmp*SIZEOF(xkmOverlayDesc); + ol= XkbAddGeomOverlay(section,XkbInternAtom(buf,FALSE), + olWire.num_rows); + if (!ol) + return nRead; + for (r=0;r<olWire.num_rows;r++) { + int k; + xkmOverlayKeyDesc keyWire; + tmp= fread(&rowWire,SIZEOF(xkmOverlayRowDesc),1,file); + nRead+= tmp*SIZEOF(xkmOverlayRowDesc); + row= XkbAddGeomOverlayRow(ol,rowWire.row_under,rowWire.num_keys); + if (!row) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomOverlay",0); + return nRead; + } + for (k=0;k<rowWire.num_keys;k++) { + tmp= fread(&keyWire,SIZEOF(xkmOverlayKeyDesc),1,file); + nRead+= tmp*SIZEOF(xkmOverlayKeyDesc); + memcpy(row->keys[k].over.name,keyWire.over,XkbKeyNameLength); + memcpy(row->keys[k].under.name,keyWire.under,XkbKeyNameLength); + } + row->num_keys= rowWire.num_keys; + } + return nRead; +} + +static int +ReadXkmGeomSection( FILE * file, + XkbGeometryPtr geom) +{ +register int i; +XkbSectionPtr section; +xkmSectionDesc sectionWire; +unsigned tmp; +int nRead= 0; +char buf[100]; +Atom nameAtom; + + nRead+= XkmGetCountedString(file,buf,100); + nameAtom= XkbInternAtom(buf,FALSE); + tmp= fread(§ionWire,SIZEOF(xkmSectionDesc),1,file); + nRead+= SIZEOF(xkmSectionDesc)*tmp; + section= XkbAddGeomSection(geom,nameAtom,sectionWire.num_rows, + sectionWire.num_doodads, + sectionWire.num_overlays); + if (!section) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomSection",0); + return nRead; + } + section->top= sectionWire.top; + section->left= sectionWire.left; + section->width= sectionWire.width; + section->height= sectionWire.height; + section->angle= sectionWire.angle; + section->priority= sectionWire.priority; + if (sectionWire.num_rows>0) { + register int k; + XkbRowPtr row; + xkmRowDesc rowWire; + XkbKeyPtr key; + xkmKeyDesc keyWire; + + for (i=0;i<sectionWire.num_rows;i++) { + tmp= fread(&rowWire,SIZEOF(xkmRowDesc),1,file); + nRead+= SIZEOF(xkmRowDesc)*tmp; + row= XkbAddGeomRow(section,rowWire.num_keys); + if (!row) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmKeycodes",0); + return nRead; + } + row->top= rowWire.top; + row->left= rowWire.left; + row->vertical= rowWire.vertical; + for (k=0;k<rowWire.num_keys;k++) { + tmp= fread(&keyWire,SIZEOF(xkmKeyDesc),1,file); + nRead+= SIZEOF(xkmKeyDesc)*tmp; + key= XkbAddGeomKey(row); + if (!key) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomSection",0); + return nRead; + } + memcpy(key->name.name,keyWire.name,XkbKeyNameLength); + key->gap= keyWire.gap; + key->shape_ndx= keyWire.shape_ndx; + key->color_ndx= keyWire.color_ndx; + } + } + } + if (sectionWire.num_doodads>0) { + for (i=0;i<sectionWire.num_doodads;i++) { + tmp= ReadXkmGeomDoodad(file,geom,section); + nRead+= tmp; + if (tmp<1) + return nRead; + } + } + if (sectionWire.num_overlays>0) { + for (i=0;i<sectionWire.num_overlays;i++) { + tmp= ReadXkmGeomOverlay(file,geom,section); + nRead+= tmp; + if (tmp<1) + return nRead; + } + } + return nRead; +} + +static int +ReadXkmGeometry(FILE *file,XkbDescPtr xkb) +{ +register int i; +char buf[100]; +unsigned tmp; +int nRead= 0; +xkmGeometryDesc wireGeom; +XkbGeometryPtr geom; +XkbGeometrySizesRec sizes; + + nRead+= XkmGetCountedString(file,buf,100); + tmp= fread(&wireGeom,SIZEOF(xkmGeometryDesc),1,file); + nRead+= tmp*SIZEOF(xkmGeometryDesc); + sizes.which= XkbGeomAllMask; + sizes.num_properties= wireGeom.num_properties; + sizes.num_colors= wireGeom.num_colors; + sizes.num_shapes= wireGeom.num_shapes; + sizes.num_sections= wireGeom.num_sections; + sizes.num_doodads= wireGeom.num_doodads; + sizes.num_key_aliases= wireGeom.num_key_aliases; + if (XkbAllocGeometry(xkb,&sizes)!=Success) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); + return nRead; + } + geom= xkb->geom; + geom->name= XkbInternAtom(buf,FALSE); + geom->width_mm= wireGeom.width_mm; + geom->height_mm= wireGeom.height_mm; + nRead+= XkmGetCountedString(file,buf,100); + geom->label_font= _XkbDupString(buf); + if (wireGeom.num_properties>0) { + char val[1024]; + for (i=0;i<wireGeom.num_properties;i++) { + nRead+= XkmGetCountedString(file,buf,100); + nRead+= XkmGetCountedString(file,val,1024); + if (XkbAddGeomProperty(geom,buf,val)==NULL) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); + return nRead; + } + } + } + if (wireGeom.num_colors>0) { + for (i=0;i<wireGeom.num_colors;i++) { + nRead+= XkmGetCountedString(file,buf,100); + if (XkbAddGeomColor(geom,buf,i)==NULL) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); + return nRead; + } + } + } + geom->base_color= &geom->colors[wireGeom.base_color_ndx]; + geom->label_color= &geom->colors[wireGeom.label_color_ndx]; + if (wireGeom.num_shapes>0) { + XkbShapePtr shape; + xkmShapeDesc shapeWire; + Atom nameAtom; + for (i=0;i<wireGeom.num_shapes;i++) { + register int n; + XkbOutlinePtr ol; + xkmOutlineDesc olWire; + nRead+= XkmGetCountedString(file,buf,100); + nameAtom= XkbInternAtom(buf,FALSE); + tmp= fread(&shapeWire,SIZEOF(xkmShapeDesc),1,file); + nRead+= tmp*SIZEOF(xkmShapeDesc); + shape= XkbAddGeomShape(geom,nameAtom,shapeWire.num_outlines); + if (!shape) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); + return nRead; + } + for (n=0;n<shapeWire.num_outlines;n++) { + register int p; + xkmPointDesc ptWire; + tmp= fread(&olWire,SIZEOF(xkmOutlineDesc),1,file); + nRead+= tmp*SIZEOF(xkmOutlineDesc); + ol= XkbAddGeomOutline(shape,olWire.num_points); + if (!ol) { + _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0); + return nRead; + } + ol->num_points= olWire.num_points; + ol->corner_radius= olWire.corner_radius; + for (p=0;p<olWire.num_points;p++) { + tmp= fread(&ptWire,SIZEOF(xkmPointDesc),1,file); + nRead+= tmp*SIZEOF(xkmPointDesc); + ol->points[p].x= ptWire.x; + ol->points[p].y= ptWire.y; + if (ptWire.x<shape->bounds.x1) shape->bounds.x1= ptWire.x; + if (ptWire.x>shape->bounds.x2) shape->bounds.x2= ptWire.x; + if (ptWire.y<shape->bounds.y1) shape->bounds.y1= ptWire.y; + if (ptWire.y>shape->bounds.y2) shape->bounds.y2= ptWire.y; + } + } + if (shapeWire.primary_ndx!=XkbNoShape) + shape->primary= &shape->outlines[shapeWire.primary_ndx]; + if (shapeWire.approx_ndx!=XkbNoShape) + shape->approx= &shape->outlines[shapeWire.approx_ndx]; + } + } + if (wireGeom.num_sections>0) { + for (i=0;i<wireGeom.num_sections;i++) { + tmp= ReadXkmGeomSection(file,geom); + nRead+= tmp; + if (tmp==0) + return nRead; + } + } + if (wireGeom.num_doodads>0) { + for (i=0;i<wireGeom.num_doodads;i++) { + tmp= ReadXkmGeomDoodad(file,geom,NULL); + nRead+= tmp; + if (tmp==0) + return nRead; + } + } + if ((wireGeom.num_key_aliases>0)&&(geom->key_aliases)) { + int sz= XkbKeyNameLength*2; + int num= wireGeom.num_key_aliases; + if (fread(geom->key_aliases,sz,num,file)!=num) { + _XkbLibError(_XkbErrBadLength,"ReadXkmGeometry",0); + return -1; + } + nRead+= (num*sz); + geom->num_key_aliases= num; + } + return nRead; +} + +Bool +XkmProbe(FILE *file) +{ +unsigned hdr,tmp; +int nRead=0; + + hdr= (('x'<<24)|('k'<<16)|('m'<<8)|XkmFileVersion); + tmp= XkmGetCARD32(file,&nRead); + if (tmp!=hdr) { + if ((tmp&(~0xff))==(hdr&(~0xff))) { + _XkbLibError(_XkbErrBadFileVersion,"XkmProbe",tmp&0xff); + } + return 0; + } + return 1; +} + +static Bool +XkmReadTOC(FILE *file,xkmFileInfo* file_info,int max_toc,xkmSectionInfo *toc) +{ +unsigned hdr,tmp; +int nRead=0; +unsigned i,size_toc; + + hdr= (('x'<<24)|('k'<<16)|('m'<<8)|XkmFileVersion); + tmp= XkmGetCARD32(file,&nRead); + if (tmp!=hdr) { + if ((tmp&(~0xff))==(hdr&(~0xff))) { + _XkbLibError(_XkbErrBadFileVersion,"XkmReadTOC",tmp&0xff); + } + else { + _XkbLibError(_XkbErrBadFileType,"XkmReadTOC",tmp); + } + return 0; + } + fread(file_info,SIZEOF(xkmFileInfo),1,file); + size_toc= file_info->num_toc; + if (size_toc>max_toc) { + DebugF("Warning! Too many TOC entries; last %d ignored\n", + size_toc-max_toc); + size_toc= max_toc; + } + for (i=0;i<size_toc;i++) { + fread(&toc[i],SIZEOF(xkmSectionInfo),1,file); + } + return 1; +} + +/***====================================================================***/ + +#define MAX_TOC 16 +unsigned +XkmReadFile(FILE *file,unsigned need,unsigned want,XkbDescPtr *xkb) +{ +register unsigned i; +xkmSectionInfo toc[MAX_TOC],tmpTOC; +xkmFileInfo fileInfo; +unsigned tmp,nRead=0; +unsigned which= need|want; + + if (!XkmReadTOC(file,&fileInfo,MAX_TOC,toc)) + return which; + if ((fileInfo.present&need)!=need) { + _XkbLibError(_XkbErrIllegalContents,"XkmReadFile", + need&(~fileInfo.present)); + return which; + } + if (*xkb==NULL) + *xkb= XkbAllocKeyboard(); + for (i=0;i<fileInfo.num_toc;i++) { + fseek(file,toc[i].offset,SEEK_SET); + tmp= fread(&tmpTOC,SIZEOF(xkmSectionInfo),1,file); + nRead= tmp*SIZEOF(xkmSectionInfo); + if ((tmpTOC.type!=toc[i].type)||(tmpTOC.format!=toc[i].format)|| + (tmpTOC.size!=toc[i].size)||(tmpTOC.offset!=toc[i].offset)) { + return which; + } + if ((which&(1<<tmpTOC.type))==0) { + continue; + } + switch (tmpTOC.type) { + case XkmVirtualModsIndex: + tmp= ReadXkmVirtualMods(file,*xkb,NULL); + break; + case XkmTypesIndex: + tmp= ReadXkmKeyTypes(file,*xkb,NULL); + break; + case XkmCompatMapIndex: + tmp= ReadXkmCompatMap(file,*xkb,NULL); + break; + case XkmKeyNamesIndex: + tmp= ReadXkmKeycodes(file,*xkb,NULL); + break; + case XkmIndicatorsIndex: + tmp= ReadXkmIndicators(file,*xkb,NULL); + break; + case XkmSymbolsIndex: + tmp= ReadXkmSymbols(file,*xkb); + break; + case XkmGeometryIndex: + tmp= ReadXkmGeometry(file,*xkb); + break; + default: + _XkbLibError(_XkbErrBadImplementation, + XkbConfigText(tmpTOC.type,XkbMessage),0); + tmp= 0; + break; + } + if (tmp>0) { + nRead+= tmp; + which&= ~(1<<toc[i].type); + (*xkb)->defined|= (1<<toc[i].type); + } + if (nRead!=tmpTOC.size) { + _XkbLibError(_XkbErrBadLength,XkbConfigText(tmpTOC.type,XkbMessage), + nRead-tmpTOC.size); + } + } + return which; +} diff --git a/xorg-server/xkbdata.src/symbols/fi b/xorg-server/xkbdata.src/symbols/fi index 6c5a3e6af..78dd91934 100644 --- a/xorg-server/xkbdata.src/symbols/fi +++ b/xorg-server/xkbdata.src/symbols/fi @@ -1,231 +1,207 @@ -// based on a keyboard map from an 'xkb/symbols/fi' file -// -// $XKeyboardConfig$ -// $XFree86: xc/programs/xkbcomp/symbols/fi,v 1.9 2003/01/29 17:17:31 dawes Exp $ - -// Troy Korjuslommi, -// Jan 6, 2006 -// May 5, 2006 -// May 6, 2006 -// May 12, 2006 -// Oct 10, 2007 -// Nov 11, 2008 -// Nov 29, 2008 -// Dec 31, 2008 -// Jan 22, 2009 -// -// -// Jan 22, 2009 -// Submit requests to change all remaining Uxxxx values to named versions -// in keysymdef.h. -// ezh : U0292: LATIN SMALL LETTER EZH -// Ezh : U01B7: LATIN CAPITAL LETTER EZH -// permille : U2030: PER MILLE SIGN -// -// Dec 31, 2008 -// U0326 replaced with dead_belowcomma. -// -// Nov 29, 2008 -// dead_belowcomma has been added to keysymdef.h, so the U0326 can be replaced with -// it, as long as the version of X11 is built with the new keysymdef.h file. -// -// Nov 11, 2008. -// (a) Changed <AC10> level 4 from Ooblique to Oslash. The two names are synonyms. Since level 3 is already -// specified as oslash, the change adds consistency. -// (b) The new Finnish keyboard standard (SFS 5966) reserves <AB10> level 4 for U0326, the combining comma below. -// Removed the previous dead_abovedot entry there and replaced it with U0326, which can be replaced -// with dead_commabelow if that is added to keysymdef.h. -// -// Oct 10, 2007. -// -Changed space column 3 to nobreakspace (from space). -// -Changed UFE63 entries to dead_stroke. -// -// Nov 29, 2006. -// UFE63 can be changed to dead_stroke starting with version 7.0.7. of the X server. -// -// Dec 05, 2006. -// Changed instances of NoSymbol in columns 3 and 4 to characters in columns 1 and 2. -// This fixes a bug where the mappings couldn't be changed (with xmodmap for example). -// NoSymbol left in other positions, so nothing is output from those key presses. -// -// Dec 11, 2006. -// Changed all Uxxxx values to named versions. -// If you have problems, check these defines (when compiling X): -// XK_LATIN9: oe, OE. -// XK_CURRENCY: EuroSign. -// XK_LATIN2: caron. -// XK_LATIN3: idotless. -// XK_LATIN4: kra, eng, ENG. -// XK_CAUCASUS: schwa, SCHWA. -// XK_PUBLISHING: rightdoublequotemark, leftdoublequotemark, singlelowquotemark, doublelowquotemark, emdash, -// rightsinglequotemark, leftsinglequotemark, endash. -// -// Unnamed positions: -// UFE63: dead_stroke. Will be fixed, once the entry is in keysymdef.h. -// U0292: LATIN SMALL LETTER EZH. -// U01B7: LATIN CAPITAL LETTER EZH. -// U2030: PER MILLE SIGN. -// Comment: XK_MillSign is U+20A5 MILL SIGN. -// Per mille is a generic term for 1/1000. Mill is 1/1000 of a dollar. -// - -partial default alphanumeric_keys -xkb_symbols "kotoistus" { - - name[Group1]="Finland"; - - key <TLDE> { [ section, onehalf, dead_stroke, NoSymbol ] }; - key <AE01> { [ 1, exclam, NoSymbol, exclamdown ] }; - key <AE02> { [ 2, quotedbl, at, rightdoublequotemark ] }; - key <AE03> { [ 3, numbersign, sterling, guillemotright ] }; - key <AE04> { [ 4, currency, dollar, guillemotleft ] }; - key <AE05> { [ 5, percent, U2030, leftdoublequotemark ] }; - key <AE06> { [ 6, ampersand, singlelowquotemark, doublelowquotemark ] }; - key <AE07> { [ 7, slash, braceleft, NoSymbol ] }; - key <AE08> { [ 8, parenleft, bracketleft, less ] }; - key <AE09> { [ 9, parenright, bracketright, greater ] }; - key <AE10> { [ 0, equal, braceright, degree ] }; - key <AE11> { [ plus, question, backslash, questiondown ] }; - key <AE12> { [ dead_acute, dead_grave, dead_cedilla, dead_ogonek ] }; - key <AD01> { [ q, Q, q, Q ] }; - key <AD02> { [ w, W, w, W ] }; - key <AD03> { [ e, E, EuroSign, NoSymbol ] }; - key <AD04> { [ r, R, r, R ] }; - key <AD05> { [ t, T, thorn, THORN ] }; - key <AD06> { [ y, Y, y, Y ] }; - key <AD07> { [ u, U, u, U ] }; - key <AD08> { [ i, I, idotless, bar ] }; - key <AD09> { [ o, O, oe, OE ] }; - key <AD10> { [ p, P, dead_horn, dead_hook ] }; - key <AD11> { [ aring, Aring, dead_doubleacute, dead_abovering ] }; - key <AD12> { [ dead_diaeresis, dead_circumflex, dead_tilde, dead_macron ] }; - key <AC01> { [ a, A, schwa, SCHWA ] }; - key <AC02> { [ s, S, ssharp, NoSymbol ] }; - key <AC03> { [ d, D, eth, ETH ] }; - key <AC04> { [ f, F, f, F ] }; - key <AC05> { [ g, G, g, G ] }; - key <AC06> { [ h, H, h, H ] }; - key <AC07> { [ j, J, j, J ] }; - key <AC08> { [ k, K, kra, NoSymbol ] }; - key <AC09> { [ l, L, dead_stroke, NoSymbol ] }; - key <AC10> { [ odiaeresis, Odiaeresis, oslash, Oslash ] }; - key <AC11> { [ adiaeresis, Adiaeresis, ae, AE ] }; - key <BKSL> { [ apostrophe, asterisk, dead_caron, dead_breve ] }; - key <LSGT> { [ less, greater, bar, NoSymbol ] }; - key <AB01> { [ z, Z, U0292, U01B7 ] }; - key <AB02> { [ x, X, multiply, periodcentered ] }; - key <AB03> { [ c, C, c, C ] }; - key <AB04> { [ v, V, v, V ] }; - key <AB05> { [ b, B, b, B ] }; - key <AB06> { [ n, N, eng, ENG ] }; - key <AB07> { [ m, M, mu, emdash ] }; - key <AB08> { [ comma, semicolon, rightsinglequotemark, leftsinglequotemark ] }; - key <AB09> { [ period, colon, dead_belowdot, dead_abovedot ] }; - key <AB10> { [ minus, underscore, endash, dead_belowcomma ] }; - - include "nbsp(level3)" - - include "kpdl(comma)" - - include "level3(ralt_switch)" - - include "compose(rwin)" -}; - - -partial alphanumeric_keys -xkb_symbols "classic" { - include "latin(type2)" - include "fi(fi)" - - name[Group1]="Finland - Classic"; -}; - -hidden partial alphanumeric_keys -xkb_symbols "fi" { - - // a Finnish keyboard with dead key support and all of - // ISO-8859-1 and ISO-8859-15 characters available. - - key <TLDE> { [ section, onehalf, onequarter, threequarters ] }; - key <LSGT> { [ less, greater, bar, brokenbar ] }; - // AltGr+<SPCE> is pressed accidentally too often after AltGr+<LSGT>, - // hence AltGr+<SPCE> produces now space, not nobreakspace. - key <SPCE> { [ space, space, space, nobreakspace ] }; - key <AE01> { [ 1, exclam, exclamdown, onesuperior ] }; - key <AE02> { [ 2, quotedbl, at, twosuperior ] }; - key <AE03> { [ 3, numbersign, sterling, threesuperior ] }; - key <AE04> { [ 4, currency, dollar, cent ] }; - key <AE05> { [ 5, percent, EuroSign, masculine ] }; - key <AE06> { [ 6, ampersand, yen, ordfeminine ] }; - key <AE07> { [ 7, slash, braceleft, plusminus ] }; - key <AE08> { [ 8, parenleft, bracketleft, guillemotleft ] }; - key <AE09> { [ 9, parenright, bracketright, guillemotright ] }; - key <AE10> { [ 0, equal, braceright, degree ] }; - key <AB09> { [ period, colon, periodcentered, notsign ] }; - key <AB01> { [ z, Z, zcaron, Zcaron ] }; - key <AB02> { [ x, X, multiply, division ] }; - key <AB03> { [ c, C, copyright, cent ] }; - key <AB05> { [ b, B, ssharp, NoSymbol ] }; - key <AB06> { [ n, N, ntilde, Ntilde ] }; - key <AB07> { [ m, M, mu, NoSymbol ] }; - key <AB10> { [ minus, underscore, hyphen, dead_macron ] }; - key <AC02> { [ s, S, scaron, Scaron ] }; - key <AC03> { [ d, D, eth, ETH ] }; - key <AD03> { [ e, E, EuroSign, cent ] }; - key <AD04> { [ r, R, registered, NoSymbol ] }; - key <AD05> { [ t, T, thorn, THORN ] }; - key <AD10> { [ p, P, paragraph, NoSymbol ] }; - key <AC10> { [ odiaeresis, Odiaeresis, oslash, Ooblique ] }; - key <AE11> { [ plus, question, backslash, questiondown ] }; - key <AC11> { [ adiaeresis, Adiaeresis, ae, AE ] }; - key <BKSL> { [ apostrophe, asterisk ] }; - key <AD11> { [ aring, Aring, oe, OE ] }; - key <AE12> { [ dead_acute, dead_grave ] }; - key <AD12> { [ dead_diaeresis, dead_circumflex, dead_tilde, dead_caron ] }; - - // End alphanumeric section, begin "Keypad" - include "kpdl(comma)" - // End "Keypad" section - - include "level3(ralt_switch)" -}; - -partial alphanumeric_keys -xkb_symbols "nodeadkeys" { - include "latin(type2)" - include "latin(type2_nodeadkeys)" - include "fi(fi)" - - name[Group1]="Finland - Classic, eliminate dead keys"; - - key <AE12> { [ acute, grave ] }; - key <AD12> { [ diaeresis, asciicircum, asciitilde, caron ] }; - key <AB10> { [ minus, underscore, hyphen, macron ] }; -}; - -xkb_symbols "smi" { - - // Describes the differences between a Norwegian Northern Sami - // (keyboard with dead key support) and a Swedish/Finnish Sami - // keyboard according to the specs at: - // http://www.hum.uit.no/a/trond/se-lat9-sefi-keys.html - - include "no(smi)" - - name[Group1]= "Finland - Northern Saami"; - - key <AC10> { [odiaeresis, Odiaeresis, oslash, Ooblique ] }; - key <AC11> { [adiaeresis, Adiaeresis, ae, AE ] }; -}; - -// Copied from macintosh_vndr/fi -partial alphanumeric_keys -xkb_symbols "mac" { - - // Describes the differences between a very simple mac_US - // keyboard and a very simple Swedish(Finland) keybaord - - include "se(mac)" - name[Group1]= "Finland - Macintosh"; -}; +// +// $XKeyboardConfig$ +// +// X keyboard maps for Finland +// +// SFS 5966 / Kotoistus keymap created by Troy Korjuslommi +// Classic keymap based on traditional by Marko Myllynen +// Eliminate deadkeys alternative sent by Linus Torvalds +// + +// +// Missing from X11/keysymdef.h as of 2010-05-13 +// +// U2030 # PER MILLE SIGN +// U0292 # LATIN SMALL LETTER EZH +// U01B7 # LATIN CAPITAL LETTER EZH +// + +partial alphanumeric_keys default +xkb_symbols "kotoistus" { + + // Official keymap for Finland based on SFS 5966 standard + // + // This keymap implements all the functionality of Annex 1 + // of the standard and additionally defines the following to + // allow entering these characters with keyboars without LSGT. + // + // AE08+4, U+003C : LESS-THAN SIGN (less) + // AE09+4, U+003E : GREATER-THAN SIGN (greater) + // AD08+4, U+007C : VERTICAL LINE (bar) + // + // Annex 3 of the standard is implemented in fi_FI.UTF-8/Compose + + name[Group1]="Finland"; + + key <TLDE> { [ section, onehalf, dead_stroke, NoSymbol ] }; + key <AE01> { [ 1, exclam, NoSymbol, exclamdown ] }; + key <AE02> { [ 2, quotedbl, at, rightdoublequotemark ] }; + key <AE03> { [ 3, numbersign, sterling, guillemotright ] }; + key <AE04> { [ 4, currency, dollar, guillemotleft ] }; + key <AE05> { [ 5, percent, U2030, leftdoublequotemark ] }; + key <AE06> { [ 6, ampersand, singlelowquotemark, doublelowquotemark ] }; + key <AE07> { [ 7, slash, braceleft, NoSymbol ] }; + key <AE08> { [ 8, parenleft, bracketleft, less ] }; + key <AE09> { [ 9, parenright, bracketright, greater ] }; + key <AE10> { [ 0, equal, braceright, degree ] }; + key <AE11> { [ plus, question, backslash, questiondown ] }; + key <AE12> { [ dead_acute, dead_grave, dead_cedilla, dead_ogonek ] }; + + key <AD01> { [ q, Q, q, Q ] }; + key <AD02> { [ w, W, w, W ] }; + key <AD03> { [ e, E, EuroSign, NoSymbol ] }; + key <AD04> { [ r, R, r, R ] }; + key <AD05> { [ t, T, thorn, THORN ] }; + key <AD06> { [ y, Y, y, Y ] }; + key <AD07> { [ u, U, u, U ] }; + key <AD08> { [ i, I, idotless, bar ] }; + key <AD09> { [ o, O, oe, OE ] }; + key <AD10> { [ p, P, dead_horn, dead_hook ] }; + key <AD11> { [ aring, Aring, dead_doubleacute, dead_abovering ] }; + key <AD12> { [ dead_diaeresis, dead_circumflex, dead_tilde, dead_macron ] }; + + key <AC01> { [ a, A, schwa, SCHWA ] }; + key <AC02> { [ s, S, ssharp, NoSymbol ] }; + key <AC03> { [ d, D, eth, ETH ] }; + key <AC04> { [ f, F, f, F ] }; + key <AC05> { [ g, G, g, G ] }; + key <AC06> { [ h, H, h, H ] }; + key <AC07> { [ j, J, j, J ] }; + key <AC08> { [ k, K, kra, NoSymbol ] }; + key <AC09> { [ l, L, dead_stroke, NoSymbol ] }; + key <AC10> { [ odiaeresis, Odiaeresis, oslash, Oslash ] }; + key <AC11> { [ adiaeresis, Adiaeresis, ae, AE ] }; + key <BKSL> { [ apostrophe, asterisk, dead_caron, dead_breve ] }; + + key <LSGT> { [ less, greater, bar, NoSymbol ] }; + key <AB01> { [ z, Z, U0292, U01B7 ] }; + key <AB02> { [ x, X, multiply, periodcentered ] }; + key <AB03> { [ c, C, c, C ] }; + key <AB04> { [ v, V, v, V ] }; + key <AB05> { [ b, B, b, B ] }; + key <AB06> { [ n, N, eng, ENG ] }; + key <AB07> { [ m, M, mu, emdash ] }; + key <AB08> { [ comma, semicolon, rightsinglequotemark, leftsinglequotemark ] }; + key <AB09> { [ period, colon, dead_belowdot, dead_abovedot ] }; + key <AB10> { [ minus, underscore, endash, dead_belowcomma ] }; + + include "nbsp(level3)" + include "kpdl(comma)" + include "level3(ralt_switch)" + include "compose(rwin)" +}; + +partial alphanumeric_keys +xkb_symbols "classic" { + + include "fi(fi)" + + name[Group1]="Finland - Classic"; +}; + +partial alphanumeric_keys hidden +xkb_symbols "fi" { + + // Classic Finnish keyboard layout with dead keys support + // and all ISO-8859-1 and ISO-8859-15 characters available + + key <TLDE> { [ section, onehalf, onequarter, threequarters ] }; + key <AE01> { [ 1, exclam, exclamdown, onesuperior ] }; + key <AE02> { [ 2, quotedbl, at, twosuperior ] }; + key <AE03> { [ 3, numbersign, sterling, threesuperior ] }; + key <AE04> { [ 4, currency, dollar, cent ] }; + key <AE05> { [ 5, percent, EuroSign, masculine ] }; + key <AE06> { [ 6, ampersand, yen, ordfeminine ] }; + key <AE07> { [ 7, slash, braceleft, plusminus ] }; + key <AE08> { [ 8, parenleft, bracketleft, guillemotleft ] }; + key <AE09> { [ 9, parenright, bracketright, guillemotright ] }; + key <AE10> { [ 0, equal, braceright, degree ] }; + key <AE11> { [ plus, question, backslash, questiondown ] }; + key <AE12> { [ dead_acute, dead_grave, dead_cedilla, dead_ogonek ] }; + + key <AD01> { [ q, Q, q, Q ] }; + key <AD02> { [ w, W, w, W ] }; + key <AD03> { [ e, E, EuroSign, cent ] }; + key <AD04> { [ r, R, registered, NoSymbol ] }; + key <AD05> { [ t, T, thorn, THORN ] }; + key <AD06> { [ y, Y, y, Y ] }; + key <AD07> { [ u, U, u, U ] }; + key <AD08> { [ i, I, idotless, bar ] }; + key <AD09> { [ o, O, o, O ] }; + key <AD10> { [ p, P, paragraph, NoSymbol ] }; + key <AD11> { [ aring, Aring, oe, OE ] }; + key <AD12> { [ dead_diaeresis, dead_circumflex, dead_tilde, dead_caron ] }; + + key <AC01> { [ a, A, schwa, SCHWA ] }; + key <AC02> { [ s, S, scaron, Scaron ] }; + key <AC03> { [ d, D, eth, ETH ] }; + key <AC04> { [ f, F, f, F ] }; + key <AC05> { [ g, G, eng, ENG ] }; + key <AC06> { [ h, H, h, H ] }; + key <AC07> { [ j, J, j, J ] }; + key <AC08> { [ k, K, kra, NoSymbol ] }; + key <AC09> { [ l, L, dead_stroke, NoSymbol ] }; + key <AC10> { [ odiaeresis, Odiaeresis, oslash, Oslash ] }; + key <AC11> { [ adiaeresis, Adiaeresis, ae, AE ] }; + key <BKSL> { [ apostrophe, asterisk, dead_caron, dead_breve ] }; + + key <LSGT> { [ less, greater, bar, brokenbar ] }; + key <AB01> { [ z, Z, zcaron, Zcaron ] }; + key <AB02> { [ x, X, multiply, division ] }; + key <AB03> { [ c, C, copyright, cent ] }; + key <AB04> { [ v, V, v, V ] }; + key <AB05> { [ b, B, ssharp, NoSymbol ] }; + key <AB06> { [ n, N, ntilde, Ntilde ] }; + key <AB07> { [ m, M, mu, NoSymbol ] }; + key <AB08> { [ comma, semicolon, dead_cedilla, dead_ogonek ] }; + key <AB09> { [ period, colon, periodcentered, notsign ] }; + key <AB10> { [ minus, underscore, hyphen, dead_macron ] }; + + include "nbsp(level4)" + include "kpdl(comma)" + include "level3(ralt_switch)" + include "compose(rwin)" +}; + +partial alphanumeric_keys +xkb_symbols "nodeadkeys" { + + // Classic Finnish keyboard layout without dead keys + + include "fi(fi)" + + name[Group1]="Finland - Classic, eliminate dead keys"; + + key <AE12> { [ acute, grave, cedilla, ogonek ] }; + key <AD12> { [ diaeresis, asciicircum, asciitilde, caron ] }; + key <AC09> { [ l, L, l, L ] }; + key <BKSL> { [ apostrophe, asterisk, caron, breve ] }; + key <AB08> { [ comma, semicolon, cedilla, ogonek ] }; + key <AB10> { [ minus, underscore, hyphen, macron ] }; +}; + +partial alphanumeric_keys +xkb_symbols "smi" { + + // Describes the differences between a Norwegian Northern Sami + // (keyboard with dead key support) and a Swedish/Finnish Sami + // keyboard according to the specs at: + // http://www.hum.uit.no/a/trond/se-lat9-sefi-keys.html + + include "no(smi)" + + name[Group1]="Finland - Northern Saami"; + + key <AC10> { [ odiaeresis, Odiaeresis, oslash, Oslash ] }; + key <AC11> { [ adiaeresis, Adiaeresis, ae, AE ] }; +}; + +partial alphanumeric_keys +xkb_symbols "mac" { + + // Macintosh keyboard for Finland based on Swedish(Macintosh) keyboard + + include "se(mac)" + + name[Group1]="Finland - Macintosh"; +}; diff --git a/xorg-server/xkbdata.src/symbols/hu b/xorg-server/xkbdata.src/symbols/hu index e5abdf2ad..9e97740fa 100644 --- a/xorg-server/xkbdata.src/symbols/hu +++ b/xorg-server/xkbdata.src/symbols/hu @@ -1,427 +1,432 @@ -// New style XKB layout for some widely used Hungarian keyboard layouts -// -// Based on old style 'xkb/symbols/hu" -// -// $XKeyboardConfig$ -// (C) 2002-2004 Soós Péter <sp@osb.hu> -// -// Permission is granted to anyone to use, distribute and modify -// this file in any way, provided that the above copyright notice -// is left intact and the author of the modification summarizes -// the changes in this header. -// -// This file is distributed without any expressed or implied warranty. -// -// Changes: -// 2004-04-17 - Moved to new style (only Unicode based layouts) -// - Added consistent dead key support -// - Fixed abovedot -// - Added adiaeresis -// - Added EuroSign and cent symbol - - -// Default layout -default partial -xkb_symbols "basic" { - include "hu(102_qwertz_comma_dead)" - name[Group1] = "Hungary"; -}; - -// Standard layout -partial -xkb_symbols "standard" { - include "hu(102_qwertz_comma_dead)" - name[Group1] = "Hungary - Standard"; -}; - -// Standard layout without dead key support -partial -xkb_symbols "nodeadkeys" { - include "hu(102_qwertz_comma_nodead)" - name[Group1] = "Hungary - Eliminate dead keys"; -}; - -// Qwerty layout -partial -xkb_symbols "qwerty" { - include "hu(101_qwerty_comma_dead)" - name[Group1] = "Hungary - qwerty"; -}; - -// Main layouts - -// 101_qwertz_comma_dead -// 101 key qwertz layout -// with decimal comma on keypad -// and with dead key support -partial -xkb_symbols "101_qwertz_comma_dead" { - name[Group1] = "Hungary - 101/qwertz/comma/Dead keys"; - include "latin" - include "hu(def_101)" - include "hu(def_qwertz)" - include "kpdl(comma)" - include "hu(def_dead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 101_qwertz_comma_nodead -// 101 key qwertz layout -// with decimal comma on keypad -// and without dead key support -partial -xkb_symbols "101_qwertz_comma_nodead" { - name[Group1] = "Hungary - 101/qwertz/comma/Eliminate dead keys"; - include "latin" - include "hu(def_101)" - include "hu(def_qwertz)" - include "kpdl(comma)" - include "hu(def_nodead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 101_qwertz_dot_dead -// 101 key qwertz layout -// with decimal dot on keypad -// and with dead key support -partial -xkb_symbols "101_qwertz_dot_dead" { - name[Group1] = "Hungary - 101/qwertz/dot/Dead keys"; - include "latin" - include "hu(def_101)" - include "hu(def_qwertz)" - include "hu(def_dot)" - include "hu(def_dead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 101_qwertz_dot_nodead -// 101 key qwertz layout -// with decimal dot on keypad -// and without dead key support -partial -xkb_symbols "101_qwertz_dot_nodead" { - name[Group1] = "Hungary - 101/qwertz/dot/Eliminate dead keys"; - include "latin" - include "hu(def_101)" - include "hu(def_qwertz)" - include "hu(def_dot)" - include "hu(def_nodead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 101_qwerty_comma_dead -// 101 key qwerty layout -// with decimal comma on keypad -// and with dead key support -partial -xkb_symbols "101_qwerty_comma_dead" { - name[Group1] = "Hungary - 101/qwerty/comma/Dead keys"; - include "latin" - include "hu(def_101)" - include "hu(def_qwerty)" - include "kpdl(comma)" - include "hu(def_dead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 101_qwerty_comma_nodead -// 101 key qwerty layout -// with decimal comma on keypad -// and without dead key support -partial -xkb_symbols "101_qwerty_comma_nodead" { - name[Group1] = "Hungary - 101/qwerty/comma/Eliminate dead keys"; - include "latin" - include "hu(def_101)" - include "hu(def_qwerty)" - include "kpdl(comma)" - include "hu(def_nodead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 101_qwerty_dot_dead -// 101 key qwerty layout -// with decimal dot on keypad -// and with dead key support -partial -xkb_symbols "101_qwerty_dot_dead" { - name[Group1] = "Hungary - 101/qwerty/dot/Dead keys"; - include "latin" - include "hu(def_101)" - include "hu(def_qwerty)" - include "hu(def_dot)" - include "hu(def_dead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 101_qwerty_dot_nodead -// 101 key qwerty layout -// with decimal dot on keypad -// and without dead key support -partial -xkb_symbols "101_qwerty_dot_nodead" { - name[Group1] = "Hungary - 101/qwerty/dot/Eliminate dead keys"; - include "latin" - include "hu(def_101)" - include "hu(def_qwerty)" - include "hu(def_dot)" - include "hu(def_nodead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 102_qwertz_comma_dead -// 102 key qwertz layout -// with decimal comma on keypad -// and with dead key support -partial -xkb_symbols "102_qwertz_comma_dead" { - name[Group1] = "Hungary - 102/qwertz/comma/Dead keys"; - include "latin" - include "hu(def_102)" - include "hu(def_qwertz)" - include "kpdl(comma)" - include "hu(def_dead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 102_qwertz_comma_nodead -// 102 key qwertz layout -// with decimal comma on keypad -// and without dead key support -partial -xkb_symbols "102_qwertz_comma_nodead" { - name[Group1] = "Hungary - 102/qwertz/comma/Eliminate dead keys"; - include "latin" - include "hu(def_102)" - include "hu(def_qwertz)" - include "kpdl(comma)" - include "hu(def_nodead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 102_qwertz_dot_dead -// 102 key qwertz layout -// with decimal dot on keypad -// and with dead key support -partial -xkb_symbols "102_qwertz_dot_dead" { - name[Group1] = "Hungary - 102/qwertz/dot/Dead keys"; - include "latin" - include "hu(def_102)" - include "hu(def_qwertz)" - include "hu(def_dot)" - include "hu(def_dead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 102_qwertz_dot_nodead -// 102 key qwertz layout -// with decimal dot on keypad -// and without dead key support -partial -xkb_symbols "102_qwertz_dot_nodead" { - name[Group1] = "Hungary - 102/qwertz/dot/Eliminate dead keys"; - include "latin" - include "hu(def_102)" - include "hu(def_qwertz)" - include "hu(def_dot)" - include "hu(def_nodead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 102_qwerty_comma_dead -// 102 key qwerty layout -// with decimal comma on keypad -// and with dead key support -partial -xkb_symbols "102_qwerty_comma_dead" { - name[Group1] = "Hungary - 102/qwerty/comma/Dead keys"; - include "latin" - include "hu(def_102)" - include "hu(def_qwerty)" - include "kpdl(comma)" - include "hu(def_dead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 102_qwerty_comma_nodead -// 102 key qwerty layout -// with decimal comma on keypad -// and without dead key support -partial -xkb_symbols "102_qwerty_comma_nodead" { - name[Group1] = "Hungary - 102/qwerty/comma/Eliminate dead keys"; - include "latin" - include "hu(def_102)" - include "hu(def_qwerty)" - include "kpdl(comma)" - include "hu(def_nodead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 102_qwerty_dot_dead -// 102 key qwerty layout -// with decimal dot on keypad -// and with dead key support -partial -xkb_symbols "102_qwerty_dot_dead" { - name[Group1] = "Hungary - 102/qwerty/dot/Dead keys"; - include "latin" - include "hu(def_102)" - include "hu(def_qwerty)" - include "hu(def_dot)" - include "hu(def_dead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// 102_qwerty_dot_nodead -// 102 key qwerty layout -// with decimal dot on keypad -// and without dead key support -partial -xkb_symbols "102_qwerty_dot_nodead" { - name[Group1] = "Hungary - 102/qwerty/dot/Eliminate dead keys"; - include "latin" - include "hu(def_102)" - include "hu(def_qwerty)" - include "hu(def_dot)" - include "hu(def_nodead)" - include "hu(def_common)" - include "level3(ralt_switch)" -}; - -// Partial layouts - -// def_102: -// The standard Hungarian 102 key layout -hidden partial alphanumeric_keys -xkb_symbols "def_102" { - key <TLDE> { [ 0, section, notsign ] }; - key <LSGT> { [ iacute, Iacute, less, greater ] }; - -}; - -// def_101: -// An alternative layout for 101 key keyboards -hidden partial alphanumeric_keys -xkb_symbols "def_101" { - key <TLDE> { [ iacute, Iacute, 0, section ] }; - key <LSGT> { [ less, greater ] }; -}; - -// def_qwertz: -// The standard Hungaryan qwertz layout -hidden partial alphanumeric_keys -xkb_symbols "def_qwertz" { - key <AD06> { [ z, Z, endash ] }; - key <AB01> { [ y, Y, greater ] }; -}; - - -// def_qwerty: -// The qwerty layout for people who familiar with the standard US layout -hidden partial alphanumeric_keys -xkb_symbols "def_qwerty" { - key <AD06> { [ y, Y, endash ] }; - key <AB01> { [ z, Z, greater ] }; -}; - -// def_dot: -// The Hungarian standard is the comma on the keypad not decimal dot, -// but programmers hate it -hidden partial keypad_keys -xkb_symbols "def_dot" { - key <KPDL> { [ KP_Delete, KP_Decimal ] }; -}; - - -// def_dead: -// Dead keys support part -hidden partial alphanumeric_keys -xkb_symbols "def_dead" { - key <AE01> { [ 1, apostrophe, asciitilde, dead_tilde ] }; - key <AE02> { [ 2, quotedbl, dead_caron, caron ] }; - key <AE03> { [ 3, plus, asciicircum, dead_circumflex ] }; - key <AE04> { [ 4, exclam, dead_breve, breve ] }; - key <AE05> { [ 5, percent, dead_abovering, degree ] }; - key <AE06> { [ 6, slash, dead_ogonek, ogonek ] }; - key <AE07> { [ 7, equal, grave, dead_grave ] }; - key <AE08> { [ 8, parenleft, dead_abovedot, abovedot ] }; - key <AE09> { [ 9, parenright, dead_acute, acute ] }; - key <AE10> { [ odiaeresis, Odiaeresis, dead_doubleacute, doubleacute ] }; - key <AE11> { [ udiaeresis, Udiaeresis, dead_diaeresis, diaeresis ] }; - key <AE12> { [ oacute, Oacute, dead_cedilla, cedilla ] }; -}; - -// def_nodead: -// Without dead keys support -hidden partial alphanumeric_keys -xkb_symbols "def_nodead" { - key <AE01> { [ 1, apostrophe, asciitilde ] }; - key <AE02> { [ 2, quotedbl, caron ] }; - key <AE03> { [ 3, plus, asciicircum ] }; - key <AE04> { [ 4, exclam, breve ] }; - key <AE05> { [ 5, percent, degree ] }; - key <AE06> { [ 6, slash, ogonek ] }; - key <AE07> { [ 7, equal, grave ] }; - key <AE08> { [ 8, parenleft, abovedot ] }; - key <AE09> { [ 9, parenright, acute ] }; - key <AE10> { [ odiaeresis, Odiaeresis, doubleacute ] }; - key <AE11> { [ udiaeresis, Udiaeresis, diaeresis ] }; - key <AE12> { [ oacute, Oacute, cedilla ] }; -}; - - -// def_common: -// The common part of all Hungarian layout above -hidden partial alphanumeric_keys -xkb_symbols "def_common" { - key <AD01> { [ q, Q, backslash ] }; - key <AD02> { [ w, W, bar ] }; - key <AD07> { [ u, U, EuroSign ] }; - key <AD08> { [ i, I, Iacute, iacute ] }; - key <AD09> { [ o, O, doublelowquotemark ] }; - key <AD10> { [ p, P, rightdoublequotemark ] }; - key <AD11> { [ odoubleacute, Odoubleacute, division ] }; - key <AD12> { [ uacute, Uacute, multiply ] }; - - key <AC01> { [ a, A, adiaeresis, Adiaeresis ] }; - key <AC02> { [ s, S, dstroke ] }; - key <AC03> { [ d, D, Dstroke ] }; - key <AC04> { [ f, F, bracketleft ] }; - key <AC05> { [ g, G, bracketright ] }; - key <AC07> { [ j, J, iacute, Iacute ] }; - key <AC08> { [ k, K, lstroke ] }; - key <AC09> { [ l, L, Lstroke ] }; - key <AC10> { [ eacute, Eacute, dollar, cent ] }; - key <AC11> { [ aacute, Aacute, ssharp ] }; - - key <BKSL> { [ udoubleacute, Udoubleacute, currency ] }; - - key <AB02> { [ x, X, numbersign ] }; - key <AB03> { [ c, C, ampersand ] }; - key <AB04> { [ v, V, at ] }; - key <AB05> { [ b, B, braceleft ] }; - key <AB06> { [ n, N, braceright ] }; - key <AB07> { [ m, M, less ] }; - key <AB08> { [ comma, question, semicolon ] }; - key <AB09> { [ period, colon, greater ] }; - key <AB10> { [ minus, underscore, asterisk ] }; - -}; +// New style XKB layout for some widely used Hungarian keyboard layouts +// +// Based on old style 'xkb/symbols/hu" +// +// $XKeyboardConfig$ +// (C) 2002-2004 Soós Péter <sp@osb.hu> +// (C) 2010 Andras Timar <timar@fsf.hu> +// +// Permission is granted to anyone to use, distribute and modify +// this file in any way, provided that the above copyright notice +// is left intact and the author of the modification summarizes +// the changes in this header. +// +// This file is distributed without any expressed or implied warranty. +// +// Changes: +// 2004-04-17 - Moved to new style (only Unicode based layouts) +// - Added consistent dead key support +// - Fixed abovedot +// - Added adiaeresis +// - Added EuroSign and cent symbol +// 2010-04-23 - Added doublelowquotemark +// - Added rightdoublequotemark +// - Added endash +// 2010-05-13 - Added ellipsis + + +// Default layout +default partial +xkb_symbols "basic" { + include "hu(102_qwertz_comma_dead)" + name[Group1] = "Hungary"; +}; + +// Standard layout +partial +xkb_symbols "standard" { + include "hu(102_qwertz_comma_dead)" + name[Group1] = "Hungary - Standard"; +}; + +// Standard layout without dead key support +partial +xkb_symbols "nodeadkeys" { + include "hu(102_qwertz_comma_nodead)" + name[Group1] = "Hungary - Eliminate dead keys"; +}; + +// Qwerty layout +partial +xkb_symbols "qwerty" { + include "hu(101_qwerty_comma_dead)" + name[Group1] = "Hungary - qwerty"; +}; + +// Main layouts + +// 101_qwertz_comma_dead +// 101 key qwertz layout +// with decimal comma on keypad +// and with dead key support +partial +xkb_symbols "101_qwertz_comma_dead" { + name[Group1] = "Hungary - 101/qwertz/comma/Dead keys"; + include "latin" + include "hu(def_101)" + include "hu(def_qwertz)" + include "kpdl(comma)" + include "hu(def_dead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 101_qwertz_comma_nodead +// 101 key qwertz layout +// with decimal comma on keypad +// and without dead key support +partial +xkb_symbols "101_qwertz_comma_nodead" { + name[Group1] = "Hungary - 101/qwertz/comma/Eliminate dead keys"; + include "latin" + include "hu(def_101)" + include "hu(def_qwertz)" + include "kpdl(comma)" + include "hu(def_nodead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 101_qwertz_dot_dead +// 101 key qwertz layout +// with decimal dot on keypad +// and with dead key support +partial +xkb_symbols "101_qwertz_dot_dead" { + name[Group1] = "Hungary - 101/qwertz/dot/Dead keys"; + include "latin" + include "hu(def_101)" + include "hu(def_qwertz)" + include "hu(def_dot)" + include "hu(def_dead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 101_qwertz_dot_nodead +// 101 key qwertz layout +// with decimal dot on keypad +// and without dead key support +partial +xkb_symbols "101_qwertz_dot_nodead" { + name[Group1] = "Hungary - 101/qwertz/dot/Eliminate dead keys"; + include "latin" + include "hu(def_101)" + include "hu(def_qwertz)" + include "hu(def_dot)" + include "hu(def_nodead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 101_qwerty_comma_dead +// 101 key qwerty layout +// with decimal comma on keypad +// and with dead key support +partial +xkb_symbols "101_qwerty_comma_dead" { + name[Group1] = "Hungary - 101/qwerty/comma/Dead keys"; + include "latin" + include "hu(def_101)" + include "hu(def_qwerty)" + include "kpdl(comma)" + include "hu(def_dead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 101_qwerty_comma_nodead +// 101 key qwerty layout +// with decimal comma on keypad +// and without dead key support +partial +xkb_symbols "101_qwerty_comma_nodead" { + name[Group1] = "Hungary - 101/qwerty/comma/Eliminate dead keys"; + include "latin" + include "hu(def_101)" + include "hu(def_qwerty)" + include "kpdl(comma)" + include "hu(def_nodead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 101_qwerty_dot_dead +// 101 key qwerty layout +// with decimal dot on keypad +// and with dead key support +partial +xkb_symbols "101_qwerty_dot_dead" { + name[Group1] = "Hungary - 101/qwerty/dot/Dead keys"; + include "latin" + include "hu(def_101)" + include "hu(def_qwerty)" + include "hu(def_dot)" + include "hu(def_dead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 101_qwerty_dot_nodead +// 101 key qwerty layout +// with decimal dot on keypad +// and without dead key support +partial +xkb_symbols "101_qwerty_dot_nodead" { + name[Group1] = "Hungary - 101/qwerty/dot/Eliminate dead keys"; + include "latin" + include "hu(def_101)" + include "hu(def_qwerty)" + include "hu(def_dot)" + include "hu(def_nodead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 102_qwertz_comma_dead +// 102 key qwertz layout +// with decimal comma on keypad +// and with dead key support +partial +xkb_symbols "102_qwertz_comma_dead" { + name[Group1] = "Hungary - 102/qwertz/comma/Dead keys"; + include "latin" + include "hu(def_102)" + include "hu(def_qwertz)" + include "kpdl(comma)" + include "hu(def_dead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 102_qwertz_comma_nodead +// 102 key qwertz layout +// with decimal comma on keypad +// and without dead key support +partial +xkb_symbols "102_qwertz_comma_nodead" { + name[Group1] = "Hungary - 102/qwertz/comma/Eliminate dead keys"; + include "latin" + include "hu(def_102)" + include "hu(def_qwertz)" + include "kpdl(comma)" + include "hu(def_nodead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 102_qwertz_dot_dead +// 102 key qwertz layout +// with decimal dot on keypad +// and with dead key support +partial +xkb_symbols "102_qwertz_dot_dead" { + name[Group1] = "Hungary - 102/qwertz/dot/Dead keys"; + include "latin" + include "hu(def_102)" + include "hu(def_qwertz)" + include "hu(def_dot)" + include "hu(def_dead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 102_qwertz_dot_nodead +// 102 key qwertz layout +// with decimal dot on keypad +// and without dead key support +partial +xkb_symbols "102_qwertz_dot_nodead" { + name[Group1] = "Hungary - 102/qwertz/dot/Eliminate dead keys"; + include "latin" + include "hu(def_102)" + include "hu(def_qwertz)" + include "hu(def_dot)" + include "hu(def_nodead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 102_qwerty_comma_dead +// 102 key qwerty layout +// with decimal comma on keypad +// and with dead key support +partial +xkb_symbols "102_qwerty_comma_dead" { + name[Group1] = "Hungary - 102/qwerty/comma/Dead keys"; + include "latin" + include "hu(def_102)" + include "hu(def_qwerty)" + include "kpdl(comma)" + include "hu(def_dead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 102_qwerty_comma_nodead +// 102 key qwerty layout +// with decimal comma on keypad +// and without dead key support +partial +xkb_symbols "102_qwerty_comma_nodead" { + name[Group1] = "Hungary - 102/qwerty/comma/Eliminate dead keys"; + include "latin" + include "hu(def_102)" + include "hu(def_qwerty)" + include "kpdl(comma)" + include "hu(def_nodead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 102_qwerty_dot_dead +// 102 key qwerty layout +// with decimal dot on keypad +// and with dead key support +partial +xkb_symbols "102_qwerty_dot_dead" { + name[Group1] = "Hungary - 102/qwerty/dot/Dead keys"; + include "latin" + include "hu(def_102)" + include "hu(def_qwerty)" + include "hu(def_dot)" + include "hu(def_dead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// 102_qwerty_dot_nodead +// 102 key qwerty layout +// with decimal dot on keypad +// and without dead key support +partial +xkb_symbols "102_qwerty_dot_nodead" { + name[Group1] = "Hungary - 102/qwerty/dot/Eliminate dead keys"; + include "latin" + include "hu(def_102)" + include "hu(def_qwerty)" + include "hu(def_dot)" + include "hu(def_nodead)" + include "hu(def_common)" + include "level3(ralt_switch)" +}; + +// Partial layouts + +// def_102: +// The standard Hungarian 102 key layout +hidden partial alphanumeric_keys +xkb_symbols "def_102" { + key <TLDE> { [ 0, section, notsign ] }; + key <LSGT> { [ iacute, Iacute, less, greater ] }; + +}; + +// def_101: +// An alternative layout for 101 key keyboards +hidden partial alphanumeric_keys +xkb_symbols "def_101" { + key <TLDE> { [ iacute, Iacute, 0, section ] }; + key <LSGT> { [ less, greater ] }; +}; + +// def_qwertz: +// The standard Hungaryan qwertz layout +hidden partial alphanumeric_keys +xkb_symbols "def_qwertz" { + key <AD06> { [ z, Z, endash ] }; + key <AB01> { [ y, Y, greater ] }; +}; + + +// def_qwerty: +// The qwerty layout for people who familiar with the standard US layout +hidden partial alphanumeric_keys +xkb_symbols "def_qwerty" { + key <AD06> { [ y, Y, endash ] }; + key <AB01> { [ z, Z, greater ] }; +}; + +// def_dot: +// The Hungarian standard is the comma on the keypad not decimal dot, +// but programmers hate it +hidden partial keypad_keys +xkb_symbols "def_dot" { + key <KPDL> { [ KP_Delete, KP_Decimal ] }; +}; + + +// def_dead: +// Dead keys support part +hidden partial alphanumeric_keys +xkb_symbols "def_dead" { + key <AE01> { [ 1, apostrophe, asciitilde, dead_tilde ] }; + key <AE02> { [ 2, quotedbl, dead_caron, caron ] }; + key <AE03> { [ 3, plus, asciicircum, dead_circumflex ] }; + key <AE04> { [ 4, exclam, dead_breve, breve ] }; + key <AE05> { [ 5, percent, dead_abovering, degree ] }; + key <AE06> { [ 6, slash, dead_ogonek, ogonek ] }; + key <AE07> { [ 7, equal, grave, dead_grave ] }; + key <AE08> { [ 8, parenleft, dead_abovedot, abovedot ] }; + key <AE09> { [ 9, parenright, dead_acute, acute ] }; + key <AE10> { [ odiaeresis, Odiaeresis, dead_doubleacute, doubleacute ] }; + key <AE11> { [ udiaeresis, Udiaeresis, dead_diaeresis, diaeresis ] }; + key <AE12> { [ oacute, Oacute, dead_cedilla, cedilla ] }; +}; + +// def_nodead: +// Without dead keys support +hidden partial alphanumeric_keys +xkb_symbols "def_nodead" { + key <AE01> { [ 1, apostrophe, asciitilde ] }; + key <AE02> { [ 2, quotedbl, caron ] }; + key <AE03> { [ 3, plus, asciicircum ] }; + key <AE04> { [ 4, exclam, breve ] }; + key <AE05> { [ 5, percent, degree ] }; + key <AE06> { [ 6, slash, ogonek ] }; + key <AE07> { [ 7, equal, grave ] }; + key <AE08> { [ 8, parenleft, abovedot ] }; + key <AE09> { [ 9, parenright, acute ] }; + key <AE10> { [ odiaeresis, Odiaeresis, doubleacute ] }; + key <AE11> { [ udiaeresis, Udiaeresis, diaeresis ] }; + key <AE12> { [ oacute, Oacute, cedilla ] }; +}; + + +// def_common: +// The common part of all Hungarian layout above +hidden partial alphanumeric_keys +xkb_symbols "def_common" { + key <AD01> { [ q, Q, backslash ] }; + key <AD02> { [ w, W, bar ] }; + key <AD07> { [ u, U, EuroSign ] }; + key <AD08> { [ i, I, Iacute, iacute ] }; + key <AD09> { [ o, O, doublelowquotemark ] }; + key <AD10> { [ p, P, rightdoublequotemark ] }; + key <AD11> { [ odoubleacute, Odoubleacute, division ] }; + key <AD12> { [ uacute, Uacute, multiply ] }; + + key <AC01> { [ a, A, adiaeresis, Adiaeresis ] }; + key <AC02> { [ s, S, dstroke ] }; + key <AC03> { [ d, D, Dstroke ] }; + key <AC04> { [ f, F, bracketleft ] }; + key <AC05> { [ g, G, bracketright ] }; + key <AC07> { [ j, J, iacute, Iacute ] }; + key <AC08> { [ k, K, lstroke ] }; + key <AC09> { [ l, L, Lstroke ] }; + key <AC10> { [ eacute, Eacute, dollar, cent ] }; + key <AC11> { [ aacute, Aacute, ssharp ] }; + + key <BKSL> { [ udoubleacute, Udoubleacute, currency ] }; + + key <AB02> { [ x, X, numbersign ] }; + key <AB03> { [ c, C, ampersand ] }; + key <AB04> { [ v, V, at ] }; + key <AB05> { [ b, B, braceleft ] }; + key <AB06> { [ n, N, braceright ] }; + key <AB07> { [ m, M, less ] }; + key <AB08> { [ comma, question, semicolon ] }; + key <AB09> { [ period, colon, ellipsis ] }; + key <AB10> { [ minus, underscore, asterisk ] }; + +}; -- cgit v1.2.3